diff --git a/Gopkg.lock b/Gopkg.lock index 33ded270..1a00a5d1 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1,6 +1,12 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. +[[projects]] + name = "cloud.google.com/go" + packages = ["civil"] + revision = "0ebda48a7f143b1cce9eb37a8c1106ac762a3430" + version = "v0.34.0" + [[projects]] name = "contrib.go.opencensus.io/exporter/ocagent" packages = ["."] @@ -25,6 +31,12 @@ revision = "7f2434bc10da710debe5c4315ed6d4df454b4024" version = "v0.1.0" +[[projects]] + branch = "master" + name = "github.com/denisenkom/go-mssqldb" + packages = [".","internal/cp"] + revision = "2fea367d496dade570d9c1959be58a98a9061522" + [[projects]] name = "github.com/dgrijalva/jwt-go" packages = ["."] @@ -58,7 +70,7 @@ [[projects]] name = "github.com/jinzhu/gorm" - packages = [".","dialects/mysql","dialects/postgres","dialects/sqlite"] + packages = [".","dialects/mssql","dialects/mysql","dialects/postgres","dialects/sqlite"] revision = "472c70caa40267cb89fd8facb07fe6454b578626" version = "v1.9.2" @@ -95,7 +107,7 @@ [[projects]] branch = "master" name = "golang.org/x/crypto" - packages = ["curve25519","ed25519","ed25519/internal/edwards25519","internal/chacha20","internal/subtle","poly1305","ssh","ssh/knownhosts","ssh/testdata"] + packages = ["curve25519","ed25519","ed25519/internal/edwards25519","internal/chacha20","internal/subtle","md4","poly1305","ssh","ssh/knownhosts","ssh/testdata"] revision = "0a9e5a7b288dccb74e2efd0fe62005aaf2a6ddbb" source = "https://github.com/tg123/sshpiper.crypto" @@ -150,6 +162,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "dbffb1a34f0f89a4b396f56587f2b9f66435734d8c213c7fccc789aab882b646" + inputs-digest = "462e8a5c0f53ae4a78ab2d005630854f64df61142ef3409475ff2b3f1c5640fb" solver-name = "gps-cdcl" solver-version = 1 diff --git a/sshpiperd/e2e/docker-compose.yml b/sshpiperd/e2e/docker-compose.yml index 06011c6c..c0c1a8e9 100644 --- a/sshpiperd/e2e/docker-compose.yml +++ b/sshpiperd/e2e/docker-compose.yml @@ -31,6 +31,7 @@ services: - piper - piper_mysql - piper_pg + - piper_mssql piper: environment: - "SSHPIPERD_UPSTREAM_WORKINGDIR_NOCHECKPERM=true" @@ -131,6 +132,39 @@ services: - "POSTGRES_DB=sshpiper" tmpfs: - /var/lib/postgresql/data + piper_mssql: + environment: + - "WAIT_HOST=mssql" + - "WAIT_PORT=1433" + - "SSHPIPERD_UPSTREAM_DRIVER=mssql" + - "SSHPIPERD_UPSTREAM_MSSQL_HOST=mssql" + - "SSHPIPERD_UPSTREAM_MSSQL_PASSWORD=yourStrong(!)Password" + - "SSHPIPERD_UPSTREAM_MSSQL_DBNAME=master" + - "SSHPIPERD_AUDITOR=typescript-logger" + - "SSHPIPERD_BANNERTEXT=hellopiper" + build: ../.. + links: + - "host1:host1" + - "host2:host2" + - "mssql:mssql" + volumes: + - ./piper.sh:/piper.sh + - workingdir:/var/sshpiper + - ./wait.sh:/wait.sh + command: + - "/bin/sh" + - "/piper.sh" + depends_on: + - mssql + - host1 + - host2 + mssql: + image: mcr.microsoft.com/mssql/server + environment: + - "ACCEPT_EULA=y" + - "SA_PASSWORD=yourStrong(!)Password" + #tmpfs: + # - /var/opt/mssql/data volumes: diff --git a/sshpiperd/e2e/test.sh b/sshpiperd/e2e/test.sh index e9dbd17d..a7e444d4 100755 --- a/sshpiperd/e2e/test.sh +++ b/sshpiperd/e2e/test.sh @@ -3,6 +3,7 @@ /wait.sh piper 2222 /wait.sh piper_mysql 2222 /wait.sh piper_pg 2222 +/wait.sh piper_mssql 2222 # TODO to python @@ -56,4 +57,5 @@ runtest "host2 with password:" "host2" "sshpass -p root ssh host2@piper -p 2222 runtest "sqlite host2 with password:" "host2" "sshpass -p root ssh host2@piper_sqlite -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host2" runtest "mysql host2 with password:" "host2" "sshpass -p root ssh host2@piper_mysql -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host2" runtest "pg host2 with password:" "host2" "sshpass -p root ssh host2@piper_pg -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host2" +runtest "msql host2 with password:" "host2" "sshpass -p root ssh host2@piper_mssql -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null cat /names/host2" diff --git a/sshpiperd/e2e/wait.sh b/sshpiperd/e2e/wait.sh index e330379e..33fb803d 100755 --- a/sshpiperd/e2e/wait.sh +++ b/sshpiperd/e2e/wait.sh @@ -1,7 +1,6 @@ #!/bin/sh for i in `seq 300`; do - nc -w 1 -z "$1" "$2" >/dev/null 2>&1 nc -w 1 -z "$1" "$2" if [ $? -eq 0 ]; then break diff --git a/sshpiperd/upstream/database/mssql.go b/sshpiperd/upstream/database/mssql.go new file mode 100644 index 00000000..3af5292c --- /dev/null +++ b/sshpiperd/upstream/database/mssql.go @@ -0,0 +1,58 @@ +package database + +import ( + "fmt" + "net/url" + + "github.com/jinzhu/gorm" + _ "github.com/jinzhu/gorm/dialects/mssql" + + upstreamprovider "github.com/tg123/sshpiper/sshpiperd/upstream" +) + +type mssqlplugin struct { + plugin + + Config struct { + Host string `long:"upstream-mssql-host" default:"127.0.0.1" description:"sql server host for driver" env:"SSHPIPERD_UPSTREAM_MSSQL_HOST" ini-name:"upstream-mssql-host"` + User string `long:"upstream-mssql-user" default:"sa" description:"sql server user for driver" env:"SSHPIPERD_UPSTREAM_MSSQL_USER" ini-name:"upstream-mssql-user"` + Password string `long:"upstream-mssql-password" default:"" description:"sql server password for driver" env:"SSHPIPERD_UPSTREAM_MSSQL_PASSWORD" ini-name:"upstream-mssql-password"` + Port uint `long:"upstream-mssql-port" default:"1433" description:"sql server port for driver" env:"SSHPIPERD_UPSTREAM_MSSQL_PORT" ini-name:"upstream-mssql-port"` + Dbname string `long:"upstream-mssql-dbname" default:"sshpiper" description:"sql server dbname for driver" env:"SSHPIPERD_UPSTREAM_MSSQL_DBNAME" ini-name:"upstream-mssql-dbname"` + Instance string `long:"upstream-mssql-instance" description:"sql server db instance" env:"SSHPIPERD_UPSTREAM_MSSQL_INSTANCE" ini-name:"upstream-mssql-instance"` + } +} + +func (p *mssqlplugin) create() (*gorm.DB, error) { + query := url.Values{} + query.Add("database", p.Config.Dbname) + + u := &url.URL{ + Scheme: "sqlserver", + User: url.UserPassword(p.Config.User, p.Config.Password), + Host: fmt.Sprintf("%s:%d", p.Config.Host, p.Config.Port), + Path: p.Config.Instance, + RawQuery: query.Encode(), + } + + db, err := gorm.Open("mssql", u.String()) + if err != nil { + return nil, err + } + + return db, nil +} + +func (mssqlplugin) GetName() string { + return "mssql" +} + +func (p *mssqlplugin) GetOpts() interface{} { + return &p.Config +} + +func init() { + p := &mssqlplugin{} + p.createdb = p + upstreamprovider.Register("mssql", p) +} diff --git a/vendor/cloud.google.com/go/AUTHORS b/vendor/cloud.google.com/go/AUTHORS new file mode 100644 index 00000000..c364af1d --- /dev/null +++ b/vendor/cloud.google.com/go/AUTHORS @@ -0,0 +1,15 @@ +# This is the official list of cloud authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as: +# Name or Organization +# The email address is not required for organizations. + +Filippo Valsorda +Google Inc. +Ingo Oeser +Palm Stone Games, Inc. +Paweł Knap +Péter Szilágyi +Tyler Treat diff --git a/vendor/cloud.google.com/go/CHANGES.md b/vendor/cloud.google.com/go/CHANGES.md new file mode 100644 index 00000000..bec57e0a --- /dev/null +++ b/vendor/cloud.google.com/go/CHANGES.md @@ -0,0 +1,1024 @@ +# Changes + +## v0.34.0 + +- functions/metadata: + - Switch to using JSON in context. + - Make Resource a value. +- vision: Fix ProductSearch return type. +- datastore: Add an example for how to handle MultiError. + +## v0.33.1 + +- compute: Removes an erroneously added go.mod. +- logging: Populate source location in fromLogEntry. + +## v0.33.0 + +- bttest: + - Add support for apply_label_transformer. +- expr: + - Add expr library. +- firestore: + - Support retrieval of missing documents. +- kms: + - Add IAM methods. +- pubsub: + - Clarify extension documentation. +- scheduler: + - Add v1beta1 client. +- vision: + - Add product search helper. + - Add new product search client. + +## v0.32.0 + +Note: This release is the last to support Go 1.6 and 1.8. + +- bigquery: + - Add support for removing an expiration. + - Ignore NeverExpire in Table.Create. + - Validate table expiration time. +- cbt: + - Add note about not supporting arbitrary bytes. +- datastore: + - Align key checks. +- firestore: + - Return an error when using Start/End without providing values. +- pubsub: + - Add pstest Close method. + - Clarify MaxExtension documentation. +- securitycenter: + - Add v1beta1 client. +- spanner: + - Allow nil in mutations. + - Improve doc of SessionPoolConfig.MaxOpened. + - Increase session deletion timeout from 5s to 15s. + +## v0.31.0 + +- bigtable: + - Group mutations across multiple requests. +- bigquery: + - Link to bigquery troubleshooting errors page in bigquery.Error comment. +- cbt: + - Fix go generate command. + - Document usage of both maxage + maxversions. +- datastore: + - Passing nil keys results in ErrInvalidKey. +- firestore: + - Clarify what Document.DataTo does with untouched struct fields. +- profile: + - Validate service name in agent. +- pubsub: + - Fix deadlock with pstest and ctx.Cancel. + - Fix a possible deadlock in pstest. +- trace: + - Update doc URL with new fragment. + +Special thanks to @fastest963 for going above and beyond helping us to debug +hard-to-reproduce Pub/Sub issues. + +## v0.30.0 + +- spanner: DML support added. See https://godoc.org/cloud.google.com/go/spanner#hdr-DML_and_Partitioned_DML for more information. +- bigtable: bttest supports row sample filter. +- functions: metadata package added for accessing Cloud Functions resource metadata. + +## v0.29.0 + +- bigtable: + - Add retry to all idempotent RPCs. + - cbt supports complex GC policies. + - Emulator supports arbitrary bytes in regex filters. +- firestore: Add ArrayUnion and ArrayRemove. +- logging: Add the ContextFunc option to supply the context used for + asynchronous RPCs. +- profiler: Ignore NotDefinedError when fetching the instance name +- pubsub: + - BEHAVIOR CHANGE: Receive doesn't retry if an RPC returns codes.Cancelled. + - BEHAVIOR CHANGE: Receive retries on Unavailable intead of returning. + - Fix deadlock. + - Restore Ack/Nack/Modacks metrics. + - Improve context handling in iterator. + - Implement synchronous mode for Receive. + - pstest: add Pull. +- spanner: Add a metric for the number of sessions currently opened. +- storage: + - Canceling the context releases all resources. + - Add additional RetentionPolicy attributes. +- vision/apiv1: Add LocalizeObjects method. + +## v0.28.0 + +- bigtable: + - Emulator returns Unimplemented for snapshot RPCs. +- bigquery: + - Support zero-length repeated, nested fields. +- cloud assets: + - Add v1beta client. +- datastore: + - Don't nil out transaction ID on retry. +- firestore: + - BREAKING CHANGE: When watching a query with Query.Snapshots, QuerySnapshotIterator.Next + returns a QuerySnapshot which contains read time, result size, change list and the DocumentIterator + (previously, QuerySnapshotIterator.Next returned just the DocumentIterator). See: https://godoc.org/cloud.google.com/go/firestore#Query.Snapshots. + - Add array-contains operator. +- IAM: + - Add iam/credentials/apiv1 client. +- pubsub: + - Canceling the context passed to Subscription.Receive causes Receive to return when + processing finishes on all messages currently in progress, even if new messages are arriving. +- redis: + - Add redis/apiv1 client. +- storage: + - Add Reader.Attrs. + - Deprecate several Reader getter methods: please use Reader.Attrs for these instead. + - Add ObjectHandle.Bucket and ObjectHandle.Object methods. + +## v0.27.0 + +- bigquery: + - Allow modification of encryption configuration and partitioning options to a table via the Update call. + - Add a SchemaFromJSON function that converts a JSON table schema. +- bigtable: + - Restore cbt count functionality. +- containeranalysis: + - Add v1beta client. +- spanner: + - Fix a case where an iterator might not be closed correctly. +- storage: + - Add ServiceAccount method https://godoc.org/cloud.google.com/go/storage#Client.ServiceAccount. + - Add a method to Reader that returns the parsed value of the Last-Modified header. + +## v0.26.0 + +- bigquery: + - Support filtering listed jobs by min/max creation time. + - Support data clustering (https://godoc.org/cloud.google.com/go/bigquery#Clustering). + - Include job creator email in Job struct. +- bigtable: + - Add `RowSampleFilter`. + - emulator: BREAKING BEHAVIOR CHANGE: Regexps in row, family, column and value filters + must match the entire target string to succeed. Previously, the emulator was + succeeding on partial matches. + NOTE: As of this release, this change only affects the emulator when run + from this repo (bigtable/cmd/emulator/cbtemulator.go). The version launched + from `gcloud` will be updated in a subsequent `gcloud` release. +- dataproc: Add apiv1beta2 client. +- datastore: Save non-nil pointer fields on omitempty. +- logging: populate Entry.Trace from the HTTP X-Cloud-Trace-Context header. +- logging/logadmin: Support writer_identity and include_children. +- pubsub: + - Support labels on topics and subscriptions. + - Support message storage policy for topics. + - Use the distribution of ack times to determine when to extend ack deadlines. + The only user-visible effect of this change should be that programs that + call only `Subscription.Receive` need no IAM permissions other than `Pub/Sub + Subscriber`. +- storage: + - Support predefined ACLs. + - Support additional ACL fields other than Entity and Role. + - Support bucket websites. + - Support bucket logging. + + +## v0.25.0 + +- Added [Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CODE_OF_CONDUCT.md) +- bigtable: + - cbt: Support a GC policy of "never". +- errorreporting: + - Support User. + - Close now calls Flush. + - Use OnError (previously ignored). + - Pass through the RPC error as-is to OnError. +- httpreplay: A tool for recording and replaying HTTP requests + (for the bigquery and storage clients in this repo). +- kms: v1 client added +- logging: add SourceLocation to Entry. +- storage: improve CRC checking on read. + +## v0.24.0 + +- bigquery: Support for the NUMERIC type. +- bigtable: + - cbt: Optionally specify columns for read/lookup + - Support instance-level administration. +- oslogin: New client for the OS Login API. +- pubsub: + - The package is now stable. There will be no further breaking changes. + - Internal changes to improve Subscription.Receive behavior. +- storage: Support updating bucket lifecycle config. +- spanner: Support struct-typed parameter bindings. +- texttospeech: New client for the Text-to-Speech API. + +## v0.23.0 + +- bigquery: Add DDL stats to query statistics. +- bigtable: + - cbt: Add cells-per-column limit for row lookup. + - cbt: Make it possible to combine read filters. +- dlp: v2beta2 client removed. Use the v2 client instead. +- firestore, spanner: Fix compilation errors due to protobuf changes. + +## v0.22.0 + +- bigtable: + - cbt: Support cells per column limit for row read. + - bttest: Correctly handle empty RowSet. + - Fix ReadModifyWrite operation in emulator. + - Fix API path in GetCluster. + +- bigquery: + - BEHAVIOR CHANGE: Retry on 503 status code. + - Add dataset.DeleteWithContents. + - Add SchemaUpdateOptions for query jobs. + - Add Timeline to QueryStatistics. + - Add more stats to ExplainQueryStage. + - Support Parquet data format. + +- datastore: + - Support omitempty for times. + +- dlp: + - **BREAKING CHANGE:** Remove v1beta1 client. Please migrate to the v2 client, + which is now out of beta. + - Add v2 client. + +- firestore: + - BEHAVIOR CHANGE: Treat set({}, MergeAll) as valid. + +- iam: + - Support JWT signing via SignJwt callopt. + +- profiler: + - BEHAVIOR CHANGE: PollForSerialOutput returns an error when context.Done. + - BEHAVIOR CHANGE: Increase the initial backoff to 1 minute. + - Avoid returning empty serial port output. + +- pubsub: + - BEHAVIOR CHANGE: Don't backoff during next retryable error once stream is healthy. + - BEHAVIOR CHANGE: Don't backoff on EOF. + - pstest: Support Acknowledge and ModifyAckDeadline RPCs. + +- redis: + - Add v1 beta Redis client. + +- spanner: + - Support SessionLabels. + +- speech: + - Add api v1 beta1 client. + +- storage: + - BEHAVIOR CHANGE: Retry reads when retryable error occurs. + - Fix delete of object in requester-pays bucket. + - Support KMS integration. + +## v0.21.0 + +- bigquery: + - Add OpenCensus tracing. + +- firestore: + - **BREAKING CHANGE:** If a document does not exist, return a DocumentSnapshot + whose Exists method returns false. DocumentRef.Get and Transaction.Get + return the non-nil DocumentSnapshot in addition to a NotFound error. + **DocumentRef.GetAll and Transaction.GetAll return a non-nil + DocumentSnapshot instead of nil.** + - Add DocumentIterator.Stop. **Call Stop whenever you are done with a + DocumentIterator.** + - Added Query.Snapshots and DocumentRef.Snapshots, which provide realtime + notification of updates. See https://cloud.google.com/firestore/docs/query-data/listen. + - Canceling an RPC now always returns a grpc.Status with codes.Canceled. + +- spanner: + - Add `CommitTimestamp`, which supports inserting the commit timestamp of a + transaction into a column. + +## v0.20.0 + +- bigquery: Support SchemaUpdateOptions for load jobs. + +- bigtable: + - Add SampleRowKeys. + - cbt: Support union, intersection GCPolicy. + - Retry admin RPCS. + - Add trace spans to retries. + +- datastore: Add OpenCensus tracing. + +- firestore: + - Fix queries involving Null and NaN. + - Allow Timestamp protobuffers for time values. + +- logging: Add a WriteTimeout option. + +- spanner: Support Batch API. + +- storage: Add OpenCensus tracing. + +## v0.19.0 + +- bigquery: + - Support customer-managed encryption keys. + +- bigtable: + - Improved emulator support. + - Support GetCluster. + +- datastore: + - Add general mutations. + - Support pointer struct fields. + - Support transaction options. + +- firestore: + - Add Transaction.GetAll. + - Support document cursors. + +- logging: + - Support concurrent RPCs to the service. + - Support per-entry resources. + +- profiler: + - Add config options to disable heap and thread profiling. + - Read the project ID from $GOOGLE_CLOUD_PROJECT when it's set. + +- pubsub: + - BEHAVIOR CHANGE: Release flow control after ack/nack (instead of after the + callback returns). + - Add SubscriptionInProject. + - Add OpenCensus instrumentation for streaming pull. + +- storage: + - Support CORS. + +## v0.18.0 + +- bigquery: + - Marked stable. + - Schema inference of nullable fields supported. + - Added TimePartitioning to QueryConfig. + +- firestore: Data provided to DocumentRef.Set with a Merge option can contain + Delete sentinels. + +- logging: Clients can accept parent resources other than projects. + +- pubsub: + - pubsub/pstest: A lighweight fake for pubsub. Experimental; feedback welcome. + - Support updating more subscription metadata: AckDeadline, + RetainAckedMessages and RetentionDuration. + +- oslogin/apiv1beta: New client for the Cloud OS Login API. + +- rpcreplay: A package for recording and replaying gRPC traffic. + +- spanner: + - Add a ReadWithOptions that supports a row limit, as well as an index. + - Support query plan and execution statistics. + - Added [OpenCensus](http://opencensus.io) support. + +- storage: Clarify checksum validation for gzipped files (it is not validated + when the file is served uncompressed). + + +## v0.17.0 + +- firestore BREAKING CHANGES: + - Remove UpdateMap and UpdateStruct; rename UpdatePaths to Update. + Change + `docref.UpdateMap(ctx, map[string]interface{}{"a.b", 1})` + to + `docref.Update(ctx, []firestore.Update{{Path: "a.b", Value: 1}})` + + Change + `docref.UpdateStruct(ctx, []string{"Field"}, aStruct)` + to + `docref.Update(ctx, []firestore.Update{{Path: "Field", Value: aStruct.Field}})` + - Rename MergePaths to Merge; require args to be FieldPaths + - A value stored as an integer can be read into a floating-point field, and vice versa. +- bigtable/cmd/cbt: + - Support deleting a column. + - Add regex option for row read. +- spanner: Mark stable. +- storage: + - Add Reader.ContentEncoding method. + - Fix handling of SignedURL headers. +- bigquery: + - If Uploader.Put is called with no rows, it returns nil without making a + call. + - Schema inference supports the "nullable" option in struct tags for + non-required fields. + - TimePartitioning supports "Field". + + +## v0.16.0 + +- Other bigquery changes: + - `JobIterator.Next` returns `*Job`; removed `JobInfo` (BREAKING CHANGE). + - UseStandardSQL is deprecated; set UseLegacySQL to true if you need + Legacy SQL. + - Uploader.Put will generate a random insert ID if you do not provide one. + - Support time partitioning for load jobs. + - Support dry-run queries. + - A `Job` remembers its last retrieved status. + - Support retrieving job configuration. + - Support labels for jobs and tables. + - Support dataset access lists. + - Improve support for external data sources, including data from Bigtable and + Google Sheets, and tables with external data. + - Support updating a table's view configuration. + - Fix uploading civil times with nanoseconds. + +- storage: + - Support PubSub notifications. + - Support Requester Pays buckets. + +- profiler: Support goroutine and mutex profile types. + +## v0.15.0 + +- firestore: beta release. See the + [announcement](https://firebase.googleblog.com/2017/10/introducing-cloud-firestore.html). + +- errorreporting: The existing package has been redesigned. + +- errors: This package has been removed. Use errorreporting. + + +## v0.14.0 + +- bigquery BREAKING CHANGES: + - Standard SQL is the default for queries and views. + - `Table.Create` takes `TableMetadata` as a second argument, instead of + options. + - `Dataset.Create` takes `DatasetMetadata` as a second argument. + - `DatasetMetadata` field `ID` renamed to `FullID` + - `TableMetadata` field `ID` renamed to `FullID` + +- Other bigquery changes: + - The client will append a random suffix to a provided job ID if you set + `AddJobIDSuffix` to true in a job config. + - Listing jobs is supported. + - Better retry logic. + +- vision, language, speech: clients are now stable + +- monitoring: client is now beta + +- profiler: + - Rename InstanceName to Instance, ZoneName to Zone + - Auto-detect service name and version on AppEngine. + +## v0.13.0 + +- bigquery: UseLegacySQL options for CreateTable and QueryConfig. Use these + options to continue using Legacy SQL after the client switches its default + to Standard SQL. + +- bigquery: Support for updating dataset labels. + +- bigquery: Set DatasetIterator.ProjectID to list datasets in a project other + than the client's. DatasetsInProject is no longer needed and is deprecated. + +- bigtable: Fail ListInstances when any zones fail. + +- spanner: support decoding of slices of basic types (e.g. []string, []int64, + etc.) + +- logging/logadmin: UpdateSink no longer creates a sink if it is missing + (actually a change to the underlying service, not the client) + +- profiler: Service and ServiceVersion replace Target in Config. + +## v0.12.0 + +- pubsub: Subscription.Receive now uses streaming pull. + +- pubsub: add Client.TopicInProject to access topics in a different project + than the client. + +- errors: renamed errorreporting. The errors package will be removed shortly. + +- datastore: improved retry behavior. + +- bigquery: support updates to dataset metadata, with etags. + +- bigquery: add etag support to Table.Update (BREAKING: etag argument added). + +- bigquery: generate all job IDs on the client. + +- storage: support bucket lifecycle configurations. + + +## v0.11.0 + +- Clients for spanner, pubsub and video are now in beta. + +- New client for DLP. + +- spanner: performance and testing improvements. + +- storage: requester-pays buckets are supported. + +- storage, profiler, bigtable, bigquery: bug fixes and other minor improvements. + +- pubsub: bug fixes and other minor improvements + +## v0.10.0 + +- pubsub: Subscription.ModifyPushConfig replaced with Subscription.Update. + +- pubsub: Subscription.Receive now runs concurrently for higher throughput. + +- vision: cloud.google.com/go/vision is deprecated. Use +cloud.google.com/go/vision/apiv1 instead. + +- translation: now stable. + +- trace: several changes to the surface. See the link below. + +### Code changes required from v0.9.0 + +- pubsub: Replace + + ``` + sub.ModifyPushConfig(ctx, pubsub.PushConfig{Endpoint: "https://example.com/push"}) + ``` + + with + + ``` + sub.Update(ctx, pubsub.SubscriptionConfigToUpdate{ + PushConfig: &pubsub.PushConfig{Endpoint: "https://example.com/push"}, + }) + ``` + +- trace: traceGRPCServerInterceptor will be provided from *trace.Client. +Given an initialized `*trace.Client` named `tc`, instead of + + ``` + s := grpc.NewServer(grpc.UnaryInterceptor(trace.GRPCServerInterceptor(tc))) + ``` + + write + + ``` + s := grpc.NewServer(grpc.UnaryInterceptor(tc.GRPCServerInterceptor())) + ``` + +- trace trace.GRPCClientInterceptor will also provided from *trace.Client. +Instead of + + ``` + conn, err := grpc.Dial(srv.Addr, grpc.WithUnaryInterceptor(trace.GRPCClientInterceptor())) + ``` + + write + + ``` + conn, err := grpc.Dial(srv.Addr, grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor())) + ``` + +- trace: We removed the deprecated `trace.EnableGRPCTracing`. Use the gRPC +interceptor as a dial option as shown below when initializing Cloud package +clients: + + ``` + c, err := pubsub.NewClient(ctx, "project-id", option.WithGRPCDialOption(grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor()))) + if err != nil { + ... + } + ``` + + +## v0.9.0 + +- Breaking changes to some autogenerated clients. +- rpcreplay package added. + +## v0.8.0 + +- profiler package added. +- storage: + - Retry Objects.Insert call. + - Add ProgressFunc to WRiter. +- pubsub: breaking changes: + - Publish is now asynchronous ([announcement](https://groups.google.com/d/topic/google-api-go-announce/aaqRDIQ3rvU/discussion)). + - Subscription.Pull replaced by Subscription.Receive, which takes a callback ([announcement](https://groups.google.com/d/topic/google-api-go-announce/8pt6oetAdKc/discussion)). + - Message.Done replaced with Message.Ack and Message.Nack. + +## v0.7.0 + +- Release of a client library for Spanner. See +the +[blog +post](https://cloudplatform.googleblog.com/2017/02/introducing-Cloud-Spanner-a-global-database-service-for-mission-critical-applications.html). +Note that although the Spanner service is beta, the Go client library is alpha. + +## v0.6.0 + +- Beta release of BigQuery, DataStore, Logging and Storage. See the +[blog post](https://cloudplatform.googleblog.com/2016/12/announcing-new-google-cloud-client.html). + +- bigquery: + - struct support. Read a row directly into a struct with +`RowIterator.Next`, and upload a row directly from a struct with `Uploader.Put`. +You can also use field tags. See the [package documentation][cloud-bigquery-ref] +for details. + + - The `ValueList` type was removed. It is no longer necessary. Instead of + ```go + var v ValueList + ... it.Next(&v) .. + ``` + use + + ```go + var v []Value + ... it.Next(&v) ... + ``` + + - Previously, repeatedly calling `RowIterator.Next` on the same `[]Value` or + `ValueList` would append to the slice. Now each call resets the size to zero first. + + - Schema inference will infer the SQL type BYTES for a struct field of + type []byte. Previously it inferred STRING. + + - The types `uint`, `uint64` and `uintptr` are no longer supported in schema + inference. BigQuery's integer type is INT64, and those types may hold values + that are not correctly represented in a 64-bit signed integer. + +## v0.5.0 + +- bigquery: + - The SQL types DATE, TIME and DATETIME are now supported. They correspond to + the `Date`, `Time` and `DateTime` types in the new `cloud.google.com/go/civil` + package. + - Support for query parameters. + - Support deleting a dataset. + - Values from INTEGER columns will now be returned as int64, not int. This + will avoid errors arising from large values on 32-bit systems. +- datastore: + - Nested Go structs encoded as Entity values, instead of a +flattened list of the embedded struct's fields. This means that you may now have twice-nested slices, eg. + ```go + type State struct { + Cities []struct{ + Populations []int + } + } + ``` + See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/79jtrdeuJAg) for +more details. + - Contexts no longer hold namespaces; instead you must set a key's namespace + explicitly. Also, key functions have been changed and renamed. + - The WithNamespace function has been removed. To specify a namespace in a Query, use the Query.Namespace method: + ```go + q := datastore.NewQuery("Kind").Namespace("ns") + ``` + - All the fields of Key are exported. That means you can construct any Key with a struct literal: + ```go + k := &Key{Kind: "Kind", ID: 37, Namespace: "ns"} + ``` + - As a result of the above, the Key methods Kind, ID, d.Name, Parent, SetParent and Namespace have been removed. + - `NewIncompleteKey` has been removed, replaced by `IncompleteKey`. Replace + ```go + NewIncompleteKey(ctx, kind, parent) + ``` + with + ```go + IncompleteKey(kind, parent) + ``` + and if you do use namespaces, make sure you set the namespace on the returned key. + - `NewKey` has been removed, replaced by `NameKey` and `IDKey`. Replace + ```go + NewKey(ctx, kind, name, 0, parent) + NewKey(ctx, kind, "", id, parent) + ``` + with + ```go + NameKey(kind, name, parent) + IDKey(kind, id, parent) + ``` + and if you do use namespaces, make sure you set the namespace on the returned key. + - The `Done` variable has been removed. Replace `datastore.Done` with `iterator.Done`, from the package `google.golang.org/api/iterator`. + - The `Client.Close` method will have a return type of error. It will return the result of closing the underlying gRPC connection. + - See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/hqXtM_4Ix-0) for +more details. + +## v0.4.0 + +- bigquery: + -`NewGCSReference` is now a function, not a method on `Client`. + - `Table.LoaderFrom` now accepts a `ReaderSource`, enabling + loading data into a table from a file or any `io.Reader`. + * Client.Table and Client.OpenTable have been removed. + Replace + ```go + client.OpenTable("project", "dataset", "table") + ``` + with + ```go + client.DatasetInProject("project", "dataset").Table("table") + ``` + + * Client.CreateTable has been removed. + Replace + ```go + client.CreateTable(ctx, "project", "dataset", "table") + ``` + with + ```go + client.DatasetInProject("project", "dataset").Table("table").Create(ctx) + ``` + + * Dataset.ListTables have been replaced with Dataset.Tables. + Replace + ```go + tables, err := ds.ListTables(ctx) + ``` + with + ```go + it := ds.Tables(ctx) + for { + table, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: use table. + } + ``` + + * Client.Read has been replaced with Job.Read, Table.Read and Query.Read. + Replace + ```go + it, err := client.Read(ctx, job) + ``` + with + ```go + it, err := job.Read(ctx) + ``` + and similarly for reading from tables or queries. + + * The iterator returned from the Read methods is now named RowIterator. Its + behavior is closer to the other iterators in these libraries. It no longer + supports the Schema method; see the next item. + Replace + ```go + for it.Next(ctx) { + var vals ValueList + if err := it.Get(&vals); err != nil { + // TODO: Handle error. + } + // TODO: use vals. + } + if err := it.Err(); err != nil { + // TODO: Handle error. + } + ``` + with + ``` + for { + var vals ValueList + err := it.Next(&vals) + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: use vals. + } + ``` + Instead of the `RecordsPerRequest(n)` option, write + ```go + it.PageInfo().MaxSize = n + ``` + Instead of the `StartIndex(i)` option, write + ```go + it.StartIndex = i + ``` + + * ValueLoader.Load now takes a Schema in addition to a slice of Values. + Replace + ```go + func (vl *myValueLoader) Load(v []bigquery.Value) + ``` + with + ```go + func (vl *myValueLoader) Load(v []bigquery.Value, s bigquery.Schema) + ``` + + + * Table.Patch is replace by Table.Update. + Replace + ```go + p := table.Patch() + p.Description("new description") + metadata, err := p.Apply(ctx) + ``` + with + ```go + metadata, err := table.Update(ctx, bigquery.TableMetadataToUpdate{ + Description: "new description", + }) + ``` + + * Client.Copy is replaced by separate methods for each of its four functions. + All options have been replaced by struct fields. + + * To load data from Google Cloud Storage into a table, use Table.LoaderFrom. + + Replace + ```go + client.Copy(ctx, table, gcsRef) + ``` + with + ```go + table.LoaderFrom(gcsRef).Run(ctx) + ``` + Instead of passing options to Copy, set fields on the Loader: + ```go + loader := table.LoaderFrom(gcsRef) + loader.WriteDisposition = bigquery.WriteTruncate + ``` + + * To extract data from a table into Google Cloud Storage, use + Table.ExtractorTo. Set fields on the returned Extractor instead of + passing options. + + Replace + ```go + client.Copy(ctx, gcsRef, table) + ``` + with + ```go + table.ExtractorTo(gcsRef).Run(ctx) + ``` + + * To copy data into a table from one or more other tables, use + Table.CopierFrom. Set fields on the returned Copier instead of passing options. + + Replace + ```go + client.Copy(ctx, dstTable, srcTable) + ``` + with + ```go + dst.Table.CopierFrom(srcTable).Run(ctx) + ``` + + * To start a query job, create a Query and call its Run method. Set fields + on the query instead of passing options. + + Replace + ```go + client.Copy(ctx, table, query) + ``` + with + ```go + query.Run(ctx) + ``` + + * Table.NewUploader has been renamed to Table.Uploader. Instead of options, + configure an Uploader by setting its fields. + Replace + ```go + u := table.NewUploader(bigquery.UploadIgnoreUnknownValues()) + ``` + with + ```go + u := table.NewUploader(bigquery.UploadIgnoreUnknownValues()) + u.IgnoreUnknownValues = true + ``` + +- pubsub: remove `pubsub.Done`. Use `iterator.Done` instead, where `iterator` is the package +`google.golang.org/api/iterator`. + +## v0.3.0 + +- storage: + * AdminClient replaced by methods on Client. + Replace + ```go + adminClient.CreateBucket(ctx, bucketName, attrs) + ``` + with + ```go + client.Bucket(bucketName).Create(ctx, projectID, attrs) + ``` + + * BucketHandle.List replaced by BucketHandle.Objects. + Replace + ```go + for query != nil { + objs, err := bucket.List(d.ctx, query) + if err != nil { ... } + query = objs.Next + for _, obj := range objs.Results { + fmt.Println(obj) + } + } + ``` + with + ```go + iter := bucket.Objects(d.ctx, query) + for { + obj, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { ... } + fmt.Println(obj) + } + ``` + (The `iterator` package is at `google.golang.org/api/iterator`.) + + Replace `Query.Cursor` with `ObjectIterator.PageInfo().Token`. + + Replace `Query.MaxResults` with `ObjectIterator.PageInfo().MaxSize`. + + + * ObjectHandle.CopyTo replaced by ObjectHandle.CopierFrom. + Replace + ```go + attrs, err := src.CopyTo(ctx, dst, nil) + ``` + with + ```go + attrs, err := dst.CopierFrom(src).Run(ctx) + ``` + + Replace + ```go + attrs, err := src.CopyTo(ctx, dst, &storage.ObjectAttrs{ContextType: "text/html"}) + ``` + with + ```go + c := dst.CopierFrom(src) + c.ContextType = "text/html" + attrs, err := c.Run(ctx) + ``` + + * ObjectHandle.ComposeFrom replaced by ObjectHandle.ComposerFrom. + Replace + ```go + attrs, err := dst.ComposeFrom(ctx, []*storage.ObjectHandle{src1, src2}, nil) + ``` + with + ```go + attrs, err := dst.ComposerFrom(src1, src2).Run(ctx) + ``` + + * ObjectHandle.Update's ObjectAttrs argument replaced by ObjectAttrsToUpdate. + Replace + ```go + attrs, err := obj.Update(ctx, &storage.ObjectAttrs{ContextType: "text/html"}) + ``` + with + ```go + attrs, err := obj.Update(ctx, storage.ObjectAttrsToUpdate{ContextType: "text/html"}) + ``` + + * ObjectHandle.WithConditions replaced by ObjectHandle.If. + Replace + ```go + obj.WithConditions(storage.Generation(gen), storage.IfMetaGenerationMatch(mgen)) + ``` + with + ```go + obj.Generation(gen).If(storage.Conditions{MetagenerationMatch: mgen}) + ``` + + Replace + ```go + obj.WithConditions(storage.IfGenerationMatch(0)) + ``` + with + ```go + obj.If(storage.Conditions{DoesNotExist: true}) + ``` + + * `storage.Done` replaced by `iterator.Done` (from package `google.golang.org/api/iterator`). + +- Package preview/logging deleted. Use logging instead. + +## v0.2.0 + +- Logging client replaced with preview version (see below). + +- New clients for some of Google's Machine Learning APIs: Vision, Speech, and +Natural Language. + +- Preview version of a new [Stackdriver Logging][cloud-logging] client in +[`cloud.google.com/go/preview/logging`](https://godoc.org/cloud.google.com/go/preview/logging). +This client uses gRPC as its transport layer, and supports log reading, sinks +and metrics. It will replace the current client at `cloud.google.com/go/logging` shortly. + + diff --git a/vendor/cloud.google.com/go/CODE_OF_CONDUCT.md b/vendor/cloud.google.com/go/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..8fd1bc9c --- /dev/null +++ b/vendor/cloud.google.com/go/CODE_OF_CONDUCT.md @@ -0,0 +1,44 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, +and in the interest of fostering an open and welcoming community, +we pledge to respect all people who contribute through reporting issues, +posting feature requests, updating documentation, +submitting pull requests or patches, and other activities. + +We are committed to making participation in this project +a harassment-free experience for everyone, +regardless of level of experience, gender, gender identity and expression, +sexual orientation, disability, personal appearance, +body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, +such as physical or electronic +addresses, without explicit permission +* Other unethical or unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct. +By adopting this Code of Conduct, +project maintainers commit themselves to fairly and consistently +applying these principles to every aspect of managing this project. +Project maintainers who do not follow or enforce the Code of Conduct +may be permanently removed from the project team. + +This code of conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior +may be reported by opening an issue +or contacting one or more of the project maintainers. + +This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, +available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) + diff --git a/vendor/cloud.google.com/go/CONTRIBUTING.md b/vendor/cloud.google.com/go/CONTRIBUTING.md new file mode 100644 index 00000000..eef41ed0 --- /dev/null +++ b/vendor/cloud.google.com/go/CONTRIBUTING.md @@ -0,0 +1,234 @@ +# Contributing + +1. Sign one of the contributor license agreements below. +1. `go get golang.org/x/review/git-codereview` to install the code reviewing +tool. + 1. You will need to ensure that your `GOBIN` directory (by default + `$GOPATH/bin`) is in your `PATH` so that git can find the command. + 1. If you would like, you may want to set up aliases for git-codereview, + such that `git codereview change` becomes `git change`. See the + [godoc](https://godoc.org/golang.org/x/review/git-codereview) for details. + 1. Should you run into issues with the git-codereview tool, please note + that all error messages will assume that you have set up these aliases. +1. Get the cloud package by running `go get -d cloud.google.com/go`. + 1. If you have already checked out the source, make sure that the remote + git origin is https://code.googlesource.com/gocloud: + + ``` + git remote set-url origin https://code.googlesource.com/gocloud + ``` + +1. Make sure your auth is configured correctly by visiting +https://code.googlesource.com, clicking "Generate Password", and following the +directions. +1. Make changes and create a change by running `git codereview change `, +provide a commit message, and use `git codereview mail` to create a Gerrit CL. +1. Keep amending to the change with `git codereview change` and mail as your +receive feedback. Each new mailed amendment will create a new patch set for +your change in Gerrit. + +## Integration Tests + +In addition to the unit tests, you may run the integration test suite. These +directions describe setting up your environment to run integration tests for +_all_ packages: note that many of these instructions may be redundant if you +intend only to run integration tests on a single package. + +#### GCP Setup + +To run the integrations tests, creation and configuration of two projects in +the Google Developers Console is required: one specifically for Firestore +integration tests, and another for all other integration tests. We'll refer to +these projects as "general project" and "Firestore project". + +After creating each project, you must [create a service account](https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount) +for each project. Ensure the project-level **Owner** +[IAM role](console.cloud.google.com/iam-admin/iam/project) role is added to +each service account. During the creation of the service account, you should +download the JSON credential file for use later. + +Next, ensure the following APIs are enabled in the general project: + +- BigQuery API +- BigQuery Data Transfer API +- Cloud Dataproc API +- Cloud Dataproc Control API Private +- Cloud Datastore API +- Cloud Firestore API +- Cloud Key Management Service (KMS) API +- Cloud Natural Language API +- Cloud OS Login API +- Cloud Pub/Sub API +- Cloud Resource Manager API +- Cloud Spanner API +- Cloud Speech API +- Cloud Translation API +- Cloud Video Intelligence API +- Cloud Vision API +- Compute Engine API +- Compute Engine Instance Group Manager API +- Container Registry API +- Firebase Rules API +- Google Cloud APIs +- Google Cloud Deployment Manager V2 API +- Google Cloud SQL +- Google Cloud Storage +- Google Cloud Storage JSON API +- Google Compute Engine Instance Group Updater API +- Google Compute Engine Instance Groups API +- Kubernetes Engine API +- Stackdriver Error Reporting API + +Next, create a Datastore database in the general project, and a Firestore +database in the Firestore project. + +Finally, in the general project, create an API key for the translate API: + +- Go to GCP Developer Console. +- Navigate to APIs & Services > Credentials. +- Click Create Credentials > API Key. +- Save this key for use in `GCLOUD_TESTS_API_KEY` as described below. + +#### Local Setup + +Once the two projects are created and configured, set the following environment +variables: + +- `GCLOUD_TESTS_GOLANG_PROJECT_ID`: Developers Console project's ID (e.g. +bamboo-shift-455) for the general project. +- `GCLOUD_TESTS_GOLANG_KEY`: The path to the JSON key file of the general +project's service account. +- `GCLOUD_TESTS_GOLANG_FIRESTORE_PROJECT_ID`: Developers Console project's ID +(e.g. doorway-cliff-677) for the Firestore project. +- `GCLOUD_TESTS_GOLANG_FIRESTORE_KEY`: The path to the JSON key file of the +Firestore project's service account. +- `GCLOUD_TESTS_GOLANG_KEYRING`: The full name of the keyring for the tests, +in the form +"projects/P/locations/L/keyRings/R". The creation of this is described below. +- `GCLOUD_TESTS_API_KEY`: API key for using the Translate API. +- `GCLOUD_TESTS_GOLANG_ZONE`: Compute Engine zone. + +Install the [gcloud command-line tool][gcloudcli] to your machine and use it to +create some resources used in integration tests. + +From the project's root directory: + +``` sh +# Sets the default project in your env. +$ gcloud config set project $GCLOUD_TESTS_GOLANG_PROJECT_ID + +# Authenticates the gcloud tool with your account. +$ gcloud auth login + +# Create the indexes used in the datastore integration tests. +$ gcloud datastore create-indexes datastore/testdata/index.yaml + +# Creates a Google Cloud storage bucket with the same name as your test project, +# and with the Stackdriver Logging service account as owner, for the sink +# integration tests in logging. +$ gsutil mb gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID +$ gsutil acl ch -g cloud-logs@google.com:O gs://$GCLOUD_TESTS_GOLANG_PROJECT_ID + +# Creates a PubSub topic for integration tests of storage notifications. +$ gcloud beta pubsub topics create go-storage-notification-test +# Next, go to the Pub/Sub dashboard in GCP console. Authorize the user +# "service-@gs-project-accounts.iam.gserviceaccount.com" +# as a publisher to that topic. + +# Creates a Spanner instance for the spanner integration tests. +$ gcloud beta spanner instances create go-integration-test --config regional-us-central1 --nodes 10 --description 'Instance for go client test' +# NOTE: Spanner instances are priced by the node-hour, so you may want to +# delete the instance after testing with 'gcloud beta spanner instances delete'. + +$ export MY_KEYRING=some-keyring-name +$ export MY_LOCATION=global +# Creates a KMS keyring, in the same location as the default location for your +# project's buckets. +$ gcloud kms keyrings create $MY_KEYRING --location $MY_LOCATION +# Creates two keys in the keyring, named key1 and key2. +$ gcloud kms keys create key1 --keyring $MY_KEYRING --location $MY_LOCATION --purpose encryption +$ gcloud kms keys create key2 --keyring $MY_KEYRING --location $MY_LOCATION --purpose encryption +# Sets the GCLOUD_TESTS_GOLANG_KEYRING environment variable. +$ export GCLOUD_TESTS_GOLANG_KEYRING=projects/$GCLOUD_TESTS_GOLANG_PROJECT_ID/locations/$MY_LOCATION/keyRings/$MY_KEYRING +# Authorizes Google Cloud Storage to encrypt and decrypt using key1. +gsutil kms authorize -p $GCLOUD_TESTS_GOLANG_PROJECT_ID -k $GCLOUD_TESTS_GOLANG_KEYRING/cryptoKeys/key1 +``` + +#### Running + +Once you've done the necessary setup, you can run the integration tests by +running: + +``` sh +$ go test -v cloud.google.com/go/... +``` + +#### Replay + +Some packages can record the RPCs during integration tests to a file for +subsequent replay. To record, pass the `-record` flag to `go test`. The +recording will be saved to the _package_`.replay` file. To replay integration +tests from a saved recording, the replay file must be present, the `-short` +flag must be passed to `go test`, and the `GCLOUD_TESTS_GOLANG_ENABLE_REPLAY` +environment variable must have a non-empty value. + +## Contributor License Agreements + +Before we can accept your pull requests you'll need to sign a Contributor +License Agreement (CLA): + +- **If you are an individual writing original source code** and **you own the +intellectual property**, then you'll need to sign an [individual CLA][indvcla]. +- **If you work for a company that wants to allow you to contribute your +work**, then you'll need to sign a [corporate CLA][corpcla]. + +You can sign these electronically (just scroll to the bottom). After that, +we'll be able to accept your pull requests. + +## Contributor Code of Conduct + +As contributors and maintainers of this project, +and in the interest of fostering an open and welcoming community, +we pledge to respect all people who contribute through reporting issues, +posting feature requests, updating documentation, +submitting pull requests or patches, and other activities. + +We are committed to making participation in this project +a harassment-free experience for everyone, +regardless of level of experience, gender, gender identity and expression, +sexual orientation, disability, personal appearance, +body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, +such as physical or electronic +addresses, without explicit permission +* Other unethical or unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct. +By adopting this Code of Conduct, +project maintainers commit themselves to fairly and consistently +applying these principles to every aspect of managing this project. +Project maintainers who do not follow or enforce the Code of Conduct +may be permanently removed from the project team. + +This code of conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior +may be reported by opening an issue +or contacting one or more of the project maintainers. + +This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, +available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) + +[gcloudcli]: https://developers.google.com/cloud/sdk/gcloud/ +[indvcla]: https://developers.google.com/open-source/cla/individual +[corpcla]: https://developers.google.com/open-source/cla/corporate diff --git a/vendor/cloud.google.com/go/CONTRIBUTORS b/vendor/cloud.google.com/go/CONTRIBUTORS new file mode 100644 index 00000000..3b3cbed9 --- /dev/null +++ b/vendor/cloud.google.com/go/CONTRIBUTORS @@ -0,0 +1,40 @@ +# People who have agreed to one of the CLAs and can contribute patches. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# https://developers.google.com/open-source/cla/individual +# https://developers.google.com/open-source/cla/corporate +# +# Names should be added to this file as: +# Name + +# Keep the list alphabetically sorted. + +Alexis Hunt +Andreas Litt +Andrew Gerrand +Brad Fitzpatrick +Burcu Dogan +Dave Day +David Sansome +David Symonds +Filippo Valsorda +Glenn Lewis +Ingo Oeser +James Hall +Johan Euphrosine +Jonathan Amsterdam +Kunpei Sakai +Luna Duclos +Magnus Hiie +Mario Castro +Michael McGreevy +Omar Jarjur +Paweł Knap +Péter Szilágyi +Sarah Adams +Thanatat Tamtan +Toby Burress +Tuo Shan +Tyler Treat diff --git a/vendor/cloud.google.com/go/LICENSE b/vendor/cloud.google.com/go/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/vendor/cloud.google.com/go/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/cloud.google.com/go/README.md b/vendor/cloud.google.com/go/README.md new file mode 100644 index 00000000..1c8c1604 --- /dev/null +++ b/vendor/cloud.google.com/go/README.md @@ -0,0 +1,505 @@ +# Google Cloud Client Libraries for Go + +[![GoDoc](https://godoc.org/cloud.google.com/go?status.svg)](https://godoc.org/cloud.google.com/go) + +Go packages for [Google Cloud Platform](https://cloud.google.com) services. + +``` go +import "cloud.google.com/go" +``` + +To install the packages on your system, *do not clone the repo*. Instead use + +``` +$ go get -u cloud.google.com/go/... +``` + +**NOTE:** Some of these packages are under development, and may occasionally +make backwards-incompatible changes. + +**NOTE:** Github repo is a mirror of [https://code.googlesource.com/gocloud](https://code.googlesource.com/gocloud). + + * [News](#news) + * [Supported APIs](#supported-apis) + * [Go Versions Supported](#go-versions-supported) + * [Authorization](#authorization) + * [Cloud Datastore](#cloud-datastore-) + * [Cloud Storage](#cloud-storage-) + * [Cloud Pub/Sub](#cloud-pub-sub-) + * [BigQuery](#cloud-bigquery-) + * [Stackdriver Logging](#stackdriver-logging-) + * [Cloud Spanner](#cloud-spanner-) + + +## News + +_7 August 2018_ + +As of November 1, the code in the repo will no longer support Go versions 1.8 +and earlier. No one other than AppEngine users should be on those old versions, +and AppEngine +[Standard](https://groups.google.com/forum/#!topic/google-appengine-go/e7oPNomd7ak) +and +[Flex](https://groups.google.com/forum/#!topic/google-appengine-go/wHsYtxvEbXI) +will stop supporting new deployments with those versions on that date. + + +Changes have been moved to [CHANGES](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CHANGES.md). + + +## Supported APIs + +Google API | Status | Package +---------------------------------------------|--------------|----------------------------------------------------------- +[Asset][cloud-asset] | alpha | [`godoc.org/cloud.google.com/go/asset/v1beta`][cloud-asset-ref] +[BigQuery][cloud-bigquery] | stable | [`godoc.org/cloud.google.com/go/bigquery`][cloud-bigquery-ref] +[Bigtable][cloud-bigtable] | stable | [`godoc.org/cloud.google.com/go/bigtable`][cloud-bigtable-ref] +[Cloudtasks][cloud-tasks] | beta | [`godoc.org/cloud.google.com/go/cloudtasks/apiv2beta3`][cloud-tasks-ref] +[Container][cloud-container] | stable | [`godoc.org/cloud.google.com/go/container/apiv1`][cloud-container-ref] +[ContainerAnalysis][cloud-containeranalysis] | beta | [`godoc.org/cloud.google.com/go/containeranalysis/apiv1beta1`][cloud-containeranalysis-ref] +[Dataproc][cloud-dataproc] | stable | [`godoc.org/cloud.google.com/go/dataproc/apiv1`][cloud-dataproc-ref] +[Datastore][cloud-datastore] | stable | [`godoc.org/cloud.google.com/go/datastore`][cloud-datastore-ref] +[Debugger][cloud-debugger] | alpha | [`godoc.org/cloud.google.com/go/debugger/apiv2`][cloud-debugger-ref] +[Dialogflow][cloud-dialogflow] | alpha | [`godoc.org/cloud.google.com/go/dialogflow/apiv2`][cloud-dialogflow-ref] +[Data Loss Prevention][cloud-dlp] | alpha | [`godoc.org/cloud.google.com/go/dlp/apiv2`][cloud-dlp-ref] +[ErrorReporting][cloud-errors] | alpha | [`godoc.org/cloud.google.com/go/errorreporting`][cloud-errors-ref] +[Firestore][cloud-firestore] | beta | [`godoc.org/cloud.google.com/go/firestore`][cloud-firestore-ref] +[IAM][cloud-iam] | stable | [`godoc.org/cloud.google.com/go/iam`][cloud-iam-ref] +[KMS][cloud-kms] | stable | [`godoc.org/cloud.google.com/go/kms`][cloud-kms-ref] +[Natural Language][cloud-natural-language] | stable | [`godoc.org/cloud.google.com/go/language/apiv1`][cloud-natural-language-ref] +[Logging][cloud-logging] | stable | [`godoc.org/cloud.google.com/go/logging`][cloud-logging-ref] +[Monitoring][cloud-monitoring] | alpha | [`godoc.org/cloud.google.com/go/monitoring/apiv3`][cloud-monitoring-ref] +[OS Login][cloud-oslogin] | alpha | [`cloud.google.com/compute/docs/oslogin/rest`][cloud-oslogin-ref] +[Pub/Sub][cloud-pubsub] | stable | [`godoc.org/cloud.google.com/go/pubsub`][cloud-pubsub-ref] +[Memorystore][cloud-memorystore] | stable | [`godoc.org/cloud.google.com/go/redis/apiv1beta1`][cloud-memorystore-ref] +[Spanner][cloud-spanner] | stable | [`godoc.org/cloud.google.com/go/spanner`][cloud-spanner-ref] +[Speech][cloud-speech] | stable | [`godoc.org/cloud.google.com/go/speech/apiv1`][cloud-speech-ref] +[Storage][cloud-storage] | stable | [`godoc.org/cloud.google.com/go/storage`][cloud-storage-ref] +[Text To Speech][cloud-texttospeech] | alpha | [`godoc.org/cloud.google.com/go/texttospeech/apiv1`][cloud-storage-ref] +[Trace][cloud-trace] | alpha | [`godoc.org/cloud.google.com/go/trace/apiv2`][cloud-translation-ref] +[Translation][cloud-translation] | stable | [`godoc.org/cloud.google.com/go/translate`][cloud-translation-ref] +[Video Intelligence][cloud-video] | alpha | [`godoc.org/cloud.google.com/go/videointelligence/apiv1beta1`][cloud-video-ref] +[Vision][cloud-vision] | stable | [`godoc.org/cloud.google.com/go/vision/apiv1`][cloud-vision-ref] + +> **Alpha status**: the API is still being actively developed. As a +> result, it might change in backward-incompatible ways and is not recommended +> for production use. +> +> **Beta status**: the API is largely complete, but still has outstanding +> features and bugs to be addressed. There may be minor backwards-incompatible +> changes where necessary. +> +> **Stable status**: the API is mature and ready for production use. We will +> continue addressing bugs and feature requests. + +Documentation and examples are available at +https://godoc.org/cloud.google.com/go + +Visit or join the +[google-api-go-announce group](https://groups.google.com/forum/#!forum/google-api-go-announce) +for updates on these packages. + +## Go Versions Supported + +We support the two most recent major versions of Go. If Google App Engine uses +an older version, we support that as well. + +## Authorization + +By default, each API will use [Google Application Default Credentials][default-creds] +for authorization credentials used in calling the API endpoints. This will allow your +application to run in many environments without requiring explicit configuration. + +[snip]:# (auth) +```go +client, err := storage.NewClient(ctx) +``` + +To authorize using a +[JSON key file](https://cloud.google.com/iam/docs/managing-service-account-keys), +pass +[`option.WithCredentialsFile`](https://godoc.org/google.golang.org/api/option#WithCredentialsFile) +to the `NewClient` function of the desired package. For example: + +[snip]:# (auth-JSON) +```go +client, err := storage.NewClient(ctx, option.WithCredentialsFile("path/to/keyfile.json")) +``` + +You can exert more control over authorization by using the +[`golang.org/x/oauth2`](https://godoc.org/golang.org/x/oauth2) package to +create an `oauth2.TokenSource`. Then pass +[`option.WithTokenSource`](https://godoc.org/google.golang.org/api/option#WithTokenSource) +to the `NewClient` function: +[snip]:# (auth-ts) +```go +tokenSource := ... +client, err := storage.NewClient(ctx, option.WithTokenSource(tokenSource)) +``` + +## Cloud Datastore [![GoDoc](https://godoc.org/cloud.google.com/go/datastore?status.svg)](https://godoc.org/cloud.google.com/go/datastore) + +- [About Cloud Datastore][cloud-datastore] +- [Activating the API for your project][cloud-datastore-activation] +- [API documentation][cloud-datastore-docs] +- [Go client documentation](https://godoc.org/cloud.google.com/go/datastore) +- [Complete sample program](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/datastore/tasks) + +### Example Usage + +First create a `datastore.Client` to use throughout your application: + +[snip]:# (datastore-1) +```go +client, err := datastore.NewClient(ctx, "my-project-id") +if err != nil { + log.Fatal(err) +} +``` + +Then use that client to interact with the API: + +[snip]:# (datastore-2) +```go +type Post struct { + Title string + Body string `datastore:",noindex"` + PublishedAt time.Time +} +keys := []*datastore.Key{ + datastore.NameKey("Post", "post1", nil), + datastore.NameKey("Post", "post2", nil), +} +posts := []*Post{ + {Title: "Post 1", Body: "...", PublishedAt: time.Now()}, + {Title: "Post 2", Body: "...", PublishedAt: time.Now()}, +} +if _, err := client.PutMulti(ctx, keys, posts); err != nil { + log.Fatal(err) +} +``` + +## Cloud Storage [![GoDoc](https://godoc.org/cloud.google.com/go/storage?status.svg)](https://godoc.org/cloud.google.com/go/storage) + +- [About Cloud Storage][cloud-storage] +- [API documentation][cloud-storage-docs] +- [Go client documentation](https://godoc.org/cloud.google.com/go/storage) +- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/storage) + +### Example Usage + +First create a `storage.Client` to use throughout your application: + +[snip]:# (storage-1) +```go +client, err := storage.NewClient(ctx) +if err != nil { + log.Fatal(err) +} +``` + +[snip]:# (storage-2) +```go +// Read the object1 from bucket. +rc, err := client.Bucket("bucket").Object("object1").NewReader(ctx) +if err != nil { + log.Fatal(err) +} +defer rc.Close() +body, err := ioutil.ReadAll(rc) +if err != nil { + log.Fatal(err) +} +``` + +## Cloud Pub/Sub [![GoDoc](https://godoc.org/cloud.google.com/go/pubsub?status.svg)](https://godoc.org/cloud.google.com/go/pubsub) + +- [About Cloud Pubsub][cloud-pubsub] +- [API documentation][cloud-pubsub-docs] +- [Go client documentation](https://godoc.org/cloud.google.com/go/pubsub) +- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/pubsub) + +### Example Usage + +First create a `pubsub.Client` to use throughout your application: + +[snip]:# (pubsub-1) +```go +client, err := pubsub.NewClient(ctx, "project-id") +if err != nil { + log.Fatal(err) +} +``` + +Then use the client to publish and subscribe: + +[snip]:# (pubsub-2) +```go +// Publish "hello world" on topic1. +topic := client.Topic("topic1") +res := topic.Publish(ctx, &pubsub.Message{ + Data: []byte("hello world"), +}) +// The publish happens asynchronously. +// Later, you can get the result from res: +... +msgID, err := res.Get(ctx) +if err != nil { + log.Fatal(err) +} + +// Use a callback to receive messages via subscription1. +sub := client.Subscription("subscription1") +err = sub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) { + fmt.Println(m.Data) + m.Ack() // Acknowledge that we've consumed the message. +}) +if err != nil { + log.Println(err) +} +``` + +## BigQuery [![GoDoc](https://godoc.org/cloud.google.com/go/bigquery?status.svg)](https://godoc.org/cloud.google.com/go/bigquery) + +- [About BigQuery][cloud-bigquery] +- [API documentation][cloud-bigquery-docs] +- [Go client documentation][cloud-bigquery-ref] +- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/bigquery) + +### Example Usage + +First create a `bigquery.Client` to use throughout your application: +[snip]:# (bq-1) +```go +c, err := bigquery.NewClient(ctx, "my-project-ID") +if err != nil { + // TODO: Handle error. +} +``` + +Then use that client to interact with the API: +[snip]:# (bq-2) +```go +// Construct a query. +q := c.Query(` + SELECT year, SUM(number) + FROM [bigquery-public-data:usa_names.usa_1910_2013] + WHERE name = "William" + GROUP BY year + ORDER BY year +`) +// Execute the query. +it, err := q.Read(ctx) +if err != nil { + // TODO: Handle error. +} +// Iterate through the results. +for { + var values []bigquery.Value + err := it.Next(&values) + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(values) +} +``` + + +## Stackdriver Logging [![GoDoc](https://godoc.org/cloud.google.com/go/logging?status.svg)](https://godoc.org/cloud.google.com/go/logging) + +- [About Stackdriver Logging][cloud-logging] +- [API documentation][cloud-logging-docs] +- [Go client documentation][cloud-logging-ref] +- [Complete sample programs](https://github.com/GoogleCloudPlatform/golang-samples/tree/master/logging) + +### Example Usage + +First create a `logging.Client` to use throughout your application: +[snip]:# (logging-1) +```go +ctx := context.Background() +client, err := logging.NewClient(ctx, "my-project") +if err != nil { + // TODO: Handle error. +} +``` + +Usually, you'll want to add log entries to a buffer to be periodically flushed +(automatically and asynchronously) to the Stackdriver Logging service. +[snip]:# (logging-2) +```go +logger := client.Logger("my-log") +logger.Log(logging.Entry{Payload: "something happened!"}) +``` + +Close your client before your program exits, to flush any buffered log entries. +[snip]:# (logging-3) +```go +err = client.Close() +if err != nil { + // TODO: Handle error. +} +``` + +## Cloud Spanner [![GoDoc](https://godoc.org/cloud.google.com/go/spanner?status.svg)](https://godoc.org/cloud.google.com/go/spanner) + +- [About Cloud Spanner][cloud-spanner] +- [API documentation][cloud-spanner-docs] +- [Go client documentation](https://godoc.org/cloud.google.com/go/spanner) + +### Example Usage + +First create a `spanner.Client` to use throughout your application: + +[snip]:# (spanner-1) +```go +client, err := spanner.NewClient(ctx, "projects/P/instances/I/databases/D") +if err != nil { + log.Fatal(err) +} +``` + +[snip]:# (spanner-2) +```go +// Simple Reads And Writes +_, err = client.Apply(ctx, []*spanner.Mutation{ + spanner.Insert("Users", + []string{"name", "email"}, + []interface{}{"alice", "a@example.com"})}) +if err != nil { + log.Fatal(err) +} +row, err := client.Single().ReadRow(ctx, "Users", + spanner.Key{"alice"}, []string{"email"}) +if err != nil { + log.Fatal(err) +} +``` + + +## Contributing + +Contributions are welcome. Please, see the +[CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md) +document for details. We're using Gerrit for our code reviews. Please don't open pull +requests against this repo, new pull requests will be automatically closed. + +Please note that this project is released with a Contributor Code of Conduct. +By participating in this project you agree to abide by its terms. +See [Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/CONTRIBUTING.md#contributor-code-of-conduct) +for more information. + +[cloud-datastore]: https://cloud.google.com/datastore/ +[cloud-datastore-ref]: https://godoc.org/cloud.google.com/go/datastore +[cloud-datastore-docs]: https://cloud.google.com/datastore/docs +[cloud-datastore-activation]: https://cloud.google.com/datastore/docs/activate + +[cloud-firestore]: https://cloud.google.com/firestore/ +[cloud-firestore-ref]: https://godoc.org/cloud.google.com/go/firestore +[cloud-firestore-docs]: https://cloud.google.com/firestore/docs +[cloud-firestore-activation]: https://cloud.google.com/firestore/docs/activate + +[cloud-pubsub]: https://cloud.google.com/pubsub/ +[cloud-pubsub-ref]: https://godoc.org/cloud.google.com/go/pubsub +[cloud-pubsub-docs]: https://cloud.google.com/pubsub/docs + +[cloud-storage]: https://cloud.google.com/storage/ +[cloud-storage-ref]: https://godoc.org/cloud.google.com/go/storage +[cloud-storage-docs]: https://cloud.google.com/storage/docs +[cloud-storage-create-bucket]: https://cloud.google.com/storage/docs/cloud-console#_creatingbuckets + +[cloud-bigtable]: https://cloud.google.com/bigtable/ +[cloud-bigtable-ref]: https://godoc.org/cloud.google.com/go/bigtable + +[cloud-bigquery]: https://cloud.google.com/bigquery/ +[cloud-bigquery-docs]: https://cloud.google.com/bigquery/docs +[cloud-bigquery-ref]: https://godoc.org/cloud.google.com/go/bigquery + +[cloud-logging]: https://cloud.google.com/logging/ +[cloud-logging-docs]: https://cloud.google.com/logging/docs +[cloud-logging-ref]: https://godoc.org/cloud.google.com/go/logging + +[cloud-monitoring]: https://cloud.google.com/monitoring/ +[cloud-monitoring-ref]: https://godoc.org/cloud.google.com/go/monitoring/apiv3 + +[cloud-vision]: https://cloud.google.com/vision +[cloud-vision-ref]: https://godoc.org/cloud.google.com/go/vision/apiv1 + +[cloud-language]: https://cloud.google.com/natural-language +[cloud-language-ref]: https://godoc.org/cloud.google.com/go/language/apiv1 + +[cloud-oslogin]: https://cloud.google.com/compute/docs/oslogin/rest +[cloud-oslogin-ref]: https://cloud.google.com/compute/docs/oslogin/rest + +[cloud-speech]: https://cloud.google.com/speech +[cloud-speech-ref]: https://godoc.org/cloud.google.com/go/speech/apiv1 + +[cloud-spanner]: https://cloud.google.com/spanner/ +[cloud-spanner-ref]: https://godoc.org/cloud.google.com/go/spanner +[cloud-spanner-docs]: https://cloud.google.com/spanner/docs + +[cloud-translation]: https://cloud.google.com/translation +[cloud-translation-ref]: https://godoc.org/cloud.google.com/go/translation + +[cloud-video]: https://cloud.google.com/video-intelligence/ +[cloud-video-ref]: https://godoc.org/cloud.google.com/go/videointelligence/apiv1beta1 + +[cloud-errors]: https://cloud.google.com/error-reporting/ +[cloud-errors-ref]: https://godoc.org/cloud.google.com/go/errorreporting + +[cloud-container]: https://cloud.google.com/containers/ +[cloud-container-ref]: https://godoc.org/cloud.google.com/go/container/apiv1 + +[cloud-debugger]: https://cloud.google.com/debugger/ +[cloud-debugger-ref]: https://godoc.org/cloud.google.com/go/debugger/apiv2 + +[cloud-dlp]: https://cloud.google.com/dlp/ +[cloud-dlp-ref]: https://godoc.org/cloud.google.com/go/dlp/apiv2beta1 + +[default-creds]: https://developers.google.com/identity/protocols/application-default-credentials + +[cloud-dataproc]: https://cloud.google.com/dataproc/ +[cloud-dataproc-docs]: https://cloud.google.com/dataproc/docs +[cloud-dataproc-ref]: https://godoc.org/cloud.google.com/go/dataproc/apiv1 + +[cloud-iam]: https://cloud.google.com/iam/ +[cloud-iam-docs]: https://cloud.google.com/iam/docs +[cloud-iam-ref]: https://godoc.org/cloud.google.com/go/iam + +[cloud-kms]: https://cloud.google.com/kms/ +[cloud-kms-docs]: https://cloud.google.com/kms/docs +[cloud-kms-ref]: https://godoc.org/cloud.google.com/go/kms/apiv1 + +[cloud-natural-language]: https://cloud.google.com/natural-language/ +[cloud-natural-language-docs]: https://cloud.google.com/natural-language/docs +[cloud-natural-language-ref]: https://godoc.org/cloud.google.com/go/language/apiv1 + +[cloud-memorystore]: https://cloud.google.com/memorystore/ +[cloud-memorystore-docs]: https://cloud.google.com/memorystore/docs +[cloud-memorystore-ref]: https://godoc.org/cloud.google.com/go/redis/apiv1beta1 + +[cloud-texttospeech]: https://cloud.google.com/texttospeech/ +[cloud-texttospeech-docs]: https://cloud.google.com/texttospeech/docs +[cloud-texttospeech-ref]: https://godoc.org/cloud.google.com/go/texttospeech/apiv1 + +[cloud-trace]: https://cloud.google.com/trace/ +[cloud-trace-docs]: https://cloud.google.com/trace/docs +[cloud-trace-ref]: https://godoc.org/cloud.google.com/go/trace/apiv1 + +[cloud-dialogflow]: https://cloud.google.com/dialogflow-enterprise/ +[cloud-dialogflow-docs]: https://cloud.google.com/dialogflow-enterprise/docs/ +[cloud-dialogflow-ref]: https://godoc.org/cloud.google.com/go/dialogflow/apiv2 + +[cloud-containeranalysis]: https://cloud.google.com/container-registry/docs/container-analysis +[cloud-containeranalysis-docs]: https://cloud.google.com/container-analysis/api/reference/rest/ +[cloud-containeranalysis-ref]: https://godoc.org/cloud.google.com/go/devtools/containeranalysis/apiv1beta1 + +[cloud-asset]: https://cloud.google.com/security-command-center/docs/how-to-asset-inventory +[cloud-asset-docs]: https://cloud.google.com/security-command-center/docs/how-to-asset-inventory +[cloud-asset-ref]: https://godoc.org/cloud.google.com/go/asset/apiv1 + +[cloud-tasks]: https://cloud.google.com/tasks/ +[cloud-tasks-ref]: https://godoc.org/cloud.google.com/go/cloudtasks/apiv2beta3 diff --git a/vendor/cloud.google.com/go/RELEASING.md b/vendor/cloud.google.com/go/RELEASING.md new file mode 100644 index 00000000..1028a261 --- /dev/null +++ b/vendor/cloud.google.com/go/RELEASING.md @@ -0,0 +1,47 @@ +# How to Create a New Release + +## Prerequisites + +Install [releasetool](https://github.com/googleapis/releasetool). + +## Create a release + +1. `cd` into the root directory, e.g., `~/go/src/cloud.google.com/go` +1. Checkout the master branch and ensure a clean and up-to-date state. + ``` + git checkout master + git pull --tags origin master + ``` +1. Run releasetool to generate a changelog from the last version. Note, + releasetool will prompt if the new version is a major, minor, or patch + version. + ``` + releasetool start --language go + ``` +1. Format the output to match CHANGES.md. +1. Submit a CL with the changes in CHANGES.md. The commit message should look + like this (where `v0.31.0` is instead the correct version number): + ``` + all: Release v0.31.0 + ``` +1. Wait for approval from all reviewers and then submit the CL. +1. Return to the master branch and pull the release commit. + ``` + git checkout master + git pull origin master + ``` +1. Tag the current commit with the new version (e.g., `v0.31.0`) + ``` + releasetool tag --language go + ``` +1. Publish the tag to GoogleSource (i.e., origin): + ``` + git push origin $NEW_VERSION + ``` +1. Visit the [releases page][releases] on GitHub and click the "Draft a new + release" button. For tag version, enter the tag published in the previous + step. For the release title, use the version (e.g., `v0.31.0`). For the + description, copy the changes added to CHANGES.md. + + +[releases]: https://github.com/GoogleCloudPlatform/google-cloud-go/releases diff --git a/vendor/cloud.google.com/go/asset/apiv1beta1/asset_client.go b/vendor/cloud.google.com/go/asset/apiv1beta1/asset_client.go new file mode 100644 index 00000000..4ff3bdb3 --- /dev/null +++ b/vendor/cloud.google.com/go/asset/apiv1beta1/asset_client.go @@ -0,0 +1,248 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package asset + +import ( + "context" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + assetpb "google.golang.org/genproto/googleapis/cloud/asset/v1beta1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + ExportAssets []gax.CallOption + BatchGetAssetsHistory []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("cloudasset.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + ExportAssets: retry[[2]string{"default", "non_idempotent"}], + BatchGetAssetsHistory: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Cloud Asset API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client assetpb.AssetServiceClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new asset service client. +// +// Asset service definition. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: assetpb.NewAssetServiceClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ExportAssets exports assets with time and resource types to a given Cloud Storage +// location. The output format is newline-delimited JSON. +// This API implements the [google.longrunning.Operation][google.longrunning.Operation] API allowing you +// to keep track of the export. +func (c *Client) ExportAssets(ctx context.Context, req *assetpb.ExportAssetsRequest, opts ...gax.CallOption) (*ExportAssetsOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ExportAssets[0:len(c.CallOptions.ExportAssets):len(c.CallOptions.ExportAssets)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ExportAssets(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &ExportAssetsOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// BatchGetAssetsHistory batch gets the update history of assets that overlap a time window. +// For RESOURCE content, this API outputs history with asset in both +// non-delete or deleted status. +// For IAM_POLICY content, this API outputs history when the asset and its +// attached IAM POLICY both exist. This can create gaps in the output history. +func (c *Client) BatchGetAssetsHistory(ctx context.Context, req *assetpb.BatchGetAssetsHistoryRequest, opts ...gax.CallOption) (*assetpb.BatchGetAssetsHistoryResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchGetAssetsHistory[0:len(c.CallOptions.BatchGetAssetsHistory):len(c.CallOptions.BatchGetAssetsHistory)], opts...) + var resp *assetpb.BatchGetAssetsHistoryResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.BatchGetAssetsHistory(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ExportAssetsOperation manages a long-running operation from ExportAssets. +type ExportAssetsOperation struct { + lro *longrunning.Operation +} + +// ExportAssetsOperation returns a new ExportAssetsOperation from a given name. +// The name must be that of a previously created ExportAssetsOperation, possibly from a different process. +func (c *Client) ExportAssetsOperation(name string) *ExportAssetsOperation { + return &ExportAssetsOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *ExportAssetsOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*assetpb.ExportAssetsResponse, error) { + var resp assetpb.ExportAssetsResponse + if err := op.lro.WaitWithInterval(ctx, &resp, 5000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *ExportAssetsOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*assetpb.ExportAssetsResponse, error) { + var resp assetpb.ExportAssetsResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *ExportAssetsOperation) Metadata() (*assetpb.ExportAssetsRequest, error) { + var meta assetpb.ExportAssetsRequest + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *ExportAssetsOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *ExportAssetsOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/asset/apiv1beta1/asset_client_example_test.go b/vendor/cloud.google.com/go/asset/apiv1beta1/asset_client_example_test.go new file mode 100644 index 00000000..bc2bd0d1 --- /dev/null +++ b/vendor/cloud.google.com/go/asset/apiv1beta1/asset_client_example_test.go @@ -0,0 +1,75 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package asset_test + +import ( + "context" + + asset "cloud.google.com/go/asset/apiv1beta1" + assetpb "google.golang.org/genproto/googleapis/cloud/asset/v1beta1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := asset.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_ExportAssets() { + ctx := context.Background() + c, err := asset.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &assetpb.ExportAssetsRequest{ + // TODO: Fill request struct fields. + } + op, err := c.ExportAssets(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_BatchGetAssetsHistory() { + ctx := context.Background() + c, err := asset.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &assetpb.BatchGetAssetsHistoryRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.BatchGetAssetsHistory(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/asset/apiv1beta1/doc.go b/vendor/cloud.google.com/go/asset/apiv1beta1/doc.go new file mode 100644 index 00000000..7ba09aff --- /dev/null +++ b/vendor/cloud.google.com/go/asset/apiv1beta1/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package asset is an auto-generated package for the +// Cloud Asset API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// The cloud asset API manages the history and inventory of cloud resources. +package asset // import "cloud.google.com/go/asset/apiv1beta1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/asset/apiv1beta1/mock_test.go b/vendor/cloud.google.com/go/asset/apiv1beta1/mock_test.go new file mode 100644 index 00000000..7e11118c --- /dev/null +++ b/vendor/cloud.google.com/go/asset/apiv1beta1/mock_test.go @@ -0,0 +1,266 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package asset + +import ( + assetpb "google.golang.org/genproto/googleapis/cloud/asset/v1beta1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockAssetServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + assetpb.AssetServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockAssetServer) ExportAssets(ctx context.Context, req *assetpb.ExportAssetsRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockAssetServer) BatchGetAssetsHistory(ctx context.Context, req *assetpb.BatchGetAssetsHistoryRequest) (*assetpb.BatchGetAssetsHistoryResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*assetpb.BatchGetAssetsHistoryResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockAsset mockAssetServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + assetpb.RegisterAssetServiceServer(serv, &mockAsset) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestAssetServiceExportAssets(t *testing.T) { + var expectedResponse *assetpb.ExportAssetsResponse = &assetpb.ExportAssetsResponse{} + + mockAsset.err = nil + mockAsset.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockAsset.resps = append(mockAsset.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var outputConfig *assetpb.OutputConfig = &assetpb.OutputConfig{} + var request = &assetpb.ExportAssetsRequest{ + Parent: formattedParent, + OutputConfig: outputConfig, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.ExportAssets(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAsset.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestAssetServiceExportAssetsError(t *testing.T) { + errCode := codes.PermissionDenied + mockAsset.err = nil + mockAsset.resps = append(mockAsset.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var outputConfig *assetpb.OutputConfig = &assetpb.OutputConfig{} + var request = &assetpb.ExportAssetsRequest{ + Parent: formattedParent, + OutputConfig: outputConfig, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.ExportAssets(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestAssetServiceBatchGetAssetsHistory(t *testing.T) { + var expectedResponse *assetpb.BatchGetAssetsHistoryResponse = &assetpb.BatchGetAssetsHistoryResponse{} + + mockAsset.err = nil + mockAsset.reqs = nil + + mockAsset.resps = append(mockAsset.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var contentType assetpb.ContentType = assetpb.ContentType_CONTENT_TYPE_UNSPECIFIED + var readTimeWindow *assetpb.TimeWindow = &assetpb.TimeWindow{} + var request = &assetpb.BatchGetAssetsHistoryRequest{ + Parent: formattedParent, + ContentType: contentType, + ReadTimeWindow: readTimeWindow, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BatchGetAssetsHistory(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAsset.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestAssetServiceBatchGetAssetsHistoryError(t *testing.T) { + errCode := codes.PermissionDenied + mockAsset.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var contentType assetpb.ContentType = assetpb.ContentType_CONTENT_TYPE_UNSPECIFIED + var readTimeWindow *assetpb.TimeWindow = &assetpb.TimeWindow{} + var request = &assetpb.BatchGetAssetsHistoryRequest{ + Parent: formattedParent, + ContentType: contentType, + ReadTimeWindow: readTimeWindow, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BatchGetAssetsHistory(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/asset/v1beta1/asset_client.go b/vendor/cloud.google.com/go/asset/v1beta1/asset_client.go new file mode 100644 index 00000000..4ff3bdb3 --- /dev/null +++ b/vendor/cloud.google.com/go/asset/v1beta1/asset_client.go @@ -0,0 +1,248 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package asset + +import ( + "context" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + assetpb "google.golang.org/genproto/googleapis/cloud/asset/v1beta1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + ExportAssets []gax.CallOption + BatchGetAssetsHistory []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("cloudasset.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + ExportAssets: retry[[2]string{"default", "non_idempotent"}], + BatchGetAssetsHistory: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Cloud Asset API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client assetpb.AssetServiceClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new asset service client. +// +// Asset service definition. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: assetpb.NewAssetServiceClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ExportAssets exports assets with time and resource types to a given Cloud Storage +// location. The output format is newline-delimited JSON. +// This API implements the [google.longrunning.Operation][google.longrunning.Operation] API allowing you +// to keep track of the export. +func (c *Client) ExportAssets(ctx context.Context, req *assetpb.ExportAssetsRequest, opts ...gax.CallOption) (*ExportAssetsOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ExportAssets[0:len(c.CallOptions.ExportAssets):len(c.CallOptions.ExportAssets)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ExportAssets(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &ExportAssetsOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// BatchGetAssetsHistory batch gets the update history of assets that overlap a time window. +// For RESOURCE content, this API outputs history with asset in both +// non-delete or deleted status. +// For IAM_POLICY content, this API outputs history when the asset and its +// attached IAM POLICY both exist. This can create gaps in the output history. +func (c *Client) BatchGetAssetsHistory(ctx context.Context, req *assetpb.BatchGetAssetsHistoryRequest, opts ...gax.CallOption) (*assetpb.BatchGetAssetsHistoryResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchGetAssetsHistory[0:len(c.CallOptions.BatchGetAssetsHistory):len(c.CallOptions.BatchGetAssetsHistory)], opts...) + var resp *assetpb.BatchGetAssetsHistoryResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.BatchGetAssetsHistory(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ExportAssetsOperation manages a long-running operation from ExportAssets. +type ExportAssetsOperation struct { + lro *longrunning.Operation +} + +// ExportAssetsOperation returns a new ExportAssetsOperation from a given name. +// The name must be that of a previously created ExportAssetsOperation, possibly from a different process. +func (c *Client) ExportAssetsOperation(name string) *ExportAssetsOperation { + return &ExportAssetsOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *ExportAssetsOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*assetpb.ExportAssetsResponse, error) { + var resp assetpb.ExportAssetsResponse + if err := op.lro.WaitWithInterval(ctx, &resp, 5000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *ExportAssetsOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*assetpb.ExportAssetsResponse, error) { + var resp assetpb.ExportAssetsResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *ExportAssetsOperation) Metadata() (*assetpb.ExportAssetsRequest, error) { + var meta assetpb.ExportAssetsRequest + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *ExportAssetsOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *ExportAssetsOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/asset/v1beta1/asset_client_example_test.go b/vendor/cloud.google.com/go/asset/v1beta1/asset_client_example_test.go new file mode 100644 index 00000000..160f1715 --- /dev/null +++ b/vendor/cloud.google.com/go/asset/v1beta1/asset_client_example_test.go @@ -0,0 +1,75 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package asset_test + +import ( + "context" + + asset "cloud.google.com/go/asset/v1beta1" + assetpb "google.golang.org/genproto/googleapis/cloud/asset/v1beta1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := asset.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_ExportAssets() { + ctx := context.Background() + c, err := asset.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &assetpb.ExportAssetsRequest{ + // TODO: Fill request struct fields. + } + op, err := c.ExportAssets(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_BatchGetAssetsHistory() { + ctx := context.Background() + c, err := asset.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &assetpb.BatchGetAssetsHistoryRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.BatchGetAssetsHistory(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/asset/v1beta1/doc.go b/vendor/cloud.google.com/go/asset/v1beta1/doc.go new file mode 100644 index 00000000..a2a639b4 --- /dev/null +++ b/vendor/cloud.google.com/go/asset/v1beta1/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package asset is an auto-generated package for the +// Cloud Asset API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// The cloud asset API manages the history and inventory of cloud resources. +package asset // import "cloud.google.com/go/asset/v1beta1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/asset/v1beta1/mock_test.go b/vendor/cloud.google.com/go/asset/v1beta1/mock_test.go new file mode 100644 index 00000000..7e11118c --- /dev/null +++ b/vendor/cloud.google.com/go/asset/v1beta1/mock_test.go @@ -0,0 +1,266 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package asset + +import ( + assetpb "google.golang.org/genproto/googleapis/cloud/asset/v1beta1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockAssetServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + assetpb.AssetServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockAssetServer) ExportAssets(ctx context.Context, req *assetpb.ExportAssetsRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockAssetServer) BatchGetAssetsHistory(ctx context.Context, req *assetpb.BatchGetAssetsHistoryRequest) (*assetpb.BatchGetAssetsHistoryResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*assetpb.BatchGetAssetsHistoryResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockAsset mockAssetServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + assetpb.RegisterAssetServiceServer(serv, &mockAsset) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestAssetServiceExportAssets(t *testing.T) { + var expectedResponse *assetpb.ExportAssetsResponse = &assetpb.ExportAssetsResponse{} + + mockAsset.err = nil + mockAsset.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockAsset.resps = append(mockAsset.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var outputConfig *assetpb.OutputConfig = &assetpb.OutputConfig{} + var request = &assetpb.ExportAssetsRequest{ + Parent: formattedParent, + OutputConfig: outputConfig, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.ExportAssets(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAsset.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestAssetServiceExportAssetsError(t *testing.T) { + errCode := codes.PermissionDenied + mockAsset.err = nil + mockAsset.resps = append(mockAsset.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var outputConfig *assetpb.OutputConfig = &assetpb.OutputConfig{} + var request = &assetpb.ExportAssetsRequest{ + Parent: formattedParent, + OutputConfig: outputConfig, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.ExportAssets(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestAssetServiceBatchGetAssetsHistory(t *testing.T) { + var expectedResponse *assetpb.BatchGetAssetsHistoryResponse = &assetpb.BatchGetAssetsHistoryResponse{} + + mockAsset.err = nil + mockAsset.reqs = nil + + mockAsset.resps = append(mockAsset.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var contentType assetpb.ContentType = assetpb.ContentType_CONTENT_TYPE_UNSPECIFIED + var readTimeWindow *assetpb.TimeWindow = &assetpb.TimeWindow{} + var request = &assetpb.BatchGetAssetsHistoryRequest{ + Parent: formattedParent, + ContentType: contentType, + ReadTimeWindow: readTimeWindow, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BatchGetAssetsHistory(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAsset.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestAssetServiceBatchGetAssetsHistoryError(t *testing.T) { + errCode := codes.PermissionDenied + mockAsset.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var contentType assetpb.ContentType = assetpb.ContentType_CONTENT_TYPE_UNSPECIFIED + var readTimeWindow *assetpb.TimeWindow = &assetpb.TimeWindow{} + var request = &assetpb.BatchGetAssetsHistoryRequest{ + Parent: formattedParent, + ContentType: contentType, + ReadTimeWindow: readTimeWindow, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BatchGetAssetsHistory(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/authexample_test.go b/vendor/cloud.google.com/go/authexample_test.go new file mode 100644 index 00000000..aafbe226 --- /dev/null +++ b/vendor/cloud.google.com/go/authexample_test.go @@ -0,0 +1,73 @@ +// Copyright 2016 Google LLC +// +// 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 cloud_test + +import ( + "context" + + "cloud.google.com/go/datastore" + "cloud.google.com/go/pubsub" + "golang.org/x/oauth2/google" + "google.golang.org/api/option" +) + +// Google Application Default Credentials is the recommended way to authorize +// and authenticate clients. +// +// For information on how to create and obtain Application Default Credentials, see +// https://developers.google.com/identity/protocols/application-default-credentials. +func Example_applicationDefaultCredentials() { + client, err := datastore.NewClient(context.Background(), "project-id") + if err != nil { + // TODO: handle error. + } + _ = client // Use the client. +} + +// You can use a file with credentials to authenticate and authorize, such as a JSON +// key file associated with a Google service account. Service Account keys can be +// created and downloaded from +// https://console.developers.google.com/permissions/serviceaccounts. +// +// This example uses the Datastore client, but the same steps apply to +// the other client libraries underneath this package. +func Example_credentialsFile() { + client, err := datastore.NewClient(context.Background(), + "project-id", option.WithCredentialsFile("/path/to/service-account-key.json")) + if err != nil { + // TODO: handle error. + } + _ = client // Use the client. +} + +// In some cases (for instance, you don't want to store secrets on disk), you can +// create credentials from in-memory JSON and use the WithCredentials option. +// +// The google package in this example is at golang.org/x/oauth2/google. +// +// This example uses the PubSub client, but the same steps apply to +// the other client libraries underneath this package. +func Example_credentialsFromJSON() { + ctx := context.Background() + creds, err := google.CredentialsFromJSON(ctx, []byte("JSON creds"), pubsub.ScopePubSub) + if err != nil { + // TODO: handle error. + } + client, err := pubsub.NewClient(ctx, "project-id", option.WithCredentials(creds)) + if err != nil { + // TODO: handle error. + } + _ = client // Use the client. +} diff --git a/vendor/cloud.google.com/go/bigquery/benchmarks/README.md b/vendor/cloud.google.com/go/bigquery/benchmarks/README.md new file mode 100644 index 00000000..c97f9d86 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/benchmarks/README.md @@ -0,0 +1,8 @@ +# BigQuery Benchmark +This directory contains benchmarks for BigQuery client. + +## Usage +`go run bench.go -- queries.json` + +BigQuery service caches requests so the benchmark should be run +at least twice, disregarding the first result. diff --git a/vendor/cloud.google.com/go/bigquery/benchmarks/bench.go b/vendor/cloud.google.com/go/bigquery/benchmarks/bench.go new file mode 100644 index 00000000..7d608c88 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/benchmarks/bench.go @@ -0,0 +1,85 @@ +// Copyright 2017 Google LLC +// +// 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. + +//+build ignore + +package main + +import ( + "context" + "encoding/json" + "flag" + "io/ioutil" + "log" + "time" + + "cloud.google.com/go/bigquery" + "google.golang.org/api/iterator" +) + +func main() { + flag.Parse() + + ctx := context.Background() + c, err := bigquery.NewClient(ctx, flag.Arg(0)) + if err != nil { + log.Fatal(err) + } + + queriesJSON, err := ioutil.ReadFile(flag.Arg(1)) + if err != nil { + log.Fatal(err) + } + + var queries []string + if err := json.Unmarshal(queriesJSON, &queries); err != nil { + log.Fatal(err) + } + + for _, q := range queries { + doQuery(ctx, c, q) + } +} + +func doQuery(ctx context.Context, c *bigquery.Client, qt string) { + startTime := time.Now() + q := c.Query(qt) + it, err := q.Read(ctx) + if err != nil { + log.Fatal(err) + } + + numRows, numCols := 0, 0 + var firstByte time.Duration + + for { + var values []bigquery.Value + err := it.Next(&values) + if err == iterator.Done { + break + } + if err != nil { + log.Fatal(err) + } + if numRows == 0 { + numCols = len(values) + firstByte = time.Since(startTime) + } else if numCols != len(values) { + log.Fatalf("got %d columns, want %d", len(values), numCols) + } + numRows++ + } + log.Printf("query %q: %d rows, %d cols, first byte %f sec, total %f sec", + qt, numRows, numCols, firstByte.Seconds(), time.Since(startTime).Seconds()) +} diff --git a/vendor/cloud.google.com/go/bigquery/benchmarks/queries.json b/vendor/cloud.google.com/go/bigquery/benchmarks/queries.json new file mode 100644 index 00000000..13fed38b --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/benchmarks/queries.json @@ -0,0 +1,10 @@ +[ + "SELECT * FROM `nyc-tlc.yellow.trips` LIMIT 10000", + "SELECT * FROM `nyc-tlc.yellow.trips` LIMIT 100000", + "SELECT * FROM `nyc-tlc.yellow.trips` LIMIT 1000000", + "SELECT title FROM `bigquery-public-data.samples.wikipedia` ORDER BY title LIMIT 1000", + "SELECT title, id, timestamp, contributor_ip FROM `bigquery-public-data.samples.wikipedia` WHERE title like 'Blo%' ORDER BY id", + "SELECT * FROM `bigquery-public-data.baseball.games_post_wide` ORDER BY gameId", + "SELECT * FROM `bigquery-public-data.samples.github_nested` WHERE repository.has_downloads ORDER BY repository.created_at LIMIT 10000", + "SELECT repo_name, path FROM `bigquery-public-data.github_repos.files` WHERE path LIKE '%.java' ORDER BY id LIMIT 1000000" +] diff --git a/vendor/cloud.google.com/go/bigquery/bigquery.go b/vendor/cloud.google.com/go/bigquery/bigquery.go new file mode 100644 index 00000000..83e160e3 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/bigquery.go @@ -0,0 +1,162 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "context" + "fmt" + "io" + "net/http" + "time" + + "cloud.google.com/go/internal" + "cloud.google.com/go/internal/version" + gax "github.com/googleapis/gax-go" + bq "google.golang.org/api/bigquery/v2" + "google.golang.org/api/googleapi" + "google.golang.org/api/option" + htransport "google.golang.org/api/transport/http" +) + +const ( + prodAddr = "https://www.googleapis.com/bigquery/v2/" + // Scope is the Oauth2 scope for the service. + Scope = "https://www.googleapis.com/auth/bigquery" + userAgent = "gcloud-golang-bigquery/20160429" +) + +var xGoogHeader = fmt.Sprintf("gl-go/%s gccl/%s", version.Go(), version.Repo) + +func setClientHeader(headers http.Header) { + headers.Set("x-goog-api-client", xGoogHeader) +} + +// Client may be used to perform BigQuery operations. +type Client struct { + // Location, if set, will be used as the default location for all subsequent + // dataset creation and job operations. A location specified directly in one of + // those operations will override this value. + Location string + + projectID string + bqs *bq.Service +} + +// NewClient constructs a new Client which can perform BigQuery operations. +// Operations performed via the client are billed to the specified GCP project. +func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) { + o := []option.ClientOption{ + option.WithEndpoint(prodAddr), + option.WithScopes(Scope), + option.WithUserAgent(userAgent), + } + o = append(o, opts...) + httpClient, endpoint, err := htransport.NewClient(ctx, o...) + if err != nil { + return nil, fmt.Errorf("bigquery: dialing: %v", err) + } + bqs, err := bq.New(httpClient) + if err != nil { + return nil, fmt.Errorf("bigquery: constructing client: %v", err) + } + bqs.BasePath = endpoint + c := &Client{ + projectID: projectID, + bqs: bqs, + } + return c, nil +} + +// Close closes any resources held by the client. +// Close should be called when the client is no longer needed. +// It need not be called at program exit. +func (c *Client) Close() error { + return nil +} + +// Calls the Jobs.Insert RPC and returns a Job. +func (c *Client) insertJob(ctx context.Context, job *bq.Job, media io.Reader) (*Job, error) { + call := c.bqs.Jobs.Insert(c.projectID, job).Context(ctx) + setClientHeader(call.Header()) + if media != nil { + call.Media(media) + } + var res *bq.Job + var err error + invoke := func() error { + res, err = call.Do() + return err + } + // A job with a client-generated ID can be retried; the presence of the + // ID makes the insert operation idempotent. + // We don't retry if there is media, because it is an io.Reader. We'd + // have to read the contents and keep it in memory, and that could be expensive. + // TODO(jba): Look into retrying if media != nil. + if job.JobReference != nil && media == nil { + err = runWithRetry(ctx, invoke) + } else { + err = invoke() + } + if err != nil { + return nil, err + } + return bqToJob(res, c) +} + +// Convert a number of milliseconds since the Unix epoch to a time.Time. +// Treat an input of zero specially: convert it to the zero time, +// rather than the start of the epoch. +func unixMillisToTime(m int64) time.Time { + if m == 0 { + return time.Time{} + } + return time.Unix(0, m*1e6) +} + +// runWithRetry calls the function until it returns nil or a non-retryable error, or +// the context is done. +// See the similar function in ../storage/invoke.go. The main difference is the +// reason for retrying. +func runWithRetry(ctx context.Context, call func() error) error { + // These parameters match the suggestions in https://cloud.google.com/bigquery/sla. + backoff := gax.Backoff{ + Initial: 1 * time.Second, + Max: 32 * time.Second, + Multiplier: 2, + } + return internal.Retry(ctx, backoff, func() (stop bool, err error) { + err = call() + if err == nil { + return true, nil + } + return !retryableError(err), err + }) +} + +// This is the correct definition of retryable according to the BigQuery team. It +// also considers 502 ("Bad Gateway") and 503 ("Service Unavailable") errors +// retryable; these are returned by systems between the client and the BigQuery +// service. +func retryableError(err error) bool { + e, ok := err.(*googleapi.Error) + if !ok { + return false + } + var reason string + if len(e.Errors) > 0 { + reason = e.Errors[0].Reason + } + return e.Code == http.StatusServiceUnavailable || e.Code == http.StatusBadGateway || reason == "backendError" || reason == "rateLimitExceeded" +} diff --git a/vendor/cloud.google.com/go/bigquery/bigquery.replay b/vendor/cloud.google.com/go/bigquery/bigquery.replay new file mode 100644 index 00000000..411f5621 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/bigquery.replay @@ -0,0 +1,38404 @@ +{ + "Initial": "IjIwMTgtMDktMTJUMDA6Mjc6NTkuNzk3NjI3WiI=", + "Version": "0.1", + "Entries": [ + { + "ID": "980cb64c0797dcf6", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "73" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "685f8583bc6a6414de00752f989fd5e7/11857414564190582814;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJkYXRhc2V0UmVmZXJlbmNlIjp7ImRhdGFzZXRJZCI6ImRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:01 GMT" + ], + "Etag": [ + "Ebkpq/E66/i28Qe6O1h+eQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RW0vDMBT+L/HRbWnamV5goGKRgTpWlT2IjDQ962KzpkvSDRn+d7PRiYgTCXk557smO1SJukAJykW5bkG/nxXMMgMW9RBYVrpNmlfNGqeUYuFHU6ATsjyH6WjkEGLPLFrJwfYbpW0/pH7SCcx9j0ReTPw5oWHsDvVDz/Pm7hJHNSAXd6KunMDS2sYkGG+320GpVCmBNcIMuFrhYyq88XGj1Rtwa/APQ9wZGvw/5w6VwQI01BxQsjvOxoc+/1Lp0ox/eQH00UOMczAGJS87pJV0HmiWjZ/SbN+8AS6YvNWqbdy8E5ppYUEbx/1iTGYPfxAm2/oEvjWgr9/TFRPSTQNKgzgOAjK86Ocksh5RKxszP4wrHpS8FOvlupJRrvJle1nABqRqQA9KJ7IRHFwR1dZ2/xvfvbL06uaPcBmw4pDutYe4BmaFqp/Eas8kFwENie9FZDj0nIBkxt6rQiwEFKcgih8U3Or5EX18AkY4zkG0AgAA" + } + }, + { + "ID": "9af0cd65340c90dd", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "205" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f399cfa3f1d7136a551f3f2097493c04/13421307512411877550;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI5ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoicmVjIiwidHlwZSI6IlJFQ09SRCJ9XX0sInRhYmxlUmVmZXJlbmNlIjp7ImRhdGFzZXRJZCI6ImRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIiwidGFibGVJZCI6InRfYmFkIn19Cg==" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:01 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:01 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAJ3MuwrDMAyF4VcRmjNk6OS1l7WQtXRQbJEIbKtIaaGYvHtd+gbdDh+cvyGbqWFov+EYbg2TFpKKAZesM2Uc0JhcvyL1RVlSp8LutHC3i3BOYBxBHLb3g2E6H6/TCebnBis5VAWPKxfC/T5g1NRfh3H8t7F/AHK97ia2AAAA" + } + }, + { + "ID": "6cbb24b766ef1832", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "360" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "542e8b993627b765d73906dd88bb91ca/15057539521024387390;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMDEifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:02 GMT" + ], + "Etag": [ + "vdO4qZ7X0ltNmhLXdZVKoA==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Q3U7CQBCF32W9Bbat2kITLkAbQ6xgSjUEY8jSHcpq2y3dRSSEd3daIRjEn2yaZmbOmfNlNuRVZJy4ZCrixRKK9Zlm0wRIjYBmMfbf+OBiMXZGRqL76dwf8fHjrey026gQpY8vkwh0PZeFrju25XKmmQI9sQyzabRMa2LaTgufbTmGYUzwMxtVxG8KXK4gmfkie8WIuda5cildrVaNWMo4AZYL1YhkSvfU9M2ieSFfINKKHiHRHZKi/2CjFZui/0GsNAHMoIAsAuJuyA6hd+IwqN/Ff07/RtknVPq/ebZ4s2gOKStBZgISroj7tCEZS5Ht84cb13lZDcOg179Bz2G+TNVh3uuH3o0XYCOVvGwE3r3XCb3rr5YCooMj8K4GwTXW36OnUiYHYXcw8L1On2yf8dXK3O5aAxqIQarSl1kcQnHcDuRqX0UFMC1kFopqv3l5bjumZTQtyymvBu+5KE4I7CYeqvQnTOk7yQWi8h927GDDTtf3SoeMqoXYehiS7QedIrM2NgMAAA==" + } + }, + { + "ID": "a510ea08c481a3ae", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "300" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "758d34cad742a2260a40540b8825ed4c/16621715035127374286;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X3ZpZXdfc3RhbmRhcmRzcWwifSwidmlldyI6eyJxdWVyeSI6IlNFTEVDVCBBUFBST1hfQ09VTlRfRElTVElOQ1QobmFtZSkgRlJPTSBgZHVsY2V0LXBvcnQtNzYyLmRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxLnRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMWAiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:02 GMT" + ], + "Etag": [ + "IU9J9oJPDjeqhBoIf+CQRA==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SXW+bMBSG/0rk3WzaGgNbQ4PUiyRlExVNMkK6SdNEXXwgbgET7BRFUf77jllyE2VrZXFxPnze5z14R55FxYlHHkW+3kCzfafZYwHkEwHNcswHy+HtUN7Ob55gvRrLIPs4+R6Nrq+xQ5h7fFOkoC9q2egLd+B4nGmmQCeOZV9ZQ9tJ7IE7xDNwXMuyEvzsvk5eBLSJ0qzirOFqXeA0BUUWiuoZZ660rpVHadu2/VzKvABWC9VPZUmPmPTFoXUjnyDVip4w0AODom+AoZ1fRc8ydbUIMmigSoF4O3LQDM5Yx/6D3t/q69pHha7/DMAet5KuoGRGORNQcEW8XztSsRJhSGYlZsK2NkEwjf1vfoSJUnKTmC7DcDQOfbL/jXOqTTneasD7xCJdGMoqj6E5TUeyPUZpA0wLWcWik7MvPw9c27GuHPfLJZYLpvSd5ALB+D9aDmz3gf8DI+PPOOl+IKYXfuhP4t5oPo9mP5PJbDmNk5tgEQfTSfzeePzQ+xrN7noPJ4vuv+mNmcX+r+MBiTYKQshZul3gtr2MFQpwV4VMO9+IuFyQ/R8LImghIwMAAA==" + } + }, + { + "ID": "db65a2b08c2602c0", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_standardsql?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "486ac6a31063a62a69550ff5148800cf/18185889454013635166;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_standardsql?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:03 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "784d3fc61a5bf80a", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "57785188fd79b8b1afd323f03d6b789a/1303602369383781102;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:03 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "f426edc670d5577a", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "360" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b497d801bf2d78375adcf41922e2aaa1/2939834378013067902;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMDIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:04 GMT" + ], + "Etag": [ + "aVGd/08ZfgAd0OMMsUuRCA==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Q3U7CQBCF32W9FXZbtWATLgo2hIQfU6oXGkOW7lBX227tLiIhvLvTUoJRVLJpmpk5Z86X2ZBXmQnikrmM35ZQrM8MnydAzgkYHmOf3/cFZe2HRewJNhmN9N0y6HmdDipk6RPLJALTyFVhGi3HdgU3XIOZ2cxqs2vLnllO6xqfY7cYYzP8rGYV8YfCxuUaksVQZq8Y8WxMrl1KV6tVM1YqToDnUjcjldI9NX23aV6oF4iMpt+QaI2k6QlstGLT9BTEShPAAgrIIiDuhtQIgyOHQX0dv5v+j7JPqPT/82zxZtEzpLwEWUhIhCbu44ZkPEW23Q83rvOymobBYNxHz2G+TPVhPhiHft8PsJEqUTYC/9b3Qv/mq6WA6OAI/N4kuMH6Z/RcqeQg7E4mQ98bk+0TvvMyt7s2gAbCSFUOVRaHUHxvB2q1r6ICuJEqC2W137q6cFqWzdqXllNeDT5yWRwROG08VOlPuDYjJSSiil921LCh1x36pUNF1UJs3U3J9hNdZMhoNgMAAA==" + } + }, + { + "ID": "90ada73fa5e59007", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0002?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d516c2ac032e3a48bf0a1e0b5d8144e0/4504008792604427022;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0002?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:04 GMT" + ], + "Etag": [ + "aVGd/08ZfgAd0OMMsUuRCA==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:04 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Q3U7CQBCF32W9FXZbtWATLgo2hIQfU6oXGkOW7lBX227tLiIhvLvTUoJRVLJpmpk5Z86X2ZBXmQnikrmM35ZQrM8MnydAzgkYHmOf3/cFZe2HRewJNhmN9N0y6HmdDipk6RPLJALTyFVhGi3HdgU3XIOZ2cxqs2vLnllO6xqfY7cYYzP8rGYV8YfCxuUaksVQZq8Y8WxMrl1KV6tVM1YqToDnUjcjldI9NX23aV6oF4iMpt+QaI2k6QlstGLT9BTEShPAAgrIIiDuhtQIgyOHQX0dv5v+j7JPqPT/82zxZtEzpLwEWUhIhCbu44ZkPEW23Q83rvOymobBYNxHz2G+TPVhPhiHft8PsJEqUTYC/9b3Qv/mq6WA6OAI/N4kuMH6Z/RcqeQg7E4mQ98bk+0TvvMyt7s2gAbCSFUOVRaHUHxvB2q1r6ICuJEqC2W137q6cFqWzdqXllNeDT5yWRwROG08VOlPuDYjJSSiil921LCh1x36pUNF1UJs3U3J9hNdZMhoNgMAAA==" + } + }, + { + "ID": "f43430b0feed2058", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "297" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ee7f6b6faed2317dcee67bbd26752eea/6068184311002315678;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJkYXRlIiwidHlwZSI6IkRBVEUifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X21ldGFkYXRhX3BhcnRpdGlvbl9ub2NsdXN0ZXJfMCJ9LCJ0aW1lUGFydGl0aW9uaW5nIjp7InR5cGUiOiJEQVkifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:05 GMT" + ], + "Etag": [ + "zx6p6pMjEHOdEb1CBpzDZQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Qa0/CMBSG/0v9KnSbYeASP4AQNcEbzg9qzFK2wyhsbW2L3MJ/93RcYgxGszTLOX3P+z49azLlIiMRGfL8YwZ6eWLZsABySsCyHPurRahCdTvpXd9nvaF/2VGr7uvjxQUquJvLZkUKtqaktrVmGEQZs8yATQLPb3nnfpD4YfMcvzBoep6X4PHrNinR3SkTxbTllkuRCJkWM2NBJx56GyhGfS6mmDC2VpmI0vl8Xs+lzAtgipt6Kku6h6afAVVaTiC1hv4gojsiQ/+BRqvXG/oPwko5gBFoECmQaE12BDdH1oL6Xfr29m+SfUKl/xNngxtLx1AyxzHiUGSGRG9rIliJaNsfGi6Vq57iwc3dFc4c7tH52323HffI5h09LS/hYR/IRe7cD6IXlypmZWdpAdOIWwqWfSnyGPTP9kDO91WqgTnDmFfhfuMsbPqB12r41aJgobg+IghbuBc3XzBjb2XG8Z3ZLx47yLjd6ffchEwrQ2w9P5HNFwKS7in1AgAA" + } + }, + { + "ID": "0765510b83893cc7", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_0?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7d9bfffe3d4510eb6dffd01cedb9d8e9/7704416319614825518;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_0?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:05 GMT" + ], + "Etag": [ + "zx6p6pMjEHOdEb1CBpzDZQ==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:05 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Qa0/CMBSG/0v9KnSbYeASP4AQNcEbzg9qzFK2wyhsbW2L3MJ/93RcYgxGszTLOX3P+z49azLlIiMRGfL8YwZ6eWLZsABySsCyHPurRahCdTvpXd9nvaF/2VGr7uvjxQUquJvLZkUKtqaktrVmGEQZs8yATQLPb3nnfpD4YfMcvzBoep6X4PHrNinR3SkTxbTllkuRCJkWM2NBJx56GyhGfS6mmDC2VpmI0vl8Xs+lzAtgipt6Kku6h6afAVVaTiC1hv4gojsiQ/+BRqvXG/oPwko5gBFoECmQaE12BDdH1oL6Xfr29m+SfUKl/xNngxtLx1AyxzHiUGSGRG9rIliJaNsfGi6Vq57iwc3dFc4c7tH52323HffI5h09LS/hYR/IRe7cD6IXlypmZWdpAdOIWwqWfSnyGPTP9kDO91WqgTnDmFfhfuMsbPqB12r41aJgobg+IghbuBc3XzBjb2XG8Z3ZLx47yLjd6ffchEwrQ2w9P5HNFwKS7in1AgAA" + } + }, + { + "ID": "a823337efd219e17", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "328" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ec07ce6d1719a5ac7d2076cc0ae53428/9268590734222961854;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjbHVzdGVyaW5nIjp7ImZpZWxkcyI6WyJuYW1lIl19LCJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJkYXRlIiwidHlwZSI6IkRBVEUifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X21ldGFkYXRhX3BhcnRpdGlvbl9jbHVzdGVyXzAifSwidGltZVBhcnRpdGlvbmluZyI6eyJ0eXBlIjoiREFZIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:05 GMT" + ], + "Etag": [ + "C+V5h/n8MzoudUQqXh2Awg==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Qb0vDMBDGv0t8qVvayrqu4Iv5BxGm6NaJIlKy9tZF26QmqXWOfXcvXTdElEkJJXfPPc8vtyKvXKQkJDOevVWglgeGzXIgRwQMy7B+dnjfW1ARXH/KKp3evT0svGGdnZyggtu5tMoTMJ1SKtPp+16YMsM0mNhz3MAZuF7s+v0Bfr7XdxwnxuN2TVygu1XGJVOGGy5FnOSVNqBiB5015PMRF6/ovzCm1CGldV13MymzHFjJdTeRBd0i03ePlkq+QGI0/cFDWx5N/wFGm7drupev0Y1hDgpEAiRckTb/6peVoL7N3nT3c2wTGv0emDVuK1lAwSzFnEOeahI+rYhgBYJtfmi3LO1tEo2vbi5xZtdH32/982F0QdbP6Gl4AbfbOC4y674TPdrUFqHt7ZI3xtZCVMXp0gAWid0ZXkdSZBGon+WxrLe3RAGziRFv6Nzesd93PSfoBT3bho+Sq18EfoBrs4KcaXMtU4446R8e7Sui4enowk7IpDHE0nRC1l8upTBxEAMAAA==" + } + }, + { + "ID": "80ba34868206e0a9", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_cluster_0?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "880e7aec0010ccba8cdd158b5db0d554/10832766248309171534;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_cluster_0?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:06 GMT" + ], + "Etag": [ + "C+V5h/n8MzoudUQqXh2Awg==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:06 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Qb0vDMBDGv0t8qVvayrqu4Iv5BxGm6NaJIlKy9tZF26QmqXWOfXcvXTdElEkJJXfPPc8vtyKvXKQkJDOevVWglgeGzXIgRwQMy7B+dnjfW1ARXH/KKp3evT0svGGdnZyggtu5tMoTMJ1SKtPp+16YMsM0mNhz3MAZuF7s+v0Bfr7XdxwnxuN2TVygu1XGJVOGGy5FnOSVNqBiB5015PMRF6/ovzCm1CGldV13MymzHFjJdTeRBd0i03ePlkq+QGI0/cFDWx5N/wFGm7drupev0Y1hDgpEAiRckTb/6peVoL7N3nT3c2wTGv0emDVuK1lAwSzFnEOeahI+rYhgBYJtfmi3LO1tEo2vbi5xZtdH32/982F0QdbP6Gl4AbfbOC4y674TPdrUFqHt7ZI3xtZCVMXp0gAWid0ZXkdSZBGon+WxrLe3RAGziRFv6Nzesd93PSfoBT3bho+Sq18EfoBrs4KcaXMtU4446R8e7Sui4enowk7IpDHE0nRC1l8upTBxEAMAAA==" + } + }, + { + "ID": "b704234edca9b8fb", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_0?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "66" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6cedf97d19885ea1952bea217912b062/12396941766707060190;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_0?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0aW1lUGFydGl0aW9uaW5nIjp7InJlcXVpcmVQYXJ0aXRpb25GaWx0ZXIiOnRydWUsInR5cGUiOiJEQVkifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:06 GMT" + ], + "Etag": [ + "Qq6PwWCacuA9Qx4rpKdzHQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Q3U7jMBCF38XcLnUSIG0jcVH+EWVFS9BqtUKRcabBkNipPdnQrfrujEMLqwoJFFnRjM8583mW7FnpnCXsQRXzBuxiB8VDCewHAxQF9Sfz+Kb9dSxkMxpOXvZtfZX/u5gcHpJCeV/elBJwtzYWd/txlOQChQPMoiAcBMMwysK4P6QvjvpBEGR0wh5mFaV7ZVYLiwqV0Zk2smwcgs0CynZQzsZKP9OER8TaJZy3bdsrjClKELVyPWkqvoHmfyNeW/MEEh3fIuJrIse/gca71zv+DcJOOYUZWNASWLJka4LLT9ZC+vX0t9uvSTYTOv2XOCvamHyESniOmYIydyz5s2RaVIT29qPARe2r23R6+fOcPO/3lPzf/ckoPWWre8pEVcHNZqDShU9/F/0mh4V5o+yH5kyVBMQStA2QXzfV0QKBWJhfGZVjo4sU7HZ7atpNJS0IH5WqDi082Iv7YRQMDsJujfBSK/uJIB7Q1ry/FA6vTa5oC/l2RjzY3/t4Zzo6Gp96h5FdILXubtnqFQd+F+MTAwAA" + } + }, + { + "ID": "9eb8ea4b663846cf", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_0?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "66" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a1c665a5f745fb91b0eb62eb81bd4d39/14033172675824719470;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_0?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0aW1lUGFydGl0aW9uaW5nIjp7InJlcXVpcmVQYXJ0aXRpb25GaWx0ZXIiOnRydWUsInR5cGUiOiJEQVkifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:07 GMT" + ], + "Etag": [ + "Qq6PwWCacuA9Qx4rpKdzHQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Q3U7jMBCF38XcLnUSIG0jcVH+EWVFS9BqtUKRcabBkNipPdnQrfrujEMLqwoJFFnRjM8583mW7FnpnCXsQRXzBuxiB8VDCewHAxQF9Sfz+Kb9dSxkMxpOXvZtfZX/u5gcHpJCeV/elBJwtzYWd/txlOQChQPMoiAcBMMwysK4P6QvjvpBEGR0wh5mFaV7ZVYLiwqV0Zk2smwcgs0CynZQzsZKP9OER8TaJZy3bdsrjClKELVyPWkqvoHmfyNeW/MEEh3fIuJrIse/gca71zv+DcJOOYUZWNASWLJka4LLT9ZC+vX0t9uvSTYTOv2XOCvamHyESniOmYIydyz5s2RaVIT29qPARe2r23R6+fOcPO/3lPzf/ckoPWWre8pEVcHNZqDShU9/F/0mh4V5o+yH5kyVBMQStA2QXzfV0QKBWJhfGZVjo4sU7HZ7atpNJS0IH5WqDi082Iv7YRQMDsJujfBSK/uJIB7Q1ry/FA6vTa5oC/l2RjzY3/t4Zzo6Gp96h5FdILXubtnqFQd+F+MTAwAA" + } + }, + { + "ID": "c95add736ab9d1e6", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "319" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "29c183417bd9a41705d5f1206ad2e624/15597348189927706366;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJkYXRlIiwidHlwZSI6IkRBVEUifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X21ldGFkYXRhX3BhcnRpdGlvbl9ub2NsdXN0ZXJfMSJ9LCJ0aW1lUGFydGl0aW9uaW5nIjp7ImV4cGlyYXRpb25NcyI6IjEwMDAiLCJ0eXBlIjoiREFZIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:08 GMT" + ], + "Etag": [ + "CmbmrifRYm5tbCPhInwXww==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Sb0vDMBDGv0t8q0tbWTcLvvDPkMEmMisoIiVrb11ck9TkZh1j391Lt4mKopRS7u655/kldM0WUhcsYVNZvizBrg5QTCtghwxQlNS/UFNl5WzyoLo4vbiZD3Vz3zSnp6SQfq9YVjngUW0sHvXiKCkECgeYRUHYD07CKAvj3gk9cdQLgiCjN+xgpsjdK7NaWJQojc60yaulQ7BZSN4OqtlI6gUlzBFrl3DeNE2nNKasQNTSdXKj+B6av0a8tuYZcnT8GxHfETn+DzTent7xfxC2ygnMwILOgSVrtiMY/nAtpN+lb6d/k+wTWv2fOBu6sXwOSniOmYSqcCx5XDMtFKFtP2S4qn11m06G11e08zEn50/zy7N0wDZP5IlSwc0+UOrSu3+IHvxP8lZLK/x0TIEsJHLPopfqfIXgWwFry5HRZQr2e3timn2VW2iNUtkihd3juBdGQd9fy5ekr4K4H/jQQ1YJh2NTSDp98YvHDj09Ox8N/IbJW0Nq3d2yzTs1dectCwMAAA==" + } + }, + { + "ID": "3f965a8f068217ae", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_1?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "4f1d86d1dec076b963ebac17778929eb/17161523704013916046;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_1?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:08 GMT" + ], + "Etag": [ + "CmbmrifRYm5tbCPhInwXww==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:08 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Sb0vDMBDGv0t8q0tbWTcLvvDPkMEmMisoIiVrb11ck9TkZh1j391Lt4mKopRS7u655/kldM0WUhcsYVNZvizBrg5QTCtghwxQlNS/UFNl5WzyoLo4vbiZD3Vz3zSnp6SQfq9YVjngUW0sHvXiKCkECgeYRUHYD07CKAvj3gk9cdQLgiCjN+xgpsjdK7NaWJQojc60yaulQ7BZSN4OqtlI6gUlzBFrl3DeNE2nNKasQNTSdXKj+B6av0a8tuYZcnT8GxHfETn+DzTent7xfxC2ygnMwILOgSVrtiMY/nAtpN+lb6d/k+wTWv2fOBu6sXwOSniOmYSqcCx5XDMtFKFtP2S4qn11m06G11e08zEn50/zy7N0wDZP5IlSwc0+UOrSu3+IHvxP8lZLK/x0TIEsJHLPopfqfIXgWwFry5HRZQr2e3timn2VW2iNUtkihd3juBdGQd9fy5ekr4K4H/jQQ1YJh2NTSDp98YvHDj09Ox8N/IbJW0Nq3d2yzTs1dectCwMAAA==" + } + }, + { + "ID": "8cca108b080f09a7", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "350" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9737a28ffd9a94c790e4d21b756d79c3/351010548028735261;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjbHVzdGVyaW5nIjp7ImZpZWxkcyI6WyJuYW1lIl19LCJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJkYXRlIiwidHlwZSI6IkRBVEUifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X21ldGFkYXRhX3BhcnRpdGlvbl9jbHVzdGVyXzEifSwidGltZVBhcnRpdGlvbmluZyI6eyJleHBpcmF0aW9uTXMiOiIxMDAwIiwidHlwZSI6IkRBWSJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:08 GMT" + ], + "Etag": [ + "Um0vgXNFPnsgRetR1JVLqA==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2TYU/bMBCG/4v3FWo7iKRE4kMRbGIqCIVs2oRQZJJr8EjsYF/pqqr/nXOaVoCYOkVWdL733vexlazYkzYVS9mDrp/n4JZfUD00wA4YoKpp/0crXupf119vjK8zwEx+/zl9npyekkKHuWrelICHnXV4mMRRWilUHrCIhByLExkVMk5O6ImjRAhR0JIjLFpyD8qiUw41amuKspl7BFdIcvbQzKbaPJH/I2LnU84Xi8WotrZuQHXaj0rb8i0yf4l45+wfKNHzDzx84PH8P8B4f3bP9/L1ugxm4MCUwNIVG/IvP7kS0g/Zm+5+jm1Cr98Ds6bbKh+hVYFipqGpPEvvVsyolsA2L7JbdqG6zbPL6280s+uT75v++SS/YOt78kTdws02Tps6uO9Ev8Pn8bfTToXuFQUySdyBZQAbJnY8m7hgbObt2RIhzAjWl1Nr6hzcx+3MLrZV6aBPynXPLI+P4kRGYjw+TuQ7lPeCeCwC1QFrlMcrW2nCqf7hMZwtn5xNL8KELXvD8APcsvUrDTs36SYDAAA=" + } + }, + { + "ID": "445bade5d50137e0", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_cluster_1?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0d432aded96e38da8905c95fb25e4564/1915186062114945197;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_cluster_1?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:08 GMT" + ], + "Etag": [ + "Um0vgXNFPnsgRetR1JVLqA==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:08 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2TYU/bMBCG/4v3FWo7iKRE4kMRbGIqCIVs2oRQZJJr8EjsYF/pqqr/nXOaVoCYOkVWdL733vexlazYkzYVS9mDrp/n4JZfUD00wA4YoKpp/0crXupf119vjK8zwEx+/zl9npyekkKHuWrelICHnXV4mMRRWilUHrCIhByLExkVMk5O6ImjRAhR0JIjLFpyD8qiUw41amuKspl7BFdIcvbQzKbaPJH/I2LnU84Xi8WotrZuQHXaj0rb8i0yf4l45+wfKNHzDzx84PH8P8B4f3bP9/L1ugxm4MCUwNIVG/IvP7kS0g/Zm+5+jm1Cr98Ds6bbKh+hVYFipqGpPEvvVsyolsA2L7JbdqG6zbPL6280s+uT75v++SS/YOt78kTdws02Tps6uO9Ev8Pn8bfTToXuFQUySdyBZQAbJnY8m7hgbObt2RIhzAjWl1Nr6hzcx+3MLrZV6aBPynXPLI+P4kRGYjw+TuQ7lPeCeCwC1QFrlMcrW2nCqf7hMZwtn5xNL8KELXvD8APcsvUrDTs36SYDAAA=" + } + }, + { + "ID": "2688d753acc14889", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_1?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "88" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "57e034e6879e2eb19e6b6f4e2740d838/3479361576217931837;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_1?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0aW1lUGFydGl0aW9uaW5nIjp7ImV4cGlyYXRpb25NcyI6IjEwMDAiLCJyZXF1aXJlUGFydGl0aW9uRmlsdGVyIjp0cnVlLCJ0eXBlIjoiREFZIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:09 GMT" + ], + "Etag": [ + "8TO8Wf0fa/hjrxMTaPa2aA==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2S7UvDMBDG/5f4VZe2atcV/DDxBWFTmRURkRLbaxdtk5pcnWPsf/fSbb4MQSml5O655/nl6IK9SJWzmD3J8rUFM99B8VQB22WAoqR6lFxFd4VXCD59Nu/jRFyLQAyPjkgh3VzeVhngXqMN7vXDIM4FCguYBp4feQM/SP2wP6AnDPqe56X0+j1Ma3J3yrQRBiVKrVKls6q1CCb1ydtCVYykeqGEKWJjY85ns1mv1LqsQDTS9jJd8w00fwt4Y/QzZGj5FhFfE1n+DzTe3d7yfxB2ygkUYEBlwOIFWxNc/LIW0q/TV92/STYJnf5PnCVtLJtCLRxHIaHKLYsfFkyJmtBWHzKcN+50k0wuLs9p5rNPzt/6J8PklC0fyRNlDdebQKlK5/4punc/yXsjjXDdMQUyn8ipauC1leZr8kxWhMliNC2Qq2rr4zmCG3BqOo60KhMw2+WJnm1OmYEuJpEdsH+4H/b9wIvc0n5w/BSEkbdCqoTFsc4l7Sbf9hgcHgy+bp8Mj0enbkJnnSGVbm/Y8gOqVItnKQMAAA==" + } + }, + { + "ID": "c46193b416ebd944", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_1?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "88" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "40668588deeee1e8f9c08456459f52a6/5115592485335591373;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_1?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0aW1lUGFydGl0aW9uaW5nIjp7ImV4cGlyYXRpb25NcyI6IjEwMDAiLCJyZXF1aXJlUGFydGl0aW9uRmlsdGVyIjp0cnVlLCJ0eXBlIjoiREFZIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:10 GMT" + ], + "Etag": [ + "8TO8Wf0fa/hjrxMTaPa2aA==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2S7UvDMBDG/5f4VZe2atcV/DDxBWFTmRURkRLbaxdtk5pcnWPsf/fSbb4MQSml5O655/nl6IK9SJWzmD3J8rUFM99B8VQB22WAoqR6lFxFd4VXCD59Nu/jRFyLQAyPjkgh3VzeVhngXqMN7vXDIM4FCguYBp4feQM/SP2wP6AnDPqe56X0+j1Ma3J3yrQRBiVKrVKls6q1CCb1ydtCVYykeqGEKWJjY85ns1mv1LqsQDTS9jJd8w00fwt4Y/QzZGj5FhFfE1n+DzTe3d7yfxB2ygkUYEBlwOIFWxNc/LIW0q/TV92/STYJnf5PnCVtLJtCLRxHIaHKLYsfFkyJmtBWHzKcN+50k0wuLs9p5rNPzt/6J8PklC0fyRNlDdebQKlK5/4punc/yXsjjXDdMQUyn8ipauC1leZr8kxWhMliNC2Qq2rr4zmCG3BqOo60KhMw2+WJnm1OmYEuJpEdsH+4H/b9wIvc0n5w/BSEkbdCqoTFsc4l7Sbf9hgcHgy+bp8Mj0enbkJnnSGVbm/Y8gOqVItnKQMAAA==" + } + }, + { + "ID": "3947399a50025c74", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "327" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "856cf4fa87aa306c877cc6e2b8c62f8d/6679768003733479773;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJkYXRlIiwidHlwZSI6IkRBVEUifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X21ldGFkYXRhX3BhcnRpdGlvbl9ub2NsdXN0ZXJfMiJ9LCJ0aW1lUGFydGl0aW9uaW5nIjp7InJlcXVpcmVQYXJ0aXRpb25GaWx0ZXIiOnRydWUsInR5cGUiOiJEQVkifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:10 GMT" + ], + "Etag": [ + "YXG38xz/xv8hcHEC59JSHw==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2QYU/jMAyG/0vuKyxt0bqtEh/gbgecBkJbTwIhVIXU63K0SUlcujHtv59TNkAIBIqiyPbr10+8ZvdK5yxhd6p4aMCufqC4K4HtMUBRUP766uRguHziy8fhQp6Of/ZHf2an7eEhKZTvy5tSAu7XxuL+II6SXKBwgFkUhMNgFEZZGA9GdOJoEARBRjfsYVaRu1dmtbCoUBmdaSPLxiHYLCJvB+V8ovQ9TVgg1i7hvG3bXmFMUYKoletJU/EdNH+MeG3NP5Do+DsiviVy/BtovPu9498g7JRTmIMFLYEla7YlOPtgLaTfTn+ufk2ym9Dpv8TZ0MbkAirhOeYKytyx5GbNtKgI7fkhw1Xto1k6Pbs4oZ6XOjm/qf86Ssdsc0ueqCq43A1UuvDuL6Jr6rDw0Cj7qvmtSgJiCdoGqF831fEKgVhYwLpwYnSRgn2fnpp2F0kLwlulqkML+wfxIIyCUdCPfRmWtbIfCOIhbc0LSuHw3OSKtpB/4rH9Qnp0PBn7DiM7Q0r9nbHNf9+6afUTAwAA" + } + }, + { + "ID": "c97d4b42a70d6c53", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_2?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5c53745b2528536c58418bf4e5628bed/8243943517819689709;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_2?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:11 GMT" + ], + "Etag": [ + "YXG38xz/xv8hcHEC59JSHw==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:11 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2QYU/jMAyG/0vuKyxt0bqtEh/gbgecBkJbTwIhVIXU63K0SUlcujHtv59TNkAIBIqiyPbr10+8ZvdK5yxhd6p4aMCufqC4K4HtMUBRUP766uRguHziy8fhQp6Of/ZHf2an7eEhKZTvy5tSAu7XxuL+II6SXKBwgFkUhMNgFEZZGA9GdOJoEARBRjfsYVaRu1dmtbCoUBmdaSPLxiHYLCJvB+V8ovQ9TVgg1i7hvG3bXmFMUYKoletJU/EdNH+MeG3NP5Do+DsiviVy/BtovPu9498g7JRTmIMFLYEla7YlOPtgLaTfTn+ufk2ym9Dpv8TZ0MbkAirhOeYKytyx5GbNtKgI7fkhw1Xto1k6Pbs4oZ6XOjm/qf86Ssdsc0ueqCq43A1UuvDuL6Jr6rDw0Cj7qvmtSgJiCdoGqF831fEKgVhYwLpwYnSRgn2fnpp2F0kLwlulqkML+wfxIIyCUdCPfRmWtbIfCOIhbc0LSuHw3OSKtpB/4rH9Qnp0PBn7DiM7Q0r9nbHNf9+6afUTAwAA" + } + }, + { + "ID": "1766891fef54164e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "358" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e50a8ef95ee2938cbab44d76b00606d4/9808117932427825789;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjbHVzdGVyaW5nIjp7ImZpZWxkcyI6WyJuYW1lIl19LCJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJkYXRlIiwidHlwZSI6IkRBVEUifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X21ldGFkYXRhX3BhcnRpdGlvbl9jbHVzdGVyXzIifSwidGltZVBhcnRpdGlvbmluZyI6eyJyZXF1aXJlUGFydGl0aW9uRmlsdGVyIjp0cnVlLCJ0eXBlIjoiREFZIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:11 GMT" + ], + "Etag": [ + "bw2VtXOtuq34WfDgiozLsA==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Qa0+DMBSG/0v9qiswZUrihy1TYzIvmXiLMaTCGVaBsvYgzmX/3VPGpjGaGUJIT9/Lw5mzV1kkLGBPMp1WoGdbKJ4yYNsMUKR2Xns3eHeB1bS7ezsZplJ9jEz/8JAU0vqSKosBd0qlcafne0EiUBjAyHPcfefA9SLX7x3Q43s9x3Eiet0ORjmlW2VUCo0SpSqiOKsMgo48SjaQTUayeKX8Z8TSBJzXdd1JlUozEKU0nVjlfIXM3zxeavUCMRr+g4e3PIb/A4w3/274Rr5GN4YJaChiYMGctf2nv6yE9G338nYzx6qh0W+AWdC24mfIhaWYSMgSw4KHOStETmDLD8XNSnu6Csen5yfkWd9T7rf7YT88YotHykSZw+WqThapTV+L7smhYVpJ/aU5lhkBsQB1BeRvAVvnmmtZawuKKh/MEGjIHNYcR6pIQ9A/x2NVr06xBmG7Qtmwu3tdv+d6tMSub3cG76XUvwj8fVqq9WfC4JlKJOEkf2S0/xj2B6Mj61BxE0ij6yu2+AQVMakrLgMAAA==" + } + }, + { + "ID": "1eaffcd03f4c7eb7", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_cluster_2?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f0f354c796d67b9a013ec190bbae60ea/11444349945352014349;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_cluster_2?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:11 GMT" + ], + "Etag": [ + "bw2VtXOtuq34WfDgiozLsA==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:11 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Qa0+DMBSG/0v9qiswZUrihy1TYzIvmXiLMaTCGVaBsvYgzmX/3VPGpjGaGUJIT9/Lw5mzV1kkLGBPMp1WoGdbKJ4yYNsMUKR2Xns3eHeB1bS7ezsZplJ9jEz/8JAU0vqSKosBd0qlcafne0EiUBjAyHPcfefA9SLX7x3Q43s9x3Eiet0ORjmlW2VUCo0SpSqiOKsMgo48SjaQTUayeKX8Z8TSBJzXdd1JlUozEKU0nVjlfIXM3zxeavUCMRr+g4e3PIb/A4w3/274Rr5GN4YJaChiYMGctf2nv6yE9G338nYzx6qh0W+AWdC24mfIhaWYSMgSw4KHOStETmDLD8XNSnu6Csen5yfkWd9T7rf7YT88YotHykSZw+WqThapTV+L7smhYVpJ/aU5lhkBsQB1BeRvAVvnmmtZawuKKh/MEGjIHNYcR6pIQ9A/x2NVr06xBmG7Qtmwu3tdv+d6tMSub3cG76XUvwj8fVqq9WfC4JlKJOEkf2S0/xj2B6Mj61BxE0ij6yu2+AQVMakrLgMAAA==" + } + }, + { + "ID": "0cb5ca046f491d65", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_2?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "67" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "25ee6d049695a91c06977f4bc2fc7251/13008525459438224285;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_2?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0aW1lUGFydGl0aW9uaW5nIjp7InJlcXVpcmVQYXJ0aXRpb25GaWx0ZXIiOmZhbHNlLCJ0eXBlIjoiREFZIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:12 GMT" + ], + "Etag": [ + "9JLvKRFOqSCdy3kebAb3IQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2QbU/CMBDHv0t9q3QbOtwSXuBjUHyC+cIYs5TtmJWuHW0nEsJ39zoBDTHRNE1zd//736+3JFMucxKTMS9mNejFnmVjAWSfgGUF5qOrwfv18OJuNjrNF+0pjHvjdv+h20UFd315LTKwB5XS9qATBnHOLDNg08Dzj73ID1I/7ER4wqDjeV6K12/ZtER3p0wrpi23XMlUqkzUxoJOA/Q2ICYDLqc44dXaysSUzufzVqFUIYBV3LQyVdINNH0PaKXVG2TW0B0iuiYy9B9otPm9of8gbJRDmIAGmQGJl2RN0P9lLahfT/+q/k2ymdDo/8RZ4cayVyiZ45hwELkh8fOSSFYi2teDhovKRaNk2L+9xJ5tHZ1/1M96yTlZvaCn5SXcbwZyWTj3regJOzTMaq6/NRdcIBCJJ0wYQANZlycLCwhDPNKEAyWLBPRueqjmmyjTwJxXwhs2/6gddvzAi7yj0JXho+L6F0F4jGtzAsGMvVE5xzXkux7B4WH0/dGkdzI4dx0qawwx9Tgiq095mnF8FAMAAA==" + } + }, + { + "ID": "b605b11c4bcb4c8c", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_2?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "67" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f35479138fbb77850d59826c9444d485/14572699874046360365;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_2?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0aW1lUGFydGl0aW9uaW5nIjp7InJlcXVpcmVQYXJ0aXRpb25GaWx0ZXIiOmZhbHNlLCJ0eXBlIjoiREFZIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:13 GMT" + ], + "Etag": [ + "9JLvKRFOqSCdy3kebAb3IQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2QbU/CMBDHv0t9q3QbOtwSXuBjUHyC+cIYs5TtmJWuHW0nEsJ39zoBDTHRNE1zd//736+3JFMucxKTMS9mNejFnmVjAWSfgGUF5qOrwfv18OJuNjrNF+0pjHvjdv+h20UFd315LTKwB5XS9qATBnHOLDNg08Dzj73ID1I/7ER4wqDjeV6K12/ZtER3p0wrpi23XMlUqkzUxoJOA/Q2ICYDLqc44dXaysSUzufzVqFUIYBV3LQyVdINNH0PaKXVG2TW0B0iuiYy9B9otPm9of8gbJRDmIAGmQGJl2RN0P9lLahfT/+q/k2ymdDo/8RZ4cayVyiZ45hwELkh8fOSSFYi2teDhovKRaNk2L+9xJ5tHZ1/1M96yTlZvaCn5SXcbwZyWTj3regJOzTMaq6/NRdcIBCJJ0wYQANZlycLCwhDPNKEAyWLBPRueqjmmyjTwJxXwhs2/6gddvzAi7yj0JXho+L6F0F4jGtzAsGMvVE5xzXkux7B4WH0/dGkdzI4dx0qawwx9Tgiq095mnF8FAMAAA==" + } + }, + { + "ID": "5c5c1bc9c25095f3", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "364" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7ad0141c20b01608a2e5904357eb25a7/16208931882658870461;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJkYXRlIiwidHlwZSI6IkRBVEUifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X21ldGFkYXRhX3BhcnRpdGlvbl9ub2NsdXN0ZXJfMyJ9LCJ0aW1lUGFydGl0aW9uaW5nIjp7ImV4cGlyYXRpb25NcyI6IjEwMDAiLCJmaWVsZCI6ImRhdGUiLCJyZXF1aXJlUGFydGl0aW9uRmlsdGVyIjp0cnVlLCJ0eXBlIjoiREFZIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:13 GMT" + ], + "Etag": [ + "1odn1p5QVJl0rHPxgDKafg==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2S0U7jMBBF/8X7CnWSqgmNxAMV7C5QEJTsSmiFIpNMg8Gxgz2hVFX/nXHaAkWLQJEVeebOvceWF+xB6pKl7FZWjy3Y+Q8UtwrYDgMUFdVDU+qwGVz+PVGB/X3xXB2eimm1v08K6efKVhWAu42xuJvEUVoKFA4wj4JwLxiGUR7GyZC+OEqCIMhphT3Ma3L3yrwRFiVKo3NtCtU6BJv3yduBmo6lfqCEO8TGpZzPZrNeZUylQDTS9QpT8w00f4p4Y809FOj4ByK+JnL8G2i8O73j3yDslBOYggVdAEsXbE1w/J9rIf06fdX9mmST0Om/xFnSjRV3UAvPMZWgSsfSfwumRU1oqx8Zzhu/u8omx+e/aOa1T87v+ocH2RFb3pAnyhouNoFSV979VXTtH8lzI63w3TPnHwuRU7UDeLO18NhK+2b0UyqiZinaFihEt/VojuDn/TBtx0ZXGdiP5YmZbXaFhS41kx1/OOjHSRgFw34yGG5hbQvivWBFqITDM1NKIi0/8VifMzsYjY/8hCk6Qyr9uWLLFwSoiPA4AwAA" + } + }, + { + "ID": "97223d6119ee3090", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_3?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "45f20642542d4cba8be8697cff96bff5/17773106301561908301;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_3?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:14 GMT" + ], + "Etag": [ + "1odn1p5QVJl0rHPxgDKafg==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:14 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2S0U7jMBBF/8X7CnWSqgmNxAMV7C5QEJTsSmiFIpNMg8Gxgz2hVFX/nXHaAkWLQJEVeebOvceWF+xB6pKl7FZWjy3Y+Q8UtwrYDgMUFdVDU+qwGVz+PVGB/X3xXB2eimm1v08K6efKVhWAu42xuJvEUVoKFA4wj4JwLxiGUR7GyZC+OEqCIMhphT3Ma3L3yrwRFiVKo3NtCtU6BJv3yduBmo6lfqCEO8TGpZzPZrNeZUylQDTS9QpT8w00f4p4Y809FOj4ByK+JnL8G2i8O73j3yDslBOYggVdAEsXbE1w/J9rIf06fdX9mmST0Om/xFnSjRV3UAvPMZWgSsfSfwumRU1oqx8Zzhu/u8omx+e/aOa1T87v+ocH2RFb3pAnyhouNoFSV979VXTtH8lzI63w3TPnHwuRU7UDeLO18NhK+2b0UyqiZinaFihEt/VojuDn/TBtx0ZXGdiP5YmZbXaFhS41kx1/OOjHSRgFw34yGG5hbQvivWBFqITDM1NKIi0/8VifMzsYjY/8hCk6Qyr9uWLLFwSoiPA4AwAA" + } + }, + { + "ID": "b7ed82181777415e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "395" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "03ba4cd812992df7148ab17eec43108b/890819216915277277;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjbHVzdGVyaW5nIjp7ImZpZWxkcyI6WyJuYW1lIl19LCJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJkYXRlIiwidHlwZSI6IkRBVEUifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X21ldGFkYXRhX3BhcnRpdGlvbl9jbHVzdGVyXzMifSwidGltZVBhcnRpdGlvbmluZyI6eyJleHBpcmF0aW9uTXMiOiIxMDAwIiwiZmllbGQiOiJkYXRlIiwicmVxdWlyZVBhcnRpdGlvbkZpbHRlciI6dHJ1ZSwidHlwZSI6IkRBWSJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:14 GMT" + ], + "Etag": [ + "/YKhdoDcqbsXlvoetiy/yQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Sb2+bMBDGv4v3do2BbNAg9UWrdlO1dNpSJrWaJuSYC/FqMLGPpijKd9+ZkPSPNmVCCPnuuef5ncWGPai6YCmbq3LVgu3eoZhrYO8ZoCipzu+/LAtzKVdzd6cfDaDqePf97IwUys8VrZaAJ42xeJLEUVoIFA4wj4LwNJiEUR7GyYSeOEqCIMjpDUeYV+TulXkjLCpUps6lbh2Czcfk7EAvpqp+IP8lYuNSztfr9ag0ptQgGuVG0lR8j8wfI95Y8xskOv6Ghw88jv8HGO93d/woX6+bwQIs1BJYumFD/vVfroT0Q/aue5xjn9Drj8Bs6bbkEirhKRYKdOFY+nPDalER2O5Ddl3jT7fZ7PrrZ5o59Mn3Rf/yPLti21/kiaqCb/s4VZfe/SC697/HU6Os8N0bCmQhcVO1B3i2tbBqlX02+qQ0UbMUbQsUMmwx2B/gd2yeom6riw7BB3h3Ok5NXWZg35ZnZr0/SQs9Vqb6BcOP4zgJo2DyYZyEr7hfC+LTYLeCFg5vTKEIp/iHx3AR2fnF9MpPGNkbUunHLdv+AaY46OhTAwAA" + } + }, + { + "ID": "8b90d2c1355ea175", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_cluster_3?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "c8df72d52cef6a6602b6d833ce1b0ead/2454994731018263917;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_cluster_3?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:14 GMT" + ], + "Etag": [ + "/YKhdoDcqbsXlvoetiy/yQ==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:14 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Sb2+bMBDGv4v3do2BbNAg9UWrdlO1dNpSJrWaJuSYC/FqMLGPpijKd9+ZkPSPNmVCCPnuuef5ncWGPai6YCmbq3LVgu3eoZhrYO8ZoCipzu+/LAtzKVdzd6cfDaDqePf97IwUys8VrZaAJ42xeJLEUVoIFA4wj4LwNJiEUR7GyYSeOEqCIMjpDUeYV+TulXkjLCpUps6lbh2Czcfk7EAvpqp+IP8lYuNSztfr9ag0ptQgGuVG0lR8j8wfI95Y8xskOv6Ghw88jv8HGO93d/woX6+bwQIs1BJYumFD/vVfroT0Q/aue5xjn9Drj8Bs6bbkEirhKRYKdOFY+nPDalER2O5Ddl3jT7fZ7PrrZ5o59Mn3Rf/yPLti21/kiaqCb/s4VZfe/SC697/HU6Os8N0bCmQhcVO1B3i2tbBqlX02+qQ0UbMUbQsUMmwx2B/gd2yeom6riw7BB3h3Ok5NXWZg35ZnZr0/SQs9Vqb6BcOP4zgJo2DyYZyEr7hfC+LTYLeCFg5vTKEIp/iHx3AR2fnF9MpPGNkbUunHLdv+AaY46OhTAwAA" + } + }, + { + "ID": "a47fe645e39c0eb7", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_3?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "89" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e584c0fe2d77631ba8c00ba616d0aaa7/4091225640135923453;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_3?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0aW1lUGFydGl0aW9uaW5nIjp7ImV4cGlyYXRpb25NcyI6IjEwMDAiLCJyZXF1aXJlUGFydGl0aW9uRmlsdGVyIjpmYWxzZSwidHlwZSI6IkRBWSJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:15 GMT" + ], + "Etag": [ + "SqqtLTUHThoU/2nKFngQVw==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SYWvbMBCG/4v2dY1sp7EbQz+0rN3K0rElzmCMYVT74miVJUc6zw0h/30nJ2nWMGgxxtzde+/7SHjDHqUuWcoeZLVqwa7foXhQwN4zQFFRf7Za4SSbf8qWZs4j/flWV9++d5eXpJB+r2xVAXjWGItnSRylpUDhAPMoCC+CcRjlYZyM6YmjJAiCnN5wgHlN7l6ZN8KiRGl0rk2hWodg8yF5O1CLidSPlLBEbFzKedd1g8qYSoFopBsUpuYHaP4n4o01v6FAx0+I+J7I8Teg8f70jr+BsFdOYQEWdAEs3bA9wd1/roX0+/Td9HWSQ0KvfxVnSzdWLKEWnmMhQZWOpT83TIua0HYfMlw3vppl07svH2nneU7O/8w/XGU3bPuLPFHW8PUQKHXl3Z9FP/xP8tRIK/z0ngJZSOTU7QGOthZWrbRHo1upiJqlC6EcUIpu6+s1gjfw21ROjK4ysKftqekOVWGhj81kf4BwNIyTMArGw2Q0fsH1UhBfBDtEJRzem1ISannqMTo/T463kV1dT278hil6Q2rNZ2z7F22kQj85AwAA" + } + }, + { + "ID": "7fbe6c238d603b82", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_3?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "89" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7b280fe49a46d59a4f83399c58b0dd08/5655119687852068493;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_3?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0aW1lUGFydGl0aW9uaW5nIjp7ImV4cGlyYXRpb25NcyI6IjEwMDAiLCJyZXF1aXJlUGFydGl0aW9uRmlsdGVyIjpmYWxzZSwidHlwZSI6IkRBWSJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:16 GMT" + ], + "Etag": [ + "SqqtLTUHThoU/2nKFngQVw==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SYWvbMBCG/4v2dY1sp7EbQz+0rN3K0rElzmCMYVT74miVJUc6zw0h/30nJ2nWMGgxxtzde+/7SHjDHqUuWcoeZLVqwa7foXhQwN4zQFFRf7Za4SSbf8qWZs4j/flWV9++d5eXpJB+r2xVAXjWGItnSRylpUDhAPMoCC+CcRjlYZyM6YmjJAiCnN5wgHlN7l6ZN8KiRGl0rk2hWodg8yF5O1CLidSPlLBEbFzKedd1g8qYSoFopBsUpuYHaP4n4o01v6FAx0+I+J7I8Teg8f70jr+BsFdOYQEWdAEs3bA9wd1/roX0+/Td9HWSQ0KvfxVnSzdWLKEWnmMhQZWOpT83TIua0HYfMlw3vppl07svH2nneU7O/8w/XGU3bPuLPFHW8PUQKHXl3Z9FP/xP8tRIK/z0ngJZSOTU7QGOthZWrbRHo1upiJqlC6EcUIpu6+s1gjfw21ROjK4ysKftqekOVWGhj81kf4BwNIyTMArGw2Q0fsH1UhBfBDtEJRzem1ISannqMTo/T463kV1dT278hil6Q2rNZ2z7F22kQj85AwAA" + } + }, + { + "ID": "a8fda36b16f09836", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_3?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ba62debb1070c40309664abab88452eb/7219295201938278173;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_3?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:16 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "9db4399650c6bd20", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_2?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "619229e136721969c480bb0ae086354a/8855526111072714669;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_2?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:16 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "fa95dcfbb52c0340", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_1?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "43ce7cfb6f6e964ff2b2b1f4fbf9f67a/10419701625158924349;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_1?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:16 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "a2cfb47d28ae73ae", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_0?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b255a962c924c4e8650bea2ec6b01e2e/11983877143556813005;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_metadata_partition_nocluster_0?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:17 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "f40911a7bc1b8cbf", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0002?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5dcd0028df3d197da03e0adeba7b66dc/13548051558148172125;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0002?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:17 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "dbf48f706b6276d4", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "111" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b66e7ee7f430f4bdf8a209ce4837f505/15184283566777459181;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJkYXRhc2V0UmVmZXJlbmNlIjp7ImRhdGFzZXRJZCI6ImRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAyIn0sImZyaWVuZGx5TmFtZSI6Im5hbWUiLCJsb2NhdGlvbiI6IkVVIn0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:17 GMT" + ], + "Etag": [ + "mRHxZUkAQvNUd/ftY8bgYw==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ra0vzMBT+L/HrtvSivYGg4tCBTiyOoSIjTU672LTpknR9x/C/v+moIqIiIQTOeW7nZI9KXjOUoIwXmxbU7ogRQzQYNEJgSGE7VXr972lRnt9v5wuGc/MYZcVjd3pqEbxnslZQMONGKjMOAy8ZBFae40ZO7HorNwhjewIvdBxnZa9nqRpEfsPr0gqsjWl0gnHXdZNCykIAabieUFnh91R46+FGyVegRuMvhngw1PhvzgMqhRwU1BRQsn+vzQ7z/EllSDP7ZgPobYRyxaFmYjcnlTVAdf+MEKEUtEbJ8x4pKfrGMp09TNN+Hw1QTsSVkm1j64P8UnEDSlvFD8bdcv4L4a6rf8C3GtTFbloRLmzVDwI/jn3fPT4ZZ25kHFdWJiZeGJfUL2jBN+tNKaJMZuv2jMEWhGxATQorsuUU7CCyrU3/R5+90un55S/hUiDskO5lhKgCYrisH/hhQe6JH4Su58Rh5EdWQBBtbiXjOQf2E0TSg4JtTRfo7T8DWVYTygIAAA==" + } + }, + { + "ID": "2424a0b67d83d843", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0002?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b7a557f7983b925909dc839d4e19a669/16748459080863668861;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0002?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:18 GMT" + ], + "Etag": [ + "mRHxZUkAQvNUd/ftY8bgYw==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:18 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ra0vzMBT+L/HrtvSivYGg4tCBTiyOoSIjTU672LTpknR9x/C/v+moIqIiIQTOeW7nZI9KXjOUoIwXmxbU7ogRQzQYNEJgSGE7VXr972lRnt9v5wuGc/MYZcVjd3pqEbxnslZQMONGKjMOAy8ZBFae40ZO7HorNwhjewIvdBxnZa9nqRpEfsPr0gqsjWl0gnHXdZNCykIAabieUFnh91R46+FGyVegRuMvhngw1PhvzgMqhRwU1BRQsn+vzQ7z/EllSDP7ZgPobYRyxaFmYjcnlTVAdf+MEKEUtEbJ8x4pKfrGMp09TNN+Hw1QTsSVkm1j64P8UnEDSlvFD8bdcv4L4a6rf8C3GtTFbloRLmzVDwI/jn3fPT4ZZ25kHFdWJiZeGJfUL2jBN+tNKaJMZuv2jMEWhGxATQorsuUU7CCyrU3/R5+90un55S/hUiDskO5lhKgCYrisH/hhQe6JH4Su58Rh5EdWQBBtbiXjOQf2E0TSg4JtTRfo7T8DWVYTygIAAA==" + } + }, + { + "ID": "20bebc801be43ae3", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0002?alt=json\u0026deleteContents=false\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "38e4a3ba45701d68375d0ecaee89cbcb/18312633499766706701;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0002?alt=json\u0026deleteContents=false\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:18 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "c08ad1aa5eb4217e", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ab639812455c7a2a01d3535badfc75ae/1502402909663152797;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:18 GMT" + ], + "Etag": [ + "Ebkpq/E66/i28Qe6O1h+eQ==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:18 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RW0vDMBT+L/HRbWnamV5goGKRgTpWlT2IjDQ962KzpkvSDRn+d7PRiYgTCXk557smO1SJukAJykW5bkG/nxXMMgMW9RBYVrpNmlfNGqeUYuFHU6ATsjyH6WjkEGLPLFrJwfYbpW0/pH7SCcx9j0ReTPw5oWHsDvVDz/Pm7hJHNSAXd6KunMDS2sYkGG+320GpVCmBNcIMuFrhYyq88XGj1Rtwa/APQ9wZGvw/5w6VwQI01BxQsjvOxoc+/1Lp0ox/eQH00UOMczAGJS87pJV0HmiWjZ/SbN+8AS6YvNWqbdy8E5ppYUEbx/1iTGYPfxAm2/oEvjWgr9/TFRPSTQNKgzgOAjK86Ocksh5RKxszP4wrHpS8FOvlupJRrvJle1nABqRqQA9KJ7IRHFwR1dZ2/xvfvbL06uaPcBmw4pDutYe4BmaFqp/Eas8kFwENie9FZDj0nIBkxt6rQiwEFKcgih8U3Or5EX18AkY4zkG0AgAA" + } + }, + { + "ID": "cc4ae0abca1487bc", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/does_not_exist?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "806a29b5af1dd2c8b2ea275f82fafac2/3066578423749362477;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/does_not_exist?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:19 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:19 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKXMQQrCQAyF4asMWbcgUizMWlx6AZESm1gK04kkKQhD7+6UHsHd44P/FWBVUYjlGAbxUYBkwTlDhCnJCxM0oIwmu2Txm6yZqi1shhNXvIuH964xXNHR2AOtaWRvP6Le9pdzJGEbajzwdzaH7dnAKFTj7tT9ebX9AJt2NLjFAAAA" + } + }, + { + "ID": "b380088eafdf8f85", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "73" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "63d304e338e399b63c0789c698a94cb1/4630752842652400573;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJkYXRhc2V0UmVmZXJlbmNlIjp7ImRhdGFzZXRJZCI6ImRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAzIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:19 GMT" + ], + "Etag": [ + "zXV1c75pOC8OREie13Eokw==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RbUvDMBD+L/HrtjaNa9fCwLciA3VQXyaIjDS9dbFZ0yXpyhz776ajiogOCffl7nm7yw4VvMxQhFKer2tQ25OMGqrBoB4CQ3M7eX9+wiwYVtPL0TSJOWASy6IZjy2Ct8ysFgxMv5LK9APfizqBuefikRtib479ILTP9wLXdee2iKVqEIsbXhZWYGlMpSPHaZpmkEuZC6AV1wMmV85nKmfjOZWSb8CMdn4YOp2hdv7n3KESWICCkgGKdp+9yWGff6l0aSa/XADte4gyBlqj6GWHlBTWA82SyUOctJtXwDgV10rWle13QjPFDShtuV+M6ezuCGHalH/gaw3qYhuvKBe2S3yfhCEh+HTYT/HIuFiuTEi9ICwYyVnO18t1IUapTJf1WQYbELICNcityIYzsIvIujTtb3z3SuLzqyPhEqDZId1rDzEF1HBZPvBVy8RD4gfYc8MwIO0hBdXmVmZ8wSH7CyLZQcGOHu/R/gMvB25VtAIAAA==" + } + }, + { + "ID": "aeaf1704956e83d5", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0003?alt=json\u0026deleteContents=false\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0e37c747cc75383561016de1e65a0c91/6266984851264910413;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0003?alt=json\u0026deleteContents=false\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:20 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "37e5d383a788cee6", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "73" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "c925e4b7645ac0e4322df4dd571b387a/7831160365367897309;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJkYXRhc2V0UmVmZXJlbmNlIjp7ImRhdGFzZXRJZCI6ImRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDA0In19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:20 GMT" + ], + "Etag": [ + "Msi46s/7XhhwHfHheG1RBw==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RW0vDMBT+L/F1W5p26w0EFYcbeIGqTBAZaXraxmZNl6QrMvbfzUYVER0j5OWc75psUcXrDMUo5cW6BfVxllFDNRg0QGBoYTd3mo99jYOXsuxm+ayEG5JcdefnFsH3zKwVDMywkcoMA9+Ne4Gl65DQiYi7JH4Q2eO7geM4S3vHlqpB5Le8rqxAaUyjY4y7rhsVUhYCaMP1iMkV/kqFNy5ulHwHZjT+ZYh7Q41Pc+5RCeSgoGaA4u3XbH7oc5JKn2b+xwug3QBRxkBrFL9ukZLCeqBFMn+aJvvmDTBOxY2SbWPnvdBCcQNKW+4342Fxf4Tw0NX/4FsN6upjuqJc2Knn+14UeR4ZT4YpCY1D5MpE1A2iinkFK/i6XFciTGVathcZbEDIBtSosCIbzsAWkW1t9r/x0yuZXl4fCZcAzQ7p3gaIKaCGy/qJr/ZMMvH8gLjEcUIvtAKCanMnM55zyP6DSHZQsKvnR7T7BP+eWu20AgAA" + } + }, + { + "ID": "977ae126e481d50c", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0004/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "147" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b539fc10b8bf44d92d303900d7cbfb20/9395334779959256429;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0004/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwNCIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMDMifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:21 GMT" + ], + "Etag": [ + "cKscLB3lcQR7Js3AEud5og==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2QQXOCMBCF/0t6VZJAgcqMB53x0JYeau2ZiWGhqUAoWco4jv+9geLFsdXJ5LAvb/d9mwPZqSolEdmq/KuFZn+HYlsAmRBAkVtdPhsZL71Cvq7DJ+MtVm3q63w+tw7V96VtIQGntW5wGgZulAoUBjBxGX9gM+4mPAhn9gRuyBhL7L13hoh/HJ4dbqDIYlXtbMQHYm0iSruuc3Kt8wJErYwjdUlP1PTbpXWjP0GioWdIdEQy9AY2OrAZegvi4FlDBg1UEkh0ICPC44WPsf4x/vf1OsopYfBf5zlOSNWWyz2CsX5GhjLWVb6B5lxe6+5UyQYEKl1tVGlXINz3gpC7nHHf73cshMEXnapMQfqHBfd1L28Wy3jVd2g5DLTS+xs5/gAU/saNYQIAAA==" + } + }, + { + "ID": "18cab6fb8a2fcdc0", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0004?alt=json\u0026deleteContents=false\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0ce549d67d86ba7798bb2bea7c9c88f1/10959228827675401725;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0004?alt=json\u0026deleteContents=false\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:21 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:21 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAALWNwQqDMBBEfyXsWWENojXnXvoBnkqR1CwSiG7ZjSfx35viN5RhYHgDMweQCAu44woK7nlA4NXHDRwsid8+QQVCXvlHhJR3memxjUqlWEnVL1Sau89eKZuwp5ly/WHJdd9ZFy4+WWxuODR2arp+KOpsj4hTcWuiGs0xJRM3s5fd81XBzKHMtoh/Ozm//Mdtmv4AAAA=" + } + }, + { + "ID": "27a31c20e523e013", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0004?alt=json\u0026deleteContents=true\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d8bc42814fba86761e1b2dc1c99b5b23/12595460836287911565;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0004?alt=json\u0026deleteContents=true\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:22 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "236c6ce2f165853f", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "bdf3580b9581de657da9c01ae40489df/14159635250896047645;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:22 GMT" + ], + "Etag": [ + "Ebkpq/E66/i28Qe6O1h+eQ==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:22 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RW0vDMBT+L/HRbWnamV5goGKRgTpWlT2IjDQ962KzpkvSDRn+d7PRiYgTCXk557smO1SJukAJykW5bkG/nxXMMgMW9RBYVrpNmlfNGqeUYuFHU6ATsjyH6WjkEGLPLFrJwfYbpW0/pH7SCcx9j0ReTPw5oWHsDvVDz/Pm7hJHNSAXd6KunMDS2sYkGG+320GpVCmBNcIMuFrhYyq88XGj1Rtwa/APQ9wZGvw/5w6VwQI01BxQsjvOxoc+/1Lp0ox/eQH00UOMczAGJS87pJV0HmiWjZ/SbN+8AS6YvNWqbdy8E5ppYUEbx/1iTGYPfxAm2/oEvjWgr9/TFRPSTQNKgzgOAjK86Ocksh5RKxszP4wrHpS8FOvlupJRrvJle1nABqRqQA9KJ7IRHFwR1dZ2/xvfvbL06uaPcBmw4pDutYe4BmaFqp/Eas8kFwENie9FZDj0nIBkxt6rQiwEFKcgih8U3Or5EX18AkY4zkG0AgAA" + } + }, + { + "ID": "818a30fdd422de02", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "41" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "275f19a316b52bbbc9fc36a89993c544/15723810764982257581;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJkZXNjcmlwdGlvbiI6ImQyIiwiZnJpZW5kbHlOYW1lIjoibjIifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:23 GMT" + ], + "Etag": [ + "2o9dlL5BSc2UFWtNlhwMWw==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1R72viMBj+X3Jf1SaptrYw2Ma8Q9gcdBv9MIbE5LXmjE1NUovI/vdLpDvuxjZGyJc3z6/3yQltZS1Qjlay2rdgjj8Ec8yCQwMEjlX+hepMqNvJ9QOnTz9Lt1Cb7q7sLi48QgamaBUHN2y0ccM0oXkvsKSYTHFG6JIkaeZPQlOM8dJf4qkW1PpW1lsvsHGusXkUdV03qrSuFLBG2hHXu+gtVXSgUWP0b+DORu8Mo97QRt9z7lEFrMFAzQHlp7fZ/LzPt1T6NPMPGkCvA7Q2Emqhjgu28waopsEYLDeycVLXgRRGjHOwFuXPJ2S0CsiymD/OilBQA1wy9cvotvHz3q800oGx3uIv475cfEG47+pP8K0Fc32c7ZhUfhonSZxlcUzGk+GKTB0meucyRtNsy+OKV3K/2W/VdKVXm/ZSwAGUbsCMKi9ykBz8IrqtXfi0f72K2dXNF+EKYOKc7mWAuAEWqnmU58bIJE5SQvGUjMfYCyhm3Z0Wci1B/A8h2IcOZSrNWV/u0wN6/QPEIxP72wIAAA==" + } + }, + { + "ID": "f3ee09257d037770", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "39" + ], + "Content-Type": [ + "application/json" + ], + "If-Match": [ + "Ebkpq/E66/i28Qe6O1h+eQ==" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f4621107701c87f117ca35b5270848d9/17360042777906511676;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJkZXNjcmlwdGlvbiI6ImQiLCJmcmllbmRseU5hbWUiOiJuIn0K" + }, + "Response": { + "StatusCode": 412, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:23 GMT" + ], + "Etag": [ + "2o9dlL5BSc2UFWtNlhwMWw==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:23 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAIWNsQoCMRBEf0W2PgvFKh8gWJxY2MkVa3a9C+SyskkjIf/uBkHs7Ib3hpkKrCoKrn5CBnerQLJiSOBgjnLHCAMoY5ZOvCQKJUg6Sxm5mFo5Z5zZ3EX5qzdHDJHJfBSPnVxfz15aGIn1hxs7PbYjFr9AmwZ7IOsddvt/0629Ad0ZvLW+AAAA" + } + }, + { + "ID": "f2f4ad5c366206e7", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "37" + ], + "Content-Type": [ + "application/json" + ], + "If-Match": [ + "2o9dlL5BSc2UFWtNlhwMWw==" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d8e4ca71cad34edc0a5a36d5aa489ab0/477754593765030092;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJkZXNjcmlwdGlvbiI6IiIsImZyaWVuZGx5TmFtZSI6IiJ9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:24 GMT" + ], + "Etag": [ + "ADCaKyMCuZyZDO9p590rOg==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RbWvCMBj8L9lXtUmrrS0M9qIM2YvQbQiOITF9rJmxiUmqFNl/X+q6sY1NRsiXyz1391z2aMWLDCVozvNNCbo6yailBixqIbA0dy/ng0t6Xd1eltNqOhjHqhdjPc5PTx2D15NZKRjYtpLatqPQTxqBmY9JH8fEn5Ewit0J/QhjPHOXuFEDYnHDi5UTWFqrTOJ5u92uk0uZC6CKmw6Ta+8jlbf1PaXlCzBrvB+GXmNovP85N6wUFqChYICS/Qc2OuzzL5UmzeiXBtBrCy00hyIT1R1dOwNU24JhmivLZfEOUMbAGJQ87ZGWomZN0tHDMK3LUcA4FVdalsrhjddEcwvaOPnPifHk7sjAeFf8wS8N6ItquKZcODQIwyCOg4B0e+056VtM5NrG1I/iFQtylvPNcrMS/bmcL8uzDLYgpALdyZ3IljNwi8iysPWHffVKh+eDI+FSoNkh3XMLMQ20LuaBH9oivSCMiI/7pNvFTkBQY29lxhccsu8UgrskiGqKZLSp9vEevb4Bj5++6dcCAAA=" + } + }, + { + "ID": "78605ccecbd90f75", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "fca77d90a75f6f41614c065a867e6afc/2041930107868016732;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:24 GMT" + ], + "Etag": [ + "ADCaKyMCuZyZDO9p590rOg==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:24 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RbWvCMBj8L9lXtUmrrS0M9qIM2YvQbQiOITF9rJmxiUmqFNl/X+q6sY1NRsiXyz1391z2aMWLDCVozvNNCbo6yailBixqIbA0dy/ng0t6Xd1eltNqOhjHqhdjPc5PTx2D15NZKRjYtpLatqPQTxqBmY9JH8fEn5Ewit0J/QhjPHOXuFEDYnHDi5UTWFqrTOJ5u92uk0uZC6CKmw6Ta+8jlbf1PaXlCzBrvB+GXmNovP85N6wUFqChYICS/Qc2OuzzL5UmzeiXBtBrCy00hyIT1R1dOwNU24JhmivLZfEOUMbAGJQ87ZGWomZN0tHDMK3LUcA4FVdalsrhjddEcwvaOPnPifHk7sjAeFf8wS8N6ItquKZcODQIwyCOg4B0e+056VtM5NrG1I/iFQtylvPNcrMS/bmcL8uzDLYgpALdyZ3IljNwi8iysPWHffVKh+eDI+FSoNkh3XMLMQ20LuaBH9oivSCMiI/7pNvFTkBQY29lxhccsu8UgrskiGqKZLSp9vEevb4Bj5++6dcCAAA=" + } + }, + { + "ID": "c0cd01f81fcdf181", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "39" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "eabf1c3cb93a4f70cec2048ab04bf854/3606105621954226668;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJkZWZhdWx0VGFibGVFeHBpcmF0aW9uTXMiOiIzNjAwMDAwIn0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:25 GMT" + ], + "Etag": [ + "RebHjWBmP+zGgP6sreLvyQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RXW/aMBT9L97jgNgJJASp0lYNdUj9zJh4mCbkODfBxYmN7cAY6n+vHYVprbaqtvxy77nnnHt8QlveFGiGcl7tWtDHDwW11IBFAwSWVq6TQf71cXVZ33/8fVXdx0bD9f74cHHhENxPFq1gYIdKajtM4nDWE6xDTKY4JeGaxEnqbhwmGOO1e8SNGhDlNW+2jmBjrTKzIDgcDqNKykoAVdyMmKyDs6tgHwZKy0dg1gSvBINe0ATvU+5RGZSgoWGAZqdzbdHt8y6W3s3iHwmgpwEqNYemEMdbWjsB5GXBMM2V5bI5F0raCrukuYD5L8U19b0b47pRjP1xIMoYGFf6cUJaCk+1yhbLeeYTVMA4FVdatsrVe0MrzS1o4zz8mbhb3b4xcHdo/oNvDejL47ymXHSe4ihNo4iMJ8OcTC0msrYpDZN0y6KKVXy32W3FNJf5pv1UwB6EVKBHlSPZcwZuEdk21v/q31rZ/POXN8xlQIvO3c8BYhq6hJa8i5RMojghIZ6S8dgnJaixN7LgJYfiJYTgSRjFHiIZ7fP//g09PQORjRil/AIAAA==" + } + }, + { + "ID": "dc93f82e80b5bf1e", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "23" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d9c81652ab62f986fc20f06f6175ea34/5242336535383564668;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJmcmllbmRseU5hbWUiOiJ4eXoifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:26 GMT" + ], + "Etag": [ + "oJOEKxnSNMfm+BhfgAmcQQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RXW+bMBT9L97jkoBNCiFSpbUamrItiUpT5WGaImMuxIvBjm3ysaj/fQbRapvaqli8nHvuOcfHF7TjdY6mKOPlvgF9/pBTSw1YNEBgaekm8usy+Xaq7xfzovp4uy3Km4rd3V1fOwZvN/NGMLBDJbUdRiGZ9gIb4uOJH2OywWEUuxOSyPf9jfuxWzUgiu+83jmBrbXKTD3veDyOSilLAVRxM2Ky8p5SeQfiKS1/AbPG+8/Q6w2N9z7nnpVCARpqBmh6ecJm3X3epdKnmb3QAHocoEJzqHNxXtDKGaDT+XfrDIZpriyXtcM6oKCNsCuaCUhOimvazubGTYPQbz9HooyBcdCPC9JStGrrdLZK0rZEBYxT8UXLRjm8z7TW3II2LsbzxnK9eGNheaxf4TcG9O05qSgXXaYwiOMgwOOrYYYn1seysjElUbxjQclKvt/ud2KSyWzbfMrhAEIq0KPSiRw4A3cR2dS2fdi/vdLk5vMb4VKgeZfu5wAxDV1DK961iq+CMMLEn+DxuG1KUGPnMucFh/xfCvZDEpCWIhnt+3+4R49/AEIv9Db/AgAA" + } + }, + { + "ID": "3c888c5e21ada5d1", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "34" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "213637aa7a297834809319baf39a43d0/6806512049469774348;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJkZWZhdWx0VGFibGVFeHBpcmF0aW9uTXMiOm51bGx9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:27 GMT" + ], + "Etag": [ + "xs1tTJ8thS0pb7RmYVtLzw==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1R72vbMBT8X7SvSSzZqX9BYRsLI6Nrwc0WxhhBll8cLbKlSM/x0tD/fXJwxza2UoS+nO7d3TudyV62FclJKetDB/b0quLIHSCZEEBe+5cfjuHqQ4q7e2rKpGi+fMabh/762jPkMFl1SgBOjbY4TeIwHwU2IWUpzVi4YXGS+ROHCaV04y/zow7U9ka2ey+wQzQuD4K+72e11rUCbqSbCd0ET6mCYxgYq7+DQBf8ZRiMhi54mfPIKmALFloBJD8/YcvLPi9SGdMs/9EAeZyQrZXQVup0yxsYOjw9DM7ghJUGpW495gEuBDhH8q9nYrUaiOtiuVoUQz8GhOTqvdWd8fhot7YSwTrv8Gvibn37zMBd3/6H3zmwb0+Lhkvl0SiOoyyLIja/mpYsRcp0gxkPk2wvolrU8rA77FVa6nLXva7gCEobsLPaixylAL+I7loc/ux3r2Lx5t0z4Qrg1SXdtwkRFvhQzEpeCmNXUZywkKZsPqdeQHGHH3UltxKqPymMJjTKBooWfKz20z15/AnJnrMX2gIAAA==" + } + }, + { + "ID": "af38555673789555", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "24f3689144d0ef71cea38e5beed6d713/8370687563572761244;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:27 GMT" + ], + "Etag": [ + "xs1tTJ8thS0pb7RmYVtLzw==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:27 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1R72vbMBT8X7SvSSzZqX9BYRsLI6Nrwc0WxhhBll8cLbKlSM/x0tD/fXJwxza2UoS+nO7d3TudyV62FclJKetDB/b0quLIHSCZEEBe+5cfjuHqQ4q7e2rKpGi+fMabh/762jPkMFl1SgBOjbY4TeIwHwU2IWUpzVi4YXGS+ROHCaV04y/zow7U9ka2ey+wQzQuD4K+72e11rUCbqSbCd0ET6mCYxgYq7+DQBf8ZRiMhi54mfPIKmALFloBJD8/YcvLPi9SGdMs/9EAeZyQrZXQVup0yxsYOjw9DM7ghJUGpW495gEuBDhH8q9nYrUaiOtiuVoUQz8GhOTqvdWd8fhot7YSwTrv8Gvibn37zMBd3/6H3zmwb0+Lhkvl0SiOoyyLIja/mpYsRcp0gxkPk2wvolrU8rA77FVa6nLXva7gCEobsLPaixylAL+I7loc/ux3r2Lx5t0z4Qrg1SXdtwkRFvhQzEpeCmNXUZywkKZsPqdeQHGHH3UltxKqPymMJjTKBooWfKz20z15/AnJnrMX2gIAAA==" + } + }, + { + "ID": "8d3ca3ff2edb3590", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "319" + ], + "Content-Type": [ + "application/json" + ], + "If-Match": [ + "xs1tTJ8thS0pb7RmYVtLzw==" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "2555cceb71fc47ab6c9a73460ba391f7/10006918476985322284;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJhY2Nlc3MiOlt7InJvbGUiOiJXUklURVIiLCJzcGVjaWFsR3JvdXAiOiJwcm9qZWN0V3JpdGVycyJ9LHsicm9sZSI6Ik9XTkVSIiwic3BlY2lhbEdyb3VwIjoicHJvamVjdE93bmVycyJ9LHsicm9sZSI6Ik9XTkVSIiwidXNlckJ5RW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LHsicm9sZSI6IlJFQURFUiIsInNwZWNpYWxHcm91cCI6InByb2plY3RSZWFkZXJzIn0seyJyb2xlIjoiUkVBREVSIiwidXNlckJ5RW1haWwiOiJKb2VAZXhhbXBsZS5jb20ifV19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:28 GMT" + ], + "Etag": [ + "fGsMjudbocLmf/3NuFru4w==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RW0/bMBT+L+a1beIk5CYhsYmCiqBIGVMfpqly7JPU1IlTXxq6iv8+hwU00IaQ5ZfP383nHNGWtwzlqOT1zoI6nDBiiAaDJggMqd1LdaVvHywrJb1pKi9c2ktlo/7szDH4oGRWUDDTTiozTeIgHw3WgY9TP8PBGsdJ5k4cJL7vr93FTqpBVDe83TqDjTGdzj2v7/tZLWUtgHRcz6hsvJdW3j7wOiUfgBrtvQv0xkDtfS55ZBVQgYKWAsqPL9ji+T+fchnbLP4xAfQ0QZXi0DJxWJLGBaDHw68hGTRVvDNctg5zAKEUtEb5jyNSUgzEVbG4nxfDfDqgnIgrJW3n8DFupbgBpV3Cq+JutfxAcNe3/+FbDerrYd4QLhwaxnGYZWGIo9NpiVPjY9mYjARJtqVhTWu+2+y2Ii1lubHnDPYgZAdqVjuTPafgPiJta4ad/Z1VzL9cfFCuAMLetXtVvK13LeEcHknTCfiT8XOCqAIyjPKeP48Yn4ZxggM/xVHkOwNBtLmVjFcc2FsK9tMoGnYoJCXjMr5/Q0+/AZNE5FcMAwAA" + } + }, + { + "ID": "967a9ec27b3d9423", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "269" + ], + "Content-Type": [ + "application/json" + ], + "If-Match": [ + "fGsMjudbocLmf/3NuFru4w==" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7d071f4e3e03f3200baa6a283b04ec4a/11571093991088309180;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJhY2Nlc3MiOlt7InJvbGUiOiJXUklURVIiLCJzcGVjaWFsR3JvdXAiOiJwcm9qZWN0V3JpdGVycyJ9LHsicm9sZSI6Ik9XTkVSIiwic3BlY2lhbEdyb3VwIjoicHJvamVjdE93bmVycyJ9LHsicm9sZSI6Ik9XTkVSIiwidXNlckJ5RW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LHsicm9sZSI6IlJFQURFUiIsInNwZWNpYWxHcm91cCI6InByb2plY3RSZWFkZXJzIn1dfQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:29 GMT" + ], + "Etag": [ + "8blwedP+5tcT7pXkSLffEA==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RbWvbMBj8L9rHJbFkJ36DwjoWRqBrh5uRwhhBlh47mhVLkeR4Weh/nxzcso2tFKEvp3vu7jmdUSNajnJUivrQgTm94dRRCw5NEDha+5e0lD3wz28Xjq0T/dDc31TV8vrqyjPEMMk7ycBNtTJumsRhPgpsQ0xSnJFwS+Ik8ycOE4zx1l/iRy3I6ka0jRfYOadtHgR9389qpWoJVAs7Y2ofPKUKjmGgjfoOzNngL8NgNLTB65xHVgEVGGgZoPz8hK0u+7xKZUyz+kcD6HGCKiOg5fJ0S/feAP04/RycwTIjtBOq9ZgHKGNgLcq/npFRciBuitV6WQz9aGCCyo9Gddrjo93GCAfGeofnibvN7QsDd337H35nwbw/LfdUSI9GcRxlWRSR+WJaktRhovYuo2GSNSyqWS0Ou0Mj01KVu+4dhyNIpcHMai9yFAz8Iqpr3fBnv3sVy+sPL4QrgPJLum8TxAzQoZi1uBRGFlGckBCnZD7HXkBS6z4pLioB/E8KwdlIUYyO1X65R4+/APs4+JLaAgAA" + } + }, + { + "ID": "96fa534c85b030c3", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "edb7b9f7dac14ae93630b5ecea97cb5d/13135268405696445260;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:29 GMT" + ], + "Etag": [ + "8blwedP+5tcT7pXkSLffEA==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:29 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RbWvbMBj8L9rHJbFkJ36DwjoWRqBrh5uRwhhBlh47mhVLkeR4Weh/nxzcso2tFKEvp3vu7jmdUSNajnJUivrQgTm94dRRCw5NEDha+5e0lD3wz28Xjq0T/dDc31TV8vrqyjPEMMk7ycBNtTJumsRhPgpsQ0xSnJFwS+Ik8ycOE4zx1l/iRy3I6ka0jRfYOadtHgR9389qpWoJVAs7Y2ofPKUKjmGgjfoOzNngL8NgNLTB65xHVgEVGGgZoPz8hK0u+7xKZUyz+kcD6HGCKiOg5fJ0S/feAP04/RycwTIjtBOq9ZgHKGNgLcq/npFRciBuitV6WQz9aGCCyo9Gddrjo93GCAfGeofnibvN7QsDd337H35nwbw/LfdUSI9GcRxlWRSR+WJaktRhovYuo2GSNSyqWS0Ou0Mj01KVu+4dhyNIpcHMai9yFAz8Iqpr3fBnv3sVy+sPL4QrgPJLum8TxAzQoZi1uBRGFlGckBCnZD7HXkBS6z4pLioB/E8KwdlIUYyO1X65R4+/APs4+JLaAgAA" + } + }, + { + "ID": "1db6cbfc6da8e8a4", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "29" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "51b192d34e8ab31c8b4261954290e021/14771500414308955356;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJsYWJlbHMiOnsibGFiZWwiOiJ2YWx1ZSJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:30 GMT" + ], + "Etag": [ + "nnyL9Y8a6+BeQaDmGw1Mag==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1R62rbMBh9F+3nkliyXV8Cha00lEAvzOsIY4wgy18cLbLkSHI8L/TdJxl3bGMrxRjM0bnp+IwOXFZoiUpeHzvQw5uKWmrAohkCS2t3IuVwm3/OaPL2Cj7Q6+amJ3e0vrx0DO6VVScY2HmrtJ2nSbicDLYhJhnOSbglSZq7JwlTjPHWvcRJDYjdLZcHZ7C3tjXLIOj7flErVQugLTcLpprguVVwCoNWq2/ArAn+CgymQBO8LnliFbADDZIBWp6fsfV4n1e5TG3W/1gAPc3QTnOQlRjuaeMC0Pfhh08GwzRvLVfSYQ4QtARhfIHxy4EnKjrwBpQxMO7oyxlpJbzHplg/rgo/XQuMU3GjVdc6fGqy0dyCNk77S/GwuX9B8NDL//A7A/pqWDWU+0pRkkR5HkUkvpiXJLOYqMbmNEzzA4tqVvPj/ngQWanKffeughMI1YJe1M7kxBm4i6hOWv87f88qVu+vXyhXAK3Gdl9niGmgfrNHPm5JLqIkJSHOSBzjcURj71TFdxyqPymE4CSOPUUxOq3+6SN6+glm4sAt9QIAAA==" + } + }, + { + "ID": "83c376d5e6bc59e0", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "26" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8b3f4434f50d0d0286403d158c0d248a/16335675932706843756;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJsYWJlbHMiOnsibGFiZWwiOm51bGx9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:31 GMT" + ], + "Etag": [ + "a4fXpFjhYTJmfw+nnLP/fg==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RYW/TMBT8L+YjbR0nadJEmgQTBRWNDWVFBSFUuc5L6tWxXdtp6Kr9d5wqQwzBNFn+cr53d+98QjsuS5SjDa/3LZjjq5I6asGhEQJHa/9C4+qrfn+3/bb82FTdaymvPuOqvrjwDN5Plq1g4MZaGTdOkzAfBNZhQGZBRsI1SdLMnyRMgyBY+0v8qAVRXXG58wJb57TNMe66blIrVQugmtsJUw1+TIUPIdZG3QFzFv9liAdDi1/mPLAKqMCAZIDy0yO2OO/zIpUhzeIfDaCHEaoMB1mK4zVtvAH6ebzvncEyw7XjSnrMA5QxsBbl30/IKNETV8ViOS/6fjQwTsUHo1rt8cFuZbgDY73D74mb1fUzAzed/A+/tWAuj/OGcuHRKEmiLIsiEk/HGzJzAVGNy2iYZjsW1azm++1+J2Ybtdm2b0o4gFAazKT2IgfOwC+iWun6P/vTq5i/ffdMuAJoeU73Y4SYAdoXs+Tnwsg0SlISBjMSx4EXENS6T6rkFYfyKYUQEkfTnqIYHar9cosefgH2Vw202gIAAA==" + } + }, + { + "ID": "a61f616e579eed4f", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "360" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5fb81788f96b5155d6bf366633e5edd6/17899568876616459772;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMDQifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:31 GMT" + ], + "Etag": [ + "uNxDH+IE05X65l5hLFMQTg==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Sb0+DMBDGv0t96VwpCiiJLzZXdQluipiYGLN0cGNVoEg757Lsu3uwLTP+T9OQu3uee35pWJJnWSTEJ2OZvsygWuwZMc6AtAgYkWJ/NnjrXe73ueXcu07mTIPzq5soPT1Fhax9ySyLwRyUqjIHnmv7iTBCgxnZFju2Tpg9Yq53gse1PcuyRnhZu4n4RXGEyzVkk0AWzxgxNabUPqXz+bydKpVmIEqp27HK6Zaavtq0rNQTxEbTT0h0g6TpP9how6bpfxAbTQgTqKCIgfhLskHof/MwqN/Er6d/o2wTGv3fPCt8s3gKuahBJhKyRBP/YUkKkSPb+oMbF2Vd3UZhf3CBnt18luvdvD+I+AUPsZGrpG6E/Jp3It77aKkg3jlCfjYMe1h/jR4rle2E3eEw4J0BWT3iadW53YUBNBCLNGWgijSC6nM7VPNtFVcgjFRFJJv9zDl0PWYzxjzHqf/ct1JW3wjcY3yo2p8Jba5UIhE1+WHHBjbqdANeO1TcLMTW3S1ZvQMe8VhgNgMAAA==" + } + }, + { + "ID": "a4e54172f742b8de", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0004?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "29" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "13242aa12f06a2ee272d5c442bd7a767/1017281791986605452;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0004?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJsYWJlbHMiOnsibGFiZWwiOiJ2YWx1ZSJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:32 GMT" + ], + "Etag": [ + "MGN1NkcBsLxwM+ejeJciDg==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SUW+iQBSF/8vs41qHoRWqSR90JcYNYkPZp2ZjRrjSqQPDMmOpMf73vUM1NG6zbSYE7r3n3PNlwoFsRZmREVmL/M8O6v03w9cSSI+A4Tn2F7OIRdt0osPXZvEdnuFnKqb53R0qhPVlO5mCuapUba58zx1l3HANZuU67NYZMnfFPH+Ix3N9x3FW+LB+G/EfxQ0u1yA3oSi3GPFkTKVHlDZN08+VyiXwSuh+qgp6pqYvLq1q9Qyp0fQCiZ6QNP0CG23ZNP0KYquJYQM1lCmQ0YGcEOYfXAzqT/Fv089Rzgmt/nOeY49IvgapLUj7hbYXLndgRzp9goLb0UaAzFD0eCAlLxD77YVh+8pWD0k8j2bo6ea7QnfzeZQEsyDGRqEy24iD+2CcBNP3lhrSzhEHP5bxFOt/o9dKyU44WS7DYByR4288PZs72RtAA3FIW4aqzBOoL9uxas5VWgM3QpWJaPezwbXnM5cx5g8G9qd+rUT9gcC7xTu0fsm1WahMIGp2ucO9vhl2sMl4EgbWodJ2IbZ+PZDjX2CLyAdRAwAA" + } + }, + { + "ID": "5c7f596033eed434", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0004?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "26" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7462f22a968f59df040c9359ac4b1bba/2653513800599115292;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0004?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJsYWJlbHMiOnsibGFiZWwiOm51bGx9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:33 GMT" + ], + "Etag": [ + "ropu8wvxW8nVzWgKKTi69g==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SUU/CMBSF/0t9VbpO2WAJD6CLISKYOeXBGFK2y6xu62yLAwn/3bsJmUGjpmmWe+8593xptiEvIo+JR+YieV2CWh8ZPk+BHBMwPMG+ksWyU76tpp38/n2aXF2FwukmvR4qROWLl2kE5qSQypy4ju3F3HANZmZbrGN1mT1jjtvF49iuZVkzvKxVR/yiOMPlGtLFSOQvGPFkTKE9SsuybCVSJinwQuhWJDO6p6ZvNi2UfIbIaHqARHdImv6DjdZsmv4HsdYEsAAFeQTE25AdwvCHh0H9Lv5z+jfKPqHW/82zxTeLniDjFchCQBpr4j1sSM4zZPv84MZ1UVW3YTAcX6KnmS8z3cyH49C/9ANsZDKuGoF/4/dD/+KrRUHUOAL/fBJcYP09ei5l2ggHk8nI74/J9hHPcZU7WBtAA7FIXY5knoSgDtuBLPdVpIAbIfNQ1PtZ+9Rxmc0Yc9vt6s9dFUL9IHA6+FCVP+XaXMtYIGp8uOPUOms3sGF/MPIrh4zqhdi6uyXbDzu9ORc2AwAA" + } + }, + { + "ID": "9037b4a511a9ba93", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0004?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b375edd8e36da2de6c8b0ce324b96578/4217688219502153388;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0004?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:33 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "3ea17b5ff83bc22c", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "360" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "08baa60693f7161db2e9b80b2b93552e/5781863733588363068;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMDUifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:33 GMT" + ], + "Etag": [ + "rAtFXobmrjkZoWr2Wf9XcQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SYU/CMBCG/0v9inQbcYMlfgCZhgRB5wxEY0jpjlnZ1tkWkRD+u7cJwSgqaZrl7t733ifN1mQu8pj4ZCqS1wWo1Ylh0xRIjYBhCfZV21yO5TRTL/MHOVLOaNYa89vzc1SI0hcvUg7mtJDKnHqu48fMMA1m4lh202rZzsR2vRYe1/Esy5rgtetVxB+KM1yuIZ31RT7HiGdjCu1Tulwu64mUSQqsELrOZUZ31PTNoYWSL8CNpt+Q6BZJ0yPYaMWm6TGIlSaEGSjIORB/TbYIvQMPg/pt/Of0f5RdQqX/n2eDb8afIWMlyExAGmviP65JzjJk+/zgxlVRVndR2BtcoWc/X2R6P+8NouAqCLGRybhshMFN0I6C7leLAr53hMHFMOxi/TN6KmW6F3aGw37QHpDNE55amdtZGUADsUhV9mWeRKC+t0O53FVcATNC5pGo9ttnDdezHdtueK5X/rnvhVAHBG4TH6r0p0ybaxkLRI1/2bGFjdqdflA6JK8WYuv+jmw+ABuL8qk2AwAA" + } + }, + { + "ID": "a00f88e25beaa3c8", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026pageToken=\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "c60c0e6818769122f98d108cd7cf720a/15823211039416877956;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026pageToken=\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:34 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/AwQhu5HNv9TofY9Hp7n969iUfH4\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:34 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAM2TW0/CQBSE/8v6Ctpt6fUNg0IjEjQQg0KapT3gam9styoh/Hd3uUQTG1FUbJq+dOfMmc6XXaBHGgfIQWM6neXA5kecjENo04yjCgJOpuJsiNrk1oqVWsO6iJou9INu6HbaEZCbZnZSf766z/VW58nuJZOB3UrN2DZs2p+0akMkTFaGGXLuFsW7hITKr0Ee+sCracJ41TRUJyCcZMA9VcGWYmPVw4Zpi8dQTUVRPPHiY+5FIqNUeilhnHKaxJ4f5hkH5inb5dcwAQaxD8hZoJQlD+Bzt2Cl0G+Wrk93B9huWOl3hFkK7TwVGVCvfto+k6M0gu5WSeOpjLeRNOoDObCZ3pxNKISBbBLFJAI0kgIGRE73hJUYw7pmmFhVLN3S5e/DS0pZgcCwRHoZ6dBMcJmY4O8zeV/pZSYLXfe4PylLN3EZSallIqXuQ4rBLKfsTXNOQ+GFHM5y+AExG2tGKYlpZSKm/dbdqqzRrPPBH2Ktaf93EaXBJwr90GR35vkIt7hWjDXTML9Q60gYJpyELodI8NKXryff0CWaCAAA" + } + }, + { + "ID": "8696f464b97eaa2f", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0005?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "382c8b3bb01a5e280a8968ba0f4bc6a2/17387386553519864596;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0005?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:34 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "f6f62ba2ef427e09", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "360" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "155d8941b52172da0766dc4ec52014e6/505098369378383012;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMDYifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:34 GMT" + ], + "Etag": [ + "X1Lt8cWOHQEz0ItOBjJFEA==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Qb0+DMBDGv0t9qytFZZPEF5tWncGhiNHEmKUrN6wCRdo557Lv7oFbZvyfhpC7e557frk5eVRFQnwyUunTBKrZhhWjDMgmAStS7N+wwHbkdXhywV+dvg17D6dHvLu/jwpV+5JJJsFulbqyW23P9RNhhQE7dB3WcfaYO2Reew+f57Ydxxnix1pNxC8KD5cbyMaBKh4x4t7a0viUTqfTVqp1moEolWlJndMVNX12aVnpB5DW0E9IdIlk6D/YaMNm6H8QG00EY6igkED8OVki9L85DOqX8e/Tv1FWCY3+b54F3kzeQy5qkLGCLDHEv52TQuTI9v7DjbOyri7jqD84Rs96PsnNet4fxPyYR9jIdVI3In7OuzE//GipQK4dET8Io0Osv0aPtM7Wwl4YBrw7IIs7fJt1bm9mAQ3EIU0Z6CKNofrcjvR0VckKhFW6iFWzn+1ue23mMraz69VjeClV9Y3A6+ChakEmjD3TiULU5IcdS9i42wt47dCyWYitq0uyeAOTlbrpNgMAAA==" + } + }, + { + "ID": "f1d148a7d8ff64e2", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006/insertAll?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "215" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6717744ea99593720eaa9e3143ff936a/2141330378007669812;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006/insertAll?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJyb3dzIjpbeyJpbnNlcnRJZCI6ImEiLCJqc29uIjp7Im5hbWUiOiJhIiwibnVtcyI6WzBdLCJyZWMiOnsiYm9vbCI6dHJ1ZX19fSx7Imluc2VydElkIjoiYiIsImpzb24iOnsibmFtZSI6ImIiLCJudW1zIjpbMV0sInJlYyI6eyJib29sIjp0cnVlfX19LHsiaW5zZXJ0SWQiOiJjIiwianNvbiI6eyJuYW1lIjoiYyIsIm51bXMiOlsyXSwicmVjIjp7ImJvb2wiOnRydWV9fX1dfQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:34 GMT" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTMK04tKnHMyQlKLS7IB3KUagGmFzWCLgAAAA==" + } + }, + { + "ID": "0ea40d76c9cc1e5f", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9b9388d51a843f455542ad16dee5a9f5/12110621189293107580;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:35 GMT" + ], + "Etag": [ + "a9WUQO9SRFFMJtQWcAmZKA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8onWoaHBvpbBge5ufl6lQSGJzvmRnk72toCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsA+lWqtUBs6B8A6XaWKgIsrKSotJUkAxEEiGehKbdkDTtyWjajQhqj60FALwx8C0ZAQAA" + } + }, + { + "ID": "fa96becd36141979", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "c3e5997d8f2f8f3a2908821bef9880d0/3705505896388781508;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:35 GMT" + ], + "Etag": [ + "X1Lt8cWOHQEz0ItOBjJFEA==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:35 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKtWKk7OSM1NVLKqVkrLTM1JKVayiq5WykvMTVWyglA6SiWVBSBecEiQp5+7Uq0OQr40txgh7+kX4uruGgQUyM1PAQkEuQa4Ooa4uiBrKUpNRugIcnX2D3IB8jGtTsrPz0EodPL393F19FOqjQXCWgCN1fK3tQAAAA==" + } + }, + { + "ID": "de65ee1314ed0b04", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a3286f58093ee0208819daea82ebdde3/13746852098427543820;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:36 GMT" + ], + "Etag": [ + "a9WUQO9SRFFMJtQWcAmZKA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8onWoaHBvpbBge5ufl6lQSGJzvmRnk72toCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsA+lWqtUBs6B8A6XaWKgIsrKSotJUkAxEEiGehKbdkDTtyWjajQhqj60FALwx8C0ZAQAA" + } + }, + { + "ID": "7ac2d1a81f27efa7", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3f530e83058ff902bc1777b89b4c29b0/5269680310996917588;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:35 GMT" + ], + "Etag": [ + "X1Lt8cWOHQEz0ItOBjJFEA==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:35 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKtWKk7OSM1NVLKqVkrLTM1JKVayiq5WykvMTVWyglA6SiWVBSBecEiQp5+7Uq0OQr40txgh7+kX4uruGgQUyM1PAQkEuQa4Ooa4uiBrKUpNRugIcnX2D3IB8jGtTsrPz0EodPL393F19FOqjQXCWgCN1fK3tQAAAA==" + } + }, + { + "ID": "5cf0294d8bf66a18", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "307" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "78bca815831916007993eac955766853/6905912319609427684;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7ImRlZmF1bHREYXRhc2V0Ijp7ImRhdGFzZXRJZCI6ImRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn0sInF1ZXJ5Ijoic2VsZWN0IG5hbWUsIG51bXMsIHJlYyBmcm9tIHRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwNiIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoibHJYMWRLZm1WbUxVN21zZkNudGhsZXVpTjJmIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:36 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/AILe_0KyxhnYiDnowGESJAXrLjA\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAIVT62rbMBR+laD9TWPZTnwJjC0kXvBqwpZLL6NgZPnIUWNLqS03CyXvPslNoXQjwxiEzne+yzn2C9pxkaMxynjx1EJ9/PQoM9RHoEihbx9QQn4FAg9nwXU1j2GT/yjjRVIBuZ031iROIMXXx99bcc9nQh7m0er75K5OHicPSJNwQ5y3JQV1tZe1uvI9Z7xZDcr6zs6vWXVTJRu/athUqG0JLV84THc1ULKEi53u3Sq1b8aWdTgcBoWURQlkz5sBlZX15td6dqx9LR+Bqsb6oGXpLI11Qe1LKSlRXIrPm5VW1vAlMKhBUEDjF3Tmjf8R4xXdVS6neVPQQK1x6iMqBeNFW59vXwzP+rjXgujnJlre654umCmdD2Yk2kdPkAr6PdFWTb9XA+2xWlY9RbISUgfbAQ5tJ7U9P9SP5/gY41S/nibMoVFcdIprA/9/uJwo0sBrNaUBC3CGw8wOMoYdBmzkDyngEQ5ghIfAvDzwPY/ovs5N10WEFIT4NobMTh3fc9Mho24aUAopsGzoUQweI7SbSQ1EwYw3e9nw87Smy2iyjtL4W7qIolk00+SHmn9E3S5jDVovN4upRndRGWlLNXv1b4K+j3I+XxiXrTkujeZkylxqJ2Yx8WIdLSfTdXxjtNsGEigIPa6eSjRmpGzgpPGNIqptjBVzMovWdhfxYo7ORa63QztANwizJV4ZnD1yPd92bNsbugHqwLX6q+aF9vuPphOpQKjzV7WKkmi6RsaJNlinUBGu7SHX89wwdF17OLrSm1XYlpUKieOHO+oWtOBP26ddGWQy27Zfc3iGUu6hHhSa45lTIJTKVijzM6LTH5KGy1NHBAAA" + } + }, + { + "ID": "bccd4ce4334021de", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/lrX1dKfmVmLU7msfCnthleuiN2f?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "40b04c397074ac60a282a3738112e62d/8470086734217563764;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/lrX1dKfmVmLU7msfCnthleuiN2f?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:37 GMT" + ], + "Etag": [ + "NkQn8l6h4jh9ZZ1bHA05HA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/22RzW7CMBCE32V7DRL0B9pIHAJYgBoFMFBVVD0kzoYE7Di1N6oQ4t3r0ErpAfmwHnk+76x9hmNRpuBDUuy/ajSnuz3SqtlwtLUk60qlS4vgAVK8d87ouCqfZT9/POQvu10vmQXdp1kwHDqHFTmqGPwzZAXK1IL/cYYyVuiwa/GATlWj1hs+j6ZOK502OtqGYTAKGVy8lqiVbYl5tGFTxluEsyULNmzyHzEoWoKz8YJPbvTwbsRLtJYtOlosQhZEt/J9uuXBQSccMzRYCmzmrYw+oKB585RpLQVSp9KGOoP+PVzd1xNp3nvpa6beVLgdKJuNS8ol1kV0nzmX1CKmQpfOuF27qYA0xZLrbxcUHuBPj06Edmm0QGuxubT722CsVSWRXBoyNXogYvcZs4LAz2Jp8fIDOHBi6eoBAAA=" + } + }, + { + "ID": "54c2b7975b9ded5f", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonaa710eb1_2763_4fc3_8cce_efb46c0e6fac/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "40b04c397074ac60a282a3738112e62d/64971441296460732;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonaa710eb1_2763_4fc3_8cce_efb46c0e6fac/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:38 GMT" + ], + "Etag": [ + "lYp7Lg9TUX59KZ2nK3hNVw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8rnRBaY+6RbhoRGmFp6RxnleRtn+IWV29oCVZTklyTmBOWXFwOVGQP5RWBmdLVSGpgsAwonKtXqgFlQvoFSbSxUBFlZSVFpKkgGIokQT0LTbkia9mQ07UYEtcfWAgCkADU1GQEAAA==" + } + }, + { + "ID": "8ac1829693772108", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "307" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "181a7970a91dc7f5519682e078ac793d/1629146955399447372;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7ImRlZmF1bHREYXRhc2V0Ijp7ImRhdGFzZXRJZCI6ImRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn0sInF1ZXJ5Ijoic2VsZWN0IG5hbWUsIG51bXMsIHJlYyBmcm9tIHRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwNiIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiUFBpMTV1Y3Q1M0wyaWFQdGtZQlNjM1lEVnU4IiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:38 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/UNaM7aGyWdF3982EOLP3HcjZa20\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAIVT62rbMBR+laD9TWP5bgfG1iVuZpZlWS4tLQUjy8euGttKLDkhlLz7JDeF0o0MYxA63/ku59gvaMPqDA1RyopdC83x0zNPUR+BJIW6fURT8hDU2BkHP6pJDOtsXsazaQXkbiKM9Yz89MnkeJfd2GFgRb+mc/s7fX4gFn5EioRp4qwtKcirLW/kle9Zw/VyMJ8z022pdO2pxchcbu6/Lal9P75tA9UloMynrN6o3icpt2JoGIfDYVBwXpRAtkwMKK+MN7/G3jK2DX8GKoXxQctQWYRxQe1LySmRjNef10ulrOALyKGBmgIavqAzb/yPGK/ornI5zZuCAiqNUx9RXuesaJvz7YvmWR23ShD9XkeLe9XTBdOl80GPRPno1aSCfq9uK9HvNUB7ecOrniRpCYmFzQCHppWYnh+qx7N8jHGiXk8RZiAkqzvFlYb/P1xGJBHwWk1okAc4xWFqBmmOrRxy13coYBcH4GIHci8LfM8jqq9z03WRmte+8kRyD5Icp2niZA5OiA1uYmYmUOq4Qei43UwaIBLGTGy5YOdpjRbR9SpK4ptkFkXjaKzIDw37iLpbxAq0WqxnI4XuouakLeX41b8O+j7K+XxhXKbiuDSaky4zrpzoxcSzVbS4Hq3iW63dCphCQehxuSvRMCelgJPCC0lkK7QVfdKLVnZn8WyCzkWmtkM7QDcIvSVWaZzp2p5vWqYZOGpQHbiRf9W8wH7/0XQiFdTy/FUto2k0WiHtRBlsEqgIU/aQ7Xl2GNq26bhXarMSm7ySIbH8cEPtghZs97TblEHK06f2awZ7KPkWmkGhOPaMAqGUt7XUPyM6/QFIeZyRRwQAAA==" + } + }, + { + "ID": "69109145ce06044d", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/PPi15uct53L2iaPtkYBSc3YDVu8?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "dcf9e2d73bcbce0263fcf501c4c4ed11/3193322473797336028;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/PPi15uct53L2iaPtkYBSc3YDVu8?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:39 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/UNaM7aGyWdF3982EOLP3HcjZa20\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:39 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAIVSXWvjMBD8K0bPKUj+Tt56sXsYgsk5To88GVleFbW2lcoyRwj+7yepfig96CEEi2Z2d3ZWd/Qq2wo4KBgZoN0dXZV8BaaLDu1QN/cM9MNVKv2QxD7aWLZDjkdBopnpKDj4gh712+XHiQWX7HlODauXjGohR0M8n9CyQUyOXLzMan292zr17Woaol/nvLqYnPcZ1M1Ca4Am6I0Ob6QDbLxxHqaNp4B5XMnB07TtofExSfGW+A2Jk605sZ9gjBtzY1Owg0mL0XWsLf3/w3VU0wk+0IalPMUt3rYkbTn2OfAoCRngCKcQ4RB43KVJHFOT59S4LDrKMTGaKI+h4bhtm7ALcUMDiBrSEWAsjNJtGDlPFFANmZiuchKrW/sqf6zzpnhqyjzP8swU/6PEV9bvqjCkujqXe8N2o3I69zr70G8H/TzKGn9jFzE1vrNmsbCQRoldTFHWefW4r4tn23ue4AAvlN1O7z3acdpPsBj+pKmeJyvFRnbRRm5ZlD/RCgqzHeYIzgi7JTFYHomCOCE+IWlojHJkpf/B4jT4/GlckwFGvf6qU37I9zValuUvXSMdiuICAAA=" + } + }, + { + "ID": "18d40e9abc5de9b8", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/PPi15uct53L2iaPtkYBSc3YDVu8?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "fa88643cb22e64a7edb1b7805620dc6a/4757215417706951788;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/PPi15uct53L2iaPtkYBSc3YDVu8?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:39 GMT" + ], + "Etag": [ + "PBIdyrlaRCuLCPeTsBBmOg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/22RUWuDMBSF/8vdq4WtpdsQ+lBt6ARRl9pBGXtI462zjcYlV4aU/vfFbuAeSh5uDjlf7rnJGU5VU4AP+6r86tD0dyXS67DhaDtF1pVWNxbBAyRROmcWREVvlOBhF4cZ5jYI6rRcLJzDyk+sBfhnOFSoCgv++xkaUaPDrsUD6ttBbXIeJWuna10MOtnG8TKIGVy8kehqOxJRkrM14yPCWcaWOVv9RwzKkeAsTPnqRg/vRry91mpEgzSN2TK5le/DLQ+Oes/xgAYbicO8rdFHlBQNT1l0SiJNWm1o8vQ4hav7epJl1cO8kzSfxdNKZHTaBRs5263eumfnUloKqnTjjNuNmwpIk1Bcf7ugMIM/HfSENjNaorU4XHr/2yDUdauQXBoyHXoghfuMl4rAPwhl8fIDbyfvBeoBAAA=" + } + }, + { + "ID": "fd0b63146166beea", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon7809af6e_f0bb_4d40_a3e5_1d1ecc458945/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "fa88643cb22e64a7edb1b7805620dc6a/14798562719240564916;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon7809af6e_f0bb_4d40_a3e5_1d1ecc458945/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:40 GMT" + ], + "Etag": [ + "WtMREdw0pxUcf3j5mO+M+w==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qHl/gGuaaUGxRUhCanGWeZ5vpr+2qX29oCVZTklyTmBOWXFwOVGQP5RWBmdLVSGpgsAwonKtXqgFlQvoFSbSxUBFlZSVFpKkgGIokQT0LTbkia9mQ07UYEtcfWAgBkLvnjGQEAAA==" + } + }, + { + "ID": "9285fe28868bdb2b", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/PPi15uct53L2iaPtkYBSc3YDVu8?alt=json\u0026fields=status%2Cstatistics\u0026location=US\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a221793620b1b8be6fcb6c83ea4c552e/16362738237621676356;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/PPi15uct53L2iaPtkYBSc3YDVu8?alt=json\u0026fields=status%2Cstatistics\u0026location=US\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:40 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/wL_KfRMWxpj-uu3t8SmpPCaLZZw\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:40 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAM1WXWvbMBT9K0HkYYO2SHZiJ4Y99CNjhWYJSUofRgmOfdNqU2TPlteFkv++q+s4H467PYzBKAXrnqNzpat7pLyy3ISmyFnwSl/AAnYz+jxgmzMay9zIiNAoAxwmeiZXliS6rucLR4hep9NlRM7MCeb1XMRAx3Wk73sWMYkJ1dXaQD7OkgjyHGJkcUS+F5CtbV76GKtQs+DLK9Mh6Uw5D1q3Oi0MUmU1h9YwzI/ycE+UK6jH+z7GX0JpJnZblz+eWMAveBka5jQm0R1lGP48otCYKFiZuKZiQ4cqO8pepaTsVaJkhfuBIyEX1+90d1il2K3RK9ETeqlu6S+ZrGl3vJ7f3QKVsHfErGSPmaWmZebPxXKpYFQYzEaniECv04hMU6nU7nQziJIszidYAoy4+8gD5jCgt8E0zEKcpeik6fy2G1dgIB43oVU7s+vRcHw3mA0oBmlO7fNNaptwMri8sfFiUUGsLQLbW2etthPoYpXjhxvgoi7aMp/rxMx1oRQGOxRcJIlCgY+T0bBlwoWCucNFj/eFMxee38c/z/E553P899jj5myX+mFyW67pKLdNazPaBAjORq35HHfyBCiRUBFRhGR2BhBBqyxv5QDxhgOEzxsd4ArHTrXFm9pUtBTOHk9d0ek7ouyAA2+Qf+vmqDG3reL+S48ILrpNHhFus0lO+aU88WsuEeT2Q4MIp3dqkUPaVoxojf5wm53z//uj1qPU+w1dum91m+H+tNkd3go+tN61O1bs/V+ZQxyaAxsX8LVa4SMWNz4piIGSGminoMIUodITjutUj9FUJVsD+TZZir6R+uleS6ogP6xvFXSYzU2zseRG2lfyNPmbL90euTpsgQUOMPNMQoYdVl+dI/p2KWH0DJ+kYcEyVDnYLllCBjqCeGZvpfJQ0yz5CpG5tcpxoSIw52mSmXO8o1AjDk2YwxYtv39zmdkWoguP+H+++mxl6HfFCrSZrVO6uwZ3g+sZ22w2vwAzkX1kfggAAA==" + } + }, + { + "ID": "018f46de96ac24e1", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b4f204cdfe9fd5e349aa741c44ff8a3f/17998969146756112852;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:40 GMT" + ], + "Etag": [ + "X1Lt8cWOHQEz0ItOBjJFEA==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:40 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKtWKk7OSM1NVLKqVkrLTM1JKVayiq5WykvMTVWyglA6SiWVBSBecEiQp5+7Uq0OQr40txgh7+kX4uruGgQUyM1PAQkEuQa4Ooa4uiBrKUpNRugIcnX2D3IB8jGtTsrPz0EodPL393F19FOqjQXCWgCN1fK3tQAAAA==" + } + }, + { + "ID": "98f4a6a3b7764536", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "4b31f9527a8d79b5c8ba765b06f72b50/7957622940422448524;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:40 GMT" + ], + "Etag": [ + "a9WUQO9SRFFMJtQWcAmZKA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8onWoaHBvpbBge5ufl6lQSGJzvmRnk72toCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsA+lWqtUBs6B8A6XaWKgIsrKSotJUkAxEEiGehKbdkDTtyWjajQhqj60FALwx8C0ZAQAA" + } + }, + { + "ID": "51e6721f52f59ae0", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "fa50e22715b8956e3bb01dc9e9f585d9/9521797359325486364;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:41 GMT" + ], + "Etag": [ + "a9WUQO9SRFFMJtQWcAmZKA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8onWoaHBvpbBge5ufl6lQSGJzvmRnk72toCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsA+lWqtUBs6B8A6XaWKgIsrKSotJUkAxEEiGehKbdkDTtyWjajQhqj60FALwx8C0ZAQAA" + } + }, + { + "ID": "e5c050133f2501a3", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a0093d0b34b2a9ab559d20987db20813/1116682062109481572;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:41 GMT" + ], + "Etag": [ + "X1Lt8cWOHQEz0ItOBjJFEA==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:41 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKtWKk7OSM1NVLKqVkrLTM1JKVayiq5WykvMTVWyglA6SiWVBSBecEiQp5+7Uq0OQr40txgh7+kX4uruGgQUyM1PAQkEuQa4Ooa4uiBrKUpNRugIcnX2D3IB8jGtTsrPz0EodPL393F19FOqjQXCWgCN1fK3tQAAAA==" + } + }, + { + "ID": "61013beff392a86c", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "1db2b5040241ab73049dc035c9660560/11158029367937996460;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:41 GMT" + ], + "Etag": [ + "a9WUQO9SRFFMJtQWcAmZKA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8onWoaHBvpbBge5ufl6lQSGJzvmRnk72toCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsA+lWqtUBs6B8A6XaWKgIsrKSotJUkAxEEiGehKbdkDTtyWjajQhqj60FALwx8C0ZAQAA" + } + }, + { + "ID": "b3637af98d4e40d2", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "937caeb65a2be8db2d5361926a324767/2680857576212468468;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:41 GMT" + ], + "Etag": [ + "X1Lt8cWOHQEz0ItOBjJFEA==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:41 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKtWKk7OSM1NVLKqVkrLTM1JKVayiq5WykvMTVWyglA6SiWVBSBecEiQp5+7Uq0OQr40txgh7+kX4uruGgQUyM1PAQkEuQa4Ooa4uiBrKUpNRugIcnX2D3IB8jGtTsrPz0EodPL393F19FOqjQXCWgCN1fK3tQAAAA==" + } + }, + { + "ID": "b7533d90dc7a4ba3", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7aee1c64fcd8b29a5b1201f6442aa5b8/4317088489625029508;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0006?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:42 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "ddb9667a4acb1a5a", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "1956" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3dabf7deb467f828528833360df89951/5881264003728016148;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJtb2RlIjoiUkVRVUlSRUQiLCJuYW1lIjoiTmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVFVSVJFRCIsIm5hbWUiOiJCeXRlcyIsInR5cGUiOiJCWVRFUyJ9LHsibW9kZSI6IlJFUVVJUkVEIiwibmFtZSI6IkludGVnZXIiLCJ0eXBlIjoiSU5URUdFUiJ9LHsibW9kZSI6IlJFUVVJUkVEIiwibmFtZSI6IkZsb2F0IiwidHlwZSI6IkZMT0FUIn0seyJtb2RlIjoiUkVRVUlSRUQiLCJuYW1lIjoiQm9vbGVhbiIsInR5cGUiOiJCT09MRUFOIn0seyJtb2RlIjoiUkVRVUlSRUQiLCJuYW1lIjoiVGltZXN0YW1wIiwidHlwZSI6IlRJTUVTVEFNUCJ9LHsibW9kZSI6IlJFUVVJUkVEIiwibmFtZSI6IkRhdGUiLCJ0eXBlIjoiREFURSJ9LHsibW9kZSI6IlJFUVVJUkVEIiwibmFtZSI6IlRpbWUiLCJ0eXBlIjoiVElNRSJ9LHsibW9kZSI6IlJFUVVJUkVEIiwibmFtZSI6IkRhdGVUaW1lIiwidHlwZSI6IkRBVEVUSU1FIn0seyJtb2RlIjoiUkVRVUlSRUQiLCJuYW1lIjoiTnVtZXJpYyIsInR5cGUiOiJOVU1FUklDIn0seyJtb2RlIjoiUkVQRUFURUQiLCJuYW1lIjoiU3RyaW5nQXJyYXkiLCJ0eXBlIjoiU1RSSU5HIn0seyJtb2RlIjoiUkVQRUFURUQiLCJuYW1lIjoiSW50ZWdlckFycmF5IiwidHlwZSI6IklOVEVHRVIifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJGbG9hdEFycmF5IiwidHlwZSI6IkZMT0FUIn0seyJtb2RlIjoiUkVQRUFURUQiLCJuYW1lIjoiQm9vbGVhbkFycmF5IiwidHlwZSI6IkJPT0xFQU4ifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJUaW1lc3RhbXBBcnJheSIsInR5cGUiOiJUSU1FU1RBTVAifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJEYXRlQXJyYXkiLCJ0eXBlIjoiREFURSJ9LHsibW9kZSI6IlJFUEVBVEVEIiwibmFtZSI6IlRpbWVBcnJheSIsInR5cGUiOiJUSU1FIn0seyJtb2RlIjoiUkVQRUFURUQiLCJuYW1lIjoiRGF0ZVRpbWVBcnJheSIsInR5cGUiOiJEQVRFVElNRSJ9LHsibW9kZSI6IlJFUEVBVEVEIiwibmFtZSI6Ik51bWVyaWNBcnJheSIsInR5cGUiOiJOVU1FUklDIn0seyJmaWVsZHMiOlt7Im1vZGUiOiJSRVFVSVJFRCIsIm5hbWUiOiJTdHJpbmciLCJ0eXBlIjoiU1RSSU5HIn0seyJmaWVsZHMiOlt7Im1vZGUiOiJSRVFVSVJFRCIsIm5hbWUiOiJJbnRlZ2VyIiwidHlwZSI6IklOVEVHRVIifV0sIm1vZGUiOiJSRVFVSVJFRCIsIm5hbWUiOiJSZWNvcmQiLCJ0eXBlIjoiUkVDT1JEIn0seyJmaWVsZHMiOlt7Im1vZGUiOiJSRVFVSVJFRCIsIm5hbWUiOiJJbnRlZ2VyIiwidHlwZSI6IklOVEVHRVIifV0sIm1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJSZWNvcmRBcnJheSIsInR5cGUiOiJSRUNPUkQifV0sIm1vZGUiOiJSRVFVSVJFRCIsIm5hbWUiOiJSZWNvcmQiLCJ0eXBlIjoiUkVDT1JEIn0seyJmaWVsZHMiOlt7Im1vZGUiOiJSRVFVSVJFRCIsIm5hbWUiOiJTdHJpbmciLCJ0eXBlIjoiU1RSSU5HIn0seyJmaWVsZHMiOlt7Im1vZGUiOiJSRVFVSVJFRCIsIm5hbWUiOiJJbnRlZ2VyIiwidHlwZSI6IklOVEVHRVIifV0sIm1vZGUiOiJSRVFVSVJFRCIsIm5hbWUiOiJSZWNvcmQiLCJ0eXBlIjoiUkVDT1JEIn0seyJmaWVsZHMiOlt7Im1vZGUiOiJSRVFVSVJFRCIsIm5hbWUiOiJJbnRlZ2VyIiwidHlwZSI6IklOVEVHRVIifV0sIm1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJSZWNvcmRBcnJheSIsInR5cGUiOiJSRUNPUkQifV0sIm1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJSZWNvcmRBcnJheSIsInR5cGUiOiJSRUNPUkQifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMDcifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:42 GMT" + ], + "Etag": [ + "M6Ef4Hr6xTS2oBNwYYm8+A==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAO2VXW+bMBSG/4t3uTZ8rCMpUi9I43ZICemAXETTFLngUK+AmXGWRlH/+wwhpQUXWnWXE4qQzXnO++acg9mDe5KGwAS3JPq9wWz3iaPbGIMTgDmKxP7MgOuzb8x48D2djp3tcpmMPlsXFyKCFFy4iQPMTzPK+OnQ0M0QcZRjvtJVbaSea/pKM4bn4jL0oaqqK/HTBqVER8RQJM9xvJ6S9F5I3HGe5aaibLfbQURpFGOUkXwQ0EQ5ulb+6ErG6C8c8FxpWFIqS7nyBm9K6S1X3mKxjHHxGjOcBhiYe1BZsCWFEfGV/OFpv5WjQhnf7+dR1Cy4wwkqjKwJjsMcmD/2IEWJ8Aac4iYy7rJi5fmu7VyLdULDYu3C7wvbhROR5YkY7zjOa2S89KHXTdgpxxFmNWM7PryGbjd1FVPEa+ZqOrf8HmeUihlIn3mbz6fQcropnyQ45yjJas63Z9DzrdlNNzlB/FntJpYP+5VeivTnf8kUGv2cs0kwI0GNOYsZdO3LbsrjjKSRxRjadQ3EDRQeZO1tkJIet9Gyxw2w1eg2VjW6AUq63Uafut2ApS1v40VLGmSz73JNiVy/kgSUTUAbriagwUrGoI26OKAsrCEXXs7diWR0TiSnyWGG3neefEjwPUfLz5Zooz5t5ao8H1f+t9r/y/xqmYU6SDfJ4SNlAhWUyylNIx+z5rZLt8dVwDDihKbleWsC7esXY6jpmq6fGcVj/JARJgkwRuIjWwTEKOczGhLxD8JXchxffWs8LV7fmAZlQrG18MDjX4lI9YZyCQAA" + } + }, + { + "ID": "690c3513487270cf", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0007/insertAll?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "1210" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0911c5c52270c358c3fad9a912800775/7445439517831068579;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0007/insertAll?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJyb3dzIjpbeyJpbnNlcnRJZCI6Im9Ea05HekdRWlNXTThXSnlPT01xd21mWXJpOCIsImpzb24iOnsiQm9vbGVhbiI6dHJ1ZSwiQm9vbGVhbkFycmF5IjpbdHJ1ZSxmYWxzZV0sIkJ5dGVzIjoiWW5sMFpRPT0iLCJEYXRlIjoiMjAxNi0wMy0yMCIsIkRhdGVBcnJheSI6WyIyMDE2LTAzLTIwIiwiMTk5NC0wNS0xNSJdLCJEYXRlVGltZSI6IjIwMTYtMDMtMjAgMTU6MDQ6MDUuMDAwMDA2IiwiRGF0ZVRpbWVBcnJheSI6WyIyMDE2LTAzLTIwIDE1OjA0OjA1LjAwMDAwNiIsIjE5OTQtMDUtMTUgMDE6MDI6MDQiXSwiRmxvYXQiOjMuMTQsIkZsb2F0QXJyYXkiOlsxLDEuNDFdLCJJbnRlZ2VyIjo0MiwiSW50ZWdlckFycmF5IjpbMSwyXSwiTmFtZSI6ImEiLCJOdW1lcmljIjoiMC41NzAwMDAwMDAiLCJOdW1lcmljQXJyYXkiOlsiMC41MDAwMDAwMDAiLCIwLjYwMDAwMDAwMCJdLCJSZWNvcmQiOnsiUmVjb3JkIjp7IkludGVnZXIiOjI0fSwiUmVjb3JkQXJyYXkiOlt7IkludGVnZXIiOjF9LHsiSW50ZWdlciI6Mn1dLCJTdHJpbmciOiJzdHJpbmcifSwiUmVjb3JkQXJyYXkiOlt7IlJlY29yZCI6eyJJbnRlZ2VyIjowfSwiU3RyaW5nIjoiZW1wdHkifSx7IlJlY29yZCI6eyJJbnRlZ2VyIjoxfSwiUmVjb3JkQXJyYXkiOlt7IkludGVnZXIiOjF9LHsiSW50ZWdlciI6Mn1dLCJTdHJpbmciOiJmdWxsIn1dLCJTdHJpbmdBcnJheSI6WyJhIiwiYiJdLCJUaW1lIjoiMTU6MDQ6MDUuMDAwMDA2IiwiVGltZUFycmF5IjpbIjE1OjA0OjA1LjAwMDAwNiIsIjAxOjAyOjA0Il0sIlRpbWVzdGFtcCI6IjIwMTYtMDMtMjBUMTU6MDQ6MDUuMDAwMDA2WiIsIlRpbWVzdGFtcEFycmF5IjpbIjIwMTYtMDMtMjBUMTU6MDQ6MDUuMDAwMDA2WiIsIjE5OTQtMDUtMTVUMDE6MDI6MDRaIl19fSx7Imluc2VydElkIjoiVkRWMmVnWnJmck1VeXJ1NFRkeEZkanJjTkttIiwianNvbiI6eyJCb29sZWFuIjpmYWxzZSwiQnl0ZXMiOiJZbmwwWlRJPSIsIkRhdGUiOiIyMDE2LTAzLTIwIiwiRGF0ZVRpbWUiOiIyMDE2LTAzLTIwIDE1OjA0OjA1LjAwMDAwNiIsIkZsb2F0Ijo0LjEzLCJJbnRlZ2VyIjoyNCwiTmFtZSI6ImIiLCJOdW1lcmljIjoiMC40NDk5MDAwMDAiLCJSZWNvcmQiOnsiUmVjb3JkIjp7IkludGVnZXIiOjB9LCJTdHJpbmciOiIifSwiVGltZSI6IjE1OjA0OjA1LjAwMDAwNiIsIlRpbWVzdGFtcCI6IjIwMTYtMDMtMjBUMTU6MDQ6MDUuMDAwMDA2WiJ9fV19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:42 GMT" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTMK04tKnHMyQlKLS7IB3KUagGmFzWCLgAAAA==" + } + }, + { + "ID": "dae863d74de77b9a", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0007/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a1149ad7470188f7d07bcd1ed02df5cf/17486786823642806507;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0007/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:43 GMT" + ], + "Etag": [ + "SvX/Hw5Y35RpG8H4c0GIew==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/71TwW7CMAz9l+y6dk7qlLYSt0mAtMsYh7Gph3QLqFoHrA0ghPj3hSKalLZI06b1ENl+9rPzGu/JR7p4JxFJ0vnXWua7GyWSTN4LJR7SQpFbIpWYa/xp83w33PKpx8erQTDENxiM5Lbf1xlqqUQ2Xm4LnQbaz0vzdU9m5bnRYUEOtydrusjg5VHXnQPIKtNzKVaOyteycijyAAOfIXfh+PkVwoD6DngOA5PMI8AIrqROulLA5b2z0xg9IYe4jlHD3cRcayIXaSOhdsGZyArZ5Oi8ds8PQt/rMTx2uahqkyQM0QHuUN7s0SUFjYBp6Ap9p4ym3aSTRkttye4b3H43hcrTxZy0IKxkrFHaMLXQWlkZj6+Vys+V2rW1BLtj3M4/W2dZWy397bTxSR+DJfWVmozMSjGzRehS7/KR/ftOIYYhMcL9rWFr8pO/Vtrx4RslhnpFAQUAAA==" + } + }, + { + "ID": "7d4a1ff7f95295b5", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0007?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "44ca438d873ac62af5aa72f19c067a5a/9009613936717329459;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0007?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:43 GMT" + ], + "Etag": [ + "M6Ef4Hr6xTS2oBNwYYm8+A==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:43 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAO3UQW+DIBgG4P/C2V/gzVbakFTskB6WpQeirDMRbZAdjPG/r26mtMAgTXfcyXB4fMn3fmEEffnBBQPxCN5r3lQ9iN9G0DLBQQzw/ImAGs7zqaAE4e3lLLpqPhP4ckAEpmCKrmI1KN5rsnqlsPAL1Cp+4lIbhCncQuJXm6ZjSpvNLk9o4GZd13DW3twtz3cwwX5Fa8F7xcRZO4oyWNAk2/tlytTN7NKEwnDSfUj4//dmzgg7/Cm4rEvN8CGDBK39qlCybk+JlGzwLcQeXu7gqteQjo5t+t2xAa2ibbYUbUBH2za9tm1gZ+U2nysxpNm7O9MRF05yQNcG2HjZAMM61sCmhJedrDQicJ2T1LE6keM1+dmhx96TpwIfeVqOVqgxHzt5Gc/zyX+b/T/mX8d8nKYvwYtPn/EGAAA=" + } + }, + { + "ID": "4f40e1707444b20e", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0007?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "53207782f83b96439d80fe792b0b0461/10645845945346616515;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0007?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:43 GMT" + ], + "Etag": [ + "M6Ef4Hr6xTS2oBNwYYm8+A==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:43 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAO3UQW+DIBgG4P/C2V/gzVbakFTskB6WpQeirDMRbZAdjPG/r26mtMAgTXfcyXB4fMn3fmEEffnBBQPxCN5r3lQ9iN9G0DLBQQzw/ImAGs7zqaAE4e3lLLpqPhP4ckAEpmCKrmI1KN5rsnqlsPAL1Cp+4lIbhCncQuJXm6ZjSpvNLk9o4GZd13DW3twtz3cwwX5Fa8F7xcRZO4oyWNAk2/tlytTN7NKEwnDSfUj4//dmzgg7/Cm4rEvN8CGDBK39qlCybk+JlGzwLcQeXu7gqteQjo5t+t2xAa2ibbYUbUBH2za9tm1gZ+U2nysxpNm7O9MRF05yQNcG2HjZAMM61sCmhJedrDQicJ2T1LE6keM1+dmhx96TpwIfeVqOVqgxHzt5Gc/zyX+b/T/mX8d8nKYvwYtPn/EGAAA=" + } + }, + { + "ID": "0e1c74c13bd781dc", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0007/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "055dc6ecbb169da27e90a48dbb47af49/604498639518101627;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0007/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:43 GMT" + ], + "Etag": [ + "SvX/Hw5Y35RpG8H4c0GIew==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/71TwW7CMAz9l+y6dk7qlLYSt0mAtMsYh7Gph3QLqFoHrA0ghPj3hSKalLZI06b1ENl+9rPzGu/JR7p4JxFJ0vnXWua7GyWSTN4LJR7SQpFbIpWYa/xp83w33PKpx8erQTDENxiM5Lbf1xlqqUQ2Xm4LnQbaz0vzdU9m5bnRYUEOtydrusjg5VHXnQPIKtNzKVaOyteycijyAAOfIXfh+PkVwoD6DngOA5PMI8AIrqROulLA5b2z0xg9IYe4jlHD3cRcayIXaSOhdsGZyArZ5Oi8ds8PQt/rMTx2uahqkyQM0QHuUN7s0SUFjYBp6Ap9p4ym3aSTRkttye4b3H43hcrTxZy0IKxkrFHaMLXQWlkZj6+Vys+V2rW1BLtj3M4/W2dZWy397bTxSR+DJfWVmozMSjGzRehS7/KR/ftOIYYhMcL9rWFr8pO/Vtrx4RslhnpFAQUAAA==" + } + }, + { + "ID": "5c31e4be2edc72ad", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0007?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3cb21170e364a816a443fa2f5daeb31e/12210021459432826195;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0007?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:44 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "2063f51f58a39c14", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "621" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8b62833eb4722856ddff6615acc1ce20/13774195874040962531;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoiU3RyaW5nIiwidHlwZSI6IlNUUklORyJ9LHsibmFtZSI6IkJ5dGVzIiwidHlwZSI6IkJZVEVTIn0seyJuYW1lIjoiSW50ZWdlciIsInR5cGUiOiJJTlRFR0VSIn0seyJuYW1lIjoiRmxvYXQiLCJ0eXBlIjoiRkxPQVQifSx7Im5hbWUiOiJCb29sZWFuIiwidHlwZSI6IkJPT0xFQU4ifSx7Im5hbWUiOiJUaW1lc3RhbXAiLCJ0eXBlIjoiVElNRVNUQU1QIn0seyJuYW1lIjoiRGF0ZSIsInR5cGUiOiJEQVRFIn0seyJuYW1lIjoiVGltZSIsInR5cGUiOiJUSU1FIn0seyJuYW1lIjoiRGF0ZVRpbWUiLCJ0eXBlIjoiREFURVRJTUUifSx7Im5hbWUiOiJOdW1lcmljIiwidHlwZSI6Ik5VTUVSSUMifSx7ImZpZWxkcyI6W3sibmFtZSI6IlgiLCJ0eXBlIjoiSU5URUdFUiJ9XSwibmFtZSI6IlJlY29yZCIsInR5cGUiOiJSRUNPUkQifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMDgifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:44 GMT" + ], + "Etag": [ + "W2yx6EApMBk70HlgkWFf+Q==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Tb2+bMBDGv4v3cm34swVSpL4gjdMhQbIRqm6apsiFC/UCNrOdpVG07z5Dk0FYtlYWL+78u+cen80erSnLkIceaP5jA2L3RpGHAtAFAkVynb+3d08O9qtovHbND0W+vp+u3n66vtYEreuyTZGCuqy4UJeuY3sZUUSCWtqmNTKvLHtpOe6VXo7tmqa51J81aFr8hxhpcQnFKqRsrVs8KlVJzzC22+0g5zwvgFRUDlJeGkfXxk/bqAT/DqmSRs+ScbAkjVd4Mxpv0niNxYaJYQUCWArI26ODheDMYDR/aP+8+7KVY4eGf9nPLz2z9BFKUhtZUSgyibyve8RIqb2hhRKU5bXmrmriJA5mt7rqDzHeKZAtMP6S4EV3P2AKchAtEcwSfIvjLjMtOFEtMQ3nfnLSg3N9e6zTZT4PsT/rMgktQSpSVi2VBBFeJH70sctNiIIWmfgJ7qucCvRrT4m6vk/NNiUImrbQ7C7CcXDTZWJIuchaJMY383ii47+v4POZ0X3T6wKxTfk8fQ+ZqAlDzvIERD8d8+0xSgUQRTlrjuEha/jOcS3bst8Ph8P6932qqDgDOCP9Wur6gkgV8Yxqn9k/NI7D88chrit42gjq1J1+Gb8BKXZp8TsEAAA=" + } + }, + { + "ID": "158d342f0cfd5930", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008/insertAll?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "190" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "aa53f7793ac8b1441cc628869314575b/15410427886948374131;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008/insertAll?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJyb3dzIjpbeyJpbnNlcnRJZCI6Im5Ra2MzS0pJYXJqeERaenp4bEY5bXk3Uld0UyIsImpzb24iOnsiQm9vbGVhbiI6bnVsbCwiQnl0ZXMiOm51bGwsIkRhdGUiOm51bGwsIkRhdGVUaW1lIjpudWxsLCJGbG9hdCI6bnVsbCwiSW50ZWdlciI6bnVsbCwiU3RyaW5nIjpudWxsLCJUaW1lIjpudWxsLCJUaW1lc3RhbXAiOm51bGx9fV19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:45 GMT" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTMK04tKnHMyQlKLS7IB3KUagGmFzWCLgAAAA==" + } + }, + { + "ID": "d7c2ac609f016900", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "4c396fdda82fe30740458c16a9c22b59/6933256095222846139;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:45 GMT" + ], + "Etag": [ + "LH1kvAzN546bzPM5X8V7hg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8r7eBhmlzlW+ZmamCVVBfiaRliEmWek29oCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsU7LKK83JqdWhKzMWCAF0/p3i3QAAAA==" + } + }, + { + "ID": "364aa1bfa3830b87", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a77e2432557a2baa01d7f0d742fdf0e1/16974603401051360771;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:45 GMT" + ], + "Etag": [ + "W2yx6EApMBk70HlgkWFf+Q==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:45 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAG3RzQqDMAwA4HfJ2Sfw5k+VgtZRO9gYOxTNtoJV0e4g4rvP7bBWN3IK+ZJAMsNYPVBL8Ge4KWzqEfzLDK3UCD6UZlDtHTwwU//JBacshcX7inAyOFoQngUp3TptDd5xsIIyQVLCXZM0nTRWJFkRiM2OrmtQts6WoshIwFwjlMbRSN1bJWhOShHkB9fF0qAlcSDIfsp2wL53K979e8WeGgdVWcSOOeE0cg3HqhtqSziJCh6v+e8LTn9Od11jeQEGk6RuugEAAA==" + } + }, + { + "ID": "4e295db815d44a8a", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3c759c965f41f893b99a4f2222941283/8569487004340505419;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:46 GMT" + ], + "Etag": [ + "LH1kvAzN546bzPM5X8V7hg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8r7eBhmlzlW+ZmamCVVBfiaRliEmWek29oCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsU7LKK83JqdWhKzMWCAF0/p3i3QAAAA==" + } + }, + { + "ID": "6794db492ddebb09", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "bc327f6d0ca48a02e9260ad644403d36/92315216909879187;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:46 GMT" + ], + "Etag": [ + "W2yx6EApMBk70HlgkWFf+Q==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:46 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAG3RzQqDMAwA4HfJ2Sfw5k+VgtZRO9gYOxTNtoJV0e4g4rvP7bBWN3IK+ZJAMsNYPVBL8Ge4KWzqEfzLDK3UCD6UZlDtHTwwU//JBacshcX7inAyOFoQngUp3TptDd5xsIIyQVLCXZM0nTRWJFkRiM2OrmtQts6WoshIwFwjlMbRSN1bJWhOShHkB9fF0qAlcSDIfsp2wL53K979e8WeGgdVWcSOOeE0cg3HqhtqSziJCh6v+e8LTn9Od11jeQEGk6RuugEAAA==" + } + }, + { + "ID": "c2d3bedabe3cf88b", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "941612b749be5bbb7b68aa21fc286522/10133381052056650715;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:46 GMT" + ], + "Etag": [ + "LH1kvAzN546bzPM5X8V7hg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8r7eBhmlzlW+ZmamCVVBfiaRliEmWek29oCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsU7LKK83JqdWhKzMWCAF0/p3i3QAAAA==" + } + }, + { + "ID": "25eb29aad5951ac0", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ed5c2f3b3fb604996afabe87b2d522de/1728265754857422627;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:46 GMT" + ], + "Etag": [ + "W2yx6EApMBk70HlgkWFf+Q==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:46 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAG3RzQqDMAwA4HfJ2Sfw5k+VgtZRO9gYOxTNtoJV0e4g4rvP7bBWN3IK+ZJAMsNYPVBL8Ge4KWzqEfzLDK3UCD6UZlDtHTwwU//JBacshcX7inAyOFoQngUp3TptDd5xsIIyQVLCXZM0nTRWJFkRiM2OrmtQts6WoshIwFwjlMbRSN1bJWhOShHkB9fF0qAlcSDIfsp2wL53K979e8WeGgdVWcSOOeE0cg3HqhtqSziJCh6v+e8LTn9Od11jeQEGk6RuugEAAA==" + } + }, + { + "ID": "9ade9d0d09ff3707", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9b06b4df072dc182e51c724fc05c0a47/3292441273238534323;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0008?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:46 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "a288f43778726172", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "621" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ab837ed06e9a71f05498354cf1de2319/4856615687846670403;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoiU3RyaW5nIiwidHlwZSI6IlNUUklORyJ9LHsibmFtZSI6IkJ5dGVzIiwidHlwZSI6IkJZVEVTIn0seyJuYW1lIjoiSW50ZWdlciIsInR5cGUiOiJJTlRFR0VSIn0seyJuYW1lIjoiRmxvYXQiLCJ0eXBlIjoiRkxPQVQifSx7Im5hbWUiOiJCb29sZWFuIiwidHlwZSI6IkJPT0xFQU4ifSx7Im5hbWUiOiJUaW1lc3RhbXAiLCJ0eXBlIjoiVElNRVNUQU1QIn0seyJuYW1lIjoiRGF0ZSIsInR5cGUiOiJEQVRFIn0seyJuYW1lIjoiVGltZSIsInR5cGUiOiJUSU1FIn0seyJuYW1lIjoiRGF0ZVRpbWUiLCJ0eXBlIjoiREFURVRJTUUifSx7Im5hbWUiOiJOdW1lcmljIiwidHlwZSI6Ik5VTUVSSUMifSx7ImZpZWxkcyI6W3sibmFtZSI6IlgiLCJ0eXBlIjoiSU5URUdFUiJ9XSwibmFtZSI6IlJlY29yZCIsInR5cGUiOiJSRUNPUkQifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMDkifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:47 GMT" + ], + "Etag": [ + "c3o/50vUjHLK10TGcNSi5Q==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2TYW+bMBCG/4v3tY2BKKFB6gfS0AyNkI4QqdM0Ra65ULeAme00i6L99xmaFMKytbL4cOfn3nt9Nnv0zIoEOeiBpT83IHafFHnIAF0gUCTVedrneGC8LJ8+B19MI57ScMEGX6+vNcGqumSTUVCXJRfq0h5aTkIUkaBWlmFeGSPTWplDe6TX0LINw1jpz+zVLf5DjLS4hGwdsOJZt3hUqpQOxtvttpdynmZASiZ7lOf46Bq/WLgU/AmokrhjCR8sSfwBb7j2JvFHLNZMBGsQUFBAzh4dLPhnBqP5Q/vX3fetHDvU/Pt+fuuZ0UfISWVkzSBLJHK+71FBcu0NLZRgRVpp7so6jiM/nOqqN2K8UyAbYPwt9hbtfb9QkIJoCD+MvakXtZnbjBPVELfB3I1PenCub69odZnPA88N20zMcpCK5GVDxf7MW8Tu7K7NTYiCBpm4sddVORXo1p4SVX2XCjc5CEYbKFzOvMi/aTMRUC6SBom8m3k00fHfV3B/ZnQ/9LpAxSZ/nb6DDFSHAS/SGEQ3HfHtMaICiGK8qI/hIHPQH9qmZVq2Zfer3/dXycQZYHilX0tVnxGpZjxh2mfyD43j8Nxx4FUVnNaCOrXUL+MPWzhjrDsEAAA=" + } + }, + { + "ID": "a4058cd3c30dc54e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009/insertAll?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "301" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "1a3c6c927aa32f514a255c1783299bdb/6420791201932880339;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009/insertAll?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJyb3dzIjpbeyJpbnNlcnRJZCI6ImNwNDkxWmdkN1BMM0M4QkFOUzhOeWdpTDZNRyIsImpzb24iOnsiQm9vbGVhbiI6dHJ1ZSwiQnl0ZXMiOiJBUUlEIiwiRGF0ZSI6IjIwMTYtMTEtMDUiLCJEYXRlVGltZSI6IjIwMTYtMTEtMDUgMTU6MDQ6MDUuMDAwMDA2IiwiRmxvYXQiOjIuMywiSW50ZWdlciI6MSwiTnVtZXJpYyI6IjAuMzMwMDAwMDAwIiwiUmVjb3JkIjp7IlgiOjR9LCJTdHJpbmciOiJ4IiwiVGltZSI6IjE1OjA0OjA1LjAwMDAwNiIsIlRpbWVzdGFtcCI6IjIwMTYtMTEtMDVUMDc6NTA6MjIuMDAwMDAwMDA4WiJ9fV19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:47 GMT" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTMK04tKnHMyQlKLS7IB3KUagGmFzWCLgAAAA==" + } + }, + { + "ID": "a18e9a527be887c2", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8aac8d4efda25cce4972434b0daf10b5/16462138507761394971;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:48 GMT" + ], + "Etag": [ + "uuGQBLFM/reaKzVFRENMlQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qXlroHOvm4+eoXpSZ6V4W5Bbn6+eYE2toCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsAwpXKNXqQFiOgZ4ucI4hnGWkZwxnlxSVpiKUmJhbGBsbAYGeAUK1gaGZrqGhroEpQp2plYGJlYGpngEImGFRGoJLiYGeMdxyZEebKNXG1gJRbC0A+g8DgCYBAAA=" + } + }, + { + "ID": "18457e0fe97dc01c", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "010bb6f522615297dc267e36c0535873/8057023210562167139;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:48 GMT" + ], + "Etag": [ + "c3o/50vUjHLK10TGcNSi5Q==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:48 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAG3RzQqDMAwA4HfJ2Sfw5k+VgtZRO9gYOxTNtoJV0e4g4rvP7bBWN3IK+ZJAMsNYPVBL8Ge4KWzqEfzLDK3UCD6UZlDtHTwwU//JBacshcX7inAyOFoQngUp3TptDd5xsIIyQVLCXZM0nTRWJFkRiM2OrmtQts6WoshIwFwjlMbRSN1bJWhOShHkB9fF0qAlcSDIfsp2wL53K979e8WeGgdVWcSOOeE0cg3HqhtqSziJCh6v+e8LTn9Od11jeQEGk6RuugEAAA==" + } + }, + { + "ID": "c228ceadfd685dc9", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "61839963d78598cfce7695c959f7617f/18026312922369531307;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:48 GMT" + ], + "Etag": [ + "uuGQBLFM/reaKzVFRENMlQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qXlroHOvm4+eoXpSZ6V4W5Bbn6+eYE2toCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsAwpXKNXqQFiOgZ4ucI4hnGWkZwxnlxSVpiKUmJhbGBsbAYGeAUK1gaGZrqGhroEpQp2plYGJlYGpngEImGFRGoJLiYGeMdxyZEebKNXG1gJRbC0A+g8DgCYBAAA=" + } + }, + { + "ID": "9c61247cae7302f9", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d04804f12887eb4cf597d4490e3034b6/9621197629448428275;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:48 GMT" + ], + "Etag": [ + "c3o/50vUjHLK10TGcNSi5Q==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:48 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAG3RzQqDMAwA4HfJ2Sfw5k+VgtZRO9gYOxTNtoJV0e4g4rvP7bBWN3IK+ZJAMsNYPVBL8Ge4KWzqEfzLDK3UCD6UZlDtHTwwU//JBacshcX7inAyOFoQngUp3TptDd5xsIIyQVLCXZM0nTRWJFkRiM2OrmtQts6WoshIwFwjlMbRSN1bJWhOShHkB9fF0qAlcSDIfsp2wL53K979e8WeGgdVWcSOOeE0cg3HqhtqSziJCh6v+e8LTn9Od11jeQEGk6RuugEAAA==" + } + }, + { + "ID": "beadbb8f9c37e820", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0822927c4645a99a7ef47c250561d97f/11185373143551414915;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:48 GMT" + ], + "Etag": [ + "c3o/50vUjHLK10TGcNSi5Q==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:48 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAG3RzQqDMAwA4HfJ2Sfw5k+VgtZRO9gYOxTNtoJV0e4g4rvP7bBWN3IK+ZJAMsNYPVBL8Ge4KWzqEfzLDK3UCD6UZlDtHTwwU//JBacshcX7inAyOFoQngUp3TptDd5xsIIyQVLCXZM0nTRWJFkRiM2OrmtQts6WoshIwFwjlMbRSN1bJWhOShHkB9fF0qAlcSDIfsp2wL53K979e8WeGgdVWcSOOeE0cg3HqhtqSziJCh6v+e8LTn9Od11jeQEGk6RuugEAAA==" + } + }, + { + "ID": "f04f1ae59719afa5", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3109c8b0bfcd4eefd76281815464ac1f/1216082332249200187;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:48 GMT" + ], + "Etag": [ + "uuGQBLFM/reaKzVFRENMlQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qXlroHOvm4+eoXpSZ6V4W5Bbn6+eYE2toCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsAwpXKNXqQFiOgZ4ucI4hnGWkZwxnlxSVpiKUmJhbGBsbAYGeAUK1gaGZrqGhroEpQp2plYGJlYGpngEImGFRGoJLiYGeMdxyZEebKNXG1gJRbC0A+g8DgCYBAAA=" + } + }, + { + "ID": "7ba388f1e057ef57", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "60eb97d2965a873ec961ecdc6a20ad0a/12821605152163924755;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0009?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:49 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "e002b8d5a3ceeac8", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "360" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "070f90934cf3ded9bc82eef283352643/14385779571066962851;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTAifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:49 GMT" + ], + "Etag": [ + "gki5seyVmgunOkAf5867aA==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SUW+CMBSF/0v3qhbYBCXxAScxJk4XZHtZFlPhip1AGa1zxvjfd4sYF+eypWnIvT3nni837Mma5zFxyYIn7xsodzeKLVIgDQKKJdhP1rwtYfecJZt8uvaW7Y7tMK/XQwXXvniTRqCahShV07EtN2aKSVBzyzA7Rte05qbtdPHYlmMYxhyv2aoifleYBg6XkC7HPF9jxEqpQrqUbrfbViJEkgIruGxFIqMnavph0aIUbxApSS+QaI0k6T/YaMUm6X8QK00ASyghj4C4e1IjjK4sBvV1/PH1b5RTQqX/m+eAO4tWkDENsuSQxpK4L3uSswzZjh+cuCt0NQuD0WSInvP7JpPn99Ek9Id+gI1MxLoR+I++F/qD75YSorMj8O+nwQDrn9ELIdKzsD+djn1vQg6veBo6t79TgAaid4rlWORJCOVlOxDbUxWVwBQXecir+Wb71nZMy7S6t3cd/ed+Fry8IrA7uCztT5lUDyLmiBr/MqOGDb3+2NcOEVUDsfU0I4cviqXwuDYDAAA=" + } + }, + { + "ID": "493710d2bb26cdd5", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e2676841773a366f7bd42f6f3e716f63/15949955085169949491;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:49 GMT" + ], + "Etag": [ + "gki5seyVmgunOkAf5867aA==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:49 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SUW+CMBSF/0v3qhbYBCXxAScxJk4XZHtZFlPhip1AGa1zxvjfd4sYF+eypWnIvT3nni837Mma5zFxyYIn7xsodzeKLVIgDQKKJdhP1rwtYfecJZt8uvaW7Y7tMK/XQwXXvniTRqCahShV07EtN2aKSVBzyzA7Rte05qbtdPHYlmMYxhyv2aoifleYBg6XkC7HPF9jxEqpQrqUbrfbViJEkgIruGxFIqMnavph0aIUbxApSS+QaI0k6T/YaMUm6X8QK00ASyghj4C4e1IjjK4sBvV1/PH1b5RTQqX/m+eAO4tWkDENsuSQxpK4L3uSswzZjh+cuCt0NQuD0WSInvP7JpPn99Ek9Id+gI1MxLoR+I++F/qD75YSorMj8O+nwQDrn9ELIdKzsD+djn1vQg6veBo6t79TgAaid4rlWORJCOVlOxDbUxWVwBQXecir+Wb71nZMy7S6t3cd/ed+Fry8IrA7uCztT5lUDyLmiBr/MqOGDb3+2NcOEVUDsfU0I4cviqXwuDYDAAA=" + } + }, + { + "ID": "e8e3484ec63a570d", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "78" + ], + "Content-Type": [ + "application/json" + ], + "If-Match": [ + "gki5seyVmgunOkAf5867aA==" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "1c58841ce41e47a90a0a51002af34509/17514130599256159427;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJkZXNjcmlwdGlvbiI6Im1vcmUiLCJleHBpcmF0aW9uVGltZSI6IjE1MzY3OTkwODAwMDAiLCJmcmllbmRseU5hbWUiOiJtb3JlIn0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:50 GMT" + ], + "Etag": [ + "HL6x8nYV77/pV6D5PubtdQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SUW+iQBSF/8vsq3UAFYSkD1pJa0K1pWyTzaYx48yVzhYYOjPWGuN/7wzVsLG7qSGE3Dvn3PNxYYdeeMVQhJY8f12D3P7QZFkA6iDQJDf9m8R/H1a/HoMA14/+ZHC3Xmp2f3lpFNz62LqgoC9qIfVF4HsRI5oo0AvPcYdO6HoL1w9Cc/le4DjOwtxut4n4v8J1zHAFxSrh1YuJeNa6VhHGm82mmwuRF0BqrrpUlPhIjd88XEvxB6hW+AQJH5AUPoMNN2wKn4PYaFJYgYSKAop26IAw/cdijP4Q/3n6PcoxodF/z7PvoJXkULFiOyOlwUGlkPZDMlBU8lpzUbVNRZ+hJJZ5xaFgCkW/d6j69DUPE76tbfWQpdPZtRnfnq9L1Z5PZ1l8HaemUQpmG2l8F4+yePK3RQJtHWl8NU8npv4avRSiaIXj+TyJRzO0fzJXx+aOtxqMAdn1mzIRVZ6BPG2nYnOsqARi3zzjzXx30PMD13O9sNcf2p/8vebyiyAMnaHZq/UXROlbwbhBZSczeo436Lew2WicxNYhKDns+ucD2n8A1NJf72EDAAA=" + } + }, + { + "ID": "960ecbe0fdbf75fd", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "21" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "4c3d0d5078045f4009ab48bd68cd8cbc/703898909657754707;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJmcmllbmRseU5hbWUiOiJ4In0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:50 GMT" + ], + "Etag": [ + "6KX69ApLJuO1eEj32rJusA==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SUW+bMBSF/4v7msaYtCQg9YG0VpWOJRWl0qRpihxzQ90CZrZZGkX577UpUaZ0UyuE0L0+556PCzv0IuocRWglit8tqO2ZYasS0ACBYYXtB99+BGHcJHftggB9HvnqrtXx1ZVVCOfL25KDOW+kMufjwI9yZpgGs/Q9MvFC4i9JMA7tFfhjz/OW9ibDLuL/CuLZ4RrKdSLqFxvxZEyjI4w3m82wkLIogTVCD7ms8IEa//Fxo+QzcKPxCRLukTT+Ahvu2DT+CmKnSWENCmoOKNqhHmH2j8VYfR//fvo5yiGh03/Osx+gtRJQ5+V2ziqLg15dJmiuRGOErG2nksp9Ws2foGIOeC2gzDWKfu5Q/W7qHjZ527jqIUtn81s7+3jeVvp4Pptn9JamtlHJ3DVSek/jjN78bVHAj46UXi/SG1t/jF5JWR6F08UiofEc7X/Za+Byp1sD1oDc7m2ZyLrIQJ22U7k5VFwBc2+eiW4+uRwFY+ITPxxdTNwf/toI9UEQht7ELtX5S6bNd5kLi5qfzBh5k25GD5vF04Q6h+Ss3/XjA9q/AdiftvBeAwAA" + } + }, + { + "ID": "2ea01c7d2803f895", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "21" + ], + "Content-Type": [ + "application/json" + ], + "If-Match": [ + "HL6x8nYV77/pV6D5PubtdQ==" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "79eaf13b377250eee8254f67d0669f41/2268074428038866403;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJmcmllbmRseU5hbWUiOiJ5In0K" + }, + "Response": { + "StatusCode": 412, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:51 GMT" + ], + "Etag": [ + "6KX69ApLJuO1eEj32rJusA==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:51 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAIWNsQoCMRBEf0W2PgvFKh8gWJxY2MkVa3a9C+SyskkjIf/uBkHs7Ib3hpkKrCoKrn5CBnerQLJiSOBgjnLHCAMoY5ZOvCQKJUg6Sxm5mFo5Z5zZ3EX5qzdHDJHJfBSPnVxfz15aGIn1hxs7PbYjFr9AmwZ7IOsddvt/0629Ad0ZvLW+AAAA" + } + }, + { + "ID": "17d52b21ca8d7cda", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "293" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "aa7379a6ebd979e1edbeab1a9bc564d6/3832248842647002483;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7ImZpZWxkcyI6W3sibmFtZSI6Im5lc3RlZCIsInR5cGUiOiJCT09MRUFOIn0seyJuYW1lIjoib3RoZXIiLCJ0eXBlIjoiU1RSSU5HIn1dLCJuYW1lIjoicmVjMiIsInR5cGUiOiJSRUNPUkQifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifV19fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:51 GMT" + ], + "Etag": [ + "5sWqMHDx43/yr7P8pBW3Gg==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TX2/aMBD/Lt5ri+OEEhKpDzAihkShSjP1YaqQcY7gNYlT2wwixHevnYKyQaeiKIru/Pt3PmWPXnmZohAtefa2AVl/03SZA7pBoGlm+nfq+e3hx2jX9XAt/cd+NXz2xtn9vUFwy0s3OQN9Wwmpb/2eG6ZUUwV64Tqk7wTEXZCeH5in5/qO4yzMSzqNxf8RxDHiCvLVlJevxmKtdaVCjLfbbScTIsuBVlx1mCjwKTX+4+JKit/AtMJnkfAxksJXZMNNNoWvidhgYliBhJIBCvfoGGHyycUY/NH+4/TrKCeHBv91nsMNWkkOZZrXM1qYOGhnPUExySvNRWk6hZB2tYqtoaA28IpDnioU/tqj8oPUfIxzXdnqKYkns7HRbs83hWrPJ7MkGkexaRQitY04eowGSTT6myKBtYw4+j6PR6a+tF4KkbfA4Xw+jQYzdHj5V8q9SqsEpSH9RK3VEnoN8nLUF2toxxzWGowmsqs25VSUWQLyvB2L7aliEqi96IQ3+uTO6/nEJW7gdfv2h9pVXF4AgsDpmx1afk6VfhApN9OkZxoe8btemzUZDKeRZQhGj6v9+YQO75ApRajNAwAA" + } + }, + { + "ID": "37e8baf6250fcd88", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "14" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "4b116386c026bc421428cd3244072335/5468480851259512323;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJzY2hlbWEiOnt9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:52 GMT" + ], + "Etag": [ + "5sWqMHDx43/yr7P8pBW3Gg==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TX2/aMBD/Lt5ri+OEEhKpDzAihkShSjP1YaqQcY7gNYlT2wwixHevnYKyQaeiKIru/Pt3PmWPXnmZohAtefa2AVl/03SZA7pBoGlm+nfq+e3hx2jX9XAt/cd+NXz2xtn9vUFwy0s3OQN9Wwmpb/2eG6ZUUwV64Tqk7wTEXZCeH5in5/qO4yzMSzqNxf8RxDHiCvLVlJevxmKtdaVCjLfbbScTIsuBVlx1mCjwKTX+4+JKit/AtMJnkfAxksJXZMNNNoWvidhgYliBhJIBCvfoGGHyycUY/NH+4/TrKCeHBv91nsMNWkkOZZrXM1qYOGhnPUExySvNRWk6hZB2tYqtoaA28IpDnioU/tqj8oPUfIxzXdnqKYkns7HRbs83hWrPJ7MkGkexaRQitY04eowGSTT6myKBtYw4+j6PR6a+tF4KkbfA4Xw+jQYzdHj5V8q9SqsEpSH9RK3VEnoN8nLUF2toxxzWGowmsqs25VSUWQLyvB2L7aliEqi96IQ3+uTO6/nEJW7gdfv2h9pVXF4AgsDpmx1afk6VfhApN9OkZxoe8btemzUZDKeRZQhGj6v9+YQO75ApRajNAwAA" + } + }, + { + "ID": "2ec4ad755fd9216d", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "311" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6762f743dc17ddf9a1a059cf86faccba/7032374894680755859;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJzY2hlbWEiOnsiZmllbGRzIjpbeyJtb2RlIjoiUkVRVUlSRUQiLCJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifSx7ImZpZWxkcyI6W3sibmFtZSI6Im5lc3RlZCIsInR5cGUiOiJCT09MRUFOIn0seyJuYW1lIjoib3RoZXIiLCJ0eXBlIjoiU1RSSU5HIn1dLCJuYW1lIjoicmVjMiIsInR5cGUiOiJSRUNPUkQifV19fQo=" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:53 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:53 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAANWPwWrDMAyGX0Xo3BY7lGT1bWUpDMLYuvU0RlBtLQnY0bC9XkLffS477wHGj+Dn4xNIC3KMEtEsvyWheV/QSaBpRoODlzN5XGFkSnIj03whP7mCAqdEAxf2HOUyOXbwakcOBE44wSwZAmU7whudPYP79pbz+ktiXjd1ZRxlSpz7Suk7tdNVr+tmV1JXjVKqL6M3+bb5t6HVBg4TewczBYaREtiR5qFcEsQxfEYJ8HTquvt910IWOLYvp8dj+4DXjxXaoqDZKvXPX7n+AJ2bPBfEAQAA" + } + }, + { + "ID": "21d185280f0121d6", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "342" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e07e5aea7e2f57be43c5a4a31e175368/8596549313567016739;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifSx7ImZpZWxkcyI6W3sibmFtZSI6Im5lc3RlZCIsInR5cGUiOiJCT09MRUFOIn0seyJuYW1lIjoib3RoZXIiLCJ0eXBlIjoiU1RSSU5HIn1dLCJuYW1lIjoicmVjMiIsInR5cGUiOiJSRUNPUkQifSx7Im1vZGUiOiJSRVFVSVJFRCIsIm5hbWUiOiJyZXEiLCJ0eXBlIjoiU1RSSU5HIn1dfX0K" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:54 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:54 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAN2P0WrDMAxFf0XoaYM22GEkq1/3A4PtbZSgRlpqcKzNdksh9N/ntM/9gSEE4ugK3bugpKQJ3XIfMrqvBVln8hEdTkEPFHCDSSjrSnw8U/Bc0Sw50ySVvSc9exaGj/EoMwGrZIhaYKYyHuGTDkGAT2GUsv3RVLZ91zqmQlnK0Br7ana2HWzX72p1bW+MGWrbpqyXjxXWNPBGcf1EzJDk9+RTtfHtJXCGokAR5OJz8XGCfDPXwNNt7Vb5M173GxyVa4oXY/5Lpusf4NFcDNYBAAA=" + } + }, + { + "ID": "5d10aaa4fbfb4fd1", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "182" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "94be27a86a8d0ea9609bfd7402418632/10160724827670003635;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifV19fQo=" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:54 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:54 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAANWOTWoDMQyFryK0ToJtykwzB+i60O5CGRRbTAT+KZaTLobcvU6yzgGCeCA+3oNvRa61VJzWx6M4HVYMJZFknHCJ5UgRN1iZtNyI5AtFCR0lVqWFO/us5SKBA3z5EyeCUFghlwaJmj/BNx0jQzhHz237W2rbjoObAjVSbrMz9t3srZvtMO77DW40xsw9dtduy+cNa3bwIRwDVPYORCGJquQFJEPmP9C7D15/NuhL6KpvxryU+PUfcCRJlKABAAA=" + } + }, + { + "ID": "707a32b273cd2d9b", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "260" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a0d7c2feb66843c50a055803c3fbfe89/11796956836282513475;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifSx7ImZpZWxkcyI6W3sibmFtZSI6Im5lc3RlZCIsInR5cGUiOiJCT09MRUFOIn1dLCJuYW1lIjoicmVjMiIsInR5cGUiOiJSRUNPUkQifV19fQo=" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:55 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:55 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAANWOQWoDMQxFryK0TgbblJlmDtB1od2FMii2mDHYVrGcdDHk7nXadQ9QxAfx+B/ejlyrVJz330dxPu8YJFMsOOOa5EIJD1iZVB4klhulGDrKrEord/Za5RYDB3jzG2eCIKxQpEGm5jd4p0tiCNfkuR0/pbbjNLo5UCPltjhjn83JusWO06nf6CZjzNJjh/ZY/t2wZoCXyClAZe8GaRtXiAo5qsayQixQ+Av0xwrvHwf0ErrwkzH/UP/+DXlpwPasAQAA" + } + }, + { + "ID": "db6492db20b86d6a", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "214" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "2e2969818db2644e041324eb17dab8a2/13361131250890649811;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifSx7Im5hbWUiOiJyZWMyIiwidHlwZSI6IlJFQ09SRCJ9XX19Cg==" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:55 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:55 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAJ3MMQrDMAyF4asIzRlC6eS1addC1tJBsUUisK1iJYVicvc69AbdHh+8vyKXogVd/Q1D96gYNJFkdDhHnShih4XJ9BDJb4oSGiU2o5mb3YRjgML+BGKwfl4M4/VyHweYthUWMsgK5hdOhPuzQ6+h3c59/3dk/wIWhYgwuAAAAA==" + } + }, + { + "ID": "e0a3e437a71e90c9", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ecb784db05490ead3dfc226efb6e2d9f/14925306769271761251;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:56 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "79db9630065768f3", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "267" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "2771091a97f39fbdea0e88c20d9ef55f/16561538777901048307;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTEifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:56 GMT" + ], + "Etag": [ + "Fkiw4Rw8iNcL3bC4SwfgVg==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2QUW+CMBDHv0v3Oi1FB0jiw1ycMWE+INvLspgKB3YCZbSOGeN334EYE6PRNE1zd//736+3I2uRR8QlS5H8bKDcPmi+TIE8EtA8wfzrWlR9v3LELPR6y5f+vIqTj2Q4RIWo+6JNGoLuFLLUHdsy3YhrrkAvTIM5xoCZC2bZAzyWaRuGscDLus2I6wrG0FxBGnsiX+OIldaFcimtqqqbSJmkwAuhuqHM6JGa/pq0KOU3hFrRMyTaIil6Bxtt2BS9B7HR+BBDCXkIxN2RFmF6YTGob8cfqrdRjhMa/W2ePe4sXEHGa5BYQBop4n7uSM4zZDs86Lgt6mge+NPZBHtO9U2mTvXpLBhPxj7Zf6EtlkZbDWhHDNKEnsyTAMrztC+rYxSWwLWQeSAad/bUs2xmsp7lsHoV8FeI8oLAcvA/dX/KlX6TkcCPRFc8WtTgeeSN6w4ZNoaYep+T/T/Q8fCf2QIAAA==" + } + }, + { + "ID": "e20a0f5740a7c573", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=3302bbd9266716e62f2ca1f1caf8e7b9c42bf1b3e39ef5880c2caa88e94b" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "658d8164c5fe89d539d4fb36100824df/18125713192492407427;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "LS0zMzAyYmJkOTI2NjcxNmU2MmYyY2ExZjFjYWY4ZTdiOWM0MmJmMWIzZTM5ZWY1ODgwYzJjYWE4OGU5NGINCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImNvbmZpZ3VyYXRpb24iOnsibGFiZWxzIjp7InRlc3QiOiJnbyJ9LCJsb2FkIjp7ImRlc3RpbmF0aW9uVGFibGUiOnsiZGF0YXNldElkIjoiZGF0YXNldF8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMDEiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIiLCJ0YWJsZUlkIjoidGFibGVfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDExIn0sIndyaXRlRGlzcG9zaXRpb24iOiJXUklURV9UUlVOQ0FURSJ9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoidVFFNHZSOWpHVkZYeVNEbVZvQzU5NEpPN0s0IiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg0KLS0zMzAyYmJkOTI2NjcxNmU2MmYyY2ExZjFjYWY4ZTdiOWM0MmJmMWIzZTM5ZWY1ODgwYzJjYWE4OGU5NGINCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOA0KDQphLDAKYiwxCmMsMgoNCi0tMzMwMmJiZDkyNjY3MTZlNjJmMmNhMWYxY2FmOGU3YjljNDJiZjFiM2UzOWVmNTg4MGMyY2FhODhlOTRiLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "899" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:58 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/fSUm5o2pn5uQcFzhaNQsSt0Ck1s\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoZp5QxKqstYQg0RLrQ3vE-qc-L5pVqXBzLuxyEYPENtz9QUcxL9eBVjtkjeYs904dC2ECSsTcoRf19QFjf3n7HxJ7V4UFnGDooH5JmHwlmbwUF1_o" + ] + }, + "Body": "eyJraW5kIjoiYmlncXVlcnkjam9iIiwiZXRhZyI6IlwiTGFaOG4wNEQ4S21HSWVVZFBsSU5MbWVhV0dzL2ZTVW01bzJwbjV1UWNGemhhTlFzU3QwQ2sxc1wiIiwiaWQiOiJkdWxjZXQtcG9ydC03NjI6VVMudVFFNHZSOWpHVkZYeVNEbVZvQzU5NEpPN0s0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9iaWdxdWVyeS92Mi9wcm9qZWN0cy9kdWxjZXQtcG9ydC03NjIvam9icy91UUU0dlI5akdWRlh5U0RtVm9DNTk0Sk83SzQ/bG9jYXRpb249VVMiLCJqb2JSZWZlcmVuY2UiOnsicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIiwiam9iSWQiOiJ1UUU0dlI5akdWRlh5U0RtVm9DNTk0Sk83SzQiLCJsb2NhdGlvbiI6IlVTIn0sImNvbmZpZ3VyYXRpb24iOnsiam9iVHlwZSI6IkxPQUQiLCJsb2FkIjp7InNjaGVtYSI6eyJmaWVsZHMiOlt7Im5hbWUiOiJuYW1lIiwidHlwZSI6IlNUUklORyJ9LHsibmFtZSI6Im51bXMiLCJ0eXBlIjoiSU5URUdFUiJ9XX0sImRlc3RpbmF0aW9uVGFibGUiOnsicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIiwiZGF0YXNldElkIjoiZGF0YXNldF8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMDEiLCJ0YWJsZUlkIjoidGFibGVfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDExIn0sIndyaXRlRGlzcG9zaXRpb24iOiJXUklURV9UUlVOQ0FURSJ9LCJsYWJlbHMiOnsidGVzdCI6ImdvIn19LCJzdGF0dXMiOnsic3RhdGUiOiJSVU5OSU5HIn0sInN0YXRpc3RpY3MiOnsiY3JlYXRpb25UaW1lIjoiMTUzNjcxMjEzODA1MiIsInN0YXJ0VGltZSI6IjE1MzY3MTIxMzg3NTcifSwidXNlcl9lbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0=" + } + }, + { + "ID": "8b4b4b0cf99ae1a3", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/uQE4vR9jGVFXySDmVoC594JO7K4?alt=json\u0026fields=status%2Cstatistics\u0026location=US\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b3838a6ab41969070dc92bd2807c9b67/11284773413691067995;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/uQE4vR9jGVFXySDmVoC594JO7K4?alt=json\u0026fields=status%2Cstatistics\u0026location=US\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:28:59 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/fSUm5o2pn5uQcFzhaNQsSt0Ck1s\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:28:59 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKtWKi5JLCktVrKqBrNSlayUgkL9/Dz93JVqdcBCmcUlmclgBclFqUBufl5IZi5InaGpsZm5oZGhsYWBqZESWHFRCYacuam5Um0tAKmOByxoAAAA" + } + }, + { + "ID": "95cabb0fab1b3ea4", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/uQE4vR9jGVFXySDmVoC594JO7K4?alt=json\u0026fields=status%2Cstatistics\u0026location=US\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b3838a6ab41969070dc92bd2807c9b67/12848948927777277931;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/uQE4vR9jGVFXySDmVoC594JO7K4?alt=json\u0026fields=status%2Cstatistics\u0026location=US\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:00 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/mL-MAr1ICYPeDbD61Glss3-7880\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:29:00 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAGWNQQ7CIBBF7zLrxpSS2srSqEtNGi9QgQUJhaYMMabh7jIYu9DdzHt/5q8QcMQYQKxl0iDgdLueIVVlNwGNLFYuOq/e3c1EIdbyfccaxvu6baCEF/xzXdtlp536NYeek5F+mq2mtwM9B8F2dQXWj4oqjZsjXozVgU5zfAPHF34gVfuIGQ/+SYRv4JvhhB6jGrT0iyJSQ0rpDdMEly76AAAA" + } + }, + { + "ID": "4d43a0678c53facd", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0011/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6f2375118cc6dc898cdb383a2f7425ec/4443832535378101043;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0011/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:00 GMT" + ], + "Etag": [ + "1h0iyrNMc2vhOyPHSj6xWA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8obZhhkVhb5+SYblWX4VwZ4BGeZVYQ72toCVZTklyTmBOWXFwOVGQP5RWBmdLVSGpgsAwonKtXqQFgGSrWxIDZCLgkuZ4ghlwyXMwLJxdYCAFZ+s/qwAAAA" + } + }, + { + "ID": "33a3770565301ef6", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0011?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e2e6cae78ddfc355cbc9370c2a73d469/14413123346680381306;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0011?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:00 GMT" + ], + "Etag": [ + "GdveL1jT26mycs0wyRgsMA==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:29:00 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKtWKk7OSM1NVLKqVkrLTM1JKVayiq5WykvMTVWyglA6SiWVBSBecEiQp5+7Uq0OQr40txgh7+kX4uruGqRUG1tbCwCcp8mLWAAAAA==" + } + }, + { + "ID": "d5329b9d3c177851", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0011?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "511777d8eb404f7585145c895bb66a93/16049355355292891146;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0011?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:00 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "ae0341210ab01f17", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "360" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "daab6dfa363738f7f0e658417fcb0721/17613529769901027482;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:01 GMT" + ], + "Etag": [ + "QavqD1QP6AFJCNgavG5Imw==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SW0/CQBCF/8v6Kmy3YpEmPHCpBINcan0yhiztUFbbbu0uVEL4705rCQYlks2mmZlz5nzZdEfeRRIQmyxE+LGGbHul+SICck1A8xD7M7756LPZ1OrcP/TGId8Mbodx3m6jQhS+YB35oGupzHStaZl2wDVXoOemwe6MFjPnzGq28Fhm0zCMOV5WLyPOK5iJyxVEy5FI3jFipXWqbErzPK+HUoYR8FSoui9jeqCmG5OmmXwDXyt6gkQrJEUvYKMlm6KXIJYaF5aQQeIDsXekQhj+8TCor+K/p/+jHBJK/f88e3wzfwUxL0CWAqJAEftlRxIeI9v3Bzdu06J68tzheICe43wdq+N8OPacgeNiI5ZB0XCdqdPxnP5PSwb+0eE6vYnbx/p39ELK6CjsTiYjpzMm+1c810Vud6sBDcQgZTmSSehBdtp2ZX6o/Ay4FjLxRLmf3d5YTWayBjMareLP/UxF9ofAusPHKvwRV/pRBgJRgzM7Kliv0x05hUP65UJsPT+R/ReahpC8NgMAAA==" + } + }, + { + "ID": "b8366d2c85a626fb", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "423" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0303782a59230136408aa38a2d0f994a/731242685254396202;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiSU5TRVJUIGRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxLnRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAxMiAobmFtZSwgbnVtcywgcmVjKVxuXHRcdFx0XHRcdFx0VkFMVUVTICgnYScsIFswXSwgU1RSVUNUXHUwMDNjQk9PTFx1MDAzZShUUlVFKSksXG5cdFx0XHRcdFx0XHRcdCAgICgnYicsIFsxXSwgU1RSVUNUXHUwMDNjQk9PTFx1MDAzZShGQUxTRSkpLFxuXHRcdFx0XHRcdFx0XHQgICAoJ2MnLCBbMl0sIFNUUlVDVFx1MDAzY0JPT0xcdTAwM2UoVFJVRSkpIiwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJ1U09CTWFpWmFpV0lUamFOOTJQYnhCVnJrTXUiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:01 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/SgAXiPn28CdKuhIYBvPhgQrX2Ig\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAIVT/W+iQBD9V8jeD20TKl9VxORypz2vIaVqBfp1XsyyjLgVWFwWe6bp/34L2txnazYkm5n35s2bHZ7RiuYx6qGIJusK+PbDI4uQikDgREZnyMMP3Vw/+9K9zC5cCONJ6o68DPDtRan5Sf+OTnKzex5fVkv3frCZLJNrfme6yQzJIrQuHFcpAXFaMC5O7Y7ZC/1W5Y8HV5g+YHrrBo945JiT6Mfghq+uKskqIV14NF9J7lKIouxp2tPTUythLEkBF7RsEZZpr/1qG1MrOHsEIkrtLy1Neim1d9Q+pYxgQVn+MfSlsoRPYQEccgKo94z2dd3/2Nihm8z7bl4VJFBqvKiIsHxBk4rvo891nWBbSEF0HQ6n95LTGKtT+wtyR/5wGigxFrgEMTd1o6s7hjk3OrYjT8e0dV2fy89oCRyl8DbCMJXjHGegKnmVlarCgZzM8pn4dW76Xjj0leMjfKQq3/TvquIH0/A8mFW6bpHBeOw1NziW0eHJifoneyYURXKjmmu8zf3a9/w3yaQmm4eE5ZxiKAXNm0EGte3Db7af4C57eJqS0cyzwR+cbP26BaeMU7F7tGA47Z8H7s1Q1qlK8CDBZOuvU9Rb4LSEF4kvBRZVWTde3+olmIajkTu6QPsklRZJAyAcdlZpVuOMttWxDdM4M0zbRg2Yi39ybcf6faEakQxysd+43WKhuhPZIJ9DhqlsD1mdjuU4lmWctU8joyt0g2XCwabtrIiVkISul+tV2o1YtKw+x7CBlBXAW4mssaEEMCGsykX9o6KXn5gsPJFjBAAA" + } + }, + { + "ID": "26793355b58efd6f", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/uSOBMaiZaiWITjaN92PbxBVrkMu?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ddebcc645497394186803b9d7130981a/2367474698178585018;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/uSOBMaiZaiWITjaN92PbxBVrkMu?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:03 GMT" + ], + "Etag": [ + "HLIWAcZeBa3NBKuTqkLjAQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/2VQTWvCQBD9L9NrhKLQ0oCHRIOGaqJrWqGlh81mYhM32bgftCL+907sIYWyh9mZ9958vAscq7YAH/LqcHKoz3cHtNv+w9A4aQ2FTrUGwQO0/EDM5SreB+INQz5JwmeXnY6rOthOp8Qw4hMbDv4FygplYcB/v0DLGyTZLXhgz12f7TIWJwu4egPuGjPgcZJFi4hRoVFFX2DRJgqyaP5XolEMChbNUjan/P/oXCk5EMM0XUVBAtcPeh7UKmdYosZWYL95p1WNwsa9KYWTAu2oU9qOHh/GcGPfELdLwzWv3ni1j7OaJ0/jTf4dvurj2hFLKsFtpVoivuxoY7DKchmeLZqNVgKNwb7J/W/DmWo6iZamW+3QA8HJxmVlwS+5NFQga+aNDMqS9sKCqS+6DiZw/QEGW6dmvQEAAA==" + } + }, + { + "ID": "222f07459416ac9b", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0012/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "27c9da546a3bddb573b235c21fbb629d/12336765505185897730;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0012/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:03 GMT" + ], + "Etag": [ + "etNHDCn8n87xAlTeRnoDUw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qnlvh5uDjnWeRZmFc45oSkBuXlu4SW29oCVZTklyTmBOWXFwOVGQP5RWBmdLVSGpgsAwonK9XqgFlQvpFSbSxUBFlZSVFpKkgGIokQT0TTbkCa9iQ07YbYtacl5hTD9MfWAgCwea51GgEAAA==" + } + }, + { + "ID": "7808d679d06da0dd", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0012?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "668cae3a234e273505e07d3eaa87d31e/3931367642088200778;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0012?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:03 GMT" + ], + "Etag": [ + "QavqD1QP6AFJCNgavG5Imw==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:29:03 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKtWKk7OSM1NVLKqVkrLTM1JKVayiq5WykvMTVWyglA6SiWVBSBecEiQp5+7Uq0OQr40txgh7+kX4uruGgQUyM1PAQkEuQa4Ooa4uiBrKUpNRugIcnX2D3IB8jGtTsrPz0EodPL393F19FOqjQXCWgCN1fK3tQAAAA==" + } + }, + { + "ID": "13b84e1f66d1b3f8", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0012?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "fec563fc37dd1cd0dab9b759819f3d11/5495543156191187674;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0012?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:03 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "b5cf520fb3efc6b1", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "321" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8f66c460b8ee22e8adacf9b8e4555649/7131775164803697514;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoiZCIsInR5cGUiOiJEQVRFIn0seyJuYW1lIjoidCIsInR5cGUiOiJUSU1FIn0seyJuYW1lIjoiZHQiLCJ0eXBlIjoiREFURVRJTUUifSx7Im5hbWUiOiJ0cyIsInR5cGUiOiJUSU1FU1RBTVAifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTMifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:03 GMT" + ], + "Etag": [ + "TUYiICgV8LQB6F4jSrKs6Q==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SUWvCMBSF/0v2Ok1TXVoLPujmQFZhah2MMSS21xptm66JcyL+9yWd3VCUSQk0955z7tdLd2jFswh5aMbjjzUU2xvFZgmgWwSKxboeTF55/z5+cf1hlz42l+PiSdJhu60V3PiidRKCquWiUDWH2l7EFJOgprZFXKtF7CmhTks/1HYsy5rqQ+rliMsK0tDhEpK5z7OVHrFQKpcexpvNph4LESfAci7roUhxRY0/bZwXYgmhkvgECR+QJL6CDZdsEl+DWGpGMIcCshCQt0MHhP6ZxWj9YfxP93+UakKp/59nr3cWLiBlBmTOIYkk8t52KGMpmIEmbpub14dO0NPy35b6awX9wVErUse2076Sx95x0Bk8o/27hsnWaXerQEMgC5VXX2RxAMVpeSQ21S0sgCkusoCX6eSuQR1ik2bDdan5Jb9yXpwRUFdvwfgTJtVARFx/fnQho4LtdP2ecYiwDNSlyRjtvwHWpjyKDwMAAA==" + } + }, + { + "ID": "f0f7d465b636be38", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0013/insertAll?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "164" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f0f9cfa8c759ac69e4a3aeb4cf86244f/8695949583706735610;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0013/insertAll?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJyb3dzIjpbeyJpbnNlcnRJZCI6Ilg2U2FTUmpGaVkwbzdoRzJKNE91Z2ptTUNVNSIsImpzb24iOnsiZCI6IjIwMTYtMDMtMjAiLCJkdCI6IjIwMTYtMDMtMjAgMTI6MzA6MDAuMDAwMDA2IiwidCI6IjEyOjMwOjAwLjAwMDAwNiIsInRzIjoiMjAxNi0wMy0yMFQxNTowNDowNVoifX1dfQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:04 GMT" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTMK04tKnHMyQlKLS7IB3KUagGmFzWCLgAAAA==" + } + }, + { + "ID": "9ff42eb7b0b8b0db", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0013/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ca7518c32c255a5dae84ca8d26cbf252/218777791981207362;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0013/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:04 GMT" + ], + "Etag": [ + "j7IGsmfhoDZoIgtfnyYL6g==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8pnmXu6F+emZeS7ROV7ppek5VVG+pil29oCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsAwobGRia6RoY6xoZKNXqQIQMjayMDawMDPQMQMAMLo5QGoJLiaGJqYWJhZmRiake0LxYIAQAOlLUUMcAAAA=" + } + }, + { + "ID": "d5efdf899711033d", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0013?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "00fa5212def8bffe447976d539323c9d/10260125097792945290;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0013?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:04 GMT" + ], + "Etag": [ + "TUYiICgV8LQB6F4jSrKs6Q==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:29:04 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKtWKk7OSM1NVLKqVkrLTM1JKVayiq5WykvMTVWyUkpR0lEqqSwAMV0cQ1yVanXgUiUIqRBPXxSplBJUbejyJcWoeoNDHH0DlGpja2sB5wvkN44AAAA=" + } + }, + { + "ID": "fca29bd6e243da90", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "332" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7a92ddbf02470c88e69b78f8254fa3ae/11824300611895931930;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiSU5TRVJUIGRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxLnRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAxMyAoZCwgdCwgZHQsIHRzKSBWQUxVRVMgKCcyMDE2LTAzLTIwJywgJzEyOjMwOjAwLjAwMDAwNicsICcyMDE2LTAzLTIwIDEyOjMwOjAwLjAwMDAwNicsICcyMDE2LTAzLTIwIDE1OjA0OjA1JykiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6InhhdkE1SzI4WGlnRmk0Z0RQaVREUmZ5YXFhbiIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:05 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/Xc8Q8Uf8Z6gSQ4WmQ18dvKrs3Tc\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAIVTfW+iMBj/KqT3h1uiUkAQSC535uYtRmOmwrZblphaHlknUKTFzSx+92vR5S73MiFNmj6/5/fSB97QhhUJCtGKpdsaqv2nZ75CbQSSpOr0EU3Ig1/g3pU/zq9HECc32Wg6yYHcXQvznvozP177D166mPXu8pnlJ7txJZyIPiJFwjRxUmcUZKfklez0PTuMF91Xshu4Y9u/Z+l31kuvblh0NV/vyZYUqktAtp6wYqN6n6QsRWiaLy8v3ZTzNANSMtGlPDff/Zo72ywr/gxUCvMPLVNlEeYHal8yTolkvPgcL5Sygs9hDRUUFFD4hk68o3/EOKKbysdp3hUUUGkc2ojyYs3SujqdvmmeaF8qQTSLh/MfqqcJpkunDRpNF8N5ZCREEgFyaWPLx4FlLy2vH6jXs/sY46VaVleSVQb/R1iOcZG0Ddk2ErWkuDRuB5N4uDAuWqrH62CnY+NW22hZdujgEOMu1o+nj34BjDNVN8S9ELutSxUmASFZ0aSNtLfzF3uKeayej6w6mtAN/mx8PYKyYrxi8niz0XA++BaNboeKpxYwgZTQ/WKboXBNMgEHhReSyFpo43qnJzWPp9PR9BqdikxFpA2AVnCMynKNs1zH61u21XOxG6AGXMm/ao7b/33qjUgOhTx9FsfpI+1EGayWkBOm7CHH85wgcBzF0FlZvsQWz2VA7H6woU5KU7Z92m4yf8VXT/XXBHaQ8RKqbqo4dowCoZTXhdR/Ezr8BGPeC9oIBAAA" + } + }, + { + "ID": "e9de9ed7b670bf72", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/xavA5K28XigFi4gDPiTDRfyaqan?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "eda4c223d001a3944f1697deab98bb66/13460531525325270186;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/xavA5K28XigFi4gDPiTDRfyaqan?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:06 GMT" + ], + "Etag": [ + "cW6cQKmLzYwj2aPiux/K8w==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/12QQU+DQBCF/8t4pVGJ1oakBxSNDTahFKPGeNguA25ddik72GLDf3eoiaaeZjLfe7NvZw8fyuQQwEqVmxab7qREWgxNiq7V5LjU1jgED5BEyUr5NJaLuHr4etmufZGodncaT7bTKSucfMdKQLCHQqHOHQSvezCiQrblzKmrhzYKs1vovV9EfyibzY9QTse2/5zcsXeZhfME+rfeg7VdpVhgg0biEKlu7BolzYbf5q2WSKPaNjS6GvtwUB/ITnyGl7E/eVblnbooo0RlUVp0YiMMq7SVgpQ1LHxccg4gS0Jfd4QuaaxE53BYcvaz8MZWtUbi16lp0QMp+D73iiAohHY8MG0VVTosCs6FeWq3fDE4h/4bymQX1pYBAAA=" + } + }, + { + "ID": "4f275723f70c5264", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0013/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3b0e3457437136700a5aeead16f2525c/4983359733582965234;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0013/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:06 GMT" + ], + "Etag": [ + "OiM28SzJ3EFOe/Ubxd7oXw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8r7Z/oaWQRXeRm7uvmn6ocmVaSY50eU29oCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsAwobGRia6RoY6xoZKNXqQIQMjayMDawMDPQMQMAMLo5QGoJLiaGJqYWJhZmRiake0LxYkDC9rIqtBQAqbzelMgEAAA==" + } + }, + { + "ID": "036e0e2575f59a27", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0013?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d51f80916d3eb78a8be3202c20aba162/15024707039411479866;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0013?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:06 GMT" + ], + "Etag": [ + "TUYiICgV8LQB6F4jSrKs6Q==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:29:06 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKtWKk7OSM1NVLKqVkrLTM1JKVayiq5WykvMTVWyUkpR0lEqqSwAMV0cQ1yVanXgUiUIqRBPXxSplBJUbejyJcWoeoNDHH0DlGpja2sB5wvkN44AAAA=" + } + }, + { + "ID": "abb8f12ee9fccf8d", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0013?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3eb3312f1698dfd8cd7f6591c93d3b64/16588882553514466762;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0013?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:07 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "b16e117c79273354", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "155" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6eef88edda2a594f405a60d4dc6ba33a/18225113462632126042;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIDEiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IkpwYThqUWxqOG12WENFY3k4WHFtSm85SjZxUSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:07 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/0x1KR_38HZJ4KfYMSUWHkYYYcO8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1S7W7aMBR9lcn725LvxEGatgqyNpSxNcBaqkrIca5TQxKH2IGhqu8+J6XS1E3V/lk+X/ce+wlteZWhIUp5vmuhOX7ciBSdIVAk17cPaErucWW6Y3xdXsawzH4U8WxaArm9lIb5y7pO1g6+up+412z1bb68vdquViv6HT8gbcI746wtKKjzWjTqPPDt4XI+mNQEb26KDS73d6OIHvHdrpyIcOLvbrRKQsGmvNpq7aNStRwaxuFwGORC5AWQmssBFaXxOq+xt426ERugShpvsgy9izTeSftcCEoUF9Wn5Vwna3oCDBqoKKDhEzr5xv9Y44XdI+9v85qgiTrj+QxRUTGet83p9qnzWRxrHYhullGy0pp+sQ46HdA8mkajxQdLYxlIxatevCBp8R9zZkQRCS/ommKGzdQMUwunzLQZMC9wKZieicEzXWB+hgPfJ1qnOvteRSpR+aFHaWBhyySZSz0vTc3AzpgPPrECPzQZs1MnsFm/YgNEwZjLWkh+Wn6URBeLaB1/Xc+iaByNdcCh4W9Zt0msSYtkORtptubUDRea1pUQzxZRcjFaxD87oJUwhZzQ43xXoCEjhYRnHS0VUa3sSulOXanaaxbPLtEJ5Lo+2hP6KbsaednxLM/xA8u23MAJXNSTG/UX5mLzzwfqQ0qo1OkFXx4KdZPoAZs1lITr8ZDj+04YOo7leue6emVaolQhsYNwS52c5nz3uNsWOBXpY/slgz0UooZmkGuPPadAKBVtpbqPj55/A9PErX+zAwAA" + } + }, + { + "ID": "dae7f636498431eb", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/Jpa8jQlj8mvXCEcy8XqmJo9J6qQ?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5501620abe4337498bf87f7e26853459/1342826382297173738;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/Jpa8jQlj8mvXCEcy8XqmJo9J6qQ?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:08 GMT" + ], + "Etag": [ + "7H3OEmML/JuN5Kr4J8QyRg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P206DQBCG32W8pbGeWiTphW2ILSIK2qSJMWa7DAjussvuoCGEd3epXs3pm3/+GeCranII4FiVbYemPyuR0inJ0HaCrAtaNRbBAyRWOnK5vXoK5WN8HnXJzYO5jvy0z8rVyhGWf6JkEAxQVChyC8HbAA2T6NaK+YcjqNdTsUtew/swcw2p8qmR7OP4bh2HML6PHtTqmGGBBhuOk5o2qkZOu8lo3gmONNPK0Gy5uIQTfZpEmvl1Kmpffh82Ie/9QysjdRst2tRRQnFGlWocuH8Bd4QUMZGpH+cSLuC/XveE9tkojtbiJDr/O7BRUgsk54ZMhx5w5l7dVgRBwYTF8Re6FWoeSAEAAA==" + } + }, + { + "ID": "c6688d7e8e5c4cc0", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon695cc71810ad4c55bb072df6e6a17690ff2b372f/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5501620abe4337498bf87f7e26853459/11384173683814009650;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon695cc71810ad4c55bb072df6e6a17690ff2b372f/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:08 GMT" + ], + "Etag": [ + "vL1Yeyg2XmdGPwLaQVKTGw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qX+RhGplamG0XkprgHlPskBoZ5h7iX29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwvXxgIhAHr9uHVuAAAA" + } + }, + { + "ID": "aad2db5c1b34c5ae", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "157" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a4576a80c97a278576adcba3a3f32d7e/12948349197916996546;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIDEuMyIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiWUZ4OXNlRHFONDNpVWlLZmFnNWZadnRkeEVRIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:09 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/BdXqqQPYb2qjDNjkgjZqjHqUf80\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1S7W6bMBR9lcn724ZvApGmrUtohxqhNoF1rSpFtrmmTgADNkmrqu8+Q1Np6qZq/5DP173n8ox2vM7RDBFetD10T5+3gqATBAoX+vUeLfFdUJvuIrisLmLI8qsyTpYV4JsLaXzPf7Xt9dUtsdvtItnuiu1du/3RZiww75E24YNx3pcU1GkjOnU69e1Ztp7cnj+GEhZt4jo845cMFx6726v8MbrWKgklW/J6p7UPSjVyZhiHw2FSCFGUgBsuJ1RUxtu8xt42mk5sgSppvMsy9C7S+CDtaykoVlzUX7K1Ttb0FTDooKaAZs/o6Bv/Y41X9oh8vM1bgibqjJcTREXNeNF3x9fnwSd9anQgus6i1a3WjIsN0PEDraNlNE8/WRNHozlIxetRnmJS/sekOVZYwiu6oYE+DzFDYgWEmTYD5k1dCqZnBuCZLjA/D6a+j7VODfajCteitqhHTcoCgi2WE0pcKwDH90xvSkLbwSbJdZrvsnHJDrCCBZeNkPy4/nwVnaXRJj7fJFG0iBY64NDx96ybVaxJ6SpL5pqtOU3HhaYNNcRJGq3O5mn8cwB6CUsoMH1atyWaMVxKeNHRUmHVy6GU4WuoVXslcXKBjiDX9dGRME451MirgWd5jj+1bMsNLd9EI7lTf2G26/55ojGkglodb/h6KjRMogfsNlBhrsdDju87Yeg4luud6uqVaYlKhdiehjvqFLTg7UO7KwMiyEP/LYc9lKKBblJojz2ngCkVfa2GXx+9/AbRxKFStQMAAA==" + } + }, + { + "ID": "d1cf6d499b15ce40", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/YFx9seDqN43iUiKfag5fZvtdxEQ?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "902aecaf55128cdbf885ebed3236cebb/14512523616803257426;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/YFx9seDqN43iUiKfag5fZvtdxEQ?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:10 GMT" + ], + "Etag": [ + "4QZN8Y7o6QLvlex4VrkGPw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P0U7CQBBF/2V8hQS1gjbhARTU2FRarQkYY5bttC5su2V3Cm2a/ru76NPMzZyZe6eDvShT8GEr8kONur3IkSLXxGhqScaWSpUGYQBILLekF23C2/VEjaPgKLHxPvT+cXWaTi1h+A8WDPwOMoEyNeB/dlCyAu1aNvq2BLWVE8vgdfZuZaFSJ8MkCGbzYAH9Vz+AndrGmKHGkqO7VWm1Q07PLmZaS440rJSm4WR8BWf6PFkvmzuDD4fQuxaJeMlYfpNtjpQ2i8hSUnFGQpUWTN7AmpAiJmN1shnhEv71vCU0K604GoPu6OjP4F4VlUSyaUjXOADO7KNPgsDPmDTY/wK+SWNXRgEAAA==" + } + }, + { + "ID": "76ec9bd623d5a554", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon1c5c0cf8ba1fdbcb418e365057b923a0bd76264f/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "902aecaf55128cdbf885ebed3236cebb/6107408319604029594;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon1c5c0cf8ba1fdbcb418e365057b923a0bd76264f/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:10 GMT" + ], + "Etag": [ + "O+IrsIPi+GBkoDyNJkYpeA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8r7a3sWFXsGZGq7O2Xnu1T6eWVHFqQ62toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwnrGSvVxgIhAL9uO7FwAAAA" + } + }, + { + "ID": "73761a49886ca9bd", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "175" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "666c2aa0a4c997db637e93c556291ce9/7671583838001917994;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIENBU1QoMS4zICBBUyBOVU1FUklDKSIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiblhjOElXVkh6aE9RandxTkFEcENOVlA1N044IiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:10 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/Ov4lG79qMalniwLpTpatgOKwQsc\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TbW+bMBj8K5H3ZZPW8A4m0rRFhGWoKW0T0m5TpciYB+IGMMFOUFf1v8/QVJq6qdo3y3fP3T1neEQ7VmdoglJW7A/QPry75yn6iECSQt3eoQX5iWvdnuHzah7BOrsqo3hRAbmdC+3yaJdzz99fkLJm3aJJGiKLy/PuWtA7pERYL5wdSgryrOGtPPNcc7JejevvFEe3N99+bS+v77t9PJ01QXxz5XgxVlMCynzB6p2a3UrZiImmdV03LjgvSiANE2PKK+0lr3Y0tabl90Cl0F55aWoXob3h9rnklEjG60/rlXJW9CXk0EJNAU0e0Uk3+scaz+wBeXubFwdFVB5PHxHldc6KQ3u6fex1kodGGaLrdbj8oWaGxXrodECrcBEGySiYrpL3xtgajaarUby+CJdR8EHxMxCS1YNgQtLyP7JnRBIBz+iG4hzrqe6nBk5z3cwhdzybgu7oGBzdhtzNsOe6RM3JXn6YIjWvSeoTkxiW5RgeTlMHu7mT67bn2j7NwTYh83VsYG9YuwUiYcZEwwU7FRIsw2kSbqKvmzgMZ+FMGXQte826XUaKlCzXcaDYitO0jCtaX0wUJ+FyGiTRTQ8cBCygIPRhtS/RJCelgCdlLSSRB9GX0p/6opVWHMVzdAKZqo8OhCFlXyOrep7hWK5nmIaju+7waUrSyr8wbHp/PtpgUkEtT6/6/HioT6ICthuoCFPxkOW6lu9blmE7Z6p6qRu8kqpQz99Rq6AF22/3uxKnPN0evmRwhJI30I4LpXFkFAil/FDL/mdAT78Bb3GZlscDAAA=" + } + }, + { + "ID": "860601969f9a7738", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/nXc8IWVHzhOQjwqNADpCNVP57N8?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ead7ed8c4e4c6a0872074969aafac64a/9235476781911534010;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/nXc8IWVHzhOQjwqNADpCNVP57N8?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:11 GMT" + ], + "Etag": [ + "nU8KFNc17AGWV+o+TJq/3g==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3U6DQBCF32W8bBtbjZaQ9IJitShii0JNjDHbZaDgsgvskKYlfXeX1qv5++bMmQ5+c5mADds8q1tsDlcZ0rpPQtStIG1CpaRGGAISywwpI+vlMeCTqfO0iQdq8PFcX99ms5khNN9hycDuIM1RJBrsrw4kK9GspeMfQ9Ch6osgel2EnmsapUouDd935v4CTt+nIRRqG2KKDUqOvVrVqAI5eb3RpBUcaVSphkbT+xs40+eJ/OSWt4mXx93butjXgfNQuUG8upsGlqGE4oxyJQ0YvYM5QoqYCNXeuIQJ/NfzA6FeNYqj1tiLji8HXFVWAsm4oabFIXBmXl3mBHbKhMbTH7cGOw9IAQAA" + } + }, + { + "ID": "7becf32dc467a0ad", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonab9a2a1335178bb586f5f047649cfe42ed908187/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ead7ed8c4e4c6a0872074969aafac64a/830361489007207682;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonab9a2a1335178bb586f5f047649cfe42ed908187/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:12 GMT" + ], + "Etag": [ + "MrZLiYvFhgqwHda83wj1bA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8r7FkX5ZEaWuWWkF5Z7pCRaGJdnGSY52toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwnrGSvVxgIhAG8tq7dwAAAA" + } + }, + { + "ID": "a818175f590134ce", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "168" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a3b7ca8149cd249726f520500b47480e/2394537003110194578;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIE5VTUVSSUMgJzAuMjUnIiwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJUSUFveWJteERJMk1hZHQzQUVpZ3B4dlVDd2ciLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:12 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/2SGmzA-fGi1ZnGVehqFHNG2K1JI\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TW2+bMBT+K5X30JcmgLlHmrYooRlrijYCrVZViow5EDeACZikadX/PkNTaeqmam+Wz3e+m+VntGVViiYoYfmug+b46YEn6AKBILm8vUdLcudUqjF3rsqFD3H6o/CDZQnkdtEqeLUon6ajbMG0u2pxA5vd5bdgga+07/49kiSsJ067goIY1bwRI9vCk3g1jvwpPybl49zH1yQV+tRjef24j2eHXG61UGRLVm3l7kaIup0oyuFwGOec5wWQmrVjykvlza+yx0rd8AegolXeaSkyS6t8oPal4JQIxqvP8UoqS3gIGTRQUUCTZ3Ti9f8R4xU9TD5O86YggVLj5QJRXmUs75rT7XPPEx1rKYh+xl74S+4MwfrR6YBW3tKbRWdBfO2F/uzsXB1j81wCU2gFqwamiCTFf5hOiSAtvE7X1MkcNVHdRHOSTMUZZKZtUFBN1QFTNSCzUse2LCL3RE8/bJFKBrBSmlJwTEdLtEyjtosTzU5pQrBuYNXAmusmkMKQtwEiYM7amrfs1MQs9KaRt/Yv14Hnzb25FDg07D3qNvQlKArjYCbRElM3jEtY34gfRF44nUX+TT/oWlhCTuhxtSvQJCNFCy9SuhVEdG1fSn/qG5ZcgR8s0GnIZH10AAwu+xpZ2eM0U7dsDWsmxrqLBnAj/prphv3naw0iJVTi9Jyvr4Z6J9Jgs4aSMGkP6Zalu66ua4Y5ktULVeOlcAm23S3Vc5qz3Wa3LZyEJ5vuawp7KHgNzTiXHHtGgVDKu0r0vwC9/AaPEhSIwAMAAA==" + } + }, + { + "ID": "08b1d29fb81ee7d5", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/TIAoybmxDI2Madt3AEigpxvUCwg?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7ab4f8a198ff5161ffe6d9fe711461e0/4030767912227853858;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/TIAoybmxDI2Madt3AEigpxvUCwg?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:13 GMT" + ], + "Etag": [ + "fukTfomfV92b4qy+sMKdyQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3U6DQBCF32W8lCYVjUaSXlAkkQjGYvHGGLMsA9IuDGUH2w3h3V1ar+bvmzNnRtjXbQEe5HV1GLA3VxXyZk5S1INibUNHrUZwAFlUliyH/bakpvx4dPO7g7nWyUthNquVJbT8wUaAN0JZoyo0eJ8jtKLBeW35bQk23Vy8ZkmYRoFtNFRcGnHsr+MQpq/JgR3lKZbYYytxVut62qHkaDZaDEoiLzrqefFw78KZPk+2kU8mb05PkZuIgm/9sK66028WHCtLKZKCa2otmL2DPcLEQqV0tC7hBv7rtWHUbz1J1Bpn0eXlQEBNp5CtG+4HdEAK++pzzeCVQmmc/gC5+wanSAEAAA==" + } + }, + { + "ID": "2b9f3bf5b05ebc4d", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonf6dcdce8581b1f1c792b17dcba2342042199bede/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7ab4f8a198ff5161ffe6d9fe711461e0/14000058723530068586;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonf6dcdce8581b1f1c792b17dcba2342042199bede/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:13 GMT" + ], + "Etag": [ + "t4Ml6hL3KkzeegmQY67JQA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qXmPjmmGX4GHtnV6WmpucGRpqZewU62toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwob6BmZKtXGAiEA09ScHHEAAAA=" + } + }, + { + "ID": "3ba06728201449bd", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "158" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "65a4ddbc099b316b6e440b4496898863/15636290732142578682;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIFRSVUUiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IlhEQndUYjBmWTF3eVJEMHlLYjZEY0R4VmZ3SyIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:14 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/VRxLkx_fu0-aL9GrobDRtHSBoxw\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1SbW+bMBj8K5P3tQnvBCJNWxtYhoqijZB2nSpFxjymbgATbEKiqv99hqbS1E3VPmH57rl77swT2rE6R3OUsWLfQXv6+MgzdIFA4kLd3qMY//Jq3Q6862oZwSb/XkaruAJ8uxTaTXKMd8ct7fQJjv1ly7Mgkd/WV/zY3yMlwgbhvCsJyEnDWzmZueZ8s57+DK76NNPpndGfkkA/XWduQILjDe2v1ZSAksas3qnZBykbMde0vu+nBedFCbhhYkp4pb3uqx1MrWn5IxAptDdemsoitHfcPpecYMl4/WmzVs6KngCFFmoCaP6EzrrRP2K8sEfk/TSvDoqoPJ4vEOE1ZUXXnm+fBp301ChD9GMTJndqZgw2QOcDWodxuEg/pMkmVHAOQrJ6nE9xVv7HqjmWWMALuiUe9fRM9zPDy6huUqDOzCagO7oHjm4DdXNv5rpYzclBfpzCNa8tw3Qt37HAyv0ccgv7YGSubYAzI7ZPPdtxaU7NbEzZApYQMNFwwc75F0l4mYbb6Ot2FYZBGCiDvmVvWbdJpEgq6mqh2IrTtIwr2tBDtErD5HKRRjcD0AmIocDktN6XaE5xKeBZWQuJZSeGUobT0KvSWkWrJTqDTNVHRsK45VAjqwae4VjuzDDVx/NtNJJb+Rfme86fbzSaVFDL8yO+vBUaNlELtluoMFPrIctV5fmWZdjORFUvdYNX0sfmzN8RqyAF2z/sd6WX8eyh+5LDAUreQDstlMaBEcCE8K6Ww7+Pnn8Doh8Um7YDAAA=" + } + }, + { + "ID": "104694419a26e211", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/XDBwTb0fY1wyRD0yKb6DcDxVfwK?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "c3fcb13520052b98bffb311ee38517de/17200466246245565322;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/XDBwTb0fY1wyRD0yKb6DcDxVfwK?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:14 GMT" + ], + "Etag": [ + "Qe3wM1qq1g6R7HFGHXzPww==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P206DQBCG32W8bRPQhCYkvShSxRR7QGtqjDHLMiB1YYEdsiLh3d2tXs3pm3/+GeGrrDPwIS2LtsduuCqQDjZJUPWClAmNrBXCDJBYYcgD3uhHt23dwksW0d19dPrZa71cGkLxT6wY+CPkJYpMgf82Qs0qNGu582EIGhpbBLtdvF5tTaOSmW1sj3G8CuI1TO/TDM4yTTDHDmuOVq3p5Bk5PVijWS840ryRHc0X3jVc6MvkFAb6OXXyV1cPSegMm9QLefj9kuuNoYTkjEpZG/D4BOYISWIikdq4BBf+62AgVPtOclQKrajzd+BWVo1AMm6o63EGnJlXo5LAz5lQOP0CPkBC5EgBAAA=" + } + }, + { + "ID": "32ea6f9108907068", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon31263953e3d9ded3a9e1b641e57c49f8456fdf2b/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "c3fcb13520052b98bffb311ee38517de/8723293359320088530;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon31263953e3d9ded3a9e1b641e57c49f8456fdf2b/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:15 GMT" + ], + "Etag": [ + "552b6oqAxoLcF+5TiUtrkw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qbmholmeUXOlbk+yS7aZuGZIaWFGWX29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwqXFJWmKtXGAiEAwd0BLnEAAAA=" + } + }, + { + "ID": "1765cf29035fd631", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "159" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "c2f1ade76aff4441736112d51e515b17/10359525367932598370;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUICdBQkMnIiwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJPU3dnVHg2NlNiQ1g1bk95RXZrcE9zMlg0V2wiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:15 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vgwn9dV1XfcP2ImCgXxbO8qWUvA\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1SXW+bMBT9K5P30Jc2fAUDkaYtI6xCi5IuIU02VYqMuaZuABNskkZV//sMTaWpm6pJPFg+555z7jFPaMerDI1QyvN9C83p44NI0SUCRXJ9e4em5JdfmcOJ/728jmGV3RTxbFoCWV9L45AfqyC7tTaM3thxGeabx3Tu79erw/gOaRHeCWdtQUFd1aJRVx62R6vlYL485skjxss03LjV/BQddvVc2pvhutBTEgo25dVOz94rVcuRYRyPx0EuRF4AqbkcUFEar3mNg23UjXgAqqTxxsvQu0jjHbfPhaBEcVF9Wi21s6YvgEEDFQU0ekJn3fgfa7ywe+T9bV4dNFF7PF8iKirG87Y53z51Osmp1oboxypa/NQz/WIddD6gZTSNwuTDxfhreKHxDKTiVS+QkLT4j6wZUUTCC7qlPvPN1AxSy0+ZaTNgrjekYLqmD645BIYz38OY6DnVyfdTpBKVmXrYyQijgf7AS60UDz2HAGO2RcHNbBb4zE2dfs0GiIIJl7WQ/FxAuIjGSbSNv21nUTSJJtrg2PC3rPUi1qRksZqFmq05dcOFpnVFxLMkWozDJL7tgFbCFHJCT8t9gUaMFBKetbVURLWyK6U7dcVqrVk8u0ZnkOv6aE/oU3Y18rLjWa6DPcu2XHeIMerJjfoLw5b15yP1JiVU6vyKL4+FuiQ6YLOFknAdDzkYO0HgONbQvdLVK9MSpQqI7QU76uQ05/v7/a7wU5Het18yOEAhamgGudY4cAqEUtFWqvv50fNvE5xygrcDAAA=" + } + }, + { + "ID": "a21e5c671b1106d1", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/OSwgTx66SbCX5nOyEvkpOs2X4Wl?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a046d9f5349e693223021995db5cff1c/11923700882035585266;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/OSwgTx66SbCX5nOyEvkpOs2X4Wl?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:16 GMT" + ], + "Etag": [ + "qA4bZjRWC1EQrAXHOpZoUg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PYWvCQAyG/0v2VUHFdVDwg4pModjZKopjjOs17VqvvfMunSvS/77U7VPykid539zhUtQp+JAU+bVB2z7lSLu+idA1ihwXo2uHMAAkkTN5nU+Tcxkdl+PVzs5P69Cc9SGfzZhw8gsrAf4dsgJV6sB/v0MtKuS1bPTJBLWmF/E+2mxfWVc67fX2EATzRbCC7qMbQKmTCDO0WEvsjxmrS5S06XOmjZJIQ6MtDV+8CTzoxySMb/n+x/PiZHl6rsN29X0xoZucpkfFlNJSUKFrBg8xsAlpEirSNw4JY/jXi5bQvVkt0Tnsj47+DJa6MgqJ05BtcABS8KfrgsDPhHLY/QK43loBRwEAAA==" + } + }, + { + "ID": "27098cd4d052675e", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon0b763dafc9fc9e7b1b6473aeff21ce5d2f98f5b3/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a046d9f5349e693223021995db5cff1c/3518585589131258938;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon0b763dafc9fc9e7b1b6473aeff21ce5d2f98f5b3/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:16 GMT" + ], + "Etag": [ + "fqEWaGU8v48YdTHoiH8TLQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qnFbqGJ7qHWpSZWESmhHjkZ3pYhPgE2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwo7Ojkr1cYCIQB6PW5IcAAAAA==" + } + }, + { + "ID": "b923115e0c61605f", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "174" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "18c4bcb11ba58140e774da4e9e40eeb0/5082760003722618314;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIENBU1QoJ2ZvbycgQVMgQllURVMpIiwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJNTHd2SGNOZFFiNWFZTEJqN0dhRTRsMzFFaEgiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:17 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/4CZlvR6hVnVdVv-7eiMuu_BOk4I\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TW2vbMBT+K0V76AZNfL8FxpYmXmrmeqvjpLQUgiwfO2psy7HkhFL63ye7KYwyyt6Ezne+m9Az2tE6QxOU0mLfQfv06ZGl6AKBwIW8fUAhvndr1Zy7P6tFAKvsdxlEYQX4dsEVc3ZfHmJ7u67X2fowcoBed93m8tfODB6QJKE9cdaVBMSoYa0YObY+WS3H1+HxcEWi7Ca18F14+egssG+WhuZvr+QWhzIPab2Tu1shGj5RlOPxOC4YK0rADeVjwirlza9y0JWmZY9ABFfeaSkyC1c+UPtWMoIFZfXX1VIqS3gMObRQE0CTZ3TiDf4R4xU9TD5O86YggVLj5QIRVue06NrT7XPPkzw1UhDdrPz4Tu4MwfrR6YCWfujPkrPZdJl8Ps8ZOz+bLs8u7xJ/+UXCM+CC1gNfgtPyP6xnWGAOr9MNcXNXTVUv1dw0V/UccssxCaiW6oKlmpDbmevYNpZ7oqcftnAtYxA30+Wu5aW2pYPqmKar5bqLnTxLsa6nDtFzD7QhdQtYwJzyhnF66mMW+9PE3wQ/NpHvz/25FDi29D3qNg4kKIlX0UyiJaZpKZOwvpcgSvx4OkuCdT/oOIRQYPK03JdokuOSw4uU5gKLjvel9Ke+Z8kVBdECnYZU1kcGwOCyr5FWPU6zDNvRdM2yPc9EA7gV72eOpmp/v9kgUkEtTo/6+naodyINthuoMJX2kGHbhucZhmZaI1m9UDVWCQ/rjrcjRkEKut/ud6WbsnTbfc/gACVroB0XkuNACWBCWFeL/i+glz+1cwPSxgMAAA==" + } + }, + { + "ID": "1648df3a4d571c3f", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/MLwvHcNdQb5aYLBj7GaE4l31EhH?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "c9f65ef2f3d271a626487406b00918f7/6646935522120506714;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/MLwvHcNdQb5aYLBj7GaE4l31EhH?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:18 GMT" + ], + "Etag": [ + "sW0uHXdcEwHWk6ctnIEKMA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3W6CQBCF32V6iwn2RxMSL6QhxRRNxRprmqZZlgHBZZfuDjWE8O7u2l7NnMw3c84McK5kDgFkVfnToe7vSqSta1I0nSBjS6ukQfAAiZWWNAe/iz9yHl3iw3nGSa6i1/VysbCE4SdsGAQDFBWK3EDwOYBkDdq1wv+2BPWtE+HxPdpZ2ajcyc0+SZZhEsH4NXpQqyzFAjVKju5Wq1WNnFYuZt4JjjRplabJfHYPN/o2WSeX35hv8m32xI5JWM9fWPQoHqbRKbaUUJxRpaQF9zuwJqSIiVRdbEaYwr8Oe0LzphVHY9Ad9f8MnlXTCiSbhnSHHnBmH40rgqBgwuB4BWP66BNGAQAA" + } + }, + { + "ID": "23f7d8cddf0b4561", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonfc8d2f8059b652e074481f28a7fdba22b7c2f9e1/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "c9f65ef2f3d271a626487406b00918f7/16688282823637342882;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonfc8d2f8059b652e074481f28a7fdba22b7c2f9e1/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:18 GMT" + ], + "Etag": [ + "nYE7y6mF77ps4xVNa1V22w==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8rnRbqaV5rlupmbFxSbVIT5JRqGGRmV29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwpH5VqWKdXGAiEAdmq4zXEAAAA=" + } + }, + { + "ID": "8833abb1f7e46cbd", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "185" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d0df1a11346e345dcfe2af952e7df911/18252457238245478962;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIFRJTUVTVEFNUCAnMjAxNi0wMy0yMCAxNTowNDowNSciLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IkJNeGdjMGg0Q1BPNDBiSTZreEpTZFR3SzAxUiIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:18 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/KbO03O0lHWtKrXK10oYk63lYgy4\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TW2+bMBT+K5X30JcmmJshSNPWJaxjSdOOkHWdKkXGHIgXggk2TaOq/32GptLUTdXeLH+3cz7Lj2jDqwwFKOXFroXm8O6XSNEZAkULfXuHZvSnX2Fn4k+3FxEss+syms+2QG8upDFNr7B9hcsvN2ra/JiaWNxuiF3eFgfnDmkT3hlnbclADWrRqIFHrGC5GH66fCgYXjvj6ysHpxHZPHxdZMl+is1YqySU+YxXG61dK1XLwDD2+/2wEKIogdZcDpnYGi/zGveWUTfiFzAljVdZht5FGm+kfSgFo4qL6v1yoZM1PYYcGqgYoOARHX2jf6zxzO6Rt7d5SdBEnfF0hpiocl60zfH2sfNJDrUORN+WYXyrNf1iHXQ8oEU4C8fJSRJdhovk/PL65NTCJhlge2DhE9MNsBNg91QrM5CKV711QtPyP7bIqKISntEV83Mfp3iUmn6aYyuH3PUcBtjFPrjYgZxkvkcI1TrV2fcqWokqy5hNRgCWa9McfMZcx8TYIcTLaebZOGXMTk2H9AU0QBVMuKyF5MdqxnF4noSr6PNqHoaTcKID9g1/zbqJI01K4uV8rNmaUzdcaFpXUTRPwvh8nETfO6CVMIOCssNiV6Igp6WEJx0tFVWt7ErpTl3l2msezS/QEeS6PtYT+im7Gvm245muTTzTMl3f8THqyY36CyOm8+fz9SFbqNTxfZ+fEXWT6AGbFWwp1+MhmxB7NLJt03EHunqFTbFVI2p5ow2zC1bw3Xq3Kf1UpOv2Ywb3UIoammGhPe45A8qYaCvVfQv09BuXdtLJ0QMAAA==" + } + }, + { + "ID": "2535491d9196c732", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/BMxgc0h4CPO40bI6kxJSdTwK01R?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8008292016163ecd363367f9c1df7807/1370170157893749698;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/BMxgc0h4CPO40bI6kxJSdTwK01R?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:19 GMT" + ], + "Etag": [ + "Q+zJSA8zCQc4LNFt+Jbqbw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P226CQBCG32V6qSbYGNuQeAHGplKwAnrVNM2yDIguLO4O8UB49+7aXs3pm3/+6eFUNTm4kFXluUN1eyqRYpskqDtB2oRWNhphDEisNGQ8ugep93pfxnwWbt5oFGTn7LJYGELzA9YM3B6KCkWuwf3qoWE1mrXC+TEE3Vpb7NbRKt150da0apnb1mYfhp4frmD4HsZwlFmCBSpsOFq9Vskjclpbq3knONKklYomL/NneNCPiR9dS+4cZsvt58zJ1vPTNUjz3eXDmSaGEpIzqmRjwH0K5ghJYiKRF+MTpvBf+zdCvVWSo9ZoRZ2/A0tZtwLJuCHV4Rg4M8++VwRuwYTG4Re8YAH+SgEAAA==" + } + }, + { + "ID": "c8edb0856f1ef8fc", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonddc369ee253afe8cc541004667fad730bcc3b146/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8008292016163ecd363367f9c1df7807/11411517459427362570;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonddc369ee253afe8cc541004667fad730bcc3b146/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:19 GMT" + ], + "Etag": [ + "u1BQpXI6/OxVGg5vsVa50g==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qXGjoFFkR4mun7V4S5p5uWFYclmhqk29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwmbmFqYWJgZmZjqGSjVxgIhAHnG1sF5AAAA" + } + }, + { + "ID": "b6abec527a0b972a", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "220" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "17f34934f552fdf1c438fe0a0ad32e0a/12975691878330466201;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIFtUSU1FU1RBTVAgJzIwMTYtMDMtMjAgMTU6MDQ6MDUnLCBUSU1FU1RBTVAgJzIwMTYtMDMtMjAgMTU6MDQ6MDUnXSIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoickp1QlhZdmhtalkyN29oQjFmZFhkRHgwNFBsIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:20 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/TrRoZUWtc9y1g58MJoUDjr8zA1A\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TXW+bMBT9K5H30JcmGAif0rSlCavY0qgjsH6sU2TMhTgBTMAky6r+9xmaSlM1dXuzfM49595z7Ue0ZWWCXBSzbNdCfXy34TE6RyBIJm8f0Jzc2yUez+wvxaUPUXKd+4t5AeTmslHCOuD30Y2gzlHNDPvqM49mm9r+NVEnD0iKsE44aXMKYljxWgwtU3Oj5aj+3F7c3u3XxeZOs/j6Qk2T22T2E4+vc1nVQJ7OWbmVtWshqsZVlMPhMMo4z3IgFWtGlBfKS7/KXlOqmm+AikZ55aXIWRrlDbcPOadEMF6+j5bSWdIDSKGGkgJyH9FJ1//LGM/sHnl7mhcHSZQeT+eI8jJlWVufbh87nfBYSUP0NfKCO1nTD9ZBpwNaenNvGg6+h/6VtwwnV9eDMw2r5hDrQw0PVMPFYxcbZ+eDfxB+SPEEGsHK3j0kcf4fgyZEkAae0RW1UxvH2IlVO06xlkJqWGMK2MA2GHgMqZnYlmkSWSc6+b6KlLykjuEQh5iObpCxaekJTXRHjW0SY9PR0kSNgeopjfuMaiACZqypeMNO6U0DbxJ6K//TauF5M28mDQ41e826CXxJCoNoMZVsyalqxiWtS9FfhF4wmYb+tw5oG5hDRuhxucuRm5K8gSdp3Qgi2qYLpTt1W5FaC39xiU4gk/HRntB32cXIio6nGrppqZpqOI5qo55ci1eYieVW/txwb1JAKU5P4HnTqOtENlivoCBMtod009QdR9fVsTGU0Qus8kI4RLOcLdUzmrHderfN7ZjH6/ZjAnvIeQX1KJMae0aBUMrbUnQ/Bz39BoLflln0AwAA" + } + }, + { + "ID": "c911642dd7a3b876", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/rJuBXYvhmjY27ohB1fdXdDx04Pl?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6084066224ceb4391c8303cc6e01dce1/14611923886942976041;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/rJuBXYvhmjY27ohB1fdXdDx04Pl?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:21 GMT" + ], + "Etag": [ + "Fdrkzrj8y9x4R3+waFIW8Q==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3U7CQBCF32W8FJKCRLAJFyAl1oSklBohxphld0pbtt26OxVKw7u7i17N3zdnznRwzCsBPuzzw3eDur07IK1dEqNpJBkbalUZhB4gsYMll0IfL7qYtE/nUfxwf2LL8H2ynk4tYXiGJQO/gzRHKQz4Hx1UrES7lnpflqC2dkUSroJNMltFtlUq4VpxEAWzJFjA9fPag0LtY0xRY8XR6dVaFcgpdFZFIzlSv1aa+uPHIdzo20S/NvPt7icri91wrLL5IBVbsTh7o0haSirOKFeVBd82YI+QIiZjdbI+YQD/9bwlNJFWHI1BJ+r9HXhWZS2RrBvSDfaAM/vsS07gp0wavP4CcTOjWEoBAAA=" + } + }, + { + "ID": "e831c73aa91ebc8f", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonc959a9a6935a4673dcd391b8ab0692fd1bec3fcb/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6084066224ceb4391c8303cc6e01dce1/6134470628830606449;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonc959a9a6935a4673dcd391b8ab0692fd1bec3fcb/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:21 GMT" + ], + "Etag": [ + "HD6g9rBjDHPikenVQxdQRA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8p7uJilWxY5Zbl4BGRmp+aFBVakBAY52toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsg5FKhiamFiYWZkYmpnoGSrU62ARjwRAA/Xuo9ZYAAAA=" + } + }, + { + "ID": "71e5e27c8479ab36", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "196" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "1d159f150ac1d17b4b5082db132102b9/7770702637459893249;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUICgnaGVsbG8nLCBUSU1FU1RBTVAgJzIwMTYtMDMtMjAgMTU6MDQ6MDUnKSIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiOGlNdktoMEY0Q211UHRvOE5aR3NGSWNnMTFTIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:22 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/R5ku3gJcB_7ZnGrzQAMgVGVQMDs\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1T72vbMBD9V4L2IRs0sfwzdmBsWeIGr0loHadlpRBk+eyosS3HkhO60v99spvCKKPsm7j37r27d+gZ7VmZoDGKWXZooH769MhjdIFAkkxVH9CC3LsltmbuVTEPYJNc58FqUQC5mwsttPeNmf2kP7aj+3Je/76ZLLPb+e3NciYekBJhrXDS5BTkoOK1HIwcY7xZD122PF7t8KU1LZpryd3V/VxcBjTT9bXqEpCnC1buVe9OykqMNe10Og0zzrMcSMXEkPJCe5tXOxpaVfNHoFJo77w0tYvQPnD7lnNKJOPl103rrOghpFBDSQGNn9FZN/jHGq/sDvl4mzcHRVQeLxeI8jJlWVOfq8+tTvRUKUN0s/HDX6qnW6yFzg+09hf+NOp97u8gz3n/ohcFS38dTZbXvb6BdWeAzYGBe7o9xtYY2/0vSiQBIVnZuUQkzv9joYRIIuAV3VI3dXGMvVh34xQbKaT2yKKAbeyCjS1IncQdOQ5RfbKV77pIycs49uIkpZ5jxxZx0jRNLGo6KbHdGDse1l2KbXuEcZdFDUTCjImKC3ZOaRr6k8jfBpfble/P/JkyONXsPesuDBQpCjerqWIrTlUzrmhtWsEq8sPJNApuW6ARsICM0Kf1IUfjlOQCXpS1kEQ2og2lfbXpK61VsJqjM8hUfLQjdFO2MbKi5em26Yx0Q3d0T/dQR67le8zA2Pn7kp1JAaU8n/r1oqidRA1Yb6EgTI2HTMcxPc80dcseqOgl1nkhPWKMvD01M5qxw+6wz92Yx7vmewJHyHkF9TBTGkdGgVDKm1K2PwS9/AFhOZ/U3AMAAA==" + } + }, + { + "ID": "f4dc7ddb6379c5c3", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/8iMvKh0F4CmuPto8NZGsFIcg11S?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f6466a455eba826def642b64fcd237ca/9334877052051252625;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/8iMvKh0F4CmuPto8NZGsFIcg11S?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:22 GMT" + ], + "Etag": [ + "Do+6uGiJjnHeaPbk7RdUWQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/22QXWvCMBSG/0t2uQo6hkrBC7/tpq6mymBjSExPazRtuuZ0Q4r/fSfuQtgkF8l78j7nq2ZHlcfMZzuVflZQnu5SwJV7cLCVRktXYXILzGOAIiXnyNy3q6l6OuQzEOHu2OHx5nXV65HDyj1kgvk1SxTo2DL/vWa5yICwpLklB54KJ/h4+MJHpDMTO73czOf9wXxMkf/k9hLatq54tObBcnoDP3t/qYcrtQ4W42jdX4S3wA86HjuYHYcESsgluDGK0hxAYuA2FFdaAjYKU2Kj03Z5yX356arF1/O+OXkcZlWIprt8m9pJINNWKyKXNlKgMjkZNxF1yNCg0Nx805DsMpTTgxOCDUsjwVpwSZu/BYYmKzQgdYNlBR6TgnY8U8j8RGgL5x/yQ3VwwQEAAA==" + } + }, + { + "ID": "fce1a01b7a7f1001", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonbb9bdfc965b4a6fffd4c36fa58b069018c055700/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f6466a455eba826def642b64fcd237ca/929761759146926553;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonbb9bdfc965b4a6fffd4c36fa58b069018c055700/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:23 GMT" + ], + "Etag": [ + "FumO7MDkim7vI1Dh//66UQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8q7leb6m/u6ZGfmmpd5Grpk6OubmYUG2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsU7JCYiplpObk5CvV6kB4hiamFiYWZkYmpnoGSrWxtUAUWwsAq13hvZUAAAA=" + } + }, + { + "ID": "1774013bb8f8b29c", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "195" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "dacf7514a516f4e17f889f1d64474be1/2493937273233136233;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIERBVEVUSU1FKFRJTUVTVEFNUCAnMjAxNi0wMy0yMCAxNTowNDowNScpIiwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJwQVpqcXZZdkg2WjVDS1VMQ29pNFhrUVlJREoiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:23 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/52sYHp8nOgfxH7DVS-mrPEhnTU4\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TbWvbMBj8K0X70A2aWH5/gbGFxGu9plmbOO1SCkGWHztqbMuxlGQl9L9PdlMY3Sj7YoTunrvnTviA1qxKUYASlm+20Dx9eOQJOkMgSa5uH9CY3HsVtkbeZXkewTy9LqLJuARydy402xCLi9qrfuTZrwt3dDvrlc11uKriufWAlAhrhdNtQUH2at7InusYwXzWrwf3j5vdYnfh3NvDy/l4yJn1c32ziEbf1ZSAIhuzaq1mV1LWItC0/X7fzznPCyA1E33KS+11X21naHXDH4FKob3x0lQWob3j9qXglEjGq8/zmXJW9Clk0EBFAQUHdNSN/hHjhd0h76d5dVBE5fF8hiivMpZvm+PtodWJn2pliG7m4XShZrpgLXQ8oFk4DofxyWgQh3F0FX5sP7N4cHV9cmpg3elhs2fgE90OsBVg+/ST0khBSFZ1JjFJiv/IkxJJBLygS+plHk6wn+hekmEjg8x2LQrYxh7Y2ILMST3XcYiak618N0UqXmHXV3JelrquR13dpYZjYMN3Ml3HTkqszMa+T32vq6IBImHERM0FO5Y0nIYq5TL6tpyE4SgcKYN9w96y7qaRIsXT+WSo2IpTN4wrWltWNInD6WAYR7ctsBUwhpzQp9mmQEFGCgHPylpIIreiLaU9teUrrUk0OUdHkKn6aEfotmxrZGXL023TcXVDd0zD91FHbuRfmIXNPx+yMymhkseXfnlQ1G6iFmyWUBKm1kOm45i+b5q6ZfdU9RLrvJQ+MVx/Tc2c5myz2qwLL+HJavs1hR0UvIamnyuNHaNAKOXbSrY/CHr+DYwYjRLbAwAA" + } + }, + { + "ID": "a4a3fca302b6e852", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/pAZjqvYvH6Z5CKULCoi4XkQYIDJ?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e3dbe80a51447df17fb0065654860a0c/4058111687841272569;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/pAZjqvYvH6Z5CKULCoi4XkQYIDJ?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:24 GMT" + ], + "Etag": [ + "oQnzkKhHYyIyFvBaIWT/bg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3U6DQBCF32W8pbEarQlJLwqtKRaNVIhSY8x2GShlYSg7YGjTd3epXs3fN2fOnKDIqwRs2ObZocWmv8qQgyFZo24VaxNqqjSCBcgiMyQF1bFY7ZZx7/WPnSO89/B6m02nhtByh6UA+wRpjirRYH+eoBIlmrV0/G0I7uuhmM/CReg9L0ynpGTovES+P3P8BZy/zhbsabvGFBusJA5ydUN7lOwNTpNWSeRRTQ2PHia3cKEvk3q22R+6uFtONvfuKvJdyu8+iiD25k+GUiQF51QZMHoDc4SJhVrTj7EJN/BfOz2jfm1IotY4iI7/DrhU1grZuOGmRQukML8ucwY7FUrj+RfwO8LjSQEAAA==" + } + }, + { + "ID": "672620ec98944305", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon0797628fd778c717c2620296f1106da4f5099c98/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e3dbe80a51447df17fb0065654860a0c/14099458993669787201;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon0797628fd778c717c2620296f1106da4f5099c98/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:24 GMT" + ], + "Etag": [ + "yDZCcCzsUejLJltuXDJ7jg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8pXukQ5JztXFYemZvl45ZSURrh4mWel29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwobGRia6RoY6xoZhBiaWhmYWBmYKtXGAiEACCGHYIAAAAA=" + } + }, + { + "ID": "3dd7358bfe7a089f", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "191" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ac3e0a647398b3c7e04bd657238b9a2a/15663634507755997137;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIERBVEUoVElNRVNUQU1QICcyMDE2LTAzLTIwIDE1OjA0OjA1JykiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IkRPZE50aXlkZ1RCWFRiYXdUWFBLaWdZOG9YMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:24 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/4KelZggzatkydGmtVodmPrhwtOY\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2vbMBT9K0X70A2WWH47hrF1iRdMUzdLnL4oBFm+dtTYlmPJDVnpf5/spjC6UfZN6J7HPUfoCW1ZlSIfJSzftdAcPjzwBH1GIEmubu/RjNx5FbYm3nk5DWGVzoswmpVArqdCs86huMvzX0RuD+m0lFc8LefNZi8vb++REmGdcNoWFOSg5o0cuI7hr5bDyWUaSXZI8/j7TZyQfXwzP2f5rcdvdMUSUGQzVm0VdyNlLXxN2+/3w5zzvABSMzGkvNRe99UeDa1u+ANQKbQ3XprKIrR33L4WnBLJePVltVTOCr6ADBqoKCD/CR11w3/EeEH3k/fTvDoooPJ4/oworzKWt83x9qnTiQ+1MkQ/V8HiVnH6YN3oeEDLYBaM45PJWRx8jMOLYBmfXcxPTg2sOwNsDgx8ots+tnxsn35S/BSEZFVvEJOk+I8sKZFEwMt0Tb3MwwkeJbqXZNjIILNdiwK2sQc2tiBzUs91HKJ4spPvWaTilWsmaephcMAwLVvPMtcmNMM60DQzM4vqnktte2T3NTRAJEyYqLlgx4LGi0AlXIc/1lEQTIKJMtg37C3qehEqULxYRWOFVpi6YVzBuqLCKA4WZ+M4vOoGrYAZ5IQelrsC+RkpBDwrayGJbEVXSnfqildaURhN0XHIVH20B/RbdjWyssPptum4uqE7lmti1IMb+dfM0+0/H7E3KaGSx1d+eUzUbaIWbNZQEqbWQ6bjmKORaeqWPVDVS6zzUo6I4Y621Mxpznab3bbwEp5s2m8pPELBa2iGudJ4ZBQIpbytZPc50PNvS0hAGNcDAAA=" + } + }, + { + "ID": "92030f4922f2776a", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/DOdNtiydgTBXTbawTXPKigY8oX1?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "74245fe59941313d537360cc60233020/17227810021858983777;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/DOdNtiydgTBXTbawTXPKigY8oX1?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:25 GMT" + ], + "Etag": [ + "Tmb1iMawpP/2WTSMoCY8/g==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/yWP3W7CMAyF38W7LeLnYkOVuKCAtGnAGBQBmqYpTd0sLK27xBWqqr77EnZlH/mzz3EHP7rKIYZMq98GbfugkN9Ds0fXGHa+1FQ5hAiQhfJkWmZjvRG3ejecnNLDhhaX6VDNZp5w8htLAXEHhUaTO4g/OqhEiX6tGH15gts6iOU8XXlVUh7U9rhez5P1CvrPPoIrZXss0GIlMZyqLV1R8ktImTdGIg9qsjx4epzAnb5Plm/5lnWbqzQ5p5m4pefdq1aXKZ3HnjIkBWuqPHg8gDdhYmH2dPMRIQB3nbSMbmdJonMYjo7+DRZU1gbZp2HbYARS+D+fNUNcCOOw/wP3HlazRQEAAA==" + } + }, + { + "ID": "a0245a0ceabbe769", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon73bdd80e6e23451ff75acf01ecdf3f4c187c5595/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "74245fe59941313d537360cc60233020/8822693629443030185;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon73bdd80e6e23451ff75acf01ecdf3f4c187c5595/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:25 GMT" + ], + "Etag": [ + "cEsYb3zCh8KmrIB7RByDrA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8onuxZHJhlXOWdYeOcWeTqZBzlVuhQ52toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwobGRia6RoY6xoZKNXGAiEAHsOJ53cAAAA=" + } + }, + { + "ID": "63d5ff5b0efb19d5", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "191" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6bd3d8525216545aafec0a3f630343bc/10386869143546016825;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIFRJTUUoVElNRVNUQU1QICcyMDE2LTAzLTIwIDE1OjA0OjA1JykiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IkZLZFRnaEFNQ0xOUjIwNTZvS1ZkcEJwWm5NaSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:26 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/RcjhOHEPMe-PoX9ZR0NKJbeDMXc\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2+bMBT9K5X3oZvUBPN+SNOWJbRlSVhGSNtVlSJjLsQNYAJOo6rqf5+hqTR1U7UvyPI9j3uOxRPasipFHkpYvttD8/jhnifoDIEguby9QzNy61TYmDjT8iKAVboognBWArm+aJWI3m9+XPqLOQwW/Ma9jXA4/Z7AZH5D75AUYZ1wui8oiEHNGzGwLc1bLYfn0zTON6P5eBZGGjYtPr1K62/1bTVnktVCkc1YtZXcjRB16ynK4XAY5pznBZCatUPKS+V1X+VBU+qG3wMVrfLGS5FZWuUdty8Fp0QwXn1eLaWzhEeQQQMVBeQ9oaNu8I8YL+h+8n6aVwcJlB7PZ4jyKmP5vjnePnU68WMtDdHPlR/9kpw+WDc6HtDSn/nj+CQO5v7H7rOMR/PFyamGVWuA9YGGT1TTw4aHzdNPkp9CK1jVG8QkKf4jS0oEaeFluqZO5uAEu4nqJBnWMshM26CATeyAiQ3IrNSxLYtInujkexapeJW4qosz17FU1UhSRwXbgNRKU4x16maqbjta6hrE6WtogAiYsLbmLTsWNI78Ueyvg/N16PsTfyINDg17i7qOAgmKo1U4lmiJqRvGJawrKghjPxqN4+CqG+xbmEFO6ONyVyAvI0ULz9K6FUTs266U7tQVL7XCILxAxyGT9dEe0G/Z1cjKDqeaumWrmmrJhCbqwY34a6Zp+p+P2JuUUInjK788Juo2kQs2aygJk+sh3bJ019V11TAHsnqBVV4Kl2i2u6V6TnO22+y2hZPwZLP/msIDFLyGZphLjQdGgVDK95Xofg70/BtSs5N+1wMAAA==" + } + }, + { + "ID": "356bed4140448400", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/FKdTghAMCLNR2056oKVdpBpZnMi?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9df1f595ba9942afe4a94c64692cdd6b/12023101156470205641;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/FKdTghAMCLNR2056oKVdpBpZnMi?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:27 GMT" + ], + "Etag": [ + "sqHG+eAsEsHnDupotBWHeA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PYU+DQAyG/0v9KEtwiTMh2QeYKMtgUdw00RhzOwpjHtcbV2II4b97TD+1b/q079sBvmtdQACHujp32PZXFfLz1ORoO8XWFUPaIniALCpH2nPyeI2hjW2i7ztDHL0lGC6XjrDyiI2AYICyRlVYCD4G0KJBt1b6X47g3kxit85ipxoqJrXdp2kYpTGMn6MHJzrkWGKLWuJ0yrR0QsnrKWXRKYk8M9Ty7G4xhwt9mTxsil11DLNVus3n/u2CNq+Ficy7zmpHKZKCa9IO3L+AM2FioXL6cRHhBv511DPap5YkWovTUf/PYEWNUcguDbcdeiCF+zOpGYJSKIvjL3JR1yFFAQAA" + } + }, + { + "ID": "ccab138e8dc7adaf", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonb9190f986114bd81e74ed6dd003c9f13782d94a8/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9df1f595ba9942afe4a94c64692cdd6b/3545929364727900433;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonb9190f986114bd81e74ed6dd003c9f13782d94a8/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:27 GMT" + ], + "Etag": [ + "IG+yD3eyq89gtd2Zj1CvpQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8p7umtXuhinVhZaWKaXpBhFZRk6lxUE2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwmbWhmYWBmYKtXGAiEAqlDm8HUAAAA=" + } + }, + { + "ID": "69a1101b793969e5", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "160" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d6bea9615b04652db521356d388c62f4/5182160273862336929;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUICgxLCAyKSIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoicHFCNDFnTlJKSTg0bEdaOFVtbmJ3Y1oxblN0IiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:27 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/6W7V5jtL3hm5fIXVMajkJQ2Glnk\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1SW2vbMBT+K0V72aCN77fA2LrEC+4yszpOu5VCkOVjR4ktOZacEEL/+2Q3hdGNsjeh853vJp3QlrIcjVFGy10H7fHdhmfoEoHEpbp9RHP84DPdnvrf6lkEy/xHFcXzGvD9TGjuvXfnbOTcWtdOEf28+44325tbc1ax7SNSJLQnzruKgLxqeCuvPNccLxejZvfFNso4uYl8u5o9+MuaZQfyYLCFVFsCqmJO2VbtrqVsxFjTDofDqOS8rAA3VIwIr7UXv9re1JqWb4BIob3S0lQWob2h9qniBEvK2cflQikreAIFtMAIoPEJnXmjf8R4Rg+Tt9O8KCig0ni6RISzgpZde7499TzpsVGC6HYZJr/UzhCsH50PaBHOw0l68d64vDA/KEAOQlI2MKQ4q/7DbI4lFvA8XRG/8PVMDzLDzwrdLKBwPJuA7ug+OLoNhZv7nutitSd7+mELM84Ml1imHTie7nqG5bi6aVu6XQS262DTB2I6XqZnBRlytoAlTKlouKDnBiZJeJ2Gq+jrKg7DaThVAoeWvkbdJ5ECpckynii0wjQt5QrWNxHFaZhcT9Lorh90AuZQYnJc7Co0LnAl4ElJC4llJ/pS+lPfrOKKo3iGzkOq6iMDYHDZ10jrHmc4lkpmGq5n2wYawK38a+YY7p+vNIjUwOT5GZ9fC/VOlMF2BTWmyh6yXNcKAssybOdKVS91g9cywKYXbIlVkpLu1rtt5Wc8W3efc9hDxRtoR6Xi2FMCmBDeMdn/fvT0GwJIXSy4AwAA" + } + }, + { + "ID": "e879fa6883e61968", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/pqB41gNRJI84lGZ8UmnbwcZ1nSt?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7486c1f7583975f8908e77196817e23e/6746335792243448369;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/pqB41gNRJI84lGZ8UmnbwcZ1nSt?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:28 GMT" + ], + "Etag": [ + "aMD8jZW+BM/GIPo52M3RiQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/42QTU/CQBCG/8t4tERAVNKEg4UGawBhkZjUGLJsp7W47ZbuNIQQ/ruzeDBRD2YPu+/s+8zXET7yMgEfNnm2a7A+XGRIC/cQaBtNlq/KlBbBAySZsVNOR/1t/HIZTK/G0dzcdKfXIl8MBuyw6h0LCf4R0hx1YsF/PUIpC2Qsba/ZQYfKCREOn8SIdWESp2eryeQ+mIQc+U2uz6F15xuPZs/hOBR/8CfvJ9b9F/bGx4Ot2QhMscZSoZuiqs0WFUVuQUmjFVKrMjW17m5dVnaff6pd0OtkM/EY9Xt6HPdXRbnZq7hTLold2ihJuSnZuFpyf0CGpBZmzzPCeSangwOhnddGobXokra/CgxNUWkk7obqBj1Qklf8kBP4qdQWT5+v+frywAEAAA==" + } + }, + { + "ID": "3f115d78b302ef32", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon16c3249570671356024304f9465a28ec257b0bfc/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7486c1f7583975f8908e77196817e23e/16787683093777061497;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon16c3249570671356024304f9465a28ec257b0bfc/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:28 GMT" + ], + "Etag": [ + "9dZuS5v/PqexuQBv6rq26Q==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8pbpkSVBpuW6QcUplaUBjqVmRUVGpkF2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsU7JCYgJV1OpAWEZKtbG1QBRbCwC2n9FhhgAAAA==" + } + }, + { + "ID": "6721bf9c453e077e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "163" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6d78e007a5948d554fd165bedc563cf8/18351857512680099337;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIFsxLCAyLCAzXSIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiU2VIdENST0x5MzFHeGIxME83bVJxVVR4UXRyIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:28 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/DGjCdJ5utBcgn-7leaZM-ZsADKI\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TbW+bMBj8K5X3NQmYdyJNW5ewjDVNV0JWresUGfNA3QAm2DSNqvz3GZJKUzdV+4Tlu+funrN4RhtWpWiMEpZvW2j27x54ggYIJMnV7R2ak1uv0q2pd1HOQlil34pwMS+B3MyENp09TNKvdis/0bwaugWQ28vhrTifXoR3SImwTjhtCwpyWPNGDl3HGK+WoyV8kZPoar438ewpwfqVW0bbVfx0LRs1JaDI5qzaqNl7KWsx1rTdbjfKOc+VQ83EiPJSe8mrPRpa3fAHoFJor7w0tYvQ3nD7UHBKJOPV+9VSOSt6BBk0UFFA42d00g3/scaR3SNvb/PioIjK4zBAlFcZy9vmdPvc6cT7Whmi61UQ/VAz/WIddDqgZTAPJvHZTzw4MwZn5i/FSUFIVvUiMUmK/8ibEkkEHNE19TJPT3Q/wV6S6UYGme1aFHRb98DWLcic1HMdh6g52cn3U6TilW85iYPtxDNwglMTfCcz1de1iOWAbjk6tr3EpG6/agNEwpSJmgt2KmESBedxsA4/rxdBMA2mymDXsNesmyhUpDhaLSaKrTh1w7iidWWEiziIzidx+L0DWgFzyAndL7cFGmekEHBQ1kIS2YqulO7Ulau0FuFihk4gU/XRntCn7GpkZcfDtum42MCO52EL9eRG/oX52PjzoXqTEip5esnjg6EuiQrYrKEkTMVDpuOYvm+a2LKHqnqpY15Knxiuv6FmTnO2vd9uCi/hyX37MYVHKHgNzShXGo+MAqGUt5XsfgB0+A3xnKgfuwMAAA==" + } + }, + { + "ID": "6f4a000522438808", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/SeHtCROLy31Gxb10O7mRqUTxQtr?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "abaebc5fd899de3d615984370e85735e/1469570428033468313;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/SeHtCROLy31Gxb10O7mRqUTxQtr?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:29 GMT" + ], + "Etag": [ + "OBtjqvaFShg5VQESCGRYFg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3U6DQBCF32W8bRPQaBOSXti6pU2MtAs1McaYZRkouLB0d9ASwru7VK/m75szZwb4KpsMAkjL4tyh6W8KpMOUcLSdIutCqxuLMAMkUTgyWlF1/hab+FTcvx5YvA7526ZYLh1h5QlrAcEAeYkqsxC8D9CIGt1a7n06gvp2KnYvCQsZd41aZ1ODsz17TNgTjB/jDCqdcszRYCNxUmuNrlDSbjKadUoizVttaL54uIUrfZ3EuKU1j577Oz+8pL4XLWp+PiaXAxlHKS0Flbpx4DEGd4Q0CcX1j3MJPvzXq57Q7o2WaC1Oot7fgbWuW4Xk3JDpcAZSuFe3JUGQC2Vx/AVLZr+6SAEAAA==" + } + }, + { + "ID": "476221b955abea69", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon946b615b821b1d3e96f31d374a46e0460158b3c7/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "abaebc5fd899de3d615984370e85735e/11510917729567081441;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon946b615b821b1d3e96f31d374a46e0460158b3c7/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:29 GMT" + ], + "Etag": [ + "2HIFRXdFp9Mtt5I1sNwWcg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8obeXi6BUWkuBVY+paUmHoaFvuVhyen29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsg5FAyVodCMsIzjJWqo0FQwA5zmMpigAAAA==" + } + }, + { + "ID": "f07a48a0d4c0951e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "173" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "c710b9ca687a1cc197ce4615ab37c6c6/13074810677771598961;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIChbMSwgMl0sIDMsIFs0LCA1XSkiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6Im1rWmNmZFM0VFZveWFZYlFkcVRlYURYWkNwRCIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:30 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/r-CC3wbcxM5SxuUZMOLXBfjDdS0\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TW2+bMBT+K5H3sklJMNdApGnrElahpdkaSC9pq8iYA3UDmGCTNKr632doKk3dVO3N8vnOd7P8hDasTNAYxSzbNlAfPjzwGPURSJKp21s0Iyu3xNbU/VGcBrBMfuXBfFYAuTwVWj2YTMx9TB/P7PCxWa7Ofs6uvqUP0yTEt0iRsJY4aXIKclDxWg5GjjFehsNis6JpElrRBT+Q6/g82UZAplerSTVVWwLydMbKjdq9l7ISY03b7/fDjPMsB1IxMaS80F79ajtDq2r+AFQK7Y2WprII7R21LzmnRDJefl6GSlnBF5BCDSUFNH5CR97gHzFe0N3k/TSvCgqoNJ77iPIyZVlTH2+fWp7oUClBdL70F9dqpwvWjo4HFPozfxL1Pt7o/Z5x1++Z/d6N1e/Zd58UOgEhWdnRRSTO/8N5QiQR8DJdUzd1cYy9WHfjFBsppPbIooBt7IKNLUidxB05DlF7sqXvtkjJy8TFdmxYnmeTGCDxPIxNwwOqGzr1PN3TFRU2E6sLXQORMGWi4oId65gs/JPIXwff13Pfn/ptWfuavUVdLgIFihbL+UShFaaqGVewtpZgHvmLk0kUXLSDRsAMMkIP4TZH45TkAp6VtJBENqItpT21NSuueTA/RcchU/XRDtC5bGtkRYvTbdMZqTQjrLsu6sC1/GtmONafT9aJFFDK45u+PB1qnSiD9RoKwpQ9ZDqO6XmmqVv2QFUvsc4L6RFj5G2omdGMbe+3m9yNeXzffE1gBzmvoB5mimPHKBBKeVPK9iug5983sBD5xQMAAA==" + } + }, + { + "ID": "d06ef086f3d8e961", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/mkZcfdS4TVoyaYbQdqTeaDXZCpD?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a27ca277c314b65159e3a09a399b9628/14638986191874585601;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/mkZcfdS4TVoyaYbQdqTeaDXZCpD?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:31 GMT" + ], + "Etag": [ + "Z4bgSZKsDBpLAnWAtVioeQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/42RUWvCMBSF/8vdawW3yQYFH6oNm6w4rdVtHUPS9Larpk1tbhlF/O8mDiZMGCMPyUnOl3tzsodtUaXgQlLkuxab7ipHmttFiLqVpM1Uq0ojOIDEc+OMB0m+iJ+0P6oDr3rxaFUonA+HxqHFJ5Yc3D1kBcpUg/u+h4qXaLCsvzYO6morQjZ+Dn2jS5VaPV0GgTcKmNm5JNenrfX1GZ9MI/bAwjMfshnzIubDwfmN3fyB/ZS9xG7/Ve3DDAc2KgkxwwYrgfbxdaM2KGhic01bKZB6tWqod39nmzHu00m5jUWWLgbRSnX8LZmnuwi5/xqPaxuMVIJToSpjXC5Mf0CKuAzVl4kGTlFYPeoI9axRArVGe2n/u8BYlbVEMt1Q06IDgpufeSwI3IxLjYcjG/nLuPcBAAA=" + } + }, + { + "ID": "4bc1ff51a37bb6b3", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anond805b24995abeed9900329ec121c99191fef03d4/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a27ca277c314b65159e3a09a399b9628/6233870898970259529;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anond805b24995abeed9900329ec121c99191fef03d4/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:31 GMT" + ], + "Etag": [ + "Z+F8F+Ov66/70nEEtxgH0A==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8pHabtZuGn7l5mZ6Zsb5Lm6llSkexg42toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsU7JCYkJIoLpaHQjLSKk2FsY2holCVZnAVZmCVMXWggkAVeRR7LQAAAA=" + } + }, + { + "ID": "6fa0a5fa086acf4e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "176" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "84f2eabf3f075c11bc7ec9a3329bd490/7798046413056469465;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIFsoMSwgMiwgMyksICg0LCA1LCA2KV0iLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6InBSNXE4Mk1vSXFvWkNqcTZtM3NITzF2Ylg0USIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:31 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/pP-EakwtJ4YCXPfL6VKRmgX_ids\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TW2+bMBT+K5H30kok3G+Rpq1KWMeaZS0hva1TZMyBugEM2CSqqv73GZpKU3fR3iyf73Y+y09oS6sUTVFC86aD9vHdA0uQgkDgXN7eoQW+9SrNmntn5WkI6/S8CJeLEvDVKVfr83GAt3vxxbqZXZ9nC+fyLCrz6w1N+R2SIrQXTruCgBjXrBVj1zGm69WkjuzGM76ysGG3s4fGKU3++Zu+S66tC8niUGQLWm0l916Imk9Vdb/fT3LG8gJwTfmEsFJ9zavuDLVu2QMQwdU3XqrcRab8u9uHghEsKKver1fSWcIjyKCFigCaPqGDbviHNV7Qw+Tf27w6SKD0eFYQYVVG86493D71OvFjLQ3RxTqIbiRnWKwfHQ5oFSyCWTz6fqQrI0MZmcfK6MhSRrYyco5/SEIKXNBqUIxxUvxH+BQLzOFluiFe5mmJ5ie6l2SakUFmuxYBzdY8sDULMif1XMfBkid6+YGFK1Y5uuUbxDN13dWyRMJ903JBN1zTAw17FgYpB1427N0CFjCnvGacHhqZRcFJHGzCT5tlEMyDuTTYt/Qt6ioKJSiO1suZREtM3VImYX0z4TIOopNZHF72g47DAnJMHldNgaYZLjg8S2susOh4X0p/6puWWstweYoOQyrrIwNgSNnXSMsep9um4+qG7uq2ZqIB3IrfZ77366sNJiVU4vCsL6+H+iQyYLuBElMZD5mOY/q+aeqWPZbVC01npfCx4fpbYuYkp819sy28hCX33ccUdlCwGtpJLjV2lAAmhHWV6H8Dev4JGomLK8gDAAA=" + } + }, + { + "ID": "d89021b61869000a", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/pR5q82MoIqoZCjq6m3sHO1vbX4Q?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "014446c116cafc7aade52fbb211f5bcd/9434277322190905705;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/pR5q82MoIqoZCjq6m3sHO1vbX4Q?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:32 GMT" + ], + "Etag": [ + "EZG6eVh6RlmyCsXOGaVHNA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/52RXWvCMBSG/8vZbQU/tm4UvNAuqOD8yFTEMSSmp1qXNm1zulHE/75EL4TtZoxcJO/J+yRvTk7wkWQRBLBL9kWFZX23R5q7BUdTKTJ2ynVmEDxAEnvrZJuBj6uDz1Vah2Y9HYjVcNLrdq3DyAOmAoITxAmqyEDwdoJMpGixuLm1DqpzJzgLp/zZ6lRHVz1jvQVzld/k9lLatm74aLJgA8Zv/GQ5Hvf6YwZn7yfW/h/W+RP2bocHR73jGGOJmUT3+LzUR5Q0cn2NKiWRGrkuqfHouzDWfdnJ+UPx1H7Ro0JvwmPhpx0znLY+d+v7uXUpLQUlOrPG5avNB6RJKK6/bGvg0gqn+zWhmZVaojHoDm1eLwh1miskm4bKCj2Qwv7MMCEIYqEMnr8Bftztg/cBAAA=" + } + }, + { + "ID": "39db88eaf5c94dbb", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon61492c831170fb5089347e12738e0a84aef02e8f/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "014446c116cafc7aade52fbb211f5bcd/957105534760279473;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon61492c831170fb5089347e12738e0a84aef02e8f/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:32 GMT" + ], + "Etag": [ + "ouAPoPFAaWa7Xo5VFjRJuw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8rnlzoG5Ae4OSaGJ5pH5JuGuWUFeZWW29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsg5FIAkB1tToQlhGcZaxUG1sL5SCrNYGrMIWzzMBqY8EQADe2u67EAAAA" + } + }, + { + "ID": "7b02b7ffa7803362", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "183" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ae1f7fc7dd79645d606cd2c8bc65bd8d/2593337543372789313;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIFsoWzEsIDIsIDNdLCA0KSwgKFs1LCA2XSwgNyldIiwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiIxVTVrU3dHT3Z3UnVmcWp2WTlVRlJHaW9NekgiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:33 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/KqfoVMPdEiq-QeNDB6HbLHCv_aU\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TbU/bMBj8K5X3BaS0eX9ppWljbVYiSgdpAmKAKsd5HEyTOE2cVgzx3+eEIk1sQvvm+O65e+6sPKMNK1M0QQnLti3UT58eeYIUBAJn8vYOLfBPr9SsmXdWzAOI04s8WC4KwNfzRj3bUn51fpH6bDu8hOXsm3OaLE6nuzWO75AUYZ1w2uYExLDitRi6jjGJVyM9tjer/fzHbh+2dPu4uxnH38M54+e/TuVUAzldsHIjZx+EqJqJqu73+1HGeZYDrlgzIrxQ3/ZVd4Za1fwRiGjUd16qzNKoH7h9yTnBgvHyc7ySzpIeAoUaSgJo8owOusE/Yryye+TjNG8Okig9XhREeElZ1taH2+dOJ3qqpCG6jP3wRs70wTrocEArf+FPo8Ht0a2uDAxlYN4rA+tYGRzd2srAkR/u8b2cS6ERrOyFI5zk/5EhxQI38IquiUc9LdHGie4lVDMoUNu1CGi25oGtWUCd1HMdB8s50cn3U7jkpU1Sg2qW49qGaekeYIcSSizdMT1NN3SKNQeDrmt9/BqwgBlrKt6wQzHT0D+J/HXwfb30/Zk/kwb7mr1nXYeBJEVhvJxKtuRUNeOS1hUULCM/PJlGwVUHtA0sIMPkabXN0YTivIEXad0ILNqmK6U7dYVLrWWwnKMDyGR9pCf0W3Y1sqLj6bbpuDKJa2qGjnpyLf7CdG385+P1JgWU4vC6r4+Iuk3kgvUaCszkesh0HHM8Nk3dsoeyeqHpvBBjbLjjDTEzkrHtw3aTewlPHtqvKewg5xXUo0xq7BgBTAhvS9H9FOjlN1071RfPAwAA" + } + }, + { + "ID": "0b3c9c4131b63195", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/1U5kSwGOvwRufqjvY9UFRGioMzH?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ed055f2561e8df71058deee45c66fdc0/4157511957980925649;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/1U5kSwGOvwRufqjvY9UFRGioMzH?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:33 GMT" + ], + "Etag": [ + "Ta/9Cgknud+/sOWZftcxLQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/32Qb0/CMBDGv8v50hHARA1LeAFzDpLJn8Ji1BhSutscdOtYbyASvrstmJioMX3RPnfP73p3B1hnRQwuLLN0U2O1v0iRpvbBUNeStLlKVWgEB5B4apxz3ux46bqo48umHj8+JyTew2m3axxavGHOwT1AkqGMNbgvByh4jgZLWgvjoH1pBfO9MbszOlfxWU/83ty3kd/k4hRatL/x4WjuBz77gz86P7Grf7BRFIa9fujD8dUcB1ZqyTDBCguBdoqyUisUNLQLimspkBqlqqhxe2OrGvcp046u17NdMN7uWJ1sVtunTnTPgkw9fAyMSyrBKVOFMUYz0x+QIi6Z2mmLwpfu7wn1pFICtUZbtHX+wFN5KZFMN1TV6IDgZsWDjMBNuNR4/ARcy4pTwAEAAA==" + } + }, + { + "ID": "ee576731072f17b7", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon5cd2f0467523418ea6fcfc416380121fa06ae110/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ed055f2561e8df71058deee45c66fdc0/14126802769266363161;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon5cd2f0467523418ea6fcfc416380121fa06ae110/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:34 GMT" + ], + "Etag": [ + "xeuNZPYf8CvMSRWnVvhPSA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8pXpJb6RQVEplk4l/kGB4XnhZVlBAQ72toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsg5EYAkDVtToQlhGcZaxUGwtjm4DYUA6mblO4HjMkPeZgPbFgCAC6Mbn53gAAAA==" + } + }, + { + "ID": "75a9336b0aa8eb30", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "182" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "82fc828ecf5f23f48c5348bed8a020cb/15763034777895650217;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEFSUkFZKFNFTEVDVCBTVFJVQ1QoWzEsIDJdKSkiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IjEyZDhGNXoyNjRjeW9ISUJpUlR6Rml0Z2JsSiIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:34 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/LVOCzKX4EPdtcoSIT3Qic-D0x6s\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TXU/bMBT9K8h7AYk2ifNdadq6NrCMqoM0hbExVY5zE0yTOI1duoL473NCkCY2oeXJ8T33nHvOlR/RmlUpGqGE5ZstNPt3dzxBxwgkydXtDZqR716lW1PvrDwNYZmeF+F8VgK5OhXa7PLr5OHsmxWcp5LyRRibF4wOpvovR9wgRcJa4nRbUJCDmjdy4Dp4tFwMDZx6J/YDdiy655/DTyyKH06YzJPii+oSUGQzVq1V762UtRhp2m63G+ac5wWQmokh5aX2Mq92j7W64XdApdBeaWnKi9DeUPtQcEok49X75UIpK3gEGTRQUUCjR9Tzhv+w8YzuKm+7eVFQQKXxdIworzKWb5v+9rHlife1EkQXyyC6Vj2dsbbUH9AimAWT+GAcRePrw/5nEUfLSXz4wzg+wD+PjlRbCkKyquONSVL8h4WUSCLgubqiXubpie4nhpdkOs4gs12Lgm7rHti6BZmTeq7jENUnW/qui1S8MizbyRLbAc9wsQ0+JoafYWyZFrb9FBIXU98lTta5b4BImDJRc8H6XCZRMI6DVXiymgfBNJgqgV3DXqOuolCBlOn5RKEVpm4YV7A2n3AeB9F4EoeXbWErYAY5ofvFpkCjjBQCnpS0kERuRRtKe2rzVlzzcH6K+iJT8dEO0E3ZxsjKFmfYpuMa2HAtE+uoAzfyr5r6/txdJ1JCJfvlPq8NtZOoAZsVlISp8ZDpOKbvm6ZKcaCil7rBS+kT7PprauY0Z5vbzbrwEp7cbj+mcA8Fr6EZ5orjnlEglPJtJds3gZ5+A6H3h2rOAwAA" + } + }, + { + "ID": "3afdbb6f6399b911", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/12d8F5z264cyoHIBiRTzFitgblJ?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6cb8f673a6c35aa300f218d3bbf4072f/17327210291981859897;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/12d8F5z264cyoHIBiRTzFitgblJ?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:35 GMT" + ], + "Etag": [ + "iXb48RAjLSR2mlxQHxPscw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/22QXWvCMBSG/8vZbQUtzknBC3V1dYytRgeDMUqannZxadM1p2gV/7uJDnaxkYuT9+R5z0eO8CWrDAJIZfHdYtPdFEgrd2FoWkXGhlpXBsEDJF5YUr6lwzGbbp/WzC/VfhXtYyN2k4kljPjEkkNwhFyiygwE70eoeInWlvcTS1BXO8HC+Qu7t7rU2VXH4XQTusxfZ3JJJYNf+/J5Ez6E7B//6cMeD7Y6ZZhjg5VAN07d6C0KWrpNs1YJpF6tG+rdjXy40JeXgZ+NF7cHfzQUnY6WM8k2h4WkIlWPllJacJK6suDrGmwT0sQV0zvjrPCjZx2hiRst0Bh0RfvXBnNd1grJTkNNix4Ibv8qkgRBzpXB0xkx+sPHiQEAAA==" + } + }, + { + "ID": "a5c060a64487b710", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon1456fb56e81725e92a19f22434259deb72c97a6f/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6cb8f673a6c35aa300f218d3bbf4072f/8922093899582683265;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon1456fb56e81725e92a19f22434259deb72c97a6f/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:35 GMT" + ], + "Etag": [ + "WhhgA0r9rC1Pp3gNQo+oyQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qHZ2SkOxoUWRY5GwYUGKf7BeZr51cG2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsg5EYAkDVtToQlpFSbSwQgonYWgB4jqbQlgAAAA==" + } + }, + { + "ID": "d300afb8b459152b", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "154" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "20101f03790f31bb901efb06714b11e2/10486269413685669905;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIDEiLCJ1c2VMZWdhY3lTcWwiOnRydWV9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiNjE3bWxHdUVwRUNDNFdBYnYxWnZ6ZlJhUnZGIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:35 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/1lRfKthoOCJ4wkJ43OATlrdhvLA\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1S7W6bMBR9lcn72wYw35GmLSI0oo3SjpBVqypFxlwTN4AJGKKs6rvP0FSauqnaP8vn695jP6M9rzI0RSnPDx00p89PIkUXCCTJ1e0jWpIHr9KtuXdTLiLYZHdFtFqWQO4XrWYUMbuRO3EbXFvH/bVl3s6Sosl2/XL2iJQJH4yzrqAgL2vRyEvXwdPNeuIYblksurAOg8C6n6W98dD/YjGJ+yulaqFgS17tlXYnZd1ONe14PE5yIfICSM3bCRWl9jav1mOtbsQTUNlq77I0tUurfZD2tRCUSC6qL5u1Slb0GBg0UFFA02d09o3+scYre0Q+3uYtQRFVxssFoqJiPO+a8+3z4JOcahWIvm/C+KfSjIsN0PmA1uEyDJJPhsIyaCWvRnFC0uI/5syIJC28olvqMU9PdT81vJTpmAGzXYuCbuse2LoFzMk813GI0snBflSRSlSUpq6VEQsThqnpM4MypjOMsYt9wwDspi4GDOa4YgNEwpy3tWj5efkgDmdJuI2utqswnIdzFXBs+HvWfRwpUhJvVoFiK07dcKFoQwnRKgnjWZBEPwaga2EJOaGn9aFAU9l08KKSW0lk1w6dDKehU2W1ilYLdAa5ao+OhHHIoUVeDjzDNh3XwIZrO66HRnIj/8Jc2/zzfcaQEip5fsDXd0LDJGq+Zgsl4Wo6ZDqO6fumaVj2pWpe6oYopU+w6++pmdOcH3aHfeGlIt113zLooRA1NJNcefScAqFUdJUc/j16+Q2olVpssgMAAA==" + } + }, + { + "ID": "07e8b6862ccd38e5", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/617mlGuEpECC4WAbv1ZvzfRaRvF?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6f84e9deeffae105acc0deee9c0566b1/12050444932066781601;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/617mlGuEpECC4WAbv1ZvzfRaRvF?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:36 GMT" + ], + "Etag": [ + "iPyLLsZbUOwUPQkAkxedAQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3WqDQBCF32V6ayCWkoCQCyM2DUiq20ohoZR1Ha1xdbfuaGqD79417dX8fXPmzBXqqs3Bg6wqv3rsxrsSKZkThqaXZGzQqjUIDiDx0pJVPEaROWbp8yWNk9qvvzH3k83GEkZ8YsPBu0JRocwNeKcrtLxBu1YsPyxBo56L/eE13IXMNhqVz41DGkX+Ngphep8cOKuMYYEdtgJnNd2pMwraz0bzXgqkhVYdLdare7jRt8nKXTdy14c6DIKHNz8b3OPwUzDOhkdLSSU4Vaq1YPoC9ggp4pKpi3UJLvzX25HQxJ0SaAzOosu/A4FqtESybqjr0QHB7atPFYFXcGlw+gX0egykSAEAAA==" + } + }, + { + "ID": "7c15427624bd57f2", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonccb74da42af2c39f1cff0f22272911e27b72e2e3/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6f84e9deeffae105acc0deee9c0566b1/3645329634867553769;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonccb74da42af2c39f1cff0f22272911e27b72e2e3/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:36 GMT" + ], + "Etag": [ + "rwXFnR/ciLuALgfHGHVONA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8oXlUe45QXpJ2f6lDr6pKd5uHuE+fs52toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwvXxgIhAPcy+KVuAAAA" + } + }, + { + "ID": "8089ef80401b514e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "156" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "97bc58f88fc9485b277cb6e5743d7d23/5209504053770591609;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIDEuMyIsInVzZUxlZ2FjeVNxbCI6dHJ1ZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJQRVBpUTBXc0dEVlRveDBUam5ja3VFVE5OTzUiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:36 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/meFbC_hSqbUNgl8P_TjQ8lDS8Ck\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1SbWvbMBj8K0P72sayHb8FxlYSN5gFN02clo1CkOVHjhLbciy5WSn975PcFEY3yr4J3T1395z0jA68KdAE5bw89tA9fd6LHF0gUKTUtw9oQX6GDR7Pwu/1PIFNsaySdFEDuZ9Lq4brfLrdrY/5Ji2rcLnN9rdhNVuH08MD0iLcCBd9RUFdtqJTl4HvTDbr0TJe8lt8L+ezu0z8wtm+oYc+ztL0xtNTEiq24M1Bz+6UauXEsk6n06gUoqyAtFyOqKitt7zWo2O1ndgDVdJ652XpXaT1gdvXSlCiuGi+bNbaWdNXwKCDhgKaPKOzbvKPNV7ZA/LxNm8Omqg9Xi4QFQ3jZd+db5+NTvbUakN0u4lXP/TMsJiBzge0jhfxNPtkj1yNFiAVb4bxjOTVfyQtiCISXtEtDVmIcxzldpgz7DBgXjCmgD0cgofHwPwiDHyf6Dll5Icp0ogmB8gxA1yE1LODcYGDKLIDxhhhmAZ4nFPfwVFBhyU7IApmXLZC8vP601V8lcXb5HqbxvEsnmmDU8ffs+5XiSZlq0061WzNaTsuNM3UkKRZvLqaZsmdAXoJCygJfVofKzRRXQ8v2lkqonppOjEn06qWSpN0js4g1+3RgTCENC3y2vBsz/UD27ED3/NMa5rcqb8w3wn+fKHBpIZGnZ/w9aWQSaLzdVuoCdfpkOv7bhS5rj32LnXzCtuiVhFxguhA3ZKW/Lg7HqowF/mu/1bAI1SihW5Uao1HToFQKvpGmZ+PXn4DAklD7rQDAAA=" + } + }, + { + "ID": "de2f7eb2cdc7a250", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/PEPiQ0WsGDVTox0TjnckuETNNO5?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3f7e390541c1fa22a0995cf2375c8428/6773679567856801289;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/PEPiQ0WsGDVTox0TjnckuETNNO5?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:36 GMT" + ], + "Etag": [ + "IaNASeHNPmGZDm9pe5tVKw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P0U6DQBBF/2V8pQmaVCNJH6jFtpFQSmlNNMZslwGhy+66O6SShn93qT7N3MyZuXcucKplAQEc6+q7Q9PfVEjbscnQdoKsK1pJi+ABEqscuWZJuMNVkrbLt0X7qHFKh5fzbOYIy7+wZRBcoKxRFBaC9wtI1qJbK/1PR1CvR/Ecb8LcyVYVo0z2cRzO4wiGj8GDRh0zLNGg5Dje0kY1yGk9xiw6wZEmWhmaPNzfwZW+TtIorbf+q10uDrn68fNG8lMX5UmymTpKKM6oVtKB+x04E1LERKbOLiPcwr+e94Q2NYqjtTge9f8MnlSrBZJLQ6ZDDzhzj65qgqBkwuLwC2kSNN9GAQAA" + } + }, + { + "ID": "c9b2b50e414655bb", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonbeeb0fe0d8c5174d079917fffaf0c704bc6209dc/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3f7e390541c1fa22a0995cf2375c8428/16815026869390414417;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonbeeb0fe0d8c5174d079917fffaf0c704bc6209dc/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:37 GMT" + ], + "Etag": [ + "5N2RMTGt0j72MpD3qI4UCA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qb+hkF+Ya4lxhkmRv5FrgYF3qahDo72toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwnrGSvVxgIhADsSdBhwAAAA" + } + }, + { + "ID": "f008672f8345609a", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "157" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0049b15461ca67e71a8e18cbf1d7dd6e/18378919817594932193;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIFRSVUUiLCJ1c2VMZWdhY3lTcWwiOnRydWV9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiTzVSOGNPclRJOWZ5TXh2RmNUNEtXbHNGajUzIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:37 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/uiVkDMbaflmtdCRxf-yN6vBbxvs\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1SbW+bMBj8K5P3tQlvwUCkaesSWqGmtCOk1aZKkTEP1A1ggk1eVPW/z6apNHVTtW+W7567585+RhvW5GiKMlZue+iOn594hs4QSFKq2we0IL/8xpzM/av6MoJVfltF8aIGcn8pjJ7dbebXGSmqWuaz5FCMjjHefc8OO/GAlAjTwnlfUZCjlndy5GF7ulqOb9zEpzddGgXF8fqwu6Dp5Oq+EhdPrqOmBFTFgjUbNfsoZSumhrHf78cl52UFpGViTHltvO1r7Gyj7fgTUCmMd16GyiKMD9y+VpwSyXjzZbVUzoqeQAEdNBTQ9BmddKN/xHhlD8jHad4cFFF5vJwhypuClX13un3WOumxVYboxypMfqqZIZiGTge0DBfhLP2UJqtQwTkIyZphPiVZ9R+r5kQSAa/omvqFb2ZmkFl+Vph2AYXrTSiYrumDa06gwLnvYUzUnNTywxRpeGPb4OPMzbGNTcuipptTsDF1rYntUDujdkBxnplkSNkBkTBnouWCnfLPkvA8DdfRxToOw3k4Vwb7jr1n3SeRIqmo8UyxFaftGFc03UMUp2FyPkujOw30AhZQEnpcbis0lV0PL8pZSCJ7oTvRJ12rkoqj+BKdQKbaowNhWFK3yGrNs1wHe5ZteZ5r6dYUuZN/Ydj0/3yiwaSGRp7e8PWpkN5E7detoSZMbYccjJ0gcBxr4o5U89K0eC0DYnvBhjolLdn2cbup/Ixnj/23HHZQ8Ra6cak0dowCoZT3jdRfH738Bk7/72y1AwAA" + } + }, + { + "ID": "9fabb08c1b2dc808", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/O5R8cOrTI9fyMxvFcT4KWlsFj53?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0a353e1606dfe7507dc8a5fc2e4b57aa/1568689227491378033;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/O5R8cOrTI9fyMxvFcT4KWlsFj53?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:37 GMT" + ], + "Etag": [ + "j5IEBdakruUfxizcO6iWiQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P206DQBCG32W8pUk9UJWkF8XQ2IjF0pJeGGO2y4BLFxZ3By0S3t3d6tWcvvnnnwGOoskhgIMoPzvU/UWJtHFJiqaTZGxoVWMQPEBipSUrfxWFOTvqLitO4ocnM7EXm/ncEoZ/YM0gGKAQKHMDwesADavRrhXTd0tQ37oiTJI4Wqxto1a5a6yzOF6EcQTj2+hBpQ4pFqix4ejUWq0q5LRyRvNOcqRJqzRNbmdXcKbPk8RP73iid6v7on8+fS357uZpL82y8q8tJRVnJFRjwWwL9ggpYjJV39YlXMJ/HfaE5kUrjsagE53+HXhQdSuRrBvSHXrAmX31URAEBZMGx1+guyXkSAEAAA==" + } + }, + { + "ID": "5e44d89c441753b1", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon22e86b5d626011c05dce26c51423c2bc29c6db0a/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0a353e1606dfe7507dc8a5fc2e4b57aa/11537980038793658296;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon22e86b5d626011c05dce26c51423c2bc29c6db0a/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:38 GMT" + ], + "Etag": [ + "pI3jfm8G4H99q+tK2CNSQQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8oXeBpnpeVauJt4WFoWapd4Gzn7BQcG2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwqXFJWmKtXGAiEARF2K8XEAAAA=" + } + }, + { + "ID": "e39283896b31c80c", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "158" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0f13a3675f434ab31546874f58989c7d/13174210947911317576;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUICdBQkMnIiwidXNlTGVnYWN5U3FsIjp0cnVlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IkpiR29iZWlDVFoxYXlYNVR4ZU1OclVHWllwZCIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:38 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/MKW7pcJflOoi8bCVhIdGepuJ2ZU\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1SXW+bMBT9K5P30Jc2fIOJNG0dYRFtyrYE2jWqFNnmQtwQTMA0jar+9xmaSlM3VXuzfM4959xjP6ENrzI0RpQXuw6aw8d7QdEpAkkKdXuHZmSJK92e4MvtNII0+1FG8WwL5GbaaleXN17NLvLyu+CYBtfrKJtC3V2Yy/QOKRHeC2ddyUCe1aKRZ55rjtPF6IJOBQUeJEuDHH45ySNcxU06Xd7WmZpqocxnvNqo2bWUdTvWtP1+PyqEKEogNW9HTGy117zag6nVjbgHJlvtjZemdmm1d9w+l4IRyUX1KV0oZ0WfQw4NVAzQ+AkddaN/rPHCHpD3t3l1UETl8XyKmKhyXnTN8fap10kOtTJEP9NwfqtmhsV66HhAi3AWBsmHk/OvwYnCM2glrwaBhNDyP7JmRJIWXtAVwznWqe5TA9NcN3PIHc9moDs6Bke3IXcz7LkuUXOylx+mSCUqSnUPG5mPmWk6NKMZdpmPdRtjYlsKynRMqO3BsGYDRMKEt7Vo+bGAYB6eJ+Eq+raKw3ASTpTBvuFvWTfzSJGSeRoHiq04dcOFovVFRHESzs+DJLruga6FGRSEHRa7Eo1l08Gzcm4lkV3bd9Kf+l6VVBzFU3QEuWqPDYQhZN8i3/Y8w7FczzAND9umjwZyI//CHFv/840Gky1U8viIL2+F+iQqX7OCLeEqHbJc1/J9yzJs50w1L3VDbKVPTM/fMKtgBd+td5sSU0HX3ZcMHqAUNTSjQmk8cAaEMdFVsv/76Pk3O++Z3LYDAAA=" + } + }, + { + "ID": "b3c379bf1157e677", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/JbGobeiCTZ1ayX5TxeMNrUGZYpd?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5611cf05c7ce4f95d88edab4b1711414/14738386462014304472;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/JbGobeiCTZ1ayX5TxeMNrUGZYpd?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:38 GMT" + ], + "Etag": [ + "8+udrBDEk3mXyzWwd37q1g==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P0U6DQBBF/2V8lCbFRmtI+iC1wRokSiHWGmOW3QFpF5buDqlI+HeX6tPMzZyZe6eHQ1kL8CAri2OLursokF7GJkbTSjK2NKo2CA4gscKSt5et0P796jCrtt3P60nM5ke3WCwsYfgXVgy8HvISpTDgvfdQswrtWj79tAR1zSg2SbyOAqsrJUYdpWF454crGD4GB/YqizFHjTXH8Vij1R45rcecopUcadIoTZP5zRWc6fPkMQtUhuUy2bms214n3/gU6TTYvTXCUlJxRqWqLZhuwJqQIiZjdbIhwYV/7XeE5lkrjsbgeHT6Z7BUVSORbBrSLTrAmf30oSTwciYNDr9FIbfoRwEAAA==" + } + }, + { + "ID": "2598e1b1225fa892", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonbb0781d98c225bdbd86c980488a43078d08ab47e/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5611cf05c7ce4f95d88edab4b1711414/6333271169093201184;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonbb0781d98c225bdbd86c980488a43078d08ab47e/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:39 GMT" + ], + "Etag": [ + "uMcvGOeLRKzt5TKlirirUA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qX+iaXufun+gR5V5WYhnjnZBZlFoU62toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwo7Ojkr1cYCIQCyn3UGcAAAAA==" + } + }, + { + "ID": "ced14d69b3677bcf", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "173" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "1a3a860aca3d9e8c609d15ee98e298b4/7897446683196188080;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIENBU1QoJ2ZvbycgQVMgQllURVMpIiwidXNlTGVnYWN5U3FsIjp0cnVlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IkU5ZURYbUJnZ1VPelpXOFlESWJWVHpXcEFyWSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:39 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/ZOKHDTtBcnigQISUQ4xy8RMnS6Q\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TbU/bMBj8K8j7wCZB89YmcaVpK23GIrqy5oUOhFQ5zpNgmsRp4tAVxH+fHYo0sWnaN8t3z909Z/kJbViVojFKWL7toNm/u+cJOkEgSC5vb9Gc3LiVPpy5F+W5D3H6vfAX8xLI6rzVbi4vvs4icUYrli/9MF4Of+7d4FsV2stbJEWYEk67goI4rXkjTh3bHMfhwMMw+1Ge5Xl8+Xizcq9nfnIVPa7qSXMtp1oosjmrNnL2Toi6HWvabrcb5JznBZCatQPKS+01r/ZganXD74GKVnvjpcldWu0fbp8KTolgvPoYh9JZ0gPIoIGKAho/oYOu/5c1Xtg98u9tXh0kUXo8nyDKq4zlXXO4fVI60b6WhmgZe4Ga6RdT0OGAQm/uTaOj6SSM3h9nnB8fTcKjs+vICz9IegqtYFWvF5Gk+I/oKRGkhRd0Td3M1RMdJ4abZLqZQTZyhhT0ke7CSB9CZqeuY9tEzgkl30+Rildg4YRQ2wUTUwqG41hOYhOcYFsfmjrVia1jw8Bmv3UDRMCMtTVv2aGPaeBNIm/tf1kvPG/mzaTBrmFvWavAl6QoiBdTyZacumFc0lQv/iLygsk08q8U0LUwh5zQfbgt0Fg0HTxL51YQ0bWqE3VSNUuphb84RweQyfZoT+hDqhZZqXjGyLIdwzQcbBoY9eRG/IFZuvX7k/UmJVTi8KYvT4dUEpmvWUNJmEyHLNu2MLYsYzg6lc0L3eClwMR08IZaOc3Z9m67KdyEJ3fd5xQeoOA1NINcajwwCoRS3lVCfQX0/Atyr2OZxQMAAA==" + } + }, + { + "ID": "d38f224f5e1166ee", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/E9eDXmBggUOzZW8YDIbVTzWpArY?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ed9a92c95f55eb0cd1ba97865584235e/9461621097804324160;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/E9eDXmBggUOzZW8YDIbVTzWpArY?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:39 GMT" + ], + "Etag": [ + "Te2OaIrrjGJvTSjOBPY1FA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PW0+DQBCF/8v42iZtH7yQ9AEsKoZI5WJFY8yyDAguLO4OGkr47y7Vp5mT+WbOmRE+qzYHC7Kq/OpRDWcl0uPchKh7QdqUTrYaYQFIrDRkjJuAeUrVt/ffcVQHzj5d39jbrSE0/8CGgTVCUaHINVivI7SsQbNWrN4NQUM3CyeN3cjIRuazfEh833Z8F6a3aQG1zEIsUGHLcb7VKVkjJ2+OmfeCIy07qWh5cb6BE32auFe4e26cskyC48vhMt152VN8PHS2Sg0lJGdUydaASQTGhCQxEcofkxHW8K+dgVDvleSoNc5HV38G17LpBJJJQ6rHBXBmHr2rCKyCCY3TLyVnFsFGAQAA" + } + }, + { + "ID": "44b89a3c74495190", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anone39bac68e29cce17737b6a9b960420c0a6091192/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ed9a92c95f55eb0cd1ba97865584235e/1056505804883221128;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anone39bac68e29cce17737b6a9b960420c0a6091192/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:39 GMT" + ], + "Etag": [ + "aDhYfSWqoJfe3/Qf3LpEJg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8onumREpgWHF+Z7paUa6wemGfsUuHql29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwpH5VqWKdXGAiEAz3tQ9HEAAAA=" + } + }, + { + "ID": "4950439bacbb6982", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "185" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "27032d80d1f634ad8cca6042aeafd14f/2620681318986207768;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIFRJTUVTVEFNUCgnMjAxNi0wMy0yMCAxNTowNDowNScpIiwidXNlTGVnYWN5U3FsIjp0cnVlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6Inl2SXhYbEh3QnE4MEtkZVBYQU5rRGN5NGkyaSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:40 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/sAk6rS8UlsuVYHktI-IZL_EiFnU\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2vbMBT9K0X70A2aWH4/YGxZ4ramqekSpy8KQZavXTWO5Vhy0lD63ye7KYwyyr4J3fO45wi9oBWrMhSglBWbFpr9lyeeohMEkhTq9gFNyb1XYWviXazPIlhkV2UUT9dAbs6EJkYrp5l7i1K013fnKxkNovvpMmSn1eIBKRHWCWdtSUEOat7IgesYwWI+3G+j59vyfPdr4+GLDK5uR/FqQvcWM5hiCSjzKatWivsoZS0CTdvtdsOC86IEUjMxpHytve+rbQ2tbvgTUCm0D16ayiK0T9x+lJwSyXj1fTFXzgo+gxwaqCig4AUddKN/xHhD95PP07w7KKDyeD1BlFc5K9rmcPvS6ST7Whmi34twdqc4fbBudDigeTgNx8lREl2G82R0efX12MC6M8DmwMBHuh1gK8D28TdFzUBIVvXaCUnL/4iREUkEvE2X1Ms9nGI/1b00x0YOue1aFLCNPbCxBbmTea7jEMWTnXzPIhWvCHY8KyVemuqubxFiYMOlqevZpm9kbgomNlNqQtY30ACRMGGi5oIduhnPwlESLqPTZRyGk3CiDHYN+4i6mUUKlMwW8VihFaZuGFewrqMoTsLZaJxE192gFTCFgtD9fFOiQDYtvCpnIYlsRddJd+oqV1JxFJ+hw5Cp9mgP6JfsWmTrDqfbpuPqhgrnuz7qwY38MPMwNs2/n683WUMlD+/79oyo20Tt1yxhTZjaDpmOY/q+aeqWPVDNS6zztfSJ4foraha0YJvHzar0Up4+tj8z2ELJa2iGhdLYMgqEUt5WsvsW6PUPaU9mjdEDAAA=" + } + }, + { + "ID": "79d0f7212bea1ee9", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/yvIxXlHwBq80KdePXANkDcy4i2i?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "dbac4048850a44f1aded041e80661087/4184855733577567144;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/yvIxXlHwBq80KdePXANkDcy4i2i?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:40 GMT" + ], + "Etag": [ + "3WQ58xBOfIWhgYGb+apUMg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P227CMAyG38W7HEiMnVAlLtoNjWrAOFUwTdOUpm4JpE1I3EGFeHcStiufPv/+fYKdqDIIIBXFvkbT3BRIM5/M0daSrAtaVRahBUiscOT9avbYO0YfebzaFJ9v6S3Tybjo9x1h+QZLBsEJcoEysxB8naBiJbq1vPPjCGq0L5bxeLBYhuOpa5Uq861JMhqF0WgA5+9zC7YqnWOOBiuOXk8btUVOsbea1ZIjtbUy1H5+6sKVvk6a3/i4lsNDtO913jOcrsPJ7pU3D6IrHCUVZyRU5cBkAe4IKWJyrg7OJ9zBfx01hHZqFEdr0Yt2/g68qFJLJOeGTI0t4Mw9OxQEQc6kxfMFmYhVMEoBAAA=" + } + }, + { + "ID": "094fed5e65c11ee4", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anona0684ba8bb1794aa2027cb785392d7be303bc3ed/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "dbac4048850a44f1aded041e80661087/14226203039406082032;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anona0684ba8bb1794aa2027cb785392d7be303bc3ed/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:40 GMT" + ], + "Etag": [ + "W0xTYAqjW6brY0lltz61AA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qHG1SERDoWZoWbJRVFGuTklFSZGTo62toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwmbmFqYWJgZmZjqGSjVxgIhAKUIkNd5AAAA" + } + }, + { + "ID": "a316fd52d851f022", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "191" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "fb26eadcb4056e8c030c97a62f28614d/15790378553509068672;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIERBVEUoVElNRVNUQU1QKCcyMDE2LTAzLTIwIDE1OjA0OjA1JykpIiwidXNlTGVnYWN5U3FsIjp0cnVlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IjY2cXFOWnF6c096Z1I1N2JCT3NFZFVtUU94MiIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:41 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/0qg8IlhO3J2kWVZuV2fmAX1xYHM\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2+bMBT9K5P3oa3UBPMMRJq2LGEdW5q0CWnXqlJkzIW4AQzYNH2o/32GptLUTdX4Yuuec8+591g8oS0rYjREEUurBuqHj7c8QscIJElV9QZNybVbYGvi/sxPAljFZ1kwm+ZALk+EhqvUDbLN3PxhbC8vrpsLI8lHv/T7q++nN0iJsFY4bjIKslfyWvYGjjFcLfuOU1Wz6+pRzB/ThT2Ivs6FH6/y8/m9oboEZMmUFVvVu5GyFENN2+12/ZTzNANSMtGnPNde59XuDK2s+S1QKbQ3XpraRWjvuH3OOCWS8eLTaqmcFX0BCdRQUEDDJ7TXDf6xxgu7Q97f5tVBEZXH8zGivEhY2tT76lOrEz6UyhCdr/zFlerpFmuh/QUt/ak/Dj9MRqF/GAan/jIcnZ4dHhhYd3rY7Bn4g24PsTXE9sHRkRKIQUhWdA4hibL/WCYmkgh4QdfUTVwcYS/S3SjBRgKJPbAoYBu7YGMLEid2B45DVJ9s5bsuUvDCiigM3ATHruHZsWV5ifqoR3TTMx1VUkecWCTpcqiBSJgwUXLB9gmNF75acR18W898f+JPlMGuZm9Zl4tAkcLFajZWbMUpa8YVrU0qmIX+YjQOg4sWaARMISX0YVllaCjrBp6Vs5BENqLNpL21wSupWTA7QXuQqfRoR+iGbFNkecvTbdMZ6Ibu6tgwUUeu5d+Yq//5iJ1JDoXcv/LLY6J2EjVfvYacMDUdMh3H9DzT1C27p5KXWOe59Igx8LbUTGnKqk21zdyIR5vmSwx3kPES6n6qNO4YBUIpbwrZ/hzo+TfGYudA1wMAAA==" + } + }, + { + "ID": "646e1d2fbe2cb1a0", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/66qqNZqzsOzgR57bBOsEdUmQOx2?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b0a6ce9f3ef7a35140f60fad1ca77509/17426610566416480272;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/66qqNZqzsOzgR57bBOsEdUmQOx2?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:41 GMT" + ], + "Etag": [ + "oOG4SJftDzSB/rcCI5Gh8A==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PQU+DQBCF/8t4bWM1lhqSHkptEEOKBblojFmWgVIXFnaHKDT89+5WTzMv8828N2f4rpocXMiqsutRDTcl0sE2MepekDallY1GmAESKw0pI/8heSnoaUy8W8W3wdI/Pm7Wa0NofsSagXuGokKRa3A/ztCwGs1asfgyBA2tFclbHOx9o2uZW71Pw3DjhTuYPqcZnGQWY4EKG472WKvkCTkFNmfeC440b6Wi+cq5hyt9nThO1+3fu1FHYxkvV5kX6V2e1ofo11JCckaVbAyYJmBMSBITsfwxIeEO/rU3EOpXJTlqjfbo4s9gK+tWIJk0pHqcAWfm0+eKwC2Y0DhdAGnwQolHAQAA" + } + }, + { + "ID": "03fbb954750d85fd", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon4bce78f0d8295d449ffffc9a13936295393df4af/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b0a6ce9f3ef7a35140f60fad1ca77509/8949437675196101720;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon4bce78f0d8295d449ffffc9a13936295393df4af/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:41 GMT" + ], + "Etag": [ + "xXGiYCfHPWequO53xyJvPg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8pXRLhnRjqneQSEpxaW+psaV1R6lQWk29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwobGRia6RoY6xoZKNXGAiEAECCg6XcAAAA=" + } + }, + { + "ID": "a784f4acfa3b799f", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "191" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0ab4b8db8f9827a5e9a040c3c1fa6aa3/10585669688103513576;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIFRJTUUoVElNRVNUQU1QKCcyMDE2LTAzLTIwIDE1OjA0OjA1JykpIiwidXNlTGVnYWN5U3FsIjp0cnVlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6InZpQ3J5YlV1bGZyMk1CYURUOFdkWkU2OXBEZCIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:41 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/tRzREemD_T8CbJNyQ8K6Rfh3F3Y\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TYU/bMBT8K8j7AEi0cZLGdStNG2sDCpQI0nQIhFQ5zktqmsRp4rTqEP99TijSxCa0L5blu3f33j35Ba1FEaMxikS6aaDaf3mWETpDoFiqX5/QjD3SAg+m9Dq/9GAR32aeP8uB3V/Whgp+BS7k02VIJ9GVv7+j1yRIVvaF/fCEtIhoheMm46B6paxUb0is8WLe34pJtY8WTZZU1s0PNg3pffzoklE5jXVVDVkyE8Va166UKuuxYex2u34qZZoBK0Xd5zI33vs1tpZRVvIZuKqND16GnqU2PnH7lknOlJDF18VcO2t6AAlUUHBA4xd00PX+McYbu0M+n+bdQRO1x+sZ4rJIRNpUh9eXVifcl9oQ3S3c4EHXdIO10OGC5u7MnYRHoXfjnrTHPDy/uT05trBJetjuWfjIdMZ4MMbO8empFoihVqLoHEIWZf8xTMwUq+ENXXKaUBzhUWTSKMFWAokzHHDADqbg4AEkJKZDQpiuU618V8UKWfAIMB1SQuIkITgGYnI6IE6sQ6WEa6dIKzF71OVQAVMwFXUpa3FIaBK456G79C6WvutO3ak22FXiI+s+8DQpDBb+RLM1p6yE1LQ2Kc8P3eB8Eno/W6CpYQYp4/v5JkNjVTXwqp1rxVRTt5m0tzZ4LeV7/iU6gEKnxztC12SboshbnunYZGhaJjWHtoM6cqX+wqhF/1xiZ5JDoQ5bflsmajvR/VVLyJnQ3SGbEHs0sm1z4PR08gqbMlcjZg1Ha26nPBWb1Wad0UhGq+Z7DFvIZAlVP9UaW8GBcS6bQrWfA73+BjRQdNfXAwAA" + } + }, + { + "ID": "b579da2600fae697", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/viCrybUulfr2MBaDT8WdZE69pDd?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8670c69d6d2609c728182128b4a57493/12149845202206500216;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/viCrybUulfr2MBaDT8WdZE69pDd?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:42 GMT" + ], + "Etag": [ + "sk4CY9omTBZCXqSwIf5/CA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3U6DQBCF32W8pbE2Wi1JLwptlAQb5SdqjTHLMuC2C0t3BxtCePcu1auZk/lmzpkeDqLOwYVMlMcWdXdVIr2OTYSmlWRsaVRtEBxAYqUlzeHW/1ioKvF2/vsxPgXF3bW/Wi4tYfgPVgzcHgqBMjfgfvZQswrtWjH9tgR1zSjiJAq2j1ZXKh/1Ng3DlRduYPgaHNirLMICNdYcx2ONVnvkFIw581ZypEmjNE3u5zO40JfJr/B1l6WtLPTs2WPr5OEt323mi2adW0oqzkio2oJpDNaEFDEZqZMNCTfwr72O0LxoxdEYHI9O/wx8VTUSyaYh3aIDnNlPnwSBWzBpcDgD76yXeUcBAAA=" + } + }, + { + "ID": "4399ac2e121f7843", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anoncbe087866dff60de61c8465defe86c762bf57a39/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8670c69d6d2609c728182128b4a57493/3744728805512421824;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anoncbe087866dff60de61c8465defe86c762bf57a39/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:42 GMT" + ], + "Etag": [ + "2JcltEdI8YDP4OgWd2zhlQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8obeSXnlLimeFpEugSY+KeHpxhVZeQE2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwmbWhmYWBmYKtXGAiEAIPmBeXUAAAA=" + } + }, + { + "ID": "7586cea28373ac67", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "257" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "dd7266cdec7cd2aadae4d0a697515c0d/5308622853211789904;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEB2YWwiLCJxdWVyeVBhcmFtZXRlcnMiOlt7Im5hbWUiOiJ2YWwiLCJwYXJhbWV0ZXJUeXBlIjp7InR5cGUiOiJJTlQ2NCJ9LCJwYXJhbWV0ZXJWYWx1ZSI6eyJ2YWx1ZSI6IjEifX1dLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6Ik90WlRQNkJWaWJzaTdkRFNLMWlWNm5oUmRkUCIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:42 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/ylr92LkYb9mS5oZd-u-f8fS7FwA\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TXW/aMBT9K5P3Wsi3kyBNawdpFRVRBoGqXSfkODfBJYlD7IAQ4r/PCXSauqnam+Nz7jn3nusc0YaVCRqgmGXbBurD51ceoysEkmTq9gWNybNX6vbIuy/uQlgk0zycjAsgj3dCO+S1b443T7FfzB3+nPSaXuqlc/d2f/OClAhrhZMmpyB7Fa9lz8XmYDHvP8jnaIq/LVksmJuM5vcGW+JyPUuSqaoSkKdjVm5U7VrKSgw0bb/f9zPOsxxIxUSf8kJ761fbmVpV81egUmjvvDQ1i9A+cPuac0ok4+WXxVw5K/oMUqihpIAGR3TRDf8xxpndIR9P8+agiMrjdIUoL1OWNfXl9tjqRIdKGaLvi2D2pGq6wVrockDzYBwMo0/XO5IrOAEhWdnVRyTO/6PVhEgi4IyuqJd6eqz7seHFqW6mkDquTUF3dA8c3YYUJ56LMVF1spXvqkjJS0x8aoBJXJwmlpkaum+lFuhJ7GFs29h0/Ji4Ova7KWsgEkZMVFywy/zDWXATBavwdjUJglEwUgb7mr1nPc5CRYpmi8lQsRWnqhlXtDaHcBIFs5thFC5boBEwhozQw3ybo0FKcgGX7KakJgVIqAUa/DiiUn2o6nN61Rt2Dv2I5Dl8pY3ttvXfhCXJm46xOx+QgU6nnydFEZLIRrRQe2oh1e4knNyhC8jUhmhH6IJoN8W6HgzHwq5hGp7pYAN15Fr+hWHL/vMZdCYFlPLyTs7PAbWdqAzqFRSEqQSQhbHl+5Zl2E5PbVfqBi+kT0zX31Aroxnbrreb3It5vG6uE9hBziuo+5nS2DEKhFLelLL9vdDpF2tz9z0ZBAAA" + } + }, + { + "ID": "ab42b1ce3e8b2c72", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/OtZTP6BVibsi7dDSK1iV6nhRddP?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8c63c15bf2741692d4a921b383c690d0/6872798367314776800;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/OtZTP6BVibsi7dDSK1iV6nhRddP?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:43 GMT" + ], + "Etag": [ + "B252J5XarU8m/UJ4npGvBA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2Pb0/CMBDGv8v5dkQgAmYJL5guCBKcgxGjMaZrb1Ds2tneNMuy726Hvrp/v3vuuRY+pRYQQi6PXzXa5uqI9NwnKbpakfOhMtohBIDEjp6MxpPxevLCbHZbXmfrG10tv6PFfO4Jx09YMghbKCQq4SB8a0GzEv1aMfzwBDVVX6y2+3gZp75RGtE3ttlms4g2MXTvXQBnk6dYoEXNsVerrDkjp1VvVNSKIw0qY2kwm47hQl8mT/S6T6bRQeZOzsT97nEkD1N9SoVIPKUMZySN9mC2A3+EDDGVmh/vEkbwX0cNoUus4egc9qLDvwN3pqwUkndDtsYAOPOvPkiCsGDKYfcLc04II0gBAAA=" + } + }, + { + "ID": "2622d412e3f630ff", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon6a9c1e2a76fd32f1093f3e0db866446259ba7069/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8c63c15bf2741692d4a921b383c690d0/16914145673143291432;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon6a9c1e2a76fd32f1093f3e0db866446259ba7069/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:43 GMT" + ], + "Etag": [ + "bq8ShEXKFYvN3M9OQMIAzA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8kXWgRnuEZ4u0WW+Rn7WvoH+no6Vjna2gJVlOSXJOYE5ZcXA5UZAvlFYGZ0tVIamCwDC9fGAiEAoIIldm4AAAA=" + } + }, + { + "ID": "5b1e90bd2406b7d4", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "261" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d6dadf499cb0de070d3e8fc5d218b2cb/31857489001809848;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEB2YWwiLCJxdWVyeVBhcmFtZXRlcnMiOlt7Im5hbWUiOiJ2YWwiLCJwYXJhbWV0ZXJUeXBlIjp7InR5cGUiOiJGTE9BVDY0In0sInBhcmFtZXRlclZhbHVlIjp7InZhbHVlIjoiMS4zIn19XSwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJZbUxsYUlLeHdOd1RncDlhMk9id3VoUTk4RnAiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:44 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/lH2hrG0-l7oJW3hV_ASs1qZuFaw\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TXW/aMBT9K5P3WkhCQj6QphVBYFkRbSG0atcJOc51cEniEDtkCPHf5wQ6TdVU7c3xOeeee49vjmjL8hgNUMSSXQXl4fMrj9AVAokTdfuCZvjZzXVr7N5k0wBW8V0azGcZ4Mep0NJvvU051Tupw78/mpuH9XApjN1zNcH1C1JFWFM4rlICslPwUnYcuzdYLbtP2SzFwc2vel6HSeHh3m1UV5t7z50USiUgpTOWb5V2I2UhBppW13U34TxJARdMdAnPtLd+tX1PK0r+CkQK7Z2XpmYR2gduX1NOsGQ8/7JaKmdFXwCFEnICaHBEl7rBP8Y4s1vk42neHBRReZyuEOE5ZUlVXm6PTZ3wUChDdL/yF09K0w7WQJcDWvozfxR+ut7jVMExCMnyVh/iKP2PVmMssYAzuiYudfVI9yLDjajeo0D7jkVA7+su9HULqB27jm1jpZNN+VaFc9V2bGNHaalOLWxEFCzLoU7PtAwLx4RS6nquFVv9dsoSsIQxEwUX7DL/aOEPQ38dTNZz3x/7Y2VQl+w963ERKFK4WM1Hiq04Rcm4ojU5BPPQXwxHYfDQAJWAGSSYHJa7FA0oTgVcsrvDJc5AQinQ4McR5epDqc/pFW/YOfQjkufwJ7PbYWhbTfN/KA84rVrO/nxARtdEp9PPkyIJiWUlGrA5NaBqeR7Mp+gCMvVKpCW0YTSvxdo+jL5pO0bPcE3PMlBLLuV7zNIN/e9VaE0yyOVlV84rgZpOVA7lGjLMVArItG3T80zTsPod9cJSN3gm1VI63paYCUnYbrPbpm7Eo011HcMeUl5A2U1UjT0jgAnhVS6bXwydfgOv6uBjHQQAAA==" + } + }, + { + "ID": "b6960d6be6fb1614", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/YmLlaIKxwNwTgp9a2ObwuhQ98Fp?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d9b8d44ba80cac0e2707c25615875476/1596033003104796488;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/YmLlaIKxwNwTgp9a2ObwuhQ98Fp?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:45 GMT" + ], + "Etag": [ + "eclDgWfmCb/410l6Ff+bVA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P0U7DMAxF/8U80oluQoNV2sM2qJioNlY2EEIIpanbdSRNSFyVquq/kwye7Csf+1738FXVOUSQVeV3g6a7KJF2vknRNoKsK1rVFiEAJFY6Erm4K18LucqursehmMbFZfaymM8dYfkRJYOoh6JCkVuI3nuomUS3VoSfjqBOexEn28XeSalyLzeHJFksk3sYPoYATipLsUCDNUd/Sxt1Qk5rHzNvBEcaaWVodDOdwJk+T95kItj68afdtPtSz9hkm7XNcTe7jbWjhOKMKlU78PAMzoQUMZGq1mWEMfzrZUdon4ziaC36o+GfwUpJLZBcGjINBsCZe/ShIogKJiwOv6jWr7VGAQAA" + } + }, + { + "ID": "2ada249d420a0a0a", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonfd6a7f80f0f4a1bfe447f723414adcfff8984d45/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d9b8d44ba80cac0e2707c25615875476/11637380308916534416;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonfd6a7f80f0f4a1bfe447f723414adcfff8984d45/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:45 GMT" + ], + "Etag": [ + "xrJk0GebkxdpykUugJRu6g==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8pXFHllG7inJmVXpBRUZoeWpnsFlZql29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwnrGSvVxgIhAFqF+CJwAAAA" + } + }, + { + "ID": "2a89bf236c040cc3", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "269" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "07b1a9833dab3cbb4eeec99f9c062797/13201554723524670496;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEB2YWwiLCJxdWVyeVBhcmFtZXRlcnMiOlt7Im5hbWUiOiJ2YWwiLCJwYXJhbWV0ZXJUeXBlIjp7InR5cGUiOiJOVU1FUklDIn0sInBhcmFtZXRlclZhbHVlIjp7InZhbHVlIjoiMS4zMDAwMDAwMDAifX1dLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6ImNKSEJTQmZLN2pKTE1CT3MxZFJRdFo5RFhIMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:45 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/er-ZEfzLdEEXrfDY5jW87IvW20w\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TXW/aMBT9K5P3WkhCvpGmtYWszUpZG6C0XSfkONepIcQhdkAd4r/PCek0dVO1PDk559xz77nOHq1YnqA+ilm6qaB8+bjkMTpBIHGqvj6hEX70ct0aelfrixBmyU0WjkdrwPMLoUHZeQzoz1ESBPclHT7Yy7nnhtt5T989IVWE1YWTKiMgOwUvZcd1ev3ZpEu+Xp5PzumVu/w6uj7/JowkupWP/vD+0lAqARkdsXyltM9SFqKvabvdrptynmaACya6hK+11361bU8rSr4EIoX2xktTswjtHbfPGSdYMp5/mk2Us6JHQKGEnADq71FbN/zHGEd2g7w/zauDIiqPwwkiPKcsrcr2676uM30plCG6nQXRg9I0g9VQe0CTYBQMph9OtzhTcAJCsrzRT3Gc/UerCZZYwBFdEI96eqz7seHFVO9RoLZrEdBt3QNbt4A6iec6DlY6WZdvVDjnObHBtEzPNU3LsnyMXd2wHMPxTJvimFqG7QIltu80U5aAJQyZKLhg7fyDKDibBovwy2IcBMNgqAx2JXvLmkehIk2j2Xig2IpTlIwrWp1DOJ4G0dlgGt7VQCVgBCkmL5NNhvoUZwLa7G5widcgoRSo/32PcvWi1Mf0ilfsGPoeyWP449l1EIWDuvnflDucVQ1nezwgo2vq7YMOhx8HRRYSy0rUpPpUk1Tr43B8gVqQqW2RhtCEUm+NNf0Ytum4Rs/wbNuot6TIpfwLc0zzzyvRmKwhl+2dOV4NVHei8igXsMZMpYFMxzF93zQNy+6oTUvd4Gvp457rr4iZkpRtnjerzIt5/FydJrCFjBdQdlNVY8sIYEJ4lcv6V0OHX1BaFQElBAAA" + } + }, + { + "ID": "6390da3d0a939aa9", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/cJHBSBfK7jJLMBOs1dRQtZ9DXH1?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7d275d063c2643c2c6cce4fef3b5345f/14837786732137180592;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/cJHBSBfK7jJLMBOs1dRQtZ9DXH1?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:46 GMT" + ], + "Etag": [ + "YzTibHdGPndy6exOKY/Paw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/yWP3U7CQBCF32W8hQheQGzChUVigSKlSCIaY7a709q67dbdabA2fXd3y9X8fXPmTAffeSXAgyTPfhrU7U2GdHBJjKaRZGyoVWUQRoDEMkue/17yJBBPUSXaGf7ut+fbiF0WC0sY/oUlA6+DNEcpDHjvHVSsRLuWTj4tQW3tiufTbhWvl7ZRKnFthOGDH66g/+hHUKgkxhQ1VhydWq1VgZzWzqhoJEca10rTeD67g4EeJnwT+Ec/3c6LTbjz92Yq4gO93T++BlNLScUZ5aqy4OkI9ggpYjJWF+sSHDDUfktoIq04GoNOdHI9sFRlLZGsG9INjoAz+2qQE3gpkwb7fxyhLcpIAQAA" + } + }, + { + "ID": "851f295e9f372f95", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonc5e34387334449aa7014616835fabf4157efc596/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7d275d063c2643c2c6cce4fef3b5345f/6360614944706554360;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonc5e34387334449aa7014616835fabf4157efc596/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:46 GMT" + ], + "Etag": [ + "a3MItnbUT0Fx5NCNuMyH8w==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8onGvt6luQlhYYYuFWY+jn7lfpWeliU29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwnrGSvVxgIhABgLW8NwAAAA" + } + }, + { + "ID": "b20843f252a6a58c", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "259" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "bed977a3e1be69279350c4279782738b/7996846953335841160;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEB2YWwiLCJxdWVyeVBhcmFtZXRlcnMiOlt7Im5hbWUiOiJ2YWwiLCJwYXJhbWV0ZXJUeXBlIjp7InR5cGUiOiJCT09MIn0sInBhcmFtZXRlclZhbHVlIjp7InZhbHVlIjoidHJ1ZSJ9fV0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiWHFvQk5pOWhuZmc2VENhWnlNclNKRkpINk8xIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:47 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/KZrPT2Y3w7la8joA-fkaPpD4ZBU\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TXW/aMBT9K5P3WsgnIUGa1hbSLi2jDEK7sk7Ica5TlxAH2wEhxH+fE+g0dVO1pzg+59xz77G9R0tWpKiHEpatKxC7jy88QWcIFM707hMa4rlfmO7Av11dRzBLx3k0Gq4AP1xL43YuxrH96Gy7OfZf+EWLLvG4HLjzy9kT0kVYXTitcgKqVXKhWl3P7s2m7e9rfjliwXNBMy/u4/nuq5jeXN188e4srZKQ0yErllr7rFQpe4ax3W7bGedZDrhksk34ynjt19jYRin4CxAljTdehp5FGu+4fc45wYrx4tNsqp01fQIUBBQEUG+PTnWjf4xxZDfI+9O8Omii9jicIcILyrJKnHb3dZ14V2pD9G0WTh61phmshk4LNA2HYT/+cL7BuYZTkIoVjT7GSf4fraZYYQlHdEF86puJGSSWn1DTpkA7XZeA2TF96JguUC/1u56HtU7V5RsVLngRUOKYFAJKwbU7ietark88j1iEYmoR23f9NEmw20wpACsYMFlyyU7z9yfhRRwuoqvFKAwH4UAbbAV7y3qYRJoUT2ajvmZrTikY17Q6h2gUh5OLfhzd10AlYQgZJrvpOkc9inMJp+zGWOAVKBAS9X7sUaF/tPqYXvmKHUPfI3UM//Lublh3/hu/x3nVEDbHBVJCfw6HnwfNkgqrStZovapR3fAoGl2jE8j0GZGG0ERRnxVrurA6jte1bMvvmqaLGrJQf2O+++dFaExWUKjTTTleCFR3olMQC1hhpjNAjuc5QeA4lttp6fNVpsVXKsB2N1gSJyMZWz+vl7mf8OS5Ok9hAzkvQbQzXWPDCGBCeFWo+oGhwy80x7HJGwQAAA==" + } + }, + { + "ID": "70b3a2baaf80bdc3", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/XqoBNi9hnfg6TCaZyMrSJFJH6O1?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0a67d890d50d40dc4701ca52e8517d8e/9561021367927200280;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/XqoBNi9hnfg6TCaZyMrSJFJH6O1?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:47 GMT" + ], + "Etag": [ + "dtIbdzLQM6KNQQ3dllbPSA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/yWP3WqDQBCF32V6ayBtwVIhFxpSktSYaBooLaWsu6MxXV2zO1Ks+O7ZtVfz982ZMwP8VI2AAPKqvHao+7sSKXVJhqaTZGxoVWMQPEBipSUFbXLxF6c7/zVJ00chZX44houFJQw/Y80gGKCoUAoDwecADavRrhXzb0tQ37oi2u/jVZjYRq2EaySnOA6jeAXj1+jBReUZFqix4ejUWq0uyGnjjIpOcqRZqzTNnvwHmOhp8n5VUVI9n5ui9N+W7KPf6eP2Zbv29/eWkoozqlRjwdMR7BFSxGSmfq1LcMBURz2hOWjF0Rh0ovP/A0tVtxLJuiHdoQec2VfXFUFQMGlwvAF63enYSAEAAA==" + } + }, + { + "ID": "a64d5f552f3d9209", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon9fc30fe9ffe425b44148c66c1cfaf1c2848dbba4/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0a67d890d50d40dc4701ca52e8517d8e/1083849580496574048;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon9fc30fe9ffe425b44148c66c1cfaf1c2848dbba4/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:48 GMT" + ], + "Etag": [ + "1sj8EtLTl+5iI9iUMS+g/A==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8obFmdZuJb4hORom2Z6WmaG+gZrp+s72toCVZTklyTmBOWXF4OUAflFYGZ0tVIamCwDCpcUlaYq1cYCIQByPgxIcQAAAA==" + } + }, + { + "ID": "9f40464ba10b2740", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "260" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "96a1c7b3fe4d3a171a4acb0c7cf84740/2720081589125861104;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEB2YWwiLCJxdWVyeVBhcmFtZXRlcnMiOlt7Im5hbWUiOiJ2YWwiLCJwYXJhbWV0ZXJUeXBlIjp7InR5cGUiOiJTVFJJTkcifSwicGFyYW1ldGVyVmFsdWUiOnsidmFsdWUiOiJBQkMifX1dLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6InROdnJZblplQ2lNWWxiWFppNm1RV3dNNlc2dyIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:48 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/S6ojXyQoH6J-3Y5OljXpDwuaAzM\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TYXOaQBT8K53r1ygocIIzncYqTWkMTRRjTNNxjuNBToFD7tCxjv+9B5pOJ+1k+u243bf73r7jgNYsj1AfhSzZVFDu3694iC4QSJKo2yc0Jo92rpsj+zq78mAW3aaeP86AzK+ENsV89bC/41/w15axsL6lq4ditKvI4OfNE1IirBaOqpSCbBW8lK0e7vZn07b0t+Uif4Qhu1mk4cMjw9ndfHeD53inqgSk8Zjla1X7LGUh+pq22+3aCedJCqRgok15pr30q227WlHyFVAptFdemppFaG+4fUw5JZLx/MNsqpwVfQIxlJBTQP0DOut6/xjjxG6Qt6d5cVBE5XG8QJTnMUuq8nx7qHWCfaEM0d3MnSxUTTNYDZ0PaOqO3WHw7nJLUgVHICTLm/qAhOl/tBoRSQSc0CW1Y1sPdSfs2GGsd2OIrZ5JQbd0GyzdhBhHdg9joupkLd9UkZznOCKKSSyDYAqmg0PbjA3HsSKr65gmsYHqIYQ9s5myBCJhxETBBTvPP5y4g8Bdep+XvuuO3JEy2JXsNWs+8RQpmMz8oWIrTlEyrmh1Dp4fuJPBMPDua6ASMIaE0P10k6J+TFIB5+xuSUkykFAK1P9+QLn6UNWn9IoX7BT6AclT+NNg4vlXde+/GfckrRrK9nRAg09DdDz+OCqSkERWogbrUw2qjv2zQn3F1JJoQ2iyqJfFmjY6loF7nW7Htk3LQQ25lH9hlmH8+RIakwxyeX4qpxeB6k5UDOUSMsJUCMjAWK3EMDqm1VILlnqHZ9Ih3Z6zpkZCE7Z53qxTO+Thc3UZwRZSXkDZTpTGllEglPIql/Ufho6/AAqt8SAcBAAA" + } + }, + { + "ID": "367899551668790c", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/tNvrYnZeCiMYlbXZi6mQWwM6W6w?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "1b7c330e26977a35e8687106f41bbaae/4284256008012121984;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/tNvrYnZeCiMYlbXZi6mQWwM6W6w?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:49 GMT" + ], + "Etag": [ + "8F8Q5AM/lvvMqDQTzRDwEw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3U6DQBCF32W8bWM1ERuSXvRPbQJEaJvaGmOWZcCtC0t3BwgS3t2lejVzMt/MOdPBtygScCEW2aVC3d5kSOHQRGgqScaWUhUGYQRILLPk9GkaPsz9W1nX/mUV7n6iVbNuZjNLGP6FOQO3g1SgTAy47x0ULEe7lk4+LUFtOYjtLtoEz1bnKhl0sPe8+cJbQ//Rj+Cs4ghT1FhwHI6VWp2R02bImVSSI41LpWn86NzDlb5OKKj1sTjhUvhHGb+dhJOHh8Z3Dk5jKak4I6EKC+63YE1IEZORamxIuIN/vWgJzatWHI3B4ejkz2Cp8lIi2TSkKxwBZ/bTF0Hgpkwa7H8BtLGgxEcBAAA=" + } + }, + { + "ID": "35d4f766bb99111c", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon6da574a53a6ce496b84f3995d52944a8ec0beb74/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "1b7c330e26977a35e8687106f41bbaae/14325603309545735112;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon6da574a53a6ce496b84f3995d52944a8ec0beb74/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:49 GMT" + ], + "Etag": [ + "8iDuCAcnUyebmtn8Fh56aw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8pbZLqUOjsm54VWpiblluRZuGWYmiWW29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwo7Ojkr1cYCIQCbU4BjcAAAAA==" + } + }, + { + "ID": "a36b190fa15dce48", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "260" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a04915099ca7a9b89c190579c867a072/15889778823631944792;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEB2YWwiLCJxdWVyeVBhcmFtZXRlcnMiOlt7Im5hbWUiOiJ2YWwiLCJwYXJhbWV0ZXJUeXBlIjp7InR5cGUiOiJCWVRFUyJ9LCJwYXJhbWV0ZXJWYWx1ZSI6eyJ2YWx1ZSI6IlptOXYifX1dLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6Ik80RWlmeHJrN0UxSXBlYkw0bURMUVRJR05IaCIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:50 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/Y_xUBLOW1HmvoYfA4tadc_DXvZE\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2+bMBT9K5P3tQ3P8Ig0rW3CUjSUtglpl65TZMyFuAFMsCGtovz3GUKnqZqqfTM+59xz77nmgLa0iNEIRTTd1VC9fn5mETpDIHAqb59QgB+dQjUnzvd86sMyvs38WZADfphyZbV+WV4FNw/add6wVXJpChyT9eRH8+g9IVmEtoXjOiMgzktWiXPb0kfLxeDG9GjyUm1tT/NLiAIznwR3oT+dXW+kikOWBLTYSu1GiJKPFGW/3w9SxtIMcEn5gLBceetXaXSlrNgzEMGVd16KnIUrH7h9zRjBgrLiy3IhnSV9DglUUBBAowPq6/r/GOPE7pCPp3lzkETpcTxDhBUJTeuqvz20dcLXUhqiu6U3X0lNN1gL9Qe08AJvHH66aHAm4Ri4oEWnD3GU/UerMRaYwwldEydx1Eh1I82JElVPIBnaJgF1qDowVE1IrNixLQtLnWjLdypcsMK2YtuMhhHYhqvbjqvFcQSGpcVOopMkToC4xMXgdlNWgAVMKC8Zp/3847l3GXpr/9t65nkTbyIN9hV9z3qY+5IUzpezsWRLTllRJmltDv4s9OaX49C/b4GaQwApJq+LXYZGCc449Nnd4grnIKDiaPTzgAr5IdWn9Mo37BT6AYlT+Fer0OsW9Idwj7O6YzSnA3rM3QYdj7+OksUFFjVv0fbUorLjmT+boh6kckmkI3RZtMuiXRva0LBsTdcc13EM1JEr8Q5zVdVQ/34JnUkOheifyulFoLYTGUO1hhxTGQIyLMtwXcPQzOG5XLBQNZYLF+u2uyVGSlK62+y2mROxaFNfxNBAxkqoBqms0VACmBBWF6L9w9DxN0C3dW4cBAAA" + } + }, + { + "ID": "c840601eda7d1b23", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/O4Eifxrk7E1IpebL4mDLQTIGNHh?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0ebfd66f970710b3dc21158c9f8cc809/17453954342029833448;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/O4Eifxrk7E1IpebL4mDLQTIGNHh?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:50 GMT" + ], + "Etag": [ + "er15T+tJ8k+8svmSS4EYIA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PQU+DQBCF/8t4LE2KQduQ9FCUWAypFuihMcYsy0ApuyzuDipp+O8u1dPMy3wz780FmrotwIe8rj571MNNhbSfmgRNL8jY0qnWIDiAxCpLonbvshk9r5rZynzJNPXCY7RZry1h+AklA/8CZY2iMOC/XaBlEu1aufiwBA3dJIJjFqZWSlVMcneI400QhzC+jw6cVZ5giRpbjtOtTqszcoqmmEUvONK8U5rmy/tbuNLXyYsX1uWPbpahG3WYx558jPdZ9LTbniwlFGdUq9aChxSsCSliIlHfNiO48K+DgdC8asXRGJyOLv4MHpTsBJJNQ7pHBzizj25rAr9kwuD4CzJ4tAFGAQAA" + } + }, + { + "ID": "bc3df1099cfc7cc0", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon76d74b5be73927891ddbe361d8f2cfdfec9c9ae9/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0ebfd66f970710b3dc21158c9f8cc809/9048837945335754800;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon76d74b5be73927891ddbe361d8f2cfdfec9c9ae9/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:50 GMT" + ], + "Etag": [ + "On+r6qzGZEgXU04oStJrTg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8r752kXmRVWuUe5pkeEGpjkB5d4FYWk29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwpH5VqWKdXGAiEA+pepBnEAAAA=" + } + }, + { + "ID": "4c7b5ebd2866bedf", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "285" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "edc564981ea81fe965dd331a1678a574/10613013463716866496;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEB2YWwiLCJxdWVyeVBhcmFtZXRlcnMiOlt7Im5hbWUiOiJ2YWwiLCJwYXJhbWV0ZXJUeXBlIjp7InR5cGUiOiJUSU1FU1RBTVAifSwicGFyYW1ldGVyVmFsdWUiOnsidmFsdWUiOiIyMDE2LTAzLTIwIDE1OjA0OjA1KzAwOjAwIn19XSwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJyMGVyaFdZODJabWhjUEIxaXM0MGw2cFRLcEgiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:51 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/hXJFfD8QVVLKXOm-j0b9VrUDSjE\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2/aMBT9K5X3cYXYeZFEmtYO0i4rZRQCfawTcsxNMOSFY0AV4r/PCXSauqnaN8fnnHvuPdfZoxXP58hDEU/WGxAvH5ZFhM4RSJqo22fUp09Ojs2ec5NdBzCZD9Ng0M+A3l9X2uLh21Xcc+6m0/7Nw/estcSROxWT3njpPyNVhNeF55uUgWyVhZCtjq17k3FbYBCL+0dHf8oWbPiF8MrEqV2GN+VXpaogjfs8XyntQsqy8jRtt9u1k6JIUqAlr9qsyLTXfrWtrpWiWAKTlfbGS1OzVNo7bp/TglHJi/zTZKycFX0EMQjIGSBvj051g3+McWQ3yPvTvDooovI4nCNW5DFPNuJ0u6/rhC+lMkR3E3/0qDTNYDV0OqCx3/e74dnFlqYKnkMled7oQxql/9HqnEpawRGdMSd2cITdiDhRjPUYYqtjMsAWdsDCJsT23OnYNlU6WZdvVDQvctsgjmnrugUdYjBsEpMS3XUdrNiWxRgh1CDMjZspBVAJPV6VRcVP83dH/mXoz4Kr2cD3e35PGewEf8u6HwWKFI4mg65iK04peKFodQ7BIPRHl90wmNbApoI+JJS9jNcp8mKaVnDKbkgFzUCCqJD3Y49y9aHUx/TKV+wY+h7JY/hhcOuPw8vbYd3+b9KUppuGtT0ekI6J3cJGS8dnxPKw6WHrI8Yexuhw+HlQ0kpSualqSX2qJWqUQTC4RieQq+2xhtCEVG+RN/0Ry7A7RCcuwaaDGrKQf2FE1/98Io1JBrk8vaHjU0F1JyofMYOMcpUOMmzbcF3DIKbVUpuXmBSZdKnecVfMSFjC14v1KnWiIlpsLuawhbQoQbQTVWPLGVDGik0u618PHX4Bo9m3FDUEAAA=" + } + }, + { + "ID": "bf59e4c5cc75bd8a", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/r0erhWY82ZmhcPB1is40l6pTKpH?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e4c730f19af011c47f61259879438ac7/12248964001664409936;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/r0erhWY82ZmhcPB1is40l6pTKpH?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:51 GMT" + ], + "Etag": [ + "aHDwO0LNaTlseaBguNzBXQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2QyW7CQAyG38W9ghRQRatIHEiLFNSQsgTRRVU1TJyFTjLTGUcojfLudWhP3j7bv93BV1mn4MOpzL8btO1NjrQdnB26RpFjY3TtEEaAJHImRfh4efaiWCTKoQjyJv4JXrbzORNOFlgJ8DvISlSpA/+9g1pUyG2Z98kEtWYIktV6uU8W6w2nKp0OqfgQRYsgWkL/0Y/grE87zNBiLXGYZ6w+o6TVIDVtlEQaG21pfDebwpW+VqyHtji+3k/fqkJugknpbj01M8mTCZlSWgoqdc3gYQ+8hDQJtdMX1gkT+I+DltBtrJboHA5Dvb8FD7oyConVkG1wBFLwsWFJ4GeCH9H/ApqQj39KAQAA" + } + }, + { + "ID": "cbb8e389576924f1", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon631846225e713c0414a12998076655cc11a31c9f/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e4c730f19af011c47f61259879438ac7/3771791114738933144;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon631846225e713c0414a12998076655cc11a31c9f/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:52 GMT" + ], + "Etag": [ + "Gsb2sTEF0LPTqMSC0KQHJQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8q7FycZFYe4uhn4BIQU+gY7G3gHengF2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwmbmFqYWJgZmZjqGSjVxgIhAPepRzN5AAAA" + } + }, + { + "ID": "f6de461c4b7370fc", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "370" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a6f50d25dd2da5414405515f2aa5ba03/5335966628825142824;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEB2YWwiLCJxdWVyeVBhcmFtZXRlcnMiOlt7Im5hbWUiOiJ2YWwiLCJwYXJhbWV0ZXJUeXBlIjp7ImFycmF5VHlwZSI6eyJ0eXBlIjoiVElNRVNUQU1QIn0sInR5cGUiOiJBUlJBWSJ9LCJwYXJhbWV0ZXJWYWx1ZSI6eyJhcnJheVZhbHVlcyI6W3sidmFsdWUiOiIyMDE2LTAzLTIwIDE1OjA0OjA1KzAwOjAwIn0seyJ2YWx1ZSI6IjIwMTYtMDMtMjAgMTU6MDQ6MDUrMDA6MDAifV19fV0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiWWVzS0JUVzI4RllYaENCbXc4dldMTnRQcnB0IiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:52 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/hR5WiQMi_yst1sh3oAdN9suNXZk\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TbW+bMBj8K5X3cUswrwGkaUsTVqGlqCWkafeiyJgH4oVgik2iKMp/nyGpVHXTNIkPhrt7jjs9PqINqzLko5QVzy00h3e/eIo+IJCkUF9/oBn55lbYmrpftzchLLK7MoxmWyDLG6GtY3vJ7m/Z6iCkLtYmH2eRJ9ro8dvmB1JDWDc4a0sKclDzRg5GjuEv5sMnEF+vk6Xhfnl6XE+ut3t3t5xF8q6ppVIJKPMZqzZKu5ayFr6m7ff7YcF5UQKpmRhSvtVe/lfbGVrd8F9ApdDeeGkqi9D+4fap5JRIxquPi7lyVvQYcmigooD8I7rMDf8S48zukX+neXFQROVx+oAor3JWtM3l67GbkxxqZYjuF0H8pDR9sA66HNA8mAWT5OrzjpQKzkBIVvX6hKTlf/xqRiQRcEZX1M1dnGIv1d00x0YOuT2yKGAbu2BjC3Inc0eOQ5ROduN7Fal4RUc68XDquDTTDRgZnmViwzVMh2SWk4KrW5ZuZjn0KRsgEqZM1FywS/5JHIyTYBV+WUVBMA2mymDfsLesZRwqUhIvooliK07dMK5oXQ9hlATxeJKEDx3QCphBQehh/lwiPyelgEt3d6QhW5DQCOR/P6JKvSj1ub36BTuXfkTyXP44jsdd+aRpyOENloS3wTwZ396h0+nVhAdStj2t1/RvZ8PdGUAG1p0BNgcGvtJtH1s+tt9j7GOsKvov1s9T96g7IYlsRWfVnTqR6icKoxt0AZlaCdoT+ua71WB9aN02nZFu6J5h6yPUkxv5J+Z6r/euN9lCJS+Led6/PrwqvVnBljBVOTIdx/Q809Qte6DWSWKdb6VHjJG3oWZBC/a8ft6UbsrTdfs5gx2UvIZmWKgZO0aBUMrbSnb3GZ1+A+2nkVCKBAAA" + } + }, + { + "ID": "deeef56b7619c97b", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/YesKBTW28FYXhCBmw8vWLNtPrpt?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3fd5068a07c1f6fde3cfd883ee34de54/6972198637454429880;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/YesKBTW28FYXhCBmw8vWLNtPrpt?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:53 GMT" + ], + "Etag": [ + "y2wGHj8Yj2ru9YdeBZNPlw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3U6DQBCF32W8pUnlQpGkF6WibbQNUpqKxpjtMlBwYdfdQUII7+5SvZq/b86cGeCrbDLw4VQW3y3q/qpAepmSGE0ryNigZGMQHEBihSV7t3tcV15aubq9SzMM3naR6BYLSxh+xpqBP0BeosgM+O8DNKxGu5bPPy1BvZqKZLMN98lyG9lWLbOpFYdRuEzCexg/RgcqeYoxR40Nx0lPaVkhp81kNWsFR5opqWl2e+PChb5MUjRPQXJ0vYf09bwK6s77OT7vKNKKLCUkZ1TKxoKHPdgjJImJWHbWJ1zDfx30hCbSkqMxOInO/w6sZK0EknVDukUHOLPPrksCP2fC4PgLcQQQHEoBAAA=" + } + }, + { + "ID": "4f7af7919e330cee", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonc71a90b68cd12e72943028236ad46be814413dfe/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3fd5068a07c1f6fde3cfd883ee34de54/16941489448739867392;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonc71a90b68cd12e72943028236ad46be814413dfe/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:53 GMT" + ], + "Etag": [ + "1mLKPW33Jqa8Qs6yEX2WuQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8ob5vp4B4QbG3sVJloEFptVukYYhZcG2toCVZTklyTmBOWXF4OUAflFYGZ0tVIamCyDkUqGJqYWJhZmRiamegZKtTrYBGPBEACpcFRelgAAAA==" + } + }, + { + "ID": "c093d7f5a750a10d", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "285" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "2ea5c1cc76ec8755768bf54e6ca20b9b/131257759141462928;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEB2YWwiLCJxdWVyeVBhcmFtZXRlcnMiOlt7Im5hbWUiOiJ2YWwiLCJwYXJhbWV0ZXJUeXBlIjp7InR5cGUiOiJEQVRFVElNRSJ9LCJwYXJhbWV0ZXJWYWx1ZSI6eyJ2YWx1ZSI6IjIwMTYtMDMtMjAgMTU6MDQ6MDUuMDAwMDAzIn19XSwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJld0tFU0tVTkNEZDN1Zk5Senk3TWZ6TmFQTFUiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:54 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/kU1Uc3K4NaP-msKCG-mzXaXLVJY\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2+bMBT9K5P3tQnmTZCmtUpYxJKiLoE+tk6RMRfqhlewSZRG+e8zJJ2mbqrGJ+Nzzj33HtsHtGZlglwUs2zTQrP/+FzF6AKBIJncfURz8t0psTFxZsXUhyi5yf1gXgC5m3JlHakR1WdGQG4GBZ+Np4Pi5Z7cz2+/PjwiWYR1hZM2pyAGddWIgW1pbrQcwm7mLWdRMJ4kepsGi5e9fZ2+yCrzSKo45OmclWupfRKi5q6i7Ha7YVZVWQ6kZnxIq0J57VfZakrdVM9ABVfeeClyFq684/Y5rygRrCo/RUvpLOkLSKGBkgJyD+hc1//HGCd2j7w/zauDJEqP4wWiVZmyrG3Ou4euTrivpSH6FnmLB6npB+ug8wItvbk3Dj9cbkku4QS4YGWvD0mc/0erCRGEwwldUSd1cIxHserEKdZSSE3boIBN7ICJDUitxLEti0id6Mr3KlJWpY0TW7dsQyNUM5NRahhmDJbcIZYdA+hWrOspdcx+ygaIgAnjdcXZef7xwrsKvZX/ZRV43sSbSINdw96y7ha+JIULGahkS07dsErSuhz8IPQWV+PQv+2AlsMcMkL3y02O3JTkHM7Z3ZCGFCCg4cj9cUCl/JHqU3r1K3YK/YDEKfyJdAv9a6/r/jfnluRtT9qeFkjDqjXA+kDDH1TTxYaLzSHuPh0djz+PUssFES3vNN2q08hRAj+YojPI5OnRntCH1J0i6/tTTZmlqqkjQ8Mm6smN+BtzjD+vSG9SQCnOd+h0VVDXicynWUFBmEwH6Zalj0a6rhrmQJ68wGpViBHR7NGa6hnN2OZps86duIqf2ssEtpBXNTTDTNbYMgqE0qotRff00PEXn6eiODUEAAA=" + } + }, + { + "ID": "fc2601e00f130e0c", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/ewKESKUNCDd3ufNRzy7MfzNaPLU?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0df548cd7a765c6fa36af31e395b9ebf/1695433273227738143;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/ewKESKUNCDd3ufNRzy7MfzNaPLU?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:55 GMT" + ], + "Etag": [ + "Jv3y5TGyj6Ecv7fuvLmwKQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P206DQBCG32W8bZNqY0lIetED0QolLYUrY8x2mUVwYZEdIJTw7u5Wr+b0zT//jPCdVym4cM2znxab4SFDOtskQt1K0ibUqtIIM0BimSHfuuXwHL8MxcrjnSPaLih7/7xeG0LzLywZuCOIHGWqwX0foWIlmjWx+DQEDbUt9pvYiw9Hz3RKldpOmATBZht4MH1MMyjUNUKBDVYcrVzdqAI5HazTtJUcaV6rhubO6gnu9H2Cve9d/CTc7dNlK8LoNjhHcQvZKUgMJRVnlKvKgMkFzBFSxGSkemMTHuG/3g6E+tQojlqjFV38HdipspZIxg01Lc6AM/Pra07gCiY1Tr/0+AtwSQEAAA==" + } + }, + { + "ID": "5dbdfb53e6e1ba57", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon70d736742ac25d9f445be6367a67bee36b33fc85/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0df548cd7a765c6fa36af31e395b9ebf/11736780579056253031;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon70d736742ac25d9f445be6367a67bee36b33fc85/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:55 GMT" + ], + "Etag": [ + "R8872kfnOaTo3FmGLPbFsQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8oHWViYG2Wn5fknhuQbu+W6+wQkuRUH2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwobGRia6RoY6xoZhBiaWhmYWBmY6hmAgLFSbSwQAgBMLM9ChwAAAA==" + } + }, + { + "ID": "39905db0fe08a147", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "265" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "4a44d7f69fe1a14c98722a423edeead9/13300954993664389367;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEB2YWwiLCJxdWVyeVBhcmFtZXRlcnMiOlt7Im5hbWUiOiJ2YWwiLCJwYXJhbWV0ZXJUeXBlIjp7InR5cGUiOiJEQVRFIn0sInBhcmFtZXRlclZhbHVlIjp7InZhbHVlIjoiMjAxNi0wMy0yMCJ9fV0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoibnVMWUtkZVExTFgyTzdYU3RkVGlKS1hQTHVZIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:56 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/i9zWYo0Diuy_cRlfHEWtTYT0j3k\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2/aMBT9K5P3tZAXeSFNawVZlzWibQilbJ2Q49ykLiEOsQNiiP8+59FpqqZq3xyfc+6591znhDa0SNAYxTTb1VAdP76wGF0gEDiTt08owN+dQh1NnZvttQ+L5C73Z8EW8PKaK9T9tVwxdUrr45qEefrVW4poFakvxuYJySK0KZzUOQExKFklBraljxfzYVEHq5sE7rXgUb+1H+ciiei3m8e7oF5JFYc8DWixkdpnIUo+VpTD4TDMGMtywCXlQ8K2ymu/yl5Xyoq9ABFceeOlyFm48o7b55wRLCgrPi3m0lnSQ0ihgoIAGp9QX9f/xxgdu0Xen+bVQRKlx/kCEVakNKur/vbU1ImOpTRE9wsvbDTtYA3UH9DcC7xJ9OFyj3MJJ8AFLVp9hOP8P1pNsMAcOnRNnNRRY9WNNSdOVT2F1LRHBFRTdcBUR5BaiWNbFpY60ZRvVbhgBdYsh5hOaiQjSAwX2wl2XTcGU0sw0a04JWaqW6nWTlkBFjClvGSc9vNPQu8q8tb+l/XM86beVBocKvqWtQx9SYrCxWwi2ZJTVpRJWpODP4u88GoS+Q8NUHMIIMPkON/laJzinEOf3R2u8BYEVByNf5xQIT+kukuvfMW60E9IdOFPG7fzX/gDzuuWsO8OSFc1a6AaA11F5/PPs+RygUXNG05zajiy7Zk/u0Y9SOWmSEtoA2k2RtteNNOwbE3XXNPVTNSSK/EWs9QW+/McWpMtFKJ/L92zQE0nMotqDVtMZRLIsCzDdQ1DG5kDuWWhamwrXKzb7oYYGcno7nm3yZ2Yxc/1ZQJ7yFkJ1TCTNfaUACaE1YVofjN0/g03XzEwIQQAAA==" + } + }, + { + "ID": "c4da81d2da181594", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/nuLYKdeQ1LX2O7XStdTiJKXPLuY?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8a3a2faa9fcf4dfa078d6225ab4a0762/14865130507750599047;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/nuLYKdeQ1LX2O7XStdTiJKXPLuY?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:56 GMT" + ], + "Etag": [ + "gstMqM5T09OSzsi5uHQ3gQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3W7CMAyF38W7LVJhYmiVuIANiY0w6A9S0TRNIXW7sLQpjaOpq/rupGxX9pE/+xx38C2rDAI4yeJisWnvCqRwaCI0VpFxpdaVQfAAiReOLAxtL9tp4j/u4l8jp3Yd3hfhfO4II76w5BB0kEtUmYHgvYOKl+jWcv/TEdTWg3heJCunSp0N6u3A2GLJVtB/9B6c9SnCHBusBA6n6kafUdDLkDKzSiCNat3QaPYwgRt9m1SWHTcZhmOWTnazNKYska+bdM/s0VFKC05SVw48xOBMSBNXkf5xEWEM/3rZEpp9owUag8NR/8/gSZe1QnJpqLHogeDuz7UkCHKuDPZXWja2AUUBAAA=" + } + }, + { + "ID": "5b6bb190df97b1b0", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anona168c58f3d4ed39a7da999be51dac26bfc5f26f1/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8a3a2faa9fcf4dfa078d6225ab4a0762/6460015214846272975;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anona168c58f3d4ed39a7da999be51dac26bfc5f26f1/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:57 GMT" + ], + "Etag": [ + "gnFSdd7A0+l9vP6Swbgvkg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qn57kFp6SYOxpo51iWBZgFlyell2Wn29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwobGRia6RoY6xoZKNXGAiEAiQA8jXcAAAA=" + } + }, + { + "ID": "81aa72ce91ac01f5", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "270" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "034b1628f2aea602dade81e33476f1e3/8024190728932482655;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEB2YWwiLCJxdWVyeVBhcmFtZXRlcnMiOlt7Im5hbWUiOiJ2YWwiLCJwYXJhbWV0ZXJUeXBlIjp7InR5cGUiOiJUSU1FIn0sInBhcmFtZXRlclZhbHVlIjp7InZhbHVlIjoiMTU6MDQ6MDUuMDAwMDAzIn19XSwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJoMXJKV3E3a1F5alJIVkdXNmh0ZHYxb2ljN28iLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:57 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/UcYSvS3bScYvsQyHsb9FKOAaLpA\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1T226bMBh+lcm7bcP5KE1rlNCWNcvahDTq1iky5oe4IZhgQxRFefcZSKepm6pxZfhO/8Ec0YYWCfJRTLNdDdXh4wuL0QUCgTP59RlN8He3UM2xe7e9CWGR3OfhdLIFvLzhyoI8zZu5Ec/JU8MfDrc89q7vvg3xpBw+I2lCW+OkzgmIy5JV4tKxdX8xH6y16sty52weDi+z28ebpb0WSaMxShwmVRzydEKLjdSuhSi5ryj7/X6QMZblgEvKB4Rtldd6lUZXyoq9ABFceZOlyF648k7a55wRLCgrPi3mMlnSZ5BCBQUB5B/R2Tf8Rxs9u0Pe7+Y1QRJlxukCEVakNKur89dj6xMdShmIHhbB7ElqusZa6HxA82ASjKIPVw3OJZwAF7To9BGO8/8oNcECc+jRFXFTV41VL9bcOFX1FFLLMQmoluqCpZqQ2onr2DaWOtHadypcsMLRwTRxDHFipybW1djSYt2zDc/CNia6NMBubOK067ICLGBMeck4Pfc/mgXDKFiF16tpEIyDsQzYV/QtazkLJSmaLaYjyZacsqJM0to5hNMomA1HUfjYAjWHCWSYHOa7HPkpzjmcZ3ePK7wFARVH/o8jKuSLVPfTK1+xfuhHJPrhR+HXoK38N/6I87ojNP0BaZavmr5qDdT2MdDp9PMkBVxgUfOW2J5aoqx9Gk5v0Bmkcl2kI3RTaddGt72hYTuarnmObruoI1fiL8xwrD/vRBeyhUKcL01/N1BbiRxItYItpnIcyLDlZjzD0EzrUq5aqBrbCg/rjrchRkYyulvvNrkbs3hdXyXQQM5KqAaZ9GgoAUwIqwvR/mvo9AuPN0mlJgQAAA==" + } + }, + { + "ID": "52696759f1cc4da6", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/h1rJWq7kQyjRHVGW6htdv1oic7o?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d5c27c9124431f703781edaed207fb89/9588365147835520751;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/h1rJWq7kQyjRHVGW6htdv1oic7o?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:58 GMT" + ], + "Etag": [ + "6JwQW3FLeqjTlDOfjrb2Nw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PQW+CQBCF/8v0ionYBBMSD7W1VUNtoVoOTdMsy6DgwuDuUEII/93F9jTzMt/Me9PDOa9S8CHJj5cGdXd3RA7HJkLTKDa21FQZBAeQxdGS3rYN4/vnAC/FXj29ZYVOZrt2sbCEkScsBfg9ZDmq1ID/1UMlSrRr2fTHEtzVo9hvXldWlZSOancIgodlsILhe3CgoCTCDDVWEsdTtaYCJW/GlGmjJPKkJs2TuTeDG32bnFy9jS/zc9gV0frzJfZOnP66lMs5WUqRFJxTZcHDB1gTJhYqotZGBBf+9bJjNO+aJBqD49Hpn8EjlbVCtmlYN+iAFPbPdc7gZ0IZHK6UnQoqRQEAAA==" + } + }, + { + "ID": "1f0880c903f5e9e5", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon72e44abebd6f4a20b51b296395a6ac2050a8b4af/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d5c27c9124431f703781edaed207fb89/1183249850636292663;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon72e44abebd6f4a20b51b296395a6ac2050a8b4af/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:58 GMT" + ], + "Etag": [ + "3C+6UmjX12kUkUE8Xtkf3g==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8obO2ubheZmRRgaZYdmh7paRJRkpxmn29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwmbWhmYWBmY6hmAgLFSbSwQAgBifs5+fAAAAA==" + } + }, + { + "ID": "975b8efd813f8d0e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "932" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5fd02df69605e0ed174b25758d811066/2747425364722502599;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEB2YWwiLCJxdWVyeVBhcmFtZXRlcnMiOlt7Im5hbWUiOiJ2YWwiLCJwYXJhbWV0ZXJUeXBlIjp7InN0cnVjdFR5cGVzIjpbeyJuYW1lIjoiVGltZXN0YW1wIiwidHlwZSI6eyJ0eXBlIjoiVElNRVNUQU1QIn19LHsibmFtZSI6IlN0cmluZ0FycmF5IiwidHlwZSI6eyJhcnJheVR5cGUiOnsidHlwZSI6IlNUUklORyJ9LCJ0eXBlIjoiQVJSQVkifX0seyJuYW1lIjoiU3ViU3RydWN0IiwidHlwZSI6eyJzdHJ1Y3RUeXBlcyI6W3sibmFtZSI6IlN0cmluZyIsInR5cGUiOnsidHlwZSI6IlNUUklORyJ9fV0sInR5cGUiOiJTVFJVQ1QifX0seyJuYW1lIjoiU3ViU3RydWN0QXJyYXkiLCJ0eXBlIjp7ImFycmF5VHlwZSI6eyJzdHJ1Y3RUeXBlcyI6W3sibmFtZSI6IlN0cmluZyIsInR5cGUiOnsidHlwZSI6IlNUUklORyJ9fV0sInR5cGUiOiJTVFJVQ1QifSwidHlwZSI6IkFSUkFZIn19XSwidHlwZSI6IlNUUlVDVCJ9LCJwYXJhbWV0ZXJWYWx1ZSI6eyJzdHJ1Y3RWYWx1ZXMiOnsiU3RyaW5nQXJyYXkiOnsiYXJyYXlWYWx1ZXMiOlt7InZhbHVlIjoiYSJ9LHsidmFsdWUiOiJiIn1dfSwiU3ViU3RydWN0Ijp7InN0cnVjdFZhbHVlcyI6eyJTdHJpbmciOnsidmFsdWUiOiJjIn19fSwiU3ViU3RydWN0QXJyYXkiOnsiYXJyYXlWYWx1ZXMiOlt7InN0cnVjdFZhbHVlcyI6eyJTdHJpbmciOnsidmFsdWUiOiJkIn19fSx7InN0cnVjdFZhbHVlcyI6eyJTdHJpbmciOnsidmFsdWUiOiJlIn19fV19LCJUaW1lc3RhbXAiOnsidmFsdWUiOiIyMDE2LTAzLTIwIDE1OjA0OjA1KzAwOjAwIn19fX1dLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IjN1dEY1b0JjZWowYlJhamFVNlFFMmpjWjdTaSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:58 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/fC7q2PhBDm_YJYN2WEwOhGIYoGA\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKVV72/bNhD9Vwru4+KI+i0LGFbXVg2trpdKcoN0HQyKomQ6kihLlI3AyP8+krJXN8maYftgQNTde+/unXg+gntaZ8AHKS12PWkfftqyFFwBwlEh3n4FC/TFq6E18z5U85CsspsyXC4qgm7nnZZP3Z1xs3k3q9Z3v90tjdvg8PtmHt6x+eQrECRUEmd9iQkfNazlI9cx/FV8bfb8vc3eYbKFaYS2aOV8Cowt/uLGVKA6UuYLWt8L7IbzpvM17XA4XBeMFSVBDe2uMau0c73a3tCalm0J5p32REsTvXTaD9R+LRlGnLL6l1UslEV6RHLSkhoT4B/BiTd8oY0hW0V+3M1ZQSQKjccrgFmd06JvT2+Pkid5aIQg+LQKojuBUY3J0OkBxMEimCZv3u5RKcIZ6TitFT5BafkvSs0QRx0Zomvs5R5M4TjVvTSHRk5y27UwgTb0iA0tkjuZ5zoOEjgu6RUK1axOXTvPjdw1PAPbFs50x0VOZnuW7Y5zYo4zZNm6brmqy5YgTma0a1hHT/1Po2CSBOvw/XoZBLNgJgQOLX2adRuFIimJVsupyBY5TUuZSJM+hMskiCbTJPwsA31HFqRA+CHelcDPUdmRk3c3qEUV4aTtgP/HEdTiINCDe805Nph+BHwwPxaS00R+f7ztMZfR79AJrYTvqGqkL99Dk/BjECeTjzfg8fHqb0DMW1oXk7ZFD88hkyiayFEjGX5eSbicC65Lsj6NVV3PqV4rfKjjRdwg8+eLQv+t8P9difhdzOgzKnuVOTCqYyfPl+aKo6rmHBWC+wEHEJCtnU8pUOzfvPxHYvl0RmE1iafGvCD6OlV2GurrmQScrPj22V1EDag7I2iODPhGt31o+dD+GUIfQolS8xQSiPfd0KG4iQIkbtRS2TwEqVgiWCWouyqXCVVT0m3TcXVDH3uO5ahhopY/i7m2ebmplEhFan5aZcPGkvdBXtN2TSpES7ksHcccj01Tt+yRWEAc6qziY2S443tsFrigu83uvvRSlm76txnZk5I1pL0uBMeeYoIwZn3N5T8AePwLCxyWCrwGAAA=" + } + }, + { + "ID": "9cee68aea36123c4", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/3utF5oBcej0bRajaU6QE2jcZ7Si?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "52843763bbd4c9d46410e7d431d2bcfd/4383656278151840599;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/3utF5oBcej0bRajaU6QE2jcZ7Si?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:59 GMT" + ], + "Etag": [ + "rwkeEgAnYSJsFX0Jg18JQg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6VSXW+CMBT9L90rJugyXUh8QMVNo04LJvvIspRyYSBQ1l5iiPG/r+gimXMvW/rQnvace05u745s4jwgFvHj6KMEWV1FgKv6QEGVKSq9FSJXQAwCyCLNlNsNOJGdP7lTNX40p1H7drqK+n3NUPwdMkasHQljSANFrJcdyVkGWhaab5qBVVED6gwf6EjjTAQ1XqxnM3swc/TNT6UXZ6CQZUWj9yZzx/Xs+fJCib1xUroo4zyypWRVo3U9OlncNULqLB3bc0bfhKWvtSXHP0Y+Gv/u2YR9veR6lvjc+pT4v9b1MkgifAohSMg51H9XSJEAx0k9FkGZcsBWISS2et0OObAPL9cljm/EgENi+pQlbN1dOZ2EP/fcWLNSwRnGItfEtas7S1AgS6nY6qykTb7woEJQSyk4KAV1UfNoMBRZkQLqNLodYBDO9GDdx0iskKUK9p+ze/EctgIAAA==" + } + }, + { + "ID": "26eb39b66b131c01", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonb75ff2f7282c54cd167a6d584579fe39da451147/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "52843763bbd4c9d46410e7d431d2bcfd/14352947085159153567;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonb75ff2f7282c54cd167a6d584579fe39da451147/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:29:59 GMT" + ], + "Etag": [ + "iseY2ksfsAX5BXew1G30Qg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8pnFqdGGmUXpxU7Rpg6RaSWG7obGwSm29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsU7JCYioZmphamFiYGZmY6hko1eqABaFSiTC+UpJSbSyUjaw3GSSMogdZNgVJFlk8FSweCyMAOivOlvMAAAA=" + } + }, + { + "ID": "5553d2716df58925", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "823" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f20330499c19149862bab819adf918c6/15989179098066565167;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUIEB2YWwuVGltZXN0YW1wLCBAdmFsLlN1YlN0cnVjdC5TdHJpbmciLCJxdWVyeVBhcmFtZXRlcnMiOlt7Im5hbWUiOiJ2YWwiLCJwYXJhbWV0ZXJUeXBlIjp7InN0cnVjdFR5cGVzIjpbeyJuYW1lIjoiVGltZXN0YW1wIiwidHlwZSI6eyJ0eXBlIjoiVElNRVNUQU1QIn19LHsibmFtZSI6IlN0cmluZ0FycmF5IiwidHlwZSI6eyJhcnJheVR5cGUiOnsidHlwZSI6IlNUUklORyJ9LCJ0eXBlIjoiQVJSQVkifX0seyJuYW1lIjoiU3ViU3RydWN0IiwidHlwZSI6eyJzdHJ1Y3RUeXBlcyI6W3sibmFtZSI6IlN0cmluZyIsInR5cGUiOnsidHlwZSI6IlNUUklORyJ9fV0sInR5cGUiOiJTVFJVQ1QifX0seyJuYW1lIjoiU3ViU3RydWN0QXJyYXkiLCJ0eXBlIjp7ImFycmF5VHlwZSI6eyJzdHJ1Y3RUeXBlcyI6W3sibmFtZSI6IlN0cmluZyIsInR5cGUiOnsidHlwZSI6IlNUUklORyJ9fV0sInR5cGUiOiJTVFJVQ1QifSwidHlwZSI6IkFSUkFZIn19XSwidHlwZSI6IlNUUlVDVCJ9LCJwYXJhbWV0ZXJWYWx1ZSI6eyJzdHJ1Y3RWYWx1ZXMiOnsiU3RyaW5nQXJyYXkiOnt9LCJTdWJTdHJ1Y3QiOnsic3RydWN0VmFsdWVzIjp7IlN0cmluZyI6eyJ2YWx1ZSI6ImEifX19LCJTdWJTdHJ1Y3RBcnJheSI6e30sIlRpbWVzdGFtcCI6eyJ2YWx1ZSI6IjIwMTYtMDMtMjAgMTU6MDQ6MDUrMDA6MDAifX19fV0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoibkFSVDJNTkp4NWkyeThnRmplYzZxREQ4SWRyIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:00 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/xVSxA7Q3ZX4rb3U2jpgvpx1sn-A\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKVUW2+bSBT+K9X0sbEZwGCMVG2RTSO2jpUCTrfdrqJhGMgk3DwMTiwr/71nwEndOmpXuw+WGc53OTdmj+54lSIXJTzfdEzsXt/WCTpDTJIc3n5FS/LFqfBk4XwozwO2Ti+LYLUsGfl03moPV9GDN/1ofvlrIhJzbdw2+bZ50Ntq5H1FIMKVcNoVlMlRUws5mtqGu47GlRfGxsXqzweLGzsnf3/LqL1ZLJwgFcBqWZEteXUH3Bspm9bVtPv7+3Fe13nBSMPbMa1L7SlfbWtojahBQrbaT14a1NJqv3D7o6gpkbyu3q4jcAZ4yDImWEUZcvfooBu8UMaA7iO/rubJAYDg8XiGaF1lPO/E4e1e6cS7BgzRx7UffgZOX5gKHR5Q5C/9efzq3ZYU45iXrJWkbM6Gc9QlkRQdlWP441UO/BQAvOoNYpIU/6KWlEjSsiF6TZ3MwQmeJbqTZNjIWGZNJ5RhCzvMwhOW2akztW0CPKnkexap6opiyhxzpicmJYlJLNN0DDLLbJpkbEJImljYMo0k7dsgGJFswdumbvmhQfPQ92L/Onh/vfL9hb8Ag3vBf0Z9CgMAxeF6NQc0YBrBa4CpRgWr2A+9eRxcqUDXsiXLCd1FmwK5GSladmjuJRGkZJKJFrl/71EFB2BDO5XcU2yYyh7JYToRWM5jtaB9u1X0B/bzYFRffqTGwYUfxd7FJXp8PHsmDPPyhCC7U4oXhp7aBaLCp5kEq3PQOhZ7WoNTqd8l/rw3p7zB5p8Xjf5b4v87E/gdzeiKFF2PHBT7Y6vO3/vxUnDwgaftwEek7+bRDI9iBtbtETZHBn6lWy6euNh6g7GLseL0zQEDIrt2sIK1BhKs56rPeQhy+CJpD+gXX32ZvC9Zt0x7qhsGxrpp950hQp7EjKlzfC/0JiWr5OHiGO4HtVxq58U1KwmHjUembZuzmWnqE2sEX7PEel3KGTGmsztq5jTnm5vNXeEkdXLTvUvZlhV1w8Q4B40tp4xQWneVVPctevwGSMnQFyoGAAA=" + } + }, + { + "ID": "a137b434d5f2fa95", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/nART2MNJx5i2y8gFjec6qDD8Idr?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3049c2285afface4ca7cea96277a1ad7/17553072041992958143;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/nART2MNJx5i2y8gFjec6qDD8Idr?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:00 GMT" + ], + "Etag": [ + "Z/I/mbL9iGT1KbhGnP/X3w==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/22QT0/CQBDFv8t4LUEwIjbhAIJYLQTbkhiNh+12KIv7p+xOgw3hu7tFoxdPO/v292bfzBE+hC4ghFyU+xptc1EiPbdFgq6W5PxRGe0QAkBipSdfu1FX5fGtmGe9p3w716vuy9VhNPKE41tUDMIjbATKwkH4dgTNFHpbJhQ6YqryHDXVWYoWszQbL1ZeUqZopeU6jseTeAan4NeZkhW6/LOlWRIt5/953k8B7Eye4AYtao5tksqaHXKK2iGLWnKkTmUsdW4GfTjT5xc9TrL+Yvn4eS36zbC895bBfjodRoX1lDSckTDag+vURwMyxGRiDn5C6MHPfdIQupU1HJ3Dtunl9wd3RlUSyachW2MAnPk1PQiCcMOkw9MXSCwujIQBAAA=" + } + }, + { + "ID": "ce247bf9388656d6", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonc0ce8391b3cab3a53382a9f6cbfe4aadb50532bd/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3049c2285afface4ca7cea96277a1ad7/9147956744776953095;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonc0ce8391b3cab3a53382a9f6cbfe4aadb50532bd/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:01 GMT" + ], + "Etag": [ + "G5nt7AgS538pP8cn0rD2SA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8q7m+aVmDumB5saWxQEWCTnGRS5GAU72toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwmbmFqYWJgZmZjqGSjV6kAEE5VqY4EQADYEi+ODAAAA" + } + }, + { + "ID": "0913ddbbff4d4779", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "229" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "952be7a21fcf408bffe22e46d2565b0e/10712132263174841751;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7ImRyeVJ1biI6dHJ1ZSwicXVlcnkiOnsicXVlcnkiOiJTRUxFQ1Qgd29yZCBmcm9tIGBiaWdxdWVyeS1wdWJsaWMtZGF0YS5zYW1wbGVzLnNoYWtlc3BlYXJlYCBMSU1JVCAxMCIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiNzFRVkJ0UVNGb3Vha1l3eDhnU29FbU5tM3hPIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:01 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/NR8l5m3YaaAN0u0XtKuF1_Jthss\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TXXObMBD8Kx71NXaFMRjnqY5NUhpKU4ybfiTjCHHYigFhSSTjyfi/V8JkmmQ6074h7d3eaXd5QltWZegUpWy9a0Ds393zFJ0gUGStb29QSH56FR7NvcvyIoBldlUEUVgCub6Q76PYK5zS/kHINMIN/q4um3Nr9UltpLxBmkRTxZCDgIoCOn1CteD3QFVg5mVNQUH1ay5Uf+wOdXXBKVGMVxpcLtDhBFFe5WzdiO72yfAl+1pToa9LP/6he9qVDdR9oIUf+rOk98hF1ssFL3t3zw/r101aMNrPiCIDScq6ADmQG7IFWQMRcNcLg89B0rOw5s1AKla1gxOSFv+xvaGVcERX1Ms9nOJJanlpjoc55M54RAE72AMHjyB3M2/sukT3KUPfdpGKV07mERcTinHuutRx8rGTTRzHdTBxRxhcJ0tH+RCnrTwCiII5kzWXrBNuFvvTxF8F56vI9+f+XA94FOxt1XUc6KIkXkYzXa1rasG4LjMCBlHix9NZEnwzQCMhhDWh+8WuQKc5KSToyZnYx40mUqIxR6mIaqSRyHwZe+ZfIh91CNNK0hZtFzaKstIUWY7tjq3hEFu2axkluCLF2V6BvBKcgpRgVLFsezgZ2S+9/lfhH/yMFUULGk8poRv4yFT3jhMknrOZtR7rHX+9dvlv0XljdRekV0a+CBU63GoV9NySmM1zBkV2nFORVgQTVNN8jPUiiYPoQp9LnplztAzD6Vmotbzt1IQSKtX9BMeso8Oh9Ums9BCmXUK269qTiW1bI6evE6iwxUs1IcPxZEvtNV2z3Wa3LbyUp5vmQwYPUPAaxGCtOR4YBUIpbyo1oLxEh9+8Aci0IAQAAA==" + } + }, + { + "ID": "4cf26026ffc5fe90", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "266" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0b16c74c789c9ff8e9cef6a43379a2eb/12276307777261051431;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJudW0iLCJ0eXBlIjoiSU5URUdFUiJ9XX0sInRhYmxlUmVmZXJlbmNlIjp7ImRhdGFzZXRJZCI6ImRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIiwidGFibGVJZCI6InRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAxNCJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:02 GMT" + ], + "Etag": [ + "ItZEVuVpre90xZIxfzifTw==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2QUW+CMBDHv0v3Oi2wDZTEh5kQQ+J8QLYHl8VUOLATKGvL0Bm/+w7UmBiNpmmau/vf/369LVnxIiYuWfD0pwK5edBskQF5JKBZinlfz7yP6qOU0DfWM3+d/PEkrAcDVPCmL66yCHSnFFJ3HNtyY6aZAj23DLNn9E1rbtpOH49tOYZhzPGa3XbEdYX5jOYKsmTMixWOWGpdKpfSuq67qRBpBqzkqhuJnB6p6a9FSym+IdKKniHRA5Kid7DRlk3RexBbTQAJSCgiIO6WHBD8C4tB/WH8vnob5Tih1d/m2eHOoiXkrAFJOGSxIu7nlhQsR7b9g46bsommYeBPRthzqlf5qexPQm/kBWT3ha5YGW40oBsxSBuORZGGIM/TgaiPUSSBaS6KkLfm5suT7ZiWZVi202wC1iWXFwR2D7/T9GdM6TcRc/xHfMXjgBq+Dsde0yGi1hBT71Oy+wdUQAvl2AIAAA==" + } + }, + { + "ID": "68e2975d40e2649b", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "292" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9cb600ce9746530fa00e741fe4781104/13840482191869187767;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiSU5TRVJUIGRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxLnRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAxNCAobmFtZSwgbnVtKVxuXHRcdCAgICAgICAgICAgICAgICBWQUxVRVMgKCdhJywgMSksICgnYicsIDIpLCAoJ2MnLCAzKSIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiRE5hQWdpdjRVNTNscEhPZ0U3ZVI5UVZYeUhUIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:03 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/dn8_wGPTwNkMM2v8sFpq5QEdciU\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAIVTa2viQBT9KzL7oS1Y89I8hGW3bLNWarOtJu4DQSaTazo1mYnJRJHS/7430cI+a0LgMPfce86ZS57JmouEDEnM000N5f7dk4xJl4CiKZ4uyIT+cIXev3Zv89EYouQ+GweTHOjXUaUlwl3uRvfhLljf3Zlbt/pcbAYPfsJ4tCA4hDeDkzpjoC4LWapLxzaH0ax3HdCrlG/70cDKipsvqe/A1HuYf9vfhNhVQbaacLHG3kelimqoabvdrpdKmWZAC171mMy1V7/a1tSKUj4BU2jody0Ns1TaG2ofMsmo4lK8j2aojPQprKAEwYAMn8lx7vgfMQ7stvJ2mlcFJKLGS5cwKVY8rcvj6XMzJ9wXKEgeIn/6HXvaYE3pCMg4mPnTsJNQRStQS1M3XN0zzKVhOx6+tunour7Ez+gpGmfwf4bR75wLmkO3I+r8YiEWaqE6fzzzq0nkzzrnZ/Ss2zEuuohiRGaLGCLrAk0mUCku2hRho3n6wo72D9XTUbCjDdPyT8ZqrrYouSy5OtxY6E+vPoXjuY9z6gomkFK2n20yMlzRrIIX5FeKqrpqjDeo2cA0CoJxMCLHIseIrCWwEg5Red7wjIFlO4Zp6patN9GQXKq/ak7f/HWbrUgOQh3XfdgqaZygwXIJOeVoj1i2bXmeZRn9wWVsuEo3ZK48ajremlkpS/nmcbPO3FjGj/XHBLaQyQLKXooztpwBZUzWQjV/CXn5CU+g0DDgAwAA" + } + }, + { + "ID": "4f5c1124232cb36b", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/DNaAgiv4U53lpHOgE7eR9QVXyHT?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "775868119dd56669a8e5ed2a930378fc/15476714204793376327;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/DNaAgiv4U53lpHOgE7eR9QVXyHT?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:04 GMT" + ], + "Etag": [ + "fSrdidPrpeTb6WPyh0gbLg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/0WPQU/DMAyF/4u5dtLEYBOVdhisWiehsXUdICEOaepmGWkTEhdUTf3vuOOwk+O8z8/PZ/jSTQkxFFp9t+i7G4W0Gx4ZhtZQ4OJsExAiQBKKyWrvS11uvcO8mL5tu+NYFc9qPmciyCPWAuIzVBpNGSD+OEMjauSxS4mAOjd0+zxbb1bQR1e9ra/yepMnqySD/rOP4GSLDCv02EgcvJ23J5S0HmKXrZFII2c9jWbTW7jQF2W5EQulf+4O9xPj0heVzDB72L2+d2nOlLFSkLYNg4c9xwCyJMxjRxi23koMAQeT8b/hk62dQeLt5FuMQAo+NNUEcSVM4A8Ov6zNoqo4F5aZ/eXTYQL9H62Ip1pfAQAA" + } + }, + { + "ID": "b199d07119ae9c27", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "374" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "efa13cb3efaa43a27766867175f0c76c/17040889718879586263;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7ImV4dHJhY3QiOnsiZGVzdGluYXRpb25Gb3JtYXQiOiJDU1YiLCJkZXN0aW5hdGlvblVyaXMiOlsiZ3M6Ly9kdWxjZXQtcG9ydC03NjIvYnEtdGVzdC10YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTQuY3N2Il0sInNvdXJjZVRhYmxlIjp7ImRhdGFzZXRJZCI6ImRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIiwidGFibGVJZCI6InRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAxNCJ9fX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IlhWZkRSeVhBQ0kxdEhFTjVCcUNQU0lNamt3MSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:05 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/UR_0BPu14mklpxMB-TPrVztVB8k\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAK2TX2/aMBTFv4v32pA4gZAgTVuhHYtGIwQJQ1sn5DgmmPxxsB0oQ3z32Sl9GNu6PUxRJMvn3N+590Y5gZxWKRiAhGa7hvDjmy1LwA0gEmXq9hFM0Bevsrp33qdyHJA4nRZBOCkJ+jwWZjxbWcNpA7tlXtRPD0MjmvLFd7kYevkjUBCqwWlTYCKNmnFp9F17EM87y8X6bnZc3o4CKD/eh73hbjSdBw/b/ABVlSDFekKrXNVupKzFwDQPh0MnYywrCKqp6GBWmi/9mnvbrDnbEiyFeZVlqlmE+Urau4JhJCmr3sZzlazsM7ImnFSYgMEJXLjBb8Z4drfK69O8JCijyjjfAMyqNc0afrk9aU50rFUguF9Gs9tRpNf/JDnCUsuCNRyTCCXFP/SUIokEuajP55VtQc/yob2Cbt9Xj2v3LctaqVf3JzW49benP7thV3efEiFp1fYec6qqMv19rvee7AypjMZfkR0s9uCaKsDg6//gfvsJ/IHxEqmNgtF8Ac5qFCGRbES7YnXS+5/FYRiEY3ARqarFrQFz0jIiWmof7DluH9q21fNsvXVl5vIXzYe+JjWC8BUpES2U6riu4/uOA7s9I4GetCArpY/svp9jJ8MZ3W12eeElLNk071OyJwWrCe9kirGnmCCMWVNJ/QOA8w+fE0hFuwMAAA==" + } + }, + { + "ID": "dc19168fd4a67ad7", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/XVfDRyXACI1tHEN5BqCPSIMjkw1?alt=json\u0026fields=status%2Cstatistics\u0026location=US\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "25d94594f6c9bb96cb175e0c654cc0eb/10199948840566619311;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/XVfDRyXACI1tHEN5BqCPSIMjkw1?alt=json\u0026fields=status%2Cstatistics\u0026location=US\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:06 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/UR_0BPu14mklpxMB-TPrVztVB8k\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:06 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKtWKi5JLCktVrKqBrNSlayUgkL9/Dz93JVqdcBCmcUlmclgBclFqUBufl5IZi5InaGpsZm5oZGRgamFkZESWHFRCYacpaGlUm0tABW4+RloAAAA" + } + }, + { + "ID": "c30d25d07c4a8ea2", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/XVfDRyXACI1tHEN5BqCPSIMjkw1?alt=json\u0026fields=status%2Cstatistics\u0026location=US\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "25d94594f6c9bb96cb175e0c654cc0eb/11764124354669605951;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/XVfDRyXACI1tHEN5BqCPSIMjkw1?alt=json\u0026fields=status%2Cstatistics\u0026location=US\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:06 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/UR_0BPu14mklpxMB-TPrVztVB8k\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:06 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKtWKi5JLCktVrKqBrNSlayUgkL9/Dz93JVqdcBCmcUlmclgBclFqUBufl5IZi5InaGpsZm5oZGRgamFkZESWHFRCYacpaGlUm0tABW4+RloAAAA" + } + }, + { + "ID": "b75d3069db1490d1", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/XVfDRyXACI1tHEN5BqCPSIMjkw1?alt=json\u0026fields=status%2Cstatistics\u0026location=US\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "25d94594f6c9bb96cb175e0c654cc0eb/13400355263787265487;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/XVfDRyXACI1tHEN5BqCPSIMjkw1?alt=json\u0026fields=status%2Cstatistics\u0026location=US\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:08 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/azLPbMdUHVlotP6XBmgQpOUIwtI\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:08 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAGWOMQvCMBSE/8ubRZpoo8mqdqwgOolDSd8QaBNJXkEo+e++ZNTtju+4uxUSDbQkMGtVCAbO1/4CeVO9S+RspTYi2+Dvbi4h0e7UQUjZtEcpoYYj/TEtNDP04y9RSu+Z2DC/Jyy1t1IORmwbzn8oDpbK6oh8wNfhR3Sdm/AUFk/86AkCXjnnL9bh0+XCAAAA" + } + }, + { + "ID": "2a9b045adf95cc13", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "421" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6b92822f0503703936ae7f88fa8e0ce5/14964530782185153887;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUICogRlJPTSBjc3YiLCJ0YWJsZURlZmluaXRpb25zIjp7ImNzdiI6eyJjc3ZPcHRpb25zIjp7InNraXBMZWFkaW5nUm93cyI6IjEifSwic2NoZW1hIjp7ImZpZWxkcyI6W3sibmFtZSI6Im5hbWUiLCJ0eXBlIjoiU1RSSU5HIn0seyJuYW1lIjoibnVtIiwidHlwZSI6IklOVEVHRVIifV19LCJzb3VyY2VGb3JtYXQiOiJDU1YiLCJzb3VyY2VVcmlzIjpbImdzOi8vZHVsY2V0LXBvcnQtNzYyL2JxLXRlc3QtdGFibGVfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDE0LmNzdiJdfX0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiQ1lHVlRGYm1wakpFVHlkdU1jRE9CQ3pFdnpHIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:08 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/kh6oT9wVsgbRzcbCK5Vi8yGFyBo\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta6/aRhD9K1fbb1XAD/ALqWoTMIiGcFtjiNImstbrsdmL7TXeNYh7xX/vrCFNdVtFlT/saubMmXN2xi/kwOuMTEjKi2MH7eWHJ5GSNwQULTD6mazoH35tjmf++2qxhG32W7lcryqgHxfSOOxdEQfnnSzS6Jml0/fOjvuXxfzyTnwmSMI1cdaVDNSgEa0aeK492W6G00+LXTxPq+bp1zC+ZN0HNnt8N30OT88LrJJQ5iteH7B2r1QjJ4ZxPp+HhRBFCbThcshEZXzVa5xso2nFEzAljVe9DPQije90+7kUjCou6p+2G+yM8AhyaKFmQCYv5M67/A8bN3Sf+b6brx0QiD2ubwgTdc6Lrr1HXzRPfGmwIfl9G0afsKY3plP3C9mEq3AaP/z4MI8ePzwweUJQBlLxumeJaVr+D8EZVVTCLZswP/fN1AxSy09z084hd7wxA9MxfXDMMeRu5nuuS7FOafq+itaiTh3foQGjiZmPs2TMPD9Jwc2SgGVmameOa4OtffZVM8h5zbVGqfVp5XhI0bUMti3H4J+k0BN+Pbn0OFBocNCzJLZp+WZg2YnlegF+ru2ZppmYpjUeas4vuDVsDxXV7DmHMtPML6SmlX7X/kBFt1fexNFyvUCJ3/Jd9S29XMfhIozI9QuauCmdi7aiSo96s0Mgdnxs/vYkD7xZAc14XUTijCFiketVD7oFqmDGZSMkv6/ANArfxmGynCfrMJyFM2Q7t/w16mO0RFAcbddTRCOmablA2OUuL3o7jZc7negkrKCg7LI5lmSS01KCbi0VVd1NHd60K+Ra31z3IY67w24j0Sr1DvH+KSxn5HqWbZu+EzikB7fqXznPc/+5pn2TCmp13+PbuhKtBAW2CQ6Gozwyct1REIxG1tgZ4N4p0xKVCqjtBQc2KljBj/vjofRTke67XzI4QSkaaIcFcpw4A8qY6Gqlf39y/Qu75jcluQQAAA==" + } + }, + { + "ID": "0394c949cf38cbd7", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/CYGVTFbmpjJETyduMcDOBCzEvzG?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ec37aea296a94e9be061489da4468c21/16528706296271363823;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/CYGVTFbmpjJETyduMcDOBCzEvzG?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:10 GMT" + ], + "Etag": [ + "LurDmnQQBU+dFvaKJd5/Hw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/21QTU/CQBD9L+PREqNGTZpwsKV8WVFKMTHGw7I7YHG3W3dnIYXw39klJFw8zbzMe/PezB5+q1pADItq9efQtFcrpGloCrROkvWl0bVFiACJrTwzd6an6uk0mV+L/oa9jMXDzXDb7XqG5T+oGMR7WFYohYX4aw81U+hlpxIBtU1As7IYTQYeKy0Cnszz/DnJMzhEF4VTF8FoUmaDrPhP8X2IYK0XBS7RYM0x+DdGr5HTKJwmnORInUYb6jw93sGJfZqkn4OPsr9QzXqcla1wr7z3lqS7bLML0aTmjCpde+J85oMBaWKy0Ft/F9zDGSctoX03mqO1GJbenh1SrRqJ5OOQcRgBZ/47w4ogXjJp8XAEFCOVxXsBAAA=" + } + }, + { + "ID": "29cf78c149245395", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonb585a9ca_0f4d_4c78_be6d_9cd0b2d562e2/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ec37aea296a94e9be061489da4468c21/8123590999072135735;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonb585a9ca_0f4d_4c78_be6d_9cd0b2d562e2/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:10 GMT" + ], + "Etag": [ + "EanIMP5LeWxxkk3DWcREyg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8q7JuZ5+gaY+qSGV1RkZxu7hCcHuVam29oCVZTklyTmBOWXFwOVGQP5RWBmdLVSGpgsAwonKtXqQFiGSrWxIDZCLhkuZ4whlwSXMwLJxdYCAPLaUVWwAAAA" + } + }, + { + "ID": "23e628191fc275f3", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "524" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "44ca1931cfe15a926a49b5a360a01670/9687765417975173831;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJleHRlcm5hbERhdGFDb25maWd1cmF0aW9uIjp7ImNzdk9wdGlvbnMiOnsic2tpcExlYWRpbmdSb3dzIjoiMSJ9LCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJudW0iLCJ0eXBlIjoiSU5URUdFUiJ9XX0sInNvdXJjZUZvcm1hdCI6IkNTViIsInNvdXJjZVVyaXMiOlsiZ3M6Ly9kdWxjZXQtcG9ydC03NjIvYnEtdGVzdC10YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTQuY3N2Il19LCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJudW0iLCJ0eXBlIjoiSU5URUdFUiJ9XX0sInRhYmxlUmVmZXJlbmNlIjp7ImRhdGFzZXRJZCI6ImRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIiwidGFibGVJZCI6InRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAxNSJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:11 GMT" + ], + "Etag": [ + "MzLKFaiZ4mCEKK5l5KLmrw==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SUW+bMBSF/4v32sSYJdAi9WHLaBWFZhKh07Spihy4oV4AU9uEZVH++64JUaWoVSpkIften/PdI+/JRlQZCchK5C8NqN0nw1cFkCsChud4/vAvmt1x8WtUTsLZbFyMZ1Gp2ttb7BD2XtYUKZhBLZUZ+J4bZNxwDWbpOuzauWHuknn+DX6e6zuOs8TFhp3F+x1sjOIainUkqg1aPBtT64DStm2HuZR5AbwWepjKkp6o6daltZJ/IDWaniHRHknTD7DRjk3TjyB2PTGsQUGVAgn2pEeYvhEM9vf2x+pllJND13+Z54CZpc9QcguyFlBkmgS/96TiJbIdf6i4q+1ukcTT+T3eea035Wt5Ok/C+zAmhydUxcrXnQFUIw7ptpGs8gTU+XEs29MuVcCNkFUiOnE2/uz5zHUZYyPfvq2/tVBvNHjXOI69X3BtHmQmcI7sHY0eNfyZhPH8S9SpGlAVL75hthNZrUXeHE1sIlo2KoVHJWwqJLfv6fydrF4GOI8ZXMp6NEz1ljxd9Zp3UpXcIMpk8cOOrrffa+uqO9uNqCPgmajyPh5GDhhqIdMejTwuyOE/jCUrrocDAAA=" + } + }, + { + "ID": "e37032103644abf5", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "230" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3c798b0825854bbdee6e5ac03d2338cf/11251940932061383511;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUICogRlJPTSBkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMS50YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTUiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IjZ1aHFXMmVuQWJiMzZpeW1xZEdTOEZ2QW1nbSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:11 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/7LQbke9bzkn40ZvQ3B5l0y_PaSM\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAIVTXW+bMBT9K5X3NrXBfEOkacsSGqGlaUvIqlWVkG0uxA1gAiZRVvW/z9B0D93WCSFZvueec+658IS2vErRGFGe7zpojh8eBUXnCCTJ1e0DWpB7r8LWzPtWzkNYpzdFuFyUQO7mreYubukWfPpzW1n4fn9rfrULfExuyOrqASkS3hOnXcFAXtSikReuY4zXq5HTbXZ3BlQTSk2HH8tdOl95l/tJmZeqq4UiW/Bqq3o3UtbtWNMOh8MoFyIvgNS8HTFRaq9+tb2h1Y14BCZb7Y2WpmZptXfUPheCEclF9Wm9UsoKHkEGDVQM0PgJnXjDv4zxgh4q70/zqqCASuP5HDFRZTzvmtPtU88TH2sliG7XQfRD9QyD9aXTAa2CRTCNzz6eXUbXV2cpkaQFmRhY97CvG4nuuL56HMPFGCfq1UeS0AL+jdBtJZNCK3k1+Ih7+P9HPikP1YR5mYcp9qnu0QwbGWS2azHANvbAxhZkTuq5jkNU3+Bm6CKVqMCm1DJsP3EIyxLL0LOEGpafmIy4aZplRmbRIakGiIQZb2vR8lOG0yiYxEESXibLIJgFM0V+aPhb1F0UKlAcrZdThVaYuuFCwfosw2UcRJNpHH7vC10LC8gJO652BRpnpGjhWUm3ksiu7QPpT/1uFNcyXM7RqchVdGwADC77CHnZ43TbdFzdMHTddC00gBv5R80eFvB7z4NICZU8fQgv+0a9E2WwSaAkXNlDpuOYvm+aumVfqNgl1kUpfWK4/paZOcv5brPbFh4VdNN9SWEPhaihGeWKY88ZEMZEV8n+/0HPvwCfbAFD+gMAAA==" + } + }, + { + "ID": "36788212ea298ea2", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/6uhqW2enAbb36iymqdGS8FvAmgm?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3a962d2bf7d05488e74598ff00f99f2f/12888171841195820007;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/6uhqW2enAbb36iymqdGS8FvAmgm?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:12 GMT" + ], + "Etag": [ + "R8kcpFHO6JPidRqa5MjmGQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/21QwW7CMAz9F+9aDgOtQ5U4wFQKE+sggDhMO6SpKYGkaRt3U4X49yUVEped7Ce/5/fsK1xkmUMEmSzqFpvuqUDa+IahbRVZVypTWoQAkHjhmGx8EdV88Rm+r2XOav7ycdbJZjJxDCtOqDlEVzhKVLmF6OsKJdfoZH0JgLrKo+2OLdPEYW1yj9P9ajWdrWK4BQ9Fqx+CZbqLk5j9p/i+BXA2GcMjNlgK9P5VY84oaOlPy1slkAaVaWjwGg6hZ/eTsD3VhyGW0ywbhbLTdZ5sx/OfqS68szKCkzSlI+63LhiQIa6Y+XV3wQjueNYR2nVjBFqLfunz3eHN6EohuTjUtBiA4O47C0kQHbmyePsDWMjymHsBAAA=" + } + }, + { + "ID": "831124755eb34e24", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anone5bb4259_6acf_421f_b249_3ca7ddff2f4b/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3a962d2bf7d05488e74598ff00f99f2f/4410718583083450159;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anone5bb4259_6acf_421f_b249_3ca7ddff2f4b/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:12 GMT" + ], + "Etag": [ + "m0dlHNtoF+1bdbWSXdhuiQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8rnGqTkePiV5LtpGyalJIUHR6RklGYG2toCVZTklyTmBOWXFwOVGQP5RWBmdLVSGpgsAwonKtXqQFiGSrWxIDZCLhkuZ4whlwSXMwLJxdYCADij6E+wAAAA" + } + }, + { + "ID": "a96f869aae3f5123", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0015?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ee5313dafa57f55c14da8e1516826f0b/6046950591695960255;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0015?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:12 GMT" + ], + "Etag": [ + "MzLKFaiZ4mCEKK5l5KLmrw==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:12 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SUW+bMBSF/4v32sSYJdAi9WHLaBWFZhKh07Spihy4oV4AU9uEZVH++64JUaWoVSpkIften/PdI+/JRlQZCchK5C8NqN0nw1cFkCsChud4/vAvmt1x8WtUTsLZbFyMZ1Gp2ttb7BD2XtYUKZhBLZUZ+J4bZNxwDWbpOuzauWHuknn+DX6e6zuOs8TFhp3F+x1sjOIainUkqg1aPBtT64DStm2HuZR5AbwWepjKkp6o6daltZJ/IDWaniHRHknTD7DRjk3TjyB2PTGsQUGVAgn2pEeYvhEM9vf2x+pllJND13+Z54CZpc9QcguyFlBkmgS/96TiJbIdf6i4q+1ukcTT+T3eea035Wt5Ok/C+zAmhydUxcrXnQFUIw7ptpGs8gTU+XEs29MuVcCNkFUiOnE2/uz5zHUZYyPfvq2/tVBvNHjXOI69X3BtHmQmcI7sHY0eNfyZhPH8S9SpGlAVL75hthNZrUXeHE1sIlo2KoVHJWwqJLfv6fydrF4GOI8ZXMp6NEz1ljxd9Zp3UpXcIMpk8cOOrrffa+uqO9uNqCPgmajyPh5GDhhqIdMejTwuyOE/jCUrrocDAAA=" + } + }, + { + "ID": "779215f35c4c6077", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/dulcet-port-762/o/bq-test-table_20180912_1679797627000_0014.csv?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e3346174fac9ff7c478eea2358b901a9/16016241402998174727;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/dulcet-port-762/o/bq-test-table_20180912_1679797627000_0014.csv?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:13 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq3bi7pahGCBveBW-0-gi_9ZPvIEh5V_0emFpjroUkHBlLKyCC5Y0sRPhUOpG1WDlmtesGyKH4xpmZOo3Dz35iuDdWtfg" + ] + }, + "Body": "" + } + }, + { + "ID": "453f1174fc0272ff", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0014?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "05d399b385907face39188820b2e1f1b/17652472312115834263;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0014?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:14 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "090683d6b520a5ad", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "360" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f0c50be5f29471bac7b8221eb5ae1f47/770185227485979943;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTYifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:14 GMT" + ], + "Etag": [ + "6oz7GnAQpjNGuUN60FbqvQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SX0/CMBTFv0t9VbpN2WSJD6CTkOCQOZ+MIWW7jMK2jrVjIuG7ezsgGP9E0zTLvfece35ptiVLnsfEJVOerCooN2eKTVMg5wQUS7Bvi3enn3fHxcLvV8++bdxPV+vxzQ0quPbFVRqBuihEqS4c23JjppgENbEM89romNbEtJ0OHttyDMOY4DVbTcTvCtPG5RLS2ZDnS4yYK1VIl9K6rluJEEkKrOCyFYmMHqnp2qJFKRYQKUm/INEDkqT/YKMNm6T/QWw0AcyghDwC4m7JAWHww8Og/hC/n/6Nckxo9H/z7PDNojlkTIPMOKSxJO7LluQsQ7b9BzduCl09hcHA76PnNK8yeZoP/NDrewE2MhHrRuA9et3Qu/tsKSE6OQLvdhTcYf09eipEehL2RqOh1/XJ7hXPuc7tbRSggRikKYciT0Iov7YDUR+rqASmuMhD3uw325e2Y1qWeWW12/rPfSt4+YPAvsbH0v6USfUgYo6o8S87DrBhtzf0tENEzUJsPT+R3Qd/5H6qNgMAAA==" + } + }, + { + "ID": "da49f60e4cc2ab52", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0016/insertAll?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "105" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b3b8ceffbbfb1aee6012217b20ffb804/2334360745867091639;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0016/insertAll?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJyb3dzIjpbeyJpbnNlcnRJZCI6Ims3Zzc5V3ZrT3Rqc2hnM01najN6VGNoc21rdiIsImpzb24iOnsibmFtZSI6bnVsbCwibnVtcyI6W10sInJlYyI6eyJib29sIjpudWxsfX19XX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:14 GMT" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTMK04tKnHMyQlKLS7IB3KUagGmFzWCLgAAAA==" + } + }, + { + "ID": "b3a0024cc5ec8592", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0016/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "eaf27dbd4c8cb28a4118791dde166504/12375708047400704767;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0016/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:14 GMT" + ], + "Etag": [ + "RaUmEwNufD/hz5bmhot8yA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8oHJYbmupb7laa56GdUmSblZuSXWFQ62toCVZTklyTmBOWXFwOVGQD5RWBmdLVSGpgsU7LKK83JqdUBM6NjoQx06dhaIIqtBQBRX9PikQAAAA==" + } + }, + { + "ID": "3826e22588adc16d", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0016?alt=json\u0026fields=schema\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "aeb62bbbd6fd52724af6b373d30bb31a/3898535160475227719;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0016?alt=json\u0026fields=schema\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:14 GMT" + ], + "Etag": [ + "6oz7GnAQpjNGuUN60FbqvQ==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:14 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKtWKk7OSM1NVLKqVkrLTM1JKVayiq5WykvMTVWyglA6SiWVBSBecEiQp5+7Uq0OQr40txgh7+kX4uruGgQUyM1PAQkEuQa4Ooa4uiBrKUpNRugIcnX2D3IB8jGtTsrPz0EodPL393F19FOqjQXCWgCN1fK3tQAAAA==" + } + }, + { + "ID": "fd83e06e958a29fe", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "296" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ffc39c7e96ef88885aa5cf85fee15cc6/5534767169104514775;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7ImRlZmF1bHREYXRhc2V0Ijp7ImRhdGFzZXRJZCI6ImRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn0sInF1ZXJ5Ijoic2VsZWN0IG5hbWUgZnJvbSB0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTYiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6Ik5pWXVMZXBBekpPaGpLblh1djExTlNPSTlmcyIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:15 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/wOunfEE2V2-j71EPReoh36100x0\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAIVTW2+bMBT+K5X32gSbO5GmrUpYxRrRLpd2nSohYw7ECeAETLKuyn+fTVOp6rZOvFg+3/ku55gntOF1hkYo5cWug+bxw1qk6ByBpIW6fUBT+sOvsT3xr6rLCJbZTRnF0wro3WVrHK67Og9D89YcrD0S3sxArCyXYPwTPyBFwjVx1pUM5GArGjnwXHO0nA9jft9NYXvx6+v1an1Vf+/2hMTz6yjIW9XVQplPeb1RvSspt+3IMA6Hw7AQoiiBbnk7ZKIyXvwae9PYNmINTLbGGy1DZWmNd9Q+lYJRyUX9cTlXygo+gxwaqBmg0RM68UZ/ifGM7ivvp3lRUEClcTxHTNQ5L7rmdPukeRaPWyWIvi3D2b3q6YPp0umgR6J8nNW0grO8EdWZpGkJiYmJjwNiJsT1AvW5pocxTjAmrmLJoJW87mUWGv7/RBmVtIXnasL83McpDlLipzk2c8gdz2aAHeyDg23I3cz3XJeqvt5N30VrUdsZpKqDJTahTmJ7YCVpYEPi0Nx3qe07WZr2g2iASpjwditafhrReBZeLMIk+pLEYTgJJ4r80PC3qLtZpECL2TIeK3QfNaddKSfP/nXQ11FO53+PCxPF8d5ojrrMhXKitxHFi3B2MV5Et1q7a2EKBWWP812JRjktWzgqfCup7FptRZ/0dpXdOIov0anI1XZYD+gHobfEK40jjuV6xDSJg4mHenAj/6gRx3n9UnqRCmp5ekrzcBqOF0g7UQabBCrKlT1kua4VBJZFbGegNisxEZUMqOkFG2YVrOC71W5T+qlIV93nDPZQii00w0Jx7DkDypjoaqn/QHT8DXRHL/E8BAAA" + } + }, + { + "ID": "3d87866bee23faa0", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/NiYuLepAzJOhjKnXuv11NSOI9fs?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "36799562027429e4fe7095554a42be54/7098942683190724455;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/NiYuLepAzJOhjKnXuv11NSOI9fs?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:16 GMT" + ], + "Etag": [ + "gZnFGG05VYJRE1Fsczo0ZA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PQU+DQBCF/8t4pQmYqJGkB2papBKq1Da2xsN2GSi47K7soKGE/+6CnmZe5pt5b3r4LGUGPpzK4qvFprsqkF7GJkXTCjK2aCUNggNIrLBkcZSrMHRv9od1uvRWhl+Uewzmc0sYfsaagd9DXqLIDPjvPUhWo12bigPU6VFtX9MoCa2uVTbqZBfHwSJewvAxOFCpU4o5Nig5jtd0oyrkFI1Bs1ZwpJlWDc3ubq9hoqdJUh7aGHVwWW/O1ZN8a789L9luovvcWEoozqhU0oK7LVgTUsREqn5sSvDgXy86QvPcKI7G4HjU/TN4ULUWSDYNNS06wJl99bEk8HMmDA6/QeAgSkgBAAA=" + } + }, + { + "ID": "72706e31f9e8b9d5", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon4debbf0c_41a5_47e3_b94e_5af86a485dbb/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "36799562027429e4fe7095554a42be54/17140289989019239343;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon4debbf0c_41a5_47e3_b94e_5af86a485dbb/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:16 GMT" + ], + "Etag": [ + "rt92sU6r8BvpiT27bpLikQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8oXlVgaFYeaFVk4lRVkhhiZJxX4ZGYH2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsU7LKK83JqY0FQgDF6uTpbwAAAA==" + } + }, + { + "ID": "0eb9fd1da8580667", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0016?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6356051d6dbc89d1c09b0698ccd6fd28/258001804877823038;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0016?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:16 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "15d19c4358f1b16e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "213" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "da3146d26ff286106643574cb5631198/1822177318980809934;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0IHdvcmQgZnJvbSBbYmlncXVlcnktcHVibGljLWRhdGE6c2FtcGxlcy5zaGFrZXNwZWFyZV0gbGltaXQgMSIsInVzZUxlZ2FjeVNxbCI6dHJ1ZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJvOHdnQ1JOd2QySEhWZU15OVN1bVdhcGxXNGQiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:16 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/XLMiNp1azyF0mqH-085-w_D1wog\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2vbMBT9K0H72sTPOHZgbCVxW7PUbHk0e3QESb521diWI8k1Wel/n+SmMLpR9sUInXPPuecIP6I9qzM0RYQVhxbE8d09J+gMgcKFvr1FC/w9rG1/Hn6qLhPYZJ/LJF1UgLeX0vq6uGZp4+Bfxwu7OlwN7XA87HZzp+PFLdIizAhnbUlBDRsu1HASuNPNasTDrpgt0y5zr65u4PoYrdpqi5ty62d6SkKZL1i917N3SjVyalld140KzosScMPkiPLKetnXenCtRvB7oEpar7wsnUVab7h9KDnFivH6/WalnTV9CTkIqCmg6SM66Sb/iPHM7pG307w4aKL2eDpDlNc5K1pxun00Outjow3Rl028/KZn+mAGOh1MJXqPQcdFNsgFrwY/XuIPm5aUjA4zrPBU4qopQY7kHd6DbAAL+DkoWcXUwNGyGUjF6t53jUn5HxGNqoRndEfDPLSJHREnJLnt5pCPJz4Fe2yHMLZ9yIMsnAQB1nPKyPdTuOa14xNCbD8AF4Ofe3gcEdclNNKfwPdI7oZulgH1+nYEYAVzJhsu2am32TI+X8e75GKXxvE8nmuDTrDXrO0y0aT1cpPONFtzGsG4ppn+knQdL89n6+TGAK2EBRSYHleHEk2VaOFJO0uFVStNJ+ZknkNLpUl6iU4g0+3RntAvaVpkleE5Yy+YOK7rBBPPRj1ZqL+w0HP/fNrepIJand5+FS/i2RqZTfR+YgcVZno75AWBF0We5/jjoW5e2Q6vVITdSbSnXkELdrg77MuQcHLXfszgAUregBgVWuOBUcCU8rZW5pdBT78BfkmBYu0DAAA=" + } + }, + { + "ID": "f8bcb74c607f9fd1", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/o8wgCRNwd2HHVeMy9SumWaplW4d?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7e2fb13ee392e829c990597e7caa9a96/3458409331888221534;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/o8wgCRNwd2HHVeMy9SumWaplW4d?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:17 GMT" + ], + "Etag": [ + "YWl+C83epwapb7YwQhL6TQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2Py27CQAxF/8VdNiwgiEckFiWqClKKmoSHUNXFMDEhdBJPZxxFEeLfO0O7sq987Ht9g++qKSCCU1X+tGj6pxI59U2GtlVsXdHUWIQAkEXpyONBPcezEHUn9Gl67NJLMtmmi4UjrLxgLSC6wblCVViIPm/QiBrdWkemcAj32qt8m603b07XVHi92SXJyzJ5hfvXPYArnTI8o8FGor+mDV1R8toHLVolkQeaDA+mkxE86MeEZl0ZZ5uuGK1We3zv53lbH4RWh7E3ViQFV9Q4cJeDM2FioTLqXEoYwr9e9oz2w5BEa9EfHYbhaD4O/2xiqrVCdpnYtBiAFO7hVcUQnYWyeP8F9qvgGU4BAAA=" + } + }, + { + "ID": "775419735b9d9d73", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "214" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9625f9e0a0d491f2c4da8285d890d864/5022583746496357870;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0IHdvcmQgZnJvbSBbYmlncXVlcnktcHVibGljLWRhdGE6c2FtcGxlcy5zaGFrZXNwZWFyZV0gbGltaXQgMSIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiWFdwSGF3aE9PUW9SYWs4VElWMW9yMmppY21ZIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:17 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/xNTOCvvXzEJMcuiBCAU43gPq0Hk\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAN1T7U7bMBR9Fcv7SxPSQD8iTRuDCrp1LfRjsLXVcJybxNSxU9tp6VDffXZWNG1DPMCk/LDuOffcc+ybJ7xiIsERjlm2rkDt3jzIGB9hMCSz1QUekG8dcXxy0flUXPZhllzz/nBQALm91P7jcDo632zufvQ+fqYV+3B+NjsJs+v18dVqga0Ic8JJxSmYRimVabRbzWg28e5uyyuyzUejGzkmq860/yWQqvnAaPHVdmng6YCJle3NjSl15Pvb7dbLpMw4kJJpj8rCf/brb5p+qeQDUKP9v2b5Nov2X5n2jktKDJPi7WxiJ1v6GFJQICjg6AkfdPsvxPjFrpHX0zxPsEQ7Y3+EqRQpyyp1qD45nemutAPxzaw3dj11MAcdDu5KrA+0lSpBqZIFmj/Hb5RVzBltJMSQSJOi5KA9nZMV6BKIgiXirGAGBVa2VEwqZpxgfzjtjc/OrdeeBSoNA8gI3U3WHEcp4Rr21qk2xFTa+XAnZ/BiNHR8UEqqMeiKG4cqILoOyMSGcJbc1K7/iL4+lArQmmROarIThjyiWipCMwGPpY0ICVrg+QIjYtA8iILO0kP9FJmcaWQ/ggyJOSCWgDAsZaCOEGhKSrAUQIIUgLbM5Oje1r3MQ/c133PAPbJXnoOyTCLQ/Dew9Nyz1EZs2Pl/kWd5eD6mDaP1E1KbypmfssLZDU7DVjtoNoN2O2zhmqzMv1jL7Q2I5EVkX2+O+g4FYXZvcNhqhd1uGAYnp4046JjjQBamS5rt7oqGGc3YOl+veCeWcV69T2ADXJagvMxqbBgFQqmshHF/N97/BBGU0rmYBAAA" + } + }, + { + "ID": "b8467cf5424675a6", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/XWpHawhOOQoRak8TIV1or2jicmY?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "68f00977cf36f4019058888427b39293/6586759260582567550;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/XWpHawhOOQoRak8TIV1or2jicmY?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:18 GMT" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/9WQzWrDMBCE736KRecgEuih+BZoKYY00J/04ph6Y20cgS250qZNCH73SoqheYWCQMzMp2W0lwxAkHPWiRwuQQTZWEVB3c3ns6vRk/fYRk+8nQ3jCdKLHDaGTgM1TAq2otwKQIZykS/uKwnFHvigPYSDwLjrCLQiw3qvyc2AfIMDBYTAYE/wo/kAdfBlK6FOvIxBDQ4D5AKJBsq/oJJiqpfK+NCuTBqmf/yD6qmisj1qExu2nd1hd5s5Qm9Tps03dlq9HMmdb4nONsj6ygzownQm5+WXmJAx3dW0Ks/Ix7gqUaw/lqvi4XP5+rR5fly/R37MxuwX442FphECAAA=" + } + }, + { + "ID": "f4ea12b0833e696a", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "214" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b81c9ba6a9f4b21bb2c56eff9433be9b/8150934778980455950;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0IHdvcmQgZnJvbSBbYmlncXVlcnktcHVibGljLWRhdGE6c2FtcGxlcy5zaGFrZXNwZWFyZV0gbGltaXQgMSIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiV1UxbFZ1dDVKTXh5WXdrTlB3Q2x5OFdZakJjIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:18 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/31YezV_bOQU2z4nF-5XoA8DsMIc\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAN1T0W7aMBT9Fct7LUlDCg2Rpq1ru4mN0hZIOwaodZxLcHHsYDtQWvHvszOqaVvVD5iUB+uec889x755xksmMhzjlOWrCtT23YNM8QEGQ3JbneIe+RGJw6Oz6FvxpQtJdsW7/V4B5PaL9sNgDE83d+nlddJ8OhKfG63v8iQ60xddOsVWhDnhrOIUTKOUyjSO2804GXq3ScBvKtP6evG4HW+W/avNKd9Gt+OHT9R2aeDzHhNL27swptSx7282Gy+XMudASqY9Kgv/xa+/bvqlkg9Ajfb/muXbLNp/Y9oHLikxTIr3ydBOtvQBzEGBoIDjZ7zX7b4S4xe7Rt5O8zLBEu2M3QGmUsxZXql99dnpjLalHYivk/PB2PbUwRy0P7grsT7QRqoMzZUs0OQlfqOsUs5oIyOGxJoUJQft6QVZgi6BKJghzgpmUGBlS8WkYsYJdvuj88HJ6ah7c26BSkMPckK3wxXH8ZxwDTvrVBtiKu18uJMzeHbZd3xQSqoB6Iobhyogug7IxJpwll3Xrv+IvtqXCtCa5E5quBWGPKJaKkaJgMfSRoQMTfFkihExaBLEQTTzUHeOzIJpZD+CDEk5IJaBMGzOQB0g0JSUYCmABCkAbZhZoHtb93IP3dd8zwH3yF75ApRlEoEmv4GZ556lNmLDTv6LPLP98zFtGK2fkNpUzvyIFc5u0Arbx0GzGUTNqI1rsjL/YGHgFh1E9iqyqzdH3UFBmN0bHLbbYacThsFRq5EGkTkMZGE6pHncWdIwpzlbLVZLHqUyXVQfM1gDlyUoL7caa0aBUCorYdzfjXc/Aeoo4Z6YBAAA" + } + }, + { + "ID": "0f83b3f78836957b", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/WU1lVut5JMxyYwkNPwCly8WYjBc?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7bebdb93a069147050ed889215cb957a/9787165688114892446;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/WU1lVut5JMxyYwkNPwCly8WYjBc?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:18 GMT" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/9WQzWrDMBCE736KRecgEuih+BZoKYY00J/04ph6Y20cgS250qZNCH73SoqheYWCQMzMp2W0lwxAkHPWiRwuQQTZWEVB3c3ns6vRk/fYRk+8nQ3jCdKLHDaGTgM1TAq2otwKQIZykS/uKwnFHvigPYSDwLjrCLQiw3qvyc2AfIMDBYTAYE/wo/kAdfBlK6FOvIxBDQ4D5AKJBsq/oJJiqpfK+NCuTBqmf/yD6qmisj1qExu2nd1hd5s5Qm9Tps03dlq9HMmdb4nONsj6ygzownQm5+WXmJAx3dW0Ks/Ix7gqUaw/lqvi4XP5+rR5fly/R37MxuwX442FphECAAA=" + } + }, + { + "ID": "3c467de0598a7e3a", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "213" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "33a3571aee83b2c22bc0d99ccbf788e5/2945944438615032694;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0IHdvcmQgZnJvbSBgYmlncXVlcnktcHVibGljLWRhdGEuc2FtcGxlcy5zaGFrZXNwZWFyZWAgbGltaXQgMSIsInVzZUxlZ2FjeVNxbCI6dHJ1ZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJKdjJ6WmpQbVJpdGoxSER0N0szSlNFMDE1c1IiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:18 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/W0hW9-lTqBlLEPxcadSygweHJEM\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAO1S627aMBh9lcj7s0lNQpIWSKRpt6KWlnaUy6r1otVxPoLBsYPtwBji3WenIK0b6hPsn/VdznfO8dmgOeUZSlBK80UFcv1mJlJ0hEDj3FQfUA/ftXnj+LR9WZx1YZz1Wfe6VwC+PVP+bWN6G7tstPjMep3+T4Kz4TpfwflF5+oBGRBqgbOKEdBuKaR2W80wGQ+9i2X4627WLwZUz4LzU926jC6GnUZwogZmSwGb9Cifm92p1qVKfH+1Wnm5EDkDXFLlEVH4e77+MvRLKWZAtPL/uuUbLcp/5doHJgjWVPD346G5bMYHMAEJnABKNmiH2z0g43m67ryuZn/BDJob2yNEBJ/QvJK76sbijNalOYhuxp3Bd7NTC7Ot3cNaYng4KyEzZyJF4Tzt5btllTJK3Axr7ClclAyUp6Z4DqoELOHJYbSg2gkMbCmpkFRbwO71qDP49GXU/dYxjUpBD3JM1sMFQ4mWFWwNUaWxrpSlYV+W3+nXazsOUgo5AFUxbbsSsKr1Ub7EzPz5C9EHmSaHmJq9ApTCuT3VfcZyNE4ZOBwXkBwWfRDqgd+P5NqpFOW5Y9jzDBvnhjc95+0+UoSJKtuF6mWgMkGUL/c58PfrrlowH7jhY0DdP6vvHj37sbUtxq/7/5Y8W/K4CxFVmpI6SMQYY00Y0cIqCk6iZisIw6AdN45RPSz1v70wtqHj2cHOto6v/AEFpia8KGo2oziOouD4xE2Dtm4EotAxDlvxnEQ5yeliupizdirSafUxgyUwUYL0coOxpAQwIaLi2spH29+WgAqXHQUAAA==" + } + }, + { + "ID": "7258db3d41f3e446", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/Jv2zZjPmRitj1HDt7K3JSE015sR?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "309877ab5a6bef18efc169f339190369/4510118853206391814;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/Jv2zZjPmRitj1HDt7K3JSE015sR?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:19 GMT" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/92QzWrDMBCE734K4VMLtZVDT74FWkogDbRNe0lDs5a2iqh+HK1cCMHvXllxIM/Q0zIz2kHfngrGSgzBh7JhpySSFF5iUvez2d3ZsEgEavTKhfsFoyWL0BpkDiw2bNdqdegxHKuub40WlYQIDYHtDFJNe/hB6hAC7j7dZh2OrCftFKMITkKQ7O1lyW72MXbUcC6M72WtvFcGa+Etv5Rz6QXxgN8Y0Ankl/WKDoajS/9JpdW1e7uty4kgE1IC2GTNJtT/QZcppLeg3QihjG/BXGcBgXzO9BmwnLIhz+10pNQee8p3WH3Ml4uHr/nr0/vz42o9vh+KofgDBW7y0y4CAAA=" + } + }, + { + "ID": "023fa9f1941efee2", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "214" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6d45b40b450ffd6a0784ba7351a460dc/6074294367309378710;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0IHdvcmQgZnJvbSBgYmlncXVlcnktcHVibGljLWRhdGEuc2FtcGxlcy5zaGFrZXNwZWFyZWAgbGltaXQgMSIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiMU1FUHBLdEV6dTNha1V2eEllZmhJYzFHYmhZIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:19 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/Hs8iL-nuIwWSeKmihHcgQn3qXr0\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TW2/aMBT+K8h7LeR+Q5q2CjIalaIWwrpNlajjnASXJA62A+uq/vfZKZWmbqr2Zvl857tZfkI72uRojDJa7jvgjx8eWIbOEEhcqts7NMc/wsZ0p+FlPUtgnV9XyWJeA76dCeNChHQ+bLrkeLuCy5puL0h50zj7b9y8Q4qEauK8qwjIYcu4HAa+PV6vRtZVfN1eyvhX5+Dd+vAzgWKbEGuWbb+rLQFVMafNTu1upWzF2DCOx+OoZKysALdUjAirjVe/xsE2Ws4egEhhvNEyVBZhvKP2qWIES8qaj+uVUlbwJRTAoSGAxk/oxJv8I8YLup+8n+ZVQQGVxvMZIqwpaNnx0+2T5kkfWyWIbtbxUu/0wfTodNCVKB+DI+P5oOCsHty/xh+2XVZRMsyxxCOB67YCMRJbvAPRAuZwP6hoTeXAUrQ5CEmbXjfFWfUfETWrgJfphoRFaGZmlFlhVph2AYUXuARMzwzBM10o/DwMfB+rPanp+y3csMYEP7NN18+DwnW8ws4icALILXAy0zJtO3DCwHWDom+HA5YwpaJlgp56myzj8zTeJF82iziexlMlcOT0Lep2mShQulwvJgqtMC2nTMF0f8kijZfnkzT5qgedgDmUmDyu9hUaF7gS8KykhcSyE7oUfdLvobgWyWKGTkOq6iM9oHepa6S1xlme4weWbVuRa3moB3P518yz7T/fthepoZGnx1/F83iSIu1EGeQbqDFV9pDj+04UOY7lekNVvTQtVssI20G0I05JSrrf7ndVmLFs233O4QAVa4GPSsVxoAQwIaxrpP4z6Pk3r73TvO4DAAA=" + } + }, + { + "ID": "31d20df69d1a0f01", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/1MEPpKtEzu3akUvxIefhIc1GbhY?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d10cd8b8356b67c389d47beca29f5016/7638469881395588390;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/1MEPpKtEzu3akUvxIefhIc1GbhY?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:20 GMT" + ], + "Etag": [ + "Q8wlAlr+gyk/qvSOA9M7Nw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PT2+CQBDFv8v0WE2jNLWSeMCGWFK1CuXQND0sy/BHFhZ3ByklfncX2tPMy/zem5keiryKwYYoT88Nqu4uRToOjY+6EaRNqWWlESaAxFJDHp9b4Qh1n3bFw/kSvDvL3WLfrlaG0DzDkoHdQ5KjiDXYXz1UrERja6WKDUJdPajgw/f2G6NLGQ96H263znrrwvX7OoGTjHxMUGHFcUirlTwhJ284NG4ER5rWUtF08TSHkR4ns517qN/I/W0sVoSXHw+TzOOzTZR9GkpIziiXlQHDAMwSksSEL1s9WOFfrztCfVCSo9Y4hlrWfPlo/a15kWUtkMxNpBqcAGfm4decwE6Y0Hi9AS8IpxVOAQAA" + } + }, + { + "ID": "a9b6728427c56b81", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "214" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "665e360e6fd26801bf8c3168842de20f/9274700794824926646;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0IHdvcmQgZnJvbSBgYmlncXVlcnktcHVibGljLWRhdGEuc2FtcGxlcy5zaGFrZXNwZWFyZWAgbGltaXQgMSIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiQnhJeWx3eHB2WVlJOE9YdkVaYkJMbnV6RWdrIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:20 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/YmV1zYvvdw3jgFIOe07WQfP7Xic\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TW0/bMBT+K5X3Shvn0iStNG3QBhStKtALUIRUHOckNU3iNHZSCuK/zw5FmtiE9mb5fOe7WX5FW1bEaIgilu5qqA7fnniEThBIkqrbBzQh936BnbH/K78IYRlfZeF0kgO5vRDGKr8xX1ZNE+/tp/Q8vATs3V4nV94dow9IkTBNHNcZBdkteSW7nmsNl/Pe2XN4yPbPZbNahf7lXRPcR2eTon4J0q3aEpAlE1Zs1e5GylIMDWO/3/dSztMMSMlEj/Lc+PBrNJZRVvwJqBTGJy1DZRHGF2o/Mk6JZLz4vpwrZQWfQQIVFBTQ8BUdecN/xHhHt5Ov03woKKDSeDtBlBcJS+vqePuqeRaHUgmi62UwW6mdNpgeHQ+6EuWjs+dV3EkqnnceP+J3yzrKGO3GRJKeIHmZgeiJDdmCKIFU8NjJWM5kx1S0MQjJilZ3QaLsPyJqVgHv0zX1Ex9HeBCZfpRgK4Gk7zkUcB/70McOJG7se65L1J7U9O0WKXiBwY0s7Lixlzh2P7GiAdgexCbYETaxZXm27zmOl7TtVEAkjJkouWDH3kaz4HQRrMPz9TQIxsFYCewr9hl1OwsVaDFbTkcKrTBlxbiC6f7C6SKYnY4W4Y0e1AImkBJ6mO8yNExIJuBNSQtJZC10Kfqk30NxTcPpBToOmaqPtoDWpa6R5Rpn9m3XMy3Lwr7poRZcyb9mA2z9+batSA6FPD7+PJgEowXSTpTBag05Ycoesl3XHgxs23T6XVW9xCbP5YBY3mBL7ZSmbLfZbTM/4tGm/hlDAxkvoeqliqNhFAilvC6k/jPo7Te1viMo7gMAAA==" + } + }, + { + "ID": "c5bd5ebb96aa927d", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/BxIylwxpvYYI8OXvEZbBLnuzEgk?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f7c6ba6976b450f6236b8a300ae862a7/10838876308911136326;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/BxIylwxpvYYI8OXvEZbBLnuzEgk?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:21 GMT" + ], + "Etag": [ + "2kXaAJI11mlHQ57JvCTuGw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PUW+CMBDHv8vtVZNhsrmQ+CCGKIa4iZrolj2UcjKktKw9QEb47hbdU++X+/Xufx3kmUzAhThLfyvU7VOKtB2KCE0lyNinVNIgjACJpdac5Ec2XweOU4jV9mW6rhf7atnMZtYw/AcLBm4H5wxFYsD96kCyAu23RunEKtSWA+32UbBZWi5UMvDmEIZzL/Sh/+5HcFFxhGfUKDkO00qtLsgpGIImleBI41JpGk9fJ3C37x3vGrSiuZb16RS8vR9r/zP2Qln9+WluLaE4o0xJKx52YJeQIiYi1diU4MA/ey2h+dCKozE4DH1+LFioohRINg3pCkfAmT11ldGD+xt5cGxpRwEAAA==" + } + }, + { + "ID": "3cfffc230c90c523", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "360" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "23354b91a6cc2048c171664bb1a34615/3997935430614946334;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im1vZGUiOiJSRVBFQVRFRCIsIm5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifSx7ImZpZWxkcyI6W3sibmFtZSI6ImJvb2wiLCJ0eXBlIjoiQk9PTEVBTiJ9XSwibmFtZSI6InJlYyIsInR5cGUiOiJSRUNPUkQifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTcifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:21 GMT" + ], + "Etag": [ + "782tfXljAlYhYkNUnBzK+w==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Rb0/CMBDGv0t9qdCt6oZLfAGyGCKCGTORGEPKdoxKt861OJHw3b0NCMY/0TTNcnfPc88v3ZosRBYTj0xF8rKEYnVk+FQCOSFgeIJ9t8XM7EE+t+V4Pl4M7rPO+81xeXmJClH54qWMwDRyVZiG6zAv5oZrMBNm2S3rwmYT23Ev8DjMtSxrgtdu1hG/K2wXl2uQs77IFhgxNybXHqVlWTYTpRIJPBe6GamU7qnpK6N5oZ4hMpp+QaI7JE3/wUZrNk3/g1hrAphBAVkExFuTHULvh4dB/S5+O/0bZZ9Q6//m2eCbRXNIeQUyEyBjTbzHNcl4imzbD25c5VU1CoPe4Bo9h/ky1Yd5bxD6136AjVTFVSPw7/x26Hc/WwqIDo7AvxoGXay/R0+VkgdhZzjs++0B2TzhOalyOysDaCAWqcu+ypIQiq/tQJX7KiqAG6GyUNT77fNTx7UZY/aZW/0XeMtF8YPAaeFjVX7JtblVsUDU+JcdO9iw3en7lUNF9UJs3Y/I5gODAaFeNgMAAA==" + } + }, + { + "ID": "0967dc2b7f67c4c9", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "221" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "cfa2c3679803ffb05afe9200964df9b1/5562110944701156270;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X3ZpZXdfMCJ9LCJ2aWV3Ijp7InF1ZXJ5IjoiU0VMRUNUIHdvcmQgZnJvbSBbYmlncXVlcnktcHVibGljLWRhdGE6c2FtcGxlcy5zaGFrZXNwZWFyZV0iLCJ1c2VMZWdhY3lTcWwiOnRydWV9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:21 GMT" + ], + "Etag": [ + "0JrMjzAGe5joXnrlJbcSDg==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1RW0vDMBT+KyO+uqWtuEvBB3VFJlOwmxeQUbL0rMuWNjVJLXPsv3tSNxFRlJCH75yT75KzJWtRpCQkc5G9VKA3R5bNJZBjApZlWPeu9c3q7fwKTlfqqdDyes4nw+zsDCeEe5dWkoNtl0rbdq8bhCmzzIBNAs/vewM/SPxub4CnG/Q8z0vw+h2bvAqoEw85DMjFWBRrZFpaW5qQ0rquO5lSmQRWCtPhKqcHc/Q1oKVWK+DW0G/KdK9s6D8s0CaloV+cNJUYFqCh4EDCLdkrjX6IifN7lY/u34oHhWb+U3aHP8CXkDOntxAgU0PC5y0pWI4WSK106h5uSocm03h0e4U4V6nDcXR3P4qjIdnNkKeo8ouNBeN2Rho4VkU2Bf29HKv6gLgGZoUqpqKR809Puj0/CAK/7/exLZmxNyoVaCz9ZWRv7WEUPSJyqVySZlnOcTSOLqctF6O10CpvPR822S6ruRS87X4uNCwvcRsds2RrMCUwDTNkqwyMIWN8M3mRJLS6AowpFW8sI/v9hOzeAdigPRzAAgAA" + } + }, + { + "ID": "554cf7cc44337d68", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_0?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b9d14feeed84c5157fe01c62e56789c1/7198342953330443070;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_0?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:22 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "dada705b48c0ce01", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "222" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9ba407d5f4819da4303e343e735724bd/8762517372216704206;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X3ZpZXdfMSJ9LCJ2aWV3Ijp7InF1ZXJ5IjoiU0VMRUNUIHdvcmQgZnJvbSBbYmlncXVlcnktcHVibGljLWRhdGE6c2FtcGxlcy5zaGFrZXNwZWFyZV0iLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0K" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:22 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:22 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAM2PwWrDMAyGX0XoHEwLOwy/QY+j3SkNRI3VVODYme2tDSHvPiU9dI8w0EF8/4fQPyOnFBPa+blktPWMLg4kAS32Pl7IY4WJKceVSPghL+7jm9OkfOCcqWcNjlMo9IDtioXPwI+Ru8IOzlifEahAvbf798bA4QrlJhl0CApdPIM4DkWuwqkCzh2NrApDoIHhLuUGrXLTG2g336xBC4lUSmpSgPoVNEYf87GjIjGcpnH9Lq7mH6zoa6uwNBV20anzttv92z7L8guRf3+WqQEAAA==" + } + }, + { + "ID": "0bfff11c217617ae", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_1?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "af4d09f15c927ae0686145599607d01b/10326692886319690846;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_1?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:22 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:22 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAALXNQQqDMBAF0KvIrLUkQbTmAF121V0pYTRTEaJTkrFdiHdvpGcow4fPW/zZgGLkCHb7lQT2voHnGacFLIyBewxQQiRMfMjCcuF18dlmSglHynhlKZ6H2uKGfaDCr2EgqV4cpWobYz0KJhJnlD6rThunm7bL15hWKeVy9Ence6KP07A/ShjY5+Fa1X98s38Bi7Csr/0AAAA=" + } + }, + { + "ID": "c9693635cab45831", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "222" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "870ab24ba63aa7e142f9f1c55858e53a/11890868400405900782;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X3ZpZXdfMiJ9LCJ2aWV3Ijp7InF1ZXJ5IjoiU0VMRUNUIHdvcmQgZnJvbSBbYmlncXVlcnktcHVibGljLWRhdGE6c2FtcGxlcy5zaGFrZXNwZWFyZV0iLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0K" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:22 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:22 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAM2PwWrDMAyGX0XoHEwLOwy/QY+j3SkNRI3VVODYme2tDSHvPiU9dI8w0EF8/4fQPyOnFBPa+blktPWMLg4kAS32Pl7IY4WJKceVSPghL+7jm9OkfOCcqWcNjlMo9IDtioXPwI+Ru8IOzlifEahAvbf798bA4QrlJhl0CApdPIM4DkWuwqkCzh2NrApDoIHhLuUGrXLTG2g336xBC4lUSmpSgPoVNEYf87GjIjGcpnH9Lq7mH6zoa6uwNBV20anzttv92z7L8guRf3+WqQEAAA==" + } + }, + { + "ID": "e26ef9bbf848cfd4", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_2?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a2729d74bcb15e7d8a5cfd282a1b5046/13527099309540337022;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_2?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:23 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:23 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAALXNQQqDMBAF0KvIrLUkQbTmAF121V0pYTRTEaJTkrFdiHdvpGcow4fPW/zZgGLkCHb7lQT2voHnGacFLIyBewxQQiRMfMjCcuF18dlmSglHynhlKZ6H2uKGfaDCr2EgqV4cpWobYz0KJhJnlD6rThunm7bL15hWKeVy9Ence6KPM7A/ShjY5+Fa1X98s38BKwEyd/0AAAA=" + } + }, + { + "ID": "1e67800a6b2326c4", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_3?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9ec935e497670141ca4d61fce8f49972/6685878060040477270;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_3?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:23 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:23 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAALXNQQqDMBAF0KvIrLUkqWjNAbrsqrtSwmimIqROScZ2Id69kZ6hDB8+b/FnBYqRI9j1VxLY2wqenzjNYGEM3GOAEiJh4l1mljMvs8/2pJRwpIwXluKxqy2u2Acq/BIGkurFUaq2MdajYCJxRumT6rRxumm7fI1plVIuRx/EvSf6uCNs9xIG9nm4VvUf32xfdGyXif0AAAA=" + } + }, + { + "ID": "a231a3766f31c664", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "221" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "c7ef93bc9d0f6245c6a74540cf12ba8b/8250052478943515366;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X3ZpZXdfNCJ9LCJ2aWV3Ijp7InF1ZXJ5IjoiU0VMRUNUIHdvcmQgZnJvbSBgYmlncXVlcnktcHVibGljLWRhdGEuc2FtcGxlcy5zaGFrZXNwZWFyZWAiLCJ1c2VMZWdhY3lTcWwiOnRydWV9fQo=" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:23 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:23 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAANXQwWrDMAwG4FcxPm3QxD3s5DcY7DLWW1eoYmuOmW2lkjMIIe8+l1LocdfdxAf6+aVVIzOxtuttEG2Pq/aUIRZtdUg0QNI7zQhCV4nlB1L0jTKKQMBmrzdTFYaEqkBGq85DDJcZeemmeUjRdR4qWIE8JZReRvhGmRAYz5/leOBFzRJLUFKheGCvPt7f1NNY6yTWGJdo9n0gCgl7R9ncw40nJ4bxCxmLQ3Nf7+SSDJbWp4V2j/p86lv3RA5qpHJYpusBVEfkB2709/56O+20I9+CXvb7//yXbfsFV1U0dg8CAAA=" + } + }, + { + "ID": "90c2e69e0393f3d4", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_4?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "fb16fa75e3fc5a0ee3cd9ab6d588178f/9814227993029725046;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_4?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:23 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:23 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAALXNQQqDMBAF0KvIrLUkQbTmAF121V0pYTRTEaJTkrFdiHdvpGcow4fPW/zZgGLkCHb7lQT2voHnGacFLIyBewxQQiRMfMjCcuF18dlmSglHynhlKZ6H2uKGfaDCr2EgqV4cpWobYz0KJhJnlD6rThunm7bL15hWKeVy9Ence6KPq2F/lDCwz8O1qv/4Zv8CKmR+Hf0AAAA=" + } + }, + { + "ID": "efd6e68267dabeba", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "222" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "dd2a43878f27fcd9e06ac3b41946763e/11450460001659011846;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X3ZpZXdfNSJ9LCJ2aWV3Ijp7InF1ZXJ5IjoiU0VMRUNUIHdvcmQgZnJvbSBgYmlncXVlcnktcHVibGljLWRhdGEuc2FtcGxlcy5zaGFrZXNwZWFyZWAiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:24 GMT" + ], + "Etag": [ + "SXlUj+2NbepFWdZcSw+RnA==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1R32vbMBD+V4L22MWy1dVZDX1oRzoCXh7iZB0bxVWks6NGtlxLrgkh/3tPXjJGWVkRevhOd98P3Z5sVS1JQtaqfOqg3X1wfK2BfCTgeIn17IdePZ6x+Rqa2zv5U2T92aK+vrrCDuXnZKcFuHFjWjeexCyR3HELLmdh9Dm8jFgexZNLPDGbhGGY440Clz8r6PML5LCgi1TVW2TaONfYhNK+74PSmFIDb5QNhKnoyRx9ZrRpzSMIZ+krZXpUtvQdFuiQ0tK/nAyVBRTQQi2AJHtyVJr9Iyb2H1V+v/5f8aQw9P+RPeAPiA1U3OsVCrS0JPm1JzWv0ALpTSv94K7xKFsuZvOviCsjPZ6v0vT6Jp2Swz3y1F11s3OA8yQkA0xNXS6hfV1emP6ERAvcKVMv1SAXXZzHk4gx9imKz/FZc+u+GanQmHyj5Wjt+2x6h8in8kmGZXnH03T6ZTnyMUZFa6rRw2mT46ZbayXG/ucCy6sGtxHYDd+CbYC38IBsnYUUSi522ZMmScG1BcypjRg8I/0qI4cXgS3Vz8ECAAA=" + } + }, + { + "ID": "610948612843a429", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_5?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "09ef248cefc2c2627431ed853bf2b7ac/13014634416250371222;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_5?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:24 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "37b8bf55fe87f857", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "222" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9aff8c55d8171370ec36df95dbc17e1c/14578809934648259622;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0X3ZpZXdfNiJ9LCJ2aWV3Ijp7InF1ZXJ5IjoiU0VMRUNUIHdvcmQgZnJvbSBgYmlncXVlcnktcHVibGljLWRhdGEuc2FtcGxlcy5zaGFrZXNwZWFyZWAiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:24 GMT" + ], + "Etag": [ + "vJVIODVCQISgti/cr8WrMQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1R30/bMBD+VyrvdY2TDBKIxAOwagoKTLSlPExTcJ1L6tWJg+00qqr+7ztnLUJoCGT54TvffT98O7IWTUESshTVcwd6+8WypQTylYBlFdY3N4v05/fF9X06q6ygXJ896tv7iwvsEG6u6CQHO26VtuM4CpOCWWbA5qEfnPnnQZgHUXyOJwpj3/dzvIFn842APo+Qw4AsM9GskWllbWsSSvu+9yqlKgmsFcbjqqZHc3QT0larP8CtoW+U6UHZ0E9YoENKQ185GSpTKEFDw4EkO3JQSv8TE/sPKv9eP1Y8Kgz9L7J7/AG+gpo5vVKALAxJfu1Iw2q0QHqlCze4bR2azafp3Q/EtSocvnvIssurbEL2v5Gn6eqrrQWcJz4ZYKaaag76bXmq+iPiGpgVqpmLQS44/RbFQRiGJ3F0gs+SGXurCoHGindaDtYW6eQRkUvlkgzLco4n2eR6PnIxRqVW9ejpuMlx2y2l4GP3c55hdYvb8MyKrcG0wDQ8IVtnIIOK8e3sWZKkZNIA5pSKD56R/mFG9n8BJwQDSMECAAA=" + } + }, + { + "ID": "94b7fe393b40cc41", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_6?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9b198d9565acb19b441d97dcea2cf37f/16142985448734469558;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_6?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:25 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "e1ac3dc4af7e4bef", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_7?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "821755830578b15058bbc77c33867a57/9302044570438279566;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/t_view_7?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:25 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:25 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAALXNQQqDMBAF0KvIrLUkQZKaA3TZVXelhGimIkSnJGO7EO/eSM9Qhg+ft/izAaZECez2KxnsfYNAs58WsDBG6n2EGhL6TIcsxBdal1Bsxpz9iAWvxNXzUFvdfB+xCmsckJsXJW6MVjZ49hnZKSHPopPKSW26cloZIYQrkSd27wk/zsD+qGGgUIZb0f7xzf4FitXgxf0AAAA=" + } + }, + { + "ID": "65ba4d41330a8a87", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0017?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "aaf0c53848769888d2b37e84491ee3dd/10938276579050789406;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0017?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:25 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "a6dd780a69021bb4", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?allUsers=false\u0026alt=json\u0026pageToken=\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e1d081dc5b751a05cc11f76e56b14139/2461104791620163174;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?allUsers=false\u0026alt=json\u0026pageToken=\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:27 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/tuY4_VPtLXmEVyNvkcFEiw98KHw\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:27 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAO19iVPbyNbvv+Li3VvJfC9hel9S9ao+FhMIa2wTlkyKq6UFJt7wwpJb87+/lmSDZXULk5FtOcFhPGDpqNtSn/6d/fx35Xu95a98WHHrlzcD1X34P9dtd6/e66+8W1F951If+WtlzzkXLUA2xW7z44469o8aOwd7TeWcfOz92R+ckYsvR/2902b5y8PB7Xdvq1y/k2J3++6vFX2RlrrvHzmXqtb+rlr6apBixiGCREIG3p9t3cue2rw5ILh+XN8NnEsanN/2/fvyZ02rp9Jb+fD1vyv1cIb+oOGp/vtOu9t/zxn6cFxdXb/feWjc3Xduz852xOHpbfncXd9rDX6UL79rcsM3iy9aUYHqqpanVj78d6XTbV8rr79jGCI+OzqSPVKj7Tn9ejv8fsfVlb/frfT6Tl9ffWXz8KC8Ev+p72nd64Ujel0VnV2rN9XTHUEICMjjk7v91DEJwumolp8+Aqk+0m/3ncb6Q1/1jrptT/V6Kpw20EeiLx+Oaz/l6ch6vdF4/NhzvCu1Xe+vfOh3B2r4rZqq1a89dMI5VMt75Y3ayt/6C3vtVlC/HHSHt+G/4Y0bnvX5uFw5G5/H8JeVnmroG1+6a3f9UtBtN0v/GT2q952B26h7732n76z2nGanoXqrvSvnu+p1lNNV/yk16s16vwT1ZX2lb2wrvqGO25jimYZX7an46IUnAgFcIF0o3ACgQAWUE08BCoSigKiA+YIz5oR3Kbx8ROW02i2gmIsAYT4PCKYBcqXCXPlQYRdAgBDHghPCg3A5RE9cbdZ7nXavPlwoG5XyWq18sbN1cVAub5Y39QB33frkWSeVHX1SrXJ8sKHP1ud0uvW2Pi28fzsHtXJlbaO28yU8MOipPXXpeA/Vm8bKh8Bp9NTfw5U4iJZdYk3+HRF0L1TTqevTVzBjWEqMIaHv9a3oA9hu9qWDuPzu4Uvvsn5zdfO9Idy2ezX4X1/dqka7o7qrl/oat3VPOZ7XHrT6q167qS9tZ1i4Xz7q7PbLPwbY+X58e7+jgqsdD350r85yZtjskXJhWChJxHomhoWSIhvDIgqsDAsxRpLgFLscNZxWtBW2nOhqVQA+lHZanUG4UddHDBvNZL+XmAejMJ7HxOcchp/fOfV+Jfxya7d6rwerAAEGBaWM60WMgUQ8Pme/F52wgsZp9p37bJrohIhG30F/fBwKKKRErznIKaKcx2eMRiFynGQ4jI0kHiQi0ctP3xGV+EIEIqy/KyajaT6e9jjaBOXoa2VRDgcdMW1ixOQ0MRqeMxqOJohGg1mJ4pGidXY1CIKGOhz09RyilaMPSOOBamd8H+8qT++xvYq+XeESYIRR9vTxiR6nH2NzuL84XUeTNqK11Rt+GH7thuor/8h0dLTFrGwc7h/tlWsxA6lOjN1Dpta7XbjF9Qbu6NDKv+CHcO/Xn25VDvdL027+K9/CHWZ42b2d/Z3axHVh4oxoB02NrD+oHZYuLvTcLxUAF+3o3mnCiPSRyeCHUnxXR1wGLVzGuTRymRDh5/XwdlXDoaLhwcq3NOeNsY/Aeq0n+Y5SA+PZSIZLhhr4DiQZDRj4DCQZC5j5apwvwmmkuApCM1tlEMYDxvtSkqtgOKsEF0meZqPxs+JrRWcZ+Ya9nG8KwTIjbjEs3ZeteTi+5vV6DMWopgZBPwOT9BmqUW+paJaq4XT0CdGC50yMIK3aaA+Zg4ULsKN5ot66PG7Voy8Pxm/N6EO0Ek4gotZ3qx/JPhkyqmVuaRkWAiIoZyG1qz/T06jVVVevk/RUSULcjaSn8GkPxQ4/kizjhzMufpi2rAkBc7iBJcTH8c0s/OavcvWrXP3P5OpPt+jH+fVRs1LvX8PtzT7fxZ+qZQBpr5KzXJ090nNytep2292K6g0a/XBI/fh60cn11q3TqPvJKxiX7QfTstV0Tb0j6G0tfHzxtUrRsiqFUP7BzAHGS/3V+lrrPpQGPb1blPTsW76j2aj6ea/09qrf7/Q+/Pmn12gP/NXLdvuyocIn8+fo4n/6ba/35+Ou8eeI/H3vpvGnaun56Iu+H//0j2+ro7v0vLohJCA2dUNIJI3qRnxkoTvJlKwV2hgyOOt18VgWT3RbYmx6vSXhLfm2oE345Bg2vgz69NP+/cPZ3feDo7uNxoM4Obte93LehLNH+oeb8OeI+ROXuRl+9LQoqg+tvnNfii71oXTcUvcdPW3ll/5a+frXSsnpl77CD1B8Wy3tBKX+Vb1X0j/OcA3VfS3r1AMti70rqZ7ndJQ+JV5apbt6/6r0H/356uVq6T/R+avhgf+U9M51pbr6TKdV+vp04EU7KBLMuoNiaDbYxEfy2kG/Tss5316+gz4nnPyajz5j/1vC77Oozev0pLPt3F0dHn5uV5zvQq8v2O6i67rXzNsymz3S6+Zl27w4x9bNi3MGzZtXdOR18yrqo3/dvPLYvNri7nKjcnDno+3tL2r/QVYHzROn0zghfs6bV/ZI+biVGMfAxuhMYIuUwgFH83MrMQmAyeDNJMcmtxLENPFDkubthCtqZIe20gztxAbztmBk/Ecmrd2RlW/S3G0jiQdhk86hRycPSfywqb1KGYRZTiUyQThhDsdGp5KVKB4J/4JOpec8Sia0Kq1Vpz43B+/TcIp5+p+GbGdgR4Gn8j/FrpMxjuQkxZJj58TrhxMDC+bmYTKs3gkWwxYWyyB8WvgGv22KMxMsRowsZiV6Yua8WKxg3DW5eBfORbl6tDB4dDo9uokEXBaHFoe/sj/rp9SQRfmzIHFdFxCmkKNIgB0qXYRcT+o3RrAbIIF8X3l4Mf6sZ4zuC5LnD+pngz3VWfvx6fDqerd1OriF8KB6uCODXs7yfPZI+cjzFFjjOiGFUZiGQZ6nIgrcmiKu859J8hRJY4AYxSgR7PUE7+NiAjAJ7kkpISEB5C8kcECFQFh/DQIhZ2kpwRrelUGZJYlPkNEJMYEZxQQr0VDNsIkJcCnFhH/BD9EyHEoK0YZ4gQAUQEJ0oRVcqf8xxIEWHgCAbP4BW1pUMwZsUfKzArNIR2ilBGYx05AsML6Y9YKTKVbgFlbIIBxK+iZOiE9+WtaTjGAMdLQSDRnBGugIlpQTbOLyDAO2QJZgy6OIxIn4pyi5YMaSbUaiQbYwy/BPCbPZAt3wd/uuBGBClHt+D5ud5BsZZCPJ9/lZLE7QJb5yNYV3QaBDLwhX+MKVRF1QJxDM0YqL77o5C7m+CpxBo78Zzz/8oi9/xFm35u9ljwtjg6ubE6Raa66LWf2heeN/rIqt27XmZTNnQTp7pHwEaYi5NQAqlKTNgjRChNvVbZSfJA2pZCaZAjIiZiZJY5F4TVi8cULgGF7VRjK0jVGLdEEnXinpYpLw0URmJ3xKbjCY41Jk06RR2IieSaMg5iNZ4gU2iRd4IYL2u9K/0IfWoDmSNabY+VafgxI6hYASjpuzYA45MjORQHwqwRyssolXks+YidFsJEOhdKYqLJx4pTMpJgkfMymshEMPGUgzliGTAqQ5yZBJYZa/wyVvdiMVn3WGq/dnpfP04s9JQhfoMaH3SUKPcgZnbXtOOpBfbnaO8K/okjqdhaQek5f+p5Tj/rs4UV5R1yWIygvmeMEFQTC4cBGRF9hzuO8HAQpI3qL8csvZG2cfv9S23Gbn+lO59uAP9r3Nw/WNH+XbHx9zlrOzR8pFzgaCSlteMxCcM7OcDTCzFyLIUc4GQs/BICIAIc1yNhAMASYko1RLF2Sq2BMrjT32BFNMiJZS6JCUTuQ0J2hGoriNZmiAnsyhHH2lJBV7QVJzFmV2UnN4GzCXGEbXmMrqbSV6xur9a0njXu92IbI0kAAYGUVCLKaUpSfTkIWBWSbzjsUspWUDY04pLmdRvkRehtCw2NMCc3zaq8Q8D4kZAp6O1oBR8nfRRWaE8pKZn0S4cMOZuYwbDrI4CdWlgjrScy5AQPwL4nFx4SrmX0jPBy7yKUMqMt9GVJsqqLfipxqJPXrmodzYHnQ9ddytR6vzMsxEm5jtn+7Ne/1Q+++fk9XJarTH6zuuH2PTCa8e1FXD743LN0OPaH/4LGqVnYOPK2P7eowYw8OhDPyxXIlDquOZbrW7mjVCtq1+CZdM7/aw8/idet/rnT29VeiFVmnfxZz+99+vIvpYgsuXYLPycLq2sQP72+UDun6zcVTd2b/+fgdzFtGzR8pHRKciis4wiuhUQnMuMGBMkqcNUF82ArAheqn7ftfxYi/KE1dr/tiqN9RGeI8fI/OyN5DyaS1cGyuJS8Zr+Cf2iLzVfxLe8+QX1FQ5sP/kVXPcVsYunNgFisdlmwfO2mX9lhxT3OhsH16WuarIz19OH7ZrOXNZ9kj5cBlmwMplmBNzJgYgcWmtWUduASw4NYn3OC46VPTILUygEE/v6WgVuwprJcyM22IS4ad3PGkGN2qwVqKhVTxHDXbsk/mI+OGxY4OYDkof/l/pjfNGH/gXhOEfyWhsCx2K6dyIDkV0aBo6HNN5ER2O6HDu+vJG29FStKee0ZgJAEaWIkCQKTVmKZDUEPz4PmFsgqZCXlLqbRk9vk8o1LEmOTtGRJQROPY+dZ4FhUigsfcUIzITIybG0u+TqUyxEW+SEyf8upN5Fva4sZnakijIZEUK/oG6bdOyk2sbTdqCkHVlG21BBEaoOrGy4RQBjzCKan4m4jE+aXa+08nFm7YGIfPizaIcTh2ZVi8jknL0+D6ZJMSNhlAr0TC60mopennQY3ENRfCfGIpQXoYimjYUIQmntRTRRcQ/IiaS1ZiL6Vcl0a1pDZqbzcZaEERp6ENbBF5JG6N2Dqrlys8bo2LyXDytpPQ2Ntvruf/xV+uv/l/90sTry9recblaequloncl+Mc7/Zurf0PRb57+Df/xj41hM1F0l9tm01qr1ND+wad7WkcP4nJL30l2s7kpdvxuztpk9kj5aJMAWgt4AIC4MGuTgGfk9U+pTSYlBIs6qfVGYpIQAGEJoB+l2kPKhSQcM0EQnKxXy0yFom0kQxHOVCc6R0mBIobHJpCSFIRNULATDrM60nJC2mtkEgzSTiO7JABfnglkVChnmf9gUygjFZJQQQRDhK6C0StSFEfK5j/W+H5eKqCEpYSCqXN94QIkAmH0Gc3G3fO/t05jNdyU9OWbnXfx39WBW+13B15/Vf9Pz/Mfg9/Pe4I84CmBJXSx57jYoRgL5MiAeW6giOP4LgUUI9dfYLzS8OaGjNXUS6ebcAvp2zlkyehY/FT+O+YmOo5M6b3ododHE9SPD2Zl5Dp6JK3t7JertbX9o3AFPOFB9LzWul3nIU2yVqmshWvBCQ+nZxI5rBIXGy2D9KWem/jjuknTxcN8Mw70cxP/xzOJ3HCPz+iL0xioWEYKrxj9GSH/0/0wHYzH0b/dxvQrTuyie3qGY8e0XMfeA/wegRKkHwD5AOj/1VCuN82//45vTsFkNTzob9H2uqeugVtxrp1j9rmMrr1zXq3nLKtlj5SHrAalYMQiq+ljnGKTrAb1XZY4c7fPR1aL2goYZDX9uZQJu77ZcpM8x2y4kbONeSfJF07bbSxGxyzKod3GWN1F2uyHQ+HPaLexEg0FP6u0hl4e4VMoaS3eM/8aaKXAW11djX5R0xjzY+fB8+QvTvL+eemOibR0F7FpUaU7bCzeMjvpboHCm8tpGE3OkUAeJZ4PGXeYrzUFymWgsPQdQiEk/FV4exXeZi68jd1c/Wc0m9HRrwmh7d3TX24cofVCwc+LBb+JG2MY9PlL+cOH+vyZamV4K34NefMKdj+d3PDvnx+uK9tfPp6wq75/C9t1j7dzljezR8pH3uQo6qBjlDc55sbUZn0k9lzMXt7kcVmUlLzJKU/4s0e2wadaImGlj4kMzNgUNmkbtJCM2cVm5wFPjk3T0qjFNphF+ALboDDkMqdtg8Lq4hbLLWyO9pvYMDhN7Mds5ETwaGd/khOnzbpciBWQ/jZyIkeKEMdVrs8C4iDgUugiqXGGOszxkL6AI1ziLLIp1D+QE0Nhb8Uoo4zQeZJFConIrcHe2a6vPsO9U3TIT6t9jVefdk+P9gZ5txDIHikfRKbS1twVSgbMxUb0EQZEJqfnhcgMYkMBM/05wkZvnQAEEy6Qnh+TdKKrqzDlQNpIhmhkSoHMD5F5PCijCHIsDVletlJmGYTWUmaGmgjJ2B9bTQT0qyIy0w9/YTiMH2XaZGGBouJwNN/fA4cdvTI8KgLsE+Vj6XDfkVK6ikJfwzBzA48GiAVwOXF4MxwtE4eftORiQrC62y1Xd/V92/TxIDio/Hjg+8GPA+do7zhnCM4eKR8IJghYIZigUbRK6oig9joEeUIwwZF6kIJgQli6DkG6wH46QiZdYH+2ITF4sg7YtIWH7IT2RGqwKjlKvCYjZAx1iDKIhnfIWpZoySHYYI9buH78mNX0VGd+2hbPi8DlSDz7PXCZA5/r3YcgjcLUlwEh1FUMh94U7iqFmYtx4Am6vLj8vI6cwTGFxOoz1dtdr50gsXV2erWx3rwTtyd7B/2jbqefM1Znj5QPViNqK3IfHhPGhGQoMcLzwWrER909Jz4XxppBTBCmz3l8n1CXE+mVoxwPC8lQXZYzVZcTI0NDqxybATuD8AUGbIinqiEYn2YObzWHUiwNXEc+zKIEPHBD/UBcZKTmv48l2+PQkcDVarQPkeJhrx+AQoeX4xPmKgEJgdgP1HIidZYrPxHSYMBxm8M9wzP9bqqzvhUS/rtAda9OzgQ6b155R+uw3iOgwTq13c52zvCfPVI+8B/WO7LBP4TIWClBH2FYZu4mecG//s9QVVh/jonJWk4YJvDpbbIIWjrv1U4yrIk20yxYIDSyjr+9oCaanfJFNdGQoQGlQQCwxEUuv7puTG9ZEP5TkjagQyQKjP8Qkt9GAGAYalEbIao4xB7Q+4UDkZQC6LMp9TwIHQw9ucSu7CHIv1BXf4w2KyBWH5JyPbjvfudluNNR7h5pbu59ru18PNi+yhmrs0fKBauFFALbsFrrLcCM1WEW1VywGkBixGqASCJwbGRVHq/PgzCcUNXTbWztJEONd6ZdbaFmfyae3vn0FSsyKO0VKwy+bTgNVEtzvumKrYfG0iD1+lmtXC2Kpm4wqcsiA3VU2/f3wGnOfE5c6iqOJeJCQt93FWbQFwHyAq2he9KTjpLLidMRF2Rj9HlT3hYTjvsHt92z1rnaqO+fNdzT8zprfj6522cn7C5nOM4eKR84FoRKCxwLQbE51VDoNZnN3znBsRCMGApH6c95JEWkLOcaqAl/fJ+AY26qH24jGXp4Z1xOnGMA6eN7Go0nS/A/as5WwlHlq+kU5+mKiSNrquGSw/GbtfWNaYo/zAR/OTNoypgUGIAhMpaC+iURmPmOPtOh2GGeIpK5ggQaXqgfdo4ljlAecJXLyXIi8GMB8AwI1rxRTAQ+vWmvH9TlVSu4ZLUN5/xhv1v9tPVpmx3mXkw7c6R8EJgDYOkrGR6zxJnpNYvnEuotOOSmUG/BkbHOL9UygxRhhXCKCOJoCuO1jWQ+xmuOuRYyANebgJQgDcHSjsA2wqfqvM8jMJjOdA2sputlr8y0MDs1T2u/EExbinEhGVe/j5laBh4GgZJBoAiiLiGQCI8xD3qBE0AvjJvxXddZUvBdPzzcy4befnegiom93qft9ep6sMuvP+3trx/2oF/53D+Xm6fbeWNv9kj5YC+l0FJiXx9jNu2XITYXY7SgnBoKguvPJUoX2gGrArPxeKrJuDET9tpIhsboGWMveyZuzIq9dsIXYW+yVL8Ve4kVe5c8buzgeL9c2dkoij1aGvRhIAuMyOz3MUh7VGGCtdCLCSHScXjoKINMYBo4bkAg5Srwwhb0S4nIQ0Z4Jg16FT8GVxQSm8+aew1nZ/f+7uCudtnR1z907wZXn6XY6uSMzdkj5YPNWJLHPhmTxwiAZkexxgM+lyJ4gjzGlU18jqgpppsKiCXFRAjMEYhauYxbpk19OWwkQ8s0nSk2c06hxFwKze0Mohc0usygfFlQl6Enjsk2be2Cs+xBXauLS7aKVM1lskz/Rrpx4DOHa9oABMSBYZ1hwgOOwthPx/eCIBCa9XyypNlWW3uHazVGnkXiYiLwYf+8dsTWv9TdXp37m9VdWP/CWlcV3z/KGYGzR8oHgRFlVgRGDFss01grZHNBYKSBxoTASJBERZFRqBbDWt8nSAutjJPJGiQJfXoUqWWmGOrGCXDNXzcmGHNMJJacSoDTrYVsJUgyCF9QgkRMZZYWv2xA9eKip9NlwESRjdL89ykXyxzpQYUczgIfowBqkTzACviuYIwQhqh0tVrMljQmS1/7WdgtJuje1je6D+7xoBF00f66s1kTJ/55mcnOpp8z6GaPlA/oQo5tZUdEiG1m0NUa13zUXiiYEXT150vQ9hVPvFKoaol+zqCLx5sq9nmqYCt7D56lreperVW2wtSMi+PaxsVxtbzx9jFR4+2w1fzbo7VKdeyEN4YcjTd//PHHu9Kbf29/+Pf+h39X3/zxLEgH4GImKA0NRcIKDdLzw+jwyY49XstzXCCKe64CgmvI9oOAAV8x6AnCqK/RQDBPj+TqKzl4QSgeOn6Lh7CM3dwcnN/86B3+uKxQ7q4f9sr+cfPz4T3KGWGzR8oJYQGyZSDpYwJaEBbK+YQ8w7hrbRphh9G6EwgL2cQribim2ppWkqFJ9RWBLQi8tNHOOSPw2ft/N9//218kAqN0W5UiI/AcS4yE9aoKjcDE9RQXAfAFktQnRAb65UkHYomZ/kj/zw8WVk67mAj8cLtzf9rYvlu/EWDXV0enawffN70HUkd59zfLHikXBOZScmvSEQC2sCsAyXzCrgBgRgQGgCcSeoup49JpIZX+HIZOFTRlDZkye2uXAEJ/GjALhZGFrsM1Xy01Cx4XiI4OYIK4jnBdvU8Sx0EAcc/lQsMi8rmrMMCuh9WCOsoWEx3LUm2eNtcvL48Pf5yfiLPNHfdL7cdJZ62bd++H7JFyQkcEbejIJQZmdNRrBcylmpWeAhYGdNSfGytkFAwd04FMFnRMxy1NhY5TNVP69XopRRn9b98E7fYilUKSDlsqcusGOMds2o21ai1+PqW1alyGZJEop7B0HY8JhaTnKcg55i5zpCsZIAh4wGFAQijRK8o9odwn92PbVfWN2jl0Hk5p7V7tH3SPP56fdfL2c2aPlA/KCYKsKCcoMYf3hnb7ueiAegoCmFBOUGPaK0miXLq7wtgpT2jyinLLhXLTlYuYGbzRdMZqkeGNzQ/d4gezwE7SLuAC+lJ4CFHXd33BPCkAEcIhWB/ygXBcwhdUV7mYcHZIK8I77NZ2ZPCwf3+75dXI7kmjt3VNcc5wlj1SPnDG7ZmknMdt+QxwxjmYS6ysngIxwhlnxhLEBVPaim3SNPfhWwI4i7LMF2edfKxfshTWyTkmmOgdvrxAMENICeZSnyEGIPQA9T2FmEchQdhDrqdVNua7wHkFsycwOyof1T+Dk97HzS+19j2oXbe874Ny7eDgkOYMZtkj5QNmjFIrmGkFjJvBjHHMMvkuLzBjjJnKIujPk23tiglmKI1mlip/KA1nU5X1+009dKP87AXaHx/RZSkgbY4KWpixt0D1TCkXBAr4QqMYJz7gUkIeBIETAE+L4K7HEJC+94poYzGfkDcbHwflTnljg5ysubfw/PZHUHEqt1s5I1r2SPkgGmXc1iGGU04tPjUq6FyyKvQUhCniRH8uE5UBioloxbY2Lm3Q5vNJiLPLb0gDWZEtjXKOQLZAGPM8V4OXQ5ATIA/LAHpBAAKEEEcSQoW4y5FCCr/C2BOMQeSLLfoDMeI9tLd31uuV2o+tev/SbXzKGcayR8oHxghGjwiSOkaIOSOfUwjnA2OEcmyCMcKEycoocGg35QBIrCnlhA/N2OfURjKXPqecaLbElGo5P0x3hCnYs/U5zSB8SZ9TkEzdt9ar4zYoXOZ6dSDMy3/7LwSS8SWW0zH4+b6oEYvNoNw7TIMqjJwGRYXVuZZ7j57V2+EfVQ0/G7W3X+G7Evq20GQFDU8scClTAnJElUQOlBpyCSaISl9pxPUkd9giG6YVEHSP6ffq3cfD27vKILi5vj2Tx1uVj3rH+pF3d9HskfIBXQyQrQwOx3GBSgPoYibnYw3FyOzawxindUc4qTvKRBuVMUgZg9XonNn1JAOcIiZC/gIEA5iGVVupuSxKe6k5sCoJQ5hRKiGWXNDJ0jdJMB7VArLQDPHbHNISap9LDLlTQWgmXheqMTlKl9aJVnZR4XeeNe2+xlj7roS/vSuRP96V3n6l70pM/8H/+LZA+KWejwJAmGZ0TKBQGmm9wCOQYQH0Jhc4gDkKQvAKv2Pw26nQG4H22zs37fON6xvWxL3tQ3jrnpLPOcNv9kj5wC+kwJaur49JS2QNQmg+gaJ6KFNBHB62TzPovFRwAtHT+4TOa2oYaiOZR8NQwPR6BU/vL6gDm0H5ojqwZLoOKcRai44sbbzpLwfB9DFF6UnJJEVuORrH3M4NhIcYHOIveVcKEXih6MsgkcgTGEIOtBIMhMSEK4g4Fgo4gjhKX06JV+V3HH2b38+9wK+S2pf2g3PmfvZvasrZPD3f6GzmjL7ZI+WDvgAKq+MUIGaxOAMxn1R9DrAwhgIBIhNe0ZHFmXFMmMSCc0ohmOhOJkxV2G0kQ/SdbRV2oQVdxCgGDCJEiJja4pxB+AKLszSowoZm3VblNzJMLDHyxmbIn4be58nnib0m8zMosv7L5+jWHZqaNfa+K30NoffbIo3OvgDURURK6rhK+VLqhYOk8vTO5kkJJdSXAthfZPuz4uFuVW33NyqHew8Yfrx3ITjkzcrNce3+c7+bM+5mj5QL7oZWTVtXUCYkREbcZZI+9VCaJe4yCbBJ62USUpPWq/FYS44CMSD0HCdr1AlTkTobyRC+ZlqkDkKcHD2t9WIz8GZRDhXVpDpr03rhVEFP0FKSTh9C5gDfpcHeIumtHKdNx3H7n6JiJwJzbE32aDpeIGRKwlwGqSsQdKGPlWQB1v/nxCFMAcIApMLFHn+FzHFD8c06gZcHlU87gjQ+novjZsu9885hq9rPGTKzR8oHMjmxNgxjnEaxLwbIFHEHqdlDJn/sJzrxOScmVZWTxD+ahExuMhTbSIZ9P2ZrKJbJf2kvrq2ZZwbhC5p5yqm6hUlrs7BlDo365VRVYmrNXeT2Y1G63LxU1RBtFxoSxTyslVPKgd7AMGUAES30BhqBqYOE8hDlLnCDBWXTFBRqt3b92uXV2v7G3kEFAcrau1/8znrnvLWfdwHX7JHygVo2VDxMUMsQMqfTMI3C2byXF9RqpDWl0zBGqClBNHIWj70moDbRznMEtRaSIdSK2UItoomf6X2yGZQv8smCqQzD8Wm/VgmgYX+wYaXQhbUJMzlSYZGNuWxhPUhKhSvx6kooQSCF3kWJ6wuoOFE+8/1Q+JIBxFwgXxJHvALoGIBuHvoH/fqDf1lbP625zl3t9Gi3fnkm2qcwZwDNHikfACUc2xJ5GBGQmgGUEjAf8y6RxAigFOB0Ik86pjhd/i4dUzzT+neTVlhDyQVLimoW5RDVDDmrYFWIBB2fDCpOFm4Y+ZZtRGNG7l8SPpn+5otzhKYLDxW6xSZdWPOQ4kEnx67vC6CYQphQGAScOl4AoPL8AAfEg4J7WjhaZPPr4kFnZ+38+ub27HabndON3eO9jXadnH7/fLazmXcObPZI+UAnRtJWOJZhYimPzkhYGGYe0IkpMkInZnAK6BRTpOOIGafjJDtIpyN+LYbcLMIXGHJ/887Thg13YUBp8HqKIgfrkjnqmCFQFl3PBFzqy4nA51x4HHIPMQSQZAGEgPkOCSiQ0pOveuY4WIr6/u3uFdgiG83BUb8tDs4/9rZ2vEsIqzmDZfZI+YAllNZeInotAItPFNH5VFlnCJp9ogjBdC+RNFgmzrGAJZutnikpJkJgjoDEAKXbWdr1TDtlpp7JAGEU6lvEJWByUs/khtp/GURjnuFfrOPlr+cVpVGs+QQcgwLDMZ9jfcG3b65Uo9F+865UYDx2Xen6gScZdYnDgiDwiYdZ4FDhaq4EUHiAhrVtXvF4DI+7nwbrp2e3V83rM8TbV+sw8E/9zXtAjho543H2SLngMZUS2tJpGAC2GCUI+HzwGEBjLQmm8clUwCkdupOA50RY06iOgoVkiNYJKM4frVni30uswnZKO1oblNup/Kb2ahLLHqVUpKBeCGQaUGWR6/XOMyHm6zM4+izQLjIY2JNUOtJhElOHMI59z8cSusIJcRYFPnSVhwPPfQXaMaBd37+/9MAV2Tg6JMDdYd/vP1X92t0ugJWcgTZ7pHyAVhBhc7BSwaA5b5VKxOZStIkKTk35M1QIaWoxHYbaMSYhRxIjjCfcrcZYYDPF0BA721BggZKjp2HWUvA+i3KU8DINzMZWhefjk/CvakXWW4VmAIYIXQWj18KSZ56Kjz7FKmFZZJxdRCdqM4ouEER9XyunUilEsRMo4XmUQAAIYzxwfI6B63nYhYS9gugYiO7v3d1uewf+Z5c6Z3vr1/yjUyYNDMtXeVc+zB4pHxANy/bYQJRDAM0gyjmaD4hyc+VDyjFJZJSOtFWNrRwzQRAEFLFpUNRGMhcYTQ4N00mo1owaO+FLMmqmykCVv17d/RhCoxbJBVFVGU9rqhAU2fZL52j7LVhr68ATPtK0VLqMIgU4IQIGSDg88F0HIZd7KJAKvuLmeDPQ6t1l7Z6xqrtxSluHD+Xb753DHjolJ3lbebNHygc3KYnUSCNuUgYtuBn2IJoLblLOhAk3tVaaTo9JeV0hTCNlyu0anzTDsoSQAKxZkXMokRQohY3cgo0ZhENnaBobwaqgkhEJERKAA8jZFHWSMoieK5u05Mg5XZfsmQUtpaN7IShyqQY5R21z0X2ygcsZ9p3Ak/pHcRe6YSaEo4IAQU9RjZtSBNRdUAebgmLj6eb6Xc0FwRm8e6hsgoddl216m/dfgrvdnLExe6R8sBELu06JpTBnvlBC5lPYiBJg7MRGw5LTJp2SIICEnjYFWhud1CmZqaCgjSRGBTbTgoLP58XYgnufTYuZSqdkU1VpYPYqDcuNjM93dJtZvmg6lJcXuaAC/33abWOIWBgMqLAvfeVjR+uGGhahotwjMhBhAxo/QK/OynFMrO2stR/c5v3mDtp3/D5eK9cvO/e3xxt3lzljYvZI+WAiQtgWpRv2PTD326ZIPgUwzBQTUQy+KUzUYDBFlG4sfT+nL4LZ5oNq9YtwQIVAWN83YugxY4v8yaDMitOVAmAZKvWCIU4oTFVQSBZaeLQ3W6hGdwlYkXHJI4MOjvfLlZ2NohhchUmLLHKSKJ9jnfrhsyq9CVvUL1Kd1Ac831OCCujCAHpcIhdy33MdvWsiQBCU0lW+eoXOMehsnXpi5+TL9o+rw8/XdzcHa5udjYMvR5QfiJyhM3ukfKATMGYLqKVhOIkZOiFh81EngaTSBJ0Q4HScTwELKQA5pvOFnVynd0LaCa0KI1jlWCZUzUn90WhotRIN1clfNpy2WKAZ17GcgKUi1ySaZ2+XyEkJV3Ep9FEOn9sivZSOq5HFgRhTyIXrUsECGgCihV3pBYog5UsgoHitlzsOnWdb97KnNm8OCK4f13cD55IG57d9/76cd2O17JFygU4iIbOFyBKJLM3EiZQQZrJiTtBJJKYmrZNIIkzRPUwLgVA+vU8U8Uukrwxxw0YydATymQIrZxLhp/d0kKwNWDMIX2CJhXC6ZuLQ2kx82UNkV/HCtMvIA7JM5eTFHOvbhg9mgcVtPeoBLxCuAwPf9dyw6ShmFFDuaoZzgOvr0Rj5DVueffv7/wMuP6Wjr4EBAA==" + } + }, + { + "ID": "b7f3fe408683f120", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "72" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a6c4ffc320699ab4f8ef41facee2c9b6/4097335700737822710;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJkYXRhc2V0UmVmZXJlbmNlIjp7ImRhdGFzZXRJZCI6InRva3lvIn0sImxvY2F0aW9uIjoiYXNpYS1ub3J0aGVhc3QxIn0K" + }, + "Response": { + "StatusCode": 409, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:28 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:28 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKXMQQrCQAwF0KsMWbcgIoqzE/QU0kWchDKYmjJJwTL07o54BHefx/+/ApeiBWL9BYN4r0A6YX5BhFH0gQIdFEbTr9AyS07o3HBiMxy56UVagdZwe2dzi+GKjsYeaJHE3s9avD8d99H1uSpsQwdJqQ0Pu/MfN9sHl9pVZ74AAAA=" + } + }, + { + "ID": "b4e07f87ffdedf38", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/tokyo?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "94df401ac8a5651cf8c1d3e31ea9573c/5661511214840809350;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/tokyo?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:29 GMT" + ], + "Etag": [ + "x0yfw4kU2qQ7q7BjenGZPg==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:29 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAH2QUW+CMBSF/0v3qiKgICRLNjNjTLa5EReTLXuo5VIrhUJbZMT431cMLssyfT33nO+eew8oZXmMQrRhtKxANjcx1liBRj0EGlMz+Ro2ST1K35zy1S/96Q7y+fsLvb01DtYm44oT0P1CSN33PSfUIm2EGSrgySPLU2PZal2o0LLquh5QISgHXDA1ICKzznutvWMVUuyAaGX9QVpdJ2Wd2Z0QQQIScgIoPJy1Rdvp7OuIi396omMPYUJAKRR+HJAU3FDQOlqsZlHbvgDCMJ9LURVG70BryTRIZbI/ieX6+UpgWecX/JUCOW1mGWbcqK7nuUHguvZo3N/YEz20RaYD7PhBSlxKKCu3ZconG7HZVncx7IGLAuSAGsieETCHiCrX7Ud/74pm9w9XykWA41O7zx4iErBmIl+xrE3aY8e2R85wNPa9wAA4VvpJxCxhEF+yCHIimBFWDPdz8+gtmJyNjt9fKYgcZwIAAA==" + } + }, + { + "ID": "fd1bb2f54a89fcbf", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/tokyo/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "237" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9246d5f5793944c91427c0f51ac7c749/7225686733238763285;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/tokyo/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJ0b2t5byIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTgifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:31 GMT" + ], + "Etag": [ + "rexvj97G7P1fci0HFZ85jQ==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SQW+CQBCF/8v2Wt1djKAkHmpirYk1LeXUpjErDLgKLGVXqTH+9w6rxsTYtOFA5r2Z780Q9mQti5j4ZCHTrw1UuzsjFhmQewJGpKhX8L1d9b2x98KTSLKnx/ded/U6GGCHbObiTRaBaZWqMi3PdXyj1jvVtpC5w3iP9bkz567Xx8d1PMbYnKGM4xqyZCqLNUKWxpTap7Su63aqVJqBKKVuRyqn573o1qFlpVYQGU2vQmksjNCAhk2nNl3T/yxhewJIoIIiAuLvySlkcuM47D8lWdeGnRlH5c/EA94dLSEXTVQiIYs18T/2pBA5ph9fSNyVTfUWBpPZGGcu/ibXF38yC0fjUUAOn4hFa7gzgDjCiC2nqkhDqK7lQNXnKqpAGKmKUFo673ZcjztOh7u82/wC36WsbjS4Pbynmc+ENs8qlnhI/AvjtGr4MJyOmgkVWSBKQkvRKvDTLgExnBx+AOV80RuMAgAA" + } + }, + { + "ID": "35904e62d2ed0020", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=45321648bd4b506bdbb038acdc28da434a140deea1b073e1bf98cb13cdd4" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d79f3e1aa70d8b1fda32b0ca54bd2e17/8861917642356422821;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "LS00NTMyMTY0OGJkNGI1MDZiZGJiMDM4YWNkYzI4ZGE0MzRhMTQwZGVlYTFiMDczZTFiZjk4Y2IxM2NkZDQNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImNvbmZpZ3VyYXRpb24iOnsibG9hZCI6eyJkZXN0aW5hdGlvblRhYmxlIjp7ImRhdGFzZXRJZCI6InRva3lvIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIiwidGFibGVJZCI6InRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAxOCJ9fX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IkJKcU9HWGRZTWdnMmIyU0NnMFhsN0Z1TlpZZyIsImxvY2F0aW9uIjoiYXNpYS1ub3J0aGVhc3QxIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg0KLS00NTMyMTY0OGJkNGI1MDZiZGJiMDM4YWNkYzI4ZGE0MzRhMTQwZGVlYTFiMDczZTFiZjk4Y2IxM2NkZDQNCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOA0KDQphLDAKYiwxCmMsMgoNCi0tNDUzMjE2NDhiZDRiNTA2YmRiYjAzOGFjZGMyOGRhNDM0YTE0MGRlZWExYjA3M2UxYmY5OGNiMTNjZGQ0LS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "849" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:36 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/3YC_ru9V70K6TctkoNlB3TPuwSE\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpPNs_i7WySJew6245I-62YbzEY7a4Ho7n_B3ff8InyIUR2JoOOs9v2oZrUexZLcdcClilNGD4rsXU-QDfn28-MCJzwhZbTqH3F4s1ng5WNk26-EzI" + ] + }, + "Body": "eyJraW5kIjoiYmlncXVlcnkjam9iIiwiZXRhZyI6IlwiTGFaOG4wNEQ4S21HSWVVZFBsSU5MbWVhV0dzLzNZQ19ydTlWNzBLNlRjdGtvTmxCM1RQdXdTRVwiIiwiaWQiOiJkdWxjZXQtcG9ydC03NjI6YXNpYS1ub3J0aGVhc3QxLkJKcU9HWGRZTWdnMmIyU0NnMFhsN0Z1TlpZZyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYmlncXVlcnkvdjIvcHJvamVjdHMvZHVsY2V0LXBvcnQtNzYyL2pvYnMvQkpxT0dYZFlNZ2cyYjJTQ2cwWGw3RnVOWllnP2xvY2F0aW9uPWFzaWEtbm9ydGhlYXN0MSIsImpvYlJlZmVyZW5jZSI6eyJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIiLCJqb2JJZCI6IkJKcU9HWGRZTWdnMmIyU0NnMFhsN0Z1TlpZZyIsImxvY2F0aW9uIjoiYXNpYS1ub3J0aGVhc3QxIn0sImNvbmZpZ3VyYXRpb24iOnsiam9iVHlwZSI6IkxPQUQiLCJsb2FkIjp7InNjaGVtYSI6eyJmaWVsZHMiOlt7Im5hbWUiOiJuYW1lIiwidHlwZSI6IlNUUklORyJ9LHsibmFtZSI6Im51bXMiLCJ0eXBlIjoiSU5URUdFUiJ9XX0sImRlc3RpbmF0aW9uVGFibGUiOnsicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIiwiZGF0YXNldElkIjoidG9reW8iLCJ0YWJsZUlkIjoidGFibGVfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDE4In19fSwic3RhdHVzIjp7InN0YXRlIjoiUlVOTklORyJ9LCJzdGF0aXN0aWNzIjp7ImNyZWF0aW9uVGltZSI6IjE1MzY3MTIyMzQ5MzYiLCJzdGFydFRpbWUiOiIxNTM2NzEyMjM2MDE0In0sInVzZXJfZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9" + } + }, + { + "ID": "40bce87fb93ec069", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/BJqOGXdYMgg2b2SCg0Xl7FuNZYg?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "938a20a38bd2da7a31db523fde19816a/10426093156459409461;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/BJqOGXdYMgg2b2SCg0Xl7FuNZYg?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:36 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:36 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAK3MvQrCMBRA4Vcpd26hhGIho0KFgnVwaRWHpImXQpqr+ZlC390UX8Ht8A0ngXaOHPD0Cw/8kUDRKhYLHNCQFAZKcFp42sVS6ChalW3V3gvUGQcKxWtXXvQkCxXNrEP1Jheq9sD4sf9cz6OaLohMstsJ69G0XRzuE8L2LGEmlS9N3fzruX0BX0OBZ9cAAAA=" + } + }, + { + "ID": "602659a8ceac2000", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/BJqOGXdYMgg2b2SCg0Xl7FuNZYg?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026location=US\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b7e500182049302eb027067c84b6ff22/11990268670545619397;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/BJqOGXdYMgg2b2SCg0Xl7FuNZYg?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026location=US\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:36 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:36 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAK3MvQrCMBRA4VcJd26lhGIho0KFgnUoQqs4JE0MQpqr+ZlC390UX8Ht8A0ngXIOHbD0Cw/snkDiwl8WGGiDghsowCnucROLocVoZbZFec+1ythjIM9NGelQEBnNrEL5RhfKZk/Zddgdus/lNMrprDUVdDjqajRNG/vbpGF9FDCjzKO6qv+4Xb8saBg63QAAAA==" + } + }, + { + "ID": "203b01c96db80db8", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/BJqOGXdYMgg2b2SCg0Xl7FuNZYg?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026location=asia-northeast1\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f85b47d79ae514adaedc8bb270aa1599/13554161618766913877;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/BJqOGXdYMgg2b2SCg0Xl7FuNZYg?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026location=asia-northeast1\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:37 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/KP3YDkPCv-r-qw4n9Qtd0yLVwSs\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:37 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1QW2uDMBT+L+fZjiTtdPVtl650bBashXZjlDSJNp0aZ+JDEf/7kjgo7Gnk4RzOdznfSQ9ndUxFLlpRMwFxD02rzoKZFYcYeFcyYSaNas0kCgkEju2Rh5fv9XLH929FQY5k81igXRk9d8n7vrCsUjFqpKotkWpJJ7U1OAmqDYYhAKbqXBZd+0vpnWl2aex2eF3fP3k95Q7Q7CQq6rpcipJriD96qGnlqL4EYEbhJktXydK6X/Gu0ld8lWSL5SKF4dMG4EIbWfv1GT2W/zibU0O1GFGjvi7KOTvpOHHdgSB8h+aYHHAYze0LSYQQOiA7hmGwa7WhptP+Ltu5VOk2ScbYfiRtLOYJrBVjPOlvwbfTMMKETGfzaQie3Jq/WIjwDNzvVk0pnDh1FhCjGzQMP9OxEMXoAQAA" + } + }, + { + "ID": "dfe354c8b9d1d863", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/BJqOGXdYMgg2b2SCg0Xl7FuNZYg?alt=json\u0026fields=status%2Cstatistics\u0026location=asia-northeast1\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "11284afd8ff816e366a3f0fc7fb33ab7/6713221839948797485;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/BJqOGXdYMgg2b2SCg0Xl7FuNZYg?alt=json\u0026fields=status%2Cstatistics\u0026location=asia-northeast1\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:38 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/1nSJgX2A04NoMgwjGlSN548y2wk\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:38 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAF2Nyw6CMBBF/2XWxJSWh7A06FIT4g9g20UTaAkdYgzpv9upkQW7uefcmdnA44Crh3ZLk4YWusf9CiFL2Xg0Mlm56BidfZqJSnkpqjrnXBSNqCCVFzy6iuVFdNqqo6nL5hyNdNM8ajrb03Fo2YllMLpB0Utj5xVvZtSeVmN9B5cP/iCP1K0Yce/eRMQO/h1B6DWoXku3KCIMQghfofZqY/oAAAA=" + } + }, + { + "ID": "392cba5837ba672a", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/BJqOGXdYMgg2b2SCg0Xl7FuNZYg/cancel?alt=json\u0026fields=\u0026location=asia-northeast1\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "0" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "065cfbdee1726343a5ebde6d0472e2c1/16754569141482410613;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/BJqOGXdYMgg2b2SCg0Xl7FuNZYg/cancel?alt=json\u0026fields=\u0026location=asia-northeast1\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:39 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/-CJBMPacuI_iZ5pGeOgpdsAh1fI\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKuuBQBDv6ajAgAAAA==" + } + }, + { + "ID": "b1cdb976afac1ef4", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "229" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "af42e88b15d7b175a2a43d3adc4a9841/18318743556073769733;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUICogRlJPTSB0b2t5by50YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTgiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IkhQbTBWeERKRGE3NkxxdjlFVVpZREVYeU9hZiIsImxvY2F0aW9uIjoiYXNpYS1ub3J0aGVhc3QxIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:41 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/lqx4KwhQ1X3RWdkXuSZtPTwIEwk\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAIVTa2+bMBT9K5X3bWoC5k2kaasS2rFmaUtJX6oU+QVxA5hgkzSK+t9naCpN0dSJL8bn3HPOvVfegxWvKBgBzPN1y5rdlxeBwSlgCuX69hlM0VNQmc4kuCwvYjan10U8m5YM3V9Io1i/Opfb5Q18sJN7unpob5/UdbqNo+3qGWgR3gnTtiBMDWrRqIHvWSMkORpU+m/JkFRw+PO6NO9eJ78myPem600YzZ8eJ9HD7gplWkKyIpvyaqWFlkrVcmQY2+12mAuRFwzVXA6JKI2P8MbGMupGvDCipHFkbOjGpPGJ2/dCEKS4qL4dRdQxdG3CMtawijAw2oODSfyPBt/ZPfJ5ax92mnhs+HYKiKgynrfNgbLvRNNdrd3BzTxKHrVA33IHHQ7gNppG4/Tk68l5cvX7RInVTgwVwgVbWCYMzBBaC+j5of48yzdNc2Hqay1EmVS86p3Sjv7/DilSSLJ3dIGR5dGMhm4nB5EVEEyx65MMuhBThH3Hoi5xuro+TV+FKlEh5jouxpCaHqKZjSlFBDNIAifAiLiu7eo6zw76eTQMKTbhshaSH8Y2TqKzNFrE54tZFE2iiTbYNvyYdZ/EmpQm89lYszWnbrjQtG5i8SyNkrNxGt91QCvZlOWI7G7XBRhlqJDsTVtLhVQru6F0p24DWmsWzy7AAeR6fKQn9Cm7MfKy40HX9nxoWY7pByHoyY06xiB04N/b7E1KVqnDut+3CrokOmCzYCXiOh6wPc8OQ9uGjjvAMFAmFKUKkeWHK2LnJOfr5XpVBFjgZfuDsg0rRM2aYa41NpwwRIhoK9W9H/D2B5BQ7bUHBAAA" + } + }, + { + "ID": "f43f1330ca469695", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/HPm0VxDJDa76Lqv9EUZYDEXyOaf?alt=json\u0026location=asia-northeast1\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "25276a787fb2b997100fc879914c1984/1508512970265117589;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/HPm0VxDJDa76Lqv9EUZYDEXyOaf?alt=json\u0026location=asia-northeast1\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:43 GMT" + ], + "Etag": [ + "TH5e3OTzPLhwqJYLYPJs5Q==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/22QQW+CQBCF/8v0iklboqYkHmoloiGKFJvapod1GRS7sMgMtUj4711sEy89zbzs92bebAOfaR6DA9t0d6ywrG92yKuuCZEqxWRKoXNCsABZ7AwZeX20l9E58Pen43zjb4I59VejkSFI7jET4DSQpKhiAue9gVxkaGyXYgHXRaeeo3C2mBqd6bjTi7XvP459F1rr6qgyujpmi8iduuF/lo/WgoPehphgibnELkBR6gNKnnW3xZWSyL1Cl9wbDu7hQl9evCC7ffmezCdiOPCPXw/u+m0zcV/rpUgMpbQUnOrcgIJS0cvNgD0K4jsTE1izUKE+mSvBhj89rhkpKLVEIuw22PbvuiedFQrZZOOyQgukMH/lpQxOIhRh+wPqdqvRiQEAAA==" + } + }, + { + "ID": "bfd1e8521988820f", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_ba26dfd9500181a28cbdb57cf151bdab742d5c42/tables/anonae545bb1d06adf3bddacbe1c848bac5535d5c638/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "25276a787fb2b997100fc879914c1984/11477803777272430557;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_ba26dfd9500181a28cbdb57cf151bdab742d5c42/tables/anonae545bb1d06adf3bddacbe1c848bac5535d5c638/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:44 GMT" + ], + "Etag": [ + "gkt+/o1d1FXt/vsRharYIg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qnZ5do6+cbphi6RZTolxUHZSQWRXqm29oCVZTklyTmBOWXFwOVGQP5RWBmdLVSGpgsAwonKtXqQFgGSrWxIDZCLgkuZ4ghlwyXMwLJxdYCAOaAQ86wAAAA" + } + }, + { + "ID": "7e930494359d15a1", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "375" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "818e5e2b30431e00c594d2a5e3de0c64/3072688484351327269;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7ImNvcHkiOnsiZGVzdGluYXRpb25UYWJsZSI6eyJkYXRhc2V0SWQiOiJ0b2t5byIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTkifSwic291cmNlVGFibGVzIjpbeyJkYXRhc2V0SWQiOiJ0b2t5byIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTgifV19fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiQnNlTkFwTFFlMHdUUlJpQU9ZajRodFA1QTg4IiwibG9jYXRpb24iOiJhc2lhLW5vcnRoZWFzdDEiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:45 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/7NWNzeXzF5yRtkXOkcv2EpvA8YE\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKVSXW/aMBT9L95rId+f0tSxrUNoKNCIqmXrhBznkph8OMROUIr473MCfaFT+zD55fqe43POvfIRZbSMkY8imuwbqLtPOxahGwQCJ7L7jOb4l1uq5nf3ZzGdwUO8zGfBvAD8OOWKEzwGL/D08sPqQpE9LTLS6ndVO3HXd89IitBeOG5yAmJUsVqMHFv3Mad4VMpbCpgLbfyVQzCp5vegHlZhSCeL9c5MxdKauK6U4JBv57TMpFAqRMV9RTkcDuOEsSQHXFE+JqxQXsMrra5UNdsBEVy5MlbkYFx5x+02ZwQLysrPVxFlDPk2hC3UUBJA/hFdTGb/GPDMHpD3R3u1k8Rrw9MNIqzc0qSpL5RjL7rqKumOvi2Wa9Qzqq4HOGtqAisc5cCR//ujcDEWmMMZFSzrmOyJ/vG501cbXdVc1dP0jWY7njy27qiqulFlG53+SA3ggpZDtMH345X8n6uHTie5Ey6waPgws6z6VYQPQTALpugCUhmLDARSwzkeLXqeZhm2o+m6aWmeiQZyLd5glj6svuFQb6DANJeoYduG5xmGZlqjSHOFqrFCeFh3vIwYCUnoPt1nuRuxKG2+xNBCziqox4nUaCkBTAhrStH/UnT6C+FvRTNtAwAA" + } + }, + { + "ID": "d43750b3a1dc541d", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "373" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "547f566cb95c3a4c70dcf5e9ddfd38d1/4636862898959463605;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7ImV4dHJhY3QiOnsiZGVzdGluYXRpb25Gb3JtYXQiOiJDU1YiLCJkZXN0aW5hdGlvblVyaXMiOlsiZ3M6Ly9kdWxjZXQtcG9ydC03NjIvYnEtdGVzdC10YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTguY3N2Il0sInNvdXJjZVRhYmxlIjp7ImRhdGFzZXRJZCI6InRva3lvIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIiwidGFibGVJZCI6InRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAxOCJ9fX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6Im9jUjNjT1RISjhJZFBsQlBVbXBHbno1bXB1SyIsImxvY2F0aW9uIjoiYXNpYS1ub3J0aGVhc3QxIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:47 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/d9roD_jNaE9oGcJfaDXaviWBK_g\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAK2S227aQBCG32V7G+MT+IBUtU1IKQHRiJomalNZ6/VgFmyv2V1DKeLdOzbkIqhKe1H5Zj3zzzf/zO6BrHmZkj5JeLapQe7frERCrghommH0iUzot6C0uoNgXAxHME/v89F0UgB9GCozDaUYxKspvQ3FkN0t6OCRbvnD9TjOnghCeANO65yBNiohteF7Tp8qTo0S/5ZAlbY7gs1c9jn6dBeMEH59Py+qYfmrV1T1GBEK8sWEl2sELbWuVN80d7tdJxMiy4FWXHWYKMxn8+bWMSspVsA0unvZ2MTBlPlKt3e5YFRzUb69sIg2sHYGC5BQMiD9Azk3Gf1hwJO6zbw+2nM7FF42PF4RJsoFz2p5lhwaaLSvsDu5fYxmH26i5pZ+akmZbtJK1JJBRJP8HwymVFMFp6wW673AmG5KT5HmFDuWHVih7cS254f4eY5vWVZsYbjxl4LSvGzdzSXHqqy5m8udJxtDo9D4K7LD1JZcUhXpf/8f3B8vwB+FLCjujNx8+UqOOIrSVNeqXSKemg3P5tPpaDok5yTHWtYKmISWEfGi0dk91/Ntx+l6geOSViz1Zc53bbch1QpkDAXlOWZdz3PD0HXtbs9I7EBbtih0SB0/XDM3YxnfLDfrPEhEsqzfp7CFXFQgOxkytpwBZUzUpW4ePzn+BuBYpLPEAwAA" + } + }, + { + "ID": "3c8bb05c4a5c9ea1", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/dulcet-port-762/o/bq-test-table_20180912_1679797627000_0018.csv?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "1fc58c5249eb700e4a0de795db37432f/14678210204787978493;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/dulcet-port-762/o/bq-test-table_20180912_1679797627000_0018.csv?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "253" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:47 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:47 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uqw1DYWtC5WmeMTgDO_UckYCG0UISGi84UhZMb9OnZuT_O1ujFPbt1br92Oor7qGkRCJfvUMUFM5p66yZbeplFui9B-Zw" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vIHN1Y2ggb2JqZWN0OiBkdWxjZXQtcG9ydC03NjIvYnEtdGVzdC10YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMTguY3N2In1dLCJjb2RlIjo0MDQsIm1lc3NhZ2UiOiJObyBzdWNoIG9iamVjdDogZHVsY2V0LXBvcnQtNzYyL2JxLXRlc3QtdGFibGVfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDE4LmNzdiJ9fQ==" + } + }, + { + "ID": "0142332eed6f61a6", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/tokyo/tables/table_20180912_1679797627000_0018?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6642c123742c2c21ccceb77849a18371/16242385718874188173;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/tokyo/tables/table_20180912_1679797627000_0018?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:48 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "30a0a801f4883cbd", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "72" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "084bd9ed16399eb1676e3634b6536482/17806560133482324253;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJkYXRhc2V0UmVmZXJlbmNlIjp7ImRhdGFzZXRJZCI6InRva3lvIn0sImxvY2F0aW9uIjoiYXNpYS1ub3J0aGVhc3QxIn0K" + }, + "Response": { + "StatusCode": 409, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:49 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:49 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKXMQQrCQAwF0KsMWbcgIoqzE/QU0kWchDKYmjJJwTL07o54BHefx/+/ApeiBWL9BYN4r0A6YX5BhFH0gQIdFEbTr9AyS07o3HBiMxy56UVagdZwe2dzi+GKjsYeaJHE3s9avD8d99H1uSpsQwdJqQ0Pu/MfN9sHl9pVZ74AAAA=" + } + }, + { + "ID": "435c8297bd27c6f1", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/tokyo?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5a36119c792ae24c1b548ca1aa3e0969/996329547656895149;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/tokyo?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:50 GMT" + ], + "Etag": [ + "x0yfw4kU2qQ7q7BjenGZPg==" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:50 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAH2QUW+CMBSF/0v3qiKgICRLNjNjTLa5EReTLXuo5VIrhUJbZMT431cMLssyfT33nO+eew8oZXmMQrRhtKxANjcx1liBRj0EGlMz+Ro2ST1K35zy1S/96Q7y+fsLvb01DtYm44oT0P1CSN33PSfUIm2EGSrgySPLU2PZal2o0LLquh5QISgHXDA1ICKzznutvWMVUuyAaGX9QVpdJ2Wd2Z0QQQIScgIoPJy1Rdvp7OuIi396omMPYUJAKRR+HJAU3FDQOlqsZlHbvgDCMJ9LURVG70BryTRIZbI/ieX6+UpgWecX/JUCOW1mGWbcqK7nuUHguvZo3N/YEz20RaYD7PhBSlxKKCu3ZconG7HZVncx7IGLAuSAGsieETCHiCrX7Ud/74pm9w9XykWA41O7zx4iErBmIl+xrE3aY8e2R85wNPa9wAA4VvpJxCxhEF+yCHIimBFWDPdz8+gtmJyNjt9fKYgcZwIAAA==" + } + }, + { + "ID": "4419c23c7fdd82be", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/tokyo/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "237" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8a858541fcc6d3590c4264dc0214a934/2560505061759881789;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/tokyo/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibmFtZSIsInR5cGUiOiJTVFJJTkcifSx7Im5hbWUiOiJudW1zIiwidHlwZSI6IklOVEVHRVIifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJ0b2t5byIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMjAifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:51 GMT" + ], + "Etag": [ + "2ztXYQO6ZcAVAJRmuK6aPg==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2S3U7CQBCF32W9FXa7SgtNuICEEBRRa2P8iSFLO5SVtlu7i7US3t1pgZAQjKYXzcyZ+c6cpmuylGlIXDKT0ccK8vLMiFkM5JyAERH2+bd5er6/tV+C3mPvyktW17a4i7pdnJDVXriKAzCNTOWm4djcNWpZqmYNmXJmtVnH4lPLdjr42NxhjE0Z4wzXNcTzsUyXCFkYk2mX0qIompFSUQwik7oZqITu76KfnGa5eofAaHpkSkNhhAYUandau2v6nyPqGQ/mkEMaAHHXZGcyOhEO53dOtVqb7Rnbzp+OG8wdLCARldVcQhxq4r6uSSoSdN++kFhmVfXge6PJEHcO+irRB3008QfDgUc2b4hFqV8aQBypgmE5VmnkQ37c9lSxr4IchJEq9WVNt1oXtmNx3rJa7LL6Bb4ymZ8YsNuYp9qPhTY3KpQYJPyFsTvV7/XHg2pDBTUQW0JL0Ujx0y4AMRbZ/ABvZEBQjAIAAA==" + } + }, + { + "ID": "a60d55e8257fb336", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=d3c790e6cbddf96f2451698f679d71dd3d2c50a7b156443ba891830c7856" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e18655e0be1ac048e62f9aab46b1b4a2/4124679476351241165;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "LS1kM2M3OTBlNmNiZGRmOTZmMjQ1MTY5OGY2NzlkNzFkZDNkMmM1MGE3YjE1NjQ0M2JhODkxODMwYzc4NTYNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImNvbmZpZ3VyYXRpb24iOnsibG9hZCI6eyJkZXN0aW5hdGlvblRhYmxlIjp7ImRhdGFzZXRJZCI6InRva3lvIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIiwidGFibGVJZCI6InRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAyMCJ9fX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IkFGY2t0SXBOQmNjR21sMmZpZjZUZnhxeFVZRSIsImxvY2F0aW9uIjoiYXNpYS1ub3J0aGVhc3QxIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg0KLS1kM2M3OTBlNmNiZGRmOTZmMjQ1MTY5OGY2NzlkNzFkZDNkMmM1MGE3YjE1NjQ0M2JhODkxODMwYzc4NTYNCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOA0KDQphLDAKYiwxCmMsMgoNCi0tZDNjNzkwZTZjYmRkZjk2ZjI0NTE2OThmNjc5ZDcxZGQzZDJjNTBhN2IxNTY0NDNiYTg5MTgzMGM3ODU2LS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "849" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:54 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/FHFVD80dL1k30b7opqCD2hGbWU8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Guploader-Uploadid": [ + "AEnB2UruRN6zQMcsk1zkSsjKyRLcL3Ja1lBrAMqkDKB5kWBMfcqiazujCVu1PpY_4q0ubh3N-KhwavsTduteJAOU3l7_mMC-caaUCebEJStzEikOlwpV2_Q" + ] + }, + "Body": "eyJraW5kIjoiYmlncXVlcnkjam9iIiwiZXRhZyI6IlwiTGFaOG4wNEQ4S21HSWVVZFBsSU5MbWVhV0dzL0ZIRlZEODBkTDFrMzBiN29wcUNEMmhHYldVOFwiIiwiaWQiOiJkdWxjZXQtcG9ydC03NjI6YXNpYS1ub3J0aGVhc3QxLkFGY2t0SXBOQmNjR21sMmZpZjZUZnhxeFVZRSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYmlncXVlcnkvdjIvcHJvamVjdHMvZHVsY2V0LXBvcnQtNzYyL2pvYnMvQUZja3RJcE5CY2NHbWwyZmlmNlRmeHF4VVlFP2xvY2F0aW9uPWFzaWEtbm9ydGhlYXN0MSIsImpvYlJlZmVyZW5jZSI6eyJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIiLCJqb2JJZCI6IkFGY2t0SXBOQmNjR21sMmZpZjZUZnhxeFVZRSIsImxvY2F0aW9uIjoiYXNpYS1ub3J0aGVhc3QxIn0sImNvbmZpZ3VyYXRpb24iOnsiam9iVHlwZSI6IkxPQUQiLCJsb2FkIjp7InNjaGVtYSI6eyJmaWVsZHMiOlt7Im5hbWUiOiJuYW1lIiwidHlwZSI6IlNUUklORyJ9LHsibmFtZSI6Im51bXMiLCJ0eXBlIjoiSU5URUdFUiJ9XX0sImRlc3RpbmF0aW9uVGFibGUiOnsicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIiwiZGF0YXNldElkIjoidG9reW8iLCJ0YWJsZUlkIjoidGFibGVfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDIwIn19fSwic3RhdHVzIjp7InN0YXRlIjoiUlVOTklORyJ9LCJzdGF0aXN0aWNzIjp7ImNyZWF0aW9uVGltZSI6IjE1MzY3MTIyNTM3MzAiLCJzdGFydFRpbWUiOiIxNTM2NzEyMjU0Njg0In0sInVzZXJfZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9" + } + }, + { + "ID": "6865a4cf1b054259", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/AFcktIpNBccGml2fif6TfxqxUYE?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026location=asia-northeast1\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "0d1c53a0dd6b08ed6027aa2e23b31c37/5760911484980527965;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/AFcktIpNBccGml2fif6TfxqxUYE?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026location=asia-northeast1\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:55 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/lv0RANluI0CMR6eZVHCyzAL9ssQ\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:55 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Q32uDMBD+X+65HTG22vrWsU6E4cDZhzGGpDGuadU4c0KL+L8viYPCnkYe7rjvx32XEc7qmIlK9KLlAqIRul6dBcekhAjKoeYCl53qcRkGFBaW7ZDdM79g0qWPnMdNTStZBXl1/b4e3veGVSvOUKrWEJmWbNkag5NgGj2YFsBVW8mvof+ljNY0v3VmO7y87p6cnpUW0PwkGma7Soq61BB9jNCyxlJdWQDOwrc8S9LYuN/xodF3PEnzfbzPYPo0AUqhUbZufc6O9T/OLhkyLWYU1eWmrLOVzhPbFZR4G7L1aOEF4da8gIaEkIIQSmCazFqNDAft7jKdTZUd0nSO7UbSxOKOwHsxx5PuFm/tB6FH6doPfQKO3ONfbBVsVmB/t+lqYcWZtYCIPJBp+gGDJYl06AEAAA==" + } + }, + { + "ID": "04b944990d83c523", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/AFcktIpNBccGml2fif6TfxqxUYE?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026location=US\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3d3c0d19511f0863336b6c9e46a0f4fe/7325087003361639661;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/AFcktIpNBccGml2fif6TfxqxUYE?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026location=US\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:56 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:56 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAK3MvQrCMBRA4VcJd25FSqmQTcEWHbpoBxGHND+lmOTWJIVC6Lub4iu4Hb7hRJDOoQMaf+GBPiMINGy0QGHQ2DMNGTjJPG5iMdQ4W5HMSO/ZIBO2GIjalJIr9kTMmsuQT+hCfqgK2t12x5q/w2VqT5w3RhdqVNVdLZ+le5xhfWXAUaRRuS//uF2/jITznN0AAAA=" + } + }, + { + "ID": "d53ddaaf6764efaa", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/AFcktIpNBccGml2fif6TfxqxUYE?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b6dccabaa46625234b49c9291cc8d4ee/8888979947288032381;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/AFcktIpNBccGml2fif6TfxqxUYE?alt=json\u0026fields=configuration%2CjobReference%2Cstatus%2Cstatistics\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:56 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:56 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAK3MvQrCMBRA4VcJd25BSqmQTcGKDp10EHFI81OKSW5NbqEQ+u6m+Apuh284CXQIGICnX0TgzwQKnRg9cBgs9sJCAUGLiJt4pBZnr7I5HaMYdMYOiZlNObtiz9RspaZywkDlvqn4oZVvukzdUcqzs5UZTXMzy2e5P06wvgqQqPKl3tX/eq5fsiN8xtcAAAA=" + } + }, + { + "ID": "f3e44228be7ec479", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/AFcktIpNBccGml2fif6TfxqxUYE?alt=json\u0026fields=status%2Cstatistics\u0026location=asia-northeast1\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ac489408d3334bfa6f944e320517e1ae/2048040168469915989;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/AFcktIpNBccGml2fif6TfxqxUYE?alt=json\u0026fields=status%2Cstatistics\u0026location=asia-northeast1\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:57 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vLzotdoIeRAfAq5XaeSND9KTbZc\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:30:57 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAF2NywrCMBBF/2XWRdKmD+1S1KVC8AdikkWgbUoyRaTk381E7KK7mXPu3FkhoMQlQL/myUAPl8f9CrHIuw1oVbbKm7S66WlHCpUNb7uyqhrecQY57HHv6vZYJ2cmvTctP1XJKDfOg6FaQeXQswMrYHBS00s7zQve7GACnab4Bs4f/EEqcQsmLNybCN/AP8MJvaQWRjmviTCIMX4BAOv1MfoAAAA=" + } + }, + { + "ID": "9a6e2acac01a1c46", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/AFcktIpNBccGml2fif6TfxqxUYE/cancel?alt=json\u0026fields=\u0026location=asia-northeast1\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "0" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e7e3b184932e821c03db0b49e6b11914/12089387470003529117;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs/AFcktIpNBccGml2fif6TfxqxUYE/cancel?alt=json\u0026fields=\u0026location=asia-northeast1\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:30:59 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/FYRZenj0_wi9EAWS9uhnL30WT5s\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKuuBQBDv6ajAgAAAA==" + } + }, + { + "ID": "f7d7c99e6fc38d79", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "229" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5e2ae3ad8217a8632dd2e8974d55f3e5/13653561888889789997;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUICogRlJPTSB0b2t5by50YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMjAiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6ImlNUk1TMG5QOThkYWtTOWo4SHZtbHJ4RHN3ZCIsImxvY2F0aW9uIjoiYXNpYS1ub3J0aGVhc3QxIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:00 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/TwqWc01yE5HaA4dg8gGAcv2ZdsE\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAIVTXW+bMBT9K5X3NjUBzHekaYsSmqKlWUfoqlWVIn9B3AAm2EkaVf3vs2m6h2jqxIvxOfecc++FF7DhDQUjgHm53bHu+OlJYHAJmEKlvn0Ec/QQNbY3jb7Xs5Td0dsqXcxrhu5n0soP23tiO8fEv0Zjj5ZRORuTPXygMnkEWoQbYbqrCFODVnRqEAZwhCRHg0a/rRmSyhnym+xmaTe3cUTRZhk/Rdf7uuqep/JAtYRkVTHnzUYLrZVq5ciyDofDsBSirBhquRwSUVvv4a09tNpOPDGipHVmbOnGpPWB29dKEKS4aL6cRdQxdG3GCtaxhjAwegEnk/QfDb6xe+Tj1t7tNPHc8PUSENEUvNx1J8qLEc2PrXYHP++S7LcW6Fs20OkAlsk8meQXny+ush83F0psjmKoEK7YCtpOZMcOXDlBGOsngKFt2yvbhrYWokwq3vROuaH/v0OKFJLsDV1hBANa0Ni3tYuDYEQwxX5ICsd3MEU49CD1iWfq+jR9FWpE40KqC5EHC08XxaEd+25AMSZB6BY4oJHnoABR3M+jY0ixKZetkPw0tkmWjPNklV6tFkkyTaba4NDxc9Z9lmpSnt0tJpqtOW3HhaaZiaWLPMnGkzz9ZYCdZHNWInJcbiswKlAl2au2lgqpnTRDMSezAa21SBczcAK5Hh/pCX1KM0ZeG56j+wkdCP04Cs1npMmdOsMCG/bY3232JjVr1Gndb1sFJokO2K1YjbiOB9wgcOPYdR3PH2AnUrYjahUjGMYb4pak5Nv1dlNFWOD17htle1aJlnXDUmvsOWGIELFrlPl/wOsfaRg8CQcEAAA=" + } + }, + { + "ID": "db51252884dcb040", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/iMRMS0nP98dakS9j8HvmlrxDswd?alt=json\u0026location=asia-northeast1\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "41e0796c438e8d481617e749151a5c1c/15217737402992776893;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/iMRMS0nP98dakS9j8HvmlrxDswd?alt=json\u0026location=asia-northeast1\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:02 GMT" + ], + "Etag": [ + "q0P763YqUXuYxkSz0uhmww==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/22Qy27CMBBF/2W6DRJtJB6RWJQ2AiRANAGpqOrCOBMw+BHscQNF/HsdWolNVzNXPnfmji9wELqABDZie/Rozw9bpLemydB5SS6UymiHEAES2wby2F50O/H6uHr369Mh/277narrwSAQju9QMUguUAqUhYPk4wKaKQy2W4mAzlWj8mU2mY+CVqZo9Hw1nT4Ppylco7vDK3d3TObLdJRm/1k+rxHszSbDEi1qjk2Aypo9cpo0txVecqRWZSy1up0nuNG3FzHLZnlbL/q9gh3y/r43/lLSnl5dXQRKGs5IGB1A5gRr6TBgh8zRY4gJZIjJzNThSojhTw/PhG5hDUfnsNkQx7/rXoyqJFLIRtZjBJyFvxoLgqRk0uH1B0TcCXGJAQAA" + } + }, + { + "ID": "6945493da1918c63", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_ba26dfd9500181a28cbdb57cf151bdab742d5c42/tables/anon32d6dfa42f428c9709536dbbc673fb6d841a6adb/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "41e0796c438e8d481617e749151a5c1c/6812622110088450565;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_ba26dfd9500181a28cbdb57cf151bdab742d5c42/tables/anon32d6dfa42f428c9709536dbbc673fb6d841a6adb/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:03 GMT" + ], + "Etag": [ + "fsFBenpiboN23psVgfr5bA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qnFbs5peYVZCbl+xkZFxSHpacVmSY52toCVZTklyTmBOWXFwOVGQP5RWBmdLVSGpgsAwonKtXqQFgGSrWxIDZCLgkuZ4ghlwyXMwLJxdYCAFDbuFmwAAAA" + } + }, + { + "ID": "05b9820d53c796c1", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "375" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e70d520f80907ec0e0a2f290060f833d/16853969411605286733;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7ImNvcHkiOnsiZGVzdGluYXRpb25UYWJsZSI6eyJkYXRhc2V0SWQiOiJ0b2t5byIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMjEifSwic291cmNlVGFibGVzIjpbeyJkYXRhc2V0SWQiOiJ0b2t5byIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMjAifV19fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoieDVJMG9YdmZGNkcybFVuRDQ1MU5VUlhZT2V1IiwibG9jYXRpb24iOiJhc2lhLW5vcnRoZWFzdDEiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:04 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/8szw75xMVgNMojn8m5wNPl6lJuc\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAKVSXW/aMBT9L95rIc6XkyBNm7RqiI2mCJWt7Tohx1yCwbFD7JAyxH+fE+gLndqHyS/X9xyfc+6VD2jD5QINUMbzbQ3V/sNaZegKgaG57T6hMX2MJQ6u4+/FcASzxUSM0nEB9OdQO7H+00Th882PPL1RaxkXYZNOBBHfavaErAhvhRe1YGB6papMLyLegGpOe9LeVkC1cfvP4Qir+93yKxl6Yiavg9BNZ9P7h1uorYQGsRxzubFCK2NKPXCcpmn6uVK5AFpy3WeqcF7COzvPKSu1Bma0c2Hs2MG084bbJ6EYNVzJjxcRbQz7dgpLqEAyQIMDOpuM/jHgid0hb4/2YmeJl4bHK8SUXPK8rs6UQyt6ty+tO/pyO3lALaPct4BWdcXgjmYCNBr8ei/cghqq4YQatdkr2zPt41OnreYedmOcuN7cJVFiD/EijPEcYw+j42+rAdpw2UXrfN9fyf+52o0c7U60oabW3cy2alcxnaXpKB2iM8htLNYRWAWneLxoeW7ok8j1PBIEJEAduTKvMBKFrVKtoZpDQbmwqE+InyS+7wZhL3Njg11VmIR6UbJhfs5yvl1tNyLOVLaqPy9gB0KVUPVzq7HjDChjqpam/aXo+BdNCurGbQMAAA==" + } + }, + { + "ID": "01f1f14c432b3c00", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "373" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a29cb76b0fd3a4de21cf9ab85ba98319/18418143830508324829;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7ImV4dHJhY3QiOnsiZGVzdGluYXRpb25Gb3JtYXQiOiJDU1YiLCJkZXN0aW5hdGlvblVyaXMiOlsiZ3M6Ly9kdWxjZXQtcG9ydC03NjIvYnEtdGVzdC10YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMjAuY3N2Il0sInNvdXJjZVRhYmxlIjp7ImRhdGFzZXRJZCI6InRva3lvIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIiwidGFibGVJZCI6InRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAyMCJ9fX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6Im9WWnFkVGpQTXhFTUtuUmxONlk5bVlySWVGUCIsImxvY2F0aW9uIjoiYXNpYS1ub3J0aGVhc3QxIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:05 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/NPfQy2UoEEGvil4wFtl45Nc9hDc\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAK1SXW/aMBT9L95rQz4JBGnqphYQKo0YC+3adUKOcwkGJw62A0WI/z470IexqdvDlBfnnnPPOffaB7SmZYZ6KKX5pgax/7DiKbpCoHCuqy9ojJ+7pRPcdu+K4Qhm2YSN4nEB+HEo7Xiy+LL3ZrzfH24pC3YDxYJ2TKLlLXlBWoQa4axmBJRVcaGsTuj1sKTYKvXfErBUbos/PG+yZDW5f+3f35VTFodPUfEkRjCYaAkJbDGm5VoLLZWqZM+2d7tdK+c8Z4ArKluEF/ZbeHvr2ZXgKyBK2hfGth5M2u+4XTNOsKK8/HgRUcfQvVNYgICSAOod0Nlk9IcBT+wGeX+0NztNvDQ8XiHCywXNa3GmHIxosq+0O+p/S6afbxJzS69KYKIMLHktCCQ4Zf8QMMMKSzihiq/3XNeUaT1VzGnuOW7XiVxv7oadSH+h13EcZ+44nmPyZSAVLZt0M0F1V27u5nLn6cZSmmj9VbJF5BZdqkrU+/4/dH/8IjzgosB6Z+jm6wM66lGkwqqWzRL1yWx4OovjUTxEZ5DqXtIQiIBGI6GF4bltP+y4nhe2/SBADVmo3zAdxijVEsQcCkyZRv0w9KPI992gbaVuVzkuL1SEvU60Jn5OcrpZbtasm/J0WX/KYAuMVyBaudbYUgKYEF6Xyjx+dPwJAYwZfcQDAAA=" + } + }, + { + "ID": "69c877ae66307f4c", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/dulcet-port-762/o/bq-test-table_20180912_1679797627000_0020.csv?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "1dd80d8c3edfb659b7bbd5fdbdc7651d/10013028533309096741;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/dulcet-port-762/o/bq-test-table_20180912_1679797627000_0020.csv?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "253" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:06 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:31:06 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo5hheQHSA-BVXA_izvYruXRWA0LNZ39C4qofT-2fPF1LGhOuodKQteoYrAXlghKODkXEIFLooqXCGI2xUVJFSM71lEdw" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vIHN1Y2ggb2JqZWN0OiBkdWxjZXQtcG9ydC03NjIvYnEtdGVzdC10YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMjAuY3N2In1dLCJjb2RlIjo0MDQsIm1lc3NhZ2UiOiJObyBzdWNoIG9iamVjdDogZHVsY2V0LXBvcnQtNzYyL2JxLXRlc3QtdGFibGVfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDIwLmNzdiJ9fQ==" + } + }, + { + "ID": "3a4b7c3f4e7458b7", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/tokyo/tables/table_20180912_1679797627000_0020?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9958c7bef1b56ee97602d73e00fd37f9/11577204047395306677;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/tokyo/tables/table_20180912_1679797627000_0020?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:06 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "adbb2de3de4040fb", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "232" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d9f3325c5ce08772885d9f11f7fc478b/13141378466298344517;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoibiIsInR5cGUiOiJOVU1FUklDIn1dfSwidGFibGVSZWZlcmVuY2UiOnsiZGF0YXNldElkIjoiZGF0YXNldF8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMDEiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIiLCJ0YWJsZUlkIjoidGFibGVfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDIyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:07 GMT" + ], + "Etag": [ + "oE4MvRlbpGzA05nLkGiiHw==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2SwW7CMAyG3yW7DpJmo4VKHGBCDKns0MFpmlBoTclok64JdAzx7nO7ckEgUJQodn7//mTlQDZSxcQnS5l8b6HYP1ixTIE8ErAiwbwePU93YbrMx78D1lHBZizla9nvo0JWdfE2jcC2cl3YludyPxZWGLALzpwu6zl84bheD5fLPcbYArfTrltcV3CO5gbSVSDVBlusrc2NT2lZlu1E6yQFkUvTjnRGT9R0x2le6C+IrKFnSLRBMvQONlqzGXoPYq0JYQUFqAiIfyANwuTCYFDftP9/vY1y6lDrb/MccWbRGjJRgawkpLEh/seBKJEhG1GV3T6vrm/z6SicvJDjJ9aobTbcW0AtYaQOA62SGRTn6VCXpygqQFip1UzW1k7nyfUczvFgvern/OSyuCBwuwhb1afC2KmOJVLGVzwa1NlgGIyqCh3Vhpiav5PjH4br7762AgAA" + } + }, + { + "ID": "c0729a14dc303d4f", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0022/insertAll?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "121" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a7127fb39a13cc3555af0ff9b97477e1/14705553980384554453;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0022/insertAll?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJyb3dzIjpbeyJpbnNlcnRJZCI6ImNJa3djSEdOa0dBR1RnWTBubjhWbFFhb1NuRSIsImpzb24iOnsibiI6IjEwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwLjAwMDAwMDAwMCJ9fV19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:07 GMT" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/42MuwoCMRBFf2UZ20XWNp3oFim0WLASi4kZQzBONA9RFv/dYQVtvdPMOXDvCGfPFhQY726V0nNW0ARaY0HNmVJZhjBQvkYBaMFPrk8ppgxqP4qw9ADVtUA/mQhzZBn1fMfgrRRDPGLxk2RBS6Y6zacoLHihnNGRgP40mu1u0w961QhVUs2i+zPz7wevg9wb8ASitOAAAAA=" + } + }, + { + "ID": "eb07855b7046be89", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0022?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "58b3f28b9286ad9be07ddad223294a26/16341785989013841253;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0022?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:07 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "4c2f87b45d2066f3", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "163" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "9e495a194d645c4257f06ffe67ba0ac5/17905960403605200629;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiYmxhaCBibGFoIGJyb2tlbiIsInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiOGw4ZU9FZG15d3hPRVU5T2paZlVwaG42Q1NMIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:07 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/145v-gcAADv9Zmv2PH15HLO9A-s\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAL1TXW/aMBT9K5H3WghJ+EgiTRsqqEVDpQWyaZRqMs4lGBw72E4AIf777JQ+bKv6uJfIuufcc+65ds5oR3mKYrSi2b4Eefq0FSt0g0DjzFSXaIwXIW+1B+G3/G4ESfrIRg/jHPCPO+V67U7VyEi/P6iiRV75j/de5348ifoNtURGhFrhtGQEdKMQUjd6XT9OZs2QhTAZpvnpcJwMk2iyXayTYsO7t7Ox6VLA1mPKd6Z3o3WhYtc9HA7NTIiMAS6oahKRu2/zupXvFlJsgWjl/uXlmizK/cDtCxMEayr452RmnA19CmuQwAmg+IyuuqN3Yryya+TjNG8Ohmg8LjeICL6mWSmv1bPVmZ8KY4iekuH0p+mpg1noekArhjfO60eKHXDDKSQVkmqLjh7mw2n/dj76PjRAqWAMGSan2Z6heI2ZgouxVRrrUllRe7Jug8mD5YOUQk5BlUxbVAJW9bSUV5jR9Kke4Y8c+2spB6VwZqVmJ67x0amlYifhcCzM3iB1aApc0zUF6SzrFEvkYO08e7H3YpdRd5ipnv+v8ct1IVRpSuqlEGNvXeY0t7peJ+j2PN/v9qJWG9Vkqf/FgsAukKfvIpf6LuQvyDE1N4GCbjeIDGD+msbKC3XLE7mOsN+LdiTISEb3m/2OhSux2pRfU6iAiQJkMzMaFSWACREl1/bxo8tvUzylmrcDAAA=" + } + }, + { + "ID": "ee5e91a8b4c0233a", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/8l8eOEdmywxOEU9OjZfUphn6CSL?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6f1b545d2e93cdd01d4538d8fc24436b/1023673323270248069;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/8l8eOEdmywxOEU9OjZfUphn6CSL?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:08 GMT" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/61PSwrCMBDd9xRD1iIWXHVXUETQgp+6qSJjM9ZAmtQkFUvp3W1jFx7A1fDm/XhtAMDIGG1YBG0PephrTj2az2aT76Mka7EYfuzQKIdv8I4IUkXvinJHHAQn5cRdkIEzu0l8nBmggyyMwgsbc7zL9jGZxzAW/rPDZ3FdolBDVCH1DeUvZwit9pxQL5SC72oyza9C6hyd+GoqNFiSI2OnTzZKOn8v4ybr0NXDJrZOTvFmvbjG+1W6XSbHQd8FXfABQ4/2rWMBAAA=" + } + }, + { + "ID": "2595ad8d754bf40c", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "270" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "db0451fd42f5e546cf6fff00b2a580c5/2659905331882757909;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJleHBpcmF0aW9uVGltZSI6IjE1MzY3MTI2ODAwMDAiLCJzY2hlbWEiOnsiZmllbGRzIjpbeyJuYW1lIjoiaW5wdXQiLCJ0eXBlIjoiSU5URUdFUiJ9LHsibmFtZSI6ImxhYmVsIiwidHlwZSI6IklOVEVHRVIifV19LCJ0YWJsZVJlZmVyZW5jZSI6eyJkYXRhc2V0SWQiOiJkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiIsInRhYmxlSWQiOiJ0YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMjMifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:08 GMT" + ], + "Etag": [ + "KnBUVD6XmEtMdjKdrRwgcg==" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Q0U7CMBSG36XeCt2KbrCEC4mLIaAXcxgTY0hpD6OwtXPtnITw7nZzeEEgkGUX5/Q7//naHdoIyVGAFiL5KqHY3hi6SAHdIjA0sf2JHM3eHr33LDTPfD3hRVQlLBkOLSHqOV6mDEwnV4Xp+B4JODVUg5kTx+07A5fMXc8f2M8jvuM4c/u73WbFeYL0bLiGdDkVcmNXrIzJdYBxVVXdRKkkBZoL3WUqwwdr/E1wXqg1MKPxkRJulTS+wg03bhpfo9gwESyhAMkABTvUKoxPPIzl2/V/p5dVDhsa/rLP3r4ZW0FGa5GlgJRrFHzskKSZdUNC5qWpI7d5XY5f4vApjOzUP5HSBaQniE+bLMtstDVgE5GDmnKqZBJDcdyOVHWoWAHUCCVj0cS79z3Pdwnx+nekPoafXBQnAK9vr1QDKdXmWXFh78LPZLSq8cNoGtYTijWBtjV7Rftf73B9ctwCAAA=" + } + }, + { + "ID": "1b71e2ad0cce4db7", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "297" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e72b30de3a240a5a044656a3fce8912d/4224079746490894245;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiSU5TRVJUIGRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxLnRhYmxlXzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAyMyAoaW5wdXQsIGxhYmVsKVxuXHRcdCAgICAgICAgICAgICAgICBWQUxVRVMgKDEsIDApLCAoMiwgMSksICgzLCAwKSwgKDQsIDEpIiwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiIxUmlnY1NUc2pGUTh0aUYwMHhrUnZzZXlyYVUiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:08 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/BAGzcS23vtRLYzEcmQit3LiWSdI\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAIVT72+bMBD9V5D3JZWS8CsFEmnaui2N0FC0QmjVKVJkzIU4AUywSZZW+d9nE7oP3daCELbv3Xv37uRntKNliiYoodm+gfr0YcsS1EcgcCZPlyjAP73SGH3zvhczH+L0R+7PgwLww4zrX25mTySy7IMIg8enKSnuqLAD+hCl/hJJEqqI0yYnIAYVq8XAdaxJHA3NkGYkWvDt7Z0n6K1h/NqFBw6nGscyi0O+Dmi5k7kbISo+0fXj8TjMGMtywBXlQ8IK/aVe/WDpVc22QATXX2np0gvX31D7lDOCBWXlxziSyhIewhpqKAmgyTPqeP1/2Lig28jbbl4UJFBqnPuIsHJNs6buTp8Vz+JUSUF0F0/DR5nTGlOhboH8eTQNF1qKBeYgVpZhesbYtFam447l61iuYRgr+ZlDgZMc/o+wbK1Hy6oRfS3HCeRXy3IplkJ79dzfBPE00npmXzOu+lrP6mum+tvdfqT2stIUuKBla2WhhN/vWufhEn3fj8xoHbX4d72p/lY1ZTUVl7YtpuHN14V/P5U8DYcAMkxO0T5HkzXOOZwlngssGq4KVys1hjCez/35DHVBKi2SFkBquFilhcKZ17bjmpbleI7nohZci79ibhv7M9JWpIBSdDO/jBapSmSB9QoKTGV5yHYcezy2bXN0PUhMTxgmK8QYW+54R+yMZHS/2e9yL2HJpvmcwgFyVkE9zCTHgRLAhLCmFOqqoPNvBYfAnOUDAAA=" + } + }, + { + "ID": "eb22cff0af71d27f", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/1RigcSTsjFQ8tiF00xkRvseyraU?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "ef9b6121be7f050669883891e33edfe3/5787973794207104820;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/1RigcSTsjFQ8tiF00xkRvseyraU?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:09 GMT" + ], + "Etag": [ + "/e7dTLxDvn70K63bYxw3/Q==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/22PTU/CQBCG/8t4LaGKoaYJBxVQojG2wMEYD9vttC5sd+vuFNo0/HemmHjyNF/PvPNOD3tlcoghU+VPg667KpGSIUnRN5o8h9oajxAAkiiZHGOUb17b+cFE4ct0kn20x8k4mc2Y8PIbKwFxD4VCnXuIP3swokJeU6ZuiBnq6qFcvW0WT4sUTsEfoUWG+h/i6xTAzmYpFujQSBz0a2d3KGk1WM8bLZFGtXU0iqY3cKEvk+tUlXK98btlckdqGYbtPj147JzYMqWtFKSsYXC7ZiNAloR+6Aj9u7MSvcdBJPwVfLRVrZH4OrkGA5CCn31WBHEhtOeGaap5pe+Lgn1hntojvw+3cDoDbXG7bGMBAAA=" + } + }, + { + "ID": "adadd13afa997262", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "338" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f2d238346b3788ff469978b870904074/7352149308293314756;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiQ1JFQVRFIE1PREVMIGRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxLm15X21vZGVsIE9QVElPTlMgKG1vZGVsX3R5cGU9J2xvZ2lzdGljX3JlZycpIEFTIFNFTEVDVCBpbnB1dCwgbGFiZWwgRlJPTSBkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMS50YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMjMiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6Im4yaUVyNHhsR1k2THNTU3JzRHhhU2NmMnZlMyIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:10 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/b_IQ02hGSsFhTTFbiLe9G7HVHro\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1T/U/bMBD9VyLvBzYJmq+SNpXQhiCUiNBCkzIxIUWOc01NnTi1nUKF+N/npEWa9gGTFcnxvbv33p39gla0ytEIZbRYNyC2nx55hg4RKFzo0wcU4R/DyuqfD6/KcQjz/IaFk6gE/H0szSwNby1nOY7lxTJJLjIagT8eXN5dCv6AdBHaFs4bRkAd1Vyoo4HnjOZxr3JoIPrPbHzvRTKOhTx/xjFZOBtwdZYEtohotdK5S6VqOTLNp6enXsF5wQDXVPYIL803vebGMWvBH4Eoaf7GZWov0nyH7SvjBCvKq5N5rJk1fAYLEFARQKMXtK8b/sXGDt1F3nfzxqCBmuP1EBFeLWjRiP3pS1sn2daaEN3Og9m9zumMtaH9Bp3NgtMkMK6n50Fk5FhhCSp1LHto+baT2t7A18tzBpZlpfqze+U2LXkOzJjeJOF0Ehufu99UaaKTA8YLKhUlqYDi4ItxGhtxEAVniUGrulGHBsOZTr2YTa//i0zhjMG/EU7bhhw0YdV5Tlr4x+3dM++iH6vQGZ2ODv9mv+13LSgXVLVtDCdJMDs9S8K7QMMbCREUmGzjNUOjBWYSXjVeKqwa2eprd+1YZvPJJJyM0T7Yta4DEAE7R7Rscfax6w1sR2uy3T7qwEL9EXP6/q8j7khKqNT+DuxGnXajRq0eLVOkUGKqRSLX81zfd127f3yU2UNl2bxUPnYG/oq4BSnoerlesWHGs2XzLYcNMF6D6BW6xoYSwITwplLtA0KvPwHa4weD+wMAAA==" + } + }, + { + "ID": "bc33f882b9544840", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/n2iEr4xlGY6LsSSrsDxaScf2ve3?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a692b811e555fbe1a66074ec23c81b36/8988380217427750996;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/n2iEr4xlGY6LsSSrsDxaScf2ve3?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:20 GMT" + ], + "Etag": [ + "SePSBe+EUFrqZSTfxB9l1A==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/yXNsQ6CMBQF0H+pozKIBiMJgygaEwelMuhWyisp1hbaYjCEf7fgdF9yz8vt0YvLAoUo52XTgv7OSrC38UjBtMIaF7WSBtACgSWlkxiuOIZ5kh1188R31sVbsdxFkROVylNgoEFSQGGPaq0qoPY8DhStoGC9WmnrbQL/r6dG+jzR606cHsHFYKzNoSOYMv8DK6eEosRyJR3MMBqmt7161wKs22BEGBh+YAMMcsYAAAA=" + } + }, + { + "ID": "7977497a948e0983", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/n2iEr4xlGY6LsSSrsDxaScf2ve3?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a692b811e555fbe1a66074ec23c81b36/511208429980347804;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/n2iEr4xlGY6LsSSrsDxaScf2ve3?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:30 GMT" + ], + "Etag": [ + "W1F92XraymntRQbo+afAvQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/yXNT0vDQBAF8O8yHk1BU6kY6MH/Ch5MgqjHzfYl3brdiTuT0lD63d3Y0zyYH+8d6MeFFRXUuO53QBzPOmg5hQoyeJV0eg4CyghquiQ/L59u8q9oxm3Qqmz43LS3u3K5TGLDTYUWEcGCigP1kTew+joNrAZvobOeo86uF/lJ/39C7h7j1d4/fy/epK6jPOxNbdt8h3lSnq1RxyHBj5qOGSmr8XejQt4jW4hgKrk4Fd7ztvfQtK5xQEbW2DVenFLRGi84/gH3ZSvQ8AAAAA==" + } + }, + { + "ID": "45574ac42a27e48a", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "300" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "13527f6a059baee6a455a783a443e824/2147440438609634604;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5IjoiU0VMRUNUICogRlJPTSBtbC5QUkVESUNUKE1PREVMIGRhdGFzZXRfMjAxODA5MTJfMTY3OTc5NzYyNzAwMF8wMDAxLm15X21vZGVsLCBUQUJMRSBkYXRhc2V0XzIwMTgwOTEyXzE2Nzk3OTc2MjcwMDBfMDAwMS50YWJsZV8yMDE4MDkxMl8xNjc5Nzk3NjI3MDAwXzAwMjMpIiwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJaVGZzdXRkSTJ1MVByeXJXazBGbjlOY295aXQiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:43 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/FInW9bX304XYgQ5Wny1hStPc2U0\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2+bMBT9K5H3ZZvaYEx4RZq2LqEVWpqmhCxtVQkZcyFeABMwjaKq/32GptLUbd2ELFm+555z7oNHtOVlgsYo5tmuhfrw7oeI0QkCSTP1eo9m9M4p8WjqfCsufFgli9yfzwqg64tGO/fLtRvfGHh0c5tdm+vyoG+WcsHICt8jRcI74qTNGcjTStTy1LbIeLUc3oVp08rEJ62+qA/1eovPS3fOxIFLldVAns54uVW5GymrZqxp+/1+mAmR5UAr3gyZKLQXv9oD0apa/AAmG+2VlqZqabQ31D7nglHJRflptVTKCh5ACjWUDND4ER15/T+U8YzuI29X86KggErj6QQxUaY8a+vj62PHEx4qJYiuV15wq3L6wrrQ8YKW3sybhIOPg/Pg6nJQ5MNF4E39Sfj+8mrqzQYJlbQBGRGsO9jVSaRbtqs+i9gY40gdfVgcokIkkJ8MwrOvM++/ciSNc/g7ghgflNkEGsnLvpqww/+7cUfpPhoxJ3VwjN1Yd+IUkxRS0x4xwCZ2wMQjSK3EsS2LqrzeTp9FS1EaLmHYcVyb2JQCxDFLTCtJDJyalm7Epkns2NEd0ve8BiphyptKNPw4jUngnYVe5J9Hc8+belMlsK/5a9Q68BUoDFbziUIrTFVzoWDdVPx56AVnk9D/3gXaBmaQUXZY7nI0TmnewJOSbiSVbdM1pbt1U1Zcc39+gY5BrtrHekDvsmsjLzqcbhqWrRMDG7ptoR5cy99ixHZ/3ZhepIBSHlfqeXNQ50QZrCMoKFf2kGFZhusahj4yT1XrJdZFIV2q2LbMyFjGd5vdNndiEW/aLwk8QC4qqIeZ4njgDChjoi1l9yeip5+0n2eyRAQAAA==" + } + }, + { + "ID": "47f9e953871d8291", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/ZTfsutdI2u1PryrWk0Fn9Ncoyit?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b8e4078d2fd34a6edc4fc201727f4ca7/3711614853200993980;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/ZTfsutdI2u1PryrWk0Fn9Ncoyit?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:44 GMT" + ], + "Etag": [ + "AKQWj2M3NfkhvZ42PxviOA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/51SbU/CMBD+L/UrJDiJL0v4MHAocY4xR0gwhnTdDQrdOtsbuhD+uy2aYKIm6qde7563XLsjG15mxCUpXz7XoJqTJeDEFjHoWqA2RyVLDaRFAOnSIL27yWzt3J+F+Wa1nXed6HXLx16vZxCaraCgxN2RnIPINHEfd6SkBRhapSDjDCFbCJqCMGhsKjsYhYl/48emUcjMNsJpEHj9wCf71k/sRaVkqo8asT8Yx9dHidiPfC/xbedrkv/5y/RIGQZjL/mO8PSJwsuqxj/a/D6acSJrmcaQg4KSgV26CbkGhiP7nlktGGC7kgrbF+cOOaAPk3mS6xqzkVOfRqpRs01nWF6FTDbcphWSUeSyNMDpg4lGUCIVsXwxKyRd8nHvNwg6UpKB1mBFLzvvDgNZVALQxEFVQ4swar7ErVF2cyo07N8ALzxfb3ACAAA=" + } + }, + { + "ID": "2553982631aee796", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon392c0889727aaeebbcd56dd30f5613b5527b8182/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "b8e4078d2fd34a6edc4fc201727f4ca7/13752962159029508612;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon392c0889727aaeebbcd56dd30f5613b5527b8182/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:44 GMT" + ], + "Etag": [ + "J5WSO78wI0zV3ElLcKd20w==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6WRTWsCMRCG/8v0KmWSzORD8NYe2gqCBT2UPcS6ytKlUk1dqux/N6xad+1SFryEmXnfSZ6Z7OEj+5xDH2bZ8us7Xf/cBT/L0wcf/DDbBOhBGvwy6s88fR0ZWzzhbqIe8+H7y1xiMRhER1gFn49XxSbaKObrKnzbw6I6t7GMUPaq6JjXJXGWAO+VZWJrUCnlJDu0UCblSW69LvZoQUxCOq01GkJrqp7kbJC/VgHHasvT/1NZlGi0I2YrjXUkOlAJZ5xUyETCSIHsmlR0O1Vz7i5MV9ttEqmL8Q9Rx9+7nll3YGrfbVLbTp0qKQ+nPsgosAIAAA==" + } + }, + { + "ID": "13f71ccbef91dad6", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026pageToken=\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "2fdc007d79ec19ab498ea08dbb090280/5275790367303980620;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables?alt=json\u0026pageToken=\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:44 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/VGhoMTYH5d0oo5eFRQfnWXetnP4\"" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:31:44 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAM2VXW/TMBSG/4u53cB2vnNX1K5UpKOrCttgU+Qlp8WQrzmORFX1v3O8thSJlsJgXRTlxn593pP3yZEX5KssUhKSOzm7b0DNX2hxl0Eka01OCGgxw70bEomPfkHtrv827w/gfTrKBudRDuKyX7/60P9cDifXb5yUlqUDZ+OLaXF5BboY2TcEizwUrEn4abHbCyXSrKZNloA+rUqlTz2Xh6nQogYdc8p8GjAeM9cL8HG5RymN8WUv83mclylkG5sxTEFBkQAJF6RS5RdI9GBHcdSvy692D1ttHB70P2yXuDqv0I0M33V7EYoSBULLspjI3Cwzx3I9xrln8yBA+RNkoOMcORllXAmlpXGPk6ypNaiYHjmZA81s85p0Xkc9cxRzGm2UspiZ9taSbufaHFifXu9NJWSp+ZtIITDh2+W+yKnv+I75fPhWSbVD4PrYPX0GJqxNTNjfM/k50mFtAl3l+HhSvuOxNpLibSLFH0NKwX0j1VZzJjOsRUKtGvgHYgGz3FYSs9pEzPpfs3WyQrPqD54Qq2093yCaAvsVzDk22YP9bOH2ria98XnnN/c/Y8z22pksP/rMHOzn17HZE6vr2/xP7vhbLFhqkQ005DgJ3vI7i0sGlvgKAAA=" + } + }, + { + "ID": "c8b227a96b7a2281", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/my_model?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "38531a00c54b0e04c83601fb097fd647/6912022380211392476;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/my_model?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:45 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "4a3e2801117dcc2e", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/my_model?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8235851eb506716912b992e86342842c/8476196794819528556;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/my_model?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:45 GMT" + ], + "Expires": [ + "Wed, 12 Sep 2018 00:31:45 GMT" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAALXNQQrCMBAF0KuEWbeShNLaHMClK3ciYdqMRUgykqQLKb27KZ5BPh8+b/M3oJQ4gdl+I4O5b+A44CuCgcXzhB4aSISZD4lcLrxGVy1QzrhQxSsX8TzUiBtOnoRb/UylfXMq7dBr47BgpmK1VGc5Km1VP4w1vR6klLZWncLHBnbkYX80MNcFppPdH2/2L6lBb0v9AAAA" + } + }, + { + "ID": "31a386ffea9e7dd4", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0023?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5e9d037939264596278ee677404beca3/10040372308922515452;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001/tables/table_20180912_1679797627000_0023?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:45 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + }, + { + "ID": "ad1c86aa72ee34bb", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "155" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "086104c5814119e861666406996e7c88/11604547827303626892;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ICoiLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6ImJzSUZmZjVmQ1kxOURGTXZTV0d3T3BmRHMxSSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:45 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/Mv8TNOflLzPguuj5N9GyEwhqN70\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAALWSUW/aMBSF/0rkvVWFEFJCQJq2CQKKBqGFsKprq8k4N8HFiYPtBDHEf5+d0YdtVd/2Zt1z7/nuufIJ7WiRoCHa0GxfgTh+eOEbdI1A4UxXn9AMf/eLzs3Y/5pPQ1gntyyMZjng+6m057UfR4uUzX7eZlX10osG02Nw2O6jfucJaRNqjJOKEVCtkgvV6nvd4XrV3shwkqa9dPTgDMaTeb26nx4WZTqWTqinJLB0Roudnt0qVcqhbR8Oh3bGecYAl1S2Cc/t133tumuXgr8AUdL+i2XrLNJ+h/aJcYIV5cXH9UqTdfsSUhBQEEDDE7r4hm/E+N3dKO+neSXoRs04XyPCi5RmlbhUT8YnPpYaiO7WwfJBzzTBjHR5mJPoPawrrZWCckGVqYZRHCy/jOLwW6CFSsIMMkyOqz1DwxQzCWeNkwqrShoz8zKU8SIy/SAEF0uQFVNGFYBlsyUtasxocteg/9h/fynlICXOjNUqmAWj2Lqy8koqa4trsLA1WS7mFmFYL2RhZT06Q//ZBG+AepPH/w97vgSnUlHShCcaaZxjmhsvp+d6fafrdnqe10FNs1D/aH3XM4cqkjeVc3Nz8QNyTPXFket57mDgus5Nr7VxfNVxeK4GuNsf7IibkYzut/sd8zd8s60+J1AD4yWIdqY9akoAE8KrQpnPjc6/ALj0Rs2XAwAA" + } + }, + { + "ID": "37ed6993bb102b34", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "241" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a537a4d2b1dc702276cb9bb3f91f50d3/13240778736438063132;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsidHlwZSI6IklOVDY0In0sInBhcmFtZXRlclZhbHVlIjp7InZhbHVlIjoiMCJ9fV0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiZVh6Y012anczcXpoQ0RFSWh6MFJES0JGZE1VIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:46 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/dHpsGSs5dyWA0K48XUljgnFqF2s\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2/aMBT9K5P3tSUmLxKkqesgsKgUtTzabuuEHOcmGJI4xA6IIv777ECnrZqqfbN9zr3nnHuTA1qzIkZdFLF0U0O1/7jiEbpAIEmqXp/RiHz3Cmz3vZt8GMI8vsvC8SgH8jgURvy1FMOpcOL94zW+sb2nebZKi8FmYIpnpJow3TiuMwrysuSVvOy4Znc+bcHTC73drnbW5mXZ6wfh8gVP+jdfBvHtXFUJyJIRK9aqdillKbqGsdvtWinnaQakZKJFeW68+jW2plFWfAVUKkN/axkqizDeUbvKOCWS8eLTfKqUFX0CCVRQUEDdAzr3Df8R48RukPfTvCoootI4XiDKi4SldXV+Peg+s32pBNH9PJh8UzVNMA2dD3okyseHK4XFICQrmuIZibL/8BkTSQSc0AX1Eg9H2I/aXpRgM4HE6dgUsIM9cLANiRt7Hdclqk7q9k0VKXjh0JiqKuwAAHVMoC71/Q62rSiOrMRy/diJTNuMmogVEAl9Jkou2Dl8bxJcz4JFOFiMg6Af9JXArmJvWY+TUJFmk/m4p9iKU1aMK5oeQjieBZPr3ix80EAtYAQpofvpJkPdhGQCzoO7IxXJQUIlUPeHGs7r9TTkA5KnYat2rq3d/iY8kKxuGNvTAWF0PP48KoqQRNZCQ/qkIeVwHI6H6AwytRTaEJrsejks17y2Y7mdtmlhx/c91JAr+RZzsWf+ufZGJIdCnr+LaTAKejOknajY1QJywlRoZLmu5fuW1badS7VQids8lz4xO/6aWilN2Wa5WWdexKNl/TmGLWS8hKqVqh5bRoFQyutC6t8JHX8Bhd46fgkEAAA=" + } + }, + { + "ID": "d7faa277fb2bf8a4", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/eXzcMvjw3qzhCDEIhz0RDKBFdMU?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6f42fa58ddfd49edc16feec08d833d4d/14804954250524273068;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/eXzcMvjw3qzhCDEIhz0RDKBFdMU?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:46 GMT" + ], + "Etag": [ + "wKNgfynWvMyk5B6z+hNNww==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "6f42fa58ddfd49edc16feec08d833d4d" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P206DQBCG32W8lCaosSYkvZAWlZQSxRJNjDHbZTh1YenuUAKEd3epXs3pm3/+GeFY1Ak4cCiyU4uqv8qQ3uYkQt0K0iY0stYIFiCxzJDdNszSvv447/rjvbscrvMw7LrVyhCa51gxcEZICxSJBudrhJpVaNZS+8cQ1Ddz4Yd779mLTKOSydwI4yB4dAMPpu/JglIeIkxRYc1xVmuULJGTPxtNWsGRFo1UtHhY3sKFvkzwc+C7c9ndnYZ8vfH8fLCjzdZ9SnaxoYTkjApZGzB+B3OEJDERyc64hBv4r92eUL8qyVFrnEXtvwNrWTUCybgh1aIFnJlXXwoCJ2VC4/QLXtNYaEgBAAA=" + } + }, + { + "ID": "c888da947632f2bd", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon5cdc9b105eeec52ec6c997043bdb3f369d5b242b/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6f42fa58ddfd49edc16feec08d833d4d/6399838957619946996;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon5cdc9b105eeec52ec6c997043bdb3f369d5b242b/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:47 GMT" + ], + "Etag": [ + "mBJdqoHVkzGK0Izu9/IdgA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "6f42fa58ddfd49edc16feec08d833d4d" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8rnOnmlFOZ7hGVXuXsbeFaVWup7pqQ72toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwobKNXGAiEAlh31B24AAAA=" + } + }, + { + "ID": "3dc8e6fbb4b77c69", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "246" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8cdd4369871520af5ff2eca55718c07f/7964014471706156676;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsidHlwZSI6IkZMT0FUNjQifSwicGFyYW1ldGVyVmFsdWUiOnsidmFsdWUiOiIzLjE0In19XSwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJMaWtIREhkdFdWMGlycDg2Q0xFb0hqdTBPVk4iLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:47 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/yoIc1PWRZs7y1gKNiljmqspiKRU\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Ta2/aMBSG/8rkfW2JQyAXpKmrIG2jorQLAbSuE3Kck9QliUPsgBDiv88OdJq6qdo32+9zznsuyQGtWZWiEUpYvmmh2X9+5Qm6QCBJrl6f0ZQ8uRUeTNz78jaAefpYBOG0BLK8FcaeB9R8XEZPwtmb+X3IitdyI2p2H82fkUrCdOK0LSjIy5o38tKx+6P5rDdl67vJXSqXC8ya2rXHU5/fvbb4YRGqKAFFNmXVWsW+SFmLkWHsdrteznleAKmZ6FFeGm/1Gtu+UTf8FagUxjsvQ/UijA/crgpOiWS8+jKfKWeFR5BBAxUFNDqgc97gH22c6E75uJs3BwUqj+MForzKWN4259eDzhPva2WIvs396LuK6RrT0vmgR6Lq+HSltBSEZFUXHJOk+I86UyKJgJO6om7m4gR7iekmGe5nkA2dAQU8xC4M8QAyO3Ud2yYqTur0XRSpeAUWIa7tOTbYtkUgS8gALA9jClZCLXPQT01ME2/YtdgAkTBhouaCnZsfR/517K+Cm1Xo+xN/ogx2DXtPLaNAQXE0D8eKVkzdMK4wPYQgjP3oehwHCy20AqaQE7qfbQo0ykgh4Dy4R9KQEiQ0Ao1+qOG8XU9DPiB5GvbN9OE6tge63t/IghRtx2xPB2T1TEUcfx4VJSSRrdCqPmlVlRkG4S06i0xthnZANwC9IVZqzhxatmP2LewMTQt1cCP/0myM/9x9Z1JCJc8fx8yf+uMY6UpU780KSsIKXaLah+dZagXDS7VViU1eSo/0HW9NrZzmbPOyWRduwpOX9msKWyh4DU0vVzm2jAKhlLeV1P8UOv4CyxjwUQ4EAAA=" + } + }, + { + "ID": "ecb80579551568f3", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/LikHDHdtWV0irp86CLEoHju0OVN?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e6fd9e3aec6244a75722cdf28725eb5c/9528188886314292756;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/LikHDHdtWV0irp86CLEoHju0OVN?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:48 GMT" + ], + "Etag": [ + "3Ae1LB2khJzJooW6W5J33w==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "e6fd9e3aec6244a75722cdf28725eb5c" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PQW/CMAyF/4t3BamAxqZKHIAxdSiCjQ16mKYppG5JSesucYW6qv+dlO1kP/mz33MLZ10mEMJRZz812uYuQ37rmx262rDzpaLSIQwAWWaenMxxJBbj82n9uyaKp/H9ejK5zGaecOqEhYSwhVSjSRyEny2UskC/lgbfnuCm6sWz2M4/vCwo6eVmL8R8IVbQfXUDyOm4wxQtlgr7W5WlHBW/9DGT2ijkYUWWhw/TMdzo20Toc/QUJRwfAm2rx+lSrCjK62B72HjKkJKsqfTg/h28CRNLs6OLzwgj+NeLhtG9WlLoHPZHgz+DJRWVQfZp2NY4ACX9o5FmCFNpHHZXOPJHMEYBAAA=" + } + }, + { + "ID": "192bff9bf8042233", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anone3aa86976e663aefba4e3900ce3bc3142d10cb95/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e6fd9e3aec6244a75722cdf28725eb5c/1123073593409966684;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anone3aa86976e663aefba4e3900ce3bc3142d10cb95/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:49 GMT" + ], + "Etag": [ + "njqOAG4hzOa/p8mHIVrFyQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "e6fd9e3aec6244a75722cdf28725eb5c" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8rnZRX6O7qbZFT5J+oXWOR6eIYVuVUG2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwob6xmaKNXGAiEA44jPuXEAAAA=" + } + }, + { + "ID": "0e2620bfdc150202", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "253" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "2aafaff8313b432ed0f106b8558f3710/2686967636814433260;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsidHlwZSI6IkZMT0FUNjQifSwicGFyYW1ldGVyVmFsdWUiOnsidmFsdWUiOiIzLjE0MTU5ZS04NyJ9fV0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiVElNaXc5RTdtMWZqbXQwWHpuVkhzVkZiV3QwIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:49 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/DwC62ZFk5HS9ESLF4CEj-kq1sWM\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Tb2/aMBDGv8rkvS3kf0iQpq6C0EajrIMAW9cJOeaSGpI4xA6IIb777JBOUzdVe+f4fnfP3XPOCW1psUZ9FNN0V0N1fL9hMbpCIHAqb5/QGD96hW4PvU/5bQjz9UMWTsY54OUt14aHgWs+jrbO3cwPZuORPQg2ne3O4Mv7JySLUFV4XWcERKdklej0XLM/n3Wj8J4e/KCXG8kmF/rXn8Xiji9G8VLoMotDloxpsZW5z0KUvK9ph8OhmzKWZoBLyruE5dpLv9re1MqKbYAIrr3S0uQsXHtD7TpjBAvKig/zmVSW+BQSqKAggPon1NYN/zHGhW4ib0/zoiBBqXG+QoQVCU3rqr09qTrRsZSC6Ms8mH6TOc1gKtQelCWyj3fXMrYGLmjRJEc4zv6jzzUWmMMluiJe4umx7seGFye6mUDi9GwCuqN74Og2JO7a67kulnlClW+ycMEKzyeW68WGDdiy3dg0MfGIY8hLJ4EYXAKO4RLHb0asAAsYUl4yTtvhB9PgJgpW4Wg1CYJhMJQCh4q+ppbTUELRdD4ZSFoyZUWZxJQJ4SQKpjeDKFyoQM1hDCkmx9kuQ/0EZxxa4x5whXMQUHHU/y7Nefm8mHxC4mL2aPz5JnJt1e9vZIGzumH2lwOyuoZtOD50vB46n3+cJcwFFjVXkDopSHY7CSe3qA1SuSDSAI0PalE0V5zhWG7PMC3dt3QPNXAl/orZpv7nE2hEcihE+0ZmwTgYREh1Ii2oVpBjmqlOXdfyfcsybKcjlyt0g+XCx2bP3xIrJSndPe+2mRez+Ln+uIY9ZKyEqpvKGntKABPC6kKoXwudfwHTaLFeFQQAAA==" + } + }, + { + "ID": "a10c1b77d47414aa", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/TIMiw9E7m1fjmt0XznVHsVFbWt0?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "39fe7a89e5c97f870d11fe7586125a60/4323198545948869500;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/TIMiw9E7m1fjmt0XznVHsVFbWt0?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:50 GMT" + ], + "Etag": [ + "hOD34xfijgtbu39mVu4A8Q==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "39fe7a89e5c97f870d11fe7586125a60" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3U7CQBCF32W8LUkRItKEi6IQSKpIhWpijNlup2Xr/tTuNFibvrtb9GrmZL6Zc6aDT6EzCCAVxVeDdXtVIO2HJkbbSLKuVEZbBA+QWOHI0+5+Mv3ORVlQ2kzmKmmm4e1+sXCE5SdUDIIOcoEysxC8daCZQreW+x+OoLYaxDrahQcnlckG+XiMonAZraB/7z0oTRpjjjVqjsOtqjYlctoOMbNGcqRRZWoazW6u4UJfJoftgzjPVzM1zktF/uuPTjY2Wacv5DtKGs5IGO3A4zM4EzLEZGzOLiOM4V8vW0L7VBuO1uJw1P8zuDOqkkguDdUNesCZe3QjCIKcSYv9Lxc2qvdGAQAA" + } + }, + { + "ID": "3e8713fbb4a69777", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon89c368b14ea346b22ac8c51c365febe6ce516c59/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "39fe7a89e5c97f870d11fe7586125a60/14292489357234307268;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon89c368b14ea346b22ac8c51c365febe6ce516c59/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:50 GMT" + ], + "Etag": [ + "4ECZ+QCznL0WtspmF+ng8Q==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "39fe7a89e5c97f870d11fe7586125a60" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qbuDpHaQc6V+X5GISXFBfkumnnpVsE2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwob6xmaGJpapupamCvVxgIhAE9fquF4AAAA" + } + }, + { + "ID": "a61539ce7b1bbf52", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "243" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "35274084dd3f6d485834311e7dd301a5/15856664871337293908;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsidHlwZSI6IkJPT0wifSwicGFyYW1ldGVyVmFsdWUiOnsidmFsdWUiOiJ0cnVlIn19XSwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJiUXM3RUFBNDdJbUhSYmh5dnFYdExtTlJuRnQiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:50 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/YPs8xJyppVpUQe_c4LAbK6kkHdc\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TXW+bMBT9K5P32gbCN5GmLktoy4rSliTtunWKjLkQN4AJNsmiKP99NkmnqZumPWF8zr3nnnNhj1a0StEAJTRft9Ds3r+wBJ0hEDiXt88owl+9SrfG3k15FcI8vSvCSVQCfrzi2tMd93583tX1Qz2/hwWxomFy46xW1yl5RrIJVY3TtiAgzmvWiHPXMQbzaS+5524wHFpuWF7HyXK3WX8RUTmJq0shqzgUWUSrlaxdClHzgaZtt9tezlheAK4p7xFWaq/zahtDqxv2AkRw7Y2WJr1w7R9qFwUjWFBWfZhPpbKkx5BBAxUBNNijU9/wLzaO7A75t5tXBUmUGoczRFiV0bxtTrd71We2q6Ugup8H8ZOs6Ywp6HRQkcg53l1ILAUuaNUVz3BS/MecKRaYwxFdEC/z9ET3k76XZLqRQWa7FgHd1j2wdQsyJ/Vcx8GyTqj2XRWuWAW+Q5zUMPuZl/rEth07dczEtw0vTXW3T5zEJ75h2Z3FBrCAMeU14/RkfhQHw1mwCC8XkyAYB2MpsG3oW9ZjHErSLJ5PRpItOXVDmaSpEMLJLIiHo1n4oICWQwQ5JrvpukCDDBccTsHd4QaXIKDhaPBNhvP6egx5j8Qx7E+3t5Ea9hf+gIu2I2yOByQa+Tgcvh8kiwssWq5QdVKonHESTq7QCaRyLaQjdO7VemipeH3bdNy+DE53LR915Eb8gXmG+/viO5ESKnH6MqZBFIxmSE0ijTcLKDGVtpHpOKbvm2bfss/lSoXeZ6XwseH6K2LmJKfr5XpVeAlLlu3HFDZQsBqaXi57bCgBTAhrK6F+KHT4CVejPe4LBAAA" + } + }, + { + "ID": "ba860fefd748e371", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/bQs7EAA47ImHRbhyvqXtLmNRnFt?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "19d4e6800c9fb465f17bea31449e7461/17492895784766632164;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/bQs7EAA47ImHRbhyvqXtLmNRnFt?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:51 GMT" + ], + "Etag": [ + "JnAbfnZwP0x8B/iTdIpdRA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "19d4e6800c9fb465f17bea31449e7461" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3U6DQBCF32W8pRGNEUPSCzCYYght0SaNxphld6DUZZfuDlZCeHeX6tX8fXPmzAhfjRIQQtnUpx7NcFUjbeekQNtLsi50WlkED5BY7chnFZWVejtv/J+H+Lp5FWknimi5dITlB2wZhCNUDUphIXwfQbEW3VrlfzqChm4u4vU6S6LcNVot5ka+y7IozhKYPiYPjrossEKDiuOs1hl9RE7pbFT0kiMtOm1oEdzfwoW+TMqtDZIougvSdlWUh+H7tKeszQv1RI6SmjNqtHLg7gXcEdLEZKHPziXcwH8dD4R2YzRHa3EW9f8OPOq2k0jODZkePeDMvbpqCMKKSYvTL+AE47VIAQAA" + } + }, + { + "ID": "d1f374d3bcfc5532", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anone96c6d231f8d9c5565d63b9528dd071c6b9c9245/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "19d4e6800c9fb465f17bea31449e7461/9015723993024326956;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anone96c6d231f8d9c5565d63b9528dd071c6b9c9245/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:51 GMT" + ], + "Etag": [ + "H4rCBIQmGR//+MI3e/zwHA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "19d4e6800c9fb465f17bea31449e7461" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8p7mBQ5O3kG5roH6etr+3oap+pXlXs42toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwqXFJWmKtXGAiEAwlLhIHEAAAA=" + } + }, + { + "ID": "14130b4c2be27779", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "247" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "7c6128b511c71ee214684319482eabe8/10651956001653614012;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsidHlwZSI6IlNUUklORyJ9LCJwYXJhbWV0ZXJWYWx1ZSI6eyJ2YWx1ZSI6InN0cmluZyJ9fV0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiYlhWdzhNY1Nwb25OZlhiSUl0alVnR2lZRHliIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:52 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/Dmfxdk16HLCHEr6sLkkO60_yRYI\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2/aMBT9K5P3tSUvEhKkqasgo9Eo60LoY+uEHOcmdUniYDswhPjvswOdpm6q9s32Ofeee85N9mhF6wwNUUqLdQt89/6ZpegMgcSFen1EU/zNr83+2P9cTSJYZDdlNJtWgO8mwhhX+c9sZXlX09FVyD0xXa2+eOZyFz9Ej0g1obpx1pYE5HnDuDwfePZwMe+l97db/5rMG1bP8vs0iuTzopjQh/FOSwso8ymtV6r2ScpGDA1ju932CsaKEnBDRY+wyniZ19jYRsPZMxApjFdahvIijDfULkpGsKSs/rCYK2VFjyEHDjUBNNyjU9/oHzaO7A55282LgiIqjcMZIqzOadHy0+te90l2jRJEXxdh/KBqOmMaOh10JGqOdxcKy0BIWnfFCU7L/5gzwxILOKJL4ue+mZpBavlpbto55O6gT8B0TR9csw+5l/kDz8OqTur2XRWuWe0OPNfOwAQzxYGbB2Zm2gPXAstyIfDAzDwfO1bf7ixywBLGVDRM0JP5URxeJuEy+rScheE4HCuBLaevWXdxpEhJvJiNFFtxGk6ZoukQolkSxpejJLrVQCtgCgUmu/m6RMMclwJOwd1gjiuQwAUaflfhvFyPIe+RPIY9T+JoNtHj/mbc4rLtKJvjAQnJaV2gw+HHQfGExLIVGtcnjas5Z6cm+omq1ZCO0CWgV0QrzbNcxxtYtmPZVt9HHZnLvzDb8f5cfidSQS1PX8c8nIajBOlJlHm+hApTZR05nucEgaPCd8/VWqVpsUoG2B4EK+IUpKDrp/Wq9FOWPrUfM9hAyRrgvUL12FACmBDW1lL/VOjwC7tjHZEPBAAA" + } + }, + { + "ID": "f5ef0a7129a6fec9", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/bXVw8McSponNfXbIItjUgGiYDyb?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "76f3796a2b740b314da636630081f1b2/12216131520034725452;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/bXVw8McSponNfXbIItjUgGiYDyb?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:53 GMT" + ], + "Etag": [ + "fuX/YJxINiP+HyifgbDtrQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "76f3796a2b740b314da636630081f1b2" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PQU/DMAyF/4s50onBAVClHRhDW1GptpaiTQihNHVKStqUxNWoqv73JYOT/eTPfs8jfMu2hBAKWf30aIaLCmnnmxRtr8i60unWIgSAxCpHin5/dXj+jRK5vdwMUlTFisxusXCE5V/YMAhHEBJVaSF8H6FlDfq1+acjaOi8yF7TKFk73ejS6ySP44dl/ATTxxRArYsUBRpsOfpjndE1cop8zrJXHGnWaUOzu9sbONPnSbF/O96/8MzFTcS+iCKq82otD6uhcJTSnJHUrQPzDJwJaWIq1UcXEq7hXy8HQrs1mqO16I/O/wweddMpJJeGTI8BcOY+3UiCUDBlcToBzqyGnEcBAAA=" + } + }, + { + "ID": "a9340f05db829f75", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon57652de0e0ba95f90d02751e115e96e0d68a3142/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "76f3796a2b740b314da636630081f1b2/3811015123340647060;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon57652de0e0ba95f90d02751e115e96e0d68a3142/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:53 GMT" + ], + "Etag": [ + "UlFFX1REA974RY1d0zLcvQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "76f3796a2b740b314da636630081f1b2" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8qH5ri5RRgGuTpampsERRqmGFT5JJcF2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwoXlxRl5qUr1cYCIQA//B0FcwAAAA==" + } + }, + { + "ID": "713a092cf711a45e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "252" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "56f21fd32a93b4db6b1ebe585f2f6333/5375190641738535460;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsidHlwZSI6IlNUUklORyJ9LCJwYXJhbWV0ZXJWYWx1ZSI6eyJ2YWx1ZSI6IuaXpeacrOiqnlxuIn19XSwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiIzMVVzb2hTTFoyTXhQNkE2SFh3eTl2MFpFZkIiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:53 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/NrDwZDIFwLAF2CAbVLgxM5wCAoE\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2T227TQBCGXwUtt218ik+RUAmJWyzcqCROC6EoWq/HzhLH69jruFGU5+AGcccN4rkqHoNdJ0WooIq79cw388/8u96hJc1j1EMRTdc1lNvnn1iEThBwnIroLQrwzMnV7tB5s7rwYRpfZf4oWAG+uaiUUTlsZkP/vAn65/qgH10H6d2l2Qz6zLtFogmVjeM6I8BPC1byU9vSe9NJx9CmFVtMgpl+eXdl9a3X75qtu1FnXvJKVFWQJQHNl6J2wXlR9RSlaZpOyliaAS5o1SFspTzMq2x0pSjZJyC8Uh5pKWKXSnlC7SxjBHPK8hfTiVAW+BgSKCEngHo7dOzr/2ONA91mnt7mQUGAQmN/ggjLE5rW5TG6k33CbSEE0dupN34vatrFZOp4kJaIOZ6diVwMFad5WxziKPuPOWPMcQWH7Jw4iaNGqhtpTpSoegKJaXcJqKbqgKl2IbFix7YsLOq4bN9W4VzMbJIkckWxqaoWcZykCzZOdNexcZw4ru7aBhYRaFcsAXMY0qpgFT0uPxh7/dCb++fzkecNvaEQaEr6mLoZ+wIKx9PRQNCCKUrKBCZN8EehN+4PQv9aJuoKAkgx2U7WGeolOKvgaNwVLvEKOJQV6n0Q5jx8HkzeIX4wexKO/dGFHPc3cY2zukU2hwO6//zt/suPn9+/3uZov/+4F3DFMa8rCcmThMSwo2MnGaLifkgLtDbIe6IryWmmYdmabmiG5WiohUv+V842nD9fQCuygpwfn8jEC7xBiOQkwoFyDitMM/kILctwXcPQuuapuFuuamzFXazb7pIYKUnperFeZk7EokX9MoYNZKyAspOKHhtKABPC6pzLPwvtfwFj+yj/FAQAAA==" + } + }, + { + "ID": "15e06ea6ff49ee86", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/31UsohSLZ2MxP6A6HXwy9v0ZEfB?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "c30fa919e1be1052600d340c1f84803d/6939366155824745396;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/31UsohSLZ2MxP6A6HXwy9v0ZEfB?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:54 GMT" + ], + "Etag": [ + "/KyzyQmttC73LqlrrgeDIg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "c30fa919e1be1052600d340c1f84803d" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P0W6CQBBF/2X6iilqgimJD2JNJaVGoSSNTdOsy4DYhcXdoZYS/t1d26eZmzkz904PX2WdgQ+Hsji3qLq7Amlnmxh1K0ib0shaIziAxApD3j93v92uIlrOptFZKFXgY1jM54bQ/IgVA7+HvESRafDfe6hZhWYtdz8NQV1jRfIah5snoyuZWb1Jo2gRRCsYPgYHTvIQY44Ka472WKPkCTmFNmfWCo40aqSi0cybwI2+TabjVMtjEu0nLz9bb+Gt3y7dw7e7X+WBoYTkjEpZGzBNwJiQJCZieTEhYQz/OugI9VZJjlqjPer+GSxl1Qgkk4ZUiw5wZj5dlwR+zoTG4QoHR1ZzRwEAAA==" + } + }, + { + "ID": "4d4f410bd63f756e", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonf5cfb9f805006c88f4e7af2987adf892973ae7ae/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "c30fa919e1be1052600d340c1f84803d/16980713461653260284;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonf5cfb9f805006c88f4e7af2987adf892973ae7ae/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:54 GMT" + ], + "Etag": [ + "mQl8gDuys0qc1iYRrYsGng==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "c30fa919e1be1052600d340c1f84803d" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8rnBuZYpLuUVhYbFCYbZkYGFUUWu+el29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwo/m7702Zw1L1bNi8lTqo0FQgCBnykVeAAAAA==" + } + }, + { + "ID": "50f1a2cf650a49a0", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "245" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "37d736db24dc79fbbc8ca6cd40d32885/98425277511778444;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsidHlwZSI6IkZMT0FUNjQifSwicGFyYW1ldGVyVmFsdWUiOnsidmFsdWUiOiJOYU4ifX1dLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IkZDSjlMcXhmR0psUlhHS3Z4czhqMmFCb0dESSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:55 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/_zEVlcXF_2p0q3oyBWr7JxPnM-k\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2TbW+bMBSF/8rkfW3CWyAQaerahES0GesS0nZbp8iYa+oGMMEmaRblv8+QdJq6qdo3w3nuPfdcwx6tWJGgAYpZuq6h2r1/4jE6QyBxqt4+oCn+5hZ6b+Re55MAFslNFoTTHPDdRGjLn/5tRu7HS7PU1xbfXd5V/avnm+JTZ/WAVBPWNE7qjIDslLySnb5jDhbz7nh45U3Xz3Rylc3uJ9ebZ+E+mfiST0aBqhKQ0SkrVqr2UcpSDDRtu912U87TDHDJRJfwXHuZV9uYWlnxJyBSaK+8NJVFaG+4nWecYMl48WExV84KnwGFCgoCaLBHp77BP2Ic6VZ5O82LgwKVx+EMEV5QltbV6e2+6RPtSmWIviz82VdV0wZrpNOhWYma49250hIQkhVtcYTj7D/mTLDEAo7qkrjU1WPdiw03prpJgdr9HgHd1l2w9R5QJ3H7joNVnWzat1W44AWhdtzXHRrbhkHcuE9pQl1Hx1T3TNvpJTpY1LaduI1YAZYwYqLkgp3CD2f+ReQvg/Ey9P2RP1IG24q9pu5mgYKi2SIcKloxZcW4wpolBGHkzy6GUXDbCLWAKaSY7ObrDA0ozgScFneDK5yDhEqgwXe1nJfH45L3SB6XPZ5+voicXjPvb+QWZ3XLbI4HFOIQHQ4/DgoSEstaNGJzakQ1ZRiEE3QSmboY0gJt/uaCWN5whm05fcO0DFu3PdTClfxLM0zjz6tvTXIo5OnbmPtTfxihZhIVvVpCjpkKjizHsTzPsoye3VGXKnWD59LDZt9bESslKVs/rleZG/P4sf6YwAYyXkLVTVWPDSOACeF1IZtfCh1+AXCKKbkNBAAA" + } + }, + { + "ID": "4564c7525f659016", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/FCJ9LqxfGJlRXGKvxs8j2aBoGDI?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a904695cf505abcfebbb54157a7c57cd/1662600791614765084;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/FCJ9LqxfGJlRXGKvxs8j2aBoGDI?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:55 GMT" + ], + "Etag": [ + "AdsTsQjst9fVLoPR6MhGog==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "a904695cf505abcfebbb54157a7c57cd" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PUU/CUAyF/0t9hQR5QFnCw4YywakwwJgYYy533di8W8faKcuy/+4d+tSe9GvPaQtfaRGBA4c0OdVYNVcJyqZvQuTaCNtSUsEIA0BRiSXdiHe8yVim8WtA63DydPQpmc0swfqIuQKnhThFEzE47y0UKke7Fo8+LSFN2YtF8OLurMwp6uXzPghcL7iH7qMbQEaHEGOssNDY3yorylDLso8Z1UajDEuqZHgzGcOFvkwW89U0OJ1jf2XCN//x+8y32Vh55N8tLWVIK0mpsOB+C9ZESJQJ6cdmhGv4114jyOuKNDJjf3T0ZzCnvDQoNo1UNQ5AK/voQyrgxMowdr/Nc783RgEAAA==" + } + }, + { + "ID": "483af213d69da99b", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anoncf5b706fb511c8b7ffdf860af092564d0e3f556b/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "a904695cf505abcfebbb54157a7c57cd/11703948097443279972;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anoncf5b706fb511c8b7ffdf860af092564d0e3f556b/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:56 GMT" + ], + "Etag": [ + "SVJYPuuqfSRD8gVN5t5V/A==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "a904695cf505abcfebbb54157a7c57cd" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8oHh3lFBpSWFqYFB7lYpIf5mZaYhuk72toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwr7Jfop1cYCIQC0/hg1cAAAAA==" + } + }, + { + "ID": "94e118a9ddd35413", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "244" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e124eb7482672e54e270545b252ce9e2/13268122512034639348;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsidHlwZSI6IkJZVEVTIn0sInBhcmFtZXRlclZhbHVlIjp7InZhbHVlIjoiWm05diJ9fV0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiYUxiSFlETEl0M0JtdzY2eUYxYmdzanhwa2RIIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:56 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/Q3oOEsu7KXk-Jj7o9OiYywboDR4\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2+bMBT9K5P3tQmv8Io0dW1CW1aUtglpl65TZMyFOgFMsEkWRfnvM4ROUzdN+2b7nHvPPefCAa1pEaMhimi6qaHaf1yxCJ0hEDiVry8owM9OoQ7Gzm1+7cM8vs/8SZADfrrmyoPB7jxe27df170vK5u5d3Sx30VsPB28INmENo3jOiMgeiWrRM+29OF81sdBdLMYB74wLvOdZe2vtCjlqx/lOr6RVRyyJKDFWta+ClHyoaLsdrt+yliaAS4p7xOWK2/zKltdKSu2AiK48k5LkV648g+184wRLCgrPs1nUlnSp5BABQUBNDygrq//Fxsndov8282bgiRKjeMZIqxIaFpX3euh6RPuSymIHubedCFrWmMN1B2aSOQcH84lFgMXtGiLQxxl/zFnjAXmcEKXxEkcNVLdSHOiRNUTSEx7QEA1VQdMdQCJFTu2ZWFZJ5r2J4cFKzTDiFQMFtGxNlCJq9tq7Lqqa+txYpumrZNY02LVbC1WgAWMKS8Zp5350dS7CL2lf7WceN7YG0uBXUXfs56mviSF0/lkJNmSU1aUSVoTgj8JvenFKPQfG6DmEECKyX62ydAwwRmHLrh7XOEcBFQcDb/JcN6up5APSJzCvlyEXruQX4RHnNUtY3s6oOfc3aLj8ftRsrjAouYN2pwaVA458SfXqAOp3AtpCa39Zj80b3iaaVi2phuaZRs2asmV+ANzZHS/bb4VyaEQ3acx8wJvFKJmEum8WkKOqfSNDMsyXNcwtIHZkzsVqsZy4WLddtfESElKN6+bdeZELHqtP8ewhYyVUPVT2WNLCWBCWF2I5o9Cx58a0GqZDAQAAA==" + } + }, + { + "ID": "1f00ec054b0ff940", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/aLbHYDLIt3Bmw66yF1bgsjxpkdH?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "878490007a87617e96a26350cab06c0a/14904354520663926148;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/aLbHYDLIt3Bmw66yF1bgsjxpkdH?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:57 GMT" + ], + "Etag": [ + "eglgNBI83k9/3Od+HVST1g==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "878490007a87617e96a26350cab06c0a" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P0U6DQBBF/2V8lMYiCSpJH0RrICFVoTVpjDHLMqzAwuLukEoI/+5SfZq5mTNz70zQVF0BAeSV+B5QjxcC6XVpUjSDJGNLrzqD4AASE5ZEIcUujG+95u7Key4uo7ds74rNxhKGf2HLIJigrFAWBoL3CTrWol0r15+WoLFfRHjcbzMrW1UscndIkvsw2cL8MTtQqzzFEjV2HJdbvVY1coqXmMUgOdKqV5pWN/41nOnzhCV5dHxMYvLC9uT745ObC1P/9E0RWUoqzqhSnQUPGVgTUsRkqk42I7jwr8OR0LxoxdEYXI6u/wweVNtLJJuG9IAOcGYfjSqCoGTS4PwLBpzHrEYBAAA=" + } + }, + { + "ID": "4d356cb0b5f2e735", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon133b0ae6c2a140c9270d990972df75572cd11d05/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "878490007a87617e96a26350cab06c0a/6427182733233299916;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon133b0ae6c2a140c9270d990972df75572cd11d05/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:58 GMT" + ], + "Etag": [ + "rRrYJfVSi0l95NdarS6jeA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8oXBRVFeqWFBWca5Fia+qUkFgWbZaU62toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwpH5VqWKdXGAiEAZauNsHEAAAA=" + } + }, + { + "ID": "424d3e31a460d7bf", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "276" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "1e7eb5badbc64a8db73655e028c19a5d/8063133271164066396;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsidHlwZSI6IlRJTUVTVEFNUCJ9LCJwYXJhbWV0ZXJWYWx1ZSI6eyJ2YWx1ZSI6IjIwMTYtMDMtMjAgMDQ6MjI6MDkuMDAwMDA1LTAxOjAyIn19XSwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJHUTV4dmczVmRSTldVMVpXRHhzRFBRS2dGM2giLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:58 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/zKg8go6oO-qm3dRVwkIpKriSUwg\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TW2/aMBT+K5X3WohzITdp6ipIUQRlFAJoXSfkJCfBJYlD4kA7xH+fHeg0dVO1PDk+3+Wc7yRHtKVFjFwU0nTXQPX66ZmF6BoBJ6m4fUJj8mgX2BjYo3zowyKeZv5knANZDWvl5yi1U2ayr51drsez5WHrl6OKzheH9AkJESqF4yaLgHdKVvGOZWruYt4dPvRe9qm+jGeT1UJ9XA1e6sH0YZTe6RvBqiFLxrTYCu6G87J2FeVwOHRTxtIMSEnrbsRy5a1fZa8pZcWeIeK18s5LEbPUygduNxmLCKes+LyYC2cBn0ECFRQRIPeILrr+P8Y4o9vKx9O8OQig8Dhdo4gVCU2b6nJ7lDrBaykM0cPCm30TnHYwWbocZCSij6sbUYuh5rRoyQEJs//oMyac1HCuriM7sXGInVC1wwRrCSQ9y4gA97ANPWxAYsa2ZZpE8LiUb1mkYAW2rFCzNEN1MAHbieJY00zAmmE4CdYJWJoZ416ctCNWQDgMaF2yml6G78+828Bb+3friecNvIEwOFT0PWo18wUomC0mfYEWmLKiTMBkCP4k8Ga3/cBfykJTwxhSEr3OdxlyE5LVcAluSiqSA4eqRu53Ec7b6znkI+LnsAP/3psHt/dT2fFv0JJkTYvanw9Iw6rZwXpHw1fYcDXNxU4Xy6fXwaqLNXQ6/TgJhZoT3tSSKU+SKYaY+JMhuhSp2FvUAtp45P5oLnFqTzctVdNVW1flvgS44n/XHOPPL6M1yaHgl09n7o29foBkJyKZag05oSIXpJum7ji6rhq9jtg5xyrLuUM0y9lGehqldLfZbTM7ZOGm+RLDHjJWQtVNhcaeRkCiiDUFl38cOv0CUL+kySwEAAA=" + } + }, + { + "ID": "bb70974be6f646db", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/GQ5xvg3VdRNWU1ZWDxsDPQKgF3h?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "83468fe90194d9a426da1f31dbc65c86/9627307685772202732;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/GQ5xvg3VdRNWU1ZWDxsDPQKgF3h?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:59 GMT" + ], + "Etag": [ + "s0iGu0vYc60mW23SNgC6rg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "83468fe90194d9a426da1f31dbc65c86" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P207CQBCG32W8haRArEkTLjiJxEKgUIkaY5btdFncduvuFGka3t1d9GpO3/zzTwtfsswggoMU3zWa5k4gbXySoK0VWRcqXVqEDiAx4UgbyHkdnF95GBT7/mC7EpPQiOHQEZYfsWAQtZBLVJmF6L2FkhXo1vLg0xHUVL7YLZaz7W60XLtWoTPfWqVxPBrHM7h+XDtw0ocEczRYcvR6ldEn5LTwVrNacaRupQ11H8I+3OjbZL65v5zF4CVLVvu097afXux0vXkWj4Ojo5TmjKQuHZhuwR0hTUwl+sf5hB781+OG0K6N5mgtetHg78BEF5VCcm7I1NgBztyzT5IgypmyeP0FkOG5qEoBAAA=" + } + }, + { + "ID": "bebb486dac7fb8d2", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon077b2724190ae89cdd226e02449f03ae726d05df/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "83468fe90194d9a426da1f31dbc65c86/1222192392851099444;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon077b2724190ae89cdd226e02449f03ae726d05df/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:59 GMT" + ], + "Etag": [ + "2y5FEPF26ue5VUbSEiHstQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "83468fe90194d9a426da1f31dbc65c86" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8obVZq6uQa4GZmVppqGhSYFu2Z6FJcE2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwmbmFqYmBqamFjqGYCAqVJtLBACADMRtex+AAAA" + } + }, + { + "ID": "91472137bb29b89f", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "249" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "e0abf10aace9f54456184ef095a23b23/2786367906954086340;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsidHlwZSI6IkRBVEUifSwicGFyYW1ldGVyVmFsdWUiOnsidmFsdWUiOiIyMDE2LTAzLTIwIn19XSwidXNlTGVnYWN5U3FsIjpmYWxzZX19LCJqb2JSZWZlcmVuY2UiOnsiam9iSWQiOiJIa1BTRnJBalFINVkyOE5vM2dqVGVKTkpscnQiLCJwcm9qZWN0SWQiOiJkdWxjZXQtcG9ydC03NjIifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:31:59 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/_NvP1gWy2bA5Gu2RxN5Ps8jP1gE\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2TbW/aMBSF/8rkfS2Nk5A3pKlDkNJsKKIQWnXrhBznJjUkcYgdGEL89zmBTlM3Vfvm+Dz3nnuu4Yg2rEzQAMUs2zZQHz6ueYyuEEiSqdtnNCXf3BL3x+7XYhLAMpnlQTgtgDxOhLYKdzM9ezwY8dCaNMb8Z2jNhLtWd/4zUk1Y2zhpcgqyV/Fa9hzbGCwX13eb2eK2Hq7v76wnww25ma0j+BJ+yWupqgTk6ZSVG1X7ImUlBpq23++vM86zHEjFxDXlhfY6r7YztKrma6BSaG+8NJVFaO+43eScEsl4+Wm5UM4Kn0MKNZQU0OCILn2Df8Q4053yfppXBwUqj9MVorxMWdbUl9tj2yc6VMoQ3S/9+ZOq6YK10uXQrkTN8eFGaQkIycquOCJx/h9zJkQSAWd1Rd3UxTH2Yt2NU2ykkFpOnwK2sAsW7kNqJ65j20TVybZ9V0VKXhLdTaidGk5CaApW4lr9fkIITj3cx4ZtkcQmuoPtLmINRMKYiYoLdgk/mvvDyF8Ft6vQ98f+WBnsa/aWepwHCormy3CkaMVUNeMKa5cQhJE/H46i4KEVGgFTyAg9LLY5GqQkF3BZ3IzUpAAJtUCD72o5r5/nJR+RPC973BqoYX/rDyRvOmB3PiAD63YPmz0Do9Ppx0mxQhLZiJZpTy2jJg2DcIIuIlOPQzug20H7SKxoOd0ybUc3TN1zdIw6uJZ/aS72/nz+zqSAUl5+Hwt/6o8i1E6i4tcrKAhT4ZFp26bnmabet3rqYSXWeSE9YjjehpoZzdj2ZbvJ3ZjHL83nBHaQ8wrq60z12DEKhFLelLL9W6HTL7AS6vkRBAAA" + } + }, + { + "ID": "f9288c41866f5c85", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/HkPSFrAjQH5Y28No3gjTeJNJlrt?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d3c47b1f72be279396d44c5ba497f255/4350542325840347220;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/HkPSFrAjQH5Y28No3gjTeJNJlrt?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:00 GMT" + ], + "Etag": [ + "lwGvI474/3sknEH8s1nsFQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "d3c47b1f72be279396d44c5ba497f255" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PW2+DMAyF/4v3SrXetlZIfaAbHa0QKr08TNM0pcEwICQsMasQ4r83dHuyj/zZ57iDMpcJuHDJs58GdfuQIcVDc0DTCDK21EoaBAeQWGZJcX373c4X88eZKaUfLM1Emk28WlnC8G+sGLgdpDmKxID70YFkFdq1dPxlCWrrQbx6J9+qSiWDis5h6K1DH/rP3oFCXQ6YokbJcThVa1Ugp+2QMmkERxrVStNo8TyFO32fBOX+uNFeEQdP79NlpGZZccJdtBOaLCUUZ5QracHzEawJKWLioK42IkzgX69bQrPXiqMxOBwd/xm8qKoWSDYN6QYd4Mz+GeQEbsqEwf4GEfijOUUBAAA=" + } + }, + { + "ID": "dec9746d65cbd3f4", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anona18dc6f27dacfe5d8544daa0f9040265ad6a1706/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "d3c47b1f72be279396d44c5ba497f255/14391889627374025883;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anona18dc6f27dacfe5d8544daa0f9040265ad6a1706/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:01 GMT" + ], + "Etag": [ + "h7n6B7xuJDQXjL/sYXKKgQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "d3c47b1f72be279396d44c5ba497f255" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8pnmOeZOZlXlHq5BEZk+egXR0Z4e6cH2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwobGRia6RoY6xoZKNXGAiEAuTAZ6ncAAAA=" + } + }, + { + "ID": "e91758f8bf0ab458", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "254" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "58a1968eb7ca3940f05d261bf35cdd44/15956065141477012523;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsidHlwZSI6IlRJTUUifSwicGFyYW1ldGVyVmFsdWUiOnsidmFsdWUiOiIwNDowNTowNi43ODkwMDAifX1dLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6ImN6Tnd3TGZPR1dBU0sxT2hPRXlzR1VIemNRVyIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:01 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/tqh4LgdBETSCB98dDeZA1XMyWUQ\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2/aMBT9K5P3tSVP8pKmjkLGolJoIZSt64Qc5ya45EXsgCjiv88OdJq6qdo3x+fce8491zmgNS1i5KGIppsG6v3H5zJCFwg4TsXtExrhR6dQzYFzkw8DmMd3WTAe5YAXQ6bwzcocpfG1H876164TD+Cxp3273S/m909INKGycdxkBPhlVdb80rZ0bz7rkJfxbjdKJsNFb3ajTVYTf8+G868v5H4hqhhkyYgWa1G74rxinqLsdrtOWpZpBriirEPKXHn1q2x1parLZyCcKW+0FDELU95Ru8pKgjkti0/zmVAW9CkkUENBAHkHdO4b/GOME7tF3p/mVUEQhcbxApGySGja1Ofbg+wT7ishiO7n/vS7qGkHk9D5ICMRPj5cCSwGxmnRFoc4yv7DZ4w5ZnBCl8RJHDVS3UhzokTVE0i6tklA7aoOdFUTEit2bMvCoo7L9m0VLoRnBzu2icE0u45hWUacJDjGsYn1xEgix8DYNcAiRjtiDZjDgLKqZPQ8fH/q90J/GXxZjn1/4A+EwK6mb1mLaSBI4XQ+7gu24FQ1LQVNhhCMQ3/a64fBgwQaBiNIMdnPNhnyEpwxOAd3h2ucA4eaIe+HCOf18xTyAfFT2GFw60uzv/EHnDUtYXs6INX01K6nWh3bcVVVRcfjz6MoYBzzhkmiPEmisDsOxkN0BqnYEGkJbRByUzSXPK1rWLamG7qmOxpqyTX/CzNs88830IrkUPDzI5n5I78fIulEZFAvIcdUJIDkUlzXMDSzeym2y1WtzLmLddtdEyMlKd2sNuvMicpo1XyOYQtZWUHdSUWPLSWACSmbgst/Cx1/AV0uEw0WBAAA" + } + }, + { + "ID": "55288dd31cb66583", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/czNwwLfOGWASK1OhOEysGUHzcQW?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "93acebc30da0257e2610020940c46219/17520239560363273659;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/czNwwLfOGWASK1OhOEysGUHzcQW?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:02 GMT" + ], + "Etag": [ + "GrVjqTei3Yf1QuMjALagow==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "93acebc30da0257e2610020940c46219" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P0WqDQBBF/2X6mkBsoQUhD6aICTWxmthQSimbdTTa1TW7I2LEf+9u0qeZy5yZe2eE37LJwIVTWVw6VMNDgRTbJkHdCdKmtLLRCDNAYoUhA/VRXQ5YPn3mTtxtKy9kheyXS0NofsaagTtCXqLINLhfIzSsRrOWL34MQUNrxWGz9Y2qZWbVLg1DbxX6MH1PM6jkKcEcFTYc7alWyQo5bWzKrBMcad5KRfOX50e40bcJv+76Psyj4Ojt35zoHPmDDtL1lcdHQwnJGZWyMWC6B2NCkphIZG8iggP/ejUQ6nclOWqN9ujibvAq61YgmTSkOpwBZ+bPdUng5kxonP4AVpYoIkUBAAA=" + } + }, + { + "ID": "6ee1ba7860ad81fb", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonf8a874ae44583663dffadad4a2f3fb83aa93e6c3/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "93acebc30da0257e2610020940c46219/9115124263164045571;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonf8a874ae44583663dffadad4a2f3fb83aa93e6c3/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:02 GMT" + ], + "Etag": [ + "BSq3ihcvSWSGl2rlH5GXGQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "93acebc30da0257e2610020940c46219" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8o7BRcaZ2YklwWHB7vnGBXleJi6R7gH2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwobmFgZmFoZmOmZW1gaGBgo1cYCIQCSQc8rfAAAAA==" + } + }, + { + "ID": "5c6fefdb27e7746b", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "269" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "87f3fc3b2a5c8fb9e9e9c60c8e4021f3/10679299781561934227;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsidHlwZSI6IkRBVEVUSU1FIn0sInBhcmFtZXRlclZhbHVlIjp7InZhbHVlIjoiMjAxNi0wMy0yMCAwNDowNTowNi43ODkwMDAifX1dLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6IkFNZ2lJZG94V1dyVVJmODlqYkpWUk1sUUQ5YSIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:03 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/lmqOB9DHDKCzOh44G5gO7MyPNO8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2+bMBT9K5X3tQnm/ZCmrgssY82jJaTRtk6RMYa4AUzASZZF+e+zSTpN1VTtm/E9555zzzVHsKZVCjyQ0HyzJc3h3TNLwDUgHOXi9gmM0Dengobv3JXDkMzT+yKcjEqCFsNWKcrN9KPrf/bvBr+mK8MYmvnUHh/uJ1PnCYgmVDZOtwUmvFezhvdsS/Pms/7tOKdhyn4uFs08yhz3OfnyGI2LB99FgtWSIhvRai24K87r1lOU/X7fzxnLC4Jq2vYxK5UXv8pOU+qGPRPMW+WVliJmaZU31G4KhhGnrHo/nwllAY9IRhpSYQK8I7j0Df8xxhndVd6e5kVBAIXG6RpgVmU03zaX26PsEx9qIQge5kH0VXC6wWTpcpCRCB9XN6KWkpbTqiPHKCn+w2eKOGrJubrETubABLqJ6iQZ1DKSmbaBCTShQ0xokMxKHduypHMu23csVLEqTV2o2hlysIqxrTuqY5PMtk1Ddw1D1RwzyzTkqmY3YkMQJz5ta9bSy/CDKLiNg2X4aTkJAj/whcC+oa9RiygUoDiaTwYCLTB1Q5mAyRDCSRxEt4M4fJSFbUtGJEf4MNsUwMtQ0ZJLcPeoQSXhpGmB912E8/J5DvkI+DlsXwjE4TiQhv9gHlGx7UC78wFoULV6UO9p8AoaHjQ9aPVtx4UQgtPpx0lwW474tpUceZIc4X4STobgUqRiYbgDdLnIxdFS4lRTt2xV0zXNdSHowA1/XdNV1fj7SXQiJan45c3MglEwiIF0IiJplqREVAQCdMvSXVfXVcPsiWVzqLKSu0iz3TXWc5zTzWqzLpyEJavth5TsSMFq0vRz0WNHMUEYs23F5a8GTr8BRd4lOiUEAAA=" + } + }, + { + "ID": "de109e8f3cb0ce4c", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/AMgiIdoxWWrURf89jbJVRMlQD9a?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "27d7ef90da26473e904ebaca15450c60/12315531790174444067;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/AMgiIdoxWWrURf89jbJVRMlQD9a?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:04 GMT" + ], + "Etag": [ + "s/7fFcXjqXgb3/asgS0aeA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "27d7ef90da26473e904ebaca15450c60" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3U6DQBCF32W8pSlqYi1JL6jFiAFjabFNjDHLMiC4sHR3iBLCu3e3ejV/35w5M8J31ebgQVaVpx7VcFUibW2SoO4FaRM62WoEB5BYaUg9XxSP/FifjmV2O2e63LkM/dXKEJp/YcPAG6GoUOQavPcRWtagWSvcT0PQ0Nli4++DfRgHptPI3HZe0ijy11EA08fkQC2zBAtU2HK0cp2SNXIKrdO8Fxxp1klFs8XdDVzoy8SPyyrM5e/hoNKkuF/W2fNbEovtZskMJSRnVMnWgOkOzBGSxEQif4xNuIb/ej0Q6lclOWqNVtT9O/Agm04gGTekenSAM/PrU0XgFUxonM74JCXLSQEAAA==" + } + }, + { + "ID": "4481752fe4d2efc3", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anondd9017fa8c1cc738187ef775439441285ff2a915/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "27d7ef90da26473e904ebaca15450c60/3838358898954065515;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anondd9017fa8c1cc738187ef775439441285ff2a915/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:04 GMT" + ], + "Etag": [ + "8Z2L7JaSClRpuCHleqBmpA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "27d7ef90da26473e904ebaca15450c60" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8pbRBn5mHslBjvnBBWUOnvkpBY65RY42toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwobGRia6RoY6xoZhBiYWBmYWhmY6ZlbWBoYGCjVxgIhAOduLtmHAAAA" + } + }, + { + "ID": "03e09476c802da34", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "254" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "4b09afb1a5f1a436939973c7c10bab71/5474590911861477371;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsidHlwZSI6Ik5VTUVSSUMifSwicGFyYW1ldGVyVmFsdWUiOnsidmFsdWUiOiIxMi4zNDUwMDAwMDAifX1dLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6Ik9rZjR4UkpqMm9uWENlcEVUa2ZmMFVoSWJyQiIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:04 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/s4x1LJMdXYwz3zgIMkCN02_Ckr0\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI2Ta2+bMBSG/8rkfW3D/RZp6jrCKrqUdYT0snWKjDlQF4IJNknbKP99hqTT1E3V+GR8nnPec17bW1TSOkNjlNJi1UH79P6BpegIgcCF3L1DU/zdrVVz4n5ZnoUwzy6rMJouAV+fcYWbj9r0/CK7ud08G89FeFH6kaov/LJV75AsQvvCWVcREMcNa8WxY+vj+Wz0tczNx/j8QWf1jQ9NkJR5rs7vw7T9JLM4VPmU1qXMvRei4WNF2Ww2o4KxogLcUD4ibKm89KusdaVp2QMQwZVXWoqchStvqJ1UjGBBWf1hPpPKEo8hhxZqAmi8RYe64T/G2NND5O1pXhQkKDV2R4iwOqdF1x52t32d5KmRgujbPIhvZc4wWB86LHpLZB/vTmQsAy5oPSQnOK3+o88MC8xhH10QN3fVVPVSzU1zVc8htxyTgGqpLliqCbmduY5tY5kn+vJDFq6ZvAI2NnMdW4ah2wbWCdie6Ti6oeXYMnPiOJ6jeUCGEVvAAiaUN4zTw/B+HJwmwSL8vIiCYBJMpMCmpa+p6ziUUBLPI1/SkmlayiTWmxBGSRCf+kl41Qc6DlMoMHmarSo0znHF4WDcJW7xEgS0HI1/SHNefvcmb5HYmx3NL4I49Pt+fyNXuOoGZr1fIE0fGaalDh/a7X7uJM0FFh3vqX7VU7LdKIzO0CFI5QmRARiM6E+KLodqlmE7mm7opqk7aIBb8XfMM/68A4PIEmpxuCSzYBr4Ceo7kR60C1hiKh1Ahm0bnmcYmmkdy9MVqsaWwsO645XEKEhBV/ersnJTlt53HzNYQ8UaaEeFrLGmBDAhrKtF/7bQ7hcmG5xhFgQAAA==" + } + }, + { + "ID": "afc35f39ea47488c", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/Okf4xRJj2onXCepETkff0UhIbrB?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3627ad631f1005ed4f6d266e8a9e97ff/7038766425964464011;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/Okf4xRJj2onXCepETkff0UhIbrB?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:05 GMT" + ], + "Etag": [ + "1naVHUx5PEW74lQj1xVGNQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "3627ad631f1005ed4f6d266e8a9e97ff" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P0W7CMAxF/8V7BakgNqRKPAxUjU4dg25lk6ZpCqlTWtIkS1wNVPHvJLAn+9rH13YPh1qVEMOurn47tKe7CmkTkhxdJ8n5YLRyCANAYpUnR4ptl8Xxfp18TCdy04yO26fVZjbzhON7bBnEPYgaZekg/upBsRb9mIh+PEEnE8SqeEnydOELrS5vhSx7nGcJnL/PA2j0LkeBFhXH4GasbpBTGg4tO8mRhkZbGk4fxnClr53Xg5gc8+dmrNXnAk3yfhAiKvbpzs49JTVnVGvlweIN/BLSxGSu/1z4Cf71/ETo1lZzdA6DaXRbsNCtkUj+GrIdDoAz/+qyJogFkw7PF+r7QWtIAQAA" + } + }, + { + "ID": "9fc91f19f9bbd730", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon046a4f2a533263a2ce69477231fa54fc779719ec/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "3627ad631f1005ed4f6d266e8a9e97ff/17008057237266678739;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon046a4f2a533263a2ce69477231fa54fc779719ec/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:05 GMT" + ], + "Etag": [ + "JE8J+J/9VDKBzEnXyKGG7A==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "3627ad631f1005ed4f6d266e8a9e97ff" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8p7uVp4aXvpW4a5eDtVueZFVHq7u5s72toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsAwkb6RmbmCrVxgIhAG0j2vZzAAAA" + } + }, + { + "ID": "97b393012d4a31ab", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "259" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "17b0c83b2bf2b4c7123f67d9e8df3304/197825547651497059;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsiYXJyYXlUeXBlIjp7InR5cGUiOiJJTlQ2NCJ9LCJ0eXBlIjoiQVJSQVkifSwicGFyYW1ldGVyVmFsdWUiOnt9fV0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiUE5ZNE05ZHpveU1UTktSZ2x4b1c0VnJuQXdoIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:06 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/4StGW_UTn3TJx84WbsBjJ9Zn-fQ\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1TXW+bMBT9K5P32oRvApGmLktYRJeilpBG7TpFBi7EDWBim6ZZlP8+Q1JpiqZqb7bPuffccy4c0IZUKRqimOTbBtj+8wuN0RUCgXP5+oxm+MmpVHPi/CinPizSu8IPZiXg5ZQr5lxMl6tFVBnRzZtjLmP+7eXGfap62f0zkk1I2zhtigREr6ZM9Aa2PlzM+3fBo3nrpr/p/jYKfoR58UaX5gOrRru1rOJQZDNSbWTtWoiaDxVlt9v1c0rzAnBNeD+hpfI+r/KqKzWjL5AIrlxoKdILVz5Quy5oggWh1ZfFXCpLeggZMKgSQMMDOvf1/2HjxO6Qj928K0ii1DheoYRWGckbdn49tH2ifS0F0f3CCx9lTWeshc6HNhI5x6driaXABam64gjHxX/MmWKBOZzQVeJkjhqrbqw5cabqGWTWwExAtVQHLNWEzE6dgW1jWSfa9l0VrmhlZpabGaC58cCysWZYOrbVzFRjQzdNW3fTDDuqatudRQZYwITwmnJyNj8OvVHkrfzvq8DzJt5ECuwYuWQtQ1+SonARjCVbcmpGqKS1IfhB5IWjceQ/tEDDYQY5TvbzbYGGGS44nIO7wwyXIIBxNPwpw3m/nkI+IHEKexSGozZszBjeX2BSyjbR8Xj8dZR2uMCi4S3cnlpczhf4wRSdQSJXknSEznm7GlK2PM0y7IGmG7rlOBrqyExcYraqmX8vvRMpoRLnr2LuzbxxhNpJpGm2ghITaRkZtm24rmFoptWT6xSqRkvhYn3gbhIjT3KyXW83hRPTeN18TeEVCloD6+eyxytJACcJbSrR/kzo+AeXTHkABwQAAA==" + } + }, + { + "ID": "47f51f821cf0ba18", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/PNY4M9dzoyMTNKRglxoW4VrnAwh?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "371fc72b7beb99c37351a821ebd69946/1762001061754483955;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/PNY4M9dzoyMTNKRglxoW4VrnAwh?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:06 GMT" + ], + "Etag": [ + "e3iAtbn2HDW8u0Hv+NgnrQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "371fc72b7beb99c37351a821ebd69946" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P207CQBCG32W8FBJE4qEJFyiNJYamrFVijDHLdlqK2526OxVLw7u7Ra/m9M0//3TwWZoMAtiUxVeDtj0rkFd9ItA1mp0PNRmHMABkWXgSL8sZb8w4mq9vmlH0fR4Xxq6mU084tcVKQtBBXqLOHARvHRhZoV/LRx+e4Lbui0Wchg+h8I2Ksr4hwiScpeEcju/HAexoIzBHi0Zhr1Zb2qHiRW80a7RCHtZkeXh9NYYTfZok8etkeZsdqF2m8aMo9A+tJy/WzPZbT2lSkksyHnx+An+EiaUWtPcu4QL+67uW0SWWFDqHvejo78A9VbVG9m7YNjgAJf2rUckQ5FI7PP4C7PHXB0gBAAA=" + } + }, + { + "ID": "ca51ee1301f1f216", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon4f59f3e19b756a1352a60f40b3244629dfa80066/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "371fc72b7beb99c37351a821ebd69946/11803348367582998587;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon4f59f3e19b756a1352a60f40b3244629dfa80066/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:07 GMT" + ], + "Etag": [ + "BeeiZdkdAp0HxZhH+PCtEQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "371fc72b7beb99c37351a821ebd69946" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8o7paZmRqVkpzgWGHhURGV4aAc4l7gG2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsA5KxtSAIAEAVChNtAAAA" + } + }, + { + "ID": "0bbd13f8d2264cf8", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "259" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8319ced35ba4b629a15f9f80fc9f2523/13367522782174357963;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsiYXJyYXlUeXBlIjp7InR5cGUiOiJJTlQ2NCJ9LCJ0eXBlIjoiQVJSQVkifSwicGFyYW1ldGVyVmFsdWUiOnt9fV0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoibnBwaUk3WHBBZjlhR2JHbExEZzFOblFuOEpyIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:07 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/aOOYnWSlE9Xi_783cQm3fHHGqjU\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2/aMBT9K5P3tSXvF9LUIchoNkTbAGu7dUKOc526JHZwDAgh/vucQKWpm6p9s33Oveeec5MDWjGeoz7KWLHegNx/fBEZukCgcKFfn9AE/wi56Y7Cb9U4gUV+WybTSQX4ftwY+Obmkd/Pyjh6YMsgdMhd5dDr6/H6ZfGEdBPWNs43JQF1WQupLgPf7i9mPV7XLAke6gGN8Dgbl5NRYU35HQ+/Sl3VQEknjK907bNSddM3jN1u1yuEKErANWt6RFTG67zG1jZqKV6AqMZ4o2VoL43xjtpVKQhWTPBPi5lW1vQUKEjgBFD/gM59k3/YOLE75H03rwqaqDWOF4gITlmxkefXQ9tnvq+1ILpbxOmjrumMtdD50Eai5/hwpbEcGsV4VzzHWfkfc+ZY4QZO6JKENDQzM8qsMKOmTYF6gUvA9MwQPNMF6udh4PtY16m2fVeFueAu9SLqgBVlgedjy/Fs7JvUNTPHdl3fjnKKQ9P0/c6iBKxgxJpaNOxsfpjGg3m8TL4sp3E8ikdaYCfZW9Z9mmjSPF1Mh5qtObVkQtPaEJLpPE4Hw3nyvQU2DUygwGQ/W5eoT3HZwDm4WyxxBQpkg/o/dTiv11PIB6ROYQ/SdNCGjaXE+zeYlvJddDwefx21nUZhtWlauD21uJ5vmkzH6AwyvRLSETrn7WpY1fIsz/EDy3bswA191JGl+gvzAuvPpXciFXB1/ipm8SQezlE7iTYtl1Bhpi0jx/edKHIcy/Uu9TqVaYlKRdgOohVxClKw9fN6VYaZyJ43n3PYQilqkL1C99gyApgQseGq/ZnQ8TeT1/pKBwQAAA==" + } + }, + { + "ID": "c4e060731733fd86", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/nppiI7XpAf9aGbGlLDg1NnQn8Jr?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5faa04e7f2dd600a0979801441a72842/14931416825595601243;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/nppiI7XpAf9aGbGlLDg1NnQn8Jr?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:07 GMT" + ], + "Etag": [ + "Tf6BmMFN04NRDM9YC9sIXw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "5faa04e7f2dd600a0979801441a72842" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2PYW+CQAyG/0v3FRNcFp0mflBhjGUSZSxxWZblOArDHXe3uxJDCP/dQ/epfdun7dsefmtZwBLyuvpr0XR3FdJhTFK0rSDrglbSIniAxCpHZuVs0+yeEv8hSYPd4mO7sPHxvFo5wvIfbBgseyhrFIWF5WcPkjXoxkr/2xHU6VHESRZGYeoKjSrGQhruw3UWBjB8DR6cVJ5iiQYlx3GbNuqEnOLRaNEKjjTRytBkPruHK33tSK3reH7U63LBojwSr0E1TeRBPr4YRwnFGdVKOvD9DdwRUsREqs7OJUzhX286Qrs3iqO1OC71bwe2qtECybkh06IHnLlXn2u66eECSPjC00cBAAA=" + } + }, + { + "ID": "7be6942ad918d3a4", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon4f59f3e19b756a1352a60f40b3244629dfa80066/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5faa04e7f2dd600a0979801441a72842/6526301532674498211;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon4f59f3e19b756a1352a60f40b3244629dfa80066/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:08 GMT" + ], + "Etag": [ + "BeeiZdkdAp0HxZhH+PCtEQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8o7paZmRqVkpzgWGHhURGV4aAc4l7gG2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsA5KxtSAIAEAVChNtAAAA" + } + }, + { + "ID": "74bb806e039d1dde", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "302" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "605a0f8b2d333d6c235e07d64202205d/8090475947282634291;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsiYXJyYXlUeXBlIjp7InR5cGUiOiJJTlQ2NCJ9LCJ0eXBlIjoiQVJSQVkifSwicGFyYW1ldGVyVmFsdWUiOnsiYXJyYXlWYWx1ZXMiOlt7InZhbHVlIjoiMSJ9LHsidmFsdWUiOiIyIn1dfX1dLCJ1c2VMZWdhY3lTcWwiOmZhbHNlfX0sImpvYlJlZmVyZW5jZSI6eyJqb2JJZCI6InEwVHhzaEQzNXBhM2sxSm1uY09vbTlrRTVCQiIsInByb2plY3RJZCI6ImR1bGNldC1wb3J0LTc2MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:08 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/oiU-MuepI5dGF6C7j23BXGgmvBI\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2/aMBT9K5P3tZCnQ4I0dTxSlI2xDkK7RyfkODfBJYlD4sAQ4r/PDnSbuqmalA+2z7n3+BzfHNGGFTHqo4il2waqw+tHHqErBIKk8vQBTclXt9Dtsfs+nwSwjG+zYDbNgdxPao2zZedDA2WA48mNM+o9mtbw8yTNd8PgAckmTDWOm4yC6JS8Ep2eY/aXi+5WD3/U67GFS2JtjHd5QT/y3Nv4eDiUVTVkyZQVG1m7FqKs+5q23++7KedpBqRkdZfyXHu6r7YztbLij0BFrT3T0qSXWntB7TrjlAjGizfLhVSW9DkkUEFBAfWP6NI3+IeNM7tFXnbzpCCJUuN0hSgvEpY21eX0qPqEh1IKok9Lf/5F1rTGFHRZqEjkPV5dSyyGWrCiLQ5JlP3HPWMiSA1ndEXdxNUj3YsMN0p0M4EE92wKOtZdwLoNiRO7Pcchsk6o9m0VKXhBYts2k9jGnq1oFnYwTaKYGiZ2qWtFBjYsTD3cWqyACBizuuQ1u5gfzf1B6K+Cm9XM98f+WArsK/acdT8PJCmcL2cjyZacsmJc0lQIwSz054NRGNwpoKlhCimhh8U2Q/2EZDVcgrslFclBQFWj/jcZztP2HPIRiXPYg/l8oMImVUUOzzAp5djoJK38qr4jWdNSWn67O/ffnQFkSOe/dyY6fT+pT86zIKKpValaKVDamwWzCbqATL4obQltcOplWd62xJbTM0zLdG1LvaQkV+IvDNu9P2emFcmhEJehWvhTfxS2ZmRm1QpywmRiyHIcy/Msy7BxR06D0A2eC4+YPW9DrZSmbLvebjI34tG6eRvDDjJeQtVNZY8do0Ao5U0h1L+ITj8BRAH5gEYEAAA=" + } + }, + { + "ID": "7ae9af72b06b315e", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/q0TxshD35pa3k1JmncOom9kE5BB?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "416fa4a05dea9fadb028ea217f6b5818/9726707955895144387;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/q0TxshD35pa3k1JmncOom9kE5BB?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:09 GMT" + ], + "Etag": [ + "B2hcXpNk7QfkBsc2xuC/QA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "416fa4a05dea9fadb028ea217f6b5818" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P206DQBCG32W8pZHS1EaSXpSWaL2oBTExMcZsl+FQdtktO8QSwru7W72a0zf//DNCU7c5hHCqy0uP3XBXIiUuSdH0gowNWrUGwQMkVloyCir+oQ/NKimayPDg2m/vk816bQnDK5QMwhGKGkVuIPwcoWUS7Vrhf1uCBu2K/SGLn+LUNqTKXSONj/Emi3cwfU0enNUpxQI7bDk6Nd2pM3LaO6N5LzjSTKuOZquHAG70bXLxs6updoulZotm/iJb/qrkYxMvo8hSQnFGtWot+P4G9ggpYiJVP9YlzOG/jgZCc+wUR2PQifp/B7ZKaoFk3VDXowec2Vefa4KwYMLg9Au9u8/rSAEAAA==" + } + }, + { + "ID": "0f4e2c4ee36ef2d8", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonad442fd459404ef3565cfbdc1258c83b15135c95/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "416fa4a05dea9fadb028ea217f6b5818/1249536168464517899;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anonad442fd459404ef3565cfbdc1258c83b15135c95/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:09 GMT" + ], + "Etag": [ + "iUorJw75VEUEERa69rr9Zw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8pnhuYXeZWbm4a5hrq6BiWaWRYVWUaV29oCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsg5FAyVodCMtIqTYWDAGAlA4agAAAAA==" + } + }, + { + "ID": "eed8181ccc910da1", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "316" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "6f49510813a049cda43e57e9d0669a38/2813711682567504795;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsiYXJyYXlUeXBlIjp7InR5cGUiOiJJTlQ2NCJ9LCJ0eXBlIjoiQVJSQVkifSwicGFyYW1ldGVyVmFsdWUiOnsiYXJyYXlWYWx1ZXMiOlt7InZhbHVlIjoiMSJ9LHsidmFsdWUiOiIyIn0seyJ2YWx1ZSI6IjMifV19fV0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiV0VQQVlIa2pZNDhNWUNhNTNsMzQzanExZVRKIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:10 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/PZsWaEDtO1rVantKcp6bYuBVpuM\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1Ta2/aMBT9K5P3tSUJIS+kqWOQdVkpYyGA6Dohx9ykhiQOjgNCiP8+O9A9uqmalA+2z7n3+BzfHNGGFivURTFNtzXww9s1i9EVAoFTefqIhvjBLfTOwL3LbwOYrsZZMBrmgOe3lTZ+qObYH4gvBp/hQtyR0o4X9YdZWd8/ItmEqsarOiMgrkvGxbVjt7vTSWvuj3uLT5v1ouPeL/rYMjOzY663BkSfZVUFWTKkxUbWPglRVl1N2+/3rZSxNANc0qpFWK4931fbtbWSszUQUWkvtDTppdJeUbvJGMGCsuLddCKVJT2EBDgUBFD3iC59g3/YOLMb5HU3zwqSKDVOV4iwIqFpzS+nR9UnOpRSEH2d+uFC1jTGFHRZqEjkPd7cSGwFlaBFUxzhOPuPe66wwBWc0SVxE1ePdS823DjR2wkkltMhoFu6C5begcReuY5tY1knVPumChescL3EcV0zcZzEwdi1Egt0M8EGBtsDwyKxrhs6ic3GIgcsYECrklX0Yr4f+r3IXwYflyPfH/gDKbDn9CVrHgaSFIXTUV+yJafklEmaCiEYRX7Y60fBTAF1BUNIMTlMthnqJjir4BLcGHOcgwBeoe43Gc7z9hzyEYlz2L0w7KmwMef48AKTUnYHnaSVn9UznNUNpeE3u3P/3RlAhnT+a9f+YydT+X5Sn5xugUVdqUZqpUBpdhSMbtEFpPJ9SUNoYlTvTPNGwDJtx2ibbc/xbNSQufgL8xzn9wlqRHIoxGXEJv7Q70eNNZkgX0KOaaZuaNum55mm0bGu5WwI3WC58HDb8TbETElKt0/bTebGLH6q369gBxkrgbdS2WNHCWBCWF0I9Wei0w+gRn8cVAQAAA==" + } + }, + { + "ID": "dea496b0c85830ab", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/WEPAYHkjY48MYCa53l343jq1eTJ?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5a05f852d4bcaf489c70a2317eb28f71/4449942595980065835;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/WEPAYHkjY48MYCa53l343jq1eTJ?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:10 GMT" + ], + "Etag": [ + "ldw+I1jBRB6tcKv1av6FDg==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "5a05f852d4bcaf489c70a2317eb28f71" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/y2P3U6DQBCF32W8lCZFKhqSXpQWLRoNrhhDjDHbZUDowlJ2aEMI796lejV/35w5M8C+qFPwYFfkhw7b/ipHepsShrqTpE1oVK0RLEDiuSFleroO7dJnvkvi+Wjzo/uwyZdLQ2jxixUHb4CsQJlq8L4GqHmFZi2b/xiC+mYqwtc4eAyYaVQqnRosiIJVHGxg/B4tKNWOYYYt1gIntaZVJQoKJ6NpJwXSrFEtze7cG7jQl8lnEK2S7b5MFvcvyZrfOtJZOOXBxvjJUFIJToWqDfjxDuYIKeKSqZNxCTb8135PqKNWCdQaJ9H534G1qhqJZNxQ26EFgptXtwWBl3GpcTwDqB7FMEgBAAA=" + } + }, + { + "ID": "91013769445da8ba", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon89f7883f77f7aa85f5e03fa1ae69e15cb0010cb3/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "5a05f852d4bcaf489c70a2317eb28f71/14419233402987378803;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon89f7883f77f7aa85f5e03fa1ae69e15cb0010cb3/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:10 GMT" + ], + "Etag": [ + "PbU4eb8rBrueMeUb4eaILQ==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "5a05f852d4bcaf489c70a2317eb28f71" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8oHJIWapCZZFDkVlab6poYmmaQmevoE2toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsg5FAyVodCMsIzjJWqo0FQwCZHJnFigAAAA==" + } + }, + { + "ID": "16cebfb48bd0423d", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "475" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f7bec0797f4566644a66cfbad8568086/16055465415911567363;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsic3RydWN0VHlwZXMiOlt7Im5hbWUiOiJBIiwidHlwZSI6eyJ0eXBlIjoiSU5UNjQifX0seyJuYW1lIjoiQiIsInR5cGUiOnsic3RydWN0VHlwZXMiOlt7Im5hbWUiOiJEIiwidHlwZSI6eyJ0eXBlIjoiU1RSSU5HIn19XSwidHlwZSI6IlNUUlVDVCJ9fSx7Im5hbWUiOiJDIiwidHlwZSI6eyJ0eXBlIjoiQk9PTCJ9fV0sInR5cGUiOiJTVFJVQ1QifSwicGFyYW1ldGVyVmFsdWUiOnsic3RydWN0VmFsdWVzIjp7IkEiOnsidmFsdWUiOiIwIn0sIkIiOnt9LCJDIjp7InZhbHVlIjoiZmFsc2UifX19fV0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiZjR3Q0t3cnBlelpYNkFOdGFKM2llTlJldzI3IiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:11 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/f5Hne7fmw0mS3r8Br6ylwqN9sVA\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1UWW/aQBD+K9X2lYDvA6lKCbipG+SkHEmPVGhtj50NvlivsSjiv3dskzZN0uMFeXe+Y+abFXuyZllIhsRn8aYCvnt9n/ukR0DQGG9vyZR+sTJJm1gX6bkLy/Aqcb1pCvTmvBxE+vsMzCitpXSucuuMG7uk3nh2eT26JSjCGuGwSgIQJ0XOxYlpKMPlvB9p9fii5gV8//LJGHmCflAZeDOoFRNZJSTRlGVr5N4JUZTDwaCu636c53ECtGBlP8jTwUO/g60yKHh+D4EoB0+8BjgLdvlnt9MkD6hgefZmOUdnhM8gAg5ZAGS4J0dd94UxOnRb+fs0Dw4IRI9DjwR5FrG44sfbfaOz2BVoSD4undln5LSDNaXjRxMJ9vHqFGshlIJlLXlB/eQ/+gypoCV01VVgRZbkS7YvW34kKRFEuqkFIOmSBbqkQWSElmkYFHmikW9ZNMsz0wcp0iyQNc2XJFmJKCiyDKEaGaaqWyDZoIS2b7YjcqACJqws8pIdhx/PnNHCWbnvVp7jTJwJGtScPUXdzFwELWZLb4xoxBSc5QhrQnC9hTMbjRfudVOoSphCTIPdfJOQYUSTEo7BXVFOUxDASzL8iuE8HLuQ90R0Yc/RZbxo3pvgVSCaakfIEI71URPB7xTswNDI4dD7CTp7DvqX7uRFiuudo/C3x9rj58Czy8tpC+v9GuuaJlWL6fzaY9mcR83PtqsSqdnL+PFNGxmKda7IpqIqOx1cHgJwCV7bVldk+O6CFtCut3l/rO1T1lXDlBVVlWVdaeemXDyrKZjco5fdmqSQiePTnztTB1NrOsHN8hWklOFeiWoYqm0jX9NP8M0KSc5TYVPFtNeBGgcx29xt1onl5/5d9TaELSR5Abwfo8aWBUCDIK8y0fxjkMMP2jHgF+wEAAA=" + } + }, + { + "ID": "06a37b69de2853a7", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/f4wCKwrpezZX6ANtaJ3ieNRew27?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8a073dbba95947881342cd1012ef7c60/17619639830502926739;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/f4wCKwrpezZX6ANtaJ3ieNRew27?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:12 GMT" + ], + "Etag": [ + "gnxO9CzbXYgaoVZPR9gK7w==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "8a073dbba95947881342cd1012ef7c60" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/52RX0/CMBTFv8v1FRL8EwhLeNjGgsiyYQGDGGNKdzeH2zrbu0wgfHc7NGIiTz61pz2/nvZ0D29pEYEF6zR5r1BtLxKk+2bCUFcZaTOUstAILUDiiXEmxUfYd3fr5WPC5cNqyvrJpFcPBsahxSvmHKw9xClmkQbraQ8Fz9FgcefFOGhbNoJ5bsiGRucyanSw8H3b8T2z8pe0T9w4mHsjj50BD60fv/PPnOGJm83ZOBidi3n+FeSeACcMfc8OzhOGgY1cM4xRYSGwKahUcoOCxk33UZUJpHYpFbV73Ss4uo878U3tTmpV4m617NoB8bvrFAOG9VXPuDIpOKWyMMbFzDQAJIlnTNbmWXAJ39rZEuqpkgK1xubQzleAK/MyQzK3IVVhCwQ3v3ebElgxzzQePgFCS8LTGwIAAA==" + } + }, + { + "ID": "5389bb897a7d9d4e", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon7be0f48e144b0012fae211ed3f67358e09e2d9b7/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "8a073dbba95947881342cd1012ef7c60/9214524533303698907;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon7be0f48e144b0012fae211ed3f67358e09e2d9b7/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:12 GMT" + ], + "Etag": [ + "8q2CaNSMAybnbCCFaRZtnA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "8a073dbba95947881342cd1012ef7c60" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8pbFBo5J/oF+zpWJuUlOTu7JQZFleQ52toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsU7JCYioZKNXqgFl5pTk5UKZSWmJOcapSbWwtEMXWAgD3QyHnlQAAAA==" + } + }, + { + "ID": "3ba5aa93392b6bf4", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "508" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "14802d13ac2e9d83c3ba5e1b114035b3/10778700051684810347;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/jobs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "eyJjb25maWd1cmF0aW9uIjp7InF1ZXJ5Ijp7InF1ZXJ5Ijoic2VsZWN0ID8iLCJxdWVyeVBhcmFtZXRlcnMiOlt7InBhcmFtZXRlclR5cGUiOnsic3RydWN0VHlwZXMiOlt7Im5hbWUiOiJBIiwidHlwZSI6eyJ0eXBlIjoiSU5UNjQifX0seyJuYW1lIjoiQiIsInR5cGUiOnsic3RydWN0VHlwZXMiOlt7Im5hbWUiOiJEIiwidHlwZSI6eyJ0eXBlIjoiU1RSSU5HIn19XSwidHlwZSI6IlNUUlVDVCJ9fSx7Im5hbWUiOiJDIiwidHlwZSI6eyJ0eXBlIjoiQk9PTCJ9fV0sInR5cGUiOiJTVFJVQ1QifSwicGFyYW1ldGVyVmFsdWUiOnsic3RydWN0VmFsdWVzIjp7IkEiOnsidmFsdWUiOiIxIn0sIkIiOnsic3RydWN0VmFsdWVzIjp7IkQiOnsidmFsdWUiOiJzIn19fSwiQyI6eyJ2YWx1ZSI6InRydWUifX19fV0sInVzZUxlZ2FjeVNxbCI6ZmFsc2V9fSwiam9iUmVmZXJlbmNlIjp7ImpvYklkIjoiaXBvZXVRZFRJeFh1YkNvM1YxbVdlUklkTzJDIiwicHJvamVjdElkIjoiZHVsY2V0LXBvcnQtNzYyIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:12 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/MtRxMlbEaOt34O-LWo4xQktouMs\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAAAI1UbVObQBD+K53r1ygQCJDMdKwS6jCNieZF+2LHOY4FryEc4Q6jk8l/7x7E1qpj+yUT7nnb3VvYkiUvEjIgMc/WNVQP73+KmHQIKJrh6TUZ0W9+YTpD//PqNIJFcp5H49EK6NWpNM7U9P4sj0M6UbYzORhdCef+YqlEfSavCZpwbZzUOQN1UIpKHXhud7CYHfJSQH2RzKP7L3UcCPvSWl3BNEom3QBVEvJ0xIslam+VKuXAMDabzWEmRJYDLbk8ZGJlPNZr3HWNshI/gSlpPMsysBdpvJF2lAtGFRfFh8UMk5E+hRQqKBiQwZbsfaNX2mjZDfJ2N48JSMSMXYcwUaQ8q6v96Vb7zB9KDCQXi3D6FTVNYxra/9EjwTreHSGWgFS8aMRzGuf/UWdCFZXQojfMT30zNvux5cep2U0h7XkOA7Nn+tAzHUjdxPdcl6JOaftGRQtRmLbpgotC0/ao2aO25Zm071s9SJmVOiiyPOhD0rRYAVUw5LIUku+bD6bh8Ty8iT7djMNwGA4xYFPx56yraYSk+XQxDpCNnLLiAml6CNF4Hk6Pg3l0qYFawggyyh5m65wMUppL2A/unFZ0BQoqSQbfcTiPj+2Qt0S1w55hSjDX+6aqmimNtoIC6Ygf6xH8LcEKXIfsdp3fpJOXpH/5Dl+VRONTNP7x1Dt4STyZTEYNrfOnrUua1w2nzWsepX4+1j93LUosfS8nr9GGT2kS3ZEYPD1DPujjpjqUU1XL1ggvGXG8rHFTfgty3E/WEJo10HvKm36snu16Vte2u57Zb+ZDK/UC80336RvQhKygUPtXZBaOQpyurgQ3oLqBFeV4/8R2Xbvft23L6R3gbivTEivVp12vv2R2xjK+vl0vcz8W8W39MYE7yEUJ1WGGHnecAWVM1IXSXxay+wUrFazBFAUAAA==" + } + }, + { + "ID": "2be3d4756b63da0e", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/ipoeuQdTIxXubCo3V1mWeRIdO2C?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f969d1f156ce27c928d46bf034482d1d/12342875565787797243;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/queries/ipoeuQdTIxXubCo3V1mWeRIdO2C?alt=json\u0026location=US\u0026maxResults=0\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:13 GMT" + ], + "Etag": [ + "9CCB8gPFt690kYd7t6vUqw==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "f969d1f156ce27c928d46bf034482d1d" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/52RX2+CMBTFv8vdqybqEp0kPggyR0JAq+xPlmVBemFooUgvc8b43de6ZS6ZT3tqT3t+Pe3pATZ5ycGCVZ5tG6z3VxnS3EwYqkaQ0kMlS4XQAqQ4086h49g32eyW+sPO5okPqP8ebXejkXao5A2LGKwDpDkKrsB6PkAZF6ixtPOqHbSvjGCuE7KJ1oXkRgeR749t39Urf8nxmfOCpTt12QXw2Prx2//MmZy5xZJ5wfRSzMuvIOcM2GHou+PgMqEZWMsVwxRrLBM0BVW1XGNCnumeNyJBaleypvag34OT+7STVxKbOV96H4/NypHX993iAZnHw57JFjKJKZelNkYL3QCQpFgwudPPgi58a3tPqGa1TFApNId2vgIcWVQCSd+G6gZbkMT69+5yAiuNhcLjJ5CADL0bAgAA" + } + }, + { + "ID": "1ca912afb9e5c78a", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon0306e609b037a05a3170a9815efc1f487617e9ed/data?alt=json\u0026prettyPrint=false\u0026startIndex=0", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "f969d1f156ce27c928d46bf034482d1d/3937759173388620355;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/_c8f80b09b18bf02fef574ce0508e504ef6d8766a/tables/anon0306e609b037a05a3170a9815efc1f487617e9ed/data?alt=json\u0026prettyPrint=false\u0026startIndex=0" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:13 GMT" + ], + "Etag": [ + "GSvmflBrdh2De5ki1v9ATA==" + ], + "Server": [ + "ESF" + ], + "Vary": [ + "Origin", + "X-Origin", + "Referer" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "SAMEORIGIN" + ], + "X-Goog-Trace-Id": [ + "f969d1f156ce27c928d46bf034482d1d" + ], + "X-Xss-Protection": [ + "1; mode=block" + ] + }, + "Body": "H4sIAAAAAAAC/6tWys7MS1GyUkrKTC8sTS2qVC5JTMpJdUksSfTJLC5R0lFKLUlMB8q7B5flpuU4FaVkGLmkmmZnGpZZOoY42toCVZTklyTmBOWXFwOVGQL5RWBmdLVSGpgsU7JCYgJV1OpgCBYr1cbWQsWVSopKU8H8WCAEAGHK9dihAAAA" + } + }, + { + "ID": "342e529cefed34af", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026deleteContents=true\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-46cd593a36b506a79df7" + ], + "X-Cloud-Trace-Context": [ + "002948bdaea5602eb7e1e54c70719110/5501934687474830291;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/bigquery/v2/projects/dulcet-port-762/datasets/dataset_20180912_1679797627000_0001?alt=json\u0026deleteContents=true\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Date": [ + "Wed, 12 Sep 2018 00:32:14 GMT" + ], + "Etag": [ + "\"LaZ8n04D8KmGIeUdPlINLmeaWGs/vyGp6PvFo4RvsFtPoIWeCReyIC8\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "GSE" + ], + "Vary": [ + "Origin", + "X-Origin" + ] + }, + "Body": "" + } + } + ] +} \ No newline at end of file diff --git a/vendor/cloud.google.com/go/bigquery/copy.go b/vendor/cloud.google.com/go/bigquery/copy.go new file mode 100644 index 00000000..44cc68d1 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/copy.go @@ -0,0 +1,107 @@ +// Copyright 2016 Google LLC +// +// 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 bigquery + +import ( + "context" + + bq "google.golang.org/api/bigquery/v2" +) + +// CopyConfig holds the configuration for a copy job. +type CopyConfig struct { + // Srcs are the tables from which data will be copied. + Srcs []*Table + + // Dst is the table into which the data will be copied. + Dst *Table + + // CreateDisposition specifies the circumstances under which the destination table will be created. + // The default is CreateIfNeeded. + CreateDisposition TableCreateDisposition + + // WriteDisposition specifies how existing data in the destination table is treated. + // The default is WriteEmpty. + WriteDisposition TableWriteDisposition + + // The labels associated with this job. + Labels map[string]string + + // Custom encryption configuration (e.g., Cloud KMS keys). + DestinationEncryptionConfig *EncryptionConfig +} + +func (c *CopyConfig) toBQ() *bq.JobConfiguration { + var ts []*bq.TableReference + for _, t := range c.Srcs { + ts = append(ts, t.toBQ()) + } + return &bq.JobConfiguration{ + Labels: c.Labels, + Copy: &bq.JobConfigurationTableCopy{ + CreateDisposition: string(c.CreateDisposition), + WriteDisposition: string(c.WriteDisposition), + DestinationTable: c.Dst.toBQ(), + DestinationEncryptionConfiguration: c.DestinationEncryptionConfig.toBQ(), + SourceTables: ts, + }, + } +} + +func bqToCopyConfig(q *bq.JobConfiguration, c *Client) *CopyConfig { + cc := &CopyConfig{ + Labels: q.Labels, + CreateDisposition: TableCreateDisposition(q.Copy.CreateDisposition), + WriteDisposition: TableWriteDisposition(q.Copy.WriteDisposition), + Dst: bqToTable(q.Copy.DestinationTable, c), + DestinationEncryptionConfig: bqToEncryptionConfig(q.Copy.DestinationEncryptionConfiguration), + } + for _, t := range q.Copy.SourceTables { + cc.Srcs = append(cc.Srcs, bqToTable(t, c)) + } + return cc +} + +// A Copier copies data into a BigQuery table from one or more BigQuery tables. +type Copier struct { + JobIDConfig + CopyConfig + c *Client +} + +// CopierFrom returns a Copier which can be used to copy data into a +// BigQuery table from one or more BigQuery tables. +// The returned Copier may optionally be further configured before its Run method is called. +func (t *Table) CopierFrom(srcs ...*Table) *Copier { + return &Copier{ + c: t.c, + CopyConfig: CopyConfig{ + Srcs: srcs, + Dst: t, + }, + } +} + +// Run initiates a copy job. +func (c *Copier) Run(ctx context.Context) (*Job, error) { + return c.c.insertJob(ctx, c.newJob(), nil) +} + +func (c *Copier) newJob() *bq.Job { + return &bq.Job{ + JobReference: c.JobIDConfig.createJobRef(c.c), + Configuration: c.CopyConfig.toBQ(), + } +} diff --git a/vendor/cloud.google.com/go/bigquery/copy_test.go b/vendor/cloud.google.com/go/bigquery/copy_test.go new file mode 100644 index 00000000..5b4ef878 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/copy_test.go @@ -0,0 +1,163 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "testing" + + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp/cmpopts" + bq "google.golang.org/api/bigquery/v2" +) + +func defaultCopyJob() *bq.Job { + return &bq.Job{ + JobReference: &bq.JobReference{JobId: "RANDOM", ProjectId: "client-project-id"}, + Configuration: &bq.JobConfiguration{ + Copy: &bq.JobConfigurationTableCopy{ + DestinationTable: &bq.TableReference{ + ProjectId: "d-project-id", + DatasetId: "d-dataset-id", + TableId: "d-table-id", + }, + SourceTables: []*bq.TableReference{ + { + ProjectId: "s-project-id", + DatasetId: "s-dataset-id", + TableId: "s-table-id", + }, + }, + }, + }, + } +} + +func TestCopy(t *testing.T) { + defer fixRandomID("RANDOM")() + testCases := []struct { + dst *Table + srcs []*Table + jobID string + location string + config CopyConfig + want *bq.Job + }{ + { + dst: &Table{ + ProjectID: "d-project-id", + DatasetID: "d-dataset-id", + TableID: "d-table-id", + }, + srcs: []*Table{ + { + ProjectID: "s-project-id", + DatasetID: "s-dataset-id", + TableID: "s-table-id", + }, + }, + want: defaultCopyJob(), + }, + { + dst: &Table{ + ProjectID: "d-project-id", + DatasetID: "d-dataset-id", + TableID: "d-table-id", + }, + srcs: []*Table{ + { + ProjectID: "s-project-id", + DatasetID: "s-dataset-id", + TableID: "s-table-id", + }, + }, + config: CopyConfig{ + CreateDisposition: CreateNever, + WriteDisposition: WriteTruncate, + DestinationEncryptionConfig: &EncryptionConfig{KMSKeyName: "keyName"}, + Labels: map[string]string{"a": "b"}, + }, + want: func() *bq.Job { + j := defaultCopyJob() + j.Configuration.Labels = map[string]string{"a": "b"} + j.Configuration.Copy.CreateDisposition = "CREATE_NEVER" + j.Configuration.Copy.WriteDisposition = "WRITE_TRUNCATE" + j.Configuration.Copy.DestinationEncryptionConfiguration = &bq.EncryptionConfiguration{KmsKeyName: "keyName"} + return j + }(), + }, + { + dst: &Table{ + ProjectID: "d-project-id", + DatasetID: "d-dataset-id", + TableID: "d-table-id", + }, + srcs: []*Table{ + { + ProjectID: "s-project-id", + DatasetID: "s-dataset-id", + TableID: "s-table-id", + }, + }, + jobID: "job-id", + want: func() *bq.Job { + j := defaultCopyJob() + j.JobReference.JobId = "job-id" + return j + }(), + }, + { + dst: &Table{ + ProjectID: "d-project-id", + DatasetID: "d-dataset-id", + TableID: "d-table-id", + }, + srcs: []*Table{ + { + ProjectID: "s-project-id", + DatasetID: "s-dataset-id", + TableID: "s-table-id", + }, + }, + location: "asia-northeast1", + want: func() *bq.Job { + j := defaultCopyJob() + j.JobReference.Location = "asia-northeast1" + return j + }(), + }, + } + c := &Client{projectID: "client-project-id"} + for i, tc := range testCases { + tc.dst.c = c + copier := tc.dst.CopierFrom(tc.srcs...) + copier.JobID = tc.jobID + copier.Location = tc.location + tc.config.Srcs = tc.srcs + tc.config.Dst = tc.dst + copier.CopyConfig = tc.config + got := copier.newJob() + checkJob(t, i, got, tc.want) + + jc, err := bqToJobConfig(got.Configuration, c) + if err != nil { + t.Fatalf("#%d: %v", i, err) + } + diff := testutil.Diff(jc.(*CopyConfig), &copier.CopyConfig, + cmpopts.IgnoreUnexported(Table{})) + if diff != "" { + t.Errorf("#%d: (got=-, want=+:\n%s", i, diff) + } + } +} diff --git a/vendor/cloud.google.com/go/bigquery/dataset.go b/vendor/cloud.google.com/go/bigquery/dataset.go new file mode 100644 index 00000000..7bdb70a5 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/dataset.go @@ -0,0 +1,536 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "context" + "errors" + "fmt" + "time" + + "cloud.google.com/go/internal/optional" + "cloud.google.com/go/internal/trace" + bq "google.golang.org/api/bigquery/v2" + "google.golang.org/api/iterator" +) + +// Dataset is a reference to a BigQuery dataset. +type Dataset struct { + ProjectID string + DatasetID string + c *Client +} + +// DatasetMetadata contains information about a BigQuery dataset. +type DatasetMetadata struct { + // These fields can be set when creating a dataset. + Name string // The user-friendly name for this dataset. + Description string // The user-friendly description of this dataset. + Location string // The geo location of the dataset. + DefaultTableExpiration time.Duration // The default expiration time for new tables. + Labels map[string]string // User-provided labels. + Access []*AccessEntry // Access permissions. + + // These fields are read-only. + CreationTime time.Time + LastModifiedTime time.Time // When the dataset or any of its tables were modified. + FullID string // The full dataset ID in the form projectID:datasetID. + + // ETag is the ETag obtained when reading metadata. Pass it to Dataset.Update to + // ensure that the metadata hasn't changed since it was read. + ETag string +} + +// DatasetMetadataToUpdate is used when updating a dataset's metadata. +// Only non-nil fields will be updated. +type DatasetMetadataToUpdate struct { + Description optional.String // The user-friendly description of this table. + Name optional.String // The user-friendly name for this dataset. + + // DefaultTableExpiration is the default expiration time for new tables. + // If set to time.Duration(0), new tables never expire. + DefaultTableExpiration optional.Duration + + // The entire access list. It is not possible to replace individual entries. + Access []*AccessEntry + + labelUpdater +} + +// Dataset creates a handle to a BigQuery dataset in the client's project. +func (c *Client) Dataset(id string) *Dataset { + return c.DatasetInProject(c.projectID, id) +} + +// DatasetInProject creates a handle to a BigQuery dataset in the specified project. +func (c *Client) DatasetInProject(projectID, datasetID string) *Dataset { + return &Dataset{ + ProjectID: projectID, + DatasetID: datasetID, + c: c, + } +} + +// Create creates a dataset in the BigQuery service. An error will be returned if the +// dataset already exists. Pass in a DatasetMetadata value to configure the dataset. +func (d *Dataset) Create(ctx context.Context, md *DatasetMetadata) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Dataset.Create") + defer func() { trace.EndSpan(ctx, err) }() + + ds, err := md.toBQ() + if err != nil { + return err + } + ds.DatasetReference = &bq.DatasetReference{DatasetId: d.DatasetID} + // Use Client.Location as a default. + if ds.Location == "" { + ds.Location = d.c.Location + } + call := d.c.bqs.Datasets.Insert(d.ProjectID, ds).Context(ctx) + setClientHeader(call.Header()) + _, err = call.Do() + return err +} + +func (dm *DatasetMetadata) toBQ() (*bq.Dataset, error) { + ds := &bq.Dataset{} + if dm == nil { + return ds, nil + } + ds.FriendlyName = dm.Name + ds.Description = dm.Description + ds.Location = dm.Location + ds.DefaultTableExpirationMs = int64(dm.DefaultTableExpiration / time.Millisecond) + ds.Labels = dm.Labels + var err error + ds.Access, err = accessListToBQ(dm.Access) + if err != nil { + return nil, err + } + if !dm.CreationTime.IsZero() { + return nil, errors.New("bigquery: Dataset.CreationTime is not writable") + } + if !dm.LastModifiedTime.IsZero() { + return nil, errors.New("bigquery: Dataset.LastModifiedTime is not writable") + } + if dm.FullID != "" { + return nil, errors.New("bigquery: Dataset.FullID is not writable") + } + if dm.ETag != "" { + return nil, errors.New("bigquery: Dataset.ETag is not writable") + } + return ds, nil +} + +func accessListToBQ(a []*AccessEntry) ([]*bq.DatasetAccess, error) { + var q []*bq.DatasetAccess + for _, e := range a { + a, err := e.toBQ() + if err != nil { + return nil, err + } + q = append(q, a) + } + return q, nil +} + +// Delete deletes the dataset. Delete will fail if the dataset is not empty. +func (d *Dataset) Delete(ctx context.Context) (err error) { + return d.deleteInternal(ctx, false) +} + +// DeleteWithContents deletes the dataset, as well as contained resources. +func (d *Dataset) DeleteWithContents(ctx context.Context) (err error) { + return d.deleteInternal(ctx, true) +} + +func (d *Dataset) deleteInternal(ctx context.Context, deleteContents bool) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Dataset.Delete") + defer func() { trace.EndSpan(ctx, err) }() + + call := d.c.bqs.Datasets.Delete(d.ProjectID, d.DatasetID).Context(ctx).DeleteContents(deleteContents) + setClientHeader(call.Header()) + return call.Do() +} + +// Metadata fetches the metadata for the dataset. +func (d *Dataset) Metadata(ctx context.Context) (md *DatasetMetadata, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Dataset.Metadata") + defer func() { trace.EndSpan(ctx, err) }() + + call := d.c.bqs.Datasets.Get(d.ProjectID, d.DatasetID).Context(ctx) + setClientHeader(call.Header()) + var ds *bq.Dataset + if err := runWithRetry(ctx, func() (err error) { + ds, err = call.Do() + return err + }); err != nil { + return nil, err + } + return bqToDatasetMetadata(ds) +} + +func bqToDatasetMetadata(d *bq.Dataset) (*DatasetMetadata, error) { + dm := &DatasetMetadata{ + CreationTime: unixMillisToTime(d.CreationTime), + LastModifiedTime: unixMillisToTime(d.LastModifiedTime), + DefaultTableExpiration: time.Duration(d.DefaultTableExpirationMs) * time.Millisecond, + Description: d.Description, + Name: d.FriendlyName, + FullID: d.Id, + Location: d.Location, + Labels: d.Labels, + ETag: d.Etag, + } + for _, a := range d.Access { + e, err := bqToAccessEntry(a, nil) + if err != nil { + return nil, err + } + dm.Access = append(dm.Access, e) + } + return dm, nil +} + +// Update modifies specific Dataset metadata fields. +// To perform a read-modify-write that protects against intervening reads, +// set the etag argument to the DatasetMetadata.ETag field from the read. +// Pass the empty string for etag for a "blind write" that will always succeed. +func (d *Dataset) Update(ctx context.Context, dm DatasetMetadataToUpdate, etag string) (md *DatasetMetadata, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Dataset.Update") + defer func() { trace.EndSpan(ctx, err) }() + + ds, err := dm.toBQ() + if err != nil { + return nil, err + } + call := d.c.bqs.Datasets.Patch(d.ProjectID, d.DatasetID, ds).Context(ctx) + setClientHeader(call.Header()) + if etag != "" { + call.Header().Set("If-Match", etag) + } + var ds2 *bq.Dataset + if err := runWithRetry(ctx, func() (err error) { + ds2, err = call.Do() + return err + }); err != nil { + return nil, err + } + return bqToDatasetMetadata(ds2) +} + +func (dm *DatasetMetadataToUpdate) toBQ() (*bq.Dataset, error) { + ds := &bq.Dataset{} + forceSend := func(field string) { + ds.ForceSendFields = append(ds.ForceSendFields, field) + } + + if dm.Description != nil { + ds.Description = optional.ToString(dm.Description) + forceSend("Description") + } + if dm.Name != nil { + ds.FriendlyName = optional.ToString(dm.Name) + forceSend("FriendlyName") + } + if dm.DefaultTableExpiration != nil { + dur := optional.ToDuration(dm.DefaultTableExpiration) + if dur == 0 { + // Send a null to delete the field. + ds.NullFields = append(ds.NullFields, "DefaultTableExpirationMs") + } else { + ds.DefaultTableExpirationMs = int64(dur / time.Millisecond) + } + } + if dm.Access != nil { + var err error + ds.Access, err = accessListToBQ(dm.Access) + if err != nil { + return nil, err + } + if len(ds.Access) == 0 { + ds.NullFields = append(ds.NullFields, "Access") + } + } + labels, forces, nulls := dm.update() + ds.Labels = labels + ds.ForceSendFields = append(ds.ForceSendFields, forces...) + ds.NullFields = append(ds.NullFields, nulls...) + return ds, nil +} + +// Table creates a handle to a BigQuery table in the dataset. +// To determine if a table exists, call Table.Metadata. +// If the table does not already exist, use Table.Create to create it. +func (d *Dataset) Table(tableID string) *Table { + return &Table{ProjectID: d.ProjectID, DatasetID: d.DatasetID, TableID: tableID, c: d.c} +} + +// Tables returns an iterator over the tables in the Dataset. +func (d *Dataset) Tables(ctx context.Context) *TableIterator { + it := &TableIterator{ + ctx: ctx, + dataset: d, + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.tables) }, + func() interface{} { b := it.tables; it.tables = nil; return b }) + return it +} + +// A TableIterator is an iterator over Tables. +type TableIterator struct { + ctx context.Context + dataset *Dataset + tables []*Table + pageInfo *iterator.PageInfo + nextFunc func() error +} + +// Next returns the next result. Its second return value is Done if there are +// no more results. Once Next returns Done, all subsequent calls will return +// Done. +func (it *TableIterator) Next() (*Table, error) { + if err := it.nextFunc(); err != nil { + return nil, err + } + t := it.tables[0] + it.tables = it.tables[1:] + return t, nil +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TableIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } + +// for testing +var listTables = func(it *TableIterator, pageSize int, pageToken string) (*bq.TableList, error) { + call := it.dataset.c.bqs.Tables.List(it.dataset.ProjectID, it.dataset.DatasetID). + PageToken(pageToken). + Context(it.ctx) + setClientHeader(call.Header()) + if pageSize > 0 { + call.MaxResults(int64(pageSize)) + } + var res *bq.TableList + err := runWithRetry(it.ctx, func() (err error) { + res, err = call.Do() + return err + }) + return res, err +} + +func (it *TableIterator) fetch(pageSize int, pageToken string) (string, error) { + res, err := listTables(it, pageSize, pageToken) + if err != nil { + return "", err + } + for _, t := range res.Tables { + it.tables = append(it.tables, bqToTable(t.TableReference, it.dataset.c)) + } + return res.NextPageToken, nil +} + +func bqToTable(tr *bq.TableReference, c *Client) *Table { + if tr == nil { + return nil + } + return &Table{ + ProjectID: tr.ProjectId, + DatasetID: tr.DatasetId, + TableID: tr.TableId, + c: c, + } +} + +// Datasets returns an iterator over the datasets in a project. +// The Client's project is used by default, but that can be +// changed by setting ProjectID on the returned iterator before calling Next. +func (c *Client) Datasets(ctx context.Context) *DatasetIterator { + return c.DatasetsInProject(ctx, c.projectID) +} + +// DatasetsInProject returns an iterator over the datasets in the provided project. +// +// Deprecated: call Client.Datasets, then set ProjectID on the returned iterator. +func (c *Client) DatasetsInProject(ctx context.Context, projectID string) *DatasetIterator { + it := &DatasetIterator{ + ctx: ctx, + c: c, + ProjectID: projectID, + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.items) }, + func() interface{} { b := it.items; it.items = nil; return b }) + return it +} + +// DatasetIterator iterates over the datasets in a project. +type DatasetIterator struct { + // ListHidden causes hidden datasets to be listed when set to true. + // Set before the first call to Next. + ListHidden bool + + // Filter restricts the datasets returned by label. The filter syntax is described in + // https://cloud.google.com/bigquery/docs/labeling-datasets#filtering_datasets_using_labels + // Set before the first call to Next. + Filter string + + // The project ID of the listed datasets. + // Set before the first call to Next. + ProjectID string + + ctx context.Context + c *Client + pageInfo *iterator.PageInfo + nextFunc func() error + items []*Dataset +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *DatasetIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } + +// Next returns the next Dataset. Its second return value is iterator.Done if +// there are no more results. Once Next returns Done, all subsequent calls will +// return Done. +func (it *DatasetIterator) Next() (*Dataset, error) { + if err := it.nextFunc(); err != nil { + return nil, err + } + item := it.items[0] + it.items = it.items[1:] + return item, nil +} + +// for testing +var listDatasets = func(it *DatasetIterator, pageSize int, pageToken string) (*bq.DatasetList, error) { + call := it.c.bqs.Datasets.List(it.ProjectID). + Context(it.ctx). + PageToken(pageToken). + All(it.ListHidden) + setClientHeader(call.Header()) + if pageSize > 0 { + call.MaxResults(int64(pageSize)) + } + if it.Filter != "" { + call.Filter(it.Filter) + } + var res *bq.DatasetList + err := runWithRetry(it.ctx, func() (err error) { + res, err = call.Do() + return err + }) + return res, err +} + +func (it *DatasetIterator) fetch(pageSize int, pageToken string) (string, error) { + res, err := listDatasets(it, pageSize, pageToken) + if err != nil { + return "", err + } + for _, d := range res.Datasets { + it.items = append(it.items, &Dataset{ + ProjectID: d.DatasetReference.ProjectId, + DatasetID: d.DatasetReference.DatasetId, + c: it.c, + }) + } + return res.NextPageToken, nil +} + +// An AccessEntry describes the permissions that an entity has on a dataset. +type AccessEntry struct { + Role AccessRole // The role of the entity + EntityType EntityType // The type of entity + Entity string // The entity (individual or group) granted access + View *Table // The view granted access (EntityType must be ViewEntity) +} + +// AccessRole is the level of access to grant to a dataset. +type AccessRole string + +const ( + // OwnerRole is the OWNER AccessRole. + OwnerRole AccessRole = "OWNER" + // ReaderRole is the READER AccessRole. + ReaderRole AccessRole = "READER" + // WriterRole is the WRITER AccessRole. + WriterRole AccessRole = "WRITER" +) + +// EntityType is the type of entity in an AccessEntry. +type EntityType int + +const ( + // DomainEntity is a domain (e.g. "example.com"). + DomainEntity EntityType = iota + 1 + + // GroupEmailEntity is an email address of a Google Group. + GroupEmailEntity + + // UserEmailEntity is an email address of an individual user. + UserEmailEntity + + // SpecialGroupEntity is a special group: one of projectOwners, projectReaders, projectWriters or + // allAuthenticatedUsers. + SpecialGroupEntity + + // ViewEntity is a BigQuery view. + ViewEntity +) + +func (e *AccessEntry) toBQ() (*bq.DatasetAccess, error) { + q := &bq.DatasetAccess{Role: string(e.Role)} + switch e.EntityType { + case DomainEntity: + q.Domain = e.Entity + case GroupEmailEntity: + q.GroupByEmail = e.Entity + case UserEmailEntity: + q.UserByEmail = e.Entity + case SpecialGroupEntity: + q.SpecialGroup = e.Entity + case ViewEntity: + q.View = e.View.toBQ() + default: + return nil, fmt.Errorf("bigquery: unknown entity type %d", e.EntityType) + } + return q, nil +} + +func bqToAccessEntry(q *bq.DatasetAccess, c *Client) (*AccessEntry, error) { + e := &AccessEntry{Role: AccessRole(q.Role)} + switch { + case q.Domain != "": + e.Entity = q.Domain + e.EntityType = DomainEntity + case q.GroupByEmail != "": + e.Entity = q.GroupByEmail + e.EntityType = GroupEmailEntity + case q.UserByEmail != "": + e.Entity = q.UserByEmail + e.EntityType = UserEmailEntity + case q.SpecialGroup != "": + e.Entity = q.SpecialGroup + e.EntityType = SpecialGroupEntity + case q.View != nil: + e.View = c.DatasetInProject(q.View.ProjectId, q.View.DatasetId).Table(q.View.TableId) + e.EntityType = ViewEntity + default: + return nil, errors.New("bigquery: invalid access value") + } + return e, nil +} diff --git a/vendor/cloud.google.com/go/bigquery/dataset_test.go b/vendor/cloud.google.com/go/bigquery/dataset_test.go new file mode 100644 index 00000000..03a05097 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/dataset_test.go @@ -0,0 +1,326 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "context" + "errors" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" + bq "google.golang.org/api/bigquery/v2" + itest "google.golang.org/api/iterator/testing" +) + +// readServiceStub services read requests by returning data from an in-memory list of values. +type listTablesStub struct { + expectedProject, expectedDataset string + tables []*bq.TableListTables +} + +func (s *listTablesStub) listTables(it *TableIterator, pageSize int, pageToken string) (*bq.TableList, error) { + if it.dataset.ProjectID != s.expectedProject { + return nil, errors.New("wrong project id") + } + if it.dataset.DatasetID != s.expectedDataset { + return nil, errors.New("wrong dataset id") + } + const maxPageSize = 2 + if pageSize <= 0 || pageSize > maxPageSize { + pageSize = maxPageSize + } + start := 0 + if pageToken != "" { + var err error + start, err = strconv.Atoi(pageToken) + if err != nil { + return nil, err + } + } + end := start + pageSize + if end > len(s.tables) { + end = len(s.tables) + } + nextPageToken := "" + if end < len(s.tables) { + nextPageToken = strconv.Itoa(end) + } + return &bq.TableList{ + Tables: s.tables[start:end], + NextPageToken: nextPageToken, + }, nil +} + +func TestTables(t *testing.T) { + c := &Client{projectID: "p1"} + inTables := []*bq.TableListTables{ + {TableReference: &bq.TableReference{ProjectId: "p1", DatasetId: "d1", TableId: "t1"}}, + {TableReference: &bq.TableReference{ProjectId: "p1", DatasetId: "d1", TableId: "t2"}}, + {TableReference: &bq.TableReference{ProjectId: "p1", DatasetId: "d1", TableId: "t3"}}, + } + outTables := []*Table{ + {ProjectID: "p1", DatasetID: "d1", TableID: "t1", c: c}, + {ProjectID: "p1", DatasetID: "d1", TableID: "t2", c: c}, + {ProjectID: "p1", DatasetID: "d1", TableID: "t3", c: c}, + } + + lts := &listTablesStub{ + expectedProject: "p1", + expectedDataset: "d1", + tables: inTables, + } + old := listTables + listTables = lts.listTables // cannot use t.Parallel with this test + defer func() { listTables = old }() + + msg, ok := itest.TestIterator(outTables, + func() interface{} { return c.Dataset("d1").Tables(context.Background()) }, + func(it interface{}) (interface{}, error) { return it.(*TableIterator).Next() }) + if !ok { + t.Error(msg) + } +} + +type listDatasetsStub struct { + expectedProject string + datasets []*bq.DatasetListDatasets + hidden map[*bq.DatasetListDatasets]bool +} + +func (s *listDatasetsStub) listDatasets(it *DatasetIterator, pageSize int, pageToken string) (*bq.DatasetList, error) { + const maxPageSize = 2 + if pageSize <= 0 || pageSize > maxPageSize { + pageSize = maxPageSize + } + if it.Filter != "" { + return nil, errors.New("filter not supported") + } + if it.ProjectID != s.expectedProject { + return nil, errors.New("bad project ID") + } + start := 0 + if pageToken != "" { + var err error + start, err = strconv.Atoi(pageToken) + if err != nil { + return nil, err + } + } + var ( + i int + result []*bq.DatasetListDatasets + nextPageToken string + ) + for i = start; len(result) < pageSize && i < len(s.datasets); i++ { + if s.hidden[s.datasets[i]] && !it.ListHidden { + continue + } + result = append(result, s.datasets[i]) + } + if i < len(s.datasets) { + nextPageToken = strconv.Itoa(i) + } + return &bq.DatasetList{ + Datasets: result, + NextPageToken: nextPageToken, + }, nil +} + +func TestDatasets(t *testing.T) { + client := &Client{projectID: "p"} + inDatasets := []*bq.DatasetListDatasets{ + {DatasetReference: &bq.DatasetReference{ProjectId: "p", DatasetId: "a"}}, + {DatasetReference: &bq.DatasetReference{ProjectId: "p", DatasetId: "b"}}, + {DatasetReference: &bq.DatasetReference{ProjectId: "p", DatasetId: "hidden"}}, + {DatasetReference: &bq.DatasetReference{ProjectId: "p", DatasetId: "c"}}, + } + outDatasets := []*Dataset{ + {"p", "a", client}, + {"p", "b", client}, + {"p", "hidden", client}, + {"p", "c", client}, + } + lds := &listDatasetsStub{ + expectedProject: "p", + datasets: inDatasets, + hidden: map[*bq.DatasetListDatasets]bool{inDatasets[2]: true}, + } + old := listDatasets + listDatasets = lds.listDatasets // cannot use t.Parallel with this test + defer func() { listDatasets = old }() + + msg, ok := itest.TestIterator(outDatasets, + func() interface{} { it := client.Datasets(context.Background()); it.ListHidden = true; return it }, + func(it interface{}) (interface{}, error) { return it.(*DatasetIterator).Next() }) + if !ok { + t.Fatalf("ListHidden=true: %s", msg) + } + + msg, ok = itest.TestIterator([]*Dataset{outDatasets[0], outDatasets[1], outDatasets[3]}, + func() interface{} { it := client.Datasets(context.Background()); it.ListHidden = false; return it }, + func(it interface{}) (interface{}, error) { return it.(*DatasetIterator).Next() }) + if !ok { + t.Fatalf("ListHidden=false: %s", msg) + } +} + +func TestDatasetToBQ(t *testing.T) { + for _, test := range []struct { + in *DatasetMetadata + want *bq.Dataset + }{ + {nil, &bq.Dataset{}}, + {&DatasetMetadata{Name: "name"}, &bq.Dataset{FriendlyName: "name"}}, + {&DatasetMetadata{ + Name: "name", + Description: "desc", + DefaultTableExpiration: time.Hour, + Location: "EU", + Labels: map[string]string{"x": "y"}, + Access: []*AccessEntry{{Role: OwnerRole, Entity: "example.com", EntityType: DomainEntity}}, + }, &bq.Dataset{ + FriendlyName: "name", + Description: "desc", + DefaultTableExpirationMs: 60 * 60 * 1000, + Location: "EU", + Labels: map[string]string{"x": "y"}, + Access: []*bq.DatasetAccess{{Role: "OWNER", Domain: "example.com"}}, + }}, + } { + got, err := test.in.toBQ() + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(got, test.want) { + t.Errorf("%v:\ngot %+v\nwant %+v", test.in, got, test.want) + } + } + + // Check that non-writeable fields are unset. + aTime := time.Date(2017, 1, 26, 0, 0, 0, 0, time.Local) + for _, dm := range []*DatasetMetadata{ + {CreationTime: aTime}, + {LastModifiedTime: aTime}, + {FullID: "x"}, + {ETag: "e"}, + } { + if _, err := dm.toBQ(); err == nil { + t.Errorf("%+v: got nil, want error", dm) + } + } +} + +func TestBQToDatasetMetadata(t *testing.T) { + cTime := time.Date(2017, 1, 26, 0, 0, 0, 0, time.Local) + cMillis := cTime.UnixNano() / 1e6 + mTime := time.Date(2017, 10, 31, 0, 0, 0, 0, time.Local) + mMillis := mTime.UnixNano() / 1e6 + q := &bq.Dataset{ + CreationTime: cMillis, + LastModifiedTime: mMillis, + FriendlyName: "name", + Description: "desc", + DefaultTableExpirationMs: 60 * 60 * 1000, + Location: "EU", + Labels: map[string]string{"x": "y"}, + Access: []*bq.DatasetAccess{ + {Role: "READER", UserByEmail: "joe@example.com"}, + {Role: "WRITER", GroupByEmail: "users@example.com"}, + }, + Etag: "etag", + } + want := &DatasetMetadata{ + CreationTime: cTime, + LastModifiedTime: mTime, + Name: "name", + Description: "desc", + DefaultTableExpiration: time.Hour, + Location: "EU", + Labels: map[string]string{"x": "y"}, + Access: []*AccessEntry{ + {Role: ReaderRole, Entity: "joe@example.com", EntityType: UserEmailEntity}, + {Role: WriterRole, Entity: "users@example.com", EntityType: GroupEmailEntity}, + }, + ETag: "etag", + } + got, err := bqToDatasetMetadata(q) + if err != nil { + t.Fatal(err) + } + if diff := testutil.Diff(got, want); diff != "" { + t.Errorf("-got, +want:\n%s", diff) + } +} + +func TestDatasetMetadataToUpdateToBQ(t *testing.T) { + dm := DatasetMetadataToUpdate{ + Description: "desc", + Name: "name", + DefaultTableExpiration: time.Hour, + } + dm.SetLabel("label", "value") + dm.DeleteLabel("del") + + got, err := dm.toBQ() + if err != nil { + t.Fatal(err) + } + want := &bq.Dataset{ + Description: "desc", + FriendlyName: "name", + DefaultTableExpirationMs: 60 * 60 * 1000, + Labels: map[string]string{"label": "value"}, + ForceSendFields: []string{"Description", "FriendlyName"}, + NullFields: []string{"Labels.del"}, + } + if diff := testutil.Diff(got, want); diff != "" { + t.Errorf("-got, +want:\n%s", diff) + } +} + +func TestConvertAccessEntry(t *testing.T) { + c := &Client{projectID: "pid"} + for _, e := range []*AccessEntry{ + {Role: ReaderRole, Entity: "e", EntityType: DomainEntity}, + {Role: WriterRole, Entity: "e", EntityType: GroupEmailEntity}, + {Role: OwnerRole, Entity: "e", EntityType: UserEmailEntity}, + {Role: ReaderRole, Entity: "e", EntityType: SpecialGroupEntity}, + {Role: ReaderRole, EntityType: ViewEntity, + View: &Table{ProjectID: "p", DatasetID: "d", TableID: "t", c: c}}, + } { + q, err := e.toBQ() + if err != nil { + t.Fatal(err) + } + got, err := bqToAccessEntry(q, c) + if err != nil { + t.Fatal(err) + } + if diff := testutil.Diff(got, e, cmp.AllowUnexported(Table{}, Client{})); diff != "" { + t.Errorf("got=-, want=+:\n%s", diff) + } + } + + e := &AccessEntry{Role: ReaderRole, Entity: "e"} + if _, err := e.toBQ(); err == nil { + t.Error("got nil, want error") + } + if _, err := bqToAccessEntry(&bq.DatasetAccess{Role: "WRITER"}, nil); err == nil { + t.Error("got nil, want error") + } +} diff --git a/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/ListDataSources_smoke_test.go b/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/ListDataSources_smoke_test.go new file mode 100644 index 00000000..3367617f --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/ListDataSources_smoke_test.go @@ -0,0 +1,67 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package datatransfer + +import ( + datatransferpb "google.golang.org/genproto/googleapis/cloud/bigquery/datatransfer/v1" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestDataTransferServiceSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var formattedParent string = fmt.Sprintf("projects/%s", projectId) + var request = &datatransferpb.ListDataSourcesRequest{ + Parent: formattedParent, + } + + iter := c.ListDataSources(ctx, request) + if _, err := iter.Next(); err != nil && err != iterator.Done { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/data_transfer_client.go b/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/data_transfer_client.go new file mode 100644 index 00000000..fea963e0 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/data_transfer_client.go @@ -0,0 +1,625 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package datatransfer + +import ( + "context" + "fmt" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + datatransferpb "google.golang.org/genproto/googleapis/cloud/bigquery/datatransfer/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + GetDataSource []gax.CallOption + ListDataSources []gax.CallOption + CreateTransferConfig []gax.CallOption + UpdateTransferConfig []gax.CallOption + DeleteTransferConfig []gax.CallOption + GetTransferConfig []gax.CallOption + ListTransferConfigs []gax.CallOption + ScheduleTransferRuns []gax.CallOption + GetTransferRun []gax.CallOption + DeleteTransferRun []gax.CallOption + ListTransferRuns []gax.CallOption + ListTransferLogs []gax.CallOption + CheckValidCreds []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("bigquerydatatransfer.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + GetDataSource: retry[[2]string{"default", "idempotent"}], + ListDataSources: retry[[2]string{"default", "idempotent"}], + CreateTransferConfig: retry[[2]string{"default", "non_idempotent"}], + UpdateTransferConfig: retry[[2]string{"default", "non_idempotent"}], + DeleteTransferConfig: retry[[2]string{"default", "idempotent"}], + GetTransferConfig: retry[[2]string{"default", "idempotent"}], + ListTransferConfigs: retry[[2]string{"default", "idempotent"}], + ScheduleTransferRuns: retry[[2]string{"default", "non_idempotent"}], + GetTransferRun: retry[[2]string{"default", "idempotent"}], + DeleteTransferRun: retry[[2]string{"default", "idempotent"}], + ListTransferRuns: retry[[2]string{"default", "idempotent"}], + ListTransferLogs: retry[[2]string{"default", "idempotent"}], + CheckValidCreds: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with BigQuery Data Transfer API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client datatransferpb.DataTransferServiceClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new data transfer service client. +// +// The Google BigQuery Data Transfer Service API enables BigQuery users to +// configure the transfer of their data from other Google Products into BigQuery. +// This service contains methods that are end user exposed. It backs up the +// frontend. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: datatransferpb.NewDataTransferServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// GetDataSource retrieves a supported data source and returns its settings, +// which can be used for UI rendering. +func (c *Client) GetDataSource(ctx context.Context, req *datatransferpb.GetDataSourceRequest, opts ...gax.CallOption) (*datatransferpb.DataSource, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.GetDataSource[0:len(c.CallOptions.GetDataSource):len(c.CallOptions.GetDataSource)], opts...) + var resp *datatransferpb.DataSource + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetDataSource(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListDataSources lists supported data sources and returns their settings, +// which can be used for UI rendering. +func (c *Client) ListDataSources(ctx context.Context, req *datatransferpb.ListDataSourcesRequest, opts ...gax.CallOption) *DataSourceIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ListDataSources[0:len(c.CallOptions.ListDataSources):len(c.CallOptions.ListDataSources)], opts...) + it := &DataSourceIterator{} + req = proto.Clone(req).(*datatransferpb.ListDataSourcesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*datatransferpb.DataSource, string, error) { + var resp *datatransferpb.ListDataSourcesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListDataSources(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.DataSources, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// CreateTransferConfig creates a new data transfer configuration. +func (c *Client) CreateTransferConfig(ctx context.Context, req *datatransferpb.CreateTransferConfigRequest, opts ...gax.CallOption) (*datatransferpb.TransferConfig, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.CreateTransferConfig[0:len(c.CallOptions.CreateTransferConfig):len(c.CallOptions.CreateTransferConfig)], opts...) + var resp *datatransferpb.TransferConfig + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateTransferConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateTransferConfig updates a data transfer configuration. +// All fields must be set, even if they are not updated. +func (c *Client) UpdateTransferConfig(ctx context.Context, req *datatransferpb.UpdateTransferConfigRequest, opts ...gax.CallOption) (*datatransferpb.TransferConfig, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "transfer_config.name", req.GetTransferConfig().GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.UpdateTransferConfig[0:len(c.CallOptions.UpdateTransferConfig):len(c.CallOptions.UpdateTransferConfig)], opts...) + var resp *datatransferpb.TransferConfig + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateTransferConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteTransferConfig deletes a data transfer configuration, +// including any associated transfer runs and logs. +func (c *Client) DeleteTransferConfig(ctx context.Context, req *datatransferpb.DeleteTransferConfigRequest, opts ...gax.CallOption) error { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.DeleteTransferConfig[0:len(c.CallOptions.DeleteTransferConfig):len(c.CallOptions.DeleteTransferConfig)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteTransferConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// GetTransferConfig returns information about a data transfer config. +func (c *Client) GetTransferConfig(ctx context.Context, req *datatransferpb.GetTransferConfigRequest, opts ...gax.CallOption) (*datatransferpb.TransferConfig, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.GetTransferConfig[0:len(c.CallOptions.GetTransferConfig):len(c.CallOptions.GetTransferConfig)], opts...) + var resp *datatransferpb.TransferConfig + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetTransferConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListTransferConfigs returns information about all data transfers in the project. +func (c *Client) ListTransferConfigs(ctx context.Context, req *datatransferpb.ListTransferConfigsRequest, opts ...gax.CallOption) *TransferConfigIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ListTransferConfigs[0:len(c.CallOptions.ListTransferConfigs):len(c.CallOptions.ListTransferConfigs)], opts...) + it := &TransferConfigIterator{} + req = proto.Clone(req).(*datatransferpb.ListTransferConfigsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*datatransferpb.TransferConfig, string, error) { + var resp *datatransferpb.ListTransferConfigsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListTransferConfigs(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.TransferConfigs, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// ScheduleTransferRuns creates transfer runs for a time range [start_time, end_time]. +// For each date - or whatever granularity the data source supports - in the +// range, one transfer run is created. +// Note that runs are created per UTC time in the time range. +func (c *Client) ScheduleTransferRuns(ctx context.Context, req *datatransferpb.ScheduleTransferRunsRequest, opts ...gax.CallOption) (*datatransferpb.ScheduleTransferRunsResponse, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ScheduleTransferRuns[0:len(c.CallOptions.ScheduleTransferRuns):len(c.CallOptions.ScheduleTransferRuns)], opts...) + var resp *datatransferpb.ScheduleTransferRunsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ScheduleTransferRuns(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetTransferRun returns information about the particular transfer run. +func (c *Client) GetTransferRun(ctx context.Context, req *datatransferpb.GetTransferRunRequest, opts ...gax.CallOption) (*datatransferpb.TransferRun, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.GetTransferRun[0:len(c.CallOptions.GetTransferRun):len(c.CallOptions.GetTransferRun)], opts...) + var resp *datatransferpb.TransferRun + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetTransferRun(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteTransferRun deletes the specified transfer run. +func (c *Client) DeleteTransferRun(ctx context.Context, req *datatransferpb.DeleteTransferRunRequest, opts ...gax.CallOption) error { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.DeleteTransferRun[0:len(c.CallOptions.DeleteTransferRun):len(c.CallOptions.DeleteTransferRun)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteTransferRun(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ListTransferRuns returns information about running and completed jobs. +func (c *Client) ListTransferRuns(ctx context.Context, req *datatransferpb.ListTransferRunsRequest, opts ...gax.CallOption) *TransferRunIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ListTransferRuns[0:len(c.CallOptions.ListTransferRuns):len(c.CallOptions.ListTransferRuns)], opts...) + it := &TransferRunIterator{} + req = proto.Clone(req).(*datatransferpb.ListTransferRunsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*datatransferpb.TransferRun, string, error) { + var resp *datatransferpb.ListTransferRunsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListTransferRuns(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.TransferRuns, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// ListTransferLogs returns user facing log messages for the data transfer run. +func (c *Client) ListTransferLogs(ctx context.Context, req *datatransferpb.ListTransferLogsRequest, opts ...gax.CallOption) *TransferMessageIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ListTransferLogs[0:len(c.CallOptions.ListTransferLogs):len(c.CallOptions.ListTransferLogs)], opts...) + it := &TransferMessageIterator{} + req = proto.Clone(req).(*datatransferpb.ListTransferLogsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*datatransferpb.TransferMessage, string, error) { + var resp *datatransferpb.ListTransferLogsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListTransferLogs(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.TransferMessages, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// CheckValidCreds returns true if valid credentials exist for the given data source and +// requesting user. +// Some data sources doesn't support service account, so we need to talk to +// them on behalf of the end user. This API just checks whether we have OAuth +// token for the particular user, which is a pre-requisite before user can +// create a transfer config. +func (c *Client) CheckValidCreds(ctx context.Context, req *datatransferpb.CheckValidCredsRequest, opts ...gax.CallOption) (*datatransferpb.CheckValidCredsResponse, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.CheckValidCreds[0:len(c.CallOptions.CheckValidCreds):len(c.CallOptions.CheckValidCreds)], opts...) + var resp *datatransferpb.CheckValidCredsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CheckValidCreds(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DataSourceIterator manages a stream of *datatransferpb.DataSource. +type DataSourceIterator struct { + items []*datatransferpb.DataSource + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*datatransferpb.DataSource, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *DataSourceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *DataSourceIterator) Next() (*datatransferpb.DataSource, error) { + var item *datatransferpb.DataSource + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *DataSourceIterator) bufLen() int { + return len(it.items) +} + +func (it *DataSourceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// TransferConfigIterator manages a stream of *datatransferpb.TransferConfig. +type TransferConfigIterator struct { + items []*datatransferpb.TransferConfig + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*datatransferpb.TransferConfig, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TransferConfigIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TransferConfigIterator) Next() (*datatransferpb.TransferConfig, error) { + var item *datatransferpb.TransferConfig + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TransferConfigIterator) bufLen() int { + return len(it.items) +} + +func (it *TransferConfigIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// TransferMessageIterator manages a stream of *datatransferpb.TransferMessage. +type TransferMessageIterator struct { + items []*datatransferpb.TransferMessage + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*datatransferpb.TransferMessage, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TransferMessageIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TransferMessageIterator) Next() (*datatransferpb.TransferMessage, error) { + var item *datatransferpb.TransferMessage + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TransferMessageIterator) bufLen() int { + return len(it.items) +} + +func (it *TransferMessageIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// TransferRunIterator manages a stream of *datatransferpb.TransferRun. +type TransferRunIterator struct { + items []*datatransferpb.TransferRun + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*datatransferpb.TransferRun, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TransferRunIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TransferRunIterator) Next() (*datatransferpb.TransferRun, error) { + var item *datatransferpb.TransferRun + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TransferRunIterator) bufLen() int { + return len(it.items) +} + +func (it *TransferRunIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/data_transfer_client_example_test.go b/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/data_transfer_client_example_test.go new file mode 100644 index 00000000..6e43c6ba --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/data_transfer_client_example_test.go @@ -0,0 +1,289 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package datatransfer_test + +import ( + "context" + + datatransfer "cloud.google.com/go/bigquery/datatransfer/apiv1" + "google.golang.org/api/iterator" + datatransferpb "google.golang.org/genproto/googleapis/cloud/bigquery/datatransfer/v1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_GetDataSource() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &datatransferpb.GetDataSourceRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetDataSource(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ListDataSources() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &datatransferpb.ListDataSourcesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListDataSources(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_CreateTransferConfig() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &datatransferpb.CreateTransferConfigRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateTransferConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_UpdateTransferConfig() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &datatransferpb.UpdateTransferConfigRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateTransferConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_DeleteTransferConfig() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &datatransferpb.DeleteTransferConfigRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteTransferConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_GetTransferConfig() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &datatransferpb.GetTransferConfigRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetTransferConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ListTransferConfigs() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &datatransferpb.ListTransferConfigsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListTransferConfigs(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_ScheduleTransferRuns() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &datatransferpb.ScheduleTransferRunsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ScheduleTransferRuns(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_GetTransferRun() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &datatransferpb.GetTransferRunRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetTransferRun(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_DeleteTransferRun() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &datatransferpb.DeleteTransferRunRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteTransferRun(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_ListTransferRuns() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &datatransferpb.ListTransferRunsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListTransferRuns(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_ListTransferLogs() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &datatransferpb.ListTransferLogsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListTransferLogs(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_CheckValidCreds() { + ctx := context.Background() + c, err := datatransfer.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &datatransferpb.CheckValidCredsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CheckValidCreds(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/doc.go b/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/doc.go new file mode 100644 index 00000000..6cd68697 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/doc.go @@ -0,0 +1,90 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package datatransfer is an auto-generated package for the +// BigQuery Data Transfer API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Transfers data from partner SaaS applications to Google BigQuery on a +// scheduled, managed basis. +package datatransfer // import "cloud.google.com/go/bigquery/datatransfer/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/mock_test.go b/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/mock_test.go new file mode 100644 index 00000000..f406f672 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/mock_test.go @@ -0,0 +1,1146 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package datatransfer + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + timestamppb "github.com/golang/protobuf/ptypes/timestamp" + datatransferpb "google.golang.org/genproto/googleapis/cloud/bigquery/datatransfer/v1" + field_maskpb "google.golang.org/genproto/protobuf/field_mask" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockDataTransferServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + datatransferpb.DataTransferServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockDataTransferServer) GetDataSource(ctx context.Context, req *datatransferpb.GetDataSourceRequest) (*datatransferpb.DataSource, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*datatransferpb.DataSource), nil +} + +func (s *mockDataTransferServer) ListDataSources(ctx context.Context, req *datatransferpb.ListDataSourcesRequest) (*datatransferpb.ListDataSourcesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*datatransferpb.ListDataSourcesResponse), nil +} + +func (s *mockDataTransferServer) CreateTransferConfig(ctx context.Context, req *datatransferpb.CreateTransferConfigRequest) (*datatransferpb.TransferConfig, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*datatransferpb.TransferConfig), nil +} + +func (s *mockDataTransferServer) UpdateTransferConfig(ctx context.Context, req *datatransferpb.UpdateTransferConfigRequest) (*datatransferpb.TransferConfig, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*datatransferpb.TransferConfig), nil +} + +func (s *mockDataTransferServer) DeleteTransferConfig(ctx context.Context, req *datatransferpb.DeleteTransferConfigRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockDataTransferServer) GetTransferConfig(ctx context.Context, req *datatransferpb.GetTransferConfigRequest) (*datatransferpb.TransferConfig, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*datatransferpb.TransferConfig), nil +} + +func (s *mockDataTransferServer) ListTransferConfigs(ctx context.Context, req *datatransferpb.ListTransferConfigsRequest) (*datatransferpb.ListTransferConfigsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*datatransferpb.ListTransferConfigsResponse), nil +} + +func (s *mockDataTransferServer) ScheduleTransferRuns(ctx context.Context, req *datatransferpb.ScheduleTransferRunsRequest) (*datatransferpb.ScheduleTransferRunsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*datatransferpb.ScheduleTransferRunsResponse), nil +} + +func (s *mockDataTransferServer) GetTransferRun(ctx context.Context, req *datatransferpb.GetTransferRunRequest) (*datatransferpb.TransferRun, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*datatransferpb.TransferRun), nil +} + +func (s *mockDataTransferServer) DeleteTransferRun(ctx context.Context, req *datatransferpb.DeleteTransferRunRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockDataTransferServer) ListTransferRuns(ctx context.Context, req *datatransferpb.ListTransferRunsRequest) (*datatransferpb.ListTransferRunsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*datatransferpb.ListTransferRunsResponse), nil +} + +func (s *mockDataTransferServer) ListTransferLogs(ctx context.Context, req *datatransferpb.ListTransferLogsRequest) (*datatransferpb.ListTransferLogsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*datatransferpb.ListTransferLogsResponse), nil +} + +func (s *mockDataTransferServer) CheckValidCreds(ctx context.Context, req *datatransferpb.CheckValidCredsRequest) (*datatransferpb.CheckValidCredsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*datatransferpb.CheckValidCredsResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockDataTransfer mockDataTransferServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + datatransferpb.RegisterDataTransferServiceServer(serv, &mockDataTransfer) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestDataTransferServiceGetDataSource(t *testing.T) { + var name2 string = "name2-1052831874" + var dataSourceId string = "dataSourceId-1015796374" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var clientId string = "clientId-1904089585" + var supportsMultipleTransfers bool = true + var updateDeadlineSeconds int32 = 991471694 + var defaultSchedule string = "defaultSchedule-800168235" + var supportsCustomSchedule bool = true + var helpUrl string = "helpUrl-789431439" + var defaultDataRefreshWindowDays int32 = 1804935157 + var manualRunsDisabled bool = true + var expectedResponse = &datatransferpb.DataSource{ + Name: name2, + DataSourceId: dataSourceId, + DisplayName: displayName, + Description: description, + ClientId: clientId, + SupportsMultipleTransfers: supportsMultipleTransfers, + UpdateDeadlineSeconds: updateDeadlineSeconds, + DefaultSchedule: defaultSchedule, + SupportsCustomSchedule: supportsCustomSchedule, + HelpUrl: helpUrl, + DefaultDataRefreshWindowDays: defaultDataRefreshWindowDays, + ManualRunsDisabled: manualRunsDisabled, + } + + mockDataTransfer.err = nil + mockDataTransfer.reqs = nil + + mockDataTransfer.resps = append(mockDataTransfer.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/dataSources/%s", "[PROJECT]", "[DATA_SOURCE]") + var request = &datatransferpb.GetDataSourceRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetDataSource(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDataTransfer.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDataTransferServiceGetDataSourceError(t *testing.T) { + errCode := codes.PermissionDenied + mockDataTransfer.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/dataSources/%s", "[PROJECT]", "[DATA_SOURCE]") + var request = &datatransferpb.GetDataSourceRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetDataSource(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDataTransferServiceListDataSources(t *testing.T) { + var nextPageToken string = "" + var dataSourcesElement *datatransferpb.DataSource = &datatransferpb.DataSource{} + var dataSources = []*datatransferpb.DataSource{dataSourcesElement} + var expectedResponse = &datatransferpb.ListDataSourcesResponse{ + NextPageToken: nextPageToken, + DataSources: dataSources, + } + + mockDataTransfer.err = nil + mockDataTransfer.reqs = nil + + mockDataTransfer.resps = append(mockDataTransfer.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &datatransferpb.ListDataSourcesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListDataSources(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDataTransfer.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.DataSources[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDataTransferServiceListDataSourcesError(t *testing.T) { + errCode := codes.PermissionDenied + mockDataTransfer.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &datatransferpb.ListDataSourcesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListDataSources(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDataTransferServiceCreateTransferConfig(t *testing.T) { + var name string = "name3373707" + var destinationDatasetId string = "destinationDatasetId1541564179" + var displayName string = "displayName1615086568" + var dataSourceId string = "dataSourceId-1015796374" + var schedule string = "schedule-697920873" + var dataRefreshWindowDays int32 = 327632845 + var disabled bool = true + var userId int64 = 147132913 + var datasetRegion string = "datasetRegion959248539" + var expectedResponse = &datatransferpb.TransferConfig{ + Name: name, + DestinationDatasetId: destinationDatasetId, + DisplayName: displayName, + DataSourceId: dataSourceId, + Schedule: schedule, + DataRefreshWindowDays: dataRefreshWindowDays, + Disabled: disabled, + UserId: userId, + DatasetRegion: datasetRegion, + } + + mockDataTransfer.err = nil + mockDataTransfer.reqs = nil + + mockDataTransfer.resps = append(mockDataTransfer.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var transferConfig *datatransferpb.TransferConfig = &datatransferpb.TransferConfig{} + var request = &datatransferpb.CreateTransferConfigRequest{ + Parent: formattedParent, + TransferConfig: transferConfig, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateTransferConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDataTransfer.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDataTransferServiceCreateTransferConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockDataTransfer.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var transferConfig *datatransferpb.TransferConfig = &datatransferpb.TransferConfig{} + var request = &datatransferpb.CreateTransferConfigRequest{ + Parent: formattedParent, + TransferConfig: transferConfig, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateTransferConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDataTransferServiceUpdateTransferConfig(t *testing.T) { + var name string = "name3373707" + var destinationDatasetId string = "destinationDatasetId1541564179" + var displayName string = "displayName1615086568" + var dataSourceId string = "dataSourceId-1015796374" + var schedule string = "schedule-697920873" + var dataRefreshWindowDays int32 = 327632845 + var disabled bool = true + var userId int64 = 147132913 + var datasetRegion string = "datasetRegion959248539" + var expectedResponse = &datatransferpb.TransferConfig{ + Name: name, + DestinationDatasetId: destinationDatasetId, + DisplayName: displayName, + DataSourceId: dataSourceId, + Schedule: schedule, + DataRefreshWindowDays: dataRefreshWindowDays, + Disabled: disabled, + UserId: userId, + DatasetRegion: datasetRegion, + } + + mockDataTransfer.err = nil + mockDataTransfer.reqs = nil + + mockDataTransfer.resps = append(mockDataTransfer.resps[:0], expectedResponse) + + var transferConfig *datatransferpb.TransferConfig = &datatransferpb.TransferConfig{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &datatransferpb.UpdateTransferConfigRequest{ + TransferConfig: transferConfig, + UpdateMask: updateMask, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateTransferConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDataTransfer.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDataTransferServiceUpdateTransferConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockDataTransfer.err = gstatus.Error(errCode, "test error") + + var transferConfig *datatransferpb.TransferConfig = &datatransferpb.TransferConfig{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &datatransferpb.UpdateTransferConfigRequest{ + TransferConfig: transferConfig, + UpdateMask: updateMask, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateTransferConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDataTransferServiceDeleteTransferConfig(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockDataTransfer.err = nil + mockDataTransfer.reqs = nil + + mockDataTransfer.resps = append(mockDataTransfer.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/transferConfigs/%s", "[PROJECT]", "[TRANSFER_CONFIG]") + var request = &datatransferpb.DeleteTransferConfigRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteTransferConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDataTransfer.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestDataTransferServiceDeleteTransferConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockDataTransfer.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/transferConfigs/%s", "[PROJECT]", "[TRANSFER_CONFIG]") + var request = &datatransferpb.DeleteTransferConfigRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteTransferConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestDataTransferServiceGetTransferConfig(t *testing.T) { + var name2 string = "name2-1052831874" + var destinationDatasetId string = "destinationDatasetId1541564179" + var displayName string = "displayName1615086568" + var dataSourceId string = "dataSourceId-1015796374" + var schedule string = "schedule-697920873" + var dataRefreshWindowDays int32 = 327632845 + var disabled bool = true + var userId int64 = 147132913 + var datasetRegion string = "datasetRegion959248539" + var expectedResponse = &datatransferpb.TransferConfig{ + Name: name2, + DestinationDatasetId: destinationDatasetId, + DisplayName: displayName, + DataSourceId: dataSourceId, + Schedule: schedule, + DataRefreshWindowDays: dataRefreshWindowDays, + Disabled: disabled, + UserId: userId, + DatasetRegion: datasetRegion, + } + + mockDataTransfer.err = nil + mockDataTransfer.reqs = nil + + mockDataTransfer.resps = append(mockDataTransfer.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/transferConfigs/%s", "[PROJECT]", "[TRANSFER_CONFIG]") + var request = &datatransferpb.GetTransferConfigRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetTransferConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDataTransfer.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDataTransferServiceGetTransferConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockDataTransfer.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/transferConfigs/%s", "[PROJECT]", "[TRANSFER_CONFIG]") + var request = &datatransferpb.GetTransferConfigRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetTransferConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDataTransferServiceListTransferConfigs(t *testing.T) { + var nextPageToken string = "" + var transferConfigsElement *datatransferpb.TransferConfig = &datatransferpb.TransferConfig{} + var transferConfigs = []*datatransferpb.TransferConfig{transferConfigsElement} + var expectedResponse = &datatransferpb.ListTransferConfigsResponse{ + NextPageToken: nextPageToken, + TransferConfigs: transferConfigs, + } + + mockDataTransfer.err = nil + mockDataTransfer.reqs = nil + + mockDataTransfer.resps = append(mockDataTransfer.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &datatransferpb.ListTransferConfigsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTransferConfigs(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDataTransfer.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.TransferConfigs[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDataTransferServiceListTransferConfigsError(t *testing.T) { + errCode := codes.PermissionDenied + mockDataTransfer.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &datatransferpb.ListTransferConfigsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTransferConfigs(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDataTransferServiceScheduleTransferRuns(t *testing.T) { + var expectedResponse *datatransferpb.ScheduleTransferRunsResponse = &datatransferpb.ScheduleTransferRunsResponse{} + + mockDataTransfer.err = nil + mockDataTransfer.reqs = nil + + mockDataTransfer.resps = append(mockDataTransfer.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/transferConfigs/%s", "[PROJECT]", "[TRANSFER_CONFIG]") + var startTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var endTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var request = &datatransferpb.ScheduleTransferRunsRequest{ + Parent: formattedParent, + StartTime: startTime, + EndTime: endTime, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ScheduleTransferRuns(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDataTransfer.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDataTransferServiceScheduleTransferRunsError(t *testing.T) { + errCode := codes.PermissionDenied + mockDataTransfer.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/transferConfigs/%s", "[PROJECT]", "[TRANSFER_CONFIG]") + var startTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var endTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var request = &datatransferpb.ScheduleTransferRunsRequest{ + Parent: formattedParent, + StartTime: startTime, + EndTime: endTime, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ScheduleTransferRuns(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDataTransferServiceGetTransferRun(t *testing.T) { + var name2 string = "name2-1052831874" + var destinationDatasetId string = "destinationDatasetId1541564179" + var dataSourceId string = "dataSourceId-1015796374" + var userId int64 = 147132913 + var schedule string = "schedule-697920873" + var expectedResponse = &datatransferpb.TransferRun{ + Name: name2, + DestinationDatasetId: destinationDatasetId, + DataSourceId: dataSourceId, + UserId: userId, + Schedule: schedule, + } + + mockDataTransfer.err = nil + mockDataTransfer.reqs = nil + + mockDataTransfer.resps = append(mockDataTransfer.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/transferConfigs/%s/runs/%s", "[PROJECT]", "[TRANSFER_CONFIG]", "[RUN]") + var request = &datatransferpb.GetTransferRunRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetTransferRun(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDataTransfer.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDataTransferServiceGetTransferRunError(t *testing.T) { + errCode := codes.PermissionDenied + mockDataTransfer.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/transferConfigs/%s/runs/%s", "[PROJECT]", "[TRANSFER_CONFIG]", "[RUN]") + var request = &datatransferpb.GetTransferRunRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetTransferRun(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDataTransferServiceDeleteTransferRun(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockDataTransfer.err = nil + mockDataTransfer.reqs = nil + + mockDataTransfer.resps = append(mockDataTransfer.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/transferConfigs/%s/runs/%s", "[PROJECT]", "[TRANSFER_CONFIG]", "[RUN]") + var request = &datatransferpb.DeleteTransferRunRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteTransferRun(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDataTransfer.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestDataTransferServiceDeleteTransferRunError(t *testing.T) { + errCode := codes.PermissionDenied + mockDataTransfer.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/transferConfigs/%s/runs/%s", "[PROJECT]", "[TRANSFER_CONFIG]", "[RUN]") + var request = &datatransferpb.DeleteTransferRunRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteTransferRun(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestDataTransferServiceListTransferRuns(t *testing.T) { + var nextPageToken string = "" + var transferRunsElement *datatransferpb.TransferRun = &datatransferpb.TransferRun{} + var transferRuns = []*datatransferpb.TransferRun{transferRunsElement} + var expectedResponse = &datatransferpb.ListTransferRunsResponse{ + NextPageToken: nextPageToken, + TransferRuns: transferRuns, + } + + mockDataTransfer.err = nil + mockDataTransfer.reqs = nil + + mockDataTransfer.resps = append(mockDataTransfer.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/transferConfigs/%s", "[PROJECT]", "[TRANSFER_CONFIG]") + var request = &datatransferpb.ListTransferRunsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTransferRuns(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDataTransfer.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.TransferRuns[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDataTransferServiceListTransferRunsError(t *testing.T) { + errCode := codes.PermissionDenied + mockDataTransfer.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/transferConfigs/%s", "[PROJECT]", "[TRANSFER_CONFIG]") + var request = &datatransferpb.ListTransferRunsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTransferRuns(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDataTransferServiceListTransferLogs(t *testing.T) { + var nextPageToken string = "" + var transferMessagesElement *datatransferpb.TransferMessage = &datatransferpb.TransferMessage{} + var transferMessages = []*datatransferpb.TransferMessage{transferMessagesElement} + var expectedResponse = &datatransferpb.ListTransferLogsResponse{ + NextPageToken: nextPageToken, + TransferMessages: transferMessages, + } + + mockDataTransfer.err = nil + mockDataTransfer.reqs = nil + + mockDataTransfer.resps = append(mockDataTransfer.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/transferConfigs/%s/runs/%s", "[PROJECT]", "[TRANSFER_CONFIG]", "[RUN]") + var request = &datatransferpb.ListTransferLogsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTransferLogs(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDataTransfer.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.TransferMessages[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDataTransferServiceListTransferLogsError(t *testing.T) { + errCode := codes.PermissionDenied + mockDataTransfer.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/transferConfigs/%s/runs/%s", "[PROJECT]", "[TRANSFER_CONFIG]", "[RUN]") + var request = &datatransferpb.ListTransferLogsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTransferLogs(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDataTransferServiceCheckValidCreds(t *testing.T) { + var hasValidCreds bool = false + var expectedResponse = &datatransferpb.CheckValidCredsResponse{ + HasValidCreds: hasValidCreds, + } + + mockDataTransfer.err = nil + mockDataTransfer.reqs = nil + + mockDataTransfer.resps = append(mockDataTransfer.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/dataSources/%s", "[PROJECT]", "[DATA_SOURCE]") + var request = &datatransferpb.CheckValidCredsRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CheckValidCreds(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDataTransfer.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDataTransferServiceCheckValidCredsError(t *testing.T) { + errCode := codes.PermissionDenied + mockDataTransfer.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/dataSources/%s", "[PROJECT]", "[DATA_SOURCE]") + var request = &datatransferpb.CheckValidCredsRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CheckValidCreds(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/path_funcs.go b/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/path_funcs.go new file mode 100644 index 00000000..89eb5bb1 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/datatransfer/apiv1/path_funcs.go @@ -0,0 +1,135 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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 datatransfer + +// ProjectPath returns the path for the project resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s", project) +// instead. +func ProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} + +// LocationPath returns the path for the location resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/locations/%s", project, location) +// instead. +func LocationPath(project, location string) string { + return "" + + "projects/" + + project + + "/locations/" + + location + + "" +} + +// LocationDataSourcePath returns the path for the location data source resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/locations/%s/dataSources/%s", project, location, dataSource) +// instead. +func LocationDataSourcePath(project, location, dataSource string) string { + return "" + + "projects/" + + project + + "/locations/" + + location + + "/dataSources/" + + dataSource + + "" +} + +// LocationTransferConfigPath returns the path for the location transfer config resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/locations/%s/transferConfigs/%s", project, location, transferConfig) +// instead. +func LocationTransferConfigPath(project, location, transferConfig string) string { + return "" + + "projects/" + + project + + "/locations/" + + location + + "/transferConfigs/" + + transferConfig + + "" +} + +// LocationRunPath returns the path for the location run resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/locations/%s/transferConfigs/%s/runs/%s", project, location, transferConfig, run) +// instead. +func LocationRunPath(project, location, transferConfig, run string) string { + return "" + + "projects/" + + project + + "/locations/" + + location + + "/transferConfigs/" + + transferConfig + + "/runs/" + + run + + "" +} + +// DataSourcePath returns the path for the data source resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/dataSources/%s", project, dataSource) +// instead. +func DataSourcePath(project, dataSource string) string { + return "" + + "projects/" + + project + + "/dataSources/" + + dataSource + + "" +} + +// TransferConfigPath returns the path for the transfer config resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/transferConfigs/%s", project, transferConfig) +// instead. +func TransferConfigPath(project, transferConfig string) string { + return "" + + "projects/" + + project + + "/transferConfigs/" + + transferConfig + + "" +} + +// RunPath returns the path for the run resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/transferConfigs/%s/runs/%s", project, transferConfig, run) +// instead. +func RunPath(project, transferConfig, run string) string { + return "" + + "projects/" + + project + + "/transferConfigs/" + + transferConfig + + "/runs/" + + run + + "" +} diff --git a/vendor/cloud.google.com/go/bigquery/doc.go b/vendor/cloud.google.com/go/bigquery/doc.go new file mode 100644 index 00000000..43e491ce --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/doc.go @@ -0,0 +1,310 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery provides a client for the BigQuery service. + +Note: This package is in beta. Some backwards-incompatible changes may occur. + +The following assumes a basic familiarity with BigQuery concepts. +See https://cloud.google.com/bigquery/docs. + +See https://godoc.org/cloud.google.com/go for authentication, timeouts, +connection pooling and similar aspects of this package. + + +Creating a Client + +To start working with this package, create a client: + + ctx := context.Background() + client, err := bigquery.NewClient(ctx, projectID) + if err != nil { + // TODO: Handle error. + } + +Querying + +To query existing tables, create a Query and call its Read method: + + q := client.Query(` + SELECT year, SUM(number) as num + FROM [bigquery-public-data:usa_names.usa_1910_2013] + WHERE name = "William" + GROUP BY year + ORDER BY year + `) + it, err := q.Read(ctx) + if err != nil { + // TODO: Handle error. + } + +Then iterate through the resulting rows. You can store a row using +anything that implements the ValueLoader interface, or with a slice or map of bigquery.Value. +A slice is simplest: + + for { + var values []bigquery.Value + err := it.Next(&values) + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(values) + } + +You can also use a struct whose exported fields match the query: + + type Count struct { + Year int + Num int + } + for { + var c Count + err := it.Next(&c) + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(c) + } + +You can also start the query running and get the results later. +Create the query as above, but call Run instead of Read. This returns a Job, +which represents an asynchronous operation. + + job, err := q.Run(ctx) + if err != nil { + // TODO: Handle error. + } + +Get the job's ID, a printable string. You can save this string to retrieve +the results at a later time, even in another process. + + jobID := job.ID() + fmt.Printf("The job ID is %s\n", jobID) + +To retrieve the job's results from the ID, first look up the Job: + + job, err = client.JobFromID(ctx, jobID) + if err != nil { + // TODO: Handle error. + } + +Use the Job.Read method to obtain an iterator, and loop over the rows. +Query.Read is just a convenience method that combines Query.Run and Job.Read. + + it, err = job.Read(ctx) + if err != nil { + // TODO: Handle error. + } + // Proceed with iteration as above. + +Datasets and Tables + +You can refer to datasets in the client's project with the Dataset method, and +in other projects with the DatasetInProject method: + + myDataset := client.Dataset("my_dataset") + yourDataset := client.DatasetInProject("your-project-id", "your_dataset") + +These methods create references to datasets, not the datasets themselves. You can have +a dataset reference even if the dataset doesn't exist yet. Use Dataset.Create to +create a dataset from a reference: + + if err := myDataset.Create(ctx, nil); err != nil { + // TODO: Handle error. + } + +You can refer to tables with Dataset.Table. Like bigquery.Dataset, bigquery.Table is a reference +to an object in BigQuery that may or may not exist. + + table := myDataset.Table("my_table") + +You can create, delete and update the metadata of tables with methods on Table. +For instance, you could create a temporary table with: + + err = myDataset.Table("temp").Create(ctx, &bigquery.TableMetadata{ + ExpirationTime: time.Now().Add(1*time.Hour)}) + if err != nil { + // TODO: Handle error. + } + +We'll see how to create a table with a schema in the next section. + +Schemas + +There are two ways to construct schemas with this package. +You can build a schema by hand, like so: + + schema1 := bigquery.Schema{ + {Name: "Name", Required: true, Type: bigquery.StringFieldType}, + {Name: "Grades", Repeated: true, Type: bigquery.IntegerFieldType}, + {Name: "Optional", Required: false, Type: bigquery.IntegerFieldType}, + } + +Or you can infer the schema from a struct: + + type student struct { + Name string + Grades []int + Optional bigquery.NullInt64 + } + schema2, err := bigquery.InferSchema(student{}) + if err != nil { + // TODO: Handle error. + } + // schema1 and schema2 are identical. + +Struct inference supports tags like those of the encoding/json package, so you can +change names, ignore fields, or mark a field as nullable (non-required). Fields +declared as one of the Null types (NullInt64, NullFloat64, NullString, NullBool, +NullTimestamp, NullDate, NullTime and NullDateTime) are automatically inferred as +nullable, so the "nullable" tag is only needed for []byte, *big.Rat and +pointer-to-struct fields. + + type student2 struct { + Name string `bigquery:"full_name"` + Grades []int + Secret string `bigquery:"-"` + Optional []byte `bigquery:",nullable" + } + schema3, err := bigquery.InferSchema(student2{}) + if err != nil { + // TODO: Handle error. + } + // schema3 has required fields "full_name" and "Grade", and nullable BYTES field "Optional". + +Having constructed a schema, you can create a table with it like so: + + if err := table.Create(ctx, &bigquery.TableMetadata{Schema: schema1}); err != nil { + // TODO: Handle error. + } + +Copying + +You can copy one or more tables to another table. Begin by constructing a Copier +describing the copy. Then set any desired copy options, and finally call Run to get a Job: + + copier := myDataset.Table("dest").CopierFrom(myDataset.Table("src")) + copier.WriteDisposition = bigquery.WriteTruncate + job, err = copier.Run(ctx) + if err != nil { + // TODO: Handle error. + } + +You can chain the call to Run if you don't want to set options: + + job, err = myDataset.Table("dest").CopierFrom(myDataset.Table("src")).Run(ctx) + if err != nil { + // TODO: Handle error. + } + +You can wait for your job to complete: + + status, err := job.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + +Job.Wait polls with exponential backoff. You can also poll yourself, if you +wish: + + for { + status, err := job.Status(ctx) + if err != nil { + // TODO: Handle error. + } + if status.Done() { + if status.Err() != nil { + log.Fatalf("Job failed with error %v", status.Err()) + } + break + } + time.Sleep(pollInterval) + } + +Loading and Uploading + +There are two ways to populate a table with this package: load the data from a Google Cloud Storage +object, or upload rows directly from your program. + +For loading, first create a GCSReference, configuring it if desired. Then make a Loader, optionally configure +it as well, and call its Run method. + + gcsRef := bigquery.NewGCSReference("gs://my-bucket/my-object") + gcsRef.AllowJaggedRows = true + loader := myDataset.Table("dest").LoaderFrom(gcsRef) + loader.CreateDisposition = bigquery.CreateNever + job, err = loader.Run(ctx) + // Poll the job for completion if desired, as above. + +To upload, first define a type that implements the ValueSaver interface, which has a single method named Save. +Then create an Uploader, and call its Put method with a slice of values. + + u := table.Uploader() + // Item implements the ValueSaver interface. + items := []*Item{ + {Name: "n1", Size: 32.6, Count: 7}, + {Name: "n2", Size: 4, Count: 2}, + {Name: "n3", Size: 101.5, Count: 1}, + } + if err := u.Put(ctx, items); err != nil { + // TODO: Handle error. + } + +You can also upload a struct that doesn't implement ValueSaver. Use the StructSaver type +to specify the schema and insert ID by hand, or just supply the struct or struct pointer +directly and the schema will be inferred: + + type Item2 struct { + Name string + Size float64 + Count int + } + // Item implements the ValueSaver interface. + items2 := []*Item2{ + {Name: "n1", Size: 32.6, Count: 7}, + {Name: "n2", Size: 4, Count: 2}, + {Name: "n3", Size: 101.5, Count: 1}, + } + if err := u.Put(ctx, items2); err != nil { + // TODO: Handle error. + } + +Extracting + +If you've been following so far, extracting data from a BigQuery table +into a Google Cloud Storage object will feel familiar. First create an +Extractor, then optionally configure it, and lastly call its Run method. + + extractor := table.ExtractorTo(gcsRef) + extractor.DisableHeader = true + job, err = extractor.Run(ctx) + // Poll the job for completion if desired, as above. + +Errors + +Errors returned by this client are often of the type [`googleapi.Error`](https://godoc.org/google.golang.org/api/googleapi#Error). +These errors can be introspected for more information by type asserting to the richer `googleapi.Error` type. For example: + + if e, ok := err.(*googleapi.Error); ok { + if e.Code = 409 { ... } + } +*/ +package bigquery // import "cloud.google.com/go/bigquery" diff --git a/vendor/cloud.google.com/go/bigquery/error.go b/vendor/cloud.google.com/go/bigquery/error.go new file mode 100644 index 00000000..27e86982 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/error.go @@ -0,0 +1,83 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "fmt" + + bq "google.golang.org/api/bigquery/v2" +) + +// An Error contains detailed information about a failed bigquery operation. +// Detailed description of possible Reasons can be found here: https://cloud.google.com/bigquery/troubleshooting-errors. +type Error struct { + // Mirrors bq.ErrorProto, but drops DebugInfo + Location, Message, Reason string +} + +func (e Error) Error() string { + return fmt.Sprintf("{Location: %q; Message: %q; Reason: %q}", e.Location, e.Message, e.Reason) +} + +func bqToError(ep *bq.ErrorProto) *Error { + if ep == nil { + return nil + } + return &Error{ + Location: ep.Location, + Message: ep.Message, + Reason: ep.Reason, + } +} + +// A MultiError contains multiple related errors. +type MultiError []error + +func (m MultiError) Error() string { + switch len(m) { + case 0: + return "(0 errors)" + case 1: + return m[0].Error() + case 2: + return m[0].Error() + " (and 1 other error)" + } + return fmt.Sprintf("%s (and %d other errors)", m[0].Error(), len(m)-1) +} + +// RowInsertionError contains all errors that occurred when attempting to insert a row. +type RowInsertionError struct { + InsertID string // The InsertID associated with the affected row. + RowIndex int // The 0-based index of the affected row in the batch of rows being inserted. + Errors MultiError +} + +func (e *RowInsertionError) Error() string { + errFmt := "insertion of row [insertID: %q; insertIndex: %v] failed with error: %s" + return fmt.Sprintf(errFmt, e.InsertID, e.RowIndex, e.Errors.Error()) +} + +// PutMultiError contains an error for each row which was not successfully inserted +// into a BigQuery table. +type PutMultiError []RowInsertionError + +func (pme PutMultiError) Error() string { + plural := "s" + if len(pme) == 1 { + plural = "" + } + + return fmt.Sprintf("%v row insertion%s failed", len(pme), plural) +} diff --git a/vendor/cloud.google.com/go/bigquery/error_test.go b/vendor/cloud.google.com/go/bigquery/error_test.go new file mode 100644 index 00000000..7442f620 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/error_test.go @@ -0,0 +1,109 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "errors" + "strings" + "testing" + + "cloud.google.com/go/internal/testutil" + bq "google.golang.org/api/bigquery/v2" +) + +func rowInsertionError(msg string) RowInsertionError { + return RowInsertionError{Errors: []error{errors.New(msg)}} +} + +func TestPutMultiErrorString(t *testing.T) { + testCases := []struct { + errs PutMultiError + want string + }{ + { + errs: PutMultiError{}, + want: "0 row insertions failed", + }, + { + errs: PutMultiError{rowInsertionError("a")}, + want: "1 row insertion failed", + }, + { + errs: PutMultiError{rowInsertionError("a"), rowInsertionError("b")}, + want: "2 row insertions failed", + }, + } + + for _, tc := range testCases { + if tc.errs.Error() != tc.want { + t.Errorf("PutMultiError string: got:\n%v\nwant:\n%v", tc.errs.Error(), tc.want) + } + } +} + +func TestMultiErrorString(t *testing.T) { + testCases := []struct { + errs MultiError + want string + }{ + { + errs: MultiError{}, + want: "(0 errors)", + }, + { + errs: MultiError{errors.New("a")}, + want: "a", + }, + { + errs: MultiError{errors.New("a"), errors.New("b")}, + want: "a (and 1 other error)", + }, + { + errs: MultiError{errors.New("a"), errors.New("b"), errors.New("c")}, + want: "a (and 2 other errors)", + }, + } + + for _, tc := range testCases { + if tc.errs.Error() != tc.want { + t.Errorf("PutMultiError string: got:\n%v\nwant:\n%v", tc.errs.Error(), tc.want) + } + } +} + +func TestErrorFromErrorProto(t *testing.T) { + for _, test := range []struct { + in *bq.ErrorProto + want *Error + }{ + {nil, nil}, + { + in: &bq.ErrorProto{Location: "L", Message: "M", Reason: "R"}, + want: &Error{Location: "L", Message: "M", Reason: "R"}, + }, + } { + if got := bqToError(test.in); !testutil.Equal(got, test.want) { + t.Errorf("%v: got %v, want %v", test.in, got, test.want) + } + } +} + +func TestErrorString(t *testing.T) { + e := &Error{Location: "", Message: "", Reason: ""} + got := e.Error() + if !strings.Contains(got, "") || !strings.Contains(got, "") || !strings.Contains(got, "") { + t.Errorf(`got %q, expected to see "", "" and ""`, got) + } +} diff --git a/vendor/cloud.google.com/go/bigquery/examples_test.go b/vendor/cloud.google.com/go/bigquery/examples_test.go new file mode 100644 index 00000000..4c568138 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/examples_test.go @@ -0,0 +1,829 @@ +// Copyright 2016 Google LLC +// +// 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 bigquery_test + +import ( + "context" + "fmt" + "os" + "time" + + "cloud.google.com/go/bigquery" + "google.golang.org/api/iterator" +) + +func ExampleNewClient() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + _ = client // TODO: Use client. +} + +func ExampleClient_Dataset() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + ds := client.Dataset("my_dataset") + fmt.Println(ds) +} + +func ExampleClient_DatasetInProject() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + ds := client.DatasetInProject("their-project-id", "their-dataset") + fmt.Println(ds) +} + +func ExampleClient_Datasets() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + it := client.Datasets(ctx) + _ = it // TODO: iterate using Next or iterator.Pager. +} + +func ExampleClient_DatasetsInProject() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + it := client.DatasetsInProject(ctx, "their-project-id") + _ = it // TODO: iterate using Next or iterator.Pager. +} + +func getJobID() string { return "" } + +func ExampleClient_JobFromID() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + jobID := getJobID() // Get a job ID using Job.ID, the console or elsewhere. + job, err := client.JobFromID(ctx, jobID) + if err != nil { + // TODO: Handle error. + } + fmt.Println(job.LastStatus()) // Display the job's status. +} + +func ExampleClient_Jobs() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + it := client.Jobs(ctx) + it.State = bigquery.Running // list only running jobs. + _ = it // TODO: iterate using Next or iterator.Pager. +} + +func ExampleNewGCSReference() { + gcsRef := bigquery.NewGCSReference("gs://my-bucket/my-object") + fmt.Println(gcsRef) +} + +func ExampleClient_Query() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + q := client.Query("select name, num from t1") + q.DefaultProjectID = "project-id" + // TODO: set other options on the Query. + // TODO: Call Query.Run or Query.Read. +} + +func ExampleClient_Query_parameters() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + q := client.Query("select num from t1 where name = @user") + q.Parameters = []bigquery.QueryParameter{ + {Name: "user", Value: "Elizabeth"}, + } + // TODO: set other options on the Query. + // TODO: Call Query.Run or Query.Read. +} + +// This example demonstrates how to run a query job on a table +// with a customer-managed encryption key. The same +// applies to load and copy jobs as well. +func ExampleClient_Query_encryptionKey() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + q := client.Query("select name, num from t1") + // TODO: Replace this key with a key you have created in Cloud KMS. + keyName := "projects/P/locations/L/keyRings/R/cryptoKeys/K" + q.DestinationEncryptionConfig = &bigquery.EncryptionConfig{KMSKeyName: keyName} + // TODO: set other options on the Query. + // TODO: Call Query.Run or Query.Read. +} + +func ExampleQuery_Read() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + q := client.Query("select name, num from t1") + it, err := q.Read(ctx) + if err != nil { + // TODO: Handle error. + } + _ = it // TODO: iterate using Next or iterator.Pager. +} + +func ExampleRowIterator_Next() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + q := client.Query("select name, num from t1") + it, err := q.Read(ctx) + if err != nil { + // TODO: Handle error. + } + for { + var row []bigquery.Value + err := it.Next(&row) + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(row) + } +} + +func ExampleRowIterator_Next_struct() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + type score struct { + Name string + Num int + } + + q := client.Query("select name, num from t1") + it, err := q.Read(ctx) + if err != nil { + // TODO: Handle error. + } + for { + var s score + err := it.Next(&s) + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(s) + } +} + +func ExampleJob_Read() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + q := client.Query("select name, num from t1") + // Call Query.Run to get a Job, then call Read on the job. + // Note: Query.Read is a shorthand for this. + job, err := q.Run(ctx) + if err != nil { + // TODO: Handle error. + } + it, err := job.Read(ctx) + if err != nil { + // TODO: Handle error. + } + _ = it // TODO: iterate using Next or iterator.Pager. +} + +func ExampleJob_Wait() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + ds := client.Dataset("my_dataset") + job, err := ds.Table("t1").CopierFrom(ds.Table("t2")).Run(ctx) + if err != nil { + // TODO: Handle error. + } + status, err := job.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + if status.Err() != nil { + // TODO: Handle error. + } +} + +func ExampleJob_Config() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + ds := client.Dataset("my_dataset") + job, err := ds.Table("t1").CopierFrom(ds.Table("t2")).Run(ctx) + if err != nil { + // TODO: Handle error. + } + jc, err := job.Config() + if err != nil { + // TODO: Handle error. + } + copyConfig := jc.(*bigquery.CopyConfig) + fmt.Println(copyConfig.Dst, copyConfig.CreateDisposition) +} + +func ExampleDataset_Create() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + ds := client.Dataset("my_dataset") + if err := ds.Create(ctx, &bigquery.DatasetMetadata{Location: "EU"}); err != nil { + // TODO: Handle error. + } +} + +func ExampleDataset_Delete() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + if err := client.Dataset("my_dataset").Delete(ctx); err != nil { + // TODO: Handle error. + } +} + +func ExampleDataset_Metadata() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + md, err := client.Dataset("my_dataset").Metadata(ctx) + if err != nil { + // TODO: Handle error. + } + fmt.Println(md) +} + +// This example illustrates how to perform a read-modify-write sequence on dataset +// metadata. Passing the metadata's ETag to the Update call ensures that the call +// will fail if the metadata was changed since the read. +func ExampleDataset_Update_readModifyWrite() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + ds := client.Dataset("my_dataset") + md, err := ds.Metadata(ctx) + if err != nil { + // TODO: Handle error. + } + md2, err := ds.Update(ctx, + bigquery.DatasetMetadataToUpdate{Name: "new " + md.Name}, + md.ETag) + if err != nil { + // TODO: Handle error. + } + fmt.Println(md2) +} + +// To perform a blind write, ignoring the existing state (and possibly overwriting +// other updates), pass the empty string as the etag. +func ExampleDataset_Update_blindWrite() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + md, err := client.Dataset("my_dataset").Update(ctx, bigquery.DatasetMetadataToUpdate{Name: "blind"}, "") + if err != nil { + // TODO: Handle error. + } + fmt.Println(md) +} + +func ExampleDataset_Table() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + // Table creates a reference to the table. It does not create the actual + // table in BigQuery; to do so, use Table.Create. + t := client.Dataset("my_dataset").Table("my_table") + fmt.Println(t) +} + +func ExampleDataset_Tables() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + it := client.Dataset("my_dataset").Tables(ctx) + _ = it // TODO: iterate using Next or iterator.Pager. +} + +func ExampleDatasetIterator_Next() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + it := client.Datasets(ctx) + for { + ds, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(ds) + } +} + +func ExampleInferSchema() { + type Item struct { + Name string + Size float64 + Count int + } + schema, err := bigquery.InferSchema(Item{}) + if err != nil { + fmt.Println(err) + // TODO: Handle error. + } + for _, fs := range schema { + fmt.Println(fs.Name, fs.Type) + } + // Output: + // Name STRING + // Size FLOAT + // Count INTEGER +} + +func ExampleInferSchema_tags() { + type Item struct { + Name string + Size float64 + Count int `bigquery:"number"` + Secret []byte `bigquery:"-"` + Optional bigquery.NullBool + OptBytes []byte `bigquery:",nullable"` + } + schema, err := bigquery.InferSchema(Item{}) + if err != nil { + fmt.Println(err) + // TODO: Handle error. + } + for _, fs := range schema { + fmt.Println(fs.Name, fs.Type, fs.Required) + } + // Output: + // Name STRING true + // Size FLOAT true + // number INTEGER true + // Optional BOOLEAN false + // OptBytes BYTES false +} + +func ExampleTable_Create() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + t := client.Dataset("my_dataset").Table("new-table") + if err := t.Create(ctx, nil); err != nil { + // TODO: Handle error. + } +} + +// Initialize a new table by passing TableMetadata to Table.Create. +func ExampleTable_Create_initialize() { + ctx := context.Background() + // Infer table schema from a Go type. + schema, err := bigquery.InferSchema(Item{}) + if err != nil { + // TODO: Handle error. + } + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + t := client.Dataset("my_dataset").Table("new-table") + if err := t.Create(ctx, + &bigquery.TableMetadata{ + Name: "My New Table", + Schema: schema, + ExpirationTime: time.Now().Add(24 * time.Hour), + }); err != nil { + // TODO: Handle error. + } +} + +// This example demonstrates how to create a table with +// a customer-managed encryption key. +func ExampleTable_Create_encryptionKey() { + ctx := context.Background() + // Infer table schema from a Go type. + schema, err := bigquery.InferSchema(Item{}) + if err != nil { + // TODO: Handle error. + } + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + t := client.Dataset("my_dataset").Table("new-table") + + // TODO: Replace this key with a key you have created in Cloud KMS. + keyName := "projects/P/locations/L/keyRings/R/cryptoKeys/K" + if err := t.Create(ctx, + &bigquery.TableMetadata{ + Name: "My New Table", + Schema: schema, + EncryptionConfig: &bigquery.EncryptionConfig{KMSKeyName: keyName}, + }); err != nil { + // TODO: Handle error. + } +} + +func ExampleTable_Delete() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + if err := client.Dataset("my_dataset").Table("my_table").Delete(ctx); err != nil { + // TODO: Handle error. + } +} + +func ExampleTable_Metadata() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + md, err := client.Dataset("my_dataset").Table("my_table").Metadata(ctx) + if err != nil { + // TODO: Handle error. + } + fmt.Println(md) +} + +func ExampleTable_Inserter() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + ins := client.Dataset("my_dataset").Table("my_table").Inserter() + _ = ins // TODO: Use ins. +} + +func ExampleTable_Inserter_options() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + ins := client.Dataset("my_dataset").Table("my_table").Inserter() + ins.SkipInvalidRows = true + ins.IgnoreUnknownValues = true + _ = ins // TODO: Use ins. +} + +func ExampleTable_CopierFrom() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + ds := client.Dataset("my_dataset") + c := ds.Table("combined").CopierFrom(ds.Table("t1"), ds.Table("t2")) + c.WriteDisposition = bigquery.WriteTruncate + // TODO: set other options on the Copier. + job, err := c.Run(ctx) + if err != nil { + // TODO: Handle error. + } + status, err := job.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + if status.Err() != nil { + // TODO: Handle error. + } +} + +func ExampleTable_ExtractorTo() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + gcsRef := bigquery.NewGCSReference("gs://my-bucket/my-object") + gcsRef.FieldDelimiter = ":" + // TODO: set other options on the GCSReference. + ds := client.Dataset("my_dataset") + extractor := ds.Table("my_table").ExtractorTo(gcsRef) + extractor.DisableHeader = true + // TODO: set other options on the Extractor. + job, err := extractor.Run(ctx) + if err != nil { + // TODO: Handle error. + } + status, err := job.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + if status.Err() != nil { + // TODO: Handle error. + } +} + +func ExampleTable_LoaderFrom() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + gcsRef := bigquery.NewGCSReference("gs://my-bucket/my-object") + gcsRef.AllowJaggedRows = true + gcsRef.MaxBadRecords = 5 + gcsRef.Schema = schema + // TODO: set other options on the GCSReference. + ds := client.Dataset("my_dataset") + loader := ds.Table("my_table").LoaderFrom(gcsRef) + loader.CreateDisposition = bigquery.CreateNever + // TODO: set other options on the Loader. + job, err := loader.Run(ctx) + if err != nil { + // TODO: Handle error. + } + status, err := job.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + if status.Err() != nil { + // TODO: Handle error. + } +} + +func ExampleTable_LoaderFrom_reader() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + f, err := os.Open("data.csv") + if err != nil { + // TODO: Handle error. + } + rs := bigquery.NewReaderSource(f) + rs.AllowJaggedRows = true + rs.MaxBadRecords = 5 + rs.Schema = schema + // TODO: set other options on the GCSReference. + ds := client.Dataset("my_dataset") + loader := ds.Table("my_table").LoaderFrom(rs) + loader.CreateDisposition = bigquery.CreateNever + // TODO: set other options on the Loader. + job, err := loader.Run(ctx) + if err != nil { + // TODO: Handle error. + } + status, err := job.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + if status.Err() != nil { + // TODO: Handle error. + } +} + +func ExampleTable_Read() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + it := client.Dataset("my_dataset").Table("my_table").Read(ctx) + _ = it // TODO: iterate using Next or iterator.Pager. +} + +// This example illustrates how to perform a read-modify-write sequence on table +// metadata. Passing the metadata's ETag to the Update call ensures that the call +// will fail if the metadata was changed since the read. +func ExampleTable_Update_readModifyWrite() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + t := client.Dataset("my_dataset").Table("my_table") + md, err := t.Metadata(ctx) + if err != nil { + // TODO: Handle error. + } + md2, err := t.Update(ctx, + bigquery.TableMetadataToUpdate{Name: "new " + md.Name}, + md.ETag) + if err != nil { + // TODO: Handle error. + } + fmt.Println(md2) +} + +// To perform a blind write, ignoring the existing state (and possibly overwriting +// other updates), pass the empty string as the etag. +func ExampleTable_Update_blindWrite() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + t := client.Dataset("my_dataset").Table("my_table") + tm, err := t.Update(ctx, bigquery.TableMetadataToUpdate{ + Description: "my favorite table", + }, "") + if err != nil { + // TODO: Handle error. + } + fmt.Println(tm) +} + +func ExampleTableIterator_Next() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + it := client.Dataset("my_dataset").Tables(ctx) + for { + t, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(t) + } +} + +type Item struct { + Name string + Size float64 + Count int +} + +// Save implements the ValueSaver interface. +func (i *Item) Save() (map[string]bigquery.Value, string, error) { + return map[string]bigquery.Value{ + "Name": i.Name, + "Size": i.Size, + "Count": i.Count, + }, "", nil +} + +func ExampleInserter_Put() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + ins := client.Dataset("my_dataset").Table("my_table").Inserter() + // Item implements the ValueSaver interface. + items := []*Item{ + {Name: "n1", Size: 32.6, Count: 7}, + {Name: "n2", Size: 4, Count: 2}, + {Name: "n3", Size: 101.5, Count: 1}, + } + if err := ins.Put(ctx, items); err != nil { + // TODO: Handle error. + } +} + +var schema bigquery.Schema + +func ExampleInserter_Put_structSaver() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + ins := client.Dataset("my_dataset").Table("my_table").Inserter() + + type score struct { + Name string + Num int + } + + // Assume schema holds the table's schema. + savers := []*bigquery.StructSaver{ + {Struct: score{Name: "n1", Num: 12}, Schema: schema, InsertID: "id1"}, + {Struct: score{Name: "n2", Num: 31}, Schema: schema, InsertID: "id2"}, + {Struct: score{Name: "n3", Num: 7}, Schema: schema, InsertID: "id3"}, + } + if err := ins.Put(ctx, savers); err != nil { + // TODO: Handle error. + } +} + +func ExampleInserter_Put_struct() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + ins := client.Dataset("my_dataset").Table("my_table").Inserter() + + type score struct { + Name string + Num int + } + scores := []score{ + {Name: "n1", Num: 12}, + {Name: "n2", Num: 31}, + {Name: "n3", Num: 7}, + } + // Schema is inferred from the score type. + if err := ins.Put(ctx, scores); err != nil { + // TODO: Handle error. + } +} + +func ExampleInserter_Put_valuesSaver() { + ctx := context.Background() + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + ins := client.Dataset("my_dataset").Table("my_table").Inserter() + + var vss []*bigquery.ValuesSaver + for i, name := range []string{"n1", "n2", "n3"} { + // Assume schema holds the table's schema. + vss = append(vss, &bigquery.ValuesSaver{ + Schema: schema, + InsertID: name, + Row: []bigquery.Value{name, int64(i)}, + }) + } + + if err := ins.Put(ctx, vss); err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/bigquery/external.go b/vendor/cloud.google.com/go/bigquery/external.go new file mode 100644 index 00000000..2ceb38d5 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/external.go @@ -0,0 +1,400 @@ +// Copyright 2017 Google LLC +// +// 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 bigquery + +import ( + "encoding/base64" + "unicode/utf8" + + bq "google.golang.org/api/bigquery/v2" +) + +// DataFormat describes the format of BigQuery table data. +type DataFormat string + +// Constants describing the format of BigQuery table data. +const ( + CSV DataFormat = "CSV" + Avro DataFormat = "AVRO" + JSON DataFormat = "NEWLINE_DELIMITED_JSON" + DatastoreBackup DataFormat = "DATASTORE_BACKUP" + GoogleSheets DataFormat = "GOOGLE_SHEETS" + Bigtable DataFormat = "BIGTABLE" + Parquet DataFormat = "PARQUET" + ORC DataFormat = "ORC" +) + +// ExternalData is a table which is stored outside of BigQuery. It is implemented by +// *ExternalDataConfig. +// GCSReference also implements it, for backwards compatibility. +type ExternalData interface { + toBQ() bq.ExternalDataConfiguration +} + +// ExternalDataConfig describes data external to BigQuery that can be used +// in queries and to create external tables. +type ExternalDataConfig struct { + // The format of the data. Required. + SourceFormat DataFormat + + // The fully-qualified URIs that point to your + // data in Google Cloud. Required. + // + // For Google Cloud Storage URIs, each URI can contain one '*' wildcard character + // and it must come after the 'bucket' name. Size limits related to load jobs + // apply to external data sources. + // + // For Google Cloud Bigtable URIs, exactly one URI can be specified and it has be + // a fully specified and valid HTTPS URL for a Google Cloud Bigtable table. + // + // For Google Cloud Datastore backups, exactly one URI can be specified. Also, + // the '*' wildcard character is not allowed. + SourceURIs []string + + // The schema of the data. Required for CSV and JSON; disallowed for the + // other formats. + Schema Schema + + // Try to detect schema and format options automatically. + // Any option specified explicitly will be honored. + AutoDetect bool + + // The compression type of the data. + Compression Compression + + // IgnoreUnknownValues causes values not matching the schema to be + // tolerated. Unknown values are ignored. For CSV this ignores extra values + // at the end of a line. For JSON this ignores named values that do not + // match any column name. If this field is not set, records containing + // unknown values are treated as bad records. The MaxBadRecords field can + // be used to customize how bad records are handled. + IgnoreUnknownValues bool + + // MaxBadRecords is the maximum number of bad records that will be ignored + // when reading data. + MaxBadRecords int64 + + // Additional options for CSV, GoogleSheets and Bigtable formats. + Options ExternalDataConfigOptions +} + +func (e *ExternalDataConfig) toBQ() bq.ExternalDataConfiguration { + q := bq.ExternalDataConfiguration{ + SourceFormat: string(e.SourceFormat), + SourceUris: e.SourceURIs, + Autodetect: e.AutoDetect, + Compression: string(e.Compression), + IgnoreUnknownValues: e.IgnoreUnknownValues, + MaxBadRecords: e.MaxBadRecords, + } + if e.Schema != nil { + q.Schema = e.Schema.toBQ() + } + if e.Options != nil { + e.Options.populateExternalDataConfig(&q) + } + return q +} + +func bqToExternalDataConfig(q *bq.ExternalDataConfiguration) (*ExternalDataConfig, error) { + e := &ExternalDataConfig{ + SourceFormat: DataFormat(q.SourceFormat), + SourceURIs: q.SourceUris, + AutoDetect: q.Autodetect, + Compression: Compression(q.Compression), + IgnoreUnknownValues: q.IgnoreUnknownValues, + MaxBadRecords: q.MaxBadRecords, + Schema: bqToSchema(q.Schema), + } + switch { + case q.CsvOptions != nil: + e.Options = bqToCSVOptions(q.CsvOptions) + case q.GoogleSheetsOptions != nil: + e.Options = bqToGoogleSheetsOptions(q.GoogleSheetsOptions) + case q.BigtableOptions != nil: + var err error + e.Options, err = bqToBigtableOptions(q.BigtableOptions) + if err != nil { + return nil, err + } + } + return e, nil +} + +// ExternalDataConfigOptions are additional options for external data configurations. +// This interface is implemented by CSVOptions, GoogleSheetsOptions and BigtableOptions. +type ExternalDataConfigOptions interface { + populateExternalDataConfig(*bq.ExternalDataConfiguration) +} + +// CSVOptions are additional options for CSV external data sources. +type CSVOptions struct { + // AllowJaggedRows causes missing trailing optional columns to be tolerated + // when reading CSV data. Missing values are treated as nulls. + AllowJaggedRows bool + + // AllowQuotedNewlines sets whether quoted data sections containing + // newlines are allowed when reading CSV data. + AllowQuotedNewlines bool + + // Encoding is the character encoding of data to be read. + Encoding Encoding + + // FieldDelimiter is the separator for fields in a CSV file, used when + // reading or exporting data. The default is ",". + FieldDelimiter string + + // Quote is the value used to quote data sections in a CSV file. The + // default quotation character is the double quote ("), which is used if + // both Quote and ForceZeroQuote are unset. + // To specify that no character should be interpreted as a quotation + // character, set ForceZeroQuote to true. + // Only used when reading data. + Quote string + ForceZeroQuote bool + + // The number of rows at the top of a CSV file that BigQuery will skip when + // reading data. + SkipLeadingRows int64 +} + +func (o *CSVOptions) populateExternalDataConfig(c *bq.ExternalDataConfiguration) { + c.CsvOptions = &bq.CsvOptions{ + AllowJaggedRows: o.AllowJaggedRows, + AllowQuotedNewlines: o.AllowQuotedNewlines, + Encoding: string(o.Encoding), + FieldDelimiter: o.FieldDelimiter, + Quote: o.quote(), + SkipLeadingRows: o.SkipLeadingRows, + } +} + +// quote returns the CSV quote character, or nil if unset. +func (o *CSVOptions) quote() *string { + if o.ForceZeroQuote { + quote := "" + return "e + } + if o.Quote == "" { + return nil + } + return &o.Quote +} + +func (o *CSVOptions) setQuote(ps *string) { + if ps != nil { + o.Quote = *ps + if o.Quote == "" { + o.ForceZeroQuote = true + } + } +} + +func bqToCSVOptions(q *bq.CsvOptions) *CSVOptions { + o := &CSVOptions{ + AllowJaggedRows: q.AllowJaggedRows, + AllowQuotedNewlines: q.AllowQuotedNewlines, + Encoding: Encoding(q.Encoding), + FieldDelimiter: q.FieldDelimiter, + SkipLeadingRows: q.SkipLeadingRows, + } + o.setQuote(q.Quote) + return o +} + +// GoogleSheetsOptions are additional options for GoogleSheets external data sources. +type GoogleSheetsOptions struct { + // The number of rows at the top of a sheet that BigQuery will skip when + // reading data. + SkipLeadingRows int64 +} + +func (o *GoogleSheetsOptions) populateExternalDataConfig(c *bq.ExternalDataConfiguration) { + c.GoogleSheetsOptions = &bq.GoogleSheetsOptions{ + SkipLeadingRows: o.SkipLeadingRows, + } +} + +func bqToGoogleSheetsOptions(q *bq.GoogleSheetsOptions) *GoogleSheetsOptions { + return &GoogleSheetsOptions{ + SkipLeadingRows: q.SkipLeadingRows, + } +} + +// BigtableOptions are additional options for Bigtable external data sources. +type BigtableOptions struct { + // A list of column families to expose in the table schema along with their + // types. If omitted, all column families are present in the table schema and + // their values are read as BYTES. + ColumnFamilies []*BigtableColumnFamily + + // If true, then the column families that are not specified in columnFamilies + // list are not exposed in the table schema. Otherwise, they are read with BYTES + // type values. The default is false. + IgnoreUnspecifiedColumnFamilies bool + + // If true, then the rowkey column families will be read and converted to string. + // Otherwise they are read with BYTES type values and users need to manually cast + // them with CAST if necessary. The default is false. + ReadRowkeyAsString bool +} + +func (o *BigtableOptions) populateExternalDataConfig(c *bq.ExternalDataConfiguration) { + q := &bq.BigtableOptions{ + IgnoreUnspecifiedColumnFamilies: o.IgnoreUnspecifiedColumnFamilies, + ReadRowkeyAsString: o.ReadRowkeyAsString, + } + for _, f := range o.ColumnFamilies { + q.ColumnFamilies = append(q.ColumnFamilies, f.toBQ()) + } + c.BigtableOptions = q +} + +func bqToBigtableOptions(q *bq.BigtableOptions) (*BigtableOptions, error) { + b := &BigtableOptions{ + IgnoreUnspecifiedColumnFamilies: q.IgnoreUnspecifiedColumnFamilies, + ReadRowkeyAsString: q.ReadRowkeyAsString, + } + for _, f := range q.ColumnFamilies { + f2, err := bqToBigtableColumnFamily(f) + if err != nil { + return nil, err + } + b.ColumnFamilies = append(b.ColumnFamilies, f2) + } + return b, nil +} + +// BigtableColumnFamily describes how BigQuery should access a Bigtable column family. +type BigtableColumnFamily struct { + // Identifier of the column family. + FamilyID string + + // Lists of columns that should be exposed as individual fields as opposed to a + // list of (column name, value) pairs. All columns whose qualifier matches a + // qualifier in this list can be accessed as .. Other columns can be accessed as + // a list through .Column field. + Columns []*BigtableColumn + + // The encoding of the values when the type is not STRING. Acceptable encoding values are: + // - TEXT - indicates values are alphanumeric text strings. + // - BINARY - indicates values are encoded using HBase Bytes.toBytes family of functions. + // This can be overridden for a specific column by listing that column in 'columns' and + // specifying an encoding for it. + Encoding string + + // If true, only the latest version of values are exposed for all columns in this + // column family. This can be overridden for a specific column by listing that + // column in 'columns' and specifying a different setting for that column. + OnlyReadLatest bool + + // The type to convert the value in cells of this + // column family. The values are expected to be encoded using HBase + // Bytes.toBytes function when using the BINARY encoding value. + // Following BigQuery types are allowed (case-sensitive): + // BYTES STRING INTEGER FLOAT BOOLEAN. + // The default type is BYTES. This can be overridden for a specific column by + // listing that column in 'columns' and specifying a type for it. + Type string +} + +func (b *BigtableColumnFamily) toBQ() *bq.BigtableColumnFamily { + q := &bq.BigtableColumnFamily{ + FamilyId: b.FamilyID, + Encoding: b.Encoding, + OnlyReadLatest: b.OnlyReadLatest, + Type: b.Type, + } + for _, col := range b.Columns { + q.Columns = append(q.Columns, col.toBQ()) + } + return q +} + +func bqToBigtableColumnFamily(q *bq.BigtableColumnFamily) (*BigtableColumnFamily, error) { + b := &BigtableColumnFamily{ + FamilyID: q.FamilyId, + Encoding: q.Encoding, + OnlyReadLatest: q.OnlyReadLatest, + Type: q.Type, + } + for _, col := range q.Columns { + c, err := bqToBigtableColumn(col) + if err != nil { + return nil, err + } + b.Columns = append(b.Columns, c) + } + return b, nil +} + +// BigtableColumn describes how BigQuery should access a Bigtable column. +type BigtableColumn struct { + // Qualifier of the column. Columns in the parent column family that have this + // exact qualifier are exposed as . field. The column field name is the + // same as the column qualifier. + Qualifier string + + // If the qualifier is not a valid BigQuery field identifier i.e. does not match + // [a-zA-Z][a-zA-Z0-9_]*, a valid identifier must be provided as the column field + // name and is used as field name in queries. + FieldName string + + // If true, only the latest version of values are exposed for this column. + // See BigtableColumnFamily.OnlyReadLatest. + OnlyReadLatest bool + + // The encoding of the values when the type is not STRING. + // See BigtableColumnFamily.Encoding + Encoding string + + // The type to convert the value in cells of this column. + // See BigtableColumnFamily.Type + Type string +} + +func (b *BigtableColumn) toBQ() *bq.BigtableColumn { + q := &bq.BigtableColumn{ + FieldName: b.FieldName, + OnlyReadLatest: b.OnlyReadLatest, + Encoding: b.Encoding, + Type: b.Type, + } + if utf8.ValidString(b.Qualifier) { + q.QualifierString = b.Qualifier + } else { + q.QualifierEncoded = base64.RawStdEncoding.EncodeToString([]byte(b.Qualifier)) + } + return q +} + +func bqToBigtableColumn(q *bq.BigtableColumn) (*BigtableColumn, error) { + b := &BigtableColumn{ + FieldName: q.FieldName, + OnlyReadLatest: q.OnlyReadLatest, + Encoding: q.Encoding, + Type: q.Type, + } + if q.QualifierString != "" { + b.Qualifier = q.QualifierString + } else { + bytes, err := base64.RawStdEncoding.DecodeString(q.QualifierEncoded) + if err != nil { + return nil, err + } + b.Qualifier = string(bytes) + } + return b, nil +} diff --git a/vendor/cloud.google.com/go/bigquery/external_test.go b/vendor/cloud.google.com/go/bigquery/external_test.go new file mode 100644 index 00000000..454bb086 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/external_test.go @@ -0,0 +1,143 @@ +// Copyright 2017 Google LLC +// +// 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 bigquery + +import ( + "testing" + + "cloud.google.com/go/internal/pretty" + "cloud.google.com/go/internal/testutil" +) + +func TestExternalDataConfig(t *testing.T) { + // Round-trip of ExternalDataConfig to underlying representation. + for i, want := range []*ExternalDataConfig{ + { + SourceFormat: CSV, + SourceURIs: []string{"uri"}, + Schema: Schema{{Name: "n", Type: IntegerFieldType}}, + AutoDetect: true, + Compression: Gzip, + IgnoreUnknownValues: true, + MaxBadRecords: 17, + Options: &CSVOptions{ + AllowJaggedRows: true, + AllowQuotedNewlines: true, + Encoding: UTF_8, + FieldDelimiter: "f", + Quote: "q", + SkipLeadingRows: 3, + }, + }, + { + SourceFormat: GoogleSheets, + Options: &GoogleSheetsOptions{SkipLeadingRows: 4}, + }, + { + SourceFormat: Bigtable, + Options: &BigtableOptions{ + IgnoreUnspecifiedColumnFamilies: true, + ReadRowkeyAsString: true, + ColumnFamilies: []*BigtableColumnFamily{ + { + FamilyID: "f1", + Encoding: "TEXT", + OnlyReadLatest: true, + Type: "FLOAT", + Columns: []*BigtableColumn{ + { + Qualifier: "valid-utf-8", + FieldName: "fn", + OnlyReadLatest: true, + Encoding: "BINARY", + Type: "STRING", + }, + }, + }, + }, + }, + }, + } { + q := want.toBQ() + got, err := bqToExternalDataConfig(&q) + if err != nil { + t.Fatal(err) + } + if diff := testutil.Diff(got, want); diff != "" { + t.Errorf("#%d: got=-, want=+:\n%s", i, diff) + } + } +} + +func TestQuote(t *testing.T) { + ptr := func(s string) *string { return &s } + + for _, test := range []struct { + quote string + force bool + want *string + }{ + {"", false, nil}, + {"", true, ptr("")}, + {"-", false, ptr("-")}, + {"-", true, ptr("")}, + } { + o := CSVOptions{ + Quote: test.quote, + ForceZeroQuote: test.force, + } + got := o.quote() + if (got == nil) != (test.want == nil) { + t.Errorf("%+v\ngot %v\nwant %v", test, pretty.Value(got), pretty.Value(test.want)) + } + if got != nil && test.want != nil && *got != *test.want { + t.Errorf("%+v: got %q, want %q", test, *got, *test.want) + } + } +} + +func TestQualifier(t *testing.T) { + b := BigtableColumn{Qualifier: "a"} + q := b.toBQ() + if q.QualifierString != b.Qualifier || q.QualifierEncoded != "" { + t.Errorf("got (%q, %q), want (%q, %q)", + q.QualifierString, q.QualifierEncoded, b.Qualifier, "") + } + b2, err := bqToBigtableColumn(q) + if err != nil { + t.Fatal(err) + } + if got, want := b2.Qualifier, b.Qualifier; got != want { + t.Errorf("got %q, want %q", got, want) + } + + const ( + invalidUTF8 = "\xDF\xFF" + invalidEncoded = "3/8" + ) + b = BigtableColumn{Qualifier: invalidUTF8} + q = b.toBQ() + if q.QualifierString != "" || q.QualifierEncoded != invalidEncoded { + t.Errorf("got (%q, %q), want (%q, %q)", + q.QualifierString, "", b.Qualifier, invalidEncoded) + } + b2, err = bqToBigtableColumn(q) + if err != nil { + t.Fatal(err) + } + if got, want := b2.Qualifier, b.Qualifier; got != want { + t.Errorf("got %q, want %q", got, want) + } +} diff --git a/vendor/cloud.google.com/go/bigquery/extract.go b/vendor/cloud.google.com/go/bigquery/extract.go new file mode 100644 index 00000000..a77f2759 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/extract.go @@ -0,0 +1,110 @@ +// Copyright 2016 Google LLC +// +// 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 bigquery + +import ( + "context" + + "cloud.google.com/go/internal/trace" + bq "google.golang.org/api/bigquery/v2" +) + +// ExtractConfig holds the configuration for an extract job. +type ExtractConfig struct { + // Src is the table from which data will be extracted. + Src *Table + + // Dst is the destination into which the data will be extracted. + Dst *GCSReference + + // DisableHeader disables the printing of a header row in exported data. + DisableHeader bool + + // The labels associated with this job. + Labels map[string]string +} + +func (e *ExtractConfig) toBQ() *bq.JobConfiguration { + var printHeader *bool + if e.DisableHeader { + f := false + printHeader = &f + } + return &bq.JobConfiguration{ + Labels: e.Labels, + Extract: &bq.JobConfigurationExtract{ + DestinationUris: append([]string{}, e.Dst.URIs...), + Compression: string(e.Dst.Compression), + DestinationFormat: string(e.Dst.DestinationFormat), + FieldDelimiter: e.Dst.FieldDelimiter, + SourceTable: e.Src.toBQ(), + PrintHeader: printHeader, + }, + } +} + +func bqToExtractConfig(q *bq.JobConfiguration, c *Client) *ExtractConfig { + qe := q.Extract + return &ExtractConfig{ + Labels: q.Labels, + Dst: &GCSReference{ + URIs: qe.DestinationUris, + Compression: Compression(qe.Compression), + DestinationFormat: DataFormat(qe.DestinationFormat), + FileConfig: FileConfig{ + CSVOptions: CSVOptions{ + FieldDelimiter: qe.FieldDelimiter, + }, + }, + }, + DisableHeader: qe.PrintHeader != nil && !*qe.PrintHeader, + Src: bqToTable(qe.SourceTable, c), + } +} + +// An Extractor extracts data from a BigQuery table into Google Cloud Storage. +type Extractor struct { + JobIDConfig + ExtractConfig + c *Client +} + +// ExtractorTo returns an Extractor which can be used to extract data from a +// BigQuery table into Google Cloud Storage. +// The returned Extractor may optionally be further configured before its Run method is called. +func (t *Table) ExtractorTo(dst *GCSReference) *Extractor { + return &Extractor{ + c: t.c, + ExtractConfig: ExtractConfig{ + Src: t, + Dst: dst, + }, + } +} + +// Run initiates an extract job. +func (e *Extractor) Run(ctx context.Context) (j *Job, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Extractor.Run") + defer func() { trace.EndSpan(ctx, err) }() + + return e.c.insertJob(ctx, e.newJob(), nil) +} + +func (e *Extractor) newJob() *bq.Job { + return &bq.Job{ + JobReference: e.JobIDConfig.createJobRef(e.c), + Configuration: e.ExtractConfig.toBQ(), + } +} diff --git a/vendor/cloud.google.com/go/bigquery/extract_test.go b/vendor/cloud.google.com/go/bigquery/extract_test.go new file mode 100644 index 00000000..ddf73092 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/extract_test.go @@ -0,0 +1,116 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "testing" + + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" + bq "google.golang.org/api/bigquery/v2" +) + +func defaultExtractJob() *bq.Job { + return &bq.Job{ + JobReference: &bq.JobReference{JobId: "RANDOM", ProjectId: "client-project-id"}, + Configuration: &bq.JobConfiguration{ + Extract: &bq.JobConfigurationExtract{ + SourceTable: &bq.TableReference{ + ProjectId: "client-project-id", + DatasetId: "dataset-id", + TableId: "table-id", + }, + DestinationUris: []string{"uri"}, + }, + }, + } +} + +func defaultGCS() *GCSReference { + return &GCSReference{ + URIs: []string{"uri"}, + } +} + +func TestExtract(t *testing.T) { + defer fixRandomID("RANDOM")() + c := &Client{ + projectID: "client-project-id", + } + + testCases := []struct { + dst *GCSReference + src *Table + config ExtractConfig + want *bq.Job + }{ + { + dst: defaultGCS(), + src: c.Dataset("dataset-id").Table("table-id"), + want: defaultExtractJob(), + }, + { + dst: defaultGCS(), + src: c.Dataset("dataset-id").Table("table-id"), + config: ExtractConfig{ + DisableHeader: true, + Labels: map[string]string{"a": "b"}, + }, + want: func() *bq.Job { + j := defaultExtractJob() + j.Configuration.Labels = map[string]string{"a": "b"} + f := false + j.Configuration.Extract.PrintHeader = &f + return j + }(), + }, + { + dst: func() *GCSReference { + g := NewGCSReference("uri") + g.Compression = Gzip + g.DestinationFormat = JSON + g.FieldDelimiter = "\t" + return g + }(), + src: c.Dataset("dataset-id").Table("table-id"), + want: func() *bq.Job { + j := defaultExtractJob() + j.Configuration.Extract.Compression = "GZIP" + j.Configuration.Extract.DestinationFormat = "NEWLINE_DELIMITED_JSON" + j.Configuration.Extract.FieldDelimiter = "\t" + return j + }(), + }, + } + + for i, tc := range testCases { + ext := tc.src.ExtractorTo(tc.dst) + tc.config.Src = ext.Src + tc.config.Dst = ext.Dst + ext.ExtractConfig = tc.config + got := ext.newJob() + checkJob(t, i, got, tc.want) + + jc, err := bqToJobConfig(got.Configuration, c) + if err != nil { + t.Fatalf("#%d: %v", i, err) + } + diff := testutil.Diff(jc, &ext.ExtractConfig, + cmp.AllowUnexported(Table{}, Client{})) + if diff != "" { + t.Errorf("#%d: (got=-, want=+:\n%s", i, diff) + } + } +} diff --git a/vendor/cloud.google.com/go/bigquery/file.go b/vendor/cloud.google.com/go/bigquery/file.go new file mode 100644 index 00000000..8dd86f5d --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/file.go @@ -0,0 +1,137 @@ +// Copyright 2016 Google LLC +// +// 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 bigquery + +import ( + "io" + + bq "google.golang.org/api/bigquery/v2" +) + +// A ReaderSource is a source for a load operation that gets +// data from an io.Reader. +// +// When a ReaderSource is part of a LoadConfig obtained via Job.Config, +// its internal io.Reader will be nil, so it cannot be used for a +// subsequent load operation. +type ReaderSource struct { + r io.Reader + FileConfig +} + +// NewReaderSource creates a ReaderSource from an io.Reader. You may +// optionally configure properties on the ReaderSource that describe the +// data being read, before passing it to Table.LoaderFrom. +func NewReaderSource(r io.Reader) *ReaderSource { + return &ReaderSource{r: r} +} + +func (r *ReaderSource) populateLoadConfig(lc *bq.JobConfigurationLoad) io.Reader { + r.FileConfig.populateLoadConfig(lc) + return r.r +} + +// FileConfig contains configuration options that pertain to files, typically +// text files that require interpretation to be used as a BigQuery table. A +// file may live in Google Cloud Storage (see GCSReference), or it may be +// loaded into a table via the Table.LoaderFromReader. +type FileConfig struct { + // SourceFormat is the format of the data to be read. + // Allowed values are: Avro, CSV, DatastoreBackup, JSON, ORC, and Parquet. The default is CSV. + SourceFormat DataFormat + + // Indicates if we should automatically infer the options and + // schema for CSV and JSON sources. + AutoDetect bool + + // MaxBadRecords is the maximum number of bad records that will be ignored + // when reading data. + MaxBadRecords int64 + + // IgnoreUnknownValues causes values not matching the schema to be + // tolerated. Unknown values are ignored. For CSV this ignores extra values + // at the end of a line. For JSON this ignores named values that do not + // match any column name. If this field is not set, records containing + // unknown values are treated as bad records. The MaxBadRecords field can + // be used to customize how bad records are handled. + IgnoreUnknownValues bool + + // Schema describes the data. It is required when reading CSV or JSON data, + // unless the data is being loaded into a table that already exists. + Schema Schema + + // Additional options for CSV files. + CSVOptions +} + +func (fc *FileConfig) populateLoadConfig(conf *bq.JobConfigurationLoad) { + conf.SkipLeadingRows = fc.SkipLeadingRows + conf.SourceFormat = string(fc.SourceFormat) + conf.Autodetect = fc.AutoDetect + conf.AllowJaggedRows = fc.AllowJaggedRows + conf.AllowQuotedNewlines = fc.AllowQuotedNewlines + conf.Encoding = string(fc.Encoding) + conf.FieldDelimiter = fc.FieldDelimiter + conf.IgnoreUnknownValues = fc.IgnoreUnknownValues + conf.MaxBadRecords = fc.MaxBadRecords + if fc.Schema != nil { + conf.Schema = fc.Schema.toBQ() + } + conf.Quote = fc.quote() +} + +func bqPopulateFileConfig(conf *bq.JobConfigurationLoad, fc *FileConfig) { + fc.SourceFormat = DataFormat(conf.SourceFormat) + fc.AutoDetect = conf.Autodetect + fc.MaxBadRecords = conf.MaxBadRecords + fc.IgnoreUnknownValues = conf.IgnoreUnknownValues + fc.Schema = bqToSchema(conf.Schema) + fc.SkipLeadingRows = conf.SkipLeadingRows + fc.AllowJaggedRows = conf.AllowJaggedRows + fc.AllowQuotedNewlines = conf.AllowQuotedNewlines + fc.Encoding = Encoding(conf.Encoding) + fc.FieldDelimiter = conf.FieldDelimiter + fc.CSVOptions.setQuote(conf.Quote) +} + +func (fc *FileConfig) populateExternalDataConfig(conf *bq.ExternalDataConfiguration) { + format := fc.SourceFormat + if format == "" { + // Format must be explicitly set for external data sources. + format = CSV + } + conf.Autodetect = fc.AutoDetect + conf.IgnoreUnknownValues = fc.IgnoreUnknownValues + conf.MaxBadRecords = fc.MaxBadRecords + conf.SourceFormat = string(format) + if fc.Schema != nil { + conf.Schema = fc.Schema.toBQ() + } + if format == CSV { + fc.CSVOptions.populateExternalDataConfig(conf) + } +} + +// Encoding specifies the character encoding of data to be loaded into BigQuery. +// See https://cloud.google.com/bigquery/docs/reference/v2/jobs#configuration.load.encoding +// for more details about how this is used. +type Encoding string + +const ( + // UTF_8 specifies the UTF-8 encoding type. + UTF_8 Encoding = "UTF-8" + // ISO_8859_1 specifies the ISO-8859-1 encoding type. + ISO_8859_1 Encoding = "ISO-8859-1" +) diff --git a/vendor/cloud.google.com/go/bigquery/file_test.go b/vendor/cloud.google.com/go/bigquery/file_test.go new file mode 100644 index 00000000..96e18bff --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/file_test.go @@ -0,0 +1,98 @@ +// Copyright 2016 Google LLC +// +// 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 bigquery + +import ( + "testing" + + "cloud.google.com/go/internal/pretty" + "cloud.google.com/go/internal/testutil" + bq "google.golang.org/api/bigquery/v2" +) + +var ( + hyphen = "-" + fc = FileConfig{ + SourceFormat: CSV, + AutoDetect: true, + MaxBadRecords: 7, + IgnoreUnknownValues: true, + Schema: Schema{ + stringFieldSchema(), + nestedFieldSchema(), + }, + CSVOptions: CSVOptions{ + Quote: hyphen, + FieldDelimiter: "\t", + SkipLeadingRows: 8, + AllowJaggedRows: true, + AllowQuotedNewlines: true, + Encoding: UTF_8, + }, + } +) + +func TestFileConfigPopulateLoadConfig(t *testing.T) { + want := &bq.JobConfigurationLoad{ + SourceFormat: "CSV", + FieldDelimiter: "\t", + SkipLeadingRows: 8, + AllowJaggedRows: true, + AllowQuotedNewlines: true, + Autodetect: true, + Encoding: "UTF-8", + MaxBadRecords: 7, + IgnoreUnknownValues: true, + Schema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqStringFieldSchema(), + bqNestedFieldSchema(), + }}, + Quote: &hyphen, + } + got := &bq.JobConfigurationLoad{} + fc.populateLoadConfig(got) + if !testutil.Equal(got, want) { + t.Errorf("got:\n%v\nwant:\n%v", pretty.Value(got), pretty.Value(want)) + } +} + +func TestFileConfigPopulateExternalDataConfig(t *testing.T) { + got := &bq.ExternalDataConfiguration{} + fc.populateExternalDataConfig(got) + + want := &bq.ExternalDataConfiguration{ + SourceFormat: "CSV", + Autodetect: true, + MaxBadRecords: 7, + IgnoreUnknownValues: true, + Schema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqStringFieldSchema(), + bqNestedFieldSchema(), + }}, + CsvOptions: &bq.CsvOptions{ + AllowJaggedRows: true, + AllowQuotedNewlines: true, + Encoding: "UTF-8", + FieldDelimiter: "\t", + Quote: &hyphen, + SkipLeadingRows: 8, + }, + } + if diff := testutil.Diff(got, want); diff != "" { + t.Errorf("got=-, want=+:\n%s", diff) + } +} diff --git a/vendor/cloud.google.com/go/bigquery/gcs.go b/vendor/cloud.google.com/go/bigquery/gcs.go new file mode 100644 index 00000000..6b70126b --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/gcs.go @@ -0,0 +1,75 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "io" + + bq "google.golang.org/api/bigquery/v2" +) + +// GCSReference is a reference to one or more Google Cloud Storage objects, which together constitute +// an input or output to a BigQuery operation. +type GCSReference struct { + // URIs refer to Google Cloud Storage objects. + URIs []string + + FileConfig + + // DestinationFormat is the format to use when writing exported files. + // Allowed values are: CSV, Avro, JSON. The default is CSV. + // CSV is not supported for tables with nested or repeated fields. + DestinationFormat DataFormat + + // Compression specifies the type of compression to apply when writing data + // to Google Cloud Storage, or using this GCSReference as an ExternalData + // source with CSV or JSON SourceFormat. Default is None. + Compression Compression +} + +// NewGCSReference constructs a reference to one or more Google Cloud Storage objects, which together constitute a data source or destination. +// In the simple case, a single URI in the form gs://bucket/object may refer to a single GCS object. +// Data may also be split into mutiple files, if multiple URIs or URIs containing wildcards are provided. +// Each URI may contain one '*' wildcard character, which (if present) must come after the bucket name. +// For more information about the treatment of wildcards and multiple URIs, +// see https://cloud.google.com/bigquery/exporting-data-from-bigquery#exportingmultiple +func NewGCSReference(uri ...string) *GCSReference { + return &GCSReference{URIs: uri} +} + +// Compression is the type of compression to apply when writing data to Google Cloud Storage. +type Compression string + +const ( + // None specifies no compression. + None Compression = "NONE" + // Gzip specifies gzip compression. + Gzip Compression = "GZIP" +) + +func (gcs *GCSReference) populateLoadConfig(lc *bq.JobConfigurationLoad) io.Reader { + lc.SourceUris = gcs.URIs + gcs.FileConfig.populateLoadConfig(lc) + return nil +} + +func (gcs *GCSReference) toBQ() bq.ExternalDataConfiguration { + conf := bq.ExternalDataConfiguration{ + Compression: string(gcs.Compression), + SourceUris: append([]string{}, gcs.URIs...), + } + gcs.FileConfig.populateExternalDataConfig(&conf) + return conf +} diff --git a/vendor/cloud.google.com/go/bigquery/inserter.go b/vendor/cloud.google.com/go/bigquery/inserter.go new file mode 100644 index 00000000..132994e9 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/inserter.go @@ -0,0 +1,238 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "context" + "errors" + "fmt" + "reflect" + + "cloud.google.com/go/internal/trace" + bq "google.golang.org/api/bigquery/v2" +) + +// An Inserter does streaming inserts into a BigQuery table. +// It is safe for concurrent use. +type Inserter struct { + t *Table + + // SkipInvalidRows causes rows containing invalid data to be silently + // ignored. The default value is false, which causes the entire request to + // fail if there is an attempt to insert an invalid row. + SkipInvalidRows bool + + // IgnoreUnknownValues causes values not matching the schema to be ignored. + // The default value is false, which causes records containing such values + // to be treated as invalid records. + IgnoreUnknownValues bool + + // A TableTemplateSuffix allows Inserters to create tables automatically. + // + // Experimental: this option is experimental and may be modified or removed in future versions, + // regardless of any other documented package stability guarantees. + // + // When you specify a suffix, the table you upload data to + // will be used as a template for creating a new table, with the same schema, + // called + . + // + // More information is available at + // https://cloud.google.com/bigquery/streaming-data-into-bigquery#template-tables + TableTemplateSuffix string +} + +// Inserter returns an Inserter that can be used to append rows to t. +// The returned Inserter may optionally be further configured before its Put method is called. +// +// To stream rows into a date-partitioned table at a particular date, add the +// $yyyymmdd suffix to the table name when constructing the Table. +func (t *Table) Inserter() *Inserter { + return &Inserter{t: t} +} + +// Uploader calls Inserter. +// Deprecated: use Table.Inserter instead. +func (t *Table) Uploader() *Inserter { return t.Inserter() } + +// Put uploads one or more rows to the BigQuery service. +// +// If src is ValueSaver, then its Save method is called to produce a row for uploading. +// +// If src is a struct or pointer to a struct, then a schema is inferred from it +// and used to create a StructSaver. The InsertID of the StructSaver will be +// empty. +// +// If src is a slice of ValueSavers, structs, or struct pointers, then each +// element of the slice is treated as above, and multiple rows are uploaded. +// +// Put returns a PutMultiError if one or more rows failed to be uploaded. +// The PutMultiError contains a RowInsertionError for each failed row. +// +// Put will retry on temporary errors (see +// https://cloud.google.com/bigquery/troubleshooting-errors). This can result +// in duplicate rows if you do not use insert IDs. Also, if the error persists, +// the call will run indefinitely. Pass a context with a timeout to prevent +// hanging calls. +func (u *Inserter) Put(ctx context.Context, src interface{}) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Inserter.Put") + defer func() { trace.EndSpan(ctx, err) }() + + savers, err := valueSavers(src) + if err != nil { + return err + } + return u.putMulti(ctx, savers) +} + +func valueSavers(src interface{}) ([]ValueSaver, error) { + saver, ok, err := toValueSaver(src) + if err != nil { + return nil, err + } + if ok { + return []ValueSaver{saver}, nil + } + srcVal := reflect.ValueOf(src) + if srcVal.Kind() != reflect.Slice { + return nil, fmt.Errorf("%T is not a ValueSaver, struct, struct pointer, or slice", src) + + } + var savers []ValueSaver + for i := 0; i < srcVal.Len(); i++ { + s := srcVal.Index(i).Interface() + saver, ok, err := toValueSaver(s) + if err != nil { + return nil, err + } + if !ok { + return nil, fmt.Errorf("src[%d] has type %T, which is not a ValueSaver, struct or struct pointer", i, s) + } + savers = append(savers, saver) + } + return savers, nil +} + +// Make a ValueSaver from x, which must implement ValueSaver already +// or be a struct or pointer to struct. +func toValueSaver(x interface{}) (ValueSaver, bool, error) { + if _, ok := x.(StructSaver); ok { + return nil, false, errors.New("bigquery: use &StructSaver, not StructSaver") + } + var insertID string + // Handle StructSavers specially so we can infer the schema if necessary. + if ss, ok := x.(*StructSaver); ok && ss.Schema == nil { + x = ss.Struct + insertID = ss.InsertID + // Fall through so we can infer the schema. + } + if saver, ok := x.(ValueSaver); ok { + return saver, ok, nil + } + v := reflect.ValueOf(x) + // Support Put with []interface{} + if v.Kind() == reflect.Interface { + v = v.Elem() + } + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + if v.Kind() != reflect.Struct { + return nil, false, nil + } + schema, err := inferSchemaReflectCached(v.Type()) + if err != nil { + return nil, false, err + } + return &StructSaver{ + Struct: x, + InsertID: insertID, + Schema: schema, + }, true, nil +} + +func (u *Inserter) putMulti(ctx context.Context, src []ValueSaver) error { + req, err := u.newInsertRequest(src) + if err != nil { + return err + } + if req == nil { + return nil + } + call := u.t.c.bqs.Tabledata.InsertAll(u.t.ProjectID, u.t.DatasetID, u.t.TableID, req) + call = call.Context(ctx) + setClientHeader(call.Header()) + var res *bq.TableDataInsertAllResponse + err = runWithRetry(ctx, func() (err error) { + res, err = call.Do() + return err + }) + if err != nil { + return err + } + return handleInsertErrors(res.InsertErrors, req.Rows) +} + +func (u *Inserter) newInsertRequest(savers []ValueSaver) (*bq.TableDataInsertAllRequest, error) { + if savers == nil { // If there are no rows, do nothing. + return nil, nil + } + req := &bq.TableDataInsertAllRequest{ + TemplateSuffix: u.TableTemplateSuffix, + IgnoreUnknownValues: u.IgnoreUnknownValues, + SkipInvalidRows: u.SkipInvalidRows, + } + for _, saver := range savers { + row, insertID, err := saver.Save() + if err != nil { + return nil, err + } + if insertID == "" { + insertID = randomIDFn() + } + m := make(map[string]bq.JsonValue) + for k, v := range row { + m[k] = bq.JsonValue(v) + } + req.Rows = append(req.Rows, &bq.TableDataInsertAllRequestRows{ + InsertId: insertID, + Json: m, + }) + } + return req, nil +} + +func handleInsertErrors(ierrs []*bq.TableDataInsertAllResponseInsertErrors, rows []*bq.TableDataInsertAllRequestRows) error { + if len(ierrs) == 0 { + return nil + } + var errs PutMultiError + for _, e := range ierrs { + if int(e.Index) > len(rows) { + return fmt.Errorf("internal error: unexpected row index: %v", e.Index) + } + rie := RowInsertionError{ + InsertID: rows[e.Index].InsertId, + RowIndex: int(e.Index), + } + for _, errp := range e.Errors { + rie.Errors = append(rie.Errors, bqToError(errp)) + } + errs = append(errs, rie) + } + return errs +} + +// Uploader is an obsolete name for Inserter. +type Uploader = Inserter diff --git a/vendor/cloud.google.com/go/bigquery/inserter_test.go b/vendor/cloud.google.com/go/bigquery/inserter_test.go new file mode 100644 index 00000000..0fafeac2 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/inserter_test.go @@ -0,0 +1,210 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "errors" + "strconv" + "testing" + + "cloud.google.com/go/internal/pretty" + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" + bq "google.golang.org/api/bigquery/v2" +) + +type testSaver struct { + row map[string]Value + insertID string + err error +} + +func (ts testSaver) Save() (map[string]Value, string, error) { + return ts.row, ts.insertID, ts.err +} + +func TestNewInsertRequest(t *testing.T) { + prev := randomIDFn + n := 0 + randomIDFn = func() string { n++; return strconv.Itoa(n) } + defer func() { randomIDFn = prev }() + + tests := []struct { + ul *Uploader + savers []ValueSaver + req *bq.TableDataInsertAllRequest + }{ + { + ul: &Uploader{}, + savers: nil, + req: nil, + }, + { + ul: &Uploader{}, + savers: []ValueSaver{ + testSaver{row: map[string]Value{"one": 1}}, + testSaver{row: map[string]Value{"two": 2}}, + }, + req: &bq.TableDataInsertAllRequest{ + Rows: []*bq.TableDataInsertAllRequestRows{ + {InsertId: "1", Json: map[string]bq.JsonValue{"one": 1}}, + {InsertId: "2", Json: map[string]bq.JsonValue{"two": 2}}, + }, + }, + }, + { + ul: &Uploader{ + TableTemplateSuffix: "suffix", + IgnoreUnknownValues: true, + SkipInvalidRows: true, + }, + savers: []ValueSaver{ + testSaver{insertID: "a", row: map[string]Value{"one": 1}}, + testSaver{insertID: "", row: map[string]Value{"two": 2}}, + }, + req: &bq.TableDataInsertAllRequest{ + Rows: []*bq.TableDataInsertAllRequestRows{ + {InsertId: "a", Json: map[string]bq.JsonValue{"one": 1}}, + {InsertId: "3", Json: map[string]bq.JsonValue{"two": 2}}, + }, + TemplateSuffix: "suffix", + SkipInvalidRows: true, + IgnoreUnknownValues: true, + }, + }, + } + for i, tc := range tests { + got, err := tc.ul.newInsertRequest(tc.savers) + if err != nil { + t.Fatal(err) + } + want := tc.req + if !testutil.Equal(got, want) { + t.Errorf("%d: %#v: got %#v, want %#v", i, tc.ul, got, want) + } + } +} + +func TestNewInsertRequestErrors(t *testing.T) { + var u Uploader + _, err := u.newInsertRequest([]ValueSaver{testSaver{err: errors.New("bang")}}) + if err == nil { + t.Error("got nil, want error") + } +} + +func TestHandleInsertErrors(t *testing.T) { + rows := []*bq.TableDataInsertAllRequestRows{ + {InsertId: "a"}, + {InsertId: "b"}, + } + for _, test := range []struct { + in []*bq.TableDataInsertAllResponseInsertErrors + want error + }{ + { + in: nil, + want: nil, + }, + { + in: []*bq.TableDataInsertAllResponseInsertErrors{{Index: 1}}, + want: PutMultiError{RowInsertionError{InsertID: "b", RowIndex: 1}}, + }, + { + in: []*bq.TableDataInsertAllResponseInsertErrors{{Index: 1}}, + want: PutMultiError{RowInsertionError{InsertID: "b", RowIndex: 1}}, + }, + { + in: []*bq.TableDataInsertAllResponseInsertErrors{ + {Errors: []*bq.ErrorProto{{Message: "m0"}}, Index: 0}, + {Errors: []*bq.ErrorProto{{Message: "m1"}}, Index: 1}, + }, + want: PutMultiError{ + RowInsertionError{InsertID: "a", RowIndex: 0, Errors: []error{&Error{Message: "m0"}}}, + RowInsertionError{InsertID: "b", RowIndex: 1, Errors: []error{&Error{Message: "m1"}}}, + }, + }, + } { + got := handleInsertErrors(test.in, rows) + if !testutil.Equal(got, test.want) { + t.Errorf("%#v:\ngot\n%#v\nwant\n%#v", test.in, got, test.want) + } + } +} + +func TestValueSavers(t *testing.T) { + ts := &testSaver{} + type T struct{ I int } + schema, err := InferSchema(T{}) + if err != nil { + t.Fatal(err) + } + for _, test := range []struct { + in interface{} + want []ValueSaver + }{ + {[]interface{}(nil), nil}, + {[]interface{}{}, nil}, + {ts, []ValueSaver{ts}}, + {T{I: 1}, []ValueSaver{&StructSaver{Schema: schema, Struct: T{I: 1}}}}, + {[]ValueSaver{ts, ts}, []ValueSaver{ts, ts}}, + {[]interface{}{ts, ts}, []ValueSaver{ts, ts}}, + {[]T{{I: 1}, {I: 2}}, []ValueSaver{ + &StructSaver{Schema: schema, Struct: T{I: 1}}, + &StructSaver{Schema: schema, Struct: T{I: 2}}, + }}, + {[]interface{}{T{I: 1}, &T{I: 2}}, []ValueSaver{ + &StructSaver{Schema: schema, Struct: T{I: 1}}, + &StructSaver{Schema: schema, Struct: &T{I: 2}}, + }}, + {&StructSaver{Struct: T{I: 3}, InsertID: "foo"}, + []ValueSaver{ + &StructSaver{Schema: schema, Struct: T{I: 3}, InsertID: "foo"}, + }}, + } { + got, err := valueSavers(test.in) + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(got, test.want, cmp.AllowUnexported(testSaver{})) { + t.Errorf("%+v: got %v, want %v", test.in, pretty.Value(got), pretty.Value(test.want)) + } + // Make sure Save is successful. + for i, vs := range got { + _, _, err := vs.Save() + if err != nil { + t.Fatalf("%+v, #%d: got error %v, want nil", test.in, i, err) + } + } + } +} + +func TestValueSaversErrors(t *testing.T) { + inputs := []interface{}{ + nil, + 1, + []int{1, 2}, + []interface{}{ + testSaver{row: map[string]Value{"one": 1}, insertID: "a"}, + 1, + }, + StructSaver{}, + } + for _, in := range inputs { + if _, err := valueSavers(in); err == nil { + t.Errorf("%#v: got nil, want error", in) + } + } +} diff --git a/vendor/cloud.google.com/go/bigquery/integration_test.go b/vendor/cloud.google.com/go/bigquery/integration_test.go new file mode 100644 index 00000000..84ce2881 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/integration_test.go @@ -0,0 +1,2141 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "context" + "encoding/json" + "errors" + "flag" + "fmt" + "log" + "math/big" + "net/http" + "os" + "sort" + "strings" + "testing" + "time" + + "cloud.google.com/go/civil" + "cloud.google.com/go/httpreplay" + "cloud.google.com/go/internal" + "cloud.google.com/go/internal/pretty" + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/internal/uid" + "cloud.google.com/go/storage" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/googleapi" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +const replayFilename = "bigquery.replay" + +var record = flag.Bool("record", false, "record RPCs") + +var ( + client *Client + storageClient *storage.Client + dataset *Dataset + schema = Schema{ + {Name: "name", Type: StringFieldType}, + {Name: "nums", Type: IntegerFieldType, Repeated: true}, + {Name: "rec", Type: RecordFieldType, Schema: Schema{ + {Name: "bool", Type: BooleanFieldType}, + }}, + } + testTableExpiration time.Time + datasetIDs, tableIDs *uid.Space +) + +// Note: integration tests cannot be run in parallel, because TestIntegration_Location +// modifies the client. + +func TestMain(m *testing.M) { + cleanup := initIntegrationTest() + r := m.Run() + cleanup() + os.Exit(r) +} + +func getClient(t *testing.T) *Client { + if client == nil { + t.Skip("Integration tests skipped") + } + return client +} + +// If integration tests will be run, create a unique dataset for them. +// Return a cleanup function. +func initIntegrationTest() func() { + ctx := context.Background() + flag.Parse() // needed for testing.Short() + projID := testutil.ProjID() + switch { + case testing.Short() && *record: + log.Fatal("cannot combine -short and -record") + return func() {} + + case testing.Short() && httpreplay.Supported() && testutil.CanReplay(replayFilename) && projID != "": + // go test -short with a replay file will replay the integration tests if the + // environment variables are set. + log.Printf("replaying from %s", replayFilename) + httpreplay.DebugHeaders() + replayer, err := httpreplay.NewReplayer(replayFilename) + if err != nil { + log.Fatal(err) + } + var t time.Time + if err := json.Unmarshal(replayer.Initial(), &t); err != nil { + log.Fatal(err) + } + hc, err := replayer.Client(ctx) // no creds needed + if err != nil { + log.Fatal(err) + } + client, err = NewClient(ctx, projID, option.WithHTTPClient(hc)) + if err != nil { + log.Fatal(err) + } + storageClient, err = storage.NewClient(ctx, option.WithHTTPClient(hc)) + if err != nil { + log.Fatal(err) + } + cleanup := initTestState(client, t) + return func() { + cleanup() + _ = replayer.Close() // No actionable error returned. + } + + case testing.Short(): + // go test -short without a replay file skips the integration tests. + if testutil.CanReplay(replayFilename) && projID != "" { + log.Print("replay not supported for Go versions before 1.8") + } + client = nil + storageClient = nil + return func() {} + + default: // Run integration tests against a real backend. + ts := testutil.TokenSource(ctx, Scope) + if ts == nil { + log.Println("Integration tests skipped. See CONTRIBUTING.md for details") + return func() {} + } + bqOpt := option.WithTokenSource(ts) + sOpt := option.WithTokenSource(testutil.TokenSource(ctx, storage.ScopeFullControl)) + cleanup := func() {} + now := time.Now().UTC() + if *record { + if !httpreplay.Supported() { + log.Print("record not supported for Go versions before 1.8") + } else { + nowBytes, err := json.Marshal(now) + if err != nil { + log.Fatal(err) + } + recorder, err := httpreplay.NewRecorder(replayFilename, nowBytes) + if err != nil { + log.Fatalf("could not record: %v", err) + } + log.Printf("recording to %s", replayFilename) + hc, err := recorder.Client(ctx, bqOpt) + if err != nil { + log.Fatal(err) + } + bqOpt = option.WithHTTPClient(hc) + hc, err = recorder.Client(ctx, sOpt) + if err != nil { + log.Fatal(err) + } + sOpt = option.WithHTTPClient(hc) + cleanup = func() { + if err := recorder.Close(); err != nil { + log.Printf("saving recording: %v", err) + } + } + } + } + var err error + client, err = NewClient(ctx, projID, bqOpt) + if err != nil { + log.Fatalf("NewClient: %v", err) + } + storageClient, err = storage.NewClient(ctx, sOpt) + if err != nil { + log.Fatalf("storage.NewClient: %v", err) + } + c := initTestState(client, now) + return func() { c(); cleanup() } + } +} + +func initTestState(client *Client, t time.Time) func() { + // BigQuery does not accept hyphens in dataset or table IDs, so we create IDs + // with underscores. + ctx := context.Background() + opts := &uid.Options{Sep: '_', Time: t} + datasetIDs = uid.NewSpace("dataset", opts) + tableIDs = uid.NewSpace("table", opts) + testTableExpiration = t.Add(10 * time.Minute).Round(time.Second) + // For replayability, seed the random source with t. + Seed(t.UnixNano()) + + dataset = client.Dataset(datasetIDs.New()) + if err := dataset.Create(ctx, nil); err != nil { + log.Fatalf("creating dataset %s: %v", dataset.DatasetID, err) + } + return func() { + if err := dataset.DeleteWithContents(ctx); err != nil { + log.Printf("could not delete %s", dataset.DatasetID) + } + } +} + +func TestIntegration_TableCreate(t *testing.T) { + // Check that creating a record field with an empty schema is an error. + if client == nil { + t.Skip("Integration tests skipped") + } + table := dataset.Table("t_bad") + schema := Schema{ + {Name: "rec", Type: RecordFieldType, Schema: Schema{}}, + } + err := table.Create(context.Background(), &TableMetadata{ + Schema: schema, + ExpirationTime: testTableExpiration.Add(5 * time.Minute), + }) + if err == nil { + t.Fatal("want error, got nil") + } + if !hasStatusCode(err, http.StatusBadRequest) { + t.Fatalf("want a 400 error, got %v", err) + } +} + +func TestIntegration_TableCreateView(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + table := newTable(t, schema) + defer table.Delete(ctx) + + // Test that standard SQL views work. + view := dataset.Table("t_view_standardsql") + query := fmt.Sprintf("SELECT APPROX_COUNT_DISTINCT(name) FROM `%s.%s.%s`", + dataset.ProjectID, dataset.DatasetID, table.TableID) + err := view.Create(context.Background(), &TableMetadata{ + ViewQuery: query, + UseStandardSQL: true, + }) + if err != nil { + t.Fatalf("table.create: Did not expect an error, got: %v", err) + } + if err := view.Delete(ctx); err != nil { + t.Fatal(err) + } +} + +func TestIntegration_TableMetadata(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + table := newTable(t, schema) + defer table.Delete(ctx) + // Check table metadata. + md, err := table.Metadata(ctx) + if err != nil { + t.Fatal(err) + } + // TODO(jba): check md more thorougly. + if got, want := md.FullID, fmt.Sprintf("%s:%s.%s", dataset.ProjectID, dataset.DatasetID, table.TableID); got != want { + t.Errorf("metadata.FullID: got %q, want %q", got, want) + } + if got, want := md.Type, RegularTable; got != want { + t.Errorf("metadata.Type: got %v, want %v", got, want) + } + if got, want := md.ExpirationTime, testTableExpiration; !got.Equal(want) { + t.Errorf("metadata.Type: got %v, want %v", got, want) + } + + // Check that timePartitioning is nil by default + if md.TimePartitioning != nil { + t.Errorf("metadata.TimePartitioning: got %v, want %v", md.TimePartitioning, nil) + } + + // Create tables that have time partitioning + partitionCases := []struct { + timePartitioning TimePartitioning + wantExpiration time.Duration + wantField string + wantPruneFilter bool + }{ + {TimePartitioning{}, time.Duration(0), "", false}, + {TimePartitioning{Expiration: time.Second}, time.Second, "", false}, + {TimePartitioning{RequirePartitionFilter: true}, time.Duration(0), "", true}, + { + TimePartitioning{ + Expiration: time.Second, + Field: "date", + RequirePartitionFilter: true, + }, time.Second, "date", true}, + } + + schema2 := Schema{ + {Name: "name", Type: StringFieldType}, + {Name: "date", Type: DateFieldType}, + } + + clustering := &Clustering{ + Fields: []string{"name"}, + } + + // Currently, clustering depends on partitioning. Interleave testing of the two features. + for i, c := range partitionCases { + table := dataset.Table(fmt.Sprintf("t_metadata_partition_nocluster_%v", i)) + clusterTable := dataset.Table(fmt.Sprintf("t_metadata_partition_cluster_%v", i)) + + // Create unclustered, partitioned variant and get metadata. + err = table.Create(context.Background(), &TableMetadata{ + Schema: schema2, + TimePartitioning: &c.timePartitioning, + ExpirationTime: testTableExpiration, + }) + if err != nil { + t.Fatal(err) + } + defer table.Delete(ctx) + md, err := table.Metadata(ctx) + if err != nil { + t.Fatal(err) + } + + // Created clustered table and get metadata. + err = clusterTable.Create(context.Background(), &TableMetadata{ + Schema: schema2, + TimePartitioning: &c.timePartitioning, + ExpirationTime: testTableExpiration, + Clustering: clustering, + }) + if err != nil { + t.Fatal(err) + } + clusterMD, err := clusterTable.Metadata(ctx) + if err != nil { + t.Fatal(err) + } + + for _, v := range []*TableMetadata{md, clusterMD} { + got := v.TimePartitioning + want := &TimePartitioning{ + Expiration: c.wantExpiration, + Field: c.wantField, + RequirePartitionFilter: c.wantPruneFilter, + } + if !testutil.Equal(got, want) { + t.Errorf("metadata.TimePartitioning: got %v, want %v", got, want) + } + // check that RequirePartitionFilter can be inverted. + mdUpdate := TableMetadataToUpdate{ + TimePartitioning: &TimePartitioning{ + Expiration: v.TimePartitioning.Expiration, + RequirePartitionFilter: !want.RequirePartitionFilter, + }, + } + + newmd, err := table.Update(ctx, mdUpdate, "") + if err != nil { + t.Errorf("failed to invert RequirePartitionFilter on %s: %v", table.FullyQualifiedName(), err) + } + if newmd.TimePartitioning.RequirePartitionFilter == want.RequirePartitionFilter { + t.Errorf("inverting RequirePartitionFilter on %s failed, want %t got %t", table.FullyQualifiedName(), !want.RequirePartitionFilter, newmd.TimePartitioning.RequirePartitionFilter) + } + + } + + if md.Clustering != nil { + t.Errorf("metadata.Clustering was not nil on unclustered table %s", table.TableID) + } + got := clusterMD.Clustering + want := clustering + if clusterMD.Clustering != clustering { + if !testutil.Equal(got, want) { + t.Errorf("metadata.Clustering: got %v, want %v", got, want) + } + } + } + +} + +func TestIntegration_DatasetCreate(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + ds := client.Dataset(datasetIDs.New()) + wmd := &DatasetMetadata{Name: "name", Location: "EU"} + err := ds.Create(ctx, wmd) + if err != nil { + t.Fatal(err) + } + gmd, err := ds.Metadata(ctx) + if err != nil { + t.Fatal(err) + } + if got, want := gmd.Name, wmd.Name; got != want { + t.Errorf("name: got %q, want %q", got, want) + } + if got, want := gmd.Location, wmd.Location; got != want { + t.Errorf("location: got %q, want %q", got, want) + } + if err := ds.Delete(ctx); err != nil { + t.Fatalf("deleting dataset %v: %v", ds, err) + } +} + +func TestIntegration_DatasetMetadata(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + md, err := dataset.Metadata(ctx) + if err != nil { + t.Fatal(err) + } + if got, want := md.FullID, fmt.Sprintf("%s:%s", dataset.ProjectID, dataset.DatasetID); got != want { + t.Errorf("FullID: got %q, want %q", got, want) + } + jan2016 := time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC) + if md.CreationTime.Before(jan2016) { + t.Errorf("CreationTime: got %s, want > 2016-1-1", md.CreationTime) + } + if md.LastModifiedTime.Before(jan2016) { + t.Errorf("LastModifiedTime: got %s, want > 2016-1-1", md.LastModifiedTime) + } + + // Verify that we get a NotFound for a nonexistent dataset. + _, err = client.Dataset("does_not_exist").Metadata(ctx) + if err == nil || !hasStatusCode(err, http.StatusNotFound) { + t.Errorf("got %v, want NotFound error", err) + } +} + +func TestIntegration_DatasetDelete(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + ds := client.Dataset(datasetIDs.New()) + if err := ds.Create(ctx, nil); err != nil { + t.Fatalf("creating dataset %s: %v", ds.DatasetID, err) + } + if err := ds.Delete(ctx); err != nil { + t.Fatalf("deleting dataset %s: %v", ds.DatasetID, err) + } +} + +func TestIntegration_DatasetDeleteWithContents(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + ds := client.Dataset(datasetIDs.New()) + if err := ds.Create(ctx, nil); err != nil { + t.Fatalf("creating dataset %s: %v", ds.DatasetID, err) + } + table := ds.Table(tableIDs.New()) + if err := table.Create(ctx, nil); err != nil { + t.Fatalf("creating table %s in dataset %s: %v", table.TableID, table.DatasetID, err) + } + // We expect failure here + if err := ds.Delete(ctx); err == nil { + t.Fatalf("non-recursive delete of dataset %s succeeded unexpectedly.", ds.DatasetID) + } + if err := ds.DeleteWithContents(ctx); err != nil { + t.Fatalf("deleting recursively dataset %s: %v", ds.DatasetID, err) + } +} + +func TestIntegration_DatasetUpdateETags(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + + check := func(md *DatasetMetadata, wantDesc, wantName string) { + if md.Description != wantDesc { + t.Errorf("description: got %q, want %q", md.Description, wantDesc) + } + if md.Name != wantName { + t.Errorf("name: got %q, want %q", md.Name, wantName) + } + } + + ctx := context.Background() + md, err := dataset.Metadata(ctx) + if err != nil { + t.Fatal(err) + } + if md.ETag == "" { + t.Fatal("empty ETag") + } + // Write without ETag succeeds. + desc := md.Description + "d2" + name := md.Name + "n2" + md2, err := dataset.Update(ctx, DatasetMetadataToUpdate{Description: desc, Name: name}, "") + if err != nil { + t.Fatal(err) + } + check(md2, desc, name) + + // Write with original ETag fails because of intervening write. + _, err = dataset.Update(ctx, DatasetMetadataToUpdate{Description: "d", Name: "n"}, md.ETag) + if err == nil { + t.Fatal("got nil, want error") + } + + // Write with most recent ETag succeeds. + md3, err := dataset.Update(ctx, DatasetMetadataToUpdate{Description: "", Name: ""}, md2.ETag) + if err != nil { + t.Fatal(err) + } + check(md3, "", "") +} + +func TestIntegration_DatasetUpdateDefaultExpiration(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + _, err := dataset.Metadata(ctx) + if err != nil { + t.Fatal(err) + } + // Set the default expiration time. + md, err := dataset.Update(ctx, DatasetMetadataToUpdate{DefaultTableExpiration: time.Hour}, "") + if err != nil { + t.Fatal(err) + } + if md.DefaultTableExpiration != time.Hour { + t.Fatalf("got %s, want 1h", md.DefaultTableExpiration) + } + // Omitting DefaultTableExpiration doesn't change it. + md, err = dataset.Update(ctx, DatasetMetadataToUpdate{Name: "xyz"}, "") + if err != nil { + t.Fatal(err) + } + if md.DefaultTableExpiration != time.Hour { + t.Fatalf("got %s, want 1h", md.DefaultTableExpiration) + } + // Setting it to 0 deletes it (which looks like a 0 duration). + md, err = dataset.Update(ctx, DatasetMetadataToUpdate{DefaultTableExpiration: time.Duration(0)}, "") + if err != nil { + t.Fatal(err) + } + if md.DefaultTableExpiration != 0 { + t.Fatalf("got %s, want 0", md.DefaultTableExpiration) + } +} + +func TestIntegration_DatasetUpdateAccess(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + md, err := dataset.Metadata(ctx) + if err != nil { + t.Fatal(err) + } + origAccess := append([]*AccessEntry(nil), md.Access...) + newEntry := &AccessEntry{ + Role: ReaderRole, + Entity: "Joe@example.com", + EntityType: UserEmailEntity, + } + newAccess := append(md.Access, newEntry) + dm := DatasetMetadataToUpdate{Access: newAccess} + md, err = dataset.Update(ctx, dm, md.ETag) + if err != nil { + t.Fatal(err) + } + defer func() { + _, err := dataset.Update(ctx, DatasetMetadataToUpdate{Access: origAccess}, md.ETag) + if err != nil { + t.Log("could not restore dataset access list") + } + }() + if diff := testutil.Diff(md.Access, newAccess); diff != "" { + t.Fatalf("got=-, want=+:\n%s", diff) + } +} + +func TestIntegration_DatasetUpdateLabels(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + _, err := dataset.Metadata(ctx) + if err != nil { + t.Fatal(err) + } + var dm DatasetMetadataToUpdate + dm.SetLabel("label", "value") + md, err := dataset.Update(ctx, dm, "") + if err != nil { + t.Fatal(err) + } + if got, want := md.Labels["label"], "value"; got != want { + t.Errorf("got %q, want %q", got, want) + } + dm = DatasetMetadataToUpdate{} + dm.DeleteLabel("label") + md, err = dataset.Update(ctx, dm, "") + if err != nil { + t.Fatal(err) + } + if _, ok := md.Labels["label"]; ok { + t.Error("label still present after deletion") + } +} + +func TestIntegration_TableUpdateLabels(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + table := newTable(t, schema) + defer table.Delete(ctx) + + var tm TableMetadataToUpdate + tm.SetLabel("label", "value") + md, err := table.Update(ctx, tm, "") + if err != nil { + t.Fatal(err) + } + if got, want := md.Labels["label"], "value"; got != want { + t.Errorf("got %q, want %q", got, want) + } + tm = TableMetadataToUpdate{} + tm.DeleteLabel("label") + md, err = table.Update(ctx, tm, "") + if err != nil { + t.Fatal(err) + } + if _, ok := md.Labels["label"]; ok { + t.Error("label still present after deletion") + } +} + +func TestIntegration_Tables(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + table := newTable(t, schema) + defer table.Delete(ctx) + wantName := table.FullyQualifiedName() + + // This test is flaky due to eventual consistency. + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + err := internal.Retry(ctx, gax.Backoff{}, func() (stop bool, err error) { + // Iterate over tables in the dataset. + it := dataset.Tables(ctx) + var tableNames []string + for { + tbl, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + return false, err + } + tableNames = append(tableNames, tbl.FullyQualifiedName()) + } + // Other tests may be running with this dataset, so there might be more + // than just our table in the list. So don't try for an exact match; just + // make sure that our table is there somewhere. + for _, tn := range tableNames { + if tn == wantName { + return true, nil + } + } + return false, fmt.Errorf("got %v\nwant %s in the list", tableNames, wantName) + }) + if err != nil { + t.Fatal(err) + } +} + +func TestIntegration_InsertAndRead(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + table := newTable(t, schema) + defer table.Delete(ctx) + + // Populate the table. + ins := table.Inserter() + var ( + wantRows [][]Value + saverRows []*ValuesSaver + ) + for i, name := range []string{"a", "b", "c"} { + row := []Value{name, []Value{int64(i)}, []Value{true}} + wantRows = append(wantRows, row) + saverRows = append(saverRows, &ValuesSaver{ + Schema: schema, + InsertID: name, + Row: row, + }) + } + if err := ins.Put(ctx, saverRows); err != nil { + t.Fatal(putError(err)) + } + + // Wait until the data has been uploaded. This can take a few seconds, according + // to https://cloud.google.com/bigquery/streaming-data-into-bigquery. + if err := waitForRow(ctx, table); err != nil { + t.Fatal(err) + } + // Read the table. + checkRead(t, "upload", table.Read(ctx), wantRows) + + // Query the table. + q := client.Query(fmt.Sprintf("select name, nums, rec from %s", table.TableID)) + q.DefaultProjectID = dataset.ProjectID + q.DefaultDatasetID = dataset.DatasetID + + rit, err := q.Read(ctx) + if err != nil { + t.Fatal(err) + } + checkRead(t, "query", rit, wantRows) + + // Query the long way. + job1, err := q.Run(ctx) + if err != nil { + t.Fatal(err) + } + if job1.LastStatus() == nil { + t.Error("no LastStatus") + } + job2, err := client.JobFromID(ctx, job1.ID()) + if err != nil { + t.Fatal(err) + } + if job2.LastStatus() == nil { + t.Error("no LastStatus") + } + rit, err = job2.Read(ctx) + if err != nil { + t.Fatal(err) + } + checkRead(t, "job.Read", rit, wantRows) + + // Get statistics. + jobStatus, err := job2.Status(ctx) + if err != nil { + t.Fatal(err) + } + if jobStatus.Statistics == nil { + t.Fatal("jobStatus missing statistics") + } + if _, ok := jobStatus.Statistics.Details.(*QueryStatistics); !ok { + t.Errorf("expected QueryStatistics, got %T", jobStatus.Statistics.Details) + } + + // Test reading directly into a []Value. + valueLists, schema, _, err := readAll(table.Read(ctx)) + if err != nil { + t.Fatal(err) + } + it := table.Read(ctx) + for i, vl := range valueLists { + var got []Value + if err := it.Next(&got); err != nil { + t.Fatal(err) + } + if !testutil.Equal(it.Schema, schema) { + t.Fatalf("got schema %v, want %v", it.Schema, schema) + } + want := []Value(vl) + if !testutil.Equal(got, want) { + t.Errorf("%d: got %v, want %v", i, got, want) + } + } + + // Test reading into a map. + it = table.Read(ctx) + for _, vl := range valueLists { + var vm map[string]Value + if err := it.Next(&vm); err != nil { + t.Fatal(err) + } + if got, want := len(vm), len(vl); got != want { + t.Fatalf("valueMap len: got %d, want %d", got, want) + } + // With maps, structs become nested maps. + vl[2] = map[string]Value{"bool": vl[2].([]Value)[0]} + for i, v := range vl { + if got, want := vm[schema[i].Name], v; !testutil.Equal(got, want) { + t.Errorf("%d, name=%s: got %#v, want %#v", + i, schema[i].Name, got, want) + } + } + } + +} + +type SubSubTestStruct struct { + Integer int64 +} + +type SubTestStruct struct { + String string + Record SubSubTestStruct + RecordArray []SubSubTestStruct +} + +type TestStruct struct { + Name string + Bytes []byte + Integer int64 + Float float64 + Boolean bool + Timestamp time.Time + Date civil.Date + Time civil.Time + DateTime civil.DateTime + Numeric *big.Rat + + StringArray []string + IntegerArray []int64 + FloatArray []float64 + BooleanArray []bool + TimestampArray []time.Time + DateArray []civil.Date + TimeArray []civil.Time + DateTimeArray []civil.DateTime + NumericArray []*big.Rat + + Record SubTestStruct + RecordArray []SubTestStruct +} + +// Round times to the microsecond for comparison purposes. +var roundToMicros = cmp.Transformer("RoundToMicros", + func(t time.Time) time.Time { return t.Round(time.Microsecond) }) + +func TestIntegration_InsertAndReadStructs(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + schema, err := InferSchema(TestStruct{}) + if err != nil { + t.Fatal(err) + } + + ctx := context.Background() + table := newTable(t, schema) + defer table.Delete(ctx) + + d := civil.Date{Year: 2016, Month: 3, Day: 20} + tm := civil.Time{Hour: 15, Minute: 4, Second: 5, Nanosecond: 6000} + ts := time.Date(2016, 3, 20, 15, 4, 5, 6000, time.UTC) + dtm := civil.DateTime{Date: d, Time: tm} + d2 := civil.Date{Year: 1994, Month: 5, Day: 15} + tm2 := civil.Time{Hour: 1, Minute: 2, Second: 4, Nanosecond: 0} + ts2 := time.Date(1994, 5, 15, 1, 2, 4, 0, time.UTC) + dtm2 := civil.DateTime{Date: d2, Time: tm2} + + // Populate the table. + ins := table.Inserter() + want := []*TestStruct{ + { + "a", + []byte("byte"), + 42, + 3.14, + true, + ts, + d, + tm, + dtm, + big.NewRat(57, 100), + []string{"a", "b"}, + []int64{1, 2}, + []float64{1, 1.41}, + []bool{true, false}, + []time.Time{ts, ts2}, + []civil.Date{d, d2}, + []civil.Time{tm, tm2}, + []civil.DateTime{dtm, dtm2}, + []*big.Rat{big.NewRat(1, 2), big.NewRat(3, 5)}, + SubTestStruct{ + "string", + SubSubTestStruct{24}, + []SubSubTestStruct{{1}, {2}}, + }, + []SubTestStruct{ + {String: "empty"}, + { + "full", + SubSubTestStruct{1}, + []SubSubTestStruct{{1}, {2}}, + }, + }, + }, + { + Name: "b", + Bytes: []byte("byte2"), + Integer: 24, + Float: 4.13, + Boolean: false, + Timestamp: ts, + Date: d, + Time: tm, + DateTime: dtm, + Numeric: big.NewRat(4499, 10000), + }, + } + var savers []*StructSaver + for _, s := range want { + savers = append(savers, &StructSaver{Schema: schema, Struct: s}) + } + if err := ins.Put(ctx, savers); err != nil { + t.Fatal(putError(err)) + } + + // Wait until the data has been uploaded. This can take a few seconds, according + // to https://cloud.google.com/bigquery/streaming-data-into-bigquery. + if err := waitForRow(ctx, table); err != nil { + t.Fatal(err) + } + + // Test iteration with structs. + it := table.Read(ctx) + var got []*TestStruct + for { + var g TestStruct + err := it.Next(&g) + if err == iterator.Done { + break + } + if err != nil { + t.Fatal(err) + } + got = append(got, &g) + } + sort.Sort(byName(got)) + + // BigQuery does not elide nils. It reports an error for nil fields. + for i, g := range got { + if i >= len(want) { + t.Errorf("%d: got %v, past end of want", i, pretty.Value(g)) + } else if diff := testutil.Diff(g, want[i], roundToMicros); diff != "" { + t.Errorf("%d: got=-, want=+:\n%s", i, diff) + } + } +} + +type byName []*TestStruct + +func (b byName) Len() int { return len(b) } +func (b byName) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byName) Less(i, j int) bool { return b[i].Name < b[j].Name } + +func TestIntegration_InsertAndReadNullable(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctm := civil.Time{Hour: 15, Minute: 4, Second: 5, Nanosecond: 6000} + cdt := civil.DateTime{Date: testDate, Time: ctm} + rat := big.NewRat(33, 100) + testInsertAndReadNullable(t, testStructNullable{}, make([]Value, len(testStructNullableSchema))) + testInsertAndReadNullable(t, testStructNullable{ + String: NullString{"x", true}, + Bytes: []byte{1, 2, 3}, + Integer: NullInt64{1, true}, + Float: NullFloat64{2.3, true}, + Boolean: NullBool{true, true}, + Timestamp: NullTimestamp{testTimestamp, true}, + Date: NullDate{testDate, true}, + Time: NullTime{ctm, true}, + DateTime: NullDateTime{cdt, true}, + Numeric: rat, + Record: &subNullable{X: NullInt64{4, true}}, + }, + []Value{"x", []byte{1, 2, 3}, int64(1), 2.3, true, testTimestamp, testDate, ctm, cdt, rat, []Value{int64(4)}}) +} + +func testInsertAndReadNullable(t *testing.T, ts testStructNullable, wantRow []Value) { + ctx := context.Background() + table := newTable(t, testStructNullableSchema) + defer table.Delete(ctx) + + // Populate the table. + ins := table.Inserter() + if err := ins.Put(ctx, []*StructSaver{{Schema: testStructNullableSchema, Struct: ts}}); err != nil { + t.Fatal(putError(err)) + } + // Wait until the data has been uploaded. This can take a few seconds, according + // to https://cloud.google.com/bigquery/streaming-data-into-bigquery. + if err := waitForRow(ctx, table); err != nil { + t.Fatal(err) + } + + // Read into a []Value. + iter := table.Read(ctx) + gotRows, _, _, err := readAll(iter) + if err != nil { + t.Fatal(err) + } + if len(gotRows) != 1 { + t.Fatalf("got %d rows, want 1", len(gotRows)) + } + if diff := testutil.Diff(gotRows[0], wantRow, roundToMicros); diff != "" { + t.Error(diff) + } + + // Read into a struct. + want := ts + var sn testStructNullable + it := table.Read(ctx) + if err := it.Next(&sn); err != nil { + t.Fatal(err) + } + if diff := testutil.Diff(sn, want, roundToMicros); diff != "" { + t.Error(diff) + } +} + +func TestIntegration_TableUpdate(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + table := newTable(t, schema) + defer table.Delete(ctx) + + // Test Update of non-schema fields. + tm, err := table.Metadata(ctx) + if err != nil { + t.Fatal(err) + } + wantDescription := tm.Description + "more" + wantName := tm.Name + "more" + wantExpiration := tm.ExpirationTime.Add(time.Hour * 24) + got, err := table.Update(ctx, TableMetadataToUpdate{ + Description: wantDescription, + Name: wantName, + ExpirationTime: wantExpiration, + }, tm.ETag) + if err != nil { + t.Fatal(err) + } + if got.Description != wantDescription { + t.Errorf("Description: got %q, want %q", got.Description, wantDescription) + } + if got.Name != wantName { + t.Errorf("Name: got %q, want %q", got.Name, wantName) + } + if got.ExpirationTime != wantExpiration { + t.Errorf("ExpirationTime: got %q, want %q", got.ExpirationTime, wantExpiration) + } + if !testutil.Equal(got.Schema, schema) { + t.Errorf("Schema: got %v, want %v", pretty.Value(got.Schema), pretty.Value(schema)) + } + + // Blind write succeeds. + _, err = table.Update(ctx, TableMetadataToUpdate{Name: "x"}, "") + if err != nil { + t.Fatal(err) + } + // Write with old etag fails. + _, err = table.Update(ctx, TableMetadataToUpdate{Name: "y"}, got.ETag) + if err == nil { + t.Fatal("Update with old ETag succeeded, wanted failure") + } + + // Test schema update. + // Columns can be added. schema2 is the same as schema, except for the + // added column in the middle. + nested := Schema{ + {Name: "nested", Type: BooleanFieldType}, + {Name: "other", Type: StringFieldType}, + } + schema2 := Schema{ + schema[0], + {Name: "rec2", Type: RecordFieldType, Schema: nested}, + schema[1], + schema[2], + } + + got, err = table.Update(ctx, TableMetadataToUpdate{Schema: schema2}, "") + if err != nil { + t.Fatal(err) + } + + // Wherever you add the column, it appears at the end. + schema3 := Schema{schema2[0], schema2[2], schema2[3], schema2[1]} + if !testutil.Equal(got.Schema, schema3) { + t.Errorf("add field:\ngot %v\nwant %v", + pretty.Value(got.Schema), pretty.Value(schema3)) + } + + // Updating with the empty schema succeeds, but is a no-op. + got, err = table.Update(ctx, TableMetadataToUpdate{Schema: Schema{}}, "") + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(got.Schema, schema3) { + t.Errorf("empty schema:\ngot %v\nwant %v", + pretty.Value(got.Schema), pretty.Value(schema3)) + } + + // Error cases when updating schema. + for _, test := range []struct { + desc string + fields Schema + }{ + {"change from optional to required", Schema{ + {Name: "name", Type: StringFieldType, Required: true}, + schema3[1], + schema3[2], + schema3[3], + }}, + {"add a required field", Schema{ + schema3[0], schema3[1], schema3[2], schema3[3], + {Name: "req", Type: StringFieldType, Required: true}, + }}, + {"remove a field", Schema{schema3[0], schema3[1], schema3[2]}}, + {"remove a nested field", Schema{ + schema3[0], schema3[1], schema3[2], + {Name: "rec2", Type: RecordFieldType, Schema: Schema{nested[0]}}}}, + {"remove all nested fields", Schema{ + schema3[0], schema3[1], schema3[2], + {Name: "rec2", Type: RecordFieldType, Schema: Schema{}}}}, + } { + _, err = table.Update(ctx, TableMetadataToUpdate{Schema: Schema(test.fields)}, "") + if err == nil { + t.Errorf("%s: want error, got nil", test.desc) + } else if !hasStatusCode(err, 400) { + t.Errorf("%s: want 400, got %v", test.desc, err) + } + } +} + +func TestIntegration_Load(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + // CSV data can't be loaded into a repeated field, so we use a different schema. + table := newTable(t, Schema{ + {Name: "name", Type: StringFieldType}, + {Name: "nums", Type: IntegerFieldType}, + }) + defer table.Delete(ctx) + + // Load the table from a reader. + r := strings.NewReader("a,0\nb,1\nc,2\n") + wantRows := [][]Value{ + {"a", int64(0)}, + {"b", int64(1)}, + {"c", int64(2)}, + } + rs := NewReaderSource(r) + loader := table.LoaderFrom(rs) + loader.WriteDisposition = WriteTruncate + loader.Labels = map[string]string{"test": "go"} + job, err := loader.Run(ctx) + if err != nil { + t.Fatal(err) + } + if job.LastStatus() == nil { + t.Error("no LastStatus") + } + conf, err := job.Config() + if err != nil { + t.Fatal(err) + } + config, ok := conf.(*LoadConfig) + if !ok { + t.Fatalf("got %T, want LoadConfig", conf) + } + diff := testutil.Diff(config, &loader.LoadConfig, + cmp.AllowUnexported(Table{}), + cmpopts.IgnoreUnexported(Client{}, ReaderSource{}), + // returned schema is at top level, not in the config + cmpopts.IgnoreFields(FileConfig{}, "Schema")) + if diff != "" { + t.Errorf("got=-, want=+:\n%s", diff) + } + if err := wait(ctx, job); err != nil { + t.Fatal(err) + } + checkReadAndTotalRows(t, "reader load", table.Read(ctx), wantRows) + +} + +func TestIntegration_DML(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + table := newTable(t, schema) + defer table.Delete(ctx) + + sql := fmt.Sprintf(`INSERT %s.%s (name, nums, rec) + VALUES ('a', [0], STRUCT(TRUE)), + ('b', [1], STRUCT(FALSE)), + ('c', [2], STRUCT(TRUE))`, + table.DatasetID, table.TableID) + if err := runDML(ctx, sql); err != nil { + t.Fatal(err) + } + wantRows := [][]Value{ + {"a", []Value{int64(0)}, []Value{true}}, + {"b", []Value{int64(1)}, []Value{false}}, + {"c", []Value{int64(2)}, []Value{true}}, + } + checkRead(t, "DML", table.Read(ctx), wantRows) +} + +func runDML(ctx context.Context, sql string) error { + // Retry insert; sometimes it fails with INTERNAL. + return internal.Retry(ctx, gax.Backoff{}, func() (stop bool, err error) { + ri, err := client.Query(sql).Read(ctx) + if err != nil { + if e, ok := err.(*googleapi.Error); ok && e.Code < 500 { + return true, err // fail on 4xx + } + return false, err + } + // It is OK to try to iterate over DML results. The first call to Next + // will return iterator.Done. + err = ri.Next(nil) + if err == nil { + return true, errors.New("want iterator.Done on the first call, got nil") + } + if err == iterator.Done { + return true, nil + } + if e, ok := err.(*googleapi.Error); ok && e.Code < 500 { + return true, err // fail on 4xx + } + return false, err + }) +} + +func TestIntegration_TimeTypes(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + dtSchema := Schema{ + {Name: "d", Type: DateFieldType}, + {Name: "t", Type: TimeFieldType}, + {Name: "dt", Type: DateTimeFieldType}, + {Name: "ts", Type: TimestampFieldType}, + } + table := newTable(t, dtSchema) + defer table.Delete(ctx) + + d := civil.Date{Year: 2016, Month: 3, Day: 20} + tm := civil.Time{Hour: 12, Minute: 30, Second: 0, Nanosecond: 6000} + dtm := civil.DateTime{Date: d, Time: tm} + ts := time.Date(2016, 3, 20, 15, 04, 05, 0, time.UTC) + wantRows := [][]Value{ + {d, tm, dtm, ts}, + } + ins := table.Inserter() + if err := ins.Put(ctx, []*ValuesSaver{ + {Schema: dtSchema, Row: wantRows[0]}, + }); err != nil { + t.Fatal(putError(err)) + } + if err := waitForRow(ctx, table); err != nil { + t.Fatal(err) + } + + // SQL wants DATETIMEs with a space between date and time, but the service + // returns them in RFC3339 form, with a "T" between. + query := fmt.Sprintf("INSERT %s.%s (d, t, dt, ts) "+ + "VALUES ('%s', '%s', '%s', '%s')", + table.DatasetID, table.TableID, + d, CivilTimeString(tm), CivilDateTimeString(dtm), ts.Format("2006-01-02 15:04:05")) + if err := runDML(ctx, query); err != nil { + t.Fatal(err) + } + wantRows = append(wantRows, wantRows[0]) + checkRead(t, "TimeTypes", table.Read(ctx), wantRows) +} + +func TestIntegration_StandardQuery(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + + d := civil.Date{Year: 2016, Month: 3, Day: 20} + tm := civil.Time{Hour: 15, Minute: 04, Second: 05, Nanosecond: 0} + ts := time.Date(2016, 3, 20, 15, 04, 05, 0, time.UTC) + dtm := ts.Format("2006-01-02 15:04:05") + + // Constructs Value slices made up of int64s. + ints := func(args ...int) []Value { + vals := make([]Value, len(args)) + for i, arg := range args { + vals[i] = int64(arg) + } + return vals + } + + testCases := []struct { + query string + wantRow []Value + }{ + {"SELECT 1", ints(1)}, + {"SELECT 1.3", []Value{1.3}}, + {"SELECT CAST(1.3 AS NUMERIC)", []Value{big.NewRat(13, 10)}}, + {"SELECT NUMERIC '0.25'", []Value{big.NewRat(1, 4)}}, + {"SELECT TRUE", []Value{true}}, + {"SELECT 'ABC'", []Value{"ABC"}}, + {"SELECT CAST('foo' AS BYTES)", []Value{[]byte("foo")}}, + {fmt.Sprintf("SELECT TIMESTAMP '%s'", dtm), []Value{ts}}, + {fmt.Sprintf("SELECT [TIMESTAMP '%s', TIMESTAMP '%s']", dtm, dtm), []Value{[]Value{ts, ts}}}, + {fmt.Sprintf("SELECT ('hello', TIMESTAMP '%s')", dtm), []Value{[]Value{"hello", ts}}}, + {fmt.Sprintf("SELECT DATETIME(TIMESTAMP '%s')", dtm), []Value{civil.DateTime{Date: d, Time: tm}}}, + {fmt.Sprintf("SELECT DATE(TIMESTAMP '%s')", dtm), []Value{d}}, + {fmt.Sprintf("SELECT TIME(TIMESTAMP '%s')", dtm), []Value{tm}}, + {"SELECT (1, 2)", []Value{ints(1, 2)}}, + {"SELECT [1, 2, 3]", []Value{ints(1, 2, 3)}}, + {"SELECT ([1, 2], 3, [4, 5])", []Value{[]Value{ints(1, 2), int64(3), ints(4, 5)}}}, + {"SELECT [(1, 2, 3), (4, 5, 6)]", []Value{[]Value{ints(1, 2, 3), ints(4, 5, 6)}}}, + {"SELECT [([1, 2, 3], 4), ([5, 6], 7)]", []Value{[]Value{[]Value{ints(1, 2, 3), int64(4)}, []Value{ints(5, 6), int64(7)}}}}, + {"SELECT ARRAY(SELECT STRUCT([1, 2]))", []Value{[]Value{[]Value{ints(1, 2)}}}}, + } + for _, c := range testCases { + q := client.Query(c.query) + it, err := q.Read(ctx) + if err != nil { + t.Fatal(err) + } + checkRead(t, "StandardQuery", it, [][]Value{c.wantRow}) + } +} + +func TestIntegration_LegacyQuery(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + + ts := time.Date(2016, 3, 20, 15, 04, 05, 0, time.UTC) + dtm := ts.Format("2006-01-02 15:04:05") + + testCases := []struct { + query string + wantRow []Value + }{ + {"SELECT 1", []Value{int64(1)}}, + {"SELECT 1.3", []Value{1.3}}, + {"SELECT TRUE", []Value{true}}, + {"SELECT 'ABC'", []Value{"ABC"}}, + {"SELECT CAST('foo' AS BYTES)", []Value{[]byte("foo")}}, + {fmt.Sprintf("SELECT TIMESTAMP('%s')", dtm), []Value{ts}}, + {fmt.Sprintf("SELECT DATE(TIMESTAMP('%s'))", dtm), []Value{"2016-03-20"}}, + {fmt.Sprintf("SELECT TIME(TIMESTAMP('%s'))", dtm), []Value{"15:04:05"}}, + } + for _, c := range testCases { + q := client.Query(c.query) + q.UseLegacySQL = true + it, err := q.Read(ctx) + if err != nil { + t.Fatal(err) + } + checkRead(t, "LegacyQuery", it, [][]Value{c.wantRow}) + } +} + +func TestIntegration_QueryParameters(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + + d := civil.Date{Year: 2016, Month: 3, Day: 20} + tm := civil.Time{Hour: 15, Minute: 04, Second: 05, Nanosecond: 3008} + rtm := tm + rtm.Nanosecond = 3000 // round to microseconds + dtm := civil.DateTime{Date: d, Time: tm} + ts := time.Date(2016, 3, 20, 15, 04, 05, 0, time.UTC) + rat := big.NewRat(13, 10) + + type ss struct { + String string + } + + type s struct { + Timestamp time.Time + StringArray []string + SubStruct ss + SubStructArray []ss + } + + testCases := []struct { + query string + parameters []QueryParameter + wantRow []Value + wantConfig interface{} + }{ + { + "SELECT @val", + []QueryParameter{{"val", 1}}, + []Value{int64(1)}, + int64(1), + }, + { + "SELECT @val", + []QueryParameter{{"val", 1.3}}, + []Value{1.3}, + 1.3, + }, + { + "SELECT @val", + []QueryParameter{{"val", rat}}, + []Value{rat}, + rat, + }, + { + "SELECT @val", + []QueryParameter{{"val", true}}, + []Value{true}, + true, + }, + { + "SELECT @val", + []QueryParameter{{"val", "ABC"}}, + []Value{"ABC"}, + "ABC", + }, + { + "SELECT @val", + []QueryParameter{{"val", []byte("foo")}}, + []Value{[]byte("foo")}, + []byte("foo"), + }, + { + "SELECT @val", + []QueryParameter{{"val", ts}}, + []Value{ts}, + ts, + }, + { + "SELECT @val", + []QueryParameter{{"val", []time.Time{ts, ts}}}, + []Value{[]Value{ts, ts}}, + []interface{}{ts, ts}, + }, + { + "SELECT @val", + []QueryParameter{{"val", dtm}}, + []Value{civil.DateTime{Date: d, Time: rtm}}, + civil.DateTime{Date: d, Time: rtm}, + }, + { + "SELECT @val", + []QueryParameter{{"val", d}}, + []Value{d}, + d, + }, + { + "SELECT @val", + []QueryParameter{{"val", tm}}, + []Value{rtm}, + rtm, + }, + { + "SELECT @val", + []QueryParameter{{"val", s{ts, []string{"a", "b"}, ss{"c"}, []ss{{"d"}, {"e"}}}}}, + []Value{[]Value{ts, []Value{"a", "b"}, []Value{"c"}, []Value{[]Value{"d"}, []Value{"e"}}}}, + map[string]interface{}{ + "Timestamp": ts, + "StringArray": []interface{}{"a", "b"}, + "SubStruct": map[string]interface{}{"String": "c"}, + "SubStructArray": []interface{}{ + map[string]interface{}{"String": "d"}, + map[string]interface{}{"String": "e"}, + }, + }, + }, + { + "SELECT @val.Timestamp, @val.SubStruct.String", + []QueryParameter{{"val", s{Timestamp: ts, SubStruct: ss{"a"}}}}, + []Value{ts, "a"}, + map[string]interface{}{ + "Timestamp": ts, + "SubStruct": map[string]interface{}{"String": "a"}, + "StringArray": nil, + "SubStructArray": nil, + }, + }, + } + for _, c := range testCases { + q := client.Query(c.query) + q.Parameters = c.parameters + job, err := q.Run(ctx) + if err != nil { + t.Fatal(err) + } + if job.LastStatus() == nil { + t.Error("no LastStatus") + } + it, err := job.Read(ctx) + if err != nil { + t.Fatal(err) + } + checkRead(t, "QueryParameters", it, [][]Value{c.wantRow}) + config, err := job.Config() + if err != nil { + t.Fatal(err) + } + got := config.(*QueryConfig).Parameters[0].Value + if !testutil.Equal(got, c.wantConfig) { + t.Errorf("param %[1]v (%[1]T): config:\ngot %[2]v (%[2]T)\nwant %[3]v (%[3]T)", + c.parameters[0].Value, got, c.wantConfig) + } + } +} + +func TestIntegration_QueryDryRun(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + q := client.Query("SELECT word from " + stdName + " LIMIT 10") + q.DryRun = true + job, err := q.Run(ctx) + if err != nil { + t.Fatal(err) + } + + s := job.LastStatus() + if s.State != Done { + t.Errorf("state is %v, expected Done", s.State) + } + if s.Statistics == nil { + t.Fatal("no statistics") + } + if s.Statistics.Details.(*QueryStatistics).Schema == nil { + t.Fatal("no schema") + } +} + +func TestIntegration_ExtractExternal(t *testing.T) { + // Create a table, extract it to GCS, then query it externally. + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + schema := Schema{ + {Name: "name", Type: StringFieldType}, + {Name: "num", Type: IntegerFieldType}, + } + table := newTable(t, schema) + defer table.Delete(ctx) + + // Insert table data. + sql := fmt.Sprintf(`INSERT %s.%s (name, num) + VALUES ('a', 1), ('b', 2), ('c', 3)`, + table.DatasetID, table.TableID) + if err := runDML(ctx, sql); err != nil { + t.Fatal(err) + } + // Extract to a GCS object as CSV. + bucketName := testutil.ProjID() + objectName := fmt.Sprintf("bq-test-%s.csv", table.TableID) + uri := fmt.Sprintf("gs://%s/%s", bucketName, objectName) + defer storageClient.Bucket(bucketName).Object(objectName).Delete(ctx) + gr := NewGCSReference(uri) + gr.DestinationFormat = CSV + e := table.ExtractorTo(gr) + job, err := e.Run(ctx) + if err != nil { + t.Fatal(err) + } + conf, err := job.Config() + if err != nil { + t.Fatal(err) + } + config, ok := conf.(*ExtractConfig) + if !ok { + t.Fatalf("got %T, want ExtractConfig", conf) + } + diff := testutil.Diff(config, &e.ExtractConfig, + cmp.AllowUnexported(Table{}), + cmpopts.IgnoreUnexported(Client{})) + if diff != "" { + t.Errorf("got=-, want=+:\n%s", diff) + } + if err := wait(ctx, job); err != nil { + t.Fatal(err) + } + + edc := &ExternalDataConfig{ + SourceFormat: CSV, + SourceURIs: []string{uri}, + Schema: schema, + Options: &CSVOptions{SkipLeadingRows: 1}, + } + // Query that CSV file directly. + q := client.Query("SELECT * FROM csv") + q.TableDefinitions = map[string]ExternalData{"csv": edc} + wantRows := [][]Value{ + {"a", int64(1)}, + {"b", int64(2)}, + {"c", int64(3)}, + } + iter, err := q.Read(ctx) + if err != nil { + t.Fatal(err) + } + checkReadAndTotalRows(t, "external query", iter, wantRows) + + // Make a table pointing to the file, and query it. + // BigQuery does not allow a Table.Read on an external table. + table = dataset.Table(tableIDs.New()) + err = table.Create(context.Background(), &TableMetadata{ + Schema: schema, + ExpirationTime: testTableExpiration, + ExternalDataConfig: edc, + }) + if err != nil { + t.Fatal(err) + } + q = client.Query(fmt.Sprintf("SELECT * FROM %s.%s", table.DatasetID, table.TableID)) + iter, err = q.Read(ctx) + if err != nil { + t.Fatal(err) + } + checkReadAndTotalRows(t, "external table", iter, wantRows) + + // While we're here, check that the table metadata is correct. + md, err := table.Metadata(ctx) + if err != nil { + t.Fatal(err) + } + // One difference: since BigQuery returns the schema as part of the ordinary + // table metadata, it does not populate ExternalDataConfig.Schema. + md.ExternalDataConfig.Schema = md.Schema + if diff := testutil.Diff(md.ExternalDataConfig, edc); diff != "" { + t.Errorf("got=-, want=+\n%s", diff) + } +} + +func TestIntegration_ReadNullIntoStruct(t *testing.T) { + // Reading a null into a struct field should return an error (not panic). + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + table := newTable(t, schema) + defer table.Delete(ctx) + + ins := table.Inserter() + row := &ValuesSaver{ + Schema: schema, + Row: []Value{nil, []Value{}, []Value{nil}}, + } + if err := ins.Put(ctx, []*ValuesSaver{row}); err != nil { + t.Fatal(putError(err)) + } + if err := waitForRow(ctx, table); err != nil { + t.Fatal(err) + } + + q := client.Query(fmt.Sprintf("select name from %s", table.TableID)) + q.DefaultProjectID = dataset.ProjectID + q.DefaultDatasetID = dataset.DatasetID + it, err := q.Read(ctx) + if err != nil { + t.Fatal(err) + } + type S struct{ Name string } + var s S + if err := it.Next(&s); err == nil { + t.Fatal("got nil, want error") + } +} + +const ( + stdName = "`bigquery-public-data.samples.shakespeare`" + legacyName = "[bigquery-public-data:samples.shakespeare]" +) + +// These tests exploit the fact that the two SQL versions have different syntaxes for +// fully-qualified table names. +var useLegacySQLTests = []struct { + t string // name of table + std, legacy bool // use standard/legacy SQL + err bool // do we expect an error? +}{ + {t: legacyName, std: false, legacy: true, err: false}, + {t: legacyName, std: true, legacy: false, err: true}, + {t: legacyName, std: false, legacy: false, err: true}, // standard SQL is default + {t: legacyName, std: true, legacy: true, err: true}, + {t: stdName, std: false, legacy: true, err: true}, + {t: stdName, std: true, legacy: false, err: false}, + {t: stdName, std: false, legacy: false, err: false}, // standard SQL is default + {t: stdName, std: true, legacy: true, err: true}, +} + +func TestIntegration_QueryUseLegacySQL(t *testing.T) { + // Test the UseLegacySQL and UseStandardSQL options for queries. + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + for _, test := range useLegacySQLTests { + q := client.Query(fmt.Sprintf("select word from %s limit 1", test.t)) + q.UseStandardSQL = test.std + q.UseLegacySQL = test.legacy + _, err := q.Read(ctx) + gotErr := err != nil + if gotErr && !test.err { + t.Errorf("%+v:\nunexpected error: %v", test, err) + } else if !gotErr && test.err { + t.Errorf("%+v:\nsucceeded, but want error", test) + } + } +} + +func TestIntegration_TableUseLegacySQL(t *testing.T) { + // Test UseLegacySQL and UseStandardSQL for Table.Create. + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + table := newTable(t, schema) + defer table.Delete(ctx) + for i, test := range useLegacySQLTests { + view := dataset.Table(fmt.Sprintf("t_view_%d", i)) + tm := &TableMetadata{ + ViewQuery: fmt.Sprintf("SELECT word from %s", test.t), + UseStandardSQL: test.std, + UseLegacySQL: test.legacy, + } + err := view.Create(ctx, tm) + gotErr := err != nil + if gotErr && !test.err { + t.Errorf("%+v:\nunexpected error: %v", test, err) + } else if !gotErr && test.err { + t.Errorf("%+v:\nsucceeded, but want error", test) + } + _ = view.Delete(ctx) + } +} + +func TestIntegration_ListJobs(t *testing.T) { + // It's difficult to test the list of jobs, because we can't easily + // control what's in it. Also, there are many jobs in the test project, + // and it takes considerable time to list them all. + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + + // About all we can do is list a few jobs. + const max = 20 + var jobs []*Job + it := client.Jobs(ctx) + for { + job, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + t.Fatal(err) + } + jobs = append(jobs, job) + if len(jobs) >= max { + break + } + } + // We expect that there is at least one job in the last few months. + if len(jobs) == 0 { + t.Fatal("did not get any jobs") + } +} + +const tokyo = "asia-northeast1" + +func TestIntegration_Location(t *testing.T) { + if client == nil { + t.Skip("Integration tests skipped") + } + client.Location = "" + testLocation(t, tokyo) + client.Location = tokyo + defer func() { + client.Location = "" + }() + testLocation(t, "") +} + +func testLocation(t *testing.T, loc string) { + ctx := context.Background() + tokyoDataset := client.Dataset("tokyo") + err := tokyoDataset.Create(ctx, &DatasetMetadata{Location: loc}) + if err != nil && !hasStatusCode(err, 409) { // 409 = already exists + t.Fatal(err) + } + md, err := tokyoDataset.Metadata(ctx) + if err != nil { + t.Fatal(err) + } + if md.Location != tokyo { + t.Fatalf("dataset location: got %s, want %s", md.Location, tokyo) + } + table := tokyoDataset.Table(tableIDs.New()) + err = table.Create(context.Background(), &TableMetadata{ + Schema: Schema{ + {Name: "name", Type: StringFieldType}, + {Name: "nums", Type: IntegerFieldType}, + }, + ExpirationTime: testTableExpiration, + }) + if err != nil { + t.Fatal(err) + } + defer table.Delete(ctx) + loader := table.LoaderFrom(NewReaderSource(strings.NewReader("a,0\nb,1\nc,2\n"))) + loader.Location = loc + job, err := loader.Run(ctx) + if err != nil { + t.Fatal("loader.Run", err) + } + if job.Location() != tokyo { + t.Fatalf("job location: got %s, want %s", job.Location(), tokyo) + } + _, err = client.JobFromID(ctx, job.ID()) + if client.Location == "" && err == nil { + t.Error("JobFromID with Tokyo job, no client location: want error, got nil") + } + if client.Location != "" && err != nil { + t.Errorf("JobFromID with Tokyo job, with client location: want nil, got %v", err) + } + _, err = client.JobFromIDLocation(ctx, job.ID(), "US") + if err == nil { + t.Error("JobFromIDLocation with US: want error, got nil") + } + job2, err := client.JobFromIDLocation(ctx, job.ID(), loc) + if loc == tokyo && err != nil { + t.Errorf("loc=tokyo: %v", err) + } + if loc == "" && err == nil { + t.Error("loc empty: got nil, want error") + } + if job2 != nil && (job2.ID() != job.ID() || job2.Location() != tokyo) { + t.Errorf("got id %s loc %s, want id%s loc %s", job2.ID(), job2.Location(), job.ID(), tokyo) + } + if err := wait(ctx, job); err != nil { + t.Fatal(err) + } + // Cancel should succeed even if the job is done. + if err := job.Cancel(ctx); err != nil { + t.Fatal(err) + } + + q := client.Query(fmt.Sprintf("SELECT * FROM %s.%s", table.DatasetID, table.TableID)) + q.Location = loc + iter, err := q.Read(ctx) + if err != nil { + t.Fatal(err) + } + wantRows := [][]Value{ + {"a", int64(0)}, + {"b", int64(1)}, + {"c", int64(2)}, + } + checkRead(t, "location", iter, wantRows) + + table2 := tokyoDataset.Table(tableIDs.New()) + copier := table2.CopierFrom(table) + copier.Location = loc + if _, err := copier.Run(ctx); err != nil { + t.Fatal(err) + } + bucketName := testutil.ProjID() + objectName := fmt.Sprintf("bq-test-%s.csv", table.TableID) + uri := fmt.Sprintf("gs://%s/%s", bucketName, objectName) + defer storageClient.Bucket(bucketName).Object(objectName).Delete(ctx) + gr := NewGCSReference(uri) + gr.DestinationFormat = CSV + e := table.ExtractorTo(gr) + e.Location = loc + if _, err := e.Run(ctx); err != nil { + t.Fatal(err) + } +} + +func TestIntegration_NumericErrors(t *testing.T) { + // Verify that the service returns an error for a big.Rat that's too large. + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + schema := Schema{{Name: "n", Type: NumericFieldType}} + table := newTable(t, schema) + defer table.Delete(ctx) + tooBigRat := &big.Rat{} + if _, ok := tooBigRat.SetString("1e40"); !ok { + t.Fatal("big.Rat.SetString failed") + } + ins := table.Inserter() + err := ins.Put(ctx, []*ValuesSaver{{Schema: schema, Row: []Value{tooBigRat}}}) + if err == nil { + t.Fatal("got nil, want error") + } +} + +func TestIntegration_QueryErrors(t *testing.T) { + // Verify that a bad query returns an appropriate error. + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + q := client.Query("blah blah broken") + _, err := q.Read(ctx) + const want = "invalidQuery" + if !strings.Contains(err.Error(), want) { + t.Fatalf("got %q, want substring %q", err, want) + } +} + +func TestIntegration_Model(t *testing.T) { + // Create an ML model. + if client == nil { + t.Skip("Integration tests skipped") + } + ctx := context.Background() + schema := Schema{ + {Name: "input", Type: IntegerFieldType}, + {Name: "label", Type: IntegerFieldType}, + } + table := newTable(t, schema) + defer table.Delete(ctx) + + // Insert table data. + tableName := fmt.Sprintf("%s.%s", table.DatasetID, table.TableID) + sql := fmt.Sprintf(`INSERT %s (input, label) + VALUES (1, 0), (2, 1), (3, 0), (4, 1)`, + tableName) + wantNumRows := 4 + + if err := runDML(ctx, sql); err != nil { + t.Fatal(err) + } + + model := dataset.Table("my_model") + modelName := fmt.Sprintf("%s.%s", model.DatasetID, model.TableID) + sql = fmt.Sprintf(`CREATE MODEL %s OPTIONS (model_type='logistic_reg') AS SELECT input, label FROM %s`, + modelName, tableName) + if err := runDML(ctx, sql); err != nil { + t.Fatal(err) + } + defer model.Delete(ctx) + + sql = fmt.Sprintf(`SELECT * FROM ml.PREDICT(MODEL %s, TABLE %s)`, modelName, tableName) + q := client.Query(sql) + ri, err := q.Read(ctx) + if err != nil { + t.Fatal(err) + } + rows, _, _, err := readAll(ri) + if err != nil { + t.Fatal(err) + } + if got := len(rows); got != wantNumRows { + t.Fatalf("got %d rows in prediction table, want %d", got, wantNumRows) + } + iter := dataset.Tables(ctx) + seen := false + for { + tbl, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + t.Fatal(err) + } + if tbl.TableID == "my_model" { + seen = true + } + } + if !seen { + t.Fatal("model not listed in dataset") + } + if err := model.Delete(ctx); err != nil { + t.Fatal(err) + } +} + +// Creates a new, temporary table with a unique name and the given schema. +func newTable(t *testing.T, s Schema) *Table { + table := dataset.Table(tableIDs.New()) + err := table.Create(context.Background(), &TableMetadata{ + Schema: s, + ExpirationTime: testTableExpiration, + }) + if err != nil { + t.Fatal(err) + } + return table +} + +func checkRead(t *testing.T, msg string, it *RowIterator, want [][]Value) { + if msg2, ok := compareRead(it, want, false); !ok { + t.Errorf("%s: %s", msg, msg2) + } +} + +func checkReadAndTotalRows(t *testing.T, msg string, it *RowIterator, want [][]Value) { + if msg2, ok := compareRead(it, want, true); !ok { + t.Errorf("%s: %s", msg, msg2) + } +} + +func compareRead(it *RowIterator, want [][]Value, compareTotalRows bool) (msg string, ok bool) { + got, _, totalRows, err := readAll(it) + if err != nil { + return err.Error(), false + } + if len(got) != len(want) { + return fmt.Sprintf("got %d rows, want %d", len(got), len(want)), false + } + if compareTotalRows && len(got) != int(totalRows) { + return fmt.Sprintf("got %d rows, but totalRows = %d", len(got), totalRows), false + } + sort.Sort(byCol0(got)) + for i, r := range got { + gotRow := []Value(r) + wantRow := want[i] + if !testutil.Equal(gotRow, wantRow) { + return fmt.Sprintf("#%d: got %#v, want %#v", i, gotRow, wantRow), false + } + } + return "", true +} + +func readAll(it *RowIterator) ([][]Value, Schema, uint64, error) { + var ( + rows [][]Value + schema Schema + totalRows uint64 + ) + for { + var vals []Value + err := it.Next(&vals) + if err == iterator.Done { + return rows, schema, totalRows, nil + } + if err != nil { + return nil, nil, 0, err + } + rows = append(rows, vals) + schema = it.Schema + totalRows = it.TotalRows + } +} + +type byCol0 [][]Value + +func (b byCol0) Len() int { return len(b) } +func (b byCol0) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byCol0) Less(i, j int) bool { + switch a := b[i][0].(type) { + case string: + return a < b[j][0].(string) + case civil.Date: + return a.Before(b[j][0].(civil.Date)) + default: + panic("unknown type") + } +} + +func hasStatusCode(err error, code int) bool { + if e, ok := err.(*googleapi.Error); ok && e.Code == code { + return true + } + return false +} + +// wait polls the job until it is complete or an error is returned. +func wait(ctx context.Context, job *Job) error { + status, err := job.Wait(ctx) + if err != nil { + return err + } + if status.Err() != nil { + return fmt.Errorf("job status error: %#v", status.Err()) + } + if status.Statistics == nil { + return errors.New("nil Statistics") + } + if status.Statistics.EndTime.IsZero() { + return errors.New("EndTime is zero") + } + if status.Statistics.Details == nil { + return errors.New("nil Statistics.Details") + } + return nil +} + +// waitForRow polls the table until it contains a row. +// TODO(jba): use internal.Retry. +func waitForRow(ctx context.Context, table *Table) error { + for { + it := table.Read(ctx) + var v []Value + err := it.Next(&v) + if err == nil { + return nil + } + if err != iterator.Done { + return err + } + time.Sleep(1 * time.Second) + } +} + +func putError(err error) string { + pme, ok := err.(PutMultiError) + if !ok { + return err.Error() + } + var msgs []string + for _, err := range pme { + msgs = append(msgs, err.Error()) + } + return strings.Join(msgs, "\n") +} diff --git a/vendor/cloud.google.com/go/bigquery/iterator.go b/vendor/cloud.google.com/go/bigquery/iterator.go new file mode 100644 index 00000000..298143cb --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/iterator.go @@ -0,0 +1,222 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "context" + "fmt" + "reflect" + + bq "google.golang.org/api/bigquery/v2" + "google.golang.org/api/iterator" +) + +// Construct a RowIterator. +// If pf is nil, there are no rows in the result set. +func newRowIterator(ctx context.Context, t *Table, pf pageFetcher) *RowIterator { + it := &RowIterator{ + ctx: ctx, + table: t, + pf: pf, + } + if pf != nil { + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.rows) }, + func() interface{} { r := it.rows; it.rows = nil; return r }) + } + return it +} + +// A RowIterator provides access to the result of a BigQuery lookup. +type RowIterator struct { + ctx context.Context + table *Table + pf pageFetcher + pageInfo *iterator.PageInfo + nextFunc func() error + + // StartIndex can be set before the first call to Next. If PageInfo().Token + // is also set, StartIndex is ignored. + StartIndex uint64 + + // The schema of the table. Available after the first call to Next. + Schema Schema + + // The total number of rows in the result. Available after the first call to Next. + // May be zero just after rows were inserted. + TotalRows uint64 + + rows [][]Value + structLoader structLoader // used to populate a pointer to a struct +} + +// Next loads the next row into dst. Its return value is iterator.Done if there +// are no more results. Once Next returns iterator.Done, all subsequent calls +// will return iterator.Done. +// +// dst may implement ValueLoader, or may be a *[]Value, *map[string]Value, or struct pointer. +// +// If dst is a *[]Value, it will be set to new []Value whose i'th element +// will be populated with the i'th column of the row. +// +// If dst is a *map[string]Value, a new map will be created if dst is nil. Then +// for each schema column name, the map key of that name will be set to the column's +// value. STRUCT types (RECORD types or nested schemas) become nested maps. +// +// If dst is pointer to a struct, each column in the schema will be matched +// with an exported field of the struct that has the same name, ignoring case. +// Unmatched schema columns and struct fields will be ignored. +// +// Each BigQuery column type corresponds to one or more Go types; a matching struct +// field must be of the correct type. The correspondences are: +// +// STRING string +// BOOL bool +// INTEGER int, int8, int16, int32, int64, uint8, uint16, uint32 +// FLOAT float32, float64 +// BYTES []byte +// TIMESTAMP time.Time +// DATE civil.Date +// TIME civil.Time +// DATETIME civil.DateTime +// +// A repeated field corresponds to a slice or array of the element type. A STRUCT +// type (RECORD or nested schema) corresponds to a nested struct or struct pointer. +// All calls to Next on the same iterator must use the same struct type. +// +// It is an error to attempt to read a BigQuery NULL value into a struct field, +// unless the field is of type []byte or is one of the special Null types: NullInt64, +// NullFloat64, NullBool, NullString, NullTimestamp, NullDate, NullTime or +// NullDateTime. You can also use a *[]Value or *map[string]Value to read from a +// table with NULLs. +func (it *RowIterator) Next(dst interface{}) error { + if it.pf == nil { // There are no rows in the result set. + return iterator.Done + } + var vl ValueLoader + switch dst := dst.(type) { + case ValueLoader: + vl = dst + case *[]Value: + vl = (*valueList)(dst) + case *map[string]Value: + vl = (*valueMap)(dst) + default: + if !isStructPtr(dst) { + return fmt.Errorf("bigquery: cannot convert %T to ValueLoader (need pointer to []Value, map[string]Value, or struct)", dst) + } + } + if err := it.nextFunc(); err != nil { + return err + } + row := it.rows[0] + it.rows = it.rows[1:] + + if vl == nil { + // This can only happen if dst is a pointer to a struct. We couldn't + // set vl above because we need the schema. + if err := it.structLoader.set(dst, it.Schema); err != nil { + return err + } + vl = &it.structLoader + } + return vl.Load(row, it.Schema) +} + +func isStructPtr(x interface{}) bool { + t := reflect.TypeOf(x) + return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *RowIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } + +func (it *RowIterator) fetch(pageSize int, pageToken string) (string, error) { + res, err := it.pf(it.ctx, it.table, it.Schema, it.StartIndex, int64(pageSize), pageToken) + if err != nil { + return "", err + } + it.rows = append(it.rows, res.rows...) + it.Schema = res.schema + it.TotalRows = res.totalRows + return res.pageToken, nil +} + +// A pageFetcher returns a page of rows from a destination table. +type pageFetcher func(ctx context.Context, _ *Table, _ Schema, startIndex uint64, pageSize int64, pageToken string) (*fetchPageResult, error) + +type fetchPageResult struct { + pageToken string + rows [][]Value + totalRows uint64 + schema Schema +} + +// fetchPage gets a page of rows from t. +func fetchPage(ctx context.Context, t *Table, schema Schema, startIndex uint64, pageSize int64, pageToken string) (*fetchPageResult, error) { + // Fetch the table schema in the background, if necessary. + errc := make(chan error, 1) + if schema != nil { + errc <- nil + } else { + go func() { + var bqt *bq.Table + err := runWithRetry(ctx, func() (err error) { + bqt, err = t.c.bqs.Tables.Get(t.ProjectID, t.DatasetID, t.TableID). + Fields("schema"). + Context(ctx). + Do() + return err + }) + if err == nil && bqt.Schema != nil { + schema = bqToSchema(bqt.Schema) + } + errc <- err + }() + } + call := t.c.bqs.Tabledata.List(t.ProjectID, t.DatasetID, t.TableID) + setClientHeader(call.Header()) + if pageToken != "" { + call.PageToken(pageToken) + } else { + call.StartIndex(startIndex) + } + if pageSize > 0 { + call.MaxResults(pageSize) + } + var res *bq.TableDataList + err := runWithRetry(ctx, func() (err error) { + res, err = call.Context(ctx).Do() + return err + }) + if err != nil { + return nil, err + } + err = <-errc + if err != nil { + return nil, err + } + rows, err := convertRows(res.Rows, schema) + if err != nil { + return nil, err + } + return &fetchPageResult{ + pageToken: res.PageToken, + rows: rows, + totalRows: uint64(res.TotalRows), + schema: schema, + }, nil +} diff --git a/vendor/cloud.google.com/go/bigquery/iterator_test.go b/vendor/cloud.google.com/go/bigquery/iterator_test.go new file mode 100644 index 00000000..125796d7 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/iterator_test.go @@ -0,0 +1,362 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "context" + "errors" + "fmt" + "testing" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" +) + +type fetchResponse struct { + result *fetchPageResult // The result to return. + err error // The error to return. +} + +// pageFetcherStub services fetch requests by returning data from an in-memory list of values. +type pageFetcherStub struct { + fetchResponses map[string]fetchResponse + err error +} + +func (pf *pageFetcherStub) fetchPage(ctx context.Context, _ *Table, _ Schema, _ uint64, _ int64, pageToken string) (*fetchPageResult, error) { + call, ok := pf.fetchResponses[pageToken] + if !ok { + pf.err = fmt.Errorf("Unexpected page token: %q", pageToken) + } + return call.result, call.err +} + +func TestIterator(t *testing.T) { + var ( + iiSchema = Schema{ + {Type: IntegerFieldType}, + {Type: IntegerFieldType}, + } + siSchema = Schema{ + {Type: StringFieldType}, + {Type: IntegerFieldType}, + } + ) + fetchFailure := errors.New("fetch failure") + + testCases := []struct { + desc string + pageToken string + fetchResponses map[string]fetchResponse + want [][]Value + wantErr error + wantSchema Schema + wantTotalRows uint64 + }{ + { + desc: "Iteration over single empty page", + fetchResponses: map[string]fetchResponse{ + "": { + result: &fetchPageResult{ + pageToken: "", + rows: [][]Value{}, + schema: Schema{}, + }, + }, + }, + want: [][]Value{}, + wantSchema: Schema{}, + }, + { + desc: "Iteration over single page", + fetchResponses: map[string]fetchResponse{ + "": { + result: &fetchPageResult{ + pageToken: "", + rows: [][]Value{{1, 2}, {11, 12}}, + schema: iiSchema, + totalRows: 4, + }, + }, + }, + want: [][]Value{{1, 2}, {11, 12}}, + wantSchema: iiSchema, + wantTotalRows: 4, + }, + { + desc: "Iteration over single page with different schema", + fetchResponses: map[string]fetchResponse{ + "": { + result: &fetchPageResult{ + pageToken: "", + rows: [][]Value{{"1", 2}, {"11", 12}}, + schema: siSchema, + }, + }, + }, + want: [][]Value{{"1", 2}, {"11", 12}}, + wantSchema: siSchema, + }, + { + desc: "Iteration over two pages", + fetchResponses: map[string]fetchResponse{ + "": { + result: &fetchPageResult{ + pageToken: "a", + rows: [][]Value{{1, 2}, {11, 12}}, + schema: iiSchema, + totalRows: 4, + }, + }, + "a": { + result: &fetchPageResult{ + pageToken: "", + rows: [][]Value{{101, 102}, {111, 112}}, + schema: iiSchema, + totalRows: 4, + }, + }, + }, + want: [][]Value{{1, 2}, {11, 12}, {101, 102}, {111, 112}}, + wantSchema: iiSchema, + wantTotalRows: 4, + }, + { + desc: "Server response includes empty page", + fetchResponses: map[string]fetchResponse{ + "": { + result: &fetchPageResult{ + pageToken: "a", + rows: [][]Value{{1, 2}, {11, 12}}, + schema: iiSchema, + }, + }, + "a": { + result: &fetchPageResult{ + pageToken: "b", + rows: [][]Value{}, + schema: iiSchema, + }, + }, + "b": { + result: &fetchPageResult{ + pageToken: "", + rows: [][]Value{{101, 102}, {111, 112}}, + schema: iiSchema, + }, + }, + }, + want: [][]Value{{1, 2}, {11, 12}, {101, 102}, {111, 112}}, + wantSchema: iiSchema, + }, + { + desc: "Fetch error", + fetchResponses: map[string]fetchResponse{ + "": { + result: &fetchPageResult{ + pageToken: "a", + rows: [][]Value{{1, 2}, {11, 12}}, + schema: iiSchema, + }, + }, + "a": { + // We returns some data from this fetch, but also an error. + // So the end result should include only data from the previous fetch. + err: fetchFailure, + result: &fetchPageResult{ + pageToken: "b", + rows: [][]Value{{101, 102}, {111, 112}}, + schema: iiSchema, + }, + }, + }, + want: [][]Value{{1, 2}, {11, 12}}, + wantErr: fetchFailure, + wantSchema: iiSchema, + }, + + { + desc: "Skip over an entire page", + pageToken: "a", + fetchResponses: map[string]fetchResponse{ + "": { + result: &fetchPageResult{ + pageToken: "a", + rows: [][]Value{{1, 2}, {11, 12}}, + schema: iiSchema, + }, + }, + "a": { + result: &fetchPageResult{ + pageToken: "", + rows: [][]Value{{101, 102}, {111, 112}}, + schema: iiSchema, + }, + }, + }, + want: [][]Value{{101, 102}, {111, 112}}, + wantSchema: iiSchema, + }, + + { + desc: "Skip beyond all data", + pageToken: "b", + fetchResponses: map[string]fetchResponse{ + "": { + result: &fetchPageResult{ + pageToken: "a", + rows: [][]Value{{1, 2}, {11, 12}}, + schema: iiSchema, + }, + }, + "a": { + result: &fetchPageResult{ + pageToken: "b", + rows: [][]Value{{101, 102}, {111, 112}}, + schema: iiSchema, + }, + }, + "b": { + result: &fetchPageResult{}, + }, + }, + // In this test case, Next will return false on its first call, + // so we won't even attempt to call Get. + want: [][]Value{}, + wantSchema: Schema{}, + }, + } + + for _, tc := range testCases { + pf := &pageFetcherStub{ + fetchResponses: tc.fetchResponses, + } + it := newRowIterator(context.Background(), nil, pf.fetchPage) + it.PageInfo().Token = tc.pageToken + values, schema, totalRows, err := consumeRowIterator(it) + if err != tc.wantErr { + t.Fatalf("%s: got %v, want %v", tc.desc, err, tc.wantErr) + } + if (len(values) != 0 || len(tc.want) != 0) && !testutil.Equal(values, tc.want) { + t.Errorf("%s: values:\ngot: %v\nwant:%v", tc.desc, values, tc.want) + } + if (len(schema) != 0 || len(tc.wantSchema) != 0) && !testutil.Equal(schema, tc.wantSchema) { + t.Errorf("%s: iterator.Schema:\ngot: %v\nwant: %v", tc.desc, schema, tc.wantSchema) + } + if totalRows != tc.wantTotalRows { + t.Errorf("%s: totalRows: got %d, want %d", tc.desc, totalRows, tc.wantTotalRows) + } + } +} + +// consumeRowIterator reads the schema and all values from a RowIterator and returns them. +func consumeRowIterator(it *RowIterator) ([][]Value, Schema, uint64, error) { + var ( + got [][]Value + schema Schema + totalRows uint64 + ) + for { + var vls []Value + err := it.Next(&vls) + if err == iterator.Done { + return got, schema, totalRows, nil + } + if err != nil { + return got, schema, totalRows, err + } + got = append(got, vls) + schema = it.Schema + totalRows = it.TotalRows + } +} + +func TestNextDuringErrorState(t *testing.T) { + pf := &pageFetcherStub{ + fetchResponses: map[string]fetchResponse{ + "": {err: errors.New("bang")}, + }, + } + it := newRowIterator(context.Background(), nil, pf.fetchPage) + var vals []Value + if err := it.Next(&vals); err == nil { + t.Errorf("Expected error after calling Next") + } + if err := it.Next(&vals); err == nil { + t.Errorf("Expected error calling Next again when iterator has a non-nil error.") + } +} + +func TestNextAfterFinished(t *testing.T) { + testCases := []struct { + fetchResponses map[string]fetchResponse + want [][]Value + }{ + { + fetchResponses: map[string]fetchResponse{ + "": { + result: &fetchPageResult{ + pageToken: "", + rows: [][]Value{{1, 2}, {11, 12}}, + }, + }, + }, + want: [][]Value{{1, 2}, {11, 12}}, + }, + { + fetchResponses: map[string]fetchResponse{ + "": { + result: &fetchPageResult{ + pageToken: "", + rows: [][]Value{}, + }, + }, + }, + want: [][]Value{}, + }, + } + + for _, tc := range testCases { + pf := &pageFetcherStub{ + fetchResponses: tc.fetchResponses, + } + it := newRowIterator(context.Background(), nil, pf.fetchPage) + + values, _, _, err := consumeRowIterator(it) + if err != nil { + t.Fatal(err) + } + if (len(values) != 0 || len(tc.want) != 0) && !testutil.Equal(values, tc.want) { + t.Errorf("values: got:\n%v\nwant:\n%v", values, tc.want) + } + // Try calling Get again. + var vals []Value + if err := it.Next(&vals); err != iterator.Done { + t.Errorf("Expected Done calling Next when there are no more values") + } + } +} + +func TestIteratorNextTypes(t *testing.T) { + it := newRowIterator(context.Background(), nil, nil) + for _, v := range []interface{}{3, "s", []int{}, &[]int{}, + map[string]Value{}, &map[string]interface{}{}, + struct{}{}, + } { + if err := it.Next(v); err == nil { + t.Errorf("%v: want error, got nil", v) + } + } +} diff --git a/vendor/cloud.google.com/go/bigquery/job.go b/vendor/cloud.google.com/go/bigquery/job.go new file mode 100644 index 00000000..d98211d9 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/job.go @@ -0,0 +1,821 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "context" + "errors" + "fmt" + "time" + + "cloud.google.com/go/internal" + "cloud.google.com/go/internal/trace" + gax "github.com/googleapis/gax-go" + bq "google.golang.org/api/bigquery/v2" + "google.golang.org/api/googleapi" + "google.golang.org/api/iterator" +) + +// A Job represents an operation which has been submitted to BigQuery for processing. +type Job struct { + c *Client + projectID string + jobID string + location string + email string + config *bq.JobConfiguration + lastStatus *JobStatus +} + +// JobFromID creates a Job which refers to an existing BigQuery job. The job +// need not have been created by this package. For example, the job may have +// been created in the BigQuery console. +// +// For jobs whose location is other than "US" or "EU", set Client.Location or use +// JobFromIDLocation. +func (c *Client) JobFromID(ctx context.Context, id string) (*Job, error) { + return c.JobFromIDLocation(ctx, id, c.Location) +} + +// JobFromIDLocation creates a Job which refers to an existing BigQuery job. The job +// need not have been created by this package (for example, it may have +// been created in the BigQuery console), but it must exist in the specified location. +func (c *Client) JobFromIDLocation(ctx context.Context, id, location string) (j *Job, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.JobFromIDLocation") + defer func() { trace.EndSpan(ctx, err) }() + + bqjob, err := c.getJobInternal(ctx, id, location, "configuration", "jobReference", "status", "statistics") + if err != nil { + return nil, err + } + return bqToJob(bqjob, c) +} + +// ID returns the job's ID. +func (j *Job) ID() string { + return j.jobID +} + +// Location returns the job's location. +func (j *Job) Location() string { + return j.location +} + +// Email returns the email of the job's creator. +func (j *Job) Email() string { + return j.email +} + +// State is one of a sequence of states that a Job progresses through as it is processed. +type State int + +const ( + // StateUnspecified is the default JobIterator state. + StateUnspecified State = iota + // Pending is a state that describes that the job is pending. + Pending + // Running is a state that describes that the job is running. + Running + // Done is a state that describes that the job is done. + Done +) + +// JobStatus contains the current State of a job, and errors encountered while processing that job. +type JobStatus struct { + State State + + err error + + // All errors encountered during the running of the job. + // Not all Errors are fatal, so errors here do not necessarily mean that the job has completed or was unsuccessful. + Errors []*Error + + // Statistics about the job. + Statistics *JobStatistics +} + +// JobConfig contains configuration information for a job. It is implemented by +// *CopyConfig, *ExtractConfig, *LoadConfig and *QueryConfig. +type JobConfig interface { + isJobConfig() +} + +func (*CopyConfig) isJobConfig() {} +func (*ExtractConfig) isJobConfig() {} +func (*LoadConfig) isJobConfig() {} +func (*QueryConfig) isJobConfig() {} + +// Config returns the configuration information for j. +func (j *Job) Config() (JobConfig, error) { + return bqToJobConfig(j.config, j.c) +} + +func bqToJobConfig(q *bq.JobConfiguration, c *Client) (JobConfig, error) { + switch { + case q == nil: + return nil, nil + case q.Copy != nil: + return bqToCopyConfig(q, c), nil + case q.Extract != nil: + return bqToExtractConfig(q, c), nil + case q.Load != nil: + return bqToLoadConfig(q, c), nil + case q.Query != nil: + return bqToQueryConfig(q, c) + default: + return nil, nil + } +} + +// JobIDConfig describes how to create an ID for a job. +type JobIDConfig struct { + // JobID is the ID to use for the job. If empty, a random job ID will be generated. + JobID string + + // If AddJobIDSuffix is true, then a random string will be appended to JobID. + AddJobIDSuffix bool + + // Location is the location for the job. + Location string +} + +// createJobRef creates a JobReference. +func (j *JobIDConfig) createJobRef(c *Client) *bq.JobReference { + // We don't check whether projectID is empty; the server will return an + // error when it encounters the resulting JobReference. + loc := j.Location + if loc == "" { // Use Client.Location as a default. + loc = c.Location + } + jr := &bq.JobReference{ProjectId: c.projectID, Location: loc} + if j.JobID == "" { + jr.JobId = randomIDFn() + } else if j.AddJobIDSuffix { + jr.JobId = j.JobID + "-" + randomIDFn() + } else { + jr.JobId = j.JobID + } + return jr +} + +// Done reports whether the job has completed. +// After Done returns true, the Err method will return an error if the job completed unsuccessfully. +func (s *JobStatus) Done() bool { + return s.State == Done +} + +// Err returns the error that caused the job to complete unsuccessfully (if any). +func (s *JobStatus) Err() error { + return s.err +} + +// Status retrieves the current status of the job from BigQuery. It fails if the Status could not be determined. +func (j *Job) Status(ctx context.Context) (js *JobStatus, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Job.Status") + defer func() { trace.EndSpan(ctx, err) }() + + bqjob, err := j.c.getJobInternal(ctx, j.jobID, j.location, "status", "statistics") + if err != nil { + return nil, err + } + if err := j.setStatus(bqjob.Status); err != nil { + return nil, err + } + j.setStatistics(bqjob.Statistics, j.c) + return j.lastStatus, nil +} + +// LastStatus returns the most recently retrieved status of the job. The status is +// retrieved when a new job is created, or when JobFromID or Job.Status is called. +// Call Job.Status to get the most up-to-date information about a job. +func (j *Job) LastStatus() *JobStatus { + return j.lastStatus +} + +// Cancel requests that a job be cancelled. This method returns without waiting for +// cancellation to take effect. To check whether the job has terminated, use Job.Status. +// Cancelled jobs may still incur costs. +func (j *Job) Cancel(ctx context.Context) error { + // Jobs.Cancel returns a job entity, but the only relevant piece of + // data it may contain (the status of the job) is unreliable. From the + // docs: "This call will return immediately, and the client will need + // to poll for the job status to see if the cancel completed + // successfully". So it would be misleading to return a status. + call := j.c.bqs.Jobs.Cancel(j.projectID, j.jobID). + Location(j.location). + Fields(). // We don't need any of the response data. + Context(ctx) + setClientHeader(call.Header()) + return runWithRetry(ctx, func() error { + _, err := call.Do() + return err + }) +} + +// Wait blocks until the job or the context is done. It returns the final status +// of the job. +// If an error occurs while retrieving the status, Wait returns that error. But +// Wait returns nil if the status was retrieved successfully, even if +// status.Err() != nil. So callers must check both errors. See the example. +func (j *Job) Wait(ctx context.Context) (js *JobStatus, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Job.Wait") + defer func() { trace.EndSpan(ctx, err) }() + + if j.isQuery() { + // We can avoid polling for query jobs. + if _, _, err := j.waitForQuery(ctx, j.projectID); err != nil { + return nil, err + } + // Note: extra RPC even if you just want to wait for the query to finish. + js, err := j.Status(ctx) + if err != nil { + return nil, err + } + return js, nil + } + // Non-query jobs must poll. + err = internal.Retry(ctx, gax.Backoff{}, func() (stop bool, err error) { + js, err = j.Status(ctx) + if err != nil { + return true, err + } + if js.Done() { + return true, nil + } + return false, nil + }) + if err != nil { + return nil, err + } + return js, nil +} + +// Read fetches the results of a query job. +// If j is not a query job, Read returns an error. +func (j *Job) Read(ctx context.Context) (ri *RowIterator, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Job.Read") + defer func() { trace.EndSpan(ctx, err) }() + + return j.read(ctx, j.waitForQuery, fetchPage) +} + +func (j *Job) read(ctx context.Context, waitForQuery func(context.Context, string) (Schema, uint64, error), pf pageFetcher) (*RowIterator, error) { + if !j.isQuery() { + return nil, errors.New("bigquery: cannot read from a non-query job") + } + destTable := j.config.Query.DestinationTable + // The destination table should only be nil if there was a query error. + projectID := j.projectID + if destTable != nil && projectID != destTable.ProjectId { + return nil, fmt.Errorf("bigquery: job project ID is %q, but destination table's is %q", projectID, destTable.ProjectId) + } + schema, totalRows, err := waitForQuery(ctx, projectID) + if err != nil { + return nil, err + } + if destTable == nil { + return nil, errors.New("bigquery: query job missing destination table") + } + dt := bqToTable(destTable, j.c) + if totalRows == 0 { + pf = nil + } + it := newRowIterator(ctx, dt, pf) + it.Schema = schema + it.TotalRows = totalRows + return it, nil +} + +// waitForQuery waits for the query job to complete and returns its schema. It also +// returns the total number of rows in the result set. +func (j *Job) waitForQuery(ctx context.Context, projectID string) (Schema, uint64, error) { + // Use GetQueryResults only to wait for completion, not to read results. + call := j.c.bqs.Jobs.GetQueryResults(projectID, j.jobID).Location(j.location).Context(ctx).MaxResults(0) + setClientHeader(call.Header()) + backoff := gax.Backoff{ + Initial: 1 * time.Second, + Multiplier: 2, + Max: 60 * time.Second, + } + var res *bq.GetQueryResultsResponse + err := internal.Retry(ctx, backoff, func() (stop bool, err error) { + res, err = call.Do() + if err != nil { + return !retryableError(err), err + } + if !res.JobComplete { // GetQueryResults may return early without error; retry. + return false, nil + } + return true, nil + }) + if err != nil { + return nil, 0, err + } + return bqToSchema(res.Schema), res.TotalRows, nil +} + +// JobStatistics contains statistics about a job. +type JobStatistics struct { + CreationTime time.Time + StartTime time.Time + EndTime time.Time + TotalBytesProcessed int64 + + Details Statistics +} + +// Statistics is one of ExtractStatistics, LoadStatistics or QueryStatistics. +type Statistics interface { + implementsStatistics() +} + +// ExtractStatistics contains statistics about an extract job. +type ExtractStatistics struct { + // The number of files per destination URI or URI pattern specified in the + // extract configuration. These values will be in the same order as the + // URIs specified in the 'destinationUris' field. + DestinationURIFileCounts []int64 +} + +// LoadStatistics contains statistics about a load job. +type LoadStatistics struct { + // The number of bytes of source data in a load job. + InputFileBytes int64 + + // The number of source files in a load job. + InputFiles int64 + + // Size of the loaded data in bytes. Note that while a load job is in the + // running state, this value may change. + OutputBytes int64 + + // The number of rows imported in a load job. Note that while an import job is + // in the running state, this value may change. + OutputRows int64 +} + +// QueryStatistics contains statistics about a query job. +type QueryStatistics struct { + // Billing tier for the job. + BillingTier int64 + + // Whether the query result was fetched from the query cache. + CacheHit bool + + // The type of query statement, if valid. + StatementType string + + // Total bytes billed for the job. + TotalBytesBilled int64 + + // Total bytes processed for the job. + TotalBytesProcessed int64 + + // Describes execution plan for the query. + QueryPlan []*ExplainQueryStage + + // The number of rows affected by a DML statement. Present only for DML + // statements INSERT, UPDATE or DELETE. + NumDMLAffectedRows int64 + + // Describes a timeline of job execution. + Timeline []*QueryTimelineSample + + // ReferencedTables: [Output-only, Experimental] Referenced tables for + // the job. Queries that reference more than 50 tables will not have a + // complete list. + ReferencedTables []*Table + + // The schema of the results. Present only for successful dry run of + // non-legacy SQL queries. + Schema Schema + + // Slot-milliseconds consumed by this query job. + SlotMillis int64 + + // Standard SQL: list of undeclared query parameter names detected during a + // dry run validation. + UndeclaredQueryParameterNames []string + + // DDL target table. + DDLTargetTable *Table + + // DDL Operation performed on the target table. Used to report how the + // query impacted the DDL target table. + DDLOperationPerformed string +} + +// ExplainQueryStage describes one stage of a query. +type ExplainQueryStage struct { + // CompletedParallelInputs: Number of parallel input segments completed. + CompletedParallelInputs int64 + + // ComputeAvg: Duration the average shard spent on CPU-bound tasks. + ComputeAvg time.Duration + + // ComputeMax: Duration the slowest shard spent on CPU-bound tasks. + ComputeMax time.Duration + + // Relative amount of the total time the average shard spent on CPU-bound tasks. + ComputeRatioAvg float64 + + // Relative amount of the total time the slowest shard spent on CPU-bound tasks. + ComputeRatioMax float64 + + // EndTime: Stage end time. + EndTime time.Time + + // Unique ID for stage within plan. + ID int64 + + // InputStages: IDs for stages that are inputs to this stage. + InputStages []int64 + + // Human-readable name for stage. + Name string + + // ParallelInputs: Number of parallel input segments to be processed. + ParallelInputs int64 + + // ReadAvg: Duration the average shard spent reading input. + ReadAvg time.Duration + + // ReadMax: Duration the slowest shard spent reading input. + ReadMax time.Duration + + // Relative amount of the total time the average shard spent reading input. + ReadRatioAvg float64 + + // Relative amount of the total time the slowest shard spent reading input. + ReadRatioMax float64 + + // Number of records read into the stage. + RecordsRead int64 + + // Number of records written by the stage. + RecordsWritten int64 + + // ShuffleOutputBytes: Total number of bytes written to shuffle. + ShuffleOutputBytes int64 + + // ShuffleOutputBytesSpilled: Total number of bytes written to shuffle + // and spilled to disk. + ShuffleOutputBytesSpilled int64 + + // StartTime: Stage start time. + StartTime time.Time + + // Current status for the stage. + Status string + + // List of operations within the stage in dependency order (approximately + // chronological). + Steps []*ExplainQueryStep + + // WaitAvg: Duration the average shard spent waiting to be scheduled. + WaitAvg time.Duration + + // WaitMax: Duration the slowest shard spent waiting to be scheduled. + WaitMax time.Duration + + // Relative amount of the total time the average shard spent waiting to be scheduled. + WaitRatioAvg float64 + + // Relative amount of the total time the slowest shard spent waiting to be scheduled. + WaitRatioMax float64 + + // WriteAvg: Duration the average shard spent on writing output. + WriteAvg time.Duration + + // WriteMax: Duration the slowest shard spent on writing output. + WriteMax time.Duration + + // Relative amount of the total time the average shard spent on writing output. + WriteRatioAvg float64 + + // Relative amount of the total time the slowest shard spent on writing output. + WriteRatioMax float64 +} + +// ExplainQueryStep describes one step of a query stage. +type ExplainQueryStep struct { + // Machine-readable operation type. + Kind string + + // Human-readable stage descriptions. + Substeps []string +} + +// QueryTimelineSample represents a sample of execution statistics at a point in time. +type QueryTimelineSample struct { + + // Total number of units currently being processed by workers, represented as largest value since last sample. + ActiveUnits int64 + + // Total parallel units of work completed by this query. + CompletedUnits int64 + + // Time elapsed since start of query execution. + Elapsed time.Duration + + // Total parallel units of work remaining for the active stages. + PendingUnits int64 + + // Cumulative slot-milliseconds consumed by the query. + SlotMillis int64 +} + +func (*ExtractStatistics) implementsStatistics() {} +func (*LoadStatistics) implementsStatistics() {} +func (*QueryStatistics) implementsStatistics() {} + +// Jobs lists jobs within a project. +func (c *Client) Jobs(ctx context.Context) *JobIterator { + it := &JobIterator{ + ctx: ctx, + c: c, + ProjectID: c.projectID, + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.items) }, + func() interface{} { b := it.items; it.items = nil; return b }) + return it +} + +// JobIterator iterates over jobs in a project. +type JobIterator struct { + ProjectID string // Project ID of the jobs to list. Default is the client's project. + AllUsers bool // Whether to list jobs owned by all users in the project, or just the current caller. + State State // List only jobs in the given state. Defaults to all states. + MinCreationTime time.Time // List only jobs created after this time. + MaxCreationTime time.Time // List only jobs created before this time. + + ctx context.Context + c *Client + pageInfo *iterator.PageInfo + nextFunc func() error + items []*Job +} + +// PageInfo is a getter for the JobIterator's PageInfo. +func (it *JobIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } + +// Next returns the next Job. Its second return value is iterator.Done if +// there are no more results. Once Next returns Done, all subsequent calls will +// return Done. +func (it *JobIterator) Next() (*Job, error) { + if err := it.nextFunc(); err != nil { + return nil, err + } + item := it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *JobIterator) fetch(pageSize int, pageToken string) (string, error) { + var st string + switch it.State { + case StateUnspecified: + st = "" + case Pending: + st = "pending" + case Running: + st = "running" + case Done: + st = "done" + default: + return "", fmt.Errorf("bigquery: invalid value for JobIterator.State: %d", it.State) + } + + req := it.c.bqs.Jobs.List(it.ProjectID). + Context(it.ctx). + PageToken(pageToken). + Projection("full"). + AllUsers(it.AllUsers) + if st != "" { + req.StateFilter(st) + } + if !it.MinCreationTime.IsZero() { + req.MinCreationTime(uint64(it.MinCreationTime.UnixNano() / 1e6)) + } + if !it.MaxCreationTime.IsZero() { + req.MaxCreationTime(uint64(it.MaxCreationTime.UnixNano() / 1e6)) + } + setClientHeader(req.Header()) + if pageSize > 0 { + req.MaxResults(int64(pageSize)) + } + res, err := req.Do() + if err != nil { + return "", err + } + for _, j := range res.Jobs { + job, err := convertListedJob(j, it.c) + if err != nil { + return "", err + } + it.items = append(it.items, job) + } + return res.NextPageToken, nil +} + +func convertListedJob(j *bq.JobListJobs, c *Client) (*Job, error) { + return bqToJob2(j.JobReference, j.Configuration, j.Status, j.Statistics, j.UserEmail, c) +} + +func (c *Client) getJobInternal(ctx context.Context, jobID, location string, fields ...googleapi.Field) (*bq.Job, error) { + var job *bq.Job + call := c.bqs.Jobs.Get(c.projectID, jobID).Context(ctx) + if location != "" { + call = call.Location(location) + } + if len(fields) > 0 { + call = call.Fields(fields...) + } + setClientHeader(call.Header()) + err := runWithRetry(ctx, func() (err error) { + job, err = call.Do() + return err + }) + if err != nil { + return nil, err + } + return job, nil +} + +func bqToJob(q *bq.Job, c *Client) (*Job, error) { + return bqToJob2(q.JobReference, q.Configuration, q.Status, q.Statistics, q.UserEmail, c) +} + +func bqToJob2(qr *bq.JobReference, qc *bq.JobConfiguration, qs *bq.JobStatus, qt *bq.JobStatistics, email string, c *Client) (*Job, error) { + j := &Job{ + projectID: qr.ProjectId, + jobID: qr.JobId, + location: qr.Location, + c: c, + email: email, + } + j.setConfig(qc) + if err := j.setStatus(qs); err != nil { + return nil, err + } + j.setStatistics(qt, c) + return j, nil +} + +func (j *Job) setConfig(config *bq.JobConfiguration) { + if config == nil { + return + } + j.config = config +} + +func (j *Job) isQuery() bool { + return j.config != nil && j.config.Query != nil +} + +var stateMap = map[string]State{"PENDING": Pending, "RUNNING": Running, "DONE": Done} + +func (j *Job) setStatus(qs *bq.JobStatus) error { + if qs == nil { + return nil + } + state, ok := stateMap[qs.State] + if !ok { + return fmt.Errorf("unexpected job state: %v", qs.State) + } + j.lastStatus = &JobStatus{ + State: state, + err: nil, + } + if err := bqToError(qs.ErrorResult); state == Done && err != nil { + j.lastStatus.err = err + } + for _, ep := range qs.Errors { + j.lastStatus.Errors = append(j.lastStatus.Errors, bqToError(ep)) + } + return nil +} + +func (j *Job) setStatistics(s *bq.JobStatistics, c *Client) { + if s == nil || j.lastStatus == nil { + return + } + js := &JobStatistics{ + CreationTime: unixMillisToTime(s.CreationTime), + StartTime: unixMillisToTime(s.StartTime), + EndTime: unixMillisToTime(s.EndTime), + TotalBytesProcessed: s.TotalBytesProcessed, + } + switch { + case s.Extract != nil: + js.Details = &ExtractStatistics{ + DestinationURIFileCounts: []int64(s.Extract.DestinationUriFileCounts), + } + case s.Load != nil: + js.Details = &LoadStatistics{ + InputFileBytes: s.Load.InputFileBytes, + InputFiles: s.Load.InputFiles, + OutputBytes: s.Load.OutputBytes, + OutputRows: s.Load.OutputRows, + } + case s.Query != nil: + var names []string + for _, qp := range s.Query.UndeclaredQueryParameters { + names = append(names, qp.Name) + } + var tables []*Table + for _, tr := range s.Query.ReferencedTables { + tables = append(tables, bqToTable(tr, c)) + } + js.Details = &QueryStatistics{ + BillingTier: s.Query.BillingTier, + CacheHit: s.Query.CacheHit, + DDLTargetTable: bqToTable(s.Query.DdlTargetTable, c), + DDLOperationPerformed: s.Query.DdlOperationPerformed, + StatementType: s.Query.StatementType, + TotalBytesBilled: s.Query.TotalBytesBilled, + TotalBytesProcessed: s.Query.TotalBytesProcessed, + NumDMLAffectedRows: s.Query.NumDmlAffectedRows, + QueryPlan: queryPlanFromProto(s.Query.QueryPlan), + Schema: bqToSchema(s.Query.Schema), + SlotMillis: s.Query.TotalSlotMs, + Timeline: timelineFromProto(s.Query.Timeline), + ReferencedTables: tables, + UndeclaredQueryParameterNames: names, + } + } + j.lastStatus.Statistics = js +} + +func queryPlanFromProto(stages []*bq.ExplainQueryStage) []*ExplainQueryStage { + var res []*ExplainQueryStage + for _, s := range stages { + var steps []*ExplainQueryStep + for _, p := range s.Steps { + steps = append(steps, &ExplainQueryStep{ + Kind: p.Kind, + Substeps: p.Substeps, + }) + } + res = append(res, &ExplainQueryStage{ + CompletedParallelInputs: s.CompletedParallelInputs, + ComputeAvg: time.Duration(s.ComputeMsAvg) * time.Millisecond, + ComputeMax: time.Duration(s.ComputeMsMax) * time.Millisecond, + ComputeRatioAvg: s.ComputeRatioAvg, + ComputeRatioMax: s.ComputeRatioMax, + EndTime: time.Unix(0, s.EndMs*1e6), + ID: s.Id, + InputStages: s.InputStages, + Name: s.Name, + ParallelInputs: s.ParallelInputs, + ReadAvg: time.Duration(s.ReadMsAvg) * time.Millisecond, + ReadMax: time.Duration(s.ReadMsMax) * time.Millisecond, + ReadRatioAvg: s.ReadRatioAvg, + ReadRatioMax: s.ReadRatioMax, + RecordsRead: s.RecordsRead, + RecordsWritten: s.RecordsWritten, + ShuffleOutputBytes: s.ShuffleOutputBytes, + ShuffleOutputBytesSpilled: s.ShuffleOutputBytesSpilled, + StartTime: time.Unix(0, s.StartMs*1e6), + Status: s.Status, + Steps: steps, + WaitAvg: time.Duration(s.WaitMsAvg) * time.Millisecond, + WaitMax: time.Duration(s.WaitMsMax) * time.Millisecond, + WaitRatioAvg: s.WaitRatioAvg, + WaitRatioMax: s.WaitRatioMax, + WriteAvg: time.Duration(s.WriteMsAvg) * time.Millisecond, + WriteMax: time.Duration(s.WriteMsMax) * time.Millisecond, + WriteRatioAvg: s.WriteRatioAvg, + WriteRatioMax: s.WriteRatioMax, + }) + } + return res +} + +func timelineFromProto(timeline []*bq.QueryTimelineSample) []*QueryTimelineSample { + var res []*QueryTimelineSample + for _, s := range timeline { + res = append(res, &QueryTimelineSample{ + ActiveUnits: s.ActiveUnits, + CompletedUnits: s.CompletedUnits, + Elapsed: time.Duration(s.ElapsedMs) * time.Millisecond, + PendingUnits: s.PendingUnits, + SlotMillis: s.TotalSlotMs, + }) + } + return res +} diff --git a/vendor/cloud.google.com/go/bigquery/job_test.go b/vendor/cloud.google.com/go/bigquery/job_test.go new file mode 100644 index 00000000..fbde305a --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/job_test.go @@ -0,0 +1,95 @@ +// Copyright 2017 Google LLC +// +// 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 bigquery + +import ( + "testing" + + "cloud.google.com/go/internal/testutil" + bq "google.golang.org/api/bigquery/v2" +) + +func TestCreateJobRef(t *testing.T) { + defer fixRandomID("RANDOM")() + cNoLoc := &Client{projectID: "projectID"} + cLoc := &Client{projectID: "projectID", Location: "defaultLoc"} + for _, test := range []struct { + in JobIDConfig + client *Client + want *bq.JobReference + }{ + { + in: JobIDConfig{JobID: "foo"}, + want: &bq.JobReference{JobId: "foo"}, + }, + { + in: JobIDConfig{}, + want: &bq.JobReference{JobId: "RANDOM"}, + }, + { + in: JobIDConfig{AddJobIDSuffix: true}, + want: &bq.JobReference{JobId: "RANDOM"}, + }, + { + in: JobIDConfig{JobID: "foo", AddJobIDSuffix: true}, + want: &bq.JobReference{JobId: "foo-RANDOM"}, + }, + { + in: JobIDConfig{JobID: "foo", Location: "loc"}, + want: &bq.JobReference{JobId: "foo", Location: "loc"}, + }, + { + in: JobIDConfig{JobID: "foo"}, + client: cLoc, + want: &bq.JobReference{JobId: "foo", Location: "defaultLoc"}, + }, + { + in: JobIDConfig{JobID: "foo", Location: "loc"}, + client: cLoc, + want: &bq.JobReference{JobId: "foo", Location: "loc"}, + }, + } { + client := test.client + if client == nil { + client = cNoLoc + } + got := test.in.createJobRef(client) + test.want.ProjectId = "projectID" + if !testutil.Equal(got, test.want) { + t.Errorf("%+v: got %+v, want %+v", test.in, got, test.want) + } + } +} + +func fixRandomID(s string) func() { + prev := randomIDFn + randomIDFn = func() string { return s } + return func() { randomIDFn = prev } +} + +func checkJob(t *testing.T, i int, got, want *bq.Job) { + if got.JobReference == nil { + t.Errorf("#%d: empty job reference", i) + return + } + if got.JobReference.JobId == "" { + t.Errorf("#%d: empty job ID", i) + return + } + d := testutil.Diff(got, want) + if d != "" { + t.Errorf("#%d: (got=-, want=+) %s", i, d) + } +} diff --git a/vendor/cloud.google.com/go/bigquery/load.go b/vendor/cloud.google.com/go/bigquery/load.go new file mode 100644 index 00000000..1cbcc84a --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/load.go @@ -0,0 +1,146 @@ +// Copyright 2016 Google LLC +// +// 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 bigquery + +import ( + "context" + "io" + + "cloud.google.com/go/internal/trace" + bq "google.golang.org/api/bigquery/v2" +) + +// LoadConfig holds the configuration for a load job. +type LoadConfig struct { + // Src is the source from which data will be loaded. + Src LoadSource + + // Dst is the table into which the data will be loaded. + Dst *Table + + // CreateDisposition specifies the circumstances under which the destination table will be created. + // The default is CreateIfNeeded. + CreateDisposition TableCreateDisposition + + // WriteDisposition specifies how existing data in the destination table is treated. + // The default is WriteAppend. + WriteDisposition TableWriteDisposition + + // The labels associated with this job. + Labels map[string]string + + // If non-nil, the destination table is partitioned by time. + TimePartitioning *TimePartitioning + + // Clustering specifies the data clustering configuration for the destination table. + Clustering *Clustering + + // Custom encryption configuration (e.g., Cloud KMS keys). + DestinationEncryptionConfig *EncryptionConfig + + // Allows the schema of the destination table to be updated as a side effect of + // the load job. + SchemaUpdateOptions []string +} + +func (l *LoadConfig) toBQ() (*bq.JobConfiguration, io.Reader) { + config := &bq.JobConfiguration{ + Labels: l.Labels, + Load: &bq.JobConfigurationLoad{ + CreateDisposition: string(l.CreateDisposition), + WriteDisposition: string(l.WriteDisposition), + DestinationTable: l.Dst.toBQ(), + TimePartitioning: l.TimePartitioning.toBQ(), + Clustering: l.Clustering.toBQ(), + DestinationEncryptionConfiguration: l.DestinationEncryptionConfig.toBQ(), + SchemaUpdateOptions: l.SchemaUpdateOptions, + }, + } + media := l.Src.populateLoadConfig(config.Load) + return config, media +} + +func bqToLoadConfig(q *bq.JobConfiguration, c *Client) *LoadConfig { + lc := &LoadConfig{ + Labels: q.Labels, + CreateDisposition: TableCreateDisposition(q.Load.CreateDisposition), + WriteDisposition: TableWriteDisposition(q.Load.WriteDisposition), + Dst: bqToTable(q.Load.DestinationTable, c), + TimePartitioning: bqToTimePartitioning(q.Load.TimePartitioning), + Clustering: bqToClustering(q.Load.Clustering), + DestinationEncryptionConfig: bqToEncryptionConfig(q.Load.DestinationEncryptionConfiguration), + SchemaUpdateOptions: q.Load.SchemaUpdateOptions, + } + var fc *FileConfig + if len(q.Load.SourceUris) == 0 { + s := NewReaderSource(nil) + fc = &s.FileConfig + lc.Src = s + } else { + s := NewGCSReference(q.Load.SourceUris...) + fc = &s.FileConfig + lc.Src = s + } + bqPopulateFileConfig(q.Load, fc) + return lc +} + +// A Loader loads data from Google Cloud Storage into a BigQuery table. +type Loader struct { + JobIDConfig + LoadConfig + c *Client +} + +// A LoadSource represents a source of data that can be loaded into +// a BigQuery table. +// +// This package defines two LoadSources: GCSReference, for Google Cloud Storage +// objects, and ReaderSource, for data read from an io.Reader. +type LoadSource interface { + // populates config, returns media + populateLoadConfig(*bq.JobConfigurationLoad) io.Reader +} + +// LoaderFrom returns a Loader which can be used to load data into a BigQuery table. +// The returned Loader may optionally be further configured before its Run method is called. +// See GCSReference and ReaderSource for additional configuration options that +// affect loading. +func (t *Table) LoaderFrom(src LoadSource) *Loader { + return &Loader{ + c: t.c, + LoadConfig: LoadConfig{ + Src: src, + Dst: t, + }, + } +} + +// Run initiates a load job. +func (l *Loader) Run(ctx context.Context) (j *Job, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Load.Run") + defer func() { trace.EndSpan(ctx, err) }() + + job, media := l.newJob() + return l.c.insertJob(ctx, job, media) +} + +func (l *Loader) newJob() (*bq.Job, io.Reader) { + config, media := l.LoadConfig.toBQ() + return &bq.Job{ + JobReference: l.JobIDConfig.createJobRef(l.c), + Configuration: config, + }, media +} diff --git a/vendor/cloud.google.com/go/bigquery/load_test.go b/vendor/cloud.google.com/go/bigquery/load_test.go new file mode 100644 index 00000000..e2af9d07 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/load_test.go @@ -0,0 +1,263 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "strings" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + bq "google.golang.org/api/bigquery/v2" +) + +func defaultLoadJob() *bq.Job { + return &bq.Job{ + JobReference: &bq.JobReference{JobId: "RANDOM", ProjectId: "client-project-id"}, + Configuration: &bq.JobConfiguration{ + Load: &bq.JobConfigurationLoad{ + DestinationTable: &bq.TableReference{ + ProjectId: "client-project-id", + DatasetId: "dataset-id", + TableId: "table-id", + }, + SourceUris: []string{"uri"}, + }, + }, + } +} + +func stringFieldSchema() *FieldSchema { + return &FieldSchema{Name: "fieldname", Type: StringFieldType} +} + +func nestedFieldSchema() *FieldSchema { + return &FieldSchema{ + Name: "nested", + Type: RecordFieldType, + Schema: Schema{stringFieldSchema()}, + } +} + +func bqStringFieldSchema() *bq.TableFieldSchema { + return &bq.TableFieldSchema{ + Name: "fieldname", + Type: "STRING", + } +} + +func bqNestedFieldSchema() *bq.TableFieldSchema { + return &bq.TableFieldSchema{ + Name: "nested", + Type: "RECORD", + Fields: []*bq.TableFieldSchema{bqStringFieldSchema()}, + } +} + +func TestLoad(t *testing.T) { + defer fixRandomID("RANDOM")() + c := &Client{projectID: "client-project-id"} + + testCases := []struct { + dst *Table + src LoadSource + jobID string + location string + config LoadConfig + want *bq.Job + }{ + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: NewGCSReference("uri"), + want: defaultLoadJob(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: NewGCSReference("uri"), + location: "loc", + want: func() *bq.Job { + j := defaultLoadJob() + j.JobReference.Location = "loc" + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + jobID: "ajob", + config: LoadConfig{ + CreateDisposition: CreateNever, + WriteDisposition: WriteTruncate, + Labels: map[string]string{"a": "b"}, + TimePartitioning: &TimePartitioning{Expiration: 1234 * time.Millisecond}, + Clustering: &Clustering{Fields: []string{"cfield1"}}, + DestinationEncryptionConfig: &EncryptionConfig{KMSKeyName: "keyName"}, + SchemaUpdateOptions: []string{"ALLOW_FIELD_ADDITION"}, + }, + src: NewGCSReference("uri"), + want: func() *bq.Job { + j := defaultLoadJob() + j.Configuration.Labels = map[string]string{"a": "b"} + j.Configuration.Load.CreateDisposition = "CREATE_NEVER" + j.Configuration.Load.WriteDisposition = "WRITE_TRUNCATE" + j.Configuration.Load.TimePartitioning = &bq.TimePartitioning{ + Type: "DAY", + ExpirationMs: 1234, + } + j.Configuration.Load.Clustering = &bq.Clustering{ + Fields: []string{"cfield1"}, + } + j.Configuration.Load.DestinationEncryptionConfiguration = &bq.EncryptionConfiguration{KmsKeyName: "keyName"} + j.JobReference = &bq.JobReference{ + JobId: "ajob", + ProjectId: "client-project-id", + } + j.Configuration.Load.SchemaUpdateOptions = []string{"ALLOW_FIELD_ADDITION"} + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: func() *GCSReference { + g := NewGCSReference("uri") + g.MaxBadRecords = 1 + g.AllowJaggedRows = true + g.AllowQuotedNewlines = true + g.IgnoreUnknownValues = true + return g + }(), + want: func() *bq.Job { + j := defaultLoadJob() + j.Configuration.Load.MaxBadRecords = 1 + j.Configuration.Load.AllowJaggedRows = true + j.Configuration.Load.AllowQuotedNewlines = true + j.Configuration.Load.IgnoreUnknownValues = true + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: func() *GCSReference { + g := NewGCSReference("uri") + g.Schema = Schema{ + stringFieldSchema(), + nestedFieldSchema(), + } + return g + }(), + want: func() *bq.Job { + j := defaultLoadJob() + j.Configuration.Load.Schema = &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqStringFieldSchema(), + bqNestedFieldSchema(), + }} + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: func() *GCSReference { + g := NewGCSReference("uri") + g.SkipLeadingRows = 1 + g.SourceFormat = JSON + g.Encoding = UTF_8 + g.FieldDelimiter = "\t" + g.Quote = "-" + return g + }(), + want: func() *bq.Job { + j := defaultLoadJob() + j.Configuration.Load.SkipLeadingRows = 1 + j.Configuration.Load.SourceFormat = "NEWLINE_DELIMITED_JSON" + j.Configuration.Load.Encoding = "UTF-8" + j.Configuration.Load.FieldDelimiter = "\t" + hyphen := "-" + j.Configuration.Load.Quote = &hyphen + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: NewGCSReference("uri"), + want: func() *bq.Job { + j := defaultLoadJob() + // Quote is left unset in GCSReference, so should be nil here. + j.Configuration.Load.Quote = nil + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: func() *GCSReference { + g := NewGCSReference("uri") + g.ForceZeroQuote = true + return g + }(), + want: func() *bq.Job { + j := defaultLoadJob() + empty := "" + j.Configuration.Load.Quote = &empty + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: func() *ReaderSource { + r := NewReaderSource(strings.NewReader("foo")) + r.SkipLeadingRows = 1 + r.SourceFormat = JSON + r.Encoding = UTF_8 + r.FieldDelimiter = "\t" + r.Quote = "-" + return r + }(), + want: func() *bq.Job { + j := defaultLoadJob() + j.Configuration.Load.SourceUris = nil + j.Configuration.Load.SkipLeadingRows = 1 + j.Configuration.Load.SourceFormat = "NEWLINE_DELIMITED_JSON" + j.Configuration.Load.Encoding = "UTF-8" + j.Configuration.Load.FieldDelimiter = "\t" + hyphen := "-" + j.Configuration.Load.Quote = &hyphen + return j + }(), + }, + } + + for i, tc := range testCases { + loader := tc.dst.LoaderFrom(tc.src) + loader.JobID = tc.jobID + loader.Location = tc.location + tc.config.Src = tc.src + tc.config.Dst = tc.dst + loader.LoadConfig = tc.config + got, _ := loader.newJob() + checkJob(t, i, got, tc.want) + + jc, err := bqToJobConfig(got.Configuration, c) + if err != nil { + t.Fatalf("#%d: %v", i, err) + } + diff := testutil.Diff(jc.(*LoadConfig), &loader.LoadConfig, + cmp.AllowUnexported(Table{}, Client{}), + cmpopts.IgnoreUnexported(ReaderSource{})) + if diff != "" { + t.Errorf("#%d: (got=-, want=+:\n%s", i, diff) + } + } +} diff --git a/vendor/cloud.google.com/go/bigquery/nulls.go b/vendor/cloud.google.com/go/bigquery/nulls.go new file mode 100644 index 00000000..5b4fbd96 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/nulls.go @@ -0,0 +1,320 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" + "strconv" + "time" + + "cloud.google.com/go/civil" +) + +// NullInt64 represents a BigQuery INT64 that may be NULL. +type NullInt64 struct { + Int64 int64 + Valid bool // Valid is true if Int64 is not NULL. +} + +func (n NullInt64) String() string { return nullstr(n.Valid, n.Int64) } + +// NullString represents a BigQuery STRING that may be NULL. +type NullString struct { + StringVal string + Valid bool // Valid is true if StringVal is not NULL. +} + +func (n NullString) String() string { return nullstr(n.Valid, n.StringVal) } + +// NullFloat64 represents a BigQuery FLOAT64 that may be NULL. +type NullFloat64 struct { + Float64 float64 + Valid bool // Valid is true if Float64 is not NULL. +} + +func (n NullFloat64) String() string { return nullstr(n.Valid, n.Float64) } + +// NullBool represents a BigQuery BOOL that may be NULL. +type NullBool struct { + Bool bool + Valid bool // Valid is true if Bool is not NULL. +} + +func (n NullBool) String() string { return nullstr(n.Valid, n.Bool) } + +// NullTimestamp represents a BigQuery TIMESTAMP that may be null. +type NullTimestamp struct { + Timestamp time.Time + Valid bool // Valid is true if Time is not NULL. +} + +func (n NullTimestamp) String() string { return nullstr(n.Valid, n.Timestamp) } + +// NullDate represents a BigQuery DATE that may be null. +type NullDate struct { + Date civil.Date + Valid bool // Valid is true if Date is not NULL. +} + +func (n NullDate) String() string { return nullstr(n.Valid, n.Date) } + +// NullTime represents a BigQuery TIME that may be null. +type NullTime struct { + Time civil.Time + Valid bool // Valid is true if Time is not NULL. +} + +func (n NullTime) String() string { + if !n.Valid { + return "" + } + return CivilTimeString(n.Time) +} + +// NullDateTime represents a BigQuery DATETIME that may be null. +type NullDateTime struct { + DateTime civil.DateTime + Valid bool // Valid is true if DateTime is not NULL. +} + +func (n NullDateTime) String() string { + if !n.Valid { + return "" + } + return CivilDateTimeString(n.DateTime) +} + +// MarshalJSON converts the NullInt64 to JSON. +func (n NullInt64) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Int64) } + +// MarshalJSON converts the NullFloat64 to JSON. +func (n NullFloat64) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Float64) } + +// MarshalJSON converts the NullBool to JSON. +func (n NullBool) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Bool) } + +// MarshalJSON converts the NullString to JSON. +func (n NullString) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.StringVal) } + +// MarshalJSON converts the NullTimestamp to JSON. +func (n NullTimestamp) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Timestamp) } + +// MarshalJSON converts the NullDate to JSON. +func (n NullDate) MarshalJSON() ([]byte, error) { return nulljson(n.Valid, n.Date) } + +// MarshalJSON converts the NullTime to JSON. +func (n NullTime) MarshalJSON() ([]byte, error) { + if !n.Valid { + return jsonNull, nil + } + return []byte(`"` + CivilTimeString(n.Time) + `"`), nil +} + +// MarshalJSON converts the NullDateTime to JSON. +func (n NullDateTime) MarshalJSON() ([]byte, error) { + if !n.Valid { + return jsonNull, nil + } + return []byte(`"` + CivilDateTimeString(n.DateTime) + `"`), nil +} + +func nullstr(valid bool, v interface{}) string { + if !valid { + return "NULL" + } + return fmt.Sprint(v) +} + +var jsonNull = []byte("null") + +func nulljson(valid bool, v interface{}) ([]byte, error) { + if !valid { + return jsonNull, nil + } + return json.Marshal(v) +} + +// UnmarshalJSON converts JSON into a NullInt64. +func (n *NullInt64) UnmarshalJSON(b []byte) error { + n.Valid = false + n.Int64 = 0 + if bytes.Equal(b, jsonNull) { + return nil + } + + if err := json.Unmarshal(b, &n.Int64); err != nil { + return err + } + n.Valid = true + return nil +} + +// UnmarshalJSON converts JSON into a NullFloat64. +func (n *NullFloat64) UnmarshalJSON(b []byte) error { + n.Valid = false + n.Float64 = 0 + if bytes.Equal(b, jsonNull) { + return nil + } + + if err := json.Unmarshal(b, &n.Float64); err != nil { + return err + } + n.Valid = true + return nil +} + +// UnmarshalJSON converts JSON into a NullBool. +func (n *NullBool) UnmarshalJSON(b []byte) error { + n.Valid = false + n.Bool = false + if bytes.Equal(b, jsonNull) { + return nil + } + + if err := json.Unmarshal(b, &n.Bool); err != nil { + return err + } + n.Valid = true + return nil +} + +// UnmarshalJSON converts JSON into a NullString. +func (n *NullString) UnmarshalJSON(b []byte) error { + n.Valid = false + n.StringVal = "" + if bytes.Equal(b, jsonNull) { + return nil + } + + if err := json.Unmarshal(b, &n.StringVal); err != nil { + return err + } + n.Valid = true + return nil +} + +// UnmarshalJSON converts JSON into a NullTimestamp. +func (n *NullTimestamp) UnmarshalJSON(b []byte) error { + n.Valid = false + n.Timestamp = time.Time{} + if bytes.Equal(b, jsonNull) { + return nil + } + + if err := json.Unmarshal(b, &n.Timestamp); err != nil { + return err + } + n.Valid = true + return nil +} + +// UnmarshalJSON converts JSON into a NullDate. +func (n *NullDate) UnmarshalJSON(b []byte) error { + n.Valid = false + n.Date = civil.Date{} + if bytes.Equal(b, jsonNull) { + return nil + } + + if err := json.Unmarshal(b, &n.Date); err != nil { + return err + } + n.Valid = true + return nil +} + +// UnmarshalJSON converts JSON into a NullTime. +func (n *NullTime) UnmarshalJSON(b []byte) error { + n.Valid = false + n.Time = civil.Time{} + if bytes.Equal(b, jsonNull) { + return nil + } + + s, err := strconv.Unquote(string(b)) + if err != nil { + return err + } + + t, err := civil.ParseTime(s) + if err != nil { + return err + } + n.Time = t + + n.Valid = true + return nil +} + +// UnmarshalJSON converts JSON into a NullDateTime. +func (n *NullDateTime) UnmarshalJSON(b []byte) error { + n.Valid = false + n.DateTime = civil.DateTime{} + if bytes.Equal(b, jsonNull) { + return nil + } + + s, err := strconv.Unquote(string(b)) + if err != nil { + return err + } + + dt, err := parseCivilDateTime(s) + if err != nil { + return err + } + n.DateTime = dt + + n.Valid = true + return nil +} + +var ( + typeOfNullInt64 = reflect.TypeOf(NullInt64{}) + typeOfNullFloat64 = reflect.TypeOf(NullFloat64{}) + typeOfNullBool = reflect.TypeOf(NullBool{}) + typeOfNullString = reflect.TypeOf(NullString{}) + typeOfNullTimestamp = reflect.TypeOf(NullTimestamp{}) + typeOfNullDate = reflect.TypeOf(NullDate{}) + typeOfNullTime = reflect.TypeOf(NullTime{}) + typeOfNullDateTime = reflect.TypeOf(NullDateTime{}) +) + +func nullableFieldType(t reflect.Type) FieldType { + switch t { + case typeOfNullInt64: + return IntegerFieldType + case typeOfNullFloat64: + return FloatFieldType + case typeOfNullBool: + return BooleanFieldType + case typeOfNullString: + return StringFieldType + case typeOfNullTimestamp: + return TimestampFieldType + case typeOfNullDate: + return DateFieldType + case typeOfNullTime: + return TimeFieldType + case typeOfNullDateTime: + return DateTimeFieldType + default: + return "" + } +} diff --git a/vendor/cloud.google.com/go/bigquery/nulls_test.go b/vendor/cloud.google.com/go/bigquery/nulls_test.go new file mode 100644 index 00000000..144e8e0e --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/nulls_test.go @@ -0,0 +1,73 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "encoding/json" + "reflect" + "testing" + + "cloud.google.com/go/civil" + "cloud.google.com/go/internal/testutil" +) + +var ( + nullsTestTime = civil.Time{Hour: 7, Minute: 50, Second: 22, Nanosecond: 1000} + nullsTestDateTime = civil.DateTime{Date: civil.Date{Year: 2016, Month: 11, Day: 5}, Time: nullsTestTime} +) + +func TestNullsJSON(t *testing.T) { + for _, test := range []struct { + in interface{} + want string + }{ + {&NullInt64{Valid: true, Int64: 3}, `3`}, + {&NullFloat64{Valid: true, Float64: 3.14}, `3.14`}, + {&NullBool{Valid: true, Bool: true}, `true`}, + {&NullString{Valid: true, StringVal: "foo"}, `"foo"`}, + {&NullTimestamp{Valid: true, Timestamp: testTimestamp}, `"2016-11-05T07:50:22.000000008Z"`}, + {&NullDate{Valid: true, Date: testDate}, `"2016-11-05"`}, + {&NullTime{Valid: true, Time: nullsTestTime}, `"07:50:22.000001"`}, + {&NullDateTime{Valid: true, DateTime: nullsTestDateTime}, `"2016-11-05 07:50:22.000001"`}, + + {&NullInt64{}, `null`}, + {&NullFloat64{}, `null`}, + {&NullBool{}, `null`}, + {&NullString{}, `null`}, + {&NullTimestamp{}, `null`}, + {&NullDate{}, `null`}, + {&NullTime{}, `null`}, + {&NullDateTime{}, `null`}, + } { + bytes, err := json.Marshal(test.in) + if err != nil { + t.Fatal(err) + } + if got, want := string(bytes), test.want; got != want { + t.Errorf("%#v: got %s, want %s", test.in, got, want) + } + + typ := reflect.Indirect(reflect.ValueOf(test.in)).Type() + value := reflect.New(typ).Interface() + err = json.Unmarshal(bytes, value) + if err != nil { + t.Fatal(err) + } + + if !testutil.Equal(value, test.in) { + t.Errorf("%#v: got %#v, want %#v", test.in, value, test.in) + } + } +} diff --git a/vendor/cloud.google.com/go/bigquery/oc_test.go b/vendor/cloud.google.com/go/bigquery/oc_test.go new file mode 100644 index 00000000..de85173f --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/oc_test.go @@ -0,0 +1,38 @@ +// Copyright 2018 Google LLC +// +// 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 bigquery + +import ( + "context" + "testing" + + "cloud.google.com/go/internal/testutil" +) + +func TestOCTracing(t *testing.T) { + ctx := context.Background() + client := getClient(t) + defer client.Close() + + te := testutil.NewTestExporter() + defer te.Unregister() + + q := client.Query("select *") + q.Run(ctx) // Doesn't matter if we get an error; span should be created either way + + if len(te.Spans) == 0 { + t.Fatalf("Expected some spans to be created, but got %d", 0) + } +} diff --git a/vendor/cloud.google.com/go/bigquery/params.go b/vendor/cloud.google.com/go/bigquery/params.go new file mode 100644 index 00000000..fb79947a --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/params.go @@ -0,0 +1,356 @@ +// Copyright 2016 Google LLC +// +// 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 bigquery + +import ( + "encoding/base64" + "errors" + "fmt" + "math/big" + "reflect" + "regexp" + "time" + + "cloud.google.com/go/civil" + "cloud.google.com/go/internal/fields" + bq "google.golang.org/api/bigquery/v2" +) + +var ( + // See https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#timestamp-type. + timestampFormat = "2006-01-02 15:04:05.999999-07:00" + + // See https://cloud.google.com/bigquery/docs/reference/rest/v2/tables#schema.fields.name + validFieldName = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]{0,127}$") +) + +const nullableTagOption = "nullable" + +func bqTagParser(t reflect.StructTag) (name string, keep bool, other interface{}, err error) { + name, keep, opts, err := fields.ParseStandardTag("bigquery", t) + if err != nil { + return "", false, nil, err + } + if name != "" && !validFieldName.MatchString(name) { + return "", false, nil, errInvalidFieldName + } + for _, opt := range opts { + if opt != nullableTagOption { + return "", false, nil, fmt.Errorf( + "bigquery: invalid tag option %q. The only valid option is %q", + opt, nullableTagOption) + } + } + return name, keep, opts, nil +} + +var fieldCache = fields.NewCache(bqTagParser, nil, nil) + +var ( + int64ParamType = &bq.QueryParameterType{Type: "INT64"} + float64ParamType = &bq.QueryParameterType{Type: "FLOAT64"} + boolParamType = &bq.QueryParameterType{Type: "BOOL"} + stringParamType = &bq.QueryParameterType{Type: "STRING"} + bytesParamType = &bq.QueryParameterType{Type: "BYTES"} + dateParamType = &bq.QueryParameterType{Type: "DATE"} + timeParamType = &bq.QueryParameterType{Type: "TIME"} + dateTimeParamType = &bq.QueryParameterType{Type: "DATETIME"} + timestampParamType = &bq.QueryParameterType{Type: "TIMESTAMP"} + numericParamType = &bq.QueryParameterType{Type: "NUMERIC"} +) + +var ( + typeOfDate = reflect.TypeOf(civil.Date{}) + typeOfTime = reflect.TypeOf(civil.Time{}) + typeOfDateTime = reflect.TypeOf(civil.DateTime{}) + typeOfGoTime = reflect.TypeOf(time.Time{}) + typeOfRat = reflect.TypeOf(&big.Rat{}) +) + +// A QueryParameter is a parameter to a query. +type QueryParameter struct { + // Name is used for named parameter mode. + // It must match the name in the query case-insensitively. + Name string + + // Value is the value of the parameter. + // + // When you create a QueryParameter to send to BigQuery, the following Go types + // are supported, with their corresponding Bigquery types: + // int, int8, int16, int32, int64, uint8, uint16, uint32: INT64 + // Note that uint, uint64 and uintptr are not supported, because + // they may contain values that cannot fit into a 64-bit signed integer. + // float32, float64: FLOAT64 + // bool: BOOL + // string: STRING + // []byte: BYTES + // time.Time: TIMESTAMP + // *big.Rat: NUMERIC + // Arrays and slices of the above. + // Structs of the above. Only the exported fields are used. + // + // When a QueryParameter is returned inside a QueryConfig from a call to + // Job.Config: + // Integers are of type int64. + // Floating-point values are of type float64. + // Arrays are of type []interface{}, regardless of the array element type. + // Structs are of type map[string]interface{}. + Value interface{} +} + +func (p QueryParameter) toBQ() (*bq.QueryParameter, error) { + pv, err := paramValue(reflect.ValueOf(p.Value)) + if err != nil { + return nil, err + } + pt, err := paramType(reflect.TypeOf(p.Value)) + if err != nil { + return nil, err + } + return &bq.QueryParameter{ + Name: p.Name, + ParameterValue: &pv, + ParameterType: pt, + }, nil +} + +func paramType(t reflect.Type) (*bq.QueryParameterType, error) { + if t == nil { + return nil, errors.New("bigquery: nil parameter") + } + switch t { + case typeOfDate: + return dateParamType, nil + case typeOfTime: + return timeParamType, nil + case typeOfDateTime: + return dateTimeParamType, nil + case typeOfGoTime: + return timestampParamType, nil + case typeOfRat: + return numericParamType, nil + } + switch t.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32: + return int64ParamType, nil + + case reflect.Float32, reflect.Float64: + return float64ParamType, nil + + case reflect.Bool: + return boolParamType, nil + + case reflect.String: + return stringParamType, nil + + case reflect.Slice: + if t.Elem().Kind() == reflect.Uint8 { + return bytesParamType, nil + } + fallthrough + + case reflect.Array: + et, err := paramType(t.Elem()) + if err != nil { + return nil, err + } + return &bq.QueryParameterType{Type: "ARRAY", ArrayType: et}, nil + + case reflect.Ptr: + if t.Elem().Kind() != reflect.Struct { + break + } + t = t.Elem() + fallthrough + + case reflect.Struct: + var fts []*bq.QueryParameterTypeStructTypes + fields, err := fieldCache.Fields(t) + if err != nil { + return nil, err + } + for _, f := range fields { + pt, err := paramType(f.Type) + if err != nil { + return nil, err + } + fts = append(fts, &bq.QueryParameterTypeStructTypes{ + Name: f.Name, + Type: pt, + }) + } + return &bq.QueryParameterType{Type: "STRUCT", StructTypes: fts}, nil + } + return nil, fmt.Errorf("bigquery: Go type %s cannot be represented as a parameter type", t) +} + +func paramValue(v reflect.Value) (bq.QueryParameterValue, error) { + var res bq.QueryParameterValue + if !v.IsValid() { + return res, errors.New("bigquery: nil parameter") + } + t := v.Type() + switch t { + case typeOfDate: + res.Value = v.Interface().(civil.Date).String() + return res, nil + + case typeOfTime: + // civil.Time has nanosecond resolution, but BigQuery TIME only microsecond. + // (If we send nanoseconds, then when we try to read the result we get "query job + // missing destination table"). + res.Value = CivilTimeString(v.Interface().(civil.Time)) + return res, nil + + case typeOfDateTime: + res.Value = CivilDateTimeString(v.Interface().(civil.DateTime)) + return res, nil + + case typeOfGoTime: + res.Value = v.Interface().(time.Time).Format(timestampFormat) + return res, nil + + case typeOfRat: + res.Value = NumericString(v.Interface().(*big.Rat)) + return res, nil + } + switch t.Kind() { + case reflect.Slice: + if t.Elem().Kind() == reflect.Uint8 { + res.Value = base64.StdEncoding.EncodeToString(v.Interface().([]byte)) + return res, nil + } + fallthrough + + case reflect.Array: + var vals []*bq.QueryParameterValue + for i := 0; i < v.Len(); i++ { + val, err := paramValue(v.Index(i)) + if err != nil { + return bq.QueryParameterValue{}, err + } + vals = append(vals, &val) + } + return bq.QueryParameterValue{ArrayValues: vals}, nil + + case reflect.Ptr: + if t.Elem().Kind() != reflect.Struct { + return res, fmt.Errorf("bigquery: Go type %s cannot be represented as a parameter value", t) + } + t = t.Elem() + v = v.Elem() + if !v.IsValid() { + // nil pointer becomes empty value + return res, nil + } + fallthrough + + case reflect.Struct: + fields, err := fieldCache.Fields(t) + if err != nil { + return bq.QueryParameterValue{}, err + } + res.StructValues = map[string]bq.QueryParameterValue{} + for _, f := range fields { + fv := v.FieldByIndex(f.Index) + fp, err := paramValue(fv) + if err != nil { + return bq.QueryParameterValue{}, err + } + res.StructValues[f.Name] = fp + } + return res, nil + } + // None of the above: assume a scalar type. (If it's not a valid type, + // paramType will catch the error.) + res.Value = fmt.Sprint(v.Interface()) + return res, nil +} + +func bqToQueryParameter(q *bq.QueryParameter) (QueryParameter, error) { + p := QueryParameter{Name: q.Name} + val, err := convertParamValue(q.ParameterValue, q.ParameterType) + if err != nil { + return QueryParameter{}, err + } + p.Value = val + return p, nil +} + +var paramTypeToFieldType = map[string]FieldType{ + int64ParamType.Type: IntegerFieldType, + float64ParamType.Type: FloatFieldType, + boolParamType.Type: BooleanFieldType, + stringParamType.Type: StringFieldType, + bytesParamType.Type: BytesFieldType, + dateParamType.Type: DateFieldType, + timeParamType.Type: TimeFieldType, + numericParamType.Type: NumericFieldType, +} + +// Convert a parameter value from the service to a Go value. This is similar to, but +// not quite the same as, converting data values. +func convertParamValue(qval *bq.QueryParameterValue, qtype *bq.QueryParameterType) (interface{}, error) { + switch qtype.Type { + case "ARRAY": + if qval == nil { + return []interface{}(nil), nil + } + return convertParamArray(qval.ArrayValues, qtype.ArrayType) + case "STRUCT": + if qval == nil { + return map[string]interface{}(nil), nil + } + return convertParamStruct(qval.StructValues, qtype.StructTypes) + case "TIMESTAMP": + return time.Parse(timestampFormat, qval.Value) + case "DATETIME": + return parseCivilDateTime(qval.Value) + default: + return convertBasicType(qval.Value, paramTypeToFieldType[qtype.Type]) + } +} + +// convertParamArray converts a query parameter array value to a Go value. It +// always returns a []interface{}. +func convertParamArray(elVals []*bq.QueryParameterValue, elType *bq.QueryParameterType) ([]interface{}, error) { + var vals []interface{} + for _, el := range elVals { + val, err := convertParamValue(el, elType) + if err != nil { + return nil, err + } + vals = append(vals, val) + } + return vals, nil +} + +// convertParamStruct converts a query parameter struct value into a Go value. It +// always returns a map[string]interface{}. +func convertParamStruct(sVals map[string]bq.QueryParameterValue, sTypes []*bq.QueryParameterTypeStructTypes) (map[string]interface{}, error) { + vals := map[string]interface{}{} + for _, st := range sTypes { + if sv, ok := sVals[st.Name]; ok { + val, err := convertParamValue(&sv, st.Type) + if err != nil { + return nil, err + } + vals[st.Name] = val + } else { + vals[st.Name] = nil + } + } + return vals, nil +} diff --git a/vendor/cloud.google.com/go/bigquery/params_test.go b/vendor/cloud.google.com/go/bigquery/params_test.go new file mode 100644 index 00000000..6464e796 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/params_test.go @@ -0,0 +1,362 @@ +// Copyright 2016 Google LLC +// +// 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 bigquery + +import ( + "context" + "errors" + "math" + "math/big" + "reflect" + "testing" + "time" + + "cloud.google.com/go/civil" + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" + bq "google.golang.org/api/bigquery/v2" +) + +var scalarTests = []struct { + val interface{} // The Go value + wantVal string // paramValue's desired output + wantType *bq.QueryParameterType // paramType's desired output +}{ + {int64(0), "0", int64ParamType}, + {3.14, "3.14", float64ParamType}, + {3.14159e-87, "3.14159e-87", float64ParamType}, + {true, "true", boolParamType}, + {"string", "string", stringParamType}, + {"\u65e5\u672c\u8a9e\n", "\u65e5\u672c\u8a9e\n", stringParamType}, + {math.NaN(), "NaN", float64ParamType}, + {[]byte("foo"), "Zm9v", bytesParamType}, // base64 encoding of "foo" + {time.Date(2016, 3, 20, 4, 22, 9, 5000, time.FixedZone("neg1-2", -3720)), + "2016-03-20 04:22:09.000005-01:02", + timestampParamType}, + {civil.Date{Year: 2016, Month: 3, Day: 20}, "2016-03-20", dateParamType}, + {civil.Time{Hour: 4, Minute: 5, Second: 6, Nanosecond: 789000000}, "04:05:06.789000", timeParamType}, + {civil.DateTime{Date: civil.Date{Year: 2016, Month: 3, Day: 20}, Time: civil.Time{Hour: 4, Minute: 5, Second: 6, Nanosecond: 789000000}}, + "2016-03-20 04:05:06.789000", + dateTimeParamType}, + {big.NewRat(12345, 1000), "12.345000000", numericParamType}, +} + +type ( + S1 struct { + A int + B *S2 + C bool + } + S2 struct { + D string + e int + } +) + +var ( + s1 = S1{ + A: 1, + B: &S2{D: "s"}, + C: true, + } + + s1ParamType = &bq.QueryParameterType{ + Type: "STRUCT", + StructTypes: []*bq.QueryParameterTypeStructTypes{ + {Name: "A", Type: int64ParamType}, + {Name: "B", Type: &bq.QueryParameterType{ + Type: "STRUCT", + StructTypes: []*bq.QueryParameterTypeStructTypes{ + {Name: "D", Type: stringParamType}, + }, + }}, + {Name: "C", Type: boolParamType}, + }, + } + + s1ParamValue = bq.QueryParameterValue{ + StructValues: map[string]bq.QueryParameterValue{ + "A": sval("1"), + "B": { + StructValues: map[string]bq.QueryParameterValue{ + "D": sval("s"), + }, + }, + "C": sval("true"), + }, + } + + s1ParamReturnValue = map[string]interface{}{ + "A": int64(1), + "B": map[string]interface{}{"D": "s"}, + "C": true, + } +) + +func sval(s string) bq.QueryParameterValue { + return bq.QueryParameterValue{Value: s} +} + +func TestParamValueScalar(t *testing.T) { + for _, test := range scalarTests { + got, err := paramValue(reflect.ValueOf(test.val)) + if err != nil { + t.Errorf("%v: got %v, want nil", test.val, err) + continue + } + want := sval(test.wantVal) + if !testutil.Equal(got, want) { + t.Errorf("%v:\ngot %+v\nwant %+v", test.val, got, want) + } + } +} + +func TestParamValueArray(t *testing.T) { + qpv := bq.QueryParameterValue{ArrayValues: []*bq.QueryParameterValue{ + {Value: "1"}, + {Value: "2"}, + }, + } + for _, test := range []struct { + val interface{} + want bq.QueryParameterValue + }{ + {[]int(nil), bq.QueryParameterValue{}}, + {[]int{}, bq.QueryParameterValue{}}, + {[]int{1, 2}, qpv}, + {[2]int{1, 2}, qpv}, + } { + got, err := paramValue(reflect.ValueOf(test.val)) + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(got, test.want) { + t.Errorf("%#v:\ngot %+v\nwant %+v", test.val, got, test.want) + } + } +} + +func TestParamValueStruct(t *testing.T) { + got, err := paramValue(reflect.ValueOf(s1)) + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(got, s1ParamValue) { + t.Errorf("got %+v\nwant %+v", got, s1ParamValue) + } +} + +func TestParamValueErrors(t *testing.T) { + // paramValue lets a few invalid types through, but paramType catches them. + // Since we never call one without the other that's fine. + for _, val := range []interface{}{nil, new([]int)} { + _, err := paramValue(reflect.ValueOf(val)) + if err == nil { + t.Errorf("%v (%T): got nil, want error", val, val) + } + } +} + +func TestParamType(t *testing.T) { + for _, test := range scalarTests { + got, err := paramType(reflect.TypeOf(test.val)) + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(got, test.wantType) { + t.Errorf("%v (%T): got %v, want %v", test.val, test.val, got, test.wantType) + } + } + for _, test := range []struct { + val interface{} + want *bq.QueryParameterType + }{ + {uint32(32767), int64ParamType}, + {[]byte("foo"), bytesParamType}, + {[]int{}, &bq.QueryParameterType{Type: "ARRAY", ArrayType: int64ParamType}}, + {[3]bool{}, &bq.QueryParameterType{Type: "ARRAY", ArrayType: boolParamType}}, + {S1{}, s1ParamType}, + } { + got, err := paramType(reflect.TypeOf(test.val)) + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(got, test.want) { + t.Errorf("%v (%T): got %v, want %v", test.val, test.val, got, test.want) + } + } +} + +func TestParamTypeErrors(t *testing.T) { + for _, val := range []interface{}{ + nil, uint(0), new([]int), make(chan int), + } { + _, err := paramType(reflect.TypeOf(val)) + if err == nil { + t.Errorf("%v (%T): got nil, want error", val, val) + } + } +} + +func TestConvertParamValue(t *testing.T) { + // Scalars. + for _, test := range scalarTests { + pval, err := paramValue(reflect.ValueOf(test.val)) + if err != nil { + t.Fatal(err) + } + ptype, err := paramType(reflect.TypeOf(test.val)) + if err != nil { + t.Fatal(err) + } + got, err := convertParamValue(&pval, ptype) + if err != nil { + t.Fatalf("convertParamValue(%+v, %+v): %v", pval, ptype, err) + } + if !testutil.Equal(got, test.val) { + t.Errorf("%#v: got %#v", test.val, got) + } + } + // Arrays. + for _, test := range []struct { + pval *bq.QueryParameterValue + want []interface{} + }{ + { + &bq.QueryParameterValue{}, + nil, + }, + { + &bq.QueryParameterValue{ + ArrayValues: []*bq.QueryParameterValue{{Value: "1"}, {Value: "2"}}, + }, + []interface{}{int64(1), int64(2)}, + }, + } { + ptype := &bq.QueryParameterType{Type: "ARRAY", ArrayType: int64ParamType} + got, err := convertParamValue(test.pval, ptype) + if err != nil { + t.Fatalf("%+v: %v", test.pval, err) + } + if !testutil.Equal(got, test.want) { + t.Errorf("%+v: got %+v, want %+v", test.pval, got, test.want) + } + } + // Structs. + got, err := convertParamValue(&s1ParamValue, s1ParamType) + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(got, s1ParamReturnValue) { + t.Errorf("got %+v, want %+v", got, s1ParamReturnValue) + } +} + +func TestIntegration_ScalarParam(t *testing.T) { + roundToMicros := cmp.Transformer("RoundToMicros", + func(t time.Time) time.Time { return t.Round(time.Microsecond) }) + c := getClient(t) + for _, test := range scalarTests { + gotData, gotParam, err := paramRoundTrip(c, test.val) + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(gotData, test.val, roundToMicros) { + t.Errorf("\ngot %#v (%T)\nwant %#v (%T)", gotData, gotData, test.val, test.val) + } + if !testutil.Equal(gotParam, test.val, roundToMicros) { + t.Errorf("\ngot %#v (%T)\nwant %#v (%T)", gotParam, gotParam, test.val, test.val) + } + } +} + +func TestIntegration_OtherParam(t *testing.T) { + c := getClient(t) + for _, test := range []struct { + val interface{} + wantData interface{} + wantParam interface{} + }{ + {[]int(nil), []Value(nil), []interface{}(nil)}, + {[]int{}, []Value(nil), []interface{}(nil)}, + { + []int{1, 2}, + []Value{int64(1), int64(2)}, + []interface{}{int64(1), int64(2)}, + }, + { + [3]int{1, 2, 3}, + []Value{int64(1), int64(2), int64(3)}, + []interface{}{int64(1), int64(2), int64(3)}, + }, + { + S1{}, + []Value{int64(0), nil, false}, + map[string]interface{}{ + "A": int64(0), + "B": nil, + "C": false, + }, + }, + { + s1, + []Value{int64(1), []Value{"s"}, true}, + s1ParamReturnValue, + }, + } { + gotData, gotParam, err := paramRoundTrip(c, test.val) + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(gotData, test.wantData) { + t.Errorf("%#v:\ngot %#v (%T)\nwant %#v (%T)", + test.val, gotData, gotData, test.wantData, test.wantData) + } + if !testutil.Equal(gotParam, test.wantParam) { + t.Errorf("%#v:\ngot %#v (%T)\nwant %#v (%T)", + test.val, gotParam, gotParam, test.wantParam, test.wantParam) + } + } +} + +// paramRoundTrip passes x as a query parameter to BigQuery. It returns +// the resulting data value from running the query and the parameter value from +// the returned job configuration. +func paramRoundTrip(c *Client, x interface{}) (data Value, param interface{}, err error) { + ctx := context.Background() + q := c.Query("select ?") + q.Parameters = []QueryParameter{{Value: x}} + job, err := q.Run(ctx) + if err != nil { + return nil, nil, err + } + it, err := job.Read(ctx) + if err != nil { + return nil, nil, err + } + var val []Value + err = it.Next(&val) + if err != nil { + return nil, nil, err + } + if len(val) != 1 { + return nil, nil, errors.New("wrong number of values") + } + conf, err := job.Config() + if err != nil { + return nil, nil, err + } + return val[0], conf.(*QueryConfig).Parameters[0].Value, nil +} diff --git a/vendor/cloud.google.com/go/bigquery/query.go b/vendor/cloud.google.com/go/bigquery/query.go new file mode 100644 index 00000000..735a54c4 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/query.go @@ -0,0 +1,328 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "context" + "errors" + + "cloud.google.com/go/internal/trace" + bq "google.golang.org/api/bigquery/v2" +) + +// QueryConfig holds the configuration for a query job. +type QueryConfig struct { + // Dst is the table into which the results of the query will be written. + // If this field is nil, a temporary table will be created. + Dst *Table + + // The query to execute. See https://cloud.google.com/bigquery/query-reference for details. + Q string + + // DefaultProjectID and DefaultDatasetID specify the dataset to use for unqualified table names in the query. + // If DefaultProjectID is set, DefaultDatasetID must also be set. + DefaultProjectID string + DefaultDatasetID string + + // TableDefinitions describes data sources outside of BigQuery. + // The map keys may be used as table names in the query string. + // + // When a QueryConfig is returned from Job.Config, the map values + // are always of type *ExternalDataConfig. + TableDefinitions map[string]ExternalData + + // CreateDisposition specifies the circumstances under which the destination table will be created. + // The default is CreateIfNeeded. + CreateDisposition TableCreateDisposition + + // WriteDisposition specifies how existing data in the destination table is treated. + // The default is WriteEmpty. + WriteDisposition TableWriteDisposition + + // DisableQueryCache prevents results being fetched from the query cache. + // If this field is false, results are fetched from the cache if they are available. + // The query cache is a best-effort cache that is flushed whenever tables in the query are modified. + // Cached results are only available when TableID is unspecified in the query's destination Table. + // For more information, see https://cloud.google.com/bigquery/querying-data#querycaching + DisableQueryCache bool + + // DisableFlattenedResults prevents results being flattened. + // If this field is false, results from nested and repeated fields are flattened. + // DisableFlattenedResults implies AllowLargeResults + // For more information, see https://cloud.google.com/bigquery/docs/data#nested + DisableFlattenedResults bool + + // AllowLargeResults allows the query to produce arbitrarily large result tables. + // The destination must be a table. + // When using this option, queries will take longer to execute, even if the result set is small. + // For additional limitations, see https://cloud.google.com/bigquery/querying-data#largequeryresults + AllowLargeResults bool + + // Priority specifies the priority with which to schedule the query. + // The default priority is InteractivePriority. + // For more information, see https://cloud.google.com/bigquery/querying-data#batchqueries + Priority QueryPriority + + // MaxBillingTier sets the maximum billing tier for a Query. + // Queries that have resource usage beyond this tier will fail (without + // incurring a charge). If this field is zero, the project default will be used. + MaxBillingTier int + + // MaxBytesBilled limits the number of bytes billed for + // this job. Queries that would exceed this limit will fail (without incurring + // a charge). + // If this field is less than 1, the project default will be + // used. + MaxBytesBilled int64 + + // UseStandardSQL causes the query to use standard SQL. The default. + // Deprecated: use UseLegacySQL. + UseStandardSQL bool + + // UseLegacySQL causes the query to use legacy SQL. + UseLegacySQL bool + + // Parameters is a list of query parameters. The presence of parameters + // implies the use of standard SQL. + // If the query uses positional syntax ("?"), then no parameter may have a name. + // If the query uses named syntax ("@p"), then all parameters must have names. + // It is illegal to mix positional and named syntax. + Parameters []QueryParameter + + // TimePartitioning specifies time-based partitioning + // for the destination table. + TimePartitioning *TimePartitioning + + // Clustering specifies the data clustering configuration for the destination table. + Clustering *Clustering + + // The labels associated with this job. + Labels map[string]string + + // If true, don't actually run this job. A valid query will return a mostly + // empty response with some processing statistics, while an invalid query will + // return the same error it would if it wasn't a dry run. + // + // Query.Read will fail with dry-run queries. Call Query.Run instead, and then + // call LastStatus on the returned job to get statistics. Calling Status on a + // dry-run job will fail. + DryRun bool + + // Custom encryption configuration (e.g., Cloud KMS keys). + DestinationEncryptionConfig *EncryptionConfig + + // Allows the schema of the destination table to be updated as a side effect of + // the query job. + SchemaUpdateOptions []string +} + +func (qc *QueryConfig) toBQ() (*bq.JobConfiguration, error) { + qconf := &bq.JobConfigurationQuery{ + Query: qc.Q, + CreateDisposition: string(qc.CreateDisposition), + WriteDisposition: string(qc.WriteDisposition), + AllowLargeResults: qc.AllowLargeResults, + Priority: string(qc.Priority), + MaximumBytesBilled: qc.MaxBytesBilled, + TimePartitioning: qc.TimePartitioning.toBQ(), + Clustering: qc.Clustering.toBQ(), + DestinationEncryptionConfiguration: qc.DestinationEncryptionConfig.toBQ(), + SchemaUpdateOptions: qc.SchemaUpdateOptions, + } + if len(qc.TableDefinitions) > 0 { + qconf.TableDefinitions = make(map[string]bq.ExternalDataConfiguration) + } + for name, data := range qc.TableDefinitions { + qconf.TableDefinitions[name] = data.toBQ() + } + if qc.DefaultProjectID != "" || qc.DefaultDatasetID != "" { + qconf.DefaultDataset = &bq.DatasetReference{ + DatasetId: qc.DefaultDatasetID, + ProjectId: qc.DefaultProjectID, + } + } + if tier := int64(qc.MaxBillingTier); tier > 0 { + qconf.MaximumBillingTier = &tier + } + f := false + if qc.DisableQueryCache { + qconf.UseQueryCache = &f + } + if qc.DisableFlattenedResults { + qconf.FlattenResults = &f + // DisableFlattenResults implies AllowLargeResults. + qconf.AllowLargeResults = true + } + if qc.UseStandardSQL && qc.UseLegacySQL { + return nil, errors.New("bigquery: cannot provide both UseStandardSQL and UseLegacySQL") + } + if len(qc.Parameters) > 0 && qc.UseLegacySQL { + return nil, errors.New("bigquery: cannot provide both Parameters (implying standard SQL) and UseLegacySQL") + } + ptrue := true + pfalse := false + if qc.UseLegacySQL { + qconf.UseLegacySql = &ptrue + } else { + qconf.UseLegacySql = &pfalse + } + if qc.Dst != nil && !qc.Dst.implicitTable() { + qconf.DestinationTable = qc.Dst.toBQ() + } + for _, p := range qc.Parameters { + qp, err := p.toBQ() + if err != nil { + return nil, err + } + qconf.QueryParameters = append(qconf.QueryParameters, qp) + } + return &bq.JobConfiguration{ + Labels: qc.Labels, + DryRun: qc.DryRun, + Query: qconf, + }, nil +} + +func bqToQueryConfig(q *bq.JobConfiguration, c *Client) (*QueryConfig, error) { + qq := q.Query + qc := &QueryConfig{ + Labels: q.Labels, + DryRun: q.DryRun, + Q: qq.Query, + CreateDisposition: TableCreateDisposition(qq.CreateDisposition), + WriteDisposition: TableWriteDisposition(qq.WriteDisposition), + AllowLargeResults: qq.AllowLargeResults, + Priority: QueryPriority(qq.Priority), + MaxBytesBilled: qq.MaximumBytesBilled, + UseLegacySQL: qq.UseLegacySql == nil || *qq.UseLegacySql, + TimePartitioning: bqToTimePartitioning(qq.TimePartitioning), + Clustering: bqToClustering(qq.Clustering), + DestinationEncryptionConfig: bqToEncryptionConfig(qq.DestinationEncryptionConfiguration), + SchemaUpdateOptions: qq.SchemaUpdateOptions, + } + qc.UseStandardSQL = !qc.UseLegacySQL + + if len(qq.TableDefinitions) > 0 { + qc.TableDefinitions = make(map[string]ExternalData) + } + for name, qedc := range qq.TableDefinitions { + edc, err := bqToExternalDataConfig(&qedc) + if err != nil { + return nil, err + } + qc.TableDefinitions[name] = edc + } + if qq.DefaultDataset != nil { + qc.DefaultProjectID = qq.DefaultDataset.ProjectId + qc.DefaultDatasetID = qq.DefaultDataset.DatasetId + } + if qq.MaximumBillingTier != nil { + qc.MaxBillingTier = int(*qq.MaximumBillingTier) + } + if qq.UseQueryCache != nil && !*qq.UseQueryCache { + qc.DisableQueryCache = true + } + if qq.FlattenResults != nil && !*qq.FlattenResults { + qc.DisableFlattenedResults = true + } + if qq.DestinationTable != nil { + qc.Dst = bqToTable(qq.DestinationTable, c) + } + for _, qp := range qq.QueryParameters { + p, err := bqToQueryParameter(qp) + if err != nil { + return nil, err + } + qc.Parameters = append(qc.Parameters, p) + } + return qc, nil +} + +// QueryPriority specifies a priority with which a query is to be executed. +type QueryPriority string + +const ( + // BatchPriority specifies that the query should be scheduled with the + // batch priority. BigQuery queues each batch query on your behalf, and + // starts the query as soon as idle resources are available, usually within + // a few minutes. If BigQuery hasn't started the query within 24 hours, + // BigQuery changes the job priority to interactive. Batch queries don't + // count towards your concurrent rate limit, which can make it easier to + // start many queries at once. + // + // More information can be found at https://cloud.google.com/bigquery/docs/running-queries#batchqueries. + BatchPriority QueryPriority = "BATCH" + // InteractivePriority specifies that the query should be scheduled with + // interactive priority, which means that the query is executed as soon as + // possible. Interactive queries count towards your concurrent rate limit + // and your daily limit. It is the default priority with which queries get + // executed. + // + // More information can be found at https://cloud.google.com/bigquery/docs/running-queries#queries. + InteractivePriority QueryPriority = "INTERACTIVE" +) + +// A Query queries data from a BigQuery table. Use Client.Query to create a Query. +type Query struct { + JobIDConfig + QueryConfig + client *Client +} + +// Query creates a query with string q. +// The returned Query may optionally be further configured before its Run method is called. +func (c *Client) Query(q string) *Query { + return &Query{ + client: c, + QueryConfig: QueryConfig{Q: q}, + } +} + +// Run initiates a query job. +func (q *Query) Run(ctx context.Context) (j *Job, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Query.Run") + defer func() { trace.EndSpan(ctx, err) }() + + job, err := q.newJob() + if err != nil { + return nil, err + } + j, err = q.client.insertJob(ctx, job, nil) + if err != nil { + return nil, err + } + return j, nil +} + +func (q *Query) newJob() (*bq.Job, error) { + config, err := q.QueryConfig.toBQ() + if err != nil { + return nil, err + } + return &bq.Job{ + JobReference: q.JobIDConfig.createJobRef(q.client), + Configuration: config, + }, nil +} + +// Read submits a query for execution and returns the results via a RowIterator. +// It is a shorthand for Query.Run followed by Job.Read. +func (q *Query) Read(ctx context.Context) (*RowIterator, error) { + job, err := q.Run(ctx) + if err != nil { + return nil, err + } + return job.Read(ctx) +} diff --git a/vendor/cloud.google.com/go/bigquery/query_test.go b/vendor/cloud.google.com/go/bigquery/query_test.go new file mode 100644 index 00000000..f56eeef6 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/query_test.go @@ -0,0 +1,408 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" + bq "google.golang.org/api/bigquery/v2" +) + +func defaultQueryJob() *bq.Job { + pfalse := false + return &bq.Job{ + JobReference: &bq.JobReference{JobId: "RANDOM", ProjectId: "client-project-id"}, + Configuration: &bq.JobConfiguration{ + Query: &bq.JobConfigurationQuery{ + DestinationTable: &bq.TableReference{ + ProjectId: "client-project-id", + DatasetId: "dataset-id", + TableId: "table-id", + }, + Query: "query string", + DefaultDataset: &bq.DatasetReference{ + ProjectId: "def-project-id", + DatasetId: "def-dataset-id", + }, + UseLegacySql: &pfalse, + }, + }, + } +} + +var defaultQuery = &QueryConfig{ + Q: "query string", + DefaultProjectID: "def-project-id", + DefaultDatasetID: "def-dataset-id", +} + +func TestQuery(t *testing.T) { + defer fixRandomID("RANDOM")() + c := &Client{ + projectID: "client-project-id", + } + testCases := []struct { + dst *Table + src *QueryConfig + jobIDConfig JobIDConfig + want *bq.Job + }{ + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: defaultQuery, + want: defaultQueryJob(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: &QueryConfig{ + Q: "query string", + Labels: map[string]string{"a": "b"}, + DryRun: true, + }, + want: func() *bq.Job { + j := defaultQueryJob() + j.Configuration.Labels = map[string]string{"a": "b"} + j.Configuration.DryRun = true + j.Configuration.Query.DefaultDataset = nil + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + jobIDConfig: JobIDConfig{JobID: "jobID", AddJobIDSuffix: true}, + src: &QueryConfig{Q: "query string"}, + want: func() *bq.Job { + j := defaultQueryJob() + j.Configuration.Query.DefaultDataset = nil + j.JobReference.JobId = "jobID-RANDOM" + return j + }(), + }, + { + dst: &Table{}, + src: defaultQuery, + want: func() *bq.Job { + j := defaultQueryJob() + j.Configuration.Query.DestinationTable = nil + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: &QueryConfig{ + Q: "query string", + TableDefinitions: map[string]ExternalData{ + "atable": func() *GCSReference { + g := NewGCSReference("uri") + g.AllowJaggedRows = true + g.AllowQuotedNewlines = true + g.Compression = Gzip + g.Encoding = UTF_8 + g.FieldDelimiter = ";" + g.IgnoreUnknownValues = true + g.MaxBadRecords = 1 + g.Quote = "'" + g.SkipLeadingRows = 2 + g.Schema = Schema{{Name: "name", Type: StringFieldType}} + return g + }(), + }, + }, + want: func() *bq.Job { + j := defaultQueryJob() + j.Configuration.Query.DefaultDataset = nil + td := make(map[string]bq.ExternalDataConfiguration) + quote := "'" + td["atable"] = bq.ExternalDataConfiguration{ + Compression: "GZIP", + IgnoreUnknownValues: true, + MaxBadRecords: 1, + SourceFormat: "CSV", // must be explicitly set. + SourceUris: []string{"uri"}, + CsvOptions: &bq.CsvOptions{ + AllowJaggedRows: true, + AllowQuotedNewlines: true, + Encoding: "UTF-8", + FieldDelimiter: ";", + SkipLeadingRows: 2, + Quote: "e, + }, + Schema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + {Name: "name", Type: "STRING"}, + }, + }, + } + j.Configuration.Query.TableDefinitions = td + return j + }(), + }, + { + dst: &Table{ + ProjectID: "project-id", + DatasetID: "dataset-id", + TableID: "table-id", + }, + src: &QueryConfig{ + Q: "query string", + DefaultProjectID: "def-project-id", + DefaultDatasetID: "def-dataset-id", + CreateDisposition: CreateNever, + WriteDisposition: WriteTruncate, + }, + want: func() *bq.Job { + j := defaultQueryJob() + j.Configuration.Query.DestinationTable.ProjectId = "project-id" + j.Configuration.Query.WriteDisposition = "WRITE_TRUNCATE" + j.Configuration.Query.CreateDisposition = "CREATE_NEVER" + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: &QueryConfig{ + Q: "query string", + DefaultProjectID: "def-project-id", + DefaultDatasetID: "def-dataset-id", + DisableQueryCache: true, + }, + want: func() *bq.Job { + j := defaultQueryJob() + f := false + j.Configuration.Query.UseQueryCache = &f + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: &QueryConfig{ + Q: "query string", + DefaultProjectID: "def-project-id", + DefaultDatasetID: "def-dataset-id", + AllowLargeResults: true, + }, + want: func() *bq.Job { + j := defaultQueryJob() + j.Configuration.Query.AllowLargeResults = true + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: &QueryConfig{ + Q: "query string", + DefaultProjectID: "def-project-id", + DefaultDatasetID: "def-dataset-id", + DisableFlattenedResults: true, + }, + want: func() *bq.Job { + j := defaultQueryJob() + f := false + j.Configuration.Query.FlattenResults = &f + j.Configuration.Query.AllowLargeResults = true + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: &QueryConfig{ + Q: "query string", + DefaultProjectID: "def-project-id", + DefaultDatasetID: "def-dataset-id", + Priority: QueryPriority("low"), + }, + want: func() *bq.Job { + j := defaultQueryJob() + j.Configuration.Query.Priority = "low" + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: &QueryConfig{ + Q: "query string", + DefaultProjectID: "def-project-id", + DefaultDatasetID: "def-dataset-id", + MaxBillingTier: 3, + MaxBytesBilled: 5, + }, + want: func() *bq.Job { + j := defaultQueryJob() + tier := int64(3) + j.Configuration.Query.MaximumBillingTier = &tier + j.Configuration.Query.MaximumBytesBilled = 5 + return j + }(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: &QueryConfig{ + Q: "query string", + DefaultProjectID: "def-project-id", + DefaultDatasetID: "def-dataset-id", + UseStandardSQL: true, + }, + want: defaultQueryJob(), + }, + { + dst: c.Dataset("dataset-id").Table("table-id"), + src: &QueryConfig{ + Q: "query string", + DefaultProjectID: "def-project-id", + DefaultDatasetID: "def-dataset-id", + UseLegacySQL: true, + }, + want: func() *bq.Job { + j := defaultQueryJob() + ptrue := true + j.Configuration.Query.UseLegacySql = &ptrue + j.Configuration.Query.ForceSendFields = nil + return j + }(), + }, + } + for i, tc := range testCases { + query := c.Query("") + query.JobIDConfig = tc.jobIDConfig + query.QueryConfig = *tc.src + query.Dst = tc.dst + got, err := query.newJob() + if err != nil { + t.Errorf("#%d: err calling query: %v", i, err) + continue + } + checkJob(t, i, got, tc.want) + + // Round-trip. + jc, err := bqToJobConfig(got.Configuration, c) + if err != nil { + t.Fatalf("#%d: %v", i, err) + } + wantConfig := query.QueryConfig + // We set AllowLargeResults to true when DisableFlattenedResults is true. + if wantConfig.DisableFlattenedResults { + wantConfig.AllowLargeResults = true + } + // A QueryConfig with neither UseXXXSQL field set is equivalent + // to one where UseStandardSQL = true. + if !wantConfig.UseLegacySQL && !wantConfig.UseStandardSQL { + wantConfig.UseStandardSQL = true + } + // Treat nil and empty tables the same, and ignore the client. + tableEqual := func(t1, t2 *Table) bool { + if t1 == nil { + t1 = &Table{} + } + if t2 == nil { + t2 = &Table{} + } + return t1.ProjectID == t2.ProjectID && t1.DatasetID == t2.DatasetID && t1.TableID == t2.TableID + } + // A table definition that is a GCSReference round-trips as an ExternalDataConfig. + // TODO(jba): see if there is a way to express this with a transformer. + gcsRefToEDC := func(g *GCSReference) *ExternalDataConfig { + q := g.toBQ() + e, _ := bqToExternalDataConfig(&q) + return e + } + externalDataEqual := func(e1, e2 ExternalData) bool { + if r, ok := e1.(*GCSReference); ok { + e1 = gcsRefToEDC(r) + } + if r, ok := e2.(*GCSReference); ok { + e2 = gcsRefToEDC(r) + } + return cmp.Equal(e1, e2) + } + diff := testutil.Diff(jc.(*QueryConfig), &wantConfig, + cmp.Comparer(tableEqual), + cmp.Comparer(externalDataEqual), + ) + if diff != "" { + t.Errorf("#%d: (got=-, want=+:\n%s", i, diff) + } + } +} + +func TestConfiguringQuery(t *testing.T) { + c := &Client{ + projectID: "project-id", + } + + query := c.Query("q") + query.JobID = "ajob" + query.DefaultProjectID = "def-project-id" + query.DefaultDatasetID = "def-dataset-id" + query.TimePartitioning = &TimePartitioning{Expiration: 1234 * time.Second, Field: "f"} + query.Clustering = &Clustering{ + Fields: []string{"cfield1"}, + } + query.DestinationEncryptionConfig = &EncryptionConfig{KMSKeyName: "keyName"} + query.SchemaUpdateOptions = []string{"ALLOW_FIELD_ADDITION"} + + // Note: Other configuration fields are tested in other tests above. + // A lot of that can be consolidated once Client.Copy is gone. + + pfalse := false + want := &bq.Job{ + Configuration: &bq.JobConfiguration{ + Query: &bq.JobConfigurationQuery{ + Query: "q", + DefaultDataset: &bq.DatasetReference{ + ProjectId: "def-project-id", + DatasetId: "def-dataset-id", + }, + UseLegacySql: &pfalse, + TimePartitioning: &bq.TimePartitioning{ExpirationMs: 1234000, Field: "f", Type: "DAY"}, + Clustering: &bq.Clustering{Fields: []string{"cfield1"}}, + DestinationEncryptionConfiguration: &bq.EncryptionConfiguration{KmsKeyName: "keyName"}, + SchemaUpdateOptions: []string{"ALLOW_FIELD_ADDITION"}, + }, + }, + JobReference: &bq.JobReference{ + JobId: "ajob", + ProjectId: "project-id", + }, + } + + got, err := query.newJob() + if err != nil { + t.Fatalf("err calling Query.newJob: %v", err) + } + if diff := testutil.Diff(got, want); diff != "" { + t.Errorf("querying: -got +want:\n%s", diff) + } +} + +func TestQueryLegacySQL(t *testing.T) { + c := &Client{projectID: "project-id"} + q := c.Query("q") + q.UseStandardSQL = true + q.UseLegacySQL = true + _, err := q.newJob() + if err == nil { + t.Error("UseStandardSQL and UseLegacySQL: got nil, want error") + } + q = c.Query("q") + q.Parameters = []QueryParameter{{Name: "p", Value: 3}} + q.UseLegacySQL = true + _, err = q.newJob() + if err == nil { + t.Error("Parameters and UseLegacySQL: got nil, want error") + } +} diff --git a/vendor/cloud.google.com/go/bigquery/random.go b/vendor/cloud.google.com/go/bigquery/random.go new file mode 100644 index 00000000..65f93843 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/random.go @@ -0,0 +1,56 @@ +// Copyright 2018 Google LLC +// +// 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 bigquery + +import ( + "math/rand" + "os" + "sync" + "time" +) + +// Support for random values (typically job IDs and insert IDs). + +const alphanum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + +var ( + rngMu sync.Mutex + rng = rand.New(rand.NewSource(time.Now().UnixNano() ^ int64(os.Getpid()))) +) + +// For testing. +var randomIDFn = randomID + +// As of August 2017, the BigQuery service uses 27 alphanumeric characters for +// suffixes. +const randomIDLen = 27 + +func randomID() string { + // This is used for both job IDs and insert IDs. + var b [randomIDLen]byte + rngMu.Lock() + for i := 0; i < len(b); i++ { + b[i] = alphanum[rng.Intn(len(alphanum))] + } + rngMu.Unlock() + return string(b[:]) +} + +// Seed seeds this package's random number generator, used for generating job and +// insert IDs. Use Seed to obtain repeatable, deterministic behavior from bigquery +// clients. Seed should be called before any clients are created. +func Seed(s int64) { + rng = rand.New(rand.NewSource(s)) +} diff --git a/vendor/cloud.google.com/go/bigquery/read_test.go b/vendor/cloud.google.com/go/bigquery/read_test.go new file mode 100644 index 00000000..883430a0 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/read_test.go @@ -0,0 +1,233 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "context" + "errors" + "testing" + + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" + bq "google.golang.org/api/bigquery/v2" + "google.golang.org/api/iterator" +) + +type pageFetcherArgs struct { + table *Table + schema Schema + startIndex uint64 + pageSize int64 + pageToken string +} + +// pageFetcherReadStub services read requests by returning data from an in-memory list of values. +type pageFetcherReadStub struct { + // values and pageTokens are used as sources of data to return in response to calls to readTabledata or readQuery. + values [][][]Value // contains pages / rows / columns. + pageTokens map[string]string // maps incoming page token to returned page token. + + // arguments are recorded for later inspection. + calls []pageFetcherArgs +} + +func (s *pageFetcherReadStub) fetchPage(ctx context.Context, t *Table, schema Schema, startIndex uint64, pageSize int64, pageToken string) (*fetchPageResult, error) { + s.calls = append(s.calls, + pageFetcherArgs{t, schema, startIndex, pageSize, pageToken}) + result := &fetchPageResult{ + pageToken: s.pageTokens[pageToken], + rows: s.values[0], + } + s.values = s.values[1:] + return result, nil +} + +func waitForQueryStub(context.Context, string) (Schema, uint64, error) { + return nil, 1, nil +} + +func TestRead(t *testing.T) { + // The data for the service stub to return is populated for each test case in the testCases for loop. + ctx := context.Background() + c := &Client{projectID: "project-id"} + pf := &pageFetcherReadStub{} + queryJob := &Job{ + projectID: "project-id", + jobID: "job-id", + c: c, + config: &bq.JobConfiguration{ + Query: &bq.JobConfigurationQuery{ + DestinationTable: &bq.TableReference{ + ProjectId: "project-id", + DatasetId: "dataset-id", + TableId: "table-id", + }, + }, + }, + } + + for _, readFunc := range []func() *RowIterator{ + func() *RowIterator { + return c.Dataset("dataset-id").Table("table-id").read(ctx, pf.fetchPage) + }, + func() *RowIterator { + it, err := queryJob.read(ctx, waitForQueryStub, pf.fetchPage) + if err != nil { + t.Fatal(err) + } + return it + }, + } { + testCases := []struct { + data [][][]Value + pageTokens map[string]string + want [][]Value + }{ + { + data: [][][]Value{{{1, 2}, {11, 12}}, {{30, 40}, {31, 41}}}, + pageTokens: map[string]string{"": "a", "a": ""}, + want: [][]Value{{1, 2}, {11, 12}, {30, 40}, {31, 41}}, + }, + { + data: [][][]Value{{{1, 2}, {11, 12}}, {{30, 40}, {31, 41}}}, + pageTokens: map[string]string{"": ""}, // no more pages after first one. + want: [][]Value{{1, 2}, {11, 12}}, + }, + } + for _, tc := range testCases { + pf.values = tc.data + pf.pageTokens = tc.pageTokens + if got, ok := collectValues(t, readFunc()); ok { + if !testutil.Equal(got, tc.want) { + t.Errorf("reading: got:\n%v\nwant:\n%v", got, tc.want) + } + } + } + } +} + +func collectValues(t *testing.T, it *RowIterator) ([][]Value, bool) { + var got [][]Value + for { + var vals []Value + err := it.Next(&vals) + if err == iterator.Done { + break + } + if err != nil { + t.Errorf("err calling Next: %v", err) + return nil, false + } + got = append(got, vals) + } + return got, true +} + +func TestNoMoreValues(t *testing.T) { + c := &Client{projectID: "project-id"} + pf := &pageFetcherReadStub{ + values: [][][]Value{{{1, 2}, {11, 12}}}, + } + it := c.Dataset("dataset-id").Table("table-id").read(context.Background(), pf.fetchPage) + var vals []Value + // We expect to retrieve two values and then fail on the next attempt. + if err := it.Next(&vals); err != nil { + t.Fatalf("Next: got: %v: want: nil", err) + } + if err := it.Next(&vals); err != nil { + t.Fatalf("Next: got: %v: want: nil", err) + } + if err := it.Next(&vals); err != iterator.Done { + t.Fatalf("Next: got: %v: want: iterator.Done", err) + } +} + +var errBang = errors.New("bang") + +func errorFetchPage(context.Context, *Table, Schema, uint64, int64, string) (*fetchPageResult, error) { + return nil, errBang +} + +func TestReadError(t *testing.T) { + // test that service read errors are propagated back to the caller. + c := &Client{projectID: "project-id"} + it := c.Dataset("dataset-id").Table("table-id").read(context.Background(), errorFetchPage) + var vals []Value + if err := it.Next(&vals); err != errBang { + t.Fatalf("Get: got: %v: want: %v", err, errBang) + } +} + +func TestReadTabledataOptions(t *testing.T) { + // test that read options are propagated. + s := &pageFetcherReadStub{ + values: [][][]Value{{{1, 2}}}, + } + c := &Client{projectID: "project-id"} + tr := c.Dataset("dataset-id").Table("table-id") + it := tr.read(context.Background(), s.fetchPage) + it.PageInfo().MaxSize = 5 + var vals []Value + if err := it.Next(&vals); err != nil { + t.Fatal(err) + } + want := []pageFetcherArgs{{ + table: tr, + pageSize: 5, + pageToken: "", + }} + if diff := testutil.Diff(s.calls, want, cmp.AllowUnexported(pageFetcherArgs{}, pageFetcherReadStub{}, Table{}, Client{})); diff != "" { + t.Errorf("reading (got=-, want=+):\n%s", diff) + } +} + +func TestReadQueryOptions(t *testing.T) { + // test that read options are propagated. + c := &Client{projectID: "project-id"} + pf := &pageFetcherReadStub{ + values: [][][]Value{{{1, 2}}}, + } + tr := &bq.TableReference{ + ProjectId: "project-id", + DatasetId: "dataset-id", + TableId: "table-id", + } + queryJob := &Job{ + projectID: "project-id", + jobID: "job-id", + c: c, + config: &bq.JobConfiguration{ + Query: &bq.JobConfigurationQuery{DestinationTable: tr}, + }, + } + it, err := queryJob.read(context.Background(), waitForQueryStub, pf.fetchPage) + if err != nil { + t.Fatalf("err calling Read: %v", err) + } + it.PageInfo().MaxSize = 5 + var vals []Value + if err := it.Next(&vals); err != nil { + t.Fatalf("Next: got: %v: want: nil", err) + } + + want := []pageFetcherArgs{{ + table: bqToTable(tr, c), + pageSize: 5, + pageToken: "", + }} + if !testutil.Equal(pf.calls, want, cmp.AllowUnexported(pageFetcherArgs{}, Table{}, Client{})) { + t.Errorf("reading: got:\n%v\nwant:\n%v", pf.calls, want) + } +} diff --git a/vendor/cloud.google.com/go/bigquery/schema.go b/vendor/cloud.google.com/go/bigquery/schema.go new file mode 100644 index 00000000..e8454767 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/schema.go @@ -0,0 +1,488 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "encoding/json" + "errors" + "fmt" + "reflect" + "sync" + + bq "google.golang.org/api/bigquery/v2" +) + +// Schema describes the fields in a table or query result. +type Schema []*FieldSchema + +// FieldSchema describes a single field. +type FieldSchema struct { + // The field name. + // Must contain only letters (a-z, A-Z), numbers (0-9), or underscores (_), + // and must start with a letter or underscore. + // The maximum length is 128 characters. + Name string + + // A description of the field. The maximum length is 16,384 characters. + Description string + + // Whether the field may contain multiple values. + Repeated bool + // Whether the field is required. Ignored if Repeated is true. + Required bool + + // The field data type. If Type is Record, then this field contains a nested schema, + // which is described by Schema. + Type FieldType + // Describes the nested schema if Type is set to Record. + Schema Schema +} + +func (fs *FieldSchema) toBQ() *bq.TableFieldSchema { + tfs := &bq.TableFieldSchema{ + Description: fs.Description, + Name: fs.Name, + Type: string(fs.Type), + } + + if fs.Repeated { + tfs.Mode = "REPEATED" + } else if fs.Required { + tfs.Mode = "REQUIRED" + } // else leave as default, which is interpreted as NULLABLE. + + for _, f := range fs.Schema { + tfs.Fields = append(tfs.Fields, f.toBQ()) + } + + return tfs +} + +func (s Schema) toBQ() *bq.TableSchema { + var fields []*bq.TableFieldSchema + for _, f := range s { + fields = append(fields, f.toBQ()) + } + return &bq.TableSchema{Fields: fields} +} + +func bqToFieldSchema(tfs *bq.TableFieldSchema) *FieldSchema { + fs := &FieldSchema{ + Description: tfs.Description, + Name: tfs.Name, + Repeated: tfs.Mode == "REPEATED", + Required: tfs.Mode == "REQUIRED", + Type: FieldType(tfs.Type), + } + + for _, f := range tfs.Fields { + fs.Schema = append(fs.Schema, bqToFieldSchema(f)) + } + return fs +} + +func bqToSchema(ts *bq.TableSchema) Schema { + if ts == nil { + return nil + } + var s Schema + for _, f := range ts.Fields { + s = append(s, bqToFieldSchema(f)) + } + return s +} + +// FieldType is the type of field. +type FieldType string + +const ( + // StringFieldType is a string field type. + StringFieldType FieldType = "STRING" + // BytesFieldType is a bytes field type. + BytesFieldType FieldType = "BYTES" + // IntegerFieldType is a integer field type. + IntegerFieldType FieldType = "INTEGER" + // FloatFieldType is a float field type. + FloatFieldType FieldType = "FLOAT" + // BooleanFieldType is a boolean field type. + BooleanFieldType FieldType = "BOOLEAN" + // TimestampFieldType is a timestamp field type. + TimestampFieldType FieldType = "TIMESTAMP" + // RecordFieldType is a record field type. It is typically used to create columns with repeated or nested data. + RecordFieldType FieldType = "RECORD" + // DateFieldType is a date field type. + DateFieldType FieldType = "DATE" + // TimeFieldType is a time field type. + TimeFieldType FieldType = "TIME" + // DateTimeFieldType is a datetime field type. + DateTimeFieldType FieldType = "DATETIME" + // NumericFieldType is a numeric field type. Numeric types include integer types, floating point types and the + // NUMERIC data type. + NumericFieldType FieldType = "NUMERIC" +) + +var ( + errNoStruct = errors.New("bigquery: can only infer schema from struct or pointer to struct") + errUnsupportedFieldType = errors.New("bigquery: unsupported type of field in struct") + errInvalidFieldName = errors.New("bigquery: invalid name of field in struct") + errBadNullable = errors.New(`bigquery: use "nullable" only for []byte and struct pointers; for all other types, use a NullXXX type`) + errEmptyJSONSchema = errors.New("bigquery: empty JSON schema") + fieldTypes = map[FieldType]bool{ + StringFieldType: true, + BytesFieldType: true, + IntegerFieldType: true, + FloatFieldType: true, + BooleanFieldType: true, + TimestampFieldType: true, + RecordFieldType: true, + DateFieldType: true, + TimeFieldType: true, + DateTimeFieldType: true, + NumericFieldType: true, + } +) + +var typeOfByteSlice = reflect.TypeOf([]byte{}) + +// InferSchema tries to derive a BigQuery schema from the supplied struct value. +// Each exported struct field is mapped to a field in the schema. +// +// The following BigQuery types are inferred from the corresponding Go types. +// (This is the same mapping as that used for RowIterator.Next.) Fields inferred +// from these types are marked required (non-nullable). +// +// STRING string +// BOOL bool +// INTEGER int, int8, int16, int32, int64, uint8, uint16, uint32 +// FLOAT float32, float64 +// BYTES []byte +// TIMESTAMP time.Time +// DATE civil.Date +// TIME civil.Time +// DATETIME civil.DateTime +// NUMERIC *big.Rat +// +// The big.Rat type supports numbers of arbitrary size and precision. Values +// will be rounded to 9 digits after the decimal point before being transmitted +// to BigQuery. See https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#numeric-type +// for more on NUMERIC. +// +// A Go slice or array type is inferred to be a BigQuery repeated field of the +// element type. The element type must be one of the above listed types. +// +// Nullable fields are inferred from the NullXXX types, declared in this package: +// +// STRING NullString +// BOOL NullBool +// INTEGER NullInt64 +// FLOAT NullFloat64 +// TIMESTAMP NullTimestamp +// DATE NullDate +// TIME NullTime +// DATETIME NullDateTime +// +// For a nullable BYTES field, use the type []byte and tag the field "nullable" (see below). +// For a nullable NUMERIC field, use the type *big.Rat and tag the field "nullable". +// +// A struct field that is of struct type is inferred to be a required field of type +// RECORD with a schema inferred recursively. For backwards compatibility, a field of +// type pointer to struct is also inferred to be required. To get a nullable RECORD +// field, use the "nullable" tag (see below). +// +// InferSchema returns an error if any of the examined fields is of type uint, +// uint64, uintptr, map, interface, complex64, complex128, func, or chan. Future +// versions may handle these cases without error. +// +// Recursively defined structs are also disallowed. +// +// Struct fields may be tagged in a way similar to the encoding/json package. +// A tag of the form +// bigquery:"name" +// uses "name" instead of the struct field name as the BigQuery field name. +// A tag of the form +// bigquery:"-" +// omits the field from the inferred schema. +// The "nullable" option marks the field as nullable (not required). It is only +// needed for []byte, *big.Rat and pointer-to-struct fields, and cannot appear on other +// fields. In this example, the Go name of the field is retained: +// bigquery:",nullable" +func InferSchema(st interface{}) (Schema, error) { + return inferSchemaReflectCached(reflect.TypeOf(st)) +} + +var schemaCache sync.Map + +type cacheVal struct { + schema Schema + err error +} + +func inferSchemaReflectCached(t reflect.Type) (Schema, error) { + var cv cacheVal + v, ok := schemaCache.Load(t) + if ok { + cv = v.(cacheVal) + } else { + s, err := inferSchemaReflect(t) + cv = cacheVal{s, err} + schemaCache.Store(t, cv) + } + return cv.schema, cv.err +} + +func inferSchemaReflect(t reflect.Type) (Schema, error) { + rec, err := hasRecursiveType(t, nil) + if err != nil { + return nil, err + } + if rec { + return nil, fmt.Errorf("bigquery: schema inference for recursive type %s", t) + } + return inferStruct(t) +} + +func inferStruct(t reflect.Type) (Schema, error) { + switch t.Kind() { + case reflect.Ptr: + if t.Elem().Kind() != reflect.Struct { + return nil, errNoStruct + } + t = t.Elem() + fallthrough + + case reflect.Struct: + return inferFields(t) + default: + return nil, errNoStruct + } +} + +// inferFieldSchema infers the FieldSchema for a Go type +func inferFieldSchema(rt reflect.Type, nullable bool) (*FieldSchema, error) { + // Only []byte and struct pointers can be tagged nullable. + if nullable && !(rt == typeOfByteSlice || rt.Kind() == reflect.Ptr && rt.Elem().Kind() == reflect.Struct) { + return nil, errBadNullable + } + switch rt { + case typeOfByteSlice: + return &FieldSchema{Required: !nullable, Type: BytesFieldType}, nil + case typeOfGoTime: + return &FieldSchema{Required: true, Type: TimestampFieldType}, nil + case typeOfDate: + return &FieldSchema{Required: true, Type: DateFieldType}, nil + case typeOfTime: + return &FieldSchema{Required: true, Type: TimeFieldType}, nil + case typeOfDateTime: + return &FieldSchema{Required: true, Type: DateTimeFieldType}, nil + case typeOfRat: + return &FieldSchema{Required: !nullable, Type: NumericFieldType}, nil + } + if ft := nullableFieldType(rt); ft != "" { + return &FieldSchema{Required: false, Type: ft}, nil + } + if isSupportedIntType(rt) || isSupportedUintType(rt) { + return &FieldSchema{Required: true, Type: IntegerFieldType}, nil + } + switch rt.Kind() { + case reflect.Slice, reflect.Array: + et := rt.Elem() + if et != typeOfByteSlice && (et.Kind() == reflect.Slice || et.Kind() == reflect.Array) { + // Multi dimensional slices/arrays are not supported by BigQuery + return nil, errUnsupportedFieldType + } + if nullableFieldType(et) != "" { + // Repeated nullable types are not supported by BigQuery. + return nil, errUnsupportedFieldType + } + f, err := inferFieldSchema(et, false) + if err != nil { + return nil, err + } + f.Repeated = true + f.Required = false + return f, nil + case reflect.Ptr: + if rt.Elem().Kind() != reflect.Struct { + return nil, errUnsupportedFieldType + } + fallthrough + case reflect.Struct: + nested, err := inferStruct(rt) + if err != nil { + return nil, err + } + return &FieldSchema{Required: !nullable, Type: RecordFieldType, Schema: nested}, nil + case reflect.String: + return &FieldSchema{Required: !nullable, Type: StringFieldType}, nil + case reflect.Bool: + return &FieldSchema{Required: !nullable, Type: BooleanFieldType}, nil + case reflect.Float32, reflect.Float64: + return &FieldSchema{Required: !nullable, Type: FloatFieldType}, nil + default: + return nil, errUnsupportedFieldType + } +} + +// inferFields extracts all exported field types from struct type. +func inferFields(rt reflect.Type) (Schema, error) { + var s Schema + fields, err := fieldCache.Fields(rt) + if err != nil { + return nil, err + } + for _, field := range fields { + var nullable bool + for _, opt := range field.ParsedTag.([]string) { + if opt == nullableTagOption { + nullable = true + break + } + } + f, err := inferFieldSchema(field.Type, nullable) + if err != nil { + return nil, err + } + f.Name = field.Name + s = append(s, f) + } + return s, nil +} + +// isSupportedIntType reports whether t is an int type that can be properly +// represented by the BigQuery INTEGER/INT64 type. +func isSupportedIntType(t reflect.Type) bool { + switch t.Kind() { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return true + default: + return false + } +} + +// isSupportedIntType reports whether t is a uint type that can be properly +// represented by the BigQuery INTEGER/INT64 type. +func isSupportedUintType(t reflect.Type) bool { + switch t.Kind() { + case reflect.Uint8, reflect.Uint16, reflect.Uint32: + return true + default: + return false + } +} + +// typeList is a linked list of reflect.Types. +type typeList struct { + t reflect.Type + next *typeList +} + +func (l *typeList) has(t reflect.Type) bool { + for l != nil { + if l.t == t { + return true + } + l = l.next + } + return false +} + +// hasRecursiveType reports whether t or any type inside t refers to itself, directly or indirectly, +// via exported fields. (Schema inference ignores unexported fields.) +func hasRecursiveType(t reflect.Type, seen *typeList) (bool, error) { + for t.Kind() == reflect.Ptr || t.Kind() == reflect.Slice || t.Kind() == reflect.Array { + t = t.Elem() + } + if t.Kind() != reflect.Struct { + return false, nil + } + if seen.has(t) { + return true, nil + } + fields, err := fieldCache.Fields(t) + if err != nil { + return false, err + } + seen = &typeList{t, seen} + // Because seen is a linked list, additions to it from one field's + // recursive call will not affect the value for subsequent fields' calls. + for _, field := range fields { + ok, err := hasRecursiveType(field.Type, seen) + if err != nil { + return false, err + } + if ok { + return true, nil + } + } + return false, nil +} + +// bigQuerySchemaJSONField is an individual field in a JSON BigQuery table schema definition +// (as generated by https://github.com/GoogleCloudPlatform/protoc-gen-bq-schema). +type bigQueryJSONField struct { + Description string `json:"description"` + Fields []bigQueryJSONField `json:"fields"` + Mode string `json:"mode"` + Name string `json:"name"` + Type string `json:"type"` +} + +// convertSchemaFromJSON generates a Schema: +func convertSchemaFromJSON(fs []bigQueryJSONField) (Schema, error) { + convertedSchema := Schema{} + for _, f := range fs { + convertedFieldSchema := &FieldSchema{ + Description: f.Description, + Name: f.Name, + Required: f.Mode == "REQUIRED", + Repeated: f.Mode == "REPEATED", + } + if len(f.Fields) > 0 { + convertedNestedFieldSchema, err := convertSchemaFromJSON(f.Fields) + if err != nil { + return nil, err + } + convertedFieldSchema.Schema = convertedNestedFieldSchema + } + + // Check that the field-type (string) maps to a known FieldType: + if _, ok := fieldTypes[FieldType(f.Type)]; !ok { + return nil, fmt.Errorf("unknown field type (%v)", f.Type) + } + convertedFieldSchema.Type = FieldType(f.Type) + + convertedSchema = append(convertedSchema, convertedFieldSchema) + } + return convertedSchema, nil +} + +// SchemaFromJSON takes a JSON BigQuery table schema definition +// (as generated by https://github.com/GoogleCloudPlatform/protoc-gen-bq-schema) +// and returns a fully-populated Schema. +func SchemaFromJSON(schemaJSON []byte) (Schema, error) { + + var bigQuerySchema []bigQueryJSONField + + // Make sure we actually have some content: + if len(schemaJSON) == 0 { + return nil, errEmptyJSONSchema + } + + if err := json.Unmarshal(schemaJSON, &bigQuerySchema); err != nil { + return nil, err + } + + return convertSchemaFromJSON(bigQuerySchema) +} diff --git a/vendor/cloud.google.com/go/bigquery/schema_test.go b/vendor/cloud.google.com/go/bigquery/schema_test.go new file mode 100644 index 00000000..3a14a5ec --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/schema_test.go @@ -0,0 +1,1054 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "fmt" + "math/big" + "reflect" + "testing" + "time" + + "cloud.google.com/go/civil" + "cloud.google.com/go/internal/pretty" + "cloud.google.com/go/internal/testutil" + bq "google.golang.org/api/bigquery/v2" +) + +func (fs *FieldSchema) GoString() string { + if fs == nil { + return "" + } + + return fmt.Sprintf("{Name:%s Description:%s Repeated:%t Required:%t Type:%s Schema:%s}", + fs.Name, + fs.Description, + fs.Repeated, + fs.Required, + fs.Type, + fmt.Sprintf("%#v", fs.Schema), + ) +} + +func bqTableFieldSchema(desc, name, typ, mode string) *bq.TableFieldSchema { + return &bq.TableFieldSchema{ + Description: desc, + Name: name, + Mode: mode, + Type: typ, + } +} + +func fieldSchema(desc, name, typ string, repeated, required bool) *FieldSchema { + return &FieldSchema{ + Description: desc, + Name: name, + Repeated: repeated, + Required: required, + Type: FieldType(typ), + } +} + +func TestSchemaConversion(t *testing.T) { + testCases := []struct { + schema Schema + bqSchema *bq.TableSchema + }{ + { + // required + bqSchema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqTableFieldSchema("desc", "name", "STRING", "REQUIRED"), + }, + }, + schema: Schema{ + fieldSchema("desc", "name", "STRING", false, true), + }, + }, + { + // repeated + bqSchema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqTableFieldSchema("desc", "name", "STRING", "REPEATED"), + }, + }, + schema: Schema{ + fieldSchema("desc", "name", "STRING", true, false), + }, + }, + { + // nullable, string + bqSchema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqTableFieldSchema("desc", "name", "STRING", ""), + }, + }, + schema: Schema{ + fieldSchema("desc", "name", "STRING", false, false), + }, + }, + { + // integer + bqSchema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqTableFieldSchema("desc", "name", "INTEGER", ""), + }, + }, + schema: Schema{ + fieldSchema("desc", "name", "INTEGER", false, false), + }, + }, + { + // float + bqSchema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqTableFieldSchema("desc", "name", "FLOAT", ""), + }, + }, + schema: Schema{ + fieldSchema("desc", "name", "FLOAT", false, false), + }, + }, + { + // boolean + bqSchema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqTableFieldSchema("desc", "name", "BOOLEAN", ""), + }, + }, + schema: Schema{ + fieldSchema("desc", "name", "BOOLEAN", false, false), + }, + }, + { + // timestamp + bqSchema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqTableFieldSchema("desc", "name", "TIMESTAMP", ""), + }, + }, + schema: Schema{ + fieldSchema("desc", "name", "TIMESTAMP", false, false), + }, + }, + { + // civil times + bqSchema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqTableFieldSchema("desc", "f1", "TIME", ""), + bqTableFieldSchema("desc", "f2", "DATE", ""), + bqTableFieldSchema("desc", "f3", "DATETIME", ""), + }, + }, + schema: Schema{ + fieldSchema("desc", "f1", "TIME", false, false), + fieldSchema("desc", "f2", "DATE", false, false), + fieldSchema("desc", "f3", "DATETIME", false, false), + }, + }, + { + // numeric + bqSchema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqTableFieldSchema("desc", "n", "NUMERIC", ""), + }, + }, + schema: Schema{ + fieldSchema("desc", "n", "NUMERIC", false, false), + }, + }, + { + // nested + bqSchema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + { + Description: "An outer schema wrapping a nested schema", + Name: "outer", + Mode: "REQUIRED", + Type: "RECORD", + Fields: []*bq.TableFieldSchema{ + bqTableFieldSchema("inner field", "inner", "STRING", ""), + }, + }, + }, + }, + schema: Schema{ + &FieldSchema{ + Description: "An outer schema wrapping a nested schema", + Name: "outer", + Required: true, + Type: "RECORD", + Schema: Schema{ + { + Description: "inner field", + Name: "inner", + Type: "STRING", + }, + }, + }, + }, + }, + } + for _, tc := range testCases { + bqSchema := tc.schema.toBQ() + if !testutil.Equal(bqSchema, tc.bqSchema) { + t.Errorf("converting to TableSchema: got:\n%v\nwant:\n%v", + pretty.Value(bqSchema), pretty.Value(tc.bqSchema)) + } + schema := bqToSchema(tc.bqSchema) + if !testutil.Equal(schema, tc.schema) { + t.Errorf("converting to Schema: got:\n%v\nwant:\n%v", schema, tc.schema) + } + } +} + +type allStrings struct { + String string + ByteSlice []byte +} + +type allSignedIntegers struct { + Int64 int64 + Int32 int32 + Int16 int16 + Int8 int8 + Int int +} + +type allUnsignedIntegers struct { + Uint32 uint32 + Uint16 uint16 + Uint8 uint8 +} + +type allFloat struct { + Float64 float64 + Float32 float32 + // NOTE: Complex32 and Complex64 are unsupported by BigQuery +} + +type allBoolean struct { + Bool bool +} + +type allTime struct { + Timestamp time.Time + Time civil.Time + Date civil.Date + DateTime civil.DateTime +} + +type allNumeric struct { + Numeric *big.Rat +} + +func reqField(name, typ string) *FieldSchema { + return &FieldSchema{ + Name: name, + Type: FieldType(typ), + Required: true, + } +} + +func optField(name, typ string) *FieldSchema { + return &FieldSchema{ + Name: name, + Type: FieldType(typ), + Required: false, + } +} + +func TestSimpleInference(t *testing.T) { + testCases := []struct { + in interface{} + want Schema + }{ + { + in: allSignedIntegers{}, + want: Schema{ + reqField("Int64", "INTEGER"), + reqField("Int32", "INTEGER"), + reqField("Int16", "INTEGER"), + reqField("Int8", "INTEGER"), + reqField("Int", "INTEGER"), + }, + }, + { + in: allUnsignedIntegers{}, + want: Schema{ + reqField("Uint32", "INTEGER"), + reqField("Uint16", "INTEGER"), + reqField("Uint8", "INTEGER"), + }, + }, + { + in: allFloat{}, + want: Schema{ + reqField("Float64", "FLOAT"), + reqField("Float32", "FLOAT"), + }, + }, + { + in: allBoolean{}, + want: Schema{ + reqField("Bool", "BOOLEAN"), + }, + }, + { + in: &allBoolean{}, + want: Schema{ + reqField("Bool", "BOOLEAN"), + }, + }, + { + in: allTime{}, + want: Schema{ + reqField("Timestamp", "TIMESTAMP"), + reqField("Time", "TIME"), + reqField("Date", "DATE"), + reqField("DateTime", "DATETIME"), + }, + }, + { + in: &allNumeric{}, + want: Schema{ + reqField("Numeric", "NUMERIC"), + }, + }, + { + in: allStrings{}, + want: Schema{ + reqField("String", "STRING"), + reqField("ByteSlice", "BYTES"), + }, + }, + } + for _, tc := range testCases { + got, err := InferSchema(tc.in) + if err != nil { + t.Fatalf("%T: error inferring TableSchema: %v", tc.in, err) + } + if !testutil.Equal(got, tc.want) { + t.Errorf("%T: inferring TableSchema: got:\n%#v\nwant:\n%#v", tc.in, + pretty.Value(got), pretty.Value(tc.want)) + } + } +} + +type containsNested struct { + hidden string + NotNested int + Nested struct { + Inside int + } +} + +type containsDoubleNested struct { + NotNested int + Nested struct { + InsideNested struct { + Inside int + } + } +} + +type ptrNested struct { + Ptr *struct{ Inside int } +} + +type dup struct { // more than one field of the same struct type + A, B allBoolean +} + +func TestNestedInference(t *testing.T) { + testCases := []struct { + in interface{} + want Schema + }{ + { + in: containsNested{}, + want: Schema{ + reqField("NotNested", "INTEGER"), + &FieldSchema{ + Name: "Nested", + Required: true, + Type: "RECORD", + Schema: Schema{reqField("Inside", "INTEGER")}, + }, + }, + }, + { + in: containsDoubleNested{}, + want: Schema{ + reqField("NotNested", "INTEGER"), + &FieldSchema{ + Name: "Nested", + Required: true, + Type: "RECORD", + Schema: Schema{ + { + Name: "InsideNested", + Required: true, + Type: "RECORD", + Schema: Schema{reqField("Inside", "INTEGER")}, + }, + }, + }, + }, + }, + { + in: ptrNested{}, + want: Schema{ + &FieldSchema{ + Name: "Ptr", + Required: true, + Type: "RECORD", + Schema: Schema{reqField("Inside", "INTEGER")}, + }, + }, + }, + { + in: dup{}, + want: Schema{ + &FieldSchema{ + Name: "A", + Required: true, + Type: "RECORD", + Schema: Schema{reqField("Bool", "BOOLEAN")}, + }, + &FieldSchema{ + Name: "B", + Required: true, + Type: "RECORD", + Schema: Schema{reqField("Bool", "BOOLEAN")}, + }, + }, + }, + } + + for _, tc := range testCases { + got, err := InferSchema(tc.in) + if err != nil { + t.Fatalf("%T: error inferring TableSchema: %v", tc.in, err) + } + if !testutil.Equal(got, tc.want) { + t.Errorf("%T: inferring TableSchema: got:\n%#v\nwant:\n%#v", tc.in, + pretty.Value(got), pretty.Value(tc.want)) + } + } +} + +type repeated struct { + NotRepeated []byte + RepeatedByteSlice [][]byte + Slice []int + Array [5]bool +} + +type nestedRepeated struct { + NotRepeated int + Repeated []struct { + Inside int + } + RepeatedPtr []*struct{ Inside int } +} + +func repField(name, typ string) *FieldSchema { + return &FieldSchema{ + Name: name, + Type: FieldType(typ), + Repeated: true, + } +} + +func TestRepeatedInference(t *testing.T) { + testCases := []struct { + in interface{} + want Schema + }{ + { + in: repeated{}, + want: Schema{ + reqField("NotRepeated", "BYTES"), + repField("RepeatedByteSlice", "BYTES"), + repField("Slice", "INTEGER"), + repField("Array", "BOOLEAN"), + }, + }, + { + in: nestedRepeated{}, + want: Schema{ + reqField("NotRepeated", "INTEGER"), + { + Name: "Repeated", + Repeated: true, + Type: "RECORD", + Schema: Schema{reqField("Inside", "INTEGER")}, + }, + { + Name: "RepeatedPtr", + Repeated: true, + Type: "RECORD", + Schema: Schema{reqField("Inside", "INTEGER")}, + }, + }, + }, + } + + for i, tc := range testCases { + got, err := InferSchema(tc.in) + if err != nil { + t.Fatalf("%d: error inferring TableSchema: %v", i, err) + } + if !testutil.Equal(got, tc.want) { + t.Errorf("%d: inferring TableSchema: got:\n%#v\nwant:\n%#v", i, + pretty.Value(got), pretty.Value(tc.want)) + } + } +} + +type allNulls struct { + A NullInt64 + B NullFloat64 + C NullBool + D NullString + E NullTimestamp + F NullTime + G NullDate + H NullDateTime +} + +func TestNullInference(t *testing.T) { + got, err := InferSchema(allNulls{}) + if err != nil { + t.Fatal(err) + } + want := Schema{ + optField("A", "INTEGER"), + optField("B", "FLOAT"), + optField("C", "BOOLEAN"), + optField("D", "STRING"), + optField("E", "TIMESTAMP"), + optField("F", "TIME"), + optField("G", "DATE"), + optField("H", "DATETIME"), + } + if diff := testutil.Diff(got, want); diff != "" { + t.Error(diff) + } +} + +type Embedded struct { + Embedded int +} + +type embedded struct { + Embedded2 int +} + +type nestedEmbedded struct { + Embedded + embedded +} + +func TestEmbeddedInference(t *testing.T) { + got, err := InferSchema(nestedEmbedded{}) + if err != nil { + t.Fatal(err) + } + want := Schema{ + reqField("Embedded", "INTEGER"), + reqField("Embedded2", "INTEGER"), + } + if !testutil.Equal(got, want) { + t.Errorf("got %v, want %v", pretty.Value(got), pretty.Value(want)) + } +} + +func TestRecursiveInference(t *testing.T) { + type List struct { + Val int + Next *List + } + + _, err := InferSchema(List{}) + if err == nil { + t.Fatal("got nil, want error") + } +} + +type withTags struct { + NoTag int + ExcludeTag int `bigquery:"-"` + SimpleTag int `bigquery:"simple_tag"` + UnderscoreTag int `bigquery:"_id"` + MixedCase int `bigquery:"MIXEDcase"` + Nullable []byte `bigquery:",nullable"` + NullNumeric *big.Rat `bigquery:",nullable"` +} + +type withTagsNested struct { + Nested withTags `bigquery:"nested"` + NestedAnonymous struct { + ExcludeTag int `bigquery:"-"` + Inside int `bigquery:"inside"` + } `bigquery:"anon"` + PNested *struct{ X int } // not nullable, for backwards compatibility + PNestedNullable *struct{ X int } `bigquery:",nullable"` +} + +type withTagsRepeated struct { + Repeated []withTags `bigquery:"repeated"` + RepeatedAnonymous []struct { + ExcludeTag int `bigquery:"-"` + Inside int `bigquery:"inside"` + } `bigquery:"anon"` +} + +type withTagsEmbedded struct { + withTags +} + +var withTagsSchema = Schema{ + reqField("NoTag", "INTEGER"), + reqField("simple_tag", "INTEGER"), + reqField("_id", "INTEGER"), + reqField("MIXEDcase", "INTEGER"), + optField("Nullable", "BYTES"), + optField("NullNumeric", "NUMERIC"), +} + +func TestTagInference(t *testing.T) { + testCases := []struct { + in interface{} + want Schema + }{ + { + in: withTags{}, + want: withTagsSchema, + }, + { + in: withTagsNested{}, + want: Schema{ + &FieldSchema{ + Name: "nested", + Required: true, + Type: "RECORD", + Schema: withTagsSchema, + }, + &FieldSchema{ + Name: "anon", + Required: true, + Type: "RECORD", + Schema: Schema{reqField("inside", "INTEGER")}, + }, + &FieldSchema{ + Name: "PNested", + Required: true, + Type: "RECORD", + Schema: Schema{reqField("X", "INTEGER")}, + }, + &FieldSchema{ + Name: "PNestedNullable", + Required: false, + Type: "RECORD", + Schema: Schema{reqField("X", "INTEGER")}, + }, + }, + }, + { + in: withTagsRepeated{}, + want: Schema{ + &FieldSchema{ + Name: "repeated", + Repeated: true, + Type: "RECORD", + Schema: withTagsSchema, + }, + &FieldSchema{ + Name: "anon", + Repeated: true, + Type: "RECORD", + Schema: Schema{reqField("inside", "INTEGER")}, + }, + }, + }, + { + in: withTagsEmbedded{}, + want: withTagsSchema, + }, + } + for i, tc := range testCases { + got, err := InferSchema(tc.in) + if err != nil { + t.Fatalf("%d: error inferring TableSchema: %v", i, err) + } + if !testutil.Equal(got, tc.want) { + t.Errorf("%d: inferring TableSchema: got:\n%#v\nwant:\n%#v", i, + pretty.Value(got), pretty.Value(tc.want)) + } + } +} + +func TestTagInferenceErrors(t *testing.T) { + testCases := []struct { + in interface{} + err error + }{ + { + in: struct { + LongTag int `bigquery:"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxy"` + }{}, + err: errInvalidFieldName, + }, + { + in: struct { + UnsupporedStartChar int `bigquery:"øab"` + }{}, + err: errInvalidFieldName, + }, + { + in: struct { + UnsupportedEndChar int `bigquery:"abø"` + }{}, + err: errInvalidFieldName, + }, + { + in: struct { + UnsupportedMiddleChar int `bigquery:"aøb"` + }{}, + err: errInvalidFieldName, + }, + { + in: struct { + StartInt int `bigquery:"1abc"` + }{}, + err: errInvalidFieldName, + }, + { + in: struct { + Hyphens int `bigquery:"a-b"` + }{}, + err: errInvalidFieldName, + }, + } + for i, tc := range testCases { + want := tc.err + _, got := InferSchema(tc.in) + if got != want { + t.Errorf("%d: inferring TableSchema: got:\n%#v\nwant:\n%#v", i, got, want) + } + } + + _, err := InferSchema(struct { + X int `bigquery:",optional"` + }{}) + if err == nil { + t.Error("got nil, want error") + } +} + +func TestSchemaErrors(t *testing.T) { + testCases := []struct { + in interface{} + err error + }{ + { + in: []byte{}, + err: errNoStruct, + }, + { + in: new(int), + err: errNoStruct, + }, + { + in: struct{ Uint uint }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ Uint64 uint64 }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ Uintptr uintptr }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ Complex complex64 }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ Map map[string]int }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ Chan chan bool }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ Ptr *int }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ Interface interface{} }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ MultiDimensional [][]int }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ MultiDimensional [][][]byte }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ SliceOfPointer []*int }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ SliceOfNull []NullInt64 }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ ChanSlice []chan bool }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ NestedChan struct{ Chan []chan bool } }{}, + err: errUnsupportedFieldType, + }, + { + in: struct { + X int `bigquery:",nullable"` + }{}, + err: errBadNullable, + }, + { + in: struct { + X bool `bigquery:",nullable"` + }{}, + err: errBadNullable, + }, + { + in: struct { + X struct{ N int } `bigquery:",nullable"` + }{}, + err: errBadNullable, + }, + { + in: struct { + X []int `bigquery:",nullable"` + }{}, + err: errBadNullable, + }, + { + in: struct{ X *[]byte }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ X *[]int }{}, + err: errUnsupportedFieldType, + }, + { + in: struct{ X *int }{}, + err: errUnsupportedFieldType, + }, + } + for _, tc := range testCases { + want := tc.err + _, got := InferSchema(tc.in) + if got != want { + t.Errorf("%#v: got:\n%#v\nwant:\n%#v", tc.in, got, want) + } + } +} + +func TestHasRecursiveType(t *testing.T) { + type ( + nonStruct int + nonRec struct{ A string } + dup struct{ A, B nonRec } + rec struct { + A int + B *rec + } + recUnexported struct { + A int + b *rec + } + hasRec struct { + A int + R *rec + } + recSlicePointer struct { + A []*recSlicePointer + } + ) + for _, test := range []struct { + in interface{} + want bool + }{ + {nonStruct(0), false}, + {nonRec{}, false}, + {dup{}, false}, + {rec{}, true}, + {recUnexported{}, false}, + {hasRec{}, true}, + {&recSlicePointer{}, true}, + } { + got, err := hasRecursiveType(reflect.TypeOf(test.in), nil) + if err != nil { + t.Fatal(err) + } + if got != test.want { + t.Errorf("%T: got %t, want %t", test.in, got, test.want) + } + } +} + +func TestSchemaFromJSON(t *testing.T) { + testCasesExpectingSuccess := []struct { + bqSchemaJSON []byte + description string + expectedSchema Schema + }{ + { + description: "Flat table with a mixture of NULLABLE and REQUIRED fields", + bqSchemaJSON: []byte(` +[ + {"name":"flat_string","type":"STRING","mode":"NULLABLE","description":"Flat nullable string"}, + {"name":"flat_bytes","type":"BYTES","mode":"REQUIRED","description":"Flat required BYTES"}, + {"name":"flat_integer","type":"INTEGER","mode":"NULLABLE","description":"Flat nullable INTEGER"}, + {"name":"flat_float","type":"FLOAT","mode":"REQUIRED","description":"Flat required FLOAT"}, + {"name":"flat_boolean","type":"BOOLEAN","mode":"NULLABLE","description":"Flat nullable BOOLEAN"}, + {"name":"flat_timestamp","type":"TIMESTAMP","mode":"REQUIRED","description":"Flat required TIMESTAMP"}, + {"name":"flat_date","type":"DATE","mode":"NULLABLE","description":"Flat required DATE"}, + {"name":"flat_time","type":"TIME","mode":"REQUIRED","description":"Flat nullable TIME"}, + {"name":"flat_datetime","type":"DATETIME","mode":"NULLABLE","description":"Flat required DATETIME"}, + {"name":"flat_numeric","type":"NUMERIC","mode":"REQUIRED","description":"Flat nullable NUMERIC"} +]`), + expectedSchema: Schema{ + fieldSchema("Flat nullable string", "flat_string", "STRING", false, false), + fieldSchema("Flat required BYTES", "flat_bytes", "BYTES", false, true), + fieldSchema("Flat nullable INTEGER", "flat_integer", "INTEGER", false, false), + fieldSchema("Flat required FLOAT", "flat_float", "FLOAT", false, true), + fieldSchema("Flat nullable BOOLEAN", "flat_boolean", "BOOLEAN", false, false), + fieldSchema("Flat required TIMESTAMP", "flat_timestamp", "TIMESTAMP", false, true), + fieldSchema("Flat required DATE", "flat_date", "DATE", false, false), + fieldSchema("Flat nullable TIME", "flat_time", "TIME", false, true), + fieldSchema("Flat required DATETIME", "flat_datetime", "DATETIME", false, false), + fieldSchema("Flat nullable NUMERIC", "flat_numeric", "NUMERIC", false, true), + }, + }, + { + description: "Table with a nested RECORD", + bqSchemaJSON: []byte(` +[ + {"name":"flat_string","type":"STRING","mode":"NULLABLE","description":"Flat nullable string"}, + {"name":"nested_record","type":"RECORD","mode":"NULLABLE","description":"Nested nullable RECORD","fields":[{"name":"record_field_1","type":"STRING","mode":"NULLABLE","description":"First nested record field"},{"name":"record_field_2","type":"INTEGER","mode":"REQUIRED","description":"Second nested record field"}]} +]`), + expectedSchema: Schema{ + fieldSchema("Flat nullable string", "flat_string", "STRING", false, false), + &FieldSchema{ + Description: "Nested nullable RECORD", + Name: "nested_record", + Required: false, + Type: "RECORD", + Schema: Schema{ + { + Description: "First nested record field", + Name: "record_field_1", + Required: false, + Type: "STRING", + }, + { + Description: "Second nested record field", + Name: "record_field_2", + Required: true, + Type: "INTEGER", + }, + }, + }, + }, + }, + { + description: "Table with a repeated RECORD", + bqSchemaJSON: []byte(` +[ + {"name":"flat_string","type":"STRING","mode":"NULLABLE","description":"Flat nullable string"}, + {"name":"nested_record","type":"RECORD","mode":"REPEATED","description":"Nested nullable RECORD","fields":[{"name":"record_field_1","type":"STRING","mode":"NULLABLE","description":"First nested record field"},{"name":"record_field_2","type":"INTEGER","mode":"REQUIRED","description":"Second nested record field"}]} +]`), + expectedSchema: Schema{ + fieldSchema("Flat nullable string", "flat_string", "STRING", false, false), + &FieldSchema{ + Description: "Nested nullable RECORD", + Name: "nested_record", + Repeated: true, + Required: false, + Type: "RECORD", + Schema: Schema{ + { + Description: "First nested record field", + Name: "record_field_1", + Required: false, + Type: "STRING", + }, + { + Description: "Second nested record field", + Name: "record_field_2", + Required: true, + Type: "INTEGER", + }, + }, + }, + }, + }, + } + for _, tc := range testCasesExpectingSuccess { + convertedSchema, err := SchemaFromJSON(tc.bqSchemaJSON) + if err != nil { + t.Errorf("encountered an error when converting JSON table schema (%s): %v", tc.description, err) + continue + } + if !testutil.Equal(convertedSchema, tc.expectedSchema) { + t.Errorf("generated JSON table schema (%s) differs from the expected schema", tc.description) + } + } + + testCasesExpectingFailure := []struct { + bqSchemaJSON []byte + description string + }{ + { + description: "Schema with invalid JSON", + bqSchemaJSON: []byte(`This is not JSON`), + }, + { + description: "Schema with unknown field type", + bqSchemaJSON: []byte(`[{"name":"strange_type","type":"STRANGE","description":"This type should not exist"}]`), + }, + { + description: "Schema with zero length", + bqSchemaJSON: []byte(``), + }, + } + for _, tc := range testCasesExpectingFailure { + _, err := SchemaFromJSON(tc.bqSchemaJSON) + if err == nil { + t.Errorf("converting this schema should have returned an error (%s): %v", tc.description, err) + continue + } + } +} diff --git a/vendor/cloud.google.com/go/bigquery/table.go b/vendor/cloud.google.com/go/bigquery/table.go new file mode 100644 index 00000000..6181f460 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/table.go @@ -0,0 +1,617 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "context" + "errors" + "fmt" + "time" + + "cloud.google.com/go/internal/optional" + "cloud.google.com/go/internal/trace" + bq "google.golang.org/api/bigquery/v2" +) + +// A Table is a reference to a BigQuery table. +type Table struct { + // ProjectID, DatasetID and TableID may be omitted if the Table is the destination for a query. + // In this case the result will be stored in an ephemeral table. + ProjectID string + DatasetID string + // TableID must contain only letters (a-z, A-Z), numbers (0-9), or underscores (_). + // The maximum length is 1,024 characters. + TableID string + + c *Client +} + +// TableMetadata contains information about a BigQuery table. +type TableMetadata struct { + // The following fields can be set when creating a table. + + // The user-friendly name for the table. + Name string + + // The user-friendly description of the table. + Description string + + // The table schema. If provided on create, ViewQuery must be empty. + Schema Schema + + // The query to use for a view. If provided on create, Schema must be nil. + ViewQuery string + + // Use Legacy SQL for the view query. + // At most one of UseLegacySQL and UseStandardSQL can be true. + UseLegacySQL bool + + // Use Legacy SQL for the view query. The default. + // At most one of UseLegacySQL and UseStandardSQL can be true. + // Deprecated: use UseLegacySQL. + UseStandardSQL bool + + // If non-nil, the table is partitioned by time. + TimePartitioning *TimePartitioning + + // Clustering specifies the data clustering configuration for the table. + Clustering *Clustering + + // The time when this table expires. If set, this table will expire at the + // specified time. Expired tables will be deleted and their storage + // reclaimed. The zero value is ignored. + ExpirationTime time.Time + + // User-provided labels. + Labels map[string]string + + // Information about a table stored outside of BigQuery. + ExternalDataConfig *ExternalDataConfig + + // Custom encryption configuration (e.g., Cloud KMS keys). + EncryptionConfig *EncryptionConfig + + // All the fields below are read-only. + + FullID string // An opaque ID uniquely identifying the table. + Type TableType + CreationTime time.Time + LastModifiedTime time.Time + + // The size of the table in bytes. + // This does not include data that is being buffered during a streaming insert. + NumBytes int64 + + // The number of rows of data in this table. + // This does not include data that is being buffered during a streaming insert. + NumRows uint64 + + // Contains information regarding this table's streaming buffer, if one is + // present. This field will be nil if the table is not being streamed to or if + // there is no data in the streaming buffer. + StreamingBuffer *StreamingBuffer + + // ETag is the ETag obtained when reading metadata. Pass it to Table.Update to + // ensure that the metadata hasn't changed since it was read. + ETag string +} + +// TableCreateDisposition specifies the circumstances under which destination table will be created. +// Default is CreateIfNeeded. +type TableCreateDisposition string + +const ( + // CreateIfNeeded will create the table if it does not already exist. + // Tables are created atomically on successful completion of a job. + CreateIfNeeded TableCreateDisposition = "CREATE_IF_NEEDED" + + // CreateNever ensures the table must already exist and will not be + // automatically created. + CreateNever TableCreateDisposition = "CREATE_NEVER" +) + +// TableWriteDisposition specifies how existing data in a destination table is treated. +// Default is WriteAppend. +type TableWriteDisposition string + +const ( + // WriteAppend will append to any existing data in the destination table. + // Data is appended atomically on successful completion of a job. + WriteAppend TableWriteDisposition = "WRITE_APPEND" + + // WriteTruncate overrides the existing data in the destination table. + // Data is overwritten atomically on successful completion of a job. + WriteTruncate TableWriteDisposition = "WRITE_TRUNCATE" + + // WriteEmpty fails writes if the destination table already contains data. + WriteEmpty TableWriteDisposition = "WRITE_EMPTY" +) + +// TableType is the type of table. +type TableType string + +const ( + // RegularTable is a regular table. + RegularTable TableType = "TABLE" + // ViewTable is a table type describing that the table is view. See more + // information at https://cloud.google.com/bigquery/docs/views. + ViewTable TableType = "VIEW" + // ExternalTable is a table type describing that the table is an external + // table (also known as a federated data source). See more information at + // https://cloud.google.com/bigquery/external-data-sources. + ExternalTable TableType = "EXTERNAL" +) + +// TimePartitioning describes the time-based date partitioning on a table. +// For more information see: https://cloud.google.com/bigquery/docs/creating-partitioned-tables. +type TimePartitioning struct { + // The amount of time to keep the storage for a partition. + // If the duration is empty (0), the data in the partitions do not expire. + Expiration time.Duration + + // If empty, the table is partitioned by pseudo column '_PARTITIONTIME'; if set, the + // table is partitioned by this field. The field must be a top-level TIMESTAMP or + // DATE field. Its mode must be NULLABLE or REQUIRED. + Field string + + // If true, queries that reference this table must include a filter (e.g. a WHERE predicate) + // that can be used for partition elimination. + RequirePartitionFilter bool +} + +func (p *TimePartitioning) toBQ() *bq.TimePartitioning { + if p == nil { + return nil + } + return &bq.TimePartitioning{ + Type: "DAY", + ExpirationMs: int64(p.Expiration / time.Millisecond), + Field: p.Field, + RequirePartitionFilter: p.RequirePartitionFilter, + } +} + +func bqToTimePartitioning(q *bq.TimePartitioning) *TimePartitioning { + if q == nil { + return nil + } + return &TimePartitioning{ + Expiration: time.Duration(q.ExpirationMs) * time.Millisecond, + Field: q.Field, + RequirePartitionFilter: q.RequirePartitionFilter, + } +} + +// Clustering governs the organization of data within a partitioned table. +// For more information, see https://cloud.google.com/bigquery/docs/clustered-tables +type Clustering struct { + Fields []string +} + +func (c *Clustering) toBQ() *bq.Clustering { + if c == nil { + return nil + } + return &bq.Clustering{ + Fields: c.Fields, + } +} + +func bqToClustering(q *bq.Clustering) *Clustering { + if q == nil { + return nil + } + return &Clustering{ + Fields: q.Fields, + } +} + +// EncryptionConfig configures customer-managed encryption on tables. +type EncryptionConfig struct { + // Describes the Cloud KMS encryption key that will be used to protect + // destination BigQuery table. The BigQuery Service Account associated with your + // project requires access to this encryption key. + KMSKeyName string +} + +func (e *EncryptionConfig) toBQ() *bq.EncryptionConfiguration { + if e == nil { + return nil + } + return &bq.EncryptionConfiguration{ + KmsKeyName: e.KMSKeyName, + } +} + +func bqToEncryptionConfig(q *bq.EncryptionConfiguration) *EncryptionConfig { + if q == nil { + return nil + } + return &EncryptionConfig{ + KMSKeyName: q.KmsKeyName, + } +} + +// StreamingBuffer holds information about the streaming buffer. +type StreamingBuffer struct { + // A lower-bound estimate of the number of bytes currently in the streaming + // buffer. + EstimatedBytes uint64 + + // A lower-bound estimate of the number of rows currently in the streaming + // buffer. + EstimatedRows uint64 + + // The time of the oldest entry in the streaming buffer. + OldestEntryTime time.Time +} + +func (t *Table) toBQ() *bq.TableReference { + return &bq.TableReference{ + ProjectId: t.ProjectID, + DatasetId: t.DatasetID, + TableId: t.TableID, + } +} + +// FullyQualifiedName returns the ID of the table in projectID:datasetID.tableID format. +func (t *Table) FullyQualifiedName() string { + return fmt.Sprintf("%s:%s.%s", t.ProjectID, t.DatasetID, t.TableID) +} + +// implicitTable reports whether Table is an empty placeholder, which signifies that a new table should be created with an auto-generated Table ID. +func (t *Table) implicitTable() bool { + return t.ProjectID == "" && t.DatasetID == "" && t.TableID == "" +} + +// Create creates a table in the BigQuery service. +// Pass in a TableMetadata value to configure the table. +// If tm.View.Query is non-empty, the created table will be of type VIEW. +// If no ExpirationTime is specified, the table will never expire. +// After table creation, a view can be modified only if its table was initially created +// with a view. +func (t *Table) Create(ctx context.Context, tm *TableMetadata) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Table.Create") + defer func() { trace.EndSpan(ctx, err) }() + + table, err := tm.toBQ() + if err != nil { + return err + } + table.TableReference = &bq.TableReference{ + ProjectId: t.ProjectID, + DatasetId: t.DatasetID, + TableId: t.TableID, + } + req := t.c.bqs.Tables.Insert(t.ProjectID, t.DatasetID, table).Context(ctx) + setClientHeader(req.Header()) + _, err = req.Do() + return err +} + +func (tm *TableMetadata) toBQ() (*bq.Table, error) { + t := &bq.Table{} + if tm == nil { + return t, nil + } + if tm.Schema != nil && tm.ViewQuery != "" { + return nil, errors.New("bigquery: provide Schema or ViewQuery, not both") + } + t.FriendlyName = tm.Name + t.Description = tm.Description + t.Labels = tm.Labels + if tm.Schema != nil { + t.Schema = tm.Schema.toBQ() + } + if tm.ViewQuery != "" { + if tm.UseStandardSQL && tm.UseLegacySQL { + return nil, errors.New("bigquery: cannot provide both UseStandardSQL and UseLegacySQL") + } + t.View = &bq.ViewDefinition{Query: tm.ViewQuery} + if tm.UseLegacySQL { + t.View.UseLegacySql = true + } else { + t.View.UseLegacySql = false + t.View.ForceSendFields = append(t.View.ForceSendFields, "UseLegacySql") + } + } else if tm.UseLegacySQL || tm.UseStandardSQL { + return nil, errors.New("bigquery: UseLegacy/StandardSQL requires ViewQuery") + } + t.TimePartitioning = tm.TimePartitioning.toBQ() + t.Clustering = tm.Clustering.toBQ() + + if !validExpiration(tm.ExpirationTime) { + return nil, fmt.Errorf("invalid expiration time: %v.\n"+ + "Valid expiration times are after 1678 and before 2262", tm.ExpirationTime) + } + if !tm.ExpirationTime.IsZero() && tm.ExpirationTime != NeverExpire { + t.ExpirationTime = tm.ExpirationTime.UnixNano() / 1e6 + } + if tm.ExternalDataConfig != nil { + edc := tm.ExternalDataConfig.toBQ() + t.ExternalDataConfiguration = &edc + } + t.EncryptionConfiguration = tm.EncryptionConfig.toBQ() + if tm.FullID != "" { + return nil, errors.New("cannot set FullID on create") + } + if tm.Type != "" { + return nil, errors.New("cannot set Type on create") + } + if !tm.CreationTime.IsZero() { + return nil, errors.New("cannot set CreationTime on create") + } + if !tm.LastModifiedTime.IsZero() { + return nil, errors.New("cannot set LastModifiedTime on create") + } + if tm.NumBytes != 0 { + return nil, errors.New("cannot set NumBytes on create") + } + if tm.NumRows != 0 { + return nil, errors.New("cannot set NumRows on create") + } + if tm.StreamingBuffer != nil { + return nil, errors.New("cannot set StreamingBuffer on create") + } + if tm.ETag != "" { + return nil, errors.New("cannot set ETag on create") + } + return t, nil +} + +// Metadata fetches the metadata for the table. +func (t *Table) Metadata(ctx context.Context) (md *TableMetadata, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Table.Metadata") + defer func() { trace.EndSpan(ctx, err) }() + + req := t.c.bqs.Tables.Get(t.ProjectID, t.DatasetID, t.TableID).Context(ctx) + setClientHeader(req.Header()) + var table *bq.Table + err = runWithRetry(ctx, func() (err error) { + table, err = req.Do() + return err + }) + if err != nil { + return nil, err + } + return bqToTableMetadata(table) +} + +func bqToTableMetadata(t *bq.Table) (*TableMetadata, error) { + md := &TableMetadata{ + Description: t.Description, + Name: t.FriendlyName, + Type: TableType(t.Type), + FullID: t.Id, + Labels: t.Labels, + NumBytes: t.NumBytes, + NumRows: t.NumRows, + ExpirationTime: unixMillisToTime(t.ExpirationTime), + CreationTime: unixMillisToTime(t.CreationTime), + LastModifiedTime: unixMillisToTime(int64(t.LastModifiedTime)), + ETag: t.Etag, + EncryptionConfig: bqToEncryptionConfig(t.EncryptionConfiguration), + } + if t.Schema != nil { + md.Schema = bqToSchema(t.Schema) + } + if t.View != nil { + md.ViewQuery = t.View.Query + md.UseLegacySQL = t.View.UseLegacySql + } + md.TimePartitioning = bqToTimePartitioning(t.TimePartitioning) + md.Clustering = bqToClustering(t.Clustering) + if t.StreamingBuffer != nil { + md.StreamingBuffer = &StreamingBuffer{ + EstimatedBytes: t.StreamingBuffer.EstimatedBytes, + EstimatedRows: t.StreamingBuffer.EstimatedRows, + OldestEntryTime: unixMillisToTime(int64(t.StreamingBuffer.OldestEntryTime)), + } + } + if t.ExternalDataConfiguration != nil { + edc, err := bqToExternalDataConfig(t.ExternalDataConfiguration) + if err != nil { + return nil, err + } + md.ExternalDataConfig = edc + } + return md, nil +} + +// Delete deletes the table. +func (t *Table) Delete(ctx context.Context) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Table.Delete") + defer func() { trace.EndSpan(ctx, err) }() + + req := t.c.bqs.Tables.Delete(t.ProjectID, t.DatasetID, t.TableID).Context(ctx) + setClientHeader(req.Header()) + return req.Do() +} + +// Read fetches the contents of the table. +func (t *Table) Read(ctx context.Context) *RowIterator { + return t.read(ctx, fetchPage) +} + +func (t *Table) read(ctx context.Context, pf pageFetcher) *RowIterator { + return newRowIterator(ctx, t, pf) +} + +// NeverExpire is a sentinel value used to remove a table'e expiration time. +var NeverExpire = time.Time{}.Add(-1) + +// Update modifies specific Table metadata fields. +func (t *Table) Update(ctx context.Context, tm TableMetadataToUpdate, etag string) (md *TableMetadata, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/bigquery.Table.Update") + defer func() { trace.EndSpan(ctx, err) }() + + bqt, err := tm.toBQ() + if err != nil { + return nil, err + } + call := t.c.bqs.Tables.Patch(t.ProjectID, t.DatasetID, t.TableID, bqt).Context(ctx) + setClientHeader(call.Header()) + if etag != "" { + call.Header().Set("If-Match", etag) + } + var res *bq.Table + if err := runWithRetry(ctx, func() (err error) { + res, err = call.Do() + return err + }); err != nil { + return nil, err + } + return bqToTableMetadata(res) +} + +func (tm *TableMetadataToUpdate) toBQ() (*bq.Table, error) { + t := &bq.Table{} + forceSend := func(field string) { + t.ForceSendFields = append(t.ForceSendFields, field) + } + + if tm.Description != nil { + t.Description = optional.ToString(tm.Description) + forceSend("Description") + } + if tm.Name != nil { + t.FriendlyName = optional.ToString(tm.Name) + forceSend("FriendlyName") + } + if tm.Schema != nil { + t.Schema = tm.Schema.toBQ() + forceSend("Schema") + } + if tm.EncryptionConfig != nil { + t.EncryptionConfiguration = tm.EncryptionConfig.toBQ() + } + + if !validExpiration(tm.ExpirationTime) { + return nil, fmt.Errorf("invalid expiration time: %v.\n"+ + "Valid expiration times are after 1678 and before 2262", tm.ExpirationTime) + } + if tm.ExpirationTime == NeverExpire { + t.NullFields = append(t.NullFields, "ExpirationTime") + } else if !tm.ExpirationTime.IsZero() { + t.ExpirationTime = tm.ExpirationTime.UnixNano() / 1e6 + forceSend("ExpirationTime") + } + if tm.TimePartitioning != nil { + t.TimePartitioning = tm.TimePartitioning.toBQ() + t.TimePartitioning.ForceSendFields = []string{"Expiration", "RequirePartitionFilter"} + } + if tm.ViewQuery != nil { + t.View = &bq.ViewDefinition{ + Query: optional.ToString(tm.ViewQuery), + ForceSendFields: []string{"Query"}, + } + } + if tm.UseLegacySQL != nil { + if t.View == nil { + t.View = &bq.ViewDefinition{} + } + t.View.UseLegacySql = optional.ToBool(tm.UseLegacySQL) + t.View.ForceSendFields = append(t.View.ForceSendFields, "UseLegacySql") + } + labels, forces, nulls := tm.update() + t.Labels = labels + t.ForceSendFields = append(t.ForceSendFields, forces...) + t.NullFields = append(t.NullFields, nulls...) + return t, nil +} + +// validExpiration ensures a specified time is either the sentinel NeverExpire, +// the zero value, or within the defined range of UnixNano. Internal +// represetations of expiration times are based upon Time.UnixNano. Any time +// before 1678 or after 2262 cannot be represented by an int64 and is therefore +// undefined and invalid. See https://godoc.org/time#Time.UnixNano. +func validExpiration(t time.Time) bool { + return t == NeverExpire || t.IsZero() || time.Unix(0, t.UnixNano()).Equal(t) +} + +// TableMetadataToUpdate is used when updating a table's metadata. +// Only non-nil fields will be updated. +type TableMetadataToUpdate struct { + // The user-friendly description of this table. + Description optional.String + + // The user-friendly name for this table. + Name optional.String + + // The table's schema. + // When updating a schema, you can add columns but not remove them. + Schema Schema + + // The table's encryption configuration. When calling Update, ensure that + // all mutable fields of EncryptionConfig are populated. + EncryptionConfig *EncryptionConfig + + // The time when this table expires. To remove a table's expiration, + // set ExpirationTime to NeverExpire. The zero value is ignored. + ExpirationTime time.Time + + // The query to use for a view. + ViewQuery optional.String + + // Use Legacy SQL for the view query. + UseLegacySQL optional.Bool + + // TimePartitioning allows modification of certain aspects of partition + // configuration such as partition expiration and whether partition + // filtration is required at query time. When calling Update, ensure + // that all mutable fields of TimePartitioning are populated. + TimePartitioning *TimePartitioning + + labelUpdater +} + +// labelUpdater contains common code for updating labels. +type labelUpdater struct { + setLabels map[string]string + deleteLabels map[string]bool +} + +// SetLabel causes a label to be added or modified on a call to Update. +func (u *labelUpdater) SetLabel(name, value string) { + if u.setLabels == nil { + u.setLabels = map[string]string{} + } + u.setLabels[name] = value +} + +// DeleteLabel causes a label to be deleted on a call to Update. +func (u *labelUpdater) DeleteLabel(name string) { + if u.deleteLabels == nil { + u.deleteLabels = map[string]bool{} + } + u.deleteLabels[name] = true +} + +func (u *labelUpdater) update() (labels map[string]string, forces, nulls []string) { + if u.setLabels == nil && u.deleteLabels == nil { + return nil, nil, nil + } + labels = map[string]string{} + for k, v := range u.setLabels { + labels[k] = v + } + if len(labels) == 0 && len(u.deleteLabels) > 0 { + forces = []string{"Labels"} + } + for l := range u.deleteLabels { + nulls = append(nulls, "Labels."+l) + } + return labels, forces, nulls +} diff --git a/vendor/cloud.google.com/go/bigquery/table_test.go b/vendor/cloud.google.com/go/bigquery/table_test.go new file mode 100644 index 00000000..c8a77663 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/table_test.go @@ -0,0 +1,350 @@ +// Copyright 2017 Google LLC +// +// 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 bigquery + +import ( + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + bq "google.golang.org/api/bigquery/v2" +) + +func TestBQToTableMetadata(t *testing.T) { + aTime := time.Date(2017, 1, 26, 0, 0, 0, 0, time.Local) + aTimeMillis := aTime.UnixNano() / 1e6 + for _, test := range []struct { + in *bq.Table + want *TableMetadata + }{ + {&bq.Table{}, &TableMetadata{}}, // test minimal case + { + &bq.Table{ + CreationTime: aTimeMillis, + Description: "desc", + Etag: "etag", + ExpirationTime: aTimeMillis, + FriendlyName: "fname", + Id: "id", + LastModifiedTime: uint64(aTimeMillis), + Location: "loc", + NumBytes: 123, + NumLongTermBytes: 23, + NumRows: 7, + StreamingBuffer: &bq.Streamingbuffer{ + EstimatedBytes: 11, + EstimatedRows: 3, + OldestEntryTime: uint64(aTimeMillis), + }, + TimePartitioning: &bq.TimePartitioning{ + ExpirationMs: 7890, + Type: "DAY", + Field: "pfield", + }, + Clustering: &bq.Clustering{ + Fields: []string{"cfield1", "cfield2"}, + }, + EncryptionConfiguration: &bq.EncryptionConfiguration{KmsKeyName: "keyName"}, + Type: "EXTERNAL", + View: &bq.ViewDefinition{Query: "view-query"}, + Labels: map[string]string{"a": "b"}, + ExternalDataConfiguration: &bq.ExternalDataConfiguration{ + SourceFormat: "GOOGLE_SHEETS", + }, + }, + &TableMetadata{ + Description: "desc", + Name: "fname", + ViewQuery: "view-query", + FullID: "id", + Type: ExternalTable, + Labels: map[string]string{"a": "b"}, + ExternalDataConfig: &ExternalDataConfig{SourceFormat: GoogleSheets}, + ExpirationTime: aTime.Truncate(time.Millisecond), + CreationTime: aTime.Truncate(time.Millisecond), + LastModifiedTime: aTime.Truncate(time.Millisecond), + NumBytes: 123, + NumRows: 7, + TimePartitioning: &TimePartitioning{ + Expiration: 7890 * time.Millisecond, + Field: "pfield", + }, + Clustering: &Clustering{ + Fields: []string{"cfield1", "cfield2"}, + }, + StreamingBuffer: &StreamingBuffer{ + EstimatedBytes: 11, + EstimatedRows: 3, + OldestEntryTime: aTime, + }, + EncryptionConfig: &EncryptionConfig{KMSKeyName: "keyName"}, + ETag: "etag", + }, + }, + } { + got, err := bqToTableMetadata(test.in) + if err != nil { + t.Fatal(err) + } + if diff := testutil.Diff(got, test.want); diff != "" { + t.Errorf("%+v:\n, -got, +want:\n%s", test.in, diff) + } + } +} + +func TestTableMetadataToBQ(t *testing.T) { + aTime := time.Date(2017, 1, 26, 0, 0, 0, 0, time.Local) + aTimeMillis := aTime.UnixNano() / 1e6 + sc := Schema{fieldSchema("desc", "name", "STRING", false, true)} + + for _, test := range []struct { + in *TableMetadata + want *bq.Table + }{ + {nil, &bq.Table{}}, + {&TableMetadata{}, &bq.Table{}}, + { + &TableMetadata{ + Name: "n", + Description: "d", + Schema: sc, + ExpirationTime: aTime, + Labels: map[string]string{"a": "b"}, + ExternalDataConfig: &ExternalDataConfig{SourceFormat: Bigtable}, + EncryptionConfig: &EncryptionConfig{KMSKeyName: "keyName"}, + }, + &bq.Table{ + FriendlyName: "n", + Description: "d", + Schema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqTableFieldSchema("desc", "name", "STRING", "REQUIRED"), + }, + }, + ExpirationTime: aTimeMillis, + Labels: map[string]string{"a": "b"}, + ExternalDataConfiguration: &bq.ExternalDataConfiguration{SourceFormat: "BIGTABLE"}, + EncryptionConfiguration: &bq.EncryptionConfiguration{KmsKeyName: "keyName"}, + }, + }, + { + &TableMetadata{ViewQuery: "q"}, + &bq.Table{ + View: &bq.ViewDefinition{ + Query: "q", + UseLegacySql: false, + ForceSendFields: []string{"UseLegacySql"}, + }, + }, + }, + { + &TableMetadata{ + ViewQuery: "q", + UseLegacySQL: true, + TimePartitioning: &TimePartitioning{}, + }, + &bq.Table{ + View: &bq.ViewDefinition{ + Query: "q", + UseLegacySql: true, + }, + TimePartitioning: &bq.TimePartitioning{ + Type: "DAY", + ExpirationMs: 0, + }, + }, + }, + { + &TableMetadata{ + ViewQuery: "q", + UseStandardSQL: true, + TimePartitioning: &TimePartitioning{ + Expiration: time.Second, + Field: "ofDreams", + }, + Clustering: &Clustering{ + Fields: []string{"cfield1"}, + }, + }, + &bq.Table{ + View: &bq.ViewDefinition{ + Query: "q", + UseLegacySql: false, + ForceSendFields: []string{"UseLegacySql"}, + }, + TimePartitioning: &bq.TimePartitioning{ + Type: "DAY", + ExpirationMs: 1000, + Field: "ofDreams", + }, + Clustering: &bq.Clustering{ + Fields: []string{"cfield1"}, + }, + }, + }, + { + &TableMetadata{ExpirationTime: NeverExpire}, + &bq.Table{ExpirationTime: 0}, + }, + } { + got, err := test.in.toBQ() + if err != nil { + t.Fatalf("%+v: %v", test.in, err) + } + if diff := testutil.Diff(got, test.want); diff != "" { + t.Errorf("%+v:\n-got, +want:\n%s", test.in, diff) + } + } + + // Errors + for _, in := range []*TableMetadata{ + {Schema: sc, ViewQuery: "q"}, // can't have both schema and query + {UseLegacySQL: true}, // UseLegacySQL without query + {UseStandardSQL: true}, // UseStandardSQL without query + // read-only fields + {FullID: "x"}, + {Type: "x"}, + {CreationTime: aTime}, + {LastModifiedTime: aTime}, + {NumBytes: 1}, + {NumRows: 1}, + {StreamingBuffer: &StreamingBuffer{}}, + {ETag: "x"}, + // expiration time outside allowable range is invalid + // See https://godoc.org/time#Time.UnixNano + {ExpirationTime: time.Date(1677, 9, 21, 0, 12, 43, 145224192, time.UTC).Add(-1)}, + {ExpirationTime: time.Date(2262, 04, 11, 23, 47, 16, 854775807, time.UTC).Add(1)}, + } { + _, err := in.toBQ() + if err == nil { + t.Errorf("%+v: got nil, want error", in) + } + } +} + +func TestTableMetadataToUpdateToBQ(t *testing.T) { + aTime := time.Date(2017, 1, 26, 0, 0, 0, 0, time.Local) + for _, test := range []struct { + tm TableMetadataToUpdate + want *bq.Table + }{ + { + tm: TableMetadataToUpdate{}, + want: &bq.Table{}, + }, + { + tm: TableMetadataToUpdate{ + Description: "d", + Name: "n", + }, + want: &bq.Table{ + Description: "d", + FriendlyName: "n", + ForceSendFields: []string{"Description", "FriendlyName"}, + }, + }, + { + tm: TableMetadataToUpdate{ + Schema: Schema{fieldSchema("desc", "name", "STRING", false, true)}, + ExpirationTime: aTime, + }, + want: &bq.Table{ + Schema: &bq.TableSchema{ + Fields: []*bq.TableFieldSchema{ + bqTableFieldSchema("desc", "name", "STRING", "REQUIRED"), + }, + }, + ExpirationTime: aTime.UnixNano() / 1e6, + ForceSendFields: []string{"Schema", "ExpirationTime"}, + }, + }, + { + tm: TableMetadataToUpdate{ViewQuery: "q"}, + want: &bq.Table{ + View: &bq.ViewDefinition{Query: "q", ForceSendFields: []string{"Query"}}, + }, + }, + { + tm: TableMetadataToUpdate{UseLegacySQL: false}, + want: &bq.Table{ + View: &bq.ViewDefinition{ + UseLegacySql: false, + ForceSendFields: []string{"UseLegacySql"}, + }, + }, + }, + { + tm: TableMetadataToUpdate{ViewQuery: "q", UseLegacySQL: true}, + want: &bq.Table{ + View: &bq.ViewDefinition{ + Query: "q", + UseLegacySql: true, + ForceSendFields: []string{"Query", "UseLegacySql"}, + }, + }, + }, + { + tm: func() (tm TableMetadataToUpdate) { + tm.SetLabel("L", "V") + tm.DeleteLabel("D") + return tm + }(), + want: &bq.Table{ + Labels: map[string]string{"L": "V"}, + NullFields: []string{"Labels.D"}, + }, + }, + { + tm: TableMetadataToUpdate{ExpirationTime: NeverExpire}, + want: &bq.Table{ + NullFields: []string{"ExpirationTime"}, + }, + }, + } { + got, _ := test.tm.toBQ() + if !testutil.Equal(got, test.want) { + t.Errorf("%+v:\ngot %+v\nwant %+v", test.tm, got, test.want) + } + } +} + +func TestTableMetadataToUpdateToBQErrors(t *testing.T) { + // See https://godoc.org/time#Time.UnixNano + start := time.Date(1677, 9, 21, 0, 12, 43, 145224192, time.UTC) + end := time.Date(2262, 04, 11, 23, 47, 16, 854775807, time.UTC) + + for _, test := range []struct { + desc string + aTime time.Time + wantErr bool + }{ + {desc: "ignored zero value", aTime: time.Time{}, wantErr: false}, + {desc: "earliest valid time", aTime: start, wantErr: false}, + {desc: "latested valid time", aTime: end, wantErr: false}, + {desc: "invalid times before 1678", aTime: start.Add(-1), wantErr: true}, + {desc: "invalid times after 2262", aTime: end.Add(1), wantErr: true}, + {desc: "valid times after 1678", aTime: start.Add(1), wantErr: false}, + {desc: "valid times before 2262", aTime: end.Add(-1), wantErr: false}, + } { + tm := &TableMetadataToUpdate{ExpirationTime: test.aTime} + _, err := tm.toBQ() + if test.wantErr && err == nil { + t.Errorf("[%s] got no error, want error", test.desc) + } + if !test.wantErr && err != nil { + t.Errorf("[%s] got error, want no error", test.desc) + } + } +} diff --git a/vendor/cloud.google.com/go/bigquery/value.go b/vendor/cloud.google.com/go/bigquery/value.go new file mode 100644 index 00000000..2755a5f3 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/value.go @@ -0,0 +1,870 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "encoding/base64" + "errors" + "fmt" + "math" + "math/big" + "reflect" + "strconv" + "strings" + "time" + + "cloud.google.com/go/civil" + bq "google.golang.org/api/bigquery/v2" +) + +// Value stores the contents of a single cell from a BigQuery result. +type Value interface{} + +// ValueLoader stores a slice of Values representing a result row from a Read operation. +// See RowIterator.Next for more information. +type ValueLoader interface { + Load(v []Value, s Schema) error +} + +// valueList converts a []Value to implement ValueLoader. +type valueList []Value + +// Load stores a sequence of values in a valueList. +// It resets the slice length to zero, then appends each value to it. +func (vs *valueList) Load(v []Value, _ Schema) error { + *vs = append((*vs)[:0], v...) + return nil +} + +// valueMap converts a map[string]Value to implement ValueLoader. +type valueMap map[string]Value + +// Load stores a sequence of values in a valueMap. +func (vm *valueMap) Load(v []Value, s Schema) error { + if *vm == nil { + *vm = map[string]Value{} + } + loadMap(*vm, v, s) + return nil +} + +func loadMap(m map[string]Value, vals []Value, s Schema) { + for i, f := range s { + val := vals[i] + var v interface{} + switch { + case val == nil: + v = val + case f.Schema == nil: + v = val + case !f.Repeated: + m2 := map[string]Value{} + loadMap(m2, val.([]Value), f.Schema) + v = m2 + default: // repeated and nested + sval := val.([]Value) + vs := make([]Value, len(sval)) + for j, e := range sval { + m2 := map[string]Value{} + loadMap(m2, e.([]Value), f.Schema) + vs[j] = m2 + } + v = vs + } + + m[f.Name] = v + } +} + +type structLoader struct { + typ reflect.Type // type of struct + err error + ops []structLoaderOp + + vstructp reflect.Value // pointer to current struct value; changed by set +} + +// A setFunc is a function that sets a struct field or slice/array +// element to a value. +type setFunc func(v reflect.Value, val interface{}) error + +// A structLoaderOp instructs the loader to set a struct field to a row value. +type structLoaderOp struct { + fieldIndex []int + valueIndex int + setFunc setFunc + repeated bool +} + +var errNoNulls = errors.New("bigquery: NULL values cannot be read into structs") + +func setAny(v reflect.Value, x interface{}) error { + if x == nil { + return errNoNulls + } + v.Set(reflect.ValueOf(x)) + return nil +} + +func setInt(v reflect.Value, x interface{}) error { + if x == nil { + return errNoNulls + } + xx := x.(int64) + if v.OverflowInt(xx) { + return fmt.Errorf("bigquery: value %v overflows struct field of type %v", xx, v.Type()) + } + v.SetInt(xx) + return nil +} + +func setUint(v reflect.Value, x interface{}) error { + if x == nil { + return errNoNulls + } + xx := x.(int64) + if xx < 0 || v.OverflowUint(uint64(xx)) { + return fmt.Errorf("bigquery: value %v overflows struct field of type %v", xx, v.Type()) + } + v.SetUint(uint64(xx)) + return nil +} + +func setFloat(v reflect.Value, x interface{}) error { + if x == nil { + return errNoNulls + } + xx := x.(float64) + if v.OverflowFloat(xx) { + return fmt.Errorf("bigquery: value %v overflows struct field of type %v", xx, v.Type()) + } + v.SetFloat(xx) + return nil +} + +func setBool(v reflect.Value, x interface{}) error { + if x == nil { + return errNoNulls + } + v.SetBool(x.(bool)) + return nil +} + +func setString(v reflect.Value, x interface{}) error { + if x == nil { + return errNoNulls + } + v.SetString(x.(string)) + return nil +} + +func setBytes(v reflect.Value, x interface{}) error { + if x == nil { + v.SetBytes(nil) + } else { + v.SetBytes(x.([]byte)) + } + return nil +} + +func setNull(v reflect.Value, x interface{}, build func() interface{}) error { + if x == nil { + v.Set(reflect.Zero(v.Type())) + } else { + n := build() + v.Set(reflect.ValueOf(n)) + } + return nil +} + +// set remembers a value for the next call to Load. The value must be +// a pointer to a struct. (This is checked in RowIterator.Next.) +func (sl *structLoader) set(structp interface{}, schema Schema) error { + if sl.err != nil { + return sl.err + } + sl.vstructp = reflect.ValueOf(structp) + typ := sl.vstructp.Type().Elem() + if sl.typ == nil { + // First call: remember the type and compile the schema. + sl.typ = typ + ops, err := compileToOps(typ, schema) + if err != nil { + sl.err = err + return err + } + sl.ops = ops + } else if sl.typ != typ { + return fmt.Errorf("bigquery: struct type changed from %s to %s", sl.typ, typ) + } + return nil +} + +// compileToOps produces a sequence of operations that will set the fields of a +// value of structType to the contents of a row with schema. +func compileToOps(structType reflect.Type, schema Schema) ([]structLoaderOp, error) { + var ops []structLoaderOp + fields, err := fieldCache.Fields(structType) + if err != nil { + return nil, err + } + for i, schemaField := range schema { + // Look for an exported struct field with the same name as the schema + // field, ignoring case (BigQuery column names are case-insensitive, + // and we want to act like encoding/json anyway). + structField := fields.Match(schemaField.Name) + if structField == nil { + // Ignore schema fields with no corresponding struct field. + continue + } + op := structLoaderOp{ + fieldIndex: structField.Index, + valueIndex: i, + } + t := structField.Type + if schemaField.Repeated { + if t.Kind() != reflect.Slice && t.Kind() != reflect.Array { + return nil, fmt.Errorf("bigquery: repeated schema field %s requires slice or array, but struct field %s has type %s", + schemaField.Name, structField.Name, t) + } + t = t.Elem() + op.repeated = true + } + if schemaField.Type == RecordFieldType { + // Field can be a struct or a pointer to a struct. + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + if t.Kind() != reflect.Struct { + return nil, fmt.Errorf("bigquery: field %s has type %s, expected struct or *struct", + structField.Name, structField.Type) + } + nested, err := compileToOps(t, schemaField.Schema) + if err != nil { + return nil, err + } + op.setFunc = func(v reflect.Value, val interface{}) error { + return setNested(nested, v, val) + } + } else { + op.setFunc = determineSetFunc(t, schemaField.Type) + if op.setFunc == nil { + return nil, fmt.Errorf("bigquery: schema field %s of type %s is not assignable to struct field %s of type %s", + schemaField.Name, schemaField.Type, structField.Name, t) + } + } + ops = append(ops, op) + } + return ops, nil +} + +// determineSetFunc chooses the best function for setting a field of type ftype +// to a value whose schema field type is stype. It returns nil if stype +// is not assignable to ftype. +// determineSetFunc considers only basic types. See compileToOps for +// handling of repetition and nesting. +func determineSetFunc(ftype reflect.Type, stype FieldType) setFunc { + switch stype { + case StringFieldType: + if ftype.Kind() == reflect.String { + return setString + } + if ftype == typeOfNullString { + return func(v reflect.Value, x interface{}) error { + return setNull(v, x, func() interface{} { + return NullString{StringVal: x.(string), Valid: true} + }) + } + } + + case BytesFieldType: + if ftype == typeOfByteSlice { + return setBytes + } + + case IntegerFieldType: + if isSupportedUintType(ftype) { + return setUint + } else if isSupportedIntType(ftype) { + return setInt + } + if ftype == typeOfNullInt64 { + return func(v reflect.Value, x interface{}) error { + return setNull(v, x, func() interface{} { + return NullInt64{Int64: x.(int64), Valid: true} + }) + } + } + + case FloatFieldType: + switch ftype.Kind() { + case reflect.Float32, reflect.Float64: + return setFloat + } + if ftype == typeOfNullFloat64 { + return func(v reflect.Value, x interface{}) error { + return setNull(v, x, func() interface{} { + return NullFloat64{Float64: x.(float64), Valid: true} + }) + } + } + + case BooleanFieldType: + if ftype.Kind() == reflect.Bool { + return setBool + } + if ftype == typeOfNullBool { + return func(v reflect.Value, x interface{}) error { + return setNull(v, x, func() interface{} { + return NullBool{Bool: x.(bool), Valid: true} + }) + } + } + + case TimestampFieldType: + if ftype == typeOfGoTime { + return setAny + } + if ftype == typeOfNullTimestamp { + return func(v reflect.Value, x interface{}) error { + return setNull(v, x, func() interface{} { + return NullTimestamp{Timestamp: x.(time.Time), Valid: true} + }) + } + } + + case DateFieldType: + if ftype == typeOfDate { + return setAny + } + if ftype == typeOfNullDate { + return func(v reflect.Value, x interface{}) error { + return setNull(v, x, func() interface{} { + return NullDate{Date: x.(civil.Date), Valid: true} + }) + } + } + + case TimeFieldType: + if ftype == typeOfTime { + return setAny + } + if ftype == typeOfNullTime { + return func(v reflect.Value, x interface{}) error { + return setNull(v, x, func() interface{} { + return NullTime{Time: x.(civil.Time), Valid: true} + }) + } + } + + case DateTimeFieldType: + if ftype == typeOfDateTime { + return setAny + } + if ftype == typeOfNullDateTime { + return func(v reflect.Value, x interface{}) error { + return setNull(v, x, func() interface{} { + return NullDateTime{DateTime: x.(civil.DateTime), Valid: true} + }) + } + } + + case NumericFieldType: + if ftype == typeOfRat { + return func(v reflect.Value, x interface{}) error { + return setNull(v, x, func() interface{} { return x.(*big.Rat) }) + } + } + } + return nil +} + +func (sl *structLoader) Load(values []Value, _ Schema) error { + if sl.err != nil { + return sl.err + } + return runOps(sl.ops, sl.vstructp.Elem(), values) +} + +// runOps executes a sequence of ops, setting the fields of vstruct to the +// supplied values. +func runOps(ops []structLoaderOp, vstruct reflect.Value, values []Value) error { + for _, op := range ops { + field := vstruct.FieldByIndex(op.fieldIndex) + var err error + if op.repeated { + err = setRepeated(field, values[op.valueIndex].([]Value), op.setFunc) + } else { + err = op.setFunc(field, values[op.valueIndex]) + } + if err != nil { + return err + } + } + return nil +} + +func setNested(ops []structLoaderOp, v reflect.Value, val interface{}) error { + // v is either a struct or a pointer to a struct. + if v.Kind() == reflect.Ptr { + // If the value is nil, set the pointer to nil. + if val == nil { + v.Set(reflect.Zero(v.Type())) + return nil + } + // If the pointer is nil, set it to a zero struct value. + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + v = v.Elem() + } + return runOps(ops, v, val.([]Value)) +} + +func setRepeated(field reflect.Value, vslice []Value, setElem setFunc) error { + vlen := len(vslice) + var flen int + switch field.Type().Kind() { + case reflect.Slice: + // Make a slice of the right size, avoiding allocation if possible. + switch { + case field.Len() < vlen: + field.Set(reflect.MakeSlice(field.Type(), vlen, vlen)) + case field.Len() > vlen: + field.SetLen(vlen) + } + flen = vlen + + case reflect.Array: + flen = field.Len() + if flen > vlen { + // Set extra elements to their zero value. + z := reflect.Zero(field.Type().Elem()) + for i := vlen; i < flen; i++ { + field.Index(i).Set(z) + } + } + default: + return fmt.Errorf("bigquery: impossible field type %s", field.Type()) + } + for i, val := range vslice { + if i < flen { // avoid writing past the end of a short array + if err := setElem(field.Index(i), val); err != nil { + return err + } + } + } + return nil +} + +// A ValueSaver returns a row of data to be inserted into a table. +type ValueSaver interface { + // Save returns a row to be inserted into a BigQuery table, represented + // as a map from field name to Value. + // If insertID is non-empty, BigQuery will use it to de-duplicate + // insertions of this row on a best-effort basis. + Save() (row map[string]Value, insertID string, err error) +} + +// ValuesSaver implements ValueSaver for a slice of Values. +type ValuesSaver struct { + Schema Schema + + // If non-empty, BigQuery will use InsertID to de-duplicate insertions + // of this row on a best-effort basis. + InsertID string + + Row []Value +} + +// Save implements ValueSaver. +func (vls *ValuesSaver) Save() (map[string]Value, string, error) { + m, err := valuesToMap(vls.Row, vls.Schema) + return m, vls.InsertID, err +} + +func valuesToMap(vs []Value, schema Schema) (map[string]Value, error) { + if len(vs) != len(schema) { + return nil, errors.New("Schema does not match length of row to be inserted") + } + + m := make(map[string]Value) + for i, fieldSchema := range schema { + if vs[i] == nil { + m[fieldSchema.Name] = nil + continue + } + if fieldSchema.Type != RecordFieldType { + m[fieldSchema.Name] = toUploadValue(vs[i], fieldSchema) + continue + } + // Nested record, possibly repeated. + vals, ok := vs[i].([]Value) + if !ok { + return nil, errors.New("nested record is not a []Value") + } + if !fieldSchema.Repeated { + value, err := valuesToMap(vals, fieldSchema.Schema) + if err != nil { + return nil, err + } + m[fieldSchema.Name] = value + continue + } + // A repeated nested field is converted into a slice of maps. + var maps []Value + for _, v := range vals { + sv, ok := v.([]Value) + if !ok { + return nil, errors.New("nested record in slice is not a []Value") + } + value, err := valuesToMap(sv, fieldSchema.Schema) + if err != nil { + return nil, err + } + maps = append(maps, value) + } + m[fieldSchema.Name] = maps + } + return m, nil +} + +// StructSaver implements ValueSaver for a struct. +// The struct is converted to a map of values by using the values of struct +// fields corresponding to schema fields. Additional and missing +// fields are ignored, as are nested struct pointers that are nil. +type StructSaver struct { + // Schema determines what fields of the struct are uploaded. It should + // match the table's schema. + // Schema is optional for StructSavers that are passed to Uploader.Put. + Schema Schema + + // If non-empty, BigQuery will use InsertID to de-duplicate insertions + // of this row on a best-effort basis. + InsertID string + + // Struct should be a struct or a pointer to a struct. + Struct interface{} +} + +// Save implements ValueSaver. +func (ss *StructSaver) Save() (row map[string]Value, insertID string, err error) { + vstruct := reflect.ValueOf(ss.Struct) + row, err = structToMap(vstruct, ss.Schema) + if err != nil { + return nil, "", err + } + return row, ss.InsertID, nil +} + +func structToMap(vstruct reflect.Value, schema Schema) (map[string]Value, error) { + if vstruct.Kind() == reflect.Ptr { + vstruct = vstruct.Elem() + } + if !vstruct.IsValid() { + return nil, nil + } + m := map[string]Value{} + if vstruct.Kind() != reflect.Struct { + return nil, fmt.Errorf("bigquery: type is %s, need struct or struct pointer", vstruct.Type()) + } + fields, err := fieldCache.Fields(vstruct.Type()) + if err != nil { + return nil, err + } + for _, schemaField := range schema { + // Look for an exported struct field with the same name as the schema + // field, ignoring case. + structField := fields.Match(schemaField.Name) + if structField == nil { + continue + } + val, err := structFieldToUploadValue(vstruct.FieldByIndex(structField.Index), schemaField) + if err != nil { + return nil, err + } + // Add the value to the map, unless it is nil. + if val != nil { + m[schemaField.Name] = val + } + } + return m, nil +} + +// structFieldToUploadValue converts a struct field to a value suitable for ValueSaver.Save, using +// the schemaField as a guide. +// structFieldToUploadValue is careful to return a true nil interface{} when needed, so its +// caller can easily identify a nil value. +func structFieldToUploadValue(vfield reflect.Value, schemaField *FieldSchema) (interface{}, error) { + if schemaField.Repeated && (vfield.Kind() != reflect.Slice && vfield.Kind() != reflect.Array) { + return nil, fmt.Errorf("bigquery: repeated schema field %s requires slice or array, but value has type %s", + schemaField.Name, vfield.Type()) + } + + // A non-nested field can be represented by its Go value, except for some types. + if schemaField.Type != RecordFieldType { + return toUploadValueReflect(vfield, schemaField), nil + } + // A non-repeated nested field is converted into a map[string]Value. + if !schemaField.Repeated { + m, err := structToMap(vfield, schemaField.Schema) + if err != nil { + return nil, err + } + if m == nil { + return nil, nil + } + return m, nil + } + // A repeated nested field is converted into a slice of maps. + // If the field is zero-length (but not nil), we return a zero-length []Value. + if vfield.IsNil() { + return nil, nil + } + vals := []Value{} + for i := 0; i < vfield.Len(); i++ { + m, err := structToMap(vfield.Index(i), schemaField.Schema) + if err != nil { + return nil, err + } + vals = append(vals, m) + } + return vals, nil +} + +func toUploadValue(val interface{}, fs *FieldSchema) interface{} { + if fs.Type == TimeFieldType || fs.Type == DateTimeFieldType || fs.Type == NumericFieldType { + return toUploadValueReflect(reflect.ValueOf(val), fs) + } + return val +} + +func toUploadValueReflect(v reflect.Value, fs *FieldSchema) interface{} { + switch fs.Type { + case TimeFieldType: + if v.Type() == typeOfNullTime { + return v.Interface() + } + return formatUploadValue(v, fs, func(v reflect.Value) string { + return CivilTimeString(v.Interface().(civil.Time)) + }) + case DateTimeFieldType: + if v.Type() == typeOfNullDateTime { + return v.Interface() + } + return formatUploadValue(v, fs, func(v reflect.Value) string { + return CivilDateTimeString(v.Interface().(civil.DateTime)) + }) + case NumericFieldType: + if r, ok := v.Interface().(*big.Rat); ok && r == nil { + return nil + } + return formatUploadValue(v, fs, func(v reflect.Value) string { + return NumericString(v.Interface().(*big.Rat)) + }) + default: + if !fs.Repeated || v.Len() > 0 { + return v.Interface() + } + // The service treats a null repeated field as an error. Return + // nil to omit the field entirely. + return nil + } +} + +func formatUploadValue(v reflect.Value, fs *FieldSchema, cvt func(reflect.Value) string) interface{} { + if !fs.Repeated { + return cvt(v) + } + if v.Len() == 0 { + return nil + } + s := make([]string, v.Len()) + for i := 0; i < v.Len(); i++ { + s[i] = cvt(v.Index(i)) + } + return s +} + +// CivilTimeString returns a string representing a civil.Time in a format compatible +// with BigQuery SQL. It rounds the time to the nearest microsecond and returns a +// string with six digits of sub-second precision. +// +// Use CivilTimeString when using civil.Time in DML, for example in INSERT +// statements. +func CivilTimeString(t civil.Time) string { + if t.Nanosecond == 0 { + return t.String() + } + micro := (t.Nanosecond + 500) / 1000 // round to nearest microsecond + t.Nanosecond = 0 + return t.String() + fmt.Sprintf(".%06d", micro) +} + +// CivilDateTimeString returns a string representing a civil.DateTime in a format compatible +// with BigQuery SQL. It separate the date and time with a space, and formats the time +// with CivilTimeString. +// +// Use CivilDateTimeString when using civil.DateTime in DML, for example in INSERT +// statements. +func CivilDateTimeString(dt civil.DateTime) string { + return dt.Date.String() + " " + CivilTimeString(dt.Time) +} + +// parseCivilDateTime parses a date-time represented in a BigQuery SQL +// compatible format and returns a civil.DateTime. +func parseCivilDateTime(s string) (civil.DateTime, error) { + parts := strings.Fields(s) + if len(parts) != 2 { + return civil.DateTime{}, fmt.Errorf("bigquery: bad DATETIME value %q", s) + } + return civil.ParseDateTime(parts[0] + "T" + parts[1]) +} + +const ( + // NumericPrecisionDigits is the maximum number of digits in a NUMERIC value. + NumericPrecisionDigits = 38 + + // NumericScaleDigits is the maximum number of digits after the decimal point in a NUMERIC value. + NumericScaleDigits = 9 +) + +// NumericString returns a string representing a *big.Rat in a format compatible +// with BigQuery SQL. It returns a floating-point literal with 9 digits +// after the decimal point. +func NumericString(r *big.Rat) string { + return r.FloatString(NumericScaleDigits) +} + +// convertRows converts a series of TableRows into a series of Value slices. +// schema is used to interpret the data from rows; its length must match the +// length of each row. +func convertRows(rows []*bq.TableRow, schema Schema) ([][]Value, error) { + var rs [][]Value + for _, r := range rows { + row, err := convertRow(r, schema) + if err != nil { + return nil, err + } + rs = append(rs, row) + } + return rs, nil +} + +func convertRow(r *bq.TableRow, schema Schema) ([]Value, error) { + if len(schema) != len(r.F) { + return nil, errors.New("schema length does not match row length") + } + var values []Value + for i, cell := range r.F { + fs := schema[i] + v, err := convertValue(cell.V, fs.Type, fs.Schema) + if err != nil { + return nil, err + } + values = append(values, v) + } + return values, nil +} + +func convertValue(val interface{}, typ FieldType, schema Schema) (Value, error) { + switch val := val.(type) { + case nil: + return nil, nil + case []interface{}: + return convertRepeatedRecord(val, typ, schema) + case map[string]interface{}: + return convertNestedRecord(val, schema) + case string: + return convertBasicType(val, typ) + default: + return nil, fmt.Errorf("got value %v; expected a value of type %s", val, typ) + } +} + +func convertRepeatedRecord(vals []interface{}, typ FieldType, schema Schema) (Value, error) { + var values []Value + for _, cell := range vals { + // each cell contains a single entry, keyed by "v" + val := cell.(map[string]interface{})["v"] + v, err := convertValue(val, typ, schema) + if err != nil { + return nil, err + } + values = append(values, v) + } + return values, nil +} + +func convertNestedRecord(val map[string]interface{}, schema Schema) (Value, error) { + // convertNestedRecord is similar to convertRow, as a record has the same structure as a row. + + // Nested records are wrapped in a map with a single key, "f". + record := val["f"].([]interface{}) + if len(record) != len(schema) { + return nil, errors.New("schema length does not match record length") + } + + var values []Value + for i, cell := range record { + // each cell contains a single entry, keyed by "v" + val := cell.(map[string]interface{})["v"] + fs := schema[i] + v, err := convertValue(val, fs.Type, fs.Schema) + if err != nil { + return nil, err + } + values = append(values, v) + } + return values, nil +} + +// convertBasicType returns val as an interface with a concrete type specified by typ. +func convertBasicType(val string, typ FieldType) (Value, error) { + switch typ { + case StringFieldType: + return val, nil + case BytesFieldType: + return base64.StdEncoding.DecodeString(val) + case IntegerFieldType: + return strconv.ParseInt(val, 10, 64) + case FloatFieldType: + return strconv.ParseFloat(val, 64) + case BooleanFieldType: + return strconv.ParseBool(val) + case TimestampFieldType: + f, err := strconv.ParseFloat(val, 64) + if err != nil { + return nil, err + } + secs := math.Trunc(f) + nanos := (f - secs) * 1e9 + return Value(time.Unix(int64(secs), int64(nanos)).UTC()), nil + case DateFieldType: + return civil.ParseDate(val) + case TimeFieldType: + return civil.ParseTime(val) + case DateTimeFieldType: + return civil.ParseDateTime(val) + case NumericFieldType: + r, ok := (&big.Rat{}).SetString(val) + if !ok { + return nil, fmt.Errorf("bigquery: invalid NUMERIC value %q", val) + } + return Value(r), nil + default: + return nil, fmt.Errorf("unrecognized type: %s", typ) + } +} diff --git a/vendor/cloud.google.com/go/bigquery/value_test.go b/vendor/cloud.google.com/go/bigquery/value_test.go new file mode 100644 index 00000000..3b441ee0 --- /dev/null +++ b/vendor/cloud.google.com/go/bigquery/value_test.go @@ -0,0 +1,1216 @@ +// Copyright 2015 Google LLC +// +// 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 bigquery + +import ( + "encoding/base64" + "fmt" + "math" + "math/big" + "testing" + "time" + + "cloud.google.com/go/civil" + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" + bq "google.golang.org/api/bigquery/v2" +) + +func TestConvertBasicValues(t *testing.T) { + schema := Schema{ + {Type: StringFieldType}, + {Type: IntegerFieldType}, + {Type: FloatFieldType}, + {Type: BooleanFieldType}, + {Type: BytesFieldType}, + {Type: NumericFieldType}, + } + row := &bq.TableRow{ + F: []*bq.TableCell{ + {V: "a"}, + {V: "1"}, + {V: "1.2"}, + {V: "true"}, + {V: base64.StdEncoding.EncodeToString([]byte("foo"))}, + {V: "123.123456789"}, + }, + } + got, err := convertRow(row, schema) + if err != nil { + t.Fatalf("error converting: %v", err) + } + + want := []Value{"a", int64(1), 1.2, true, []byte("foo"), big.NewRat(123123456789, 1e9)} + if !testutil.Equal(got, want) { + t.Errorf("converting basic values: got:\n%v\nwant:\n%v", got, want) + } +} + +func TestConvertTime(t *testing.T) { + schema := Schema{ + {Type: TimestampFieldType}, + {Type: DateFieldType}, + {Type: TimeFieldType}, + {Type: DateTimeFieldType}, + } + ts := testTimestamp.Round(time.Millisecond) + row := &bq.TableRow{ + F: []*bq.TableCell{ + {V: fmt.Sprintf("%.10f", float64(ts.UnixNano())/1e9)}, + {V: testDate.String()}, + {V: testTime.String()}, + {V: testDateTime.String()}, + }, + } + got, err := convertRow(row, schema) + if err != nil { + t.Fatalf("error converting: %v", err) + } + want := []Value{ts, testDate, testTime, testDateTime} + for i, g := range got { + w := want[i] + if !testutil.Equal(g, w) { + t.Errorf("#%d: got:\n%v\nwant:\n%v", i, g, w) + } + } + if got[0].(time.Time).Location() != time.UTC { + t.Errorf("expected time zone UTC: got:\n%v", got) + } +} + +func TestConvertSmallTimes(t *testing.T) { + for _, year := range []int{1600, 1066, 1} { + want := time.Date(year, time.January, 1, 0, 0, 0, 0, time.UTC) + s := fmt.Sprintf("%.10f", float64(want.Unix())) + got, err := convertBasicType(s, TimestampFieldType) + if err != nil { + t.Fatal(err) + } + if !got.(time.Time).Equal(want) { + t.Errorf("got %v, want %v", got, want) + } + } +} + +func TestConvertNullValues(t *testing.T) { + schema := Schema{{Type: StringFieldType}} + row := &bq.TableRow{ + F: []*bq.TableCell{ + {V: nil}, + }, + } + got, err := convertRow(row, schema) + if err != nil { + t.Fatalf("error converting: %v", err) + } + want := []Value{nil} + if !testutil.Equal(got, want) { + t.Errorf("converting null values: got:\n%v\nwant:\n%v", got, want) + } +} + +func TestBasicRepetition(t *testing.T) { + schema := Schema{ + {Type: IntegerFieldType, Repeated: true}, + } + row := &bq.TableRow{ + F: []*bq.TableCell{ + { + V: []interface{}{ + map[string]interface{}{ + "v": "1", + }, + map[string]interface{}{ + "v": "2", + }, + map[string]interface{}{ + "v": "3", + }, + }, + }, + }, + } + got, err := convertRow(row, schema) + if err != nil { + t.Fatalf("error converting: %v", err) + } + want := []Value{[]Value{int64(1), int64(2), int64(3)}} + if !testutil.Equal(got, want) { + t.Errorf("converting basic repeated values: got:\n%v\nwant:\n%v", got, want) + } +} + +func TestNestedRecordContainingRepetition(t *testing.T) { + schema := Schema{ + { + Type: RecordFieldType, + Schema: Schema{ + {Type: IntegerFieldType, Repeated: true}, + }, + }, + } + row := &bq.TableRow{ + F: []*bq.TableCell{ + { + V: map[string]interface{}{ + "f": []interface{}{ + map[string]interface{}{ + "v": []interface{}{ + map[string]interface{}{"v": "1"}, + map[string]interface{}{"v": "2"}, + map[string]interface{}{"v": "3"}, + }, + }, + }, + }, + }, + }, + } + + got, err := convertRow(row, schema) + if err != nil { + t.Fatalf("error converting: %v", err) + } + want := []Value{[]Value{[]Value{int64(1), int64(2), int64(3)}}} + if !testutil.Equal(got, want) { + t.Errorf("converting basic repeated values: got:\n%v\nwant:\n%v", got, want) + } +} + +func TestRepeatedRecordContainingRepetition(t *testing.T) { + schema := Schema{ + { + Type: RecordFieldType, + Repeated: true, + Schema: Schema{ + {Type: IntegerFieldType, Repeated: true}, + }, + }, + } + row := &bq.TableRow{F: []*bq.TableCell{ + { + V: []interface{}{ // repeated records. + map[string]interface{}{ // first record. + "v": map[string]interface{}{ // pointless single-key-map wrapper. + "f": []interface{}{ // list of record fields. + map[string]interface{}{ // only record (repeated ints) + "v": []interface{}{ // pointless wrapper. + map[string]interface{}{ + "v": "1", + }, + map[string]interface{}{ + "v": "2", + }, + map[string]interface{}{ + "v": "3", + }, + }, + }, + }, + }, + }, + map[string]interface{}{ // second record. + "v": map[string]interface{}{ + "f": []interface{}{ + map[string]interface{}{ + "v": []interface{}{ + map[string]interface{}{ + "v": "4", + }, + map[string]interface{}{ + "v": "5", + }, + map[string]interface{}{ + "v": "6", + }, + }, + }, + }, + }, + }, + }, + }, + }} + + got, err := convertRow(row, schema) + if err != nil { + t.Fatalf("error converting: %v", err) + } + want := []Value{ // the row is a list of length 1, containing an entry for the repeated record. + []Value{ // the repeated record is a list of length 2, containing an entry for each repetition. + []Value{ // the record is a list of length 1, containing an entry for the repeated integer field. + []Value{int64(1), int64(2), int64(3)}, // the repeated integer field is a list of length 3. + }, + []Value{ // second record + []Value{int64(4), int64(5), int64(6)}, + }, + }, + } + if !testutil.Equal(got, want) { + t.Errorf("converting repeated records with repeated values: got:\n%v\nwant:\n%v", got, want) + } +} + +func TestRepeatedRecordContainingRecord(t *testing.T) { + schema := Schema{ + { + Type: RecordFieldType, + Repeated: true, + Schema: Schema{ + { + Type: StringFieldType, + }, + { + Type: RecordFieldType, + Schema: Schema{ + {Type: IntegerFieldType}, + {Type: StringFieldType}, + }, + }, + }, + }, + } + row := &bq.TableRow{F: []*bq.TableCell{ + { + V: []interface{}{ // repeated records. + map[string]interface{}{ // first record. + "v": map[string]interface{}{ // pointless single-key-map wrapper. + "f": []interface{}{ // list of record fields. + map[string]interface{}{ // first record field (name) + "v": "first repeated record", + }, + map[string]interface{}{ // second record field (nested record). + "v": map[string]interface{}{ // pointless single-key-map wrapper. + "f": []interface{}{ // nested record fields + map[string]interface{}{ + "v": "1", + }, + map[string]interface{}{ + "v": "two", + }, + }, + }, + }, + }, + }, + }, + map[string]interface{}{ // second record. + "v": map[string]interface{}{ + "f": []interface{}{ + map[string]interface{}{ + "v": "second repeated record", + }, + map[string]interface{}{ + "v": map[string]interface{}{ + "f": []interface{}{ + map[string]interface{}{ + "v": "3", + }, + map[string]interface{}{ + "v": "four", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }} + + got, err := convertRow(row, schema) + if err != nil { + t.Fatalf("error converting: %v", err) + } + // TODO: test with flattenresults. + want := []Value{ // the row is a list of length 1, containing an entry for the repeated record. + []Value{ // the repeated record is a list of length 2, containing an entry for each repetition. + []Value{ // record contains a string followed by a nested record. + "first repeated record", + []Value{ + int64(1), + "two", + }, + }, + []Value{ // second record. + "second repeated record", + []Value{ + int64(3), + "four", + }, + }, + }, + } + if !testutil.Equal(got, want) { + t.Errorf("converting repeated records containing record : got:\n%v\nwant:\n%v", got, want) + } +} + +func TestConvertRowErrors(t *testing.T) { + // mismatched lengths + if _, err := convertRow(&bq.TableRow{F: []*bq.TableCell{{V: ""}}}, Schema{}); err == nil { + t.Error("got nil, want error") + } + v3 := map[string]interface{}{"v": 3} + for _, test := range []struct { + value interface{} + fs FieldSchema + }{ + {3, FieldSchema{Type: IntegerFieldType}}, // not a string + {[]interface{}{v3}, // not a string, repeated + FieldSchema{Type: IntegerFieldType, Repeated: true}}, + {map[string]interface{}{"f": []interface{}{v3}}, // not a string, nested + FieldSchema{Type: RecordFieldType, Schema: Schema{{Type: IntegerFieldType}}}}, + {map[string]interface{}{"f": []interface{}{v3}}, // wrong length, nested + FieldSchema{Type: RecordFieldType, Schema: Schema{}}}, + } { + _, err := convertRow( + &bq.TableRow{F: []*bq.TableCell{{V: test.value}}}, + Schema{&test.fs}) + if err == nil { + t.Errorf("value %v, fs %v: got nil, want error", test.value, test.fs) + } + } + + // bad field type + if _, err := convertBasicType("", FieldType("BAD")); err == nil { + t.Error("got nil, want error") + } +} + +func TestValuesSaverConvertsToMap(t *testing.T) { + testCases := []struct { + vs ValuesSaver + wantInsertID string + wantRow map[string]Value + }{ + { + vs: ValuesSaver{ + Schema: Schema{ + {Name: "intField", Type: IntegerFieldType}, + {Name: "strField", Type: StringFieldType}, + {Name: "dtField", Type: DateTimeFieldType}, + {Name: "nField", Type: NumericFieldType}, + }, + InsertID: "iid", + Row: []Value{1, "a", + civil.DateTime{ + Date: civil.Date{Year: 1, Month: 2, Day: 3}, + Time: civil.Time{Hour: 4, Minute: 5, Second: 6, Nanosecond: 7000}}, + big.NewRat(123456789000, 1e9), + }, + }, + wantInsertID: "iid", + wantRow: map[string]Value{ + "intField": 1, + "strField": "a", + "dtField": "0001-02-03 04:05:06.000007", + "nField": "123.456789000", + }, + }, + { + vs: ValuesSaver{ + Schema: Schema{ + {Name: "intField", Type: IntegerFieldType}, + { + Name: "recordField", + Type: RecordFieldType, + Schema: Schema{ + {Name: "nestedInt", Type: IntegerFieldType, Repeated: true}, + }, + }, + }, + InsertID: "iid", + Row: []Value{1, []Value{[]Value{2, 3}}}, + }, + wantInsertID: "iid", + wantRow: map[string]Value{ + "intField": 1, + "recordField": map[string]Value{ + "nestedInt": []Value{2, 3}, + }, + }, + }, + { // repeated nested field + vs: ValuesSaver{ + Schema: Schema{ + { + Name: "records", + Type: RecordFieldType, + Schema: Schema{ + {Name: "x", Type: IntegerFieldType}, + {Name: "y", Type: IntegerFieldType}, + }, + Repeated: true, + }, + }, + InsertID: "iid", + Row: []Value{ // a row is a []Value + []Value{ // repeated field's value is a []Value + []Value{1, 2}, // first record of the repeated field + []Value{3, 4}, // second record + }, + }, + }, + wantInsertID: "iid", + wantRow: map[string]Value{ + "records": []Value{ + map[string]Value{"x": 1, "y": 2}, + map[string]Value{"x": 3, "y": 4}, + }, + }, + }, + } + for _, tc := range testCases { + gotRow, gotInsertID, err := tc.vs.Save() + if err != nil { + t.Errorf("Expected successful save; got: %v", err) + continue + } + if !testutil.Equal(gotRow, tc.wantRow) { + t.Errorf("%v row:\ngot:\n%+v\nwant:\n%+v", tc.vs, gotRow, tc.wantRow) + } + if !testutil.Equal(gotInsertID, tc.wantInsertID) { + t.Errorf("%v ID:\ngot:\n%+v\nwant:\n%+v", tc.vs, gotInsertID, tc.wantInsertID) + } + } +} + +func TestValuesToMapErrors(t *testing.T) { + for _, test := range []struct { + values []Value + schema Schema + }{ + { // mismatched length + []Value{1}, + Schema{}, + }, + { // nested record not a slice + []Value{1}, + Schema{{Type: RecordFieldType}}, + }, + { // nested record mismatched length + []Value{[]Value{1}}, + Schema{{Type: RecordFieldType}}, + }, + { // nested repeated record not a slice + []Value{[]Value{1}}, + Schema{{Type: RecordFieldType, Repeated: true}}, + }, + { // nested repeated record mismatched length + []Value{[]Value{[]Value{1}}}, + Schema{{Type: RecordFieldType, Repeated: true}}, + }, + } { + _, err := valuesToMap(test.values, test.schema) + if err == nil { + t.Errorf("%v, %v: got nil, want error", test.values, test.schema) + } + } +} + +func TestStructSaver(t *testing.T) { + schema := Schema{ + {Name: "s", Type: StringFieldType}, + {Name: "r", Type: IntegerFieldType, Repeated: true}, + {Name: "t", Type: TimeFieldType}, + {Name: "tr", Type: TimeFieldType, Repeated: true}, + {Name: "nested", Type: RecordFieldType, Schema: Schema{ + {Name: "b", Type: BooleanFieldType}, + }}, + {Name: "rnested", Type: RecordFieldType, Repeated: true, Schema: Schema{ + {Name: "b", Type: BooleanFieldType}, + }}, + {Name: "p", Type: IntegerFieldType, Required: false}, + {Name: "n", Type: NumericFieldType, Required: false}, + {Name: "nr", Type: NumericFieldType, Repeated: true}, + } + + type ( + N struct{ B bool } + T struct { + S string + R []int + T civil.Time + TR []civil.Time + Nested *N + Rnested []*N + P NullInt64 + N *big.Rat + NR []*big.Rat + } + ) + + check := func(msg string, in interface{}, want map[string]Value) { + ss := StructSaver{ + Schema: schema, + InsertID: "iid", + Struct: in, + } + got, gotIID, err := ss.Save() + if err != nil { + t.Fatalf("%s: %v", msg, err) + } + if wantIID := "iid"; gotIID != wantIID { + t.Errorf("%s: InsertID: got %q, want %q", msg, gotIID, wantIID) + } + if diff := testutil.Diff(got, want); diff != "" { + t.Errorf("%s: %s", msg, diff) + } + } + + ct1 := civil.Time{Hour: 1, Minute: 2, Second: 3, Nanosecond: 4000} + ct2 := civil.Time{Hour: 5, Minute: 6, Second: 7, Nanosecond: 8000} + in := T{ + S: "x", + R: []int{1, 2}, + T: ct1, + TR: []civil.Time{ct1, ct2}, + Nested: &N{B: true}, + Rnested: []*N{{true}, {false}}, + P: NullInt64{Valid: true, Int64: 17}, + N: big.NewRat(123456, 1000), + NR: []*big.Rat{big.NewRat(3, 1), big.NewRat(56789, 1e5)}, + } + want := map[string]Value{ + "s": "x", + "r": []int{1, 2}, + "t": "01:02:03.000004", + "tr": []string{"01:02:03.000004", "05:06:07.000008"}, + "nested": map[string]Value{"b": true}, + "rnested": []Value{map[string]Value{"b": true}, map[string]Value{"b": false}}, + "p": NullInt64{Valid: true, Int64: 17}, + "n": "123.456000000", + "nr": []string{"3.000000000", "0.567890000"}, + } + check("all values", in, want) + check("all values, ptr", &in, want) + check("empty struct", T{}, map[string]Value{"s": "", "t": "00:00:00", "p": NullInt64{}}) + + // Missing and extra fields ignored. + type T2 struct { + S string + // missing R, Nested, RNested + Extra int + } + check("missing and extra", T2{S: "x"}, map[string]Value{"s": "x"}) + + check("nils in slice", T{Rnested: []*N{{true}, nil, {false}}}, + map[string]Value{ + "s": "", + "t": "00:00:00", + "p": NullInt64{}, + "rnested": []Value{map[string]Value{"b": true}, map[string]Value(nil), map[string]Value{"b": false}}, + }) + + check("zero-length repeated", T{Rnested: []*N{}}, + map[string]Value{ + "rnested": []Value{}, + "s": "", + "t": "00:00:00", + "p": NullInt64{}, + }) +} + +func TestStructSaverErrors(t *testing.T) { + type ( + badField struct { + I int `bigquery:"@"` + } + badR struct{ R int } + badRN struct{ R []int } + ) + + for i, test := range []struct { + inputStruct interface{} + schema Schema + }{ + {0, nil}, // not a struct + {&badField{}, nil}, // bad field name + {&badR{}, Schema{{Name: "r", Repeated: true}}}, // repeated field has bad type + {&badR{}, Schema{{Name: "r", Type: RecordFieldType}}}, // nested field has bad type + {&badRN{[]int{0}}, // nested repeated field has bad type + Schema{{Name: "r", Type: RecordFieldType, Repeated: true}}}, + } { + ss := &StructSaver{Struct: test.inputStruct, Schema: test.schema} + _, _, err := ss.Save() + if err == nil { + t.Errorf("#%d, %v, %v: got nil, want error", i, test.inputStruct, test.schema) + } + } +} + +func TestNumericString(t *testing.T) { + for _, test := range []struct { + in *big.Rat + want string + }{ + {big.NewRat(2, 3), "0.666666667"}, // round to 9 places + {big.NewRat(1, 2), "0.500000000"}, + {big.NewRat(1, 2*1e8), "0.000000005"}, + {big.NewRat(5, 1e10), "0.000000001"}, // round up the 5 in the 10th decimal place + {big.NewRat(-5, 1e10), "-0.000000001"}, // round half away from zero + } { + got := NumericString(test.in) + if got != test.want { + t.Errorf("%v: got %q, want %q", test.in, got, test.want) + } + } +} + +func TestConvertRows(t *testing.T) { + schema := Schema{ + {Type: StringFieldType}, + {Type: IntegerFieldType}, + {Type: FloatFieldType}, + {Type: BooleanFieldType}, + } + rows := []*bq.TableRow{ + {F: []*bq.TableCell{ + {V: "a"}, + {V: "1"}, + {V: "1.2"}, + {V: "true"}, + }}, + {F: []*bq.TableCell{ + {V: "b"}, + {V: "2"}, + {V: "2.2"}, + {V: "false"}, + }}, + } + want := [][]Value{ + {"a", int64(1), 1.2, true}, + {"b", int64(2), 2.2, false}, + } + got, err := convertRows(rows, schema) + if err != nil { + t.Fatalf("got %v, want nil", err) + } + if !testutil.Equal(got, want) { + t.Errorf("\ngot %v\nwant %v", got, want) + } + + rows[0].F[0].V = 1 + _, err = convertRows(rows, schema) + if err == nil { + t.Error("got nil, want error") + } +} + +func TestValueList(t *testing.T) { + schema := Schema{ + {Name: "s", Type: StringFieldType}, + {Name: "i", Type: IntegerFieldType}, + {Name: "f", Type: FloatFieldType}, + {Name: "b", Type: BooleanFieldType}, + } + want := []Value{"x", 7, 3.14, true} + var got []Value + vl := (*valueList)(&got) + if err := vl.Load(want, schema); err != nil { + t.Fatal(err) + } + + if !testutil.Equal(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } + + // Load truncates, not appends. + // https://github.com/GoogleCloudPlatform/google-cloud-go/issues/437 + if err := vl.Load(want, schema); err != nil { + t.Fatal(err) + } + if !testutil.Equal(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } +} + +func TestValueMap(t *testing.T) { + ns := Schema{ + {Name: "x", Type: IntegerFieldType}, + {Name: "y", Type: IntegerFieldType}, + } + schema := Schema{ + {Name: "s", Type: StringFieldType}, + {Name: "i", Type: IntegerFieldType}, + {Name: "f", Type: FloatFieldType}, + {Name: "b", Type: BooleanFieldType}, + {Name: "n", Type: RecordFieldType, Schema: ns}, + {Name: "rn", Type: RecordFieldType, Schema: ns, Repeated: true}, + } + in := []Value{"x", 7, 3.14, true, + []Value{1, 2}, + []Value{[]Value{3, 4}, []Value{5, 6}}, + } + var vm valueMap + if err := vm.Load(in, schema); err != nil { + t.Fatal(err) + } + want := map[string]Value{ + "s": "x", + "i": 7, + "f": 3.14, + "b": true, + "n": map[string]Value{"x": 1, "y": 2}, + "rn": []Value{ + map[string]Value{"x": 3, "y": 4}, + map[string]Value{"x": 5, "y": 6}, + }, + } + if !testutil.Equal(vm, valueMap(want)) { + t.Errorf("got\n%+v\nwant\n%+v", vm, want) + } + + in = make([]Value, len(schema)) + want = map[string]Value{ + "s": nil, + "i": nil, + "f": nil, + "b": nil, + "n": nil, + "rn": nil, + } + var vm2 valueMap + if err := vm2.Load(in, schema); err != nil { + t.Fatal(err) + } + if !testutil.Equal(vm2, valueMap(want)) { + t.Errorf("got\n%+v\nwant\n%+v", vm2, want) + } +} + +var ( + // For testing StructLoader + schema2 = Schema{ + {Name: "s", Type: StringFieldType}, + {Name: "s2", Type: StringFieldType}, + {Name: "by", Type: BytesFieldType}, + {Name: "I", Type: IntegerFieldType}, + {Name: "U", Type: IntegerFieldType}, + {Name: "F", Type: FloatFieldType}, + {Name: "B", Type: BooleanFieldType}, + {Name: "TS", Type: TimestampFieldType}, + {Name: "D", Type: DateFieldType}, + {Name: "T", Type: TimeFieldType}, + {Name: "DT", Type: DateTimeFieldType}, + {Name: "N", Type: NumericFieldType}, + {Name: "nested", Type: RecordFieldType, Schema: Schema{ + {Name: "nestS", Type: StringFieldType}, + {Name: "nestI", Type: IntegerFieldType}, + }}, + {Name: "t", Type: StringFieldType}, + } + + testTimestamp = time.Date(2016, 11, 5, 7, 50, 22, 8, time.UTC) + testDate = civil.Date{Year: 2016, Month: 11, Day: 5} + testTime = civil.Time{Hour: 7, Minute: 50, Second: 22, Nanosecond: 8} + testDateTime = civil.DateTime{Date: testDate, Time: testTime} + testNumeric = big.NewRat(123, 456) + + testValues = []Value{"x", "y", []byte{1, 2, 3}, int64(7), int64(8), 3.14, true, + testTimestamp, testDate, testTime, testDateTime, testNumeric, + []Value{"nested", int64(17)}, "z"} +) + +type testStruct1 struct { + B bool + I int + U uint16 + times + S string + S2 String + By []byte + s string + F float64 + N *big.Rat + Nested nested + Tagged string `bigquery:"t"` +} + +type String string + +type nested struct { + NestS string + NestI int +} + +type times struct { + TS time.Time + T civil.Time + D civil.Date + DT civil.DateTime +} + +func TestStructLoader(t *testing.T) { + var ts1 testStruct1 + mustLoad(t, &ts1, schema2, testValues) + // Note: the schema field named "s" gets matched to the exported struct + // field "S", not the unexported "s". + want := &testStruct1{ + B: true, + I: 7, + U: 8, + F: 3.14, + times: times{TS: testTimestamp, T: testTime, D: testDate, DT: testDateTime}, + S: "x", + S2: "y", + By: []byte{1, 2, 3}, + N: big.NewRat(123, 456), + Nested: nested{NestS: "nested", NestI: 17}, + Tagged: "z", + } + if diff := testutil.Diff(&ts1, want, cmp.AllowUnexported(testStruct1{})); diff != "" { + t.Error(diff) + } + + // Test pointers to nested structs. + type nestedPtr struct{ Nested *nested } + var np nestedPtr + mustLoad(t, &np, schema2, testValues) + want2 := &nestedPtr{Nested: &nested{NestS: "nested", NestI: 17}} + if diff := testutil.Diff(&np, want2); diff != "" { + t.Error(diff) + } + + // Existing values should be reused. + nst := &nested{NestS: "x", NestI: -10} + np = nestedPtr{Nested: nst} + mustLoad(t, &np, schema2, testValues) + if diff := testutil.Diff(&np, want2); diff != "" { + t.Error(diff) + } + if np.Nested != nst { + t.Error("nested struct pointers not equal") + } +} + +type repStruct struct { + Nums []int + ShortNums [2]int // to test truncation + LongNums [5]int // to test padding with zeroes + Nested []*nested +} + +var ( + repSchema = Schema{ + {Name: "nums", Type: IntegerFieldType, Repeated: true}, + {Name: "shortNums", Type: IntegerFieldType, Repeated: true}, + {Name: "longNums", Type: IntegerFieldType, Repeated: true}, + {Name: "nested", Type: RecordFieldType, Repeated: true, Schema: Schema{ + {Name: "nestS", Type: StringFieldType}, + {Name: "nestI", Type: IntegerFieldType}, + }}, + } + v123 = []Value{int64(1), int64(2), int64(3)} + repValues = []Value{v123, v123, v123, + []Value{ + []Value{"x", int64(1)}, + []Value{"y", int64(2)}, + }, + } +) + +func TestStructLoaderRepeated(t *testing.T) { + var r1 repStruct + mustLoad(t, &r1, repSchema, repValues) + want := repStruct{ + Nums: []int{1, 2, 3}, + ShortNums: [...]int{1, 2}, // extra values discarded + LongNums: [...]int{1, 2, 3, 0, 0}, + Nested: []*nested{{"x", 1}, {"y", 2}}, + } + if diff := testutil.Diff(r1, want); diff != "" { + t.Error(diff) + } + r2 := repStruct{ + Nums: []int{-1, -2, -3, -4, -5}, // truncated to zero and appended to + LongNums: [...]int{-1, -2, -3, -4, -5}, // unset elements are zeroed + } + mustLoad(t, &r2, repSchema, repValues) + if diff := testutil.Diff(r2, want); diff != "" { + t.Error(diff) + } + if got, want := cap(r2.Nums), 5; got != want { + t.Errorf("cap(r2.Nums) = %d, want %d", got, want) + } + + // Short slice case. + r3 := repStruct{Nums: []int{-1}} + mustLoad(t, &r3, repSchema, repValues) + if diff := testutil.Diff(r3, want); diff != "" { + t.Error(diff) + } + if got, want := cap(r3.Nums), 3; got != want { + t.Errorf("cap(r3.Nums) = %d, want %d", got, want) + } +} + +type testStructNullable struct { + String NullString + Bytes []byte + Integer NullInt64 + Float NullFloat64 + Boolean NullBool + Timestamp NullTimestamp + Date NullDate + Time NullTime + DateTime NullDateTime + Numeric *big.Rat + Record *subNullable +} + +type subNullable struct { + X NullInt64 +} + +var testStructNullableSchema = Schema{ + {Name: "String", Type: StringFieldType, Required: false}, + {Name: "Bytes", Type: BytesFieldType, Required: false}, + {Name: "Integer", Type: IntegerFieldType, Required: false}, + {Name: "Float", Type: FloatFieldType, Required: false}, + {Name: "Boolean", Type: BooleanFieldType, Required: false}, + {Name: "Timestamp", Type: TimestampFieldType, Required: false}, + {Name: "Date", Type: DateFieldType, Required: false}, + {Name: "Time", Type: TimeFieldType, Required: false}, + {Name: "DateTime", Type: DateTimeFieldType, Required: false}, + {Name: "Numeric", Type: NumericFieldType, Required: false}, + {Name: "Record", Type: RecordFieldType, Required: false, Schema: Schema{ + {Name: "X", Type: IntegerFieldType, Required: false}, + }}, +} + +func TestStructLoaderNullable(t *testing.T) { + var ts testStructNullable + nilVals := make([]Value, len(testStructNullableSchema)) + mustLoad(t, &ts, testStructNullableSchema, nilVals) + want := testStructNullable{} + if diff := testutil.Diff(ts, want); diff != "" { + t.Error(diff) + } + + nonnilVals := []Value{"x", []byte{1, 2, 3}, int64(1), 2.3, true, testTimestamp, testDate, testTime, + testDateTime, big.NewRat(1, 2), []Value{int64(4)}} + + // All ts fields are nil. Loading non-nil values will cause them all to + // be allocated. + mustLoad(t, &ts, testStructNullableSchema, nonnilVals) + want = testStructNullable{ + String: NullString{StringVal: "x", Valid: true}, + Bytes: []byte{1, 2, 3}, + Integer: NullInt64{Int64: 1, Valid: true}, + Float: NullFloat64{Float64: 2.3, Valid: true}, + Boolean: NullBool{Bool: true, Valid: true}, + Timestamp: NullTimestamp{Timestamp: testTimestamp, Valid: true}, + Date: NullDate{Date: testDate, Valid: true}, + Time: NullTime{Time: testTime, Valid: true}, + DateTime: NullDateTime{DateTime: testDateTime, Valid: true}, + Numeric: big.NewRat(1, 2), + Record: &subNullable{X: NullInt64{Int64: 4, Valid: true}}, + } + if diff := testutil.Diff(ts, want); diff != "" { + t.Error(diff) + } + + // Struct pointers are reused, byte slices are not. + want = ts + want.Bytes = []byte{17} + vals2 := []Value{nil, []byte{17}, nil, nil, nil, nil, nil, nil, nil, nil, []Value{int64(7)}} + mustLoad(t, &ts, testStructNullableSchema, vals2) + if ts.Record != want.Record { + t.Error("record pointers not identical") + } +} + +func TestStructLoaderOverflow(t *testing.T) { + type S struct { + I int16 + U uint16 + F float32 + } + schema := Schema{ + {Name: "I", Type: IntegerFieldType}, + {Name: "U", Type: IntegerFieldType}, + {Name: "F", Type: FloatFieldType}, + } + var s S + z64 := int64(0) + for _, vals := range [][]Value{ + {int64(math.MaxInt16 + 1), z64, 0}, + {z64, int64(math.MaxInt32), 0}, + {z64, int64(-1), 0}, + {z64, z64, math.MaxFloat32 * 2}, + } { + if err := load(&s, schema, vals); err == nil { + t.Errorf("%+v: got nil, want error", vals) + } + } +} + +func TestStructLoaderFieldOverlap(t *testing.T) { + // It's OK if the struct has fields that the schema does not, and vice versa. + type S1 struct { + I int + X [][]int // not in the schema; does not even correspond to a valid BigQuery type + // many schema fields missing + } + var s1 S1 + if err := load(&s1, schema2, testValues); err != nil { + t.Fatal(err) + } + want1 := S1{I: 7} + if diff := testutil.Diff(s1, want1); diff != "" { + t.Error(diff) + } + + // It's even valid to have no overlapping fields at all. + type S2 struct{ Z int } + + var s2 S2 + mustLoad(t, &s2, schema2, testValues) + want2 := S2{} + if diff := testutil.Diff(s2, want2); diff != "" { + t.Error(diff) + } +} + +func TestStructLoaderErrors(t *testing.T) { + check := func(sp interface{}) { + var sl structLoader + err := sl.set(sp, schema2) + if err == nil { + t.Errorf("%T: got nil, want error", sp) + } + } + + type bad1 struct{ F int32 } // wrong type for FLOAT column + check(&bad1{}) + + type bad2 struct{ I uint } // unsupported integer type + check(&bad2{}) + + type bad3 struct { + I int `bigquery:"@"` + } // bad field name + check(&bad3{}) + + type bad4 struct{ Nested int } // non-struct for nested field + check(&bad4{}) + + type bad5 struct{ Nested struct{ NestS int } } // bad nested struct + check(&bad5{}) + + bad6 := &struct{ Nums int }{} // non-slice for repeated field + sl := structLoader{} + err := sl.set(bad6, repSchema) + if err == nil { + t.Errorf("%T: got nil, want error", bad6) + } + + // sl.set's error is sticky, even with good input. + err2 := sl.set(&repStruct{}, repSchema) + if err2 != err { + t.Errorf("%v != %v, expected equal", err2, err) + } + // sl.Load is similarly sticky + err2 = sl.Load(nil, nil) + if err2 != err { + t.Errorf("%v != %v, expected equal", err2, err) + } + + // Null values. + schema := Schema{ + {Name: "i", Type: IntegerFieldType}, + {Name: "f", Type: FloatFieldType}, + {Name: "b", Type: BooleanFieldType}, + {Name: "s", Type: StringFieldType}, + {Name: "d", Type: DateFieldType}, + {Name: "r", Type: RecordFieldType, Schema: Schema{{Name: "X", Type: IntegerFieldType}}}, + } + type s struct { + I int + F float64 + B bool + S string + D civil.Date + } + vals := []Value{int64(0), 0.0, false, "", testDate} + mustLoad(t, &s{}, schema, vals) + for i, e := range vals { + vals[i] = nil + got := load(&s{}, schema, vals) + if got != errNoNulls { + t.Errorf("#%d: got %v, want %v", i, got, errNoNulls) + } + vals[i] = e + } + + // Using more than one struct type with the same structLoader. + type different struct { + B bool + I int + times + S string + s string + Nums []int + } + + sl = structLoader{} + if err := sl.set(&testStruct1{}, schema2); err != nil { + t.Fatal(err) + } + err = sl.set(&different{}, schema2) + if err == nil { + t.Error("different struct types: got nil, want error") + } +} + +func mustLoad(t *testing.T, pval interface{}, schema Schema, vals []Value) { + if err := load(pval, schema, vals); err != nil { + t.Fatalf("loading: %v", err) + } +} + +func load(pval interface{}, schema Schema, vals []Value) error { + var sl structLoader + if err := sl.set(pval, schema); err != nil { + return err + } + return sl.Load(vals, nil) +} + +func BenchmarkStructLoader_NoCompile(b *testing.B) { + benchmarkStructLoader(b, false) +} + +func BenchmarkStructLoader_Compile(b *testing.B) { + benchmarkStructLoader(b, true) +} + +func benchmarkStructLoader(b *testing.B, compile bool) { + var ts1 testStruct1 + for i := 0; i < b.N; i++ { + var sl structLoader + for j := 0; j < 10; j++ { + if err := load(&ts1, schema2, testValues); err != nil { + b.Fatal(err) + } + if !compile { + sl.typ = nil + } + } + } +} diff --git a/vendor/cloud.google.com/go/bigtable/admin.go b/vendor/cloud.google.com/go/bigtable/admin.go new file mode 100644 index 00000000..5a0c2348 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/admin.go @@ -0,0 +1,1135 @@ +/* +Copyright 2015 Google LLC + +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 bigtable + +import ( + "context" + "errors" + "fmt" + "math" + "regexp" + "strings" + "time" + + "cloud.google.com/go/bigtable/internal/gax" + btopt "cloud.google.com/go/bigtable/internal/option" + "cloud.google.com/go/iam" + "cloud.google.com/go/internal/optional" + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/ptypes" + durpb "github.com/golang/protobuf/ptypes/duration" + "google.golang.org/api/cloudresourcemanager/v1" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + gtransport "google.golang.org/api/transport/grpc" + btapb "google.golang.org/genproto/googleapis/bigtable/admin/v2" + "google.golang.org/genproto/protobuf/field_mask" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +const adminAddr = "bigtableadmin.googleapis.com:443" + +// AdminClient is a client type for performing admin operations within a specific instance. +type AdminClient struct { + conn *grpc.ClientConn + tClient btapb.BigtableTableAdminClient + lroClient *lroauto.OperationsClient + + project, instance string + + // Metadata to be sent with each request. + md metadata.MD +} + +// NewAdminClient creates a new AdminClient for a given project and instance. +func NewAdminClient(ctx context.Context, project, instance string, opts ...option.ClientOption) (*AdminClient, error) { + o, err := btopt.DefaultClientOptions(adminAddr, AdminScope, clientUserAgent) + if err != nil { + return nil, err + } + // Need to add scopes for long running operations (for create table & snapshots) + o = append(o, option.WithScopes(cloudresourcemanager.CloudPlatformScope)) + o = append(o, opts...) + conn, err := gtransport.Dial(ctx, o...) + if err != nil { + return nil, fmt.Errorf("dialing: %v", err) + } + + lroClient, err := lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + + return &AdminClient{ + conn: conn, + tClient: btapb.NewBigtableTableAdminClient(conn), + lroClient: lroClient, + project: project, + instance: instance, + md: metadata.Pairs(resourcePrefixHeader, fmt.Sprintf("projects/%s/instances/%s", project, instance)), + }, nil +} + +// Close closes the AdminClient. +func (ac *AdminClient) Close() error { + return ac.conn.Close() +} + +func (ac *AdminClient) instancePrefix() string { + return fmt.Sprintf("projects/%s/instances/%s", ac.project, ac.instance) +} + +// Tables returns a list of the tables in the instance. +func (ac *AdminClient) Tables(ctx context.Context) ([]string, error) { + ctx = mergeOutgoingMetadata(ctx, ac.md) + prefix := ac.instancePrefix() + req := &btapb.ListTablesRequest{ + Parent: prefix, + } + + var res *btapb.ListTablesResponse + err := gax.Invoke(ctx, func(ctx context.Context) error { + var err error + res, err = ac.tClient.ListTables(ctx, req) + return err + }, retryOptions...) + if err != nil { + return nil, err + } + + names := make([]string, 0, len(res.Tables)) + for _, tbl := range res.Tables { + names = append(names, strings.TrimPrefix(tbl.Name, prefix+"/tables/")) + } + return names, nil +} + +// TableConf contains all of the information necessary to create a table with column families. +type TableConf struct { + TableID string + SplitKeys []string + // Families is a map from family name to GCPolicy + Families map[string]GCPolicy +} + +// CreateTable creates a new table in the instance. +// This method may return before the table's creation is complete. +func (ac *AdminClient) CreateTable(ctx context.Context, table string) error { + return ac.CreateTableFromConf(ctx, &TableConf{TableID: table}) +} + +// CreatePresplitTable creates a new table in the instance. +// The list of row keys will be used to initially split the table into multiple tablets. +// Given two split keys, "s1" and "s2", three tablets will be created, +// spanning the key ranges: [, s1), [s1, s2), [s2, ). +// This method may return before the table's creation is complete. +func (ac *AdminClient) CreatePresplitTable(ctx context.Context, table string, splitKeys []string) error { + return ac.CreateTableFromConf(ctx, &TableConf{TableID: table, SplitKeys: splitKeys}) +} + +// CreateTableFromConf creates a new table in the instance from the given configuration. +func (ac *AdminClient) CreateTableFromConf(ctx context.Context, conf *TableConf) error { + ctx = mergeOutgoingMetadata(ctx, ac.md) + var reqSplits []*btapb.CreateTableRequest_Split + for _, split := range conf.SplitKeys { + reqSplits = append(reqSplits, &btapb.CreateTableRequest_Split{Key: []byte(split)}) + } + var tbl btapb.Table + if conf.Families != nil { + tbl.ColumnFamilies = make(map[string]*btapb.ColumnFamily) + for fam, policy := range conf.Families { + tbl.ColumnFamilies[fam] = &btapb.ColumnFamily{GcRule: policy.proto()} + } + } + prefix := ac.instancePrefix() + req := &btapb.CreateTableRequest{ + Parent: prefix, + TableId: conf.TableID, + Table: &tbl, + InitialSplits: reqSplits, + } + _, err := ac.tClient.CreateTable(ctx, req) + return err +} + +// CreateColumnFamily creates a new column family in a table. +func (ac *AdminClient) CreateColumnFamily(ctx context.Context, table, family string) error { + // TODO(dsymonds): Permit specifying gcexpr and any other family settings. + ctx = mergeOutgoingMetadata(ctx, ac.md) + prefix := ac.instancePrefix() + req := &btapb.ModifyColumnFamiliesRequest{ + Name: prefix + "/tables/" + table, + Modifications: []*btapb.ModifyColumnFamiliesRequest_Modification{{ + Id: family, + Mod: &btapb.ModifyColumnFamiliesRequest_Modification_Create{Create: &btapb.ColumnFamily{}}, + }}, + } + _, err := ac.tClient.ModifyColumnFamilies(ctx, req) + return err +} + +// DeleteTable deletes a table and all of its data. +func (ac *AdminClient) DeleteTable(ctx context.Context, table string) error { + ctx = mergeOutgoingMetadata(ctx, ac.md) + prefix := ac.instancePrefix() + req := &btapb.DeleteTableRequest{ + Name: prefix + "/tables/" + table, + } + _, err := ac.tClient.DeleteTable(ctx, req) + return err +} + +// DeleteColumnFamily deletes a column family in a table and all of its data. +func (ac *AdminClient) DeleteColumnFamily(ctx context.Context, table, family string) error { + ctx = mergeOutgoingMetadata(ctx, ac.md) + prefix := ac.instancePrefix() + req := &btapb.ModifyColumnFamiliesRequest{ + Name: prefix + "/tables/" + table, + Modifications: []*btapb.ModifyColumnFamiliesRequest_Modification{{ + Id: family, + Mod: &btapb.ModifyColumnFamiliesRequest_Modification_Drop{Drop: true}, + }}, + } + _, err := ac.tClient.ModifyColumnFamilies(ctx, req) + return err +} + +// TableInfo represents information about a table. +type TableInfo struct { + // DEPRECATED - This field is deprecated. Please use FamilyInfos instead. + Families []string + FamilyInfos []FamilyInfo +} + +// FamilyInfo represents information about a column family. +type FamilyInfo struct { + Name string + GCPolicy string +} + +// TableInfo retrieves information about a table. +func (ac *AdminClient) TableInfo(ctx context.Context, table string) (*TableInfo, error) { + ctx = mergeOutgoingMetadata(ctx, ac.md) + prefix := ac.instancePrefix() + req := &btapb.GetTableRequest{ + Name: prefix + "/tables/" + table, + } + + var res *btapb.Table + + err := gax.Invoke(ctx, func(ctx context.Context) error { + var err error + res, err = ac.tClient.GetTable(ctx, req) + return err + }, retryOptions...) + if err != nil { + return nil, err + } + + ti := &TableInfo{} + for name, fam := range res.ColumnFamilies { + ti.Families = append(ti.Families, name) + ti.FamilyInfos = append(ti.FamilyInfos, FamilyInfo{Name: name, GCPolicy: GCRuleToString(fam.GcRule)}) + } + return ti, nil +} + +// SetGCPolicy specifies which cells in a column family should be garbage collected. +// GC executes opportunistically in the background; table reads may return data +// matching the GC policy. +func (ac *AdminClient) SetGCPolicy(ctx context.Context, table, family string, policy GCPolicy) error { + ctx = mergeOutgoingMetadata(ctx, ac.md) + prefix := ac.instancePrefix() + req := &btapb.ModifyColumnFamiliesRequest{ + Name: prefix + "/tables/" + table, + Modifications: []*btapb.ModifyColumnFamiliesRequest_Modification{{ + Id: family, + Mod: &btapb.ModifyColumnFamiliesRequest_Modification_Update{Update: &btapb.ColumnFamily{GcRule: policy.proto()}}, + }}, + } + _, err := ac.tClient.ModifyColumnFamilies(ctx, req) + return err +} + +// DropRowRange permanently deletes a row range from the specified table. +func (ac *AdminClient) DropRowRange(ctx context.Context, table, rowKeyPrefix string) error { + ctx = mergeOutgoingMetadata(ctx, ac.md) + prefix := ac.instancePrefix() + req := &btapb.DropRowRangeRequest{ + Name: prefix + "/tables/" + table, + Target: &btapb.DropRowRangeRequest_RowKeyPrefix{RowKeyPrefix: []byte(rowKeyPrefix)}, + } + _, err := ac.tClient.DropRowRange(ctx, req) + return err +} + +// CreateTableFromSnapshot creates a table from snapshot. +// The table will be created in the same cluster as the snapshot. +// +// This is a private alpha release of Cloud Bigtable snapshots. This feature +// is not currently available to most Cloud Bigtable customers. This feature +// might be changed in backward-incompatible ways and is not recommended for +// production use. It is not subject to any SLA or deprecation policy. +func (ac *AdminClient) CreateTableFromSnapshot(ctx context.Context, table, cluster, snapshot string) error { + ctx = mergeOutgoingMetadata(ctx, ac.md) + prefix := ac.instancePrefix() + snapshotPath := prefix + "/clusters/" + cluster + "/snapshots/" + snapshot + + req := &btapb.CreateTableFromSnapshotRequest{ + Parent: prefix, + TableId: table, + SourceSnapshot: snapshotPath, + } + op, err := ac.tClient.CreateTableFromSnapshot(ctx, req) + if err != nil { + return err + } + resp := btapb.Table{} + return longrunning.InternalNewOperation(ac.lroClient, op).Wait(ctx, &resp) +} + +// DefaultSnapshotDuration is the default TTL for a snapshot. +const DefaultSnapshotDuration time.Duration = 0 + +// SnapshotTable creates a new snapshot in the specified cluster from the +// specified source table. Setting the TTL to `DefaultSnapshotDuration` will +// use the server side default for the duration. +// +// This is a private alpha release of Cloud Bigtable snapshots. This feature +// is not currently available to most Cloud Bigtable customers. This feature +// might be changed in backward-incompatible ways and is not recommended for +// production use. It is not subject to any SLA or deprecation policy. +func (ac *AdminClient) SnapshotTable(ctx context.Context, table, cluster, snapshot string, ttl time.Duration) error { + ctx = mergeOutgoingMetadata(ctx, ac.md) + prefix := ac.instancePrefix() + + var ttlProto *durpb.Duration + + if ttl > 0 { + ttlProto = ptypes.DurationProto(ttl) + } + + req := &btapb.SnapshotTableRequest{ + Name: prefix + "/tables/" + table, + Cluster: prefix + "/clusters/" + cluster, + SnapshotId: snapshot, + Ttl: ttlProto, + } + + op, err := ac.tClient.SnapshotTable(ctx, req) + if err != nil { + return err + } + resp := btapb.Snapshot{} + return longrunning.InternalNewOperation(ac.lroClient, op).Wait(ctx, &resp) +} + +// Snapshots returns a SnapshotIterator for iterating over the snapshots in a cluster. +// To list snapshots across all of the clusters in the instance specify "-" as the cluster. +// +// This is a private alpha release of Cloud Bigtable snapshots. This feature is not +// currently available to most Cloud Bigtable customers. This feature might be +// changed in backward-incompatible ways and is not recommended for production use. +// It is not subject to any SLA or deprecation policy. +func (ac *AdminClient) Snapshots(ctx context.Context, cluster string) *SnapshotIterator { + ctx = mergeOutgoingMetadata(ctx, ac.md) + prefix := ac.instancePrefix() + clusterPath := prefix + "/clusters/" + cluster + + it := &SnapshotIterator{} + req := &btapb.ListSnapshotsRequest{ + Parent: clusterPath, + } + + fetch := func(pageSize int, pageToken string) (string, error) { + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + + var resp *btapb.ListSnapshotsResponse + err := gax.Invoke(ctx, func(ctx context.Context) error { + var err error + resp, err = ac.tClient.ListSnapshots(ctx, req) + return err + }, retryOptions...) + if err != nil { + return "", err + } + for _, s := range resp.Snapshots { + snapshotInfo, err := newSnapshotInfo(s) + if err != nil { + return "", fmt.Errorf("Failed to parse snapshot proto %v", err) + } + it.items = append(it.items, snapshotInfo) + } + return resp.NextPageToken, nil + } + bufLen := func() int { return len(it.items) } + takeBuf := func() interface{} { b := it.items; it.items = nil; return b } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, bufLen, takeBuf) + + return it +} + +func newSnapshotInfo(snapshot *btapb.Snapshot) (*SnapshotInfo, error) { + nameParts := strings.Split(snapshot.Name, "/") + name := nameParts[len(nameParts)-1] + tablePathParts := strings.Split(snapshot.SourceTable.Name, "/") + tableID := tablePathParts[len(tablePathParts)-1] + + createTime, err := ptypes.Timestamp(snapshot.CreateTime) + if err != nil { + return nil, fmt.Errorf("Invalid createTime: %v", err) + } + + deleteTime, err := ptypes.Timestamp(snapshot.DeleteTime) + if err != nil { + return nil, fmt.Errorf("Invalid deleteTime: %v", err) + } + + return &SnapshotInfo{ + Name: name, + SourceTable: tableID, + DataSize: snapshot.DataSizeBytes, + CreateTime: createTime, + DeleteTime: deleteTime, + }, nil +} + +// SnapshotIterator is an EntryIterator that iterates over log entries. +// +// This is a private alpha release of Cloud Bigtable snapshots. This feature +// is not currently available to most Cloud Bigtable customers. This feature +// might be changed in backward-incompatible ways and is not recommended for +// production use. It is not subject to any SLA or deprecation policy. +type SnapshotIterator struct { + items []*SnapshotInfo + pageInfo *iterator.PageInfo + nextFunc func() error +} + +// PageInfo supports pagination. See https://godoc.org/google.golang.org/api/iterator package for details. +func (it *SnapshotIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done +// (https://godoc.org/google.golang.org/api/iterator) if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *SnapshotIterator) Next() (*SnapshotInfo, error) { + if err := it.nextFunc(); err != nil { + return nil, err + } + item := it.items[0] + it.items = it.items[1:] + return item, nil +} + +// SnapshotInfo contains snapshot metadata. +type SnapshotInfo struct { + Name string + SourceTable string + DataSize int64 + CreateTime time.Time + DeleteTime time.Time +} + +// SnapshotInfo gets snapshot metadata. +// +// This is a private alpha release of Cloud Bigtable snapshots. This feature +// is not currently available to most Cloud Bigtable customers. This feature +// might be changed in backward-incompatible ways and is not recommended for +// production use. It is not subject to any SLA or deprecation policy. +func (ac *AdminClient) SnapshotInfo(ctx context.Context, cluster, snapshot string) (*SnapshotInfo, error) { + ctx = mergeOutgoingMetadata(ctx, ac.md) + prefix := ac.instancePrefix() + clusterPath := prefix + "/clusters/" + cluster + snapshotPath := clusterPath + "/snapshots/" + snapshot + + req := &btapb.GetSnapshotRequest{ + Name: snapshotPath, + } + + var resp *btapb.Snapshot + err := gax.Invoke(ctx, func(ctx context.Context) error { + var err error + resp, err = ac.tClient.GetSnapshot(ctx, req) + return err + }, retryOptions...) + if err != nil { + return nil, err + } + + return newSnapshotInfo(resp) +} + +// DeleteSnapshot deletes a snapshot in a cluster. +// +// This is a private alpha release of Cloud Bigtable snapshots. This feature +// is not currently available to most Cloud Bigtable customers. This feature +// might be changed in backward-incompatible ways and is not recommended for +// production use. It is not subject to any SLA or deprecation policy. +func (ac *AdminClient) DeleteSnapshot(ctx context.Context, cluster, snapshot string) error { + ctx = mergeOutgoingMetadata(ctx, ac.md) + prefix := ac.instancePrefix() + clusterPath := prefix + "/clusters/" + cluster + snapshotPath := clusterPath + "/snapshots/" + snapshot + + req := &btapb.DeleteSnapshotRequest{ + Name: snapshotPath, + } + _, err := ac.tClient.DeleteSnapshot(ctx, req) + return err +} + +// getConsistencyToken gets the consistency token for a table. +func (ac *AdminClient) getConsistencyToken(ctx context.Context, tableName string) (string, error) { + req := &btapb.GenerateConsistencyTokenRequest{ + Name: tableName, + } + resp, err := ac.tClient.GenerateConsistencyToken(ctx, req) + if err != nil { + return "", err + } + return resp.GetConsistencyToken(), nil +} + +// isConsistent checks if a token is consistent for a table. +func (ac *AdminClient) isConsistent(ctx context.Context, tableName, token string) (bool, error) { + req := &btapb.CheckConsistencyRequest{ + Name: tableName, + ConsistencyToken: token, + } + var resp *btapb.CheckConsistencyResponse + + // Retry calls on retryable errors to avoid losing the token gathered before. + err := gax.Invoke(ctx, func(ctx context.Context) error { + var err error + resp, err = ac.tClient.CheckConsistency(ctx, req) + return err + }, retryOptions...) + if err != nil { + return false, err + } + return resp.GetConsistent(), nil +} + +// WaitForReplication waits until all the writes committed before the call started have been propagated to all the clusters in the instance via replication. +func (ac *AdminClient) WaitForReplication(ctx context.Context, table string) error { + // Get the token. + prefix := ac.instancePrefix() + tableName := prefix + "/tables/" + table + token, err := ac.getConsistencyToken(ctx, tableName) + if err != nil { + return err + } + + // Periodically check if the token is consistent. + timer := time.NewTicker(time.Second * 10) + defer timer.Stop() + for { + consistent, err := ac.isConsistent(ctx, tableName, token) + if err != nil { + return err + } + if consistent { + return nil + } + // Sleep for a bit or until the ctx is cancelled. + select { + case <-ctx.Done(): + return ctx.Err() + case <-timer.C: + } + } +} + +const instanceAdminAddr = "bigtableadmin.googleapis.com:443" + +// InstanceAdminClient is a client type for performing admin operations on instances. +// These operations can be substantially more dangerous than those provided by AdminClient. +type InstanceAdminClient struct { + conn *grpc.ClientConn + iClient btapb.BigtableInstanceAdminClient + lroClient *lroauto.OperationsClient + + project string + + // Metadata to be sent with each request. + md metadata.MD +} + +// NewInstanceAdminClient creates a new InstanceAdminClient for a given project. +func NewInstanceAdminClient(ctx context.Context, project string, opts ...option.ClientOption) (*InstanceAdminClient, error) { + o, err := btopt.DefaultClientOptions(instanceAdminAddr, InstanceAdminScope, clientUserAgent) + if err != nil { + return nil, err + } + o = append(o, opts...) + conn, err := gtransport.Dial(ctx, o...) + if err != nil { + return nil, fmt.Errorf("dialing: %v", err) + } + + lroClient, err := lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + + return &InstanceAdminClient{ + conn: conn, + iClient: btapb.NewBigtableInstanceAdminClient(conn), + lroClient: lroClient, + + project: project, + md: metadata.Pairs(resourcePrefixHeader, "projects/"+project), + }, nil +} + +// Close closes the InstanceAdminClient. +func (iac *InstanceAdminClient) Close() error { + return iac.conn.Close() +} + +// StorageType is the type of storage used for all tables in an instance +type StorageType int + +const ( + SSD StorageType = iota + HDD +) + +func (st StorageType) proto() btapb.StorageType { + if st == HDD { + return btapb.StorageType_HDD + } + return btapb.StorageType_SSD +} + +// InstanceType is the type of the instance +type InstanceType int32 + +const ( + PRODUCTION InstanceType = InstanceType(btapb.Instance_PRODUCTION) + DEVELOPMENT = InstanceType(btapb.Instance_DEVELOPMENT) +) + +// InstanceInfo represents information about an instance +type InstanceInfo struct { + Name string // name of the instance + DisplayName string // display name for UIs +} + +// InstanceConf contains the information necessary to create an Instance +type InstanceConf struct { + InstanceId, DisplayName, ClusterId, Zone string + // NumNodes must not be specified for DEVELOPMENT instance types + NumNodes int32 + StorageType StorageType + InstanceType InstanceType +} + +// InstanceWithClustersConfig contains the information necessary to create an Instance +type InstanceWithClustersConfig struct { + InstanceID, DisplayName string + Clusters []ClusterConfig + InstanceType InstanceType +} + +var instanceNameRegexp = regexp.MustCompile(`^projects/([^/]+)/instances/([a-z][-a-z0-9]*)$`) + +// CreateInstance creates a new instance in the project. +// This method will return when the instance has been created or when an error occurs. +func (iac *InstanceAdminClient) CreateInstance(ctx context.Context, conf *InstanceConf) error { + newConfig := InstanceWithClustersConfig{ + InstanceID: conf.InstanceId, + DisplayName: conf.DisplayName, + InstanceType: conf.InstanceType, + Clusters: []ClusterConfig{ + { + InstanceID: conf.InstanceId, + ClusterID: conf.ClusterId, + Zone: conf.Zone, + NumNodes: conf.NumNodes, + StorageType: conf.StorageType, + }, + }, + } + return iac.CreateInstanceWithClusters(ctx, &newConfig) +} + +// CreateInstanceWithClusters creates a new instance with configured clusters in the project. +// This method will return when the instance has been created or when an error occurs. +func (iac *InstanceAdminClient) CreateInstanceWithClusters(ctx context.Context, conf *InstanceWithClustersConfig) error { + ctx = mergeOutgoingMetadata(ctx, iac.md) + clusters := make(map[string]*btapb.Cluster) + for _, cluster := range conf.Clusters { + clusters[cluster.ClusterID] = cluster.proto(iac.project) + } + + req := &btapb.CreateInstanceRequest{ + Parent: "projects/" + iac.project, + InstanceId: conf.InstanceID, + Instance: &btapb.Instance{DisplayName: conf.DisplayName, Type: btapb.Instance_Type(conf.InstanceType)}, + Clusters: clusters, + } + + lro, err := iac.iClient.CreateInstance(ctx, req) + if err != nil { + return err + } + resp := btapb.Instance{} + return longrunning.InternalNewOperation(iac.lroClient, lro).Wait(ctx, &resp) +} + +// DeleteInstance deletes an instance from the project. +func (iac *InstanceAdminClient) DeleteInstance(ctx context.Context, instanceID string) error { + ctx = mergeOutgoingMetadata(ctx, iac.md) + req := &btapb.DeleteInstanceRequest{Name: "projects/" + iac.project + "/instances/" + instanceID} + _, err := iac.iClient.DeleteInstance(ctx, req) + return err +} + +// Instances returns a list of instances in the project. +func (iac *InstanceAdminClient) Instances(ctx context.Context) ([]*InstanceInfo, error) { + ctx = mergeOutgoingMetadata(ctx, iac.md) + req := &btapb.ListInstancesRequest{ + Parent: "projects/" + iac.project, + } + var res *btapb.ListInstancesResponse + err := gax.Invoke(ctx, func(ctx context.Context) error { + var err error + res, err = iac.iClient.ListInstances(ctx, req) + return err + }, retryOptions...) + if err != nil { + return nil, err + } + if len(res.FailedLocations) > 0 { + // We don't have a good way to return a partial result in the face of some zones being unavailable. + // Fail the entire request. + return nil, status.Errorf(codes.Unavailable, "Failed locations: %v", res.FailedLocations) + } + + var is []*InstanceInfo + for _, i := range res.Instances { + m := instanceNameRegexp.FindStringSubmatch(i.Name) + if m == nil { + return nil, fmt.Errorf("malformed instance name %q", i.Name) + } + is = append(is, &InstanceInfo{ + Name: m[2], + DisplayName: i.DisplayName, + }) + } + return is, nil +} + +// InstanceInfo returns information about an instance. +func (iac *InstanceAdminClient) InstanceInfo(ctx context.Context, instanceID string) (*InstanceInfo, error) { + ctx = mergeOutgoingMetadata(ctx, iac.md) + req := &btapb.GetInstanceRequest{ + Name: "projects/" + iac.project + "/instances/" + instanceID, + } + var res *btapb.Instance + err := gax.Invoke(ctx, func(ctx context.Context) error { + var err error + res, err = iac.iClient.GetInstance(ctx, req) + return err + }, retryOptions...) + if err != nil { + return nil, err + } + + m := instanceNameRegexp.FindStringSubmatch(res.Name) + if m == nil { + return nil, fmt.Errorf("malformed instance name %q", res.Name) + } + return &InstanceInfo{ + Name: m[2], + DisplayName: res.DisplayName, + }, nil +} + +// ClusterConfig contains the information necessary to create a cluster +type ClusterConfig struct { + InstanceID, ClusterID, Zone string + NumNodes int32 + StorageType StorageType +} + +func (cc *ClusterConfig) proto(project string) *btapb.Cluster { + return &btapb.Cluster{ + ServeNodes: cc.NumNodes, + DefaultStorageType: cc.StorageType.proto(), + Location: "projects/" + project + "/locations/" + cc.Zone, + } +} + +// ClusterInfo represents information about a cluster. +type ClusterInfo struct { + Name string // name of the cluster + Zone string // GCP zone of the cluster (e.g. "us-central1-a") + ServeNodes int // number of allocated serve nodes + State string // state of the cluster +} + +// CreateCluster creates a new cluster in an instance. +// This method will return when the cluster has been created or when an error occurs. +func (iac *InstanceAdminClient) CreateCluster(ctx context.Context, conf *ClusterConfig) error { + ctx = mergeOutgoingMetadata(ctx, iac.md) + + req := &btapb.CreateClusterRequest{ + Parent: "projects/" + iac.project + "/instances/" + conf.InstanceID, + ClusterId: conf.ClusterID, + Cluster: conf.proto(iac.project), + } + + lro, err := iac.iClient.CreateCluster(ctx, req) + if err != nil { + return err + } + resp := btapb.Cluster{} + return longrunning.InternalNewOperation(iac.lroClient, lro).Wait(ctx, &resp) +} + +// DeleteCluster deletes a cluster from an instance. +func (iac *InstanceAdminClient) DeleteCluster(ctx context.Context, instanceID, clusterID string) error { + ctx = mergeOutgoingMetadata(ctx, iac.md) + req := &btapb.DeleteClusterRequest{Name: "projects/" + iac.project + "/instances/" + instanceID + "/clusters/" + clusterID} + _, err := iac.iClient.DeleteCluster(ctx, req) + return err +} + +// UpdateCluster updates attributes of a cluster +func (iac *InstanceAdminClient) UpdateCluster(ctx context.Context, instanceID, clusterID string, serveNodes int32) error { + ctx = mergeOutgoingMetadata(ctx, iac.md) + cluster := &btapb.Cluster{ + Name: "projects/" + iac.project + "/instances/" + instanceID + "/clusters/" + clusterID, + ServeNodes: serveNodes} + lro, err := iac.iClient.UpdateCluster(ctx, cluster) + if err != nil { + return err + } + return longrunning.InternalNewOperation(iac.lroClient, lro).Wait(ctx, nil) +} + +// Clusters lists the clusters in an instance. +func (iac *InstanceAdminClient) Clusters(ctx context.Context, instanceID string) ([]*ClusterInfo, error) { + ctx = mergeOutgoingMetadata(ctx, iac.md) + req := &btapb.ListClustersRequest{Parent: "projects/" + iac.project + "/instances/" + instanceID} + var res *btapb.ListClustersResponse + err := gax.Invoke(ctx, func(ctx context.Context) error { + var err error + res, err = iac.iClient.ListClusters(ctx, req) + return err + }, retryOptions...) + if err != nil { + return nil, err + } + // TODO(garyelliott): Deal with failed_locations. + var cis []*ClusterInfo + for _, c := range res.Clusters { + nameParts := strings.Split(c.Name, "/") + locParts := strings.Split(c.Location, "/") + cis = append(cis, &ClusterInfo{ + Name: nameParts[len(nameParts)-1], + Zone: locParts[len(locParts)-1], + ServeNodes: int(c.ServeNodes), + State: c.State.String(), + }) + } + return cis, nil +} + +// GetCluster fetches a cluster in an instance +func (iac *InstanceAdminClient) GetCluster(ctx context.Context, instanceID, clusterID string) (*ClusterInfo, error) { + ctx = mergeOutgoingMetadata(ctx, iac.md) + req := &btapb.GetClusterRequest{Name: "projects/" + iac.project + "/instances/" + instanceID + "/clusters/" + clusterID} + var c *btapb.Cluster + err := gax.Invoke(ctx, func(ctx context.Context) error { + var err error + c, err = iac.iClient.GetCluster(ctx, req) + return err + }, retryOptions...) + if err != nil { + return nil, err + } + + nameParts := strings.Split(c.Name, "/") + locParts := strings.Split(c.Location, "/") + cis := &ClusterInfo{ + Name: nameParts[len(nameParts)-1], + Zone: locParts[len(locParts)-1], + ServeNodes: int(c.ServeNodes), + State: c.State.String(), + } + return cis, nil +} + +// InstanceIAM returns the instance's IAM handle. +func (iac *InstanceAdminClient) InstanceIAM(instanceID string) *iam.Handle { + return iam.InternalNewHandleGRPCClient(iac.iClient, "projects/"+iac.project+"/instances/"+instanceID) + +} + +// Routing policies. +const ( + // MultiClusterRouting is a policy that allows read/write requests to be + // routed to any cluster in the instance. Requests will will fail over to + // another cluster in the event of transient errors or delays. Choosing + // this option sacrifices read-your-writes consistency to improve + // availability. + MultiClusterRouting = "multi_cluster_routing_use_any" + // SingleClusterRouting is a policy that unconditionally routes all + // read/write requests to a specific cluster. This option preserves + // read-your-writes consistency, but does not improve availability. + SingleClusterRouting = "single_cluster_routing" +) + +// ProfileConf contains the information necessary to create an profile +type ProfileConf struct { + Name string + ProfileID string + InstanceID string + Etag string + Description string + RoutingPolicy string + ClusterID string + AllowTransactionalWrites bool + + // If true, warnings are ignored + IgnoreWarnings bool +} + +// ProfileIterator iterates over profiles. +type ProfileIterator struct { + items []*btapb.AppProfile + pageInfo *iterator.PageInfo + nextFunc func() error +} + +// ProfileAttrsToUpdate define addrs to update during an Update call. If unset, no fields will be replaced. +type ProfileAttrsToUpdate struct { + // If set, updates the description. + Description optional.String + + //If set, updates the routing policy. + RoutingPolicy optional.String + + //If RoutingPolicy is updated to SingleClusterRouting, set these fields as well. + ClusterID string + AllowTransactionalWrites bool + + // If true, warnings are ignored + IgnoreWarnings bool +} + +// GetFieldMaskPath returns the field mask path. +func (p *ProfileAttrsToUpdate) GetFieldMaskPath() []string { + path := make([]string, 0) + if p.Description != nil { + path = append(path, "description") + } + + if p.RoutingPolicy != nil { + path = append(path, optional.ToString(p.RoutingPolicy)) + } + return path +} + +// PageInfo supports pagination. See https://godoc.org/google.golang.org/api/iterator package for details. +func (it *ProfileIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done +// (https://godoc.org/google.golang.org/api/iterator) if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ProfileIterator) Next() (*btapb.AppProfile, error) { + if err := it.nextFunc(); err != nil { + return nil, err + } + item := it.items[0] + it.items = it.items[1:] + return item, nil +} + +// CreateAppProfile creates an app profile within an instance. +func (iac *InstanceAdminClient) CreateAppProfile(ctx context.Context, profile ProfileConf) (*btapb.AppProfile, error) { + ctx = mergeOutgoingMetadata(ctx, iac.md) + parent := "projects/" + iac.project + "/instances/" + profile.InstanceID + appProfile := &btapb.AppProfile{ + Etag: profile.Etag, + Description: profile.Description, + } + + if profile.RoutingPolicy == "" { + return nil, errors.New("invalid routing policy") + } + + switch profile.RoutingPolicy { + case MultiClusterRouting: + appProfile.RoutingPolicy = &btapb.AppProfile_MultiClusterRoutingUseAny_{ + MultiClusterRoutingUseAny: &btapb.AppProfile_MultiClusterRoutingUseAny{}, + } + case SingleClusterRouting: + appProfile.RoutingPolicy = &btapb.AppProfile_SingleClusterRouting_{ + SingleClusterRouting: &btapb.AppProfile_SingleClusterRouting{ + ClusterId: profile.ClusterID, + AllowTransactionalWrites: profile.AllowTransactionalWrites, + }, + } + default: + return nil, errors.New("invalid routing policy") + } + + return iac.iClient.CreateAppProfile(ctx, &btapb.CreateAppProfileRequest{ + Parent: parent, + AppProfile: appProfile, + AppProfileId: profile.ProfileID, + IgnoreWarnings: profile.IgnoreWarnings, + }) +} + +// GetAppProfile gets information about an app profile. +func (iac *InstanceAdminClient) GetAppProfile(ctx context.Context, instanceID, name string) (*btapb.AppProfile, error) { + ctx = mergeOutgoingMetadata(ctx, iac.md) + profileRequest := &btapb.GetAppProfileRequest{ + Name: "projects/" + iac.project + "/instances/" + instanceID + "/appProfiles/" + name, + } + var ap *btapb.AppProfile + err := gax.Invoke(ctx, func(ctx context.Context) error { + var err error + ap, err = iac.iClient.GetAppProfile(ctx, profileRequest) + return err + }, retryOptions...) + if err != nil { + return nil, err + } + return ap, err +} + +// ListAppProfiles lists information about app profiles in an instance. +func (iac *InstanceAdminClient) ListAppProfiles(ctx context.Context, instanceID string) *ProfileIterator { + ctx = mergeOutgoingMetadata(ctx, iac.md) + listRequest := &btapb.ListAppProfilesRequest{ + Parent: "projects/" + iac.project + "/instances/" + instanceID, + } + + pit := &ProfileIterator{} + fetch := func(pageSize int, pageToken string) (string, error) { + listRequest.PageToken = pageToken + var profileRes *btapb.ListAppProfilesResponse + err := gax.Invoke(ctx, func(ctx context.Context) error { + var err error + profileRes, err = iac.iClient.ListAppProfiles(ctx, listRequest) + return err + }, retryOptions...) + if err != nil { + return "", err + } + + for _, a := range profileRes.AppProfiles { + pit.items = append(pit.items, a) + } + return profileRes.NextPageToken, nil + } + + bufLen := func() int { return len(pit.items) } + takeBuf := func() interface{} { b := pit.items; pit.items = nil; return b } + pit.pageInfo, pit.nextFunc = iterator.NewPageInfo(fetch, bufLen, takeBuf) + return pit + +} + +// UpdateAppProfile updates an app profile within an instance. +// updateAttrs should be set. If unset, all fields will be replaced. +func (iac *InstanceAdminClient) UpdateAppProfile(ctx context.Context, instanceID, profileID string, updateAttrs ProfileAttrsToUpdate) error { + ctx = mergeOutgoingMetadata(ctx, iac.md) + + profile := &btapb.AppProfile{ + Name: "projects/" + iac.project + "/instances/" + instanceID + "/appProfiles/" + profileID, + } + + if updateAttrs.Description != nil { + profile.Description = optional.ToString(updateAttrs.Description) + } + if updateAttrs.RoutingPolicy != nil { + switch optional.ToString(updateAttrs.RoutingPolicy) { + case MultiClusterRouting: + profile.RoutingPolicy = &btapb.AppProfile_MultiClusterRoutingUseAny_{ + MultiClusterRoutingUseAny: &btapb.AppProfile_MultiClusterRoutingUseAny{}, + } + case SingleClusterRouting: + profile.RoutingPolicy = &btapb.AppProfile_SingleClusterRouting_{ + SingleClusterRouting: &btapb.AppProfile_SingleClusterRouting{ + ClusterId: updateAttrs.ClusterID, + AllowTransactionalWrites: updateAttrs.AllowTransactionalWrites, + }, + } + default: + return errors.New("invalid routing policy") + } + } + patchRequest := &btapb.UpdateAppProfileRequest{ + AppProfile: profile, + UpdateMask: &field_mask.FieldMask{ + Paths: updateAttrs.GetFieldMaskPath(), + }, + IgnoreWarnings: updateAttrs.IgnoreWarnings, + } + updateRequest, err := iac.iClient.UpdateAppProfile(ctx, patchRequest) + if err != nil { + return err + } + + return longrunning.InternalNewOperation(iac.lroClient, updateRequest).Wait(ctx, nil) + +} + +// DeleteAppProfile deletes an app profile from an instance. +func (iac *InstanceAdminClient) DeleteAppProfile(ctx context.Context, instanceID, name string) error { + ctx = mergeOutgoingMetadata(ctx, iac.md) + deleteProfileRequest := &btapb.DeleteAppProfileRequest{ + Name: "projects/" + iac.project + "/instances/" + instanceID + "/appProfiles/" + name, + IgnoreWarnings: true, + } + _, err := iac.iClient.DeleteAppProfile(ctx, deleteProfileRequest) + return err + +} diff --git a/vendor/cloud.google.com/go/bigtable/admin_test.go b/vendor/cloud.google.com/go/bigtable/admin_test.go new file mode 100644 index 00000000..907f483e --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/admin_test.go @@ -0,0 +1,578 @@ +// Copyright 2015 Google LLC +// +// 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 bigtable + +import ( + "context" + "fmt" + "math" + "sort" + "strings" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "github.com/golang/protobuf/proto" + "google.golang.org/api/iterator" + btapb "google.golang.org/genproto/googleapis/bigtable/admin/v2" +) + +func TestAdminIntegration(t *testing.T) { + testEnv, err := NewIntegrationEnv() + if err != nil { + t.Fatalf("IntegrationEnv: %v", err) + } + defer testEnv.Close() + + timeout := 2 * time.Second + if testEnv.Config().UseProd { + timeout = 5 * time.Minute + } + ctx, _ := context.WithTimeout(context.Background(), timeout) + + adminClient, err := testEnv.NewAdminClient() + if err != nil { + t.Fatalf("NewAdminClient: %v", err) + } + defer adminClient.Close() + + iAdminClient, err := testEnv.NewInstanceAdminClient() + if err != nil { + t.Fatalf("NewInstanceAdminClient: %v", err) + } + if iAdminClient != nil { + defer iAdminClient.Close() + + iInfo, err := iAdminClient.InstanceInfo(ctx, adminClient.instance) + if err != nil { + t.Errorf("InstanceInfo: %v", err) + } + if iInfo.Name != adminClient.instance { + t.Errorf("InstanceInfo returned name %#v, want %#v", iInfo.Name, adminClient.instance) + } + } + + list := func() []string { + tbls, err := adminClient.Tables(ctx) + if err != nil { + t.Fatalf("Fetching list of tables: %v", err) + } + sort.Strings(tbls) + return tbls + } + containsAll := func(got, want []string) bool { + gotSet := make(map[string]bool) + + for _, s := range got { + gotSet[s] = true + } + for _, s := range want { + if !gotSet[s] { + return false + } + } + return true + } + + defer adminClient.DeleteTable(ctx, "mytable") + + if err := adminClient.CreateTable(ctx, "mytable"); err != nil { + t.Fatalf("Creating table: %v", err) + } + + defer adminClient.DeleteTable(ctx, "myothertable") + + if err := adminClient.CreateTable(ctx, "myothertable"); err != nil { + t.Fatalf("Creating table: %v", err) + } + + if got, want := list(), []string{"myothertable", "mytable"}; !containsAll(got, want) { + t.Errorf("adminClient.Tables returned %#v, want %#v", got, want) + } + + must(adminClient.WaitForReplication(ctx, "mytable")) + + if err := adminClient.DeleteTable(ctx, "myothertable"); err != nil { + t.Fatalf("Deleting table: %v", err) + } + tables := list() + if got, want := tables, []string{"mytable"}; !containsAll(got, want) { + t.Errorf("adminClient.Tables returned %#v, want %#v", got, want) + } + if got, unwanted := tables, []string{"myothertable"}; containsAll(got, unwanted) { + t.Errorf("adminClient.Tables return %#v. unwanted %#v", got, unwanted) + } + + tblConf := TableConf{ + TableID: "conftable", + Families: map[string]GCPolicy{ + "fam1": MaxVersionsPolicy(1), + "fam2": MaxVersionsPolicy(2), + }, + } + if err := adminClient.CreateTableFromConf(ctx, &tblConf); err != nil { + t.Fatalf("Creating table from TableConf: %v", err) + } + defer adminClient.DeleteTable(ctx, tblConf.TableID) + + tblInfo, err := adminClient.TableInfo(ctx, tblConf.TableID) + if err != nil { + t.Fatalf("Getting table info: %v", err) + } + sort.Strings(tblInfo.Families) + wantFams := []string{"fam1", "fam2"} + if !testutil.Equal(tblInfo.Families, wantFams) { + t.Errorf("Column family mismatch, got %v, want %v", tblInfo.Families, wantFams) + } + + // Populate mytable and drop row ranges + if err = adminClient.CreateColumnFamily(ctx, "mytable", "cf"); err != nil { + t.Fatalf("Creating column family: %v", err) + } + + client, err := testEnv.NewClient() + if err != nil { + t.Fatalf("NewClient: %v", err) + } + defer client.Close() + + tbl := client.Open("mytable") + + prefixes := []string{"a", "b", "c"} + for _, prefix := range prefixes { + for i := 0; i < 5; i++ { + mut := NewMutation() + mut.Set("cf", "col", 1000, []byte("1")) + if err := tbl.Apply(ctx, fmt.Sprintf("%v-%v", prefix, i), mut); err != nil { + t.Fatalf("Mutating row: %v", err) + } + } + } + + if err = adminClient.DropRowRange(ctx, "mytable", "a"); err != nil { + t.Errorf("DropRowRange a: %v", err) + } + if err = adminClient.DropRowRange(ctx, "mytable", "c"); err != nil { + t.Errorf("DropRowRange c: %v", err) + } + if err = adminClient.DropRowRange(ctx, "mytable", "x"); err != nil { + t.Errorf("DropRowRange x: %v", err) + } + + var gotRowCount int + must(tbl.ReadRows(ctx, RowRange{}, func(row Row) bool { + gotRowCount++ + if !strings.HasPrefix(row.Key(), "b") { + t.Errorf("Invalid row after dropping range: %v", row) + } + return true + })) + if gotRowCount != 5 { + t.Errorf("Invalid row count after dropping range: got %v, want %v", gotRowCount, 5) + } +} + +func TestInstanceUpdate(t *testing.T) { + testEnv, err := NewIntegrationEnv() + if err != nil { + t.Fatalf("IntegrationEnv: %v", err) + } + defer testEnv.Close() + + timeout := 2 * time.Second + if testEnv.Config().UseProd { + timeout = 5 * time.Minute + } + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + adminClient, err := testEnv.NewAdminClient() + if err != nil { + t.Fatalf("NewAdminClient: %v", err) + } + + defer adminClient.Close() + + iAdminClient, err := testEnv.NewInstanceAdminClient() + if err != nil { + t.Fatalf("NewInstanceAdminClient: %v", err) + } + + if iAdminClient == nil { + return + } + + defer iAdminClient.Close() + + iInfo, err := iAdminClient.InstanceInfo(ctx, adminClient.instance) + if err != nil { + t.Errorf("InstanceInfo: %v", err) + } + + if iInfo.Name != adminClient.instance { + t.Errorf("InstanceInfo returned name %#v, want %#v", iInfo.Name, adminClient.instance) + } + + if iInfo.DisplayName != adminClient.instance { + t.Errorf("InstanceInfo returned name %#v, want %#v", iInfo.Name, adminClient.instance) + } + + const numNodes = 4 + // update cluster nodes + if err := iAdminClient.UpdateCluster(ctx, adminClient.instance, testEnv.Config().Cluster, int32(numNodes)); err != nil { + t.Errorf("UpdateCluster: %v", err) + } + + // get cluster after updating + cis, err := iAdminClient.GetCluster(ctx, adminClient.instance, testEnv.Config().Cluster) + if err != nil { + t.Errorf("GetCluster %v", err) + } + if cis.ServeNodes != int(numNodes) { + t.Errorf("ServeNodes returned %d, want %d", cis.ServeNodes, int(numNodes)) + } +} + +func TestAdminSnapshotIntegration(t *testing.T) { + testEnv, err := NewIntegrationEnv() + if err != nil { + t.Fatalf("IntegrationEnv: %v", err) + } + defer testEnv.Close() + + if !testEnv.Config().UseProd { + t.Skip("emulator doesn't support snapshots") + } + + timeout := 2 * time.Second + if testEnv.Config().UseProd { + timeout = 5 * time.Minute + } + ctx, _ := context.WithTimeout(context.Background(), timeout) + + adminClient, err := testEnv.NewAdminClient() + if err != nil { + t.Fatalf("NewAdminClient: %v", err) + } + defer adminClient.Close() + + table := testEnv.Config().Table + cluster := testEnv.Config().Cluster + + list := func(cluster string) ([]*SnapshotInfo, error) { + infos := []*SnapshotInfo(nil) + + it := adminClient.Snapshots(ctx, cluster) + for { + s, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + return nil, err + } + infos = append(infos, s) + } + return infos, err + } + + // Delete the table at the end of the test. Schedule ahead of time + // in case the client fails + defer adminClient.DeleteTable(ctx, table) + + if err := adminClient.CreateTable(ctx, table); err != nil { + t.Fatalf("Creating table: %v", err) + } + + // Precondition: no snapshots + snapshots, err := list(cluster) + if err != nil { + t.Fatalf("Initial snapshot list: %v", err) + } + if got, want := len(snapshots), 0; got != want { + t.Fatalf("Initial snapshot list len: %d, want: %d", got, want) + } + + // Create snapshot + defer adminClient.DeleteSnapshot(ctx, cluster, "mysnapshot") + + if err = adminClient.SnapshotTable(ctx, table, cluster, "mysnapshot", 5*time.Hour); err != nil { + t.Fatalf("Creating snaphot: %v", err) + } + + // List snapshot + snapshots, err = list(cluster) + if err != nil { + t.Fatalf("Listing snapshots: %v", err) + } + if got, want := len(snapshots), 1; got != want { + t.Fatalf("Listing snapshot count: %d, want: %d", got, want) + } + if got, want := snapshots[0].Name, "mysnapshot"; got != want { + t.Fatalf("Snapshot name: %s, want: %s", got, want) + } + if got, want := snapshots[0].SourceTable, table; got != want { + t.Fatalf("Snapshot SourceTable: %s, want: %s", got, want) + } + if got, want := snapshots[0].DeleteTime, snapshots[0].CreateTime.Add(5*time.Hour); math.Abs(got.Sub(want).Minutes()) > 1 { + t.Fatalf("Snapshot DeleteTime: %s, want: %s", got, want) + } + + // Get snapshot + snapshot, err := adminClient.SnapshotInfo(ctx, cluster, "mysnapshot") + if err != nil { + t.Fatalf("SnapshotInfo: %v", snapshot) + } + if got, want := *snapshot, *snapshots[0]; got != want { + t.Fatalf("SnapshotInfo: %v, want: %v", got, want) + } + + // Restore + restoredTable := table + "-restored" + defer adminClient.DeleteTable(ctx, restoredTable) + if err = adminClient.CreateTableFromSnapshot(ctx, restoredTable, cluster, "mysnapshot"); err != nil { + t.Fatalf("CreateTableFromSnapshot: %v", err) + } + if _, err := adminClient.TableInfo(ctx, restoredTable); err != nil { + t.Fatalf("Restored TableInfo: %v", err) + } + + // Delete snapshot + if err = adminClient.DeleteSnapshot(ctx, cluster, "mysnapshot"); err != nil { + t.Fatalf("DeleteSnapshot: %v", err) + } + snapshots, err = list(cluster) + if err != nil { + t.Fatalf("List after Delete: %v", err) + } + if got, want := len(snapshots), 0; got != want { + t.Fatalf("List after delete len: %d, want: %d", got, want) + } +} + +func TestGranularity(t *testing.T) { + testEnv, err := NewIntegrationEnv() + if err != nil { + t.Fatalf("IntegrationEnv: %v", err) + } + defer testEnv.Close() + + timeout := 2 * time.Second + if testEnv.Config().UseProd { + timeout = 5 * time.Minute + } + ctx, _ := context.WithTimeout(context.Background(), timeout) + + adminClient, err := testEnv.NewAdminClient() + if err != nil { + t.Fatalf("NewAdminClient: %v", err) + } + defer adminClient.Close() + + list := func() []string { + tbls, err := adminClient.Tables(ctx) + if err != nil { + t.Fatalf("Fetching list of tables: %v", err) + } + sort.Strings(tbls) + return tbls + } + containsAll := func(got, want []string) bool { + gotSet := make(map[string]bool) + + for _, s := range got { + gotSet[s] = true + } + for _, s := range want { + if !gotSet[s] { + return false + } + } + return true + } + + defer adminClient.DeleteTable(ctx, "mytable") + + if err := adminClient.CreateTable(ctx, "mytable"); err != nil { + t.Fatalf("Creating table: %v", err) + } + + tables := list() + if got, want := tables, []string{"mytable"}; !containsAll(got, want) { + t.Errorf("adminClient.Tables returned %#v, want %#v", got, want) + } + + // calling ModifyColumnFamilies to check the granularity of table + prefix := adminClient.instancePrefix() + req := &btapb.ModifyColumnFamiliesRequest{ + Name: prefix + "/tables/" + "mytable", + Modifications: []*btapb.ModifyColumnFamiliesRequest_Modification{{ + Id: "cf", + Mod: &btapb.ModifyColumnFamiliesRequest_Modification_Create{&btapb.ColumnFamily{}}, + }}, + } + table, err := adminClient.tClient.ModifyColumnFamilies(ctx, req) + if err != nil { + t.Fatalf("Creating column family: %v", err) + } + if table.Granularity != btapb.Table_TimestampGranularity(btapb.Table_MILLIS) { + t.Errorf("ModifyColumnFamilies returned granularity %#v, want %#v", table.Granularity, btapb.Table_TimestampGranularity(btapb.Table_MILLIS)) + } +} + +func TestInstanceAdminClient_AppProfile(t *testing.T) { + testEnv, err := NewIntegrationEnv() + if err != nil { + t.Fatalf("IntegrationEnv: %v", err) + } + defer testEnv.Close() + + timeout := 2 * time.Second + if testEnv.Config().UseProd { + timeout = 5 * time.Minute + } + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + adminClient, err := testEnv.NewAdminClient() + if err != nil { + t.Fatalf("NewAdminClient: %v", err) + } + defer adminClient.Close() + + iAdminClient, err := testEnv.NewInstanceAdminClient() + if err != nil { + t.Fatalf("NewInstanceAdminClient: %v", err) + } + + if iAdminClient == nil { + return + } + + defer iAdminClient.Close() + profile := ProfileConf{ + ProfileID: "app_profile1", + InstanceID: adminClient.instance, + ClusterID: testEnv.Config().Cluster, + Description: "creating new app profile 1", + RoutingPolicy: SingleClusterRouting, + } + + createdProfile, err := iAdminClient.CreateAppProfile(ctx, profile) + if err != nil { + t.Fatalf("Creating app profile: %v", err) + + } + + gotProfile, err := iAdminClient.GetAppProfile(ctx, adminClient.instance, "app_profile1") + + if err != nil { + t.Fatalf("Get app profile: %v", err) + } + + if !proto.Equal(createdProfile, gotProfile) { + t.Fatalf("created profile: %s, got profile: %s", createdProfile.Name, gotProfile.Name) + + } + + list := func(instanceID string) ([]*btapb.AppProfile, error) { + profiles := []*btapb.AppProfile(nil) + + it := iAdminClient.ListAppProfiles(ctx, instanceID) + for { + s, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + return nil, err + } + profiles = append(profiles, s) + } + return profiles, err + } + + profiles, err := list(adminClient.instance) + if err != nil { + t.Fatalf("List app profile: %v", err) + } + + if got, want := len(profiles), 1; got != want { + t.Fatalf("Initial app profile list len: %d, want: %d", got, want) + } + + for _, test := range []struct { + desc string + uattrs ProfileAttrsToUpdate + want *btapb.AppProfile // nil means error + }{ + { + desc: "empty update", + uattrs: ProfileAttrsToUpdate{}, + want: nil, + }, + + { + desc: "empty description update", + uattrs: ProfileAttrsToUpdate{Description: ""}, + want: &btapb.AppProfile{ + Name: gotProfile.Name, + Description: "", + RoutingPolicy: gotProfile.RoutingPolicy, + Etag: gotProfile.Etag}, + }, + { + desc: "routing update", + uattrs: ProfileAttrsToUpdate{ + RoutingPolicy: SingleClusterRouting, + ClusterID: testEnv.Config().Cluster, + }, + want: &btapb.AppProfile{ + Name: gotProfile.Name, + Description: "", + Etag: gotProfile.Etag, + RoutingPolicy: &btapb.AppProfile_SingleClusterRouting_{ + SingleClusterRouting: &btapb.AppProfile_SingleClusterRouting{ + ClusterId: testEnv.Config().Cluster, + }}, + }, + }, + } { + err = iAdminClient.UpdateAppProfile(ctx, adminClient.instance, "app_profile1", test.uattrs) + if err != nil { + if test.want != nil { + t.Errorf("%s: %v", test.desc, err) + } + continue + } + if err == nil && test.want == nil { + t.Errorf("%s: got nil, want error", test.desc) + continue + } + + got, _ := iAdminClient.GetAppProfile(ctx, adminClient.instance, "app_profile1") + + if !proto.Equal(got, test.want) { + t.Fatalf("%s : got profile : %v, want profile: %v", test.desc, gotProfile, test.want) + } + + } + + err = iAdminClient.DeleteAppProfile(ctx, adminClient.instance, "app_profile1") + if err != nil { + t.Fatalf("Delete app profile: %v", err) + } + +} diff --git a/vendor/cloud.google.com/go/bigtable/bigtable.go b/vendor/cloud.google.com/go/bigtable/bigtable.go new file mode 100644 index 00000000..07b4ee88 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/bigtable.go @@ -0,0 +1,914 @@ +/* +Copyright 2015 Google LLC + +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 bigtable // import "cloud.google.com/go/bigtable" + +import ( + "context" + "errors" + "fmt" + "io" + "strconv" + "time" + + "cloud.google.com/go/bigtable/internal/gax" + btopt "cloud.google.com/go/bigtable/internal/option" + "github.com/golang/protobuf/proto" + "google.golang.org/api/option" + gtransport "google.golang.org/api/transport/grpc" + btpb "google.golang.org/genproto/googleapis/bigtable/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +const prodAddr = "bigtable.googleapis.com:443" + +// Client is a client for reading and writing data to tables in an instance. +// +// A Client is safe to use concurrently, except for its Close method. +type Client struct { + conn *grpc.ClientConn + client btpb.BigtableClient + project, instance string + appProfile string +} + +// ClientConfig has configurations for the client. +type ClientConfig struct { + // The id of the app profile to associate with all data operations sent from this client. + // If unspecified, the default app profile for the instance will be used. + AppProfile string +} + +// NewClient creates a new Client for a given project and instance. +// The default ClientConfig will be used. +func NewClient(ctx context.Context, project, instance string, opts ...option.ClientOption) (*Client, error) { + return NewClientWithConfig(ctx, project, instance, ClientConfig{}, opts...) +} + +// NewClientWithConfig creates a new client with the given config. +func NewClientWithConfig(ctx context.Context, project, instance string, config ClientConfig, opts ...option.ClientOption) (*Client, error) { + o, err := btopt.DefaultClientOptions(prodAddr, Scope, clientUserAgent) + if err != nil { + return nil, err + } + // Default to a small connection pool that can be overridden. + o = append(o, + option.WithGRPCConnectionPool(4), + // Set the max size to correspond to server-side limits. + option.WithGRPCDialOption(grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(100<<20), grpc.MaxCallRecvMsgSize(100<<20))), + // TODO(grpc/grpc-go#1388) using connection pool without WithBlock + // can cause RPCs to fail randomly. We can delete this after the issue is fixed. + option.WithGRPCDialOption(grpc.WithBlock())) + o = append(o, opts...) + conn, err := gtransport.Dial(ctx, o...) + if err != nil { + return nil, fmt.Errorf("dialing: %v", err) + } + + return &Client{ + conn: conn, + client: btpb.NewBigtableClient(conn), + project: project, + instance: instance, + appProfile: config.AppProfile, + }, nil +} + +// Close closes the Client. +func (c *Client) Close() error { + return c.conn.Close() +} + +var ( + idempotentRetryCodes = []codes.Code{codes.DeadlineExceeded, codes.Unavailable, codes.Aborted} + isIdempotentRetryCode = make(map[codes.Code]bool) + retryOptions = []gax.CallOption{ + gax.WithDelayTimeoutSettings(100*time.Millisecond, 2000*time.Millisecond, 1.2), + gax.WithRetryCodes(idempotentRetryCodes), + } +) + +func init() { + for _, code := range idempotentRetryCodes { + isIdempotentRetryCode[code] = true + } +} + +func (c *Client) fullTableName(table string) string { + return fmt.Sprintf("projects/%s/instances/%s/tables/%s", c.project, c.instance, table) +} + +// A Table refers to a table. +// +// A Table is safe to use concurrently. +type Table struct { + c *Client + table string + + // Metadata to be sent with each request. + md metadata.MD +} + +// Open opens a table. +func (c *Client) Open(table string) *Table { + return &Table{ + c: c, + table: table, + md: metadata.Pairs(resourcePrefixHeader, c.fullTableName(table)), + } +} + +// TODO(dsymonds): Read method that returns a sequence of ReadItems. + +// ReadRows reads rows from a table. f is called for each row. +// If f returns false, the stream is shut down and ReadRows returns. +// f owns its argument, and f is called serially in order by row key. +// +// By default, the yielded rows will contain all values in all cells. +// Use RowFilter to limit the cells returned. +func (t *Table) ReadRows(ctx context.Context, arg RowSet, f func(Row) bool, opts ...ReadOption) error { + ctx = mergeOutgoingMetadata(ctx, t.md) + + var prevRowKey string + var err error + ctx = traceStartSpan(ctx, "cloud.google.com/go/bigtable.ReadRows") + defer func() { traceEndSpan(ctx, err) }() + attrMap := make(map[string]interface{}) + err = gax.Invoke(ctx, func(ctx context.Context) error { + if !arg.valid() { + // Empty row set, no need to make an API call. + // NOTE: we must return early if arg == RowList{} because reading + // an empty RowList from bigtable returns all rows from that table. + return nil + } + req := &btpb.ReadRowsRequest{ + TableName: t.c.fullTableName(t.table), + AppProfileId: t.c.appProfile, + Rows: arg.proto(), + } + for _, opt := range opts { + opt.set(req) + } + ctx, cancel := context.WithCancel(ctx) // for aborting the stream + defer cancel() + + startTime := time.Now() + stream, err := t.c.client.ReadRows(ctx, req) + if err != nil { + return err + } + cr := newChunkReader() + for { + res, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + // Reset arg for next Invoke call. + arg = arg.retainRowsAfter(prevRowKey) + attrMap["rowKey"] = prevRowKey + attrMap["error"] = err.Error() + attrMap["time_secs"] = time.Since(startTime).Seconds() + tracePrintf(ctx, attrMap, "Retry details in ReadRows") + return err + } + attrMap["time_secs"] = time.Since(startTime).Seconds() + attrMap["rowCount"] = len(res.Chunks) + tracePrintf(ctx, attrMap, "Details in ReadRows") + + for _, cc := range res.Chunks { + row, err := cr.Process(cc) + if err != nil { + // No need to prepare for a retry, this is an unretryable error. + return err + } + if row == nil { + continue + } + prevRowKey = row.Key() + if !f(row) { + // Cancel and drain stream. + cancel() + for { + if _, err := stream.Recv(); err != nil { + // The stream has ended. We don't return an error + // because the caller has intentionally interrupted the scan. + return nil + } + } + } + } + if err := cr.Close(); err != nil { + // No need to prepare for a retry, this is an unretryable error. + return err + } + } + return err + }, retryOptions...) + + return err +} + +// ReadRow is a convenience implementation of a single-row reader. +// A missing row will return a zero-length map and a nil error. +func (t *Table) ReadRow(ctx context.Context, row string, opts ...ReadOption) (Row, error) { + var r Row + err := t.ReadRows(ctx, SingleRow(row), func(rr Row) bool { + r = rr + return true + }, opts...) + return r, err +} + +// decodeFamilyProto adds the cell data from f to the given row. +func decodeFamilyProto(r Row, row string, f *btpb.Family) { + fam := f.Name // does not have colon + for _, col := range f.Columns { + for _, cell := range col.Cells { + ri := ReadItem{ + Row: row, + Column: fam + ":" + string(col.Qualifier), + Timestamp: Timestamp(cell.TimestampMicros), + Value: cell.Value, + } + r[fam] = append(r[fam], ri) + } + } +} + +// RowSet is a set of rows to be read. It is satisfied by RowList, RowRange and RowRangeList. +// The serialized size of the RowSet must be no larger than 1MiB. +type RowSet interface { + proto() *btpb.RowSet + + // retainRowsAfter returns a new RowSet that does not include the + // given row key or any row key lexicographically less than it. + retainRowsAfter(lastRowKey string) RowSet + + // Valid reports whether this set can cover at least one row. + valid() bool +} + +// RowList is a sequence of row keys. +type RowList []string + +func (r RowList) proto() *btpb.RowSet { + keys := make([][]byte, len(r)) + for i, row := range r { + keys[i] = []byte(row) + } + return &btpb.RowSet{RowKeys: keys} +} + +func (r RowList) retainRowsAfter(lastRowKey string) RowSet { + var retryKeys RowList + for _, key := range r { + if key > lastRowKey { + retryKeys = append(retryKeys, key) + } + } + return retryKeys +} + +func (r RowList) valid() bool { + return len(r) > 0 +} + +// A RowRange is a half-open interval [Start, Limit) encompassing +// all the rows with keys at least as large as Start, and less than Limit. +// (Bigtable string comparison is the same as Go's.) +// A RowRange can be unbounded, encompassing all keys at least as large as Start. +type RowRange struct { + start string + limit string +} + +// NewRange returns the new RowRange [begin, end). +func NewRange(begin, end string) RowRange { + return RowRange{ + start: begin, + limit: end, + } +} + +// Unbounded tests whether a RowRange is unbounded. +func (r RowRange) Unbounded() bool { + return r.limit == "" +} + +// Contains says whether the RowRange contains the key. +func (r RowRange) Contains(row string) bool { + return r.start <= row && (r.limit == "" || r.limit > row) +} + +// String provides a printable description of a RowRange. +func (r RowRange) String() string { + a := strconv.Quote(r.start) + if r.Unbounded() { + return fmt.Sprintf("[%s,∞)", a) + } + return fmt.Sprintf("[%s,%q)", a, r.limit) +} + +func (r RowRange) proto() *btpb.RowSet { + rr := &btpb.RowRange{ + StartKey: &btpb.RowRange_StartKeyClosed{StartKeyClosed: []byte(r.start)}, + } + if !r.Unbounded() { + rr.EndKey = &btpb.RowRange_EndKeyOpen{EndKeyOpen: []byte(r.limit)} + } + return &btpb.RowSet{RowRanges: []*btpb.RowRange{rr}} +} + +func (r RowRange) retainRowsAfter(lastRowKey string) RowSet { + if lastRowKey == "" || lastRowKey < r.start { + return r + } + // Set the beginning of the range to the row after the last scanned. + start := lastRowKey + "\x00" + if r.Unbounded() { + return InfiniteRange(start) + } + return NewRange(start, r.limit) +} + +func (r RowRange) valid() bool { + return r.Unbounded() || r.start < r.limit +} + +// RowRangeList is a sequence of RowRanges representing the union of the ranges. +type RowRangeList []RowRange + +func (r RowRangeList) proto() *btpb.RowSet { + ranges := make([]*btpb.RowRange, len(r)) + for i, rr := range r { + // RowRange.proto() returns a RowSet with a single element RowRange array + ranges[i] = rr.proto().RowRanges[0] + } + return &btpb.RowSet{RowRanges: ranges} +} + +func (r RowRangeList) retainRowsAfter(lastRowKey string) RowSet { + if lastRowKey == "" { + return r + } + // Return a list of any range that has not yet been completely processed + var ranges RowRangeList + for _, rr := range r { + retained := rr.retainRowsAfter(lastRowKey) + if retained.valid() { + ranges = append(ranges, retained.(RowRange)) + } + } + return ranges +} + +func (r RowRangeList) valid() bool { + for _, rr := range r { + if rr.valid() { + return true + } + } + return false +} + +// SingleRow returns a RowSet for reading a single row. +func SingleRow(row string) RowSet { + return RowList{row} +} + +// PrefixRange returns a RowRange consisting of all keys starting with the prefix. +func PrefixRange(prefix string) RowRange { + return RowRange{ + start: prefix, + limit: prefixSuccessor(prefix), + } +} + +// InfiniteRange returns the RowRange consisting of all keys at least as +// large as start. +func InfiniteRange(start string) RowRange { + return RowRange{ + start: start, + limit: "", + } +} + +// prefixSuccessor returns the lexically smallest string greater than the +// prefix, if it exists, or "" otherwise. In either case, it is the string +// needed for the Limit of a RowRange. +func prefixSuccessor(prefix string) string { + if prefix == "" { + return "" // infinite range + } + n := len(prefix) + for n--; n >= 0 && prefix[n] == '\xff'; n-- { + } + if n == -1 { + return "" + } + ans := []byte(prefix[:n]) + ans = append(ans, prefix[n]+1) + return string(ans) +} + +// A ReadOption is an optional argument to ReadRows. +type ReadOption interface { + set(req *btpb.ReadRowsRequest) +} + +// RowFilter returns a ReadOption that applies f to the contents of read rows. +// +// If multiple RowFilters are provided, only the last is used. To combine filters, +// use ChainFilters or InterleaveFilters instead. +func RowFilter(f Filter) ReadOption { return rowFilter{f} } + +type rowFilter struct{ f Filter } + +func (rf rowFilter) set(req *btpb.ReadRowsRequest) { req.Filter = rf.f.proto() } + +// LimitRows returns a ReadOption that will limit the number of rows to be read. +func LimitRows(limit int64) ReadOption { return limitRows{limit} } + +type limitRows struct{ limit int64 } + +func (lr limitRows) set(req *btpb.ReadRowsRequest) { req.RowsLimit = lr.limit } + +// mutationsAreRetryable returns true if all mutations are idempotent +// and therefore retryable. A mutation is idempotent iff all cell timestamps +// have an explicit timestamp set and do not rely on the timestamp being set on the server. +func mutationsAreRetryable(muts []*btpb.Mutation) bool { + serverTime := int64(ServerTime) + for _, mut := range muts { + setCell := mut.GetSetCell() + if setCell != nil && setCell.TimestampMicros == serverTime { + return false + } + } + return true +} + +const maxMutations = 100000 + +// Apply mutates a row atomically. A mutation must contain at least one +// operation and at most 100000 operations. +func (t *Table) Apply(ctx context.Context, row string, m *Mutation, opts ...ApplyOption) error { + ctx = mergeOutgoingMetadata(ctx, t.md) + after := func(res proto.Message) { + for _, o := range opts { + o.after(res) + } + } + + var err error + ctx = traceStartSpan(ctx, "cloud.google.com/go/bigtable/Apply") + defer func() { traceEndSpan(ctx, err) }() + var callOptions []gax.CallOption + if m.cond == nil { + req := &btpb.MutateRowRequest{ + TableName: t.c.fullTableName(t.table), + AppProfileId: t.c.appProfile, + RowKey: []byte(row), + Mutations: m.ops, + } + if mutationsAreRetryable(m.ops) { + callOptions = retryOptions + } + var res *btpb.MutateRowResponse + err := gax.Invoke(ctx, func(ctx context.Context) error { + var err error + res, err = t.c.client.MutateRow(ctx, req) + return err + }, callOptions...) + if err == nil { + after(res) + } + return err + } + + req := &btpb.CheckAndMutateRowRequest{ + TableName: t.c.fullTableName(t.table), + AppProfileId: t.c.appProfile, + RowKey: []byte(row), + PredicateFilter: m.cond.proto(), + } + if m.mtrue != nil { + if m.mtrue.cond != nil { + return errors.New("bigtable: conditional mutations cannot be nested") + } + req.TrueMutations = m.mtrue.ops + } + if m.mfalse != nil { + if m.mfalse.cond != nil { + return errors.New("bigtable: conditional mutations cannot be nested") + } + req.FalseMutations = m.mfalse.ops + } + if mutationsAreRetryable(req.TrueMutations) && mutationsAreRetryable(req.FalseMutations) { + callOptions = retryOptions + } + var cmRes *btpb.CheckAndMutateRowResponse + err = gax.Invoke(ctx, func(ctx context.Context) error { + var err error + cmRes, err = t.c.client.CheckAndMutateRow(ctx, req) + return err + }, callOptions...) + if err == nil { + after(cmRes) + } + return err +} + +// An ApplyOption is an optional argument to Apply. +type ApplyOption interface { + after(res proto.Message) +} + +type applyAfterFunc func(res proto.Message) + +func (a applyAfterFunc) after(res proto.Message) { a(res) } + +// GetCondMutationResult returns an ApplyOption that reports whether the conditional +// mutation's condition matched. +func GetCondMutationResult(matched *bool) ApplyOption { + return applyAfterFunc(func(res proto.Message) { + if res, ok := res.(*btpb.CheckAndMutateRowResponse); ok { + *matched = res.PredicateMatched + } + }) +} + +// Mutation represents a set of changes for a single row of a table. +type Mutation struct { + ops []*btpb.Mutation + + // for conditional mutations + cond Filter + mtrue, mfalse *Mutation +} + +// NewMutation returns a new mutation. +func NewMutation() *Mutation { + return new(Mutation) +} + +// NewCondMutation returns a conditional mutation. +// The given row filter determines which mutation is applied: +// If the filter matches any cell in the row, mtrue is applied; +// otherwise, mfalse is applied. +// Either given mutation may be nil. +func NewCondMutation(cond Filter, mtrue, mfalse *Mutation) *Mutation { + return &Mutation{cond: cond, mtrue: mtrue, mfalse: mfalse} +} + +// Set sets a value in a specified column, with the given timestamp. +// The timestamp will be truncated to millisecond granularity. +// A timestamp of ServerTime means to use the server timestamp. +func (m *Mutation) Set(family, column string, ts Timestamp, value []byte) { + m.ops = append(m.ops, &btpb.Mutation{Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{ + FamilyName: family, + ColumnQualifier: []byte(column), + TimestampMicros: int64(ts.TruncateToMilliseconds()), + Value: value, + }}}) +} + +// DeleteCellsInColumn will delete all the cells whose columns are family:column. +func (m *Mutation) DeleteCellsInColumn(family, column string) { + m.ops = append(m.ops, &btpb.Mutation{Mutation: &btpb.Mutation_DeleteFromColumn_{DeleteFromColumn: &btpb.Mutation_DeleteFromColumn{ + FamilyName: family, + ColumnQualifier: []byte(column), + }}}) +} + +// DeleteTimestampRange deletes all cells whose columns are family:column +// and whose timestamps are in the half-open interval [start, end). +// If end is zero, it will be interpreted as infinity. +// The timestamps will be truncated to millisecond granularity. +func (m *Mutation) DeleteTimestampRange(family, column string, start, end Timestamp) { + m.ops = append(m.ops, &btpb.Mutation{Mutation: &btpb.Mutation_DeleteFromColumn_{DeleteFromColumn: &btpb.Mutation_DeleteFromColumn{ + FamilyName: family, + ColumnQualifier: []byte(column), + TimeRange: &btpb.TimestampRange{ + StartTimestampMicros: int64(start.TruncateToMilliseconds()), + EndTimestampMicros: int64(end.TruncateToMilliseconds()), + }, + }}}) +} + +// DeleteCellsInFamily will delete all the cells whose columns are family:*. +func (m *Mutation) DeleteCellsInFamily(family string) { + m.ops = append(m.ops, &btpb.Mutation{Mutation: &btpb.Mutation_DeleteFromFamily_{DeleteFromFamily: &btpb.Mutation_DeleteFromFamily{ + FamilyName: family, + }}}) +} + +// DeleteRow deletes the entire row. +func (m *Mutation) DeleteRow() { + m.ops = append(m.ops, &btpb.Mutation{Mutation: &btpb.Mutation_DeleteFromRow_{DeleteFromRow: &btpb.Mutation_DeleteFromRow{}}}) +} + +// entryErr is a container that combines an entry with the error that was returned for it. +// Err may be nil if no error was returned for the Entry, or if the Entry has not yet been processed. +type entryErr struct { + Entry *btpb.MutateRowsRequest_Entry + Err error +} + +// ApplyBulk applies multiple Mutations, up to a maximum of 100,000. +// Each mutation is individually applied atomically, +// but the set of mutations may be applied in any order. +// +// Two types of failures may occur. If the entire process +// fails, (nil, err) will be returned. If specific mutations +// fail to apply, ([]err, nil) will be returned, and the errors +// will correspond to the relevant rowKeys/muts arguments. +// +// Conditional mutations cannot be applied in bulk and providing one will result in an error. +func (t *Table) ApplyBulk(ctx context.Context, rowKeys []string, muts []*Mutation, opts ...ApplyOption) ([]error, error) { + ctx = mergeOutgoingMetadata(ctx, t.md) + if len(rowKeys) != len(muts) { + return nil, fmt.Errorf("mismatched rowKeys and mutation array lengths: %d, %d", len(rowKeys), len(muts)) + } + + origEntries := make([]*entryErr, len(rowKeys)) + for i, key := range rowKeys { + mut := muts[i] + if mut.cond != nil { + return nil, errors.New("conditional mutations cannot be applied in bulk") + } + origEntries[i] = &entryErr{Entry: &btpb.MutateRowsRequest_Entry{RowKey: []byte(key), Mutations: mut.ops}} + } + + var err error + ctx = traceStartSpan(ctx, "cloud.google.com/go/bigtable/ApplyBulk") + defer func() { traceEndSpan(ctx, err) }() + + for _, group := range groupEntries(origEntries, maxMutations) { + attrMap := make(map[string]interface{}) + err = gax.Invoke(ctx, func(ctx context.Context) error { + attrMap["rowCount"] = len(group) + tracePrintf(ctx, attrMap, "Row count in ApplyBulk") + err := t.doApplyBulk(ctx, group, opts...) + if err != nil { + // We want to retry the entire request with the current group + return err + } + group = t.getApplyBulkRetries(group) + if len(group) > 0 && len(idempotentRetryCodes) > 0 { + // We have at least one mutation that needs to be retried. + // Return an arbitrary error that is retryable according to callOptions. + return status.Errorf(idempotentRetryCodes[0], "Synthetic error: partial failure of ApplyBulk") + } + return nil + }, retryOptions...) + if err != nil { + return nil, err + } + } + + // Accumulate all of the errors into an array to return, interspersed with nils for successful + // entries. The absence of any errors means we should return nil. + var errs []error + var foundErr bool + for _, entry := range origEntries { + if entry.Err != nil { + foundErr = true + } + errs = append(errs, entry.Err) + } + if foundErr { + return errs, nil + } + return nil, nil +} + +// getApplyBulkRetries returns the entries that need to be retried +func (t *Table) getApplyBulkRetries(entries []*entryErr) []*entryErr { + var retryEntries []*entryErr + for _, entry := range entries { + err := entry.Err + if err != nil && isIdempotentRetryCode[grpc.Code(err)] && mutationsAreRetryable(entry.Entry.Mutations) { + // There was an error and the entry is retryable. + retryEntries = append(retryEntries, entry) + } + } + return retryEntries +} + +// doApplyBulk does the work of a single ApplyBulk invocation +func (t *Table) doApplyBulk(ctx context.Context, entryErrs []*entryErr, opts ...ApplyOption) error { + after := func(res proto.Message) { + for _, o := range opts { + o.after(res) + } + } + + entries := make([]*btpb.MutateRowsRequest_Entry, len(entryErrs)) + for i, entryErr := range entryErrs { + entries[i] = entryErr.Entry + } + req := &btpb.MutateRowsRequest{ + TableName: t.c.fullTableName(t.table), + AppProfileId: t.c.appProfile, + Entries: entries, + } + stream, err := t.c.client.MutateRows(ctx, req) + if err != nil { + return err + } + for { + res, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + return err + } + + for i, entry := range res.Entries { + s := entry.Status + if s.Code == int32(codes.OK) { + entryErrs[i].Err = nil + } else { + entryErrs[i].Err = status.Errorf(codes.Code(s.Code), s.Message) + } + } + after(res) + } + return nil +} + +// groupEntries groups entries into groups of a specified size without breaking up +// individual entries. +func groupEntries(entries []*entryErr, maxSize int) [][]*entryErr { + var ( + res [][]*entryErr + start int + gmuts int + ) + addGroup := func(end int) { + if end-start > 0 { + res = append(res, entries[start:end]) + start = end + gmuts = 0 + } + } + for i, e := range entries { + emuts := len(e.Entry.Mutations) + if gmuts+emuts > maxSize { + addGroup(i) + } + gmuts += emuts + } + addGroup(len(entries)) + return res +} + +// Timestamp is in units of microseconds since 1 January 1970. +type Timestamp int64 + +// ServerTime is a specific Timestamp that may be passed to (*Mutation).Set. +// It indicates that the server's timestamp should be used. +const ServerTime Timestamp = -1 + +// Time converts a time.Time into a Timestamp. +func Time(t time.Time) Timestamp { return Timestamp(t.UnixNano() / 1e3) } + +// Now returns the Timestamp representation of the current time on the client. +func Now() Timestamp { return Time(time.Now()) } + +// Time converts a Timestamp into a time.Time. +func (ts Timestamp) Time() time.Time { return time.Unix(0, int64(ts)*1e3) } + +// TruncateToMilliseconds truncates a Timestamp to millisecond granularity, +// which is currently the only granularity supported. +func (ts Timestamp) TruncateToMilliseconds() Timestamp { + if ts == ServerTime { + return ts + } + return ts - ts%1000 +} + +// ApplyReadModifyWrite applies a ReadModifyWrite to a specific row. +// It returns the newly written cells. +func (t *Table) ApplyReadModifyWrite(ctx context.Context, row string, m *ReadModifyWrite) (Row, error) { + ctx = mergeOutgoingMetadata(ctx, t.md) + req := &btpb.ReadModifyWriteRowRequest{ + TableName: t.c.fullTableName(t.table), + AppProfileId: t.c.appProfile, + RowKey: []byte(row), + Rules: m.ops, + } + res, err := t.c.client.ReadModifyWriteRow(ctx, req) + if err != nil { + return nil, err + } + if res.Row == nil { + return nil, errors.New("unable to apply ReadModifyWrite: res.Row=nil") + } + r := make(Row) + for _, fam := range res.Row.Families { // res is *btpb.Row, fam is *btpb.Family + decodeFamilyProto(r, row, fam) + } + return r, nil +} + +// ReadModifyWrite represents a set of operations on a single row of a table. +// It is like Mutation but for non-idempotent changes. +// When applied, these operations operate on the latest values of the row's cells, +// and result in a new value being written to the relevant cell with a timestamp +// that is max(existing timestamp, current server time). +// +// The application of a ReadModifyWrite is atomic; concurrent ReadModifyWrites will +// be executed serially by the server. +type ReadModifyWrite struct { + ops []*btpb.ReadModifyWriteRule +} + +// NewReadModifyWrite returns a new ReadModifyWrite. +func NewReadModifyWrite() *ReadModifyWrite { return new(ReadModifyWrite) } + +// AppendValue appends a value to a specific cell's value. +// If the cell is unset, it will be treated as an empty value. +func (m *ReadModifyWrite) AppendValue(family, column string, v []byte) { + m.ops = append(m.ops, &btpb.ReadModifyWriteRule{ + FamilyName: family, + ColumnQualifier: []byte(column), + Rule: &btpb.ReadModifyWriteRule_AppendValue{AppendValue: v}, + }) +} + +// Increment interprets the value in a specific cell as a 64-bit big-endian signed integer, +// and adds a value to it. If the cell is unset, it will be treated as zero. +// If the cell is set and is not an 8-byte value, the entire ApplyReadModifyWrite +// operation will fail. +func (m *ReadModifyWrite) Increment(family, column string, delta int64) { + m.ops = append(m.ops, &btpb.ReadModifyWriteRule{ + FamilyName: family, + ColumnQualifier: []byte(column), + Rule: &btpb.ReadModifyWriteRule_IncrementAmount{IncrementAmount: delta}, + }) +} + +// mergeOutgoingMetadata returns a context populated by the existing outgoing metadata, +// if any, joined with internal metadata. +func mergeOutgoingMetadata(ctx context.Context, md metadata.MD) context.Context { + mdCopy, _ := metadata.FromOutgoingContext(ctx) + return metadata.NewOutgoingContext(ctx, metadata.Join(mdCopy, md)) +} + +// SampleRowKeys returns a sample of row keys in the table. The returned row keys will delimit contiguous sections of +// the table of approximately equal size, which can be used to break up the data for distributed tasks like mapreduces. +func (t *Table) SampleRowKeys(ctx context.Context) ([]string, error) { + ctx = mergeOutgoingMetadata(ctx, t.md) + var sampledRowKeys []string + err := gax.Invoke(ctx, func(ctx context.Context) error { + sampledRowKeys = nil + req := &btpb.SampleRowKeysRequest{ + TableName: t.c.fullTableName(t.table), + AppProfileId: t.c.appProfile, + } + ctx, cancel := context.WithCancel(ctx) // for aborting the stream + defer cancel() + + stream, err := t.c.client.SampleRowKeys(ctx, req) + if err != nil { + return err + } + for { + res, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + return err + } + + key := string(res.RowKey) + if key == "" { + continue + } + + sampledRowKeys = append(sampledRowKeys, key) + } + return nil + }, retryOptions...) + return sampledRowKeys, err +} diff --git a/vendor/cloud.google.com/go/bigtable/bigtable_test.go b/vendor/cloud.google.com/go/bigtable/bigtable_test.go new file mode 100644 index 00000000..55bf17aa --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/bigtable_test.go @@ -0,0 +1,1255 @@ +/* +Copyright 2015 Google LLC + +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 bigtable + +import ( + "context" + "fmt" + "math/rand" + "strings" + "sync" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" + "google.golang.org/api/option" + btpb "google.golang.org/genproto/googleapis/bigtable/v2" + "google.golang.org/grpc" +) + +func TestPrefix(t *testing.T) { + tests := []struct { + prefix, succ string + }{ + {"", ""}, + {"\xff", ""}, // when used, "" means Infinity + {"x\xff", "y"}, + {"\xfe", "\xff"}, + } + for _, tc := range tests { + got := prefixSuccessor(tc.prefix) + if got != tc.succ { + t.Errorf("prefixSuccessor(%q) = %q, want %s", tc.prefix, got, tc.succ) + continue + } + r := PrefixRange(tc.prefix) + if tc.succ == "" && r.limit != "" { + t.Errorf("PrefixRange(%q) got limit %q", tc.prefix, r.limit) + } + if tc.succ != "" && r.limit != tc.succ { + t.Errorf("PrefixRange(%q) got limit %q, want %q", tc.prefix, r.limit, tc.succ) + } + } +} + +func TestApplyErrors(t *testing.T) { + ctx := context.Background() + table := &Table{ + c: &Client{ + project: "P", + instance: "I", + }, + table: "t", + } + f := ColumnFilter("C") + m := NewMutation() + m.DeleteRow() + // Test nested conditional mutations. + cm := NewCondMutation(f, NewCondMutation(f, m, nil), nil) + if err := table.Apply(ctx, "x", cm); err == nil { + t.Error("got nil, want error") + } + cm = NewCondMutation(f, nil, NewCondMutation(f, m, nil)) + if err := table.Apply(ctx, "x", cm); err == nil { + t.Error("got nil, want error") + } +} + +func TestGroupEntries(t *testing.T) { + tests := []struct { + desc string + in []*entryErr + size int + want [][]*entryErr + }{ + { + desc: "one entry less than max size is one group", + in: []*entryErr{buildEntry(5)}, + size: 10, + want: [][]*entryErr{{buildEntry(5)}}, + }, + { + desc: "one entry equal to max size is one group", + in: []*entryErr{buildEntry(10)}, + size: 10, + want: [][]*entryErr{{buildEntry(10)}}, + }, + { + desc: "one entry greater than max size is one group", + in: []*entryErr{buildEntry(15)}, + size: 10, + want: [][]*entryErr{{buildEntry(15)}}, + }, + { + desc: "all entries fitting within max size are one group", + in: []*entryErr{buildEntry(10), buildEntry(10)}, + size: 20, + want: [][]*entryErr{{buildEntry(10), buildEntry(10)}}, + }, + { + desc: "entries each under max size and together over max size are grouped separately", + in: []*entryErr{buildEntry(10), buildEntry(10)}, + size: 15, + want: [][]*entryErr{{buildEntry(10)}, {buildEntry(10)}}, + }, + { + desc: "entries together over max size are grouped by max size", + in: []*entryErr{buildEntry(5), buildEntry(5), buildEntry(5)}, + size: 10, + want: [][]*entryErr{{buildEntry(5), buildEntry(5)}, {buildEntry(5)}}, + }, + { + desc: "one entry over max size and one entry under max size are two groups", + in: []*entryErr{buildEntry(15), buildEntry(5)}, + size: 10, + want: [][]*entryErr{{buildEntry(15)}, {buildEntry(5)}}, + }, + } + + for _, test := range tests { + if got, want := groupEntries(test.in, test.size), test.want; !cmp.Equal(mutationCounts(got), mutationCounts(want)) { + t.Errorf("[%s] want = %v, got = %v", test.desc, mutationCounts(want), mutationCounts(got)) + } + } +} + +func buildEntry(numMutations int) *entryErr { + var muts []*btpb.Mutation + for i := 0; i < numMutations; i++ { + muts = append(muts, &btpb.Mutation{}) + } + return &entryErr{Entry: &btpb.MutateRowsRequest_Entry{Mutations: muts}} +} + +func mutationCounts(batched [][]*entryErr) []int { + var res []int + for _, entries := range batched { + var count int + for _, e := range entries { + count += len(e.Entry.Mutations) + } + res = append(res, count) + } + return res +} + +func TestClientIntegration(t *testing.T) { + // TODO(jba): go1.9: Use subtests. + start := time.Now() + lastCheckpoint := start + checkpoint := func(s string) { + n := time.Now() + t.Logf("[%s] %v since start, %v since last checkpoint", s, n.Sub(start), n.Sub(lastCheckpoint)) + lastCheckpoint = n + } + + testEnv, err := NewIntegrationEnv() + if err != nil { + t.Fatalf("IntegrationEnv: %v", err) + } + + var timeout time.Duration + if testEnv.Config().UseProd { + timeout = 10 * time.Minute + t.Logf("Running test against production") + } else { + timeout = 1 * time.Minute + t.Logf("bttest.Server running on %s", testEnv.Config().AdminEndpoint) + } + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + client, err := testEnv.NewClient() + if err != nil { + t.Fatalf("Client: %v", err) + } + defer client.Close() + checkpoint("dialed Client") + + adminClient, err := testEnv.NewAdminClient() + if err != nil { + t.Fatalf("AdminClient: %v", err) + } + defer adminClient.Close() + checkpoint("dialed AdminClient") + + table := testEnv.Config().Table + + // Delete the table at the end of the test. + // Do this even before creating the table so that if this is running + // against production and CreateTable fails there's a chance of cleaning it up. + defer adminClient.DeleteTable(ctx, table) + + if err := adminClient.CreateTable(ctx, table); err != nil { + t.Fatalf("Creating table: %v", err) + } + checkpoint("created table") + if err := adminClient.CreateColumnFamily(ctx, table, "follows"); err != nil { + t.Fatalf("Creating column family: %v", err) + } + checkpoint(`created "follows" column family`) + + tbl := client.Open(table) + + // Insert some data. + initialData := map[string][]string{ + "wmckinley": {"tjefferson"}, + "gwashington": {"jadams"}, + "tjefferson": {"gwashington", "jadams"}, // wmckinley set conditionally below + "jadams": {"gwashington", "tjefferson"}, + } + for row, ss := range initialData { + mut := NewMutation() + for _, name := range ss { + mut.Set("follows", name, 1000, []byte("1")) + } + if err := tbl.Apply(ctx, row, mut); err != nil { + t.Errorf("Mutating row %q: %v", row, err) + } + } + checkpoint("inserted initial data") + + // TODO(igorbernstein): re-enable this when ready + //if err := adminClient.WaitForReplication(ctx, table); err != nil { + // t.Errorf("Waiting for replication for table %q: %v", table, err) + //} + //checkpoint("waited for replication") + + // Do a conditional mutation with a complex filter. + mutTrue := NewMutation() + mutTrue.Set("follows", "wmckinley", 1000, []byte("1")) + filter := ChainFilters(ColumnFilter("gwash[iz].*"), ValueFilter(".")) + mut := NewCondMutation(filter, mutTrue, nil) + if err := tbl.Apply(ctx, "tjefferson", mut); err != nil { + t.Errorf("Conditionally mutating row: %v", err) + } + // Do a second condition mutation with a filter that does not match, + // and thus no changes should be made. + mutTrue = NewMutation() + mutTrue.DeleteRow() + filter = ColumnFilter("snoop.dogg") + mut = NewCondMutation(filter, mutTrue, nil) + if err := tbl.Apply(ctx, "tjefferson", mut); err != nil { + t.Errorf("Conditionally mutating row: %v", err) + } + checkpoint("did two conditional mutations") + + // Fetch a row. + row, err := tbl.ReadRow(ctx, "jadams") + if err != nil { + t.Fatalf("Reading a row: %v", err) + } + wantRow := Row{ + "follows": []ReadItem{ + {Row: "jadams", Column: "follows:gwashington", Timestamp: 1000, Value: []byte("1")}, + {Row: "jadams", Column: "follows:tjefferson", Timestamp: 1000, Value: []byte("1")}, + }, + } + if !testutil.Equal(row, wantRow) { + t.Errorf("Read row mismatch.\n got %#v\nwant %#v", row, wantRow) + } + checkpoint("tested ReadRow") + + // Do a bunch of reads with filters. + readTests := []struct { + desc string + rr RowSet + filter Filter // may be nil + limit ReadOption // may be nil + + // We do the read, grab all the cells, turn them into "--", + // and join with a comma. + want string + }{ + { + desc: "read all, unfiltered", + rr: RowRange{}, + want: "gwashington-jadams-1,jadams-gwashington-1,jadams-tjefferson-1,tjefferson-gwashington-1,tjefferson-jadams-1,tjefferson-wmckinley-1,wmckinley-tjefferson-1", + }, + { + desc: "read with InfiniteRange, unfiltered", + rr: InfiniteRange("tjefferson"), + want: "tjefferson-gwashington-1,tjefferson-jadams-1,tjefferson-wmckinley-1,wmckinley-tjefferson-1", + }, + { + desc: "read with NewRange, unfiltered", + rr: NewRange("gargamel", "hubbard"), + want: "gwashington-jadams-1", + }, + { + desc: "read with PrefixRange, unfiltered", + rr: PrefixRange("jad"), + want: "jadams-gwashington-1,jadams-tjefferson-1", + }, + { + desc: "read with SingleRow, unfiltered", + rr: SingleRow("wmckinley"), + want: "wmckinley-tjefferson-1", + }, + { + desc: "read all, with ColumnFilter", + rr: RowRange{}, + filter: ColumnFilter(".*j.*"), // matches "jadams" and "tjefferson" + want: "gwashington-jadams-1,jadams-tjefferson-1,tjefferson-jadams-1,wmckinley-tjefferson-1", + }, + { + desc: "read all, with ColumnFilter, prefix", + rr: RowRange{}, + filter: ColumnFilter("j"), // no matches + want: "", + }, + { + desc: "read range, with ColumnRangeFilter", + rr: RowRange{}, + filter: ColumnRangeFilter("follows", "h", "k"), + want: "gwashington-jadams-1,tjefferson-jadams-1", + }, + { + desc: "read range from empty, with ColumnRangeFilter", + rr: RowRange{}, + filter: ColumnRangeFilter("follows", "", "u"), + want: "gwashington-jadams-1,jadams-gwashington-1,jadams-tjefferson-1,tjefferson-gwashington-1,tjefferson-jadams-1,wmckinley-tjefferson-1", + }, + { + desc: "read range from start to empty, with ColumnRangeFilter", + rr: RowRange{}, + filter: ColumnRangeFilter("follows", "h", ""), + want: "gwashington-jadams-1,jadams-tjefferson-1,tjefferson-jadams-1,tjefferson-wmckinley-1,wmckinley-tjefferson-1", + }, + { + desc: "read with RowKeyFilter", + rr: RowRange{}, + filter: RowKeyFilter(".*wash.*"), + want: "gwashington-jadams-1", + }, + { + desc: "read with RowKeyFilter, prefix", + rr: RowRange{}, + filter: RowKeyFilter("gwash"), + want: "", + }, + { + desc: "read with RowKeyFilter, no matches", + rr: RowRange{}, + filter: RowKeyFilter(".*xxx.*"), + want: "", + }, + { + desc: "read with FamilyFilter, no matches", + rr: RowRange{}, + filter: FamilyFilter(".*xxx.*"), + want: "", + }, + { + desc: "read with ColumnFilter + row limit", + rr: RowRange{}, + filter: ColumnFilter(".*j.*"), // matches "jadams" and "tjefferson" + limit: LimitRows(2), + want: "gwashington-jadams-1,jadams-tjefferson-1", + }, + { + desc: "read all, strip values", + rr: RowRange{}, + filter: StripValueFilter(), + want: "gwashington-jadams-,jadams-gwashington-,jadams-tjefferson-,tjefferson-gwashington-,tjefferson-jadams-,tjefferson-wmckinley-,wmckinley-tjefferson-", + }, + { + desc: "read with ColumnFilter + row limit + strip values", + rr: RowRange{}, + filter: ChainFilters(ColumnFilter(".*j.*"), StripValueFilter()), // matches "jadams" and "tjefferson" + limit: LimitRows(2), + want: "gwashington-jadams-,jadams-tjefferson-", + }, + { + desc: "read with condition, strip values on true", + rr: RowRange{}, + filter: ConditionFilter(ColumnFilter(".*j.*"), StripValueFilter(), nil), + want: "gwashington-jadams-,jadams-gwashington-,jadams-tjefferson-,tjefferson-gwashington-,tjefferson-jadams-,tjefferson-wmckinley-,wmckinley-tjefferson-", + }, + { + desc: "read with condition, strip values on false", + rr: RowRange{}, + filter: ConditionFilter(ColumnFilter(".*xxx.*"), nil, StripValueFilter()), + want: "gwashington-jadams-,jadams-gwashington-,jadams-tjefferson-,tjefferson-gwashington-,tjefferson-jadams-,tjefferson-wmckinley-,wmckinley-tjefferson-", + }, + { + desc: "read with ValueRangeFilter + row limit", + rr: RowRange{}, + filter: ValueRangeFilter([]byte("1"), []byte("5")), // matches our value of "1" + limit: LimitRows(2), + want: "gwashington-jadams-1,jadams-gwashington-1,jadams-tjefferson-1", + }, + { + desc: "read with ValueRangeFilter, no match on exclusive end", + rr: RowRange{}, + filter: ValueRangeFilter([]byte("0"), []byte("1")), // no match + want: "", + }, + { + desc: "read with ValueRangeFilter, no matches", + rr: RowRange{}, + filter: ValueRangeFilter([]byte("3"), []byte("5")), // matches nothing + want: "", + }, + { + desc: "read with InterleaveFilter, no matches on all filters", + rr: RowRange{}, + filter: InterleaveFilters(ColumnFilter(".*x.*"), ColumnFilter(".*z.*")), + want: "", + }, + { + desc: "read with InterleaveFilter, no duplicate cells", + rr: RowRange{}, + filter: InterleaveFilters(ColumnFilter(".*g.*"), ColumnFilter(".*j.*")), + want: "gwashington-jadams-1,jadams-gwashington-1,jadams-tjefferson-1,tjefferson-gwashington-1,tjefferson-jadams-1,wmckinley-tjefferson-1", + }, + { + desc: "read with InterleaveFilter, with duplicate cells", + rr: RowRange{}, + filter: InterleaveFilters(ColumnFilter(".*g.*"), ColumnFilter(".*g.*")), + want: "jadams-gwashington-1,jadams-gwashington-1,tjefferson-gwashington-1,tjefferson-gwashington-1", + }, + { + desc: "read with a RowRangeList and no filter", + rr: RowRangeList{NewRange("gargamel", "hubbard"), InfiniteRange("wmckinley")}, + want: "gwashington-jadams-1,wmckinley-tjefferson-1", + }, + { + desc: "chain that excludes rows and matches nothing, in a condition", + rr: RowRange{}, + filter: ConditionFilter(ChainFilters(ColumnFilter(".*j.*"), ColumnFilter(".*mckinley.*")), StripValueFilter(), nil), + want: "", + }, + { + desc: "chain that ends with an interleave that has no match. covers #804", + rr: RowRange{}, + filter: ConditionFilter(ChainFilters(ColumnFilter(".*j.*"), InterleaveFilters(ColumnFilter(".*x.*"), ColumnFilter(".*z.*"))), StripValueFilter(), nil), + want: "", + }, + } + for _, tc := range readTests { + var opts []ReadOption + if tc.filter != nil { + opts = append(opts, RowFilter(tc.filter)) + } + if tc.limit != nil { + opts = append(opts, tc.limit) + } + var elt []string + err := tbl.ReadRows(ctx, tc.rr, func(r Row) bool { + for _, ris := range r { + for _, ri := range ris { + elt = append(elt, formatReadItem(ri)) + } + } + return true + }, opts...) + if err != nil { + t.Errorf("%s: %v", tc.desc, err) + continue + } + if got := strings.Join(elt, ","); got != tc.want { + t.Errorf("%s: wrong reads.\n got %q\nwant %q", tc.desc, got, tc.want) + } + } + + // Read a RowList + var elt []string + keys := RowList{"wmckinley", "gwashington", "jadams"} + want := "gwashington-jadams-1,jadams-gwashington-1,jadams-tjefferson-1,wmckinley-tjefferson-1" + err = tbl.ReadRows(ctx, keys, func(r Row) bool { + for _, ris := range r { + for _, ri := range ris { + elt = append(elt, formatReadItem(ri)) + } + } + return true + }) + if err != nil { + t.Errorf("read RowList: %v", err) + } + + if got := strings.Join(elt, ","); got != want { + t.Errorf("bulk read: wrong reads.\n got %q\nwant %q", got, want) + } + checkpoint("tested ReadRows in a few ways") + + // Do a scan and stop part way through. + // Verify that the ReadRows callback doesn't keep running. + stopped := false + err = tbl.ReadRows(ctx, InfiniteRange(""), func(r Row) bool { + if r.Key() < "h" { + return true + } + if !stopped { + stopped = true + return false + } + t.Errorf("ReadRows kept scanning to row %q after being told to stop", r.Key()) + return false + }) + if err != nil { + t.Errorf("Partial ReadRows: %v", err) + } + checkpoint("did partial ReadRows test") + + // Delete a row and check it goes away. + mut = NewMutation() + mut.DeleteRow() + if err := tbl.Apply(ctx, "wmckinley", mut); err != nil { + t.Errorf("Apply DeleteRow: %v", err) + } + row, err = tbl.ReadRow(ctx, "wmckinley") + if err != nil { + t.Fatalf("Reading a row after DeleteRow: %v", err) + } + if len(row) != 0 { + t.Fatalf("Read non-zero row after DeleteRow: %v", row) + } + checkpoint("exercised DeleteRow") + + // Check ReadModifyWrite. + + if err := adminClient.CreateColumnFamily(ctx, table, "counter"); err != nil { + t.Fatalf("Creating column family: %v", err) + } + + appendRMW := func(b []byte) *ReadModifyWrite { + rmw := NewReadModifyWrite() + rmw.AppendValue("counter", "likes", b) + return rmw + } + incRMW := func(n int64) *ReadModifyWrite { + rmw := NewReadModifyWrite() + rmw.Increment("counter", "likes", n) + return rmw + } + rmwSeq := []struct { + desc string + rmw *ReadModifyWrite + want []byte + }{ + { + desc: "append #1", + rmw: appendRMW([]byte{0, 0, 0}), + want: []byte{0, 0, 0}, + }, + { + desc: "append #2", + rmw: appendRMW([]byte{0, 0, 0, 0, 17}), // the remaining 40 bits to make a big-endian 17 + want: []byte{0, 0, 0, 0, 0, 0, 0, 17}, + }, + { + desc: "increment", + rmw: incRMW(8), + want: []byte{0, 0, 0, 0, 0, 0, 0, 25}, + }, + } + for _, step := range rmwSeq { + row, err := tbl.ApplyReadModifyWrite(ctx, "gwashington", step.rmw) + if err != nil { + t.Fatalf("ApplyReadModifyWrite %+v: %v", step.rmw, err) + } + // Make sure the modified cell returned by the RMW operation has a timestamp. + if row["counter"][0].Timestamp == 0 { + t.Errorf("RMW returned cell timestamp: got %v, want > 0", row["counter"][0].Timestamp) + } + clearTimestamps(row) + wantRow := Row{"counter": []ReadItem{{Row: "gwashington", Column: "counter:likes", Value: step.want}}} + if !testutil.Equal(row, wantRow) { + t.Fatalf("After %s,\n got %v\nwant %v", step.desc, row, wantRow) + } + } + + // Check for google-cloud-go/issues/723. RMWs that insert new rows should keep row order sorted in the emulator. + _, err = tbl.ApplyReadModifyWrite(ctx, "issue-723-2", appendRMW([]byte{0})) + if err != nil { + t.Fatalf("ApplyReadModifyWrite null string: %v", err) + } + _, err = tbl.ApplyReadModifyWrite(ctx, "issue-723-1", appendRMW([]byte{0})) + if err != nil { + t.Fatalf("ApplyReadModifyWrite null string: %v", err) + } + // Get only the correct row back on read. + r, err := tbl.ReadRow(ctx, "issue-723-1") + if err != nil { + t.Fatalf("Reading row: %v", err) + } + if r.Key() != "issue-723-1" { + t.Errorf("ApplyReadModifyWrite: incorrect read after RMW,\n got %v\nwant %v", r.Key(), "issue-723-1") + } + checkpoint("tested ReadModifyWrite") + + // Test arbitrary timestamps more thoroughly. + if err := adminClient.CreateColumnFamily(ctx, table, "ts"); err != nil { + t.Fatalf("Creating column family: %v", err) + } + const numVersions = 4 + mut = NewMutation() + for i := 1; i < numVersions; i++ { + // Timestamps are used in thousands because the server + // only permits that granularity. + mut.Set("ts", "col", Timestamp(i*1000), []byte(fmt.Sprintf("val-%d", i))) + mut.Set("ts", "col2", Timestamp(i*1000), []byte(fmt.Sprintf("val-%d", i))) + } + if err := tbl.Apply(ctx, "testrow", mut); err != nil { + t.Fatalf("Mutating row: %v", err) + } + r, err = tbl.ReadRow(ctx, "testrow") + if err != nil { + t.Fatalf("Reading row: %v", err) + } + wantRow = Row{"ts": []ReadItem{ + // These should be returned in descending timestamp order. + {Row: "testrow", Column: "ts:col", Timestamp: 3000, Value: []byte("val-3")}, + {Row: "testrow", Column: "ts:col", Timestamp: 2000, Value: []byte("val-2")}, + {Row: "testrow", Column: "ts:col", Timestamp: 1000, Value: []byte("val-1")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 3000, Value: []byte("val-3")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 2000, Value: []byte("val-2")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 1000, Value: []byte("val-1")}, + }} + if !testutil.Equal(r, wantRow) { + t.Errorf("Cell with multiple versions,\n got %v\nwant %v", r, wantRow) + } + // Do the same read, but filter to the latest two versions. + r, err = tbl.ReadRow(ctx, "testrow", RowFilter(LatestNFilter(2))) + if err != nil { + t.Fatalf("Reading row: %v", err) + } + wantRow = Row{"ts": []ReadItem{ + {Row: "testrow", Column: "ts:col", Timestamp: 3000, Value: []byte("val-3")}, + {Row: "testrow", Column: "ts:col", Timestamp: 2000, Value: []byte("val-2")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 3000, Value: []byte("val-3")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 2000, Value: []byte("val-2")}, + }} + if !testutil.Equal(r, wantRow) { + t.Errorf("Cell with multiple versions and LatestNFilter(2),\n got %v\nwant %v", r, wantRow) + } + // Check cell offset / limit + r, err = tbl.ReadRow(ctx, "testrow", RowFilter(CellsPerRowLimitFilter(3))) + if err != nil { + t.Fatalf("Reading row: %v", err) + } + wantRow = Row{"ts": []ReadItem{ + {Row: "testrow", Column: "ts:col", Timestamp: 3000, Value: []byte("val-3")}, + {Row: "testrow", Column: "ts:col", Timestamp: 2000, Value: []byte("val-2")}, + {Row: "testrow", Column: "ts:col", Timestamp: 1000, Value: []byte("val-1")}, + }} + if !testutil.Equal(r, wantRow) { + t.Errorf("Cell with multiple versions and CellsPerRowLimitFilter(3),\n got %v\nwant %v", r, wantRow) + } + r, err = tbl.ReadRow(ctx, "testrow", RowFilter(CellsPerRowOffsetFilter(3))) + if err != nil { + t.Fatalf("Reading row: %v", err) + } + wantRow = Row{"ts": []ReadItem{ + {Row: "testrow", Column: "ts:col2", Timestamp: 3000, Value: []byte("val-3")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 2000, Value: []byte("val-2")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 1000, Value: []byte("val-1")}, + }} + if !testutil.Equal(r, wantRow) { + t.Errorf("Cell with multiple versions and CellsPerRowOffsetFilter(3),\n got %v\nwant %v", r, wantRow) + } + // Check timestamp range filtering (with truncation) + r, err = tbl.ReadRow(ctx, "testrow", RowFilter(TimestampRangeFilterMicros(1001, 3000))) + if err != nil { + t.Fatalf("Reading row: %v", err) + } + wantRow = Row{"ts": []ReadItem{ + {Row: "testrow", Column: "ts:col", Timestamp: 2000, Value: []byte("val-2")}, + {Row: "testrow", Column: "ts:col", Timestamp: 1000, Value: []byte("val-1")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 2000, Value: []byte("val-2")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 1000, Value: []byte("val-1")}, + }} + if !testutil.Equal(r, wantRow) { + t.Errorf("Cell with multiple versions and TimestampRangeFilter(1000, 3000),\n got %v\nwant %v", r, wantRow) + } + r, err = tbl.ReadRow(ctx, "testrow", RowFilter(TimestampRangeFilterMicros(1000, 0))) + if err != nil { + t.Fatalf("Reading row: %v", err) + } + wantRow = Row{"ts": []ReadItem{ + {Row: "testrow", Column: "ts:col", Timestamp: 3000, Value: []byte("val-3")}, + {Row: "testrow", Column: "ts:col", Timestamp: 2000, Value: []byte("val-2")}, + {Row: "testrow", Column: "ts:col", Timestamp: 1000, Value: []byte("val-1")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 3000, Value: []byte("val-3")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 2000, Value: []byte("val-2")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 1000, Value: []byte("val-1")}, + }} + if !testutil.Equal(r, wantRow) { + t.Errorf("Cell with multiple versions and TimestampRangeFilter(1000, 0),\n got %v\nwant %v", r, wantRow) + } + // Delete non-existing cells, no such column family in this row + // Should not delete anything + if err := adminClient.CreateColumnFamily(ctx, table, "non-existing"); err != nil { + t.Fatalf("Creating column family: %v", err) + } + mut = NewMutation() + mut.DeleteTimestampRange("non-existing", "col", 2000, 3000) // half-open interval + if err := tbl.Apply(ctx, "testrow", mut); err != nil { + t.Fatalf("Mutating row: %v", err) + } + r, err = tbl.ReadRow(ctx, "testrow", RowFilter(LatestNFilter(3))) + if err != nil { + t.Fatalf("Reading row: %v", err) + } + if !testutil.Equal(r, wantRow) { + t.Errorf("Cell was deleted unexpectly,\n got %v\nwant %v", r, wantRow) + } + // Delete non-existing cells, no such column in this column family + // Should not delete anything + mut = NewMutation() + mut.DeleteTimestampRange("ts", "non-existing", 2000, 3000) // half-open interval + if err := tbl.Apply(ctx, "testrow", mut); err != nil { + t.Fatalf("Mutating row: %v", err) + } + r, err = tbl.ReadRow(ctx, "testrow", RowFilter(LatestNFilter(3))) + if err != nil { + t.Fatalf("Reading row: %v", err) + } + if !testutil.Equal(r, wantRow) { + t.Errorf("Cell was deleted unexpectly,\n got %v\nwant %v", r, wantRow) + } + // Delete the cell with timestamp 2000 and repeat the last read, + // checking that we get ts 3000 and ts 1000. + mut = NewMutation() + mut.DeleteTimestampRange("ts", "col", 2001, 3000) // half-open interval + if err := tbl.Apply(ctx, "testrow", mut); err != nil { + t.Fatalf("Mutating row: %v", err) + } + r, err = tbl.ReadRow(ctx, "testrow", RowFilter(LatestNFilter(2))) + if err != nil { + t.Fatalf("Reading row: %v", err) + } + wantRow = Row{"ts": []ReadItem{ + {Row: "testrow", Column: "ts:col", Timestamp: 3000, Value: []byte("val-3")}, + {Row: "testrow", Column: "ts:col", Timestamp: 1000, Value: []byte("val-1")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 3000, Value: []byte("val-3")}, + {Row: "testrow", Column: "ts:col2", Timestamp: 2000, Value: []byte("val-2")}, + }} + if !testutil.Equal(r, wantRow) { + t.Errorf("Cell with multiple versions and LatestNFilter(2), after deleting timestamp 2000,\n got %v\nwant %v", r, wantRow) + } + checkpoint("tested multiple versions in a cell") + + // Check DeleteCellsInFamily + if err := adminClient.CreateColumnFamily(ctx, table, "status"); err != nil { + t.Fatalf("Creating column family: %v", err) + } + + mut = NewMutation() + mut.Set("status", "start", 2000, []byte("2")) + mut.Set("status", "end", 3000, []byte("3")) + mut.Set("ts", "col", 1000, []byte("1")) + if err := tbl.Apply(ctx, "row1", mut); err != nil { + t.Errorf("Mutating row: %v", err) + } + if err := tbl.Apply(ctx, "row2", mut); err != nil { + t.Errorf("Mutating row: %v", err) + } + + mut = NewMutation() + mut.DeleteCellsInFamily("status") + if err := tbl.Apply(ctx, "row1", mut); err != nil { + t.Errorf("Delete cf: %v", err) + } + + // ColumnFamily removed + r, err = tbl.ReadRow(ctx, "row1") + if err != nil { + t.Fatalf("Reading row: %v", err) + } + wantRow = Row{"ts": []ReadItem{ + {Row: "row1", Column: "ts:col", Timestamp: 1000, Value: []byte("1")}, + }} + if !testutil.Equal(r, wantRow) { + t.Errorf("column family was not deleted.\n got %v\n want %v", r, wantRow) + } + + // ColumnFamily not removed + r, err = tbl.ReadRow(ctx, "row2") + if err != nil { + t.Fatalf("Reading row: %v", err) + } + wantRow = Row{ + "ts": []ReadItem{ + {Row: "row2", Column: "ts:col", Timestamp: 1000, Value: []byte("1")}, + }, + "status": []ReadItem{ + {Row: "row2", Column: "status:end", Timestamp: 3000, Value: []byte("3")}, + {Row: "row2", Column: "status:start", Timestamp: 2000, Value: []byte("2")}, + }, + } + if !testutil.Equal(r, wantRow) { + t.Errorf("Column family was deleted unexpectly.\n got %v\n want %v", r, wantRow) + } + checkpoint("tested family delete") + + // Check DeleteCellsInColumn + mut = NewMutation() + mut.Set("status", "start", 2000, []byte("2")) + mut.Set("status", "middle", 3000, []byte("3")) + mut.Set("status", "end", 1000, []byte("1")) + if err := tbl.Apply(ctx, "row3", mut); err != nil { + t.Errorf("Mutating row: %v", err) + } + mut = NewMutation() + mut.DeleteCellsInColumn("status", "middle") + if err := tbl.Apply(ctx, "row3", mut); err != nil { + t.Errorf("Delete column: %v", err) + } + r, err = tbl.ReadRow(ctx, "row3") + if err != nil { + t.Fatalf("Reading row: %v", err) + } + wantRow = Row{ + "status": []ReadItem{ + {Row: "row3", Column: "status:end", Timestamp: 1000, Value: []byte("1")}, + {Row: "row3", Column: "status:start", Timestamp: 2000, Value: []byte("2")}, + }, + } + if !testutil.Equal(r, wantRow) { + t.Errorf("Column was not deleted.\n got %v\n want %v", r, wantRow) + } + mut = NewMutation() + mut.DeleteCellsInColumn("status", "start") + if err := tbl.Apply(ctx, "row3", mut); err != nil { + t.Errorf("Delete column: %v", err) + } + r, err = tbl.ReadRow(ctx, "row3") + if err != nil { + t.Fatalf("Reading row: %v", err) + } + wantRow = Row{ + "status": []ReadItem{ + {Row: "row3", Column: "status:end", Timestamp: 1000, Value: []byte("1")}, + }, + } + if !testutil.Equal(r, wantRow) { + t.Errorf("Column was not deleted.\n got %v\n want %v", r, wantRow) + } + mut = NewMutation() + mut.DeleteCellsInColumn("status", "end") + if err := tbl.Apply(ctx, "row3", mut); err != nil { + t.Errorf("Delete column: %v", err) + } + r, err = tbl.ReadRow(ctx, "row3") + if err != nil { + t.Fatalf("Reading row: %v", err) + } + if len(r) != 0 { + t.Errorf("Delete column: got %v, want empty row", r) + } + // Add same cell after delete + mut = NewMutation() + mut.Set("status", "end", 1000, []byte("1")) + if err := tbl.Apply(ctx, "row3", mut); err != nil { + t.Errorf("Mutating row: %v", err) + } + r, err = tbl.ReadRow(ctx, "row3") + if err != nil { + t.Fatalf("Reading row: %v", err) + } + if !testutil.Equal(r, wantRow) { + t.Errorf("Column was not deleted correctly.\n got %v\n want %v", r, wantRow) + } + checkpoint("tested column delete") + + // Do highly concurrent reads/writes. + // TODO(dsymonds): Raise this to 1000 when https://github.com/grpc/grpc-go/issues/205 is resolved. + const maxConcurrency = 100 + var wg sync.WaitGroup + for i := 0; i < maxConcurrency; i++ { + wg.Add(1) + go func() { + defer wg.Done() + switch r := rand.Intn(100); { // r ∈ [0,100) + case 0 <= r && r < 30: + // Do a read. + _, err := tbl.ReadRow(ctx, "testrow", RowFilter(LatestNFilter(1))) + if err != nil { + t.Errorf("Concurrent read: %v", err) + } + case 30 <= r && r < 100: + // Do a write. + mut := NewMutation() + mut.Set("ts", "col", 1000, []byte("data")) + if err := tbl.Apply(ctx, "testrow", mut); err != nil { + t.Errorf("Concurrent write: %v", err) + } + } + }() + } + wg.Wait() + checkpoint("tested high concurrency") + + // Large reads, writes and scans. + bigBytes := make([]byte, 5<<20) // 5 MB is larger than current default gRPC max of 4 MB, but less than the max we set. + nonsense := []byte("lorem ipsum dolor sit amet, ") + fill(bigBytes, nonsense) + mut = NewMutation() + mut.Set("ts", "col", 1000, bigBytes) + if err := tbl.Apply(ctx, "bigrow", mut); err != nil { + t.Errorf("Big write: %v", err) + } + r, err = tbl.ReadRow(ctx, "bigrow") + if err != nil { + t.Errorf("Big read: %v", err) + } + wantRow = Row{"ts": []ReadItem{ + {Row: "bigrow", Column: "ts:col", Timestamp: 1000, Value: bigBytes}, + }} + if !testutil.Equal(r, wantRow) { + t.Errorf("Big read returned incorrect bytes: %v", r) + } + // Now write 1000 rows, each with 82 KB values, then scan them all. + medBytes := make([]byte, 82<<10) + fill(medBytes, nonsense) + sem := make(chan int, 50) // do up to 50 mutations at a time. + for i := 0; i < 1000; i++ { + mut := NewMutation() + mut.Set("ts", "big-scan", 1000, medBytes) + row := fmt.Sprintf("row-%d", i) + wg.Add(1) + go func() { + defer wg.Done() + defer func() { <-sem }() + sem <- 1 + if err := tbl.Apply(ctx, row, mut); err != nil { + t.Errorf("Preparing large scan: %v", err) + } + }() + } + wg.Wait() + n := 0 + err = tbl.ReadRows(ctx, PrefixRange("row-"), func(r Row) bool { + for _, ris := range r { + for _, ri := range ris { + n += len(ri.Value) + } + } + return true + }, RowFilter(ColumnFilter("big-scan"))) + if err != nil { + t.Errorf("Doing large scan: %v", err) + } + if want := 1000 * len(medBytes); n != want { + t.Errorf("Large scan returned %d bytes, want %d", n, want) + } + // Scan a subset of the 1000 rows that we just created, using a LimitRows ReadOption. + rc := 0 + wantRc := 3 + err = tbl.ReadRows(ctx, PrefixRange("row-"), func(r Row) bool { + rc++ + return true + }, LimitRows(int64(wantRc))) + if err != nil { + t.Fatal(err) + } + if rc != wantRc { + t.Errorf("Scan with row limit returned %d rows, want %d", rc, wantRc) + } + checkpoint("tested big read/write/scan") + + // Test bulk mutations + if err := adminClient.CreateColumnFamily(ctx, table, "bulk"); err != nil { + t.Fatalf("Creating column family: %v", err) + } + bulkData := map[string][]string{ + "red sox": {"2004", "2007", "2013"}, + "patriots": {"2001", "2003", "2004", "2014"}, + "celtics": {"1981", "1984", "1986", "2008"}, + } + var rowKeys []string + var muts []*Mutation + for row, ss := range bulkData { + mut := NewMutation() + for _, name := range ss { + mut.Set("bulk", name, 1000, []byte("1")) + } + rowKeys = append(rowKeys, row) + muts = append(muts, mut) + } + status, err := tbl.ApplyBulk(ctx, rowKeys, muts) + if err != nil { + t.Fatalf("Bulk mutating rows %q: %v", rowKeys, err) + } + if status != nil { + t.Errorf("non-nil errors: %v", err) + } + checkpoint("inserted bulk data") + + // Read each row back + for rowKey, ss := range bulkData { + row, err := tbl.ReadRow(ctx, rowKey) + if err != nil { + t.Fatalf("Reading a bulk row: %v", err) + } + var wantItems []ReadItem + for _, val := range ss { + wantItems = append(wantItems, ReadItem{Row: rowKey, Column: "bulk:" + val, Timestamp: 1000, Value: []byte("1")}) + } + wantRow := Row{"bulk": wantItems} + if !testutil.Equal(row, wantRow) { + t.Errorf("Read row mismatch.\n got %#v\nwant %#v", row, wantRow) + } + } + checkpoint("tested reading from bulk insert") + + // Test bulk write errors. + // Note: Setting timestamps as ServerTime makes sure the mutations are not retried on error. + badMut := NewMutation() + badMut.Set("badfamily", "col", ServerTime, nil) + badMut2 := NewMutation() + badMut2.Set("badfamily2", "goodcol", ServerTime, []byte("1")) + status, err = tbl.ApplyBulk(ctx, []string{"badrow", "badrow2"}, []*Mutation{badMut, badMut2}) + if err != nil { + t.Fatalf("Bulk mutating rows %q: %v", rowKeys, err) + } + if status == nil { + t.Errorf("No errors for bad bulk mutation") + } else if status[0] == nil || status[1] == nil { + t.Errorf("No error for bad bulk mutation") + } +} + +type requestCountingInterceptor struct { + grpc.ClientStream + requestCallback func() +} + +func (i *requestCountingInterceptor) SendMsg(m interface{}) error { + i.requestCallback() + return i.ClientStream.SendMsg(m) +} + +func (i *requestCountingInterceptor) RecvMsg(m interface{}) error { + return i.ClientStream.RecvMsg(m) +} + +func requestCallback(callback func()) func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { + return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { + clientStream, err := streamer(ctx, desc, cc, method, opts...) + return &requestCountingInterceptor{ + ClientStream: clientStream, + requestCallback: callback, + }, err + } +} + +// TestReadRowsInvalidRowSet verifies that the client doesn't send ReadRows() requests with invalid RowSets. +func TestReadRowsInvalidRowSet(t *testing.T) { + testEnv, err := NewEmulatedEnv(IntegrationTestConfig{}) + if err != nil { + t.Fatalf("NewEmulatedEnv failed: %v", err) + } + var requestCount int + incrementRequestCount := func() { requestCount++ } + conn, err := grpc.Dial(testEnv.server.Addr, grpc.WithInsecure(), grpc.WithBlock(), + grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(100<<20), grpc.MaxCallRecvMsgSize(100<<20)), + grpc.WithStreamInterceptor(requestCallback(incrementRequestCount)), + ) + if err != nil { + t.Fatalf("grpc.Dial failed: %v", err) + } + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + defer cancel() + adminClient, err := NewAdminClient(ctx, testEnv.config.Project, testEnv.config.Instance, option.WithGRPCConn(conn)) + if err != nil { + t.Fatalf("NewClient failed: %v", err) + } + defer adminClient.Close() + if err := adminClient.CreateTable(ctx, testEnv.config.Table); err != nil { + t.Fatalf("CreateTable(%v) failed: %v", testEnv.config.Table, err) + } + client, err := NewClient(ctx, testEnv.config.Project, testEnv.config.Instance, option.WithGRPCConn(conn)) + if err != nil { + t.Fatalf("NewClient failed: %v", err) + } + defer client.Close() + table := client.Open(testEnv.config.Table) + tests := []struct { + rr RowSet + valid bool + }{ + { + rr: RowRange{}, + valid: true, + }, + { + rr: RowRange{start: "b"}, + valid: true, + }, + { + rr: RowRange{start: "b", limit: "c"}, + valid: true, + }, + { + rr: RowRange{start: "b", limit: "a"}, + valid: false, + }, + { + rr: RowList{"a"}, + valid: true, + }, + { + rr: RowList{}, + valid: false, + }, + } + for _, test := range tests { + requestCount = 0 + err = table.ReadRows(ctx, test.rr, func(r Row) bool { return true }) + if err != nil { + t.Fatalf("ReadRows(%v) failed: %v", test.rr, err) + } + requestValid := requestCount != 0 + if requestValid != test.valid { + t.Errorf("%s: got %v, want %v", test.rr, requestValid, test.valid) + } + } +} + +func formatReadItem(ri ReadItem) string { + // Use the column qualifier only to make the test data briefer. + col := ri.Column[strings.Index(ri.Column, ":")+1:] + return fmt.Sprintf("%s-%s-%s", ri.Row, col, ri.Value) +} + +func fill(b, sub []byte) { + for len(b) > len(sub) { + n := copy(b, sub) + b = b[n:] + } +} + +func clearTimestamps(r Row) { + for _, ris := range r { + for i := range ris { + ris[i].Timestamp = 0 + } + } +} + +func TestSampleRowKeys(t *testing.T) { + start := time.Now() + lastCheckpoint := start + checkpoint := func(s string) { + n := time.Now() + t.Logf("[%s] %v since start, %v since last checkpoint", s, n.Sub(start), n.Sub(lastCheckpoint)) + lastCheckpoint = n + } + ctx := context.Background() + client, adminClient, table, err := doSetup(ctx) + if err != nil { + t.Fatalf("%v", err) + } + defer client.Close() + defer adminClient.Close() + tbl := client.Open(table) + // Delete the table at the end of the test. + // Do this even before creating the table so that if this is running + // against production and CreateTable fails there's a chance of cleaning it up. + defer adminClient.DeleteTable(ctx, table) + + // Insert some data. + initialData := map[string][]string{ + "wmckinley11": {"tjefferson11"}, + "gwashington77": {"jadams77"}, + "tjefferson0": {"gwashington0", "jadams0"}, + } + + for row, ss := range initialData { + mut := NewMutation() + for _, name := range ss { + mut.Set("follows", name, 1000, []byte("1")) + } + if err := tbl.Apply(ctx, row, mut); err != nil { + t.Errorf("Mutating row %q: %v", row, err) + } + } + checkpoint("inserted initial data") + sampleKeys, err := tbl.SampleRowKeys(context.Background()) + if err != nil { + t.Errorf("%s: %v", "SampleRowKeys:", err) + } + if len(sampleKeys) == 0 { + t.Error("SampleRowKeys length 0") + } + checkpoint("tested SampleRowKeys.") +} + +func doSetup(ctx context.Context) (*Client, *AdminClient, string, error) { + start := time.Now() + lastCheckpoint := start + checkpoint := func(s string) { + n := time.Now() + fmt.Printf("[%s] %v since start, %v since last checkpoint", s, n.Sub(start), n.Sub(lastCheckpoint)) + lastCheckpoint = n + } + + testEnv, err := NewIntegrationEnv() + if err != nil { + return nil, nil, "", fmt.Errorf("IntegrationEnv: %v", err) + } + + var timeout time.Duration + if testEnv.Config().UseProd { + timeout = 10 * time.Minute + fmt.Printf("Running test against production") + } else { + timeout = 1 * time.Minute + fmt.Printf("bttest.Server running on %s", testEnv.Config().AdminEndpoint) + } + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + client, err := testEnv.NewClient() + if err != nil { + return nil, nil, "", fmt.Errorf("Client: %v", err) + } + checkpoint("dialed Client") + + adminClient, err := testEnv.NewAdminClient() + if err != nil { + return nil, nil, "", fmt.Errorf("AdminClient: %v", err) + } + checkpoint("dialed AdminClient") + + table := testEnv.Config().Table + if err := adminClient.CreateTable(ctx, table); err != nil { + return nil, nil, "", fmt.Errorf("Creating table: %v", err) + } + checkpoint("created table") + if err := adminClient.CreateColumnFamily(ctx, table, "follows"); err != nil { + return nil, nil, "", fmt.Errorf("Creating column family: %v", err) + } + checkpoint(`created "follows" column family`) + + return client, adminClient, table, nil +} diff --git a/vendor/cloud.google.com/go/bigtable/bttest/example_test.go b/vendor/cloud.google.com/go/bigtable/bttest/example_test.go new file mode 100644 index 00000000..6348c7c4 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/bttest/example_test.go @@ -0,0 +1,83 @@ +/* +Copyright 2016 Google LLC + +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 bttest_test + +import ( + "context" + "fmt" + "log" + + "cloud.google.com/go/bigtable" + "cloud.google.com/go/bigtable/bttest" + "google.golang.org/api/option" + "google.golang.org/grpc" +) + +func ExampleNewServer() { + + srv, err := bttest.NewServer("localhost:0") + + if err != nil { + log.Fatalln(err) + } + + ctx := context.Background() + + conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure()) + if err != nil { + log.Fatalln(err) + } + + proj, instance := "proj", "instance" + + adminClient, err := bigtable.NewAdminClient(ctx, proj, instance, option.WithGRPCConn(conn)) + if err != nil { + log.Fatalln(err) + } + + if err = adminClient.CreateTable(ctx, "example"); err != nil { + log.Fatalln(err) + } + + if err = adminClient.CreateColumnFamily(ctx, "example", "links"); err != nil { + log.Fatalln(err) + } + + client, err := bigtable.NewClient(ctx, proj, instance, option.WithGRPCConn(conn)) + if err != nil { + log.Fatalln(err) + } + tbl := client.Open("example") + + mut := bigtable.NewMutation() + mut.Set("links", "golang.org", bigtable.Now(), []byte("Gophers!")) + if err = tbl.Apply(ctx, "com.google.cloud", mut); err != nil { + log.Fatalln(err) + } + + if row, err := tbl.ReadRow(ctx, "com.google.cloud"); err != nil { + log.Fatalln(err) + } else { + for _, column := range row["links"] { + fmt.Println(column.Column) + fmt.Println(string(column.Value)) + } + } + + // Output: + // links:golang.org + // Gophers! +} diff --git a/vendor/cloud.google.com/go/bigtable/bttest/inmem.go b/vendor/cloud.google.com/go/bigtable/bttest/inmem.go new file mode 100644 index 00000000..81bcf4ef --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/bttest/inmem.go @@ -0,0 +1,1400 @@ +/* +Copyright 2015 Google LLC + +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 bttest contains test helpers for working with the bigtable package. + +To use a Server, create it, and then connect to it with no security: +(The project/instance values are ignored.) + srv, err := bttest.NewServer("localhost:0") + ... + conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure()) + ... + client, err := bigtable.NewClient(ctx, proj, instance, + option.WithGRPCConn(conn)) + ... +*/ +package bttest // import "cloud.google.com/go/bigtable/bttest" + +import ( + "bytes" + "context" + "encoding/binary" + "fmt" + "log" + "math/rand" + "net" + "regexp" + "sort" + "strings" + "sync" + "time" + + emptypb "github.com/golang/protobuf/ptypes/empty" + "github.com/golang/protobuf/ptypes/wrappers" + "github.com/google/btree" + btapb "google.golang.org/genproto/googleapis/bigtable/admin/v2" + btpb "google.golang.org/genproto/googleapis/bigtable/v2" + "google.golang.org/genproto/googleapis/longrunning" + statpb "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const ( + // MilliSeconds field of the minimum valid Timestamp. + minValidMilliSeconds = 0 + + // MilliSeconds field of the max valid Timestamp. + maxValidMilliSeconds = int64(time.Millisecond) * 253402300800 +) + +var ( + validLabelTransformer = regexp.MustCompile(`[a-z0-9\-]{1,15}`) +) + +// Server is an in-memory Cloud Bigtable fake. +// It is unauthenticated, and only a rough approximation. +type Server struct { + Addr string + + l net.Listener + srv *grpc.Server + s *server +} + +// server is the real implementation of the fake. +// It is a separate and unexported type so the API won't be cluttered with +// methods that are only relevant to the fake's implementation. +type server struct { + mu sync.Mutex + tables map[string]*table // keyed by fully qualified name + gcc chan int // set when gcloop starts, closed when server shuts down + + // Any unimplemented methods will cause a panic. + btapb.BigtableTableAdminServer + btpb.BigtableServer +} + +// NewServer creates a new Server. +// The Server will be listening for gRPC connections, without TLS, +// on the provided address. The resolved address is named by the Addr field. +func NewServer(laddr string, opt ...grpc.ServerOption) (*Server, error) { + l, err := net.Listen("tcp", laddr) + if err != nil { + return nil, err + } + + s := &Server{ + Addr: l.Addr().String(), + l: l, + srv: grpc.NewServer(opt...), + s: &server{ + tables: make(map[string]*table), + }, + } + btapb.RegisterBigtableTableAdminServer(s.srv, s.s) + btpb.RegisterBigtableServer(s.srv, s.s) + + go s.srv.Serve(s.l) + + return s, nil +} + +// Close shuts down the server. +func (s *Server) Close() { + s.s.mu.Lock() + if s.s.gcc != nil { + close(s.s.gcc) + } + s.s.mu.Unlock() + + s.srv.Stop() + s.l.Close() +} + +func (s *server) CreateTable(ctx context.Context, req *btapb.CreateTableRequest) (*btapb.Table, error) { + tbl := req.Parent + "/tables/" + req.TableId + + s.mu.Lock() + if _, ok := s.tables[tbl]; ok { + s.mu.Unlock() + return nil, status.Errorf(codes.AlreadyExists, "table %q already exists", tbl) + } + s.tables[tbl] = newTable(req) + s.mu.Unlock() + + return &btapb.Table{Name: tbl}, nil +} + +func (s *server) CreateTableFromSnapshot(context.Context, *btapb.CreateTableFromSnapshotRequest) (*longrunning.Operation, error) { + return nil, status.Errorf(codes.Unimplemented, "the emulator does not currently support snapshots") +} + +func (s *server) ListTables(ctx context.Context, req *btapb.ListTablesRequest) (*btapb.ListTablesResponse, error) { + res := &btapb.ListTablesResponse{} + prefix := req.Parent + "/tables/" + + s.mu.Lock() + for tbl := range s.tables { + if strings.HasPrefix(tbl, prefix) { + res.Tables = append(res.Tables, &btapb.Table{Name: tbl}) + } + } + s.mu.Unlock() + + return res, nil +} + +func (s *server) GetTable(ctx context.Context, req *btapb.GetTableRequest) (*btapb.Table, error) { + tbl := req.Name + + s.mu.Lock() + tblIns, ok := s.tables[tbl] + s.mu.Unlock() + if !ok { + return nil, status.Errorf(codes.NotFound, "table %q not found", tbl) + } + + return &btapb.Table{ + Name: tbl, + ColumnFamilies: toColumnFamilies(tblIns.columnFamilies()), + }, nil +} + +func (s *server) DeleteTable(ctx context.Context, req *btapb.DeleteTableRequest) (*emptypb.Empty, error) { + s.mu.Lock() + defer s.mu.Unlock() + if _, ok := s.tables[req.Name]; !ok { + return nil, status.Errorf(codes.NotFound, "table %q not found", req.Name) + } + delete(s.tables, req.Name) + return &emptypb.Empty{}, nil +} + +func (s *server) ModifyColumnFamilies(ctx context.Context, req *btapb.ModifyColumnFamiliesRequest) (*btapb.Table, error) { + s.mu.Lock() + tbl, ok := s.tables[req.Name] + s.mu.Unlock() + if !ok { + return nil, status.Errorf(codes.NotFound, "table %q not found", req.Name) + } + + tbl.mu.Lock() + defer tbl.mu.Unlock() + + for _, mod := range req.Modifications { + if create := mod.GetCreate(); create != nil { + if _, ok := tbl.families[mod.Id]; ok { + return nil, status.Errorf(codes.AlreadyExists, "family %q already exists", mod.Id) + } + newcf := &columnFamily{ + name: req.Name + "/columnFamilies/" + mod.Id, + order: tbl.counter, + gcRule: create.GcRule, + } + tbl.counter++ + tbl.families[mod.Id] = newcf + } else if mod.GetDrop() { + if _, ok := tbl.families[mod.Id]; !ok { + return nil, fmt.Errorf("can't delete unknown family %q", mod.Id) + } + delete(tbl.families, mod.Id) + } else if modify := mod.GetUpdate(); modify != nil { + if _, ok := tbl.families[mod.Id]; !ok { + return nil, fmt.Errorf("no such family %q", mod.Id) + } + newcf := &columnFamily{ + name: req.Name + "/columnFamilies/" + mod.Id, + gcRule: modify.GcRule, + } + // assume that we ALWAYS want to replace by the new setting + // we may need partial update through + tbl.families[mod.Id] = newcf + } + } + + s.needGC() + return &btapb.Table{ + Name: req.Name, + ColumnFamilies: toColumnFamilies(tbl.families), + Granularity: btapb.Table_TimestampGranularity(btapb.Table_MILLIS), + }, nil +} + +func (s *server) DropRowRange(ctx context.Context, req *btapb.DropRowRangeRequest) (*emptypb.Empty, error) { + s.mu.Lock() + defer s.mu.Unlock() + tbl, ok := s.tables[req.Name] + if !ok { + return nil, status.Errorf(codes.NotFound, "table %q not found", req.Name) + } + + if req.GetDeleteAllDataFromTable() { + tbl.rows = btree.New(btreeDegree) + } else { + // Delete rows by prefix. + prefixBytes := req.GetRowKeyPrefix() + if prefixBytes == nil { + return nil, fmt.Errorf("missing row key prefix") + } + prefix := string(prefixBytes) + + // The BTree does not specify what happens if rows are deleted during + // iteration, and it provides no "delete range" method. + // So we collect the rows first, then delete them one by one. + var rowsToDelete []*row + tbl.rows.AscendGreaterOrEqual(btreeKey(prefix), func(i btree.Item) bool { + r := i.(*row) + if strings.HasPrefix(r.key, prefix) { + rowsToDelete = append(rowsToDelete, r) + return true + } + return false // stop iteration + }) + for _, r := range rowsToDelete { + tbl.rows.Delete(r) + } + } + return &emptypb.Empty{}, nil +} + +func (s *server) GenerateConsistencyToken(ctx context.Context, req *btapb.GenerateConsistencyTokenRequest) (*btapb.GenerateConsistencyTokenResponse, error) { + // Check that the table exists. + _, ok := s.tables[req.Name] + if !ok { + return nil, status.Errorf(codes.NotFound, "table %q not found", req.Name) + } + + return &btapb.GenerateConsistencyTokenResponse{ + ConsistencyToken: "TokenFor-" + req.Name, + }, nil +} + +func (s *server) CheckConsistency(ctx context.Context, req *btapb.CheckConsistencyRequest) (*btapb.CheckConsistencyResponse, error) { + // Check that the table exists. + _, ok := s.tables[req.Name] + if !ok { + return nil, status.Errorf(codes.NotFound, "table %q not found", req.Name) + } + + // Check this is the right token. + if req.ConsistencyToken != "TokenFor-"+req.Name { + return nil, status.Errorf(codes.InvalidArgument, "token %q not valid", req.ConsistencyToken) + } + + // Single cluster instances are always consistent. + return &btapb.CheckConsistencyResponse{ + Consistent: true, + }, nil +} + +func (s *server) SnapshotTable(context.Context, *btapb.SnapshotTableRequest) (*longrunning.Operation, error) { + return nil, status.Errorf(codes.Unimplemented, "the emulator does not currently support snapshots") +} + +func (s *server) GetSnapshot(context.Context, *btapb.GetSnapshotRequest) (*btapb.Snapshot, error) { + return nil, status.Errorf(codes.Unimplemented, "the emulator does not currently support snapshots") +} +func (s *server) ListSnapshots(context.Context, *btapb.ListSnapshotsRequest) (*btapb.ListSnapshotsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "the emulator does not currently support snapshots") +} +func (s *server) DeleteSnapshot(context.Context, *btapb.DeleteSnapshotRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "the emulator does not currently support snapshots") +} + +func (s *server) ReadRows(req *btpb.ReadRowsRequest, stream btpb.Bigtable_ReadRowsServer) error { + s.mu.Lock() + tbl, ok := s.tables[req.TableName] + s.mu.Unlock() + if !ok { + return status.Errorf(codes.NotFound, "table %q not found", req.TableName) + } + + // Rows to read can be specified by a set of row keys and/or a set of row ranges. + // Output is a stream of sorted, de-duped rows. + tbl.mu.RLock() + rowSet := make(map[string]*row) + + addRow := func(i btree.Item) bool { + r := i.(*row) + rowSet[r.key] = r + return true + } + + if req.Rows != nil && + len(req.Rows.RowKeys)+len(req.Rows.RowRanges) > 0 { + // Add the explicitly given keys + for _, key := range req.Rows.RowKeys { + k := string(key) + if i := tbl.rows.Get(btreeKey(k)); i != nil { + addRow(i) + } + } + + // Add keys from row ranges + for _, rr := range req.Rows.RowRanges { + var start, end string + switch sk := rr.StartKey.(type) { + case *btpb.RowRange_StartKeyClosed: + start = string(sk.StartKeyClosed) + case *btpb.RowRange_StartKeyOpen: + start = string(sk.StartKeyOpen) + "\x00" + } + switch ek := rr.EndKey.(type) { + case *btpb.RowRange_EndKeyClosed: + end = string(ek.EndKeyClosed) + "\x00" + case *btpb.RowRange_EndKeyOpen: + end = string(ek.EndKeyOpen) + } + switch { + case start == "" && end == "": + tbl.rows.Ascend(addRow) // all rows + case start == "": + tbl.rows.AscendLessThan(btreeKey(end), addRow) + case end == "": + tbl.rows.AscendGreaterOrEqual(btreeKey(start), addRow) + default: + tbl.rows.AscendRange(btreeKey(start), btreeKey(end), addRow) + } + } + } else { + // Read all rows + tbl.rows.Ascend(addRow) + } + tbl.mu.RUnlock() + + rows := make([]*row, 0, len(rowSet)) + for _, r := range rowSet { + rows = append(rows, r) + } + sort.Sort(byRowKey(rows)) + + limit := int(req.RowsLimit) + count := 0 + for _, r := range rows { + if limit > 0 && count >= limit { + return nil + } + streamed, err := streamRow(stream, r, req.Filter) + if err != nil { + return err + } + if streamed { + count++ + } + } + return nil +} + +// streamRow filters the given row and sends it via the given stream. +// Returns true if at least one cell matched the filter and was streamed, false otherwise. +func streamRow(stream btpb.Bigtable_ReadRowsServer, r *row, f *btpb.RowFilter) (bool, error) { + r.mu.Lock() + nr := r.copy() + r.mu.Unlock() + r = nr + + match, err := filterRow(f, r) + if err != nil { + return false, err + } + if !match { + return false, nil + } + + rrr := &btpb.ReadRowsResponse{} + families := r.sortedFamilies() + for _, fam := range families { + for _, colName := range fam.colNames { + cells := fam.cells[colName] + if len(cells) == 0 { + continue + } + for _, cell := range cells { + rrr.Chunks = append(rrr.Chunks, &btpb.ReadRowsResponse_CellChunk{ + RowKey: []byte(r.key), + FamilyName: &wrappers.StringValue{Value: fam.name}, + Qualifier: &wrappers.BytesValue{Value: []byte(colName)}, + TimestampMicros: cell.ts, + Value: cell.value, + Labels: cell.labels, + }) + } + } + } + // We can't have a cell with just COMMIT set, which would imply a new empty cell. + // So modify the last cell to have the COMMIT flag set. + if len(rrr.Chunks) > 0 { + rrr.Chunks[len(rrr.Chunks)-1].RowStatus = &btpb.ReadRowsResponse_CellChunk_CommitRow{CommitRow: true} + } + + return true, stream.Send(rrr) +} + +// filterRow modifies a row with the given filter. Returns true if at least one cell from the row matches, +// false otherwise. If a filter is invalid, filterRow returns false and an error. +func filterRow(f *btpb.RowFilter, r *row) (bool, error) { + if f == nil { + return true, nil + } + // Handle filters that apply beyond just including/excluding cells. + switch f := f.Filter.(type) { + case *btpb.RowFilter_BlockAllFilter: + return !f.BlockAllFilter, nil + case *btpb.RowFilter_PassAllFilter: + return f.PassAllFilter, nil + case *btpb.RowFilter_Chain_: + for _, sub := range f.Chain.Filters { + match, err := filterRow(sub, r) + if err != nil { + return false, err + } + if !match { + return false, nil + } + } + return true, nil + case *btpb.RowFilter_Interleave_: + srs := make([]*row, 0, len(f.Interleave.Filters)) + for _, sub := range f.Interleave.Filters { + sr := r.copy() + filterRow(sub, sr) + srs = append(srs, sr) + } + // merge + // TODO(dsymonds): is this correct? + r.families = make(map[string]*family) + for _, sr := range srs { + for _, fam := range sr.families { + f := r.getOrCreateFamily(fam.name, fam.order) + for colName, cs := range fam.cells { + f.cells[colName] = append(f.cellsByColumn(colName), cs...) + } + } + } + var count int + for _, fam := range r.families { + for _, cs := range fam.cells { + sort.Sort(byDescTS(cs)) + count += len(cs) + } + } + return count > 0, nil + case *btpb.RowFilter_CellsPerColumnLimitFilter: + lim := int(f.CellsPerColumnLimitFilter) + for _, fam := range r.families { + for col, cs := range fam.cells { + if len(cs) > lim { + fam.cells[col] = cs[:lim] + } + } + } + return true, nil + case *btpb.RowFilter_Condition_: + match, err := filterRow(f.Condition.PredicateFilter, r.copy()) + if err != nil { + return false, err + } + if match { + if f.Condition.TrueFilter == nil { + return false, nil + } + return filterRow(f.Condition.TrueFilter, r) + } + if f.Condition.FalseFilter == nil { + return false, nil + } + return filterRow(f.Condition.FalseFilter, r) + case *btpb.RowFilter_RowKeyRegexFilter: + rx, err := newRegexp(f.RowKeyRegexFilter) + if err != nil { + return false, status.Errorf(codes.InvalidArgument, "Error in field 'rowkey_regex_filter' : %v", err) + } + if !rx.MatchString(r.key) { + return false, nil + } + case *btpb.RowFilter_CellsPerRowLimitFilter: + // Grab the first n cells in the row. + lim := int(f.CellsPerRowLimitFilter) + for _, fam := range r.families { + for _, col := range fam.colNames { + cs := fam.cells[col] + if len(cs) > lim { + fam.cells[col] = cs[:lim] + lim = 0 + } else { + lim -= len(cs) + } + } + } + return true, nil + case *btpb.RowFilter_CellsPerRowOffsetFilter: + // Skip the first n cells in the row. + offset := int(f.CellsPerRowOffsetFilter) + for _, fam := range r.families { + for _, col := range fam.colNames { + cs := fam.cells[col] + if len(cs) > offset { + fam.cells[col] = cs[offset:] + offset = 0 + return true, nil + } + fam.cells[col] = cs[:0] + offset -= len(cs) + } + } + return true, nil + case *btpb.RowFilter_RowSampleFilter: + // The row sample filter "matches all cells from a row with probability + // p, and matches no cells from the row with probability 1-p." + // See https://github.com/googleapis/googleapis/blob/master/google/bigtable/v2/data.proto + if f.RowSampleFilter <= 0.0 || f.RowSampleFilter >= 1.0 { + return false, status.Error(codes.InvalidArgument, "row_sample_filter argument must be between 0.0 and 1.0") + } + return randFloat() < f.RowSampleFilter, nil + } + + // Any other case, operate on a per-cell basis. + cellCount := 0 + for _, fam := range r.families { + for colName, cs := range fam.cells { + filtered, err := filterCells(f, fam.name, colName, cs) + if err != nil { + return false, err + } + fam.cells[colName] = filtered + cellCount += len(fam.cells[colName]) + } + } + return cellCount > 0, nil +} + +var randFloat = rand.Float64 + +func filterCells(f *btpb.RowFilter, fam, col string, cs []cell) ([]cell, error) { + var ret []cell + for _, cell := range cs { + include, err := includeCell(f, fam, col, cell) + if err != nil { + return nil, err + } + if include { + cell, err = modifyCell(f, cell) + if err != nil { + return nil, err + } + ret = append(ret, cell) + } + } + return ret, nil +} + +func modifyCell(f *btpb.RowFilter, c cell) (cell, error) { + if f == nil { + return c, nil + } + // Consider filters that may modify the cell contents + switch filter := f.Filter.(type) { + case *btpb.RowFilter_StripValueTransformer: + return cell{ts: c.ts}, nil + case *btpb.RowFilter_ApplyLabelTransformer: + if !validLabelTransformer.MatchString(filter.ApplyLabelTransformer) { + return cell{}, status.Errorf( + codes.InvalidArgument, + `apply_label_transformer must match RE2([a-z0-9\-]+), but found %v`, + filter.ApplyLabelTransformer, + ) + } + return cell{ts: c.ts, value: c.value, labels: []string{filter.ApplyLabelTransformer}}, nil + default: + return c, nil + } +} + +func includeCell(f *btpb.RowFilter, fam, col string, cell cell) (bool, error) { + if f == nil { + return true, nil + } + // TODO(dsymonds): Implement many more filters. + switch f := f.Filter.(type) { + case *btpb.RowFilter_CellsPerColumnLimitFilter: + // Don't log, row-level filter + return true, nil + case *btpb.RowFilter_RowKeyRegexFilter: + // Don't log, row-level filter + return true, nil + case *btpb.RowFilter_StripValueTransformer: + // Don't log, cell-modifying filter + return true, nil + case *btpb.RowFilter_ApplyLabelTransformer: + // Don't log, cell-modifying filter + return true, nil + default: + log.Printf("WARNING: don't know how to handle filter of type %T (ignoring it)", f) + return true, nil + case *btpb.RowFilter_FamilyNameRegexFilter: + rx, err := newRegexp([]byte(f.FamilyNameRegexFilter)) + if err != nil { + return false, status.Errorf(codes.InvalidArgument, "Error in field 'family_name_regex_filter' : %v", err) + } + return rx.MatchString(fam), nil + case *btpb.RowFilter_ColumnQualifierRegexFilter: + rx, err := newRegexp(f.ColumnQualifierRegexFilter) + if err != nil { + return false, status.Errorf(codes.InvalidArgument, "Error in field 'column_qualifier_regex_filter' : %v", err) + } + return rx.MatchString(toUTF8([]byte(col))), nil + case *btpb.RowFilter_ValueRegexFilter: + rx, err := newRegexp(f.ValueRegexFilter) + if err != nil { + return false, status.Errorf(codes.InvalidArgument, "Error in field 'value_regex_filter' : %v", err) + } + return rx.Match(cell.value), nil + case *btpb.RowFilter_ColumnRangeFilter: + if fam != f.ColumnRangeFilter.FamilyName { + return false, nil + } + // Start qualifier defaults to empty string closed + inRangeStart := func() bool { return col >= "" } + switch sq := f.ColumnRangeFilter.StartQualifier.(type) { + case *btpb.ColumnRange_StartQualifierOpen: + inRangeStart = func() bool { return col > string(sq.StartQualifierOpen) } + case *btpb.ColumnRange_StartQualifierClosed: + inRangeStart = func() bool { return col >= string(sq.StartQualifierClosed) } + } + // End qualifier defaults to no upper boundary + inRangeEnd := func() bool { return true } + switch eq := f.ColumnRangeFilter.EndQualifier.(type) { + case *btpb.ColumnRange_EndQualifierClosed: + inRangeEnd = func() bool { return col <= string(eq.EndQualifierClosed) } + case *btpb.ColumnRange_EndQualifierOpen: + inRangeEnd = func() bool { return col < string(eq.EndQualifierOpen) } + } + return inRangeStart() && inRangeEnd(), nil + case *btpb.RowFilter_TimestampRangeFilter: + // Lower bound is inclusive and defaults to 0, upper bound is exclusive and defaults to infinity. + return cell.ts >= f.TimestampRangeFilter.StartTimestampMicros && + (f.TimestampRangeFilter.EndTimestampMicros == 0 || cell.ts < f.TimestampRangeFilter.EndTimestampMicros), nil + case *btpb.RowFilter_ValueRangeFilter: + v := cell.value + // Start value defaults to empty string closed + inRangeStart := func() bool { return bytes.Compare(v, []byte{}) >= 0 } + switch sv := f.ValueRangeFilter.StartValue.(type) { + case *btpb.ValueRange_StartValueOpen: + inRangeStart = func() bool { return bytes.Compare(v, sv.StartValueOpen) > 0 } + case *btpb.ValueRange_StartValueClosed: + inRangeStart = func() bool { return bytes.Compare(v, sv.StartValueClosed) >= 0 } + } + // End value defaults to no upper boundary + inRangeEnd := func() bool { return true } + switch ev := f.ValueRangeFilter.EndValue.(type) { + case *btpb.ValueRange_EndValueClosed: + inRangeEnd = func() bool { return bytes.Compare(v, ev.EndValueClosed) <= 0 } + case *btpb.ValueRange_EndValueOpen: + inRangeEnd = func() bool { return bytes.Compare(v, ev.EndValueOpen) < 0 } + } + return inRangeStart() && inRangeEnd(), nil + } +} + +func toUTF8(bs []byte) string { + var rs []rune + for _, b := range bs { + rs = append(rs, rune(b)) + } + return string(rs) +} + +func newRegexp(patBytes []byte) (*regexp.Regexp, error) { + pat := toUTF8(patBytes) + re, err := regexp.Compile("^" + pat + "$") // match entire target + if err != nil { + log.Printf("Bad pattern %q: %v", pat, err) + } + return re, err +} + +func (s *server) MutateRow(ctx context.Context, req *btpb.MutateRowRequest) (*btpb.MutateRowResponse, error) { + s.mu.Lock() + tbl, ok := s.tables[req.TableName] + s.mu.Unlock() + if !ok { + return nil, status.Errorf(codes.NotFound, "table %q not found", req.TableName) + } + fs := tbl.columnFamilies() + r := tbl.mutableRow(string(req.RowKey)) + r.mu.Lock() + defer r.mu.Unlock() + if err := applyMutations(tbl, r, req.Mutations, fs); err != nil { + return nil, err + } + return &btpb.MutateRowResponse{}, nil +} + +func (s *server) MutateRows(req *btpb.MutateRowsRequest, stream btpb.Bigtable_MutateRowsServer) error { + s.mu.Lock() + tbl, ok := s.tables[req.TableName] + s.mu.Unlock() + if !ok { + return status.Errorf(codes.NotFound, "table %q not found", req.TableName) + } + res := &btpb.MutateRowsResponse{Entries: make([]*btpb.MutateRowsResponse_Entry, len(req.Entries))} + + fs := tbl.columnFamilies() + + for i, entry := range req.Entries { + r := tbl.mutableRow(string(entry.RowKey)) + r.mu.Lock() + code, msg := int32(codes.OK), "" + if err := applyMutations(tbl, r, entry.Mutations, fs); err != nil { + code = int32(codes.Internal) + msg = err.Error() + } + res.Entries[i] = &btpb.MutateRowsResponse_Entry{ + Index: int64(i), + Status: &statpb.Status{Code: code, Message: msg}, + } + r.mu.Unlock() + } + return stream.Send(res) +} + +func (s *server) CheckAndMutateRow(ctx context.Context, req *btpb.CheckAndMutateRowRequest) (*btpb.CheckAndMutateRowResponse, error) { + s.mu.Lock() + tbl, ok := s.tables[req.TableName] + s.mu.Unlock() + if !ok { + return nil, status.Errorf(codes.NotFound, "table %q not found", req.TableName) + } + res := &btpb.CheckAndMutateRowResponse{} + + fs := tbl.columnFamilies() + + r := tbl.mutableRow(string(req.RowKey)) + r.mu.Lock() + defer r.mu.Unlock() + + // Figure out which mutation to apply. + whichMut := false + if req.PredicateFilter == nil { + // Use true_mutations iff row contains any cells. + whichMut = !r.isEmpty() + } else { + // Use true_mutations iff any cells in the row match the filter. + // TODO(dsymonds): This could be cheaper. + nr := r.copy() + filterRow(req.PredicateFilter, nr) + whichMut = !nr.isEmpty() + } + res.PredicateMatched = whichMut + muts := req.FalseMutations + if whichMut { + muts = req.TrueMutations + } + + if err := applyMutations(tbl, r, muts, fs); err != nil { + return nil, err + } + return res, nil +} + +// applyMutations applies a sequence of mutations to a row. +// fam should be a snapshot of the keys of tbl.families. +// It assumes r.mu is locked. +func applyMutations(tbl *table, r *row, muts []*btpb.Mutation, fs map[string]*columnFamily) error { + for _, mut := range muts { + switch mut := mut.Mutation.(type) { + default: + return fmt.Errorf("can't handle mutation type %T", mut) + case *btpb.Mutation_SetCell_: + set := mut.SetCell + if _, ok := fs[set.FamilyName]; !ok { + return fmt.Errorf("unknown family %q", set.FamilyName) + } + ts := set.TimestampMicros + if ts == -1 { // bigtable.ServerTime + ts = newTimestamp() + } + if !tbl.validTimestamp(ts) { + return fmt.Errorf("invalid timestamp %d", ts) + } + fam := set.FamilyName + col := string(set.ColumnQualifier) + + newCell := cell{ts: ts, value: set.Value} + f := r.getOrCreateFamily(fam, fs[fam].order) + f.cells[col] = appendOrReplaceCell(f.cellsByColumn(col), newCell) + case *btpb.Mutation_DeleteFromColumn_: + del := mut.DeleteFromColumn + if _, ok := fs[del.FamilyName]; !ok { + return fmt.Errorf("unknown family %q", del.FamilyName) + } + fam := del.FamilyName + col := string(del.ColumnQualifier) + if _, ok := r.families[fam]; ok { + cs := r.families[fam].cells[col] + if del.TimeRange != nil { + tsr := del.TimeRange + if !tbl.validTimestamp(tsr.StartTimestampMicros) { + return fmt.Errorf("invalid timestamp %d", tsr.StartTimestampMicros) + } + if !tbl.validTimestamp(tsr.EndTimestampMicros) && tsr.EndTimestampMicros != 0 { + return fmt.Errorf("invalid timestamp %d", tsr.EndTimestampMicros) + } + if tsr.StartTimestampMicros >= tsr.EndTimestampMicros && tsr.EndTimestampMicros != 0 { + return fmt.Errorf("inverted or invalid timestamp range [%d, %d]", tsr.StartTimestampMicros, tsr.EndTimestampMicros) + } + + // Find half-open interval to remove. + // Cells are in descending timestamp order, + // so the predicates to sort.Search are inverted. + si, ei := 0, len(cs) + if tsr.StartTimestampMicros > 0 { + ei = sort.Search(len(cs), func(i int) bool { return cs[i].ts < tsr.StartTimestampMicros }) + } + if tsr.EndTimestampMicros > 0 { + si = sort.Search(len(cs), func(i int) bool { return cs[i].ts < tsr.EndTimestampMicros }) + } + if si < ei { + copy(cs[si:], cs[ei:]) + cs = cs[:len(cs)-(ei-si)] + } + } else { + cs = nil + } + if len(cs) == 0 { + delete(r.families[fam].cells, col) + colNames := r.families[fam].colNames + i := sort.Search(len(colNames), func(i int) bool { return colNames[i] >= col }) + if i < len(colNames) && colNames[i] == col { + r.families[fam].colNames = append(colNames[:i], colNames[i+1:]...) + } + if len(r.families[fam].cells) == 0 { + delete(r.families, fam) + } + } else { + r.families[fam].cells[col] = cs + } + } + case *btpb.Mutation_DeleteFromRow_: + r.families = make(map[string]*family) + case *btpb.Mutation_DeleteFromFamily_: + fampre := mut.DeleteFromFamily.FamilyName + delete(r.families, fampre) + } + } + return nil +} + +func maxTimestamp(x, y int64) int64 { + if x > y { + return x + } + return y +} + +func newTimestamp() int64 { + ts := time.Now().UnixNano() / 1e3 + ts -= ts % 1000 // round to millisecond granularity + return ts +} + +func appendOrReplaceCell(cs []cell, newCell cell) []cell { + replaced := false + for i, cell := range cs { + if cell.ts == newCell.ts { + cs[i] = newCell + replaced = true + break + } + } + if !replaced { + cs = append(cs, newCell) + } + sort.Sort(byDescTS(cs)) + return cs +} + +func (s *server) ReadModifyWriteRow(ctx context.Context, req *btpb.ReadModifyWriteRowRequest) (*btpb.ReadModifyWriteRowResponse, error) { + s.mu.Lock() + tbl, ok := s.tables[req.TableName] + s.mu.Unlock() + if !ok { + return nil, status.Errorf(codes.NotFound, "table %q not found", req.TableName) + } + + fs := tbl.columnFamilies() + + rowKey := string(req.RowKey) + r := tbl.mutableRow(rowKey) + resultRow := newRow(rowKey) // copy of updated cells + + // This must be done before the row lock, acquired below, is released. + r.mu.Lock() + defer r.mu.Unlock() + // Assume all mutations apply to the most recent version of the cell. + // TODO(dsymonds): Verify this assumption and document it in the proto. + for _, rule := range req.Rules { + if _, ok := fs[rule.FamilyName]; !ok { + return nil, fmt.Errorf("unknown family %q", rule.FamilyName) + } + + fam := rule.FamilyName + col := string(rule.ColumnQualifier) + isEmpty := false + f := r.getOrCreateFamily(fam, fs[fam].order) + cs := f.cells[col] + isEmpty = len(cs) == 0 + + ts := newTimestamp() + var newCell, prevCell cell + if !isEmpty { + cells := r.families[fam].cells[col] + prevCell = cells[0] + + // ts is the max of now or the prev cell's timestamp in case the + // prev cell is in the future + ts = maxTimestamp(ts, prevCell.ts) + } + + switch rule := rule.Rule.(type) { + default: + return nil, fmt.Errorf("unknown RMW rule oneof %T", rule) + case *btpb.ReadModifyWriteRule_AppendValue: + newCell = cell{ts: ts, value: append(prevCell.value, rule.AppendValue...)} + case *btpb.ReadModifyWriteRule_IncrementAmount: + var v int64 + if !isEmpty { + prevVal := prevCell.value + if len(prevVal) != 8 { + return nil, fmt.Errorf("increment on non-64-bit value") + } + v = int64(binary.BigEndian.Uint64(prevVal)) + } + v += rule.IncrementAmount + var val [8]byte + binary.BigEndian.PutUint64(val[:], uint64(v)) + newCell = cell{ts: ts, value: val[:]} + } + + // Store the new cell + f.cells[col] = appendOrReplaceCell(f.cellsByColumn(col), newCell) + + // Store a copy for the result row + resultFamily := resultRow.getOrCreateFamily(fam, fs[fam].order) + resultFamily.cellsByColumn(col) // create the column + resultFamily.cells[col] = []cell{newCell} // overwrite the cells + } + + // Build the response using the result row + res := &btpb.Row{ + Key: req.RowKey, + Families: make([]*btpb.Family, len(resultRow.families)), + } + + for i, family := range resultRow.sortedFamilies() { + res.Families[i] = &btpb.Family{ + Name: family.name, + Columns: make([]*btpb.Column, len(family.colNames)), + } + + for j, colName := range family.colNames { + res.Families[i].Columns[j] = &btpb.Column{ + Qualifier: []byte(colName), + Cells: []*btpb.Cell{{ + TimestampMicros: family.cells[colName][0].ts, + Value: family.cells[colName][0].value, + }}, + } + } + } + return &btpb.ReadModifyWriteRowResponse{Row: res}, nil +} + +func (s *server) SampleRowKeys(req *btpb.SampleRowKeysRequest, stream btpb.Bigtable_SampleRowKeysServer) error { + s.mu.Lock() + tbl, ok := s.tables[req.TableName] + s.mu.Unlock() + if !ok { + return status.Errorf(codes.NotFound, "table %q not found", req.TableName) + } + + tbl.mu.RLock() + defer tbl.mu.RUnlock() + + // The return value of SampleRowKeys is very loosely defined. Return at least the + // final row key in the table and choose other row keys randomly. + var offset int64 + var err error + i := 0 + tbl.rows.Ascend(func(it btree.Item) bool { + row := it.(*row) + if i == tbl.rows.Len()-1 || rand.Int31n(100) == 0 { + resp := &btpb.SampleRowKeysResponse{ + RowKey: []byte(row.key), + OffsetBytes: offset, + } + err = stream.Send(resp) + if err != nil { + return false + } + } + offset += int64(row.size()) + i++ + return true + }) + return err +} + +// needGC is invoked whenever the server needs gcloop running. +func (s *server) needGC() { + s.mu.Lock() + if s.gcc == nil { + s.gcc = make(chan int) + go s.gcloop(s.gcc) + } + s.mu.Unlock() +} + +func (s *server) gcloop(done <-chan int) { + const ( + minWait = 500 // ms + maxWait = 1500 // ms + ) + + for { + // Wait for a random time interval. + d := time.Duration(minWait+rand.Intn(maxWait-minWait)) * time.Millisecond + select { + case <-time.After(d): + case <-done: + return // server has been closed + } + + // Do a GC pass over all tables. + var tables []*table + s.mu.Lock() + for _, tbl := range s.tables { + tables = append(tables, tbl) + } + s.mu.Unlock() + for _, tbl := range tables { + tbl.gc() + } + } +} + +type table struct { + mu sync.RWMutex + counter uint64 // increment by 1 when a new family is created + families map[string]*columnFamily // keyed by plain family name + rows *btree.BTree // indexed by row key +} + +const btreeDegree = 16 + +func newTable(ctr *btapb.CreateTableRequest) *table { + fams := make(map[string]*columnFamily) + c := uint64(0) + if ctr.Table != nil { + for id, cf := range ctr.Table.ColumnFamilies { + fams[id] = &columnFamily{ + name: ctr.Parent + "/columnFamilies/" + id, + order: c, + gcRule: cf.GcRule, + } + c++ + } + } + return &table{ + families: fams, + counter: c, + rows: btree.New(btreeDegree), + } +} + +func (t *table) validTimestamp(ts int64) bool { + if ts < minValidMilliSeconds || ts > maxValidMilliSeconds { + return false + } + + // Assume millisecond granularity is required. + return ts%1000 == 0 +} + +func (t *table) columnFamilies() map[string]*columnFamily { + cp := make(map[string]*columnFamily) + t.mu.RLock() + for fam, cf := range t.families { + cp[fam] = cf + } + t.mu.RUnlock() + return cp +} + +func (t *table) mutableRow(key string) *row { + bkey := btreeKey(key) + // Try fast path first. + t.mu.RLock() + i := t.rows.Get(bkey) + t.mu.RUnlock() + if i != nil { + return i.(*row) + } + + // We probably need to create the row. + t.mu.Lock() + defer t.mu.Unlock() + i = t.rows.Get(bkey) + if i != nil { + return i.(*row) + } + r := newRow(key) + t.rows.ReplaceOrInsert(r) + return r +} + +func (t *table) gc() { + // This method doesn't add or remove rows, so we only need a read lock for the table. + t.mu.RLock() + defer t.mu.RUnlock() + + // Gather GC rules we'll apply. + rules := make(map[string]*btapb.GcRule) // keyed by "fam" + for fam, cf := range t.families { + if cf.gcRule != nil { + rules[fam] = cf.gcRule + } + } + if len(rules) == 0 { + return + } + + t.rows.Ascend(func(i btree.Item) bool { + r := i.(*row) + r.mu.Lock() + r.gc(rules) + r.mu.Unlock() + return true + }) +} + +type byRowKey []*row + +func (b byRowKey) Len() int { return len(b) } +func (b byRowKey) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byRowKey) Less(i, j int) bool { return b[i].key < b[j].key } + +type row struct { + key string + + mu sync.Mutex + families map[string]*family // keyed by family name +} + +func newRow(key string) *row { + return &row{ + key: key, + families: make(map[string]*family), + } +} + +// copy returns a copy of the row. +// Cell values are aliased. +// r.mu should be held. +func (r *row) copy() *row { + nr := newRow(r.key) + for _, fam := range r.families { + nr.families[fam.name] = &family{ + name: fam.name, + order: fam.order, + colNames: fam.colNames, + cells: make(map[string][]cell), + } + for col, cs := range fam.cells { + // Copy the []cell slice, but not the []byte inside each cell. + nr.families[fam.name].cells[col] = append([]cell(nil), cs...) + } + } + return nr +} + +// isEmpty returns true if a row doesn't contain any cell +func (r *row) isEmpty() bool { + for _, fam := range r.families { + for _, cs := range fam.cells { + if len(cs) > 0 { + return false + } + } + } + return true +} + +// sortedFamilies returns a column family set +// sorted in ascending creation order in a row. +func (r *row) sortedFamilies() []*family { + var families []*family + for _, fam := range r.families { + families = append(families, fam) + } + sort.Sort(byCreationOrder(families)) + return families +} + +func (r *row) getOrCreateFamily(name string, order uint64) *family { + if _, ok := r.families[name]; !ok { + r.families[name] = &family{ + name: name, + order: order, + cells: make(map[string][]cell), + } + } + return r.families[name] +} + +// gc applies the given GC rules to the row. +// r.mu should be held. +func (r *row) gc(rules map[string]*btapb.GcRule) { + for _, fam := range r.families { + rule, ok := rules[fam.name] + if !ok { + continue + } + for col, cs := range fam.cells { + r.families[fam.name].cells[col] = applyGC(cs, rule) + } + } +} + +// size returns the total size of all cell values in the row. +func (r *row) size() int { + size := 0 + for _, fam := range r.families { + for _, cells := range fam.cells { + for _, cell := range cells { + size += len(cell.value) + } + } + } + return size +} + +// Less implements btree.Less. +func (r *row) Less(i btree.Item) bool { + return r.key < i.(*row).key +} + +// btreeKey returns a row for use as a key into the BTree. +func btreeKey(s string) *row { return &row{key: s} } + +func (r *row) String() string { + return r.key +} + +var gcTypeWarn sync.Once + +// applyGC applies the given GC rule to the cells. +func applyGC(cells []cell, rule *btapb.GcRule) []cell { + switch rule := rule.Rule.(type) { + default: + // TODO(dsymonds): Support GcRule_Intersection_ + gcTypeWarn.Do(func() { + log.Printf("Unsupported GC rule type %T", rule) + }) + case *btapb.GcRule_Union_: + for _, sub := range rule.Union.Rules { + cells = applyGC(cells, sub) + } + return cells + case *btapb.GcRule_MaxAge: + // Timestamps are in microseconds. + cutoff := time.Now().UnixNano() / 1e3 + cutoff -= rule.MaxAge.Seconds * 1e6 + cutoff -= int64(rule.MaxAge.Nanos) / 1e3 + // The slice of cells in in descending timestamp order. + // This sort.Search will return the index of the first cell whose timestamp is chronologically before the cutoff. + si := sort.Search(len(cells), func(i int) bool { return cells[i].ts < cutoff }) + if si < len(cells) { + log.Printf("bttest: GC MaxAge(%v) deleted %d cells.", rule.MaxAge, len(cells)-si) + } + return cells[:si] + case *btapb.GcRule_MaxNumVersions: + n := int(rule.MaxNumVersions) + if len(cells) > n { + cells = cells[:n] + } + return cells + } + return cells +} + +type family struct { + name string // Column family name + order uint64 // Creation order of column family + colNames []string // Column names are sorted in lexicographical ascending order + cells map[string][]cell // Keyed by column name; cells are in descending timestamp order +} + +type byCreationOrder []*family + +func (b byCreationOrder) Len() int { return len(b) } +func (b byCreationOrder) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byCreationOrder) Less(i, j int) bool { return b[i].order < b[j].order } + +// cellsByColumn adds the column name to colNames set if it does not exist +// and returns all cells within a column +func (f *family) cellsByColumn(name string) []cell { + if _, ok := f.cells[name]; !ok { + f.colNames = append(f.colNames, name) + sort.Strings(f.colNames) + } + return f.cells[name] +} + +type cell struct { + ts int64 + value []byte + labels []string +} + +type byDescTS []cell + +func (b byDescTS) Len() int { return len(b) } +func (b byDescTS) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byDescTS) Less(i, j int) bool { return b[i].ts > b[j].ts } + +type columnFamily struct { + name string + order uint64 // Creation order of column family + gcRule *btapb.GcRule +} + +func (c *columnFamily) proto() *btapb.ColumnFamily { + return &btapb.ColumnFamily{ + GcRule: c.gcRule, + } +} + +func toColumnFamilies(families map[string]*columnFamily) map[string]*btapb.ColumnFamily { + fs := make(map[string]*btapb.ColumnFamily) + for k, v := range families { + fs[k] = v.proto() + } + return fs +} diff --git a/vendor/cloud.google.com/go/bigtable/bttest/inmem_test.go b/vendor/cloud.google.com/go/bigtable/bttest/inmem_test.go new file mode 100644 index 00000000..df36c3ca --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/bttest/inmem_test.go @@ -0,0 +1,1153 @@ +// Copyright 2016 Google LLC +// +// 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 bttest + +import ( + "context" + "fmt" + "math/rand" + "strconv" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/golang/protobuf/proto" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + btapb "google.golang.org/genproto/googleapis/bigtable/admin/v2" + btpb "google.golang.org/genproto/googleapis/bigtable/v2" + "google.golang.org/grpc" +) + +func TestConcurrentMutationsReadModifyAndGC(t *testing.T) { + s := &server{ + tables: make(map[string]*table), + } + ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) + defer cancel() + if _, err := s.CreateTable( + ctx, + &btapb.CreateTableRequest{Parent: "cluster", TableId: "t"}); err != nil { + t.Fatal(err) + } + const name = `cluster/tables/t` + tbl := s.tables[name] + req := &btapb.ModifyColumnFamiliesRequest{ + Name: name, + Modifications: []*btapb.ModifyColumnFamiliesRequest_Modification{{ + Id: "cf", + Mod: &btapb.ModifyColumnFamiliesRequest_Modification_Create{Create: &btapb.ColumnFamily{}}, + }}, + } + _, err := s.ModifyColumnFamilies(ctx, req) + if err != nil { + t.Fatal(err) + } + req = &btapb.ModifyColumnFamiliesRequest{ + Name: name, + Modifications: []*btapb.ModifyColumnFamiliesRequest_Modification{{ + Id: "cf", + Mod: &btapb.ModifyColumnFamiliesRequest_Modification_Update{Update: &btapb.ColumnFamily{ + GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}, + }}, + }}, + } + if _, err := s.ModifyColumnFamilies(ctx, req); err != nil { + t.Fatal(err) + } + + var wg sync.WaitGroup + var ts int64 + ms := func() []*btpb.Mutation { + return []*btpb.Mutation{{ + Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{ + FamilyName: "cf", + ColumnQualifier: []byte(`col`), + TimestampMicros: atomic.AddInt64(&ts, 1000), + }}, + }} + } + + rmw := func() *btpb.ReadModifyWriteRowRequest { + return &btpb.ReadModifyWriteRowRequest{ + TableName: name, + RowKey: []byte(fmt.Sprint(rand.Intn(100))), + Rules: []*btpb.ReadModifyWriteRule{{ + FamilyName: "cf", + ColumnQualifier: []byte("col"), + Rule: &btpb.ReadModifyWriteRule_IncrementAmount{IncrementAmount: 1}, + }}, + } + } + for i := 0; i < 100; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for ctx.Err() == nil { + req := &btpb.MutateRowRequest{ + TableName: name, + RowKey: []byte(fmt.Sprint(rand.Intn(100))), + Mutations: ms(), + } + if _, err := s.MutateRow(ctx, req); err != nil { + panic(err) // can't use t.Fatal in goroutine + } + } + }() + wg.Add(1) + go func() { + defer wg.Done() + for ctx.Err() == nil { + _, _ = s.ReadModifyWriteRow(ctx, rmw()) + } + }() + + wg.Add(1) + go func() { + defer wg.Done() + tbl.gc() + }() + } + done := make(chan struct{}) + go func() { + wg.Wait() + close(done) + }() + select { + case <-done: + case <-time.After(1 * time.Second): + t.Error("Concurrent mutations and GCs haven't completed after 1s") + } +} + +func TestCreateTableWithFamily(t *testing.T) { + // The Go client currently doesn't support creating a table with column families + // in one operation but it is allowed by the API. This must still be supported by the + // fake server so this test lives here instead of in the main bigtable + // integration test. + s := &server{ + tables: make(map[string]*table), + } + ctx := context.Background() + newTbl := btapb.Table{ + ColumnFamilies: map[string]*btapb.ColumnFamily{ + "cf1": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 123}}}, + "cf2": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 456}}}, + }, + } + cTbl, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl}) + if err != nil { + t.Fatalf("Creating table: %v", err) + } + tbl, err := s.GetTable(ctx, &btapb.GetTableRequest{Name: cTbl.Name}) + if err != nil { + t.Fatalf("Getting table: %v", err) + } + cf := tbl.ColumnFamilies["cf1"] + if cf == nil { + t.Fatalf("Missing col family cf1") + } + if got, want := cf.GcRule.GetMaxNumVersions(), int32(123); got != want { + t.Errorf("Invalid MaxNumVersions: wanted:%d, got:%d", want, got) + } + cf = tbl.ColumnFamilies["cf2"] + if cf == nil { + t.Fatalf("Missing col family cf2") + } + if got, want := cf.GcRule.GetMaxNumVersions(), int32(456); got != want { + t.Errorf("Invalid MaxNumVersions: wanted:%d, got:%d", want, got) + } +} + +type MockSampleRowKeysServer struct { + responses []*btpb.SampleRowKeysResponse + grpc.ServerStream +} + +func (s *MockSampleRowKeysServer) Send(resp *btpb.SampleRowKeysResponse) error { + s.responses = append(s.responses, resp) + return nil +} + +func TestSampleRowKeys(t *testing.T) { + s := &server{ + tables: make(map[string]*table), + } + ctx := context.Background() + newTbl := btapb.Table{ + ColumnFamilies: map[string]*btapb.ColumnFamily{ + "cf": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}}, + }, + } + tbl, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl}) + if err != nil { + t.Fatalf("Creating table: %v", err) + } + + // Populate the table + val := []byte("value") + rowCount := 1000 + for i := 0; i < rowCount; i++ { + req := &btpb.MutateRowRequest{ + TableName: tbl.Name, + RowKey: []byte("row-" + strconv.Itoa(i)), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{ + FamilyName: "cf", + ColumnQualifier: []byte("col"), + TimestampMicros: 1000, + Value: val, + }}, + }}, + } + if _, err := s.MutateRow(ctx, req); err != nil { + t.Fatalf("Populating table: %v", err) + } + } + + mock := &MockSampleRowKeysServer{} + if err := s.SampleRowKeys(&btpb.SampleRowKeysRequest{TableName: tbl.Name}, mock); err != nil { + t.Errorf("SampleRowKeys error: %v", err) + } + if len(mock.responses) == 0 { + t.Fatal("Response count: got 0, want > 0") + } + // Make sure the offset of the final response is the offset of the final row + got := mock.responses[len(mock.responses)-1].OffsetBytes + want := int64((rowCount - 1) * len(val)) + if got != want { + t.Errorf("Invalid offset: got %d, want %d", got, want) + } +} + +func TestDropRowRange(t *testing.T) { + s := &server{ + tables: make(map[string]*table), + } + ctx := context.Background() + newTbl := btapb.Table{ + ColumnFamilies: map[string]*btapb.ColumnFamily{ + "cf": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}}, + }, + } + tblInfo, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl}) + if err != nil { + t.Fatalf("Creating table: %v", err) + } + + tbl := s.tables[tblInfo.Name] + + // Populate the table + prefixes := []string{"AAA", "BBB", "CCC", "DDD"} + count := 3 + doWrite := func() { + for _, prefix := range prefixes { + for i := 0; i < count; i++ { + req := &btpb.MutateRowRequest{ + TableName: tblInfo.Name, + RowKey: []byte(prefix + strconv.Itoa(i)), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{ + FamilyName: "cf", + ColumnQualifier: []byte("col"), + TimestampMicros: 1000, + Value: []byte{}, + }}, + }}, + } + if _, err := s.MutateRow(ctx, req); err != nil { + t.Fatalf("Populating table: %v", err) + } + } + } + } + + doWrite() + tblSize := tbl.rows.Len() + req := &btapb.DropRowRangeRequest{ + Name: tblInfo.Name, + Target: &btapb.DropRowRangeRequest_RowKeyPrefix{RowKeyPrefix: []byte("AAA")}, + } + if _, err = s.DropRowRange(ctx, req); err != nil { + t.Fatalf("Dropping first range: %v", err) + } + got, want := tbl.rows.Len(), tblSize-count + if got != want { + t.Errorf("Row count after first drop: got %d (%v), want %d", got, tbl.rows, want) + } + + req = &btapb.DropRowRangeRequest{ + Name: tblInfo.Name, + Target: &btapb.DropRowRangeRequest_RowKeyPrefix{RowKeyPrefix: []byte("DDD")}, + } + if _, err = s.DropRowRange(ctx, req); err != nil { + t.Fatalf("Dropping second range: %v", err) + } + got, want = tbl.rows.Len(), tblSize-(2*count) + if got != want { + t.Errorf("Row count after second drop: got %d (%v), want %d", got, tbl.rows, want) + } + + req = &btapb.DropRowRangeRequest{ + Name: tblInfo.Name, + Target: &btapb.DropRowRangeRequest_RowKeyPrefix{RowKeyPrefix: []byte("XXX")}, + } + if _, err = s.DropRowRange(ctx, req); err != nil { + t.Fatalf("Dropping invalid range: %v", err) + } + got, want = tbl.rows.Len(), tblSize-(2*count) + if got != want { + t.Errorf("Row count after invalid drop: got %d (%v), want %d", got, tbl.rows, want) + } + + req = &btapb.DropRowRangeRequest{ + Name: tblInfo.Name, + Target: &btapb.DropRowRangeRequest_DeleteAllDataFromTable{DeleteAllDataFromTable: true}, + } + if _, err = s.DropRowRange(ctx, req); err != nil { + t.Fatalf("Dropping all data: %v", err) + } + got, want = tbl.rows.Len(), 0 + if got != want { + t.Errorf("Row count after drop all: got %d, want %d", got, want) + } + + // Test that we can write rows, delete some and then write them again. + count = 1 + doWrite() + + req = &btapb.DropRowRangeRequest{ + Name: tblInfo.Name, + Target: &btapb.DropRowRangeRequest_DeleteAllDataFromTable{DeleteAllDataFromTable: true}, + } + if _, err = s.DropRowRange(ctx, req); err != nil { + t.Fatalf("Dropping all data: %v", err) + } + got, want = tbl.rows.Len(), 0 + if got != want { + t.Errorf("Row count after drop all: got %d, want %d", got, want) + } + + doWrite() + got, want = tbl.rows.Len(), len(prefixes) + if got != want { + t.Errorf("Row count after rewrite: got %d, want %d", got, want) + } + + req = &btapb.DropRowRangeRequest{ + Name: tblInfo.Name, + Target: &btapb.DropRowRangeRequest_RowKeyPrefix{RowKeyPrefix: []byte("BBB")}, + } + if _, err = s.DropRowRange(ctx, req); err != nil { + t.Fatalf("Dropping range: %v", err) + } + doWrite() + got, want = tbl.rows.Len(), len(prefixes) + if got != want { + t.Errorf("Row count after drop range: got %d, want %d", got, want) + } +} + +type MockReadRowsServer struct { + responses []*btpb.ReadRowsResponse + grpc.ServerStream +} + +func (s *MockReadRowsServer) Send(resp *btpb.ReadRowsResponse) error { + s.responses = append(s.responses, resp) + return nil +} + +func TestReadRows(t *testing.T) { + ctx := context.Background() + s := &server{ + tables: make(map[string]*table), + } + newTbl := btapb.Table{ + ColumnFamilies: map[string]*btapb.ColumnFamily{ + "cf0": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}}, + }, + } + tblInfo, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl}) + if err != nil { + t.Fatalf("Creating table: %v", err) + } + mreq := &btpb.MutateRowRequest{ + TableName: tblInfo.Name, + RowKey: []byte("row"), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{ + FamilyName: "cf0", + ColumnQualifier: []byte("col"), + TimestampMicros: 1000, + Value: []byte{}, + }}, + }}, + } + if _, err := s.MutateRow(ctx, mreq); err != nil { + t.Fatalf("Populating table: %v", err) + } + + for _, rowset := range []*btpb.RowSet{ + {RowKeys: [][]byte{[]byte("row")}}, + {RowRanges: []*btpb.RowRange{{StartKey: &btpb.RowRange_StartKeyClosed{StartKeyClosed: []byte("")}}}}, + {RowRanges: []*btpb.RowRange{{StartKey: &btpb.RowRange_StartKeyClosed{StartKeyClosed: []byte("r")}}}}, + {RowRanges: []*btpb.RowRange{{ + StartKey: &btpb.RowRange_StartKeyClosed{StartKeyClosed: []byte("")}, + EndKey: &btpb.RowRange_EndKeyOpen{EndKeyOpen: []byte("s")}, + }}}, + } { + mock := &MockReadRowsServer{} + req := &btpb.ReadRowsRequest{TableName: tblInfo.Name, Rows: rowset} + if err = s.ReadRows(req, mock); err != nil { + t.Fatalf("ReadRows error: %v", err) + } + if got, want := len(mock.responses), 1; got != want { + t.Errorf("%+v: response count: got %d, want %d", rowset, got, want) + } + } +} + +func TestReadRowsError(t *testing.T) { + ctx := context.Background() + s := &server{ + tables: make(map[string]*table), + } + newTbl := btapb.Table{ + ColumnFamilies: map[string]*btapb.ColumnFamily{ + "cf0": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}}, + }, + } + tblInfo, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl}) + if err != nil { + t.Fatalf("Creating table: %v", err) + } + mreq := &btpb.MutateRowRequest{ + TableName: tblInfo.Name, + RowKey: []byte("row"), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{ + FamilyName: "cf0", + ColumnQualifier: []byte("col"), + TimestampMicros: 1000, + Value: []byte{}, + }}, + }}, + } + if _, err := s.MutateRow(ctx, mreq); err != nil { + t.Fatalf("Populating table: %v", err) + } + + mock := &MockReadRowsServer{} + req := &btpb.ReadRowsRequest{TableName: tblInfo.Name, Filter: &btpb.RowFilter{ + Filter: &btpb.RowFilter_RowKeyRegexFilter{RowKeyRegexFilter: []byte("[")}}, // Invalid regex. + } + if err = s.ReadRows(req, mock); err == nil { + t.Fatal("ReadRows got no error, want error") + } +} + +func TestReadRowsOrder(t *testing.T) { + s := &server{ + tables: make(map[string]*table), + } + ctx := context.Background() + newTbl := btapb.Table{ + ColumnFamilies: map[string]*btapb.ColumnFamily{ + "cf0": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}}, + }, + } + tblInfo, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl}) + if err != nil { + t.Fatalf("Creating table: %v", err) + } + count := 3 + mcf := func(i int) *btapb.ModifyColumnFamiliesRequest { + return &btapb.ModifyColumnFamiliesRequest{ + Name: tblInfo.Name, + Modifications: []*btapb.ModifyColumnFamiliesRequest_Modification{{ + Id: "cf" + strconv.Itoa(i), + Mod: &btapb.ModifyColumnFamiliesRequest_Modification_Create{Create: &btapb.ColumnFamily{}}, + }}, + } + } + for i := 1; i <= count; i++ { + _, err = s.ModifyColumnFamilies(ctx, mcf(i)) + if err != nil { + t.Fatal(err) + } + } + // Populate the table + for fc := 0; fc < count; fc++ { + for cc := count; cc > 0; cc-- { + for tc := 0; tc < count; tc++ { + req := &btpb.MutateRowRequest{ + TableName: tblInfo.Name, + RowKey: []byte("row"), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{ + FamilyName: "cf" + strconv.Itoa(fc), + ColumnQualifier: []byte("col" + strconv.Itoa(cc)), + TimestampMicros: int64((tc + 1) * 1000), + Value: []byte{}, + }}, + }}, + } + if _, err := s.MutateRow(ctx, req); err != nil { + t.Fatalf("Populating table: %v", err) + } + } + } + } + req := &btpb.ReadRowsRequest{ + TableName: tblInfo.Name, + Rows: &btpb.RowSet{RowKeys: [][]byte{[]byte("row")}}, + } + mock := &MockReadRowsServer{} + if err = s.ReadRows(req, mock); err != nil { + t.Errorf("ReadRows error: %v", err) + } + if len(mock.responses) == 0 { + t.Fatal("Response count: got 0, want > 0") + } + if len(mock.responses[0].Chunks) != 27 { + t.Fatalf("Chunk count: got %d, want 27", len(mock.responses[0].Chunks)) + } + testOrder := func(ms *MockReadRowsServer) { + var prevFam, prevCol string + var prevTime int64 + for _, cc := range ms.responses[0].Chunks { + if prevFam == "" { + prevFam = cc.FamilyName.Value + prevCol = string(cc.Qualifier.Value) + prevTime = cc.TimestampMicros + continue + } + if cc.FamilyName.Value < prevFam { + t.Errorf("Family order is not correct: got %s < %s", cc.FamilyName.Value, prevFam) + } else if cc.FamilyName.Value == prevFam { + if string(cc.Qualifier.Value) < prevCol { + t.Errorf("Column order is not correct: got %s < %s", string(cc.Qualifier.Value), prevCol) + } else if string(cc.Qualifier.Value) == prevCol { + if cc.TimestampMicros > prevTime { + t.Errorf("cell order is not correct: got %d > %d", cc.TimestampMicros, prevTime) + } + } + } + prevFam = cc.FamilyName.Value + prevCol = string(cc.Qualifier.Value) + prevTime = cc.TimestampMicros + } + } + testOrder(mock) + + // Read with interleave filter + inter := &btpb.RowFilter_Interleave{} + fnr := &btpb.RowFilter{Filter: &btpb.RowFilter_FamilyNameRegexFilter{FamilyNameRegexFilter: "cf1"}} + cqr := &btpb.RowFilter{Filter: &btpb.RowFilter_ColumnQualifierRegexFilter{ColumnQualifierRegexFilter: []byte("col2")}} + inter.Filters = append(inter.Filters, fnr, cqr) + req = &btpb.ReadRowsRequest{ + TableName: tblInfo.Name, + Rows: &btpb.RowSet{RowKeys: [][]byte{[]byte("row")}}, + Filter: &btpb.RowFilter{ + Filter: &btpb.RowFilter_Interleave_{Interleave: inter}, + }, + } + + mock = &MockReadRowsServer{} + if err = s.ReadRows(req, mock); err != nil { + t.Errorf("ReadRows error: %v", err) + } + if len(mock.responses) == 0 { + t.Fatal("Response count: got 0, want > 0") + } + if len(mock.responses[0].Chunks) != 18 { + t.Fatalf("Chunk count: got %d, want 18", len(mock.responses[0].Chunks)) + } + testOrder(mock) + + // Check order after ReadModifyWriteRow + rmw := func(i int) *btpb.ReadModifyWriteRowRequest { + return &btpb.ReadModifyWriteRowRequest{ + TableName: tblInfo.Name, + RowKey: []byte("row"), + Rules: []*btpb.ReadModifyWriteRule{{ + FamilyName: "cf3", + ColumnQualifier: []byte("col" + strconv.Itoa(i)), + Rule: &btpb.ReadModifyWriteRule_IncrementAmount{IncrementAmount: 1}, + }}, + } + } + for i := count; i > 0; i-- { + if _, err := s.ReadModifyWriteRow(ctx, rmw(i)); err != nil { + t.Fatal(err) + } + } + req = &btpb.ReadRowsRequest{ + TableName: tblInfo.Name, + Rows: &btpb.RowSet{RowKeys: [][]byte{[]byte("row")}}, + } + mock = &MockReadRowsServer{} + if err = s.ReadRows(req, mock); err != nil { + t.Errorf("ReadRows error: %v", err) + } + if len(mock.responses) == 0 { + t.Fatal("Response count: got 0, want > 0") + } + if len(mock.responses[0].Chunks) != 30 { + t.Fatalf("Chunk count: got %d, want 30", len(mock.responses[0].Chunks)) + } + testOrder(mock) +} + +func TestReadRowsWithlabelTransformer(t *testing.T) { + ctx := context.Background() + s := &server{ + tables: make(map[string]*table), + } + newTbl := btapb.Table{ + ColumnFamilies: map[string]*btapb.ColumnFamily{ + "cf0": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}}, + }, + } + tblInfo, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl}) + if err != nil { + t.Fatalf("Creating table: %v", err) + } + mreq := &btpb.MutateRowRequest{ + TableName: tblInfo.Name, + RowKey: []byte("row"), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{ + FamilyName: "cf0", + ColumnQualifier: []byte("col"), + TimestampMicros: 1000, + Value: []byte{}, + }}, + }}, + } + if _, err := s.MutateRow(ctx, mreq); err != nil { + t.Fatalf("Populating table: %v", err) + } + + mock := &MockReadRowsServer{} + req := &btpb.ReadRowsRequest{ + TableName: tblInfo.Name, + Filter: &btpb.RowFilter{ + Filter: &btpb.RowFilter_ApplyLabelTransformer{ + ApplyLabelTransformer: "label", + }, + }, + } + if err = s.ReadRows(req, mock); err != nil { + t.Fatalf("ReadRows error: %v", err) + } + + if got, want := len(mock.responses), 1; got != want { + t.Fatalf("response count: got %d, want %d", got, want) + } + resp := mock.responses[0] + if got, want := len(resp.Chunks), 1; got != want { + t.Fatalf("chunks count: got %d, want %d", got, want) + } + chunk := resp.Chunks[0] + if got, want := len(chunk.Labels), 1; got != want { + t.Fatalf("labels count: got %d, want %d", got, want) + } + if got, want := chunk.Labels[0], "label"; got != want { + t.Fatalf("label: got %s, want %s", got, want) + } + + mock = &MockReadRowsServer{} + req = &btpb.ReadRowsRequest{ + TableName: tblInfo.Name, + Filter: &btpb.RowFilter{ + Filter: &btpb.RowFilter_ApplyLabelTransformer{ + ApplyLabelTransformer: "", // invalid label + }, + }, + } + if err = s.ReadRows(req, mock); err == nil { + t.Fatal("ReadRows want invalid label error, got none") + } +} + +func TestCheckAndMutateRowWithoutPredicate(t *testing.T) { + s := &server{ + tables: make(map[string]*table), + } + ctx := context.Background() + newTbl := btapb.Table{ + ColumnFamilies: map[string]*btapb.ColumnFamily{ + "cf": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}}, + }, + } + tbl, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl}) + if err != nil { + t.Fatalf("Creating table: %v", err) + } + + // Populate the table + val := []byte("value") + mrreq := &btpb.MutateRowRequest{ + TableName: tbl.Name, + RowKey: []byte("row-present"), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{ + FamilyName: "cf", + ColumnQualifier: []byte("col"), + TimestampMicros: 1000, + Value: val, + }}, + }}, + } + if _, err := s.MutateRow(ctx, mrreq); err != nil { + t.Fatalf("Populating table: %v", err) + } + + req := &btpb.CheckAndMutateRowRequest{ + TableName: tbl.Name, + RowKey: []byte("row-not-present"), + } + if res, err := s.CheckAndMutateRow(ctx, req); err != nil { + t.Errorf("CheckAndMutateRow error: %v", err) + } else if got, want := res.PredicateMatched, false; got != want { + t.Errorf("Invalid PredicateMatched value: got %t, want %t", got, want) + } + + req = &btpb.CheckAndMutateRowRequest{ + TableName: tbl.Name, + RowKey: []byte("row-present"), + } + if res, err := s.CheckAndMutateRow(ctx, req); err != nil { + t.Errorf("CheckAndMutateRow error: %v", err) + } else if got, want := res.PredicateMatched, true; got != want { + t.Errorf("Invalid PredicateMatched value: got %t, want %t", got, want) + } +} + +func TestServer_ReadModifyWriteRow(t *testing.T) { + s := &server{ + tables: make(map[string]*table), + } + + ctx := context.Background() + newTbl := btapb.Table{ + ColumnFamilies: map[string]*btapb.ColumnFamily{ + "cf": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}}, + }, + } + tbl, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl}) + if err != nil { + t.Fatalf("Creating table: %v", err) + } + + req := &btpb.ReadModifyWriteRowRequest{ + TableName: tbl.Name, + RowKey: []byte("row-key"), + Rules: []*btpb.ReadModifyWriteRule{ + { + FamilyName: "cf", + ColumnQualifier: []byte("q1"), + Rule: &btpb.ReadModifyWriteRule_AppendValue{ + AppendValue: []byte("a"), + }, + }, + // multiple ops for same cell + { + FamilyName: "cf", + ColumnQualifier: []byte("q1"), + Rule: &btpb.ReadModifyWriteRule_AppendValue{ + AppendValue: []byte("b"), + }, + }, + // different cell whose qualifier should sort before the prior rules + { + FamilyName: "cf", + ColumnQualifier: []byte("q0"), + Rule: &btpb.ReadModifyWriteRule_IncrementAmount{ + IncrementAmount: 1, + }, + }, + }, + } + + got, err := s.ReadModifyWriteRow(ctx, req) + + if err != nil { + t.Fatalf("ReadModifyWriteRow error: %v", err) + } + + want := &btpb.ReadModifyWriteRowResponse{ + Row: &btpb.Row{ + Key: []byte("row-key"), + Families: []*btpb.Family{{ + Name: "cf", + Columns: []*btpb.Column{ + { + Qualifier: []byte("q0"), + Cells: []*btpb.Cell{{ + Value: []byte{0, 0, 0, 0, 0, 0, 0, 1}, + }}, + }, + { + Qualifier: []byte("q1"), + Cells: []*btpb.Cell{{ + Value: []byte("ab"), + }}, + }, + }, + }}, + }, + } + + diff := cmp.Diff(got, want, cmpopts.IgnoreFields(btpb.Cell{}, "TimestampMicros")) + if diff != "" { + t.Errorf("unexpected response: %s", diff) + } +} + +// helper function to populate table data +func populateTable(ctx context.Context, s *server) (*btapb.Table, error) { + newTbl := btapb.Table{ + ColumnFamilies: map[string]*btapb.ColumnFamily{ + "cf0": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{1}}}, + }, + } + tblInfo, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl}) + if err != nil { + return nil, err + } + count := 3 + mcf := func(i int) *btapb.ModifyColumnFamiliesRequest { + return &btapb.ModifyColumnFamiliesRequest{ + Name: tblInfo.Name, + Modifications: []*btapb.ModifyColumnFamiliesRequest_Modification{{ + Id: "cf" + strconv.Itoa(i), + Mod: &btapb.ModifyColumnFamiliesRequest_Modification_Create{&btapb.ColumnFamily{}}, + }}, + } + } + for i := 1; i <= count; i++ { + _, err = s.ModifyColumnFamilies(ctx, mcf(i)) + if err != nil { + return nil, err + } + } + // Populate the table + for fc := 0; fc < count; fc++ { + for cc := count; cc > 0; cc-- { + for tc := 0; tc < count; tc++ { + req := &btpb.MutateRowRequest{ + TableName: tblInfo.Name, + RowKey: []byte("row"), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_SetCell_{&btpb.Mutation_SetCell{ + FamilyName: "cf" + strconv.Itoa(fc), + ColumnQualifier: []byte("col" + strconv.Itoa(cc)), + TimestampMicros: int64((tc + 1) * 1000), + Value: []byte{}, + }}, + }}, + } + if _, err := s.MutateRow(ctx, req); err != nil { + return nil, err + } + } + } + } + + return tblInfo, nil +} + +func TestFilters(t *testing.T) { + tests := []struct { + in *btpb.RowFilter + out int + }{ + {in: &btpb.RowFilter{Filter: &btpb.RowFilter_BlockAllFilter{true}}, out: 0}, + {in: &btpb.RowFilter{Filter: &btpb.RowFilter_BlockAllFilter{false}}, out: 1}, + {in: &btpb.RowFilter{Filter: &btpb.RowFilter_PassAllFilter{true}}, out: 1}, + {in: &btpb.RowFilter{Filter: &btpb.RowFilter_PassAllFilter{false}}, out: 0}, + } + + ctx := context.Background() + + s := &server{ + tables: make(map[string]*table), + } + + tblInfo, err := populateTable(ctx, s) + if err != nil { + t.Fatal(err) + } + + req := &btpb.ReadRowsRequest{ + TableName: tblInfo.Name, + Rows: &btpb.RowSet{RowKeys: [][]byte{[]byte("row")}}, + } + + for _, tc := range tests { + req.Filter = tc.in + + mock := &MockReadRowsServer{} + if err = s.ReadRows(req, mock); err != nil { + t.Errorf("ReadRows error: %v", err) + continue + } + + if len(mock.responses) != tc.out { + t.Errorf("Response count: got %d, want %d", len(mock.responses), tc.out) + continue + } + } +} + +func Test_Mutation_DeleteFromColumn(t *testing.T) { + ctx := context.Background() + + s := &server{ + tables: make(map[string]*table), + } + + tblInfo, err := populateTable(ctx, s) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + in *btpb.MutateRowRequest + fail bool + }{ + {in: &btpb.MutateRowRequest{ + TableName: tblInfo.Name, + RowKey: []byte("row"), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_DeleteFromColumn_{DeleteFromColumn: &btpb.Mutation_DeleteFromColumn{ + FamilyName: "cf1", + ColumnQualifier: []byte("col1"), + TimeRange: &btpb.TimestampRange{ + StartTimestampMicros: 2000, + EndTimestampMicros: 1000, + }, + }}, + }}, + }, + fail: true, + }, + {in: &btpb.MutateRowRequest{ + TableName: tblInfo.Name, + RowKey: []byte("row"), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_DeleteFromColumn_{DeleteFromColumn: &btpb.Mutation_DeleteFromColumn{ + FamilyName: "cf2", + ColumnQualifier: []byte("col2"), + TimeRange: &btpb.TimestampRange{ + StartTimestampMicros: 1000, + EndTimestampMicros: 2000, + }, + }}, + }}, + }, + fail: false, + }, + {in: &btpb.MutateRowRequest{ + TableName: tblInfo.Name, + RowKey: []byte("row"), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_DeleteFromColumn_{DeleteFromColumn: &btpb.Mutation_DeleteFromColumn{ + FamilyName: "cf3", + ColumnQualifier: []byte("col3"), + TimeRange: &btpb.TimestampRange{ + StartTimestampMicros: 1000, + EndTimestampMicros: 0, + }, + }}, + }}, + }, + fail: false, + }, + {in: &btpb.MutateRowRequest{ + TableName: tblInfo.Name, + RowKey: []byte("row"), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_DeleteFromColumn_{DeleteFromColumn: &btpb.Mutation_DeleteFromColumn{ + FamilyName: "cf4", + ColumnQualifier: []byte("col4"), + TimeRange: &btpb.TimestampRange{ + StartTimestampMicros: 0, + EndTimestampMicros: 1000, + }, + }}, + }}, + }, + fail: true, + }, + } + + for _, tst := range tests { + _, err = s.MutateRow(ctx, tst.in) + + if err != nil && !tst.fail { + t.Errorf("expected passed got failure for : %v \n with err: %v", tst.in, err) + } + + if err == nil && tst.fail { + t.Errorf("expected failure got passed for : %v", tst) + } + } +} + +func TestFilterRow(t *testing.T) { + row := &row{ + key: "row", + families: map[string]*family{ + "fam": { + name: "fam", + cells: map[string][]cell{ + "col": {{ts: 100, value: []byte("val")}}, + }, + }, + }, + } + for _, test := range []struct { + filter *btpb.RowFilter + want bool + }{ + // The regexp-based filters perform whole-string, case-sensitive matches. + {&btpb.RowFilter{Filter: &btpb.RowFilter_RowKeyRegexFilter{[]byte("row")}}, true}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_RowKeyRegexFilter{[]byte("ro")}}, false}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_RowKeyRegexFilter{[]byte("ROW")}}, false}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_RowKeyRegexFilter{[]byte("moo")}}, false}, + + {&btpb.RowFilter{Filter: &btpb.RowFilter_FamilyNameRegexFilter{"fam"}}, true}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_FamilyNameRegexFilter{"f.*"}}, true}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_FamilyNameRegexFilter{"[fam]+"}}, true}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_FamilyNameRegexFilter{"fa"}}, false}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_FamilyNameRegexFilter{"FAM"}}, false}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_FamilyNameRegexFilter{"moo"}}, false}, + + {&btpb.RowFilter{Filter: &btpb.RowFilter_ColumnQualifierRegexFilter{[]byte("col")}}, true}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_ColumnQualifierRegexFilter{[]byte("co")}}, false}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_ColumnQualifierRegexFilter{[]byte("COL")}}, false}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_ColumnQualifierRegexFilter{[]byte("moo")}}, false}, + + {&btpb.RowFilter{Filter: &btpb.RowFilter_ValueRegexFilter{[]byte("val")}}, true}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_ValueRegexFilter{[]byte("va")}}, false}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_ValueRegexFilter{[]byte("VAL")}}, false}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_ValueRegexFilter{[]byte("moo")}}, false}, + } { + got, _ := filterRow(test.filter, row.copy()) + if got != test.want { + t.Errorf("%s: got %t, want %t", proto.CompactTextString(test.filter), got, test.want) + } + } +} + +func TestFilterRowWithErrors(t *testing.T) { + row := &row{ + key: "row", + families: map[string]*family{ + "fam": { + name: "fam", + cells: map[string][]cell{ + "col": {{ts: 100, value: []byte("val")}}, + }, + }, + }, + } + for _, test := range []struct { + badRegex *btpb.RowFilter + }{ + {&btpb.RowFilter{Filter: &btpb.RowFilter_RowKeyRegexFilter{[]byte("[")}}}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_FamilyNameRegexFilter{"["}}}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_ColumnQualifierRegexFilter{[]byte("[")}}}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_ValueRegexFilter{[]byte("[")}}}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_Chain_{ + Chain: &btpb.RowFilter_Chain{Filters: []*btpb.RowFilter{ + {Filter: &btpb.RowFilter_ValueRegexFilter{[]byte("[")}}}, + }, + }}}, + {&btpb.RowFilter{Filter: &btpb.RowFilter_Condition_{ + Condition: &btpb.RowFilter_Condition{ + PredicateFilter: &btpb.RowFilter{Filter: &btpb.RowFilter_ValueRegexFilter{[]byte("[")}}, + }, + }}}, + + {&btpb.RowFilter{Filter: &btpb.RowFilter_RowSampleFilter{0.0}}}, // 0.0 is invalid. + {&btpb.RowFilter{Filter: &btpb.RowFilter_RowSampleFilter{1.0}}}, // 1.0 is invalid. + } { + got, err := filterRow(test.badRegex, row.copy()) + if got != false { + t.Errorf("%s: got true, want false", proto.CompactTextString(test.badRegex)) + } + if err == nil { + t.Errorf("%s: got no error, want error", proto.CompactTextString(test.badRegex)) + } + } +} + +func TestFilterRowWithRowSampleFilter(t *testing.T) { + prev := randFloat + randFloat = func() float64 { return 0.5 } + defer func() { randFloat = prev }() + for _, test := range []struct { + p float64 + want bool + }{ + {0.1, false}, // Less than random float. Return no rows. + {0.5, false}, // Equal to random float. Return no rows. + {0.9, true}, // Greater than random float. Return all rows. + } { + got, err := filterRow(&btpb.RowFilter{Filter: &btpb.RowFilter_RowSampleFilter{test.p}}, &row{}) + if err != nil { + t.Fatalf("%f: %v", test.p, err) + } + if got != test.want { + t.Errorf("%v: got %t, want %t", test.p, got, test.want) + } + } +} + +func TestFilterRowWithBinaryColumnQualifier(t *testing.T) { + rs := []byte{128, 128} + row := &row{ + key: string(rs), + families: map[string]*family{ + "fam": { + name: "fam", + cells: map[string][]cell{ + string(rs): {{ts: 100, value: []byte("val")}}, + }, + }, + }, + } + for _, test := range []struct { + filter []byte + want bool + }{ + {[]byte{128, 128}, true}, // succeeds, exact match + {[]byte{128, 129}, false}, // fails + {[]byte{128}, false}, // fails, because the regexp must match the entire input + {[]byte{128, '*'}, true}, // succeeds: 0 or more 128s + {[]byte{'[', 127, 128, ']', '{', '2', '}'}, true}, // succeeds: exactly two of either 127 or 128 + } { + got, _ := filterRow(&btpb.RowFilter{Filter: &btpb.RowFilter_ColumnQualifierRegexFilter{test.filter}}, row.copy()) + if got != test.want { + t.Errorf("%v: got %t, want %t", test.filter, got, test.want) + } + } +} diff --git a/vendor/cloud.google.com/go/bigtable/cmd/cbt/cbt.go b/vendor/cloud.google.com/go/bigtable/cmd/cbt/cbt.go new file mode 100644 index 00000000..b6986d4d --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/cmd/cbt/cbt.go @@ -0,0 +1,1614 @@ +/* +Copyright 2015 Google LLC + +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 main + +// Command docs are in cbtdoc.go. + +import ( + "bytes" + "context" + "encoding/csv" + "flag" + "fmt" + "go/format" + "io" + "log" + "os" + "regexp" + "sort" + "strconv" + "strings" + "text/tabwriter" + "text/template" + "time" + + "cloud.google.com/go/bigtable" + "cloud.google.com/go/bigtable/internal/cbtconfig" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/grpc" +) + +var ( + oFlag = flag.String("o", "", "if set, redirect stdout to this file") + + config *cbtconfig.Config + client *bigtable.Client + adminClient *bigtable.AdminClient + instanceAdminClient *bigtable.InstanceAdminClient + + version = "" + revision = "" + revisionDate = "" + cliUserAgent = "cbt-cli-go/unknown" +) + +func getCredentialOpts(opts []option.ClientOption) []option.ClientOption { + if ts := config.TokenSource; ts != nil { + opts = append(opts, option.WithTokenSource(ts)) + } + if tlsCreds := config.TLSCreds; tlsCreds != nil { + opts = append(opts, option.WithGRPCDialOption(grpc.WithTransportCredentials(tlsCreds))) + } + return opts +} + +func getClient(clientConf bigtable.ClientConfig) *bigtable.Client { + if client == nil { + var opts []option.ClientOption + if ep := config.DataEndpoint; ep != "" { + opts = append(opts, option.WithEndpoint(ep)) + } + opts = append(opts, option.WithUserAgent(cliUserAgent)) + opts = getCredentialOpts(opts) + var err error + client, err = bigtable.NewClientWithConfig(context.Background(), config.Project, config.Instance, clientConf, opts...) + if err != nil { + log.Fatalf("Making bigtable.Client: %v", err) + } + } + return client +} + +func getAdminClient() *bigtable.AdminClient { + if adminClient == nil { + var opts []option.ClientOption + if ep := config.AdminEndpoint; ep != "" { + opts = append(opts, option.WithEndpoint(ep)) + } + opts = append(opts, option.WithUserAgent(cliUserAgent)) + opts = getCredentialOpts(opts) + var err error + adminClient, err = bigtable.NewAdminClient(context.Background(), config.Project, config.Instance, opts...) + if err != nil { + log.Fatalf("Making bigtable.AdminClient: %v", err) + } + } + return adminClient +} + +func getInstanceAdminClient() *bigtable.InstanceAdminClient { + if instanceAdminClient == nil { + var opts []option.ClientOption + if ep := config.AdminEndpoint; ep != "" { + opts = append(opts, option.WithEndpoint(ep)) + } + opts = getCredentialOpts(opts) + var err error + instanceAdminClient, err = bigtable.NewInstanceAdminClient(context.Background(), config.Project, opts...) + if err != nil { + log.Fatalf("Making bigtable.InstanceAdminClient: %v", err) + } + } + return instanceAdminClient +} + +func main() { + var err error + config, err = cbtconfig.Load() + if err != nil { + log.Fatal(err) + } + config.RegisterFlags() + + flag.Usage = func() { usage(os.Stderr) } + flag.Parse() + if flag.NArg() == 0 { + usage(os.Stderr) + os.Exit(1) + } + + if *oFlag != "" { + f, err := os.Create(*oFlag) + if err != nil { + log.Fatal(err) + } + defer func() { + if err := f.Close(); err != nil { + log.Fatal(err) + } + }() + os.Stdout = f + } + + if config.UserAgent != "" { + cliUserAgent = config.UserAgent + } + + ctx := context.Background() + for _, cmd := range commands { + if cmd.Name == flag.Arg(0) { + if err := config.CheckFlags(cmd.Required); err != nil { + log.Fatal(err) + } + cmd.do(ctx, flag.Args()[1:]...) + return + } + } + log.Fatalf("Unknown command %q", flag.Arg(0)) +} + +func usage(w io.Writer) { + fmt.Fprintf(w, "Usage: %s [flags] ...\n", os.Args[0]) + flag.CommandLine.SetOutput(w) + flag.CommandLine.PrintDefaults() + fmt.Fprintf(w, "\n%s", cmdSummary) +} + +var cmdSummary string // generated in init, below + +func init() { + var buf bytes.Buffer + tw := tabwriter.NewWriter(&buf, 10, 8, 4, '\t', 0) + for _, cmd := range commands { + fmt.Fprintf(tw, "cbt %s\t%s\n", cmd.Name, cmd.Desc) + } + tw.Flush() + buf.WriteString(configHelp) + buf.WriteString("\ncbt " + version + " " + revision + " " + revisionDate + "\n") + cmdSummary = buf.String() +} + +var configHelp = ` +Alpha features are not currently available to most Cloud Bigtable customers. The +features might be changed in backward-incompatible ways and are not recommended +for production use. They are not subject to any SLA or deprecation policy. + +Note: cbt does not support specifying arbitrary bytes on the command line for +any value that Bigtable otherwise supports (e.g., row key, column qualifier, +etc.). + +For convenience, values of the -project, -instance, -creds, +-admin-endpoint and -data-endpoint flags may be specified in +~/.cbtrc in this format: + + project = my-project-123 + instance = my-instance + creds = path-to-account-key.json + admin-endpoint = hostname:port + data-endpoint = hostname:port + +All values are optional, and all will be overridden by flags. +` + +var commands = []struct { + Name, Desc string + do func(context.Context, ...string) + Usage string + Required cbtconfig.RequiredFlags +}{ + { + Name: "count", + Desc: "Count rows in a table", + do: doCount, + Usage: "cbt count
", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "createinstance", + Desc: "Create an instance with an initial cluster", + do: doCreateInstance, + Usage: "cbt createinstance \n" + + " instance-id Permanent, unique id for the instance\n" + + " display-name Description of the instance\n" + + " cluster-id Permanent, unique id for the cluster in the instance\n" + + " zone The zone in which to create the cluster\n" + + " num-nodes The number of nodes to create\n" + + " storage-type SSD or HDD\n", + Required: cbtconfig.ProjectRequired, + }, + { + Name: "createcluster", + Desc: "Create a cluster in the configured instance ", + do: doCreateCluster, + Usage: "cbt createcluster \n" + + " cluster-id Permanent, unique id for the cluster in the instance\n" + + " zone The zone in which to create the cluster\n" + + " num-nodes The number of nodes to create\n" + + " storage-type SSD or HDD\n", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "createfamily", + Desc: "Create a column family", + do: doCreateFamily, + Usage: "cbt createfamily
", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "createtable", + Desc: "Create a table", + do: doCreateTable, + Usage: "cbt createtable
[families=family[:gcpolicy],...] [splits=split,...]\n" + + " families: Column families and their associated GC policies. For gcpolicy,\n" + + " see \"setgcpolicy\".\n" + + " Example: families=family1:maxage=1w,family2:maxversions=1\n" + + " splits: Row key to be used to initially split the table", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "updatecluster", + Desc: "Update a cluster in the configured instance", + do: doUpdateCluster, + Usage: "cbt updatecluster [num-nodes=num-nodes]\n" + + " cluster-id Permanent, unique id for the cluster in the instance\n" + + " num-nodes The number of nodes to update to", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "deleteinstance", + Desc: "Delete an instance", + do: doDeleteInstance, + Usage: "cbt deleteinstance ", + Required: cbtconfig.ProjectRequired, + }, + { + Name: "deletecluster", + Desc: "Delete a cluster from the configured instance ", + do: doDeleteCluster, + Usage: "cbt deletecluster ", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "deletecolumn", + Desc: "Delete all cells in a column", + do: doDeleteColumn, + Usage: "cbt deletecolumn
[app-profile=]\n" + + " app-profile= The app profile id to use for the request\n", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "deletefamily", + Desc: "Delete a column family", + do: doDeleteFamily, + Usage: "cbt deletefamily
", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "deleterow", + Desc: "Delete a row", + do: doDeleteRow, + Usage: "cbt deleterow
[app-profile=]\n" + + " app-profile= The app profile id to use for the request\n", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "deletetable", + Desc: "Delete a table", + do: doDeleteTable, + Usage: "cbt deletetable
", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "doc", + Desc: "Print godoc-suitable documentation for cbt", + do: doDoc, + Usage: "cbt doc", + Required: cbtconfig.NoneRequired, + }, + { + Name: "help", + Desc: "Print help text", + do: doHelp, + Usage: "cbt help [command]", + Required: cbtconfig.NoneRequired, + }, + { + Name: "listinstances", + Desc: "List instances in a project", + do: doListInstances, + Usage: "cbt listinstances", + Required: cbtconfig.ProjectRequired, + }, + { + Name: "listclusters", + Desc: "List clusters in an instance", + do: doListClusters, + Usage: "cbt listclusters", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "lookup", + Desc: "Read from a single row", + do: doLookup, + Usage: "cbt lookup
[columns=[family]:[qualifier],...] [cells-per-column=] " + + "[app-profile=]\n" + + " columns=[family]:[qualifier],... Read only these columns, comma-separated\n" + + " cells-per-column= Read only this many cells per column\n" + + " app-profile= The app profile id to use for the request\n", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "ls", + Desc: "List tables and column families", + do: doLS, + Usage: "cbt ls List tables\n" + + "cbt ls
List column families in
", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "mddoc", + Desc: "Print documentation for cbt in Markdown format", + do: doMDDoc, + Usage: "cbt mddoc", + Required: cbtconfig.NoneRequired, + }, + { + Name: "read", + Desc: "Read rows", + do: doRead, + Usage: "cbt read
[start=] [end=] [prefix=]" + + " [regex=] [columns=[family]:[qualifier],...] [count=] [cells-per-column=]" + + " [app-profile=]\n" + + " start= Start reading at this row\n" + + " end= Stop reading before this row\n" + + " prefix= Read rows with this prefix\n" + + " regex= Read rows with keys matching this regex\n" + + " columns=[family]:[qualifier],... Read only these columns, comma-separated\n" + + " count= Read only this many rows\n" + + " cells-per-column= Read only this many cells per column\n" + + " app-profile= The app profile id to use for the request\n", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "set", + Desc: "Set value of a cell", + do: doSet, + Usage: "cbt set
[app-profile=] family:column=val[@ts] ...\n" + + " app-profile= The app profile id to use for the request\n" + + " family:column=val[@ts] may be repeated to set multiple cells.\n" + + "\n" + + " ts is an optional integer timestamp.\n" + + " If it cannot be parsed, the `@ts` part will be\n" + + " interpreted as part of the value.", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "setgcpolicy", + Desc: "Set the GC policy for a column family", + do: doSetGCPolicy, + Usage: "cbt setgcpolicy
((maxage= | maxversions=) [(and|or) (maxage= | maxversions=),...] | never)\n" + + "\n" + + ` maxage= Maximum timestamp age to preserve (e.g. "1h", "4d")` + "\n" + + " maxversions= Maximum number of versions to preserve", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "waitforreplication", + Desc: "Block until all the completed writes have been replicated to all the clusters", + do: doWaitForReplicaiton, + Usage: "cbt waitforreplication
", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "createtablefromsnapshot", + Desc: "Create a table from a snapshot (snapshots alpha)", + do: doCreateTableFromSnapshot, + Usage: "cbt createtablefromsnapshot
\n" + + " table The name of the table to create\n" + + " cluster The cluster where the snapshot is located\n" + + " snapshot The snapshot to restore", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "createsnapshot", + Desc: "Create a snapshot from a source table (snapshots alpha)", + do: doSnapshotTable, + Usage: "cbt createsnapshot
[ttl=]\n" + + "\n" + + ` [ttl=] Lifespan of the snapshot (e.g. "1h", "4d")` + "\n", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "listsnapshots", + Desc: "List snapshots in a cluster (snapshots alpha)", + do: doListSnapshots, + Usage: "cbt listsnapshots []", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "getsnapshot", + Desc: "Get snapshot info (snapshots alpha)", + do: doGetSnapshot, + Usage: "cbt getsnapshot ", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "deletesnapshot", + Desc: "Delete snapshot in a cluster (snapshots alpha)", + do: doDeleteSnapshot, + Usage: "cbt deletesnapshot ", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "version", + Desc: "Print the current cbt version", + do: doVersion, + Usage: "cbt version", + Required: cbtconfig.NoneRequired, + }, + { + Name: "createappprofile", + Desc: "Creates app profile for an instance", + do: doCreateAppProfile, + Usage: "usage: cbt createappprofile " + + "(route-any | [ route-to= : transactional-writes]) [optional flag] \n" + + "optional flags may be `force`", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "getappprofile", + Desc: "Reads app profile for an instance", + do: doGetAppProfile, + Usage: "cbt getappprofile ", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "listappprofile", + Desc: "Lists app profile for an instance", + do: doListAppProfiles, + Usage: "cbt listappprofile ", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "updateappprofile", + Desc: "Updates app profile for an instance", + do: doUpdateAppProfile, + Usage: "usage: cbt updateappprofile " + + "(route-any | [ route-to= : transactional-writes]) [optional flag] \n" + + "optional flags may be `force`", + Required: cbtconfig.ProjectAndInstanceRequired, + }, + { + Name: "deleteappprofile", + Desc: "Deletes app profile for an instance", + do: doDeleteAppProfile, + Usage: "cbt deleteappprofile ", + Required: cbtconfig.ProjectAndInstanceRequired, + }, +} + +func doCount(ctx context.Context, args ...string) { + if len(args) != 1 { + log.Fatal("usage: cbt count
") + } + tbl := getClient(bigtable.ClientConfig{}).Open(args[0]) + + n := 0 + err := tbl.ReadRows(ctx, bigtable.InfiniteRange(""), func(_ bigtable.Row) bool { + n++ + return true + }, bigtable.RowFilter(bigtable.StripValueFilter())) + if err != nil { + log.Fatalf("Reading rows: %v", err) + } + fmt.Println(n) +} + +func doCreateTable(ctx context.Context, args ...string) { + if len(args) < 1 { + log.Fatal("usage: cbt createtable
[families=family[:gcpolicy],...] [splits=split,...]") + } + + tblConf := bigtable.TableConf{TableID: args[0]} + parsed, err := parseArgs(args[1:], []string{"families", "splits"}) + if err != nil { + log.Fatal(err) + } + for key, val := range parsed { + chunks, err := csv.NewReader(strings.NewReader(val)).Read() + if err != nil { + log.Fatalf("Invalid %s arg format: %v", key, err) + } + switch key { + case "families": + tblConf.Families = make(map[string]bigtable.GCPolicy) + for _, family := range chunks { + famPolicy := strings.Split(family, ":") + var gcPolicy bigtable.GCPolicy + if len(famPolicy) < 2 { + gcPolicy = bigtable.MaxVersionsPolicy(1) + log.Printf("Using default GC Policy of %v for family %v", gcPolicy, family) + } else { + gcPolicy, err = parseGCPolicy(famPolicy[1]) + if err != nil { + log.Fatal(err) + } + } + tblConf.Families[famPolicy[0]] = gcPolicy + } + case "splits": + tblConf.SplitKeys = chunks + } + } + + if err := getAdminClient().CreateTableFromConf(ctx, &tblConf); err != nil { + log.Fatalf("Creating table: %v", err) + } +} + +func doCreateFamily(ctx context.Context, args ...string) { + if len(args) != 2 { + log.Fatal("usage: cbt createfamily
") + } + err := getAdminClient().CreateColumnFamily(ctx, args[0], args[1]) + if err != nil { + log.Fatalf("Creating column family: %v", err) + } +} + +func doCreateInstance(ctx context.Context, args ...string) { + if len(args) < 6 { + log.Fatal("cbt createinstance ") + } + + numNodes, err := strconv.ParseInt(args[4], 0, 32) + if err != nil { + log.Fatalf("Bad num-nodes %q: %v", args[4], err) + } + + sType, err := parseStorageType(args[5]) + if err != nil { + log.Fatal(err) + } + + ic := bigtable.InstanceWithClustersConfig{ + InstanceID: args[0], + DisplayName: args[1], + Clusters: []bigtable.ClusterConfig{{ + ClusterID: args[2], + Zone: args[3], + NumNodes: int32(numNodes), + StorageType: sType, + }}, + } + err = getInstanceAdminClient().CreateInstanceWithClusters(ctx, &ic) + if err != nil { + log.Fatalf("Creating instance: %v", err) + } +} + +func doCreateCluster(ctx context.Context, args ...string) { + if len(args) < 4 { + log.Fatal("usage: cbt createcluster ") + } + + numNodes, err := strconv.ParseInt(args[2], 0, 32) + if err != nil { + log.Fatalf("Bad num_nodes %q: %v", args[2], err) + } + + sType, err := parseStorageType(args[3]) + if err != nil { + log.Fatal(err) + } + + cc := bigtable.ClusterConfig{ + InstanceID: config.Instance, + ClusterID: args[0], + Zone: args[1], + NumNodes: int32(numNodes), + StorageType: sType, + } + err = getInstanceAdminClient().CreateCluster(ctx, &cc) + if err != nil { + log.Fatalf("Creating cluster: %v", err) + } +} + +func doUpdateCluster(ctx context.Context, args ...string) { + if len(args) < 2 { + log.Fatal("cbt updatecluster [num-nodes=num-nodes]") + } + + numNodes := int64(0) + parsed, err := parseArgs(args[1:], []string{"num-nodes"}) + if err != nil { + log.Fatal(err) + } + if val, ok := parsed["num-nodes"]; ok { + numNodes, err = strconv.ParseInt(val, 0, 32) + if err != nil { + log.Fatalf("Bad num-nodes %q: %v", val, err) + } + } + if numNodes > 0 { + err = getInstanceAdminClient().UpdateCluster(ctx, config.Instance, args[0], int32(numNodes)) + if err != nil { + log.Fatalf("Updating cluster: %v", err) + } + } else { + log.Fatal("Updating cluster: nothing to update") + } +} + +func doDeleteInstance(ctx context.Context, args ...string) { + if len(args) != 1 { + log.Fatal("usage: cbt deleteinstance ") + } + err := getInstanceAdminClient().DeleteInstance(ctx, args[0]) + if err != nil { + log.Fatalf("Deleting instance: %v", err) + } +} + +func doDeleteCluster(ctx context.Context, args ...string) { + if len(args) != 1 { + log.Fatal("usage: cbt deletecluster ") + } + err := getInstanceAdminClient().DeleteCluster(ctx, config.Instance, args[0]) + if err != nil { + log.Fatalf("Deleting cluster: %v", err) + } +} + +func doDeleteColumn(ctx context.Context, args ...string) { + usage := "usage: cbt deletecolumn
[app-profile=]" + if len(args) != 4 && len(args) != 5 { + log.Fatal(usage) + } + var appProfile string + if len(args) == 5 { + if !strings.HasPrefix(args[4], "app-profile=") { + log.Fatal(usage) + } + appProfile = strings.Split(args[4], "=")[1] + } + tbl := getClient(bigtable.ClientConfig{AppProfile: appProfile}).Open(args[0]) + mut := bigtable.NewMutation() + mut.DeleteCellsInColumn(args[2], args[3]) + if err := tbl.Apply(ctx, args[1], mut); err != nil { + log.Fatalf("Deleting cells in column: %v", err) + } +} + +func doDeleteFamily(ctx context.Context, args ...string) { + if len(args) != 2 { + log.Fatal("usage: cbt deletefamily
") + } + err := getAdminClient().DeleteColumnFamily(ctx, args[0], args[1]) + if err != nil { + log.Fatalf("Deleting column family: %v", err) + } +} + +func doDeleteRow(ctx context.Context, args ...string) { + usage := "usage: cbt deleterow
[app-profile=]" + if len(args) != 2 && len(args) != 3 { + log.Fatal(usage) + } + var appProfile string + if len(args) == 3 { + if !strings.HasPrefix(args[2], "app-profile=") { + log.Fatal(usage) + } + appProfile = strings.Split(args[2], "=")[1] + } + tbl := getClient(bigtable.ClientConfig{AppProfile: appProfile}).Open(args[0]) + mut := bigtable.NewMutation() + mut.DeleteRow() + if err := tbl.Apply(ctx, args[1], mut); err != nil { + log.Fatalf("Deleting row: %v", err) + } +} + +func doDeleteTable(ctx context.Context, args ...string) { + if len(args) != 1 { + log.Fatalf("Can't do `cbt deletetable %s`", args) + } + err := getAdminClient().DeleteTable(ctx, args[0]) + if err != nil { + log.Fatalf("Deleting table: %v", err) + } +} + +// to break circular dependencies +var ( + doDocFn func(ctx context.Context, args ...string) + doHelpFn func(ctx context.Context, args ...string) + doMDDocFn func(ctx context.Context, args ...string) +) + +func init() { + doDocFn = doDocReal + doHelpFn = doHelpReal + doMDDocFn = doMDDocReal +} + +func doDoc(ctx context.Context, args ...string) { doDocFn(ctx, args...) } +func doHelp(ctx context.Context, args ...string) { doHelpFn(ctx, args...) } +func doMDDoc(ctx context.Context, args ...string) { doMDDocFn(ctx, args...) } + +func docFlags() []*flag.Flag { + // Only include specific flags, in a specific order. + var flags []*flag.Flag + for _, name := range []string{"project", "instance", "creds"} { + f := flag.Lookup(name) + if f == nil { + log.Fatalf("Flag not linked: -%s", name) + } + flags = append(flags, f) + } + return flags +} + +func doDocReal(ctx context.Context, args ...string) { + data := map[string]interface{}{ + "Commands": commands, + "Flags": docFlags(), + "ConfigHelp": configHelp, + } + var buf bytes.Buffer + if err := docTemplate.Execute(&buf, data); err != nil { + log.Fatalf("Bad doc template: %v", err) + } + out, err := format.Source(buf.Bytes()) + if err != nil { + log.Fatalf("Bad doc output: %v", err) + } + os.Stdout.Write(out) +} + +func indentLines(s, ind string) string { + ss := strings.Split(s, "\n") + for i, p := range ss { + ss[i] = ind + p + } + return strings.Join(ss, "\n") +} + +var docTemplate = template.Must(template.New("doc").Funcs(template.FuncMap{ + "indent": indentLines, +}). + Parse(` +// Copyright 2016 Google LLC +// +// 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. + +// DO NOT EDIT. THIS IS AUTOMATICALLY GENERATED. +// Run "go generate" to regenerate. +//go:generate go run cbt.go gcpolicy.go -o cbtdoc.go doc + +/* +Cbt is a tool for doing basic interactions with Cloud Bigtable. To learn how to +install the cbt tool, see the +[cbt overview](https://cloud.google.com/bigtable/docs/cbt-overview). + +Usage: + + cbt [options] command [arguments] + +The commands are: +{{range .Commands}} + {{printf "%-25s %s" .Name .Desc}}{{end}} + +Use "cbt help " for more information about a command. + +The options are: +{{range .Flags}} + -{{.Name}} string + {{.Usage}}{{end}} + +{{.ConfigHelp}} + +{{range .Commands}} +{{.Desc}} + +Usage: +{{indent .Usage "\t"}} + + + +{{end}} +*/ +package main +`)) + +func doHelpReal(ctx context.Context, args ...string) { + if len(args) == 0 { + usage(os.Stdout) + return + } + for _, cmd := range commands { + if cmd.Name == args[0] { + fmt.Println(cmd.Usage) + return + } + } + log.Fatalf("Don't know command %q", args[0]) +} + +func doListInstances(ctx context.Context, args ...string) { + if len(args) != 0 { + log.Fatalf("usage: cbt listinstances") + } + is, err := getInstanceAdminClient().Instances(ctx) + if err != nil { + log.Fatalf("Getting list of instances: %v", err) + } + tw := tabwriter.NewWriter(os.Stdout, 10, 8, 4, '\t', 0) + fmt.Fprintf(tw, "Instance Name\tInfo\n") + fmt.Fprintf(tw, "-------------\t----\n") + for _, i := range is { + fmt.Fprintf(tw, "%s\t%s\n", i.Name, i.DisplayName) + } + tw.Flush() +} + +func doListClusters(ctx context.Context, args ...string) { + if len(args) != 0 { + log.Fatalf("usage: cbt listclusters") + } + cis, err := getInstanceAdminClient().Clusters(ctx, config.Instance) + if err != nil { + log.Fatalf("Getting list of clusters: %v", err) + } + tw := tabwriter.NewWriter(os.Stdout, 10, 8, 4, '\t', 0) + fmt.Fprintf(tw, "Cluster Name\tZone\tState\n") + fmt.Fprintf(tw, "------------\t----\t----\n") + for _, ci := range cis { + fmt.Fprintf(tw, "%s\t%s\t%s (%d serve nodes)\n", ci.Name, ci.Zone, ci.State, ci.ServeNodes) + } + tw.Flush() +} + +func doLookup(ctx context.Context, args ...string) { + if len(args) < 2 { + log.Fatalf("usage: cbt lookup
[columns=...] [cells-per-column=] " + + "[app-profile=]") + } + + parsed, err := parseArgs(args[2:], []string{"columns", "cells-per-column", "app-profile"}) + if err != nil { + log.Fatal(err) + } + var opts []bigtable.ReadOption + var filters []bigtable.Filter + if cellsPerColumn := parsed["cells-per-column"]; cellsPerColumn != "" { + n, err := strconv.Atoi(cellsPerColumn) + if err != nil { + log.Fatalf("Bad number of cells per column %q: %v", cellsPerColumn, err) + } + filters = append(filters, bigtable.LatestNFilter(n)) + } + if columns := parsed["columns"]; columns != "" { + columnFilters, err := parseColumnsFilter(columns) + if err != nil { + log.Fatal(err) + } + filters = append(filters, columnFilters) + } + + if len(filters) > 1 { + opts = append(opts, bigtable.RowFilter(bigtable.ChainFilters(filters...))) + } else if len(filters) == 1 { + opts = append(opts, bigtable.RowFilter(filters[0])) + } + + table, row := args[0], args[1] + tbl := getClient(bigtable.ClientConfig{AppProfile: parsed["app-profile"]}).Open(table) + r, err := tbl.ReadRow(ctx, row, opts...) + if err != nil { + log.Fatalf("Reading row: %v", err) + } + printRow(r) +} + +func printRow(r bigtable.Row) { + fmt.Println(strings.Repeat("-", 40)) + fmt.Println(r.Key()) + + var fams []string + for fam := range r { + fams = append(fams, fam) + } + sort.Strings(fams) + for _, fam := range fams { + ris := r[fam] + sort.Sort(byColumn(ris)) + for _, ri := range ris { + ts := time.Unix(0, int64(ri.Timestamp)*1e3) + fmt.Printf(" %-40s @ %s\n", ri.Column, ts.Format("2006/01/02-15:04:05.000000")) + fmt.Printf(" %q\n", ri.Value) + } + } +} + +type byColumn []bigtable.ReadItem + +func (b byColumn) Len() int { return len(b) } +func (b byColumn) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byColumn) Less(i, j int) bool { return b[i].Column < b[j].Column } + +type byFamilyName []bigtable.FamilyInfo + +func (b byFamilyName) Len() int { return len(b) } +func (b byFamilyName) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byFamilyName) Less(i, j int) bool { return b[i].Name < b[j].Name } + +func doLS(ctx context.Context, args ...string) { + switch len(args) { + default: + log.Fatalf("Can't do `cbt ls %s`", args) + case 0: + tables, err := getAdminClient().Tables(ctx) + if err != nil { + log.Fatalf("Getting list of tables: %v", err) + } + sort.Strings(tables) + for _, table := range tables { + fmt.Println(table) + } + case 1: + table := args[0] + ti, err := getAdminClient().TableInfo(ctx, table) + if err != nil { + log.Fatalf("Getting table info: %v", err) + } + sort.Sort(byFamilyName(ti.FamilyInfos)) + tw := tabwriter.NewWriter(os.Stdout, 10, 8, 4, '\t', 0) + fmt.Fprintf(tw, "Family Name\tGC Policy\n") + fmt.Fprintf(tw, "-----------\t---------\n") + for _, fam := range ti.FamilyInfos { + fmt.Fprintf(tw, "%s\t%s\n", fam.Name, fam.GCPolicy) + } + tw.Flush() + } +} + +func doMDDocReal(ctx context.Context, args ...string) { + data := map[string]interface{}{ + "Commands": commands, + "Flags": docFlags(), + "ConfigHelp": configHelp, + } + var buf bytes.Buffer + if err := mddocTemplate.Execute(&buf, data); err != nil { + log.Fatalf("Bad mddoc template: %v", err) + } + io.Copy(os.Stdout, &buf) +} + +var mddocTemplate = template.Must(template.New("mddoc").Funcs(template.FuncMap{ + "indent": indentLines, +}). + Parse(` +Cbt is a tool for doing basic interactions with Cloud Bigtable. To learn how to +install the cbt tool, see the +[cbt overview](https://cloud.google.com/bigtable/docs/cbt-overview). + +Usage: + + cbt [options] command [arguments] + +The commands are: +{{range .Commands}} + {{printf "%-25s %s" .Name .Desc}}{{end}} + +Use "cbt help " for more information about a command. + +The options are: +{{range .Flags}} + -{{.Name}} string + {{.Usage}}{{end}} + +{{.ConfigHelp}} + +{{range .Commands}} +## {{.Desc}} + +{{indent .Usage "\t"}} + + + +{{end}} +`)) + +func doRead(ctx context.Context, args ...string) { + if len(args) < 1 { + log.Fatalf("usage: cbt read
[args ...]") + } + + parsed, err := parseArgs(args[1:], []string{ + "start", "end", "prefix", "columns", "count", "cells-per-column", "regex", "app-profile", "limit", + }) + if err != nil { + log.Fatal(err) + } + if _, ok := parsed["limit"]; ok { + // Be nicer; we used to support this, but renamed it to "end". + log.Fatal("Unknown arg key 'limit'; did you mean 'end'?") + } + if (parsed["start"] != "" || parsed["end"] != "") && parsed["prefix"] != "" { + log.Fatal(`"start"/"end" may not be mixed with "prefix"`) + } + + var rr bigtable.RowRange + if start, end := parsed["start"], parsed["end"]; end != "" { + rr = bigtable.NewRange(start, end) + } else if start != "" { + rr = bigtable.InfiniteRange(start) + } + if prefix := parsed["prefix"]; prefix != "" { + rr = bigtable.PrefixRange(prefix) + } + + var opts []bigtable.ReadOption + if count := parsed["count"]; count != "" { + n, err := strconv.ParseInt(count, 0, 64) + if err != nil { + log.Fatalf("Bad count %q: %v", count, err) + } + opts = append(opts, bigtable.LimitRows(n)) + } + + var filters []bigtable.Filter + if cellsPerColumn := parsed["cells-per-column"]; cellsPerColumn != "" { + n, err := strconv.Atoi(cellsPerColumn) + if err != nil { + log.Fatalf("Bad number of cells per column %q: %v", cellsPerColumn, err) + } + filters = append(filters, bigtable.LatestNFilter(n)) + } + if regex := parsed["regex"]; regex != "" { + filters = append(filters, bigtable.RowKeyFilter(regex)) + } + if columns := parsed["columns"]; columns != "" { + columnFilters, err := parseColumnsFilter(columns) + if err != nil { + log.Fatal(err) + } + filters = append(filters, columnFilters) + } + + if len(filters) > 1 { + opts = append(opts, bigtable.RowFilter(bigtable.ChainFilters(filters...))) + } else if len(filters) == 1 { + opts = append(opts, bigtable.RowFilter(filters[0])) + } + + // TODO(dsymonds): Support filters. + tbl := getClient(bigtable.ClientConfig{AppProfile: parsed["app-profile"]}).Open(args[0]) + err = tbl.ReadRows(ctx, rr, func(r bigtable.Row) bool { + printRow(r) + return true + }, opts...) + if err != nil { + log.Fatalf("Reading rows: %v", err) + } +} + +var setArg = regexp.MustCompile(`([^:]+):([^=]*)=(.*)`) + +func doSet(ctx context.Context, args ...string) { + if len(args) < 3 { + log.Fatalf("usage: cbt set
[app-profile=] family:[column]=val[@ts] ...") + } + var appProfile string + row := args[1] + mut := bigtable.NewMutation() + for _, arg := range args[2:] { + if strings.HasPrefix(arg, "app-profile=") { + appProfile = strings.Split(arg, "=")[1] + continue + } + m := setArg.FindStringSubmatch(arg) + if m == nil { + log.Fatalf("Bad set arg %q", arg) + } + val := m[3] + ts := bigtable.Now() + if i := strings.LastIndex(val, "@"); i >= 0 { + // Try parsing a timestamp. + n, err := strconv.ParseInt(val[i+1:], 0, 64) + if err == nil { + val = val[:i] + ts = bigtable.Timestamp(n) + } + } + mut.Set(m[1], m[2], ts, []byte(val)) + } + tbl := getClient(bigtable.ClientConfig{AppProfile: appProfile}).Open(args[0]) + if err := tbl.Apply(ctx, row, mut); err != nil { + log.Fatalf("Applying mutation: %v", err) + } +} + +func doSetGCPolicy(ctx context.Context, args ...string) { + if len(args) < 3 { + log.Fatalf("usage: cbt setgcpolicy
((maxage= | maxversions=) [(and|or) (maxage= | maxversions=),...] | never)") + } + table := args[0] + fam := args[1] + pol, err := parseGCPolicy(strings.Join(args[2:], " ")) + if err != nil { + log.Fatal(err) + } + if err := getAdminClient().SetGCPolicy(ctx, table, fam, pol); err != nil { + log.Fatalf("Setting GC policy: %v", err) + } +} + +func doWaitForReplicaiton(ctx context.Context, args ...string) { + if len(args) != 1 { + log.Fatalf("usage: cbt waitforreplication
") + } + table := args[0] + + fmt.Printf("Waiting for all writes up to %s to be replicated.\n", time.Now().Format("2006/01/02-15:04:05")) + if err := getAdminClient().WaitForReplication(ctx, table); err != nil { + log.Fatalf("Waiting for replication: %v", err) + } +} + +func parseStorageType(storageTypeStr string) (bigtable.StorageType, error) { + switch storageTypeStr { + case "SSD": + return bigtable.SSD, nil + case "HDD": + return bigtable.HDD, nil + } + return -1, fmt.Errorf("Invalid storage type: %v, must be SSD or HDD", storageTypeStr) +} + +func doCreateTableFromSnapshot(ctx context.Context, args ...string) { + if len(args) != 3 { + log.Fatal("usage: cbt createtablefromsnapshot
") + } + tableName := args[0] + clusterName := args[1] + snapshotName := args[2] + err := getAdminClient().CreateTableFromSnapshot(ctx, tableName, clusterName, snapshotName) + + if err != nil { + log.Fatalf("Creating table: %v", err) + } +} + +func doSnapshotTable(ctx context.Context, args ...string) { + if len(args) != 3 && len(args) != 4 { + log.Fatal("usage: cbt createsnapshot
[ttl=]") + } + clusterName := args[0] + snapshotName := args[1] + tableName := args[2] + ttl := bigtable.DefaultSnapshotDuration + + parsed, err := parseArgs(args[3:], []string{"ttl"}) + if err != nil { + log.Fatal(err) + } + if val, ok := parsed["ttl"]; ok { + var err error + ttl, err = parseDuration(val) + if err != nil { + log.Fatalf("Invalid snapshot ttl value %q: %v", val, err) + } + } + + err = getAdminClient().SnapshotTable(ctx, tableName, clusterName, snapshotName, ttl) + if err != nil { + log.Fatalf("Failed to create Snapshot: %v", err) + } +} + +func doListSnapshots(ctx context.Context, args ...string) { + if len(args) != 0 && len(args) != 1 { + log.Fatal("usage: cbt listsnapshots []") + } + + var cluster string + + if len(args) == 0 { + cluster = "-" + } else { + cluster = args[0] + } + + it := getAdminClient().Snapshots(ctx, cluster) + + tw := tabwriter.NewWriter(os.Stdout, 10, 8, 4, '\t', 0) + fmt.Fprintf(tw, "Snapshot\tSource Table\tCreated At\tExpires At\n") + fmt.Fprintf(tw, "--------\t------------\t----------\t----------\n") + timeLayout := "2006-01-02 15:04 MST" + + for { + snapshot, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + log.Fatalf("Failed to fetch snapshots %v", err) + } + fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", snapshot.Name, snapshot.SourceTable, snapshot.CreateTime.Format(timeLayout), snapshot.DeleteTime.Format(timeLayout)) + } + tw.Flush() +} + +func doGetSnapshot(ctx context.Context, args ...string) { + if len(args) != 2 { + log.Fatalf("usage: cbt getsnapshot ") + } + clusterName := args[0] + snapshotName := args[1] + + snapshot, err := getAdminClient().SnapshotInfo(ctx, clusterName, snapshotName) + if err != nil { + log.Fatalf("Failed to get snapshot: %v", err) + } + + timeLayout := "2006-01-02 15:04 MST" + + fmt.Printf("Name: %s\n", snapshot.Name) + fmt.Printf("Source table: %s\n", snapshot.SourceTable) + fmt.Printf("Created at: %s\n", snapshot.CreateTime.Format(timeLayout)) + fmt.Printf("Expires at: %s\n", snapshot.DeleteTime.Format(timeLayout)) +} + +func doDeleteSnapshot(ctx context.Context, args ...string) { + if len(args) != 2 { + log.Fatal("usage: cbt deletesnapshot ") + } + cluster := args[0] + snapshot := args[1] + + err := getAdminClient().DeleteSnapshot(ctx, cluster, snapshot) + + if err != nil { + log.Fatalf("Failed to delete snapshot: %v", err) + } +} + +func doCreateAppProfile(ctx context.Context, args ...string) { + if len(args) < 4 || len(args) > 6 { + log.Fatal("usage: cbt createappprofile " + + " (route-any | [ route-to= : transactional-writes]) [optional flag] \n" + + "optional flags may be `force`") + } + + routingPolicy, clusterID, err := parseProfileRoute(args[3]) + if err != nil { + log.Fatalln("Exactly one of (route-any | [route-to : transactional-writes]) must be specified.") + } + + config := bigtable.ProfileConf{ + RoutingPolicy: routingPolicy, + InstanceID: args[0], + ProfileID: args[1], + Description: args[2], + } + + opFlags := []string{"force", "transactional-writes"} + parseValues, err := parseArgs(args[4:], opFlags) + if err != nil { + log.Fatalf("optional flags can be specified as (force=|transactional-writes=) got %s ", args[4:]) + } + + for _, f := range opFlags { + fv, err := parseProfileOpts(f, parseValues) + if err != nil { + log.Fatalf("optional flags can be specified as (force=|transactional-writes=) got %s ", args[4:]) + } + + switch f { + case opFlags[0]: + config.IgnoreWarnings = fv + case opFlags[1]: + config.AllowTransactionalWrites = fv + default: + + } + } + + if routingPolicy == bigtable.SingleClusterRouting { + config.ClusterID = clusterID + } + + profile, err := getInstanceAdminClient().CreateAppProfile(ctx, config) + if err != nil { + log.Fatalf("Failed to create app profile : %v", err) + } + + fmt.Printf("Name: %s\n", profile.Name) + fmt.Printf("RoutingPolicy: %v\n", profile.RoutingPolicy) +} + +func doGetAppProfile(ctx context.Context, args ...string) { + if len(args) != 2 { + log.Fatalln("usage: cbt getappprofile ") + } + + instanceID := args[0] + profileID := args[1] + profile, err := getInstanceAdminClient().GetAppProfile(ctx, instanceID, profileID) + if err != nil { + log.Fatalf("Failed to get app profile : %v", err) + } + + fmt.Printf("Name: %s\n", profile.Name) + fmt.Printf("Etag: %s\n", profile.Etag) + fmt.Printf("Description: %s\n", profile.Description) + fmt.Printf("RoutingPolicy: %v\n", profile.RoutingPolicy) +} + +func doListAppProfiles(ctx context.Context, args ...string) { + if len(args) != 1 { + log.Fatalln("usage: cbt listappprofile ") + } + + instance := args[0] + + it := getInstanceAdminClient().ListAppProfiles(ctx, instance) + + tw := tabwriter.NewWriter(os.Stdout, 10, 8, 4, '\t', 0) + fmt.Fprintf(tw, "AppProfile\tProfile Description\tProfile Etag\tProfile Routing Policy\n") + fmt.Fprintf(tw, "-----------\t--------------------\t------------\t----------------------\n") + + for { + profile, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + log.Fatalf("Failed to fetch app profile %v", err) + } + fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n", profile.Name, profile.Description, profile.Etag, profile.RoutingPolicy) + } + tw.Flush() +} + +func doUpdateAppProfile(ctx context.Context, args ...string) { + + if len(args) < 4 { + log.Fatal("usage: cbt updateappprofile " + + " (route-any | [ route-to= : transactional-writes]) [optional flag] \n" + + "optional flags may be `force`") + } + + routingPolicy, clusterID, err := parseProfileRoute(args[3]) + if err != nil { + log.Fatalln("Exactly one of (route-any | [route-to : transactional-writes]) must be specified.") + } + InstanceID := args[0] + ProfileID := args[1] + config := bigtable.ProfileAttrsToUpdate{ + RoutingPolicy: routingPolicy, + Description: args[2], + } + opFlags := []string{"force", "transactional-writes"} + parseValues, err := parseArgs(args[4:], opFlags) + if err != nil { + log.Fatalf("optional flags can be specified as (force=|transactional-writes=) got %s ", args[4:]) + } + + for _, f := range opFlags { + fv, err := parseProfileOpts(f, parseValues) + if err != nil { + log.Fatalf("optional flags can be specified as (force=|transactional-writes=) got %s ", args[4:]) + } + + switch f { + case opFlags[0]: + config.IgnoreWarnings = fv + case opFlags[1]: + config.AllowTransactionalWrites = fv + default: + + } + } + if routingPolicy == bigtable.SingleClusterRouting { + config.ClusterID = clusterID + } + + err = getInstanceAdminClient().UpdateAppProfile(ctx, InstanceID, ProfileID, config) + if err != nil { + log.Fatalf("Failed to update app profile : %v", err) + } +} + +func doDeleteAppProfile(ctx context.Context, args ...string) { + if len(args) != 2 { + log.Println("usage: cbt deleteappprofile ") + } + + err := getInstanceAdminClient().DeleteAppProfile(ctx, args[0], args[1]) + if err != nil { + log.Fatalf("Failed to delete app profile : %v", err) + } +} + +// parseDuration parses a duration string. +// It is similar to Go's time.ParseDuration, except with a different set of supported units, +// and only simple formats supported. +func parseDuration(s string) (time.Duration, error) { + // [0-9]+[a-z]+ + + // Split [0-9]+ from [a-z]+. + i := 0 + for ; i < len(s); i++ { + c := s[i] + if c < '0' || c > '9' { + break + } + } + ds, u := s[:i], s[i:] + if ds == "" || u == "" { + return 0, fmt.Errorf("invalid duration %q", s) + } + // Parse them. + d, err := strconv.ParseUint(ds, 10, 32) + if err != nil { + return 0, fmt.Errorf("invalid duration %q: %v", s, err) + } + unit, ok := unitMap[u] + if !ok { + return 0, fmt.Errorf("unknown unit %q in duration %q", u, s) + } + if d > uint64((1<<63-1)/unit) { + // overflow + return 0, fmt.Errorf("invalid duration %q overflows", s) + } + return time.Duration(d) * unit, nil +} + +var unitMap = map[string]time.Duration{ + "ms": time.Millisecond, + "s": time.Second, + "m": time.Minute, + "h": time.Hour, + "d": 24 * time.Hour, +} + +func doVersion(ctx context.Context, args ...string) { + fmt.Printf("%s %s %s\n", version, revision, revisionDate) +} + +// parseArgs takes a slice of arguments of the form key=value and returns a map from +// key to value. It returns an error if an argument is malformed or a key is not in +// the valid slice. +func parseArgs(args []string, valid []string) (map[string]string, error) { + parsed := make(map[string]string) + for _, arg := range args { + i := strings.Index(arg, "=") + if i < 0 { + return nil, fmt.Errorf("Bad arg %q", arg) + } + key, val := arg[:i], arg[i+1:] + if !stringInSlice(key, valid) { + return nil, fmt.Errorf("Unknown arg key %q", key) + } + parsed[key] = val + } + return parsed, nil +} + +func stringInSlice(s string, list []string) bool { + for _, e := range list { + if s == e { + return true + } + } + return false +} + +func parseColumnsFilter(columns string) (bigtable.Filter, error) { + splitColumns := strings.FieldsFunc(columns, func(c rune) bool { return c == ',' }) + if len(splitColumns) == 1 { + filter, err := columnFilter(splitColumns[0]) + if err != nil { + return nil, err + } + return filter, nil + } + + var columnFilters []bigtable.Filter + for _, column := range splitColumns { + filter, err := columnFilter(column) + if err != nil { + return nil, err + } + columnFilters = append(columnFilters, filter) + } + return bigtable.InterleaveFilters(columnFilters...), nil +} + +func columnFilter(column string) (bigtable.Filter, error) { + splitColumn := strings.Split(column, ":") + if len(splitColumn) == 1 { + return bigtable.ColumnFilter(splitColumn[0]), nil + } else if len(splitColumn) == 2 { + if strings.HasSuffix(column, ":") { + return bigtable.FamilyFilter(splitColumn[0]), nil + } else if strings.HasPrefix(column, ":") { + return bigtable.ColumnFilter(splitColumn[1]), nil + } else { + familyFilter := bigtable.FamilyFilter(splitColumn[0]) + qualifierFilter := bigtable.ColumnFilter(splitColumn[1]) + return bigtable.ChainFilters(familyFilter, qualifierFilter), nil + } + } else { + return nil, fmt.Errorf("Bad format for column %q", column) + } +} + +func parseProfileRoute(str string) (routingPolicy, clusterID string, err error) { + + route := strings.Split(str, "=") + switch route[0] { + case "route-any": + if len(route) > 1 { + err = fmt.Errorf("got %v", route) + break + } + routingPolicy = bigtable.MultiClusterRouting + + case "route-to": + if len(route) != 2 || route[1] == "" { + err = fmt.Errorf("got %v", route) + break + } + routingPolicy = bigtable.SingleClusterRouting + clusterID = route[1] + default: + err = fmt.Errorf("got %v", route) + } + + return +} + +func parseProfileOpts(opt string, parsedArgs map[string]string) (bool, error) { + + if val, ok := parsedArgs[opt]; ok { + status, err := strconv.ParseBool(val) + if err != nil { + return false, fmt.Errorf("expected %s = got %s ", opt, val) + } + + return status, nil + } + return false, nil +} diff --git a/vendor/cloud.google.com/go/bigtable/cmd/cbt/cbt_test.go b/vendor/cloud.google.com/go/bigtable/cmd/cbt/cbt_test.go new file mode 100644 index 00000000..e7c6ea2c --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/cmd/cbt/cbt_test.go @@ -0,0 +1,173 @@ +// Copyright 2016 Google LLC +// +// 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 main + +import ( + "testing" + "time" + + "cloud.google.com/go/bigtable" + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" +) + +func TestParseDuration(t *testing.T) { + tests := []struct { + in string + // out or fail are mutually exclusive + out time.Duration + fail bool + }{ + {in: "10ms", out: 10 * time.Millisecond}, + {in: "3s", out: 3 * time.Second}, + {in: "60m", out: 60 * time.Minute}, + {in: "12h", out: 12 * time.Hour}, + {in: "7d", out: 168 * time.Hour}, + + {in: "", fail: true}, + {in: "0", fail: true}, + {in: "7ns", fail: true}, + {in: "14mo", fail: true}, + {in: "3.5h", fail: true}, + {in: "106752d", fail: true}, // overflow + } + for _, tc := range tests { + got, err := parseDuration(tc.in) + if !tc.fail && err != nil { + t.Errorf("parseDuration(%q) unexpectedly failed: %v", tc.in, err) + continue + } + if tc.fail && err == nil { + t.Errorf("parseDuration(%q) did not fail", tc.in) + continue + } + if tc.fail { + continue + } + if got != tc.out { + t.Errorf("parseDuration(%q) = %v, want %v", tc.in, got, tc.out) + } + } +} + +func TestParseArgs(t *testing.T) { + got, err := parseArgs([]string{"a=1", "b=2"}, []string{"a", "b"}) + if err != nil { + t.Fatal(err) + } + want := map[string]string{"a": "1", "b": "2"} + if !testutil.Equal(got, want) { + t.Fatalf("got %v, want %v", got, want) + } + + if _, err := parseArgs([]string{"a1"}, []string{"a1"}); err == nil { + t.Error("malformed: got nil, want error") + } + if _, err := parseArgs([]string{"a=1"}, []string{"b"}); err == nil { + t.Error("invalid: got nil, want error") + } +} + +func TestParseColumnsFilter(t *testing.T) { + tests := []struct { + in string + out bigtable.Filter + fail bool + }{ + { + in: "columnA", + out: bigtable.ColumnFilter("columnA"), + }, + { + in: "familyA:columnA", + out: bigtable.ChainFilters(bigtable.FamilyFilter("familyA"), bigtable.ColumnFilter("columnA")), + }, + { + in: "columnA,columnB", + out: bigtable.InterleaveFilters(bigtable.ColumnFilter("columnA"), bigtable.ColumnFilter("columnB")), + }, + { + in: "familyA:columnA,columnB", + out: bigtable.InterleaveFilters( + bigtable.ChainFilters(bigtable.FamilyFilter("familyA"), bigtable.ColumnFilter("columnA")), + bigtable.ColumnFilter("columnB"), + ), + }, + { + in: "columnA,familyB:columnB", + out: bigtable.InterleaveFilters( + bigtable.ColumnFilter("columnA"), + bigtable.ChainFilters(bigtable.FamilyFilter("familyB"), bigtable.ColumnFilter("columnB")), + ), + }, + { + in: "familyA:columnA,familyB:columnB", + out: bigtable.InterleaveFilters( + bigtable.ChainFilters(bigtable.FamilyFilter("familyA"), bigtable.ColumnFilter("columnA")), + bigtable.ChainFilters(bigtable.FamilyFilter("familyB"), bigtable.ColumnFilter("columnB")), + ), + }, + { + in: "familyA:", + out: bigtable.FamilyFilter("familyA"), + }, + { + in: ":columnA", + out: bigtable.ColumnFilter("columnA"), + }, + { + in: ",:columnA,,familyB:columnB,", + out: bigtable.InterleaveFilters( + bigtable.ColumnFilter("columnA"), + bigtable.ChainFilters(bigtable.FamilyFilter("familyB"), bigtable.ColumnFilter("columnB")), + ), + }, + { + in: "familyA:columnA:cellA", + fail: true, + }, + { + in: "familyA::columnA", + fail: true, + }, + } + + for _, tc := range tests { + got, err := parseColumnsFilter(tc.in) + + if !tc.fail && err != nil { + t.Errorf("parseColumnsFilter(%q) unexpectedly failed: %v", tc.in, err) + continue + } + if tc.fail && err == nil { + t.Errorf("parseColumnsFilter(%q) did not fail", tc.in) + continue + } + if tc.fail { + continue + } + + var cmpOpts cmp.Options + cmpOpts = + append( + cmpOpts, + cmp.AllowUnexported(bigtable.ChainFilters([]bigtable.Filter{}...)), + cmp.AllowUnexported(bigtable.InterleaveFilters([]bigtable.Filter{}...))) + + if !cmp.Equal(got, tc.out, cmpOpts) { + t.Errorf("parseColumnsFilter(%q) = %v, want %v", tc.in, got, tc.out) + } + } +} diff --git a/vendor/cloud.google.com/go/bigtable/cmd/cbt/cbtdoc.go b/vendor/cloud.google.com/go/bigtable/cmd/cbt/cbtdoc.go new file mode 100644 index 00000000..2c91a1af --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/cmd/cbt/cbtdoc.go @@ -0,0 +1,425 @@ +// Copyright 2016 Google LLC +// +// 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. + +// DO NOT EDIT. THIS IS AUTOMATICALLY GENERATED. +// Run "go generate" to regenerate. +//go:generate go run cbt.go gcpolicy.go -o cbtdoc.go doc + +/* +Cbt is a tool for doing basic interactions with Cloud Bigtable. To learn how to +install the cbt tool, see the +[cbt overview](https://cloud.google.com/bigtable/docs/cbt-overview). + +Usage: + + cbt [options] command [arguments] + +The commands are: + + count Count rows in a table + createinstance Create an instance with an initial cluster + createcluster Create a cluster in the configured instance + createfamily Create a column family + createtable Create a table + updatecluster Update a cluster in the configured instance + deleteinstance Delete an instance + deletecluster Delete a cluster from the configured instance + deletecolumn Delete all cells in a column + deletefamily Delete a column family + deleterow Delete a row + deletetable Delete a table + doc Print godoc-suitable documentation for cbt + help Print help text + listinstances List instances in a project + listclusters List clusters in an instance + lookup Read from a single row + ls List tables and column families + mddoc Print documentation for cbt in Markdown format + read Read rows + set Set value of a cell + setgcpolicy Set the GC policy for a column family + waitforreplication Block until all the completed writes have been replicated to all the clusters + createtablefromsnapshot Create a table from a snapshot (snapshots alpha) + createsnapshot Create a snapshot from a source table (snapshots alpha) + listsnapshots List snapshots in a cluster (snapshots alpha) + getsnapshot Get snapshot info (snapshots alpha) + deletesnapshot Delete snapshot in a cluster (snapshots alpha) + version Print the current cbt version + createappprofile Creates app profile for an instance + getappprofile Reads app profile for an instance + listappprofile Lists app profile for an instance + updateappprofile Updates app profile for an instance + deleteappprofile Deletes app profile for an instance + +Use "cbt help " for more information about a command. + +The options are: + + -project string + project ID, if unset uses gcloud configured project + -instance string + Cloud Bigtable instance + -creds string + if set, use application credentials in this file + + +Alpha features are not currently available to most Cloud Bigtable customers. The +features might be changed in backward-incompatible ways and are not recommended +for production use. They are not subject to any SLA or deprecation policy. + +Note: cbt does not support specifying arbitrary bytes on the command line for +any value that Bigtable otherwise supports (e.g., row key, column qualifier, +etc.). + +For convenience, values of the -project, -instance, -creds, +-admin-endpoint and -data-endpoint flags may be specified in +~/.cbtrc in this format: + + project = my-project-123 + instance = my-instance + creds = path-to-account-key.json + admin-endpoint = hostname:port + data-endpoint = hostname:port + +All values are optional, and all will be overridden by flags. + + + +Count rows in a table + +Usage: + cbt count
+ + + + +Create an instance with an initial cluster + +Usage: + cbt createinstance + instance-id Permanent, unique id for the instance + display-name Description of the instance + cluster-id Permanent, unique id for the cluster in the instance + zone The zone in which to create the cluster + num-nodes The number of nodes to create + storage-type SSD or HDD + + + + + +Create a cluster in the configured instance + +Usage: + cbt createcluster + cluster-id Permanent, unique id for the cluster in the instance + zone The zone in which to create the cluster + num-nodes The number of nodes to create + storage-type SSD or HDD + + + + + +Create a column family + +Usage: + cbt createfamily
+ + + + +Create a table + +Usage: + cbt createtable
[families=family[:gcpolicy],...] [splits=split,...] + families: Column families and their associated GC policies. For gcpolicy, + see "setgcpolicy". + Example: families=family1:maxage=1w,family2:maxversions=1 + splits: Row key to be used to initially split the table + + + + +Update a cluster in the configured instance + +Usage: + cbt updatecluster [num-nodes=num-nodes] + cluster-id Permanent, unique id for the cluster in the instance + num-nodes The number of nodes to update to + + + + +Delete an instance + +Usage: + cbt deleteinstance + + + + +Delete a cluster from the configured instance + +Usage: + cbt deletecluster + + + + +Delete all cells in a column + +Usage: + cbt deletecolumn
[app-profile=] + app-profile= The app profile id to use for the request + + + + + +Delete a column family + +Usage: + cbt deletefamily
+ + + + +Delete a row + +Usage: + cbt deleterow
[app-profile=] + app-profile= The app profile id to use for the request + + + + + +Delete a table + +Usage: + cbt deletetable
+ + + + +Print godoc-suitable documentation for cbt + +Usage: + cbt doc + + + + +Print help text + +Usage: + cbt help [command] + + + + +List instances in a project + +Usage: + cbt listinstances + + + + +List clusters in an instance + +Usage: + cbt listclusters + + + + +Read from a single row + +Usage: + cbt lookup
[columns=[family]:[qualifier],...] [cells-per-column=] [app-profile=] + columns=[family]:[qualifier],... Read only these columns, comma-separated + cells-per-column= Read only this many cells per column + app-profile= The app profile id to use for the request + + + + + +List tables and column families + +Usage: + cbt ls List tables + cbt ls
List column families in
+ + + + +Print documentation for cbt in Markdown format + +Usage: + cbt mddoc + + + + +Read rows + +Usage: + cbt read
[start=] [end=] [prefix=] [regex=] [columns=[family]:[qualifier],...] [count=] [cells-per-column=] [app-profile=] + start= Start reading at this row + end= Stop reading before this row + prefix= Read rows with this prefix + regex= Read rows with keys matching this regex + columns=[family]:[qualifier],... Read only these columns, comma-separated + count= Read only this many rows + cells-per-column= Read only this many cells per column + app-profile= The app profile id to use for the request + + + + + +Set value of a cell + +Usage: + cbt set
[app-profile=] family:column=val[@ts] ... + app-profile= The app profile id to use for the request + family:column=val[@ts] may be repeated to set multiple cells. + + ts is an optional integer timestamp. + If it cannot be parsed, the `@ts` part will be + interpreted as part of the value. + + + + +Set the GC policy for a column family + +Usage: + cbt setgcpolicy
((maxage= | maxversions=) [(and|or) (maxage= | maxversions=),...] | never) + + maxage= Maximum timestamp age to preserve (e.g. "1h", "4d") + maxversions= Maximum number of versions to preserve + + + + +Block until all the completed writes have been replicated to all the clusters + +Usage: + cbt waitforreplication
+ + + + +Create a table from a snapshot (snapshots alpha) + +Usage: + cbt createtablefromsnapshot
+ table The name of the table to create + cluster The cluster where the snapshot is located + snapshot The snapshot to restore + + + + +Create a snapshot from a source table (snapshots alpha) + +Usage: + cbt createsnapshot
[ttl=] + + [ttl=] Lifespan of the snapshot (e.g. "1h", "4d") + + + + + +List snapshots in a cluster (snapshots alpha) + +Usage: + cbt listsnapshots [] + + + + +Get snapshot info (snapshots alpha) + +Usage: + cbt getsnapshot + + + + +Delete snapshot in a cluster (snapshots alpha) + +Usage: + cbt deletesnapshot + + + + +Print the current cbt version + +Usage: + cbt version + + + + +Creates app profile for an instance + +Usage: + usage: cbt createappprofile (route-any | [ route-to= : transactional-writes]) [optional flag] + optional flags may be `force` + + + + +Reads app profile for an instance + +Usage: + cbt getappprofile + + + + +Lists app profile for an instance + +Usage: + cbt listappprofile + + + + +Updates app profile for an instance + +Usage: + usage: cbt updateappprofile (route-any | [ route-to= : transactional-writes]) [optional flag] + optional flags may be `force` + + + + +Deletes app profile for an instance + +Usage: + cbt deleteappprofile + + + + +*/ +package main diff --git a/vendor/cloud.google.com/go/bigtable/cmd/cbt/gcpolicy.go b/vendor/cloud.google.com/go/bigtable/cmd/cbt/gcpolicy.go new file mode 100644 index 00000000..5a7c05b4 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/cmd/cbt/gcpolicy.go @@ -0,0 +1,215 @@ +/* +Copyright 2015 Google LLC + +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 main + +import ( + "bytes" + "errors" + "fmt" + "io" + "strconv" + "strings" + "unicode" + + "cloud.google.com/go/bigtable" +) + +// Parse a GC policy. Valid policies include +// never +// maxage = 5d +// maxversions = 3 +// maxage = 5d || maxversions = 3 +// maxage=30d || (maxage=3d && maxversions=100) +func parseGCPolicy(s string) (bigtable.GCPolicy, error) { + if strings.TrimSpace(s) == "never" { + return bigtable.NoGcPolicy(), nil + } + r := strings.NewReader(s) + p, err := parsePolicyExpr(r) + if err != nil { + return nil, fmt.Errorf("invalid GC policy: %v", err) + } + tok, err := getToken(r) + if err != nil { + return nil, err + } + if tok != "" { + return nil, fmt.Errorf("invalid GC policy: want end of input, got %q", tok) + } + return p, nil +} + +// expr ::= term (op term)* +// op ::= "and" | "or" | "&&" | "||" +func parsePolicyExpr(r io.RuneScanner) (bigtable.GCPolicy, error) { + policy, err := parsePolicyTerm(r) + if err != nil { + return nil, err + } + for { + tok, err := getToken(r) + if err != nil { + return nil, err + } + var f func(...bigtable.GCPolicy) bigtable.GCPolicy + switch tok { + case "and", "&&": + f = bigtable.IntersectionPolicy + case "or", "||": + f = bigtable.UnionPolicy + default: + ungetToken(tok) + return policy, nil + } + p2, err := parsePolicyTerm(r) + if err != nil { + return nil, err + } + policy = f(policy, p2) + } +} + +// term ::= "maxage" "=" duration | "maxversions" "=" int | "(" policy ")" +func parsePolicyTerm(r io.RuneScanner) (bigtable.GCPolicy, error) { + tok, err := getToken(r) + if err != nil { + return nil, err + } + switch tok { + case "": + return nil, errors.New("empty GC policy term") + + case "maxage", "maxversions": + if err := expectToken(r, "="); err != nil { + return nil, err + } + tok2, err := getToken(r) + if err != nil { + return nil, err + } + if tok2 == "" { + return nil, errors.New("expected a token after '='") + } + if tok == "maxage" { + dur, err := parseDuration(tok2) + if err != nil { + return nil, err + } + return bigtable.MaxAgePolicy(dur), nil + } + n, err := strconv.ParseUint(tok2, 10, 16) + if err != nil { + return nil, err + } + return bigtable.MaxVersionsPolicy(int(n)), nil + + case "(": + p, err := parsePolicyExpr(r) + if err != nil { + return nil, err + } + if err := expectToken(r, ")"); err != nil { + return nil, err + } + return p, nil + + default: + return nil, fmt.Errorf("unexpected token: %q", tok) + } + +} + +func expectToken(r io.RuneScanner, want string) error { + got, err := getToken(r) + if err != nil { + return err + } + if got != want { + return fmt.Errorf("expected %q, saw %q", want, got) + } + return nil +} + +const noToken = "_" // empty token is valid, so use "_" instead + +// If not noToken, getToken will return this instead of reading a new token +// from the input. +var ungotToken = noToken + +// getToken extracts the first token from the input. Valid tokens include +// any sequence of letters and digits, and these symbols: &&, ||, =, ( and ). +// getToken returns ("", nil) at end of input. +func getToken(r io.RuneScanner) (string, error) { + if ungotToken != noToken { + t := ungotToken + ungotToken = noToken + return t, nil + } + var err error + // Skip leading whitespace. + c := ' ' + for unicode.IsSpace(c) { + c, _, err = r.ReadRune() + if err == io.EOF { + return "", nil + } + if err != nil { + return "", err + } + } + switch { + case c == '=' || c == '(' || c == ')': + return string(c), nil + + case c == '&' || c == '|': + c2, _, err := r.ReadRune() + if err != nil && err != io.EOF { + return "", err + } + if c != c2 { + return "", fmt.Errorf("expected %c%c", c, c) + } + return string([]rune{c, c}), nil + + case unicode.IsLetter(c) || unicode.IsDigit(c): + // Collect an alphanumeric token. + var b bytes.Buffer + for unicode.IsLetter(c) || unicode.IsDigit(c) { + b.WriteRune(c) + c, _, err = r.ReadRune() + if err == io.EOF { + break + } + if err != nil { + return "", err + } + } + r.UnreadRune() + return b.String(), nil + + default: + return "", fmt.Errorf("bad rune %q", c) + } +} + +// "unget" a token so the next call to getToken will return it. +func ungetToken(tok string) { + if ungotToken != noToken { + panic("ungetToken called twice") + } + ungotToken = tok +} diff --git a/vendor/cloud.google.com/go/bigtable/cmd/cbt/gcpolicy_test.go b/vendor/cloud.google.com/go/bigtable/cmd/cbt/gcpolicy_test.go new file mode 100644 index 00000000..da9f72e1 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/cmd/cbt/gcpolicy_test.go @@ -0,0 +1,196 @@ +/* +Copyright 2015 Google LLC + +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 main + +import ( + "strings" + "testing" + "time" + + "cloud.google.com/go/bigtable" + "github.com/google/go-cmp/cmp" +) + +func TestParseGCPolicy(t *testing.T) { + for _, test := range []struct { + in string + want bigtable.GCPolicy + }{ + { + "never", + bigtable.NoGcPolicy(), + }, + { + "maxage=3h", + bigtable.MaxAgePolicy(3 * time.Hour), + }, + { + "maxversions=2", + bigtable.MaxVersionsPolicy(2), + }, + { + "maxversions=2 and maxage=1h", + bigtable.IntersectionPolicy(bigtable.MaxVersionsPolicy(2), bigtable.MaxAgePolicy(time.Hour)), + }, + { + "(((maxversions=2 and (maxage=1h))))", + bigtable.IntersectionPolicy(bigtable.MaxVersionsPolicy(2), bigtable.MaxAgePolicy(time.Hour)), + }, + { + "maxversions=7 or maxage=8h", + bigtable.UnionPolicy(bigtable.MaxVersionsPolicy(7), bigtable.MaxAgePolicy(8*time.Hour)), + }, + { + "maxversions = 7||maxage = 8h", + bigtable.UnionPolicy(bigtable.MaxVersionsPolicy(7), bigtable.MaxAgePolicy(8*time.Hour)), + }, + { + "maxversions=7||maxage=8h", + bigtable.UnionPolicy(bigtable.MaxVersionsPolicy(7), bigtable.MaxAgePolicy(8*time.Hour)), + }, + { + "maxage=30d || (maxage=3d && maxversions=100)", + bigtable.UnionPolicy( + bigtable.MaxAgePolicy(30*24*time.Hour), + bigtable.IntersectionPolicy( + bigtable.MaxAgePolicy(3*24*time.Hour), + bigtable.MaxVersionsPolicy(100))), + }, + { + "maxage=30d || (maxage=3d && maxversions=100) || maxversions=7", + bigtable.UnionPolicy( + bigtable.UnionPolicy( + bigtable.MaxAgePolicy(30*24*time.Hour), + bigtable.IntersectionPolicy( + bigtable.MaxAgePolicy(3*24*time.Hour), + bigtable.MaxVersionsPolicy(100))), + bigtable.MaxVersionsPolicy(7)), + }, + { + // && and || have same precedence, left associativity + "maxage=1h && maxage=2h || maxage=3h", + bigtable.UnionPolicy( + bigtable.IntersectionPolicy( + bigtable.MaxAgePolicy(1*time.Hour), + bigtable.MaxAgePolicy(2*time.Hour)), + bigtable.MaxAgePolicy(3*time.Hour)), + }, + } { + got, err := parseGCPolicy(test.in) + if err != nil { + t.Errorf("%s: %v", test.in, err) + continue + } + if !cmp.Equal(got, test.want, cmp.AllowUnexported(bigtable.IntersectionPolicy(), bigtable.UnionPolicy())) { + t.Errorf("%s: got %+v, want %+v", test.in, got, test.want) + } + } +} + +func TestParseGCPolicyErrors(t *testing.T) { + for _, in := range []string{ + "", + "a", + "b = 1h", + "c = 1", + "maxage=1", // need duration + "maxversions=1h", // need int + "maxage", + "maxversions", + "never=never", + "maxversions=1 && never", + "(((maxage=1h))", + "((maxage=1h)))", + "maxage=30d || ((maxage=3d && maxversions=100)", + "maxversions = 3 and", + } { + _, err := parseGCPolicy(in) + if err == nil { + t.Errorf("%s: got nil, want error", in) + } + } +} + +func TestTokenizeGCPolicy(t *testing.T) { + for _, test := range []struct { + in string + want []string + }{ + { + "maxage=5d", + []string{"maxage", "=", "5d"}, + }, + { + "maxage = 5d", + []string{"maxage", "=", "5d"}, + }, + { + "maxage=5d or maxversions=5", + []string{"maxage", "=", "5d", "or", "maxversions", "=", "5"}, + }, + { + "maxage=5d || (maxversions=5)", + []string{"maxage", "=", "5d", "||", "(", "maxversions", "=", "5", ")"}, + }, + { + "maxage=5d||( maxversions=5 )", + []string{"maxage", "=", "5d", "||", "(", "maxversions", "=", "5", ")"}, + }, + } { + got, err := tokenizeGCPolicy(test.in) + if err != nil { + t.Errorf("%s: %v", test.in, err) + continue + } + if diff := cmp.Diff(got, test.want); diff != "" { + t.Errorf("%s: %s", test.in, diff) + } + } +} + +func TestTokenizeGCPolicyErrors(t *testing.T) { + for _, in := range []string{ + "a &", + "a & b", + "a &x b", + "a |", + "a | b", + "a |& b", + "a % b", + } { + _, err := tokenizeGCPolicy(in) + if err == nil { + t.Errorf("%s: got nil, want error", in) + } + } +} + +func tokenizeGCPolicy(s string) ([]string, error) { + var tokens []string + r := strings.NewReader(s) + for { + tok, err := getToken(r) + if err != nil { + return nil, err + } + if tok == "" { + break + } + tokens = append(tokens, tok) + } + return tokens, nil +} diff --git a/vendor/cloud.google.com/go/bigtable/cmd/emulator/cbtemulator.go b/vendor/cloud.google.com/go/bigtable/cmd/emulator/cbtemulator.go new file mode 100644 index 00000000..2477a642 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/cmd/emulator/cbtemulator.go @@ -0,0 +1,44 @@ +// Copyright 2016 Google LLC +// +// 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. + +/* +cbtemulator launches the in-memory Cloud Bigtable server on the given address. +*/ +package main + +import ( + "flag" + "fmt" + "log" + + "cloud.google.com/go/bigtable/bttest" + "google.golang.org/grpc" +) + +var ( + host = flag.String("host", "localhost", "the address to bind to on the local machine") + port = flag.Int("port", 9000, "the port number to bind to on the local machine") +) + +func main() { + grpc.EnableTracing = false + flag.Parse() + srv, err := bttest.NewServer(fmt.Sprintf("%s:%d", *host, *port)) + if err != nil { + log.Fatalf("failed to start emulator: %v", err) + } + + fmt.Printf("Cloud Bigtable emulator running on %s\n", srv.Addr) + select {} +} diff --git a/vendor/cloud.google.com/go/bigtable/cmd/loadtest/loadtest.go b/vendor/cloud.google.com/go/bigtable/cmd/loadtest/loadtest.go new file mode 100644 index 00000000..d05aac13 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/cmd/loadtest/loadtest.go @@ -0,0 +1,205 @@ +/* +Copyright 2015 Google LLC + +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. +*/ + +/* +Loadtest does some load testing through the Go client library for Cloud Bigtable. +*/ +package main + +import ( + "bytes" + "context" + "flag" + "fmt" + "log" + "math/rand" + "os" + "os/signal" + "sync" + "sync/atomic" + "time" + + "cloud.google.com/go/bigtable" + "cloud.google.com/go/bigtable/internal/cbtconfig" + "cloud.google.com/go/bigtable/internal/stat" + "google.golang.org/api/option" + "google.golang.org/grpc" +) + +var ( + runFor = flag.Duration("run_for", 5*time.Second, + "how long to run the load test for; 0 to run forever until SIGTERM") + scratchTable = flag.String("scratch_table", "loadtest-scratch", "name of table to use; should not already exist") + csvOutput = flag.String("csv_output", "", + "output path for statistics in .csv format. If this file already exists it will be overwritten.") + poolSize = flag.Int("pool_size", 1, "size of the gRPC connection pool to use for the data client") + reqCount = flag.Int("req_count", 100, "number of concurrent requests") + + config *cbtconfig.Config + client *bigtable.Client + adminClient *bigtable.AdminClient +) + +func main() { + var err error + config, err = cbtconfig.Load() + if err != nil { + log.Fatal(err) + } + config.RegisterFlags() + + flag.Parse() + if err := config.CheckFlags(cbtconfig.ProjectAndInstanceRequired); err != nil { + log.Fatal(err) + } + if config.Creds != "" { + os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", config.Creds) + } + if flag.NArg() != 0 { + flag.Usage() + os.Exit(1) + } + + var options []option.ClientOption + if *poolSize > 1 { + options = append(options, + option.WithGRPCConnectionPool(*poolSize), + + // TODO(grpc/grpc-go#1388) using connection pool without WithBlock + // can cause RPCs to fail randomly. We can delete this after the issue is fixed. + option.WithGRPCDialOption(grpc.WithBlock())) + } + + var csvFile *os.File + if *csvOutput != "" { + csvFile, err = os.Create(*csvOutput) + if err != nil { + log.Fatalf("creating csv output file: %v", err) + } + defer csvFile.Close() + log.Printf("Writing statistics to %q ...", *csvOutput) + } + + log.Printf("Dialing connections...") + client, err = bigtable.NewClient(context.Background(), config.Project, config.Instance, options...) + if err != nil { + log.Fatalf("Making bigtable.Client: %v", err) + } + defer client.Close() + adminClient, err = bigtable.NewAdminClient(context.Background(), config.Project, config.Instance) + if err != nil { + log.Fatalf("Making bigtable.AdminClient: %v", err) + } + defer adminClient.Close() + + // Create a scratch table. + log.Printf("Setting up scratch table...") + tblConf := bigtable.TableConf{ + TableID: *scratchTable, + Families: map[string]bigtable.GCPolicy{"f": bigtable.MaxVersionsPolicy(1)}, + } + if err := adminClient.CreateTableFromConf(context.Background(), &tblConf); err != nil { + log.Fatalf("Making scratch table %q: %v", *scratchTable, err) + } + // Upon a successful run, delete the table. Don't bother checking for errors. + defer adminClient.DeleteTable(context.Background(), *scratchTable) + + // Also delete the table on SIGTERM. + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + go func() { + s := <-c + log.Printf("Caught %v, cleaning scratch table.", s) + _ = adminClient.DeleteTable(context.Background(), *scratchTable) + os.Exit(1) + }() + + log.Printf("Starting load test... (run for %v)", *runFor) + tbl := client.Open(*scratchTable) + sem := make(chan int, *reqCount) // limit the number of requests happening at once + var reads, writes stats + stopTime := time.Now().Add(*runFor) + var wg sync.WaitGroup + for time.Now().Before(stopTime) || *runFor == 0 { + sem <- 1 + wg.Add(1) + go func() { + defer wg.Done() + defer func() { <-sem }() + + ok := true + opStart := time.Now() + var stats *stats + defer func() { + stats.Record(ok, time.Since(opStart)) + }() + + row := fmt.Sprintf("row%d", rand.Intn(100)) // operate on 1 of 100 rows + + switch rand.Intn(10) { + default: + // read + stats = &reads + _, err := tbl.ReadRow(context.Background(), row, bigtable.RowFilter(bigtable.LatestNFilter(1))) + if err != nil { + log.Printf("Error doing read: %v", err) + ok = false + } + case 0, 1, 2, 3, 4: + // write + stats = &writes + mut := bigtable.NewMutation() + mut.Set("f", "col", bigtable.Now(), bytes.Repeat([]byte("0"), 1<<10)) // 1 KB write + if err := tbl.Apply(context.Background(), row, mut); err != nil { + log.Printf("Error doing mutation: %v", err) + ok = false + } + } + }() + } + wg.Wait() + + readsAgg := stat.NewAggregate("reads", reads.ds, reads.tries-reads.ok) + writesAgg := stat.NewAggregate("writes", writes.ds, writes.tries-writes.ok) + log.Printf("Reads (%d ok / %d tries):\n%v", reads.ok, reads.tries, readsAgg) + log.Printf("Writes (%d ok / %d tries):\n%v", writes.ok, writes.tries, writesAgg) + + if csvFile != nil { + stat.WriteCSV([]*stat.Aggregate{readsAgg, writesAgg}, csvFile) + } +} + +var allStats int64 // atomic + +type stats struct { + mu sync.Mutex + tries, ok int + ds []time.Duration +} + +func (s *stats) Record(ok bool, d time.Duration) { + s.mu.Lock() + s.tries++ + if ok { + s.ok++ + } + s.ds = append(s.ds, d) + s.mu.Unlock() + + if n := atomic.AddInt64(&allStats, 1); n%1000 == 0 { + log.Printf("Progress: done %d ops", n) + } +} diff --git a/vendor/cloud.google.com/go/bigtable/cmd/scantest/scantest.go b/vendor/cloud.google.com/go/bigtable/cmd/scantest/scantest.go new file mode 100644 index 00000000..bcfde8cc --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/cmd/scantest/scantest.go @@ -0,0 +1,155 @@ +/* +Copyright 2016 Google LLC + +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. +*/ + +/* +Scantest does scan-related load testing against Cloud Bigtable. The logic here +mimics a similar test written using the Java client. +*/ +package main + +import ( + "bytes" + "context" + "flag" + "fmt" + "log" + "math/rand" + "os" + "sync" + "sync/atomic" + "text/tabwriter" + "time" + + "cloud.google.com/go/bigtable" + "cloud.google.com/go/bigtable/internal/cbtconfig" + "cloud.google.com/go/bigtable/internal/stat" +) + +var ( + runFor = flag.Duration("run_for", 5*time.Second, "how long to run the load test for") + numScans = flag.Int("concurrent_scans", 1, "number of concurrent scans") + rowLimit = flag.Int("row_limit", 10000, "max number of records per scan") + + config *cbtconfig.Config + client *bigtable.Client +) + +func main() { + flag.Usage = func() { + fmt.Printf("Usage: scantest [options] \n\n") + flag.PrintDefaults() + } + + var err error + config, err = cbtconfig.Load() + if err != nil { + log.Fatal(err) + } + config.RegisterFlags() + + flag.Parse() + if err := config.CheckFlags(cbtconfig.ProjectAndInstanceRequired); err != nil { + log.Fatal(err) + } + if config.Creds != "" { + os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", config.Creds) + } + if flag.NArg() != 1 { + flag.Usage() + os.Exit(1) + } + + table := flag.Arg(0) + + log.Printf("Dialing connections...") + client, err = bigtable.NewClient(context.Background(), config.Project, config.Instance) + if err != nil { + log.Fatalf("Making bigtable.Client: %v", err) + } + defer client.Close() + + log.Printf("Starting scan test... (run for %v)", *runFor) + tbl := client.Open(table) + sem := make(chan int, *numScans) // limit the number of requests happening at once + var scans stats + + stopTime := time.Now().Add(*runFor) + var wg sync.WaitGroup + for time.Now().Before(stopTime) { + sem <- 1 + wg.Add(1) + go func() { + defer wg.Done() + defer func() { <-sem }() + + ok := true + opStart := time.Now() + defer func() { + scans.Record(ok, time.Since(opStart)) + }() + + // Start at a random row key + key := fmt.Sprintf("user%d", rand.Int63()) + limit := bigtable.LimitRows(int64(*rowLimit)) + noop := func(bigtable.Row) bool { return true } + if err := tbl.ReadRows(context.Background(), bigtable.NewRange(key, ""), noop, limit); err != nil { + log.Printf("Error during scan: %v", err) + ok = false + } + }() + } + wg.Wait() + + agg := stat.NewAggregate("scans", scans.ds, scans.tries-scans.ok) + log.Printf("Scans (%d ok / %d tries):\nscan times:\n%v\nthroughput (rows/second):\n%v", + scans.ok, scans.tries, agg, throughputString(agg)) +} + +func throughputString(agg *stat.Aggregate) string { + var buf bytes.Buffer + tw := tabwriter.NewWriter(&buf, 0, 0, 1, ' ', 0) // one-space padding + rowLimitF := float64(*rowLimit) + fmt.Fprintf( + tw, + "min:\t%.2f\nmedian:\t%.2f\nmax:\t%.2f\n", + rowLimitF/agg.Max.Seconds(), + rowLimitF/agg.Median.Seconds(), + rowLimitF/agg.Min.Seconds()) + tw.Flush() + return buf.String() +} + +var allStats int64 // atomic + +type stats struct { + mu sync.Mutex + tries, ok int + ds []time.Duration +} + +func (s *stats) Record(ok bool, d time.Duration) { + s.mu.Lock() + s.tries++ + if ok { + s.ok++ + } + s.ds = append(s.ds, d) + s.mu.Unlock() + + if n := atomic.AddInt64(&allStats, 1); n%1000 == 0 { + log.Printf("Progress: done %d ops", n) + } +} diff --git a/vendor/cloud.google.com/go/bigtable/doc.go b/vendor/cloud.google.com/go/bigtable/doc.go new file mode 100644 index 00000000..1b75ff7c --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/doc.go @@ -0,0 +1,123 @@ +/* +Copyright 2015 Google LLC + +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 bigtable is an API to Google Cloud Bigtable. + +See https://cloud.google.com/bigtable/docs/ for general product documentation. + +See https://godoc.org/cloud.google.com/go for authentication, timeouts, +connection pooling and similar aspects of this package. + + +Setup and Credentials + +Use NewClient or NewAdminClient to create a client that can be used to access +the data or admin APIs respectively. Both require credentials that have permission +to access the Cloud Bigtable API. + +If your program is run on Google App Engine or Google Compute Engine, using the Application Default Credentials +(https://developers.google.com/accounts/docs/application-default-credentials) +is the simplest option. Those credentials will be used by default when NewClient or NewAdminClient are called. + +To use alternate credentials, pass them to NewClient or NewAdminClient using option.WithTokenSource. +For instance, you can use service account credentials by visiting +https://cloud.google.com/console/project/MYPROJECT/apiui/credential, +creating a new OAuth "Client ID", storing the JSON key somewhere accessible, and writing + jsonKey, err := ioutil.ReadFile(pathToKeyFile) + ... + config, err := google.JWTConfigFromJSON(jsonKey, bigtable.Scope) // or bigtable.AdminScope, etc. + ... + client, err := bigtable.NewClient(ctx, project, instance, option.WithTokenSource(config.TokenSource(ctx))) + ... +Here, `google` means the golang.org/x/oauth2/google package +and `option` means the google.golang.org/api/option package. + +Reading + +The principal way to read from a Bigtable is to use the ReadRows method on *Table. +A RowRange specifies a contiguous portion of a table. A Filter may be provided through +RowFilter to limit or transform the data that is returned. + tbl := client.Open("mytable") + ... + // Read all the rows starting with "com.google.", + // but only fetch the columns in the "links" family. + rr := bigtable.PrefixRange("com.google.") + err := tbl.ReadRows(ctx, rr, func(r Row) bool { + // do something with r + return true // keep going + }, bigtable.RowFilter(bigtable.FamilyFilter("links"))) + ... + +To read a single row, use the ReadRow helper method. + r, err := tbl.ReadRow(ctx, "com.google.cloud") // "com.google.cloud" is the entire row key + ... + +Writing + +This API exposes two distinct forms of writing to a Bigtable: a Mutation and a ReadModifyWrite. +The former expresses idempotent operations. +The latter expresses non-idempotent operations and returns the new values of updated cells. +These operations are performed by creating a Mutation or ReadModifyWrite (with NewMutation or NewReadModifyWrite), +building up one or more operations on that, and then using the Apply or ApplyReadModifyWrite +methods on a Table. + +For instance, to set a couple of cells in a table, + tbl := client.Open("mytable") + mut := bigtable.NewMutation() + mut.Set("links", "maps.google.com", bigtable.Now(), []byte("1")) + mut.Set("links", "golang.org", bigtable.Now(), []byte("1")) + err := tbl.Apply(ctx, "com.google.cloud", mut) + ... + +To increment an encoded value in one cell, + tbl := client.Open("mytable") + rmw := bigtable.NewReadModifyWrite() + rmw.Increment("links", "golang.org", 12) // add 12 to the cell in column "links:golang.org" + r, err := tbl.ApplyReadModifyWrite(ctx, "com.google.cloud", rmw) + ... + +Retries + +If a read or write operation encounters a transient error it will be retried until a successful +response, an unretryable error or the context deadline is reached. Non-idempotent writes (where +the timestamp is set to ServerTime) will not be retried. In the case of ReadRows, retried calls +will not re-scan rows that have already been processed. +*/ +package bigtable // import "cloud.google.com/go/bigtable" + +// Scope constants for authentication credentials. +// These should be used when using credential creation functions such as oauth.NewServiceAccountFromFile. +const ( + // Scope is the OAuth scope for Cloud Bigtable data operations. + Scope = "https://www.googleapis.com/auth/bigtable.data" + // ReadonlyScope is the OAuth scope for Cloud Bigtable read-only data operations. + ReadonlyScope = "https://www.googleapis.com/auth/bigtable.readonly" + + // AdminScope is the OAuth scope for Cloud Bigtable table admin operations. + AdminScope = "https://www.googleapis.com/auth/bigtable.admin.table" + + // InstanceAdminScope is the OAuth scope for Cloud Bigtable instance (and cluster) admin operations. + InstanceAdminScope = "https://www.googleapis.com/auth/bigtable.admin.cluster" +) + +// clientUserAgent identifies the version of this package. +// It should be bumped upon significant changes only. +const clientUserAgent = "cbt-go/20180601" + +// resourcePrefixHeader is the name of the metadata header used to indicate +// the resource being operated on. +const resourcePrefixHeader = "google-cloud-resource-prefix" diff --git a/vendor/cloud.google.com/go/bigtable/export_test.go b/vendor/cloud.google.com/go/bigtable/export_test.go new file mode 100644 index 00000000..33f55dea --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/export_test.go @@ -0,0 +1,215 @@ +/* +Copyright 2016 Google LLC + +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 bigtable + +import ( + "context" + "errors" + "flag" + "fmt" + "strings" + "time" + + "cloud.google.com/go/bigtable/bttest" + "google.golang.org/api/option" + "google.golang.org/grpc" +) + +var legacyUseProd string +var integrationConfig IntegrationTestConfig + +func init() { + c := &integrationConfig + + flag.BoolVar(&c.UseProd, "it.use-prod", false, "Use remote bigtable instead of local emulator") + flag.StringVar(&c.AdminEndpoint, "it.admin-endpoint", "", "Admin api host and port") + flag.StringVar(&c.DataEndpoint, "it.data-endpoint", "", "Data api host and port") + flag.StringVar(&c.Project, "it.project", "", "Project to use for integration test") + flag.StringVar(&c.Instance, "it.instance", "", "Bigtable instance to use") + flag.StringVar(&c.Cluster, "it.cluster", "", "Bigtable cluster to use") + flag.StringVar(&c.Table, "it.table", "", "Bigtable table to create") + + // Backwards compat + flag.StringVar(&legacyUseProd, "use_prod", "", `DEPRECATED: if set to "proj,instance,table", run integration test against production`) + +} + +// IntegrationTestConfig contains parameters to pick and setup a IntegrationEnv for testing +type IntegrationTestConfig struct { + UseProd bool + AdminEndpoint string + DataEndpoint string + Project string + Instance string + Cluster string + Table string +} + +// IntegrationEnv represents a testing environment. +// The environment can be implemented using production or an emulator +type IntegrationEnv interface { + Config() IntegrationTestConfig + NewAdminClient() (*AdminClient, error) + // NewInstanceAdminClient will return nil if instance administration is unsupported in this environment + NewInstanceAdminClient() (*InstanceAdminClient, error) + NewClient() (*Client, error) + Close() +} + +// NewIntegrationEnv creates a new environment based on the command line args +func NewIntegrationEnv() (IntegrationEnv, error) { + c := integrationConfig + + if legacyUseProd != "" { + fmt.Println("WARNING: using legacy commandline arg -use_prod, please switch to -it.*") + parts := strings.SplitN(legacyUseProd, ",", 3) + c.UseProd = true + c.Project = parts[0] + c.Instance = parts[1] + c.Table = parts[2] + } + + if integrationConfig.UseProd { + return NewProdEnv(c) + } + return NewEmulatedEnv(c) +} + +// EmulatedEnv encapsulates the state of an emulator +type EmulatedEnv struct { + config IntegrationTestConfig + server *bttest.Server +} + +// NewEmulatedEnv builds and starts the emulator based environment +func NewEmulatedEnv(config IntegrationTestConfig) (*EmulatedEnv, error) { + srv, err := bttest.NewServer("localhost:0", grpc.MaxRecvMsgSize(200<<20), grpc.MaxSendMsgSize(100<<20)) + if err != nil { + return nil, err + } + + if config.Project == "" { + config.Project = "project" + } + if config.Instance == "" { + config.Instance = "instance" + } + if config.Table == "" { + config.Table = "mytable" + } + config.AdminEndpoint = srv.Addr + config.DataEndpoint = srv.Addr + + env := &EmulatedEnv{ + config: config, + server: srv, + } + return env, nil +} + +// Close stops & cleans up the emulator +func (e *EmulatedEnv) Close() { + e.server.Close() +} + +// Config gets the config used to build this environment +func (e *EmulatedEnv) Config() IntegrationTestConfig { + return e.config +} + +// NewAdminClient builds a new connected admin client for this environment +func (e *EmulatedEnv) NewAdminClient() (*AdminClient, error) { + timeout := 20 * time.Second + ctx, _ := context.WithTimeout(context.Background(), timeout) + conn, err := grpc.Dial(e.server.Addr, grpc.WithInsecure(), grpc.WithBlock()) + if err != nil { + return nil, err + } + return NewAdminClient(ctx, e.config.Project, e.config.Instance, option.WithGRPCConn(conn)) +} + +// NewInstanceAdminClient returns nil for the emulated environment since the API is not implemented. +func (e *EmulatedEnv) NewInstanceAdminClient() (*InstanceAdminClient, error) { + return nil, nil +} + +// NewClient builds a new connected data client for this environment +func (e *EmulatedEnv) NewClient() (*Client, error) { + timeout := 20 * time.Second + ctx, _ := context.WithTimeout(context.Background(), timeout) + conn, err := grpc.Dial(e.server.Addr, grpc.WithInsecure(), grpc.WithBlock(), + grpc.WithDefaultCallOptions(grpc.MaxCallSendMsgSize(100<<20), grpc.MaxCallRecvMsgSize(100<<20))) + if err != nil { + return nil, err + } + return NewClient(ctx, e.config.Project, e.config.Instance, option.WithGRPCConn(conn)) +} + +// ProdEnv encapsulates the state necessary to connect to the external Bigtable service +type ProdEnv struct { + config IntegrationTestConfig +} + +// NewProdEnv builds the environment representation +func NewProdEnv(config IntegrationTestConfig) (*ProdEnv, error) { + if config.Project == "" { + return nil, errors.New("Project not set") + } + if config.Instance == "" { + return nil, errors.New("Instance not set") + } + if config.Table == "" { + return nil, errors.New("Table not set") + } + + return &ProdEnv{config}, nil +} + +// Close is a no-op for production environments +func (e *ProdEnv) Close() {} + +// Config gets the config used to build this environment +func (e *ProdEnv) Config() IntegrationTestConfig { + return e.config +} + +// NewAdminClient builds a new connected admin client for this environment +func (e *ProdEnv) NewAdminClient() (*AdminClient, error) { + var clientOpts []option.ClientOption + if endpoint := e.config.AdminEndpoint; endpoint != "" { + clientOpts = append(clientOpts, option.WithEndpoint(endpoint)) + } + return NewAdminClient(context.Background(), e.config.Project, e.config.Instance, clientOpts...) +} + +// NewInstanceAdminClient returns a new connected instance admin client for this environment +func (e *ProdEnv) NewInstanceAdminClient() (*InstanceAdminClient, error) { + var clientOpts []option.ClientOption + if endpoint := e.config.AdminEndpoint; endpoint != "" { + clientOpts = append(clientOpts, option.WithEndpoint(endpoint)) + } + return NewInstanceAdminClient(context.Background(), e.config.Project, clientOpts...) +} + +// NewClient builds a connected data client for this environment +func (e *ProdEnv) NewClient() (*Client, error) { + var clientOpts []option.ClientOption + if endpoint := e.config.DataEndpoint; endpoint != "" { + clientOpts = append(clientOpts, option.WithEndpoint(endpoint)) + } + return NewClient(context.Background(), e.config.Project, e.config.Instance, clientOpts...) +} diff --git a/vendor/cloud.google.com/go/bigtable/filter.go b/vendor/cloud.google.com/go/bigtable/filter.go new file mode 100644 index 00000000..c42574f1 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/filter.go @@ -0,0 +1,330 @@ +/* +Copyright 2015 Google LLC + +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 bigtable + +import ( + "fmt" + "strings" + "time" + + btpb "google.golang.org/genproto/googleapis/bigtable/v2" +) + +// A Filter represents a row filter. +type Filter interface { + String() string + proto() *btpb.RowFilter +} + +// ChainFilters returns a filter that applies a sequence of filters. +func ChainFilters(sub ...Filter) Filter { return chainFilter{sub} } + +type chainFilter struct { + sub []Filter +} + +func (cf chainFilter) String() string { + var ss []string + for _, sf := range cf.sub { + ss = append(ss, sf.String()) + } + return "(" + strings.Join(ss, " | ") + ")" +} + +func (cf chainFilter) proto() *btpb.RowFilter { + chain := &btpb.RowFilter_Chain{} + for _, sf := range cf.sub { + chain.Filters = append(chain.Filters, sf.proto()) + } + return &btpb.RowFilter{ + Filter: &btpb.RowFilter_Chain_{Chain: chain}, + } +} + +// InterleaveFilters returns a filter that applies a set of filters in parallel +// and interleaves the results. +func InterleaveFilters(sub ...Filter) Filter { return interleaveFilter{sub} } + +type interleaveFilter struct { + sub []Filter +} + +func (ilf interleaveFilter) String() string { + var ss []string + for _, sf := range ilf.sub { + ss = append(ss, sf.String()) + } + return "(" + strings.Join(ss, " + ") + ")" +} + +func (ilf interleaveFilter) proto() *btpb.RowFilter { + inter := &btpb.RowFilter_Interleave{} + for _, sf := range ilf.sub { + inter.Filters = append(inter.Filters, sf.proto()) + } + return &btpb.RowFilter{ + Filter: &btpb.RowFilter_Interleave_{Interleave: inter}, + } +} + +// RowKeyFilter returns a filter that matches cells from rows whose +// key matches the provided RE2 pattern. +// See https://github.com/google/re2/wiki/Syntax for the accepted syntax. +func RowKeyFilter(pattern string) Filter { return rowKeyFilter(pattern) } + +type rowKeyFilter string + +func (rkf rowKeyFilter) String() string { return fmt.Sprintf("row(%s)", string(rkf)) } + +func (rkf rowKeyFilter) proto() *btpb.RowFilter { + return &btpb.RowFilter{Filter: &btpb.RowFilter_RowKeyRegexFilter{RowKeyRegexFilter: []byte(rkf)}} +} + +// FamilyFilter returns a filter that matches cells whose family name +// matches the provided RE2 pattern. +// See https://github.com/google/re2/wiki/Syntax for the accepted syntax. +func FamilyFilter(pattern string) Filter { return familyFilter(pattern) } + +type familyFilter string + +func (ff familyFilter) String() string { return fmt.Sprintf("col(%s:)", string(ff)) } + +func (ff familyFilter) proto() *btpb.RowFilter { + return &btpb.RowFilter{Filter: &btpb.RowFilter_FamilyNameRegexFilter{FamilyNameRegexFilter: string(ff)}} +} + +// ColumnFilter returns a filter that matches cells whose column name +// matches the provided RE2 pattern. +// See https://github.com/google/re2/wiki/Syntax for the accepted syntax. +func ColumnFilter(pattern string) Filter { return columnFilter(pattern) } + +type columnFilter string + +func (cf columnFilter) String() string { return fmt.Sprintf("col(.*:%s)", string(cf)) } + +func (cf columnFilter) proto() *btpb.RowFilter { + return &btpb.RowFilter{Filter: &btpb.RowFilter_ColumnQualifierRegexFilter{ColumnQualifierRegexFilter: []byte(cf)}} +} + +// ValueFilter returns a filter that matches cells whose value +// matches the provided RE2 pattern. +// See https://github.com/google/re2/wiki/Syntax for the accepted syntax. +func ValueFilter(pattern string) Filter { return valueFilter(pattern) } + +type valueFilter string + +func (vf valueFilter) String() string { return fmt.Sprintf("value_match(%s)", string(vf)) } + +func (vf valueFilter) proto() *btpb.RowFilter { + return &btpb.RowFilter{Filter: &btpb.RowFilter_ValueRegexFilter{ValueRegexFilter: []byte(vf)}} +} + +// LatestNFilter returns a filter that matches the most recent N cells in each column. +func LatestNFilter(n int) Filter { return latestNFilter(n) } + +type latestNFilter int32 + +func (lnf latestNFilter) String() string { return fmt.Sprintf("col(*,%d)", lnf) } + +func (lnf latestNFilter) proto() *btpb.RowFilter { + return &btpb.RowFilter{Filter: &btpb.RowFilter_CellsPerColumnLimitFilter{CellsPerColumnLimitFilter: int32(lnf)}} +} + +// StripValueFilter returns a filter that replaces each value with the empty string. +func StripValueFilter() Filter { return stripValueFilter{} } + +type stripValueFilter struct{} + +func (stripValueFilter) String() string { return "strip_value()" } +func (stripValueFilter) proto() *btpb.RowFilter { + return &btpb.RowFilter{Filter: &btpb.RowFilter_StripValueTransformer{StripValueTransformer: true}} +} + +// TimestampRangeFilter returns a filter that matches any cells whose timestamp is within the given time bounds. A zero +// time means no bound. +// The timestamp will be truncated to millisecond granularity. +func TimestampRangeFilter(startTime time.Time, endTime time.Time) Filter { + trf := timestampRangeFilter{} + if !startTime.IsZero() { + trf.startTime = Time(startTime) + } + if !endTime.IsZero() { + trf.endTime = Time(endTime) + } + return trf +} + +// TimestampRangeFilterMicros returns a filter that matches any cells whose timestamp is within the given time bounds, +// specified in units of microseconds since 1 January 1970. A zero value for the end time is interpreted as no bound. +// The timestamp will be truncated to millisecond granularity. +func TimestampRangeFilterMicros(startTime Timestamp, endTime Timestamp) Filter { + return timestampRangeFilter{startTime, endTime} +} + +type timestampRangeFilter struct { + startTime Timestamp + endTime Timestamp +} + +func (trf timestampRangeFilter) String() string { + return fmt.Sprintf("timestamp_range(%v,%v)", trf.startTime, trf.endTime) +} + +func (trf timestampRangeFilter) proto() *btpb.RowFilter { + return &btpb.RowFilter{ + Filter: &btpb.RowFilter_TimestampRangeFilter{TimestampRangeFilter: &btpb.TimestampRange{ + StartTimestampMicros: int64(trf.startTime.TruncateToMilliseconds()), + EndTimestampMicros: int64(trf.endTime.TruncateToMilliseconds()), + }, + }} +} + +// ColumnRangeFilter returns a filter that matches a contiguous range of columns within a single +// family, as specified by an inclusive start qualifier and exclusive end qualifier. +func ColumnRangeFilter(family, start, end string) Filter { + return columnRangeFilter{family, start, end} +} + +type columnRangeFilter struct { + family string + start string + end string +} + +func (crf columnRangeFilter) String() string { + return fmt.Sprintf("columnRangeFilter(%s,%s,%s)", crf.family, crf.start, crf.end) +} + +func (crf columnRangeFilter) proto() *btpb.RowFilter { + r := &btpb.ColumnRange{FamilyName: crf.family} + if crf.start != "" { + r.StartQualifier = &btpb.ColumnRange_StartQualifierClosed{StartQualifierClosed: []byte(crf.start)} + } + if crf.end != "" { + r.EndQualifier = &btpb.ColumnRange_EndQualifierOpen{EndQualifierOpen: []byte(crf.end)} + } + return &btpb.RowFilter{Filter: &btpb.RowFilter_ColumnRangeFilter{ColumnRangeFilter: r}} +} + +// ValueRangeFilter returns a filter that matches cells with values that fall within +// the given range, as specified by an inclusive start value and exclusive end value. +func ValueRangeFilter(start, end []byte) Filter { + return valueRangeFilter{start, end} +} + +type valueRangeFilter struct { + start []byte + end []byte +} + +func (vrf valueRangeFilter) String() string { + return fmt.Sprintf("valueRangeFilter(%s,%s)", vrf.start, vrf.end) +} + +func (vrf valueRangeFilter) proto() *btpb.RowFilter { + r := &btpb.ValueRange{} + if vrf.start != nil { + r.StartValue = &btpb.ValueRange_StartValueClosed{StartValueClosed: vrf.start} + } + if vrf.end != nil { + r.EndValue = &btpb.ValueRange_EndValueOpen{EndValueOpen: vrf.end} + } + return &btpb.RowFilter{Filter: &btpb.RowFilter_ValueRangeFilter{ValueRangeFilter: r}} +} + +// ConditionFilter returns a filter that evaluates to one of two possible filters depending +// on whether or not the given predicate filter matches at least one cell. +// If the matched filter is nil then no results will be returned. +// IMPORTANT NOTE: The predicate filter does not execute atomically with the +// true and false filters, which may lead to inconsistent or unexpected +// results. Additionally, condition filters have poor performance, especially +// when filters are set for the false condition. +func ConditionFilter(predicateFilter, trueFilter, falseFilter Filter) Filter { + return conditionFilter{predicateFilter, trueFilter, falseFilter} +} + +type conditionFilter struct { + predicateFilter Filter + trueFilter Filter + falseFilter Filter +} + +func (cf conditionFilter) String() string { + return fmt.Sprintf("conditionFilter(%s,%s,%s)", cf.predicateFilter, cf.trueFilter, cf.falseFilter) +} + +func (cf conditionFilter) proto() *btpb.RowFilter { + var tf *btpb.RowFilter + var ff *btpb.RowFilter + if cf.trueFilter != nil { + tf = cf.trueFilter.proto() + } + if cf.falseFilter != nil { + ff = cf.falseFilter.proto() + } + return &btpb.RowFilter{ + Filter: &btpb.RowFilter_Condition_{Condition: &btpb.RowFilter_Condition{ + PredicateFilter: cf.predicateFilter.proto(), + TrueFilter: tf, + FalseFilter: ff, + }}} +} + +// CellsPerRowOffsetFilter returns a filter that skips the first N cells of each row, matching all subsequent cells. +func CellsPerRowOffsetFilter(n int) Filter { + return cellsPerRowOffsetFilter(n) +} + +type cellsPerRowOffsetFilter int32 + +func (cof cellsPerRowOffsetFilter) String() string { + return fmt.Sprintf("cells_per_row_offset(%d)", cof) +} + +func (cof cellsPerRowOffsetFilter) proto() *btpb.RowFilter { + return &btpb.RowFilter{Filter: &btpb.RowFilter_CellsPerRowOffsetFilter{CellsPerRowOffsetFilter: int32(cof)}} +} + +// CellsPerRowLimitFilter returns a filter that matches only the first N cells of each row. +func CellsPerRowLimitFilter(n int) Filter { + return cellsPerRowLimitFilter(n) +} + +type cellsPerRowLimitFilter int32 + +func (clf cellsPerRowLimitFilter) String() string { + return fmt.Sprintf("cells_per_row_limit(%d)", clf) +} + +func (clf cellsPerRowLimitFilter) proto() *btpb.RowFilter { + return &btpb.RowFilter{Filter: &btpb.RowFilter_CellsPerRowLimitFilter{CellsPerRowLimitFilter: int32(clf)}} +} + +// RowSampleFilter returns a filter that matches a row with a probability of p (must be in the interval (0, 1)). +func RowSampleFilter(p float64) Filter { + return rowSampleFilter(p) +} + +type rowSampleFilter float64 + +func (rsf rowSampleFilter) String() string { + return fmt.Sprintf("filter(%f)", rsf) +} + +func (rsf rowSampleFilter) proto() *btpb.RowFilter { + return &btpb.RowFilter{Filter: &btpb.RowFilter_RowSampleFilter{RowSampleFilter: float64(rsf)}} +} diff --git a/vendor/cloud.google.com/go/bigtable/gc.go b/vendor/cloud.google.com/go/bigtable/gc.go new file mode 100644 index 00000000..dce4c823 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/gc.go @@ -0,0 +1,167 @@ +/* +Copyright 2015 Google LLC + +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 bigtable + +import ( + "fmt" + "strings" + "time" + + durpb "github.com/golang/protobuf/ptypes/duration" + bttdpb "google.golang.org/genproto/googleapis/bigtable/admin/v2" +) + +// A GCPolicy represents a rule that determines which cells are eligible for garbage collection. +type GCPolicy interface { + String() string + proto() *bttdpb.GcRule +} + +// IntersectionPolicy returns a GC policy that only applies when all its sub-policies apply. +func IntersectionPolicy(sub ...GCPolicy) GCPolicy { return intersectionPolicy{sub} } + +type intersectionPolicy struct { + sub []GCPolicy +} + +func (ip intersectionPolicy) String() string { + var ss []string + for _, sp := range ip.sub { + ss = append(ss, sp.String()) + } + return "(" + strings.Join(ss, " && ") + ")" +} + +func (ip intersectionPolicy) proto() *bttdpb.GcRule { + inter := &bttdpb.GcRule_Intersection{} + for _, sp := range ip.sub { + inter.Rules = append(inter.Rules, sp.proto()) + } + return &bttdpb.GcRule{ + Rule: &bttdpb.GcRule_Intersection_{Intersection: inter}, + } +} + +// UnionPolicy returns a GC policy that applies when any of its sub-policies apply. +func UnionPolicy(sub ...GCPolicy) GCPolicy { return unionPolicy{sub} } + +type unionPolicy struct { + sub []GCPolicy +} + +func (up unionPolicy) String() string { + var ss []string + for _, sp := range up.sub { + ss = append(ss, sp.String()) + } + return "(" + strings.Join(ss, " || ") + ")" +} + +func (up unionPolicy) proto() *bttdpb.GcRule { + union := &bttdpb.GcRule_Union{} + for _, sp := range up.sub { + union.Rules = append(union.Rules, sp.proto()) + } + return &bttdpb.GcRule{ + Rule: &bttdpb.GcRule_Union_{Union: union}, + } +} + +// MaxVersionsPolicy returns a GC policy that applies to all versions of a cell +// except for the most recent n. +func MaxVersionsPolicy(n int) GCPolicy { return maxVersionsPolicy(n) } + +type maxVersionsPolicy int + +func (mvp maxVersionsPolicy) String() string { return fmt.Sprintf("versions() > %d", int(mvp)) } + +func (mvp maxVersionsPolicy) proto() *bttdpb.GcRule { + return &bttdpb.GcRule{Rule: &bttdpb.GcRule_MaxNumVersions{MaxNumVersions: int32(mvp)}} +} + +// MaxAgePolicy returns a GC policy that applies to all cells +// older than the given age. +func MaxAgePolicy(d time.Duration) GCPolicy { return maxAgePolicy(d) } + +type maxAgePolicy time.Duration + +var units = []struct { + d time.Duration + suffix string +}{ + {24 * time.Hour, "d"}, + {time.Hour, "h"}, + {time.Minute, "m"}, +} + +func (ma maxAgePolicy) String() string { + d := time.Duration(ma) + for _, u := range units { + if d%u.d == 0 { + return fmt.Sprintf("age() > %d%s", d/u.d, u.suffix) + } + } + return fmt.Sprintf("age() > %d", d/time.Microsecond) +} + +func (ma maxAgePolicy) proto() *bttdpb.GcRule { + // This doesn't handle overflows, etc. + // Fix this if people care about GC policies over 290 years. + ns := time.Duration(ma).Nanoseconds() + return &bttdpb.GcRule{ + Rule: &bttdpb.GcRule_MaxAge{MaxAge: &durpb.Duration{ + Seconds: ns / 1e9, + Nanos: int32(ns % 1e9), + }}, + } +} + +type noGCPolicy struct{} + +func (n noGCPolicy) String() string { return "" } + +func (n noGCPolicy) proto() *bttdpb.GcRule { return &bttdpb.GcRule{Rule: nil} } + +// NoGcPolicy applies to all cells setting maxage and maxversions to nil implies no gc policies +func NoGcPolicy() GCPolicy { return noGCPolicy{} } + +// GCRuleToString converts the given GcRule proto to a user-visible string. +func GCRuleToString(rule *bttdpb.GcRule) string { + if rule == nil { + return "" + } + switch r := rule.Rule.(type) { + case *bttdpb.GcRule_MaxNumVersions: + return MaxVersionsPolicy(int(r.MaxNumVersions)).String() + case *bttdpb.GcRule_MaxAge: + return MaxAgePolicy(time.Duration(r.MaxAge.Seconds) * time.Second).String() + case *bttdpb.GcRule_Intersection_: + return joinRules(r.Intersection.Rules, " && ") + case *bttdpb.GcRule_Union_: + return joinRules(r.Union.Rules, " || ") + default: + return "" + } +} + +func joinRules(rules []*bttdpb.GcRule, sep string) string { + var chunks []string + for _, r := range rules { + chunks = append(chunks, GCRuleToString(r)) + } + return "(" + strings.Join(chunks, sep) + ")" +} diff --git a/vendor/cloud.google.com/go/bigtable/gc_test.go b/vendor/cloud.google.com/go/bigtable/gc_test.go new file mode 100644 index 00000000..70849ab4 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/gc_test.go @@ -0,0 +1,46 @@ +/* +Copyright 2017 Google LLC + +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 bigtable + +import ( + "testing" + "time" + + bttdpb "google.golang.org/genproto/googleapis/bigtable/admin/v2" +) + +func TestGcRuleToString(t *testing.T) { + + intersection := IntersectionPolicy(MaxVersionsPolicy(5), MaxVersionsPolicy(10), MaxAgePolicy(16*time.Hour)) + + var tests = []struct { + proto *bttdpb.GcRule + want string + }{ + {MaxAgePolicy(72 * time.Hour).proto(), "age() > 3d"}, + {MaxVersionsPolicy(5).proto(), "versions() > 5"}, + {intersection.proto(), "(versions() > 5 && versions() > 10 && age() > 16h)"}, + {UnionPolicy(intersection, MaxAgePolicy(72*time.Hour)).proto(), + "((versions() > 5 && versions() > 10 && age() > 16h) || age() > 3d)"}, + } + + for _, test := range tests { + got := GCRuleToString(test.proto) + if got != test.want { + t.Errorf("got gc rule string: %v, wanted: %v", got, test.want) + } + } +} diff --git a/vendor/cloud.google.com/go/bigtable/internal/cbtconfig/cbtconfig.go b/vendor/cloud.google.com/go/bigtable/internal/cbtconfig/cbtconfig.go new file mode 100644 index 00000000..f60c5e9f --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/internal/cbtconfig/cbtconfig.go @@ -0,0 +1,262 @@ +/* +Copyright 2015 Google LLC + +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 cbtconfig encapsulates common code for reading configuration from .cbtrc and gcloud. +package cbtconfig + +import ( + "bufio" + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "time" + + "golang.org/x/oauth2" + "google.golang.org/grpc/credentials" +) + +// Config represents a configuration. +type Config struct { + Project, Instance string // required + Creds string // optional + AdminEndpoint string // optional + DataEndpoint string // optional + CertFile string // optional + UserAgent string // optional + TokenSource oauth2.TokenSource // derived + TLSCreds credentials.TransportCredentials // derived +} + +// RequiredFlags describes the flag requirements for a cbt command. +type RequiredFlags uint + +const ( + // NoneRequired specifies that not flags are required. + NoneRequired RequiredFlags = 0 + // ProjectRequired specifies that the -project flag is required. + ProjectRequired RequiredFlags = 1 << iota + // InstanceRequired specifies that the -instance flag is required. + InstanceRequired + // ProjectAndInstanceRequired specifies that both -project and -instance is required. + ProjectAndInstanceRequired = ProjectRequired | InstanceRequired +) + +// RegisterFlags registers a set of standard flags for this config. +// It should be called before flag.Parse. +func (c *Config) RegisterFlags() { + flag.StringVar(&c.Project, "project", c.Project, "project ID, if unset uses gcloud configured project") + flag.StringVar(&c.Instance, "instance", c.Instance, "Cloud Bigtable instance") + flag.StringVar(&c.Creds, "creds", c.Creds, "if set, use application credentials in this file") + flag.StringVar(&c.AdminEndpoint, "admin-endpoint", c.AdminEndpoint, "Override the admin api endpoint") + flag.StringVar(&c.DataEndpoint, "data-endpoint", c.DataEndpoint, "Override the data api endpoint") + flag.StringVar(&c.CertFile, "cert-file", c.CertFile, "Override the TLS certificates file") + flag.StringVar(&c.UserAgent, "user-agent", c.UserAgent, "Override the user agent string") +} + +// CheckFlags checks that the required config values are set. +func (c *Config) CheckFlags(required RequiredFlags) error { + var missing []string + if c.CertFile != "" { + b, err := ioutil.ReadFile(c.CertFile) + if err != nil { + return fmt.Errorf("Failed to load certificates from %s: %v", c.CertFile, err) + } + + cp := x509.NewCertPool() + if !cp.AppendCertsFromPEM(b) { + return fmt.Errorf("Failed to append certificates from %s", c.CertFile) + } + + c.TLSCreds = credentials.NewTLS(&tls.Config{RootCAs: cp}) + } + if required != NoneRequired { + c.SetFromGcloud() + } + if required&ProjectRequired != 0 && c.Project == "" { + missing = append(missing, "-project") + } + if required&InstanceRequired != 0 && c.Instance == "" { + missing = append(missing, "-instance") + } + if len(missing) > 0 { + return fmt.Errorf("Missing %s", strings.Join(missing, " and ")) + } + return nil +} + +// Filename returns the filename consulted for standard configuration. +func Filename() string { + // TODO(dsymonds): Might need tweaking for Windows. + return filepath.Join(os.Getenv("HOME"), ".cbtrc") +} + +// Load loads a .cbtrc file. +// If the file is not present, an empty config is returned. +func Load() (*Config, error) { + filename := Filename() + data, err := ioutil.ReadFile(filename) + if err != nil { + // silent fail if the file isn't there + if os.IsNotExist(err) { + return &Config{}, nil + } + return nil, fmt.Errorf("Reading %s: %v", filename, err) + } + c := new(Config) + s := bufio.NewScanner(bytes.NewReader(data)) + for s.Scan() { + line := s.Text() + i := strings.Index(line, "=") + if i < 0 { + return nil, fmt.Errorf("Bad line in %s: %q", filename, line) + } + key, val := strings.TrimSpace(line[:i]), strings.TrimSpace(line[i+1:]) + switch key { + default: + return nil, fmt.Errorf("Unknown key in %s: %q", filename, key) + case "project": + c.Project = val + case "instance": + c.Instance = val + case "creds": + c.Creds = val + case "admin-endpoint": + c.AdminEndpoint = val + case "data-endpoint": + c.DataEndpoint = val + case "cert-file": + c.CertFile = val + case "user-agent": + c.UserAgent = val + } + + } + return c, s.Err() +} + +// GcloudCredential holds gcloud credential information. +type GcloudCredential struct { + AccessToken string `json:"access_token"` + Expiry time.Time `json:"token_expiry"` +} + +// Token creates an oauth2 token using gcloud credentials. +func (cred *GcloudCredential) Token() *oauth2.Token { + return &oauth2.Token{AccessToken: cred.AccessToken, TokenType: "Bearer", Expiry: cred.Expiry} +} + +// GcloudConfig holds gcloud configuration values. +type GcloudConfig struct { + Configuration struct { + Properties struct { + Core struct { + Project string `json:"project"` + } `json:"core"` + } `json:"properties"` + } `json:"configuration"` + Credential GcloudCredential `json:"credential"` +} + +// GcloudCmdTokenSource holds the comamnd arguments. It is only intended to be set by the program. +// TODO(deklerk) Can this be unexported? +type GcloudCmdTokenSource struct { + Command string + Args []string +} + +// Token implements the oauth2.TokenSource interface +func (g *GcloudCmdTokenSource) Token() (*oauth2.Token, error) { + gcloudConfig, err := LoadGcloudConfig(g.Command, g.Args) + if err != nil { + return nil, err + } + return gcloudConfig.Credential.Token(), nil +} + +// LoadGcloudConfig retrieves the gcloud configuration values we need use via the +// 'config-helper' command +func LoadGcloudConfig(gcloudCmd string, gcloudCmdArgs []string) (*GcloudConfig, error) { + out, err := exec.Command(gcloudCmd, gcloudCmdArgs...).Output() + if err != nil { + return nil, fmt.Errorf("Could not retrieve gcloud configuration") + } + + var gcloudConfig GcloudConfig + if err := json.Unmarshal(out, &gcloudConfig); err != nil { + return nil, fmt.Errorf("Could not parse gcloud configuration") + } + + return &gcloudConfig, nil +} + +// SetFromGcloud retrieves and sets any missing config values from the gcloud +// configuration if possible possible +func (c *Config) SetFromGcloud() error { + + if c.Creds == "" { + c.Creds = os.Getenv("GOOGLE_APPLICATION_CREDENTIALS") + if c.Creds == "" { + log.Printf("-creds flag unset, will use gcloud credential") + } + } else { + os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", c.Creds) + } + + if c.Project == "" { + log.Printf("-project flag unset, will use gcloud active project") + } + + if c.Creds != "" && c.Project != "" { + return nil + } + + gcloudCmd := "gcloud" + if runtime.GOOS == "windows" { + gcloudCmd = gcloudCmd + ".cmd" + } + + gcloudCmdArgs := []string{"config", "config-helper", + "--format=json(configuration.properties.core.project,credential)"} + + gcloudConfig, err := LoadGcloudConfig(gcloudCmd, gcloudCmdArgs) + if err != nil { + return err + } + + if c.Project == "" && gcloudConfig.Configuration.Properties.Core.Project != "" { + log.Printf("gcloud active project is \"%s\"", + gcloudConfig.Configuration.Properties.Core.Project) + c.Project = gcloudConfig.Configuration.Properties.Core.Project + } + + if c.Creds == "" { + c.TokenSource = oauth2.ReuseTokenSource( + gcloudConfig.Credential.Token(), + &GcloudCmdTokenSource{Command: gcloudCmd, Args: gcloudCmdArgs}) + } + + return nil +} diff --git a/vendor/cloud.google.com/go/bigtable/internal/gax/call_option.go b/vendor/cloud.google.com/go/bigtable/internal/gax/call_option.go new file mode 100644 index 00000000..79c580b0 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/internal/gax/call_option.go @@ -0,0 +1,110 @@ +/* +Copyright 2016 Google LLC + +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 gax is a snapshot from github.com/googleapis/gax-go with minor modifications. +package gax + +import ( + "time" + + "google.golang.org/grpc/codes" +) + +// CallOption is a generic interface for modifying the behavior of outbound calls. +type CallOption interface { + Resolve(*CallSettings) +} + +type callOptions []CallOption + +// Resolve resolves all call options individually. +func (opts callOptions) Resolve(s *CallSettings) *CallSettings { + for _, opt := range opts { + opt.Resolve(s) + } + return s +} + +// CallSettings encapsulates the call settings for a particular API call. +type CallSettings struct { + Timeout time.Duration + RetrySettings RetrySettings +} + +// RetrySettings are per-call configurable settings for retrying upon transient failure. +type RetrySettings struct { + RetryCodes map[codes.Code]bool + BackoffSettings BackoffSettings +} + +// BackoffSettings are parameters to the exponential backoff algorithm for retrying. +type BackoffSettings struct { + DelayTimeoutSettings MultipliableDuration + RPCTimeoutSettings MultipliableDuration +} + +// MultipliableDuration defines parameters for backoff settings. +type MultipliableDuration struct { + Initial time.Duration + Max time.Duration + Multiplier float64 +} + +// Resolve merges the receiver CallSettings into the given CallSettings. +func (w CallSettings) Resolve(s *CallSettings) { + s.Timeout = w.Timeout + s.RetrySettings = w.RetrySettings + + s.RetrySettings.RetryCodes = make(map[codes.Code]bool, len(w.RetrySettings.RetryCodes)) + for key, value := range w.RetrySettings.RetryCodes { + s.RetrySettings.RetryCodes[key] = value + } +} + +type withRetryCodes []codes.Code + +func (w withRetryCodes) Resolve(s *CallSettings) { + s.RetrySettings.RetryCodes = make(map[codes.Code]bool) + for _, code := range w { + s.RetrySettings.RetryCodes[code] = true + } +} + +// WithRetryCodes sets a list of Google API canonical error codes upon which a +// retry should be attempted. +func WithRetryCodes(retryCodes []codes.Code) CallOption { + return withRetryCodes(retryCodes) +} + +type withDelayTimeoutSettings MultipliableDuration + +func (w withDelayTimeoutSettings) Resolve(s *CallSettings) { + s.RetrySettings.BackoffSettings.DelayTimeoutSettings = MultipliableDuration(w) +} + +// WithDelayTimeoutSettings specifies: +// - The initial delay time, in milliseconds, between the completion of +// the first failed request and the initiation of the first retrying +// request. +// - The multiplier by which to increase the delay time between the +// completion of failed requests, and the initiation of the subsequent +// retrying request. +// - The maximum delay time, in milliseconds, between requests. When this +// value is reached, `RetryDelayMultiplier` will no longer be used to +// increase delay time. +func WithDelayTimeoutSettings(initial time.Duration, max time.Duration, multiplier float64) CallOption { + return withDelayTimeoutSettings(MultipliableDuration{initial, max, multiplier}) +} diff --git a/vendor/cloud.google.com/go/bigtable/internal/gax/invoke.go b/vendor/cloud.google.com/go/bigtable/internal/gax/invoke.go new file mode 100644 index 00000000..228dd443 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/internal/gax/invoke.go @@ -0,0 +1,87 @@ +/* +Copyright 2015 Google LLC + +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 gax is a snapshot from github.com/googleapis/gax-go with minor modifications. +package gax + +import ( + "context" + "log" + "math/rand" + "os" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" +) + +// Logger is a logger that logs to stderr. +var Logger = log.New(os.Stderr, "", log.LstdFlags) + +// APICall is a user defined call stub. +type APICall func(context.Context) error + +// scaleDuration returns the product of a and mult. +func scaleDuration(a time.Duration, mult float64) time.Duration { + ns := float64(a) * mult + return time.Duration(ns) +} + +// invokeWithRetry calls stub using an exponential backoff retry mechanism +// based on the values provided in callSettings. +func invokeWithRetry(ctx context.Context, stub APICall, callSettings CallSettings) error { + retrySettings := callSettings.RetrySettings + backoffSettings := callSettings.RetrySettings.BackoffSettings + delay := backoffSettings.DelayTimeoutSettings.Initial + for { + // If the deadline is exceeded... + if ctx.Err() != nil { + return ctx.Err() + } + err := stub(ctx) + code := grpc.Code(err) + if code == codes.OK { + return nil + } + + if !retrySettings.RetryCodes[code] { + return err + } + + // Sleep a random amount up to the current delay + d := time.Duration(rand.Int63n(int64(delay))) + delayCtx, _ := context.WithTimeout(ctx, delay) + if Logger != nil { + Logger.Printf("Retryable error: %v, retrying in %v", err, d) + } + <-delayCtx.Done() + + delay = scaleDuration(delay, backoffSettings.DelayTimeoutSettings.Multiplier) + if delay > backoffSettings.DelayTimeoutSettings.Max { + delay = backoffSettings.DelayTimeoutSettings.Max + } + } +} + +// Invoke calls stub with a child of context modified by the specified options. +func Invoke(ctx context.Context, stub APICall, opts ...CallOption) error { + settings := &CallSettings{} + callOptions(opts).Resolve(settings) + if len(settings.RetrySettings.RetryCodes) > 0 { + return invokeWithRetry(ctx, stub, *settings) + } + return stub(ctx) +} diff --git a/vendor/cloud.google.com/go/bigtable/internal/gax/invoke_test.go b/vendor/cloud.google.com/go/bigtable/internal/gax/invoke_test.go new file mode 100644 index 00000000..633ba687 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/internal/gax/invoke_test.go @@ -0,0 +1,49 @@ +/* +Copyright 2015 Google LLC + +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 gax + +import ( + "context" + "testing" + "time" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestRandomizedDelays(t *testing.T) { + max := 200 * time.Millisecond + settings := []CallOption{ + WithRetryCodes([]codes.Code{codes.Unavailable, codes.DeadlineExceeded}), + WithDelayTimeoutSettings(10*time.Millisecond, max, 1.5), + } + + deadline := time.Now().Add(1 * time.Second) + ctx, _ := context.WithDeadline(context.Background(), deadline) + var invokeTime time.Time + _ = Invoke(ctx, func(childCtx context.Context) error { + // Keep failing, make sure we never slept more than max (plus a fudge factor) + if !invokeTime.IsZero() { + if got, want := time.Since(invokeTime), max; got > (want + 20*time.Millisecond) { + t.Logf("Slept too long. Got: %v, want: %v", got, max) + } + } + invokeTime = time.Now() + // Workaround for `go vet`: https://github.com/grpc/grpc-go/issues/90 + errf := status.Errorf + return errf(codes.Unavailable, "") + }, settings...) +} diff --git a/vendor/cloud.google.com/go/bigtable/internal/option/option.go b/vendor/cloud.google.com/go/bigtable/internal/option/option.go new file mode 100644 index 00000000..d0869863 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/internal/option/option.go @@ -0,0 +1,48 @@ +/* +Copyright 2015 Google LLC + +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 option contains common code for dealing with client options. +package option + +import ( + "fmt" + "os" + + "google.golang.org/api/option" + "google.golang.org/grpc" +) + +// DefaultClientOptions returns the default client options to use for the +// client's gRPC connection. +func DefaultClientOptions(endpoint, scope, userAgent string) ([]option.ClientOption, error) { + var o []option.ClientOption + // Check the environment variables for the bigtable emulator. + // Dial it directly and don't pass any credentials. + if addr := os.Getenv("BIGTABLE_EMULATOR_HOST"); addr != "" { + conn, err := grpc.Dial(addr, grpc.WithInsecure()) + if err != nil { + return nil, fmt.Errorf("emulator grpc.Dial: %v", err) + } + o = []option.ClientOption{option.WithGRPCConn(conn)} + } else { + o = []option.ClientOption{ + option.WithEndpoint(endpoint), + option.WithScopes(scope), + option.WithUserAgent(userAgent), + } + } + return o, nil +} diff --git a/vendor/cloud.google.com/go/bigtable/internal/stat/stats.go b/vendor/cloud.google.com/go/bigtable/internal/stat/stats.go new file mode 100644 index 00000000..1470130a --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/internal/stat/stats.go @@ -0,0 +1,150 @@ +// Copyright 2016 Google LLC +// +// 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 stat + +import ( + "bytes" + "encoding/csv" + "fmt" + "io" + "math" + "sort" + "strconv" + "text/tabwriter" + "time" +) + +type byDuration []time.Duration + +func (data byDuration) Len() int { return len(data) } +func (data byDuration) Swap(i, j int) { data[i], data[j] = data[j], data[i] } +func (data byDuration) Less(i, j int) bool { return data[i] < data[j] } + +// quantile returns a value representing the kth of q quantiles. +// May alter the order of data. +func quantile(data []time.Duration, k, q int) (quantile time.Duration, ok bool) { + if len(data) < 1 { + return 0, false + } + if k > q { + return 0, false + } + if k < 0 || q < 1 { + return 0, false + } + + sort.Sort(byDuration(data)) + + if k == 0 { + return data[0], true + } + if k == q { + return data[len(data)-1], true + } + + bucketSize := float64(len(data)-1) / float64(q) + i := float64(k) * bucketSize + + lower := int(math.Trunc(i)) + var upper int + if i > float64(lower) && lower+1 < len(data) { + // If the quantile lies between two elements + upper = lower + 1 + } else { + upper = lower + } + weightUpper := i - float64(lower) + weightLower := 1 - weightUpper + return time.Duration(weightLower*float64(data[lower]) + weightUpper*float64(data[upper])), true +} + +// Aggregate is an aggregate of latencies. +type Aggregate struct { + Name string + Count, Errors int + Min, Median, Max time.Duration + P75, P90, P95, P99 time.Duration // percentiles +} + +// NewAggregate constructs an aggregate from latencies. Returns nil if latencies does not contain aggregateable data. +func NewAggregate(name string, latencies []time.Duration, errorCount int) *Aggregate { + agg := Aggregate{Name: name, Count: len(latencies), Errors: errorCount} + + if len(latencies) == 0 { + return nil + } + var ok bool + if agg.Min, ok = quantile(latencies, 0, 2); !ok { + return nil + } + if agg.Median, ok = quantile(latencies, 1, 2); !ok { + return nil + } + if agg.Max, ok = quantile(latencies, 2, 2); !ok { + return nil + } + if agg.P75, ok = quantile(latencies, 75, 100); !ok { + return nil + } + if agg.P90, ok = quantile(latencies, 90, 100); !ok { + return nil + } + if agg.P95, ok = quantile(latencies, 95, 100); !ok { + return nil + } + if agg.P99, ok = quantile(latencies, 99, 100); !ok { + return nil + } + return &agg +} + +func (agg *Aggregate) String() string { + if agg == nil { + return "no data" + } + var buf bytes.Buffer + tw := tabwriter.NewWriter(&buf, 0, 0, 1, ' ', 0) // one-space padding + fmt.Fprintf(tw, "min:\t%v\nmedian:\t%v\nmax:\t%v\n95th percentile:\t%v\n99th percentile:\t%v\n", + agg.Min, agg.Median, agg.Max, agg.P95, agg.P99) + tw.Flush() + return buf.String() +} + +// WriteCSV writes a csv file to the given Writer, +// with a header row and one row per aggregate. +func WriteCSV(aggs []*Aggregate, iow io.Writer) (err error) { + w := csv.NewWriter(iow) + defer func() { + w.Flush() + if err == nil { + err = w.Error() + } + }() + err = w.Write([]string{"name", "count", "errors", "min", "median", "max", "p75", "p90", "p95", "p99"}) + if err != nil { + return err + } + for _, agg := range aggs { + err = w.Write([]string{ + agg.Name, strconv.Itoa(agg.Count), strconv.Itoa(agg.Errors), + agg.Min.String(), agg.Median.String(), agg.Max.String(), + agg.P75.String(), agg.P90.String(), agg.P95.String(), agg.P99.String(), + }) + if err != nil { + return err + } + } + return nil +} diff --git a/vendor/cloud.google.com/go/bigtable/reader.go b/vendor/cloud.google.com/go/bigtable/reader.go new file mode 100644 index 00000000..c84a61e4 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/reader.go @@ -0,0 +1,249 @@ +/* +Copyright 2016 Google LLC + +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 bigtable + +import ( + "bytes" + "fmt" + + btpb "google.golang.org/genproto/googleapis/bigtable/v2" +) + +// A Row is returned by ReadRows. The map is keyed by column family (the prefix +// of the column name before the colon). The values are the returned ReadItems +// for that column family in the order returned by Read. +type Row map[string][]ReadItem + +// Key returns the row's key, or "" if the row is empty. +func (r Row) Key() string { + for _, items := range r { + if len(items) > 0 { + return items[0].Row + } + } + return "" +} + +// A ReadItem is returned by Read. A ReadItem contains data from a specific row and column. +type ReadItem struct { + Row, Column string + Timestamp Timestamp + Value []byte +} + +// The current state of the read rows state machine. +type rrState int64 + +const ( + newRow rrState = iota + rowInProgress + cellInProgress +) + +// chunkReader handles cell chunks from the read rows response and combines +// them into full Rows. +type chunkReader struct { + state rrState + curKey []byte + curFam string + curQual []byte + curTS int64 + curVal []byte + curRow Row + lastKey string +} + +// newChunkReader returns a new chunkReader for handling read rows responses. +func newChunkReader() *chunkReader { + return &chunkReader{state: newRow} +} + +// Process takes a cell chunk and returns a new Row if the given chunk +// completes a Row, or nil otherwise. +func (cr *chunkReader) Process(cc *btpb.ReadRowsResponse_CellChunk) (Row, error) { + var row Row + switch cr.state { + case newRow: + if err := cr.validateNewRow(cc); err != nil { + return nil, err + } + + cr.curRow = make(Row) + cr.curKey = cc.RowKey + cr.curFam = cc.FamilyName.Value + cr.curQual = cc.Qualifier.Value + cr.curTS = cc.TimestampMicros + row = cr.handleCellValue(cc) + + case rowInProgress: + if err := cr.validateRowInProgress(cc); err != nil { + return nil, err + } + + if cc.GetResetRow() { + cr.resetToNewRow() + return nil, nil + } + + if cc.FamilyName != nil { + cr.curFam = cc.FamilyName.Value + } + if cc.Qualifier != nil { + cr.curQual = cc.Qualifier.Value + } + cr.curTS = cc.TimestampMicros + row = cr.handleCellValue(cc) + + case cellInProgress: + if err := cr.validateCellInProgress(cc); err != nil { + return nil, err + } + if cc.GetResetRow() { + cr.resetToNewRow() + return nil, nil + } + row = cr.handleCellValue(cc) + } + + return row, nil +} + +// Close must be called after all cell chunks from the response +// have been processed. An error will be returned if the reader is +// in an invalid state, in which case the error should be propagated to the caller. +func (cr *chunkReader) Close() error { + if cr.state != newRow { + return fmt.Errorf("invalid state for end of stream %q", cr.state) + } + return nil +} + +// handleCellValue returns a Row if the cell value includes a commit, otherwise nil. +func (cr *chunkReader) handleCellValue(cc *btpb.ReadRowsResponse_CellChunk) Row { + if cc.ValueSize > 0 { + // ValueSize is specified so expect a split value of ValueSize bytes + if cr.curVal == nil { + cr.curVal = make([]byte, 0, cc.ValueSize) + } + cr.curVal = append(cr.curVal, cc.Value...) + cr.state = cellInProgress + } else { + // This cell is either the complete value or the last chunk of a split + if cr.curVal == nil { + cr.curVal = cc.Value + } else { + cr.curVal = append(cr.curVal, cc.Value...) + } + cr.finishCell() + + if cc.GetCommitRow() { + return cr.commitRow() + } + cr.state = rowInProgress + } + + return nil +} + +func (cr *chunkReader) finishCell() { + ri := ReadItem{ + Row: string(cr.curKey), + Column: string(cr.curFam) + ":" + string(cr.curQual), + Timestamp: Timestamp(cr.curTS), + Value: cr.curVal, + } + cr.curRow[cr.curFam] = append(cr.curRow[cr.curFam], ri) + cr.curVal = nil +} + +func (cr *chunkReader) commitRow() Row { + row := cr.curRow + cr.lastKey = cr.curRow.Key() + cr.resetToNewRow() + return row +} + +func (cr *chunkReader) resetToNewRow() { + cr.curKey = nil + cr.curFam = "" + cr.curQual = nil + cr.curVal = nil + cr.curRow = nil + cr.curTS = 0 + cr.state = newRow +} + +func (cr *chunkReader) validateNewRow(cc *btpb.ReadRowsResponse_CellChunk) error { + if cc.GetResetRow() { + return fmt.Errorf("reset_row not allowed between rows") + } + if cc.RowKey == nil || cc.FamilyName == nil || cc.Qualifier == nil { + return fmt.Errorf("missing key field for new row %v", cc) + } + if cr.lastKey != "" && cr.lastKey >= string(cc.RowKey) { + return fmt.Errorf("out of order row key: %q, %q", cr.lastKey, string(cc.RowKey)) + } + return nil +} + +func (cr *chunkReader) validateRowInProgress(cc *btpb.ReadRowsResponse_CellChunk) error { + if err := cr.validateRowStatus(cc); err != nil { + return err + } + if cc.RowKey != nil && !bytes.Equal(cc.RowKey, cr.curKey) { + return fmt.Errorf("received new row key %q during existing row %q", cc.RowKey, cr.curKey) + } + if cc.FamilyName != nil && cc.Qualifier == nil { + return fmt.Errorf("family name %q specified without a qualifier", cc.FamilyName) + } + return nil +} + +func (cr *chunkReader) validateCellInProgress(cc *btpb.ReadRowsResponse_CellChunk) error { + if err := cr.validateRowStatus(cc); err != nil { + return err + } + if cr.curVal == nil { + return fmt.Errorf("no cached cell while CELL_IN_PROGRESS %v", cc) + } + if cc.GetResetRow() == false && cr.isAnyKeyPresent(cc) { + return fmt.Errorf("cell key components found while CELL_IN_PROGRESS %v", cc) + } + return nil +} + +func (cr *chunkReader) isAnyKeyPresent(cc *btpb.ReadRowsResponse_CellChunk) bool { + return cc.RowKey != nil || + cc.FamilyName != nil || + cc.Qualifier != nil || + cc.TimestampMicros != 0 +} + +// Validate a RowStatus, commit or reset, if present. +func (cr *chunkReader) validateRowStatus(cc *btpb.ReadRowsResponse_CellChunk) error { + // Resets can't be specified with any other part of a cell + if cc.GetResetRow() && (cr.isAnyKeyPresent(cc) || + cc.Value != nil || + cc.ValueSize != 0 || + cc.Labels != nil) { + return fmt.Errorf("reset must not be specified with other fields %v", cc) + } + if cc.GetCommitRow() && cc.ValueSize > 0 { + return fmt.Errorf("commit row found in between chunks in a cell") + } + return nil +} diff --git a/vendor/cloud.google.com/go/bigtable/reader_test.go b/vendor/cloud.google.com/go/bigtable/reader_test.go new file mode 100644 index 00000000..8264dc3e --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/reader_test.go @@ -0,0 +1,350 @@ +/* +Copyright 2016 Google LLC + +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 bigtable + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "strings" + "testing" + + "cloud.google.com/go/internal/testutil" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/wrappers" + btspb "google.golang.org/genproto/googleapis/bigtable/v2" +) + +// Indicates that a field in the proto should be omitted, rather than included +// as a wrapped empty string. +const nilStr = "<>" + +func TestSingleCell(t *testing.T) { + cr := newChunkReader() + + // All in one cell + row, err := cr.Process(cc("rk", "fm", "col", 1, "value", 0, true)) + if err != nil { + t.Fatalf("Processing chunk: %v", err) + } + if row == nil { + t.Fatalf("Missing row") + } + if len(row["fm"]) != 1 { + t.Fatalf("Family name length mismatch %d, %d", 1, len(row["fm"])) + } + want := []ReadItem{ri("rk", "fm", "col", 1, "value")} + if !testutil.Equal(row["fm"], want) { + t.Fatalf("Incorrect ReadItem: got: %v\nwant: %v\n", row["fm"], want) + } + if err := cr.Close(); err != nil { + t.Fatalf("Close: %v", err) + } +} + +func TestMultipleCells(t *testing.T) { + cr := newChunkReader() + + mustProcess(t, cr, cc("rs", "fm1", "col1", 0, "val1", 0, false)) + mustProcess(t, cr, cc("rs", "fm1", "col1", 1, "val2", 0, false)) + mustProcess(t, cr, cc("rs", "fm1", "col2", 0, "val3", 0, false)) + mustProcess(t, cr, cc("rs", "fm2", "col1", 0, "val4", 0, false)) + row, err := cr.Process(cc("rs", "fm2", "col2", 1, "extralongval5", 0, true)) + if err != nil { + t.Fatalf("Processing chunk: %v", err) + } + if row == nil { + t.Fatalf("Missing row") + } + + want := []ReadItem{ + ri("rs", "fm1", "col1", 0, "val1"), + ri("rs", "fm1", "col1", 1, "val2"), + ri("rs", "fm1", "col2", 0, "val3"), + } + if !testutil.Equal(row["fm1"], want) { + t.Fatalf("Incorrect ReadItem: got: %v\nwant: %v\n", row["fm1"], want) + } + want = []ReadItem{ + ri("rs", "fm2", "col1", 0, "val4"), + ri("rs", "fm2", "col2", 1, "extralongval5"), + } + if !testutil.Equal(row["fm2"], want) { + t.Fatalf("Incorrect ReadItem: got: %v\nwant: %v\n", row["fm2"], want) + } + if err := cr.Close(); err != nil { + t.Fatalf("Close: %v", err) + } +} + +func TestSplitCells(t *testing.T) { + cr := newChunkReader() + + mustProcess(t, cr, cc("rs", "fm1", "col1", 0, "hello ", 11, false)) + mustProcess(t, cr, ccData("world", 0, false)) + row, err := cr.Process(cc("rs", "fm1", "col2", 0, "val2", 0, true)) + if err != nil { + t.Fatalf("Processing chunk: %v", err) + } + if row == nil { + t.Fatalf("Missing row") + } + + want := []ReadItem{ + ri("rs", "fm1", "col1", 0, "hello world"), + ri("rs", "fm1", "col2", 0, "val2"), + } + if !testutil.Equal(row["fm1"], want) { + t.Fatalf("Incorrect ReadItem: got: %v\nwant: %v\n", row["fm1"], want) + } + if err := cr.Close(); err != nil { + t.Fatalf("Close: %v", err) + } +} + +func TestMultipleRows(t *testing.T) { + cr := newChunkReader() + + row, err := cr.Process(cc("rs1", "fm1", "col1", 1, "val1", 0, true)) + if err != nil { + t.Fatalf("Processing chunk: %v", err) + } + want := []ReadItem{ri("rs1", "fm1", "col1", 1, "val1")} + if !testutil.Equal(row["fm1"], want) { + t.Fatalf("Incorrect ReadItem: got: %v\nwant: %v\n", row["fm1"], want) + } + + row, err = cr.Process(cc("rs2", "fm2", "col2", 2, "val2", 0, true)) + if err != nil { + t.Fatalf("Processing chunk: %v", err) + } + want = []ReadItem{ri("rs2", "fm2", "col2", 2, "val2")} + if !testutil.Equal(row["fm2"], want) { + t.Fatalf("Incorrect ReadItem: got: %v\nwant: %v\n", row["fm2"], want) + } + + if err := cr.Close(); err != nil { + t.Fatalf("Close: %v", err) + } +} + +func TestBlankQualifier(t *testing.T) { + cr := newChunkReader() + + row, err := cr.Process(cc("rs1", "fm1", "", 1, "val1", 0, true)) + if err != nil { + t.Fatalf("Processing chunk: %v", err) + } + want := []ReadItem{ri("rs1", "fm1", "", 1, "val1")} + if !testutil.Equal(row["fm1"], want) { + t.Fatalf("Incorrect ReadItem: got: %v\nwant: %v\n", row["fm1"], want) + } + + row, err = cr.Process(cc("rs2", "fm2", "col2", 2, "val2", 0, true)) + if err != nil { + t.Fatalf("Processing chunk: %v", err) + } + want = []ReadItem{ri("rs2", "fm2", "col2", 2, "val2")} + if !testutil.Equal(row["fm2"], want) { + t.Fatalf("Incorrect ReadItem: got: %v\nwant: %v\n", row["fm2"], want) + } + + if err := cr.Close(); err != nil { + t.Fatalf("Close: %v", err) + } +} + +func TestReset(t *testing.T) { + cr := newChunkReader() + mustProcess(t, cr, cc("rs", "fm1", "col1", 0, "val1", 0, false)) + mustProcess(t, cr, cc("rs", "fm1", "col1", 1, "val2", 0, false)) + mustProcess(t, cr, cc("rs", "fm1", "col2", 0, "val3", 0, false)) + mustProcess(t, cr, ccReset()) + row := mustProcess(t, cr, cc("rs1", "fm1", "col1", 1, "val1", 0, true)) + want := []ReadItem{ri("rs1", "fm1", "col1", 1, "val1")} + if !testutil.Equal(row["fm1"], want) { + t.Fatalf("Reset: got: %v\nwant: %v\n", row["fm1"], want) + } + if err := cr.Close(); err != nil { + t.Fatalf("Close: %v", err) + } +} + +func TestNewFamEmptyQualifier(t *testing.T) { + cr := newChunkReader() + + mustProcess(t, cr, cc("rs", "fm1", "col1", 0, "val1", 0, false)) + _, err := cr.Process(cc(nilStr, "fm2", nilStr, 0, "val2", 0, true)) + if err == nil { + t.Fatalf("Expected error on second chunk with no qualifier set") + } +} + +func mustProcess(t *testing.T, cr *chunkReader, cc *btspb.ReadRowsResponse_CellChunk) Row { + row, err := cr.Process(cc) + if err != nil { + t.Fatal(err) + } + return row +} + +// The read rows acceptance test reads a json file specifying a number of tests, +// each consisting of one or more cell chunk text protos and one or more resulting +// cells or errors. +type AcceptanceTest struct { + Tests []TestCase `json:"tests"` +} + +type TestCase struct { + Name string `json:"name"` + Chunks []string `json:"chunks"` + Results []TestResult `json:"results"` +} + +type TestResult struct { + RK string `json:"rk"` + FM string `json:"fm"` + Qual string `json:"qual"` + TS int64 `json:"ts"` + Value string `json:"value"` + Error bool `json:"error"` // If true, expect an error. Ignore any other field. +} + +func TestAcceptance(t *testing.T) { + testJSON, err := ioutil.ReadFile("./testdata/read-rows-acceptance-test.json") + if err != nil { + t.Fatalf("could not open acceptance test file %v", err) + } + + var accTest AcceptanceTest + err = json.Unmarshal(testJSON, &accTest) + if err != nil { + t.Fatalf("could not parse acceptance test file: %v", err) + } + + for _, test := range accTest.Tests { + runTestCase(t, test) + } +} + +func runTestCase(t *testing.T, test TestCase) { + // Increment an index into the result array as we get results + cr := newChunkReader() + var results []TestResult + var seenErr bool + for _, chunkText := range test.Chunks { + // Parse and pass each cell chunk to the ChunkReader + cc := &btspb.ReadRowsResponse_CellChunk{} + err := proto.UnmarshalText(chunkText, cc) + if err != nil { + t.Errorf("[%s] failed to unmarshal text proto: %s\n%s", test.Name, chunkText, err) + return + } + row, err := cr.Process(cc) + if err != nil { + results = append(results, TestResult{Error: true}) + seenErr = true + break + } else { + // Turn the Row into TestResults + for fm, ris := range row { + for _, ri := range ris { + tr := TestResult{ + RK: ri.Row, + FM: fm, + Qual: strings.Split(ri.Column, ":")[1], + TS: int64(ri.Timestamp), + Value: string(ri.Value), + } + results = append(results, tr) + } + } + } + } + + // Only Close if we don't have an error yet, otherwise Close: is expected. + if !seenErr { + err := cr.Close() + if err != nil { + results = append(results, TestResult{Error: true}) + } + } + + got := toSet(results) + want := toSet(test.Results) + if !testutil.Equal(got, want) { + t.Fatalf("[%s]: got: %v\nwant: %v\n", test.Name, got, want) + } +} + +func toSet(res []TestResult) map[TestResult]bool { + set := make(map[TestResult]bool) + for _, tr := range res { + set[tr] = true + } + return set +} + +// ri returns a ReadItem for the given components +func ri(rk string, fm string, qual string, ts int64, val string) ReadItem { + return ReadItem{Row: rk, Column: fmt.Sprintf("%s:%s", fm, qual), Value: []byte(val), Timestamp: Timestamp(ts)} +} + +// cc returns a CellChunk proto +func cc(rk string, fm string, qual string, ts int64, val string, size int32, commit bool) *btspb.ReadRowsResponse_CellChunk { + // The components of the cell key are wrapped and can be null or empty + var rkWrapper []byte + if rk == nilStr { + rkWrapper = nil + } else { + rkWrapper = []byte(rk) + } + + var fmWrapper *wrappers.StringValue + if fm != nilStr { + fmWrapper = &wrappers.StringValue{Value: fm} + } else { + fmWrapper = nil + } + + var qualWrapper *wrappers.BytesValue + if qual != nilStr { + qualWrapper = &wrappers.BytesValue{Value: []byte(qual)} + } else { + qualWrapper = nil + } + + return &btspb.ReadRowsResponse_CellChunk{ + RowKey: rkWrapper, + FamilyName: fmWrapper, + Qualifier: qualWrapper, + TimestampMicros: ts, + Value: []byte(val), + ValueSize: size, + RowStatus: &btspb.ReadRowsResponse_CellChunk_CommitRow{CommitRow: commit}} +} + +// ccData returns a CellChunk with only a value and size +func ccData(val string, size int32, commit bool) *btspb.ReadRowsResponse_CellChunk { + return cc(nilStr, nilStr, nilStr, 0, val, size, commit) +} + +// ccReset returns a CellChunk with RestRow set to true +func ccReset() *btspb.ReadRowsResponse_CellChunk { + return &btspb.ReadRowsResponse_CellChunk{ + RowStatus: &btspb.ReadRowsResponse_CellChunk_ResetRow{ResetRow: true}} +} diff --git a/vendor/cloud.google.com/go/bigtable/retry_test.go b/vendor/cloud.google.com/go/bigtable/retry_test.go new file mode 100644 index 00000000..9ffb6f96 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/retry_test.go @@ -0,0 +1,381 @@ +/* +Copyright 2016 Google LLC + +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 bigtable + +import ( + "context" + "strings" + "testing" + "time" + + "cloud.google.com/go/bigtable/bttest" + "cloud.google.com/go/bigtable/internal/gax" + "cloud.google.com/go/internal/testutil" + "github.com/golang/protobuf/ptypes/wrappers" + "github.com/google/go-cmp/cmp" + "google.golang.org/api/option" + btpb "google.golang.org/genproto/googleapis/bigtable/v2" + rpcpb "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func setupFakeServer(opt ...grpc.ServerOption) (tbl *Table, cleanup func(), err error) { + srv, err := bttest.NewServer("localhost:0", opt...) + if err != nil { + return nil, nil, err + } + conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure(), grpc.WithBlock()) + if err != nil { + return nil, nil, err + } + + client, err := NewClient(context.Background(), "client", "instance", option.WithGRPCConn(conn), option.WithGRPCDialOption(grpc.WithBlock())) + if err != nil { + return nil, nil, err + } + + adminClient, err := NewAdminClient(context.Background(), "client", "instance", option.WithGRPCConn(conn), option.WithGRPCDialOption(grpc.WithBlock())) + if err != nil { + return nil, nil, err + } + if err := adminClient.CreateTable(context.Background(), "table"); err != nil { + return nil, nil, err + } + if err := adminClient.CreateColumnFamily(context.Background(), "table", "cf"); err != nil { + return nil, nil, err + } + t := client.Open("table") + + cleanupFunc := func() { + adminClient.Close() + client.Close() + srv.Close() + } + return t, cleanupFunc, nil +} + +func TestRetryApply(t *testing.T) { + gax.Logger = nil + ctx := context.Background() + + errCount := 0 + code := codes.Unavailable // Will be retried + // Intercept requests and return an error or defer to the underlying handler + errInjector := func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + if strings.HasSuffix(info.FullMethod, "MutateRow") && errCount < 3 { + errCount++ + return nil, status.Errorf(code, "") + } + return handler(ctx, req) + } + tbl, cleanup, err := setupFakeServer(grpc.UnaryInterceptor(errInjector)) + if err != nil { + t.Fatalf("fake server setup: %v", err) + } + defer cleanup() + + mut := NewMutation() + mut.Set("cf", "col", 1000, []byte("val")) + if err := tbl.Apply(ctx, "row1", mut); err != nil { + t.Errorf("applying single mutation with retries: %v", err) + } + row, err := tbl.ReadRow(ctx, "row1") + if err != nil { + t.Errorf("reading single value with retries: %v", err) + } + if row == nil { + t.Errorf("applying single mutation with retries: could not read back row") + } + + code = codes.FailedPrecondition // Won't be retried + errCount = 0 + if err := tbl.Apply(ctx, "row", mut); err == nil { + t.Errorf("applying single mutation with no retries: no error") + } + + // Check and mutate + mutTrue := NewMutation() + mutTrue.DeleteRow() + mutFalse := NewMutation() + mutFalse.Set("cf", "col", 1000, []byte("val")) + condMut := NewCondMutation(ValueFilter(".*"), mutTrue, mutFalse) + + errCount = 0 + code = codes.Unavailable // Will be retried + if err := tbl.Apply(ctx, "row1", condMut); err != nil { + t.Errorf("conditionally mutating row with retries: %v", err) + } + row, err = tbl.ReadRow(ctx, "row1") // row1 already in the table + if err != nil { + t.Errorf("reading single value after conditional mutation: %v", err) + } + if row != nil { + t.Errorf("reading single value after conditional mutation: row not deleted") + } + + errCount = 0 + code = codes.FailedPrecondition // Won't be retried + if err := tbl.Apply(ctx, "row", condMut); err == nil { + t.Errorf("conditionally mutating row with no retries: no error") + } +} + +func TestRetryApplyBulk(t *testing.T) { + ctx := context.Background() + gax.Logger = nil + + // Intercept requests and delegate to an interceptor defined by the test case + errCount := 0 + var f func(grpc.ServerStream) error + errInjector := func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + if strings.HasSuffix(info.FullMethod, "MutateRows") { + return f(ss) + } + return handler(ctx, ss) + } + + tbl, cleanup, err := setupFakeServer(grpc.StreamInterceptor(errInjector)) + defer cleanup() + if err != nil { + t.Fatalf("fake server setup: %v", err) + } + + errCount = 0 + // Test overall request failure and retries + f = func(ss grpc.ServerStream) error { + if errCount < 3 { + errCount++ + return status.Errorf(codes.Aborted, "") + } + return nil + } + mut := NewMutation() + mut.Set("cf", "col", 1, []byte{}) + errors, err := tbl.ApplyBulk(ctx, []string{"row2"}, []*Mutation{mut}) + if errors != nil || err != nil { + t.Errorf("bulk with request failure: got: %v, %v, want: nil", errors, err) + } + + // Test failures and retries in one request + errCount = 0 + m1 := NewMutation() + m1.Set("cf", "col", 1, []byte{}) + m2 := NewMutation() + m2.Set("cf", "col2", 1, []byte{}) + m3 := NewMutation() + m3.Set("cf", "col3", 1, []byte{}) + f = func(ss grpc.ServerStream) error { + var err error + req := new(btpb.MutateRowsRequest) + must(ss.RecvMsg(req)) + switch errCount { + case 0: + // Retryable request failure + err = status.Errorf(codes.Unavailable, "") + case 1: + // Two mutations fail + must(writeMutateRowsResponse(ss, codes.Unavailable, codes.OK, codes.Aborted)) + err = nil + case 2: + // Two failures were retried. One will succeed. + if want, got := 2, len(req.Entries); want != got { + t.Errorf("2 bulk retries, got: %d, want %d", got, want) + } + must(writeMutateRowsResponse(ss, codes.OK, codes.Aborted)) + err = nil + case 3: + // One failure was retried and will succeed. + if want, got := 1, len(req.Entries); want != got { + t.Errorf("1 bulk retry, got: %d, want %d", got, want) + } + must(writeMutateRowsResponse(ss, codes.OK)) + err = nil + } + errCount++ + return err + } + errors, err = tbl.ApplyBulk(ctx, []string{"row1", "row2", "row3"}, []*Mutation{m1, m2, m3}) + if errors != nil || err != nil { + t.Errorf("bulk with retries: got: %v, %v, want: nil", errors, err) + } + + // Test unretryable errors + niMut := NewMutation() + niMut.Set("cf", "col", ServerTime, []byte{}) // Non-idempotent + errCount = 0 + f = func(ss grpc.ServerStream) error { + var err error + req := new(btpb.MutateRowsRequest) + must(ss.RecvMsg(req)) + switch errCount { + case 0: + // Give non-idempotent mutation a retryable error code. + // Nothing should be retried. + must(writeMutateRowsResponse(ss, codes.FailedPrecondition, codes.Aborted)) + err = nil + case 1: + t.Errorf("unretryable errors: got one retry, want no retries") + } + errCount++ + return err + } + errors, err = tbl.ApplyBulk(ctx, []string{"row1", "row2"}, []*Mutation{m1, niMut}) + if err != nil { + t.Errorf("unretryable errors: request failed %v", err) + } + want := []error{ + status.Errorf(codes.FailedPrecondition, ""), + status.Errorf(codes.Aborted, ""), + } + if !testutil.Equal(want, errors) { + t.Errorf("unretryable errors: got: %v, want: %v", errors, want) + } + + // Test individual errors and a deadline exceeded + f = func(ss grpc.ServerStream) error { + return writeMutateRowsResponse(ss, codes.FailedPrecondition, codes.OK, codes.Aborted) + } + ctx, _ = context.WithTimeout(ctx, 100*time.Millisecond) + errors, err = tbl.ApplyBulk(ctx, []string{"row1", "row2", "row3"}, []*Mutation{m1, m2, m3}) + wantErr := context.DeadlineExceeded + if wantErr != err { + t.Errorf("deadline exceeded error: got: %v, want: %v", err, wantErr) + } + if errors != nil { + t.Errorf("deadline exceeded errors: got: %v, want: nil", err) + } +} + +func writeMutateRowsResponse(ss grpc.ServerStream, codes ...codes.Code) error { + res := &btpb.MutateRowsResponse{Entries: make([]*btpb.MutateRowsResponse_Entry, len(codes))} + for i, code := range codes { + res.Entries[i] = &btpb.MutateRowsResponse_Entry{ + Index: int64(i), + Status: &rpcpb.Status{Code: int32(code), Message: ""}, + } + } + return ss.SendMsg(res) +} + +func TestRetainRowsAfter(t *testing.T) { + prevRowRange := NewRange("a", "z") + prevRowKey := "m" + want := NewRange("m\x00", "z") + got := prevRowRange.retainRowsAfter(prevRowKey) + if !testutil.Equal(want, got, cmp.AllowUnexported(RowRange{})) { + t.Errorf("range retry: got %v, want %v", got, want) + } + + prevRowRangeList := RowRangeList{NewRange("a", "d"), NewRange("e", "g"), NewRange("h", "l")} + prevRowKey = "f" + wantRowRangeList := RowRangeList{NewRange("f\x00", "g"), NewRange("h", "l")} + got = prevRowRangeList.retainRowsAfter(prevRowKey) + if !testutil.Equal(wantRowRangeList, got, cmp.AllowUnexported(RowRange{})) { + t.Errorf("range list retry: got %v, want %v", got, wantRowRangeList) + } + + prevRowList := RowList{"a", "b", "c", "d", "e", "f"} + prevRowKey = "b" + wantList := RowList{"c", "d", "e", "f"} + got = prevRowList.retainRowsAfter(prevRowKey) + if !testutil.Equal(wantList, got) { + t.Errorf("list retry: got %v, want %v", got, wantList) + } +} + +func TestRetryReadRows(t *testing.T) { + ctx := context.Background() + gax.Logger = nil + + // Intercept requests and delegate to an interceptor defined by the test case + errCount := 0 + var f func(grpc.ServerStream) error + errInjector := func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + if strings.HasSuffix(info.FullMethod, "ReadRows") { + return f(ss) + } + return handler(ctx, ss) + } + + tbl, cleanup, err := setupFakeServer(grpc.StreamInterceptor(errInjector)) + defer cleanup() + if err != nil { + t.Fatalf("fake server setup: %v", err) + } + + errCount = 0 + // Test overall request failure and retries + f = func(ss grpc.ServerStream) error { + var err error + req := new(btpb.ReadRowsRequest) + must(ss.RecvMsg(req)) + switch errCount { + case 0: + // Retryable request failure + err = status.Errorf(codes.Unavailable, "") + case 1: + // Write two rows then error + if want, got := "a", string(req.Rows.RowRanges[0].GetStartKeyClosed()); want != got { + t.Errorf("first retry, no data received yet: got %q, want %q", got, want) + } + must(writeReadRowsResponse(ss, "a", "b")) + err = status.Errorf(codes.Unavailable, "") + case 2: + // Retryable request failure + if want, got := "b\x00", string(req.Rows.RowRanges[0].GetStartKeyClosed()); want != got { + t.Errorf("2 range retries: got %q, want %q", got, want) + } + err = status.Errorf(codes.Unavailable, "") + case 3: + // Write two more rows + must(writeReadRowsResponse(ss, "c", "d")) + err = nil + } + errCount++ + return err + } + + var got []string + must(tbl.ReadRows(ctx, NewRange("a", "z"), func(r Row) bool { + got = append(got, r.Key()) + return true + })) + want := []string{"a", "b", "c", "d"} + if !testutil.Equal(got, want) { + t.Errorf("retry range integration: got %v, want %v", got, want) + } +} + +func writeReadRowsResponse(ss grpc.ServerStream, rowKeys ...string) error { + var chunks []*btpb.ReadRowsResponse_CellChunk + for _, key := range rowKeys { + chunks = append(chunks, &btpb.ReadRowsResponse_CellChunk{ + RowKey: []byte(key), + FamilyName: &wrappers.StringValue{Value: "fm"}, + Qualifier: &wrappers.BytesValue{Value: []byte("col")}, + RowStatus: &btpb.ReadRowsResponse_CellChunk_CommitRow{CommitRow: true}, + }) + } + return ss.SendMsg(&btpb.ReadRowsResponse{Chunks: chunks}) +} + +func must(err error) { + if err != nil { + panic(err) + } +} diff --git a/vendor/cloud.google.com/go/bigtable/testdata/read-rows-acceptance-test.json b/vendor/cloud.google.com/go/bigtable/testdata/read-rows-acceptance-test.json new file mode 100644 index 00000000..4973831f --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/testdata/read-rows-acceptance-test.json @@ -0,0 +1,1178 @@ +{ + "tests": [ + { + "name": "invalid - no commit", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: false\n" + ], + "results": [ + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "invalid - no cell key before commit", + "chunks": [ + "commit_row: true\n" + ], + "results": [ + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "invalid - no cell key before value", + "chunks": [ + "timestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: false\n" + ], + "results": [ + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "invalid - new col family must specify qualifier", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 101\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "family_name: \u003c\n value: \"B\"\n\u003e\ntimestamp_micros: 102\nvalue: \"value-VAL_2\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "bare commit implies ts=0", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: false\n", + "commit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "", + "error": false + }, + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 0, + "value": "", + "label": "", + "error": false + } + ] + }, + { + "name": "simple row with timestamp", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "", + "error": false + } + ] + }, + { + "name": "missing timestamp, implied ts=0", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\nvalue: \"value-VAL\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 0, + "value": "value-VAL", + "label": "", + "error": false + } + ] + }, + { + "name": "empty cell value", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 0, + "value": "", + "label": "", + "error": false + } + ] + }, + { + "name": "two unsplit cells", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 101\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "timestamp_micros: 102\nvalue: \"value-VAL_2\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 101, + "value": "value-VAL_1", + "label": "", + "error": false + }, + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 102, + "value": "value-VAL_2", + "label": "", + "error": false + } + ] + }, + { + "name": "two qualifiers", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 101\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "qualifier: \u003c\n value: \"D\"\n\u003e\ntimestamp_micros: 102\nvalue: \"value-VAL_2\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 101, + "value": "value-VAL_1", + "label": "", + "error": false + }, + { + "rk": "RK", + "fm": "A", + "qual": "D", + "ts": 102, + "value": "value-VAL_2", + "label": "", + "error": false + } + ] + }, + { + "name": "two families", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 101\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "family_name: \u003c\n value: \"B\"\n\u003e\nqualifier: \u003c\n value: \"E\"\n\u003e\ntimestamp_micros: 102\nvalue: \"value-VAL_2\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 101, + "value": "value-VAL_1", + "label": "", + "error": false + }, + { + "rk": "RK", + "fm": "B", + "qual": "E", + "ts": 102, + "value": "value-VAL_2", + "label": "", + "error": false + } + ] + }, + { + "name": "with labels", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 101\nlabels: \"L_1\"\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "timestamp_micros: 102\nlabels: \"L_2\"\nvalue: \"value-VAL_2\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 101, + "value": "value-VAL_1", + "label": "L_1", + "error": false + }, + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 102, + "value": "value-VAL_2", + "label": "L_2", + "error": false + } + ] + }, + { + "name": "split cell, bare commit", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"alue-VAL\"\ncommit_row: false\n", + "commit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "", + "error": false + }, + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 0, + "value": "", + "label": "", + "error": false + } + ] + }, + { + "name": "split cell", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"alue-VAL\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "", + "error": false + } + ] + }, + { + "name": "split four ways", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nlabels: \"L\"\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"a\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"l\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"ue-VAL\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "L", + "error": false + } + ] + }, + { + "name": "two split cells", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 101\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"alue-VAL_1\"\ncommit_row: false\n", + "timestamp_micros: 102\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"alue-VAL_2\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 101, + "value": "value-VAL_1", + "label": "", + "error": false + }, + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 102, + "value": "value-VAL_2", + "label": "", + "error": false + } + ] + }, + { + "name": "multi-qualifier splits", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 101\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"alue-VAL_1\"\ncommit_row: false\n", + "qualifier: \u003c\n value: \"D\"\n\u003e\ntimestamp_micros: 102\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"alue-VAL_2\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 101, + "value": "value-VAL_1", + "label": "", + "error": false + }, + { + "rk": "RK", + "fm": "A", + "qual": "D", + "ts": 102, + "value": "value-VAL_2", + "label": "", + "error": false + } + ] + }, + { + "name": "multi-qualifier multi-split", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 101\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"a\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"lue-VAL_1\"\ncommit_row: false\n", + "qualifier: \u003c\n value: \"D\"\n\u003e\ntimestamp_micros: 102\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"a\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"lue-VAL_2\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 101, + "value": "value-VAL_1", + "label": "", + "error": false + }, + { + "rk": "RK", + "fm": "A", + "qual": "D", + "ts": 102, + "value": "value-VAL_2", + "label": "", + "error": false + } + ] + }, + { + "name": "multi-family split", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 101\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"alue-VAL_1\"\ncommit_row: false\n", + "family_name: \u003c\n value: \"B\"\n\u003e\nqualifier: \u003c\n value: \"E\"\n\u003e\ntimestamp_micros: 102\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"alue-VAL_2\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 101, + "value": "value-VAL_1", + "label": "", + "error": false + }, + { + "rk": "RK", + "fm": "B", + "qual": "E", + "ts": 102, + "value": "value-VAL_2", + "label": "", + "error": false + } + ] + }, + { + "name": "invalid - no commit between rows", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: false\n", + "row_key: \"RK_2\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: false\n" + ], + "results": [ + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "invalid - no commit after first row", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: false\n", + "row_key: \"RK_2\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "invalid - last row missing commit", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: true\n", + "row_key: \"RK_2\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: false\n" + ], + "results": [ + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "", + "error": false + }, + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "invalid - duplicate row key", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: true\n", + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"B\"\n\u003e\nqualifier: \u003c\n value: \"D\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "", + "error": false + }, + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "invalid - new row missing row key", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: true\n", + "timestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "", + "error": false + }, + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "two rows", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: true\n", + "row_key: \"RK_2\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "", + "error": false + }, + { + "rk": "RK_2", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "", + "error": false + } + ] + }, + { + "name": "two rows implicit timestamp", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\nvalue: \"value-VAL\"\ncommit_row: true\n", + "row_key: \"RK_2\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 0, + "value": "value-VAL", + "label": "", + "error": false + }, + { + "rk": "RK_2", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "", + "error": false + } + ] + }, + { + "name": "two rows empty value", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ncommit_row: true\n", + "row_key: \"RK_2\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 0, + "value": "", + "label": "", + "error": false + }, + { + "rk": "RK_2", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "", + "error": false + } + ] + }, + { + "name": "two rows, one with multiple cells", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 101\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "timestamp_micros: 102\nvalue: \"value-VAL_2\"\ncommit_row: true\n", + "row_key: \"RK_2\"\nfamily_name: \u003c\n value: \"B\"\n\u003e\nqualifier: \u003c\n value: \"D\"\n\u003e\ntimestamp_micros: 103\nvalue: \"value-VAL_3\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 101, + "value": "value-VAL_1", + "label": "", + "error": false + }, + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 102, + "value": "value-VAL_2", + "label": "", + "error": false + }, + { + "rk": "RK_2", + "fm": "B", + "qual": "D", + "ts": 103, + "value": "value-VAL_3", + "label": "", + "error": false + } + ] + }, + { + "name": "two rows, multiple cells", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 101\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "qualifier: \u003c\n value: \"D\"\n\u003e\ntimestamp_micros: 102\nvalue: \"value-VAL_2\"\ncommit_row: true\n", + "row_key: \"RK_2\"\nfamily_name: \u003c\n value: \"B\"\n\u003e\nqualifier: \u003c\n value: \"E\"\n\u003e\ntimestamp_micros: 103\nvalue: \"value-VAL_3\"\ncommit_row: false\n", + "qualifier: \u003c\n value: \"F\"\n\u003e\ntimestamp_micros: 104\nvalue: \"value-VAL_4\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 101, + "value": "value-VAL_1", + "label": "", + "error": false + }, + { + "rk": "RK_1", + "fm": "A", + "qual": "D", + "ts": 102, + "value": "value-VAL_2", + "label": "", + "error": false + }, + { + "rk": "RK_2", + "fm": "B", + "qual": "E", + "ts": 103, + "value": "value-VAL_3", + "label": "", + "error": false + }, + { + "rk": "RK_2", + "fm": "B", + "qual": "F", + "ts": 104, + "value": "value-VAL_4", + "label": "", + "error": false + } + ] + }, + { + "name": "two rows, multiple cells, multiple families", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 101\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "family_name: \u003c\n value: \"B\"\n\u003e\nqualifier: \u003c\n value: \"E\"\n\u003e\ntimestamp_micros: 102\nvalue: \"value-VAL_2\"\ncommit_row: true\n", + "row_key: \"RK_2\"\nfamily_name: \u003c\n value: \"M\"\n\u003e\nqualifier: \u003c\n value: \"O\"\n\u003e\ntimestamp_micros: 103\nvalue: \"value-VAL_3\"\ncommit_row: false\n", + "family_name: \u003c\n value: \"N\"\n\u003e\nqualifier: \u003c\n value: \"P\"\n\u003e\ntimestamp_micros: 104\nvalue: \"value-VAL_4\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 101, + "value": "value-VAL_1", + "label": "", + "error": false + }, + { + "rk": "RK_1", + "fm": "B", + "qual": "E", + "ts": 102, + "value": "value-VAL_2", + "label": "", + "error": false + }, + { + "rk": "RK_2", + "fm": "M", + "qual": "O", + "ts": 103, + "value": "value-VAL_3", + "label": "", + "error": false + }, + { + "rk": "RK_2", + "fm": "N", + "qual": "P", + "ts": 104, + "value": "value-VAL_4", + "label": "", + "error": false + } + ] + }, + { + "name": "two rows, four cells, 2 labels", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 101\nlabels: \"L_1\"\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "timestamp_micros: 102\nvalue: \"value-VAL_2\"\ncommit_row: true\n", + "row_key: \"RK_2\"\nfamily_name: \u003c\n value: \"B\"\n\u003e\nqualifier: \u003c\n value: \"D\"\n\u003e\ntimestamp_micros: 103\nlabels: \"L_3\"\nvalue: \"value-VAL_3\"\ncommit_row: false\n", + "timestamp_micros: 104\nvalue: \"value-VAL_4\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 101, + "value": "value-VAL_1", + "label": "L_1", + "error": false + }, + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 102, + "value": "value-VAL_2", + "label": "", + "error": false + }, + { + "rk": "RK_2", + "fm": "B", + "qual": "D", + "ts": 103, + "value": "value-VAL_3", + "label": "L_3", + "error": false + }, + { + "rk": "RK_2", + "fm": "B", + "qual": "D", + "ts": 104, + "value": "value-VAL_4", + "label": "", + "error": false + } + ] + }, + { + "name": "two rows with splits, same timestamp", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"alue-VAL_1\"\ncommit_row: true\n", + "row_key: \"RK_2\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"alue-VAL_2\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL_1", + "label": "", + "error": false + }, + { + "rk": "RK_2", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL_2", + "label": "", + "error": false + } + ] + }, + { + "name": "invalid - bare reset", + "chunks": [ + "reset_row: true\n" + ], + "results": [ + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "invalid - bad reset, no commit", + "chunks": [ + "reset_row: true\n", + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: false\n" + ], + "results": [ + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "invalid - missing key after reset", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: false\n", + "reset_row: true\n", + "timestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "no data after reset", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: false\n", + "reset_row: true\n" + ], + "results": null + }, + { + "name": "simple reset", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: false\n", + "reset_row: true\n", + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "", + "error": false + } + ] + }, + { + "name": "reset to new val", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "reset_row: true\n", + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_2\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL_2", + "label": "", + "error": false + } + ] + }, + { + "name": "reset to new qual", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "reset_row: true\n", + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"D\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_1\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "D", + "ts": 100, + "value": "value-VAL_1", + "label": "", + "error": false + } + ] + }, + { + "name": "reset with splits", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "timestamp_micros: 102\nvalue: \"value-VAL_2\"\ncommit_row: false\n", + "reset_row: true\n", + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_2\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL_2", + "label": "", + "error": false + } + ] + }, + { + "name": "reset two cells", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "reset_row: true\n", + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_2\"\ncommit_row: false\n", + "timestamp_micros: 103\nvalue: \"value-VAL_3\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL_2", + "label": "", + "error": false + }, + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 103, + "value": "value-VAL_3", + "label": "", + "error": false + } + ] + }, + { + "name": "two resets", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "reset_row: true\n", + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_2\"\ncommit_row: false\n", + "reset_row: true\n", + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_3\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL_3", + "label": "", + "error": false + } + ] + }, + { + "name": "reset then two cells", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "reset_row: true\n", + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"B\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_2\"\ncommit_row: false\n", + "qualifier: \u003c\n value: \"D\"\n\u003e\ntimestamp_micros: 103\nvalue: \"value-VAL_3\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "B", + "qual": "C", + "ts": 100, + "value": "value-VAL_2", + "label": "", + "error": false + }, + { + "rk": "RK", + "fm": "B", + "qual": "D", + "ts": 103, + "value": "value-VAL_3", + "label": "", + "error": false + } + ] + }, + { + "name": "reset to new row", + "chunks": [ + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_1\"\ncommit_row: false\n", + "reset_row: true\n", + "row_key: \"RK_2\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_2\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK_2", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL_2", + "label": "", + "error": false + } + ] + }, + { + "name": "reset in between chunks", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nlabels: \"L\"\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"a\"\nvalue_size: 10\ncommit_row: false\n", + "reset_row: true\n", + "row_key: \"RK_1\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL_1\"\ncommit_row: true\n" + ], + "results": [ + { + "rk": "RK_1", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL_1", + "label": "", + "error": false + } + ] + }, + { + "name": "invalid - reset with chunk", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nlabels: \"L\"\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"a\"\nvalue_size: 10\nreset_row: true\n" + ], + "results": [ + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "invalid - commit with chunk", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nlabels: \"L\"\nvalue: \"v\"\nvalue_size: 10\ncommit_row: false\n", + "value: \"a\"\nvalue_size: 10\ncommit_row: true\n" + ], + "results": [ + { + "rk": "", + "fm": "", + "qual": "", + "ts": 0, + "value": "", + "label": "", + "error": true + } + ] + }, + { + "name": "empty cell chunk", + "chunks": [ + "row_key: \"RK\"\nfamily_name: \u003c\n value: \"A\"\n\u003e\nqualifier: \u003c\n value: \"C\"\n\u003e\ntimestamp_micros: 100\nvalue: \"value-VAL\"\ncommit_row: false\n", + "commit_row: false\n", + "commit_row: true\n" + ], + "results": [ + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 100, + "value": "value-VAL", + "label": "", + "error": false + }, + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 0, + "value": "", + "label": "", + "error": false + }, + { + "rk": "RK", + "fm": "A", + "qual": "C", + "ts": 0, + "value": "", + "label": "", + "error": false + } + ] + } + ] +} \ No newline at end of file diff --git a/vendor/cloud.google.com/go/bigtable/trace.go b/vendor/cloud.google.com/go/bigtable/trace.go new file mode 100644 index 00000000..6c579b18 --- /dev/null +++ b/vendor/cloud.google.com/go/bigtable/trace.go @@ -0,0 +1,57 @@ +// Copyright 2018 Google LLC +// +// 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 bigtable + +import ( + "context" + "fmt" + + "go.opencensus.io/trace" +) + +func traceStartSpan(ctx context.Context, name string) context.Context { + ctx, _ = trace.StartSpan(ctx, name) + return ctx +} + +func traceEndSpan(ctx context.Context, err error) { + span := trace.FromContext(ctx) + if err != nil { + span.SetStatus(trace.Status{Message: err.Error()}) + } + + span.End() +} + +func tracePrintf(ctx context.Context, attrMap map[string]interface{}, format string, args ...interface{}) { + var attrs []trace.Attribute + for k, v := range attrMap { + var a trace.Attribute + switch v := v.(type) { + case string: + a = trace.StringAttribute(k, v) + case bool: + a = trace.BoolAttribute(k, v) + case int: + a = trace.Int64Attribute(k, int64(v)) + case int64: + a = trace.Int64Attribute(k, v) + default: + a = trace.StringAttribute(k, fmt.Sprintf("%#v", v)) + } + attrs = append(attrs, a) + } + trace.FromContext(ctx).Annotatef(attrs, format, args...) +} diff --git a/vendor/cloud.google.com/go/civil/civil.go b/vendor/cloud.google.com/go/civil/civil.go new file mode 100644 index 00000000..29272ef2 --- /dev/null +++ b/vendor/cloud.google.com/go/civil/civil.go @@ -0,0 +1,277 @@ +// Copyright 2016 Google LLC +// +// 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 civil implements types for civil time, a time-zone-independent +// representation of time that follows the rules of the proleptic +// Gregorian calendar with exactly 24-hour days, 60-minute hours, and 60-second +// minutes. +// +// Because they lack location information, these types do not represent unique +// moments or intervals of time. Use time.Time for that purpose. +package civil + +import ( + "fmt" + "time" +) + +// A Date represents a date (year, month, day). +// +// This type does not include location information, and therefore does not +// describe a unique 24-hour timespan. +type Date struct { + Year int // Year (e.g., 2014). + Month time.Month // Month of the year (January = 1, ...). + Day int // Day of the month, starting at 1. +} + +// DateOf returns the Date in which a time occurs in that time's location. +func DateOf(t time.Time) Date { + var d Date + d.Year, d.Month, d.Day = t.Date() + return d +} + +// ParseDate parses a string in RFC3339 full-date format and returns the date value it represents. +func ParseDate(s string) (Date, error) { + t, err := time.Parse("2006-01-02", s) + if err != nil { + return Date{}, err + } + return DateOf(t), nil +} + +// String returns the date in RFC3339 full-date format. +func (d Date) String() string { + return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day) +} + +// IsValid reports whether the date is valid. +func (d Date) IsValid() bool { + return DateOf(d.In(time.UTC)) == d +} + +// In returns the time corresponding to time 00:00:00 of the date in the location. +// +// In is always consistent with time.Date, even when time.Date returns a time +// on a different day. For example, if loc is America/Indiana/Vincennes, then both +// time.Date(1955, time.May, 1, 0, 0, 0, 0, loc) +// and +// civil.Date{Year: 1955, Month: time.May, Day: 1}.In(loc) +// return 23:00:00 on April 30, 1955. +// +// In panics if loc is nil. +func (d Date) In(loc *time.Location) time.Time { + return time.Date(d.Year, d.Month, d.Day, 0, 0, 0, 0, loc) +} + +// AddDays returns the date that is n days in the future. +// n can also be negative to go into the past. +func (d Date) AddDays(n int) Date { + return DateOf(d.In(time.UTC).AddDate(0, 0, n)) +} + +// DaysSince returns the signed number of days between the date and s, not including the end day. +// This is the inverse operation to AddDays. +func (d Date) DaysSince(s Date) (days int) { + // We convert to Unix time so we do not have to worry about leap seconds: + // Unix time increases by exactly 86400 seconds per day. + deltaUnix := d.In(time.UTC).Unix() - s.In(time.UTC).Unix() + return int(deltaUnix / 86400) +} + +// Before reports whether d1 occurs before d2. +func (d1 Date) Before(d2 Date) bool { + if d1.Year != d2.Year { + return d1.Year < d2.Year + } + if d1.Month != d2.Month { + return d1.Month < d2.Month + } + return d1.Day < d2.Day +} + +// After reports whether d1 occurs after d2. +func (d1 Date) After(d2 Date) bool { + return d2.Before(d1) +} + +// MarshalText implements the encoding.TextMarshaler interface. +// The output is the result of d.String(). +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The date is expected to be a string in a format accepted by ParseDate. +func (d *Date) UnmarshalText(data []byte) error { + var err error + *d, err = ParseDate(string(data)) + return err +} + +// A Time represents a time with nanosecond precision. +// +// This type does not include location information, and therefore does not +// describe a unique moment in time. +// +// This type exists to represent the TIME type in storage-based APIs like BigQuery. +// Most operations on Times are unlikely to be meaningful. Prefer the DateTime type. +type Time struct { + Hour int // The hour of the day in 24-hour format; range [0-23] + Minute int // The minute of the hour; range [0-59] + Second int // The second of the minute; range [0-59] + Nanosecond int // The nanosecond of the second; range [0-999999999] +} + +// TimeOf returns the Time representing the time of day in which a time occurs +// in that time's location. It ignores the date. +func TimeOf(t time.Time) Time { + var tm Time + tm.Hour, tm.Minute, tm.Second = t.Clock() + tm.Nanosecond = t.Nanosecond() + return tm +} + +// ParseTime parses a string and returns the time value it represents. +// ParseTime accepts an extended form of the RFC3339 partial-time format. After +// the HH:MM:SS part of the string, an optional fractional part may appear, +// consisting of a decimal point followed by one to nine decimal digits. +// (RFC3339 admits only one digit after the decimal point). +func ParseTime(s string) (Time, error) { + t, err := time.Parse("15:04:05.999999999", s) + if err != nil { + return Time{}, err + } + return TimeOf(t), nil +} + +// String returns the date in the format described in ParseTime. If Nanoseconds +// is zero, no fractional part will be generated. Otherwise, the result will +// end with a fractional part consisting of a decimal point and nine digits. +func (t Time) String() string { + s := fmt.Sprintf("%02d:%02d:%02d", t.Hour, t.Minute, t.Second) + if t.Nanosecond == 0 { + return s + } + return s + fmt.Sprintf(".%09d", t.Nanosecond) +} + +// IsValid reports whether the time is valid. +func (t Time) IsValid() bool { + // Construct a non-zero time. + tm := time.Date(2, 2, 2, t.Hour, t.Minute, t.Second, t.Nanosecond, time.UTC) + return TimeOf(tm) == t +} + +// MarshalText implements the encoding.TextMarshaler interface. +// The output is the result of t.String(). +func (t Time) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The time is expected to be a string in a format accepted by ParseTime. +func (t *Time) UnmarshalText(data []byte) error { + var err error + *t, err = ParseTime(string(data)) + return err +} + +// A DateTime represents a date and time. +// +// This type does not include location information, and therefore does not +// describe a unique moment in time. +type DateTime struct { + Date Date + Time Time +} + +// Note: We deliberately do not embed Date into DateTime, to avoid promoting AddDays and Sub. + +// DateTimeOf returns the DateTime in which a time occurs in that time's location. +func DateTimeOf(t time.Time) DateTime { + return DateTime{ + Date: DateOf(t), + Time: TimeOf(t), + } +} + +// ParseDateTime parses a string and returns the DateTime it represents. +// ParseDateTime accepts a variant of the RFC3339 date-time format that omits +// the time offset but includes an optional fractional time, as described in +// ParseTime. Informally, the accepted format is +// YYYY-MM-DDTHH:MM:SS[.FFFFFFFFF] +// where the 'T' may be a lower-case 't'. +func ParseDateTime(s string) (DateTime, error) { + t, err := time.Parse("2006-01-02T15:04:05.999999999", s) + if err != nil { + t, err = time.Parse("2006-01-02t15:04:05.999999999", s) + if err != nil { + return DateTime{}, err + } + } + return DateTimeOf(t), nil +} + +// String returns the date in the format described in ParseDate. +func (dt DateTime) String() string { + return dt.Date.String() + "T" + dt.Time.String() +} + +// IsValid reports whether the datetime is valid. +func (dt DateTime) IsValid() bool { + return dt.Date.IsValid() && dt.Time.IsValid() +} + +// In returns the time corresponding to the DateTime in the given location. +// +// If the time is missing or ambigous at the location, In returns the same +// result as time.Date. For example, if loc is America/Indiana/Vincennes, then +// both +// time.Date(1955, time.May, 1, 0, 30, 0, 0, loc) +// and +// civil.DateTime{ +// civil.Date{Year: 1955, Month: time.May, Day: 1}}, +// civil.Time{Minute: 30}}.In(loc) +// return 23:30:00 on April 30, 1955. +// +// In panics if loc is nil. +func (dt DateTime) In(loc *time.Location) time.Time { + return time.Date(dt.Date.Year, dt.Date.Month, dt.Date.Day, dt.Time.Hour, dt.Time.Minute, dt.Time.Second, dt.Time.Nanosecond, loc) +} + +// Before reports whether dt1 occurs before dt2. +func (dt1 DateTime) Before(dt2 DateTime) bool { + return dt1.In(time.UTC).Before(dt2.In(time.UTC)) +} + +// After reports whether dt1 occurs after dt2. +func (dt1 DateTime) After(dt2 DateTime) bool { + return dt2.Before(dt1) +} + +// MarshalText implements the encoding.TextMarshaler interface. +// The output is the result of dt.String(). +func (dt DateTime) MarshalText() ([]byte, error) { + return []byte(dt.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The datetime is expected to be a string in a format accepted by ParseDateTime +func (dt *DateTime) UnmarshalText(data []byte) error { + var err error + *dt, err = ParseDateTime(string(data)) + return err +} diff --git a/vendor/cloud.google.com/go/civil/civil_test.go b/vendor/cloud.google.com/go/civil/civil_test.go new file mode 100644 index 00000000..0720092e --- /dev/null +++ b/vendor/cloud.google.com/go/civil/civil_test.go @@ -0,0 +1,442 @@ +// Copyright 2016 Google LLC +// +// 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 civil + +import ( + "encoding/json" + "testing" + "time" + + "github.com/google/go-cmp/cmp" +) + +func TestDates(t *testing.T) { + for _, test := range []struct { + date Date + loc *time.Location + wantStr string + wantTime time.Time + }{ + { + date: Date{2014, 7, 29}, + loc: time.Local, + wantStr: "2014-07-29", + wantTime: time.Date(2014, time.July, 29, 0, 0, 0, 0, time.Local), + }, + { + date: DateOf(time.Date(2014, 8, 20, 15, 8, 43, 1, time.Local)), + loc: time.UTC, + wantStr: "2014-08-20", + wantTime: time.Date(2014, 8, 20, 0, 0, 0, 0, time.UTC), + }, + { + date: DateOf(time.Date(999, time.January, 26, 0, 0, 0, 0, time.Local)), + loc: time.UTC, + wantStr: "0999-01-26", + wantTime: time.Date(999, 1, 26, 0, 0, 0, 0, time.UTC), + }, + } { + if got := test.date.String(); got != test.wantStr { + t.Errorf("%#v.String() = %q, want %q", test.date, got, test.wantStr) + } + if got := test.date.In(test.loc); !got.Equal(test.wantTime) { + t.Errorf("%#v.In(%v) = %v, want %v", test.date, test.loc, got, test.wantTime) + } + } +} + +func TestDateIsValid(t *testing.T) { + for _, test := range []struct { + date Date + want bool + }{ + {Date{2014, 7, 29}, true}, + {Date{2000, 2, 29}, true}, + {Date{10000, 12, 31}, true}, + {Date{1, 1, 1}, true}, + {Date{0, 1, 1}, true}, // year zero is OK + {Date{-1, 1, 1}, true}, // negative year is OK + {Date{1, 0, 1}, false}, + {Date{1, 1, 0}, false}, + {Date{2016, 1, 32}, false}, + {Date{2016, 13, 1}, false}, + {Date{1, -1, 1}, false}, + {Date{1, 1, -1}, false}, + } { + got := test.date.IsValid() + if got != test.want { + t.Errorf("%#v: got %t, want %t", test.date, got, test.want) + } + } +} + +func TestParseDate(t *testing.T) { + for _, test := range []struct { + str string + want Date // if empty, expect an error + }{ + {"2016-01-02", Date{2016, 1, 2}}, + {"2016-12-31", Date{2016, 12, 31}}, + {"0003-02-04", Date{3, 2, 4}}, + {"999-01-26", Date{}}, + {"", Date{}}, + {"2016-01-02x", Date{}}, + } { + got, err := ParseDate(test.str) + if got != test.want { + t.Errorf("ParseDate(%q) = %+v, want %+v", test.str, got, test.want) + } + if err != nil && test.want != (Date{}) { + t.Errorf("Unexpected error %v from ParseDate(%q)", err, test.str) + } + } +} + +func TestDateArithmetic(t *testing.T) { + for _, test := range []struct { + desc string + start Date + end Date + days int + }{ + { + desc: "zero days noop", + start: Date{2014, 5, 9}, + end: Date{2014, 5, 9}, + days: 0, + }, + { + desc: "crossing a year boundary", + start: Date{2014, 12, 31}, + end: Date{2015, 1, 1}, + days: 1, + }, + { + desc: "negative number of days", + start: Date{2015, 1, 1}, + end: Date{2014, 12, 31}, + days: -1, + }, + { + desc: "full leap year", + start: Date{2004, 1, 1}, + end: Date{2005, 1, 1}, + days: 366, + }, + { + desc: "full non-leap year", + start: Date{2001, 1, 1}, + end: Date{2002, 1, 1}, + days: 365, + }, + { + desc: "crossing a leap second", + start: Date{1972, 6, 30}, + end: Date{1972, 7, 1}, + days: 1, + }, + { + desc: "dates before the unix epoch", + start: Date{101, 1, 1}, + end: Date{102, 1, 1}, + days: 365, + }, + } { + if got := test.start.AddDays(test.days); got != test.end { + t.Errorf("[%s] %#v.AddDays(%v) = %#v, want %#v", test.desc, test.start, test.days, got, test.end) + } + if got := test.end.DaysSince(test.start); got != test.days { + t.Errorf("[%s] %#v.Sub(%#v) = %v, want %v", test.desc, test.end, test.start, got, test.days) + } + } +} + +func TestDateBefore(t *testing.T) { + for _, test := range []struct { + d1, d2 Date + want bool + }{ + {Date{2016, 12, 31}, Date{2017, 1, 1}, true}, + {Date{2016, 1, 1}, Date{2016, 1, 1}, false}, + {Date{2016, 12, 30}, Date{2016, 12, 31}, true}, + } { + if got := test.d1.Before(test.d2); got != test.want { + t.Errorf("%v.Before(%v): got %t, want %t", test.d1, test.d2, got, test.want) + } + } +} + +func TestDateAfter(t *testing.T) { + for _, test := range []struct { + d1, d2 Date + want bool + }{ + {Date{2016, 12, 31}, Date{2017, 1, 1}, false}, + {Date{2016, 1, 1}, Date{2016, 1, 1}, false}, + {Date{2016, 12, 30}, Date{2016, 12, 31}, false}, + } { + if got := test.d1.After(test.d2); got != test.want { + t.Errorf("%v.After(%v): got %t, want %t", test.d1, test.d2, got, test.want) + } + } +} + +func TestTimeToString(t *testing.T) { + for _, test := range []struct { + str string + time Time + roundTrip bool // ParseTime(str).String() == str? + }{ + {"13:26:33", Time{13, 26, 33, 0}, true}, + {"01:02:03.000023456", Time{1, 2, 3, 23456}, true}, + {"00:00:00.000000001", Time{0, 0, 0, 1}, true}, + {"13:26:03.1", Time{13, 26, 3, 100000000}, false}, + {"13:26:33.0000003", Time{13, 26, 33, 300}, false}, + } { + gotTime, err := ParseTime(test.str) + if err != nil { + t.Errorf("ParseTime(%q): got error: %v", test.str, err) + continue + } + if gotTime != test.time { + t.Errorf("ParseTime(%q) = %+v, want %+v", test.str, gotTime, test.time) + } + if test.roundTrip { + gotStr := test.time.String() + if gotStr != test.str { + t.Errorf("%#v.String() = %q, want %q", test.time, gotStr, test.str) + } + } + } +} + +func TestTimeOf(t *testing.T) { + for _, test := range []struct { + time time.Time + want Time + }{ + {time.Date(2014, 8, 20, 15, 8, 43, 1, time.Local), Time{15, 8, 43, 1}}, + {time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC), Time{0, 0, 0, 0}}, + } { + if got := TimeOf(test.time); got != test.want { + t.Errorf("TimeOf(%v) = %+v, want %+v", test.time, got, test.want) + } + } +} + +func TestTimeIsValid(t *testing.T) { + for _, test := range []struct { + time Time + want bool + }{ + {Time{0, 0, 0, 0}, true}, + {Time{23, 0, 0, 0}, true}, + {Time{23, 59, 59, 999999999}, true}, + {Time{24, 59, 59, 999999999}, false}, + {Time{23, 60, 59, 999999999}, false}, + {Time{23, 59, 60, 999999999}, false}, + {Time{23, 59, 59, 1000000000}, false}, + {Time{-1, 0, 0, 0}, false}, + {Time{0, -1, 0, 0}, false}, + {Time{0, 0, -1, 0}, false}, + {Time{0, 0, 0, -1}, false}, + } { + got := test.time.IsValid() + if got != test.want { + t.Errorf("%#v: got %t, want %t", test.time, got, test.want) + } + } +} + +func TestDateTimeToString(t *testing.T) { + for _, test := range []struct { + str string + dateTime DateTime + roundTrip bool // ParseDateTime(str).String() == str? + }{ + {"2016-03-22T13:26:33", DateTime{Date{2016, 03, 22}, Time{13, 26, 33, 0}}, true}, + {"2016-03-22T13:26:33.000000600", DateTime{Date{2016, 03, 22}, Time{13, 26, 33, 600}}, true}, + {"2016-03-22t13:26:33", DateTime{Date{2016, 03, 22}, Time{13, 26, 33, 0}}, false}, + } { + gotDateTime, err := ParseDateTime(test.str) + if err != nil { + t.Errorf("ParseDateTime(%q): got error: %v", test.str, err) + continue + } + if gotDateTime != test.dateTime { + t.Errorf("ParseDateTime(%q) = %+v, want %+v", test.str, gotDateTime, test.dateTime) + } + if test.roundTrip { + gotStr := test.dateTime.String() + if gotStr != test.str { + t.Errorf("%#v.String() = %q, want %q", test.dateTime, gotStr, test.str) + } + } + } +} + +func TestParseDateTimeErrors(t *testing.T) { + for _, str := range []string{ + "", + "2016-03-22", // just a date + "13:26:33", // just a time + "2016-03-22 13:26:33", // wrong separating character + "2016-03-22T13:26:33x", // extra at end + } { + if _, err := ParseDateTime(str); err == nil { + t.Errorf("ParseDateTime(%q) succeeded, want error", str) + } + } +} + +func TestDateTimeOf(t *testing.T) { + for _, test := range []struct { + time time.Time + want DateTime + }{ + {time.Date(2014, 8, 20, 15, 8, 43, 1, time.Local), + DateTime{Date{2014, 8, 20}, Time{15, 8, 43, 1}}}, + {time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC), + DateTime{Date{1, 1, 1}, Time{0, 0, 0, 0}}}, + } { + if got := DateTimeOf(test.time); got != test.want { + t.Errorf("DateTimeOf(%v) = %+v, want %+v", test.time, got, test.want) + } + } +} + +func TestDateTimeIsValid(t *testing.T) { + // No need to be exhaustive here; it's just Date.IsValid && Time.IsValid. + for _, test := range []struct { + dt DateTime + want bool + }{ + {DateTime{Date{2016, 3, 20}, Time{0, 0, 0, 0}}, true}, + {DateTime{Date{2016, -3, 20}, Time{0, 0, 0, 0}}, false}, + {DateTime{Date{2016, 3, 20}, Time{24, 0, 0, 0}}, false}, + } { + got := test.dt.IsValid() + if got != test.want { + t.Errorf("%#v: got %t, want %t", test.dt, got, test.want) + } + } +} + +func TestDateTimeIn(t *testing.T) { + dt := DateTime{Date{2016, 1, 2}, Time{3, 4, 5, 6}} + got := dt.In(time.UTC) + want := time.Date(2016, 1, 2, 3, 4, 5, 6, time.UTC) + if !got.Equal(want) { + t.Errorf("got %v, want %v", got, want) + } +} + +func TestDateTimeBefore(t *testing.T) { + d1 := Date{2016, 12, 31} + d2 := Date{2017, 1, 1} + t1 := Time{5, 6, 7, 8} + t2 := Time{5, 6, 7, 9} + for _, test := range []struct { + dt1, dt2 DateTime + want bool + }{ + {DateTime{d1, t1}, DateTime{d2, t1}, true}, + {DateTime{d1, t1}, DateTime{d1, t2}, true}, + {DateTime{d2, t1}, DateTime{d1, t1}, false}, + {DateTime{d2, t1}, DateTime{d2, t1}, false}, + } { + if got := test.dt1.Before(test.dt2); got != test.want { + t.Errorf("%v.Before(%v): got %t, want %t", test.dt1, test.dt2, got, test.want) + } + } +} + +func TestDateTimeAfter(t *testing.T) { + d1 := Date{2016, 12, 31} + d2 := Date{2017, 1, 1} + t1 := Time{5, 6, 7, 8} + t2 := Time{5, 6, 7, 9} + for _, test := range []struct { + dt1, dt2 DateTime + want bool + }{ + {DateTime{d1, t1}, DateTime{d2, t1}, false}, + {DateTime{d1, t1}, DateTime{d1, t2}, false}, + {DateTime{d2, t1}, DateTime{d1, t1}, true}, + {DateTime{d2, t1}, DateTime{d2, t1}, false}, + } { + if got := test.dt1.After(test.dt2); got != test.want { + t.Errorf("%v.After(%v): got %t, want %t", test.dt1, test.dt2, got, test.want) + } + } +} + +func TestMarshalJSON(t *testing.T) { + for _, test := range []struct { + value interface{} + want string + }{ + {Date{1987, 4, 15}, `"1987-04-15"`}, + {Time{18, 54, 2, 0}, `"18:54:02"`}, + {DateTime{Date{1987, 4, 15}, Time{18, 54, 2, 0}}, `"1987-04-15T18:54:02"`}, + } { + bgot, err := json.Marshal(test.value) + if err != nil { + t.Fatal(err) + } + if got := string(bgot); got != test.want { + t.Errorf("%#v: got %s, want %s", test.value, got, test.want) + } + } +} + +func TestUnmarshalJSON(t *testing.T) { + var d Date + var tm Time + var dt DateTime + for _, test := range []struct { + data string + ptr interface{} + want interface{} + }{ + {`"1987-04-15"`, &d, &Date{1987, 4, 15}}, + {`"1987-04-\u0031\u0035"`, &d, &Date{1987, 4, 15}}, + {`"18:54:02"`, &tm, &Time{18, 54, 2, 0}}, + {`"1987-04-15T18:54:02"`, &dt, &DateTime{Date{1987, 4, 15}, Time{18, 54, 2, 0}}}, + } { + if err := json.Unmarshal([]byte(test.data), test.ptr); err != nil { + t.Fatalf("%s: %v", test.data, err) + } + if !cmp.Equal(test.ptr, test.want) { + t.Errorf("%s: got %#v, want %#v", test.data, test.ptr, test.want) + } + } + + for _, bad := range []string{"", `""`, `"bad"`, `"1987-04-15x"`, + `19870415`, // a JSON number + `11987-04-15x`, // not a JSON string + + } { + if json.Unmarshal([]byte(bad), &d) == nil { + t.Errorf("%q, Date: got nil, want error", bad) + } + if json.Unmarshal([]byte(bad), &tm) == nil { + t.Errorf("%q, Time: got nil, want error", bad) + } + if json.Unmarshal([]byte(bad), &dt) == nil { + t.Errorf("%q, DateTime: got nil, want error", bad) + } + } +} diff --git a/vendor/cloud.google.com/go/cloud.go b/vendor/cloud.google.com/go/cloud.go new file mode 100644 index 00000000..9cf75c5e --- /dev/null +++ b/vendor/cloud.google.com/go/cloud.go @@ -0,0 +1,79 @@ +// Copyright 2014 Google LLC +// +// 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 cloud is the root of the packages used to access Google Cloud +Services. See https://godoc.org/cloud.google.com/go for a full list +of sub-packages. + + +Client Options + +All clients in sub-packages are configurable via client options. These options are +described here: https://godoc.org/google.golang.org/api/option. + + +Authentication and Authorization + +All the clients in sub-packages support authentication via Google Application Default +Credentials (see https://cloud.google.com/docs/authentication/production), or +by providing a JSON key file for a Service Account. See the authentication examples +in this package for details. + + +Timeouts and Cancellation + +By default, all requests in sub-packages will run indefinitely, retrying on transient +errors when correctness allows. To set timeouts or arrange for cancellation, use +contexts. See the examples for details. + +Do not attempt to control the initial connection (dialing) of a service by setting a +timeout on the context passed to NewClient. Dialing is non-blocking, so timeouts +would be ineffective and would only interfere with credential refreshing, which uses +the same context. + + +Connection Pooling + +Connection pooling differs in clients based on their transport. Cloud +clients either rely on HTTP or gRPC transports to communicate +with Google Cloud. + +Cloud clients that use HTTP (bigquery, compute, storage, and translate) rely on the +underlying HTTP transport to cache connections for later re-use. These are cached to +the default http.MaxIdleConns and http.MaxIdleConnsPerHost settings in +http.DefaultTransport. + +For gRPC clients (all others in this repo), connection pooling is configurable. Users +of cloud client libraries may specify option.WithGRPCConnectionPool(n) as a client +option to NewClient calls. This configures the underlying gRPC connections to be +pooled and addressed in a round robin fashion. + + +Using the Libraries with Docker + +Minimal docker images like Alpine lack CA certificates. This causes RPCs to appear to +hang, because gRPC retries indefinitely. See https://github.com/GoogleCloudPlatform/google-cloud-go/issues/928 +for more information. + + +Debugging + +To see gRPC logs, set the environment variable GRPC_GO_LOG_SEVERITY_LEVEL. See +https://godoc.org/google.golang.org/grpc/grpclog for more information. + +For HTTP logging, set the GODEBUG environment variable to "http2debug=1" or "http2debug=2". + +*/ +package cloud // import "cloud.google.com/go" diff --git a/vendor/cloud.google.com/go/cloudtasks/apiv2beta2/cloud_tasks_client.go b/vendor/cloud.google.com/go/cloudtasks/apiv2beta2/cloud_tasks_client.go new file mode 100644 index 00000000..0a2d93e4 --- /dev/null +++ b/vendor/cloud.google.com/go/cloudtasks/apiv2beta2/cloud_tasks_client.go @@ -0,0 +1,784 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package cloudtasks + +import ( + "context" + "fmt" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2beta2" + iampb "google.golang.org/genproto/googleapis/iam/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + ListQueues []gax.CallOption + GetQueue []gax.CallOption + CreateQueue []gax.CallOption + UpdateQueue []gax.CallOption + DeleteQueue []gax.CallOption + PurgeQueue []gax.CallOption + PauseQueue []gax.CallOption + ResumeQueue []gax.CallOption + GetIamPolicy []gax.CallOption + SetIamPolicy []gax.CallOption + TestIamPermissions []gax.CallOption + ListTasks []gax.CallOption + GetTask []gax.CallOption + CreateTask []gax.CallOption + DeleteTask []gax.CallOption + LeaseTasks []gax.CallOption + AcknowledgeTask []gax.CallOption + RenewLease []gax.CallOption + CancelLease []gax.CallOption + RunTask []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("cloudtasks.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + ListQueues: retry[[2]string{"default", "idempotent"}], + GetQueue: retry[[2]string{"default", "idempotent"}], + CreateQueue: retry[[2]string{"default", "non_idempotent"}], + UpdateQueue: retry[[2]string{"default", "non_idempotent"}], + DeleteQueue: retry[[2]string{"default", "idempotent"}], + PurgeQueue: retry[[2]string{"default", "non_idempotent"}], + PauseQueue: retry[[2]string{"default", "non_idempotent"}], + ResumeQueue: retry[[2]string{"default", "non_idempotent"}], + GetIamPolicy: retry[[2]string{"default", "idempotent"}], + SetIamPolicy: retry[[2]string{"default", "non_idempotent"}], + TestIamPermissions: retry[[2]string{"default", "idempotent"}], + ListTasks: retry[[2]string{"default", "idempotent"}], + GetTask: retry[[2]string{"default", "idempotent"}], + CreateTask: retry[[2]string{"default", "non_idempotent"}], + DeleteTask: retry[[2]string{"default", "idempotent"}], + LeaseTasks: retry[[2]string{"default", "non_idempotent"}], + AcknowledgeTask: retry[[2]string{"default", "non_idempotent"}], + RenewLease: retry[[2]string{"default", "non_idempotent"}], + CancelLease: retry[[2]string{"default", "non_idempotent"}], + RunTask: retry[[2]string{"default", "non_idempotent"}], + } +} + +// Client is a client for interacting with Cloud Tasks API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client taskspb.CloudTasksClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new cloud tasks client. +// +// Cloud Tasks allows developers to manage the execution of background +// work in their applications. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: taskspb.NewCloudTasksClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListQueues lists queues. +// +// Queues are returned in lexicographical order. +func (c *Client) ListQueues(ctx context.Context, req *taskspb.ListQueuesRequest, opts ...gax.CallOption) *QueueIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ListQueues[0:len(c.CallOptions.ListQueues):len(c.CallOptions.ListQueues)], opts...) + it := &QueueIterator{} + req = proto.Clone(req).(*taskspb.ListQueuesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*taskspb.Queue, string, error) { + var resp *taskspb.ListQueuesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListQueues(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Queues, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetQueue gets a queue. +func (c *Client) GetQueue(ctx context.Context, req *taskspb.GetQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.GetQueue[0:len(c.CallOptions.GetQueue):len(c.CallOptions.GetQueue)], opts...) + var resp *taskspb.Queue + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateQueue creates a queue. +// +// Queues created with this method allow tasks to live for a maximum of 31 +// days. After a task is 31 days old, the task will be deleted regardless of whether +// it was dispatched or not. +// +// WARNING: Using this method may have unintended side effects if you are +// using an App Engine queue.yaml or queue.xml file to manage your queues. +// Read +// Overview of Queue Management and queue.yaml (at https://cloud.google.com/tasks/docs/queue-yaml) +// before using this method. +func (c *Client) CreateQueue(ctx context.Context, req *taskspb.CreateQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.CreateQueue[0:len(c.CallOptions.CreateQueue):len(c.CallOptions.CreateQueue)], opts...) + var resp *taskspb.Queue + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateQueue updates a queue. +// +// This method creates the queue if it does not exist and updates +// the queue if it does exist. +// +// Queues created with this method allow tasks to live for a maximum of 31 +// days. After a task is 31 days old, the task will be deleted regardless of whether +// it was dispatched or not. +// +// WARNING: Using this method may have unintended side effects if you are +// using an App Engine queue.yaml or queue.xml file to manage your queues. +// Read +// Overview of Queue Management and queue.yaml (at https://cloud.google.com/tasks/docs/queue-yaml) +// before using this method. +func (c *Client) UpdateQueue(ctx context.Context, req *taskspb.UpdateQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "queue.name", req.GetQueue().GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.UpdateQueue[0:len(c.CallOptions.UpdateQueue):len(c.CallOptions.UpdateQueue)], opts...) + var resp *taskspb.Queue + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteQueue deletes a queue. +// +// This command will delete the queue even if it has tasks in it. +// +// Note: If you delete a queue, a queue with the same name can't be created +// for 7 days. +// +// WARNING: Using this method may have unintended side effects if you are +// using an App Engine queue.yaml or queue.xml file to manage your queues. +// Read +// Overview of Queue Management and queue.yaml (at https://cloud.google.com/tasks/docs/queue-yaml) +// before using this method. +func (c *Client) DeleteQueue(ctx context.Context, req *taskspb.DeleteQueueRequest, opts ...gax.CallOption) error { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.DeleteQueue[0:len(c.CallOptions.DeleteQueue):len(c.CallOptions.DeleteQueue)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// PurgeQueue purges a queue by deleting all of its tasks. +// +// All tasks created before this method is called are permanently deleted. +// +// Purge operations can take up to one minute to take effect. Tasks +// might be dispatched before the purge takes effect. A purge is irreversible. +func (c *Client) PurgeQueue(ctx context.Context, req *taskspb.PurgeQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.PurgeQueue[0:len(c.CallOptions.PurgeQueue):len(c.CallOptions.PurgeQueue)], opts...) + var resp *taskspb.Queue + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.PurgeQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// PauseQueue pauses the queue. +// +// If a queue is paused then the system will stop dispatching tasks +// until the queue is resumed via +// [ResumeQueue][google.cloud.tasks.v2beta2.CloudTasks.ResumeQueue]. Tasks can still be added +// when the queue is paused. A queue is paused if its +// [state][google.cloud.tasks.v2beta2.Queue.state] is [PAUSED][google.cloud.tasks.v2beta2.Queue.State.PAUSED]. +func (c *Client) PauseQueue(ctx context.Context, req *taskspb.PauseQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.PauseQueue[0:len(c.CallOptions.PauseQueue):len(c.CallOptions.PauseQueue)], opts...) + var resp *taskspb.Queue + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.PauseQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ResumeQueue resume a queue. +// +// This method resumes a queue after it has been +// [PAUSED][google.cloud.tasks.v2beta2.Queue.State.PAUSED] or +// [DISABLED][google.cloud.tasks.v2beta2.Queue.State.DISABLED]. The state of a queue is stored +// in the queue's [state][google.cloud.tasks.v2beta2.Queue.state]; after calling this method it +// will be set to [RUNNING][google.cloud.tasks.v2beta2.Queue.State.RUNNING]. +// +// WARNING: Resuming many high-QPS queues at the same time can +// lead to target overloading. If you are resuming high-QPS +// queues, follow the 500/50/5 pattern described in +// Managing Cloud Tasks Scaling Risks (at https://cloud.google.com/tasks/docs/manage-cloud-task-scaling). +func (c *Client) ResumeQueue(ctx context.Context, req *taskspb.ResumeQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ResumeQueue[0:len(c.CallOptions.ResumeQueue):len(c.CallOptions.ResumeQueue)], opts...) + var resp *taskspb.Queue + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ResumeQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetIamPolicy gets the access control policy for a [Queue][google.cloud.tasks.v2beta2.Queue]. +// Returns an empty policy if the resource exists and does not have a policy +// set. +// +// Authorization requires the following +// Google IAM (at https://cloud.google.com/iam) permission on the specified +// resource parent: +// +// cloudtasks.queues.getIamPolicy +func (c *Client) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", req.GetResource())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.GetIamPolicy[0:len(c.CallOptions.GetIamPolicy):len(c.CallOptions.GetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetIamPolicy sets the access control policy for a [Queue][google.cloud.tasks.v2beta2.Queue]. Replaces any existing +// policy. +// +// Note: The Cloud Console does not check queue-level IAM permissions yet. +// Project-level permissions are required to use the Cloud Console. +// +// Authorization requires the following +// Google IAM (at https://cloud.google.com/iam) permission on the specified +// resource parent: +// +// cloudtasks.queues.setIamPolicy +func (c *Client) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", req.GetResource())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.SetIamPolicy[0:len(c.CallOptions.SetIamPolicy):len(c.CallOptions.SetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.SetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// TestIamPermissions returns permissions that a caller has on a [Queue][google.cloud.tasks.v2beta2.Queue]. +// If the resource does not exist, this will return an empty set of +// permissions, not a [NOT_FOUND][google.rpc.Code.NOT_FOUND] error. +// +// Note: This operation is designed to be used for building permission-aware +// UIs and command-line tools, not for authorization checking. This operation +// may "fail open" without warning. +func (c *Client) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", req.GetResource())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.TestIamPermissions[0:len(c.CallOptions.TestIamPermissions):len(c.CallOptions.TestIamPermissions)], opts...) + var resp *iampb.TestIamPermissionsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.TestIamPermissions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListTasks lists the tasks in a queue. +// +// By default, only the [BASIC][google.cloud.tasks.v2beta2.Task.View.BASIC] view is retrieved +// due to performance considerations; +// [response_view][google.cloud.tasks.v2beta2.ListTasksRequest.response_view] controls the +// subset of information which is returned. +// +// The tasks may be returned in any order. The ordering may change at any +// time. +func (c *Client) ListTasks(ctx context.Context, req *taskspb.ListTasksRequest, opts ...gax.CallOption) *TaskIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ListTasks[0:len(c.CallOptions.ListTasks):len(c.CallOptions.ListTasks)], opts...) + it := &TaskIterator{} + req = proto.Clone(req).(*taskspb.ListTasksRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*taskspb.Task, string, error) { + var resp *taskspb.ListTasksResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListTasks(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Tasks, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetTask gets a task. +func (c *Client) GetTask(ctx context.Context, req *taskspb.GetTaskRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.GetTask[0:len(c.CallOptions.GetTask):len(c.CallOptions.GetTask)], opts...) + var resp *taskspb.Task + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetTask(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateTask creates a task and adds it to a queue. +// +// Tasks cannot be updated after creation; there is no UpdateTask command. +// +// For [App Engine queues][google.cloud.tasks.v2beta2.AppEngineHttpTarget], the maximum task size is +// 100KB. +// +// For [pull queues][google.cloud.tasks.v2beta2.PullTarget], the maximum task size is 1MB. +func (c *Client) CreateTask(ctx context.Context, req *taskspb.CreateTaskRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.CreateTask[0:len(c.CallOptions.CreateTask):len(c.CallOptions.CreateTask)], opts...) + var resp *taskspb.Task + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateTask(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteTask deletes a task. +// +// A task can be deleted if it is scheduled or dispatched. A task +// cannot be deleted if it has completed successfully or permanently +// failed. +func (c *Client) DeleteTask(ctx context.Context, req *taskspb.DeleteTaskRequest, opts ...gax.CallOption) error { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.DeleteTask[0:len(c.CallOptions.DeleteTask):len(c.CallOptions.DeleteTask)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteTask(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// LeaseTasks leases tasks from a pull queue for +// [lease_duration][google.cloud.tasks.v2beta2.LeaseTasksRequest.lease_duration]. +// +// This method is invoked by the worker to obtain a lease. The +// worker must acknowledge the task via +// [AcknowledgeTask][google.cloud.tasks.v2beta2.CloudTasks.AcknowledgeTask] after they have +// performed the work associated with the task. +// +// The [payload][google.cloud.tasks.v2beta2.PullMessage.payload] is intended to store data that +// the worker needs to perform the work associated with the task. To +// return the payloads in the [response][google.cloud.tasks.v2beta2.LeaseTasksResponse], set +// [response_view][google.cloud.tasks.v2beta2.LeaseTasksRequest.response_view] to +// [FULL][google.cloud.tasks.v2beta2.Task.View.FULL]. +// +// A maximum of 10 qps of [LeaseTasks][google.cloud.tasks.v2beta2.CloudTasks.LeaseTasks] +// requests are allowed per +// queue. [RESOURCE_EXHAUSTED][google.rpc.Code.RESOURCE_EXHAUSTED] +// is returned when this limit is +// exceeded. [RESOURCE_EXHAUSTED][google.rpc.Code.RESOURCE_EXHAUSTED] +// is also returned when +// [max_tasks_dispatched_per_second][google.cloud.tasks.v2beta2.RateLimits.max_tasks_dispatched_per_second] +// is exceeded. +func (c *Client) LeaseTasks(ctx context.Context, req *taskspb.LeaseTasksRequest, opts ...gax.CallOption) (*taskspb.LeaseTasksResponse, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.LeaseTasks[0:len(c.CallOptions.LeaseTasks):len(c.CallOptions.LeaseTasks)], opts...) + var resp *taskspb.LeaseTasksResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.LeaseTasks(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// AcknowledgeTask acknowledges a pull task. +// +// The worker, that is, the entity that +// [leased][google.cloud.tasks.v2beta2.CloudTasks.LeaseTasks] this task must call this method +// to indicate that the work associated with the task has finished. +// +// The worker must acknowledge a task within the +// [lease_duration][google.cloud.tasks.v2beta2.LeaseTasksRequest.lease_duration] or the lease +// will expire and the task will become available to be leased +// again. After the task is acknowledged, it will not be returned +// by a later [LeaseTasks][google.cloud.tasks.v2beta2.CloudTasks.LeaseTasks], +// [GetTask][google.cloud.tasks.v2beta2.CloudTasks.GetTask], or +// [ListTasks][google.cloud.tasks.v2beta2.CloudTasks.ListTasks]. +func (c *Client) AcknowledgeTask(ctx context.Context, req *taskspb.AcknowledgeTaskRequest, opts ...gax.CallOption) error { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.AcknowledgeTask[0:len(c.CallOptions.AcknowledgeTask):len(c.CallOptions.AcknowledgeTask)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.AcknowledgeTask(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// RenewLease renew the current lease of a pull task. +// +// The worker can use this method to extend the lease by a new +// duration, starting from now. The new task lease will be +// returned in the task's [schedule_time][google.cloud.tasks.v2beta2.Task.schedule_time]. +func (c *Client) RenewLease(ctx context.Context, req *taskspb.RenewLeaseRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.RenewLease[0:len(c.CallOptions.RenewLease):len(c.CallOptions.RenewLease)], opts...) + var resp *taskspb.Task + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.RenewLease(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CancelLease cancel a pull task's lease. +// +// The worker can use this method to cancel a task's lease by +// setting its [schedule_time][google.cloud.tasks.v2beta2.Task.schedule_time] to now. This will +// make the task available to be leased to the next caller of +// [LeaseTasks][google.cloud.tasks.v2beta2.CloudTasks.LeaseTasks]. +func (c *Client) CancelLease(ctx context.Context, req *taskspb.CancelLeaseRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.CancelLease[0:len(c.CallOptions.CancelLease):len(c.CallOptions.CancelLease)], opts...) + var resp *taskspb.Task + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CancelLease(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// RunTask forces a task to run now. +// +// When this method is called, Cloud Tasks will dispatch the task, even if +// the task is already running, the queue has reached its [RateLimits][google.cloud.tasks.v2beta2.RateLimits] or +// is [PAUSED][google.cloud.tasks.v2beta2.Queue.State.PAUSED]. +// +// This command is meant to be used for manual debugging. For +// example, [RunTask][google.cloud.tasks.v2beta2.CloudTasks.RunTask] can be used to retry a failed +// task after a fix has been made or to manually force a task to be +// dispatched now. +// +// The dispatched task is returned. That is, the task that is returned +// contains the [status][google.cloud.tasks.v2beta2.Task.status] after the task is dispatched but +// before the task is received by its target. +// +// If Cloud Tasks receives a successful response from the task's +// target, then the task will be deleted; otherwise the task's +// [schedule_time][google.cloud.tasks.v2beta2.Task.schedule_time] will be reset to the time that +// [RunTask][google.cloud.tasks.v2beta2.CloudTasks.RunTask] was called plus the retry delay specified +// in the queue's [RetryConfig][google.cloud.tasks.v2beta2.RetryConfig]. +// +// [RunTask][google.cloud.tasks.v2beta2.CloudTasks.RunTask] returns +// [NOT_FOUND][google.rpc.Code.NOT_FOUND] when it is called on a +// task that has already succeeded or permanently failed. +// +// [RunTask][google.cloud.tasks.v2beta2.CloudTasks.RunTask] cannot be called on a +// [pull task][google.cloud.tasks.v2beta2.PullMessage]. +func (c *Client) RunTask(ctx context.Context, req *taskspb.RunTaskRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.RunTask[0:len(c.CallOptions.RunTask):len(c.CallOptions.RunTask)], opts...) + var resp *taskspb.Task + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.RunTask(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// QueueIterator manages a stream of *taskspb.Queue. +type QueueIterator struct { + items []*taskspb.Queue + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*taskspb.Queue, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *QueueIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *QueueIterator) Next() (*taskspb.Queue, error) { + var item *taskspb.Queue + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *QueueIterator) bufLen() int { + return len(it.items) +} + +func (it *QueueIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// TaskIterator manages a stream of *taskspb.Task. +type TaskIterator struct { + items []*taskspb.Task + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*taskspb.Task, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TaskIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TaskIterator) Next() (*taskspb.Task, error) { + var item *taskspb.Task + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TaskIterator) bufLen() int { + return len(it.items) +} + +func (it *TaskIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/cloudtasks/apiv2beta2/cloud_tasks_client_example_test.go b/vendor/cloud.google.com/go/cloudtasks/apiv2beta2/cloud_tasks_client_example_test.go new file mode 100644 index 00000000..4c289343 --- /dev/null +++ b/vendor/cloud.google.com/go/cloudtasks/apiv2beta2/cloud_tasks_client_example_test.go @@ -0,0 +1,402 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package cloudtasks_test + +import ( + "context" + + cloudtasks "cloud.google.com/go/cloudtasks/apiv2beta2" + "google.golang.org/api/iterator" + taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2beta2" + iampb "google.golang.org/genproto/googleapis/iam/v1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_ListQueues() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.ListQueuesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListQueues(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_GetQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.GetQueueRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_CreateQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.CreateQueueRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_UpdateQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.UpdateQueueRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_DeleteQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.DeleteQueueRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_PurgeQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.PurgeQueueRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.PurgeQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_PauseQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.PauseQueueRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.PauseQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ResumeQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.ResumeQueueRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ResumeQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_GetIamPolicy() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.GetIamPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetIamPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_SetIamPolicy() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.SetIamPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetIamPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_TestIamPermissions() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.TestIamPermissionsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.TestIamPermissions(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ListTasks() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.ListTasksRequest{ + // TODO: Fill request struct fields. + } + it := c.ListTasks(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_GetTask() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.GetTaskRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetTask(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_CreateTask() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.CreateTaskRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateTask(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_DeleteTask() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.DeleteTaskRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteTask(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_LeaseTasks() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.LeaseTasksRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.LeaseTasks(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_AcknowledgeTask() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.AcknowledgeTaskRequest{ + // TODO: Fill request struct fields. + } + err = c.AcknowledgeTask(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_RenewLease() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.RenewLeaseRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.RenewLease(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_CancelLease() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.CancelLeaseRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CancelLease(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_RunTask() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.RunTaskRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.RunTask(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/cloudtasks/apiv2beta2/doc.go b/vendor/cloud.google.com/go/cloudtasks/apiv2beta2/doc.go new file mode 100644 index 00000000..75530751 --- /dev/null +++ b/vendor/cloud.google.com/go/cloudtasks/apiv2beta2/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package cloudtasks is an auto-generated package for the +// Cloud Tasks API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Manages the execution of large numbers of distributed requests. +package cloudtasks // import "cloud.google.com/go/cloudtasks/apiv2beta2" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/cloudtasks/apiv2beta2/mock_test.go b/vendor/cloud.google.com/go/cloudtasks/apiv2beta2/mock_test.go new file mode 100644 index 00000000..e3f62aa7 --- /dev/null +++ b/vendor/cloud.google.com/go/cloudtasks/apiv2beta2/mock_test.go @@ -0,0 +1,1554 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package cloudtasks + +import ( + durationpb "github.com/golang/protobuf/ptypes/duration" + emptypb "github.com/golang/protobuf/ptypes/empty" + timestamppb "github.com/golang/protobuf/ptypes/timestamp" + taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2beta2" + iampb "google.golang.org/genproto/googleapis/iam/v1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockCloudTasksServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + taskspb.CloudTasksServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockCloudTasksServer) ListQueues(ctx context.Context, req *taskspb.ListQueuesRequest) (*taskspb.ListQueuesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.ListQueuesResponse), nil +} + +func (s *mockCloudTasksServer) GetQueue(ctx context.Context, req *taskspb.GetQueueRequest) (*taskspb.Queue, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Queue), nil +} + +func (s *mockCloudTasksServer) CreateQueue(ctx context.Context, req *taskspb.CreateQueueRequest) (*taskspb.Queue, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Queue), nil +} + +func (s *mockCloudTasksServer) UpdateQueue(ctx context.Context, req *taskspb.UpdateQueueRequest) (*taskspb.Queue, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Queue), nil +} + +func (s *mockCloudTasksServer) DeleteQueue(ctx context.Context, req *taskspb.DeleteQueueRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockCloudTasksServer) PurgeQueue(ctx context.Context, req *taskspb.PurgeQueueRequest) (*taskspb.Queue, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Queue), nil +} + +func (s *mockCloudTasksServer) PauseQueue(ctx context.Context, req *taskspb.PauseQueueRequest) (*taskspb.Queue, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Queue), nil +} + +func (s *mockCloudTasksServer) ResumeQueue(ctx context.Context, req *taskspb.ResumeQueueRequest) (*taskspb.Queue, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Queue), nil +} + +func (s *mockCloudTasksServer) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockCloudTasksServer) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockCloudTasksServer) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest) (*iampb.TestIamPermissionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.TestIamPermissionsResponse), nil +} + +func (s *mockCloudTasksServer) ListTasks(ctx context.Context, req *taskspb.ListTasksRequest) (*taskspb.ListTasksResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.ListTasksResponse), nil +} + +func (s *mockCloudTasksServer) GetTask(ctx context.Context, req *taskspb.GetTaskRequest) (*taskspb.Task, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Task), nil +} + +func (s *mockCloudTasksServer) CreateTask(ctx context.Context, req *taskspb.CreateTaskRequest) (*taskspb.Task, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Task), nil +} + +func (s *mockCloudTasksServer) DeleteTask(ctx context.Context, req *taskspb.DeleteTaskRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockCloudTasksServer) LeaseTasks(ctx context.Context, req *taskspb.LeaseTasksRequest) (*taskspb.LeaseTasksResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.LeaseTasksResponse), nil +} + +func (s *mockCloudTasksServer) AcknowledgeTask(ctx context.Context, req *taskspb.AcknowledgeTaskRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockCloudTasksServer) RenewLease(ctx context.Context, req *taskspb.RenewLeaseRequest) (*taskspb.Task, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Task), nil +} + +func (s *mockCloudTasksServer) CancelLease(ctx context.Context, req *taskspb.CancelLeaseRequest) (*taskspb.Task, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Task), nil +} + +func (s *mockCloudTasksServer) RunTask(ctx context.Context, req *taskspb.RunTaskRequest) (*taskspb.Task, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Task), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockCloudTasks mockCloudTasksServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + taskspb.RegisterCloudTasksServer(serv, &mockCloudTasks) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestCloudTasksListQueues(t *testing.T) { + var nextPageToken string = "" + var queuesElement *taskspb.Queue = &taskspb.Queue{} + var queues = []*taskspb.Queue{queuesElement} + var expectedResponse = &taskspb.ListQueuesResponse{ + NextPageToken: nextPageToken, + Queues: queues, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &taskspb.ListQueuesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListQueues(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Queues[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksListQueuesError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &taskspb.ListQueuesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListQueues(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksGetQueue(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &taskspb.Queue{ + Name: name2, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.GetQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksGetQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.GetQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksCreateQueue(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &taskspb.Queue{ + Name: name, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var queue *taskspb.Queue = &taskspb.Queue{} + var request = &taskspb.CreateQueueRequest{ + Parent: formattedParent, + Queue: queue, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksCreateQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var queue *taskspb.Queue = &taskspb.Queue{} + var request = &taskspb.CreateQueueRequest{ + Parent: formattedParent, + Queue: queue, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksUpdateQueue(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &taskspb.Queue{ + Name: name, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var queue *taskspb.Queue = &taskspb.Queue{} + var request = &taskspb.UpdateQueueRequest{ + Queue: queue, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksUpdateQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var queue *taskspb.Queue = &taskspb.Queue{} + var request = &taskspb.UpdateQueueRequest{ + Queue: queue, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksDeleteQueue(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.DeleteQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestCloudTasksDeleteQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.DeleteQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestCloudTasksPurgeQueue(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &taskspb.Queue{ + Name: name2, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.PurgeQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PurgeQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksPurgeQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.PurgeQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PurgeQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksPauseQueue(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &taskspb.Queue{ + Name: name2, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.PauseQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PauseQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksPauseQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.PauseQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PauseQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksResumeQueue(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &taskspb.Queue{ + Name: name2, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.ResumeQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ResumeQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksResumeQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.ResumeQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ResumeQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksGetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksGetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksSetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksSetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksTestIamPermissions(t *testing.T) { + var expectedResponse *iampb.TestIamPermissionsResponse = &iampb.TestIamPermissionsResponse{} + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksTestIamPermissionsError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksListTasks(t *testing.T) { + var nextPageToken string = "" + var tasksElement *taskspb.Task = &taskspb.Task{} + var tasks = []*taskspb.Task{tasksElement} + var expectedResponse = &taskspb.ListTasksResponse{ + NextPageToken: nextPageToken, + Tasks: tasks, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.ListTasksRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTasks(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Tasks[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksListTasksError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.ListTasksRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTasks(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksGetTask(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &taskspb.Task{ + Name: name2, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var request = &taskspb.GetTaskRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetTask(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksGetTaskError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var request = &taskspb.GetTaskRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetTask(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksCreateTask(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &taskspb.Task{ + Name: name, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var task *taskspb.Task = &taskspb.Task{} + var request = &taskspb.CreateTaskRequest{ + Parent: formattedParent, + Task: task, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateTask(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksCreateTaskError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var task *taskspb.Task = &taskspb.Task{} + var request = &taskspb.CreateTaskRequest{ + Parent: formattedParent, + Task: task, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateTask(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksDeleteTask(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var request = &taskspb.DeleteTaskRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteTask(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestCloudTasksDeleteTaskError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var request = &taskspb.DeleteTaskRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteTask(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestCloudTasksLeaseTasks(t *testing.T) { + var expectedResponse *taskspb.LeaseTasksResponse = &taskspb.LeaseTasksResponse{} + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var leaseDuration *durationpb.Duration = &durationpb.Duration{} + var request = &taskspb.LeaseTasksRequest{ + Parent: formattedParent, + LeaseDuration: leaseDuration, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.LeaseTasks(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksLeaseTasksError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var leaseDuration *durationpb.Duration = &durationpb.Duration{} + var request = &taskspb.LeaseTasksRequest{ + Parent: formattedParent, + LeaseDuration: leaseDuration, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.LeaseTasks(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksAcknowledgeTask(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var scheduleTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var request = &taskspb.AcknowledgeTaskRequest{ + Name: formattedName, + ScheduleTime: scheduleTime, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.AcknowledgeTask(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestCloudTasksAcknowledgeTaskError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var scheduleTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var request = &taskspb.AcknowledgeTaskRequest{ + Name: formattedName, + ScheduleTime: scheduleTime, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.AcknowledgeTask(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestCloudTasksRenewLease(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &taskspb.Task{ + Name: name2, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var scheduleTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var leaseDuration *durationpb.Duration = &durationpb.Duration{} + var request = &taskspb.RenewLeaseRequest{ + Name: formattedName, + ScheduleTime: scheduleTime, + LeaseDuration: leaseDuration, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RenewLease(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksRenewLeaseError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var scheduleTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var leaseDuration *durationpb.Duration = &durationpb.Duration{} + var request = &taskspb.RenewLeaseRequest{ + Name: formattedName, + ScheduleTime: scheduleTime, + LeaseDuration: leaseDuration, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RenewLease(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksCancelLease(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &taskspb.Task{ + Name: name2, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var scheduleTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var request = &taskspb.CancelLeaseRequest{ + Name: formattedName, + ScheduleTime: scheduleTime, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CancelLease(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksCancelLeaseError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var scheduleTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var request = &taskspb.CancelLeaseRequest{ + Name: formattedName, + ScheduleTime: scheduleTime, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CancelLease(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksRunTask(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &taskspb.Task{ + Name: name2, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var request = &taskspb.RunTaskRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RunTask(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksRunTaskError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var request = &taskspb.RunTaskRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RunTask(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/cloudtasks/apiv2beta3/cloud_tasks_client.go b/vendor/cloud.google.com/go/cloudtasks/apiv2beta3/cloud_tasks_client.go new file mode 100644 index 00000000..e956a7e0 --- /dev/null +++ b/vendor/cloud.google.com/go/cloudtasks/apiv2beta3/cloud_tasks_client.go @@ -0,0 +1,665 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package cloudtasks + +import ( + "context" + "fmt" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2beta3" + iampb "google.golang.org/genproto/googleapis/iam/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + ListQueues []gax.CallOption + GetQueue []gax.CallOption + CreateQueue []gax.CallOption + UpdateQueue []gax.CallOption + DeleteQueue []gax.CallOption + PurgeQueue []gax.CallOption + PauseQueue []gax.CallOption + ResumeQueue []gax.CallOption + GetIamPolicy []gax.CallOption + SetIamPolicy []gax.CallOption + TestIamPermissions []gax.CallOption + ListTasks []gax.CallOption + GetTask []gax.CallOption + CreateTask []gax.CallOption + DeleteTask []gax.CallOption + RunTask []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("cloudtasks.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + ListQueues: retry[[2]string{"default", "idempotent"}], + GetQueue: retry[[2]string{"default", "idempotent"}], + CreateQueue: retry[[2]string{"default", "non_idempotent"}], + UpdateQueue: retry[[2]string{"default", "non_idempotent"}], + DeleteQueue: retry[[2]string{"default", "idempotent"}], + PurgeQueue: retry[[2]string{"default", "non_idempotent"}], + PauseQueue: retry[[2]string{"default", "non_idempotent"}], + ResumeQueue: retry[[2]string{"default", "non_idempotent"}], + GetIamPolicy: retry[[2]string{"default", "idempotent"}], + SetIamPolicy: retry[[2]string{"default", "non_idempotent"}], + TestIamPermissions: retry[[2]string{"default", "idempotent"}], + ListTasks: retry[[2]string{"default", "idempotent"}], + GetTask: retry[[2]string{"default", "idempotent"}], + CreateTask: retry[[2]string{"default", "non_idempotent"}], + DeleteTask: retry[[2]string{"default", "idempotent"}], + RunTask: retry[[2]string{"default", "non_idempotent"}], + } +} + +// Client is a client for interacting with Cloud Tasks API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client taskspb.CloudTasksClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new cloud tasks client. +// +// Cloud Tasks allows developers to manage the execution of background +// work in their applications. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: taskspb.NewCloudTasksClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListQueues lists queues. +// +// Queues are returned in lexicographical order. +func (c *Client) ListQueues(ctx context.Context, req *taskspb.ListQueuesRequest, opts ...gax.CallOption) *QueueIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ListQueues[0:len(c.CallOptions.ListQueues):len(c.CallOptions.ListQueues)], opts...) + it := &QueueIterator{} + req = proto.Clone(req).(*taskspb.ListQueuesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*taskspb.Queue, string, error) { + var resp *taskspb.ListQueuesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListQueues(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Queues, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetQueue gets a queue. +func (c *Client) GetQueue(ctx context.Context, req *taskspb.GetQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.GetQueue[0:len(c.CallOptions.GetQueue):len(c.CallOptions.GetQueue)], opts...) + var resp *taskspb.Queue + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateQueue creates a queue. +// +// Queues created with this method allow tasks to live for a maximum of 31 +// days. After a task is 31 days old, the task will be deleted regardless of whether +// it was dispatched or not. +// +// WARNING: Using this method may have unintended side effects if you are +// using an App Engine queue.yaml or queue.xml file to manage your queues. +// Read +// Overview of Queue Management and queue.yaml (at https://cloud.google.com/tasks/docs/queue-yaml) +// before using this method. +func (c *Client) CreateQueue(ctx context.Context, req *taskspb.CreateQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.CreateQueue[0:len(c.CallOptions.CreateQueue):len(c.CallOptions.CreateQueue)], opts...) + var resp *taskspb.Queue + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateQueue updates a queue. +// +// This method creates the queue if it does not exist and updates +// the queue if it does exist. +// +// Queues created with this method allow tasks to live for a maximum of 31 +// days. After a task is 31 days old, the task will be deleted regardless of whether +// it was dispatched or not. +// +// WARNING: Using this method may have unintended side effects if you are +// using an App Engine queue.yaml or queue.xml file to manage your queues. +// Read +// Overview of Queue Management and queue.yaml (at https://cloud.google.com/tasks/docs/queue-yaml) +// before using this method. +func (c *Client) UpdateQueue(ctx context.Context, req *taskspb.UpdateQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "queue.name", req.GetQueue().GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.UpdateQueue[0:len(c.CallOptions.UpdateQueue):len(c.CallOptions.UpdateQueue)], opts...) + var resp *taskspb.Queue + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteQueue deletes a queue. +// +// This command will delete the queue even if it has tasks in it. +// +// Note: If you delete a queue, a queue with the same name can't be created +// for 7 days. +// +// WARNING: Using this method may have unintended side effects if you are +// using an App Engine queue.yaml or queue.xml file to manage your queues. +// Read +// Overview of Queue Management and queue.yaml (at https://cloud.google.com/tasks/docs/queue-yaml) +// before using this method. +func (c *Client) DeleteQueue(ctx context.Context, req *taskspb.DeleteQueueRequest, opts ...gax.CallOption) error { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.DeleteQueue[0:len(c.CallOptions.DeleteQueue):len(c.CallOptions.DeleteQueue)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// PurgeQueue purges a queue by deleting all of its tasks. +// +// All tasks created before this method is called are permanently deleted. +// +// Purge operations can take up to one minute to take effect. Tasks +// might be dispatched before the purge takes effect. A purge is irreversible. +func (c *Client) PurgeQueue(ctx context.Context, req *taskspb.PurgeQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.PurgeQueue[0:len(c.CallOptions.PurgeQueue):len(c.CallOptions.PurgeQueue)], opts...) + var resp *taskspb.Queue + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.PurgeQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// PauseQueue pauses the queue. +// +// If a queue is paused then the system will stop dispatching tasks +// until the queue is resumed via +// [ResumeQueue][google.cloud.tasks.v2beta3.CloudTasks.ResumeQueue]. Tasks can still be added +// when the queue is paused. A queue is paused if its +// [state][google.cloud.tasks.v2beta3.Queue.state] is [PAUSED][google.cloud.tasks.v2beta3.Queue.State.PAUSED]. +func (c *Client) PauseQueue(ctx context.Context, req *taskspb.PauseQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.PauseQueue[0:len(c.CallOptions.PauseQueue):len(c.CallOptions.PauseQueue)], opts...) + var resp *taskspb.Queue + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.PauseQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ResumeQueue resume a queue. +// +// This method resumes a queue after it has been +// [PAUSED][google.cloud.tasks.v2beta3.Queue.State.PAUSED] or +// [DISABLED][google.cloud.tasks.v2beta3.Queue.State.DISABLED]. The state of a queue is stored +// in the queue's [state][google.cloud.tasks.v2beta3.Queue.state]; after calling this method it +// will be set to [RUNNING][google.cloud.tasks.v2beta3.Queue.State.RUNNING]. +// +// WARNING: Resuming many high-QPS queues at the same time can +// lead to target overloading. If you are resuming high-QPS +// queues, follow the 500/50/5 pattern described in +// Managing Cloud Tasks Scaling Risks (at https://cloud.google.com/tasks/docs/manage-cloud-task-scaling). +func (c *Client) ResumeQueue(ctx context.Context, req *taskspb.ResumeQueueRequest, opts ...gax.CallOption) (*taskspb.Queue, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ResumeQueue[0:len(c.CallOptions.ResumeQueue):len(c.CallOptions.ResumeQueue)], opts...) + var resp *taskspb.Queue + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ResumeQueue(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetIamPolicy gets the access control policy for a [Queue][google.cloud.tasks.v2beta3.Queue]. +// Returns an empty policy if the resource exists and does not have a policy +// set. +// +// Authorization requires the following +// Google IAM (at https://cloud.google.com/iam) permission on the specified +// resource parent: +// +// cloudtasks.queues.getIamPolicy +func (c *Client) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", req.GetResource())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.GetIamPolicy[0:len(c.CallOptions.GetIamPolicy):len(c.CallOptions.GetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetIamPolicy sets the access control policy for a [Queue][google.cloud.tasks.v2beta3.Queue]. Replaces any existing +// policy. +// +// Note: The Cloud Console does not check queue-level IAM permissions yet. +// Project-level permissions are required to use the Cloud Console. +// +// Authorization requires the following +// Google IAM (at https://cloud.google.com/iam) permission on the specified +// resource parent: +// +// cloudtasks.queues.setIamPolicy +func (c *Client) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", req.GetResource())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.SetIamPolicy[0:len(c.CallOptions.SetIamPolicy):len(c.CallOptions.SetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.SetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// TestIamPermissions returns permissions that a caller has on a [Queue][google.cloud.tasks.v2beta3.Queue]. +// If the resource does not exist, this will return an empty set of +// permissions, not a [NOT_FOUND][google.rpc.Code.NOT_FOUND] error. +// +// Note: This operation is designed to be used for building permission-aware +// UIs and command-line tools, not for authorization checking. This operation +// may "fail open" without warning. +func (c *Client) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "resource", req.GetResource())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.TestIamPermissions[0:len(c.CallOptions.TestIamPermissions):len(c.CallOptions.TestIamPermissions)], opts...) + var resp *iampb.TestIamPermissionsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.TestIamPermissions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListTasks lists the tasks in a queue. +// +// By default, only the [BASIC][google.cloud.tasks.v2beta3.Task.View.BASIC] view is retrieved +// due to performance considerations; +// [response_view][google.cloud.tasks.v2beta3.ListTasksRequest.response_view] controls the +// subset of information which is returned. +// +// The tasks may be returned in any order. The ordering may change at any +// time. +func (c *Client) ListTasks(ctx context.Context, req *taskspb.ListTasksRequest, opts ...gax.CallOption) *TaskIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ListTasks[0:len(c.CallOptions.ListTasks):len(c.CallOptions.ListTasks)], opts...) + it := &TaskIterator{} + req = proto.Clone(req).(*taskspb.ListTasksRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*taskspb.Task, string, error) { + var resp *taskspb.ListTasksResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListTasks(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Tasks, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetTask gets a task. +func (c *Client) GetTask(ctx context.Context, req *taskspb.GetTaskRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.GetTask[0:len(c.CallOptions.GetTask):len(c.CallOptions.GetTask)], opts...) + var resp *taskspb.Task + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetTask(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateTask creates a task and adds it to a queue. +// +// Tasks cannot be updated after creation; there is no UpdateTask command. +// +// For [App Engine queues][google.cloud.tasks.v2beta3.AppEngineHttpQueue], the maximum task size is +// 100KB. +func (c *Client) CreateTask(ctx context.Context, req *taskspb.CreateTaskRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.CreateTask[0:len(c.CallOptions.CreateTask):len(c.CallOptions.CreateTask)], opts...) + var resp *taskspb.Task + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateTask(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteTask deletes a task. +// +// A task can be deleted if it is scheduled or dispatched. A task +// cannot be deleted if it has executed successfully or permanently +// failed. +func (c *Client) DeleteTask(ctx context.Context, req *taskspb.DeleteTaskRequest, opts ...gax.CallOption) error { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.DeleteTask[0:len(c.CallOptions.DeleteTask):len(c.CallOptions.DeleteTask)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteTask(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// RunTask forces a task to run now. +// +// When this method is called, Cloud Tasks will dispatch the task, even if +// the task is already running, the queue has reached its [RateLimits][google.cloud.tasks.v2beta3.RateLimits] or +// is [PAUSED][google.cloud.tasks.v2beta3.Queue.State.PAUSED]. +// +// This command is meant to be used for manual debugging. For +// example, [RunTask][google.cloud.tasks.v2beta3.CloudTasks.RunTask] can be used to retry a failed +// task after a fix has been made or to manually force a task to be +// dispatched now. +// +// The dispatched task is returned. That is, the task that is returned +// contains the [status][Task.status] after the task is dispatched but +// before the task is received by its target. +// +// If Cloud Tasks receives a successful response from the task's +// target, then the task will be deleted; otherwise the task's +// [schedule_time][google.cloud.tasks.v2beta3.Task.schedule_time] will be reset to the time that +// [RunTask][google.cloud.tasks.v2beta3.CloudTasks.RunTask] was called plus the retry delay specified +// in the queue's [RetryConfig][google.cloud.tasks.v2beta3.RetryConfig]. +// +// [RunTask][google.cloud.tasks.v2beta3.CloudTasks.RunTask] returns +// [NOT_FOUND][google.rpc.Code.NOT_FOUND] when it is called on a +// task that has already succeeded or permanently failed. +func (c *Client) RunTask(ctx context.Context, req *taskspb.RunTaskRequest, opts ...gax.CallOption) (*taskspb.Task, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.RunTask[0:len(c.CallOptions.RunTask):len(c.CallOptions.RunTask)], opts...) + var resp *taskspb.Task + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.RunTask(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// QueueIterator manages a stream of *taskspb.Queue. +type QueueIterator struct { + items []*taskspb.Queue + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*taskspb.Queue, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *QueueIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *QueueIterator) Next() (*taskspb.Queue, error) { + var item *taskspb.Queue + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *QueueIterator) bufLen() int { + return len(it.items) +} + +func (it *QueueIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// TaskIterator manages a stream of *taskspb.Task. +type TaskIterator struct { + items []*taskspb.Task + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*taskspb.Task, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TaskIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TaskIterator) Next() (*taskspb.Task, error) { + var item *taskspb.Task + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TaskIterator) bufLen() int { + return len(it.items) +} + +func (it *TaskIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/cloudtasks/apiv2beta3/cloud_tasks_client_example_test.go b/vendor/cloud.google.com/go/cloudtasks/apiv2beta3/cloud_tasks_client_example_test.go new file mode 100644 index 00000000..477cba25 --- /dev/null +++ b/vendor/cloud.google.com/go/cloudtasks/apiv2beta3/cloud_tasks_client_example_test.go @@ -0,0 +1,332 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package cloudtasks_test + +import ( + "context" + + cloudtasks "cloud.google.com/go/cloudtasks/apiv2beta3" + "google.golang.org/api/iterator" + taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2beta3" + iampb "google.golang.org/genproto/googleapis/iam/v1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_ListQueues() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.ListQueuesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListQueues(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_GetQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.GetQueueRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_CreateQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.CreateQueueRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_UpdateQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.UpdateQueueRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_DeleteQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.DeleteQueueRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_PurgeQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.PurgeQueueRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.PurgeQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_PauseQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.PauseQueueRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.PauseQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ResumeQueue() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.ResumeQueueRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ResumeQueue(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_GetIamPolicy() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.GetIamPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetIamPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_SetIamPolicy() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.SetIamPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetIamPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_TestIamPermissions() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.TestIamPermissionsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.TestIamPermissions(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ListTasks() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.ListTasksRequest{ + // TODO: Fill request struct fields. + } + it := c.ListTasks(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_GetTask() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.GetTaskRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetTask(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_CreateTask() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.CreateTaskRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateTask(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_DeleteTask() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.DeleteTaskRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteTask(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_RunTask() { + ctx := context.Background() + c, err := cloudtasks.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &taskspb.RunTaskRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.RunTask(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/cloudtasks/apiv2beta3/doc.go b/vendor/cloud.google.com/go/cloudtasks/apiv2beta3/doc.go new file mode 100644 index 00000000..d0a6f7b5 --- /dev/null +++ b/vendor/cloud.google.com/go/cloudtasks/apiv2beta3/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package cloudtasks is an auto-generated package for the +// Cloud Tasks API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Manages the execution of large numbers of distributed requests. +package cloudtasks // import "cloud.google.com/go/cloudtasks/apiv2beta3" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/cloudtasks/apiv2beta3/mock_test.go b/vendor/cloud.google.com/go/cloudtasks/apiv2beta3/mock_test.go new file mode 100644 index 00000000..f7d747ff --- /dev/null +++ b/vendor/cloud.google.com/go/cloudtasks/apiv2beta3/mock_test.go @@ -0,0 +1,1270 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package cloudtasks + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2beta3" + iampb "google.golang.org/genproto/googleapis/iam/v1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockCloudTasksServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + taskspb.CloudTasksServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockCloudTasksServer) ListQueues(ctx context.Context, req *taskspb.ListQueuesRequest) (*taskspb.ListQueuesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.ListQueuesResponse), nil +} + +func (s *mockCloudTasksServer) GetQueue(ctx context.Context, req *taskspb.GetQueueRequest) (*taskspb.Queue, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Queue), nil +} + +func (s *mockCloudTasksServer) CreateQueue(ctx context.Context, req *taskspb.CreateQueueRequest) (*taskspb.Queue, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Queue), nil +} + +func (s *mockCloudTasksServer) UpdateQueue(ctx context.Context, req *taskspb.UpdateQueueRequest) (*taskspb.Queue, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Queue), nil +} + +func (s *mockCloudTasksServer) DeleteQueue(ctx context.Context, req *taskspb.DeleteQueueRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockCloudTasksServer) PurgeQueue(ctx context.Context, req *taskspb.PurgeQueueRequest) (*taskspb.Queue, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Queue), nil +} + +func (s *mockCloudTasksServer) PauseQueue(ctx context.Context, req *taskspb.PauseQueueRequest) (*taskspb.Queue, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Queue), nil +} + +func (s *mockCloudTasksServer) ResumeQueue(ctx context.Context, req *taskspb.ResumeQueueRequest) (*taskspb.Queue, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Queue), nil +} + +func (s *mockCloudTasksServer) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockCloudTasksServer) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockCloudTasksServer) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest) (*iampb.TestIamPermissionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.TestIamPermissionsResponse), nil +} + +func (s *mockCloudTasksServer) ListTasks(ctx context.Context, req *taskspb.ListTasksRequest) (*taskspb.ListTasksResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.ListTasksResponse), nil +} + +func (s *mockCloudTasksServer) GetTask(ctx context.Context, req *taskspb.GetTaskRequest) (*taskspb.Task, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Task), nil +} + +func (s *mockCloudTasksServer) CreateTask(ctx context.Context, req *taskspb.CreateTaskRequest) (*taskspb.Task, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Task), nil +} + +func (s *mockCloudTasksServer) DeleteTask(ctx context.Context, req *taskspb.DeleteTaskRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockCloudTasksServer) RunTask(ctx context.Context, req *taskspb.RunTaskRequest) (*taskspb.Task, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*taskspb.Task), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockCloudTasks mockCloudTasksServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + taskspb.RegisterCloudTasksServer(serv, &mockCloudTasks) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestCloudTasksListQueues(t *testing.T) { + var nextPageToken string = "" + var queuesElement *taskspb.Queue = &taskspb.Queue{} + var queues = []*taskspb.Queue{queuesElement} + var expectedResponse = &taskspb.ListQueuesResponse{ + NextPageToken: nextPageToken, + Queues: queues, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &taskspb.ListQueuesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListQueues(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Queues[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksListQueuesError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &taskspb.ListQueuesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListQueues(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksGetQueue(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &taskspb.Queue{ + Name: name2, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.GetQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksGetQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.GetQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksCreateQueue(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &taskspb.Queue{ + Name: name, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var queue *taskspb.Queue = &taskspb.Queue{} + var request = &taskspb.CreateQueueRequest{ + Parent: formattedParent, + Queue: queue, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksCreateQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var queue *taskspb.Queue = &taskspb.Queue{} + var request = &taskspb.CreateQueueRequest{ + Parent: formattedParent, + Queue: queue, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksUpdateQueue(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &taskspb.Queue{ + Name: name, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var queue *taskspb.Queue = &taskspb.Queue{} + var request = &taskspb.UpdateQueueRequest{ + Queue: queue, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksUpdateQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var queue *taskspb.Queue = &taskspb.Queue{} + var request = &taskspb.UpdateQueueRequest{ + Queue: queue, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksDeleteQueue(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.DeleteQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestCloudTasksDeleteQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.DeleteQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestCloudTasksPurgeQueue(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &taskspb.Queue{ + Name: name2, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.PurgeQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PurgeQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksPurgeQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.PurgeQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PurgeQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksPauseQueue(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &taskspb.Queue{ + Name: name2, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.PauseQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PauseQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksPauseQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.PauseQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PauseQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksResumeQueue(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &taskspb.Queue{ + Name: name2, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.ResumeQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ResumeQueue(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksResumeQueueError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.ResumeQueueRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ResumeQueue(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksGetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksGetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksSetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksSetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksTestIamPermissions(t *testing.T) { + var expectedResponse *iampb.TestIamPermissionsResponse = &iampb.TestIamPermissionsResponse{} + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksTestIamPermissionsError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksListTasks(t *testing.T) { + var nextPageToken string = "" + var tasksElement *taskspb.Task = &taskspb.Task{} + var tasks = []*taskspb.Task{tasksElement} + var expectedResponse = &taskspb.ListTasksResponse{ + NextPageToken: nextPageToken, + Tasks: tasks, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.ListTasksRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTasks(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Tasks[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksListTasksError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var request = &taskspb.ListTasksRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTasks(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksGetTask(t *testing.T) { + var name2 string = "name2-1052831874" + var dispatchCount int32 = 1217252086 + var responseCount int32 = 424727441 + var expectedResponse = &taskspb.Task{ + Name: name2, + DispatchCount: dispatchCount, + ResponseCount: responseCount, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var request = &taskspb.GetTaskRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetTask(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksGetTaskError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var request = &taskspb.GetTaskRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetTask(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksCreateTask(t *testing.T) { + var name string = "name3373707" + var dispatchCount int32 = 1217252086 + var responseCount int32 = 424727441 + var expectedResponse = &taskspb.Task{ + Name: name, + DispatchCount: dispatchCount, + ResponseCount: responseCount, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var task *taskspb.Task = &taskspb.Task{} + var request = &taskspb.CreateTaskRequest{ + Parent: formattedParent, + Task: task, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateTask(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksCreateTaskError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/queues/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]") + var task *taskspb.Task = &taskspb.Task{} + var request = &taskspb.CreateTaskRequest{ + Parent: formattedParent, + Task: task, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateTask(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudTasksDeleteTask(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var request = &taskspb.DeleteTaskRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteTask(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestCloudTasksDeleteTaskError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var request = &taskspb.DeleteTaskRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteTask(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestCloudTasksRunTask(t *testing.T) { + var name2 string = "name2-1052831874" + var dispatchCount int32 = 1217252086 + var responseCount int32 = 424727441 + var expectedResponse = &taskspb.Task{ + Name: name2, + DispatchCount: dispatchCount, + ResponseCount: responseCount, + } + + mockCloudTasks.err = nil + mockCloudTasks.reqs = nil + + mockCloudTasks.resps = append(mockCloudTasks.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var request = &taskspb.RunTaskRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RunTask(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudTasks.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudTasksRunTaskError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudTasks.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/queues/%s/tasks/%s", "[PROJECT]", "[LOCATION]", "[QUEUE]", "[TASK]") + var request = &taskspb.RunTaskRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RunTask(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/debuglet.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/debuglet.go new file mode 100644 index 00000000..b5852b6f --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/debuglet.go @@ -0,0 +1,450 @@ +// Copyright 2016 Google LLC +// +// 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. + +// +build linux,go1.7 + +package main + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "log" + "math/rand" + "os" + "sync" + "time" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints" + debuglet "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/local" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector" + "cloud.google.com/go/compute/metadata" + "golang.org/x/oauth2" + "golang.org/x/oauth2/google" + cd "google.golang.org/api/clouddebugger/v2" +) + +var ( + appModule = flag.String("appmodule", "", "Optional application module name.") + appVersion = flag.String("appversion", "", "Optional application module version name.") + sourceContextFile = flag.String("sourcecontext", "", "File containing JSON-encoded source context.") + verbose = flag.Bool("v", false, "Output verbose log messages.") + projectNumber = flag.String("projectnumber", "", "Project number."+ + " If this is not set, it is read from the GCP metadata server.") + projectID = flag.String("projectid", "", "Project ID."+ + " If this is not set, it is read from the GCP metadata server.") + serviceAccountFile = flag.String("serviceaccountfile", "", "File containing JSON service account credentials.") +) + +const ( + maxCapturedStackFrames = 50 + maxCapturedVariables = 1000 +) + +func main() { + flag.Usage = usage + flag.Parse() + args := flag.Args() + if len(args) == 0 { + // The user needs to supply the name of the executable to run. + flag.Usage() + return + } + if *projectNumber == "" { + var err error + *projectNumber, err = metadata.NumericProjectID() + if err != nil { + log.Print("Debuglet initialization: ", err) + } + } + if *projectID == "" { + var err error + *projectID, err = metadata.ProjectID() + if err != nil { + log.Print("Debuglet initialization: ", err) + } + } + sourceContexts, err := readSourceContextFile(*sourceContextFile) + if err != nil { + log.Print("Reading source context file: ", err) + } + var ts oauth2.TokenSource + ctx := context.Background() + if *serviceAccountFile != "" { + if ts, err = serviceAcctTokenSource(ctx, *serviceAccountFile, cd.CloudDebuggerScope); err != nil { + log.Fatalf("Error getting credentials from file %s: %v", *serviceAccountFile, err) + } + } else if ts, err = google.DefaultTokenSource(ctx, cd.CloudDebuggerScope); err != nil { + log.Print("Error getting application default credentials for Cloud Debugger:", err) + os.Exit(103) + } + c, err := debuglet.NewController(ctx, debuglet.Options{ + ProjectNumber: *projectNumber, + ProjectID: *projectID, + AppModule: *appModule, + AppVersion: *appVersion, + SourceContexts: sourceContexts, + Verbose: *verbose, + TokenSource: ts, + }) + if err != nil { + log.Fatal("Error connecting to Cloud Debugger: ", err) + } + prog, err := local.New(args[0]) + if err != nil { + log.Fatal("Error loading program: ", err) + } + // Load the program, but don't actually start it running yet. + if _, err = prog.Run(args[1:]...); err != nil { + log.Fatal("Error loading program: ", err) + } + bs := breakpoints.NewBreakpointStore(prog) + + // Seed the random number generator. + rand.Seed(time.Now().UnixNano()) + + // Now we want to do two things: run the user's program, and start sending + // List requests periodically to the Debuglet Controller to get breakpoints + // to set. + // + // We want to give the Debuglet Controller a chance to give us breakpoints + // before we start the program, otherwise we would miss any breakpoint + // triggers that occur during program startup -- for example, a breakpoint on + // the first line of main. But if the Debuglet Controller is not responding or + // is returning errors, we don't want to delay starting the program + // indefinitely. + // + // We pass a channel to breakpointListLoop, which will close it when the first + // List call finishes. Then we wait until either the channel is closed or a + // 5-second timer has finished before starting the program. + ch := make(chan bool) + // Start a goroutine that sends List requests to the Debuglet Controller, and + // sets any breakpoints it gets back. + go breakpointListLoop(ctx, c, bs, ch) + // Wait until 5 seconds have passed or breakpointListLoop has closed ch. + select { + case <-time.After(5 * time.Second): + case <-ch: + } + // Run the debuggee. + programLoop(ctx, c, bs, prog) +} + +// usage prints a usage message to stderr and exits. +func usage() { + me := "a.out" + if len(os.Args) >= 1 { + me = os.Args[0] + } + fmt.Fprintf(os.Stderr, "Usage of %s:\n", me) + fmt.Fprintf(os.Stderr, "\t%s [flags...] -- args...\n", me) + fmt.Fprintf(os.Stderr, "Flags:\n") + flag.PrintDefaults() + fmt.Fprintf(os.Stderr, + "See https://cloud.google.com/tools/cloud-debugger/setting-up-on-compute-engine for more information.\n") + os.Exit(2) +} + +// readSourceContextFile reads a JSON-encoded source context from the given file. +// It returns a non-empty slice on success. +func readSourceContextFile(filename string) ([]*cd.SourceContext, error) { + if filename == "" { + return nil, nil + } + scJSON, err := ioutil.ReadFile(filename) + if err != nil { + return nil, fmt.Errorf("reading file %q: %v", filename, err) + } + var sc cd.SourceContext + if err = json.Unmarshal(scJSON, &sc); err != nil { + return nil, fmt.Errorf("parsing file %q: %v", filename, err) + } + return []*cd.SourceContext{&sc}, nil +} + +// breakpointListLoop repeatedly calls the Debuglet Controller's List RPC, and +// passes the results to the BreakpointStore so it can set and unset breakpoints +// in the program. +// +// After the first List call finishes, ch is closed. +func breakpointListLoop(ctx context.Context, c *debuglet.Controller, bs *breakpoints.BreakpointStore, first chan bool) { + const ( + avgTimeBetweenCalls = time.Second + errorDelay = 5 * time.Second + ) + + // randomDuration returns a random duration with expected value avg. + randomDuration := func(avg time.Duration) time.Duration { + return time.Duration(rand.Int63n(int64(2*avg + 1))) + } + + var consecutiveFailures uint + + for { + callStart := time.Now() + resp, err := c.List(ctx) + if err != nil && err != debuglet.ErrListUnchanged { + log.Printf("Debuglet controller server error: %v", err) + } + if err == nil { + bs.ProcessBreakpointList(resp.Breakpoints) + } + + if first != nil { + // We've finished one call to List and set any breakpoints we received. + close(first) + first = nil + } + + // Asynchronously send updates for any breakpoints that caused an error when + // the BreakpointStore tried to process them. We don't wait for the update + // to finish before the program can exit, as we do for normal updates. + errorBps := bs.ErrorBreakpoints() + for _, bp := range errorBps { + go func(bp *cd.Breakpoint) { + if err := c.Update(ctx, bp.Id, bp); err != nil { + log.Printf("Failed to send breakpoint update for %s: %s", bp.Id, err) + } + }(bp) + } + + // Make the next call not too soon after the one we just did. + delay := randomDuration(avgTimeBetweenCalls) + + // If the call returned an error other than ErrListUnchanged, wait longer. + if err != nil && err != debuglet.ErrListUnchanged { + // Wait twice as long after each consecutive failure, to a maximum of 16x. + delay += randomDuration(errorDelay * (1 << consecutiveFailures)) + if consecutiveFailures < 4 { + consecutiveFailures++ + } + } else { + consecutiveFailures = 0 + } + + // Sleep until we reach time callStart+delay. If we've already passed that + // time, time.Sleep will return immediately -- this should be the common + // case, since the server will delay responding to List for a while when + // there are no changes to report. + time.Sleep(callStart.Add(delay).Sub(time.Now())) + } +} + +// programLoop runs the program being debugged to completion. When a breakpoint's +// conditions are satisfied, it sends an Update RPC to the Debuglet Controller. +// The function returns when the program exits and all Update RPCs have finished. +func programLoop(ctx context.Context, c *debuglet.Controller, bs *breakpoints.BreakpointStore, prog debug.Program) { + var wg sync.WaitGroup + for { + // Run the program until it hits a breakpoint or exits. + status, err := prog.Resume() + if err != nil { + break + } + + // Get the breakpoints at this address whose conditions were satisfied, + // and remove the ones that aren't logpoints. + bps := bs.BreakpointsAtPC(status.PC) + bps = bpsWithConditionSatisfied(bps, prog) + for _, bp := range bps { + if bp.Action != "LOG" { + bs.RemoveBreakpoint(bp) + } + } + + if len(bps) == 0 { + continue + } + + // Evaluate expressions and get the stack. + vc := valuecollector.NewCollector(prog, maxCapturedVariables) + needStackFrames := false + for _, bp := range bps { + // If evaluating bp's condition didn't return an error, evaluate bp's + // expressions, and later get the stack frames. + if bp.Status == nil { + bp.EvaluatedExpressions = expressionValues(bp.Expressions, prog, vc) + needStackFrames = true + } + } + var ( + stack []*cd.StackFrame + stackFramesStatusMessage *cd.StatusMessage + ) + if needStackFrames { + stack, stackFramesStatusMessage = stackFrames(prog, vc) + } + + // Read variable values from the program. + variableTable := vc.ReadValues() + + // Start a goroutine to send updates to the Debuglet Controller or write + // to logs, concurrently with resuming the program. + // TODO: retry Update on failure. + for _, bp := range bps { + wg.Add(1) + switch bp.Action { + case "LOG": + go func(format string, evaluatedExpressions []*cd.Variable) { + s := valuecollector.LogString(format, evaluatedExpressions, variableTable) + log.Print(s) + wg.Done() + }(bp.LogMessageFormat, bp.EvaluatedExpressions) + bp.Status = nil + bp.EvaluatedExpressions = nil + default: + go func(bp *cd.Breakpoint) { + defer wg.Done() + bp.IsFinalState = true + if bp.Status == nil { + // If evaluating bp's condition didn't return an error, include the + // stack frames, variable table, and any status message produced when + // getting the stack frames. + bp.StackFrames = stack + bp.VariableTable = variableTable + bp.Status = stackFramesStatusMessage + } + if err := c.Update(ctx, bp.Id, bp); err != nil { + log.Printf("Failed to send breakpoint update for %s: %s", bp.Id, err) + } + }(bp) + } + } + } + + // Wait for all updates to finish before returning. + wg.Wait() +} + +// bpsWithConditionSatisfied returns the breakpoints whose conditions are true +// (or that do not have a condition.) +func bpsWithConditionSatisfied(bpsIn []*cd.Breakpoint, prog debug.Program) []*cd.Breakpoint { + var bpsOut []*cd.Breakpoint + for _, bp := range bpsIn { + cond, err := condTruth(bp.Condition, prog) + if err != nil { + bp.Status = errorStatusMessage(err.Error(), refersToBreakpointCondition) + // Include bp in the list to be updated when there's an error, so that + // the user gets a response. + bpsOut = append(bpsOut, bp) + } else if cond { + bpsOut = append(bpsOut, bp) + } + } + return bpsOut +} + +// condTruth evaluates a condition. +func condTruth(condition string, prog debug.Program) (bool, error) { + if condition == "" { + // A condition wasn't set. + return true, nil + } + val, err := prog.Evaluate(condition) + if err != nil { + return false, err + } + if v, ok := val.(bool); !ok { + return false, fmt.Errorf("condition expression has type %T, should be bool", val) + } else { + return v, nil + } +} + +// expressionValues evaluates a slice of expressions and returns a []*cd.Variable +// containing the results. +// If the result of an expression evaluation refers to values from the program's +// memory (e.g., the expression evaluates to a slice) a corresponding variable is +// added to the value collector, to be read later. +func expressionValues(expressions []string, prog debug.Program, vc *valuecollector.Collector) []*cd.Variable { + evaluatedExpressions := make([]*cd.Variable, len(expressions)) + for i, exp := range expressions { + ee := &cd.Variable{Name: exp} + evaluatedExpressions[i] = ee + if val, err := prog.Evaluate(exp); err != nil { + ee.Status = errorStatusMessage(err.Error(), refersToBreakpointExpression) + } else { + vc.FillValue(val, ee) + } + } + return evaluatedExpressions +} + +// stackFrames returns a stack trace for the program. It passes references to +// function parameters and local variables to the value collector, so it can read +// their values later. +func stackFrames(prog debug.Program, vc *valuecollector.Collector) ([]*cd.StackFrame, *cd.StatusMessage) { + frames, err := prog.Frames(maxCapturedStackFrames) + if err != nil { + return nil, errorStatusMessage("Error getting stack: "+err.Error(), refersToUnspecified) + } + stackFrames := make([]*cd.StackFrame, len(frames)) + for i, f := range frames { + frame := &cd.StackFrame{} + frame.Function = f.Function + for _, v := range f.Params { + frame.Arguments = append(frame.Arguments, vc.AddVariable(debug.LocalVar(v))) + } + for _, v := range f.Vars { + frame.Locals = append(frame.Locals, vc.AddVariable(v)) + } + frame.Location = &cd.SourceLocation{ + Path: f.File, + Line: int64(f.Line), + } + stackFrames[i] = frame + } + return stackFrames, nil +} + +// errorStatusMessage returns a *cd.StatusMessage indicating an error, +// with the given message and refersTo field. +func errorStatusMessage(msg string, refersTo int) *cd.StatusMessage { + return &cd.StatusMessage{ + Description: &cd.FormatMessage{Format: "$0", Parameters: []string{msg}}, + IsError: true, + RefersTo: refersToString[refersTo], + } +} + +const ( + // RefersTo values for cd.StatusMessage. + refersToUnspecified = iota + refersToBreakpointCondition + refersToBreakpointExpression +) + +// refersToString contains the strings for each refersTo value. +// See the definition of StatusMessage in the v2/clouddebugger package. +var refersToString = map[int]string{ + refersToUnspecified: "UNSPECIFIED", + refersToBreakpointCondition: "BREAKPOINT_CONDITION", + refersToBreakpointExpression: "BREAKPOINT_EXPRESSION", +} + +func serviceAcctTokenSource(ctx context.Context, filename string, scope ...string) (oauth2.TokenSource, error) { + data, err := ioutil.ReadFile(filename) + if err != nil { + return nil, fmt.Errorf("cannot read service account file: %v", err) + } + cfg, err := google.JWTConfigFromJSON(data, scope...) + if err != nil { + return nil, fmt.Errorf("google.JWTConfigFromJSON: %v", err) + } + return cfg.TokenSource(ctx), nil +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints.go new file mode 100644 index 00000000..351def95 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints.go @@ -0,0 +1,174 @@ +// Copyright 2016 Google LLC +// +// 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 breakpoints handles breakpoint requests we get from the user through +// the Debuglet Controller, and manages corresponding breakpoints set in the code. +package breakpoints + +import ( + "log" + "sync" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" + cd "google.golang.org/api/clouddebugger/v2" +) + +// BreakpointStore stores the set of breakpoints for a program. +type BreakpointStore struct { + mu sync.Mutex + // prog is the program being debugged. + prog debug.Program + // idToBreakpoint is a map from breakpoint identifier to *cd.Breakpoint. The + // map value is nil if the breakpoint is inactive. A breakpoint is active if: + // - We received it from the Debuglet Controller, and it was active at the time; + // - We were able to set code breakpoints for it; + // - We have not reached any of those code breakpoints while satisfying the + // breakpoint's conditions, or the breakpoint has action LOG; and + // - The Debuglet Controller hasn't informed us the breakpoint has become inactive. + idToBreakpoint map[string]*cd.Breakpoint + // pcToBps and bpToPCs store the many-to-many relationship between breakpoints we + // received from the Debuglet Controller and the code breakpoints we set for them. + pcToBps map[uint64][]*cd.Breakpoint + bpToPCs map[*cd.Breakpoint][]uint64 + // errors contains any breakpoints which couldn't be set because they caused an + // error. These are retrieved with ErrorBreakpoints, and the caller is + // expected to handle sending updates for them. + errors []*cd.Breakpoint +} + +// NewBreakpointStore returns a BreakpointStore for the given program. +func NewBreakpointStore(prog debug.Program) *BreakpointStore { + return &BreakpointStore{ + idToBreakpoint: make(map[string]*cd.Breakpoint), + pcToBps: make(map[uint64][]*cd.Breakpoint), + bpToPCs: make(map[*cd.Breakpoint][]uint64), + prog: prog, + } +} + +// ProcessBreakpointList applies updates received from the Debuglet Controller through a List call. +func (bs *BreakpointStore) ProcessBreakpointList(bps []*cd.Breakpoint) { + bs.mu.Lock() + defer bs.mu.Unlock() + for _, bp := range bps { + if storedBp, ok := bs.idToBreakpoint[bp.Id]; ok { + if storedBp != nil && bp.IsFinalState { + // IsFinalState indicates that the breakpoint has been made inactive. + bs.removeBreakpointLocked(storedBp) + } + } else { + if bp.IsFinalState { + // The controller is notifying us that the breakpoint is no longer active, + // but we didn't know about it anyway. + continue + } + if bp.Action != "" && bp.Action != "CAPTURE" && bp.Action != "LOG" { + bp.IsFinalState = true + bp.Status = &cd.StatusMessage{ + Description: &cd.FormatMessage{Format: "Action is not supported"}, + IsError: true, + } + bs.errors = append(bs.errors, bp) + // Note in idToBreakpoint that we've already seen this breakpoint, so that we + // don't try to report it as an error multiple times. + bs.idToBreakpoint[bp.Id] = nil + continue + } + pcs, err := bs.prog.BreakpointAtLine(bp.Location.Path, uint64(bp.Location.Line)) + if err != nil { + log.Printf("error setting breakpoint at %s:%d: %v", bp.Location.Path, bp.Location.Line, err) + } + if len(pcs) == 0 { + // We can't find a PC for this breakpoint's source line, so don't make it active. + // TODO: we could snap the line to a location where we can break, or report an error to the user. + bs.idToBreakpoint[bp.Id] = nil + } else { + bs.idToBreakpoint[bp.Id] = bp + for _, pc := range pcs { + bs.pcToBps[pc] = append(bs.pcToBps[pc], bp) + } + bs.bpToPCs[bp] = pcs + } + } + } +} + +// ErrorBreakpoints returns a slice of Breakpoints that caused errors when the +// BreakpointStore tried to process them, and resets the list of such +// breakpoints. +// The caller is expected to send updates to the server to indicate the errors. +func (bs *BreakpointStore) ErrorBreakpoints() []*cd.Breakpoint { + bs.mu.Lock() + defer bs.mu.Unlock() + bps := bs.errors + bs.errors = nil + return bps +} + +// BreakpointsAtPC returns all the breakpoints for which we set a code +// breakpoint at the given address. +func (bs *BreakpointStore) BreakpointsAtPC(pc uint64) []*cd.Breakpoint { + bs.mu.Lock() + defer bs.mu.Unlock() + return bs.pcToBps[pc] +} + +// RemoveBreakpoint makes the given breakpoint inactive. +// This is called when either the debugged program hits the breakpoint, or the Debuglet +// Controller informs us that the breakpoint is now inactive. +func (bs *BreakpointStore) RemoveBreakpoint(bp *cd.Breakpoint) { + bs.mu.Lock() + bs.removeBreakpointLocked(bp) + bs.mu.Unlock() +} + +func (bs *BreakpointStore) removeBreakpointLocked(bp *cd.Breakpoint) { + // Set the ID's corresponding breakpoint to nil, so that we won't activate it + // if we see it again. + // TODO: we could delete it after a few seconds. + bs.idToBreakpoint[bp.Id] = nil + + // Delete bp from the list of cd breakpoints at each of its corresponding + // code breakpoint locations, and delete any code breakpoints which no longer + // have a corresponding cd breakpoint. + var codeBreakpointsToDelete []uint64 + for _, pc := range bs.bpToPCs[bp] { + bps := remove(bs.pcToBps[pc], bp) + if len(bps) == 0 { + // bp was the last breakpoint set at this PC, so delete the code breakpoint. + codeBreakpointsToDelete = append(codeBreakpointsToDelete, pc) + delete(bs.pcToBps, pc) + } else { + bs.pcToBps[pc] = bps + } + } + if len(codeBreakpointsToDelete) > 0 { + bs.prog.DeleteBreakpoints(codeBreakpointsToDelete) + } + delete(bs.bpToPCs, bp) +} + +// remove updates rs by removing r, then returns rs. +// The mutex in the BreakpointStore which contains rs should be held. +func remove(rs []*cd.Breakpoint, r *cd.Breakpoint) []*cd.Breakpoint { + for i := range rs { + if rs[i] == r { + rs[i] = rs[len(rs)-1] + rs = rs[0 : len(rs)-1] + return rs + } + } + // We shouldn't reach here. + return rs +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints_test.go new file mode 100644 index 00000000..54ef3839 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/breakpoints/breakpoints_test.go @@ -0,0 +1,168 @@ +// Copyright 2016 Google LLC +// +// 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 breakpoints + +import ( + "testing" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" + "cloud.google.com/go/internal/testutil" + cd "google.golang.org/api/clouddebugger/v2" +) + +var ( + testPC1 uint64 = 0x1234 + testPC2 uint64 = 0x5678 + testPC3 uint64 = 0x3333 + testFile = "foo.go" + testLine uint64 = 42 + testLine2 uint64 = 99 + testLogPC uint64 = 0x9abc + testLogLine uint64 = 43 + testBadPC uint64 = 0xdef0 + testBadLine uint64 = 44 + testBP = &cd.Breakpoint{ + Action: "CAPTURE", + Id: "TestBreakpoint", + IsFinalState: false, + Location: &cd.SourceLocation{Path: testFile, Line: int64(testLine)}, + } + testBP2 = &cd.Breakpoint{ + Action: "CAPTURE", + Id: "TestBreakpoint2", + IsFinalState: false, + Location: &cd.SourceLocation{Path: testFile, Line: int64(testLine2)}, + } + testLogBP = &cd.Breakpoint{ + Action: "LOG", + Id: "TestLogBreakpoint", + IsFinalState: false, + Location: &cd.SourceLocation{Path: testFile, Line: int64(testLogLine)}, + } + testBadBP = &cd.Breakpoint{ + Action: "BEEP", + Id: "TestBadBreakpoint", + IsFinalState: false, + Location: &cd.SourceLocation{Path: testFile, Line: int64(testBadLine)}, + } +) + +func TestBreakpointStore(t *testing.T) { + p := &Program{breakpointPCs: make(map[uint64]bool)} + bs := NewBreakpointStore(p) + checkPCs := func(expected map[uint64]bool) { + if !testutil.Equal(p.breakpointPCs, expected) { + t.Errorf("got breakpoint map %v want %v", p.breakpointPCs, expected) + } + } + bs.ProcessBreakpointList([]*cd.Breakpoint{testBP, testBP2, testLogBP, testBadBP}) + checkPCs(map[uint64]bool{ + testPC1: true, + testPC2: true, + testPC3: true, + testLogPC: true, + }) + for _, test := range []struct { + pc uint64 + expected []*cd.Breakpoint + }{ + {testPC1, []*cd.Breakpoint{testBP}}, + {testPC2, []*cd.Breakpoint{testBP}}, + {testPC3, []*cd.Breakpoint{testBP2}}, + {testLogPC, []*cd.Breakpoint{testLogBP}}, + } { + if bps := bs.BreakpointsAtPC(test.pc); !testutil.Equal(bps, test.expected) { + t.Errorf("BreakpointsAtPC(%x): got %v want %v", test.pc, bps, test.expected) + } + } + testBP2.IsFinalState = true + bs.ProcessBreakpointList([]*cd.Breakpoint{testBP, testBP2, testLogBP, testBadBP}) + checkPCs(map[uint64]bool{ + testPC1: true, + testPC2: true, + testPC3: false, + testLogPC: true, + }) + bs.RemoveBreakpoint(testBP) + checkPCs(map[uint64]bool{ + testPC1: false, + testPC2: false, + testPC3: false, + testLogPC: true, + }) + for _, pc := range []uint64{testPC1, testPC2, testPC3} { + if bps := bs.BreakpointsAtPC(pc); len(bps) != 0 { + t.Errorf("BreakpointsAtPC(%x): got %v want []", pc, bps) + } + } + // bs.ErrorBreakpoints should return testBadBP. + errorBps := bs.ErrorBreakpoints() + if len(errorBps) != 1 { + t.Errorf("ErrorBreakpoints: got %d want 1", len(errorBps)) + } else { + bp := errorBps[0] + if bp.Id != testBadBP.Id { + t.Errorf("ErrorBreakpoints: got id %q want 1", bp.Id) + } + if bp.Status == nil || !bp.Status.IsError { + t.Errorf("ErrorBreakpoints: got %v, want error", bp.Status) + } + } + // The error should have been removed by the last call to bs.ErrorBreakpoints. + errorBps = bs.ErrorBreakpoints() + if len(errorBps) != 0 { + t.Errorf("ErrorBreakpoints: got %d want 0", len(errorBps)) + } + // Even if testBadBP is sent in a new list, it should not be returned again. + bs.ProcessBreakpointList([]*cd.Breakpoint{testBadBP}) + errorBps = bs.ErrorBreakpoints() + if len(errorBps) != 0 { + t.Errorf("ErrorBreakpoints: got %d want 0", len(errorBps)) + } +} + +// Program implements the similarly-named interface in x/debug. +// ValueCollector should only call its BreakpointAtLine and DeleteBreakpoints methods. +type Program struct { + debug.Program + // breakpointPCs contains the state of code breakpoints -- true if the + // breakpoint is currently set, false if it has been deleted. + breakpointPCs map[uint64]bool +} + +func (p *Program) BreakpointAtLine(file string, line uint64) ([]uint64, error) { + var pcs []uint64 + switch { + case file == testFile && line == testLine: + pcs = []uint64{testPC1, testPC2} + case file == testFile && line == testLine2: + pcs = []uint64{testPC3} + case file == testFile && line == testLogLine: + pcs = []uint64{testLogPC} + default: + pcs = []uint64{0xbad} + } + for _, pc := range pcs { + p.breakpointPCs[pc] = true + } + return pcs, nil +} + +func (p *Program) DeleteBreakpoints(pcs []uint64) error { + for _, pc := range pcs { + p.breakpointPCs[pc] = false + } + return nil +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client.go new file mode 100644 index 00000000..da5caaf2 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client.go @@ -0,0 +1,291 @@ +// Copyright 2016 Google LLC +// +// 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 controller is a library for interacting with the Google Cloud Debugger's Debuglet Controller service. +package controller + +import ( + "context" + "crypto/sha256" + "encoding/json" + "errors" + "fmt" + "log" + "sync" + + "golang.org/x/oauth2" + cd "google.golang.org/api/clouddebugger/v2" + "google.golang.org/api/googleapi" + "google.golang.org/api/option" + htransport "google.golang.org/api/transport/http" +) + +const ( + // agentVersionString identifies the agent to the service. + agentVersionString = "google.com/go-gcp/v0.2" + // initWaitToken is the wait token sent in the first Update request to a server. + initWaitToken = "init" +) + +var ( + // ErrListUnchanged is returned by List if the server time limit is reached + // before the list of breakpoints changes. + ErrListUnchanged = errors.New("breakpoint list unchanged") + // ErrDebuggeeDisabled is returned by List or Update if the server has disabled + // this Debuggee. The caller can retry later. + ErrDebuggeeDisabled = errors.New("debuglet disabled by server") +) + +// Controller manages a connection to the Debuglet Controller service. +type Controller struct { + s serviceInterface + // waitToken is sent with List requests so the server knows which set of + // breakpoints this client has already seen. Each successful List request + // returns a new waitToken to send in the next request. + waitToken string + // verbose determines whether to do some logging + verbose bool + // options, uniquifier and description are used in register. + options Options + uniquifier string + description string + // labels are included when registering the debuggee. They should contain + // the module name, version and minorversion, and are used by the debug UI + // to label the correct version active for debugging. + labels map[string]string + // mu protects debuggeeID + mu sync.Mutex + // debuggeeID is returned from the server on registration, and is passed back + // to the server in List and Update requests. + debuggeeID string +} + +// Options controls how the Debuglet Controller client identifies itself to the server. +// See https://cloud.google.com/storage/docs/projects and +// https://cloud.google.com/tools/cloud-debugger/setting-up-on-compute-engine +// for further documentation of these parameters. +type Options struct { + ProjectNumber string // GCP Project Number. + ProjectID string // GCP Project ID. + AppModule string // Module name for the debugged program. + AppVersion string // Version number for this module. + SourceContexts []*cd.SourceContext // Description of source. + Verbose bool + TokenSource oauth2.TokenSource // Source of Credentials used for Stackdriver Debugger. +} + +type serviceInterface interface { + Register(ctx context.Context, req *cd.RegisterDebuggeeRequest) (*cd.RegisterDebuggeeResponse, error) + Update(ctx context.Context, debuggeeID, breakpointID string, req *cd.UpdateActiveBreakpointRequest) (*cd.UpdateActiveBreakpointResponse, error) + List(ctx context.Context, debuggeeID, waitToken string) (*cd.ListActiveBreakpointsResponse, error) +} + +var newService = func(ctx context.Context, tokenSource oauth2.TokenSource) (serviceInterface, error) { + httpClient, endpoint, err := htransport.NewClient(ctx, option.WithTokenSource(tokenSource)) + if err != nil { + return nil, err + } + s, err := cd.New(httpClient) + if err != nil { + return nil, err + } + if endpoint != "" { + s.BasePath = endpoint + } + return &service{s: s}, nil +} + +type service struct { + s *cd.Service +} + +func (s service) Register(ctx context.Context, req *cd.RegisterDebuggeeRequest) (*cd.RegisterDebuggeeResponse, error) { + call := cd.NewControllerDebuggeesService(s.s).Register(req) + return call.Context(ctx).Do() +} + +func (s service) Update(ctx context.Context, debuggeeID, breakpointID string, req *cd.UpdateActiveBreakpointRequest) (*cd.UpdateActiveBreakpointResponse, error) { + call := cd.NewControllerDebuggeesBreakpointsService(s.s).Update(debuggeeID, breakpointID, req) + return call.Context(ctx).Do() +} + +func (s service) List(ctx context.Context, debuggeeID, waitToken string) (*cd.ListActiveBreakpointsResponse, error) { + call := cd.NewControllerDebuggeesBreakpointsService(s.s).List(debuggeeID) + call.WaitToken(waitToken) + return call.Context(ctx).Do() +} + +// NewController connects to the Debuglet Controller server using the given options, +// and returns a Controller for that connection. +// Google Application Default Credentials are used to connect to the Debuglet Controller; +// see https://developers.google.com/identity/protocols/application-default-credentials +func NewController(ctx context.Context, o Options) (*Controller, error) { + // We build a JSON encoding of o.SourceContexts so we can hash it. + scJSON, err := json.Marshal(o.SourceContexts) + if err != nil { + scJSON = nil + o.SourceContexts = nil + } + const minorversion = "107157" // any arbitrary numeric string + + // Compute a uniquifier string by hashing the project number, app module name, + // app module version, debuglet version, and source context. + // The choice of hash function is arbitrary. + h := sha256.Sum256([]byte(fmt.Sprintf("%d %s %d %s %d %s %d %s %d %s %d %s", + len(o.ProjectNumber), o.ProjectNumber, + len(o.AppModule), o.AppModule, + len(o.AppVersion), o.AppVersion, + len(agentVersionString), agentVersionString, + len(scJSON), scJSON, + len(minorversion), minorversion))) + uniquifier := fmt.Sprintf("%X", h[0:16]) // 32 hex characters + + description := o.ProjectID + if o.AppModule != "" { + description += "-" + o.AppModule + } + if o.AppVersion != "" { + description += "-" + o.AppVersion + } + + s, err := newService(ctx, o.TokenSource) + if err != nil { + return nil, err + } + + // Construct client. + c := &Controller{ + s: s, + waitToken: initWaitToken, + verbose: o.Verbose, + options: o, + uniquifier: uniquifier, + description: description, + labels: map[string]string{ + "module": o.AppModule, + "version": o.AppVersion, + "minorversion": minorversion, + }, + } + + return c, nil +} + +func (c *Controller) getDebuggeeID(ctx context.Context) (string, error) { + c.mu.Lock() + defer c.mu.Unlock() + if c.debuggeeID != "" { + return c.debuggeeID, nil + } + // The debuglet hasn't been registered yet, or it is disabled and we should try registering again. + if err := c.register(ctx); err != nil { + return "", err + } + return c.debuggeeID, nil +} + +// List retrieves the current list of breakpoints from the server. +// If the set of breakpoints on the server is the same as the one returned in +// the previous call to List, the server can delay responding until it changes, +// and return an error instead if no change occurs before a time limit the +// server sets. List can't be called concurrently with itself. +func (c *Controller) List(ctx context.Context) (*cd.ListActiveBreakpointsResponse, error) { + id, err := c.getDebuggeeID(ctx) + if err != nil { + return nil, err + } + resp, err := c.s.List(ctx, id, c.waitToken) + if err != nil { + if isAbortedError(err) { + return nil, ErrListUnchanged + } + // For other errors, the protocol requires that we attempt to re-register. + c.mu.Lock() + defer c.mu.Unlock() + if regError := c.register(ctx); regError != nil { + return nil, regError + } + return nil, err + } + if resp == nil { + return nil, errors.New("no response") + } + if c.verbose { + log.Printf("List response: %v", resp) + } + c.waitToken = resp.NextWaitToken + return resp, nil +} + +// isAbortedError tests if err is a *googleapi.Error, that it contains one error +// in Errors, and that that error's Reason is "aborted". +func isAbortedError(err error) bool { + e, _ := err.(*googleapi.Error) + if e == nil { + return false + } + if len(e.Errors) != 1 { + return false + } + return e.Errors[0].Reason == "aborted" +} + +// Update reports information to the server about a breakpoint that was hit. +// Update can be called concurrently with List and Update. +func (c *Controller) Update(ctx context.Context, breakpointID string, bp *cd.Breakpoint) error { + req := &cd.UpdateActiveBreakpointRequest{Breakpoint: bp} + if c.verbose { + log.Printf("sending update for %s: %v", breakpointID, req) + } + id, err := c.getDebuggeeID(ctx) + if err != nil { + return err + } + _, err = c.s.Update(ctx, id, breakpointID, req) + return err +} + +// register calls the Debuglet Controller Register method, and sets c.debuggeeID. +// c.mu should be locked while calling this function. List and Update can't +// make progress until it returns. +func (c *Controller) register(ctx context.Context) error { + req := cd.RegisterDebuggeeRequest{ + Debuggee: &cd.Debuggee{ + AgentVersion: agentVersionString, + Description: c.description, + Project: c.options.ProjectNumber, + SourceContexts: c.options.SourceContexts, + Uniquifier: c.uniquifier, + Labels: c.labels, + }, + } + resp, err := c.s.Register(ctx, &req) + if err != nil { + return err + } + if resp == nil { + return errors.New("register: no response") + } + if resp.Debuggee.IsDisabled { + // Setting c.debuggeeID to empty makes sure future List and Update calls + // will call register first. + c.debuggeeID = "" + } else { + c.debuggeeID = resp.Debuggee.Id + } + if c.debuggeeID == "" { + return ErrDebuggeeDisabled + } + return nil +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client_test.go new file mode 100644 index 00000000..a5a9e322 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client_test.go @@ -0,0 +1,253 @@ +// Copyright 2016 Google LLC +// +// 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 controller + +import ( + "bytes" + "context" + "errors" + "fmt" + "strconv" + "testing" + + "golang.org/x/oauth2" + cd "google.golang.org/api/clouddebugger/v2" + "google.golang.org/api/googleapi" +) + +const ( + testDebuggeeID = "d12345" + testBreakpointID = "bp12345" +) + +var ( + // The sequence of wait tokens in List requests and responses. + expectedWaitToken = []string{"init", "token1", "token2", "token1", "token1"} + // The set of breakpoints returned from each List call. + expectedBreakpoints = [][]*cd.Breakpoint{ + nil, + { + &cd.Breakpoint{ + Id: testBreakpointID, + IsFinalState: false, + Location: &cd.SourceLocation{Line: 42, Path: "foo.go"}, + }, + }, + nil, + } + abortedError error = &googleapi.Error{ + Code: 409, + Message: "Conflict", + Body: `{ + "error": { + "errors": [ + { + "domain": "global", + "reason": "aborted", + "message": "Conflict" + } + ], + "code": 409, + "message": "Conflict" + } + }`, + Errors: []googleapi.ErrorItem{ + {Reason: "aborted", Message: "Conflict"}, + }, + } + backendError error = &googleapi.Error{ + Code: 503, + Message: "Backend Error", + Body: `{ + "error": { + "errors": [ + { + "domain": "global", + "reason": "backendError", + "message": "Backend Error" + } + ], + "code": 503, + "message": "Backend Error" + } + }`, + Errors: []googleapi.ErrorItem{ + {Reason: "backendError", Message: "Backend Error"}, + }, + } +) + +type mockService struct { + t *testing.T + listCallsSeen int + registerCallsSeen int +} + +func (s *mockService) Register(ctx context.Context, req *cd.RegisterDebuggeeRequest) (*cd.RegisterDebuggeeResponse, error) { + s.registerCallsSeen++ + if req.Debuggee == nil { + s.t.Errorf("missing debuggee") + return nil, nil + } + if req.Debuggee.AgentVersion == "" { + s.t.Errorf("missing agent version") + } + if req.Debuggee.Description == "" { + s.t.Errorf("missing debuglet description") + } + if req.Debuggee.Project == "" { + s.t.Errorf("missing project id") + } + if req.Debuggee.Uniquifier == "" { + s.t.Errorf("missing uniquifier") + } + return &cd.RegisterDebuggeeResponse{ + Debuggee: &cd.Debuggee{Id: testDebuggeeID}, + }, nil +} + +func (s *mockService) Update(ctx context.Context, id, breakpointID string, req *cd.UpdateActiveBreakpointRequest) (*cd.UpdateActiveBreakpointResponse, error) { + if id != testDebuggeeID { + s.t.Errorf("got debuggee ID %s want %s", id, testDebuggeeID) + } + if breakpointID != testBreakpointID { + s.t.Errorf("got breakpoint ID %s want %s", breakpointID, testBreakpointID) + } + if !req.Breakpoint.IsFinalState { + s.t.Errorf("got IsFinalState = false, want true") + } + return nil, nil +} + +func (s *mockService) List(ctx context.Context, id, waitToken string) (*cd.ListActiveBreakpointsResponse, error) { + if id != testDebuggeeID { + s.t.Errorf("got debuggee ID %s want %s", id, testDebuggeeID) + } + if waitToken != expectedWaitToken[s.listCallsSeen] { + s.t.Errorf("got wait token %s want %s", waitToken, expectedWaitToken[s.listCallsSeen]) + } + s.listCallsSeen++ + if s.listCallsSeen == 4 { + return nil, backendError + } + if s.listCallsSeen == 5 { + return nil, abortedError + } + resp := &cd.ListActiveBreakpointsResponse{ + Breakpoints: expectedBreakpoints[s.listCallsSeen-1], + NextWaitToken: expectedWaitToken[s.listCallsSeen], + } + return resp, nil +} + +func TestDebugletControllerClientLibrary(t *testing.T) { + var ( + m *mockService + c *Controller + list *cd.ListActiveBreakpointsResponse + err error + ) + m = &mockService{t: t} + newService = func(context.Context, oauth2.TokenSource) (serviceInterface, error) { return m, nil } + opts := Options{ + ProjectNumber: "5", + ProjectID: "p1", + AppModule: "mod1", + AppVersion: "v1", + } + ctx := context.Background() + if c, err = NewController(ctx, opts); err != nil { + t.Fatal("Initializing Controller client:", err) + } + if err := validateLabels(c, opts); err != nil { + t.Fatalf("Invalid labels:\n%v", err) + } + if list, err = c.List(ctx); err != nil { + t.Fatal("List:", err) + } + if m.registerCallsSeen != 1 { + t.Errorf("saw %d Register calls, want 1", m.registerCallsSeen) + } + if list, err = c.List(ctx); err != nil { + t.Fatal("List:", err) + } + if len(list.Breakpoints) != 1 { + t.Fatalf("got %d breakpoints, want 1", len(list.Breakpoints)) + } + if err = c.Update(ctx, list.Breakpoints[0].Id, &cd.Breakpoint{Id: testBreakpointID, IsFinalState: true}); err != nil { + t.Fatal("Update:", err) + } + if list, err = c.List(ctx); err != nil { + t.Fatal("List:", err) + } + if m.registerCallsSeen != 1 { + t.Errorf("saw %d Register calls, want 1", m.registerCallsSeen) + } + // The next List call produces an error that should cause a Register call. + if list, err = c.List(ctx); err == nil { + t.Fatal("List should have returned an error") + } + if m.registerCallsSeen != 2 { + t.Errorf("saw %d Register calls, want 2", m.registerCallsSeen) + } + // The next List call produces an error that should not cause a Register call. + if list, err = c.List(ctx); err == nil { + t.Fatal("List should have returned an error") + } + if m.registerCallsSeen != 2 { + t.Errorf("saw %d Register calls, want 2", m.registerCallsSeen) + } + if m.listCallsSeen != 5 { + t.Errorf("saw %d list calls, want 5", m.listCallsSeen) + } +} + +func validateLabels(c *Controller, o Options) error { + errMsg := new(bytes.Buffer) + if m, ok := c.labels["module"]; ok { + if m != o.AppModule { + errMsg.WriteString(fmt.Sprintf("label module: want %s, got %s\n", o.AppModule, m)) + } + } else { + errMsg.WriteString("Missing \"module\" label\n") + } + if v, ok := c.labels["version"]; ok { + if v != o.AppVersion { + errMsg.WriteString(fmt.Sprintf("label version: want %s, got %s\n", o.AppVersion, v)) + } + } else { + errMsg.WriteString("Missing \"version\" label\n") + } + if mv, ok := c.labels["minorversion"]; ok { + if _, err := strconv.Atoi(mv); err != nil { + errMsg.WriteString(fmt.Sprintln("label minorversion: not a numeric string:", mv)) + } + } else { + errMsg.WriteString("Missing \"minorversion\" label\n") + } + if errMsg.Len() != 0 { + return errors.New(errMsg.String()) + } + return nil +} + +func TestIsAbortedError(t *testing.T) { + if !isAbortedError(abortedError) { + t.Errorf("isAborted(%+v): got false, want true", abortedError) + } + if isAbortedError(backendError) { + t.Errorf("isAborted(%+v): got true, want false", backendError) + } +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/arch/arch.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/arch/arch.go new file mode 100644 index 00000000..3ec2b029 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/arch/arch.go @@ -0,0 +1,186 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 arch contains architecture-specific definitions. +package arch + +import ( + "encoding/binary" + "math" +) + +const MaxBreakpointSize = 4 // TODO + +// Architecture defines the architecture-specific details for a given machine. +type Architecture struct { + // BreakpointSize is the size of a breakpoint instruction, in bytes. + BreakpointSize int + // IntSize is the size of the int type, in bytes. + IntSize int + // PointerSize is the size of a pointer, in bytes. + PointerSize int + // ByteOrder is the byte order for ints and pointers. + ByteOrder binary.ByteOrder + // FloatByteOrder is the byte order for floats. + FloatByteOrder binary.ByteOrder + BreakpointInstr [MaxBreakpointSize]byte +} + +func (a *Architecture) Int(buf []byte) int64 { + return int64(a.Uint(buf)) +} + +func (a *Architecture) Uint(buf []byte) uint64 { + if len(buf) != a.IntSize { + panic("bad IntSize") + } + switch a.IntSize { + case 4: + return uint64(a.ByteOrder.Uint32(buf[:4])) + case 8: + return a.ByteOrder.Uint64(buf[:8]) + } + panic("no IntSize") +} + +func (a *Architecture) Int16(buf []byte) int16 { + return int16(a.Uint16(buf)) +} + +func (a *Architecture) Int32(buf []byte) int32 { + return int32(a.Uint32(buf)) +} + +func (a *Architecture) Int64(buf []byte) int64 { + return int64(a.Uint64(buf)) +} + +func (a *Architecture) Uint16(buf []byte) uint16 { + return a.ByteOrder.Uint16(buf) +} + +func (a *Architecture) Uint32(buf []byte) uint32 { + return a.ByteOrder.Uint32(buf) +} + +func (a *Architecture) Uint64(buf []byte) uint64 { + return a.ByteOrder.Uint64(buf) +} + +func (a *Architecture) IntN(buf []byte) int64 { + if len(buf) == 0 { + return 0 + } + x := int64(0) + if a.ByteOrder == binary.LittleEndian { + i := len(buf) - 1 + x = int64(int8(buf[i])) // sign-extended + for i--; i >= 0; i-- { + x <<= 8 + x |= int64(buf[i]) // not sign-extended + } + } else { + x = int64(int8(buf[0])) // sign-extended + for i := 1; i < len(buf); i++ { + x <<= 8 + x |= int64(buf[i]) // not sign-extended + } + } + return x +} + +func (a *Architecture) UintN(buf []byte) uint64 { + u := uint64(0) + if a.ByteOrder == binary.LittleEndian { + shift := uint(0) + for _, c := range buf { + u |= uint64(c) << shift + shift += 8 + } + } else { + for _, c := range buf { + u <<= 8 + u |= uint64(c) + } + } + return u +} + +func (a *Architecture) Uintptr(buf []byte) uint64 { + if len(buf) != a.PointerSize { + panic("bad PointerSize") + } + switch a.PointerSize { + case 4: + return uint64(a.ByteOrder.Uint32(buf[:4])) + case 8: + return a.ByteOrder.Uint64(buf[:8]) + } + panic("no PointerSize") +} + +func (a *Architecture) Float32(buf []byte) float32 { + if len(buf) != 4 { + panic("bad float32 size") + } + return math.Float32frombits(a.FloatByteOrder.Uint32(buf)) +} + +func (a *Architecture) Float64(buf []byte) float64 { + if len(buf) != 8 { + panic("bad float64 size") + } + return math.Float64frombits(a.FloatByteOrder.Uint64(buf)) +} + +func (a *Architecture) Complex64(buf []byte) complex64 { + if len(buf) != 8 { + panic("bad complex64 size") + } + return complex(a.Float32(buf[0:4]), a.Float32(buf[4:8])) +} + +func (a *Architecture) Complex128(buf []byte) complex128 { + if len(buf) != 16 { + panic("bad complex128 size") + } + return complex(a.Float64(buf[0:8]), a.Float64(buf[8:16])) +} + +var AMD64 = Architecture{ + BreakpointSize: 1, + IntSize: 8, + PointerSize: 8, + ByteOrder: binary.LittleEndian, + FloatByteOrder: binary.LittleEndian, + BreakpointInstr: [MaxBreakpointSize]byte{0xCC}, // INT 3 +} + +var X86 = Architecture{ + BreakpointSize: 1, + IntSize: 4, + PointerSize: 4, + ByteOrder: binary.LittleEndian, + FloatByteOrder: binary.LittleEndian, + BreakpointInstr: [MaxBreakpointSize]byte{0xCC}, // INT 3 +} + +var ARM = Architecture{ + BreakpointSize: 4, // TODO + IntSize: 4, + PointerSize: 4, + ByteOrder: binary.LittleEndian, + FloatByteOrder: binary.LittleEndian, // TODO + BreakpointInstr: [MaxBreakpointSize]byte{0x00, 0x00, 0x00, 0x00}, // TODO +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/cmd/debugproxy/main.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/cmd/debugproxy/main.go new file mode 100644 index 00000000..c8c2f75f --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/cmd/debugproxy/main.go @@ -0,0 +1,85 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// debugproxy connects to the target binary, and serves an RPC interface using +// the types in server/protocol to access and control it. + +// +build linux + +package main + +import ( + "flag" + "fmt" + "log" + "net/rpc" + "os" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server" +) + +var ( + textFlag = flag.String("text", "", "file name of binary being debugged") +) + +func main() { + log.SetFlags(0) + log.SetPrefix("debugproxy: ") + flag.Parse() + if *textFlag == "" { + flag.Usage() + os.Exit(2) + } + s, err := server.New(*textFlag) + if err != nil { + fmt.Printf("server.New: %v\n", err) + os.Exit(2) + } + err = rpc.Register(s) + if err != nil { + fmt.Printf("rpc.Register: %v\n", err) + os.Exit(2) + } + fmt.Println("OK") + log.Print("starting server") + rpc.ServeConn(&rwc{ + os.Stdin, + os.Stdout, + }) + log.Print("server finished") +} + +// rwc creates a single io.ReadWriteCloser from a read side and a write side. +// It allows us to do RPC using standard in and standard out. +type rwc struct { + r *os.File + w *os.File +} + +func (rwc *rwc) Read(p []byte) (int, error) { + return rwc.r.Read(p) +} + +func (rwc *rwc) Write(p []byte) (int, error) { + return rwc.w.Write(p) +} + +func (rwc *rwc) Close() error { + rerr := rwc.r.Close() + werr := rwc.w.Close() + if rerr != nil { + return rerr + } + return werr +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/doc/ptrace-nptl.txt b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/doc/ptrace-nptl.txt new file mode 100644 index 00000000..81f6a106 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/doc/ptrace-nptl.txt @@ -0,0 +1,128 @@ +ptrace and NTPL, the missing manpage + +== Signals == + +A signal sent to a ptrace'd process or thread causes only the thread +that receives it to stop and report to the attached process. + +Use tgkill to target a signal (for example, SIGSTOP) at a particular +thread. If you use kill, the signal could be delivered to another +thread in the same process. + +Note that SIGSTOP differs from its usual behavior when a process is +being traced. Usually, a SIGSTOP sent to any thread in a thread group +will stop all threads in the thread group. When a thread is traced, +however, a SIGSTOP affects only the receiving thread (and any other +threads in the thread group that are not traced). + +SIGKILL behaves like it does for non-traced processes. It affects all +threads in the process and terminates them without the WSTOPSIG event +generated by other signals. However, if PTRACE_O_TRACEEXIT is set, +the attached process will still receive PTRACE_EVENT_EXIT events +before receiving WIFSIGNALED events. + +See "Following thread death" for a caveat regarding signal delivery to +zombie threads. + +== Waiting on threads == + +Cloned threads in ptrace'd processes are treated similarly to cloned +threads in your own process. Thus, you must use the __WALL option in +order to receive notifications from threads created by the child +process. Similarly, the __WCLONE option will wait only on +notifications from threads created by the child process and *not* on +notifications from the initial child thread. + +Even when waiting on a specific thread's PID using waitpid or similar, +__WALL or __WCLONE is necessary or waitpid will return ECHILD. + +== Attaching to existing threads == + +libthread_db (which gdb uses), attaches to existing threads by pulling +the pthread data structures out of the traced process. The much +easier way is to traverse the /proc/PID/task directory, though it's +unclear how the semantics of these two approaches differ. + +Unfortunately, if the main thread has exited (but the overall process +has not), it sticks around as a zombie process. This zombie will +appear in the /proc/PID/task directory, but trying to attach to it +will yield EPERM. In this case, the third field of the +/proc/PID/task/PID/stat file will be "Z". Attempting to open the stat +file is also a convenient way to detect races between listing the task +directory and the thread exiting. Coincidentally, gdb will simply +fail to attach to a process whose main thread is a zombie. + +Because new threads may be created while the debugger is in the +process of attaching to existing threads, the debugger must repeatedly +re-list the task directory until it has attached to (and thus stopped) +every thread listed. + +In order to follow new threads created by existing threads, +PTRACE_O_TRACECLONE must be set on each thread attached to. + +== Following new threads == + +With the child process stopped, use PTRACE_SETOPTIONS to set the +PTRACE_O_TRACECLONE option. This option is per-thread, and thus must +be set on each existing thread individually. When an existing thread +with PTRACE_O_TRACECLONE set spawns a new thread, the existing thread +will stop with (SIGTRAP | PTRACE_EVENT_CLONE << 8) and the PID of the +new thread can be retrieved with PTRACE_GETEVENTMSG on the creating +thread. At this time, the new thread will exist, but will initially +be stopped with a SIGSTOP. The new thread will automatically be +traced and will inherit the PTRACE_O_TRACECLONE option from its +parent. The attached process should wait on the new thread to receive +the SIGSTOP notification. + +When using waitpid(-1, ...), don't rely on the parent thread reporting +a SIGTRAP before receiving the SIGSTOP from the new child thread. + +Without PTRACE_O_TRACECLONE, newly cloned threads will not be +ptrace'd. As a result, signals received by new threads will be +handled in the usual way, which may affect the parent and in turn +appear to the attached process, but attributed to the parent (possibly +in unexpected ways). + +== Following thread death == + +If any thread with the PTRACE_O_TRACEEXIT option set exits (either by +returning or pthread_exit'ing), the tracing process will receive an +immediate PTRACE_EVENT_EXIT. At this point, the thread will still +exist. The exit status, encoded as for wait, can be queried using +PTRACE_GETEVENTMSG on the exiting thread's PID. The thread should be +continued so it can actually exit, after which its wait behavior is +the same as for a thread without the PTRACE_O_TRACEEXIT option. + +If a non-main thread exits (either by returning or pthread_exit'ing), +its corresponding process will also exit, producing a WIFEXITED event +(after the process is continued from a possible PTRACE_EVENT_EXIT +event). It is *not* necessary for another thread to ptrace_join for +this to happen. + +If the main thread exits by returning, then all threads will exit, +first generating a PTRACE_EVENT_EXIT event for each thread if +appropriate, then producing a WIFEXITED event for each thread. + +If the main thread exits using pthread_exit, then it enters a +non-waitable zombie state. It will still produce an immediate +PTRACE_O_TRACEEXIT event, but the WIFEXITED event will be delayed +until the entire process exits. This state exists so that shells +don't think the process is done until all of the threads have exited. +Unfortunately, signals cannot be delivered to non-waitable zombies. +Most notably, SIGSTOP cannot be delivered; as a result, when you +broadcast SIGSTOP to all of the threads, you must not wait for +non-waitable zombies to stop. Furthermore, any ptrace command on a +non-waitable zombie, including PTRACE_DETACH, will return ESRCH. + +== Multi-threaded debuggers == + +If the debugger itself is multi-threaded, ptrace calls must come from +the same thread that originally attached to the remote thread. The +kernel simply compares the PID of the caller of ptrace against the +tracer PID of the process passed to ptrace. Because each debugger +thread has a different PID, calling ptrace from a different thread +might as well be calling it from a different process and the kernel +will return ESRCH. + +wait, on the other hand, does not have this restriction. Any debugger +thread can wait on any thread in the attached process. diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/buf.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/buf.go new file mode 100644 index 00000000..df4dcade --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/buf.go @@ -0,0 +1,213 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// Buffered reading and decoding of DWARF data streams. + +package dwarf + +import ( + "encoding/binary" + "fmt" + "strconv" +) + +// Data buffer being decoded. +type buf struct { + dwarf *Data + order binary.ByteOrder + format dataFormat + name string + off Offset + data []byte + err error +} + +// Data format, other than byte order. This affects the handling of +// certain field formats. +type dataFormat interface { + // DWARF version number. Zero means unknown. + version() int + + // 64-bit DWARF format? + dwarf64() (dwarf64 bool, isKnown bool) + + // Size of an address, in bytes. Zero means unknown. + addrsize() int +} + +// Some parts of DWARF have no data format, e.g., abbrevs. +type unknownFormat struct{} + +func (u unknownFormat) version() int { + return 0 +} + +func (u unknownFormat) dwarf64() (bool, bool) { + return false, false +} + +func (u unknownFormat) addrsize() int { + return 0 +} + +func makeBuf(d *Data, format dataFormat, name string, off Offset, data []byte) buf { + return buf{d, d.order, format, name, off, data, nil} +} + +func (b *buf) slice(length int) buf { + n := *b + data := b.data + b.skip(length) // Will validate length. + n.data = data[:length] + return n +} + +func (b *buf) uint8() uint8 { + if len(b.data) < 1 { + b.error("underflow") + return 0 + } + val := b.data[0] + b.data = b.data[1:] + b.off++ + return val +} + +func (b *buf) bytes(n int) []byte { + if len(b.data) < n { + b.error("underflow") + return nil + } + data := b.data[0:n] + b.data = b.data[n:] + b.off += Offset(n) + return data +} + +func (b *buf) skip(n int) { b.bytes(n) } + +// string returns the NUL-terminated (C-like) string at the start of the buffer. +// The terminal NUL is discarded. +func (b *buf) string() string { + for i := 0; i < len(b.data); i++ { + if b.data[i] == 0 { + s := string(b.data[0:i]) + b.data = b.data[i+1:] + b.off += Offset(i + 1) + return s + } + } + b.error("underflow") + return "" +} + +func (b *buf) uint16() uint16 { + a := b.bytes(2) + if a == nil { + return 0 + } + return b.order.Uint16(a) +} + +func (b *buf) uint32() uint32 { + a := b.bytes(4) + if a == nil { + return 0 + } + return b.order.Uint32(a) +} + +func (b *buf) uint64() uint64 { + a := b.bytes(8) + if a == nil { + return 0 + } + return b.order.Uint64(a) +} + +// Read a varint, which is 7 bits per byte, little endian. +// the 0x80 bit means read another byte. +func (b *buf) varint() (c uint64, bits uint) { + for i := 0; i < len(b.data); i++ { + byte := b.data[i] + c |= uint64(byte&0x7F) << bits + bits += 7 + if byte&0x80 == 0 { + b.off += Offset(i + 1) + b.data = b.data[i+1:] + return c, bits + } + } + return 0, 0 +} + +// Unsigned int is just a varint. +func (b *buf) uint() uint64 { + x, _ := b.varint() + return x +} + +// Signed int is a sign-extended varint. +func (b *buf) int() int64 { + ux, bits := b.varint() + x := int64(ux) + if x&(1<<(bits-1)) != 0 { + x |= -1 << bits + } + return x +} + +// Address-sized uint. +func (b *buf) addr() uint64 { + switch b.format.addrsize() { + case 1: + return uint64(b.uint8()) + case 2: + return uint64(b.uint16()) + case 4: + return uint64(b.uint32()) + case 8: + return uint64(b.uint64()) + } + b.error("unknown address size") + return 0 +} + +// assertEmpty checks that everything has been read from b. +func (b *buf) assertEmpty() { + if len(b.data) == 0 { + return + } + if len(b.data) > 5 { + b.error(fmt.Sprintf("unexpected extra data: %x...", b.data[0:5])) + } + b.error(fmt.Sprintf("unexpected extra data: %x", b.data)) +} + +func (b *buf) error(s string) { + if b.err == nil { + b.data = nil + b.err = DecodeError{b.name, b.off, s} + } +} + +type DecodeError struct { + Name string + Offset Offset + Err string +} + +func (e DecodeError) Error() string { + return "decoding dwarf section " + e.Name + " at offset 0x" + strconv.FormatInt(int64(e.Offset), 16) + ": " + e.Err +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/cache.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/cache.go new file mode 100644 index 00000000..bd00128d --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/cache.go @@ -0,0 +1,277 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 dwarf + +import ( + "fmt" + "sort" +) + +// pcToFuncEntries maps PC ranges to function entries. +// +// Each element contains a *Entry for a function and its corresponding start PC. +// If we know the address one past the last instruction of a function, and it is +// not equal to the start address of the next function, we mark that with +// another element containing that address and a nil entry. The elements are +// sorted by PC. Among elements with the same PC, those with non-nil *Entry +// are put earlier. +type pcToFuncEntries []pcToFuncEntry +type pcToFuncEntry struct { + pc uint64 + entry *Entry +} + +func (p pcToFuncEntries) Len() int { return len(p) } +func (p pcToFuncEntries) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (p pcToFuncEntries) Less(i, j int) bool { + if p[i].pc != p[j].pc { + return p[i].pc < p[j].pc + } + return p[i].entry != nil && p[j].entry == nil +} + +// nameCache maps each symbol name to a linked list of the entries with that name. +type nameCache map[string]*nameCacheEntry +type nameCacheEntry struct { + entry *Entry + link *nameCacheEntry +} + +// pcToLineEntries maps PCs to line numbers. +// +// It is a slice of (PC, line, file number) triples, sorted by PC. The file +// number is an index into the source files slice. +// If (PC1, line1, file1) and (PC2, line2, file2) are two consecutive elements, +// then the span of addresses [PC1, PC2) belongs to (line1, file1). If an +// element's file number is zero, it only marks the end of a span. +// +// TODO: could save memory by changing pcToLineEntries and lineToPCEntries to use +// interval trees containing references into .debug_line. +type pcToLineEntries []pcToLineEntry +type pcToLineEntry struct { + pc uint64 + line uint64 + file uint64 +} + +func (p pcToLineEntries) Len() int { return len(p) } +func (p pcToLineEntries) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (p pcToLineEntries) Less(i, j int) bool { + if p[i].pc != p[j].pc { + return p[i].pc < p[j].pc + } + return p[i].file > p[j].file +} + +// byFileLine is used temporarily while building lineToPCEntries. +type byFileLine []pcToLineEntry + +func (b byFileLine) Len() int { return len(b) } +func (b byFileLine) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byFileLine) Less(i, j int) bool { + if b[i].file != b[j].file { + return b[i].file < b[j].file + } + return b[i].line < b[j].line +} + +// lineToPCEntries maps line numbers to breakpoint addresses. +// +// The slice contains, for each source file in Data, a slice of (line, PC) +// pairs, sorted by line. Note that there may be more than one PC for a line. +type lineToPCEntries [][]lineToPCEntry +type lineToPCEntry struct { + line uint64 + pc uint64 +} + +func (d *Data) buildLineToPCCache(pclfs pcToLineEntries) { + // TODO: only include lines where is_stmt is true + sort.Sort(byFileLine(pclfs)) + // Make a slice of (line, PC) pairs for each (non-zero) file. + var ( + c = make(lineToPCEntries, len(d.sourceFiles)) + curSlice []lineToPCEntry + ) + for i, pclf := range pclfs { + if pclf.file == 0 { + // This entry indicated the end of an instruction sequence, not a breakpoint. + continue + } + curSlice = append(curSlice, lineToPCEntry{line: pclf.line, pc: pclf.pc}) + if i+1 == len(pclfs) || pclf.file != pclfs[i+1].file { + // curSlice now contains all of the entries for pclf.file. + if pclf.file > 0 && pclf.file < uint64(len(c)) { + c[pclf.file] = curSlice + } + curSlice = nil + } + } + d.lineToPCEntries = c +} + +func (d *Data) buildPCToLineCache(cache pcToLineEntries) { + // Sort cache by PC (in increasing order), then by file number (in decreasing order). + sort.Sort(cache) + + // Build a copy without redundant entries. + var out pcToLineEntries + for i, pclf := range cache { + if i > 0 && pclf.pc == cache[i-1].pc { + // This entry is for the same PC as the previous entry. + continue + } + if i > 0 && pclf.file == cache[i-1].file && pclf.line == cache[i-1].line { + // This entry is for the same file and line as the previous entry. + continue + } + out = append(out, pclf) + } + d.pcToLineEntries = out +} + +// buildLineCaches constructs d.sourceFiles, d.lineToPCEntries, d.pcToLineEntries. +func (d *Data) buildLineCaches() error { + var cache pcToLineEntries + r := d.Reader() + for { + entry, err := r.Next() + if err != nil { + return err + } + if entry == nil { + break + } + if entry.Tag != TagCompileUnit { + r.SkipChildren() + continue + } + // Get the offset of this unit's line number program in .debug_line. + offset, ok := entry.Val(AttrStmtList).(int64) + if !ok { + return fmt.Errorf("AttrStmtList not present or not int64 for unit %d", r.unit) + } + buf := makeBuf(d, &d.unit[r.unit], "line", Offset(offset), d.line[offset:]) + var m lineMachine + if err := m.parseHeader(&buf); err != nil { + return err + } + fileNumOffset := uint64(len(d.sourceFiles)) + for _, f := range m.header.file { + d.sourceFiles = append(d.sourceFiles, f.name) + } + fn := func(m *lineMachine) bool { + if m.endSequence { + cache = append(cache, pcToLineEntry{ + pc: m.address, + line: 0, + file: 0, + }) + } else { + // m.file is a 1-based index into the files of this line number program's + // header. Translate it to a 0-based index into d.sourceFiles. + fnum := fileNumOffset + m.file - 1 + cache = append(cache, pcToLineEntry{ + pc: m.address, + line: m.line, + file: fnum, + }) + } + return true + } + if err := m.evalCompilationUnit(&buf, fn); err != nil { + return err + } + } + d.buildLineToPCCache(cache) + d.buildPCToLineCache(cache) + return nil +} + +// buildInfoCaches initializes nameCache and pcToFuncEntries by walking the +// top-level entries under each compile unit. It swallows any errors in parsing. +func (d *Data) buildInfoCaches() { + // TODO: record errors somewhere? + d.nameCache = make(map[string]*nameCacheEntry) + + var pcToFuncEntries pcToFuncEntries + + r := d.Reader() +loop: + for { + entry, err := r.Next() + if entry == nil || err != nil { + break loop + } + if entry.Tag != TagCompileUnit /* DW_TAG_compile_unit */ { + r.SkipChildren() + continue + } + for { + entry, err := r.Next() + if entry == nil || err != nil { + break loop + } + if entry.Tag == 0 { + // End of children of current compile unit. + break + } + r.SkipChildren() + // Update name-to-entry cache. + if name, ok := entry.Val(AttrName).(string); ok { + d.nameCache[name] = &nameCacheEntry{entry: entry, link: d.nameCache[name]} + } + + // If this entry is a function, update PC-to-containing-function cache. + if entry.Tag != TagSubprogram /* DW_TAG_subprogram */ { + continue + } + + // DW_AT_low_pc, if present, is the address of the first instruction of + // the function. + lowpc, ok := entry.Val(AttrLowpc).(uint64) + if !ok { + continue + } + pcToFuncEntries = append(pcToFuncEntries, pcToFuncEntry{lowpc, entry}) + + // DW_AT_high_pc, if present (TODO: and of class address) is the address + // one past the last instruction of the function. + highpc, ok := entry.Val(AttrHighpc).(uint64) + if !ok { + continue + } + pcToFuncEntries = append(pcToFuncEntries, pcToFuncEntry{highpc, nil}) + } + } + // Sort elements by PC. If there are multiple elements with the same PC, + // those with non-nil *Entry are placed earlier. + sort.Sort(pcToFuncEntries) + + // Copy only the first element for each PC to out. + n := 0 + for i, ce := range pcToFuncEntries { + if i == 0 || ce.pc != pcToFuncEntries[i-1].pc { + n++ + } + } + out := make([]pcToFuncEntry, 0, n) + for i, ce := range pcToFuncEntries { + if i == 0 || ce.pc != pcToFuncEntries[i-1].pc { + out = append(out, ce) + } + } + d.pcToFuncEntries = out +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/const.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/const.go new file mode 100644 index 00000000..adf7882f --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/const.go @@ -0,0 +1,480 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// Constants + +package dwarf + +import "strconv" + +// An Attr identifies the attribute type in a DWARF Entry's Field. +type Attr uint32 + +const ( + AttrSibling Attr = 0x01 + AttrLocation Attr = 0x02 + AttrName Attr = 0x03 + AttrOrdering Attr = 0x09 + AttrByteSize Attr = 0x0B + AttrBitOffset Attr = 0x0C + AttrBitSize Attr = 0x0D + AttrStmtList Attr = 0x10 + AttrLowpc Attr = 0x11 + AttrHighpc Attr = 0x12 + AttrLanguage Attr = 0x13 + AttrDiscr Attr = 0x15 + AttrDiscrValue Attr = 0x16 + AttrVisibility Attr = 0x17 + AttrImport Attr = 0x18 + AttrStringLength Attr = 0x19 + AttrCommonRef Attr = 0x1A + AttrCompDir Attr = 0x1B + AttrConstValue Attr = 0x1C + AttrContainingType Attr = 0x1D + AttrDefaultValue Attr = 0x1E + AttrInline Attr = 0x20 + AttrIsOptional Attr = 0x21 + AttrLowerBound Attr = 0x22 + AttrProducer Attr = 0x25 + AttrPrototyped Attr = 0x27 + AttrReturnAddr Attr = 0x2A + AttrStartScope Attr = 0x2C + AttrStrideSize Attr = 0x2E + AttrUpperBound Attr = 0x2F + AttrAbstractOrigin Attr = 0x31 + AttrAccessibility Attr = 0x32 + AttrAddrClass Attr = 0x33 + AttrArtificial Attr = 0x34 + AttrBaseTypes Attr = 0x35 + AttrCalling Attr = 0x36 + AttrCount Attr = 0x37 + AttrDataMemberLoc Attr = 0x38 + AttrDeclColumn Attr = 0x39 + AttrDeclFile Attr = 0x3A + AttrDeclLine Attr = 0x3B + AttrDeclaration Attr = 0x3C + AttrDiscrList Attr = 0x3D + AttrEncoding Attr = 0x3E + AttrExternal Attr = 0x3F + AttrFrameBase Attr = 0x40 + AttrFriend Attr = 0x41 + AttrIdentifierCase Attr = 0x42 + AttrMacroInfo Attr = 0x43 + AttrNamelistItem Attr = 0x44 + AttrPriority Attr = 0x45 + AttrSegment Attr = 0x46 + AttrSpecification Attr = 0x47 + AttrStaticLink Attr = 0x48 + AttrType Attr = 0x49 + AttrUseLocation Attr = 0x4A + AttrVarParam Attr = 0x4B + AttrVirtuality Attr = 0x4C + AttrVtableElemLoc Attr = 0x4D + AttrAllocated Attr = 0x4E + AttrAssociated Attr = 0x4F + AttrDataLocation Attr = 0x50 + AttrStride Attr = 0x51 + AttrEntrypc Attr = 0x52 + AttrUseUTF8 Attr = 0x53 + AttrExtension Attr = 0x54 + AttrRanges Attr = 0x55 + AttrTrampoline Attr = 0x56 + AttrCallColumn Attr = 0x57 + AttrCallFile Attr = 0x58 + AttrCallLine Attr = 0x59 + AttrDescription Attr = 0x5A + + // Go-specific attributes. + AttrGoKind Attr = 0x2900 + AttrGoKey Attr = 0x2901 + AttrGoElem Attr = 0x2902 + AttrGoEmbeddedField Attr = 0x2903 +) + +var attrNames = [...]string{ + AttrSibling: "Sibling", + AttrLocation: "Location", + AttrName: "Name", + AttrOrdering: "Ordering", + AttrByteSize: "ByteSize", + AttrBitOffset: "BitOffset", + AttrBitSize: "BitSize", + AttrStmtList: "StmtList", + AttrLowpc: "Lowpc", + AttrHighpc: "Highpc", + AttrLanguage: "Language", + AttrDiscr: "Discr", + AttrDiscrValue: "DiscrValue", + AttrVisibility: "Visibility", + AttrImport: "Import", + AttrStringLength: "StringLength", + AttrCommonRef: "CommonRef", + AttrCompDir: "CompDir", + AttrConstValue: "ConstValue", + AttrContainingType: "ContainingType", + AttrDefaultValue: "DefaultValue", + AttrInline: "Inline", + AttrIsOptional: "IsOptional", + AttrLowerBound: "LowerBound", + AttrProducer: "Producer", + AttrPrototyped: "Prototyped", + AttrReturnAddr: "ReturnAddr", + AttrStartScope: "StartScope", + AttrStrideSize: "StrideSize", + AttrUpperBound: "UpperBound", + AttrAbstractOrigin: "AbstractOrigin", + AttrAccessibility: "Accessibility", + AttrAddrClass: "AddrClass", + AttrArtificial: "Artificial", + AttrBaseTypes: "BaseTypes", + AttrCalling: "Calling", + AttrCount: "Count", + AttrDataMemberLoc: "DataMemberLoc", + AttrDeclColumn: "DeclColumn", + AttrDeclFile: "DeclFile", + AttrDeclLine: "DeclLine", + AttrDeclaration: "Declaration", + AttrDiscrList: "DiscrList", + AttrEncoding: "Encoding", + AttrExternal: "External", + AttrFrameBase: "FrameBase", + AttrFriend: "Friend", + AttrIdentifierCase: "IdentifierCase", + AttrMacroInfo: "MacroInfo", + AttrNamelistItem: "NamelistItem", + AttrPriority: "Priority", + AttrSegment: "Segment", + AttrSpecification: "Specification", + AttrStaticLink: "StaticLink", + AttrType: "Type", + AttrUseLocation: "UseLocation", + AttrVarParam: "VarParam", + AttrVirtuality: "Virtuality", + AttrVtableElemLoc: "VtableElemLoc", + AttrAllocated: "Allocated", + AttrAssociated: "Associated", + AttrDataLocation: "DataLocation", + AttrStride: "Stride", + AttrEntrypc: "Entrypc", + AttrUseUTF8: "UseUTF8", + AttrExtension: "Extension", + AttrRanges: "Ranges", + AttrTrampoline: "Trampoline", + AttrCallColumn: "CallColumn", + AttrCallFile: "CallFile", + AttrCallLine: "CallLine", + AttrDescription: "Description", +} + +func (a Attr) String() string { + if int(a) < len(attrNames) { + s := attrNames[a] + if s != "" { + return s + } + } + switch a { + case AttrGoKind: + return "GoKind" + case AttrGoKey: + return "GoKey" + case AttrGoElem: + return "GoElem" + case AttrGoEmbeddedField: + return "GoEmbeddedField" + } + return strconv.Itoa(int(a)) +} + +func (a Attr) GoString() string { + if int(a) < len(attrNames) { + s := attrNames[a] + if s != "" { + return "dwarf.Attr" + s + } + } + return "dwarf.Attr(" + strconv.FormatInt(int64(a), 10) + ")" +} + +// A format is a DWARF data encoding format. +type format uint32 + +const ( + // value formats + formAddr format = 0x01 + formDwarfBlock2 format = 0x03 + formDwarfBlock4 format = 0x04 + formData2 format = 0x05 + formData4 format = 0x06 + formData8 format = 0x07 + formString format = 0x08 + formDwarfBlock format = 0x09 + formDwarfBlock1 format = 0x0A + formData1 format = 0x0B + formFlag format = 0x0C + formSdata format = 0x0D + formStrp format = 0x0E + formUdata format = 0x0F + formRefAddr format = 0x10 + formRef1 format = 0x11 + formRef2 format = 0x12 + formRef4 format = 0x13 + formRef8 format = 0x14 + formRefUdata format = 0x15 + formIndirect format = 0x16 + // The following are new in DWARF 4. + formSecOffset format = 0x17 + formExprloc format = 0x18 + formFlagPresent format = 0x19 + formRefSig8 format = 0x20 + // Extensions for multi-file compression (.dwz) + // http://www.dwarfstd.org/ShowIssue.php?issue=120604.1 + formGnuRefAlt format = 0x1f20 + formGnuStrpAlt format = 0x1f21 +) + +// A Tag is the classification (the type) of an Entry. +type Tag uint32 + +const ( + TagArrayType Tag = 0x01 + TagClassType Tag = 0x02 + TagEntryPoint Tag = 0x03 + TagEnumerationType Tag = 0x04 + TagFormalParameter Tag = 0x05 + TagImportedDeclaration Tag = 0x08 + TagLabel Tag = 0x0A + TagLexDwarfBlock Tag = 0x0B + TagMember Tag = 0x0D + TagPointerType Tag = 0x0F + TagReferenceType Tag = 0x10 + TagCompileUnit Tag = 0x11 + TagStringType Tag = 0x12 + TagStructType Tag = 0x13 + TagSubroutineType Tag = 0x15 + TagTypedef Tag = 0x16 + TagUnionType Tag = 0x17 + TagUnspecifiedParameters Tag = 0x18 + TagVariant Tag = 0x19 + TagCommonDwarfBlock Tag = 0x1A + TagCommonInclusion Tag = 0x1B + TagInheritance Tag = 0x1C + TagInlinedSubroutine Tag = 0x1D + TagModule Tag = 0x1E + TagPtrToMemberType Tag = 0x1F + TagSetType Tag = 0x20 + TagSubrangeType Tag = 0x21 + TagWithStmt Tag = 0x22 + TagAccessDeclaration Tag = 0x23 + TagBaseType Tag = 0x24 + TagCatchDwarfBlock Tag = 0x25 + TagConstType Tag = 0x26 + TagConstant Tag = 0x27 + TagEnumerator Tag = 0x28 + TagFileType Tag = 0x29 + TagFriend Tag = 0x2A + TagNamelist Tag = 0x2B + TagNamelistItem Tag = 0x2C + TagPackedType Tag = 0x2D + TagSubprogram Tag = 0x2E + TagTemplateTypeParameter Tag = 0x2F + TagTemplateValueParameter Tag = 0x30 + TagThrownType Tag = 0x31 + TagTryDwarfBlock Tag = 0x32 + TagVariantPart Tag = 0x33 + TagVariable Tag = 0x34 + TagVolatileType Tag = 0x35 + // The following are new in DWARF 3. + TagDwarfProcedure Tag = 0x36 + TagRestrictType Tag = 0x37 + TagInterfaceType Tag = 0x38 + TagNamespace Tag = 0x39 + TagImportedModule Tag = 0x3A + TagUnspecifiedType Tag = 0x3B + TagPartialUnit Tag = 0x3C + TagImportedUnit Tag = 0x3D + TagMutableType Tag = 0x3E // Later removed from DWARF. + TagCondition Tag = 0x3F + TagSharedType Tag = 0x40 + // The following are new in DWARF 4. + TagTypeUnit Tag = 0x41 + TagRvalueReferenceType Tag = 0x42 + TagTemplateAlias Tag = 0x43 +) + +var tagNames = [...]string{ + TagArrayType: "ArrayType", + TagClassType: "ClassType", + TagEntryPoint: "EntryPoint", + TagEnumerationType: "EnumerationType", + TagFormalParameter: "FormalParameter", + TagImportedDeclaration: "ImportedDeclaration", + TagLabel: "Label", + TagLexDwarfBlock: "LexDwarfBlock", + TagMember: "Member", + TagPointerType: "PointerType", + TagReferenceType: "ReferenceType", + TagCompileUnit: "CompileUnit", + TagStringType: "StringType", + TagStructType: "StructType", + TagSubroutineType: "SubroutineType", + TagTypedef: "Typedef", + TagUnionType: "UnionType", + TagUnspecifiedParameters: "UnspecifiedParameters", + TagVariant: "Variant", + TagCommonDwarfBlock: "CommonDwarfBlock", + TagCommonInclusion: "CommonInclusion", + TagInheritance: "Inheritance", + TagInlinedSubroutine: "InlinedSubroutine", + TagModule: "Module", + TagPtrToMemberType: "PtrToMemberType", + TagSetType: "SetType", + TagSubrangeType: "SubrangeType", + TagWithStmt: "WithStmt", + TagAccessDeclaration: "AccessDeclaration", + TagBaseType: "BaseType", + TagCatchDwarfBlock: "CatchDwarfBlock", + TagConstType: "ConstType", + TagConstant: "Constant", + TagEnumerator: "Enumerator", + TagFileType: "FileType", + TagFriend: "Friend", + TagNamelist: "Namelist", + TagNamelistItem: "NamelistItem", + TagPackedType: "PackedType", + TagSubprogram: "Subprogram", + TagTemplateTypeParameter: "TemplateTypeParameter", + TagTemplateValueParameter: "TemplateValueParameter", + TagThrownType: "ThrownType", + TagTryDwarfBlock: "TryDwarfBlock", + TagVariantPart: "VariantPart", + TagVariable: "Variable", + TagVolatileType: "VolatileType", + TagDwarfProcedure: "DwarfProcedure", + TagRestrictType: "RestrictType", + TagInterfaceType: "InterfaceType", + TagNamespace: "Namespace", + TagImportedModule: "ImportedModule", + TagUnspecifiedType: "UnspecifiedType", + TagPartialUnit: "PartialUnit", + TagImportedUnit: "ImportedUnit", + TagMutableType: "MutableType", + TagCondition: "Condition", + TagSharedType: "SharedType", + TagTypeUnit: "TypeUnit", + TagRvalueReferenceType: "RvalueReferenceType", + TagTemplateAlias: "TemplateAlias", +} + +func (t Tag) String() string { + if int(t) < len(tagNames) { + s := tagNames[t] + if s != "" { + return s + } + } + return strconv.Itoa(int(t)) +} + +func (t Tag) GoString() string { + if int(t) < len(tagNames) { + s := tagNames[t] + if s != "" { + return "dwarf.Tag" + s + } + } + return "dwarf.Tag(" + strconv.FormatInt(int64(t), 10) + ")" +} + +// Location expression operators. +// The debug info encodes value locations like 8(R3) +// as a sequence of these op codes. +// This package does not implement full expressions; +// the opPlusUconst operator is expected by the type parser. +const ( + opAddr = 0x03 /* 1 op, const addr */ + opDeref = 0x06 + opConst1u = 0x08 /* 1 op, 1 byte const */ + opConst1s = 0x09 /* " signed */ + opConst2u = 0x0A /* 1 op, 2 byte const */ + opConst2s = 0x0B /* " signed */ + opConst4u = 0x0C /* 1 op, 4 byte const */ + opConst4s = 0x0D /* " signed */ + opConst8u = 0x0E /* 1 op, 8 byte const */ + opConst8s = 0x0F /* " signed */ + opConstu = 0x10 /* 1 op, LEB128 const */ + opConsts = 0x11 /* " signed */ + opDup = 0x12 + opDrop = 0x13 + opOver = 0x14 + opPick = 0x15 /* 1 op, 1 byte stack index */ + opSwap = 0x16 + opRot = 0x17 + opXderef = 0x18 + opAbs = 0x19 + opAnd = 0x1A + opDiv = 0x1B + opMinus = 0x1C + opMod = 0x1D + opMul = 0x1E + opNeg = 0x1F + opNot = 0x20 + opOr = 0x21 + opPlus = 0x22 + opPlusUconst = 0x23 /* 1 op, ULEB128 addend */ + opShl = 0x24 + opShr = 0x25 + opShra = 0x26 + opXor = 0x27 + opSkip = 0x2F /* 1 op, signed 2-byte constant */ + opBra = 0x28 /* 1 op, signed 2-byte constant */ + opEq = 0x29 + opGe = 0x2A + opGt = 0x2B + opLe = 0x2C + opLt = 0x2D + opNe = 0x2E + opLit0 = 0x30 + /* OpLitN = OpLit0 + N for N = 0..31 */ + opReg0 = 0x50 + /* OpRegN = OpReg0 + N for N = 0..31 */ + opBreg0 = 0x70 /* 1 op, signed LEB128 constant */ + /* OpBregN = OpBreg0 + N for N = 0..31 */ + opRegx = 0x90 /* 1 op, ULEB128 register */ + opFbreg = 0x91 /* 1 op, SLEB128 offset */ + opBregx = 0x92 /* 2 op, ULEB128 reg; SLEB128 off */ + opPiece = 0x93 /* 1 op, ULEB128 size of piece */ + opDerefSize = 0x94 /* 1-byte size of data retrieved */ + opXderefSize = 0x95 /* 1-byte size of data retrieved */ + opNop = 0x96 + /* next four new in Dwarf v3 */ + opPushObjAddr = 0x97 + opCall2 = 0x98 /* 2-byte offset of DIE */ + opCall4 = 0x99 /* 4-byte offset of DIE */ + opCallRef = 0x9A /* 4- or 8- byte offset of DIE */ + /* 0xE0-0xFF reserved for user-specific */ +) + +// Basic type encodings -- the value for AttrEncoding in a TagBaseType Entry. +const ( + encAddress = 0x01 + encBoolean = 0x02 + encComplexFloat = 0x03 + encFloat = 0x04 + encSigned = 0x05 + encSignedChar = 0x06 + encUnsigned = 0x07 + encUnsignedChar = 0x08 + encImaginaryFloat = 0x09 +) diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/entry.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/entry.go new file mode 100644 index 00000000..ecf2a084 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/entry.go @@ -0,0 +1,417 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// DWARF debug information entry parser. +// An entry is a sequence of data items of a given format. +// The first word in the entry is an index into what DWARF +// calls the ``abbreviation table.'' An abbreviation is really +// just a type descriptor: it's an array of attribute tag/value format pairs. + +package dwarf + +import ( + "errors" + "strconv" +) + +// a single entry's description: a sequence of attributes +type abbrev struct { + tag Tag + children bool + field []afield +} + +type afield struct { + attr Attr + fmt format +} + +// a map from entry format ids to their descriptions +type abbrevTable map[uint32]abbrev + +// ParseAbbrev returns the abbreviation table that starts at byte off +// in the .debug_abbrev section. +func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) { + if m, ok := d.abbrevCache[off]; ok { + return m, nil + } + + data := d.abbrev + if off > uint32(len(data)) { + data = nil + } else { + data = data[off:] + } + b := makeBuf(d, unknownFormat{}, "abbrev", 0, data) + + // Error handling is simplified by the buf getters + // returning an endless stream of 0s after an error. + m := make(abbrevTable) + for { + // Table ends with id == 0. + id := uint32(b.uint()) + if id == 0 { + break + } + + // Walk over attributes, counting. + n := 0 + b1 := b // Read from copy of b. + b1.uint() + b1.uint8() + for { + tag := b1.uint() + fmt := b1.uint() + if tag == 0 && fmt == 0 { + break + } + n++ + } + if b1.err != nil { + return nil, b1.err + } + + // Walk over attributes again, this time writing them down. + var a abbrev + a.tag = Tag(b.uint()) + a.children = b.uint8() != 0 + a.field = make([]afield, n) + for i := range a.field { + a.field[i].attr = Attr(b.uint()) + a.field[i].fmt = format(b.uint()) + } + b.uint() + b.uint() + + m[id] = a + } + if b.err != nil { + return nil, b.err + } + d.abbrevCache[off] = m + return m, nil +} + +// An entry is a sequence of attribute/value pairs. +type Entry struct { + Offset Offset // offset of Entry in DWARF info + Tag Tag // tag (kind of Entry) + Children bool // whether Entry is followed by children + Field []Field +} + +// A Field is a single attribute/value pair in an Entry. +type Field struct { + Attr Attr + Val interface{} +} + +// Val returns the value associated with attribute Attr in Entry, +// or nil if there is no such attribute. +// +// A common idiom is to merge the check for nil return with +// the check that the value has the expected dynamic type, as in: +// v, ok := e.Val(AttrSibling).(int64); +// +func (e *Entry) Val(a Attr) interface{} { + for _, f := range e.Field { + if f.Attr == a { + return f.Val + } + } + return nil +} + +// An Offset represents the location of an Entry within the DWARF info. +// (See Reader.Seek.) +type Offset uint32 + +// Entry reads a single entry from buf, decoding +// according to the given abbreviation table. +func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry { + off := b.off + id := uint32(b.uint()) + if id == 0 { + return &Entry{} + } + a, ok := atab[id] + if !ok { + b.error("unknown abbreviation table index") + return nil + } + e := &Entry{ + Offset: off, + Tag: a.tag, + Children: a.children, + Field: make([]Field, len(a.field)), + } + for i := range e.Field { + e.Field[i].Attr = a.field[i].attr + fmt := a.field[i].fmt + if fmt == formIndirect { + fmt = format(b.uint()) + } + var val interface{} + switch fmt { + default: + b.error("unknown entry attr format 0x" + strconv.FormatInt(int64(fmt), 16)) + + // address + case formAddr: + val = b.addr() + + // block + case formDwarfBlock1: + val = b.bytes(int(b.uint8())) + case formDwarfBlock2: + val = b.bytes(int(b.uint16())) + case formDwarfBlock4: + val = b.bytes(int(b.uint32())) + case formDwarfBlock: + val = b.bytes(int(b.uint())) + + // constant + case formData1: + val = int64(b.uint8()) + case formData2: + val = int64(b.uint16()) + case formData4: + val = int64(b.uint32()) + case formData8: + val = int64(b.uint64()) + case formSdata: + val = int64(b.int()) + case formUdata: + val = int64(b.uint()) + + // flag + case formFlag: + val = b.uint8() == 1 + // New in DWARF 4. + case formFlagPresent: + // The attribute is implicitly indicated as present, and no value is + // encoded in the debugging information entry itself. + val = true + + // reference to other entry + case formRefAddr: + vers := b.format.version() + if vers == 0 { + b.error("unknown version for DW_FORM_ref_addr") + } else if vers == 2 { + val = Offset(b.addr()) + } else { + is64, known := b.format.dwarf64() + if !known { + b.error("unknown size for DW_FORM_ref_addr") + } else if is64 { + val = Offset(b.uint64()) + } else { + val = Offset(b.uint32()) + } + } + case formRef1: + val = Offset(b.uint8()) + ubase + case formRef2: + val = Offset(b.uint16()) + ubase + case formRef4: + val = Offset(b.uint32()) + ubase + case formRef8: + val = Offset(b.uint64()) + ubase + case formRefUdata: + val = Offset(b.uint()) + ubase + + // string + case formString: + val = b.string() + case formStrp: + off := b.uint32() // offset into .debug_str + if b.err != nil { + return nil + } + b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str) + b1.skip(int(off)) + val = b1.string() + if b1.err != nil { + b.err = b1.err + return nil + } + + // lineptr, loclistptr, macptr, rangelistptr + // New in DWARF 4, but clang can generate them with -gdwarf-2. + // Section reference, replacing use of formData4 and formData8. + case formSecOffset, formGnuRefAlt, formGnuStrpAlt: + is64, known := b.format.dwarf64() + if !known { + b.error("unknown size for form 0x" + strconv.FormatInt(int64(fmt), 16)) + } else if is64 { + val = int64(b.uint64()) + } else { + val = int64(b.uint32()) + } + + // exprloc + // New in DWARF 4. + case formExprloc: + val = b.bytes(int(b.uint())) + + // reference + // New in DWARF 4. + case formRefSig8: + // 64-bit type signature. + val = b.uint64() + } + e.Field[i].Val = val + } + if b.err != nil { + return nil + } + return e +} + +// A Reader allows reading Entry structures from a DWARF ``info'' section. +// The Entry structures are arranged in a tree. The Reader's Next function +// return successive entries from a pre-order traversal of the tree. +// If an entry has children, its Children field will be true, and the children +// follow, terminated by an Entry with Tag 0. +type Reader struct { + b buf + d *Data + err error + unit int + lastChildren bool // .Children of last entry returned by Next + lastSibling Offset // .Val(AttrSibling) of last entry returned by Next +} + +// Reader returns a new Reader for Data. +// The reader is positioned at byte offset 0 in the DWARF ``info'' section. +func (d *Data) Reader() *Reader { + r := &Reader{d: d} + r.Seek(0) + return r +} + +// AddressSize returns the size in bytes of addresses in the current compilation +// unit. +func (r *Reader) AddressSize() int { + return r.d.unit[r.unit].asize +} + +// Seek positions the Reader at offset off in the encoded entry stream. +// Offset 0 can be used to denote the first entry. +func (r *Reader) Seek(off Offset) { + d := r.d + r.err = nil + r.lastChildren = false + if off == 0 { + if len(d.unit) == 0 { + return + } + u := &d.unit[0] + r.unit = 0 + r.b = makeBuf(r.d, u, "info", u.off, u.data) + return + } + + // TODO(rsc): binary search (maybe a new package) + var i int + var u *unit + for i = range d.unit { + u = &d.unit[i] + if u.off <= off && off < u.off+Offset(len(u.data)) { + r.unit = i + r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:]) + return + } + } + r.err = errors.New("offset out of range") +} + +// maybeNextUnit advances to the next unit if this one is finished. +func (r *Reader) maybeNextUnit() { + for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) { + r.unit++ + u := &r.d.unit[r.unit] + r.b = makeBuf(r.d, u, "info", u.off, u.data) + } +} + +// Next reads the next entry from the encoded entry stream. +// It returns nil, nil when it reaches the end of the section. +// It returns an error if the current offset is invalid or the data at the +// offset cannot be decoded as a valid Entry. +func (r *Reader) Next() (*Entry, error) { + if r.err != nil { + return nil, r.err + } + r.maybeNextUnit() + if len(r.b.data) == 0 { + return nil, nil + } + u := &r.d.unit[r.unit] + e := r.b.entry(u.atable, u.base) + if r.b.err != nil { + r.err = r.b.err + return nil, r.err + } + if e != nil { + r.lastChildren = e.Children + if r.lastChildren { + r.lastSibling, _ = e.Val(AttrSibling).(Offset) + } + } else { + r.lastChildren = false + } + return e, nil +} + +// SkipChildren skips over the child entries associated with +// the last Entry returned by Next. If that Entry did not have +// children or Next has not been called, SkipChildren is a no-op. +func (r *Reader) SkipChildren() { + if r.err != nil || !r.lastChildren { + return + } + + // If the last entry had a sibling attribute, + // that attribute gives the offset of the next + // sibling, so we can avoid decoding the + // child subtrees. + if r.lastSibling >= r.b.off { + r.Seek(r.lastSibling) + return + } + + for { + e, err := r.Next() + if err != nil || e == nil || e.Tag == 0 { + break + } + if e.Children { + r.SkipChildren() + } + } +} + +// clone returns a copy of the reader. This is used by the typeReader +// interface. +func (r *Reader) clone() typeReader { + return r.d.Reader() +} + +// offset returns the current buffer offset. This is used by the +// typeReader interface. +func (r *Reader) offset() Offset { + return r.b.off +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/frame.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/frame.go new file mode 100644 index 00000000..56cae8d8 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/frame.go @@ -0,0 +1,309 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// Mapping from PC to SP offset (called CFA - Canonical Frame Address - in DWARF). +// This value is the offset from the stack pointer to the virtual frame pointer +// (address of zeroth argument) at each PC value in the program. + +package dwarf + +import "fmt" + +// http://www.dwarfstd.org/doc/DWARF4.pdf Section 6.4 page 126 +// We implement only the CFA column of the table, not the location +// information about other registers. In other words, we implement +// only what we need to understand Go programs compiled by gc. + +// PCToSPOffset returns the offset, at the specified PC, to add to the +// SP to reach the virtual frame pointer, which corresponds to the +// address of the zeroth argument of the function, the word on the +// stack immediately above the return PC. +func (d *Data) PCToSPOffset(pc uint64) (offset int64, err error) { + if len(d.frame) == 0 { + return 0, fmt.Errorf("PCToSPOffset: no frame table") + } + var m frameMachine + // Assume the first info unit is the same as us. Extremely likely. TODO? + if len(d.unit) == 0 { + return 0, fmt.Errorf("PCToSPOffset: no info section") + } + buf := makeBuf(d, &d.unit[0], "frame", 0, d.frame) + for len(buf.data) > 0 { + offset, err := m.evalCompilationUnit(&buf, pc) + if err != nil { + return 0, err + } + return offset, nil + } + return 0, fmt.Errorf("PCToSPOffset: no frame defined for PC %#x", pc) +} + +// Call Frame instructions. Figure 40, page 181. +// Structure is high two bits plus low 6 bits specified by + in comment. +// Some take one or two operands. +const ( + frameNop = 0<<6 + 0x00 + frameAdvanceLoc = 1<<6 + 0x00 // + delta + frameOffset = 2<<6 + 0x00 // + register op: ULEB128 offset + frameRestore = 3<<6 + 0x00 // + register + frameSetLoc = 0<<6 + 0x01 // op: address + frameAdvanceLoc1 = 0<<6 + 0x02 // op: 1-byte delta + frameAdvanceLoc2 = 0<<6 + 0x03 // op: 2-byte delta + frameAdvanceLoc4 = 0<<6 + 0x04 // op: 4-byte delta + frameOffsetExtended = 0<<6 + 0x05 // ops: ULEB128 register ULEB128 offset + frameRestoreExtended = 0<<6 + 0x06 // op: ULEB128 register + frameUndefined = 0<<6 + 0x07 // op: ULEB128 register + frameSameValue = 0<<6 + 0x08 // op: ULEB128 register + frameRegister = 0<<6 + 0x09 // op: ULEB128 register ULEB128 register + frameRememberState = 0<<6 + 0x0a + frameRestoreState = 0<<6 + 0x0b + frameDefCFA = 0<<6 + 0x0c // op: ULEB128 register ULEB128 offset + frameDefCFARegister = 0<<6 + 0x0d // op: ULEB128 register + frameDefCFAOffset = 0<<6 + 0x0e // op: ULEB128 offset + frameDefCFAExpression = 0<<6 + 0x0f // op: BLOCK + frameExpression = 0<<6 + 0x10 // op: ULEB128 register BLOCK + frameOffsetExtendedSf = 0<<6 + 0x11 // op: ULEB128 register SLEB128 offset + frameDefCFASf = 0<<6 + 0x12 // op: ULEB128 register SLEB128 offset + frameDefCFAOffsetSf = 0<<6 + 0x13 // op: SLEB128 offset + frameValOffset = 0<<6 + 0x14 // op: ULEB128 ULEB128 + frameValOffsetSf = 0<<6 + 0x15 // op: ULEB128 SLEB128 + frameValExpression = 0<<6 + 0x16 // op: ULEB128 BLOCK + frameLoUser = 0<<6 + 0x1c + frameHiUser = 0<<6 + 0x3f +) + +// frameMachine represents the PC/SP engine. +// Section 6.4, page 129. +type frameMachine struct { + // Initial values from CIE. + version uint8 // Version number, "independent of DWARF version" + augmentation string // Augmentation; treated as unexpected for now. TODO. + addressSize uint8 // In DWARF v4 and above. Size of a target address. + segmentSize uint8 // In DWARF v4 and above. Size of a segment selector. + codeAlignmentFactor uint64 // Unit of code size in advance instructions. + dataAlignmentFactor int64 // Unit of data size in certain offset instructions. + returnAddressRegister int // Pseudo-register (actually data column) representing return address. + returnRegisterOffset int64 // Offset to saved PC from CFA in bytes. + // CFA definition. + cfaRegister int // Which register represents the SP. + cfaOffset int64 // CFA offset value. + // Running machine. + location uint64 +} + +// evalCompilationUnit scans the frame data for one compilation unit to retrieve +// the offset information for the specified pc. +func (m *frameMachine) evalCompilationUnit(b *buf, pc uint64) (int64, error) { + err := m.parseCIE(b) + if err != nil { + return 0, err + } + for { + offset, found, err := m.scanFDE(b, pc) + if err != nil { + return 0, err + } + if found { + return offset, nil + } + } +} + +// parseCIE assumes the incoming buffer starts with a CIE block and parses it +// to initialize a frameMachine. +func (m *frameMachine) parseCIE(allBuf *buf) error { + length := int(allBuf.uint32()) + if len(allBuf.data) < length { + return fmt.Errorf("CIE parse error: too short") + } + // Create buffer for just this section. + b := allBuf.slice(length) + cie := b.uint32() + if cie != 0xFFFFFFFF { + return fmt.Errorf("CIE parse error: not CIE: %x", cie) + } + m.version = b.uint8() + if m.version != 3 && m.version != 4 { + return fmt.Errorf("CIE parse error: unsupported version %d", m.version) + } + m.augmentation = b.string() + if len(m.augmentation) > 0 { + return fmt.Errorf("CIE: can't handled augmentation string %q", m.augmentation) + } + if m.version >= 4 { + m.addressSize = b.uint8() + m.segmentSize = b.uint8() + } else { + // Unused. Gc generates version 3, so these values will not be + // set, but they are also not used so it's OK. + } + m.codeAlignmentFactor = b.uint() + m.dataAlignmentFactor = b.int() + m.returnAddressRegister = int(b.uint()) + + // Initial instructions. At least for Go, establishes SP register number + // and initial value of CFA offset at start of function. + _, err := m.run(&b, ^uint64(0)) + if err != nil { + return err + } + + // There's padding, but we can ignore it. + return nil +} + +// scanFDE assumes the incoming buffer starts with a FDE block and parses it +// to run a frameMachine and, if the PC is represented in its range, return +// the CFA offset for that PC. The boolean returned reports whether the +// PC is in range for this FDE. +func (m *frameMachine) scanFDE(allBuf *buf, pc uint64) (int64, bool, error) { + length := int(allBuf.uint32()) + if len(allBuf.data) < length { + return 0, false, fmt.Errorf("FDE parse error: too short") + } + if length <= 0 { + if length == 0 { + // EOF. + return 0, false, fmt.Errorf("PC %#x not found in PC/SP table", pc) + } + return 0, false, fmt.Errorf("bad FDE length %d", length) + } + // Create buffer for just this section. + b := allBuf.slice(length) + cieOffset := b.uint32() // TODO assumes 32 bits. + // Expect 0: first CIE in this segment. TODO. + if cieOffset != 0 { + return 0, false, fmt.Errorf("FDE parse error: bad CIE offset: %.2x", cieOffset) + } + // Initial location. + m.location = b.addr() + addressRange := b.addr() + // If the PC is not in this function, there's no point in executing the instructions. + if pc < m.location || m.location+addressRange <= pc { + return 0, false, nil + } + // The PC appears in this FDE. Scan to find the location. + offset, err := m.run(&b, pc) + if err != nil { + return 0, false, err + } + + // There's padding, but we can ignore it. + return offset, true, nil +} + +// run executes the instructions in the buffer, which has been sliced to contain +// only the data for this block. When we run out of data, we return. +// Since we are only called when we know the PC is in this block, reaching +// EOF is not an error, it just means the final CFA definition matches the +// tail of the block that holds the PC. +// The return value is the CFA at the end of the block or the PC, whichever +// comes first. +func (m *frameMachine) run(b *buf, pc uint64) (int64, error) { + // We run the machine at location == PC because if the PC is at the first + // instruction of a block, the definition of its offset arrives as an + // offset-defining operand after the PC is set to that location. + for m.location <= pc && len(b.data) > 0 { + op := b.uint8() + // Ops with embedded operands + switch op & 0xC0 { + case frameAdvanceLoc: // (6.4.2.1) + // delta in low bits + m.location += uint64(op & 0x3F) + continue + case frameOffset: // (6.4.2.3) + // Register in low bits; ULEB128 offset. + // For Go binaries we only see this in the CIE for the return address register. + if int(op&0x3F) != m.returnAddressRegister { + return 0, fmt.Errorf("invalid frameOffset register R%d should be R%d", op&0x3f, m.returnAddressRegister) + } + m.returnRegisterOffset = int64(b.uint()) * m.dataAlignmentFactor + continue + case frameRestore: // (6.4.2.3) + // register in low bits + return 0, fmt.Errorf("unimplemented frameRestore(R%d)\n", op&0x3F) + } + + // The remaining ops do not have embedded operands. + + switch op { + // Row creation instructions (6.4.2.1) + case frameNop: + case frameSetLoc: // op: address + return 0, fmt.Errorf("unimplemented setloc") // what size is operand? + case frameAdvanceLoc1: // op: 1-byte delta + m.location += uint64(b.uint8()) + case frameAdvanceLoc2: // op: 2-byte delta + m.location += uint64(b.uint16()) + case frameAdvanceLoc4: // op: 4-byte delta + m.location += uint64(b.uint32()) + + // CFA definition instructions (6.4.2.2) + case frameDefCFA: // op: ULEB128 register ULEB128 offset + m.cfaRegister = int(b.int()) + m.cfaOffset = int64(b.uint()) + case frameDefCFASf: // op: ULEB128 register SLEB128 offset + return 0, fmt.Errorf("unimplemented frameDefCFASf") + case frameDefCFARegister: // op: ULEB128 register + return 0, fmt.Errorf("unimplemented frameDefCFARegister") + case frameDefCFAOffset: // op: ULEB128 offset + return 0, fmt.Errorf("unimplemented frameDefCFAOffset") + case frameDefCFAOffsetSf: // op: SLEB128 offset + offset := b.int() + m.cfaOffset = offset * m.dataAlignmentFactor + // TODO: Verify we are using a factored offset. + case frameDefCFAExpression: // op: BLOCK + return 0, fmt.Errorf("unimplemented frameDefCFAExpression") + + // Register Rule instructions (6.4.2.3) + case frameOffsetExtended: // ops: ULEB128 register ULEB128 offset + // The same as frameOffset, but with the register specified in an operand. + reg := b.uint() + // For Go binaries we only see this in the CIE for the return address register. + if reg != uint64(m.returnAddressRegister) { + return 0, fmt.Errorf("invalid frameOffsetExtended: register R%d should be R%d", reg, m.returnAddressRegister) + } + m.returnRegisterOffset = int64(b.uint()) * m.dataAlignmentFactor + case frameRestoreExtended: // op: ULEB128 register + return 0, fmt.Errorf("unimplemented frameRestoreExtended") + case frameUndefined: // op: ULEB128 register; unimplemented + return 0, fmt.Errorf("unimplemented frameUndefined") + case frameSameValue: // op: ULEB128 register + return 0, fmt.Errorf("unimplemented frameSameValue") + case frameRegister: // op: ULEB128 register ULEB128 register + return 0, fmt.Errorf("unimplemented frameRegister") + case frameRememberState: + return 0, fmt.Errorf("unimplemented frameRememberState") + case frameRestoreState: + return 0, fmt.Errorf("unimplemented frameRestoreState") + case frameExpression: // op: ULEB128 register BLOCK + return 0, fmt.Errorf("unimplemented frameExpression") + case frameOffsetExtendedSf: // op: ULEB128 register SLEB128 offset + return 0, fmt.Errorf("unimplemented frameOffsetExtended_sf") + case frameValOffset: // op: ULEB128 ULEB128 + return 0, fmt.Errorf("unimplemented frameValOffset") + case frameValOffsetSf: // op: ULEB128 SLEB128 + return 0, fmt.Errorf("unimplemented frameValOffsetSf") + case frameValExpression: // op: ULEB128 BLOCK + return 0, fmt.Errorf("unimplemented frameValExpression") + + default: + if frameLoUser <= op && op <= frameHiUser { + return 0, fmt.Errorf("unknown user-defined frame op %#x", op) + } + return 0, fmt.Errorf("unknown frame op %#x", op) + } + } + return m.cfaOffset, nil +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/frame_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/frame_test.go new file mode 100644 index 00000000..ba4105b7 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/frame_test.go @@ -0,0 +1,158 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 dwarf_test + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf" +) + +var ( + pcspTempDir string + pcsptestBinary string +) + +func doPCToSPTest(self bool) bool { + // For now, only works on amd64 platforms. + if runtime.GOARCH != "amd64" { + return false + } + // Self test reads test binary; only works on Linux or Mac. + if self { + if runtime.GOOS != "linux" && runtime.GOOS != "darwin" { + return false + } + } + // Command below expects "sh", so Unix. + if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { + return false + } + if pcsptestBinary != "" { + return true + } + var err error + pcspTempDir, err = ioutil.TempDir("", "pcsptest") + if err != nil { + panic(err) + } + if strings.Contains(pcspTempDir, " ") { + panic("unexpected space in tempdir") + } + // This command builds pcsptest from testdata/pcsptest.go. + pcsptestBinary = filepath.Join(pcspTempDir, "pcsptest") + command := fmt.Sprintf("go tool compile -o %s.6 testdata/pcsptest.go && go tool link -H %s -o %s %s.6", + pcsptestBinary, runtime.GOOS, pcsptestBinary, pcsptestBinary) + cmd := exec.Command("sh", "-c", command) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + panic(err) + } + return true +} + +func endPCToSPTest() { + if pcspTempDir != "" { + os.RemoveAll(pcspTempDir) + pcspTempDir = "" + pcsptestBinary = "" + } +} + +func TestPCToSPOffset(t *testing.T) { + t.Skip("gets a stack layout it doesn't expect") + + if !doPCToSPTest(false) { + return + } + defer endPCToSPTest() + + data, err := getData(pcsptestBinary) + if err != nil { + t.Fatal(err) + } + entry, err := data.LookupFunction("main.test") + if err != nil { + t.Fatal("lookup startPC:", err) + } + startPC, ok := entry.Val(dwarf.AttrLowpc).(uint64) + if !ok { + t.Fatal(`DWARF data for function "main.test" has no low PC`) + } + endPC, ok := entry.Val(dwarf.AttrHighpc).(uint64) + if !ok { + t.Fatal(`DWARF data for function "main.test" has no high PC`) + } + + const addrSize = 8 // TODO: Assumes amd64. + const argSize = 8 // Defined by int64 arguments in test binary. + + // On 64-bit machines, the first offset must be one address size, + // for the return PC. + offset, err := data.PCToSPOffset(startPC) + if err != nil { + t.Fatal("startPC:", err) + } + if offset != addrSize { + t.Fatalf("expected %d at start of function; got %d", addrSize, offset) + } + // On 64-bit machines, expect some 8s and some 32s. (See the + // comments in testdata/pcsptest.go. + // TODO: The test could be stronger, but not much unless we + // disassemble the binary. + count := make(map[int64]int) + for pc := startPC; pc < endPC; pc++ { + offset, err := data.PCToSPOffset(pc) + if err != nil { + t.Fatal("scanning function:", err) + } + count[offset]++ + } + if len(count) != 2 { + t.Errorf("expected 2 offset values, got %d; counts are: %v", len(count), count) + } + if count[addrSize] == 0 { + t.Errorf("expected some values at offset %d; got %v", addrSize, count) + } + if count[addrSize+3*argSize] == 0 { + t.Errorf("expected some values at offset %d; got %v", addrSize+3*argSize, count) + } +} + +func getData(file string) (*dwarf.Data, error) { + switch runtime.GOOS { + case "linux": + f, err := elf.Open(file) + if err != nil { + return nil, err + } + dwarf, err := f.DWARF() + if err != nil { + return nil, err + } + f.Close() + return dwarf, nil + } + panic("unimplemented DWARF for GOOS=" + runtime.GOOS) +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/line.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/line.go new file mode 100644 index 00000000..e93bec55 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/line.go @@ -0,0 +1,463 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 dwarf + +// This file implements the mapping from PC to lines. +// TODO: Find a way to test this properly. + +// http://www.dwarfstd.org/doc/DWARF4.pdf Section 6.2 page 108 + +import ( + "fmt" + "sort" + "strings" +) + +// PCToLine returns the file and line number corresponding to the PC value. +// It returns an error if a correspondence cannot be found. +func (d *Data) PCToLine(pc uint64) (file string, line uint64, err error) { + c := d.pcToLineEntries + if len(c) == 0 { + return "", 0, fmt.Errorf("PCToLine: no line table") + } + i := sort.Search(len(c), func(i int) bool { return c[i].pc > pc }) - 1 + // c[i] is now the entry in pcToLineEntries with the largest pc that is not + // larger than the query pc. + // The search has failed if: + // - All pcs in c were larger than the query pc (i == -1). + // - c[i] marked the end of a sequence of instructions (c[i].file == 0). + // - c[i] is the last element of c, and isn't the end of a sequence of + // instructions, and the search pc is much larger than c[i].pc. In this + // case, we don't know the range of the last instruction, but the search + // pc is probably past it. + if i == -1 || c[i].file == 0 || (i+1 == len(c) && pc-c[i].pc > 1024) { + return "", 0, fmt.Errorf("no source line defined for PC %#x", pc) + } + if c[i].file >= uint64(len(d.sourceFiles)) { + return "", 0, fmt.Errorf("invalid file number in DWARF data") + } + return d.sourceFiles[c[i].file], c[i].line, nil +} + +// LineToBreakpointPCs returns the PCs that should be used as breakpoints +// corresponding to the given file and line number. +// It returns an empty slice if no PCs were found. +func (d *Data) LineToBreakpointPCs(file string, line uint64) ([]uint64, error) { + compDir := d.compilationDirectory() + + // Find the closest match in the executable for the specified file. + // We choose the file with the largest number of path components matching + // at the end of the name. If there is a tie, we prefer files that are + // under the compilation directory. If there is still a tie, we choose + // the file with the shortest name. + // TODO: handle duplicate file names in the DWARF? + var bestFile struct { + fileNum uint64 // Index of the file in the DWARF data. + components int // Number of matching path components. + length int // Length of the filename. + underComp bool // File is under the compilation directory. + } + for filenum, filename := range d.sourceFiles { + c := matchingPathComponentSuffixSize(filename, file) + underComp := strings.HasPrefix(filename, compDir) + better := false + if c != bestFile.components { + better = c > bestFile.components + } else if underComp != bestFile.underComp { + better = underComp + } else { + better = len(filename) < bestFile.length + } + if better { + bestFile.fileNum = uint64(filenum) + bestFile.components = c + bestFile.length = len(filename) + bestFile.underComp = underComp + } + } + if bestFile.components == 0 { + return nil, fmt.Errorf("couldn't find file %q", file) + } + c := d.lineToPCEntries[bestFile.fileNum] + // c contains all (pc, line) pairs for the appropriate file. + start := sort.Search(len(c), func(i int) bool { return c[i].line >= line }) + end := sort.Search(len(c), func(i int) bool { return c[i].line > line }) + // c[i].line == line for all i in the range [start, end). + pcs := make([]uint64, 0, end-start) + for i := start; i < end; i++ { + pcs = append(pcs, c[i].pc) + } + return pcs, nil +} + +// compilationDirectory finds the first compilation unit entry in d and returns +// the compilation directory contained in it. +// If it fails, it returns the empty string. +func (d *Data) compilationDirectory() string { + r := d.Reader() + for { + entry, err := r.Next() + if entry == nil || err != nil { + return "" + } + if entry.Tag == TagCompileUnit { + name, _ := entry.Val(AttrCompDir).(string) + return name + } + } +} + +// matchingPathComponentSuffixSize returns the largest n such that the last n +// components of the paths p1 and p2 are equal. +// e.g. matchingPathComponentSuffixSize("a/b/x/y.go", "b/a/x/y.go") returns 2. +func matchingPathComponentSuffixSize(p1, p2 string) int { + // TODO: deal with other path separators. + c1 := strings.Split(p1, "/") + c2 := strings.Split(p2, "/") + min := len(c1) + if len(c2) < min { + min = len(c2) + } + var n int + for n = 0; n < min; n++ { + if c1[len(c1)-1-n] != c2[len(c2)-1-n] { + break + } + } + return n +} + +// Standard opcodes. Figure 37, page 178. +// If an opcode >= lineMachine.prologue.opcodeBase, it is a special +// opcode rather than the opcode defined in this table. +const ( + lineStdCopy = 0x01 + lineStdAdvancePC = 0x02 + lineStdAdvanceLine = 0x03 + lineStdSetFile = 0x04 + lineStdSetColumn = 0x05 + lineStdNegateStmt = 0x06 + lineStdSetBasicBlock = 0x07 + lineStdConstAddPC = 0x08 + lineStdFixedAdvancePC = 0x09 + lineStdSetPrologueEnd = 0x0a + lineStdSetEpilogueBegin = 0x0b + lineStdSetISA = 0x0c +) + +// Extended opcodes. Figure 38, page 179. +const ( + lineStartExtendedOpcode = 0x00 // Not defined as a named constant in the spec. + lineExtEndSequence = 0x01 + lineExtSetAddress = 0x02 + lineExtDefineFile = 0x03 + lineExtSetDiscriminator = 0x04 // New in version 4. + lineExtLoUser = 0x80 + lineExtHiUser = 0xff +) + +// lineHeader holds the information stored in the header of the line table for a +// single compilation unit. +// Section 6.2.4, page 112. +type lineHeader struct { + unitLength int + version int + headerLength int + minInstructionLength int + maxOpsPerInstruction int + defaultIsStmt bool + lineBase int + lineRange int + opcodeBase byte + stdOpcodeLengths []byte + include []string // entry 0 is empty; means current directory + file []lineFile // entry 0 is empty. +} + +// lineFile represents a file name stored in the PC/line table, usually in the header. +type lineFile struct { + name string + index int // index into include directories + time int // implementation-defined time of last modification + length int // length in bytes, 0 if not available. +} + +// lineMachine holds the registers evaluated during executing of the PC/line mapping engine. +// Section 6.2.2, page 109. +// A .debug_line section consists of multiple line number programs, one for each compilation unit. +type lineMachine struct { + // The program-counter value corresponding to a machine instruction generated by the compiler. + address uint64 + + // An unsigned integer representing the index of an operation within a VLIW + // instruction. The index of the first operation is 0. For non-VLIW + // architectures, this register will always be 0. + // The address and op_index registers, taken together, form an operation + // pointer that can reference any individual operation with the instruction + // stream. + opIndex uint64 + + // An unsigned integer indicating the identity of the source file corresponding to a machine instruction. + file uint64 + + // An unsigned integer indicating a source line number. Lines are numbered + // beginning at 1. The compiler may emit the value 0 in cases where an + // instruction cannot be attributed to any source line. + line uint64 + + // An unsigned integer indicating a column number within a source line. + // Columns are numbered beginning at 1. The value 0 is reserved to indicate + // that a statement begins at the “left edge” of the line. + column uint64 + + // A boolean indicating that the current instruction is a recommended + // breakpoint location. A recommended breakpoint location is intended to + // “represent” a line, a statement and/or a semantically distinct subpart of a + // statement. + isStmt bool + + // A boolean indicating that the current instruction is the beginning of a basic + // block. + basicBlock bool + + // A boolean indicating that the current address is that of the first byte after + // the end of a sequence of target machine instructions. end_sequence + // terminates a sequence of lines; therefore other information in the same + // row is not meaningful. + endSequence bool + + // A boolean indicating that the current address is one (of possibly many) + // where execution should be suspended for an entry breakpoint of a + // function. + prologueEnd bool + + // A boolean indicating that the current address is one (of possibly many) + // where execution should be suspended for an exit breakpoint of a function. + epilogueBegin bool + + // An unsigned integer whose value encodes the applicable instruction set + // architecture for the current instruction. + // The encoding of instruction sets should be shared by all users of a given + // architecture. It is recommended that this encoding be defined by the ABI + // authoring committee for each architecture. + isa uint64 + + // An unsigned integer identifying the block to which the current instruction + // belongs. Discriminator values are assigned arbitrarily by the DWARF + // producer and serve to distinguish among multiple blocks that may all be + // associated with the same source file, line, and column. Where only one + // block exists for a given source position, the discriminator value should be + // zero. + discriminator uint64 + + // The header for the current compilation unit. + // Not an actual register, but stored here for cleanliness. + header lineHeader + + // Offset in buf of the end of the line number program for the current unit. + unitEndOff Offset +} + +// parseHeader parses the header describing the compilation unit in the line +// table starting at the specified offset. +func (m *lineMachine) parseHeader(b *buf) error { + m.header = lineHeader{} + m.header.unitLength = int(b.uint32()) // Note: We are assuming 32-bit DWARF format. + m.unitEndOff = b.off + Offset(m.header.unitLength) + if m.header.unitLength > len(b.data) { + return fmt.Errorf("DWARF: bad PC/line header length") + } + m.header.version = int(b.uint16()) + m.header.headerLength = int(b.uint32()) + m.header.minInstructionLength = int(b.uint8()) + if m.header.version >= 4 { + m.header.maxOpsPerInstruction = int(b.uint8()) + } else { + m.header.maxOpsPerInstruction = 1 + } + m.header.defaultIsStmt = b.uint8() != 0 + m.header.lineBase = int(int8(b.uint8())) + m.header.lineRange = int(b.uint8()) + m.header.opcodeBase = b.uint8() + m.header.stdOpcodeLengths = make([]byte, m.header.opcodeBase-1) + copy(m.header.stdOpcodeLengths, b.bytes(int(m.header.opcodeBase-1))) + m.header.include = make([]string, 1) // First entry is empty; file index entries are 1-indexed. + // Includes + for { + name := b.string() + if name == "" { + break + } + m.header.include = append(m.header.include, name) + } + // Files + // Files are 1-indexed in line number program, but we'll deal with that in Data.buildLineCaches. + // Here, just collect the filenames. + for { + name := b.string() + if name == "" { + break + } + index := b.uint() + time := b.uint() + length := b.uint() + f := lineFile{ + name: name, + index: int(index), + time: int(time), + length: int(length), + } + m.header.file = append(m.header.file, f) + } + return nil +} + +// Special opcodes, page 117. +// There are seven steps to processing special opcodes. We break them up here +// because the caller needs to output a row between steps 2 and 4, and because +// we need to perform just step 2 for the opcode DW_LNS_const_add_pc. + +func (m *lineMachine) specialOpcodeStep1(opcode byte) { + adjustedOpcode := int(opcode - m.header.opcodeBase) + lineAdvance := m.header.lineBase + (adjustedOpcode % m.header.lineRange) + m.line += uint64(lineAdvance) +} + +func (m *lineMachine) specialOpcodeStep2(opcode byte) { + adjustedOpcode := int(opcode - m.header.opcodeBase) + advance := adjustedOpcode / m.header.lineRange + delta := (int(m.opIndex) + advance) / m.header.maxOpsPerInstruction + m.address += uint64(m.header.minInstructionLength * delta) + m.opIndex = (m.opIndex + uint64(advance)) % uint64(m.header.maxOpsPerInstruction) +} + +func (m *lineMachine) specialOpcodeSteps4To7() { + m.basicBlock = false + m.prologueEnd = false + m.epilogueBegin = false + m.discriminator = 0 +} + +// evalCompilationUnit reads the next compilation unit and calls f at each output row. +// Line machine execution continues while f returns true. +func (m *lineMachine) evalCompilationUnit(b *buf, f func(m *lineMachine) (cont bool)) error { + m.reset() + for b.off < m.unitEndOff { + op := b.uint8() + if op >= m.header.opcodeBase { + m.specialOpcodeStep1(op) + m.specialOpcodeStep2(op) + // Step 3 is to output a row, so we call f here. + if !f(m) { + return nil + } + m.specialOpcodeSteps4To7() + continue + } + switch op { + case lineStartExtendedOpcode: + if len(b.data) == 0 { + return fmt.Errorf("DWARF: short extended opcode (1)") + } + size := b.uint() + if uint64(len(b.data)) < size { + return fmt.Errorf("DWARF: short extended opcode (2)") + } + op = b.uint8() + switch op { + case lineExtEndSequence: + m.endSequence = true + if !f(m) { + return nil + } + if len(b.data) == 0 { + return nil + } + m.reset() + case lineExtSetAddress: + m.address = b.addr() + m.opIndex = 0 + case lineExtDefineFile: + return fmt.Errorf("DWARF: unimplemented define_file op") + case lineExtSetDiscriminator: + discriminator := b.uint() + m.discriminator = discriminator + default: + return fmt.Errorf("DWARF: unknown extended opcode %#x", op) + } + case lineStdCopy: + if !f(m) { + return nil + } + m.discriminator = 0 + m.basicBlock = false + m.prologueEnd = false + m.epilogueBegin = false + case lineStdAdvancePC: + advance := b.uint() + delta := (int(m.opIndex) + int(advance)) / m.header.maxOpsPerInstruction + m.address += uint64(m.header.minInstructionLength * delta) + m.opIndex = (m.opIndex + uint64(advance)) % uint64(m.header.maxOpsPerInstruction) + m.basicBlock = false + m.prologueEnd = false + m.epilogueBegin = false + m.discriminator = 0 + case lineStdAdvanceLine: + advance := b.int() + m.line = uint64(int64(m.line) + advance) + case lineStdSetFile: + index := b.uint() + m.file = index + case lineStdSetColumn: + column := b.uint() + m.column = column + case lineStdNegateStmt: + m.isStmt = !m.isStmt + case lineStdSetBasicBlock: + m.basicBlock = true + case lineStdFixedAdvancePC: + m.address += uint64(b.uint16()) + m.opIndex = 0 + case lineStdSetPrologueEnd: + m.prologueEnd = true + case lineStdSetEpilogueBegin: + m.epilogueBegin = true + case lineStdSetISA: + m.isa = b.uint() + case lineStdConstAddPC: + // Update the address and op_index registers. + m.specialOpcodeStep2(255) + default: + panic("not reached") + } + } + return nil +} + +// reset sets the machine's registers to the initial state. Page 111. +func (m *lineMachine) reset() { + m.address = 0 + m.opIndex = 0 + m.file = 1 + m.line = 1 + m.column = 0 + m.isStmt = m.header.defaultIsStmt + m.basicBlock = false + m.endSequence = false + m.prologueEnd = false + m.epilogueBegin = false + m.isa = 0 + m.discriminator = 0 +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/open.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/open.go new file mode 100644 index 00000000..56531cee --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/open.go @@ -0,0 +1,106 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 dwarf provides access to DWARF debugging information loaded from +// executable files, as defined in the DWARF 2.0 Standard at +// http://dwarfstd.org/doc/dwarf-2.0.0.pdf +package dwarf // import "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" + +import "encoding/binary" + +// Data represents the DWARF debugging information +// loaded from an executable file (for example, an ELF or Mach-O executable). +type Data struct { + // raw data + abbrev []byte + aranges []byte + frame []byte + info []byte + line []byte + pubnames []byte + ranges []byte + str []byte + + // parsed data + abbrevCache map[uint32]abbrevTable + order binary.ByteOrder + typeCache map[Offset]Type + typeSigs map[uint64]*typeUnit + unit []unit + sourceFiles []string // All the source files listed in .debug_line, from all the compilation units. + nameCache // map from name to top-level entries in .debug_info. + pcToFuncEntries // cache of .debug_info data for function bounds. + pcToLineEntries // cache of .debug_line data, used for efficient PC-to-line mapping. + lineToPCEntries // cache of .debug_line data, used for efficient line-to-[]PC mapping. +} + +// New returns a new Data object initialized from the given parameters. +// Rather than calling this function directly, clients should typically use +// the DWARF method of the File type of the appropriate package debug/elf, +// debug/macho, or debug/pe. +// +// The []byte arguments are the data from the corresponding debug section +// in the object file; for example, for an ELF object, abbrev is the contents of +// the ".debug_abbrev" section. +func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, error) { + d := &Data{ + abbrev: abbrev, + aranges: aranges, + frame: frame, + info: info, + line: line, + pubnames: pubnames, + ranges: ranges, + str: str, + abbrevCache: make(map[uint32]abbrevTable), + typeCache: make(map[Offset]Type), + typeSigs: make(map[uint64]*typeUnit), + } + + // Sniff .debug_info to figure out byte order. + // bytes 4:6 are the version, a tiny 16-bit number (1, 2, 3). + if len(d.info) < 6 { + return nil, DecodeError{"info", Offset(len(d.info)), "too short"} + } + x, y := d.info[4], d.info[5] + switch { + case x == 0 && y == 0: + return nil, DecodeError{"info", 4, "unsupported version 0"} + case x == 0: + d.order = binary.BigEndian + case y == 0: + d.order = binary.LittleEndian + default: + return nil, DecodeError{"info", 4, "cannot determine byte order"} + } + + u, err := d.parseUnits() + if err != nil { + return nil, err + } + d.unit = u + d.buildInfoCaches() + if err := d.buildLineCaches(); err != nil { + return nil, err + } + return d, nil +} + +// AddTypes will add one .debug_types section to the DWARF data. A +// typical object with DWARF version 4 debug info will have multiple +// .debug_types sections. The name is used for error reporting only, +// and serves to distinguish one .debug_types section from another. +func (d *Data) AddTypes(name string, types []byte) error { + return d.parseTypes(name, types) +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/pclntab_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/pclntab_test.go new file mode 100644 index 00000000..779718b8 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/pclntab_test.go @@ -0,0 +1,154 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// +build go1.10 + +package dwarf_test + +// Stripped-down, simplified version of ../../gosym/pclntab_test.go + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" + + . "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" +) + +var ( + pclineTempDir string + pclinetestBinary string +) + +func dotest(self bool) bool { + // For now, only works on amd64 platforms. + if runtime.GOARCH != "amd64" { + return false + } + // Self test reads test binary; only works on Linux or Mac. + if self { + if runtime.GOOS != "linux" && runtime.GOOS != "darwin" { + return false + } + } + // Command below expects "sh", so Unix. + if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { + return false + } + if pclinetestBinary != "" { + return true + } + var err error + pclineTempDir, err = ioutil.TempDir("", "pclinetest") + if err != nil { + panic(err) + } + if strings.Contains(pclineTempDir, " ") { + panic("unexpected space in tempdir") + } + pclinetestBinary = filepath.Join(pclineTempDir, "pclinetest") + command := fmt.Sprintf("go tool compile -o %s.6 testdata/pclinetest.go && go tool link -H %s -E main -o %s %s.6", + pclinetestBinary, runtime.GOOS, pclinetestBinary, pclinetestBinary) + cmd := exec.Command("sh", "-c", command) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + panic(err) + } + return true +} + +func endtest() { + if pclineTempDir != "" { + os.RemoveAll(pclineTempDir) + pclineTempDir = "" + pclinetestBinary = "" + } +} + +func TestPCAndLine(t *testing.T) { + // TODO(jba): go1.9: use subtests + if !dotest(false) { + return + } + defer endtest() + + data, err := getData(pclinetestBinary) + if err != nil { + t.Fatal(err) + } + + testLineToBreakpointPCs(t, data) + testPCToLine(t, data) +} + +func testPCToLine(t *testing.T, data *Data) { + entry, err := data.LookupFunction("main.main") + if err != nil { + t.Fatal(err) + } + pc, ok := entry.Val(AttrLowpc).(uint64) + if !ok { + t.Fatal(`DWARF data for function "main" has no PC`) + } + for _, tt := range []struct { + offset, want uint64 + }{ + {0, 19}, + {19, 19}, + {33, 20}, + {97, 22}, + {165, 23}, + } { + file, line, err := data.PCToLine(pc + tt.offset) + if err != nil { + t.Fatal(err) + } + if !strings.HasSuffix(file, "/pclinetest.go") { + t.Errorf("got %s; want %s", file, "/pclinetest.go") + } + if line != tt.want { + t.Errorf("line for offset %d: got %d; want %d", tt.offset, line, tt.want) + } + } +} + +func testLineToBreakpointPCs(t *testing.T, data *Data) { + for _, tt := range []struct { + line uint64 + want bool + }{ + {18, false}, + {19, true}, + {20, true}, + {21, false}, + {22, true}, + {23, true}, + {24, false}, + } { + pcs, err := data.LineToBreakpointPCs("pclinetest.go", uint64(tt.line)) + if err != nil { + t.Fatal(err) + } + if got := len(pcs) > 0; got != tt.want { + t.Errorf("line %d: got pcs=%t, want pcs=%t", tt.line, got, tt.want) + + } + } +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/symbol.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/symbol.go new file mode 100644 index 00000000..7bbdf48d --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/symbol.go @@ -0,0 +1,129 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 dwarf + +// This file provides simple methods to access the symbol table by name and address. + +import ( + "fmt" + "regexp" + "sort" +) + +// lookupEntry returns the first Entry for the name. +// If tag is non-zero, only entries with that tag are considered. +func (d *Data) lookupEntry(name string, tag Tag) (*Entry, error) { + x, ok := d.nameCache[name] + if !ok { + return nil, fmt.Errorf("DWARF entry for %q not found", name) + } + for ; x != nil; x = x.link { + if tag == 0 || x.entry.Tag == tag { + return x.entry, nil + } + } + return nil, fmt.Errorf("no DWARF entry for %q with tag %s", name, tag) +} + +// LookupMatchingSymbols returns the names of all top-level entries matching +// the given regular expression. +func (d *Data) LookupMatchingSymbols(nameRE *regexp.Regexp) (result []string, err error) { + for name := range d.nameCache { + if nameRE.MatchString(name) { + result = append(result, name) + } + } + return result, nil +} + +// LookupEntry returns the Entry for the named symbol. +func (d *Data) LookupEntry(name string) (*Entry, error) { + return d.lookupEntry(name, 0) +} + +// LookupFunction returns the entry for a function. +func (d *Data) LookupFunction(name string) (*Entry, error) { + return d.lookupEntry(name, TagSubprogram) +} + +// LookupVariable returns the entry for a (global) variable. +func (d *Data) LookupVariable(name string) (*Entry, error) { + return d.lookupEntry(name, TagVariable) +} + +// EntryLocation returns the address of the object referred to by the given Entry. +func (d *Data) EntryLocation(e *Entry) (uint64, error) { + loc, _ := e.Val(AttrLocation).([]byte) + if len(loc) == 0 { + return 0, fmt.Errorf("DWARF entry has no Location attribute") + } + // TODO: implement the DWARF Location bytecode. What we have here only + // recognizes a program with a single literal opAddr bytecode. + if asize := d.unit[0].asize; loc[0] == opAddr && len(loc) == 1+asize { + switch asize { + case 1: + return uint64(loc[1]), nil + case 2: + return uint64(d.order.Uint16(loc[1:])), nil + case 4: + return uint64(d.order.Uint32(loc[1:])), nil + case 8: + return d.order.Uint64(loc[1:]), nil + } + } + return 0, fmt.Errorf("DWARF entry has an unimplemented Location op") +} + +// EntryType returns the Type for an Entry. +func (d *Data) EntryType(e *Entry) (Type, error) { + off, err := d.EntryTypeOffset(e) + if err != nil { + return nil, err + } + return d.Type(off) +} + +// EntryTypeOffset returns the offset in the given Entry's type attribute. +func (d *Data) EntryTypeOffset(e *Entry) (Offset, error) { + v := e.Val(AttrType) + if v == nil { + return 0, fmt.Errorf("DWARF entry has no Type attribute") + } + off, ok := v.(Offset) + if !ok { + return 0, fmt.Errorf("DWARF entry has an invalid Type attribute") + } + return off, nil +} + +// PCToFunction returns the entry and address for the function containing the +// specified PC. +func (d *Data) PCToFunction(pc uint64) (entry *Entry, lowpc uint64, err error) { + p := d.pcToFuncEntries + if len(p) == 0 { + return nil, 0, fmt.Errorf("no function addresses loaded") + } + i := sort.Search(len(p), func(i int) bool { return p[i].pc > pc }) - 1 + // The search failed if: + // - pc was before the start of any function. + // - The largest function bound not larger than pc was the end of a function, + // not the start of one. + // - The largest function bound not larger than pc was the start of a function + // that we don't know the end of, and the PC is much larger than the start. + if i == -1 || p[i].entry == nil || (i+1 == len(p) && pc-p[i].pc >= 1<<20) { + return nil, 0, fmt.Errorf("no function at %x", pc) + } + return p[i].entry, p[i].pc, nil +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/pclinetest.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/pclinetest.go new file mode 100644 index 00000000..88c3da41 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/pclinetest.go @@ -0,0 +1,23 @@ +// Copyright 2016 Google LLC +// +// 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 main + +import "fmt" + +func main() { + fmt.Print("line 20") + + fmt.Print("line 22") +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/pcsptest.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/pcsptest.go new file mode 100644 index 00000000..96202ffe --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/pcsptest.go @@ -0,0 +1,39 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 main + +import "fmt" + +func main() { + test(1, 2, 3) +} + +// This is the function we examine. After the preamble its stack should be +// pulled down 1*addrSize for the return PC plus 3*8 for the three +// arguments. That will be (1+3)*8=32 on 64-bit machines. +func test(a, b, c int64) int64 { + // Put in enough code that it's not inlined. + for a = 0; a < 100; a++ { + b += c + } + afterTest(a, b, c) + return b +} + +// This function follows test in the binary. We use it to force arguments +// onto the stack and as a delimiter in the text we scan in the test. +func afterTest(a, b, c int64) { + fmt.Println(a, b, c) +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/typedef.c b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/typedef.c new file mode 100644 index 00000000..a9659b30 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/typedef.c @@ -0,0 +1,95 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +/* +Linux ELF: +gcc -gdwarf-2 -m64 -c typedef.c && gcc -gdwarf-2 -m64 -o typedef.elf typedef.o + +OS X Mach-O: +gcc -gdwarf-2 -m64 -c typedef.c -o typedef.macho +*/ +#include + +typedef volatile int* t_ptr_volatile_int; +typedef const char *t_ptr_const_char; +typedef long t_long; +typedef unsigned short t_ushort; +typedef int t_func_int_of_float_double(float, double); +typedef int (*t_ptr_func_int_of_float_double)(float, double); +typedef int (*t_ptr_func_int_of_float_complex)(float complex); +typedef int (*t_ptr_func_int_of_double_complex)(double complex); +typedef int (*t_ptr_func_int_of_long_double_complex)(long double complex); +typedef int *t_func_ptr_int_of_char_schar_uchar(char, signed char, unsigned char); +typedef void t_func_void_of_char(char); +typedef void t_func_void_of_void(void); +typedef void t_func_void_of_ptr_char_dots(char*, ...); +typedef struct my_struct { + volatile int vi; + char x : 1; + int y : 4; + int z[0]; + long long array[40]; + int zz[0]; +} t_my_struct; +typedef struct my_struct1 { + int zz [1]; +} t_my_struct1; +typedef union my_union { + volatile int vi; + char x : 1; + int y : 4; + long long array[40]; +} t_my_union; +typedef enum my_enum { + e1 = 1, + e2 = 2, + e3 = -5, + e4 = 1000000000000000LL, +} t_my_enum; + +typedef struct list t_my_list; +struct list { + short val; + t_my_list *next; +}; + +typedef struct tree { + struct tree *left, *right; + unsigned long long val; +} t_my_tree; + +t_ptr_volatile_int *a2; +t_ptr_const_char **a3a; +t_long *a4; +t_ushort *a5; +t_func_int_of_float_double *a6; +t_ptr_func_int_of_float_double *a7; +t_func_ptr_int_of_char_schar_uchar *a8; +t_func_void_of_char *a9; +t_func_void_of_void *a10; +t_func_void_of_ptr_char_dots *a11; +t_my_struct *a12; +t_my_struct1 *a12a; +t_my_union *a12b; +t_my_enum *a13; +t_my_list *a14; +t_my_tree *a15; +t_ptr_func_int_of_float_complex *a16; +t_ptr_func_int_of_double_complex *a17; +t_ptr_func_int_of_long_double_complex *a18; + +int main() +{ + return 0; +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/typedef.elf b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/typedef.elf new file mode 100755 index 00000000..b2062d2c Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/typedef.elf differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/typedef.elf4 b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/typedef.elf4 new file mode 100644 index 00000000..3d5a5a1b Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/typedef.elf4 differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/typedef.macho b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/typedef.macho new file mode 100644 index 00000000..f75afccc Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/testdata/typedef.macho differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/type.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/type.go new file mode 100644 index 00000000..04722cae --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/type.go @@ -0,0 +1,877 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// DWARF type information structures. +// The format is heavily biased toward C, but for simplicity +// the String methods use a pseudo-Go syntax. + +package dwarf + +import ( + "fmt" + "reflect" + "strconv" +) + +// A Type conventionally represents a pointer to any of the +// specific Type structures (CharType, StructType, etc.). +type Type interface { + Common() *CommonType + String() string + Size() int64 +} + +// A CommonType holds fields common to multiple types. +// If a field is not known or not applicable for a given type, +// the zero value is used. +type CommonType struct { + ByteSize int64 // size of value of this type, in bytes + Name string // name that can be used to refer to type + ReflectKind reflect.Kind // the reflect kind of the type. + Offset Offset // the offset at which this type was read +} + +func (c *CommonType) Common() *CommonType { return c } + +func (c *CommonType) Size() int64 { return c.ByteSize } + +// Basic types + +// A BasicType holds fields common to all basic types. +type BasicType struct { + CommonType + BitSize int64 + BitOffset int64 +} + +func (b *BasicType) Basic() *BasicType { return b } + +func (t *BasicType) String() string { + if t.Name != "" { + return t.Name + } + return "?" +} + +// A CharType represents a signed character type. +type CharType struct { + BasicType +} + +// A UcharType represents an unsigned character type. +type UcharType struct { + BasicType +} + +// An IntType represents a signed integer type. +type IntType struct { + BasicType +} + +// A UintType represents an unsigned integer type. +type UintType struct { + BasicType +} + +// A FloatType represents a floating point type. +type FloatType struct { + BasicType +} + +// A ComplexType represents a complex floating point type. +type ComplexType struct { + BasicType +} + +// A BoolType represents a boolean type. +type BoolType struct { + BasicType +} + +// An AddrType represents a machine address type. +type AddrType struct { + BasicType +} + +// An UnspecifiedType represents an implicit, unknown, ambiguous or nonexistent type. +type UnspecifiedType struct { + BasicType +} + +// qualifiers + +// A QualType represents a type that has the C/C++ "const", "restrict", or "volatile" qualifier. +type QualType struct { + CommonType + Qual string + Type Type +} + +func (t *QualType) String() string { return t.Qual + " " + t.Type.String() } + +func (t *QualType) Size() int64 { return t.Type.Size() } + +// An ArrayType represents a fixed size array type. +type ArrayType struct { + CommonType + Type Type + StrideBitSize int64 // if > 0, number of bits to hold each element + Count int64 // if == -1, an incomplete array, like char x[]. +} + +func (t *ArrayType) String() string { + return "[" + strconv.FormatInt(t.Count, 10) + "]" + t.Type.String() +} + +func (t *ArrayType) Size() int64 { return t.Count * t.Type.Size() } + +// A VoidType represents the C void type. +type VoidType struct { + CommonType +} + +func (t *VoidType) String() string { return "void" } + +// A PtrType represents a pointer type. +type PtrType struct { + CommonType + Type Type +} + +func (t *PtrType) String() string { return "*" + t.Type.String() } + +// A StructType represents a struct, union, or C++ class type. +type StructType struct { + CommonType + StructName string + Kind string // "struct", "union", or "class". + Field []*StructField + Incomplete bool // if true, struct, union, class is declared but not defined +} + +// A StructField represents a field in a struct, union, or C++ class type. +type StructField struct { + Name string + Type Type + ByteOffset int64 + ByteSize int64 + BitOffset int64 // within the ByteSize bytes at ByteOffset + BitSize int64 // zero if not a bit field + Embedded bool +} + +func (t *StructType) String() string { + if t.StructName != "" { + return t.Kind + " " + t.StructName + } + return t.Defn() +} + +func (t *StructType) Defn() string { + s := t.Kind + if t.StructName != "" { + s += " " + t.StructName + } + if t.Incomplete { + s += " /*incomplete*/" + return s + } + s += " {" + for i, f := range t.Field { + if i > 0 { + s += "; " + } + s += f.Name + " " + f.Type.String() + s += "@" + strconv.FormatInt(f.ByteOffset, 10) + if f.BitSize > 0 { + s += " : " + strconv.FormatInt(f.BitSize, 10) + s += "@" + strconv.FormatInt(f.BitOffset, 10) + } + } + s += "}" + return s +} + +// A SliceType represents a Go slice type. It looks like a StructType, describing +// the runtime-internal structure, with extra fields. +type SliceType struct { + StructType + ElemType Type +} + +func (t *SliceType) String() string { + if t.Name != "" { + return t.Name + } + return "[]" + t.ElemType.String() +} + +// A StringType represents a Go string type. It looks like a StructType, describing +// the runtime-internal structure, but we wrap it for neatness. +type StringType struct { + StructType +} + +func (t *StringType) String() string { + if t.Name != "" { + return t.Name + } + return "string" +} + +// An InterfaceType represents a Go interface. +type InterfaceType struct { + TypedefType +} + +func (t *InterfaceType) String() string { + if t.Name != "" { + return t.Name + } + return "Interface" +} + +// An EnumType represents an enumerated type. +// The only indication of its native integer type is its ByteSize +// (inside CommonType). +type EnumType struct { + CommonType + EnumName string + Val []*EnumValue +} + +// An EnumValue represents a single enumeration value. +type EnumValue struct { + Name string + Val int64 +} + +func (t *EnumType) String() string { + s := "enum" + if t.EnumName != "" { + s += " " + t.EnumName + } + s += " {" + for i, v := range t.Val { + if i > 0 { + s += "; " + } + s += v.Name + "=" + strconv.FormatInt(v.Val, 10) + } + s += "}" + return s +} + +// A FuncType represents a function type. +type FuncType struct { + CommonType + ReturnType Type + ParamType []Type +} + +func (t *FuncType) String() string { + s := "func(" + for i, t := range t.ParamType { + if i > 0 { + s += ", " + } + s += t.String() + } + s += ")" + if t.ReturnType != nil { + s += " " + t.ReturnType.String() + } + return s +} + +// A DotDotDotType represents the variadic ... function parameter. +type DotDotDotType struct { + CommonType +} + +func (t *DotDotDotType) String() string { return "..." } + +// A TypedefType represents a named type. +type TypedefType struct { + CommonType + Type Type +} + +func (t *TypedefType) String() string { return t.Name } + +func (t *TypedefType) Size() int64 { return t.Type.Size() } + +// A MapType represents a Go map type. It looks like a TypedefType, describing +// the runtime-internal structure, with extra fields. +type MapType struct { + TypedefType + KeyType Type + ElemType Type +} + +func (t *MapType) String() string { + if t.Name != "" { + return t.Name + } + return "map[" + t.KeyType.String() + "]" + t.ElemType.String() +} + +// A ChanType represents a Go channel type. +type ChanType struct { + TypedefType + ElemType Type +} + +func (t *ChanType) String() string { + if t.Name != "" { + return t.Name + } + return "chan " + t.ElemType.String() +} + +// typeReader is used to read from either the info section or the +// types section. +type typeReader interface { + Seek(Offset) + Next() (*Entry, error) + clone() typeReader + offset() Offset + // AddressSize returns the size in bytes of addresses in the current + // compilation unit. + AddressSize() int +} + +// Type reads the type at off in the DWARF ``info'' section. +func (d *Data) Type(off Offset) (Type, error) { + return d.readType("info", d.Reader(), off, d.typeCache) +} + +func getKind(e *Entry) reflect.Kind { + integer, _ := e.Val(AttrGoKind).(int64) + return reflect.Kind(integer) +} + +// readType reads a type from r at off of name using and updating a +// type cache. +func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type) (Type, error) { + if t, ok := typeCache[off]; ok { + return t, nil + } + r.Seek(off) + e, err := r.Next() + if err != nil { + return nil, err + } + addressSize := r.AddressSize() + if e == nil || e.Offset != off { + return nil, DecodeError{name, off, "no type at offset"} + } + + // Parse type from Entry. + // Must always set typeCache[off] before calling + // d.Type recursively, to handle circular types correctly. + var typ Type + + nextDepth := 0 + + // Get next child; set err if error happens. + next := func() *Entry { + if !e.Children { + return nil + } + // Only return direct children. + // Skip over composite entries that happen to be nested + // inside this one. Most DWARF generators wouldn't generate + // such a thing, but clang does. + // See golang.org/issue/6472. + for { + kid, err1 := r.Next() + if err1 != nil { + err = err1 + return nil + } + if kid == nil { + err = DecodeError{name, r.offset(), "unexpected end of DWARF entries"} + return nil + } + if kid.Tag == 0 { + if nextDepth > 0 { + nextDepth-- + continue + } + return nil + } + if kid.Children { + nextDepth++ + } + if nextDepth > 0 { + continue + } + return kid + } + } + + // Get Type referred to by Entry's attr. + // Set err if error happens. Not having a type is an error. + typeOf := func(e *Entry, attr Attr) Type { + tval := e.Val(attr) + var t Type + switch toff := tval.(type) { + case Offset: + if t, err = d.readType(name, r.clone(), toff, typeCache); err != nil { + return nil + } + case uint64: + if t, err = d.sigToType(toff); err != nil { + return nil + } + default: + // It appears that no Type means "void". + return new(VoidType) + } + return t + } + + switch e.Tag { + case TagArrayType: + // Multi-dimensional array. (DWARF v2 §5.4) + // Attributes: + // AttrType:subtype [required] + // AttrStrideSize: distance in bits between each element of the array + // AttrStride: distance in bytes between each element of the array + // AttrByteSize: size of entire array + // Children: + // TagSubrangeType or TagEnumerationType giving one dimension. + // dimensions are in left to right order. + t := new(ArrayType) + t.Name, _ = e.Val(AttrName).(string) + t.ReflectKind = getKind(e) + typ = t + typeCache[off] = t + if t.Type = typeOf(e, AttrType); err != nil { + goto Error + } + if bytes, ok := e.Val(AttrStride).(int64); ok { + t.StrideBitSize = 8 * bytes + } else if bits, ok := e.Val(AttrStrideSize).(int64); ok { + t.StrideBitSize = bits + } else { + // If there's no stride specified, assume it's the size of the + // array's element type. + t.StrideBitSize = 8 * t.Type.Size() + } + + // Accumulate dimensions, + ndim := 0 + for kid := next(); kid != nil; kid = next() { + // TODO(rsc): Can also be TagEnumerationType + // but haven't seen that in the wild yet. + switch kid.Tag { + case TagSubrangeType: + count, ok := kid.Val(AttrCount).(int64) + if !ok { + // Old binaries may have an upper bound instead. + count, ok = kid.Val(AttrUpperBound).(int64) + if ok { + count++ // Length is one more than upper bound. + } else { + count = -1 // As in x[]. + } + } + if ndim == 0 { + t.Count = count + } else { + // Multidimensional array. + // Create new array type underneath this one. + t.Type = &ArrayType{Type: t.Type, Count: count} + } + ndim++ + case TagEnumerationType: + err = DecodeError{name, kid.Offset, "cannot handle enumeration type as array bound"} + goto Error + } + } + if ndim == 0 { + // LLVM generates this for x[]. + t.Count = -1 + } + + case TagBaseType: + // Basic type. (DWARF v2 §5.1) + // Attributes: + // AttrName: name of base type in programming language of the compilation unit [required] + // AttrEncoding: encoding value for type (encFloat etc) [required] + // AttrByteSize: size of type in bytes [required] + // AttrBitOffset: for sub-byte types, size in bits + // AttrBitSize: for sub-byte types, bit offset of high order bit in the AttrByteSize bytes + name, _ := e.Val(AttrName).(string) + enc, ok := e.Val(AttrEncoding).(int64) + if !ok { + err = DecodeError{name, e.Offset, "missing encoding attribute for " + name} + goto Error + } + switch enc { + default: + err = DecodeError{name, e.Offset, "unrecognized encoding attribute value"} + goto Error + + case encAddress: + typ = new(AddrType) + case encBoolean: + typ = new(BoolType) + case encComplexFloat: + typ = new(ComplexType) + if name == "complex" { + // clang writes out 'complex' instead of 'complex float' or 'complex double'. + // clang also writes out a byte size that we can use to distinguish. + // See issue 8694. + switch byteSize, _ := e.Val(AttrByteSize).(int64); byteSize { + case 8: + name = "complex float" + case 16: + name = "complex double" + } + } + case encFloat: + typ = new(FloatType) + case encSigned: + typ = new(IntType) + case encUnsigned: + typ = new(UintType) + case encSignedChar: + typ = new(CharType) + case encUnsignedChar: + typ = new(UcharType) + } + typeCache[off] = typ + t := typ.(interface { + Basic() *BasicType + }).Basic() + t.Name = name + t.BitSize, _ = e.Val(AttrBitSize).(int64) + t.BitOffset, _ = e.Val(AttrBitOffset).(int64) + t.ReflectKind = getKind(e) + + case TagClassType, TagStructType, TagUnionType: + // Structure, union, or class type. (DWARF v2 §5.5) + // Also Slices and Strings (Go-specific). + // Attributes: + // AttrName: name of struct, union, or class + // AttrByteSize: byte size [required] + // AttrDeclaration: if true, struct/union/class is incomplete + // AttrGoElem: present for slices only. + // Children: + // TagMember to describe one member. + // AttrName: name of member [required] + // AttrType: type of member [required] + // AttrByteSize: size in bytes + // AttrBitOffset: bit offset within bytes for bit fields + // AttrBitSize: bit size for bit fields + // AttrDataMemberLoc: location within struct [required for struct, class] + // There is much more to handle C++, all ignored for now. + t := new(StructType) + t.ReflectKind = getKind(e) + switch t.ReflectKind { + case reflect.Slice: + slice := new(SliceType) + slice.ElemType = typeOf(e, AttrGoElem) + t = &slice.StructType + typ = slice + case reflect.String: + str := new(StringType) + t = &str.StructType + typ = str + default: + typ = t + } + typeCache[off] = typ + switch e.Tag { + case TagClassType: + t.Kind = "class" + case TagStructType: + t.Kind = "struct" + case TagUnionType: + t.Kind = "union" + } + t.Name, _ = e.Val(AttrName).(string) + t.StructName, _ = e.Val(AttrName).(string) + t.Incomplete = e.Val(AttrDeclaration) != nil + t.Field = make([]*StructField, 0, 8) + var lastFieldType Type + var lastFieldBitOffset int64 + for kid := next(); kid != nil; kid = next() { + if kid.Tag == TagMember { + f := new(StructField) + if f.Type = typeOf(kid, AttrType); err != nil { + goto Error + } + switch loc := kid.Val(AttrDataMemberLoc).(type) { + case []byte: + // TODO: Should have original compilation + // unit here, not unknownFormat. + if len(loc) == 0 { + // Empty exprloc. f.ByteOffset=0. + break + } + b := makeBuf(d, unknownFormat{}, "location", 0, loc) + op := b.uint8() + switch op { + case opPlusUconst: + // Handle opcode sequence [DW_OP_plus_uconst ] + f.ByteOffset = int64(b.uint()) + b.assertEmpty() + case opConsts: + // Handle opcode sequence [DW_OP_consts DW_OP_plus] + f.ByteOffset = b.int() + op = b.uint8() + if op != opPlus { + err = DecodeError{name, kid.Offset, fmt.Sprintf("unexpected opcode 0x%x", op)} + goto Error + } + b.assertEmpty() + default: + err = DecodeError{name, kid.Offset, fmt.Sprintf("unexpected opcode 0x%x", op)} + goto Error + } + if b.err != nil { + err = b.err + goto Error + } + case int64: + f.ByteOffset = loc + } + + haveBitOffset := false + f.Name, _ = kid.Val(AttrName).(string) + f.ByteSize, _ = kid.Val(AttrByteSize).(int64) + f.BitOffset, haveBitOffset = kid.Val(AttrBitOffset).(int64) + f.BitSize, _ = kid.Val(AttrBitSize).(int64) + f.Embedded, _ = kid.Val(AttrGoEmbeddedField).(bool) + t.Field = append(t.Field, f) + + bito := f.BitOffset + if !haveBitOffset { + bito = f.ByteOffset * 8 + } + if bito == lastFieldBitOffset && t.Kind != "union" { + // Last field was zero width. Fix array length. + // (DWARF writes out 0-length arrays as if they were 1-length arrays.) + zeroArray(lastFieldType) + } + lastFieldType = f.Type + lastFieldBitOffset = bito + } + } + if t.Kind != "union" { + b, ok := e.Val(AttrByteSize).(int64) + if ok && b*8 == lastFieldBitOffset { + // Final field must be zero width. Fix array length. + zeroArray(lastFieldType) + } + } + + case TagConstType, TagVolatileType, TagRestrictType: + // Type modifier (DWARF v2 §5.2) + // Attributes: + // AttrType: subtype + t := new(QualType) + t.Name, _ = e.Val(AttrName).(string) + t.ReflectKind = getKind(e) + typ = t + typeCache[off] = t + if t.Type = typeOf(e, AttrType); err != nil { + goto Error + } + switch e.Tag { + case TagConstType: + t.Qual = "const" + case TagRestrictType: + t.Qual = "restrict" + case TagVolatileType: + t.Qual = "volatile" + } + + case TagEnumerationType: + // Enumeration type (DWARF v2 §5.6) + // Attributes: + // AttrName: enum name if any + // AttrByteSize: bytes required to represent largest value + // Children: + // TagEnumerator: + // AttrName: name of constant + // AttrConstValue: value of constant + t := new(EnumType) + t.ReflectKind = getKind(e) + typ = t + typeCache[off] = t + t.Name, _ = e.Val(AttrName).(string) + t.EnumName, _ = e.Val(AttrName).(string) + t.Val = make([]*EnumValue, 0, 8) + for kid := next(); kid != nil; kid = next() { + if kid.Tag == TagEnumerator { + f := new(EnumValue) + f.Name, _ = kid.Val(AttrName).(string) + f.Val, _ = kid.Val(AttrConstValue).(int64) + n := len(t.Val) + if n >= cap(t.Val) { + val := make([]*EnumValue, n, n*2) + copy(val, t.Val) + t.Val = val + } + t.Val = t.Val[0 : n+1] + t.Val[n] = f + } + } + + case TagPointerType: + // Type modifier (DWARF v2 §5.2) + // Attributes: + // AttrType: subtype [not required! void* has no AttrType] + // AttrAddrClass: address class [ignored] + t := new(PtrType) + t.Name, _ = e.Val(AttrName).(string) + t.ReflectKind = getKind(e) + typ = t + typeCache[off] = t + if e.Val(AttrType) == nil { + t.Type = &VoidType{} + break + } + t.Type = typeOf(e, AttrType) + + case TagSubroutineType: + // Subroutine type. (DWARF v2 §5.7) + // Attributes: + // AttrType: type of return value if any + // AttrName: possible name of type [ignored] + // AttrPrototyped: whether used ANSI C prototype [ignored] + // Children: + // TagFormalParameter: typed parameter + // AttrType: type of parameter + // TagUnspecifiedParameter: final ... + t := new(FuncType) + t.Name, _ = e.Val(AttrName).(string) + t.ReflectKind = getKind(e) + typ = t + typeCache[off] = t + if t.ReturnType = typeOf(e, AttrType); err != nil { + goto Error + } + t.ParamType = make([]Type, 0, 8) + for kid := next(); kid != nil; kid = next() { + var tkid Type + switch kid.Tag { + default: + continue + case TagFormalParameter: + if tkid = typeOf(kid, AttrType); err != nil { + goto Error + } + case TagUnspecifiedParameters: + tkid = &DotDotDotType{} + } + t.ParamType = append(t.ParamType, tkid) + } + + case TagTypedef: + // Typedef (DWARF v2 §5.3) + // Also maps and channels (Go-specific). + // Attributes: + // AttrName: name [required] + // AttrType: type definition [required] + // AttrGoKey: present for maps. + // AttrGoElem: present for maps and channels. + t := new(TypedefType) + t.ReflectKind = getKind(e) + switch t.ReflectKind { + case reflect.Map: + m := new(MapType) + m.KeyType = typeOf(e, AttrGoKey) + m.ElemType = typeOf(e, AttrGoElem) + t = &m.TypedefType + typ = m + case reflect.Chan: + c := new(ChanType) + c.ElemType = typeOf(e, AttrGoElem) + t = &c.TypedefType + typ = c + case reflect.Interface: + it := new(InterfaceType) + t = &it.TypedefType + typ = it + default: + typ = t + } + typeCache[off] = typ + t.Name, _ = e.Val(AttrName).(string) + t.Type = typeOf(e, AttrType) + + case TagUnspecifiedType: + // Unspecified type (DWARF v3 §5.2) + // Attributes: + // AttrName: name + t := new(UnspecifiedType) + typ = t + typeCache[off] = t + t.Name, _ = e.Val(AttrName).(string) + + default: + err = DecodeError{name, off, "unsupported type tag"} + } + + if err != nil { + goto Error + } + + typ.Common().Offset = off + + { + b, ok := e.Val(AttrByteSize).(int64) + if !ok { + b = -1 + switch t := typ.(type) { + case *TypedefType: + b = t.Type.Size() + case *MapType: + b = t.Type.Size() + case *ChanType: + b = t.Type.Size() + case *InterfaceType: + b = t.Type.Size() + case *PtrType: + b = int64(addressSize) + } + } + typ.Common().ByteSize = b + } + return typ, nil + +Error: + // If the parse fails, take the type out of the cache + // so that the next call with this offset doesn't hit + // the cache and return success. + delete(typeCache, off) + return nil, err +} + +func zeroArray(t Type) { + for { + at, ok := t.(*ArrayType) + if !ok { + break + } + at.Count = 0 + t = at.Type + } +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/type_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/type_test.go new file mode 100644 index 00000000..5be303db --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/type_test.go @@ -0,0 +1,122 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 dwarf_test + +import ( + "testing" + + . "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf" +) + +var typedefTests = map[string]string{ + "t_ptr_volatile_int": "*volatile int", + "t_ptr_const_char": "*const char", + "t_long": "long int", + "t_ushort": "short unsigned int", + "t_func_int_of_float_double": "func(float, double) int", + "t_ptr_func_int_of_float_double": "*func(float, double) int", + "t_ptr_func_int_of_float_complex": "*func(complex float) int", + "t_ptr_func_int_of_double_complex": "*func(complex double) int", + "t_ptr_func_int_of_long_double_complex": "*func(complex long double) int", + "t_func_ptr_int_of_char_schar_uchar": "func(char, signed char, unsigned char) *int", + "t_func_void_of_char": "func(char) void", + "t_func_void_of_void": "func() void", + "t_func_void_of_ptr_char_dots": "func(*char, ...) void", + "t_my_struct": "struct my_struct {vi volatile int@0; x char@4 : 1@7; y int@4 : 4@27; z [0]int@8; array [40]long long int@8; zz [0]int@328}", + "t_my_struct1": "struct my_struct1 {zz [1]int@0}", + "t_my_union": "union my_union {vi volatile int@0; x char@0 : 1@7; y int@0 : 4@28; array [40]long long int@0}", + "t_my_enum": "enum my_enum {e1=1; e2=2; e3=-5; e4=1000000000000000}", + "t_my_list": "struct list {val short int@0; next *t_my_list@8}", + "t_my_tree": "struct tree {left *struct tree@0; right *struct tree@8; val long long unsigned int@16}", +} + +func elfData(t *testing.T, name string) *Data { + f, err := elf.Open(name) + if err != nil { + t.Fatal(err) + } + + d, err := f.DWARF() + if err != nil { + t.Fatal(err) + } + return d +} + +func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf"), "elf") } + +func TestTypedefsELFDwarf4(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf4"), "elf") } + +func testTypedefs(t *testing.T, d *Data, kind string) { + r := d.Reader() + seen := make(map[string]bool) + for { + e, err := r.Next() + if err != nil { + t.Fatal("r.Next:", err) + } + if e == nil { + break + } + if e.Tag == TagTypedef { + typ, err := d.Type(e.Offset) + if err != nil { + t.Fatal("d.Type:", err) + } + t1 := typ.(*TypedefType) + var typstr string + if ts, ok := t1.Type.(*StructType); ok { + typstr = ts.Defn() + } else { + typstr = t1.Type.String() + } + + if want, ok := typedefTests[t1.Name]; ok { + if seen[t1.Name] { + t.Errorf("multiple definitions for %s", t1.Name) + } + seen[t1.Name] = true + if typstr != want { + t.Errorf("%s:\n\thave %s\n\twant %s", t1.Name, typstr, want) + } + } + } + if e.Tag != TagCompileUnit { + r.SkipChildren() + } + } + + for k := range typedefTests { + if !seen[k] { + t.Errorf("missing %s", k) + } + } +} + +func TestTypeForNonTypeEntry(t *testing.T) { + d := elfData(t, "testdata/typedef.elf") + + // The returned entry will be a Subprogram. + ent, err := d.LookupFunction("main") + if err != nil { + t.Fatal("d.LookupFunction:", err) + } + + _, err = d.Type(ent.Offset) + if err == nil { + t.Fatal("nil error for unreadable entry") + } +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/typeunit.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/typeunit.go new file mode 100644 index 00000000..eeb99add --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/typeunit.go @@ -0,0 +1,181 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 dwarf + +import ( + "fmt" + "strconv" +) + +// Parse the type units stored in a DWARF4 .debug_types section. Each +// type unit defines a single primary type and an 8-byte signature. +// Other sections may then use formRefSig8 to refer to the type. + +// The typeUnit format is a single type with a signature. It holds +// the same data as a compilation unit. +type typeUnit struct { + unit + toff Offset // Offset to signature type within data. + name string // Name of .debug_type section. + cache Type // Cache the type, nil to start. +} + +// Parse a .debug_types section. +func (d *Data) parseTypes(name string, types []byte) error { + b := makeBuf(d, unknownFormat{}, name, 0, types) + for len(b.data) > 0 { + base := b.off + dwarf64 := false + n := b.uint32() + if n == 0xffffffff { + n64 := b.uint64() + if n64 != uint64(uint32(n64)) { + b.error("type unit length overflow") + return b.err + } + n = uint32(n64) + dwarf64 = true + } + hdroff := b.off + vers := b.uint16() + if vers != 4 { + b.error("unsupported DWARF version " + strconv.Itoa(int(vers))) + return b.err + } + var ao uint32 + if !dwarf64 { + ao = b.uint32() + } else { + ao64 := b.uint64() + if ao64 != uint64(uint32(ao64)) { + b.error("type unit abbrev offset overflow") + return b.err + } + ao = uint32(ao64) + } + atable, err := d.parseAbbrev(ao) + if err != nil { + return err + } + asize := b.uint8() + sig := b.uint64() + + var toff uint32 + if !dwarf64 { + toff = b.uint32() + } else { + to64 := b.uint64() + if to64 != uint64(uint32(to64)) { + b.error("type unit type offset overflow") + return b.err + } + toff = uint32(to64) + } + + boff := b.off + d.typeSigs[sig] = &typeUnit{ + unit: unit{ + base: base, + off: boff, + data: b.bytes(int(Offset(n) - (b.off - hdroff))), + atable: atable, + asize: int(asize), + vers: int(vers), + is64: dwarf64, + }, + toff: Offset(toff), + name: name, + } + if b.err != nil { + return b.err + } + } + return nil +} + +// Return the type for a type signature. +func (d *Data) sigToType(sig uint64) (Type, error) { + tu := d.typeSigs[sig] + if tu == nil { + return nil, fmt.Errorf("no type unit with signature %v", sig) + } + if tu.cache != nil { + return tu.cache, nil + } + + b := makeBuf(d, tu, tu.name, tu.off, tu.data) + r := &typeUnitReader{d: d, tu: tu, b: b} + t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type)) + if err != nil { + return nil, err + } + + tu.cache = t + return t, nil +} + +// typeUnitReader is a typeReader for a tagTypeUnit. +type typeUnitReader struct { + d *Data + tu *typeUnit + b buf + err error +} + +// Seek to a new position in the type unit. +func (tur *typeUnitReader) Seek(off Offset) { + tur.err = nil + doff := off - tur.tu.off + if doff < 0 || doff >= Offset(len(tur.tu.data)) { + tur.err = fmt.Errorf("%s: offset %d out of range; max %d", tur.tu.name, doff, len(tur.tu.data)) + return + } + tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:]) +} + +// AddressSize returns the size in bytes of addresses in the current type unit. +func (tur *typeUnitReader) AddressSize() int { + return tur.tu.unit.asize +} + +// Next reads the next Entry from the type unit. +func (tur *typeUnitReader) Next() (*Entry, error) { + if tur.err != nil { + return nil, tur.err + } + if len(tur.tu.data) == 0 { + return nil, nil + } + e := tur.b.entry(tur.tu.atable, tur.tu.base) + if tur.b.err != nil { + tur.err = tur.b.err + return nil, tur.err + } + return e, nil +} + +// clone returns a new reader for the type unit. +func (tur *typeUnitReader) clone() typeReader { + return &typeUnitReader{ + d: tur.d, + tu: tur.tu, + b: makeBuf(tur.d, tur.tu, tur.tu.name, tur.tu.off, tur.tu.data), + } +} + +// offset returns the current offset. +func (tur *typeUnitReader) offset() Offset { + return tur.b.off +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/unit.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/unit.go new file mode 100644 index 00000000..ddbfd1dc --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/unit.go @@ -0,0 +1,100 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 dwarf + +import "strconv" + +// DWARF debug info is split into a sequence of compilation units. +// Each unit has its own abbreviation table and address size. + +type unit struct { + base Offset // byte offset of header within the aggregate info + off Offset // byte offset of data within the aggregate info + data []byte + atable abbrevTable + asize int + vers int + is64 bool // True for 64-bit DWARF format +} + +// Implement the dataFormat interface. + +func (u *unit) version() int { + return u.vers +} + +func (u *unit) dwarf64() (bool, bool) { + return u.is64, true +} + +func (u *unit) addrsize() int { + return u.asize +} + +func (d *Data) parseUnits() ([]unit, error) { + // Count units. + nunit := 0 + b := makeBuf(d, unknownFormat{}, "info", 0, d.info) + for len(b.data) > 0 { + len := b.uint32() + if len == 0xffffffff { + len64 := b.uint64() + if len64 != uint64(uint32(len64)) { + b.error("unit length overflow") + break + } + len = uint32(len64) + } + b.skip(int(len)) + nunit++ + } + if b.err != nil { + return nil, b.err + } + + // Again, this time writing them down. + b = makeBuf(d, unknownFormat{}, "info", 0, d.info) + units := make([]unit, nunit) + for i := range units { + u := &units[i] + u.base = b.off + n := b.uint32() + if n == 0xffffffff { + u.is64 = true + n = uint32(b.uint64()) + } + vers := b.uint16() + if vers != 2 && vers != 3 && vers != 4 { + b.error("unsupported DWARF version " + strconv.Itoa(int(vers))) + break + } + u.vers = int(vers) + atable, err := d.parseAbbrev(b.uint32()) + if err != nil { + if b.err == nil { + b.err = err + } + break + } + u.atable = atable + u.asize = int(b.uint8()) + u.off = b.off + u.data = b.bytes(int(n - (2 + 4 + 1))) + } + if b.err != nil { + return nil, b.err + } + return units, nil +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/elf.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/elf.go new file mode 100644 index 00000000..b326713e --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/elf.go @@ -0,0 +1,2993 @@ +/* + * ELF constants and data structures + * + * Derived from: + * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $ + * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $ + * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $ + * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $ + * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $ + * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $ + * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $ + * "System V ABI" (http://www.sco.com/developers/gabi/latest/ch4.eheader.html) + * "ELF for the ARM® 64-bit Architecture (AArch64)" (ARM IHI 0056B) + * "RISC-V ELF psABI specification" (https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md) + * llvm/BinaryFormat/ELF.h - ELF constants and structures + * + * Copyright (c) 1996-1998 John D. Polstra. All rights reserved. + * Copyright (c) 2001 David E. O'Brien + * Portions Copyright 2018 Google LLC. + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +package elf + +import "strconv" + +/* + * Constants + */ + +// Indexes into the Header.Ident array. +const ( + EI_CLASS = 4 /* Class of machine. */ + EI_DATA = 5 /* Data format. */ + EI_VERSION = 6 /* ELF format version. */ + EI_OSABI = 7 /* Operating system / ABI identification */ + EI_ABIVERSION = 8 /* ABI version */ + EI_PAD = 9 /* Start of padding (per SVR4 ABI). */ + EI_NIDENT = 16 /* Size of e_ident array. */ +) + +// Initial magic number for ELF files. +const ELFMAG = "\177ELF" + +// Version is found in Header.Ident[EI_VERSION] and Header.Version. +type Version byte + +const ( + EV_NONE Version = 0 + EV_CURRENT Version = 1 +) + +var versionStrings = []intName{ + {0, "EV_NONE"}, + {1, "EV_CURRENT"}, +} + +func (i Version) String() string { return stringName(uint32(i), versionStrings, false) } +func (i Version) GoString() string { return stringName(uint32(i), versionStrings, true) } + +// Class is found in Header.Ident[EI_CLASS] and Header.Class. +type Class byte + +const ( + ELFCLASSNONE Class = 0 /* Unknown class. */ + ELFCLASS32 Class = 1 /* 32-bit architecture. */ + ELFCLASS64 Class = 2 /* 64-bit architecture. */ +) + +var classStrings = []intName{ + {0, "ELFCLASSNONE"}, + {1, "ELFCLASS32"}, + {2, "ELFCLASS64"}, +} + +func (i Class) String() string { return stringName(uint32(i), classStrings, false) } +func (i Class) GoString() string { return stringName(uint32(i), classStrings, true) } + +// Data is found in Header.Ident[EI_DATA] and Header.Data. +type Data byte + +const ( + ELFDATANONE Data = 0 /* Unknown data format. */ + ELFDATA2LSB Data = 1 /* 2's complement little-endian. */ + ELFDATA2MSB Data = 2 /* 2's complement big-endian. */ +) + +var dataStrings = []intName{ + {0, "ELFDATANONE"}, + {1, "ELFDATA2LSB"}, + {2, "ELFDATA2MSB"}, +} + +func (i Data) String() string { return stringName(uint32(i), dataStrings, false) } +func (i Data) GoString() string { return stringName(uint32(i), dataStrings, true) } + +// OSABI is found in Header.Ident[EI_OSABI] and Header.OSABI. +type OSABI byte + +const ( + ELFOSABI_NONE OSABI = 0 /* UNIX System V ABI */ + ELFOSABI_HPUX OSABI = 1 /* HP-UX operating system */ + ELFOSABI_NETBSD OSABI = 2 /* NetBSD */ + ELFOSABI_LINUX OSABI = 3 /* GNU/Linux */ + ELFOSABI_HURD OSABI = 4 /* GNU/Hurd */ + ELFOSABI_86OPEN OSABI = 5 /* 86Open common IA32 ABI */ + ELFOSABI_SOLARIS OSABI = 6 /* Solaris */ + ELFOSABI_AIX OSABI = 7 /* AIX */ + ELFOSABI_IRIX OSABI = 8 /* IRIX */ + ELFOSABI_FREEBSD OSABI = 9 /* FreeBSD */ + ELFOSABI_TRU64 OSABI = 10 /* TRU64 UNIX */ + ELFOSABI_MODESTO OSABI = 11 /* Novell Modesto */ + ELFOSABI_OPENBSD OSABI = 12 /* OpenBSD */ + ELFOSABI_OPENVMS OSABI = 13 /* Open VMS */ + ELFOSABI_NSK OSABI = 14 /* HP Non-Stop Kernel */ + ELFOSABI_AROS OSABI = 15 /* Amiga Research OS */ + ELFOSABI_FENIXOS OSABI = 16 /* The FenixOS highly scalable multi-core OS */ + ELFOSABI_CLOUDABI OSABI = 17 /* Nuxi CloudABI */ + ELFOSABI_ARM OSABI = 97 /* ARM */ + ELFOSABI_STANDALONE OSABI = 255 /* Standalone (embedded) application */ +) + +var osabiStrings = []intName{ + {0, "ELFOSABI_NONE"}, + {1, "ELFOSABI_HPUX"}, + {2, "ELFOSABI_NETBSD"}, + {3, "ELFOSABI_LINUX"}, + {4, "ELFOSABI_HURD"}, + {5, "ELFOSABI_86OPEN"}, + {6, "ELFOSABI_SOLARIS"}, + {7, "ELFOSABI_AIX"}, + {8, "ELFOSABI_IRIX"}, + {9, "ELFOSABI_FREEBSD"}, + {10, "ELFOSABI_TRU64"}, + {11, "ELFOSABI_MODESTO"}, + {12, "ELFOSABI_OPENBSD"}, + {13, "ELFOSABI_OPENVMS"}, + {14, "ELFOSABI_NSK"}, + {15, "ELFOSABI_AROS"}, + {16, "ELFOSABI_FENIXOS"}, + {17, "ELFOSABI_CLOUDABI"}, + {97, "ELFOSABI_ARM"}, + {255, "ELFOSABI_STANDALONE"}, +} + +func (i OSABI) String() string { return stringName(uint32(i), osabiStrings, false) } +func (i OSABI) GoString() string { return stringName(uint32(i), osabiStrings, true) } + +// Type is found in Header.Type. +type Type uint16 + +const ( + ET_NONE Type = 0 /* Unknown type. */ + ET_REL Type = 1 /* Relocatable. */ + ET_EXEC Type = 2 /* Executable. */ + ET_DYN Type = 3 /* Shared object. */ + ET_CORE Type = 4 /* Core file. */ + ET_LOOS Type = 0xfe00 /* First operating system specific. */ + ET_HIOS Type = 0xfeff /* Last operating system-specific. */ + ET_LOPROC Type = 0xff00 /* First processor-specific. */ + ET_HIPROC Type = 0xffff /* Last processor-specific. */ +) + +var typeStrings = []intName{ + {0, "ET_NONE"}, + {1, "ET_REL"}, + {2, "ET_EXEC"}, + {3, "ET_DYN"}, + {4, "ET_CORE"}, + {0xfe00, "ET_LOOS"}, + {0xfeff, "ET_HIOS"}, + {0xff00, "ET_LOPROC"}, + {0xffff, "ET_HIPROC"}, +} + +func (i Type) String() string { return stringName(uint32(i), typeStrings, false) } +func (i Type) GoString() string { return stringName(uint32(i), typeStrings, true) } + +// Machine is found in Header.Machine. +type Machine uint16 + +const ( + EM_NONE Machine = 0 /* Unknown machine. */ + EM_M32 Machine = 1 /* AT&T WE32100. */ + EM_SPARC Machine = 2 /* Sun SPARC. */ + EM_386 Machine = 3 /* Intel i386. */ + EM_68K Machine = 4 /* Motorola 68000. */ + EM_88K Machine = 5 /* Motorola 88000. */ + EM_860 Machine = 7 /* Intel i860. */ + EM_MIPS Machine = 8 /* MIPS R3000 Big-Endian only. */ + EM_S370 Machine = 9 /* IBM System/370. */ + EM_MIPS_RS3_LE Machine = 10 /* MIPS R3000 Little-Endian. */ + EM_PARISC Machine = 15 /* HP PA-RISC. */ + EM_VPP500 Machine = 17 /* Fujitsu VPP500. */ + EM_SPARC32PLUS Machine = 18 /* SPARC v8plus. */ + EM_960 Machine = 19 /* Intel 80960. */ + EM_PPC Machine = 20 /* PowerPC 32-bit. */ + EM_PPC64 Machine = 21 /* PowerPC 64-bit. */ + EM_S390 Machine = 22 /* IBM System/390. */ + EM_V800 Machine = 36 /* NEC V800. */ + EM_FR20 Machine = 37 /* Fujitsu FR20. */ + EM_RH32 Machine = 38 /* TRW RH-32. */ + EM_RCE Machine = 39 /* Motorola RCE. */ + EM_ARM Machine = 40 /* ARM. */ + EM_SH Machine = 42 /* Hitachi SH. */ + EM_SPARCV9 Machine = 43 /* SPARC v9 64-bit. */ + EM_TRICORE Machine = 44 /* Siemens TriCore embedded processor. */ + EM_ARC Machine = 45 /* Argonaut RISC Core. */ + EM_H8_300 Machine = 46 /* Hitachi H8/300. */ + EM_H8_300H Machine = 47 /* Hitachi H8/300H. */ + EM_H8S Machine = 48 /* Hitachi H8S. */ + EM_H8_500 Machine = 49 /* Hitachi H8/500. */ + EM_IA_64 Machine = 50 /* Intel IA-64 Processor. */ + EM_MIPS_X Machine = 51 /* Stanford MIPS-X. */ + EM_COLDFIRE Machine = 52 /* Motorola ColdFire. */ + EM_68HC12 Machine = 53 /* Motorola M68HC12. */ + EM_MMA Machine = 54 /* Fujitsu MMA. */ + EM_PCP Machine = 55 /* Siemens PCP. */ + EM_NCPU Machine = 56 /* Sony nCPU. */ + EM_NDR1 Machine = 57 /* Denso NDR1 microprocessor. */ + EM_STARCORE Machine = 58 /* Motorola Star*Core processor. */ + EM_ME16 Machine = 59 /* Toyota ME16 processor. */ + EM_ST100 Machine = 60 /* STMicroelectronics ST100 processor. */ + EM_TINYJ Machine = 61 /* Advanced Logic Corp. TinyJ processor. */ + EM_X86_64 Machine = 62 /* Advanced Micro Devices x86-64 */ + EM_PDSP Machine = 63 /* Sony DSP Processor */ + EM_PDP10 Machine = 64 /* Digital Equipment Corp. PDP-10 */ + EM_PDP11 Machine = 65 /* Digital Equipment Corp. PDP-11 */ + EM_FX66 Machine = 66 /* Siemens FX66 microcontroller */ + EM_ST9PLUS Machine = 67 /* STMicroelectronics ST9+ 8/16 bit microcontroller */ + EM_ST7 Machine = 68 /* STMicroelectronics ST7 8-bit microcontroller */ + EM_68HC16 Machine = 69 /* Motorola MC68HC16 Microcontroller */ + EM_68HC11 Machine = 70 /* Motorola MC68HC11 Microcontroller */ + EM_68HC08 Machine = 71 /* Motorola MC68HC08 Microcontroller */ + EM_68HC05 Machine = 72 /* Motorola MC68HC05 Microcontroller */ + EM_SVX Machine = 73 /* Silicon Graphics SVx */ + EM_ST19 Machine = 74 /* STMicroelectronics ST19 8-bit microcontroller */ + EM_VAX Machine = 75 /* Digital VAX */ + EM_CRIS Machine = 76 /* Axis Communications 32-bit embedded processor */ + EM_JAVELIN Machine = 77 /* Infineon Technologies 32-bit embedded processor */ + EM_FIREPATH Machine = 78 /* Element 14 64-bit DSP Processor */ + EM_ZSP Machine = 79 /* LSI Logic 16-bit DSP Processor */ + EM_MMIX Machine = 80 /* Donald Knuth's educational 64-bit processor */ + EM_HUANY Machine = 81 /* Harvard University machine-independent object files */ + EM_PRISM Machine = 82 /* SiTera Prism */ + EM_AVR Machine = 83 /* Atmel AVR 8-bit microcontroller */ + EM_FR30 Machine = 84 /* Fujitsu FR30 */ + EM_D10V Machine = 85 /* Mitsubishi D10V */ + EM_D30V Machine = 86 /* Mitsubishi D30V */ + EM_V850 Machine = 87 /* NEC v850 */ + EM_M32R Machine = 88 /* Mitsubishi M32R */ + EM_MN10300 Machine = 89 /* Matsushita MN10300 */ + EM_MN10200 Machine = 90 /* Matsushita MN10200 */ + EM_PJ Machine = 91 /* picoJava */ + EM_OPENRISC Machine = 92 /* OpenRISC 32-bit embedded processor */ + EM_ARC_COMPACT Machine = 93 /* ARC International ARCompact processor (old spelling/synonym: EM_ARC_A5) */ + EM_XTENSA Machine = 94 /* Tensilica Xtensa Architecture */ + EM_VIDEOCORE Machine = 95 /* Alphamosaic VideoCore processor */ + EM_TMM_GPP Machine = 96 /* Thompson Multimedia General Purpose Processor */ + EM_NS32K Machine = 97 /* National Semiconductor 32000 series */ + EM_TPC Machine = 98 /* Tenor Network TPC processor */ + EM_SNP1K Machine = 99 /* Trebia SNP 1000 processor */ + EM_ST200 Machine = 100 /* STMicroelectronics (www.st.com) ST200 microcontroller */ + EM_IP2K Machine = 101 /* Ubicom IP2xxx microcontroller family */ + EM_MAX Machine = 102 /* MAX Processor */ + EM_CR Machine = 103 /* National Semiconductor CompactRISC microprocessor */ + EM_F2MC16 Machine = 104 /* Fujitsu F2MC16 */ + EM_MSP430 Machine = 105 /* Texas Instruments embedded microcontroller msp430 */ + EM_BLACKFIN Machine = 106 /* Analog Devices Blackfin (DSP) processor */ + EM_SE_C33 Machine = 107 /* S1C33 Family of Seiko Epson processors */ + EM_SEP Machine = 108 /* Sharp embedded microprocessor */ + EM_ARCA Machine = 109 /* Arca RISC Microprocessor */ + EM_UNICORE Machine = 110 /* Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University */ + EM_EXCESS Machine = 111 /* eXcess: 16/32/64-bit configurable embedded CPU */ + EM_DXP Machine = 112 /* Icera Semiconductor Inc. Deep Execution Processor */ + EM_ALTERA_NIOS2 Machine = 113 /* Altera Nios II soft-core processor */ + EM_CRX Machine = 114 /* National Semiconductor CompactRISC CRX microprocessor */ + EM_XGATE Machine = 115 /* Motorola XGATE embedded processor */ + EM_C166 Machine = 116 /* Infineon C16x/XC16x processor */ + EM_M16C Machine = 117 /* Renesas M16C series microprocessors */ + EM_DSPIC30F Machine = 118 /* Microchip Technology dsPIC30F Digital Signal Controller */ + EM_CE Machine = 119 /* Freescale Communication Engine RISC core */ + EM_M32C Machine = 120 /* Renesas M32C series microprocessors */ + EM_TSK3000 Machine = 131 /* Altium TSK3000 core */ + EM_RS08 Machine = 132 /* Freescale RS08 embedded processor */ + EM_SHARC Machine = 133 /* Analog Devices SHARC family of 32-bit DSP processors */ + EM_ECOG2 Machine = 134 /* Cyan Technology eCOG2 microprocessor */ + EM_SCORE7 Machine = 135 /* Sunplus S+core7 RISC processor */ + EM_DSP24 Machine = 136 /* New Japan Radio (NJR) 24-bit DSP Processor */ + EM_VIDEOCORE3 Machine = 137 /* Broadcom VideoCore III processor */ + EM_LATTICEMICO32 Machine = 138 /* RISC processor for Lattice FPGA architecture */ + EM_SE_C17 Machine = 139 /* Seiko Epson C17 family */ + EM_TI_C6000 Machine = 140 /* The Texas Instruments TMS320C6000 DSP family */ + EM_TI_C2000 Machine = 141 /* The Texas Instruments TMS320C2000 DSP family */ + EM_TI_C5500 Machine = 142 /* The Texas Instruments TMS320C55x DSP family */ + EM_TI_ARP32 Machine = 143 /* Texas Instruments Application Specific RISC Processor, 32bit fetch */ + EM_TI_PRU Machine = 144 /* Texas Instruments Programmable Realtime Unit */ + EM_MMDSP_PLUS Machine = 160 /* STMicroelectronics 64bit VLIW Data Signal Processor */ + EM_CYPRESS_M8C Machine = 161 /* Cypress M8C microprocessor */ + EM_R32C Machine = 162 /* Renesas R32C series microprocessors */ + EM_TRIMEDIA Machine = 163 /* NXP Semiconductors TriMedia architecture family */ + EM_QDSP6 Machine = 164 /* QUALCOMM DSP6 Processor */ + EM_8051 Machine = 165 /* Intel 8051 and variants */ + EM_STXP7X Machine = 166 /* STMicroelectronics STxP7x family of configurable and extensible RISC processors */ + EM_NDS32 Machine = 167 /* Andes Technology compact code size embedded RISC processor family */ + EM_ECOG1 Machine = 168 /* Cyan Technology eCOG1X family */ + EM_ECOG1X Machine = 168 /* Cyan Technology eCOG1X family */ + EM_MAXQ30 Machine = 169 /* Dallas Semiconductor MAXQ30 Core Micro-controllers */ + EM_XIMO16 Machine = 170 /* New Japan Radio (NJR) 16-bit DSP Processor */ + EM_MANIK Machine = 171 /* M2000 Reconfigurable RISC Microprocessor */ + EM_CRAYNV2 Machine = 172 /* Cray Inc. NV2 vector architecture */ + EM_RX Machine = 173 /* Renesas RX family */ + EM_METAG Machine = 174 /* Imagination Technologies META processor architecture */ + EM_MCST_ELBRUS Machine = 175 /* MCST Elbrus general purpose hardware architecture */ + EM_ECOG16 Machine = 176 /* Cyan Technology eCOG16 family */ + EM_CR16 Machine = 177 /* National Semiconductor CompactRISC CR16 16-bit microprocessor */ + EM_ETPU Machine = 178 /* Freescale Extended Time Processing Unit */ + EM_SLE9X Machine = 179 /* Infineon Technologies SLE9X core */ + EM_L10M Machine = 180 /* Intel L10M */ + EM_K10M Machine = 181 /* Intel K10M */ + EM_AARCH64 Machine = 183 /* ARM 64-bit Architecture (AArch64) */ + EM_AVR32 Machine = 185 /* Atmel Corporation 32-bit microprocessor family */ + EM_STM8 Machine = 186 /* STMicroeletronics STM8 8-bit microcontroller */ + EM_TILE64 Machine = 187 /* Tilera TILE64 multicore architecture family */ + EM_TILEPRO Machine = 188 /* Tilera TILEPro multicore architecture family */ + EM_MICROBLAZE Machine = 189 /* Xilinx MicroBlaze 32-bit RISC soft processor core */ + EM_CUDA Machine = 190 /* NVIDIA CUDA architecture */ + EM_TILEGX Machine = 191 /* Tilera TILE-Gx multicore architecture family */ + EM_CLOUDSHIELD Machine = 192 /* CloudShield architecture family */ + EM_COREA_1ST Machine = 193 /* KIPO-KAIST Core-A 1st generation processor family */ + EM_COREA_2ND Machine = 194 /* KIPO-KAIST Core-A 2nd generation processor family */ + EM_ARC_COMPACT2 Machine = 195 /* Synopsys ARCompact V2 */ + EM_OPEN8 Machine = 196 /* Open8 8-bit RISC soft processor core */ + EM_RL78 Machine = 197 /* Renesas RL78 family */ + EM_VIDEOCORE5 Machine = 198 /* Broadcom VideoCore V processor */ + EM_78KOR Machine = 199 /* Renesas 78KOR family */ + EM_56800EX Machine = 200 /* Freescale 56800EX Digital Signal Controller (DSC) */ + EM_BA1 Machine = 201 /* Beyond BA1 CPU architecture */ + EM_BA2 Machine = 202 /* Beyond BA2 CPU architecture */ + EM_XCORE Machine = 203 /* XMOS xCORE processor family */ + EM_MCHP_PIC Machine = 204 /* Microchip 8-bit PIC(r) family */ + EM_INTEL205 Machine = 205 /* Reserved by Intel */ + EM_INTEL206 Machine = 206 /* Reserved by Intel */ + EM_INTEL207 Machine = 207 /* Reserved by Intel */ + EM_INTEL208 Machine = 208 /* Reserved by Intel */ + EM_INTEL209 Machine = 209 /* Reserved by Intel */ + EM_KM32 Machine = 210 /* KM211 KM32 32-bit processor */ + EM_KMX32 Machine = 211 /* KM211 KMX32 32-bit processor */ + EM_KMX16 Machine = 212 /* KM211 KMX16 16-bit processor */ + EM_KMX8 Machine = 213 /* KM211 KMX8 8-bit processor */ + EM_KVARC Machine = 214 /* KM211 KVARC processor */ + EM_CDP Machine = 215 /* Paneve CDP architecture family */ + EM_COGE Machine = 216 /* Cognitive Smart Memory Processor */ + EM_COOL Machine = 217 /* Bluechip Systems CoolEngine */ + EM_NORC Machine = 218 /* Nanoradio Optimized RISC */ + EM_CSR_KALIMBA Machine = 219 /* CSR Kalimba architecture family */ + EM_Z80 Machine = 220 /* Zilog Z80 */ + EM_VISIUM Machine = 221 /* Controls and Data Services VISIUMcore processor */ + EM_FT32 Machine = 222 /* FTDI Chip FT32 high performance 32-bit RISC architecture */ + EM_MOXIE Machine = 223 /* Moxie processor family */ + EM_AMDGPU Machine = 224 /* AMD GPU architecture */ + EM_RISCV Machine = 243 /* RISC-V */ + EM_LANAI Machine = 244 /* Lanai 32-bit processor */ + EM_BPF Machine = 247 /* Linux BPF – in-kernel virtual machine */ + + /* Non-standard or deprecated. */ + EM_486 Machine = 6 /* Intel i486. */ + EM_MIPS_RS4_BE Machine = 10 /* MIPS R4000 Big-Endian */ + EM_ALPHA_STD Machine = 41 /* Digital Alpha (standard value). */ + EM_ALPHA Machine = 0x9026 /* Alpha (written in the absence of an ABI) */ +) + +var machineStrings = []intName{ + {0, "EM_NONE"}, + {1, "EM_M32"}, + {2, "EM_SPARC"}, + {3, "EM_386"}, + {4, "EM_68K"}, + {5, "EM_88K"}, + {7, "EM_860"}, + {8, "EM_MIPS"}, + {9, "EM_S370"}, + {10, "EM_MIPS_RS3_LE"}, + {15, "EM_PARISC"}, + {17, "EM_VPP500"}, + {18, "EM_SPARC32PLUS"}, + {19, "EM_960"}, + {20, "EM_PPC"}, + {21, "EM_PPC64"}, + {22, "EM_S390"}, + {36, "EM_V800"}, + {37, "EM_FR20"}, + {38, "EM_RH32"}, + {39, "EM_RCE"}, + {40, "EM_ARM"}, + {42, "EM_SH"}, + {43, "EM_SPARCV9"}, + {44, "EM_TRICORE"}, + {45, "EM_ARC"}, + {46, "EM_H8_300"}, + {47, "EM_H8_300H"}, + {48, "EM_H8S"}, + {49, "EM_H8_500"}, + {50, "EM_IA_64"}, + {51, "EM_MIPS_X"}, + {52, "EM_COLDFIRE"}, + {53, "EM_68HC12"}, + {54, "EM_MMA"}, + {55, "EM_PCP"}, + {56, "EM_NCPU"}, + {57, "EM_NDR1"}, + {58, "EM_STARCORE"}, + {59, "EM_ME16"}, + {60, "EM_ST100"}, + {61, "EM_TINYJ"}, + {62, "EM_X86_64"}, + {63, "EM_PDSP"}, + {64, "EM_PDP10"}, + {65, "EM_PDP11"}, + {66, "EM_FX66"}, + {67, "EM_ST9PLUS"}, + {68, "EM_ST7"}, + {69, "EM_68HC16"}, + {70, "EM_68HC11"}, + {71, "EM_68HC08"}, + {72, "EM_68HC05"}, + {73, "EM_SVX"}, + {74, "EM_ST19"}, + {75, "EM_VAX"}, + {76, "EM_CRIS"}, + {77, "EM_JAVELIN"}, + {78, "EM_FIREPATH"}, + {79, "EM_ZSP"}, + {80, "EM_MMIX"}, + {81, "EM_HUANY"}, + {82, "EM_PRISM"}, + {83, "EM_AVR"}, + {84, "EM_FR30"}, + {85, "EM_D10V"}, + {86, "EM_D30V"}, + {87, "EM_V850"}, + {88, "EM_M32R"}, + {89, "EM_MN10300"}, + {90, "EM_MN10200"}, + {91, "EM_PJ"}, + {92, "EM_OPENRISC"}, + {93, "EM_ARC_COMPACT"}, + {94, "EM_XTENSA"}, + {95, "EM_VIDEOCORE"}, + {96, "EM_TMM_GPP"}, + {97, "EM_NS32K"}, + {98, "EM_TPC"}, + {99, "EM_SNP1K"}, + {100, "EM_ST200"}, + {101, "EM_IP2K"}, + {102, "EM_MAX"}, + {103, "EM_CR"}, + {104, "EM_F2MC16"}, + {105, "EM_MSP430"}, + {106, "EM_BLACKFIN"}, + {107, "EM_SE_C33"}, + {108, "EM_SEP"}, + {109, "EM_ARCA"}, + {110, "EM_UNICORE"}, + {111, "EM_EXCESS"}, + {112, "EM_DXP"}, + {113, "EM_ALTERA_NIOS2"}, + {114, "EM_CRX"}, + {115, "EM_XGATE"}, + {116, "EM_C166"}, + {117, "EM_M16C"}, + {118, "EM_DSPIC30F"}, + {119, "EM_CE"}, + {120, "EM_M32C"}, + {131, "EM_TSK3000"}, + {132, "EM_RS08"}, + {133, "EM_SHARC"}, + {134, "EM_ECOG2"}, + {135, "EM_SCORE7"}, + {136, "EM_DSP24"}, + {137, "EM_VIDEOCORE3"}, + {138, "EM_LATTICEMICO32"}, + {139, "EM_SE_C17"}, + {140, "EM_TI_C6000"}, + {141, "EM_TI_C2000"}, + {142, "EM_TI_C5500"}, + {143, "EM_TI_ARP32"}, + {144, "EM_TI_PRU"}, + {160, "EM_MMDSP_PLUS"}, + {161, "EM_CYPRESS_M8C"}, + {162, "EM_R32C"}, + {163, "EM_TRIMEDIA"}, + {164, "EM_QDSP6"}, + {165, "EM_8051"}, + {166, "EM_STXP7X"}, + {167, "EM_NDS32"}, + {168, "EM_ECOG1"}, + {168, "EM_ECOG1X"}, + {169, "EM_MAXQ30"}, + {170, "EM_XIMO16"}, + {171, "EM_MANIK"}, + {172, "EM_CRAYNV2"}, + {173, "EM_RX"}, + {174, "EM_METAG"}, + {175, "EM_MCST_ELBRUS"}, + {176, "EM_ECOG16"}, + {177, "EM_CR16"}, + {178, "EM_ETPU"}, + {179, "EM_SLE9X"}, + {180, "EM_L10M"}, + {181, "EM_K10M"}, + {183, "EM_AARCH64"}, + {185, "EM_AVR32"}, + {186, "EM_STM8"}, + {187, "EM_TILE64"}, + {188, "EM_TILEPRO"}, + {189, "EM_MICROBLAZE"}, + {190, "EM_CUDA"}, + {191, "EM_TILEGX"}, + {192, "EM_CLOUDSHIELD"}, + {193, "EM_COREA_1ST"}, + {194, "EM_COREA_2ND"}, + {195, "EM_ARC_COMPACT2"}, + {196, "EM_OPEN8"}, + {197, "EM_RL78"}, + {198, "EM_VIDEOCORE5"}, + {199, "EM_78KOR"}, + {200, "EM_56800EX"}, + {201, "EM_BA1"}, + {202, "EM_BA2"}, + {203, "EM_XCORE"}, + {204, "EM_MCHP_PIC"}, + {205, "EM_INTEL205"}, + {206, "EM_INTEL206"}, + {207, "EM_INTEL207"}, + {208, "EM_INTEL208"}, + {209, "EM_INTEL209"}, + {210, "EM_KM32"}, + {211, "EM_KMX32"}, + {212, "EM_KMX16"}, + {213, "EM_KMX8"}, + {214, "EM_KVARC"}, + {215, "EM_CDP"}, + {216, "EM_COGE"}, + {217, "EM_COOL"}, + {218, "EM_NORC"}, + {219, "EM_CSR_KALIMBA "}, + {220, "EM_Z80 "}, + {221, "EM_VISIUM "}, + {222, "EM_FT32 "}, + {223, "EM_MOXIE"}, + {224, "EM_AMDGPU"}, + {243, "EM_RISCV"}, + {244, "EM_LANAI"}, + {247, "EM_BPF"}, + + /* Non-standard or deprecated. */ + {6, "EM_486"}, + {10, "EM_MIPS_RS4_BE"}, + {41, "EM_ALPHA_STD"}, + {0x9026, "EM_ALPHA"}, +} + +func (i Machine) String() string { return stringName(uint32(i), machineStrings, false) } +func (i Machine) GoString() string { return stringName(uint32(i), machineStrings, true) } + +// Special section indices. +type SectionIndex int + +const ( + SHN_UNDEF SectionIndex = 0 /* Undefined, missing, irrelevant. */ + SHN_LORESERVE SectionIndex = 0xff00 /* First of reserved range. */ + SHN_LOPROC SectionIndex = 0xff00 /* First processor-specific. */ + SHN_HIPROC SectionIndex = 0xff1f /* Last processor-specific. */ + SHN_LOOS SectionIndex = 0xff20 /* First operating system-specific. */ + SHN_HIOS SectionIndex = 0xff3f /* Last operating system-specific. */ + SHN_ABS SectionIndex = 0xfff1 /* Absolute values. */ + SHN_COMMON SectionIndex = 0xfff2 /* Common data. */ + SHN_XINDEX SectionIndex = 0xffff /* Escape; index stored elsewhere. */ + SHN_HIRESERVE SectionIndex = 0xffff /* Last of reserved range. */ +) + +var shnStrings = []intName{ + {0, "SHN_UNDEF"}, + {0xff00, "SHN_LOPROC"}, + {0xff20, "SHN_LOOS"}, + {0xfff1, "SHN_ABS"}, + {0xfff2, "SHN_COMMON"}, + {0xffff, "SHN_XINDEX"}, +} + +func (i SectionIndex) String() string { return stringName(uint32(i), shnStrings, false) } +func (i SectionIndex) GoString() string { return stringName(uint32(i), shnStrings, true) } + +// Section type. +type SectionType uint32 + +const ( + SHT_NULL SectionType = 0 /* inactive */ + SHT_PROGBITS SectionType = 1 /* program defined information */ + SHT_SYMTAB SectionType = 2 /* symbol table section */ + SHT_STRTAB SectionType = 3 /* string table section */ + SHT_RELA SectionType = 4 /* relocation section with addends */ + SHT_HASH SectionType = 5 /* symbol hash table section */ + SHT_DYNAMIC SectionType = 6 /* dynamic section */ + SHT_NOTE SectionType = 7 /* note section */ + SHT_NOBITS SectionType = 8 /* no space section */ + SHT_REL SectionType = 9 /* relocation section - no addends */ + SHT_SHLIB SectionType = 10 /* reserved - purpose unknown */ + SHT_DYNSYM SectionType = 11 /* dynamic symbol table section */ + SHT_INIT_ARRAY SectionType = 14 /* Initialization function pointers. */ + SHT_FINI_ARRAY SectionType = 15 /* Termination function pointers. */ + SHT_PREINIT_ARRAY SectionType = 16 /* Pre-initialization function ptrs. */ + SHT_GROUP SectionType = 17 /* Section group. */ + SHT_SYMTAB_SHNDX SectionType = 18 /* Section indexes (see SHN_XINDEX). */ + SHT_LOOS SectionType = 0x60000000 /* First of OS specific semantics */ + SHT_GNU_ATTRIBUTES SectionType = 0x6ffffff5 /* GNU object attributes */ + SHT_GNU_HASH SectionType = 0x6ffffff6 /* GNU hash table */ + SHT_GNU_LIBLIST SectionType = 0x6ffffff7 /* GNU prelink library list */ + SHT_GNU_VERDEF SectionType = 0x6ffffffd /* GNU version definition section */ + SHT_GNU_VERNEED SectionType = 0x6ffffffe /* GNU version needs section */ + SHT_GNU_VERSYM SectionType = 0x6fffffff /* GNU version symbol table */ + SHT_HIOS SectionType = 0x6fffffff /* Last of OS specific semantics */ + SHT_LOPROC SectionType = 0x70000000 /* reserved range for processor */ + SHT_HIPROC SectionType = 0x7fffffff /* specific section header types */ + SHT_LOUSER SectionType = 0x80000000 /* reserved range for application */ + SHT_HIUSER SectionType = 0xffffffff /* specific indexes */ +) + +var shtStrings = []intName{ + {0, "SHT_NULL"}, + {1, "SHT_PROGBITS"}, + {2, "SHT_SYMTAB"}, + {3, "SHT_STRTAB"}, + {4, "SHT_RELA"}, + {5, "SHT_HASH"}, + {6, "SHT_DYNAMIC"}, + {7, "SHT_NOTE"}, + {8, "SHT_NOBITS"}, + {9, "SHT_REL"}, + {10, "SHT_SHLIB"}, + {11, "SHT_DYNSYM"}, + {14, "SHT_INIT_ARRAY"}, + {15, "SHT_FINI_ARRAY"}, + {16, "SHT_PREINIT_ARRAY"}, + {17, "SHT_GROUP"}, + {18, "SHT_SYMTAB_SHNDX"}, + {0x60000000, "SHT_LOOS"}, + {0x6ffffff5, "SHT_GNU_ATTRIBUTES"}, + {0x6ffffff6, "SHT_GNU_HASH"}, + {0x6ffffff7, "SHT_GNU_LIBLIST"}, + {0x6ffffffd, "SHT_GNU_VERDEF"}, + {0x6ffffffe, "SHT_GNU_VERNEED"}, + {0x6fffffff, "SHT_GNU_VERSYM"}, + {0x70000000, "SHT_LOPROC"}, + {0x7fffffff, "SHT_HIPROC"}, + {0x80000000, "SHT_LOUSER"}, + {0xffffffff, "SHT_HIUSER"}, +} + +func (i SectionType) String() string { return stringName(uint32(i), shtStrings, false) } +func (i SectionType) GoString() string { return stringName(uint32(i), shtStrings, true) } + +// Section flags. +type SectionFlag uint32 + +const ( + SHF_WRITE SectionFlag = 0x1 /* Section contains writable data. */ + SHF_ALLOC SectionFlag = 0x2 /* Section occupies memory. */ + SHF_EXECINSTR SectionFlag = 0x4 /* Section contains instructions. */ + SHF_MERGE SectionFlag = 0x10 /* Section may be merged. */ + SHF_STRINGS SectionFlag = 0x20 /* Section contains strings. */ + SHF_INFO_LINK SectionFlag = 0x40 /* sh_info holds section index. */ + SHF_LINK_ORDER SectionFlag = 0x80 /* Special ordering requirements. */ + SHF_OS_NONCONFORMING SectionFlag = 0x100 /* OS-specific processing required. */ + SHF_GROUP SectionFlag = 0x200 /* Member of section group. */ + SHF_TLS SectionFlag = 0x400 /* Section contains TLS data. */ + SHF_COMPRESSED SectionFlag = 0x800 /* Section is compressed. */ + SHF_MASKOS SectionFlag = 0x0ff00000 /* OS-specific semantics. */ + SHF_MASKPROC SectionFlag = 0xf0000000 /* Processor-specific semantics. */ +) + +var shfStrings = []intName{ + {0x1, "SHF_WRITE"}, + {0x2, "SHF_ALLOC"}, + {0x4, "SHF_EXECINSTR"}, + {0x10, "SHF_MERGE"}, + {0x20, "SHF_STRINGS"}, + {0x40, "SHF_INFO_LINK"}, + {0x80, "SHF_LINK_ORDER"}, + {0x100, "SHF_OS_NONCONFORMING"}, + {0x200, "SHF_GROUP"}, + {0x400, "SHF_TLS"}, + {0x800, "SHF_COMPRESSED"}, +} + +func (i SectionFlag) String() string { return flagName(uint32(i), shfStrings, false) } +func (i SectionFlag) GoString() string { return flagName(uint32(i), shfStrings, true) } + +// Section compression type. +type CompressionType int + +const ( + COMPRESS_ZLIB CompressionType = 1 /* ZLIB compression. */ + COMPRESS_LOOS CompressionType = 0x60000000 /* First OS-specific. */ + COMPRESS_HIOS CompressionType = 0x6fffffff /* Last OS-specific. */ + COMPRESS_LOPROC CompressionType = 0x70000000 /* First processor-specific type. */ + COMPRESS_HIPROC CompressionType = 0x7fffffff /* Last processor-specific type. */ +) + +var compressionStrings = []intName{ + {0, "COMPRESS_ZLIB"}, + {0x60000000, "COMPRESS_LOOS"}, + {0x6fffffff, "COMPRESS_HIOS"}, + {0x70000000, "COMPRESS_LOPROC"}, + {0x7fffffff, "COMPRESS_HIPROC"}, +} + +func (i CompressionType) String() string { return stringName(uint32(i), compressionStrings, false) } +func (i CompressionType) GoString() string { return stringName(uint32(i), compressionStrings, true) } + +// Prog.Type +type ProgType int + +const ( + PT_NULL ProgType = 0 /* Unused entry. */ + PT_LOAD ProgType = 1 /* Loadable segment. */ + PT_DYNAMIC ProgType = 2 /* Dynamic linking information segment. */ + PT_INTERP ProgType = 3 /* Pathname of interpreter. */ + PT_NOTE ProgType = 4 /* Auxiliary information. */ + PT_SHLIB ProgType = 5 /* Reserved (not used). */ + PT_PHDR ProgType = 6 /* Location of program header itself. */ + PT_TLS ProgType = 7 /* Thread local storage segment */ + PT_LOOS ProgType = 0x60000000 /* First OS-specific. */ + PT_HIOS ProgType = 0x6fffffff /* Last OS-specific. */ + PT_LOPROC ProgType = 0x70000000 /* First processor-specific type. */ + PT_HIPROC ProgType = 0x7fffffff /* Last processor-specific type. */ +) + +var ptStrings = []intName{ + {0, "PT_NULL"}, + {1, "PT_LOAD"}, + {2, "PT_DYNAMIC"}, + {3, "PT_INTERP"}, + {4, "PT_NOTE"}, + {5, "PT_SHLIB"}, + {6, "PT_PHDR"}, + {7, "PT_TLS"}, + {0x60000000, "PT_LOOS"}, + {0x6fffffff, "PT_HIOS"}, + {0x70000000, "PT_LOPROC"}, + {0x7fffffff, "PT_HIPROC"}, +} + +func (i ProgType) String() string { return stringName(uint32(i), ptStrings, false) } +func (i ProgType) GoString() string { return stringName(uint32(i), ptStrings, true) } + +// Prog.Flag +type ProgFlag uint32 + +const ( + PF_X ProgFlag = 0x1 /* Executable. */ + PF_W ProgFlag = 0x2 /* Writable. */ + PF_R ProgFlag = 0x4 /* Readable. */ + PF_MASKOS ProgFlag = 0x0ff00000 /* Operating system-specific. */ + PF_MASKPROC ProgFlag = 0xf0000000 /* Processor-specific. */ +) + +var pfStrings = []intName{ + {0x1, "PF_X"}, + {0x2, "PF_W"}, + {0x4, "PF_R"}, +} + +func (i ProgFlag) String() string { return flagName(uint32(i), pfStrings, false) } +func (i ProgFlag) GoString() string { return flagName(uint32(i), pfStrings, true) } + +// Dyn.Tag +type DynTag int + +const ( + DT_NULL DynTag = 0 /* Terminating entry. */ + DT_NEEDED DynTag = 1 /* String table offset of a needed shared library. */ + DT_PLTRELSZ DynTag = 2 /* Total size in bytes of PLT relocations. */ + DT_PLTGOT DynTag = 3 /* Processor-dependent address. */ + DT_HASH DynTag = 4 /* Address of symbol hash table. */ + DT_STRTAB DynTag = 5 /* Address of string table. */ + DT_SYMTAB DynTag = 6 /* Address of symbol table. */ + DT_RELA DynTag = 7 /* Address of ElfNN_Rela relocations. */ + DT_RELASZ DynTag = 8 /* Total size of ElfNN_Rela relocations. */ + DT_RELAENT DynTag = 9 /* Size of each ElfNN_Rela relocation entry. */ + DT_STRSZ DynTag = 10 /* Size of string table. */ + DT_SYMENT DynTag = 11 /* Size of each symbol table entry. */ + DT_INIT DynTag = 12 /* Address of initialization function. */ + DT_FINI DynTag = 13 /* Address of finalization function. */ + DT_SONAME DynTag = 14 /* String table offset of shared object name. */ + DT_RPATH DynTag = 15 /* String table offset of library path. [sup] */ + DT_SYMBOLIC DynTag = 16 /* Indicates "symbolic" linking. [sup] */ + DT_REL DynTag = 17 /* Address of ElfNN_Rel relocations. */ + DT_RELSZ DynTag = 18 /* Total size of ElfNN_Rel relocations. */ + DT_RELENT DynTag = 19 /* Size of each ElfNN_Rel relocation. */ + DT_PLTREL DynTag = 20 /* Type of relocation used for PLT. */ + DT_DEBUG DynTag = 21 /* Reserved (not used). */ + DT_TEXTREL DynTag = 22 /* Indicates there may be relocations in non-writable segments. [sup] */ + DT_JMPREL DynTag = 23 /* Address of PLT relocations. */ + DT_BIND_NOW DynTag = 24 /* [sup] */ + DT_INIT_ARRAY DynTag = 25 /* Address of the array of pointers to initialization functions */ + DT_FINI_ARRAY DynTag = 26 /* Address of the array of pointers to termination functions */ + DT_INIT_ARRAYSZ DynTag = 27 /* Size in bytes of the array of initialization functions. */ + DT_FINI_ARRAYSZ DynTag = 28 /* Size in bytes of the array of termination functions. */ + DT_RUNPATH DynTag = 29 /* String table offset of a null-terminated library search path string. */ + DT_FLAGS DynTag = 30 /* Object specific flag values. */ + DT_ENCODING DynTag = 32 /* Values greater than or equal to DT_ENCODING + and less than DT_LOOS follow the rules for + the interpretation of the d_un union + as follows: even == 'd_ptr', even == 'd_val' + or none */ + DT_PREINIT_ARRAY DynTag = 32 /* Address of the array of pointers to pre-initialization functions. */ + DT_PREINIT_ARRAYSZ DynTag = 33 /* Size in bytes of the array of pre-initialization functions. */ + DT_LOOS DynTag = 0x6000000d /* First OS-specific */ + DT_HIOS DynTag = 0x6ffff000 /* Last OS-specific */ + DT_VERSYM DynTag = 0x6ffffff0 + DT_VERNEED DynTag = 0x6ffffffe + DT_VERNEEDNUM DynTag = 0x6fffffff + DT_LOPROC DynTag = 0x70000000 /* First processor-specific type. */ + DT_HIPROC DynTag = 0x7fffffff /* Last processor-specific type. */ +) + +var dtStrings = []intName{ + {0, "DT_NULL"}, + {1, "DT_NEEDED"}, + {2, "DT_PLTRELSZ"}, + {3, "DT_PLTGOT"}, + {4, "DT_HASH"}, + {5, "DT_STRTAB"}, + {6, "DT_SYMTAB"}, + {7, "DT_RELA"}, + {8, "DT_RELASZ"}, + {9, "DT_RELAENT"}, + {10, "DT_STRSZ"}, + {11, "DT_SYMENT"}, + {12, "DT_INIT"}, + {13, "DT_FINI"}, + {14, "DT_SONAME"}, + {15, "DT_RPATH"}, + {16, "DT_SYMBOLIC"}, + {17, "DT_REL"}, + {18, "DT_RELSZ"}, + {19, "DT_RELENT"}, + {20, "DT_PLTREL"}, + {21, "DT_DEBUG"}, + {22, "DT_TEXTREL"}, + {23, "DT_JMPREL"}, + {24, "DT_BIND_NOW"}, + {25, "DT_INIT_ARRAY"}, + {26, "DT_FINI_ARRAY"}, + {27, "DT_INIT_ARRAYSZ"}, + {28, "DT_FINI_ARRAYSZ"}, + {29, "DT_RUNPATH"}, + {30, "DT_FLAGS"}, + {32, "DT_ENCODING"}, + {32, "DT_PREINIT_ARRAY"}, + {33, "DT_PREINIT_ARRAYSZ"}, + {0x6000000d, "DT_LOOS"}, + {0x6ffff000, "DT_HIOS"}, + {0x6ffffff0, "DT_VERSYM"}, + {0x6ffffffe, "DT_VERNEED"}, + {0x6fffffff, "DT_VERNEEDNUM"}, + {0x70000000, "DT_LOPROC"}, + {0x7fffffff, "DT_HIPROC"}, +} + +func (i DynTag) String() string { return stringName(uint32(i), dtStrings, false) } +func (i DynTag) GoString() string { return stringName(uint32(i), dtStrings, true) } + +// DT_FLAGS values. +type DynFlag int + +const ( + DF_ORIGIN DynFlag = 0x0001 /* Indicates that the object being loaded may + make reference to the + $ORIGIN substitution string */ + DF_SYMBOLIC DynFlag = 0x0002 /* Indicates "symbolic" linking. */ + DF_TEXTREL DynFlag = 0x0004 /* Indicates there may be relocations in non-writable segments. */ + DF_BIND_NOW DynFlag = 0x0008 /* Indicates that the dynamic linker should + process all relocations for the object + containing this entry before transferring + control to the program. */ + DF_STATIC_TLS DynFlag = 0x0010 /* Indicates that the shared object or + executable contains code using a static + thread-local storage scheme. */ +) + +var dflagStrings = []intName{ + {0x0001, "DF_ORIGIN"}, + {0x0002, "DF_SYMBOLIC"}, + {0x0004, "DF_TEXTREL"}, + {0x0008, "DF_BIND_NOW"}, + {0x0010, "DF_STATIC_TLS"}, +} + +func (i DynFlag) String() string { return flagName(uint32(i), dflagStrings, false) } +func (i DynFlag) GoString() string { return flagName(uint32(i), dflagStrings, true) } + +// NType values; used in core files. +type NType int + +const ( + NT_PRSTATUS NType = 1 /* Process status. */ + NT_FPREGSET NType = 2 /* Floating point registers. */ + NT_PRPSINFO NType = 3 /* Process state info. */ +) + +var ntypeStrings = []intName{ + {1, "NT_PRSTATUS"}, + {2, "NT_FPREGSET"}, + {3, "NT_PRPSINFO"}, +} + +func (i NType) String() string { return stringName(uint32(i), ntypeStrings, false) } +func (i NType) GoString() string { return stringName(uint32(i), ntypeStrings, true) } + +/* Symbol Binding - ELFNN_ST_BIND - st_info */ +type SymBind int + +const ( + STB_LOCAL SymBind = 0 /* Local symbol */ + STB_GLOBAL SymBind = 1 /* Global symbol */ + STB_WEAK SymBind = 2 /* like global - lower precedence */ + STB_LOOS SymBind = 10 /* Reserved range for operating system */ + STB_HIOS SymBind = 12 /* specific semantics. */ + STB_LOPROC SymBind = 13 /* reserved range for processor */ + STB_HIPROC SymBind = 15 /* specific semantics. */ +) + +var stbStrings = []intName{ + {0, "STB_LOCAL"}, + {1, "STB_GLOBAL"}, + {2, "STB_WEAK"}, + {10, "STB_LOOS"}, + {12, "STB_HIOS"}, + {13, "STB_LOPROC"}, + {15, "STB_HIPROC"}, +} + +func (i SymBind) String() string { return stringName(uint32(i), stbStrings, false) } +func (i SymBind) GoString() string { return stringName(uint32(i), stbStrings, true) } + +/* Symbol type - ELFNN_ST_TYPE - st_info */ +type SymType int + +const ( + STT_NOTYPE SymType = 0 /* Unspecified type. */ + STT_OBJECT SymType = 1 /* Data object. */ + STT_FUNC SymType = 2 /* Function. */ + STT_SECTION SymType = 3 /* Section. */ + STT_FILE SymType = 4 /* Source file. */ + STT_COMMON SymType = 5 /* Uninitialized common block. */ + STT_TLS SymType = 6 /* TLS object. */ + STT_LOOS SymType = 10 /* Reserved range for operating system */ + STT_HIOS SymType = 12 /* specific semantics. */ + STT_LOPROC SymType = 13 /* reserved range for processor */ + STT_HIPROC SymType = 15 /* specific semantics. */ +) + +var sttStrings = []intName{ + {0, "STT_NOTYPE"}, + {1, "STT_OBJECT"}, + {2, "STT_FUNC"}, + {3, "STT_SECTION"}, + {4, "STT_FILE"}, + {5, "STT_COMMON"}, + {6, "STT_TLS"}, + {10, "STT_LOOS"}, + {12, "STT_HIOS"}, + {13, "STT_LOPROC"}, + {15, "STT_HIPROC"}, +} + +func (i SymType) String() string { return stringName(uint32(i), sttStrings, false) } +func (i SymType) GoString() string { return stringName(uint32(i), sttStrings, true) } + +/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */ +type SymVis int + +const ( + STV_DEFAULT SymVis = 0x0 /* Default visibility (see binding). */ + STV_INTERNAL SymVis = 0x1 /* Special meaning in relocatable objects. */ + STV_HIDDEN SymVis = 0x2 /* Not visible. */ + STV_PROTECTED SymVis = 0x3 /* Visible but not preemptible. */ +) + +var stvStrings = []intName{ + {0x0, "STV_DEFAULT"}, + {0x1, "STV_INTERNAL"}, + {0x2, "STV_HIDDEN"}, + {0x3, "STV_PROTECTED"}, +} + +func (i SymVis) String() string { return stringName(uint32(i), stvStrings, false) } +func (i SymVis) GoString() string { return stringName(uint32(i), stvStrings, true) } + +/* + * Relocation types. + */ + +// Relocation types for x86-64. +type R_X86_64 int + +const ( + R_X86_64_NONE R_X86_64 = 0 /* No relocation. */ + R_X86_64_64 R_X86_64 = 1 /* Add 64 bit symbol value. */ + R_X86_64_PC32 R_X86_64 = 2 /* PC-relative 32 bit signed sym value. */ + R_X86_64_GOT32 R_X86_64 = 3 /* PC-relative 32 bit GOT offset. */ + R_X86_64_PLT32 R_X86_64 = 4 /* PC-relative 32 bit PLT offset. */ + R_X86_64_COPY R_X86_64 = 5 /* Copy data from shared object. */ + R_X86_64_GLOB_DAT R_X86_64 = 6 /* Set GOT entry to data address. */ + R_X86_64_JMP_SLOT R_X86_64 = 7 /* Set GOT entry to code address. */ + R_X86_64_RELATIVE R_X86_64 = 8 /* Add load address of shared object. */ + R_X86_64_GOTPCREL R_X86_64 = 9 /* Add 32 bit signed pcrel offset to GOT. */ + R_X86_64_32 R_X86_64 = 10 /* Add 32 bit zero extended symbol value */ + R_X86_64_32S R_X86_64 = 11 /* Add 32 bit sign extended symbol value */ + R_X86_64_16 R_X86_64 = 12 /* Add 16 bit zero extended symbol value */ + R_X86_64_PC16 R_X86_64 = 13 /* Add 16 bit signed extended pc relative symbol value */ + R_X86_64_8 R_X86_64 = 14 /* Add 8 bit zero extended symbol value */ + R_X86_64_PC8 R_X86_64 = 15 /* Add 8 bit signed extended pc relative symbol value */ + R_X86_64_DTPMOD64 R_X86_64 = 16 /* ID of module containing symbol */ + R_X86_64_DTPOFF64 R_X86_64 = 17 /* Offset in TLS block */ + R_X86_64_TPOFF64 R_X86_64 = 18 /* Offset in static TLS block */ + R_X86_64_TLSGD R_X86_64 = 19 /* PC relative offset to GD GOT entry */ + R_X86_64_TLSLD R_X86_64 = 20 /* PC relative offset to LD GOT entry */ + R_X86_64_DTPOFF32 R_X86_64 = 21 /* Offset in TLS block */ + R_X86_64_GOTTPOFF R_X86_64 = 22 /* PC relative offset to IE GOT entry */ + R_X86_64_TPOFF32 R_X86_64 = 23 /* Offset in static TLS block */ + R_X86_64_PC64 R_X86_64 = 24 /* PC relative 64-bit sign extended symbol value. */ + R_X86_64_GOTOFF64 R_X86_64 = 25 + R_X86_64_GOTPC32 R_X86_64 = 26 + R_X86_64_GOT64 R_X86_64 = 27 + R_X86_64_GOTPCREL64 R_X86_64 = 28 + R_X86_64_GOTPC64 R_X86_64 = 29 + R_X86_64_GOTPLT64 R_X86_64 = 30 + R_X86_64_PLTOFF64 R_X86_64 = 31 + R_X86_64_SIZE32 R_X86_64 = 32 + R_X86_64_SIZE64 R_X86_64 = 33 + R_X86_64_GOTPC32_TLSDESC R_X86_64 = 34 + R_X86_64_TLSDESC_CALL R_X86_64 = 35 + R_X86_64_TLSDESC R_X86_64 = 36 + R_X86_64_IRELATIVE R_X86_64 = 37 + R_X86_64_RELATIVE64 R_X86_64 = 38 + R_X86_64_PC32_BND R_X86_64 = 39 + R_X86_64_PLT32_BND R_X86_64 = 40 + R_X86_64_GOTPCRELX R_X86_64 = 41 + R_X86_64_REX_GOTPCRELX R_X86_64 = 42 +) + +var rx86_64Strings = []intName{ + {0, "R_X86_64_NONE"}, + {1, "R_X86_64_64"}, + {2, "R_X86_64_PC32"}, + {3, "R_X86_64_GOT32"}, + {4, "R_X86_64_PLT32"}, + {5, "R_X86_64_COPY"}, + {6, "R_X86_64_GLOB_DAT"}, + {7, "R_X86_64_JMP_SLOT"}, + {8, "R_X86_64_RELATIVE"}, + {9, "R_X86_64_GOTPCREL"}, + {10, "R_X86_64_32"}, + {11, "R_X86_64_32S"}, + {12, "R_X86_64_16"}, + {13, "R_X86_64_PC16"}, + {14, "R_X86_64_8"}, + {15, "R_X86_64_PC8"}, + {16, "R_X86_64_DTPMOD64"}, + {17, "R_X86_64_DTPOFF64"}, + {18, "R_X86_64_TPOFF64"}, + {19, "R_X86_64_TLSGD"}, + {20, "R_X86_64_TLSLD"}, + {21, "R_X86_64_DTPOFF32"}, + {22, "R_X86_64_GOTTPOFF"}, + {23, "R_X86_64_TPOFF32"}, + {24, "R_X86_64_PC64"}, + {25, "R_X86_64_GOTOFF64"}, + {26, "R_X86_64_GOTPC32"}, + {27, "R_X86_64_GOT64"}, + {28, "R_X86_64_GOTPCREL64"}, + {29, "R_X86_64_GOTPC64"}, + {30, "R_X86_64_GOTPLT64"}, + {31, "R_X86_64_PLTOFF64"}, + {32, "R_X86_64_SIZE32"}, + {33, "R_X86_64_SIZE64"}, + {34, "R_X86_64_GOTPC32_TLSDESC"}, + {35, "R_X86_64_TLSDESC_CALL"}, + {36, "R_X86_64_TLSDESC"}, + {37, "R_X86_64_IRELATIVE"}, + {38, "R_X86_64_RELATIVE64"}, + {39, "R_X86_64_PC32_BND"}, + {40, "R_X86_64_PLT32_BND"}, + {41, "R_X86_64_GOTPCRELX"}, + {42, "R_X86_64_REX_GOTPCRELX"}, +} + +func (i R_X86_64) String() string { return stringName(uint32(i), rx86_64Strings, false) } +func (i R_X86_64) GoString() string { return stringName(uint32(i), rx86_64Strings, true) } + +// Relocation types for AArch64 (aka arm64) +type R_AARCH64 int + +const ( + R_AARCH64_NONE R_AARCH64 = 0 + R_AARCH64_P32_ABS32 R_AARCH64 = 1 + R_AARCH64_P32_ABS16 R_AARCH64 = 2 + R_AARCH64_P32_PREL32 R_AARCH64 = 3 + R_AARCH64_P32_PREL16 R_AARCH64 = 4 + R_AARCH64_P32_MOVW_UABS_G0 R_AARCH64 = 5 + R_AARCH64_P32_MOVW_UABS_G0_NC R_AARCH64 = 6 + R_AARCH64_P32_MOVW_UABS_G1 R_AARCH64 = 7 + R_AARCH64_P32_MOVW_SABS_G0 R_AARCH64 = 8 + R_AARCH64_P32_LD_PREL_LO19 R_AARCH64 = 9 + R_AARCH64_P32_ADR_PREL_LO21 R_AARCH64 = 10 + R_AARCH64_P32_ADR_PREL_PG_HI21 R_AARCH64 = 11 + R_AARCH64_P32_ADD_ABS_LO12_NC R_AARCH64 = 12 + R_AARCH64_P32_LDST8_ABS_LO12_NC R_AARCH64 = 13 + R_AARCH64_P32_LDST16_ABS_LO12_NC R_AARCH64 = 14 + R_AARCH64_P32_LDST32_ABS_LO12_NC R_AARCH64 = 15 + R_AARCH64_P32_LDST64_ABS_LO12_NC R_AARCH64 = 16 + R_AARCH64_P32_LDST128_ABS_LO12_NC R_AARCH64 = 17 + R_AARCH64_P32_TSTBR14 R_AARCH64 = 18 + R_AARCH64_P32_CONDBR19 R_AARCH64 = 19 + R_AARCH64_P32_JUMP26 R_AARCH64 = 20 + R_AARCH64_P32_CALL26 R_AARCH64 = 21 + R_AARCH64_P32_GOT_LD_PREL19 R_AARCH64 = 25 + R_AARCH64_P32_ADR_GOT_PAGE R_AARCH64 = 26 + R_AARCH64_P32_LD32_GOT_LO12_NC R_AARCH64 = 27 + R_AARCH64_P32_TLSGD_ADR_PAGE21 R_AARCH64 = 81 + R_AARCH64_P32_TLSGD_ADD_LO12_NC R_AARCH64 = 82 + R_AARCH64_P32_TLSIE_ADR_GOTTPREL_PAGE21 R_AARCH64 = 103 + R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC R_AARCH64 = 104 + R_AARCH64_P32_TLSIE_LD_GOTTPREL_PREL19 R_AARCH64 = 105 + R_AARCH64_P32_TLSLE_MOVW_TPREL_G1 R_AARCH64 = 106 + R_AARCH64_P32_TLSLE_MOVW_TPREL_G0 R_AARCH64 = 107 + R_AARCH64_P32_TLSLE_MOVW_TPREL_G0_NC R_AARCH64 = 108 + R_AARCH64_P32_TLSLE_ADD_TPREL_HI12 R_AARCH64 = 109 + R_AARCH64_P32_TLSLE_ADD_TPREL_LO12 R_AARCH64 = 110 + R_AARCH64_P32_TLSLE_ADD_TPREL_LO12_NC R_AARCH64 = 111 + R_AARCH64_P32_TLSDESC_LD_PREL19 R_AARCH64 = 122 + R_AARCH64_P32_TLSDESC_ADR_PREL21 R_AARCH64 = 123 + R_AARCH64_P32_TLSDESC_ADR_PAGE21 R_AARCH64 = 124 + R_AARCH64_P32_TLSDESC_LD32_LO12_NC R_AARCH64 = 125 + R_AARCH64_P32_TLSDESC_ADD_LO12_NC R_AARCH64 = 126 + R_AARCH64_P32_TLSDESC_CALL R_AARCH64 = 127 + R_AARCH64_P32_COPY R_AARCH64 = 180 + R_AARCH64_P32_GLOB_DAT R_AARCH64 = 181 + R_AARCH64_P32_JUMP_SLOT R_AARCH64 = 182 + R_AARCH64_P32_RELATIVE R_AARCH64 = 183 + R_AARCH64_P32_TLS_DTPMOD R_AARCH64 = 184 + R_AARCH64_P32_TLS_DTPREL R_AARCH64 = 185 + R_AARCH64_P32_TLS_TPREL R_AARCH64 = 186 + R_AARCH64_P32_TLSDESC R_AARCH64 = 187 + R_AARCH64_P32_IRELATIVE R_AARCH64 = 188 + R_AARCH64_NULL R_AARCH64 = 256 + R_AARCH64_ABS64 R_AARCH64 = 257 + R_AARCH64_ABS32 R_AARCH64 = 258 + R_AARCH64_ABS16 R_AARCH64 = 259 + R_AARCH64_PREL64 R_AARCH64 = 260 + R_AARCH64_PREL32 R_AARCH64 = 261 + R_AARCH64_PREL16 R_AARCH64 = 262 + R_AARCH64_MOVW_UABS_G0 R_AARCH64 = 263 + R_AARCH64_MOVW_UABS_G0_NC R_AARCH64 = 264 + R_AARCH64_MOVW_UABS_G1 R_AARCH64 = 265 + R_AARCH64_MOVW_UABS_G1_NC R_AARCH64 = 266 + R_AARCH64_MOVW_UABS_G2 R_AARCH64 = 267 + R_AARCH64_MOVW_UABS_G2_NC R_AARCH64 = 268 + R_AARCH64_MOVW_UABS_G3 R_AARCH64 = 269 + R_AARCH64_MOVW_SABS_G0 R_AARCH64 = 270 + R_AARCH64_MOVW_SABS_G1 R_AARCH64 = 271 + R_AARCH64_MOVW_SABS_G2 R_AARCH64 = 272 + R_AARCH64_LD_PREL_LO19 R_AARCH64 = 273 + R_AARCH64_ADR_PREL_LO21 R_AARCH64 = 274 + R_AARCH64_ADR_PREL_PG_HI21 R_AARCH64 = 275 + R_AARCH64_ADR_PREL_PG_HI21_NC R_AARCH64 = 276 + R_AARCH64_ADD_ABS_LO12_NC R_AARCH64 = 277 + R_AARCH64_LDST8_ABS_LO12_NC R_AARCH64 = 278 + R_AARCH64_TSTBR14 R_AARCH64 = 279 + R_AARCH64_CONDBR19 R_AARCH64 = 280 + R_AARCH64_JUMP26 R_AARCH64 = 282 + R_AARCH64_CALL26 R_AARCH64 = 283 + R_AARCH64_LDST16_ABS_LO12_NC R_AARCH64 = 284 + R_AARCH64_LDST32_ABS_LO12_NC R_AARCH64 = 285 + R_AARCH64_LDST64_ABS_LO12_NC R_AARCH64 = 286 + R_AARCH64_LDST128_ABS_LO12_NC R_AARCH64 = 299 + R_AARCH64_GOT_LD_PREL19 R_AARCH64 = 309 + R_AARCH64_LD64_GOTOFF_LO15 R_AARCH64 = 310 + R_AARCH64_ADR_GOT_PAGE R_AARCH64 = 311 + R_AARCH64_LD64_GOT_LO12_NC R_AARCH64 = 312 + R_AARCH64_LD64_GOTPAGE_LO15 R_AARCH64 = 313 + R_AARCH64_TLSGD_ADR_PREL21 R_AARCH64 = 512 + R_AARCH64_TLSGD_ADR_PAGE21 R_AARCH64 = 513 + R_AARCH64_TLSGD_ADD_LO12_NC R_AARCH64 = 514 + R_AARCH64_TLSGD_MOVW_G1 R_AARCH64 = 515 + R_AARCH64_TLSGD_MOVW_G0_NC R_AARCH64 = 516 + R_AARCH64_TLSLD_ADR_PREL21 R_AARCH64 = 517 + R_AARCH64_TLSLD_ADR_PAGE21 R_AARCH64 = 518 + R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 R_AARCH64 = 539 + R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC R_AARCH64 = 540 + R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 R_AARCH64 = 541 + R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC R_AARCH64 = 542 + R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 R_AARCH64 = 543 + R_AARCH64_TLSLE_MOVW_TPREL_G2 R_AARCH64 = 544 + R_AARCH64_TLSLE_MOVW_TPREL_G1 R_AARCH64 = 545 + R_AARCH64_TLSLE_MOVW_TPREL_G1_NC R_AARCH64 = 546 + R_AARCH64_TLSLE_MOVW_TPREL_G0 R_AARCH64 = 547 + R_AARCH64_TLSLE_MOVW_TPREL_G0_NC R_AARCH64 = 548 + R_AARCH64_TLSLE_ADD_TPREL_HI12 R_AARCH64 = 549 + R_AARCH64_TLSLE_ADD_TPREL_LO12 R_AARCH64 = 550 + R_AARCH64_TLSLE_ADD_TPREL_LO12_NC R_AARCH64 = 551 + R_AARCH64_TLSDESC_LD_PREL19 R_AARCH64 = 560 + R_AARCH64_TLSDESC_ADR_PREL21 R_AARCH64 = 561 + R_AARCH64_TLSDESC_ADR_PAGE21 R_AARCH64 = 562 + R_AARCH64_TLSDESC_LD64_LO12_NC R_AARCH64 = 563 + R_AARCH64_TLSDESC_ADD_LO12_NC R_AARCH64 = 564 + R_AARCH64_TLSDESC_OFF_G1 R_AARCH64 = 565 + R_AARCH64_TLSDESC_OFF_G0_NC R_AARCH64 = 566 + R_AARCH64_TLSDESC_LDR R_AARCH64 = 567 + R_AARCH64_TLSDESC_ADD R_AARCH64 = 568 + R_AARCH64_TLSDESC_CALL R_AARCH64 = 569 + R_AARCH64_TLSLE_LDST128_TPREL_LO12 R_AARCH64 = 570 + R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC R_AARCH64 = 571 + R_AARCH64_TLSLD_LDST128_DTPREL_LO12 R_AARCH64 = 572 + R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC R_AARCH64 = 573 + R_AARCH64_COPY R_AARCH64 = 1024 + R_AARCH64_GLOB_DAT R_AARCH64 = 1025 + R_AARCH64_JUMP_SLOT R_AARCH64 = 1026 + R_AARCH64_RELATIVE R_AARCH64 = 1027 + R_AARCH64_TLS_DTPMOD64 R_AARCH64 = 1028 + R_AARCH64_TLS_DTPREL64 R_AARCH64 = 1029 + R_AARCH64_TLS_TPREL64 R_AARCH64 = 1030 + R_AARCH64_TLSDESC R_AARCH64 = 1031 + R_AARCH64_IRELATIVE R_AARCH64 = 1032 +) + +var raarch64Strings = []intName{ + {0, "R_AARCH64_NONE"}, + {1, "R_AARCH64_P32_ABS32"}, + {2, "R_AARCH64_P32_ABS16"}, + {3, "R_AARCH64_P32_PREL32"}, + {4, "R_AARCH64_P32_PREL16"}, + {5, "R_AARCH64_P32_MOVW_UABS_G0"}, + {6, "R_AARCH64_P32_MOVW_UABS_G0_NC"}, + {7, "R_AARCH64_P32_MOVW_UABS_G1"}, + {8, "R_AARCH64_P32_MOVW_SABS_G0"}, + {9, "R_AARCH64_P32_LD_PREL_LO19"}, + {10, "R_AARCH64_P32_ADR_PREL_LO21"}, + {11, "R_AARCH64_P32_ADR_PREL_PG_HI21"}, + {12, "R_AARCH64_P32_ADD_ABS_LO12_NC"}, + {13, "R_AARCH64_P32_LDST8_ABS_LO12_NC"}, + {14, "R_AARCH64_P32_LDST16_ABS_LO12_NC"}, + {15, "R_AARCH64_P32_LDST32_ABS_LO12_NC"}, + {16, "R_AARCH64_P32_LDST64_ABS_LO12_NC"}, + {17, "R_AARCH64_P32_LDST128_ABS_LO12_NC"}, + {18, "R_AARCH64_P32_TSTBR14"}, + {19, "R_AARCH64_P32_CONDBR19"}, + {20, "R_AARCH64_P32_JUMP26"}, + {21, "R_AARCH64_P32_CALL26"}, + {25, "R_AARCH64_P32_GOT_LD_PREL19"}, + {26, "R_AARCH64_P32_ADR_GOT_PAGE"}, + {27, "R_AARCH64_P32_LD32_GOT_LO12_NC"}, + {81, "R_AARCH64_P32_TLSGD_ADR_PAGE21"}, + {82, "R_AARCH64_P32_TLSGD_ADD_LO12_NC"}, + {103, "R_AARCH64_P32_TLSIE_ADR_GOTTPREL_PAGE21"}, + {104, "R_AARCH64_P32_TLSIE_LD32_GOTTPREL_LO12_NC"}, + {105, "R_AARCH64_P32_TLSIE_LD_GOTTPREL_PREL19"}, + {106, "R_AARCH64_P32_TLSLE_MOVW_TPREL_G1"}, + {107, "R_AARCH64_P32_TLSLE_MOVW_TPREL_G0"}, + {108, "R_AARCH64_P32_TLSLE_MOVW_TPREL_G0_NC"}, + {109, "R_AARCH64_P32_TLSLE_ADD_TPREL_HI12"}, + {110, "R_AARCH64_P32_TLSLE_ADD_TPREL_LO12"}, + {111, "R_AARCH64_P32_TLSLE_ADD_TPREL_LO12_NC"}, + {122, "R_AARCH64_P32_TLSDESC_LD_PREL19"}, + {123, "R_AARCH64_P32_TLSDESC_ADR_PREL21"}, + {124, "R_AARCH64_P32_TLSDESC_ADR_PAGE21"}, + {125, "R_AARCH64_P32_TLSDESC_LD32_LO12_NC"}, + {126, "R_AARCH64_P32_TLSDESC_ADD_LO12_NC"}, + {127, "R_AARCH64_P32_TLSDESC_CALL"}, + {180, "R_AARCH64_P32_COPY"}, + {181, "R_AARCH64_P32_GLOB_DAT"}, + {182, "R_AARCH64_P32_JUMP_SLOT"}, + {183, "R_AARCH64_P32_RELATIVE"}, + {184, "R_AARCH64_P32_TLS_DTPMOD"}, + {185, "R_AARCH64_P32_TLS_DTPREL"}, + {186, "R_AARCH64_P32_TLS_TPREL"}, + {187, "R_AARCH64_P32_TLSDESC"}, + {188, "R_AARCH64_P32_IRELATIVE"}, + {256, "R_AARCH64_NULL"}, + {257, "R_AARCH64_ABS64"}, + {258, "R_AARCH64_ABS32"}, + {259, "R_AARCH64_ABS16"}, + {260, "R_AARCH64_PREL64"}, + {261, "R_AARCH64_PREL32"}, + {262, "R_AARCH64_PREL16"}, + {263, "R_AARCH64_MOVW_UABS_G0"}, + {264, "R_AARCH64_MOVW_UABS_G0_NC"}, + {265, "R_AARCH64_MOVW_UABS_G1"}, + {266, "R_AARCH64_MOVW_UABS_G1_NC"}, + {267, "R_AARCH64_MOVW_UABS_G2"}, + {268, "R_AARCH64_MOVW_UABS_G2_NC"}, + {269, "R_AARCH64_MOVW_UABS_G3"}, + {270, "R_AARCH64_MOVW_SABS_G0"}, + {271, "R_AARCH64_MOVW_SABS_G1"}, + {272, "R_AARCH64_MOVW_SABS_G2"}, + {273, "R_AARCH64_LD_PREL_LO19"}, + {274, "R_AARCH64_ADR_PREL_LO21"}, + {275, "R_AARCH64_ADR_PREL_PG_HI21"}, + {276, "R_AARCH64_ADR_PREL_PG_HI21_NC"}, + {277, "R_AARCH64_ADD_ABS_LO12_NC"}, + {278, "R_AARCH64_LDST8_ABS_LO12_NC"}, + {279, "R_AARCH64_TSTBR14"}, + {280, "R_AARCH64_CONDBR19"}, + {282, "R_AARCH64_JUMP26"}, + {283, "R_AARCH64_CALL26"}, + {284, "R_AARCH64_LDST16_ABS_LO12_NC"}, + {285, "R_AARCH64_LDST32_ABS_LO12_NC"}, + {286, "R_AARCH64_LDST64_ABS_LO12_NC"}, + {299, "R_AARCH64_LDST128_ABS_LO12_NC"}, + {309, "R_AARCH64_GOT_LD_PREL19"}, + {310, "R_AARCH64_LD64_GOTOFF_LO15"}, + {311, "R_AARCH64_ADR_GOT_PAGE"}, + {312, "R_AARCH64_LD64_GOT_LO12_NC"}, + {313, "R_AARCH64_LD64_GOTPAGE_LO15"}, + {512, "R_AARCH64_TLSGD_ADR_PREL21"}, + {513, "R_AARCH64_TLSGD_ADR_PAGE21"}, + {514, "R_AARCH64_TLSGD_ADD_LO12_NC"}, + {515, "R_AARCH64_TLSGD_MOVW_G1"}, + {516, "R_AARCH64_TLSGD_MOVW_G0_NC"}, + {517, "R_AARCH64_TLSLD_ADR_PREL21"}, + {518, "R_AARCH64_TLSLD_ADR_PAGE21"}, + {539, "R_AARCH64_TLSIE_MOVW_GOTTPREL_G1"}, + {540, "R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC"}, + {541, "R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21"}, + {542, "R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC"}, + {543, "R_AARCH64_TLSIE_LD_GOTTPREL_PREL19"}, + {544, "R_AARCH64_TLSLE_MOVW_TPREL_G2"}, + {545, "R_AARCH64_TLSLE_MOVW_TPREL_G1"}, + {546, "R_AARCH64_TLSLE_MOVW_TPREL_G1_NC"}, + {547, "R_AARCH64_TLSLE_MOVW_TPREL_G0"}, + {548, "R_AARCH64_TLSLE_MOVW_TPREL_G0_NC"}, + {549, "R_AARCH64_TLSLE_ADD_TPREL_HI12"}, + {550, "R_AARCH64_TLSLE_ADD_TPREL_LO12"}, + {551, "R_AARCH64_TLSLE_ADD_TPREL_LO12_NC"}, + {560, "R_AARCH64_TLSDESC_LD_PREL19"}, + {561, "R_AARCH64_TLSDESC_ADR_PREL21"}, + {562, "R_AARCH64_TLSDESC_ADR_PAGE21"}, + {563, "R_AARCH64_TLSDESC_LD64_LO12_NC"}, + {564, "R_AARCH64_TLSDESC_ADD_LO12_NC"}, + {565, "R_AARCH64_TLSDESC_OFF_G1"}, + {566, "R_AARCH64_TLSDESC_OFF_G0_NC"}, + {567, "R_AARCH64_TLSDESC_LDR"}, + {568, "R_AARCH64_TLSDESC_ADD"}, + {569, "R_AARCH64_TLSDESC_CALL"}, + {570, "R_AARCH64_TLSLE_LDST128_TPREL_LO12"}, + {571, "R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC"}, + {572, "R_AARCH64_TLSLD_LDST128_DTPREL_LO12"}, + {573, "R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC"}, + {1024, "R_AARCH64_COPY"}, + {1025, "R_AARCH64_GLOB_DAT"}, + {1026, "R_AARCH64_JUMP_SLOT"}, + {1027, "R_AARCH64_RELATIVE"}, + {1028, "R_AARCH64_TLS_DTPMOD64"}, + {1029, "R_AARCH64_TLS_DTPREL64"}, + {1030, "R_AARCH64_TLS_TPREL64"}, + {1031, "R_AARCH64_TLSDESC"}, + {1032, "R_AARCH64_IRELATIVE"}, +} + +func (i R_AARCH64) String() string { return stringName(uint32(i), raarch64Strings, false) } +func (i R_AARCH64) GoString() string { return stringName(uint32(i), raarch64Strings, true) } + +// Relocation types for Alpha. +type R_ALPHA int + +const ( + R_ALPHA_NONE R_ALPHA = 0 /* No reloc */ + R_ALPHA_REFLONG R_ALPHA = 1 /* Direct 32 bit */ + R_ALPHA_REFQUAD R_ALPHA = 2 /* Direct 64 bit */ + R_ALPHA_GPREL32 R_ALPHA = 3 /* GP relative 32 bit */ + R_ALPHA_LITERAL R_ALPHA = 4 /* GP relative 16 bit w/optimization */ + R_ALPHA_LITUSE R_ALPHA = 5 /* Optimization hint for LITERAL */ + R_ALPHA_GPDISP R_ALPHA = 6 /* Add displacement to GP */ + R_ALPHA_BRADDR R_ALPHA = 7 /* PC+4 relative 23 bit shifted */ + R_ALPHA_HINT R_ALPHA = 8 /* PC+4 relative 16 bit shifted */ + R_ALPHA_SREL16 R_ALPHA = 9 /* PC relative 16 bit */ + R_ALPHA_SREL32 R_ALPHA = 10 /* PC relative 32 bit */ + R_ALPHA_SREL64 R_ALPHA = 11 /* PC relative 64 bit */ + R_ALPHA_OP_PUSH R_ALPHA = 12 /* OP stack push */ + R_ALPHA_OP_STORE R_ALPHA = 13 /* OP stack pop and store */ + R_ALPHA_OP_PSUB R_ALPHA = 14 /* OP stack subtract */ + R_ALPHA_OP_PRSHIFT R_ALPHA = 15 /* OP stack right shift */ + R_ALPHA_GPVALUE R_ALPHA = 16 + R_ALPHA_GPRELHIGH R_ALPHA = 17 + R_ALPHA_GPRELLOW R_ALPHA = 18 + R_ALPHA_IMMED_GP_16 R_ALPHA = 19 + R_ALPHA_IMMED_GP_HI32 R_ALPHA = 20 + R_ALPHA_IMMED_SCN_HI32 R_ALPHA = 21 + R_ALPHA_IMMED_BR_HI32 R_ALPHA = 22 + R_ALPHA_IMMED_LO32 R_ALPHA = 23 + R_ALPHA_COPY R_ALPHA = 24 /* Copy symbol at runtime */ + R_ALPHA_GLOB_DAT R_ALPHA = 25 /* Create GOT entry */ + R_ALPHA_JMP_SLOT R_ALPHA = 26 /* Create PLT entry */ + R_ALPHA_RELATIVE R_ALPHA = 27 /* Adjust by program base */ +) + +var ralphaStrings = []intName{ + {0, "R_ALPHA_NONE"}, + {1, "R_ALPHA_REFLONG"}, + {2, "R_ALPHA_REFQUAD"}, + {3, "R_ALPHA_GPREL32"}, + {4, "R_ALPHA_LITERAL"}, + {5, "R_ALPHA_LITUSE"}, + {6, "R_ALPHA_GPDISP"}, + {7, "R_ALPHA_BRADDR"}, + {8, "R_ALPHA_HINT"}, + {9, "R_ALPHA_SREL16"}, + {10, "R_ALPHA_SREL32"}, + {11, "R_ALPHA_SREL64"}, + {12, "R_ALPHA_OP_PUSH"}, + {13, "R_ALPHA_OP_STORE"}, + {14, "R_ALPHA_OP_PSUB"}, + {15, "R_ALPHA_OP_PRSHIFT"}, + {16, "R_ALPHA_GPVALUE"}, + {17, "R_ALPHA_GPRELHIGH"}, + {18, "R_ALPHA_GPRELLOW"}, + {19, "R_ALPHA_IMMED_GP_16"}, + {20, "R_ALPHA_IMMED_GP_HI32"}, + {21, "R_ALPHA_IMMED_SCN_HI32"}, + {22, "R_ALPHA_IMMED_BR_HI32"}, + {23, "R_ALPHA_IMMED_LO32"}, + {24, "R_ALPHA_COPY"}, + {25, "R_ALPHA_GLOB_DAT"}, + {26, "R_ALPHA_JMP_SLOT"}, + {27, "R_ALPHA_RELATIVE"}, +} + +func (i R_ALPHA) String() string { return stringName(uint32(i), ralphaStrings, false) } +func (i R_ALPHA) GoString() string { return stringName(uint32(i), ralphaStrings, true) } + +// Relocation types for ARM. +type R_ARM int + +const ( + R_ARM_NONE R_ARM = 0 /* No relocation. */ + R_ARM_PC24 R_ARM = 1 + R_ARM_ABS32 R_ARM = 2 + R_ARM_REL32 R_ARM = 3 + R_ARM_PC13 R_ARM = 4 + R_ARM_ABS16 R_ARM = 5 + R_ARM_ABS12 R_ARM = 6 + R_ARM_THM_ABS5 R_ARM = 7 + R_ARM_ABS8 R_ARM = 8 + R_ARM_SBREL32 R_ARM = 9 + R_ARM_THM_PC22 R_ARM = 10 + R_ARM_THM_PC8 R_ARM = 11 + R_ARM_AMP_VCALL9 R_ARM = 12 + R_ARM_SWI24 R_ARM = 13 + R_ARM_THM_SWI8 R_ARM = 14 + R_ARM_XPC25 R_ARM = 15 + R_ARM_THM_XPC22 R_ARM = 16 + R_ARM_TLS_DTPMOD32 R_ARM = 17 + R_ARM_TLS_DTPOFF32 R_ARM = 18 + R_ARM_TLS_TPOFF32 R_ARM = 19 + R_ARM_COPY R_ARM = 20 /* Copy data from shared object. */ + R_ARM_GLOB_DAT R_ARM = 21 /* Set GOT entry to data address. */ + R_ARM_JUMP_SLOT R_ARM = 22 /* Set GOT entry to code address. */ + R_ARM_RELATIVE R_ARM = 23 /* Add load address of shared object. */ + R_ARM_GOTOFF R_ARM = 24 /* Add GOT-relative symbol address. */ + R_ARM_GOTPC R_ARM = 25 /* Add PC-relative GOT table address. */ + R_ARM_GOT32 R_ARM = 26 /* Add PC-relative GOT offset. */ + R_ARM_PLT32 R_ARM = 27 /* Add PC-relative PLT offset. */ + R_ARM_CALL R_ARM = 28 + R_ARM_JUMP24 R_ARM = 29 + R_ARM_THM_JUMP24 R_ARM = 30 + R_ARM_BASE_ABS R_ARM = 31 + R_ARM_ALU_PCREL_7_0 R_ARM = 32 + R_ARM_ALU_PCREL_15_8 R_ARM = 33 + R_ARM_ALU_PCREL_23_15 R_ARM = 34 + R_ARM_LDR_SBREL_11_10_NC R_ARM = 35 + R_ARM_ALU_SBREL_19_12_NC R_ARM = 36 + R_ARM_ALU_SBREL_27_20_CK R_ARM = 37 + R_ARM_TARGET1 R_ARM = 38 + R_ARM_SBREL31 R_ARM = 39 + R_ARM_V4BX R_ARM = 40 + R_ARM_TARGET2 R_ARM = 41 + R_ARM_PREL31 R_ARM = 42 + R_ARM_MOVW_ABS_NC R_ARM = 43 + R_ARM_MOVT_ABS R_ARM = 44 + R_ARM_MOVW_PREL_NC R_ARM = 45 + R_ARM_MOVT_PREL R_ARM = 46 + R_ARM_THM_MOVW_ABS_NC R_ARM = 47 + R_ARM_THM_MOVT_ABS R_ARM = 48 + R_ARM_THM_MOVW_PREL_NC R_ARM = 49 + R_ARM_THM_MOVT_PREL R_ARM = 50 + R_ARM_THM_JUMP19 R_ARM = 51 + R_ARM_THM_JUMP6 R_ARM = 52 + R_ARM_THM_ALU_PREL_11_0 R_ARM = 53 + R_ARM_THM_PC12 R_ARM = 54 + R_ARM_ABS32_NOI R_ARM = 55 + R_ARM_REL32_NOI R_ARM = 56 + R_ARM_ALU_PC_G0_NC R_ARM = 57 + R_ARM_ALU_PC_G0 R_ARM = 58 + R_ARM_ALU_PC_G1_NC R_ARM = 59 + R_ARM_ALU_PC_G1 R_ARM = 60 + R_ARM_ALU_PC_G2 R_ARM = 61 + R_ARM_LDR_PC_G1 R_ARM = 62 + R_ARM_LDR_PC_G2 R_ARM = 63 + R_ARM_LDRS_PC_G0 R_ARM = 64 + R_ARM_LDRS_PC_G1 R_ARM = 65 + R_ARM_LDRS_PC_G2 R_ARM = 66 + R_ARM_LDC_PC_G0 R_ARM = 67 + R_ARM_LDC_PC_G1 R_ARM = 68 + R_ARM_LDC_PC_G2 R_ARM = 69 + R_ARM_ALU_SB_G0_NC R_ARM = 70 + R_ARM_ALU_SB_G0 R_ARM = 71 + R_ARM_ALU_SB_G1_NC R_ARM = 72 + R_ARM_ALU_SB_G1 R_ARM = 73 + R_ARM_ALU_SB_G2 R_ARM = 74 + R_ARM_LDR_SB_G0 R_ARM = 75 + R_ARM_LDR_SB_G1 R_ARM = 76 + R_ARM_LDR_SB_G2 R_ARM = 77 + R_ARM_LDRS_SB_G0 R_ARM = 78 + R_ARM_LDRS_SB_G1 R_ARM = 79 + R_ARM_LDRS_SB_G2 R_ARM = 80 + R_ARM_LDC_SB_G0 R_ARM = 81 + R_ARM_LDC_SB_G1 R_ARM = 82 + R_ARM_LDC_SB_G2 R_ARM = 83 + R_ARM_MOVW_BREL_NC R_ARM = 84 + R_ARM_MOVT_BREL R_ARM = 85 + R_ARM_MOVW_BREL R_ARM = 86 + R_ARM_THM_MOVW_BREL_NC R_ARM = 87 + R_ARM_THM_MOVT_BREL R_ARM = 88 + R_ARM_THM_MOVW_BREL R_ARM = 89 + R_ARM_TLS_GOTDESC R_ARM = 90 + R_ARM_TLS_CALL R_ARM = 91 + R_ARM_TLS_DESCSEQ R_ARM = 92 + R_ARM_THM_TLS_CALL R_ARM = 93 + R_ARM_PLT32_ABS R_ARM = 94 + R_ARM_GOT_ABS R_ARM = 95 + R_ARM_GOT_PREL R_ARM = 96 + R_ARM_GOT_BREL12 R_ARM = 97 + R_ARM_GOTOFF12 R_ARM = 98 + R_ARM_GOTRELAX R_ARM = 99 + R_ARM_GNU_VTENTRY R_ARM = 100 + R_ARM_GNU_VTINHERIT R_ARM = 101 + R_ARM_THM_JUMP11 R_ARM = 102 + R_ARM_THM_JUMP8 R_ARM = 103 + R_ARM_TLS_GD32 R_ARM = 104 + R_ARM_TLS_LDM32 R_ARM = 105 + R_ARM_TLS_LDO32 R_ARM = 106 + R_ARM_TLS_IE32 R_ARM = 107 + R_ARM_TLS_LE32 R_ARM = 108 + R_ARM_TLS_LDO12 R_ARM = 109 + R_ARM_TLS_LE12 R_ARM = 110 + R_ARM_TLS_IE12GP R_ARM = 111 + R_ARM_PRIVATE_0 R_ARM = 112 + R_ARM_PRIVATE_1 R_ARM = 113 + R_ARM_PRIVATE_2 R_ARM = 114 + R_ARM_PRIVATE_3 R_ARM = 115 + R_ARM_PRIVATE_4 R_ARM = 116 + R_ARM_PRIVATE_5 R_ARM = 117 + R_ARM_PRIVATE_6 R_ARM = 118 + R_ARM_PRIVATE_7 R_ARM = 119 + R_ARM_PRIVATE_8 R_ARM = 120 + R_ARM_PRIVATE_9 R_ARM = 121 + R_ARM_PRIVATE_10 R_ARM = 122 + R_ARM_PRIVATE_11 R_ARM = 123 + R_ARM_PRIVATE_12 R_ARM = 124 + R_ARM_PRIVATE_13 R_ARM = 125 + R_ARM_PRIVATE_14 R_ARM = 126 + R_ARM_PRIVATE_15 R_ARM = 127 + R_ARM_ME_TOO R_ARM = 128 + R_ARM_THM_TLS_DESCSEQ16 R_ARM = 129 + R_ARM_THM_TLS_DESCSEQ32 R_ARM = 130 + R_ARM_THM_GOT_BREL12 R_ARM = 131 + R_ARM_THM_ALU_ABS_G0_NC R_ARM = 132 + R_ARM_THM_ALU_ABS_G1_NC R_ARM = 133 + R_ARM_THM_ALU_ABS_G2_NC R_ARM = 134 + R_ARM_THM_ALU_ABS_G3 R_ARM = 135 + R_ARM_IRELATIVE R_ARM = 160 + R_ARM_RXPC25 R_ARM = 249 + R_ARM_RSBREL32 R_ARM = 250 + R_ARM_THM_RPC22 R_ARM = 251 + R_ARM_RREL32 R_ARM = 252 + R_ARM_RABS32 R_ARM = 253 + R_ARM_RPC24 R_ARM = 254 + R_ARM_RBASE R_ARM = 255 +) + +var rarmStrings = []intName{ + {0, "R_ARM_NONE"}, + {1, "R_ARM_PC24"}, + {2, "R_ARM_ABS32"}, + {3, "R_ARM_REL32"}, + {4, "R_ARM_PC13"}, + {5, "R_ARM_ABS16"}, + {6, "R_ARM_ABS12"}, + {7, "R_ARM_THM_ABS5"}, + {8, "R_ARM_ABS8"}, + {9, "R_ARM_SBREL32"}, + {10, "R_ARM_THM_PC22"}, + {11, "R_ARM_THM_PC8"}, + {12, "R_ARM_AMP_VCALL9"}, + {13, "R_ARM_SWI24"}, + {14, "R_ARM_THM_SWI8"}, + {15, "R_ARM_XPC25"}, + {16, "R_ARM_THM_XPC22"}, + {17, "R_ARM_TLS_DTPMOD32"}, + {18, "R_ARM_TLS_DTPOFF32"}, + {19, "R_ARM_TLS_TPOFF32"}, + {20, "R_ARM_COPY"}, + {21, "R_ARM_GLOB_DAT"}, + {22, "R_ARM_JUMP_SLOT"}, + {23, "R_ARM_RELATIVE"}, + {24, "R_ARM_GOTOFF"}, + {25, "R_ARM_GOTPC"}, + {26, "R_ARM_GOT32"}, + {27, "R_ARM_PLT32"}, + {28, "R_ARM_CALL"}, + {29, "R_ARM_JUMP24"}, + {30, "R_ARM_THM_JUMP24"}, + {31, "R_ARM_BASE_ABS"}, + {32, "R_ARM_ALU_PCREL_7_0"}, + {33, "R_ARM_ALU_PCREL_15_8"}, + {34, "R_ARM_ALU_PCREL_23_15"}, + {35, "R_ARM_LDR_SBREL_11_10_NC"}, + {36, "R_ARM_ALU_SBREL_19_12_NC"}, + {37, "R_ARM_ALU_SBREL_27_20_CK"}, + {38, "R_ARM_TARGET1"}, + {39, "R_ARM_SBREL31"}, + {40, "R_ARM_V4BX"}, + {41, "R_ARM_TARGET2"}, + {42, "R_ARM_PREL31"}, + {43, "R_ARM_MOVW_ABS_NC"}, + {44, "R_ARM_MOVT_ABS"}, + {45, "R_ARM_MOVW_PREL_NC"}, + {46, "R_ARM_MOVT_PREL"}, + {47, "R_ARM_THM_MOVW_ABS_NC"}, + {48, "R_ARM_THM_MOVT_ABS"}, + {49, "R_ARM_THM_MOVW_PREL_NC"}, + {50, "R_ARM_THM_MOVT_PREL"}, + {51, "R_ARM_THM_JUMP19"}, + {52, "R_ARM_THM_JUMP6"}, + {53, "R_ARM_THM_ALU_PREL_11_0"}, + {54, "R_ARM_THM_PC12"}, + {55, "R_ARM_ABS32_NOI"}, + {56, "R_ARM_REL32_NOI"}, + {57, "R_ARM_ALU_PC_G0_NC"}, + {58, "R_ARM_ALU_PC_G0"}, + {59, "R_ARM_ALU_PC_G1_NC"}, + {60, "R_ARM_ALU_PC_G1"}, + {61, "R_ARM_ALU_PC_G2"}, + {62, "R_ARM_LDR_PC_G1"}, + {63, "R_ARM_LDR_PC_G2"}, + {64, "R_ARM_LDRS_PC_G0"}, + {65, "R_ARM_LDRS_PC_G1"}, + {66, "R_ARM_LDRS_PC_G2"}, + {67, "R_ARM_LDC_PC_G0"}, + {68, "R_ARM_LDC_PC_G1"}, + {69, "R_ARM_LDC_PC_G2"}, + {70, "R_ARM_ALU_SB_G0_NC"}, + {71, "R_ARM_ALU_SB_G0"}, + {72, "R_ARM_ALU_SB_G1_NC"}, + {73, "R_ARM_ALU_SB_G1"}, + {74, "R_ARM_ALU_SB_G2"}, + {75, "R_ARM_LDR_SB_G0"}, + {76, "R_ARM_LDR_SB_G1"}, + {77, "R_ARM_LDR_SB_G2"}, + {78, "R_ARM_LDRS_SB_G0"}, + {79, "R_ARM_LDRS_SB_G1"}, + {80, "R_ARM_LDRS_SB_G2"}, + {81, "R_ARM_LDC_SB_G0"}, + {82, "R_ARM_LDC_SB_G1"}, + {83, "R_ARM_LDC_SB_G2"}, + {84, "R_ARM_MOVW_BREL_NC"}, + {85, "R_ARM_MOVT_BREL"}, + {86, "R_ARM_MOVW_BREL"}, + {87, "R_ARM_THM_MOVW_BREL_NC"}, + {88, "R_ARM_THM_MOVT_BREL"}, + {89, "R_ARM_THM_MOVW_BREL"}, + {90, "R_ARM_TLS_GOTDESC"}, + {91, "R_ARM_TLS_CALL"}, + {92, "R_ARM_TLS_DESCSEQ"}, + {93, "R_ARM_THM_TLS_CALL"}, + {94, "R_ARM_PLT32_ABS"}, + {95, "R_ARM_GOT_ABS"}, + {96, "R_ARM_GOT_PREL"}, + {97, "R_ARM_GOT_BREL12"}, + {98, "R_ARM_GOTOFF12"}, + {99, "R_ARM_GOTRELAX"}, + {100, "R_ARM_GNU_VTENTRY"}, + {101, "R_ARM_GNU_VTINHERIT"}, + {102, "R_ARM_THM_JUMP11"}, + {103, "R_ARM_THM_JUMP8"}, + {104, "R_ARM_TLS_GD32"}, + {105, "R_ARM_TLS_LDM32"}, + {106, "R_ARM_TLS_LDO32"}, + {107, "R_ARM_TLS_IE32"}, + {108, "R_ARM_TLS_LE32"}, + {109, "R_ARM_TLS_LDO12"}, + {110, "R_ARM_TLS_LE12"}, + {111, "R_ARM_TLS_IE12GP"}, + {112, "R_ARM_PRIVATE_0"}, + {113, "R_ARM_PRIVATE_1"}, + {114, "R_ARM_PRIVATE_2"}, + {115, "R_ARM_PRIVATE_3"}, + {116, "R_ARM_PRIVATE_4"}, + {117, "R_ARM_PRIVATE_5"}, + {118, "R_ARM_PRIVATE_6"}, + {119, "R_ARM_PRIVATE_7"}, + {120, "R_ARM_PRIVATE_8"}, + {121, "R_ARM_PRIVATE_9"}, + {122, "R_ARM_PRIVATE_10"}, + {123, "R_ARM_PRIVATE_11"}, + {124, "R_ARM_PRIVATE_12"}, + {125, "R_ARM_PRIVATE_13"}, + {126, "R_ARM_PRIVATE_14"}, + {127, "R_ARM_PRIVATE_15"}, + {128, "R_ARM_ME_TOO"}, + {129, "R_ARM_THM_TLS_DESCSEQ16"}, + {130, "R_ARM_THM_TLS_DESCSEQ32"}, + {131, "R_ARM_THM_GOT_BREL12"}, + {132, "R_ARM_THM_ALU_ABS_G0_NC"}, + {133, "R_ARM_THM_ALU_ABS_G1_NC"}, + {134, "R_ARM_THM_ALU_ABS_G2_NC"}, + {135, "R_ARM_THM_ALU_ABS_G3"}, + {160, "R_ARM_IRELATIVE"}, + {249, "R_ARM_RXPC25"}, + {250, "R_ARM_RSBREL32"}, + {251, "R_ARM_THM_RPC22"}, + {252, "R_ARM_RREL32"}, + {253, "R_ARM_RABS32"}, + {254, "R_ARM_RPC24"}, + {255, "R_ARM_RBASE"}, +} + +func (i R_ARM) String() string { return stringName(uint32(i), rarmStrings, false) } +func (i R_ARM) GoString() string { return stringName(uint32(i), rarmStrings, true) } + +// Relocation types for 386. +type R_386 int + +const ( + R_386_NONE R_386 = 0 /* No relocation. */ + R_386_32 R_386 = 1 /* Add symbol value. */ + R_386_PC32 R_386 = 2 /* Add PC-relative symbol value. */ + R_386_GOT32 R_386 = 3 /* Add PC-relative GOT offset. */ + R_386_PLT32 R_386 = 4 /* Add PC-relative PLT offset. */ + R_386_COPY R_386 = 5 /* Copy data from shared object. */ + R_386_GLOB_DAT R_386 = 6 /* Set GOT entry to data address. */ + R_386_JMP_SLOT R_386 = 7 /* Set GOT entry to code address. */ + R_386_RELATIVE R_386 = 8 /* Add load address of shared object. */ + R_386_GOTOFF R_386 = 9 /* Add GOT-relative symbol address. */ + R_386_GOTPC R_386 = 10 /* Add PC-relative GOT table address. */ + R_386_32PLT R_386 = 11 + R_386_TLS_TPOFF R_386 = 14 /* Negative offset in static TLS block */ + R_386_TLS_IE R_386 = 15 /* Absolute address of GOT for -ve static TLS */ + R_386_TLS_GOTIE R_386 = 16 /* GOT entry for negative static TLS block */ + R_386_TLS_LE R_386 = 17 /* Negative offset relative to static TLS */ + R_386_TLS_GD R_386 = 18 /* 32 bit offset to GOT (index,off) pair */ + R_386_TLS_LDM R_386 = 19 /* 32 bit offset to GOT (index,zero) pair */ + R_386_16 R_386 = 20 + R_386_PC16 R_386 = 21 + R_386_8 R_386 = 22 + R_386_PC8 R_386 = 23 + R_386_TLS_GD_32 R_386 = 24 /* 32 bit offset to GOT (index,off) pair */ + R_386_TLS_GD_PUSH R_386 = 25 /* pushl instruction for Sun ABI GD sequence */ + R_386_TLS_GD_CALL R_386 = 26 /* call instruction for Sun ABI GD sequence */ + R_386_TLS_GD_POP R_386 = 27 /* popl instruction for Sun ABI GD sequence */ + R_386_TLS_LDM_32 R_386 = 28 /* 32 bit offset to GOT (index,zero) pair */ + R_386_TLS_LDM_PUSH R_386 = 29 /* pushl instruction for Sun ABI LD sequence */ + R_386_TLS_LDM_CALL R_386 = 30 /* call instruction for Sun ABI LD sequence */ + R_386_TLS_LDM_POP R_386 = 31 /* popl instruction for Sun ABI LD sequence */ + R_386_TLS_LDO_32 R_386 = 32 /* 32 bit offset from start of TLS block */ + R_386_TLS_IE_32 R_386 = 33 /* 32 bit offset to GOT static TLS offset entry */ + R_386_TLS_LE_32 R_386 = 34 /* 32 bit offset within static TLS block */ + R_386_TLS_DTPMOD32 R_386 = 35 /* GOT entry containing TLS index */ + R_386_TLS_DTPOFF32 R_386 = 36 /* GOT entry containing TLS offset */ + R_386_TLS_TPOFF32 R_386 = 37 /* GOT entry of -ve static TLS offset */ + R_386_SIZE32 R_386 = 38 + R_386_TLS_GOTDESC R_386 = 39 + R_386_TLS_DESC_CALL R_386 = 40 + R_386_TLS_DESC R_386 = 41 + R_386_IRELATIVE R_386 = 42 + R_386_GOT32X R_386 = 43 +) + +var r386Strings = []intName{ + {0, "R_386_NONE"}, + {1, "R_386_32"}, + {2, "R_386_PC32"}, + {3, "R_386_GOT32"}, + {4, "R_386_PLT32"}, + {5, "R_386_COPY"}, + {6, "R_386_GLOB_DAT"}, + {7, "R_386_JMP_SLOT"}, + {8, "R_386_RELATIVE"}, + {9, "R_386_GOTOFF"}, + {10, "R_386_GOTPC"}, + {11, "R_386_32PLT"}, + {14, "R_386_TLS_TPOFF"}, + {15, "R_386_TLS_IE"}, + {16, "R_386_TLS_GOTIE"}, + {17, "R_386_TLS_LE"}, + {18, "R_386_TLS_GD"}, + {19, "R_386_TLS_LDM"}, + {20, "R_386_16"}, + {21, "R_386_PC16"}, + {22, "R_386_8"}, + {23, "R_386_PC8"}, + {24, "R_386_TLS_GD_32"}, + {25, "R_386_TLS_GD_PUSH"}, + {26, "R_386_TLS_GD_CALL"}, + {27, "R_386_TLS_GD_POP"}, + {28, "R_386_TLS_LDM_32"}, + {29, "R_386_TLS_LDM_PUSH"}, + {30, "R_386_TLS_LDM_CALL"}, + {31, "R_386_TLS_LDM_POP"}, + {32, "R_386_TLS_LDO_32"}, + {33, "R_386_TLS_IE_32"}, + {34, "R_386_TLS_LE_32"}, + {35, "R_386_TLS_DTPMOD32"}, + {36, "R_386_TLS_DTPOFF32"}, + {37, "R_386_TLS_TPOFF32"}, + {38, "R_386_SIZE32"}, + {39, "R_386_TLS_GOTDESC"}, + {40, "R_386_TLS_DESC_CALL"}, + {41, "R_386_TLS_DESC"}, + {42, "R_386_IRELATIVE"}, + {43, "R_386_GOT32X"}, +} + +func (i R_386) String() string { return stringName(uint32(i), r386Strings, false) } +func (i R_386) GoString() string { return stringName(uint32(i), r386Strings, true) } + +// Relocation types for MIPS. +type R_MIPS int + +const ( + R_MIPS_NONE R_MIPS = 0 + R_MIPS_16 R_MIPS = 1 + R_MIPS_32 R_MIPS = 2 + R_MIPS_REL32 R_MIPS = 3 + R_MIPS_26 R_MIPS = 4 + R_MIPS_HI16 R_MIPS = 5 /* high 16 bits of symbol value */ + R_MIPS_LO16 R_MIPS = 6 /* low 16 bits of symbol value */ + R_MIPS_GPREL16 R_MIPS = 7 /* GP-relative reference */ + R_MIPS_LITERAL R_MIPS = 8 /* Reference to literal section */ + R_MIPS_GOT16 R_MIPS = 9 /* Reference to global offset table */ + R_MIPS_PC16 R_MIPS = 10 /* 16 bit PC relative reference */ + R_MIPS_CALL16 R_MIPS = 11 /* 16 bit call through glbl offset tbl */ + R_MIPS_GPREL32 R_MIPS = 12 + R_MIPS_SHIFT5 R_MIPS = 16 + R_MIPS_SHIFT6 R_MIPS = 17 + R_MIPS_64 R_MIPS = 18 + R_MIPS_GOT_DISP R_MIPS = 19 + R_MIPS_GOT_PAGE R_MIPS = 20 + R_MIPS_GOT_OFST R_MIPS = 21 + R_MIPS_GOT_HI16 R_MIPS = 22 + R_MIPS_GOT_LO16 R_MIPS = 23 + R_MIPS_SUB R_MIPS = 24 + R_MIPS_INSERT_A R_MIPS = 25 + R_MIPS_INSERT_B R_MIPS = 26 + R_MIPS_DELETE R_MIPS = 27 + R_MIPS_HIGHER R_MIPS = 28 + R_MIPS_HIGHEST R_MIPS = 29 + R_MIPS_CALL_HI16 R_MIPS = 30 + R_MIPS_CALL_LO16 R_MIPS = 31 + R_MIPS_SCN_DISP R_MIPS = 32 + R_MIPS_REL16 R_MIPS = 33 + R_MIPS_ADD_IMMEDIATE R_MIPS = 34 + R_MIPS_PJUMP R_MIPS = 35 + R_MIPS_RELGOT R_MIPS = 36 + R_MIPS_JALR R_MIPS = 37 + + R_MIPS_TLS_DTPMOD32 R_MIPS = 38 /* Module number 32 bit */ + R_MIPS_TLS_DTPREL32 R_MIPS = 39 /* Module-relative offset 32 bit */ + R_MIPS_TLS_DTPMOD64 R_MIPS = 40 /* Module number 64 bit */ + R_MIPS_TLS_DTPREL64 R_MIPS = 41 /* Module-relative offset 64 bit */ + R_MIPS_TLS_GD R_MIPS = 42 /* 16 bit GOT offset for GD */ + R_MIPS_TLS_LDM R_MIPS = 43 /* 16 bit GOT offset for LDM */ + R_MIPS_TLS_DTPREL_HI16 R_MIPS = 44 /* Module-relative offset, high 16 bits */ + R_MIPS_TLS_DTPREL_LO16 R_MIPS = 45 /* Module-relative offset, low 16 bits */ + R_MIPS_TLS_GOTTPREL R_MIPS = 46 /* 16 bit GOT offset for IE */ + R_MIPS_TLS_TPREL32 R_MIPS = 47 /* TP-relative offset, 32 bit */ + R_MIPS_TLS_TPREL64 R_MIPS = 48 /* TP-relative offset, 64 bit */ + R_MIPS_TLS_TPREL_HI16 R_MIPS = 49 /* TP-relative offset, high 16 bits */ + R_MIPS_TLS_TPREL_LO16 R_MIPS = 50 /* TP-relative offset, low 16 bits */ +) + +var rmipsStrings = []intName{ + {0, "R_MIPS_NONE"}, + {1, "R_MIPS_16"}, + {2, "R_MIPS_32"}, + {3, "R_MIPS_REL32"}, + {4, "R_MIPS_26"}, + {5, "R_MIPS_HI16"}, + {6, "R_MIPS_LO16"}, + {7, "R_MIPS_GPREL16"}, + {8, "R_MIPS_LITERAL"}, + {9, "R_MIPS_GOT16"}, + {10, "R_MIPS_PC16"}, + {11, "R_MIPS_CALL16"}, + {12, "R_MIPS_GPREL32"}, + {16, "R_MIPS_SHIFT5"}, + {17, "R_MIPS_SHIFT6"}, + {18, "R_MIPS_64"}, + {19, "R_MIPS_GOT_DISP"}, + {20, "R_MIPS_GOT_PAGE"}, + {21, "R_MIPS_GOT_OFST"}, + {22, "R_MIPS_GOT_HI16"}, + {23, "R_MIPS_GOT_LO16"}, + {24, "R_MIPS_SUB"}, + {25, "R_MIPS_INSERT_A"}, + {26, "R_MIPS_INSERT_B"}, + {27, "R_MIPS_DELETE"}, + {28, "R_MIPS_HIGHER"}, + {29, "R_MIPS_HIGHEST"}, + {30, "R_MIPS_CALL_HI16"}, + {31, "R_MIPS_CALL_LO16"}, + {32, "R_MIPS_SCN_DISP"}, + {33, "R_MIPS_REL16"}, + {34, "R_MIPS_ADD_IMMEDIATE"}, + {35, "R_MIPS_PJUMP"}, + {36, "R_MIPS_RELGOT"}, + {37, "R_MIPS_JALR"}, + {38, "R_MIPS_TLS_DTPMOD32"}, + {39, "R_MIPS_TLS_DTPREL32"}, + {40, "R_MIPS_TLS_DTPMOD64"}, + {41, "R_MIPS_TLS_DTPREL64"}, + {42, "R_MIPS_TLS_GD"}, + {43, "R_MIPS_TLS_LDM"}, + {44, "R_MIPS_TLS_DTPREL_HI16"}, + {45, "R_MIPS_TLS_DTPREL_LO16"}, + {46, "R_MIPS_TLS_GOTTPREL"}, + {47, "R_MIPS_TLS_TPREL32"}, + {48, "R_MIPS_TLS_TPREL64"}, + {49, "R_MIPS_TLS_TPREL_HI16"}, + {50, "R_MIPS_TLS_TPREL_LO16"}, +} + +func (i R_MIPS) String() string { return stringName(uint32(i), rmipsStrings, false) } +func (i R_MIPS) GoString() string { return stringName(uint32(i), rmipsStrings, true) } + +// Relocation types for PowerPC. +// +// Values that are shared by both R_PPC and R_PPC64 are prefixed with +// R_POWERPC_ in the ELF standard. For the R_PPC type, the relevant +// shared relocations have been renamed with the prefix R_PPC_. +// The original name follows the value in a comment. +type R_PPC int + +const ( + R_PPC_NONE R_PPC = 0 // R_POWERPC_NONE + R_PPC_ADDR32 R_PPC = 1 // R_POWERPC_ADDR32 + R_PPC_ADDR24 R_PPC = 2 // R_POWERPC_ADDR24 + R_PPC_ADDR16 R_PPC = 3 // R_POWERPC_ADDR16 + R_PPC_ADDR16_LO R_PPC = 4 // R_POWERPC_ADDR16_LO + R_PPC_ADDR16_HI R_PPC = 5 // R_POWERPC_ADDR16_HI + R_PPC_ADDR16_HA R_PPC = 6 // R_POWERPC_ADDR16_HA + R_PPC_ADDR14 R_PPC = 7 // R_POWERPC_ADDR14 + R_PPC_ADDR14_BRTAKEN R_PPC = 8 // R_POWERPC_ADDR14_BRTAKEN + R_PPC_ADDR14_BRNTAKEN R_PPC = 9 // R_POWERPC_ADDR14_BRNTAKEN + R_PPC_REL24 R_PPC = 10 // R_POWERPC_REL24 + R_PPC_REL14 R_PPC = 11 // R_POWERPC_REL14 + R_PPC_REL14_BRTAKEN R_PPC = 12 // R_POWERPC_REL14_BRTAKEN + R_PPC_REL14_BRNTAKEN R_PPC = 13 // R_POWERPC_REL14_BRNTAKEN + R_PPC_GOT16 R_PPC = 14 // R_POWERPC_GOT16 + R_PPC_GOT16_LO R_PPC = 15 // R_POWERPC_GOT16_LO + R_PPC_GOT16_HI R_PPC = 16 // R_POWERPC_GOT16_HI + R_PPC_GOT16_HA R_PPC = 17 // R_POWERPC_GOT16_HA + R_PPC_PLTREL24 R_PPC = 18 + R_PPC_COPY R_PPC = 19 // R_POWERPC_COPY + R_PPC_GLOB_DAT R_PPC = 20 // R_POWERPC_GLOB_DAT + R_PPC_JMP_SLOT R_PPC = 21 // R_POWERPC_JMP_SLOT + R_PPC_RELATIVE R_PPC = 22 // R_POWERPC_RELATIVE + R_PPC_LOCAL24PC R_PPC = 23 + R_PPC_UADDR32 R_PPC = 24 // R_POWERPC_UADDR32 + R_PPC_UADDR16 R_PPC = 25 // R_POWERPC_UADDR16 + R_PPC_REL32 R_PPC = 26 // R_POWERPC_REL32 + R_PPC_PLT32 R_PPC = 27 // R_POWERPC_PLT32 + R_PPC_PLTREL32 R_PPC = 28 // R_POWERPC_PLTREL32 + R_PPC_PLT16_LO R_PPC = 29 // R_POWERPC_PLT16_LO + R_PPC_PLT16_HI R_PPC = 30 // R_POWERPC_PLT16_HI + R_PPC_PLT16_HA R_PPC = 31 // R_POWERPC_PLT16_HA + R_PPC_SDAREL16 R_PPC = 32 + R_PPC_SECTOFF R_PPC = 33 // R_POWERPC_SECTOFF + R_PPC_SECTOFF_LO R_PPC = 34 // R_POWERPC_SECTOFF_LO + R_PPC_SECTOFF_HI R_PPC = 35 // R_POWERPC_SECTOFF_HI + R_PPC_SECTOFF_HA R_PPC = 36 // R_POWERPC_SECTOFF_HA + R_PPC_TLS R_PPC = 67 // R_POWERPC_TLS + R_PPC_DTPMOD32 R_PPC = 68 // R_POWERPC_DTPMOD32 + R_PPC_TPREL16 R_PPC = 69 // R_POWERPC_TPREL16 + R_PPC_TPREL16_LO R_PPC = 70 // R_POWERPC_TPREL16_LO + R_PPC_TPREL16_HI R_PPC = 71 // R_POWERPC_TPREL16_HI + R_PPC_TPREL16_HA R_PPC = 72 // R_POWERPC_TPREL16_HA + R_PPC_TPREL32 R_PPC = 73 // R_POWERPC_TPREL32 + R_PPC_DTPREL16 R_PPC = 74 // R_POWERPC_DTPREL16 + R_PPC_DTPREL16_LO R_PPC = 75 // R_POWERPC_DTPREL16_LO + R_PPC_DTPREL16_HI R_PPC = 76 // R_POWERPC_DTPREL16_HI + R_PPC_DTPREL16_HA R_PPC = 77 // R_POWERPC_DTPREL16_HA + R_PPC_DTPREL32 R_PPC = 78 // R_POWERPC_DTPREL32 + R_PPC_GOT_TLSGD16 R_PPC = 79 // R_POWERPC_GOT_TLSGD16 + R_PPC_GOT_TLSGD16_LO R_PPC = 80 // R_POWERPC_GOT_TLSGD16_LO + R_PPC_GOT_TLSGD16_HI R_PPC = 81 // R_POWERPC_GOT_TLSGD16_HI + R_PPC_GOT_TLSGD16_HA R_PPC = 82 // R_POWERPC_GOT_TLSGD16_HA + R_PPC_GOT_TLSLD16 R_PPC = 83 // R_POWERPC_GOT_TLSLD16 + R_PPC_GOT_TLSLD16_LO R_PPC = 84 // R_POWERPC_GOT_TLSLD16_LO + R_PPC_GOT_TLSLD16_HI R_PPC = 85 // R_POWERPC_GOT_TLSLD16_HI + R_PPC_GOT_TLSLD16_HA R_PPC = 86 // R_POWERPC_GOT_TLSLD16_HA + R_PPC_GOT_TPREL16 R_PPC = 87 // R_POWERPC_GOT_TPREL16 + R_PPC_GOT_TPREL16_LO R_PPC = 88 // R_POWERPC_GOT_TPREL16_LO + R_PPC_GOT_TPREL16_HI R_PPC = 89 // R_POWERPC_GOT_TPREL16_HI + R_PPC_GOT_TPREL16_HA R_PPC = 90 // R_POWERPC_GOT_TPREL16_HA + R_PPC_EMB_NADDR32 R_PPC = 101 + R_PPC_EMB_NADDR16 R_PPC = 102 + R_PPC_EMB_NADDR16_LO R_PPC = 103 + R_PPC_EMB_NADDR16_HI R_PPC = 104 + R_PPC_EMB_NADDR16_HA R_PPC = 105 + R_PPC_EMB_SDAI16 R_PPC = 106 + R_PPC_EMB_SDA2I16 R_PPC = 107 + R_PPC_EMB_SDA2REL R_PPC = 108 + R_PPC_EMB_SDA21 R_PPC = 109 + R_PPC_EMB_MRKREF R_PPC = 110 + R_PPC_EMB_RELSEC16 R_PPC = 111 + R_PPC_EMB_RELST_LO R_PPC = 112 + R_PPC_EMB_RELST_HI R_PPC = 113 + R_PPC_EMB_RELST_HA R_PPC = 114 + R_PPC_EMB_BIT_FLD R_PPC = 115 + R_PPC_EMB_RELSDA R_PPC = 116 +) + +var rppcStrings = []intName{ + {0, "R_PPC_NONE"}, + {1, "R_PPC_ADDR32"}, + {2, "R_PPC_ADDR24"}, + {3, "R_PPC_ADDR16"}, + {4, "R_PPC_ADDR16_LO"}, + {5, "R_PPC_ADDR16_HI"}, + {6, "R_PPC_ADDR16_HA"}, + {7, "R_PPC_ADDR14"}, + {8, "R_PPC_ADDR14_BRTAKEN"}, + {9, "R_PPC_ADDR14_BRNTAKEN"}, + {10, "R_PPC_REL24"}, + {11, "R_PPC_REL14"}, + {12, "R_PPC_REL14_BRTAKEN"}, + {13, "R_PPC_REL14_BRNTAKEN"}, + {14, "R_PPC_GOT16"}, + {15, "R_PPC_GOT16_LO"}, + {16, "R_PPC_GOT16_HI"}, + {17, "R_PPC_GOT16_HA"}, + {18, "R_PPC_PLTREL24"}, + {19, "R_PPC_COPY"}, + {20, "R_PPC_GLOB_DAT"}, + {21, "R_PPC_JMP_SLOT"}, + {22, "R_PPC_RELATIVE"}, + {23, "R_PPC_LOCAL24PC"}, + {24, "R_PPC_UADDR32"}, + {25, "R_PPC_UADDR16"}, + {26, "R_PPC_REL32"}, + {27, "R_PPC_PLT32"}, + {28, "R_PPC_PLTREL32"}, + {29, "R_PPC_PLT16_LO"}, + {30, "R_PPC_PLT16_HI"}, + {31, "R_PPC_PLT16_HA"}, + {32, "R_PPC_SDAREL16"}, + {33, "R_PPC_SECTOFF"}, + {34, "R_PPC_SECTOFF_LO"}, + {35, "R_PPC_SECTOFF_HI"}, + {36, "R_PPC_SECTOFF_HA"}, + {67, "R_PPC_TLS"}, + {68, "R_PPC_DTPMOD32"}, + {69, "R_PPC_TPREL16"}, + {70, "R_PPC_TPREL16_LO"}, + {71, "R_PPC_TPREL16_HI"}, + {72, "R_PPC_TPREL16_HA"}, + {73, "R_PPC_TPREL32"}, + {74, "R_PPC_DTPREL16"}, + {75, "R_PPC_DTPREL16_LO"}, + {76, "R_PPC_DTPREL16_HI"}, + {77, "R_PPC_DTPREL16_HA"}, + {78, "R_PPC_DTPREL32"}, + {79, "R_PPC_GOT_TLSGD16"}, + {80, "R_PPC_GOT_TLSGD16_LO"}, + {81, "R_PPC_GOT_TLSGD16_HI"}, + {82, "R_PPC_GOT_TLSGD16_HA"}, + {83, "R_PPC_GOT_TLSLD16"}, + {84, "R_PPC_GOT_TLSLD16_LO"}, + {85, "R_PPC_GOT_TLSLD16_HI"}, + {86, "R_PPC_GOT_TLSLD16_HA"}, + {87, "R_PPC_GOT_TPREL16"}, + {88, "R_PPC_GOT_TPREL16_LO"}, + {89, "R_PPC_GOT_TPREL16_HI"}, + {90, "R_PPC_GOT_TPREL16_HA"}, + {101, "R_PPC_EMB_NADDR32"}, + {102, "R_PPC_EMB_NADDR16"}, + {103, "R_PPC_EMB_NADDR16_LO"}, + {104, "R_PPC_EMB_NADDR16_HI"}, + {105, "R_PPC_EMB_NADDR16_HA"}, + {106, "R_PPC_EMB_SDAI16"}, + {107, "R_PPC_EMB_SDA2I16"}, + {108, "R_PPC_EMB_SDA2REL"}, + {109, "R_PPC_EMB_SDA21"}, + {110, "R_PPC_EMB_MRKREF"}, + {111, "R_PPC_EMB_RELSEC16"}, + {112, "R_PPC_EMB_RELST_LO"}, + {113, "R_PPC_EMB_RELST_HI"}, + {114, "R_PPC_EMB_RELST_HA"}, + {115, "R_PPC_EMB_BIT_FLD"}, + {116, "R_PPC_EMB_RELSDA"}, +} + +func (i R_PPC) String() string { return stringName(uint32(i), rppcStrings, false) } +func (i R_PPC) GoString() string { return stringName(uint32(i), rppcStrings, true) } + +// Relocation types for 64-bit PowerPC or Power Architecture processors. +// +// Values that are shared by both R_PPC and R_PPC64 are prefixed with +// R_POWERPC_ in the ELF standard. For the R_PPC64 type, the relevant +// shared relocations have been renamed with the prefix R_PPC64_. +// The original name follows the value in a comment. +type R_PPC64 int + +const ( + R_PPC64_NONE R_PPC64 = 0 // R_POWERPC_NONE + R_PPC64_ADDR32 R_PPC64 = 1 // R_POWERPC_ADDR32 + R_PPC64_ADDR24 R_PPC64 = 2 // R_POWERPC_ADDR24 + R_PPC64_ADDR16 R_PPC64 = 3 // R_POWERPC_ADDR16 + R_PPC64_ADDR16_LO R_PPC64 = 4 // R_POWERPC_ADDR16_LO + R_PPC64_ADDR16_HI R_PPC64 = 5 // R_POWERPC_ADDR16_HI + R_PPC64_ADDR16_HA R_PPC64 = 6 // R_POWERPC_ADDR16_HA + R_PPC64_ADDR14 R_PPC64 = 7 // R_POWERPC_ADDR14 + R_PPC64_ADDR14_BRTAKEN R_PPC64 = 8 // R_POWERPC_ADDR14_BRTAKEN + R_PPC64_ADDR14_BRNTAKEN R_PPC64 = 9 // R_POWERPC_ADDR14_BRNTAKEN + R_PPC64_REL24 R_PPC64 = 10 // R_POWERPC_REL24 + R_PPC64_REL14 R_PPC64 = 11 // R_POWERPC_REL14 + R_PPC64_REL14_BRTAKEN R_PPC64 = 12 // R_POWERPC_REL14_BRTAKEN + R_PPC64_REL14_BRNTAKEN R_PPC64 = 13 // R_POWERPC_REL14_BRNTAKEN + R_PPC64_GOT16 R_PPC64 = 14 // R_POWERPC_GOT16 + R_PPC64_GOT16_LO R_PPC64 = 15 // R_POWERPC_GOT16_LO + R_PPC64_GOT16_HI R_PPC64 = 16 // R_POWERPC_GOT16_HI + R_PPC64_GOT16_HA R_PPC64 = 17 // R_POWERPC_GOT16_HA + R_PPC64_JMP_SLOT R_PPC64 = 21 // R_POWERPC_JMP_SLOT + R_PPC64_REL32 R_PPC64 = 26 // R_POWERPC_REL32 + R_PPC64_ADDR64 R_PPC64 = 38 + R_PPC64_ADDR16_HIGHER R_PPC64 = 39 + R_PPC64_ADDR16_HIGHERA R_PPC64 = 40 + R_PPC64_ADDR16_HIGHEST R_PPC64 = 41 + R_PPC64_ADDR16_HIGHESTA R_PPC64 = 42 + R_PPC64_REL64 R_PPC64 = 44 + R_PPC64_TOC16 R_PPC64 = 47 + R_PPC64_TOC16_LO R_PPC64 = 48 + R_PPC64_TOC16_HI R_PPC64 = 49 + R_PPC64_TOC16_HA R_PPC64 = 50 + R_PPC64_TOC R_PPC64 = 51 + R_PPC64_PLTGOT16 R_PPC64 = 52 + R_PPC64_PLTGOT16_LO R_PPC64 = 53 + R_PPC64_PLTGOT16_HI R_PPC64 = 54 + R_PPC64_PLTGOT16_HA R_PPC64 = 55 + R_PPC64_ADDR16_DS R_PPC64 = 56 + R_PPC64_ADDR16_LO_DS R_PPC64 = 57 + R_PPC64_GOT16_DS R_PPC64 = 58 + R_PPC64_GOT16_LO_DS R_PPC64 = 59 + R_PPC64_PLT16_LO_DS R_PPC64 = 60 + R_PPC64_SECTOFF_DS R_PPC64 = 61 + R_PPC64_SECTOFF_LO_DS R_PPC64 = 61 + R_PPC64_TOC16_DS R_PPC64 = 63 + R_PPC64_TOC16_LO_DS R_PPC64 = 64 + R_PPC64_PLTGOT16_DS R_PPC64 = 65 + R_PPC64_PLTGOT_LO_DS R_PPC64 = 66 + R_PPC64_TLS R_PPC64 = 67 // R_POWERPC_TLS + R_PPC64_DTPMOD64 R_PPC64 = 68 // R_POWERPC_DTPMOD64 + R_PPC64_TPREL16 R_PPC64 = 69 // R_POWERPC_TPREL16 + R_PPC64_TPREL16_LO R_PPC64 = 70 // R_POWERPC_TPREL16_LO + R_PPC64_TPREL16_HI R_PPC64 = 71 // R_POWERPC_TPREL16_HI + R_PPC64_TPREL16_HA R_PPC64 = 72 // R_POWERPC_TPREL16_HA + R_PPC64_TPREL64 R_PPC64 = 73 // R_POWERPC_TPREL64 + R_PPC64_DTPREL16 R_PPC64 = 74 // R_POWERPC_DTPREL16 + R_PPC64_DTPREL16_LO R_PPC64 = 75 // R_POWERPC_DTPREL16_LO + R_PPC64_DTPREL16_HI R_PPC64 = 76 // R_POWERPC_DTPREL16_HI + R_PPC64_DTPREL16_HA R_PPC64 = 77 // R_POWERPC_DTPREL16_HA + R_PPC64_DTPREL64 R_PPC64 = 78 // R_POWERPC_DTPREL64 + R_PPC64_GOT_TLSGD16 R_PPC64 = 79 // R_POWERPC_GOT_TLSGD16 + R_PPC64_GOT_TLSGD16_LO R_PPC64 = 80 // R_POWERPC_GOT_TLSGD16_LO + R_PPC64_GOT_TLSGD16_HI R_PPC64 = 81 // R_POWERPC_GOT_TLSGD16_HI + R_PPC64_GOT_TLSGD16_HA R_PPC64 = 82 // R_POWERPC_GOT_TLSGD16_HA + R_PPC64_GOT_TLSLD16 R_PPC64 = 83 // R_POWERPC_GOT_TLSLD16 + R_PPC64_GOT_TLSLD16_LO R_PPC64 = 84 // R_POWERPC_GOT_TLSLD16_LO + R_PPC64_GOT_TLSLD16_HI R_PPC64 = 85 // R_POWERPC_GOT_TLSLD16_HI + R_PPC64_GOT_TLSLD16_HA R_PPC64 = 86 // R_POWERPC_GOT_TLSLD16_HA + R_PPC64_GOT_TPREL16_DS R_PPC64 = 87 // R_POWERPC_GOT_TPREL16_DS + R_PPC64_GOT_TPREL16_LO_DS R_PPC64 = 88 // R_POWERPC_GOT_TPREL16_LO_DS + R_PPC64_GOT_TPREL16_HI R_PPC64 = 89 // R_POWERPC_GOT_TPREL16_HI + R_PPC64_GOT_TPREL16_HA R_PPC64 = 90 // R_POWERPC_GOT_TPREL16_HA + R_PPC64_GOT_DTPREL16_DS R_PPC64 = 91 // R_POWERPC_GOT_DTPREL16_DS + R_PPC64_GOT_DTPREL16_LO_DS R_PPC64 = 92 // R_POWERPC_GOT_DTPREL16_LO_DS + R_PPC64_GOT_DTPREL16_HI R_PPC64 = 93 // R_POWERPC_GOT_DTPREL16_HI + R_PPC64_GOT_DTPREL16_HA R_PPC64 = 94 // R_POWERPC_GOT_DTPREL16_HA + R_PPC64_TPREL16_DS R_PPC64 = 95 + R_PPC64_TPREL16_LO_DS R_PPC64 = 96 + R_PPC64_TPREL16_HIGHER R_PPC64 = 97 + R_PPC64_TPREL16_HIGHERA R_PPC64 = 98 + R_PPC64_TPREL16_HIGHEST R_PPC64 = 99 + R_PPC64_TPREL16_HIGHESTA R_PPC64 = 100 + R_PPC64_DTPREL16_DS R_PPC64 = 101 + R_PPC64_DTPREL16_LO_DS R_PPC64 = 102 + R_PPC64_DTPREL16_HIGHER R_PPC64 = 103 + R_PPC64_DTPREL16_HIGHERA R_PPC64 = 104 + R_PPC64_DTPREL16_HIGHEST R_PPC64 = 105 + R_PPC64_DTPREL16_HIGHESTA R_PPC64 = 106 + R_PPC64_TLSGD R_PPC64 = 107 + R_PPC64_TLSLD R_PPC64 = 108 + R_PPC64_TOCSAVE R_PPC64 = 109 + R_PPC64_ADDR16_HIGH R_PPC64 = 110 + R_PPC64_ADDR16_HIGHA R_PPC64 = 111 + R_PPC64_TPREL16_HIGH R_PPC64 = 112 + R_PPC64_TPREL16_HIGHA R_PPC64 = 113 + R_PPC64_DTPREL16_HIGH R_PPC64 = 114 + R_PPC64_DTPREL16_HIGHA R_PPC64 = 115 + R_PPC64_REL24_NOTOC R_PPC64 = 116 + R_PPC64_ADDR64_LOCAL R_PPC64 = 117 + R_PPC64_ENTRY R_PPC64 = 118 + R_PPC64_REL16DX_HA R_PPC64 = 246 // R_POWERPC_REL16DX_HA + R_PPC64_JMP_IREL R_PPC64 = 247 + R_PPC64_IRELATIVE R_PPC64 = 248 // R_POWERPC_IRELATIVE + R_PPC64_REL16 R_PPC64 = 249 // R_POWERPC_REL16 + R_PPC64_REL16_LO R_PPC64 = 250 // R_POWERPC_REL16_LO + R_PPC64_REL16_HI R_PPC64 = 251 // R_POWERPC_REL16_HI + R_PPC64_REL16_HA R_PPC64 = 252 // R_POWERPC_REL16_HA +) + +var rppc64Strings = []intName{ + {0, "R_PPC64_NONE"}, + {1, "R_PPC64_ADDR32"}, + {2, "R_PPC64_ADDR24"}, + {3, "R_PPC64_ADDR16"}, + {4, "R_PPC64_ADDR16_LO"}, + {5, "R_PPC64_ADDR16_HI"}, + {6, "R_PPC64_ADDR16_HA"}, + {7, "R_PPC64_ADDR14"}, + {8, "R_PPC64_ADDR14_BRTAKEN"}, + {9, "R_PPC64_ADDR14_BRNTAKEN"}, + {10, "R_PPC64_REL24"}, + {11, "R_PPC64_REL14"}, + {12, "R_PPC64_REL14_BRTAKEN"}, + {13, "R_PPC64_REL14_BRNTAKEN"}, + {14, "R_PPC64_GOT16"}, + {15, "R_PPC64_GOT16_LO"}, + {16, "R_PPC64_GOT16_HI"}, + {17, "R_PPC64_GOT16_HA"}, + {21, "R_PPC64_JMP_SLOT"}, + {26, "R_PPC64_REL32"}, + {38, "R_PPC64_ADDR64"}, + {39, "R_PPC64_ADDR16_HIGHER"}, + {40, "R_PPC64_ADDR16_HIGHERA"}, + {41, "R_PPC64_ADDR16_HIGHEST"}, + {42, "R_PPC64_ADDR16_HIGHESTA"}, + {44, "R_PPC64_REL64"}, + {47, "R_PPC64_TOC16"}, + {48, "R_PPC64_TOC16_LO"}, + {49, "R_PPC64_TOC16_HI"}, + {50, "R_PPC64_TOC16_HA"}, + {51, "R_PPC64_TOC"}, + {52, "R_PPC64_PLTGOT16"}, + {53, "R_PPC64_PLTGOT16_LO"}, + {54, "R_PPC64_PLTGOT16_HI"}, + {55, "R_PPC64_PLTGOT16_HA"}, + {56, "R_PPC64_ADDR16_DS"}, + {57, "R_PPC64_ADDR16_LO_DS"}, + {58, "R_PPC64_GOT16_DS"}, + {59, "R_PPC64_GOT16_LO_DS"}, + {60, "R_PPC64_PLT16_LO_DS"}, + {61, "R_PPC64_SECTOFF_DS"}, + {61, "R_PPC64_SECTOFF_LO_DS"}, + {63, "R_PPC64_TOC16_DS"}, + {64, "R_PPC64_TOC16_LO_DS"}, + {65, "R_PPC64_PLTGOT16_DS"}, + {66, "R_PPC64_PLTGOT_LO_DS"}, + {67, "R_PPC64_TLS"}, + {68, "R_PPC64_DTPMOD64"}, + {69, "R_PPC64_TPREL16"}, + {70, "R_PPC64_TPREL16_LO"}, + {71, "R_PPC64_TPREL16_HI"}, + {72, "R_PPC64_TPREL16_HA"}, + {73, "R_PPC64_TPREL64"}, + {74, "R_PPC64_DTPREL16"}, + {75, "R_PPC64_DTPREL16_LO"}, + {76, "R_PPC64_DTPREL16_HI"}, + {77, "R_PPC64_DTPREL16_HA"}, + {78, "R_PPC64_DTPREL64"}, + {79, "R_PPC64_GOT_TLSGD16"}, + {80, "R_PPC64_GOT_TLSGD16_LO"}, + {81, "R_PPC64_GOT_TLSGD16_HI"}, + {82, "R_PPC64_GOT_TLSGD16_HA"}, + {83, "R_PPC64_GOT_TLSLD16"}, + {84, "R_PPC64_GOT_TLSLD16_LO"}, + {85, "R_PPC64_GOT_TLSLD16_HI"}, + {86, "R_PPC64_GOT_TLSLD16_HA"}, + {87, "R_PPC64_GOT_TPREL16_DS"}, + {88, "R_PPC64_GOT_TPREL16_LO_DS"}, + {89, "R_PPC64_GOT_TPREL16_HI"}, + {90, "R_PPC64_GOT_TPREL16_HA"}, + {91, "R_PPC64_GOT_DTPREL16_DS"}, + {92, "R_PPC64_GOT_DTPREL16_LO_DS"}, + {93, "R_PPC64_GOT_DTPREL16_HI"}, + {94, "R_PPC64_GOT_DTPREL16_HA"}, + {95, "R_PPC64_TPREL16_DS"}, + {96, "R_PPC64_TPREL16_LO_DS"}, + {97, "R_PPC64_TPREL16_HIGHER"}, + {98, "R_PPC64_TPREL16_HIGHERA"}, + {99, "R_PPC64_TPREL16_HIGHEST"}, + {100, "R_PPC64_TPREL16_HIGHESTA"}, + {101, "R_PPC64_DTPREL16_DS"}, + {102, "R_PPC64_DTPREL16_LO_DS"}, + {103, "R_PPC64_DTPREL16_HIGHER"}, + {104, "R_PPC64_DTPREL16_HIGHERA"}, + {105, "R_PPC64_DTPREL16_HIGHEST"}, + {106, "R_PPC64_DTPREL16_HIGHESTA"}, + {107, "R_PPC64_TLSGD"}, + {108, "R_PPC64_TLSLD"}, + {109, "R_PPC64_TOCSAVE"}, + {110, "R_PPC64_ADDR16_HIGH"}, + {111, "R_PPC64_ADDR16_HIGHA"}, + {112, "R_PPC64_TPREL16_HIGH"}, + {113, "R_PPC64_TPREL16_HIGHA"}, + {114, "R_PPC64_DTPREL16_HIGH"}, + {115, "R_PPC64_DTPREL16_HIGHA"}, + {116, "R_PPC64_REL24_NOTOC"}, + {117, "R_PPC64_ADDR64_LOCAL"}, + {118, "R_PPC64_ENTRY"}, + {246, "R_PPC64_REL16DX_HA"}, + {247, "R_PPC64_JMP_IREL"}, + {248, "R_PPC64_IRELATIVE"}, + {249, "R_PPC64_REL16"}, + {250, "R_PPC64_REL16_LO"}, + {251, "R_PPC64_REL16_HI"}, + {252, "R_PPC64_REL16_HA"}, +} + +func (i R_PPC64) String() string { return stringName(uint32(i), rppc64Strings, false) } +func (i R_PPC64) GoString() string { return stringName(uint32(i), rppc64Strings, true) } + +// Relocation types for RISC-V processors. +type R_RISCV int + +const ( + R_RISCV_NONE R_RISCV = 0 /* No relocation. */ + R_RISCV_32 R_RISCV = 1 /* Add 32 bit zero extended symbol value */ + R_RISCV_64 R_RISCV = 2 /* Add 64 bit symbol value. */ + R_RISCV_RELATIVE R_RISCV = 3 /* Add load address of shared object. */ + R_RISCV_COPY R_RISCV = 4 /* Copy data from shared object. */ + R_RISCV_JUMP_SLOT R_RISCV = 5 /* Set GOT entry to code address. */ + R_RISCV_TLS_DTPMOD32 R_RISCV = 6 /* 32 bit ID of module containing symbol */ + R_RISCV_TLS_DTPMOD64 R_RISCV = 7 /* ID of module containing symbol */ + R_RISCV_TLS_DTPREL32 R_RISCV = 8 /* 32 bit relative offset in TLS block */ + R_RISCV_TLS_DTPREL64 R_RISCV = 9 /* Relative offset in TLS block */ + R_RISCV_TLS_TPREL32 R_RISCV = 10 /* 32 bit relative offset in static TLS block */ + R_RISCV_TLS_TPREL64 R_RISCV = 11 /* Relative offset in static TLS block */ + R_RISCV_BRANCH R_RISCV = 16 /* PC-relative branch */ + R_RISCV_JAL R_RISCV = 17 /* PC-relative jump */ + R_RISCV_CALL R_RISCV = 18 /* PC-relative call */ + R_RISCV_CALL_PLT R_RISCV = 19 /* PC-relative call (PLT) */ + R_RISCV_GOT_HI20 R_RISCV = 20 /* PC-relative GOT reference */ + R_RISCV_TLS_GOT_HI20 R_RISCV = 21 /* PC-relative TLS IE GOT offset */ + R_RISCV_TLS_GD_HI20 R_RISCV = 22 /* PC-relative TLS GD reference */ + R_RISCV_PCREL_HI20 R_RISCV = 23 /* PC-relative reference */ + R_RISCV_PCREL_LO12_I R_RISCV = 24 /* PC-relative reference */ + R_RISCV_PCREL_LO12_S R_RISCV = 25 /* PC-relative reference */ + R_RISCV_HI20 R_RISCV = 26 /* Absolute address */ + R_RISCV_LO12_I R_RISCV = 27 /* Absolute address */ + R_RISCV_LO12_S R_RISCV = 28 /* Absolute address */ + R_RISCV_TPREL_HI20 R_RISCV = 29 /* TLS LE thread offset */ + R_RISCV_TPREL_LO12_I R_RISCV = 30 /* TLS LE thread offset */ + R_RISCV_TPREL_LO12_S R_RISCV = 31 /* TLS LE thread offset */ + R_RISCV_TPREL_ADD R_RISCV = 32 /* TLS LE thread usage */ + R_RISCV_ADD8 R_RISCV = 33 /* 8-bit label addition */ + R_RISCV_ADD16 R_RISCV = 34 /* 16-bit label addition */ + R_RISCV_ADD32 R_RISCV = 35 /* 32-bit label addition */ + R_RISCV_ADD64 R_RISCV = 36 /* 64-bit label addition */ + R_RISCV_SUB8 R_RISCV = 37 /* 8-bit label subtraction */ + R_RISCV_SUB16 R_RISCV = 38 /* 16-bit label subtraction */ + R_RISCV_SUB32 R_RISCV = 39 /* 32-bit label subtraction */ + R_RISCV_SUB64 R_RISCV = 40 /* 64-bit label subtraction */ + R_RISCV_GNU_VTINHERIT R_RISCV = 41 /* GNU C++ vtable hierarchy */ + R_RISCV_GNU_VTENTRY R_RISCV = 42 /* GNU C++ vtable member usage */ + R_RISCV_ALIGN R_RISCV = 43 /* Alignment statement */ + R_RISCV_RVC_BRANCH R_RISCV = 44 /* PC-relative branch offset */ + R_RISCV_RVC_JUMP R_RISCV = 45 /* PC-relative jump offset */ + R_RISCV_RVC_LUI R_RISCV = 46 /* Absolute address */ + R_RISCV_GPREL_I R_RISCV = 47 /* GP-relative reference */ + R_RISCV_GPREL_S R_RISCV = 48 /* GP-relative reference */ + R_RISCV_TPREL_I R_RISCV = 49 /* TP-relative TLS LE load */ + R_RISCV_TPREL_S R_RISCV = 50 /* TP-relative TLS LE store */ + R_RISCV_RELAX R_RISCV = 51 /* Instruction pair can be relaxed */ + R_RISCV_SUB6 R_RISCV = 52 /* Local label subtraction */ + R_RISCV_SET6 R_RISCV = 53 /* Local label subtraction */ + R_RISCV_SET8 R_RISCV = 54 /* Local label subtraction */ + R_RISCV_SET16 R_RISCV = 55 /* Local label subtraction */ + R_RISCV_SET32 R_RISCV = 56 /* Local label subtraction */ +) + +var rriscvStrings = []intName{ + {0, "R_RISCV_NONE"}, + {1, "R_RISCV_32"}, + {2, "R_RISCV_64"}, + {3, "R_RISCV_RELATIVE"}, + {4, "R_RISCV_COPY"}, + {5, "R_RISCV_JUMP_SLOT"}, + {6, "R_RISCV_TLS_DTPMOD32"}, + {7, "R_RISCV_TLS_DTPMOD64"}, + {8, "R_RISCV_TLS_DTPREL32"}, + {9, "R_RISCV_TLS_DTPREL64"}, + {10, "R_RISCV_TLS_TPREL32"}, + {11, "R_RISCV_TLS_TPREL64"}, + {16, "R_RISCV_BRANCH"}, + {17, "R_RISCV_JAL"}, + {18, "R_RISCV_CALL"}, + {19, "R_RISCV_CALL_PLT"}, + {20, "R_RISCV_GOT_HI20"}, + {21, "R_RISCV_TLS_GOT_HI20"}, + {22, "R_RISCV_TLS_GD_HI20"}, + {23, "R_RISCV_PCREL_HI20"}, + {24, "R_RISCV_PCREL_LO12_I"}, + {25, "R_RISCV_PCREL_LO12_S"}, + {26, "R_RISCV_HI20"}, + {27, "R_RISCV_LO12_I"}, + {28, "R_RISCV_LO12_S"}, + {29, "R_RISCV_TPREL_HI20"}, + {30, "R_RISCV_TPREL_LO12_I"}, + {31, "R_RISCV_TPREL_LO12_S"}, + {32, "R_RISCV_TPREL_ADD"}, + {33, "R_RISCV_ADD8"}, + {34, "R_RISCV_ADD16"}, + {35, "R_RISCV_ADD32"}, + {36, "R_RISCV_ADD64"}, + {37, "R_RISCV_SUB8"}, + {38, "R_RISCV_SUB16"}, + {39, "R_RISCV_SUB32"}, + {40, "R_RISCV_SUB64"}, + {41, "R_RISCV_GNU_VTINHERIT"}, + {42, "R_RISCV_GNU_VTENTRY"}, + {43, "R_RISCV_ALIGN"}, + {44, "R_RISCV_RVC_BRANCH"}, + {45, "R_RISCV_RVC_JUMP"}, + {46, "R_RISCV_RVC_LUI"}, + {47, "R_RISCV_GPREL_I"}, + {48, "R_RISCV_GPREL_S"}, + {49, "R_RISCV_TPREL_I"}, + {50, "R_RISCV_TPREL_S"}, + {51, "R_RISCV_RELAX"}, + {52, "R_RISCV_SUB6"}, + {53, "R_RISCV_SET6"}, + {54, "R_RISCV_SET8"}, + {55, "R_RISCV_SET16"}, + {56, "R_RISCV_SET32"}, +} + +func (i R_RISCV) String() string { return stringName(uint32(i), rriscvStrings, false) } +func (i R_RISCV) GoString() string { return stringName(uint32(i), rriscvStrings, true) } + +// Relocation types for s390x processors. +type R_390 int + +const ( + R_390_NONE R_390 = 0 + R_390_8 R_390 = 1 + R_390_12 R_390 = 2 + R_390_16 R_390 = 3 + R_390_32 R_390 = 4 + R_390_PC32 R_390 = 5 + R_390_GOT12 R_390 = 6 + R_390_GOT32 R_390 = 7 + R_390_PLT32 R_390 = 8 + R_390_COPY R_390 = 9 + R_390_GLOB_DAT R_390 = 10 + R_390_JMP_SLOT R_390 = 11 + R_390_RELATIVE R_390 = 12 + R_390_GOTOFF R_390 = 13 + R_390_GOTPC R_390 = 14 + R_390_GOT16 R_390 = 15 + R_390_PC16 R_390 = 16 + R_390_PC16DBL R_390 = 17 + R_390_PLT16DBL R_390 = 18 + R_390_PC32DBL R_390 = 19 + R_390_PLT32DBL R_390 = 20 + R_390_GOTPCDBL R_390 = 21 + R_390_64 R_390 = 22 + R_390_PC64 R_390 = 23 + R_390_GOT64 R_390 = 24 + R_390_PLT64 R_390 = 25 + R_390_GOTENT R_390 = 26 + R_390_GOTOFF16 R_390 = 27 + R_390_GOTOFF64 R_390 = 28 + R_390_GOTPLT12 R_390 = 29 + R_390_GOTPLT16 R_390 = 30 + R_390_GOTPLT32 R_390 = 31 + R_390_GOTPLT64 R_390 = 32 + R_390_GOTPLTENT R_390 = 33 + R_390_GOTPLTOFF16 R_390 = 34 + R_390_GOTPLTOFF32 R_390 = 35 + R_390_GOTPLTOFF64 R_390 = 36 + R_390_TLS_LOAD R_390 = 37 + R_390_TLS_GDCALL R_390 = 38 + R_390_TLS_LDCALL R_390 = 39 + R_390_TLS_GD32 R_390 = 40 + R_390_TLS_GD64 R_390 = 41 + R_390_TLS_GOTIE12 R_390 = 42 + R_390_TLS_GOTIE32 R_390 = 43 + R_390_TLS_GOTIE64 R_390 = 44 + R_390_TLS_LDM32 R_390 = 45 + R_390_TLS_LDM64 R_390 = 46 + R_390_TLS_IE32 R_390 = 47 + R_390_TLS_IE64 R_390 = 48 + R_390_TLS_IEENT R_390 = 49 + R_390_TLS_LE32 R_390 = 50 + R_390_TLS_LE64 R_390 = 51 + R_390_TLS_LDO32 R_390 = 52 + R_390_TLS_LDO64 R_390 = 53 + R_390_TLS_DTPMOD R_390 = 54 + R_390_TLS_DTPOFF R_390 = 55 + R_390_TLS_TPOFF R_390 = 56 + R_390_20 R_390 = 57 + R_390_GOT20 R_390 = 58 + R_390_GOTPLT20 R_390 = 59 + R_390_TLS_GOTIE20 R_390 = 60 +) + +var r390Strings = []intName{ + {0, "R_390_NONE"}, + {1, "R_390_8"}, + {2, "R_390_12"}, + {3, "R_390_16"}, + {4, "R_390_32"}, + {5, "R_390_PC32"}, + {6, "R_390_GOT12"}, + {7, "R_390_GOT32"}, + {8, "R_390_PLT32"}, + {9, "R_390_COPY"}, + {10, "R_390_GLOB_DAT"}, + {11, "R_390_JMP_SLOT"}, + {12, "R_390_RELATIVE"}, + {13, "R_390_GOTOFF"}, + {14, "R_390_GOTPC"}, + {15, "R_390_GOT16"}, + {16, "R_390_PC16"}, + {17, "R_390_PC16DBL"}, + {18, "R_390_PLT16DBL"}, + {19, "R_390_PC32DBL"}, + {20, "R_390_PLT32DBL"}, + {21, "R_390_GOTPCDBL"}, + {22, "R_390_64"}, + {23, "R_390_PC64"}, + {24, "R_390_GOT64"}, + {25, "R_390_PLT64"}, + {26, "R_390_GOTENT"}, + {27, "R_390_GOTOFF16"}, + {28, "R_390_GOTOFF64"}, + {29, "R_390_GOTPLT12"}, + {30, "R_390_GOTPLT16"}, + {31, "R_390_GOTPLT32"}, + {32, "R_390_GOTPLT64"}, + {33, "R_390_GOTPLTENT"}, + {34, "R_390_GOTPLTOFF16"}, + {35, "R_390_GOTPLTOFF32"}, + {36, "R_390_GOTPLTOFF64"}, + {37, "R_390_TLS_LOAD"}, + {38, "R_390_TLS_GDCALL"}, + {39, "R_390_TLS_LDCALL"}, + {40, "R_390_TLS_GD32"}, + {41, "R_390_TLS_GD64"}, + {42, "R_390_TLS_GOTIE12"}, + {43, "R_390_TLS_GOTIE32"}, + {44, "R_390_TLS_GOTIE64"}, + {45, "R_390_TLS_LDM32"}, + {46, "R_390_TLS_LDM64"}, + {47, "R_390_TLS_IE32"}, + {48, "R_390_TLS_IE64"}, + {49, "R_390_TLS_IEENT"}, + {50, "R_390_TLS_LE32"}, + {51, "R_390_TLS_LE64"}, + {52, "R_390_TLS_LDO32"}, + {53, "R_390_TLS_LDO64"}, + {54, "R_390_TLS_DTPMOD"}, + {55, "R_390_TLS_DTPOFF"}, + {56, "R_390_TLS_TPOFF"}, + {57, "R_390_20"}, + {58, "R_390_GOT20"}, + {59, "R_390_GOTPLT20"}, + {60, "R_390_TLS_GOTIE20"}, +} + +func (i R_390) String() string { return stringName(uint32(i), r390Strings, false) } +func (i R_390) GoString() string { return stringName(uint32(i), r390Strings, true) } + +// Relocation types for SPARC. +type R_SPARC int + +const ( + R_SPARC_NONE R_SPARC = 0 + R_SPARC_8 R_SPARC = 1 + R_SPARC_16 R_SPARC = 2 + R_SPARC_32 R_SPARC = 3 + R_SPARC_DISP8 R_SPARC = 4 + R_SPARC_DISP16 R_SPARC = 5 + R_SPARC_DISP32 R_SPARC = 6 + R_SPARC_WDISP30 R_SPARC = 7 + R_SPARC_WDISP22 R_SPARC = 8 + R_SPARC_HI22 R_SPARC = 9 + R_SPARC_22 R_SPARC = 10 + R_SPARC_13 R_SPARC = 11 + R_SPARC_LO10 R_SPARC = 12 + R_SPARC_GOT10 R_SPARC = 13 + R_SPARC_GOT13 R_SPARC = 14 + R_SPARC_GOT22 R_SPARC = 15 + R_SPARC_PC10 R_SPARC = 16 + R_SPARC_PC22 R_SPARC = 17 + R_SPARC_WPLT30 R_SPARC = 18 + R_SPARC_COPY R_SPARC = 19 + R_SPARC_GLOB_DAT R_SPARC = 20 + R_SPARC_JMP_SLOT R_SPARC = 21 + R_SPARC_RELATIVE R_SPARC = 22 + R_SPARC_UA32 R_SPARC = 23 + R_SPARC_PLT32 R_SPARC = 24 + R_SPARC_HIPLT22 R_SPARC = 25 + R_SPARC_LOPLT10 R_SPARC = 26 + R_SPARC_PCPLT32 R_SPARC = 27 + R_SPARC_PCPLT22 R_SPARC = 28 + R_SPARC_PCPLT10 R_SPARC = 29 + R_SPARC_10 R_SPARC = 30 + R_SPARC_11 R_SPARC = 31 + R_SPARC_64 R_SPARC = 32 + R_SPARC_OLO10 R_SPARC = 33 + R_SPARC_HH22 R_SPARC = 34 + R_SPARC_HM10 R_SPARC = 35 + R_SPARC_LM22 R_SPARC = 36 + R_SPARC_PC_HH22 R_SPARC = 37 + R_SPARC_PC_HM10 R_SPARC = 38 + R_SPARC_PC_LM22 R_SPARC = 39 + R_SPARC_WDISP16 R_SPARC = 40 + R_SPARC_WDISP19 R_SPARC = 41 + R_SPARC_GLOB_JMP R_SPARC = 42 + R_SPARC_7 R_SPARC = 43 + R_SPARC_5 R_SPARC = 44 + R_SPARC_6 R_SPARC = 45 + R_SPARC_DISP64 R_SPARC = 46 + R_SPARC_PLT64 R_SPARC = 47 + R_SPARC_HIX22 R_SPARC = 48 + R_SPARC_LOX10 R_SPARC = 49 + R_SPARC_H44 R_SPARC = 50 + R_SPARC_M44 R_SPARC = 51 + R_SPARC_L44 R_SPARC = 52 + R_SPARC_REGISTER R_SPARC = 53 + R_SPARC_UA64 R_SPARC = 54 + R_SPARC_UA16 R_SPARC = 55 +) + +var rsparcStrings = []intName{ + {0, "R_SPARC_NONE"}, + {1, "R_SPARC_8"}, + {2, "R_SPARC_16"}, + {3, "R_SPARC_32"}, + {4, "R_SPARC_DISP8"}, + {5, "R_SPARC_DISP16"}, + {6, "R_SPARC_DISP32"}, + {7, "R_SPARC_WDISP30"}, + {8, "R_SPARC_WDISP22"}, + {9, "R_SPARC_HI22"}, + {10, "R_SPARC_22"}, + {11, "R_SPARC_13"}, + {12, "R_SPARC_LO10"}, + {13, "R_SPARC_GOT10"}, + {14, "R_SPARC_GOT13"}, + {15, "R_SPARC_GOT22"}, + {16, "R_SPARC_PC10"}, + {17, "R_SPARC_PC22"}, + {18, "R_SPARC_WPLT30"}, + {19, "R_SPARC_COPY"}, + {20, "R_SPARC_GLOB_DAT"}, + {21, "R_SPARC_JMP_SLOT"}, + {22, "R_SPARC_RELATIVE"}, + {23, "R_SPARC_UA32"}, + {24, "R_SPARC_PLT32"}, + {25, "R_SPARC_HIPLT22"}, + {26, "R_SPARC_LOPLT10"}, + {27, "R_SPARC_PCPLT32"}, + {28, "R_SPARC_PCPLT22"}, + {29, "R_SPARC_PCPLT10"}, + {30, "R_SPARC_10"}, + {31, "R_SPARC_11"}, + {32, "R_SPARC_64"}, + {33, "R_SPARC_OLO10"}, + {34, "R_SPARC_HH22"}, + {35, "R_SPARC_HM10"}, + {36, "R_SPARC_LM22"}, + {37, "R_SPARC_PC_HH22"}, + {38, "R_SPARC_PC_HM10"}, + {39, "R_SPARC_PC_LM22"}, + {40, "R_SPARC_WDISP16"}, + {41, "R_SPARC_WDISP19"}, + {42, "R_SPARC_GLOB_JMP"}, + {43, "R_SPARC_7"}, + {44, "R_SPARC_5"}, + {45, "R_SPARC_6"}, + {46, "R_SPARC_DISP64"}, + {47, "R_SPARC_PLT64"}, + {48, "R_SPARC_HIX22"}, + {49, "R_SPARC_LOX10"}, + {50, "R_SPARC_H44"}, + {51, "R_SPARC_M44"}, + {52, "R_SPARC_L44"}, + {53, "R_SPARC_REGISTER"}, + {54, "R_SPARC_UA64"}, + {55, "R_SPARC_UA16"}, +} + +func (i R_SPARC) String() string { return stringName(uint32(i), rsparcStrings, false) } +func (i R_SPARC) GoString() string { return stringName(uint32(i), rsparcStrings, true) } + +// Magic number for the elf trampoline, chosen wisely to be an immediate value. +const ARM_MAGIC_TRAMP_NUMBER = 0x5c000003 + +// ELF32 File header. +type Header32 struct { + Ident [EI_NIDENT]byte /* File identification. */ + Type uint16 /* File type. */ + Machine uint16 /* Machine architecture. */ + Version uint32 /* ELF format version. */ + Entry uint32 /* Entry point. */ + Phoff uint32 /* Program header file offset. */ + Shoff uint32 /* Section header file offset. */ + Flags uint32 /* Architecture-specific flags. */ + Ehsize uint16 /* Size of ELF header in bytes. */ + Phentsize uint16 /* Size of program header entry. */ + Phnum uint16 /* Number of program header entries. */ + Shentsize uint16 /* Size of section header entry. */ + Shnum uint16 /* Number of section header entries. */ + Shstrndx uint16 /* Section name strings section. */ +} + +// ELF32 Section header. +type Section32 struct { + Name uint32 /* Section name (index into the section header string table). */ + Type uint32 /* Section type. */ + Flags uint32 /* Section flags. */ + Addr uint32 /* Address in memory image. */ + Off uint32 /* Offset in file. */ + Size uint32 /* Size in bytes. */ + Link uint32 /* Index of a related section. */ + Info uint32 /* Depends on section type. */ + Addralign uint32 /* Alignment in bytes. */ + Entsize uint32 /* Size of each entry in section. */ +} + +// ELF32 Program header. +type Prog32 struct { + Type uint32 /* Entry type. */ + Off uint32 /* File offset of contents. */ + Vaddr uint32 /* Virtual address in memory image. */ + Paddr uint32 /* Physical address (not used). */ + Filesz uint32 /* Size of contents in file. */ + Memsz uint32 /* Size of contents in memory. */ + Flags uint32 /* Access permission flags. */ + Align uint32 /* Alignment in memory and file. */ +} + +// ELF32 Dynamic structure. The ".dynamic" section contains an array of them. +type Dyn32 struct { + Tag int32 /* Entry type. */ + Val uint32 /* Integer/Address value. */ +} + +// ELF32 Compression header. +type Chdr32 struct { + Type uint32 + Size uint32 + Addralign uint32 +} + +/* + * Relocation entries. + */ + +// ELF32 Relocations that don't need an addend field. +type Rel32 struct { + Off uint32 /* Location to be relocated. */ + Info uint32 /* Relocation type and symbol index. */ +} + +// ELF32 Relocations that need an addend field. +type Rela32 struct { + Off uint32 /* Location to be relocated. */ + Info uint32 /* Relocation type and symbol index. */ + Addend int32 /* Addend. */ +} + +func R_SYM32(info uint32) uint32 { return info >> 8 } +func R_TYPE32(info uint32) uint32 { return info & 0xff } +func R_INFO32(sym, typ uint32) uint32 { return sym<<8 | typ } + +// ELF32 Symbol. +type Sym32 struct { + Name uint32 + Value uint32 + Size uint32 + Info uint8 + Other uint8 + Shndx uint16 +} + +const Sym32Size = 16 + +func ST_BIND(info uint8) SymBind { return SymBind(info >> 4) } +func ST_TYPE(info uint8) SymType { return SymType(info & 0xF) } +func ST_INFO(bind SymBind, typ SymType) uint8 { + return uint8(bind)<<4 | uint8(typ)&0xf +} +func ST_VISIBILITY(other uint8) SymVis { return SymVis(other & 3) } + +/* + * ELF64 + */ + +// ELF64 file header. +type Header64 struct { + Ident [EI_NIDENT]byte /* File identification. */ + Type uint16 /* File type. */ + Machine uint16 /* Machine architecture. */ + Version uint32 /* ELF format version. */ + Entry uint64 /* Entry point. */ + Phoff uint64 /* Program header file offset. */ + Shoff uint64 /* Section header file offset. */ + Flags uint32 /* Architecture-specific flags. */ + Ehsize uint16 /* Size of ELF header in bytes. */ + Phentsize uint16 /* Size of program header entry. */ + Phnum uint16 /* Number of program header entries. */ + Shentsize uint16 /* Size of section header entry. */ + Shnum uint16 /* Number of section header entries. */ + Shstrndx uint16 /* Section name strings section. */ +} + +// ELF64 Section header. +type Section64 struct { + Name uint32 /* Section name (index into the section header string table). */ + Type uint32 /* Section type. */ + Flags uint64 /* Section flags. */ + Addr uint64 /* Address in memory image. */ + Off uint64 /* Offset in file. */ + Size uint64 /* Size in bytes. */ + Link uint32 /* Index of a related section. */ + Info uint32 /* Depends on section type. */ + Addralign uint64 /* Alignment in bytes. */ + Entsize uint64 /* Size of each entry in section. */ +} + +// ELF64 Program header. +type Prog64 struct { + Type uint32 /* Entry type. */ + Flags uint32 /* Access permission flags. */ + Off uint64 /* File offset of contents. */ + Vaddr uint64 /* Virtual address in memory image. */ + Paddr uint64 /* Physical address (not used). */ + Filesz uint64 /* Size of contents in file. */ + Memsz uint64 /* Size of contents in memory. */ + Align uint64 /* Alignment in memory and file. */ +} + +// ELF64 Dynamic structure. The ".dynamic" section contains an array of them. +type Dyn64 struct { + Tag int64 /* Entry type. */ + Val uint64 /* Integer/address value */ +} + +// ELF64 Compression header. +type Chdr64 struct { + Type uint32 + _ uint32 /* Reserved. */ + Size uint64 + Addralign uint64 +} + +/* + * Relocation entries. + */ + +/* ELF64 relocations that don't need an addend field. */ +type Rel64 struct { + Off uint64 /* Location to be relocated. */ + Info uint64 /* Relocation type and symbol index. */ +} + +/* ELF64 relocations that need an addend field. */ +type Rela64 struct { + Off uint64 /* Location to be relocated. */ + Info uint64 /* Relocation type and symbol index. */ + Addend int64 /* Addend. */ +} + +func R_SYM64(info uint64) uint32 { return uint32(info >> 32) } +func R_TYPE64(info uint64) uint32 { return uint32(info) } +func R_INFO(sym, typ uint32) uint64 { return uint64(sym)<<32 | uint64(typ) } + +// ELF64 symbol table entries. +type Sym64 struct { + Name uint32 /* String table index of name. */ + Info uint8 /* Type and binding information. */ + Other uint8 /* Reserved (not used). */ + Shndx uint16 /* Section index of symbol. */ + Value uint64 /* Symbol value. */ + Size uint64 /* Size of associated object. */ +} + +const Sym64Size = 24 + +type intName struct { + i uint32 + s string +} + +func stringName(i uint32, names []intName, goSyntax bool) string { + for _, n := range names { + if n.i == i { + if goSyntax { + return "elf." + n.s + } + return n.s + } + } + + // second pass - look for smaller to add with. + // assume sorted already + for j := len(names) - 1; j >= 0; j-- { + n := names[j] + if n.i < i { + s := n.s + if goSyntax { + s = "elf." + s + } + return s + "+" + strconv.FormatUint(uint64(i-n.i), 10) + } + } + + return strconv.FormatUint(uint64(i), 10) +} + +func flagName(i uint32, names []intName, goSyntax bool) string { + s := "" + for _, n := range names { + if n.i&i == n.i { + if len(s) > 0 { + s += "+" + } + if goSyntax { + s += "elf." + } + s += n.s + i -= n.i + } + } + if len(s) == 0 { + return "0x" + strconv.FormatUint(uint64(i), 16) + } + if i != 0 { + s += "+0x" + strconv.FormatUint(uint64(i), 16) + } + return s +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/elf_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/elf_test.go new file mode 100644 index 00000000..49238c90 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/elf_test.go @@ -0,0 +1,59 @@ +// Copyright 2018 Google LLC +// +// 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 elf + +import ( + "fmt" + "testing" +) + +type nameTest struct { + val interface{} + str string +} + +var nameTests = []nameTest{ + {ELFOSABI_LINUX, "ELFOSABI_LINUX"}, + {ET_EXEC, "ET_EXEC"}, + {EM_860, "EM_860"}, + {SHN_LOPROC, "SHN_LOPROC"}, + {SHT_PROGBITS, "SHT_PROGBITS"}, + {SHF_MERGE + SHF_TLS, "SHF_MERGE+SHF_TLS"}, + {PT_LOAD, "PT_LOAD"}, + {PF_W + PF_R + 0x50, "PF_W+PF_R+0x50"}, + {DT_SYMBOLIC, "DT_SYMBOLIC"}, + {DF_BIND_NOW, "DF_BIND_NOW"}, + {NT_FPREGSET, "NT_FPREGSET"}, + {STB_GLOBAL, "STB_GLOBAL"}, + {STT_COMMON, "STT_COMMON"}, + {STV_HIDDEN, "STV_HIDDEN"}, + {R_X86_64_PC32, "R_X86_64_PC32"}, + {R_ALPHA_OP_PUSH, "R_ALPHA_OP_PUSH"}, + {R_ARM_THM_ABS5, "R_ARM_THM_ABS5"}, + {R_386_GOT32, "R_386_GOT32"}, + {R_PPC_GOT16_HI, "R_PPC_GOT16_HI"}, + {R_SPARC_GOT22, "R_SPARC_GOT22"}, + {ET_LOOS + 5, "ET_LOOS+5"}, + {ProgFlag(0x50), "0x50"}, +} + +func TestNames(t *testing.T) { + for i, tt := range nameTests { + s := fmt.Sprint(tt.val) + if s != tt.str { + t.Errorf("#%d: Sprint(%d) = %q, want %q", i, tt.val, s, tt.str) + } + } +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/file.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/file.go new file mode 100644 index 00000000..4441a784 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/file.go @@ -0,0 +1,1417 @@ +// Copyright 2018 Google LLC +// +// 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 elf implements access to ELF object files. +package elf + +import ( + "bytes" + "compress/zlib" + "encoding/binary" + "errors" + "fmt" + "io" + "os" + "strings" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" +) + +// seekStart, seekCurrent, seekEnd are copies of +// io.SeekStart, io.SeekCurrent, and io.SeekEnd. +// We can't use the ones from package io because +// we want this code to build with Go 1.4 during +// cmd/dist bootstrap. +const ( + seekStart int = 0 + seekCurrent int = 1 + seekEnd int = 2 +) + +// TODO: error reporting detail + +/* + * Internal ELF representation + */ + +// A FileHeader represents an ELF file header. +type FileHeader struct { + Class Class + Data Data + Version Version + OSABI OSABI + ABIVersion uint8 + ByteOrder binary.ByteOrder + Type Type + Machine Machine + Entry uint64 +} + +// A File represents an open ELF file. +type File struct { + FileHeader + Sections []*Section + Progs []*Prog + closer io.Closer + gnuNeed []verneed + gnuVersym []byte +} + +// A SectionHeader represents a single ELF section header. +type SectionHeader struct { + Name string + Type SectionType + Flags SectionFlag + Addr uint64 + Offset uint64 + Size uint64 + Link uint32 + Info uint32 + Addralign uint64 + Entsize uint64 + + // FileSize is the size of this section in the file in bytes. + // If a section is compressed, FileSize is the size of the + // compressed data, while Size (above) is the size of the + // uncompressed data. + FileSize uint64 +} + +// A Section represents a single section in an ELF file. +type Section struct { + SectionHeader + + // Embed ReaderAt for ReadAt method. + // Do not embed SectionReader directly + // to avoid having Read and Seek. + // If a client wants Read and Seek it must use + // Open() to avoid fighting over the seek offset + // with other clients. + // + // ReaderAt may be nil if the section is not easily available + // in a random-access form. For example, a compressed section + // may have a nil ReaderAt. + io.ReaderAt + sr *io.SectionReader + + compressionType CompressionType + compressionOffset int64 +} + +// Data reads and returns the contents of the ELF section. +// Even if the section is stored compressed in the ELF file, +// Data returns uncompressed data. +func (s *Section) Data() ([]byte, error) { + dat := make([]byte, s.Size) + n, err := io.ReadFull(s.Open(), dat) + return dat[0:n], err +} + +// stringTable reads and returns the string table given by the +// specified link value. +func (f *File) stringTable(link uint32) ([]byte, error) { + if link <= 0 || link >= uint32(len(f.Sections)) { + return nil, errors.New("section has invalid string table link") + } + return f.Sections[link].Data() +} + +// Open returns a new ReadSeeker reading the ELF section. +// Even if the section is stored compressed in the ELF file, +// the ReadSeeker reads uncompressed data. +func (s *Section) Open() io.ReadSeeker { + if s.Flags&SHF_COMPRESSED == 0 { + return io.NewSectionReader(s.sr, 0, 1<<63-1) + } + if s.compressionType == COMPRESS_ZLIB { + return &readSeekerFromReader{ + reset: func() (io.Reader, error) { + fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset) + return zlib.NewReader(fr) + }, + size: int64(s.Size), + } + } + err := &FormatError{int64(s.Offset), "unknown compression type", s.compressionType} + return errorReader{err} +} + +// A ProgHeader represents a single ELF program header. +type ProgHeader struct { + Type ProgType + Flags ProgFlag + Off uint64 + Vaddr uint64 + Paddr uint64 + Filesz uint64 + Memsz uint64 + Align uint64 +} + +// A Prog represents a single ELF program header in an ELF binary. +type Prog struct { + ProgHeader + + // Embed ReaderAt for ReadAt method. + // Do not embed SectionReader directly + // to avoid having Read and Seek. + // If a client wants Read and Seek it must use + // Open() to avoid fighting over the seek offset + // with other clients. + io.ReaderAt + sr *io.SectionReader +} + +// Open returns a new ReadSeeker reading the ELF program body. +func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) } + +// A Symbol represents an entry in an ELF symbol table section. +type Symbol struct { + Name string + Info, Other byte + Section SectionIndex + Value, Size uint64 +} + +/* + * ELF reader + */ + +type FormatError struct { + off int64 + msg string + val interface{} +} + +func (e *FormatError) Error() string { + msg := e.msg + if e.val != nil { + msg += fmt.Sprintf(" '%v' ", e.val) + } + msg += fmt.Sprintf("in record at byte %#x", e.off) + return msg +} + +// Open opens the named file using os.Open and prepares it for use as an ELF binary. +func Open(name string) (*File, error) { + f, err := os.Open(name) + if err != nil { + return nil, err + } + ff, err := NewFile(f) + if err != nil { + f.Close() + return nil, err + } + ff.closer = f + return ff, nil +} + +// Close closes the File. +// If the File was created using NewFile directly instead of Open, +// Close has no effect. +func (f *File) Close() error { + var err error + if f.closer != nil { + err = f.closer.Close() + f.closer = nil + } + return err +} + +// SectionByType returns the first section in f with the +// given type, or nil if there is no such section. +func (f *File) SectionByType(typ SectionType) *Section { + for _, s := range f.Sections { + if s.Type == typ { + return s + } + } + return nil +} + +// NewFile creates a new File for accessing an ELF binary in an underlying reader. +// The ELF binary is expected to start at position 0 in the ReaderAt. +func NewFile(r io.ReaderAt) (*File, error) { + sr := io.NewSectionReader(r, 0, 1<<63-1) + // Read and decode ELF identifier + var ident [16]uint8 + if _, err := r.ReadAt(ident[0:], 0); err != nil { + return nil, err + } + if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' { + return nil, &FormatError{0, "bad magic number", ident[0:4]} + } + + f := new(File) + f.Class = Class(ident[EI_CLASS]) + switch f.Class { + case ELFCLASS32: + case ELFCLASS64: + // ok + default: + return nil, &FormatError{0, "unknown ELF class", f.Class} + } + + f.Data = Data(ident[EI_DATA]) + switch f.Data { + case ELFDATA2LSB: + f.ByteOrder = binary.LittleEndian + case ELFDATA2MSB: + f.ByteOrder = binary.BigEndian + default: + return nil, &FormatError{0, "unknown ELF data encoding", f.Data} + } + + f.Version = Version(ident[EI_VERSION]) + if f.Version != EV_CURRENT { + return nil, &FormatError{0, "unknown ELF version", f.Version} + } + + f.OSABI = OSABI(ident[EI_OSABI]) + f.ABIVersion = ident[EI_ABIVERSION] + + // Read ELF file header + var phoff int64 + var phentsize, phnum int + var shoff int64 + var shentsize, shnum, shstrndx int + shstrndx = -1 + switch f.Class { + case ELFCLASS32: + hdr := new(Header32) + sr.Seek(0, seekStart) + if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { + return nil, err + } + f.Type = Type(hdr.Type) + f.Machine = Machine(hdr.Machine) + f.Entry = uint64(hdr.Entry) + if v := Version(hdr.Version); v != f.Version { + return nil, &FormatError{0, "mismatched ELF version", v} + } + phoff = int64(hdr.Phoff) + phentsize = int(hdr.Phentsize) + phnum = int(hdr.Phnum) + shoff = int64(hdr.Shoff) + shentsize = int(hdr.Shentsize) + shnum = int(hdr.Shnum) + shstrndx = int(hdr.Shstrndx) + case ELFCLASS64: + hdr := new(Header64) + sr.Seek(0, seekStart) + if err := binary.Read(sr, f.ByteOrder, hdr); err != nil { + return nil, err + } + f.Type = Type(hdr.Type) + f.Machine = Machine(hdr.Machine) + f.Entry = hdr.Entry + if v := Version(hdr.Version); v != f.Version { + return nil, &FormatError{0, "mismatched ELF version", v} + } + phoff = int64(hdr.Phoff) + phentsize = int(hdr.Phentsize) + phnum = int(hdr.Phnum) + shoff = int64(hdr.Shoff) + shentsize = int(hdr.Shentsize) + shnum = int(hdr.Shnum) + shstrndx = int(hdr.Shstrndx) + } + + if shnum > 0 && shoff > 0 && (shstrndx < 0 || shstrndx >= shnum) { + return nil, &FormatError{0, "invalid ELF shstrndx", shstrndx} + } + + // Read program headers + f.Progs = make([]*Prog, phnum) + for i := 0; i < phnum; i++ { + off := phoff + int64(i)*int64(phentsize) + sr.Seek(off, seekStart) + p := new(Prog) + switch f.Class { + case ELFCLASS32: + ph := new(Prog32) + if err := binary.Read(sr, f.ByteOrder, ph); err != nil { + return nil, err + } + p.ProgHeader = ProgHeader{ + Type: ProgType(ph.Type), + Flags: ProgFlag(ph.Flags), + Off: uint64(ph.Off), + Vaddr: uint64(ph.Vaddr), + Paddr: uint64(ph.Paddr), + Filesz: uint64(ph.Filesz), + Memsz: uint64(ph.Memsz), + Align: uint64(ph.Align), + } + case ELFCLASS64: + ph := new(Prog64) + if err := binary.Read(sr, f.ByteOrder, ph); err != nil { + return nil, err + } + p.ProgHeader = ProgHeader{ + Type: ProgType(ph.Type), + Flags: ProgFlag(ph.Flags), + Off: ph.Off, + Vaddr: ph.Vaddr, + Paddr: ph.Paddr, + Filesz: ph.Filesz, + Memsz: ph.Memsz, + Align: ph.Align, + } + } + p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz)) + p.ReaderAt = p.sr + f.Progs[i] = p + } + + // Read section headers + f.Sections = make([]*Section, shnum) + names := make([]uint32, shnum) + for i := 0; i < shnum; i++ { + off := shoff + int64(i)*int64(shentsize) + sr.Seek(off, seekStart) + s := new(Section) + switch f.Class { + case ELFCLASS32: + sh := new(Section32) + if err := binary.Read(sr, f.ByteOrder, sh); err != nil { + return nil, err + } + names[i] = sh.Name + s.SectionHeader = SectionHeader{ + Type: SectionType(sh.Type), + Flags: SectionFlag(sh.Flags), + Addr: uint64(sh.Addr), + Offset: uint64(sh.Off), + FileSize: uint64(sh.Size), + Link: sh.Link, + Info: sh.Info, + Addralign: uint64(sh.Addralign), + Entsize: uint64(sh.Entsize), + } + case ELFCLASS64: + sh := new(Section64) + if err := binary.Read(sr, f.ByteOrder, sh); err != nil { + return nil, err + } + names[i] = sh.Name + s.SectionHeader = SectionHeader{ + Type: SectionType(sh.Type), + Flags: SectionFlag(sh.Flags), + Offset: sh.Off, + FileSize: sh.Size, + Addr: sh.Addr, + Link: sh.Link, + Info: sh.Info, + Addralign: sh.Addralign, + Entsize: sh.Entsize, + } + } + s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize)) + + if s.Flags&SHF_COMPRESSED == 0 { + s.ReaderAt = s.sr + s.Size = s.FileSize + } else { + // Read the compression header. + switch f.Class { + case ELFCLASS32: + ch := new(Chdr32) + if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil { + return nil, err + } + s.compressionType = CompressionType(ch.Type) + s.Size = uint64(ch.Size) + s.Addralign = uint64(ch.Addralign) + s.compressionOffset = int64(binary.Size(ch)) + case ELFCLASS64: + ch := new(Chdr64) + if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil { + return nil, err + } + s.compressionType = CompressionType(ch.Type) + s.Size = ch.Size + s.Addralign = ch.Addralign + s.compressionOffset = int64(binary.Size(ch)) + } + } + + f.Sections[i] = s + } + + if len(f.Sections) == 0 { + return f, nil + } + + // Load section header string table. + shstrtab, err := f.Sections[shstrndx].Data() + if err != nil { + return nil, err + } + for i, s := range f.Sections { + var ok bool + s.Name, ok = getString(shstrtab, int(names[i])) + if !ok { + return nil, &FormatError{shoff + int64(i*shentsize), "bad section name index", names[i]} + } + } + + return f, nil +} + +// getSymbols returns a slice of Symbols from parsing the symbol table +// with the given type, along with the associated string table. +func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) { + switch f.Class { + case ELFCLASS64: + return f.getSymbols64(typ) + + case ELFCLASS32: + return f.getSymbols32(typ) + } + + return nil, nil, errors.New("not implemented") +} + +// ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols +// if there is no such section in the File. +var ErrNoSymbols = errors.New("no symbol section") + +func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) { + symtabSection := f.SectionByType(typ) + if symtabSection == nil { + return nil, nil, ErrNoSymbols + } + + data, err := symtabSection.Data() + if err != nil { + return nil, nil, errors.New("cannot load symbol section") + } + symtab := bytes.NewReader(data) + if symtab.Len()%Sym32Size != 0 { + return nil, nil, errors.New("length of symbol section is not a multiple of SymSize") + } + + strdata, err := f.stringTable(symtabSection.Link) + if err != nil { + return nil, nil, errors.New("cannot load string table section") + } + + // The first entry is all zeros. + var skip [Sym32Size]byte + symtab.Read(skip[:]) + + symbols := make([]Symbol, symtab.Len()/Sym32Size) + + i := 0 + var sym Sym32 + for symtab.Len() > 0 { + binary.Read(symtab, f.ByteOrder, &sym) + str, _ := getString(strdata, int(sym.Name)) + symbols[i].Name = str + symbols[i].Info = sym.Info + symbols[i].Other = sym.Other + symbols[i].Section = SectionIndex(sym.Shndx) + symbols[i].Value = uint64(sym.Value) + symbols[i].Size = uint64(sym.Size) + i++ + } + + return symbols, strdata, nil +} + +func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) { + symtabSection := f.SectionByType(typ) + if symtabSection == nil { + return nil, nil, ErrNoSymbols + } + + data, err := symtabSection.Data() + if err != nil { + return nil, nil, errors.New("cannot load symbol section") + } + symtab := bytes.NewReader(data) + if symtab.Len()%Sym64Size != 0 { + return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") + } + + strdata, err := f.stringTable(symtabSection.Link) + if err != nil { + return nil, nil, errors.New("cannot load string table section") + } + + // The first entry is all zeros. + var skip [Sym64Size]byte + symtab.Read(skip[:]) + + symbols := make([]Symbol, symtab.Len()/Sym64Size) + + i := 0 + var sym Sym64 + for symtab.Len() > 0 { + binary.Read(symtab, f.ByteOrder, &sym) + str, _ := getString(strdata, int(sym.Name)) + symbols[i].Name = str + symbols[i].Info = sym.Info + symbols[i].Other = sym.Other + symbols[i].Section = SectionIndex(sym.Shndx) + symbols[i].Value = sym.Value + symbols[i].Size = sym.Size + i++ + } + + return symbols, strdata, nil +} + +// getString extracts a string from an ELF string table. +func getString(section []byte, start int) (string, bool) { + if start < 0 || start >= len(section) { + return "", false + } + + for end := start; end < len(section); end++ { + if section[end] == 0 { + return string(section[start:end]), true + } + } + return "", false +} + +// Section returns a section with the given name, or nil if no such +// section exists. +func (f *File) Section(name string) *Section { + for _, s := range f.Sections { + if s.Name == name { + return s + } + } + return nil +} + +// applyRelocations applies relocations to dst. rels is a relocations section +// in REL or RELA format. +func (f *File) applyRelocations(dst []byte, rels []byte) error { + switch { + case f.Class == ELFCLASS64 && f.Machine == EM_X86_64: + return f.applyRelocationsAMD64(dst, rels) + case f.Class == ELFCLASS32 && f.Machine == EM_386: + return f.applyRelocations386(dst, rels) + case f.Class == ELFCLASS32 && f.Machine == EM_ARM: + return f.applyRelocationsARM(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64: + return f.applyRelocationsARM64(dst, rels) + case f.Class == ELFCLASS32 && f.Machine == EM_PPC: + return f.applyRelocationsPPC(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_PPC64: + return f.applyRelocationsPPC64(dst, rels) + case f.Class == ELFCLASS32 && f.Machine == EM_MIPS: + return f.applyRelocationsMIPS(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_MIPS: + return f.applyRelocationsMIPS64(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_RISCV: + return f.applyRelocationsRISCV64(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_S390: + return f.applyRelocationss390x(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9: + return f.applyRelocationsSPARC64(dst, rels) + default: + return errors.New("applyRelocations: not implemented") + } +} + +func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_X86_64(rela.Info & 0xffff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if SymType(sym.Info&0xf) != STT_SECTION { + // We don't handle non-section relocations for now. + continue + } + + // There are relocations, so this must be a normal + // object file, and we only look at section symbols, + // so we assume that the symbol value is 0. + + switch t { + case R_X86_64_64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) + case R_X86_64_32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) + } + } + + return nil +} + +func (f *File) applyRelocations386(dst []byte, rels []byte) error { + // 8 is the size of Rel32. + if len(rels)%8 != 0 { + return errors.New("length of relocation section is not a multiple of 8") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rel Rel32 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rel) + symNo := rel.Info >> 8 + t := R_386(rel.Info & 0xff) + + if symNo == 0 || symNo > uint32(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + + if t == R_386_32 { + if rel.Off+4 >= uint32(len(dst)) { + continue + } + val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) + val += uint32(sym.Value) + f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) + } + } + + return nil +} + +func (f *File) applyRelocationsARM(dst []byte, rels []byte) error { + // 8 is the size of Rel32. + if len(rels)%8 != 0 { + return errors.New("length of relocation section is not a multiple of 8") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rel Rel32 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rel) + symNo := rel.Info >> 8 + t := R_ARM(rel.Info & 0xff) + + if symNo == 0 || symNo > uint32(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + + switch t { + case R_ARM_ABS32: + if rel.Off+4 >= uint32(len(dst)) { + continue + } + val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) + val += uint32(sym.Value) + f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) + } + } + + return nil +} + +func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_AARCH64(rela.Info & 0xffff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if SymType(sym.Info&0xf) != STT_SECTION { + // We don't handle non-section relocations for now. + continue + } + + // There are relocations, so this must be a normal + // object file, and we only look at section symbols, + // so we assume that the symbol value is 0. + + switch t { + case R_AARCH64_ABS64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) + case R_AARCH64_ABS32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) + } + } + + return nil +} + +func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error { + // 12 is the size of Rela32. + if len(rels)%12 != 0 { + return errors.New("length of relocation section is not a multiple of 12") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela32 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 8 + t := R_PPC(rela.Info & 0xff) + + if symNo == 0 || symNo > uint32(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if SymType(sym.Info&0xf) != STT_SECTION { + // We don't handle non-section relocations for now. + continue + } + + switch t { + case R_PPC_ADDR32: + if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) + } + } + + return nil +} + +func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_PPC64(rela.Info & 0xffff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if SymType(sym.Info&0xf) != STT_SECTION { + // We don't handle non-section relocations for now. + continue + } + + switch t { + case R_PPC64_ADDR64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) + case R_PPC64_ADDR32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) + } + } + + return nil +} + +func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error { + // 8 is the size of Rel32. + if len(rels)%8 != 0 { + return errors.New("length of relocation section is not a multiple of 8") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rel Rel32 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rel) + symNo := rel.Info >> 8 + t := R_MIPS(rel.Info & 0xff) + + if symNo == 0 || symNo > uint32(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + + switch t { + case R_MIPS_32: + if rel.Off+4 >= uint32(len(dst)) { + continue + } + val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) + val += uint32(sym.Value) + f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) + } + } + + return nil +} + +func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + var symNo uint64 + var t R_MIPS + if f.ByteOrder == binary.BigEndian { + symNo = rela.Info >> 32 + t = R_MIPS(rela.Info & 0xff) + } else { + symNo = rela.Info & 0xffffffff + t = R_MIPS(rela.Info >> 56) + } + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if SymType(sym.Info&0xf) != STT_SECTION { + // We don't handle non-section relocations for now. + continue + } + + switch t { + case R_MIPS_64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) + case R_MIPS_32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) + } + } + + return nil +} + +func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_RISCV(rela.Info & 0xffff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + switch SymType(sym.Info & 0xf) { + case STT_SECTION, STT_NOTYPE: + break + default: + continue + } + + switch t { + case R_RISCV_64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val := sym.Value + uint64(rela.Addend) + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val) + case R_RISCV_32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val := uint32(sym.Value) + uint32(rela.Addend) + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val) + } + } + + return nil +} + +func (f *File) applyRelocationss390x(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_390(rela.Info & 0xffff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + switch SymType(sym.Info & 0xf) { + case STT_SECTION, STT_NOTYPE: + break + default: + continue + } + + switch t { + case R_390_64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val := sym.Value + uint64(rela.Addend) + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val) + case R_390_32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + val := uint32(sym.Value) + uint32(rela.Addend) + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val) + } + } + + return nil +} + +func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error { + // 24 is the size of Rela64. + if len(rels)%24 != 0 { + return errors.New("length of relocation section is not a multiple of 24") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rela Rela64 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rela) + symNo := rela.Info >> 32 + t := R_SPARC(rela.Info & 0xff) + + if symNo == 0 || symNo > uint64(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + if SymType(sym.Info&0xf) != STT_SECTION { + // We don't handle non-section relocations for now. + continue + } + + switch t { + case R_SPARC_64, R_SPARC_UA64: + if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend)) + case R_SPARC_32, R_SPARC_UA32: + if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 { + continue + } + f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend)) + } + } + + return nil +} + +func (f *File) DWARF() (*dwarf.Data, error) { + dwarfSuffix := func(s *Section) string { + switch { + case strings.HasPrefix(s.Name, ".debug_"): + return s.Name[7:] + case strings.HasPrefix(s.Name, ".zdebug_"): + return s.Name[8:] + default: + return "" + } + + } + // sectionData gets the data for s, checks its size, and + // applies any applicable relations. + sectionData := func(i int, s *Section) ([]byte, error) { + b, err := s.Data() + if err != nil && uint64(len(b)) < s.Size { + return nil, err + } + + if len(b) >= 12 && string(b[:4]) == "ZLIB" { + dlen := binary.BigEndian.Uint64(b[4:12]) + dbuf := make([]byte, dlen) + r, err := zlib.NewReader(bytes.NewBuffer(b[12:])) + if err != nil { + return nil, err + } + if _, err := io.ReadFull(r, dbuf); err != nil { + return nil, err + } + if err := r.Close(); err != nil { + return nil, err + } + b = dbuf + } + + for _, r := range f.Sections { + if r.Type != SHT_RELA && r.Type != SHT_REL { + continue + } + if int(r.Info) != i { + continue + } + rd, err := r.Data() + if err != nil { + return nil, err + } + err = f.applyRelocations(b, rd) + if err != nil { + return nil, err + } + } + return b, nil + } + + // There are many other DWARF sections, but these + // are the ones the debug/dwarf package uses. + // Don't bother loading others. + var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} + for i, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix == "" { + continue + } + if _, ok := dat[suffix]; !ok { + continue + } + b, err := sectionData(i, s) + if err != nil { + return nil, err + } + dat[suffix] = b + } + + d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) + if err != nil { + return nil, err + } + + // Look for DWARF4 .debug_types sections. + for i, s := range f.Sections { + suffix := dwarfSuffix(s) + if suffix != "types" { + continue + } + + b, err := sectionData(i, s) + if err != nil { + return nil, err + } + + err = d.AddTypes(fmt.Sprintf("types-%d", i), b) + if err != nil { + return nil, err + } + } + + return d, nil +} + +// Symbols returns the symbol table for f. The symbols will be listed in the order +// they appear in f. +// +// For compatibility with Go 1.0, Symbols omits the null symbol at index 0. +// After retrieving the symbols as symtab, an externally supplied index x +// corresponds to symtab[x-1], not symtab[x]. +func (f *File) Symbols() ([]Symbol, error) { + sym, _, err := f.getSymbols(SHT_SYMTAB) + return sym, err +} + +// DynamicSymbols returns the dynamic symbol table for f. The symbols +// will be listed in the order they appear in f. +// +// For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0. +// After retrieving the symbols as symtab, an externally supplied index x +// corresponds to symtab[x-1], not symtab[x]. +func (f *File) DynamicSymbols() ([]Symbol, error) { + sym, _, err := f.getSymbols(SHT_DYNSYM) + return sym, err +} + +type ImportedSymbol struct { + Name string + Version string + Library string +} + +// ImportedSymbols returns the names of all symbols +// referred to by the binary f that are expected to be +// satisfied by other libraries at dynamic load time. +// It does not return weak symbols. +func (f *File) ImportedSymbols() ([]ImportedSymbol, error) { + sym, str, err := f.getSymbols(SHT_DYNSYM) + if err != nil { + return nil, err + } + f.gnuVersionInit(str) + var all []ImportedSymbol + for i, s := range sym { + if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF { + all = append(all, ImportedSymbol{Name: s.Name}) + f.gnuVersion(i, &all[len(all)-1]) + } + } + return all, nil +} + +type verneed struct { + File string + Name string +} + +// gnuVersionInit parses the GNU version tables +// for use by calls to gnuVersion. +func (f *File) gnuVersionInit(str []byte) { + // Accumulate verneed information. + vn := f.SectionByType(SHT_GNU_VERNEED) + if vn == nil { + return + } + d, _ := vn.Data() + + var need []verneed + i := 0 + for { + if i+16 > len(d) { + break + } + vers := f.ByteOrder.Uint16(d[i : i+2]) + if vers != 1 { + break + } + cnt := f.ByteOrder.Uint16(d[i+2 : i+4]) + fileoff := f.ByteOrder.Uint32(d[i+4 : i+8]) + aux := f.ByteOrder.Uint32(d[i+8 : i+12]) + next := f.ByteOrder.Uint32(d[i+12 : i+16]) + file, _ := getString(str, int(fileoff)) + + var name string + j := i + int(aux) + for c := 0; c < int(cnt); c++ { + if j+16 > len(d) { + break + } + // hash := f.ByteOrder.Uint32(d[j:j+4]) + // flags := f.ByteOrder.Uint16(d[j+4:j+6]) + other := f.ByteOrder.Uint16(d[j+6 : j+8]) + nameoff := f.ByteOrder.Uint32(d[j+8 : j+12]) + next := f.ByteOrder.Uint32(d[j+12 : j+16]) + name, _ = getString(str, int(nameoff)) + ndx := int(other) + if ndx >= len(need) { + a := make([]verneed, 2*(ndx+1)) + copy(a, need) + need = a + } + + need[ndx] = verneed{file, name} + if next == 0 { + break + } + j += int(next) + } + + if next == 0 { + break + } + i += int(next) + } + + // Versym parallels symbol table, indexing into verneed. + vs := f.SectionByType(SHT_GNU_VERSYM) + if vs == nil { + return + } + d, _ = vs.Data() + + f.gnuNeed = need + f.gnuVersym = d +} + +// gnuVersion adds Library and Version information to sym, +// which came from offset i of the symbol table. +func (f *File) gnuVersion(i int, sym *ImportedSymbol) { + // Each entry is two bytes. + i = (i + 1) * 2 + if i >= len(f.gnuVersym) { + return + } + j := int(f.ByteOrder.Uint16(f.gnuVersym[i:])) + if j < 2 || j >= len(f.gnuNeed) { + return + } + n := &f.gnuNeed[j] + sym.Library = n.File + sym.Version = n.Name +} + +// ImportedLibraries returns the names of all libraries +// referred to by the binary f that are expected to be +// linked with the binary at dynamic link time. +func (f *File) ImportedLibraries() ([]string, error) { + return f.DynString(DT_NEEDED) +} + +// DynString returns the strings listed for the given tag in the file's dynamic +// section. +// +// The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or +// DT_RUNPATH. +func (f *File) DynString(tag DynTag) ([]string, error) { + switch tag { + case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH: + default: + return nil, fmt.Errorf("non-string-valued tag %v", tag) + } + ds := f.SectionByType(SHT_DYNAMIC) + if ds == nil { + // not dynamic, so no libraries + return nil, nil + } + d, err := ds.Data() + if err != nil { + return nil, err + } + str, err := f.stringTable(ds.Link) + if err != nil { + return nil, err + } + var all []string + for len(d) > 0 { + var t DynTag + var v uint64 + switch f.Class { + case ELFCLASS32: + t = DynTag(f.ByteOrder.Uint32(d[0:4])) + v = uint64(f.ByteOrder.Uint32(d[4:8])) + d = d[8:] + case ELFCLASS64: + t = DynTag(f.ByteOrder.Uint64(d[0:8])) + v = f.ByteOrder.Uint64(d[8:16]) + d = d[16:] + } + if t == tag { + s, ok := getString(str, int(v)) + if ok { + all = append(all, s) + } + } + } + return all, nil +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/file_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/file_test.go new file mode 100644 index 00000000..4cc2699d --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/file_test.go @@ -0,0 +1,825 @@ +// Copyright 2018 Google LLC +// +// 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. + +// +build go1.7 + +package elf + +import ( + "bytes" + "compress/gzip" + "encoding/binary" + "io" + "math/rand" + "net" + "os" + "path" + "reflect" + "runtime" + "testing" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" +) + +type fileTest struct { + file string + hdr FileHeader + sections []SectionHeader + progs []ProgHeader + needed []string +} + +var fileTests = []fileTest{ + { + "testdata/gcc-386-freebsd-exec", + FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386, 0x80483cc}, + []SectionHeader{ + {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + {".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0, 0x15}, + {".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4, 0x90}, + {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10, 0x110}, + {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0, 0xbb}, + {".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8, 0x20}, + {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11}, + {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4, 0x50}, + {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0, 0x180}, + {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc}, + {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0, 0xa3}, + {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc}, + {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4}, + {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8, 0x98}, + {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8}, + {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8}, + {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4}, + {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4, 0x1c}, + {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20}, + {".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0, 0x12d}, + {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20}, + {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b}, + {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0, 0x11d}, + {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0, 0x41}, + {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0, 0x35}, + {".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0, 0x30}, + {".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd}, + {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0, 0xf8}, + {".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10, 0x4b0}, + {".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0, 0x206}, + }, + []ProgHeader{ + {PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4}, + {PT_INTERP, PF_R, 0xd4, 0x80480d4, 0x80480d4, 0x15, 0x15, 0x1}, + {PT_LOAD, PF_R + PF_X, 0x0, 0x8048000, 0x8048000, 0x5fb, 0x5fb, 0x1000}, + {PT_LOAD, PF_R + PF_W, 0x5fc, 0x80495fc, 0x80495fc, 0xd8, 0xf8, 0x1000}, + {PT_DYNAMIC, PF_R + PF_W, 0x60c, 0x804960c, 0x804960c, 0x98, 0x98, 0x4}, + }, + []string{"libc.so.6"}, + }, + { + "testdata/gcc-amd64-linux-exec", + FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64, 0x4003e0}, + []SectionHeader{ + {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + {".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0, 0x1c}, + {".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20}, + {".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4, 0x24}, + {".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0, 0x1c}, + {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18, 0x60}, + {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0, 0x3d}, + {".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2, 0x8}, + {".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0, 0x20}, + {".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18, 0x18}, + {".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18, 0x30}, + {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0, 0x18}, + {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10, 0x30}, + {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0, 0x1b4}, + {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0, 0xe}, + {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11}, + {".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0, 0x24}, + {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0, 0xa4}, + {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10}, + {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10}, + {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0, 0x8}, + {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10, 0x1a0}, + {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8, 0x8}, + {".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8, 0x28}, + {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0, 0x18}, + {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8}, + {".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0, 0x126}, + {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90}, + {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0, 0x25}, + {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0, 0x1a7}, + {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0, 0x6f}, + {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0, 0x13f}, + {".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1, 0xb1}, + {".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90}, + {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0, 0x149}, + {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18, 0x6f0}, + {".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0, 0x1fc}, + }, + []ProgHeader{ + {PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8}, + {PT_INTERP, PF_R, 0x200, 0x400200, 0x400200, 0x1c, 0x1c, 1}, + {PT_LOAD, PF_R + PF_X, 0x0, 0x400000, 0x400000, 0x684, 0x684, 0x200000}, + {PT_LOAD, PF_R + PF_W, 0x688, 0x600688, 0x600688, 0x210, 0x218, 0x200000}, + {PT_DYNAMIC, PF_R + PF_W, 0x6b0, 0x6006b0, 0x6006b0, 0x1a0, 0x1a0, 0x8}, + {PT_NOTE, PF_R, 0x21c, 0x40021c, 0x40021c, 0x20, 0x20, 0x4}, + {PT_LOOS + 0x474E550, PF_R, 0x5b8, 0x4005b8, 0x4005b8, 0x24, 0x24, 0x4}, + {PT_LOOS + 0x474E551, PF_R + PF_W, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8}, + }, + []string{"libc.so.6"}, + }, + { + "testdata/hello-world-core.gz", + FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_CORE, EM_X86_64, 0x0}, + []SectionHeader{}, + []ProgHeader{ + {Type: PT_NOTE, Flags: 0x0, Off: 0x3f8, Vaddr: 0x0, Paddr: 0x0, Filesz: 0x8ac, Memsz: 0x0, Align: 0x0}, + {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x1000, Vaddr: 0x400000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_R, Off: 0x1000, Vaddr: 0x401000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x2000, Vaddr: 0x402000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3000, Vaddr: 0x7f54078b8000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1b5000, Align: 0x1000}, + {Type: PT_LOAD, Flags: 0x0, Off: 0x3000, Vaddr: 0x7f5407a6d000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1ff000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_R, Off: 0x3000, Vaddr: 0x7f5407c6c000, Paddr: 0x0, Filesz: 0x4000, Memsz: 0x4000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x7000, Vaddr: 0x7f5407c70000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x9000, Vaddr: 0x7f5407c72000, Paddr: 0x0, Filesz: 0x5000, Memsz: 0x5000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0xe000, Vaddr: 0x7f5407c77000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x22000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0xe000, Vaddr: 0x7f5407e81000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x11000, Vaddr: 0x7f5407e96000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_R, Off: 0x14000, Vaddr: 0x7f5407e99000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x15000, Vaddr: 0x7f5407e9a000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x17000, Vaddr: 0x7fff79972000, Paddr: 0x0, Filesz: 0x23000, Memsz: 0x23000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3a000, Vaddr: 0x7fff799f8000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000}, + {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3b000, Vaddr: 0xffffffffff600000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000}, + }, + nil, + }, + { + "testdata/compressed-32.obj", + FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_386, 0x0}, + []SectionHeader{ + {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + {".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x34, 0x17, 0x0, 0x0, 0x1, 0x0, 0x17}, + {".rel.text", SHT_REL, SHF_INFO_LINK, 0x0, 0x3dc, 0x10, 0x13, 0x1, 0x4, 0x8, 0x10}, + {".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0}, + {".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0}, + {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x4b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd}, + {".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x58, 0xb4, 0x0, 0x0, 0x1, 0x0, 0x84}, + {".rel.debug_info", SHT_REL, SHF_INFO_LINK, 0x0, 0x3ec, 0xa0, 0x13, 0x6, 0x4, 0x8, 0xa0}, + {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xdc, 0x5a, 0x0, 0x0, 0x1, 0x0, 0x5a}, + {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x136, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20}, + {".rel.debug_aranges", SHT_REL, SHF_INFO_LINK, 0x0, 0x48c, 0x10, 0x13, 0x9, 0x4, 0x8, 0x10}, + {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x156, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c}, + {".rel.debug_line", SHT_REL, SHF_INFO_LINK, 0x0, 0x49c, 0x8, 0x13, 0xb, 0x4, 0x8, 0x8}, + {".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1b2, 0x10f, 0x0, 0x0, 0x1, 0x1, 0xb3}, + {".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x265, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a}, + {".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x28f, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0}, + {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x290, 0x38, 0x0, 0x0, 0x4, 0x0, 0x38}, + {".rel.eh_frame", SHT_REL, SHF_INFO_LINK, 0x0, 0x4a4, 0x8, 0x13, 0x10, 0x4, 0x8, 0x8}, + {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x4ac, 0xab, 0x0, 0x0, 0x1, 0x0, 0xab}, + {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2c8, 0x100, 0x14, 0xe, 0x4, 0x10, 0x100}, + {".strtab", SHT_STRTAB, 0x0, 0x0, 0x3c8, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13}, + }, + []ProgHeader{}, + nil, + }, + { + "testdata/compressed-64.obj", + FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_X86_64, 0x0}, + []SectionHeader{ + {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + {".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x40, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b}, + {".rela.text", SHT_RELA, SHF_INFO_LINK, 0x0, 0x488, 0x30, 0x13, 0x1, 0x8, 0x18, 0x30}, + {".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0}, + {".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0}, + {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x5b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd}, + {".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x68, 0xba, 0x0, 0x0, 0x1, 0x0, 0x72}, + {".rela.debug_info", SHT_RELA, SHF_INFO_LINK, 0x0, 0x4b8, 0x1c8, 0x13, 0x6, 0x8, 0x18, 0x1c8}, + {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xda, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c}, + {".debug_aranges", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x136, 0x30, 0x0, 0x0, 0x1, 0x0, 0x2f}, + {".rela.debug_aranges", SHT_RELA, SHF_INFO_LINK, 0x0, 0x680, 0x30, 0x13, 0x9, 0x8, 0x18, 0x30}, + {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x165, 0x60, 0x0, 0x0, 0x1, 0x0, 0x60}, + {".rela.debug_line", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6b0, 0x18, 0x13, 0xb, 0x8, 0x18, 0x18}, + {".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1c5, 0x104, 0x0, 0x0, 0x1, 0x1, 0xc3}, + {".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x288, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a}, + {".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x2b2, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0}, + {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x2b8, 0x38, 0x0, 0x0, 0x8, 0x0, 0x38}, + {".rela.eh_frame", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6c8, 0x18, 0x13, 0x10, 0x8, 0x18, 0x18}, + {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x6e0, 0xb0, 0x0, 0x0, 0x1, 0x0, 0xb0}, + {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2f0, 0x180, 0x14, 0xe, 0x8, 0x18, 0x180}, + {".strtab", SHT_STRTAB, 0x0, 0x0, 0x470, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13}, + }, + []ProgHeader{}, + nil, + }, +} + +func TestOpen(t *testing.T) { + for i := range fileTests { + tt := &fileTests[i] + + var f *File + var err error + if path.Ext(tt.file) == ".gz" { + var r io.ReaderAt + if r, err = decompress(tt.file); err == nil { + f, err = NewFile(r) + } + } else { + f, err = Open(tt.file) + } + if err != nil { + t.Errorf("cannot open file %s: %v", tt.file, err) + continue + } + defer f.Close() + if !reflect.DeepEqual(f.FileHeader, tt.hdr) { + t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr) + continue + } + for i, s := range f.Sections { + if i >= len(tt.sections) { + break + } + sh := &tt.sections[i] + if !reflect.DeepEqual(&s.SectionHeader, sh) { + t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &s.SectionHeader, sh) + } + } + for i, p := range f.Progs { + if i >= len(tt.progs) { + break + } + ph := &tt.progs[i] + if !reflect.DeepEqual(&p.ProgHeader, ph) { + t.Errorf("open %s, program %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &p.ProgHeader, ph) + } + } + tn := len(tt.sections) + fn := len(f.Sections) + if tn != fn { + t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn) + } + tn = len(tt.progs) + fn = len(f.Progs) + if tn != fn { + t.Errorf("open %s: len(Progs) = %d, want %d", tt.file, fn, tn) + } + tl := tt.needed + fl, err := f.ImportedLibraries() + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(tl, fl) { + t.Errorf("open %s: DT_NEEDED = %v, want %v", tt.file, tl, fl) + } + } +} + +// elf.NewFile requires io.ReaderAt, which compress/gzip cannot +// provide. Decompress the file to a bytes.Reader. +func decompress(gz string) (io.ReaderAt, error) { + in, err := os.Open(gz) + if err != nil { + return nil, err + } + defer in.Close() + r, err := gzip.NewReader(in) + if err != nil { + return nil, err + } + var out bytes.Buffer + _, err = io.Copy(&out, r) + return bytes.NewReader(out.Bytes()), err +} + +type relocationTestEntry struct { + entryNumber int + entry *dwarf.Entry +} + +type relocationTest struct { + file string + entries []relocationTestEntry +} + +var relocationTests = []relocationTest{ + { + "testdata/go-relocation-test-gcc441-x86-64.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, + {Attr: dwarf.AttrLanguage, Val: int64(1)}, + {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc441-x86.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, + {Attr: dwarf.AttrLanguage, Val: int64(1)}, + {Attr: dwarf.AttrName, Val: "t.c"}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc424-x86-64.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, + {Attr: dwarf.AttrLanguage, Val: int64(1)}, + {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc482-aarch64.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector"}, + {Attr: dwarf.AttrLanguage, Val: int64(1)}, + {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c"}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: int64(0x24)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc492-arm.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 20141224 (prerelease) -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mtls-dialect=gnu -g"}, + {Attr: dwarf.AttrLanguage, Val: int64(1)}, + {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c"}, + {Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: int64(0x28)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-clang-arm.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)"}, + {Attr: dwarf.AttrLanguage, Val: int64(12)}, + {Attr: dwarf.AttrName, Val: "hello.c"}, + {Attr: dwarf.AttrStmtList, Val: int64(0x0)}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: int64(48)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc5-ppc.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g"}, + {Attr: dwarf.AttrLanguage, Val: int64(12)}, + {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c"}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: int64(0x44)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc482-ppc64le.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector"}, + {Attr: dwarf.AttrLanguage, Val: int64(1)}, + {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c"}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: uint64(0x24)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc492-mips64.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -meb -mabi=64 -march=mips3 -mtune=mips64 -mllsc -mno-shared -g"}, + {Attr: dwarf.AttrLanguage, Val: int64(1)}, + {Attr: dwarf.AttrName, Val: "hello.c"}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: int64(100)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc531-s390x.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C11 5.3.1 20160316 -march=zEC12 -m64 -mzarch -g -fstack-protector-strong"}, + {Attr: dwarf.AttrLanguage, Val: int64(12)}, + {Attr: dwarf.AttrName, Val: "hello.c"}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: int64(58)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc620-sparc64.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C11 6.2.0 20160914 -mcpu=v9 -g -fstack-protector-strong"}, + {Attr: dwarf.AttrLanguage, Val: int64(12)}, + {Attr: dwarf.AttrName, Val: "hello.c"}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: int64(0x2c)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc492-mipsle.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -mel -march=mips2 -mtune=mips32 -mllsc -mno-shared -mabi=32 -g"}, + {Attr: dwarf.AttrLanguage, Val: int64(1)}, + {Attr: dwarf.AttrName, Val: "hello.c"}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: int64(0x58)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc540-mips.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C11 5.4.0 20160609 -meb -mips32 -mtune=mips32r2 -mfpxx -mllsc -mno-shared -mabi=32 -g -gdwarf-2"}, + {Attr: dwarf.AttrLanguage, Val: int64(12)}, + {Attr: dwarf.AttrName, Val: "hello.c"}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: uint64(0x5c)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc493-mips64le.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.3 -mel -mabi=64 -mllsc -mno-shared -g -fstack-protector-strong"}, + {Attr: dwarf.AttrLanguage, Val: int64(1)}, + {Attr: dwarf.AttrName, Val: "hello.c"}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: int64(100)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-gcc720-riscv64.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "GNU C11 7.2.0 -march=rv64imafdc -mabi=lp64d -g -gdwarf-2"}, + {Attr: dwarf.AttrLanguage, Val: int64(12)}, + {Attr: dwarf.AttrName, Val: "hello.c"}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, + {Attr: dwarf.AttrHighpc, Val: uint64(0x2c)}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + }, + }}, + }, + }, + { + "testdata/go-relocation-test-clang-x86.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{ + Offset: 0xb, + Tag: dwarf.TagCompileUnit, + Children: true, + Field: []dwarf.Field{ + {Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)"}, + {Attr: dwarf.AttrLanguage, Val: int64(12)}, + {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c"}, + {Attr: dwarf.AttrStmtList, Val: int64(0)}, + {Attr: dwarf.AttrCompDir, Val: "/tmp"}, + }, + }}, + }, + }, + { + "testdata/gcc-amd64-openbsd-debug-with-rela.obj", + []relocationTestEntry{ + {203, &dwarf.Entry{ + Offset: 0xc62, + Tag: dwarf.TagMember, + Children: false, + Field: []dwarf.Field{ + {Attr: dwarf.AttrName, Val: "it_interval"}, + {Attr: dwarf.AttrDeclFile, Val: int64(7)}, + {Attr: dwarf.AttrDeclLine, Val: int64(236)}, + {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, + {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}}, + }, + }}, + {204, &dwarf.Entry{ + Offset: 0xc70, + Tag: dwarf.TagMember, + Children: false, + Field: []dwarf.Field{ + {Attr: dwarf.AttrName, Val: "it_value"}, + {Attr: dwarf.AttrDeclFile, Val: int64(7)}, + {Attr: dwarf.AttrDeclLine, Val: int64(237)}, + {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, + {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}}, + }, + }}, + }, + }, +} + +func TestDWARFRelocations(t *testing.T) { + for i, test := range relocationTests { + f, err := Open(test.file) + if err != nil { + t.Error(err) + continue + } + dwarf, err := f.DWARF() + if err != nil { + t.Error(err) + continue + } + for _, testEntry := range test.entries { + reader := dwarf.Reader() + for j := 0; j < testEntry.entryNumber; j++ { + entry, err := reader.Next() + if entry == nil || err != nil { + t.Errorf("Failed to skip to entry %d: %v", testEntry.entryNumber, err) + continue + } + } + entry, err := reader.Next() + if err != nil { + t.Error(err) + continue + } + if !reflect.DeepEqual(testEntry.entry, entry) { + t.Errorf("#%d/%d: mismatch: got:%#v want:%#v", i, testEntry.entryNumber, entry, testEntry.entry) + continue + } + } + } +} + +func TestCompressedDWARF(t *testing.T) { + // Test file built with GCC 4.8.4 and as 2.24 using: + // gcc -Wa,--compress-debug-sections -g -c -o zdebug-test-gcc484-x86-64.obj hello.c + f, err := Open("testdata/zdebug-test-gcc484-x86-64.obj") + if err != nil { + t.Fatal(err) + } + dwarf, err := f.DWARF() + if err != nil { + t.Fatal(err) + } + reader := dwarf.Reader() + n := 0 + for { + entry, err := reader.Next() + if err != nil { + t.Fatal(err) + } + if entry == nil { + break + } + n++ + } + if n != 18 { + t.Fatalf("want %d DWARF entries, got %d", 18, n) + } +} + +func TestCompressedSection(t *testing.T) { + // Test files built with gcc -g -S hello.c and assembled with + // --compress-debug-sections=zlib-gabi. + f, err := Open("testdata/compressed-64.obj") + if err != nil { + t.Fatal(err) + } + sec := f.Section(".debug_info") + wantData := []byte{ + 182, 0, 0, 0, 4, 0, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 7, + 0, 0, 0, 0, 2, 1, 8, 0, 0, 0, 0, 2, 2, 7, 0, 0, + 0, 0, 2, 4, 7, 0, 0, 0, 0, 2, 1, 6, 0, 0, 0, 0, + 2, 2, 5, 0, 0, 0, 0, 3, 4, 5, 105, 110, 116, 0, 2, 8, + 5, 0, 0, 0, 0, 2, 8, 7, 0, 0, 0, 0, 4, 8, 114, 0, + 0, 0, 2, 1, 6, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, + 1, 156, 179, 0, 0, 0, 6, 0, 0, 0, 0, 1, 4, 87, 0, 0, + 0, 2, 145, 108, 6, 0, 0, 0, 0, 1, 4, 179, 0, 0, 0, 2, + 145, 96, 0, 4, 8, 108, 0, 0, 0, 0, + } + + // Test Data method. + b, err := sec.Data() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(wantData, b) { + t.Fatalf("want data %x, got %x", wantData, b) + } + + // Test Open method and seeking. + buf, have, count := make([]byte, len(b)), make([]bool, len(b)), 0 + sf := sec.Open() + if got, err := sf.Seek(0, io.SeekEnd); got != int64(len(b)) || err != nil { + t.Fatalf("want seek end %d, got %d error %v", len(b), got, err) + } + if n, err := sf.Read(buf); n != 0 || err != io.EOF { + t.Fatalf("want EOF with 0 bytes, got %v with %d bytes", err, n) + } + pos := int64(len(buf)) + for count < len(buf) { + // Construct random seek arguments. + whence := rand.Intn(3) + target := rand.Int63n(int64(len(buf))) + var offset int64 + switch whence { + case io.SeekStart: + offset = target + case io.SeekCurrent: + offset = target - pos + case io.SeekEnd: + offset = target - int64(len(buf)) + } + pos, err = sf.Seek(offset, whence) + if err != nil { + t.Fatal(err) + } + if pos != target { + t.Fatalf("want position %d, got %d", target, pos) + } + + // Read data from the new position. + end := pos + 16 + if end > int64(len(buf)) { + end = int64(len(buf)) + } + n, err := io.ReadFull(sf, buf[pos:end]) + if err != nil { + t.Fatal(err) + } + for i := 0; i < n; i++ { + if !have[pos] { + have[pos] = true + count++ + } + pos++ + } + } + if !bytes.Equal(wantData, buf) { + t.Fatalf("want data %x, got %x", wantData, buf) + } +} + +func TestNoSectionOverlaps(t *testing.T) { + // Ensure cmd/link outputs sections without overlaps. + switch runtime.GOOS { + case "android", "darwin", "js", "nacl", "plan9", "windows": + t.Skipf("cmd/link doesn't produce ELF binaries on %s", runtime.GOOS) + } + _ = net.ResolveIPAddr // force dynamic linkage + f, err := Open(os.Args[0]) + if err != nil { + t.Error(err) + return + } + for i, si := range f.Sections { + sih := si.SectionHeader + if sih.Type == SHT_NOBITS { + continue + } + for j, sj := range f.Sections { + sjh := sj.SectionHeader + if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.Size == 0 { + continue + } + if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.Size { + t.Errorf("ld produced ELF with section %s within %s: 0x%x <= 0x%x..0x%x < 0x%x", + sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.Size, sjh.Offset+sjh.Size) + } + } + } +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/reader.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/reader.go new file mode 100644 index 00000000..bfb893fe --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/reader.go @@ -0,0 +1,118 @@ +// Copyright 2018 Google LLC +// +// 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 elf + +import ( + "io" + "os" +) + +// errorReader returns error from all operations. +type errorReader struct { + error +} + +func (r errorReader) Read(p []byte) (n int, err error) { + return 0, r.error +} + +func (r errorReader) ReadAt(p []byte, off int64) (n int, err error) { + return 0, r.error +} + +func (r errorReader) Seek(offset int64, whence int) (int64, error) { + return 0, r.error +} + +func (r errorReader) Close() error { + return r.error +} + +// readSeekerFromReader converts an io.Reader into an io.ReadSeeker. +// In general Seek may not be efficient, but it is optimized for +// common cases such as seeking to the end to find the length of the +// data. +type readSeekerFromReader struct { + reset func() (io.Reader, error) + r io.Reader + size int64 + offset int64 +} + +func (r *readSeekerFromReader) start() { + x, err := r.reset() + if err != nil { + r.r = errorReader{err} + } else { + r.r = x + } + r.offset = 0 +} + +func (r *readSeekerFromReader) Read(p []byte) (n int, err error) { + if r.r == nil { + r.start() + } + n, err = r.r.Read(p) + r.offset += int64(n) + return n, err +} + +func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) { + var newOffset int64 + switch whence { + case seekStart: + newOffset = offset + case seekCurrent: + newOffset = r.offset + offset + case seekEnd: + newOffset = r.size + offset + default: + return 0, os.ErrInvalid + } + + switch { + case newOffset == r.offset: + return newOffset, nil + + case newOffset < 0, newOffset > r.size: + return 0, os.ErrInvalid + + case newOffset == 0: + r.r = nil + + case newOffset == r.size: + r.r = errorReader{io.EOF} + + default: + if newOffset < r.offset { + // Restart at the beginning. + r.start() + } + // Read until we reach offset. + var buf [512]byte + for r.offset < newOffset { + b := buf[:] + if newOffset-r.offset < int64(len(buf)) { + b = buf[:newOffset-r.offset] + } + if _, err := r.Read(b); err != nil { + return 0, err + } + } + } + r.offset = newOffset + return r.offset, nil +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/symbols_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/symbols_test.go new file mode 100644 index 00000000..1eac61fd --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/symbols_test.go @@ -0,0 +1,846 @@ +// Copyright 2018 Google LLC +// +// 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. + +// +build go1.7 + +package elf + +import ( + "io" + "path" + "reflect" + "testing" +) + +// TODO: remove duplicate code +func TestSymbols(t *testing.T) { + do := func(file string, ts []Symbol, getfunc func(*File) ([]Symbol, error)) { + var f *File + var err error + if path.Ext(file) == ".gz" { + var r io.ReaderAt + if r, err = decompress(file); err == nil { + f, err = NewFile(r) + } + } else { + f, err = Open(file) + } + if err != nil { + t.Errorf("TestSymbols: cannot open file %s: %v", file, err) + return + } + defer f.Close() + fs, err := getfunc(f) + if err != nil && err != ErrNoSymbols { + t.Error(err) + return + } else if err == ErrNoSymbols { + fs = []Symbol{} + } + if !reflect.DeepEqual(ts, fs) { + t.Errorf("%s: Symbols = %v, want %v", file, ts, fs) + } + } + for file, ts := range symbolsGolden { + do(file, ts, (*File).Symbols) + } + for file, ts := range dynamicSymbolsGolden { + do(file, ts, (*File).DynamicSymbols) + } +} + +// golden symbol table data generated by testdata/getgoldsym.c + +var symbolsGolden = map[string][]Symbol{ + "testdata/gcc-amd64-linux-exec": { + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x1, + Value: 0x400200, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x2, + Value: 0x40021C, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x3, + Value: 0x400240, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x4, + Value: 0x400268, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x5, + Value: 0x400288, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x6, + Value: 0x4002E8, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x7, + Value: 0x400326, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x8, + Value: 0x400330, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x9, + Value: 0x400350, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0xA, + Value: 0x400368, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0xB, + Value: 0x400398, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0xC, + Value: 0x4003B0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0xD, + Value: 0x4003E0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0xE, + Value: 0x400594, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0xF, + Value: 0x4005A4, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x10, + Value: 0x4005B8, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x11, + Value: 0x4005E0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x12, + Value: 0x600688, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x13, + Value: 0x600698, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x14, + Value: 0x6006A8, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x15, + Value: 0x6006B0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x16, + Value: 0x600850, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x17, + Value: 0x600858, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x18, + Value: 0x600880, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x19, + Value: 0x600898, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x1A, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x1B, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x1C, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x1D, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x1E, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x1F, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x20, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x21, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "init.c", + Info: 0x4, + Other: 0x0, + Section: 0xFFF1, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "initfini.c", + Info: 0x4, + Other: 0x0, + Section: 0xFFF1, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "call_gmon_start", + Info: 0x2, + Other: 0x0, + Section: 0xD, + Value: 0x40040C, + Size: 0x0, + }, + Symbol{ + Name: "crtstuff.c", + Info: 0x4, + Other: 0x0, + Section: 0xFFF1, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "__CTOR_LIST__", + Info: 0x1, + Other: 0x0, + Section: 0x12, + Value: 0x600688, + Size: 0x0, + }, + Symbol{ + Name: "__DTOR_LIST__", + Info: 0x1, + Other: 0x0, + Section: 0x13, + Value: 0x600698, + Size: 0x0, + }, + Symbol{ + Name: "__JCR_LIST__", + Info: 0x1, + Other: 0x0, + Section: 0x14, + Value: 0x6006A8, + Size: 0x0, + }, + Symbol{ + Name: "__do_global_dtors_aux", + Info: 0x2, + Other: 0x0, + Section: 0xD, + Value: 0x400430, + Size: 0x0, + }, + Symbol{ + Name: "completed.6183", + Info: 0x1, + Other: 0x0, + Section: 0x19, + Value: 0x600898, + Size: 0x1, + }, + Symbol{ + Name: "p.6181", + Info: 0x1, + Other: 0x0, + Section: 0x18, + Value: 0x600890, + Size: 0x0, + }, + Symbol{ + Name: "frame_dummy", + Info: 0x2, + Other: 0x0, + Section: 0xD, + Value: 0x400470, + Size: 0x0, + }, + Symbol{ + Name: "crtstuff.c", + Info: 0x4, + Other: 0x0, + Section: 0xFFF1, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "__CTOR_END__", + Info: 0x1, + Other: 0x0, + Section: 0x12, + Value: 0x600690, + Size: 0x0, + }, + Symbol{ + Name: "__DTOR_END__", + Info: 0x1, + Other: 0x0, + Section: 0x13, + Value: 0x6006A0, + Size: 0x0, + }, + Symbol{ + Name: "__FRAME_END__", + Info: 0x1, + Other: 0x0, + Section: 0x11, + Value: 0x400680, + Size: 0x0, + }, + Symbol{ + Name: "__JCR_END__", + Info: 0x1, + Other: 0x0, + Section: 0x14, + Value: 0x6006A8, + Size: 0x0, + }, + Symbol{ + Name: "__do_global_ctors_aux", + Info: 0x2, + Other: 0x0, + Section: 0xD, + Value: 0x400560, + Size: 0x0, + }, + Symbol{ + Name: "initfini.c", + Info: 0x4, + Other: 0x0, + Section: 0xFFF1, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "hello.c", + Info: 0x4, + Other: 0x0, + Section: 0xFFF1, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "_GLOBAL_OFFSET_TABLE_", + Info: 0x1, + Other: 0x2, + Section: 0x17, + Value: 0x600858, + Size: 0x0, + }, + Symbol{ + Name: "__init_array_end", + Info: 0x0, + Other: 0x2, + Section: 0x12, + Value: 0x600684, + Size: 0x0, + }, + Symbol{ + Name: "__init_array_start", + Info: 0x0, + Other: 0x2, + Section: 0x12, + Value: 0x600684, + Size: 0x0, + }, + Symbol{ + Name: "_DYNAMIC", + Info: 0x1, + Other: 0x2, + Section: 0x15, + Value: 0x6006B0, + Size: 0x0, + }, + Symbol{ + Name: "data_start", + Info: 0x20, + Other: 0x0, + Section: 0x18, + Value: 0x600880, + Size: 0x0, + }, + Symbol{ + Name: "__libc_csu_fini", + Info: 0x12, + Other: 0x0, + Section: 0xD, + Value: 0x4004C0, + Size: 0x2, + }, + Symbol{ + Name: "_start", + Info: 0x12, + Other: 0x0, + Section: 0xD, + Value: 0x4003E0, + Size: 0x0, + }, + Symbol{ + Name: "__gmon_start__", + Info: 0x20, + Other: 0x0, + Section: 0x0, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "_Jv_RegisterClasses", + Info: 0x20, + Other: 0x0, + Section: 0x0, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "puts@@GLIBC_2.2.5", + Info: 0x12, + Other: 0x0, + Section: 0x0, + Value: 0x0, + Size: 0x18C, + }, + Symbol{ + Name: "_fini", + Info: 0x12, + Other: 0x0, + Section: 0xE, + Value: 0x400594, + Size: 0x0, + }, + Symbol{ + Name: "__libc_start_main@@GLIBC_2.2.5", + Info: 0x12, + Other: 0x0, + Section: 0x0, + Value: 0x0, + Size: 0x1C2, + }, + Symbol{ + Name: "_IO_stdin_used", + Info: 0x11, + Other: 0x0, + Section: 0xF, + Value: 0x4005A4, + Size: 0x4, + }, + Symbol{ + Name: "__data_start", + Info: 0x10, + Other: 0x0, + Section: 0x18, + Value: 0x600880, + Size: 0x0, + }, + Symbol{ + Name: "__dso_handle", + Info: 0x11, + Other: 0x2, + Section: 0x18, + Value: 0x600888, + Size: 0x0, + }, + Symbol{ + Name: "__libc_csu_init", + Info: 0x12, + Other: 0x0, + Section: 0xD, + Value: 0x4004D0, + Size: 0x89, + }, + Symbol{ + Name: "__bss_start", + Info: 0x10, + Other: 0x0, + Section: 0xFFF1, + Value: 0x600898, + Size: 0x0, + }, + Symbol{ + Name: "_end", + Info: 0x10, + Other: 0x0, + Section: 0xFFF1, + Value: 0x6008A0, + Size: 0x0, + }, + Symbol{ + Name: "_edata", + Info: 0x10, + Other: 0x0, + Section: 0xFFF1, + Value: 0x600898, + Size: 0x0, + }, + Symbol{ + Name: "main", + Info: 0x12, + Other: 0x0, + Section: 0xD, + Value: 0x400498, + Size: 0x1B, + }, + Symbol{ + Name: "_init", + Info: 0x12, + Other: 0x0, + Section: 0xB, + Value: 0x400398, + Size: 0x0, + }, + }, + "testdata/go-relocation-test-clang-x86.obj": { + Symbol{ + Name: "go-relocation-test-clang.c", + Info: 0x4, + Other: 0x0, + Section: 0xFFF1, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: ".Linfo_string0", + Info: 0x0, + Other: 0x0, + Section: 0xC, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: ".Linfo_string1", + Info: 0x0, + Other: 0x0, + Section: 0xC, + Value: 0x2C, + Size: 0x0, + }, + Symbol{ + Name: ".Linfo_string2", + Info: 0x0, + Other: 0x0, + Section: 0xC, + Value: 0x47, + Size: 0x0, + }, + Symbol{ + Name: ".Linfo_string3", + Info: 0x0, + Other: 0x0, + Section: 0xC, + Value: 0x4C, + Size: 0x0, + }, + Symbol{ + Name: ".Linfo_string4", + Info: 0x0, + Other: 0x0, + Section: 0xC, + Value: 0x4E, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x1, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x2, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x3, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x4, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x6, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x7, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x8, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0xA, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0xC, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0xD, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0xE, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0xF, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "", + Info: 0x3, + Other: 0x0, + Section: 0x10, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "v", + Info: 0x11, + Other: 0x0, + Section: 0xFFF2, + Value: 0x4, + Size: 0x4, + }, + }, + "testdata/hello-world-core.gz": {}, +} + +var dynamicSymbolsGolden = map[string][]Symbol{ + "testdata/gcc-amd64-linux-exec": { + Symbol{ + Name: "__gmon_start__", + Info: 0x20, + Other: 0x0, + Section: 0x0, + Value: 0x0, + Size: 0x0, + }, + Symbol{ + Name: "puts", + Info: 0x12, + Other: 0x0, + Section: 0x0, + Value: 0x0, + Size: 0x18C, + }, + Symbol{ + Name: "__libc_start_main", + Info: 0x12, + Other: 0x0, + Section: 0x0, + Value: 0x0, + Size: 0x1C2, + }, + }, + "testdata/go-relocation-test-clang-x86.obj": {}, + "testdata/hello-world-core.gz": {}, +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/compressed-32.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/compressed-32.obj new file mode 100755 index 00000000..2bfdb442 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/compressed-32.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/compressed-64.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/compressed-64.obj new file mode 100755 index 00000000..ffae56a9 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/compressed-64.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/gcc-386-freebsd-exec b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/gcc-386-freebsd-exec new file mode 100755 index 00000000..7af9c58c Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/gcc-386-freebsd-exec differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/gcc-amd64-linux-exec b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/gcc-amd64-linux-exec new file mode 100755 index 00000000..c6cb1de2 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/gcc-amd64-linux-exec differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/gcc-amd64-openbsd-debug-with-rela.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/gcc-amd64-openbsd-debug-with-rela.obj new file mode 100755 index 00000000..f62b1ea1 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/gcc-amd64-openbsd-debug-with-rela.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-clang-arm.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-clang-arm.obj new file mode 100755 index 00000000..1cc7e4b1 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-clang-arm.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-clang-x86.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-clang-x86.obj new file mode 100755 index 00000000..e909cf4e Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-clang-x86.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj new file mode 100755 index 00000000..a7c6d6e5 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj new file mode 100755 index 00000000..2d37ab6e Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc441-x86.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc441-x86.obj new file mode 100755 index 00000000..0d59fe30 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc441-x86.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc482-aarch64.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc482-aarch64.obj new file mode 100755 index 00000000..849e2644 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc482-aarch64.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.obj new file mode 100755 index 00000000..dad74454 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc492-arm.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc492-arm.obj new file mode 100755 index 00000000..ed45be2c Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc492-arm.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc492-mips64.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc492-mips64.obj new file mode 100755 index 00000000..68febe18 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc492-mips64.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc492-mipsle.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc492-mipsle.obj new file mode 100755 index 00000000..a5fbcfbb Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc492-mipsle.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc493-mips64le.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc493-mips64le.obj new file mode 100755 index 00000000..20bbd6c4 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc493-mips64le.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc5-ppc.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc5-ppc.obj new file mode 100755 index 00000000..f4165af0 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc5-ppc.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc531-s390x.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc531-s390x.obj new file mode 100755 index 00000000..caacb9b9 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc531-s390x.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc540-mips.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc540-mips.obj new file mode 100755 index 00000000..270c7775 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc540-mips.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc620-sparc64.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc620-sparc64.obj new file mode 100755 index 00000000..d65c23e1 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc620-sparc64.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc720-riscv64.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc720-riscv64.obj new file mode 100755 index 00000000..91ae6487 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/go-relocation-test-gcc720-riscv64.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/hello-world-core.gz b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/hello-world-core.gz new file mode 100755 index 00000000..6d76ab09 Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/hello-world-core.gz differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/hello.c b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/hello.c new file mode 100755 index 00000000..34d9ee79 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/hello.c @@ -0,0 +1,7 @@ +#include + +void +main(int argc, char *argv[]) +{ + printf("hello, world\n"); +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj new file mode 100755 index 00000000..a595a01d Binary files /dev/null and b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/testdata/zdebug-test-gcc484-x86-64.obj differ diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclinetest.asm b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclinetest.asm new file mode 100644 index 00000000..b9ee9c0a --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclinetest.asm @@ -0,0 +1,58 @@ +TEXT linefrompc(SB),4,$0 // Each byte stores its line delta +BYTE $2; +BYTE $1; +BYTE $1; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; +BYTE $1; +BYTE $1; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +BYTE $1; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; BYTE $0; +#include "pclinetest.h" +BYTE $2; +#include "pclinetest.h" +BYTE $2; +BYTE $255; + +TEXT pcfromline(SB),4,$0 // Each record stores its line delta, then n, then n more bytes +BYTE $32; BYTE $0; +BYTE $1; BYTE $1; BYTE $0; +BYTE $1; BYTE $0; + +BYTE $2; BYTE $4; BYTE $0; BYTE $0; BYTE $0; BYTE $0; + + +#include "pclinetest.h" +BYTE $4; BYTE $0; + + +BYTE $3; BYTE $3; BYTE $0; BYTE $0; BYTE $0; +#include "pclinetest.h" + + +BYTE $4; BYTE $3; BYTE $0; BYTE $0; BYTE $0; +BYTE $255; + +// Keep the linker happy +TEXT main·main(SB),4,$0 + RET + +TEXT main·init(SB),4,$0 + // Prevent GC of our test symbols + CALL linefrompc(SB) + CALL pcfromline(SB) + RET diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclinetest.h b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclinetest.h new file mode 100644 index 00000000..156c0b87 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclinetest.h @@ -0,0 +1,9 @@ +// +build ignore + +// Empty include file to generate z symbols + + + + + +// EOF diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclntab.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclntab.go new file mode 100644 index 00000000..dcd7015b --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclntab.go @@ -0,0 +1,472 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +/* + * Line tables + */ + +package gosym + +import ( + "encoding/binary" + "sync" +) + +// A LineTable is a data structure mapping program counters to line numbers. +// +// In Go 1.1 and earlier, each function (represented by a Func) had its own LineTable, +// and the line number corresponded to a numbering of all source lines in the +// program, across all files. That absolute line number would then have to be +// converted separately to a file name and line number within the file. +// +// In Go 1.2, the format of the data changed so that there is a single LineTable +// for the entire program, shared by all Funcs, and there are no absolute line +// numbers, just line numbers within specific files. +// +// For the most part, LineTable's methods should be treated as an internal +// detail of the package; callers should use the methods on Table instead. +type LineTable struct { + Data []byte + PC uint64 + Line int + + // Go 1.2 state + mu sync.Mutex + go12 int // is this in Go 1.2 format? -1 no, 0 unknown, 1 yes + binary binary.ByteOrder + quantum uint32 + ptrsize uint32 + functab []byte + nfunctab uint32 + filetab []byte + nfiletab uint32 + fileMap map[string]uint32 +} + +// NOTE(rsc): This is wrong for GOARCH=arm, which uses a quantum of 4, +// but we have no idea whether we're using arm or not. This only +// matters in the old (pre-Go 1.2) symbol table format, so it's not worth +// fixing. +const oldQuantum = 1 + +func (t *LineTable) parse(targetPC uint64, targetLine int) (b []byte, pc uint64, line int) { + // The PC/line table can be thought of as a sequence of + // * + // batches. Each update batch results in a (pc, line) pair, + // where line applies to every PC from pc up to but not + // including the pc of the next pair. + // + // Here we process each update individually, which simplifies + // the code, but makes the corner cases more confusing. + b, pc, line = t.Data, t.PC, t.Line + for pc <= targetPC && line != targetLine && len(b) > 0 { + code := b[0] + b = b[1:] + switch { + case code == 0: + if len(b) < 4 { + b = b[0:0] + break + } + val := binary.BigEndian.Uint32(b) + b = b[4:] + line += int(val) + case code <= 64: + line += int(code) + case code <= 128: + line -= int(code - 64) + default: + pc += oldQuantum * uint64(code-128) + continue + } + pc += oldQuantum + } + return b, pc, line +} + +func (t *LineTable) slice(pc uint64) *LineTable { + data, pc, line := t.parse(pc, -1) + return &LineTable{Data: data, PC: pc, Line: line} +} + +// PCToLine returns the line number for the given program counter. +// Callers should use Table's PCToLine method instead. +func (t *LineTable) PCToLine(pc uint64) int { + if t.isGo12() { + return t.go12PCToLine(pc) + } + _, _, line := t.parse(pc, -1) + return line +} + +// LineToPC returns the program counter for the given line number, +// considering only program counters before maxpc. +// Callers should use Table's LineToPC method instead. +func (t *LineTable) LineToPC(line int, maxpc uint64) uint64 { + if t.isGo12() { + return 0 + } + _, pc, line1 := t.parse(maxpc, line) + if line1 != line { + return 0 + } + // Subtract quantum from PC to account for post-line increment + return pc - oldQuantum +} + +// NewLineTable returns a new PC/line table +// corresponding to the encoded data. +// Text must be the start address of the +// corresponding text segment. +func NewLineTable(data []byte, text uint64) *LineTable { + return &LineTable{Data: data, PC: text, Line: 0} +} + +// Go 1.2 symbol table format. +// See golang.org/s/go12symtab. +// +// A general note about the methods here: rather than try to avoid +// index out of bounds errors, we trust Go to detect them, and then +// we recover from the panics and treat them as indicative of a malformed +// or incomplete table. +// +// The methods called by symtab.go, which begin with "go12" prefixes, +// are expected to have that recovery logic. + +// isGo12 reports whether this is a Go 1.2 (or later) symbol table. +func (t *LineTable) isGo12() bool { + t.go12Init() + return t.go12 == 1 +} + +const go12magic = 0xfffffffb + +// uintptr returns the pointer-sized value encoded at b. +// The pointer size is dictated by the table being read. +func (t *LineTable) uintptr(b []byte) uint64 { + if t.ptrsize == 4 { + return uint64(t.binary.Uint32(b)) + } + return t.binary.Uint64(b) +} + +// go12init initializes the Go 1.2 metadata if t is a Go 1.2 symbol table. +func (t *LineTable) go12Init() { + t.mu.Lock() + defer t.mu.Unlock() + if t.go12 != 0 { + return + } + + defer func() { + // If we panic parsing, assume it's not a Go 1.2 symbol table. + recover() + }() + + // Check header: 4-byte magic, two zeros, pc quantum, pointer size. + t.go12 = -1 // not Go 1.2 until proven otherwise + if len(t.Data) < 16 || t.Data[4] != 0 || t.Data[5] != 0 || + (t.Data[6] != 1 && t.Data[6] != 4) || // pc quantum + (t.Data[7] != 4 && t.Data[7] != 8) { // pointer size + return + } + + switch uint32(go12magic) { + case binary.LittleEndian.Uint32(t.Data): + t.binary = binary.LittleEndian + case binary.BigEndian.Uint32(t.Data): + t.binary = binary.BigEndian + default: + return + } + + t.quantum = uint32(t.Data[6]) + t.ptrsize = uint32(t.Data[7]) + + t.nfunctab = uint32(t.uintptr(t.Data[8:])) + t.functab = t.Data[8+t.ptrsize:] + functabsize := t.nfunctab*2*t.ptrsize + t.ptrsize + fileoff := t.binary.Uint32(t.functab[functabsize:]) + t.functab = t.functab[:functabsize] + t.filetab = t.Data[fileoff:] + t.nfiletab = t.binary.Uint32(t.filetab) + t.filetab = t.filetab[:t.nfiletab*4] + + t.go12 = 1 // so far so good +} + +// go12Funcs returns a slice of Funcs derived from the Go 1.2 pcln table. +func (t *LineTable) go12Funcs() []Func { + // Assume it is malformed and return nil on error. + defer func() { + recover() + }() + + n := len(t.functab) / int(t.ptrsize) / 2 + funcs := make([]Func, n) + for i := range funcs { + f := &funcs[i] + f.Entry = uint64(t.uintptr(t.functab[2*i*int(t.ptrsize):])) + f.End = uint64(t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):])) + info := t.Data[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):] + f.LineTable = t + f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:])) + f.Sym = &Sym{ + Value: f.Entry, + Type: 'T', + Name: t.string(t.binary.Uint32(info[t.ptrsize:])), + GoType: 0, + Func: f, + } + } + return funcs +} + +// findFunc returns the func corresponding to the given program counter. +func (t *LineTable) findFunc(pc uint64) []byte { + if pc < t.uintptr(t.functab) || pc >= t.uintptr(t.functab[len(t.functab)-int(t.ptrsize):]) { + return nil + } + + // The function table is a list of 2*nfunctab+1 uintptrs, + // alternating program counters and offsets to func structures. + f := t.functab + nf := t.nfunctab + for nf > 0 { + m := nf / 2 + fm := f[2*t.ptrsize*m:] + if t.uintptr(fm) <= pc && pc < t.uintptr(fm[2*t.ptrsize:]) { + return t.Data[t.uintptr(fm[t.ptrsize:]):] + } else if pc < t.uintptr(fm) { + nf = m + } else { + f = f[(m+1)*2*t.ptrsize:] + nf -= m + 1 + } + } + return nil +} + +// readvarint reads, removes, and returns a varint from *pp. +func (t *LineTable) readvarint(pp *[]byte) uint32 { + var v, shift uint32 + p := *pp + for shift = 0; ; shift += 7 { + b := p[0] + p = p[1:] + v |= (uint32(b) & 0x7F) << shift + if b&0x80 == 0 { + break + } + } + *pp = p + return v +} + +// string returns a Go string found at off. +func (t *LineTable) string(off uint32) string { + for i := off; ; i++ { + if t.Data[i] == 0 { + return string(t.Data[off:i]) + } + } +} + +// step advances to the next pc, value pair in the encoded table. +func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool { + uvdelta := t.readvarint(p) + if uvdelta == 0 && !first { + return false + } + if uvdelta&1 != 0 { + uvdelta = ^(uvdelta >> 1) + } else { + uvdelta >>= 1 + } + vdelta := int32(uvdelta) + pcdelta := t.readvarint(p) * t.quantum + *pc += uint64(pcdelta) + *val += vdelta + return true +} + +// pcvalue reports the value associated with the target pc. +// off is the offset to the beginning of the pc-value table, +// and entry is the start PC for the corresponding function. +func (t *LineTable) pcvalue(off uint32, entry, targetpc uint64) int32 { + if off == 0 { + return -1 + } + p := t.Data[off:] + + val := int32(-1) + pc := entry + for t.step(&p, &pc, &val, pc == entry) { + if targetpc < pc { + return val + } + } + return -1 +} + +// findFileLine scans one function in the binary looking for a +// program counter in the given file on the given line. +// It does so by running the pc-value tables mapping program counter +// to file number. Since most functions come from a single file, these +// are usually short and quick to scan. If a file match is found, then the +// code goes to the expense of looking for a simultaneous line number match. +func (t *LineTable) findFileLine(entry uint64, filetab, linetab uint32, filenum, line int32) uint64 { + if filetab == 0 || linetab == 0 { + return 0 + } + + fp := t.Data[filetab:] + fl := t.Data[linetab:] + fileVal := int32(-1) + filePC := entry + lineVal := int32(-1) + linePC := entry + fileStartPC := filePC + for t.step(&fp, &filePC, &fileVal, filePC == entry) { + if fileVal == filenum && fileStartPC < filePC { + // fileVal is in effect starting at fileStartPC up to + // but not including filePC, and it's the file we want. + // Run the PC table looking for a matching line number + // or until we reach filePC. + lineStartPC := linePC + for linePC < filePC && t.step(&fl, &linePC, &lineVal, linePC == entry) { + // lineVal is in effect until linePC, and lineStartPC < filePC. + if lineVal == line { + if fileStartPC <= lineStartPC { + return lineStartPC + } + if fileStartPC < linePC { + return fileStartPC + } + } + lineStartPC = linePC + } + } + fileStartPC = filePC + } + return 0 +} + +// go12PCToLine maps program counter to line number for the Go 1.2 pcln table. +func (t *LineTable) go12PCToLine(pc uint64) (line int) { + return t.go12PCToVal(pc, t.ptrsize+5*4) +} + +// go12PCToSPAdj maps program counter to Stack Pointer adjustment for the Go 1.2 pcln table. +func (t *LineTable) go12PCToSPAdj(pc uint64) (spadj int) { + return t.go12PCToVal(pc, t.ptrsize+3*4) +} + +func (t *LineTable) go12PCToVal(pc uint64, fOffset uint32) (val int) { + defer func() { + if recover() != nil { + val = -1 + } + }() + + f := t.findFunc(pc) + if f == nil { + return -1 + } + entry := t.uintptr(f) + linetab := t.binary.Uint32(f[fOffset:]) + return int(t.pcvalue(linetab, entry, pc)) +} + +// go12PCToFile maps program counter to file name for the Go 1.2 pcln table. +func (t *LineTable) go12PCToFile(pc uint64) (file string) { + defer func() { + if recover() != nil { + file = "" + } + }() + + f := t.findFunc(pc) + if f == nil { + return "" + } + entry := t.uintptr(f) + filetab := t.binary.Uint32(f[t.ptrsize+4*4:]) + fno := t.pcvalue(filetab, entry, pc) + if fno <= 0 { + return "" + } + return t.string(t.binary.Uint32(t.filetab[4*fno:])) +} + +// go12LineToPC maps a (file, line) pair to a program counter for the Go 1.2 pcln table. +func (t *LineTable) go12LineToPC(file string, line int) (pc uint64) { + defer func() { + if recover() != nil { + pc = 0 + } + }() + + t.initFileMap() + filenum := t.fileMap[file] + if filenum == 0 { + return 0 + } + + // Scan all functions. + // If this turns out to be a bottleneck, we could build a map[int32][]int32 + // mapping file number to a list of functions with code from that file. + for i := uint32(0); i < t.nfunctab; i++ { + f := t.Data[t.uintptr(t.functab[2*t.ptrsize*i+t.ptrsize:]):] + entry := t.uintptr(f) + filetab := t.binary.Uint32(f[t.ptrsize+4*4:]) + linetab := t.binary.Uint32(f[t.ptrsize+5*4:]) + pc := t.findFileLine(entry, filetab, linetab, int32(filenum), int32(line)) + if pc != 0 { + return pc + } + } + return 0 +} + +// initFileMap initializes the map from file name to file number. +func (t *LineTable) initFileMap() { + t.mu.Lock() + defer t.mu.Unlock() + + if t.fileMap != nil { + return + } + m := make(map[string]uint32) + + for i := uint32(1); i < t.nfiletab; i++ { + s := t.string(t.binary.Uint32(t.filetab[4*i:])) + m[s] = i + } + t.fileMap = m +} + +// go12MapFiles adds to m a key for every file in the Go 1.2 LineTable. +// Every key maps to obj. That's not a very interesting map, but it provides +// a way for callers to obtain the list of files in the program. +func (t *LineTable) go12MapFiles(m map[string]*Obj, obj *Obj) { + defer func() { + recover() + }() + + t.initFileMap() + for file := range t.fileMap { + m[file] = obj + } +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclntab_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclntab_test.go new file mode 100644 index 00000000..4bd3b097 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/pclntab_test.go @@ -0,0 +1,287 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 gosym + +import ( + "debug/elf" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" +) + +var ( + pclineTempDir string + pclinetestBinary string +) + +func dotest(self bool) bool { + // For now, only works on amd64 platforms. + if runtime.GOARCH != "amd64" { + return false + } + // Self test reads test binary; only works on Linux. + if self && runtime.GOOS != "linux" { + return false + } + // Command below expects "sh", so Unix. + if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { + return false + } + if pclinetestBinary != "" { + return true + } + var err error + pclineTempDir, err = ioutil.TempDir("", "pclinetest") + if err != nil { + panic(err) + } + if strings.Contains(pclineTempDir, " ") { + panic("unexpected space in tempdir") + } + // This command builds pclinetest from pclinetest.asm; + // the resulting binary looks like it was built from pclinetest.s, + // but we have renamed it to keep it away from the go tool. + pclinetestBinary = filepath.Join(pclineTempDir, "pclinetest") + command := fmt.Sprintf("go tool 6a -o %s.6 pclinetest.asm && go tool 6l -H linux -E main -o %s %s.6", + pclinetestBinary, pclinetestBinary, pclinetestBinary) + cmd := exec.Command("sh", "-c", command) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + panic(err) + } + return true +} + +func endtest() { + if pclineTempDir != "" { + os.RemoveAll(pclineTempDir) + pclineTempDir = "" + pclinetestBinary = "" + } +} + +func getTable(t *testing.T) *Table { + f, tab := crack(os.Args[0], t) + f.Close() + return tab +} + +func crack(file string, t *testing.T) (*elf.File, *Table) { + // Open self + f, err := elf.Open(file) + if err != nil { + t.Fatal(err) + } + return parse(file, f, t) +} + +func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) { + symdat, err := f.Section(".gosymtab").Data() + if err != nil { + f.Close() + t.Fatalf("reading %s gosymtab: %v", file, err) + } + pclndat, err := f.Section(".gopclntab").Data() + if err != nil { + f.Close() + t.Fatalf("reading %s gopclntab: %v", file, err) + } + + pcln := NewLineTable(pclndat, f.Section(".text").Addr) + tab, err := NewTable(symdat, pcln) + if err != nil { + f.Close() + t.Fatalf("parsing %s gosymtab: %v", file, err) + } + + return f, tab +} + +var goarch = os.Getenv("O") + +func TestLineFromAline(t *testing.T) { + t.Skip("wants to use go tool 6a which hasn't existed for who knows how long") + if !dotest(true) { + return + } + defer endtest() + + tab := getTable(t) + if tab.go12line != nil { + // aline's don't exist in the Go 1.2 table. + t.Skip("not relevant to Go 1.2 symbol table") + } + + // Find the sym package + pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj + if pkg == nil { + t.Fatalf("nil pkg") + } + + // Walk every absolute line and ensure that we hit every + // source line monotonically + lastline := make(map[string]int) + final := -1 + for i := 0; i < 10000; i++ { + path, line := pkg.lineFromAline(i) + // Check for end of object + if path == "" { + if final == -1 { + final = i - 1 + } + continue + } else if final != -1 { + t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line) + } + // It's okay to see files multiple times (e.g., sys.a) + if line == 1 { + lastline[path] = 1 + continue + } + // Check that the is the next line in path + ll, ok := lastline[path] + if !ok { + t.Errorf("file %s starts on line %d", path, line) + } else if line != ll+1 { + t.Fatalf("expected next line of file %s to be %d, got %d", path, ll+1, line) + } + lastline[path] = line + } + if final == -1 { + t.Errorf("never reached end of object") + } +} + +func TestLineAline(t *testing.T) { + t.Skip("wants to use go tool 6a which hasn't existed for who knows how long") + if !dotest(true) { + return + } + defer endtest() + + tab := getTable(t) + if tab.go12line != nil { + // aline's don't exist in the Go 1.2 table. + t.Skip("not relevant to Go 1.2 symbol table") + } + + for _, o := range tab.Files { + // A source file can appear multiple times in a + // object. alineFromLine will always return alines in + // the first file, so track which lines we've seen. + found := make(map[string]int) + for i := 0; i < 1000; i++ { + path, line := o.lineFromAline(i) + if path == "" { + break + } + + // cgo files are full of 'Z' symbols, which we don't handle + if len(path) > 4 && path[len(path)-4:] == ".cgo" { + continue + } + + if minline, ok := found[path]; path != "" && ok { + if minline >= line { + // We've already covered this file + continue + } + } + found[path] = line + + a, err := o.alineFromLine(path, line) + if err != nil { + t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err) + } else if a != i { + t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a) + } + } + } +} + +func TestPCLine(t *testing.T) { + t.Skip("wants to use go tool 6a which hasn't existed for who knows how long") + if !dotest(false) { + return + } + defer endtest() + + f, tab := crack(pclinetestBinary, t) + text := f.Section(".text") + textdat, err := text.Data() + if err != nil { + t.Fatalf("reading .text: %v", err) + } + + // Test PCToLine + sym := tab.LookupFunc("linefrompc") + wantLine := 0 + for pc := sym.Entry; pc < sym.End; pc++ { + off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g + if textdat[off] == 255 { + break + } + wantLine += int(textdat[off]) + t.Logf("off is %d %#x (max %d)", off, textdat[off], sym.End-pc) + file, line, fn := tab.PCToLine(pc) + if fn == nil { + t.Errorf("failed to get line of PC %#x", pc) + } else if !strings.HasSuffix(file, "pclinetest.asm") || line != wantLine || fn != sym { + t.Errorf("PCToLine(%#x) = %s:%d (%s), want %s:%d (%s)", pc, file, line, fn.Name, "pclinetest.asm", wantLine, sym.Name) + } + } + + // Test LineToPC + sym = tab.LookupFunc("pcfromline") + lookupline := -1 + wantLine = 0 + off := uint64(0) // TODO(rsc): should not need off; bug in 8g + for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) { + file, line, fn := tab.PCToLine(pc) + off = pc - text.Addr + if textdat[off] == 255 { + break + } + wantLine += int(textdat[off]) + if line != wantLine { + t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line) + off = pc + 1 - text.Addr + continue + } + if lookupline == -1 { + lookupline = line + } + for ; lookupline <= line; lookupline++ { + pc2, fn2, err := tab.LineToPC(file, lookupline) + if lookupline != line { + // Should be nothing on this line + if err == nil { + t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name) + } + } else if err != nil { + t.Errorf("failed to get PC of line %d: %s", lookupline, err) + } else if pc != pc2 { + t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name) + } + } + off = pc + 1 - text.Addr + } +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/symtab.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/symtab.go new file mode 100644 index 00000000..2c83b841 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/gosym/symtab.go @@ -0,0 +1,731 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 gosym implements access to the Go symbol +// and line number tables embedded in Go binaries generated +// by the gc compilers. +package gosym + +// The table format is a variant of the format used in Plan 9's a.out +// format, documented at http://plan9.bell-labs.com/magic/man2html/6/a.out. +// The best reference for the differences between the Plan 9 format +// and the Go format is the runtime source, specifically ../../runtime/symtab.c. + +import ( + "bytes" + "encoding/binary" + "fmt" + "strconv" + "strings" +) + +/* + * Symbols + */ + +// A Sym represents a single symbol table entry. +type Sym struct { + Value uint64 + Type byte + Name string + GoType uint64 + // If this symbol if a function symbol, the corresponding Func + Func *Func +} + +// Static reports whether this symbol is static (not visible outside its file). +func (s *Sym) Static() bool { return s.Type >= 'a' } + +// PackageName returns the package part of the symbol name, +// or the empty string if there is none. +func (s *Sym) PackageName() string { + if i := strings.Index(s.Name, "."); i != -1 { + return s.Name[0:i] + } + return "" +} + +// ReceiverName returns the receiver type name of this symbol, +// or the empty string if there is none. +func (s *Sym) ReceiverName() string { + l := strings.Index(s.Name, ".") + r := strings.LastIndex(s.Name, ".") + if l == -1 || r == -1 || l == r { + return "" + } + return s.Name[l+1 : r] +} + +// BaseName returns the symbol name without the package or receiver name. +func (s *Sym) BaseName() string { + if i := strings.LastIndex(s.Name, "."); i != -1 { + return s.Name[i+1:] + } + return s.Name +} + +// A Func collects information about a single function. +type Func struct { + Entry uint64 + *Sym + End uint64 + Params []*Sym + Locals []*Sym + FrameSize int + LineTable *LineTable + Obj *Obj +} + +// An Obj represents a collection of functions in a symbol table. +// +// The exact method of division of a binary into separate Objs is an internal detail +// of the symbol table format. +// +// In early versions of Go each source file became a different Obj. +// +// In Go 1 and Go 1.1, each package produced one Obj for all Go sources +// and one Obj per C source file. +// +// In Go 1.2, there is a single Obj for the entire program. +type Obj struct { + // Funcs is a list of functions in the Obj. + Funcs []Func + + // In Go 1.1 and earlier, Paths is a list of symbols corresponding + // to the source file names that produced the Obj. + // In Go 1.2, Paths is nil. + // Use the keys of Table.Files to obtain a list of source files. + Paths []Sym // meta +} + +/* + * Symbol tables + */ + +// Table represents a Go symbol table. It stores all of the +// symbols decoded from the program and provides methods to translate +// between symbols, names, and addresses. +type Table struct { + Syms []Sym + Funcs []Func + Files map[string]*Obj // nil for Go 1.2 and later binaries + Objs []Obj // nil for Go 1.2 and later binaries + + go12line *LineTable // Go 1.2 line number table +} + +type sym struct { + value uint64 + gotype uint64 + typ byte + name []byte +} + +var ( + littleEndianSymtab = []byte{0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00} + bigEndianSymtab = []byte{0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00} + oldLittleEndianSymtab = []byte{0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00} +) + +func walksymtab(data []byte, fn func(sym) error) error { + if len(data) == 0 { // missing symtab is okay + return nil + } + var order binary.ByteOrder = binary.BigEndian + newTable := false + switch { + case bytes.HasPrefix(data, oldLittleEndianSymtab): + // Same as Go 1.0, but little endian. + // Format was used during interim development between Go 1.0 and Go 1.1. + // Should not be widespread, but easy to support. + data = data[6:] + order = binary.LittleEndian + case bytes.HasPrefix(data, bigEndianSymtab): + newTable = true + case bytes.HasPrefix(data, littleEndianSymtab): + newTable = true + order = binary.LittleEndian + } + var ptrsz int + if newTable { + if len(data) < 8 { + return &DecodingError{len(data), "unexpected EOF", nil} + } + ptrsz = int(data[7]) + if ptrsz != 4 && ptrsz != 8 { + return &DecodingError{7, "invalid pointer size", ptrsz} + } + data = data[8:] + } + var s sym + p := data + for len(p) >= 4 { + var typ byte + if newTable { + // Symbol type, value, Go type. + typ = p[0] & 0x3F + wideValue := p[0]&0x40 != 0 + goType := p[0]&0x80 != 0 + if typ < 26 { + typ += 'A' + } else { + typ += 'a' - 26 + } + s.typ = typ + p = p[1:] + if wideValue { + if len(p) < ptrsz { + return &DecodingError{len(data), "unexpected EOF", nil} + } + // fixed-width value + if ptrsz == 8 { + s.value = order.Uint64(p[0:8]) + p = p[8:] + } else { + s.value = uint64(order.Uint32(p[0:4])) + p = p[4:] + } + } else { + // varint value + s.value = 0 + shift := uint(0) + for len(p) > 0 && p[0]&0x80 != 0 { + s.value |= uint64(p[0]&0x7F) << shift + shift += 7 + p = p[1:] + } + if len(p) == 0 { + return &DecodingError{len(data), "unexpected EOF", nil} + } + s.value |= uint64(p[0]) << shift + p = p[1:] + } + if goType { + if len(p) < ptrsz { + return &DecodingError{len(data), "unexpected EOF", nil} + } + // fixed-width go type + if ptrsz == 8 { + s.gotype = order.Uint64(p[0:8]) + p = p[8:] + } else { + s.gotype = uint64(order.Uint32(p[0:4])) + p = p[4:] + } + } + } else { + // Value, symbol type. + s.value = uint64(order.Uint32(p[0:4])) + if len(p) < 5 { + return &DecodingError{len(data), "unexpected EOF", nil} + } + typ = p[4] + if typ&0x80 == 0 { + return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ} + } + typ &^= 0x80 + s.typ = typ + p = p[5:] + } + + // Name. + var i int + var nnul int + for i = 0; i < len(p); i++ { + if p[i] == 0 { + nnul = 1 + break + } + } + switch typ { + case 'z', 'Z': + p = p[i+nnul:] + for i = 0; i+2 <= len(p); i += 2 { + if p[i] == 0 && p[i+1] == 0 { + nnul = 2 + break + } + } + } + if len(p) < i+nnul { + return &DecodingError{len(data), "unexpected EOF", nil} + } + s.name = p[0:i] + i += nnul + p = p[i:] + + if !newTable { + if len(p) < 4 { + return &DecodingError{len(data), "unexpected EOF", nil} + } + // Go type. + s.gotype = uint64(order.Uint32(p[:4])) + p = p[4:] + } + fn(s) + } + return nil +} + +// NewTable decodes the Go symbol table in data, +// returning an in-memory representation. +func NewTable(symtab []byte, pcln *LineTable) (*Table, error) { + var n int + err := walksymtab(symtab, func(s sym) error { + n++ + return nil + }) + if err != nil { + return nil, err + } + + var t Table + if pcln.isGo12() { + t.go12line = pcln + } + fname := make(map[uint16]string) + t.Syms = make([]Sym, 0, n) + nf := 0 + nz := 0 + lasttyp := uint8(0) + err = walksymtab(symtab, func(s sym) error { + n := len(t.Syms) + t.Syms = t.Syms[0 : n+1] + ts := &t.Syms[n] + ts.Type = s.typ + ts.Value = uint64(s.value) + ts.GoType = uint64(s.gotype) + switch s.typ { + default: + // rewrite name to use . instead of · (c2 b7) + w := 0 + b := s.name + for i := 0; i < len(b); i++ { + if b[i] == 0xc2 && i+1 < len(b) && b[i+1] == 0xb7 { + i++ + b[i] = '.' + } + b[w] = b[i] + w++ + } + ts.Name = string(s.name[0:w]) + case 'z', 'Z': + if lasttyp != 'z' && lasttyp != 'Z' { + nz++ + } + for i := 0; i < len(s.name); i += 2 { + eltIdx := binary.BigEndian.Uint16(s.name[i : i+2]) + elt, ok := fname[eltIdx] + if !ok { + return &DecodingError{-1, "bad filename code", eltIdx} + } + if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' { + ts.Name += "/" + } + ts.Name += elt + } + } + switch s.typ { + case 'T', 't', 'L', 'l': + nf++ + case 'f': + fname[uint16(s.value)] = ts.Name + } + lasttyp = s.typ + return nil + }) + if err != nil { + return nil, err + } + + t.Funcs = make([]Func, 0, nf) + t.Files = make(map[string]*Obj) + + var obj *Obj + if t.go12line != nil { + // Put all functions into one Obj. + t.Objs = make([]Obj, 1) + obj = &t.Objs[0] + t.go12line.go12MapFiles(t.Files, obj) + } else { + t.Objs = make([]Obj, 0, nz) + } + + // Count text symbols and attach frame sizes, parameters, and + // locals to them. Also, find object file boundaries. + lastf := 0 + for i := 0; i < len(t.Syms); i++ { + sym := &t.Syms[i] + switch sym.Type { + case 'Z', 'z': // path symbol + if t.go12line != nil { + // Go 1.2 binaries have the file information elsewhere. Ignore. + break + } + // Finish the current object + if obj != nil { + obj.Funcs = t.Funcs[lastf:] + } + lastf = len(t.Funcs) + + // Start new object + n := len(t.Objs) + t.Objs = t.Objs[0 : n+1] + obj = &t.Objs[n] + + // Count & copy path symbols + var end int + for end = i + 1; end < len(t.Syms); end++ { + if c := t.Syms[end].Type; c != 'Z' && c != 'z' { + break + } + } + obj.Paths = t.Syms[i:end] + i = end - 1 // loop will i++ + + // Record file names + depth := 0 + for j := range obj.Paths { + s := &obj.Paths[j] + if s.Name == "" { + depth-- + } else { + if depth == 0 { + t.Files[s.Name] = obj + } + depth++ + } + } + + case 'T', 't', 'L', 'l': // text symbol + if n := len(t.Funcs); n > 0 { + t.Funcs[n-1].End = sym.Value + } + if sym.Name == "etext" { + continue + } + + // Count parameter and local (auto) syms + var np, na int + var end int + countloop: + for end = i + 1; end < len(t.Syms); end++ { + switch t.Syms[end].Type { + case 'T', 't', 'L', 'l', 'Z', 'z': + break countloop + case 'p': + np++ + case 'a': + na++ + } + } + + // Fill in the function symbol + n := len(t.Funcs) + t.Funcs = t.Funcs[0 : n+1] + fn := &t.Funcs[n] + sym.Func = fn + fn.Params = make([]*Sym, 0, np) + fn.Locals = make([]*Sym, 0, na) + fn.Sym = sym + fn.Entry = sym.Value + fn.Obj = obj + if t.go12line != nil { + // All functions share the same line table. + // It knows how to narrow down to a specific + // function quickly. + fn.LineTable = t.go12line + } else if pcln != nil { + fn.LineTable = pcln.slice(fn.Entry) + pcln = fn.LineTable + } + for j := i; j < end; j++ { + s := &t.Syms[j] + switch s.Type { + case 'm': + fn.FrameSize = int(s.Value) + case 'p': + n := len(fn.Params) + fn.Params = fn.Params[0 : n+1] + fn.Params[n] = s + case 'a': + n := len(fn.Locals) + fn.Locals = fn.Locals[0 : n+1] + fn.Locals[n] = s + } + } + i = end - 1 // loop will i++ + } + } + + if t.go12line != nil && nf == 0 { + t.Funcs = t.go12line.go12Funcs() + } + if obj != nil { + obj.Funcs = t.Funcs[lastf:] + } + return &t, nil +} + +// PCToFunc returns the function containing the program counter pc, +// or nil if there is no such function. +func (t *Table) PCToFunc(pc uint64) *Func { + funcs := t.Funcs + for len(funcs) > 0 { + m := len(funcs) / 2 + fn := &funcs[m] + switch { + case pc < fn.Entry: + funcs = funcs[0:m] + case fn.Entry <= pc && pc < fn.End: + return fn + default: + funcs = funcs[m+1:] + } + } + return nil +} + +// PCToLine looks up line number information for a program counter. +// If there is no information, it returns fn == nil. +func (t *Table) PCToLine(pc uint64) (file string, line int, fn *Func) { + if fn = t.PCToFunc(pc); fn == nil { + return + } + if t.go12line != nil { + file = t.go12line.go12PCToFile(pc) + line = t.go12line.go12PCToLine(pc) + } else { + file, line = fn.Obj.lineFromAline(fn.LineTable.PCToLine(pc)) + } + return +} + +// PCToSPAdj returns the stack pointer adjustment for a program counter. +func (t *Table) PCToSPAdj(pc uint64) (spadj int) { + if fn := t.PCToFunc(pc); fn == nil { + return 0 + } + if t.go12line != nil { + return t.go12line.go12PCToSPAdj(pc) + } + return 0 +} + +// LineToPC looks up the first program counter on the given line in +// the named file. It returns UnknownPathError or UnknownLineError if +// there is an error looking up this line. +func (t *Table) LineToPC(file string, line int) (pc uint64, fn *Func, err error) { + obj, ok := t.Files[file] + if !ok { + return 0, nil, UnknownFileError(file) + } + + if t.go12line != nil { + pc := t.go12line.go12LineToPC(file, line) + if pc == 0 { + return 0, nil, &UnknownLineError{file, line} + } + return pc, t.PCToFunc(pc), nil + } + + abs, err := obj.alineFromLine(file, line) + if err != nil { + return + } + for i := range obj.Funcs { + f := &obj.Funcs[i] + pc := f.LineTable.LineToPC(abs, f.End) + if pc != 0 { + return pc, f, nil + } + } + return 0, nil, &UnknownLineError{file, line} +} + +// LookupSym returns the text, data, or bss symbol with the given name, +// or nil if no such symbol is found. +func (t *Table) LookupSym(name string) *Sym { + // TODO(austin) Maybe make a map + for i := range t.Syms { + s := &t.Syms[i] + switch s.Type { + case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b': + if s.Name == name { + return s + } + } + } + return nil +} + +// LookupFunc returns the text, data, or bss symbol with the given name, +// or nil if no such symbol is found. +func (t *Table) LookupFunc(name string) *Func { + for i := range t.Funcs { + f := &t.Funcs[i] + if f.Sym.Name == name { + return f + } + } + return nil +} + +// SymByAddr returns the text, data, or bss symbol starting at the given address. +func (t *Table) SymByAddr(addr uint64) *Sym { + for i := range t.Syms { + s := &t.Syms[i] + switch s.Type { + case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b': + if s.Value == addr { + return s + } + } + } + return nil +} + +/* + * Object files + */ + +// This is legacy code for Go 1.1 and earlier, which used the +// Plan 9 format for pc-line tables. This code was never quite +// correct. It's probably very close, and it's usually correct, but +// we never quite found all the corner cases. +// +// Go 1.2 and later use a simpler format, documented at golang.org/s/go12symtab. + +func (o *Obj) lineFromAline(aline int) (string, int) { + type stackEnt struct { + path string + start int + offset int + prev *stackEnt + } + + noPath := &stackEnt{"", 0, 0, nil} + tos := noPath + +pathloop: + for _, s := range o.Paths { + val := int(s.Value) + switch { + case val > aline: + break pathloop + + case val == 1: + // Start a new stack + tos = &stackEnt{s.Name, val, 0, noPath} + + case s.Name == "": + // Pop + if tos == noPath { + return "", 0 + } + tos.prev.offset += val - tos.start + tos = tos.prev + + default: + // Push + tos = &stackEnt{s.Name, val, 0, tos} + } + } + + if tos == noPath { + return "", 0 + } + return tos.path, aline - tos.start - tos.offset + 1 +} + +func (o *Obj) alineFromLine(path string, line int) (int, error) { + if line < 1 { + return 0, &UnknownLineError{path, line} + } + + for i, s := range o.Paths { + // Find this path + if s.Name != path { + continue + } + + // Find this line at this stack level + depth := 0 + var incstart int + line += int(s.Value) + pathloop: + for _, s := range o.Paths[i:] { + val := int(s.Value) + switch { + case depth == 1 && val >= line: + return line - 1, nil + + case s.Name == "": + depth-- + if depth == 0 { + break pathloop + } else if depth == 1 { + line += val - incstart + } + + default: + if depth == 1 { + incstart = val + } + depth++ + } + } + return 0, &UnknownLineError{path, line} + } + return 0, UnknownFileError(path) +} + +/* + * Errors + */ + +// UnknownFileError represents a failure to find the specific file in +// the symbol table. +type UnknownFileError string + +func (e UnknownFileError) Error() string { return "unknown file: " + string(e) } + +// UnknownLineError represents a failure to map a line to a program +// counter, either because the line is beyond the bounds of the file +// or because there is no code on the given line. +type UnknownLineError struct { + File string + Line int +} + +func (e *UnknownLineError) Error() string { + return "no code at " + e.File + ":" + strconv.Itoa(e.Line) +} + +// DecodingError represents an error during the decoding of +// the symbol table. +type DecodingError struct { + off int + msg string + val interface{} +} + +func (e *DecodingError) Error() string { + msg := e.msg + if e.val != nil { + msg += fmt.Sprintf(" '%v'", e.val) + } + msg += fmt.Sprintf(" at byte %#x", e.off) + return msg +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/local/local.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/local/local.go new file mode 100644 index 00000000..b75004bf --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/local/local.go @@ -0,0 +1,205 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// +build linux + +// Package local provides access to a local program. +package local + +import ( + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/protocol" +) + +var _ debug.Program = (*Program)(nil) +var _ debug.File = (*File)(nil) + +// Program implements the debug.Program interface. +// Through that interface it provides access to a program being debugged. +type Program struct { + s *server.Server +} + +// New creates a new program from the specified file. +// The program can then be started by the Run method. +func New(textFile string) (*Program, error) { + s, err := server.New(textFile) + return &Program{s: s}, err +} + +func (p *Program) Open(name string, mode string) (debug.File, error) { + req := protocol.OpenRequest{ + Name: name, + Mode: mode, + } + var resp protocol.OpenResponse + err := p.s.Open(&req, &resp) + if err != nil { + return nil, err + } + f := &File{ + prog: p, + fd: resp.FD, + } + return f, nil +} + +func (p *Program) Run(args ...string) (debug.Status, error) { + req := protocol.RunRequest{args} + var resp protocol.RunResponse + err := p.s.Run(&req, &resp) + if err != nil { + return debug.Status{}, err + } + return resp.Status, nil +} + +func (p *Program) Stop() (debug.Status, error) { + panic("unimplemented") +} + +func (p *Program) Resume() (debug.Status, error) { + req := protocol.ResumeRequest{} + var resp protocol.ResumeResponse + err := p.s.Resume(&req, &resp) + if err != nil { + return debug.Status{}, err + } + return resp.Status, nil +} + +func (p *Program) Kill() (debug.Status, error) { + panic("unimplemented") +} + +func (p *Program) Breakpoint(address uint64) ([]uint64, error) { + req := protocol.BreakpointRequest{ + Address: address, + } + var resp protocol.BreakpointResponse + err := p.s.Breakpoint(&req, &resp) + return resp.PCs, err +} + +func (p *Program) BreakpointAtFunction(name string) ([]uint64, error) { + req := protocol.BreakpointAtFunctionRequest{ + Function: name, + } + var resp protocol.BreakpointResponse + err := p.s.BreakpointAtFunction(&req, &resp) + return resp.PCs, err +} + +func (p *Program) BreakpointAtLine(file string, line uint64) ([]uint64, error) { + req := protocol.BreakpointAtLineRequest{ + File: file, + Line: line, + } + var resp protocol.BreakpointResponse + err := p.s.BreakpointAtLine(&req, &resp) + return resp.PCs, err +} + +func (p *Program) DeleteBreakpoints(pcs []uint64) error { + req := protocol.DeleteBreakpointsRequest{PCs: pcs} + var resp protocol.DeleteBreakpointsResponse + return p.s.DeleteBreakpoints(&req, &resp) +} + +func (p *Program) Eval(expr string) ([]string, error) { + req := protocol.EvalRequest{ + Expr: expr, + } + var resp protocol.EvalResponse + err := p.s.Eval(&req, &resp) + return resp.Result, err +} + +func (p *Program) Evaluate(e string) (debug.Value, error) { + req := protocol.EvaluateRequest{ + Expression: e, + } + var resp protocol.EvaluateResponse + err := p.s.Evaluate(&req, &resp) + return resp.Result, err +} + +func (p *Program) Frames(count int) ([]debug.Frame, error) { + req := protocol.FramesRequest{ + Count: count, + } + var resp protocol.FramesResponse + err := p.s.Frames(&req, &resp) + return resp.Frames, err +} + +func (p *Program) Goroutines() ([]*debug.Goroutine, error) { + req := protocol.GoroutinesRequest{} + var resp protocol.GoroutinesResponse + err := p.s.Goroutines(&req, &resp) + return resp.Goroutines, err +} + +func (p *Program) VarByName(name string) (debug.Var, error) { + req := protocol.VarByNameRequest{Name: name} + var resp protocol.VarByNameResponse + err := p.s.VarByName(&req, &resp) + return resp.Var, err +} + +func (p *Program) Value(v debug.Var) (debug.Value, error) { + req := protocol.ValueRequest{Var: v} + var resp protocol.ValueResponse + err := p.s.Value(&req, &resp) + return resp.Value, err +} + +func (p *Program) MapElement(m debug.Map, index uint64) (debug.Var, debug.Var, error) { + req := protocol.MapElementRequest{Map: m, Index: index} + var resp protocol.MapElementResponse + err := p.s.MapElement(&req, &resp) + return resp.Key, resp.Value, err +} + +// File implements the debug.File interface, providing access +// to file-like resources associated with the target program. +type File struct { + prog *Program // The Program associated with the file. + fd int // File descriptor. +} + +func (f *File) ReadAt(p []byte, offset int64) (int, error) { + req := protocol.ReadAtRequest{ + FD: f.fd, + Len: len(p), + Offset: offset, + } + var resp protocol.ReadAtResponse + err := f.prog.s.ReadAt(&req, &resp) + return copy(p, resp.Data), err +} + +func (f *File) WriteAt(p []byte, offset int64) (int, error) { + panic("unimplemented") +} + +func (f *File) Close() error { + req := protocol.CloseRequest{ + FD: f.fd, + } + var resp protocol.CloseResponse + err := f.prog.s.Close(&req, &resp) + return err +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/program.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/program.go new file mode 100644 index 00000000..8cbf53db --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/program.go @@ -0,0 +1,327 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 debug provides the portable interface to a program being debugged. +package debug + +import ( + "fmt" + "io" + "strings" +) + +// Program is the interface to a (possibly remote) program being debugged. +// The process (if any) and text file associated with it may change during +// the session, but many resources are associated with the Program rather +// than process or text file so they persist across debuggging runs. +type Program interface { + // Open opens a virtual file associated with the process. + // Names are things like "text", "mem", "fd/2". + // Mode is one of "r", "w", "rw". + // Return values are open File and error. + // When the target binary is re-run, open files are + // automatically updated to refer to the corresponding + // file in the new process. + Open(name string, mode string) (File, error) + + // Run abandons the current running process, if any, + // and execs a new instance of the target binary file + // (which may have changed underfoot). + // Breakpoints and open files are re-established. + // The call hangs until the program stops executing, + // at which point it returns the program status. + // args contains the command-line arguments for the process. + Run(args ...string) (Status, error) + + // Stop stops execution of the current process but + // does not kill it. + Stop() (Status, error) + + // Resume resumes execution of a stopped process. + // The call hangs until the program stops executing, + // at which point it returns the program status. + Resume() (Status, error) + + // TODO: Step(). Where does the granularity happen, + // on the proxy end or the debugging control end? + + // Kill kills the current process. + Kill() (Status, error) + + // Breakpoint sets a breakpoint at the specified address. + Breakpoint(address uint64) (PCs []uint64, err error) + + // BreakpointAtFunction sets a breakpoint at the start of the specified function. + BreakpointAtFunction(name string) (PCs []uint64, err error) + + // BreakpointAtLine sets a breakpoint at the specified source line. + BreakpointAtLine(file string, line uint64) (PCs []uint64, err error) + + // DeleteBreakpoints removes the breakpoints at the specified addresses. + // Addresses where no breakpoint is set are ignored. + DeleteBreakpoints(pcs []uint64) error + + // Eval evaluates the expression (typically an address) and returns + // its string representation(s). Multivalued expressions such as + // matches for regular expressions return multiple values. + // TODO: change this to multiple functions with more specific names. + // Syntax: + // re:regexp + // Returns a list of symbol names that match the expression + // addr:symbol + // Returns a one-element list holding the hexadecimal + // ("0x1234") value of the address of the symbol + // val:symbol + // Returns a one-element list holding the formatted + // value of the symbol + // 0x1234, 01234, 467 + // Returns a one-element list holding the name of the + // symbol ("main.foo") at that address (hex, octal, decimal). + Eval(expr string) ([]string, error) + + // Evaluate evaluates an expression. Accepts a subset of Go expression syntax: + // basic literals, identifiers, parenthesized expressions, and most operators. + // Only the len function call is available. + // + // The expression can refer to local variables and function parameters of the + // function where the program is stopped. + // + // On success, the type of the value returned will be one of: + // int8, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64, + // complex64, complex128, bool, Pointer, Array, Slice, String, Map, Struct, + // Channel, Func, or Interface. + Evaluate(e string) (Value, error) + + // Frames returns up to count stack frames from where the program + // is currently stopped. + Frames(count int) ([]Frame, error) + + // VarByName returns a Var referring to a global variable with the given name. + // TODO: local variables + VarByName(name string) (Var, error) + + // Value gets the value of a variable by reading the program's memory. + Value(v Var) (Value, error) + + // MapElement returns Vars for the key and value of a map element specified by + // a 0-based index. + MapElement(m Map, index uint64) (Var, Var, error) + + // Goroutines gets the current goroutines. + Goroutines() ([]*Goroutine, error) +} + +type Goroutine struct { + ID int64 + Status GoroutineStatus + StatusString string // A human-readable string explaining the status in more detail. + Function string // Name of the goroutine function. + Caller string // Name of the function that created this goroutine. + StackFrames []Frame +} + +type GoroutineStatus byte + +const ( + Running GoroutineStatus = iota + Queued + Blocked +) + +func (g GoroutineStatus) String() string { + switch g { + case Running: + return "running" + case Queued: + return "queued" + case Blocked: + return "blocked" + } + return "invalid status" +} + +func (g *Goroutine) String() string { + return fmt.Sprintf("goroutine %d [%s] %s -> %s", g.ID, g.StatusString, g.Caller, g.Function) +} + +// A reference to a variable in a program. +// TODO: handle variables stored in registers +type Var struct { + TypeID uint64 // A type identifier, opaque to the user. + Address uint64 // The address of the variable. +} + +// A value read from a remote program. +type Value interface{} + +// Pointer is a Value representing a pointer. +// Note that the TypeID field will be the type of the variable being pointed to, +// not the type of this pointer. +type Pointer struct { + TypeID uint64 // A type identifier, opaque to the user. + Address uint64 // The address of the variable. +} + +// Array is a Value representing an array. +type Array struct { + ElementTypeID uint64 + Address uint64 + Length uint64 // Number of elements in the array + StrideBits uint64 // Number of bits between array entries +} + +// Len returns the number of elements in the array. +func (a Array) Len() uint64 { + return a.Length +} + +// Element returns a Var referring to the given element of the array. +func (a Array) Element(index uint64) Var { + return Var{ + TypeID: a.ElementTypeID, + Address: a.Address + index*(a.StrideBits/8), + } +} + +// Slice is a Value representing a slice. +type Slice struct { + Array + Capacity uint64 +} + +// String is a Value representing a string. +// TODO: a method to access more of a truncated string. +type String struct { + // Length contains the length of the remote string, in bytes. + Length uint64 + // String contains the string itself; it may be truncated to fewer bytes than the value of the Length field. + String string +} + +// Map is a Value representing a map. +type Map struct { + TypeID uint64 + Address uint64 + Length uint64 // Number of elements in the map. +} + +// Struct is a Value representing a struct. +type Struct struct { + Fields []StructField +} + +// StructField represents a field in a struct object. +type StructField struct { + Name string + Var Var +} + +// Channel is a Value representing a channel. +type Channel struct { + ElementTypeID uint64 + Address uint64 // Location of the channel struct in memory. + Buffer uint64 // Location of the buffer; zero for nil channels. + Length uint64 // Number of elements stored in the channel buffer. + Capacity uint64 // Capacity of the buffer; zero for unbuffered channels. + Stride uint64 // Number of bytes between buffer entries. + BufferStart uint64 // Index in the buffer of the element at the head of the queue. +} + +// Element returns a Var referring to the given element of the channel's queue. +// If the channel is unbuffered, nil, or if the index is too large, returns a Var with Address == 0. +func (m Channel) Element(index uint64) Var { + if index >= m.Length { + return Var{ + TypeID: m.ElementTypeID, + Address: 0, + } + } + if index < m.Capacity-m.BufferStart { + // The element is in the part of the queue that occurs later in the buffer + // than the head of the queue. + return Var{ + TypeID: m.ElementTypeID, + Address: m.Buffer + (m.BufferStart+index)*m.Stride, + } + } + // The element is in the part of the queue that has wrapped around to the + // start of the buffer. + return Var{ + TypeID: m.ElementTypeID, + Address: m.Buffer + (m.BufferStart+index-m.Capacity)*m.Stride, + } +} + +// Func is a Value representing a func. +type Func struct { + Address uint64 +} + +// Interface is a Value representing an interface. +type Interface struct{} + +// The File interface provides access to file-like resources in the program. +// It implements only ReaderAt and WriterAt, not Reader and Writer, because +// random access is a far more common pattern for things like symbol tables, +// and because enormous address space of virtual memory makes routines +// like io.Copy dangerous. +type File interface { + io.ReaderAt + io.WriterAt + io.Closer +} + +type Status struct { + PC, SP uint64 +} + +type Frame struct { + // PC is the hardware program counter. + PC uint64 + // SP is the hardware stack pointer. + SP uint64 + // File and Line are the source code location of the PC. + File string + Line uint64 + // Function is the name of this frame's function. + Function string + // FunctionStart is the starting PC of the function. + FunctionStart uint64 + // Params contains the function's parameters. + Params []Param + // Vars contains the function's local variables. + Vars []LocalVar +} + +func (f Frame) String() string { + params := make([]string, len(f.Params)) + for i, p := range f.Params { + params[i] = p.Name // TODO: more information + } + p := strings.Join(params, ", ") + off := f.PC - f.FunctionStart + return fmt.Sprintf("%s(%s)\n\t%s:%d +0x%x", f.Function, p, f.File, f.Line, off) +} + +// Param is a parameter of a function. +type Param struct { + Name string + Var Var +} + +// LocalVar is a local variable of a function. +type LocalVar struct { + Name string + Var Var +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/remote/remote.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/remote/remote.go new file mode 100644 index 00000000..0790623d --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/remote/remote.go @@ -0,0 +1,305 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 remote provides remote access to a debugproxy server. +package remote + +import ( + "fmt" + "io" + "net/rpc" + "os" + "os/exec" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/protocol" +) + +var _ debug.Program = (*Program)(nil) +var _ debug.File = (*File)(nil) + +// Program implements the debug.Program interface. +// Through that interface it provides access to a program being +// debugged on a possibly remote machine by communicating +// with a debugproxy adjacent to the target program. +type Program struct { + client *rpc.Client +} + +// DebugproxyCmd is the path to the debugproxy command. It is a variable in case +// the default value, "debugproxy", is not in the $PATH. +var DebugproxyCmd = "debugproxy" + +// New connects to the specified host using SSH, starts DebugproxyCmd +// there, and creates a new program from the specified file. +// The program can then be started by the Run method. +func New(host string, textFile string) (*Program, error) { + // TODO: add args. + cmdStrs := []string{"/usr/bin/ssh", host, DebugproxyCmd, "-text", textFile} + if host == "localhost" { + cmdStrs = cmdStrs[2:] + } + cmd := exec.Command(cmdStrs[0], cmdStrs[1:]...) + stdin, toStdin, err := os.Pipe() + if err != nil { + return nil, err + } + fromStdout, stdout, err := os.Pipe() + if err != nil { + return nil, err + } + cmd.Stdin = stdin + cmd.Stdout = stdout + cmd.Stderr = os.Stderr // Stderr from proxy appears on our stderr. + err = cmd.Start() + if err != nil { + return nil, err + } + stdout.Close() + if msg, err := readLine(fromStdout); err != nil { + return nil, err + } else if msg != "OK" { + // Communication error. + return nil, fmt.Errorf("unrecognized message %q", msg) + } + program := &Program{ + client: rpc.NewClient(&rwc{ + ssh: cmd, + r: fromStdout, + w: toStdin, + }), + } + return program, nil +} + +// readLine reads one line of text from the reader. It does no buffering. +// The trailing newline is read but not returned. +func readLine(r io.Reader) (string, error) { + b := make([]byte, 0, 10) + var c [1]byte + for { + _, err := io.ReadFull(r, c[:]) + if err != nil { + return "", err + } + if c[0] == '\n' { + break + } + b = append(b, c[0]) + } + return string(b), nil +} + +// rwc creates a single io.ReadWriteCloser from a read side and a write side. +// It also holds the command object so we can wait for SSH to complete. +// It allows us to do RPC over an SSH connection. +type rwc struct { + ssh *exec.Cmd + r *os.File + w *os.File +} + +func (rwc *rwc) Read(p []byte) (int, error) { + return rwc.r.Read(p) +} + +func (rwc *rwc) Write(p []byte) (int, error) { + return rwc.w.Write(p) +} + +func (rwc *rwc) Close() error { + rerr := rwc.r.Close() + werr := rwc.w.Close() + cerr := rwc.ssh.Wait() + if cerr != nil { + // Wait exit status is most important. + return cerr + } + if rerr != nil { + return rerr + } + return werr +} + +func (p *Program) Open(name string, mode string) (debug.File, error) { + req := protocol.OpenRequest{ + Name: name, + Mode: mode, + } + var resp protocol.OpenResponse + err := p.client.Call("Server.Open", &req, &resp) + if err != nil { + return nil, err + } + f := &File{ + prog: p, + fd: resp.FD, + } + return f, nil +} + +func (p *Program) Run(args ...string) (debug.Status, error) { + req := protocol.RunRequest{args} + var resp protocol.RunResponse + err := p.client.Call("Server.Run", &req, &resp) + if err != nil { + return debug.Status{}, err + } + return resp.Status, nil +} + +func (p *Program) Stop() (debug.Status, error) { + panic("unimplemented") +} + +func (p *Program) Resume() (debug.Status, error) { + req := protocol.ResumeRequest{} + var resp protocol.ResumeResponse + err := p.client.Call("Server.Resume", &req, &resp) + if err != nil { + return debug.Status{}, err + } + return resp.Status, nil +} + +func (p *Program) Kill() (debug.Status, error) { + panic("unimplemented") +} + +func (p *Program) Breakpoint(address uint64) ([]uint64, error) { + req := protocol.BreakpointRequest{ + Address: address, + } + var resp protocol.BreakpointResponse + err := p.client.Call("Server.Breakpoint", &req, &resp) + return resp.PCs, err +} + +func (p *Program) BreakpointAtFunction(name string) ([]uint64, error) { + req := protocol.BreakpointAtFunctionRequest{ + Function: name, + } + var resp protocol.BreakpointResponse + err := p.client.Call("Server.BreakpointAtFunction", &req, &resp) + return resp.PCs, err +} + +func (p *Program) BreakpointAtLine(file string, line uint64) ([]uint64, error) { + req := protocol.BreakpointAtLineRequest{ + File: file, + Line: line, + } + var resp protocol.BreakpointResponse + err := p.client.Call("Server.BreakpointAtLine", &req, &resp) + return resp.PCs, err +} + +func (p *Program) DeleteBreakpoints(pcs []uint64) error { + req := protocol.DeleteBreakpointsRequest{PCs: pcs} + var resp protocol.DeleteBreakpointsResponse + return p.client.Call("Server.DeleteBreakpoints", &req, &resp) +} + +func (p *Program) Eval(expr string) ([]string, error) { + req := protocol.EvalRequest{ + Expr: expr, + } + var resp protocol.EvalResponse + err := p.client.Call("Server.Eval", &req, &resp) + return resp.Result, err +} + +func (p *Program) Evaluate(e string) (debug.Value, error) { + req := protocol.EvaluateRequest{ + Expression: e, + } + var resp protocol.EvaluateResponse + err := p.client.Call("Server.Evaluate", &req, &resp) + return resp.Result, err +} + +func (p *Program) Frames(count int) ([]debug.Frame, error) { + req := protocol.FramesRequest{ + Count: count, + } + var resp protocol.FramesResponse + err := p.client.Call("Server.Frames", &req, &resp) + return resp.Frames, err +} + +func (p *Program) Goroutines() ([]*debug.Goroutine, error) { + req := protocol.GoroutinesRequest{} + var resp protocol.GoroutinesResponse + err := p.client.Call("Server.Goroutines", &req, &resp) + return resp.Goroutines, err +} + +func (p *Program) VarByName(name string) (debug.Var, error) { + req := protocol.VarByNameRequest{Name: name} + var resp protocol.VarByNameResponse + err := p.client.Call("Server.VarByName", &req, &resp) + return resp.Var, err +} + +func (p *Program) Value(v debug.Var) (debug.Value, error) { + req := protocol.ValueRequest{Var: v} + var resp protocol.ValueResponse + err := p.client.Call("Server.Value", &req, &resp) + return resp.Value, err +} + +func (p *Program) MapElement(m debug.Map, index uint64) (debug.Var, debug.Var, error) { + req := protocol.MapElementRequest{Map: m, Index: index} + var resp protocol.MapElementResponse + err := p.client.Call("Server.MapElement", &req, &resp) + return resp.Key, resp.Value, err +} + +// File implements the debug.File interface, providing access +// to file-like resources associated with the target program. +type File struct { + prog *Program // The Program associated with the file. + fd int // File descriptor. +} + +func (f *File) ReadAt(p []byte, offset int64) (int, error) { + req := protocol.ReadAtRequest{ + FD: f.fd, + Len: len(p), + Offset: offset, + } + var resp protocol.ReadAtResponse + err := f.prog.client.Call("Server.ReadAt", &req, &resp) + return copy(p, resp.Data), err +} + +func (f *File) WriteAt(p []byte, offset int64) (int, error) { + req := protocol.WriteAtRequest{ + FD: f.fd, + Data: p, + Offset: offset, + } + var resp protocol.WriteAtResponse + err := f.prog.client.Call("Server.WriteAt", &req, &resp) + return resp.Len, err +} + +func (f *File) Close() error { + req := protocol.CloseRequest{ + FD: f.fd, + } + var resp protocol.CloseResponse + err := f.prog.client.Call("Server.Close", &req, &resp) + return err +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/dwarf.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/dwarf.go new file mode 100644 index 00000000..c0ae9c10 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/dwarf.go @@ -0,0 +1,112 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// +build linux + +package server + +import ( + "errors" + "fmt" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" +) + +func (s *Server) functionStartAddress(name string) (uint64, error) { + entry, err := s.dwarfData.LookupFunction(name) + if err != nil { + return 0, err + } + addrAttr := entry.Val(dwarf.AttrLowpc) + if addrAttr == nil { + return 0, fmt.Errorf("symbol %q has no LowPC attribute", name) + } + addr, ok := addrAttr.(uint64) + if !ok { + return 0, fmt.Errorf("symbol %q has non-uint64 LowPC attribute", name) + } + return addr, nil +} + +// evalLocation parses a DWARF location description encoded in v. It works for +// cases where the variable is stored at an offset from the Canonical Frame +// Address. The return value is this offset. +// TODO: a more general location-description-parsing function. +func evalLocation(v []uint8) (int64, error) { + // Some DWARF constants. + const ( + opConsts = 0x11 + opPlus = 0x22 + opCallFrameCFA = 0x9C + ) + if len(v) == 0 { + return 0, errors.New("empty location specifier") + } + if v[0] != opCallFrameCFA { + return 0, errors.New("unsupported location specifier") + } + if len(v) == 1 { + // The location description was just DW_OP_call_frame_cfa, so the location is exactly the CFA. + return 0, nil + } + if v[1] != opConsts { + return 0, errors.New("unsupported location specifier") + } + offset, v, err := sleb128(v[2:]) + if err != nil { + return 0, err + } + if len(v) == 1 && v[0] == opPlus { + // The location description was DW_OP_call_frame_cfa, DW_OP_consts , DW_OP_plus. + // So return the offset. + return offset, nil + } + return 0, errors.New("unsupported location specifier") +} + +func uleb128(v []uint8) (u uint64) { + var shift uint + for _, x := range v { + u |= (uint64(x) & 0x7F) << shift + shift += 7 + if x&0x80 == 0 { + break + } + } + return u +} + +// sleb128 parses a signed integer encoded with sleb128 at the start of v, and +// returns the integer and the remainder of v. +func sleb128(v []uint8) (s int64, rest []uint8, err error) { + var shift uint + var sign int64 = -1 + var i int + var x uint8 + for i, x = range v { + s |= (int64(x) & 0x7F) << shift + shift += 7 + sign <<= 7 + if x&0x80 == 0 { + if x&0x40 != 0 { + s |= sign + } + break + } + } + if i == len(v) { + return 0, nil, errors.New("truncated sleb128") + } + return s, v[i+1:], nil +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/eval.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/eval.go new file mode 100644 index 00000000..6a6493a4 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/eval.go @@ -0,0 +1,2115 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// Evaluates Go expressions, using the current values of variables in a program +// being debugged. +// +// TODOs: +// More overflow checking. +// Stricter type checking. +// More expression types. + +// +build linux + +package server + +import ( + "errors" + "fmt" + "go/ast" + "go/parser" + "go/token" + "math" + "math/big" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" +) + +const prec = 256 // precision for untyped float and complex constants. + +var ( + // Some big.Ints to use in overflow checks. + bigIntMaxInt32 = big.NewInt(math.MaxInt32) + bigIntMinInt32 = big.NewInt(math.MinInt32) + bigIntMaxInt64 = big.NewInt(math.MaxInt64) + bigIntMinInt64 = big.NewInt(math.MinInt64) + bigIntMaxUint64 = new(big.Int).SetUint64(math.MaxUint64) +) + +// result stores an intermediate value produced during evaluation of an expression. +// +// d contains the DWARF type of the value. For untyped values, d will be nil. +// +// v contains the value itself. For numeric and bool types, v will have the +// corresponding predeclared Go type. +// For untyped integer, rune, float, complex, string, and bool constants, v will +// have type untInt, untRune, untFloat, untComplex, untString, or bool, +// respectively. +// For values of type int, uint and uintptr, v will be an int32, int64, uint32 +// or uint64 as appropriate. +// For address operations, v will have type pointerToValue. +// For the operands of address operations, v will have type addressableValue. +// Other types are represented using the corresponding implementation of +// debug.Value in program.go. +// +// If an evaluation results in an error, the zero value of result is used. +type result struct { + d dwarf.Type + v interface{} +} + +// untInt is an untyped integer constant +type untInt struct { + *big.Int +} + +// untRune is an untyped rune constant +type untRune struct { + *big.Int +} + +// untFloat is an untyped floating-point constant +type untFloat struct { + *big.Float +} + +// untComplex is an untyped complex constant +type untComplex struct { + r *big.Float + i *big.Float +} + +// untString is an untyped string constant +type untString string + +// pointerToValue is a pointer to a value in memory. +// The evaluator constructs these as the result of address operations like "&x". +// Unlike debug.Pointer, the DWARF type stored alongside values of this type +// is the type of the variable, not the type of the pointer. +type pointerToValue struct { + a uint64 +} + +// addressableValue is the memory location of a value. +// The evaluator constructs these while evaluating the operands of address +// operations like "&x", instead of computing the value of x itself. +type addressableValue struct { + a uint64 +} + +// A sliceOf is a slice created by slicing an array. +// Unlike debug.Slice, the DWARF type stored alongside a value of this type is +// the type of the slice's elements, not the type of the slice. +type sliceOf debug.Slice + +// ident is a value for representing a special identifier. +type ident string + +// identLookup is a built-in function of the expression evaluator which gets the +// value of a global symbol. +var identLookup ident = "lookup" + +// evalExpression evaluates a Go expression. +// If the program counter and stack pointer are nonzero, they are used to determine +// what local variables are available and where in memory they are. +func (s *Server) evalExpression(expression string, pc, sp uint64) (debug.Value, error) { + e := evaluator{server: s, expression: expression, pc: pc, sp: sp} + node, err := parser.ParseExpr(expression) + if err != nil { + return nil, err + } + val := e.evalNode(node, false) + if e.evalError != nil { + return nil, e.evalError + } + + // Convert untyped constants to their default types. + switch v := val.v.(type) { + case untInt: + return e.intFromInteger(v) + case untRune: + if v.Cmp(bigIntMaxInt32) == +1 { + return nil, errors.New("constant overflows rune") + } + if v.Cmp(bigIntMinInt32) == -1 { + return nil, errors.New("constant overflows rune") + } + return int32(v.Int64()), nil + case untFloat: + f, _ := v.Float64() + if math.IsInf(f, 0) { + return nil, errors.New("constant overflows float64") + } + if math.IsNaN(f) { + return nil, errors.New("constant is NaN") + } + return f, nil + case untComplex: + r, _ := v.r.Float64() + i, _ := v.i.Float64() + if math.IsInf(r, 0) || math.IsInf(i, 0) { + return nil, errors.New("constant overflows complex128") + } + if math.IsNaN(r) || math.IsNaN(i) { + return nil, errors.New("constant is NaN") + } + return complex(r, i), nil + case untString: + return debug.String{Length: uint64(len(v)), String: string(v)}, nil + case pointerToValue: + return debug.Pointer{TypeID: uint64(val.d.Common().Offset), Address: v.a}, nil + case sliceOf: + return debug.Slice(v), nil + case nil, addressableValue: + // This case should not be reachable. + return nil, errors.New("unknown error") + } + return val.v, nil +} + +type evaluator struct { + // expression is the expression being evaluated. + expression string + // server interacts with the program being debugged. + server *Server + // curNode is the current parse tree node. This is set so that error messages + // can quote the part of the expression that caused an error. + curNode ast.Node + // evalError is the first error that occurred while evaluating the expression, + // or nil if no error has occurred. + evalError error + // pc and sp are the current program counter and stack pointer, used for + // finding local variables. If either are zero, the expression is evaluated + // without using local variables. + pc uint64 + sp uint64 +} + +// setNode sets curNode, and returns curNode's previous value. +func (e *evaluator) setNode(node ast.Node) (old ast.Node) { + old, e.curNode = e.curNode, node + return old +} + +// err saves an error that occurred during evaluation. +// It returns a zero result, so that functions can exit and set an error with +// return e.err(...) +func (e *evaluator) err(s string) result { + if e.evalError != nil { + return result{} + } + // Append the substring of the expression that corresponds to the current AST node. + start := int(e.curNode.Pos() - 1) + end := int(e.curNode.End() - 1) + if start < 0 { + start = 0 + } + if end > len(e.expression) { + end = len(e.expression) + } + if start > end { + start, end = 0, 0 + } + e.evalError = errors.New(s + `: "` + e.expression[start:end] + `"`) + return result{} +} + +// evalNode computes the value of a node in the expression tree. +// If getAddress is true, the node is the argument of an & operator, so evalNode +// will return a result with a value of type addressableValue if possible. +func (e *evaluator) evalNode(node ast.Node, getAddress bool) result { + // Set the current node in the evaluator, so that error messages can refer to + // it. Defer a function call that changes it back. + defer e.setNode(e.setNode(node)) + + switch n := node.(type) { + case *ast.Ident: + if e.pc != 0 && e.sp != 0 { + a, t := e.server.findLocalVar(n.Name, e.pc, e.sp) + if t != nil { + return e.resultFrom(a, t, getAddress) + } + } + a, t := e.server.findGlobalVar(n.Name) + if t != nil { + return e.resultFrom(a, t, getAddress) + } + switch n.Name { + // Note: these could have been redefined as constants in the code, but we + // don't have a way to detect that. + case "true": + return result{nil, true} + case "false": + return result{nil, false} + case "lookup": + return result{nil, identLookup} + } + return e.err("unknown identifier") + + case *ast.BasicLit: + switch n.Kind { + case token.INT: + i := new(big.Int) + if _, ok := i.SetString(n.Value, 0); !ok { + return e.err("invalid integer constant") + } + return result{nil, untInt{i}} + case token.FLOAT: + r, _, err := big.ParseFloat(n.Value, 10, prec, big.ToNearestEven) + if err != nil { + return e.err(err.Error()) + } + return result{nil, untFloat{r}} + case token.IMAG: + if len(n.Value) <= 1 || n.Value[len(n.Value)-1] != 'i' { + return e.err("invalid imaginary constant") + } + r, _, err := big.ParseFloat(n.Value[:len(n.Value)-1], 10, prec, big.ToNearestEven) + if err != nil { + return e.err(err.Error()) + } + return result{nil, untComplex{new(big.Float), r}} + case token.CHAR: + // TODO: unescaping + return result{nil, untRune{new(big.Int).SetInt64(int64(n.Value[1]))}} + case token.STRING: + // TODO: unescaping + if len(n.Value) <= 1 { + return e.err("invalid string constant") + } + return result{nil, untString(n.Value[1 : len(n.Value)-1])} + } + + case *ast.ParenExpr: + return e.evalNode(n.X, getAddress) + + case *ast.StarExpr: + x := e.evalNode(n.X, false) + switch v := x.v.(type) { + case debug.Pointer: + // x.d may be a typedef pointing to a pointer type (or a typedef pointing + // to a typedef pointing to a pointer type, etc.), so remove typedefs + // until we get the underlying pointer type. + t := followTypedefs(x.d) + if pt, ok := t.(*dwarf.PtrType); ok { + return e.resultFrom(v.Address, pt.Type, getAddress) + } else { + return e.err("invalid DWARF type for pointer") + } + case pointerToValue: + return e.resultFrom(v.a, x.d, getAddress) + case nil: + return x + } + return e.err("invalid indirect") + + case *ast.SelectorExpr: + x := e.evalNode(n.X, false) + sel := n.Sel.Name + switch v := x.v.(type) { + case debug.Struct: + for _, f := range v.Fields { + if f.Name == sel { + t, err := e.server.dwarfData.Type(dwarf.Offset(f.Var.TypeID)) + if err != nil { + return e.err(err.Error()) + } + return e.resultFrom(f.Var.Address, t, getAddress) + } + } + return e.err("struct field not found") + case debug.Pointer: + pt, ok := followTypedefs(x.d).(*dwarf.PtrType) // x.d should be a pointer to struct. + if !ok { + return e.err("invalid DWARF information for pointer") + } + st, ok := followTypedefs(pt.Type).(*dwarf.StructType) + if !ok { + break + } + for _, f := range st.Field { + if f.Name == sel { + return e.resultFrom(v.Address+uint64(f.ByteOffset), f.Type, getAddress) + } + } + return e.err("struct field not found") + case pointerToValue: + st, ok := followTypedefs(x.d).(*dwarf.StructType) // x.d should be a struct. + if !ok { + break + } + for _, f := range st.Field { + if f.Name == sel { + return e.resultFrom(v.a+uint64(f.ByteOffset), f.Type, getAddress) + } + } + return e.err("struct field not found") + } + return e.err("invalid selector expression") + + case *ast.IndexExpr: + x, index := e.evalNode(n.X, false), e.evalNode(n.Index, false) + if x.v == nil || index.v == nil { + return result{} + } + // The expression is x[index] + if m, ok := x.v.(debug.Map); ok { + if getAddress { + return e.err("can't take address of map value") + } + mt, ok := followTypedefs(x.d).(*dwarf.MapType) + if !ok { + return e.err("invalid DWARF type for map") + } + var ( + found bool // true if the key was found + value result // the map value for the key + abort bool // true if an error occurred while searching + // fn is a function that checks if one (key, value) pair corresponds + // to the index in the expression. + fn = func(keyAddr, valAddr uint64, keyType, valType dwarf.Type) bool { + key := e.resultFrom(keyAddr, keyType, false) + if key.v == nil { + abort = true + return false // stop searching map + } + equal, ok := e.evalBinaryOp(token.EQL, index, key).v.(bool) + if !ok { + abort = true + return false // stop searching map + } + if equal { + found = true + value = e.resultFrom(valAddr, valType, false) + return false // stop searching map + } + return true // continue searching map + } + ) + if err := e.server.peekMapValues(mt, m.Address, fn); err != nil { + return e.err(err.Error()) + } + if abort { + // Some operation on individual map keys failed. + return result{} + } + if found { + return value + } + // The key wasn't in the map; return the zero value. + return e.zero(mt.ElemType) + } + + // The index should be a non-negative integer for the remaining cases. + u, err := uint64FromResult(index) + if err != nil { + return e.err("invalid index: " + err.Error()) + } + switch v := x.v.(type) { + case debug.Array: + if u >= v.Length { + return e.err("array index out of bounds") + } + elemType, err := e.server.dwarfData.Type(dwarf.Offset(v.ElementTypeID)) + if err != nil { + return e.err(err.Error()) + } + return e.resultFrom(v.Element(u).Address, elemType, getAddress) + case debug.Slice: + if u >= v.Length { + return e.err("slice index out of bounds") + } + elemType, err := e.server.dwarfData.Type(dwarf.Offset(v.ElementTypeID)) + if err != nil { + return e.err(err.Error()) + } + return e.resultFrom(v.Element(u).Address, elemType, getAddress) + case sliceOf: + if u >= v.Length { + return e.err("slice index out of bounds") + } + return e.resultFrom(v.Element(u).Address, x.d, getAddress) + case debug.String: + if getAddress { + return e.err("can't take address of string element") + } + if u >= v.Length { + return e.err("string index out of bounds") + } + if u >= uint64(len(v.String)) { + return e.err("string element unavailable") + } + return e.uint8Result(v.String[u]) + case untString: + if getAddress { + return e.err("can't take address of string element") + } + if u >= uint64(len(v)) { + return e.err("string index out of bounds") + } + return e.uint8Result(v[u]) + } + return e.err("invalid index expression") + + case *ast.SliceExpr: + if n.Slice3 && n.High == nil { + return e.err("middle index required in full slice") + } + if n.Slice3 && n.Max == nil { + return e.err("final index required in full slice") + } + var ( + low, high, max uint64 + err error + ) + if n.Low != nil { + low, err = uint64FromResult(e.evalNode(n.Low, false)) + if err != nil { + return e.err("invalid slice lower bound: " + err.Error()) + } + } + if n.High != nil { + high, err = uint64FromResult(e.evalNode(n.High, false)) + if err != nil { + return e.err("invalid slice upper bound: " + err.Error()) + } + } + if n.Max != nil { + max, err = uint64FromResult(e.evalNode(n.Max, false)) + if err != nil { + return e.err("invalid slice capacity: " + err.Error()) + } + } + x := e.evalNode(n.X, false) + switch v := x.v.(type) { + case debug.Array, debug.Pointer, pointerToValue: + // This case handles the slicing of arrays and pointers to arrays. + var arr debug.Array + switch v := x.v.(type) { + case debug.Array: + arr = v + case debug.Pointer: + pt, ok := followTypedefs(x.d).(*dwarf.PtrType) + if !ok { + return e.err("invalid DWARF type for pointer") + } + a := e.resultFrom(v.Address, pt.Type, false) + arr, ok = a.v.(debug.Array) + if !ok { + // v is a pointer to something other than an array. + return e.err("cannot slice pointer") + } + case pointerToValue: + a := e.resultFrom(v.a, x.d, false) + var ok bool + arr, ok = a.v.(debug.Array) + if !ok { + // v is a pointer to something other than an array. + return e.err("cannot slice pointer") + } + } + elemType, err := e.server.dwarfData.Type(dwarf.Offset(arr.ElementTypeID)) + if err != nil { + return e.err(err.Error()) + } + if n.High == nil { + high = arr.Length + } else if high > arr.Length { + return e.err("slice upper bound is too large") + } + if n.Max == nil { + max = arr.Length + } else if max > arr.Length { + return e.err("slice capacity is too large") + } + if low > high || high > max { + return e.err("invalid slice index") + } + return result{ + d: elemType, + v: sliceOf{ + Array: debug.Array{ + ElementTypeID: arr.ElementTypeID, + Address: arr.Element(low).Address, + Length: high - low, + StrideBits: uint64(elemType.Common().ByteSize) * 8, + }, + Capacity: max - low, + }, + } + case debug.Slice: + if n.High == nil { + high = v.Length + } else if high > v.Capacity { + return e.err("slice upper bound is too large") + } + if n.Max == nil { + max = v.Capacity + } else if max > v.Capacity { + return e.err("slice capacity is too large") + } + if low > high || high > max { + return e.err("invalid slice index") + } + v.Address += low * (v.StrideBits / 8) + v.Length = high - low + v.Capacity = max - low + return result{x.d, v} + case sliceOf: + if n.High == nil { + high = v.Length + } else if high > v.Capacity { + return e.err("slice upper bound is too large") + } + if n.Max == nil { + max = v.Capacity + } else if max > v.Capacity { + return e.err("slice capacity is too large") + } + if low > high || high > max { + return e.err("invalid slice index") + } + v.Address += low * (v.StrideBits / 8) + v.Length = high - low + v.Capacity = max - low + return result{x.d, v} + case debug.String: + if n.Max != nil { + return e.err("full slice of string") + } + if n.High == nil { + high = v.Length + } + if low > high || high > v.Length { + return e.err("invalid slice index") + } + v.Length = high - low + if low > uint64(len(v.String)) { + // v.String was truncated before the point where this slice starts. + v.String = "" + } else { + if high > uint64(len(v.String)) { + // v.String was truncated before the point where this slice ends. + high = uint64(len(v.String)) + } + v.String = v.String[low:high] + } + return result{x.d, v} + case untString: + if n.Max != nil { + return e.err("full slice of string") + } + if n.High == nil { + high = uint64(len(v)) + } + if low > high { + return e.err("invalid slice expression") + } + if high > uint64(len(v)) { + return e.err("slice upper bound is too large") + } + return e.stringResult(string(v[low:high])) + default: + return e.err("invalid slice expression") + } + + case *ast.CallExpr: + // Only supports lookup("x"), which gets the value of a global symbol x. + fun := e.evalNode(n.Fun, false) + var args []result + for _, a := range n.Args { + args = append(args, e.evalNode(a, false)) + } + if fun.v == identLookup { + if len(args) != 1 { + return e.err("lookup should have one argument") + } + ident, ok := args[0].v.(untString) + if !ok { + return e.err("argument for lookup should be a string constant") + } + if a, t := e.server.findGlobalVar(string(ident)); t == nil { + return e.err("symbol not found") + } else { + return e.resultFrom(a, t, getAddress) + } + } + return e.err("function calls not implemented") + + case *ast.UnaryExpr: + if n.Op == token.AND { + x := e.evalNode(n.X, true) + switch v := x.v.(type) { + case addressableValue: + return result{x.d, pointerToValue{v.a}} + case nil: + return x + } + return e.err("can't take address") + } + + x := e.evalNode(n.X, false) + if x.v == nil { + return x + } + switch v := x.v.(type) { + + case int8: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + case token.XOR: + v = ^v + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case int16: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + case token.XOR: + v = ^v + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case int32: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + case token.XOR: + v = ^v + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case int64: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + case token.XOR: + v = ^v + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case uint8: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + case token.XOR: + v = ^v + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case uint16: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + case token.XOR: + v = ^v + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case uint32: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + case token.XOR: + v = ^v + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case uint64: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + case token.XOR: + v = ^v + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case float32: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case float64: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case complex64: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case complex128: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case untInt: + switch n.Op { + case token.ADD: + case token.SUB: + v.Int.Neg(v.Int) + case token.XOR: + v.Int.Not(v.Int) + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case untRune: + switch n.Op { + case token.ADD: + case token.SUB: + v.Int.Neg(v.Int) + case token.XOR: + v.Int.Not(v.Int) + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case untFloat: + switch n.Op { + case token.ADD: + case token.SUB: + v.Float.Neg(v.Float) + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case untComplex: + switch n.Op { + case token.ADD: + case token.SUB: + v.r.Neg(v.r) + v.i.Neg(v.i) + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case bool: + switch n.Op { + case token.NOT: + v = !v + default: + return e.err("invalid operation") + } + return result{x.d, v} + } + + case *ast.BinaryExpr: + x := e.evalNode(n.X, false) + if x.v == nil { + return x + } + y := e.evalNode(n.Y, false) + if y.v == nil { + return y + } + return e.evalBinaryOp(n.Op, x, y) + } + return e.err("invalid expression") +} + +// evalBinaryOp evaluates a binary operator op applied to x and y. +func (e *evaluator) evalBinaryOp(op token.Token, x, y result) result { + if op == token.NEQ { + tmp := e.evalBinaryOp(token.EQL, x, y) + b, ok := tmp.v.(bool) + if !ok { + return tmp + } + return result{nil, !b} + } + if op == token.GTR { + return e.evalBinaryOp(token.LSS, y, x) + } + if op == token.GEQ { + return e.evalBinaryOp(token.LEQ, x, y) + } + + x = convertUntyped(x, y) + y = convertUntyped(y, x) + + switch a := x.v.(type) { + + case int8: + b, ok := y.v.(int8) + if !ok { + return e.err("type mismatch") + } + var c int8 + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.OR: + c = a | b + case token.XOR: + c = a ^ b + case token.MUL: + c = a * b + case token.QUO: + if b == 0 { + return e.err("integer divide by zero") + } + c = a / b + case token.REM: + if b == 0 { + return e.err("integer divide by zero") + } + c = a % b + case token.AND: + c = a & b + case token.AND_NOT: + c = a &^ b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case int16: + b, ok := y.v.(int16) + if !ok { + return e.err("type mismatch") + } + var c int16 + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.OR: + c = a | b + case token.XOR: + c = a ^ b + case token.MUL: + c = a * b + case token.QUO: + if b == 0 { + return e.err("integer divide by zero") + } + c = a / b + case token.REM: + if b == 0 { + return e.err("integer divide by zero") + } + c = a % b + case token.AND: + c = a & b + case token.AND_NOT: + c = a &^ b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case int32: + b, ok := y.v.(int32) + if !ok { + return e.err("type mismatch") + } + var c int32 + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.OR: + c = a | b + case token.XOR: + c = a ^ b + case token.MUL: + c = a * b + case token.QUO: + if b == 0 { + return e.err("integer divide by zero") + } + c = a / b + case token.REM: + if b == 0 { + return e.err("integer divide by zero") + } + c = a % b + case token.AND: + c = a & b + case token.AND_NOT: + c = a &^ b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case int64: + b, ok := y.v.(int64) + if !ok { + return e.err("type mismatch") + } + var c int64 + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.OR: + c = a | b + case token.XOR: + c = a ^ b + case token.MUL: + c = a * b + case token.QUO: + if b == 0 { + return e.err("integer divide by zero") + } + c = a / b + case token.REM: + if b == 0 { + return e.err("integer divide by zero") + } + c = a % b + case token.AND: + c = a & b + case token.AND_NOT: + c = a &^ b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case uint8: + b, ok := y.v.(uint8) + if !ok { + return e.err("type mismatch") + } + var c uint8 + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.OR: + c = a | b + case token.XOR: + c = a ^ b + case token.MUL: + c = a * b + case token.QUO: + if b == 0 { + return e.err("integer divide by zero") + } + c = a / b + case token.REM: + if b == 0 { + return e.err("integer divide by zero") + } + c = a % b + case token.AND: + c = a & b + case token.AND_NOT: + c = a &^ b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case uint16: + b, ok := y.v.(uint16) + if !ok { + return e.err("type mismatch") + } + var c uint16 + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.OR: + c = a | b + case token.XOR: + c = a ^ b + case token.MUL: + c = a * b + case token.QUO: + if b == 0 { + return e.err("integer divide by zero") + } + c = a / b + case token.REM: + if b == 0 { + return e.err("integer divide by zero") + } + c = a % b + case token.AND: + c = a & b + case token.AND_NOT: + c = a &^ b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case uint32: + b, ok := y.v.(uint32) + if !ok { + return e.err("type mismatch") + } + var c uint32 + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.OR: + c = a | b + case token.XOR: + c = a ^ b + case token.MUL: + c = a * b + case token.QUO: + if b == 0 { + return e.err("integer divide by zero") + } + c = a / b + case token.REM: + if b == 0 { + return e.err("integer divide by zero") + } + c = a % b + case token.AND: + c = a & b + case token.AND_NOT: + c = a &^ b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case uint64: + b, ok := y.v.(uint64) + if !ok { + return e.err("type mismatch") + } + var c uint64 + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.OR: + c = a | b + case token.XOR: + c = a ^ b + case token.MUL: + c = a * b + case token.QUO: + if b == 0 { + return e.err("integer divide by zero") + } + c = a / b + case token.REM: + if b == 0 { + return e.err("integer divide by zero") + } + c = a % b + case token.AND: + c = a & b + case token.AND_NOT: + c = a &^ b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case float32: + b, ok := y.v.(float32) + if !ok { + return e.err("type mismatch") + } + var c float32 + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.MUL: + c = a * b + case token.QUO: + c = a / b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case float64: + b, ok := y.v.(float64) + if !ok { + return e.err("type mismatch") + } + var c float64 + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.MUL: + c = a * b + case token.QUO: + c = a / b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case complex64: + b, ok := y.v.(complex64) + if !ok { + return e.err("type mismatch") + } + var c complex64 + switch op { + case token.EQL: + return result{nil, a == b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.MUL: + c = a * b + case token.QUO: + c = a / b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case complex128: + b, ok := y.v.(complex128) + if !ok { + return e.err("type mismatch") + } + var c complex128 + switch op { + case token.EQL: + return result{nil, a == b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.MUL: + c = a * b + case token.QUO: + c = a / b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case bool: + b, ok := y.v.(bool) + if !ok { + return e.err("type mismatch") + } + var c bool + switch op { + case token.LOR: + c = a || b + case token.LAND: + c = a && b + case token.EQL: + c = a == b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case debug.String: + b, ok := y.v.(debug.String) + if !ok { + return e.err("type mismatch") + } + var c debug.String + switch op { + // TODO: these comparison operators only use the part of the string that + // was read. Very large strings do not have their entire contents read by + // server.value. + case token.EQL: + return result{nil, a.Length == b.Length && a.String == b.String} + case token.LSS: + return result{nil, a.String < b.String} + case token.LEQ: + return result{nil, a.String <= b.String} + case token.ADD: + c.Length = a.Length + b.Length + if a.Length == uint64(len(a.String)) { + c.String = a.String + b.String + } else { + // The first string was truncated at a.Length characters, so the sum + // must be truncated there too. + c.String = a.String + } + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case untString: + b, ok := y.v.(untString) + if !ok { + return e.err("type mismatch") + } + var c untString + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case untInt: + i := a.Int + b, ok := y.v.(untInt) + if !ok { + return e.err("type mismatch") + } + switch op { + case token.EQL: + return result{nil, i.Cmp(b.Int) == 0} + case token.LSS: + return result{nil, i.Cmp(b.Int) < 0} + case token.LEQ: + return result{nil, i.Cmp(b.Int) <= 0} + } + c := new(big.Int) + switch op { + case token.ADD: + c.Add(i, b.Int) + case token.SUB: + c.Sub(i, b.Int) + case token.OR: + c.Or(i, b.Int) + case token.XOR: + c.Xor(i, b.Int) + case token.MUL: + c.Mul(i, b.Int) + case token.QUO: + if b.Sign() == 0 { + return e.err("integer divide by zero") + } + c.Quo(i, b.Int) + case token.REM: + if b.Sign() == 0 { + return e.err("integer divide by zero") + } + c.Mod(i, b.Int) + case token.AND: + c.And(i, b.Int) + case token.AND_NOT: + c.AndNot(i, b.Int) + default: + return e.err("invalid operation") + } + return result{nil, untInt{c}} + + case untRune: + i := a.Int + b, ok := y.v.(untRune) + if !ok { + return e.err("type mismatch") + } + switch op { + case token.EQL: + return result{nil, i.Cmp(b.Int) == 0} + case token.LSS: + return result{nil, i.Cmp(b.Int) < 0} + case token.LEQ: + return result{nil, i.Cmp(b.Int) <= 0} + } + c := new(big.Int) + switch op { + case token.ADD: + c.Add(i, b.Int) + case token.SUB: + c.Sub(i, b.Int) + case token.OR: + c.Or(i, b.Int) + case token.XOR: + c.Xor(i, b.Int) + case token.MUL: + c.Mul(i, b.Int) + case token.QUO: + if b.Sign() == 0 { + return e.err("integer divide by zero") + } + c.Quo(i, b.Int) + case token.REM: + if b.Sign() == 0 { + return e.err("integer divide by zero") + } + c.Mod(i, b.Int) + case token.AND: + c.And(i, b.Int) + case token.AND_NOT: + c.AndNot(i, b.Int) + default: + return e.err("invalid operation") + } + return result{nil, untRune{c}} + + case untFloat: + r := a.Float + b, ok := y.v.(untFloat) + if !ok { + return e.err("type mismatch") + } + switch op { + case token.EQL: + return result{nil, r.Cmp(b.Float) == 0} + case token.LSS: + return result{nil, r.Cmp(b.Float) < 0} + case token.LEQ: + return result{nil, r.Cmp(b.Float) <= 0} + } + c := new(big.Float) + switch op { + case token.ADD: + c.Add(r, b.Float) + case token.SUB: + c.Sub(r, b.Float) + case token.MUL: + c.Mul(r, b.Float) + case token.QUO: + if b.Sign() == 0 { + return e.err("divide by zero") + } + c.Quo(r, b.Float) + default: + return e.err("invalid operation") + } + return result{nil, untFloat{c}} + + case untComplex: + b, ok := y.v.(untComplex) + if !ok { + return e.err("type mismatch") + } + var ( + ar = a.r + br = b.r + ai = a.i + bi = b.i + ) + if op == token.EQL { + return result{nil, ar.Cmp(br) == 0 && ai.Cmp(bi) == 0} + } + var ( + cr = new(big.Float) + ci = new(big.Float) + ) + switch op { + case token.ADD: + cr.Add(ar, br) + ci.Add(ai, bi) + case token.SUB: + cr.Sub(ar, br) + ci.Sub(ai, bi) + case token.MUL: + var t0, t1 big.Float + t0.Mul(ar, br) + t1.Mul(ai, bi) + cr.Sub(&t0, &t1) + t0.Mul(ar, bi) + t1.Mul(ai, br) + ci.Add(&t0, &t1) + case token.QUO: + // a/b = a*conj(b)/|b|^2 + var t0, t1 big.Float + cr.Mul(ar, br) + t0.Mul(ai, bi) + cr.Add(cr, &t0) // cr = Re(a*conj(b)) + ci.Mul(ai, br) + t0.Mul(ar, bi) + ci.Sub(ci, &t0) // ci = Im(a*conj(b)) + t0.Mul(br, br) + t1.Mul(bi, bi) + t0.Add(&t0, &t1) // t0 = |b|^2 + if t0.Sign() == 0 { + return e.err("divide by zero") + } + cr.Quo(cr, &t0) // cr = Re(a*conj(b))/|b|^2 = Re(a/b) + ci.Quo(ci, &t0) // ci = Im(a*conj(b))/|b|^2 = Im(a/b) + } + return result{nil, untComplex{cr, ci}} + } + + return e.err("invalid operation") +} + +// findLocalVar finds a local variable (or function parameter) by name, and +// returns its address and DWARF type. It returns a nil type on failure. +// The PC and SP are used to determine the current function and stack frame. +func (s *Server) findLocalVar(name string, pc, sp uint64) (uint64, dwarf.Type) { + // Find the DWARF entry for the function at pc. + funcEntry, _, err := s.dwarfData.PCToFunction(uint64(pc)) + if err != nil { + return 0, nil + } + + // Compute the stack frame pointer. + fpOffset, err := s.dwarfData.PCToSPOffset(uint64(pc)) + if err != nil { + return 0, nil + } + framePointer := sp + uint64(fpOffset) + + // Check each child of the function's DWARF entry to see if it is a parameter + // or local variable with the right name. If so, return its address and type. + r := s.dwarfData.Reader() + r.Seek(funcEntry.Offset) + for { + varEntry, err := r.Next() + if err != nil { + break + } + if varEntry.Tag == 0 { + // This tag marks the end of the function's DWARF entry's children. + break + } + + // Check this entry corresponds to a local variable or function parameter, + // that it has the correct name, and that we can get its type and location. + // If so, return them. + if varEntry.Tag != dwarf.TagFormalParameter && varEntry.Tag != dwarf.TagVariable { + continue + } + varName, ok := varEntry.Val(dwarf.AttrName).(string) + if !ok { + continue + } + if varName != name { + continue + } + varTypeOffset, ok := varEntry.Val(dwarf.AttrType).(dwarf.Offset) + if !ok { + continue + } + varType, err := s.dwarfData.Type(varTypeOffset) + if err != nil { + continue + } + locationAttribute := varEntry.Val(dwarf.AttrLocation) + if locationAttribute == nil { + continue + } + locationDescription, ok := locationAttribute.([]uint8) + if !ok { + continue + } + frameOffset, err := evalLocation(locationDescription) + if err != nil { + continue + } + return framePointer + uint64(frameOffset), varType + } + + return 0, nil +} + +// findGlobalVar finds a global variable by name, and returns its address and +// DWARF type. It returns a nil type on failure. +func (s *Server) findGlobalVar(name string) (uint64, dwarf.Type) { + entry, err := s.dwarfData.LookupVariable(name) + if err != nil { + return 0, nil + } + loc, err := s.dwarfData.EntryLocation(entry) + if err != nil { + return 0, nil + } + ofs, err := s.dwarfData.EntryTypeOffset(entry) + if err != nil { + return 0, nil + } + typ, err := s.dwarfData.Type(ofs) + if err != nil { + return 0, nil + } + return loc, typ +} + +// intFromInteger converts an untyped integer constant to an int32 or int64, +// depending on the int size of the debugged program. +// It returns an error on overflow, or if it can't determine the int size. +func (e *evaluator) intFromInteger(v untInt) (interface{}, error) { + t, ok := e.getBaseType("int") + if !ok { + return nil, errors.New("couldn't get int size from DWARF info") + } + switch t.Common().ByteSize { + case 4: + if v.Cmp(bigIntMaxInt32) == +1 || v.Cmp(bigIntMinInt32) == -1 { + return nil, errors.New("constant overflows int") + } + return int32(v.Int64()), nil + case 8: + if v.Cmp(bigIntMaxInt64) == +1 || v.Cmp(bigIntMinInt64) == -1 { + return nil, errors.New("constant overflows int") + } + return v.Int64(), nil + } + return nil, errors.New("invalid int size in DWARF info") +} + +// uint8Result constructs a result for a uint8 value. +func (e *evaluator) uint8Result(v uint8) result { + t, ok := e.getBaseType("uint8") + if !ok { + e.err("couldn't construct uint8") + } + return result{t, uint8(v)} +} + +// stringResult constructs a result for a string value. +func (e *evaluator) stringResult(s string) result { + t, ok := e.getBaseType("string") + if !ok { + e.err("couldn't construct string") + } + return result{t, debug.String{Length: uint64(len(s)), String: s}} +} + +// getBaseType returns the *dwarf.Type with a given name. +// TODO: cache this. +func (e *evaluator) getBaseType(name string) (dwarf.Type, bool) { + entry, err := e.server.dwarfData.LookupEntry(name) + if err != nil { + return nil, false + } + t, err := e.server.dwarfData.Type(entry.Offset) + if err != nil { + return nil, false + } + return t, true +} + +// resultFrom constructs a result corresponding to a value in the program with +// the given address and DWARF type. +// If getAddress is true, the result will be the operand of an address expression, +// so resultFrom returns a result containing a value of type addressableValue. +func (e *evaluator) resultFrom(a uint64, t dwarf.Type, getAddress bool) result { + if a == 0 { + return e.err("nil pointer dereference") + } + if getAddress { + return result{t, addressableValue{a}} + } + v, err := e.server.value(t, a) + if err != nil { + return e.err(err.Error()) + } + return result{t, v} +} + +// zero returns the zero value of type t. +// TODO: implement for array and struct. +func (e *evaluator) zero(t dwarf.Type) result { + var v interface{} + switch typ := followTypedefs(t).(type) { + case *dwarf.CharType, *dwarf.IntType, *dwarf.EnumType: + switch typ.Common().ByteSize { + case 1: + v = int8(0) + case 2: + v = int16(0) + case 4: + v = int32(0) + case 8: + v = int64(0) + default: + return e.err("invalid integer size " + fmt.Sprint(typ.Common().ByteSize)) + } + case *dwarf.UcharType, *dwarf.UintType: + switch typ.Common().ByteSize { + case 1: + v = uint8(0) + case 2: + v = uint16(0) + case 4: + v = uint32(0) + case 8: + v = uint64(0) + default: + return e.err("invalid unsigned integer size " + fmt.Sprint(typ.Common().ByteSize)) + } + case *dwarf.FloatType: + switch typ.Common().ByteSize { + case 4: + v = float32(0) + case 8: + v = float64(0) + default: + return e.err("invalid float size " + fmt.Sprint(typ.Common().ByteSize)) + } + case *dwarf.ComplexType: + switch typ.Common().ByteSize { + case 8: + v = complex64(0) + case 16: + v = complex128(0) + default: + return e.err("invalid complex size " + fmt.Sprint(typ.Common().ByteSize)) + } + case *dwarf.BoolType: + v = false + case *dwarf.PtrType: + v = debug.Pointer{TypeID: uint64(t.Common().Offset)} + case *dwarf.SliceType: + v = debug.Slice{ + Array: debug.Array{ + ElementTypeID: uint64(typ.ElemType.Common().Offset), + StrideBits: uint64(typ.ElemType.Common().ByteSize) * 8, + }, + } + case *dwarf.StringType: + v = debug.String{} + case *dwarf.InterfaceType: + v = debug.Interface{} + case *dwarf.FuncType: + v = debug.Func{} + case *dwarf.MapType: + v = debug.Map{TypeID: uint64(t.Common().Offset)} + case *dwarf.ChanType: + v = debug.Channel{ + ElementTypeID: uint64(typ.ElemType.Common().Offset), + Stride: uint64(typ.ElemType.Common().ByteSize), + } + default: + return e.err("can't get zero value of this type") + } + return result{t, v} +} + +// convertUntyped converts x to be the same type as y, if x is untyped and the +// conversion is possible. +// +// An untyped bool can be converted to a boolean type. +// An untyped string can be converted to a string type. +// An untyped integer, rune, float or complex value can be converted to a +// numeric type, or to an untyped value later in that list. +// +// x is returned unchanged if none of these cases apply. +func convertUntyped(x, y result) result { + switch a := x.v.(type) { + case untInt: + i := a.Int + switch y.v.(type) { + case int8: + return result{y.d, int8(i.Int64())} + case int16: + return result{y.d, int16(i.Int64())} + case int32: + return result{y.d, int32(i.Int64())} + case int64: + return result{y.d, int64(i.Int64())} + case uint8: + return result{y.d, uint8(i.Uint64())} + case uint16: + return result{y.d, uint16(i.Uint64())} + case uint32: + return result{y.d, uint32(i.Uint64())} + case uint64: + return result{y.d, uint64(i.Uint64())} + case float32: + f, _ := new(big.Float).SetInt(i).Float32() + return result{y.d, f} + case float64: + f, _ := new(big.Float).SetInt(i).Float64() + return result{y.d, f} + case complex64: + f, _ := new(big.Float).SetInt(i).Float32() + return result{y.d, complex(f, 0)} + case complex128: + f, _ := new(big.Float).SetInt(i).Float64() + return result{y.d, complex(f, 0)} + case untRune: + return result{nil, untRune{i}} + case untFloat: + return result{nil, untFloat{new(big.Float).SetPrec(prec).SetInt(i)}} + case untComplex: + return result{nil, untComplex{new(big.Float).SetPrec(prec).SetInt(i), new(big.Float)}} + } + case untRune: + i := a.Int + switch y.v.(type) { + case int8: + return result{y.d, int8(i.Int64())} + case int16: + return result{y.d, int16(i.Int64())} + case int32: + return result{y.d, int32(i.Int64())} + case int64: + return result{y.d, int64(i.Int64())} + case uint8: + return result{y.d, uint8(i.Uint64())} + case uint16: + return result{y.d, uint16(i.Uint64())} + case uint32: + return result{y.d, uint32(i.Uint64())} + case uint64: + return result{y.d, uint64(i.Uint64())} + case float32: + f, _ := new(big.Float).SetInt(i).Float32() + return result{y.d, f} + case float64: + f, _ := new(big.Float).SetInt(i).Float64() + return result{y.d, f} + case complex64: + f, _ := new(big.Float).SetInt(i).Float32() + return result{y.d, complex(f, 0)} + case complex128: + f, _ := new(big.Float).SetInt(i).Float64() + return result{y.d, complex(f, 0)} + case untRune: + return result{nil, untRune{i}} + case untFloat: + return result{nil, untFloat{new(big.Float).SetPrec(prec).SetInt(i)}} + case untComplex: + return result{nil, untComplex{new(big.Float).SetPrec(prec).SetInt(i), new(big.Float)}} + } + case untFloat: + if a.IsInt() { + i, _ := a.Int(nil) + switch y.v.(type) { + case int8: + return result{y.d, int8(i.Int64())} + case int16: + return result{y.d, int16(i.Int64())} + case int32: + return result{y.d, int32(i.Int64())} + case int64: + return result{y.d, int64(i.Int64())} + case uint8: + return result{y.d, uint8(i.Uint64())} + case uint16: + return result{y.d, uint16(i.Uint64())} + case uint32: + return result{y.d, uint32(i.Uint64())} + case uint64: + return result{y.d, uint64(i.Uint64())} + } + } + switch y.v.(type) { + case float32: + f, _ := a.Float32() + return result{y.d, float32(f)} + case float64: + f, _ := a.Float64() + return result{y.d, float64(f)} + case complex64: + f, _ := a.Float32() + return result{y.d, complex(f, 0)} + case complex128: + f, _ := a.Float64() + return result{y.d, complex(f, 0)} + case untComplex: + return result{nil, untComplex{a.Float, new(big.Float)}} + } + case untComplex: + if a.i.Sign() == 0 { + // a is a real number. + if a.r.IsInt() { + // a is an integer. + i, _ := a.r.Int(nil) + switch y.v.(type) { + case int8: + return result{y.d, int8(i.Int64())} + case int16: + return result{y.d, int16(i.Int64())} + case int32: + return result{y.d, int32(i.Int64())} + case int64: + return result{y.d, int64(i.Int64())} + case uint8: + return result{y.d, uint8(i.Uint64())} + case uint16: + return result{y.d, uint16(i.Uint64())} + case uint32: + return result{y.d, uint32(i.Uint64())} + case uint64: + return result{y.d, uint64(i.Uint64())} + } + } + switch y.v.(type) { + case float32: + f, _ := a.r.Float32() + return result{y.d, float32(f)} + case float64: + f, _ := a.r.Float64() + return result{y.d, float64(f)} + } + } + switch y.v.(type) { + case complex64: + r, _ := a.r.Float32() + i, _ := a.i.Float32() + return result{y.d, complex(r, i)} + case complex128: + r, _ := a.r.Float64() + i, _ := a.i.Float64() + return result{y.d, complex(r, i)} + } + case bool: + if x.d != nil { + // x is a typed bool, not an untyped bool. + break + } + switch y.v.(type) { + case bool: + return result{y.d, bool(a)} + } + case untString: + switch y.v.(type) { + case debug.String: + return result{y.d, debug.String{Length: uint64(len(a)), String: string(a)}} + } + } + return x +} + +// uint64FromResult converts a result into a uint64 for slice or index expressions. +// It returns an error if the conversion cannot be done. +func uint64FromResult(x result) (uint64, error) { + switch v := x.v.(type) { + case int8: + if v < 0 { + return 0, errors.New("value is negative") + } + return uint64(v), nil + case int16: + if v < 0 { + return 0, errors.New("value is negative") + } + return uint64(v), nil + case int32: + if v < 0 { + return 0, errors.New("value is negative") + } + return uint64(v), nil + case int64: + if v < 0 { + return 0, errors.New("value is negative") + } + return uint64(v), nil + case uint8: + return uint64(v), nil + case uint16: + return uint64(v), nil + case uint32: + return uint64(v), nil + case uint64: + return v, nil + case untInt: + if v.Int.Sign() == -1 { + return 0, errors.New("value is negative") + } + if v.Int.Cmp(bigIntMaxUint64) == +1 { + return 0, errors.New("value is too large") + } + return v.Int.Uint64(), nil + case untRune: + if v.Sign() == -1 { + return 0, errors.New("value is negative") + } + if v.Cmp(bigIntMaxUint64) == +1 { + return 0, errors.New("value is too large") + } + return v.Uint64(), nil + case untFloat: + if !v.IsInt() { + return 0, errors.New("value is not an integer") + } + if v.Sign() == -1 { + return 0, errors.New("value is negative") + } + i, _ := v.Int(nil) + if i.Cmp(bigIntMaxUint64) == +1 { + return 0, errors.New("value is too large") + } + return i.Uint64(), nil + case untComplex: + if v.i.Sign() != 0 { + return 0, errors.New("value is complex") + } + if !v.r.IsInt() { + return 0, errors.New("value is not an integer") + } + if v.r.Sign() == -1 { + return 0, errors.New("value is negative") + } + i, _ := v.r.Int(nil) + if i.Cmp(bigIntMaxUint64) == +1 { + return 0, errors.New("value is too large") + } + return i.Uint64(), nil + } + return 0, fmt.Errorf("cannot convert to unsigned integer") +} + +// followTypedefs returns the underlying type of t, removing any typedefs. +// If t leads to a cycle of typedefs, followTypedefs returns nil. +func followTypedefs(t dwarf.Type) dwarf.Type { + // If t is a *dwarf.TypedefType, next returns t.Type, otherwise it returns t. + // The bool returned is true when the argument was a typedef. + next := func(t dwarf.Type) (dwarf.Type, bool) { + tt, ok := t.(*dwarf.TypedefType) + if !ok { + return t, false + } + return tt.Type, true + } + // Advance two pointers, one at twice the speed, so we can detect if we get + // stuck in a cycle. + slow, fast := t, t + for { + var wasTypedef bool + fast, wasTypedef = next(fast) + if !wasTypedef { + return fast + } + fast, wasTypedef = next(fast) + if !wasTypedef { + return fast + } + slow, _ = next(slow) + if slow == fast { + return nil + } + } +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/eval.m4 b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/eval.m4 new file mode 100644 index 00000000..a191b364 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/eval.m4 @@ -0,0 +1,1721 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. +//m4_changequote(`@',`@') +// Evaluates Go expressions, using the current values of variables in a program +// being debugged. +// +// TODOs: +// More overflow checking. +// Stricter type checking. +// More expression types. + +package server + +import ( + "errors" + "fmt" + "go/ast" + "go/parser" + "go/token" + "math" + "math/big" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" +) + +const prec = 256 // precision for untyped float and complex constants. + +var ( + // Some big.Ints to use in overflow checks. + bigIntMaxInt32 = big.NewInt(math.MaxInt32) + bigIntMinInt32 = big.NewInt(math.MinInt32) + bigIntMaxInt64 = big.NewInt(math.MaxInt64) + bigIntMinInt64 = big.NewInt(math.MinInt64) + bigIntMaxUint64 = new(big.Int).SetUint64(math.MaxUint64) +) + +// result stores an intermediate value produced during evaluation of an expression. +// +// d contains the DWARF type of the value. For untyped values, d will be nil. +// +// v contains the value itself. For numeric and bool types, v will have the +// corresponding predeclared Go type. +// For untyped integer, rune, float, complex, string, and bool constants, v will +// have type untInt, untRune, untFloat, untComplex, untString, or bool, +// respectively. +// For values of type int, uint and uintptr, v will be an int32, int64, uint32 +// or uint64 as appropriate. +// For address operations, v will have type pointerToValue. +// For the operands of address operations, v will have type addressableValue. +// Other types are represented using the corresponding implementation of +// debug.Value in program.go. +// +// If an evaluation results in an error, the zero value of result is used. +type result struct { + d dwarf.Type + v interface{} +} + +// untInt is an untyped integer constant +type untInt struct { + *big.Int +} + +// untRune is an untyped rune constant +type untRune struct { + *big.Int +} + +// untFloat is an untyped floating-point constant +type untFloat struct { + *big.Float +} + +// untComplex is an untyped complex constant +type untComplex struct { + r *big.Float + i *big.Float +} + +// untString is an untyped string constant +type untString string + +// pointerToValue is a pointer to a value in memory. +// The evaluator constructs these as the result of address operations like "&x". +// Unlike debug.Pointer, the DWARF type stored alongside values of this type +// is the type of the variable, not the type of the pointer. +type pointerToValue struct { + a uint64 +} + +// addressableValue is the memory location of a value. +// The evaluator constructs these while evaluating the operands of address +// operations like "&x", instead of computing the value of x itself. +type addressableValue struct { + a uint64 +} + +// A sliceOf is a slice created by slicing an array. +// Unlike debug.Slice, the DWARF type stored alongside a value of this type is +// the type of the slice's elements, not the type of the slice. +type sliceOf debug.Slice + +// ident is a value for representing a special identifier. +type ident string + +// identLookup is a built-in function of the expression evaluator which gets the +// value of a global symbol. +var identLookup ident = "lookup" + +// evalExpression evaluates a Go expression. +// If the program counter and stack pointer are nonzero, they are used to determine +// what local variables are available and where in memory they are. +func (s *Server) evalExpression(expression string, pc, sp uint64) (debug.Value, error) { + e := evaluator{server: s, expression: expression, pc: pc, sp: sp} + node, err := parser.ParseExpr(expression) + if err != nil { + return nil, err + } + val := e.evalNode(node, false) + if e.evalError != nil { + return nil, e.evalError + } + + // Convert untyped constants to their default types. + switch v := val.v.(type) { + case untInt: + return e.intFromInteger(v) + case untRune: + if v.Cmp(bigIntMaxInt32) == +1 { + return nil, errors.New("constant overflows rune") + } + if v.Cmp(bigIntMinInt32) == -1 { + return nil, errors.New("constant overflows rune") + } + return int32(v.Int64()), nil + case untFloat: + f, _ := v.Float64() + if math.IsInf(f, 0) { + return nil, errors.New("constant overflows float64") + } + if math.IsNaN(f) { + return nil, errors.New("constant is NaN") + } + return f, nil + case untComplex: + r, _ := v.r.Float64() + i, _ := v.i.Float64() + if math.IsInf(r, 0) || math.IsInf(i, 0) { + return nil, errors.New("constant overflows complex128") + } + if math.IsNaN(r) || math.IsNaN(i) { + return nil, errors.New("constant is NaN") + } + return complex(r, i), nil + case untString: + return debug.String{Length: uint64(len(v)), String: string(v)}, nil + case pointerToValue: + return debug.Pointer{TypeID: uint64(val.d.Common().Offset), Address: v.a}, nil + case sliceOf: + return debug.Slice(v), nil + case nil, addressableValue: + // This case should not be reachable. + return nil, errors.New("unknown error") + } + return val.v, nil +} + +type evaluator struct { + // expression is the expression being evaluated. + expression string + // server interacts with the program being debugged. + server *Server + // curNode is the current parse tree node. This is set so that error messages + // can quote the part of the expression that caused an error. + curNode ast.Node + // evalError is the first error that occurred while evaluating the expression, + // or nil if no error has occurred. + evalError error + // pc and sp are the current program counter and stack pointer, used for + // finding local variables. If either are zero, the expression is evaluated + // without using local variables. + pc uint64 + sp uint64 +} + +// setNode sets curNode, and returns curNode's previous value. +func (e *evaluator) setNode(node ast.Node) (old ast.Node) { + old, e.curNode = e.curNode, node + return old +} + +// err saves an error that occurred during evaluation. +// It returns a zero result, so that functions can exit and set an error with +// return e.err(...) +func (e *evaluator) err(s string) result { + if e.evalError != nil { + return result{} + } + // Append the substring of the expression that corresponds to the current AST node. + start := int(e.curNode.Pos() - 1) + end := int(e.curNode.End() - 1) + if start < 0 { + start = 0 + } + if end > len(e.expression) { + end = len(e.expression) + } + if start > end { + start, end = 0, 0 + } + e.evalError = errors.New(s + `: "` + e.expression[start:end] + `"`) + return result{} +} + +// evalNode computes the value of a node in the expression tree. +// If getAddress is true, the node is the argument of an & operator, so evalNode +// will return a result with a value of type addressableValue if possible. +func (e *evaluator) evalNode(node ast.Node, getAddress bool) result { + // Set the current node in the evaluator, so that error messages can refer to + // it. Defer a function call that changes it back. + defer e.setNode(e.setNode(node)) + + switch n := node.(type) { + case *ast.Ident: + if e.pc != 0 && e.sp != 0 { + a, t := e.server.findLocalVar(n.Name, e.pc, e.sp) + if t != nil { + return e.resultFrom(a, t, getAddress) + } + } + a, t := e.server.findGlobalVar(n.Name) + if t != nil { + return e.resultFrom(a, t, getAddress) + } + switch n.Name { + // Note: these could have been redefined as constants in the code, but we + // don't have a way to detect that. + case "true": + return result{nil, true} + case "false": + return result{nil, false} + case "lookup": + return result{nil, identLookup} + } + return e.err("unknown identifier") + + case *ast.BasicLit: + switch n.Kind { + case token.INT: + i := new(big.Int) + if _, ok := i.SetString(n.Value, 0); !ok { + return e.err("invalid integer constant") + } + return result{nil, untInt{i}} + case token.FLOAT: + r, _, err := big.ParseFloat(n.Value, 10, prec, big.ToNearestEven) + if err != nil { + return e.err(err.Error()) + } + return result{nil, untFloat{r}} + case token.IMAG: + if len(n.Value) <= 1 || n.Value[len(n.Value)-1] != 'i' { + return e.err("invalid imaginary constant") + } + r, _, err := big.ParseFloat(n.Value[:len(n.Value)-1], 10, prec, big.ToNearestEven) + if err != nil { + return e.err(err.Error()) + } + return result{nil, untComplex{new(big.Float), r}} + case token.CHAR: + // TODO: unescaping + return result{nil, untRune{new(big.Int).SetInt64(int64(n.Value[1]))}} + case token.STRING: + // TODO: unescaping + if len(n.Value) <= 1 { + return e.err("invalid string constant") + } + return result{nil, untString(n.Value[1 : len(n.Value)-1])} + } + + case *ast.ParenExpr: + return e.evalNode(n.X, getAddress) + + case *ast.StarExpr: + x := e.evalNode(n.X, false) + switch v := x.v.(type) { + case debug.Pointer: + // x.d may be a typedef pointing to a pointer type (or a typedef pointing + // to a typedef pointing to a pointer type, etc.), so remove typedefs + // until we get the underlying pointer type. + t := followTypedefs(x.d) + if pt, ok := t.(*dwarf.PtrType); ok { + return e.resultFrom(v.Address, pt.Type, getAddress) + } else { + return e.err("invalid DWARF type for pointer") + } + case pointerToValue: + return e.resultFrom(v.a, x.d, getAddress) + case nil: + return x + } + return e.err("invalid indirect") + + case *ast.SelectorExpr: + x := e.evalNode(n.X, false) + sel := n.Sel.Name + switch v := x.v.(type) { + case debug.Struct: + for _, f := range v.Fields { + if f.Name == sel { + t, err := e.server.dwarfData.Type(dwarf.Offset(f.Var.TypeID)) + if err != nil { + return e.err(err.Error()) + } + return e.resultFrom(f.Var.Address, t, getAddress) + } + } + return e.err("struct field not found") + case debug.Pointer: + pt, ok := followTypedefs(x.d).(*dwarf.PtrType) // x.d should be a pointer to struct. + if !ok { + return e.err("invalid DWARF information for pointer") + } + st, ok := followTypedefs(pt.Type).(*dwarf.StructType) + if !ok { + break + } + for _, f := range st.Field { + if f.Name == sel { + return e.resultFrom(v.Address+uint64(f.ByteOffset), f.Type, getAddress) + } + } + return e.err("struct field not found") + case pointerToValue: + st, ok := followTypedefs(x.d).(*dwarf.StructType) // x.d should be a struct. + if !ok { + break + } + for _, f := range st.Field { + if f.Name == sel { + return e.resultFrom(v.a+uint64(f.ByteOffset), f.Type, getAddress) + } + } + return e.err("struct field not found") + } + return e.err("invalid selector expression") + + case *ast.IndexExpr: + x, index := e.evalNode(n.X, false), e.evalNode(n.Index, false) + if x.v == nil || index.v == nil { + return result{} + } + // The expression is x[index] + if m, ok := x.v.(debug.Map); ok { + if getAddress { + return e.err("can't take address of map value") + } + mt, ok := followTypedefs(x.d).(*dwarf.MapType) + if !ok { + return e.err("invalid DWARF type for map") + } + var ( + found bool // true if the key was found + value result // the map value for the key + abort bool // true if an error occurred while searching + // fn is a function that checks if one (key, value) pair corresponds + // to the index in the expression. + fn = func(keyAddr, valAddr uint64, keyType, valType dwarf.Type) bool { + key := e.resultFrom(keyAddr, keyType, false) + if key.v == nil { + abort = true + return false // stop searching map + } + equal, ok := e.evalBinaryOp(token.EQL, index, key).v.(bool) + if !ok { + abort = true + return false // stop searching map + } + if equal { + found = true + value = e.resultFrom(valAddr, valType, false) + return false // stop searching map + } + return true // continue searching map + } + ) + if err := e.server.peekMapValues(mt, m.Address, fn); err != nil { + return e.err(err.Error()) + } + if abort { + // Some operation on individual map keys failed. + return result{} + } + if found { + return value + } + // The key wasn't in the map; return the zero value. + return e.zero(mt.ElemType) + } + + // The index should be a non-negative integer for the remaining cases. + u, err := uint64FromResult(index) + if err != nil { + return e.err("invalid index: " + err.Error()) + } + switch v := x.v.(type) { + case debug.Array: + if u >= v.Length { + return e.err("array index out of bounds") + } + elemType, err := e.server.dwarfData.Type(dwarf.Offset(v.ElementTypeID)) + if err != nil { + return e.err(err.Error()) + } + return e.resultFrom(v.Element(u).Address, elemType, getAddress) + case debug.Slice: + if u >= v.Length { + return e.err("slice index out of bounds") + } + elemType, err := e.server.dwarfData.Type(dwarf.Offset(v.ElementTypeID)) + if err != nil { + return e.err(err.Error()) + } + return e.resultFrom(v.Element(u).Address, elemType, getAddress) + case sliceOf: + if u >= v.Length { + return e.err("slice index out of bounds") + } + return e.resultFrom(v.Element(u).Address, x.d, getAddress) + case debug.String: + if getAddress { + return e.err("can't take address of string element") + } + if u >= v.Length { + return e.err("string index out of bounds") + } + if u >= uint64(len(v.String)) { + return e.err("string element unavailable") + } + return e.uint8Result(v.String[u]) + case untString: + if getAddress { + return e.err("can't take address of string element") + } + if u >= uint64(len(v)) { + return e.err("string index out of bounds") + } + return e.uint8Result(v[u]) + } + return e.err("invalid index expression") + + case *ast.SliceExpr: + if n.Slice3 && n.High == nil { + return e.err("middle index required in full slice") + } + if n.Slice3 && n.Max == nil { + return e.err("final index required in full slice") + } + var ( + low, high, max uint64 + err error + ) + if n.Low != nil { + low, err = uint64FromResult(e.evalNode(n.Low, false)) + if err != nil { + return e.err("invalid slice lower bound: " + err.Error()) + } + } + if n.High != nil { + high, err = uint64FromResult(e.evalNode(n.High, false)) + if err != nil { + return e.err("invalid slice upper bound: " + err.Error()) + } + } + if n.Max != nil { + max, err = uint64FromResult(e.evalNode(n.Max, false)) + if err != nil { + return e.err("invalid slice capacity: " + err.Error()) + } + } + x := e.evalNode(n.X, false) + switch v := x.v.(type) { + case debug.Array, debug.Pointer, pointerToValue: + // This case handles the slicing of arrays and pointers to arrays. + var arr debug.Array + switch v := x.v.(type) { + case debug.Array: + arr = v + case debug.Pointer: + pt, ok := followTypedefs(x.d).(*dwarf.PtrType) + if !ok { + return e.err("invalid DWARF type for pointer") + } + a := e.resultFrom(v.Address, pt.Type, false) + arr, ok = a.v.(debug.Array) + if !ok { + // v is a pointer to something other than an array. + return e.err("cannot slice pointer") + } + case pointerToValue: + a := e.resultFrom(v.a, x.d, false) + var ok bool + arr, ok = a.v.(debug.Array) + if !ok { + // v is a pointer to something other than an array. + return e.err("cannot slice pointer") + } + } + elemType, err := e.server.dwarfData.Type(dwarf.Offset(arr.ElementTypeID)) + if err != nil { + return e.err(err.Error()) + } + if n.High == nil { + high = arr.Length + } else if high > arr.Length { + return e.err("slice upper bound is too large") + } + if n.Max == nil { + max = arr.Length + } else if max > arr.Length { + return e.err("slice capacity is too large") + } + if low > high || high > max { + return e.err("invalid slice index") + } + return result{ + d: elemType, + v: sliceOf{ + Array: debug.Array{ + ElementTypeID: arr.ElementTypeID, + Address: arr.Element(low).Address, + Length: high - low, + StrideBits: uint64(elemType.Common().ByteSize) * 8, + }, + Capacity: max - low, + }, + } + case debug.Slice: + if n.High == nil { + high = v.Length + } else if high > v.Capacity { + return e.err("slice upper bound is too large") + } + if n.Max == nil { + max = v.Capacity + } else if max > v.Capacity { + return e.err("slice capacity is too large") + } + if low > high || high > max { + return e.err("invalid slice index") + } + v.Address += low * (v.StrideBits / 8) + v.Length = high - low + v.Capacity = max - low + return result{x.d, v} + case sliceOf: + if n.High == nil { + high = v.Length + } else if high > v.Capacity { + return e.err("slice upper bound is too large") + } + if n.Max == nil { + max = v.Capacity + } else if max > v.Capacity { + return e.err("slice capacity is too large") + } + if low > high || high > max { + return e.err("invalid slice index") + } + v.Address += low * (v.StrideBits / 8) + v.Length = high - low + v.Capacity = max - low + return result{x.d, v} + case debug.String: + if n.Max != nil { + return e.err("full slice of string") + } + if n.High == nil { + high = v.Length + } + if low > high || high > v.Length { + return e.err("invalid slice index") + } + v.Length = high - low + if low > uint64(len(v.String)) { + // v.String was truncated before the point where this slice starts. + v.String = "" + } else { + if high > uint64(len(v.String)) { + // v.String was truncated before the point where this slice ends. + high = uint64(len(v.String)) + } + v.String = v.String[low:high] + } + return result{x.d, v} + case untString: + if n.Max != nil { + return e.err("full slice of string") + } + if n.High == nil { + high = uint64(len(v)) + } + if low > high { + return e.err("invalid slice expression") + } + if high > uint64(len(v)) { + return e.err("slice upper bound is too large") + } + return e.stringResult(string(v[low:high])) + default: + return e.err("invalid slice expression") + } + + case *ast.CallExpr: + // Only supports lookup("x"), which gets the value of a global symbol x. + fun := e.evalNode(n.Fun, false) + var args []result + for _, a := range n.Args { + args = append(args, e.evalNode(a, false)) + } + if fun.v == identLookup { + if len(args) != 1 { + return e.err("lookup should have one argument") + } + ident, ok := args[0].v.(untString) + if !ok { + return e.err("argument for lookup should be a string constant") + } + if a, t := e.server.findGlobalVar(string(ident)); t == nil { + return e.err("symbol not found") + } else { + return e.resultFrom(a, t, getAddress) + } + } + return e.err("function calls not implemented") + + case *ast.UnaryExpr: + if n.Op == token.AND { + x := e.evalNode(n.X, true) + switch v := x.v.(type) { + case addressableValue: + return result{x.d, pointerToValue{v.a}} + case nil: + return x + } + return e.err("can't take address") + } + + x := e.evalNode(n.X, false) + if x.v == nil { + return x + } + switch v := x.v.(type) { +m4_define(UNARY_INT_OPS, @case $1: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + case token.XOR: + v = ^v + default: + return e.err("invalid operation") + } + return result{x.d, v} +@) +m4_define(UNARY_FLOAT_OPS, @case $1: + switch n.Op { + case token.ADD: + case token.SUB: + v = -v + default: + return e.err("invalid operation") + } + return result{x.d, v} +@) + UNARY_INT_OPS(int8) + UNARY_INT_OPS(int16) + UNARY_INT_OPS(int32) + UNARY_INT_OPS(int64) + UNARY_INT_OPS(uint8) + UNARY_INT_OPS(uint16) + UNARY_INT_OPS(uint32) + UNARY_INT_OPS(uint64) + UNARY_FLOAT_OPS(float32) + UNARY_FLOAT_OPS(float64) + UNARY_FLOAT_OPS(complex64) + UNARY_FLOAT_OPS(complex128) + case untInt: + switch n.Op { + case token.ADD: + case token.SUB: + v.Int.Neg(v.Int) + case token.XOR: + v.Int.Not(v.Int) + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case untRune: + switch n.Op { + case token.ADD: + case token.SUB: + v.Int.Neg(v.Int) + case token.XOR: + v.Int.Not(v.Int) + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case untFloat: + switch n.Op { + case token.ADD: + case token.SUB: + v.Float.Neg(v.Float) + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case untComplex: + switch n.Op { + case token.ADD: + case token.SUB: + v.r.Neg(v.r) + v.i.Neg(v.i) + default: + return e.err("invalid operation") + } + return result{x.d, v} + + case bool: + switch n.Op { + case token.NOT: + v = !v + default: + return e.err("invalid operation") + } + return result{x.d, v} + } + + case *ast.BinaryExpr: + x := e.evalNode(n.X, false) + if x.v == nil { + return x + } + y := e.evalNode(n.Y, false) + if y.v == nil { + return y + } + return e.evalBinaryOp(n.Op, x, y) + } + return e.err("invalid expression") +} + +// evalBinaryOp evaluates a binary operator op applied to x and y. +func (e *evaluator) evalBinaryOp(op token.Token, x, y result) result { + if op == token.NEQ { + tmp := e.evalBinaryOp(token.EQL, x, y) + b, ok := tmp.v.(bool) + if !ok { + return tmp + } + return result{nil, !b} + } + if op == token.GTR { + return e.evalBinaryOp(token.LSS, y, x) + } + if op == token.GEQ { + return e.evalBinaryOp(token.LEQ, x, y) + } + + x = convertUntyped(x, y) + y = convertUntyped(y, x) + + switch a := x.v.(type) { +m4_define(INT_OPS, @case $1: + b, ok := y.v.($1) + if !ok { + return e.err("type mismatch") + } + var c $1 + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.OR: + c = a | b + case token.XOR: + c = a ^ b + case token.MUL: + c = a * b + case token.QUO: + if b == 0 { + return e.err("integer divide by zero") + } + c = a / b + case token.REM: + if b == 0 { + return e.err("integer divide by zero") + } + c = a % b + case token.AND: + c = a & b + case token.AND_NOT: + c = a &^ b + default: + return e.err("invalid operation") + } + return result{x.d, c} +@) +m4_define(UINT_OPS, @case $1: + b, ok := y.v.($1) + if !ok { + return e.err("type mismatch") + } + var c $1 + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.OR: + c = a | b + case token.XOR: + c = a ^ b + case token.MUL: + c = a * b + case token.QUO: + if b == 0 { + return e.err("integer divide by zero") + } + c = a / b + case token.REM: + if b == 0 { + return e.err("integer divide by zero") + } + c = a % b + case token.AND: + c = a & b + case token.AND_NOT: + c = a &^ b + default: + return e.err("invalid operation") + } + return result{x.d, c} +@) +m4_define(FLOAT_OPS, @case $1: + b, ok := y.v.($1) + if !ok { + return e.err("type mismatch") + } + var c $1 + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.MUL: + c = a * b + case token.QUO: + c = a / b + default: + return e.err("invalid operation") + } + return result{x.d, c} +@) +m4_define(COMPLEX_OPS, @case $1: + b, ok := y.v.($1) + if !ok { + return e.err("type mismatch") + } + var c $1 + switch op { + case token.EQL: + return result{nil, a == b} + case token.ADD: + c = a + b + case token.SUB: + c = a - b + case token.MUL: + c = a * b + case token.QUO: + c = a / b + default: + return e.err("invalid operation") + } + return result{x.d, c} +@) + INT_OPS(int8) + INT_OPS(int16) + INT_OPS(int32) + INT_OPS(int64) + UINT_OPS(uint8) + UINT_OPS(uint16) + UINT_OPS(uint32) + UINT_OPS(uint64) + FLOAT_OPS(float32) + FLOAT_OPS(float64) + COMPLEX_OPS(complex64) + COMPLEX_OPS(complex128) + case bool: + b, ok := y.v.(bool) + if !ok { + return e.err("type mismatch") + } + var c bool + switch op { + case token.LOR: + c = a || b + case token.LAND: + c = a && b + case token.EQL: + c = a == b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case debug.String: + b, ok := y.v.(debug.String) + if !ok { + return e.err("type mismatch") + } + var c debug.String + switch op { + // TODO: these comparison operators only use the part of the string that + // was read. Very large strings do not have their entire contents read by + // server.value. + case token.EQL: + return result{nil, a.Length == b.Length && a.String == b.String} + case token.LSS: + return result{nil, a.String < b.String} + case token.LEQ: + return result{nil, a.String <= b.String} + case token.ADD: + c.Length = a.Length + b.Length + if a.Length == uint64(len(a.String)) { + c.String = a.String + b.String + } else { + // The first string was truncated at a.Length characters, so the sum + // must be truncated there too. + c.String = a.String + } + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case untString: + b, ok := y.v.(untString) + if !ok { + return e.err("type mismatch") + } + var c untString + switch op { + case token.EQL: + return result{nil, a == b} + case token.LSS: + return result{nil, a < b} + case token.LEQ: + return result{nil, a <= b} + case token.ADD: + c = a + b + default: + return e.err("invalid operation") + } + return result{x.d, c} + + case untInt: + i := a.Int + b, ok := y.v.(untInt) + if !ok { + return e.err("type mismatch") + } + switch op { + case token.EQL: + return result{nil, i.Cmp(b.Int) == 0} + case token.LSS: + return result{nil, i.Cmp(b.Int) < 0} + case token.LEQ: + return result{nil, i.Cmp(b.Int) <= 0} + } + c := new(big.Int) + switch op { + case token.ADD: + c.Add(i, b.Int) + case token.SUB: + c.Sub(i, b.Int) + case token.OR: + c.Or(i, b.Int) + case token.XOR: + c.Xor(i, b.Int) + case token.MUL: + c.Mul(i, b.Int) + case token.QUO: + if b.Sign() == 0 { + return e.err("integer divide by zero") + } + c.Quo(i, b.Int) + case token.REM: + if b.Sign() == 0 { + return e.err("integer divide by zero") + } + c.Mod(i, b.Int) + case token.AND: + c.And(i, b.Int) + case token.AND_NOT: + c.AndNot(i, b.Int) + default: + return e.err("invalid operation") + } + return result{nil, untInt{c}} + + case untRune: + i := a.Int + b, ok := y.v.(untRune) + if !ok { + return e.err("type mismatch") + } + switch op { + case token.EQL: + return result{nil, i.Cmp(b.Int) == 0} + case token.LSS: + return result{nil, i.Cmp(b.Int) < 0} + case token.LEQ: + return result{nil, i.Cmp(b.Int) <= 0} + } + c := new(big.Int) + switch op { + case token.ADD: + c.Add(i, b.Int) + case token.SUB: + c.Sub(i, b.Int) + case token.OR: + c.Or(i, b.Int) + case token.XOR: + c.Xor(i, b.Int) + case token.MUL: + c.Mul(i, b.Int) + case token.QUO: + if b.Sign() == 0 { + return e.err("integer divide by zero") + } + c.Quo(i, b.Int) + case token.REM: + if b.Sign() == 0 { + return e.err("integer divide by zero") + } + c.Mod(i, b.Int) + case token.AND: + c.And(i, b.Int) + case token.AND_NOT: + c.AndNot(i, b.Int) + default: + return e.err("invalid operation") + } + return result{nil, untRune{c}} + + case untFloat: + r := a.Float + b, ok := y.v.(untFloat) + if !ok { + return e.err("type mismatch") + } + switch op { + case token.EQL: + return result{nil, r.Cmp(b.Float) == 0} + case token.LSS: + return result{nil, r.Cmp(b.Float) < 0} + case token.LEQ: + return result{nil, r.Cmp(b.Float) <= 0} + } + c := new(big.Float) + switch op { + case token.ADD: + c.Add(r, b.Float) + case token.SUB: + c.Sub(r, b.Float) + case token.MUL: + c.Mul(r, b.Float) + case token.QUO: + if b.Sign() == 0 { + return e.err("divide by zero") + } + c.Quo(r, b.Float) + default: + return e.err("invalid operation") + } + return result{nil, untFloat{c}} + + case untComplex: + b, ok := y.v.(untComplex) + if !ok { + return e.err("type mismatch") + } + var ( + ar = a.r + br = b.r + ai = a.i + bi = b.i + ) + if op == token.EQL { + return result{nil, ar.Cmp(br) == 0 && ai.Cmp(bi) == 0} + } + var ( + cr = new(big.Float) + ci = new(big.Float) + ) + switch op { + case token.ADD: + cr.Add(ar, br) + ci.Add(ai, bi) + case token.SUB: + cr.Sub(ar, br) + ci.Sub(ai, bi) + case token.MUL: + var t0, t1 big.Float + t0.Mul(ar, br) + t1.Mul(ai, bi) + cr.Sub(&t0, &t1) + t0.Mul(ar, bi) + t1.Mul(ai, br) + ci.Add(&t0, &t1) + case token.QUO: + // a/b = a*conj(b)/|b|^2 + var t0, t1 big.Float + cr.Mul(ar, br) + t0.Mul(ai, bi) + cr.Add(cr, &t0) // cr = Re(a*conj(b)) + ci.Mul(ai, br) + t0.Mul(ar, bi) + ci.Sub(ci, &t0) // ci = Im(a*conj(b)) + t0.Mul(br, br) + t1.Mul(bi, bi) + t0.Add(&t0, &t1) // t0 = |b|^2 + if t0.Sign() == 0 { + return e.err("divide by zero") + } + cr.Quo(cr, &t0) // cr = Re(a*conj(b))/|b|^2 = Re(a/b) + ci.Quo(ci, &t0) // ci = Im(a*conj(b))/|b|^2 = Im(a/b) + } + return result{nil, untComplex{cr, ci}} + } + + return e.err("invalid operation") +} + +// findLocalVar finds a local variable (or function parameter) by name, and +// returns its address and DWARF type. It returns a nil type on failure. +// The PC and SP are used to determine the current function and stack frame. +func (s *Server) findLocalVar(name string, pc, sp uint64) (uint64, dwarf.Type) { + // Find the DWARF entry for the function at pc. + funcEntry, _, err := s.dwarfData.PCToFunction(uint64(pc)) + if err != nil { + return 0, nil + } + + // Compute the stack frame pointer. + fpOffset, err := s.dwarfData.PCToSPOffset(uint64(pc)) + if err != nil { + return 0, nil + } + framePointer := sp + uint64(fpOffset) + + // Check each child of the function's DWARF entry to see if it is a parameter + // or local variable with the right name. If so, return its address and type. + r := s.dwarfData.Reader() + r.Seek(funcEntry.Offset) + for { + varEntry, err := r.Next() + if err != nil { + break + } + if varEntry.Tag == 0 { + // This tag marks the end of the function's DWARF entry's children. + break + } + + // Check this entry corresponds to a local variable or function parameter, + // that it has the correct name, and that we can get its type and location. + // If so, return them. + if varEntry.Tag != dwarf.TagFormalParameter && varEntry.Tag != dwarf.TagVariable { + continue + } + varName, ok := varEntry.Val(dwarf.AttrName).(string) + if !ok { + continue + } + if varName != name { + continue + } + varTypeOffset, ok := varEntry.Val(dwarf.AttrType).(dwarf.Offset) + if !ok { + continue + } + varType, err := s.dwarfData.Type(varTypeOffset) + if err != nil { + continue + } + locationAttribute := varEntry.Val(dwarf.AttrLocation) + if locationAttribute == nil { + continue + } + locationDescription, ok := locationAttribute.([]uint8) + if !ok { + continue + } + frameOffset, err := evalLocation(locationDescription) + if err != nil { + continue + } + return framePointer + uint64(frameOffset), varType + } + + return 0, nil +} + +// findGlobalVar finds a global variable by name, and returns its address and +// DWARF type. It returns a nil type on failure. +func (s *Server) findGlobalVar(name string) (uint64, dwarf.Type) { + entry, err := s.dwarfData.LookupVariable(name) + if err != nil { + return 0, nil + } + loc, err := s.dwarfData.EntryLocation(entry) + if err != nil { + return 0, nil + } + ofs, err := s.dwarfData.EntryTypeOffset(entry) + if err != nil { + return 0, nil + } + typ, err := s.dwarfData.Type(ofs) + if err != nil { + return 0, nil + } + return loc, typ +} + +// intFromInteger converts an untyped integer constant to an int32 or int64, +// depending on the int size of the debugged program. +// It returns an error on overflow, or if it can't determine the int size. +func (e *evaluator) intFromInteger(v untInt) (interface{}, error) { + t, ok := e.getBaseType("int") + if !ok { + return nil, errors.New("couldn't get int size from DWARF info") + } + switch t.Common().ByteSize { + case 4: + if v.Cmp(bigIntMaxInt32) == +1 || v.Cmp(bigIntMinInt32) == -1 { + return nil, errors.New("constant overflows int") + } + return int32(v.Int64()), nil + case 8: + if v.Cmp(bigIntMaxInt64) == +1 || v.Cmp(bigIntMinInt64) == -1 { + return nil, errors.New("constant overflows int") + } + return v.Int64(), nil + } + return nil, errors.New("invalid int size in DWARF info") +} + +// uint8Result constructs a result for a uint8 value. +func (e *evaluator) uint8Result(v uint8) result { + t, ok := e.getBaseType("uint8") + if !ok { + e.err("couldn't construct uint8") + } + return result{t, uint8(v)} +} + +// stringResult constructs a result for a string value. +func (e *evaluator) stringResult(s string) result { + t, ok := e.getBaseType("string") + if !ok { + e.err("couldn't construct string") + } + return result{t, debug.String{Length: uint64(len(s)), String: s}} +} + +// getBaseType returns the *dwarf.Type with a given name. +// TODO: cache this. +func (e *evaluator) getBaseType(name string) (dwarf.Type, bool) { + entry, err := e.server.dwarfData.LookupEntry(name) + if err != nil { + return nil, false + } + t, err := e.server.dwarfData.Type(entry.Offset) + if err != nil { + return nil, false + } + return t, true +} + +// resultFrom constructs a result corresponding to a value in the program with +// the given address and DWARF type. +// If getAddress is true, the result will be the operand of an address expression, +// so resultFrom returns a result containing a value of type addressableValue. +func (e *evaluator) resultFrom(a uint64, t dwarf.Type, getAddress bool) result { + if a == 0 { + return e.err("nil pointer dereference") + } + if getAddress { + return result{t, addressableValue{a}} + } + v, err := e.server.value(t, a) + if err != nil { + return e.err(err.Error()) + } + return result{t, v} +} + +// zero returns the zero value of type t. +// TODO: implement for array and struct. +func (e *evaluator) zero(t dwarf.Type) result { + var v interface{} + switch typ := followTypedefs(t).(type) { + case *dwarf.CharType, *dwarf.IntType, *dwarf.EnumType: + switch typ.Common().ByteSize { + case 1: + v = int8(0) + case 2: + v = int16(0) + case 4: + v = int32(0) + case 8: + v = int64(0) + default: + return e.err("invalid integer size " + fmt.Sprint(typ.Common().ByteSize)) + } + case *dwarf.UcharType, *dwarf.UintType: + switch typ.Common().ByteSize { + case 1: + v = uint8(0) + case 2: + v = uint16(0) + case 4: + v = uint32(0) + case 8: + v = uint64(0) + default: + return e.err("invalid unsigned integer size " + fmt.Sprint(typ.Common().ByteSize)) + } + case *dwarf.FloatType: + switch typ.Common().ByteSize { + case 4: + v = float32(0) + case 8: + v = float64(0) + default: + return e.err("invalid float size " + fmt.Sprint(typ.Common().ByteSize)) + } + case *dwarf.ComplexType: + switch typ.Common().ByteSize { + case 8: + v = complex64(0) + case 16: + v = complex128(0) + default: + return e.err("invalid complex size " + fmt.Sprint(typ.Common().ByteSize)) + } + case *dwarf.BoolType: + v = false + case *dwarf.PtrType: + v = debug.Pointer{TypeID: uint64(t.Common().Offset)} + case *dwarf.SliceType: + v = debug.Slice{ + Array: debug.Array{ + ElementTypeID: uint64(typ.ElemType.Common().Offset), + StrideBits: uint64(typ.ElemType.Common().ByteSize) * 8, + }, + } + case *dwarf.StringType: + v = debug.String{} + case *dwarf.InterfaceType: + v = debug.Interface{} + case *dwarf.FuncType: + v = debug.Func{} + case *dwarf.MapType: + v = debug.Map{TypeID: uint64(t.Common().Offset)} + case *dwarf.ChanType: + v = debug.Channel{ + ElementTypeID: uint64(typ.ElemType.Common().Offset), + Stride: uint64(typ.ElemType.Common().ByteSize), + } + default: + return e.err("can't get zero value of this type") + } + return result{t, v} +} + +// convertUntyped converts x to be the same type as y, if x is untyped and the +// conversion is possible. +// +// An untyped bool can be converted to a boolean type. +// An untyped string can be converted to a string type. +// An untyped integer, rune, float or complex value can be converted to a +// numeric type, or to an untyped value later in that list. +// +// x is returned unchanged if none of these cases apply. +func convertUntyped(x, y result) result { + switch a := x.v.(type) { + case untInt: + i := a.Int + switch y.v.(type) { + case int8: + return result{y.d, int8(i.Int64())} + case int16: + return result{y.d, int16(i.Int64())} + case int32: + return result{y.d, int32(i.Int64())} + case int64: + return result{y.d, int64(i.Int64())} + case uint8: + return result{y.d, uint8(i.Uint64())} + case uint16: + return result{y.d, uint16(i.Uint64())} + case uint32: + return result{y.d, uint32(i.Uint64())} + case uint64: + return result{y.d, uint64(i.Uint64())} + case float32: + f, _ := new(big.Float).SetInt(i).Float32() + return result{y.d, f} + case float64: + f, _ := new(big.Float).SetInt(i).Float64() + return result{y.d, f} + case complex64: + f, _ := new(big.Float).SetInt(i).Float32() + return result{y.d, complex(f, 0)} + case complex128: + f, _ := new(big.Float).SetInt(i).Float64() + return result{y.d, complex(f, 0)} + case untRune: + return result{nil, untRune{i}} + case untFloat: + return result{nil, untFloat{new(big.Float).SetPrec(prec).SetInt(i)}} + case untComplex: + return result{nil, untComplex{new(big.Float).SetPrec(prec).SetInt(i), new(big.Float)}} + } + case untRune: + i := a.Int + switch y.v.(type) { + case int8: + return result{y.d, int8(i.Int64())} + case int16: + return result{y.d, int16(i.Int64())} + case int32: + return result{y.d, int32(i.Int64())} + case int64: + return result{y.d, int64(i.Int64())} + case uint8: + return result{y.d, uint8(i.Uint64())} + case uint16: + return result{y.d, uint16(i.Uint64())} + case uint32: + return result{y.d, uint32(i.Uint64())} + case uint64: + return result{y.d, uint64(i.Uint64())} + case float32: + f, _ := new(big.Float).SetInt(i).Float32() + return result{y.d, f} + case float64: + f, _ := new(big.Float).SetInt(i).Float64() + return result{y.d, f} + case complex64: + f, _ := new(big.Float).SetInt(i).Float32() + return result{y.d, complex(f, 0)} + case complex128: + f, _ := new(big.Float).SetInt(i).Float64() + return result{y.d, complex(f, 0)} + case untRune: + return result{nil, untRune{i}} + case untFloat: + return result{nil, untFloat{new(big.Float).SetPrec(prec).SetInt(i)}} + case untComplex: + return result{nil, untComplex{new(big.Float).SetPrec(prec).SetInt(i), new(big.Float)}} + } + case untFloat: + if a.IsInt() { + i, _ := a.Int(nil) + switch y.v.(type) { + case int8: + return result{y.d, int8(i.Int64())} + case int16: + return result{y.d, int16(i.Int64())} + case int32: + return result{y.d, int32(i.Int64())} + case int64: + return result{y.d, int64(i.Int64())} + case uint8: + return result{y.d, uint8(i.Uint64())} + case uint16: + return result{y.d, uint16(i.Uint64())} + case uint32: + return result{y.d, uint32(i.Uint64())} + case uint64: + return result{y.d, uint64(i.Uint64())} + } + } + switch y.v.(type) { + case float32: + f, _ := a.Float32() + return result{y.d, float32(f)} + case float64: + f, _ := a.Float64() + return result{y.d, float64(f)} + case complex64: + f, _ := a.Float32() + return result{y.d, complex(f, 0)} + case complex128: + f, _ := a.Float64() + return result{y.d, complex(f, 0)} + case untComplex: + return result{nil, untComplex{a.Float, new(big.Float)}} + } + case untComplex: + if a.i.Sign() == 0 { + // a is a real number. + if a.r.IsInt() { + // a is an integer. + i, _ := a.r.Int(nil) + switch y.v.(type) { + case int8: + return result{y.d, int8(i.Int64())} + case int16: + return result{y.d, int16(i.Int64())} + case int32: + return result{y.d, int32(i.Int64())} + case int64: + return result{y.d, int64(i.Int64())} + case uint8: + return result{y.d, uint8(i.Uint64())} + case uint16: + return result{y.d, uint16(i.Uint64())} + case uint32: + return result{y.d, uint32(i.Uint64())} + case uint64: + return result{y.d, uint64(i.Uint64())} + } + } + switch y.v.(type) { + case float32: + f, _ := a.r.Float32() + return result{y.d, float32(f)} + case float64: + f, _ := a.r.Float64() + return result{y.d, float64(f)} + } + } + switch y.v.(type) { + case complex64: + r, _ := a.r.Float32() + i, _ := a.i.Float32() + return result{y.d, complex(r, i)} + case complex128: + r, _ := a.r.Float64() + i, _ := a.i.Float64() + return result{y.d, complex(r, i)} + } + case bool: + if x.d != nil { + // x is a typed bool, not an untyped bool. + break + } + switch y.v.(type) { + case bool: + return result{y.d, bool(a)} + } + case untString: + switch y.v.(type) { + case debug.String: + return result{y.d, debug.String{Length: uint64(len(a)), String: string(a)}} + } + } + return x +} + +// uint64FromResult converts a result into a uint64 for slice or index expressions. +// It returns an error if the conversion cannot be done. +func uint64FromResult(x result) (uint64, error) { + switch v := x.v.(type) { + case int8: + if v < 0 { + return 0, errors.New("value is negative") + } + return uint64(v), nil + case int16: + if v < 0 { + return 0, errors.New("value is negative") + } + return uint64(v), nil + case int32: + if v < 0 { + return 0, errors.New("value is negative") + } + return uint64(v), nil + case int64: + if v < 0 { + return 0, errors.New("value is negative") + } + return uint64(v), nil + case uint8: + return uint64(v), nil + case uint16: + return uint64(v), nil + case uint32: + return uint64(v), nil + case uint64: + return v, nil + case untInt: + if v.Int.Sign() == -1 { + return 0, errors.New("value is negative") + } + if v.Int.Cmp(bigIntMaxUint64) == +1 { + return 0, errors.New("value is too large") + } + return v.Int.Uint64(), nil + case untRune: + if v.Sign() == -1 { + return 0, errors.New("value is negative") + } + if v.Cmp(bigIntMaxUint64) == +1 { + return 0, errors.New("value is too large") + } + return v.Uint64(), nil + case untFloat: + if !v.IsInt() { + return 0, errors.New("value is not an integer") + } + if v.Sign() == -1 { + return 0, errors.New("value is negative") + } + i, _ := v.Int(nil) + if i.Cmp(bigIntMaxUint64) == +1 { + return 0, errors.New("value is too large") + } + return i.Uint64(), nil + case untComplex: + if v.i.Sign() != 0 { + return 0, errors.New("value is complex") + } + if !v.r.IsInt() { + return 0, errors.New("value is not an integer") + } + if v.r.Sign() == -1 { + return 0, errors.New("value is negative") + } + i, _ := v.r.Int(nil) + if i.Cmp(bigIntMaxUint64) == +1 { + return 0, errors.New("value is too large") + } + return i.Uint64(), nil + } + return 0, fmt.Errorf("cannot convert to unsigned integer") +} + +// followTypedefs returns the underlying type of t, removing any typedefs. +// If t leads to a cycle of typedefs, followTypedefs returns nil. +func followTypedefs(t dwarf.Type) dwarf.Type { + // If t is a *dwarf.TypedefType, next returns t.Type, otherwise it returns t. + // The bool returned is true when the argument was a typedef. + next := func(t dwarf.Type) (dwarf.Type, bool) { + tt, ok := t.(*dwarf.TypedefType) + if !ok { + return t, false + } + return tt.Type, true + } + // Advance two pointers, one at twice the speed, so we can detect if we get + // stuck in a cycle. + slow, fast := t, t + for { + var wasTypedef bool + fast, wasTypedef = next(fast) + if !wasTypedef { + return fast + } + fast, wasTypedef = next(fast) + if !wasTypedef { + return fast + } + slow, _ = next(slow) + if slow == fast { + return nil + } + } +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/peek.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/peek.go new file mode 100644 index 00000000..8b0e11ba --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/peek.go @@ -0,0 +1,378 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// Functions for reading values of various types from a program's memory. + +// +build linux + +package server + +import ( + "errors" + "fmt" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" +) + +// peekBytes reads len(buf) bytes at addr. +func (s *Server) peekBytes(addr uint64, buf []byte) error { + return s.ptracePeek(s.stoppedPid, uintptr(addr), buf) +} + +// peekPtr reads a pointer at addr. +func (s *Server) peekPtr(addr uint64) (uint64, error) { + buf := make([]byte, s.arch.PointerSize) + if err := s.peekBytes(addr, buf); err != nil { + return 0, err + } + return s.arch.Uintptr(buf), nil +} + +// peekUint8 reads a single byte at addr. +func (s *Server) peekUint8(addr uint64) (byte, error) { + buf := make([]byte, 1) + if err := s.peekBytes(addr, buf); err != nil { + return 0, err + } + return uint8(s.arch.UintN(buf)), nil +} + +// peekInt reads an int of size n bytes at addr. +func (s *Server) peekInt(addr uint64, n int64) (int64, error) { + buf := make([]byte, n) + if err := s.peekBytes(addr, buf); err != nil { + return 0, err + } + return s.arch.IntN(buf), nil +} + +// peekUint reads a uint of size n bytes at addr. +func (s *Server) peekUint(addr uint64, n int64) (uint64, error) { + buf := make([]byte, n) + if err := s.peekBytes(addr, buf); err != nil { + return 0, err + } + return s.arch.UintN(buf), nil +} + +// peekSlice reads the header of a slice with the given type and address. +func (s *Server) peekSlice(t *dwarf.SliceType, addr uint64) (debug.Slice, error) { + ptr, err := s.peekPtrStructField(&t.StructType, addr, "array") + if err != nil { + return debug.Slice{}, fmt.Errorf("reading slice location: %s", err) + } + length, err := s.peekUintOrIntStructField(&t.StructType, addr, "len") + if err != nil { + return debug.Slice{}, fmt.Errorf("reading slice length: %s", err) + } + capacity, err := s.peekUintOrIntStructField(&t.StructType, addr, "cap") + if err != nil { + return debug.Slice{}, fmt.Errorf("reading slice capacity: %s", err) + } + if capacity < length { + return debug.Slice{}, fmt.Errorf("slice's capacity %d is less than its length %d", capacity, length) + } + + return debug.Slice{ + debug.Array{ + ElementTypeID: uint64(t.ElemType.Common().Offset), + Address: uint64(ptr), + Length: length, + StrideBits: uint64(t.ElemType.Common().ByteSize) * 8, + }, + capacity, + }, nil +} + +// peekString reads a string of the given type at the given address. +// At most byteLimit bytes will be read. If the string is longer, "..." is appended. +func (s *Server) peekString(typ *dwarf.StringType, a uint64, byteLimit uint64) (string, error) { + ptr, err := s.peekPtrStructField(&typ.StructType, a, "str") + if err != nil { + return "", err + } + length, err := s.peekUintOrIntStructField(&typ.StructType, a, "len") + if err != nil { + return "", err + } + if length > byteLimit { + buf := make([]byte, byteLimit, byteLimit+3) + if err := s.peekBytes(ptr, buf); err != nil { + return "", err + } else { + buf = append(buf, '.', '.', '.') + return string(buf), nil + } + } else { + buf := make([]byte, length) + if err := s.peekBytes(ptr, buf); err != nil { + return "", err + } else { + return string(buf), nil + } + } +} + +// peekCString reads a NUL-terminated string at the given address. +// At most byteLimit bytes will be read. If the string is longer, "..." is appended. +// peekCString never returns errors; if an error occurs, the string will be truncated in some way. +func (s *Server) peekCString(a uint64, byteLimit uint64) string { + buf := make([]byte, byteLimit, byteLimit+3) + s.peekBytes(a, buf) + for i, c := range buf { + if c == 0 { + return string(buf[0:i]) + } + } + buf = append(buf, '.', '.', '.') + return string(buf) +} + +// peekPtrStructField reads a pointer in the field fieldName of the struct +// of type t at addr. +func (s *Server) peekPtrStructField(t *dwarf.StructType, addr uint64, fieldName string) (uint64, error) { + f, err := getField(t, fieldName) + if err != nil { + return 0, fmt.Errorf("reading field %s: %s", fieldName, err) + } + if _, ok := f.Type.(*dwarf.PtrType); !ok { + return 0, fmt.Errorf("field %s is not a pointer", fieldName) + } + return s.peekPtr(addr + uint64(f.ByteOffset)) +} + +// peekUintOrIntStructField reads a signed or unsigned integer in the field fieldName +// of the struct of type t at addr. If the value is negative, it returns an error. +// This function is used when the value should be non-negative, but the DWARF +// type of the field may be signed or unsigned. +func (s *Server) peekUintOrIntStructField(t *dwarf.StructType, addr uint64, fieldName string) (uint64, error) { + f, err := getField(t, fieldName) + if err != nil { + return 0, fmt.Errorf("reading field %s: %s", fieldName, err) + } + ut, ok := f.Type.(*dwarf.UintType) + if ok { + return s.peekUint(addr+uint64(f.ByteOffset), ut.ByteSize) + } + it, ok := f.Type.(*dwarf.IntType) + if !ok { + return 0, fmt.Errorf("field %s is not an integer", fieldName) + } + i, err := s.peekInt(addr+uint64(f.ByteOffset), it.ByteSize) + if err != nil { + return 0, err + } + if i < 0 { + return 0, fmt.Errorf("field %s is negative", fieldName) + } + return uint64(i), nil +} + +// peekUintStructField reads a uint in the field fieldName of the struct +// of type t at addr. The size of the uint is determined by the field. +func (s *Server) peekUintStructField(t *dwarf.StructType, addr uint64, fieldName string) (uint64, error) { + f, err := getField(t, fieldName) + if err != nil { + return 0, fmt.Errorf("reading field %s: %s", fieldName, err) + } + ut, ok := f.Type.(*dwarf.UintType) + if !ok { + return 0, fmt.Errorf("field %s is not an unsigned integer", fieldName) + } + return s.peekUint(addr+uint64(f.ByteOffset), ut.ByteSize) +} + +// peekIntStructField reads an int in the field fieldName of the struct +// of type t at addr. The size of the int is determined by the field. +func (s *Server) peekIntStructField(t *dwarf.StructType, addr uint64, fieldName string) (int64, error) { + f, err := getField(t, fieldName) + if err != nil { + return 0, fmt.Errorf("reading field %s: %s", fieldName, err) + } + it, ok := f.Type.(*dwarf.IntType) + if !ok { + return 0, fmt.Errorf("field %s is not a signed integer", fieldName) + } + return s.peekInt(addr+uint64(f.ByteOffset), it.ByteSize) +} + +// peekStringStructField reads a string field from the struct of the given type +// at the given address. +// At most byteLimit bytes will be read. If the string is longer, "..." is appended. +func (s *Server) peekStringStructField(t *dwarf.StructType, addr uint64, fieldName string, byteLimit uint64) (string, error) { + f, err := getField(t, fieldName) + if err != nil { + return "", fmt.Errorf("reading field %s: %s", fieldName, err) + } + st, ok := followTypedefs(f.Type).(*dwarf.StringType) + if !ok { + return "", fmt.Errorf("field %s is not a string", fieldName) + } + return s.peekString(st, addr+uint64(f.ByteOffset), byteLimit) +} + +// peekMapLocationAndType returns the address and DWARF type of the underlying +// struct of a map variable. +func (s *Server) peekMapLocationAndType(t *dwarf.MapType, a uint64) (uint64, *dwarf.StructType, error) { + // Maps are pointers to structs. + pt, ok := t.Type.(*dwarf.PtrType) + if !ok { + return 0, nil, errors.New("bad map type: not a pointer") + } + st, ok := pt.Type.(*dwarf.StructType) + if !ok { + return 0, nil, errors.New("bad map type: not a pointer to a struct") + } + // a is the address of a pointer to a struct. Get the pointer's value. + a, err := s.peekPtr(a) + if err != nil { + return 0, nil, fmt.Errorf("reading map pointer: %s", err) + } + return a, st, nil +} + +// peekMapValues reads a map at the given address and calls fn with the addresses for each (key, value) pair. +// If fn returns false, peekMapValues stops. +func (s *Server) peekMapValues(t *dwarf.MapType, a uint64, fn func(keyAddr, valAddr uint64, keyType, valType dwarf.Type) bool) error { + a, st, err := s.peekMapLocationAndType(t, a) + if err != nil { + return err + } + if a == 0 { + // The pointer was nil, so the map is empty. + return nil + } + // Gather information about the struct type and the map bucket type. + b, err := s.peekUintStructField(st, a, "B") + if err != nil { + return fmt.Errorf("reading map: %s", err) + } + buckets, err := s.peekPtrStructField(st, a, "buckets") + if err != nil { + return fmt.Errorf("reading map: %s", err) + } + oldbuckets, err := s.peekPtrStructField(st, a, "oldbuckets") + if err != nil { + return fmt.Errorf("reading map: %s", err) + } + bf, err := getField(st, "buckets") + if err != nil { + return fmt.Errorf("reading map: %s", err) + } + bucketPtrType, ok := bf.Type.(*dwarf.PtrType) + if !ok { + return errors.New("bad map bucket type: not a pointer") + } + bt, ok := bucketPtrType.Type.(*dwarf.StructType) + if !ok { + return errors.New("bad map bucket type: not a pointer to a struct") + } + bucketSize := uint64(bucketPtrType.Type.Size()) + tophashField, err := getField(bt, "tophash") + if err != nil { + return fmt.Errorf("reading map: %s", err) + } + bucketCnt := uint64(tophashField.Type.Size()) + tophashFieldOffset := uint64(tophashField.ByteOffset) + keysField, err := getField(bt, "keys") + if err != nil { + return fmt.Errorf("reading map: %s", err) + } + keysType, ok := keysField.Type.(*dwarf.ArrayType) + if !ok { + return errors.New(`bad map bucket type: "keys" is not an array`) + } + keyType := keysType.Type + keysStride := uint64(keysType.StrideBitSize / 8) + keysFieldOffset := uint64(keysField.ByteOffset) + valuesField, err := getField(bt, "values") + if err != nil { + return fmt.Errorf("reading map: %s", err) + } + valuesType, ok := valuesField.Type.(*dwarf.ArrayType) + if !ok { + return errors.New(`bad map bucket type: "values" is not an array`) + } + valueType := valuesType.Type + valuesStride := uint64(valuesType.StrideBitSize / 8) + valuesFieldOffset := uint64(valuesField.ByteOffset) + overflowField, err := getField(bt, "overflow") + if err != nil { + return fmt.Errorf("reading map: %s", err) + } + overflowFieldOffset := uint64(overflowField.ByteOffset) + + // Iterate through the two arrays of buckets. + bucketArrays := [2]struct { + addr uint64 + size uint64 + }{ + {buckets, 1 << b}, + {oldbuckets, 1 << (b - 1)}, + } + for _, bucketArray := range bucketArrays { + if bucketArray.addr == 0 { + continue + } + for i := uint64(0); i < bucketArray.size; i++ { + bucketAddr := bucketArray.addr + i*bucketSize + // Iterate through the linked list of buckets. + // TODO: check for repeated bucket pointers. + for bucketAddr != 0 { + // Iterate through each entry in the bucket. + for j := uint64(0); j < bucketCnt; j++ { + tophash, err := s.peekUint8(bucketAddr + tophashFieldOffset + j) + if err != nil { + return errors.New("reading map: " + err.Error()) + } + // From runtime/hashmap.go + const minTopHash = 4 + if tophash < minTopHash { + continue + } + keyAddr := bucketAddr + keysFieldOffset + j*keysStride + valAddr := bucketAddr + valuesFieldOffset + j*valuesStride + if !fn(keyAddr, valAddr, keyType, valueType) { + return nil + } + } + var err error + bucketAddr, err = s.peekPtr(bucketAddr + overflowFieldOffset) + if err != nil { + return errors.New("reading map: " + err.Error()) + } + } + } + } + + return nil +} + +// peekMapLength returns the number of elements in a map at the given address. +func (s *Server) peekMapLength(t *dwarf.MapType, a uint64) (uint64, error) { + a, st, err := s.peekMapLocationAndType(t, a) + if err != nil { + return 0, err + } + if a == 0 { + // The pointer was nil, so the map is empty. + return 0, nil + } + length, err := s.peekUintOrIntStructField(st, a, "count") + if err != nil { + return 0, fmt.Errorf("reading map: %s", err) + } + return uint64(length), nil +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/print.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/print.go new file mode 100644 index 00000000..7a004e5a --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/print.go @@ -0,0 +1,548 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// +build linux + +package server + +import ( + "bytes" + "fmt" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/arch" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" +) + +// typeAndAddress associates an address in the target with a DWARF type. +type typeAndAddress struct { + Type dwarf.Type + Address uint64 +} + +// Routines to print a value using DWARF type descriptions. +// TODO: Does this deserve its own package? It has no dependencies on Server. + +// A Printer pretty-prints values in the target address space. +// It can be reused after each printing operation to avoid unnecessary +// allocations. However, it is not safe for concurrent access. +type Printer struct { + err error // Sticky error value. + server *Server + dwarf *dwarf.Data + arch *arch.Architecture + printBuf bytes.Buffer // Accumulates the output. + visited map[typeAndAddress]bool // Prevents looping on cyclic data. +} + +// printf prints to printBuf. +func (p *Printer) printf(format string, args ...interface{}) { + fmt.Fprintf(&p.printBuf, format, args...) +} + +// errorf prints the error to printBuf, then sets the sticky error for the +// printer, if not already set. +func (p *Printer) errorf(format string, args ...interface{}) { + fmt.Fprintf(&p.printBuf, "<"+format+">", args...) + if p.err != nil { + return + } + p.err = fmt.Errorf(format, args...) +} + +// NewPrinter returns a printer that can use the Server to access and print +// values of the specified architecture described by the provided DWARF data. +func NewPrinter(arch *arch.Architecture, dwarf *dwarf.Data, server *Server) *Printer { + return &Printer{ + server: server, + arch: arch, + dwarf: dwarf, + visited: make(map[typeAndAddress]bool), + } +} + +// reset resets the Printer. It must be called before starting a new +// printing operation. +func (p *Printer) reset() { + p.err = nil + p.printBuf.Reset() + // Just wipe the map rather than reallocating. It's almost always tiny. + for k := range p.visited { + delete(p.visited, k) + } +} + +// Sprint returns the pretty-printed value of the item with the given name, such as "main.global". +func (p *Printer) Sprint(name string) (string, error) { + entry, err := p.dwarf.LookupEntry(name) + if err != nil { + return "", err + } + p.reset() + switch entry.Tag { + case dwarf.TagVariable: // TODO: What other entries have global location attributes? + var a uint64 + iface := entry.Val(dwarf.AttrLocation) + if iface != nil { + a = p.decodeLocation(iface.([]byte)) + } + p.printEntryValueAt(entry, a) + default: + p.errorf("unrecognized entry type %s", entry.Tag) + } + return p.printBuf.String(), p.err +} + +// Figure 24 of DWARF v4. +const ( + locationAddr = 0x03 +) + +// decodeLocation decodes the dwarf data describing an address. +func (p *Printer) decodeLocation(data []byte) uint64 { + switch data[0] { + case locationAddr: + return p.arch.Uintptr(data[1:]) + default: + p.errorf("unimplemented location type %#x", data[0]) + } + return 0 +} + +// SprintEntry returns the pretty-printed value of the item with the specified DWARF Entry and address. +func (p *Printer) SprintEntry(entry *dwarf.Entry, a uint64) (string, error) { + p.reset() + p.printEntryValueAt(entry, a) + return p.printBuf.String(), p.err +} + +// printEntryValueAt pretty-prints the data at the specified address. +// using the type information in the Entry. +func (p *Printer) printEntryValueAt(entry *dwarf.Entry, a uint64) { + if a == 0 { + p.printf("") + return + } + switch entry.Tag { + case dwarf.TagVariable, dwarf.TagFormalParameter: + // OK + default: + p.errorf("unrecognized entry type %s", entry.Tag) + return + } + iface := entry.Val(dwarf.AttrType) + if iface == nil { + p.errorf("no type") + return + } + typ, err := p.dwarf.Type(iface.(dwarf.Offset)) + if err != nil { + p.errorf("type lookup: %v", err) + return + } + p.printValueAt(typ, a) +} + +// printValueAt pretty-prints the data at the specified address. +// using the provided type information. +func (p *Printer) printValueAt(typ dwarf.Type, a uint64) { + if a != 0 { + // Check if we are repeating the same type and address. + ta := typeAndAddress{typ, a} + if p.visited[ta] { + p.printf("(%v %#x)", typ, a) + return + } + p.visited[ta] = true + } + switch typ := typ.(type) { + case *dwarf.BoolType: + if typ.ByteSize != 1 { + p.errorf("unrecognized bool size %d", typ.ByteSize) + return + } + if b, err := p.server.peekUint8(a); err != nil { + p.errorf("reading bool: %s", err) + } else { + p.printf("%t", b != 0) + } + case *dwarf.PtrType: + if ptr, err := p.server.peekPtr(a); err != nil { + p.errorf("reading pointer: %s", err) + } else { + p.printf("%#x", ptr) + } + case *dwarf.IntType: + // Sad we can't tell a rune from an int32. + if i, err := p.server.peekInt(a, typ.ByteSize); err != nil { + p.errorf("reading integer: %s", err) + } else { + p.printf("%d", i) + } + case *dwarf.UintType: + if u, err := p.server.peekUint(a, typ.ByteSize); err != nil { + p.errorf("reading unsigned integer: %s", err) + } else { + p.printf("%d", u) + } + case *dwarf.FloatType: + buf := make([]byte, typ.ByteSize) + if err := p.server.peekBytes(a, buf); err != nil { + p.errorf("reading float: %s", err) + return + } + switch typ.ByteSize { + case 4: + p.printf("%g", p.arch.Float32(buf)) + case 8: + p.printf("%g", p.arch.Float64(buf)) + default: + p.errorf("unrecognized float size %d", typ.ByteSize) + } + case *dwarf.ComplexType: + buf := make([]byte, typ.ByteSize) + if err := p.server.peekBytes(a, buf); err != nil { + p.errorf("reading complex: %s", err) + return + } + switch typ.ByteSize { + case 8: + p.printf("%g", p.arch.Complex64(buf)) + case 16: + p.printf("%g", p.arch.Complex128(buf)) + default: + p.errorf("unrecognized complex size %d", typ.ByteSize) + } + case *dwarf.StructType: + if typ.Kind != "struct" { + // Could be "class" or "union". + p.errorf("can't handle struct type %s", typ.Kind) + return + } + p.printf("%s {", typ.String()) + for i, field := range typ.Field { + if i != 0 { + p.printf(", ") + } + p.printValueAt(field.Type, a+uint64(field.ByteOffset)) + } + p.printf("}") + case *dwarf.ArrayType: + p.printArrayAt(typ, a) + case *dwarf.InterfaceType: + p.printInterfaceAt(typ, a) + case *dwarf.MapType: + p.printMapAt(typ, a) + case *dwarf.ChanType: + p.printChannelAt(typ, a) + case *dwarf.SliceType: + p.printSliceAt(typ, a) + case *dwarf.StringType: + p.printStringAt(typ, a) + case *dwarf.TypedefType: + p.printValueAt(typ.Type, a) + case *dwarf.FuncType: + p.printf("%v @%#x ", typ, a) + case *dwarf.VoidType: + p.printf("void") + default: + p.errorf("unimplemented type %v", typ) + } +} + +func (p *Printer) printArrayAt(typ *dwarf.ArrayType, a uint64) { + elemType := typ.Type + length := typ.Count + stride, ok := p.arrayStride(typ) + if !ok { + p.errorf("can't determine element size") + } + p.printf("%s{", typ) + n := length + if n > 100 { + n = 100 // TODO: Have a way to control this? + } + for i := int64(0); i < n; i++ { + if i != 0 { + p.printf(", ") + } + p.printValueAt(elemType, a) + a += stride // TODO: Alignment and padding - not given by Type + } + if n < length { + p.printf(", ...") + } + p.printf("}") +} + +func (p *Printer) printInterfaceAt(t *dwarf.InterfaceType, a uint64) { + // t embeds a TypedefType, which may point to another typedef. + // The underlying type should be a struct. + st, ok := followTypedefs(&t.TypedefType).(*dwarf.StructType) + if !ok { + p.errorf("bad interface type: not a struct") + return + } + p.printf("(") + tab, err := p.server.peekPtrStructField(st, a, "tab") + if err != nil { + p.errorf("reading interface type: %s", err) + } else { + f, err := getField(st, "tab") + if err != nil { + p.errorf("%s", err) + } else { + p.printTypeOfInterface(f.Type, tab) + } + } + p.printf(", ") + data, err := p.server.peekPtrStructField(st, a, "data") + if err != nil { + p.errorf("reading interface value: %s", err) + } else if data == 0 { + p.printf("") + } else { + p.printf("%#x", data) + } + p.printf(")") +} + +// printTypeOfInterface prints the type of the given tab pointer. +func (p *Printer) printTypeOfInterface(t dwarf.Type, a uint64) { + if a == 0 { + p.printf("") + return + } + // t should be a pointer to a struct containing _type, which is a pointer to a + // struct containing _string, which is the name of the type. + // Depending on the compiler version, some of these types can be typedefs, and + // _string may be a string or a *string. + t1, ok := followTypedefs(t).(*dwarf.PtrType) + if !ok { + p.errorf("interface's tab is not a pointer") + return + } + t2, ok := followTypedefs(t1.Type).(*dwarf.StructType) + if !ok { + p.errorf("interface's tab is not a pointer to struct") + return + } + typeField, err := getField(t2, "_type") + if err != nil { + p.errorf("%s", err) + return + } + t3, ok := followTypedefs(typeField.Type).(*dwarf.PtrType) + if !ok { + p.errorf("interface's _type is not a pointer") + return + } + t4, ok := followTypedefs(t3.Type).(*dwarf.StructType) + if !ok { + p.errorf("interface's _type is not a pointer to struct") + return + } + stringField, err := getField(t4, "_string") + if err != nil { + p.errorf("%s", err) + return + } + if t5, ok := stringField.Type.(*dwarf.PtrType); ok { + stringType, ok := t5.Type.(*dwarf.StringType) + if !ok { + p.errorf("interface _string is a pointer to %T, want string or *string", t5.Type) + return + } + typeAddr, err := p.server.peekPtrStructField(t2, a, "_type") + if err != nil { + p.errorf("reading interface type: %s", err) + return + } + stringAddr, err := p.server.peekPtrStructField(t4, typeAddr, "_string") + if err != nil { + p.errorf("reading interface type: %s", err) + return + } + p.printStringAt(stringType, stringAddr) + } else { + stringType, ok := stringField.Type.(*dwarf.StringType) + if !ok { + p.errorf("interface _string is a %T, want string or *string", stringField.Type) + return + } + typeAddr, err := p.server.peekPtrStructField(t2, a, "_type") + if err != nil { + p.errorf("reading interface type: %s", err) + return + } + stringAddr := typeAddr + uint64(stringField.ByteOffset) + p.printStringAt(stringType, stringAddr) + } +} + +// maxMapValuesToPrint values are printed for each map; any remaining values are +// truncated to "...". +const maxMapValuesToPrint = 8 + +func (p *Printer) printMapAt(typ *dwarf.MapType, a uint64) { + count := 0 + fn := func(keyAddr, valAddr uint64, keyType, valType dwarf.Type) (stop bool) { + count++ + if count > maxMapValuesToPrint { + return false + } + if count > 1 { + p.printf(" ") + } + p.printValueAt(keyType, keyAddr) + p.printf(":") + p.printValueAt(valType, valAddr) + return true + } + p.printf("map[") + if err := p.server.peekMapValues(typ, a, fn); err != nil { + p.errorf("reading map values: %s", err) + } + if count > maxMapValuesToPrint { + p.printf(" ...") + } + p.printf("]") +} + +func (p *Printer) printChannelAt(ct *dwarf.ChanType, a uint64) { + p.printf("(chan %s ", ct.ElemType) + defer p.printf(")") + + a, err := p.server.peekPtr(a) + if err != nil { + p.errorf("reading channel: %s", err) + return + } + if a == 0 { + p.printf("") + return + } + p.printf("%#x", a) + + // ct is a typedef for a pointer to a struct. + pt, ok := ct.TypedefType.Type.(*dwarf.PtrType) + if !ok { + p.errorf("bad channel type: not a pointer") + return + } + st, ok := pt.Type.(*dwarf.StructType) + if !ok { + p.errorf("bad channel type: not a pointer to a struct") + return + } + + // Print the channel buffer's length (qcount) and capacity (dataqsiz), + // if not 0/0. + qcount, err := p.server.peekUintOrIntStructField(st, a, "qcount") + if err != nil { + p.errorf("reading channel: %s", err) + return + } + dataqsiz, err := p.server.peekUintOrIntStructField(st, a, "dataqsiz") + if err != nil { + p.errorf("reading channel: %s", err) + return + } + if qcount != 0 || dataqsiz != 0 { + p.printf(" [%d/%d]", qcount, dataqsiz) + } +} + +func (p *Printer) printSliceAt(typ *dwarf.SliceType, a uint64) { + // Slices look like a struct with fields array *elemtype, len uint32/64, cap uint32/64. + // BUG: Slice header appears to have fields with ByteSize == 0 + ptr, err := p.server.peekPtrStructField(&typ.StructType, a, "array") + if err != nil { + p.errorf("reading slice: %s", err) + return + } + length, err := p.server.peekUintOrIntStructField(&typ.StructType, a, "len") + if err != nil { + p.errorf("reading slice: %s", err) + return + } + // Capacity is not used yet. + _, err = p.server.peekUintOrIntStructField(&typ.StructType, a, "cap") + if err != nil { + p.errorf("reading slice: %s", err) + return + } + elemType := typ.ElemType + size, ok := p.sizeof(typ.ElemType) + if !ok { + p.errorf("can't determine element size") + } + p.printf("%s{", typ) + for i := uint64(0); i < length; i++ { + if i != 0 { + p.printf(", ") + } + p.printValueAt(elemType, ptr) + ptr += size // TODO: Alignment and padding - not given by Type + } + p.printf("}") +} + +func (p *Printer) printStringAt(typ *dwarf.StringType, a uint64) { + const maxStringSize = 100 + if s, err := p.server.peekString(typ, a, maxStringSize); err != nil { + p.errorf("reading string: %s", err) + } else { + p.printf("%q", s) + } +} + +// sizeof returns the byte size of the type. +func (p *Printer) sizeof(typ dwarf.Type) (uint64, bool) { + size := typ.Size() // Will be -1 if ByteSize is not set. + if size >= 0 { + return uint64(size), true + } + switch typ.(type) { + case *dwarf.PtrType: + // This is the only one we know of, but more may arise. + return uint64(p.arch.PointerSize), true + } + return 0, false +} + +// arrayStride returns the stride of a dwarf.ArrayType in bytes. +func (p *Printer) arrayStride(t *dwarf.ArrayType) (uint64, bool) { + stride := t.StrideBitSize + if stride > 0 { + return uint64(stride / 8), true + } + return p.sizeof(t.Type) +} + +// getField finds the *dwarf.StructField in a dwarf.StructType with name fieldName. +func getField(t *dwarf.StructType, fieldName string) (*dwarf.StructField, error) { + var r *dwarf.StructField + for _, f := range t.Field { + if f.Name == fieldName { + if r != nil { + return nil, fmt.Errorf("struct definition repeats field %s", fieldName) + } + r = f + } + } + if r == nil { + return nil, fmt.Errorf("struct field %s missing", fieldName) + } + return r, nil +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/protocol/protocol.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/protocol/protocol.go new file mode 100644 index 00000000..31c852c0 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/protocol/protocol.go @@ -0,0 +1,174 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 protocol defines the types used to represent calls to the debug server. +package protocol + +import ( + "encoding/gob" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" +) + +func init() { + // Register implementations of debug.Value with gob. + gob.Register(debug.Pointer{}) + gob.Register(debug.Array{}) + gob.Register(debug.Struct{}) + gob.Register(debug.Slice{}) + gob.Register(debug.Map{}) + gob.Register(debug.String{}) + gob.Register(debug.Channel{}) + gob.Register(debug.Func{}) + gob.Register(debug.Interface{}) +} + +// For regularity, each method has a unique Request and a Response type even +// when not strictly necessary. + +// File I/O, at the top because they're simple. + +type ReadAtRequest struct { + FD int + Len int + Offset int64 +} + +type ReadAtResponse struct { + Data []byte +} + +type WriteAtRequest struct { + FD int + Data []byte + Offset int64 +} + +type WriteAtResponse struct { + Len int +} + +type CloseRequest struct { + FD int +} + +type CloseResponse struct { +} + +// Program methods. + +type OpenRequest struct { + Name string + Mode string +} + +type OpenResponse struct { + FD int +} + +type RunRequest struct { + Args []string +} + +type RunResponse struct { + Status debug.Status +} + +type ResumeRequest struct { +} + +type ResumeResponse struct { + Status debug.Status +} + +type BreakpointRequest struct { + Address uint64 +} + +type BreakpointAtFunctionRequest struct { + Function string +} + +type BreakpointAtLineRequest struct { + File string + Line uint64 +} + +type BreakpointResponse struct { + PCs []uint64 +} + +type DeleteBreakpointsRequest struct { + PCs []uint64 +} + +type DeleteBreakpointsResponse struct { +} + +type EvalRequest struct { + Expr string +} + +type EvalResponse struct { + Result []string +} + +type EvaluateRequest struct { + Expression string +} + +type EvaluateResponse struct { + Result debug.Value +} + +type FramesRequest struct { + Count int +} + +type FramesResponse struct { + Frames []debug.Frame +} + +type VarByNameRequest struct { + Name string +} + +type VarByNameResponse struct { + Var debug.Var +} + +type ValueRequest struct { + Var debug.Var +} + +type ValueResponse struct { + Value debug.Value +} + +type MapElementRequest struct { + Map debug.Map + Index uint64 +} + +type MapElementResponse struct { + Key debug.Var + Value debug.Var +} + +type GoroutinesRequest struct { +} + +type GoroutinesResponse struct { + Goroutines []*debug.Goroutine +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/ptrace.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/ptrace.go new file mode 100644 index 00000000..dba82454 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/ptrace.go @@ -0,0 +1,157 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// +build linux + +package server + +import ( + "fmt" + "os" + "runtime" + "syscall" + "time" +) + +// ptraceRun runs all the closures from fc on a dedicated OS thread. Errors +// are returned on ec. Both channels must be unbuffered, to ensure that the +// resultant error is sent back to the same goroutine that sent the closure. +func ptraceRun(fc chan func() error, ec chan error) { + if cap(fc) != 0 || cap(ec) != 0 { + panic("ptraceRun was given buffered channels") + } + runtime.LockOSThread() + for f := range fc { + ec <- f() + } +} + +func (s *Server) startProcess(name string, argv []string, attr *os.ProcAttr) (proc *os.Process, err error) { + s.fc <- func() error { + var err1 error + proc, err1 = os.StartProcess(name, argv, attr) + return err1 + } + err = <-s.ec + return +} + +func (s *Server) ptraceCont(pid int, signal int) (err error) { + s.fc <- func() error { + return syscall.PtraceCont(pid, signal) + } + return <-s.ec +} + +func (s *Server) ptraceGetRegs(pid int, regsout *syscall.PtraceRegs) (err error) { + s.fc <- func() error { + return syscall.PtraceGetRegs(pid, regsout) + } + return <-s.ec +} + +func (s *Server) ptracePeek(pid int, addr uintptr, out []byte) (err error) { + s.fc <- func() error { + n, err := syscall.PtracePeekText(pid, addr, out) + if err != nil { + return err + } + if n != len(out) { + return fmt.Errorf("ptracePeek: peeked %d bytes, want %d", n, len(out)) + } + return nil + } + return <-s.ec +} + +func (s *Server) ptracePoke(pid int, addr uintptr, data []byte) (err error) { + s.fc <- func() error { + n, err := syscall.PtracePokeText(pid, addr, data) + if err != nil { + return err + } + if n != len(data) { + return fmt.Errorf("ptracePoke: poked %d bytes, want %d", n, len(data)) + } + return nil + } + return <-s.ec +} + +func (s *Server) ptraceSetOptions(pid int, options int) (err error) { + s.fc <- func() error { + return syscall.PtraceSetOptions(pid, options) + } + return <-s.ec +} + +func (s *Server) ptraceSetRegs(pid int, regs *syscall.PtraceRegs) (err error) { + s.fc <- func() error { + return syscall.PtraceSetRegs(pid, regs) + } + return <-s.ec +} + +func (s *Server) ptraceSingleStep(pid int) (err error) { + s.fc <- func() error { + return syscall.PtraceSingleStep(pid) + } + return <-s.ec +} + +type breakpointsChangedError struct { + call call +} + +func (*breakpointsChangedError) Error() string { + return "breakpoints changed" +} + +func (s *Server) wait(pid int, allowBreakpointsChange bool) (wpid int, status syscall.WaitStatus, err error) { + // We poll syscall.Wait4 with WNOHANG, sleeping in between, as a poor man's + // waitpid-with-timeout. This allows adding and removing breakpoints + // concurrently with waiting to hit an existing breakpoint. + f := func() error { + var err1 error + wpid, err1 = syscall.Wait4(pid, &status, syscall.WALL|syscall.WNOHANG, nil) + return err1 + } + + const ( + minSleep = 1 * time.Microsecond + maxSleep = 100 * time.Millisecond + ) + for sleep := minSleep; ; { + s.fc <- f + err = <-s.ec + + // wpid == 0 means that wait found nothing (and returned due to WNOHANG). + if wpid != 0 { + return + } + + if allowBreakpointsChange { + select { + case c := <-s.breakpointc: + return 0, 0, &breakpointsChangedError{c} + default: + } + } + + time.Sleep(sleep) + if sleep < maxSleep { + sleep *= 10 + } + } +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/server.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/server.go new file mode 100644 index 00000000..6bed24f1 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/server.go @@ -0,0 +1,1136 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// +build linux + +// Package server provides RPC access to a local program being debugged. +// It is the remote end of the client implementation of the Program interface. +package server + +//go:generate sh -c "m4 -P eval.m4 > eval.go" + +import ( + "bytes" + "errors" + "fmt" + "os" + "regexp" + "strconv" + "strings" + "sync" + "syscall" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/arch" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/protocol" +) + +type breakpoint struct { + pc uint64 + origInstr [arch.MaxBreakpointSize]byte +} + +type call struct { + req, resp interface{} + errc chan error +} + +type Server struct { + arch arch.Architecture + executable string // Name of executable. + dwarfData *dwarf.Data + + breakpointc chan call + otherc chan call + + fc chan func() error + ec chan error + + proc *os.Process + procIsUp bool + stoppedPid int + stoppedRegs syscall.PtraceRegs + topOfStackAddrs []uint64 + breakpoints map[uint64]breakpoint + files []*file // Index == file descriptor. + printer *Printer + + // goroutineStack reads the stack of a (non-running) goroutine. + goroutineStack func(uint64) ([]debug.Frame, error) + goroutineStackOnce sync.Once +} + +// peek implements the Peeker interface required by the printer. +func (s *Server) peek(offset uintptr, buf []byte) error { + return s.ptracePeek(s.stoppedPid, offset, buf) +} + +// New parses the executable and builds local data structures for answering requests. +// It returns a Server ready to serve requests about the executable. +func New(executable string) (*Server, error) { + fd, err := os.Open(executable) + if err != nil { + return nil, err + } + defer fd.Close() + architecture, dwarfData, err := loadExecutable(fd) + if err != nil { + return nil, err + } + srv := &Server{ + arch: *architecture, + executable: executable, + dwarfData: dwarfData, + breakpointc: make(chan call), + otherc: make(chan call), + fc: make(chan func() error), + ec: make(chan error), + breakpoints: make(map[uint64]breakpoint), + } + srv.printer = NewPrinter(architecture, dwarfData, srv) + go ptraceRun(srv.fc, srv.ec) + go srv.loop() + return srv, nil +} + +func loadExecutable(f *os.File) (*arch.Architecture, *dwarf.Data, error) { + // TODO: How do we detect NaCl? + if obj, err := elf.NewFile(f); err == nil { + dwarfData, err := obj.DWARF() + if err != nil { + return nil, nil, err + } + + switch obj.Machine { + case elf.EM_ARM: + return &arch.ARM, dwarfData, nil + case elf.EM_386: + switch obj.Class { + case elf.ELFCLASS32: + return &arch.X86, dwarfData, nil + case elf.ELFCLASS64: + return &arch.AMD64, dwarfData, nil + } + case elf.EM_X86_64: + return &arch.AMD64, dwarfData, nil + } + return nil, nil, fmt.Errorf("unrecognized ELF architecture") + } + return nil, nil, fmt.Errorf("unrecognized binary format") +} + +func (s *Server) loop() { + for { + var c call + select { + case c = <-s.breakpointc: + case c = <-s.otherc: + } + s.dispatch(c) + } +} + +func (s *Server) dispatch(c call) { + switch req := c.req.(type) { + case *protocol.BreakpointRequest: + c.errc <- s.handleBreakpoint(req, c.resp.(*protocol.BreakpointResponse)) + case *protocol.BreakpointAtFunctionRequest: + c.errc <- s.handleBreakpointAtFunction(req, c.resp.(*protocol.BreakpointResponse)) + case *protocol.BreakpointAtLineRequest: + c.errc <- s.handleBreakpointAtLine(req, c.resp.(*protocol.BreakpointResponse)) + case *protocol.DeleteBreakpointsRequest: + c.errc <- s.handleDeleteBreakpoints(req, c.resp.(*protocol.DeleteBreakpointsResponse)) + case *protocol.CloseRequest: + c.errc <- s.handleClose(req, c.resp.(*protocol.CloseResponse)) + case *protocol.EvalRequest: + c.errc <- s.handleEval(req, c.resp.(*protocol.EvalResponse)) + case *protocol.EvaluateRequest: + c.errc <- s.handleEvaluate(req, c.resp.(*protocol.EvaluateResponse)) + case *protocol.FramesRequest: + c.errc <- s.handleFrames(req, c.resp.(*protocol.FramesResponse)) + case *protocol.OpenRequest: + c.errc <- s.handleOpen(req, c.resp.(*protocol.OpenResponse)) + case *protocol.ReadAtRequest: + c.errc <- s.handleReadAt(req, c.resp.(*protocol.ReadAtResponse)) + case *protocol.ResumeRequest: + c.errc <- s.handleResume(req, c.resp.(*protocol.ResumeResponse)) + case *protocol.RunRequest: + c.errc <- s.handleRun(req, c.resp.(*protocol.RunResponse)) + case *protocol.VarByNameRequest: + c.errc <- s.handleVarByName(req, c.resp.(*protocol.VarByNameResponse)) + case *protocol.ValueRequest: + c.errc <- s.handleValue(req, c.resp.(*protocol.ValueResponse)) + case *protocol.MapElementRequest: + c.errc <- s.handleMapElement(req, c.resp.(*protocol.MapElementResponse)) + case *protocol.GoroutinesRequest: + c.errc <- s.handleGoroutines(req, c.resp.(*protocol.GoroutinesResponse)) + default: + panic(fmt.Sprintf("unexpected call request type %T", c.req)) + } +} + +func (s *Server) call(c chan call, req, resp interface{}) error { + errc := make(chan error) + c <- call{req, resp, errc} + return <-errc +} + +type file struct { + mode string + index int + f debug.File +} + +func (s *Server) Open(req *protocol.OpenRequest, resp *protocol.OpenResponse) error { + return s.call(s.otherc, req, resp) +} + +func (s *Server) handleOpen(req *protocol.OpenRequest, resp *protocol.OpenResponse) error { + // TODO: Better simulation. For now we just open the named OS file. + var flag int + switch req.Mode { + case "r": + flag = os.O_RDONLY + case "w": + flag = os.O_WRONLY + case "rw": + flag = os.O_RDWR + default: + return fmt.Errorf("Open: bad open mode %q", req.Mode) + } + osFile, err := os.OpenFile(req.Name, flag, 0) + if err != nil { + return err + } + // Find a file descriptor (index) slot. + index := 0 + for ; index < len(s.files) && s.files[index] != nil; index++ { + } + f := &file{ + mode: req.Mode, + index: index, + f: osFile, + } + if index == len(s.files) { + s.files = append(s.files, f) + } else { + s.files[index] = f + } + return nil +} + +func (s *Server) ReadAt(req *protocol.ReadAtRequest, resp *protocol.ReadAtResponse) error { + return s.call(s.otherc, req, resp) +} + +func (s *Server) handleReadAt(req *protocol.ReadAtRequest, resp *protocol.ReadAtResponse) error { + fd := req.FD + if fd < 0 || len(s.files) <= fd || s.files[fd] == nil { + return fmt.Errorf("ReadAt: bad file descriptor %d", fd) + } + f := s.files[fd] + buf := make([]byte, req.Len) // TODO: Don't allocate every time + n, err := f.f.ReadAt(buf, req.Offset) + resp.Data = buf[:n] + return err +} + +func (s *Server) Close(req *protocol.CloseRequest, resp *protocol.CloseResponse) error { + return s.call(s.otherc, req, resp) +} + +func (s *Server) handleClose(req *protocol.CloseRequest, resp *protocol.CloseResponse) error { + fd := req.FD + if fd < 0 || fd >= len(s.files) || s.files[fd] == nil { + return fmt.Errorf("Close: bad file descriptor %d", fd) + } + err := s.files[fd].f.Close() + // Remove it regardless + s.files[fd] = nil + return err +} + +func (s *Server) Run(req *protocol.RunRequest, resp *protocol.RunResponse) error { + return s.call(s.otherc, req, resp) +} + +func (s *Server) handleRun(req *protocol.RunRequest, resp *protocol.RunResponse) error { + if s.proc != nil { + s.proc.Kill() + s.proc = nil + s.procIsUp = false + s.stoppedPid = 0 + s.stoppedRegs = syscall.PtraceRegs{} + s.topOfStackAddrs = nil + } + argv := append([]string{s.executable}, req.Args...) + p, err := s.startProcess(s.executable, argv, &os.ProcAttr{ + Files: []*os.File{ + nil, // TODO: be able to feed the target's stdin. + os.Stderr, // TODO: be able to capture the target's stdout. + os.Stderr, + }, + Sys: &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGKILL, + Ptrace: true, + }, + }) + if err != nil { + return err + } + s.proc = p + s.stoppedPid = p.Pid + return nil +} + +func (s *Server) Resume(req *protocol.ResumeRequest, resp *protocol.ResumeResponse) error { + return s.call(s.otherc, req, resp) +} + +func (s *Server) handleResume(req *protocol.ResumeRequest, resp *protocol.ResumeResponse) error { + if s.proc == nil { + return fmt.Errorf("Resume: Run did not successfully start a process") + } + + if !s.procIsUp { + s.procIsUp = true + if _, err := s.waitForTrap(s.stoppedPid, false); err != nil { + return err + } + if err := s.ptraceSetOptions(s.stoppedPid, syscall.PTRACE_O_TRACECLONE); err != nil { + return fmt.Errorf("ptraceSetOptions: %v", err) + } + } else if _, ok := s.breakpoints[s.stoppedRegs.Rip]; ok { + if err := s.ptraceSingleStep(s.stoppedPid); err != nil { + return fmt.Errorf("ptraceSingleStep: %v", err) + } + if _, err := s.waitForTrap(s.stoppedPid, false); err != nil { + return err + } + } + + for { + if err := s.setBreakpoints(); err != nil { + return err + } + if err := s.ptraceCont(s.stoppedPid, 0); err != nil { + return fmt.Errorf("ptraceCont: %v", err) + } + + wpid, err := s.waitForTrap(-1, true) + if err == nil { + s.stoppedPid = wpid + break + } + bce, ok := err.(*breakpointsChangedError) + if !ok { + return err + } + + if err := syscall.Kill(s.stoppedPid, syscall.SIGSTOP); err != nil { + return fmt.Errorf("kill(SIGSTOP): %v", err) + } + _, status, err := s.wait(s.stoppedPid, false) + if err != nil { + return fmt.Errorf("wait (after SIGSTOP): %v", err) + } + if !status.Stopped() || status.StopSignal() != syscall.SIGSTOP { + return fmt.Errorf("wait (after SIGSTOP): unexpected wait status 0x%x", status) + } + + if err := s.liftBreakpoints(); err != nil { + return err + } + + loop: + for c := bce.call; ; { + s.dispatch(c) + select { + case c = <-s.breakpointc: + default: + break loop + } + } + } + if err := s.liftBreakpoints(); err != nil { + return err + } + + if err := s.ptraceGetRegs(s.stoppedPid, &s.stoppedRegs); err != nil { + return fmt.Errorf("ptraceGetRegs: %v", err) + } + + s.stoppedRegs.Rip -= uint64(s.arch.BreakpointSize) + + if err := s.ptraceSetRegs(s.stoppedPid, &s.stoppedRegs); err != nil { + return fmt.Errorf("ptraceSetRegs: %v", err) + } + + resp.Status.PC = s.stoppedRegs.Rip + resp.Status.SP = s.stoppedRegs.Rsp + return nil +} + +func (s *Server) waitForTrap(pid int, allowBreakpointsChange bool) (wpid int, err error) { + for { + wpid, status, err := s.wait(pid, allowBreakpointsChange) + if err != nil { + if _, ok := err.(*breakpointsChangedError); !ok { + err = fmt.Errorf("wait: %v", err) + } + return 0, err + } + if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != syscall.PTRACE_EVENT_CLONE { + return wpid, nil + } + if status.StopSignal() == syscall.SIGPROF { + err = s.ptraceCont(wpid, int(syscall.SIGPROF)) + } else { + err = s.ptraceCont(wpid, 0) // TODO: non-zero when wait catches other signals? + } + if err != nil { + return 0, fmt.Errorf("ptraceCont: %v", err) + } + } +} + +func (s *Server) Breakpoint(req *protocol.BreakpointRequest, resp *protocol.BreakpointResponse) error { + return s.call(s.breakpointc, req, resp) +} + +func (s *Server) handleBreakpoint(req *protocol.BreakpointRequest, resp *protocol.BreakpointResponse) error { + return s.addBreakpoints([]uint64{req.Address}, resp) +} + +func (s *Server) BreakpointAtFunction(req *protocol.BreakpointAtFunctionRequest, resp *protocol.BreakpointResponse) error { + return s.call(s.breakpointc, req, resp) +} + +func (s *Server) handleBreakpointAtFunction(req *protocol.BreakpointAtFunctionRequest, resp *protocol.BreakpointResponse) error { + pc, err := s.functionStartAddress(req.Function) + if err != nil { + return err + } + return s.addBreakpoints([]uint64{pc}, resp) +} + +func (s *Server) BreakpointAtLine(req *protocol.BreakpointAtLineRequest, resp *protocol.BreakpointResponse) error { + return s.call(s.breakpointc, req, resp) +} + +func (s *Server) handleBreakpointAtLine(req *protocol.BreakpointAtLineRequest, resp *protocol.BreakpointResponse) error { + if s.dwarfData == nil { + return fmt.Errorf("no DWARF data") + } + if pcs, err := s.dwarfData.LineToBreakpointPCs(req.File, req.Line); err != nil { + return err + } else { + return s.addBreakpoints(pcs, resp) + } +} + +// addBreakpoints adds breakpoints at the addresses in pcs, then stores pcs in the response. +func (s *Server) addBreakpoints(pcs []uint64, resp *protocol.BreakpointResponse) error { + // Get the original code at each address with ptracePeek. + bps := make([]breakpoint, 0, len(pcs)) + for _, pc := range pcs { + if _, alreadySet := s.breakpoints[pc]; alreadySet { + continue + } + var bp breakpoint + if err := s.ptracePeek(s.stoppedPid, uintptr(pc), bp.origInstr[:s.arch.BreakpointSize]); err != nil { + return fmt.Errorf("ptracePeek: %v", err) + } + bp.pc = pc + bps = append(bps, bp) + } + // If all the peeks succeeded, update the list of breakpoints. + for _, bp := range bps { + s.breakpoints[bp.pc] = bp + } + resp.PCs = pcs + return nil +} + +func (s *Server) DeleteBreakpoints(req *protocol.DeleteBreakpointsRequest, resp *protocol.DeleteBreakpointsResponse) error { + return s.call(s.breakpointc, req, resp) +} + +func (s *Server) handleDeleteBreakpoints(req *protocol.DeleteBreakpointsRequest, resp *protocol.DeleteBreakpointsResponse) error { + for _, pc := range req.PCs { + delete(s.breakpoints, pc) + } + return nil +} + +func (s *Server) setBreakpoints() error { + for pc := range s.breakpoints { + err := s.ptracePoke(s.stoppedPid, uintptr(pc), s.arch.BreakpointInstr[:s.arch.BreakpointSize]) + if err != nil { + return fmt.Errorf("setBreakpoints: %v", err) + } + } + return nil +} + +func (s *Server) liftBreakpoints() error { + for pc, breakpoint := range s.breakpoints { + err := s.ptracePoke(s.stoppedPid, uintptr(pc), breakpoint.origInstr[:s.arch.BreakpointSize]) + if err != nil { + return fmt.Errorf("liftBreakpoints: %v", err) + } + } + return nil +} + +func (s *Server) Eval(req *protocol.EvalRequest, resp *protocol.EvalResponse) error { + return s.call(s.otherc, req, resp) +} + +func (s *Server) handleEval(req *protocol.EvalRequest, resp *protocol.EvalResponse) (err error) { + resp.Result, err = s.eval(req.Expr) + return err +} + +// eval evaluates an expression. +// TODO: very weak. +func (s *Server) eval(expr string) ([]string, error) { + switch { + case strings.HasPrefix(expr, "re:"): + // Regular expression. Return list of symbols. + re, err := regexp.Compile(expr[3:]) + if err != nil { + return nil, err + } + return s.dwarfData.LookupMatchingSymbols(re) + + case strings.HasPrefix(expr, "addr:"): + // Symbol lookup. Return address. + addr, err := s.functionStartAddress(expr[5:]) + if err != nil { + return nil, err + } + return []string{fmt.Sprintf("%#x", addr)}, nil + + case strings.HasPrefix(expr, "val:"): + // Symbol lookup. Return formatted value. + value, err := s.printer.Sprint(expr[4:]) + if err != nil { + return nil, err + } + return []string{value}, nil + + case strings.HasPrefix(expr, "src:"): + // Numerical address. Return file.go:123. + addr, err := strconv.ParseUint(expr[4:], 0, 0) + if err != nil { + return nil, err + } + file, line, err := s.lookupSource(addr) + if err != nil { + return nil, err + } + return []string{fmt.Sprintf("%s:%d", file, line)}, nil + + case len(expr) > 0 && '0' <= expr[0] && expr[0] <= '9': + // Numerical address. Return symbol. + addr, err := strconv.ParseUint(expr, 0, 0) + if err != nil { + return nil, err + } + entry, _, err := s.dwarfData.PCToFunction(addr) + if err != nil { + return nil, err + } + name, ok := entry.Val(dwarf.AttrName).(string) + if !ok { + return nil, fmt.Errorf("function at 0x%x has no name", addr) + } + return []string{name}, nil + } + + return nil, fmt.Errorf("bad expression syntax: %q", expr) +} + +func (s *Server) Evaluate(req *protocol.EvaluateRequest, resp *protocol.EvaluateResponse) error { + return s.call(s.otherc, req, resp) +} + +func (s *Server) handleEvaluate(req *protocol.EvaluateRequest, resp *protocol.EvaluateResponse) (err error) { + resp.Result, err = s.evalExpression(req.Expression, s.stoppedRegs.Rip, s.stoppedRegs.Rsp) + return err +} + +func (s *Server) lookupSource(pc uint64) (file string, line uint64, err error) { + if s.dwarfData == nil { + return + } + // TODO: The gosym equivalent also returns the relevant Func. Do that when + // DWARF has the same facility. + return s.dwarfData.PCToLine(pc) +} + +func (s *Server) Frames(req *protocol.FramesRequest, resp *protocol.FramesResponse) error { + return s.call(s.otherc, req, resp) +} + +func (s *Server) handleFrames(req *protocol.FramesRequest, resp *protocol.FramesResponse) error { + // TODO: verify that we're stopped. + if s.topOfStackAddrs == nil { + if err := s.evaluateTopOfStackAddrs(); err != nil { + return err + } + } + + regs := syscall.PtraceRegs{} + err := s.ptraceGetRegs(s.stoppedPid, ®s) + if err != nil { + return err + } + resp.Frames, err = s.walkStack(regs.Rip, regs.Rsp, req.Count) + return err +} + +// walkStack returns up to the requested number of stack frames. +func (s *Server) walkStack(pc, sp uint64, count int) ([]debug.Frame, error) { + var frames []debug.Frame + + var buf [8]byte + b := new(bytes.Buffer) + r := s.dwarfData.Reader() + + // TODO: handle walking over a split stack. + for i := 0; i < count; i++ { + b.Reset() + file, line, err := s.dwarfData.PCToLine(pc) + if err != nil { + return frames, err + } + fpOffset, err := s.dwarfData.PCToSPOffset(pc) + if err != nil { + return frames, err + } + fp := sp + uint64(fpOffset) + entry, funcEntry, err := s.dwarfData.PCToFunction(pc) + if err != nil { + return frames, err + } + frame := debug.Frame{ + PC: pc, + SP: sp, + File: file, + Line: line, + FunctionStart: funcEntry, + } + frame.Function, _ = entry.Val(dwarf.AttrName).(string) + r.Seek(entry.Offset) + for { + entry, err := r.Next() + if err != nil { + return frames, err + } + if entry.Tag == 0 { + break + } + // TODO: report variables we couldn't parse? + if entry.Tag == dwarf.TagFormalParameter { + if v, err := s.parseParameterOrLocal(entry, fp); err == nil { + frame.Params = append(frame.Params, debug.Param(v)) + } + } + if entry.Tag == dwarf.TagVariable { + if v, err := s.parseParameterOrLocal(entry, fp); err == nil { + frame.Vars = append(frame.Vars, v) + } + } + } + frames = append(frames, frame) + + // Walk to the caller's PC and SP. + if s.topOfStack(funcEntry) { + break + } + err = s.ptracePeek(s.stoppedPid, uintptr(fp-uint64(s.arch.PointerSize)), buf[:s.arch.PointerSize]) + if err != nil { + return frames, fmt.Errorf("ptracePeek: %v", err) + } + pc, sp = s.arch.Uintptr(buf[:s.arch.PointerSize]), fp + } + return frames, nil +} + +// parseParameterOrLocal parses the entry for a function parameter or local +// variable, which are both specified the same way. fp contains the frame +// pointer, which is used to calculate the variable location. +func (s *Server) parseParameterOrLocal(entry *dwarf.Entry, fp uint64) (debug.LocalVar, error) { + var v debug.LocalVar + v.Name, _ = entry.Val(dwarf.AttrName).(string) + if off, err := s.dwarfData.EntryTypeOffset(entry); err != nil { + return v, err + } else { + v.Var.TypeID = uint64(off) + } + if i := entry.Val(dwarf.AttrLocation); i == nil { + return v, fmt.Errorf("missing location description") + } else if locationDescription, ok := i.([]uint8); !ok { + return v, fmt.Errorf("unsupported location description") + } else if offset, err := evalLocation(locationDescription); err != nil { + return v, err + } else { + v.Var.Address = fp + uint64(offset) + } + return v, nil +} + +func (s *Server) evaluateTopOfStackAddrs() error { + var ( + lookup func(name string) (uint64, error) + indirect bool + names []string + ) + if _, err := s.dwarfData.LookupVariable("runtime.rt0_goPC"); err != nil { + // Look for a Go 1.3 binary (or earlier version). + lookup, indirect, names = s.functionStartAddress, false, []string{ + "runtime.goexit", + "runtime.mstart", + "runtime.mcall", + "runtime.morestack", + "runtime.lessstack", + "_rt0_go", + } + } else { + // Look for a Go 1.4 binary (or later version). + lookup = func(name string) (uint64, error) { + entry, err := s.dwarfData.LookupVariable(name) + if err != nil { + return 0, err + } + return s.dwarfData.EntryLocation(entry) + } + indirect, names = true, []string{ + "runtime.goexitPC", + "runtime.mstartPC", + "runtime.mcallPC", + "runtime.morestackPC", + "runtime.rt0_goPC", + } + } + // TODO: also look for runtime.externalthreadhandlerp, on Windows. + + addrs := make([]uint64, 0, len(names)) + for _, name := range names { + addr, err := lookup(name) + if err != nil { + return err + } + addrs = append(addrs, addr) + } + + if indirect { + buf := make([]byte, s.arch.PointerSize) + for i, addr := range addrs { + if err := s.ptracePeek(s.stoppedPid, uintptr(addr), buf); err != nil { + return fmt.Errorf("ptracePeek: %v", err) + } + addrs[i] = s.arch.Uintptr(buf) + } + } + + s.topOfStackAddrs = addrs + return nil +} + +// topOfStack is the out-of-process equivalent of runtime·topofstack. +func (s *Server) topOfStack(funcEntry uint64) bool { + for _, addr := range s.topOfStackAddrs { + if addr == funcEntry { + return true + } + } + return false +} + +func (s *Server) VarByName(req *protocol.VarByNameRequest, resp *protocol.VarByNameResponse) error { + return s.call(s.otherc, req, resp) +} + +func (s *Server) handleVarByName(req *protocol.VarByNameRequest, resp *protocol.VarByNameResponse) error { + entry, err := s.dwarfData.LookupVariable(req.Name) + if err != nil { + return fmt.Errorf("variable %s: %s", req.Name, err) + } + + loc, err := s.dwarfData.EntryLocation(entry) + if err != nil { + return fmt.Errorf("variable %s: %s", req.Name, err) + } + + off, err := s.dwarfData.EntryTypeOffset(entry) + if err != nil { + return fmt.Errorf("variable %s: %s", req.Name, err) + } + + resp.Var.TypeID = uint64(off) + resp.Var.Address = loc + return nil +} + +func (s *Server) Value(req *protocol.ValueRequest, resp *protocol.ValueResponse) error { + return s.call(s.otherc, req, resp) +} + +func (s *Server) handleValue(req *protocol.ValueRequest, resp *protocol.ValueResponse) error { + t, err := s.dwarfData.Type(dwarf.Offset(req.Var.TypeID)) + if err != nil { + return err + } + resp.Value, err = s.value(t, req.Var.Address) + return err +} + +func (s *Server) MapElement(req *protocol.MapElementRequest, resp *protocol.MapElementResponse) error { + return s.call(s.otherc, req, resp) +} + +func (s *Server) handleMapElement(req *protocol.MapElementRequest, resp *protocol.MapElementResponse) error { + t, err := s.dwarfData.Type(dwarf.Offset(req.Map.TypeID)) + if err != nil { + return err + } + m, ok := t.(*dwarf.MapType) + if !ok { + return fmt.Errorf("variable is not a map") + } + var count uint64 + // fn will be called for each element of the map. + // When we reach the requested element, we fill in *resp and stop. + // TODO: cache locations of elements. + fn := func(keyAddr, valAddr uint64, keyType, valType dwarf.Type) bool { + count++ + if count == req.Index+1 { + resp.Key = debug.Var{TypeID: uint64(keyType.Common().Offset), Address: keyAddr} + resp.Value = debug.Var{TypeID: uint64(valType.Common().Offset), Address: valAddr} + return false + } + return true + } + if err := s.peekMapValues(m, req.Map.Address, fn); err != nil { + return err + } + if count <= req.Index { + // There weren't enough elements. + return fmt.Errorf("map has no element %d", req.Index) + } + return nil +} + +func (s *Server) Goroutines(req *protocol.GoroutinesRequest, resp *protocol.GoroutinesResponse) error { + return s.call(s.otherc, req, resp) +} + +const invalidStatus debug.GoroutineStatus = 99 + +var ( + gStatus = [...]debug.GoroutineStatus{ + 0: debug.Queued, // _Gidle + 1: debug.Queued, // _Grunnable + 2: debug.Running, // _Grunning + 3: debug.Blocked, // _Gsyscall + 4: debug.Blocked, // _Gwaiting + 5: invalidStatus, // _Gmoribund_unused + 6: invalidStatus, // _Gdead + 7: invalidStatus, // _Genqueue + 8: debug.Running, // _Gcopystack + } + gScanStatus = [...]debug.GoroutineStatus{ + 0: invalidStatus, // _Gscan + _Gidle + 1: debug.Queued, // _Gscanrunnable + 2: debug.Running, // _Gscanrunning + 3: debug.Blocked, // _Gscansyscall + 4: debug.Blocked, // _Gscanwaiting + 5: invalidStatus, // _Gscan + _Gmoribund_unused + 6: invalidStatus, // _Gscan + _Gdead + 7: debug.Queued, // _Gscanenqueue + } + gStatusString = [...]string{ + 0: "idle", + 1: "runnable", + 2: "running", + 3: "syscall", + 4: "waiting", + 8: "copystack", + } + gScanStatusString = [...]string{ + 1: "scanrunnable", + 2: "scanrunning", + 3: "scansyscall", + 4: "scanwaiting", + 7: "scanenqueue", + } +) + +func (s *Server) handleGoroutines(req *protocol.GoroutinesRequest, resp *protocol.GoroutinesResponse) error { + // Get DWARF type information for runtime.g. + ge, err := s.dwarfData.LookupEntry("runtime.g") + if err != nil { + return err + } + t, err := s.dwarfData.Type(ge.Offset) + if err != nil { + return err + } + gType, ok := followTypedefs(t).(*dwarf.StructType) + if !ok { + return errors.New("runtime.g is not a struct") + } + + var ( + allgPtr, allgLen uint64 + allgPtrOk bool + ) + for { + // Try to read the slice runtime.allgs. + allgsEntry, err := s.dwarfData.LookupVariable("runtime.allgs") + if err != nil { + break + } + allgsAddr, err := s.dwarfData.EntryLocation(allgsEntry) + if err != nil { + break + } + off, err := s.dwarfData.EntryTypeOffset(allgsEntry) + if err != nil { + break + } + t, err := s.dwarfData.Type(off) + if err != nil { + break + } + allgsType, ok := followTypedefs(t).(*dwarf.SliceType) + if !ok { + break + } + allgs, err := s.peekSlice(allgsType, allgsAddr) + if err != nil { + break + } + + allgPtr, allgLen, allgPtrOk = allgs.Address, allgs.Length, true + break + } + if !allgPtrOk { + // Read runtime.allg. + allgEntry, err := s.dwarfData.LookupVariable("runtime.allg") + if err != nil { + return err + } + allgAddr, err := s.dwarfData.EntryLocation(allgEntry) + if err != nil { + return err + } + allgPtr, err = s.peekPtr(allgAddr) + if err != nil { + return fmt.Errorf("reading allg: %v", err) + } + + // Read runtime.allglen. + allglenEntry, err := s.dwarfData.LookupVariable("runtime.allglen") + if err != nil { + return err + } + off, err := s.dwarfData.EntryTypeOffset(allglenEntry) + if err != nil { + return err + } + allglenType, err := s.dwarfData.Type(off) + if err != nil { + return err + } + allglenAddr, err := s.dwarfData.EntryLocation(allglenEntry) + if err != nil { + return err + } + switch followTypedefs(allglenType).(type) { + case *dwarf.UintType, *dwarf.IntType: + allgLen, err = s.peekUint(allglenAddr, allglenType.Common().ByteSize) + if err != nil { + return fmt.Errorf("reading allglen: %v", err) + } + default: + // Some runtimes don't specify the type for allglen. Assume it's uint32. + allgLen, err = s.peekUint(allglenAddr, 4) + if err != nil { + return fmt.Errorf("reading allglen: %v", err) + } + if allgLen != 0 { + break + } + // Zero? Let's try uint64. + allgLen, err = s.peekUint(allglenAddr, 8) + if err != nil { + return fmt.Errorf("reading allglen: %v", err) + } + } + } + + // Initialize s.goroutineStack. + s.goroutineStackOnce.Do(func() { s.goroutineStackInit(gType) }) + + for i := uint64(0); i < allgLen; i++ { + // allg is an array of pointers to g structs. Read allg[i]. + g, err := s.peekPtr(allgPtr + i*uint64(s.arch.PointerSize)) + if err != nil { + return err + } + gr := debug.Goroutine{} + + // Read status from the field named "atomicstatus" or "status". + status, err := s.peekUintStructField(gType, g, "atomicstatus") + if err != nil { + status, err = s.peekUintOrIntStructField(gType, g, "status") + } + if err != nil { + return err + } + if status == 6 { + // _Gdead. + continue + } + gr.Status = invalidStatus + if status < uint64(len(gStatus)) { + gr.Status = gStatus[status] + gr.StatusString = gStatusString[status] + } else if status^0x1000 < uint64(len(gScanStatus)) { + gr.Status = gScanStatus[status^0x1000] + gr.StatusString = gScanStatusString[status^0x1000] + } + if gr.Status == invalidStatus { + return fmt.Errorf("unexpected goroutine status 0x%x", status) + } + if status == 4 || status == 0x1004 { + // _Gwaiting or _Gscanwaiting. + // Try reading waitreason to get a better value for StatusString. + // Depending on the runtime, waitreason may be a Go string or a C string. + if waitreason, err := s.peekStringStructField(gType, g, "waitreason", 80); err == nil { + if waitreason != "" { + gr.StatusString = waitreason + } + } else if ptr, err := s.peekPtrStructField(gType, g, "waitreason"); err == nil { + waitreason := s.peekCString(ptr, 80) + if waitreason != "" { + gr.StatusString = waitreason + } + } + } + + gr.ID, err = s.peekIntStructField(gType, g, "goid") + if err != nil { + return err + } + + // Best-effort attempt to get the names of the goroutine function and the + // function that created the goroutine. They aren't always available. + functionName := func(pc uint64) string { + entry, _, err := s.dwarfData.PCToFunction(pc) + if err != nil { + return "" + } + name, _ := entry.Val(dwarf.AttrName).(string) + return name + } + if startpc, err := s.peekUintStructField(gType, g, "startpc"); err == nil { + gr.Function = functionName(startpc) + } + if gopc, err := s.peekUintStructField(gType, g, "gopc"); err == nil { + gr.Caller = functionName(gopc) + } + if gr.Status != debug.Running { + // TODO: running goroutines too. + gr.StackFrames, _ = s.goroutineStack(g) + } + + resp.Goroutines = append(resp.Goroutines, &gr) + } + + return nil +} + +// TODO: let users specify how many frames they want. 10 will be enough to +// determine the reason a goroutine is blocked. +const goroutineStackFrameCount = 10 + +// goroutineStackInit initializes s.goroutineStack. +func (s *Server) goroutineStackInit(gType *dwarf.StructType) { + // If we fail to read the DWARF data needed for s.goroutineStack, calling it + // will always return the error that occurred during initialization. + var err error // err is captured by the func below. + s.goroutineStack = func(gAddr uint64) ([]debug.Frame, error) { + return nil, err + } + + // Get g field "sched", which contains fields pc and sp. + schedField, err := getField(gType, "sched") + if err != nil { + return + } + schedOffset := uint64(schedField.ByteOffset) + schedType, ok := followTypedefs(schedField.Type).(*dwarf.StructType) + if !ok { + err = errors.New(`g field "sched" has the wrong type`) + return + } + + // Get the size of the pc and sp fields and their offsets inside the g struct, + // so we can quickly peek those values for each goroutine later. + var ( + schedPCOffset, schedSPOffset uint64 + schedPCByteSize, schedSPByteSize int64 + ) + for _, x := range []struct { + field string + offset *uint64 + bytesize *int64 + }{ + {"pc", &schedPCOffset, &schedPCByteSize}, + {"sp", &schedSPOffset, &schedSPByteSize}, + } { + var f *dwarf.StructField + f, err = getField(schedType, x.field) + if err != nil { + return + } + *x.offset = schedOffset + uint64(f.ByteOffset) + switch t := followTypedefs(f.Type).(type) { + case *dwarf.UintType, *dwarf.IntType: + *x.bytesize = t.Common().ByteSize + default: + err = fmt.Errorf("gobuf field %q has the wrong type", x.field) + return + } + } + + s.goroutineStack = func(gAddr uint64) ([]debug.Frame, error) { + schedPC, err := s.peekUint(gAddr+schedPCOffset, schedPCByteSize) + if err != nil { + return nil, err + } + schedSP, err := s.peekUint(gAddr+schedSPOffset, schedSPByteSize) + if err != nil { + return nil, err + } + return s.walkStack(schedPC, schedSP, goroutineStackFrameCount) + } +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/value.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/value.go new file mode 100644 index 00000000..324b2443 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/value.go @@ -0,0 +1,260 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// +build linux + +package server + +import ( + "fmt" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf" +) + +// value peeks the program's memory at the given address, parsing it as a value of type t. +func (s *Server) value(t dwarf.Type, addr uint64) (debug.Value, error) { + // readBasic reads the memory for a basic type of size n bytes. + readBasic := func(n int64) ([]byte, error) { + switch n { + case 1, 2, 4, 8, 16: + default: + return nil, fmt.Errorf("invalid size: %d", n) + } + buf := make([]byte, n) + if err := s.peek(uintptr(addr), buf); err != nil { + return nil, err + } + return buf, nil + } + + switch t := t.(type) { + case *dwarf.CharType, *dwarf.IntType: + bs := t.Common().ByteSize + buf, err := readBasic(bs) + if err != nil { + return nil, fmt.Errorf("reading integer: %s", err) + } + x := s.arch.IntN(buf) + switch bs { + case 1: + return int8(x), nil + case 2: + return int16(x), nil + case 4: + return int32(x), nil + case 8: + return int64(x), nil + default: + return nil, fmt.Errorf("invalid integer size: %d", bs) + } + case *dwarf.UcharType, *dwarf.UintType, *dwarf.AddrType: + bs := t.Common().ByteSize + buf, err := readBasic(bs) + if err != nil { + return nil, fmt.Errorf("reading unsigned integer: %s", err) + } + x := s.arch.UintN(buf) + switch bs { + case 1: + return uint8(x), nil + case 2: + return uint16(x), nil + case 4: + return uint32(x), nil + case 8: + return uint64(x), nil + default: + return nil, fmt.Errorf("invalid unsigned integer size: %d", bs) + } + case *dwarf.BoolType: + bs := t.Common().ByteSize + buf, err := readBasic(bs) + if err != nil { + return nil, fmt.Errorf("reading boolean: %s", err) + } + for _, b := range buf { + if b != 0 { + return true, nil + } + } + return false, nil + case *dwarf.FloatType: + bs := t.Common().ByteSize + buf, err := readBasic(bs) + if err != nil { + return nil, fmt.Errorf("reading float: %s", err) + } + switch bs { + case 4: + return s.arch.Float32(buf), nil + case 8: + return s.arch.Float64(buf), nil + default: + return nil, fmt.Errorf("invalid float size: %d", bs) + } + case *dwarf.ComplexType: + bs := t.Common().ByteSize + buf, err := readBasic(bs) + if err != nil { + return nil, fmt.Errorf("reading complex: %s", err) + } + switch bs { + case 8: + return s.arch.Complex64(buf), nil + case 16: + return s.arch.Complex128(buf), nil + default: + return nil, fmt.Errorf("invalid complex size: %d", bs) + } + case *dwarf.PtrType: + bs := t.Common().ByteSize + if bs != int64(s.arch.PointerSize) { + return nil, fmt.Errorf("invalid pointer size: %d", bs) + } + buf, err := readBasic(bs) + if err != nil { + return nil, fmt.Errorf("reading pointer: %s", err) + } + return debug.Pointer{ + TypeID: uint64(t.Type.Common().Offset), + Address: uint64(s.arch.Uintptr(buf)), + }, nil + case *dwarf.SliceType: + if s, err := s.peekSlice(t, addr); err != nil { + return nil, err + } else { + return s, nil + } + case *dwarf.ArrayType: + length := t.Count + stride := t.StrideBitSize + if stride%8 != 0 { + return nil, fmt.Errorf("array is not byte-aligned") + } + return debug.Array{ + ElementTypeID: uint64(t.Type.Common().Offset), + Address: uint64(addr), + Length: uint64(length), + StrideBits: uint64(stride), + }, nil + case *dwarf.StructType: + fields := make([]debug.StructField, len(t.Field)) + for i, field := range t.Field { + fields[i] = debug.StructField{ + Name: field.Name, + Var: debug.Var{ + TypeID: uint64(field.Type.Common().Offset), + Address: uint64(addr) + uint64(field.ByteOffset), + }, + } + } + return debug.Struct{fields}, nil + case *dwarf.TypedefType: + return s.value(t.Type, addr) + case *dwarf.MapType: + length, err := s.peekMapLength(t, addr) + if err != nil { + return nil, err + } + return debug.Map{ + TypeID: uint64(t.Common().Offset), + Address: addr, + Length: length, + }, nil + case *dwarf.StringType: + ptr, err := s.peekPtrStructField(&t.StructType, addr, "str") + if err != nil { + return nil, fmt.Errorf("reading string location: %s", err) + } + length, err := s.peekUintOrIntStructField(&t.StructType, addr, "len") + if err != nil { + return nil, fmt.Errorf("reading string length: %s", err) + } + + const maxStringSize = 256 + + n := length + if n > maxStringSize { + n = maxStringSize + } + tmp := make([]byte, n) + if err := s.peekBytes(ptr, tmp); err != nil { + return nil, fmt.Errorf("reading string contents: %s", err) + } + return debug.String{Length: length, String: string(tmp)}, nil + case *dwarf.ChanType: + pt, ok := t.TypedefType.Type.(*dwarf.PtrType) + if !ok { + return nil, fmt.Errorf("reading channel: type is not a pointer") + } + st, ok := pt.Type.(*dwarf.StructType) + if !ok { + return nil, fmt.Errorf("reading channel: type is not a pointer to struct") + } + + a, err := s.peekPtr(addr) + if err != nil { + return nil, fmt.Errorf("reading channel pointer: %s", err) + } + if a == 0 { + // This channel is nil. + return debug.Channel{ + ElementTypeID: uint64(t.ElemType.Common().Offset), + Address: 0, + Buffer: 0, + Length: 0, + Capacity: 0, + Stride: uint64(t.ElemType.Common().ByteSize), + BufferStart: 0, + }, nil + } + + buf, err := s.peekPtrStructField(st, a, "buf") + if err != nil { + return nil, fmt.Errorf("reading channel buffer location: %s", err) + } + qcount, err := s.peekUintOrIntStructField(st, a, "qcount") + if err != nil { + return nil, fmt.Errorf("reading channel length: %s", err) + } + capacity, err := s.peekUintOrIntStructField(st, a, "dataqsiz") + if err != nil { + return nil, fmt.Errorf("reading channel capacity: %s", err) + } + recvx, err := s.peekUintOrIntStructField(st, a, "recvx") + if err != nil { + return nil, fmt.Errorf("reading channel buffer index: %s", err) + } + return debug.Channel{ + ElementTypeID: uint64(t.ElemType.Common().Offset), + Address: a, + Buffer: buf, + Length: qcount, + Capacity: capacity, + Stride: uint64(t.ElemType.Common().ByteSize), + BufferStart: recvx, + }, nil + case *dwarf.FuncType: + a, err := s.peekPtr(addr) + if err != nil { + return nil, fmt.Errorf("reading func: %s", err) + } + return debug.Func{Address: a}, nil + case *dwarf.InterfaceType: + return debug.Interface{}, nil + // TODO: more types + } + return nil, fmt.Errorf("Unsupported type %T", t) +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/tests/peek/doc.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/tests/peek/doc.go new file mode 100644 index 00000000..42572276 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/tests/peek/doc.go @@ -0,0 +1,15 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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 peek diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/tests/peek/peek_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/tests/peek/peek_test.go new file mode 100644 index 00000000..c72e4162 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/tests/peek/peek_test.go @@ -0,0 +1,1074 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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. + +// +build linux + +package peek_test + +import ( + "flag" + "fmt" + "log" + "os" + "os/exec" + "reflect" + "regexp" + "sync" + "testing" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/local" + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/remote" +) + +var expectedVarValues = map[string]interface{}{ + `main.Z_bool_false`: false, + `main.Z_bool_true`: true, + `main.Z_complex128`: complex128(1.987654321 - 2.987654321i), + `main.Z_complex64`: complex64(1.54321 + 2.54321i), + `main.Z_float32`: float32(1.54321), + `main.Z_float64`: float64(1.987654321), + `main.Z_int16`: int16(-32321), + `main.Z_int32`: int32(-1987654321), + `main.Z_int64`: int64(-9012345678987654321), + `main.Z_int8`: int8(-121), + `main.Z_uint16`: uint16(54321), + `main.Z_uint32`: uint32(3217654321), + `main.Z_uint64`: uint64(12345678900987654321), + `main.Z_uint8`: uint8(231), +} + +// TODO: the string forms of some types we're testing aren't stable +var expectedVars = map[string]string{ + `main.Z_array`: `[5]int8{-121, 121, 3, 2, 1}`, + `main.Z_array_empty`: `[0]int8{}`, + `main.Z_bool_false`: `false`, + `main.Z_bool_true`: `true`, + `main.Z_channel`: `(chan int16 0xX)`, + `main.Z_channel_2`: `(chan int16 0xX)`, + `main.Z_channel_buffered`: `(chan int16 0xX [6/10])`, + `main.Z_channel_nil`: `(chan int16 )`, + `main.Z_array_of_empties`: `[2]{}{{} {}, ({} 0xX)}`, + `main.Z_complex128`: `(1.987654321-2.987654321i)`, + `main.Z_complex64`: `(1.54321+2.54321i)`, + `main.Z_float32`: `1.54321`, + `main.Z_float64`: `1.987654321`, + `main.Z_func_int8_r_int8`: `func(int8, *int8) void @0xX `, + `main.Z_func_int8_r_pint8`: `func(int8, **int8) void @0xX `, + `main.Z_func_bar`: `func(*main.FooStruct) void @0xX `, + `main.Z_func_nil`: `func(int8, *int8) void @0xX `, + `main.Z_int`: `-21`, + `main.Z_int16`: `-32321`, + `main.Z_int32`: `-1987654321`, + `main.Z_int64`: `-9012345678987654321`, + `main.Z_int8`: `-121`, + `main.Z_int_typedef`: `88`, + `main.Z_interface`: `("*main.FooStruct", 0xX)`, + `main.Z_interface_nil`: `(, )`, + `main.Z_interface_typed_nil`: `("*main.FooStruct", )`, + `main.Z_map`: `map[-21:3.54321]`, + `main.Z_map_2`: `map[1024:1]`, + `main.Z_map_3`: `map[1024:1 512:-1]`, + `main.Z_map_empty`: `map[]`, + `main.Z_map_nil`: `map[]`, + `main.Z_pointer`: `0xX`, + `main.Z_pointer_nil`: `0x0`, + `main.Z_slice`: `[]uint8{115, 108, 105, 99, 101}`, + `main.Z_slice_2`: `[]int8{-121, 121}`, + `main.Z_slice_nil`: `[]uint8{}`, + `main.Z_string`: `"I'm a string"`, + `main.Z_struct`: `main.FooStruct {21, "hi"}`, + `main.Z_uint`: `21`, + `main.Z_uint16`: `54321`, + `main.Z_uint32`: `3217654321`, + `main.Z_uint64`: `12345678900987654321`, + `main.Z_uint8`: `231`, + `main.Z_uintptr`: `21`, + `main.Z_unsafe_pointer`: `0xX`, + `main.Z_unsafe_pointer_nil`: `0x0`, +} + +// expectedEvaluate contains expected results of the debug.Evaluate function. +// A nil value indicates that an error is expected. +var expectedEvaluate = map[string]debug.Value{ + `x`: int16(42), + `local_array`: debug.Array{42, 42, 5, 8}, + `local_channel`: debug.Channel{42, 42, 42, 0, 0, 2, 0}, + `local_channel_buffered`: debug.Channel{42, 42, 42, 6, 10, 2, 8}, + `local_map`: debug.Map{42, 42, 1}, + `local_map_2`: debug.Map{42, 42, 1}, + `local_map_3`: debug.Map{42, 42, 2}, + `local_map_empty`: debug.Map{42, 42, 0}, + `x + 5`: int16(47), + `x - 5`: int16(37), + `x / 5`: int16(8), + `x % 5`: int16(2), + `x & 2`: int16(2), + `x | 1`: int16(43), + `x ^ 3`: int16(41), + `5 + x`: int16(47), + `5 - x`: int16(-37), + `100 / x`: int16(2), + `100 % x`: int16(16), + `2 & x`: int16(2), + `1 | x`: int16(43), + `3 ^ x`: int16(41), + `12`: 12, + `+42`: 42, + `23i`: 23i, + `34.0`: 34.0, + `34.5`: 34.5, + `1e5`: 100000.0, + `0x42`: 66, + `'c'`: 'c', + `"de"`: debug.String{2, `de`}, + "`ef`": debug.String{2, `ef`}, + `"de" + "fg"`: debug.String{4, `defg`}, + `/* comment */ -5`: -5, + `false`: false, + `true`: true, + `!false`: true, + `!true`: false, + `5 + 5`: 10, + `true || false`: true, + `false || false`: false, + `true && false`: false, + `true && true`: true, + `!(5 > 8)`: true, + `10 + 'a'`: 'k', + `10 + 10.5`: 20.5, + `10 + 10.5i`: 10 + 10.5i, + `'a' + 10.5`: 107.5, + `'a' + 10.5i`: 97 + 10.5i, + `10.5 + 20.5i`: 10.5 + 20.5i, + `10 * 20`: 200, + `10.0 - 20.5`: -10.5, + `(6 + 8i) * 4`: 24 + 32i, + `(6 + 8i) * (1 + 1i)`: -2 + 14i, + `(6 + 8i) * (6 - 8i)`: complex128(100), + `(6 + 8i) / (3 + 4i)`: complex128(2), + `local_array[2]`: int8(3), + `&local_array[1]`: debug.Pointer{42, 42}, + `local_map[-21]`: float32(3.54321), + `local_map[+21]`: float32(0), + `local_map_3[1024]`: int8(1), + `local_map_3[512]`: int8(-1), + `local_map_empty[21]`: float32(0), + `"hello"[2]`: uint8('l'), + `local_array[1:3][1]`: int8(3), + `local_array[0:4][2:3][0]`: int8(3), + `local_array[:]`: debug.Slice{debug.Array{42, 42, 5, 8}, 5}, + `local_array[:2]`: debug.Slice{debug.Array{42, 42, 2, 8}, 5}, + `local_array[2:]`: debug.Slice{debug.Array{42, 42, 3, 8}, 3}, + `local_array[1:3]`: debug.Slice{debug.Array{42, 42, 2, 8}, 4}, + `local_array[:3:4]`: debug.Slice{debug.Array{42, 42, 3, 8}, 4}, + `local_array[1:3:4]`: debug.Slice{debug.Array{42, 42, 2, 8}, 3}, + `local_array[1:][1:][1:]`: debug.Slice{debug.Array{42, 42, 2, 8}, 2}, + `(&local_array)[:]`: debug.Slice{debug.Array{42, 42, 5, 8}, 5}, + `(&local_array)[:2]`: debug.Slice{debug.Array{42, 42, 2, 8}, 5}, + `(&local_array)[2:]`: debug.Slice{debug.Array{42, 42, 3, 8}, 3}, + `(&local_array)[1:3]`: debug.Slice{debug.Array{42, 42, 2, 8}, 4}, + `(&local_array)[:3:4]`: debug.Slice{debug.Array{42, 42, 3, 8}, 4}, + `(&local_array)[1:3:4]`: debug.Slice{debug.Array{42, 42, 2, 8}, 3}, + `lookup("main.Z_array")`: debug.Array{42, 42, 5, 8}, + `lookup("main.Z_array_empty")`: debug.Array{42, 42, 0, 8}, + `lookup("main.Z_bool_false")`: false, + `lookup("main.Z_bool_true")`: true, + `lookup("main.Z_channel")`: debug.Channel{42, 42, 42, 0, 0, 2, 0}, + `lookup("main.Z_channel_buffered")`: debug.Channel{42, 42, 42, 6, 10, 2, 8}, + `lookup("main.Z_channel_nil")`: debug.Channel{42, 0, 0, 0, 0, 2, 0}, + `lookup("main.Z_array_of_empties")`: debug.Array{42, 42, 2, 0}, + `lookup("main.Z_complex128")`: complex128(1.987654321 - 2.987654321i), + `lookup("main.Z_complex64")`: complex64(1.54321 + 2.54321i), + `lookup("main.Z_float32")`: float32(1.54321), + `lookup("main.Z_float64")`: float64(1.987654321), + `lookup("main.Z_func_int8_r_int8")`: debug.Func{42}, + `lookup("main.Z_func_int8_r_pint8")`: debug.Func{42}, + `lookup("main.Z_func_bar")`: debug.Func{42}, + `lookup("main.Z_func_nil")`: debug.Func{0}, + `lookup("main.Z_int")`: -21, + `lookup("main.Z_int16")`: int16(-32321), + `lookup("main.Z_int32")`: int32(-1987654321), + `lookup("main.Z_int64")`: int64(-9012345678987654321), + `lookup("main.Z_int8")`: int8(-121), + `lookup("main.Z_int_typedef")`: int16(88), + `lookup("main.Z_interface")`: debug.Interface{}, + `lookup("main.Z_interface_nil")`: debug.Interface{}, + `lookup("main.Z_interface_typed_nil")`: debug.Interface{}, + `lookup("main.Z_map")`: debug.Map{42, 42, 1}, + `lookup("main.Z_map_2")`: debug.Map{42, 42, 1}, + `lookup("main.Z_map_3")`: debug.Map{42, 42, 2}, + `lookup("main.Z_map_empty")`: debug.Map{42, 42, 0}, + `lookup("main.Z_map_nil")`: debug.Map{42, 42, 0}, + `lookup("main.Z_pointer")`: debug.Pointer{42, 42}, + `lookup("main.Z_pointer_nil")`: debug.Pointer{42, 0}, + `lookup("main.Z_slice")`: debug.Slice{debug.Array{42, 42, 5, 8}, 5}, + `lookup("main.Z_slice_2")`: debug.Slice{debug.Array{42, 42, 2, 8}, 5}, + `lookup("main.Z_slice_nil")`: debug.Slice{debug.Array{42, 0, 0, 8}, 0}, + `lookup("main.Z_string")`: debug.String{12, `I'm a string`}, + `lookup("main.Z_struct")`: debug.Struct{[]debug.StructField{{"a", debug.Var{}}, {"b", debug.Var{}}}}, + `lookup("main.Z_uint")`: uint(21), + `lookup("main.Z_uint16")`: uint16(54321), + `lookup("main.Z_uint32")`: uint32(3217654321), + `lookup("main.Z_uint64")`: uint64(12345678900987654321), + `lookup("main.Z_uint8")`: uint8(231), + `lookup("main.Z_uintptr")`: uint(21), + `lookup("main.Z_unsafe_pointer")`: debug.Pointer{0, 42}, + `lookup("main.Z_unsafe_pointer_nil")`: debug.Pointer{0, 0}, + `lookup("main.Z_int") + lookup("main.Z_int")`: -42, + `lookup("main.Z_int16") < 0`: true, + `lookup("main.Z_uint32") + lookup("main.Z_uint32")`: uint32(2140341346), + `lookup("main.Z_bool_true") || lookup("main.Z_bool_false")`: true, + `lookup("main.Z_bool_true") && lookup("main.Z_bool_false")`: false, + `lookup("main.Z_bool_false") || lookup("main.Z_bool_false")`: false, + `!lookup("main.Z_bool_true")`: false, + `!lookup("main.Z_bool_false")`: true, + `lookup("main.Z_array")[2]`: int8(3), + `lookup("main.Z_array")[1:3][1]`: int8(3), + `lookup("main.Z_array")[0:4][2:3][0]`: int8(3), + `lookup("main.Z_array_of_empties")[0]`: debug.Struct{}, + `lookup("main.Z_complex128") * 10.0`: complex128(19.87654321 - 29.87654321i), + `lookup("main.Z_complex64") * 0.1`: complex64(0.154321 + 0.254321i), + `lookup("main.Z_float32") * 10.0`: float32(15.4321), + `lookup("main.Z_float64") * 0.1`: float64(0.1987654321), + `lookup("main.Z_int") + 1`: int(-20), + `lookup("main.Z_int16") - 10`: int16(-32331), + `lookup("main.Z_int32") / 10`: int32(-198765432), + `lookup("main.Z_int64") / 10`: int64(-901234567898765432), + `lookup("main.Z_int8") + 10`: int8(-111), + `lookup("main.Z_map")[-21]`: float32(3.54321), + `lookup("main.Z_map")[+21]`: float32(0), + `lookup("main.Z_map_empty")[21]`: float32(0), + `lookup("main.Z_slice")[1]`: uint8(108), + `lookup("main.Z_slice_2")[1]`: int8(121), + `lookup("main.Z_slice")[1:5][0:3][1]`: uint8('i'), + `lookup("main.Z_array")[1:3:4]`: debug.Slice{debug.Array{42, 42, 2, 8}, 3}, + `(&lookup("main.Z_array"))[1:3:4]`: debug.Slice{debug.Array{42, 42, 2, 8}, 3}, + `lookup("main.Z_string") + "!"`: debug.String{13, `I'm a string!`}, + `lookup("main.Z_struct").a`: 21, + `(&lookup("main.Z_struct")).a`: 21, + `lookup("main.Z_uint")/10`: uint(2), + `lookup("main.Z_uint16")/10`: uint16(5432), + `lookup("main.Z_uint32")/10`: uint32(321765432), + `lookup("main.Z_uint64")/10`: uint64(1234567890098765432), + `lookup("main.Z_uint8")/10`: uint8(23), + `lookup("main.Z_pointer").a`: 21, + `(*lookup("main.Z_pointer")).a`: 21, + `(&*lookup("main.Z_pointer")).a`: 21, + `lookup("main.Z_pointer").b`: debug.String{2, `hi`}, + `(*lookup("main.Z_pointer")).b`: debug.String{2, `hi`}, + `(&*lookup("main.Z_pointer")).b`: debug.String{2, `hi`}, + `lookup("main.Z_map_nil")[32]`: float32(0), + `&lookup("main.Z_int16")`: debug.Pointer{42, 42}, + `&lookup("main.Z_array")[1]`: debug.Pointer{42, 42}, + `&lookup("main.Z_slice")[1]`: debug.Pointer{42, 42}, + `*&lookup("main.Z_int16")`: int16(-32321), + `*&*&*&*&lookup("main.Z_int16")`: int16(-32321), + `lookup("time.Local")`: debug.Pointer{42, 42}, + `5 + false`: nil, + ``: nil, + `x + ""`: nil, + `x / 0`: nil, + `0 / 0`: nil, + `'a' / ('a'-'a')`: nil, + `0.0 / 0.0`: nil, + `3i / 0.0`: nil, + `x % 0`: nil, + `0 % 0`: nil, + `'a' % ('a'-'a')`: nil, + `local_array[-2] + 1`: nil, + `local_array[22] + 1`: nil, + `local_slice[-2] + 1`: nil, + `local_slice[22] + 1`: nil, + `local_string[-2]`: nil, + `local_string[22]`: nil, + `"hello"[-2]`: nil, + `"hello"[22]`: nil, + `local_pointer_nil.a`: nil, + `(local_struct).c`: nil, + `(&local_struct).c`: nil, + `(*local_pointer).c`: nil, + `lookup("not a real symbol")`: nil, + `lookup("x")`: nil, + `lookup(x)`: nil, + `lookup(42)`: nil, +} + +func isHex(r uint8) bool { + switch { + case '0' <= r && r <= '9': + return true + case 'a' <= r && r <= 'f': + return true + case 'A' <= r && r <= 'F': + return true + default: + return false + } +} + +// structRE is used by matches to remove 'struct ' from type names, which is not +// output by every version of the compiler. +var structRE = regexp.MustCompile("struct *") + +// Check s matches the pattern in p. +// An 'X' in p greedily matches one or more hex characters in s. +func matches(p, s string) bool { + // Remove 'struct' and following spaces from s. + s = structRE.ReplaceAllString(s, "") + j := 0 + for i := 0; i < len(p); i++ { + if j == len(s) { + return false + } + c := p[i] + if c == 'X' { + if !isHex(s[j]) { + return false + } + for j < len(s) && isHex(s[j]) { + j++ + } + continue + } + if c != s[j] { + return false + } + j++ + } + return j == len(s) +} + +const ( + proxySrc = "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/cmd/debugproxy" + traceeSrc = "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/tests/peek/testdata" +) + +var ( + // Locations of the proxy and tracee executables. + proxyBinary = "./debugproxy.out" + traceeBinary = "./tracee.out" + // Onces that ensure initProxy and initTracee are called at most once. + proxyOnce sync.Once + traceeOnce sync.Once + // Flags for setting the location of the proxy and tracee, so they don't need to be built. + proxyFlag = flag.String("proxy", "", "Location of debugproxy. If empty, proxy will be built.") + traceeFlag = flag.String("target", "", "Location of target. If empty, target will be built.") + // Executables this test has built, which will be removed on completion of the tests. + filesToRemove []string +) + +func TestMain(m *testing.M) { + flag.Parse() + x := m.Run() + for _, f := range filesToRemove { + os.Remove(f) + } + os.Exit(x) +} + +func run(name string, args ...string) error { + cmd := exec.Command(name, args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} + +func initProxy() { + if *proxyFlag != "" { + proxyBinary = *proxyFlag + remote.DebugproxyCmd = proxyBinary + return + } + if err := run("go", "build", "-o", proxyBinary, proxySrc); err != nil { + log.Fatalf("couldn't build proxy: %v", err) + } + filesToRemove = append(filesToRemove, proxyBinary) + remote.DebugproxyCmd = proxyBinary +} + +func initTracee() { + if *traceeFlag != "" { + traceeBinary = *traceeFlag + return + } + if err := run("go", "build", "-o", traceeBinary, traceeSrc); err != nil { + log.Fatalf("couldn't build target: %v", err) + } + filesToRemove = append(filesToRemove, traceeBinary) +} + +func TestLocalProgram(t *testing.T) { + t.Skip("Fails looking for runtime.lessstack for some reason") + traceeOnce.Do(initTracee) + prog, err := local.New(traceeBinary) + if err != nil { + t.Fatal("local.New:", err) + } + testProgram(t, prog) +} + +func TestRemoteProgram(t *testing.T) { + t.Skip("Fails looking for runtime.lessstack for some reason") + traceeOnce.Do(initTracee) + proxyOnce.Do(initProxy) + prog, err := remote.New("localhost", traceeBinary) + if err != nil { + t.Fatal("remote.New:", err) + } + testProgram(t, prog) +} + +func testProgram(t *testing.T, prog debug.Program) { + _, err := prog.Run("some", "arguments") + if err != nil { + log.Fatalf("Run: %v", err) + } + + pcs, err := prog.BreakpointAtFunction("main.foo") + if err != nil { + log.Fatalf("BreakpointAtFunction: %v", err) + } + fmt.Printf("breakpoints set at %x\n", pcs) + + _, err = prog.Resume() + if err != nil { + log.Fatalf("Resume: %v", err) + } + + gs, err := prog.Goroutines() + if err != nil { + t.Fatalf("Goroutines(): got error %s", err) + } + for _, g := range gs { + fmt.Println(g) + for _, f := range g.StackFrames { + fmt.Println(f) + } + } + + frames, err := prog.Frames(100) + if err != nil { + log.Fatalf("prog.Frames error: %v", err) + } + fmt.Printf("%#v\n", frames) + if len(frames) == 0 { + t.Fatalf("no stack frames returned") + } + if frames[0].Function != "main.foo" { + t.Errorf("function name: got %s expected main.foo", frames[0].Function) + } + if len(frames[0].Params) != 2 { + t.Errorf("got %d parameters, expected 2", len(frames[0].Params)) + } else { + x := frames[0].Params[0] + y := frames[0].Params[1] + if x.Name != "x" { + x, y = y, x + } + if x.Name != "x" { + t.Errorf("parameter name: got %s expected x", x.Name) + } + if y.Name != "y" { + t.Errorf("parameter name: got %s expected y", y.Name) + } + if val, err := prog.Value(x.Var); err != nil { + t.Errorf("value of x: %s", err) + } else if val != int16(42) { + t.Errorf("value of x: got %T(%v) expected int16(42)", val, val) + } + if val, err := prog.Value(y.Var); err != nil { + t.Errorf("value of y: %s", err) + } else if val != float32(1.5) { + t.Errorf("value of y: got %T(%v) expected float32(1.5)", val, val) + } + } + + varnames, err := prog.Eval(`re:main\.Z_.*`) + if err != nil { + log.Fatalf("prog.Eval error: %v", err) + } + + // Evaluate each of the variables found above, and check they match + // expectedVars. + seen := make(map[string]bool) + for _, v := range varnames { + val, err := prog.Eval("val:" + v) + if err != nil { + log.Fatalf("prog.Eval error for %s: %v", v, err) + } else { + fmt.Printf("%s = %v\n", v, val) + if seen[v] { + log.Fatalf("repeated variable %s\n", v) + } + seen[v] = true + if len(val) != 1 { + log.Fatalf("should be one value for %s\n", v) + } + expected, ok := expectedVars[v] + if !ok { + log.Fatalf("unexpected variable %s\n", v) + } else { + if !matches(expected, val[0]) { + log.Fatalf("expected %s = %s\n", v, expected) + } + } + } + } + for v, e := range expectedVars { + if !seen[v] { + log.Fatalf("didn't get %s = %s\n", v, e) + } + } + + // Remove the breakpoint at main.foo. + err = prog.DeleteBreakpoints(pcs) + if err != nil { + log.Fatalf("DeleteBreakpoints: %v", err) + } + + // Set a breakpoint at line 125, resume, and check we stopped there. + pcsLine125, err := prog.BreakpointAtLine("testdata/main.go", 125) + if err != nil { + t.Fatal("BreakpointAtLine:", err) + } + status, err := prog.Resume() + if err != nil { + log.Fatalf("Resume: %v", err) + } + stoppedAt := func(pcs []uint64) bool { + for _, pc := range pcs { + if status.PC == pc { + return true + } + } + return false + } + if !stoppedAt(pcsLine125) { + t.Errorf("stopped at %X; expected one of %X.", status.PC, pcsLine125) + } + + for k, v := range expectedEvaluate { + val, err := prog.Evaluate(k) + if v == nil { + if err == nil { + t.Errorf("got Evaluate(%s) = %v, expected error", k, val) + } + continue + } + if err != nil { + t.Errorf("Evaluate(%s): got error %s, expected %v", k, err, v) + continue + } + typ := reflect.TypeOf(v) + if typ != reflect.TypeOf(val) && typ != reflect.TypeOf(int(0)) && typ != reflect.TypeOf(uint(0)) { + t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v) + continue + } + + // For types with fields like Address, TypeID, etc., we can't know the exact + // value, so we only test whether those fields are zero or not. + switch v := v.(type) { + default: + if v != val { + t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v) + } + case debug.Array: + val := val.(debug.Array) + if v.ElementTypeID == 0 && val.ElementTypeID != 0 { + t.Errorf("got Evaluate(%s) = %+v, expected zero ElementTypeID", k, val) + } + if v.ElementTypeID != 0 && val.ElementTypeID == 0 { + t.Errorf("got Evaluate(%s) = %+v, expected non-zero ElementTypeID", k, val) + } + if v.Address == 0 && val.Address != 0 { + t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val) + } + if v.Address != 0 && val.Address == 0 { + t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val) + } + case debug.Slice: + val := val.(debug.Slice) + if v.ElementTypeID == 0 && val.ElementTypeID != 0 { + t.Errorf("got Evaluate(%s) = %+v, expected zero ElementTypeID", k, val) + } + if v.ElementTypeID != 0 && val.ElementTypeID == 0 { + t.Errorf("got Evaluate(%s) = %+v, expected non-zero ElementTypeID", k, val) + } + if v.Address == 0 && val.Address != 0 { + t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val) + } + if v.Address != 0 && val.Address == 0 { + t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val) + } + case debug.Map: + val := val.(debug.Map) + if v.TypeID == 0 && val.TypeID != 0 { + t.Errorf("got Evaluate(%s) = %+v, expected zero TypeID", k, val) + } + if v.TypeID != 0 && val.TypeID == 0 { + t.Errorf("got Evaluate(%s) = %+v, expected non-zero TypeID", k, val) + } + if v.Address == 0 && val.Address != 0 { + t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val) + } + if v.Address != 0 && val.Address == 0 { + t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val) + } + case debug.Pointer: + val := val.(debug.Pointer) + if v.TypeID == 0 && val.TypeID != 0 { + t.Errorf("got Evaluate(%s) = %+v, expected zero TypeID", k, val) + } + if v.TypeID != 0 && val.TypeID == 0 { + t.Errorf("got Evaluate(%s) = %+v, expected non-zero TypeID", k, val) + } + if v.Address == 0 && val.Address != 0 { + t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val) + } + if v.Address != 0 && val.Address == 0 { + t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val) + } + case debug.Channel: + val := val.(debug.Channel) + if v.ElementTypeID == 0 && val.ElementTypeID != 0 { + t.Errorf("got Evaluate(%s) = %+v, expected zero ElementTypeID", k, val) + } + if v.ElementTypeID != 0 && val.ElementTypeID == 0 { + t.Errorf("got Evaluate(%s) = %+v, expected non-zero ElementTypeID", k, val) + } + if v.Address == 0 && val.Address != 0 { + t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val) + } + if v.Address != 0 && val.Address == 0 { + t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val) + } + if v.Buffer == 0 && val.Buffer != 0 { + t.Errorf("got Evaluate(%s) = %+v, expected zero Buffer", k, val) + } + if v.Buffer != 0 && val.Buffer == 0 { + t.Errorf("got Evaluate(%s) = %+v, expected non-zero Buffer", k, val) + } + case debug.Struct: + val := val.(debug.Struct) + if len(v.Fields) != len(val.Fields) { + t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v) + break + } + for i := range v.Fields { + a := v.Fields[i].Name + b := val.Fields[i].Name + if a != b { + t.Errorf("Evaluate(%s): field name mismatch: %s vs %s", k, a, b) + break + } + } + case debug.Func: + val := val.(debug.Func) + if v.Address == 0 && val.Address != 0 { + t.Errorf("got Evaluate(%s) = %+v, expected zero Address", k, val) + } + if v.Address != 0 && val.Address == 0 { + t.Errorf("got Evaluate(%s) = %+v, expected non-zero Address", k, val) + } + case int: + // ints in a remote program can be returned as int32 or int64 + switch val := val.(type) { + case int32: + if val != int32(v) { + t.Errorf("got Evaluate(%s) = %T(%v), expected %v", k, val, val, v) + } + case int64: + if val != int64(v) { + t.Errorf("got Evaluate(%s) = %T(%v), expected %v", k, val, val, v) + } + default: + t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v) + } + case uint: + // uints in a remote program can be returned as uint32 or uint64 + switch val := val.(type) { + case uint32: + if val != uint32(v) { + t.Errorf("got Evaluate(%s) = %T(%v), expected %v", k, val, val, v) + } + case uint64: + if val != uint64(v) { + t.Errorf("got Evaluate(%s) = %T(%v), expected %v", k, val, val, v) + } + default: + t.Errorf("got Evaluate(%s) = %T(%v), expected %T(%v)", k, val, val, v, v) + } + } + } + + // Evaluate a struct. + v := `lookup("main.Z_struct")` + val, err := prog.Evaluate(v) + if err != nil { + t.Fatalf("Evaluate: %s", err) + } + s, ok := val.(debug.Struct) + if !ok { + t.Fatalf("got Evaluate(%q) = %T(%v), expected debug.Struct", v, val, val) + } + // Check the values of its fields. + if len(s.Fields) != 2 { + t.Fatalf("got Evaluate(%q) = %+v, expected 2 fields", v, s) + } + if v0, err := prog.Value(s.Fields[0].Var); err != nil { + t.Errorf("Value: %s", err) + } else if v0 != int32(21) && v0 != int64(21) { + t.Errorf("Value: got %T(%v), expected 21", v0, v0) + } + if v1, err := prog.Value(s.Fields[1].Var); err != nil { + t.Errorf("Value: %s", err) + } else if v1 != (debug.String{2, "hi"}) { + t.Errorf("Value: got %T(%v), expected `hi`", v1, v1) + } + + // Remove the breakpoint at line 125, set a breakpoint at main.f1 and main.f2, + // then delete the breakpoint at main.f1. Resume, then check we stopped at + // main.f2. + err = prog.DeleteBreakpoints(pcsLine125) + if err != nil { + log.Fatalf("DeleteBreakpoints: %v", err) + } + pcs1, err := prog.BreakpointAtFunction("main.f1") + if err != nil { + log.Fatalf("BreakpointAtFunction: %v", err) + } + pcs2, err := prog.BreakpointAtFunction("main.f2") + if err != nil { + log.Fatalf("BreakpointAtFunction: %v", err) + } + err = prog.DeleteBreakpoints(pcs1) + if err != nil { + log.Fatalf("DeleteBreakpoints: %v", err) + } + status, err = prog.Resume() + if err != nil { + log.Fatalf("Resume: %v", err) + } + if !stoppedAt(pcs2) { + t.Errorf("stopped at %X; expected one of %X.", status.PC, pcs2) + } + + // Check we get the expected results calling VarByName then Value + // for the variables in expectedVarValues. + for name, exp := range expectedVarValues { + if v, err := prog.VarByName(name); err != nil { + t.Errorf("VarByName(%s): %s", name, err) + } else if val, err := prog.Value(v); err != nil { + t.Errorf("value of %s: %s", name, err) + } else if val != exp { + t.Errorf("value of %s: got %T(%v) want %T(%v)", name, val, val, exp, exp) + } + } + + // Check some error cases for VarByName and Value. + if _, err = prog.VarByName("not a real name"); err == nil { + t.Error("VarByName for invalid name: expected error") + } + if _, err = prog.Value(debug.Var{}); err == nil { + t.Error("value of invalid var: expected error") + } + if v, err := prog.VarByName("main.Z_int16"); err != nil { + t.Error("VarByName(main.Z_int16) error:", err) + } else { + v.Address = 0 + // v now has a valid type but a bad address. + _, err = prog.Value(v) + if err == nil { + t.Error("value of invalid location: expected error") + } + } + + // checkValue tests that we can get a Var for a variable with the given name, + // that we can then get the value of that Var, and that calling fn for that + // value succeeds. + checkValue := func(name string, fn func(val debug.Value) error) { + if v, err := prog.VarByName(name); err != nil { + t.Errorf("VarByName(%s): %s", name, err) + } else if val, err := prog.Value(v); err != nil { + t.Errorf("value of %s: %s", name, err) + } else if err := fn(val); err != nil { + t.Errorf("value of %s: %s", name, err) + } + } + + checkValue("main.Z_uintptr", func(val debug.Value) error { + if val != uint32(21) && val != uint64(21) { + // Z_uintptr should be an unsigned integer with size equal to the debugged + // program's address size. + return fmt.Errorf("got %T(%v) want 21", val, val) + } + return nil + }) + + checkValue("main.Z_int", func(val debug.Value) error { + if val != int32(-21) && val != int64(-21) { + return fmt.Errorf("got %T(%v) want -21", val, val) + } + return nil + }) + + checkValue("main.Z_uint", func(val debug.Value) error { + if val != uint32(21) && val != uint64(21) { + return fmt.Errorf("got %T(%v) want 21", val, val) + } + return nil + }) + + checkValue("main.Z_pointer", func(val debug.Value) error { + if _, ok := val.(debug.Pointer); !ok { + return fmt.Errorf("got %T(%v) expected Pointer", val, val) + } + return nil + }) + + checkValue("main.Z_pointer_nil", func(val debug.Value) error { + if p, ok := val.(debug.Pointer); !ok { + return fmt.Errorf("got %T(%v) expected Pointer", val, val) + } else if p.Address != 0 { + return fmt.Errorf("got %T(%v) expected nil pointer", val, val) + } + return nil + }) + + checkValue("main.Z_array", func(val debug.Value) error { + a, ok := val.(debug.Array) + if !ok { + return fmt.Errorf("got %T(%v) expected Array", val, val) + } + if a.Len() != 5 { + return fmt.Errorf("got array length %d expected 5", a.Len()) + } + expected := [5]int8{-121, 121, 3, 2, 1} + for i := uint64(0); i < 5; i++ { + if v, err := prog.Value(a.Element(i)); err != nil { + return fmt.Errorf("reading element %d: %s", i, err) + } else if v != expected[i] { + return fmt.Errorf("element %d: got %T(%v) want %T(%d)", i, v, v, expected[i], expected[i]) + } + } + return nil + }) + + checkValue("main.Z_slice", func(val debug.Value) error { + s, ok := val.(debug.Slice) + if !ok { + return fmt.Errorf("got %T(%v) expected Slice", val, val) + } + if s.Len() != 5 { + return fmt.Errorf("got slice length %d expected 5", s.Len()) + } + expected := []uint8{115, 108, 105, 99, 101} + for i := uint64(0); i < 5; i++ { + if v, err := prog.Value(s.Element(i)); err != nil { + return fmt.Errorf("reading element %d: %s", i, err) + } else if v != expected[i] { + return fmt.Errorf("element %d: got %T(%v) want %T(%d)", i, v, v, expected[i], expected[i]) + } + } + return nil + }) + + checkValue("main.Z_map_empty", func(val debug.Value) error { + m, ok := val.(debug.Map) + if !ok { + return fmt.Errorf("got %T(%v) expected Map", val, val) + } + if m.Length != 0 { + return fmt.Errorf("got map length %d expected 0", m.Length) + } + return nil + }) + + checkValue("main.Z_map_nil", func(val debug.Value) error { + m, ok := val.(debug.Map) + if !ok { + return fmt.Errorf("got %T(%v) expected Map", val, val) + } + if m.Length != 0 { + return fmt.Errorf("got map length %d expected 0", m.Length) + } + return nil + }) + + checkValue("main.Z_map_3", func(val debug.Value) error { + m, ok := val.(debug.Map) + if !ok { + return fmt.Errorf("got %T(%v) expected Map", val, val) + } + if m.Length != 2 { + return fmt.Errorf("got map length %d expected 2", m.Length) + } + keyVar0, valVar0, err := prog.MapElement(m, 0) + if err != nil { + return err + } + keyVar1, valVar1, err := prog.MapElement(m, 1) + if err != nil { + return err + } + key0, err := prog.Value(keyVar0) + if err != nil { + return err + } + key1, err := prog.Value(keyVar1) + if err != nil { + return err + } + val0, err := prog.Value(valVar0) + if err != nil { + return err + } + val1, err := prog.Value(valVar1) + if err != nil { + return err + } + // The map should contain 1024,1 and 512,-1 in some order. + ok1 := key0 == int16(1024) && val0 == int8(1) && key1 == int16(512) && val1 == int8(-1) + ok2 := key1 == int16(1024) && val1 == int8(1) && key0 == int16(512) && val0 == int8(-1) + if !ok1 && !ok2 { + return fmt.Errorf("got values (%d,%d) and (%d,%d), expected (1024,1) and (512,-1) in some order", key0, val0, key1, val1) + } + _, _, err = prog.MapElement(m, 2) + if err == nil { + return fmt.Errorf("MapElement: reading at a bad index succeeded, expected error") + } + return nil + }) + + checkValue("main.Z_string", func(val debug.Value) error { + s, ok := val.(debug.String) + if !ok { + return fmt.Errorf("got %T(%v) expected String", val, val) + } + if s.Length != 12 { + return fmt.Errorf("got string length %d expected 12", s.Length) + } + expected := "I'm a string" + if s.String != expected { + return fmt.Errorf("got %s expected %s", s.String, expected) + } + return nil + }) + + checkValue("main.Z_channel", func(val debug.Value) error { + c, ok := val.(debug.Channel) + if !ok { + return fmt.Errorf("got %T(%v) expected Channel", val, val) + } + if c.Buffer == 0 { + return fmt.Errorf("got buffer address %d expected nonzero", c.Buffer) + } + if c.Length != 0 { + return fmt.Errorf("got length %d expected 0", c.Length) + } + if c.Capacity != 0 { + return fmt.Errorf("got capacity %d expected 0", c.Capacity) + } + return nil + }) + + checkValue("main.Z_channel_2", func(val debug.Value) error { + c, ok := val.(debug.Channel) + if !ok { + return fmt.Errorf("got %T(%v) expected Channel", val, val) + } + if c.Buffer == 0 { + return fmt.Errorf("got buffer address %d expected nonzero", c.Buffer) + } + if c.Length != 0 { + return fmt.Errorf("got length %d expected 0", c.Length) + } + if c.Capacity != 0 { + return fmt.Errorf("got capacity %d expected 0", c.Capacity) + } + return nil + }) + + checkValue("main.Z_channel_nil", func(val debug.Value) error { + c, ok := val.(debug.Channel) + if !ok { + return fmt.Errorf("got %T(%v) expected Channel", val, val) + } + if c.Buffer != 0 { + return fmt.Errorf("got buffer address %d expected 0", c.Buffer) + } + if c.Length != 0 { + return fmt.Errorf("got length %d expected 0", c.Length) + } + if c.Capacity != 0 { + return fmt.Errorf("got capacity %d expected 0", c.Capacity) + } + return nil + }) + + checkValue("main.Z_channel_buffered", func(val debug.Value) error { + c, ok := val.(debug.Channel) + if !ok { + return fmt.Errorf("got %T(%v) expected Channel", val, val) + } + if c.Buffer == 0 { + return fmt.Errorf("got buffer address %d expected nonzero", c.Buffer) + } + if c.Length != 6 { + return fmt.Errorf("got length %d expected 6", c.Length) + } + if c.Capacity != 10 { + return fmt.Errorf("got capacity %d expected 10", c.Capacity) + } + if c.Stride != 2 { + return fmt.Errorf("got stride %d expected 2", c.Stride) + } + expected := []int16{8, 9, 10, 11, 12, 13} + for i := uint64(0); i < 6; i++ { + if v, err := prog.Value(c.Element(i)); err != nil { + return fmt.Errorf("reading element %d: %s", i, err) + } else if v != expected[i] { + return fmt.Errorf("element %d: got %T(%v) want %T(%d)", i, v, v, expected[i], expected[i]) + } + } + v := c.Element(6) + if v.Address != 0 { + return fmt.Errorf("invalid element returned Var with address %d, expected 0", v.Address) + } + return nil + }) + + checkValue("main.Z_func_bar", func(val debug.Value) error { + f, ok := val.(debug.Func) + if !ok { + return fmt.Errorf("got %T(%v) expected Func", val, val) + } + if f.Address == 0 { + return fmt.Errorf("got func address %d expected nonzero", f.Address) + } + return nil + }) + + checkValue("main.Z_func_nil", func(val debug.Value) error { + f, ok := val.(debug.Func) + if !ok { + return fmt.Errorf("got %T(%v) expected Func", val, val) + } + if f.Address != 0 { + return fmt.Errorf("got func address %d expected zero", f.Address) + } + return nil + }) +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/tests/peek/testdata/main.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/tests/peek/testdata/main.go new file mode 100644 index 00000000..68c22c17 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/tests/peek/testdata/main.go @@ -0,0 +1,203 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 main + +import ( + "fmt" + "log" + "os" + "time" + "unsafe" +) + +type FooInterface interface { + Bar() +} + +type FooStruct struct { + a int + b string +} + +func (f *FooStruct) Bar() {} + +type myInt int16 + +var ( + Z_bool_false bool = false + Z_bool_true bool = true + Z_int int = -21 + Z_int8 int8 = -121 + Z_int16 int16 = -32321 + Z_int32 int32 = -1987654321 + Z_int64 int64 = -9012345678987654321 + Z_int_typedef myInt = 88 + Z_uint uint = 21 + Z_uint8 uint8 = 231 + Z_uint16 uint16 = 54321 + Z_uint32 uint32 = 3217654321 + Z_uint64 uint64 = 12345678900987654321 + Z_uintptr uintptr = 21 + Z_float32 float32 = 1.54321 + Z_float64 float64 = 1.987654321 + Z_complex64 complex64 = 1.54321 + 2.54321i + Z_complex128 complex128 = 1.987654321 - 2.987654321i + Z_array [5]int8 = [5]int8{-121, 121, 3, 2, 1} + Z_array_empty [0]int8 = [0]int8{} + Z_array_of_empties [2]struct{} = [2]struct{}{{}, {}} + Z_channel chan int16 = make(chan int16) + Z_channel_2 chan int16 = make(chan int16) + Z_channel_buffered chan int16 = make(chan int16, 10) + Z_channel_nil chan int16 + Z_func_bar = (*FooStruct).Bar + Z_func_int8_r_int8 = func(x int8) int8 { return x + 1 } + Z_func_int8_r_pint8 = func(x int8) *int8 { y := x + 1; return &y } + Z_func_nil func(x int8) int8 = nil + Z_interface FooInterface = &Z_struct + Z_interface_typed_nil FooInterface = Z_pointer_nil + Z_interface_nil FooInterface + Z_map map[int8]float32 = map[int8]float32{-21: 3.54321} + Z_map_2 map[int16]int8 = map[int16]int8{1024: 1} + Z_map_3 map[int16]int8 = map[int16]int8{1024: 1, 512: -1} + Z_map_empty map[int8]float32 = map[int8]float32{} + Z_map_nil map[int8]float32 + Z_pointer *FooStruct = &Z_struct + Z_pointer_nil *FooStruct + Z_slice []byte = []byte{'s', 'l', 'i', 'c', 'e'} + Z_slice_2 []int8 = Z_array[0:2] + Z_slice_nil []byte + Z_string string = "I'm a string" + Z_struct FooStruct = FooStruct{a: 21, b: "hi"} + Z_unsafe_pointer unsafe.Pointer = unsafe.Pointer(&Z_uint) + Z_unsafe_pointer_nil unsafe.Pointer +) + +func foo(x int16, y float32) { + var ( + local_array [5]int8 = [5]int8{-121, 121, 3, 2, 1} + local_bool_false bool = false + local_bool_true bool = true + local_channel chan int16 = Z_channel + local_channel_buffered chan int16 = Z_channel_buffered + local_channel_nil chan int16 + local_complex128 complex128 = 1.987654321 - 2.987654321i + local_complex64 complex64 = 1.54321 + 2.54321i + local_float32 float32 = 1.54321 + local_float64 float64 = 1.987654321 + local_func_bar = (*FooStruct).Bar + local_func_int8_r_int8 = func(x int8) int8 { return x + 1 } + local_func_int8_r_pint8 = func(x int8) *int8 { y := x + 1; return &y } + local_func_nil func(x int8) int8 = nil + local_int int = -21 + local_int16 int16 = -32321 + local_int32 int32 = -1987654321 + local_int64 int64 = -9012345678987654321 + local_int8 int8 = -121 + local_int_typedef myInt = 88 + local_interface FooInterface = &Z_struct + local_interface_nil FooInterface + local_interface_typed_nil FooInterface = Z_pointer_nil + local_map map[int8]float32 = map[int8]float32{-21: 3.54321} + local_map_2 map[int16]int8 = map[int16]int8{1024: 1} + local_map_3 map[int16]int8 = map[int16]int8{1024: 1, 512: -1} + local_map_empty map[int8]float32 = map[int8]float32{} + local_map_nil map[int8]float32 + local_pointer *FooStruct = &Z_struct + local_pointer_nil *FooStruct + local_slice []byte = []byte{'s', 'l', 'i', 'c', 'e'} + local_slice_2 []int8 = Z_array[0:2] + local_slice_nil []byte + local_string string = "I'm a string" + local_struct FooStruct = FooStruct{a: 21, b: "hi"} + local_uint uint = 21 + local_uint16 uint16 = 54321 + local_uint32 uint32 = 3217654321 + local_uint64 uint64 = 12345678900987654321 + local_uint8 uint8 = 231 + local_uintptr uintptr = 21 + local_unsafe_pointer unsafe.Pointer = unsafe.Pointer(&Z_uint) + local_unsafe_pointer_nil unsafe.Pointer + ) + fmt.Println(Z_bool_false, Z_bool_true) + fmt.Println(Z_int, Z_int8, Z_int16, Z_int32, Z_int64, Z_int_typedef) + fmt.Println(Z_uint, Z_uint8, Z_uint16, Z_uint32, Z_uint64, Z_uintptr) + fmt.Println(Z_float32, Z_float64, Z_complex64, Z_complex128) + fmt.Println(Z_array, Z_array_empty, Z_array_of_empties) + fmt.Println(Z_channel, Z_channel_buffered, Z_channel_nil) + fmt.Println(Z_func_bar, Z_func_int8_r_int8, Z_func_int8_r_pint8, Z_func_nil) + fmt.Println(Z_interface, Z_interface_nil, Z_interface_typed_nil) + fmt.Println(Z_map, Z_map_2, Z_map_3, Z_map_empty, Z_map_nil) + fmt.Println(Z_pointer, Z_pointer_nil) + fmt.Println(Z_slice, Z_slice_2, Z_slice_nil) + fmt.Println(Z_string, Z_struct) + fmt.Println(Z_unsafe_pointer, Z_unsafe_pointer_nil) + fmt.Println(local_bool_false, local_bool_true) + fmt.Println(local_int, local_int8, local_int16, local_int32, local_int64, local_int_typedef) + fmt.Println(local_uint, local_uint8, local_uint16, local_uint32, local_uint64, local_uintptr) + fmt.Println(local_float32, local_float64, local_complex64, local_complex128, local_array) + fmt.Println(local_channel, local_channel_buffered, local_channel_nil) + fmt.Println(local_func_bar, local_func_int8_r_int8, local_func_int8_r_pint8, local_func_nil) + fmt.Println(local_interface, local_interface_nil, local_interface_typed_nil) + fmt.Println(local_map, local_map_2, local_map_3, local_map_empty, local_map_nil) + fmt.Println(local_pointer, local_pointer_nil) + fmt.Println(local_slice, local_slice_2, local_slice_nil) + fmt.Println(local_string, local_struct) + fmt.Println(local_unsafe_pointer, local_unsafe_pointer_nil) + f1() + f2() +} + +func f1() { + fmt.Println() +} + +func f2() { + fmt.Println() +} + +func bar() { + foo(42, 1.5) + fmt.Print() +} + +func populateChannels() { + go func() { + Z_channel_2 <- 8 + }() + go func() { + for i := int16(0); i < 14; i++ { + Z_channel_buffered <- i + } + }() + go func() { + for i := 0; i < 8; i++ { + <-Z_channel_buffered + } + }() + time.Sleep(time.Second / 20) +} + +func main() { + args := os.Args[1:] + expected := []string{"some", "arguments"} + if len(args) != 2 || args[0] != expected[0] || args[1] != expected[1] { + log.Fatalf("got command-line args %v, expected %v", args, expected) + } + populateChannels() + for ; ; time.Sleep(2 * time.Second) { + bar() + } + select {} +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector.go new file mode 100644 index 00000000..5467df97 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector.go @@ -0,0 +1,460 @@ +// Copyright 2016 Google LLC +// +// 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 valuecollector is used to collect the values of variables in a program. +package valuecollector + +import ( + "bytes" + "fmt" + "strconv" + "strings" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" + cd "google.golang.org/api/clouddebugger/v2" +) + +const ( + maxArrayLength = 50 + maxMapLength = 20 +) + +// Collector is given references to variables from a program being debugged +// using AddVariable. Then when ReadValues is called, the Collector will fetch +// the values of those variables. Any variables referred to by those values +// will also be fetched; e.g. the targets of pointers, members of structs, +// elements of slices, etc. This continues iteratively, building a graph of +// values, until all the reachable values are fetched, or a size limit is +// reached. +// +// Variables are passed to the Collector as debug.Var, which is used by x/debug +// to represent references to variables. Values are returned as cd.Variable, +// which is used by the Debuglet Controller to represent the graph of values. +// +// For example, if the program has a struct variable: +// +// foo := SomeStruct{a:42, b:"xyz"} +// +// and we call AddVariable with a reference to foo, we will get back a result +// like: +// +// cd.Variable{Name:"foo", VarTableIndex:10} +// +// which denotes a variable named "foo" which will have its value stored in +// element 10 of the table that will later be returned by ReadValues. That +// element might be: +// +// out[10] = &cd.Variable{Members:{{Name:"a", VarTableIndex:11},{Name:"b", VarTableIndex:12}}} +// +// which denotes a struct with two members a and b, whose values are in elements +// 11 and 12 of the output table: +// +// out[11] = &cd.Variable{Value:"42"} +// out[12] = &cd.Variable{Value:"xyz"} +type Collector struct { + // prog is the program being debugged. + prog debug.Program + // limit is the maximum size of the output slice of values. + limit int + // index is a map from references (variables and map elements) to their + // locations in the table. + index map[reference]int + // table contains the references, including those given to the + // Collector directly and those the Collector itself found. + // If VarTableIndex is set to 0 in a cd.Variable, it is ignored, so the first entry + // of table can't be used. On initialization we put a dummy value there. + table []reference +} + +// reference represents a value which is in the queue to be read by the +// collector. It is either a debug.Var, or a mapElement. +type reference interface{} + +// mapElement represents an element of a map in the debugged program's memory. +type mapElement struct { + debug.Map + index uint64 +} + +// NewCollector returns a Collector for the given program and size limit. +// The limit is the maximum size of the slice of values returned by ReadValues. +func NewCollector(prog debug.Program, limit int) *Collector { + return &Collector{ + prog: prog, + limit: limit, + index: make(map[reference]int), + table: []reference{debug.Var{}}, + } +} + +// AddVariable adds another variable to be collected. +// The Collector doesn't get the value immediately; it returns a cd.Variable +// that contains an index into the table which will later be returned by +// ReadValues. +func (c *Collector) AddVariable(lv debug.LocalVar) *cd.Variable { + ret := &cd.Variable{Name: lv.Name} + if index, ok := c.add(lv.Var); !ok { + // If the add call failed, it's because we reached the size limit. + // The Debuglet Controller's convention is to pass it a "Not Captured" error + // in this case. + ret.Status = statusMessage(messageNotCaptured, true, refersToVariableName) + } else { + ret.VarTableIndex = int64(index) + } + return ret +} + +// add adds a reference to the set of values to be read from the +// program. It returns the index in the output table that will contain the +// corresponding value. It fails if the table has reached the size limit. +// It deduplicates references, so the index may be the same as one that was +// returned from an earlier add call. +func (c *Collector) add(r reference) (outputIndex int, ok bool) { + if i, ok := c.index[r]; ok { + return i, true + } + i := len(c.table) + if i >= c.limit { + return 0, false + } + c.index[r] = i + c.table = append(c.table, r) + return i, true +} + +func addMember(v *cd.Variable, name string) *cd.Variable { + v2 := &cd.Variable{Name: name} + v.Members = append(v.Members, v2) + return v2 +} + +// ReadValues fetches values of the variables that were passed to the Collector +// with AddVariable. The values of any new variables found are also fetched, +// e.g. the targets of pointers or the members of structs, until we reach the +// size limit or we run out of values to fetch. +// The results are output as a []*cd.Variable, which is the type we need to send +// to the Debuglet Controller after we trigger a breakpoint. +func (c *Collector) ReadValues() (out []*cd.Variable) { + for i := 0; i < len(c.table); i++ { + // Create a new cd.Variable for this value, and append it to the output. + dcv := new(cd.Variable) + out = append(out, dcv) + if i == 0 { + // The first element is unused. + continue + } + switch x := c.table[i].(type) { + case mapElement: + key, value, err := c.prog.MapElement(x.Map, x.index) + if err != nil { + dcv.Status = statusMessage(err.Error(), true, refersToVariableValue) + continue + } + // Add a member for the key. + member := addMember(dcv, "key") + if index, ok := c.add(key); !ok { + // The table is full. + member.Status = statusMessage(messageNotCaptured, true, refersToVariableName) + continue + } else { + member.VarTableIndex = int64(index) + } + // Add a member for the value. + member = addMember(dcv, "value") + if index, ok := c.add(value); !ok { + // The table is full. + member.Status = statusMessage(messageNotCaptured, true, refersToVariableName) + } else { + member.VarTableIndex = int64(index) + } + case debug.Var: + if v, err := c.prog.Value(x); err != nil { + dcv.Status = statusMessage(err.Error(), true, refersToVariableValue) + } else { + c.FillValue(v, dcv) + } + } + } + return out +} + +// indexable is an interface for arrays, slices and channels. +type indexable interface { + Len() uint64 + Element(uint64) debug.Var +} + +// channel implements indexable. +type channel struct { + debug.Channel +} + +func (c channel) Len() uint64 { + return c.Length +} + +var ( + _ indexable = debug.Array{} + _ indexable = debug.Slice{} + _ indexable = channel{} +) + +// FillValue copies a value into a cd.Variable. Any variables referred to by +// that value, e.g. struct members and pointer targets, are added to the +// collector's queue, to be fetched later by ReadValues. +func (c *Collector) FillValue(v debug.Value, dcv *cd.Variable) { + if c, ok := v.(debug.Channel); ok { + // Convert to channel, which implements indexable. + v = channel{c} + } + // Fill in dcv in a manner depending on the type of the value we got. + switch val := v.(type) { + case int8, int16, int32, int64, bool, uint8, uint16, uint32, uint64, float32, float64, complex64, complex128: + // For simple types, we just print the value to dcv.Value. + dcv.Value = fmt.Sprint(val) + case string: + // Put double quotes around strings. + dcv.Value = strconv.Quote(val) + case debug.String: + if uint64(len(val.String)) < val.Length { + // This string value was truncated. + dcv.Value = strconv.Quote(val.String + "...") + } else { + dcv.Value = strconv.Quote(val.String) + } + case debug.Struct: + // For structs, we add an entry to dcv.Members for each field in the + // struct. + // Each member will contain the name of the field, and the index in the + // output table which will contain the value of that field. + for _, f := range val.Fields { + member := addMember(dcv, f.Name) + if index, ok := c.add(f.Var); !ok { + // The table is full. + member.Status = statusMessage(messageNotCaptured, true, refersToVariableName) + } else { + member.VarTableIndex = int64(index) + } + } + case debug.Map: + dcv.Value = fmt.Sprintf("len = %d", val.Length) + for i := uint64(0); i < val.Length; i++ { + field := addMember(dcv, `⚫`) + if i == maxMapLength { + field.Name = "..." + field.Status = statusMessage(messageTruncated, true, refersToVariableName) + break + } + if index, ok := c.add(mapElement{val, i}); !ok { + // The value table is full; add a member to contain the error message. + field.Name = "..." + field.Status = statusMessage(messageNotCaptured, true, refersToVariableName) + break + } else { + field.VarTableIndex = int64(index) + } + } + case debug.Pointer: + if val.Address == 0 { + dcv.Value = "" + } else if val.TypeID == 0 { + // We don't know the type of the pointer, so just output the address as + // the value. + dcv.Value = fmt.Sprintf("0x%X", val.Address) + dcv.Status = statusMessage(messageUnknownPointerType, false, refersToVariableName) + } else { + // Adds the pointed-to variable to the table, and links this value to + // that table entry through VarTableIndex. + dcv.Value = fmt.Sprintf("0x%X", val.Address) + target := addMember(dcv, "") + if index, ok := c.add(debug.Var(val)); !ok { + target.Status = statusMessage(messageNotCaptured, true, refersToVariableName) + } else { + target.VarTableIndex = int64(index) + } + } + case indexable: + // Arrays, slices and channels. + dcv.Value = "len = " + fmt.Sprint(val.Len()) + for j := uint64(0); j < val.Len(); j++ { + field := addMember(dcv, fmt.Sprint(`[`, j, `]`)) + if j == maxArrayLength { + field.Name = "..." + field.Status = statusMessage(messageTruncated, true, refersToVariableName) + break + } + vr := val.Element(j) + if index, ok := c.add(vr); !ok { + // The value table is full; add a member to contain the error message. + field.Name = "..." + field.Status = statusMessage(messageNotCaptured, true, refersToVariableName) + break + } else { + // Add a member with the index as the name. + field.VarTableIndex = int64(index) + } + } + default: + dcv.Status = statusMessage(messageUnknownType, false, refersToVariableName) + } +} + +// statusMessage returns a *cd.StatusMessage with the given message, IsError +// field and refersTo field. +func statusMessage(msg string, isError bool, refersTo int) *cd.StatusMessage { + return &cd.StatusMessage{ + Description: &cd.FormatMessage{Format: "$0", Parameters: []string{msg}}, + IsError: isError, + RefersTo: refersToString[refersTo], + } +} + +// LogString produces a string for a logpoint, substituting in variable values +// using evaluatedExpressions and varTable. +func LogString(s string, evaluatedExpressions []*cd.Variable, varTable []*cd.Variable) string { + var buf bytes.Buffer + fmt.Fprintf(&buf, "LOGPOINT: ") + seen := make(map[*cd.Variable]bool) + for i := 0; i < len(s); { + if s[i] == '$' { + i++ + if num, n, ok := parseToken(s[i:], len(evaluatedExpressions)-1); ok { + // This token is one of $0, $1, etc. Write the corresponding expression. + writeExpression(&buf, evaluatedExpressions[num], false, varTable, seen) + i += n + } else { + // Something else, like $$. + buf.WriteByte(s[i]) + i++ + } + } else { + buf.WriteByte(s[i]) + i++ + } + } + return buf.String() +} + +func parseToken(s string, max int) (num int, bytesRead int, ok bool) { + var i int + for i < len(s) && s[i] >= '0' && s[i] <= '9' { + i++ + } + num, err := strconv.Atoi(s[:i]) + return num, i, err == nil && num <= max +} + +// writeExpression recursively writes variables to buf, in a format suitable +// for logging. If printName is true, writes the name of the variable. +func writeExpression(buf *bytes.Buffer, v *cd.Variable, printName bool, varTable []*cd.Variable, seen map[*cd.Variable]bool) { + if v == nil { + // Shouldn't happen. + return + } + name, value, status, members := v.Name, v.Value, v.Status, v.Members + + // If v.VarTableIndex is not zero, it refers to an element of varTable. + // We merge its fields with the fields we got from v. + var other *cd.Variable + if idx := int(v.VarTableIndex); idx > 0 && idx < len(varTable) { + other = varTable[idx] + } + if other != nil { + if name == "" { + name = other.Name + } + if value == "" { + value = other.Value + } + if status == nil { + status = other.Status + } + if len(members) == 0 { + members = other.Members + } + } + if printName && name != "" { + buf.WriteString(name) + buf.WriteByte(':') + } + + // If we have seen this value before, write "..." rather than repeating it. + if seen[v] { + buf.WriteString("...") + return + } + seen[v] = true + if other != nil { + if seen[other] { + buf.WriteString("...") + return + } + seen[other] = true + } + + if value != "" && !strings.HasPrefix(value, "len = ") { + // A plain value. + buf.WriteString(value) + } else if status != nil && status.Description != nil { + // An error. + for _, p := range status.Description.Parameters { + buf.WriteByte('(') + buf.WriteString(p) + buf.WriteByte(')') + } + } else if name == `⚫` { + // A map element. + first := true + for _, member := range members { + if first { + first = false + } else { + buf.WriteByte(':') + } + writeExpression(buf, member, false, varTable, seen) + } + } else { + // A map, array, slice, channel, or struct. + isStruct := value == "" + first := true + buf.WriteByte('{') + for _, member := range members { + if first { + first = false + } else { + buf.WriteString(", ") + } + writeExpression(buf, member, isStruct, varTable, seen) + } + buf.WriteByte('}') + } +} + +const ( + // Error messages for cd.StatusMessage + messageNotCaptured = "Not captured" + messageTruncated = "Truncated" + messageUnknownPointerType = "Unknown pointer type" + messageUnknownType = "Unknown type" + // RefersTo values for cd.StatusMessage. + refersToVariableName = iota + refersToVariableValue +) + +// refersToString contains the strings for each refersTo value. +// See the definition of StatusMessage in the v2/clouddebugger package. +var refersToString = map[int]string{ + refersToVariableName: "VARIABLE_NAME", + refersToVariableValue: "VARIABLE_VALUE", +} diff --git a/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector_test.go b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector_test.go new file mode 100644 index 00000000..30da2cc3 --- /dev/null +++ b/vendor/cloud.google.com/go/cmd/go-cloud-debug-agent/internal/valuecollector/valuecollector_test.go @@ -0,0 +1,418 @@ +// Copyright 2016 Google LLC +// +// 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 valuecollector + +import ( + "fmt" + "testing" + + "cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug" + "cloud.google.com/go/internal/testutil" + cd "google.golang.org/api/clouddebugger/v2" +) + +const ( + // Some arbitrary type IDs for the test, for use in debug.Var's TypeID field. + // A TypeID of 0 means the type is unknown, so we start at 1. + int16Type = iota + 1 + stringType + structType + pointerType + arrayType + int32Type + debugStringType + mapType + channelType + sliceType +) + +func TestValueCollector(t *testing.T) { + // Construct the collector. + c := NewCollector(&Program{}, 26) + // Add some variables of various types, whose values we want the collector to read. + variablesToAdd := []debug.LocalVar{ + {Name: "a", Var: debug.Var{TypeID: int16Type, Address: 0x1}}, + {Name: "b", Var: debug.Var{TypeID: stringType, Address: 0x2}}, + {Name: "c", Var: debug.Var{TypeID: structType, Address: 0x3}}, + {Name: "d", Var: debug.Var{TypeID: pointerType, Address: 0x4}}, + {Name: "e", Var: debug.Var{TypeID: arrayType, Address: 0x5}}, + {Name: "f", Var: debug.Var{TypeID: debugStringType, Address: 0x6}}, + {Name: "g", Var: debug.Var{TypeID: mapType, Address: 0x7}}, + {Name: "h", Var: debug.Var{TypeID: channelType, Address: 0x8}}, + {Name: "i", Var: debug.Var{TypeID: sliceType, Address: 0x9}}, + } + expectedResults := []*cd.Variable{ + {Name: "a", VarTableIndex: 1}, + {Name: "b", VarTableIndex: 2}, + {Name: "c", VarTableIndex: 3}, + {Name: "d", VarTableIndex: 4}, + {Name: "e", VarTableIndex: 5}, + {Name: "f", VarTableIndex: 6}, + {Name: "g", VarTableIndex: 7}, + {Name: "h", VarTableIndex: 8}, + {Name: "i", VarTableIndex: 9}, + } + for i, v := range variablesToAdd { + added := c.AddVariable(v) + if !testutil.Equal(added, expectedResults[i]) { + t.Errorf("AddVariable: got %+v want %+v", *added, *expectedResults[i]) + } + } + // Read the values, compare the output to what we expect. + v := c.ReadValues() + expectedValues := []*cd.Variable{ + {}, + {Value: "1"}, + {Value: `"hello"`}, + { + Members: []*cd.Variable{ + {Name: "x", VarTableIndex: 1}, + {Name: "y", VarTableIndex: 2}, + }, + }, + { + Members: []*cd.Variable{ + {VarTableIndex: 1}, + }, + Value: "0x1", + }, + { + Members: []*cd.Variable{ + {Name: "[0]", VarTableIndex: 10}, + {Name: "[1]", VarTableIndex: 11}, + {Name: "[2]", VarTableIndex: 12}, + {Name: "[3]", VarTableIndex: 13}, + }, + Value: "len = 4", + }, + {Value: `"world"`}, + { + Members: []*cd.Variable{ + {Name: "⚫", VarTableIndex: 14}, + {Name: "⚫", VarTableIndex: 15}, + {Name: "⚫", VarTableIndex: 16}, + }, + Value: "len = 3", + }, + { + Members: []*cd.Variable{ + {Name: "[0]", VarTableIndex: 17}, + {Name: "[1]", VarTableIndex: 18}, + }, + Value: "len = 2", + }, + { + Members: []*cd.Variable{ + {Name: "[0]", VarTableIndex: 19}, + {Name: "[1]", VarTableIndex: 20}, + }, + Value: "len = 2", + }, + {Value: "100"}, + {Value: "104"}, + {Value: "108"}, + {Value: "112"}, + { + Members: []*cd.Variable{ + {Name: "key", VarTableIndex: 21}, + {Name: "value", VarTableIndex: 22}, + }, + }, + { + Members: []*cd.Variable{ + {Name: "key", VarTableIndex: 23}, + {Name: "value", VarTableIndex: 24}, + }, + }, + { + Members: []*cd.Variable{ + {Name: "key", VarTableIndex: 25}, + { + Name: "value", + Status: &cd.StatusMessage{ + Description: &cd.FormatMessage{ + Format: "$0", + Parameters: []string{"Not captured"}, + }, + IsError: true, + RefersTo: "VARIABLE_NAME", + }, + }, + }, + }, + {Value: "246"}, + {Value: "210"}, + {Value: "300"}, + {Value: "304"}, + {Value: "400"}, + {Value: "404"}, + {Value: "1400"}, + {Value: "1404"}, + {Value: "2400"}, + } + if !testutil.Equal(v, expectedValues) { + t.Errorf("ReadValues: got %v want %v", v, expectedValues) + // Do element-by-element comparisons, for more useful error messages. + for i := range v { + if i < len(expectedValues) && !testutil.Equal(v[i], expectedValues[i]) { + t.Errorf("element %d: got %+v want %+v", i, *v[i], *expectedValues[i]) + } + } + } +} + +// Program implements the similarly-named interface in x/debug. +// ValueCollector should only call its Value and MapElement methods. +type Program struct { + debug.Program +} + +func (p *Program) Value(v debug.Var) (debug.Value, error) { + // We determine what to return using v.TypeID. + switch v.TypeID { + case int16Type: + // We use the address as the value, so that we're testing whether the right + // address was calculated. + return int16(v.Address), nil + case stringType: + // A string. + return "hello", nil + case structType: + // A struct with two elements. + return debug.Struct{ + Fields: []debug.StructField{ + { + Name: "x", + Var: debug.Var{TypeID: int16Type, Address: 0x1}, + }, + { + Name: "y", + Var: debug.Var{TypeID: stringType, Address: 0x2}, + }, + }, + }, nil + case pointerType: + // A pointer to the first variable above. + return debug.Pointer{TypeID: int16Type, Address: 0x1}, nil + case arrayType: + // An array of 4 32-bit-wide elements. + return debug.Array{ + ElementTypeID: int32Type, + Address: 0x64, + Length: 4, + StrideBits: 32, + }, nil + case debugStringType: + return debug.String{ + Length: 5, + String: "world", + }, nil + case mapType: + return debug.Map{ + TypeID: 99, + Address: 0x100, + Length: 3, + }, nil + case channelType: + return debug.Channel{ + ElementTypeID: int32Type, + Address: 200, + Buffer: 210, + Length: 2, + Capacity: 10, + Stride: 4, + BufferStart: 9, + }, nil + case sliceType: + // A slice of 2 32-bit-wide elements. + return debug.Slice{ + Array: debug.Array{ + ElementTypeID: int32Type, + Address: 300, + Length: 2, + StrideBits: 32, + }, + Capacity: 50, + }, nil + case int32Type: + // We use the address as the value, so that we're testing whether the right + // address was calculated. + return int32(v.Address), nil + } + return nil, fmt.Errorf("unexpected Value request") +} + +func (p *Program) MapElement(m debug.Map, index uint64) (debug.Var, debug.Var, error) { + return debug.Var{TypeID: int16Type, Address: 1000*index + 400}, + debug.Var{TypeID: int32Type, Address: 1000*index + 404}, + nil +} + +func TestLogString(t *testing.T) { + bp := cd.Breakpoint{ + Action: "LOG", + LogMessageFormat: "$0 hello, $$7world! $1 $2 $3 $4 $5$6 $7 $8", + EvaluatedExpressions: []*cd.Variable{ + {Name: "a", VarTableIndex: 1}, + {Name: "b", VarTableIndex: 2}, + {Name: "c", VarTableIndex: 3}, + {Name: "d", VarTableIndex: 4}, + {Name: "e", VarTableIndex: 5}, + {Name: "f", VarTableIndex: 6}, + {Name: "g", VarTableIndex: 7}, + {Name: "h", VarTableIndex: 8}, + {Name: "i", VarTableIndex: 9}, + }, + } + varTable := []*cd.Variable{ + {}, + {Value: "1"}, + {Value: `"hello"`}, + { + Members: []*cd.Variable{ + {Name: "x", Value: "1"}, + {Name: "y", Value: `"hello"`}, + {Name: "z", VarTableIndex: 3}, + }, + }, + { + Members: []*cd.Variable{ + {VarTableIndex: 1}, + }, + Value: "0x1", + }, + { + Members: []*cd.Variable{ + {Name: "[0]", VarTableIndex: 10}, + {Name: "[1]", VarTableIndex: 11}, + {Name: "[2]", VarTableIndex: 12}, + {Name: "[3]", VarTableIndex: 13}, + }, + Value: "len = 4", + }, + {Value: `"world"`}, + { + Members: []*cd.Variable{ + {Name: "⚫", VarTableIndex: 14}, + {Name: "⚫", VarTableIndex: 15}, + {Name: "⚫", VarTableIndex: 16}, + }, + Value: "len = 3", + }, + { + Members: []*cd.Variable{ + {Name: "[0]", VarTableIndex: 17}, + {Name: "[1]", VarTableIndex: 18}, + }, + Value: "len = 2", + }, + { + Members: []*cd.Variable{ + {Name: "[0]", VarTableIndex: 19}, + {Name: "[1]", VarTableIndex: 20}, + }, + Value: "len = 2", + }, + {Value: "100"}, + {Value: "104"}, + {Value: "108"}, + {Value: "112"}, + { + Members: []*cd.Variable{ + {Name: "key", VarTableIndex: 21}, + {Name: "value", VarTableIndex: 22}, + }, + }, + { + Members: []*cd.Variable{ + {Name: "key", VarTableIndex: 23}, + {Name: "value", VarTableIndex: 24}, + }, + }, + { + Members: []*cd.Variable{ + {Name: "key", VarTableIndex: 25}, + { + Name: "value", + Status: &cd.StatusMessage{ + Description: &cd.FormatMessage{ + Format: "$0", + Parameters: []string{"Not captured"}, + }, + IsError: true, + RefersTo: "VARIABLE_NAME", + }, + }, + }, + }, + {Value: "246"}, + {Value: "210"}, + {Value: "300"}, + {Value: "304"}, + {Value: "400"}, + {Value: "404"}, + {Value: "1400"}, + {Value: "1404"}, + {Value: "2400"}, + } + s := LogString(bp.LogMessageFormat, bp.EvaluatedExpressions, varTable) + expected := `LOGPOINT: 1 hello, $7world! "hello" {x:1, y:"hello", z:...} ` + + `0x1 {100, 104, 108, 112} "world"{400:404, 1400:1404, 2400:(Not captured)} ` + + `{246, 210} {300, 304}` + if s != expected { + t.Errorf("LogString: got %q want %q", s, expected) + } +} + +func TestParseToken(t *testing.T) { + for _, c := range []struct { + s string + max int + num int + n int + ok bool + }{ + {"", 0, 0, 0, false}, + {".", 0, 0, 0, false}, + {"0", 0, 0, 1, true}, + {"0", 1, 0, 1, true}, + {"00", 0, 0, 2, true}, + {"1.", 1, 1, 1, true}, + {"1.", 0, 0, 0, false}, + {"10", 10, 10, 2, true}, + {"10..", 10, 10, 2, true}, + {"10", 11, 10, 2, true}, + {"10..", 11, 10, 2, true}, + {"10", 9, 0, 0, false}, + {"10..", 9, 0, 0, false}, + {" 10", 10, 0, 0, false}, + {"010", 10, 10, 3, true}, + {"123456789", 123456789, 123456789, 9, true}, + {"123456789", 123456788, 0, 0, false}, + {"123456789123456789123456789", 999999999, 0, 0, false}, + } { + num, n, ok := parseToken(c.s, c.max) + if ok != c.ok { + t.Errorf("parseToken(%q, %d): got ok=%t want ok=%t", c.s, c.max, ok, c.ok) + continue + } + if !ok { + continue + } + if num != c.num || n != c.n { + t.Errorf("parseToken(%q, %d): got %d,%d,%t want %d,%d,%t", c.s, c.max, num, n, ok, c.num, c.n, c.ok) + } + } +} diff --git a/vendor/cloud.google.com/go/compute/metadata/examples_test.go b/vendor/cloud.google.com/go/compute/metadata/examples_test.go new file mode 100644 index 00000000..6c546a63 --- /dev/null +++ b/vendor/cloud.google.com/go/compute/metadata/examples_test.go @@ -0,0 +1,46 @@ +// Copyright 2018 Google LLC +// +// 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 metadata_test + +import ( + "net/http" + + "cloud.google.com/go/compute/metadata" +) + +// This example demonstrates how to use your own transport when using this package. +func ExampleNewClient() { + c := metadata.NewClient(&http.Client{Transport: userAgentTransport{ + userAgent: "my-user-agent", + base: http.DefaultTransport, + }}) + p, err := c.ProjectID() + if err != nil { + // TODO: Handle error. + } + _ = p // TODO: Use p. +} + +// userAgentTransport sets the User-Agent header before calling base. +type userAgentTransport struct { + userAgent string + base http.RoundTripper +} + +// RoundTrip implements the http.RoundTripper interface. +func (t userAgentTransport) RoundTrip(req *http.Request) (*http.Response, error) { + req.Header.Set("User-Agent", t.userAgent) + return t.base.RoundTrip(req) +} diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata.go b/vendor/cloud.google.com/go/compute/metadata/metadata.go new file mode 100644 index 00000000..0d929a61 --- /dev/null +++ b/vendor/cloud.google.com/go/compute/metadata/metadata.go @@ -0,0 +1,501 @@ +// Copyright 2014 Google LLC +// +// 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 metadata provides access to Google Compute Engine (GCE) +// metadata and API service accounts. +// +// This package is a wrapper around the GCE metadata service, +// as documented at https://developers.google.com/compute/docs/metadata. +package metadata // import "cloud.google.com/go/compute/metadata" + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net" + "net/http" + "net/url" + "os" + "runtime" + "strings" + "sync" + "time" +) + +const ( + // metadataIP is the documented metadata server IP address. + metadataIP = "169.254.169.254" + + // metadataHostEnv is the environment variable specifying the + // GCE metadata hostname. If empty, the default value of + // metadataIP ("169.254.169.254") is used instead. + // This is variable name is not defined by any spec, as far as + // I know; it was made up for the Go package. + metadataHostEnv = "GCE_METADATA_HOST" + + userAgent = "gcloud-golang/0.1" +) + +type cachedValue struct { + k string + trim bool + mu sync.Mutex + v string +} + +var ( + projID = &cachedValue{k: "project/project-id", trim: true} + projNum = &cachedValue{k: "project/numeric-project-id", trim: true} + instID = &cachedValue{k: "instance/id", trim: true} +) + +var ( + defaultClient = &Client{hc: &http.Client{ + Transport: &http.Transport{ + Dial: (&net.Dialer{ + Timeout: 2 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + ResponseHeaderTimeout: 2 * time.Second, + }, + }} + subscribeClient = &Client{hc: &http.Client{ + Transport: &http.Transport{ + Dial: (&net.Dialer{ + Timeout: 2 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + }, + }} +) + +// NotDefinedError is returned when requested metadata is not defined. +// +// The underlying string is the suffix after "/computeMetadata/v1/". +// +// This error is not returned if the value is defined to be the empty +// string. +type NotDefinedError string + +func (suffix NotDefinedError) Error() string { + return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix)) +} + +func (c *cachedValue) get(cl *Client) (v string, err error) { + defer c.mu.Unlock() + c.mu.Lock() + if c.v != "" { + return c.v, nil + } + if c.trim { + v, err = cl.getTrimmed(c.k) + } else { + v, err = cl.Get(c.k) + } + if err == nil { + c.v = v + } + return +} + +var ( + onGCEOnce sync.Once + onGCE bool +) + +// OnGCE reports whether this process is running on Google Compute Engine. +func OnGCE() bool { + onGCEOnce.Do(initOnGCE) + return onGCE +} + +func initOnGCE() { + onGCE = testOnGCE() +} + +func testOnGCE() bool { + // The user explicitly said they're on GCE, so trust them. + if os.Getenv(metadataHostEnv) != "" { + return true + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + resc := make(chan bool, 2) + + // Try two strategies in parallel. + // See https://github.com/GoogleCloudPlatform/google-cloud-go/issues/194 + go func() { + req, _ := http.NewRequest("GET", "http://"+metadataIP, nil) + req.Header.Set("User-Agent", userAgent) + res, err := defaultClient.hc.Do(req.WithContext(ctx)) + if err != nil { + resc <- false + return + } + defer res.Body.Close() + resc <- res.Header.Get("Metadata-Flavor") == "Google" + }() + + go func() { + addrs, err := net.LookupHost("metadata.google.internal") + if err != nil || len(addrs) == 0 { + resc <- false + return + } + resc <- strsContains(addrs, metadataIP) + }() + + tryHarder := systemInfoSuggestsGCE() + if tryHarder { + res := <-resc + if res { + // The first strategy succeeded, so let's use it. + return true + } + // Wait for either the DNS or metadata server probe to + // contradict the other one and say we are running on + // GCE. Give it a lot of time to do so, since the system + // info already suggests we're running on a GCE BIOS. + timer := time.NewTimer(5 * time.Second) + defer timer.Stop() + select { + case res = <-resc: + return res + case <-timer.C: + // Too slow. Who knows what this system is. + return false + } + } + + // There's no hint from the system info that we're running on + // GCE, so use the first probe's result as truth, whether it's + // true or false. The goal here is to optimize for speed for + // users who are NOT running on GCE. We can't assume that + // either a DNS lookup or an HTTP request to a blackholed IP + // address is fast. Worst case this should return when the + // metaClient's Transport.ResponseHeaderTimeout or + // Transport.Dial.Timeout fires (in two seconds). + return <-resc +} + +// systemInfoSuggestsGCE reports whether the local system (without +// doing network requests) suggests that we're running on GCE. If this +// returns true, testOnGCE tries a bit harder to reach its metadata +// server. +func systemInfoSuggestsGCE() bool { + if runtime.GOOS != "linux" { + // We don't have any non-Linux clues available, at least yet. + return false + } + slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name") + name := strings.TrimSpace(string(slurp)) + return name == "Google" || name == "Google Compute Engine" +} + +// Subscribe calls Client.Subscribe on a client designed for subscribing (one with no +// ResponseHeaderTimeout). +func Subscribe(suffix string, fn func(v string, ok bool) error) error { + return subscribeClient.Subscribe(suffix, fn) +} + +// Get calls Client.Get on the default client. +func Get(suffix string) (string, error) { return defaultClient.Get(suffix) } + +// ProjectID returns the current instance's project ID string. +func ProjectID() (string, error) { return defaultClient.ProjectID() } + +// NumericProjectID returns the current instance's numeric project ID. +func NumericProjectID() (string, error) { return defaultClient.NumericProjectID() } + +// InternalIP returns the instance's primary internal IP address. +func InternalIP() (string, error) { return defaultClient.InternalIP() } + +// ExternalIP returns the instance's primary external (public) IP address. +func ExternalIP() (string, error) { return defaultClient.ExternalIP() } + +// Hostname returns the instance's hostname. This will be of the form +// ".c..internal". +func Hostname() (string, error) { return defaultClient.Hostname() } + +// InstanceTags returns the list of user-defined instance tags, +// assigned when initially creating a GCE instance. +func InstanceTags() ([]string, error) { return defaultClient.InstanceTags() } + +// InstanceID returns the current VM's numeric instance ID. +func InstanceID() (string, error) { return defaultClient.InstanceID() } + +// InstanceName returns the current VM's instance ID string. +func InstanceName() (string, error) { return defaultClient.InstanceName() } + +// Zone returns the current VM's zone, such as "us-central1-b". +func Zone() (string, error) { return defaultClient.Zone() } + +// InstanceAttributes calls Client.InstanceAttributes on the default client. +func InstanceAttributes() ([]string, error) { return defaultClient.InstanceAttributes() } + +// ProjectAttributes calls Client.ProjectAttributes on the default client. +func ProjectAttributes() ([]string, error) { return defaultClient.ProjectAttributes() } + +// InstanceAttributeValue calls Client.InstanceAttributeValue on the default client. +func InstanceAttributeValue(attr string) (string, error) { + return defaultClient.InstanceAttributeValue(attr) +} + +// ProjectAttributeValue calls Client.ProjectAttributeValue on the default client. +func ProjectAttributeValue(attr string) (string, error) { + return defaultClient.ProjectAttributeValue(attr) +} + +// Scopes calls Client.Scopes on the default client. +func Scopes(serviceAccount string) ([]string, error) { return defaultClient.Scopes(serviceAccount) } + +func strsContains(ss []string, s string) bool { + for _, v := range ss { + if v == s { + return true + } + } + return false +} + +// A Client provides metadata. +type Client struct { + hc *http.Client +} + +// NewClient returns a Client that can be used to fetch metadata. All HTTP requests +// will use the given http.Client instead of the default client. +func NewClient(c *http.Client) *Client { + return &Client{hc: c} +} + +// getETag returns a value from the metadata service as well as the associated ETag. +// This func is otherwise equivalent to Get. +func (c *Client) getETag(suffix string) (value, etag string, err error) { + // Using a fixed IP makes it very difficult to spoof the metadata service in + // a container, which is an important use-case for local testing of cloud + // deployments. To enable spoofing of the metadata service, the environment + // variable GCE_METADATA_HOST is first inspected to decide where metadata + // requests shall go. + host := os.Getenv(metadataHostEnv) + if host == "" { + // Using 169.254.169.254 instead of "metadata" here because Go + // binaries built with the "netgo" tag and without cgo won't + // know the search suffix for "metadata" is + // ".google.internal", and this IP address is documented as + // being stable anyway. + host = metadataIP + } + url := "http://" + host + "/computeMetadata/v1/" + suffix + req, _ := http.NewRequest("GET", url, nil) + req.Header.Set("Metadata-Flavor", "Google") + req.Header.Set("User-Agent", userAgent) + res, err := c.hc.Do(req) + if err != nil { + return "", "", err + } + defer res.Body.Close() + if res.StatusCode == http.StatusNotFound { + return "", "", NotDefinedError(suffix) + } + if res.StatusCode != 200 { + return "", "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url) + } + all, err := ioutil.ReadAll(res.Body) + if err != nil { + return "", "", err + } + return string(all), res.Header.Get("Etag"), nil +} + +// Get returns a value from the metadata service. +// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/". +// +// If the GCE_METADATA_HOST environment variable is not defined, a default of +// 169.254.169.254 will be used instead. +// +// If the requested metadata is not defined, the returned error will +// be of type NotDefinedError. +func (c *Client) Get(suffix string) (string, error) { + val, _, err := c.getETag(suffix) + return val, err +} + +func (c *Client) getTrimmed(suffix string) (s string, err error) { + s, err = c.Get(suffix) + s = strings.TrimSpace(s) + return +} + +func (c *Client) lines(suffix string) ([]string, error) { + j, err := c.Get(suffix) + if err != nil { + return nil, err + } + s := strings.Split(strings.TrimSpace(j), "\n") + for i := range s { + s[i] = strings.TrimSpace(s[i]) + } + return s, nil +} + +// ProjectID returns the current instance's project ID string. +func (c *Client) ProjectID() (string, error) { return projID.get(c) } + +// NumericProjectID returns the current instance's numeric project ID. +func (c *Client) NumericProjectID() (string, error) { return projNum.get(c) } + +// InstanceID returns the current VM's numeric instance ID. +func (c *Client) InstanceID() (string, error) { return instID.get(c) } + +// InternalIP returns the instance's primary internal IP address. +func (c *Client) InternalIP() (string, error) { + return c.getTrimmed("instance/network-interfaces/0/ip") +} + +// ExternalIP returns the instance's primary external (public) IP address. +func (c *Client) ExternalIP() (string, error) { + return c.getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip") +} + +// Hostname returns the instance's hostname. This will be of the form +// ".c..internal". +func (c *Client) Hostname() (string, error) { + return c.getTrimmed("instance/hostname") +} + +// InstanceTags returns the list of user-defined instance tags, +// assigned when initially creating a GCE instance. +func (c *Client) InstanceTags() ([]string, error) { + var s []string + j, err := c.Get("instance/tags") + if err != nil { + return nil, err + } + if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil { + return nil, err + } + return s, nil +} + +// InstanceName returns the current VM's instance ID string. +func (c *Client) InstanceName() (string, error) { + host, err := c.Hostname() + if err != nil { + return "", err + } + return strings.Split(host, ".")[0], nil +} + +// Zone returns the current VM's zone, such as "us-central1-b". +func (c *Client) Zone() (string, error) { + zone, err := c.getTrimmed("instance/zone") + // zone is of the form "projects//zones/". + if err != nil { + return "", err + } + return zone[strings.LastIndex(zone, "/")+1:], nil +} + +// InstanceAttributes returns the list of user-defined attributes, +// assigned when initially creating a GCE VM instance. The value of an +// attribute can be obtained with InstanceAttributeValue. +func (c *Client) InstanceAttributes() ([]string, error) { return c.lines("instance/attributes/") } + +// ProjectAttributes returns the list of user-defined attributes +// applying to the project as a whole, not just this VM. The value of +// an attribute can be obtained with ProjectAttributeValue. +func (c *Client) ProjectAttributes() ([]string, error) { return c.lines("project/attributes/") } + +// InstanceAttributeValue returns the value of the provided VM +// instance attribute. +// +// If the requested attribute is not defined, the returned error will +// be of type NotDefinedError. +// +// InstanceAttributeValue may return ("", nil) if the attribute was +// defined to be the empty string. +func (c *Client) InstanceAttributeValue(attr string) (string, error) { + return c.Get("instance/attributes/" + attr) +} + +// ProjectAttributeValue returns the value of the provided +// project attribute. +// +// If the requested attribute is not defined, the returned error will +// be of type NotDefinedError. +// +// ProjectAttributeValue may return ("", nil) if the attribute was +// defined to be the empty string. +func (c *Client) ProjectAttributeValue(attr string) (string, error) { + return c.Get("project/attributes/" + attr) +} + +// Scopes returns the service account scopes for the given account. +// The account may be empty or the string "default" to use the instance's +// main account. +func (c *Client) Scopes(serviceAccount string) ([]string, error) { + if serviceAccount == "" { + serviceAccount = "default" + } + return c.lines("instance/service-accounts/" + serviceAccount + "/scopes") +} + +// Subscribe subscribes to a value from the metadata service. +// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/". +// The suffix may contain query parameters. +// +// Subscribe calls fn with the latest metadata value indicated by the provided +// suffix. If the metadata value is deleted, fn is called with the empty string +// and ok false. Subscribe blocks until fn returns a non-nil error or the value +// is deleted. Subscribe returns the error value returned from the last call to +// fn, which may be nil when ok == false. +func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error { + const failedSubscribeSleep = time.Second * 5 + + // First check to see if the metadata value exists at all. + val, lastETag, err := c.getETag(suffix) + if err != nil { + return err + } + + if err := fn(val, true); err != nil { + return err + } + + ok := true + if strings.ContainsRune(suffix, '?') { + suffix += "&wait_for_change=true&last_etag=" + } else { + suffix += "?wait_for_change=true&last_etag=" + } + for { + val, etag, err := c.getETag(suffix + url.QueryEscape(lastETag)) + if err != nil { + if _, deleted := err.(NotDefinedError); !deleted { + time.Sleep(failedSubscribeSleep) + continue // Retry on other errors. + } + ok = false + } + lastETag = etag + + if err := fn(val, ok); err != nil || !ok { + return err + } + } +} diff --git a/vendor/cloud.google.com/go/compute/metadata/metadata_test.go b/vendor/cloud.google.com/go/compute/metadata/metadata_test.go new file mode 100644 index 00000000..83142b26 --- /dev/null +++ b/vendor/cloud.google.com/go/compute/metadata/metadata_test.go @@ -0,0 +1,80 @@ +// Copyright 2016 Google LLC +// +// 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 metadata + +import ( + "bytes" + "io/ioutil" + "net/http" + "os" + "sync" + "testing" +) + +func TestOnGCE_Stress(t *testing.T) { + if testing.Short() { + t.Skip("skipping in -short mode") + } + var last bool + for i := 0; i < 100; i++ { + onGCEOnce = sync.Once{} + + now := OnGCE() + if i > 0 && now != last { + t.Errorf("%d. changed from %v to %v", i, last, now) + } + last = now + } + t.Logf("OnGCE() = %v", last) +} + +func TestOnGCE_Force(t *testing.T) { + onGCEOnce = sync.Once{} + old := os.Getenv(metadataHostEnv) + defer os.Setenv(metadataHostEnv, old) + os.Setenv(metadataHostEnv, "127.0.0.1") + if !OnGCE() { + t.Error("OnGCE() = false; want true") + } +} + +func TestOverrideUserAgent(t *testing.T) { + const userAgent = "my-user-agent" + rt := &rrt{} + c := NewClient(&http.Client{Transport: userAgentTransport{userAgent, rt}}) + c.Get("foo") + if got, want := rt.gotUserAgent, userAgent; got != want { + t.Errorf("got %q, want %q", got, want) + } +} + +type userAgentTransport struct { + userAgent string + base http.RoundTripper +} + +func (t userAgentTransport) RoundTrip(req *http.Request) (*http.Response, error) { + req.Header.Set("User-Agent", t.userAgent) + return t.base.RoundTrip(req) +} + +type rrt struct { + gotUserAgent string +} + +func (r *rrt) RoundTrip(req *http.Request) (*http.Response, error) { + r.gotUserAgent = req.Header.Get("User-Agent") + return &http.Response{Body: ioutil.NopCloser(bytes.NewReader(nil))}, nil +} diff --git a/vendor/cloud.google.com/go/container/apiv1/ListClusters_smoke_test.go b/vendor/cloud.google.com/go/container/apiv1/ListClusters_smoke_test.go new file mode 100644 index 00000000..7d55b2f5 --- /dev/null +++ b/vendor/cloud.google.com/go/container/apiv1/ListClusters_smoke_test.go @@ -0,0 +1,68 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package container + +import ( + containerpb "google.golang.org/genproto/googleapis/container/v1" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestClusterManagerSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewClusterManagerClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var projectId2 string = projectId + var zone string = "us-central1-a" + var request = &containerpb.ListClustersRequest{ + ProjectId: projectId2, + Zone: zone, + } + + if _, err := c.ListClusters(ctx, request); err != nil { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/container/apiv1/cluster_manager_client.go b/vendor/cloud.google.com/go/container/apiv1/cluster_manager_client.go new file mode 100644 index 00000000..bb3011c3 --- /dev/null +++ b/vendor/cloud.google.com/go/container/apiv1/cluster_manager_client.go @@ -0,0 +1,676 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package container + +import ( + "context" + "time" + + "cloud.google.com/go/internal/version" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + containerpb "google.golang.org/genproto/googleapis/container/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// ClusterManagerCallOptions contains the retry settings for each method of ClusterManagerClient. +type ClusterManagerCallOptions struct { + ListClusters []gax.CallOption + GetCluster []gax.CallOption + CreateCluster []gax.CallOption + UpdateCluster []gax.CallOption + UpdateNodePool []gax.CallOption + SetNodePoolAutoscaling []gax.CallOption + SetLoggingService []gax.CallOption + SetMonitoringService []gax.CallOption + SetAddonsConfig []gax.CallOption + SetLocations []gax.CallOption + UpdateMaster []gax.CallOption + SetMasterAuth []gax.CallOption + DeleteCluster []gax.CallOption + ListOperations []gax.CallOption + GetOperation []gax.CallOption + CancelOperation []gax.CallOption + GetServerConfig []gax.CallOption + ListNodePools []gax.CallOption + GetNodePool []gax.CallOption + CreateNodePool []gax.CallOption + DeleteNodePool []gax.CallOption + RollbackNodePoolUpgrade []gax.CallOption + SetNodePoolManagement []gax.CallOption + SetLabels []gax.CallOption + SetLegacyAbac []gax.CallOption + StartIPRotation []gax.CallOption + CompleteIPRotation []gax.CallOption + SetNodePoolSize []gax.CallOption + SetNetworkPolicy []gax.CallOption + SetMaintenancePolicy []gax.CallOption +} + +func defaultClusterManagerClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("container.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultClusterManagerCallOptions() *ClusterManagerCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &ClusterManagerCallOptions{ + ListClusters: retry[[2]string{"default", "idempotent"}], + GetCluster: retry[[2]string{"default", "idempotent"}], + CreateCluster: retry[[2]string{"default", "non_idempotent"}], + UpdateCluster: retry[[2]string{"default", "non_idempotent"}], + UpdateNodePool: retry[[2]string{"default", "non_idempotent"}], + SetNodePoolAutoscaling: retry[[2]string{"default", "non_idempotent"}], + SetLoggingService: retry[[2]string{"default", "non_idempotent"}], + SetMonitoringService: retry[[2]string{"default", "non_idempotent"}], + SetAddonsConfig: retry[[2]string{"default", "non_idempotent"}], + SetLocations: retry[[2]string{"default", "non_idempotent"}], + UpdateMaster: retry[[2]string{"default", "non_idempotent"}], + SetMasterAuth: retry[[2]string{"default", "non_idempotent"}], + DeleteCluster: retry[[2]string{"default", "idempotent"}], + ListOperations: retry[[2]string{"default", "idempotent"}], + GetOperation: retry[[2]string{"default", "idempotent"}], + CancelOperation: retry[[2]string{"default", "non_idempotent"}], + GetServerConfig: retry[[2]string{"default", "idempotent"}], + ListNodePools: retry[[2]string{"default", "idempotent"}], + GetNodePool: retry[[2]string{"default", "idempotent"}], + CreateNodePool: retry[[2]string{"default", "non_idempotent"}], + DeleteNodePool: retry[[2]string{"default", "idempotent"}], + RollbackNodePoolUpgrade: retry[[2]string{"default", "non_idempotent"}], + SetNodePoolManagement: retry[[2]string{"default", "non_idempotent"}], + SetLabels: retry[[2]string{"default", "non_idempotent"}], + SetLegacyAbac: retry[[2]string{"default", "non_idempotent"}], + StartIPRotation: retry[[2]string{"default", "non_idempotent"}], + CompleteIPRotation: retry[[2]string{"default", "non_idempotent"}], + SetNodePoolSize: retry[[2]string{"default", "non_idempotent"}], + SetNetworkPolicy: retry[[2]string{"default", "non_idempotent"}], + SetMaintenancePolicy: retry[[2]string{"default", "non_idempotent"}], + } +} + +// ClusterManagerClient is a client for interacting with Google Container Engine API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type ClusterManagerClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + clusterManagerClient containerpb.ClusterManagerClient + + // The call options for this service. + CallOptions *ClusterManagerCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClusterManagerClient creates a new cluster manager client. +// +// Google Container Engine Cluster Manager v1 +func NewClusterManagerClient(ctx context.Context, opts ...option.ClientOption) (*ClusterManagerClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClusterManagerClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &ClusterManagerClient{ + conn: conn, + CallOptions: defaultClusterManagerCallOptions(), + + clusterManagerClient: containerpb.NewClusterManagerClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *ClusterManagerClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *ClusterManagerClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *ClusterManagerClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", version.Go()}, keyval...) + kv = append(kv, "gapic", version.Repo, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListClusters lists all clusters owned by a project in either the specified zone or all +// zones. +func (c *ClusterManagerClient) ListClusters(ctx context.Context, req *containerpb.ListClustersRequest, opts ...gax.CallOption) (*containerpb.ListClustersResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListClusters[0:len(c.CallOptions.ListClusters):len(c.CallOptions.ListClusters)], opts...) + var resp *containerpb.ListClustersResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.ListClusters(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetCluster gets the details of a specific cluster. +func (c *ClusterManagerClient) GetCluster(ctx context.Context, req *containerpb.GetClusterRequest, opts ...gax.CallOption) (*containerpb.Cluster, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetCluster[0:len(c.CallOptions.GetCluster):len(c.CallOptions.GetCluster)], opts...) + var resp *containerpb.Cluster + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.GetCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateCluster creates a cluster, consisting of the specified number and type of Google +// Compute Engine instances. +// +// By default, the cluster is created in the project's +// default network (at /compute/docs/networks-and-firewalls#networks). +// +// One firewall is added for the cluster. After cluster creation, +// the cluster creates routes for each node to allow the containers +// on that node to communicate with all other instances in the +// cluster. +// +// Finally, an entry is added to the project's global metadata indicating +// which CIDR range is being used by the cluster. +func (c *ClusterManagerClient) CreateCluster(ctx context.Context, req *containerpb.CreateClusterRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateCluster[0:len(c.CallOptions.CreateCluster):len(c.CallOptions.CreateCluster)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.CreateCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateCluster updates the settings of a specific cluster. +func (c *ClusterManagerClient) UpdateCluster(ctx context.Context, req *containerpb.UpdateClusterRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateCluster[0:len(c.CallOptions.UpdateCluster):len(c.CallOptions.UpdateCluster)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.UpdateCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateNodePool updates the version and/or image type of a specific node pool. +func (c *ClusterManagerClient) UpdateNodePool(ctx context.Context, req *containerpb.UpdateNodePoolRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateNodePool[0:len(c.CallOptions.UpdateNodePool):len(c.CallOptions.UpdateNodePool)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.UpdateNodePool(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetNodePoolAutoscaling sets the autoscaling settings of a specific node pool. +func (c *ClusterManagerClient) SetNodePoolAutoscaling(ctx context.Context, req *containerpb.SetNodePoolAutoscalingRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetNodePoolAutoscaling[0:len(c.CallOptions.SetNodePoolAutoscaling):len(c.CallOptions.SetNodePoolAutoscaling)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.SetNodePoolAutoscaling(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetLoggingService sets the logging service of a specific cluster. +func (c *ClusterManagerClient) SetLoggingService(ctx context.Context, req *containerpb.SetLoggingServiceRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetLoggingService[0:len(c.CallOptions.SetLoggingService):len(c.CallOptions.SetLoggingService)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.SetLoggingService(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetMonitoringService sets the monitoring service of a specific cluster. +func (c *ClusterManagerClient) SetMonitoringService(ctx context.Context, req *containerpb.SetMonitoringServiceRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetMonitoringService[0:len(c.CallOptions.SetMonitoringService):len(c.CallOptions.SetMonitoringService)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.SetMonitoringService(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetAddonsConfig sets the addons of a specific cluster. +func (c *ClusterManagerClient) SetAddonsConfig(ctx context.Context, req *containerpb.SetAddonsConfigRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetAddonsConfig[0:len(c.CallOptions.SetAddonsConfig):len(c.CallOptions.SetAddonsConfig)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.SetAddonsConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetLocations sets the locations of a specific cluster. +func (c *ClusterManagerClient) SetLocations(ctx context.Context, req *containerpb.SetLocationsRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetLocations[0:len(c.CallOptions.SetLocations):len(c.CallOptions.SetLocations)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.SetLocations(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateMaster updates the master of a specific cluster. +func (c *ClusterManagerClient) UpdateMaster(ctx context.Context, req *containerpb.UpdateMasterRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateMaster[0:len(c.CallOptions.UpdateMaster):len(c.CallOptions.UpdateMaster)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.UpdateMaster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetMasterAuth used to set master auth materials. Currently supports :- +// Changing the admin password of a specific cluster. +// This can be either via password generation or explicitly set the password. +func (c *ClusterManagerClient) SetMasterAuth(ctx context.Context, req *containerpb.SetMasterAuthRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetMasterAuth[0:len(c.CallOptions.SetMasterAuth):len(c.CallOptions.SetMasterAuth)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.SetMasterAuth(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteCluster deletes the cluster, including the Kubernetes endpoint and all worker +// nodes. +// +// Firewalls and routes that were configured during cluster creation +// are also deleted. +// +// Other Google Compute Engine resources that might be in use by the cluster +// (e.g. load balancer resources) will not be deleted if they weren't present +// at the initial create time. +func (c *ClusterManagerClient) DeleteCluster(ctx context.Context, req *containerpb.DeleteClusterRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteCluster[0:len(c.CallOptions.DeleteCluster):len(c.CallOptions.DeleteCluster)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.DeleteCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListOperations lists all operations in a project in a specific zone or all zones. +func (c *ClusterManagerClient) ListOperations(ctx context.Context, req *containerpb.ListOperationsRequest, opts ...gax.CallOption) (*containerpb.ListOperationsResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListOperations[0:len(c.CallOptions.ListOperations):len(c.CallOptions.ListOperations)], opts...) + var resp *containerpb.ListOperationsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.ListOperations(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetOperation gets the specified operation. +func (c *ClusterManagerClient) GetOperation(ctx context.Context, req *containerpb.GetOperationRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetOperation[0:len(c.CallOptions.GetOperation):len(c.CallOptions.GetOperation)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.GetOperation(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CancelOperation cancels the specified operation. +func (c *ClusterManagerClient) CancelOperation(ctx context.Context, req *containerpb.CancelOperationRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CancelOperation[0:len(c.CallOptions.CancelOperation):len(c.CallOptions.CancelOperation)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.clusterManagerClient.CancelOperation(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// GetServerConfig returns configuration info about the Container Engine service. +func (c *ClusterManagerClient) GetServerConfig(ctx context.Context, req *containerpb.GetServerConfigRequest, opts ...gax.CallOption) (*containerpb.ServerConfig, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetServerConfig[0:len(c.CallOptions.GetServerConfig):len(c.CallOptions.GetServerConfig)], opts...) + var resp *containerpb.ServerConfig + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.GetServerConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListNodePools lists the node pools for a cluster. +func (c *ClusterManagerClient) ListNodePools(ctx context.Context, req *containerpb.ListNodePoolsRequest, opts ...gax.CallOption) (*containerpb.ListNodePoolsResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListNodePools[0:len(c.CallOptions.ListNodePools):len(c.CallOptions.ListNodePools)], opts...) + var resp *containerpb.ListNodePoolsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.ListNodePools(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetNodePool retrieves the node pool requested. +func (c *ClusterManagerClient) GetNodePool(ctx context.Context, req *containerpb.GetNodePoolRequest, opts ...gax.CallOption) (*containerpb.NodePool, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetNodePool[0:len(c.CallOptions.GetNodePool):len(c.CallOptions.GetNodePool)], opts...) + var resp *containerpb.NodePool + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.GetNodePool(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateNodePool creates a node pool for a cluster. +func (c *ClusterManagerClient) CreateNodePool(ctx context.Context, req *containerpb.CreateNodePoolRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateNodePool[0:len(c.CallOptions.CreateNodePool):len(c.CallOptions.CreateNodePool)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.CreateNodePool(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteNodePool deletes a node pool from a cluster. +func (c *ClusterManagerClient) DeleteNodePool(ctx context.Context, req *containerpb.DeleteNodePoolRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteNodePool[0:len(c.CallOptions.DeleteNodePool):len(c.CallOptions.DeleteNodePool)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.DeleteNodePool(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// RollbackNodePoolUpgrade roll back the previously Aborted or Failed NodePool upgrade. +// This will be an no-op if the last upgrade successfully completed. +func (c *ClusterManagerClient) RollbackNodePoolUpgrade(ctx context.Context, req *containerpb.RollbackNodePoolUpgradeRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.RollbackNodePoolUpgrade[0:len(c.CallOptions.RollbackNodePoolUpgrade):len(c.CallOptions.RollbackNodePoolUpgrade)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.RollbackNodePoolUpgrade(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetNodePoolManagement sets the NodeManagement options for a node pool. +func (c *ClusterManagerClient) SetNodePoolManagement(ctx context.Context, req *containerpb.SetNodePoolManagementRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetNodePoolManagement[0:len(c.CallOptions.SetNodePoolManagement):len(c.CallOptions.SetNodePoolManagement)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.SetNodePoolManagement(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetLabels sets labels on a cluster. +func (c *ClusterManagerClient) SetLabels(ctx context.Context, req *containerpb.SetLabelsRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetLabels[0:len(c.CallOptions.SetLabels):len(c.CallOptions.SetLabels)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.SetLabels(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetLegacyAbac enables or disables the ABAC authorization mechanism on a cluster. +func (c *ClusterManagerClient) SetLegacyAbac(ctx context.Context, req *containerpb.SetLegacyAbacRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetLegacyAbac[0:len(c.CallOptions.SetLegacyAbac):len(c.CallOptions.SetLegacyAbac)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.SetLegacyAbac(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// StartIPRotation start master IP rotation. +func (c *ClusterManagerClient) StartIPRotation(ctx context.Context, req *containerpb.StartIPRotationRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.StartIPRotation[0:len(c.CallOptions.StartIPRotation):len(c.CallOptions.StartIPRotation)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.StartIPRotation(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CompleteIPRotation completes master IP rotation. +func (c *ClusterManagerClient) CompleteIPRotation(ctx context.Context, req *containerpb.CompleteIPRotationRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CompleteIPRotation[0:len(c.CallOptions.CompleteIPRotation):len(c.CallOptions.CompleteIPRotation)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.CompleteIPRotation(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetNodePoolSize sets the size of a specific node pool. +func (c *ClusterManagerClient) SetNodePoolSize(ctx context.Context, req *containerpb.SetNodePoolSizeRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetNodePoolSize[0:len(c.CallOptions.SetNodePoolSize):len(c.CallOptions.SetNodePoolSize)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.SetNodePoolSize(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetNetworkPolicy enables/Disables Network Policy for a cluster. +func (c *ClusterManagerClient) SetNetworkPolicy(ctx context.Context, req *containerpb.SetNetworkPolicyRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetNetworkPolicy[0:len(c.CallOptions.SetNetworkPolicy):len(c.CallOptions.SetNetworkPolicy)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.SetNetworkPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetMaintenancePolicy sets the maintenance policy for a cluster. +func (c *ClusterManagerClient) SetMaintenancePolicy(ctx context.Context, req *containerpb.SetMaintenancePolicyRequest, opts ...gax.CallOption) (*containerpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetMaintenancePolicy[0:len(c.CallOptions.SetMaintenancePolicy):len(c.CallOptions.SetMaintenancePolicy)], opts...) + var resp *containerpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterManagerClient.SetMaintenancePolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/container/apiv1/cluster_manager_client_example_test.go b/vendor/cloud.google.com/go/container/apiv1/cluster_manager_client_example_test.go new file mode 100644 index 00000000..ffd98610 --- /dev/null +++ b/vendor/cloud.google.com/go/container/apiv1/cluster_manager_client_example_test.go @@ -0,0 +1,572 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package container_test + +import ( + "context" + + container "cloud.google.com/go/container/apiv1" + containerpb "google.golang.org/genproto/googleapis/container/v1" +) + +func ExampleNewClusterManagerClient() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClusterManagerClient_ListClusters() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.ListClustersRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ListClusters(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_GetCluster() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.GetClusterRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_CreateCluster() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.CreateClusterRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_UpdateCluster() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.UpdateClusterRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_UpdateNodePool() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.UpdateNodePoolRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateNodePool(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_SetNodePoolAutoscaling() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.SetNodePoolAutoscalingRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetNodePoolAutoscaling(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_SetLoggingService() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.SetLoggingServiceRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetLoggingService(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_SetMonitoringService() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.SetMonitoringServiceRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetMonitoringService(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_SetAddonsConfig() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.SetAddonsConfigRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetAddonsConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_SetLocations() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.SetLocationsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetLocations(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_UpdateMaster() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.UpdateMasterRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateMaster(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_SetMasterAuth() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.SetMasterAuthRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetMasterAuth(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_DeleteCluster() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.DeleteClusterRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.DeleteCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_ListOperations() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.ListOperationsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ListOperations(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_GetOperation() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.GetOperationRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetOperation(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_CancelOperation() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.CancelOperationRequest{ + // TODO: Fill request struct fields. + } + err = c.CancelOperation(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClusterManagerClient_GetServerConfig() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.GetServerConfigRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetServerConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_ListNodePools() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.ListNodePoolsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ListNodePools(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_GetNodePool() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.GetNodePoolRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetNodePool(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_CreateNodePool() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.CreateNodePoolRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateNodePool(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_DeleteNodePool() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.DeleteNodePoolRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.DeleteNodePool(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_RollbackNodePoolUpgrade() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.RollbackNodePoolUpgradeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.RollbackNodePoolUpgrade(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_SetNodePoolManagement() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.SetNodePoolManagementRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetNodePoolManagement(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_SetLabels() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.SetLabelsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetLabels(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_SetLegacyAbac() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.SetLegacyAbacRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetLegacyAbac(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_StartIPRotation() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.StartIPRotationRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.StartIPRotation(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_CompleteIPRotation() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.CompleteIPRotationRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CompleteIPRotation(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_SetNodePoolSize() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.SetNodePoolSizeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetNodePoolSize(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_SetNetworkPolicy() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.SetNetworkPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetNetworkPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterManagerClient_SetMaintenancePolicy() { + ctx := context.Background() + c, err := container.NewClusterManagerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containerpb.SetMaintenancePolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetMaintenancePolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/container/apiv1/doc.go b/vendor/cloud.google.com/go/container/apiv1/doc.go new file mode 100644 index 00000000..0f995054 --- /dev/null +++ b/vendor/cloud.google.com/go/container/apiv1/doc.go @@ -0,0 +1,49 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package container is an auto-generated package for the +// Google Container Engine API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// The Google Kubernetes Engine API is used for building and managing +// container +// based applications, powered by the open source Kubernetes technology. +package container // import "cloud.google.com/go/container/apiv1" + +import ( + "context" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} diff --git a/vendor/cloud.google.com/go/container/apiv1/mock_test.go b/vendor/cloud.google.com/go/container/apiv1/mock_test.go new file mode 100644 index 00000000..f90aa7a4 --- /dev/null +++ b/vendor/cloud.google.com/go/container/apiv1/mock_test.go @@ -0,0 +1,2912 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package container + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + containerpb "google.golang.org/genproto/googleapis/container/v1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockClusterManagerServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + containerpb.ClusterManagerServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockClusterManagerServer) ListClusters(ctx context.Context, req *containerpb.ListClustersRequest) (*containerpb.ListClustersResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.ListClustersResponse), nil +} + +func (s *mockClusterManagerServer) GetCluster(ctx context.Context, req *containerpb.GetClusterRequest) (*containerpb.Cluster, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Cluster), nil +} + +func (s *mockClusterManagerServer) CreateCluster(ctx context.Context, req *containerpb.CreateClusterRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) UpdateCluster(ctx context.Context, req *containerpb.UpdateClusterRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) UpdateNodePool(ctx context.Context, req *containerpb.UpdateNodePoolRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) SetNodePoolAutoscaling(ctx context.Context, req *containerpb.SetNodePoolAutoscalingRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) SetLoggingService(ctx context.Context, req *containerpb.SetLoggingServiceRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) SetMonitoringService(ctx context.Context, req *containerpb.SetMonitoringServiceRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) SetAddonsConfig(ctx context.Context, req *containerpb.SetAddonsConfigRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) SetLocations(ctx context.Context, req *containerpb.SetLocationsRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) UpdateMaster(ctx context.Context, req *containerpb.UpdateMasterRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) SetMasterAuth(ctx context.Context, req *containerpb.SetMasterAuthRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) DeleteCluster(ctx context.Context, req *containerpb.DeleteClusterRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) ListOperations(ctx context.Context, req *containerpb.ListOperationsRequest) (*containerpb.ListOperationsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.ListOperationsResponse), nil +} + +func (s *mockClusterManagerServer) GetOperation(ctx context.Context, req *containerpb.GetOperationRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) CancelOperation(ctx context.Context, req *containerpb.CancelOperationRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockClusterManagerServer) GetServerConfig(ctx context.Context, req *containerpb.GetServerConfigRequest) (*containerpb.ServerConfig, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.ServerConfig), nil +} + +func (s *mockClusterManagerServer) ListNodePools(ctx context.Context, req *containerpb.ListNodePoolsRequest) (*containerpb.ListNodePoolsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.ListNodePoolsResponse), nil +} + +func (s *mockClusterManagerServer) GetNodePool(ctx context.Context, req *containerpb.GetNodePoolRequest) (*containerpb.NodePool, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.NodePool), nil +} + +func (s *mockClusterManagerServer) CreateNodePool(ctx context.Context, req *containerpb.CreateNodePoolRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) DeleteNodePool(ctx context.Context, req *containerpb.DeleteNodePoolRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) RollbackNodePoolUpgrade(ctx context.Context, req *containerpb.RollbackNodePoolUpgradeRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) SetNodePoolManagement(ctx context.Context, req *containerpb.SetNodePoolManagementRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) SetLabels(ctx context.Context, req *containerpb.SetLabelsRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) SetLegacyAbac(ctx context.Context, req *containerpb.SetLegacyAbacRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) StartIPRotation(ctx context.Context, req *containerpb.StartIPRotationRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) CompleteIPRotation(ctx context.Context, req *containerpb.CompleteIPRotationRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) SetNodePoolSize(ctx context.Context, req *containerpb.SetNodePoolSizeRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) SetNetworkPolicy(ctx context.Context, req *containerpb.SetNetworkPolicyRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +func (s *mockClusterManagerServer) SetMaintenancePolicy(ctx context.Context, req *containerpb.SetMaintenancePolicyRequest) (*containerpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containerpb.Operation), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockClusterManager mockClusterManagerServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + containerpb.RegisterClusterManagerServer(serv, &mockClusterManager) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestClusterManagerListClusters(t *testing.T) { + var expectedResponse *containerpb.ListClustersResponse = &containerpb.ListClustersResponse{} + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var request = &containerpb.ListClustersRequest{ + ProjectId: projectId, + Zone: zone, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListClusters(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerListClustersError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var request = &containerpb.ListClustersRequest{ + ProjectId: projectId, + Zone: zone, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListClusters(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerGetCluster(t *testing.T) { + var name string = "name3373707" + var description string = "description-1724546052" + var initialNodeCount int32 = 1682564205 + var loggingService string = "loggingService-1700501035" + var monitoringService string = "monitoringService1469270462" + var network string = "network1843485230" + var clusterIpv4Cidr string = "clusterIpv4Cidr-141875831" + var subnetwork string = "subnetwork-1302785042" + var enableKubernetesAlpha bool = false + var labelFingerprint string = "labelFingerprint714995737" + var selfLink string = "selfLink-1691268851" + var zone2 string = "zone2-696322977" + var endpoint string = "endpoint1741102485" + var initialClusterVersion string = "initialClusterVersion-276373352" + var currentMasterVersion string = "currentMasterVersion-920953983" + var currentNodeVersion string = "currentNodeVersion-407476063" + var createTime string = "createTime-493574096" + var statusMessage string = "statusMessage-239442758" + var nodeIpv4CidrSize int32 = 1181176815 + var servicesIpv4Cidr string = "servicesIpv4Cidr1966438125" + var currentNodeCount int32 = 178977560 + var expireTime string = "expireTime-96179731" + var expectedResponse = &containerpb.Cluster{ + Name: name, + Description: description, + InitialNodeCount: initialNodeCount, + LoggingService: loggingService, + MonitoringService: monitoringService, + Network: network, + ClusterIpv4Cidr: clusterIpv4Cidr, + Subnetwork: subnetwork, + EnableKubernetesAlpha: enableKubernetesAlpha, + LabelFingerprint: labelFingerprint, + SelfLink: selfLink, + Zone: zone2, + Endpoint: endpoint, + InitialClusterVersion: initialClusterVersion, + CurrentMasterVersion: currentMasterVersion, + CurrentNodeVersion: currentNodeVersion, + CreateTime: createTime, + StatusMessage: statusMessage, + NodeIpv4CidrSize: nodeIpv4CidrSize, + ServicesIpv4Cidr: servicesIpv4Cidr, + CurrentNodeCount: currentNodeCount, + ExpireTime: expireTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var request = &containerpb.GetClusterRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetCluster(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerGetClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var request = &containerpb.GetClusterRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetCluster(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerCreateCluster(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var cluster *containerpb.Cluster = &containerpb.Cluster{} + var request = &containerpb.CreateClusterRequest{ + ProjectId: projectId, + Zone: zone, + Cluster: cluster, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateCluster(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerCreateClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var cluster *containerpb.Cluster = &containerpb.Cluster{} + var request = &containerpb.CreateClusterRequest{ + ProjectId: projectId, + Zone: zone, + Cluster: cluster, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateCluster(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerUpdateCluster(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var update *containerpb.ClusterUpdate = &containerpb.ClusterUpdate{} + var request = &containerpb.UpdateClusterRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + Update: update, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateCluster(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerUpdateClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var update *containerpb.ClusterUpdate = &containerpb.ClusterUpdate{} + var request = &containerpb.UpdateClusterRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + Update: update, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateCluster(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerUpdateNodePool(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var nodeVersion string = "nodeVersion1790136219" + var imageType string = "imageType-1442758754" + var request = &containerpb.UpdateNodePoolRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + NodeVersion: nodeVersion, + ImageType: imageType, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateNodePool(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerUpdateNodePoolError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var nodeVersion string = "nodeVersion1790136219" + var imageType string = "imageType-1442758754" + var request = &containerpb.UpdateNodePoolRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + NodeVersion: nodeVersion, + ImageType: imageType, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateNodePool(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerSetNodePoolAutoscaling(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var autoscaling *containerpb.NodePoolAutoscaling = &containerpb.NodePoolAutoscaling{} + var request = &containerpb.SetNodePoolAutoscalingRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + Autoscaling: autoscaling, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetNodePoolAutoscaling(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerSetNodePoolAutoscalingError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var autoscaling *containerpb.NodePoolAutoscaling = &containerpb.NodePoolAutoscaling{} + var request = &containerpb.SetNodePoolAutoscalingRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + Autoscaling: autoscaling, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetNodePoolAutoscaling(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerSetLoggingService(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var loggingService string = "loggingService-1700501035" + var request = &containerpb.SetLoggingServiceRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + LoggingService: loggingService, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetLoggingService(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerSetLoggingServiceError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var loggingService string = "loggingService-1700501035" + var request = &containerpb.SetLoggingServiceRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + LoggingService: loggingService, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetLoggingService(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerSetMonitoringService(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var monitoringService string = "monitoringService1469270462" + var request = &containerpb.SetMonitoringServiceRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + MonitoringService: monitoringService, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetMonitoringService(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerSetMonitoringServiceError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var monitoringService string = "monitoringService1469270462" + var request = &containerpb.SetMonitoringServiceRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + MonitoringService: monitoringService, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetMonitoringService(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerSetAddonsConfig(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var addonsConfig *containerpb.AddonsConfig = &containerpb.AddonsConfig{} + var request = &containerpb.SetAddonsConfigRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + AddonsConfig: addonsConfig, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetAddonsConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerSetAddonsConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var addonsConfig *containerpb.AddonsConfig = &containerpb.AddonsConfig{} + var request = &containerpb.SetAddonsConfigRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + AddonsConfig: addonsConfig, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetAddonsConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerSetLocations(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var locations []string = nil + var request = &containerpb.SetLocationsRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + Locations: locations, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetLocations(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerSetLocationsError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var locations []string = nil + var request = &containerpb.SetLocationsRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + Locations: locations, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetLocations(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerUpdateMaster(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var masterVersion string = "masterVersion-2139460613" + var request = &containerpb.UpdateMasterRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + MasterVersion: masterVersion, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateMaster(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerUpdateMasterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var masterVersion string = "masterVersion-2139460613" + var request = &containerpb.UpdateMasterRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + MasterVersion: masterVersion, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateMaster(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerSetMasterAuth(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var action containerpb.SetMasterAuthRequest_Action = containerpb.SetMasterAuthRequest_UNKNOWN + var update *containerpb.MasterAuth = &containerpb.MasterAuth{} + var request = &containerpb.SetMasterAuthRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + Action: action, + Update: update, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetMasterAuth(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerSetMasterAuthError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var action containerpb.SetMasterAuthRequest_Action = containerpb.SetMasterAuthRequest_UNKNOWN + var update *containerpb.MasterAuth = &containerpb.MasterAuth{} + var request = &containerpb.SetMasterAuthRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + Action: action, + Update: update, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetMasterAuth(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerDeleteCluster(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var request = &containerpb.DeleteClusterRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.DeleteCluster(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerDeleteClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var request = &containerpb.DeleteClusterRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.DeleteCluster(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerListOperations(t *testing.T) { + var expectedResponse *containerpb.ListOperationsResponse = &containerpb.ListOperationsResponse{} + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var request = &containerpb.ListOperationsRequest{ + ProjectId: projectId, + Zone: zone, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListOperations(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerListOperationsError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var request = &containerpb.ListOperationsRequest{ + ProjectId: projectId, + Zone: zone, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListOperations(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerGetOperation(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var operationId string = "operationId-274116877" + var request = &containerpb.GetOperationRequest{ + ProjectId: projectId, + Zone: zone, + OperationId: operationId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetOperation(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerGetOperationError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var operationId string = "operationId-274116877" + var request = &containerpb.GetOperationRequest{ + ProjectId: projectId, + Zone: zone, + OperationId: operationId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetOperation(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerCancelOperation(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var operationId string = "operationId-274116877" + var request = &containerpb.CancelOperationRequest{ + ProjectId: projectId, + Zone: zone, + OperationId: operationId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.CancelOperation(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestClusterManagerCancelOperationError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var operationId string = "operationId-274116877" + var request = &containerpb.CancelOperationRequest{ + ProjectId: projectId, + Zone: zone, + OperationId: operationId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.CancelOperation(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestClusterManagerGetServerConfig(t *testing.T) { + var defaultClusterVersion string = "defaultClusterVersion111003029" + var defaultImageType string = "defaultImageType-918225828" + var expectedResponse = &containerpb.ServerConfig{ + DefaultClusterVersion: defaultClusterVersion, + DefaultImageType: defaultImageType, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var request = &containerpb.GetServerConfigRequest{ + ProjectId: projectId, + Zone: zone, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetServerConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerGetServerConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var request = &containerpb.GetServerConfigRequest{ + ProjectId: projectId, + Zone: zone, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetServerConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerListNodePools(t *testing.T) { + var expectedResponse *containerpb.ListNodePoolsResponse = &containerpb.ListNodePoolsResponse{} + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var request = &containerpb.ListNodePoolsRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListNodePools(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerListNodePoolsError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var request = &containerpb.ListNodePoolsRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListNodePools(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerGetNodePool(t *testing.T) { + var name string = "name3373707" + var initialNodeCount int32 = 1682564205 + var selfLink string = "selfLink-1691268851" + var version string = "version351608024" + var statusMessage string = "statusMessage-239442758" + var expectedResponse = &containerpb.NodePool{ + Name: name, + InitialNodeCount: initialNodeCount, + SelfLink: selfLink, + Version: version, + StatusMessage: statusMessage, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var request = &containerpb.GetNodePoolRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetNodePool(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerGetNodePoolError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var request = &containerpb.GetNodePoolRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetNodePool(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerCreateNodePool(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePool *containerpb.NodePool = &containerpb.NodePool{} + var request = &containerpb.CreateNodePoolRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePool: nodePool, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateNodePool(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerCreateNodePoolError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePool *containerpb.NodePool = &containerpb.NodePool{} + var request = &containerpb.CreateNodePoolRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePool: nodePool, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateNodePool(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerDeleteNodePool(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var request = &containerpb.DeleteNodePoolRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.DeleteNodePool(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerDeleteNodePoolError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var request = &containerpb.DeleteNodePoolRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.DeleteNodePool(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerRollbackNodePoolUpgrade(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var request = &containerpb.RollbackNodePoolUpgradeRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RollbackNodePoolUpgrade(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerRollbackNodePoolUpgradeError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var request = &containerpb.RollbackNodePoolUpgradeRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RollbackNodePoolUpgrade(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerSetNodePoolManagement(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var management *containerpb.NodeManagement = &containerpb.NodeManagement{} + var request = &containerpb.SetNodePoolManagementRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + Management: management, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetNodePoolManagement(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerSetNodePoolManagementError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var management *containerpb.NodeManagement = &containerpb.NodeManagement{} + var request = &containerpb.SetNodePoolManagementRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + Management: management, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetNodePoolManagement(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerSetLabels(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var resourceLabels map[string]string = nil + var labelFingerprint string = "labelFingerprint714995737" + var request = &containerpb.SetLabelsRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + ResourceLabels: resourceLabels, + LabelFingerprint: labelFingerprint, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetLabels(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerSetLabelsError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var resourceLabels map[string]string = nil + var labelFingerprint string = "labelFingerprint714995737" + var request = &containerpb.SetLabelsRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + ResourceLabels: resourceLabels, + LabelFingerprint: labelFingerprint, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetLabels(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerSetLegacyAbac(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var enabled bool = false + var request = &containerpb.SetLegacyAbacRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + Enabled: enabled, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetLegacyAbac(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerSetLegacyAbacError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var enabled bool = false + var request = &containerpb.SetLegacyAbacRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + Enabled: enabled, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetLegacyAbac(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerStartIPRotation(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var request = &containerpb.StartIPRotationRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.StartIPRotation(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerStartIPRotationError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var request = &containerpb.StartIPRotationRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.StartIPRotation(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerCompleteIPRotation(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var request = &containerpb.CompleteIPRotationRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CompleteIPRotation(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerCompleteIPRotationError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var request = &containerpb.CompleteIPRotationRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CompleteIPRotation(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerSetNodePoolSize(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var nodeCount int32 = 1539922066 + var request = &containerpb.SetNodePoolSizeRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + NodeCount: nodeCount, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetNodePoolSize(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerSetNodePoolSizeError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var nodePoolId string = "nodePoolId1043384033" + var nodeCount int32 = 1539922066 + var request = &containerpb.SetNodePoolSizeRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NodePoolId: nodePoolId, + NodeCount: nodeCount, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetNodePoolSize(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerSetNetworkPolicy(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var networkPolicy *containerpb.NetworkPolicy = &containerpb.NetworkPolicy{} + var request = &containerpb.SetNetworkPolicyRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NetworkPolicy: networkPolicy, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetNetworkPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerSetNetworkPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var networkPolicy *containerpb.NetworkPolicy = &containerpb.NetworkPolicy{} + var request = &containerpb.SetNetworkPolicyRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + NetworkPolicy: networkPolicy, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetNetworkPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterManagerSetMaintenancePolicy(t *testing.T) { + var name string = "name3373707" + var zone2 string = "zone2-696322977" + var detail string = "detail-1335224239" + var statusMessage string = "statusMessage-239442758" + var selfLink string = "selfLink-1691268851" + var targetLink string = "targetLink-2084812312" + var startTime string = "startTime-1573145462" + var endTime string = "endTime1725551537" + var expectedResponse = &containerpb.Operation{ + Name: name, + Zone: zone2, + Detail: detail, + StatusMessage: statusMessage, + SelfLink: selfLink, + TargetLink: targetLink, + StartTime: startTime, + EndTime: endTime, + } + + mockClusterManager.err = nil + mockClusterManager.reqs = nil + + mockClusterManager.resps = append(mockClusterManager.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var maintenancePolicy *containerpb.MaintenancePolicy = &containerpb.MaintenancePolicy{} + var request = &containerpb.SetMaintenancePolicyRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + MaintenancePolicy: maintenancePolicy, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetMaintenancePolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterManager.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterManagerSetMaintenancePolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterManager.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var zone string = "zone3744684" + var clusterId string = "clusterId240280960" + var maintenancePolicy *containerpb.MaintenancePolicy = &containerpb.MaintenancePolicy{} + var request = &containerpb.SetMaintenancePolicyRequest{ + ProjectId: projectId, + Zone: zone, + ClusterId: clusterId, + MaintenancePolicy: maintenancePolicy, + } + + c, err := NewClusterManagerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetMaintenancePolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/container/container.go b/vendor/cloud.google.com/go/container/container.go new file mode 100644 index 00000000..aac46d82 --- /dev/null +++ b/vendor/cloud.google.com/go/container/container.go @@ -0,0 +1,276 @@ +// Copyright 2014 Google LLC +// +// 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 container contains a deprecated Google Container Engine client. +// +// Deprecated: Use cloud.google.com/go/container/apiv1 instead. +package container // import "cloud.google.com/go/container" + +import ( + "context" + "errors" + "fmt" + "time" + + raw "google.golang.org/api/container/v1" + "google.golang.org/api/option" + htransport "google.golang.org/api/transport/http" +) + +// Type is the operation type. +type Type string + +const ( + // TypeCreate describes that the operation is "create cluster". + TypeCreate = Type("createCluster") + // TypeDelete describes that the operation is "delete cluster". + TypeDelete = Type("deleteCluster") +) + +// Status is the current status of the operation or resource. +type Status string + +const ( + // StatusDone is a status indicating that the resource or operation is in done state. + StatusDone = Status("done") + // StatusPending is a status indicating that the resource or operation is in pending state. + StatusPending = Status("pending") + // StatusRunning is a status indicating that the resource or operation is in running state. + StatusRunning = Status("running") + // StatusError is a status indicating that the resource or operation is in error state. + StatusError = Status("error") + // StatusProvisioning is a status indicating that the resource or operation is in provisioning state. + StatusProvisioning = Status("provisioning") + // StatusStopping is a status indicating that the resource or operation is in stopping state. + StatusStopping = Status("stopping") +) + +const prodAddr = "https://container.googleapis.com/" +const userAgent = "gcloud-golang-container/20151008" + +// Client is a Google Container Engine client, which may be used to manage +// clusters with a project. It must be constructed via NewClient. +type Client struct { + projectID string + svc *raw.Service +} + +// NewClient creates a new Google Container Engine client. +func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) { + o := []option.ClientOption{ + option.WithEndpoint(prodAddr), + option.WithScopes(raw.CloudPlatformScope), + option.WithUserAgent(userAgent), + } + o = append(o, opts...) + httpClient, endpoint, err := htransport.NewClient(ctx, o...) + if err != nil { + return nil, fmt.Errorf("dialing: %v", err) + } + + svc, err := raw.New(httpClient) + if err != nil { + return nil, fmt.Errorf("constructing container client: %v", err) + } + svc.BasePath = endpoint + + c := &Client{ + projectID: projectID, + svc: svc, + } + + return c, nil +} + +// Resource is a Google Container Engine cluster resource. +type Resource struct { + // Name is the name of this cluster. The name must be unique + // within this project and zone, and can be up to 40 characters. + Name string + + // Description is the description of the cluster. Optional. + Description string + + // Zone is the Google Compute Engine zone in which the cluster resides. + Zone string + + // Status is the current status of the cluster. It could either be + // StatusError, StatusProvisioning, StatusRunning or StatusStopping. + Status Status + + // Num is the number of the nodes in this cluster resource. + Num int64 + + // APIVersion is the version of the Kubernetes master and kubelets running + // in this cluster. Allowed value is 0.4.2, or leave blank to + // pick up the latest stable release. + APIVersion string + + // Endpoint is the IP address of this cluster's Kubernetes master. + // The endpoint can be accessed at https://username:password@endpoint/. + // See Username and Password fields for the username and password information. + Endpoint string + + // Username is the username to use when accessing the Kubernetes master endpoint. + Username string + + // Password is the password to use when accessing the Kubernetes master endpoint. + Password string + + // ContainerIPv4CIDR is the IP addresses of the container pods in + // this cluster, in CIDR notation (e.g. 1.2.3.4/29). + ContainerIPv4CIDR string + + // ServicesIPv4CIDR is the IP addresses of the Kubernetes services in this + // cluster, in CIDR notation (e.g. 1.2.3.4/29). Service addresses are + // always in the 10.0.0.0/16 range. + ServicesIPv4CIDR string + + // MachineType is a Google Compute Engine machine type (e.g. n1-standard-1). + // If none set, the default type is used while creating a new cluster. + MachineType string + + // This field is ignored. It was removed from the underlying container API in v1. + SourceImage string + + // Created is the creation time of this cluster. + Created time.Time +} + +func resourceFromRaw(c *raw.Cluster) *Resource { + if c == nil { + return nil + } + r := &Resource{ + Name: c.Name, + Description: c.Description, + Zone: c.Zone, + Status: Status(c.Status), + Num: c.CurrentNodeCount, + APIVersion: c.InitialClusterVersion, + Endpoint: c.Endpoint, + Username: c.MasterAuth.Username, + Password: c.MasterAuth.Password, + ContainerIPv4CIDR: c.ClusterIpv4Cidr, + ServicesIPv4CIDR: c.ServicesIpv4Cidr, + MachineType: c.NodeConfig.MachineType, + } + r.Created, _ = time.Parse(time.RFC3339, c.CreateTime) + return r +} + +func resourcesFromRaw(c []*raw.Cluster) []*Resource { + r := make([]*Resource, len(c)) + for i, val := range c { + r[i] = resourceFromRaw(val) + } + return r +} + +// Op represents a Google Container Engine API operation. +type Op struct { + // Name is the name of the operation. + Name string + + // Zone is the Google Compute Engine zone. + Zone string + + // This field is ignored. It was removed from the underlying container API in v1. + TargetURL string + + // Type is the operation type. It could be either be TypeCreate or TypeDelete. + Type Type + + // Status is the current status of this operation. It could be either + // OpDone or OpPending. + Status Status +} + +func opFromRaw(o *raw.Operation) *Op { + if o == nil { + return nil + } + return &Op{ + Name: o.Name, + Zone: o.Zone, + Type: Type(o.OperationType), + Status: Status(o.Status), + } +} + +func opsFromRaw(o []*raw.Operation) []*Op { + ops := make([]*Op, len(o)) + for i, val := range o { + ops[i] = opFromRaw(val) + } + return ops +} + +// Clusters returns a list of cluster resources from the specified zone. +// If no zone is specified, it returns all clusters under the user project. +func (c *Client) Clusters(ctx context.Context, zone string) ([]*Resource, error) { + if zone == "" { + zone = "-" + } + resp, err := c.svc.Projects.Zones.Clusters.List(c.projectID, zone).Do() + if err != nil { + return nil, err + } + return resourcesFromRaw(resp.Clusters), nil +} + +// Cluster returns metadata about the specified cluster. +func (c *Client) Cluster(ctx context.Context, zone, name string) (*Resource, error) { + resp, err := c.svc.Projects.Zones.Clusters.Get(c.projectID, zone, name).Do() + if err != nil { + return nil, err + } + return resourceFromRaw(resp), nil +} + +// DeleteCluster deletes a cluster. +func (c *Client) DeleteCluster(ctx context.Context, zone, name string) error { + _, err := c.svc.Projects.Zones.Clusters.Delete(c.projectID, zone, name).Do() + return err +} + +// Operations returns a list of operations from the specified zone. +// If no zone is specified, it looks up for all of the operations +// that are running under the user's project. +func (c *Client) Operations(ctx context.Context, zone string) ([]*Op, error) { + if zone == "" { + resp, err := c.svc.Projects.Zones.Operations.List(c.projectID, "-").Do() + if err != nil { + return nil, err + } + return opsFromRaw(resp.Operations), nil + } + resp, err := c.svc.Projects.Zones.Operations.List(c.projectID, zone).Do() + if err != nil { + return nil, err + } + return opsFromRaw(resp.Operations), nil +} + +// Operation returns an operation. +func (c *Client) Operation(ctx context.Context, zone, name string) (*Op, error) { + resp, err := c.svc.Projects.Zones.Operations.Get(c.projectID, zone, name).Do() + if err != nil { + return nil, err + } + if resp.StatusMessage != "" { + return nil, errors.New(resp.StatusMessage) + } + return opFromRaw(resp), nil +} diff --git a/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client.go b/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client.go new file mode 100644 index 00000000..1a5dd24f --- /dev/null +++ b/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client.go @@ -0,0 +1,322 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package containeranalysis + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + containeranalysispb "google.golang.org/genproto/googleapis/devtools/containeranalysis/v1beta1" + iampb "google.golang.org/genproto/googleapis/iam/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// ContainerAnalysisV1Beta1CallOptions contains the retry settings for each method of ContainerAnalysisV1Beta1Client. +type ContainerAnalysisV1Beta1CallOptions struct { + SetIamPolicy []gax.CallOption + GetIamPolicy []gax.CallOption + TestIamPermissions []gax.CallOption + GetScanConfig []gax.CallOption + ListScanConfigs []gax.CallOption + UpdateScanConfig []gax.CallOption +} + +func defaultContainerAnalysisV1Beta1ClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("containeranalysis.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultContainerAnalysisV1Beta1CallOptions() *ContainerAnalysisV1Beta1CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &ContainerAnalysisV1Beta1CallOptions{ + SetIamPolicy: retry[[2]string{"default", "non_idempotent"}], + GetIamPolicy: retry[[2]string{"default", "non_idempotent"}], + TestIamPermissions: retry[[2]string{"default", "non_idempotent"}], + GetScanConfig: retry[[2]string{"default", "idempotent"}], + ListScanConfigs: retry[[2]string{"default", "idempotent"}], + UpdateScanConfig: retry[[2]string{"default", "non_idempotent"}], + } +} + +// ContainerAnalysisV1Beta1Client is a client for interacting with Container Analysis API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type ContainerAnalysisV1Beta1Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + containerAnalysisV1Beta1Client containeranalysispb.ContainerAnalysisV1Beta1Client + + // The call options for this service. + CallOptions *ContainerAnalysisV1Beta1CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewContainerAnalysisV1Beta1Client creates a new container analysis v1 beta1 client. +// +// Retrieves analysis results of Cloud components such as Docker container +// images. The Container Analysis API is an implementation of the +// Grafeas (at grafeas.io) API. +// +// Analysis results are stored as a series of occurrences. An Occurrence +// contains information about a specific analysis instance on a resource. An +// occurrence refers to a Note. A note contains details describing the +// analysis and is generally stored in a separate project, called a Provider. +// Multiple occurrences can refer to the same note. +// +// For example, an SSL vulnerability could affect multiple images. In this case, +// there would be one note for the vulnerability and an occurrence for each +// image with the vulnerability referring to that note. +func NewContainerAnalysisV1Beta1Client(ctx context.Context, opts ...option.ClientOption) (*ContainerAnalysisV1Beta1Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultContainerAnalysisV1Beta1ClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &ContainerAnalysisV1Beta1Client{ + conn: conn, + CallOptions: defaultContainerAnalysisV1Beta1CallOptions(), + + containerAnalysisV1Beta1Client: containeranalysispb.NewContainerAnalysisV1Beta1Client(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *ContainerAnalysisV1Beta1Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *ContainerAnalysisV1Beta1Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *ContainerAnalysisV1Beta1Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// SetIamPolicy sets the access control policy on the specified note or occurrence. +// Requires containeranalysis.notes.setIamPolicy or +// containeranalysis.occurrences.setIamPolicy permission if the resource is +// a note or an occurrence, respectively. +// +// The resource takes the format projects/[PROJECT_ID]/notes/[NOTE_ID] for +// notes and projects/[PROJECT_ID]/occurrences/[OCCURRENCE_ID] for +// occurrences. +func (c *ContainerAnalysisV1Beta1Client) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetIamPolicy[0:len(c.CallOptions.SetIamPolicy):len(c.CallOptions.SetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.containerAnalysisV1Beta1Client.SetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetIamPolicy gets the access control policy for a note or an occurrence resource. +// Requires containeranalysis.notes.setIamPolicy or +// containeranalysis.occurrences.setIamPolicy permission if the resource is +// a note or occurrence, respectively. +// +// The resource takes the format projects/[PROJECT_ID]/notes/[NOTE_ID] for +// notes and projects/[PROJECT_ID]/occurrences/[OCCURRENCE_ID] for +// occurrences. +func (c *ContainerAnalysisV1Beta1Client) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetIamPolicy[0:len(c.CallOptions.GetIamPolicy):len(c.CallOptions.GetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.containerAnalysisV1Beta1Client.GetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// TestIamPermissions returns the permissions that a caller has on the specified note or +// occurrence. Requires list permission on the project (for example, +// containeranalysis.notes.list). +// +// The resource takes the format projects/[PROJECT_ID]/notes/[NOTE_ID] for +// notes and projects/[PROJECT_ID]/occurrences/[OCCURRENCE_ID] for +// occurrences. +func (c *ContainerAnalysisV1Beta1Client) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.TestIamPermissions[0:len(c.CallOptions.TestIamPermissions):len(c.CallOptions.TestIamPermissions)], opts...) + var resp *iampb.TestIamPermissionsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.containerAnalysisV1Beta1Client.TestIamPermissions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetScanConfig gets the specified scan configuration. +func (c *ContainerAnalysisV1Beta1Client) GetScanConfig(ctx context.Context, req *containeranalysispb.GetScanConfigRequest, opts ...gax.CallOption) (*containeranalysispb.ScanConfig, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetScanConfig[0:len(c.CallOptions.GetScanConfig):len(c.CallOptions.GetScanConfig)], opts...) + var resp *containeranalysispb.ScanConfig + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.containerAnalysisV1Beta1Client.GetScanConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListScanConfigs lists scan configurations for the specified project. +func (c *ContainerAnalysisV1Beta1Client) ListScanConfigs(ctx context.Context, req *containeranalysispb.ListScanConfigsRequest, opts ...gax.CallOption) *ScanConfigIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListScanConfigs[0:len(c.CallOptions.ListScanConfigs):len(c.CallOptions.ListScanConfigs)], opts...) + it := &ScanConfigIterator{} + req = proto.Clone(req).(*containeranalysispb.ListScanConfigsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*containeranalysispb.ScanConfig, string, error) { + var resp *containeranalysispb.ListScanConfigsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.containerAnalysisV1Beta1Client.ListScanConfigs(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.ScanConfigs, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// UpdateScanConfig updates the specified scan configuration. +func (c *ContainerAnalysisV1Beta1Client) UpdateScanConfig(ctx context.Context, req *containeranalysispb.UpdateScanConfigRequest, opts ...gax.CallOption) (*containeranalysispb.ScanConfig, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateScanConfig[0:len(c.CallOptions.UpdateScanConfig):len(c.CallOptions.UpdateScanConfig)], opts...) + var resp *containeranalysispb.ScanConfig + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.containerAnalysisV1Beta1Client.UpdateScanConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ScanConfigIterator manages a stream of *containeranalysispb.ScanConfig. +type ScanConfigIterator struct { + items []*containeranalysispb.ScanConfig + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*containeranalysispb.ScanConfig, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ScanConfigIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ScanConfigIterator) Next() (*containeranalysispb.ScanConfig, error) { + var item *containeranalysispb.ScanConfig + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ScanConfigIterator) bufLen() int { + return len(it.items) +} + +func (it *ScanConfigIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client_example_test.go b/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client_example_test.go new file mode 100644 index 00000000..78c7bd9c --- /dev/null +++ b/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/container_analysis_v1_beta1_client_example_test.go @@ -0,0 +1,150 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package containeranalysis_test + +import ( + "context" + + containeranalysis "cloud.google.com/go/containeranalysis/apiv1beta1" + "google.golang.org/api/iterator" + containeranalysispb "google.golang.org/genproto/googleapis/devtools/containeranalysis/v1beta1" + iampb "google.golang.org/genproto/googleapis/iam/v1" +) + +func ExampleNewContainerAnalysisV1Beta1Client() { + ctx := context.Background() + c, err := containeranalysis.NewContainerAnalysisV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleContainerAnalysisV1Beta1Client_SetIamPolicy() { + ctx := context.Background() + c, err := containeranalysis.NewContainerAnalysisV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.SetIamPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetIamPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleContainerAnalysisV1Beta1Client_GetIamPolicy() { + ctx := context.Background() + c, err := containeranalysis.NewContainerAnalysisV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.GetIamPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetIamPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleContainerAnalysisV1Beta1Client_TestIamPermissions() { + ctx := context.Background() + c, err := containeranalysis.NewContainerAnalysisV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.TestIamPermissionsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.TestIamPermissions(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleContainerAnalysisV1Beta1Client_GetScanConfig() { + ctx := context.Background() + c, err := containeranalysis.NewContainerAnalysisV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containeranalysispb.GetScanConfigRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetScanConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleContainerAnalysisV1Beta1Client_ListScanConfigs() { + ctx := context.Background() + c, err := containeranalysis.NewContainerAnalysisV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containeranalysispb.ListScanConfigsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListScanConfigs(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleContainerAnalysisV1Beta1Client_UpdateScanConfig() { + ctx := context.Background() + c, err := containeranalysis.NewContainerAnalysisV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &containeranalysispb.UpdateScanConfigRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateScanConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/doc.go b/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/doc.go new file mode 100644 index 00000000..1f13e5bf --- /dev/null +++ b/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/doc.go @@ -0,0 +1,91 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package containeranalysis is an auto-generated package for the +// Container Analysis API. +// +// NOTE: This package is in beta. It is not stable, and may be subject to changes. +// +// An implementation of the Grafeas API, which stores, and enables querying +// and +// retrieval of critical metadata about all of your software artifacts. +package containeranalysis // import "cloud.google.com/go/containeranalysis/apiv1beta1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/grafeas_v1_beta1_client.go b/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/grafeas_v1_beta1_client.go new file mode 100644 index 00000000..b5d2c21a --- /dev/null +++ b/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/grafeas_v1_beta1_client.go @@ -0,0 +1,545 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package containeranalysis + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + grafeaspb "google.golang.org/genproto/googleapis/devtools/containeranalysis/v1beta1/grafeas" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// GrafeasV1Beta1CallOptions contains the retry settings for each method of GrafeasV1Beta1Client. +type GrafeasV1Beta1CallOptions struct { + GetOccurrence []gax.CallOption + ListOccurrences []gax.CallOption + DeleteOccurrence []gax.CallOption + CreateOccurrence []gax.CallOption + BatchCreateOccurrences []gax.CallOption + UpdateOccurrence []gax.CallOption + GetOccurrenceNote []gax.CallOption + GetNote []gax.CallOption + ListNotes []gax.CallOption + DeleteNote []gax.CallOption + CreateNote []gax.CallOption + BatchCreateNotes []gax.CallOption + UpdateNote []gax.CallOption + ListNoteOccurrences []gax.CallOption + GetVulnerabilityOccurrencesSummary []gax.CallOption +} + +func defaultGrafeasV1Beta1ClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("containeranalysis.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultGrafeasV1Beta1CallOptions() *GrafeasV1Beta1CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &GrafeasV1Beta1CallOptions{ + GetOccurrence: retry[[2]string{"default", "idempotent"}], + ListOccurrences: retry[[2]string{"default", "idempotent"}], + DeleteOccurrence: retry[[2]string{"default", "idempotent"}], + CreateOccurrence: retry[[2]string{"default", "non_idempotent"}], + BatchCreateOccurrences: retry[[2]string{"default", "non_idempotent"}], + UpdateOccurrence: retry[[2]string{"default", "non_idempotent"}], + GetOccurrenceNote: retry[[2]string{"default", "idempotent"}], + GetNote: retry[[2]string{"default", "idempotent"}], + ListNotes: retry[[2]string{"default", "idempotent"}], + DeleteNote: retry[[2]string{"default", "idempotent"}], + CreateNote: retry[[2]string{"default", "non_idempotent"}], + BatchCreateNotes: retry[[2]string{"default", "non_idempotent"}], + UpdateNote: retry[[2]string{"default", "non_idempotent"}], + ListNoteOccurrences: retry[[2]string{"default", "idempotent"}], + GetVulnerabilityOccurrencesSummary: retry[[2]string{"default", "idempotent"}], + } +} + +// GrafeasV1Beta1Client is a client for interacting with Container Analysis API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type GrafeasV1Beta1Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + grafeasV1Beta1Client grafeaspb.GrafeasV1Beta1Client + + // The call options for this service. + CallOptions *GrafeasV1Beta1CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewGrafeasV1Beta1Client creates a new grafeas v1 beta1 client. +// +// Grafeas (at grafeas.io) API. +// +// Retrieves analysis results of Cloud components such as Docker container +// images. +// +// Analysis results are stored as a series of occurrences. An Occurrence +// contains information about a specific analysis instance on a resource. An +// occurrence refers to a Note. A note contains details describing the +// analysis and is generally stored in a separate project, called a Provider. +// Multiple occurrences can refer to the same note. +// +// For example, an SSL vulnerability could affect multiple images. In this case, +// there would be one note for the vulnerability and an occurrence for each +// image with the vulnerability referring to that note. +func NewGrafeasV1Beta1Client(ctx context.Context, opts ...option.ClientOption) (*GrafeasV1Beta1Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultGrafeasV1Beta1ClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &GrafeasV1Beta1Client{ + conn: conn, + CallOptions: defaultGrafeasV1Beta1CallOptions(), + + grafeasV1Beta1Client: grafeaspb.NewGrafeasV1Beta1Client(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *GrafeasV1Beta1Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *GrafeasV1Beta1Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *GrafeasV1Beta1Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// GetOccurrence gets the specified occurrence. +func (c *GrafeasV1Beta1Client) GetOccurrence(ctx context.Context, req *grafeaspb.GetOccurrenceRequest, opts ...gax.CallOption) (*grafeaspb.Occurrence, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetOccurrence[0:len(c.CallOptions.GetOccurrence):len(c.CallOptions.GetOccurrence)], opts...) + var resp *grafeaspb.Occurrence + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.grafeasV1Beta1Client.GetOccurrence(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListOccurrences lists occurrences for the specified project. +func (c *GrafeasV1Beta1Client) ListOccurrences(ctx context.Context, req *grafeaspb.ListOccurrencesRequest, opts ...gax.CallOption) *OccurrenceIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListOccurrences[0:len(c.CallOptions.ListOccurrences):len(c.CallOptions.ListOccurrences)], opts...) + it := &OccurrenceIterator{} + req = proto.Clone(req).(*grafeaspb.ListOccurrencesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*grafeaspb.Occurrence, string, error) { + var resp *grafeaspb.ListOccurrencesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.grafeasV1Beta1Client.ListOccurrences(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Occurrences, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DeleteOccurrence deletes the specified occurrence. For example, use this method to delete an +// occurrence when the occurrence is no longer applicable for the given +// resource. +func (c *GrafeasV1Beta1Client) DeleteOccurrence(ctx context.Context, req *grafeaspb.DeleteOccurrenceRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteOccurrence[0:len(c.CallOptions.DeleteOccurrence):len(c.CallOptions.DeleteOccurrence)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.grafeasV1Beta1Client.DeleteOccurrence(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// CreateOccurrence creates a new occurrence. +func (c *GrafeasV1Beta1Client) CreateOccurrence(ctx context.Context, req *grafeaspb.CreateOccurrenceRequest, opts ...gax.CallOption) (*grafeaspb.Occurrence, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateOccurrence[0:len(c.CallOptions.CreateOccurrence):len(c.CallOptions.CreateOccurrence)], opts...) + var resp *grafeaspb.Occurrence + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.grafeasV1Beta1Client.CreateOccurrence(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// BatchCreateOccurrences creates new occurrences in batch. +func (c *GrafeasV1Beta1Client) BatchCreateOccurrences(ctx context.Context, req *grafeaspb.BatchCreateOccurrencesRequest, opts ...gax.CallOption) (*grafeaspb.BatchCreateOccurrencesResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchCreateOccurrences[0:len(c.CallOptions.BatchCreateOccurrences):len(c.CallOptions.BatchCreateOccurrences)], opts...) + var resp *grafeaspb.BatchCreateOccurrencesResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.grafeasV1Beta1Client.BatchCreateOccurrences(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateOccurrence updates the specified occurrence. +func (c *GrafeasV1Beta1Client) UpdateOccurrence(ctx context.Context, req *grafeaspb.UpdateOccurrenceRequest, opts ...gax.CallOption) (*grafeaspb.Occurrence, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateOccurrence[0:len(c.CallOptions.UpdateOccurrence):len(c.CallOptions.UpdateOccurrence)], opts...) + var resp *grafeaspb.Occurrence + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.grafeasV1Beta1Client.UpdateOccurrence(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetOccurrenceNote gets the note attached to the specified occurrence. Consumer projects can +// use this method to get a note that belongs to a provider project. +func (c *GrafeasV1Beta1Client) GetOccurrenceNote(ctx context.Context, req *grafeaspb.GetOccurrenceNoteRequest, opts ...gax.CallOption) (*grafeaspb.Note, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetOccurrenceNote[0:len(c.CallOptions.GetOccurrenceNote):len(c.CallOptions.GetOccurrenceNote)], opts...) + var resp *grafeaspb.Note + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.grafeasV1Beta1Client.GetOccurrenceNote(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetNote gets the specified note. +func (c *GrafeasV1Beta1Client) GetNote(ctx context.Context, req *grafeaspb.GetNoteRequest, opts ...gax.CallOption) (*grafeaspb.Note, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetNote[0:len(c.CallOptions.GetNote):len(c.CallOptions.GetNote)], opts...) + var resp *grafeaspb.Note + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.grafeasV1Beta1Client.GetNote(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListNotes lists notes for the specified project. +func (c *GrafeasV1Beta1Client) ListNotes(ctx context.Context, req *grafeaspb.ListNotesRequest, opts ...gax.CallOption) *NoteIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListNotes[0:len(c.CallOptions.ListNotes):len(c.CallOptions.ListNotes)], opts...) + it := &NoteIterator{} + req = proto.Clone(req).(*grafeaspb.ListNotesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*grafeaspb.Note, string, error) { + var resp *grafeaspb.ListNotesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.grafeasV1Beta1Client.ListNotes(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Notes, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DeleteNote deletes the specified note. +func (c *GrafeasV1Beta1Client) DeleteNote(ctx context.Context, req *grafeaspb.DeleteNoteRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteNote[0:len(c.CallOptions.DeleteNote):len(c.CallOptions.DeleteNote)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.grafeasV1Beta1Client.DeleteNote(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// CreateNote creates a new note. +func (c *GrafeasV1Beta1Client) CreateNote(ctx context.Context, req *grafeaspb.CreateNoteRequest, opts ...gax.CallOption) (*grafeaspb.Note, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateNote[0:len(c.CallOptions.CreateNote):len(c.CallOptions.CreateNote)], opts...) + var resp *grafeaspb.Note + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.grafeasV1Beta1Client.CreateNote(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// BatchCreateNotes creates new notes in batch. +func (c *GrafeasV1Beta1Client) BatchCreateNotes(ctx context.Context, req *grafeaspb.BatchCreateNotesRequest, opts ...gax.CallOption) (*grafeaspb.BatchCreateNotesResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchCreateNotes[0:len(c.CallOptions.BatchCreateNotes):len(c.CallOptions.BatchCreateNotes)], opts...) + var resp *grafeaspb.BatchCreateNotesResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.grafeasV1Beta1Client.BatchCreateNotes(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateNote updates the specified note. +func (c *GrafeasV1Beta1Client) UpdateNote(ctx context.Context, req *grafeaspb.UpdateNoteRequest, opts ...gax.CallOption) (*grafeaspb.Note, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateNote[0:len(c.CallOptions.UpdateNote):len(c.CallOptions.UpdateNote)], opts...) + var resp *grafeaspb.Note + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.grafeasV1Beta1Client.UpdateNote(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListNoteOccurrences lists occurrences referencing the specified note. Provider projects can use +// this method to get all occurrences across consumer projects referencing the +// specified note. +func (c *GrafeasV1Beta1Client) ListNoteOccurrences(ctx context.Context, req *grafeaspb.ListNoteOccurrencesRequest, opts ...gax.CallOption) *OccurrenceIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListNoteOccurrences[0:len(c.CallOptions.ListNoteOccurrences):len(c.CallOptions.ListNoteOccurrences)], opts...) + it := &OccurrenceIterator{} + req = proto.Clone(req).(*grafeaspb.ListNoteOccurrencesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*grafeaspb.Occurrence, string, error) { + var resp *grafeaspb.ListNoteOccurrencesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.grafeasV1Beta1Client.ListNoteOccurrences(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Occurrences, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetVulnerabilityOccurrencesSummary gets a summary of the number and severity of occurrences. +func (c *GrafeasV1Beta1Client) GetVulnerabilityOccurrencesSummary(ctx context.Context, req *grafeaspb.GetVulnerabilityOccurrencesSummaryRequest, opts ...gax.CallOption) (*grafeaspb.VulnerabilityOccurrencesSummary, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetVulnerabilityOccurrencesSummary[0:len(c.CallOptions.GetVulnerabilityOccurrencesSummary):len(c.CallOptions.GetVulnerabilityOccurrencesSummary)], opts...) + var resp *grafeaspb.VulnerabilityOccurrencesSummary + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.grafeasV1Beta1Client.GetVulnerabilityOccurrencesSummary(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// NoteIterator manages a stream of *grafeaspb.Note. +type NoteIterator struct { + items []*grafeaspb.Note + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*grafeaspb.Note, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NoteIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NoteIterator) Next() (*grafeaspb.Note, error) { + var item *grafeaspb.Note + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *NoteIterator) bufLen() int { + return len(it.items) +} + +func (it *NoteIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// OccurrenceIterator manages a stream of *grafeaspb.Occurrence. +type OccurrenceIterator struct { + items []*grafeaspb.Occurrence + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*grafeaspb.Occurrence, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *OccurrenceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *OccurrenceIterator) Next() (*grafeaspb.Occurrence, error) { + var item *grafeaspb.Occurrence + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *OccurrenceIterator) bufLen() int { + return len(it.items) +} + +func (it *OccurrenceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/grafeas_v1_beta1_client_example_test.go b/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/grafeas_v1_beta1_client_example_test.go new file mode 100644 index 00000000..55e8e477 --- /dev/null +++ b/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/grafeas_v1_beta1_client_example_test.go @@ -0,0 +1,319 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package containeranalysis_test + +import ( + "context" + + containeranalysis "cloud.google.com/go/containeranalysis/apiv1beta1" + "google.golang.org/api/iterator" + grafeaspb "google.golang.org/genproto/googleapis/devtools/containeranalysis/v1beta1/grafeas" +) + +func ExampleNewGrafeasV1Beta1Client() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleGrafeasV1Beta1Client_GetOccurrence() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.GetOccurrenceRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetOccurrence(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleGrafeasV1Beta1Client_ListOccurrences() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.ListOccurrencesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListOccurrences(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleGrafeasV1Beta1Client_DeleteOccurrence() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.DeleteOccurrenceRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteOccurrence(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleGrafeasV1Beta1Client_CreateOccurrence() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.CreateOccurrenceRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateOccurrence(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleGrafeasV1Beta1Client_BatchCreateOccurrences() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.BatchCreateOccurrencesRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.BatchCreateOccurrences(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleGrafeasV1Beta1Client_UpdateOccurrence() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.UpdateOccurrenceRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateOccurrence(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleGrafeasV1Beta1Client_GetOccurrenceNote() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.GetOccurrenceNoteRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetOccurrenceNote(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleGrafeasV1Beta1Client_GetNote() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.GetNoteRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetNote(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleGrafeasV1Beta1Client_ListNotes() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.ListNotesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListNotes(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleGrafeasV1Beta1Client_DeleteNote() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.DeleteNoteRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteNote(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleGrafeasV1Beta1Client_CreateNote() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.CreateNoteRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateNote(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleGrafeasV1Beta1Client_BatchCreateNotes() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.BatchCreateNotesRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.BatchCreateNotes(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleGrafeasV1Beta1Client_UpdateNote() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.UpdateNoteRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateNote(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleGrafeasV1Beta1Client_ListNoteOccurrences() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.ListNoteOccurrencesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListNoteOccurrences(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleGrafeasV1Beta1Client_GetVulnerabilityOccurrencesSummary() { + ctx := context.Background() + c, err := containeranalysis.NewGrafeasV1Beta1Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &grafeaspb.GetVulnerabilityOccurrencesSummaryRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetVulnerabilityOccurrencesSummary(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/mock_test.go b/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/mock_test.go new file mode 100644 index 00000000..bfa61fc2 --- /dev/null +++ b/vendor/cloud.google.com/go/containeranalysis/apiv1beta1/mock_test.go @@ -0,0 +1,1708 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package containeranalysis + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + containeranalysispb "google.golang.org/genproto/googleapis/devtools/containeranalysis/v1beta1" + grafeaspb "google.golang.org/genproto/googleapis/devtools/containeranalysis/v1beta1/grafeas" + iampb "google.golang.org/genproto/googleapis/iam/v1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockContainerAnalysisV1Beta1Server struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + containeranalysispb.ContainerAnalysisV1Beta1Server + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockContainerAnalysisV1Beta1Server) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockContainerAnalysisV1Beta1Server) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockContainerAnalysisV1Beta1Server) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest) (*iampb.TestIamPermissionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.TestIamPermissionsResponse), nil +} + +func (s *mockContainerAnalysisV1Beta1Server) GetScanConfig(ctx context.Context, req *containeranalysispb.GetScanConfigRequest) (*containeranalysispb.ScanConfig, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containeranalysispb.ScanConfig), nil +} + +func (s *mockContainerAnalysisV1Beta1Server) ListScanConfigs(ctx context.Context, req *containeranalysispb.ListScanConfigsRequest) (*containeranalysispb.ListScanConfigsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containeranalysispb.ListScanConfigsResponse), nil +} + +func (s *mockContainerAnalysisV1Beta1Server) UpdateScanConfig(ctx context.Context, req *containeranalysispb.UpdateScanConfigRequest) (*containeranalysispb.ScanConfig, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*containeranalysispb.ScanConfig), nil +} + +type mockGrafeasV1Beta1Server struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + grafeaspb.GrafeasV1Beta1Server + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockGrafeasV1Beta1Server) GetOccurrence(ctx context.Context, req *grafeaspb.GetOccurrenceRequest) (*grafeaspb.Occurrence, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*grafeaspb.Occurrence), nil +} + +func (s *mockGrafeasV1Beta1Server) ListOccurrences(ctx context.Context, req *grafeaspb.ListOccurrencesRequest) (*grafeaspb.ListOccurrencesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*grafeaspb.ListOccurrencesResponse), nil +} + +func (s *mockGrafeasV1Beta1Server) DeleteOccurrence(ctx context.Context, req *grafeaspb.DeleteOccurrenceRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockGrafeasV1Beta1Server) CreateOccurrence(ctx context.Context, req *grafeaspb.CreateOccurrenceRequest) (*grafeaspb.Occurrence, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*grafeaspb.Occurrence), nil +} + +func (s *mockGrafeasV1Beta1Server) BatchCreateOccurrences(ctx context.Context, req *grafeaspb.BatchCreateOccurrencesRequest) (*grafeaspb.BatchCreateOccurrencesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*grafeaspb.BatchCreateOccurrencesResponse), nil +} + +func (s *mockGrafeasV1Beta1Server) UpdateOccurrence(ctx context.Context, req *grafeaspb.UpdateOccurrenceRequest) (*grafeaspb.Occurrence, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*grafeaspb.Occurrence), nil +} + +func (s *mockGrafeasV1Beta1Server) GetOccurrenceNote(ctx context.Context, req *grafeaspb.GetOccurrenceNoteRequest) (*grafeaspb.Note, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*grafeaspb.Note), nil +} + +func (s *mockGrafeasV1Beta1Server) GetNote(ctx context.Context, req *grafeaspb.GetNoteRequest) (*grafeaspb.Note, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*grafeaspb.Note), nil +} + +func (s *mockGrafeasV1Beta1Server) ListNotes(ctx context.Context, req *grafeaspb.ListNotesRequest) (*grafeaspb.ListNotesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*grafeaspb.ListNotesResponse), nil +} + +func (s *mockGrafeasV1Beta1Server) DeleteNote(ctx context.Context, req *grafeaspb.DeleteNoteRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockGrafeasV1Beta1Server) CreateNote(ctx context.Context, req *grafeaspb.CreateNoteRequest) (*grafeaspb.Note, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*grafeaspb.Note), nil +} + +func (s *mockGrafeasV1Beta1Server) BatchCreateNotes(ctx context.Context, req *grafeaspb.BatchCreateNotesRequest) (*grafeaspb.BatchCreateNotesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*grafeaspb.BatchCreateNotesResponse), nil +} + +func (s *mockGrafeasV1Beta1Server) UpdateNote(ctx context.Context, req *grafeaspb.UpdateNoteRequest) (*grafeaspb.Note, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*grafeaspb.Note), nil +} + +func (s *mockGrafeasV1Beta1Server) ListNoteOccurrences(ctx context.Context, req *grafeaspb.ListNoteOccurrencesRequest) (*grafeaspb.ListNoteOccurrencesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*grafeaspb.ListNoteOccurrencesResponse), nil +} + +func (s *mockGrafeasV1Beta1Server) GetVulnerabilityOccurrencesSummary(ctx context.Context, req *grafeaspb.GetVulnerabilityOccurrencesSummaryRequest) (*grafeaspb.VulnerabilityOccurrencesSummary, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*grafeaspb.VulnerabilityOccurrencesSummary), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockContainerAnalysisV1Beta1 mockContainerAnalysisV1Beta1Server + mockGrafeasV1Beta1 mockGrafeasV1Beta1Server +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + containeranalysispb.RegisterContainerAnalysisV1Beta1Server(serv, &mockContainerAnalysisV1Beta1) + grafeaspb.RegisterGrafeasV1Beta1Server(serv, &mockGrafeasV1Beta1) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestContainerAnalysisV1Beta1SetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockContainerAnalysisV1Beta1.err = nil + mockContainerAnalysisV1Beta1.reqs = nil + + mockContainerAnalysisV1Beta1.resps = append(mockContainerAnalysisV1Beta1.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewContainerAnalysisV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockContainerAnalysisV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestContainerAnalysisV1Beta1SetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockContainerAnalysisV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewContainerAnalysisV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestContainerAnalysisV1Beta1GetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockContainerAnalysisV1Beta1.err = nil + mockContainerAnalysisV1Beta1.reqs = nil + + mockContainerAnalysisV1Beta1.resps = append(mockContainerAnalysisV1Beta1.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewContainerAnalysisV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockContainerAnalysisV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestContainerAnalysisV1Beta1GetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockContainerAnalysisV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewContainerAnalysisV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestContainerAnalysisV1Beta1TestIamPermissions(t *testing.T) { + var expectedResponse *iampb.TestIamPermissionsResponse = &iampb.TestIamPermissionsResponse{} + + mockContainerAnalysisV1Beta1.err = nil + mockContainerAnalysisV1Beta1.reqs = nil + + mockContainerAnalysisV1Beta1.resps = append(mockContainerAnalysisV1Beta1.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewContainerAnalysisV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockContainerAnalysisV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestContainerAnalysisV1Beta1TestIamPermissionsError(t *testing.T) { + errCode := codes.PermissionDenied + mockContainerAnalysisV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewContainerAnalysisV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestContainerAnalysisV1Beta1GetScanConfig(t *testing.T) { + var name2 string = "name2-1052831874" + var description string = "description-1724546052" + var enabled bool = false + var expectedResponse = &containeranalysispb.ScanConfig{ + Name: name2, + Description: description, + Enabled: enabled, + } + + mockContainerAnalysisV1Beta1.err = nil + mockContainerAnalysisV1Beta1.reqs = nil + + mockContainerAnalysisV1Beta1.resps = append(mockContainerAnalysisV1Beta1.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/scanConfigs/%s", "[PROJECT]", "[SCAN_CONFIG]") + var request = &containeranalysispb.GetScanConfigRequest{ + Name: formattedName, + } + + c, err := NewContainerAnalysisV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetScanConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockContainerAnalysisV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestContainerAnalysisV1Beta1GetScanConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockContainerAnalysisV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/scanConfigs/%s", "[PROJECT]", "[SCAN_CONFIG]") + var request = &containeranalysispb.GetScanConfigRequest{ + Name: formattedName, + } + + c, err := NewContainerAnalysisV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetScanConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestContainerAnalysisV1Beta1ListScanConfigs(t *testing.T) { + var nextPageToken string = "" + var scanConfigsElement *containeranalysispb.ScanConfig = &containeranalysispb.ScanConfig{} + var scanConfigs = []*containeranalysispb.ScanConfig{scanConfigsElement} + var expectedResponse = &containeranalysispb.ListScanConfigsResponse{ + NextPageToken: nextPageToken, + ScanConfigs: scanConfigs, + } + + mockContainerAnalysisV1Beta1.err = nil + mockContainerAnalysisV1Beta1.reqs = nil + + mockContainerAnalysisV1Beta1.resps = append(mockContainerAnalysisV1Beta1.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &containeranalysispb.ListScanConfigsRequest{ + Parent: formattedParent, + } + + c, err := NewContainerAnalysisV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListScanConfigs(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockContainerAnalysisV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.ScanConfigs[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestContainerAnalysisV1Beta1ListScanConfigsError(t *testing.T) { + errCode := codes.PermissionDenied + mockContainerAnalysisV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &containeranalysispb.ListScanConfigsRequest{ + Parent: formattedParent, + } + + c, err := NewContainerAnalysisV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListScanConfigs(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestContainerAnalysisV1Beta1UpdateScanConfig(t *testing.T) { + var name2 string = "name2-1052831874" + var description string = "description-1724546052" + var enabled bool = false + var expectedResponse = &containeranalysispb.ScanConfig{ + Name: name2, + Description: description, + Enabled: enabled, + } + + mockContainerAnalysisV1Beta1.err = nil + mockContainerAnalysisV1Beta1.reqs = nil + + mockContainerAnalysisV1Beta1.resps = append(mockContainerAnalysisV1Beta1.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/scanConfigs/%s", "[PROJECT]", "[SCAN_CONFIG]") + var scanConfig *containeranalysispb.ScanConfig = &containeranalysispb.ScanConfig{} + var request = &containeranalysispb.UpdateScanConfigRequest{ + Name: formattedName, + ScanConfig: scanConfig, + } + + c, err := NewContainerAnalysisV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateScanConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockContainerAnalysisV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestContainerAnalysisV1Beta1UpdateScanConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockContainerAnalysisV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/scanConfigs/%s", "[PROJECT]", "[SCAN_CONFIG]") + var scanConfig *containeranalysispb.ScanConfig = &containeranalysispb.ScanConfig{} + var request = &containeranalysispb.UpdateScanConfigRequest{ + Name: formattedName, + ScanConfig: scanConfig, + } + + c, err := NewContainerAnalysisV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateScanConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGrafeasV1Beta1GetOccurrence(t *testing.T) { + var name2 string = "name2-1052831874" + var noteName string = "noteName1780787896" + var remediation string = "remediation779381797" + var expectedResponse = &grafeaspb.Occurrence{ + Name: name2, + NoteName: noteName, + Remediation: remediation, + } + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/occurrences/%s", "[PROJECT]", "[OCCURRENCE]") + var request = &grafeaspb.GetOccurrenceRequest{ + Name: formattedName, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetOccurrence(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGrafeasV1Beta1GetOccurrenceError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/occurrences/%s", "[PROJECT]", "[OCCURRENCE]") + var request = &grafeaspb.GetOccurrenceRequest{ + Name: formattedName, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetOccurrence(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGrafeasV1Beta1ListOccurrences(t *testing.T) { + var nextPageToken string = "" + var occurrencesElement *grafeaspb.Occurrence = &grafeaspb.Occurrence{} + var occurrences = []*grafeaspb.Occurrence{occurrencesElement} + var expectedResponse = &grafeaspb.ListOccurrencesResponse{ + NextPageToken: nextPageToken, + Occurrences: occurrences, + } + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &grafeaspb.ListOccurrencesRequest{ + Parent: formattedParent, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListOccurrences(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Occurrences[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGrafeasV1Beta1ListOccurrencesError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &grafeaspb.ListOccurrencesRequest{ + Parent: formattedParent, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListOccurrences(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGrafeasV1Beta1DeleteOccurrence(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/occurrences/%s", "[PROJECT]", "[OCCURRENCE]") + var request = &grafeaspb.DeleteOccurrenceRequest{ + Name: formattedName, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteOccurrence(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestGrafeasV1Beta1DeleteOccurrenceError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/occurrences/%s", "[PROJECT]", "[OCCURRENCE]") + var request = &grafeaspb.DeleteOccurrenceRequest{ + Name: formattedName, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteOccurrence(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestGrafeasV1Beta1CreateOccurrence(t *testing.T) { + var name string = "name3373707" + var noteName string = "noteName1780787896" + var remediation string = "remediation779381797" + var expectedResponse = &grafeaspb.Occurrence{ + Name: name, + NoteName: noteName, + Remediation: remediation, + } + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var occurrence *grafeaspb.Occurrence = &grafeaspb.Occurrence{} + var request = &grafeaspb.CreateOccurrenceRequest{ + Parent: formattedParent, + Occurrence: occurrence, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateOccurrence(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGrafeasV1Beta1CreateOccurrenceError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var occurrence *grafeaspb.Occurrence = &grafeaspb.Occurrence{} + var request = &grafeaspb.CreateOccurrenceRequest{ + Parent: formattedParent, + Occurrence: occurrence, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateOccurrence(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGrafeasV1Beta1BatchCreateOccurrences(t *testing.T) { + var expectedResponse *grafeaspb.BatchCreateOccurrencesResponse = &grafeaspb.BatchCreateOccurrencesResponse{} + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var occurrences []*grafeaspb.Occurrence = nil + var request = &grafeaspb.BatchCreateOccurrencesRequest{ + Parent: formattedParent, + Occurrences: occurrences, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BatchCreateOccurrences(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGrafeasV1Beta1BatchCreateOccurrencesError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var occurrences []*grafeaspb.Occurrence = nil + var request = &grafeaspb.BatchCreateOccurrencesRequest{ + Parent: formattedParent, + Occurrences: occurrences, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BatchCreateOccurrences(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGrafeasV1Beta1UpdateOccurrence(t *testing.T) { + var name2 string = "name2-1052831874" + var noteName string = "noteName1780787896" + var remediation string = "remediation779381797" + var expectedResponse = &grafeaspb.Occurrence{ + Name: name2, + NoteName: noteName, + Remediation: remediation, + } + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/occurrences/%s", "[PROJECT]", "[OCCURRENCE]") + var occurrence *grafeaspb.Occurrence = &grafeaspb.Occurrence{} + var request = &grafeaspb.UpdateOccurrenceRequest{ + Name: formattedName, + Occurrence: occurrence, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateOccurrence(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGrafeasV1Beta1UpdateOccurrenceError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/occurrences/%s", "[PROJECT]", "[OCCURRENCE]") + var occurrence *grafeaspb.Occurrence = &grafeaspb.Occurrence{} + var request = &grafeaspb.UpdateOccurrenceRequest{ + Name: formattedName, + Occurrence: occurrence, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateOccurrence(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGrafeasV1Beta1GetOccurrenceNote(t *testing.T) { + var name2 string = "name2-1052831874" + var shortDescription string = "shortDescription-235369287" + var longDescription string = "longDescription-1747792199" + var expectedResponse = &grafeaspb.Note{ + Name: name2, + ShortDescription: shortDescription, + LongDescription: longDescription, + } + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/occurrences/%s", "[PROJECT]", "[OCCURRENCE]") + var request = &grafeaspb.GetOccurrenceNoteRequest{ + Name: formattedName, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetOccurrenceNote(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGrafeasV1Beta1GetOccurrenceNoteError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/occurrences/%s", "[PROJECT]", "[OCCURRENCE]") + var request = &grafeaspb.GetOccurrenceNoteRequest{ + Name: formattedName, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetOccurrenceNote(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGrafeasV1Beta1GetNote(t *testing.T) { + var name2 string = "name2-1052831874" + var shortDescription string = "shortDescription-235369287" + var longDescription string = "longDescription-1747792199" + var expectedResponse = &grafeaspb.Note{ + Name: name2, + ShortDescription: shortDescription, + LongDescription: longDescription, + } + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var request = &grafeaspb.GetNoteRequest{ + Name: formattedName, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetNote(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGrafeasV1Beta1GetNoteError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var request = &grafeaspb.GetNoteRequest{ + Name: formattedName, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetNote(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGrafeasV1Beta1ListNotes(t *testing.T) { + var nextPageToken string = "" + var notesElement *grafeaspb.Note = &grafeaspb.Note{} + var notes = []*grafeaspb.Note{notesElement} + var expectedResponse = &grafeaspb.ListNotesResponse{ + NextPageToken: nextPageToken, + Notes: notes, + } + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &grafeaspb.ListNotesRequest{ + Parent: formattedParent, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListNotes(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Notes[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGrafeasV1Beta1ListNotesError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &grafeaspb.ListNotesRequest{ + Parent: formattedParent, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListNotes(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGrafeasV1Beta1DeleteNote(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var request = &grafeaspb.DeleteNoteRequest{ + Name: formattedName, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteNote(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestGrafeasV1Beta1DeleteNoteError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var request = &grafeaspb.DeleteNoteRequest{ + Name: formattedName, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteNote(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestGrafeasV1Beta1CreateNote(t *testing.T) { + var name string = "name3373707" + var shortDescription string = "shortDescription-235369287" + var longDescription string = "longDescription-1747792199" + var expectedResponse = &grafeaspb.Note{ + Name: name, + ShortDescription: shortDescription, + LongDescription: longDescription, + } + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var noteId string = "noteId2129224840" + var note *grafeaspb.Note = &grafeaspb.Note{} + var request = &grafeaspb.CreateNoteRequest{ + Parent: formattedParent, + NoteId: noteId, + Note: note, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateNote(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGrafeasV1Beta1CreateNoteError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var noteId string = "noteId2129224840" + var note *grafeaspb.Note = &grafeaspb.Note{} + var request = &grafeaspb.CreateNoteRequest{ + Parent: formattedParent, + NoteId: noteId, + Note: note, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateNote(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGrafeasV1Beta1BatchCreateNotes(t *testing.T) { + var expectedResponse *grafeaspb.BatchCreateNotesResponse = &grafeaspb.BatchCreateNotesResponse{} + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var notes map[string]*grafeaspb.Note = nil + var request = &grafeaspb.BatchCreateNotesRequest{ + Parent: formattedParent, + Notes: notes, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BatchCreateNotes(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGrafeasV1Beta1BatchCreateNotesError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var notes map[string]*grafeaspb.Note = nil + var request = &grafeaspb.BatchCreateNotesRequest{ + Parent: formattedParent, + Notes: notes, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BatchCreateNotes(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGrafeasV1Beta1UpdateNote(t *testing.T) { + var name2 string = "name2-1052831874" + var shortDescription string = "shortDescription-235369287" + var longDescription string = "longDescription-1747792199" + var expectedResponse = &grafeaspb.Note{ + Name: name2, + ShortDescription: shortDescription, + LongDescription: longDescription, + } + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var note *grafeaspb.Note = &grafeaspb.Note{} + var request = &grafeaspb.UpdateNoteRequest{ + Name: formattedName, + Note: note, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateNote(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGrafeasV1Beta1UpdateNoteError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var note *grafeaspb.Note = &grafeaspb.Note{} + var request = &grafeaspb.UpdateNoteRequest{ + Name: formattedName, + Note: note, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateNote(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGrafeasV1Beta1ListNoteOccurrences(t *testing.T) { + var nextPageToken string = "" + var occurrencesElement *grafeaspb.Occurrence = &grafeaspb.Occurrence{} + var occurrences = []*grafeaspb.Occurrence{occurrencesElement} + var expectedResponse = &grafeaspb.ListNoteOccurrencesResponse{ + NextPageToken: nextPageToken, + Occurrences: occurrences, + } + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var request = &grafeaspb.ListNoteOccurrencesRequest{ + Name: formattedName, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListNoteOccurrences(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Occurrences[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGrafeasV1Beta1ListNoteOccurrencesError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/notes/%s", "[PROJECT]", "[NOTE]") + var request = &grafeaspb.ListNoteOccurrencesRequest{ + Name: formattedName, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListNoteOccurrences(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGrafeasV1Beta1GetVulnerabilityOccurrencesSummary(t *testing.T) { + var expectedResponse *grafeaspb.VulnerabilityOccurrencesSummary = &grafeaspb.VulnerabilityOccurrencesSummary{} + + mockGrafeasV1Beta1.err = nil + mockGrafeasV1Beta1.reqs = nil + + mockGrafeasV1Beta1.resps = append(mockGrafeasV1Beta1.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &grafeaspb.GetVulnerabilityOccurrencesSummaryRequest{ + Parent: formattedParent, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetVulnerabilityOccurrencesSummary(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGrafeasV1Beta1.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGrafeasV1Beta1GetVulnerabilityOccurrencesSummaryError(t *testing.T) { + errCode := codes.PermissionDenied + mockGrafeasV1Beta1.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &grafeaspb.GetVulnerabilityOccurrencesSummaryRequest{ + Parent: formattedParent, + } + + c, err := NewGrafeasV1Beta1Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetVulnerabilityOccurrencesSummary(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1/ListClusters_smoke_test.go b/vendor/cloud.google.com/go/dataproc/apiv1/ListClusters_smoke_test.go new file mode 100644 index 00000000..0a1b5c14 --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1/ListClusters_smoke_test.go @@ -0,0 +1,69 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc + +import ( + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestClusterControllerSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewClusterControllerClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var projectId2 string = projectId + var region string = "global" + var request = &dataprocpb.ListClustersRequest{ + ProjectId: projectId2, + Region: region, + } + + iter := c.ListClusters(ctx, request) + if _, err := iter.Next(); err != nil && err != iterator.Done { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1/cluster_controller_client.go b/vendor/cloud.google.com/go/dataproc/apiv1/cluster_controller_client.go new file mode 100644 index 00000000..16394c23 --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1/cluster_controller_client.go @@ -0,0 +1,609 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc + +import ( + "context" + "math" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// ClusterControllerCallOptions contains the retry settings for each method of ClusterControllerClient. +type ClusterControllerCallOptions struct { + CreateCluster []gax.CallOption + UpdateCluster []gax.CallOption + DeleteCluster []gax.CallOption + GetCluster []gax.CallOption + ListClusters []gax.CallOption + DiagnoseCluster []gax.CallOption +} + +func defaultClusterControllerClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("dataproc.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultClusterControllerCallOptions() *ClusterControllerCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Internal, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + {"default", "non_idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &ClusterControllerCallOptions{ + CreateCluster: retry[[2]string{"default", "non_idempotent"}], + UpdateCluster: retry[[2]string{"default", "non_idempotent"}], + DeleteCluster: retry[[2]string{"default", "non_idempotent"}], + GetCluster: retry[[2]string{"default", "idempotent"}], + ListClusters: retry[[2]string{"default", "idempotent"}], + DiagnoseCluster: retry[[2]string{"default", "non_idempotent"}], + } +} + +// ClusterControllerClient is a client for interacting with Google Cloud Dataproc API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type ClusterControllerClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + clusterControllerClient dataprocpb.ClusterControllerClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *ClusterControllerCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClusterControllerClient creates a new cluster controller client. +// +// The ClusterControllerService provides methods to manage clusters +// of Compute Engine instances. +func NewClusterControllerClient(ctx context.Context, opts ...option.ClientOption) (*ClusterControllerClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClusterControllerClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &ClusterControllerClient{ + conn: conn, + CallOptions: defaultClusterControllerCallOptions(), + + clusterControllerClient: dataprocpb.NewClusterControllerClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *ClusterControllerClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *ClusterControllerClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *ClusterControllerClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// CreateCluster creates a cluster in a project. +func (c *ClusterControllerClient) CreateCluster(ctx context.Context, req *dataprocpb.CreateClusterRequest, opts ...gax.CallOption) (*CreateClusterOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateCluster[0:len(c.CallOptions.CreateCluster):len(c.CallOptions.CreateCluster)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterControllerClient.CreateCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &CreateClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// UpdateCluster updates a cluster in a project. +func (c *ClusterControllerClient) UpdateCluster(ctx context.Context, req *dataprocpb.UpdateClusterRequest, opts ...gax.CallOption) (*UpdateClusterOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateCluster[0:len(c.CallOptions.UpdateCluster):len(c.CallOptions.UpdateCluster)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterControllerClient.UpdateCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &UpdateClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// DeleteCluster deletes a cluster in a project. +func (c *ClusterControllerClient) DeleteCluster(ctx context.Context, req *dataprocpb.DeleteClusterRequest, opts ...gax.CallOption) (*DeleteClusterOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteCluster[0:len(c.CallOptions.DeleteCluster):len(c.CallOptions.DeleteCluster)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterControllerClient.DeleteCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &DeleteClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// GetCluster gets the resource representation for a cluster in a project. +func (c *ClusterControllerClient) GetCluster(ctx context.Context, req *dataprocpb.GetClusterRequest, opts ...gax.CallOption) (*dataprocpb.Cluster, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetCluster[0:len(c.CallOptions.GetCluster):len(c.CallOptions.GetCluster)], opts...) + var resp *dataprocpb.Cluster + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterControllerClient.GetCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListClusters lists all regions/{region}/clusters in a project. +func (c *ClusterControllerClient) ListClusters(ctx context.Context, req *dataprocpb.ListClustersRequest, opts ...gax.CallOption) *ClusterIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListClusters[0:len(c.CallOptions.ListClusters):len(c.CallOptions.ListClusters)], opts...) + it := &ClusterIterator{} + req = proto.Clone(req).(*dataprocpb.ListClustersRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataprocpb.Cluster, string, error) { + var resp *dataprocpb.ListClustersResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterControllerClient.ListClusters(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Clusters, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DiagnoseCluster gets cluster diagnostic information. +// After the operation completes, the Operation.response field +// contains DiagnoseClusterOutputLocation. +func (c *ClusterControllerClient) DiagnoseCluster(ctx context.Context, req *dataprocpb.DiagnoseClusterRequest, opts ...gax.CallOption) (*DiagnoseClusterOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DiagnoseCluster[0:len(c.CallOptions.DiagnoseCluster):len(c.CallOptions.DiagnoseCluster)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterControllerClient.DiagnoseCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &DiagnoseClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// ClusterIterator manages a stream of *dataprocpb.Cluster. +type ClusterIterator struct { + items []*dataprocpb.Cluster + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dataprocpb.Cluster, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ClusterIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ClusterIterator) Next() (*dataprocpb.Cluster, error) { + var item *dataprocpb.Cluster + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ClusterIterator) bufLen() int { + return len(it.items) +} + +func (it *ClusterIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// CreateClusterOperation manages a long-running operation from CreateCluster. +type CreateClusterOperation struct { + lro *longrunning.Operation +} + +// CreateClusterOperation returns a new CreateClusterOperation from a given name. +// The name must be that of a previously created CreateClusterOperation, possibly from a different process. +func (c *ClusterControllerClient) CreateClusterOperation(name string) *CreateClusterOperation { + return &CreateClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateClusterOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*dataprocpb.Cluster, error) { + var resp dataprocpb.Cluster + if err := op.lro.WaitWithInterval(ctx, &resp, 10000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateClusterOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*dataprocpb.Cluster, error) { + var resp dataprocpb.Cluster + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateClusterOperation) Metadata() (*dataprocpb.ClusterOperationMetadata, error) { + var meta dataprocpb.ClusterOperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateClusterOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *CreateClusterOperation) Name() string { + return op.lro.Name() +} + +// Delete deletes a long-running operation. +// This method indicates that the client is no longer interested in the operation result. +// It does not cancel the operation. +func (op *CreateClusterOperation) Delete(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Delete(ctx, opts...) +} + +// DeleteClusterOperation manages a long-running operation from DeleteCluster. +type DeleteClusterOperation struct { + lro *longrunning.Operation +} + +// DeleteClusterOperation returns a new DeleteClusterOperation from a given name. +// The name must be that of a previously created DeleteClusterOperation, possibly from a different process. +func (c *ClusterControllerClient) DeleteClusterOperation(name string) *DeleteClusterOperation { + return &DeleteClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *DeleteClusterOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 10000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *DeleteClusterOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *DeleteClusterOperation) Metadata() (*dataprocpb.ClusterOperationMetadata, error) { + var meta dataprocpb.ClusterOperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *DeleteClusterOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *DeleteClusterOperation) Name() string { + return op.lro.Name() +} + +// Delete deletes a long-running operation. +// This method indicates that the client is no longer interested in the operation result. +// It does not cancel the operation. +func (op *DeleteClusterOperation) Delete(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Delete(ctx, opts...) +} + +// DiagnoseClusterOperation manages a long-running operation from DiagnoseCluster. +type DiagnoseClusterOperation struct { + lro *longrunning.Operation +} + +// DiagnoseClusterOperation returns a new DiagnoseClusterOperation from a given name. +// The name must be that of a previously created DiagnoseClusterOperation, possibly from a different process. +func (c *ClusterControllerClient) DiagnoseClusterOperation(name string) *DiagnoseClusterOperation { + return &DiagnoseClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *DiagnoseClusterOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 10000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *DiagnoseClusterOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *DiagnoseClusterOperation) Metadata() (*dataprocpb.DiagnoseClusterResults, error) { + var meta dataprocpb.DiagnoseClusterResults + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *DiagnoseClusterOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *DiagnoseClusterOperation) Name() string { + return op.lro.Name() +} + +// Delete deletes a long-running operation. +// This method indicates that the client is no longer interested in the operation result. +// It does not cancel the operation. +func (op *DiagnoseClusterOperation) Delete(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Delete(ctx, opts...) +} + +// UpdateClusterOperation manages a long-running operation from UpdateCluster. +type UpdateClusterOperation struct { + lro *longrunning.Operation +} + +// UpdateClusterOperation returns a new UpdateClusterOperation from a given name. +// The name must be that of a previously created UpdateClusterOperation, possibly from a different process. +func (c *ClusterControllerClient) UpdateClusterOperation(name string) *UpdateClusterOperation { + return &UpdateClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *UpdateClusterOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*dataprocpb.Cluster, error) { + var resp dataprocpb.Cluster + if err := op.lro.WaitWithInterval(ctx, &resp, 10000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *UpdateClusterOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*dataprocpb.Cluster, error) { + var resp dataprocpb.Cluster + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *UpdateClusterOperation) Metadata() (*dataprocpb.ClusterOperationMetadata, error) { + var meta dataprocpb.ClusterOperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *UpdateClusterOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *UpdateClusterOperation) Name() string { + return op.lro.Name() +} + +// Delete deletes a long-running operation. +// This method indicates that the client is no longer interested in the operation result. +// It does not cancel the operation. +func (op *UpdateClusterOperation) Delete(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Delete(ctx, opts...) +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1/cluster_controller_client_example_test.go b/vendor/cloud.google.com/go/dataproc/apiv1/cluster_controller_client_example_test.go new file mode 100644 index 00000000..103cde03 --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1/cluster_controller_client_example_test.go @@ -0,0 +1,161 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc_test + +import ( + "context" + + dataproc "cloud.google.com/go/dataproc/apiv1" + "google.golang.org/api/iterator" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1" +) + +func ExampleNewClusterControllerClient() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClusterControllerClient_CreateCluster() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.CreateClusterRequest{ + // TODO: Fill request struct fields. + } + op, err := c.CreateCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterControllerClient_UpdateCluster() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.UpdateClusterRequest{ + // TODO: Fill request struct fields. + } + op, err := c.UpdateCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterControllerClient_DeleteCluster() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.DeleteClusterRequest{ + // TODO: Fill request struct fields. + } + op, err := c.DeleteCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} + +func ExampleClusterControllerClient_GetCluster() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.GetClusterRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterControllerClient_ListClusters() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.ListClustersRequest{ + // TODO: Fill request struct fields. + } + it := c.ListClusters(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClusterControllerClient_DiagnoseCluster() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.DiagnoseClusterRequest{ + // TODO: Fill request struct fields. + } + op, err := c.DiagnoseCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1/doc.go b/vendor/cloud.google.com/go/dataproc/apiv1/doc.go new file mode 100644 index 00000000..8130fb23 --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package dataproc is an auto-generated package for the +// Google Cloud Dataproc API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Manages Hadoop-based clusters and jobs on Google Cloud Platform. +package dataproc // import "cloud.google.com/go/dataproc/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/dataproc/apiv1/job_controller_client.go b/vendor/cloud.google.com/go/dataproc/apiv1/job_controller_client.go new file mode 100644 index 00000000..f38ecb5f --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1/job_controller_client.go @@ -0,0 +1,301 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// JobControllerCallOptions contains the retry settings for each method of JobControllerClient. +type JobControllerCallOptions struct { + SubmitJob []gax.CallOption + GetJob []gax.CallOption + ListJobs []gax.CallOption + UpdateJob []gax.CallOption + CancelJob []gax.CallOption + DeleteJob []gax.CallOption +} + +func defaultJobControllerClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("dataproc.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultJobControllerCallOptions() *JobControllerCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Internal, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + {"default", "non_idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &JobControllerCallOptions{ + SubmitJob: retry[[2]string{"default", "non_idempotent"}], + GetJob: retry[[2]string{"default", "idempotent"}], + ListJobs: retry[[2]string{"default", "idempotent"}], + UpdateJob: retry[[2]string{"default", "non_idempotent"}], + CancelJob: retry[[2]string{"default", "idempotent"}], + DeleteJob: retry[[2]string{"default", "non_idempotent"}], + } +} + +// JobControllerClient is a client for interacting with Google Cloud Dataproc API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type JobControllerClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + jobControllerClient dataprocpb.JobControllerClient + + // The call options for this service. + CallOptions *JobControllerCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewJobControllerClient creates a new job controller client. +// +// The JobController provides methods to manage jobs. +func NewJobControllerClient(ctx context.Context, opts ...option.ClientOption) (*JobControllerClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultJobControllerClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &JobControllerClient{ + conn: conn, + CallOptions: defaultJobControllerCallOptions(), + + jobControllerClient: dataprocpb.NewJobControllerClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *JobControllerClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *JobControllerClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *JobControllerClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// SubmitJob submits a job to a cluster. +func (c *JobControllerClient) SubmitJob(ctx context.Context, req *dataprocpb.SubmitJobRequest, opts ...gax.CallOption) (*dataprocpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SubmitJob[0:len(c.CallOptions.SubmitJob):len(c.CallOptions.SubmitJob)], opts...) + var resp *dataprocpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.jobControllerClient.SubmitJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetJob gets the resource representation for a job in a project. +func (c *JobControllerClient) GetJob(ctx context.Context, req *dataprocpb.GetJobRequest, opts ...gax.CallOption) (*dataprocpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetJob[0:len(c.CallOptions.GetJob):len(c.CallOptions.GetJob)], opts...) + var resp *dataprocpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.jobControllerClient.GetJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListJobs lists regions/{region}/jobs in a project. +func (c *JobControllerClient) ListJobs(ctx context.Context, req *dataprocpb.ListJobsRequest, opts ...gax.CallOption) *JobIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListJobs[0:len(c.CallOptions.ListJobs):len(c.CallOptions.ListJobs)], opts...) + it := &JobIterator{} + req = proto.Clone(req).(*dataprocpb.ListJobsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataprocpb.Job, string, error) { + var resp *dataprocpb.ListJobsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.jobControllerClient.ListJobs(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Jobs, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// UpdateJob updates a job in a project. +func (c *JobControllerClient) UpdateJob(ctx context.Context, req *dataprocpb.UpdateJobRequest, opts ...gax.CallOption) (*dataprocpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateJob[0:len(c.CallOptions.UpdateJob):len(c.CallOptions.UpdateJob)], opts...) + var resp *dataprocpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.jobControllerClient.UpdateJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CancelJob starts a job cancellation request. To access the job resource +// after cancellation, call +// regions/{region}/jobs.list (at /dataproc/docs/reference/rest/v1/projects.regions.jobs/list) or +// regions/{region}/jobs.get (at /dataproc/docs/reference/rest/v1/projects.regions.jobs/get). +func (c *JobControllerClient) CancelJob(ctx context.Context, req *dataprocpb.CancelJobRequest, opts ...gax.CallOption) (*dataprocpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CancelJob[0:len(c.CallOptions.CancelJob):len(c.CallOptions.CancelJob)], opts...) + var resp *dataprocpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.jobControllerClient.CancelJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteJob deletes the job from the project. If the job is active, the delete fails, +// and the response returns FAILED_PRECONDITION. +func (c *JobControllerClient) DeleteJob(ctx context.Context, req *dataprocpb.DeleteJobRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteJob[0:len(c.CallOptions.DeleteJob):len(c.CallOptions.DeleteJob)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.jobControllerClient.DeleteJob(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// JobIterator manages a stream of *dataprocpb.Job. +type JobIterator struct { + items []*dataprocpb.Job + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dataprocpb.Job, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *JobIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *JobIterator) Next() (*dataprocpb.Job, error) { + var item *dataprocpb.Job + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *JobIterator) bufLen() int { + return len(it.items) +} + +func (it *JobIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1/job_controller_client_example_test.go b/vendor/cloud.google.com/go/dataproc/apiv1/job_controller_client_example_test.go new file mode 100644 index 00000000..eaaf5b62 --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1/job_controller_client_example_test.go @@ -0,0 +1,147 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc_test + +import ( + "context" + + dataproc "cloud.google.com/go/dataproc/apiv1" + "google.golang.org/api/iterator" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1" +) + +func ExampleNewJobControllerClient() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleJobControllerClient_SubmitJob() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.SubmitJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SubmitJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleJobControllerClient_GetJob() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.GetJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleJobControllerClient_ListJobs() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.ListJobsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListJobs(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleJobControllerClient_UpdateJob() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.UpdateJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleJobControllerClient_CancelJob() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.CancelJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CancelJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleJobControllerClient_DeleteJob() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.DeleteJobRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteJob(ctx, req) + if err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1/mock_test.go b/vendor/cloud.google.com/go/dataproc/apiv1/mock_test.go new file mode 100644 index 00000000..992af278 --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1/mock_test.go @@ -0,0 +1,1782 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + field_maskpb "google.golang.org/genproto/protobuf/field_mask" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockClusterControllerServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + dataprocpb.ClusterControllerServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockClusterControllerServer) CreateCluster(ctx context.Context, req *dataprocpb.CreateClusterRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockClusterControllerServer) UpdateCluster(ctx context.Context, req *dataprocpb.UpdateClusterRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockClusterControllerServer) DeleteCluster(ctx context.Context, req *dataprocpb.DeleteClusterRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockClusterControllerServer) GetCluster(ctx context.Context, req *dataprocpb.GetClusterRequest) (*dataprocpb.Cluster, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.Cluster), nil +} + +func (s *mockClusterControllerServer) ListClusters(ctx context.Context, req *dataprocpb.ListClustersRequest) (*dataprocpb.ListClustersResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.ListClustersResponse), nil +} + +func (s *mockClusterControllerServer) DiagnoseCluster(ctx context.Context, req *dataprocpb.DiagnoseClusterRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +type mockJobControllerServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + dataprocpb.JobControllerServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockJobControllerServer) SubmitJob(ctx context.Context, req *dataprocpb.SubmitJobRequest) (*dataprocpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.Job), nil +} + +func (s *mockJobControllerServer) GetJob(ctx context.Context, req *dataprocpb.GetJobRequest) (*dataprocpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.Job), nil +} + +func (s *mockJobControllerServer) ListJobs(ctx context.Context, req *dataprocpb.ListJobsRequest) (*dataprocpb.ListJobsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.ListJobsResponse), nil +} + +func (s *mockJobControllerServer) UpdateJob(ctx context.Context, req *dataprocpb.UpdateJobRequest) (*dataprocpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.Job), nil +} + +func (s *mockJobControllerServer) CancelJob(ctx context.Context, req *dataprocpb.CancelJobRequest) (*dataprocpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.Job), nil +} + +func (s *mockJobControllerServer) DeleteJob(ctx context.Context, req *dataprocpb.DeleteJobRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +type mockWorkflowTemplateServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + dataprocpb.WorkflowTemplateServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockWorkflowTemplateServer) CreateWorkflowTemplate(ctx context.Context, req *dataprocpb.CreateWorkflowTemplateRequest) (*dataprocpb.WorkflowTemplate, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.WorkflowTemplate), nil +} + +func (s *mockWorkflowTemplateServer) GetWorkflowTemplate(ctx context.Context, req *dataprocpb.GetWorkflowTemplateRequest) (*dataprocpb.WorkflowTemplate, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.WorkflowTemplate), nil +} + +func (s *mockWorkflowTemplateServer) InstantiateWorkflowTemplate(ctx context.Context, req *dataprocpb.InstantiateWorkflowTemplateRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockWorkflowTemplateServer) InstantiateInlineWorkflowTemplate(ctx context.Context, req *dataprocpb.InstantiateInlineWorkflowTemplateRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockWorkflowTemplateServer) UpdateWorkflowTemplate(ctx context.Context, req *dataprocpb.UpdateWorkflowTemplateRequest) (*dataprocpb.WorkflowTemplate, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.WorkflowTemplate), nil +} + +func (s *mockWorkflowTemplateServer) ListWorkflowTemplates(ctx context.Context, req *dataprocpb.ListWorkflowTemplatesRequest) (*dataprocpb.ListWorkflowTemplatesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.ListWorkflowTemplatesResponse), nil +} + +func (s *mockWorkflowTemplateServer) DeleteWorkflowTemplate(ctx context.Context, req *dataprocpb.DeleteWorkflowTemplateRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockClusterController mockClusterControllerServer + mockJobController mockJobControllerServer + mockWorkflowTemplate mockWorkflowTemplateServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + dataprocpb.RegisterClusterControllerServer(serv, &mockClusterController) + dataprocpb.RegisterJobControllerServer(serv, &mockJobController) + dataprocpb.RegisterWorkflowTemplateServiceServer(serv, &mockWorkflowTemplate) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestClusterControllerCreateCluster(t *testing.T) { + var projectId2 string = "projectId2939242356" + var clusterName string = "clusterName-1018081872" + var clusterUuid string = "clusterUuid-1017854240" + var expectedResponse = &dataprocpb.Cluster{ + ProjectId: projectId2, + ClusterName: clusterName, + ClusterUuid: clusterUuid, + } + + mockClusterController.err = nil + mockClusterController.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var cluster *dataprocpb.Cluster = &dataprocpb.Cluster{} + var request = &dataprocpb.CreateClusterRequest{ + ProjectId: projectId, + Region: region, + Cluster: cluster, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.CreateCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterControllerCreateClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterController.err = nil + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var cluster *dataprocpb.Cluster = &dataprocpb.Cluster{} + var request = &dataprocpb.CreateClusterRequest{ + ProjectId: projectId, + Region: region, + Cluster: cluster, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.CreateCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterControllerUpdateCluster(t *testing.T) { + var projectId2 string = "projectId2939242356" + var clusterName2 string = "clusterName2875867491" + var clusterUuid string = "clusterUuid-1017854240" + var expectedResponse = &dataprocpb.Cluster{ + ProjectId: projectId2, + ClusterName: clusterName2, + ClusterUuid: clusterUuid, + } + + mockClusterController.err = nil + mockClusterController.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var cluster *dataprocpb.Cluster = &dataprocpb.Cluster{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &dataprocpb.UpdateClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + Cluster: cluster, + UpdateMask: updateMask, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.UpdateCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterControllerUpdateClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterController.err = nil + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var cluster *dataprocpb.Cluster = &dataprocpb.Cluster{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &dataprocpb.UpdateClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + Cluster: cluster, + UpdateMask: updateMask, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.UpdateCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterControllerDeleteCluster(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockClusterController.err = nil + mockClusterController.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var request = &dataprocpb.DeleteClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.DeleteCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestClusterControllerDeleteClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterController.err = nil + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var request = &dataprocpb.DeleteClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.DeleteCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestClusterControllerGetCluster(t *testing.T) { + var projectId2 string = "projectId2939242356" + var clusterName2 string = "clusterName2875867491" + var clusterUuid string = "clusterUuid-1017854240" + var expectedResponse = &dataprocpb.Cluster{ + ProjectId: projectId2, + ClusterName: clusterName2, + ClusterUuid: clusterUuid, + } + + mockClusterController.err = nil + mockClusterController.reqs = nil + + mockClusterController.resps = append(mockClusterController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var request = &dataprocpb.GetClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetCluster(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterControllerGetClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var request = &dataprocpb.GetClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetCluster(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterControllerListClusters(t *testing.T) { + var nextPageToken string = "" + var clustersElement *dataprocpb.Cluster = &dataprocpb.Cluster{} + var clusters = []*dataprocpb.Cluster{clustersElement} + var expectedResponse = &dataprocpb.ListClustersResponse{ + NextPageToken: nextPageToken, + Clusters: clusters, + } + + mockClusterController.err = nil + mockClusterController.reqs = nil + + mockClusterController.resps = append(mockClusterController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var request = &dataprocpb.ListClustersRequest{ + ProjectId: projectId, + Region: region, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListClusters(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Clusters[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterControllerListClustersError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var request = &dataprocpb.ListClustersRequest{ + ProjectId: projectId, + Region: region, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListClusters(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterControllerDiagnoseCluster(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockClusterController.err = nil + mockClusterController.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var request = &dataprocpb.DiagnoseClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.DiagnoseCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestClusterControllerDiagnoseClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterController.err = nil + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var request = &dataprocpb.DiagnoseClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.DiagnoseCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestJobControllerSubmitJob(t *testing.T) { + var driverOutputResourceUri string = "driverOutputResourceUri-542229086" + var driverControlFilesUri string = "driverControlFilesUri207057643" + var jobUuid string = "jobUuid-1615012099" + var expectedResponse = &dataprocpb.Job{ + DriverOutputResourceUri: driverOutputResourceUri, + DriverControlFilesUri: driverControlFilesUri, + JobUuid: jobUuid, + } + + mockJobController.err = nil + mockJobController.reqs = nil + + mockJobController.resps = append(mockJobController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var job *dataprocpb.Job = &dataprocpb.Job{} + var request = &dataprocpb.SubmitJobRequest{ + ProjectId: projectId, + Region: region, + Job: job, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SubmitJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockJobController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestJobControllerSubmitJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockJobController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var job *dataprocpb.Job = &dataprocpb.Job{} + var request = &dataprocpb.SubmitJobRequest{ + ProjectId: projectId, + Region: region, + Job: job, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SubmitJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestJobControllerGetJob(t *testing.T) { + var driverOutputResourceUri string = "driverOutputResourceUri-542229086" + var driverControlFilesUri string = "driverControlFilesUri207057643" + var jobUuid string = "jobUuid-1615012099" + var expectedResponse = &dataprocpb.Job{ + DriverOutputResourceUri: driverOutputResourceUri, + DriverControlFilesUri: driverControlFilesUri, + JobUuid: jobUuid, + } + + mockJobController.err = nil + mockJobController.reqs = nil + + mockJobController.resps = append(mockJobController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var request = &dataprocpb.GetJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockJobController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestJobControllerGetJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockJobController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var request = &dataprocpb.GetJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestJobControllerListJobs(t *testing.T) { + var nextPageToken string = "" + var jobsElement *dataprocpb.Job = &dataprocpb.Job{} + var jobs = []*dataprocpb.Job{jobsElement} + var expectedResponse = &dataprocpb.ListJobsResponse{ + NextPageToken: nextPageToken, + Jobs: jobs, + } + + mockJobController.err = nil + mockJobController.reqs = nil + + mockJobController.resps = append(mockJobController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var request = &dataprocpb.ListJobsRequest{ + ProjectId: projectId, + Region: region, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListJobs(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockJobController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Jobs[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestJobControllerListJobsError(t *testing.T) { + errCode := codes.PermissionDenied + mockJobController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var request = &dataprocpb.ListJobsRequest{ + ProjectId: projectId, + Region: region, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListJobs(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestJobControllerUpdateJob(t *testing.T) { + var driverOutputResourceUri string = "driverOutputResourceUri-542229086" + var driverControlFilesUri string = "driverControlFilesUri207057643" + var jobUuid string = "jobUuid-1615012099" + var expectedResponse = &dataprocpb.Job{ + DriverOutputResourceUri: driverOutputResourceUri, + DriverControlFilesUri: driverControlFilesUri, + JobUuid: jobUuid, + } + + mockJobController.err = nil + mockJobController.reqs = nil + + mockJobController.resps = append(mockJobController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var job *dataprocpb.Job = &dataprocpb.Job{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &dataprocpb.UpdateJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + Job: job, + UpdateMask: updateMask, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockJobController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestJobControllerUpdateJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockJobController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var job *dataprocpb.Job = &dataprocpb.Job{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &dataprocpb.UpdateJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + Job: job, + UpdateMask: updateMask, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestJobControllerCancelJob(t *testing.T) { + var driverOutputResourceUri string = "driverOutputResourceUri-542229086" + var driverControlFilesUri string = "driverControlFilesUri207057643" + var jobUuid string = "jobUuid-1615012099" + var expectedResponse = &dataprocpb.Job{ + DriverOutputResourceUri: driverOutputResourceUri, + DriverControlFilesUri: driverControlFilesUri, + JobUuid: jobUuid, + } + + mockJobController.err = nil + mockJobController.reqs = nil + + mockJobController.resps = append(mockJobController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var request = &dataprocpb.CancelJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CancelJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockJobController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestJobControllerCancelJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockJobController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var request = &dataprocpb.CancelJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CancelJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestJobControllerDeleteJob(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockJobController.err = nil + mockJobController.reqs = nil + + mockJobController.resps = append(mockJobController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var request = &dataprocpb.DeleteJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockJobController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestJobControllerDeleteJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockJobController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var request = &dataprocpb.DeleteJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestWorkflowTemplateServiceCreateWorkflowTemplate(t *testing.T) { + var id string = "id3355" + var name string = "name3373707" + var version int32 = 351608024 + var expectedResponse = &dataprocpb.WorkflowTemplate{ + Id: id, + Name: name, + Version: version, + } + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/regions/%s", "[PROJECT]", "[REGION]") + var template *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var request = &dataprocpb.CreateWorkflowTemplateRequest{ + Parent: formattedParent, + Template: template, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateWorkflowTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestWorkflowTemplateServiceCreateWorkflowTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/regions/%s", "[PROJECT]", "[REGION]") + var template *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var request = &dataprocpb.CreateWorkflowTemplateRequest{ + Parent: formattedParent, + Template: template, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateWorkflowTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestWorkflowTemplateServiceGetWorkflowTemplate(t *testing.T) { + var id string = "id3355" + var name2 string = "name2-1052831874" + var version int32 = 351608024 + var expectedResponse = &dataprocpb.WorkflowTemplate{ + Id: id, + Name: name2, + Version: version, + } + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/regions/%s/workflowTemplates/%s", "[PROJECT]", "[REGION]", "[WORKFLOW_TEMPLATE]") + var request = &dataprocpb.GetWorkflowTemplateRequest{ + Name: formattedName, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetWorkflowTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestWorkflowTemplateServiceGetWorkflowTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/regions/%s/workflowTemplates/%s", "[PROJECT]", "[REGION]", "[WORKFLOW_TEMPLATE]") + var request = &dataprocpb.GetWorkflowTemplateRequest{ + Name: formattedName, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetWorkflowTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestWorkflowTemplateServiceInstantiateWorkflowTemplate(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedName string = fmt.Sprintf("projects/%s/regions/%s/workflowTemplates/%s", "[PROJECT]", "[REGION]", "[WORKFLOW_TEMPLATE]") + var request = &dataprocpb.InstantiateWorkflowTemplateRequest{ + Name: formattedName, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.InstantiateWorkflowTemplate(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestWorkflowTemplateServiceInstantiateWorkflowTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedName string = fmt.Sprintf("projects/%s/regions/%s/workflowTemplates/%s", "[PROJECT]", "[REGION]", "[WORKFLOW_TEMPLATE]") + var request = &dataprocpb.InstantiateWorkflowTemplateRequest{ + Name: formattedName, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.InstantiateWorkflowTemplate(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestWorkflowTemplateServiceInstantiateInlineWorkflowTemplate(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/regions/%s", "[PROJECT]", "[REGION]") + var template *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var request = &dataprocpb.InstantiateInlineWorkflowTemplateRequest{ + Parent: formattedParent, + Template: template, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.InstantiateInlineWorkflowTemplate(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestWorkflowTemplateServiceInstantiateInlineWorkflowTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/regions/%s", "[PROJECT]", "[REGION]") + var template *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var request = &dataprocpb.InstantiateInlineWorkflowTemplateRequest{ + Parent: formattedParent, + Template: template, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.InstantiateInlineWorkflowTemplate(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestWorkflowTemplateServiceUpdateWorkflowTemplate(t *testing.T) { + var id string = "id3355" + var name string = "name3373707" + var version int32 = 351608024 + var expectedResponse = &dataprocpb.WorkflowTemplate{ + Id: id, + Name: name, + Version: version, + } + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], expectedResponse) + + var template *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var request = &dataprocpb.UpdateWorkflowTemplateRequest{ + Template: template, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateWorkflowTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestWorkflowTemplateServiceUpdateWorkflowTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = gstatus.Error(errCode, "test error") + + var template *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var request = &dataprocpb.UpdateWorkflowTemplateRequest{ + Template: template, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateWorkflowTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestWorkflowTemplateServiceListWorkflowTemplates(t *testing.T) { + var nextPageToken string = "" + var templatesElement *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var templates = []*dataprocpb.WorkflowTemplate{templatesElement} + var expectedResponse = &dataprocpb.ListWorkflowTemplatesResponse{ + NextPageToken: nextPageToken, + Templates: templates, + } + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/regions/%s", "[PROJECT]", "[REGION]") + var request = &dataprocpb.ListWorkflowTemplatesRequest{ + Parent: formattedParent, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListWorkflowTemplates(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Templates[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestWorkflowTemplateServiceListWorkflowTemplatesError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/regions/%s", "[PROJECT]", "[REGION]") + var request = &dataprocpb.ListWorkflowTemplatesRequest{ + Parent: formattedParent, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListWorkflowTemplates(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestWorkflowTemplateServiceDeleteWorkflowTemplate(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/regions/%s/workflowTemplates/%s", "[PROJECT]", "[REGION]", "[WORKFLOW_TEMPLATE]") + var request = &dataprocpb.DeleteWorkflowTemplateRequest{ + Name: formattedName, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteWorkflowTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestWorkflowTemplateServiceDeleteWorkflowTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/regions/%s/workflowTemplates/%s", "[PROJECT]", "[REGION]", "[WORKFLOW_TEMPLATE]") + var request = &dataprocpb.DeleteWorkflowTemplateRequest{ + Name: formattedName, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteWorkflowTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1/workflow_template_client.go b/vendor/cloud.google.com/go/dataproc/apiv1/workflow_template_client.go new file mode 100644 index 00000000..c7817a66 --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1/workflow_template_client.go @@ -0,0 +1,525 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc + +import ( + "context" + "math" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// WorkflowTemplateCallOptions contains the retry settings for each method of WorkflowTemplateClient. +type WorkflowTemplateCallOptions struct { + CreateWorkflowTemplate []gax.CallOption + GetWorkflowTemplate []gax.CallOption + InstantiateWorkflowTemplate []gax.CallOption + InstantiateInlineWorkflowTemplate []gax.CallOption + UpdateWorkflowTemplate []gax.CallOption + ListWorkflowTemplates []gax.CallOption + DeleteWorkflowTemplate []gax.CallOption +} + +func defaultWorkflowTemplateClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("dataproc.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultWorkflowTemplateCallOptions() *WorkflowTemplateCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Internal, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + {"default", "non_idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &WorkflowTemplateCallOptions{ + CreateWorkflowTemplate: retry[[2]string{"default", "non_idempotent"}], + GetWorkflowTemplate: retry[[2]string{"default", "idempotent"}], + InstantiateWorkflowTemplate: retry[[2]string{"default", "non_idempotent"}], + InstantiateInlineWorkflowTemplate: retry[[2]string{"default", "non_idempotent"}], + UpdateWorkflowTemplate: retry[[2]string{"default", "non_idempotent"}], + ListWorkflowTemplates: retry[[2]string{"default", "idempotent"}], + DeleteWorkflowTemplate: retry[[2]string{"default", "non_idempotent"}], + } +} + +// WorkflowTemplateClient is a client for interacting with Google Cloud Dataproc API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type WorkflowTemplateClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + workflowTemplateClient dataprocpb.WorkflowTemplateServiceClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *WorkflowTemplateCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewWorkflowTemplateClient creates a new workflow template service client. +// +// The API interface for managing Workflow Templates in the +// Cloud Dataproc API. +func NewWorkflowTemplateClient(ctx context.Context, opts ...option.ClientOption) (*WorkflowTemplateClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultWorkflowTemplateClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &WorkflowTemplateClient{ + conn: conn, + CallOptions: defaultWorkflowTemplateCallOptions(), + + workflowTemplateClient: dataprocpb.NewWorkflowTemplateServiceClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *WorkflowTemplateClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *WorkflowTemplateClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *WorkflowTemplateClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// CreateWorkflowTemplate creates new workflow template. +func (c *WorkflowTemplateClient) CreateWorkflowTemplate(ctx context.Context, req *dataprocpb.CreateWorkflowTemplateRequest, opts ...gax.CallOption) (*dataprocpb.WorkflowTemplate, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateWorkflowTemplate[0:len(c.CallOptions.CreateWorkflowTemplate):len(c.CallOptions.CreateWorkflowTemplate)], opts...) + var resp *dataprocpb.WorkflowTemplate + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.workflowTemplateClient.CreateWorkflowTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetWorkflowTemplate retrieves the latest workflow template. +// +// Can retrieve previously instantiated template by specifying optional +// version parameter. +func (c *WorkflowTemplateClient) GetWorkflowTemplate(ctx context.Context, req *dataprocpb.GetWorkflowTemplateRequest, opts ...gax.CallOption) (*dataprocpb.WorkflowTemplate, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetWorkflowTemplate[0:len(c.CallOptions.GetWorkflowTemplate):len(c.CallOptions.GetWorkflowTemplate)], opts...) + var resp *dataprocpb.WorkflowTemplate + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.workflowTemplateClient.GetWorkflowTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// InstantiateWorkflowTemplate instantiates a template and begins execution. +// +// The returned Operation can be used to track execution of +// workflow by polling +// [operations.get][google.longrunning.Operations.GetOperation]. +// The Operation will complete when entire workflow is finished. +// +// The running workflow can be aborted via +// [operations.cancel][google.longrunning.Operations.CancelOperation]. +// This will cause any inflight jobs to be cancelled and workflow-owned +// clusters to be deleted. +// +// The [Operation.metadata][google.longrunning.Operation.metadata] will be +// [WorkflowMetadata][google.cloud.dataproc.v1.WorkflowMetadata]. +// +// On successful completion, +// [Operation.response][google.longrunning.Operation.response] will be +// [Empty][google.protobuf.Empty]. +func (c *WorkflowTemplateClient) InstantiateWorkflowTemplate(ctx context.Context, req *dataprocpb.InstantiateWorkflowTemplateRequest, opts ...gax.CallOption) (*InstantiateWorkflowTemplateOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.InstantiateWorkflowTemplate[0:len(c.CallOptions.InstantiateWorkflowTemplate):len(c.CallOptions.InstantiateWorkflowTemplate)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.workflowTemplateClient.InstantiateWorkflowTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &InstantiateWorkflowTemplateOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// InstantiateInlineWorkflowTemplate instantiates a template and begins execution. +// +// This method is equivalent to executing the sequence +// [CreateWorkflowTemplate][google.cloud.dataproc.v1.WorkflowTemplateService.CreateWorkflowTemplate], [InstantiateWorkflowTemplate][google.cloud.dataproc.v1.WorkflowTemplateService.InstantiateWorkflowTemplate], +// [DeleteWorkflowTemplate][google.cloud.dataproc.v1.WorkflowTemplateService.DeleteWorkflowTemplate]. +// +// The returned Operation can be used to track execution of +// workflow by polling +// [operations.get][google.longrunning.Operations.GetOperation]. +// The Operation will complete when entire workflow is finished. +// +// The running workflow can be aborted via +// [operations.cancel][google.longrunning.Operations.CancelOperation]. +// This will cause any inflight jobs to be cancelled and workflow-owned +// clusters to be deleted. +// +// The [Operation.metadata][google.longrunning.Operation.metadata] will be +// [WorkflowMetadata][google.cloud.dataproc.v1.WorkflowMetadata]. +// +// On successful completion, +// [Operation.response][google.longrunning.Operation.response] will be +// [Empty][google.protobuf.Empty]. +func (c *WorkflowTemplateClient) InstantiateInlineWorkflowTemplate(ctx context.Context, req *dataprocpb.InstantiateInlineWorkflowTemplateRequest, opts ...gax.CallOption) (*InstantiateInlineWorkflowTemplateOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.InstantiateInlineWorkflowTemplate[0:len(c.CallOptions.InstantiateInlineWorkflowTemplate):len(c.CallOptions.InstantiateInlineWorkflowTemplate)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.workflowTemplateClient.InstantiateInlineWorkflowTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &InstantiateInlineWorkflowTemplateOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// UpdateWorkflowTemplate updates (replaces) workflow template. The updated template +// must contain version that matches the current server version. +func (c *WorkflowTemplateClient) UpdateWorkflowTemplate(ctx context.Context, req *dataprocpb.UpdateWorkflowTemplateRequest, opts ...gax.CallOption) (*dataprocpb.WorkflowTemplate, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateWorkflowTemplate[0:len(c.CallOptions.UpdateWorkflowTemplate):len(c.CallOptions.UpdateWorkflowTemplate)], opts...) + var resp *dataprocpb.WorkflowTemplate + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.workflowTemplateClient.UpdateWorkflowTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListWorkflowTemplates lists workflows that match the specified filter in the request. +func (c *WorkflowTemplateClient) ListWorkflowTemplates(ctx context.Context, req *dataprocpb.ListWorkflowTemplatesRequest, opts ...gax.CallOption) *WorkflowTemplateIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListWorkflowTemplates[0:len(c.CallOptions.ListWorkflowTemplates):len(c.CallOptions.ListWorkflowTemplates)], opts...) + it := &WorkflowTemplateIterator{} + req = proto.Clone(req).(*dataprocpb.ListWorkflowTemplatesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataprocpb.WorkflowTemplate, string, error) { + var resp *dataprocpb.ListWorkflowTemplatesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.workflowTemplateClient.ListWorkflowTemplates(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Templates, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DeleteWorkflowTemplate deletes a workflow template. It does not cancel in-progress workflows. +func (c *WorkflowTemplateClient) DeleteWorkflowTemplate(ctx context.Context, req *dataprocpb.DeleteWorkflowTemplateRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteWorkflowTemplate[0:len(c.CallOptions.DeleteWorkflowTemplate):len(c.CallOptions.DeleteWorkflowTemplate)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.workflowTemplateClient.DeleteWorkflowTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// WorkflowTemplateIterator manages a stream of *dataprocpb.WorkflowTemplate. +type WorkflowTemplateIterator struct { + items []*dataprocpb.WorkflowTemplate + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dataprocpb.WorkflowTemplate, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *WorkflowTemplateIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *WorkflowTemplateIterator) Next() (*dataprocpb.WorkflowTemplate, error) { + var item *dataprocpb.WorkflowTemplate + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *WorkflowTemplateIterator) bufLen() int { + return len(it.items) +} + +func (it *WorkflowTemplateIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// InstantiateInlineWorkflowTemplateOperation manages a long-running operation from InstantiateInlineWorkflowTemplate. +type InstantiateInlineWorkflowTemplateOperation struct { + lro *longrunning.Operation +} + +// InstantiateInlineWorkflowTemplateOperation returns a new InstantiateInlineWorkflowTemplateOperation from a given name. +// The name must be that of a previously created InstantiateInlineWorkflowTemplateOperation, possibly from a different process. +func (c *WorkflowTemplateClient) InstantiateInlineWorkflowTemplateOperation(name string) *InstantiateInlineWorkflowTemplateOperation { + return &InstantiateInlineWorkflowTemplateOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *InstantiateInlineWorkflowTemplateOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 10000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *InstantiateInlineWorkflowTemplateOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *InstantiateInlineWorkflowTemplateOperation) Metadata() (*dataprocpb.WorkflowMetadata, error) { + var meta dataprocpb.WorkflowMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *InstantiateInlineWorkflowTemplateOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *InstantiateInlineWorkflowTemplateOperation) Name() string { + return op.lro.Name() +} + +// Cancel starts asynchronous cancellation on a long-running operation. +// The server makes a best effort to cancel the operation, but success is not guaranteed. +// Clients can use Poll or other methods to check whether the cancellation succeeded or whether the operation +// completed despite cancellation. On successful cancellation, the operation is not deleted; +// instead, op.Poll returns an error with code Canceled. +func (op *InstantiateInlineWorkflowTemplateOperation) Cancel(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Cancel(ctx, opts...) +} + +// Delete deletes a long-running operation. +// This method indicates that the client is no longer interested in the operation result. +// It does not cancel the operation. +func (op *InstantiateInlineWorkflowTemplateOperation) Delete(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Delete(ctx, opts...) +} + +// InstantiateWorkflowTemplateOperation manages a long-running operation from InstantiateWorkflowTemplate. +type InstantiateWorkflowTemplateOperation struct { + lro *longrunning.Operation +} + +// InstantiateWorkflowTemplateOperation returns a new InstantiateWorkflowTemplateOperation from a given name. +// The name must be that of a previously created InstantiateWorkflowTemplateOperation, possibly from a different process. +func (c *WorkflowTemplateClient) InstantiateWorkflowTemplateOperation(name string) *InstantiateWorkflowTemplateOperation { + return &InstantiateWorkflowTemplateOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *InstantiateWorkflowTemplateOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 10000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *InstantiateWorkflowTemplateOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *InstantiateWorkflowTemplateOperation) Metadata() (*dataprocpb.WorkflowMetadata, error) { + var meta dataprocpb.WorkflowMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *InstantiateWorkflowTemplateOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *InstantiateWorkflowTemplateOperation) Name() string { + return op.lro.Name() +} + +// Cancel starts asynchronous cancellation on a long-running operation. +// The server makes a best effort to cancel the operation, but success is not guaranteed. +// Clients can use Poll or other methods to check whether the cancellation succeeded or whether the operation +// completed despite cancellation. On successful cancellation, the operation is not deleted; +// instead, op.Poll returns an error with code Canceled. +func (op *InstantiateWorkflowTemplateOperation) Cancel(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Cancel(ctx, opts...) +} + +// Delete deletes a long-running operation. +// This method indicates that the client is no longer interested in the operation result. +// It does not cancel the operation. +func (op *InstantiateWorkflowTemplateOperation) Delete(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Delete(ctx, opts...) +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1/workflow_template_client_example_test.go b/vendor/cloud.google.com/go/dataproc/apiv1/workflow_template_client_example_test.go new file mode 100644 index 00000000..0756d4bb --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1/workflow_template_client_example_test.go @@ -0,0 +1,167 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc_test + +import ( + "context" + + dataproc "cloud.google.com/go/dataproc/apiv1" + "google.golang.org/api/iterator" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1" +) + +func ExampleNewWorkflowTemplateClient() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleWorkflowTemplateClient_CreateWorkflowTemplate() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.CreateWorkflowTemplateRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateWorkflowTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleWorkflowTemplateClient_GetWorkflowTemplate() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.GetWorkflowTemplateRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetWorkflowTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleWorkflowTemplateClient_InstantiateWorkflowTemplate() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.InstantiateWorkflowTemplateRequest{ + // TODO: Fill request struct fields. + } + op, err := c.InstantiateWorkflowTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} + +func ExampleWorkflowTemplateClient_InstantiateInlineWorkflowTemplate() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.InstantiateInlineWorkflowTemplateRequest{ + // TODO: Fill request struct fields. + } + op, err := c.InstantiateInlineWorkflowTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} + +func ExampleWorkflowTemplateClient_UpdateWorkflowTemplate() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.UpdateWorkflowTemplateRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateWorkflowTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleWorkflowTemplateClient_ListWorkflowTemplates() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.ListWorkflowTemplatesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListWorkflowTemplates(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleWorkflowTemplateClient_DeleteWorkflowTemplate() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.DeleteWorkflowTemplateRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteWorkflowTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1beta2/ListClusters_smoke_test.go b/vendor/cloud.google.com/go/dataproc/apiv1beta2/ListClusters_smoke_test.go new file mode 100644 index 00000000..020c8a06 --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1beta2/ListClusters_smoke_test.go @@ -0,0 +1,69 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc + +import ( + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1beta2" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestClusterControllerSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewClusterControllerClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var projectId2 string = projectId + var region string = "global" + var request = &dataprocpb.ListClustersRequest{ + ProjectId: projectId2, + Region: region, + } + + iter := c.ListClusters(ctx, request) + if _, err := iter.Next(); err != nil && err != iterator.Done { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1beta2/cluster_controller_client.go b/vendor/cloud.google.com/go/dataproc/apiv1beta2/cluster_controller_client.go new file mode 100644 index 00000000..25c3d575 --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1beta2/cluster_controller_client.go @@ -0,0 +1,609 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc + +import ( + "context" + "math" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1beta2" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// ClusterControllerCallOptions contains the retry settings for each method of ClusterControllerClient. +type ClusterControllerCallOptions struct { + CreateCluster []gax.CallOption + UpdateCluster []gax.CallOption + DeleteCluster []gax.CallOption + GetCluster []gax.CallOption + ListClusters []gax.CallOption + DiagnoseCluster []gax.CallOption +} + +func defaultClusterControllerClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("dataproc.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultClusterControllerCallOptions() *ClusterControllerCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Internal, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + {"default", "non_idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &ClusterControllerCallOptions{ + CreateCluster: retry[[2]string{"default", "non_idempotent"}], + UpdateCluster: retry[[2]string{"default", "non_idempotent"}], + DeleteCluster: retry[[2]string{"default", "non_idempotent"}], + GetCluster: retry[[2]string{"default", "idempotent"}], + ListClusters: retry[[2]string{"default", "idempotent"}], + DiagnoseCluster: retry[[2]string{"default", "non_idempotent"}], + } +} + +// ClusterControllerClient is a client for interacting with Google Cloud Dataproc API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type ClusterControllerClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + clusterControllerClient dataprocpb.ClusterControllerClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *ClusterControllerCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClusterControllerClient creates a new cluster controller client. +// +// The ClusterControllerService provides methods to manage clusters +// of Compute Engine instances. +func NewClusterControllerClient(ctx context.Context, opts ...option.ClientOption) (*ClusterControllerClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClusterControllerClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &ClusterControllerClient{ + conn: conn, + CallOptions: defaultClusterControllerCallOptions(), + + clusterControllerClient: dataprocpb.NewClusterControllerClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *ClusterControllerClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *ClusterControllerClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *ClusterControllerClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// CreateCluster creates a cluster in a project. +func (c *ClusterControllerClient) CreateCluster(ctx context.Context, req *dataprocpb.CreateClusterRequest, opts ...gax.CallOption) (*CreateClusterOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateCluster[0:len(c.CallOptions.CreateCluster):len(c.CallOptions.CreateCluster)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterControllerClient.CreateCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &CreateClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// UpdateCluster updates a cluster in a project. +func (c *ClusterControllerClient) UpdateCluster(ctx context.Context, req *dataprocpb.UpdateClusterRequest, opts ...gax.CallOption) (*UpdateClusterOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateCluster[0:len(c.CallOptions.UpdateCluster):len(c.CallOptions.UpdateCluster)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterControllerClient.UpdateCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &UpdateClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// DeleteCluster deletes a cluster in a project. +func (c *ClusterControllerClient) DeleteCluster(ctx context.Context, req *dataprocpb.DeleteClusterRequest, opts ...gax.CallOption) (*DeleteClusterOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteCluster[0:len(c.CallOptions.DeleteCluster):len(c.CallOptions.DeleteCluster)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterControllerClient.DeleteCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &DeleteClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// GetCluster gets the resource representation for a cluster in a project. +func (c *ClusterControllerClient) GetCluster(ctx context.Context, req *dataprocpb.GetClusterRequest, opts ...gax.CallOption) (*dataprocpb.Cluster, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetCluster[0:len(c.CallOptions.GetCluster):len(c.CallOptions.GetCluster)], opts...) + var resp *dataprocpb.Cluster + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterControllerClient.GetCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListClusters lists all regions/{region}/clusters in a project. +func (c *ClusterControllerClient) ListClusters(ctx context.Context, req *dataprocpb.ListClustersRequest, opts ...gax.CallOption) *ClusterIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListClusters[0:len(c.CallOptions.ListClusters):len(c.CallOptions.ListClusters)], opts...) + it := &ClusterIterator{} + req = proto.Clone(req).(*dataprocpb.ListClustersRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataprocpb.Cluster, string, error) { + var resp *dataprocpb.ListClustersResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterControllerClient.ListClusters(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Clusters, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DiagnoseCluster gets cluster diagnostic information. +// After the operation completes, the Operation.response field +// contains DiagnoseClusterOutputLocation. +func (c *ClusterControllerClient) DiagnoseCluster(ctx context.Context, req *dataprocpb.DiagnoseClusterRequest, opts ...gax.CallOption) (*DiagnoseClusterOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DiagnoseCluster[0:len(c.CallOptions.DiagnoseCluster):len(c.CallOptions.DiagnoseCluster)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.clusterControllerClient.DiagnoseCluster(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &DiagnoseClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// ClusterIterator manages a stream of *dataprocpb.Cluster. +type ClusterIterator struct { + items []*dataprocpb.Cluster + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dataprocpb.Cluster, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ClusterIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ClusterIterator) Next() (*dataprocpb.Cluster, error) { + var item *dataprocpb.Cluster + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ClusterIterator) bufLen() int { + return len(it.items) +} + +func (it *ClusterIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// CreateClusterOperation manages a long-running operation from CreateCluster. +type CreateClusterOperation struct { + lro *longrunning.Operation +} + +// CreateClusterOperation returns a new CreateClusterOperation from a given name. +// The name must be that of a previously created CreateClusterOperation, possibly from a different process. +func (c *ClusterControllerClient) CreateClusterOperation(name string) *CreateClusterOperation { + return &CreateClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateClusterOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*dataprocpb.Cluster, error) { + var resp dataprocpb.Cluster + if err := op.lro.WaitWithInterval(ctx, &resp, 10000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateClusterOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*dataprocpb.Cluster, error) { + var resp dataprocpb.Cluster + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateClusterOperation) Metadata() (*dataprocpb.ClusterOperationMetadata, error) { + var meta dataprocpb.ClusterOperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateClusterOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *CreateClusterOperation) Name() string { + return op.lro.Name() +} + +// Delete deletes a long-running operation. +// This method indicates that the client is no longer interested in the operation result. +// It does not cancel the operation. +func (op *CreateClusterOperation) Delete(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Delete(ctx, opts...) +} + +// DeleteClusterOperation manages a long-running operation from DeleteCluster. +type DeleteClusterOperation struct { + lro *longrunning.Operation +} + +// DeleteClusterOperation returns a new DeleteClusterOperation from a given name. +// The name must be that of a previously created DeleteClusterOperation, possibly from a different process. +func (c *ClusterControllerClient) DeleteClusterOperation(name string) *DeleteClusterOperation { + return &DeleteClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *DeleteClusterOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 10000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *DeleteClusterOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *DeleteClusterOperation) Metadata() (*dataprocpb.ClusterOperationMetadata, error) { + var meta dataprocpb.ClusterOperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *DeleteClusterOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *DeleteClusterOperation) Name() string { + return op.lro.Name() +} + +// Delete deletes a long-running operation. +// This method indicates that the client is no longer interested in the operation result. +// It does not cancel the operation. +func (op *DeleteClusterOperation) Delete(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Delete(ctx, opts...) +} + +// DiagnoseClusterOperation manages a long-running operation from DiagnoseCluster. +type DiagnoseClusterOperation struct { + lro *longrunning.Operation +} + +// DiagnoseClusterOperation returns a new DiagnoseClusterOperation from a given name. +// The name must be that of a previously created DiagnoseClusterOperation, possibly from a different process. +func (c *ClusterControllerClient) DiagnoseClusterOperation(name string) *DiagnoseClusterOperation { + return &DiagnoseClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *DiagnoseClusterOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 10000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *DiagnoseClusterOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *DiagnoseClusterOperation) Metadata() (*dataprocpb.DiagnoseClusterResults, error) { + var meta dataprocpb.DiagnoseClusterResults + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *DiagnoseClusterOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *DiagnoseClusterOperation) Name() string { + return op.lro.Name() +} + +// Delete deletes a long-running operation. +// This method indicates that the client is no longer interested in the operation result. +// It does not cancel the operation. +func (op *DiagnoseClusterOperation) Delete(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Delete(ctx, opts...) +} + +// UpdateClusterOperation manages a long-running operation from UpdateCluster. +type UpdateClusterOperation struct { + lro *longrunning.Operation +} + +// UpdateClusterOperation returns a new UpdateClusterOperation from a given name. +// The name must be that of a previously created UpdateClusterOperation, possibly from a different process. +func (c *ClusterControllerClient) UpdateClusterOperation(name string) *UpdateClusterOperation { + return &UpdateClusterOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *UpdateClusterOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*dataprocpb.Cluster, error) { + var resp dataprocpb.Cluster + if err := op.lro.WaitWithInterval(ctx, &resp, 10000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *UpdateClusterOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*dataprocpb.Cluster, error) { + var resp dataprocpb.Cluster + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *UpdateClusterOperation) Metadata() (*dataprocpb.ClusterOperationMetadata, error) { + var meta dataprocpb.ClusterOperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *UpdateClusterOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *UpdateClusterOperation) Name() string { + return op.lro.Name() +} + +// Delete deletes a long-running operation. +// This method indicates that the client is no longer interested in the operation result. +// It does not cancel the operation. +func (op *UpdateClusterOperation) Delete(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Delete(ctx, opts...) +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1beta2/cluster_controller_client_example_test.go b/vendor/cloud.google.com/go/dataproc/apiv1beta2/cluster_controller_client_example_test.go new file mode 100644 index 00000000..f6c18bc0 --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1beta2/cluster_controller_client_example_test.go @@ -0,0 +1,161 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc_test + +import ( + "context" + + dataproc "cloud.google.com/go/dataproc/apiv1beta2" + "google.golang.org/api/iterator" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1beta2" +) + +func ExampleNewClusterControllerClient() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClusterControllerClient_CreateCluster() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.CreateClusterRequest{ + // TODO: Fill request struct fields. + } + op, err := c.CreateCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterControllerClient_UpdateCluster() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.UpdateClusterRequest{ + // TODO: Fill request struct fields. + } + op, err := c.UpdateCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterControllerClient_DeleteCluster() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.DeleteClusterRequest{ + // TODO: Fill request struct fields. + } + op, err := c.DeleteCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} + +func ExampleClusterControllerClient_GetCluster() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.GetClusterRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClusterControllerClient_ListClusters() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.ListClustersRequest{ + // TODO: Fill request struct fields. + } + it := c.ListClusters(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClusterControllerClient_DiagnoseCluster() { + ctx := context.Background() + c, err := dataproc.NewClusterControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.DiagnoseClusterRequest{ + // TODO: Fill request struct fields. + } + op, err := c.DiagnoseCluster(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1beta2/doc.go b/vendor/cloud.google.com/go/dataproc/apiv1beta2/doc.go new file mode 100644 index 00000000..de8a575c --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1beta2/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package dataproc is an auto-generated package for the +// Google Cloud Dataproc API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Manages Hadoop-based clusters and jobs on Google Cloud Platform. +package dataproc // import "cloud.google.com/go/dataproc/apiv1beta2" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/dataproc/apiv1beta2/job_controller_client.go b/vendor/cloud.google.com/go/dataproc/apiv1beta2/job_controller_client.go new file mode 100644 index 00000000..6049a7db --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1beta2/job_controller_client.go @@ -0,0 +1,301 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1beta2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// JobControllerCallOptions contains the retry settings for each method of JobControllerClient. +type JobControllerCallOptions struct { + SubmitJob []gax.CallOption + GetJob []gax.CallOption + ListJobs []gax.CallOption + UpdateJob []gax.CallOption + CancelJob []gax.CallOption + DeleteJob []gax.CallOption +} + +func defaultJobControllerClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("dataproc.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultJobControllerCallOptions() *JobControllerCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Internal, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + {"default", "non_idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &JobControllerCallOptions{ + SubmitJob: retry[[2]string{"default", "non_idempotent"}], + GetJob: retry[[2]string{"default", "idempotent"}], + ListJobs: retry[[2]string{"default", "idempotent"}], + UpdateJob: retry[[2]string{"default", "non_idempotent"}], + CancelJob: retry[[2]string{"default", "idempotent"}], + DeleteJob: retry[[2]string{"default", "non_idempotent"}], + } +} + +// JobControllerClient is a client for interacting with Google Cloud Dataproc API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type JobControllerClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + jobControllerClient dataprocpb.JobControllerClient + + // The call options for this service. + CallOptions *JobControllerCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewJobControllerClient creates a new job controller client. +// +// The JobController provides methods to manage jobs. +func NewJobControllerClient(ctx context.Context, opts ...option.ClientOption) (*JobControllerClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultJobControllerClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &JobControllerClient{ + conn: conn, + CallOptions: defaultJobControllerCallOptions(), + + jobControllerClient: dataprocpb.NewJobControllerClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *JobControllerClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *JobControllerClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *JobControllerClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// SubmitJob submits a job to a cluster. +func (c *JobControllerClient) SubmitJob(ctx context.Context, req *dataprocpb.SubmitJobRequest, opts ...gax.CallOption) (*dataprocpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SubmitJob[0:len(c.CallOptions.SubmitJob):len(c.CallOptions.SubmitJob)], opts...) + var resp *dataprocpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.jobControllerClient.SubmitJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetJob gets the resource representation for a job in a project. +func (c *JobControllerClient) GetJob(ctx context.Context, req *dataprocpb.GetJobRequest, opts ...gax.CallOption) (*dataprocpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetJob[0:len(c.CallOptions.GetJob):len(c.CallOptions.GetJob)], opts...) + var resp *dataprocpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.jobControllerClient.GetJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListJobs lists regions/{region}/jobs in a project. +func (c *JobControllerClient) ListJobs(ctx context.Context, req *dataprocpb.ListJobsRequest, opts ...gax.CallOption) *JobIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListJobs[0:len(c.CallOptions.ListJobs):len(c.CallOptions.ListJobs)], opts...) + it := &JobIterator{} + req = proto.Clone(req).(*dataprocpb.ListJobsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataprocpb.Job, string, error) { + var resp *dataprocpb.ListJobsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.jobControllerClient.ListJobs(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Jobs, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// UpdateJob updates a job in a project. +func (c *JobControllerClient) UpdateJob(ctx context.Context, req *dataprocpb.UpdateJobRequest, opts ...gax.CallOption) (*dataprocpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateJob[0:len(c.CallOptions.UpdateJob):len(c.CallOptions.UpdateJob)], opts...) + var resp *dataprocpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.jobControllerClient.UpdateJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CancelJob starts a job cancellation request. To access the job resource +// after cancellation, call +// regions/{region}/jobs.list (at /dataproc/docs/reference/rest/v1beta2/projects.regions.jobs/list) or +// regions/{region}/jobs.get (at /dataproc/docs/reference/rest/v1beta2/projects.regions.jobs/get). +func (c *JobControllerClient) CancelJob(ctx context.Context, req *dataprocpb.CancelJobRequest, opts ...gax.CallOption) (*dataprocpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CancelJob[0:len(c.CallOptions.CancelJob):len(c.CallOptions.CancelJob)], opts...) + var resp *dataprocpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.jobControllerClient.CancelJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteJob deletes the job from the project. If the job is active, the delete fails, +// and the response returns FAILED_PRECONDITION. +func (c *JobControllerClient) DeleteJob(ctx context.Context, req *dataprocpb.DeleteJobRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteJob[0:len(c.CallOptions.DeleteJob):len(c.CallOptions.DeleteJob)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.jobControllerClient.DeleteJob(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// JobIterator manages a stream of *dataprocpb.Job. +type JobIterator struct { + items []*dataprocpb.Job + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dataprocpb.Job, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *JobIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *JobIterator) Next() (*dataprocpb.Job, error) { + var item *dataprocpb.Job + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *JobIterator) bufLen() int { + return len(it.items) +} + +func (it *JobIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1beta2/job_controller_client_example_test.go b/vendor/cloud.google.com/go/dataproc/apiv1beta2/job_controller_client_example_test.go new file mode 100644 index 00000000..588d0a79 --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1beta2/job_controller_client_example_test.go @@ -0,0 +1,147 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc_test + +import ( + "context" + + dataproc "cloud.google.com/go/dataproc/apiv1beta2" + "google.golang.org/api/iterator" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1beta2" +) + +func ExampleNewJobControllerClient() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleJobControllerClient_SubmitJob() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.SubmitJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SubmitJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleJobControllerClient_GetJob() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.GetJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleJobControllerClient_ListJobs() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.ListJobsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListJobs(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleJobControllerClient_UpdateJob() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.UpdateJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleJobControllerClient_CancelJob() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.CancelJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CancelJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleJobControllerClient_DeleteJob() { + ctx := context.Background() + c, err := dataproc.NewJobControllerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.DeleteJobRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteJob(ctx, req) + if err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1beta2/mock_test.go b/vendor/cloud.google.com/go/dataproc/apiv1beta2/mock_test.go new file mode 100644 index 00000000..733f2ddd --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1beta2/mock_test.go @@ -0,0 +1,1790 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1beta2" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + field_maskpb "google.golang.org/genproto/protobuf/field_mask" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockClusterControllerServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + dataprocpb.ClusterControllerServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockClusterControllerServer) CreateCluster(ctx context.Context, req *dataprocpb.CreateClusterRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockClusterControllerServer) UpdateCluster(ctx context.Context, req *dataprocpb.UpdateClusterRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockClusterControllerServer) DeleteCluster(ctx context.Context, req *dataprocpb.DeleteClusterRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockClusterControllerServer) GetCluster(ctx context.Context, req *dataprocpb.GetClusterRequest) (*dataprocpb.Cluster, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.Cluster), nil +} + +func (s *mockClusterControllerServer) ListClusters(ctx context.Context, req *dataprocpb.ListClustersRequest) (*dataprocpb.ListClustersResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.ListClustersResponse), nil +} + +func (s *mockClusterControllerServer) DiagnoseCluster(ctx context.Context, req *dataprocpb.DiagnoseClusterRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +type mockJobControllerServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + dataprocpb.JobControllerServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockJobControllerServer) SubmitJob(ctx context.Context, req *dataprocpb.SubmitJobRequest) (*dataprocpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.Job), nil +} + +func (s *mockJobControllerServer) GetJob(ctx context.Context, req *dataprocpb.GetJobRequest) (*dataprocpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.Job), nil +} + +func (s *mockJobControllerServer) ListJobs(ctx context.Context, req *dataprocpb.ListJobsRequest) (*dataprocpb.ListJobsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.ListJobsResponse), nil +} + +func (s *mockJobControllerServer) UpdateJob(ctx context.Context, req *dataprocpb.UpdateJobRequest) (*dataprocpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.Job), nil +} + +func (s *mockJobControllerServer) CancelJob(ctx context.Context, req *dataprocpb.CancelJobRequest) (*dataprocpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.Job), nil +} + +func (s *mockJobControllerServer) DeleteJob(ctx context.Context, req *dataprocpb.DeleteJobRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +type mockWorkflowTemplateServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + dataprocpb.WorkflowTemplateServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockWorkflowTemplateServer) CreateWorkflowTemplate(ctx context.Context, req *dataprocpb.CreateWorkflowTemplateRequest) (*dataprocpb.WorkflowTemplate, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.WorkflowTemplate), nil +} + +func (s *mockWorkflowTemplateServer) GetWorkflowTemplate(ctx context.Context, req *dataprocpb.GetWorkflowTemplateRequest) (*dataprocpb.WorkflowTemplate, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.WorkflowTemplate), nil +} + +func (s *mockWorkflowTemplateServer) InstantiateWorkflowTemplate(ctx context.Context, req *dataprocpb.InstantiateWorkflowTemplateRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockWorkflowTemplateServer) InstantiateInlineWorkflowTemplate(ctx context.Context, req *dataprocpb.InstantiateInlineWorkflowTemplateRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockWorkflowTemplateServer) UpdateWorkflowTemplate(ctx context.Context, req *dataprocpb.UpdateWorkflowTemplateRequest) (*dataprocpb.WorkflowTemplate, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.WorkflowTemplate), nil +} + +func (s *mockWorkflowTemplateServer) ListWorkflowTemplates(ctx context.Context, req *dataprocpb.ListWorkflowTemplatesRequest) (*dataprocpb.ListWorkflowTemplatesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dataprocpb.ListWorkflowTemplatesResponse), nil +} + +func (s *mockWorkflowTemplateServer) DeleteWorkflowTemplate(ctx context.Context, req *dataprocpb.DeleteWorkflowTemplateRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockClusterController mockClusterControllerServer + mockJobController mockJobControllerServer + mockWorkflowTemplate mockWorkflowTemplateServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + dataprocpb.RegisterClusterControllerServer(serv, &mockClusterController) + dataprocpb.RegisterJobControllerServer(serv, &mockJobController) + dataprocpb.RegisterWorkflowTemplateServiceServer(serv, &mockWorkflowTemplate) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestClusterControllerCreateCluster(t *testing.T) { + var projectId2 string = "projectId2939242356" + var clusterName string = "clusterName-1018081872" + var clusterUuid string = "clusterUuid-1017854240" + var expectedResponse = &dataprocpb.Cluster{ + ProjectId: projectId2, + ClusterName: clusterName, + ClusterUuid: clusterUuid, + } + + mockClusterController.err = nil + mockClusterController.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var cluster *dataprocpb.Cluster = &dataprocpb.Cluster{} + var request = &dataprocpb.CreateClusterRequest{ + ProjectId: projectId, + Region: region, + Cluster: cluster, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.CreateCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterControllerCreateClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterController.err = nil + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var cluster *dataprocpb.Cluster = &dataprocpb.Cluster{} + var request = &dataprocpb.CreateClusterRequest{ + ProjectId: projectId, + Region: region, + Cluster: cluster, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.CreateCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterControllerUpdateCluster(t *testing.T) { + var projectId2 string = "projectId2939242356" + var clusterName2 string = "clusterName2875867491" + var clusterUuid string = "clusterUuid-1017854240" + var expectedResponse = &dataprocpb.Cluster{ + ProjectId: projectId2, + ClusterName: clusterName2, + ClusterUuid: clusterUuid, + } + + mockClusterController.err = nil + mockClusterController.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var cluster *dataprocpb.Cluster = &dataprocpb.Cluster{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &dataprocpb.UpdateClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + Cluster: cluster, + UpdateMask: updateMask, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.UpdateCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterControllerUpdateClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterController.err = nil + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var cluster *dataprocpb.Cluster = &dataprocpb.Cluster{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &dataprocpb.UpdateClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + Cluster: cluster, + UpdateMask: updateMask, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.UpdateCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterControllerDeleteCluster(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockClusterController.err = nil + mockClusterController.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var request = &dataprocpb.DeleteClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.DeleteCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestClusterControllerDeleteClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterController.err = nil + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var request = &dataprocpb.DeleteClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.DeleteCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestClusterControllerGetCluster(t *testing.T) { + var projectId2 string = "projectId2939242356" + var clusterName2 string = "clusterName2875867491" + var clusterUuid string = "clusterUuid-1017854240" + var expectedResponse = &dataprocpb.Cluster{ + ProjectId: projectId2, + ClusterName: clusterName2, + ClusterUuid: clusterUuid, + } + + mockClusterController.err = nil + mockClusterController.reqs = nil + + mockClusterController.resps = append(mockClusterController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var request = &dataprocpb.GetClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetCluster(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterControllerGetClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var request = &dataprocpb.GetClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetCluster(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterControllerListClusters(t *testing.T) { + var nextPageToken string = "" + var clustersElement *dataprocpb.Cluster = &dataprocpb.Cluster{} + var clusters = []*dataprocpb.Cluster{clustersElement} + var expectedResponse = &dataprocpb.ListClustersResponse{ + NextPageToken: nextPageToken, + Clusters: clusters, + } + + mockClusterController.err = nil + mockClusterController.reqs = nil + + mockClusterController.resps = append(mockClusterController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var request = &dataprocpb.ListClustersRequest{ + ProjectId: projectId, + Region: region, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListClusters(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Clusters[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestClusterControllerListClustersError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var request = &dataprocpb.ListClustersRequest{ + ProjectId: projectId, + Region: region, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListClusters(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestClusterControllerDiagnoseCluster(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockClusterController.err = nil + mockClusterController.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var request = &dataprocpb.DiagnoseClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.DiagnoseCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockClusterController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestClusterControllerDiagnoseClusterError(t *testing.T) { + errCode := codes.PermissionDenied + mockClusterController.err = nil + mockClusterController.resps = append(mockClusterController.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var clusterName string = "clusterName-1018081872" + var request = &dataprocpb.DiagnoseClusterRequest{ + ProjectId: projectId, + Region: region, + ClusterName: clusterName, + } + + c, err := NewClusterControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.DiagnoseCluster(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestJobControllerSubmitJob(t *testing.T) { + var submittedBy string = "submittedBy-2047729125" + var driverOutputResourceUri string = "driverOutputResourceUri-542229086" + var driverControlFilesUri string = "driverControlFilesUri207057643" + var jobUuid string = "jobUuid-1615012099" + var expectedResponse = &dataprocpb.Job{ + SubmittedBy: submittedBy, + DriverOutputResourceUri: driverOutputResourceUri, + DriverControlFilesUri: driverControlFilesUri, + JobUuid: jobUuid, + } + + mockJobController.err = nil + mockJobController.reqs = nil + + mockJobController.resps = append(mockJobController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var job *dataprocpb.Job = &dataprocpb.Job{} + var request = &dataprocpb.SubmitJobRequest{ + ProjectId: projectId, + Region: region, + Job: job, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SubmitJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockJobController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestJobControllerSubmitJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockJobController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var job *dataprocpb.Job = &dataprocpb.Job{} + var request = &dataprocpb.SubmitJobRequest{ + ProjectId: projectId, + Region: region, + Job: job, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SubmitJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestJobControllerGetJob(t *testing.T) { + var submittedBy string = "submittedBy-2047729125" + var driverOutputResourceUri string = "driverOutputResourceUri-542229086" + var driverControlFilesUri string = "driverControlFilesUri207057643" + var jobUuid string = "jobUuid-1615012099" + var expectedResponse = &dataprocpb.Job{ + SubmittedBy: submittedBy, + DriverOutputResourceUri: driverOutputResourceUri, + DriverControlFilesUri: driverControlFilesUri, + JobUuid: jobUuid, + } + + mockJobController.err = nil + mockJobController.reqs = nil + + mockJobController.resps = append(mockJobController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var request = &dataprocpb.GetJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockJobController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestJobControllerGetJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockJobController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var request = &dataprocpb.GetJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestJobControllerListJobs(t *testing.T) { + var nextPageToken string = "" + var jobsElement *dataprocpb.Job = &dataprocpb.Job{} + var jobs = []*dataprocpb.Job{jobsElement} + var expectedResponse = &dataprocpb.ListJobsResponse{ + NextPageToken: nextPageToken, + Jobs: jobs, + } + + mockJobController.err = nil + mockJobController.reqs = nil + + mockJobController.resps = append(mockJobController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var request = &dataprocpb.ListJobsRequest{ + ProjectId: projectId, + Region: region, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListJobs(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockJobController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Jobs[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestJobControllerListJobsError(t *testing.T) { + errCode := codes.PermissionDenied + mockJobController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var request = &dataprocpb.ListJobsRequest{ + ProjectId: projectId, + Region: region, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListJobs(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestJobControllerUpdateJob(t *testing.T) { + var submittedBy string = "submittedBy-2047729125" + var driverOutputResourceUri string = "driverOutputResourceUri-542229086" + var driverControlFilesUri string = "driverControlFilesUri207057643" + var jobUuid string = "jobUuid-1615012099" + var expectedResponse = &dataprocpb.Job{ + SubmittedBy: submittedBy, + DriverOutputResourceUri: driverOutputResourceUri, + DriverControlFilesUri: driverControlFilesUri, + JobUuid: jobUuid, + } + + mockJobController.err = nil + mockJobController.reqs = nil + + mockJobController.resps = append(mockJobController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var job *dataprocpb.Job = &dataprocpb.Job{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &dataprocpb.UpdateJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + Job: job, + UpdateMask: updateMask, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockJobController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestJobControllerUpdateJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockJobController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var job *dataprocpb.Job = &dataprocpb.Job{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &dataprocpb.UpdateJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + Job: job, + UpdateMask: updateMask, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestJobControllerCancelJob(t *testing.T) { + var submittedBy string = "submittedBy-2047729125" + var driverOutputResourceUri string = "driverOutputResourceUri-542229086" + var driverControlFilesUri string = "driverControlFilesUri207057643" + var jobUuid string = "jobUuid-1615012099" + var expectedResponse = &dataprocpb.Job{ + SubmittedBy: submittedBy, + DriverOutputResourceUri: driverOutputResourceUri, + DriverControlFilesUri: driverControlFilesUri, + JobUuid: jobUuid, + } + + mockJobController.err = nil + mockJobController.reqs = nil + + mockJobController.resps = append(mockJobController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var request = &dataprocpb.CancelJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CancelJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockJobController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestJobControllerCancelJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockJobController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var request = &dataprocpb.CancelJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CancelJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestJobControllerDeleteJob(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockJobController.err = nil + mockJobController.reqs = nil + + mockJobController.resps = append(mockJobController.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var request = &dataprocpb.DeleteJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockJobController.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestJobControllerDeleteJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockJobController.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var region string = "region-934795532" + var jobId string = "jobId-1154752291" + var request = &dataprocpb.DeleteJobRequest{ + ProjectId: projectId, + Region: region, + JobId: jobId, + } + + c, err := NewJobControllerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestWorkflowTemplateServiceCreateWorkflowTemplate(t *testing.T) { + var id string = "id3355" + var name string = "name3373707" + var version int32 = 351608024 + var expectedResponse = &dataprocpb.WorkflowTemplate{ + Id: id, + Name: name, + Version: version, + } + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/regions/%s", "[PROJECT]", "[REGION]") + var template *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var request = &dataprocpb.CreateWorkflowTemplateRequest{ + Parent: formattedParent, + Template: template, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateWorkflowTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestWorkflowTemplateServiceCreateWorkflowTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/regions/%s", "[PROJECT]", "[REGION]") + var template *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var request = &dataprocpb.CreateWorkflowTemplateRequest{ + Parent: formattedParent, + Template: template, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateWorkflowTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestWorkflowTemplateServiceGetWorkflowTemplate(t *testing.T) { + var id string = "id3355" + var name2 string = "name2-1052831874" + var version int32 = 351608024 + var expectedResponse = &dataprocpb.WorkflowTemplate{ + Id: id, + Name: name2, + Version: version, + } + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/regions/%s/workflowTemplates/%s", "[PROJECT]", "[REGION]", "[WORKFLOW_TEMPLATE]") + var request = &dataprocpb.GetWorkflowTemplateRequest{ + Name: formattedName, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetWorkflowTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestWorkflowTemplateServiceGetWorkflowTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/regions/%s/workflowTemplates/%s", "[PROJECT]", "[REGION]", "[WORKFLOW_TEMPLATE]") + var request = &dataprocpb.GetWorkflowTemplateRequest{ + Name: formattedName, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetWorkflowTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestWorkflowTemplateServiceInstantiateWorkflowTemplate(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedName string = fmt.Sprintf("projects/%s/regions/%s/workflowTemplates/%s", "[PROJECT]", "[REGION]", "[WORKFLOW_TEMPLATE]") + var request = &dataprocpb.InstantiateWorkflowTemplateRequest{ + Name: formattedName, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.InstantiateWorkflowTemplate(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestWorkflowTemplateServiceInstantiateWorkflowTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedName string = fmt.Sprintf("projects/%s/regions/%s/workflowTemplates/%s", "[PROJECT]", "[REGION]", "[WORKFLOW_TEMPLATE]") + var request = &dataprocpb.InstantiateWorkflowTemplateRequest{ + Name: formattedName, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.InstantiateWorkflowTemplate(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestWorkflowTemplateServiceInstantiateInlineWorkflowTemplate(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/regions/%s", "[PROJECT]", "[REGION]") + var template *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var request = &dataprocpb.InstantiateInlineWorkflowTemplateRequest{ + Parent: formattedParent, + Template: template, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.InstantiateInlineWorkflowTemplate(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestWorkflowTemplateServiceInstantiateInlineWorkflowTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/regions/%s", "[PROJECT]", "[REGION]") + var template *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var request = &dataprocpb.InstantiateInlineWorkflowTemplateRequest{ + Parent: formattedParent, + Template: template, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.InstantiateInlineWorkflowTemplate(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestWorkflowTemplateServiceUpdateWorkflowTemplate(t *testing.T) { + var id string = "id3355" + var name string = "name3373707" + var version int32 = 351608024 + var expectedResponse = &dataprocpb.WorkflowTemplate{ + Id: id, + Name: name, + Version: version, + } + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], expectedResponse) + + var template *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var request = &dataprocpb.UpdateWorkflowTemplateRequest{ + Template: template, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateWorkflowTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestWorkflowTemplateServiceUpdateWorkflowTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = gstatus.Error(errCode, "test error") + + var template *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var request = &dataprocpb.UpdateWorkflowTemplateRequest{ + Template: template, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateWorkflowTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestWorkflowTemplateServiceListWorkflowTemplates(t *testing.T) { + var nextPageToken string = "" + var templatesElement *dataprocpb.WorkflowTemplate = &dataprocpb.WorkflowTemplate{} + var templates = []*dataprocpb.WorkflowTemplate{templatesElement} + var expectedResponse = &dataprocpb.ListWorkflowTemplatesResponse{ + NextPageToken: nextPageToken, + Templates: templates, + } + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/regions/%s", "[PROJECT]", "[REGION]") + var request = &dataprocpb.ListWorkflowTemplatesRequest{ + Parent: formattedParent, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListWorkflowTemplates(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Templates[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestWorkflowTemplateServiceListWorkflowTemplatesError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/regions/%s", "[PROJECT]", "[REGION]") + var request = &dataprocpb.ListWorkflowTemplatesRequest{ + Parent: formattedParent, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListWorkflowTemplates(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestWorkflowTemplateServiceDeleteWorkflowTemplate(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockWorkflowTemplate.err = nil + mockWorkflowTemplate.reqs = nil + + mockWorkflowTemplate.resps = append(mockWorkflowTemplate.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/regions/%s/workflowTemplates/%s", "[PROJECT]", "[REGION]", "[WORKFLOW_TEMPLATE]") + var request = &dataprocpb.DeleteWorkflowTemplateRequest{ + Name: formattedName, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteWorkflowTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockWorkflowTemplate.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestWorkflowTemplateServiceDeleteWorkflowTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockWorkflowTemplate.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/regions/%s/workflowTemplates/%s", "[PROJECT]", "[REGION]", "[WORKFLOW_TEMPLATE]") + var request = &dataprocpb.DeleteWorkflowTemplateRequest{ + Name: formattedName, + } + + c, err := NewWorkflowTemplateClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteWorkflowTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1beta2/workflow_template_client.go b/vendor/cloud.google.com/go/dataproc/apiv1beta2/workflow_template_client.go new file mode 100644 index 00000000..4af9232b --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1beta2/workflow_template_client.go @@ -0,0 +1,525 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc + +import ( + "context" + "math" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1beta2" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// WorkflowTemplateCallOptions contains the retry settings for each method of WorkflowTemplateClient. +type WorkflowTemplateCallOptions struct { + CreateWorkflowTemplate []gax.CallOption + GetWorkflowTemplate []gax.CallOption + InstantiateWorkflowTemplate []gax.CallOption + InstantiateInlineWorkflowTemplate []gax.CallOption + UpdateWorkflowTemplate []gax.CallOption + ListWorkflowTemplates []gax.CallOption + DeleteWorkflowTemplate []gax.CallOption +} + +func defaultWorkflowTemplateClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("dataproc.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultWorkflowTemplateCallOptions() *WorkflowTemplateCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Internal, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + {"default", "non_idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &WorkflowTemplateCallOptions{ + CreateWorkflowTemplate: retry[[2]string{"default", "non_idempotent"}], + GetWorkflowTemplate: retry[[2]string{"default", "idempotent"}], + InstantiateWorkflowTemplate: retry[[2]string{"default", "non_idempotent"}], + InstantiateInlineWorkflowTemplate: retry[[2]string{"default", "non_idempotent"}], + UpdateWorkflowTemplate: retry[[2]string{"default", "non_idempotent"}], + ListWorkflowTemplates: retry[[2]string{"default", "idempotent"}], + DeleteWorkflowTemplate: retry[[2]string{"default", "non_idempotent"}], + } +} + +// WorkflowTemplateClient is a client for interacting with Google Cloud Dataproc API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type WorkflowTemplateClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + workflowTemplateClient dataprocpb.WorkflowTemplateServiceClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *WorkflowTemplateCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewWorkflowTemplateClient creates a new workflow template service client. +// +// The API interface for managing Workflow Templates in the +// Cloud Dataproc API. +func NewWorkflowTemplateClient(ctx context.Context, opts ...option.ClientOption) (*WorkflowTemplateClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultWorkflowTemplateClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &WorkflowTemplateClient{ + conn: conn, + CallOptions: defaultWorkflowTemplateCallOptions(), + + workflowTemplateClient: dataprocpb.NewWorkflowTemplateServiceClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *WorkflowTemplateClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *WorkflowTemplateClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *WorkflowTemplateClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// CreateWorkflowTemplate creates new workflow template. +func (c *WorkflowTemplateClient) CreateWorkflowTemplate(ctx context.Context, req *dataprocpb.CreateWorkflowTemplateRequest, opts ...gax.CallOption) (*dataprocpb.WorkflowTemplate, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateWorkflowTemplate[0:len(c.CallOptions.CreateWorkflowTemplate):len(c.CallOptions.CreateWorkflowTemplate)], opts...) + var resp *dataprocpb.WorkflowTemplate + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.workflowTemplateClient.CreateWorkflowTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetWorkflowTemplate retrieves the latest workflow template. +// +// Can retrieve previously instantiated template by specifying optional +// version parameter. +func (c *WorkflowTemplateClient) GetWorkflowTemplate(ctx context.Context, req *dataprocpb.GetWorkflowTemplateRequest, opts ...gax.CallOption) (*dataprocpb.WorkflowTemplate, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetWorkflowTemplate[0:len(c.CallOptions.GetWorkflowTemplate):len(c.CallOptions.GetWorkflowTemplate)], opts...) + var resp *dataprocpb.WorkflowTemplate + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.workflowTemplateClient.GetWorkflowTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// InstantiateWorkflowTemplate instantiates a template and begins execution. +// +// The returned Operation can be used to track execution of +// workflow by polling +// [operations.get][google.longrunning.Operations.GetOperation]. +// The Operation will complete when entire workflow is finished. +// +// The running workflow can be aborted via +// [operations.cancel][google.longrunning.Operations.CancelOperation]. +// This will cause any inflight jobs to be cancelled and workflow-owned +// clusters to be deleted. +// +// The [Operation.metadata][google.longrunning.Operation.metadata] will be +// [WorkflowMetadata][google.cloud.dataproc.v1beta2.WorkflowMetadata]. +// +// On successful completion, +// [Operation.response][google.longrunning.Operation.response] will be +// [Empty][google.protobuf.Empty]. +func (c *WorkflowTemplateClient) InstantiateWorkflowTemplate(ctx context.Context, req *dataprocpb.InstantiateWorkflowTemplateRequest, opts ...gax.CallOption) (*InstantiateWorkflowTemplateOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.InstantiateWorkflowTemplate[0:len(c.CallOptions.InstantiateWorkflowTemplate):len(c.CallOptions.InstantiateWorkflowTemplate)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.workflowTemplateClient.InstantiateWorkflowTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &InstantiateWorkflowTemplateOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// InstantiateInlineWorkflowTemplate instantiates a template and begins execution. +// +// This method is equivalent to executing the sequence +// [CreateWorkflowTemplate][google.cloud.dataproc.v1beta2.WorkflowTemplateService.CreateWorkflowTemplate], [InstantiateWorkflowTemplate][google.cloud.dataproc.v1beta2.WorkflowTemplateService.InstantiateWorkflowTemplate], +// [DeleteWorkflowTemplate][google.cloud.dataproc.v1beta2.WorkflowTemplateService.DeleteWorkflowTemplate]. +// +// The returned Operation can be used to track execution of +// workflow by polling +// [operations.get][google.longrunning.Operations.GetOperation]. +// The Operation will complete when entire workflow is finished. +// +// The running workflow can be aborted via +// [operations.cancel][google.longrunning.Operations.CancelOperation]. +// This will cause any inflight jobs to be cancelled and workflow-owned +// clusters to be deleted. +// +// The [Operation.metadata][google.longrunning.Operation.metadata] will be +// [WorkflowMetadata][google.cloud.dataproc.v1beta2.WorkflowMetadata]. +// +// On successful completion, +// [Operation.response][google.longrunning.Operation.response] will be +// [Empty][google.protobuf.Empty]. +func (c *WorkflowTemplateClient) InstantiateInlineWorkflowTemplate(ctx context.Context, req *dataprocpb.InstantiateInlineWorkflowTemplateRequest, opts ...gax.CallOption) (*InstantiateInlineWorkflowTemplateOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.InstantiateInlineWorkflowTemplate[0:len(c.CallOptions.InstantiateInlineWorkflowTemplate):len(c.CallOptions.InstantiateInlineWorkflowTemplate)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.workflowTemplateClient.InstantiateInlineWorkflowTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &InstantiateInlineWorkflowTemplateOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// UpdateWorkflowTemplate updates (replaces) workflow template. The updated template +// must contain version that matches the current server version. +func (c *WorkflowTemplateClient) UpdateWorkflowTemplate(ctx context.Context, req *dataprocpb.UpdateWorkflowTemplateRequest, opts ...gax.CallOption) (*dataprocpb.WorkflowTemplate, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateWorkflowTemplate[0:len(c.CallOptions.UpdateWorkflowTemplate):len(c.CallOptions.UpdateWorkflowTemplate)], opts...) + var resp *dataprocpb.WorkflowTemplate + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.workflowTemplateClient.UpdateWorkflowTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListWorkflowTemplates lists workflows that match the specified filter in the request. +func (c *WorkflowTemplateClient) ListWorkflowTemplates(ctx context.Context, req *dataprocpb.ListWorkflowTemplatesRequest, opts ...gax.CallOption) *WorkflowTemplateIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListWorkflowTemplates[0:len(c.CallOptions.ListWorkflowTemplates):len(c.CallOptions.ListWorkflowTemplates)], opts...) + it := &WorkflowTemplateIterator{} + req = proto.Clone(req).(*dataprocpb.ListWorkflowTemplatesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dataprocpb.WorkflowTemplate, string, error) { + var resp *dataprocpb.ListWorkflowTemplatesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.workflowTemplateClient.ListWorkflowTemplates(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Templates, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DeleteWorkflowTemplate deletes a workflow template. It does not cancel in-progress workflows. +func (c *WorkflowTemplateClient) DeleteWorkflowTemplate(ctx context.Context, req *dataprocpb.DeleteWorkflowTemplateRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteWorkflowTemplate[0:len(c.CallOptions.DeleteWorkflowTemplate):len(c.CallOptions.DeleteWorkflowTemplate)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.workflowTemplateClient.DeleteWorkflowTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// WorkflowTemplateIterator manages a stream of *dataprocpb.WorkflowTemplate. +type WorkflowTemplateIterator struct { + items []*dataprocpb.WorkflowTemplate + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dataprocpb.WorkflowTemplate, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *WorkflowTemplateIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *WorkflowTemplateIterator) Next() (*dataprocpb.WorkflowTemplate, error) { + var item *dataprocpb.WorkflowTemplate + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *WorkflowTemplateIterator) bufLen() int { + return len(it.items) +} + +func (it *WorkflowTemplateIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// InstantiateInlineWorkflowTemplateOperation manages a long-running operation from InstantiateInlineWorkflowTemplate. +type InstantiateInlineWorkflowTemplateOperation struct { + lro *longrunning.Operation +} + +// InstantiateInlineWorkflowTemplateOperation returns a new InstantiateInlineWorkflowTemplateOperation from a given name. +// The name must be that of a previously created InstantiateInlineWorkflowTemplateOperation, possibly from a different process. +func (c *WorkflowTemplateClient) InstantiateInlineWorkflowTemplateOperation(name string) *InstantiateInlineWorkflowTemplateOperation { + return &InstantiateInlineWorkflowTemplateOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *InstantiateInlineWorkflowTemplateOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 10000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *InstantiateInlineWorkflowTemplateOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *InstantiateInlineWorkflowTemplateOperation) Metadata() (*dataprocpb.WorkflowMetadata, error) { + var meta dataprocpb.WorkflowMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *InstantiateInlineWorkflowTemplateOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *InstantiateInlineWorkflowTemplateOperation) Name() string { + return op.lro.Name() +} + +// Cancel starts asynchronous cancellation on a long-running operation. +// The server makes a best effort to cancel the operation, but success is not guaranteed. +// Clients can use Poll or other methods to check whether the cancellation succeeded or whether the operation +// completed despite cancellation. On successful cancellation, the operation is not deleted; +// instead, op.Poll returns an error with code Canceled. +func (op *InstantiateInlineWorkflowTemplateOperation) Cancel(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Cancel(ctx, opts...) +} + +// Delete deletes a long-running operation. +// This method indicates that the client is no longer interested in the operation result. +// It does not cancel the operation. +func (op *InstantiateInlineWorkflowTemplateOperation) Delete(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Delete(ctx, opts...) +} + +// InstantiateWorkflowTemplateOperation manages a long-running operation from InstantiateWorkflowTemplate. +type InstantiateWorkflowTemplateOperation struct { + lro *longrunning.Operation +} + +// InstantiateWorkflowTemplateOperation returns a new InstantiateWorkflowTemplateOperation from a given name. +// The name must be that of a previously created InstantiateWorkflowTemplateOperation, possibly from a different process. +func (c *WorkflowTemplateClient) InstantiateWorkflowTemplateOperation(name string) *InstantiateWorkflowTemplateOperation { + return &InstantiateWorkflowTemplateOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *InstantiateWorkflowTemplateOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 10000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *InstantiateWorkflowTemplateOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *InstantiateWorkflowTemplateOperation) Metadata() (*dataprocpb.WorkflowMetadata, error) { + var meta dataprocpb.WorkflowMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *InstantiateWorkflowTemplateOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *InstantiateWorkflowTemplateOperation) Name() string { + return op.lro.Name() +} + +// Cancel starts asynchronous cancellation on a long-running operation. +// The server makes a best effort to cancel the operation, but success is not guaranteed. +// Clients can use Poll or other methods to check whether the cancellation succeeded or whether the operation +// completed despite cancellation. On successful cancellation, the operation is not deleted; +// instead, op.Poll returns an error with code Canceled. +func (op *InstantiateWorkflowTemplateOperation) Cancel(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Cancel(ctx, opts...) +} + +// Delete deletes a long-running operation. +// This method indicates that the client is no longer interested in the operation result. +// It does not cancel the operation. +func (op *InstantiateWorkflowTemplateOperation) Delete(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Delete(ctx, opts...) +} diff --git a/vendor/cloud.google.com/go/dataproc/apiv1beta2/workflow_template_client_example_test.go b/vendor/cloud.google.com/go/dataproc/apiv1beta2/workflow_template_client_example_test.go new file mode 100644 index 00000000..56c971fa --- /dev/null +++ b/vendor/cloud.google.com/go/dataproc/apiv1beta2/workflow_template_client_example_test.go @@ -0,0 +1,167 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dataproc_test + +import ( + "context" + + dataproc "cloud.google.com/go/dataproc/apiv1beta2" + "google.golang.org/api/iterator" + dataprocpb "google.golang.org/genproto/googleapis/cloud/dataproc/v1beta2" +) + +func ExampleNewWorkflowTemplateClient() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleWorkflowTemplateClient_CreateWorkflowTemplate() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.CreateWorkflowTemplateRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateWorkflowTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleWorkflowTemplateClient_GetWorkflowTemplate() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.GetWorkflowTemplateRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetWorkflowTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleWorkflowTemplateClient_InstantiateWorkflowTemplate() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.InstantiateWorkflowTemplateRequest{ + // TODO: Fill request struct fields. + } + op, err := c.InstantiateWorkflowTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} + +func ExampleWorkflowTemplateClient_InstantiateInlineWorkflowTemplate() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.InstantiateInlineWorkflowTemplateRequest{ + // TODO: Fill request struct fields. + } + op, err := c.InstantiateInlineWorkflowTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} + +func ExampleWorkflowTemplateClient_UpdateWorkflowTemplate() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.UpdateWorkflowTemplateRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateWorkflowTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleWorkflowTemplateClient_ListWorkflowTemplates() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.ListWorkflowTemplatesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListWorkflowTemplates(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleWorkflowTemplateClient_DeleteWorkflowTemplate() { + ctx := context.Background() + c, err := dataproc.NewWorkflowTemplateClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dataprocpb.DeleteWorkflowTemplateRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteWorkflowTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/datastore/client.go b/vendor/cloud.google.com/go/datastore/client.go new file mode 100644 index 00000000..8eee203b --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/client.go @@ -0,0 +1,117 @@ +// Copyright 2017 Google LLC +// +// 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 datastore + +import ( + "context" + "fmt" + + "cloud.google.com/go/internal" + "cloud.google.com/go/internal/version" + gax "github.com/googleapis/gax-go" + pb "google.golang.org/genproto/googleapis/datastore/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// datastoreClient is a wrapper for the pb.DatastoreClient that includes gRPC +// metadata to be sent in each request for server-side traffic management. +type datastoreClient struct { + // Embed so we still implement the DatastoreClient interface, + // if the interface adds more methods. + pb.DatastoreClient + + c pb.DatastoreClient + md metadata.MD +} + +func newDatastoreClient(conn *grpc.ClientConn, projectID string) pb.DatastoreClient { + return &datastoreClient{ + c: pb.NewDatastoreClient(conn), + md: metadata.Pairs( + resourcePrefixHeader, "projects/"+projectID, + "x-goog-api-client", fmt.Sprintf("gl-go/%s gccl/%s grpc/", version.Go(), version.Repo)), + } +} + +func (dc *datastoreClient) Lookup(ctx context.Context, in *pb.LookupRequest, opts ...grpc.CallOption) (res *pb.LookupResponse, err error) { + err = dc.invoke(ctx, func(ctx context.Context) error { + res, err = dc.c.Lookup(ctx, in, opts...) + return err + }) + return res, err +} + +func (dc *datastoreClient) RunQuery(ctx context.Context, in *pb.RunQueryRequest, opts ...grpc.CallOption) (res *pb.RunQueryResponse, err error) { + err = dc.invoke(ctx, func(ctx context.Context) error { + res, err = dc.c.RunQuery(ctx, in, opts...) + return err + }) + return res, err +} + +func (dc *datastoreClient) BeginTransaction(ctx context.Context, in *pb.BeginTransactionRequest, opts ...grpc.CallOption) (res *pb.BeginTransactionResponse, err error) { + err = dc.invoke(ctx, func(ctx context.Context) error { + res, err = dc.c.BeginTransaction(ctx, in, opts...) + return err + }) + return res, err +} + +func (dc *datastoreClient) Commit(ctx context.Context, in *pb.CommitRequest, opts ...grpc.CallOption) (res *pb.CommitResponse, err error) { + err = dc.invoke(ctx, func(ctx context.Context) error { + res, err = dc.c.Commit(ctx, in, opts...) + return err + }) + return res, err +} + +func (dc *datastoreClient) Rollback(ctx context.Context, in *pb.RollbackRequest, opts ...grpc.CallOption) (res *pb.RollbackResponse, err error) { + err = dc.invoke(ctx, func(ctx context.Context) error { + res, err = dc.c.Rollback(ctx, in, opts...) + return err + }) + return res, err +} + +func (dc *datastoreClient) AllocateIds(ctx context.Context, in *pb.AllocateIdsRequest, opts ...grpc.CallOption) (res *pb.AllocateIdsResponse, err error) { + err = dc.invoke(ctx, func(ctx context.Context) error { + res, err = dc.c.AllocateIds(ctx, in, opts...) + return err + }) + return res, err +} + +func (dc *datastoreClient) invoke(ctx context.Context, f func(ctx context.Context) error) error { + ctx = metadata.NewOutgoingContext(ctx, dc.md) + return internal.Retry(ctx, gax.Backoff{}, func() (stop bool, err error) { + err = f(ctx) + return !shouldRetry(err), err + }) +} + +func shouldRetry(err error) bool { + if err == nil { + return false + } + s, ok := status.FromError(err) + if !ok { + return false + } + // See https://cloud.google.com/datastore/docs/concepts/errors. + return s.Code() == codes.Unavailable || s.Code() == codes.DeadlineExceeded +} diff --git a/vendor/cloud.google.com/go/datastore/datastore.go b/vendor/cloud.google.com/go/datastore/datastore.go new file mode 100644 index 00000000..315df2b0 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/datastore.go @@ -0,0 +1,645 @@ +// Copyright 2014 Google LLC +// +// 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 datastore + +import ( + "context" + "errors" + "fmt" + "log" + "os" + "reflect" + + "cloud.google.com/go/internal/trace" + "google.golang.org/api/option" + gtransport "google.golang.org/api/transport/grpc" + pb "google.golang.org/genproto/googleapis/datastore/v1" + "google.golang.org/grpc" +) + +const ( + prodAddr = "datastore.googleapis.com:443" + userAgent = "gcloud-golang-datastore/20160401" +) + +// ScopeDatastore grants permissions to view and/or manage datastore entities +const ScopeDatastore = "https://www.googleapis.com/auth/datastore" + +// resourcePrefixHeader is the name of the metadata header used to indicate +// the resource being operated on. +const resourcePrefixHeader = "google-cloud-resource-prefix" + +// Client is a client for reading and writing data in a datastore dataset. +type Client struct { + conn *grpc.ClientConn + client pb.DatastoreClient + endpoint string + dataset string // Called dataset by the datastore API, synonym for project ID. +} + +// NewClient creates a new Client for a given dataset. +// If the project ID is empty, it is derived from the DATASTORE_PROJECT_ID environment variable. +// If the DATASTORE_EMULATOR_HOST environment variable is set, client will use its value +// to connect to a locally-running datastore emulator. +func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) { + var o []option.ClientOption + // Environment variables for gcd emulator: + // https://cloud.google.com/datastore/docs/tools/datastore-emulator + // If the emulator is available, dial it without passing any credentials. + if addr := os.Getenv("DATASTORE_EMULATOR_HOST"); addr != "" { + o = []option.ClientOption{ + option.WithEndpoint(addr), + option.WithoutAuthentication(), + option.WithGRPCDialOption(grpc.WithInsecure()), + } + } else { + o = []option.ClientOption{ + option.WithEndpoint(prodAddr), + option.WithScopes(ScopeDatastore), + option.WithUserAgent(userAgent), + } + } + // Warn if we see the legacy emulator environment variables. + if os.Getenv("DATASTORE_HOST") != "" && os.Getenv("DATASTORE_EMULATOR_HOST") == "" { + log.Print("WARNING: legacy environment variable DATASTORE_HOST is ignored. Use DATASTORE_EMULATOR_HOST instead.") + } + if os.Getenv("DATASTORE_DATASET") != "" && os.Getenv("DATASTORE_PROJECT_ID") == "" { + log.Print("WARNING: legacy environment variable DATASTORE_DATASET is ignored. Use DATASTORE_PROJECT_ID instead.") + } + if projectID == "" { + projectID = os.Getenv("DATASTORE_PROJECT_ID") + } + if projectID == "" { + return nil, errors.New("datastore: missing project/dataset id") + } + o = append(o, opts...) + conn, err := gtransport.Dial(ctx, o...) + if err != nil { + return nil, fmt.Errorf("dialing: %v", err) + } + return &Client{ + conn: conn, + client: newDatastoreClient(conn, projectID), + dataset: projectID, + }, nil + +} + +var ( + // ErrInvalidEntityType is returned when functions like Get or Next are + // passed a dst or src argument of invalid type. + ErrInvalidEntityType = errors.New("datastore: invalid entity type") + // ErrInvalidKey is returned when an invalid key is presented. + ErrInvalidKey = errors.New("datastore: invalid key") + // ErrNoSuchEntity is returned when no entity was found for a given key. + ErrNoSuchEntity = errors.New("datastore: no such entity") +) + +type multiArgType int + +const ( + multiArgTypeInvalid multiArgType = iota + multiArgTypePropertyLoadSaver + multiArgTypeStruct + multiArgTypeStructPtr + multiArgTypeInterface +) + +// ErrFieldMismatch is returned when a field is to be loaded into a different +// type than the one it was stored from, or when a field is missing or +// unexported in the destination struct. +// StructType is the type of the struct pointed to by the destination argument +// passed to Get or to Iterator.Next. +type ErrFieldMismatch struct { + StructType reflect.Type + FieldName string + Reason string +} + +func (e *ErrFieldMismatch) Error() string { + return fmt.Sprintf("datastore: cannot load field %q into a %q: %s", + e.FieldName, e.StructType, e.Reason) +} + +// GeoPoint represents a location as latitude/longitude in degrees. +type GeoPoint struct { + Lat, Lng float64 +} + +// Valid returns whether a GeoPoint is within [-90, 90] latitude and [-180, 180] longitude. +func (g GeoPoint) Valid() bool { + return -90 <= g.Lat && g.Lat <= 90 && -180 <= g.Lng && g.Lng <= 180 +} + +func keyToProto(k *Key) *pb.Key { + if k == nil { + return nil + } + + var path []*pb.Key_PathElement + for { + el := &pb.Key_PathElement{Kind: k.Kind} + if k.ID != 0 { + el.IdType = &pb.Key_PathElement_Id{Id: k.ID} + } else if k.Name != "" { + el.IdType = &pb.Key_PathElement_Name{Name: k.Name} + } + path = append(path, el) + if k.Parent == nil { + break + } + k = k.Parent + } + + // The path should be in order [grandparent, parent, child] + // We did it backward above, so reverse back. + for i := 0; i < len(path)/2; i++ { + path[i], path[len(path)-i-1] = path[len(path)-i-1], path[i] + } + + key := &pb.Key{Path: path} + if k.Namespace != "" { + key.PartitionId = &pb.PartitionId{ + NamespaceId: k.Namespace, + } + } + return key +} + +// protoToKey decodes a protocol buffer representation of a key into an +// equivalent *Key object. If the key is invalid, protoToKey will return the +// invalid key along with ErrInvalidKey. +func protoToKey(p *pb.Key) (*Key, error) { + var key *Key + var namespace string + if partition := p.PartitionId; partition != nil { + namespace = partition.NamespaceId + } + for _, el := range p.Path { + key = &Key{ + Namespace: namespace, + Kind: el.Kind, + ID: el.GetId(), + Name: el.GetName(), + Parent: key, + } + } + if !key.valid() { // Also detects key == nil. + return key, ErrInvalidKey + } + return key, nil +} + +// multiKeyToProto is a batch version of keyToProto. +func multiKeyToProto(keys []*Key) []*pb.Key { + ret := make([]*pb.Key, len(keys)) + for i, k := range keys { + ret[i] = keyToProto(k) + } + return ret +} + +// multiKeyToProto is a batch version of keyToProto. +func multiProtoToKey(keys []*pb.Key) ([]*Key, error) { + hasErr := false + ret := make([]*Key, len(keys)) + err := make(MultiError, len(keys)) + for i, k := range keys { + ret[i], err[i] = protoToKey(k) + if err[i] != nil { + hasErr = true + } + } + if hasErr { + return nil, err + } + return ret, nil +} + +// multiValid is a batch version of Key.valid. It returns an error, not a +// []bool. +func multiValid(key []*Key) error { + invalid := false + for _, k := range key { + if !k.valid() { + invalid = true + break + } + } + if !invalid { + return nil + } + err := make(MultiError, len(key)) + for i, k := range key { + if !k.valid() { + err[i] = ErrInvalidKey + } + } + return err +} + +// checkMultiArg checks that v has type []S, []*S, []I, or []P, for some struct +// type S, for some interface type I, or some non-interface non-pointer type P +// such that P or *P implements PropertyLoadSaver. +// +// It returns what category the slice's elements are, and the reflect.Type +// that represents S, I or P. +// +// As a special case, PropertyList is an invalid type for v. +func checkMultiArg(v reflect.Value) (m multiArgType, elemType reflect.Type) { + // TODO(djd): multiArg is very confusing. Fold this logic into the + // relevant Put/Get methods to make the logic less opaque. + if v.Kind() != reflect.Slice { + return multiArgTypeInvalid, nil + } + if v.Type() == typeOfPropertyList { + return multiArgTypeInvalid, nil + } + elemType = v.Type().Elem() + if reflect.PtrTo(elemType).Implements(typeOfPropertyLoadSaver) { + return multiArgTypePropertyLoadSaver, elemType + } + switch elemType.Kind() { + case reflect.Struct: + return multiArgTypeStruct, elemType + case reflect.Interface: + return multiArgTypeInterface, elemType + case reflect.Ptr: + elemType = elemType.Elem() + if elemType.Kind() == reflect.Struct { + return multiArgTypeStructPtr, elemType + } + } + return multiArgTypeInvalid, nil +} + +// Close closes the Client. +func (c *Client) Close() error { + return c.conn.Close() +} + +// Get loads the entity stored for key into dst, which must be a struct pointer +// or implement PropertyLoadSaver. If there is no such entity for the key, Get +// returns ErrNoSuchEntity. +// +// The values of dst's unmatched struct fields are not modified, and matching +// slice-typed fields are not reset before appending to them. In particular, it +// is recommended to pass a pointer to a zero valued struct on each Get call. +// +// ErrFieldMismatch is returned when a field is to be loaded into a different +// type than the one it was stored from, or when a field is missing or +// unexported in the destination struct. ErrFieldMismatch is only returned if +// dst is a struct pointer. +func (c *Client) Get(ctx context.Context, key *Key, dst interface{}) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.Get") + defer func() { trace.EndSpan(ctx, err) }() + + if dst == nil { // get catches nil interfaces; we need to catch nil ptr here + return ErrInvalidEntityType + } + err = c.get(ctx, []*Key{key}, []interface{}{dst}, nil) + if me, ok := err.(MultiError); ok { + return me[0] + } + return err +} + +// GetMulti is a batch version of Get. +// +// dst must be a []S, []*S, []I or []P, for some struct type S, some interface +// type I, or some non-interface non-pointer type P such that P or *P +// implements PropertyLoadSaver. If an []I, each element must be a valid dst +// for Get: it must be a struct pointer or implement PropertyLoadSaver. +// +// As a special case, PropertyList is an invalid type for dst, even though a +// PropertyList is a slice of structs. It is treated as invalid to avoid being +// mistakenly passed when []PropertyList was intended. +// +// err may be a MultiError. See ExampleMultiError to check it. +func (c *Client) GetMulti(ctx context.Context, keys []*Key, dst interface{}) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.GetMulti") + defer func() { trace.EndSpan(ctx, err) }() + + return c.get(ctx, keys, dst, nil) +} + +func (c *Client) get(ctx context.Context, keys []*Key, dst interface{}, opts *pb.ReadOptions) error { + v := reflect.ValueOf(dst) + multiArgType, _ := checkMultiArg(v) + + // Sanity checks + if multiArgType == multiArgTypeInvalid { + return errors.New("datastore: dst has invalid type") + } + if len(keys) != v.Len() { + return errors.New("datastore: keys and dst slices have different length") + } + if len(keys) == 0 { + return nil + } + + // Go through keys, validate them, serialize then, and create a dict mapping them to their indices. + // Equal keys are deduped. + multiErr, any := make(MultiError, len(keys)), false + keyMap := make(map[string][]int, len(keys)) + pbKeys := make([]*pb.Key, 0, len(keys)) + for i, k := range keys { + if !k.valid() { + multiErr[i] = ErrInvalidKey + any = true + } else if k.Incomplete() { + multiErr[i] = fmt.Errorf("datastore: can't get the incomplete key: %v", k) + any = true + } else { + ks := k.String() + if _, ok := keyMap[ks]; !ok { + pbKeys = append(pbKeys, keyToProto(k)) + } + keyMap[ks] = append(keyMap[ks], i) + } + } + if any { + return multiErr + } + req := &pb.LookupRequest{ + ProjectId: c.dataset, + Keys: pbKeys, + ReadOptions: opts, + } + resp, err := c.client.Lookup(ctx, req) + if err != nil { + return err + } + found := resp.Found + missing := resp.Missing + // Upper bound 100 iterations to prevent infinite loop. + // We choose 100 iterations somewhat logically: + // Max number of Entities you can request from Datastore is 1,000. + // Max size for a Datastore Entity is 1 MiB. + // Max request size is 10 MiB, so we assume max response size is also 10 MiB. + // 1,000 / 10 = 100. + // Note that if ctx has a deadline, the deadline will probably + // be hit before we reach 100 iterations. + for i := 0; len(resp.Deferred) > 0 && i < 100; i++ { + req.Keys = resp.Deferred + resp, err = c.client.Lookup(ctx, req) + if err != nil { + return err + } + found = append(found, resp.Found...) + missing = append(missing, resp.Missing...) + } + + filled := 0 + for _, e := range found { + k, err := protoToKey(e.Entity.Key) + if err != nil { + return errors.New("datastore: internal error: server returned an invalid key") + } + filled += len(keyMap[k.String()]) + for _, index := range keyMap[k.String()] { + elem := v.Index(index) + if multiArgType == multiArgTypePropertyLoadSaver || multiArgType == multiArgTypeStruct { + elem = elem.Addr() + } + if multiArgType == multiArgTypeStructPtr && elem.IsNil() { + elem.Set(reflect.New(elem.Type().Elem())) + } + if err := loadEntityProto(elem.Interface(), e.Entity); err != nil { + multiErr[index] = err + any = true + } + } + } + for _, e := range missing { + k, err := protoToKey(e.Entity.Key) + if err != nil { + return errors.New("datastore: internal error: server returned an invalid key") + } + filled += len(keyMap[k.String()]) + for _, index := range keyMap[k.String()] { + multiErr[index] = ErrNoSuchEntity + } + any = true + } + + if filled != len(keys) { + return errors.New("datastore: internal error: server returned the wrong number of entities") + } + + if any { + return multiErr + } + return nil +} + +// Put saves the entity src into the datastore with the given key. src must be +// a struct pointer or implement PropertyLoadSaver; if the struct pointer has +// any unexported fields they will be skipped. If the key is incomplete, the +// returned key will be a unique key generated by the datastore. +func (c *Client) Put(ctx context.Context, key *Key, src interface{}) (*Key, error) { + k, err := c.PutMulti(ctx, []*Key{key}, []interface{}{src}) + if err != nil { + if me, ok := err.(MultiError); ok { + return nil, me[0] + } + return nil, err + } + return k[0], nil +} + +// PutMulti is a batch version of Put. +// +// src must satisfy the same conditions as the dst argument to GetMulti. +// err may be a MultiError. See ExampleMultiError to check it. +func (c *Client) PutMulti(ctx context.Context, keys []*Key, src interface{}) (ret []*Key, err error) { + // TODO(jba): rewrite in terms of Mutate. + ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.PutMulti") + defer func() { trace.EndSpan(ctx, err) }() + + mutations, err := putMutations(keys, src) + if err != nil { + return nil, err + } + + // Make the request. + req := &pb.CommitRequest{ + ProjectId: c.dataset, + Mutations: mutations, + Mode: pb.CommitRequest_NON_TRANSACTIONAL, + } + resp, err := c.client.Commit(ctx, req) + if err != nil { + return nil, err + } + + // Copy any newly minted keys into the returned keys. + ret = make([]*Key, len(keys)) + for i, key := range keys { + if key.Incomplete() { + // This key is in the mutation results. + ret[i], err = protoToKey(resp.MutationResults[i].Key) + if err != nil { + return nil, errors.New("datastore: internal error: server returned an invalid key") + } + } else { + ret[i] = key + } + } + return ret, nil +} + +func putMutations(keys []*Key, src interface{}) ([]*pb.Mutation, error) { + v := reflect.ValueOf(src) + multiArgType, _ := checkMultiArg(v) + if multiArgType == multiArgTypeInvalid { + return nil, errors.New("datastore: src has invalid type") + } + if len(keys) != v.Len() { + return nil, errors.New("datastore: key and src slices have different length") + } + if len(keys) == 0 { + return nil, nil + } + if err := multiValid(keys); err != nil { + return nil, err + } + mutations := make([]*pb.Mutation, 0, len(keys)) + multiErr := make(MultiError, len(keys)) + hasErr := false + for i, k := range keys { + elem := v.Index(i) + // Two cases where we need to take the address: + // 1) multiArgTypePropertyLoadSaver => &elem implements PLS + // 2) multiArgTypeStruct => saveEntity needs *struct + if multiArgType == multiArgTypePropertyLoadSaver || multiArgType == multiArgTypeStruct { + elem = elem.Addr() + } + p, err := saveEntity(k, elem.Interface()) + if err != nil { + multiErr[i] = err + hasErr = true + } + var mut *pb.Mutation + if k.Incomplete() { + mut = &pb.Mutation{Operation: &pb.Mutation_Insert{Insert: p}} + } else { + mut = &pb.Mutation{Operation: &pb.Mutation_Upsert{Upsert: p}} + } + mutations = append(mutations, mut) + } + if hasErr { + return nil, multiErr + } + return mutations, nil +} + +// Delete deletes the entity for the given key. +func (c *Client) Delete(ctx context.Context, key *Key) error { + err := c.DeleteMulti(ctx, []*Key{key}) + if me, ok := err.(MultiError); ok { + return me[0] + } + return err +} + +// DeleteMulti is a batch version of Delete. +// +// err may be a MultiError. See ExampleMultiError to check it. +func (c *Client) DeleteMulti(ctx context.Context, keys []*Key) (err error) { + // TODO(jba): rewrite in terms of Mutate. + ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.DeleteMulti") + defer func() { trace.EndSpan(ctx, err) }() + + mutations, err := deleteMutations(keys) + if err != nil { + return err + } + + req := &pb.CommitRequest{ + ProjectId: c.dataset, + Mutations: mutations, + Mode: pb.CommitRequest_NON_TRANSACTIONAL, + } + _, err = c.client.Commit(ctx, req) + return err +} + +func deleteMutations(keys []*Key) ([]*pb.Mutation, error) { + mutations := make([]*pb.Mutation, 0, len(keys)) + set := make(map[string]bool, len(keys)) + multiErr := make(MultiError, len(keys)) + hasErr := false + for i, k := range keys { + if !k.valid() { + multiErr[i] = ErrInvalidKey + hasErr = true + } else if k.Incomplete() { + multiErr[i] = fmt.Errorf("datastore: can't delete the incomplete key: %v", k) + hasErr = true + } else { + ks := k.String() + if !set[ks] { + mutations = append(mutations, &pb.Mutation{ + Operation: &pb.Mutation_Delete{Delete: keyToProto(k)}, + }) + } + set[ks] = true + } + } + if hasErr { + return nil, multiErr + } + return mutations, nil +} + +// Mutate applies one or more mutations atomically. +// It returns the keys of the argument Mutations, in the same order. +// +// If any of the mutations are invalid, Mutate returns a MultiError with the errors. +// Mutate returns a MultiError in this case even if there is only one Mutation. +// See ExampleMultiError to check it. +func (c *Client) Mutate(ctx context.Context, muts ...*Mutation) (ret []*Key, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.Mutate") + defer func() { trace.EndSpan(ctx, err) }() + + pmuts, err := mutationProtos(muts) + if err != nil { + return nil, err + } + req := &pb.CommitRequest{ + ProjectId: c.dataset, + Mutations: pmuts, + Mode: pb.CommitRequest_NON_TRANSACTIONAL, + } + resp, err := c.client.Commit(ctx, req) + if err != nil { + return nil, err + } + // Copy any newly minted keys into the returned keys. + ret = make([]*Key, len(muts)) + for i, mut := range muts { + if mut.key.Incomplete() { + // This key is in the mutation results. + ret[i], err = protoToKey(resp.MutationResults[i].Key) + if err != nil { + return nil, errors.New("datastore: internal error: server returned an invalid key") + } + } else { + ret[i] = mut.key + } + } + return ret, nil +} diff --git a/vendor/cloud.google.com/go/datastore/datastore.replay b/vendor/cloud.google.com/go/datastore/datastore.replay new file mode 100644 index 00000000..25235ecd Binary files /dev/null and b/vendor/cloud.google.com/go/datastore/datastore.replay differ diff --git a/vendor/cloud.google.com/go/datastore/datastore_test.go b/vendor/cloud.google.com/go/datastore/datastore_test.go new file mode 100644 index 00000000..bc805d8f --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/datastore_test.go @@ -0,0 +1,3568 @@ +// Copyright 2014 Google LLC +// +// 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 datastore + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "reflect" + "sort" + "strings" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "github.com/golang/protobuf/proto" + "github.com/google/go-cmp/cmp" + pb "google.golang.org/genproto/googleapis/datastore/v1" + "google.golang.org/grpc" +) + +type ( + myBlob []byte + myByte byte + myString string +) + +func makeMyByteSlice(n int) []myByte { + b := make([]myByte, n) + for i := range b { + b[i] = myByte(i) + } + return b +} + +func makeInt8Slice(n int) []int8 { + b := make([]int8, n) + for i := range b { + b[i] = int8(i) + } + return b +} + +func makeUint8Slice(n int) []uint8 { + b := make([]uint8, n) + for i := range b { + b[i] = uint8(i) + } + return b +} + +func newKey(stringID string, parent *Key) *Key { + return NameKey("kind", stringID, parent) +} + +var ( + testKey0 = newKey("name0", nil) + testKey1a = newKey("name1", nil) + testKey1b = newKey("name1", nil) + testKey2a = newKey("name2", testKey0) + testKey2b = newKey("name2", testKey0) + testGeoPt0 = GeoPoint{Lat: 1.2, Lng: 3.4} + testGeoPt1 = GeoPoint{Lat: 5, Lng: 10} + testBadGeoPt = GeoPoint{Lat: 1000, Lng: 34} + + ts = time.Unix(1e9, 0).UTC() +) + +type B0 struct { + B []byte `datastore:",noindex"` +} + +type B1 struct { + B []int8 +} + +type B2 struct { + B myBlob `datastore:",noindex"` +} + +type B3 struct { + B []myByte `datastore:",noindex"` +} + +type B4 struct { + B [][]byte +} + +type C0 struct { + I int + C chan int +} + +type C1 struct { + I int + C *chan int +} + +type C2 struct { + I int + C []chan int +} + +type C3 struct { + C string +} + +type c4 struct { + C string +} + +type E struct{} + +type G0 struct { + G GeoPoint +} + +type G1 struct { + G []GeoPoint +} + +type K0 struct { + K *Key +} + +type K1 struct { + K []*Key +} + +type S struct { + St string +} + +type NoOmit struct { + A string + B int `datastore:"Bb"` + C bool `datastore:",noindex"` +} + +type OmitAll struct { + A string `datastore:",omitempty"` + B int `datastore:"Bb,omitempty"` + C bool `datastore:",omitempty,noindex"` + D time.Time `datastore:",omitempty"` + F []int `datastore:",omitempty"` +} + +type Omit struct { + A string `datastore:",omitempty"` + B int `datastore:"Bb,omitempty"` + C bool `datastore:",omitempty,noindex"` + D time.Time `datastore:",omitempty"` + F []int `datastore:",omitempty"` + S `datastore:",omitempty"` +} + +type NoOmits struct { + No []NoOmit `datastore:",omitempty"` + S `datastore:",omitempty"` + Ss S `datastore:",omitempty"` +} + +type N0 struct { + X0 + Nonymous X0 + Ignore string `datastore:"-"` + Other string +} + +type N1 struct { + X0 + Nonymous []X0 + Ignore string `datastore:"-"` + Other string +} + +type N2 struct { + N1 `datastore:"red"` + Green N1 `datastore:"green"` + Blue N1 + White N1 `datastore:"-"` +} + +type N3 struct { + C3 `datastore:"red"` +} + +type N4 struct { + c4 +} + +type N5 struct { + c4 `datastore:"red"` +} + +type O0 struct { + I int64 +} + +type O1 struct { + I int32 +} + +type U0 struct { + U uint +} + +type U1 struct { + U string +} + +type T struct { + T time.Time +} + +type X0 struct { + S string + I int + i int +} + +type X1 struct { + S myString + I int32 + J int64 +} + +type X2 struct { + Z string + i int +} + +type X3 struct { + S bool + I int +} + +type Y0 struct { + B bool + F []float64 + G []float64 +} + +type Y1 struct { + B bool + F float64 +} + +type Y2 struct { + B bool + F []int64 +} + +type Pointers struct { + Pi *int + Ps *string + Pb *bool + Pf *float64 + Pg *GeoPoint + Pt *time.Time +} + +type PointersOmitEmpty struct { + Pi *int `datastore:",omitempty"` + Ps *string `datastore:",omitempty"` + Pb *bool `datastore:",omitempty"` + Pf *float64 `datastore:",omitempty"` + Pg *GeoPoint `datastore:",omitempty"` + Pt *time.Time `datastore:",omitempty"` +} + +func populatedPointers() *Pointers { + var ( + i int + s string + b bool + f float64 + g GeoPoint + t time.Time + ) + return &Pointers{ + Pi: &i, + Ps: &s, + Pb: &b, + Pf: &f, + Pg: &g, + Pt: &t, + } +} + +type Tagged struct { + A int `datastore:"a,noindex"` + B []int `datastore:"b"` + C int `datastore:",noindex"` + D int `datastore:""` + E int + I int `datastore:"-"` + J int `datastore:",noindex" json:"j"` + + Y0 `datastore:"-"` + Z chan int `datastore:"-"` +} + +type InvalidTagged1 struct { + I int `datastore:"\t"` +} + +type InvalidTagged2 struct { + I int + J int `datastore:"I"` +} + +type InvalidTagged3 struct { + X string `datastore:"-,noindex"` +} + +type InvalidTagged4 struct { + X string `datastore:",garbage"` +} + +type Inner1 struct { + W int32 + X string +} + +type Inner2 struct { + Y float64 +} + +type Inner3 struct { + Z bool +} + +type Inner5 struct { + WW int +} + +type Inner4 struct { + X Inner5 +} + +type Outer struct { + A int16 + I []Inner1 + J Inner2 + Inner3 +} + +type OuterFlatten struct { + A int16 + I []Inner1 `datastore:",flatten"` + J Inner2 `datastore:",flatten,noindex"` + Inner3 `datastore:",flatten"` + K Inner4 `datastore:",flatten"` +} + +type OuterEquivalent struct { + A int16 + IDotW []int32 `datastore:"I.W"` + IDotX []string `datastore:"I.X"` + JDotY float64 `datastore:"J.Y"` + Z bool +} + +type Dotted struct { + A DottedA `datastore:"A0.A1.A2"` +} + +type DottedA struct { + B DottedB `datastore:"B3"` +} + +type DottedB struct { + C int `datastore:"C4.C5"` +} + +type SliceOfSlices struct { + I int + S []struct { + J int + F []float64 + } `datastore:",flatten"` +} + +type Recursive struct { + I int + R []Recursive +} + +type MutuallyRecursive0 struct { + I int + R []MutuallyRecursive1 +} + +type MutuallyRecursive1 struct { + I int + R []MutuallyRecursive0 +} + +type EntityWithKey struct { + I int + S string + K *Key `datastore:"__key__"` +} + +type EntityWithKey2 EntityWithKey + +type WithNestedEntityWithKey struct { + N EntityWithKey +} + +type WithNonKeyField struct { + I int + K string `datastore:"__key__"` +} + +type NestedWithNonKeyField struct { + N WithNonKeyField +} + +type Basic struct { + A string +} + +type PtrToStructField struct { + B *Basic + C *Basic `datastore:"c,noindex"` + *Basic + D []*Basic +} + +var two = 2 + +type EmbeddedTime struct { + time.Time +} + +type SpecialTime struct { + MyTime EmbeddedTime +} + +type Doubler struct { + S string + I int64 + B bool +} + +type Repeat struct { + Key string + Value []byte +} + +type Repeated struct { + Repeats []Repeat +} + +func (d *Doubler) Load(props []Property) error { + return LoadStruct(d, props) +} + +func (d *Doubler) Save() ([]Property, error) { + // Save the default Property slice to an in-memory buffer (a PropertyList). + props, err := SaveStruct(d) + if err != nil { + return nil, err + } + var list PropertyList + if err := list.Load(props); err != nil { + return nil, err + } + + // Edit that PropertyList, and send it on. + for i := range list { + switch v := list[i].Value.(type) { + case string: + // + means string concatenation. + list[i].Value = v + v + case int64: + // + means integer addition. + list[i].Value = v + v + } + } + return list.Save() +} + +var _ PropertyLoadSaver = (*Doubler)(nil) + +type Deriver struct { + S, Derived, Ignored string +} + +func (e *Deriver) Load(props []Property) error { + for _, p := range props { + if p.Name != "S" { + continue + } + e.S = p.Value.(string) + e.Derived = "derived+" + e.S + } + return nil +} + +func (e *Deriver) Save() ([]Property, error) { + return []Property{ + { + Name: "S", + Value: e.S, + }, + }, nil +} + +var _ PropertyLoadSaver = (*Deriver)(nil) + +type BadMultiPropEntity struct{} + +func (e *BadMultiPropEntity) Load(props []Property) error { + return errors.New("unimplemented") +} + +func (e *BadMultiPropEntity) Save() ([]Property, error) { + // Write multiple properties with the same name "I". + var props []Property + for i := 0; i < 3; i++ { + props = append(props, Property{ + Name: "I", + Value: int64(i), + }) + } + return props, nil +} + +var _ PropertyLoadSaver = (*BadMultiPropEntity)(nil) + +type testCase struct { + desc string + src interface{} + want interface{} + putErr string + getErr string +} + +var testCases = []testCase{ + { + "chan save fails", + &C0{I: -1}, + &E{}, + "unsupported struct field", + "", + }, + { + "*chan save fails", + &C1{I: -1}, + &E{}, + "unsupported struct field", + "", + }, + { + "[]chan save fails", + &C2{I: -1, C: make([]chan int, 8)}, + &E{}, + "unsupported struct field", + "", + }, + { + "chan load fails", + &C3{C: "not a chan"}, + &C0{}, + "", + "type mismatch", + }, + { + "*chan load fails", + &C3{C: "not a *chan"}, + &C1{}, + "", + "type mismatch", + }, + { + "[]chan load fails", + &C3{C: "not a []chan"}, + &C2{}, + "", + "type mismatch", + }, + { + "empty struct", + &E{}, + &E{}, + "", + "", + }, + { + "geopoint", + &G0{G: testGeoPt0}, + &G0{G: testGeoPt0}, + "", + "", + }, + { + "geopoint invalid", + &G0{G: testBadGeoPt}, + &G0{}, + "invalid GeoPoint value", + "", + }, + { + "geopoint as props", + &G0{G: testGeoPt0}, + &PropertyList{ + Property{Name: "G", Value: testGeoPt0, NoIndex: false}, + }, + "", + "", + }, + { + "geopoint slice", + &G1{G: []GeoPoint{testGeoPt0, testGeoPt1}}, + &G1{G: []GeoPoint{testGeoPt0, testGeoPt1}}, + "", + "", + }, + { + "omit empty, all", + &OmitAll{}, + new(PropertyList), + "", + "", + }, + { + "omit empty", + &Omit{}, + &PropertyList{ + Property{Name: "St", Value: "", NoIndex: false}, + }, + "", + "", + }, + { + "omit empty, fields populated", + &Omit{ + A: "a", + B: 10, + C: true, + F: []int{11}, + }, + &PropertyList{ + Property{Name: "A", Value: "a", NoIndex: false}, + Property{Name: "Bb", Value: int64(10), NoIndex: false}, + Property{Name: "C", Value: true, NoIndex: true}, + Property{Name: "F", Value: []interface{}{int64(11)}, NoIndex: false}, + Property{Name: "St", Value: "", NoIndex: false}, + }, + "", + "", + }, + { + "omit empty, fields populated", + &Omit{ + A: "a", + B: 10, + C: true, + F: []int{11}, + S: S{St: "string"}, + }, + &PropertyList{ + Property{Name: "A", Value: "a", NoIndex: false}, + Property{Name: "Bb", Value: int64(10), NoIndex: false}, + Property{Name: "C", Value: true, NoIndex: true}, + Property{Name: "F", Value: []interface{}{int64(11)}, NoIndex: false}, + Property{Name: "St", Value: "string", NoIndex: false}, + }, + "", + "", + }, + { + "omit empty does not propagate", + &NoOmits{ + No: []NoOmit{ + {}, + }, + S: S{}, + Ss: S{}, + }, + &PropertyList{ + Property{Name: "No", Value: []interface{}{ + &Entity{ + Properties: []Property{ + {Name: "A", Value: "", NoIndex: false}, + {Name: "Bb", Value: int64(0), NoIndex: false}, + {Name: "C", Value: false, NoIndex: true}, + }, + }, + }, NoIndex: false}, + Property{Name: "Ss", Value: &Entity{ + Properties: []Property{ + {Name: "St", Value: "", NoIndex: false}, + }, + }, NoIndex: false}, + Property{Name: "St", Value: "", NoIndex: false}, + }, + "", + "", + }, + { + "key", + &K0{K: testKey1a}, + &K0{K: testKey1b}, + "", + "", + }, + { + "key with parent", + &K0{K: testKey2a}, + &K0{K: testKey2b}, + "", + "", + }, + { + "nil key", + &K0{}, + &K0{}, + "", + "", + }, + { + "all nil keys in slice", + &K1{[]*Key{nil, nil}}, + &K1{[]*Key{nil, nil}}, + "", + "", + }, + { + "some nil keys in slice", + &K1{[]*Key{testKey1a, nil, testKey2a}}, + &K1{[]*Key{testKey1b, nil, testKey2b}}, + "", + "", + }, + { + "overflow", + &O0{I: 1 << 48}, + &O1{}, + "", + "overflow", + }, + { + "time", + &T{T: time.Unix(1e9, 0)}, + &T{T: time.Unix(1e9, 0)}, + "", + "", + }, + { + "time as props", + &T{T: time.Unix(1e9, 0)}, + &PropertyList{ + Property{Name: "T", Value: time.Unix(1e9, 0), NoIndex: false}, + }, + "", + "", + }, + { + "uint save", + &U0{U: 1}, + &U0{}, + "unsupported struct field", + "", + }, + { + "uint load", + &U1{U: "not a uint"}, + &U0{}, + "", + "type mismatch", + }, + { + "zero", + &X0{}, + &X0{}, + "", + "", + }, + { + "basic", + &X0{S: "one", I: 2, i: 3}, + &X0{S: "one", I: 2}, + "", + "", + }, + { + "save string/int load myString/int32", + &X0{S: "one", I: 2, i: 3}, + &X1{S: "one", I: 2}, + "", + "", + }, + { + "missing fields", + &X0{S: "one", I: 2, i: 3}, + &X2{}, + "", + "no such struct field", + }, + { + "save string load bool", + &X0{S: "one", I: 2, i: 3}, + &X3{I: 2}, + "", + "type mismatch", + }, + { + "basic slice", + &Y0{B: true, F: []float64{7, 8, 9}}, + &Y0{B: true, F: []float64{7, 8, 9}}, + "", + "", + }, + { + "save []float64 load float64", + &Y0{B: true, F: []float64{7, 8, 9}}, + &Y1{B: true}, + "", + "requires a slice", + }, + { + "save []float64 load []int64", + &Y0{B: true, F: []float64{7, 8, 9}}, + &Y2{B: true}, + "", + "type mismatch", + }, + { + "single slice is too long", + &Y0{F: make([]float64, maxIndexedProperties+1)}, + &Y0{}, + "too many indexed properties", + "", + }, + { + "two slices are too long", + &Y0{F: make([]float64, maxIndexedProperties), G: make([]float64, maxIndexedProperties)}, + &Y0{}, + "too many indexed properties", + "", + }, + { + "one slice and one scalar are too long", + &Y0{F: make([]float64, maxIndexedProperties), B: true}, + &Y0{}, + "too many indexed properties", + "", + }, + { + "slice of slices of bytes", + &Repeated{ + Repeats: []Repeat{ + { + Key: "key 1", + Value: []byte("value 1"), + }, + { + Key: "key 2", + Value: []byte("value 2"), + }, + }, + }, + &Repeated{ + Repeats: []Repeat{ + { + Key: "key 1", + Value: []byte("value 1"), + }, + { + Key: "key 2", + Value: []byte("value 2"), + }, + }, + }, + "", + "", + }, + { + "long blob", + &B0{B: makeUint8Slice(maxIndexedProperties + 1)}, + &B0{B: makeUint8Slice(maxIndexedProperties + 1)}, + "", + "", + }, + { + "long []int8 is too long", + &B1{B: makeInt8Slice(maxIndexedProperties + 1)}, + &B1{}, + "too many indexed properties", + "", + }, + { + "short []int8", + &B1{B: makeInt8Slice(3)}, + &B1{B: makeInt8Slice(3)}, + "", + "", + }, + { + "long myBlob", + &B2{B: makeUint8Slice(maxIndexedProperties + 1)}, + &B2{B: makeUint8Slice(maxIndexedProperties + 1)}, + "", + "", + }, + { + "short myBlob", + &B2{B: makeUint8Slice(3)}, + &B2{B: makeUint8Slice(3)}, + "", + "", + }, + { + "long []myByte", + &B3{B: makeMyByteSlice(maxIndexedProperties + 1)}, + &B3{B: makeMyByteSlice(maxIndexedProperties + 1)}, + "", + "", + }, + { + "short []myByte", + &B3{B: makeMyByteSlice(3)}, + &B3{B: makeMyByteSlice(3)}, + "", + "", + }, + { + "slice of blobs", + &B4{B: [][]byte{ + makeUint8Slice(3), + makeUint8Slice(4), + makeUint8Slice(5), + }}, + &B4{B: [][]byte{ + makeUint8Slice(3), + makeUint8Slice(4), + makeUint8Slice(5), + }}, + "", + "", + }, + { + "[]byte must be noindex", + &PropertyList{ + Property{Name: "B", Value: makeUint8Slice(1501), NoIndex: false}, + }, + nil, + "[]byte property too long to index", + "", + }, + { + "string must be noindex", + &PropertyList{ + Property{Name: "B", Value: strings.Repeat("x", 1501), NoIndex: false}, + }, + nil, + "string property too long to index", + "", + }, + { + "slice of []byte must be noindex", + &PropertyList{ + Property{Name: "B", Value: []interface{}{ + []byte("short"), + makeUint8Slice(1501), + }, NoIndex: false}, + }, + nil, + "[]byte property too long to index", + "", + }, + { + "slice of string must be noindex", + &PropertyList{ + Property{Name: "B", Value: []interface{}{ + "short", + strings.Repeat("x", 1501), + }, NoIndex: false}, + }, + nil, + "string property too long to index", + "", + }, + { + "save tagged load props", + &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, I: 6, J: 7}, + &PropertyList{ + // A and B are renamed to a and b; A and C are noindex, I is ignored. + // Order is sorted as per byName. + Property{Name: "C", Value: int64(3), NoIndex: true}, + Property{Name: "D", Value: int64(4), NoIndex: false}, + Property{Name: "E", Value: int64(5), NoIndex: false}, + Property{Name: "J", Value: int64(7), NoIndex: true}, + Property{Name: "a", Value: int64(1), NoIndex: true}, + Property{Name: "b", Value: []interface{}{int64(21), int64(22), int64(23)}, NoIndex: false}, + }, + "", + "", + }, + { + "save tagged load tagged", + &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, I: 6, J: 7}, + &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, J: 7}, + "", + "", + }, + { + "invalid tagged1", + &InvalidTagged1{I: 1}, + &InvalidTagged1{}, + "struct tag has invalid property name", + "", + }, + { + "invalid tagged2", + &InvalidTagged2{I: 1, J: 2}, + &InvalidTagged2{J: 2}, + "", + "", + }, + { + "invalid tagged3", + &InvalidTagged3{X: "hello"}, + &InvalidTagged3{}, + "struct tag has invalid property name: \"-\"", + "", + }, + { + "invalid tagged4", + &InvalidTagged4{X: "hello"}, + &InvalidTagged4{}, + "struct tag has invalid option: \"garbage\"", + "", + }, + { + "doubler", + &Doubler{S: "s", I: 1, B: true}, + &Doubler{S: "ss", I: 2, B: true}, + "", + "", + }, + { + "save struct load props", + &X0{S: "s", I: 1}, + &PropertyList{ + Property{Name: "I", Value: int64(1), NoIndex: false}, + Property{Name: "S", Value: "s", NoIndex: false}, + }, + "", + "", + }, + { + "save props load struct", + &PropertyList{ + Property{Name: "I", Value: int64(1), NoIndex: false}, + Property{Name: "S", Value: "s", NoIndex: false}, + }, + &X0{S: "s", I: 1}, + "", + "", + }, + { + "nil-value props", + &PropertyList{ + Property{Name: "I", Value: nil, NoIndex: false}, + Property{Name: "B", Value: nil, NoIndex: false}, + Property{Name: "S", Value: nil, NoIndex: false}, + Property{Name: "F", Value: nil, NoIndex: false}, + Property{Name: "K", Value: nil, NoIndex: false}, + Property{Name: "T", Value: nil, NoIndex: false}, + Property{Name: "J", Value: []interface{}{nil, int64(7), nil}, NoIndex: false}, + }, + &struct { + I int64 + B bool + S string + F float64 + K *Key + T time.Time + J []int64 + }{ + J: []int64{0, 7, 0}, + }, + "", + "", + }, + { + "save outer load props flatten", + &OuterFlatten{ + A: 1, + I: []Inner1{ + {10, "ten"}, + {20, "twenty"}, + {30, "thirty"}, + }, + J: Inner2{ + Y: 3.14, + }, + Inner3: Inner3{ + Z: true, + }, + K: Inner4{ + X: Inner5{ + WW: 12, + }, + }, + }, + &PropertyList{ + Property{Name: "A", Value: int64(1), NoIndex: false}, + Property{Name: "I.W", Value: []interface{}{int64(10), int64(20), int64(30)}, NoIndex: false}, + Property{Name: "I.X", Value: []interface{}{"ten", "twenty", "thirty"}, NoIndex: false}, + Property{Name: "J.Y", Value: float64(3.14), NoIndex: true}, + Property{Name: "K.X.WW", Value: int64(12), NoIndex: false}, + Property{Name: "Z", Value: true, NoIndex: false}, + }, + "", + "", + }, + { + "load outer props flatten", + &PropertyList{ + Property{Name: "A", Value: int64(1), NoIndex: false}, + Property{Name: "I.W", Value: []interface{}{int64(10), int64(20), int64(30)}, NoIndex: false}, + Property{Name: "I.X", Value: []interface{}{"ten", "twenty", "thirty"}, NoIndex: false}, + Property{Name: "J.Y", Value: float64(3.14), NoIndex: true}, + Property{Name: "Z", Value: true, NoIndex: false}, + }, + &OuterFlatten{ + A: 1, + I: []Inner1{ + {10, "ten"}, + {20, "twenty"}, + {30, "thirty"}, + }, + J: Inner2{ + Y: 3.14, + }, + Inner3: Inner3{ + Z: true, + }, + }, + "", + "", + }, + { + "save outer load props", + &Outer{ + A: 1, + I: []Inner1{ + {10, "ten"}, + {20, "twenty"}, + {30, "thirty"}, + }, + J: Inner2{ + Y: 3.14, + }, + Inner3: Inner3{ + Z: true, + }, + }, + &PropertyList{ + Property{Name: "A", Value: int64(1), NoIndex: false}, + Property{Name: "I", Value: []interface{}{ + &Entity{ + Properties: []Property{ + {Name: "W", Value: int64(10), NoIndex: false}, + {Name: "X", Value: "ten", NoIndex: false}, + }, + }, + &Entity{ + Properties: []Property{ + {Name: "W", Value: int64(20), NoIndex: false}, + {Name: "X", Value: "twenty", NoIndex: false}, + }, + }, + &Entity{ + Properties: []Property{ + {Name: "W", Value: int64(30), NoIndex: false}, + {Name: "X", Value: "thirty", NoIndex: false}, + }, + }, + }, NoIndex: false}, + Property{Name: "J", Value: &Entity{ + Properties: []Property{ + {Name: "Y", Value: float64(3.14), NoIndex: false}, + }, + }, NoIndex: false}, + Property{Name: "Z", Value: true, NoIndex: false}, + }, + "", + "", + }, + { + "save props load outer-equivalent", + &PropertyList{ + Property{Name: "A", Value: int64(1), NoIndex: false}, + Property{Name: "I.W", Value: []interface{}{int64(10), int64(20), int64(30)}, NoIndex: false}, + Property{Name: "I.X", Value: []interface{}{"ten", "twenty", "thirty"}, NoIndex: false}, + Property{Name: "J.Y", Value: float64(3.14), NoIndex: false}, + Property{Name: "Z", Value: true, NoIndex: false}, + }, + &OuterEquivalent{ + A: 1, + IDotW: []int32{10, 20, 30}, + IDotX: []string{"ten", "twenty", "thirty"}, + JDotY: 3.14, + Z: true, + }, + "", + "", + }, + { + "dotted names save", + &Dotted{A: DottedA{B: DottedB{C: 88}}}, + &PropertyList{ + Property{Name: "A0.A1.A2", Value: &Entity{ + Properties: []Property{ + {Name: "B3", Value: &Entity{ + Properties: []Property{ + {Name: "C4.C5", Value: int64(88), NoIndex: false}, + }, + }, NoIndex: false}, + }, + }, NoIndex: false}, + }, + "", + "", + }, + { + "dotted names load", + &PropertyList{ + Property{Name: "A0.A1.A2", Value: &Entity{ + Properties: []Property{ + {Name: "B3", Value: &Entity{ + Properties: []Property{ + {Name: "C4.C5", Value: 99, NoIndex: false}, + }, + }, NoIndex: false}, + }, + }, NoIndex: false}, + }, + &Dotted{A: DottedA{B: DottedB{C: 99}}}, + "", + "", + }, + { + "save struct load deriver", + &X0{S: "s", I: 1}, + &Deriver{S: "s", Derived: "derived+s"}, + "", + "", + }, + { + "save deriver load struct", + &Deriver{S: "s", Derived: "derived+s", Ignored: "ignored"}, + &X0{S: "s"}, + "", + "", + }, + { + "zero time.Time", + &T{T: time.Time{}}, + &T{T: time.Time{}}, + "", + "", + }, + { + "time.Time near Unix zero time", + &T{T: time.Unix(0, 4e3)}, + &T{T: time.Unix(0, 4e3)}, + "", + "", + }, + { + "time.Time, far in the future", + &T{T: time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC)}, + &T{T: time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC)}, + "", + "", + }, + { + "time.Time, very far in the past", + &T{T: time.Date(-300000, 1, 1, 0, 0, 0, 0, time.UTC)}, + &T{}, + "time value out of range", + "", + }, + { + "time.Time, very far in the future", + &T{T: time.Date(294248, 1, 1, 0, 0, 0, 0, time.UTC)}, + &T{}, + "time value out of range", + "", + }, + { + "structs", + &N0{ + X0: X0{S: "one", I: 2, i: 3}, + Nonymous: X0{S: "four", I: 5, i: 6}, + Ignore: "ignore", + Other: "other", + }, + &N0{ + X0: X0{S: "one", I: 2}, + Nonymous: X0{S: "four", I: 5}, + Other: "other", + }, + "", + "", + }, + { + "slice of structs", + &N1{ + X0: X0{S: "one", I: 2, i: 3}, + Nonymous: []X0{ + {S: "four", I: 5, i: 6}, + {S: "seven", I: 8, i: 9}, + {S: "ten", I: 11, i: 12}, + {S: "thirteen", I: 14, i: 15}, + }, + Ignore: "ignore", + Other: "other", + }, + &N1{ + X0: X0{S: "one", I: 2}, + Nonymous: []X0{ + {S: "four", I: 5}, + {S: "seven", I: 8}, + {S: "ten", I: 11}, + {S: "thirteen", I: 14}, + }, + Other: "other", + }, + "", + "", + }, + { + "structs with slices of structs", + &N2{ + N1: N1{ + X0: X0{S: "rouge"}, + Nonymous: []X0{ + {S: "rosso0"}, + {S: "rosso1"}, + }, + }, + Green: N1{ + X0: X0{S: "vert"}, + Nonymous: []X0{ + {S: "verde0"}, + {S: "verde1"}, + {S: "verde2"}, + }, + }, + Blue: N1{ + X0: X0{S: "bleu"}, + Nonymous: []X0{ + {S: "blu0"}, + {S: "blu1"}, + {S: "blu2"}, + {S: "blu3"}, + }, + }, + }, + &N2{ + N1: N1{ + X0: X0{S: "rouge"}, + Nonymous: []X0{ + {S: "rosso0"}, + {S: "rosso1"}, + }, + }, + Green: N1{ + X0: X0{S: "vert"}, + Nonymous: []X0{ + {S: "verde0"}, + {S: "verde1"}, + {S: "verde2"}, + }, + }, + Blue: N1{ + X0: X0{S: "bleu"}, + Nonymous: []X0{ + {S: "blu0"}, + {S: "blu1"}, + {S: "blu2"}, + {S: "blu3"}, + }, + }, + }, + "", + "", + }, + { + "save structs load props", + &N2{ + N1: N1{ + X0: X0{S: "rouge"}, + Nonymous: []X0{ + {S: "rosso0"}, + {S: "rosso1"}, + }, + }, + Green: N1{ + X0: X0{S: "vert"}, + Nonymous: []X0{ + {S: "verde0"}, + {S: "verde1"}, + {S: "verde2"}, + }, + }, + Blue: N1{ + X0: X0{S: "bleu"}, + Nonymous: []X0{ + {S: "blu0"}, + {S: "blu1"}, + {S: "blu2"}, + {S: "blu3"}, + }, + }, + }, + &PropertyList{ + Property{Name: "Blue", Value: &Entity{ + Properties: []Property{ + {Name: "I", Value: int64(0), NoIndex: false}, + {Name: "Nonymous", Value: []interface{}{ + &Entity{ + Properties: []Property{ + {Name: "I", Value: int64(0), NoIndex: false}, + {Name: "S", Value: "blu0", NoIndex: false}, + }, + }, + &Entity{ + Properties: []Property{ + {Name: "I", Value: int64(0), NoIndex: false}, + {Name: "S", Value: "blu1", NoIndex: false}, + }, + }, + &Entity{ + Properties: []Property{ + {Name: "I", Value: int64(0), NoIndex: false}, + {Name: "S", Value: "blu2", NoIndex: false}, + }, + }, + &Entity{ + Properties: []Property{ + {Name: "I", Value: int64(0), NoIndex: false}, + {Name: "S", Value: "blu3", NoIndex: false}, + }, + }, + }, NoIndex: false}, + {Name: "Other", Value: "", NoIndex: false}, + {Name: "S", Value: "bleu", NoIndex: false}, + }, + }, NoIndex: false}, + Property{Name: "green", Value: &Entity{ + Properties: []Property{ + {Name: "I", Value: int64(0), NoIndex: false}, + {Name: "Nonymous", Value: []interface{}{ + &Entity{ + Properties: []Property{ + {Name: "I", Value: int64(0), NoIndex: false}, + {Name: "S", Value: "verde0", NoIndex: false}, + }, + }, + &Entity{ + Properties: []Property{ + {Name: "I", Value: int64(0), NoIndex: false}, + {Name: "S", Value: "verde1", NoIndex: false}, + }, + }, + &Entity{ + Properties: []Property{ + {Name: "I", Value: int64(0), NoIndex: false}, + {Name: "S", Value: "verde2", NoIndex: false}, + }, + }, + }, NoIndex: false}, + {Name: "Other", Value: "", NoIndex: false}, + {Name: "S", Value: "vert", NoIndex: false}, + }, + }, NoIndex: false}, + Property{Name: "red", Value: &Entity{ + Properties: []Property{ + {Name: "I", Value: int64(0), NoIndex: false}, + {Name: "Nonymous", Value: []interface{}{ + &Entity{ + Properties: []Property{ + {Name: "I", Value: int64(0), NoIndex: false}, + {Name: "S", Value: "rosso0", NoIndex: false}, + }, + }, + &Entity{ + Properties: []Property{ + {Name: "I", Value: int64(0), NoIndex: false}, + {Name: "S", Value: "rosso1", NoIndex: false}, + }, + }, + }, NoIndex: false}, + {Name: "Other", Value: "", NoIndex: false}, + {Name: "S", Value: "rouge", NoIndex: false}, + }, + }, NoIndex: false}, + }, + "", + "", + }, + { + "nested entity with key", + &WithNestedEntityWithKey{ + N: EntityWithKey{ + I: 12, + S: "abcd", + K: testKey0, + }, + }, + &WithNestedEntityWithKey{ + N: EntityWithKey{ + I: 12, + S: "abcd", + K: testKey0, + }, + }, + "", + "", + }, + { + "entity with key at top level", + &EntityWithKey{ + I: 12, + S: "abc", + K: testKey0, + }, + &EntityWithKey{ + I: 12, + S: "abc", + K: testKey0, + }, + "", + "", + }, + { + "entity with key at top level (key is populated on load)", + &EntityWithKey{ + I: 12, + S: "abc", + }, + &EntityWithKey{ + I: 12, + S: "abc", + K: testKey0, + }, + "", + "", + }, + { + "__key__ field not a *Key", + &NestedWithNonKeyField{ + N: WithNonKeyField{ + I: 12, + K: "abcd", + }, + }, + &NestedWithNonKeyField{ + N: WithNonKeyField{ + I: 12, + K: "abcd", + }, + }, + "datastore: __key__ field on struct datastore.WithNonKeyField is not a *datastore.Key", + "", + }, + { + "save struct with ptr to struct fields", + &PtrToStructField{ + &Basic{ + A: "b", + }, + &Basic{ + A: "c", + }, + &Basic{ + A: "anon", + }, + []*Basic{ + { + A: "slice0", + }, + { + A: "slice1", + }, + }, + }, + &PropertyList{ + Property{Name: "A", Value: "anon", NoIndex: false}, + Property{Name: "B", Value: &Entity{ + Properties: []Property{ + {Name: "A", Value: "b", NoIndex: false}, + }, + }}, + Property{Name: "D", Value: []interface{}{ + &Entity{ + Properties: []Property{ + {Name: "A", Value: "slice0", NoIndex: false}, + }, + }, + &Entity{ + Properties: []Property{ + {Name: "A", Value: "slice1", NoIndex: false}, + }, + }, + }, NoIndex: false}, + Property{Name: "c", Value: &Entity{ + Properties: []Property{ + {Name: "A", Value: "c", NoIndex: true}, + }, + }, NoIndex: true}, + }, + "", + "", + }, + { + "save and load struct with ptr to struct fields", + &PtrToStructField{ + &Basic{ + A: "b", + }, + &Basic{ + A: "c", + }, + &Basic{ + A: "anon", + }, + []*Basic{ + { + A: "slice0", + }, + { + A: "slice1", + }, + }, + }, + &PtrToStructField{ + &Basic{ + A: "b", + }, + &Basic{ + A: "c", + }, + &Basic{ + A: "anon", + }, + []*Basic{ + { + A: "slice0", + }, + { + A: "slice1", + }, + }, + }, + "", + "", + }, + { + "struct with nil ptr to struct fields", + &PtrToStructField{ + nil, + nil, + nil, + nil, + }, + new(PropertyList), + "", + "", + }, + { + "nested load entity with key", + &WithNestedEntityWithKey{ + N: EntityWithKey{ + I: 12, + S: "abcd", + K: testKey0, + }, + }, + &PropertyList{ + Property{Name: "N", Value: &Entity{ + Key: testKey0, + Properties: []Property{ + {Name: "I", Value: int64(12), NoIndex: false}, + {Name: "S", Value: "abcd", NoIndex: false}, + }, + }, + NoIndex: false}, + }, + "", + "", + }, + { + "nested save entity with key", + &PropertyList{ + Property{Name: "N", Value: &Entity{ + Key: testKey0, + Properties: []Property{ + {Name: "I", Value: int64(12), NoIndex: false}, + {Name: "S", Value: "abcd", NoIndex: false}, + }, + }, NoIndex: false}, + }, + + &WithNestedEntityWithKey{ + N: EntityWithKey{ + I: 12, + S: "abcd", + K: testKey0, + }, + }, + "", + "", + }, + { + "anonymous field with tag", + &N3{ + C3: C3{C: "s"}, + }, + &PropertyList{ + Property{Name: "red", Value: &Entity{ + Properties: []Property{ + {Name: "C", Value: "s", NoIndex: false}, + }, + }, NoIndex: false}, + }, + "", + "", + }, + { + "unexported anonymous field", + &N4{ + c4: c4{C: "s"}, + }, + &PropertyList{ + Property{Name: "C", Value: "s", NoIndex: false}, + }, + "", + "", + }, + { + "unexported anonymous field with tag", + &N5{ + c4: c4{C: "s"}, + }, + new(PropertyList), + "", + "", + }, + { + "save props load structs with ragged fields", + &PropertyList{ + Property{Name: "red.S", Value: "rot", NoIndex: false}, + Property{Name: "green.Nonymous.I", Value: []interface{}{int64(10), int64(11), int64(12), int64(13)}, NoIndex: false}, + Property{Name: "Blue.Nonymous.I", Value: []interface{}{int64(20), int64(21)}, NoIndex: false}, + Property{Name: "Blue.Nonymous.S", Value: []interface{}{"blau0", "blau1", "blau2"}, NoIndex: false}, + }, + &N2{ + N1: N1{ + X0: X0{S: "rot"}, + }, + Green: N1{ + Nonymous: []X0{ + {I: 10}, + {I: 11}, + {I: 12}, + {I: 13}, + }, + }, + Blue: N1{ + Nonymous: []X0{ + {S: "blau0", I: 20}, + {S: "blau1", I: 21}, + {S: "blau2"}, + }, + }, + }, + "", + "", + }, + { + "save structs with noindex tags", + &struct { + A struct { + X string `datastore:",noindex"` + Y string + } `datastore:",noindex"` + B struct { + X string `datastore:",noindex"` + Y string + } + }{}, + &PropertyList{ + Property{Name: "A", Value: &Entity{ + Properties: []Property{ + {Name: "X", Value: "", NoIndex: true}, + {Name: "Y", Value: "", NoIndex: true}, + }, + }, NoIndex: true}, + Property{Name: "B", Value: &Entity{ + Properties: []Property{ + {Name: "X", Value: "", NoIndex: true}, + {Name: "Y", Value: "", NoIndex: false}, + }, + }, NoIndex: false}, + }, + "", + "", + }, + { + "embedded struct with name override", + &struct { + Inner1 `datastore:"foo"` + }{}, + &PropertyList{ + Property{Name: "foo", Value: &Entity{ + Properties: []Property{ + {Name: "W", Value: int64(0), NoIndex: false}, + {Name: "X", Value: "", NoIndex: false}, + }, + }, NoIndex: false}, + }, + "", + "", + }, + { + "slice of slices", + &SliceOfSlices{}, + nil, + "flattening nested structs leads to a slice of slices", + "", + }, + { + "recursive struct", + &Recursive{}, + &Recursive{}, + "", + "", + }, + { + "mutually recursive struct", + &MutuallyRecursive0{}, + &MutuallyRecursive0{}, + "", + "", + }, + { + "non-exported struct fields", + &struct { + i, J int64 + }{i: 1, J: 2}, + &PropertyList{ + Property{Name: "J", Value: int64(2), NoIndex: false}, + }, + "", + "", + }, + { + "json.RawMessage", + &struct { + J json.RawMessage + }{ + J: json.RawMessage("rawr"), + }, + &PropertyList{ + Property{Name: "J", Value: []byte("rawr"), NoIndex: false}, + }, + "", + "", + }, + { + "json.RawMessage to myBlob", + &struct { + B json.RawMessage + }{ + B: json.RawMessage("rawr"), + }, + &B2{B: myBlob("rawr")}, + "", + "", + }, + { + "repeated property names", + &PropertyList{ + Property{Name: "A", Value: ""}, + Property{Name: "A", Value: ""}, + }, + nil, + "duplicate Property", + "", + }, + { + "embedded time field", + &SpecialTime{MyTime: EmbeddedTime{ts}}, + &SpecialTime{MyTime: EmbeddedTime{ts}}, + "", + "", + }, + { + "embedded time load", + &PropertyList{ + Property{Name: "MyTime.Time", Value: ts}, + }, + &SpecialTime{MyTime: EmbeddedTime{ts}}, + "", + "", + }, + { + "pointer fields: nil", + &Pointers{}, + &Pointers{}, + "", + "", + }, + { + "pointer fields: populated with zeroes", + populatedPointers(), + populatedPointers(), + "", + "", + }, +} + +// checkErr returns the empty string if either both want and err are zero, +// or if want is a non-empty substring of err's string representation. +func checkErr(want string, err error) string { + if err != nil { + got := err.Error() + if want == "" || strings.Index(got, want) == -1 { + return got + } + } else if want != "" { + return fmt.Sprintf("want error %q", want) + } + return "" +} + +func TestRoundTrip(t *testing.T) { + for _, tc := range testCases { + p, err := saveEntity(testKey0, tc.src) + if s := checkErr(tc.putErr, err); s != "" { + t.Errorf("%s: save: %s", tc.desc, s) + continue + } + if p == nil { + continue + } + var got interface{} + if _, ok := tc.want.(*PropertyList); ok { + got = new(PropertyList) + } else { + got = reflect.New(reflect.TypeOf(tc.want).Elem()).Interface() + } + err = loadEntityProto(got, p) + if s := checkErr(tc.getErr, err); s != "" { + t.Errorf("%s: load: %s", tc.desc, s) + continue + } + if pl, ok := got.(*PropertyList); ok { + // Sort by name to make sure we have a deterministic order. + sortPL(*pl) + } + + if !testutil.Equal(got, tc.want, cmp.AllowUnexported(X0{}, X2{})) { + t.Errorf("%s: compare:\ngot: %+#v\nwant: %+#v", tc.desc, got, tc.want) + continue + } + } +} + +type aPtrPLS struct { + Count int +} + +func (pls *aPtrPLS) Load([]Property) error { + pls.Count++ + return nil +} + +func (pls *aPtrPLS) Save() ([]Property, error) { + return []Property{{Name: "Count", Value: 4}}, nil +} + +type aValuePLS struct { + Count int +} + +func (pls aValuePLS) Load([]Property) error { + pls.Count += 2 + return nil +} + +func (pls aValuePLS) Save() ([]Property, error) { + return []Property{{Name: "Count", Value: 8}}, nil +} + +type aValuePtrPLS struct { + Count int +} + +func (pls *aValuePtrPLS) Load([]Property) error { + pls.Count = 11 + return nil +} + +func (pls *aValuePtrPLS) Save() ([]Property, error) { + return []Property{{Name: "Count", Value: 12}}, nil +} + +type aNotPLS struct { + Count int +} + +type plsString string + +func (s *plsString) Load([]Property) error { + *s = "LOADED" + return nil +} + +func (s *plsString) Save() ([]Property, error) { + return []Property{{Name: "SS", Value: "SAVED"}}, nil +} + +func ptrToplsString(s string) *plsString { + plsStr := plsString(s) + return &plsStr +} + +type aSubPLS struct { + Foo string + Bar *aPtrPLS + Baz aValuePtrPLS + S plsString +} + +type aSubNotPLS struct { + Foo string + Bar *aNotPLS +} + +type aSubPLSErr struct { + Foo string + Bar aValuePLS +} + +type aSubPLSNoErr struct { + Foo string + Bar aPtrPLS +} + +type GrandparentFlatten struct { + Parent Parent `datastore:",flatten"` +} + +type GrandparentOfPtrFlatten struct { + Parent ParentOfPtr `datastore:",flatten"` +} + +type GrandparentOfSlice struct { + Parent ParentOfSlice +} + +type GrandparentOfSlicePtrs struct { + Parent ParentOfSlicePtrs +} + +type GrandparentOfSliceFlatten struct { + Parent ParentOfSlice `datastore:",flatten"` +} + +type GrandparentOfSlicePtrsFlatten struct { + Parent ParentOfSlicePtrs `datastore:",flatten"` +} + +type Grandparent struct { + Parent Parent +} + +type Parent struct { + Child Child + String plsString +} + +type ParentOfPtr struct { + Child *Child + String *plsString +} + +type ParentOfSlice struct { + Children []Child + Strings []plsString +} + +type ParentOfSlicePtrs struct { + Children []*Child + Strings []*plsString +} + +type Child struct { + I int + Grandchild Grandchild +} + +type Grandchild struct { + S string +} + +func (c *Child) Load(props []Property) error { + for _, p := range props { + if p.Name == "I" { + c.I++ + } else if p.Name == "Grandchild.S" { + c.Grandchild.S = "grandchild loaded" + } + } + + return nil +} + +func (c *Child) Save() ([]Property, error) { + v := c.I + 1 + return []Property{ + {Name: "I", Value: v}, + {Name: "Grandchild.S", Value: fmt.Sprintf("grandchild saved %d", v)}, + }, nil +} + +func TestLoadSavePLS(t *testing.T) { + type testCase struct { + desc string + src interface{} + wantSave *pb.Entity + wantLoad interface{} + saveErr string + loadErr string + } + + testCases := []testCase{ + { + desc: "non-struct implements PLS (top-level)", + src: ptrToplsString("hello"), + wantSave: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "SS": {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + }, + }, + wantLoad: ptrToplsString("LOADED"), + }, + { + desc: "substructs do implement PLS", + src: &aSubPLS{Foo: "foo", Bar: &aPtrPLS{Count: 2}, Baz: aValuePtrPLS{Count: 15}, S: "something"}, + wantSave: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Foo": {ValueType: &pb.Value_StringValue{StringValue: "foo"}}, + "Bar": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "Count": {ValueType: &pb.Value_IntegerValue{IntegerValue: 4}}, + }, + }, + }}, + "Baz": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "Count": {ValueType: &pb.Value_IntegerValue{IntegerValue: 12}}, + }, + }, + }}, + "S": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "SS": {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + }, + }, + }}, + }, + }, + wantLoad: &aSubPLS{Foo: "foo", Bar: &aPtrPLS{Count: 1}, Baz: aValuePtrPLS{Count: 11}, S: "LOADED"}, + }, + { + desc: "substruct (ptr) does implement PLS, nil valued substruct", + src: &aSubPLS{Foo: "foo", S: "something"}, + wantSave: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Foo": {ValueType: &pb.Value_StringValue{StringValue: "foo"}}, + "Baz": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "Count": {ValueType: &pb.Value_IntegerValue{IntegerValue: 12}}, + }, + }, + }}, + "S": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "SS": {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + }, + }, + }}, + }, + }, + wantLoad: &aSubPLS{Foo: "foo", Baz: aValuePtrPLS{Count: 11}, S: "LOADED"}, + }, + { + desc: "substruct (ptr) does not implement PLS", + src: &aSubNotPLS{Foo: "foo", Bar: &aNotPLS{Count: 2}}, + wantSave: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Foo": {ValueType: &pb.Value_StringValue{StringValue: "foo"}}, + "Bar": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "Count": {ValueType: &pb.Value_IntegerValue{IntegerValue: 2}}, + }, + }, + }}, + }, + }, + wantLoad: &aSubNotPLS{Foo: "foo", Bar: &aNotPLS{Count: 2}}, + }, + { + desc: "substruct (value) does implement PLS, error on save", + src: &aSubPLSErr{Foo: "foo", Bar: aValuePLS{Count: 2}}, + wantSave: (*pb.Entity)(nil), + wantLoad: &aSubPLSErr{}, + saveErr: "PropertyLoadSaver methods must be implemented on a pointer", + }, + { + desc: "substruct (value) does implement PLS, error on load", + src: &aSubPLSNoErr{Foo: "foo", Bar: aPtrPLS{Count: 2}}, + wantSave: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Foo": {ValueType: &pb.Value_StringValue{StringValue: "foo"}}, + "Bar": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "Count": {ValueType: &pb.Value_IntegerValue{IntegerValue: 4}}, + }, + }, + }}, + }, + }, + wantLoad: &aSubPLSErr{}, + loadErr: "PropertyLoadSaver methods must be implemented on a pointer", + }, + + { + desc: "parent does not have flatten option, child impl PLS", + src: &Grandparent{ + Parent: Parent{ + Child: Child{ + I: 9, + Grandchild: Grandchild{ + S: "BAD", + }, + }, + String: plsString("something"), + }, + }, + wantSave: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Parent": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "Child": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 10}}, + "Grandchild.S": {ValueType: &pb.Value_StringValue{StringValue: "grandchild saved 10"}}, + }, + }, + }}, + "String": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "SS": {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + }, + }, + }}, + }, + }, + }}, + }, + }, + wantLoad: &Grandparent{ + Parent: Parent{ + Child: Child{ + I: 1, + Grandchild: Grandchild{ + S: "grandchild loaded", + }, + }, + String: "LOADED", + }, + }, + }, + { + desc: "parent has flatten option enabled, child impl PLS", + src: &GrandparentFlatten{ + Parent: Parent{ + Child: Child{ + I: 7, + Grandchild: Grandchild{ + S: "BAD", + }, + }, + String: plsString("something"), + }, + }, + wantSave: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Parent.Child.I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 8}}, + "Parent.Child.Grandchild.S": {ValueType: &pb.Value_StringValue{StringValue: "grandchild saved 8"}}, + "Parent.String.SS": {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + }, + }, + wantLoad: &GrandparentFlatten{ + Parent: Parent{ + Child: Child{ + I: 1, + Grandchild: Grandchild{ + S: "grandchild loaded", + }, + }, + String: "LOADED", + }, + }, + }, + + { + desc: "parent has flatten option enabled, child (ptr to) impl PLS", + src: &GrandparentOfPtrFlatten{ + Parent: ParentOfPtr{ + Child: &Child{ + I: 7, + Grandchild: Grandchild{ + S: "BAD", + }, + }, + String: ptrToplsString("something"), + }, + }, + wantSave: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Parent.Child.I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 8}}, + "Parent.Child.Grandchild.S": {ValueType: &pb.Value_StringValue{StringValue: "grandchild saved 8"}}, + "Parent.String.SS": {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + }, + }, + wantLoad: &GrandparentOfPtrFlatten{ + Parent: ParentOfPtr{ + Child: &Child{ + I: 1, + Grandchild: Grandchild{ + S: "grandchild loaded", + }, + }, + String: ptrToplsString("LOADED"), + }, + }, + }, + { + desc: "children (slice of) impl PLS", + src: &GrandparentOfSlice{ + Parent: ParentOfSlice{ + Children: []Child{ + { + I: 7, + Grandchild: Grandchild{ + S: "BAD", + }, + }, + { + I: 9, + Grandchild: Grandchild{ + S: "BAD2", + }, + }, + }, + Strings: []plsString{ + "something1", + "something2", + }, + }, + }, + wantSave: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Parent": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "Children": {ValueType: &pb.Value_ArrayValue{ + ArrayValue: &pb.ArrayValue{Values: []*pb.Value{ + {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 8}}, + "Grandchild.S": {ValueType: &pb.Value_StringValue{StringValue: "grandchild saved 8"}}, + }, + }, + }}, + {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 10}}, + "Grandchild.S": {ValueType: &pb.Value_StringValue{StringValue: "grandchild saved 10"}}, + }, + }, + }}, + }}, + }}, + "Strings": {ValueType: &pb.Value_ArrayValue{ + ArrayValue: &pb.ArrayValue{Values: []*pb.Value{ + {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "SS": {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + }, + }, + }}, + {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "SS": {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + }, + }, + }}, + }}, + }}, + }, + }, + }}, + }, + }, + wantLoad: &GrandparentOfSlice{ + Parent: ParentOfSlice{ + Children: []Child{ + { + I: 1, + Grandchild: Grandchild{ + S: "grandchild loaded", + }, + }, + { + I: 1, + Grandchild: Grandchild{ + S: "grandchild loaded", + }, + }, + }, + Strings: []plsString{ + "LOADED", + "LOADED", + }, + }, + }, + }, + { + desc: "children (slice of ptrs) impl PLS", + src: &GrandparentOfSlicePtrs{ + Parent: ParentOfSlicePtrs{ + Children: []*Child{ + { + I: 7, + Grandchild: Grandchild{ + S: "BAD", + }, + }, + { + I: 9, + Grandchild: Grandchild{ + S: "BAD2", + }, + }, + }, + Strings: []*plsString{ + ptrToplsString("something1"), + ptrToplsString("something2"), + }, + }, + }, + wantSave: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Parent": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "Children": {ValueType: &pb.Value_ArrayValue{ + ArrayValue: &pb.ArrayValue{Values: []*pb.Value{ + {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 8}}, + "Grandchild.S": {ValueType: &pb.Value_StringValue{StringValue: "grandchild saved 8"}}, + }, + }, + }}, + {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 10}}, + "Grandchild.S": {ValueType: &pb.Value_StringValue{StringValue: "grandchild saved 10"}}, + }, + }, + }}, + }}, + }}, + "Strings": {ValueType: &pb.Value_ArrayValue{ + ArrayValue: &pb.ArrayValue{Values: []*pb.Value{ + {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "SS": {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + }, + }, + }}, + {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "SS": {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + }, + }, + }}, + }}, + }}, + }, + }, + }}, + }, + }, + wantLoad: &GrandparentOfSlicePtrs{ + Parent: ParentOfSlicePtrs{ + Children: []*Child{ + { + I: 1, + Grandchild: Grandchild{ + S: "grandchild loaded", + }, + }, + { + I: 1, + Grandchild: Grandchild{ + S: "grandchild loaded", + }, + }, + }, + Strings: []*plsString{ + ptrToplsString("LOADED"), + ptrToplsString("LOADED"), + }, + }, + }, + }, + { + desc: "parent has flatten option, children (slice of) impl PLS", + src: &GrandparentOfSliceFlatten{ + Parent: ParentOfSlice{ + Children: []Child{ + { + I: 7, + Grandchild: Grandchild{ + S: "BAD", + }, + }, + { + I: 9, + Grandchild: Grandchild{ + S: "BAD2", + }, + }, + }, + Strings: []plsString{ + "something1", + "something2", + }, + }, + }, + wantSave: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Parent.Children.I": {ValueType: &pb.Value_ArrayValue{ArrayValue: &pb.ArrayValue{ + Values: []*pb.Value{ + {ValueType: &pb.Value_IntegerValue{IntegerValue: 8}}, + {ValueType: &pb.Value_IntegerValue{IntegerValue: 10}}, + }, + }, + }}, + "Parent.Children.Grandchild.S": {ValueType: &pb.Value_ArrayValue{ArrayValue: &pb.ArrayValue{ + Values: []*pb.Value{ + {ValueType: &pb.Value_StringValue{StringValue: "grandchild saved 8"}}, + {ValueType: &pb.Value_StringValue{StringValue: "grandchild saved 10"}}, + }, + }, + }}, + "Parent.Strings.SS": {ValueType: &pb.Value_ArrayValue{ArrayValue: &pb.ArrayValue{ + Values: []*pb.Value{ + {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + }, + }, + }}, + }, + }, + wantLoad: &GrandparentOfSliceFlatten{ + Parent: ParentOfSlice{ + Children: []Child{ + { + I: 1, + Grandchild: Grandchild{ + S: "grandchild loaded", + }, + }, + { + I: 1, + Grandchild: Grandchild{ + S: "grandchild loaded", + }, + }, + }, + Strings: []plsString{ + "LOADED", + "LOADED", + }, + }, + }, + }, + { + desc: "parent has flatten option, children (slice of ptrs) impl PLS", + src: &GrandparentOfSlicePtrsFlatten{ + Parent: ParentOfSlicePtrs{ + Children: []*Child{ + { + I: 7, + Grandchild: Grandchild{ + S: "BAD", + }, + }, + { + I: 9, + Grandchild: Grandchild{ + S: "BAD2", + }, + }, + }, + Strings: []*plsString{ + ptrToplsString("something1"), + ptrToplsString("something1"), + }, + }, + }, + wantSave: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Parent.Children.I": {ValueType: &pb.Value_ArrayValue{ArrayValue: &pb.ArrayValue{ + Values: []*pb.Value{ + {ValueType: &pb.Value_IntegerValue{IntegerValue: 8}}, + {ValueType: &pb.Value_IntegerValue{IntegerValue: 10}}, + }, + }, + }}, + "Parent.Children.Grandchild.S": {ValueType: &pb.Value_ArrayValue{ArrayValue: &pb.ArrayValue{ + Values: []*pb.Value{ + {ValueType: &pb.Value_StringValue{StringValue: "grandchild saved 8"}}, + {ValueType: &pb.Value_StringValue{StringValue: "grandchild saved 10"}}, + }, + }, + }}, + "Parent.Strings.SS": {ValueType: &pb.Value_ArrayValue{ArrayValue: &pb.ArrayValue{ + Values: []*pb.Value{ + {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + {ValueType: &pb.Value_StringValue{StringValue: "SAVED"}}, + }, + }, + }}, + }, + }, + wantLoad: &GrandparentOfSlicePtrsFlatten{ + Parent: ParentOfSlicePtrs{ + Children: []*Child{ + { + I: 1, + Grandchild: Grandchild{ + S: "grandchild loaded", + }, + }, + { + I: 1, + Grandchild: Grandchild{ + S: "grandchild loaded", + }, + }, + }, + Strings: []*plsString{ + ptrToplsString("LOADED"), + ptrToplsString("LOADED"), + }, + }, + }, + }, + } + + for _, tc := range testCases { + e, err := saveEntity(testKey0, tc.src) + if tc.saveErr == "" { // Want no error. + if err != nil { + t.Errorf("%s: save: %v", tc.desc, err) + continue + } + if !testutil.Equal(e, tc.wantSave) { + t.Errorf("%s: save: \ngot: %+v\nwant: %+v", tc.desc, e, tc.wantSave) + continue + } + } else { // Want error. + if err == nil { + t.Errorf("%s: save: want err", tc.desc) + continue + } + if !strings.Contains(err.Error(), tc.saveErr) { + t.Errorf("%s: save: \ngot err '%s'\nwant err '%s'", tc.desc, err.Error(), tc.saveErr) + } + continue + } + + gota := reflect.New(reflect.TypeOf(tc.wantLoad).Elem()).Interface() + err = loadEntityProto(gota, e) + if tc.loadErr == "" { // Want no error. + if err != nil { + t.Errorf("%s: load: %v", tc.desc, err) + continue + } + if !testutil.Equal(gota, tc.wantLoad) { + t.Errorf("%s: load: \ngot: %+v\nwant: %+v", tc.desc, gota, tc.wantLoad) + continue + } + } else { // Want error. + if err == nil { + t.Errorf("%s: load: want err", tc.desc) + continue + } + if !strings.Contains(err.Error(), tc.loadErr) { + t.Errorf("%s: load: \ngot err '%s'\nwant err '%s'", tc.desc, err.Error(), tc.loadErr) + } + } + } +} + +func TestQueryConstruction(t *testing.T) { + tests := []struct { + q, exp *Query + err string + }{ + { + q: NewQuery("Foo"), + exp: &Query{ + kind: "Foo", + limit: -1, + }, + }, + { + // Regular filtered query with standard spacing. + q: NewQuery("Foo").Filter("foo >", 7), + exp: &Query{ + kind: "Foo", + filter: []filter{ + { + FieldName: "foo", + Op: greaterThan, + Value: 7, + }, + }, + limit: -1, + }, + }, + { + // Filtered query with no spacing. + q: NewQuery("Foo").Filter("foo=", 6), + exp: &Query{ + kind: "Foo", + filter: []filter{ + { + FieldName: "foo", + Op: equal, + Value: 6, + }, + }, + limit: -1, + }, + }, + { + // Filtered query with funky spacing. + q: NewQuery("Foo").Filter(" foo< ", 8), + exp: &Query{ + kind: "Foo", + filter: []filter{ + { + FieldName: "foo", + Op: lessThan, + Value: 8, + }, + }, + limit: -1, + }, + }, + { + // Filtered query with multicharacter op. + q: NewQuery("Foo").Filter("foo >=", 9), + exp: &Query{ + kind: "Foo", + filter: []filter{ + { + FieldName: "foo", + Op: greaterEq, + Value: 9, + }, + }, + limit: -1, + }, + }, + { + // Query with ordering. + q: NewQuery("Foo").Order("bar"), + exp: &Query{ + kind: "Foo", + order: []order{ + { + FieldName: "bar", + Direction: ascending, + }, + }, + limit: -1, + }, + }, + { + // Query with reverse ordering, and funky spacing. + q: NewQuery("Foo").Order(" - bar"), + exp: &Query{ + kind: "Foo", + order: []order{ + { + FieldName: "bar", + Direction: descending, + }, + }, + limit: -1, + }, + }, + { + // Query with an empty ordering. + q: NewQuery("Foo").Order(""), + err: "empty order", + }, + { + // Query with a + ordering. + q: NewQuery("Foo").Order("+bar"), + err: "invalid order", + }, + } + for i, test := range tests { + if test.q.err != nil { + got := test.q.err.Error() + if !strings.Contains(got, test.err) { + t.Errorf("%d: error mismatch: got %q want something containing %q", i, got, test.err) + } + continue + } + if !testutil.Equal(test.q, test.exp, cmp.AllowUnexported(Query{})) { + t.Errorf("%d: mismatch: got %v want %v", i, test.q, test.exp) + } + } +} + +func TestPutMultiTypes(t *testing.T) { + ctx := context.Background() + type S struct { + A int + B string + } + + testCases := []struct { + desc string + src interface{} + wantErr bool + }{ + // Test cases to check each of the valid input types for src. + // Each case has the same elements. + { + desc: "type []struct", + src: []S{ + {1, "one"}, {2, "two"}, + }, + }, + { + desc: "type []*struct", + src: []*S{ + {1, "one"}, {2, "two"}, + }, + }, + { + desc: "type []interface{} with PLS elems", + src: []interface{}{ + &PropertyList{Property{Name: "A", Value: 1}, Property{Name: "B", Value: "one"}}, + &PropertyList{Property{Name: "A", Value: 2}, Property{Name: "B", Value: "two"}}, + }, + }, + { + desc: "type []interface{} with struct ptr elems", + src: []interface{}{ + &S{1, "one"}, &S{2, "two"}, + }, + }, + { + desc: "type []PropertyLoadSaver{}", + src: []PropertyLoadSaver{ + &PropertyList{Property{Name: "A", Value: 1}, Property{Name: "B", Value: "one"}}, + &PropertyList{Property{Name: "A", Value: 2}, Property{Name: "B", Value: "two"}}, + }, + }, + { + desc: "type []P (non-pointer, *P implements PropertyLoadSaver)", + src: []PropertyList{ + {Property{Name: "A", Value: 1}, Property{Name: "B", Value: "one"}}, + {Property{Name: "A", Value: 2}, Property{Name: "B", Value: "two"}}, + }, + }, + // Test some invalid cases. + { + desc: "type []interface{} with struct elems", + src: []interface{}{ + S{1, "one"}, S{2, "two"}, + }, + wantErr: true, + }, + { + desc: "PropertyList", + src: PropertyList{ + Property{Name: "A", Value: 1}, + Property{Name: "B", Value: "one"}, + }, + wantErr: true, + }, + { + desc: "type []int", + src: []int{1, 2}, + wantErr: true, + }, + { + desc: "not a slice", + src: S{1, "one"}, + wantErr: true, + }, + } + + // Use the same keys and expected entities for all tests. + keys := []*Key{ + NameKey("testKind", "first", nil), + NameKey("testKind", "second", nil), + } + want := []*pb.Mutation{ + {Operation: &pb.Mutation_Upsert{ + Upsert: &pb.Entity{ + Key: keyToProto(keys[0]), + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_IntegerValue{IntegerValue: 1}}, + "B": {ValueType: &pb.Value_StringValue{StringValue: "one"}}, + }, + }}}, + {Operation: &pb.Mutation_Upsert{ + Upsert: &pb.Entity{ + Key: keyToProto(keys[1]), + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_IntegerValue{IntegerValue: 2}}, + "B": {ValueType: &pb.Value_StringValue{StringValue: "two"}}, + }, + }}}, + } + + for _, tt := range testCases { + // Set up a fake client which captures upserts. + var got []*pb.Mutation + client := &Client{ + client: &fakeClient{ + commitFn: func(req *pb.CommitRequest) (*pb.CommitResponse, error) { + got = req.Mutations + return &pb.CommitResponse{}, nil + }, + }, + } + + _, err := client.PutMulti(ctx, keys, tt.src) + if err != nil { + if !tt.wantErr { + t.Errorf("%s: error %v", tt.desc, err) + } + continue + } + if tt.wantErr { + t.Errorf("%s: wanted error, but none returned", tt.desc) + continue + } + if len(got) != len(want) { + t.Errorf("%s: got %d entities, want %d", tt.desc, len(got), len(want)) + continue + } + for i, e := range got { + if !proto.Equal(e, want[i]) { + t.Logf("%s: entity %d doesn't match\ngot: %v\nwant: %v", tt.desc, i, e, want[i]) + } + } + } +} + +func TestNoIndexOnSliceProperties(t *testing.T) { + // Check that ExcludeFromIndexes is set on the inner elements, + // rather than the top-level ArrayValue value. + pl := PropertyList{ + Property{ + Name: "repeated", + Value: []interface{}{ + 123, + false, + "short", + strings.Repeat("a", 1503), + }, + NoIndex: true, + }, + } + key := NameKey("dummy", "dummy", nil) + + entity, err := saveEntity(key, &pl) + if err != nil { + t.Fatalf("saveEntity: %v", err) + } + + want := &pb.Value{ + ValueType: &pb.Value_ArrayValue{ArrayValue: &pb.ArrayValue{Values: []*pb.Value{ + {ValueType: &pb.Value_IntegerValue{IntegerValue: 123}, ExcludeFromIndexes: true}, + {ValueType: &pb.Value_BooleanValue{BooleanValue: false}, ExcludeFromIndexes: true}, + {ValueType: &pb.Value_StringValue{StringValue: "short"}, ExcludeFromIndexes: true}, + {ValueType: &pb.Value_StringValue{StringValue: strings.Repeat("a", 1503)}, ExcludeFromIndexes: true}, + }}}, + } + if got := entity.Properties["repeated"]; !proto.Equal(got, want) { + t.Errorf("Entity proto differs\ngot: %v\nwant: %v", got, want) + } +} + +type byName PropertyList + +func (s byName) Len() int { return len(s) } +func (s byName) Less(i, j int) bool { return s[i].Name < s[j].Name } +func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +// sortPL sorts the property list by property name, and +// recursively sorts any nested property lists, or nested slices of +// property lists. +func sortPL(pl PropertyList) { + sort.Stable(byName(pl)) + for _, p := range pl { + switch p.Value.(type) { + case *Entity: + sortPL(p.Value.(*Entity).Properties) + case []interface{}: + for _, p2 := range p.Value.([]interface{}) { + if nent, ok := p2.(*Entity); ok { + sortPL(nent.Properties) + } + } + } + } +} + +func TestValidGeoPoint(t *testing.T) { + testCases := []struct { + desc string + pt GeoPoint + want bool + }{ + { + "valid", + GeoPoint{67.21, 13.37}, + true, + }, + { + "high lat", + GeoPoint{-90.01, 13.37}, + false, + }, + { + "low lat", + GeoPoint{90.01, 13.37}, + false, + }, + { + "high lng", + GeoPoint{67.21, 182}, + false, + }, + { + "low lng", + GeoPoint{67.21, -181}, + false, + }, + } + + for _, tc := range testCases { + if got := tc.pt.Valid(); got != tc.want { + t.Errorf("%s: got %v, want %v", tc.desc, got, tc.want) + } + } +} + +func TestPutInvalidEntity(t *testing.T) { + // Test that trying to put an invalid entity always returns the correct error + // type. + + // Fake client that can pretend to start a transaction. + fakeClient := &fakeDatastoreClient{ + beginTransaction: func(*pb.BeginTransactionRequest) (*pb.BeginTransactionResponse, error) { + return &pb.BeginTransactionResponse{ + Transaction: []byte("deadbeef"), + }, nil + }, + } + client := &Client{ + client: fakeClient, + } + + ctx := context.Background() + key := IncompleteKey("kind", nil) + + _, err := client.Put(ctx, key, "invalid entity") + if err != ErrInvalidEntityType { + t.Errorf("client.Put returned err %v, want %v", err, ErrInvalidEntityType) + } + + _, err = client.PutMulti(ctx, []*Key{key}, []interface{}{"invalid entity"}) + if me, ok := err.(MultiError); !ok { + t.Errorf("client.PutMulti returned err %v, want MultiError type", err) + } else if len(me) != 1 || me[0] != ErrInvalidEntityType { + t.Errorf("client.PutMulti returned err %v, want MulitError{ErrInvalidEntityType}", err) + } + + client.RunInTransaction(ctx, func(tx *Transaction) error { + _, err := tx.Put(key, "invalid entity") + if err != ErrInvalidEntityType { + t.Errorf("tx.Put returned err %v, want %v", err, ErrInvalidEntityType) + } + + _, err = tx.PutMulti([]*Key{key}, []interface{}{"invalid entity"}) + if me, ok := err.(MultiError); !ok { + t.Errorf("tx.PutMulti returned err %v, want MultiError type", err) + } else if len(me) != 1 || me[0] != ErrInvalidEntityType { + t.Errorf("tx.PutMulti returned err %v, want MulitError{ErrInvalidEntityType}", err) + } + + return errors.New("bang") // Return error: we don't actually want to commit. + }) +} + +func TestDeferred(t *testing.T) { + type Ent struct { + A int + B string + } + + keys := []*Key{ + NameKey("testKind", "first", nil), + NameKey("testKind", "second", nil), + } + + entity1 := &pb.Entity{ + Key: keyToProto(keys[0]), + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_IntegerValue{IntegerValue: 1}}, + "B": {ValueType: &pb.Value_StringValue{StringValue: "one"}}, + }, + } + entity2 := &pb.Entity{ + Key: keyToProto(keys[1]), + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_IntegerValue{IntegerValue: 2}}, + "B": {ValueType: &pb.Value_StringValue{StringValue: "two"}}, + }, + } + + // count keeps track of the number of times fakeClient.lookup has been + // called. + var count int + // Fake client that will return Deferred keys in resp on the first call. + fakeClient := &fakeDatastoreClient{ + lookup: func(*pb.LookupRequest) (*pb.LookupResponse, error) { + count++ + // On the first call, we return deferred keys. + if count == 1 { + return &pb.LookupResponse{ + Found: []*pb.EntityResult{ + { + Entity: entity1, + Version: 1, + }, + }, + Deferred: []*pb.Key{ + keyToProto(keys[1]), + }, + }, nil + } + + // On the second call, we do not return any more deferred keys. + return &pb.LookupResponse{ + Found: []*pb.EntityResult{ + { + Entity: entity2, + Version: 1, + }, + }, + }, nil + }, + } + client := &Client{ + client: fakeClient, + } + + ctx := context.Background() + + dst := make([]Ent, len(keys)) + err := client.GetMulti(ctx, keys, dst) + if err != nil { + t.Fatalf("client.Get: %v", err) + } + + if count != 2 { + t.Fatalf("expected client.lookup to be called 2 times. Got %d", count) + } + + if len(dst) != 2 { + t.Fatalf("expected 2 entities returned, got %d", len(dst)) + } + + for _, e := range dst { + if e.A == 1 { + if e.B != "one" { + t.Fatalf("unexpected entity %+v", e) + } + } else if e.A == 2 { + if e.B != "two" { + t.Fatalf("unexpected entity %+v", e) + } + } else { + t.Fatalf("unexpected entity %+v", e) + } + } + +} + +type KeyLoaderEnt struct { + A int + K *Key +} + +func (e *KeyLoaderEnt) Load(p []Property) error { + e.A = 2 + return nil +} + +func (e *KeyLoaderEnt) LoadKey(k *Key) error { + e.K = k + return nil +} + +func (e *KeyLoaderEnt) Save() ([]Property, error) { + return []Property{{Name: "A", Value: int64(3)}}, nil +} + +func TestKeyLoaderEndToEnd(t *testing.T) { + keys := []*Key{ + NameKey("testKind", "first", nil), + NameKey("testKind", "second", nil), + } + + entity1 := &pb.Entity{ + Key: keyToProto(keys[0]), + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_IntegerValue{IntegerValue: 1}}, + "B": {ValueType: &pb.Value_StringValue{StringValue: "one"}}, + }, + } + entity2 := &pb.Entity{ + Key: keyToProto(keys[1]), + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_IntegerValue{IntegerValue: 2}}, + "B": {ValueType: &pb.Value_StringValue{StringValue: "two"}}, + }, + } + + fakeClient := &fakeDatastoreClient{ + lookup: func(*pb.LookupRequest) (*pb.LookupResponse, error) { + return &pb.LookupResponse{ + Found: []*pb.EntityResult{ + { + Entity: entity1, + Version: 1, + }, + { + Entity: entity2, + Version: 1, + }, + }, + }, nil + }, + } + client := &Client{ + client: fakeClient, + } + + ctx := context.Background() + + dst := make([]*KeyLoaderEnt, len(keys)) + err := client.GetMulti(ctx, keys, dst) + if err != nil { + t.Fatalf("client.Get: %v", err) + } + + for i := range dst { + if !testutil.Equal(dst[i].K, keys[i]) { + t.Fatalf("unexpected entity %d to have key %+v, got %+v", i, keys[i], dst[i].K) + } + } +} + +func TestDeferredMissing(t *testing.T) { + type Ent struct { + A int + B string + } + + keys := []*Key{ + NameKey("testKind", "first", nil), + NameKey("testKind", "second", nil), + } + + entity1 := &pb.Entity{ + Key: keyToProto(keys[0]), + } + entity2 := &pb.Entity{ + Key: keyToProto(keys[1]), + } + + var count int + fakeClient := &fakeDatastoreClient{ + lookup: func(*pb.LookupRequest) (*pb.LookupResponse, error) { + count++ + + if count == 1 { + return &pb.LookupResponse{ + Missing: []*pb.EntityResult{ + { + Entity: entity1, + Version: 1, + }, + }, + Deferred: []*pb.Key{ + keyToProto(keys[1]), + }, + }, nil + } + + return &pb.LookupResponse{ + Missing: []*pb.EntityResult{ + { + Entity: entity2, + Version: 1, + }, + }, + }, nil + }, + } + client := &Client{ + client: fakeClient, + } + + ctx := context.Background() + + dst := make([]Ent, len(keys)) + err := client.GetMulti(ctx, keys, dst) + errs, ok := err.(MultiError) + if !ok { + t.Fatalf("expected error returns to be MultiError; got %v", err) + } + if len(errs) != 2 { + t.Fatalf("expected 2 errors returns, got %d", len(errs)) + } + if errs[0] != ErrNoSuchEntity { + t.Fatalf("expected error to be ErrNoSuchEntity; got %v", errs[0]) + } + if errs[1] != ErrNoSuchEntity { + t.Fatalf("expected error to be ErrNoSuchEntity; got %v", errs[1]) + } + + if count != 2 { + t.Fatalf("expected client.lookup to be called 2 times. Got %d", count) + } + + if len(dst) != 2 { + t.Fatalf("expected 2 entities returned, got %d", len(dst)) + } + + for _, e := range dst { + if e.A != 0 || e.B != "" { + t.Fatalf("unexpected entity %+v", e) + } + } +} + +func TestGetWithNilKey(t *testing.T) { + client := &Client{} + err := client.Get(context.Background(), nil, []Property{}) + if err != ErrInvalidKey { + t.Fatalf("want ErrInvalidKey, got %v", err) + } +} + +func TestGetMultiWithNilKey(t *testing.T) { + client := &Client{} + dest := make([]PropertyList, 1) + err := client.GetMulti(context.Background(), []*Key{nil}, dest) + if me, ok := err.(MultiError); !ok { + t.Fatalf("want MultiError, got %v", err) + } else if len(me) != 1 || me[0] != ErrInvalidKey { + t.Fatalf("want MultiError{ErrInvalidKey}, got %v", me) + } +} + +func TestGetWithIncompleteKey(t *testing.T) { + client := &Client{} + err := client.Get(context.Background(), &Key{Kind: "testKind"}, []Property{}) + if err == nil { + t.Fatalf("want err, got nil") + } +} + +func TestGetMultiWithIncompleteKey(t *testing.T) { + client := &Client{} + dest := make([]PropertyList, 1) + err := client.GetMulti(context.Background(), []*Key{{Kind: "testKind"}}, dest) + if me, ok := err.(MultiError); !ok { + t.Fatalf("want MultiError, got %v", err) + } else if len(me) != 1 || me[0] == nil { + t.Fatalf("want MultiError{err}, got %v", me) + } +} + +func TestDeleteWithNilKey(t *testing.T) { + client := &Client{} + err := client.Delete(context.Background(), nil) + if err != ErrInvalidKey { + t.Fatalf("want ErrInvalidKey, got %v", err) + } +} + +func TestDeleteMultiWithNilKey(t *testing.T) { + client := &Client{} + err := client.DeleteMulti(context.Background(), []*Key{nil}) + if me, ok := err.(MultiError); !ok { + t.Fatalf("want MultiError, got %v", err) + } else if len(me) != 1 || me[0] != ErrInvalidKey { + t.Fatalf("want MultiError{ErrInvalidKey}, got %v", me) + } +} + +func TestDeleteWithIncompleteKey(t *testing.T) { + client := &Client{} + err := client.Delete(context.Background(), &Key{Kind: "testKind"}) + if err == nil { + t.Fatalf("want err, got nil") + } +} + +func TestDeleteMultiWithIncompleteKey(t *testing.T) { + client := &Client{} + err := client.DeleteMulti(context.Background(), []*Key{{Kind: "testKind"}}) + if me, ok := err.(MultiError); !ok { + t.Fatalf("want MultiError, got %v", err) + } else if len(me) != 1 || me[0] == nil { + t.Fatalf("want MultiError{err}, got %v", me) + } +} + +type fakeDatastoreClient struct { + pb.DatastoreClient + + // Optional handlers for the datastore methods. + // Any handlers left undefined will return an error. + lookup func(*pb.LookupRequest) (*pb.LookupResponse, error) + runQuery func(*pb.RunQueryRequest) (*pb.RunQueryResponse, error) + beginTransaction func(*pb.BeginTransactionRequest) (*pb.BeginTransactionResponse, error) + commit func(*pb.CommitRequest) (*pb.CommitResponse, error) + rollback func(*pb.RollbackRequest) (*pb.RollbackResponse, error) + allocateIds func(*pb.AllocateIdsRequest) (*pb.AllocateIdsResponse, error) +} + +func (c *fakeDatastoreClient) Lookup(ctx context.Context, in *pb.LookupRequest, opts ...grpc.CallOption) (*pb.LookupResponse, error) { + if c.lookup == nil { + return nil, errors.New("no lookup handler defined") + } + return c.lookup(in) +} +func (c *fakeDatastoreClient) RunQuery(ctx context.Context, in *pb.RunQueryRequest, opts ...grpc.CallOption) (*pb.RunQueryResponse, error) { + if c.runQuery == nil { + return nil, errors.New("no runQuery handler defined") + } + return c.runQuery(in) +} +func (c *fakeDatastoreClient) BeginTransaction(ctx context.Context, in *pb.BeginTransactionRequest, opts ...grpc.CallOption) (*pb.BeginTransactionResponse, error) { + if c.beginTransaction == nil { + return nil, errors.New("no beginTransaction handler defined") + } + return c.beginTransaction(in) +} +func (c *fakeDatastoreClient) Commit(ctx context.Context, in *pb.CommitRequest, opts ...grpc.CallOption) (*pb.CommitResponse, error) { + if c.commit == nil { + return nil, errors.New("no commit handler defined") + } + return c.commit(in) +} +func (c *fakeDatastoreClient) Rollback(ctx context.Context, in *pb.RollbackRequest, opts ...grpc.CallOption) (*pb.RollbackResponse, error) { + if c.rollback == nil { + return nil, errors.New("no rollback handler defined") + } + return c.rollback(in) +} +func (c *fakeDatastoreClient) AllocateIds(ctx context.Context, in *pb.AllocateIdsRequest, opts ...grpc.CallOption) (*pb.AllocateIdsResponse, error) { + if c.allocateIds == nil { + return nil, errors.New("no allocateIds handler defined") + } + return c.allocateIds(in) +} diff --git a/vendor/cloud.google.com/go/datastore/doc.go b/vendor/cloud.google.com/go/datastore/doc.go new file mode 100644 index 00000000..2d252e03 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/doc.go @@ -0,0 +1,490 @@ +// Copyright 2016 Google LLC +// +// 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 datastore provides a client for Google Cloud Datastore. + +See https://godoc.org/cloud.google.com/go for authentication, timeouts, +connection pooling and similar aspects of this package. + + +Basic Operations + +Entities are the unit of storage and are associated with a key. A key +consists of an optional parent key, a string application ID, a string kind +(also known as an entity type), and either a StringID or an IntID. A +StringID is also known as an entity name or key name. + +It is valid to create a key with a zero StringID and a zero IntID; this is +called an incomplete key, and does not refer to any saved entity. Putting an +entity into the datastore under an incomplete key will cause a unique key +to be generated for that entity, with a non-zero IntID. + +An entity's contents are a mapping from case-sensitive field names to values. +Valid value types are: + - Signed integers (int, int8, int16, int32 and int64) + - bool + - string + - float32 and float64 + - []byte (up to 1 megabyte in length) + - Any type whose underlying type is one of the above predeclared types + - *Key + - GeoPoint + - time.Time (stored with microsecond precision, retrieved as local time) + - Structs whose fields are all valid value types + - Pointers to structs whose fields are all valid value types + - Slices of any of the above + - Pointers to a signed integer, bool, string, float32, or float64 + +Slices of structs are valid, as are structs that contain slices. + +The Get and Put functions load and save an entity's contents. An entity's +contents are typically represented by a struct pointer. + +Example code: + + type Entity struct { + Value string + } + + func main() { + ctx := context.Background() + + // Create a datastore client. In a typical application, you would create + // a single client which is reused for every datastore operation. + dsClient, err := datastore.NewClient(ctx, "my-project") + if err != nil { + // Handle error. + } + + k := datastore.NameKey("Entity", "stringID", nil) + e := new(Entity) + if err := dsClient.Get(ctx, k, e); err != nil { + // Handle error. + } + + old := e.Value + e.Value = "Hello World!" + + if _, err := dsClient.Put(ctx, k, e); err != nil { + // Handle error. + } + + fmt.Printf("Updated value from %q to %q\n", old, e.Value) + } + +GetMulti, PutMulti and DeleteMulti are batch versions of the Get, Put and +Delete functions. They take a []*Key instead of a *Key, and may return a +datastore.MultiError when encountering partial failure. + +Mutate generalizes PutMulti and DeleteMulti to a sequence of any Datastore mutations. +It takes a series of mutations created with NewInsert, NewUpdate, NewUpsert and +NewDelete and applies them atomically. + + +Properties + +An entity's contents can be represented by a variety of types. These are +typically struct pointers, but can also be any type that implements the +PropertyLoadSaver interface. If using a struct pointer, you do not have to +explicitly implement the PropertyLoadSaver interface; the datastore will +automatically convert via reflection. If a struct pointer does implement +PropertyLoadSaver then those methods will be used in preference to the default +behavior for struct pointers. Struct pointers are more strongly typed and are +easier to use; PropertyLoadSavers are more flexible. + +The actual types passed do not have to match between Get and Put calls or even +across different calls to datastore. It is valid to put a *PropertyList and +get that same entity as a *myStruct, or put a *myStruct0 and get a *myStruct1. +Conceptually, any entity is saved as a sequence of properties, and is loaded +into the destination value on a property-by-property basis. When loading into +a struct pointer, an entity that cannot be completely represented (such as a +missing field) will result in an ErrFieldMismatch error but it is up to the +caller whether this error is fatal, recoverable or ignorable. + +By default, for struct pointers, all properties are potentially indexed, and +the property name is the same as the field name (and hence must start with an +upper case letter). + +Fields may have a `datastore:"name,options"` tag. The tag name is the +property name, which must be one or more valid Go identifiers joined by ".", +but may start with a lower case letter. An empty tag name means to just use the +field name. A "-" tag name means that the datastore will ignore that field. + +The only valid options are "omitempty", "noindex" and "flatten". + +If the options include "omitempty" and the value of the field is a zero value, +then the field will be omitted on Save. Zero values are best defined in the +golang spec (https://golang.org/ref/spec#The_zero_value). Struct field values +will never be empty, except for nil pointers. + +If options include "noindex" then the field will not be indexed. All fields +are indexed by default. Strings or byte slices longer than 1500 bytes cannot +be indexed; fields used to store long strings and byte slices must be tagged +with "noindex" or they will cause Put operations to fail. + +For a nested struct field, the options may also include "flatten". This +indicates that the immediate fields and any nested substruct fields of the +nested struct should be flattened. See below for examples. + +To use multiple options together, separate them by a comma. +The order does not matter. + +If the options is "" then the comma may be omitted. + +Example code: + + // A and B are renamed to a and b. + // A, C and J are not indexed. + // D's tag is equivalent to having no tag at all (E). + // I is ignored entirely by the datastore. + // J has tag information for both the datastore and json packages. + type TaggedStruct struct { + A int `datastore:"a,noindex"` + B int `datastore:"b"` + C int `datastore:",noindex"` + D int `datastore:""` + E int + I int `datastore:"-"` + J int `datastore:",noindex" json:"j"` + } + + +Slice Fields + +A field of slice type corresponds to a Datastore array property, except for []byte, which corresponds +to a Datastore blob. + +Zero-length slice fields are not saved. Slice fields of length 1 or greater are saved +as Datastore arrays. When a zero-length Datastore array is loaded into a slice field, +the slice field remains unchanged. + +If a non-array value is loaded into a slice field, the result will be a slice with +one element, containing the value. + +Loading Nulls + +Loading a Datastore Null into a basic type (int, float, etc.) results in a zero value. +Loading a Null into a slice of basic type results in a slice of size 1 containing the zero value. +Loading a Null into a pointer field results in nil. +Loading a Null into a field of struct type is an error. + +Pointer Fields + +A struct field can be a pointer to a signed integer, floating-point number, string or +bool. Putting a non-nil pointer will store its dereferenced value. Putting a nil +pointer will store a Datastore Null property, unless the field is marked omitempty, +in which case no property will be stored. + +Loading a Null into a pointer field sets the pointer to nil. Loading any other value +allocates new storage with the value, and sets the field to point to it. + + +Key Field + +If the struct contains a *datastore.Key field tagged with the name "__key__", +its value will be ignored on Put. When reading the Entity back into the Go struct, +the field will be populated with the *datastore.Key value used to query for +the Entity. + +Example code: + + type MyEntity struct { + A int + K *datastore.Key `datastore:"__key__"` + } + + k := datastore.NameKey("Entity", "stringID", nil) + e := MyEntity{A: 12} + k, err = dsClient.Put(ctx, k, e) + if err != nil { + // Handle error. + } + + var entities []MyEntity + q := datastore.NewQuery("Entity").Filter("A =", 12).Limit(1) + _, err := dsClient.GetAll(ctx, q, &entities) + if err != nil { + // Handle error + } + + log.Println(entities[0]) + // Prints {12 /Entity,stringID} + + + +Structured Properties + +If the struct pointed to contains other structs, then the nested or embedded +structs are themselves saved as Entity values. For example, given these definitions: + + type Inner struct { + W int32 + X string + } + + type Outer struct { + I Inner + } + +then an Outer would have one property, Inner, encoded as an Entity value. + +If an outer struct is tagged "noindex" then all of its implicit flattened +fields are effectively "noindex". + +If the Inner struct contains a *Key field with the name "__key__", like so: + + type Inner struct { + W int32 + X string + K *datastore.Key `datastore:"__key__"` + } + + type Outer struct { + I Inner + } + +then the value of K will be used as the Key for Inner, represented +as an Entity value in datastore. + +If any nested struct fields should be flattened, instead of encoded as +Entity values, the nested struct field should be tagged with the "flatten" +option. For example, given the following: + + type Inner1 struct { + W int32 + X string + } + + type Inner2 struct { + Y float64 + } + + type Inner3 struct { + Z bool + } + + type Inner4 struct { + WW int + } + + type Inner5 struct { + X Inner4 + } + + type Outer struct { + A int16 + I []Inner1 `datastore:",flatten"` + J Inner2 `datastore:",flatten"` + K Inner5 `datastore:",flatten"` + Inner3 `datastore:",flatten"` + } + +an Outer's properties would be equivalent to those of: + + type OuterEquivalent struct { + A int16 + IDotW []int32 `datastore:"I.W"` + IDotX []string `datastore:"I.X"` + JDotY float64 `datastore:"J.Y"` + KDotXDotWW int `datastore:"K.X.WW"` + Z bool + } + +Note that the "flatten" option cannot be used for Entity value fields. +The server will reject any dotted field names for an Entity value. + + +The PropertyLoadSaver Interface + +An entity's contents can also be represented by any type that implements the +PropertyLoadSaver interface. This type may be a struct pointer, but it does +not have to be. The datastore package will call Load when getting the entity's +contents, and Save when putting the entity's contents. +Possible uses include deriving non-stored fields, verifying fields, or indexing +a field only if its value is positive. + +Example code: + + type CustomPropsExample struct { + I, J int + // Sum is not stored, but should always be equal to I + J. + Sum int `datastore:"-"` + } + + func (x *CustomPropsExample) Load(ps []datastore.Property) error { + // Load I and J as usual. + if err := datastore.LoadStruct(x, ps); err != nil { + return err + } + // Derive the Sum field. + x.Sum = x.I + x.J + return nil + } + + func (x *CustomPropsExample) Save() ([]datastore.Property, error) { + // Validate the Sum field. + if x.Sum != x.I + x.J { + return nil, errors.New("CustomPropsExample has inconsistent sum") + } + // Save I and J as usual. The code below is equivalent to calling + // "return datastore.SaveStruct(x)", but is done manually for + // demonstration purposes. + return []datastore.Property{ + { + Name: "I", + Value: int64(x.I), + }, + { + Name: "J", + Value: int64(x.J), + }, + }, nil + } + +The *PropertyList type implements PropertyLoadSaver, and can therefore hold an +arbitrary entity's contents. + +The KeyLoader Interface + +If a type implements the PropertyLoadSaver interface, it may +also want to implement the KeyLoader interface. +The KeyLoader interface exists to allow implementations of PropertyLoadSaver +to also load an Entity's Key into the Go type. This type may be a struct +pointer, but it does not have to be. The datastore package will call LoadKey +when getting the entity's contents, after calling Load. + +Example code: + + type WithKeyExample struct { + I int + Key *datastore.Key + } + + func (x *WithKeyExample) LoadKey(k *datastore.Key) error { + x.Key = k + return nil + } + + func (x *WithKeyExample) Load(ps []datastore.Property) error { + // Load I as usual. + return datastore.LoadStruct(x, ps) + } + + func (x *WithKeyExample) Save() ([]datastore.Property, error) { + // Save I as usual. + return datastore.SaveStruct(x) + } + +To load a Key into a struct which does not implement the PropertyLoadSaver +interface, see the "Key Field" section above. + + +Queries + +Queries retrieve entities based on their properties or key's ancestry. Running +a query yields an iterator of results: either keys or (key, entity) pairs. +Queries are re-usable and it is safe to call Query.Run from concurrent +goroutines. Iterators are not safe for concurrent use. + +Queries are immutable, and are either created by calling NewQuery, or derived +from an existing query by calling a method like Filter or Order that returns a +new query value. A query is typically constructed by calling NewQuery followed +by a chain of zero or more such methods. These methods are: + - Ancestor and Filter constrain the entities returned by running a query. + - Order affects the order in which they are returned. + - Project constrains the fields returned. + - Distinct de-duplicates projected entities. + - KeysOnly makes the iterator return only keys, not (key, entity) pairs. + - Start, End, Offset and Limit define which sub-sequence of matching entities + to return. Start and End take cursors, Offset and Limit take integers. Start + and Offset affect the first result, End and Limit affect the last result. + If both Start and Offset are set, then the offset is relative to Start. + If both End and Limit are set, then the earliest constraint wins. Limit is + relative to Start+Offset, not relative to End. As a special case, a + negative limit means unlimited. + +Example code: + + type Widget struct { + Description string + Price int + } + + func printWidgets(ctx context.Context, client *datastore.Client) { + q := datastore.NewQuery("Widget"). + Filter("Price <", 1000). + Order("-Price") + + t := client.Run(ctx, q) + for { + var x Widget + key, err := t.Next(&x) + if err == iterator.Done { + break + } + if err != nil { + // Handle error. + } + fmt.Printf("Key=%v\nWidget=%#v\n\n", key, x) + } + } + + +Transactions + +Client.RunInTransaction runs a function in a transaction. + +Example code: + + type Counter struct { + Count int + } + + func incCount(ctx context.Context, client *datastore.Client) { + var count int + key := datastore.NameKey("Counter", "singleton", nil) + _, err := client.RunInTransaction(ctx, func(tx *datastore.Transaction) error { + var x Counter + if err := tx.Get(key, &x); err != nil && err != datastore.ErrNoSuchEntity { + return err + } + x.Count++ + if _, err := tx.Put(key, &x); err != nil { + return err + } + count = x.Count + return nil + }) + if err != nil { + // Handle error. + } + // The value of count is only valid once the transaction is successful + // (RunInTransaction has returned nil). + fmt.Printf("Count=%d\n", count) + } + +Pass the ReadOnly option to RunInTransaction if your transaction is used only for Get, +GetMulti or queries. Read-only transactions are more efficient. + +Google Cloud Datastore Emulator + +This package supports the Cloud Datastore emulator, which is useful for testing and +development. Environment variables are used to indicate that datastore traffic should be +directed to the emulator instead of the production Datastore service. + +To install and set up the emulator and its environment variables, see the documentation +at https://cloud.google.com/datastore/docs/tools/datastore-emulator. +*/ +package datastore // import "cloud.google.com/go/datastore" diff --git a/vendor/cloud.google.com/go/datastore/errors.go b/vendor/cloud.google.com/go/datastore/errors.go new file mode 100644 index 00000000..ee1f0022 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/errors.go @@ -0,0 +1,47 @@ +// Copyright 2014 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file provides error functions for common API failure modes. + +package datastore + +import ( + "fmt" +) + +// MultiError is returned by batch operations when there are errors with +// particular elements. Errors will be in a one-to-one correspondence with +// the input elements; successful elements will have a nil entry. +type MultiError []error + +func (m MultiError) Error() string { + s, n := "", 0 + for _, e := range m { + if e != nil { + if n == 0 { + s = e.Error() + } + n++ + } + } + switch n { + case 0: + return "(0 errors)" + case 1: + return s + case 2: + return s + " (and 1 other error)" + } + return fmt.Sprintf("%s (and %d other errors)", s, n-1) +} diff --git a/vendor/cloud.google.com/go/datastore/example_test.go b/vendor/cloud.google.com/go/datastore/example_test.go new file mode 100644 index 00000000..bbeba426 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/example_test.go @@ -0,0 +1,593 @@ +// Copyright 2014 Google LLC +// +// 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 datastore_test + +import ( + "context" + "fmt" + "log" + "time" + + "cloud.google.com/go/datastore" + "google.golang.org/api/iterator" +) + +func ExampleNewClient() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + _ = client // TODO: Use client. +} + +func ExampleClient_Get() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + type Article struct { + Title string + Description string + Body string `datastore:",noindex"` + Author *datastore.Key + PublishedAt time.Time + } + key := datastore.NameKey("Article", "articled1", nil) + article := &Article{} + if err := client.Get(ctx, key, article); err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_Put() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + type Article struct { + Title string + Description string + Body string `datastore:",noindex"` + Author *datastore.Key + PublishedAt time.Time + } + newKey := datastore.IncompleteKey("Article", nil) + _, err = client.Put(ctx, newKey, &Article{ + Title: "The title of the article", + Description: "The description of the article...", + Body: "...", + Author: datastore.NameKey("Author", "jbd", nil), + PublishedAt: time.Now(), + }) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_Put_flatten() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + log.Fatal(err) + } + + type Animal struct { + Name string + Type string + Breed string + } + + type Human struct { + Name string + Height int + Pet Animal `datastore:",flatten"` + } + + newKey := datastore.IncompleteKey("Human", nil) + _, err = client.Put(ctx, newKey, &Human{ + Name: "Susan", + Height: 67, + Pet: Animal{ + Name: "Fluffy", + Type: "Cat", + Breed: "Sphynx", + }, + }) + if err != nil { + log.Fatal(err) + } +} + +func ExampleClient_Delete() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + key := datastore.NameKey("Article", "articled1", nil) + if err := client.Delete(ctx, key); err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_DeleteMulti() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + var keys []*datastore.Key + for i := 1; i <= 10; i++ { + keys = append(keys, datastore.IDKey("Article", int64(i), nil)) + } + if err := client.DeleteMulti(ctx, keys); err != nil { + // TODO: Handle error. + } +} + +type Post struct { + Title string + PublishedAt time.Time + Comments int +} + +func ExampleClient_GetMulti() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + keys := []*datastore.Key{ + datastore.NameKey("Post", "post1", nil), + datastore.NameKey("Post", "post2", nil), + datastore.NameKey("Post", "post3", nil), + } + posts := make([]Post, 3) + if err := client.GetMulti(ctx, keys, posts); err != nil { + // TODO: Handle error. + } +} + +func ExampleMultiError() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + keys := []*datastore.Key{ + datastore.NameKey("bad-key", "bad-key", nil), + } + posts := make([]Post, 1) + if err := client.GetMulti(ctx, keys, posts); err != nil { + if merr, ok := err.(datastore.MultiError); ok { + for _, err := range merr { + // TODO: Handle error. + _ = err + } + } else { + // TODO: Handle error. + } + } +} + +func ExampleClient_PutMulti_slice() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + keys := []*datastore.Key{ + datastore.NameKey("Post", "post1", nil), + datastore.NameKey("Post", "post2", nil), + } + + // PutMulti with a Post slice. + posts := []*Post{ + {Title: "Post 1", PublishedAt: time.Now()}, + {Title: "Post 2", PublishedAt: time.Now()}, + } + if _, err := client.PutMulti(ctx, keys, posts); err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_PutMulti_interfaceSlice() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + keys := []*datastore.Key{ + datastore.NameKey("Post", "post1", nil), + datastore.NameKey("Post", "post2", nil), + } + + // PutMulti with an empty interface slice. + posts := []interface{}{ + &Post{Title: "Post 1", PublishedAt: time.Now()}, + &Post{Title: "Post 2", PublishedAt: time.Now()}, + } + if _, err := client.PutMulti(ctx, keys, posts); err != nil { + // TODO: Handle error. + } +} + +func ExampleNewQuery() { + // Query for Post entities. + q := datastore.NewQuery("Post") + _ = q // TODO: Use the query with Client.Run. +} + +func ExampleNewQuery_options() { + // Query to order the posts by the number of comments they have received. + q := datastore.NewQuery("Post").Order("-Comments") + // Start listing from an offset and limit the results. + q = q.Offset(20).Limit(10) + _ = q // TODO: Use the query. +} + +func ExampleClient_Count() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + // Count the number of the post entities. + q := datastore.NewQuery("Post") + n, err := client.Count(ctx, q) + if err != nil { + // TODO: Handle error. + } + fmt.Printf("There are %d posts.", n) +} + +func ExampleClient_Run() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + // List the posts published since yesterday. + yesterday := time.Now().Add(-24 * time.Hour) + q := datastore.NewQuery("Post").Filter("PublishedAt >", yesterday) + it := client.Run(ctx, q) + _ = it // TODO: iterate using Next. +} + +func ExampleClient_NewTransaction() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + const retries = 3 + + // Increment a counter. + // See https://cloud.google.com/appengine/articles/sharding_counters for + // a more scalable solution. + type Counter struct { + Count int + } + + key := datastore.NameKey("counter", "CounterA", nil) + var tx *datastore.Transaction + for i := 0; i < retries; i++ { + tx, err = client.NewTransaction(ctx) + if err != nil { + break + } + + var c Counter + if err = tx.Get(key, &c); err != nil && err != datastore.ErrNoSuchEntity { + break + } + c.Count++ + if _, err = tx.Put(key, &c); err != nil { + break + } + + // Attempt to commit the transaction. If there's a conflict, try again. + if _, err = tx.Commit(); err != datastore.ErrConcurrentTransaction { + break + } + } + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_RunInTransaction() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + // Increment a counter. + // See https://cloud.google.com/appengine/articles/sharding_counters for + // a more scalable solution. + type Counter struct { + Count int + } + + var count int + key := datastore.NameKey("Counter", "singleton", nil) + _, err = client.RunInTransaction(ctx, func(tx *datastore.Transaction) error { + var x Counter + if err := tx.Get(key, &x); err != nil && err != datastore.ErrNoSuchEntity { + return err + } + x.Count++ + if _, err := tx.Put(key, &x); err != nil { + return err + } + count = x.Count + return nil + }) + if err != nil { + // TODO: Handle error. + } + // The value of count is only valid once the transaction is successful + // (RunInTransaction has returned nil). + fmt.Printf("Count=%d\n", count) +} + +func ExampleClient_AllocateIDs() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + var keys []*datastore.Key + for i := 0; i < 10; i++ { + keys = append(keys, datastore.IncompleteKey("Article", nil)) + } + keys, err = client.AllocateIDs(ctx, keys) + if err != nil { + // TODO: Handle error. + } + _ = keys // TODO: Use keys. +} + +func ExampleKey_Encode() { + key := datastore.IDKey("Article", 1, nil) + encoded := key.Encode() + fmt.Println(encoded) + // Output: EgsKB0FydGljbGUQAQ +} + +func ExampleDecodeKey() { + const encoded = "EgsKB0FydGljbGUQAQ" + key, err := datastore.DecodeKey(encoded) + if err != nil { + // TODO: Handle error. + } + fmt.Println(key) + // Output: /Article,1 +} + +func ExampleIDKey() { + // Key with numeric ID. + k := datastore.IDKey("Article", 1, nil) + _ = k // TODO: Use key. +} + +func ExampleNameKey() { + // Key with string ID. + k := datastore.NameKey("Article", "article8", nil) + _ = k // TODO: Use key. +} + +func ExampleIncompleteKey() { + k := datastore.IncompleteKey("Article", nil) + _ = k // TODO: Use incomplete key. +} + +func ExampleClient_GetAll() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + var posts []*Post + keys, err := client.GetAll(ctx, datastore.NewQuery("Post"), &posts) + if err != nil { + // TODO: Handle error. + } + for i, key := range keys { + fmt.Println(key) + fmt.Println(posts[i]) + } +} + +func ExampleClient_Mutate() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + key1 := datastore.NameKey("Post", "post1", nil) + key2 := datastore.NameKey("Post", "post2", nil) + key3 := datastore.NameKey("Post", "post3", nil) + key4 := datastore.NameKey("Post", "post4", nil) + + _, err = client.Mutate(ctx, + datastore.NewInsert(key1, Post{Title: "Post 1"}), + datastore.NewUpsert(key2, Post{Title: "Post 2"}), + datastore.NewUpdate(key3, Post{Title: "Post 3"}), + datastore.NewDelete(key4)) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleCommit_Key() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "") + if err != nil { + // TODO: Handle error. + } + var pk1, pk2 *datastore.PendingKey + // Create two posts in a single transaction. + commit, err := client.RunInTransaction(ctx, func(tx *datastore.Transaction) error { + var err error + pk1, err = tx.Put(datastore.IncompleteKey("Post", nil), &Post{Title: "Post 1", PublishedAt: time.Now()}) + if err != nil { + return err + } + pk2, err = tx.Put(datastore.IncompleteKey("Post", nil), &Post{Title: "Post 2", PublishedAt: time.Now()}) + if err != nil { + return err + } + return nil + }) + if err != nil { + // TODO: Handle error. + } + // Now pk1, pk2 are valid PendingKeys. Let's convert them into real keys + // using the Commit object. + k1 := commit.Key(pk1) + k2 := commit.Key(pk2) + fmt.Println(k1, k2) +} + +func ExampleIterator_Next() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + it := client.Run(ctx, datastore.NewQuery("Post")) + for { + var p Post + key, err := it.Next(&p) + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(key, p) + } +} + +func ExampleIterator_Cursor() { + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + it := client.Run(ctx, datastore.NewQuery("Post")) + for { + var p Post + _, err := it.Next(&p) + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(p) + cursor, err := it.Cursor() + if err != nil { + // TODO: Handle error. + } + // When printed, a cursor will display as a string that can be passed + // to datastore.NewCursor. + fmt.Printf("to resume with this post, use cursor %s\n", cursor) + } +} + +func ExampleDecodeCursor() { + // See Query.Start for a fuller example of DecodeCursor. + // getCursor represents a function that returns a cursor from a previous + // iteration in string form. + cursorString := getCursor() + cursor, err := datastore.DecodeCursor(cursorString) + if err != nil { + // TODO: Handle error. + } + _ = cursor // TODO: Use the cursor with Query.Start or Query.End. +} + +func getCursor() string { return "" } + +func ExampleQuery_Start() { + // This example demonstrates how to use cursors and Query.Start + // to resume an iteration. + ctx := context.Background() + client, err := datastore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + // getCursor represents a function that returns a cursor from a previous + // iteration in string form. + cursorString := getCursor() + cursor, err := datastore.DecodeCursor(cursorString) + if err != nil { + // TODO: Handle error. + } + it := client.Run(ctx, datastore.NewQuery("Post").Start(cursor)) + _ = it // TODO: Use iterator. +} + +func ExampleLoadStruct() { + type Player struct { + User string + Score int + } + // Normally LoadStruct would only be used inside a custom implementation of + // PropertyLoadSaver; this is for illustrative purposes only. + props := []datastore.Property{ + {Name: "User", Value: "Alice"}, + {Name: "Score", Value: int64(97)}, + } + + var p Player + if err := datastore.LoadStruct(&p, props); err != nil { + // TODO: Handle error. + } + fmt.Println(p) + // Output: {Alice 97} +} + +func ExampleSaveStruct() { + type Player struct { + User string + Score int + } + + p := &Player{ + User: "Alice", + Score: 97, + } + props, err := datastore.SaveStruct(p) + if err != nil { + // TODO: Handle error. + } + fmt.Println(props) + // TODO(jba): make this output stable: Output: [{User Alice false} {Score 97 false}] +} diff --git a/vendor/cloud.google.com/go/datastore/integration_test.go b/vendor/cloud.google.com/go/datastore/integration_test.go new file mode 100644 index 00000000..bb8e6d55 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/integration_test.go @@ -0,0 +1,1280 @@ +// Copyright 2014 Google LLC +// +// 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 datastore + +import ( + "context" + "encoding/json" + "errors" + "flag" + "fmt" + "log" + "net" + "os" + "reflect" + "sort" + "strings" + "sync" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/rpcreplay" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// TODO(djd): Make test entity clean up more robust: some test entities may +// be left behind if tests are aborted, the transport fails, etc. + +var timeNow = time.Now() + +// suffix is a timestamp-based suffix which is appended to key names, +// particularly for the root keys of entity groups. This reduces flakiness +// when the tests are run in parallel. +var suffix string + +const replayFilename = "datastore.replay" + +type replayInfo struct { + ProjectID string + Time time.Time +} + +var ( + record = flag.Bool("record", false, "record RPCs") + + newTestClient = func(ctx context.Context, t *testing.T) *Client { + return newClient(ctx, t, nil) + } +) + +func TestMain(m *testing.M) { + os.Exit(testMain(m)) +} + +func testMain(m *testing.M) int { + flag.Parse() + if testing.Short() { + if *record { + log.Fatal("cannot combine -short and -record") + } + if testutil.CanReplay(replayFilename) { + initReplay() + } + } else if *record { + if testutil.ProjID() == "" { + log.Fatal("must record with a project ID") + } + b, err := json.Marshal(replayInfo{ + ProjectID: testutil.ProjID(), + Time: timeNow, + }) + if err != nil { + log.Fatal(err) + } + rec, err := rpcreplay.NewRecorder(replayFilename, b) + if err != nil { + log.Fatal(err) + } + defer func() { + if err := rec.Close(); err != nil { + log.Fatalf("closing recorder: %v", err) + } + }() + newTestClient = func(ctx context.Context, t *testing.T) *Client { + return newClient(ctx, t, rec.DialOptions()) + } + log.Printf("recording to %s", replayFilename) + } + suffix = fmt.Sprintf("-t%d", timeNow.UnixNano()) + return m.Run() +} + +func initReplay() { + rep, err := rpcreplay.NewReplayer(replayFilename) + if err != nil { + log.Fatal(err) + } + defer rep.Close() + + var ri replayInfo + if err := json.Unmarshal(rep.Initial(), &ri); err != nil { + log.Fatalf("unmarshaling initial replay info: %v", err) + } + timeNow = ri.Time.In(time.Local) + + conn, err := replayConn(rep) + if err != nil { + log.Fatal(err) + } + newTestClient = func(ctx context.Context, t *testing.T) *Client { + client, err := NewClient(ctx, ri.ProjectID, option.WithGRPCConn(conn)) + if err != nil { + t.Fatalf("NewClient: %v", err) + } + return client + } + log.Printf("replaying from %s", replayFilename) +} + +func replayConn(rep *rpcreplay.Replayer) (*grpc.ClientConn, error) { + // If we make a real connection we need creds from somewhere, and they + // might not be available, for instance on Travis. + // Replaying doesn't require a connection live at all, but we need + // something to attach gRPC interceptors to. + // So we start a local listener and connect to it, then close them down. + // TODO(jba): build something like this into the replayer? + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return nil, err + } + conn, err := grpc.Dial(l.Addr().String(), + append([]grpc.DialOption{grpc.WithInsecure()}, rep.DialOptions()...)...) + if err != nil { + return nil, err + } + conn.Close() + l.Close() + return conn, nil +} + +func newClient(ctx context.Context, t *testing.T, dialOpts []grpc.DialOption) *Client { + if testing.Short() { + t.Skip("Integration tests skipped in short mode") + } + ts := testutil.TokenSource(ctx, ScopeDatastore) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + opts := []option.ClientOption{option.WithTokenSource(ts)} + for _, opt := range dialOpts { + opts = append(opts, option.WithGRPCDialOption(opt)) + } + client, err := NewClient(ctx, testutil.ProjID(), opts...) + if err != nil { + t.Fatalf("NewClient: %v", err) + } + return client +} + +func TestBasics(t *testing.T) { + ctx, _ := context.WithTimeout(context.Background(), time.Second*20) + client := newTestClient(ctx, t) + defer client.Close() + + type X struct { + I int + S string + T time.Time + } + + x0 := X{66, "99", timeNow.Truncate(time.Millisecond)} + k, err := client.Put(ctx, IncompleteKey("BasicsX", nil), &x0) + if err != nil { + t.Fatalf("client.Put: %v", err) + } + x1 := X{} + err = client.Get(ctx, k, &x1) + if err != nil { + t.Errorf("client.Get: %v", err) + } + err = client.Delete(ctx, k) + if err != nil { + t.Errorf("client.Delete: %v", err) + } + if !testutil.Equal(x0, x1) { + t.Errorf("compare: x0=%v, x1=%v", x0, x1) + } +} + +func TestTopLevelKeyLoaded(t *testing.T) { + ctx, _ := context.WithTimeout(context.Background(), time.Second*20) + client := newTestClient(ctx, t) + defer client.Close() + + completeKey := NameKey("EntityWithKey", "myent", nil) + + type EntityWithKey struct { + I int + S string + K *Key `datastore:"__key__"` + } + + in := &EntityWithKey{ + I: 12, + S: "abcd", + } + + k, err := client.Put(ctx, completeKey, in) + if err != nil { + t.Fatalf("client.Put: %v", err) + } + + var e EntityWithKey + err = client.Get(ctx, k, &e) + if err != nil { + t.Fatalf("client.Get: %v", err) + } + + // The two keys should be absolutely identical. + if !testutil.Equal(e.K, k) { + t.Fatalf("e.K not equal to k; got %#v, want %#v", e.K, k) + } + +} + +func TestListValues(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + p0 := PropertyList{ + {Name: "L", Value: []interface{}{int64(12), "string", true}}, + } + k, err := client.Put(ctx, IncompleteKey("ListValue", nil), &p0) + if err != nil { + t.Fatalf("client.Put: %v", err) + } + var p1 PropertyList + if err := client.Get(ctx, k, &p1); err != nil { + t.Errorf("client.Get: %v", err) + } + if !testutil.Equal(p0, p1) { + t.Errorf("compare:\np0=%v\np1=%#v", p0, p1) + } + if err = client.Delete(ctx, k); err != nil { + t.Errorf("client.Delete: %v", err) + } +} + +func TestGetMulti(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + type X struct { + I int + } + p := NameKey("X", "x"+suffix, nil) + + cases := []struct { + key *Key + put bool + }{ + {key: NameKey("X", "item1", p), put: true}, + {key: NameKey("X", "item2", p), put: false}, + {key: NameKey("X", "item3", p), put: false}, + {key: NameKey("X", "item3", p), put: false}, + {key: NameKey("X", "item4", p), put: true}, + } + + var src, dst []*X + var srcKeys, dstKeys []*Key + for _, c := range cases { + dst = append(dst, &X{}) + dstKeys = append(dstKeys, c.key) + if c.put { + src = append(src, &X{}) + srcKeys = append(srcKeys, c.key) + } + } + if _, err := client.PutMulti(ctx, srcKeys, src); err != nil { + t.Error(err) + } + err := client.GetMulti(ctx, dstKeys, dst) + if err == nil { + t.Errorf("client.GetMulti got %v, expected error", err) + } + e, ok := err.(MultiError) + if !ok { + t.Errorf("client.GetMulti got %T, expected MultiError", err) + } + for i, err := range e { + got, want := err, (error)(nil) + if !cases[i].put { + got, want = err, ErrNoSuchEntity + } + if got != want { + t.Errorf("MultiError[%d] == %v, want %v", i, got, want) + } + } +} + +type Z struct { + S string + T string `datastore:",noindex"` + P []byte + K []byte `datastore:",noindex"` +} + +func (z Z) String() string { + var lens []string + v := reflect.ValueOf(z) + for i := 0; i < v.NumField(); i++ { + if l := v.Field(i).Len(); l > 0 { + lens = append(lens, fmt.Sprintf("len(%s)=%d", v.Type().Field(i).Name, l)) + } + } + return fmt.Sprintf("Z{ %s }", strings.Join(lens, ",")) +} + +func TestUnindexableValues(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + x1500 := strings.Repeat("x", 1500) + x1501 := strings.Repeat("x", 1501) + testCases := []struct { + in Z + wantErr bool + }{ + {in: Z{S: x1500}, wantErr: false}, + {in: Z{S: x1501}, wantErr: true}, + {in: Z{T: x1500}, wantErr: false}, + {in: Z{T: x1501}, wantErr: false}, + {in: Z{P: []byte(x1500)}, wantErr: false}, + {in: Z{P: []byte(x1501)}, wantErr: true}, + {in: Z{K: []byte(x1500)}, wantErr: false}, + {in: Z{K: []byte(x1501)}, wantErr: false}, + } + for _, tt := range testCases { + _, err := client.Put(ctx, IncompleteKey("BasicsZ", nil), &tt.in) + if (err != nil) != tt.wantErr { + t.Errorf("client.Put %s got err %v, want err %t", tt.in, err, tt.wantErr) + } + } +} + +func TestNilKey(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + testCases := []struct { + in K0 + wantErr bool + }{ + {in: K0{K: testKey0}, wantErr: false}, + {in: K0{}, wantErr: false}, + } + for _, tt := range testCases { + _, err := client.Put(ctx, IncompleteKey("NilKey", nil), &tt.in) + if (err != nil) != tt.wantErr { + t.Errorf("client.Put %s got err %v, want err %t", tt.in, err, tt.wantErr) + } + } +} + +type SQChild struct { + I, J int + T, U int64 +} + +type SQTestCase struct { + desc string + q *Query + wantCount int + wantSum int +} + +func testSmallQueries(ctx context.Context, t *testing.T, client *Client, parent *Key, children []*SQChild, + testCases []SQTestCase, extraTests ...func()) { + keys := make([]*Key, len(children)) + for i := range keys { + keys[i] = IncompleteKey("SQChild", parent) + } + keys, err := client.PutMulti(ctx, keys, children) + if err != nil { + t.Fatalf("client.PutMulti: %v", err) + } + defer func() { + err := client.DeleteMulti(ctx, keys) + if err != nil { + t.Errorf("client.DeleteMulti: %v", err) + } + }() + + for _, tc := range testCases { + count, err := client.Count(ctx, tc.q) + if err != nil { + t.Errorf("Count %q: %v", tc.desc, err) + continue + } + if count != tc.wantCount { + t.Errorf("Count %q: got %d want %d", tc.desc, count, tc.wantCount) + continue + } + } + + for _, tc := range testCases { + var got []SQChild + _, err := client.GetAll(ctx, tc.q, &got) + if err != nil { + t.Errorf("client.GetAll %q: %v", tc.desc, err) + continue + } + sum := 0 + for _, c := range got { + sum += c.I + c.J + } + if sum != tc.wantSum { + t.Errorf("sum %q: got %d want %d", tc.desc, sum, tc.wantSum) + continue + } + } + for _, x := range extraTests { + x() + } +} + +func TestFilters(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + parent := NameKey("SQParent", "TestFilters"+suffix, nil) + now := timeNow.Truncate(time.Millisecond).Unix() + children := []*SQChild{ + {I: 0, T: now, U: now}, + {I: 1, T: now, U: now}, + {I: 2, T: now, U: now}, + {I: 3, T: now, U: now}, + {I: 4, T: now, U: now}, + {I: 5, T: now, U: now}, + {I: 6, T: now, U: now}, + {I: 7, T: now, U: now}, + } + baseQuery := NewQuery("SQChild").Ancestor(parent).Filter("T=", now) + testSmallQueries(ctx, t, client, parent, children, []SQTestCase{ + { + "I>1", + baseQuery.Filter("I>", 1), + 6, + 2 + 3 + 4 + 5 + 6 + 7, + }, + { + "I>2 AND I<=5", + baseQuery.Filter("I>", 2).Filter("I<=", 5), + 3, + 3 + 4 + 5, + }, + { + "I>=3 AND I<3", + baseQuery.Filter("I>=", 3).Filter("I<", 3), + 0, + 0, + }, + { + "I=4", + baseQuery.Filter("I=", 4), + 1, + 4, + }, + }, func() { + got := []*SQChild{} + want := []*SQChild{ + {I: 0, T: now, U: now}, + {I: 1, T: now, U: now}, + {I: 2, T: now, U: now}, + {I: 3, T: now, U: now}, + {I: 4, T: now, U: now}, + {I: 5, T: now, U: now}, + {I: 6, T: now, U: now}, + {I: 7, T: now, U: now}, + } + _, err := client.GetAll(ctx, baseQuery.Order("I"), &got) + if err != nil { + t.Errorf("client.GetAll: %v", err) + } + if !testutil.Equal(got, want) { + t.Errorf("compare: got=%v, want=%v", got, want) + } + }, func() { + got := []*SQChild{} + want := []*SQChild{ + {I: 7, T: now, U: now}, + {I: 6, T: now, U: now}, + {I: 5, T: now, U: now}, + {I: 4, T: now, U: now}, + {I: 3, T: now, U: now}, + {I: 2, T: now, U: now}, + {I: 1, T: now, U: now}, + {I: 0, T: now, U: now}, + } + _, err := client.GetAll(ctx, baseQuery.Order("-I"), &got) + if err != nil { + t.Errorf("client.GetAll: %v", err) + } + if !testutil.Equal(got, want) { + t.Errorf("compare: got=%v, want=%v", got, want) + } + }) +} + +type ckey struct{} + +func TestLargeQuery(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + parent := NameKey("LQParent", "TestFilters"+suffix, nil) + now := timeNow.Truncate(time.Millisecond).Unix() + + // Make a large number of children entities. + const n = 800 + children := make([]*SQChild, 0, n) + keys := make([]*Key, 0, n) + for i := 0; i < n; i++ { + children = append(children, &SQChild{I: i, T: now, U: now}) + keys = append(keys, IncompleteKey("SQChild", parent)) + } + + // Store using PutMulti in batches. + const batchSize = 500 + for i := 0; i < n; i = i + 500 { + j := i + batchSize + if j > n { + j = n + } + fullKeys, err := client.PutMulti(ctx, keys[i:j], children[i:j]) + if err != nil { + t.Fatalf("PutMulti(%d, %d): %v", i, j, err) + } + defer func() { + err := client.DeleteMulti(ctx, fullKeys) + if err != nil { + t.Errorf("client.DeleteMulti: %v", err) + } + }() + } + + q := NewQuery("SQChild").Ancestor(parent).Filter("T=", now).Order("I") + + // Wait group to allow us to run query tests in parallel below. + var wg sync.WaitGroup + + // Check we get the expected count and results for various limits/offsets. + queryTests := []struct { + limit, offset, want int + }{ + // Just limit. + {limit: 0, want: 0}, + {limit: 100, want: 100}, + {limit: 501, want: 501}, + {limit: n, want: n}, + {limit: n * 2, want: n}, + {limit: -1, want: n}, + // Just offset. + {limit: -1, offset: 100, want: n - 100}, + {limit: -1, offset: 500, want: n - 500}, + {limit: -1, offset: n, want: 0}, + // Limit and offset. + {limit: 100, offset: 100, want: 100}, + {limit: 1000, offset: 100, want: n - 100}, + {limit: 500, offset: 500, want: n - 500}, + } + for _, tt := range queryTests { + q := q.Limit(tt.limit).Offset(tt.offset) + wg.Add(1) + + go func(limit, offset, want int) { + defer wg.Done() + // Check Count returns the expected number of results. + count, err := client.Count(ctx, q) + if err != nil { + t.Errorf("client.Count(limit=%d offset=%d): %v", limit, offset, err) + return + } + if count != want { + t.Errorf("Count(limit=%d offset=%d) returned %d, want %d", limit, offset, count, want) + } + + var got []SQChild + _, err = client.GetAll(ctx, q, &got) + if err != nil { + t.Errorf("client.GetAll(limit=%d offset=%d): %v", limit, offset, err) + return + } + if len(got) != want { + t.Errorf("GetAll(limit=%d offset=%d) returned %d, want %d", limit, offset, len(got), want) + } + for i, child := range got { + if got, want := child.I, i+offset; got != want { + t.Errorf("GetAll(limit=%d offset=%d) got[%d].I == %d; want %d", limit, offset, i, got, want) + break + } + } + }(tt.limit, tt.offset, tt.want) + } + + // Also check iterator cursor behaviour. + cursorTests := []struct { + limit, offset int // Query limit and offset. + count int // The number of times to call "next" + want int // The I value of the desired element, -1 for "Done". + }{ + // No limits. + {count: 0, limit: -1, want: 0}, + {count: 5, limit: -1, want: 5}, + {count: 500, limit: -1, want: 500}, + {count: 1000, limit: -1, want: -1}, // No more results. + // Limits. + {count: 5, limit: 5, want: 5}, + {count: 500, limit: 5, want: 5}, + {count: 1000, limit: 1000, want: -1}, // No more results. + // Offsets. + {count: 0, offset: 5, limit: -1, want: 5}, + {count: 5, offset: 5, limit: -1, want: 10}, + {count: 200, offset: 500, limit: -1, want: 700}, + {count: 200, offset: 1000, limit: -1, want: -1}, // No more results. + } + for _, tt := range cursorTests { + wg.Add(1) + + go func(count, limit, offset, want int) { + defer wg.Done() + + ctx := context.WithValue(ctx, ckey{}, fmt.Sprintf("c=%d,l=%d,o=%d", count, limit, offset)) + // Run iterator through count calls to Next. + it := client.Run(ctx, q.Limit(limit).Offset(offset).KeysOnly()) + for i := 0; i < count; i++ { + _, err := it.Next(nil) + if err == iterator.Done { + break + } + if err != nil { + t.Errorf("count=%d, limit=%d, offset=%d: it.Next failed at i=%d", count, limit, offset, i) + return + } + } + + // Grab the cursor. + cursor, err := it.Cursor() + if err != nil { + t.Errorf("count=%d, limit=%d, offset=%d: it.Cursor: %v", count, limit, offset, err) + return + } + + // Make a request for the next element. + it = client.Run(ctx, q.Limit(1).Start(cursor)) + var entity SQChild + _, err = it.Next(&entity) + switch { + case want == -1: + if err != iterator.Done { + t.Errorf("count=%d, limit=%d, offset=%d: it.Next from cursor %v, want Done", count, limit, offset, err) + } + case err != nil: + t.Errorf("count=%d, limit=%d, offset=%d: it.Next from cursor: %v, want nil", count, limit, offset, err) + case entity.I != want: + t.Errorf("count=%d, limit=%d, offset=%d: got.I = %d, want %d", count, limit, offset, entity.I, want) + } + }(tt.count, tt.limit, tt.offset, tt.want) + } + wg.Wait() +} + +func TestEventualConsistency(t *testing.T) { + // TODO(jba): either make this actually test eventual consistency, or + // delete it. Currently it behaves the same with or without the + // EventualConsistency call. + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + parent := NameKey("SQParent", "TestEventualConsistency"+suffix, nil) + now := timeNow.Truncate(time.Millisecond).Unix() + children := []*SQChild{ + {I: 0, T: now, U: now}, + {I: 1, T: now, U: now}, + {I: 2, T: now, U: now}, + } + query := NewQuery("SQChild").Ancestor(parent).Filter("T =", now).EventualConsistency() + testSmallQueries(ctx, t, client, parent, children, nil, func() { + got, err := client.Count(ctx, query) + if err != nil { + t.Fatalf("Count: %v", err) + } + if got < 0 || 3 < got { + t.Errorf("Count: got %d, want [0,3]", got) + } + }) +} + +func TestProjection(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + parent := NameKey("SQParent", "TestProjection"+suffix, nil) + now := timeNow.Truncate(time.Millisecond).Unix() + children := []*SQChild{ + {I: 1 << 0, J: 100, T: now, U: now}, + {I: 1 << 1, J: 100, T: now, U: now}, + {I: 1 << 2, J: 200, T: now, U: now}, + {I: 1 << 3, J: 300, T: now, U: now}, + {I: 1 << 4, J: 300, T: now, U: now}, + } + baseQuery := NewQuery("SQChild").Ancestor(parent).Filter("T=", now).Filter("J>", 150) + testSmallQueries(ctx, t, client, parent, children, []SQTestCase{ + { + "project", + baseQuery.Project("J"), + 3, + 200 + 300 + 300, + }, + { + "distinct", + baseQuery.Project("J").Distinct(), + 2, + 200 + 300, + }, + { + "distinct on", + baseQuery.Project("J").DistinctOn("J"), + 2, + 200 + 300, + }, + { + "project on meaningful (GD_WHEN) field", + baseQuery.Project("U"), + 3, + 0, + }, + }) +} + +func TestAllocateIDs(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + keys := make([]*Key, 5) + for i := range keys { + keys[i] = IncompleteKey("AllocID", nil) + } + keys, err := client.AllocateIDs(ctx, keys) + if err != nil { + t.Errorf("AllocID #0 failed: %v", err) + } + if want := len(keys); want != 5 { + t.Errorf("Expected to allocate 5 keys, %d keys are found", want) + } + for _, k := range keys { + if k.Incomplete() { + t.Errorf("Unexpeceted incomplete key found: %v", k) + } + } +} + +func TestGetAllWithFieldMismatch(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + type Fat struct { + X, Y int + } + type Thin struct { + X int + } + + // Ancestor queries (those within an entity group) are strongly consistent + // by default, which prevents a test from being flaky. + // See https://cloud.google.com/appengine/docs/go/datastore/queries#Go_Data_consistency + // for more information. + parent := NameKey("SQParent", "TestGetAllWithFieldMismatch"+suffix, nil) + putKeys := make([]*Key, 3) + for i := range putKeys { + putKeys[i] = IDKey("GetAllThing", int64(10+i), parent) + _, err := client.Put(ctx, putKeys[i], &Fat{X: 20 + i, Y: 30 + i}) + if err != nil { + t.Fatalf("client.Put: %v", err) + } + } + + var got []Thin + want := []Thin{ + {X: 20}, + {X: 21}, + {X: 22}, + } + getKeys, err := client.GetAll(ctx, NewQuery("GetAllThing").Ancestor(parent), &got) + if len(getKeys) != 3 && !testutil.Equal(getKeys, putKeys) { + t.Errorf("client.GetAll: keys differ\ngetKeys=%v\nputKeys=%v", getKeys, putKeys) + } + if !testutil.Equal(got, want) { + t.Errorf("client.GetAll: entities differ\ngot =%v\nwant=%v", got, want) + } + if _, ok := err.(*ErrFieldMismatch); !ok { + t.Errorf("client.GetAll: got err=%v, want ErrFieldMismatch", err) + } +} + +func TestKindlessQueries(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + type Dee struct { + I int + Why string + } + type Dum struct { + I int + Pling string + } + + parent := NameKey("Tweedle", "tweedle"+suffix, nil) + + keys := []*Key{ + NameKey("Dee", "dee0", parent), + NameKey("Dum", "dum1", parent), + NameKey("Dum", "dum2", parent), + NameKey("Dum", "dum3", parent), + } + src := []interface{}{ + &Dee{1, "binary0001"}, + &Dum{2, "binary0010"}, + &Dum{4, "binary0100"}, + &Dum{8, "binary1000"}, + } + keys, err := client.PutMulti(ctx, keys, src) + if err != nil { + t.Fatalf("put: %v", err) + } + + testCases := []struct { + desc string + query *Query + want []int + wantErr string + }{ + { + desc: "Dee", + query: NewQuery("Dee"), + want: []int{1}, + }, + { + desc: "Doh", + query: NewQuery("Doh"), + want: nil}, + { + desc: "Dum", + query: NewQuery("Dum"), + want: []int{2, 4, 8}, + }, + { + desc: "", + query: NewQuery(""), + want: []int{1, 2, 4, 8}, + }, + { + desc: "Kindless filter", + query: NewQuery("").Filter("__key__ =", keys[2]), + want: []int{4}, + }, + { + desc: "Kindless order", + query: NewQuery("").Order("__key__"), + want: []int{1, 2, 4, 8}, + }, + { + desc: "Kindless bad filter", + query: NewQuery("").Filter("I =", 4), + wantErr: "kind is required", + }, + { + desc: "Kindless bad order", + query: NewQuery("").Order("-__key__"), + wantErr: "kind is required for all orders except __key__ ascending", + }, + } +loop: + for _, tc := range testCases { + q := tc.query.Ancestor(parent) + gotCount, err := client.Count(ctx, q) + if err != nil { + if tc.wantErr == "" || !strings.Contains(err.Error(), tc.wantErr) { + t.Errorf("count %q: err %v, want err %q", tc.desc, err, tc.wantErr) + } + continue + } + if tc.wantErr != "" { + t.Errorf("count %q: want err %q", tc.desc, tc.wantErr) + continue + } + if gotCount != len(tc.want) { + t.Errorf("count %q: got %d want %d", tc.desc, gotCount, len(tc.want)) + continue + } + var got []int + for iter := client.Run(ctx, q); ; { + var dst struct { + I int + Why, Pling string + } + _, err := iter.Next(&dst) + if err == iterator.Done { + break + } + if err != nil { + t.Errorf("iter.Next %q: %v", tc.desc, err) + continue loop + } + got = append(got, dst.I) + } + sort.Ints(got) + if !testutil.Equal(got, tc.want) { + t.Errorf("elems %q: got %+v want %+v", tc.desc, got, tc.want) + continue + } + } +} + +func TestTransaction(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + type Counter struct { + N int + T time.Time + } + + bangErr := errors.New("bang") + tests := []struct { + desc string + causeConflict []bool + retErr []error + want int + wantErr error + }{ + { + desc: "3 attempts, no conflicts", + causeConflict: []bool{false}, + retErr: []error{nil}, + want: 11, + }, + { + desc: "1 attempt, user error", + causeConflict: []bool{false}, + retErr: []error{bangErr}, + wantErr: bangErr, + }, + { + desc: "2 attempts, 1 conflict", + causeConflict: []bool{true, false}, + retErr: []error{nil, nil}, + want: 13, // Each conflict increments by 2. + }, + { + desc: "3 attempts, 3 conflicts", + causeConflict: []bool{true, true, true}, + retErr: []error{nil, nil, nil}, + wantErr: ErrConcurrentTransaction, + }, + } + + for i, tt := range tests { + // Put a new counter. + c := &Counter{N: 10, T: timeNow} + key, err := client.Put(ctx, IncompleteKey("TransCounter", nil), c) + if err != nil { + t.Errorf("%s: client.Put: %v", tt.desc, err) + continue + } + defer client.Delete(ctx, key) + + // Increment the counter in a transaction. + // The test case can manually cause a conflict or return an + // error at each attempt. + var attempts int + _, err = client.RunInTransaction(ctx, func(tx *Transaction) error { + attempts++ + if attempts > len(tt.causeConflict) { + return fmt.Errorf("too many attempts. Got %d, max %d", attempts, len(tt.causeConflict)) + } + + var c Counter + if err := tx.Get(key, &c); err != nil { + return err + } + c.N++ + if _, err := tx.Put(key, &c); err != nil { + return err + } + + if tt.causeConflict[attempts-1] { + c.N++ + if _, err := client.Put(ctx, key, &c); err != nil { + return err + } + } + + return tt.retErr[attempts-1] + }, MaxAttempts(i)) + + // Check the error returned by RunInTransaction. + if err != tt.wantErr { + t.Errorf("%s: got err %v, want %v", tt.desc, err, tt.wantErr) + continue + } + if err != nil { + continue + } + + // Check the final value of the counter. + if err := client.Get(ctx, key, c); err != nil { + t.Errorf("%s: client.Get: %v", tt.desc, err) + continue + } + if c.N != tt.want { + t.Errorf("%s: counter N=%d, want N=%d", tt.desc, c.N, tt.want) + } + } +} + +func TestReadOnlyTransaction(t *testing.T) { + if testing.Short() { + t.Skip("Integration tests skipped in short mode") + } + ctx := context.Background() + client := newClient(ctx, t, nil) + defer client.Close() + + type value struct{ N int } + + // Put a value. + const n = 5 + v := &value{N: n} + key, err := client.Put(ctx, IncompleteKey("roTxn", nil), v) + if err != nil { + t.Fatal(err) + } + defer client.Delete(ctx, key) + + // Read it from a read-only transaction. + _, err = client.RunInTransaction(ctx, func(tx *Transaction) error { + if err := tx.Get(key, v); err != nil { + return err + } + return nil + }, ReadOnly) + if err != nil { + t.Fatal(err) + } + if v.N != n { + t.Fatalf("got %d, want %d", v.N, n) + } + + // Attempting to write from a read-only transaction is an error. + _, err = client.RunInTransaction(ctx, func(tx *Transaction) error { + if _, err := tx.Put(key, v); err != nil { + return err + } + return nil + }, ReadOnly) + if err == nil { + t.Fatal("got nil, want error") + } +} + +func TestNilPointers(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + type X struct { + S string + } + + src := []*X{{"zero"}, {"one"}} + keys := []*Key{IncompleteKey("NilX", nil), IncompleteKey("NilX", nil)} + keys, err := client.PutMulti(ctx, keys, src) + if err != nil { + t.Fatalf("PutMulti: %v", err) + } + + // It's okay to store into a slice of nil *X. + xs := make([]*X, 2) + if err := client.GetMulti(ctx, keys, xs); err != nil { + t.Errorf("GetMulti: %v", err) + } else if !testutil.Equal(xs, src) { + t.Errorf("GetMulti fetched %v, want %v", xs, src) + } + + // It isn't okay to store into a single nil *X. + var x0 *X + if err, want := client.Get(ctx, keys[0], x0), ErrInvalidEntityType; err != want { + t.Errorf("Get: err %v; want %v", err, want) + } + + // Test that deleting with duplicate keys work. + keys = append(keys, keys...) + if err := client.DeleteMulti(ctx, keys); err != nil { + t.Errorf("Delete: %v", err) + } +} + +func TestNestedRepeatedElementNoIndex(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + type Inner struct { + Name string + Value string `datastore:",noindex"` + } + type Outer struct { + Config []Inner + } + m := &Outer{ + Config: []Inner{ + {Name: "short", Value: "a"}, + {Name: "long", Value: strings.Repeat("a", 2000)}, + }, + } + + key := NameKey("Nested", "Nested"+suffix, nil) + if _, err := client.Put(ctx, key, m); err != nil { + t.Fatalf("client.Put: %v", err) + } + if err := client.Delete(ctx, key); err != nil { + t.Fatalf("client.Delete: %v", err) + } +} + +func TestPointerFields(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + want := populatedPointers() + key, err := client.Put(ctx, IncompleteKey("pointers", nil), want) + if err != nil { + t.Fatal(err) + } + var got Pointers + if err := client.Get(ctx, key, &got); err != nil { + t.Fatal(err) + } + if got.Pi == nil || *got.Pi != *want.Pi { + t.Errorf("Pi: got %v, want %v", got.Pi, *want.Pi) + } + if got.Ps == nil || *got.Ps != *want.Ps { + t.Errorf("Ps: got %v, want %v", got.Ps, *want.Ps) + } + if got.Pb == nil || *got.Pb != *want.Pb { + t.Errorf("Pb: got %v, want %v", got.Pb, *want.Pb) + } + if got.Pf == nil || *got.Pf != *want.Pf { + t.Errorf("Pf: got %v, want %v", got.Pf, *want.Pf) + } + if got.Pg == nil || *got.Pg != *want.Pg { + t.Errorf("Pg: got %v, want %v", got.Pg, *want.Pg) + } + if got.Pt == nil || !got.Pt.Equal(*want.Pt) { + t.Errorf("Pt: got %v, want %v", got.Pt, *want.Pt) + } +} + +func TestMutate(t *testing.T) { + // test Client.Mutate + testMutate(t, func(ctx context.Context, client *Client, muts ...*Mutation) ([]*Key, error) { + return client.Mutate(ctx, muts...) + }) + // test Transaction.Mutate + testMutate(t, func(ctx context.Context, client *Client, muts ...*Mutation) ([]*Key, error) { + var pkeys []*PendingKey + commit, err := client.RunInTransaction(ctx, func(tx *Transaction) error { + var err error + pkeys, err = tx.Mutate(muts...) + return err + }) + if err != nil { + return nil, err + } + var keys []*Key + for _, pk := range pkeys { + keys = append(keys, commit.Key(pk)) + } + return keys, nil + }) +} + +func testMutate(t *testing.T, mutate func(ctx context.Context, client *Client, muts ...*Mutation) ([]*Key, error)) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + type T struct{ I int } + + check := func(k *Key, want interface{}) { + var x T + err := client.Get(ctx, k, &x) + switch want := want.(type) { + case error: + if err != want { + t.Errorf("key %s: got error %v, want %v", k, err, want) + } + case int: + if err != nil { + t.Fatalf("key %s: %v", k, err) + } + if x.I != want { + t.Errorf("key %s: got %d, want %d", k, x.I, want) + } + default: + panic("check: bad arg") + } + } + + keys, err := mutate(ctx, client, + NewInsert(IncompleteKey("t", nil), &T{1}), + NewUpsert(IncompleteKey("t", nil), &T{2}), + ) + if err != nil { + t.Fatal(err) + } + check(keys[0], 1) + check(keys[1], 2) + + _, err = mutate(ctx, client, + NewUpdate(keys[0], &T{3}), + NewDelete(keys[1]), + ) + if err != nil { + t.Fatal(err) + } + check(keys[0], 3) + check(keys[1], ErrNoSuchEntity) + + _, err = mutate(ctx, client, NewInsert(keys[0], &T{4})) + if got, want := status.Code(err), codes.AlreadyExists; got != want { + t.Errorf("Insert existing key: got %s, want %s", got, want) + } + + _, err = mutate(ctx, client, NewUpdate(keys[1], &T{4})) + if got, want := status.Code(err), codes.NotFound; got != want { + t.Errorf("Update non-existing key: got %s, want %s", got, want) + } +} diff --git a/vendor/cloud.google.com/go/datastore/key.go b/vendor/cloud.google.com/go/datastore/key.go new file mode 100644 index 00000000..778fa260 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/key.go @@ -0,0 +1,280 @@ +// Copyright 2014 Google LLC +// +// 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 datastore + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/gob" + "errors" + "strconv" + "strings" + + "github.com/golang/protobuf/proto" + pb "google.golang.org/genproto/googleapis/datastore/v1" +) + +// Key represents the datastore key for a stored entity. +type Key struct { + // Kind cannot be empty. + Kind string + // Either ID or Name must be zero for the Key to be valid. + // If both are zero, the Key is incomplete. + ID int64 + Name string + // Parent must either be a complete Key or nil. + Parent *Key + + // Namespace provides the ability to partition your data for multiple + // tenants. In most cases, it is not necessary to specify a namespace. + // See docs on datastore multitenancy for details: + // https://cloud.google.com/datastore/docs/concepts/multitenancy + Namespace string +} + +// Incomplete reports whether the key does not refer to a stored entity. +func (k *Key) Incomplete() bool { + return k.Name == "" && k.ID == 0 +} + +// valid returns whether the key is valid. +func (k *Key) valid() bool { + if k == nil { + return false + } + for ; k != nil; k = k.Parent { + if k.Kind == "" { + return false + } + if k.Name != "" && k.ID != 0 { + return false + } + if k.Parent != nil { + if k.Parent.Incomplete() { + return false + } + if k.Parent.Namespace != k.Namespace { + return false + } + } + } + return true +} + +// Equal reports whether two keys are equal. Two keys are equal if they are +// both nil, or if their kinds, IDs, names, namespaces and parents are equal. +func (k *Key) Equal(o *Key) bool { + for { + if k == nil || o == nil { + return k == o // if either is nil, both must be nil + } + if k.Namespace != o.Namespace || k.Name != o.Name || k.ID != o.ID || k.Kind != o.Kind { + return false + } + if k.Parent == nil && o.Parent == nil { + return true + } + k = k.Parent + o = o.Parent + } +} + +// marshal marshals the key's string representation to the buffer. +func (k *Key) marshal(b *bytes.Buffer) { + if k.Parent != nil { + k.Parent.marshal(b) + } + b.WriteByte('/') + b.WriteString(k.Kind) + b.WriteByte(',') + if k.Name != "" { + b.WriteString(k.Name) + } else { + b.WriteString(strconv.FormatInt(k.ID, 10)) + } +} + +// String returns a string representation of the key. +func (k *Key) String() string { + if k == nil { + return "" + } + b := bytes.NewBuffer(make([]byte, 0, 512)) + k.marshal(b) + return b.String() +} + +// Note: Fields not renamed compared to appengine gobKey struct +// This ensures gobs created by appengine can be read here, and vice/versa +type gobKey struct { + Kind string + StringID string + IntID int64 + Parent *gobKey + AppID string + Namespace string +} + +func keyToGobKey(k *Key) *gobKey { + if k == nil { + return nil + } + return &gobKey{ + Kind: k.Kind, + StringID: k.Name, + IntID: k.ID, + Parent: keyToGobKey(k.Parent), + Namespace: k.Namespace, + } +} + +func gobKeyToKey(gk *gobKey) *Key { + if gk == nil { + return nil + } + return &Key{ + Kind: gk.Kind, + Name: gk.StringID, + ID: gk.IntID, + Parent: gobKeyToKey(gk.Parent), + Namespace: gk.Namespace, + } +} + +// GobEncode marshals the key into a sequence of bytes +// using an encoding/gob.Encoder. +func (k *Key) GobEncode() ([]byte, error) { + buf := new(bytes.Buffer) + if err := gob.NewEncoder(buf).Encode(keyToGobKey(k)); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// GobDecode unmarshals a sequence of bytes using an encoding/gob.Decoder. +func (k *Key) GobDecode(buf []byte) error { + gk := new(gobKey) + if err := gob.NewDecoder(bytes.NewBuffer(buf)).Decode(gk); err != nil { + return err + } + *k = *gobKeyToKey(gk) + return nil +} + +// MarshalJSON marshals the key into JSON. +func (k *Key) MarshalJSON() ([]byte, error) { + return []byte(`"` + k.Encode() + `"`), nil +} + +// UnmarshalJSON unmarshals a key JSON object into a Key. +func (k *Key) UnmarshalJSON(buf []byte) error { + if len(buf) < 2 || buf[0] != '"' || buf[len(buf)-1] != '"' { + return errors.New("datastore: bad JSON key") + } + k2, err := DecodeKey(string(buf[1 : len(buf)-1])) + if err != nil { + return err + } + *k = *k2 + return nil +} + +// Encode returns an opaque representation of the key +// suitable for use in HTML and URLs. +// This is compatible with the Python and Java runtimes. +func (k *Key) Encode() string { + pKey := keyToProto(k) + + b, err := proto.Marshal(pKey) + if err != nil { + panic(err) + } + + // Trailing padding is stripped. + return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=") +} + +// DecodeKey decodes a key from the opaque representation returned by Encode. +func DecodeKey(encoded string) (*Key, error) { + // Re-add padding. + if m := len(encoded) % 4; m != 0 { + encoded += strings.Repeat("=", 4-m) + } + + b, err := base64.URLEncoding.DecodeString(encoded) + if err != nil { + return nil, err + } + + pKey := new(pb.Key) + if err := proto.Unmarshal(b, pKey); err != nil { + return nil, err + } + return protoToKey(pKey) +} + +// AllocateIDs accepts a slice of incomplete keys and returns a +// slice of complete keys that are guaranteed to be valid in the datastore. +func (c *Client) AllocateIDs(ctx context.Context, keys []*Key) ([]*Key, error) { + if keys == nil { + return nil, nil + } + + req := &pb.AllocateIdsRequest{ + ProjectId: c.dataset, + Keys: multiKeyToProto(keys), + } + resp, err := c.client.AllocateIds(ctx, req) + if err != nil { + return nil, err + } + + return multiProtoToKey(resp.Keys) +} + +// IncompleteKey creates a new incomplete key. +// The supplied kind cannot be empty. +// The namespace of the new key is empty. +func IncompleteKey(kind string, parent *Key) *Key { + return &Key{ + Kind: kind, + Parent: parent, + } +} + +// NameKey creates a new key with a name. +// The supplied kind cannot be empty. +// The supplied parent must either be a complete key or nil. +// The namespace of the new key is empty. +func NameKey(kind, name string, parent *Key) *Key { + return &Key{ + Kind: kind, + Name: name, + Parent: parent, + } +} + +// IDKey creates a new key with an ID. +// The supplied kind cannot be empty. +// The supplied parent must either be a complete key or nil. +// The namespace of the new key is empty. +func IDKey(kind string, id int64, parent *Key) *Key { + return &Key{ + Kind: kind, + ID: id, + Parent: parent, + } +} diff --git a/vendor/cloud.google.com/go/datastore/key_test.go b/vendor/cloud.google.com/go/datastore/key_test.go new file mode 100644 index 00000000..eaa81cf8 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/key_test.go @@ -0,0 +1,210 @@ +// Copyright 2014 Google LLC +// +// 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 datastore + +import ( + "bytes" + "encoding/gob" + "encoding/json" + "testing" +) + +func TestEqual(t *testing.T) { + testCases := []struct { + x, y *Key + equal bool + }{ + { + x: nil, + y: nil, + equal: true, + }, + { + x: &Key{Kind: "kindA"}, + y: &Key{Kind: "kindA"}, + equal: true, + }, + { + x: &Key{Kind: "kindA", Name: "nameA"}, + y: &Key{Kind: "kindA", Name: "nameA"}, + equal: true, + }, + { + x: &Key{Kind: "kindA", Name: "nameA", Namespace: "gopherspace"}, + y: &Key{Kind: "kindA", Name: "nameA", Namespace: "gopherspace"}, + equal: true, + }, + { + x: &Key{Kind: "kindA", ID: 1337, Parent: &Key{Kind: "kindX", Name: "nameX"}}, + y: &Key{Kind: "kindA", ID: 1337, Parent: &Key{Kind: "kindX", Name: "nameX"}}, + equal: true, + }, + { + x: &Key{Kind: "kindA", Name: "nameA"}, + y: &Key{Kind: "kindB", Name: "nameA"}, + equal: false, + }, + { + x: &Key{Kind: "kindA", Name: "nameA"}, + y: &Key{Kind: "kindA", Name: "nameB"}, + equal: false, + }, + { + x: &Key{Kind: "kindA", Name: "nameA"}, + y: &Key{Kind: "kindA", ID: 1337}, + equal: false, + }, + { + x: &Key{Kind: "kindA", Name: "nameA"}, + y: &Key{Kind: "kindA", Name: "nameA", Namespace: "gopherspace"}, + equal: false, + }, + { + x: &Key{Kind: "kindA", ID: 1337, Parent: &Key{Kind: "kindX", Name: "nameX"}}, + y: &Key{Kind: "kindA", ID: 1337, Parent: &Key{Kind: "kindY", Name: "nameX"}}, + equal: false, + }, + { + x: &Key{Kind: "kindA", ID: 1337, Parent: &Key{Kind: "kindX", Name: "nameX"}}, + y: &Key{Kind: "kindA", ID: 1337}, + equal: false, + }, + } + + for _, tt := range testCases { + if got := tt.x.Equal(tt.y); got != tt.equal { + t.Errorf("Equal(%v, %v) = %t; want %t", tt.x, tt.y, got, tt.equal) + } + if got := tt.y.Equal(tt.x); got != tt.equal { + t.Errorf("Equal(%v, %v) = %t; want %t", tt.y, tt.x, got, tt.equal) + } + } +} + +func TestEncoding(t *testing.T) { + testCases := []struct { + k *Key + valid bool + }{ + { + k: nil, + valid: false, + }, + { + k: &Key{}, + valid: false, + }, + { + k: &Key{Kind: "kindA"}, + valid: true, + }, + { + k: &Key{Kind: "kindA", Namespace: "gopherspace"}, + valid: true, + }, + { + k: &Key{Kind: "kindA", Name: "nameA"}, + valid: true, + }, + { + k: &Key{Kind: "kindA", ID: 1337}, + valid: true, + }, + { + k: &Key{Kind: "kindA", Name: "nameA", ID: 1337}, + valid: false, + }, + { + k: &Key{Kind: "kindA", Parent: &Key{Kind: "kindB", Name: "nameB"}}, + valid: true, + }, + { + k: &Key{Kind: "kindA", Parent: &Key{Kind: "kindB"}}, + valid: false, + }, + { + k: &Key{Kind: "kindA", Parent: &Key{Kind: "kindB", Name: "nameB", Namespace: "gopherspace"}}, + valid: false, + }, + } + + for _, tt := range testCases { + if got := tt.k.valid(); got != tt.valid { + t.Errorf("valid(%v) = %t; want %t", tt.k, got, tt.valid) + } + + // Check encoding/decoding for valid keys. + if !tt.valid { + continue + } + enc := tt.k.Encode() + dec, err := DecodeKey(enc) + if err != nil { + t.Errorf("DecodeKey(%q) from %v: %v", enc, tt.k, err) + continue + } + if !tt.k.Equal(dec) { + t.Logf("Proto: %s", keyToProto(tt.k)) + t.Errorf("Decoded key %v not equal to %v", dec, tt.k) + } + + b, err := json.Marshal(tt.k) + if err != nil { + t.Errorf("json.Marshal(%v): %v", tt.k, err) + continue + } + key := &Key{} + if err := json.Unmarshal(b, key); err != nil { + t.Errorf("json.Unmarshal(%s) for key %v: %v", b, tt.k, err) + continue + } + if !tt.k.Equal(key) { + t.Errorf("JSON decoded key %v not equal to %v", dec, tt.k) + } + + buf := &bytes.Buffer{} + gobEnc := gob.NewEncoder(buf) + if err := gobEnc.Encode(tt.k); err != nil { + t.Errorf("gobEnc.Encode(%v): %v", tt.k, err) + continue + } + gobDec := gob.NewDecoder(buf) + key = &Key{} + if err := gobDec.Decode(key); err != nil { + t.Errorf("gobDec.Decode() for key %v: %v", tt.k, err) + } + if !tt.k.Equal(key) { + t.Errorf("gob decoded key %v not equal to %v", dec, tt.k) + } + } +} + +func TestInvalidKeyDecode(t *testing.T) { + // Check that decoding an invalid key returns an err and doesn't panic. + enc := NameKey("Kind", "Foo", nil).Encode() + + invalid := []string{ + "", + "Laboratorio", + enc + "Junk", + enc[:len(enc)-4], + } + for _, enc := range invalid { + key, err := DecodeKey(enc) + if err == nil || key != nil { + t.Errorf("DecodeKey(%q) = %v, %v; want nil, error", enc, key, err) + } + } +} diff --git a/vendor/cloud.google.com/go/datastore/load.go b/vendor/cloud.google.com/go/datastore/load.go new file mode 100644 index 00000000..61aa3ed2 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/load.go @@ -0,0 +1,509 @@ +// Copyright 2014 Google LLC +// +// 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 datastore + +import ( + "fmt" + "reflect" + "strings" + "time" + + "cloud.google.com/go/internal/fields" + pb "google.golang.org/genproto/googleapis/datastore/v1" +) + +var ( + typeOfByteSlice = reflect.TypeOf([]byte(nil)) + typeOfTime = reflect.TypeOf(time.Time{}) + typeOfGeoPoint = reflect.TypeOf(GeoPoint{}) + typeOfKeyPtr = reflect.TypeOf(&Key{}) + typeOfEntityPtr = reflect.TypeOf(&Entity{}) +) + +// typeMismatchReason returns a string explaining why the property p could not +// be stored in an entity field of type v.Type(). +func typeMismatchReason(p Property, v reflect.Value) string { + entityType := "empty" + switch p.Value.(type) { + case int64: + entityType = "int" + case bool: + entityType = "bool" + case string: + entityType = "string" + case float64: + entityType = "float" + case *Key: + entityType = "*datastore.Key" + case *Entity: + entityType = "*datastore.Entity" + case GeoPoint: + entityType = "GeoPoint" + case time.Time: + entityType = "time.Time" + case []byte: + entityType = "[]byte" + } + + return fmt.Sprintf("type mismatch: %s versus %v", entityType, v.Type()) +} + +func overflowReason(x interface{}, v reflect.Value) string { + return fmt.Sprintf("value %v overflows struct field of type %v", x, v.Type()) +} + +type propertyLoader struct { + // m holds the number of times a substruct field like "Foo.Bar.Baz" has + // been seen so far. The map is constructed lazily. + m map[string]int +} + +func (l *propertyLoader) load(codec fields.List, structValue reflect.Value, p Property, prev map[string]struct{}) string { + sl, ok := p.Value.([]interface{}) + if !ok { + return l.loadOneElement(codec, structValue, p, prev) + } + for _, val := range sl { + p.Value = val + if errStr := l.loadOneElement(codec, structValue, p, prev); errStr != "" { + return errStr + } + } + return "" +} + +// loadOneElement loads the value of Property p into structValue based on the provided +// codec. codec is used to find the field in structValue into which p should be loaded. +// prev is the set of property names already seen for structValue. +func (l *propertyLoader) loadOneElement(codec fields.List, structValue reflect.Value, p Property, prev map[string]struct{}) string { + var sliceOk bool + var sliceIndex int + var v reflect.Value + + name := p.Name + fieldNames := strings.Split(name, ".") + + for len(fieldNames) > 0 { + var field *fields.Field + + // Start by trying to find a field with name. If none found, + // cut off the last field (delimited by ".") and find its parent + // in the codec. + // eg. for name "A.B.C.D", split off "A.B.C" and try to + // find a field in the codec with this name. + // Loop again with "A.B", etc. + for i := len(fieldNames); i > 0; i-- { + parent := strings.Join(fieldNames[:i], ".") + field = codec.Match(parent) + if field != nil { + fieldNames = fieldNames[i:] + break + } + } + + // If we never found a matching field in the codec, return + // error message. + if field == nil { + return "no such struct field" + } + + v = initField(structValue, field.Index) + if !v.IsValid() { + return "no such struct field" + } + if !v.CanSet() { + return "cannot set struct field" + } + + // If field implements PLS, we delegate loading to the PLS's Load early, + // and stop iterating through fields. + ok, err := plsFieldLoad(v, p, fieldNames) + if err != nil { + return err.Error() + } + if ok { + return "" + } + + if field.Type.Kind() == reflect.Struct { + codec, err = structCache.Fields(field.Type) + if err != nil { + return err.Error() + } + structValue = v + } + + // If the element is a slice, we need to accommodate it. + if v.Kind() == reflect.Slice && v.Type() != typeOfByteSlice { + if l.m == nil { + l.m = make(map[string]int) + } + sliceIndex = l.m[p.Name] + l.m[p.Name] = sliceIndex + 1 + for v.Len() <= sliceIndex { + v.Set(reflect.Append(v, reflect.New(v.Type().Elem()).Elem())) + } + structValue = v.Index(sliceIndex) + + // If structValue implements PLS, we delegate loading to the PLS's + // Load early, and stop iterating through fields. + ok, err := plsFieldLoad(structValue, p, fieldNames) + if err != nil { + return err.Error() + } + if ok { + return "" + } + + if structValue.Type().Kind() == reflect.Struct { + codec, err = structCache.Fields(structValue.Type()) + if err != nil { + return err.Error() + } + } + sliceOk = true + } + } + + var slice reflect.Value + if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 { + slice = v + v = reflect.New(v.Type().Elem()).Elem() + } else if _, ok := prev[p.Name]; ok && !sliceOk { + // Zero the field back out that was set previously, turns out + // it's a slice and we don't know what to do with it + v.Set(reflect.Zero(v.Type())) + return "multiple-valued property requires a slice field type" + } + + prev[p.Name] = struct{}{} + + if errReason := setVal(v, p); errReason != "" { + // Set the slice back to its zero value. + if slice.IsValid() { + slice.Set(reflect.Zero(slice.Type())) + } + return errReason + } + + if slice.IsValid() { + slice.Index(sliceIndex).Set(v) + } + + return "" +} + +// plsFieldLoad first tries to converts v's value to a PLS, then v's addressed +// value to a PLS. If neither succeeds, plsFieldLoad returns false for first return +// value. Otherwise, the first return value will be true. +// If v is successfully converted to a PLS, plsFieldLoad will then try to Load +// the property p into v (by way of the PLS's Load method). +// +// If the field v has been flattened, the Property's name must be altered +// before calling Load to reflect the field v. +// For example, if our original field name was "A.B.C.D", +// and at this point in iteration we had initialized the field +// corresponding to "A" and have moved into the struct, so that now +// v corresponds to the field named "B", then we want to let the +// PLS handle this field (B)'s subfields ("C", "D"), +// so we send the property to the PLS's Load, renamed to "C.D". +// +// If subfields are present, the field v has been flattened. +func plsFieldLoad(v reflect.Value, p Property, subfields []string) (ok bool, err error) { + vpls, err := plsForLoad(v) + if err != nil { + return false, err + } + + if vpls == nil { + return false, nil + } + + // If Entity, load properties as well as key. + if e, ok := p.Value.(*Entity); ok { + err = loadEntity(vpls, e) + return true, err + } + + // If flattened, we must alter the property's name to reflect + // the field v. + if len(subfields) > 0 { + p.Name = strings.Join(subfields, ".") + } + + return true, vpls.Load([]Property{p}) +} + +// setVal sets 'v' to the value of the Property 'p'. +func setVal(v reflect.Value, p Property) (s string) { + pValue := p.Value + switch v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + x, ok := pValue.(int64) + if !ok && pValue != nil { + return typeMismatchReason(p, v) + } + if v.OverflowInt(x) { + return overflowReason(x, v) + } + v.SetInt(x) + case reflect.Bool: + x, ok := pValue.(bool) + if !ok && pValue != nil { + return typeMismatchReason(p, v) + } + v.SetBool(x) + case reflect.String: + x, ok := pValue.(string) + if !ok && pValue != nil { + return typeMismatchReason(p, v) + } + v.SetString(x) + case reflect.Float32, reflect.Float64: + x, ok := pValue.(float64) + if !ok && pValue != nil { + return typeMismatchReason(p, v) + } + if v.OverflowFloat(x) { + return overflowReason(x, v) + } + v.SetFloat(x) + case reflect.Ptr: + // v must be a pointer to either a Key, an Entity, or one of the supported basic types. + if v.Type() != typeOfKeyPtr && v.Type().Elem().Kind() != reflect.Struct && !isValidPointerType(v.Type().Elem()) { + return typeMismatchReason(p, v) + } + + if pValue == nil { + // If v is populated already, set it to nil. + if !v.IsNil() { + v.Set(reflect.New(v.Type()).Elem()) + } + return "" + } + + if x, ok := p.Value.(*Key); ok { + if _, ok := v.Interface().(*Key); !ok { + return typeMismatchReason(p, v) + } + v.Set(reflect.ValueOf(x)) + return "" + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + switch x := pValue.(type) { + case *Entity: + err := loadEntity(v.Interface(), x) + if err != nil { + return err.Error() + } + case int64: + if v.Elem().OverflowInt(x) { + return overflowReason(x, v.Elem()) + } + v.Elem().SetInt(x) + case float64: + if v.Elem().OverflowFloat(x) { + return overflowReason(x, v.Elem()) + } + v.Elem().SetFloat(x) + case bool: + v.Elem().SetBool(x) + case string: + v.Elem().SetString(x) + case GeoPoint, time.Time: + v.Elem().Set(reflect.ValueOf(x)) + default: + return typeMismatchReason(p, v) + } + case reflect.Struct: + switch v.Type() { + case typeOfTime: + x, ok := pValue.(time.Time) + if !ok && pValue != nil { + return typeMismatchReason(p, v) + } + v.Set(reflect.ValueOf(x)) + case typeOfGeoPoint: + x, ok := pValue.(GeoPoint) + if !ok && pValue != nil { + return typeMismatchReason(p, v) + } + v.Set(reflect.ValueOf(x)) + default: + ent, ok := pValue.(*Entity) + if !ok { + return typeMismatchReason(p, v) + } + err := loadEntity(v.Addr().Interface(), ent) + if err != nil { + return err.Error() + } + } + case reflect.Slice: + x, ok := pValue.([]byte) + if !ok && pValue != nil { + return typeMismatchReason(p, v) + } + if v.Type().Elem().Kind() != reflect.Uint8 { + return typeMismatchReason(p, v) + } + v.SetBytes(x) + default: + return typeMismatchReason(p, v) + } + return "" +} + +// initField is similar to reflect's Value.FieldByIndex, in that it +// returns the nested struct field corresponding to index, but it +// initialises any nil pointers encountered when traversing the structure. +func initField(val reflect.Value, index []int) reflect.Value { + for _, i := range index[:len(index)-1] { + val = val.Field(i) + if val.Kind() == reflect.Ptr { + if val.IsNil() { + val.Set(reflect.New(val.Type().Elem())) + } + val = val.Elem() + } + } + return val.Field(index[len(index)-1]) +} + +// loadEntityProto loads an EntityProto into PropertyLoadSaver or struct pointer. +func loadEntityProto(dst interface{}, src *pb.Entity) error { + ent, err := protoToEntity(src) + if err != nil { + return err + } + return loadEntity(dst, ent) +} + +func loadEntity(dst interface{}, ent *Entity) error { + if pls, ok := dst.(PropertyLoadSaver); ok { + err := pls.Load(ent.Properties) + if err != nil { + return err + } + if e, ok := dst.(KeyLoader); ok { + err = e.LoadKey(ent.Key) + } + return err + } + return loadEntityToStruct(dst, ent) +} + +func loadEntityToStruct(dst interface{}, ent *Entity) error { + pls, err := newStructPLS(dst) + if err != nil { + return err + } + + // Try and load key. + keyField := pls.codec.Match(keyFieldName) + if keyField != nil && ent.Key != nil { + pls.v.FieldByIndex(keyField.Index).Set(reflect.ValueOf(ent.Key)) + } + + // Load properties. + return pls.Load(ent.Properties) +} + +func (s structPLS) Load(props []Property) error { + var fieldName, errReason string + var l propertyLoader + + prev := make(map[string]struct{}) + for _, p := range props { + if errStr := l.load(s.codec, s.v, p, prev); errStr != "" { + // We don't return early, as we try to load as many properties as possible. + // It is valid to load an entity into a struct that cannot fully represent it. + // That case returns an error, but the caller is free to ignore it. + fieldName, errReason = p.Name, errStr + } + } + if errReason != "" { + return &ErrFieldMismatch{ + StructType: s.v.Type(), + FieldName: fieldName, + Reason: errReason, + } + } + return nil +} + +func protoToEntity(src *pb.Entity) (*Entity, error) { + props := make([]Property, 0, len(src.Properties)) + for name, val := range src.Properties { + v, err := propToValue(val) + if err != nil { + return nil, err + } + props = append(props, Property{ + Name: name, + Value: v, + NoIndex: val.ExcludeFromIndexes, + }) + } + var key *Key + if src.Key != nil { + // Ignore any error, since nested entity values + // are allowed to have an invalid key. + key, _ = protoToKey(src.Key) + } + + return &Entity{key, props}, nil +} + +// propToValue returns a Go value that represents the PropertyValue. For +// example, a TimestampValue becomes a time.Time. +func propToValue(v *pb.Value) (interface{}, error) { + switch v := v.ValueType.(type) { + case *pb.Value_NullValue: + return nil, nil + case *pb.Value_BooleanValue: + return v.BooleanValue, nil + case *pb.Value_IntegerValue: + return v.IntegerValue, nil + case *pb.Value_DoubleValue: + return v.DoubleValue, nil + case *pb.Value_TimestampValue: + return time.Unix(v.TimestampValue.Seconds, int64(v.TimestampValue.Nanos)), nil + case *pb.Value_KeyValue: + return protoToKey(v.KeyValue) + case *pb.Value_StringValue: + return v.StringValue, nil + case *pb.Value_BlobValue: + return []byte(v.BlobValue), nil + case *pb.Value_GeoPointValue: + return GeoPoint{Lat: v.GeoPointValue.Latitude, Lng: v.GeoPointValue.Longitude}, nil + case *pb.Value_EntityValue: + return protoToEntity(v.EntityValue) + case *pb.Value_ArrayValue: + arr := make([]interface{}, 0, len(v.ArrayValue.Values)) + for _, v := range v.ArrayValue.Values { + vv, err := propToValue(v) + if err != nil { + return nil, err + } + arr = append(arr, vv) + } + return arr, nil + default: + return nil, nil + } +} diff --git a/vendor/cloud.google.com/go/datastore/load_test.go b/vendor/cloud.google.com/go/datastore/load_test.go new file mode 100644 index 00000000..f381cdf0 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/load_test.go @@ -0,0 +1,909 @@ +// Copyright 2016 Google LLC +// +// 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 datastore + +import ( + "reflect" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + pb "google.golang.org/genproto/googleapis/datastore/v1" +) + +type Simple struct { + I int64 +} + +type SimpleWithTag struct { + I int64 `datastore:"II"` +} + +type NestedSimpleWithTag struct { + A SimpleWithTag `datastore:"AA"` +} + +type NestedSliceOfSimple struct { + A []Simple +} + +type SimpleTwoFields struct { + S string + SS string +} + +type NestedSimpleAnonymous struct { + Simple + X string +} + +type NestedSimple struct { + A Simple + I int +} + +type NestedSimple1 struct { + A Simple + X string +} + +type NestedSimple2X struct { + AA NestedSimple + A SimpleTwoFields + S string +} + +type BDotB struct { + B string `datastore:"B.B"` +} + +type ABDotB struct { + A BDotB +} + +type MultiAnonymous struct { + Simple + SimpleTwoFields + X string +} + +func TestLoadEntityNestedLegacy(t *testing.T) { + testCases := []struct { + desc string + src *pb.Entity + want interface{} + }{ + { + desc: "nested", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "X": {ValueType: &pb.Value_StringValue{StringValue: "two"}}, + "A.I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 2}}, + }, + }, + want: &NestedSimple1{ + A: Simple{I: 2}, + X: "two", + }, + }, + { + desc: "nested with tag", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "AA.II": {ValueType: &pb.Value_IntegerValue{IntegerValue: 2}}, + }, + }, + want: &NestedSimpleWithTag{ + A: SimpleWithTag{I: 2}, + }, + }, + { + desc: "nested with anonymous struct field", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "X": {ValueType: &pb.Value_StringValue{StringValue: "two"}}, + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 2}}, + }, + }, + want: &NestedSimpleAnonymous{ + Simple: Simple{I: 2}, + X: "two", + }, + }, + { + desc: "nested with dotted field tag", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "A.B.B": {ValueType: &pb.Value_StringValue{StringValue: "bb"}}, + }, + }, + want: &ABDotB{ + A: BDotB{ + B: "bb", + }, + }, + }, + { + desc: "nested with multiple anonymous fields", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 3}}, + "S": {ValueType: &pb.Value_StringValue{StringValue: "S"}}, + "SS": {ValueType: &pb.Value_StringValue{StringValue: "s"}}, + "X": {ValueType: &pb.Value_StringValue{StringValue: "s"}}, + }, + }, + want: &MultiAnonymous{ + Simple: Simple{I: 3}, + SimpleTwoFields: SimpleTwoFields{S: "S", SS: "s"}, + X: "s", + }, + }, + } + + for _, tc := range testCases { + dst := reflect.New(reflect.TypeOf(tc.want).Elem()).Interface() + err := loadEntityProto(dst, tc.src) + if err != nil { + t.Errorf("loadEntityProto: %s: %v", tc.desc, err) + continue + } + + if !testutil.Equal(tc.want, dst) { + t.Errorf("%s: compare:\ngot: %#v\nwant: %#v", tc.desc, dst, tc.want) + } + } +} + +type WithKey struct { + X string + I int + K *Key `datastore:"__key__"` +} + +type NestedWithKey struct { + Y string + N WithKey +} + +var ( + incompleteKey = newKey("", nil) + invalidKey = newKey("s", incompleteKey) +) + +func TestLoadEntityNested(t *testing.T) { + testCases := []struct { + desc string + src *pb.Entity + want interface{} + }{ + { + desc: "nested basic", + src: &pb.Entity{ + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 3}}, + }, + }, + }}, + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 10}}, + }, + }, + want: &NestedSimple{ + A: Simple{I: 3}, + I: 10, + }, + }, + { + desc: "nested with struct tags", + src: &pb.Entity{ + Properties: map[string]*pb.Value{ + "AA": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "II": {ValueType: &pb.Value_IntegerValue{IntegerValue: 1}}, + }, + }, + }}, + }, + }, + want: &NestedSimpleWithTag{ + A: SimpleWithTag{I: 1}, + }, + }, + { + desc: "nested 2x", + src: &pb.Entity{ + Properties: map[string]*pb.Value{ + "AA": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 3}}, + }, + }, + }}, + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 1}}, + }, + }, + }}, + "A": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "S": {ValueType: &pb.Value_StringValue{StringValue: "S"}}, + "SS": {ValueType: &pb.Value_StringValue{StringValue: "s"}}, + }, + }, + }}, + "S": {ValueType: &pb.Value_StringValue{StringValue: "SS"}}, + }, + }, + want: &NestedSimple2X{ + AA: NestedSimple{ + A: Simple{I: 3}, + I: 1, + }, + A: SimpleTwoFields{S: "S", SS: "s"}, + S: "SS", + }, + }, + { + desc: "nested anonymous", + src: &pb.Entity{ + Properties: map[string]*pb.Value{ + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 3}}, + "X": {ValueType: &pb.Value_StringValue{StringValue: "SomeX"}}, + }, + }, + want: &NestedSimpleAnonymous{ + Simple: Simple{I: 3}, + X: "SomeX", + }, + }, + { + desc: "nested simple with slice", + src: &pb.Entity{ + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_ArrayValue{ + ArrayValue: &pb.ArrayValue{ + Values: []*pb.Value{ + {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 3}}, + }, + }, + }}, + {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 4}}, + }, + }, + }}, + }, + }, + }}, + }, + }, + + want: &NestedSliceOfSimple{ + A: []Simple{{I: 3}, {I: 4}}, + }, + }, + { + desc: "nested with multiple anonymous fields", + src: &pb.Entity{ + Properties: map[string]*pb.Value{ + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 3}}, + "S": {ValueType: &pb.Value_StringValue{StringValue: "S"}}, + "SS": {ValueType: &pb.Value_StringValue{StringValue: "s"}}, + "X": {ValueType: &pb.Value_StringValue{StringValue: "ss"}}, + }, + }, + want: &MultiAnonymous{ + Simple: Simple{I: 3}, + SimpleTwoFields: SimpleTwoFields{S: "S", SS: "s"}, + X: "ss", + }, + }, + { + desc: "nested with dotted field tag", + src: &pb.Entity{ + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "B.B": {ValueType: &pb.Value_StringValue{StringValue: "bb"}}, + }, + }, + }}, + }, + }, + want: &ABDotB{ + A: BDotB{ + B: "bb", + }, + }, + }, + { + desc: "nested entity with key", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Y": {ValueType: &pb.Value_StringValue{StringValue: "yyy"}}, + "N": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Key: keyToProto(testKey1a), + Properties: map[string]*pb.Value{ + "X": {ValueType: &pb.Value_StringValue{StringValue: "two"}}, + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 2}}, + }, + }, + }}, + }, + }, + want: &NestedWithKey{ + Y: "yyy", + N: WithKey{ + X: "two", + I: 2, + K: testKey1a, + }, + }, + }, + { + desc: "nested entity with invalid key", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Y": {ValueType: &pb.Value_StringValue{StringValue: "yyy"}}, + "N": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Key: keyToProto(invalidKey), + Properties: map[string]*pb.Value{ + "X": {ValueType: &pb.Value_StringValue{StringValue: "two"}}, + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 2}}, + }, + }, + }}, + }, + }, + want: &NestedWithKey{ + Y: "yyy", + N: WithKey{ + X: "two", + I: 2, + K: invalidKey, + }, + }, + }, + } + + for _, tc := range testCases { + dst := reflect.New(reflect.TypeOf(tc.want).Elem()).Interface() + err := loadEntityProto(dst, tc.src) + if err != nil { + t.Errorf("loadEntityProto: %s: %v", tc.desc, err) + continue + } + + if !testutil.Equal(tc.want, dst) { + t.Errorf("%s: compare:\ngot: %#v\nwant: %#v", tc.desc, dst, tc.want) + } + } +} + +type NestedStructPtrs struct { + *SimpleTwoFields + Nest *SimpleTwoFields + TwiceNest *NestedSimple2 + I int +} + +type NestedSimple2 struct { + A *Simple + I int +} + +func TestAlreadyPopulatedDst(t *testing.T) { + testCases := []struct { + desc string + src *pb.Entity + dst interface{} + want interface{} + }{ + { + desc: "simple already populated, nil properties", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "I": {ValueType: &pb.Value_NullValue{}}, + }, + }, + dst: &Simple{ + I: 12, + }, + want: &Simple{}, + }, + { + desc: "nested structs already populated", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "SS": {ValueType: &pb.Value_StringValue{StringValue: "world"}}, + }, + }, + dst: &SimpleTwoFields{S: "hello" /* SS: "" */}, + want: &SimpleTwoFields{S: "hello", SS: "world"}, + }, + { + desc: "nested structs already populated, pValues nil", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "S": {ValueType: &pb.Value_NullValue{}}, + "SS": {ValueType: &pb.Value_StringValue{StringValue: "ss hello"}}, + "Nest": {ValueType: &pb.Value_NullValue{}}, + "TwiceNest": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_NullValue{}}, + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 2}}, + }, + }, + }}, + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 5}}, + }, + }, + dst: &NestedStructPtrs{ + &SimpleTwoFields{S: "hello" /* SS: "" */}, + &SimpleTwoFields{ /* S: "" */ SS: "twice hello"}, + &NestedSimple2{ + A: &Simple{I: 2}, + /* I: 0 */ + }, + 0, + }, + want: &NestedStructPtrs{ + &SimpleTwoFields{ /* S: "" */ SS: "ss hello"}, + nil, + &NestedSimple2{ + /* A: nil, */ + I: 2, + }, + 5, + }, + }, + } + + for _, tc := range testCases { + err := loadEntityProto(tc.dst, tc.src) + if err != nil { + t.Errorf("loadEntityProto: %s: %v", tc.desc, err) + continue + } + + if !testutil.Equal(tc.want, tc.dst) { + t.Errorf("%s: compare:\ngot: %#v\nwant: %#v", tc.desc, tc.dst, tc.want) + } + } +} + +type PLS0 struct { + A string +} + +func (p *PLS0) Load(props []Property) error { + for _, pp := range props { + if pp.Name == "A" { + p.A = pp.Value.(string) + } + } + return nil +} + +func (p *PLS0) Save() (props []Property, err error) { + return []Property{{Name: "A", Value: p.A}}, nil +} + +type KeyLoader1 struct { + A string + K *Key +} + +func (kl *KeyLoader1) Load(props []Property) error { + for _, pp := range props { + if pp.Name == "A" { + kl.A = pp.Value.(string) + } + } + return nil +} + +func (kl *KeyLoader1) Save() (props []Property, err error) { + return []Property{{Name: "A", Value: kl.A}}, nil +} + +func (kl *KeyLoader1) LoadKey(k *Key) error { + kl.K = k + return nil +} + +type KeyLoader2 struct { + B int + Key *Key +} + +func (kl *KeyLoader2) Load(props []Property) error { + for _, pp := range props { + if pp.Name == "B" { + kl.B = int(pp.Value.(int64)) + } + } + return nil +} + +func (kl *KeyLoader2) Save() (props []Property, err error) { + return []Property{{Name: "B", Value: int64(kl.B)}}, nil +} + +func (kl *KeyLoader2) LoadKey(k *Key) error { + kl.Key = k + return nil +} + +type KeyLoader3 struct { + C bool + K *Key +} + +func (kl *KeyLoader3) Load(props []Property) error { + for _, pp := range props { + if pp.Name == "C" { + kl.C = pp.Value.(bool) + } + } + return nil +} + +func (kl *KeyLoader3) Save() (props []Property, err error) { + return []Property{{Name: "C", Value: kl.C}}, nil +} + +func (kl *KeyLoader3) LoadKey(k *Key) error { + kl.K = k + return nil +} + +type KeyLoader4 struct { + PLS0 + K *Key +} + +func (kl *KeyLoader4) LoadKey(k *Key) error { + kl.K = k + return nil +} + +type NotKeyLoader struct { + A string + K *Key +} + +func (p *NotKeyLoader) Load(props []Property) error { + for _, pp := range props { + if pp.Name == "A" { + p.A = pp.Value.(string) + } + } + return nil +} + +func (p *NotKeyLoader) Save() (props []Property, err error) { + return []Property{{Name: "A", Value: p.A}}, nil +} + +type NotPLSKeyLoader struct { + A string + K *Key `datastore:"__key__"` +} + +type NestedKeyLoaders struct { + Two *KeyLoader2 + Three []*KeyLoader3 + Four *KeyLoader4 + PLS *NotKeyLoader +} + +func TestKeyLoader(t *testing.T) { + testCases := []struct { + desc string + src *pb.Entity + dst interface{} + want interface{} + }{ + { + desc: "simple key loader", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_StringValue{StringValue: "hello"}}, + }, + }, + dst: &KeyLoader1{}, + want: &KeyLoader1{ + A: "hello", + K: testKey0, + }, + }, + { + desc: "simple key loader with unmatched properties", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_StringValue{StringValue: "hello"}}, + "B": {ValueType: &pb.Value_StringValue{StringValue: "unmatched"}}, + }, + }, + dst: &NotPLSKeyLoader{}, + want: &NotPLSKeyLoader{ + A: "hello", + K: testKey0, + }, + }, + { + desc: "embedded PLS key loader", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_StringValue{StringValue: "hello"}}, + }, + }, + dst: &KeyLoader4{}, + want: &KeyLoader4{ + PLS0: PLS0{A: "hello"}, + K: testKey0, + }, + }, + { + desc: "nested key loaders", + src: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Two": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "B": {ValueType: &pb.Value_IntegerValue{IntegerValue: 12}}, + }, + Key: keyToProto(testKey1a), + }, + }}, + "Three": {ValueType: &pb.Value_ArrayValue{ + ArrayValue: &pb.ArrayValue{ + Values: []*pb.Value{ + {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "C": {ValueType: &pb.Value_BooleanValue{BooleanValue: true}}, + }, + Key: keyToProto(testKey1b), + }, + }}, + {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "C": {ValueType: &pb.Value_BooleanValue{BooleanValue: false}}, + }, + Key: keyToProto(testKey0), + }, + }}, + }, + }, + }}, + "Four": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_StringValue{StringValue: "testing"}}, + }, + Key: keyToProto(testKey2a), + }, + }}, + "PLS": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "A": {ValueType: &pb.Value_StringValue{StringValue: "something"}}, + }, + + Key: keyToProto(testKey1a), + }, + }}, + }, + }, + dst: &NestedKeyLoaders{}, + want: &NestedKeyLoaders{ + Two: &KeyLoader2{B: 12, Key: testKey1a}, + Three: []*KeyLoader3{ + { + C: true, + K: testKey1b, + }, + { + C: false, + K: testKey0, + }, + }, + Four: &KeyLoader4{ + PLS0: PLS0{A: "testing"}, + K: testKey2a, + }, + PLS: &NotKeyLoader{A: "something"}, + }, + }, + } + + for _, tc := range testCases { + err := loadEntityProto(tc.dst, tc.src) + if err != nil { + // While loadEntityProto may return an error, if that error is + // ErrFieldMismatch, then there is still data in tc.dst to compare. + if _, ok := err.(*ErrFieldMismatch); !ok { + t.Errorf("loadEntityProto: %s: %v", tc.desc, err) + continue + } + } + + if !testutil.Equal(tc.want, tc.dst) { + t.Errorf("%s: compare:\ngot: %+v\nwant: %+v", tc.desc, tc.dst, tc.want) + } + } +} + +func TestLoadPointers(t *testing.T) { + for _, test := range []struct { + desc string + in []Property + want Pointers + }{ + { + desc: "nil properties load as nil pointers", + in: []Property{ + {Name: "Pi", Value: nil}, + {Name: "Ps", Value: nil}, + {Name: "Pb", Value: nil}, + {Name: "Pf", Value: nil}, + {Name: "Pg", Value: nil}, + {Name: "Pt", Value: nil}, + }, + want: Pointers{}, + }, + { + desc: "missing properties load as nil pointers", + in: []Property(nil), + want: Pointers{}, + }, + { + desc: "non-nil properties load as the appropriate values", + in: []Property{ + {Name: "Pi", Value: int64(1)}, + {Name: "Ps", Value: "x"}, + {Name: "Pb", Value: true}, + {Name: "Pf", Value: 3.14}, + {Name: "Pg", Value: GeoPoint{Lat: 1, Lng: 2}}, + {Name: "Pt", Value: time.Unix(100, 0)}, + }, + want: func() Pointers { + p := populatedPointers() + *p.Pi = 1 + *p.Ps = "x" + *p.Pb = true + *p.Pf = 3.14 + *p.Pg = GeoPoint{Lat: 1, Lng: 2} + *p.Pt = time.Unix(100, 0) + return *p + }(), + }, + } { + var got Pointers + if err := LoadStruct(&got, test.in); err != nil { + t.Fatalf("%s: %v", test.desc, err) + } + if !testutil.Equal(got, test.want) { + t.Errorf("%s:\ngot %+v\nwant %+v", test.desc, got, test.want) + } + } +} + +func TestLoadNonArrayIntoSlice(t *testing.T) { + // Loading a non-array value into a slice field results in a slice of size 1. + var got struct{ S []string } + if err := LoadStruct(&got, []Property{{Name: "S", Value: "x"}}); err != nil { + t.Fatal(err) + } + if want := []string{"x"}; !testutil.Equal(got.S, want) { + t.Errorf("got %#v, want %#v", got.S, want) + } +} + +func TestLoadEmptyArrayIntoSlice(t *testing.T) { + // Loading an empty array into a slice field is a no-op. + var got = struct{ S []string }{[]string{"x"}} + if err := LoadStruct(&got, []Property{{Name: "S", Value: []interface{}{}}}); err != nil { + t.Fatal(err) + } + if want := []string{"x"}; !testutil.Equal(got.S, want) { + t.Errorf("got %#v, want %#v", got.S, want) + } +} + +func TestLoadNull(t *testing.T) { + // Loading a Datastore Null into a basic type (int, float, etc.) results in a zero value. + // Loading a Null into a slice of basic type results in a slice of size 1 containing the zero value. + // (As expected from the behavior of slices and nulls with basic types.) + type S struct { + I int64 + F float64 + S string + B bool + A []string + } + got := S{ + I: 1, + F: 1.0, + S: "1", + B: true, + A: []string{"X"}, + } + want := S{A: []string{""}} + props := []Property{{Name: "I"}, {Name: "F"}, {Name: "S"}, {Name: "B"}, {Name: "A"}} + if err := LoadStruct(&got, props); err != nil { + t.Fatal(err) + } + if !testutil.Equal(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } + + // Loading a Null into a pointer to struct field results in a nil field. + got2 := struct{ X *S }{X: &S{}} + if err := LoadStruct(&got2, []Property{{Name: "X"}}); err != nil { + t.Fatal(err) + } + if got2.X != nil { + t.Errorf("got %v, want nil", got2.X) + } + + // Loading a Null into a struct field is an error. + got3 := struct{ X S }{} + err := LoadStruct(&got3, []Property{{Name: "X"}}) + if err == nil { + t.Error("got nil, want error") + } +} + +// var got2 struct{ S []Pet } +// if err := LoadStruct(&got2, []Property{{Name: "S", Value: nil}}); err != nil { +// t.Fatal(err) +// } + +// } diff --git a/vendor/cloud.google.com/go/datastore/mutation.go b/vendor/cloud.google.com/go/datastore/mutation.go new file mode 100644 index 00000000..f80f9646 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/mutation.go @@ -0,0 +1,129 @@ +// Copyright 2018 Google LLC +// +// 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 datastore + +import ( + "fmt" + + pb "google.golang.org/genproto/googleapis/datastore/v1" +) + +// A Mutation represents a change to a Datastore entity. +type Mutation struct { + key *Key // needed for transaction PendingKeys and to dedup deletions + mut *pb.Mutation + err error +} + +func (m *Mutation) isDelete() bool { + _, ok := m.mut.Operation.(*pb.Mutation_Delete) + return ok +} + +// NewInsert creates a mutation that will save the entity src into the datastore with +// key k, returning an error if k already exists. +// See Client.Put for valid values of src. +func NewInsert(k *Key, src interface{}) *Mutation { + if !k.valid() { + return &Mutation{err: ErrInvalidKey} + } + p, err := saveEntity(k, src) + if err != nil { + return &Mutation{err: err} + } + return &Mutation{ + key: k, + mut: &pb.Mutation{Operation: &pb.Mutation_Insert{Insert: p}}, + } +} + +// NewUpsert creates a mutation that saves the entity src into the datastore with key +// k, whether or not k exists. See Client.Put for valid values of src. +func NewUpsert(k *Key, src interface{}) *Mutation { + if !k.valid() { + return &Mutation{err: ErrInvalidKey} + } + p, err := saveEntity(k, src) + if err != nil { + return &Mutation{err: err} + } + return &Mutation{ + key: k, + mut: &pb.Mutation{Operation: &pb.Mutation_Upsert{Upsert: p}}, + } +} + +// NewUpdate creates a mutation that replaces the entity in the datastore with key k, +// returning an error if k does not exist. See Client.Put for valid values of src. +func NewUpdate(k *Key, src interface{}) *Mutation { + if !k.valid() { + return &Mutation{err: ErrInvalidKey} + } + if k.Incomplete() { + return &Mutation{err: fmt.Errorf("datastore: can't update the incomplete key: %v", k)} + } + p, err := saveEntity(k, src) + if err != nil { + return &Mutation{err: err} + } + return &Mutation{ + key: k, + mut: &pb.Mutation{Operation: &pb.Mutation_Update{Update: p}}, + } +} + +// NewDelete creates a mutation that deletes the entity with key k. +func NewDelete(k *Key) *Mutation { + if !k.valid() { + return &Mutation{err: ErrInvalidKey} + } + if k.Incomplete() { + return &Mutation{err: fmt.Errorf("datastore: can't delete the incomplete key: %v", k)} + } + return &Mutation{ + key: k, + mut: &pb.Mutation{Operation: &pb.Mutation_Delete{Delete: keyToProto(k)}}, + } +} + +func mutationProtos(muts []*Mutation) ([]*pb.Mutation, error) { + // If any of the mutations have errors, collect and return them. + var merr MultiError + for i, m := range muts { + if m.err != nil { + if merr == nil { + merr = make(MultiError, len(muts)) + } + merr[i] = m.err + } + } + if merr != nil { + return nil, merr + } + var protos []*pb.Mutation + // Collect protos. Remove duplicate deletions (see deleteMutations). + seen := map[string]bool{} + for _, m := range muts { + if m.isDelete() { + ks := m.key.String() + if seen[ks] { + continue + } + seen[ks] = true + } + protos = append(protos, m.mut) + } + return protos, nil +} diff --git a/vendor/cloud.google.com/go/datastore/mutation_test.go b/vendor/cloud.google.com/go/datastore/mutation_test.go new file mode 100644 index 00000000..0d21141a --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/mutation_test.go @@ -0,0 +1,150 @@ +// Copyright 2018 Google LLC +// +// 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 datastore + +import ( + "testing" + + "cloud.google.com/go/internal/testutil" + pb "google.golang.org/genproto/googleapis/datastore/v1" +) + +func TestMutationProtos(t *testing.T) { + var keys []*Key + for i := 1; i <= 4; i++ { + k := IDKey("kind", int64(i), nil) + keys = append(keys, k) + } + entity := &PropertyList{{Name: "n", Value: "v"}} + entityForKey := func(k *Key) *pb.Entity { + return &pb.Entity{ + Key: keyToProto(k), + Properties: map[string]*pb.Value{ + "n": {ValueType: &pb.Value_StringValue{StringValue: "v"}}, + }, + } + } + for _, test := range []struct { + desc string + in []*Mutation + want []*pb.Mutation + }{ + { + desc: "nil", + in: nil, + want: nil, + }, + { + desc: "empty", + in: []*Mutation{}, + want: nil, + }, + { + desc: "various", + in: []*Mutation{ + NewInsert(keys[0], entity), + NewUpsert(keys[1], entity), + NewUpdate(keys[2], entity), + NewDelete(keys[3]), + }, + want: []*pb.Mutation{ + {Operation: &pb.Mutation_Insert{Insert: entityForKey(keys[0])}}, + {Operation: &pb.Mutation_Upsert{Upsert: entityForKey(keys[1])}}, + {Operation: &pb.Mutation_Update{Update: entityForKey(keys[2])}}, + {Operation: &pb.Mutation_Delete{Delete: keyToProto(keys[3])}}, + }, + }, + { + desc: "duplicate deletes", + in: []*Mutation{ + NewDelete(keys[0]), + NewInsert(keys[1], entity), + NewDelete(keys[0]), + NewDelete(keys[2]), + NewDelete(keys[0]), + }, + want: []*pb.Mutation{ + {Operation: &pb.Mutation_Delete{Delete: keyToProto(keys[0])}}, + {Operation: &pb.Mutation_Insert{Insert: entityForKey(keys[1])}}, + {Operation: &pb.Mutation_Delete{Delete: keyToProto(keys[2])}}, + }, + }, + } { + got, err := mutationProtos(test.in) + if err != nil { + t.Errorf("%s: %v", test.desc, err) + continue + } + if diff := testutil.Diff(got, test.want); diff != "" { + t.Errorf("%s: %s", test.desc, diff) + } + } +} + +func TestMutationProtosErrors(t *testing.T) { + entity := &PropertyList{{Name: "n", Value: "v"}} + k := IDKey("kind", 1, nil) + ik := IncompleteKey("kind", nil) + for _, test := range []struct { + desc string + in []*Mutation + want []int // non-nil indexes of MultiError + }{ + { + desc: "invalid key", + in: []*Mutation{ + NewInsert(nil, entity), + NewUpdate(nil, entity), + NewUpsert(nil, entity), + NewDelete(nil), + }, + want: []int{0, 1, 2, 3}, + }, + { + desc: "incomplete key", + in: []*Mutation{ + NewInsert(ik, entity), + NewUpdate(ik, entity), + NewUpsert(ik, entity), + NewDelete(ik), + }, + want: []int{1, 3}, + }, + { + desc: "bad entity", + in: []*Mutation{ + NewInsert(k, 1), + NewUpdate(k, 2), + NewUpsert(k, 3), + }, + want: []int{0, 1, 2}, + }, + } { + _, err := mutationProtos(test.in) + if err == nil { + t.Errorf("%s: got nil, want error", test.desc) + continue + } + var got []int + for i, err := range err.(MultiError) { + if err != nil { + got = append(got, i) + } + } + if !testutil.Equal(got, test.want) { + t.Errorf("%s: got errors at %v, want at %v", test.desc, got, test.want) + } + } +} diff --git a/vendor/cloud.google.com/go/datastore/oc_test.go b/vendor/cloud.google.com/go/datastore/oc_test.go new file mode 100644 index 00000000..be1e5a4f --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/oc_test.go @@ -0,0 +1,43 @@ +// Copyright 2018 Google LLC +// +// 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 datastore + +import ( + "context" + "testing" + + "cloud.google.com/go/internal/testutil" +) + +func TestOCTracing(t *testing.T) { + ctx := context.Background() + client := newTestClient(ctx, t) + defer client.Close() + + te := testutil.NewTestExporter() + defer te.Unregister() + + type SomeValue struct { + S string + } + _, err := client.Put(ctx, IncompleteKey("SomeKey", nil), &SomeValue{"foo"}) + if err != nil { + t.Fatalf("client.Put: %v", err) + } + + if len(te.Spans) == 0 { + t.Fatalf("Expected some span to be created, but got %d", 0) + } +} diff --git a/vendor/cloud.google.com/go/datastore/prop.go b/vendor/cloud.google.com/go/datastore/prop.go new file mode 100644 index 00000000..98084d03 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/prop.go @@ -0,0 +1,342 @@ +// Copyright 2014 Google LLC +// +// 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 datastore + +import ( + "fmt" + "reflect" + "strings" + "unicode" + + "cloud.google.com/go/internal/fields" +) + +// Entities with more than this many indexed properties will not be saved. +const maxIndexedProperties = 20000 + +// []byte fields more than 1 megabyte long will not be loaded or saved. +const maxBlobLen = 1 << 20 + +// Property is a name/value pair plus some metadata. A datastore entity's +// contents are loaded and saved as a sequence of Properties. Each property +// name must be unique within an entity. +type Property struct { + // Name is the property name. + Name string + // Value is the property value. The valid types are: + // - int64 + // - bool + // - string + // - float64 + // - *Key + // - time.Time (retrieved as local time) + // - GeoPoint + // - []byte (up to 1 megabyte in length) + // - *Entity (representing a nested struct) + // Value can also be: + // - []interface{} where each element is one of the above types + // This set is smaller than the set of valid struct field types that the + // datastore can load and save. A Value's type must be explicitly on + // the list above; it is not sufficient for the underlying type to be + // on that list. For example, a Value of "type myInt64 int64" is + // invalid. Smaller-width integers and floats are also invalid. Again, + // this is more restrictive than the set of valid struct field types. + // + // A Value will have an opaque type when loading entities from an index, + // such as via a projection query. Load entities into a struct instead + // of a PropertyLoadSaver when using a projection query. + // + // A Value may also be the nil interface value; this is equivalent to + // Python's None but not directly representable by a Go struct. Loading + // a nil-valued property into a struct will set that field to the zero + // value. + Value interface{} + // NoIndex is whether the datastore cannot index this property. + // If NoIndex is set to false, []byte and string values are limited to + // 1500 bytes. + NoIndex bool +} + +// An Entity is the value type for a nested struct. +// This type is only used for a Property's Value. +type Entity struct { + Key *Key + Properties []Property +} + +// PropertyLoadSaver can be converted from and to a slice of Properties. +type PropertyLoadSaver interface { + Load([]Property) error + Save() ([]Property, error) +} + +// KeyLoader can store a Key. +type KeyLoader interface { + // PropertyLoadSaver is embedded because a KeyLoader + // must also always implement PropertyLoadSaver. + PropertyLoadSaver + LoadKey(k *Key) error +} + +// PropertyList converts a []Property to implement PropertyLoadSaver. +type PropertyList []Property + +var ( + typeOfPropertyLoadSaver = reflect.TypeOf((*PropertyLoadSaver)(nil)).Elem() + typeOfPropertyList = reflect.TypeOf(PropertyList(nil)) +) + +// Load loads all of the provided properties into l. +// It does not first reset *l to an empty slice. +func (l *PropertyList) Load(p []Property) error { + *l = append(*l, p...) + return nil +} + +// Save saves all of l's properties as a slice of Properties. +func (l *PropertyList) Save() ([]Property, error) { + return *l, nil +} + +// validPropertyName returns whether name consists of one or more valid Go +// identifiers joined by ".". +func validPropertyName(name string) bool { + if name == "" { + return false + } + for _, s := range strings.Split(name, ".") { + if s == "" { + return false + } + first := true + for _, c := range s { + if first { + first = false + if c != '_' && !unicode.IsLetter(c) { + return false + } + } else { + if c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) { + return false + } + } + } + } + return true +} + +// parseTag interprets datastore struct field tags +func parseTag(t reflect.StructTag) (name string, keep bool, other interface{}, err error) { + s := t.Get("datastore") + parts := strings.Split(s, ",") + if parts[0] == "-" && len(parts) == 1 { + return "", false, nil, nil + } + if parts[0] != "" && !validPropertyName(parts[0]) { + err = fmt.Errorf("datastore: struct tag has invalid property name: %q", parts[0]) + return "", false, nil, err + } + + var opts saveOpts + if len(parts) > 1 { + for _, p := range parts[1:] { + switch p { + case "flatten": + opts.flatten = true + case "omitempty": + opts.omitEmpty = true + case "noindex": + opts.noIndex = true + default: + err = fmt.Errorf("datastore: struct tag has invalid option: %q", p) + return "", false, nil, err + } + } + other = opts + } + return parts[0], true, other, nil +} + +func validateType(t reflect.Type) error { + if t.Kind() != reflect.Struct { + return fmt.Errorf("datastore: validate called with non-struct type %s", t) + } + + return validateChildType(t, "", false, false, map[reflect.Type]bool{}) +} + +// validateChildType is a recursion helper func for validateType +func validateChildType(t reflect.Type, fieldName string, flatten, prevSlice bool, prevTypes map[reflect.Type]bool) error { + if prevTypes[t] { + return nil + } + prevTypes[t] = true + + switch t.Kind() { + case reflect.Slice: + if flatten && prevSlice { + return fmt.Errorf("datastore: flattening nested structs leads to a slice of slices: field %q", fieldName) + } + return validateChildType(t.Elem(), fieldName, flatten, true, prevTypes) + case reflect.Struct: + if t == typeOfTime || t == typeOfGeoPoint { + return nil + } + + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + + // If a named field is unexported, ignore it. An anonymous + // unexported field is processed, because it may contain + // exported fields, which are visible. + exported := (f.PkgPath == "") + if !exported && !f.Anonymous { + continue + } + + _, keep, other, err := parseTag(f.Tag) + // Handle error from parseTag now instead of later (in cache.Fields call). + if err != nil { + return err + } + if !keep { + continue + } + if other != nil { + opts := other.(saveOpts) + flatten = flatten || opts.flatten + } + if err := validateChildType(f.Type, f.Name, flatten, prevSlice, prevTypes); err != nil { + return err + } + } + case reflect.Ptr: + if t == typeOfKeyPtr { + return nil + } + return validateChildType(t.Elem(), fieldName, flatten, prevSlice, prevTypes) + } + return nil +} + +// isLeafType determines whether or not a type is a 'leaf type' +// and should not be recursed into, but considered one field. +func isLeafType(t reflect.Type) bool { + return t == typeOfTime || t == typeOfGeoPoint +} + +// structCache collects the structs whose fields have already been calculated. +var structCache = fields.NewCache(parseTag, validateType, isLeafType) + +// structPLS adapts a struct to be a PropertyLoadSaver. +type structPLS struct { + v reflect.Value + codec fields.List +} + +// newStructPLS returns a structPLS, which implements the +// PropertyLoadSaver interface, for the struct pointer p. +func newStructPLS(p interface{}) (*structPLS, error) { + v := reflect.ValueOf(p) + if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { + return nil, ErrInvalidEntityType + } + v = v.Elem() + f, err := structCache.Fields(v.Type()) + if err != nil { + return nil, err + } + return &structPLS{v, f}, nil +} + +// LoadStruct loads the properties from p to dst. +// dst must be a struct pointer. +// +// The values of dst's unmatched struct fields are not modified, +// and matching slice-typed fields are not reset before appending to +// them. In particular, it is recommended to pass a pointer to a zero +// valued struct on each LoadStruct call. +func LoadStruct(dst interface{}, p []Property) error { + x, err := newStructPLS(dst) + if err != nil { + return err + } + return x.Load(p) +} + +// SaveStruct returns the properties from src as a slice of Properties. +// src must be a struct pointer. +func SaveStruct(src interface{}) ([]Property, error) { + x, err := newStructPLS(src) + if err != nil { + return nil, err + } + return x.Save() +} + +// plsForLoad tries to convert v to a PropertyLoadSaver. +// If successful, plsForLoad returns a settable v as a PropertyLoadSaver. +// +// plsForLoad is intended to be used with nested struct fields which +// may implement PropertyLoadSaver. +// +// v must be settable. +func plsForLoad(v reflect.Value) (PropertyLoadSaver, error) { + var nilPtr bool + if v.Kind() == reflect.Ptr && v.IsNil() { + nilPtr = true + v.Set(reflect.New(v.Type().Elem())) + } + + vpls, err := pls(v) + if nilPtr && (vpls == nil || err != nil) { + // unset v + v.Set(reflect.Zero(v.Type())) + } + + return vpls, err +} + +// plsForSave tries to convert v to a PropertyLoadSaver. +// If successful, plsForSave returns v as a PropertyLoadSaver. +// +// plsForSave is intended to be used with nested struct fields which +// may implement PropertyLoadSaver. +// +// v must be settable. +func plsForSave(v reflect.Value) (PropertyLoadSaver, error) { + switch v.Kind() { + case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Interface, reflect.Chan, reflect.Func: + // If v is nil, return early. v contains no data to save. + if v.IsNil() { + return nil, nil + } + } + + return pls(v) +} + +func pls(v reflect.Value) (PropertyLoadSaver, error) { + if v.Kind() != reflect.Ptr { + if _, ok := v.Interface().(PropertyLoadSaver); ok { + return nil, fmt.Errorf("datastore: PropertyLoadSaver methods must be implemented on a pointer to %T", v.Interface()) + } + + v = v.Addr() + } + + vpls, _ := v.Interface().(PropertyLoadSaver) + return vpls, nil +} diff --git a/vendor/cloud.google.com/go/datastore/query.go b/vendor/cloud.google.com/go/datastore/query.go new file mode 100644 index 00000000..19576cdd --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/query.go @@ -0,0 +1,784 @@ +// Copyright 2014 Google LLC +// +// 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 datastore + +import ( + "context" + "encoding/base64" + "errors" + "fmt" + "math" + "reflect" + "strconv" + "strings" + + "cloud.google.com/go/internal/trace" + wrapperspb "github.com/golang/protobuf/ptypes/wrappers" + "google.golang.org/api/iterator" + pb "google.golang.org/genproto/googleapis/datastore/v1" +) + +type operator int + +const ( + lessThan operator = iota + 1 + lessEq + equal + greaterEq + greaterThan + + keyFieldName = "__key__" +) + +var operatorToProto = map[operator]pb.PropertyFilter_Operator{ + lessThan: pb.PropertyFilter_LESS_THAN, + lessEq: pb.PropertyFilter_LESS_THAN_OR_EQUAL, + equal: pb.PropertyFilter_EQUAL, + greaterEq: pb.PropertyFilter_GREATER_THAN_OR_EQUAL, + greaterThan: pb.PropertyFilter_GREATER_THAN, +} + +// filter is a conditional filter on query results. +type filter struct { + FieldName string + Op operator + Value interface{} +} + +type sortDirection bool + +const ( + ascending sortDirection = false + descending sortDirection = true +) + +var sortDirectionToProto = map[sortDirection]pb.PropertyOrder_Direction{ + ascending: pb.PropertyOrder_ASCENDING, + descending: pb.PropertyOrder_DESCENDING, +} + +// order is a sort order on query results. +type order struct { + FieldName string + Direction sortDirection +} + +// NewQuery creates a new Query for a specific entity kind. +// +// An empty kind means to return all entities, including entities created and +// managed by other App Engine features, and is called a kindless query. +// Kindless queries cannot include filters or sort orders on property values. +func NewQuery(kind string) *Query { + return &Query{ + kind: kind, + limit: -1, + } +} + +// Query represents a datastore query. +type Query struct { + kind string + ancestor *Key + filter []filter + order []order + projection []string + + distinct bool + distinctOn []string + keysOnly bool + eventual bool + limit int32 + offset int32 + start []byte + end []byte + + namespace string + + trans *Transaction + + err error +} + +func (q *Query) clone() *Query { + x := *q + // Copy the contents of the slice-typed fields to a new backing store. + if len(q.filter) > 0 { + x.filter = make([]filter, len(q.filter)) + copy(x.filter, q.filter) + } + if len(q.order) > 0 { + x.order = make([]order, len(q.order)) + copy(x.order, q.order) + } + return &x +} + +// Ancestor returns a derivative query with an ancestor filter. +// The ancestor should not be nil. +func (q *Query) Ancestor(ancestor *Key) *Query { + q = q.clone() + if ancestor == nil { + q.err = errors.New("datastore: nil query ancestor") + return q + } + q.ancestor = ancestor + return q +} + +// EventualConsistency returns a derivative query that returns eventually +// consistent results. +// It only has an effect on ancestor queries. +func (q *Query) EventualConsistency() *Query { + q = q.clone() + q.eventual = true + return q +} + +// Namespace returns a derivative query that is associated with the given +// namespace. +// +// A namespace may be used to partition data for multi-tenant applications. +// For details, see https://cloud.google.com/datastore/docs/concepts/multitenancy. +func (q *Query) Namespace(ns string) *Query { + q = q.clone() + q.namespace = ns + return q +} + +// Transaction returns a derivative query that is associated with the given +// transaction. +// +// All reads performed as part of the transaction will come from a single +// consistent snapshot. Furthermore, if the transaction is set to a +// serializable isolation level, another transaction cannot concurrently modify +// the data that is read or modified by this transaction. +func (q *Query) Transaction(t *Transaction) *Query { + q = q.clone() + q.trans = t + return q +} + +// Filter returns a derivative query with a field-based filter. +// The filterStr argument must be a field name followed by optional space, +// followed by an operator, one of ">", "<", ">=", "<=", or "=". +// Fields are compared against the provided value using the operator. +// Multiple filters are AND'ed together. +// Field names which contain spaces, quote marks, or operator characters +// should be passed as quoted Go string literals as returned by strconv.Quote +// or the fmt package's %q verb. +func (q *Query) Filter(filterStr string, value interface{}) *Query { + q = q.clone() + filterStr = strings.TrimSpace(filterStr) + if filterStr == "" { + q.err = fmt.Errorf("datastore: invalid filter %q", filterStr) + return q + } + f := filter{ + FieldName: strings.TrimRight(filterStr, " ><=!"), + Value: value, + } + switch op := strings.TrimSpace(filterStr[len(f.FieldName):]); op { + case "<=": + f.Op = lessEq + case ">=": + f.Op = greaterEq + case "<": + f.Op = lessThan + case ">": + f.Op = greaterThan + case "=": + f.Op = equal + default: + q.err = fmt.Errorf("datastore: invalid operator %q in filter %q", op, filterStr) + return q + } + var err error + f.FieldName, err = unquote(f.FieldName) + if err != nil { + q.err = fmt.Errorf("datastore: invalid syntax for quoted field name %q", f.FieldName) + return q + } + q.filter = append(q.filter, f) + return q +} + +// Order returns a derivative query with a field-based sort order. Orders are +// applied in the order they are added. The default order is ascending; to sort +// in descending order prefix the fieldName with a minus sign (-). +// Field names which contain spaces, quote marks, or the minus sign +// should be passed as quoted Go string literals as returned by strconv.Quote +// or the fmt package's %q verb. +func (q *Query) Order(fieldName string) *Query { + q = q.clone() + fieldName, dir := strings.TrimSpace(fieldName), ascending + if strings.HasPrefix(fieldName, "-") { + fieldName, dir = strings.TrimSpace(fieldName[1:]), descending + } else if strings.HasPrefix(fieldName, "+") { + q.err = fmt.Errorf("datastore: invalid order: %q", fieldName) + return q + } + fieldName, err := unquote(fieldName) + if err != nil { + q.err = fmt.Errorf("datastore: invalid syntax for quoted field name %q", fieldName) + return q + } + if fieldName == "" { + q.err = errors.New("datastore: empty order") + return q + } + q.order = append(q.order, order{ + Direction: dir, + FieldName: fieldName, + }) + return q +} + +// unquote optionally interprets s as a double-quoted or backquoted Go +// string literal if it begins with the relevant character. +func unquote(s string) (string, error) { + if s == "" || (s[0] != '`' && s[0] != '"') { + return s, nil + } + return strconv.Unquote(s) +} + +// Project returns a derivative query that yields only the given fields. It +// cannot be used with KeysOnly. +func (q *Query) Project(fieldNames ...string) *Query { + q = q.clone() + q.projection = append([]string(nil), fieldNames...) + return q +} + +// Distinct returns a derivative query that yields de-duplicated entities with +// respect to the set of projected fields. It is only used for projection +// queries. Distinct cannot be used with DistinctOn. +func (q *Query) Distinct() *Query { + q = q.clone() + q.distinct = true + return q +} + +// DistinctOn returns a derivative query that yields de-duplicated entities with +// respect to the set of the specified fields. It is only used for projection +// queries. The field list should be a subset of the projected field list. +// DistinctOn cannot be used with Distinct. +func (q *Query) DistinctOn(fieldNames ...string) *Query { + q = q.clone() + q.distinctOn = fieldNames + return q +} + +// KeysOnly returns a derivative query that yields only keys, not keys and +// entities. It cannot be used with projection queries. +func (q *Query) KeysOnly() *Query { + q = q.clone() + q.keysOnly = true + return q +} + +// Limit returns a derivative query that has a limit on the number of results +// returned. A negative value means unlimited. +func (q *Query) Limit(limit int) *Query { + q = q.clone() + if limit < math.MinInt32 || limit > math.MaxInt32 { + q.err = errors.New("datastore: query limit overflow") + return q + } + q.limit = int32(limit) + return q +} + +// Offset returns a derivative query that has an offset of how many keys to +// skip over before returning results. A negative value is invalid. +func (q *Query) Offset(offset int) *Query { + q = q.clone() + if offset < 0 { + q.err = errors.New("datastore: negative query offset") + return q + } + if offset > math.MaxInt32 { + q.err = errors.New("datastore: query offset overflow") + return q + } + q.offset = int32(offset) + return q +} + +// Start returns a derivative query with the given start point. +func (q *Query) Start(c Cursor) *Query { + q = q.clone() + q.start = c.cc + return q +} + +// End returns a derivative query with the given end point. +func (q *Query) End(c Cursor) *Query { + q = q.clone() + q.end = c.cc + return q +} + +// toProto converts the query to a protocol buffer. +func (q *Query) toProto(req *pb.RunQueryRequest) error { + if len(q.projection) != 0 && q.keysOnly { + return errors.New("datastore: query cannot both project and be keys-only") + } + if len(q.distinctOn) != 0 && q.distinct { + return errors.New("datastore: query cannot be both distinct and distinct-on") + } + dst := &pb.Query{} + if q.kind != "" { + dst.Kind = []*pb.KindExpression{{Name: q.kind}} + } + if q.projection != nil { + for _, propertyName := range q.projection { + dst.Projection = append(dst.Projection, &pb.Projection{Property: &pb.PropertyReference{Name: propertyName}}) + } + + for _, propertyName := range q.distinctOn { + dst.DistinctOn = append(dst.DistinctOn, &pb.PropertyReference{Name: propertyName}) + } + + if q.distinct { + for _, propertyName := range q.projection { + dst.DistinctOn = append(dst.DistinctOn, &pb.PropertyReference{Name: propertyName}) + } + } + } + if q.keysOnly { + dst.Projection = []*pb.Projection{{Property: &pb.PropertyReference{Name: keyFieldName}}} + } + + var filters []*pb.Filter + for _, qf := range q.filter { + if qf.FieldName == "" { + return errors.New("datastore: empty query filter field name") + } + v, err := interfaceToProto(reflect.ValueOf(qf.Value).Interface(), false) + if err != nil { + return fmt.Errorf("datastore: bad query filter value type: %v", err) + } + op, ok := operatorToProto[qf.Op] + if !ok { + return errors.New("datastore: unknown query filter operator") + } + xf := &pb.PropertyFilter{ + Op: op, + Property: &pb.PropertyReference{Name: qf.FieldName}, + Value: v, + } + filters = append(filters, &pb.Filter{ + FilterType: &pb.Filter_PropertyFilter{PropertyFilter: xf}, + }) + } + + if q.ancestor != nil { + filters = append(filters, &pb.Filter{ + FilterType: &pb.Filter_PropertyFilter{PropertyFilter: &pb.PropertyFilter{ + Property: &pb.PropertyReference{Name: keyFieldName}, + Op: pb.PropertyFilter_HAS_ANCESTOR, + Value: &pb.Value{ValueType: &pb.Value_KeyValue{KeyValue: keyToProto(q.ancestor)}}, + }}}) + } + + if len(filters) == 1 { + dst.Filter = filters[0] + } else if len(filters) > 1 { + dst.Filter = &pb.Filter{FilterType: &pb.Filter_CompositeFilter{CompositeFilter: &pb.CompositeFilter{ + Op: pb.CompositeFilter_AND, + Filters: filters, + }}} + } + + for _, qo := range q.order { + if qo.FieldName == "" { + return errors.New("datastore: empty query order field name") + } + xo := &pb.PropertyOrder{ + Property: &pb.PropertyReference{Name: qo.FieldName}, + Direction: sortDirectionToProto[qo.Direction], + } + dst.Order = append(dst.Order, xo) + } + if q.limit >= 0 { + dst.Limit = &wrapperspb.Int32Value{Value: q.limit} + } + dst.Offset = q.offset + dst.StartCursor = q.start + dst.EndCursor = q.end + + if t := q.trans; t != nil { + if t.id == nil { + return errExpiredTransaction + } + if q.eventual { + return errors.New("datastore: cannot use EventualConsistency query in a transaction") + } + req.ReadOptions = &pb.ReadOptions{ + ConsistencyType: &pb.ReadOptions_Transaction{Transaction: t.id}, + } + } + + if q.eventual { + req.ReadOptions = &pb.ReadOptions{ConsistencyType: &pb.ReadOptions_ReadConsistency_{ReadConsistency: pb.ReadOptions_EVENTUAL}} + } + + req.QueryType = &pb.RunQueryRequest_Query{Query: dst} + return nil +} + +// Count returns the number of results for the given query. +// +// The running time and number of API calls made by Count scale linearly with +// the sum of the query's offset and limit. Unless the result count is +// expected to be small, it is best to specify a limit; otherwise Count will +// continue until it finishes counting or the provided context expires. +func (c *Client) Count(ctx context.Context, q *Query) (n int, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.Query.Count") + defer func() { trace.EndSpan(ctx, err) }() + + // Check that the query is well-formed. + if q.err != nil { + return 0, q.err + } + + // Create a copy of the query, with keysOnly true (if we're not a projection, + // since the two are incompatible). + newQ := q.clone() + newQ.keysOnly = len(newQ.projection) == 0 + + // Create an iterator and use it to walk through the batches of results + // directly. + it := c.Run(ctx, newQ) + for { + err := it.nextBatch() + if err == iterator.Done { + return n, nil + } + if err != nil { + return 0, err + } + n += len(it.results) + } +} + +// GetAll runs the provided query in the given context and returns all keys +// that match that query, as well as appending the values to dst. +// +// dst must have type *[]S or *[]*S or *[]P, for some struct type S or some non- +// interface, non-pointer type P such that P or *P implements PropertyLoadSaver. +// +// As a special case, *PropertyList is an invalid type for dst, even though a +// PropertyList is a slice of structs. It is treated as invalid to avoid being +// mistakenly passed when *[]PropertyList was intended. +// +// The keys returned by GetAll will be in a 1-1 correspondence with the entities +// added to dst. +// +// If q is a ``keys-only'' query, GetAll ignores dst and only returns the keys. +// +// The running time and number of API calls made by GetAll scale linearly with +// with the sum of the query's offset and limit. Unless the result count is +// expected to be small, it is best to specify a limit; otherwise GetAll will +// continue until it finishes collecting results or the provided context +// expires. +func (c *Client) GetAll(ctx context.Context, q *Query, dst interface{}) (keys []*Key, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.Query.GetAll") + defer func() { trace.EndSpan(ctx, err) }() + + var ( + dv reflect.Value + mat multiArgType + elemType reflect.Type + errFieldMismatch error + ) + if !q.keysOnly { + dv = reflect.ValueOf(dst) + if dv.Kind() != reflect.Ptr || dv.IsNil() { + return nil, ErrInvalidEntityType + } + dv = dv.Elem() + mat, elemType = checkMultiArg(dv) + if mat == multiArgTypeInvalid || mat == multiArgTypeInterface { + return nil, ErrInvalidEntityType + } + } + + for t := c.Run(ctx, q); ; { + k, e, err := t.next() + if err == iterator.Done { + break + } + if err != nil { + return keys, err + } + if !q.keysOnly { + ev := reflect.New(elemType) + if elemType.Kind() == reflect.Map { + // This is a special case. The zero values of a map type are + // not immediately useful; they have to be make'd. + // + // Funcs and channels are similar, in that a zero value is not useful, + // but even a freshly make'd channel isn't useful: there's no fixed + // channel buffer size that is always going to be large enough, and + // there's no goroutine to drain the other end. Theoretically, these + // types could be supported, for example by sniffing for a constructor + // method or requiring prior registration, but for now it's not a + // frequent enough concern to be worth it. Programmers can work around + // it by explicitly using Iterator.Next instead of the Query.GetAll + // convenience method. + x := reflect.MakeMap(elemType) + ev.Elem().Set(x) + } + if err = loadEntityProto(ev.Interface(), e); err != nil { + if _, ok := err.(*ErrFieldMismatch); ok { + // We continue loading entities even in the face of field mismatch errors. + // If we encounter any other error, that other error is returned. Otherwise, + // an ErrFieldMismatch is returned. + errFieldMismatch = err + } else { + return keys, err + } + } + if mat != multiArgTypeStructPtr { + ev = ev.Elem() + } + dv.Set(reflect.Append(dv, ev)) + } + keys = append(keys, k) + } + return keys, errFieldMismatch +} + +// Run runs the given query in the given context. +func (c *Client) Run(ctx context.Context, q *Query) *Iterator { + if q.err != nil { + return &Iterator{err: q.err} + } + t := &Iterator{ + ctx: ctx, + client: c, + limit: q.limit, + offset: q.offset, + keysOnly: q.keysOnly, + pageCursor: q.start, + entityCursor: q.start, + req: &pb.RunQueryRequest{ + ProjectId: c.dataset, + }, + } + + ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.Query.Run") + defer func() { trace.EndSpan(ctx, t.err) }() + if q.namespace != "" { + t.req.PartitionId = &pb.PartitionId{ + NamespaceId: q.namespace, + } + } + + if err := q.toProto(t.req); err != nil { + t.err = err + } + return t +} + +// Iterator is the result of running a query. +type Iterator struct { + ctx context.Context + client *Client + err error + + // results is the list of EntityResults still to be iterated over from the + // most recent API call. It will be nil if no requests have yet been issued. + results []*pb.EntityResult + // req is the request to send. It may be modified and used multiple times. + req *pb.RunQueryRequest + + // limit is the limit on the number of results this iterator should return. + // The zero value is used to prevent further fetches from the server. + // A negative value means unlimited. + limit int32 + // offset is the number of results that still need to be skipped. + offset int32 + // keysOnly records whether the query was keys-only (skip entity loading). + keysOnly bool + + // pageCursor is the compiled cursor for the next batch/page of result. + // TODO(djd): Can we delete this in favour of paging with the last + // entityCursor from each batch? + pageCursor []byte + // entityCursor is the compiled cursor of the next result. + entityCursor []byte +} + +// Next returns the key of the next result. When there are no more results, +// iterator.Done is returned as the error. +// +// If the query is not keys only and dst is non-nil, it also loads the entity +// stored for that key into the struct pointer or PropertyLoadSaver dst, with +// the same semantics and possible errors as for the Get function. +func (t *Iterator) Next(dst interface{}) (k *Key, err error) { + k, e, err := t.next() + if err != nil { + return nil, err + } + if dst != nil && !t.keysOnly { + err = loadEntityProto(dst, e) + } + return k, err +} + +func (t *Iterator) next() (*Key, *pb.Entity, error) { + // Fetch additional batches while there are no more results. + for t.err == nil && len(t.results) == 0 { + t.err = t.nextBatch() + } + if t.err != nil { + return nil, nil, t.err + } + + // Extract the next result, update cursors, and parse the entity's key. + e := t.results[0] + t.results = t.results[1:] + t.entityCursor = e.Cursor + if len(t.results) == 0 { + t.entityCursor = t.pageCursor // At the end of the batch. + } + if e.Entity.Key == nil { + return nil, nil, errors.New("datastore: internal error: server did not return a key") + } + k, err := protoToKey(e.Entity.Key) + if err != nil || k.Incomplete() { + return nil, nil, errors.New("datastore: internal error: server returned an invalid key") + } + + return k, e.Entity, nil +} + +// nextBatch makes a single call to the server for a batch of results. +func (t *Iterator) nextBatch() error { + if t.limit == 0 { + return iterator.Done // Short-circuits the zero-item response. + } + + // Adjust the query with the latest start cursor, limit and offset. + q := t.req.GetQuery() + q.StartCursor = t.pageCursor + q.Offset = t.offset + if t.limit >= 0 { + q.Limit = &wrapperspb.Int32Value{Value: t.limit} + } else { + q.Limit = nil + } + + // Run the query. + resp, err := t.client.client.RunQuery(t.ctx, t.req) + if err != nil { + return err + } + + // Adjust any offset from skipped results. + skip := resp.Batch.SkippedResults + if skip < 0 { + return errors.New("datastore: internal error: negative number of skipped_results") + } + t.offset -= skip + if t.offset < 0 { + return errors.New("datastore: internal error: query skipped too many results") + } + if t.offset > 0 && len(resp.Batch.EntityResults) > 0 { + return errors.New("datastore: internal error: query returned results before requested offset") + } + + // Adjust the limit. + if t.limit >= 0 { + t.limit -= int32(len(resp.Batch.EntityResults)) + if t.limit < 0 { + return errors.New("datastore: internal error: query returned more results than the limit") + } + } + + // If there are no more results available, set limit to zero to prevent + // further fetches. Otherwise, check that there is a next page cursor available. + if resp.Batch.MoreResults != pb.QueryResultBatch_NOT_FINISHED { + t.limit = 0 + } else if resp.Batch.EndCursor == nil { + return errors.New("datastore: internal error: server did not return a cursor") + } + + // Update cursors. + // If any results were skipped, use the SkippedCursor as the next entity cursor. + if skip > 0 { + t.entityCursor = resp.Batch.SkippedCursor + } else { + t.entityCursor = q.StartCursor + } + t.pageCursor = resp.Batch.EndCursor + + t.results = resp.Batch.EntityResults + return nil +} + +// Cursor returns a cursor for the iterator's current location. +func (t *Iterator) Cursor() (c Cursor, err error) { + t.ctx = trace.StartSpan(t.ctx, "cloud.google.com/go/datastore.Query.Cursor") + defer func() { trace.EndSpan(t.ctx, err) }() + + // If there is still an offset, we need to the skip those results first. + for t.err == nil && t.offset > 0 { + t.err = t.nextBatch() + } + + if t.err != nil && t.err != iterator.Done { + return Cursor{}, t.err + } + + return Cursor{t.entityCursor}, nil +} + +// Cursor is an iterator's position. It can be converted to and from an opaque +// string. A cursor can be used from different HTTP requests, but only with a +// query with the same kind, ancestor, filter and order constraints. +// +// The zero Cursor can be used to indicate that there is no start and/or end +// constraint for a query. +type Cursor struct { + cc []byte +} + +// String returns a base-64 string representation of a cursor. +func (c Cursor) String() string { + if c.cc == nil { + return "" + } + + return strings.TrimRight(base64.URLEncoding.EncodeToString(c.cc), "=") +} + +// DecodeCursor decodes a cursor from its base-64 string representation. +func DecodeCursor(s string) (Cursor, error) { + if s == "" { + return Cursor{}, nil + } + if n := len(s) % 4; n != 0 { + s += strings.Repeat("=", 4-n) + } + b, err := base64.URLEncoding.DecodeString(s) + if err != nil { + return Cursor{}, err + } + return Cursor{b}, nil +} diff --git a/vendor/cloud.google.com/go/datastore/query_test.go b/vendor/cloud.google.com/go/datastore/query_test.go new file mode 100644 index 00000000..18060652 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/query_test.go @@ -0,0 +1,547 @@ +// Copyright 2014 Google LLC +// +// 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 datastore + +import ( + "context" + "errors" + "fmt" + "reflect" + "sort" + "testing" + + "cloud.google.com/go/internal/testutil" + "github.com/golang/protobuf/proto" + "github.com/google/go-cmp/cmp" + pb "google.golang.org/genproto/googleapis/datastore/v1" + "google.golang.org/grpc" +) + +var ( + key1 = &pb.Key{ + Path: []*pb.Key_PathElement{ + { + Kind: "Gopher", + IdType: &pb.Key_PathElement_Id{Id: 6}, + }, + }, + } + key2 = &pb.Key{ + Path: []*pb.Key_PathElement{ + { + Kind: "Gopher", + IdType: &pb.Key_PathElement_Id{Id: 6}, + }, + { + Kind: "Gopher", + IdType: &pb.Key_PathElement_Id{Id: 8}, + }, + }, + } +) + +type fakeClient struct { + pb.DatastoreClient + queryFn func(*pb.RunQueryRequest) (*pb.RunQueryResponse, error) + commitFn func(*pb.CommitRequest) (*pb.CommitResponse, error) +} + +func (c *fakeClient) RunQuery(_ context.Context, req *pb.RunQueryRequest, _ ...grpc.CallOption) (*pb.RunQueryResponse, error) { + return c.queryFn(req) +} + +func (c *fakeClient) Commit(_ context.Context, req *pb.CommitRequest, _ ...grpc.CallOption) (*pb.CommitResponse, error) { + return c.commitFn(req) +} + +func fakeRunQuery(in *pb.RunQueryRequest) (*pb.RunQueryResponse, error) { + expectedIn := &pb.RunQueryRequest{ + QueryType: &pb.RunQueryRequest_Query{Query: &pb.Query{ + Kind: []*pb.KindExpression{{Name: "Gopher"}}, + }}, + } + if !proto.Equal(in, expectedIn) { + return nil, fmt.Errorf("unsupported argument: got %v want %v", in, expectedIn) + } + return &pb.RunQueryResponse{ + Batch: &pb.QueryResultBatch{ + MoreResults: pb.QueryResultBatch_NO_MORE_RESULTS, + EntityResultType: pb.EntityResult_FULL, + EntityResults: []*pb.EntityResult{ + { + Entity: &pb.Entity{ + Key: key1, + Properties: map[string]*pb.Value{ + "Name": {ValueType: &pb.Value_StringValue{StringValue: "George"}}, + "Height": {ValueType: &pb.Value_IntegerValue{IntegerValue: 32}}, + }, + }, + }, + { + Entity: &pb.Entity{ + Key: key2, + Properties: map[string]*pb.Value{ + "Name": {ValueType: &pb.Value_StringValue{StringValue: "Rufus"}}, + // No height for Rufus. + }, + }, + }, + }, + }, + }, nil +} + +type StructThatImplementsPLS struct{} + +func (StructThatImplementsPLS) Load(p []Property) error { return nil } +func (StructThatImplementsPLS) Save() ([]Property, error) { return nil, nil } + +var _ PropertyLoadSaver = StructThatImplementsPLS{} + +type StructPtrThatImplementsPLS struct{} + +func (*StructPtrThatImplementsPLS) Load(p []Property) error { return nil } +func (*StructPtrThatImplementsPLS) Save() ([]Property, error) { return nil, nil } + +var _ PropertyLoadSaver = &StructPtrThatImplementsPLS{} + +type PropertyMap map[string]Property + +func (m PropertyMap) Load(props []Property) error { + for _, p := range props { + m[p.Name] = p + } + return nil +} + +func (m PropertyMap) Save() ([]Property, error) { + props := make([]Property, 0, len(m)) + for _, p := range m { + props = append(props, p) + } + return props, nil +} + +var _ PropertyLoadSaver = PropertyMap{} + +type Gopher struct { + Name string + Height int +} + +// typeOfEmptyInterface is the type of interface{}, but we can't use +// reflect.TypeOf((interface{})(nil)) directly because TypeOf takes an +// interface{}. +var typeOfEmptyInterface = reflect.TypeOf((*interface{})(nil)).Elem() + +func TestCheckMultiArg(t *testing.T) { + testCases := []struct { + v interface{} + mat multiArgType + elemType reflect.Type + }{ + // Invalid cases. + {nil, multiArgTypeInvalid, nil}, + {Gopher{}, multiArgTypeInvalid, nil}, + {&Gopher{}, multiArgTypeInvalid, nil}, + {PropertyList{}, multiArgTypeInvalid, nil}, // This is a special case. + {PropertyMap{}, multiArgTypeInvalid, nil}, + {[]*PropertyList(nil), multiArgTypeInvalid, nil}, + {[]*PropertyMap(nil), multiArgTypeInvalid, nil}, + {[]**Gopher(nil), multiArgTypeInvalid, nil}, + {[]*interface{}(nil), multiArgTypeInvalid, nil}, + // Valid cases. + { + []PropertyList(nil), + multiArgTypePropertyLoadSaver, + reflect.TypeOf(PropertyList{}), + }, + { + []PropertyMap(nil), + multiArgTypePropertyLoadSaver, + reflect.TypeOf(PropertyMap{}), + }, + { + []StructThatImplementsPLS(nil), + multiArgTypePropertyLoadSaver, + reflect.TypeOf(StructThatImplementsPLS{}), + }, + { + []StructPtrThatImplementsPLS(nil), + multiArgTypePropertyLoadSaver, + reflect.TypeOf(StructPtrThatImplementsPLS{}), + }, + { + []Gopher(nil), + multiArgTypeStruct, + reflect.TypeOf(Gopher{}), + }, + { + []*Gopher(nil), + multiArgTypeStructPtr, + reflect.TypeOf(Gopher{}), + }, + { + []interface{}(nil), + multiArgTypeInterface, + typeOfEmptyInterface, + }, + } + for _, tc := range testCases { + mat, elemType := checkMultiArg(reflect.ValueOf(tc.v)) + if mat != tc.mat || elemType != tc.elemType { + t.Errorf("checkMultiArg(%T): got %v, %v want %v, %v", + tc.v, mat, elemType, tc.mat, tc.elemType) + } + } +} + +func TestSimpleQuery(t *testing.T) { + struct1 := Gopher{Name: "George", Height: 32} + struct2 := Gopher{Name: "Rufus"} + pList1 := PropertyList{ + { + Name: "Height", + Value: int64(32), + }, + { + Name: "Name", + Value: "George", + }, + } + pList2 := PropertyList{ + { + Name: "Name", + Value: "Rufus", + }, + } + pMap1 := PropertyMap{ + "Name": Property{ + Name: "Name", + Value: "George", + }, + "Height": Property{ + Name: "Height", + Value: int64(32), + }, + } + pMap2 := PropertyMap{ + "Name": Property{ + Name: "Name", + Value: "Rufus", + }, + } + + testCases := []struct { + dst interface{} + want interface{} + }{ + // The destination must have type *[]P, *[]S or *[]*S, for some non-interface + // type P such that *P implements PropertyLoadSaver, or for some struct type S. + {new([]Gopher), &[]Gopher{struct1, struct2}}, + {new([]*Gopher), &[]*Gopher{&struct1, &struct2}}, + {new([]PropertyList), &[]PropertyList{pList1, pList2}}, + {new([]PropertyMap), &[]PropertyMap{pMap1, pMap2}}, + + // Any other destination type is invalid. + {0, nil}, + {Gopher{}, nil}, + {PropertyList{}, nil}, + {PropertyMap{}, nil}, + {[]int{}, nil}, + {[]Gopher{}, nil}, + {[]PropertyList{}, nil}, + {new(int), nil}, + {new(Gopher), nil}, + {new(PropertyList), nil}, // This is a special case. + {new(PropertyMap), nil}, + {new([]int), nil}, + {new([]map[int]int), nil}, + {new([]map[string]Property), nil}, + {new([]map[string]interface{}), nil}, + {new([]*int), nil}, + {new([]*map[int]int), nil}, + {new([]*map[string]Property), nil}, + {new([]*map[string]interface{}), nil}, + {new([]**Gopher), nil}, + {new([]*PropertyList), nil}, + {new([]*PropertyMap), nil}, + } + for _, tc := range testCases { + nCall := 0 + client := &Client{ + client: &fakeClient{ + queryFn: func(req *pb.RunQueryRequest) (*pb.RunQueryResponse, error) { + nCall++ + return fakeRunQuery(req) + }, + }, + } + ctx := context.Background() + + var ( + expectedErr error + expectedNCall int + ) + if tc.want == nil { + expectedErr = ErrInvalidEntityType + } else { + expectedNCall = 1 + } + keys, err := client.GetAll(ctx, NewQuery("Gopher"), tc.dst) + if err != expectedErr { + t.Errorf("dst type %T: got error %v, want %v", tc.dst, err, expectedErr) + continue + } + if nCall != expectedNCall { + t.Errorf("dst type %T: Context.Call was called an incorrect number of times: got %d want %d", tc.dst, nCall, expectedNCall) + continue + } + if err != nil { + continue + } + + key1 := IDKey("Gopher", 6, nil) + expectedKeys := []*Key{ + key1, + IDKey("Gopher", 8, key1), + } + if l1, l2 := len(keys), len(expectedKeys); l1 != l2 { + t.Errorf("dst type %T: got %d keys, want %d keys", tc.dst, l1, l2) + continue + } + for i, key := range keys { + if !keysEqual(key, expectedKeys[i]) { + t.Errorf("dst type %T: got key #%d %v, want %v", tc.dst, i, key, expectedKeys[i]) + continue + } + } + + // Make sure we sort any PropertyList items (the order is not deterministic). + if pLists, ok := tc.dst.(*[]PropertyList); ok { + for _, p := range *pLists { + sort.Sort(byName(p)) + } + } + + if !testutil.Equal(tc.dst, tc.want) { + t.Errorf("dst type %T: Entities\ngot %+v\nwant %+v", tc.dst, tc.dst, tc.want) + continue + } + } +} + +// keysEqual is like (*Key).Equal, but ignores the App ID. +func keysEqual(a, b *Key) bool { + for a != nil && b != nil { + if a.Kind != b.Kind || a.Name != b.Name || a.ID != b.ID { + return false + } + a, b = a.Parent, b.Parent + } + return a == b +} + +func TestQueriesAreImmutable(t *testing.T) { + // Test that deriving q2 from q1 does not modify q1. + q0 := NewQuery("foo") + q1 := NewQuery("foo") + q2 := q1.Offset(2) + if !testutil.Equal(q0, q1, cmp.AllowUnexported(Query{})) { + t.Errorf("q0 and q1 were not equal") + } + if testutil.Equal(q1, q2, cmp.AllowUnexported(Query{})) { + t.Errorf("q1 and q2 were equal") + } + + // Test that deriving from q4 twice does not conflict, even though + // q4 has a long list of order clauses. This tests that the arrays + // backed by a query's slice of orders are not shared. + f := func() *Query { + q := NewQuery("bar") + // 47 is an ugly number that is unlikely to be near a re-allocation + // point in repeated append calls. For example, it's not near a power + // of 2 or a multiple of 10. + for i := 0; i < 47; i++ { + q = q.Order(fmt.Sprintf("x%d", i)) + } + return q + } + q3 := f().Order("y") + q4 := f() + q5 := q4.Order("y") + q6 := q4.Order("z") + if !testutil.Equal(q3, q5, cmp.AllowUnexported(Query{})) { + t.Errorf("q3 and q5 were not equal") + } + if testutil.Equal(q5, q6, cmp.AllowUnexported(Query{})) { + t.Errorf("q5 and q6 were equal") + } +} + +func TestFilterParser(t *testing.T) { + testCases := []struct { + filterStr string + wantOK bool + wantFieldName string + wantOp operator + }{ + // Supported ops. + {"x<", true, "x", lessThan}, + {"x <", true, "x", lessThan}, + {"x <", true, "x", lessThan}, + {" x < ", true, "x", lessThan}, + {"x <=", true, "x", lessEq}, + {"x =", true, "x", equal}, + {"x >=", true, "x", greaterEq}, + {"x >", true, "x", greaterThan}, + {"in >", true, "in", greaterThan}, + {"in>", true, "in", greaterThan}, + // Valid but (currently) unsupported ops. + {"x!=", false, "", 0}, + {"x !=", false, "", 0}, + {" x != ", false, "", 0}, + {"x IN", false, "", 0}, + {"x in", false, "", 0}, + // Invalid ops. + {"x EQ", false, "", 0}, + {"x lt", false, "", 0}, + {"x <>", false, "", 0}, + {"x >>", false, "", 0}, + {"x ==", false, "", 0}, + {"x =<", false, "", 0}, + {"x =>", false, "", 0}, + {"x !", false, "", 0}, + {"x ", false, "", 0}, + {"x", false, "", 0}, + // Quoted and interesting field names. + {"x > y =", true, "x > y", equal}, + {"` x ` =", true, " x ", equal}, + {`" x " =`, true, " x ", equal}, + {`" \"x " =`, true, ` "x `, equal}, + {`" x =`, false, "", 0}, + {`" x ="`, false, "", 0}, + {"` x \" =", false, "", 0}, + } + for _, tc := range testCases { + q := NewQuery("foo").Filter(tc.filterStr, 42) + if ok := q.err == nil; ok != tc.wantOK { + t.Errorf("%q: ok=%t, want %t", tc.filterStr, ok, tc.wantOK) + continue + } + if !tc.wantOK { + continue + } + if len(q.filter) != 1 { + t.Errorf("%q: len=%d, want %d", tc.filterStr, len(q.filter), 1) + continue + } + got, want := q.filter[0], filter{tc.wantFieldName, tc.wantOp, 42} + if got != want { + t.Errorf("%q: got %v, want %v", tc.filterStr, got, want) + continue + } + } +} + +func TestNamespaceQuery(t *testing.T) { + gotNamespace := make(chan string, 1) + ctx := context.Background() + client := &Client{ + client: &fakeClient{ + queryFn: func(req *pb.RunQueryRequest) (*pb.RunQueryResponse, error) { + if part := req.PartitionId; part != nil { + gotNamespace <- part.NamespaceId + } else { + gotNamespace <- "" + } + return nil, errors.New("not implemented") + }, + }, + } + + var gs []Gopher + + // Ignore errors for the rest of this test. + client.GetAll(ctx, NewQuery("gopher"), &gs) + if got, want := <-gotNamespace, ""; got != want { + t.Errorf("GetAll: got namespace %q, want %q", got, want) + } + client.Count(ctx, NewQuery("gopher")) + if got, want := <-gotNamespace, ""; got != want { + t.Errorf("Count: got namespace %q, want %q", got, want) + } + + const ns = "not_default" + client.GetAll(ctx, NewQuery("gopher").Namespace(ns), &gs) + if got, want := <-gotNamespace, ns; got != want { + t.Errorf("GetAll: got namespace %q, want %q", got, want) + } + client.Count(ctx, NewQuery("gopher").Namespace(ns)) + if got, want := <-gotNamespace, ns; got != want { + t.Errorf("Count: got namespace %q, want %q", got, want) + } +} + +func TestReadOptions(t *testing.T) { + tid := []byte{1} + for _, test := range []struct { + q *Query + want *pb.ReadOptions + }{ + { + q: NewQuery(""), + want: nil, + }, + { + q: NewQuery("").Transaction(nil), + want: nil, + }, + { + q: NewQuery("").Transaction(&Transaction{id: tid}), + want: &pb.ReadOptions{ + ConsistencyType: &pb.ReadOptions_Transaction{ + Transaction: tid, + }, + }, + }, + { + q: NewQuery("").EventualConsistency(), + want: &pb.ReadOptions{ + ConsistencyType: &pb.ReadOptions_ReadConsistency_{ + ReadConsistency: pb.ReadOptions_EVENTUAL, + }, + }, + }, + } { + req := &pb.RunQueryRequest{} + if err := test.q.toProto(req); err != nil { + t.Fatalf("%+v: got %v, want no error", test.q, err) + } + if got := req.ReadOptions; !proto.Equal(got, test.want) { + t.Errorf("%+v:\ngot %+v\nwant %+v", test.q, got, test.want) + } + } + // Test errors. + for _, q := range []*Query{ + NewQuery("").Transaction(&Transaction{id: nil}), + NewQuery("").Transaction(&Transaction{id: tid}).EventualConsistency(), + } { + req := &pb.RunQueryRequest{} + if err := q.toProto(req); err == nil { + t.Errorf("%+v: got nil, wanted error", q) + } + } +} diff --git a/vendor/cloud.google.com/go/datastore/save.go b/vendor/cloud.google.com/go/datastore/save.go new file mode 100644 index 00000000..2a444699 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/save.go @@ -0,0 +1,470 @@ +// Copyright 2014 Google LLC +// +// 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 datastore + +import ( + "errors" + "fmt" + "reflect" + "time" + "unicode/utf8" + + timepb "github.com/golang/protobuf/ptypes/timestamp" + pb "google.golang.org/genproto/googleapis/datastore/v1" + llpb "google.golang.org/genproto/googleapis/type/latlng" +) + +type saveOpts struct { + noIndex bool + flatten bool + omitEmpty bool +} + +// saveEntity saves an EntityProto into a PropertyLoadSaver or struct pointer. +func saveEntity(key *Key, src interface{}) (*pb.Entity, error) { + var err error + var props []Property + if e, ok := src.(PropertyLoadSaver); ok { + props, err = e.Save() + } else { + props, err = SaveStruct(src) + } + if err != nil { + return nil, err + } + return propertiesToProto(key, props) +} + +// TODO(djd): Convert this and below to return ([]Property, error). +func saveStructProperty(props *[]Property, name string, opts saveOpts, v reflect.Value) error { + p := Property{ + Name: name, + NoIndex: opts.noIndex, + } + + if opts.omitEmpty && isEmptyValue(v) { + return nil + } + + // First check if field type implements PLS. If so, use PLS to + // save. + ok, err := plsFieldSave(props, p, name, opts, v) + if err != nil { + return err + } + if ok { + return nil + } + + switch x := v.Interface().(type) { + case *Key, time.Time, GeoPoint: + p.Value = x + default: + switch v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p.Value = v.Int() + case reflect.Bool: + p.Value = v.Bool() + case reflect.String: + p.Value = v.String() + case reflect.Float32, reflect.Float64: + p.Value = v.Float() + case reflect.Slice: + if v.Type().Elem().Kind() == reflect.Uint8 { + p.Value = v.Bytes() + } else { + return saveSliceProperty(props, name, opts, v) + } + case reflect.Ptr: + if isValidPointerType(v.Type().Elem()) { + if v.IsNil() { + // Nil pointer becomes a nil property value (unless omitempty, handled above). + p.Value = nil + *props = append(*props, p) + return nil + } + // When we recurse on the derefenced pointer, omitempty no longer applies: + // we already know the pointer is not empty, it doesn't matter if its referent + // is empty or not. + opts.omitEmpty = false + return saveStructProperty(props, name, opts, v.Elem()) + } + if v.Type().Elem().Kind() != reflect.Struct { + return fmt.Errorf("datastore: unsupported struct field type: %s", v.Type()) + } + // Pointer to struct is a special case. + if v.IsNil() { + return nil + } + v = v.Elem() + fallthrough + case reflect.Struct: + if !v.CanAddr() { + return fmt.Errorf("datastore: unsupported struct field: value is unaddressable") + } + vi := v.Addr().Interface() + + sub, err := newStructPLS(vi) + if err != nil { + return fmt.Errorf("datastore: unsupported struct field: %v", err) + } + + if opts.flatten { + return sub.save(props, opts, name+".") + } + + var subProps []Property + err = sub.save(&subProps, opts, "") + if err != nil { + return err + } + subKey, err := sub.key(v) + if err != nil { + return err + } + + p.Value = &Entity{ + Key: subKey, + Properties: subProps, + } + } + } + if p.Value == nil { + return fmt.Errorf("datastore: unsupported struct field type: %v", v.Type()) + } + *props = append(*props, p) + return nil +} + +// plsFieldSave first tries to converts v's value to a PLS, then v's addressed +// value to a PLS. If neither succeeds, plsFieldSave returns false for first return +// value. +// If v is successfully converted to a PLS, plsFieldSave will then add the +// Value to property p by way of the PLS's Save method, and append it to props. +// +// If the flatten option is present in opts, name must be prepended to each property's +// name before it is appended to props. Eg. if name were "A" and a subproperty's name +// were "B", the resultant name of the property to be appended to props would be "A.B". +func plsFieldSave(props *[]Property, p Property, name string, opts saveOpts, v reflect.Value) (ok bool, err error) { + vpls, err := plsForSave(v) + if err != nil { + return false, err + } + + if vpls == nil { + return false, nil + } + + subProps, err := vpls.Save() + if err != nil { + return true, err + } + + if opts.flatten { + for _, subp := range subProps { + subp.Name = name + "." + subp.Name + *props = append(*props, subp) + } + return true, nil + } + + p.Value = &Entity{Properties: subProps} + *props = append(*props, p) + + return true, nil +} + +// key extracts the *Key struct field from struct v based on the structCodec of s. +func (s structPLS) key(v reflect.Value) (*Key, error) { + if v.Kind() != reflect.Struct { + return nil, errors.New("datastore: cannot save key of non-struct type") + } + + keyField := s.codec.Match(keyFieldName) + + if keyField == nil { + return nil, nil + } + + f := v.FieldByIndex(keyField.Index) + k, ok := f.Interface().(*Key) + if !ok { + return nil, fmt.Errorf("datastore: %s field on struct %T is not a *datastore.Key", keyFieldName, v.Interface()) + } + + return k, nil +} + +func saveSliceProperty(props *[]Property, name string, opts saveOpts, v reflect.Value) error { + // Easy case: if the slice is empty, we're done. + if v.Len() == 0 { + return nil + } + // Work out the properties generated by the first element in the slice. This will + // usually be a single property, but will be more if this is a slice of structs. + var headProps []Property + if err := saveStructProperty(&headProps, name, opts, v.Index(0)); err != nil { + return err + } + + // Convert the first element's properties into slice properties, and + // keep track of the values in a map. + values := make(map[string][]interface{}, len(headProps)) + for _, p := range headProps { + values[p.Name] = append(make([]interface{}, 0, v.Len()), p.Value) + } + + // Find the elements for the subsequent elements. + for i := 1; i < v.Len(); i++ { + elemProps := make([]Property, 0, len(headProps)) + if err := saveStructProperty(&elemProps, name, opts, v.Index(i)); err != nil { + return err + } + for _, p := range elemProps { + v, ok := values[p.Name] + if !ok { + return fmt.Errorf("datastore: unexpected property %q in elem %d of slice", p.Name, i) + } + values[p.Name] = append(v, p.Value) + } + } + + // Convert to the final properties. + for _, p := range headProps { + p.Value = values[p.Name] + *props = append(*props, p) + } + return nil +} + +func (s structPLS) Save() ([]Property, error) { + var props []Property + if err := s.save(&props, saveOpts{}, ""); err != nil { + return nil, err + } + return props, nil +} + +func (s structPLS) save(props *[]Property, opts saveOpts, prefix string) error { + for _, f := range s.codec { + name := prefix + f.Name + v := getField(s.v, f.Index) + if !v.IsValid() || !v.CanSet() { + continue + } + + var tagOpts saveOpts + if f.ParsedTag != nil { + tagOpts = f.ParsedTag.(saveOpts) + } + + var opts1 saveOpts + opts1.noIndex = opts.noIndex || tagOpts.noIndex + opts1.flatten = opts.flatten || tagOpts.flatten + opts1.omitEmpty = tagOpts.omitEmpty // don't propagate + if err := saveStructProperty(props, name, opts1, v); err != nil { + return err + } + } + return nil +} + +// getField returns the field from v at the given index path. +// If it encounters a nil-valued field in the path, getField +// stops and returns a zero-valued reflect.Value, preventing the +// panic that would have been caused by reflect's FieldByIndex. +func getField(v reflect.Value, index []int) reflect.Value { + var zero reflect.Value + if v.Type().Kind() != reflect.Struct { + return zero + } + + for _, i := range index { + if v.Kind() == reflect.Ptr && v.Type().Elem().Kind() == reflect.Struct { + if v.IsNil() { + return zero + } + v = v.Elem() + } + v = v.Field(i) + } + return v +} + +func propertiesToProto(key *Key, props []Property) (*pb.Entity, error) { + e := &pb.Entity{ + Key: keyToProto(key), + Properties: map[string]*pb.Value{}, + } + indexedProps := 0 + for _, p := range props { + // Do not send a Key value a field to datastore. + if p.Name == keyFieldName { + continue + } + + val, err := interfaceToProto(p.Value, p.NoIndex) + if err != nil { + return nil, fmt.Errorf("datastore: %v for a Property with Name %q", err, p.Name) + } + if !p.NoIndex { + rVal := reflect.ValueOf(p.Value) + if rVal.Kind() == reflect.Slice && rVal.Type().Elem().Kind() != reflect.Uint8 { + indexedProps += rVal.Len() + } else { + indexedProps++ + } + } + if indexedProps > maxIndexedProperties { + return nil, errors.New("datastore: too many indexed properties") + } + + if _, ok := e.Properties[p.Name]; ok { + return nil, fmt.Errorf("datastore: duplicate Property with Name %q", p.Name) + } + e.Properties[p.Name] = val + } + return e, nil +} + +func interfaceToProto(iv interface{}, noIndex bool) (*pb.Value, error) { + val := &pb.Value{ExcludeFromIndexes: noIndex} + switch v := iv.(type) { + case int: + val.ValueType = &pb.Value_IntegerValue{IntegerValue: int64(v)} + case int32: + val.ValueType = &pb.Value_IntegerValue{IntegerValue: int64(v)} + case int64: + val.ValueType = &pb.Value_IntegerValue{IntegerValue: v} + case bool: + val.ValueType = &pb.Value_BooleanValue{BooleanValue: v} + case string: + if len(v) > 1500 && !noIndex { + return nil, errors.New("string property too long to index") + } + if !utf8.ValidString(v) { + return nil, fmt.Errorf("string is not valid utf8: %q", v) + } + val.ValueType = &pb.Value_StringValue{StringValue: v} + case float32: + val.ValueType = &pb.Value_DoubleValue{DoubleValue: float64(v)} + case float64: + val.ValueType = &pb.Value_DoubleValue{DoubleValue: v} + case *Key: + if v == nil { + val.ValueType = &pb.Value_NullValue{} + } else { + val.ValueType = &pb.Value_KeyValue{KeyValue: keyToProto(v)} + } + case GeoPoint: + if !v.Valid() { + return nil, errors.New("invalid GeoPoint value") + } + val.ValueType = &pb.Value_GeoPointValue{GeoPointValue: &llpb.LatLng{ + Latitude: v.Lat, + Longitude: v.Lng, + }} + case time.Time: + if v.Before(minTime) || v.After(maxTime) { + return nil, errors.New("time value out of range") + } + val.ValueType = &pb.Value_TimestampValue{TimestampValue: &timepb.Timestamp{ + Seconds: v.Unix(), + Nanos: int32(v.Nanosecond()), + }} + case []byte: + if len(v) > 1500 && !noIndex { + return nil, errors.New("[]byte property too long to index") + } + val.ValueType = &pb.Value_BlobValue{BlobValue: v} + case *Entity: + e, err := propertiesToProto(v.Key, v.Properties) + if err != nil { + return nil, err + } + val.ValueType = &pb.Value_EntityValue{EntityValue: e} + case []interface{}: + arr := make([]*pb.Value, 0, len(v)) + for i, v := range v { + elem, err := interfaceToProto(v, noIndex) + if err != nil { + return nil, fmt.Errorf("%v at index %d", err, i) + } + arr = append(arr, elem) + } + val.ValueType = &pb.Value_ArrayValue{ArrayValue: &pb.ArrayValue{Values: arr}} + // ArrayValues have ExcludeFromIndexes set on the individual items, rather + // than the top-level value. + val.ExcludeFromIndexes = false + default: + rv := reflect.ValueOf(iv) + if !rv.IsValid() { + val.ValueType = &pb.Value_NullValue{} + } else if rv.Kind() == reflect.Ptr { // non-nil pointer: dereference + if rv.IsNil() { + val.ValueType = &pb.Value_NullValue{} + return val, nil + } + return interfaceToProto(rv.Elem().Interface(), noIndex) + } else { + return nil, fmt.Errorf("invalid Value type %T", iv) + } + } + // TODO(jbd): Support EntityValue. + return val, nil +} + +// isEmptyValue is taken from the encoding/json package in the +// standard library. +func isEmptyValue(v reflect.Value) bool { + switch v.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + case reflect.Struct: + if t, ok := v.Interface().(time.Time); ok { + return t.IsZero() + } + } + return false +} + +// isValidPointerType reports whether a struct field can be a pointer to type t +// for the purposes of saving and loading. +func isValidPointerType(t reflect.Type) bool { + if t == typeOfTime || t == typeOfGeoPoint { + return true + } + switch t.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return true + case reflect.Bool: + return true + case reflect.String: + return true + case reflect.Float32, reflect.Float64: + return true + } + return false +} diff --git a/vendor/cloud.google.com/go/datastore/save_test.go b/vendor/cloud.google.com/go/datastore/save_test.go new file mode 100644 index 00000000..36e9fb04 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/save_test.go @@ -0,0 +1,289 @@ +// Copyright 2016 Google LLC +// +// 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 datastore + +import ( + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + pb "google.golang.org/genproto/googleapis/datastore/v1" +) + +func TestInterfaceToProtoNil(t *testing.T) { + // A nil *Key, or a nil value of any other pointer type, should convert to a NullValue. + for _, in := range []interface{}{ + (*Key)(nil), + (*int)(nil), + (*string)(nil), + (*bool)(nil), + (*float64)(nil), + (*GeoPoint)(nil), + (*time.Time)(nil), + } { + got, err := interfaceToProto(in, false) + if err != nil { + t.Fatalf("%T: %v", in, err) + } + _, ok := got.ValueType.(*pb.Value_NullValue) + if !ok { + t.Errorf("%T: got: %T\nwant: %T", in, got.ValueType, &pb.Value_NullValue{}) + } + } +} + +func TestSaveEntityNested(t *testing.T) { + type WithKey struct { + X string + I int + K *Key `datastore:"__key__"` + } + + type NestedWithKey struct { + Y string + N WithKey + } + + type WithoutKey struct { + X string + I int + } + + type NestedWithoutKey struct { + Y string + N WithoutKey + } + + type a struct { + S string + } + + type UnexpAnonym struct { + a + } + + testCases := []struct { + desc string + src interface{} + key *Key + want *pb.Entity + }{ + { + desc: "nested entity with key", + src: &NestedWithKey{ + Y: "yyy", + N: WithKey{ + X: "two", + I: 2, + K: testKey1a, + }, + }, + key: testKey0, + want: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Y": {ValueType: &pb.Value_StringValue{StringValue: "yyy"}}, + "N": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Key: keyToProto(testKey1a), + Properties: map[string]*pb.Value{ + "X": {ValueType: &pb.Value_StringValue{StringValue: "two"}}, + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 2}}, + }, + }, + }}, + }, + }, + }, + { + desc: "nested entity with incomplete key", + src: &NestedWithKey{ + Y: "yyy", + N: WithKey{ + X: "two", + I: 2, + K: incompleteKey, + }, + }, + key: testKey0, + want: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Y": {ValueType: &pb.Value_StringValue{StringValue: "yyy"}}, + "N": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Key: keyToProto(incompleteKey), + Properties: map[string]*pb.Value{ + "X": {ValueType: &pb.Value_StringValue{StringValue: "two"}}, + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 2}}, + }, + }, + }}, + }, + }, + }, + { + desc: "nested entity without key", + src: &NestedWithoutKey{ + Y: "yyy", + N: WithoutKey{ + X: "two", + I: 2, + }, + }, + key: testKey0, + want: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "Y": {ValueType: &pb.Value_StringValue{StringValue: "yyy"}}, + "N": {ValueType: &pb.Value_EntityValue{ + EntityValue: &pb.Entity{ + Properties: map[string]*pb.Value{ + "X": {ValueType: &pb.Value_StringValue{StringValue: "two"}}, + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 2}}, + }, + }, + }}, + }, + }, + }, + { + desc: "key at top level", + src: &WithKey{ + X: "three", + I: 3, + K: testKey0, + }, + key: testKey0, + want: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "X": {ValueType: &pb.Value_StringValue{StringValue: "three"}}, + "I": {ValueType: &pb.Value_IntegerValue{IntegerValue: 3}}, + }, + }, + }, + { + desc: "nested unexported anonymous struct field", + src: &UnexpAnonym{ + a{S: "hello"}, + }, + key: testKey0, + want: &pb.Entity{ + Key: keyToProto(testKey0), + Properties: map[string]*pb.Value{ + "S": {ValueType: &pb.Value_StringValue{StringValue: "hello"}}, + }, + }, + }, + } + + for _, tc := range testCases { + got, err := saveEntity(tc.key, tc.src) + if err != nil { + t.Errorf("saveEntity: %s: %v", tc.desc, err) + continue + } + + if !testutil.Equal(tc.want, got) { + t.Errorf("%s: compare:\ngot: %#v\nwant: %#v", tc.desc, got, tc.want) + } + } +} + +func TestSavePointers(t *testing.T) { + for _, test := range []struct { + desc string + in interface{} + want []Property + }{ + { + desc: "nil pointers save as nil-valued properties", + in: &Pointers{}, + want: []Property{ + {Name: "Pi", Value: nil}, + {Name: "Ps", Value: nil}, + {Name: "Pb", Value: nil}, + {Name: "Pf", Value: nil}, + {Name: "Pg", Value: nil}, + {Name: "Pt", Value: nil}, + }, + }, + { + desc: "nil omitempty pointers not saved", + in: &PointersOmitEmpty{}, + want: []Property(nil), + }, + { + desc: "non-nil omitempty zero-valued pointers are saved", + in: func() *PointersOmitEmpty { pi := 0; return &PointersOmitEmpty{Pi: &pi} }(), + want: []Property{{Name: "Pi", Value: int64(0)}}, + }, + { + desc: "non-nil zero-valued pointers save as zero values", + in: populatedPointers(), + want: []Property{ + {Name: "Pi", Value: int64(0)}, + {Name: "Ps", Value: ""}, + {Name: "Pb", Value: false}, + {Name: "Pf", Value: 0.0}, + {Name: "Pg", Value: GeoPoint{}}, + {Name: "Pt", Value: time.Time{}}, + }, + }, + { + desc: "non-nil non-zero-valued pointers save as the appropriate values", + in: func() *Pointers { + p := populatedPointers() + *p.Pi = 1 + *p.Ps = "x" + *p.Pb = true + *p.Pf = 3.14 + *p.Pg = GeoPoint{Lat: 1, Lng: 2} + *p.Pt = time.Unix(100, 0) + return p + }(), + want: []Property{ + {Name: "Pi", Value: int64(1)}, + {Name: "Ps", Value: "x"}, + {Name: "Pb", Value: true}, + {Name: "Pf", Value: 3.14}, + {Name: "Pg", Value: GeoPoint{Lat: 1, Lng: 2}}, + {Name: "Pt", Value: time.Unix(100, 0)}, + }, + }, + } { + got, err := SaveStruct(test.in) + if err != nil { + t.Fatalf("%s: %v", test.desc, err) + } + if !testutil.Equal(got, test.want) { + t.Errorf("%s\ngot %#v\nwant %#v\n", test.desc, got, test.want) + } + } +} + +func TestSaveEmptySlice(t *testing.T) { + // Zero-length slice fields are not saved. + for _, slice := range [][]string{nil, {}} { + got, err := SaveStruct(&struct{ S []string }{S: slice}) + if err != nil { + t.Fatal(err) + } + if len(got) != 0 { + t.Errorf("%#v: got %d properties, wanted zero", slice, len(got)) + } + } +} diff --git a/vendor/cloud.google.com/go/datastore/testdata/index.yaml b/vendor/cloud.google.com/go/datastore/testdata/index.yaml new file mode 100644 index 00000000..47bc9de8 --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/testdata/index.yaml @@ -0,0 +1,41 @@ +indexes: + +- kind: SQChild + ancestor: yes + properties: + - name: T + - name: I + +- kind: SQChild + ancestor: yes + properties: + - name: T + - name: I + direction: desc + +- kind: SQChild + ancestor: yes + properties: + - name: I + - name: T + - name: U + +- kind: SQChild + ancestor: yes + properties: + - name: I + - name: T + - name: U + +- kind: SQChild + ancestor: yes + properties: + - name: T + - name: J + +- kind: SQChild + ancestor: yes + properties: + - name: T + - name: J + - name: U \ No newline at end of file diff --git a/vendor/cloud.google.com/go/datastore/time.go b/vendor/cloud.google.com/go/datastore/time.go new file mode 100644 index 00000000..da6c780d --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/time.go @@ -0,0 +1,36 @@ +// Copyright 2014 Google LLC +// +// 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 datastore + +import ( + "math" + "time" +) + +var ( + minTime = time.Unix(int64(math.MinInt64)/1e6, (int64(math.MinInt64)%1e6)*1e3) + maxTime = time.Unix(int64(math.MaxInt64)/1e6, (int64(math.MaxInt64)%1e6)*1e3) +) + +func toUnixMicro(t time.Time) int64 { + // We cannot use t.UnixNano() / 1e3 because we want to handle times more than + // 2^63 nanoseconds (which is about 292 years) away from 1970, and those cannot + // be represented in the numerator of a single int64 divide. + return t.Unix()*1e6 + int64(t.Nanosecond()/1e3) +} + +func fromUnixMicro(t int64) time.Time { + return time.Unix(t/1e6, (t%1e6)*1e3) +} diff --git a/vendor/cloud.google.com/go/datastore/time_test.go b/vendor/cloud.google.com/go/datastore/time_test.go new file mode 100644 index 00000000..f82efc7e --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/time_test.go @@ -0,0 +1,75 @@ +// Copyright 2014 Google LLC +// +// 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 datastore + +import ( + "testing" + "time" +) + +func TestUnixMicro(t *testing.T) { + // Test that all these time.Time values survive a round trip to unix micros. + testCases := []time.Time{ + {}, + time.Date(2, 1, 1, 0, 0, 0, 0, time.UTC), + time.Date(23, 1, 1, 0, 0, 0, 0, time.UTC), + time.Date(234, 1, 1, 0, 0, 0, 0, time.UTC), + time.Date(1000, 1, 1, 0, 0, 0, 0, time.UTC), + time.Date(1600, 1, 1, 0, 0, 0, 0, time.UTC), + time.Date(1700, 1, 1, 0, 0, 0, 0, time.UTC), + time.Date(1800, 1, 1, 0, 0, 0, 0, time.UTC), + time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC), + time.Unix(-1e6, -1000), + time.Unix(-1e6, 0), + time.Unix(-1e6, +1000), + time.Unix(-60, -1000), + time.Unix(-60, 0), + time.Unix(-60, +1000), + time.Unix(-1, -1000), + time.Unix(-1, 0), + time.Unix(-1, +1000), + time.Unix(0, -3000), + time.Unix(0, -2000), + time.Unix(0, -1000), + time.Unix(0, 0), + time.Unix(0, +1000), + time.Unix(0, +2000), + time.Unix(+60, -1000), + time.Unix(+60, 0), + time.Unix(+60, +1000), + time.Unix(+1e6, -1000), + time.Unix(+1e6, 0), + time.Unix(+1e6, +1000), + time.Date(1999, 12, 31, 23, 59, 59, 999000, time.UTC), + time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), + time.Date(2006, 1, 2, 15, 4, 5, 678000, time.UTC), + time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), + time.Date(3456, 1, 1, 0, 0, 0, 0, time.UTC), + } + for _, tc := range testCases { + got := fromUnixMicro(toUnixMicro(tc)) + if !got.Equal(tc) { + t.Errorf("got %q, want %q", got, tc) + } + } + + // Test that a time.Time that isn't an integral number of microseconds + // is not perfectly reconstructed after a round trip. + t0 := time.Unix(0, 123) + t1 := fromUnixMicro(toUnixMicro(t0)) + if t1.Nanosecond()%1000 != 0 || t0.Nanosecond()%1000 == 0 { + t.Errorf("quantization to µs: got %q with %d ns, started with %d ns", t1, t1.Nanosecond(), t0.Nanosecond()) + } +} diff --git a/vendor/cloud.google.com/go/datastore/transaction.go b/vendor/cloud.google.com/go/datastore/transaction.go new file mode 100644 index 00000000..236f505d --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/transaction.go @@ -0,0 +1,408 @@ +// Copyright 2014 Google LLC +// +// 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 datastore + +import ( + "context" + "errors" + + "cloud.google.com/go/internal/trace" + pb "google.golang.org/genproto/googleapis/datastore/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" +) + +// ErrConcurrentTransaction is returned when a transaction is rolled back due +// to a conflict with a concurrent transaction. +var ErrConcurrentTransaction = errors.New("datastore: concurrent transaction") + +var errExpiredTransaction = errors.New("datastore: transaction expired") + +type transactionSettings struct { + attempts int + readOnly bool + prevID []byte // ID of the transaction to retry +} + +// newTransactionSettings creates a transactionSettings with a given TransactionOption slice. +// Unconfigured options will be set to default values. +func newTransactionSettings(opts []TransactionOption) *transactionSettings { + s := &transactionSettings{attempts: 3} + for _, o := range opts { + o.apply(s) + } + return s +} + +// TransactionOption configures the way a transaction is executed. +type TransactionOption interface { + apply(*transactionSettings) +} + +// MaxAttempts returns a TransactionOption that overrides the default 3 attempt times. +func MaxAttempts(attempts int) TransactionOption { + return maxAttempts(attempts) +} + +type maxAttempts int + +func (w maxAttempts) apply(s *transactionSettings) { + if w > 0 { + s.attempts = int(w) + } +} + +// ReadOnly is a TransactionOption that marks the transaction as read-only. +var ReadOnly TransactionOption + +func init() { + ReadOnly = readOnly{} +} + +type readOnly struct{} + +func (readOnly) apply(s *transactionSettings) { + s.readOnly = true +} + +// Transaction represents a set of datastore operations to be committed atomically. +// +// Operations are enqueued by calling the Put and Delete methods on Transaction +// (or their Multi-equivalents). These operations are only committed when the +// Commit method is invoked. To ensure consistency, reads must be performed by +// using Transaction's Get method or by using the Transaction method when +// building a query. +// +// A Transaction must be committed or rolled back exactly once. +type Transaction struct { + id []byte + client *Client + ctx context.Context + mutations []*pb.Mutation // The mutations to apply. + pending map[int]*PendingKey // Map from mutation index to incomplete keys pending transaction completion. +} + +// NewTransaction starts a new transaction. +func (c *Client) NewTransaction(ctx context.Context, opts ...TransactionOption) (t *Transaction, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.NewTransaction") + defer func() { trace.EndSpan(ctx, err) }() + + for _, o := range opts { + if _, ok := o.(maxAttempts); ok { + return nil, errors.New("datastore: NewTransaction does not accept MaxAttempts option") + } + } + return c.newTransaction(ctx, newTransactionSettings(opts)) +} + +func (c *Client) newTransaction(ctx context.Context, s *transactionSettings) (*Transaction, error) { + req := &pb.BeginTransactionRequest{ProjectId: c.dataset} + if s.readOnly { + req.TransactionOptions = &pb.TransactionOptions{ + Mode: &pb.TransactionOptions_ReadOnly_{ReadOnly: &pb.TransactionOptions_ReadOnly{}}, + } + } else if s.prevID != nil { + req.TransactionOptions = &pb.TransactionOptions{ + Mode: &pb.TransactionOptions_ReadWrite_{ReadWrite: &pb.TransactionOptions_ReadWrite{ + PreviousTransaction: s.prevID, + }}, + } + } + resp, err := c.client.BeginTransaction(ctx, req) + if err != nil { + return nil, err + } + return &Transaction{ + id: resp.Transaction, + ctx: ctx, + client: c, + mutations: nil, + pending: make(map[int]*PendingKey), + }, nil +} + +// RunInTransaction runs f in a transaction. f is invoked with a Transaction +// that f should use for all the transaction's datastore operations. +// +// f must not call Commit or Rollback on the provided Transaction. +// +// If f returns nil, RunInTransaction commits the transaction, +// returning the Commit and a nil error if it succeeds. If the commit fails due +// to a conflicting transaction, RunInTransaction retries f with a new +// Transaction. It gives up and returns ErrConcurrentTransaction after three +// failed attempts (or as configured with MaxAttempts). +// +// If f returns non-nil, then the transaction will be rolled back and +// RunInTransaction will return the same error. The function f is not retried. +// +// Note that when f returns, the transaction is not committed. Calling code +// must not assume that any of f's changes have been committed until +// RunInTransaction returns nil. +// +// Since f may be called multiple times, f should usually be idempotent – that +// is, it should have the same result when called multiple times. Note that +// Transaction.Get will append when unmarshalling slice fields, so it is not +// necessarily idempotent. +func (c *Client) RunInTransaction(ctx context.Context, f func(tx *Transaction) error, opts ...TransactionOption) (cmt *Commit, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.RunInTransaction") + defer func() { trace.EndSpan(ctx, err) }() + + settings := newTransactionSettings(opts) + for n := 0; n < settings.attempts; n++ { + tx, err := c.newTransaction(ctx, settings) + if err != nil { + return nil, err + } + if err := f(tx); err != nil { + _ = tx.Rollback() + return nil, err + } + if cmt, err := tx.Commit(); err != ErrConcurrentTransaction { + return cmt, err + } + // Pass this transaction's ID to the retry transaction to preserve + // transaction priority. + if !settings.readOnly { + settings.prevID = tx.id + } + } + return nil, ErrConcurrentTransaction +} + +// Commit applies the enqueued operations atomically. +func (t *Transaction) Commit() (c *Commit, err error) { + t.ctx = trace.StartSpan(t.ctx, "cloud.google.com/go/datastore.Transaction.Commit") + defer func() { trace.EndSpan(t.ctx, err) }() + + if t.id == nil { + return nil, errExpiredTransaction + } + req := &pb.CommitRequest{ + ProjectId: t.client.dataset, + TransactionSelector: &pb.CommitRequest_Transaction{Transaction: t.id}, + Mutations: t.mutations, + Mode: pb.CommitRequest_TRANSACTIONAL, + } + resp, err := t.client.client.Commit(t.ctx, req) + if grpc.Code(err) == codes.Aborted { + return nil, ErrConcurrentTransaction + } + t.id = nil // mark the transaction as expired + if err != nil { + return nil, err + } + + // Copy any newly minted keys into the returned keys. + for i, p := range t.pending { + if i >= len(resp.MutationResults) || resp.MutationResults[i].Key == nil { + return nil, errors.New("datastore: internal error: server returned the wrong mutation results") + } + key, err := protoToKey(resp.MutationResults[i].Key) + if err != nil { + return nil, errors.New("datastore: internal error: server returned an invalid key") + } + p.key = key + p.commit = c + } + + return c, nil +} + +// Rollback abandons a pending transaction. +func (t *Transaction) Rollback() (err error) { + t.ctx = trace.StartSpan(t.ctx, "cloud.google.com/go/datastore.Transaction.Rollback") + defer func() { trace.EndSpan(t.ctx, err) }() + + if t.id == nil { + return errExpiredTransaction + } + id := t.id + t.id = nil + _, err = t.client.client.Rollback(t.ctx, &pb.RollbackRequest{ + ProjectId: t.client.dataset, + Transaction: id, + }) + return err +} + +// Get is the transaction-specific version of the package function Get. +// All reads performed during the transaction will come from a single consistent +// snapshot. Furthermore, if the transaction is set to a serializable isolation +// level, another transaction cannot concurrently modify the data that is read +// or modified by this transaction. +func (t *Transaction) Get(key *Key, dst interface{}) (err error) { + t.ctx = trace.StartSpan(t.ctx, "cloud.google.com/go/datastore.Transaction.Get") + defer func() { trace.EndSpan(t.ctx, err) }() + + opts := &pb.ReadOptions{ + ConsistencyType: &pb.ReadOptions_Transaction{Transaction: t.id}, + } + err = t.client.get(t.ctx, []*Key{key}, []interface{}{dst}, opts) + if me, ok := err.(MultiError); ok { + return me[0] + } + return err +} + +// GetMulti is a batch version of Get. +func (t *Transaction) GetMulti(keys []*Key, dst interface{}) (err error) { + t.ctx = trace.StartSpan(t.ctx, "cloud.google.com/go/datastore.Transaction.GetMulti") + defer func() { trace.EndSpan(t.ctx, err) }() + + if t.id == nil { + return errExpiredTransaction + } + opts := &pb.ReadOptions{ + ConsistencyType: &pb.ReadOptions_Transaction{Transaction: t.id}, + } + return t.client.get(t.ctx, keys, dst, opts) +} + +// Put is the transaction-specific version of the package function Put. +// +// Put returns a PendingKey which can be resolved into a Key using the +// return value from a successful Commit. If key is an incomplete key, the +// returned pending key will resolve to a unique key generated by the +// datastore. +func (t *Transaction) Put(key *Key, src interface{}) (*PendingKey, error) { + h, err := t.PutMulti([]*Key{key}, []interface{}{src}) + if err != nil { + if me, ok := err.(MultiError); ok { + return nil, me[0] + } + return nil, err + } + return h[0], nil +} + +// PutMulti is a batch version of Put. One PendingKey is returned for each +// element of src in the same order. +// TODO(jba): rewrite in terms of Mutate. +func (t *Transaction) PutMulti(keys []*Key, src interface{}) (ret []*PendingKey, err error) { + t.ctx = trace.StartSpan(t.ctx, "cloud.google.com/go/datastore.Transaction.PutMulti") + defer func() { trace.EndSpan(t.ctx, err) }() + + if t.id == nil { + return nil, errExpiredTransaction + } + mutations, err := putMutations(keys, src) + if err != nil { + return nil, err + } + origin := len(t.mutations) + t.mutations = append(t.mutations, mutations...) + + // Prepare the returned handles, pre-populating where possible. + ret = make([]*PendingKey, len(keys)) + for i, key := range keys { + p := &PendingKey{} + if key.Incomplete() { + // This key will be in the final commit result. + t.pending[origin+i] = p + } else { + p.key = key + } + ret[i] = p + } + + return ret, nil +} + +// Delete is the transaction-specific version of the package function Delete. +// Delete enqueues the deletion of the entity for the given key, to be +// committed atomically upon calling Commit. +func (t *Transaction) Delete(key *Key) error { + err := t.DeleteMulti([]*Key{key}) + if me, ok := err.(MultiError); ok { + return me[0] + } + return err +} + +// DeleteMulti is a batch version of Delete. +// TODO(jba): rewrite in terms of Mutate. +func (t *Transaction) DeleteMulti(keys []*Key) (err error) { + t.ctx = trace.StartSpan(t.ctx, "cloud.google.com/go/datastore.Transaction.DeleteMulti") + defer func() { trace.EndSpan(t.ctx, err) }() + + if t.id == nil { + return errExpiredTransaction + } + mutations, err := deleteMutations(keys) + if err != nil { + return err + } + t.mutations = append(t.mutations, mutations...) + return nil +} + +// Mutate adds the mutations to the transaction. They will all be applied atomically +// upon calling Commit. Mutate returns a PendingKey for each Mutation in the argument +// list, in the same order. PendingKeys for Delete mutations are always nil. +// +// If any of the mutations are invalid, Mutate returns a MultiError with the errors. +// Mutate returns a MultiError in this case even if there is only one Mutation. +// +// For an example, see Client.Mutate. +func (t *Transaction) Mutate(muts ...*Mutation) ([]*PendingKey, error) { + if t.id == nil { + return nil, errExpiredTransaction + } + pmuts, err := mutationProtos(muts) + if err != nil { + return nil, err + } + origin := len(t.mutations) + t.mutations = append(t.mutations, pmuts...) + // Prepare the returned handles, pre-populating where possible. + ret := make([]*PendingKey, len(muts)) + for i, mut := range muts { + if mut.isDelete() { + continue + } + p := &PendingKey{} + if mut.key.Incomplete() { + // This key will be in the final commit result. + t.pending[origin+i] = p + } else { + p.key = mut.key + } + ret[i] = p + } + return ret, nil +} + +// Commit represents the result of a committed transaction. +type Commit struct{} + +// Key resolves a pending key handle into a final key. +func (c *Commit) Key(p *PendingKey) *Key { + if p == nil { // if called on a *PendingKey from a Delete mutation + return nil + } + // If p.commit is nil, the PendingKey did not come from an incomplete key, + // so p.key is valid. + if p.commit != nil && c != p.commit { + panic("PendingKey was not created by corresponding transaction") + } + return p.key +} + +// PendingKey represents the key for newly-inserted entity. It can be +// resolved into a Key by calling the Key method of Commit. +type PendingKey struct { + key *Key + commit *Commit +} diff --git a/vendor/cloud.google.com/go/datastore/transaction_test.go b/vendor/cloud.google.com/go/datastore/transaction_test.go new file mode 100644 index 00000000..31d7e9fc --- /dev/null +++ b/vendor/cloud.google.com/go/datastore/transaction_test.go @@ -0,0 +1,77 @@ +// Copyright 2017 Google LLC +// +// 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 datastore + +import ( + "context" + "testing" + + "github.com/golang/protobuf/proto" + pb "google.golang.org/genproto/googleapis/datastore/v1" +) + +func TestNewTransaction(t *testing.T) { + var got *pb.BeginTransactionRequest + client := &Client{ + dataset: "project", + client: &fakeDatastoreClient{ + beginTransaction: func(req *pb.BeginTransactionRequest) (*pb.BeginTransactionResponse, error) { + got = req + return &pb.BeginTransactionResponse{ + Transaction: []byte("tid"), + }, nil + }, + }, + } + ctx := context.Background() + for _, test := range []struct { + settings *transactionSettings + want *pb.BeginTransactionRequest + }{ + { + &transactionSettings{}, + &pb.BeginTransactionRequest{ProjectId: "project"}, + }, + { + &transactionSettings{readOnly: true}, + &pb.BeginTransactionRequest{ + ProjectId: "project", + TransactionOptions: &pb.TransactionOptions{ + Mode: &pb.TransactionOptions_ReadOnly_{ReadOnly: &pb.TransactionOptions_ReadOnly{}}, + }, + }, + }, + { + &transactionSettings{prevID: []byte("tid")}, + &pb.BeginTransactionRequest{ + ProjectId: "project", + TransactionOptions: &pb.TransactionOptions{ + Mode: &pb.TransactionOptions_ReadWrite_{ReadWrite: &pb.TransactionOptions_ReadWrite{ + PreviousTransaction: []byte("tid"), + }, + }, + }, + }, + }, + } { + _, err := client.newTransaction(ctx, test.settings) + if err != nil { + t.Fatal(err) + } + if !proto.Equal(got, test.want) { + t.Errorf("%+v:\ngot %+v\nwant %+v", test.settings, got, test.want) + } + } +} diff --git a/vendor/cloud.google.com/go/debugger/apiv2/controller2_client.go b/vendor/cloud.google.com/go/debugger/apiv2/controller2_client.go new file mode 100644 index 00000000..3c12efbf --- /dev/null +++ b/vendor/cloud.google.com/go/debugger/apiv2/controller2_client.go @@ -0,0 +1,216 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package debugger + +import ( + "context" + "time" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + clouddebuggerpb "google.golang.org/genproto/googleapis/devtools/clouddebugger/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// Controller2CallOptions contains the retry settings for each method of Controller2Client. +type Controller2CallOptions struct { + RegisterDebuggee []gax.CallOption + ListActiveBreakpoints []gax.CallOption + UpdateActiveBreakpoint []gax.CallOption +} + +func defaultController2ClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("clouddebugger.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultController2CallOptions() *Controller2CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &Controller2CallOptions{ + RegisterDebuggee: retry[[2]string{"default", "non_idempotent"}], + ListActiveBreakpoints: retry[[2]string{"default", "idempotent"}], + UpdateActiveBreakpoint: retry[[2]string{"default", "idempotent"}], + } +} + +// Controller2Client is a client for interacting with Stackdriver Debugger API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Controller2Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + controller2Client clouddebuggerpb.Controller2Client + + // The call options for this service. + CallOptions *Controller2CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewController2Client creates a new controller2 client. +// +// The Controller service provides the API for orchestrating a collection of +// debugger agents to perform debugging tasks. These agents are each attached +// to a process of an application which may include one or more replicas. +// +// The debugger agents register with the Controller to identify the application +// being debugged, the Debuggee. All agents that register with the same data, +// represent the same Debuggee, and are assigned the same debuggee_id. +// +// The debugger agents call the Controller to retrieve the list of active +// Breakpoints. Agents with the same debuggee_id get the same breakpoints +// list. An agent that can fulfill the breakpoint request updates the +// Controller with the breakpoint result. The controller selects the first +// result received and discards the rest of the results. +// Agents that poll again for active breakpoints will no longer have +// the completed breakpoint in the list and should remove that breakpoint from +// their attached process. +// +// The Controller service does not provide a way to retrieve the results of +// a completed breakpoint. This functionality is available using the Debugger +// service. +func NewController2Client(ctx context.Context, opts ...option.ClientOption) (*Controller2Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultController2ClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Controller2Client{ + conn: conn, + CallOptions: defaultController2CallOptions(), + + controller2Client: clouddebuggerpb.NewController2Client(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Controller2Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Controller2Client) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Controller2Client) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// RegisterDebuggee registers the debuggee with the controller service. +// +// All agents attached to the same application must call this method with +// exactly the same request content to get back the same stable debuggee_id. +// Agents should call this method again whenever google.rpc.Code.NOT_FOUND +// is returned from any controller method. +// +// This protocol allows the controller service to disable debuggees, recover +// from data loss, or change the debuggee_id format. Agents must handle +// debuggee_id value changing upon re-registration. +func (c *Controller2Client) RegisterDebuggee(ctx context.Context, req *clouddebuggerpb.RegisterDebuggeeRequest, opts ...gax.CallOption) (*clouddebuggerpb.RegisterDebuggeeResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.RegisterDebuggee[0:len(c.CallOptions.RegisterDebuggee):len(c.CallOptions.RegisterDebuggee)], opts...) + var resp *clouddebuggerpb.RegisterDebuggeeResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.controller2Client.RegisterDebuggee(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListActiveBreakpoints returns the list of all active breakpoints for the debuggee. +// +// The breakpoint specification (location, condition, and expressions +// fields) is semantically immutable, although the field values may +// change. For example, an agent may update the location line number +// to reflect the actual line where the breakpoint was set, but this +// doesn't change the breakpoint semantics. +// +// This means that an agent does not need to check if a breakpoint has changed +// when it encounters the same breakpoint on a successive call. +// Moreover, an agent should remember the breakpoints that are completed +// until the controller removes them from the active list to avoid +// setting those breakpoints again. +func (c *Controller2Client) ListActiveBreakpoints(ctx context.Context, req *clouddebuggerpb.ListActiveBreakpointsRequest, opts ...gax.CallOption) (*clouddebuggerpb.ListActiveBreakpointsResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListActiveBreakpoints[0:len(c.CallOptions.ListActiveBreakpoints):len(c.CallOptions.ListActiveBreakpoints)], opts...) + var resp *clouddebuggerpb.ListActiveBreakpointsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.controller2Client.ListActiveBreakpoints(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateActiveBreakpoint updates the breakpoint state or mutable fields. +// The entire Breakpoint message must be sent back to the controller service. +// +// Updates to active breakpoint fields are only allowed if the new value +// does not change the breakpoint specification. Updates to the location, +// condition and expressions fields should not alter the breakpoint +// semantics. These may only make changes such as canonicalizing a value +// or snapping the location to the correct line of code. +func (c *Controller2Client) UpdateActiveBreakpoint(ctx context.Context, req *clouddebuggerpb.UpdateActiveBreakpointRequest, opts ...gax.CallOption) (*clouddebuggerpb.UpdateActiveBreakpointResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateActiveBreakpoint[0:len(c.CallOptions.UpdateActiveBreakpoint):len(c.CallOptions.UpdateActiveBreakpoint)], opts...) + var resp *clouddebuggerpb.UpdateActiveBreakpointResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.controller2Client.UpdateActiveBreakpoint(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/debugger/apiv2/controller2_client_example_test.go b/vendor/cloud.google.com/go/debugger/apiv2/controller2_client_example_test.go new file mode 100644 index 00000000..cbe64c3f --- /dev/null +++ b/vendor/cloud.google.com/go/debugger/apiv2/controller2_client_example_test.go @@ -0,0 +1,88 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package debugger_test + +import ( + "context" + + debugger "cloud.google.com/go/debugger/apiv2" + clouddebuggerpb "google.golang.org/genproto/googleapis/devtools/clouddebugger/v2" +) + +func ExampleNewController2Client() { + ctx := context.Background() + c, err := debugger.NewController2Client(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleController2Client_RegisterDebuggee() { + ctx := context.Background() + c, err := debugger.NewController2Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouddebuggerpb.RegisterDebuggeeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.RegisterDebuggee(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleController2Client_ListActiveBreakpoints() { + ctx := context.Background() + c, err := debugger.NewController2Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouddebuggerpb.ListActiveBreakpointsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ListActiveBreakpoints(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleController2Client_UpdateActiveBreakpoint() { + ctx := context.Background() + c, err := debugger.NewController2Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouddebuggerpb.UpdateActiveBreakpointRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateActiveBreakpoint(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/debugger/apiv2/debugger2_client.go b/vendor/cloud.google.com/go/debugger/apiv2/debugger2_client.go new file mode 100644 index 00000000..de5e0f13 --- /dev/null +++ b/vendor/cloud.google.com/go/debugger/apiv2/debugger2_client.go @@ -0,0 +1,212 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package debugger + +import ( + "context" + "time" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + clouddebuggerpb "google.golang.org/genproto/googleapis/devtools/clouddebugger/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// Debugger2CallOptions contains the retry settings for each method of Debugger2Client. +type Debugger2CallOptions struct { + SetBreakpoint []gax.CallOption + GetBreakpoint []gax.CallOption + DeleteBreakpoint []gax.CallOption + ListBreakpoints []gax.CallOption + ListDebuggees []gax.CallOption +} + +func defaultDebugger2ClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("clouddebugger.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultDebugger2CallOptions() *Debugger2CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &Debugger2CallOptions{ + SetBreakpoint: retry[[2]string{"default", "non_idempotent"}], + GetBreakpoint: retry[[2]string{"default", "idempotent"}], + DeleteBreakpoint: retry[[2]string{"default", "idempotent"}], + ListBreakpoints: retry[[2]string{"default", "idempotent"}], + ListDebuggees: retry[[2]string{"default", "idempotent"}], + } +} + +// Debugger2Client is a client for interacting with Stackdriver Debugger API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Debugger2Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + debugger2Client clouddebuggerpb.Debugger2Client + + // The call options for this service. + CallOptions *Debugger2CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewDebugger2Client creates a new debugger2 client. +// +// The Debugger service provides the API that allows users to collect run-time +// information from a running application, without stopping or slowing it down +// and without modifying its state. An application may include one or +// more replicated processes performing the same work. +// +// A debugged application is represented using the Debuggee concept. The +// Debugger service provides a way to query for available debuggees, but does +// not provide a way to create one. A debuggee is created using the Controller +// service, usually by running a debugger agent with the application. +// +// The Debugger service enables the client to set one or more Breakpoints on a +// Debuggee and collect the results of the set Breakpoints. +func NewDebugger2Client(ctx context.Context, opts ...option.ClientOption) (*Debugger2Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultDebugger2ClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Debugger2Client{ + conn: conn, + CallOptions: defaultDebugger2CallOptions(), + + debugger2Client: clouddebuggerpb.NewDebugger2Client(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Debugger2Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Debugger2Client) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Debugger2Client) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// SetBreakpoint sets the breakpoint to the debuggee. +func (c *Debugger2Client) SetBreakpoint(ctx context.Context, req *clouddebuggerpb.SetBreakpointRequest, opts ...gax.CallOption) (*clouddebuggerpb.SetBreakpointResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetBreakpoint[0:len(c.CallOptions.SetBreakpoint):len(c.CallOptions.SetBreakpoint)], opts...) + var resp *clouddebuggerpb.SetBreakpointResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.debugger2Client.SetBreakpoint(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetBreakpoint gets breakpoint information. +func (c *Debugger2Client) GetBreakpoint(ctx context.Context, req *clouddebuggerpb.GetBreakpointRequest, opts ...gax.CallOption) (*clouddebuggerpb.GetBreakpointResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetBreakpoint[0:len(c.CallOptions.GetBreakpoint):len(c.CallOptions.GetBreakpoint)], opts...) + var resp *clouddebuggerpb.GetBreakpointResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.debugger2Client.GetBreakpoint(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteBreakpoint deletes the breakpoint from the debuggee. +func (c *Debugger2Client) DeleteBreakpoint(ctx context.Context, req *clouddebuggerpb.DeleteBreakpointRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteBreakpoint[0:len(c.CallOptions.DeleteBreakpoint):len(c.CallOptions.DeleteBreakpoint)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.debugger2Client.DeleteBreakpoint(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ListBreakpoints lists all breakpoints for the debuggee. +func (c *Debugger2Client) ListBreakpoints(ctx context.Context, req *clouddebuggerpb.ListBreakpointsRequest, opts ...gax.CallOption) (*clouddebuggerpb.ListBreakpointsResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListBreakpoints[0:len(c.CallOptions.ListBreakpoints):len(c.CallOptions.ListBreakpoints)], opts...) + var resp *clouddebuggerpb.ListBreakpointsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.debugger2Client.ListBreakpoints(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListDebuggees lists all the debuggees that the user has access to. +func (c *Debugger2Client) ListDebuggees(ctx context.Context, req *clouddebuggerpb.ListDebuggeesRequest, opts ...gax.CallOption) (*clouddebuggerpb.ListDebuggeesResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListDebuggees[0:len(c.CallOptions.ListDebuggees):len(c.CallOptions.ListDebuggees)], opts...) + var resp *clouddebuggerpb.ListDebuggeesResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.debugger2Client.ListDebuggees(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/debugger/apiv2/debugger2_client_example_test.go b/vendor/cloud.google.com/go/debugger/apiv2/debugger2_client_example_test.go new file mode 100644 index 00000000..a7a9cb8e --- /dev/null +++ b/vendor/cloud.google.com/go/debugger/apiv2/debugger2_client_example_test.go @@ -0,0 +1,122 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package debugger_test + +import ( + "context" + + debugger "cloud.google.com/go/debugger/apiv2" + clouddebuggerpb "google.golang.org/genproto/googleapis/devtools/clouddebugger/v2" +) + +func ExampleNewDebugger2Client() { + ctx := context.Background() + c, err := debugger.NewDebugger2Client(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleDebugger2Client_SetBreakpoint() { + ctx := context.Background() + c, err := debugger.NewDebugger2Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouddebuggerpb.SetBreakpointRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetBreakpoint(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleDebugger2Client_GetBreakpoint() { + ctx := context.Background() + c, err := debugger.NewDebugger2Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouddebuggerpb.GetBreakpointRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetBreakpoint(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleDebugger2Client_DeleteBreakpoint() { + ctx := context.Background() + c, err := debugger.NewDebugger2Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouddebuggerpb.DeleteBreakpointRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteBreakpoint(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleDebugger2Client_ListBreakpoints() { + ctx := context.Background() + c, err := debugger.NewDebugger2Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouddebuggerpb.ListBreakpointsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ListBreakpoints(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleDebugger2Client_ListDebuggees() { + ctx := context.Background() + c, err := debugger.NewDebugger2Client(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouddebuggerpb.ListDebuggeesRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ListDebuggees(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/debugger/apiv2/doc.go b/vendor/cloud.google.com/go/debugger/apiv2/doc.go new file mode 100644 index 00000000..e3d5256a --- /dev/null +++ b/vendor/cloud.google.com/go/debugger/apiv2/doc.go @@ -0,0 +1,93 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package debugger is an auto-generated package for the +// Stackdriver Debugger API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Examines the call stack and variables of a running application without +// stopping or slowing it down. +// +// Use the client at cloud.google.com/go/cmd/go-cloud-debug-agent in preference to this. +package debugger // import "cloud.google.com/go/debugger/apiv2" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/cloud_debugger", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/debugger/apiv2/mock_test.go b/vendor/cloud.google.com/go/debugger/apiv2/mock_test.go new file mode 100644 index 00000000..022a4d07 --- /dev/null +++ b/vendor/cloud.google.com/go/debugger/apiv2/mock_test.go @@ -0,0 +1,693 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package debugger + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + clouddebuggerpb "google.golang.org/genproto/googleapis/devtools/clouddebugger/v2" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockController2Server struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + clouddebuggerpb.Controller2Server + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockController2Server) RegisterDebuggee(ctx context.Context, req *clouddebuggerpb.RegisterDebuggeeRequest) (*clouddebuggerpb.RegisterDebuggeeResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*clouddebuggerpb.RegisterDebuggeeResponse), nil +} + +func (s *mockController2Server) ListActiveBreakpoints(ctx context.Context, req *clouddebuggerpb.ListActiveBreakpointsRequest) (*clouddebuggerpb.ListActiveBreakpointsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*clouddebuggerpb.ListActiveBreakpointsResponse), nil +} + +func (s *mockController2Server) UpdateActiveBreakpoint(ctx context.Context, req *clouddebuggerpb.UpdateActiveBreakpointRequest) (*clouddebuggerpb.UpdateActiveBreakpointResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*clouddebuggerpb.UpdateActiveBreakpointResponse), nil +} + +type mockDebugger2Server struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + clouddebuggerpb.Debugger2Server + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockDebugger2Server) SetBreakpoint(ctx context.Context, req *clouddebuggerpb.SetBreakpointRequest) (*clouddebuggerpb.SetBreakpointResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*clouddebuggerpb.SetBreakpointResponse), nil +} + +func (s *mockDebugger2Server) GetBreakpoint(ctx context.Context, req *clouddebuggerpb.GetBreakpointRequest) (*clouddebuggerpb.GetBreakpointResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*clouddebuggerpb.GetBreakpointResponse), nil +} + +func (s *mockDebugger2Server) DeleteBreakpoint(ctx context.Context, req *clouddebuggerpb.DeleteBreakpointRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockDebugger2Server) ListBreakpoints(ctx context.Context, req *clouddebuggerpb.ListBreakpointsRequest) (*clouddebuggerpb.ListBreakpointsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*clouddebuggerpb.ListBreakpointsResponse), nil +} + +func (s *mockDebugger2Server) ListDebuggees(ctx context.Context, req *clouddebuggerpb.ListDebuggeesRequest) (*clouddebuggerpb.ListDebuggeesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*clouddebuggerpb.ListDebuggeesResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockController2 mockController2Server + mockDebugger2 mockDebugger2Server +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + clouddebuggerpb.RegisterController2Server(serv, &mockController2) + clouddebuggerpb.RegisterDebugger2Server(serv, &mockDebugger2) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestController2RegisterDebuggee(t *testing.T) { + var expectedResponse *clouddebuggerpb.RegisterDebuggeeResponse = &clouddebuggerpb.RegisterDebuggeeResponse{} + + mockController2.err = nil + mockController2.reqs = nil + + mockController2.resps = append(mockController2.resps[:0], expectedResponse) + + var debuggee *clouddebuggerpb.Debuggee = &clouddebuggerpb.Debuggee{} + var request = &clouddebuggerpb.RegisterDebuggeeRequest{ + Debuggee: debuggee, + } + + c, err := NewController2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RegisterDebuggee(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockController2.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestController2RegisterDebuggeeError(t *testing.T) { + errCode := codes.PermissionDenied + mockController2.err = gstatus.Error(errCode, "test error") + + var debuggee *clouddebuggerpb.Debuggee = &clouddebuggerpb.Debuggee{} + var request = &clouddebuggerpb.RegisterDebuggeeRequest{ + Debuggee: debuggee, + } + + c, err := NewController2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RegisterDebuggee(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestController2ListActiveBreakpoints(t *testing.T) { + var nextWaitToken string = "nextWaitToken1006864251" + var waitExpired bool = false + var expectedResponse = &clouddebuggerpb.ListActiveBreakpointsResponse{ + NextWaitToken: nextWaitToken, + WaitExpired: waitExpired, + } + + mockController2.err = nil + mockController2.reqs = nil + + mockController2.resps = append(mockController2.resps[:0], expectedResponse) + + var debuggeeId string = "debuggeeId-997255898" + var request = &clouddebuggerpb.ListActiveBreakpointsRequest{ + DebuggeeId: debuggeeId, + } + + c, err := NewController2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListActiveBreakpoints(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockController2.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestController2ListActiveBreakpointsError(t *testing.T) { + errCode := codes.PermissionDenied + mockController2.err = gstatus.Error(errCode, "test error") + + var debuggeeId string = "debuggeeId-997255898" + var request = &clouddebuggerpb.ListActiveBreakpointsRequest{ + DebuggeeId: debuggeeId, + } + + c, err := NewController2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListActiveBreakpoints(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestController2UpdateActiveBreakpoint(t *testing.T) { + var expectedResponse *clouddebuggerpb.UpdateActiveBreakpointResponse = &clouddebuggerpb.UpdateActiveBreakpointResponse{} + + mockController2.err = nil + mockController2.reqs = nil + + mockController2.resps = append(mockController2.resps[:0], expectedResponse) + + var debuggeeId string = "debuggeeId-997255898" + var breakpoint *clouddebuggerpb.Breakpoint = &clouddebuggerpb.Breakpoint{} + var request = &clouddebuggerpb.UpdateActiveBreakpointRequest{ + DebuggeeId: debuggeeId, + Breakpoint: breakpoint, + } + + c, err := NewController2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateActiveBreakpoint(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockController2.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestController2UpdateActiveBreakpointError(t *testing.T) { + errCode := codes.PermissionDenied + mockController2.err = gstatus.Error(errCode, "test error") + + var debuggeeId string = "debuggeeId-997255898" + var breakpoint *clouddebuggerpb.Breakpoint = &clouddebuggerpb.Breakpoint{} + var request = &clouddebuggerpb.UpdateActiveBreakpointRequest{ + DebuggeeId: debuggeeId, + Breakpoint: breakpoint, + } + + c, err := NewController2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateActiveBreakpoint(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDebugger2SetBreakpoint(t *testing.T) { + var expectedResponse *clouddebuggerpb.SetBreakpointResponse = &clouddebuggerpb.SetBreakpointResponse{} + + mockDebugger2.err = nil + mockDebugger2.reqs = nil + + mockDebugger2.resps = append(mockDebugger2.resps[:0], expectedResponse) + + var debuggeeId string = "debuggeeId-997255898" + var breakpoint *clouddebuggerpb.Breakpoint = &clouddebuggerpb.Breakpoint{} + var clientVersion string = "clientVersion-1506231196" + var request = &clouddebuggerpb.SetBreakpointRequest{ + DebuggeeId: debuggeeId, + Breakpoint: breakpoint, + ClientVersion: clientVersion, + } + + c, err := NewDebugger2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetBreakpoint(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDebugger2.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDebugger2SetBreakpointError(t *testing.T) { + errCode := codes.PermissionDenied + mockDebugger2.err = gstatus.Error(errCode, "test error") + + var debuggeeId string = "debuggeeId-997255898" + var breakpoint *clouddebuggerpb.Breakpoint = &clouddebuggerpb.Breakpoint{} + var clientVersion string = "clientVersion-1506231196" + var request = &clouddebuggerpb.SetBreakpointRequest{ + DebuggeeId: debuggeeId, + Breakpoint: breakpoint, + ClientVersion: clientVersion, + } + + c, err := NewDebugger2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetBreakpoint(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDebugger2GetBreakpoint(t *testing.T) { + var expectedResponse *clouddebuggerpb.GetBreakpointResponse = &clouddebuggerpb.GetBreakpointResponse{} + + mockDebugger2.err = nil + mockDebugger2.reqs = nil + + mockDebugger2.resps = append(mockDebugger2.resps[:0], expectedResponse) + + var debuggeeId string = "debuggeeId-997255898" + var breakpointId string = "breakpointId498424873" + var clientVersion string = "clientVersion-1506231196" + var request = &clouddebuggerpb.GetBreakpointRequest{ + DebuggeeId: debuggeeId, + BreakpointId: breakpointId, + ClientVersion: clientVersion, + } + + c, err := NewDebugger2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetBreakpoint(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDebugger2.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDebugger2GetBreakpointError(t *testing.T) { + errCode := codes.PermissionDenied + mockDebugger2.err = gstatus.Error(errCode, "test error") + + var debuggeeId string = "debuggeeId-997255898" + var breakpointId string = "breakpointId498424873" + var clientVersion string = "clientVersion-1506231196" + var request = &clouddebuggerpb.GetBreakpointRequest{ + DebuggeeId: debuggeeId, + BreakpointId: breakpointId, + ClientVersion: clientVersion, + } + + c, err := NewDebugger2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetBreakpoint(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDebugger2DeleteBreakpoint(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockDebugger2.err = nil + mockDebugger2.reqs = nil + + mockDebugger2.resps = append(mockDebugger2.resps[:0], expectedResponse) + + var debuggeeId string = "debuggeeId-997255898" + var breakpointId string = "breakpointId498424873" + var clientVersion string = "clientVersion-1506231196" + var request = &clouddebuggerpb.DeleteBreakpointRequest{ + DebuggeeId: debuggeeId, + BreakpointId: breakpointId, + ClientVersion: clientVersion, + } + + c, err := NewDebugger2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteBreakpoint(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDebugger2.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestDebugger2DeleteBreakpointError(t *testing.T) { + errCode := codes.PermissionDenied + mockDebugger2.err = gstatus.Error(errCode, "test error") + + var debuggeeId string = "debuggeeId-997255898" + var breakpointId string = "breakpointId498424873" + var clientVersion string = "clientVersion-1506231196" + var request = &clouddebuggerpb.DeleteBreakpointRequest{ + DebuggeeId: debuggeeId, + BreakpointId: breakpointId, + ClientVersion: clientVersion, + } + + c, err := NewDebugger2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteBreakpoint(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestDebugger2ListBreakpoints(t *testing.T) { + var nextWaitToken string = "nextWaitToken1006864251" + var expectedResponse = &clouddebuggerpb.ListBreakpointsResponse{ + NextWaitToken: nextWaitToken, + } + + mockDebugger2.err = nil + mockDebugger2.reqs = nil + + mockDebugger2.resps = append(mockDebugger2.resps[:0], expectedResponse) + + var debuggeeId string = "debuggeeId-997255898" + var clientVersion string = "clientVersion-1506231196" + var request = &clouddebuggerpb.ListBreakpointsRequest{ + DebuggeeId: debuggeeId, + ClientVersion: clientVersion, + } + + c, err := NewDebugger2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListBreakpoints(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDebugger2.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDebugger2ListBreakpointsError(t *testing.T) { + errCode := codes.PermissionDenied + mockDebugger2.err = gstatus.Error(errCode, "test error") + + var debuggeeId string = "debuggeeId-997255898" + var clientVersion string = "clientVersion-1506231196" + var request = &clouddebuggerpb.ListBreakpointsRequest{ + DebuggeeId: debuggeeId, + ClientVersion: clientVersion, + } + + c, err := NewDebugger2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListBreakpoints(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDebugger2ListDebuggees(t *testing.T) { + var expectedResponse *clouddebuggerpb.ListDebuggeesResponse = &clouddebuggerpb.ListDebuggeesResponse{} + + mockDebugger2.err = nil + mockDebugger2.reqs = nil + + mockDebugger2.resps = append(mockDebugger2.resps[:0], expectedResponse) + + var project string = "project-309310695" + var clientVersion string = "clientVersion-1506231196" + var request = &clouddebuggerpb.ListDebuggeesRequest{ + Project: project, + ClientVersion: clientVersion, + } + + c, err := NewDebugger2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListDebuggees(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDebugger2.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDebugger2ListDebuggeesError(t *testing.T) { + errCode := codes.PermissionDenied + mockDebugger2.err = gstatus.Error(errCode, "test error") + + var project string = "project-309310695" + var clientVersion string = "clientVersion-1506231196" + var request = &clouddebuggerpb.ListDebuggeesRequest{ + Project: project, + ClientVersion: clientVersion, + } + + c, err := NewDebugger2Client(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListDebuggees(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/agents_client.go b/vendor/cloud.google.com/go/dialogflow/apiv2/agents_client.go new file mode 100644 index 00000000..a6f72509 --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/agents_client.go @@ -0,0 +1,603 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dialogflow + +import ( + "context" + "math" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + structpbpb "github.com/golang/protobuf/ptypes/struct" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// AgentsCallOptions contains the retry settings for each method of AgentsClient. +type AgentsCallOptions struct { + GetAgent []gax.CallOption + SearchAgents []gax.CallOption + TrainAgent []gax.CallOption + ExportAgent []gax.CallOption + ImportAgent []gax.CallOption + RestoreAgent []gax.CallOption +} + +func defaultAgentsClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("dialogflow.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultAgentsCallOptions() *AgentsCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &AgentsCallOptions{ + GetAgent: retry[[2]string{"default", "idempotent"}], + SearchAgents: retry[[2]string{"default", "idempotent"}], + TrainAgent: retry[[2]string{"default", "idempotent"}], + ExportAgent: retry[[2]string{"default", "idempotent"}], + ImportAgent: retry[[2]string{"default", "non_idempotent"}], + RestoreAgent: retry[[2]string{"default", "idempotent"}], + } +} + +// AgentsClient is a client for interacting with Dialogflow API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type AgentsClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + agentsClient dialogflowpb.AgentsClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *AgentsCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewAgentsClient creates a new agents client. +// +// Agents are best described as Natural Language Understanding (NLU) modules +// that transform user requests into actionable data. You can include agents +// in your app, product, or service to determine user intent and respond to the +// user in a natural way. +// +// After you create an agent, you can add [Intents][google.cloud.dialogflow.v2.Intents], [Contexts][google.cloud.dialogflow.v2.Contexts], +// [Entity Types][google.cloud.dialogflow.v2.EntityTypes], [Webhooks][google.cloud.dialogflow.v2.WebhookRequest], and so on to +// manage the flow of a conversation and match user input to predefined intents +// and actions. +// +// You can create an agent using both Dialogflow Standard Edition and +// Dialogflow Enterprise Edition. For details, see +// Dialogflow Editions (at /dialogflow-enterprise/docs/editions). +// +// You can save your agent for backup or versioning by exporting the agent by +// using the [ExportAgent][google.cloud.dialogflow.v2.Agents.ExportAgent] method. You can import a saved +// agent by using the [ImportAgent][google.cloud.dialogflow.v2.Agents.ImportAgent] method. +// +// Dialogflow provides several +// prebuilt agents (at https://dialogflow.com/docs/prebuilt-agents) for common +// conversation scenarios such as determining a date and time, converting +// currency, and so on. +// +// For more information about agents, see the +// Dialogflow documentation (at https://dialogflow.com/docs/agents). +func NewAgentsClient(ctx context.Context, opts ...option.ClientOption) (*AgentsClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultAgentsClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &AgentsClient{ + conn: conn, + CallOptions: defaultAgentsCallOptions(), + + agentsClient: dialogflowpb.NewAgentsClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *AgentsClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *AgentsClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *AgentsClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// GetAgent retrieves the specified agent. +func (c *AgentsClient) GetAgent(ctx context.Context, req *dialogflowpb.GetAgentRequest, opts ...gax.CallOption) (*dialogflowpb.Agent, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetAgent[0:len(c.CallOptions.GetAgent):len(c.CallOptions.GetAgent)], opts...) + var resp *dialogflowpb.Agent + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.agentsClient.GetAgent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SearchAgents returns the list of agents. +// +// Since there is at most one conversational agent per project, this method is +// useful primarily for listing all agents across projects the caller has +// access to. One can achieve that with a wildcard project collection id "-". +// Refer to List +// Sub-Collections (at https://cloud.google.com/apis/design/design_patterns#list_sub-collections). +func (c *AgentsClient) SearchAgents(ctx context.Context, req *dialogflowpb.SearchAgentsRequest, opts ...gax.CallOption) *AgentIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SearchAgents[0:len(c.CallOptions.SearchAgents):len(c.CallOptions.SearchAgents)], opts...) + it := &AgentIterator{} + req = proto.Clone(req).(*dialogflowpb.SearchAgentsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dialogflowpb.Agent, string, error) { + var resp *dialogflowpb.SearchAgentsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.agentsClient.SearchAgents(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Agents, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// TrainAgent trains the specified agent. +// +// Operation +func (c *AgentsClient) TrainAgent(ctx context.Context, req *dialogflowpb.TrainAgentRequest, opts ...gax.CallOption) (*TrainAgentOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.TrainAgent[0:len(c.CallOptions.TrainAgent):len(c.CallOptions.TrainAgent)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.agentsClient.TrainAgent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &TrainAgentOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// ExportAgent exports the specified agent to a ZIP file. +// +// Operation +func (c *AgentsClient) ExportAgent(ctx context.Context, req *dialogflowpb.ExportAgentRequest, opts ...gax.CallOption) (*ExportAgentOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ExportAgent[0:len(c.CallOptions.ExportAgent):len(c.CallOptions.ExportAgent)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.agentsClient.ExportAgent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &ExportAgentOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// ImportAgent imports the specified agent from a ZIP file. +// +// Uploads new intents and entity types without deleting the existing ones. +// Intents and entity types with the same name are replaced with the new +// versions from ImportAgentRequest. +// +// Operation +func (c *AgentsClient) ImportAgent(ctx context.Context, req *dialogflowpb.ImportAgentRequest, opts ...gax.CallOption) (*ImportAgentOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ImportAgent[0:len(c.CallOptions.ImportAgent):len(c.CallOptions.ImportAgent)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.agentsClient.ImportAgent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &ImportAgentOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// RestoreAgent restores the specified agent from a ZIP file. +// +// Replaces the current agent version with a new one. All the intents and +// entity types in the older version are deleted. +// +// Operation +func (c *AgentsClient) RestoreAgent(ctx context.Context, req *dialogflowpb.RestoreAgentRequest, opts ...gax.CallOption) (*RestoreAgentOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.RestoreAgent[0:len(c.CallOptions.RestoreAgent):len(c.CallOptions.RestoreAgent)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.agentsClient.RestoreAgent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &RestoreAgentOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// AgentIterator manages a stream of *dialogflowpb.Agent. +type AgentIterator struct { + items []*dialogflowpb.Agent + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dialogflowpb.Agent, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *AgentIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *AgentIterator) Next() (*dialogflowpb.Agent, error) { + var item *dialogflowpb.Agent + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *AgentIterator) bufLen() int { + return len(it.items) +} + +func (it *AgentIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// ExportAgentOperation manages a long-running operation from ExportAgent. +type ExportAgentOperation struct { + lro *longrunning.Operation +} + +// ExportAgentOperation returns a new ExportAgentOperation from a given name. +// The name must be that of a previously created ExportAgentOperation, possibly from a different process. +func (c *AgentsClient) ExportAgentOperation(name string) *ExportAgentOperation { + return &ExportAgentOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *ExportAgentOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*dialogflowpb.ExportAgentResponse, error) { + var resp dialogflowpb.ExportAgentResponse + if err := op.lro.WaitWithInterval(ctx, &resp, 5000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *ExportAgentOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*dialogflowpb.ExportAgentResponse, error) { + var resp dialogflowpb.ExportAgentResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *ExportAgentOperation) Metadata() (*structpbpb.Struct, error) { + var meta structpbpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *ExportAgentOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *ExportAgentOperation) Name() string { + return op.lro.Name() +} + +// ImportAgentOperation manages a long-running operation from ImportAgent. +type ImportAgentOperation struct { + lro *longrunning.Operation +} + +// ImportAgentOperation returns a new ImportAgentOperation from a given name. +// The name must be that of a previously created ImportAgentOperation, possibly from a different process. +func (c *AgentsClient) ImportAgentOperation(name string) *ImportAgentOperation { + return &ImportAgentOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *ImportAgentOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 5000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *ImportAgentOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *ImportAgentOperation) Metadata() (*structpbpb.Struct, error) { + var meta structpbpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *ImportAgentOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *ImportAgentOperation) Name() string { + return op.lro.Name() +} + +// RestoreAgentOperation manages a long-running operation from RestoreAgent. +type RestoreAgentOperation struct { + lro *longrunning.Operation +} + +// RestoreAgentOperation returns a new RestoreAgentOperation from a given name. +// The name must be that of a previously created RestoreAgentOperation, possibly from a different process. +func (c *AgentsClient) RestoreAgentOperation(name string) *RestoreAgentOperation { + return &RestoreAgentOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *RestoreAgentOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 5000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *RestoreAgentOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *RestoreAgentOperation) Metadata() (*structpbpb.Struct, error) { + var meta structpbpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *RestoreAgentOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *RestoreAgentOperation) Name() string { + return op.lro.Name() +} + +// TrainAgentOperation manages a long-running operation from TrainAgent. +type TrainAgentOperation struct { + lro *longrunning.Operation +} + +// TrainAgentOperation returns a new TrainAgentOperation from a given name. +// The name must be that of a previously created TrainAgentOperation, possibly from a different process. +func (c *AgentsClient) TrainAgentOperation(name string) *TrainAgentOperation { + return &TrainAgentOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *TrainAgentOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 5000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *TrainAgentOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *TrainAgentOperation) Metadata() (*structpbpb.Struct, error) { + var meta structpbpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *TrainAgentOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *TrainAgentOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/agents_client_example_test.go b/vendor/cloud.google.com/go/dialogflow/apiv2/agents_client_example_test.go new file mode 100644 index 00000000..43cf3d3d --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/agents_client_example_test.go @@ -0,0 +1,157 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dialogflow_test + +import ( + "context" + + dialogflow "cloud.google.com/go/dialogflow/apiv2" + "google.golang.org/api/iterator" + dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" +) + +func ExampleNewAgentsClient() { + ctx := context.Background() + c, err := dialogflow.NewAgentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleAgentsClient_GetAgent() { + ctx := context.Background() + c, err := dialogflow.NewAgentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.GetAgentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetAgent(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleAgentsClient_SearchAgents() { + ctx := context.Background() + c, err := dialogflow.NewAgentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.SearchAgentsRequest{ + // TODO: Fill request struct fields. + } + it := c.SearchAgents(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleAgentsClient_TrainAgent() { + ctx := context.Background() + c, err := dialogflow.NewAgentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.TrainAgentRequest{ + // TODO: Fill request struct fields. + } + op, err := c.TrainAgent(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} + +func ExampleAgentsClient_ExportAgent() { + ctx := context.Background() + c, err := dialogflow.NewAgentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.ExportAgentRequest{ + // TODO: Fill request struct fields. + } + op, err := c.ExportAgent(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleAgentsClient_ImportAgent() { + ctx := context.Background() + c, err := dialogflow.NewAgentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.ImportAgentRequest{ + // TODO: Fill request struct fields. + } + op, err := c.ImportAgent(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} + +func ExampleAgentsClient_RestoreAgent() { + ctx := context.Background() + c, err := dialogflow.NewAgentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.RestoreAgentRequest{ + // TODO: Fill request struct fields. + } + op, err := c.RestoreAgent(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/contexts_client.go b/vendor/cloud.google.com/go/dialogflow/apiv2/contexts_client.go new file mode 100644 index 00000000..6d016ee4 --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/contexts_client.go @@ -0,0 +1,297 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dialogflow + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// ContextsCallOptions contains the retry settings for each method of ContextsClient. +type ContextsCallOptions struct { + ListContexts []gax.CallOption + GetContext []gax.CallOption + CreateContext []gax.CallOption + UpdateContext []gax.CallOption + DeleteContext []gax.CallOption + DeleteAllContexts []gax.CallOption +} + +func defaultContextsClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("dialogflow.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultContextsCallOptions() *ContextsCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &ContextsCallOptions{ + ListContexts: retry[[2]string{"default", "idempotent"}], + GetContext: retry[[2]string{"default", "idempotent"}], + CreateContext: retry[[2]string{"default", "non_idempotent"}], + UpdateContext: retry[[2]string{"default", "non_idempotent"}], + DeleteContext: retry[[2]string{"default", "idempotent"}], + DeleteAllContexts: retry[[2]string{"default", "idempotent"}], + } +} + +// ContextsClient is a client for interacting with Dialogflow API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type ContextsClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + contextsClient dialogflowpb.ContextsClient + + // The call options for this service. + CallOptions *ContextsCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewContextsClient creates a new contexts client. +// +// A context represents additional information included with user input or with +// an intent returned by the Dialogflow API. Contexts are helpful for +// differentiating user input which may be vague or have a different meaning +// depending on additional details from your application such as user setting +// and preferences, previous user input, where the user is in your application, +// geographic location, and so on. +// +// You can include contexts as input parameters of a +// [DetectIntent][google.cloud.dialogflow.v2.Sessions.DetectIntent] (or +// [StreamingDetectIntent][google.cloud.dialogflow.v2.Sessions.StreamingDetectIntent]) request, +// or as output contexts included in the returned intent. +// Contexts expire when an intent is matched, after the number of DetectIntent +// requests specified by the lifespan_count parameter, or after 10 minutes +// if no intents are matched for a DetectIntent request. +// +// For more information about contexts, see the +// Dialogflow documentation (at https://dialogflow.com/docs/contexts). +func NewContextsClient(ctx context.Context, opts ...option.ClientOption) (*ContextsClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultContextsClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &ContextsClient{ + conn: conn, + CallOptions: defaultContextsCallOptions(), + + contextsClient: dialogflowpb.NewContextsClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *ContextsClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *ContextsClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *ContextsClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListContexts returns the list of all contexts in the specified session. +func (c *ContextsClient) ListContexts(ctx context.Context, req *dialogflowpb.ListContextsRequest, opts ...gax.CallOption) *ContextIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListContexts[0:len(c.CallOptions.ListContexts):len(c.CallOptions.ListContexts)], opts...) + it := &ContextIterator{} + req = proto.Clone(req).(*dialogflowpb.ListContextsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dialogflowpb.Context, string, error) { + var resp *dialogflowpb.ListContextsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.contextsClient.ListContexts(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Contexts, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetContext retrieves the specified context. +func (c *ContextsClient) GetContext(ctx context.Context, req *dialogflowpb.GetContextRequest, opts ...gax.CallOption) (*dialogflowpb.Context, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetContext[0:len(c.CallOptions.GetContext):len(c.CallOptions.GetContext)], opts...) + var resp *dialogflowpb.Context + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.contextsClient.GetContext(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateContext creates a context. +func (c *ContextsClient) CreateContext(ctx context.Context, req *dialogflowpb.CreateContextRequest, opts ...gax.CallOption) (*dialogflowpb.Context, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateContext[0:len(c.CallOptions.CreateContext):len(c.CallOptions.CreateContext)], opts...) + var resp *dialogflowpb.Context + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.contextsClient.CreateContext(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateContext updates the specified context. +func (c *ContextsClient) UpdateContext(ctx context.Context, req *dialogflowpb.UpdateContextRequest, opts ...gax.CallOption) (*dialogflowpb.Context, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateContext[0:len(c.CallOptions.UpdateContext):len(c.CallOptions.UpdateContext)], opts...) + var resp *dialogflowpb.Context + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.contextsClient.UpdateContext(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteContext deletes the specified context. +func (c *ContextsClient) DeleteContext(ctx context.Context, req *dialogflowpb.DeleteContextRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteContext[0:len(c.CallOptions.DeleteContext):len(c.CallOptions.DeleteContext)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.contextsClient.DeleteContext(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// DeleteAllContexts deletes all active contexts in the specified session. +func (c *ContextsClient) DeleteAllContexts(ctx context.Context, req *dialogflowpb.DeleteAllContextsRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteAllContexts[0:len(c.CallOptions.DeleteAllContexts):len(c.CallOptions.DeleteAllContexts)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.contextsClient.DeleteAllContexts(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ContextIterator manages a stream of *dialogflowpb.Context. +type ContextIterator struct { + items []*dialogflowpb.Context + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dialogflowpb.Context, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ContextIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ContextIterator) Next() (*dialogflowpb.Context, error) { + var item *dialogflowpb.Context + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ContextIterator) bufLen() int { + return len(it.items) +} + +func (it *ContextIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/contexts_client_example_test.go b/vendor/cloud.google.com/go/dialogflow/apiv2/contexts_client_example_test.go new file mode 100644 index 00000000..d8192a51 --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/contexts_client_example_test.go @@ -0,0 +1,145 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dialogflow_test + +import ( + "context" + + dialogflow "cloud.google.com/go/dialogflow/apiv2" + "google.golang.org/api/iterator" + dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" +) + +func ExampleNewContextsClient() { + ctx := context.Background() + c, err := dialogflow.NewContextsClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleContextsClient_ListContexts() { + ctx := context.Background() + c, err := dialogflow.NewContextsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.ListContextsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListContexts(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleContextsClient_GetContext() { + ctx := context.Background() + c, err := dialogflow.NewContextsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.GetContextRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetContext(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleContextsClient_CreateContext() { + ctx := context.Background() + c, err := dialogflow.NewContextsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.CreateContextRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateContext(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleContextsClient_UpdateContext() { + ctx := context.Background() + c, err := dialogflow.NewContextsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.UpdateContextRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateContext(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleContextsClient_DeleteContext() { + ctx := context.Background() + c, err := dialogflow.NewContextsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.DeleteContextRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteContext(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleContextsClient_DeleteAllContexts() { + ctx := context.Background() + c, err := dialogflow.NewContextsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.DeleteAllContextsRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteAllContexts(ctx, req) + if err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/doc.go b/vendor/cloud.google.com/go/dialogflow/apiv2/doc.go new file mode 100644 index 00000000..61f42d7c --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/doc.go @@ -0,0 +1,90 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package dialogflow is an auto-generated package for the +// Dialogflow API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// An end-to-end development suite for conversational interfaces (e.g., +// chatbots, voice-powered apps and devices). +package dialogflow // import "cloud.google.com/go/dialogflow/apiv2" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/entity_types_client.go b/vendor/cloud.google.com/go/dialogflow/apiv2/entity_types_client.go new file mode 100644 index 00000000..2536b540 --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/entity_types_client.go @@ -0,0 +1,722 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dialogflow + +import ( + "context" + "math" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + structpbpb "github.com/golang/protobuf/ptypes/struct" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// EntityTypesCallOptions contains the retry settings for each method of EntityTypesClient. +type EntityTypesCallOptions struct { + ListEntityTypes []gax.CallOption + GetEntityType []gax.CallOption + CreateEntityType []gax.CallOption + UpdateEntityType []gax.CallOption + DeleteEntityType []gax.CallOption + BatchUpdateEntityTypes []gax.CallOption + BatchDeleteEntityTypes []gax.CallOption + BatchCreateEntities []gax.CallOption + BatchUpdateEntities []gax.CallOption + BatchDeleteEntities []gax.CallOption +} + +func defaultEntityTypesClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("dialogflow.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultEntityTypesCallOptions() *EntityTypesCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &EntityTypesCallOptions{ + ListEntityTypes: retry[[2]string{"default", "idempotent"}], + GetEntityType: retry[[2]string{"default", "idempotent"}], + CreateEntityType: retry[[2]string{"default", "non_idempotent"}], + UpdateEntityType: retry[[2]string{"default", "non_idempotent"}], + DeleteEntityType: retry[[2]string{"default", "idempotent"}], + BatchUpdateEntityTypes: retry[[2]string{"default", "non_idempotent"}], + BatchDeleteEntityTypes: retry[[2]string{"default", "idempotent"}], + BatchCreateEntities: retry[[2]string{"default", "non_idempotent"}], + BatchUpdateEntities: retry[[2]string{"default", "non_idempotent"}], + BatchDeleteEntities: retry[[2]string{"default", "idempotent"}], + } +} + +// EntityTypesClient is a client for interacting with Dialogflow API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type EntityTypesClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + entityTypesClient dialogflowpb.EntityTypesClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *EntityTypesCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewEntityTypesClient creates a new entity types client. +// +// Entities are extracted from user input and represent parameters that are +// meaningful to your application. For example, a date range, a proper name +// such as a geographic location or landmark, and so on. Entities represent +// actionable data for your application. +// +// When you define an entity, you can also include synonyms that all map to +// that entity. For example, "soft drink", "soda", "pop", and so on. +// +// There are three types of entities: +// +// * **System** - entities that are defined by the Dialogflow API for common +// data types such as date, time, currency, and so on. A system entity is +// represented by the `EntityType` type. +// +// * **Developer** - entities that are defined by you that represent +// actionable data that is meaningful to your application. For example, +// you could define a `pizza.sauce` entity for red or white pizza sauce, +// a `pizza.cheese` entity for the different types of cheese on a pizza, +// a `pizza.topping` entity for different toppings, and so on. A developer +// entity is represented by the `EntityType` type. +// +// * **User** - entities that are built for an individual user such as +// favorites, preferences, playlists, and so on. A user entity is +// represented by the [SessionEntityType][google.cloud.dialogflow.v2.SessionEntityType] type. +// +// For more information about entity types, see the +// [Dialogflow documentation](https://dialogflow.com/docs/entities). +func NewEntityTypesClient(ctx context.Context, opts ...option.ClientOption) (*EntityTypesClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultEntityTypesClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &EntityTypesClient{ + conn: conn, + CallOptions: defaultEntityTypesCallOptions(), + + entityTypesClient: dialogflowpb.NewEntityTypesClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *EntityTypesClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *EntityTypesClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *EntityTypesClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListEntityTypes returns the list of all entity types in the specified agent. +func (c *EntityTypesClient) ListEntityTypes(ctx context.Context, req *dialogflowpb.ListEntityTypesRequest, opts ...gax.CallOption) *EntityTypeIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListEntityTypes[0:len(c.CallOptions.ListEntityTypes):len(c.CallOptions.ListEntityTypes)], opts...) + it := &EntityTypeIterator{} + req = proto.Clone(req).(*dialogflowpb.ListEntityTypesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dialogflowpb.EntityType, string, error) { + var resp *dialogflowpb.ListEntityTypesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.entityTypesClient.ListEntityTypes(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.EntityTypes, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetEntityType retrieves the specified entity type. +func (c *EntityTypesClient) GetEntityType(ctx context.Context, req *dialogflowpb.GetEntityTypeRequest, opts ...gax.CallOption) (*dialogflowpb.EntityType, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetEntityType[0:len(c.CallOptions.GetEntityType):len(c.CallOptions.GetEntityType)], opts...) + var resp *dialogflowpb.EntityType + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.entityTypesClient.GetEntityType(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateEntityType creates an entity type in the specified agent. +func (c *EntityTypesClient) CreateEntityType(ctx context.Context, req *dialogflowpb.CreateEntityTypeRequest, opts ...gax.CallOption) (*dialogflowpb.EntityType, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateEntityType[0:len(c.CallOptions.CreateEntityType):len(c.CallOptions.CreateEntityType)], opts...) + var resp *dialogflowpb.EntityType + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.entityTypesClient.CreateEntityType(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateEntityType updates the specified entity type. +func (c *EntityTypesClient) UpdateEntityType(ctx context.Context, req *dialogflowpb.UpdateEntityTypeRequest, opts ...gax.CallOption) (*dialogflowpb.EntityType, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateEntityType[0:len(c.CallOptions.UpdateEntityType):len(c.CallOptions.UpdateEntityType)], opts...) + var resp *dialogflowpb.EntityType + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.entityTypesClient.UpdateEntityType(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteEntityType deletes the specified entity type. +func (c *EntityTypesClient) DeleteEntityType(ctx context.Context, req *dialogflowpb.DeleteEntityTypeRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteEntityType[0:len(c.CallOptions.DeleteEntityType):len(c.CallOptions.DeleteEntityType)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.entityTypesClient.DeleteEntityType(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// BatchUpdateEntityTypes updates/Creates multiple entity types in the specified agent. +// +// Operation +func (c *EntityTypesClient) BatchUpdateEntityTypes(ctx context.Context, req *dialogflowpb.BatchUpdateEntityTypesRequest, opts ...gax.CallOption) (*BatchUpdateEntityTypesOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchUpdateEntityTypes[0:len(c.CallOptions.BatchUpdateEntityTypes):len(c.CallOptions.BatchUpdateEntityTypes)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.entityTypesClient.BatchUpdateEntityTypes(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &BatchUpdateEntityTypesOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// BatchDeleteEntityTypes deletes entity types in the specified agent. +// +// Operation +func (c *EntityTypesClient) BatchDeleteEntityTypes(ctx context.Context, req *dialogflowpb.BatchDeleteEntityTypesRequest, opts ...gax.CallOption) (*BatchDeleteEntityTypesOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchDeleteEntityTypes[0:len(c.CallOptions.BatchDeleteEntityTypes):len(c.CallOptions.BatchDeleteEntityTypes)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.entityTypesClient.BatchDeleteEntityTypes(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &BatchDeleteEntityTypesOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// BatchCreateEntities creates multiple new entities in the specified entity type (extends the +// existing collection of entries). +// +// Operation +func (c *EntityTypesClient) BatchCreateEntities(ctx context.Context, req *dialogflowpb.BatchCreateEntitiesRequest, opts ...gax.CallOption) (*BatchCreateEntitiesOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchCreateEntities[0:len(c.CallOptions.BatchCreateEntities):len(c.CallOptions.BatchCreateEntities)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.entityTypesClient.BatchCreateEntities(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &BatchCreateEntitiesOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// BatchUpdateEntities updates entities in the specified entity type (replaces the existing +// collection of entries). +// +// Operation +func (c *EntityTypesClient) BatchUpdateEntities(ctx context.Context, req *dialogflowpb.BatchUpdateEntitiesRequest, opts ...gax.CallOption) (*BatchUpdateEntitiesOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchUpdateEntities[0:len(c.CallOptions.BatchUpdateEntities):len(c.CallOptions.BatchUpdateEntities)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.entityTypesClient.BatchUpdateEntities(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &BatchUpdateEntitiesOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// BatchDeleteEntities deletes entities in the specified entity type. +// +// Operation +func (c *EntityTypesClient) BatchDeleteEntities(ctx context.Context, req *dialogflowpb.BatchDeleteEntitiesRequest, opts ...gax.CallOption) (*BatchDeleteEntitiesOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchDeleteEntities[0:len(c.CallOptions.BatchDeleteEntities):len(c.CallOptions.BatchDeleteEntities)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.entityTypesClient.BatchDeleteEntities(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &BatchDeleteEntitiesOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// EntityTypeIterator manages a stream of *dialogflowpb.EntityType. +type EntityTypeIterator struct { + items []*dialogflowpb.EntityType + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dialogflowpb.EntityType, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *EntityTypeIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *EntityTypeIterator) Next() (*dialogflowpb.EntityType, error) { + var item *dialogflowpb.EntityType + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *EntityTypeIterator) bufLen() int { + return len(it.items) +} + +func (it *EntityTypeIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// BatchCreateEntitiesOperation manages a long-running operation from BatchCreateEntities. +type BatchCreateEntitiesOperation struct { + lro *longrunning.Operation +} + +// BatchCreateEntitiesOperation returns a new BatchCreateEntitiesOperation from a given name. +// The name must be that of a previously created BatchCreateEntitiesOperation, possibly from a different process. +func (c *EntityTypesClient) BatchCreateEntitiesOperation(name string) *BatchCreateEntitiesOperation { + return &BatchCreateEntitiesOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *BatchCreateEntitiesOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 5000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *BatchCreateEntitiesOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *BatchCreateEntitiesOperation) Metadata() (*structpbpb.Struct, error) { + var meta structpbpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *BatchCreateEntitiesOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *BatchCreateEntitiesOperation) Name() string { + return op.lro.Name() +} + +// BatchDeleteEntitiesOperation manages a long-running operation from BatchDeleteEntities. +type BatchDeleteEntitiesOperation struct { + lro *longrunning.Operation +} + +// BatchDeleteEntitiesOperation returns a new BatchDeleteEntitiesOperation from a given name. +// The name must be that of a previously created BatchDeleteEntitiesOperation, possibly from a different process. +func (c *EntityTypesClient) BatchDeleteEntitiesOperation(name string) *BatchDeleteEntitiesOperation { + return &BatchDeleteEntitiesOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *BatchDeleteEntitiesOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 5000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *BatchDeleteEntitiesOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *BatchDeleteEntitiesOperation) Metadata() (*structpbpb.Struct, error) { + var meta structpbpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *BatchDeleteEntitiesOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *BatchDeleteEntitiesOperation) Name() string { + return op.lro.Name() +} + +// BatchDeleteEntityTypesOperation manages a long-running operation from BatchDeleteEntityTypes. +type BatchDeleteEntityTypesOperation struct { + lro *longrunning.Operation +} + +// BatchDeleteEntityTypesOperation returns a new BatchDeleteEntityTypesOperation from a given name. +// The name must be that of a previously created BatchDeleteEntityTypesOperation, possibly from a different process. +func (c *EntityTypesClient) BatchDeleteEntityTypesOperation(name string) *BatchDeleteEntityTypesOperation { + return &BatchDeleteEntityTypesOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *BatchDeleteEntityTypesOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 5000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *BatchDeleteEntityTypesOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *BatchDeleteEntityTypesOperation) Metadata() (*structpbpb.Struct, error) { + var meta structpbpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *BatchDeleteEntityTypesOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *BatchDeleteEntityTypesOperation) Name() string { + return op.lro.Name() +} + +// BatchUpdateEntitiesOperation manages a long-running operation from BatchUpdateEntities. +type BatchUpdateEntitiesOperation struct { + lro *longrunning.Operation +} + +// BatchUpdateEntitiesOperation returns a new BatchUpdateEntitiesOperation from a given name. +// The name must be that of a previously created BatchUpdateEntitiesOperation, possibly from a different process. +func (c *EntityTypesClient) BatchUpdateEntitiesOperation(name string) *BatchUpdateEntitiesOperation { + return &BatchUpdateEntitiesOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *BatchUpdateEntitiesOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 5000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *BatchUpdateEntitiesOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *BatchUpdateEntitiesOperation) Metadata() (*structpbpb.Struct, error) { + var meta structpbpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *BatchUpdateEntitiesOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *BatchUpdateEntitiesOperation) Name() string { + return op.lro.Name() +} + +// BatchUpdateEntityTypesOperation manages a long-running operation from BatchUpdateEntityTypes. +type BatchUpdateEntityTypesOperation struct { + lro *longrunning.Operation +} + +// BatchUpdateEntityTypesOperation returns a new BatchUpdateEntityTypesOperation from a given name. +// The name must be that of a previously created BatchUpdateEntityTypesOperation, possibly from a different process. +func (c *EntityTypesClient) BatchUpdateEntityTypesOperation(name string) *BatchUpdateEntityTypesOperation { + return &BatchUpdateEntityTypesOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *BatchUpdateEntityTypesOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*dialogflowpb.BatchUpdateEntityTypesResponse, error) { + var resp dialogflowpb.BatchUpdateEntityTypesResponse + if err := op.lro.WaitWithInterval(ctx, &resp, 5000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *BatchUpdateEntityTypesOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*dialogflowpb.BatchUpdateEntityTypesResponse, error) { + var resp dialogflowpb.BatchUpdateEntityTypesResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *BatchUpdateEntityTypesOperation) Metadata() (*structpbpb.Struct, error) { + var meta structpbpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *BatchUpdateEntityTypesOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *BatchUpdateEntityTypesOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/entity_types_client_example_test.go b/vendor/cloud.google.com/go/dialogflow/apiv2/entity_types_client_example_test.go new file mode 100644 index 00000000..4dab88d7 --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/entity_types_client_example_test.go @@ -0,0 +1,228 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dialogflow_test + +import ( + "context" + + dialogflow "cloud.google.com/go/dialogflow/apiv2" + "google.golang.org/api/iterator" + dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" +) + +func ExampleNewEntityTypesClient() { + ctx := context.Background() + c, err := dialogflow.NewEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleEntityTypesClient_ListEntityTypes() { + ctx := context.Background() + c, err := dialogflow.NewEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.ListEntityTypesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListEntityTypes(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleEntityTypesClient_GetEntityType() { + ctx := context.Background() + c, err := dialogflow.NewEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.GetEntityTypeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetEntityType(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleEntityTypesClient_CreateEntityType() { + ctx := context.Background() + c, err := dialogflow.NewEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.CreateEntityTypeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateEntityType(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleEntityTypesClient_UpdateEntityType() { + ctx := context.Background() + c, err := dialogflow.NewEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.UpdateEntityTypeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateEntityType(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleEntityTypesClient_DeleteEntityType() { + ctx := context.Background() + c, err := dialogflow.NewEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.DeleteEntityTypeRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteEntityType(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleEntityTypesClient_BatchUpdateEntityTypes() { + ctx := context.Background() + c, err := dialogflow.NewEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.BatchUpdateEntityTypesRequest{ + // TODO: Fill request struct fields. + } + op, err := c.BatchUpdateEntityTypes(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleEntityTypesClient_BatchDeleteEntityTypes() { + ctx := context.Background() + c, err := dialogflow.NewEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.BatchDeleteEntityTypesRequest{ + // TODO: Fill request struct fields. + } + op, err := c.BatchDeleteEntityTypes(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} + +func ExampleEntityTypesClient_BatchCreateEntities() { + ctx := context.Background() + c, err := dialogflow.NewEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.BatchCreateEntitiesRequest{ + // TODO: Fill request struct fields. + } + op, err := c.BatchCreateEntities(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} + +func ExampleEntityTypesClient_BatchUpdateEntities() { + ctx := context.Background() + c, err := dialogflow.NewEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.BatchUpdateEntitiesRequest{ + // TODO: Fill request struct fields. + } + op, err := c.BatchUpdateEntities(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} + +func ExampleEntityTypesClient_BatchDeleteEntities() { + ctx := context.Background() + c, err := dialogflow.NewEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.BatchDeleteEntitiesRequest{ + // TODO: Fill request struct fields. + } + op, err := c.BatchDeleteEntities(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/intents_client.go b/vendor/cloud.google.com/go/dialogflow/apiv2/intents_client.go new file mode 100644 index 00000000..73f5ed35 --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/intents_client.go @@ -0,0 +1,486 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dialogflow + +import ( + "context" + "math" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + structpbpb "github.com/golang/protobuf/ptypes/struct" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// IntentsCallOptions contains the retry settings for each method of IntentsClient. +type IntentsCallOptions struct { + ListIntents []gax.CallOption + GetIntent []gax.CallOption + CreateIntent []gax.CallOption + UpdateIntent []gax.CallOption + DeleteIntent []gax.CallOption + BatchUpdateIntents []gax.CallOption + BatchDeleteIntents []gax.CallOption +} + +func defaultIntentsClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("dialogflow.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultIntentsCallOptions() *IntentsCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &IntentsCallOptions{ + ListIntents: retry[[2]string{"default", "idempotent"}], + GetIntent: retry[[2]string{"default", "idempotent"}], + CreateIntent: retry[[2]string{"default", "non_idempotent"}], + UpdateIntent: retry[[2]string{"default", "non_idempotent"}], + DeleteIntent: retry[[2]string{"default", "idempotent"}], + BatchUpdateIntents: retry[[2]string{"default", "non_idempotent"}], + BatchDeleteIntents: retry[[2]string{"default", "idempotent"}], + } +} + +// IntentsClient is a client for interacting with Dialogflow API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type IntentsClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + intentsClient dialogflowpb.IntentsClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *IntentsCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewIntentsClient creates a new intents client. +// +// An intent represents a mapping between input from a user and an action to +// be taken by your application. When you pass user input to the +// [DetectIntent][google.cloud.dialogflow.v2.Sessions.DetectIntent] (or +// [StreamingDetectIntent][google.cloud.dialogflow.v2.Sessions.StreamingDetectIntent]) method, the +// Dialogflow API analyzes the input and searches +// for a matching intent. If no match is found, the Dialogflow API returns a +// fallback intent (`is_fallback` = true). +// +// You can provide additional information for the Dialogflow API to use to +// match user input to an intent by adding the following to your intent. +// +// * **Contexts** - provide additional context for intent analysis. For +// example, if an intent is related to an object in your application that +// plays music, you can provide a context to determine when to match the +// intent if the user input is “turn it off”. You can include a context +// that matches the intent when there is previous user input of +// "play music", and not when there is previous user input of +// "turn on the light". +// +// * **Events** - allow for matching an intent by using an event name +// instead of user input. Your application can provide an event name and +// related parameters to the Dialogflow API to match an intent. For +// example, when your application starts, you can send a welcome event +// with a user name parameter to the Dialogflow API to match an intent with +// a personalized welcome message for the user. +// +// * **Training phrases** - provide examples of user input to train the +// Dialogflow API agent to better match intents. +// +// For more information about intents, see the +// [Dialogflow documentation](https://dialogflow.com/docs/intents). +func NewIntentsClient(ctx context.Context, opts ...option.ClientOption) (*IntentsClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultIntentsClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &IntentsClient{ + conn: conn, + CallOptions: defaultIntentsCallOptions(), + + intentsClient: dialogflowpb.NewIntentsClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *IntentsClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *IntentsClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *IntentsClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListIntents returns the list of all intents in the specified agent. +func (c *IntentsClient) ListIntents(ctx context.Context, req *dialogflowpb.ListIntentsRequest, opts ...gax.CallOption) *IntentIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListIntents[0:len(c.CallOptions.ListIntents):len(c.CallOptions.ListIntents)], opts...) + it := &IntentIterator{} + req = proto.Clone(req).(*dialogflowpb.ListIntentsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dialogflowpb.Intent, string, error) { + var resp *dialogflowpb.ListIntentsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.intentsClient.ListIntents(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Intents, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetIntent retrieves the specified intent. +func (c *IntentsClient) GetIntent(ctx context.Context, req *dialogflowpb.GetIntentRequest, opts ...gax.CallOption) (*dialogflowpb.Intent, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetIntent[0:len(c.CallOptions.GetIntent):len(c.CallOptions.GetIntent)], opts...) + var resp *dialogflowpb.Intent + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.intentsClient.GetIntent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateIntent creates an intent in the specified agent. +func (c *IntentsClient) CreateIntent(ctx context.Context, req *dialogflowpb.CreateIntentRequest, opts ...gax.CallOption) (*dialogflowpb.Intent, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateIntent[0:len(c.CallOptions.CreateIntent):len(c.CallOptions.CreateIntent)], opts...) + var resp *dialogflowpb.Intent + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.intentsClient.CreateIntent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateIntent updates the specified intent. +func (c *IntentsClient) UpdateIntent(ctx context.Context, req *dialogflowpb.UpdateIntentRequest, opts ...gax.CallOption) (*dialogflowpb.Intent, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateIntent[0:len(c.CallOptions.UpdateIntent):len(c.CallOptions.UpdateIntent)], opts...) + var resp *dialogflowpb.Intent + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.intentsClient.UpdateIntent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteIntent deletes the specified intent. +func (c *IntentsClient) DeleteIntent(ctx context.Context, req *dialogflowpb.DeleteIntentRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteIntent[0:len(c.CallOptions.DeleteIntent):len(c.CallOptions.DeleteIntent)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.intentsClient.DeleteIntent(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// BatchUpdateIntents updates/Creates multiple intents in the specified agent. +// +// Operation +func (c *IntentsClient) BatchUpdateIntents(ctx context.Context, req *dialogflowpb.BatchUpdateIntentsRequest, opts ...gax.CallOption) (*BatchUpdateIntentsOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchUpdateIntents[0:len(c.CallOptions.BatchUpdateIntents):len(c.CallOptions.BatchUpdateIntents)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.intentsClient.BatchUpdateIntents(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &BatchUpdateIntentsOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// BatchDeleteIntents deletes intents in the specified agent. +// +// Operation +func (c *IntentsClient) BatchDeleteIntents(ctx context.Context, req *dialogflowpb.BatchDeleteIntentsRequest, opts ...gax.CallOption) (*BatchDeleteIntentsOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchDeleteIntents[0:len(c.CallOptions.BatchDeleteIntents):len(c.CallOptions.BatchDeleteIntents)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.intentsClient.BatchDeleteIntents(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &BatchDeleteIntentsOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// IntentIterator manages a stream of *dialogflowpb.Intent. +type IntentIterator struct { + items []*dialogflowpb.Intent + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dialogflowpb.Intent, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *IntentIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *IntentIterator) Next() (*dialogflowpb.Intent, error) { + var item *dialogflowpb.Intent + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *IntentIterator) bufLen() int { + return len(it.items) +} + +func (it *IntentIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// BatchDeleteIntentsOperation manages a long-running operation from BatchDeleteIntents. +type BatchDeleteIntentsOperation struct { + lro *longrunning.Operation +} + +// BatchDeleteIntentsOperation returns a new BatchDeleteIntentsOperation from a given name. +// The name must be that of a previously created BatchDeleteIntentsOperation, possibly from a different process. +func (c *IntentsClient) BatchDeleteIntentsOperation(name string) *BatchDeleteIntentsOperation { + return &BatchDeleteIntentsOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *BatchDeleteIntentsOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 5000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *BatchDeleteIntentsOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *BatchDeleteIntentsOperation) Metadata() (*structpbpb.Struct, error) { + var meta structpbpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *BatchDeleteIntentsOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *BatchDeleteIntentsOperation) Name() string { + return op.lro.Name() +} + +// BatchUpdateIntentsOperation manages a long-running operation from BatchUpdateIntents. +type BatchUpdateIntentsOperation struct { + lro *longrunning.Operation +} + +// BatchUpdateIntentsOperation returns a new BatchUpdateIntentsOperation from a given name. +// The name must be that of a previously created BatchUpdateIntentsOperation, possibly from a different process. +func (c *IntentsClient) BatchUpdateIntentsOperation(name string) *BatchUpdateIntentsOperation { + return &BatchUpdateIntentsOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *BatchUpdateIntentsOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*dialogflowpb.BatchUpdateIntentsResponse, error) { + var resp dialogflowpb.BatchUpdateIntentsResponse + if err := op.lro.WaitWithInterval(ctx, &resp, 5000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *BatchUpdateIntentsOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*dialogflowpb.BatchUpdateIntentsResponse, error) { + var resp dialogflowpb.BatchUpdateIntentsResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *BatchUpdateIntentsOperation) Metadata() (*structpbpb.Struct, error) { + var meta structpbpb.Struct + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *BatchUpdateIntentsOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *BatchUpdateIntentsOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/intents_client_example_test.go b/vendor/cloud.google.com/go/dialogflow/apiv2/intents_client_example_test.go new file mode 100644 index 00000000..bedb628f --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/intents_client_example_test.go @@ -0,0 +1,171 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dialogflow_test + +import ( + "context" + + dialogflow "cloud.google.com/go/dialogflow/apiv2" + "google.golang.org/api/iterator" + dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" +) + +func ExampleNewIntentsClient() { + ctx := context.Background() + c, err := dialogflow.NewIntentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleIntentsClient_ListIntents() { + ctx := context.Background() + c, err := dialogflow.NewIntentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.ListIntentsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListIntents(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleIntentsClient_GetIntent() { + ctx := context.Background() + c, err := dialogflow.NewIntentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.GetIntentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetIntent(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIntentsClient_CreateIntent() { + ctx := context.Background() + c, err := dialogflow.NewIntentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.CreateIntentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateIntent(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIntentsClient_UpdateIntent() { + ctx := context.Background() + c, err := dialogflow.NewIntentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.UpdateIntentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateIntent(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIntentsClient_DeleteIntent() { + ctx := context.Background() + c, err := dialogflow.NewIntentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.DeleteIntentRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteIntent(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleIntentsClient_BatchUpdateIntents() { + ctx := context.Background() + c, err := dialogflow.NewIntentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.BatchUpdateIntentsRequest{ + // TODO: Fill request struct fields. + } + op, err := c.BatchUpdateIntents(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIntentsClient_BatchDeleteIntents() { + ctx := context.Background() + c, err := dialogflow.NewIntentsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.BatchDeleteIntentsRequest{ + // TODO: Fill request struct fields. + } + op, err := c.BatchDeleteIntents(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/mock_test.go b/vendor/cloud.google.com/go/dialogflow/apiv2/mock_test.go new file mode 100644 index 00000000..2d58fe96 --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/mock_test.go @@ -0,0 +1,3149 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dialogflow + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockAgentsServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + dialogflowpb.AgentsServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockAgentsServer) GetAgent(ctx context.Context, req *dialogflowpb.GetAgentRequest) (*dialogflowpb.Agent, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.Agent), nil +} + +func (s *mockAgentsServer) SearchAgents(ctx context.Context, req *dialogflowpb.SearchAgentsRequest) (*dialogflowpb.SearchAgentsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.SearchAgentsResponse), nil +} + +func (s *mockAgentsServer) TrainAgent(ctx context.Context, req *dialogflowpb.TrainAgentRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockAgentsServer) ExportAgent(ctx context.Context, req *dialogflowpb.ExportAgentRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockAgentsServer) ImportAgent(ctx context.Context, req *dialogflowpb.ImportAgentRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockAgentsServer) RestoreAgent(ctx context.Context, req *dialogflowpb.RestoreAgentRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +type mockContextsServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + dialogflowpb.ContextsServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockContextsServer) ListContexts(ctx context.Context, req *dialogflowpb.ListContextsRequest) (*dialogflowpb.ListContextsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.ListContextsResponse), nil +} + +func (s *mockContextsServer) GetContext(ctx context.Context, req *dialogflowpb.GetContextRequest) (*dialogflowpb.Context, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.Context), nil +} + +func (s *mockContextsServer) CreateContext(ctx context.Context, req *dialogflowpb.CreateContextRequest) (*dialogflowpb.Context, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.Context), nil +} + +func (s *mockContextsServer) UpdateContext(ctx context.Context, req *dialogflowpb.UpdateContextRequest) (*dialogflowpb.Context, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.Context), nil +} + +func (s *mockContextsServer) DeleteContext(ctx context.Context, req *dialogflowpb.DeleteContextRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockContextsServer) DeleteAllContexts(ctx context.Context, req *dialogflowpb.DeleteAllContextsRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +type mockEntityTypesServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + dialogflowpb.EntityTypesServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockEntityTypesServer) ListEntityTypes(ctx context.Context, req *dialogflowpb.ListEntityTypesRequest) (*dialogflowpb.ListEntityTypesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.ListEntityTypesResponse), nil +} + +func (s *mockEntityTypesServer) GetEntityType(ctx context.Context, req *dialogflowpb.GetEntityTypeRequest) (*dialogflowpb.EntityType, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.EntityType), nil +} + +func (s *mockEntityTypesServer) CreateEntityType(ctx context.Context, req *dialogflowpb.CreateEntityTypeRequest) (*dialogflowpb.EntityType, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.EntityType), nil +} + +func (s *mockEntityTypesServer) UpdateEntityType(ctx context.Context, req *dialogflowpb.UpdateEntityTypeRequest) (*dialogflowpb.EntityType, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.EntityType), nil +} + +func (s *mockEntityTypesServer) DeleteEntityType(ctx context.Context, req *dialogflowpb.DeleteEntityTypeRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockEntityTypesServer) BatchUpdateEntityTypes(ctx context.Context, req *dialogflowpb.BatchUpdateEntityTypesRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockEntityTypesServer) BatchDeleteEntityTypes(ctx context.Context, req *dialogflowpb.BatchDeleteEntityTypesRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockEntityTypesServer) BatchCreateEntities(ctx context.Context, req *dialogflowpb.BatchCreateEntitiesRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockEntityTypesServer) BatchUpdateEntities(ctx context.Context, req *dialogflowpb.BatchUpdateEntitiesRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockEntityTypesServer) BatchDeleteEntities(ctx context.Context, req *dialogflowpb.BatchDeleteEntitiesRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +type mockIntentsServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + dialogflowpb.IntentsServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockIntentsServer) ListIntents(ctx context.Context, req *dialogflowpb.ListIntentsRequest) (*dialogflowpb.ListIntentsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.ListIntentsResponse), nil +} + +func (s *mockIntentsServer) GetIntent(ctx context.Context, req *dialogflowpb.GetIntentRequest) (*dialogflowpb.Intent, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.Intent), nil +} + +func (s *mockIntentsServer) CreateIntent(ctx context.Context, req *dialogflowpb.CreateIntentRequest) (*dialogflowpb.Intent, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.Intent), nil +} + +func (s *mockIntentsServer) UpdateIntent(ctx context.Context, req *dialogflowpb.UpdateIntentRequest) (*dialogflowpb.Intent, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.Intent), nil +} + +func (s *mockIntentsServer) DeleteIntent(ctx context.Context, req *dialogflowpb.DeleteIntentRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockIntentsServer) BatchUpdateIntents(ctx context.Context, req *dialogflowpb.BatchUpdateIntentsRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockIntentsServer) BatchDeleteIntents(ctx context.Context, req *dialogflowpb.BatchDeleteIntentsRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +type mockSessionEntityTypesServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + dialogflowpb.SessionEntityTypesServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockSessionEntityTypesServer) ListSessionEntityTypes(ctx context.Context, req *dialogflowpb.ListSessionEntityTypesRequest) (*dialogflowpb.ListSessionEntityTypesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.ListSessionEntityTypesResponse), nil +} + +func (s *mockSessionEntityTypesServer) GetSessionEntityType(ctx context.Context, req *dialogflowpb.GetSessionEntityTypeRequest) (*dialogflowpb.SessionEntityType, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.SessionEntityType), nil +} + +func (s *mockSessionEntityTypesServer) CreateSessionEntityType(ctx context.Context, req *dialogflowpb.CreateSessionEntityTypeRequest) (*dialogflowpb.SessionEntityType, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.SessionEntityType), nil +} + +func (s *mockSessionEntityTypesServer) UpdateSessionEntityType(ctx context.Context, req *dialogflowpb.UpdateSessionEntityTypeRequest) (*dialogflowpb.SessionEntityType, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.SessionEntityType), nil +} + +func (s *mockSessionEntityTypesServer) DeleteSessionEntityType(ctx context.Context, req *dialogflowpb.DeleteSessionEntityTypeRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +type mockSessionsServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + dialogflowpb.SessionsServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockSessionsServer) DetectIntent(ctx context.Context, req *dialogflowpb.DetectIntentRequest) (*dialogflowpb.DetectIntentResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dialogflowpb.DetectIntentResponse), nil +} + +func (s *mockSessionsServer) StreamingDetectIntent(stream dialogflowpb.Sessions_StreamingDetectIntentServer) error { + md, _ := metadata.FromIncomingContext(stream.Context()) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + for { + if req, err := stream.Recv(); err == io.EOF { + break + } else if err != nil { + return err + } else { + s.reqs = append(s.reqs, req) + } + } + if s.err != nil { + return s.err + } + for _, v := range s.resps { + if err := stream.Send(v.(*dialogflowpb.StreamingDetectIntentResponse)); err != nil { + return err + } + } + return nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockAgents mockAgentsServer + mockContexts mockContextsServer + mockEntityTypes mockEntityTypesServer + mockIntents mockIntentsServer + mockSessionEntityTypes mockSessionEntityTypesServer + mockSessions mockSessionsServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + dialogflowpb.RegisterAgentsServer(serv, &mockAgents) + dialogflowpb.RegisterContextsServer(serv, &mockContexts) + dialogflowpb.RegisterEntityTypesServer(serv, &mockEntityTypes) + dialogflowpb.RegisterIntentsServer(serv, &mockIntents) + dialogflowpb.RegisterSessionEntityTypesServer(serv, &mockSessionEntityTypes) + dialogflowpb.RegisterSessionsServer(serv, &mockSessions) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestAgentsGetAgent(t *testing.T) { + var parent2 string = "parent21175163357" + var displayName string = "displayName1615086568" + var defaultLanguageCode string = "defaultLanguageCode856575222" + var timeZone string = "timeZone36848094" + var description string = "description-1724546052" + var avatarUri string = "avatarUri-402824826" + var enableLogging bool = false + var classificationThreshold float32 = 1.11581064E8 + var expectedResponse = &dialogflowpb.Agent{ + Parent: parent2, + DisplayName: displayName, + DefaultLanguageCode: defaultLanguageCode, + TimeZone: timeZone, + Description: description, + AvatarUri: avatarUri, + EnableLogging: enableLogging, + ClassificationThreshold: classificationThreshold, + } + + mockAgents.err = nil + mockAgents.reqs = nil + + mockAgents.resps = append(mockAgents.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dialogflowpb.GetAgentRequest{ + Parent: formattedParent, + } + + c, err := NewAgentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetAgent(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAgents.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestAgentsGetAgentError(t *testing.T) { + errCode := codes.PermissionDenied + mockAgents.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dialogflowpb.GetAgentRequest{ + Parent: formattedParent, + } + + c, err := NewAgentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetAgent(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestAgentsSearchAgents(t *testing.T) { + var nextPageToken string = "" + var agentsElement *dialogflowpb.Agent = &dialogflowpb.Agent{} + var agents = []*dialogflowpb.Agent{agentsElement} + var expectedResponse = &dialogflowpb.SearchAgentsResponse{ + NextPageToken: nextPageToken, + Agents: agents, + } + + mockAgents.err = nil + mockAgents.reqs = nil + + mockAgents.resps = append(mockAgents.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dialogflowpb.SearchAgentsRequest{ + Parent: formattedParent, + } + + c, err := NewAgentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SearchAgents(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAgents.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Agents[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestAgentsSearchAgentsError(t *testing.T) { + errCode := codes.PermissionDenied + mockAgents.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dialogflowpb.SearchAgentsRequest{ + Parent: formattedParent, + } + + c, err := NewAgentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SearchAgents(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestAgentsTrainAgent(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockAgents.err = nil + mockAgents.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockAgents.resps = append(mockAgents.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dialogflowpb.TrainAgentRequest{ + Parent: formattedParent, + } + + c, err := NewAgentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.TrainAgent(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAgents.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestAgentsTrainAgentError(t *testing.T) { + errCode := codes.PermissionDenied + mockAgents.err = nil + mockAgents.resps = append(mockAgents.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dialogflowpb.TrainAgentRequest{ + Parent: formattedParent, + } + + c, err := NewAgentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.TrainAgent(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestAgentsExportAgent(t *testing.T) { + var agentUri string = "agentUri-1700713166" + var expectedResponse = &dialogflowpb.ExportAgentResponse{ + Agent: &dialogflowpb.ExportAgentResponse_AgentUri{ + AgentUri: agentUri, + }, + } + + mockAgents.err = nil + mockAgents.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockAgents.resps = append(mockAgents.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dialogflowpb.ExportAgentRequest{ + Parent: formattedParent, + } + + c, err := NewAgentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.ExportAgent(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAgents.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestAgentsExportAgentError(t *testing.T) { + errCode := codes.PermissionDenied + mockAgents.err = nil + mockAgents.resps = append(mockAgents.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dialogflowpb.ExportAgentRequest{ + Parent: formattedParent, + } + + c, err := NewAgentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.ExportAgent(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestAgentsImportAgent(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockAgents.err = nil + mockAgents.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockAgents.resps = append(mockAgents.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dialogflowpb.ImportAgentRequest{ + Parent: formattedParent, + } + + c, err := NewAgentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.ImportAgent(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAgents.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestAgentsImportAgentError(t *testing.T) { + errCode := codes.PermissionDenied + mockAgents.err = nil + mockAgents.resps = append(mockAgents.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dialogflowpb.ImportAgentRequest{ + Parent: formattedParent, + } + + c, err := NewAgentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.ImportAgent(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestAgentsRestoreAgent(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockAgents.err = nil + mockAgents.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockAgents.resps = append(mockAgents.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dialogflowpb.RestoreAgentRequest{ + Parent: formattedParent, + } + + c, err := NewAgentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.RestoreAgent(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAgents.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestAgentsRestoreAgentError(t *testing.T) { + errCode := codes.PermissionDenied + mockAgents.err = nil + mockAgents.resps = append(mockAgents.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dialogflowpb.RestoreAgentRequest{ + Parent: formattedParent, + } + + c, err := NewAgentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.RestoreAgent(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestContextsListContexts(t *testing.T) { + var nextPageToken string = "" + var contextsElement *dialogflowpb.Context = &dialogflowpb.Context{} + var contexts = []*dialogflowpb.Context{contextsElement} + var expectedResponse = &dialogflowpb.ListContextsResponse{ + NextPageToken: nextPageToken, + Contexts: contexts, + } + + mockContexts.err = nil + mockContexts.reqs = nil + + mockContexts.resps = append(mockContexts.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/agent/sessions/%s", "[PROJECT]", "[SESSION]") + var request = &dialogflowpb.ListContextsRequest{ + Parent: formattedParent, + } + + c, err := NewContextsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListContexts(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockContexts.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Contexts[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestContextsListContextsError(t *testing.T) { + errCode := codes.PermissionDenied + mockContexts.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/agent/sessions/%s", "[PROJECT]", "[SESSION]") + var request = &dialogflowpb.ListContextsRequest{ + Parent: formattedParent, + } + + c, err := NewContextsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListContexts(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestContextsGetContext(t *testing.T) { + var name2 string = "name2-1052831874" + var lifespanCount int32 = 1178775510 + var expectedResponse = &dialogflowpb.Context{ + Name: name2, + LifespanCount: lifespanCount, + } + + mockContexts.err = nil + mockContexts.reqs = nil + + mockContexts.resps = append(mockContexts.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/agent/sessions/%s/contexts/%s", "[PROJECT]", "[SESSION]", "[CONTEXT]") + var request = &dialogflowpb.GetContextRequest{ + Name: formattedName, + } + + c, err := NewContextsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetContext(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockContexts.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestContextsGetContextError(t *testing.T) { + errCode := codes.PermissionDenied + mockContexts.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/agent/sessions/%s/contexts/%s", "[PROJECT]", "[SESSION]", "[CONTEXT]") + var request = &dialogflowpb.GetContextRequest{ + Name: formattedName, + } + + c, err := NewContextsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetContext(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestContextsCreateContext(t *testing.T) { + var name string = "name3373707" + var lifespanCount int32 = 1178775510 + var expectedResponse = &dialogflowpb.Context{ + Name: name, + LifespanCount: lifespanCount, + } + + mockContexts.err = nil + mockContexts.reqs = nil + + mockContexts.resps = append(mockContexts.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/agent/sessions/%s", "[PROJECT]", "[SESSION]") + var context_ *dialogflowpb.Context = &dialogflowpb.Context{} + var request = &dialogflowpb.CreateContextRequest{ + Parent: formattedParent, + Context: context_, + } + + c, err := NewContextsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateContext(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockContexts.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestContextsCreateContextError(t *testing.T) { + errCode := codes.PermissionDenied + mockContexts.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/agent/sessions/%s", "[PROJECT]", "[SESSION]") + var context_ *dialogflowpb.Context = &dialogflowpb.Context{} + var request = &dialogflowpb.CreateContextRequest{ + Parent: formattedParent, + Context: context_, + } + + c, err := NewContextsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateContext(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestContextsUpdateContext(t *testing.T) { + var name string = "name3373707" + var lifespanCount int32 = 1178775510 + var expectedResponse = &dialogflowpb.Context{ + Name: name, + LifespanCount: lifespanCount, + } + + mockContexts.err = nil + mockContexts.reqs = nil + + mockContexts.resps = append(mockContexts.resps[:0], expectedResponse) + + var context_ *dialogflowpb.Context = &dialogflowpb.Context{} + var request = &dialogflowpb.UpdateContextRequest{ + Context: context_, + } + + c, err := NewContextsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateContext(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockContexts.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestContextsUpdateContextError(t *testing.T) { + errCode := codes.PermissionDenied + mockContexts.err = gstatus.Error(errCode, "test error") + + var context_ *dialogflowpb.Context = &dialogflowpb.Context{} + var request = &dialogflowpb.UpdateContextRequest{ + Context: context_, + } + + c, err := NewContextsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateContext(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestContextsDeleteContext(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockContexts.err = nil + mockContexts.reqs = nil + + mockContexts.resps = append(mockContexts.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/agent/sessions/%s/contexts/%s", "[PROJECT]", "[SESSION]", "[CONTEXT]") + var request = &dialogflowpb.DeleteContextRequest{ + Name: formattedName, + } + + c, err := NewContextsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteContext(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockContexts.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestContextsDeleteContextError(t *testing.T) { + errCode := codes.PermissionDenied + mockContexts.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/agent/sessions/%s/contexts/%s", "[PROJECT]", "[SESSION]", "[CONTEXT]") + var request = &dialogflowpb.DeleteContextRequest{ + Name: formattedName, + } + + c, err := NewContextsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteContext(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestContextsDeleteAllContexts(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockContexts.err = nil + mockContexts.reqs = nil + + mockContexts.resps = append(mockContexts.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/agent/sessions/%s", "[PROJECT]", "[SESSION]") + var request = &dialogflowpb.DeleteAllContextsRequest{ + Parent: formattedParent, + } + + c, err := NewContextsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteAllContexts(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockContexts.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestContextsDeleteAllContextsError(t *testing.T) { + errCode := codes.PermissionDenied + mockContexts.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/agent/sessions/%s", "[PROJECT]", "[SESSION]") + var request = &dialogflowpb.DeleteAllContextsRequest{ + Parent: formattedParent, + } + + c, err := NewContextsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteAllContexts(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestEntityTypesListEntityTypes(t *testing.T) { + var nextPageToken string = "" + var entityTypesElement *dialogflowpb.EntityType = &dialogflowpb.EntityType{} + var entityTypes = []*dialogflowpb.EntityType{entityTypesElement} + var expectedResponse = &dialogflowpb.ListEntityTypesResponse{ + NextPageToken: nextPageToken, + EntityTypes: entityTypes, + } + + mockEntityTypes.err = nil + mockEntityTypes.reqs = nil + + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var request = &dialogflowpb.ListEntityTypesRequest{ + Parent: formattedParent, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListEntityTypes(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.EntityTypes[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestEntityTypesListEntityTypesError(t *testing.T) { + errCode := codes.PermissionDenied + mockEntityTypes.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var request = &dialogflowpb.ListEntityTypesRequest{ + Parent: formattedParent, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListEntityTypes(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestEntityTypesGetEntityType(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var expectedResponse = &dialogflowpb.EntityType{ + Name: name2, + DisplayName: displayName, + } + + mockEntityTypes.err = nil + mockEntityTypes.reqs = nil + + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/agent/entityTypes/%s", "[PROJECT]", "[ENTITY_TYPE]") + var request = &dialogflowpb.GetEntityTypeRequest{ + Name: formattedName, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetEntityType(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestEntityTypesGetEntityTypeError(t *testing.T) { + errCode := codes.PermissionDenied + mockEntityTypes.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/agent/entityTypes/%s", "[PROJECT]", "[ENTITY_TYPE]") + var request = &dialogflowpb.GetEntityTypeRequest{ + Name: formattedName, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetEntityType(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestEntityTypesCreateEntityType(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var expectedResponse = &dialogflowpb.EntityType{ + Name: name, + DisplayName: displayName, + } + + mockEntityTypes.err = nil + mockEntityTypes.reqs = nil + + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var entityType *dialogflowpb.EntityType = &dialogflowpb.EntityType{} + var request = &dialogflowpb.CreateEntityTypeRequest{ + Parent: formattedParent, + EntityType: entityType, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateEntityType(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestEntityTypesCreateEntityTypeError(t *testing.T) { + errCode := codes.PermissionDenied + mockEntityTypes.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var entityType *dialogflowpb.EntityType = &dialogflowpb.EntityType{} + var request = &dialogflowpb.CreateEntityTypeRequest{ + Parent: formattedParent, + EntityType: entityType, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateEntityType(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestEntityTypesUpdateEntityType(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var expectedResponse = &dialogflowpb.EntityType{ + Name: name, + DisplayName: displayName, + } + + mockEntityTypes.err = nil + mockEntityTypes.reqs = nil + + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], expectedResponse) + + var entityType *dialogflowpb.EntityType = &dialogflowpb.EntityType{} + var request = &dialogflowpb.UpdateEntityTypeRequest{ + EntityType: entityType, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateEntityType(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestEntityTypesUpdateEntityTypeError(t *testing.T) { + errCode := codes.PermissionDenied + mockEntityTypes.err = gstatus.Error(errCode, "test error") + + var entityType *dialogflowpb.EntityType = &dialogflowpb.EntityType{} + var request = &dialogflowpb.UpdateEntityTypeRequest{ + EntityType: entityType, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateEntityType(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestEntityTypesDeleteEntityType(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockEntityTypes.err = nil + mockEntityTypes.reqs = nil + + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/agent/entityTypes/%s", "[PROJECT]", "[ENTITY_TYPE]") + var request = &dialogflowpb.DeleteEntityTypeRequest{ + Name: formattedName, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteEntityType(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestEntityTypesDeleteEntityTypeError(t *testing.T) { + errCode := codes.PermissionDenied + mockEntityTypes.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/agent/entityTypes/%s", "[PROJECT]", "[ENTITY_TYPE]") + var request = &dialogflowpb.DeleteEntityTypeRequest{ + Name: formattedName, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteEntityType(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestEntityTypesBatchUpdateEntityTypes(t *testing.T) { + var expectedResponse *dialogflowpb.BatchUpdateEntityTypesResponse = &dialogflowpb.BatchUpdateEntityTypesResponse{} + + mockEntityTypes.err = nil + mockEntityTypes.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var request = &dialogflowpb.BatchUpdateEntityTypesRequest{ + Parent: formattedParent, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchUpdateEntityTypes(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestEntityTypesBatchUpdateEntityTypesError(t *testing.T) { + errCode := codes.PermissionDenied + mockEntityTypes.err = nil + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var request = &dialogflowpb.BatchUpdateEntityTypesRequest{ + Parent: formattedParent, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchUpdateEntityTypes(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestEntityTypesBatchDeleteEntityTypes(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockEntityTypes.err = nil + mockEntityTypes.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var entityTypeNames []string = nil + var request = &dialogflowpb.BatchDeleteEntityTypesRequest{ + Parent: formattedParent, + EntityTypeNames: entityTypeNames, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchDeleteEntityTypes(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestEntityTypesBatchDeleteEntityTypesError(t *testing.T) { + errCode := codes.PermissionDenied + mockEntityTypes.err = nil + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var entityTypeNames []string = nil + var request = &dialogflowpb.BatchDeleteEntityTypesRequest{ + Parent: formattedParent, + EntityTypeNames: entityTypeNames, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchDeleteEntityTypes(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestEntityTypesBatchCreateEntities(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockEntityTypes.err = nil + mockEntityTypes.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent/entityTypes/%s", "[PROJECT]", "[ENTITY_TYPE]") + var entities []*dialogflowpb.EntityType_Entity = nil + var request = &dialogflowpb.BatchCreateEntitiesRequest{ + Parent: formattedParent, + Entities: entities, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchCreateEntities(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestEntityTypesBatchCreateEntitiesError(t *testing.T) { + errCode := codes.PermissionDenied + mockEntityTypes.err = nil + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent/entityTypes/%s", "[PROJECT]", "[ENTITY_TYPE]") + var entities []*dialogflowpb.EntityType_Entity = nil + var request = &dialogflowpb.BatchCreateEntitiesRequest{ + Parent: formattedParent, + Entities: entities, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchCreateEntities(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestEntityTypesBatchUpdateEntities(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockEntityTypes.err = nil + mockEntityTypes.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent/entityTypes/%s", "[PROJECT]", "[ENTITY_TYPE]") + var entities []*dialogflowpb.EntityType_Entity = nil + var request = &dialogflowpb.BatchUpdateEntitiesRequest{ + Parent: formattedParent, + Entities: entities, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchUpdateEntities(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestEntityTypesBatchUpdateEntitiesError(t *testing.T) { + errCode := codes.PermissionDenied + mockEntityTypes.err = nil + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent/entityTypes/%s", "[PROJECT]", "[ENTITY_TYPE]") + var entities []*dialogflowpb.EntityType_Entity = nil + var request = &dialogflowpb.BatchUpdateEntitiesRequest{ + Parent: formattedParent, + Entities: entities, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchUpdateEntities(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestEntityTypesBatchDeleteEntities(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockEntityTypes.err = nil + mockEntityTypes.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent/entityTypes/%s", "[PROJECT]", "[ENTITY_TYPE]") + var entityValues []string = nil + var request = &dialogflowpb.BatchDeleteEntitiesRequest{ + Parent: formattedParent, + EntityValues: entityValues, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchDeleteEntities(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestEntityTypesBatchDeleteEntitiesError(t *testing.T) { + errCode := codes.PermissionDenied + mockEntityTypes.err = nil + mockEntityTypes.resps = append(mockEntityTypes.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent/entityTypes/%s", "[PROJECT]", "[ENTITY_TYPE]") + var entityValues []string = nil + var request = &dialogflowpb.BatchDeleteEntitiesRequest{ + Parent: formattedParent, + EntityValues: entityValues, + } + + c, err := NewEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchDeleteEntities(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestIntentsListIntents(t *testing.T) { + var nextPageToken string = "" + var intentsElement *dialogflowpb.Intent = &dialogflowpb.Intent{} + var intents = []*dialogflowpb.Intent{intentsElement} + var expectedResponse = &dialogflowpb.ListIntentsResponse{ + NextPageToken: nextPageToken, + Intents: intents, + } + + mockIntents.err = nil + mockIntents.reqs = nil + + mockIntents.resps = append(mockIntents.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var request = &dialogflowpb.ListIntentsRequest{ + Parent: formattedParent, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListIntents(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIntents.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Intents[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIntentsListIntentsError(t *testing.T) { + errCode := codes.PermissionDenied + mockIntents.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var request = &dialogflowpb.ListIntentsRequest{ + Parent: formattedParent, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListIntents(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIntentsGetIntent(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var priority int32 = 1165461084 + var isFallback bool = false + var mlDisabled bool = true + var action string = "action-1422950858" + var resetContexts bool = true + var rootFollowupIntentName string = "rootFollowupIntentName402253784" + var parentFollowupIntentName string = "parentFollowupIntentName-1131901680" + var expectedResponse = &dialogflowpb.Intent{ + Name: name2, + DisplayName: displayName, + Priority: priority, + IsFallback: isFallback, + MlDisabled: mlDisabled, + Action: action, + ResetContexts: resetContexts, + RootFollowupIntentName: rootFollowupIntentName, + ParentFollowupIntentName: parentFollowupIntentName, + } + + mockIntents.err = nil + mockIntents.reqs = nil + + mockIntents.resps = append(mockIntents.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/agent/intents/%s", "[PROJECT]", "[INTENT]") + var request = &dialogflowpb.GetIntentRequest{ + Name: formattedName, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIntent(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIntents.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIntentsGetIntentError(t *testing.T) { + errCode := codes.PermissionDenied + mockIntents.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/agent/intents/%s", "[PROJECT]", "[INTENT]") + var request = &dialogflowpb.GetIntentRequest{ + Name: formattedName, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIntent(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIntentsCreateIntent(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var priority int32 = 1165461084 + var isFallback bool = false + var mlDisabled bool = true + var action string = "action-1422950858" + var resetContexts bool = true + var rootFollowupIntentName string = "rootFollowupIntentName402253784" + var parentFollowupIntentName string = "parentFollowupIntentName-1131901680" + var expectedResponse = &dialogflowpb.Intent{ + Name: name, + DisplayName: displayName, + Priority: priority, + IsFallback: isFallback, + MlDisabled: mlDisabled, + Action: action, + ResetContexts: resetContexts, + RootFollowupIntentName: rootFollowupIntentName, + ParentFollowupIntentName: parentFollowupIntentName, + } + + mockIntents.err = nil + mockIntents.reqs = nil + + mockIntents.resps = append(mockIntents.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var intent *dialogflowpb.Intent = &dialogflowpb.Intent{} + var request = &dialogflowpb.CreateIntentRequest{ + Parent: formattedParent, + Intent: intent, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateIntent(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIntents.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIntentsCreateIntentError(t *testing.T) { + errCode := codes.PermissionDenied + mockIntents.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var intent *dialogflowpb.Intent = &dialogflowpb.Intent{} + var request = &dialogflowpb.CreateIntentRequest{ + Parent: formattedParent, + Intent: intent, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateIntent(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIntentsUpdateIntent(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var priority int32 = 1165461084 + var isFallback bool = false + var mlDisabled bool = true + var action string = "action-1422950858" + var resetContexts bool = true + var rootFollowupIntentName string = "rootFollowupIntentName402253784" + var parentFollowupIntentName string = "parentFollowupIntentName-1131901680" + var expectedResponse = &dialogflowpb.Intent{ + Name: name, + DisplayName: displayName, + Priority: priority, + IsFallback: isFallback, + MlDisabled: mlDisabled, + Action: action, + ResetContexts: resetContexts, + RootFollowupIntentName: rootFollowupIntentName, + ParentFollowupIntentName: parentFollowupIntentName, + } + + mockIntents.err = nil + mockIntents.reqs = nil + + mockIntents.resps = append(mockIntents.resps[:0], expectedResponse) + + var intent *dialogflowpb.Intent = &dialogflowpb.Intent{} + var languageCode string = "languageCode-412800396" + var request = &dialogflowpb.UpdateIntentRequest{ + Intent: intent, + LanguageCode: languageCode, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateIntent(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIntents.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIntentsUpdateIntentError(t *testing.T) { + errCode := codes.PermissionDenied + mockIntents.err = gstatus.Error(errCode, "test error") + + var intent *dialogflowpb.Intent = &dialogflowpb.Intent{} + var languageCode string = "languageCode-412800396" + var request = &dialogflowpb.UpdateIntentRequest{ + Intent: intent, + LanguageCode: languageCode, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateIntent(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIntentsDeleteIntent(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockIntents.err = nil + mockIntents.reqs = nil + + mockIntents.resps = append(mockIntents.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/agent/intents/%s", "[PROJECT]", "[INTENT]") + var request = &dialogflowpb.DeleteIntentRequest{ + Name: formattedName, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteIntent(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIntents.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestIntentsDeleteIntentError(t *testing.T) { + errCode := codes.PermissionDenied + mockIntents.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/agent/intents/%s", "[PROJECT]", "[INTENT]") + var request = &dialogflowpb.DeleteIntentRequest{ + Name: formattedName, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteIntent(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestIntentsBatchUpdateIntents(t *testing.T) { + var expectedResponse *dialogflowpb.BatchUpdateIntentsResponse = &dialogflowpb.BatchUpdateIntentsResponse{} + + mockIntents.err = nil + mockIntents.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockIntents.resps = append(mockIntents.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var languageCode string = "languageCode-412800396" + var request = &dialogflowpb.BatchUpdateIntentsRequest{ + Parent: formattedParent, + LanguageCode: languageCode, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchUpdateIntents(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIntents.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIntentsBatchUpdateIntentsError(t *testing.T) { + errCode := codes.PermissionDenied + mockIntents.err = nil + mockIntents.resps = append(mockIntents.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var languageCode string = "languageCode-412800396" + var request = &dialogflowpb.BatchUpdateIntentsRequest{ + Parent: formattedParent, + LanguageCode: languageCode, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchUpdateIntents(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIntentsBatchDeleteIntents(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockIntents.err = nil + mockIntents.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockIntents.resps = append(mockIntents.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var intents []*dialogflowpb.Intent = nil + var request = &dialogflowpb.BatchDeleteIntentsRequest{ + Parent: formattedParent, + Intents: intents, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchDeleteIntents(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIntents.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestIntentsBatchDeleteIntentsError(t *testing.T) { + errCode := codes.PermissionDenied + mockIntents.err = nil + mockIntents.resps = append(mockIntents.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/agent", "[PROJECT]") + var intents []*dialogflowpb.Intent = nil + var request = &dialogflowpb.BatchDeleteIntentsRequest{ + Parent: formattedParent, + Intents: intents, + } + + c, err := NewIntentsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.BatchDeleteIntents(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestSessionEntityTypesListSessionEntityTypes(t *testing.T) { + var nextPageToken string = "" + var sessionEntityTypesElement *dialogflowpb.SessionEntityType = &dialogflowpb.SessionEntityType{} + var sessionEntityTypes = []*dialogflowpb.SessionEntityType{sessionEntityTypesElement} + var expectedResponse = &dialogflowpb.ListSessionEntityTypesResponse{ + NextPageToken: nextPageToken, + SessionEntityTypes: sessionEntityTypes, + } + + mockSessionEntityTypes.err = nil + mockSessionEntityTypes.reqs = nil + + mockSessionEntityTypes.resps = append(mockSessionEntityTypes.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/agent/sessions/%s", "[PROJECT]", "[SESSION]") + var request = &dialogflowpb.ListSessionEntityTypesRequest{ + Parent: formattedParent, + } + + c, err := NewSessionEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListSessionEntityTypes(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSessionEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.SessionEntityTypes[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSessionEntityTypesListSessionEntityTypesError(t *testing.T) { + errCode := codes.PermissionDenied + mockSessionEntityTypes.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/agent/sessions/%s", "[PROJECT]", "[SESSION]") + var request = &dialogflowpb.ListSessionEntityTypesRequest{ + Parent: formattedParent, + } + + c, err := NewSessionEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListSessionEntityTypes(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSessionEntityTypesGetSessionEntityType(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &dialogflowpb.SessionEntityType{ + Name: name2, + } + + mockSessionEntityTypes.err = nil + mockSessionEntityTypes.reqs = nil + + mockSessionEntityTypes.resps = append(mockSessionEntityTypes.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/agent/sessions/%s/entityTypes/%s", "[PROJECT]", "[SESSION]", "[ENTITY_TYPE]") + var request = &dialogflowpb.GetSessionEntityTypeRequest{ + Name: formattedName, + } + + c, err := NewSessionEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSessionEntityType(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSessionEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSessionEntityTypesGetSessionEntityTypeError(t *testing.T) { + errCode := codes.PermissionDenied + mockSessionEntityTypes.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/agent/sessions/%s/entityTypes/%s", "[PROJECT]", "[SESSION]", "[ENTITY_TYPE]") + var request = &dialogflowpb.GetSessionEntityTypeRequest{ + Name: formattedName, + } + + c, err := NewSessionEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSessionEntityType(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSessionEntityTypesCreateSessionEntityType(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &dialogflowpb.SessionEntityType{ + Name: name, + } + + mockSessionEntityTypes.err = nil + mockSessionEntityTypes.reqs = nil + + mockSessionEntityTypes.resps = append(mockSessionEntityTypes.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/agent/sessions/%s", "[PROJECT]", "[SESSION]") + var sessionEntityType *dialogflowpb.SessionEntityType = &dialogflowpb.SessionEntityType{} + var request = &dialogflowpb.CreateSessionEntityTypeRequest{ + Parent: formattedParent, + SessionEntityType: sessionEntityType, + } + + c, err := NewSessionEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSessionEntityType(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSessionEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSessionEntityTypesCreateSessionEntityTypeError(t *testing.T) { + errCode := codes.PermissionDenied + mockSessionEntityTypes.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/agent/sessions/%s", "[PROJECT]", "[SESSION]") + var sessionEntityType *dialogflowpb.SessionEntityType = &dialogflowpb.SessionEntityType{} + var request = &dialogflowpb.CreateSessionEntityTypeRequest{ + Parent: formattedParent, + SessionEntityType: sessionEntityType, + } + + c, err := NewSessionEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSessionEntityType(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSessionEntityTypesUpdateSessionEntityType(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &dialogflowpb.SessionEntityType{ + Name: name, + } + + mockSessionEntityTypes.err = nil + mockSessionEntityTypes.reqs = nil + + mockSessionEntityTypes.resps = append(mockSessionEntityTypes.resps[:0], expectedResponse) + + var sessionEntityType *dialogflowpb.SessionEntityType = &dialogflowpb.SessionEntityType{} + var request = &dialogflowpb.UpdateSessionEntityTypeRequest{ + SessionEntityType: sessionEntityType, + } + + c, err := NewSessionEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSessionEntityType(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSessionEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSessionEntityTypesUpdateSessionEntityTypeError(t *testing.T) { + errCode := codes.PermissionDenied + mockSessionEntityTypes.err = gstatus.Error(errCode, "test error") + + var sessionEntityType *dialogflowpb.SessionEntityType = &dialogflowpb.SessionEntityType{} + var request = &dialogflowpb.UpdateSessionEntityTypeRequest{ + SessionEntityType: sessionEntityType, + } + + c, err := NewSessionEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSessionEntityType(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSessionEntityTypesDeleteSessionEntityType(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockSessionEntityTypes.err = nil + mockSessionEntityTypes.reqs = nil + + mockSessionEntityTypes.resps = append(mockSessionEntityTypes.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/agent/sessions/%s/entityTypes/%s", "[PROJECT]", "[SESSION]", "[ENTITY_TYPE]") + var request = &dialogflowpb.DeleteSessionEntityTypeRequest{ + Name: formattedName, + } + + c, err := NewSessionEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSessionEntityType(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSessionEntityTypes.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestSessionEntityTypesDeleteSessionEntityTypeError(t *testing.T) { + errCode := codes.PermissionDenied + mockSessionEntityTypes.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/agent/sessions/%s/entityTypes/%s", "[PROJECT]", "[SESSION]", "[ENTITY_TYPE]") + var request = &dialogflowpb.DeleteSessionEntityTypeRequest{ + Name: formattedName, + } + + c, err := NewSessionEntityTypesClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSessionEntityType(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestSessionsDetectIntent(t *testing.T) { + var responseId string = "responseId1847552473" + var expectedResponse = &dialogflowpb.DetectIntentResponse{ + ResponseId: responseId, + } + + mockSessions.err = nil + mockSessions.reqs = nil + + mockSessions.resps = append(mockSessions.resps[:0], expectedResponse) + + var formattedSession string = fmt.Sprintf("projects/%s/agent/sessions/%s", "[PROJECT]", "[SESSION]") + var queryInput *dialogflowpb.QueryInput = &dialogflowpb.QueryInput{} + var request = &dialogflowpb.DetectIntentRequest{ + Session: formattedSession, + QueryInput: queryInput, + } + + c, err := NewSessionsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.DetectIntent(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSessions.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSessionsDetectIntentError(t *testing.T) { + errCode := codes.PermissionDenied + mockSessions.err = gstatus.Error(errCode, "test error") + + var formattedSession string = fmt.Sprintf("projects/%s/agent/sessions/%s", "[PROJECT]", "[SESSION]") + var queryInput *dialogflowpb.QueryInput = &dialogflowpb.QueryInput{} + var request = &dialogflowpb.DetectIntentRequest{ + Session: formattedSession, + QueryInput: queryInput, + } + + c, err := NewSessionsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.DetectIntent(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSessionsStreamingDetectIntent(t *testing.T) { + var responseId string = "responseId1847552473" + var expectedResponse = &dialogflowpb.StreamingDetectIntentResponse{ + ResponseId: responseId, + } + + mockSessions.err = nil + mockSessions.reqs = nil + + mockSessions.resps = append(mockSessions.resps[:0], expectedResponse) + + var session string = "session1984987798" + var queryInput *dialogflowpb.QueryInput = &dialogflowpb.QueryInput{} + var request = &dialogflowpb.StreamingDetectIntentRequest{ + Session: session, + QueryInput: queryInput, + } + + c, err := NewSessionsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.StreamingDetectIntent(context.Background()) + if err != nil { + t.Fatal(err) + } + if err := stream.Send(request); err != nil { + t.Fatal(err) + } + if err := stream.CloseSend(); err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSessions.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSessionsStreamingDetectIntentError(t *testing.T) { + errCode := codes.PermissionDenied + mockSessions.err = gstatus.Error(errCode, "test error") + + var session string = "session1984987798" + var queryInput *dialogflowpb.QueryInput = &dialogflowpb.QueryInput{} + var request = &dialogflowpb.StreamingDetectIntentRequest{ + Session: session, + QueryInput: queryInput, + } + + c, err := NewSessionsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.StreamingDetectIntent(context.Background()) + if err != nil { + t.Fatal(err) + } + if err := stream.Send(request); err != nil { + t.Fatal(err) + } + if err := stream.CloseSend(); err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/session_entity_types_client.go b/vendor/cloud.google.com/go/dialogflow/apiv2/session_entity_types_client.go new file mode 100644 index 00000000..8849a855 --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/session_entity_types_client.go @@ -0,0 +1,278 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dialogflow + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// SessionEntityTypesCallOptions contains the retry settings for each method of SessionEntityTypesClient. +type SessionEntityTypesCallOptions struct { + ListSessionEntityTypes []gax.CallOption + GetSessionEntityType []gax.CallOption + CreateSessionEntityType []gax.CallOption + UpdateSessionEntityType []gax.CallOption + DeleteSessionEntityType []gax.CallOption +} + +func defaultSessionEntityTypesClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("dialogflow.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultSessionEntityTypesCallOptions() *SessionEntityTypesCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &SessionEntityTypesCallOptions{ + ListSessionEntityTypes: retry[[2]string{"default", "idempotent"}], + GetSessionEntityType: retry[[2]string{"default", "idempotent"}], + CreateSessionEntityType: retry[[2]string{"default", "non_idempotent"}], + UpdateSessionEntityType: retry[[2]string{"default", "non_idempotent"}], + DeleteSessionEntityType: retry[[2]string{"default", "idempotent"}], + } +} + +// SessionEntityTypesClient is a client for interacting with Dialogflow API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type SessionEntityTypesClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + sessionEntityTypesClient dialogflowpb.SessionEntityTypesClient + + // The call options for this service. + CallOptions *SessionEntityTypesCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewSessionEntityTypesClient creates a new session entity types client. +// +// Entities are extracted from user input and represent parameters that are +// meaningful to your application. For example, a date range, a proper name +// such as a geographic location or landmark, and so on. Entities represent +// actionable data for your application. +// +// Session entity types are referred to as **User** entity types and are +// entities that are built for an individual user such as +// favorites, preferences, playlists, and so on. You can redefine a session +// entity type at the session level. +// +// For more information about entity types, see the +// [Dialogflow documentation](https://dialogflow.com/docs/entities). +func NewSessionEntityTypesClient(ctx context.Context, opts ...option.ClientOption) (*SessionEntityTypesClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultSessionEntityTypesClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &SessionEntityTypesClient{ + conn: conn, + CallOptions: defaultSessionEntityTypesCallOptions(), + + sessionEntityTypesClient: dialogflowpb.NewSessionEntityTypesClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *SessionEntityTypesClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *SessionEntityTypesClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *SessionEntityTypesClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListSessionEntityTypes returns the list of all session entity types in the specified session. +func (c *SessionEntityTypesClient) ListSessionEntityTypes(ctx context.Context, req *dialogflowpb.ListSessionEntityTypesRequest, opts ...gax.CallOption) *SessionEntityTypeIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListSessionEntityTypes[0:len(c.CallOptions.ListSessionEntityTypes):len(c.CallOptions.ListSessionEntityTypes)], opts...) + it := &SessionEntityTypeIterator{} + req = proto.Clone(req).(*dialogflowpb.ListSessionEntityTypesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dialogflowpb.SessionEntityType, string, error) { + var resp *dialogflowpb.ListSessionEntityTypesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.sessionEntityTypesClient.ListSessionEntityTypes(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.SessionEntityTypes, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetSessionEntityType retrieves the specified session entity type. +func (c *SessionEntityTypesClient) GetSessionEntityType(ctx context.Context, req *dialogflowpb.GetSessionEntityTypeRequest, opts ...gax.CallOption) (*dialogflowpb.SessionEntityType, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetSessionEntityType[0:len(c.CallOptions.GetSessionEntityType):len(c.CallOptions.GetSessionEntityType)], opts...) + var resp *dialogflowpb.SessionEntityType + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.sessionEntityTypesClient.GetSessionEntityType(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateSessionEntityType creates a session entity type. +func (c *SessionEntityTypesClient) CreateSessionEntityType(ctx context.Context, req *dialogflowpb.CreateSessionEntityTypeRequest, opts ...gax.CallOption) (*dialogflowpb.SessionEntityType, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateSessionEntityType[0:len(c.CallOptions.CreateSessionEntityType):len(c.CallOptions.CreateSessionEntityType)], opts...) + var resp *dialogflowpb.SessionEntityType + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.sessionEntityTypesClient.CreateSessionEntityType(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateSessionEntityType updates the specified session entity type. +func (c *SessionEntityTypesClient) UpdateSessionEntityType(ctx context.Context, req *dialogflowpb.UpdateSessionEntityTypeRequest, opts ...gax.CallOption) (*dialogflowpb.SessionEntityType, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateSessionEntityType[0:len(c.CallOptions.UpdateSessionEntityType):len(c.CallOptions.UpdateSessionEntityType)], opts...) + var resp *dialogflowpb.SessionEntityType + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.sessionEntityTypesClient.UpdateSessionEntityType(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteSessionEntityType deletes the specified session entity type. +func (c *SessionEntityTypesClient) DeleteSessionEntityType(ctx context.Context, req *dialogflowpb.DeleteSessionEntityTypeRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteSessionEntityType[0:len(c.CallOptions.DeleteSessionEntityType):len(c.CallOptions.DeleteSessionEntityType)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.sessionEntityTypesClient.DeleteSessionEntityType(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// SessionEntityTypeIterator manages a stream of *dialogflowpb.SessionEntityType. +type SessionEntityTypeIterator struct { + items []*dialogflowpb.SessionEntityType + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dialogflowpb.SessionEntityType, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *SessionEntityTypeIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *SessionEntityTypeIterator) Next() (*dialogflowpb.SessionEntityType, error) { + var item *dialogflowpb.SessionEntityType + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *SessionEntityTypeIterator) bufLen() int { + return len(it.items) +} + +func (it *SessionEntityTypeIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/session_entity_types_client_example_test.go b/vendor/cloud.google.com/go/dialogflow/apiv2/session_entity_types_client_example_test.go new file mode 100644 index 00000000..43afd897 --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/session_entity_types_client_example_test.go @@ -0,0 +1,129 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dialogflow_test + +import ( + "context" + + dialogflow "cloud.google.com/go/dialogflow/apiv2" + "google.golang.org/api/iterator" + dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" +) + +func ExampleNewSessionEntityTypesClient() { + ctx := context.Background() + c, err := dialogflow.NewSessionEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleSessionEntityTypesClient_ListSessionEntityTypes() { + ctx := context.Background() + c, err := dialogflow.NewSessionEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.ListSessionEntityTypesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListSessionEntityTypes(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleSessionEntityTypesClient_GetSessionEntityType() { + ctx := context.Background() + c, err := dialogflow.NewSessionEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.GetSessionEntityTypeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetSessionEntityType(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleSessionEntityTypesClient_CreateSessionEntityType() { + ctx := context.Background() + c, err := dialogflow.NewSessionEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.CreateSessionEntityTypeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateSessionEntityType(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleSessionEntityTypesClient_UpdateSessionEntityType() { + ctx := context.Background() + c, err := dialogflow.NewSessionEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.UpdateSessionEntityTypeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateSessionEntityType(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleSessionEntityTypesClient_DeleteSessionEntityType() { + ctx := context.Background() + c, err := dialogflow.NewSessionEntityTypesClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.DeleteSessionEntityTypeRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteSessionEntityType(ctx, req) + if err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/sessions_client.go b/vendor/cloud.google.com/go/dialogflow/apiv2/sessions_client.go new file mode 100644 index 00000000..7485e93b --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/sessions_client.go @@ -0,0 +1,144 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dialogflow + +import ( + "context" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +// SessionsCallOptions contains the retry settings for each method of SessionsClient. +type SessionsCallOptions struct { + DetectIntent []gax.CallOption + StreamingDetectIntent []gax.CallOption +} + +func defaultSessionsClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("dialogflow.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultSessionsCallOptions() *SessionsCallOptions { + retry := map[[2]string][]gax.CallOption{} + return &SessionsCallOptions{ + DetectIntent: retry[[2]string{"default", "non_idempotent"}], + StreamingDetectIntent: retry[[2]string{"default", "non_idempotent"}], + } +} + +// SessionsClient is a client for interacting with Dialogflow API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type SessionsClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + sessionsClient dialogflowpb.SessionsClient + + // The call options for this service. + CallOptions *SessionsCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewSessionsClient creates a new sessions client. +// +// A session represents an interaction with a user. You retrieve user input +// and pass it to the [DetectIntent][google.cloud.dialogflow.v2.Sessions.DetectIntent] (or +// [StreamingDetectIntent][google.cloud.dialogflow.v2.Sessions.StreamingDetectIntent]) method to determine +// user intent and respond. +func NewSessionsClient(ctx context.Context, opts ...option.ClientOption) (*SessionsClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultSessionsClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &SessionsClient{ + conn: conn, + CallOptions: defaultSessionsCallOptions(), + + sessionsClient: dialogflowpb.NewSessionsClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *SessionsClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *SessionsClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *SessionsClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// DetectIntent processes a natural language query and returns structured, actionable data +// as a result. This method is not idempotent, because it may cause contexts +// and session entity types to be updated, which in turn might affect +// results of future queries. +func (c *SessionsClient) DetectIntent(ctx context.Context, req *dialogflowpb.DetectIntentRequest, opts ...gax.CallOption) (*dialogflowpb.DetectIntentResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DetectIntent[0:len(c.CallOptions.DetectIntent):len(c.CallOptions.DetectIntent)], opts...) + var resp *dialogflowpb.DetectIntentResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.sessionsClient.DetectIntent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// StreamingDetectIntent processes a natural language query in audio format in a streaming fashion +// and returns structured, actionable data as a result. This method is only +// available via the gRPC API (not REST). +func (c *SessionsClient) StreamingDetectIntent(ctx context.Context, opts ...gax.CallOption) (dialogflowpb.Sessions_StreamingDetectIntentClient, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.StreamingDetectIntent[0:len(c.CallOptions.StreamingDetectIntent):len(c.CallOptions.StreamingDetectIntent)], opts...) + var resp dialogflowpb.Sessions_StreamingDetectIntentClient + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.sessionsClient.StreamingDetectIntent(ctx, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/dialogflow/apiv2/sessions_client_example_test.go b/vendor/cloud.google.com/go/dialogflow/apiv2/sessions_client_example_test.go new file mode 100644 index 00000000..e6b91eb3 --- /dev/null +++ b/vendor/cloud.google.com/go/dialogflow/apiv2/sessions_client_example_test.go @@ -0,0 +1,87 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dialogflow_test + +import ( + "context" + "io" + + dialogflow "cloud.google.com/go/dialogflow/apiv2" + dialogflowpb "google.golang.org/genproto/googleapis/cloud/dialogflow/v2" +) + +func ExampleNewSessionsClient() { + ctx := context.Background() + c, err := dialogflow.NewSessionsClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleSessionsClient_DetectIntent() { + ctx := context.Background() + c, err := dialogflow.NewSessionsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dialogflowpb.DetectIntentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.DetectIntent(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleSessionsClient_StreamingDetectIntent() { + ctx := context.Background() + c, err := dialogflow.NewSessionsClient(ctx) + if err != nil { + // TODO: Handle error. + } + stream, err := c.StreamingDetectIntent(ctx) + if err != nil { + // TODO: Handle error. + } + go func() { + reqs := []*dialogflowpb.StreamingDetectIntentRequest{ + // TODO: Create requests. + } + for _, req := range reqs { + if err := stream.Send(req); err != nil { + // TODO: Handle error. + } + } + stream.CloseSend() + }() + for { + resp, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + // TODO: handle error. + } + // TODO: Use resp. + _ = resp + } +} diff --git a/vendor/cloud.google.com/go/dlp/apiv2/dlp_client.go b/vendor/cloud.google.com/go/dlp/apiv2/dlp_client.go new file mode 100644 index 00000000..359daa57 --- /dev/null +++ b/vendor/cloud.google.com/go/dlp/apiv2/dlp_client.go @@ -0,0 +1,1036 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dlp + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + dlppb "google.golang.org/genproto/googleapis/privacy/dlp/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + InspectContent []gax.CallOption + RedactImage []gax.CallOption + DeidentifyContent []gax.CallOption + ReidentifyContent []gax.CallOption + ListInfoTypes []gax.CallOption + CreateInspectTemplate []gax.CallOption + UpdateInspectTemplate []gax.CallOption + GetInspectTemplate []gax.CallOption + ListInspectTemplates []gax.CallOption + DeleteInspectTemplate []gax.CallOption + CreateDeidentifyTemplate []gax.CallOption + UpdateDeidentifyTemplate []gax.CallOption + GetDeidentifyTemplate []gax.CallOption + ListDeidentifyTemplates []gax.CallOption + DeleteDeidentifyTemplate []gax.CallOption + CreateDlpJob []gax.CallOption + ListDlpJobs []gax.CallOption + GetDlpJob []gax.CallOption + DeleteDlpJob []gax.CallOption + CancelDlpJob []gax.CallOption + ListJobTriggers []gax.CallOption + GetJobTrigger []gax.CallOption + DeleteJobTrigger []gax.CallOption + UpdateJobTrigger []gax.CallOption + CreateJobTrigger []gax.CallOption + CreateStoredInfoType []gax.CallOption + UpdateStoredInfoType []gax.CallOption + GetStoredInfoType []gax.CallOption + ListStoredInfoTypes []gax.CallOption + DeleteStoredInfoType []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("dlp.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + InspectContent: retry[[2]string{"default", "idempotent"}], + RedactImage: retry[[2]string{"default", "idempotent"}], + DeidentifyContent: retry[[2]string{"default", "idempotent"}], + ReidentifyContent: retry[[2]string{"default", "idempotent"}], + ListInfoTypes: retry[[2]string{"default", "idempotent"}], + CreateInspectTemplate: retry[[2]string{"default", "non_idempotent"}], + UpdateInspectTemplate: retry[[2]string{"default", "non_idempotent"}], + GetInspectTemplate: retry[[2]string{"default", "idempotent"}], + ListInspectTemplates: retry[[2]string{"default", "idempotent"}], + DeleteInspectTemplate: retry[[2]string{"default", "idempotent"}], + CreateDeidentifyTemplate: retry[[2]string{"default", "non_idempotent"}], + UpdateDeidentifyTemplate: retry[[2]string{"default", "non_idempotent"}], + GetDeidentifyTemplate: retry[[2]string{"default", "idempotent"}], + ListDeidentifyTemplates: retry[[2]string{"default", "idempotent"}], + DeleteDeidentifyTemplate: retry[[2]string{"default", "idempotent"}], + CreateDlpJob: retry[[2]string{"default", "non_idempotent"}], + ListDlpJobs: retry[[2]string{"default", "idempotent"}], + GetDlpJob: retry[[2]string{"default", "idempotent"}], + DeleteDlpJob: retry[[2]string{"default", "idempotent"}], + CancelDlpJob: retry[[2]string{"default", "non_idempotent"}], + ListJobTriggers: retry[[2]string{"default", "idempotent"}], + GetJobTrigger: retry[[2]string{"default", "idempotent"}], + DeleteJobTrigger: retry[[2]string{"default", "idempotent"}], + UpdateJobTrigger: retry[[2]string{"default", "non_idempotent"}], + CreateJobTrigger: retry[[2]string{"default", "non_idempotent"}], + CreateStoredInfoType: retry[[2]string{"default", "non_idempotent"}], + UpdateStoredInfoType: retry[[2]string{"default", "non_idempotent"}], + GetStoredInfoType: retry[[2]string{"default", "idempotent"}], + ListStoredInfoTypes: retry[[2]string{"default", "idempotent"}], + DeleteStoredInfoType: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Cloud Data Loss Prevention (DLP) API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client dlppb.DlpServiceClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new dlp service client. +// +// The Cloud Data Loss Prevention (DLP) API is a service that allows clients +// to detect the presence of Personally Identifiable Information (PII) and other +// privacy-sensitive data in user-supplied, unstructured data streams, like text +// blocks or images. +// The service also includes methods for sensitive data redaction and +// scheduling of data scans on Google Cloud Platform based data sets. +// +// To learn more about concepts and find how-to guides see +// https://cloud.google.com/dlp/docs/. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: dlppb.NewDlpServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// InspectContent finds potentially sensitive info in content. +// This method has limits on input size, processing time, and output size. +// +// When no InfoTypes or CustomInfoTypes are specified in this request, the +// system will automatically choose what detectors to run. By default this may +// be all types, but may change over time as detectors are updated. +// +// For how to guides, see https://cloud.google.com/dlp/docs/inspecting-images +// and https://cloud.google.com/dlp/docs/inspecting-text, +func (c *Client) InspectContent(ctx context.Context, req *dlppb.InspectContentRequest, opts ...gax.CallOption) (*dlppb.InspectContentResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.InspectContent[0:len(c.CallOptions.InspectContent):len(c.CallOptions.InspectContent)], opts...) + var resp *dlppb.InspectContentResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.InspectContent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// RedactImage redacts potentially sensitive info from an image. +// This method has limits on input size, processing time, and output size. +// See https://cloud.google.com/dlp/docs/redacting-sensitive-data-images to +// learn more. +// +// When no InfoTypes or CustomInfoTypes are specified in this request, the +// system will automatically choose what detectors to run. By default this may +// be all types, but may change over time as detectors are updated. +func (c *Client) RedactImage(ctx context.Context, req *dlppb.RedactImageRequest, opts ...gax.CallOption) (*dlppb.RedactImageResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.RedactImage[0:len(c.CallOptions.RedactImage):len(c.CallOptions.RedactImage)], opts...) + var resp *dlppb.RedactImageResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.RedactImage(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeidentifyContent de-identifies potentially sensitive info from a ContentItem. +// This method has limits on input size and output size. +// See https://cloud.google.com/dlp/docs/deidentify-sensitive-data to +// learn more. +// +// When no InfoTypes or CustomInfoTypes are specified in this request, the +// system will automatically choose what detectors to run. By default this may +// be all types, but may change over time as detectors are updated. +func (c *Client) DeidentifyContent(ctx context.Context, req *dlppb.DeidentifyContentRequest, opts ...gax.CallOption) (*dlppb.DeidentifyContentResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeidentifyContent[0:len(c.CallOptions.DeidentifyContent):len(c.CallOptions.DeidentifyContent)], opts...) + var resp *dlppb.DeidentifyContentResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.DeidentifyContent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ReidentifyContent re-identifies content that has been de-identified. +// See +// https://cloud.google.com/dlp/docs/pseudonymization#re-identification_in_free_text_code_example +// to learn more. +func (c *Client) ReidentifyContent(ctx context.Context, req *dlppb.ReidentifyContentRequest, opts ...gax.CallOption) (*dlppb.ReidentifyContentResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ReidentifyContent[0:len(c.CallOptions.ReidentifyContent):len(c.CallOptions.ReidentifyContent)], opts...) + var resp *dlppb.ReidentifyContentResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ReidentifyContent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListInfoTypes returns a list of the sensitive information types that the DLP API +// supports. See https://cloud.google.com/dlp/docs/infotypes-reference to +// learn more. +func (c *Client) ListInfoTypes(ctx context.Context, req *dlppb.ListInfoTypesRequest, opts ...gax.CallOption) (*dlppb.ListInfoTypesResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListInfoTypes[0:len(c.CallOptions.ListInfoTypes):len(c.CallOptions.ListInfoTypes)], opts...) + var resp *dlppb.ListInfoTypesResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListInfoTypes(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateInspectTemplate creates an InspectTemplate for re-using frequently used configuration +// for inspecting content, images, and storage. +// See https://cloud.google.com/dlp/docs/creating-templates to learn more. +func (c *Client) CreateInspectTemplate(ctx context.Context, req *dlppb.CreateInspectTemplateRequest, opts ...gax.CallOption) (*dlppb.InspectTemplate, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateInspectTemplate[0:len(c.CallOptions.CreateInspectTemplate):len(c.CallOptions.CreateInspectTemplate)], opts...) + var resp *dlppb.InspectTemplate + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateInspectTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateInspectTemplate updates the InspectTemplate. +// See https://cloud.google.com/dlp/docs/creating-templates to learn more. +func (c *Client) UpdateInspectTemplate(ctx context.Context, req *dlppb.UpdateInspectTemplateRequest, opts ...gax.CallOption) (*dlppb.InspectTemplate, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateInspectTemplate[0:len(c.CallOptions.UpdateInspectTemplate):len(c.CallOptions.UpdateInspectTemplate)], opts...) + var resp *dlppb.InspectTemplate + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateInspectTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetInspectTemplate gets an InspectTemplate. +// See https://cloud.google.com/dlp/docs/creating-templates to learn more. +func (c *Client) GetInspectTemplate(ctx context.Context, req *dlppb.GetInspectTemplateRequest, opts ...gax.CallOption) (*dlppb.InspectTemplate, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetInspectTemplate[0:len(c.CallOptions.GetInspectTemplate):len(c.CallOptions.GetInspectTemplate)], opts...) + var resp *dlppb.InspectTemplate + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetInspectTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListInspectTemplates lists InspectTemplates. +// See https://cloud.google.com/dlp/docs/creating-templates to learn more. +func (c *Client) ListInspectTemplates(ctx context.Context, req *dlppb.ListInspectTemplatesRequest, opts ...gax.CallOption) *InspectTemplateIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListInspectTemplates[0:len(c.CallOptions.ListInspectTemplates):len(c.CallOptions.ListInspectTemplates)], opts...) + it := &InspectTemplateIterator{} + req = proto.Clone(req).(*dlppb.ListInspectTemplatesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dlppb.InspectTemplate, string, error) { + var resp *dlppb.ListInspectTemplatesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListInspectTemplates(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.InspectTemplates, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DeleteInspectTemplate deletes an InspectTemplate. +// See https://cloud.google.com/dlp/docs/creating-templates to learn more. +func (c *Client) DeleteInspectTemplate(ctx context.Context, req *dlppb.DeleteInspectTemplateRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteInspectTemplate[0:len(c.CallOptions.DeleteInspectTemplate):len(c.CallOptions.DeleteInspectTemplate)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteInspectTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// CreateDeidentifyTemplate creates a DeidentifyTemplate for re-using frequently used configuration +// for de-identifying content, images, and storage. +// See https://cloud.google.com/dlp/docs/creating-templates-deid to learn +// more. +func (c *Client) CreateDeidentifyTemplate(ctx context.Context, req *dlppb.CreateDeidentifyTemplateRequest, opts ...gax.CallOption) (*dlppb.DeidentifyTemplate, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateDeidentifyTemplate[0:len(c.CallOptions.CreateDeidentifyTemplate):len(c.CallOptions.CreateDeidentifyTemplate)], opts...) + var resp *dlppb.DeidentifyTemplate + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateDeidentifyTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateDeidentifyTemplate updates the DeidentifyTemplate. +// See https://cloud.google.com/dlp/docs/creating-templates-deid to learn +// more. +func (c *Client) UpdateDeidentifyTemplate(ctx context.Context, req *dlppb.UpdateDeidentifyTemplateRequest, opts ...gax.CallOption) (*dlppb.DeidentifyTemplate, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateDeidentifyTemplate[0:len(c.CallOptions.UpdateDeidentifyTemplate):len(c.CallOptions.UpdateDeidentifyTemplate)], opts...) + var resp *dlppb.DeidentifyTemplate + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateDeidentifyTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetDeidentifyTemplate gets a DeidentifyTemplate. +// See https://cloud.google.com/dlp/docs/creating-templates-deid to learn +// more. +func (c *Client) GetDeidentifyTemplate(ctx context.Context, req *dlppb.GetDeidentifyTemplateRequest, opts ...gax.CallOption) (*dlppb.DeidentifyTemplate, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetDeidentifyTemplate[0:len(c.CallOptions.GetDeidentifyTemplate):len(c.CallOptions.GetDeidentifyTemplate)], opts...) + var resp *dlppb.DeidentifyTemplate + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetDeidentifyTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListDeidentifyTemplates lists DeidentifyTemplates. +// See https://cloud.google.com/dlp/docs/creating-templates-deid to learn +// more. +func (c *Client) ListDeidentifyTemplates(ctx context.Context, req *dlppb.ListDeidentifyTemplatesRequest, opts ...gax.CallOption) *DeidentifyTemplateIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListDeidentifyTemplates[0:len(c.CallOptions.ListDeidentifyTemplates):len(c.CallOptions.ListDeidentifyTemplates)], opts...) + it := &DeidentifyTemplateIterator{} + req = proto.Clone(req).(*dlppb.ListDeidentifyTemplatesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dlppb.DeidentifyTemplate, string, error) { + var resp *dlppb.ListDeidentifyTemplatesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListDeidentifyTemplates(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.DeidentifyTemplates, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DeleteDeidentifyTemplate deletes a DeidentifyTemplate. +// See https://cloud.google.com/dlp/docs/creating-templates-deid to learn +// more. +func (c *Client) DeleteDeidentifyTemplate(ctx context.Context, req *dlppb.DeleteDeidentifyTemplateRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteDeidentifyTemplate[0:len(c.CallOptions.DeleteDeidentifyTemplate):len(c.CallOptions.DeleteDeidentifyTemplate)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteDeidentifyTemplate(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// CreateDlpJob creates a new job to inspect storage or calculate risk metrics. +// See https://cloud.google.com/dlp/docs/inspecting-storage and +// https://cloud.google.com/dlp/docs/compute-risk-analysis to learn more. +// +// When no InfoTypes or CustomInfoTypes are specified in inspect jobs, the +// system will automatically choose what detectors to run. By default this may +// be all types, but may change over time as detectors are updated. +func (c *Client) CreateDlpJob(ctx context.Context, req *dlppb.CreateDlpJobRequest, opts ...gax.CallOption) (*dlppb.DlpJob, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateDlpJob[0:len(c.CallOptions.CreateDlpJob):len(c.CallOptions.CreateDlpJob)], opts...) + var resp *dlppb.DlpJob + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateDlpJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListDlpJobs lists DlpJobs that match the specified filter in the request. +// See https://cloud.google.com/dlp/docs/inspecting-storage and +// https://cloud.google.com/dlp/docs/compute-risk-analysis to learn more. +func (c *Client) ListDlpJobs(ctx context.Context, req *dlppb.ListDlpJobsRequest, opts ...gax.CallOption) *DlpJobIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListDlpJobs[0:len(c.CallOptions.ListDlpJobs):len(c.CallOptions.ListDlpJobs)], opts...) + it := &DlpJobIterator{} + req = proto.Clone(req).(*dlppb.ListDlpJobsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dlppb.DlpJob, string, error) { + var resp *dlppb.ListDlpJobsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListDlpJobs(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Jobs, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetDlpJob gets the latest state of a long-running DlpJob. +// See https://cloud.google.com/dlp/docs/inspecting-storage and +// https://cloud.google.com/dlp/docs/compute-risk-analysis to learn more. +func (c *Client) GetDlpJob(ctx context.Context, req *dlppb.GetDlpJobRequest, opts ...gax.CallOption) (*dlppb.DlpJob, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetDlpJob[0:len(c.CallOptions.GetDlpJob):len(c.CallOptions.GetDlpJob)], opts...) + var resp *dlppb.DlpJob + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetDlpJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteDlpJob deletes a long-running DlpJob. This method indicates that the client is +// no longer interested in the DlpJob result. The job will be cancelled if +// possible. +// See https://cloud.google.com/dlp/docs/inspecting-storage and +// https://cloud.google.com/dlp/docs/compute-risk-analysis to learn more. +func (c *Client) DeleteDlpJob(ctx context.Context, req *dlppb.DeleteDlpJobRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteDlpJob[0:len(c.CallOptions.DeleteDlpJob):len(c.CallOptions.DeleteDlpJob)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteDlpJob(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// CancelDlpJob starts asynchronous cancellation on a long-running DlpJob. The server +// makes a best effort to cancel the DlpJob, but success is not +// guaranteed. +// See https://cloud.google.com/dlp/docs/inspecting-storage and +// https://cloud.google.com/dlp/docs/compute-risk-analysis to learn more. +func (c *Client) CancelDlpJob(ctx context.Context, req *dlppb.CancelDlpJobRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CancelDlpJob[0:len(c.CallOptions.CancelDlpJob):len(c.CallOptions.CancelDlpJob)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.CancelDlpJob(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ListJobTriggers lists job triggers. +// See https://cloud.google.com/dlp/docs/creating-job-triggers to learn more. +func (c *Client) ListJobTriggers(ctx context.Context, req *dlppb.ListJobTriggersRequest, opts ...gax.CallOption) *JobTriggerIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListJobTriggers[0:len(c.CallOptions.ListJobTriggers):len(c.CallOptions.ListJobTriggers)], opts...) + it := &JobTriggerIterator{} + req = proto.Clone(req).(*dlppb.ListJobTriggersRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dlppb.JobTrigger, string, error) { + var resp *dlppb.ListJobTriggersResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListJobTriggers(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.JobTriggers, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetJobTrigger gets a job trigger. +// See https://cloud.google.com/dlp/docs/creating-job-triggers to learn more. +func (c *Client) GetJobTrigger(ctx context.Context, req *dlppb.GetJobTriggerRequest, opts ...gax.CallOption) (*dlppb.JobTrigger, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetJobTrigger[0:len(c.CallOptions.GetJobTrigger):len(c.CallOptions.GetJobTrigger)], opts...) + var resp *dlppb.JobTrigger + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetJobTrigger(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteJobTrigger deletes a job trigger. +// See https://cloud.google.com/dlp/docs/creating-job-triggers to learn more. +func (c *Client) DeleteJobTrigger(ctx context.Context, req *dlppb.DeleteJobTriggerRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteJobTrigger[0:len(c.CallOptions.DeleteJobTrigger):len(c.CallOptions.DeleteJobTrigger)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteJobTrigger(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// UpdateJobTrigger updates a job trigger. +// See https://cloud.google.com/dlp/docs/creating-job-triggers to learn more. +func (c *Client) UpdateJobTrigger(ctx context.Context, req *dlppb.UpdateJobTriggerRequest, opts ...gax.CallOption) (*dlppb.JobTrigger, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateJobTrigger[0:len(c.CallOptions.UpdateJobTrigger):len(c.CallOptions.UpdateJobTrigger)], opts...) + var resp *dlppb.JobTrigger + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateJobTrigger(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateJobTrigger creates a job trigger to run DLP actions such as scanning storage for +// sensitive information on a set schedule. +// See https://cloud.google.com/dlp/docs/creating-job-triggers to learn more. +func (c *Client) CreateJobTrigger(ctx context.Context, req *dlppb.CreateJobTriggerRequest, opts ...gax.CallOption) (*dlppb.JobTrigger, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateJobTrigger[0:len(c.CallOptions.CreateJobTrigger):len(c.CallOptions.CreateJobTrigger)], opts...) + var resp *dlppb.JobTrigger + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateJobTrigger(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateStoredInfoType creates a pre-built stored infoType to be used for inspection. +// See https://cloud.google.com/dlp/docs/creating-stored-infotypes to +// learn more. +func (c *Client) CreateStoredInfoType(ctx context.Context, req *dlppb.CreateStoredInfoTypeRequest, opts ...gax.CallOption) (*dlppb.StoredInfoType, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateStoredInfoType[0:len(c.CallOptions.CreateStoredInfoType):len(c.CallOptions.CreateStoredInfoType)], opts...) + var resp *dlppb.StoredInfoType + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateStoredInfoType(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateStoredInfoType updates the stored infoType by creating a new version. The existing version +// will continue to be used until the new version is ready. +// See https://cloud.google.com/dlp/docs/creating-stored-infotypes to +// learn more. +func (c *Client) UpdateStoredInfoType(ctx context.Context, req *dlppb.UpdateStoredInfoTypeRequest, opts ...gax.CallOption) (*dlppb.StoredInfoType, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateStoredInfoType[0:len(c.CallOptions.UpdateStoredInfoType):len(c.CallOptions.UpdateStoredInfoType)], opts...) + var resp *dlppb.StoredInfoType + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateStoredInfoType(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetStoredInfoType gets a stored infoType. +// See https://cloud.google.com/dlp/docs/creating-stored-infotypes to +// learn more. +func (c *Client) GetStoredInfoType(ctx context.Context, req *dlppb.GetStoredInfoTypeRequest, opts ...gax.CallOption) (*dlppb.StoredInfoType, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetStoredInfoType[0:len(c.CallOptions.GetStoredInfoType):len(c.CallOptions.GetStoredInfoType)], opts...) + var resp *dlppb.StoredInfoType + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetStoredInfoType(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListStoredInfoTypes lists stored infoTypes. +// See https://cloud.google.com/dlp/docs/creating-stored-infotypes to +// learn more. +func (c *Client) ListStoredInfoTypes(ctx context.Context, req *dlppb.ListStoredInfoTypesRequest, opts ...gax.CallOption) *StoredInfoTypeIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListStoredInfoTypes[0:len(c.CallOptions.ListStoredInfoTypes):len(c.CallOptions.ListStoredInfoTypes)], opts...) + it := &StoredInfoTypeIterator{} + req = proto.Clone(req).(*dlppb.ListStoredInfoTypesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*dlppb.StoredInfoType, string, error) { + var resp *dlppb.ListStoredInfoTypesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListStoredInfoTypes(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.StoredInfoTypes, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DeleteStoredInfoType deletes a stored infoType. +// See https://cloud.google.com/dlp/docs/creating-stored-infotypes to +// learn more. +func (c *Client) DeleteStoredInfoType(ctx context.Context, req *dlppb.DeleteStoredInfoTypeRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteStoredInfoType[0:len(c.CallOptions.DeleteStoredInfoType):len(c.CallOptions.DeleteStoredInfoType)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteStoredInfoType(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// DeidentifyTemplateIterator manages a stream of *dlppb.DeidentifyTemplate. +type DeidentifyTemplateIterator struct { + items []*dlppb.DeidentifyTemplate + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dlppb.DeidentifyTemplate, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *DeidentifyTemplateIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *DeidentifyTemplateIterator) Next() (*dlppb.DeidentifyTemplate, error) { + var item *dlppb.DeidentifyTemplate + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *DeidentifyTemplateIterator) bufLen() int { + return len(it.items) +} + +func (it *DeidentifyTemplateIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// DlpJobIterator manages a stream of *dlppb.DlpJob. +type DlpJobIterator struct { + items []*dlppb.DlpJob + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dlppb.DlpJob, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *DlpJobIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *DlpJobIterator) Next() (*dlppb.DlpJob, error) { + var item *dlppb.DlpJob + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *DlpJobIterator) bufLen() int { + return len(it.items) +} + +func (it *DlpJobIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// InspectTemplateIterator manages a stream of *dlppb.InspectTemplate. +type InspectTemplateIterator struct { + items []*dlppb.InspectTemplate + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dlppb.InspectTemplate, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InspectTemplateIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InspectTemplateIterator) Next() (*dlppb.InspectTemplate, error) { + var item *dlppb.InspectTemplate + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InspectTemplateIterator) bufLen() int { + return len(it.items) +} + +func (it *InspectTemplateIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// JobTriggerIterator manages a stream of *dlppb.JobTrigger. +type JobTriggerIterator struct { + items []*dlppb.JobTrigger + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dlppb.JobTrigger, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *JobTriggerIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *JobTriggerIterator) Next() (*dlppb.JobTrigger, error) { + var item *dlppb.JobTrigger + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *JobTriggerIterator) bufLen() int { + return len(it.items) +} + +func (it *JobTriggerIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// StoredInfoTypeIterator manages a stream of *dlppb.StoredInfoType. +type StoredInfoTypeIterator struct { + items []*dlppb.StoredInfoType + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*dlppb.StoredInfoType, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *StoredInfoTypeIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *StoredInfoTypeIterator) Next() (*dlppb.StoredInfoType, error) { + var item *dlppb.StoredInfoType + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *StoredInfoTypeIterator) bufLen() int { + return len(it.items) +} + +func (it *StoredInfoTypeIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/dlp/apiv2/dlp_client_example_test.go b/vendor/cloud.google.com/go/dlp/apiv2/dlp_client_example_test.go new file mode 100644 index 00000000..aef8debf --- /dev/null +++ b/vendor/cloud.google.com/go/dlp/apiv2/dlp_client_example_test.go @@ -0,0 +1,593 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dlp_test + +import ( + "context" + + dlp "cloud.google.com/go/dlp/apiv2" + "google.golang.org/api/iterator" + dlppb "google.golang.org/genproto/googleapis/privacy/dlp/v2" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_InspectContent() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.InspectContentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.InspectContent(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_RedactImage() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.RedactImageRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.RedactImage(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_DeidentifyContent() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.DeidentifyContentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.DeidentifyContent(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ReidentifyContent() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.ReidentifyContentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ReidentifyContent(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ListInfoTypes() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.ListInfoTypesRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ListInfoTypes(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_CreateInspectTemplate() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.CreateInspectTemplateRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateInspectTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_UpdateInspectTemplate() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.UpdateInspectTemplateRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateInspectTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_GetInspectTemplate() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.GetInspectTemplateRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetInspectTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ListInspectTemplates() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.ListInspectTemplatesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListInspectTemplates(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_DeleteInspectTemplate() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.DeleteInspectTemplateRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteInspectTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_CreateDeidentifyTemplate() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.CreateDeidentifyTemplateRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateDeidentifyTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_UpdateDeidentifyTemplate() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.UpdateDeidentifyTemplateRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateDeidentifyTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_GetDeidentifyTemplate() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.GetDeidentifyTemplateRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetDeidentifyTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ListDeidentifyTemplates() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.ListDeidentifyTemplatesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListDeidentifyTemplates(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_DeleteDeidentifyTemplate() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.DeleteDeidentifyTemplateRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteDeidentifyTemplate(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_CreateDlpJob() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.CreateDlpJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateDlpJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ListDlpJobs() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.ListDlpJobsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListDlpJobs(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_GetDlpJob() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.GetDlpJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetDlpJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_DeleteDlpJob() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.DeleteDlpJobRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteDlpJob(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_CancelDlpJob() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.CancelDlpJobRequest{ + // TODO: Fill request struct fields. + } + err = c.CancelDlpJob(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_ListJobTriggers() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.ListJobTriggersRequest{ + // TODO: Fill request struct fields. + } + it := c.ListJobTriggers(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_GetJobTrigger() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.GetJobTriggerRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetJobTrigger(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_DeleteJobTrigger() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.DeleteJobTriggerRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteJobTrigger(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_UpdateJobTrigger() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.UpdateJobTriggerRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateJobTrigger(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_CreateJobTrigger() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.CreateJobTriggerRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateJobTrigger(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_CreateStoredInfoType() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.CreateStoredInfoTypeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateStoredInfoType(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_UpdateStoredInfoType() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.UpdateStoredInfoTypeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateStoredInfoType(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_GetStoredInfoType() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.GetStoredInfoTypeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetStoredInfoType(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ListStoredInfoTypes() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.ListStoredInfoTypesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListStoredInfoTypes(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_DeleteStoredInfoType() { + ctx := context.Background() + c, err := dlp.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &dlppb.DeleteStoredInfoTypeRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteStoredInfoType(ctx, req) + if err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/dlp/apiv2/doc.go b/vendor/cloud.google.com/go/dlp/apiv2/doc.go new file mode 100644 index 00000000..4ee9d0d4 --- /dev/null +++ b/vendor/cloud.google.com/go/dlp/apiv2/doc.go @@ -0,0 +1,90 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package dlp is an auto-generated package for the +// Cloud Data Loss Prevention (DLP) API. + +// +// Provides methods for detection, risk analysis, and de-identification of +// privacy-sensitive fragments in text, images, and Google Cloud Platform +// storage repositories. +package dlp // import "cloud.google.com/go/dlp/apiv2" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/dlp/apiv2/mock_test.go b/vendor/cloud.google.com/go/dlp/apiv2/mock_test.go new file mode 100644 index 00000000..2eed9e24 --- /dev/null +++ b/vendor/cloud.google.com/go/dlp/apiv2/mock_test.go @@ -0,0 +1,2263 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package dlp + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + dlppb "google.golang.org/genproto/googleapis/privacy/dlp/v2" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockDlpServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + dlppb.DlpServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockDlpServer) InspectContent(ctx context.Context, req *dlppb.InspectContentRequest) (*dlppb.InspectContentResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.InspectContentResponse), nil +} + +func (s *mockDlpServer) RedactImage(ctx context.Context, req *dlppb.RedactImageRequest) (*dlppb.RedactImageResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.RedactImageResponse), nil +} + +func (s *mockDlpServer) DeidentifyContent(ctx context.Context, req *dlppb.DeidentifyContentRequest) (*dlppb.DeidentifyContentResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.DeidentifyContentResponse), nil +} + +func (s *mockDlpServer) ReidentifyContent(ctx context.Context, req *dlppb.ReidentifyContentRequest) (*dlppb.ReidentifyContentResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.ReidentifyContentResponse), nil +} + +func (s *mockDlpServer) ListInfoTypes(ctx context.Context, req *dlppb.ListInfoTypesRequest) (*dlppb.ListInfoTypesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.ListInfoTypesResponse), nil +} + +func (s *mockDlpServer) CreateInspectTemplate(ctx context.Context, req *dlppb.CreateInspectTemplateRequest) (*dlppb.InspectTemplate, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.InspectTemplate), nil +} + +func (s *mockDlpServer) UpdateInspectTemplate(ctx context.Context, req *dlppb.UpdateInspectTemplateRequest) (*dlppb.InspectTemplate, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.InspectTemplate), nil +} + +func (s *mockDlpServer) GetInspectTemplate(ctx context.Context, req *dlppb.GetInspectTemplateRequest) (*dlppb.InspectTemplate, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.InspectTemplate), nil +} + +func (s *mockDlpServer) ListInspectTemplates(ctx context.Context, req *dlppb.ListInspectTemplatesRequest) (*dlppb.ListInspectTemplatesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.ListInspectTemplatesResponse), nil +} + +func (s *mockDlpServer) DeleteInspectTemplate(ctx context.Context, req *dlppb.DeleteInspectTemplateRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockDlpServer) CreateDeidentifyTemplate(ctx context.Context, req *dlppb.CreateDeidentifyTemplateRequest) (*dlppb.DeidentifyTemplate, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.DeidentifyTemplate), nil +} + +func (s *mockDlpServer) UpdateDeidentifyTemplate(ctx context.Context, req *dlppb.UpdateDeidentifyTemplateRequest) (*dlppb.DeidentifyTemplate, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.DeidentifyTemplate), nil +} + +func (s *mockDlpServer) GetDeidentifyTemplate(ctx context.Context, req *dlppb.GetDeidentifyTemplateRequest) (*dlppb.DeidentifyTemplate, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.DeidentifyTemplate), nil +} + +func (s *mockDlpServer) ListDeidentifyTemplates(ctx context.Context, req *dlppb.ListDeidentifyTemplatesRequest) (*dlppb.ListDeidentifyTemplatesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.ListDeidentifyTemplatesResponse), nil +} + +func (s *mockDlpServer) DeleteDeidentifyTemplate(ctx context.Context, req *dlppb.DeleteDeidentifyTemplateRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockDlpServer) CreateJobTrigger(ctx context.Context, req *dlppb.CreateJobTriggerRequest) (*dlppb.JobTrigger, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.JobTrigger), nil +} + +func (s *mockDlpServer) UpdateJobTrigger(ctx context.Context, req *dlppb.UpdateJobTriggerRequest) (*dlppb.JobTrigger, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.JobTrigger), nil +} + +func (s *mockDlpServer) GetJobTrigger(ctx context.Context, req *dlppb.GetJobTriggerRequest) (*dlppb.JobTrigger, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.JobTrigger), nil +} + +func (s *mockDlpServer) ListJobTriggers(ctx context.Context, req *dlppb.ListJobTriggersRequest) (*dlppb.ListJobTriggersResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.ListJobTriggersResponse), nil +} + +func (s *mockDlpServer) DeleteJobTrigger(ctx context.Context, req *dlppb.DeleteJobTriggerRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockDlpServer) CreateDlpJob(ctx context.Context, req *dlppb.CreateDlpJobRequest) (*dlppb.DlpJob, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.DlpJob), nil +} + +func (s *mockDlpServer) ListDlpJobs(ctx context.Context, req *dlppb.ListDlpJobsRequest) (*dlppb.ListDlpJobsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.ListDlpJobsResponse), nil +} + +func (s *mockDlpServer) GetDlpJob(ctx context.Context, req *dlppb.GetDlpJobRequest) (*dlppb.DlpJob, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.DlpJob), nil +} + +func (s *mockDlpServer) DeleteDlpJob(ctx context.Context, req *dlppb.DeleteDlpJobRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockDlpServer) CancelDlpJob(ctx context.Context, req *dlppb.CancelDlpJobRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockDlpServer) CreateStoredInfoType(ctx context.Context, req *dlppb.CreateStoredInfoTypeRequest) (*dlppb.StoredInfoType, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.StoredInfoType), nil +} + +func (s *mockDlpServer) UpdateStoredInfoType(ctx context.Context, req *dlppb.UpdateStoredInfoTypeRequest) (*dlppb.StoredInfoType, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.StoredInfoType), nil +} + +func (s *mockDlpServer) GetStoredInfoType(ctx context.Context, req *dlppb.GetStoredInfoTypeRequest) (*dlppb.StoredInfoType, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.StoredInfoType), nil +} + +func (s *mockDlpServer) ListStoredInfoTypes(ctx context.Context, req *dlppb.ListStoredInfoTypesRequest) (*dlppb.ListStoredInfoTypesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*dlppb.ListStoredInfoTypesResponse), nil +} + +func (s *mockDlpServer) DeleteStoredInfoType(ctx context.Context, req *dlppb.DeleteStoredInfoTypeRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockDlp mockDlpServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + dlppb.RegisterDlpServiceServer(serv, &mockDlp) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestDlpServiceInspectContent(t *testing.T) { + var expectedResponse *dlppb.InspectContentResponse = &dlppb.InspectContentResponse{} + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.InspectContentRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.InspectContent(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceInspectContentError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.InspectContentRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.InspectContent(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceRedactImage(t *testing.T) { + var redactedImage []byte = []byte("28") + var extractedText string = "extractedText998260012" + var expectedResponse = &dlppb.RedactImageResponse{ + RedactedImage: redactedImage, + ExtractedText: extractedText, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.RedactImageRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RedactImage(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceRedactImageError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.RedactImageRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RedactImage(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceDeidentifyContent(t *testing.T) { + var expectedResponse *dlppb.DeidentifyContentResponse = &dlppb.DeidentifyContentResponse{} + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.DeidentifyContentRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.DeidentifyContent(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceDeidentifyContentError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.DeidentifyContentRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.DeidentifyContent(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceReidentifyContent(t *testing.T) { + var expectedResponse *dlppb.ReidentifyContentResponse = &dlppb.ReidentifyContentResponse{} + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.ReidentifyContentRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ReidentifyContent(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceReidentifyContentError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.ReidentifyContentRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ReidentifyContent(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceListInfoTypes(t *testing.T) { + var expectedResponse *dlppb.ListInfoTypesResponse = &dlppb.ListInfoTypesResponse{} + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var request *dlppb.ListInfoTypesRequest = &dlppb.ListInfoTypesRequest{} + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListInfoTypes(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceListInfoTypesError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var request *dlppb.ListInfoTypesRequest = &dlppb.ListInfoTypesRequest{} + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListInfoTypes(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceCreateInspectTemplate(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &dlppb.InspectTemplate{ + Name: name, + DisplayName: displayName, + Description: description, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &dlppb.CreateInspectTemplateRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateInspectTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceCreateInspectTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &dlppb.CreateInspectTemplateRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateInspectTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceUpdateInspectTemplate(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &dlppb.InspectTemplate{ + Name: name2, + DisplayName: displayName, + Description: description, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("organizations/%s/inspectTemplates/%s", "[ORGANIZATION]", "[INSPECT_TEMPLATE]") + var request = &dlppb.UpdateInspectTemplateRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateInspectTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceUpdateInspectTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("organizations/%s/inspectTemplates/%s", "[ORGANIZATION]", "[INSPECT_TEMPLATE]") + var request = &dlppb.UpdateInspectTemplateRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateInspectTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceGetInspectTemplate(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &dlppb.InspectTemplate{ + Name: name, + DisplayName: displayName, + Description: description, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var request *dlppb.GetInspectTemplateRequest = &dlppb.GetInspectTemplateRequest{} + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetInspectTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceGetInspectTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var request *dlppb.GetInspectTemplateRequest = &dlppb.GetInspectTemplateRequest{} + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetInspectTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceListInspectTemplates(t *testing.T) { + var nextPageToken string = "" + var inspectTemplatesElement *dlppb.InspectTemplate = &dlppb.InspectTemplate{} + var inspectTemplates = []*dlppb.InspectTemplate{inspectTemplatesElement} + var expectedResponse = &dlppb.ListInspectTemplatesResponse{ + NextPageToken: nextPageToken, + InspectTemplates: inspectTemplates, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &dlppb.ListInspectTemplatesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListInspectTemplates(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.InspectTemplates[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceListInspectTemplatesError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &dlppb.ListInspectTemplatesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListInspectTemplates(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceDeleteInspectTemplate(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("organizations/%s/inspectTemplates/%s", "[ORGANIZATION]", "[INSPECT_TEMPLATE]") + var request = &dlppb.DeleteInspectTemplateRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteInspectTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestDlpServiceDeleteInspectTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("organizations/%s/inspectTemplates/%s", "[ORGANIZATION]", "[INSPECT_TEMPLATE]") + var request = &dlppb.DeleteInspectTemplateRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteInspectTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestDlpServiceCreateDeidentifyTemplate(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &dlppb.DeidentifyTemplate{ + Name: name, + DisplayName: displayName, + Description: description, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &dlppb.CreateDeidentifyTemplateRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateDeidentifyTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceCreateDeidentifyTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &dlppb.CreateDeidentifyTemplateRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateDeidentifyTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceUpdateDeidentifyTemplate(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &dlppb.DeidentifyTemplate{ + Name: name2, + DisplayName: displayName, + Description: description, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("organizations/%s/deidentifyTemplates/%s", "[ORGANIZATION]", "[DEIDENTIFY_TEMPLATE]") + var request = &dlppb.UpdateDeidentifyTemplateRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateDeidentifyTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceUpdateDeidentifyTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("organizations/%s/deidentifyTemplates/%s", "[ORGANIZATION]", "[DEIDENTIFY_TEMPLATE]") + var request = &dlppb.UpdateDeidentifyTemplateRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateDeidentifyTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceGetDeidentifyTemplate(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &dlppb.DeidentifyTemplate{ + Name: name2, + DisplayName: displayName, + Description: description, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("organizations/%s/deidentifyTemplates/%s", "[ORGANIZATION]", "[DEIDENTIFY_TEMPLATE]") + var request = &dlppb.GetDeidentifyTemplateRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetDeidentifyTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceGetDeidentifyTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("organizations/%s/deidentifyTemplates/%s", "[ORGANIZATION]", "[DEIDENTIFY_TEMPLATE]") + var request = &dlppb.GetDeidentifyTemplateRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetDeidentifyTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceListDeidentifyTemplates(t *testing.T) { + var nextPageToken string = "" + var deidentifyTemplatesElement *dlppb.DeidentifyTemplate = &dlppb.DeidentifyTemplate{} + var deidentifyTemplates = []*dlppb.DeidentifyTemplate{deidentifyTemplatesElement} + var expectedResponse = &dlppb.ListDeidentifyTemplatesResponse{ + NextPageToken: nextPageToken, + DeidentifyTemplates: deidentifyTemplates, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &dlppb.ListDeidentifyTemplatesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListDeidentifyTemplates(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.DeidentifyTemplates[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceListDeidentifyTemplatesError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &dlppb.ListDeidentifyTemplatesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListDeidentifyTemplates(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceDeleteDeidentifyTemplate(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("organizations/%s/deidentifyTemplates/%s", "[ORGANIZATION]", "[DEIDENTIFY_TEMPLATE]") + var request = &dlppb.DeleteDeidentifyTemplateRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteDeidentifyTemplate(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestDlpServiceDeleteDeidentifyTemplateError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("organizations/%s/deidentifyTemplates/%s", "[ORGANIZATION]", "[DEIDENTIFY_TEMPLATE]") + var request = &dlppb.DeleteDeidentifyTemplateRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteDeidentifyTemplate(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestDlpServiceCreateDlpJob(t *testing.T) { + var name string = "name3373707" + var jobTriggerName string = "jobTriggerName1819490804" + var expectedResponse = &dlppb.DlpJob{ + Name: name, + JobTriggerName: jobTriggerName, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.CreateDlpJobRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateDlpJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceCreateDlpJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.CreateDlpJobRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateDlpJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceListDlpJobs(t *testing.T) { + var nextPageToken string = "" + var jobsElement *dlppb.DlpJob = &dlppb.DlpJob{} + var jobs = []*dlppb.DlpJob{jobsElement} + var expectedResponse = &dlppb.ListDlpJobsResponse{ + NextPageToken: nextPageToken, + Jobs: jobs, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.ListDlpJobsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListDlpJobs(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Jobs[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceListDlpJobsError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.ListDlpJobsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListDlpJobs(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceGetDlpJob(t *testing.T) { + var name2 string = "name2-1052831874" + var jobTriggerName string = "jobTriggerName1819490804" + var expectedResponse = &dlppb.DlpJob{ + Name: name2, + JobTriggerName: jobTriggerName, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/dlpJobs/%s", "[PROJECT]", "[DLP_JOB]") + var request = &dlppb.GetDlpJobRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetDlpJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceGetDlpJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/dlpJobs/%s", "[PROJECT]", "[DLP_JOB]") + var request = &dlppb.GetDlpJobRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetDlpJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceDeleteDlpJob(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/dlpJobs/%s", "[PROJECT]", "[DLP_JOB]") + var request = &dlppb.DeleteDlpJobRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteDlpJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestDlpServiceDeleteDlpJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/dlpJobs/%s", "[PROJECT]", "[DLP_JOB]") + var request = &dlppb.DeleteDlpJobRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteDlpJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestDlpServiceCancelDlpJob(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/dlpJobs/%s", "[PROJECT]", "[DLP_JOB]") + var request = &dlppb.CancelDlpJobRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.CancelDlpJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestDlpServiceCancelDlpJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/dlpJobs/%s", "[PROJECT]", "[DLP_JOB]") + var request = &dlppb.CancelDlpJobRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.CancelDlpJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestDlpServiceListJobTriggers(t *testing.T) { + var nextPageToken string = "" + var jobTriggersElement *dlppb.JobTrigger = &dlppb.JobTrigger{} + var jobTriggers = []*dlppb.JobTrigger{jobTriggersElement} + var expectedResponse = &dlppb.ListJobTriggersResponse{ + NextPageToken: nextPageToken, + JobTriggers: jobTriggers, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.ListJobTriggersRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListJobTriggers(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.JobTriggers[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceListJobTriggersError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.ListJobTriggersRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListJobTriggers(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceGetJobTrigger(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &dlppb.JobTrigger{ + Name: name2, + DisplayName: displayName, + Description: description, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/jobTriggers/%s", "[PROJECT]", "[JOB_TRIGGER]") + var request = &dlppb.GetJobTriggerRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetJobTrigger(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceGetJobTriggerError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/jobTriggers/%s", "[PROJECT]", "[JOB_TRIGGER]") + var request = &dlppb.GetJobTriggerRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetJobTrigger(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceDeleteJobTrigger(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var name string = "name3373707" + var request = &dlppb.DeleteJobTriggerRequest{ + Name: name, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteJobTrigger(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestDlpServiceDeleteJobTriggerError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var name string = "name3373707" + var request = &dlppb.DeleteJobTriggerRequest{ + Name: name, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteJobTrigger(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestDlpServiceUpdateJobTrigger(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &dlppb.JobTrigger{ + Name: name2, + DisplayName: displayName, + Description: description, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/jobTriggers/%s", "[PROJECT]", "[JOB_TRIGGER]") + var request = &dlppb.UpdateJobTriggerRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateJobTrigger(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceUpdateJobTriggerError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/jobTriggers/%s", "[PROJECT]", "[JOB_TRIGGER]") + var request = &dlppb.UpdateJobTriggerRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateJobTrigger(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceCreateJobTrigger(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &dlppb.JobTrigger{ + Name: name, + DisplayName: displayName, + Description: description, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.CreateJobTriggerRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateJobTrigger(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceCreateJobTriggerError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &dlppb.CreateJobTriggerRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateJobTrigger(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceCreateStoredInfoType(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &dlppb.StoredInfoType{ + Name: name, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &dlppb.CreateStoredInfoTypeRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateStoredInfoType(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceCreateStoredInfoTypeError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &dlppb.CreateStoredInfoTypeRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateStoredInfoType(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceUpdateStoredInfoType(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &dlppb.StoredInfoType{ + Name: name2, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("organizations/%s/storedInfoTypes/%s", "[ORGANIZATION]", "[STORED_INFO_TYPE]") + var request = &dlppb.UpdateStoredInfoTypeRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateStoredInfoType(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceUpdateStoredInfoTypeError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("organizations/%s/storedInfoTypes/%s", "[ORGANIZATION]", "[STORED_INFO_TYPE]") + var request = &dlppb.UpdateStoredInfoTypeRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateStoredInfoType(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceGetStoredInfoType(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &dlppb.StoredInfoType{ + Name: name2, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("organizations/%s/storedInfoTypes/%s", "[ORGANIZATION]", "[STORED_INFO_TYPE]") + var request = &dlppb.GetStoredInfoTypeRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetStoredInfoType(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceGetStoredInfoTypeError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("organizations/%s/storedInfoTypes/%s", "[ORGANIZATION]", "[STORED_INFO_TYPE]") + var request = &dlppb.GetStoredInfoTypeRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetStoredInfoType(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceListStoredInfoTypes(t *testing.T) { + var nextPageToken string = "" + var storedInfoTypesElement *dlppb.StoredInfoType = &dlppb.StoredInfoType{} + var storedInfoTypes = []*dlppb.StoredInfoType{storedInfoTypesElement} + var expectedResponse = &dlppb.ListStoredInfoTypesResponse{ + NextPageToken: nextPageToken, + StoredInfoTypes: storedInfoTypes, + } + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &dlppb.ListStoredInfoTypesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListStoredInfoTypes(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.StoredInfoTypes[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDlpServiceListStoredInfoTypesError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &dlppb.ListStoredInfoTypesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListStoredInfoTypes(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDlpServiceDeleteStoredInfoType(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockDlp.err = nil + mockDlp.reqs = nil + + mockDlp.resps = append(mockDlp.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("organizations/%s/storedInfoTypes/%s", "[ORGANIZATION]", "[STORED_INFO_TYPE]") + var request = &dlppb.DeleteStoredInfoTypeRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteStoredInfoType(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDlp.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestDlpServiceDeleteStoredInfoTypeError(t *testing.T) { + errCode := codes.PermissionDenied + mockDlp.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("organizations/%s/storedInfoTypes/%s", "[ORGANIZATION]", "[STORED_INFO_TYPE]") + var request = &dlppb.DeleteStoredInfoTypeRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteStoredInfoType(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} diff --git a/vendor/cloud.google.com/go/errorreporting/apiv1beta1/ReportErrorEvent_smoke_test.go b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/ReportErrorEvent_smoke_test.go new file mode 100644 index 00000000..3470a2fe --- /dev/null +++ b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/ReportErrorEvent_smoke_test.go @@ -0,0 +1,88 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package errorreporting + +import ( + clouderrorreportingpb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestReportErrorsServiceSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewReportErrorsClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var formattedProjectName string = fmt.Sprintf("projects/%s", projectId) + var message string = "[MESSAGE]" + var service string = "[SERVICE]" + var serviceContext = &clouderrorreportingpb.ServiceContext{ + Service: service, + } + var filePath string = "path/to/file.lang" + var lineNumber int32 = 42 + var functionName string = "meaningOfLife" + var reportLocation = &clouderrorreportingpb.SourceLocation{ + FilePath: filePath, + LineNumber: lineNumber, + FunctionName: functionName, + } + var context_ = &clouderrorreportingpb.ErrorContext{ + ReportLocation: reportLocation, + } + var event = &clouderrorreportingpb.ReportedErrorEvent{ + Message: message, + ServiceContext: serviceContext, + Context: context_, + } + var request = &clouderrorreportingpb.ReportErrorEventRequest{ + ProjectName: formattedProjectName, + Event: event, + } + + if _, err := c.ReportErrorEvent(ctx, request); err != nil { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/errorreporting/apiv1beta1/doc.go b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/doc.go new file mode 100644 index 00000000..65af3790 --- /dev/null +++ b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/doc.go @@ -0,0 +1,93 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package errorreporting is an auto-generated package for the +// Stackdriver Error Reporting API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Stackdriver Error Reporting groups and counts similar errors from cloud +// services. The Stackdriver Error Reporting API provides a way to report new +// errors and read access to error groups and their associated errors. +// +// Use the client at cloud.google.com/go/errorreporting in preference to this. +package errorreporting // import "cloud.google.com/go/errorreporting/apiv1beta1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/errorreporting/apiv1beta1/error_group_client.go b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/error_group_client.go new file mode 100644 index 00000000..d4d360a8 --- /dev/null +++ b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/error_group_client.go @@ -0,0 +1,152 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package errorreporting + +import ( + "context" + "time" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + clouderrorreportingpb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// ErrorGroupCallOptions contains the retry settings for each method of ErrorGroupClient. +type ErrorGroupCallOptions struct { + GetGroup []gax.CallOption + UpdateGroup []gax.CallOption +} + +func defaultErrorGroupClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("clouderrorreporting.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultErrorGroupCallOptions() *ErrorGroupCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &ErrorGroupCallOptions{ + GetGroup: retry[[2]string{"default", "idempotent"}], + UpdateGroup: retry[[2]string{"default", "idempotent"}], + } +} + +// ErrorGroupClient is a client for interacting with Stackdriver Error Reporting API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type ErrorGroupClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + errorGroupClient clouderrorreportingpb.ErrorGroupServiceClient + + // The call options for this service. + CallOptions *ErrorGroupCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewErrorGroupClient creates a new error group service client. +// +// Service for retrieving and updating individual error groups. +func NewErrorGroupClient(ctx context.Context, opts ...option.ClientOption) (*ErrorGroupClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultErrorGroupClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &ErrorGroupClient{ + conn: conn, + CallOptions: defaultErrorGroupCallOptions(), + + errorGroupClient: clouderrorreportingpb.NewErrorGroupServiceClient(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *ErrorGroupClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *ErrorGroupClient) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *ErrorGroupClient) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// GetGroup get the specified group. +func (c *ErrorGroupClient) GetGroup(ctx context.Context, req *clouderrorreportingpb.GetGroupRequest, opts ...gax.CallOption) (*clouderrorreportingpb.ErrorGroup, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetGroup[0:len(c.CallOptions.GetGroup):len(c.CallOptions.GetGroup)], opts...) + var resp *clouderrorreportingpb.ErrorGroup + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.errorGroupClient.GetGroup(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateGroup replace the data for the specified group. +// Fails if the group does not exist. +func (c *ErrorGroupClient) UpdateGroup(ctx context.Context, req *clouderrorreportingpb.UpdateGroupRequest, opts ...gax.CallOption) (*clouderrorreportingpb.ErrorGroup, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateGroup[0:len(c.CallOptions.UpdateGroup):len(c.CallOptions.UpdateGroup)], opts...) + var resp *clouderrorreportingpb.ErrorGroup + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.errorGroupClient.UpdateGroup(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/errorreporting/apiv1beta1/error_group_client_example_test.go b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/error_group_client_example_test.go new file mode 100644 index 00000000..de8435c2 --- /dev/null +++ b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/error_group_client_example_test.go @@ -0,0 +1,70 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package errorreporting_test + +import ( + "context" + + errorreporting "cloud.google.com/go/errorreporting/apiv1beta1" + clouderrorreportingpb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" +) + +func ExampleNewErrorGroupClient() { + ctx := context.Background() + c, err := errorreporting.NewErrorGroupClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleErrorGroupClient_GetGroup() { + ctx := context.Background() + c, err := errorreporting.NewErrorGroupClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouderrorreportingpb.GetGroupRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetGroup(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleErrorGroupClient_UpdateGroup() { + ctx := context.Background() + c, err := errorreporting.NewErrorGroupClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouderrorreportingpb.UpdateGroupRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateGroup(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/errorreporting/apiv1beta1/error_stats_client.go b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/error_stats_client.go new file mode 100644 index 00000000..52c06b5a --- /dev/null +++ b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/error_stats_client.go @@ -0,0 +1,299 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package errorreporting + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + clouderrorreportingpb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// ErrorStatsCallOptions contains the retry settings for each method of ErrorStatsClient. +type ErrorStatsCallOptions struct { + ListGroupStats []gax.CallOption + ListEvents []gax.CallOption + DeleteEvents []gax.CallOption +} + +func defaultErrorStatsClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("clouderrorreporting.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultErrorStatsCallOptions() *ErrorStatsCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &ErrorStatsCallOptions{ + ListGroupStats: retry[[2]string{"default", "idempotent"}], + ListEvents: retry[[2]string{"default", "idempotent"}], + DeleteEvents: retry[[2]string{"default", "idempotent"}], + } +} + +// ErrorStatsClient is a client for interacting with Stackdriver Error Reporting API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type ErrorStatsClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + errorStatsClient clouderrorreportingpb.ErrorStatsServiceClient + + // The call options for this service. + CallOptions *ErrorStatsCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewErrorStatsClient creates a new error stats service client. +// +// An API for retrieving and managing error statistics as well as data for +// individual events. +func NewErrorStatsClient(ctx context.Context, opts ...option.ClientOption) (*ErrorStatsClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultErrorStatsClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &ErrorStatsClient{ + conn: conn, + CallOptions: defaultErrorStatsCallOptions(), + + errorStatsClient: clouderrorreportingpb.NewErrorStatsServiceClient(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *ErrorStatsClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *ErrorStatsClient) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *ErrorStatsClient) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListGroupStats lists the specified groups. +func (c *ErrorStatsClient) ListGroupStats(ctx context.Context, req *clouderrorreportingpb.ListGroupStatsRequest, opts ...gax.CallOption) *ErrorGroupStatsIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListGroupStats[0:len(c.CallOptions.ListGroupStats):len(c.CallOptions.ListGroupStats)], opts...) + it := &ErrorGroupStatsIterator{} + req = proto.Clone(req).(*clouderrorreportingpb.ListGroupStatsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*clouderrorreportingpb.ErrorGroupStats, string, error) { + var resp *clouderrorreportingpb.ListGroupStatsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.errorStatsClient.ListGroupStats(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.ErrorGroupStats, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// ListEvents lists the specified events. +func (c *ErrorStatsClient) ListEvents(ctx context.Context, req *clouderrorreportingpb.ListEventsRequest, opts ...gax.CallOption) *ErrorEventIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListEvents[0:len(c.CallOptions.ListEvents):len(c.CallOptions.ListEvents)], opts...) + it := &ErrorEventIterator{} + req = proto.Clone(req).(*clouderrorreportingpb.ListEventsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*clouderrorreportingpb.ErrorEvent, string, error) { + var resp *clouderrorreportingpb.ListEventsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.errorStatsClient.ListEvents(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.ErrorEvents, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DeleteEvents deletes all error events of a given project. +func (c *ErrorStatsClient) DeleteEvents(ctx context.Context, req *clouderrorreportingpb.DeleteEventsRequest, opts ...gax.CallOption) (*clouderrorreportingpb.DeleteEventsResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteEvents[0:len(c.CallOptions.DeleteEvents):len(c.CallOptions.DeleteEvents)], opts...) + var resp *clouderrorreportingpb.DeleteEventsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.errorStatsClient.DeleteEvents(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ErrorEventIterator manages a stream of *clouderrorreportingpb.ErrorEvent. +type ErrorEventIterator struct { + items []*clouderrorreportingpb.ErrorEvent + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*clouderrorreportingpb.ErrorEvent, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ErrorEventIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ErrorEventIterator) Next() (*clouderrorreportingpb.ErrorEvent, error) { + var item *clouderrorreportingpb.ErrorEvent + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ErrorEventIterator) bufLen() int { + return len(it.items) +} + +func (it *ErrorEventIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// ErrorGroupStatsIterator manages a stream of *clouderrorreportingpb.ErrorGroupStats. +type ErrorGroupStatsIterator struct { + items []*clouderrorreportingpb.ErrorGroupStats + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*clouderrorreportingpb.ErrorGroupStats, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ErrorGroupStatsIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ErrorGroupStatsIterator) Next() (*clouderrorreportingpb.ErrorGroupStats, error) { + var item *clouderrorreportingpb.ErrorGroupStats + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ErrorGroupStatsIterator) bufLen() int { + return len(it.items) +} + +func (it *ErrorGroupStatsIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/errorreporting/apiv1beta1/error_stats_client_example_test.go b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/error_stats_client_example_test.go new file mode 100644 index 00000000..fdcf75a3 --- /dev/null +++ b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/error_stats_client_example_test.go @@ -0,0 +1,101 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package errorreporting_test + +import ( + "context" + + errorreporting "cloud.google.com/go/errorreporting/apiv1beta1" + "google.golang.org/api/iterator" + clouderrorreportingpb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" +) + +func ExampleNewErrorStatsClient() { + ctx := context.Background() + c, err := errorreporting.NewErrorStatsClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleErrorStatsClient_ListGroupStats() { + ctx := context.Background() + c, err := errorreporting.NewErrorStatsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouderrorreportingpb.ListGroupStatsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListGroupStats(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleErrorStatsClient_ListEvents() { + ctx := context.Background() + c, err := errorreporting.NewErrorStatsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouderrorreportingpb.ListEventsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListEvents(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleErrorStatsClient_DeleteEvents() { + ctx := context.Background() + c, err := errorreporting.NewErrorStatsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouderrorreportingpb.DeleteEventsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.DeleteEvents(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/errorreporting/apiv1beta1/mock_test.go b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/mock_test.go new file mode 100644 index 00000000..75f5cb8c --- /dev/null +++ b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/mock_test.go @@ -0,0 +1,587 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package errorreporting + +import ( + clouderrorreportingpb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockErrorGroupServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + clouderrorreportingpb.ErrorGroupServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockErrorGroupServer) GetGroup(ctx context.Context, req *clouderrorreportingpb.GetGroupRequest) (*clouderrorreportingpb.ErrorGroup, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*clouderrorreportingpb.ErrorGroup), nil +} + +func (s *mockErrorGroupServer) UpdateGroup(ctx context.Context, req *clouderrorreportingpb.UpdateGroupRequest) (*clouderrorreportingpb.ErrorGroup, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*clouderrorreportingpb.ErrorGroup), nil +} + +type mockErrorStatsServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + clouderrorreportingpb.ErrorStatsServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockErrorStatsServer) ListGroupStats(ctx context.Context, req *clouderrorreportingpb.ListGroupStatsRequest) (*clouderrorreportingpb.ListGroupStatsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*clouderrorreportingpb.ListGroupStatsResponse), nil +} + +func (s *mockErrorStatsServer) ListEvents(ctx context.Context, req *clouderrorreportingpb.ListEventsRequest) (*clouderrorreportingpb.ListEventsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*clouderrorreportingpb.ListEventsResponse), nil +} + +func (s *mockErrorStatsServer) DeleteEvents(ctx context.Context, req *clouderrorreportingpb.DeleteEventsRequest) (*clouderrorreportingpb.DeleteEventsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*clouderrorreportingpb.DeleteEventsResponse), nil +} + +type mockReportErrorsServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + clouderrorreportingpb.ReportErrorsServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockReportErrorsServer) ReportErrorEvent(ctx context.Context, req *clouderrorreportingpb.ReportErrorEventRequest) (*clouderrorreportingpb.ReportErrorEventResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*clouderrorreportingpb.ReportErrorEventResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockErrorGroup mockErrorGroupServer + mockErrorStats mockErrorStatsServer + mockReportErrors mockReportErrorsServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + clouderrorreportingpb.RegisterErrorGroupServiceServer(serv, &mockErrorGroup) + clouderrorreportingpb.RegisterErrorStatsServiceServer(serv, &mockErrorStats) + clouderrorreportingpb.RegisterReportErrorsServiceServer(serv, &mockReportErrors) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestErrorGroupServiceGetGroup(t *testing.T) { + var name string = "name3373707" + var groupId string = "groupId506361563" + var expectedResponse = &clouderrorreportingpb.ErrorGroup{ + Name: name, + GroupId: groupId, + } + + mockErrorGroup.err = nil + mockErrorGroup.reqs = nil + + mockErrorGroup.resps = append(mockErrorGroup.resps[:0], expectedResponse) + + var formattedGroupName string = fmt.Sprintf("projects/%s/groups/%s", "[PROJECT]", "[GROUP]") + var request = &clouderrorreportingpb.GetGroupRequest{ + GroupName: formattedGroupName, + } + + c, err := NewErrorGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetGroup(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockErrorGroup.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestErrorGroupServiceGetGroupError(t *testing.T) { + errCode := codes.PermissionDenied + mockErrorGroup.err = gstatus.Error(errCode, "test error") + + var formattedGroupName string = fmt.Sprintf("projects/%s/groups/%s", "[PROJECT]", "[GROUP]") + var request = &clouderrorreportingpb.GetGroupRequest{ + GroupName: formattedGroupName, + } + + c, err := NewErrorGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetGroup(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestErrorGroupServiceUpdateGroup(t *testing.T) { + var name string = "name3373707" + var groupId string = "groupId506361563" + var expectedResponse = &clouderrorreportingpb.ErrorGroup{ + Name: name, + GroupId: groupId, + } + + mockErrorGroup.err = nil + mockErrorGroup.reqs = nil + + mockErrorGroup.resps = append(mockErrorGroup.resps[:0], expectedResponse) + + var group *clouderrorreportingpb.ErrorGroup = &clouderrorreportingpb.ErrorGroup{} + var request = &clouderrorreportingpb.UpdateGroupRequest{ + Group: group, + } + + c, err := NewErrorGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateGroup(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockErrorGroup.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestErrorGroupServiceUpdateGroupError(t *testing.T) { + errCode := codes.PermissionDenied + mockErrorGroup.err = gstatus.Error(errCode, "test error") + + var group *clouderrorreportingpb.ErrorGroup = &clouderrorreportingpb.ErrorGroup{} + var request = &clouderrorreportingpb.UpdateGroupRequest{ + Group: group, + } + + c, err := NewErrorGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateGroup(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestErrorStatsServiceListGroupStats(t *testing.T) { + var nextPageToken string = "" + var errorGroupStatsElement *clouderrorreportingpb.ErrorGroupStats = &clouderrorreportingpb.ErrorGroupStats{} + var errorGroupStats = []*clouderrorreportingpb.ErrorGroupStats{errorGroupStatsElement} + var expectedResponse = &clouderrorreportingpb.ListGroupStatsResponse{ + NextPageToken: nextPageToken, + ErrorGroupStats: errorGroupStats, + } + + mockErrorStats.err = nil + mockErrorStats.reqs = nil + + mockErrorStats.resps = append(mockErrorStats.resps[:0], expectedResponse) + + var formattedProjectName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var timeRange *clouderrorreportingpb.QueryTimeRange = &clouderrorreportingpb.QueryTimeRange{} + var request = &clouderrorreportingpb.ListGroupStatsRequest{ + ProjectName: formattedProjectName, + TimeRange: timeRange, + } + + c, err := NewErrorStatsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListGroupStats(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockErrorStats.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.ErrorGroupStats[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestErrorStatsServiceListGroupStatsError(t *testing.T) { + errCode := codes.PermissionDenied + mockErrorStats.err = gstatus.Error(errCode, "test error") + + var formattedProjectName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var timeRange *clouderrorreportingpb.QueryTimeRange = &clouderrorreportingpb.QueryTimeRange{} + var request = &clouderrorreportingpb.ListGroupStatsRequest{ + ProjectName: formattedProjectName, + TimeRange: timeRange, + } + + c, err := NewErrorStatsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListGroupStats(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestErrorStatsServiceListEvents(t *testing.T) { + var nextPageToken string = "" + var errorEventsElement *clouderrorreportingpb.ErrorEvent = &clouderrorreportingpb.ErrorEvent{} + var errorEvents = []*clouderrorreportingpb.ErrorEvent{errorEventsElement} + var expectedResponse = &clouderrorreportingpb.ListEventsResponse{ + NextPageToken: nextPageToken, + ErrorEvents: errorEvents, + } + + mockErrorStats.err = nil + mockErrorStats.reqs = nil + + mockErrorStats.resps = append(mockErrorStats.resps[:0], expectedResponse) + + var formattedProjectName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var groupId string = "groupId506361563" + var request = &clouderrorreportingpb.ListEventsRequest{ + ProjectName: formattedProjectName, + GroupId: groupId, + } + + c, err := NewErrorStatsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListEvents(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockErrorStats.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.ErrorEvents[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestErrorStatsServiceListEventsError(t *testing.T) { + errCode := codes.PermissionDenied + mockErrorStats.err = gstatus.Error(errCode, "test error") + + var formattedProjectName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var groupId string = "groupId506361563" + var request = &clouderrorreportingpb.ListEventsRequest{ + ProjectName: formattedProjectName, + GroupId: groupId, + } + + c, err := NewErrorStatsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListEvents(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestErrorStatsServiceDeleteEvents(t *testing.T) { + var expectedResponse *clouderrorreportingpb.DeleteEventsResponse = &clouderrorreportingpb.DeleteEventsResponse{} + + mockErrorStats.err = nil + mockErrorStats.reqs = nil + + mockErrorStats.resps = append(mockErrorStats.resps[:0], expectedResponse) + + var formattedProjectName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &clouderrorreportingpb.DeleteEventsRequest{ + ProjectName: formattedProjectName, + } + + c, err := NewErrorStatsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.DeleteEvents(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockErrorStats.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestErrorStatsServiceDeleteEventsError(t *testing.T) { + errCode := codes.PermissionDenied + mockErrorStats.err = gstatus.Error(errCode, "test error") + + var formattedProjectName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &clouderrorreportingpb.DeleteEventsRequest{ + ProjectName: formattedProjectName, + } + + c, err := NewErrorStatsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.DeleteEvents(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestReportErrorsServiceReportErrorEvent(t *testing.T) { + var expectedResponse *clouderrorreportingpb.ReportErrorEventResponse = &clouderrorreportingpb.ReportErrorEventResponse{} + + mockReportErrors.err = nil + mockReportErrors.reqs = nil + + mockReportErrors.resps = append(mockReportErrors.resps[:0], expectedResponse) + + var formattedProjectName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var event *clouderrorreportingpb.ReportedErrorEvent = &clouderrorreportingpb.ReportedErrorEvent{} + var request = &clouderrorreportingpb.ReportErrorEventRequest{ + ProjectName: formattedProjectName, + Event: event, + } + + c, err := NewReportErrorsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ReportErrorEvent(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockReportErrors.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestReportErrorsServiceReportErrorEventError(t *testing.T) { + errCode := codes.PermissionDenied + mockReportErrors.err = gstatus.Error(errCode, "test error") + + var formattedProjectName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var event *clouderrorreportingpb.ReportedErrorEvent = &clouderrorreportingpb.ReportedErrorEvent{} + var request = &clouderrorreportingpb.ReportErrorEventRequest{ + ProjectName: formattedProjectName, + Event: event, + } + + c, err := NewReportErrorsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ReportErrorEvent(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/errorreporting/apiv1beta1/path_funcs.go b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/path_funcs.go new file mode 100644 index 00000000..5ca5e927 --- /dev/null +++ b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/path_funcs.go @@ -0,0 +1,51 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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 errorreporting + +// ResultPath returns the path for the result resource. +// +// Deprecated: Use +// fmt.Sprintf("inspect/results/%s", result) +// instead. +func ResultPath(result string) string { + return "" + + "inspect/results/" + + result + + "" +} + +// ErrorStatsProjectPath returns the path for the project resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s", project) +// instead. +func ErrorStatsProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} + +// ReportErrorsProjectPath returns the path for the project resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s", project) +// instead. +func ReportErrorsProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} diff --git a/vendor/cloud.google.com/go/errorreporting/apiv1beta1/report_errors_client.go b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/report_errors_client.go new file mode 100644 index 00000000..fa16976c --- /dev/null +++ b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/report_errors_client.go @@ -0,0 +1,124 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package errorreporting + +import ( + "context" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + clouderrorreportingpb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +// ReportErrorsCallOptions contains the retry settings for each method of ReportErrorsClient. +type ReportErrorsCallOptions struct { + ReportErrorEvent []gax.CallOption +} + +func defaultReportErrorsClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("clouderrorreporting.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultReportErrorsCallOptions() *ReportErrorsCallOptions { + retry := map[[2]string][]gax.CallOption{} + return &ReportErrorsCallOptions{ + ReportErrorEvent: retry[[2]string{"default", "non_idempotent"}], + } +} + +// ReportErrorsClient is a client for interacting with Stackdriver Error Reporting API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type ReportErrorsClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + reportErrorsClient clouderrorreportingpb.ReportErrorsServiceClient + + // The call options for this service. + CallOptions *ReportErrorsCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewReportErrorsClient creates a new report errors service client. +// +// An API for reporting error events. +func NewReportErrorsClient(ctx context.Context, opts ...option.ClientOption) (*ReportErrorsClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultReportErrorsClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &ReportErrorsClient{ + conn: conn, + CallOptions: defaultReportErrorsCallOptions(), + + reportErrorsClient: clouderrorreportingpb.NewReportErrorsServiceClient(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *ReportErrorsClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *ReportErrorsClient) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *ReportErrorsClient) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ReportErrorEvent report an individual error event. +// +// This endpoint accepts either an OAuth token, +// or an +// API key +// for authentication. To use an API key, append it to the URL as the value of +// a key parameter. For example:
POST https://clouderrorreporting.googleapis.com/v1beta1/projects/example-project/events:report?key=123ABC456
+func (c *ReportErrorsClient) ReportErrorEvent(ctx context.Context, req *clouderrorreportingpb.ReportErrorEventRequest, opts ...gax.CallOption) (*clouderrorreportingpb.ReportErrorEventResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ReportErrorEvent[0:len(c.CallOptions.ReportErrorEvent):len(c.CallOptions.ReportErrorEvent)], opts...) + var resp *clouderrorreportingpb.ReportErrorEventResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.reportErrorsClient.ReportErrorEvent(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/errorreporting/apiv1beta1/report_errors_client_example_test.go b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/report_errors_client_example_test.go new file mode 100644 index 00000000..eb1db097 --- /dev/null +++ b/vendor/cloud.google.com/go/errorreporting/apiv1beta1/report_errors_client_example_test.go @@ -0,0 +1,52 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package errorreporting_test + +import ( + "context" + + errorreporting "cloud.google.com/go/errorreporting/apiv1beta1" + clouderrorreportingpb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" +) + +func ExampleNewReportErrorsClient() { + ctx := context.Background() + c, err := errorreporting.NewReportErrorsClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleReportErrorsClient_ReportErrorEvent() { + ctx := context.Background() + c, err := errorreporting.NewReportErrorsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &clouderrorreportingpb.ReportErrorEventRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ReportErrorEvent(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/errorreporting/errors.go b/vendor/cloud.google.com/go/errorreporting/errors.go new file mode 100644 index 00000000..1a470579 --- /dev/null +++ b/vendor/cloud.google.com/go/errorreporting/errors.go @@ -0,0 +1,231 @@ +// Copyright 2016 Google LLC +// +// 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 errorreporting is a Google Stackdriver Error Reporting library. +// +// This package is still experimental and subject to change. +// +// See https://cloud.google.com/error-reporting/ for more information. +package errorreporting // import "cloud.google.com/go/errorreporting" + +import ( + "bytes" + "context" + "fmt" + "log" + "net/http" + "runtime" + "time" + + vkit "cloud.google.com/go/errorreporting/apiv1beta1" + "cloud.google.com/go/internal/version" + "github.com/golang/protobuf/ptypes" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/support/bundler" + pb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" +) + +const ( + userAgent = `gcloud-golang-errorreporting/20160701` +) + +// Config is additional configuration for Client. +type Config struct { + // ServiceName identifies the running program and is included in the error reports. + // Optional. + ServiceName string + + // ServiceVersion identifies the version of the running program and is + // included in the error reports. + // Optional. + ServiceVersion string + + // OnError is the function to call if any background + // tasks errored. By default, errors are logged. + OnError func(err error) +} + +// Entry holds information about the reported error. +type Entry struct { + Error error + Req *http.Request // if error is associated with a request. + User string // an identifier for the user affected by the error + Stack []byte // if user does not provide a stack trace, runtime.Stack will be called +} + +// Client represents a Google Cloud Error Reporting client. +type Client struct { + projectName string + apiClient client + serviceContext *pb.ServiceContext + bundler *bundler.Bundler + + onErrorFn func(err error) +} + +var newClient = func(ctx context.Context, opts ...option.ClientOption) (client, error) { + client, err := vkit.NewReportErrorsClient(ctx, opts...) + if err != nil { + return nil, err + } + client.SetGoogleClientInfo("gccl", version.Repo) + return client, nil +} + +// NewClient returns a new error reporting client. Generally you will want +// to create a client on program initialization and use it through the lifetime +// of the process. +func NewClient(ctx context.Context, projectID string, cfg Config, opts ...option.ClientOption) (*Client, error) { + if cfg.ServiceName == "" { + cfg.ServiceName = "goapp" + } + c, err := newClient(ctx, opts...) + if err != nil { + return nil, fmt.Errorf("creating client: %v", err) + } + + client := &Client{ + apiClient: c, + projectName: "projects/" + projectID, + serviceContext: &pb.ServiceContext{ + Service: cfg.ServiceName, + Version: cfg.ServiceVersion, + }, + onErrorFn: cfg.OnError, + } + bundler := bundler.NewBundler((*pb.ReportErrorEventRequest)(nil), func(bundle interface{}) { + reqs := bundle.([]*pb.ReportErrorEventRequest) + for _, req := range reqs { + _, err = client.apiClient.ReportErrorEvent(ctx, req) + if err != nil { + client.onError(err) + } + } + }) + // TODO(jbd): Optimize bundler limits. + bundler.DelayThreshold = 2 * time.Second + bundler.BundleCountThreshold = 100 + bundler.BundleByteThreshold = 1000 + bundler.BundleByteLimit = 1000 + bundler.BufferedByteLimit = 10000 + client.bundler = bundler + return client, nil +} + +func (c *Client) onError(err error) { + if c.onErrorFn != nil { + c.onErrorFn(err) + return + } + log.Println(err) +} + +// Close calls Flush, then closes any resources held by the client. +// Close should be called when the client is no longer needed. +func (c *Client) Close() error { + c.Flush() + return c.apiClient.Close() +} + +// Report writes an error report. It doesn't block. Errors in +// writing the error report can be handled via Config.OnError. +func (c *Client) Report(e Entry) { + c.bundler.Add(c.newRequest(e), 1) +} + +// ReportSync writes an error report. It blocks until the entry is written. +func (c *Client) ReportSync(ctx context.Context, e Entry) error { + _, err := c.apiClient.ReportErrorEvent(ctx, c.newRequest(e)) + return err +} + +// Flush blocks until all currently buffered error reports are sent. +// +// If any errors occurred since the last call to Flush, or the +// creation of the client if this is the first call, then Flush reports the +// error via the Config.OnError handler. +func (c *Client) Flush() { + c.bundler.Flush() +} + +func (c *Client) newRequest(e Entry) *pb.ReportErrorEventRequest { + var stack string + if e.Stack != nil { + stack = string(e.Stack) + } else { + // limit the stack trace to 16k. + var buf [16 * 1024]byte + stack = chopStack(buf[0:runtime.Stack(buf[:], false)]) + } + message := e.Error.Error() + "\n" + stack + + var errorContext *pb.ErrorContext + if r := e.Req; r != nil { + errorContext = &pb.ErrorContext{ + HttpRequest: &pb.HttpRequestContext{ + Method: r.Method, + Url: r.Host + r.RequestURI, + UserAgent: r.UserAgent(), + Referrer: r.Referer(), + RemoteIp: r.RemoteAddr, + }, + } + } + if e.User != "" { + if errorContext == nil { + errorContext = &pb.ErrorContext{} + } + errorContext.User = e.User + } + return &pb.ReportErrorEventRequest{ + ProjectName: c.projectName, + Event: &pb.ReportedErrorEvent{ + EventTime: ptypes.TimestampNow(), + ServiceContext: c.serviceContext, + Message: message, + Context: errorContext, + }, + } +} + +// chopStack trims a stack trace so that the function which panics or calls +// Report is first. +func chopStack(s []byte) string { + f := []byte("cloud.google.com/go/errorreporting.(*Client).Report") + + lfFirst := bytes.IndexByte(s, '\n') + if lfFirst == -1 { + return string(s) + } + stack := s[lfFirst:] + panicLine := bytes.Index(stack, f) + if panicLine == -1 { + return string(s) + } + stack = stack[panicLine+1:] + for i := 0; i < 2; i++ { + nextLine := bytes.IndexByte(stack, '\n') + if nextLine == -1 { + return string(s) + } + stack = stack[nextLine+1:] + } + return string(s[:lfFirst+1]) + string(stack) +} + +type client interface { + ReportErrorEvent(ctx context.Context, req *pb.ReportErrorEventRequest, opts ...gax.CallOption) (*pb.ReportErrorEventResponse, error) + Close() error +} diff --git a/vendor/cloud.google.com/go/errorreporting/errors_test.go b/vendor/cloud.google.com/go/errorreporting/errors_test.go new file mode 100644 index 00000000..29a7adb8 --- /dev/null +++ b/vendor/cloud.google.com/go/errorreporting/errors_test.go @@ -0,0 +1,175 @@ +// Copyright 2016 Google LLC +// +// 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 errorreporting + +import ( + "context" + "errors" + "strings" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + pb "google.golang.org/genproto/googleapis/devtools/clouderrorreporting/v1beta1" +) + +type fakeReportErrorsClient struct { + req *pb.ReportErrorEventRequest + fail bool + doneCh chan struct{} +} + +func (c *fakeReportErrorsClient) ReportErrorEvent(ctx context.Context, req *pb.ReportErrorEventRequest, _ ...gax.CallOption) (*pb.ReportErrorEventResponse, error) { + defer close(c.doneCh) + if c.fail { + return nil, errors.New("request failed") + } + c.req = req + return &pb.ReportErrorEventResponse{}, nil +} + +func (c *fakeReportErrorsClient) Close() error { + return nil +} + +var defaultConfig = Config{ + ServiceName: "myservice", + ServiceVersion: "v1.0", +} + +func newFakeReportErrorsClient() *fakeReportErrorsClient { + c := &fakeReportErrorsClient{} + c.doneCh = make(chan struct{}) + return c +} + +func newTestClient(c *fakeReportErrorsClient, cfg Config) *Client { + newClient = func(ctx context.Context, opts ...option.ClientOption) (client, error) { + return c, nil + } + t, err := NewClient(context.Background(), testutil.ProjID(), cfg) + if err != nil { + panic(err) + } + return t +} + +func commonChecks(t *testing.T, req *pb.ReportErrorEventRequest, fn string) { + if req.Event.ServiceContext.Service != "myservice" { + t.Errorf("error report didn't contain service name") + } + if req.Event.ServiceContext.Version != "v1.0" { + t.Errorf("error report didn't contain version name") + } + if !strings.Contains(req.Event.Message, "error") { + t.Errorf("error report didn't contain message") + } + if !strings.Contains(req.Event.Message, fn) { + t.Errorf("error report didn't contain stack trace") + } + if got, want := req.Event.Context.User, "user"; got != want { + t.Errorf("got %q, want %q", got, want) + } +} + +func TestReport(t *testing.T) { + fc := newFakeReportErrorsClient() + c := newTestClient(fc, defaultConfig) + c.Report(Entry{Error: errors.New("error"), User: "user"}) + c.Flush() + <-fc.doneCh + r := fc.req + if r == nil { + t.Fatalf("got no error report, expected one") + } + commonChecks(t, r, "errorreporting.TestReport") +} + +func TestReportSync(t *testing.T) { + ctx := context.Background() + fc := newFakeReportErrorsClient() + c := newTestClient(fc, defaultConfig) + if err := c.ReportSync(ctx, Entry{Error: errors.New("error"), User: "user"}); err != nil { + t.Fatalf("cannot upload errors: %v", err) + } + + <-fc.doneCh + r := fc.req + if r == nil { + t.Fatalf("got no error report, expected one") + } + commonChecks(t, r, "errorreporting.TestReport") +} + +func TestOnError(t *testing.T) { + fc := newFakeReportErrorsClient() + fc.fail = true + cfg := defaultConfig + errc := make(chan error, 1) + cfg.OnError = func(err error) { errc <- err } + c := newTestClient(fc, cfg) + c.Report(Entry{Error: errors.New("error")}) + c.Flush() + <-fc.doneCh + select { + case err := <-errc: + if err == nil { + t.Error("got nil, want error") + } + case <-time.After(5 * time.Second): + t.Error("timeout") + } +} + +func TestChopStack(t *testing.T) { + for _, test := range []struct { + name string + in []byte + expected string + }{ + { + name: "Report", + in: []byte(` goroutine 39 [running]: +runtime/debug.Stack() + /gopath/runtime/debug/stack.go:24 +0x79 +cloud.google.com/go/errorreporting.(*Client).logInternal() + /gopath/cloud.google.com/go/errorreporting/errors.go:259 +0x18b +cloud.google.com/go/errorreporting.(*Client).Report() + /gopath/cloud.google.com/go/errorreporting/errors.go:248 +0x4ed +cloud.google.com/go/errorreporting.TestReport() + /gopath/cloud.google.com/go/errorreporting/errors_test.go:137 +0x2a1 +testing.tRunner() + /gopath/testing/testing.go:610 +0x81 +created by testing.(*T).Run + /gopath/testing/testing.go:646 +0x2ec +`), + expected: ` goroutine 39 [running]: +cloud.google.com/go/errorreporting.TestReport() + /gopath/cloud.google.com/go/errorreporting/errors_test.go:137 +0x2a1 +testing.tRunner() + /gopath/testing/testing.go:610 +0x81 +created by testing.(*T).Run + /gopath/testing/testing.go:646 +0x2ec +`, + }, + } { + out := chopStack(test.in) + if out != test.expected { + t.Errorf("case %q: chopStack(%q): got %q want %q", test.name, test.in, out, test.expected) + } + } +} diff --git a/vendor/cloud.google.com/go/errorreporting/example_test.go b/vendor/cloud.google.com/go/errorreporting/example_test.go new file mode 100644 index 00000000..f06c36b8 --- /dev/null +++ b/vendor/cloud.google.com/go/errorreporting/example_test.go @@ -0,0 +1,52 @@ +// Copyright 2017 Google LLC +// +// 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 errorreporting_test + +import ( + "context" + "errors" + "log" + + "cloud.google.com/go/errorreporting" +) + +func Example() { + // Create the client. + ctx := context.Background() + ec, err := errorreporting.NewClient(ctx, "my-gcp-project", errorreporting.Config{ + ServiceName: "myservice", + ServiceVersion: "v1.0", + }) + if err != nil { + // TODO: handle error + } + defer func() { + if err := ec.Close(); err != nil { + log.Printf("failed to report errors to Stackdriver: %v", err) + } + }() + + // Report an error. + err = doSomething() + if err != nil { + ec.Report(errorreporting.Entry{ + Error: err, + }) + } +} + +func doSomething() error { + return errors.New("something went wrong") +} diff --git a/vendor/cloud.google.com/go/examples_test.go b/vendor/cloud.google.com/go/examples_test.go new file mode 100644 index 00000000..c623ba9d --- /dev/null +++ b/vendor/cloud.google.com/go/examples_test.go @@ -0,0 +1,60 @@ +// Copyright 2018 Google LLC +// +// 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 cloud_test + +import ( + "context" + "time" + + "cloud.google.com/go/bigquery" +) + +// To set a timeout for an RPC, use context.WithTimeout. +func Example_timeout() { + ctx := context.Background() + // Do not set a timeout on the context passed to NewClient: dialing happens + // asynchronously, and the context is used to refresh credentials in the + // background. + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: handle error. + } + // Time out if it takes more than 10 seconds to create a dataset. + tctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() // Always call cancel. + + if err := client.Dataset("new-dataset").Create(tctx, nil); err != nil { + // TODO: handle error. + } +} + +// To arrange for an RPC to be canceled, use context.WithCancel. +func Example_cancellation() { + ctx := context.Background() + // Do not cancel the context passed to NewClient: dialing happens asynchronously, + // and the context is used to refresh credentials in the background. + client, err := bigquery.NewClient(ctx, "project-id") + if err != nil { + // TODO: handle error. + } + cctx, cancel := context.WithCancel(ctx) + defer cancel() // Always call cancel. + + // TODO: Make the cancel function available to whatever might want to cancel the + // call--perhaps a GUI button. + if err := client.Dataset("new-dataset").Create(cctx, nil); err != nil { + // TODO: handle error. + } +} diff --git a/vendor/cloud.google.com/go/expr/apiv1alpha1/cel_client.go b/vendor/cloud.google.com/go/expr/apiv1alpha1/cel_client.go new file mode 100644 index 00000000..fedeccb4 --- /dev/null +++ b/vendor/cloud.google.com/go/expr/apiv1alpha1/cel_client.go @@ -0,0 +1,160 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package expr + +import ( + "context" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +// CelCallOptions contains the retry settings for each method of CelClient. +type CelCallOptions struct { + Parse []gax.CallOption + Check []gax.CallOption + Eval []gax.CallOption +} + +func defaultCelClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("cel.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCelCallOptions() *CelCallOptions { + retry := map[[2]string][]gax.CallOption{} + return &CelCallOptions{ + Parse: retry[[2]string{"default", "non_idempotent"}], + Check: retry[[2]string{"default", "non_idempotent"}], + Eval: retry[[2]string{"default", "non_idempotent"}], + } +} + +// CelClient is a client for interacting with Common Expression Language. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type CelClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + celClient exprpb.CelServiceClient + + // The call options for this service. + CallOptions *CelCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewCelClient creates a new cel service client. +// +// Access a CEL implementation from another process or machine. +// A CEL implementation is decomposed as a parser, a static checker, +// and an evaluator. Every CEL implementation is expected to provide +// a server for this API. The API will be used for conformance testing, +// utilities, and execution as a service. +func NewCelClient(ctx context.Context, opts ...option.ClientOption) (*CelClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultCelClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &CelClient{ + conn: conn, + CallOptions: defaultCelCallOptions(), + + celClient: exprpb.NewCelServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *CelClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *CelClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *CelClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Parse transforms CEL source text into a parsed representation. +func (c *CelClient) Parse(ctx context.Context, req *exprpb.ParseRequest, opts ...gax.CallOption) (*exprpb.ParseResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Parse[0:len(c.CallOptions.Parse):len(c.CallOptions.Parse)], opts...) + var resp *exprpb.ParseResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.celClient.Parse(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Check runs static checks on a parsed CEL representation and return +// an annotated representation, or a set of issues. +func (c *CelClient) Check(ctx context.Context, req *exprpb.CheckRequest, opts ...gax.CallOption) (*exprpb.CheckResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Check[0:len(c.CallOptions.Check):len(c.CallOptions.Check)], opts...) + var resp *exprpb.CheckResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.celClient.Check(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Eval evaluates a parsed or annotation CEL representation given +// values of external bindings. +func (c *CelClient) Eval(ctx context.Context, req *exprpb.EvalRequest, opts ...gax.CallOption) (*exprpb.EvalResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Eval[0:len(c.CallOptions.Eval):len(c.CallOptions.Eval)], opts...) + var resp *exprpb.EvalResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.celClient.Eval(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/expr/apiv1alpha1/cel_client_example_test.go b/vendor/cloud.google.com/go/expr/apiv1alpha1/cel_client_example_test.go new file mode 100644 index 00000000..598cac19 --- /dev/null +++ b/vendor/cloud.google.com/go/expr/apiv1alpha1/cel_client_example_test.go @@ -0,0 +1,88 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package expr_test + +import ( + "context" + + expr "cloud.google.com/go/expr/apiv1alpha1" + exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" +) + +func ExampleNewCelClient() { + ctx := context.Background() + c, err := expr.NewCelClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleCelClient_Parse() { + ctx := context.Background() + c, err := expr.NewCelClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &exprpb.ParseRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Parse(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleCelClient_Check() { + ctx := context.Background() + c, err := expr.NewCelClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &exprpb.CheckRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Check(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleCelClient_Eval() { + ctx := context.Background() + c, err := expr.NewCelClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &exprpb.EvalRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Eval(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/expr/apiv1alpha1/conformance_client.go b/vendor/cloud.google.com/go/expr/apiv1alpha1/conformance_client.go new file mode 100644 index 00000000..05acb821 --- /dev/null +++ b/vendor/cloud.google.com/go/expr/apiv1alpha1/conformance_client.go @@ -0,0 +1,160 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package expr + +import ( + "context" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +// ConformanceCallOptions contains the retry settings for each method of ConformanceClient. +type ConformanceCallOptions struct { + Parse []gax.CallOption + Check []gax.CallOption + Eval []gax.CallOption +} + +func defaultConformanceClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("cel.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultConformanceCallOptions() *ConformanceCallOptions { + retry := map[[2]string][]gax.CallOption{} + return &ConformanceCallOptions{ + Parse: retry[[2]string{"default", "non_idempotent"}], + Check: retry[[2]string{"default", "non_idempotent"}], + Eval: retry[[2]string{"default", "non_idempotent"}], + } +} + +// ConformanceClient is a client for interacting with Common Expression Language. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type ConformanceClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + conformanceClient exprpb.ConformanceServiceClient + + // The call options for this service. + CallOptions *ConformanceCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewConformanceClient creates a new conformance service client. +// +// Access a CEL implementation from another process or machine. +// A CEL implementation is decomposed as a parser, a static checker, +// and an evaluator. Every CEL implementation is expected to provide +// a server for this API. The API will be used for conformance testing +// and other utilities. +func NewConformanceClient(ctx context.Context, opts ...option.ClientOption) (*ConformanceClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultConformanceClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &ConformanceClient{ + conn: conn, + CallOptions: defaultConformanceCallOptions(), + + conformanceClient: exprpb.NewConformanceServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *ConformanceClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *ConformanceClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *ConformanceClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Parse transforms CEL source text into a parsed representation. +func (c *ConformanceClient) Parse(ctx context.Context, req *exprpb.ParseRequest, opts ...gax.CallOption) (*exprpb.ParseResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Parse[0:len(c.CallOptions.Parse):len(c.CallOptions.Parse)], opts...) + var resp *exprpb.ParseResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.conformanceClient.Parse(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Check runs static checks on a parsed CEL representation and return +// an annotated representation, or a set of issues. +func (c *ConformanceClient) Check(ctx context.Context, req *exprpb.CheckRequest, opts ...gax.CallOption) (*exprpb.CheckResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Check[0:len(c.CallOptions.Check):len(c.CallOptions.Check)], opts...) + var resp *exprpb.CheckResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.conformanceClient.Check(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Eval evaluates a parsed or annotation CEL representation given +// values of external bindings. +func (c *ConformanceClient) Eval(ctx context.Context, req *exprpb.EvalRequest, opts ...gax.CallOption) (*exprpb.EvalResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Eval[0:len(c.CallOptions.Eval):len(c.CallOptions.Eval)], opts...) + var resp *exprpb.EvalResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.conformanceClient.Eval(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/expr/apiv1alpha1/conformance_client_example_test.go b/vendor/cloud.google.com/go/expr/apiv1alpha1/conformance_client_example_test.go new file mode 100644 index 00000000..2f33942b --- /dev/null +++ b/vendor/cloud.google.com/go/expr/apiv1alpha1/conformance_client_example_test.go @@ -0,0 +1,88 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package expr_test + +import ( + "context" + + expr "cloud.google.com/go/expr/apiv1alpha1" + exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" +) + +func ExampleNewConformanceClient() { + ctx := context.Background() + c, err := expr.NewConformanceClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleConformanceClient_Parse() { + ctx := context.Background() + c, err := expr.NewConformanceClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &exprpb.ParseRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Parse(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleConformanceClient_Check() { + ctx := context.Background() + c, err := expr.NewConformanceClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &exprpb.CheckRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Check(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleConformanceClient_Eval() { + ctx := context.Background() + c, err := expr.NewConformanceClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &exprpb.EvalRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Eval(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/expr/apiv1alpha1/doc.go b/vendor/cloud.google.com/go/expr/apiv1alpha1/doc.go new file mode 100644 index 00000000..6d9588c8 --- /dev/null +++ b/vendor/cloud.google.com/go/expr/apiv1alpha1/doc.go @@ -0,0 +1,87 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package expr is an auto-generated package for the +// Common Expression Language. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Defines common types for the Common Expression Language. +package expr // import "cloud.google.com/go/expr/apiv1alpha1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{} +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/expr/apiv1alpha1/mock_test.go b/vendor/cloud.google.com/go/expr/apiv1alpha1/mock_test.go new file mode 100644 index 00000000..6b402ae1 --- /dev/null +++ b/vendor/cloud.google.com/go/expr/apiv1alpha1/mock_test.go @@ -0,0 +1,504 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package expr + +import ( + exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockConformanceServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + exprpb.ConformanceServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockConformanceServer) Parse(ctx context.Context, req *exprpb.ParseRequest) (*exprpb.ParseResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*exprpb.ParseResponse), nil +} + +func (s *mockConformanceServer) Check(ctx context.Context, req *exprpb.CheckRequest) (*exprpb.CheckResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*exprpb.CheckResponse), nil +} + +func (s *mockConformanceServer) Eval(ctx context.Context, req *exprpb.EvalRequest) (*exprpb.EvalResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*exprpb.EvalResponse), nil +} + +type mockCelServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + exprpb.CelServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockCelServer) Parse(ctx context.Context, req *exprpb.ParseRequest) (*exprpb.ParseResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*exprpb.ParseResponse), nil +} + +func (s *mockCelServer) Check(ctx context.Context, req *exprpb.CheckRequest) (*exprpb.CheckResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*exprpb.CheckResponse), nil +} + +func (s *mockCelServer) Eval(ctx context.Context, req *exprpb.EvalRequest) (*exprpb.EvalResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*exprpb.EvalResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockConformance mockConformanceServer + mockCel mockCelServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + exprpb.RegisterConformanceServiceServer(serv, &mockConformance) + exprpb.RegisterCelServiceServer(serv, &mockCel) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestConformanceServiceParse(t *testing.T) { + var expectedResponse *exprpb.ParseResponse = &exprpb.ParseResponse{} + + mockConformance.err = nil + mockConformance.reqs = nil + + mockConformance.resps = append(mockConformance.resps[:0], expectedResponse) + + var celSource string = "celSource912645552" + var request = &exprpb.ParseRequest{ + CelSource: celSource, + } + + c, err := NewConformanceClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Parse(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockConformance.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestConformanceServiceParseError(t *testing.T) { + errCode := codes.PermissionDenied + mockConformance.err = gstatus.Error(errCode, "test error") + + var celSource string = "celSource912645552" + var request = &exprpb.ParseRequest{ + CelSource: celSource, + } + + c, err := NewConformanceClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Parse(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestConformanceServiceCheck(t *testing.T) { + var expectedResponse *exprpb.CheckResponse = &exprpb.CheckResponse{} + + mockConformance.err = nil + mockConformance.reqs = nil + + mockConformance.resps = append(mockConformance.resps[:0], expectedResponse) + + var parsedExpr *exprpb.ParsedExpr = &exprpb.ParsedExpr{} + var request = &exprpb.CheckRequest{ + ParsedExpr: parsedExpr, + } + + c, err := NewConformanceClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Check(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockConformance.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestConformanceServiceCheckError(t *testing.T) { + errCode := codes.PermissionDenied + mockConformance.err = gstatus.Error(errCode, "test error") + + var parsedExpr *exprpb.ParsedExpr = &exprpb.ParsedExpr{} + var request = &exprpb.CheckRequest{ + ParsedExpr: parsedExpr, + } + + c, err := NewConformanceClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Check(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestConformanceServiceEval(t *testing.T) { + var expectedResponse *exprpb.EvalResponse = &exprpb.EvalResponse{} + + mockConformance.err = nil + mockConformance.reqs = nil + + mockConformance.resps = append(mockConformance.resps[:0], expectedResponse) + + var request *exprpb.EvalRequest = &exprpb.EvalRequest{} + + c, err := NewConformanceClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Eval(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockConformance.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestConformanceServiceEvalError(t *testing.T) { + errCode := codes.PermissionDenied + mockConformance.err = gstatus.Error(errCode, "test error") + + var request *exprpb.EvalRequest = &exprpb.EvalRequest{} + + c, err := NewConformanceClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Eval(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCelServiceParse(t *testing.T) { + var expectedResponse *exprpb.ParseResponse = &exprpb.ParseResponse{} + + mockCel.err = nil + mockCel.reqs = nil + + mockCel.resps = append(mockCel.resps[:0], expectedResponse) + + var celSource string = "celSource912645552" + var request = &exprpb.ParseRequest{ + CelSource: celSource, + } + + c, err := NewCelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Parse(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCel.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCelServiceParseError(t *testing.T) { + errCode := codes.PermissionDenied + mockCel.err = gstatus.Error(errCode, "test error") + + var celSource string = "celSource912645552" + var request = &exprpb.ParseRequest{ + CelSource: celSource, + } + + c, err := NewCelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Parse(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCelServiceCheck(t *testing.T) { + var expectedResponse *exprpb.CheckResponse = &exprpb.CheckResponse{} + + mockCel.err = nil + mockCel.reqs = nil + + mockCel.resps = append(mockCel.resps[:0], expectedResponse) + + var parsedExpr *exprpb.ParsedExpr = &exprpb.ParsedExpr{} + var request = &exprpb.CheckRequest{ + ParsedExpr: parsedExpr, + } + + c, err := NewCelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Check(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCel.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCelServiceCheckError(t *testing.T) { + errCode := codes.PermissionDenied + mockCel.err = gstatus.Error(errCode, "test error") + + var parsedExpr *exprpb.ParsedExpr = &exprpb.ParsedExpr{} + var request = &exprpb.CheckRequest{ + ParsedExpr: parsedExpr, + } + + c, err := NewCelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Check(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCelServiceEval(t *testing.T) { + var expectedResponse *exprpb.EvalResponse = &exprpb.EvalResponse{} + + mockCel.err = nil + mockCel.reqs = nil + + mockCel.resps = append(mockCel.resps[:0], expectedResponse) + + var request *exprpb.EvalRequest = &exprpb.EvalRequest{} + + c, err := NewCelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Eval(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCel.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCelServiceEvalError(t *testing.T) { + errCode := codes.PermissionDenied + mockCel.err = gstatus.Error(errCode, "test error") + + var request *exprpb.EvalRequest = &exprpb.EvalRequest{} + + c, err := NewCelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Eval(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/firestore/Makefile b/vendor/cloud.google.com/go/firestore/Makefile new file mode 100644 index 00000000..b1f9ff79 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/Makefile @@ -0,0 +1,13 @@ +# Copy textproto files in this directory from the source of truth. + +SRC=$(GOPATH)/src/github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore + +.PHONY: refresh-tests + +refresh-tests: + -rm genproto/*.pb.go + cp $(SRC)/genproto/*.pb.go genproto + -rm testdata/*.textproto + cp $(SRC)/testdata/*.textproto testdata + openssl dgst -sha1 $(SRC)/testdata/test-suite.binproto > testdata/VERSION + diff --git a/vendor/cloud.google.com/go/firestore/apiv1beta1/doc.go b/vendor/cloud.google.com/go/firestore/apiv1beta1/doc.go new file mode 100644 index 00000000..a3a68a24 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/apiv1beta1/doc.go @@ -0,0 +1,91 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package firestore is an auto-generated package for the +// Google Cloud Firestore API. +// +// NOTE: This package is in beta. It is not stable, and may be subject to changes. +// +// +// Use the client at cloud.google.com/go/firestore in preference to this. +package firestore // import "cloud.google.com/go/firestore/apiv1beta1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/datastore", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/firestore/apiv1beta1/firestore_client.go b/vendor/cloud.google.com/go/firestore/apiv1beta1/firestore_client.go new file mode 100644 index 00000000..24404e2c --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/apiv1beta1/firestore_client.go @@ -0,0 +1,503 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package firestore + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + firestorepb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + GetDocument []gax.CallOption + ListDocuments []gax.CallOption + CreateDocument []gax.CallOption + UpdateDocument []gax.CallOption + DeleteDocument []gax.CallOption + BatchGetDocuments []gax.CallOption + BeginTransaction []gax.CallOption + Commit []gax.CallOption + Rollback []gax.CallOption + RunQuery []gax.CallOption + Write []gax.CallOption + Listen []gax.CallOption + ListCollectionIds []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("firestore.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + {"streaming", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + GetDocument: retry[[2]string{"default", "idempotent"}], + ListDocuments: retry[[2]string{"default", "idempotent"}], + CreateDocument: retry[[2]string{"default", "non_idempotent"}], + UpdateDocument: retry[[2]string{"default", "non_idempotent"}], + DeleteDocument: retry[[2]string{"default", "idempotent"}], + BatchGetDocuments: retry[[2]string{"streaming", "idempotent"}], + BeginTransaction: retry[[2]string{"default", "idempotent"}], + Commit: retry[[2]string{"default", "non_idempotent"}], + Rollback: retry[[2]string{"default", "idempotent"}], + RunQuery: retry[[2]string{"streaming", "idempotent"}], + Write: retry[[2]string{"streaming", "non_idempotent"}], + Listen: retry[[2]string{"streaming", "idempotent"}], + ListCollectionIds: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Google Cloud Firestore API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client firestorepb.FirestoreClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new firestore client. +// +// The Cloud Firestore service. +// +// This service exposes several types of comparable timestamps: +// +// create_time - The time at which a document was created. Changes only +// when a document is deleted, then re-created. Increases in a strict +// monotonic fashion. +// +// update_time - The time at which a document was last updated. Changes +// every time a document is modified. Does not change when a write results +// in no modifications. Increases in a strict monotonic fashion. +// +// read_time - The time at which a particular state was observed. Used +// to denote a consistent snapshot of the database or the time at which a +// Document was observed to not exist. +// +// commit_time - The time at which the writes in a transaction were +// committed. Any read with an equal or greater read_time is guaranteed +// to see the effects of the transaction. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: firestorepb.NewFirestoreClient(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// GetDocument gets a single document. +func (c *Client) GetDocument(ctx context.Context, req *firestorepb.GetDocumentRequest, opts ...gax.CallOption) (*firestorepb.Document, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetDocument[0:len(c.CallOptions.GetDocument):len(c.CallOptions.GetDocument)], opts...) + var resp *firestorepb.Document + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetDocument(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListDocuments lists documents. +func (c *Client) ListDocuments(ctx context.Context, req *firestorepb.ListDocumentsRequest, opts ...gax.CallOption) *DocumentIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListDocuments[0:len(c.CallOptions.ListDocuments):len(c.CallOptions.ListDocuments)], opts...) + it := &DocumentIterator{} + req = proto.Clone(req).(*firestorepb.ListDocumentsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*firestorepb.Document, string, error) { + var resp *firestorepb.ListDocumentsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListDocuments(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Documents, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// CreateDocument creates a new document. +func (c *Client) CreateDocument(ctx context.Context, req *firestorepb.CreateDocumentRequest, opts ...gax.CallOption) (*firestorepb.Document, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateDocument[0:len(c.CallOptions.CreateDocument):len(c.CallOptions.CreateDocument)], opts...) + var resp *firestorepb.Document + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateDocument(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateDocument updates or inserts a document. +func (c *Client) UpdateDocument(ctx context.Context, req *firestorepb.UpdateDocumentRequest, opts ...gax.CallOption) (*firestorepb.Document, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateDocument[0:len(c.CallOptions.UpdateDocument):len(c.CallOptions.UpdateDocument)], opts...) + var resp *firestorepb.Document + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateDocument(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteDocument deletes a document. +func (c *Client) DeleteDocument(ctx context.Context, req *firestorepb.DeleteDocumentRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteDocument[0:len(c.CallOptions.DeleteDocument):len(c.CallOptions.DeleteDocument)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteDocument(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// BatchGetDocuments gets multiple documents. +// +// Documents returned by this method are not guaranteed to be returned in the +// same order that they were requested. +func (c *Client) BatchGetDocuments(ctx context.Context, req *firestorepb.BatchGetDocumentsRequest, opts ...gax.CallOption) (firestorepb.Firestore_BatchGetDocumentsClient, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchGetDocuments[0:len(c.CallOptions.BatchGetDocuments):len(c.CallOptions.BatchGetDocuments)], opts...) + var resp firestorepb.Firestore_BatchGetDocumentsClient + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.BatchGetDocuments(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// BeginTransaction starts a new transaction. +func (c *Client) BeginTransaction(ctx context.Context, req *firestorepb.BeginTransactionRequest, opts ...gax.CallOption) (*firestorepb.BeginTransactionResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BeginTransaction[0:len(c.CallOptions.BeginTransaction):len(c.CallOptions.BeginTransaction)], opts...) + var resp *firestorepb.BeginTransactionResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.BeginTransaction(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Commit commits a transaction, while optionally updating documents. +func (c *Client) Commit(ctx context.Context, req *firestorepb.CommitRequest, opts ...gax.CallOption) (*firestorepb.CommitResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Commit[0:len(c.CallOptions.Commit):len(c.CallOptions.Commit)], opts...) + var resp *firestorepb.CommitResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.Commit(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Rollback rolls back a transaction. +func (c *Client) Rollback(ctx context.Context, req *firestorepb.RollbackRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Rollback[0:len(c.CallOptions.Rollback):len(c.CallOptions.Rollback)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.Rollback(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// RunQuery runs a query. +func (c *Client) RunQuery(ctx context.Context, req *firestorepb.RunQueryRequest, opts ...gax.CallOption) (firestorepb.Firestore_RunQueryClient, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.RunQuery[0:len(c.CallOptions.RunQuery):len(c.CallOptions.RunQuery)], opts...) + var resp firestorepb.Firestore_RunQueryClient + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.RunQuery(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Write streams batches of document updates and deletes, in order. +func (c *Client) Write(ctx context.Context, opts ...gax.CallOption) (firestorepb.Firestore_WriteClient, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Write[0:len(c.CallOptions.Write):len(c.CallOptions.Write)], opts...) + var resp firestorepb.Firestore_WriteClient + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.Write(ctx, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Listen listens to changes. +func (c *Client) Listen(ctx context.Context, opts ...gax.CallOption) (firestorepb.Firestore_ListenClient, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Listen[0:len(c.CallOptions.Listen):len(c.CallOptions.Listen)], opts...) + var resp firestorepb.Firestore_ListenClient + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.Listen(ctx, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListCollectionIds lists all the collection IDs underneath a document. +func (c *Client) ListCollectionIds(ctx context.Context, req *firestorepb.ListCollectionIdsRequest, opts ...gax.CallOption) *StringIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListCollectionIds[0:len(c.CallOptions.ListCollectionIds):len(c.CallOptions.ListCollectionIds)], opts...) + it := &StringIterator{} + req = proto.Clone(req).(*firestorepb.ListCollectionIdsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]string, string, error) { + var resp *firestorepb.ListCollectionIdsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListCollectionIds(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.CollectionIds, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DocumentIterator manages a stream of *firestorepb.Document. +type DocumentIterator struct { + items []*firestorepb.Document + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*firestorepb.Document, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *DocumentIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *DocumentIterator) Next() (*firestorepb.Document, error) { + var item *firestorepb.Document + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *DocumentIterator) bufLen() int { + return len(it.items) +} + +func (it *DocumentIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// StringIterator manages a stream of string. +type StringIterator struct { + items []string + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []string, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *StringIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *StringIterator) Next() (string, error) { + var item string + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *StringIterator) bufLen() int { + return len(it.items) +} + +func (it *StringIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/firestore/apiv1beta1/firestore_client_example_test.go b/vendor/cloud.google.com/go/firestore/apiv1beta1/firestore_client_example_test.go new file mode 100644 index 00000000..78368673 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/apiv1beta1/firestore_client_example_test.go @@ -0,0 +1,328 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package firestore_test + +import ( + "context" + "io" + + firestore "cloud.google.com/go/firestore/apiv1beta1" + "google.golang.org/api/iterator" + firestorepb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_GetDocument() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &firestorepb.GetDocumentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetDocument(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ListDocuments() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &firestorepb.ListDocumentsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListDocuments(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_CreateDocument() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &firestorepb.CreateDocumentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateDocument(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_UpdateDocument() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &firestorepb.UpdateDocumentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateDocument(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_DeleteDocument() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &firestorepb.DeleteDocumentRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteDocument(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_BatchGetDocuments() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &firestorepb.BatchGetDocumentsRequest{ + // TODO: Fill request struct fields. + } + stream, err := c.BatchGetDocuments(ctx, req) + if err != nil { + // TODO: Handle error. + } + for { + resp, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + // TODO: handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_BeginTransaction() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &firestorepb.BeginTransactionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.BeginTransaction(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_Commit() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &firestorepb.CommitRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Commit(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_Rollback() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &firestorepb.RollbackRequest{ + // TODO: Fill request struct fields. + } + err = c.Rollback(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_RunQuery() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &firestorepb.RunQueryRequest{ + // TODO: Fill request struct fields. + } + stream, err := c.RunQuery(ctx, req) + if err != nil { + // TODO: Handle error. + } + for { + resp, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + // TODO: handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_Write() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + stream, err := c.Write(ctx) + if err != nil { + // TODO: Handle error. + } + go func() { + reqs := []*firestorepb.WriteRequest{ + // TODO: Create requests. + } + for _, req := range reqs { + if err := stream.Send(req); err != nil { + // TODO: Handle error. + } + } + stream.CloseSend() + }() + for { + resp, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + // TODO: handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_Listen() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + stream, err := c.Listen(ctx) + if err != nil { + // TODO: Handle error. + } + go func() { + reqs := []*firestorepb.ListenRequest{ + // TODO: Create requests. + } + for _, req := range reqs { + if err := stream.Send(req); err != nil { + // TODO: Handle error. + } + } + stream.CloseSend() + }() + for { + resp, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + // TODO: handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_ListCollectionIds() { + ctx := context.Background() + c, err := firestore.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &firestorepb.ListCollectionIdsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListCollectionIds(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} diff --git a/vendor/cloud.google.com/go/firestore/apiv1beta1/mock_test.go b/vendor/cloud.google.com/go/firestore/apiv1beta1/mock_test.go new file mode 100644 index 00000000..e0fd8297 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/apiv1beta1/mock_test.go @@ -0,0 +1,1153 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package firestore + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + firestorepb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockFirestoreServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + firestorepb.FirestoreServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockFirestoreServer) GetDocument(ctx context.Context, req *firestorepb.GetDocumentRequest) (*firestorepb.Document, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*firestorepb.Document), nil +} + +func (s *mockFirestoreServer) ListDocuments(ctx context.Context, req *firestorepb.ListDocumentsRequest) (*firestorepb.ListDocumentsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*firestorepb.ListDocumentsResponse), nil +} + +func (s *mockFirestoreServer) CreateDocument(ctx context.Context, req *firestorepb.CreateDocumentRequest) (*firestorepb.Document, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*firestorepb.Document), nil +} + +func (s *mockFirestoreServer) UpdateDocument(ctx context.Context, req *firestorepb.UpdateDocumentRequest) (*firestorepb.Document, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*firestorepb.Document), nil +} + +func (s *mockFirestoreServer) DeleteDocument(ctx context.Context, req *firestorepb.DeleteDocumentRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockFirestoreServer) BatchGetDocuments(req *firestorepb.BatchGetDocumentsRequest, stream firestorepb.Firestore_BatchGetDocumentsServer) error { + md, _ := metadata.FromIncomingContext(stream.Context()) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return s.err + } + for _, v := range s.resps { + if err := stream.Send(v.(*firestorepb.BatchGetDocumentsResponse)); err != nil { + return err + } + } + return nil +} + +func (s *mockFirestoreServer) BeginTransaction(ctx context.Context, req *firestorepb.BeginTransactionRequest) (*firestorepb.BeginTransactionResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*firestorepb.BeginTransactionResponse), nil +} + +func (s *mockFirestoreServer) Commit(ctx context.Context, req *firestorepb.CommitRequest) (*firestorepb.CommitResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*firestorepb.CommitResponse), nil +} + +func (s *mockFirestoreServer) Rollback(ctx context.Context, req *firestorepb.RollbackRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockFirestoreServer) RunQuery(req *firestorepb.RunQueryRequest, stream firestorepb.Firestore_RunQueryServer) error { + md, _ := metadata.FromIncomingContext(stream.Context()) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return s.err + } + for _, v := range s.resps { + if err := stream.Send(v.(*firestorepb.RunQueryResponse)); err != nil { + return err + } + } + return nil +} + +func (s *mockFirestoreServer) Write(stream firestorepb.Firestore_WriteServer) error { + md, _ := metadata.FromIncomingContext(stream.Context()) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + for { + if req, err := stream.Recv(); err == io.EOF { + break + } else if err != nil { + return err + } else { + s.reqs = append(s.reqs, req) + } + } + if s.err != nil { + return s.err + } + for _, v := range s.resps { + if err := stream.Send(v.(*firestorepb.WriteResponse)); err != nil { + return err + } + } + return nil +} + +func (s *mockFirestoreServer) Listen(stream firestorepb.Firestore_ListenServer) error { + md, _ := metadata.FromIncomingContext(stream.Context()) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + for { + if req, err := stream.Recv(); err == io.EOF { + break + } else if err != nil { + return err + } else { + s.reqs = append(s.reqs, req) + } + } + if s.err != nil { + return s.err + } + for _, v := range s.resps { + if err := stream.Send(v.(*firestorepb.ListenResponse)); err != nil { + return err + } + } + return nil +} + +func (s *mockFirestoreServer) ListCollectionIds(ctx context.Context, req *firestorepb.ListCollectionIdsRequest) (*firestorepb.ListCollectionIdsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*firestorepb.ListCollectionIdsResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockFirestore mockFirestoreServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + firestorepb.RegisterFirestoreServer(serv, &mockFirestore) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestFirestoreGetDocument(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &firestorepb.Document{ + Name: name2, + } + + mockFirestore.err = nil + mockFirestore.reqs = nil + + mockFirestore.resps = append(mockFirestore.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/databases/%s/documents/%s/%s", "[PROJECT]", "[DATABASE]", "[DOCUMENT]", "[ANY_PATH]") + var request = &firestorepb.GetDocumentRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetDocument(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockFirestore.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestFirestoreGetDocumentError(t *testing.T) { + errCode := codes.PermissionDenied + mockFirestore.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/databases/%s/documents/%s/%s", "[PROJECT]", "[DATABASE]", "[DOCUMENT]", "[ANY_PATH]") + var request = &firestorepb.GetDocumentRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetDocument(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestFirestoreListDocuments(t *testing.T) { + var nextPageToken string = "" + var documentsElement *firestorepb.Document = &firestorepb.Document{} + var documents = []*firestorepb.Document{documentsElement} + var expectedResponse = &firestorepb.ListDocumentsResponse{ + NextPageToken: nextPageToken, + Documents: documents, + } + + mockFirestore.err = nil + mockFirestore.reqs = nil + + mockFirestore.resps = append(mockFirestore.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/databases/%s/documents/%s/%s", "[PROJECT]", "[DATABASE]", "[DOCUMENT]", "[ANY_PATH]") + var collectionId string = "collectionId-821242276" + var request = &firestorepb.ListDocumentsRequest{ + Parent: formattedParent, + CollectionId: collectionId, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListDocuments(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockFirestore.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Documents[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestFirestoreListDocumentsError(t *testing.T) { + errCode := codes.PermissionDenied + mockFirestore.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/databases/%s/documents/%s/%s", "[PROJECT]", "[DATABASE]", "[DOCUMENT]", "[ANY_PATH]") + var collectionId string = "collectionId-821242276" + var request = &firestorepb.ListDocumentsRequest{ + Parent: formattedParent, + CollectionId: collectionId, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListDocuments(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestFirestoreCreateDocument(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &firestorepb.Document{ + Name: name, + } + + mockFirestore.err = nil + mockFirestore.reqs = nil + + mockFirestore.resps = append(mockFirestore.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/databases/%s/documents/%s/%s", "[PROJECT]", "[DATABASE]", "[DOCUMENT]", "[ANY_PATH]") + var collectionId string = "collectionId-821242276" + var documentId string = "documentId506676927" + var document *firestorepb.Document = &firestorepb.Document{} + var request = &firestorepb.CreateDocumentRequest{ + Parent: formattedParent, + CollectionId: collectionId, + DocumentId: documentId, + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateDocument(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockFirestore.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestFirestoreCreateDocumentError(t *testing.T) { + errCode := codes.PermissionDenied + mockFirestore.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/databases/%s/documents/%s/%s", "[PROJECT]", "[DATABASE]", "[DOCUMENT]", "[ANY_PATH]") + var collectionId string = "collectionId-821242276" + var documentId string = "documentId506676927" + var document *firestorepb.Document = &firestorepb.Document{} + var request = &firestorepb.CreateDocumentRequest{ + Parent: formattedParent, + CollectionId: collectionId, + DocumentId: documentId, + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateDocument(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestFirestoreUpdateDocument(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &firestorepb.Document{ + Name: name, + } + + mockFirestore.err = nil + mockFirestore.reqs = nil + + mockFirestore.resps = append(mockFirestore.resps[:0], expectedResponse) + + var document *firestorepb.Document = &firestorepb.Document{} + var updateMask *firestorepb.DocumentMask = &firestorepb.DocumentMask{} + var request = &firestorepb.UpdateDocumentRequest{ + Document: document, + UpdateMask: updateMask, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateDocument(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockFirestore.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestFirestoreUpdateDocumentError(t *testing.T) { + errCode := codes.PermissionDenied + mockFirestore.err = gstatus.Error(errCode, "test error") + + var document *firestorepb.Document = &firestorepb.Document{} + var updateMask *firestorepb.DocumentMask = &firestorepb.DocumentMask{} + var request = &firestorepb.UpdateDocumentRequest{ + Document: document, + UpdateMask: updateMask, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateDocument(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestFirestoreDeleteDocument(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockFirestore.err = nil + mockFirestore.reqs = nil + + mockFirestore.resps = append(mockFirestore.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/databases/%s/documents/%s/%s", "[PROJECT]", "[DATABASE]", "[DOCUMENT]", "[ANY_PATH]") + var request = &firestorepb.DeleteDocumentRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteDocument(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockFirestore.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestFirestoreDeleteDocumentError(t *testing.T) { + errCode := codes.PermissionDenied + mockFirestore.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/databases/%s/documents/%s/%s", "[PROJECT]", "[DATABASE]", "[DOCUMENT]", "[ANY_PATH]") + var request = &firestorepb.DeleteDocumentRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteDocument(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestFirestoreBatchGetDocuments(t *testing.T) { + var missing string = "missing1069449574" + var transaction []byte = []byte("-34") + var expectedResponse = &firestorepb.BatchGetDocumentsResponse{ + Result: &firestorepb.BatchGetDocumentsResponse_Missing{ + Missing: missing, + }, + Transaction: transaction, + } + + mockFirestore.err = nil + mockFirestore.reqs = nil + + mockFirestore.resps = append(mockFirestore.resps[:0], expectedResponse) + + var formattedDatabase string = fmt.Sprintf("projects/%s/databases/%s", "[PROJECT]", "[DATABASE]") + var documents []string = nil + var request = &firestorepb.BatchGetDocumentsRequest{ + Database: formattedDatabase, + Documents: documents, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.BatchGetDocuments(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockFirestore.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestFirestoreBatchGetDocumentsError(t *testing.T) { + errCode := codes.PermissionDenied + mockFirestore.err = gstatus.Error(errCode, "test error") + + var formattedDatabase string = fmt.Sprintf("projects/%s/databases/%s", "[PROJECT]", "[DATABASE]") + var documents []string = nil + var request = &firestorepb.BatchGetDocumentsRequest{ + Database: formattedDatabase, + Documents: documents, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.BatchGetDocuments(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestFirestoreBeginTransaction(t *testing.T) { + var transaction []byte = []byte("-34") + var expectedResponse = &firestorepb.BeginTransactionResponse{ + Transaction: transaction, + } + + mockFirestore.err = nil + mockFirestore.reqs = nil + + mockFirestore.resps = append(mockFirestore.resps[:0], expectedResponse) + + var formattedDatabase string = fmt.Sprintf("projects/%s/databases/%s", "[PROJECT]", "[DATABASE]") + var request = &firestorepb.BeginTransactionRequest{ + Database: formattedDatabase, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BeginTransaction(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockFirestore.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestFirestoreBeginTransactionError(t *testing.T) { + errCode := codes.PermissionDenied + mockFirestore.err = gstatus.Error(errCode, "test error") + + var formattedDatabase string = fmt.Sprintf("projects/%s/databases/%s", "[PROJECT]", "[DATABASE]") + var request = &firestorepb.BeginTransactionRequest{ + Database: formattedDatabase, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BeginTransaction(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestFirestoreCommit(t *testing.T) { + var expectedResponse *firestorepb.CommitResponse = &firestorepb.CommitResponse{} + + mockFirestore.err = nil + mockFirestore.reqs = nil + + mockFirestore.resps = append(mockFirestore.resps[:0], expectedResponse) + + var formattedDatabase string = fmt.Sprintf("projects/%s/databases/%s", "[PROJECT]", "[DATABASE]") + var writes []*firestorepb.Write = nil + var request = &firestorepb.CommitRequest{ + Database: formattedDatabase, + Writes: writes, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Commit(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockFirestore.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestFirestoreCommitError(t *testing.T) { + errCode := codes.PermissionDenied + mockFirestore.err = gstatus.Error(errCode, "test error") + + var formattedDatabase string = fmt.Sprintf("projects/%s/databases/%s", "[PROJECT]", "[DATABASE]") + var writes []*firestorepb.Write = nil + var request = &firestorepb.CommitRequest{ + Database: formattedDatabase, + Writes: writes, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Commit(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestFirestoreRollback(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockFirestore.err = nil + mockFirestore.reqs = nil + + mockFirestore.resps = append(mockFirestore.resps[:0], expectedResponse) + + var formattedDatabase string = fmt.Sprintf("projects/%s/databases/%s", "[PROJECT]", "[DATABASE]") + var transaction []byte = []byte("-34") + var request = &firestorepb.RollbackRequest{ + Database: formattedDatabase, + Transaction: transaction, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.Rollback(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockFirestore.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestFirestoreRollbackError(t *testing.T) { + errCode := codes.PermissionDenied + mockFirestore.err = gstatus.Error(errCode, "test error") + + var formattedDatabase string = fmt.Sprintf("projects/%s/databases/%s", "[PROJECT]", "[DATABASE]") + var transaction []byte = []byte("-34") + var request = &firestorepb.RollbackRequest{ + Database: formattedDatabase, + Transaction: transaction, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.Rollback(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestFirestoreRunQuery(t *testing.T) { + var transaction []byte = []byte("-34") + var skippedResults int32 = 880286183 + var expectedResponse = &firestorepb.RunQueryResponse{ + Transaction: transaction, + SkippedResults: skippedResults, + } + + mockFirestore.err = nil + mockFirestore.reqs = nil + + mockFirestore.resps = append(mockFirestore.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/databases/%s/documents/%s/%s", "[PROJECT]", "[DATABASE]", "[DOCUMENT]", "[ANY_PATH]") + var request = &firestorepb.RunQueryRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.RunQuery(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockFirestore.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestFirestoreRunQueryError(t *testing.T) { + errCode := codes.PermissionDenied + mockFirestore.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/databases/%s/documents/%s/%s", "[PROJECT]", "[DATABASE]", "[DOCUMENT]", "[ANY_PATH]") + var request = &firestorepb.RunQueryRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.RunQuery(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestFirestoreWrite(t *testing.T) { + var streamId string = "streamId-315624902" + var streamToken []byte = []byte("122") + var expectedResponse = &firestorepb.WriteResponse{ + StreamId: streamId, + StreamToken: streamToken, + } + + mockFirestore.err = nil + mockFirestore.reqs = nil + + mockFirestore.resps = append(mockFirestore.resps[:0], expectedResponse) + + var formattedDatabase string = fmt.Sprintf("projects/%s/databases/%s", "[PROJECT]", "[DATABASE]") + var request = &firestorepb.WriteRequest{ + Database: formattedDatabase, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.Write(context.Background()) + if err != nil { + t.Fatal(err) + } + if err := stream.Send(request); err != nil { + t.Fatal(err) + } + if err := stream.CloseSend(); err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockFirestore.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestFirestoreWriteError(t *testing.T) { + errCode := codes.PermissionDenied + mockFirestore.err = gstatus.Error(errCode, "test error") + + var formattedDatabase string = fmt.Sprintf("projects/%s/databases/%s", "[PROJECT]", "[DATABASE]") + var request = &firestorepb.WriteRequest{ + Database: formattedDatabase, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.Write(context.Background()) + if err != nil { + t.Fatal(err) + } + if err := stream.Send(request); err != nil { + t.Fatal(err) + } + if err := stream.CloseSend(); err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestFirestoreListen(t *testing.T) { + var expectedResponse *firestorepb.ListenResponse = &firestorepb.ListenResponse{} + + mockFirestore.err = nil + mockFirestore.reqs = nil + + mockFirestore.resps = append(mockFirestore.resps[:0], expectedResponse) + + var formattedDatabase string = fmt.Sprintf("projects/%s/databases/%s", "[PROJECT]", "[DATABASE]") + var request = &firestorepb.ListenRequest{ + Database: formattedDatabase, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.Listen(context.Background()) + if err != nil { + t.Fatal(err) + } + if err := stream.Send(request); err != nil { + t.Fatal(err) + } + if err := stream.CloseSend(); err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockFirestore.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestFirestoreListenError(t *testing.T) { + errCode := codes.PermissionDenied + mockFirestore.err = gstatus.Error(errCode, "test error") + + var formattedDatabase string = fmt.Sprintf("projects/%s/databases/%s", "[PROJECT]", "[DATABASE]") + var request = &firestorepb.ListenRequest{ + Database: formattedDatabase, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.Listen(context.Background()) + if err != nil { + t.Fatal(err) + } + if err := stream.Send(request); err != nil { + t.Fatal(err) + } + if err := stream.CloseSend(); err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestFirestoreListCollectionIds(t *testing.T) { + var nextPageToken string = "" + var collectionIdsElement string = "collectionIdsElement1368994900" + var collectionIds = []string{collectionIdsElement} + var expectedResponse = &firestorepb.ListCollectionIdsResponse{ + NextPageToken: nextPageToken, + CollectionIds: collectionIds, + } + + mockFirestore.err = nil + mockFirestore.reqs = nil + + mockFirestore.resps = append(mockFirestore.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/databases/%s/documents/%s/%s", "[PROJECT]", "[DATABASE]", "[DOCUMENT]", "[ANY_PATH]") + var request = &firestorepb.ListCollectionIdsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListCollectionIds(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockFirestore.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.CollectionIds[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestFirestoreListCollectionIdsError(t *testing.T) { + errCode := codes.PermissionDenied + mockFirestore.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/databases/%s/documents/%s/%s", "[PROJECT]", "[DATABASE]", "[DOCUMENT]", "[ANY_PATH]") + var request = &firestorepb.ListCollectionIdsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListCollectionIds(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/firestore/apiv1beta1/path_funcs.go b/vendor/cloud.google.com/go/firestore/apiv1beta1/path_funcs.go new file mode 100644 index 00000000..7f4b0ad6 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/apiv1beta1/path_funcs.go @@ -0,0 +1,78 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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 firestore + +// DatabaseRootPath returns the path for the database root resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/databases/%s", project, database) +// instead. +func DatabaseRootPath(project, database string) string { + return "" + + "projects/" + + project + + "/databases/" + + database + + "" +} + +// DocumentRootPath returns the path for the document root resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/databases/%s/documents", project, database) +// instead. +func DocumentRootPath(project, database string) string { + return "" + + "projects/" + + project + + "/databases/" + + database + + "/documents" + + "" +} + +// DocumentPathPath returns the path for the document path resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/databases/%s/documents/%s", project, database, documentPath) +// instead. +func DocumentPathPath(project, database, documentPath string) string { + return "" + + "projects/" + + project + + "/databases/" + + database + + "/documents/" + + documentPath + + "" +} + +// AnyPathPath returns the path for the any path resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/databases/%s/documents/%s/%s", project, database, document, anyPath) +// instead. +func AnyPathPath(project, database, document, anyPath string) string { + return "" + + "projects/" + + project + + "/databases/" + + database + + "/documents/" + + document + + "/" + + anyPath + + "" +} diff --git a/vendor/cloud.google.com/go/firestore/client.go b/vendor/cloud.google.com/go/firestore/client.go new file mode 100644 index 00000000..a5f014f7 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/client.go @@ -0,0 +1,280 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "errors" + "fmt" + "io" + "strings" + "time" + + vkit "cloud.google.com/go/firestore/apiv1beta1" + "cloud.google.com/go/internal/version" + "github.com/golang/protobuf/ptypes" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// resourcePrefixHeader is the name of the metadata header used to indicate +// the resource being operated on. +const resourcePrefixHeader = "google-cloud-resource-prefix" + +// A Client provides access to the Firestore service. +type Client struct { + c *vkit.Client + projectID string + databaseID string // A client is tied to a single database. +} + +// NewClient creates a new Firestore client that uses the given project. +func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) { + vc, err := vkit.NewClient(ctx, opts...) + if err != nil { + return nil, err + } + vc.SetGoogleClientInfo("gccl", version.Repo) + c := &Client{ + c: vc, + projectID: projectID, + databaseID: "(default)", // always "(default)", for now + } + return c, nil + +} + +// Close closes any resources held by the client. +// +// Close need not be called at program exit. +func (c *Client) Close() error { + return c.c.Close() +} + +func (c *Client) path() string { + return fmt.Sprintf("projects/%s/databases/%s", c.projectID, c.databaseID) +} + +func withResourceHeader(ctx context.Context, resource string) context.Context { + md, _ := metadata.FromOutgoingContext(ctx) + md = md.Copy() + md[resourcePrefixHeader] = []string{resource} + return metadata.NewOutgoingContext(ctx, md) +} + +// Collection creates a reference to a collection with the given path. +// A path is a sequence of IDs separated by slashes. +// +// Collection returns nil if path contains an even number of IDs or any ID is empty. +func (c *Client) Collection(path string) *CollectionRef { + coll, _ := c.idsToRef(strings.Split(path, "/"), c.path()) + return coll +} + +// Doc creates a reference to a document with the given path. +// A path is a sequence of IDs separated by slashes. +// +// Doc returns nil if path contains an odd number of IDs or any ID is empty. +func (c *Client) Doc(path string) *DocumentRef { + _, doc := c.idsToRef(strings.Split(path, "/"), c.path()) + return doc +} + +func (c *Client) idsToRef(IDs []string, dbPath string) (*CollectionRef, *DocumentRef) { + if len(IDs) == 0 { + return nil, nil + } + for _, id := range IDs { + if id == "" { + return nil, nil + } + } + coll := newTopLevelCollRef(c, dbPath, IDs[0]) + i := 1 + for i < len(IDs) { + doc := newDocRef(coll, IDs[i]) + i++ + if i == len(IDs) { + return nil, doc + } + coll = newCollRefWithParent(c, doc, IDs[i]) + i++ + } + return coll, nil +} + +// GetAll retrieves multiple documents with a single call. The DocumentSnapshots are +// returned in the order of the given DocumentRefs. +// +// If a document is not present, the corresponding DocumentSnapshot's Exists method will return false. +func (c *Client) GetAll(ctx context.Context, docRefs []*DocumentRef) ([]*DocumentSnapshot, error) { + if err := checkTransaction(ctx); err != nil { + return nil, err + } + return c.getAll(ctx, docRefs, nil) +} + +func (c *Client) getAll(ctx context.Context, docRefs []*DocumentRef, tid []byte) ([]*DocumentSnapshot, error) { + var docNames []string + docIndex := map[string]int{} // doc name to position in docRefs + for i, dr := range docRefs { + if dr == nil { + return nil, errNilDocRef + } + docNames = append(docNames, dr.Path) + docIndex[dr.Path] = i + } + req := &pb.BatchGetDocumentsRequest{ + Database: c.path(), + Documents: docNames, + } + if tid != nil { + req.ConsistencySelector = &pb.BatchGetDocumentsRequest_Transaction{tid} + } + streamClient, err := c.c.BatchGetDocuments(withResourceHeader(ctx, req.Database), req) + if err != nil { + return nil, err + } + + // Read and remember all results from the stream. + var resps []*pb.BatchGetDocumentsResponse + for { + resp, err := streamClient.Recv() + if err == io.EOF { + break + } + if err != nil { + return nil, err + } + resps = append(resps, resp) + } + + // Results may arrive out of order. Put each at the right index. + docs := make([]*DocumentSnapshot, len(docNames)) + for _, resp := range resps { + var ( + i int + doc *pb.Document + err error + ) + switch r := resp.Result.(type) { + case *pb.BatchGetDocumentsResponse_Found: + i = docIndex[r.Found.Name] + doc = r.Found + case *pb.BatchGetDocumentsResponse_Missing: + i = docIndex[r.Missing] + doc = nil + default: + return nil, errors.New("firestore: unknown BatchGetDocumentsResponse result type") + } + if docs[i] != nil { + return nil, fmt.Errorf("firestore: %q seen twice", docRefs[i].Path) + } + docs[i], err = newDocumentSnapshot(docRefs[i], doc, c, resp.ReadTime) + if err != nil { + return nil, err + } + } + return docs, nil +} + +// Collections returns an interator over the top-level collections. +func (c *Client) Collections(ctx context.Context) *CollectionIterator { + it := &CollectionIterator{ + err: checkTransaction(ctx), + client: c, + it: c.c.ListCollectionIds( + withResourceHeader(ctx, c.path()), + &pb.ListCollectionIdsRequest{Parent: c.path()}), + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.items) }, + func() interface{} { b := it.items; it.items = nil; return b }) + return it +} + +// Batch returns a WriteBatch. +func (c *Client) Batch() *WriteBatch { + return &WriteBatch{c: c} +} + +// commit calls the Commit RPC outside of a transaction. +func (c *Client) commit(ctx context.Context, ws []*pb.Write) ([]*WriteResult, error) { + if err := checkTransaction(ctx); err != nil { + return nil, err + } + req := &pb.CommitRequest{ + Database: c.path(), + Writes: ws, + } + res, err := c.c.Commit(withResourceHeader(ctx, req.Database), req) + if err != nil { + return nil, err + } + if len(res.WriteResults) == 0 { + return nil, errors.New("firestore: missing WriteResult") + } + var wrs []*WriteResult + for _, pwr := range res.WriteResults { + wr, err := writeResultFromProto(pwr) + if err != nil { + return nil, err + } + wrs = append(wrs, wr) + } + return wrs, nil +} + +func (c *Client) commit1(ctx context.Context, ws []*pb.Write) (*WriteResult, error) { + wrs, err := c.commit(ctx, ws) + if err != nil { + return nil, err + } + return wrs[0], nil +} + +// A WriteResult is returned by methods that write documents. +type WriteResult struct { + // The time at which the document was updated, or created if it did not + // previously exist. Writes that do not actually change the document do + // not change the update time. + UpdateTime time.Time +} + +func writeResultFromProto(wr *pb.WriteResult) (*WriteResult, error) { + t, err := ptypes.Timestamp(wr.UpdateTime) + if err != nil { + t = time.Time{} + // TODO(jba): Follow up if Delete is supposed to return a nil timestamp. + } + return &WriteResult{UpdateTime: t}, nil +} + +func sleep(ctx context.Context, dur time.Duration) error { + switch err := gax.Sleep(ctx, dur); err { + case context.Canceled: + return status.Error(codes.Canceled, "context canceled") + case context.DeadlineExceeded: + return status.Error(codes.DeadlineExceeded, "context deadline exceeded") + default: + return err + } +} diff --git a/vendor/cloud.google.com/go/firestore/client_test.go b/vendor/cloud.google.com/go/firestore/client_test.go new file mode 100644 index 00000000..92ff877e --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/client_test.go @@ -0,0 +1,212 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "testing" + + tspb "github.com/golang/protobuf/ptypes/timestamp" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var testClient = &Client{ + projectID: "projectID", + databaseID: "(default)", +} + +func TestClientCollectionAndDoc(t *testing.T) { + coll1 := testClient.Collection("X") + db := "projects/projectID/databases/(default)" + wantc1 := &CollectionRef{ + c: testClient, + parentPath: db, + Parent: nil, + ID: "X", + Path: "projects/projectID/databases/(default)/documents/X", + Query: Query{c: testClient, collectionID: "X", parentPath: db}, + } + if !testEqual(coll1, wantc1) { + t.Fatalf("got\n%+v\nwant\n%+v", coll1, wantc1) + } + doc1 := testClient.Doc("X/a") + wantd1 := &DocumentRef{ + Parent: coll1, + ID: "a", + Path: "projects/projectID/databases/(default)/documents/X/a", + } + + if !testEqual(doc1, wantd1) { + t.Fatalf("got %+v, want %+v", doc1, wantd1) + } + coll2 := testClient.Collection("X/a/Y") + parentPath := "projects/projectID/databases/(default)/documents/X/a" + wantc2 := &CollectionRef{ + c: testClient, + parentPath: parentPath, + Parent: doc1, + ID: "Y", + Path: "projects/projectID/databases/(default)/documents/X/a/Y", + Query: Query{c: testClient, collectionID: "Y", parentPath: parentPath}, + } + if !testEqual(coll2, wantc2) { + t.Fatalf("\ngot %+v\nwant %+v", coll2, wantc2) + } + doc2 := testClient.Doc("X/a/Y/b") + wantd2 := &DocumentRef{ + Parent: coll2, + ID: "b", + Path: "projects/projectID/databases/(default)/documents/X/a/Y/b", + } + if !testEqual(doc2, wantd2) { + t.Fatalf("got %+v, want %+v", doc2, wantd2) + } +} + +func TestClientCollDocErrors(t *testing.T) { + for _, badColl := range []string{"", "/", "/a/", "/a/b", "a/b/", "a//b"} { + coll := testClient.Collection(badColl) + if coll != nil { + t.Errorf("coll path %q: got %+v, want nil", badColl, coll) + } + } + for _, badDoc := range []string{"", "a", "/", "/a", "a/", "a/b/c", "a//b/c"} { + doc := testClient.Doc(badDoc) + if doc != nil { + t.Errorf("doc path %q: got %+v, want nil", badDoc, doc) + } + } +} + +func TestGetAll(t *testing.T) { + c, srv := newMock(t) + defer c.Close() + const dbPath = "projects/projectID/databases/(default)" + req := &pb.BatchGetDocumentsRequest{ + Database: dbPath, + Documents: []string{ + dbPath + "/documents/C/a", + dbPath + "/documents/C/b", + dbPath + "/documents/C/c", + }, + } + testGetAll(t, c, srv, dbPath, func(drs []*DocumentRef) ([]*DocumentSnapshot, error) { + return c.GetAll(context.Background(), drs) + }, req) +} + +func testGetAll(t *testing.T, c *Client, srv *mockServer, dbPath string, getAll func([]*DocumentRef) ([]*DocumentSnapshot, error), req *pb.BatchGetDocumentsRequest) { + wantPBDocs := []*pb.Document{ + { + Name: dbPath + "/documents/C/a", + CreateTime: aTimestamp, + UpdateTime: aTimestamp, + Fields: map[string]*pb.Value{"f": intval(2)}, + }, + nil, + { + Name: dbPath + "/documents/C/c", + CreateTime: aTimestamp, + UpdateTime: aTimestamp, + Fields: map[string]*pb.Value{"f": intval(1)}, + }, + } + wantReadTimes := []*tspb.Timestamp{aTimestamp, aTimestamp2, aTimestamp3} + srv.addRPC(req, + []interface{}{ + // deliberately put these out of order + &pb.BatchGetDocumentsResponse{ + Result: &pb.BatchGetDocumentsResponse_Found{wantPBDocs[2]}, + ReadTime: aTimestamp3, + }, + &pb.BatchGetDocumentsResponse{ + Result: &pb.BatchGetDocumentsResponse_Found{wantPBDocs[0]}, + ReadTime: aTimestamp, + }, + &pb.BatchGetDocumentsResponse{ + Result: &pb.BatchGetDocumentsResponse_Missing{dbPath + "/documents/C/b"}, + ReadTime: aTimestamp2, + }, + }, + ) + coll := c.Collection("C") + var docRefs []*DocumentRef + for _, name := range []string{"a", "b", "c"} { + docRefs = append(docRefs, coll.Doc(name)) + } + docs, err := getAll(docRefs) + if err != nil { + t.Fatal(err) + } + if got, want := len(docs), len(wantPBDocs); got != want { + t.Errorf("got %d docs, wanted %d", got, want) + } + for i, got := range docs { + want, err := newDocumentSnapshot(docRefs[i], wantPBDocs[i], c, wantReadTimes[i]) + if err != nil { + t.Fatal(err) + } + if diff := testDiff(got, want); diff != "" { + t.Errorf("#%d: got=--, want==++\n%s", i, diff) + } + } +} + +func TestGetAllErrors(t *testing.T) { + ctx := context.Background() + const ( + dbPath = "projects/projectID/databases/(default)" + docPath = dbPath + "/documents/C/a" + ) + c, srv := newMock(t) + if _, err := c.GetAll(ctx, []*DocumentRef{nil}); err != errNilDocRef { + t.Errorf("got %v, want errNilDocRef", err) + } + + // Internal server error. + srv.addRPC( + &pb.BatchGetDocumentsRequest{ + Database: dbPath, + Documents: []string{docPath}, + }, + []interface{}{status.Errorf(codes.Internal, "")}, + ) + _, err := c.GetAll(ctx, []*DocumentRef{c.Doc("C/a")}) + codeEq(t, "GetAll #1", codes.Internal, err) + + // Doc appears as both found and missing (server bug). + srv.reset() + srv.addRPC( + &pb.BatchGetDocumentsRequest{ + Database: dbPath, + Documents: []string{docPath}, + }, + []interface{}{ + &pb.BatchGetDocumentsResponse{ + Result: &pb.BatchGetDocumentsResponse_Found{&pb.Document{Name: docPath}}, + ReadTime: aTimestamp, + }, + &pb.BatchGetDocumentsResponse{ + Result: &pb.BatchGetDocumentsResponse_Missing{docPath}, + ReadTime: aTimestamp, + }, + }, + ) + if _, err := c.GetAll(ctx, []*DocumentRef{c.Doc("C/a")}); err == nil { + t.Error("got nil, want error") + } +} diff --git a/vendor/cloud.google.com/go/firestore/collref.go b/vendor/cloud.google.com/go/firestore/collref.go new file mode 100644 index 00000000..ff445d11 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/collref.go @@ -0,0 +1,123 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "math/rand" + "os" + "sync" + "time" +) + +// A CollectionRef is a reference to Firestore collection. +type CollectionRef struct { + c *Client + + // Typically Parent.Path, or c.path if Parent is nil. + // May be different if this CollectionRef was created from a stored reference + // to a different project/DB. + parentPath string + + // Parent is the document of which this collection is a part. It is + // nil for top-level collections. + Parent *DocumentRef + + // The full resource path of the collection: "projects/P/databases/D/documents..." + Path string + + // ID is the collection identifier. + ID string + + // Use the methods of Query on a CollectionRef to create and run queries. + Query +} + +func newTopLevelCollRef(c *Client, dbPath, id string) *CollectionRef { + return &CollectionRef{ + c: c, + ID: id, + parentPath: dbPath, + Path: dbPath + "/documents/" + id, + Query: Query{c: c, collectionID: id, parentPath: dbPath}, + } +} + +func newCollRefWithParent(c *Client, parent *DocumentRef, id string) *CollectionRef { + return &CollectionRef{ + c: c, + Parent: parent, + ID: id, + parentPath: parent.Path, + Path: parent.Path + "/" + id, + Query: Query{c: c, collectionID: id, parentPath: parent.Path}, + } +} + +// Doc returns a DocumentRef that refers to the document in the collection with the +// given identifier. +func (c *CollectionRef) Doc(id string) *DocumentRef { + if c == nil { + return nil + } + return newDocRef(c, id) +} + +// NewDoc returns a DocumentRef with a uniquely generated ID. +func (c *CollectionRef) NewDoc() *DocumentRef { + return c.Doc(uniqueID()) +} + +// Add generates a DocumentRef with a unique ID. It then creates the document +// with the given data, which can be a map[string]interface{}, a struct or a +// pointer to a struct. +// +// Add returns an error in the unlikely event that a document with the same ID +// already exists. +func (c *CollectionRef) Add(ctx context.Context, data interface{}) (*DocumentRef, *WriteResult, error) { + d := c.NewDoc() + wr, err := d.Create(ctx, data) + if err != nil { + return nil, nil, err + } + return d, wr, nil +} + +// DocumentRefs returns references to all the documents in the collection, including +// missing documents. A missing document is a document that does not exist but has +// sub-documents. +func (c *CollectionRef) DocumentRefs(ctx context.Context) *DocumentRefIterator { + if err := checkTransaction(ctx); err != nil { + return &DocumentRefIterator{err: err} + } + return newDocumentRefIterator(ctx, c, nil) +} + +const alphanum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + +var ( + rngMu sync.Mutex + rng = rand.New(rand.NewSource(time.Now().UnixNano() ^ int64(os.Getpid()))) +) + +func uniqueID() string { + var b [20]byte + rngMu.Lock() + for i := 0; i < len(b); i++ { + b[i] = alphanum[rng.Intn(len(alphanum))] + } + rngMu.Unlock() + return string(b[:]) +} diff --git a/vendor/cloud.google.com/go/firestore/collref_test.go b/vendor/cloud.google.com/go/firestore/collref_test.go new file mode 100644 index 00000000..e77c0db6 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/collref_test.go @@ -0,0 +1,95 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "testing" + + "github.com/golang/protobuf/proto" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +func TestDoc(t *testing.T) { + coll := testClient.Collection("C") + got := coll.Doc("d") + want := &DocumentRef{ + Parent: coll, + ID: "d", + Path: "projects/projectID/databases/(default)/documents/C/d", + } + if !testEqual(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } +} + +func TestNewDoc(t *testing.T) { + c := &Client{} + coll := c.Collection("C") + got := coll.NewDoc() + if got.Parent != coll { + t.Errorf("got %v, want %v", got.Parent, coll) + } + if len(got.ID) != 20 { + t.Errorf("got %d-char ID, wanted 20", len(got.ID)) + } + + got2 := coll.NewDoc() + if got.ID == got2.ID { + t.Error("got same ID") + } +} + +func TestAdd(t *testing.T) { + ctx := context.Background() + c, srv := newMock(t) + wantReq := commitRequestForSet() + w := wantReq.Writes[0] + w.CurrentDocument = &pb.Precondition{ + ConditionType: &pb.Precondition_Exists{false}, + } + srv.addRPCAdjust(wantReq, commitResponseForSet, func(gotReq proto.Message) { + // We can't know the doc ID before Add is called, so we take it from + // the request. + w.Operation.(*pb.Write_Update).Update.Name = gotReq.(*pb.CommitRequest).Writes[0].Operation.(*pb.Write_Update).Update.Name + }) + _, wr, err := c.Collection("C").Add(ctx, testData) + if err != nil { + t.Fatal(err) + } + if !testEqual(wr, writeResultForSet) { + t.Errorf("got %v, want %v", wr, writeResultForSet) + } +} + +func TestNilErrors(t *testing.T) { + ctx := context.Background() + c, _ := newMock(t) + // Test that a nil CollectionRef results in a nil DocumentRef and errors + // where possible. + coll := c.Collection("a/b") // nil because "a/b" denotes a doc. + if coll != nil { + t.Fatal("collection not nil") + } + if got := coll.Doc("d"); got != nil { + t.Fatalf("got %v, want nil", got) + } + if got := coll.NewDoc(); got != nil { + t.Fatalf("got %v, want nil", got) + } + if _, _, err := coll.Add(ctx, testData); err != errNilDocRef { + t.Fatalf("got <%v>, want <%v>", err, errNilDocRef) + } +} diff --git a/vendor/cloud.google.com/go/firestore/conformance_test.go b/vendor/cloud.google.com/go/firestore/conformance_test.go new file mode 100644 index 00000000..1fcbaaa7 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/conformance_test.go @@ -0,0 +1,442 @@ +// Copyright 2017 Google LLC +// +// 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. + +// A runner for the conformance tests. + +package firestore + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "math" + "path" + "path/filepath" + "strings" + "testing" + "time" + + pb "cloud.google.com/go/firestore/genproto" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + ts "github.com/golang/protobuf/ptypes/timestamp" + "github.com/google/go-cmp/cmp" + "google.golang.org/api/iterator" + fspb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +const conformanceTestWatchTargetID = 1 + +func TestConformanceTests(t *testing.T) { + const dir = "testdata" + fis, err := ioutil.ReadDir(dir) + if err != nil { + t.Fatal(err) + } + wtid := watchTargetID + watchTargetID = conformanceTestWatchTargetID + defer func() { watchTargetID = wtid }() + n := 0 + for _, fi := range fis { + if strings.HasSuffix(fi.Name(), ".textproto") { + runTestFromFile(t, filepath.Join(dir, fi.Name())) + n++ + } + } + t.Logf("ran %d conformance tests", n) +} + +func runTestFromFile(t *testing.T, filename string) { + bytes, err := ioutil.ReadFile(filename) + if err != nil { + t.Fatalf("%s: %v", filename, err) + } + var test pb.Test + if err := proto.UnmarshalText(string(bytes), &test); err != nil { + t.Fatalf("unmarshalling %s: %v", filename, err) + } + msg := fmt.Sprintf("%s (file %s)", test.Description, filepath.Base(filename)) + runTest(t, msg, &test) +} + +func runTest(t *testing.T, msg string, test *pb.Test) { + check := func(gotErr error, wantErr bool) bool { + if wantErr && gotErr == nil { + t.Errorf("%s: got nil, want error", msg) + return false + } else if !wantErr && gotErr != nil { + t.Errorf("%s: %v", msg, gotErr) + return false + } + return true + } + + ctx := context.Background() + c, srv := newMock(t) + switch tt := test.Test.(type) { + case *pb.Test_Get: + req := &fspb.BatchGetDocumentsRequest{ + Database: c.path(), + Documents: []string{tt.Get.DocRefPath}, + } + srv.addRPC(req, []interface{}{ + &fspb.BatchGetDocumentsResponse{ + Result: &fspb.BatchGetDocumentsResponse_Found{&fspb.Document{ + Name: tt.Get.DocRefPath, + CreateTime: &ts.Timestamp{}, + UpdateTime: &ts.Timestamp{}, + }}, + ReadTime: &ts.Timestamp{}, + }, + }) + ref := docRefFromPath(tt.Get.DocRefPath, c) + _, err := ref.Get(ctx) + if err != nil { + t.Errorf("%s: %v", msg, err) + return + } + // Checking response would just be testing the function converting a Document + // proto to a DocumentSnapshot, hence uninteresting. + + case *pb.Test_Create: + srv.addRPC(tt.Create.Request, commitResponseForSet) + ref := docRefFromPath(tt.Create.DocRefPath, c) + data, err := convertData(tt.Create.JsonData) + if err != nil { + t.Errorf("%s: %v", msg, err) + return + } + _, err = ref.Create(ctx, data) + check(err, tt.Create.IsError) + + case *pb.Test_Set: + srv.addRPC(tt.Set.Request, commitResponseForSet) + ref := docRefFromPath(tt.Set.DocRefPath, c) + data, err := convertData(tt.Set.JsonData) + if err != nil { + t.Errorf("%s: %v", msg, err) + return + } + var opts []SetOption + if tt.Set.Option != nil { + opts = []SetOption{convertSetOption(tt.Set.Option)} + } + _, err = ref.Set(ctx, data, opts...) + check(err, tt.Set.IsError) + + case *pb.Test_Update: + // Ignore Update test because we only support UpdatePaths. + // Not to worry, every Update test has a corresponding UpdatePaths test. + + case *pb.Test_UpdatePaths: + srv.addRPC(tt.UpdatePaths.Request, commitResponseForSet) + ref := docRefFromPath(tt.UpdatePaths.DocRefPath, c) + preconds := convertPrecondition(t, tt.UpdatePaths.Precondition) + paths := convertFieldPaths(tt.UpdatePaths.FieldPaths) + var ups []Update + for i, path := range paths { + val, err := convertJSONValue(tt.UpdatePaths.JsonValues[i]) + if err != nil { + t.Fatalf("%s: %v", msg, err) + } + ups = append(ups, Update{ + FieldPath: path, + Value: val, + }) + } + _, err := ref.Update(ctx, ups, preconds...) + check(err, tt.UpdatePaths.IsError) + + case *pb.Test_Delete: + srv.addRPC(tt.Delete.Request, commitResponseForSet) + ref := docRefFromPath(tt.Delete.DocRefPath, c) + preconds := convertPrecondition(t, tt.Delete.Precondition) + _, err := ref.Delete(ctx, preconds...) + check(err, tt.Delete.IsError) + + case *pb.Test_Query: + q := convertQuery(t, tt.Query) + got, err := q.toProto() + if check(err, tt.Query.IsError) && err == nil { + if want := tt.Query.Query; !proto.Equal(got, want) { + t.Errorf("%s\ngot: %s\nwant: %s", msg, proto.MarshalTextString(got), proto.MarshalTextString(want)) + } + } + + case *pb.Test_Listen: + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + iter := c.Collection("C").OrderBy("a", Asc).Snapshots(ctx) + var rs []interface{} + for _, r := range tt.Listen.Responses { + rs = append(rs, r) + } + srv.addRPC(&fspb.ListenRequest{ + Database: "projects/projectID/databases/(default)", + TargetChange: &fspb.ListenRequest_AddTarget{iter.ws.target}, + }, rs) + got, err := nSnapshots(iter, len(tt.Listen.Snapshots)) + if err != nil { + t.Errorf("%s: %v", msg, err) + } else if diff := cmp.Diff(got, tt.Listen.Snapshots); diff != "" { + t.Errorf("%s:\n%s", msg, diff) + } + if tt.Listen.IsError { + _, err := iter.Next() + if err == nil { + t.Errorf("%s: got nil, want error", msg) + } + } + + default: + t.Fatalf("unknown test type %T", tt) + } +} + +func nSnapshots(iter *QuerySnapshotIterator, n int) ([]*pb.Snapshot, error) { + var snaps []*pb.Snapshot + for i := 0; i < n; i++ { + qsnap, err := iter.Next() + if err != nil { + return snaps, err + } + s := &pb.Snapshot{ReadTime: mustTimestampProto(qsnap.ReadTime)} + for { + doc, err := qsnap.Documents.Next() + if err == iterator.Done { + break + } + if err != nil { + return snaps, err + } + s.Docs = append(s.Docs, doc.proto) + } + for _, c := range qsnap.Changes { + var k pb.DocChange_Kind + switch c.Kind { + case DocumentAdded: + k = pb.DocChange_ADDED + case DocumentRemoved: + k = pb.DocChange_REMOVED + case DocumentModified: + k = pb.DocChange_MODIFIED + default: + panic("bad kind") + } + s.Changes = append(s.Changes, &pb.DocChange{ + Kind: k, + Doc: c.Doc.proto, + OldIndex: int32(c.OldIndex), + NewIndex: int32(c.NewIndex), + }) + } + snaps = append(snaps, s) + } + return snaps, nil +} + +func docRefFromPath(p string, c *Client) *DocumentRef { + return &DocumentRef{ + Path: p, + ID: path.Base(p), + Parent: &CollectionRef{c: c}, + } +} + +func convertJSONValue(jv string) (interface{}, error) { + var val interface{} + if err := json.Unmarshal([]byte(jv), &val); err != nil { + return nil, err + } + return convertTestValue(val), nil +} + +func convertData(jsonData string) (map[string]interface{}, error) { + var m map[string]interface{} + if err := json.Unmarshal([]byte(jsonData), &m); err != nil { + return nil, err + } + return convertTestMap(m), nil +} + +func convertTestMap(m map[string]interface{}) map[string]interface{} { + for k, v := range m { + m[k] = convertTestValue(v) + } + return m +} + +func convertTestValue(v interface{}) interface{} { + switch v := v.(type) { + case string: + switch v { + case "ServerTimestamp": + return ServerTimestamp + case "Delete": + return Delete + case "NaN": + return math.NaN() + default: + return v + } + case float64: + if v == float64(int(v)) { + return int(v) + } + return v + case []interface{}: + if len(v) > 0 { + if fv, ok := v[0].(string); ok { + if fv == "ArrayUnion" { + return ArrayUnion(convertTestValue(v[1:]).([]interface{})...) + } + if fv == "ArrayRemove" { + return ArrayRemove(convertTestValue(v[1:]).([]interface{})...) + } + } + } + for i, e := range v { + v[i] = convertTestValue(e) + } + return v + case map[string]interface{}: + return convertTestMap(v) + default: + return v + } +} + +func convertSetOption(opt *pb.SetOption) SetOption { + if opt.All { + return MergeAll + } + return Merge(convertFieldPaths(opt.Fields)...) +} + +func convertFieldPaths(fps []*pb.FieldPath) []FieldPath { + var res []FieldPath + for _, fp := range fps { + res = append(res, fp.Field) + } + return res +} + +func convertPrecondition(t *testing.T, fp *fspb.Precondition) []Precondition { + if fp == nil { + return nil + } + var pc Precondition + switch fp := fp.ConditionType.(type) { + case *fspb.Precondition_Exists: + pc = exists(fp.Exists) + case *fspb.Precondition_UpdateTime: + tm, err := ptypes.Timestamp(fp.UpdateTime) + if err != nil { + t.Fatal(err) + } + pc = LastUpdateTime(tm) + default: + t.Fatalf("unknown precondition type %T", fp) + } + return []Precondition{pc} +} + +func convertQuery(t *testing.T, qt *pb.QueryTest) Query { + parts := strings.Split(qt.CollPath, "/") + q := Query{ + parentPath: strings.Join(parts[:len(parts)-2], "/"), + collectionID: parts[len(parts)-1], + } + for _, c := range qt.Clauses { + switch c := c.Clause.(type) { + case *pb.Clause_Select: + q = q.SelectPaths(convertFieldPaths(c.Select.Fields)...) + case *pb.Clause_OrderBy: + var dir Direction + switch c.OrderBy.Direction { + case "asc": + dir = Asc + case "desc": + dir = Desc + default: + t.Fatalf("bad direction: %q", c.OrderBy.Direction) + } + q = q.OrderByPath(FieldPath(c.OrderBy.Path.Field), dir) + case *pb.Clause_Where: + val, err := convertJSONValue(c.Where.JsonValue) + if err != nil { + t.Fatal(err) + } + q = q.WherePath(FieldPath(c.Where.Path.Field), c.Where.Op, val) + case *pb.Clause_Offset: + q = q.Offset(int(c.Offset)) + case *pb.Clause_Limit: + q = q.Limit(int(c.Limit)) + case *pb.Clause_StartAt: + q = q.StartAt(convertCursor(t, c.StartAt)...) + case *pb.Clause_StartAfter: + q = q.StartAfter(convertCursor(t, c.StartAfter)...) + case *pb.Clause_EndAt: + q = q.EndAt(convertCursor(t, c.EndAt)...) + case *pb.Clause_EndBefore: + q = q.EndBefore(convertCursor(t, c.EndBefore)...) + default: + t.Fatalf("bad clause type %T", c) + } + } + return q +} + +// Returns args to a cursor method (StartAt, etc.). +func convertCursor(t *testing.T, c *pb.Cursor) []interface{} { + if c.DocSnapshot != nil { + ds, err := convertDocSnapshot(c.DocSnapshot) + if err != nil { + t.Fatal(err) + } + return []interface{}{ds} + } + var vals []interface{} + for _, jv := range c.JsonValues { + v, err := convertJSONValue(jv) + if err != nil { + t.Fatal(err) + } + vals = append(vals, v) + } + return vals +} + +func convertDocSnapshot(ds *pb.DocSnapshot) (*DocumentSnapshot, error) { + data, err := convertData(ds.JsonData) + if err != nil { + return nil, err + } + doc, transformPaths, err := toProtoDocument(data) + if err != nil { + return nil, err + } + if len(transformPaths) > 0 { + return nil, errors.New("saw transform paths in DocSnapshot") + } + return &DocumentSnapshot{ + Ref: &DocumentRef{ + Path: ds.Path, + Parent: &CollectionRef{Path: path.Dir(ds.Path)}, + }, + proto: doc, + }, nil +} diff --git a/vendor/cloud.google.com/go/firestore/doc.go b/vendor/cloud.google.com/go/firestore/doc.go new file mode 100644 index 00000000..1e4c3f1e --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/doc.go @@ -0,0 +1,218 @@ +// Copyright 2017 Google LLC +// +// 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. + +// DO NOT EDIT doc.go. Modify internal/doc.template, then run make -C internal. + +/* +Package firestore provides a client for reading and writing to a Cloud Firestore +database. + +See https://cloud.google.com/firestore/docs for an introduction +to Cloud Firestore and additional help on using the Firestore API. + +See https://godoc.org/cloud.google.com/go for authentication, timeouts, +connection pooling and similar aspects of this package. + +Note: you can't use both Cloud Firestore and Cloud Datastore in the same +project. + +Creating a Client + +To start working with this package, create a client with a project ID: + + ctx := context.Background() + client, err := firestore.NewClient(ctx, "projectID") + if err != nil { + // TODO: Handle error. + } + +CollectionRefs and DocumentRefs + +In Firestore, documents are sets of key-value pairs, and collections are groups of +documents. A Firestore database consists of a hierarchy of alternating collections +and documents, referred to by slash-separated paths like +"States/California/Cities/SanFrancisco". + +This client is built around references to collections and documents. CollectionRefs +and DocumentRefs are lightweight values that refer to the corresponding database +entities. Creating a ref does not involve any network traffic. + + states := client.Collection("States") + ny := states.Doc("NewYork") + // Or, in a single call: + ny = client.Doc("States/NewYork") + +Reading + +Use DocumentRef.Get to read a document. The result is a DocumentSnapshot. +Call its Data method to obtain the entire document contents as a map. + + docsnap, err := ny.Get(ctx) + if err != nil { + // TODO: Handle error. + } + dataMap := docsnap.Data() + fmt.Println(dataMap) + +You can also obtain a single field with DataAt, or extract the data into a struct +with DataTo. With the type definition + + type State struct { + Capital string `firestore:"capital"` + Population float64 `firestore:"pop"` // in millions + } + +we can extract the document's data into a value of type State: + + var nyData State + if err := docsnap.DataTo(&nyData); err != nil { + // TODO: Handle error. + } + +Note that this client supports struct tags beginning with "firestore:" that work like +the tags of the encoding/json package, letting you rename fields, ignore them, or +omit their values when empty. + +To retrieve multiple documents from their references in a single call, use +Client.GetAll. + + docsnaps, err := client.GetAll(ctx, []*firestore.DocumentRef{ + states.Doc("Wisconsin"), states.Doc("Ohio"), + }) + if err != nil { + // TODO: Handle error. + } + for _, ds := range docsnaps { + _ = ds // TODO: Use ds. + } + + +Writing + +For writing individual documents, use the methods on DocumentReference. +Create creates a new document. + + wr, err := ny.Create(ctx, State{ + Capital: "Albany", + Population: 19.8, + }) + if err != nil { + // TODO: Handle error. + } + fmt.Println(wr) + +The first return value is a WriteResult, which contains the time +at which the document was updated. + +Create fails if the document exists. Another method, Set, either replaces an existing +document or creates a new one. + + ca := states.Doc("California") + _, err = ca.Set(ctx, State{ + Capital: "Sacramento", + Population: 39.14, + }) + +To update some fields of an existing document, use Update. It takes a list of +paths to update and their corresponding values. + + _, err = ca.Update(ctx, []firestore.Update{{Path: "capital", Value: "Sacramento"}}) + +Use DocumentRef.Delete to delete a document. + + _, err = ny.Delete(ctx) + +Preconditions + +You can condition Deletes or Updates on when a document was last changed. Specify +these preconditions as an option to a Delete or Update method. The check and the +write happen atomically with a single RPC. + + docsnap, err = ca.Get(ctx) + if err != nil { + // TODO: Handle error. + } + _, err = ca.Update(ctx, + []firestore.Update{{Path: "capital", Value: "Sacramento"}}, + firestore.LastUpdateTime(docsnap.UpdateTime)) + +Here we update a doc only if it hasn't changed since we read it. +You could also do this with a transaction. + +To perform multiple writes at once, use a WriteBatch. Its methods chain +for convenience. + +WriteBatch.Commit sends the collected writes to the server, where they happen +atomically. + + writeResults, err := client.Batch(). + Create(ny, State{Capital: "Albany"}). + Update(ca, []firestore.Update{{Path: "capital", Value: "Sacramento"}}). + Delete(client.Doc("States/WestDakota")). + Commit(ctx) + +Queries + +You can use SQL to select documents from a collection. Begin with the collection, and +build up a query using Select, Where and other methods of Query. + + q := states.Where("pop", ">", 10).OrderBy("pop", firestore.Desc) + +Supported operators include `<`, `<=`, `>`, `>=`, `==`, and 'array-contains'. + +Call the Query's Documents method to get an iterator, and use it like +the other Google Cloud Client iterators. + + iter := q.Documents(ctx) + defer iter.Stop() + for { + doc, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(doc.Data()) + } + +To get all the documents in a collection, you can use the collection itself +as a query. + + iter = client.Collection("States").Documents(ctx) + +Transactions + +Use a transaction to execute reads and writes atomically. All reads must happen +before any writes. Transaction creation, commit, rollback and retry are handled for +you by the Client.RunTransaction method; just provide a function and use the +read and write methods of the Transaction passed to it. + + ny := client.Doc("States/NewYork") + err := client.RunTransaction(ctx, func(ctx context.Context, tx *firestore.Transaction) error { + doc, err := tx.Get(ny) // tx.Get, NOT ny.Get! + if err != nil { + return err + } + pop, err := doc.DataAt("pop") + if err != nil { + return err + } + return tx.Update(ny, []firestore.Update{{Path: "pop", Value: pop.(float64) + 0.2}}) + }) + if err != nil { + // TODO: Handle error. + } +*/ +package firestore diff --git a/vendor/cloud.google.com/go/firestore/docref.go b/vendor/cloud.google.com/go/firestore/docref.go new file mode 100644 index 00000000..422b6bde --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/docref.go @@ -0,0 +1,706 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "errors" + "fmt" + "io" + "reflect" + "sort" + + vkit "cloud.google.com/go/firestore/apiv1beta1" + "google.golang.org/api/iterator" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var errNilDocRef = errors.New("firestore: nil DocumentRef") + +// A DocumentRef is a reference to a Firestore document. +type DocumentRef struct { + // The CollectionRef that this document is a part of. Never nil. + Parent *CollectionRef + + // The full resource path of the document: "projects/P/databases/D/documents..." + Path string + + // The ID of the document: the last component of the resource path. + ID string +} + +func newDocRef(parent *CollectionRef, id string) *DocumentRef { + return &DocumentRef{ + Parent: parent, + ID: id, + Path: parent.Path + "/" + id, + } +} + +// Collection returns a reference to sub-collection of this document. +func (d *DocumentRef) Collection(id string) *CollectionRef { + return newCollRefWithParent(d.Parent.c, d, id) +} + +// Get retrieves the document. If the document does not exist, Get return a NotFound error, which +// can be checked with +// grpc.Code(err) == codes.NotFound +// In that case, Get returns a non-nil DocumentSnapshot whose Exists method return false and whose +// ReadTime is the time of the failed read operation. +func (d *DocumentRef) Get(ctx context.Context) (*DocumentSnapshot, error) { + if err := checkTransaction(ctx); err != nil { + return nil, err + } + if d == nil { + return nil, errNilDocRef + } + docsnaps, err := d.Parent.c.getAll(ctx, []*DocumentRef{d}, nil) + if err != nil { + return nil, err + } + ds := docsnaps[0] + if !ds.Exists() { + return ds, status.Errorf(codes.NotFound, "%q not found", d.Path) + } + return ds, nil +} + +// Create creates the document with the given data. +// It returns an error if a document with the same ID already exists. +// +// The data argument can be a map with string keys, a struct, or a pointer to a +// struct. The map keys or exported struct fields become the fields of the firestore +// document. +// The values of data are converted to Firestore values as follows: +// +// - bool converts to Bool. +// - string converts to String. +// - int, int8, int16, int32 and int64 convert to Integer. +// - uint8, uint16 and uint32 convert to Integer. uint64 is disallowed, +// because it can represent values that cannot be represented in an int64, which +// is the underlying type of a Integer. +// - float32 and float64 convert to Double. +// - []byte converts to Bytes. +// - time.Time and *ts.Timestamp convert to Timestamp. ts is the package +// "github.com/golang/protobuf/ptypes/timestamp". +// - *latlng.LatLng converts to GeoPoint. latlng is the package +// "google.golang.org/genproto/googleapis/type/latlng". You should always use +// a pointer to a LatLng. +// - Slices convert to Array. +// - *firestore.DocumentRef converts to Reference. +// - Maps and structs convert to Map. +// - nils of any type convert to Null. +// +// Pointers and interface{} are also permitted, and their elements processed +// recursively. +// +// Struct fields can have tags like those used by the encoding/json package. Tags +// begin with "firestore:" and are followed by "-", meaning "ignore this field," or +// an alternative name for the field. Following the name, these comma-separated +// options may be provided: +// +// - omitempty: Do not encode this field if it is empty. A value is empty +// if it is a zero value, or an array, slice or map of length zero. +// - serverTimestamp: The field must be of type time.Time. When writing, if +// the field has the zero value, the server will populate the stored document with +// the time that the request is processed. +func (d *DocumentRef) Create(ctx context.Context, data interface{}) (*WriteResult, error) { + ws, err := d.newCreateWrites(data) + if err != nil { + return nil, err + } + return d.Parent.c.commit1(ctx, ws) +} + +func (d *DocumentRef) newCreateWrites(data interface{}) ([]*pb.Write, error) { + if d == nil { + return nil, errNilDocRef + } + doc, transforms, err := toProtoDocument(data) + if err != nil { + return nil, err + } + doc.Name = d.Path + pc, err := exists(false).preconditionProto() + if err != nil { + return nil, err + } + return d.newUpdateWithTransform(doc, nil, pc, transforms, false), nil +} + +// Set creates or overwrites the document with the given data. See DocumentRef.Create +// for the acceptable values of data. Without options, Set overwrites the document +// completely. Specify one of the Merge options to preserve an existing document's +// fields. To delete some fields, use a Merge option with firestore.Delete as the +// field value. +func (d *DocumentRef) Set(ctx context.Context, data interface{}, opts ...SetOption) (*WriteResult, error) { + ws, err := d.newSetWrites(data, opts) + if err != nil { + return nil, err + } + return d.Parent.c.commit1(ctx, ws) +} + +func (d *DocumentRef) newSetWrites(data interface{}, opts []SetOption) ([]*pb.Write, error) { + if d == nil { + return nil, errNilDocRef + } + if data == nil { + return nil, errors.New("firestore: nil document contents") + } + if len(opts) == 0 { // Set without merge + doc, serverTimestampPaths, err := toProtoDocument(data) + if err != nil { + return nil, err + } + doc.Name = d.Path + return d.newUpdateWithTransform(doc, nil, nil, serverTimestampPaths, true), nil + } + // Set with merge. + // This is just like Update, except for the existence precondition. + // So we turn data into a list of (FieldPath, interface{}) pairs (fpv's), as we do + // for Update. + fieldPaths, allPaths, err := processSetOptions(opts) + if err != nil { + return nil, err + } + var fpvs []fpv + v := reflect.ValueOf(data) + if allPaths { + // Set with MergeAll. Collect all the leaves of the map. + if v.Kind() != reflect.Map { + return nil, errors.New("firestore: MergeAll can only be specified with map data") + } + if v.Len() == 0 { + // Special case: MergeAll with an empty map. + return d.newUpdateWithTransform(&pb.Document{Name: d.Path}, []FieldPath{}, nil, nil, true), nil + } + fpvsFromData(v, nil, &fpvs) + } else { + // Set with merge paths. Collect only the values at the given paths. + for _, fp := range fieldPaths { + val, err := getAtPath(v, fp) + if err != nil { + return nil, err + } + fpvs = append(fpvs, fpv{fp, val}) + } + } + return d.fpvsToWrites(fpvs, nil) +} + +// fpvsFromData converts v into a list of (FieldPath, value) pairs. +func fpvsFromData(v reflect.Value, prefix FieldPath, fpvs *[]fpv) { + switch v.Kind() { + case reflect.Map: + for _, k := range v.MapKeys() { + fpvsFromData(v.MapIndex(k), prefix.with(k.String()), fpvs) + } + case reflect.Interface: + fpvsFromData(v.Elem(), prefix, fpvs) + + default: + var val interface{} + if v.IsValid() { + val = v.Interface() + } + *fpvs = append(*fpvs, fpv{prefix, val}) + } +} + +// removePathsIf creates a new slice of FieldPaths that contains +// exactly those elements of fps for which pred returns false. +func removePathsIf(fps []FieldPath, pred func(FieldPath) bool) []FieldPath { + // Return fps if it's empty to preserve the distinction betweeen nil and zero-length. + if len(fps) == 0 { + return fps + } + var result []FieldPath + for _, fp := range fps { + if !pred(fp) { + result = append(result, fp) + } + } + return result +} + +// Delete deletes the document. If the document doesn't exist, it does nothing +// and returns no error. +func (d *DocumentRef) Delete(ctx context.Context, preconds ...Precondition) (*WriteResult, error) { + ws, err := d.newDeleteWrites(preconds) + if err != nil { + return nil, err + } + return d.Parent.c.commit1(ctx, ws) +} + +func (d *DocumentRef) newDeleteWrites(preconds []Precondition) ([]*pb.Write, error) { + if d == nil { + return nil, errNilDocRef + } + pc, err := processPreconditionsForDelete(preconds) + if err != nil { + return nil, err + } + return []*pb.Write{{ + Operation: &pb.Write_Delete{d.Path}, + CurrentDocument: pc, + }}, nil +} + +func (d *DocumentRef) newUpdatePathWrites(updates []Update, preconds []Precondition) ([]*pb.Write, error) { + if len(updates) == 0 { + return nil, errors.New("firestore: no paths to update") + } + var fpvs []fpv + for _, u := range updates { + v, err := u.process() + if err != nil { + return nil, err + } + fpvs = append(fpvs, v) + } + pc, err := processPreconditionsForUpdate(preconds) + if err != nil { + return nil, err + } + return d.fpvsToWrites(fpvs, pc) +} + +func (d *DocumentRef) fpvsToWrites(fpvs []fpv, pc *pb.Precondition) ([]*pb.Write, error) { + // Make sure there are no duplications or prefixes among the field paths. + var fps []FieldPath + for _, fpv := range fpvs { + fps = append(fps, fpv.fieldPath) + } + if err := checkNoDupOrPrefix(fps); err != nil { + return nil, err + } + + // Process each fpv. + var updatePaths []FieldPath + var transforms []*pb.DocumentTransform_FieldTransform + doc := &pb.Document{ + Name: d.Path, + Fields: map[string]*pb.Value{}, + } + for _, fpv := range fpvs { + switch fpv.value.(type) { + case arrayUnion: + au := fpv.value.(arrayUnion) + t, err := arrayUnionTransform(au, fpv.fieldPath) + if err != nil { + return nil, err + } + transforms = append(transforms, t) + case arrayRemove: + ar := fpv.value.(arrayRemove) + t, err := arrayRemoveTransform(ar, fpv.fieldPath) + if err != nil { + return nil, err + } + transforms = append(transforms, t) + default: + switch fpv.value { + case Delete: + // Send the field path without a corresponding value. + updatePaths = append(updatePaths, fpv.fieldPath) + + case ServerTimestamp: + // Use the path in a transform operation. + transforms = append(transforms, serverTimestamp(fpv.fieldPath.toServiceFieldPath())) + + default: + updatePaths = append(updatePaths, fpv.fieldPath) + // Convert the value to a proto and put it into the document. + v := reflect.ValueOf(fpv.value) + + pv, _, err := toProtoValue(v) + if err != nil { + return nil, err + } + setAtPath(doc.Fields, fpv.fieldPath, pv) + // Also accumulate any transforms within the value. + ts, err := extractTransforms(v, fpv.fieldPath) + if err != nil { + return nil, err + } + transforms = append(transforms, ts...) + } + } + } + return d.newUpdateWithTransform(doc, updatePaths, pc, transforms, false), nil +} + +// newUpdateWithTransform constructs operations for a commit. Most generally, it +// returns an update operation followed by a transform. +// +// If there are no serverTimestampPaths, the transform is omitted. +// +// If doc.Fields is empty, there are no updatePaths, and there is no precondition, +// the update is omitted, unless updateOnEmpty is true. +func (d *DocumentRef) newUpdateWithTransform(doc *pb.Document, updatePaths []FieldPath, pc *pb.Precondition, transforms []*pb.DocumentTransform_FieldTransform, updateOnEmpty bool) []*pb.Write { + var ws []*pb.Write + if updateOnEmpty || len(doc.Fields) > 0 || + len(updatePaths) > 0 || (pc != nil && len(transforms) == 0) { + var mask *pb.DocumentMask + if updatePaths != nil { + sfps := toServiceFieldPaths(updatePaths) + sort.Strings(sfps) // TODO(jba): make tests pass without this + mask = &pb.DocumentMask{FieldPaths: sfps} + } + w := &pb.Write{ + Operation: &pb.Write_Update{doc}, + UpdateMask: mask, + CurrentDocument: pc, + } + ws = append(ws, w) + pc = nil // If the precondition is in the write, we don't need it in the transform. + } + if len(transforms) > 0 || pc != nil { + ws = append(ws, &pb.Write{ + Operation: &pb.Write_Transform{ + Transform: &pb.DocumentTransform{ + Document: d.Path, + FieldTransforms: transforms, + }, + }, + CurrentDocument: pc, + }) + } + return ws +} + +// This helper turns server timestamp fields into a transform proto. +func (d *DocumentRef) newServerTimestampTransform(serverTimestampFieldPaths []FieldPath, pc *pb.Precondition) *pb.Write { + sort.Sort(byPath(serverTimestampFieldPaths)) // TODO(jba): make tests pass without this + var fts []*pb.DocumentTransform_FieldTransform + for _, p := range serverTimestampFieldPaths { + fts = append(fts, serverTimestamp(p.toServiceFieldPath())) + } + return &pb.Write{ + Operation: &pb.Write_Transform{ + &pb.DocumentTransform{ + Document: d.Path, + FieldTransforms: fts, + // TODO(jba): should the transform have the same preconditions as the write? + }, + }, + CurrentDocument: pc, + } +} + +// arrayUnion is a special type in firestore. It instructs the server to add its +// elements to whatever array already exists, or to create an array if no value +// exists. +type arrayUnion struct { + elems []interface{} +} + +// ArrayUnion specifies elements to be added to whatever array already exists in +// the server, or to create an array if no value exists. +// +// If a value exists and it's an array, values are appended to it. Any duplicate +// value is ignored. +// If a value exists and it's not an array, the value is replaced by an array of +// the values in the ArrayUnion. +// If a value does not exist, an array of the values in the ArrayUnion is created. +// +// ArrayUnion must be the value of a field directly; it cannot appear in +// array or struct values, or in any value that is itself inside an array or +// struct. +func ArrayUnion(elems ...interface{}) arrayUnion { + return arrayUnion{elems: elems} +} + +// This helper converts an arrayUnion into a proto object. +func arrayUnionTransform(au arrayUnion, fp FieldPath) (*pb.DocumentTransform_FieldTransform, error) { + var elems []*pb.Value + for _, v := range au.elems { + pv, _, err := toProtoValue(reflect.ValueOf(v)) + if err != nil { + return nil, err + } + elems = append(elems, pv) + } + return &pb.DocumentTransform_FieldTransform{ + FieldPath: fp.toServiceFieldPath(), + TransformType: &pb.DocumentTransform_FieldTransform_AppendMissingElements{ + AppendMissingElements: &pb.ArrayValue{Values: elems}, + }, + }, nil +} + +// arrayRemove is a special type in firestore. It instructs the server to remove +// the specified values. +type arrayRemove struct { + elems []interface{} +} + +// ArrayRemove specifies elements to be removed from whatever array already +// exists in the server. +// +// If a value exists and it's an array, values are removed from it. All +// duplicate values are removed. +// If a value exists and it's not an array, the value is replaced by an empty +// array. +// If a value does not exist, an empty array is created. +// +// ArrayRemove must be the value of a field directly; it cannot appear in +// array or struct values, or in any value that is itself inside an array or +// struct. +func ArrayRemove(elems ...interface{}) arrayRemove { + return arrayRemove{elems: elems} +} + +// This helper converts an arrayRemove into a proto object. +func arrayRemoveTransform(ar arrayRemove, fp FieldPath) (*pb.DocumentTransform_FieldTransform, error) { + var elems []*pb.Value + for _, v := range ar.elems { + // ServerTimestamp cannot occur in an array, so we ignore transformations here. + pv, _, err := toProtoValue(reflect.ValueOf(v)) + if err != nil { + return nil, err + } + elems = append(elems, pv) + } + return &pb.DocumentTransform_FieldTransform{ + FieldPath: fp.toServiceFieldPath(), + TransformType: &pb.DocumentTransform_FieldTransform_RemoveAllFromArray{ + RemoveAllFromArray: &pb.ArrayValue{Values: elems}, + }, + }, nil +} + +type sentinel int + +const ( + // Delete is used as a value in a call to Update or Set with merge to indicate + // that the corresponding key should be deleted. + Delete sentinel = iota + + // ServerTimestamp is used as a value in a call to Update to indicate that the + // key's value should be set to the time at which the server processed + // the request. + // + // ServerTimestamp must be the value of a field directly; it cannot appear in + // array or struct values, or in any value that is itself inside an array or + // struct. + ServerTimestamp +) + +func (s sentinel) String() string { + switch s { + case Delete: + return "Delete" + case ServerTimestamp: + return "ServerTimestamp" + default: + return "" + } +} + +// An Update describes an update to a value referred to by a path. +// An Update should have either a non-empty Path or a non-empty FieldPath, +// but not both. +// +// See DocumentRef.Create for acceptable values. +// To delete a field, specify firestore.Delete as the value. +type Update struct { + Path string // Will be split on dots, and must not contain any of "˜*/[]". + FieldPath FieldPath + Value interface{} +} + +// An fpv is a pair of validated FieldPath and value. +type fpv struct { + fieldPath FieldPath + value interface{} +} + +func (u *Update) process() (fpv, error) { + if (u.Path != "") == (u.FieldPath != nil) { + return fpv{}, fmt.Errorf("firestore: update %+v should have exactly one of Path or FieldPath", u) + } + fp := u.FieldPath + var err error + if fp == nil { + fp, err = parseDotSeparatedString(u.Path) + if err != nil { + return fpv{}, err + } + } + if err := fp.validate(); err != nil { + return fpv{}, err + } + return fpv{fp, u.Value}, nil +} + +// Update updates the document. The values at the given +// field paths are replaced, but other fields of the stored document are untouched. +func (d *DocumentRef) Update(ctx context.Context, updates []Update, preconds ...Precondition) (*WriteResult, error) { + ws, err := d.newUpdatePathWrites(updates, preconds) + if err != nil { + return nil, err + } + return d.Parent.c.commit1(ctx, ws) +} + +// Collections returns an interator over the immediate sub-collections of the document. +func (d *DocumentRef) Collections(ctx context.Context) *CollectionIterator { + client := d.Parent.c + it := &CollectionIterator{ + err: checkTransaction(ctx), + client: client, + parent: d, + it: client.c.ListCollectionIds( + withResourceHeader(ctx, client.path()), + &pb.ListCollectionIdsRequest{Parent: d.Path}), + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.items) }, + func() interface{} { b := it.items; it.items = nil; return b }) + return it +} + +// CollectionIterator is an iterator over sub-collections of a document. +type CollectionIterator struct { + client *Client + parent *DocumentRef + it *vkit.StringIterator + pageInfo *iterator.PageInfo + nextFunc func() error + items []*CollectionRef + err error +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *CollectionIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } + +// Next returns the next result. Its second return value is iterator.Done if there +// are no more results. Once Next returns Done, all subsequent calls will return +// Done. +func (it *CollectionIterator) Next() (*CollectionRef, error) { + if err := it.nextFunc(); err != nil { + return nil, err + } + item := it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *CollectionIterator) fetch(pageSize int, pageToken string) (string, error) { + if it.err != nil { + return "", it.err + } + return iterFetch(pageSize, pageToken, it.it.PageInfo(), func() error { + id, err := it.it.Next() + if err != nil { + return err + } + var cr *CollectionRef + if it.parent == nil { + cr = newTopLevelCollRef(it.client, it.client.path(), id) + } else { + cr = newCollRefWithParent(it.client, it.parent, id) + } + it.items = append(it.items, cr) + return nil + }) +} + +// GetAll returns all the collections remaining from the iterator. +func (it *CollectionIterator) GetAll() ([]*CollectionRef, error) { + var crs []*CollectionRef + for { + cr, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + return nil, err + } + crs = append(crs, cr) + } + return crs, nil +} + +// Common fetch code for iterators that are backed by vkit iterators. +// TODO(jba): dedup with same function in logging/logadmin. +func iterFetch(pageSize int, pageToken string, pi *iterator.PageInfo, next func() error) (string, error) { + pi.MaxSize = pageSize + pi.Token = pageToken + // Get one item, which will fill the buffer. + if err := next(); err != nil { + return "", err + } + // Collect the rest of the buffer. + for pi.Remaining() > 0 { + if err := next(); err != nil { + return "", err + } + } + return pi.Token, nil +} + +// Snapshots returns an iterator over snapshots of the document. Each time the document +// changes or is added or deleted, a new snapshot will be generated. +func (d *DocumentRef) Snapshots(ctx context.Context) *DocumentSnapshotIterator { + return &DocumentSnapshotIterator{ + docref: d, + ws: newWatchStreamForDocument(ctx, d), + } +} + +// DocumentSnapshotIterator is an iterator over snapshots of a document. +// Call Next on the iterator to get a snapshot of the document each time it changes. +// Call Stop on the iterator when done. +// +// For an example, see DocumentRef.Snapshots. +type DocumentSnapshotIterator struct { + docref *DocumentRef + ws *watchStream +} + +// Next blocks until the document changes, then returns the DocumentSnapshot for +// the current state of the document. If the document has been deleted, Next +// returns a DocumentSnapshot whose Exists method returns false. +// +// Next never returns iterator.Done unless it is called after Stop. +func (it *DocumentSnapshotIterator) Next() (*DocumentSnapshot, error) { + btree, _, readTime, err := it.ws.nextSnapshot() + if err != nil { + if err == io.EOF { + err = iterator.Done + } + // watchStream's error is sticky, so SnapshotIterator does not need to remember it. + return nil, err + } + if btree.Len() == 0 { // document deleted + return &DocumentSnapshot{Ref: it.docref, ReadTime: readTime}, nil + } + snap, _ := btree.At(0) + return snap.(*DocumentSnapshot), nil +} + +// Stop stops receiving snapshots. You should always call Stop when you are done with +// a DocumentSnapshotIterator, to free up resources. It is not safe to call Stop +// concurrently with Next. +func (it *DocumentSnapshotIterator) Stop() { + it.ws.stop() +} diff --git a/vendor/cloud.google.com/go/firestore/docref_test.go b/vendor/cloud.google.com/go/firestore/docref_test.go new file mode 100644 index 00000000..cda97a00 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/docref_test.go @@ -0,0 +1,311 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "reflect" + "sort" + "testing" + "time" + + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/genproto/googleapis/type/latlng" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" +) + +var ( + writeResultForSet = &WriteResult{UpdateTime: aTime} + commitResponseForSet = &pb.CommitResponse{ + WriteResults: []*pb.WriteResult{{UpdateTime: aTimestamp}}, + } +) + +func TestDocGet(t *testing.T) { + ctx := context.Background() + c, srv := newMock(t) + path := "projects/projectID/databases/(default)/documents/C/a" + pdoc := &pb.Document{ + Name: path, + CreateTime: aTimestamp, + UpdateTime: aTimestamp, + Fields: map[string]*pb.Value{"f": intval(1)}, + } + srv.addRPC(&pb.BatchGetDocumentsRequest{ + Database: c.path(), + Documents: []string{path}, + }, []interface{}{ + &pb.BatchGetDocumentsResponse{ + Result: &pb.BatchGetDocumentsResponse_Found{pdoc}, + ReadTime: aTimestamp2, + }, + }) + ref := c.Collection("C").Doc("a") + gotDoc, err := ref.Get(ctx) + if err != nil { + t.Fatal(err) + } + wantDoc := &DocumentSnapshot{ + Ref: ref, + CreateTime: aTime, + UpdateTime: aTime, + ReadTime: aTime2, + proto: pdoc, + c: c, + } + if !testEqual(gotDoc, wantDoc) { + t.Fatalf("\ngot %+v\nwant %+v", gotDoc, wantDoc) + } + + path2 := "projects/projectID/databases/(default)/documents/C/b" + srv.addRPC( + &pb.BatchGetDocumentsRequest{ + Database: c.path(), + Documents: []string{path2}, + }, []interface{}{ + &pb.BatchGetDocumentsResponse{ + Result: &pb.BatchGetDocumentsResponse_Missing{path2}, + ReadTime: aTimestamp3, + }, + }) + _, err = c.Collection("C").Doc("b").Get(ctx) + if grpc.Code(err) != codes.NotFound { + t.Errorf("got %v, want NotFound", err) + } +} + +func TestDocSet(t *testing.T) { + // Most tests for Set are in the conformance tests. + ctx := context.Background() + c, srv := newMock(t) + + doc := c.Collection("C").Doc("d") + // Merge with a struct and FieldPaths. + srv.addRPC(&pb.CommitRequest{ + Database: "projects/projectID/databases/(default)", + Writes: []*pb.Write{ + { + Operation: &pb.Write_Update{ + Update: &pb.Document{ + Name: "projects/projectID/databases/(default)/documents/C/d", + Fields: map[string]*pb.Value{ + "*": mapval(map[string]*pb.Value{ + "~": boolval(true), + }), + }, + }, + }, + UpdateMask: &pb.DocumentMask{FieldPaths: []string{"`*`.`~`"}}, + }, + }, + }, commitResponseForSet) + data := struct { + A map[string]bool `firestore:"*"` + }{A: map[string]bool{"~": true}} + wr, err := doc.Set(ctx, data, Merge([]string{"*", "~"})) + if err != nil { + t.Fatal(err) + } + if !testEqual(wr, writeResultForSet) { + t.Errorf("got %v, want %v", wr, writeResultForSet) + } + + // MergeAll cannot be used with structs. + _, err = doc.Set(ctx, data, MergeAll) + if err == nil { + t.Errorf("got nil, want error") + } +} + +func TestDocCreate(t *testing.T) { + // Verify creation with structs. In particular, make sure zero values + // are handled well. + // Other tests for Create are handled by the conformance tests. + ctx := context.Background() + c, srv := newMock(t) + + type create struct { + Time time.Time + Bytes []byte + Geo *latlng.LatLng + } + srv.addRPC( + &pb.CommitRequest{ + Database: "projects/projectID/databases/(default)", + Writes: []*pb.Write{ + { + Operation: &pb.Write_Update{ + Update: &pb.Document{ + Name: "projects/projectID/databases/(default)/documents/C/d", + Fields: map[string]*pb.Value{ + "Time": tsval(time.Time{}), + "Bytes": bytesval(nil), + "Geo": nullValue, + }, + }, + }, + CurrentDocument: &pb.Precondition{ + ConditionType: &pb.Precondition_Exists{false}, + }, + }, + }, + }, + commitResponseForSet, + ) + _, err := c.Collection("C").Doc("d").Create(ctx, &create{}) + if err != nil { + t.Fatal(err) + } +} + +func TestDocDelete(t *testing.T) { + ctx := context.Background() + c, srv := newMock(t) + srv.addRPC( + &pb.CommitRequest{ + Database: "projects/projectID/databases/(default)", + Writes: []*pb.Write{ + {Operation: &pb.Write_Delete{"projects/projectID/databases/(default)/documents/C/d"}}, + }, + }, + &pb.CommitResponse{ + WriteResults: []*pb.WriteResult{{}}, + }) + wr, err := c.Collection("C").Doc("d").Delete(ctx) + if err != nil { + t.Fatal(err) + } + if !testEqual(wr, &WriteResult{}) { + t.Errorf("got %+v, want %+v", wr, writeResultForSet) + } +} + +var ( + testData = map[string]interface{}{"a": 1} + testFields = map[string]*pb.Value{"a": intval(1)} +) + +// Update is tested by the conformance tests. + +func TestFPVsFromData(t *testing.T) { + type S struct{ X int } + + for _, test := range []struct { + in interface{} + want []fpv + }{ + { + in: nil, + want: []fpv{{nil, nil}}, + }, + { + in: map[string]interface{}{"a": nil}, + want: []fpv{{[]string{"a"}, nil}}, + }, + { + in: map[string]interface{}{"a": 1}, + want: []fpv{{[]string{"a"}, 1}}, + }, + { + in: map[string]interface{}{ + "a": 1, + "b": map[string]interface{}{"c": 2}, + }, + want: []fpv{{[]string{"a"}, 1}, {[]string{"b", "c"}, 2}}, + }, + { + in: map[string]interface{}{"s": &S{X: 3}}, + want: []fpv{{[]string{"s"}, &S{X: 3}}}, + }, + } { + var got []fpv + fpvsFromData(reflect.ValueOf(test.in), nil, &got) + sort.Sort(byFieldPath(got)) + if !testEqual(got, test.want) { + t.Errorf("%+v: got %v, want %v", test.in, got, test.want) + } + } +} + +type byFieldPath []fpv + +func (b byFieldPath) Len() int { return len(b) } +func (b byFieldPath) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byFieldPath) Less(i, j int) bool { return b[i].fieldPath.less(b[j].fieldPath) } + +func commitRequestForSet() *pb.CommitRequest { + return &pb.CommitRequest{ + Database: "projects/projectID/databases/(default)", + Writes: []*pb.Write{ + { + Operation: &pb.Write_Update{ + Update: &pb.Document{ + Name: "projects/projectID/databases/(default)/documents/C/d", + Fields: testFields, + }, + }, + }, + }, + } +} + +func TestUpdateProcess(t *testing.T) { + for _, test := range []struct { + in Update + want fpv + wantErr bool + }{ + { + in: Update{Path: "a", Value: 1}, + want: fpv{fieldPath: []string{"a"}, value: 1}, + }, + { + in: Update{Path: "c.d", Value: Delete}, + want: fpv{fieldPath: []string{"c", "d"}, value: Delete}, + }, + { + in: Update{FieldPath: []string{"*", "~"}, Value: ServerTimestamp}, + want: fpv{fieldPath: []string{"*", "~"}, value: ServerTimestamp}, + }, + { + in: Update{Path: "*"}, + wantErr: true, // bad rune in path + }, + { + in: Update{Path: "a", FieldPath: []string{"b"}}, + wantErr: true, // both Path and FieldPath + }, + { + in: Update{Value: 1}, + wantErr: true, // neither Path nor FieldPath + }, + { + in: Update{FieldPath: []string{"", "a"}}, + wantErr: true, // empty FieldPath component + }, + } { + got, err := test.in.process() + if test.wantErr { + if err == nil { + t.Errorf("%+v: got nil, want error", test.in) + } + } else if err != nil { + t.Errorf("%+v: got error %v, want nil", test.in, err) + } else if !testEqual(got, test.want) { + t.Errorf("%+v: got %+v, want %+v", test.in, got, test.want) + } + } +} diff --git a/vendor/cloud.google.com/go/firestore/document.go b/vendor/cloud.google.com/go/firestore/document.go new file mode 100644 index 00000000..75063acc --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/document.go @@ -0,0 +1,322 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "errors" + "fmt" + "reflect" + "time" + + "github.com/golang/protobuf/ptypes" + tspb "github.com/golang/protobuf/ptypes/timestamp" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// A DocumentSnapshot contains document data and metadata. +type DocumentSnapshot struct { + // The DocumentRef for this document. + Ref *DocumentRef + + // Read-only. The time at which the document was created. + // Increases monotonically when a document is deleted then + // recreated. It can also be compared to values from other documents and + // the read time of a query. + CreateTime time.Time + + // Read-only. The time at which the document was last changed. This value + // is initially set to CreateTime then increases monotonically with each + // change to the document. It can also be compared to values from other + // documents and the read time of a query. + UpdateTime time.Time + + // Read-only. The time at which the document was read. + ReadTime time.Time + + c *Client + proto *pb.Document +} + +// Exists reports whether the DocumentSnapshot represents an existing document. +// Even if Exists returns false, the Ref and ReadTime fields of the DocumentSnapshot +// are valid. +func (d *DocumentSnapshot) Exists() bool { + return d.proto != nil +} + +// Data returns the DocumentSnapshot's fields as a map. +// It is equivalent to +// var m map[string]interface{} +// d.DataTo(&m) +// except that it returns nil if the document does not exist. +func (d *DocumentSnapshot) Data() map[string]interface{} { + if !d.Exists() { + return nil + } + m, err := createMapFromValueMap(d.proto.Fields, d.c) + // Any error here is a bug in the client. + if err != nil { + panic(fmt.Sprintf("firestore: %v", err)) + } + return m +} + +// DataTo uses the document's fields to populate p, which can be a pointer to a +// map[string]interface{} or a pointer to a struct. +// +// Firestore field values are converted to Go values as follows: +// - Null converts to nil. +// - Bool converts to bool. +// - String converts to string. +// - Integer converts int64. When setting a struct field, any signed or unsigned +// integer type is permitted except uint64. Overflow is detected and results in +// an error. +// - Double converts to float64. When setting a struct field, float32 is permitted. +// Overflow is detected and results in an error. +// - Bytes is converted to []byte. +// - Timestamp converts to time.Time. +// - GeoPoint converts to *latlng.LatLng, where latlng is the package +// "google.golang.org/genproto/googleapis/type/latlng". +// - Arrays convert to []interface{}. When setting a struct field, the field +// may be a slice or array of any type and is populated recursively. +// Slices are resized to the incoming value's size, while arrays that are too +// long have excess elements filled with zero values. If the array is too short, +// excess incoming values will be dropped. +// - Maps convert to map[string]interface{}. When setting a struct field, +// maps of key type string and any value type are permitted, and are populated +// recursively. +// - References are converted to *firestore.DocumentRefs. +// +// Field names given by struct field tags are observed, as described in +// DocumentRef.Create. +// +// Only the fields actually present in the document are used to populate p. Other fields +// of p are left unchanged. +// +// If the document does not exist, DataTo returns a NotFound error. +func (d *DocumentSnapshot) DataTo(p interface{}) error { + if !d.Exists() { + return status.Errorf(codes.NotFound, "document %s does not exist", d.Ref.Path) + } + return setFromProtoValue(p, &pb.Value{ValueType: &pb.Value_MapValue{&pb.MapValue{Fields: d.proto.Fields}}}, d.c) +} + +// DataAt returns the data value denoted by path. +// +// The path argument can be a single field or a dot-separated sequence of +// fields, and must not contain any of the runes "˜*/[]". Use DataAtPath instead for +// such a path. +// +// See DocumentSnapshot.DataTo for how Firestore values are converted to Go values. +// +// If the document does not exist, DataAt returns a NotFound error. +func (d *DocumentSnapshot) DataAt(path string) (interface{}, error) { + if !d.Exists() { + return nil, status.Errorf(codes.NotFound, "document %s does not exist", d.Ref.Path) + } + fp, err := parseDotSeparatedString(path) + if err != nil { + return nil, err + } + return d.DataAtPath(fp) +} + +// DataAtPath returns the data value denoted by the FieldPath fp. +// If the document does not exist, DataAtPath returns a NotFound error. +func (d *DocumentSnapshot) DataAtPath(fp FieldPath) (interface{}, error) { + if !d.Exists() { + return nil, status.Errorf(codes.NotFound, "document %s does not exist", d.Ref.Path) + } + v, err := valueAtPath(fp, d.proto.Fields) + if err != nil { + return nil, err + } + return createFromProtoValue(v, d.c) +} + +// valueAtPath returns the value of m referred to by fp. +func valueAtPath(fp FieldPath, m map[string]*pb.Value) (*pb.Value, error) { + for _, k := range fp[:len(fp)-1] { + v := m[k] + if v == nil { + return nil, fmt.Errorf("firestore: no field %q", k) + } + mv := v.GetMapValue() + if mv == nil { + return nil, fmt.Errorf("firestore: value for field %q is not a map", k) + } + m = mv.Fields + } + k := fp[len(fp)-1] + v := m[k] + if v == nil { + return nil, fmt.Errorf("firestore: no field %q", k) + } + return v, nil +} + +// toProtoDocument converts a Go value to a Document proto. +// Valid values are: map[string]T, struct, or pointer to a valid value. +// It also returns a list DocumentTransforms. +func toProtoDocument(x interface{}) (*pb.Document, []*pb.DocumentTransform_FieldTransform, error) { + if x == nil { + return nil, nil, errors.New("firestore: nil document contents") + } + v := reflect.ValueOf(x) + pv, _, err := toProtoValue(v) + if err != nil { + return nil, nil, err + } + var transforms []*pb.DocumentTransform_FieldTransform + transforms, err = extractTransforms(v, nil) + if err != nil { + return nil, nil, err + } + var fields map[string]*pb.Value + if pv != nil { + m := pv.GetMapValue() + if m == nil { + return nil, nil, fmt.Errorf("firestore: cannot convert value of type %T into a map", x) + } + fields = m.Fields + } + return &pb.Document{Fields: fields}, transforms, nil +} + +func extractTransforms(v reflect.Value, prefix FieldPath) ([]*pb.DocumentTransform_FieldTransform, error) { + switch v.Kind() { + case reflect.Map: + return extractTransformsFromMap(v, prefix) + case reflect.Struct: + return extractTransformsFromStruct(v, prefix) + case reflect.Ptr: + if v.IsNil() { + return nil, nil + } + return extractTransforms(v.Elem(), prefix) + case reflect.Interface: + if v.NumMethod() == 0 { // empty interface: recurse on its contents + return extractTransforms(v.Elem(), prefix) + } + return nil, nil + default: + return nil, nil + } +} + +func extractTransformsFromMap(v reflect.Value, prefix FieldPath) ([]*pb.DocumentTransform_FieldTransform, error) { + var transforms []*pb.DocumentTransform_FieldTransform + for _, k := range v.MapKeys() { + sk := k.Interface().(string) // assume keys are strings; checked in toProtoValue + path := prefix.with(sk) + mi := v.MapIndex(k) + if mi.Interface() == ServerTimestamp { + transforms = append(transforms, serverTimestamp(path.toServiceFieldPath())) + } else if au, ok := mi.Interface().(arrayUnion); ok { + t, err := arrayUnionTransform(au, path) + if err != nil { + return nil, err + } + transforms = append(transforms, t) + } else if ar, ok := mi.Interface().(arrayRemove); ok { + t, err := arrayRemoveTransform(ar, path) + if err != nil { + return nil, err + } + transforms = append(transforms, t) + } else { + ps, err := extractTransforms(mi, path) + if err != nil { + return nil, err + } + transforms = append(transforms, ps...) + } + } + return transforms, nil +} + +func extractTransformsFromStruct(v reflect.Value, prefix FieldPath) ([]*pb.DocumentTransform_FieldTransform, error) { + var transforms []*pb.DocumentTransform_FieldTransform + fields, err := fieldCache.Fields(v.Type()) + if err != nil { + return nil, err + } + for _, f := range fields { + fv := v.FieldByIndex(f.Index) + path := prefix.with(f.Name) + opts := f.ParsedTag.(tagOptions) + if opts.serverTimestamp { + var isZero bool + switch f.Type { + case typeOfGoTime: + isZero = fv.Interface().(time.Time).IsZero() + case reflect.PtrTo(typeOfGoTime): + isZero = fv.IsNil() || fv.Elem().Interface().(time.Time).IsZero() + default: + return nil, fmt.Errorf("firestore: field %s of struct %s with serverTimestamp tag must be of type time.Time or *time.Time", + f.Name, v.Type()) + } + if isZero { + transforms = append(transforms, serverTimestamp(path.toServiceFieldPath())) + } + } else { + ps, err := extractTransforms(fv, path) + if err != nil { + return nil, err + } + transforms = append(transforms, ps...) + } + } + return transforms, nil +} + +func newDocumentSnapshot(ref *DocumentRef, proto *pb.Document, c *Client, readTime *tspb.Timestamp) (*DocumentSnapshot, error) { + d := &DocumentSnapshot{ + Ref: ref, + c: c, + proto: proto, + } + if proto != nil { + ts, err := ptypes.Timestamp(proto.CreateTime) + if err != nil { + return nil, err + } + d.CreateTime = ts + ts, err = ptypes.Timestamp(proto.UpdateTime) + if err != nil { + return nil, err + } + d.UpdateTime = ts + } + if readTime != nil { + ts, err := ptypes.Timestamp(readTime) + if err != nil { + return nil, err + } + d.ReadTime = ts + } + return d, nil +} + +func serverTimestamp(path string) *pb.DocumentTransform_FieldTransform { + return &pb.DocumentTransform_FieldTransform{ + FieldPath: path, + TransformType: &pb.DocumentTransform_FieldTransform_SetToServerValue{ + SetToServerValue: pb.DocumentTransform_FieldTransform_REQUEST_TIME, + }, + } +} diff --git a/vendor/cloud.google.com/go/firestore/document_test.go b/vendor/cloud.google.com/go/firestore/document_test.go new file mode 100644 index 00000000..c4e57dfc --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/document_test.go @@ -0,0 +1,300 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "reflect" + "sort" + "strings" + "testing" + "time" + + tspb "github.com/golang/protobuf/ptypes/timestamp" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +func TestToProtoDocument(t *testing.T) { + type s struct{ I int } + + for _, test := range []struct { + in interface{} + want *pb.Document + wantErr bool + }{ + {nil, nil, true}, + {[]int{1}, nil, true}, + {map[string]int{"a": 1}, + &pb.Document{Fields: map[string]*pb.Value{"a": intval(1)}}, + false}, + {s{2}, &pb.Document{Fields: map[string]*pb.Value{"I": intval(2)}}, false}, + {&s{3}, &pb.Document{Fields: map[string]*pb.Value{"I": intval(3)}}, false}, + } { + got, _, gotErr := toProtoDocument(test.in) + if (gotErr != nil) != test.wantErr { + t.Errorf("%v: got error %v, want %t", test.in, gotErr, test.wantErr) + } + if gotErr != nil { + continue + } + if !testEqual(got, test.want) { + t.Errorf("%v: got %v, want %v", test.in, got, test.want) + } + } +} + +func TestNewDocumentSnapshot(t *testing.T) { + c := &Client{ + projectID: "projID", + databaseID: "(database)", + } + docRef := c.Doc("C/a") + in := &pb.Document{ + CreateTime: &tspb.Timestamp{Seconds: 10}, + UpdateTime: &tspb.Timestamp{Seconds: 20}, + Fields: map[string]*pb.Value{"a": intval(1)}, + } + want := &DocumentSnapshot{ + Ref: docRef, + CreateTime: time.Unix(10, 0).UTC(), + UpdateTime: time.Unix(20, 0).UTC(), + ReadTime: aTime, + proto: in, + c: c, + } + got, err := newDocumentSnapshot(docRef, in, c, aTimestamp) + if err != nil { + t.Fatal(err) + } + if !testEqual(got, want) { + t.Errorf("got %+v\nwant %+v", got, want) + } +} + +func TestData(t *testing.T) { + doc := &DocumentSnapshot{ + proto: &pb.Document{ + Fields: map[string]*pb.Value{"a": intval(1), "b": strval("x")}, + }, + } + got := doc.Data() + want := map[string]interface{}{"a": int64(1), "b": "x"} + if !testEqual(got, want) { + t.Errorf("got %#v\nwant %#v", got, want) + } + var got2 map[string]interface{} + if err := doc.DataTo(&got2); err != nil { + t.Fatal(err) + } + if !testEqual(got2, want) { + t.Errorf("got %#v\nwant %#v", got2, want) + } + + type s struct { + A int + B string + } + var got3 s + if err := doc.DataTo(&got3); err != nil { + t.Fatal(err) + } + want2 := s{A: 1, B: "x"} + if !testEqual(got3, want2) { + t.Errorf("got %#v\nwant %#v", got3, want2) + } +} + +var testDoc = &DocumentSnapshot{ + proto: &pb.Document{ + Fields: map[string]*pb.Value{ + "a": intval(1), + "b": mapval(map[string]*pb.Value{ + "`": intval(2), + "~": mapval(map[string]*pb.Value{ + "x": intval(3), + }), + }), + }, + }, +} + +func TestDataAt(t *testing.T) { + for _, test := range []struct { + fieldPath string + want interface{} + }{ + {"a", int64(1)}, + {"b.`", int64(2)}, + } { + got, err := testDoc.DataAt(test.fieldPath) + if err != nil { + t.Errorf("%q: %v", test.fieldPath, err) + continue + } + if !testEqual(got, test.want) { + t.Errorf("%q: got %v, want %v", test.fieldPath, got, test.want) + } + } + + for _, bad := range []string{ + "c.~.x", // bad field path + "a.b", // "a" isn't a map + "z.b", // bad non-final key + "b.z", // bad final key + } { + _, err := testDoc.DataAt(bad) + if err == nil { + t.Errorf("%q: got nil, want error", bad) + } + } +} + +func TestDataAtPath(t *testing.T) { + for _, test := range []struct { + fieldPath FieldPath + want interface{} + }{ + {[]string{"a"}, int64(1)}, + {[]string{"b", "`"}, int64(2)}, + {[]string{"b", "~"}, map[string]interface{}{"x": int64(3)}}, + {[]string{"b", "~", "x"}, int64(3)}, + } { + got, err := testDoc.DataAtPath(test.fieldPath) + if err != nil { + t.Errorf("%v: %v", test.fieldPath, err) + continue + } + if !testEqual(got, test.want) { + t.Errorf("%v: got %v, want %v", test.fieldPath, got, test.want) + } + } + + for _, bad := range []FieldPath{ + []string{"c", "", "x"}, // bad field path + []string{"a", "b"}, // "a" isn't a map + []string{"z", "~"}, // bad non-final key + []string{"b", "z"}, // bad final key + } { + _, err := testDoc.DataAtPath(bad) + if err == nil { + t.Errorf("%v: got nil, want error", bad) + } + } +} + +func TestExtractTransforms(t *testing.T) { + type S struct { + A time.Time `firestore:",serverTimestamp"` + B time.Time `firestore:",serverTimestamp"` + C *time.Time `firestore:",serverTimestamp"` + D *time.Time `firestore:"d.d,serverTimestamp"` + E *time.Time `firestore:",serverTimestamp"` + F time.Time + G int + } + + m := map[string]interface{}{ + "ar": map[string]interface{}{"k2": ArrayRemove("e", "f", "g")}, + "au": map[string]interface{}{"k1": ArrayUnion("a", "b", "c")}, + "x": 1, + "y": &S{ + // A is a zero time: included + B: aTime, // not a zero time: excluded + //C is nil: included + D: &time.Time{}, // pointer to a zero time: included + E: &aTime, // pointer to a non-zero time: excluded + //F is a zero time, but does not have the right tag: excluded + G: 15, // not a time.Time + }, + "z": map[string]interface{}{"w": ServerTimestamp}, + } + got, err := extractTransforms(reflect.ValueOf(m), nil) + if err != nil { + t.Fatal(err) + } + want := []*pb.DocumentTransform_FieldTransform{ + { + FieldPath: "ar.k2", + TransformType: &pb.DocumentTransform_FieldTransform_RemoveAllFromArray{ + RemoveAllFromArray: &pb.ArrayValue{Values: []*pb.Value{ + {ValueType: &pb.Value_StringValue{"e"}}, + {ValueType: &pb.Value_StringValue{"f"}}, + {ValueType: &pb.Value_StringValue{"g"}}, + }}, + }, + }, + { + FieldPath: "au.k1", + TransformType: &pb.DocumentTransform_FieldTransform_AppendMissingElements{ + AppendMissingElements: &pb.ArrayValue{Values: []*pb.Value{ + {ValueType: &pb.Value_StringValue{"a"}}, + {ValueType: &pb.Value_StringValue{"b"}}, + {ValueType: &pb.Value_StringValue{"c"}}, + }}, + }, + }, + { + FieldPath: "y.A", + TransformType: &pb.DocumentTransform_FieldTransform_SetToServerValue{ + SetToServerValue: pb.DocumentTransform_FieldTransform_REQUEST_TIME, + }, + }, + { + FieldPath: "y.C", + TransformType: &pb.DocumentTransform_FieldTransform_SetToServerValue{ + SetToServerValue: pb.DocumentTransform_FieldTransform_REQUEST_TIME, + }, + }, + { + FieldPath: "y.`d.d`", + TransformType: &pb.DocumentTransform_FieldTransform_SetToServerValue{ + SetToServerValue: pb.DocumentTransform_FieldTransform_REQUEST_TIME, + }, + }, + { + FieldPath: "z.w", + TransformType: &pb.DocumentTransform_FieldTransform_SetToServerValue{ + SetToServerValue: pb.DocumentTransform_FieldTransform_REQUEST_TIME, + }, + }, + } + if len(got) != len(want) { + t.Fatalf("Expected output array of size %d, got %d: %v", len(want), len(got), got) + } + sort.Sort(byDocumentTransformFieldPath(got)) + for i, vw := range want { + vg := got[i] + if !testEqual(vw, vg) { + t.Fatalf("index %d: got %#v, want %#v", i, vg, vw) + } + } +} + +type byDocumentTransformFieldPath []*pb.DocumentTransform_FieldTransform + +func (b byDocumentTransformFieldPath) Len() int { return len(b) } +func (b byDocumentTransformFieldPath) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byDocumentTransformFieldPath) Less(i, j int) bool { + return strings.Compare(b[i].FieldPath, b[j].FieldPath) < 1 +} + +func TestExtractTransformPathsErrors(t *testing.T) { + type S struct { + A int `firestore:",serverTimestamp"` + } + _, err := extractTransforms(reflect.ValueOf(S{}), nil) + if err == nil { + t.Error("got nil, want error") + } +} diff --git a/vendor/cloud.google.com/go/firestore/examples_test.go b/vendor/cloud.google.com/go/firestore/examples_test.go new file mode 100644 index 00000000..40e5d989 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/examples_test.go @@ -0,0 +1,609 @@ +// Copyright 2017 Google LLC +// +// 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. + +// TODO(jba): add Output comments to examples when feasible. + +package firestore_test + +import ( + "context" + "fmt" + + "cloud.google.com/go/firestore" + "google.golang.org/api/iterator" +) + +func ExampleNewClient() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() // Close client when done. + _ = client // TODO: Use client. +} + +func ExampleClient_Collection() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + coll1 := client.Collection("States") + coll2 := client.Collection("States/NewYork/Cities") + fmt.Println(coll1, coll2) +} + +func ExampleClient_Doc() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + doc1 := client.Doc("States/NewYork") + doc2 := client.Doc("States/NewYork/Cities/Albany") + fmt.Println(doc1, doc2) +} + +func ExampleClient_GetAll() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + docs, err := client.GetAll(ctx, []*firestore.DocumentRef{ + client.Doc("States/NorthCarolina"), + client.Doc("States/SouthCarolina"), + client.Doc("States/WestCarolina"), + client.Doc("States/EastCarolina"), + }) + if err != nil { + // TODO: Handle error. + } + // docs is a slice with four DocumentSnapshots, but the last two are + // nil because there is no West or East Carolina. + fmt.Println(docs) +} + +func ExampleClient_Batch() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + b := client.Batch() + _ = b // TODO: Use batch. +} + +func ExampleWriteBatch_Commit() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + type State struct { + Capital string `firestore:"capital"` + Population float64 `firestore:"pop"` // in millions + } + + ny := client.Doc("States/NewYork") + ca := client.Doc("States/California") + + writeResults, err := client.Batch(). + Create(ny, State{Capital: "Albany", Population: 19.8}). + Set(ca, State{Capital: "Sacramento", Population: 39.14}). + Delete(client.Doc("States/WestDakota")). + Commit(ctx) + if err != nil { + // TODO: Handle error. + } + fmt.Println(writeResults) +} + +func ExampleCollectionRef_Add() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + doc, wr, err := client.Collection("Users").Add(ctx, map[string]interface{}{ + "name": "Alice", + "email": "aj@example.com", + }) + if err != nil { + // TODO: Handle error. + } + fmt.Println(doc, wr) +} + +func ExampleCollectionRef_Doc() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + fl := client.Collection("States").Doc("Florida") + ta := client.Collection("States").Doc("Florida/Cities/Tampa") + + fmt.Println(fl, ta) +} + +func ExampleCollectionRef_NewDoc() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + doc := client.Collection("Users").NewDoc() + + fmt.Println(doc) +} + +func ExampleDocumentRef_Collection() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + mi := client.Collection("States").Doc("Michigan") + cities := mi.Collection("Cities") + + fmt.Println(cities) +} + +func ExampleDocumentRef_Create_map() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + wr, err := client.Doc("States/Colorado").Create(ctx, map[string]interface{}{ + "capital": "Denver", + "pop": 5.5, + }) + if err != nil { + // TODO: Handle error. + } + fmt.Println(wr.UpdateTime) +} + +func ExampleDocumentRef_Create_struct() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + type State struct { + Capital string `firestore:"capital"` + Population float64 `firestore:"pop"` // in millions + } + + wr, err := client.Doc("States/Colorado").Create(ctx, State{ + Capital: "Denver", + Population: 5.5, + }) + if err != nil { + // TODO: Handle error. + } + fmt.Println(wr.UpdateTime) +} + +func ExampleDocumentRef_Set() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + // Overwrite the document with the given data. Any other fields currently + // in the document will be removed. + wr, err := client.Doc("States/Alabama").Set(ctx, map[string]interface{}{ + "capital": "Montgomery", + "pop": 4.9, + }) + if err != nil { + // TODO: Handle error. + } + fmt.Println(wr.UpdateTime) +} + +func ExampleDocumentRef_Set_merge() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + // Overwrite only the fields in the map; preserve all others. + _, err = client.Doc("States/Alabama").Set(ctx, map[string]interface{}{ + "pop": 5.2, + }, firestore.MergeAll) + if err != nil { + // TODO: Handle error. + } + + type State struct { + Capital string `firestore:"capital"` + Population float64 `firestore:"pop"` // in millions + } + + // To do a merging Set with struct data, specify the exact fields to overwrite. + // MergeAll is disallowed here, because it would probably be a mistake: the "capital" + // field would be overwritten with the empty string. + _, err = client.Doc("States/Alabama").Set(ctx, State{Population: 5.2}, firestore.Merge([]string{"pop"})) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleDocumentRef_Update() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + tenn := client.Doc("States/Tennessee") + wr, err := tenn.Update(ctx, []firestore.Update{ + {Path: "pop", Value: 6.6}, + {FieldPath: []string{".", "*", "/"}, Value: "odd"}, + }) + if err != nil { + // TODO: Handle error. + } + fmt.Println(wr.UpdateTime) +} + +func ExampleDocumentRef_Delete() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + // Oops, Ontario is a Canadian province... + if _, err = client.Doc("States/Ontario").Delete(ctx); err != nil { + // TODO: Handle error. + } +} + +func ExampleDocumentRef_Get() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + docsnap, err := client.Doc("States/Ohio").Get(ctx) + if err != nil { + // TODO: Handle error. + } + _ = docsnap // TODO: Use DocumentSnapshot. +} + +func ExampleDocumentRef_Snapshots() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + iter := client.Doc("States/Idaho").Snapshots(ctx) + defer iter.Stop() + for { + docsnap, err := iter.Next() + if err != nil { + // TODO: Handle error. + } + _ = docsnap // TODO: Use DocumentSnapshot. + } +} + +func ExampleDocumentSnapshot_Data() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + docsnap, err := client.Doc("States/Ohio").Get(ctx) + if err != nil { + // TODO: Handle error. + } + ohioMap := docsnap.Data() + fmt.Println(ohioMap["capital"]) +} + +func ExampleDocumentSnapshot_DataAt() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + docsnap, err := client.Doc("States/Ohio").Get(ctx) + if err != nil { + // TODO: Handle error. + } + cap, err := docsnap.DataAt("capital") + if err != nil { + // TODO: Handle error. + } + fmt.Println(cap) +} + +func ExampleDocumentSnapshot_DataAtPath() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + docsnap, err := client.Doc("States/Ohio").Get(ctx) + if err != nil { + // TODO: Handle error. + } + pop, err := docsnap.DataAtPath([]string{"capital", "population"}) + if err != nil { + // TODO: Handle error. + } + fmt.Println(pop) +} + +func ExampleDocumentSnapshot_DataTo() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + docsnap, err := client.Doc("States/Ohio").Get(ctx) + if err != nil { + // TODO: Handle error. + } + + type State struct { + Capital string `firestore:"capital"` + Population float64 `firestore:"pop"` // in millions + } + + var s State + if err := docsnap.DataTo(&s); err != nil { + // TODO: Handle error. + } + fmt.Println(s) +} + +func ExampleQuery_Documents() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + q := client.Collection("States").Select("pop"). + Where("pop", ">", 10). + OrderBy("pop", firestore.Desc). + Limit(10) + iter1 := q.Documents(ctx) + _ = iter1 // TODO: Use iter1. + + // You can call Documents directly on a CollectionRef as well. + iter2 := client.Collection("States").Documents(ctx) + _ = iter2 // TODO: Use iter2. +} + +// This example is just like the one above, but illustrates +// how to use the XXXPath methods of Query for field paths +// that can't be expressed as a dot-separated string. +func ExampleQuery_Documents_path_methods() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + q := client.Collection("Unusual").SelectPaths([]string{"*"}, []string{"[~]"}). + WherePath([]string{"/"}, ">", 10). + OrderByPath([]string{"/"}, firestore.Desc). + Limit(10) + iter1 := q.Documents(ctx) + _ = iter1 // TODO: Use iter1. + + // You can call Documents directly on a CollectionRef as well. + iter2 := client.Collection("States").Documents(ctx) + _ = iter2 // TODO: Use iter2. +} + +func ExampleQuery_Snapshots() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + q := client.Collection("States").Select("pop"). + Where("pop", ">", 10). + OrderBy("pop", firestore.Desc). + Limit(10) + qsnapIter := q.Snapshots(ctx) + // Listen forever for changes to the query's results. + for { + qsnap, err := qsnapIter.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Printf("At %s there were %d results.\n", qsnap.ReadTime, qsnap.Size) + _ = qsnap.Documents // TODO: Iterate over the results if desired. + _ = qsnap.Changes // TODO: Use the list of incremental changes if desired. + } +} + +func ExampleDocumentIterator_Next() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + q := client.Collection("States"). + Where("pop", ">", 10). + OrderBy("pop", firestore.Desc) + iter := q.Documents(ctx) + defer iter.Stop() + for { + doc, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(doc.Data()) + } +} + +func ExampleDocumentIterator_GetAll() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + q := client.Collection("States"). + Where("pop", ">", 10). + OrderBy("pop", firestore.Desc). + Limit(10) // a good idea with GetAll, to avoid filling memory + docs, err := q.Documents(ctx).GetAll() + if err != nil { + // TODO: Handle error. + } + for _, doc := range docs { + fmt.Println(doc.Data()) + } +} + +func ExampleClient_RunTransaction() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + nm := client.Doc("States/NewMexico") + err = client.RunTransaction(ctx, func(ctx context.Context, tx *firestore.Transaction) error { + doc, err := tx.Get(nm) // tx.Get, NOT nm.Get! + if err != nil { + return err + } + pop, err := doc.DataAt("pop") + if err != nil { + return err + } + return tx.Update(nm, []firestore.Update{{Path: "pop", Value: pop.(float64) + 0.2}}) + }) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleArrayUnion_create() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + wr, err := client.Doc("States/Colorado").Create(ctx, map[string]interface{}{ + "cities": firestore.ArrayUnion("Denver", "Golden", "Boulder"), + "pop": 5.5, + }) + if err != nil { + // TODO: Handle error. + } + fmt.Println(wr.UpdateTime) +} + +func ExampleArrayUnion_update() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + co := client.Doc("States/Colorado") + wr, err := co.Update(ctx, []firestore.Update{ + {Path: "cities", Value: firestore.ArrayUnion("Broomfield")}, + }) + if err != nil { + // TODO: Handle error. + } + fmt.Println(wr.UpdateTime) +} + +func ExampleArrayRemove_update() { + ctx := context.Background() + client, err := firestore.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + + co := client.Doc("States/Colorado") + wr, err := co.Update(ctx, []firestore.Update{ + {Path: "cities", Value: firestore.ArrayRemove("Denver")}, + }) + if err != nil { + // TODO: Handle error. + } + fmt.Println(wr.UpdateTime) +} diff --git a/vendor/cloud.google.com/go/firestore/fieldpath.go b/vendor/cloud.google.com/go/firestore/fieldpath.go new file mode 100644 index 00000000..3f64ced8 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/fieldpath.go @@ -0,0 +1,277 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "bytes" + "errors" + "fmt" + "reflect" + "regexp" + "sort" + "strings" + "sync" + + "cloud.google.com/go/internal/fields" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +// A FieldPath is a non-empty sequence of non-empty fields that reference a value. +// +// A FieldPath value should only be necessary if one of the field names contains +// one of the runes ".˜*/[]". Most methods accept a simpler form of field path +// as a string in which the individual fields are separated by dots. +// For example, +// []string{"a", "b"} +// is equivalent to the string form +// "a.b" +// but +// []string{"*"} +// has no equivalent string form. +type FieldPath []string + +// parseDotSeparatedString constructs a FieldPath from a string that separates +// path components with dots. Other than splitting at dots and checking for invalid +// characters, it ignores everything else about the string, +// including attempts to quote field path compontents. So "a.`b.c`.d" is parsed into +// four parts, "a", "`b", "c`" and "d". +func parseDotSeparatedString(s string) (FieldPath, error) { + const invalidRunes = "~*/[]" + if strings.ContainsAny(s, invalidRunes) { + return nil, fmt.Errorf("firestore: %q contains an invalid rune (one of %s)", s, invalidRunes) + } + fp := FieldPath(strings.Split(s, ".")) + if err := fp.validate(); err != nil { + return nil, err + } + return fp, nil +} + +func (fp1 FieldPath) equal(fp2 FieldPath) bool { + if len(fp1) != len(fp2) { + return false + } + for i, c1 := range fp1 { + if c1 != fp2[i] { + return false + } + } + return true +} + +func (fp1 FieldPath) prefixOf(fp2 FieldPath) bool { + return len(fp1) <= len(fp2) && fp1.equal(fp2[:len(fp1)]) +} + +// Lexicographic ordering. +func (fp1 FieldPath) less(fp2 FieldPath) bool { + for i := range fp1 { + switch { + case i >= len(fp2): + return false + case fp1[i] < fp2[i]: + return true + case fp1[i] > fp2[i]: + return false + } + } + // fp1 and fp2 are equal up to len(fp1). + return len(fp1) < len(fp2) +} + +// validate checks the validity of fp and returns an error if it is invalid. +func (fp FieldPath) validate() error { + if len(fp) == 0 { + return errors.New("firestore: empty field path") + } + for _, c := range fp { + if len(c) == 0 { + return errors.New("firestore: empty component in field path") + } + } + return nil +} + +// with creates a new FieldPath consisting of fp followed by k. +func (fp FieldPath) with(k string) FieldPath { + r := make(FieldPath, len(fp), len(fp)+1) + copy(r, fp) + return append(r, k) +} + +// concat creates a new FieldPath consisting of fp1 followed by fp2. +func (fp1 FieldPath) concat(fp2 FieldPath) FieldPath { + r := make(FieldPath, len(fp1)+len(fp2)) + copy(r, fp1) + copy(r[len(fp1):], fp2) + return r +} + +// in reports whether fp is equal to one of the fps. +func (fp FieldPath) in(fps []FieldPath) bool { + for _, e := range fps { + if fp.equal(e) { + return true + } + } + return false +} + +// checkNoDupOrPrefix checks whether any FieldPath is a prefix of (or equal to) +// another. +// It modifies the order of FieldPaths in its argument (via sorting). +func checkNoDupOrPrefix(fps []FieldPath) error { + // Sort fps lexicographically. + sort.Sort(byPath(fps)) + // Check adjacent pairs for prefix. + for i := 1; i < len(fps); i++ { + if fps[i-1].prefixOf(fps[i]) { + return fmt.Errorf("field path %v cannot be used in the same update as %v", fps[i-1], fps[i]) + } + } + return nil +} + +type byPath []FieldPath + +func (b byPath) Len() int { return len(b) } +func (b byPath) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byPath) Less(i, j int) bool { return b[i].less(b[j]) } + +// setAtPath sets val at the location in m specified by fp, creating sub-maps as +// needed. m must not be nil. fp is assumed to be valid. +func setAtPath(m map[string]*pb.Value, fp FieldPath, val *pb.Value) { + if val == nil { + return + } + if len(fp) == 1 { + m[fp[0]] = val + } else { + v, ok := m[fp[0]] + if !ok { + v = &pb.Value{ValueType: &pb.Value_MapValue{&pb.MapValue{Fields: map[string]*pb.Value{}}}} + m[fp[0]] = v + } + // The type assertion below cannot fail, because setAtPath is only called + // with either an empty map or one filled by setAtPath itself, and the + // set of FieldPaths it is called with has been checked to make sure that + // no path is the prefix of any other. + setAtPath(v.GetMapValue().Fields, fp[1:], val) + } +} + +// getAtPath gets the value in data referred to by fp. The data argument can +// be a map or a struct. +// Compare with valueAtPath, which does the same thing for a document. +func getAtPath(v reflect.Value, fp FieldPath) (interface{}, error) { + var err error + for _, k := range fp { + v, err = getAtField(v, k) + if err != nil { + return nil, err + } + } + return v.Interface(), nil +} + +// getAtField returns the equivalent of v[k], if v is a map, or v.k if v is a struct. +func getAtField(v reflect.Value, k string) (reflect.Value, error) { + switch v.Kind() { + case reflect.Map: + if r := v.MapIndex(reflect.ValueOf(k)); r.IsValid() { + return r, nil + } + + case reflect.Struct: + fm, err := fieldMap(v.Type()) + if err != nil { + return reflect.Value{}, err + } + if f, ok := fm[k]; ok { + return v.FieldByIndex(f.Index), nil + } + + case reflect.Interface: + return getAtField(v.Elem(), k) + + case reflect.Ptr: + return getAtField(v.Elem(), k) + } + return reflect.Value{}, fmt.Errorf("firestore: no field %q for value %#v", k, v) +} + +// fieldMapCache holds maps from from Firestore field name to struct field, +// keyed by struct type. +var fieldMapCache sync.Map + +func fieldMap(t reflect.Type) (map[string]fields.Field, error) { + x, ok := fieldMapCache.Load(t) + if !ok { + fieldList, err := fieldCache.Fields(t) + if err != nil { + x = err + } else { + m := map[string]fields.Field{} + for _, f := range fieldList { + m[f.Name] = f + } + x = m + } + fieldMapCache.Store(t, x) + } + if err, ok := x.(error); ok { + return nil, err + } + return x.(map[string]fields.Field), nil +} + +// toServiceFieldPath converts fp the form required by the Firestore service. +// It assumes fp has been validated. +func (fp FieldPath) toServiceFieldPath() string { + cs := make([]string, len(fp)) + for i, c := range fp { + cs[i] = toServiceFieldPathComponent(c) + } + return strings.Join(cs, ".") +} + +func toServiceFieldPaths(fps []FieldPath) []string { + var sfps []string + for _, fp := range fps { + sfps = append(sfps, fp.toServiceFieldPath()) + } + return sfps +} + +// Google SQL syntax for an unquoted field. +var unquotedFieldRegexp = regexp.MustCompile("^[A-Za-z_][A-Za-z_0-9]*$") + +// toServiceFieldPathComponent returns a string that represents key and is a valid +// field path component. +func toServiceFieldPathComponent(key string) string { + if unquotedFieldRegexp.MatchString(key) { + return key + } + var buf bytes.Buffer + buf.WriteRune('`') + for _, r := range key { + if r == '`' || r == '\\' { + buf.WriteRune('\\') + } + buf.WriteRune(r) + } + buf.WriteRune('`') + return buf.String() +} diff --git a/vendor/cloud.google.com/go/firestore/fieldpath_test.go b/vendor/cloud.google.com/go/firestore/fieldpath_test.go new file mode 100644 index 00000000..2c8072fd --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/fieldpath_test.go @@ -0,0 +1,232 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "reflect" + "strings" + "testing" + + "cloud.google.com/go/internal/testutil" +) + +func TestFieldPathValidate(t *testing.T) { + for _, in := range [][]string{nil, {}, {"a", "", "b"}} { + if err := FieldPath(in).validate(); err == nil { + t.Errorf("%v: want error, got nil", in) + } + } +} + +func TestFieldPathLess(t *testing.T) { + for _, test := range []struct { + in1, in2 string + want bool + }{ + {"a b", "a b", false}, + {"a", "b", true}, + {"b", "a", false}, + {"a", "a b", true}, + {"a b", "a", false}, + {"a b c", "a b d", true}, + {"a b d", "a b c", false}, + } { + fp1 := FieldPath(strings.Fields(test.in1)) + fp2 := FieldPath(strings.Fields(test.in2)) + got := fp1.less(fp2) + if got != test.want { + t.Errorf("%q.less(%q): got %t, want %t", test.in1, test.in2, got, test.want) + } + } +} + +func TestCheckForPrefix(t *testing.T) { + for _, test := range []struct { + in []string // field paths as space-separated strings + wantErr bool + }{ + {in: []string{"a", "b", "c"}, wantErr: false}, + {in: []string{"a b", "b", "c d"}, wantErr: false}, + {in: []string{"a b", "a c", "a d"}, wantErr: false}, + {in: []string{"a b", "b", "b d"}, wantErr: true}, + {in: []string{"a b", "b", "b d"}, wantErr: true}, + {in: []string{"b c d", "c d", "b c"}, wantErr: true}, + } { + var fps []FieldPath + for _, s := range test.in { + fps = append(fps, strings.Fields(s)) + } + err := checkNoDupOrPrefix(fps) + if got, want := (err != nil), test.wantErr; got != want { + t.Errorf("%#v: got '%v', want %t", test.in, err, want) + } + } +} + +func TestGetAtPath(t *testing.T) { + type S struct { + X int + Y int `firestore:"y"` + M map[string]interface{} + Next *S + } + + const fail = "ERROR" // value for expected error + + for _, test := range []struct { + val interface{} + fp FieldPath + want interface{} + }{ + { + val: map[string]int(nil), + fp: nil, + want: map[string]int(nil), + }, + { + val: 1, + fp: nil, + want: 1, + }, + { + val: 1, + fp: []string{"a"}, + want: fail, + }, + { + val: map[string]int{"a": 2}, + fp: []string{"a"}, + want: 2, + }, + { + val: map[string]int{"a": 2}, + fp: []string{"b"}, + want: fail, + }, + { + val: map[string]interface{}{"a": map[string]int{"b": 3}}, + fp: []string{"a", "b"}, + want: 3, + }, + { + val: map[string]interface{}{"a": map[string]int{"b": 3}}, + fp: []string{"a", "b", "c"}, + want: fail, + }, + { + val: S{X: 1, Y: 2}, + fp: nil, + want: S{X: 1, Y: 2}, + }, + { + val: S{X: 1, Y: 2}, + fp: []string{"X"}, + want: 1, + }, + { + val: S{X: 1, Y: 2}, + fp: []string{"Y"}, + want: fail, // because Y is tagged with name "y" + }, + { + val: S{X: 1, Y: 2}, + fp: []string{"y"}, + want: 2, + }, + { + val: &S{X: 1}, + fp: []string{"X"}, + want: 1, + }, + { + val: &S{X: 1, Next: nil}, + fp: []string{"Next"}, + want: (*S)(nil), + }, + { + val: &S{X: 1, Next: nil}, + fp: []string{"Next", "Next"}, + want: fail, + }, + { + val: map[string]S{"a": {X: 1, Y: 2}}, + fp: []string{"a", "y"}, + want: 2, + }, + { + val: map[string]S{"a": {X: 1, Y: 2}}, + fp: []string{"a", "z"}, + want: fail, + }, + { + val: map[string]*S{ + "a": { + M: map[string]interface{}{ + "b": S{ + Next: &S{ + X: 17, + }, + }, + }, + }, + }, + fp: []string{"a", "M", "b", "Next", "X"}, + want: 17, + }, + } { + got, err := getAtPath(reflect.ValueOf(test.val), test.fp) + if err != nil && test.want != fail { + t.Errorf("%+v: got error <%v>, want nil", test, err) + } + if err == nil && !testutil.Equal(got, test.want) { + t.Errorf("%+v: got %v, want %v, want nil", test, got, test.want) + } + } +} + +func TestToServiceFieldPath(t *testing.T) { + for _, test := range []struct { + in FieldPath + want string + }{ + {[]string{"a"}, "a"}, + {[]string{"a", "b"}, "a.b"}, + {[]string{"a.", "[b*", "c2"}, "`a.`.`[b*`.c2"}, + {[]string{"`a", `b\`}, "`\\`a`.`b\\\\`"}, + } { + got := test.in.toServiceFieldPath() + if got != test.want { + t.Errorf("%v: got %s, want %s", test.in, got, test.want) + } + } +} + +func TestToServiceFieldPathComponent(t *testing.T) { + for _, test := range []struct { + in, want string + }{ + {"", "``"}, + {"clam_chowder23", "clam_chowder23"}, + {"23skidoo", "`23skidoo`"}, + {"bak`tik", "`bak\\`tik`"}, + {"a\\b", "`a\\\\b`"}, + {"dots.are.confusing", "`dots.are.confusing`"}, + } { + got := toServiceFieldPathComponent(test.in) + if got != test.want { + t.Errorf("%q: got %q, want %q", test.in, got, test.want) + } + } +} diff --git a/vendor/cloud.google.com/go/firestore/from_value.go b/vendor/cloud.google.com/go/firestore/from_value.go new file mode 100644 index 00000000..feba34fc --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/from_value.go @@ -0,0 +1,430 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "errors" + "fmt" + "reflect" + "strings" + + "github.com/golang/protobuf/ptypes" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +func setFromProtoValue(x interface{}, vproto *pb.Value, c *Client) error { + v := reflect.ValueOf(x) + if v.Kind() != reflect.Ptr || v.IsNil() { + return errors.New("firestore: nil or not a pointer") + } + return setReflectFromProtoValue(v.Elem(), vproto, c) +} + +// setReflectFromProtoValue sets v from a Firestore Value. +// v must be a settable value. +func setReflectFromProtoValue(v reflect.Value, vproto *pb.Value, c *Client) error { + typeErr := func() error { + return fmt.Errorf("firestore: cannot set type %s to %s", v.Type(), typeString(vproto)) + } + + val := vproto.ValueType + // A Null value sets anything nullable to nil, and has no effect + // on anything else. + if _, ok := val.(*pb.Value_NullValue); ok { + switch v.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: + v.Set(reflect.Zero(v.Type())) + } + return nil + } + + // Handle special types first. + switch v.Type() { + case typeOfByteSlice: + x, ok := val.(*pb.Value_BytesValue) + if !ok { + return typeErr() + } + v.SetBytes(x.BytesValue) + return nil + + case typeOfGoTime: + x, ok := val.(*pb.Value_TimestampValue) + if !ok { + return typeErr() + } + t, err := ptypes.Timestamp(x.TimestampValue) + if err != nil { + return err + } + v.Set(reflect.ValueOf(t)) + return nil + + case typeOfProtoTimestamp: + x, ok := val.(*pb.Value_TimestampValue) + if !ok { + return typeErr() + } + v.Set(reflect.ValueOf(x.TimestampValue)) + return nil + + case typeOfLatLng: + x, ok := val.(*pb.Value_GeoPointValue) + if !ok { + return typeErr() + } + v.Set(reflect.ValueOf(x.GeoPointValue)) + return nil + + case typeOfDocumentRef: + x, ok := val.(*pb.Value_ReferenceValue) + if !ok { + return typeErr() + } + dr, err := pathToDoc(x.ReferenceValue, c) + if err != nil { + return err + } + v.Set(reflect.ValueOf(dr)) + return nil + } + + switch v.Kind() { + case reflect.Bool: + x, ok := val.(*pb.Value_BooleanValue) + if !ok { + return typeErr() + } + v.SetBool(x.BooleanValue) + + case reflect.String: + x, ok := val.(*pb.Value_StringValue) + if !ok { + return typeErr() + } + v.SetString(x.StringValue) + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + var i int64 + switch x := val.(type) { + case *pb.Value_IntegerValue: + i = x.IntegerValue + case *pb.Value_DoubleValue: + f := x.DoubleValue + i = int64(f) + if float64(i) != f { + return fmt.Errorf("firestore: float %f does not fit into %s", f, v.Type()) + } + default: + return typeErr() + } + if v.OverflowInt(i) { + return overflowErr(v, i) + } + v.SetInt(i) + + case reflect.Uint8, reflect.Uint16, reflect.Uint32: + var u uint64 + switch x := val.(type) { + case *pb.Value_IntegerValue: + u = uint64(x.IntegerValue) + case *pb.Value_DoubleValue: + f := x.DoubleValue + u = uint64(f) + if float64(u) != f { + return fmt.Errorf("firestore: float %f does not fit into %s", f, v.Type()) + } + default: + return typeErr() + } + if v.OverflowUint(u) { + return overflowErr(v, u) + } + v.SetUint(u) + + case reflect.Float32, reflect.Float64: + var f float64 + switch x := val.(type) { + case *pb.Value_DoubleValue: + f = x.DoubleValue + case *pb.Value_IntegerValue: + f = float64(x.IntegerValue) + if int64(f) != x.IntegerValue { + return overflowErr(v, x.IntegerValue) + } + default: + return typeErr() + } + if v.OverflowFloat(f) { + return overflowErr(v, f) + } + v.SetFloat(f) + + case reflect.Slice: + x, ok := val.(*pb.Value_ArrayValue) + if !ok { + return typeErr() + } + vals := x.ArrayValue.Values + vlen := v.Len() + xlen := len(vals) + // Make a slice of the right size, avoiding allocation if possible. + switch { + case vlen < xlen: + v.Set(reflect.MakeSlice(v.Type(), xlen, xlen)) + case vlen > xlen: + v.SetLen(xlen) + } + return populateRepeated(v, vals, xlen, c) + + case reflect.Array: + x, ok := val.(*pb.Value_ArrayValue) + if !ok { + return typeErr() + } + vals := x.ArrayValue.Values + xlen := len(vals) + vlen := v.Len() + minlen := vlen + // Set extra elements to their zero value. + if vlen > xlen { + z := reflect.Zero(v.Type().Elem()) + for i := xlen; i < vlen; i++ { + v.Index(i).Set(z) + } + minlen = xlen + } + return populateRepeated(v, vals, minlen, c) + + case reflect.Map: + x, ok := val.(*pb.Value_MapValue) + if !ok { + return typeErr() + } + return populateMap(v, x.MapValue.Fields, c) + + case reflect.Ptr: + // If the pointer is nil, set it to a zero value. + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + return setReflectFromProtoValue(v.Elem(), vproto, c) + + case reflect.Struct: + x, ok := val.(*pb.Value_MapValue) + if !ok { + return typeErr() + } + return populateStruct(v, x.MapValue.Fields, c) + + case reflect.Interface: + if v.NumMethod() == 0 { // empty interface + // If v holds a pointer, set the pointer. + if !v.IsNil() && v.Elem().Kind() == reflect.Ptr { + return setReflectFromProtoValue(v.Elem(), vproto, c) + } + // Otherwise, create a fresh value. + x, err := createFromProtoValue(vproto, c) + if err != nil { + return err + } + v.Set(reflect.ValueOf(x)) + return nil + } + // Any other kind of interface is an error. + fallthrough + + default: + return fmt.Errorf("firestore: cannot set type %s", v.Type()) + } + return nil +} + +// populateRepeated sets the first n elements of vr, which must be a slice or +// array, to the corresponding elements of vals. +func populateRepeated(vr reflect.Value, vals []*pb.Value, n int, c *Client) error { + for i := 0; i < n; i++ { + if err := setReflectFromProtoValue(vr.Index(i), vals[i], c); err != nil { + return err + } + } + return nil +} + +// populateMap sets the elements of vm, which must be a map, from the +// corresponding elements of pm. +// +// Since a map value is not settable, this function always creates a new +// element for each corresponding map key. Existing values of vm are +// overwritten. This happens even if the map value is something like a pointer +// to a struct, where we could in theory populate the existing struct value +// instead of discarding it. This behavior matches encoding/json. +func populateMap(vm reflect.Value, pm map[string]*pb.Value, c *Client) error { + t := vm.Type() + if t.Key().Kind() != reflect.String { + return errors.New("firestore: map key type is not string") + } + if vm.IsNil() { + vm.Set(reflect.MakeMap(t)) + } + et := t.Elem() + for k, vproto := range pm { + el := reflect.New(et).Elem() + if err := setReflectFromProtoValue(el, vproto, c); err != nil { + return err + } + vm.SetMapIndex(reflect.ValueOf(k), el) + } + return nil +} + +// createMapFromValueMap creates a fresh map and populates it with pm. +func createMapFromValueMap(pm map[string]*pb.Value, c *Client) (map[string]interface{}, error) { + m := map[string]interface{}{} + for k, pv := range pm { + v, err := createFromProtoValue(pv, c) + if err != nil { + return nil, err + } + m[k] = v + } + return m, nil +} + +// populateStruct sets the fields of vs, which must be a struct, from +// the matching elements of pm. +func populateStruct(vs reflect.Value, pm map[string]*pb.Value, c *Client) error { + fields, err := fieldCache.Fields(vs.Type()) + if err != nil { + return err + } + for k, vproto := range pm { + f := fields.Match(k) + if f == nil { + continue + } + if err := setReflectFromProtoValue(vs.FieldByIndex(f.Index), vproto, c); err != nil { + return fmt.Errorf("%s.%s: %v", vs.Type(), f.Name, err) + } + } + return nil +} + +func createFromProtoValue(vproto *pb.Value, c *Client) (interface{}, error) { + switch v := vproto.ValueType.(type) { + case *pb.Value_NullValue: + return nil, nil + case *pb.Value_BooleanValue: + return v.BooleanValue, nil + case *pb.Value_IntegerValue: + return v.IntegerValue, nil + case *pb.Value_DoubleValue: + return v.DoubleValue, nil + case *pb.Value_TimestampValue: + return ptypes.Timestamp(v.TimestampValue) + case *pb.Value_StringValue: + return v.StringValue, nil + case *pb.Value_BytesValue: + return v.BytesValue, nil + case *pb.Value_ReferenceValue: + return pathToDoc(v.ReferenceValue, c) + case *pb.Value_GeoPointValue: + return v.GeoPointValue, nil + + case *pb.Value_ArrayValue: + vals := v.ArrayValue.Values + ret := make([]interface{}, len(vals)) + for i, v := range vals { + r, err := createFromProtoValue(v, c) + if err != nil { + return nil, err + } + ret[i] = r + } + return ret, nil + + case *pb.Value_MapValue: + fields := v.MapValue.Fields + ret := make(map[string]interface{}, len(fields)) + for k, v := range fields { + r, err := createFromProtoValue(v, c) + if err != nil { + return nil, err + } + ret[k] = r + } + return ret, nil + + default: + return nil, fmt.Errorf("firestore: unknown value type %T", v) + } +} + +// Convert a document path to a DocumentRef. +func pathToDoc(docPath string, c *Client) (*DocumentRef, error) { + projID, dbID, docIDs, err := parseDocumentPath(docPath) + if err != nil { + return nil, err + } + parentResourceName := fmt.Sprintf("projects/%s/databases/%s", projID, dbID) + _, doc := c.idsToRef(docIDs, parentResourceName) + return doc, nil +} + +// A document path should be of the form "projects/P/databases/D/documents/coll1/doc1/coll2/doc2/...". +func parseDocumentPath(path string) (projectID, databaseID string, docPath []string, err error) { + parts := strings.Split(path, "/") + if len(parts) < 6 || parts[0] != "projects" || parts[2] != "databases" || parts[4] != "documents" { + return "", "", nil, fmt.Errorf("firestore: malformed document path %q", path) + } + docp := parts[5:] + if len(docp)%2 != 0 { + return "", "", nil, fmt.Errorf("firestore: path %q refers to collection, not document", path) + } + return parts[1], parts[3], docp, nil +} + +func typeString(vproto *pb.Value) string { + switch vproto.ValueType.(type) { + case *pb.Value_NullValue: + return "null" + case *pb.Value_BooleanValue: + return "bool" + case *pb.Value_IntegerValue: + return "int" + case *pb.Value_DoubleValue: + return "float" + case *pb.Value_TimestampValue: + return "timestamp" + case *pb.Value_StringValue: + return "string" + case *pb.Value_BytesValue: + return "bytes" + case *pb.Value_ReferenceValue: + return "reference" + case *pb.Value_GeoPointValue: + return "GeoPoint" + case *pb.Value_MapValue: + return "map" + case *pb.Value_ArrayValue: + return "array" + default: + return "" + } +} + +func overflowErr(v reflect.Value, x interface{}) error { + return fmt.Errorf("firestore: value %v overflows type %s", x, v.Type()) +} diff --git a/vendor/cloud.google.com/go/firestore/from_value_test.go b/vendor/cloud.google.com/go/firestore/from_value_test.go new file mode 100644 index 00000000..00937956 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/from_value_test.go @@ -0,0 +1,549 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "encoding/json" + "fmt" + "io" + "math" + "reflect" + "strings" + "testing" + "time" + + ts "github.com/golang/protobuf/ptypes/timestamp" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/genproto/googleapis/type/latlng" +) + +var ( + tm = time.Date(2016, 12, 25, 0, 0, 0, 123456789, time.UTC) + ll = &latlng.LatLng{Latitude: 20, Longitude: 30} + ptm = &ts.Timestamp{Seconds: 12345, Nanos: 67890} +) + +func TestCreateFromProtoValue(t *testing.T) { + for _, test := range []struct { + in *pb.Value + want interface{} + }{ + {in: nullValue, want: nil}, + {in: boolval(true), want: true}, + {in: intval(3), want: int64(3)}, + {in: floatval(1.5), want: 1.5}, + {in: strval("str"), want: "str"}, + {in: tsval(tm), want: tm}, + { + in: bytesval([]byte{1, 2}), + want: []byte{1, 2}, + }, + { + in: &pb.Value{ValueType: &pb.Value_GeoPointValue{ll}}, + want: ll, + }, + { + in: arrayval(intval(1), intval(2)), + want: []interface{}{int64(1), int64(2)}, + }, + { + in: arrayval(), + want: []interface{}{}, + }, + { + in: mapval(map[string]*pb.Value{"a": intval(1), "b": intval(2)}), + want: map[string]interface{}{"a": int64(1), "b": int64(2)}, + }, + { + in: mapval(map[string]*pb.Value{}), + want: map[string]interface{}{}, + }, + { + in: refval("projects/P/databases/D/documents/c/d"), + want: &DocumentRef{ + ID: "d", + Parent: &CollectionRef{ + ID: "c", + parentPath: "projects/P/databases/D", + Path: "projects/P/databases/D/documents/c", + Query: Query{collectionID: "c", parentPath: "projects/P/databases/D"}, + }, + Path: "projects/P/databases/D/documents/c/d", + }, + }, + } { + got, err := createFromProtoValue(test.in, nil) + if err != nil { + t.Errorf("%v: %v", test.in, err) + continue + } + if !testEqual(got, test.want) { + t.Errorf("%+v:\ngot\n%#v\nwant\n%#v", test.in, got, test.want) + } + } +} + +func TestSetFromProtoValue(t *testing.T) { + testSetFromProtoValue(t, "json", jsonTester{}) + testSetFromProtoValue(t, "firestore", protoTester{}) +} + +func testSetFromProtoValue(t *testing.T, prefix string, r tester) { + pi := newfloat(7) + s := []float64{7, 8} + ar1 := [1]float64{7} + ar2 := [2]float64{7, 8} + ar3 := [3]float64{7, 8, 9} + mf := map[string]float64{"a": 7} + + type T struct { + I **float64 + J float64 + } + + one := newfloat(1) + six := newfloat(6) + st := []*T{{I: &six}, nil, {I: &six, J: 7}} + vs := interface{}(T{J: 1}) + vm := interface{}(map[string]float64{"i": 1}) + var ( + i int + i8 int8 + i16 int16 + i32 int32 + i64 int64 + u8 uint8 + u16 uint16 + u32 uint32 + b bool + ll *latlng.LatLng + mi map[string]interface{} + ms map[string]T + ) + + for i, test := range []struct { + in interface{} + val interface{} + want interface{} + }{ + {&pi, r.Null(), (*float64)(nil)}, + {pi, r.Float(1), 1.0}, + {&s, r.Null(), ([]float64)(nil)}, + {&s, r.Array(r.Float(1), r.Float(2)), []float64{1, 2}}, + {&ar1, r.Array(r.Float(1), r.Float(2)), [1]float64{1}}, + {&ar2, r.Array(r.Float(1), r.Float(2)), [2]float64{1, 2}}, + {&ar3, r.Array(r.Float(1), r.Float(2)), [3]float64{1, 2, 0}}, + {&mf, r.Null(), (map[string]float64)(nil)}, + {&mf, r.Map("a", r.Float(1), "b", r.Float(2)), map[string]float64{"a": 1, "b": 2}}, + {&st, r.Array( + r.Null(), // overwrites st[0] with nil + r.Map("i", r.Float(1)), // sets st[1] to a new struct + r.Map("i", r.Float(2)), // modifies st[2] + ), + []*T{nil, {I: &one}, {I: &six, J: 7}}}, + {&mi, r.Map("a", r.Float(1), "b", r.Float(2)), map[string]interface{}{"a": 1.0, "b": 2.0}}, + {&ms, r.Map("a", r.Map("j", r.Float(1))), map[string]T{"a": {J: 1}}}, + {&vs, r.Map("i", r.Float(2)), map[string]interface{}{"i": 2.0}}, + {&vm, r.Map("i", r.Float(2)), map[string]interface{}{"i": 2.0}}, + {&ll, r.Null(), (*latlng.LatLng)(nil)}, + {&i, r.Int(1), int(1)}, + {&i8, r.Int(1), int8(1)}, + {&i16, r.Int(1), int16(1)}, + {&i32, r.Int(1), int32(1)}, + {&i64, r.Int(1), int64(1)}, + {&u8, r.Int(1), uint8(1)}, + {&u16, r.Int(1), uint16(1)}, + {&u32, r.Int(1), uint32(1)}, + {&b, r.Bool(true), true}, + {&i, r.Float(1), int(1)}, // can put a float with no fractional part into an int + {pi, r.Int(1), float64(1)}, // can put an int into a float + } { + if err := r.Set(test.in, test.val); err != nil { + t.Errorf("%s: #%d: got error %v", prefix, i, err) + continue + } + got := reflect.ValueOf(test.in).Elem().Interface() + if !testEqual(got, test.want) { + t.Errorf("%s: #%d, %v:\ngot\n%+v (%T)\nwant\n%+v (%T)", + prefix, i, test.val, got, got, test.want, test.want) + } + } +} + +func TestSetFromProtoValueNoJSON(t *testing.T) { + // Test code paths that we cannot compare to JSON. + var ( + bs []byte + tmi time.Time + lli *latlng.LatLng + tmp *ts.Timestamp + ) + bytes := []byte{1, 2, 3} + + for i, test := range []struct { + in interface{} + val *pb.Value + want interface{} + }{ + {&bs, bytesval(bytes), bytes}, + {&tmi, tsval(tm), tm}, + {&tmp, &pb.Value{ValueType: &pb.Value_TimestampValue{ptm}}, ptm}, + {&lli, geoval(ll), ll}, + } { + if err := setFromProtoValue(test.in, test.val, &Client{}); err != nil { + t.Errorf("#%d: got error %v", i, err) + continue + } + got := reflect.ValueOf(test.in).Elem().Interface() + if !testEqual(got, test.want) { + t.Errorf("#%d, %v:\ngot\n%+v (%T)\nwant\n%+v (%T)", + i, test.val, got, got, test.want, test.want) + } + } +} + +func TestSetFromProtoValueErrors(t *testing.T) { + c := &Client{} + ival := intval(3) + for i, test := range []struct { + in interface{} + val *pb.Value + }{ + {3, ival}, // not a pointer + {new(int8), intval(128)}, // int overflow + {new(uint8), intval(256)}, // uint overflow + {new(float32), floatval(2 * math.MaxFloat32)}, // float overflow + {new(uint), ival}, // cannot set type + {new(uint64), ival}, // cannot set type + {new(io.Reader), ival}, // cannot set type + {new(map[int]int), + mapval(map[string]*pb.Value{"x": ival})}, // map key type is not string + // the rest are all type mismatches + {new(bool), ival}, + {new(*latlng.LatLng), ival}, + {new(time.Time), ival}, + {new(string), ival}, + {new([]byte), ival}, + {new([]int), ival}, + {new([1]int), ival}, + {new(map[string]int), ival}, + {new(*bool), ival}, + {new(struct{}), ival}, + {new(int), floatval(2.5)}, // float must be integral + {new(uint16), intval(-1)}, // uint cannot be negative + {new(int16), floatval(math.MaxFloat32)}, // doesn't fit + {new(uint16), floatval(math.MaxFloat32)}, // doesn't fit + {new(float32), + &pb.Value{ValueType: &pb.Value_IntegerValue{math.MaxInt64}}}, // overflow + } { + err := setFromProtoValue(test.in, test.val, c) + if err == nil { + t.Errorf("#%d: %v, %v: got nil, want error", i, test.in, test.val) + } + } +} + +func TestSetFromProtoValuePointers(t *testing.T) { + // Verify that pointers are set, instead of being replaced. + // Confirm that the behavior matches encoding/json. + testSetPointer(t, "json", jsonTester{}) + testSetPointer(t, "firestore", protoTester{&Client{}}) +} + +func testSetPointer(t *testing.T, prefix string, r tester) { + // If an interface{} holds a pointer, the pointer is set. + + set := func(x, val interface{}) { + if err := r.Set(x, val); err != nil { + t.Fatalf("%s: set(%v, %v): %v", prefix, x, val, err) + } + } + p := new(float64) + var st struct { + I interface{} + } + + // A pointer in a slice of interface{} is set. + s := []interface{}{p} + set(&s, r.Array(r.Float(1))) + if s[0] != p { + t.Errorf("%s: pointers not identical", prefix) + } + if *p != 1 { + t.Errorf("%s: got %f, want 1", prefix, *p) + } + // Setting a null will set the pointer to nil. + set(&s, r.Array(r.Null())) + if got := s[0]; got != nil { + t.Errorf("%s: got %v, want null", prefix, got) + } + + // It doesn't matter how deep the pointers nest. + p = new(float64) + p2 := &p + p3 := &p2 + s = []interface{}{p3} + set(&s, r.Array(r.Float(1))) + if s[0] != p3 { + t.Errorf("%s: pointers not identical", prefix) + } + if *p != 1 { + t.Errorf("%s: got %f, want 1", prefix, *p) + } + + // A pointer in an interface{} field is set. + p = new(float64) + st.I = p + set(&st, r.Map("i", r.Float(1))) + if st.I != p { + t.Errorf("%s: pointers not identical", prefix) + } + if *p != 1 { + t.Errorf("%s: got %f, want 1", prefix, *p) + } + // Setting a null will set the pointer to nil. + set(&st, r.Map("i", r.Null())) + if got := st.I; got != nil { + t.Errorf("%s: got %v, want null", prefix, got) + } + + // A pointer to a slice (instead of to float64) is set. + psi := &[]float64{7, 8, 9} + st.I = psi + set(&st, r.Map("i", r.Array(r.Float(1)))) + if st.I != psi { + t.Errorf("%s: pointers not identical", prefix) + } + // The slice itself should be truncated and filled, not replaced. + if got, want := cap(*psi), 3; got != want { + t.Errorf("cap: got %d, want %d", got, want) + } + if want := &[]float64{1}; !testEqual(st.I, want) { + t.Errorf("got %+v, want %+v", st.I, want) + } + + // A pointer to a map is set. + pmf := &map[string]float64{"a": 7, "b": 8} + st.I = pmf + set(&st, r.Map("i", r.Map("a", r.Float(1)))) + if st.I != pmf { + t.Errorf("%s: pointers not identical", prefix) + } + if want := map[string]float64{"a": 1, "b": 8}; !testEqual(*pmf, want) { + t.Errorf("%s: got %+v, want %+v", prefix, *pmf, want) + } + + // Maps are different: since the map values aren't addressable, they + // are always discarded, even if the map element type is not interface{}. + + // A map's values are discarded if the value type is a pointer type. + p = new(float64) + m := map[string]*float64{"i": p} + set(&m, r.Map("i", r.Float(1))) + if m["i"] == p { + t.Errorf("%s: pointers are identical", prefix) + } + if got, want := *m["i"], 1.0; got != want { + t.Errorf("%s: got %v, want %v", prefix, got, want) + } + // A map's values are discarded if the value type is interface{}. + p = new(float64) + m2 := map[string]interface{}{"i": p} + set(&m2, r.Map("i", r.Float(1))) + if m2["i"] == p { + t.Errorf("%s: pointers are identical", prefix) + } + if got, want := m2["i"].(float64), 1.0; got != want { + t.Errorf("%s: got %f, want %f", prefix, got, want) + } +} + +// An interface for setting and building values, to facilitate comparing firestore deserialization +// with encoding/json. +type tester interface { + Set(x, val interface{}) error + Null() interface{} + Int(int) interface{} + Float(float64) interface{} + Bool(bool) interface{} + Array(...interface{}) interface{} + Map(keysvals ...interface{}) interface{} +} + +type protoTester struct { + c *Client +} + +func (p protoTester) Set(x, val interface{}) error { return setFromProtoValue(x, val.(*pb.Value), p.c) } +func (protoTester) Null() interface{} { return nullValue } +func (protoTester) Int(i int) interface{} { return intval(i) } +func (protoTester) Float(f float64) interface{} { return floatval(f) } +func (protoTester) Bool(b bool) interface{} { return boolval(b) } + +func (protoTester) Array(els ...interface{}) interface{} { + var s []*pb.Value + for _, el := range els { + s = append(s, el.(*pb.Value)) + } + return arrayval(s...) +} + +func (protoTester) Map(keysvals ...interface{}) interface{} { + m := map[string]*pb.Value{} + for i := 0; i < len(keysvals); i += 2 { + m[keysvals[i].(string)] = keysvals[i+1].(*pb.Value) + } + return mapval(m) +} + +type jsonTester struct{} + +func (jsonTester) Set(x, val interface{}) error { return json.Unmarshal([]byte(val.(string)), x) } +func (jsonTester) Null() interface{} { return "null" } +func (jsonTester) Int(i int) interface{} { return fmt.Sprint(i) } +func (jsonTester) Float(f float64) interface{} { return fmt.Sprint(f) } + +func (jsonTester) Bool(b bool) interface{} { + if b { + return "true" + } + return "false" +} + +func (jsonTester) Array(els ...interface{}) interface{} { + var s []string + for _, el := range els { + s = append(s, el.(string)) + } + return "[" + strings.Join(s, ", ") + "]" +} + +func (jsonTester) Map(keysvals ...interface{}) interface{} { + var s []string + for i := 0; i < len(keysvals); i += 2 { + s = append(s, fmt.Sprintf("%q: %v", keysvals[i], keysvals[i+1])) + } + return "{" + strings.Join(s, ", ") + "}" +} + +func newfloat(f float64) *float64 { + p := new(float64) + *p = f + return p +} + +func TestParseDocumentPath(t *testing.T) { + for _, test := range []struct { + in string + pid, dbid string + dpath []string + }{ + {"projects/foo-bar/databases/db2/documents/c1/d1", + "foo-bar", "db2", []string{"c1", "d1"}}, + {"projects/P/databases/D/documents/c1/d1/c2/d2", + "P", "D", []string{"c1", "d1", "c2", "d2"}}, + } { + gotPid, gotDbid, gotDpath, err := parseDocumentPath(test.in) + if err != nil { + t.Fatal(err) + } + if got, want := gotPid, test.pid; got != want { + t.Errorf("project ID: got %q, want %q", got, want) + } + if got, want := gotDbid, test.dbid; got != want { + t.Errorf("db ID: got %q, want %q", got, want) + } + if got, want := gotDpath, test.dpath; !testEqual(got, want) { + t.Errorf("doc path: got %q, want %q", got, want) + } + } +} + +func TestParseDocumentPathErrors(t *testing.T) { + for _, badPath := range []string{ + "projects/P/databases/D/documents/c", // collection path + "/projects/P/databases/D/documents/c/d", // initial slash + "projects/P/databases/D/c/d", // missing "documents" + "project/P/database/D/document/c/d", + } { + // Every prefix of a bad path is also bad. + for i := 0; i <= len(badPath); i++ { + in := badPath[:i] + _, _, _, err := parseDocumentPath(in) + if err == nil { + t.Errorf("%q: got nil, want error", in) + } + } + } +} + +func TestPathToDoc(t *testing.T) { + c := &Client{} + path := "projects/P/databases/D/documents/c1/d1/c2/d2" + got, err := pathToDoc(path, c) + if err != nil { + t.Fatal(err) + } + want := &DocumentRef{ + ID: "d2", + Path: "projects/P/databases/D/documents/c1/d1/c2/d2", + Parent: &CollectionRef{ + ID: "c2", + parentPath: "projects/P/databases/D/documents/c1/d1", + Path: "projects/P/databases/D/documents/c1/d1/c2", + c: c, + Query: Query{c: c, collectionID: "c2", parentPath: "projects/P/databases/D/documents/c1/d1"}, + Parent: &DocumentRef{ + ID: "d1", + Path: "projects/P/databases/D/documents/c1/d1", + Parent: &CollectionRef{ + ID: "c1", + c: c, + parentPath: "projects/P/databases/D", + Path: "projects/P/databases/D/documents/c1", + Parent: nil, + Query: Query{c: c, collectionID: "c1", parentPath: "projects/P/databases/D"}, + }, + }, + }, + } + if !testEqual(got, want) { + t.Errorf("\ngot %+v\nwant %+v", got, want) + } +} + +func TestTypeString(t *testing.T) { + for _, test := range []struct { + in *pb.Value + want string + }{ + {nullValue, "null"}, + {intval(1), "int"}, + {floatval(1), "float"}, + {boolval(true), "bool"}, + {strval(""), "string"}, + {tsval(tm), "timestamp"}, + {geoval(ll), "GeoPoint"}, + {bytesval(nil), "bytes"}, + {refval(""), "reference"}, + {arrayval(nil), "array"}, + {mapval(nil), "map"}, + } { + got := typeString(test.in) + if got != test.want { + t.Errorf("%+v: got %q, want %q", test.in, got, test.want) + } + } +} diff --git a/vendor/cloud.google.com/go/firestore/genproto/test.pb.go b/vendor/cloud.google.com/go/firestore/genproto/test.pb.go new file mode 100644 index 00000000..1c8cb4ad --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/genproto/test.pb.go @@ -0,0 +1,1853 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: test.proto + +package tests + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import timestamp "github.com/golang/protobuf/ptypes/timestamp" +import v1beta1 "google.golang.org/genproto/googleapis/firestore/v1beta1" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type DocChange_Kind int32 + +const ( + DocChange_KIND_UNSPECIFIED DocChange_Kind = 0 + DocChange_ADDED DocChange_Kind = 1 + DocChange_REMOVED DocChange_Kind = 2 + DocChange_MODIFIED DocChange_Kind = 3 +) + +var DocChange_Kind_name = map[int32]string{ + 0: "KIND_UNSPECIFIED", + 1: "ADDED", + 2: "REMOVED", + 3: "MODIFIED", +} +var DocChange_Kind_value = map[string]int32{ + "KIND_UNSPECIFIED": 0, + "ADDED": 1, + "REMOVED": 2, + "MODIFIED": 3, +} + +func (x DocChange_Kind) String() string { + return proto.EnumName(DocChange_Kind_name, int32(x)) +} +func (DocChange_Kind) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{19, 0} +} + +// A collection of tests. +type TestSuite struct { + Tests []*Test `protobuf:"bytes,1,rep,name=tests,proto3" json:"tests,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TestSuite) Reset() { *m = TestSuite{} } +func (m *TestSuite) String() string { return proto.CompactTextString(m) } +func (*TestSuite) ProtoMessage() {} +func (*TestSuite) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{0} +} +func (m *TestSuite) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TestSuite.Unmarshal(m, b) +} +func (m *TestSuite) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TestSuite.Marshal(b, m, deterministic) +} +func (dst *TestSuite) XXX_Merge(src proto.Message) { + xxx_messageInfo_TestSuite.Merge(dst, src) +} +func (m *TestSuite) XXX_Size() int { + return xxx_messageInfo_TestSuite.Size(m) +} +func (m *TestSuite) XXX_DiscardUnknown() { + xxx_messageInfo_TestSuite.DiscardUnknown(m) +} + +var xxx_messageInfo_TestSuite proto.InternalMessageInfo + +func (m *TestSuite) GetTests() []*Test { + if m != nil { + return m.Tests + } + return nil +} + +// A Test describes a single client method call and its expected result. +type Test struct { + Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"` + // Types that are valid to be assigned to Test: + // *Test_Get + // *Test_Create + // *Test_Set + // *Test_Update + // *Test_UpdatePaths + // *Test_Delete + // *Test_Query + // *Test_Listen + Test isTest_Test `protobuf_oneof:"test"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Test) Reset() { *m = Test{} } +func (m *Test) String() string { return proto.CompactTextString(m) } +func (*Test) ProtoMessage() {} +func (*Test) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{1} +} +func (m *Test) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Test.Unmarshal(m, b) +} +func (m *Test) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Test.Marshal(b, m, deterministic) +} +func (dst *Test) XXX_Merge(src proto.Message) { + xxx_messageInfo_Test.Merge(dst, src) +} +func (m *Test) XXX_Size() int { + return xxx_messageInfo_Test.Size(m) +} +func (m *Test) XXX_DiscardUnknown() { + xxx_messageInfo_Test.DiscardUnknown(m) +} + +var xxx_messageInfo_Test proto.InternalMessageInfo + +type isTest_Test interface { + isTest_Test() +} + +type Test_Get struct { + Get *GetTest `protobuf:"bytes,2,opt,name=get,proto3,oneof"` +} +type Test_Create struct { + Create *CreateTest `protobuf:"bytes,3,opt,name=create,proto3,oneof"` +} +type Test_Set struct { + Set *SetTest `protobuf:"bytes,4,opt,name=set,proto3,oneof"` +} +type Test_Update struct { + Update *UpdateTest `protobuf:"bytes,5,opt,name=update,proto3,oneof"` +} +type Test_UpdatePaths struct { + UpdatePaths *UpdatePathsTest `protobuf:"bytes,6,opt,name=update_paths,json=updatePaths,proto3,oneof"` +} +type Test_Delete struct { + Delete *DeleteTest `protobuf:"bytes,7,opt,name=delete,proto3,oneof"` +} +type Test_Query struct { + Query *QueryTest `protobuf:"bytes,8,opt,name=query,proto3,oneof"` +} +type Test_Listen struct { + Listen *ListenTest `protobuf:"bytes,9,opt,name=listen,proto3,oneof"` +} + +func (*Test_Get) isTest_Test() {} +func (*Test_Create) isTest_Test() {} +func (*Test_Set) isTest_Test() {} +func (*Test_Update) isTest_Test() {} +func (*Test_UpdatePaths) isTest_Test() {} +func (*Test_Delete) isTest_Test() {} +func (*Test_Query) isTest_Test() {} +func (*Test_Listen) isTest_Test() {} + +func (m *Test) GetTest() isTest_Test { + if m != nil { + return m.Test + } + return nil +} + +func (m *Test) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *Test) GetGet() *GetTest { + if x, ok := m.GetTest().(*Test_Get); ok { + return x.Get + } + return nil +} + +func (m *Test) GetCreate() *CreateTest { + if x, ok := m.GetTest().(*Test_Create); ok { + return x.Create + } + return nil +} + +func (m *Test) GetSet() *SetTest { + if x, ok := m.GetTest().(*Test_Set); ok { + return x.Set + } + return nil +} + +func (m *Test) GetUpdate() *UpdateTest { + if x, ok := m.GetTest().(*Test_Update); ok { + return x.Update + } + return nil +} + +func (m *Test) GetUpdatePaths() *UpdatePathsTest { + if x, ok := m.GetTest().(*Test_UpdatePaths); ok { + return x.UpdatePaths + } + return nil +} + +func (m *Test) GetDelete() *DeleteTest { + if x, ok := m.GetTest().(*Test_Delete); ok { + return x.Delete + } + return nil +} + +func (m *Test) GetQuery() *QueryTest { + if x, ok := m.GetTest().(*Test_Query); ok { + return x.Query + } + return nil +} + +func (m *Test) GetListen() *ListenTest { + if x, ok := m.GetTest().(*Test_Listen); ok { + return x.Listen + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*Test) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _Test_OneofMarshaler, _Test_OneofUnmarshaler, _Test_OneofSizer, []interface{}{ + (*Test_Get)(nil), + (*Test_Create)(nil), + (*Test_Set)(nil), + (*Test_Update)(nil), + (*Test_UpdatePaths)(nil), + (*Test_Delete)(nil), + (*Test_Query)(nil), + (*Test_Listen)(nil), + } +} + +func _Test_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*Test) + // test + switch x := m.Test.(type) { + case *Test_Get: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Get); err != nil { + return err + } + case *Test_Create: + b.EncodeVarint(3<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Create); err != nil { + return err + } + case *Test_Set: + b.EncodeVarint(4<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Set); err != nil { + return err + } + case *Test_Update: + b.EncodeVarint(5<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Update); err != nil { + return err + } + case *Test_UpdatePaths: + b.EncodeVarint(6<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.UpdatePaths); err != nil { + return err + } + case *Test_Delete: + b.EncodeVarint(7<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Delete); err != nil { + return err + } + case *Test_Query: + b.EncodeVarint(8<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Query); err != nil { + return err + } + case *Test_Listen: + b.EncodeVarint(9<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Listen); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("Test.Test has unexpected type %T", x) + } + return nil +} + +func _Test_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*Test) + switch tag { + case 2: // test.get + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(GetTest) + err := b.DecodeMessage(msg) + m.Test = &Test_Get{msg} + return true, err + case 3: // test.create + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(CreateTest) + err := b.DecodeMessage(msg) + m.Test = &Test_Create{msg} + return true, err + case 4: // test.set + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(SetTest) + err := b.DecodeMessage(msg) + m.Test = &Test_Set{msg} + return true, err + case 5: // test.update + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(UpdateTest) + err := b.DecodeMessage(msg) + m.Test = &Test_Update{msg} + return true, err + case 6: // test.update_paths + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(UpdatePathsTest) + err := b.DecodeMessage(msg) + m.Test = &Test_UpdatePaths{msg} + return true, err + case 7: // test.delete + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(DeleteTest) + err := b.DecodeMessage(msg) + m.Test = &Test_Delete{msg} + return true, err + case 8: // test.query + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(QueryTest) + err := b.DecodeMessage(msg) + m.Test = &Test_Query{msg} + return true, err + case 9: // test.listen + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(ListenTest) + err := b.DecodeMessage(msg) + m.Test = &Test_Listen{msg} + return true, err + default: + return false, nil + } +} + +func _Test_OneofSizer(msg proto.Message) (n int) { + m := msg.(*Test) + // test + switch x := m.Test.(type) { + case *Test_Get: + s := proto.Size(x.Get) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Test_Create: + s := proto.Size(x.Create) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Test_Set: + s := proto.Size(x.Set) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Test_Update: + s := proto.Size(x.Update) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Test_UpdatePaths: + s := proto.Size(x.UpdatePaths) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Test_Delete: + s := proto.Size(x.Delete) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Test_Query: + s := proto.Size(x.Query) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Test_Listen: + s := proto.Size(x.Listen) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +// Call to the DocumentRef.Get method. +type GetTest struct { + // The path of the doc, e.g. "projects/projectID/databases/(default)/documents/C/d" + DocRefPath string `protobuf:"bytes,1,opt,name=doc_ref_path,json=docRefPath,proto3" json:"doc_ref_path,omitempty"` + // The request that the call should send to the Firestore service. + Request *v1beta1.GetDocumentRequest `protobuf:"bytes,2,opt,name=request,proto3" json:"request,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GetTest) Reset() { *m = GetTest{} } +func (m *GetTest) String() string { return proto.CompactTextString(m) } +func (*GetTest) ProtoMessage() {} +func (*GetTest) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{2} +} +func (m *GetTest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_GetTest.Unmarshal(m, b) +} +func (m *GetTest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_GetTest.Marshal(b, m, deterministic) +} +func (dst *GetTest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetTest.Merge(dst, src) +} +func (m *GetTest) XXX_Size() int { + return xxx_messageInfo_GetTest.Size(m) +} +func (m *GetTest) XXX_DiscardUnknown() { + xxx_messageInfo_GetTest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetTest proto.InternalMessageInfo + +func (m *GetTest) GetDocRefPath() string { + if m != nil { + return m.DocRefPath + } + return "" +} + +func (m *GetTest) GetRequest() *v1beta1.GetDocumentRequest { + if m != nil { + return m.Request + } + return nil +} + +// Call to DocumentRef.Create. +type CreateTest struct { + // The path of the doc, e.g. "projects/projectID/databases/(default)/documents/C/d" + DocRefPath string `protobuf:"bytes,1,opt,name=doc_ref_path,json=docRefPath,proto3" json:"doc_ref_path,omitempty"` + // The data passed to Create, as JSON. The strings "Delete" and "ServerTimestamp" + // denote the two special sentinel values. Values that could be interpreted as integers + // (i.e. digit strings) should be treated as integers. + JsonData string `protobuf:"bytes,2,opt,name=json_data,json=jsonData,proto3" json:"json_data,omitempty"` + // The request that the call should generate. + Request *v1beta1.CommitRequest `protobuf:"bytes,3,opt,name=request,proto3" json:"request,omitempty"` + // If true, the call should result in an error without generating a request. + // If this is true, request should not be set. + IsError bool `protobuf:"varint,4,opt,name=is_error,json=isError,proto3" json:"is_error,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CreateTest) Reset() { *m = CreateTest{} } +func (m *CreateTest) String() string { return proto.CompactTextString(m) } +func (*CreateTest) ProtoMessage() {} +func (*CreateTest) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{3} +} +func (m *CreateTest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CreateTest.Unmarshal(m, b) +} +func (m *CreateTest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CreateTest.Marshal(b, m, deterministic) +} +func (dst *CreateTest) XXX_Merge(src proto.Message) { + xxx_messageInfo_CreateTest.Merge(dst, src) +} +func (m *CreateTest) XXX_Size() int { + return xxx_messageInfo_CreateTest.Size(m) +} +func (m *CreateTest) XXX_DiscardUnknown() { + xxx_messageInfo_CreateTest.DiscardUnknown(m) +} + +var xxx_messageInfo_CreateTest proto.InternalMessageInfo + +func (m *CreateTest) GetDocRefPath() string { + if m != nil { + return m.DocRefPath + } + return "" +} + +func (m *CreateTest) GetJsonData() string { + if m != nil { + return m.JsonData + } + return "" +} + +func (m *CreateTest) GetRequest() *v1beta1.CommitRequest { + if m != nil { + return m.Request + } + return nil +} + +func (m *CreateTest) GetIsError() bool { + if m != nil { + return m.IsError + } + return false +} + +// A call to DocumentRef.Set. +type SetTest struct { + DocRefPath string `protobuf:"bytes,1,opt,name=doc_ref_path,json=docRefPath,proto3" json:"doc_ref_path,omitempty"` + Option *SetOption `protobuf:"bytes,2,opt,name=option,proto3" json:"option,omitempty"` + JsonData string `protobuf:"bytes,3,opt,name=json_data,json=jsonData,proto3" json:"json_data,omitempty"` + Request *v1beta1.CommitRequest `protobuf:"bytes,4,opt,name=request,proto3" json:"request,omitempty"` + IsError bool `protobuf:"varint,5,opt,name=is_error,json=isError,proto3" json:"is_error,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetTest) Reset() { *m = SetTest{} } +func (m *SetTest) String() string { return proto.CompactTextString(m) } +func (*SetTest) ProtoMessage() {} +func (*SetTest) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{4} +} +func (m *SetTest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetTest.Unmarshal(m, b) +} +func (m *SetTest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetTest.Marshal(b, m, deterministic) +} +func (dst *SetTest) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetTest.Merge(dst, src) +} +func (m *SetTest) XXX_Size() int { + return xxx_messageInfo_SetTest.Size(m) +} +func (m *SetTest) XXX_DiscardUnknown() { + xxx_messageInfo_SetTest.DiscardUnknown(m) +} + +var xxx_messageInfo_SetTest proto.InternalMessageInfo + +func (m *SetTest) GetDocRefPath() string { + if m != nil { + return m.DocRefPath + } + return "" +} + +func (m *SetTest) GetOption() *SetOption { + if m != nil { + return m.Option + } + return nil +} + +func (m *SetTest) GetJsonData() string { + if m != nil { + return m.JsonData + } + return "" +} + +func (m *SetTest) GetRequest() *v1beta1.CommitRequest { + if m != nil { + return m.Request + } + return nil +} + +func (m *SetTest) GetIsError() bool { + if m != nil { + return m.IsError + } + return false +} + +// A call to the form of DocumentRef.Update that represents the data as a map +// or dictionary. +type UpdateTest struct { + DocRefPath string `protobuf:"bytes,1,opt,name=doc_ref_path,json=docRefPath,proto3" json:"doc_ref_path,omitempty"` + Precondition *v1beta1.Precondition `protobuf:"bytes,2,opt,name=precondition,proto3" json:"precondition,omitempty"` + JsonData string `protobuf:"bytes,3,opt,name=json_data,json=jsonData,proto3" json:"json_data,omitempty"` + Request *v1beta1.CommitRequest `protobuf:"bytes,4,opt,name=request,proto3" json:"request,omitempty"` + IsError bool `protobuf:"varint,5,opt,name=is_error,json=isError,proto3" json:"is_error,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdateTest) Reset() { *m = UpdateTest{} } +func (m *UpdateTest) String() string { return proto.CompactTextString(m) } +func (*UpdateTest) ProtoMessage() {} +func (*UpdateTest) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{5} +} +func (m *UpdateTest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdateTest.Unmarshal(m, b) +} +func (m *UpdateTest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdateTest.Marshal(b, m, deterministic) +} +func (dst *UpdateTest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateTest.Merge(dst, src) +} +func (m *UpdateTest) XXX_Size() int { + return xxx_messageInfo_UpdateTest.Size(m) +} +func (m *UpdateTest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateTest.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateTest proto.InternalMessageInfo + +func (m *UpdateTest) GetDocRefPath() string { + if m != nil { + return m.DocRefPath + } + return "" +} + +func (m *UpdateTest) GetPrecondition() *v1beta1.Precondition { + if m != nil { + return m.Precondition + } + return nil +} + +func (m *UpdateTest) GetJsonData() string { + if m != nil { + return m.JsonData + } + return "" +} + +func (m *UpdateTest) GetRequest() *v1beta1.CommitRequest { + if m != nil { + return m.Request + } + return nil +} + +func (m *UpdateTest) GetIsError() bool { + if m != nil { + return m.IsError + } + return false +} + +// A call to the form of DocumentRef.Update that represents the data as a list +// of field paths and their values. +type UpdatePathsTest struct { + DocRefPath string `protobuf:"bytes,1,opt,name=doc_ref_path,json=docRefPath,proto3" json:"doc_ref_path,omitempty"` + Precondition *v1beta1.Precondition `protobuf:"bytes,2,opt,name=precondition,proto3" json:"precondition,omitempty"` + // parallel sequences: field_paths[i] corresponds to json_values[i] + FieldPaths []*FieldPath `protobuf:"bytes,3,rep,name=field_paths,json=fieldPaths,proto3" json:"field_paths,omitempty"` + JsonValues []string `protobuf:"bytes,4,rep,name=json_values,json=jsonValues,proto3" json:"json_values,omitempty"` + Request *v1beta1.CommitRequest `protobuf:"bytes,5,opt,name=request,proto3" json:"request,omitempty"` + IsError bool `protobuf:"varint,6,opt,name=is_error,json=isError,proto3" json:"is_error,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UpdatePathsTest) Reset() { *m = UpdatePathsTest{} } +func (m *UpdatePathsTest) String() string { return proto.CompactTextString(m) } +func (*UpdatePathsTest) ProtoMessage() {} +func (*UpdatePathsTest) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{6} +} +func (m *UpdatePathsTest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UpdatePathsTest.Unmarshal(m, b) +} +func (m *UpdatePathsTest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UpdatePathsTest.Marshal(b, m, deterministic) +} +func (dst *UpdatePathsTest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdatePathsTest.Merge(dst, src) +} +func (m *UpdatePathsTest) XXX_Size() int { + return xxx_messageInfo_UpdatePathsTest.Size(m) +} +func (m *UpdatePathsTest) XXX_DiscardUnknown() { + xxx_messageInfo_UpdatePathsTest.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdatePathsTest proto.InternalMessageInfo + +func (m *UpdatePathsTest) GetDocRefPath() string { + if m != nil { + return m.DocRefPath + } + return "" +} + +func (m *UpdatePathsTest) GetPrecondition() *v1beta1.Precondition { + if m != nil { + return m.Precondition + } + return nil +} + +func (m *UpdatePathsTest) GetFieldPaths() []*FieldPath { + if m != nil { + return m.FieldPaths + } + return nil +} + +func (m *UpdatePathsTest) GetJsonValues() []string { + if m != nil { + return m.JsonValues + } + return nil +} + +func (m *UpdatePathsTest) GetRequest() *v1beta1.CommitRequest { + if m != nil { + return m.Request + } + return nil +} + +func (m *UpdatePathsTest) GetIsError() bool { + if m != nil { + return m.IsError + } + return false +} + +// A call to DocmentRef.Delete +type DeleteTest struct { + DocRefPath string `protobuf:"bytes,1,opt,name=doc_ref_path,json=docRefPath,proto3" json:"doc_ref_path,omitempty"` + Precondition *v1beta1.Precondition `protobuf:"bytes,2,opt,name=precondition,proto3" json:"precondition,omitempty"` + Request *v1beta1.CommitRequest `protobuf:"bytes,3,opt,name=request,proto3" json:"request,omitempty"` + IsError bool `protobuf:"varint,4,opt,name=is_error,json=isError,proto3" json:"is_error,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DeleteTest) Reset() { *m = DeleteTest{} } +func (m *DeleteTest) String() string { return proto.CompactTextString(m) } +func (*DeleteTest) ProtoMessage() {} +func (*DeleteTest) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{7} +} +func (m *DeleteTest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DeleteTest.Unmarshal(m, b) +} +func (m *DeleteTest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DeleteTest.Marshal(b, m, deterministic) +} +func (dst *DeleteTest) XXX_Merge(src proto.Message) { + xxx_messageInfo_DeleteTest.Merge(dst, src) +} +func (m *DeleteTest) XXX_Size() int { + return xxx_messageInfo_DeleteTest.Size(m) +} +func (m *DeleteTest) XXX_DiscardUnknown() { + xxx_messageInfo_DeleteTest.DiscardUnknown(m) +} + +var xxx_messageInfo_DeleteTest proto.InternalMessageInfo + +func (m *DeleteTest) GetDocRefPath() string { + if m != nil { + return m.DocRefPath + } + return "" +} + +func (m *DeleteTest) GetPrecondition() *v1beta1.Precondition { + if m != nil { + return m.Precondition + } + return nil +} + +func (m *DeleteTest) GetRequest() *v1beta1.CommitRequest { + if m != nil { + return m.Request + } + return nil +} + +func (m *DeleteTest) GetIsError() bool { + if m != nil { + return m.IsError + } + return false +} + +// An option to the DocumentRef.Set call. +type SetOption struct { + All bool `protobuf:"varint,1,opt,name=all,proto3" json:"all,omitempty"` + Fields []*FieldPath `protobuf:"bytes,2,rep,name=fields,proto3" json:"fields,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SetOption) Reset() { *m = SetOption{} } +func (m *SetOption) String() string { return proto.CompactTextString(m) } +func (*SetOption) ProtoMessage() {} +func (*SetOption) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{8} +} +func (m *SetOption) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SetOption.Unmarshal(m, b) +} +func (m *SetOption) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SetOption.Marshal(b, m, deterministic) +} +func (dst *SetOption) XXX_Merge(src proto.Message) { + xxx_messageInfo_SetOption.Merge(dst, src) +} +func (m *SetOption) XXX_Size() int { + return xxx_messageInfo_SetOption.Size(m) +} +func (m *SetOption) XXX_DiscardUnknown() { + xxx_messageInfo_SetOption.DiscardUnknown(m) +} + +var xxx_messageInfo_SetOption proto.InternalMessageInfo + +func (m *SetOption) GetAll() bool { + if m != nil { + return m.All + } + return false +} + +func (m *SetOption) GetFields() []*FieldPath { + if m != nil { + return m.Fields + } + return nil +} + +type QueryTest struct { + CollPath string `protobuf:"bytes,1,opt,name=coll_path,json=collPath,proto3" json:"coll_path,omitempty"` + Clauses []*Clause `protobuf:"bytes,2,rep,name=clauses,proto3" json:"clauses,omitempty"` + Query *v1beta1.StructuredQuery `protobuf:"bytes,3,opt,name=query,proto3" json:"query,omitempty"` + IsError bool `protobuf:"varint,4,opt,name=is_error,json=isError,proto3" json:"is_error,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *QueryTest) Reset() { *m = QueryTest{} } +func (m *QueryTest) String() string { return proto.CompactTextString(m) } +func (*QueryTest) ProtoMessage() {} +func (*QueryTest) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{9} +} +func (m *QueryTest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_QueryTest.Unmarshal(m, b) +} +func (m *QueryTest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_QueryTest.Marshal(b, m, deterministic) +} +func (dst *QueryTest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTest.Merge(dst, src) +} +func (m *QueryTest) XXX_Size() int { + return xxx_messageInfo_QueryTest.Size(m) +} +func (m *QueryTest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTest proto.InternalMessageInfo + +func (m *QueryTest) GetCollPath() string { + if m != nil { + return m.CollPath + } + return "" +} + +func (m *QueryTest) GetClauses() []*Clause { + if m != nil { + return m.Clauses + } + return nil +} + +func (m *QueryTest) GetQuery() *v1beta1.StructuredQuery { + if m != nil { + return m.Query + } + return nil +} + +func (m *QueryTest) GetIsError() bool { + if m != nil { + return m.IsError + } + return false +} + +type Clause struct { + // Types that are valid to be assigned to Clause: + // *Clause_Select + // *Clause_Where + // *Clause_OrderBy + // *Clause_Offset + // *Clause_Limit + // *Clause_StartAt + // *Clause_StartAfter + // *Clause_EndAt + // *Clause_EndBefore + Clause isClause_Clause `protobuf_oneof:"clause"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Clause) Reset() { *m = Clause{} } +func (m *Clause) String() string { return proto.CompactTextString(m) } +func (*Clause) ProtoMessage() {} +func (*Clause) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{10} +} +func (m *Clause) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Clause.Unmarshal(m, b) +} +func (m *Clause) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Clause.Marshal(b, m, deterministic) +} +func (dst *Clause) XXX_Merge(src proto.Message) { + xxx_messageInfo_Clause.Merge(dst, src) +} +func (m *Clause) XXX_Size() int { + return xxx_messageInfo_Clause.Size(m) +} +func (m *Clause) XXX_DiscardUnknown() { + xxx_messageInfo_Clause.DiscardUnknown(m) +} + +var xxx_messageInfo_Clause proto.InternalMessageInfo + +type isClause_Clause interface { + isClause_Clause() +} + +type Clause_Select struct { + Select *Select `protobuf:"bytes,1,opt,name=select,proto3,oneof"` +} +type Clause_Where struct { + Where *Where `protobuf:"bytes,2,opt,name=where,proto3,oneof"` +} +type Clause_OrderBy struct { + OrderBy *OrderBy `protobuf:"bytes,3,opt,name=order_by,json=orderBy,proto3,oneof"` +} +type Clause_Offset struct { + Offset int32 `protobuf:"varint,4,opt,name=offset,proto3,oneof"` +} +type Clause_Limit struct { + Limit int32 `protobuf:"varint,5,opt,name=limit,proto3,oneof"` +} +type Clause_StartAt struct { + StartAt *Cursor `protobuf:"bytes,6,opt,name=start_at,json=startAt,proto3,oneof"` +} +type Clause_StartAfter struct { + StartAfter *Cursor `protobuf:"bytes,7,opt,name=start_after,json=startAfter,proto3,oneof"` +} +type Clause_EndAt struct { + EndAt *Cursor `protobuf:"bytes,8,opt,name=end_at,json=endAt,proto3,oneof"` +} +type Clause_EndBefore struct { + EndBefore *Cursor `protobuf:"bytes,9,opt,name=end_before,json=endBefore,proto3,oneof"` +} + +func (*Clause_Select) isClause_Clause() {} +func (*Clause_Where) isClause_Clause() {} +func (*Clause_OrderBy) isClause_Clause() {} +func (*Clause_Offset) isClause_Clause() {} +func (*Clause_Limit) isClause_Clause() {} +func (*Clause_StartAt) isClause_Clause() {} +func (*Clause_StartAfter) isClause_Clause() {} +func (*Clause_EndAt) isClause_Clause() {} +func (*Clause_EndBefore) isClause_Clause() {} + +func (m *Clause) GetClause() isClause_Clause { + if m != nil { + return m.Clause + } + return nil +} + +func (m *Clause) GetSelect() *Select { + if x, ok := m.GetClause().(*Clause_Select); ok { + return x.Select + } + return nil +} + +func (m *Clause) GetWhere() *Where { + if x, ok := m.GetClause().(*Clause_Where); ok { + return x.Where + } + return nil +} + +func (m *Clause) GetOrderBy() *OrderBy { + if x, ok := m.GetClause().(*Clause_OrderBy); ok { + return x.OrderBy + } + return nil +} + +func (m *Clause) GetOffset() int32 { + if x, ok := m.GetClause().(*Clause_Offset); ok { + return x.Offset + } + return 0 +} + +func (m *Clause) GetLimit() int32 { + if x, ok := m.GetClause().(*Clause_Limit); ok { + return x.Limit + } + return 0 +} + +func (m *Clause) GetStartAt() *Cursor { + if x, ok := m.GetClause().(*Clause_StartAt); ok { + return x.StartAt + } + return nil +} + +func (m *Clause) GetStartAfter() *Cursor { + if x, ok := m.GetClause().(*Clause_StartAfter); ok { + return x.StartAfter + } + return nil +} + +func (m *Clause) GetEndAt() *Cursor { + if x, ok := m.GetClause().(*Clause_EndAt); ok { + return x.EndAt + } + return nil +} + +func (m *Clause) GetEndBefore() *Cursor { + if x, ok := m.GetClause().(*Clause_EndBefore); ok { + return x.EndBefore + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*Clause) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _Clause_OneofMarshaler, _Clause_OneofUnmarshaler, _Clause_OneofSizer, []interface{}{ + (*Clause_Select)(nil), + (*Clause_Where)(nil), + (*Clause_OrderBy)(nil), + (*Clause_Offset)(nil), + (*Clause_Limit)(nil), + (*Clause_StartAt)(nil), + (*Clause_StartAfter)(nil), + (*Clause_EndAt)(nil), + (*Clause_EndBefore)(nil), + } +} + +func _Clause_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*Clause) + // clause + switch x := m.Clause.(type) { + case *Clause_Select: + b.EncodeVarint(1<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Select); err != nil { + return err + } + case *Clause_Where: + b.EncodeVarint(2<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.Where); err != nil { + return err + } + case *Clause_OrderBy: + b.EncodeVarint(3<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.OrderBy); err != nil { + return err + } + case *Clause_Offset: + b.EncodeVarint(4<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.Offset)) + case *Clause_Limit: + b.EncodeVarint(5<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.Limit)) + case *Clause_StartAt: + b.EncodeVarint(6<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.StartAt); err != nil { + return err + } + case *Clause_StartAfter: + b.EncodeVarint(7<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.StartAfter); err != nil { + return err + } + case *Clause_EndAt: + b.EncodeVarint(8<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.EndAt); err != nil { + return err + } + case *Clause_EndBefore: + b.EncodeVarint(9<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.EndBefore); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("Clause.Clause has unexpected type %T", x) + } + return nil +} + +func _Clause_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*Clause) + switch tag { + case 1: // clause.select + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Select) + err := b.DecodeMessage(msg) + m.Clause = &Clause_Select{msg} + return true, err + case 2: // clause.where + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Where) + err := b.DecodeMessage(msg) + m.Clause = &Clause_Where{msg} + return true, err + case 3: // clause.order_by + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(OrderBy) + err := b.DecodeMessage(msg) + m.Clause = &Clause_OrderBy{msg} + return true, err + case 4: // clause.offset + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Clause = &Clause_Offset{int32(x)} + return true, err + case 5: // clause.limit + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Clause = &Clause_Limit{int32(x)} + return true, err + case 6: // clause.start_at + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Cursor) + err := b.DecodeMessage(msg) + m.Clause = &Clause_StartAt{msg} + return true, err + case 7: // clause.start_after + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Cursor) + err := b.DecodeMessage(msg) + m.Clause = &Clause_StartAfter{msg} + return true, err + case 8: // clause.end_at + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Cursor) + err := b.DecodeMessage(msg) + m.Clause = &Clause_EndAt{msg} + return true, err + case 9: // clause.end_before + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(Cursor) + err := b.DecodeMessage(msg) + m.Clause = &Clause_EndBefore{msg} + return true, err + default: + return false, nil + } +} + +func _Clause_OneofSizer(msg proto.Message) (n int) { + m := msg.(*Clause) + // clause + switch x := m.Clause.(type) { + case *Clause_Select: + s := proto.Size(x.Select) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Clause_Where: + s := proto.Size(x.Where) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Clause_OrderBy: + s := proto.Size(x.OrderBy) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Clause_Offset: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(x.Offset)) + case *Clause_Limit: + n += 1 // tag and wire + n += proto.SizeVarint(uint64(x.Limit)) + case *Clause_StartAt: + s := proto.Size(x.StartAt) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Clause_StartAfter: + s := proto.Size(x.StartAfter) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Clause_EndAt: + s := proto.Size(x.EndAt) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case *Clause_EndBefore: + s := proto.Size(x.EndBefore) + n += 1 // tag and wire + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type Select struct { + Fields []*FieldPath `protobuf:"bytes,1,rep,name=fields,proto3" json:"fields,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Select) Reset() { *m = Select{} } +func (m *Select) String() string { return proto.CompactTextString(m) } +func (*Select) ProtoMessage() {} +func (*Select) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{11} +} +func (m *Select) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Select.Unmarshal(m, b) +} +func (m *Select) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Select.Marshal(b, m, deterministic) +} +func (dst *Select) XXX_Merge(src proto.Message) { + xxx_messageInfo_Select.Merge(dst, src) +} +func (m *Select) XXX_Size() int { + return xxx_messageInfo_Select.Size(m) +} +func (m *Select) XXX_DiscardUnknown() { + xxx_messageInfo_Select.DiscardUnknown(m) +} + +var xxx_messageInfo_Select proto.InternalMessageInfo + +func (m *Select) GetFields() []*FieldPath { + if m != nil { + return m.Fields + } + return nil +} + +type Where struct { + Path *FieldPath `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + Op string `protobuf:"bytes,2,opt,name=op,proto3" json:"op,omitempty"` + JsonValue string `protobuf:"bytes,3,opt,name=json_value,json=jsonValue,proto3" json:"json_value,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Where) Reset() { *m = Where{} } +func (m *Where) String() string { return proto.CompactTextString(m) } +func (*Where) ProtoMessage() {} +func (*Where) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{12} +} +func (m *Where) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Where.Unmarshal(m, b) +} +func (m *Where) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Where.Marshal(b, m, deterministic) +} +func (dst *Where) XXX_Merge(src proto.Message) { + xxx_messageInfo_Where.Merge(dst, src) +} +func (m *Where) XXX_Size() int { + return xxx_messageInfo_Where.Size(m) +} +func (m *Where) XXX_DiscardUnknown() { + xxx_messageInfo_Where.DiscardUnknown(m) +} + +var xxx_messageInfo_Where proto.InternalMessageInfo + +func (m *Where) GetPath() *FieldPath { + if m != nil { + return m.Path + } + return nil +} + +func (m *Where) GetOp() string { + if m != nil { + return m.Op + } + return "" +} + +func (m *Where) GetJsonValue() string { + if m != nil { + return m.JsonValue + } + return "" +} + +type OrderBy struct { + Path *FieldPath `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + Direction string `protobuf:"bytes,2,opt,name=direction,proto3" json:"direction,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *OrderBy) Reset() { *m = OrderBy{} } +func (m *OrderBy) String() string { return proto.CompactTextString(m) } +func (*OrderBy) ProtoMessage() {} +func (*OrderBy) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{13} +} +func (m *OrderBy) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_OrderBy.Unmarshal(m, b) +} +func (m *OrderBy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_OrderBy.Marshal(b, m, deterministic) +} +func (dst *OrderBy) XXX_Merge(src proto.Message) { + xxx_messageInfo_OrderBy.Merge(dst, src) +} +func (m *OrderBy) XXX_Size() int { + return xxx_messageInfo_OrderBy.Size(m) +} +func (m *OrderBy) XXX_DiscardUnknown() { + xxx_messageInfo_OrderBy.DiscardUnknown(m) +} + +var xxx_messageInfo_OrderBy proto.InternalMessageInfo + +func (m *OrderBy) GetPath() *FieldPath { + if m != nil { + return m.Path + } + return nil +} + +func (m *OrderBy) GetDirection() string { + if m != nil { + return m.Direction + } + return "" +} + +type Cursor struct { + // one of: + DocSnapshot *DocSnapshot `protobuf:"bytes,1,opt,name=doc_snapshot,json=docSnapshot,proto3" json:"doc_snapshot,omitempty"` + JsonValues []string `protobuf:"bytes,2,rep,name=json_values,json=jsonValues,proto3" json:"json_values,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Cursor) Reset() { *m = Cursor{} } +func (m *Cursor) String() string { return proto.CompactTextString(m) } +func (*Cursor) ProtoMessage() {} +func (*Cursor) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{14} +} +func (m *Cursor) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Cursor.Unmarshal(m, b) +} +func (m *Cursor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Cursor.Marshal(b, m, deterministic) +} +func (dst *Cursor) XXX_Merge(src proto.Message) { + xxx_messageInfo_Cursor.Merge(dst, src) +} +func (m *Cursor) XXX_Size() int { + return xxx_messageInfo_Cursor.Size(m) +} +func (m *Cursor) XXX_DiscardUnknown() { + xxx_messageInfo_Cursor.DiscardUnknown(m) +} + +var xxx_messageInfo_Cursor proto.InternalMessageInfo + +func (m *Cursor) GetDocSnapshot() *DocSnapshot { + if m != nil { + return m.DocSnapshot + } + return nil +} + +func (m *Cursor) GetJsonValues() []string { + if m != nil { + return m.JsonValues + } + return nil +} + +type DocSnapshot struct { + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + JsonData string `protobuf:"bytes,2,opt,name=json_data,json=jsonData,proto3" json:"json_data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DocSnapshot) Reset() { *m = DocSnapshot{} } +func (m *DocSnapshot) String() string { return proto.CompactTextString(m) } +func (*DocSnapshot) ProtoMessage() {} +func (*DocSnapshot) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{15} +} +func (m *DocSnapshot) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DocSnapshot.Unmarshal(m, b) +} +func (m *DocSnapshot) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DocSnapshot.Marshal(b, m, deterministic) +} +func (dst *DocSnapshot) XXX_Merge(src proto.Message) { + xxx_messageInfo_DocSnapshot.Merge(dst, src) +} +func (m *DocSnapshot) XXX_Size() int { + return xxx_messageInfo_DocSnapshot.Size(m) +} +func (m *DocSnapshot) XXX_DiscardUnknown() { + xxx_messageInfo_DocSnapshot.DiscardUnknown(m) +} + +var xxx_messageInfo_DocSnapshot proto.InternalMessageInfo + +func (m *DocSnapshot) GetPath() string { + if m != nil { + return m.Path + } + return "" +} + +func (m *DocSnapshot) GetJsonData() string { + if m != nil { + return m.JsonData + } + return "" +} + +type FieldPath struct { + Field []string `protobuf:"bytes,1,rep,name=field,proto3" json:"field,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FieldPath) Reset() { *m = FieldPath{} } +func (m *FieldPath) String() string { return proto.CompactTextString(m) } +func (*FieldPath) ProtoMessage() {} +func (*FieldPath) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{16} +} +func (m *FieldPath) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FieldPath.Unmarshal(m, b) +} +func (m *FieldPath) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FieldPath.Marshal(b, m, deterministic) +} +func (dst *FieldPath) XXX_Merge(src proto.Message) { + xxx_messageInfo_FieldPath.Merge(dst, src) +} +func (m *FieldPath) XXX_Size() int { + return xxx_messageInfo_FieldPath.Size(m) +} +func (m *FieldPath) XXX_DiscardUnknown() { + xxx_messageInfo_FieldPath.DiscardUnknown(m) +} + +var xxx_messageInfo_FieldPath proto.InternalMessageInfo + +func (m *FieldPath) GetField() []string { + if m != nil { + return m.Field + } + return nil +} + +// A test of the Listen streaming RPC (a.k.a. FireStore watch). +// If the sequence of responses is provided to the implementation, +// it should produce the sequence of snapshots. +// If is_error is true, an error should occur after the snapshots. +// +// The tests assume that the query is +// Collection("projects/projectID/databases/(default)/documents/C").OrderBy("a", Ascending) +// +// The watch target ID used in these tests is 1. Test interpreters +// should either change their client's ID for testing, +// or change the ID in the tests before running them. +type ListenTest struct { + Responses []*v1beta1.ListenResponse `protobuf:"bytes,1,rep,name=responses,proto3" json:"responses,omitempty"` + Snapshots []*Snapshot `protobuf:"bytes,2,rep,name=snapshots,proto3" json:"snapshots,omitempty"` + IsError bool `protobuf:"varint,3,opt,name=is_error,json=isError,proto3" json:"is_error,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ListenTest) Reset() { *m = ListenTest{} } +func (m *ListenTest) String() string { return proto.CompactTextString(m) } +func (*ListenTest) ProtoMessage() {} +func (*ListenTest) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{17} +} +func (m *ListenTest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ListenTest.Unmarshal(m, b) +} +func (m *ListenTest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ListenTest.Marshal(b, m, deterministic) +} +func (dst *ListenTest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ListenTest.Merge(dst, src) +} +func (m *ListenTest) XXX_Size() int { + return xxx_messageInfo_ListenTest.Size(m) +} +func (m *ListenTest) XXX_DiscardUnknown() { + xxx_messageInfo_ListenTest.DiscardUnknown(m) +} + +var xxx_messageInfo_ListenTest proto.InternalMessageInfo + +func (m *ListenTest) GetResponses() []*v1beta1.ListenResponse { + if m != nil { + return m.Responses + } + return nil +} + +func (m *ListenTest) GetSnapshots() []*Snapshot { + if m != nil { + return m.Snapshots + } + return nil +} + +func (m *ListenTest) GetIsError() bool { + if m != nil { + return m.IsError + } + return false +} + +type Snapshot struct { + Docs []*v1beta1.Document `protobuf:"bytes,1,rep,name=docs,proto3" json:"docs,omitempty"` + Changes []*DocChange `protobuf:"bytes,2,rep,name=changes,proto3" json:"changes,omitempty"` + ReadTime *timestamp.Timestamp `protobuf:"bytes,3,opt,name=read_time,json=readTime,proto3" json:"read_time,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Snapshot) Reset() { *m = Snapshot{} } +func (m *Snapshot) String() string { return proto.CompactTextString(m) } +func (*Snapshot) ProtoMessage() {} +func (*Snapshot) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{18} +} +func (m *Snapshot) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Snapshot.Unmarshal(m, b) +} +func (m *Snapshot) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Snapshot.Marshal(b, m, deterministic) +} +func (dst *Snapshot) XXX_Merge(src proto.Message) { + xxx_messageInfo_Snapshot.Merge(dst, src) +} +func (m *Snapshot) XXX_Size() int { + return xxx_messageInfo_Snapshot.Size(m) +} +func (m *Snapshot) XXX_DiscardUnknown() { + xxx_messageInfo_Snapshot.DiscardUnknown(m) +} + +var xxx_messageInfo_Snapshot proto.InternalMessageInfo + +func (m *Snapshot) GetDocs() []*v1beta1.Document { + if m != nil { + return m.Docs + } + return nil +} + +func (m *Snapshot) GetChanges() []*DocChange { + if m != nil { + return m.Changes + } + return nil +} + +func (m *Snapshot) GetReadTime() *timestamp.Timestamp { + if m != nil { + return m.ReadTime + } + return nil +} + +type DocChange struct { + Kind DocChange_Kind `protobuf:"varint,1,opt,name=kind,proto3,enum=tests.DocChange_Kind" json:"kind,omitempty"` + Doc *v1beta1.Document `protobuf:"bytes,2,opt,name=doc,proto3" json:"doc,omitempty"` + OldIndex int32 `protobuf:"varint,3,opt,name=old_index,json=oldIndex,proto3" json:"old_index,omitempty"` + NewIndex int32 `protobuf:"varint,4,opt,name=new_index,json=newIndex,proto3" json:"new_index,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *DocChange) Reset() { *m = DocChange{} } +func (m *DocChange) String() string { return proto.CompactTextString(m) } +func (*DocChange) ProtoMessage() {} +func (*DocChange) Descriptor() ([]byte, []int) { + return fileDescriptor_test_338de568ad9314f7, []int{19} +} +func (m *DocChange) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_DocChange.Unmarshal(m, b) +} +func (m *DocChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_DocChange.Marshal(b, m, deterministic) +} +func (dst *DocChange) XXX_Merge(src proto.Message) { + xxx_messageInfo_DocChange.Merge(dst, src) +} +func (m *DocChange) XXX_Size() int { + return xxx_messageInfo_DocChange.Size(m) +} +func (m *DocChange) XXX_DiscardUnknown() { + xxx_messageInfo_DocChange.DiscardUnknown(m) +} + +var xxx_messageInfo_DocChange proto.InternalMessageInfo + +func (m *DocChange) GetKind() DocChange_Kind { + if m != nil { + return m.Kind + } + return DocChange_KIND_UNSPECIFIED +} + +func (m *DocChange) GetDoc() *v1beta1.Document { + if m != nil { + return m.Doc + } + return nil +} + +func (m *DocChange) GetOldIndex() int32 { + if m != nil { + return m.OldIndex + } + return 0 +} + +func (m *DocChange) GetNewIndex() int32 { + if m != nil { + return m.NewIndex + } + return 0 +} + +func init() { + proto.RegisterType((*TestSuite)(nil), "tests.TestSuite") + proto.RegisterType((*Test)(nil), "tests.Test") + proto.RegisterType((*GetTest)(nil), "tests.GetTest") + proto.RegisterType((*CreateTest)(nil), "tests.CreateTest") + proto.RegisterType((*SetTest)(nil), "tests.SetTest") + proto.RegisterType((*UpdateTest)(nil), "tests.UpdateTest") + proto.RegisterType((*UpdatePathsTest)(nil), "tests.UpdatePathsTest") + proto.RegisterType((*DeleteTest)(nil), "tests.DeleteTest") + proto.RegisterType((*SetOption)(nil), "tests.SetOption") + proto.RegisterType((*QueryTest)(nil), "tests.QueryTest") + proto.RegisterType((*Clause)(nil), "tests.Clause") + proto.RegisterType((*Select)(nil), "tests.Select") + proto.RegisterType((*Where)(nil), "tests.Where") + proto.RegisterType((*OrderBy)(nil), "tests.OrderBy") + proto.RegisterType((*Cursor)(nil), "tests.Cursor") + proto.RegisterType((*DocSnapshot)(nil), "tests.DocSnapshot") + proto.RegisterType((*FieldPath)(nil), "tests.FieldPath") + proto.RegisterType((*ListenTest)(nil), "tests.ListenTest") + proto.RegisterType((*Snapshot)(nil), "tests.Snapshot") + proto.RegisterType((*DocChange)(nil), "tests.DocChange") + proto.RegisterEnum("tests.DocChange_Kind", DocChange_Kind_name, DocChange_Kind_value) +} + +func init() { proto.RegisterFile("test.proto", fileDescriptor_test_338de568ad9314f7) } + +var fileDescriptor_test_338de568ad9314f7 = []byte{ + // 1292 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0x4d, 0x73, 0xdb, 0xc4, + 0x1b, 0xaf, 0x6c, 0x4b, 0x96, 0x1e, 0xe7, 0xdf, 0xe6, 0xbf, 0x53, 0x3a, 0x26, 0xc0, 0x34, 0xd5, + 0x94, 0xc6, 0x6d, 0xc1, 0xa1, 0xe1, 0xed, 0xc0, 0x0c, 0x4c, 0x12, 0x3b, 0x6d, 0x28, 0x6d, 0x82, + 0xdc, 0x96, 0x4b, 0x66, 0x8c, 0xa2, 0x5d, 0x27, 0x02, 0x59, 0xeb, 0xee, 0xae, 0xfa, 0xf2, 0x39, + 0xb8, 0x73, 0x65, 0x60, 0x86, 0x03, 0x5f, 0x83, 0x13, 0x47, 0x3e, 0x03, 0x77, 0x38, 0x33, 0xfb, + 0x26, 0x59, 0x69, 0x5d, 0x72, 0x28, 0xe5, 0xb6, 0xfb, 0x3c, 0xbf, 0xe7, 0xfd, 0x65, 0x25, 0x00, + 0x41, 0xb8, 0xe8, 0xcf, 0x18, 0x15, 0x14, 0xb9, 0xf2, 0xcc, 0x57, 0xde, 0x3e, 0xa2, 0xf4, 0x28, + 0x23, 0xeb, 0x93, 0x94, 0x11, 0x2e, 0x28, 0x23, 0xeb, 0x8f, 0x6e, 0x1c, 0x12, 0x11, 0xdf, 0x58, + 0x4f, 0xe8, 0x74, 0x4a, 0x73, 0x8d, 0x5e, 0x59, 0x5b, 0x08, 0xc3, 0x34, 0x29, 0xa6, 0x24, 0x37, + 0x6a, 0x57, 0x7a, 0x0b, 0x81, 0x25, 0xc5, 0x20, 0x2f, 0x2f, 0x44, 0x3e, 0x2c, 0x08, 0x7b, 0x6a, + 0x50, 0x17, 0x0d, 0x4a, 0xdd, 0x0e, 0x8b, 0xc9, 0xba, 0x48, 0xa7, 0x84, 0x8b, 0x78, 0x3a, 0xd3, + 0x80, 0xb0, 0x0f, 0xc1, 0x3d, 0xc2, 0xc5, 0xa8, 0x48, 0x05, 0x41, 0x97, 0x40, 0x87, 0xd5, 0x75, + 0x56, 0x9b, 0xbd, 0xce, 0x46, 0xa7, 0xaf, 0x6e, 0x7d, 0x09, 0x88, 0x34, 0x27, 0xfc, 0xae, 0x09, + 0x2d, 0x79, 0x47, 0xab, 0xd0, 0xc1, 0x84, 0x27, 0x2c, 0x9d, 0x89, 0x94, 0xe6, 0x5d, 0x67, 0xd5, + 0xe9, 0x05, 0xd1, 0x3c, 0x09, 0x85, 0xd0, 0x3c, 0x22, 0xa2, 0xdb, 0x58, 0x75, 0x7a, 0x9d, 0x8d, + 0xb3, 0x46, 0xd7, 0x4d, 0x22, 0xa4, 0xf8, 0xad, 0x33, 0x91, 0x64, 0xa2, 0xeb, 0xe0, 0x25, 0x8c, + 0xc4, 0x82, 0x74, 0x9b, 0x0a, 0xf6, 0x7f, 0x03, 0xdb, 0x56, 0x44, 0x83, 0x34, 0x10, 0xa9, 0x90, + 0x13, 0xd1, 0x6d, 0xd5, 0x14, 0x8e, 0x2a, 0x85, 0x5c, 0x2b, 0x2c, 0x66, 0x58, 0x2a, 0x74, 0x6b, + 0x0a, 0xef, 0x2b, 0xa2, 0x55, 0xa8, 0x21, 0xe8, 0x13, 0x58, 0xd2, 0xa7, 0xf1, 0x2c, 0x16, 0xc7, + 0xbc, 0xeb, 0x29, 0x91, 0x0b, 0x35, 0x91, 0x7d, 0xc9, 0x31, 0x72, 0x9d, 0xa2, 0x22, 0x49, 0x4b, + 0x98, 0x64, 0x44, 0x90, 0x6e, 0xbb, 0x66, 0x69, 0xa0, 0x88, 0xd6, 0x92, 0x86, 0xa0, 0x1e, 0xb8, + 0xaa, 0x2c, 0x5d, 0x5f, 0x61, 0x97, 0x0d, 0xf6, 0x4b, 0x49, 0x33, 0x50, 0x0d, 0x90, 0x6a, 0xb3, + 0x94, 0x0b, 0x92, 0x77, 0x83, 0x9a, 0xda, 0x2f, 0x14, 0xd1, 0xaa, 0xd5, 0x90, 0x2d, 0x0f, 0x5a, + 0x92, 0x1b, 0x72, 0x68, 0x9b, 0xc4, 0xa2, 0x55, 0x58, 0xc2, 0x34, 0x19, 0x33, 0x32, 0x51, 0x41, + 0x99, 0xc2, 0x00, 0xa6, 0x49, 0x44, 0x26, 0xd2, 0x73, 0xb4, 0x03, 0x6d, 0x46, 0x1e, 0x16, 0x84, + 0xdb, 0xda, 0xbc, 0xd3, 0xd7, 0x5d, 0xd2, 0xaf, 0x7a, 0xcc, 0xf4, 0x92, 0x2c, 0xd7, 0xc0, 0x74, + 0x68, 0xa4, 0x65, 0x22, 0x2b, 0x1c, 0xfe, 0xe8, 0x00, 0x54, 0x75, 0x3a, 0x85, 0xe1, 0x37, 0x20, + 0xf8, 0x86, 0xd3, 0x7c, 0x8c, 0x63, 0x11, 0x2b, 0xd3, 0x41, 0xe4, 0x4b, 0xc2, 0x20, 0x16, 0x31, + 0xda, 0xac, 0xbc, 0xd2, 0xad, 0xb0, 0xb6, 0xd8, 0xab, 0x6d, 0x3a, 0x9d, 0xa6, 0xcf, 0x38, 0x84, + 0x5e, 0x07, 0x3f, 0xe5, 0x63, 0xc2, 0x18, 0x65, 0xaa, 0x49, 0xfc, 0xa8, 0x9d, 0xf2, 0xa1, 0xbc, + 0x86, 0xbf, 0x39, 0xd0, 0x1e, 0x9d, 0x3a, 0x43, 0x3d, 0xf0, 0xa8, 0x6e, 0xeb, 0x46, 0xad, 0x5c, + 0x23, 0x22, 0xf6, 0x14, 0x3d, 0x32, 0xfc, 0x7a, 0x48, 0xcd, 0xc5, 0x21, 0xb5, 0x5e, 0x42, 0x48, + 0x6e, 0x3d, 0xa4, 0x3f, 0x1d, 0x80, 0xaa, 0xab, 0x4f, 0x11, 0xd5, 0xe7, 0xb0, 0x34, 0x63, 0x24, + 0xa1, 0x39, 0x4e, 0xe7, 0x62, 0xbb, 0xb2, 0xd8, 0xa7, 0xfd, 0x39, 0x74, 0x54, 0x93, 0xfd, 0x2f, + 0xe3, 0xfe, 0xa5, 0x01, 0xe7, 0x4e, 0x8c, 0xe6, 0x2b, 0x0e, 0xfe, 0x06, 0x74, 0x26, 0x29, 0xc9, + 0xb0, 0xd9, 0x1a, 0x4d, 0xb5, 0x2c, 0x6d, 0x8f, 0xec, 0x48, 0x8e, 0x34, 0x19, 0xc1, 0xc4, 0x1e, + 0x39, 0xba, 0x08, 0x1d, 0x95, 0xaf, 0x47, 0x71, 0x56, 0x10, 0xde, 0x6d, 0xad, 0x36, 0xa5, 0x7f, + 0x92, 0xf4, 0x40, 0x51, 0xe6, 0x73, 0xe6, 0xbe, 0x84, 0x9c, 0x79, 0xf5, 0x9c, 0xfd, 0xee, 0x00, + 0x54, 0x7b, 0xe9, 0x15, 0xa7, 0xeb, 0xdf, 0x9d, 0xec, 0x9b, 0x10, 0x94, 0x63, 0x89, 0x96, 0xa1, + 0x19, 0x67, 0x99, 0x8a, 0xc7, 0x8f, 0xe4, 0x51, 0x8e, 0xb2, 0x2a, 0x03, 0xef, 0x36, 0x16, 0x94, + 0xc9, 0xf0, 0xc3, 0x9f, 0x1d, 0x08, 0xca, 0x7d, 0x2c, 0x1b, 0x3c, 0xa1, 0x59, 0x36, 0x9f, 0x1f, + 0x5f, 0x12, 0x54, 0x76, 0xd6, 0xa0, 0x9d, 0x64, 0x71, 0xc1, 0x89, 0xd5, 0xfa, 0x3f, 0xfb, 0x6c, + 0x29, 0x6a, 0x64, 0xb9, 0xe8, 0x33, 0xbb, 0xf6, 0x75, 0xe0, 0x57, 0x17, 0x07, 0x3e, 0x12, 0xac, + 0x48, 0x44, 0xc1, 0x08, 0x56, 0x3e, 0xd8, 0xd7, 0xe0, 0x05, 0x81, 0xff, 0xd5, 0x00, 0x4f, 0xdb, + 0x43, 0x6b, 0xe0, 0x71, 0x92, 0x91, 0x44, 0x28, 0x4f, 0x2b, 0x77, 0x46, 0x8a, 0x28, 0xdf, 0x0b, + 0xcd, 0x46, 0x97, 0xc1, 0x7d, 0x7c, 0x4c, 0x18, 0x31, 0xf5, 0x5c, 0x32, 0xb8, 0xaf, 0x24, 0x4d, + 0x3e, 0x41, 0x8a, 0x89, 0xae, 0x83, 0x4f, 0x19, 0x26, 0x6c, 0x7c, 0x68, 0x1d, 0xb7, 0x8f, 0xed, + 0x9e, 0x24, 0x6f, 0x3d, 0xbd, 0x75, 0x26, 0x6a, 0x53, 0x7d, 0x44, 0x5d, 0xf0, 0xe8, 0x64, 0x62, + 0xdf, 0x65, 0x57, 0x1a, 0xd3, 0x77, 0x74, 0x01, 0xdc, 0x2c, 0x9d, 0xa6, 0xba, 0xa1, 0x25, 0x43, + 0x5f, 0xd1, 0x35, 0xf0, 0xb9, 0x88, 0x99, 0x18, 0xc7, 0xc2, 0xbc, 0xb8, 0x65, 0xfa, 0x0a, 0xc6, + 0x29, 0x93, 0xda, 0x15, 0x60, 0x53, 0xa0, 0xf7, 0xa0, 0x63, 0xb0, 0x13, 0x41, 0x98, 0x79, 0x69, + 0x9f, 0x81, 0x83, 0x86, 0x4b, 0x08, 0xba, 0x02, 0x1e, 0xc9, 0xb1, 0xd4, 0xed, 0x3f, 0x1f, 0xec, + 0x92, 0x1c, 0x6f, 0x0a, 0xd4, 0x07, 0x90, 0xb8, 0x43, 0x32, 0xa1, 0x8c, 0x98, 0xb7, 0xf6, 0x19, + 0x6c, 0x40, 0x72, 0xbc, 0xa5, 0x10, 0x5b, 0x3e, 0x78, 0xba, 0xaa, 0xe1, 0x06, 0x78, 0x3a, 0xb1, + 0x73, 0xcd, 0xe5, 0xfc, 0x43, 0x73, 0x1d, 0x80, 0xab, 0x92, 0x8c, 0x2e, 0x43, 0xab, 0x6c, 0xa9, + 0xe7, 0x09, 0x28, 0x2e, 0x3a, 0x0b, 0x0d, 0x3a, 0x33, 0x4f, 0x64, 0x83, 0xce, 0xd0, 0x5b, 0x00, + 0xd5, 0xfa, 0x30, 0xfb, 0x36, 0x28, 0xb7, 0x47, 0x78, 0x07, 0xda, 0xa6, 0x32, 0xa7, 0xd4, 0xff, + 0x26, 0x04, 0x38, 0x65, 0x24, 0x29, 0x67, 0x3b, 0x88, 0x2a, 0x42, 0xf8, 0x35, 0x78, 0x3a, 0x03, + 0xe8, 0x43, 0xbd, 0x28, 0x78, 0x1e, 0xcf, 0xf8, 0x31, 0xb5, 0xed, 0x85, 0xec, 0x97, 0x0e, 0x4d, + 0x46, 0x86, 0x13, 0x75, 0x70, 0x75, 0x39, 0xb9, 0xed, 0x1a, 0x27, 0xb7, 0x5d, 0xf8, 0x29, 0x74, + 0xe6, 0x84, 0x11, 0x9a, 0x73, 0x3a, 0x30, 0x2e, 0xbe, 0xe8, 0x63, 0x21, 0xbc, 0x04, 0x41, 0x19, + 0x12, 0x3a, 0x0f, 0xae, 0xca, 0xb2, 0x2a, 0x42, 0x10, 0xe9, 0x4b, 0xf8, 0xbd, 0x03, 0x50, 0x7d, + 0x33, 0xa1, 0x1d, 0x08, 0x18, 0xe1, 0x33, 0x9a, 0xcb, 0xa1, 0xd5, 0xd5, 0xea, 0x2d, 0x9e, 0x46, + 0x2d, 0x18, 0x19, 0x81, 0xa8, 0x12, 0x45, 0xef, 0x42, 0x60, 0xb3, 0x61, 0x87, 0xff, 0x9c, 0x9d, + 0x36, 0x9b, 0x8b, 0x0a, 0x51, 0x9b, 0xdf, 0x66, 0x7d, 0x7e, 0x7f, 0x70, 0xc0, 0x2f, 0x33, 0xf0, + 0x11, 0xb4, 0x30, 0x4d, 0xac, 0x67, 0xe1, 0x62, 0xcf, 0xca, 0xaf, 0x31, 0x85, 0x47, 0xd7, 0xa0, + 0x9d, 0x1c, 0xc7, 0xf9, 0x11, 0x39, 0xb9, 0xdf, 0x06, 0x34, 0xd9, 0x56, 0x8c, 0xc8, 0x02, 0xd0, + 0xc7, 0x32, 0x05, 0x31, 0x1e, 0xcb, 0x5f, 0x00, 0x33, 0xd7, 0x2b, 0xd6, 0x90, 0xfd, 0x3f, 0xe8, + 0xdf, 0xb3, 0xff, 0x07, 0x91, 0x2f, 0xc1, 0xf2, 0x1a, 0xfe, 0xe1, 0x40, 0x50, 0xea, 0x43, 0x57, + 0xa1, 0xf5, 0x6d, 0x9a, 0x63, 0x55, 0xac, 0xb3, 0x1b, 0xaf, 0x9d, 0xb4, 0xd7, 0xbf, 0x9d, 0xe6, + 0x38, 0x52, 0x10, 0xf4, 0x01, 0x34, 0x31, 0x4d, 0xcc, 0xb2, 0x39, 0x4d, 0x50, 0x12, 0x2e, 0x2b, + 0x4f, 0x33, 0x3c, 0x4e, 0x73, 0x4c, 0x9e, 0x28, 0x3f, 0xdd, 0xc8, 0xa7, 0x19, 0xde, 0x95, 0x77, + 0xc9, 0xcc, 0xc9, 0x63, 0xc3, 0x6c, 0x69, 0x66, 0x4e, 0x1e, 0x2b, 0x66, 0xb8, 0x05, 0x2d, 0x69, + 0x1d, 0x9d, 0x87, 0xe5, 0xdb, 0xbb, 0x77, 0x07, 0xe3, 0xfb, 0x77, 0x47, 0xfb, 0xc3, 0xed, 0xdd, + 0x9d, 0xdd, 0xe1, 0x60, 0xf9, 0x0c, 0x0a, 0xc0, 0xdd, 0x1c, 0x0c, 0x86, 0x83, 0x65, 0x07, 0x75, + 0xa0, 0x1d, 0x0d, 0xef, 0xec, 0x3d, 0x18, 0x0e, 0x96, 0x1b, 0x68, 0x09, 0xfc, 0x3b, 0x7b, 0x03, + 0x8d, 0x6a, 0x6e, 0x3d, 0x81, 0x2b, 0x09, 0x9d, 0x5a, 0x5f, 0x93, 0x8c, 0x16, 0x78, 0xce, 0xe3, + 0x84, 0xe6, 0x13, 0xca, 0xa6, 0x71, 0x9e, 0x90, 0x9f, 0x1a, 0xe1, 0x4d, 0x0d, 0xda, 0x56, 0xa0, + 0x9d, 0x12, 0x74, 0x4f, 0x65, 0x64, 0x5f, 0xa6, 0xf4, 0xd7, 0x46, 0x4f, 0x83, 0x0e, 0x14, 0xe8, + 0xa0, 0x04, 0x1d, 0x28, 0xd0, 0xc1, 0x76, 0xa5, 0xef, 0xd0, 0x53, 0x45, 0x78, 0xff, 0xef, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xc2, 0x7a, 0x63, 0xd5, 0x67, 0x0e, 0x00, 0x00, +} diff --git a/vendor/cloud.google.com/go/firestore/integration_test.go b/vendor/cloud.google.com/go/firestore/integration_test.go new file mode 100644 index 00000000..bf9c9ffa --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/integration_test.go @@ -0,0 +1,1339 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "errors" + "flag" + "fmt" + "log" + "math" + "os" + "path/filepath" + "runtime" + "sort" + "testing" + "time" + + "cloud.google.com/go/internal/pretty" + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/internal/uid" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "google.golang.org/api/option" + "google.golang.org/genproto/googleapis/type/latlng" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +func TestMain(m *testing.M) { + initIntegrationTest() + status := m.Run() + cleanupIntegrationTest() + os.Exit(status) +} + +const ( + envProjID = "GCLOUD_TESTS_GOLANG_FIRESTORE_PROJECT_ID" + envPrivateKey = "GCLOUD_TESTS_GOLANG_FIRESTORE_KEY" +) + +var ( + iClient *Client + iColl *CollectionRef + collectionIDs = uid.NewSpace("go-integration-test", nil) +) + +func initIntegrationTest() { + flag.Parse() // needed for testing.Short() + if testing.Short() { + return + } + ctx := context.Background() + testProjectID := os.Getenv(envProjID) + if testProjectID == "" { + log.Println("Integration tests skipped. See CONTRIBUTING.md for details") + return + } + ts := testutil.TokenSourceEnv(ctx, envPrivateKey, + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/datastore") + if ts == nil { + log.Fatal("The project key must be set. See CONTRIBUTING.md for details") + } + ti := &testInterceptor{dbPath: "projects/" + testProjectID + "/databases/(default)"} + c, err := NewClient(ctx, testProjectID, + option.WithTokenSource(ts), + option.WithGRPCDialOption(grpc.WithUnaryInterceptor(ti.interceptUnary)), + option.WithGRPCDialOption(grpc.WithStreamInterceptor(ti.interceptStream)), + ) + if err != nil { + log.Fatalf("NewClient: %v", err) + } + iClient = c + iColl = c.Collection(collectionIDs.New()) + refDoc := iColl.NewDoc() + integrationTestMap["ref"] = refDoc + wantIntegrationTestMap["ref"] = refDoc + integrationTestStruct.Ref = refDoc +} + +type testInterceptor struct { + dbPath string +} + +func (ti *testInterceptor) interceptUnary(ctx context.Context, method string, req, res interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + ti.checkMetadata(ctx, method) + return invoker(ctx, method, req, res, cc, opts...) +} + +func (ti *testInterceptor) interceptStream(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { + ti.checkMetadata(ctx, method) + return streamer(ctx, desc, cc, method, opts...) +} + +func (ti *testInterceptor) checkMetadata(ctx context.Context, method string) { + md, ok := metadata.FromOutgoingContext(ctx) + if !ok { + log.Fatalf("method %s: bad metadata", method) + } + for _, h := range []string{"google-cloud-resource-prefix", "x-goog-api-client"} { + v, ok := md[h] + if !ok { + log.Fatalf("method %s, header %s missing", method, h) + } + if len(v) != 1 { + log.Fatalf("method %s, header %s: bad value %v", method, h, v) + } + } + v := md["google-cloud-resource-prefix"][0] + if v != ti.dbPath { + log.Fatalf("method %s: bad resource prefix header: %q", method, v) + } +} + +func cleanupIntegrationTest() { + if iClient == nil { + return + } + // TODO(jba): delete everything in integrationColl. + iClient.Close() +} + +// integrationClient should be called by integration tests to get a valid client. It will never +// return nil. If integrationClient returns, an integration test can proceed without +// further checks. +func integrationClient(t *testing.T) *Client { + if testing.Short() { + t.Skip("Integration tests skipped in short mode") + } + if iClient == nil { + t.SkipNow() // log message printed in initIntegrationTest + } + return iClient +} + +func integrationColl(t *testing.T) *CollectionRef { + _ = integrationClient(t) + return iColl +} + +type integrationTestStructType struct { + Int int + Str string + Bool bool + Float float32 + Null interface{} + Bytes []byte + Time time.Time + Geo, NilGeo *latlng.LatLng + Ref *DocumentRef +} + +var ( + integrationTime = time.Date(2017, 3, 20, 1, 2, 3, 456789, time.UTC) + // Firestore times are accurate only to microseconds. + wantIntegrationTime = time.Date(2017, 3, 20, 1, 2, 3, 456000, time.UTC) + + integrationGeo = &latlng.LatLng{Latitude: 30, Longitude: 70} + + // Use this when writing a doc. + integrationTestMap = map[string]interface{}{ + "int": 1, + "str": "two", + "bool": true, + "float": 3.14, + "null": nil, + "bytes": []byte("bytes"), + "*": map[string]interface{}{"`": 4}, + "time": integrationTime, + "geo": integrationGeo, + "ref": nil, // populated by initIntegrationTest + } + + // The returned data is slightly different. + wantIntegrationTestMap = map[string]interface{}{ + "int": int64(1), + "str": "two", + "bool": true, + "float": 3.14, + "null": nil, + "bytes": []byte("bytes"), + "*": map[string]interface{}{"`": int64(4)}, + "time": wantIntegrationTime, + "geo": integrationGeo, + "ref": nil, // populated by initIntegrationTest + } + + integrationTestStruct = integrationTestStructType{ + Int: 1, + Str: "two", + Bool: true, + Float: 3.14, + Null: nil, + Bytes: []byte("bytes"), + Time: integrationTime, + Geo: integrationGeo, + NilGeo: nil, + Ref: nil, // populated by initIntegrationTest + } +) + +func TestIntegration_Create(t *testing.T) { + ctx := context.Background() + doc := integrationColl(t).NewDoc() + start := time.Now() + h := testHelper{t} + wr := h.mustCreate(doc, integrationTestMap) + end := time.Now() + checkTimeBetween(t, wr.UpdateTime, start, end) + _, err := doc.Create(ctx, integrationTestMap) + codeEq(t, "Create on a present doc", codes.AlreadyExists, err) + // OK to create an empty document. + _, err = integrationColl(t).NewDoc().Create(ctx, map[string]interface{}{}) + codeEq(t, "Create empty doc", codes.OK, err) +} + +func TestIntegration_Get(t *testing.T) { + ctx := context.Background() + doc := integrationColl(t).NewDoc() + h := testHelper{t} + h.mustCreate(doc, integrationTestMap) + ds := h.mustGet(doc) + if ds.CreateTime != ds.UpdateTime { + t.Errorf("create time %s != update time %s", ds.CreateTime, ds.UpdateTime) + } + got := ds.Data() + if want := wantIntegrationTestMap; !testEqual(got, want) { + t.Errorf("got\n%v\nwant\n%v", pretty.Value(got), pretty.Value(want)) + } + + doc = integrationColl(t).NewDoc() + empty := map[string]interface{}{} + h.mustCreate(doc, empty) + ds = h.mustGet(doc) + if ds.CreateTime != ds.UpdateTime { + t.Errorf("create time %s != update time %s", ds.CreateTime, ds.UpdateTime) + } + if got, want := ds.Data(), empty; !testEqual(got, want) { + t.Errorf("got\n%v\nwant\n%v", pretty.Value(got), pretty.Value(want)) + } + + ds, err := integrationColl(t).NewDoc().Get(ctx) + codeEq(t, "Get on a missing doc", codes.NotFound, err) + if ds == nil || ds.Exists() { + t.Fatal("got nil or existing doc snapshot, want !ds.Exists") + } + if ds.ReadTime.IsZero() { + t.Error("got zero read time") + } +} + +func TestIntegration_GetAll(t *testing.T) { + type getAll struct{ N int } + + h := testHelper{t} + coll := integrationColl(t) + ctx := context.Background() + var docRefs []*DocumentRef + for i := 0; i < 5; i++ { + doc := coll.NewDoc() + docRefs = append(docRefs, doc) + if i != 3 { + h.mustCreate(doc, getAll{N: i}) + } + } + docSnapshots, err := iClient.GetAll(ctx, docRefs) + if err != nil { + t.Fatal(err) + } + if got, want := len(docSnapshots), len(docRefs); got != want { + t.Fatalf("got %d snapshots, want %d", got, want) + } + for i, ds := range docSnapshots { + if i == 3 { + if ds == nil || ds.Exists() { + t.Fatal("got nil or existing doc snapshot, want !ds.Exists") + } + err := ds.DataTo(nil) + codeEq(t, "DataTo on a missing doc", codes.NotFound, err) + } else { + var got getAll + if err := ds.DataTo(&got); err != nil { + t.Fatal(err) + } + want := getAll{N: i} + if got != want { + t.Errorf("%d: got %+v, want %+v", i, got, want) + } + } + if ds.ReadTime.IsZero() { + t.Errorf("%d: got zero read time", i) + } + } +} + +func TestIntegration_Add(t *testing.T) { + start := time.Now() + _, wr, err := integrationColl(t).Add(context.Background(), integrationTestMap) + if err != nil { + t.Fatal(err) + } + end := time.Now() + checkTimeBetween(t, wr.UpdateTime, start, end) +} + +func TestIntegration_Set(t *testing.T) { + coll := integrationColl(t) + h := testHelper{t} + ctx := context.Background() + + // Set Should be able to create a new doc. + doc := coll.NewDoc() + wr1 := h.mustSet(doc, integrationTestMap) + // Calling Set on the doc completely replaces the contents. + // The update time should increase. + newData := map[string]interface{}{ + "str": "change", + "x": "1", + } + wr2 := h.mustSet(doc, newData) + if !wr1.UpdateTime.Before(wr2.UpdateTime) { + t.Errorf("update time did not increase: old=%s, new=%s", wr1.UpdateTime, wr2.UpdateTime) + } + ds := h.mustGet(doc) + if got := ds.Data(); !testEqual(got, newData) { + t.Errorf("got %v, want %v", got, newData) + } + + newData = map[string]interface{}{ + "str": "1", + "x": "2", + "y": "3", + } + // SetOptions: + // Only fields mentioned in the Merge option will be changed. + // In this case, "str" will not be changed to "1". + wr3, err := doc.Set(ctx, newData, Merge([]string{"x"}, []string{"y"})) + if err != nil { + t.Fatal(err) + } + ds = h.mustGet(doc) + want := map[string]interface{}{ + "str": "change", + "x": "2", + "y": "3", + } + if got := ds.Data(); !testEqual(got, want) { + t.Errorf("got %v, want %v", got, want) + } + if !wr2.UpdateTime.Before(wr3.UpdateTime) { + t.Errorf("update time did not increase: old=%s, new=%s", wr2.UpdateTime, wr3.UpdateTime) + } + + // Another way to change only x and y is to pass a map with only + // those keys, and use MergeAll. + wr4, err := doc.Set(ctx, map[string]interface{}{"x": "4", "y": "5"}, MergeAll) + if err != nil { + t.Fatal(err) + } + ds = h.mustGet(doc) + want = map[string]interface{}{ + "str": "change", + "x": "4", + "y": "5", + } + if got := ds.Data(); !testEqual(got, want) { + t.Errorf("got %v, want %v", got, want) + } + if !wr3.UpdateTime.Before(wr4.UpdateTime) { + t.Errorf("update time did not increase: old=%s, new=%s", wr3.UpdateTime, wr4.UpdateTime) + } + + // use firestore.Delete to delete a field. + // TODO(deklerk) We should be able to use mustSet, but then we get a test error. We should investigate this. + _, err = doc.Set(ctx, map[string]interface{}{"str": Delete}, MergeAll) + if err != nil { + t.Fatal(err) + } + ds = h.mustGet(doc) + want = map[string]interface{}{ + "x": "4", + "y": "5", + } + if got := ds.Data(); !testEqual(got, want) { + t.Errorf("got %v, want %v", got, want) + } + + // Writing an empty doc with MergeAll should create the doc. + doc2 := coll.NewDoc() + want = map[string]interface{}{} + h.mustSet(doc2, want, MergeAll) + ds = h.mustGet(doc2) + if got := ds.Data(); !testEqual(got, want) { + t.Errorf("got %v, want %v", got, want) + } +} + +func TestIntegration_Delete(t *testing.T) { + ctx := context.Background() + doc := integrationColl(t).NewDoc() + h := testHelper{t} + h.mustCreate(doc, integrationTestMap) + h.mustDelete(doc) + // Confirm that doc doesn't exist. + if _, err := doc.Get(ctx); grpc.Code(err) != codes.NotFound { + t.Fatalf("got error <%v>, want NotFound", err) + } + + er := func(_ *WriteResult, err error) error { return err } + + codeEq(t, "Delete on a missing doc", codes.OK, + er(doc.Delete(ctx))) + // TODO(jba): confirm that the server should return InvalidArgument instead of + // FailedPrecondition. + wr := h.mustCreate(doc, integrationTestMap) + codeEq(t, "Delete with wrong LastUpdateTime", codes.FailedPrecondition, + er(doc.Delete(ctx, LastUpdateTime(wr.UpdateTime.Add(-time.Millisecond))))) + codeEq(t, "Delete with right LastUpdateTime", codes.OK, + er(doc.Delete(ctx, LastUpdateTime(wr.UpdateTime)))) +} + +func TestIntegration_Update(t *testing.T) { + ctx := context.Background() + doc := integrationColl(t).NewDoc() + h := testHelper{t} + + h.mustCreate(doc, integrationTestMap) + fpus := []Update{ + {Path: "bool", Value: false}, + {Path: "time", Value: 17}, + {FieldPath: []string{"*", "`"}, Value: 18}, + {Path: "null", Value: Delete}, + {Path: "noSuchField", Value: Delete}, // deleting a non-existent field is a no-op + } + wr := h.mustUpdate(doc, fpus) + ds := h.mustGet(doc) + got := ds.Data() + want := copyMap(wantIntegrationTestMap) + want["bool"] = false + want["time"] = int64(17) + want["*"] = map[string]interface{}{"`": int64(18)} + delete(want, "null") + if !testEqual(got, want) { + t.Errorf("got\n%#v\nwant\n%#v", got, want) + } + + er := func(_ *WriteResult, err error) error { return err } + + codeEq(t, "Update on missing doc", codes.NotFound, + er(integrationColl(t).NewDoc().Update(ctx, fpus))) + codeEq(t, "Update with wrong LastUpdateTime", codes.FailedPrecondition, + er(doc.Update(ctx, fpus, LastUpdateTime(wr.UpdateTime.Add(-time.Millisecond))))) + codeEq(t, "Update with right LastUpdateTime", codes.OK, + er(doc.Update(ctx, fpus, LastUpdateTime(wr.UpdateTime)))) +} + +func TestIntegration_Collections(t *testing.T) { + ctx := context.Background() + c := integrationClient(t) + h := testHelper{t} + got, err := c.Collections(ctx).GetAll() + if err != nil { + t.Fatal(err) + } + // There should be at least one collection. + if len(got) == 0 { + t.Error("got 0 top-level collections, want at least one") + } + + doc := integrationColl(t).NewDoc() + got, err = doc.Collections(ctx).GetAll() + if err != nil { + t.Fatal(err) + } + if len(got) != 0 { + t.Errorf("got %d collections, want 0", len(got)) + } + var want []*CollectionRef + for i := 0; i < 3; i++ { + id := collectionIDs.New() + cr := doc.Collection(id) + want = append(want, cr) + h.mustCreate(cr.NewDoc(), integrationTestMap) + } + got, err = doc.Collections(ctx).GetAll() + if err != nil { + t.Fatal(err) + } + if !testEqual(got, want) { + t.Errorf("got\n%#v\nwant\n%#v", got, want) + } +} + +func TestIntegration_ServerTimestamp(t *testing.T) { + type S struct { + A int + B time.Time + C time.Time `firestore:"C.C,serverTimestamp"` + D map[string]interface{} + E time.Time `firestore:",omitempty,serverTimestamp"` + } + data := S{ + A: 1, + B: aTime, + // C is unset, so will get the server timestamp. + D: map[string]interface{}{"x": ServerTimestamp}, + // E is unset, so will get the server timestamp. + } + h := testHelper{t} + doc := integrationColl(t).NewDoc() + // Bound times of the RPC, with some slack for clock skew. + start := time.Now() + h.mustCreate(doc, data) + end := time.Now() + ds := h.mustGet(doc) + var got S + if err := ds.DataTo(&got); err != nil { + t.Fatal(err) + } + if !testEqual(got.B, aTime) { + t.Errorf("B: got %s, want %s", got.B, aTime) + } + checkTimeBetween(t, got.C, start, end) + if g, w := got.D["x"], got.C; !testEqual(g, w) { + t.Errorf(`D["x"] = %s, want equal to C (%s)`, g, w) + } + if g, w := got.E, got.C; !testEqual(g, w) { + t.Errorf(`E = %s, want equal to C (%s)`, g, w) + } +} + +func TestIntegration_MergeServerTimestamp(t *testing.T) { + doc := integrationColl(t).NewDoc() + h := testHelper{t} + + // Create a doc with an ordinary field "a" and a ServerTimestamp field "b". + h.mustSet(doc, map[string]interface{}{"a": 1, "b": ServerTimestamp}) + docSnap := h.mustGet(doc) + data1 := docSnap.Data() + // Merge with a document with a different value of "a". However, + // specify only "b" in the list of merge fields. + h.mustSet(doc, map[string]interface{}{"a": 2, "b": ServerTimestamp}, Merge([]string{"b"})) + // The result should leave "a" unchanged, while "b" is updated. + docSnap = h.mustGet(doc) + data2 := docSnap.Data() + if got, want := data2["a"], data1["a"]; got != want { + t.Errorf("got %v, want %v", got, want) + } + t1 := data1["b"].(time.Time) + t2 := data2["b"].(time.Time) + if !t1.Before(t2) { + t.Errorf("got t1=%s, t2=%s; want t1 before t2", t1, t2) + } +} + +func TestIntegration_MergeNestedServerTimestamp(t *testing.T) { + doc := integrationColl(t).NewDoc() + h := testHelper{t} + + // Create a doc with an ordinary field "a" a ServerTimestamp field "b", + // and a second ServerTimestamp field "c.d". + h.mustSet(doc, map[string]interface{}{ + "a": 1, + "b": ServerTimestamp, + "c": map[string]interface{}{"d": ServerTimestamp}, + }) + data1 := h.mustGet(doc).Data() + // Merge with a document with a different value of "a". However, + // specify only "c.d" in the list of merge fields. + h.mustSet(doc, map[string]interface{}{ + "a": 2, + "b": ServerTimestamp, + "c": map[string]interface{}{"d": ServerTimestamp}, + }, Merge([]string{"c", "d"})) + // The result should leave "a" and "b" unchanged, while "c.d" is updated. + data2 := h.mustGet(doc).Data() + if got, want := data2["a"], data1["a"]; got != want { + t.Errorf("a: got %v, want %v", got, want) + } + want := data1["b"].(time.Time) + got := data2["b"].(time.Time) + if !got.Equal(want) { + t.Errorf("b: got %s, want %s", got, want) + } + t1 := data1["c"].(map[string]interface{})["d"].(time.Time) + t2 := data2["c"].(map[string]interface{})["d"].(time.Time) + if !t1.Before(t2) { + t.Errorf("got t1=%s, t2=%s; want t1 before t2", t1, t2) + } +} + +func TestIntegration_WriteBatch(t *testing.T) { + ctx := context.Background() + b := integrationClient(t).Batch() + h := testHelper{t} + doc1 := iColl.NewDoc() + doc2 := iColl.NewDoc() + b.Create(doc1, integrationTestMap) + b.Set(doc2, integrationTestMap) + b.Update(doc1, []Update{{Path: "bool", Value: false}}) + b.Update(doc1, []Update{{Path: "str", Value: Delete}}) + + wrs, err := b.Commit(ctx) + if err != nil { + t.Fatal(err) + } + if got, want := len(wrs), 4; got != want { + t.Fatalf("got %d WriteResults, want %d", got, want) + } + got1 := h.mustGet(doc1).Data() + want := copyMap(wantIntegrationTestMap) + want["bool"] = false + delete(want, "str") + if !testEqual(got1, want) { + t.Errorf("got\n%#v\nwant\n%#v", got1, want) + } + got2 := h.mustGet(doc2).Data() + if !testEqual(got2, wantIntegrationTestMap) { + t.Errorf("got\n%#v\nwant\n%#v", got2, wantIntegrationTestMap) + } + // TODO(jba): test two updates to the same document when it is supported. + // TODO(jba): test verify when it is supported. +} + +func TestIntegration_Query(t *testing.T) { + ctx := context.Background() + coll := integrationColl(t) + h := testHelper{t} + var wants []map[string]interface{} + for i := 0; i < 3; i++ { + doc := coll.NewDoc() + // To support running this test in parallel with the others, use a field name + // that we don't use anywhere else. + h.mustCreate(doc, map[string]interface{}{"q": i, "x": 1}) + wants = append(wants, map[string]interface{}{"q": int64(i)}) + } + q := coll.Select("q").OrderBy("q", Asc) + for i, test := range []struct { + q Query + want []map[string]interface{} + }{ + {q, wants}, + {q.Where("q", ">", 1), wants[2:]}, + {q.WherePath([]string{"q"}, ">", 1), wants[2:]}, + {q.Offset(1).Limit(1), wants[1:2]}, + {q.StartAt(1), wants[1:]}, + {q.StartAfter(1), wants[2:]}, + {q.EndAt(1), wants[:2]}, + {q.EndBefore(1), wants[:1]}, + } { + gotDocs, err := test.q.Documents(ctx).GetAll() + if err != nil { + t.Errorf("#%d: %+v: %v", i, test.q, err) + continue + } + if len(gotDocs) != len(test.want) { + t.Errorf("#%d: %+v: got %d docs, want %d", i, test.q, len(gotDocs), len(test.want)) + continue + } + for j, g := range gotDocs { + if got, want := g.Data(), test.want[j]; !testEqual(got, want) { + t.Errorf("#%d: %+v, #%d: got\n%+v\nwant\n%+v", i, test.q, j, got, want) + } + } + } + _, err := coll.Select("q").Where("x", "==", 1).OrderBy("q", Asc).Documents(ctx).GetAll() + codeEq(t, "Where and OrderBy on different fields without an index", codes.FailedPrecondition, err) + + // Using the collection itself as the query should return the full documents. + allDocs, err := coll.Documents(ctx).GetAll() + if err != nil { + t.Fatal(err) + } + seen := map[int64]bool{} // "q" values we see + for _, d := range allDocs { + data := d.Data() + q, ok := data["q"] + if !ok { + // A document from another test. + continue + } + if seen[q.(int64)] { + t.Errorf("%v: duplicate doc", data) + } + seen[q.(int64)] = true + if data["x"] != int64(1) { + t.Errorf("%v: wrong or missing 'x'", data) + } + if len(data) != 2 { + t.Errorf("%v: want two keys", data) + } + } + if got, want := len(seen), len(wants); got != want { + t.Errorf("got %d docs with 'q', want %d", len(seen), len(wants)) + } +} + +// Test unary filters. +func TestIntegration_QueryUnary(t *testing.T) { + ctx := context.Background() + coll := integrationColl(t) + h := testHelper{t} + h.mustCreate(coll.NewDoc(), map[string]interface{}{"x": 2, "q": "a"}) + h.mustCreate(coll.NewDoc(), map[string]interface{}{"x": 2, "q": nil}) + h.mustCreate(coll.NewDoc(), map[string]interface{}{"x": 2, "q": math.NaN()}) + wantNull := map[string]interface{}{"q": nil} + wantNaN := map[string]interface{}{"q": math.NaN()} + + base := coll.Select("q").Where("x", "==", 2) + for _, test := range []struct { + q Query + want map[string]interface{} + }{ + {base.Where("q", "==", nil), wantNull}, + {base.Where("q", "==", math.NaN()), wantNaN}, + } { + got, err := test.q.Documents(ctx).GetAll() + if err != nil { + t.Fatal(err) + } + if len(got) != 1 { + t.Errorf("got %d responses, want 1", len(got)) + continue + } + if g, w := got[0].Data(), test.want; !testEqual(g, w) { + t.Errorf("%v: got %v, want %v", test.q, g, w) + } + } +} + +// Test the special DocumentID field in queries. +func TestIntegration_QueryName(t *testing.T) { + ctx := context.Background() + h := testHelper{t} + + checkIDs := func(q Query, wantIDs []string) { + gots, err := q.Documents(ctx).GetAll() + if err != nil { + t.Fatal(err) + } + if len(gots) != len(wantIDs) { + t.Fatalf("got %d, want %d", len(gots), len(wantIDs)) + } + for i, g := range gots { + if got, want := g.Ref.ID, wantIDs[i]; got != want { + t.Errorf("#%d: got %s, want %s", i, got, want) + } + } + } + + coll := integrationColl(t) + var wantIDs []string + for i := 0; i < 3; i++ { + doc := coll.NewDoc() + h.mustCreate(doc, map[string]interface{}{"nm": 1}) + wantIDs = append(wantIDs, doc.ID) + } + sort.Strings(wantIDs) + q := coll.Where("nm", "==", 1).OrderBy(DocumentID, Asc) + checkIDs(q, wantIDs) + + // Empty Select. + q = coll.Select().Where("nm", "==", 1).OrderBy(DocumentID, Asc) + checkIDs(q, wantIDs) + + // Test cursors with __name__. + checkIDs(q.StartAt(wantIDs[1]), wantIDs[1:]) + checkIDs(q.EndAt(wantIDs[1]), wantIDs[:2]) +} + +func TestIntegration_QueryNested(t *testing.T) { + ctx := context.Background() + h := testHelper{t} + coll1 := integrationColl(t) + doc1 := coll1.NewDoc() + coll2 := doc1.Collection(collectionIDs.New()) + doc2 := coll2.NewDoc() + wantData := map[string]interface{}{"x": int64(1)} + h.mustCreate(doc2, wantData) + q := coll2.Select("x") + got, err := q.Documents(ctx).GetAll() + if err != nil { + t.Fatal(err) + } + if len(got) != 1 { + t.Fatalf("got %d docs, want 1", len(got)) + } + if gotData := got[0].Data(); !testEqual(gotData, wantData) { + t.Errorf("got\n%+v\nwant\n%+v", gotData, wantData) + } +} + +func TestIntegration_RunTransaction(t *testing.T) { + ctx := context.Background() + h := testHelper{t} + + type Player struct { + Name string + Score int + Star bool `firestore:"*"` + } + + pat := Player{Name: "Pat", Score: 3, Star: false} + client := integrationClient(t) + patDoc := iColl.Doc("pat") + var anError error + incPat := func(_ context.Context, tx *Transaction) error { + doc, err := tx.Get(patDoc) + if err != nil { + return err + } + score, err := doc.DataAt("Score") + if err != nil { + return err + } + // Since the Star field is called "*", we must use DataAtPath to get it. + star, err := doc.DataAtPath([]string{"*"}) + if err != nil { + return err + } + err = tx.Update(patDoc, []Update{{Path: "Score", Value: int(score.(int64) + 7)}}) + if err != nil { + return err + } + // Since the Star field is called "*", we must use Update to change it. + err = tx.Update(patDoc, + []Update{{FieldPath: []string{"*"}, Value: !star.(bool)}}) + if err != nil { + return err + } + return anError + } + + h.mustCreate(patDoc, pat) + err := client.RunTransaction(ctx, incPat) + if err != nil { + t.Fatal(err) + } + ds := h.mustGet(patDoc) + var got Player + if err := ds.DataTo(&got); err != nil { + t.Fatal(err) + } + want := Player{Name: "Pat", Score: 10, Star: true} + if got != want { + t.Errorf("got %+v, want %+v", got, want) + } + + // Function returns error, so transaction is rolled back and no writes happen. + anError = errors.New("bad") + err = client.RunTransaction(ctx, incPat) + if err != anError { + t.Fatalf("got %v, want %v", err, anError) + } + if err := ds.DataTo(&got); err != nil { + t.Fatal(err) + } + // want is same as before. + if got != want { + t.Errorf("got %+v, want %+v", got, want) + } +} + +func TestIntegration_TransactionGetAll(t *testing.T) { + ctx := context.Background() + h := testHelper{t} + type Player struct { + Name string + Score int + } + lee := Player{Name: "Lee", Score: 3} + sam := Player{Name: "Sam", Score: 1} + client := integrationClient(t) + leeDoc := iColl.Doc("lee") + samDoc := iColl.Doc("sam") + h.mustCreate(leeDoc, lee) + h.mustCreate(samDoc, sam) + + err := client.RunTransaction(ctx, func(_ context.Context, tx *Transaction) error { + docs, err := tx.GetAll([]*DocumentRef{samDoc, leeDoc}) + if err != nil { + return err + } + for i, want := range []Player{sam, lee} { + var got Player + if err := docs[i].DataTo(&got); err != nil { + return err + } + if !testutil.Equal(got, want) { + return fmt.Errorf("got %+v, want %+v", got, want) + } + } + return nil + }) + if err != nil { + t.Fatal(err) + } +} + +func TestIntegration_WatchDocument(t *testing.T) { + coll := integrationColl(t) + ctx := context.Background() + h := testHelper{t} + doc := coll.NewDoc() + it := doc.Snapshots(ctx) + defer it.Stop() + + next := func() *DocumentSnapshot { + snap, err := it.Next() + if err != nil { + t.Fatal(err) + } + return snap + } + + snap := next() + if snap.Exists() { + t.Fatal("snapshot exists; it should not") + } + want := map[string]interface{}{"a": int64(1), "b": "two"} + h.mustCreate(doc, want) + snap = next() + if got := snap.Data(); !testutil.Equal(got, want) { + t.Fatalf("got %v, want %v", got, want) + } + + h.mustUpdate(doc, []Update{{Path: "a", Value: int64(2)}}) + want["a"] = int64(2) + snap = next() + if got := snap.Data(); !testutil.Equal(got, want) { + t.Fatalf("got %v, want %v", got, want) + } + + h.mustDelete(doc) + snap = next() + if snap.Exists() { + t.Fatal("snapshot exists; it should not") + } + + h.mustCreate(doc, want) + snap = next() + if got := snap.Data(); !testutil.Equal(got, want) { + t.Fatalf("got %v, want %v", got, want) + } +} + +func TestIntegration_ArrayUnion_Create(t *testing.T) { + path := "somepath" + data := map[string]interface{}{ + path: ArrayUnion("a", "b"), + } + + doc := integrationColl(t).NewDoc() + h := testHelper{t} + h.mustCreate(doc, data) + ds := h.mustGet(doc) + var gotMap map[string][]string + if err := ds.DataTo(&gotMap); err != nil { + t.Fatal(err) + } + if _, ok := gotMap[path]; !ok { + t.Fatalf("expected a %v key in data, got %v", path, gotMap) + } + + want := []string{"a", "b"} + for i, v := range gotMap[path] { + if v != want[i] { + t.Fatalf("got\n%#v\nwant\n%#v", gotMap[path], want) + } + } +} + +func TestIntegration_ArrayUnion_Update(t *testing.T) { + doc := integrationColl(t).NewDoc() + h := testHelper{t} + path := "somepath" + + h.mustCreate(doc, map[string]interface{}{ + path: []string{"a", "b"}, + }) + fpus := []Update{ + { + Path: path, + Value: ArrayUnion("this should be added"), + }, + } + h.mustUpdate(doc, fpus) + ds := h.mustGet(doc) + var gotMap map[string][]string + err := ds.DataTo(&gotMap) + if err != nil { + t.Fatal(err) + } + if _, ok := gotMap[path]; !ok { + t.Fatalf("expected a %v key in data, got %v", path, gotMap) + } + + want := []string{"a", "b", "this should be added"} + for i, v := range gotMap[path] { + if v != want[i] { + t.Fatalf("got\n%#v\nwant\n%#v", gotMap[path], want) + } + } +} + +func TestIntegration_ArrayUnion_Set(t *testing.T) { + coll := integrationColl(t) + h := testHelper{t} + path := "somepath" + + doc := coll.NewDoc() + newData := map[string]interface{}{ + path: ArrayUnion("a", "b"), + } + h.mustSet(doc, newData) + ds := h.mustGet(doc) + var gotMap map[string][]string + if err := ds.DataTo(&gotMap); err != nil { + t.Fatal(err) + } + if _, ok := gotMap[path]; !ok { + t.Fatalf("expected a %v key in data, got %v", path, gotMap) + } + + want := []string{"a", "b"} + for i, v := range gotMap[path] { + if v != want[i] { + t.Fatalf("got\n%#v\nwant\n%#v", gotMap[path], want) + } + } +} + +func TestIntegration_ArrayRemove_Create(t *testing.T) { + doc := integrationColl(t).NewDoc() + h := testHelper{t} + path := "somepath" + + h.mustCreate(doc, map[string]interface{}{ + path: ArrayRemove("a", "b"), + }) + + ds := h.mustGet(doc) + var gotMap map[string][]string + err := ds.DataTo(&gotMap) + if err != nil { + t.Fatal(err) + } + if _, ok := gotMap[path]; !ok { + t.Fatalf("expected a %v key in data, got %v", path, gotMap) + } + + // A create with arrayRemove results in an empty array. + want := []string(nil) + if !testEqual(gotMap[path], want) { + t.Fatalf("got\n%#v\nwant\n%#v", gotMap[path], want) + } +} + +func TestIntegration_ArrayRemove_Update(t *testing.T) { + doc := integrationColl(t).NewDoc() + h := testHelper{t} + path := "somepath" + + h.mustCreate(doc, map[string]interface{}{ + path: []string{"a", "this should be removed", "c"}, + }) + fpus := []Update{ + { + Path: path, + Value: ArrayRemove("this should be removed"), + }, + } + h.mustUpdate(doc, fpus) + ds := h.mustGet(doc) + var gotMap map[string][]string + err := ds.DataTo(&gotMap) + if err != nil { + t.Fatal(err) + } + if _, ok := gotMap[path]; !ok { + t.Fatalf("expected a %v key in data, got %v", path, gotMap) + } + + want := []string{"a", "c"} + for i, v := range gotMap[path] { + if v != want[i] { + t.Fatalf("got\n%#v\nwant\n%#v", gotMap[path], want) + } + } +} + +func TestIntegration_ArrayRemove_Set(t *testing.T) { + coll := integrationColl(t) + h := testHelper{t} + path := "somepath" + + doc := coll.NewDoc() + newData := map[string]interface{}{ + path: ArrayRemove("a", "b"), + } + h.mustSet(doc, newData) + ds := h.mustGet(doc) + var gotMap map[string][]string + if err := ds.DataTo(&gotMap); err != nil { + t.Fatal(err) + } + if _, ok := gotMap[path]; !ok { + t.Fatalf("expected a %v key in data, got %v", path, gotMap) + } + + want := []string(nil) + if !testEqual(gotMap[path], want) { + t.Fatalf("got\n%#v\nwant\n%#v", gotMap[path], want) + } +} + +type imap map[string]interface{} + +func TestIntegration_WatchQuery(t *testing.T) { + ctx := context.Background() + coll := integrationColl(t) + h := testHelper{t} + + q := coll.Where("e", ">", 1).OrderBy("e", Asc) + it := q.Snapshots(ctx) + defer it.Stop() + + next := func() ([]*DocumentSnapshot, []DocumentChange) { + qsnap, err := it.Next() + if err != nil { + t.Fatal(err) + } + if qsnap.ReadTime.IsZero() { + t.Fatal("zero time") + } + ds, err := qsnap.Documents.GetAll() + if err != nil { + t.Fatal(err) + } + if qsnap.Size != len(ds) { + t.Fatalf("Size=%d but we have %d docs", qsnap.Size, len(ds)) + } + return ds, qsnap.Changes + } + + copts := append([]cmp.Option{cmpopts.IgnoreFields(DocumentSnapshot{}, "ReadTime")}, cmpOpts...) + check := func(msg string, wantd []*DocumentSnapshot, wantc []DocumentChange) { + gotd, gotc := next() + if diff := testutil.Diff(gotd, wantd, copts...); diff != "" { + t.Errorf("%s: %s", msg, diff) + } + if diff := testutil.Diff(gotc, wantc, copts...); diff != "" { + t.Errorf("%s: %s", msg, diff) + } + } + + check("initial", nil, nil) + doc1 := coll.NewDoc() + h.mustCreate(doc1, imap{"e": int64(2), "b": "two"}) + wds := h.mustGet(doc1) + check("one", + []*DocumentSnapshot{wds}, + []DocumentChange{{Kind: DocumentAdded, Doc: wds, OldIndex: -1, NewIndex: 0}}) + + // Add a doc that does not match. We won't see a snapshot for this. + doc2 := coll.NewDoc() + h.mustCreate(doc2, imap{"e": int64(1)}) + + // Update the first doc. We should see the change. We won't see doc2. + h.mustUpdate(doc1, []Update{{Path: "e", Value: int64(3)}}) + wds = h.mustGet(doc1) + check("update", + []*DocumentSnapshot{wds}, + []DocumentChange{{Kind: DocumentModified, Doc: wds, OldIndex: 0, NewIndex: 0}}) + + // Now update doc so that it is not in the query. We should see a snapshot with no docs. + h.mustUpdate(doc1, []Update{{Path: "e", Value: int64(0)}}) + check("update2", nil, []DocumentChange{{Kind: DocumentRemoved, Doc: wds, OldIndex: 0, NewIndex: -1}}) + + // Add two docs out of order. We should see them in order. + doc3 := coll.NewDoc() + doc4 := coll.NewDoc() + want3 := imap{"e": int64(5)} + want4 := imap{"e": int64(4)} + h.mustCreate(doc3, want3) + h.mustCreate(doc4, want4) + wds4 := h.mustGet(doc4) + wds3 := h.mustGet(doc3) + check("two#1", + []*DocumentSnapshot{wds3}, + []DocumentChange{{Kind: DocumentAdded, Doc: wds3, OldIndex: -1, NewIndex: 0}}) + check("two#2", + []*DocumentSnapshot{wds4, wds3}, + []DocumentChange{{Kind: DocumentAdded, Doc: wds4, OldIndex: -1, NewIndex: 0}}) + // Delete a doc. + h.mustDelete(doc4) + check("after del", []*DocumentSnapshot{wds3}, []DocumentChange{{Kind: DocumentRemoved, Doc: wds4, OldIndex: 0, NewIndex: -1}}) +} + +func TestIntegration_WatchQueryCancel(t *testing.T) { + ctx := context.Background() + coll := integrationColl(t) + + q := coll.Where("e", ">", 1).OrderBy("e", Asc) + ctx, cancel := context.WithCancel(ctx) + it := q.Snapshots(ctx) + defer it.Stop() + + // First call opens the stream. + _, err := it.Next() + if err != nil { + t.Fatal(err) + } + cancel() + _, err = it.Next() + codeEq(t, "after cancel", codes.Canceled, err) +} + +func TestIntegration_MissingDocs(t *testing.T) { + ctx := context.Background() + h := testHelper{t} + client := integrationClient(t) + coll := client.Collection(collectionIDs.New()) + dr1 := coll.NewDoc() + dr2 := coll.NewDoc() + dr3 := dr2.Collection("sub").NewDoc() + h.mustCreate(dr1, integrationTestMap) + defer h.mustDelete(dr1) + h.mustCreate(dr3, integrationTestMap) + defer h.mustDelete(dr3) + + // dr1 is a document in coll. dr2 was never created, but there are documents in + // its sub-collections. It is "missing". + // The Collection.DocumentRefs method includes missing document refs. + want := []string{dr1.Path, dr2.Path} + drs, err := coll.DocumentRefs(ctx).GetAll() + if err != nil { + t.Fatal(err) + } + var got []string + for _, dr := range drs { + got = append(got, dr.Path) + } + sort.Strings(want) + sort.Strings(got) + if !testutil.Equal(got, want) { + t.Errorf("got %v, want %v", got, want) + } +} + +func codeEq(t *testing.T, msg string, code codes.Code, err error) { + if grpc.Code(err) != code { + t.Fatalf("%s:\ngot <%v>\nwant code %s", msg, err, code) + } +} + +func loc() string { + _, file, line, ok := runtime.Caller(2) + if !ok { + return "???" + } + return fmt.Sprintf("%s:%d", filepath.Base(file), line) +} + +func copyMap(m map[string]interface{}) map[string]interface{} { + c := map[string]interface{}{} + for k, v := range m { + c[k] = v + } + return c +} + +func checkTimeBetween(t *testing.T, got, low, high time.Time) { + // Allow slack for clock skew. + const slack = 4 * time.Second + low = low.Add(-slack) + high = high.Add(slack) + if got.Before(low) || got.After(high) { + t.Fatalf("got %s, not in [%s, %s]", got, low, high) + } +} + +type testHelper struct { + t *testing.T +} + +func (h testHelper) mustCreate(doc *DocumentRef, data interface{}) *WriteResult { + wr, err := doc.Create(context.Background(), data) + if err != nil { + h.t.Fatalf("%s: creating: %v", loc(), err) + } + return wr +} + +func (h testHelper) mustUpdate(doc *DocumentRef, updates []Update) *WriteResult { + wr, err := doc.Update(context.Background(), updates) + if err != nil { + h.t.Fatalf("%s: updating: %v", loc(), err) + } + return wr +} + +func (h testHelper) mustGet(doc *DocumentRef) *DocumentSnapshot { + d, err := doc.Get(context.Background()) + if err != nil { + h.t.Fatalf("%s: getting: %v", loc(), err) + } + return d +} + +func (h testHelper) mustDelete(doc *DocumentRef) *WriteResult { + wr, err := doc.Delete(context.Background()) + if err != nil { + h.t.Fatalf("%s: updating: %v", loc(), err) + } + return wr +} + +func (h testHelper) mustSet(doc *DocumentRef, data interface{}, opts ...SetOption) *WriteResult { + wr, err := doc.Set(context.Background(), data, opts...) + if err != nil { + h.t.Fatalf("%s: updating: %v", loc(), err) + } + return wr +} diff --git a/vendor/cloud.google.com/go/firestore/internal/Makefile b/vendor/cloud.google.com/go/firestore/internal/Makefile new file mode 100644 index 00000000..6769cb36 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/internal/Makefile @@ -0,0 +1,16 @@ +# Build doc.go from template and snippets. + +SHELL=/bin/bash + +../doc.go: build doc-snippets.go doc.template snipdoc.awk + @tmp=$$(mktemp) && \ + awk -f snipdoc.awk doc-snippets.go doc.template > $$tmp && \ + chmod +w $@ && \ + mv $$tmp $@ && \ + chmod -w $@ + @echo "wrote $@" + +.PHONY: build + +build: + go build doc-snippets.go diff --git a/vendor/cloud.google.com/go/firestore/internal/doc-snippets.go b/vendor/cloud.google.com/go/firestore/internal/doc-snippets.go new file mode 100644 index 00000000..44a15687 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/internal/doc-snippets.go @@ -0,0 +1,161 @@ +// Copyright 2017 Google LLC +// +// 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 internal + +// TODO(deklerk) can this file and directory be deleted, or is it being used for documentation somewhere? + +import ( + "context" + "fmt" + + firestore "cloud.google.com/go/firestore" + "google.golang.org/api/iterator" +) + +// State represents a state. +//[ structDef +type State struct { + Capital string `firestore:"capital"` + Population float64 `firestore:"pop"` // in millions +} + +//] + +func f1() { + //[ NewClient + ctx := context.Background() + client, err := firestore.NewClient(ctx, "projectID") + if err != nil { + // TODO: Handle error. + } + //] + //[ refs + states := client.Collection("States") + ny := states.Doc("NewYork") + // Or, in a single call: + ny = client.Doc("States/NewYork") + //] + //[ docref.Get + docsnap, err := ny.Get(ctx) + if err != nil { + // TODO: Handle error. + } + dataMap := docsnap.Data() + fmt.Println(dataMap) + //] + //[ DataTo + var nyData State + if err := docsnap.DataTo(&nyData); err != nil { + // TODO: Handle error. + } + //] + //[ GetAll + docsnaps, err := client.GetAll(ctx, []*firestore.DocumentRef{ + states.Doc("Wisconsin"), states.Doc("Ohio"), + }) + if err != nil { + // TODO: Handle error. + } + for _, ds := range docsnaps { + _ = ds // TODO: Use ds. + } + //[ docref.Create + wr, err := ny.Create(ctx, State{ + Capital: "Albany", + Population: 19.8, + }) + if err != nil { + // TODO: Handle error. + } + fmt.Println(wr) + //] + //[ docref.Set + ca := states.Doc("California") + _, err = ca.Set(ctx, State{ + Capital: "Sacramento", + Population: 39.14, + }) + //] + + //[ docref.Update + _, err = ca.Update(ctx, []firestore.Update{{Path: "capital", Value: "Sacramento"}}) + //] + + //[ docref.Delete + _, err = ny.Delete(ctx) + //] + + //[ LUT-precond + docsnap, err = ca.Get(ctx) + if err != nil { + // TODO: Handle error. + } + _, err = ca.Update(ctx, + []firestore.Update{{Path: "capital", Value: "Sacramento"}}, + firestore.LastUpdateTime(docsnap.UpdateTime)) + //] + + //[ WriteBatch + writeResults, err := client.Batch(). + Create(ny, State{Capital: "Albany"}). + Update(ca, []firestore.Update{{Path: "capital", Value: "Sacramento"}}). + Delete(client.Doc("States/WestDakota")). + Commit(ctx) + //] + _ = writeResults + + //[ Query + q := states.Where("pop", ">", 10).OrderBy("pop", firestore.Desc) + //] + //[ Documents + iter := q.Documents(ctx) + for { + doc, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(doc.Data()) + } + //] + + //[ CollQuery + iter = client.Collection("States").Documents(ctx) + //] +} + +func txn() { + var ctx context.Context + var client *firestore.Client + //[ Transaction + ny := client.Doc("States/NewYork") + err := client.RunTransaction(ctx, func(ctx context.Context, tx *firestore.Transaction) error { + doc, err := tx.Get(ny) // tx.Get, NOT ny.Get! + if err != nil { + return err + } + pop, err := doc.DataAt("pop") + if err != nil { + return err + } + return tx.Update(ny, []firestore.Update{{Path: "pop", Value: pop.(float64) + 0.2}}) + }) + if err != nil { + // TODO: Handle error. + } + //] +} diff --git a/vendor/cloud.google.com/go/firestore/internal/doc.template b/vendor/cloud.google.com/go/firestore/internal/doc.template new file mode 100644 index 00000000..6d428235 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/internal/doc.template @@ -0,0 +1,145 @@ +// Copyright 2017 Google LLC +// +// 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. + +// DO NOT EDIT doc.go. Modify internal/doc.template, then run make -C internal. + +/* +Package firestore provides a client for reading and writing to a Cloud Firestore +database. + +See https://cloud.google.com/firestore/docs for an introduction +to Cloud Firestore and additional help on using the Firestore API. + +Note: you can't use both Cloud Firestore and Cloud Datastore in the same +project. + +Creating a Client + +To start working with this package, create a client with a project ID: + +[NewClient] + +CollectionRefs and DocumentRefs + +In Firestore, documents are sets of key-value pairs, and collections are groups of +documents. A Firestore database consists of a hierarchy of alternating collections +and documents, referred to by slash-separated paths like +"States/California/Cities/SanFrancisco". + +This client is built around references to collections and documents. CollectionRefs +and DocumentRefs are lightweight values that refer to the corresponding database +entities. Creating a ref does not involve any network traffic. + +[refs] + +Reading + +Use DocumentRef.Get to read a document. The result is a DocumentSnapshot. +Call its Data method to obtain the entire document contents as a map. + +[docref.Get] + +You can also obtain a single field with DataAt, or extract the data into a struct +with DataTo. With the type definition + +[structDef] + +we can extract the document's data into a value of type State: + +[DataTo] + +Note that this client supports struct tags beginning with "firestore:" that work like +the tags of the encoding/json package, letting you rename fields, ignore them, or +omit their values when empty. + +To retrieve multiple documents from their references in a single call, use +Client.GetAll. + +[GetAll] + +Writing + +For writing individual documents, use the methods on DocumentReference. +Create creates a new document. + +[docref.Create] + +The first return value is a WriteResult, which contains the time +at which the document was updated. + +Create fails if the document exists. Another method, Set, either replaces an existing +document or creates a new one. + +[docref.Set] + +To update some fields of an existing document, use Update. It takes a list of +paths to update and their corresponding values. + +[docref.Update] + +Use DocumentRef.Delete to delete a document. + +[docref.Delete] + +Preconditions + +You can condition Deletes or Updates on when a document was last changed. Specify +these preconditions as an option to a Delete or Update method. The check and the +write happen atomically with a single RPC. + +[LUT-precond] + +Here we update a doc only if it hasn't changed since we read it. +You could also do this with a transaction. + +To perform multiple writes at once, use a WriteBatch. Its methods chain +for convenience. + +WriteBatch.Commit sends the collected writes to the server, where they happen +atomically. + +[WriteBatch] + +Queries + +You can use SQL to select documents from a collection. Begin with the collection, and +build up a query using Select, Where and other methods of Query. + +[Query] + +Call the Query's Documents method to get an iterator, and use it like +the other Google Cloud Client iterators. + +[Documents] + +To get all the documents in a collection, you can use the collection itself +as a query. + +[CollQuery] + +Transactions + +Use a transaction to execute reads and writes atomically. All reads must happen +before any writes. Transaction creation, commit, rollback and retry are handled for +you by the Client.RunTransaction method; just provide a function and use the +read and write methods of the Transaction passed to it. + +[Transaction] + +Authentication + +See examples of authorization and authentication at +https://godoc.org/cloud.google.com/go#pkg-examples. +*/ +package firestore diff --git a/vendor/cloud.google.com/go/firestore/internal/snipdoc.awk b/vendor/cloud.google.com/go/firestore/internal/snipdoc.awk new file mode 100644 index 00000000..98e788eb --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/internal/snipdoc.awk @@ -0,0 +1,116 @@ +# Copyright 2017 Google LLC +# +# 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. + +# snipdoc merges code snippets from Go source files into a template to +# produce another go file (typically doc.go). +# +# Call with one or more .go files and a template file. +# +# awk -f snipmd.awk foo.go bar.go doc.template +# +# In the Go files, start a snippet with +# //[ NAME +# and end it with +# //] +# +# In the template, write +# [NAME] +# on a line by itself to insert the snippet NAME on that line. +# +# The following transformations are made to the Go code: +# - Trailing blank lines are removed. +# - `ELLIPSIS` and `_ = ELLIPSIS` are replaced by `...` + + +/^[ \t]*\/\/\[/ { # start snippet in Go file + if (inGo()) { + if ($2 == "") { + die("missing snippet name") + } + curSnip = $2 + next + } +} + +/^[ \t]*\/\/]/ { # end snippet in Go file + if (inGo()) { + if (curSnip != "") { + # Remove all trailing newlines. + gsub(/[\t\n]+$/, "", snips[curSnip]) + curSnip = "" + next + } else { + die("//] without corresponding //[") + } + } +} + +ENDFILE { + if (curSnip != "") { + die("unclosed snippet: " curSnip) + } +} + +/^\[.*\]$/ { # Snippet marker in template file. + if (inTemplate()) { + name = substr($1, 2, length($1)-2) + if (snips[name] == "") { + die("no snippet named " name) + } + printf("%s\n", snips[name]) + afterSnip = 1 + next + } +} + +# Matches every line. +{ + if (curSnip != "") { + # If the first line in the snip has no indent, add the indent. + if (snips[curSnip] == "") { + if (index($0, "\t") == 1) { + extraIndent = "" + } else { + extraIndent = "\t" + } + } + + line = $0 + # Replace ELLIPSIS. + gsub(/_ = ELLIPSIS/, "...", line) + gsub(/ELLIPSIS/, "...", line) + + snips[curSnip] = snips[curSnip] extraIndent line "\n" + } else if (inTemplate()) { + afterSnip = 0 + # Copy to output. + print + } +} + + + +function inTemplate() { + return match(FILENAME, /\.template$/) +} + +function inGo() { + return match(FILENAME, /\.go$/) +} + + +function die(msg) { + printf("%s:%d: %s\n", FILENAME, FNR, msg) > "/dev/stderr" + exit 1 +} diff --git a/vendor/cloud.google.com/go/firestore/list_documents.go b/vendor/cloud.google.com/go/firestore/list_documents.go new file mode 100644 index 00000000..f056d779 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/list_documents.go @@ -0,0 +1,104 @@ +// Copyright 2018 Google LLC +// +// 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 firestore + +import ( + "context" + + vkit "cloud.google.com/go/firestore/apiv1beta1" + "google.golang.org/api/iterator" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +// DocumentRefIterator is an interator over DocumentRefs. +type DocumentRefIterator struct { + client *Client + it *vkit.DocumentIterator + pageInfo *iterator.PageInfo + nextFunc func() error + items []*DocumentRef + err error +} + +func newDocumentRefIterator(ctx context.Context, cr *CollectionRef, tid []byte) *DocumentRefIterator { + client := cr.c + req := &pb.ListDocumentsRequest{ + Parent: cr.parentPath, + CollectionId: cr.ID, + ShowMissing: true, + Mask: &pb.DocumentMask{}, // empty mask: we want only the ref + } + if tid != nil { + req.ConsistencySelector = &pb.ListDocumentsRequest_Transaction{tid} + } + it := &DocumentRefIterator{ + client: client, + it: client.c.ListDocuments(withResourceHeader(ctx, client.path()), req), + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.items) }, + func() interface{} { b := it.items; it.items = nil; return b }) + return it +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *DocumentRefIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } + +// Next returns the next result. Its second return value is iterator.Done if there +// are no more results. Once Next returns Done, all subsequent calls will return +// Done. +func (it *DocumentRefIterator) Next() (*DocumentRef, error) { + if err := it.nextFunc(); err != nil { + return nil, err + } + item := it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *DocumentRefIterator) fetch(pageSize int, pageToken string) (string, error) { + if it.err != nil { + return "", it.err + } + return iterFetch(pageSize, pageToken, it.it.PageInfo(), func() error { + docProto, err := it.it.Next() + if err != nil { + return err + } + docRef, err := pathToDoc(docProto.Name, it.client) + if err != nil { + return err + } + it.items = append(it.items, docRef) + return nil + }) +} + +// GetAll returns all the DocumentRefs remaining from the iterator. +func (it *DocumentRefIterator) GetAll() ([]*DocumentRef, error) { + var drs []*DocumentRef + for { + dr, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + return nil, err + } + drs = append(drs, dr) + } + return drs, nil +} diff --git a/vendor/cloud.google.com/go/firestore/mock_test.go b/vendor/cloud.google.com/go/firestore/mock_test.go new file mode 100644 index 00000000..a482a6c5 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/mock_test.go @@ -0,0 +1,226 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +// A simple mock server. + +import ( + "context" + "fmt" + "sort" + "strings" + + "cloud.google.com/go/internal/testutil" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/empty" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type mockServer struct { + pb.FirestoreServer + + Addr string + + reqItems []reqItem + resps []interface{} +} + +type reqItem struct { + wantReq proto.Message + adjust func(gotReq proto.Message) +} + +func newMockServer() (*mockServer, error) { + srv, err := testutil.NewServer() + if err != nil { + return nil, err + } + mock := &mockServer{Addr: srv.Addr} + pb.RegisterFirestoreServer(srv.Gsrv, mock) + srv.Start() + return mock, nil +} + +// addRPC adds a (request, response) pair to the server's list of expected +// interactions. The server will compare the incoming request with wantReq +// using proto.Equal. The response can be a message or an error. +// +// For the Listen RPC, resp should be a []interface{}, where each element +// is either ListenResponse or an error. +// +// Passing nil for wantReq disables the request check. +func (s *mockServer) addRPC(wantReq proto.Message, resp interface{}) { + s.addRPCAdjust(wantReq, resp, nil) +} + +// addRPCAdjust is like addRPC, but accepts a function that can be used +// to tweak the requests before comparison, for example to adjust for +// randomness. +func (s *mockServer) addRPCAdjust(wantReq proto.Message, resp interface{}, adjust func(proto.Message)) { + s.reqItems = append(s.reqItems, reqItem{wantReq, adjust}) + s.resps = append(s.resps, resp) +} + +// popRPC compares the request with the next expected (request, response) pair. +// It returns the response, or an error if the request doesn't match what +// was expected or there are no expected rpcs. +func (s *mockServer) popRPC(gotReq proto.Message) (interface{}, error) { + if len(s.reqItems) == 0 { + panic("out of RPCs") + } + ri := s.reqItems[0] + s.reqItems = s.reqItems[1:] + if ri.wantReq != nil { + if ri.adjust != nil { + ri.adjust(gotReq) + } + + // Sort FieldTransforms by FieldPath, since slice order is undefined and proto.Equal + // is strict about order. + switch gotReqTyped := gotReq.(type) { + case *pb.CommitRequest: + for _, w := range gotReqTyped.Writes { + switch opTyped := w.Operation.(type) { + case *pb.Write_Transform: + sort.Sort(ByFieldPath(opTyped.Transform.FieldTransforms)) + } + } + } + + if !proto.Equal(gotReq, ri.wantReq) { + return nil, fmt.Errorf("mockServer: bad request\ngot: %T\n%s\nwant: %T\n%s", + gotReq, proto.MarshalTextString(gotReq), + ri.wantReq, proto.MarshalTextString(ri.wantReq)) + } + } + resp := s.resps[0] + s.resps = s.resps[1:] + if err, ok := resp.(error); ok { + return nil, err + } + return resp, nil +} + +func (a ByFieldPath) Len() int { return len(a) } +func (a ByFieldPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a ByFieldPath) Less(i, j int) bool { return a[i].FieldPath < a[j].FieldPath } + +type ByFieldPath []*pb.DocumentTransform_FieldTransform + +func (s *mockServer) reset() { + s.reqItems = nil + s.resps = nil +} + +func (s *mockServer) GetDocument(_ context.Context, req *pb.GetDocumentRequest) (*pb.Document, error) { + res, err := s.popRPC(req) + if err != nil { + return nil, err + } + return res.(*pb.Document), nil +} + +func (s *mockServer) Commit(_ context.Context, req *pb.CommitRequest) (*pb.CommitResponse, error) { + res, err := s.popRPC(req) + if err != nil { + return nil, err + } + return res.(*pb.CommitResponse), nil +} + +func (s *mockServer) BatchGetDocuments(req *pb.BatchGetDocumentsRequest, bs pb.Firestore_BatchGetDocumentsServer) error { + res, err := s.popRPC(req) + if err != nil { + return err + } + responses := res.([]interface{}) + for _, res := range responses { + switch res := res.(type) { + case *pb.BatchGetDocumentsResponse: + if err := bs.Send(res); err != nil { + return err + } + case error: + return res + default: + panic(fmt.Sprintf("bad response type in BatchGetDocuments: %+v", res)) + } + } + return nil +} + +func (s *mockServer) RunQuery(req *pb.RunQueryRequest, qs pb.Firestore_RunQueryServer) error { + res, err := s.popRPC(req) + if err != nil { + return err + } + responses := res.([]interface{}) + for _, res := range responses { + switch res := res.(type) { + case *pb.RunQueryResponse: + if err := qs.Send(res); err != nil { + return err + } + case error: + return res + default: + panic(fmt.Sprintf("bad response type in RunQuery: %+v", res)) + } + } + return nil +} + +func (s *mockServer) BeginTransaction(_ context.Context, req *pb.BeginTransactionRequest) (*pb.BeginTransactionResponse, error) { + res, err := s.popRPC(req) + if err != nil { + return nil, err + } + return res.(*pb.BeginTransactionResponse), nil +} + +func (s *mockServer) Rollback(_ context.Context, req *pb.RollbackRequest) (*empty.Empty, error) { + res, err := s.popRPC(req) + if err != nil { + return nil, err + } + return res.(*empty.Empty), nil +} + +func (s *mockServer) Listen(stream pb.Firestore_ListenServer) error { + req, err := stream.Recv() + if err != nil { + return err + } + responses, err := s.popRPC(req) + if err != nil { + if status.Code(err) == codes.Unknown && strings.Contains(err.Error(), "mockServer") { + // The stream will retry on Unknown, but we don't want that to happen if + // the error comes from us. + panic(err) + } + return err + } + for _, res := range responses.([]interface{}) { + if err, ok := res.(error); ok { + return err + } + if err := stream.Send(res.(*pb.ListenResponse)); err != nil { + return err + } + } + return nil +} diff --git a/vendor/cloud.google.com/go/firestore/options.go b/vendor/cloud.google.com/go/firestore/options.go new file mode 100644 index 00000000..ec6a2ae8 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/options.go @@ -0,0 +1,175 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "errors" + "fmt" + "time" + + "github.com/golang/protobuf/ptypes" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +// A Precondition modifies a Firestore update or delete operation. +type Precondition interface { + // Returns the corresponding Precondition proto. + preconditionProto() (*pb.Precondition, error) +} + +// Exists is a Precondition that checks for the existence of a resource before +// writing to it. If the check fails, the write does not occur. +var Exists Precondition + +func init() { + // Initialize here so godoc doesn't show the internal value. + Exists = exists(true) +} + +type exists bool + +func (e exists) preconditionProto() (*pb.Precondition, error) { + return &pb.Precondition{ + ConditionType: &pb.Precondition_Exists{bool(e)}, + }, nil +} + +func (e exists) String() string { + if e { + return "Exists" + } + return "DoesNotExist" +} + +// LastUpdateTime returns a Precondition that checks that a resource must exist and +// must have last been updated at the given time. If the check fails, the write +// does not occur. +func LastUpdateTime(t time.Time) Precondition { return lastUpdateTime(t) } + +type lastUpdateTime time.Time + +func (u lastUpdateTime) preconditionProto() (*pb.Precondition, error) { + ts, err := ptypes.TimestampProto(time.Time(u)) + if err != nil { + return nil, err + } + return &pb.Precondition{ + ConditionType: &pb.Precondition_UpdateTime{ts}, + }, nil +} + +func (u lastUpdateTime) String() string { return fmt.Sprintf("LastUpdateTime(%s)", time.Time(u)) } + +func processPreconditionsForDelete(preconds []Precondition) (*pb.Precondition, error) { + // At most one option permitted. + switch len(preconds) { + case 0: + return nil, nil + case 1: + return preconds[0].preconditionProto() + default: + return nil, fmt.Errorf("firestore: conflicting preconditions: %+v", preconds) + } +} + +func processPreconditionsForUpdate(preconds []Precondition) (*pb.Precondition, error) { + // At most one option permitted, and it cannot be Exists. + switch len(preconds) { + case 0: + // If the user doesn't provide any options, default to Exists(true). + return exists(true).preconditionProto() + case 1: + if _, ok := preconds[0].(exists); ok { + return nil, errors.New("Cannot use Exists with Update") + } + return preconds[0].preconditionProto() + default: + return nil, fmt.Errorf("firestore: conflicting preconditions: %+v", preconds) + } +} + +func processPreconditionsForVerify(preconds []Precondition) (*pb.Precondition, error) { + // At most one option permitted. + switch len(preconds) { + case 0: + return nil, nil + case 1: + return preconds[0].preconditionProto() + default: + return nil, fmt.Errorf("firestore: conflicting preconditions: %+v", preconds) + } +} + +// A SetOption modifies a Firestore set operation. +type SetOption interface { + fieldPaths() (fps []FieldPath, all bool, err error) +} + +// MergeAll is a SetOption that causes all the field paths given in the data argument +// to Set to be overwritten. It is not supported for struct data. +var MergeAll SetOption = merge{all: true} + +// Merge returns a SetOption that causes only the given field paths to be +// overwritten. Other fields on the existing document will be untouched. It is an +// error if a provided field path does not refer to a value in the data passed to +// Set. +func Merge(fps ...FieldPath) SetOption { + for _, fp := range fps { + if err := fp.validate(); err != nil { + return merge{err: err} + } + } + return merge{paths: fps} +} + +type merge struct { + all bool + paths []FieldPath + err error +} + +func (m merge) String() string { + if m.err != nil { + return fmt.Sprintf("", m.err) + } + if m.all { + return "MergeAll" + } + return fmt.Sprintf("Merge(%+v)", m.paths) +} + +func (m merge) fieldPaths() (fps []FieldPath, all bool, err error) { + if m.err != nil { + return nil, false, m.err + } + if err := checkNoDupOrPrefix(m.paths); err != nil { + return nil, false, err + } + if m.all { + return nil, true, nil + } + return m.paths, false, nil +} + +func processSetOptions(opts []SetOption) (fps []FieldPath, all bool, err error) { + switch len(opts) { + case 0: + return nil, false, nil + case 1: + return opts[0].fieldPaths() + default: + return nil, false, fmt.Errorf("conflicting options: %+v", opts) + } +} diff --git a/vendor/cloud.google.com/go/firestore/options_test.go b/vendor/cloud.google.com/go/firestore/options_test.go new file mode 100644 index 00000000..999a0a61 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/options_test.go @@ -0,0 +1,151 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "testing" + + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +func TestProcessPreconditionsForVerify(t *testing.T) { + for _, test := range []struct { + in []Precondition + want *pb.Precondition + wantErr bool + }{ + { + in: nil, + want: nil, + }, + { + in: []Precondition{}, + want: nil, + }, + { + in: []Precondition{Exists}, + want: &pb.Precondition{ConditionType: &pb.Precondition_Exists{true}}, + }, + { + in: []Precondition{LastUpdateTime(aTime)}, + want: &pb.Precondition{ConditionType: &pb.Precondition_UpdateTime{aTimestamp}}, + }, + { + in: []Precondition{Exists, LastUpdateTime(aTime)}, + wantErr: true, + }, + { + in: []Precondition{Exists, Exists}, + wantErr: true, + }, + } { + got, err := processPreconditionsForVerify(test.in) + switch { + case test.wantErr && err == nil: + t.Errorf("%v: got nil, want error", test.in) + case !test.wantErr && err != nil: + t.Errorf("%v: got <%v>, want no error", test.in, err) + case !test.wantErr && err == nil && !testEqual(got, test.want): + t.Errorf("%v: got %+v, want %v", test.in, got, test.want) + } + } +} + +func TestProcessPreconditionsForDelete(t *testing.T) { + for _, test := range []struct { + in []Precondition + want *pb.Precondition + wantErr bool + }{ + { + in: nil, + want: nil, + }, + { + in: []Precondition{}, + want: nil, + }, + { + in: []Precondition{Exists}, + want: &pb.Precondition{ConditionType: &pb.Precondition_Exists{true}}, + }, + { + in: []Precondition{LastUpdateTime(aTime)}, + want: &pb.Precondition{ConditionType: &pb.Precondition_UpdateTime{aTimestamp}}, + }, + { + in: []Precondition{Exists, LastUpdateTime(aTime)}, + wantErr: true, + }, + { + in: []Precondition{Exists, Exists}, + wantErr: true, + }, + } { + got, err := processPreconditionsForDelete(test.in) + switch { + case test.wantErr && err == nil: + t.Errorf("%v: got nil, want error", test.in) + case !test.wantErr && err != nil: + t.Errorf("%v: got <%v>, want no error", test.in, err) + case !test.wantErr && err == nil && !testEqual(got, test.want): + t.Errorf("%v: got %+v, want %v", test.in, got, test.want) + } + } +} + +func TestProcessPreconditionsForUpdate(t *testing.T) { + for _, test := range []struct { + in []Precondition + want *pb.Precondition + wantErr bool + }{ + { + in: nil, + want: &pb.Precondition{ConditionType: &pb.Precondition_Exists{true}}, + }, + { + in: []Precondition{}, + want: &pb.Precondition{ConditionType: &pb.Precondition_Exists{true}}, + }, + + { + in: []Precondition{Exists}, + wantErr: true, + }, + { + in: []Precondition{LastUpdateTime(aTime)}, + want: &pb.Precondition{ConditionType: &pb.Precondition_UpdateTime{aTimestamp}}, + }, + { + in: []Precondition{Exists, LastUpdateTime(aTime)}, + wantErr: true, + }, + { + in: []Precondition{Exists, Exists}, + wantErr: true, + }, + } { + got, err := processPreconditionsForUpdate(test.in) + switch { + case test.wantErr && err == nil: + t.Errorf("%v: got nil, want error", test.in) + case !test.wantErr && err != nil: + t.Errorf("%v: got <%v>, want no error", test.in, err) + case !test.wantErr && err == nil && !testEqual(got, test.want): + t.Errorf("%v: got %+v, want %v", test.in, got, test.want) + } + } +} diff --git a/vendor/cloud.google.com/go/firestore/order.go b/vendor/cloud.google.com/go/firestore/order.go new file mode 100644 index 00000000..c3f59ce1 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/order.go @@ -0,0 +1,216 @@ +// Copyright 2018 Google LLC +// +// 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 firestore + +import ( + "bytes" + "fmt" + "math" + "sort" + "strings" + + tspb "github.com/golang/protobuf/ptypes/timestamp" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +// Returns a negative number, zero, or a positive number depending on whether a is +// less than, equal to, or greater than b according to Firestore's ordering of +// values. +func compareValues(a, b *pb.Value) int { + ta := typeOrder(a) + tb := typeOrder(b) + if ta != tb { + return compareInt64s(int64(ta), int64(tb)) + } + switch a := a.ValueType.(type) { + case *pb.Value_NullValue: + return 0 // nulls are equal + + case *pb.Value_BooleanValue: + av := a.BooleanValue + bv := b.GetBooleanValue() + switch { + case av && !bv: + return 1 + case bv && !av: + return -1 + default: + return 0 + } + + case *pb.Value_IntegerValue: + return compareNumbers(float64(a.IntegerValue), toFloat(b)) + + case *pb.Value_DoubleValue: + return compareNumbers(a.DoubleValue, toFloat(b)) + + case *pb.Value_TimestampValue: + return compareTimestamps(a.TimestampValue, b.GetTimestampValue()) + + case *pb.Value_StringValue: + return strings.Compare(a.StringValue, b.GetStringValue()) + + case *pb.Value_BytesValue: + return bytes.Compare(a.BytesValue, b.GetBytesValue()) + + case *pb.Value_ReferenceValue: + return compareReferences(a.ReferenceValue, b.GetReferenceValue()) + + case *pb.Value_GeoPointValue: + ag := a.GeoPointValue + bg := b.GetGeoPointValue() + if ag.Latitude != bg.Latitude { + return compareFloat64s(ag.Latitude, bg.Latitude) + } + return compareFloat64s(ag.Longitude, bg.Longitude) + + case *pb.Value_ArrayValue: + return compareArrays(a.ArrayValue.Values, b.GetArrayValue().Values) + + case *pb.Value_MapValue: + return compareMaps(a.MapValue.Fields, b.GetMapValue().Fields) + + default: + panic(fmt.Sprintf("bad value type: %v", a)) + } +} + +// Treats NaN as less than any non-NaN. +func compareNumbers(a, b float64) int { + switch { + case math.IsNaN(a): + if math.IsNaN(b) { + return 0 + } + return -1 + case math.IsNaN(b): + return 1 + default: + return compareFloat64s(a, b) + } +} + +// Return v as a float64, assuming it's an Integer or Double. +func toFloat(v *pb.Value) float64 { + if x, ok := v.ValueType.(*pb.Value_IntegerValue); ok { + return float64(x.IntegerValue) + } + return v.GetDoubleValue() +} + +func compareTimestamps(a, b *tspb.Timestamp) int { + if c := compareInt64s(a.Seconds, b.Seconds); c != 0 { + return c + } + return compareInt64s(int64(a.Nanos), int64(b.Nanos)) +} + +func compareReferences(a, b string) int { + // Compare path components lexicographically. + pa := strings.Split(a, "/") + pb := strings.Split(b, "/") + return compareSequences(len(pa), len(pb), func(i int) int { + return strings.Compare(pa[i], pb[i]) + }) +} + +func compareArrays(a, b []*pb.Value) int { + return compareSequences(len(a), len(b), func(i int) int { + return compareValues(a[i], b[i]) + }) +} + +func compareMaps(a, b map[string]*pb.Value) int { + sortedKeys := func(m map[string]*pb.Value) []string { + var ks []string + for k := range m { + ks = append(ks, k) + } + sort.Strings(ks) + return ks + } + + aks := sortedKeys(a) + bks := sortedKeys(b) + return compareSequences(len(aks), len(bks), func(i int) int { + if c := strings.Compare(aks[i], bks[i]); c != 0 { + return c + } + k := aks[i] + return compareValues(a[k], b[k]) + }) +} + +func compareSequences(len1, len2 int, compare func(int) int) int { + for i := 0; i < len1 && i < len2; i++ { + if c := compare(i); c != 0 { + return c + } + } + return compareInt64s(int64(len1), int64(len2)) +} + +func compareFloat64s(a, b float64) int { + switch { + case a < b: + return -1 + case a > b: + return 1 + default: + return 0 + } +} + +func compareInt64s(a, b int64) int { + switch { + case a < b: + return -1 + case a > b: + return 1 + default: + return 0 + } +} + +// Return an integer corresponding to the type of value stored in v, such that +// comparing the resulting integers gives the Firestore ordering for types. +func typeOrder(v *pb.Value) int { + switch v.ValueType.(type) { + case *pb.Value_NullValue: + return 0 + case *pb.Value_BooleanValue: + return 1 + case *pb.Value_IntegerValue: + return 2 + case *pb.Value_DoubleValue: + return 2 + case *pb.Value_TimestampValue: + return 3 + case *pb.Value_StringValue: + return 4 + case *pb.Value_BytesValue: + return 5 + case *pb.Value_ReferenceValue: + return 6 + case *pb.Value_GeoPointValue: + return 7 + case *pb.Value_ArrayValue: + return 8 + case *pb.Value_MapValue: + return 9 + default: + panic(fmt.Sprintf("bad value type: %v", v)) + } +} diff --git a/vendor/cloud.google.com/go/firestore/order_test.go b/vendor/cloud.google.com/go/firestore/order_test.go new file mode 100644 index 00000000..ac8e06e2 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/order_test.go @@ -0,0 +1,118 @@ +// Copyright 2018 Google LLC +// +// 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 firestore + +import ( + "math" + "testing" + "time" + + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/genproto/googleapis/type/latlng" +) + +func TestCompareValues(t *testing.T) { + // Ordered list of values. + vals := []*pb.Value{ + nullValue, + boolval(false), + boolval(true), + floatval(math.NaN()), + floatval(math.Inf(-1)), + floatval(-math.MaxFloat64), + int64val(math.MinInt64), + floatval(-1.1), + intval(-1), + intval(0), + floatval(math.SmallestNonzeroFloat64), + intval(1), + floatval(1.1), + intval(2), + int64val(math.MaxInt64), + floatval(math.MaxFloat64), + floatval(math.Inf(1)), + tsval(time.Date(2016, 5, 20, 10, 20, 0, 0, time.UTC)), + tsval(time.Date(2016, 10, 21, 15, 32, 0, 0, time.UTC)), + strval(""), + strval("\u0000\ud7ff\ue000\uffff"), + strval("(╯°□°)╯︵ ┻━┻"), + strval("a"), + strval("abc def"), + strval("e\u0301b"), + strval("æ"), + strval("\u00e9a"), + bytesval([]byte{}), + bytesval([]byte{0}), + bytesval([]byte{0, 1, 2, 3, 4}), + bytesval([]byte{0, 1, 2, 4, 3}), + bytesval([]byte{255}), + refval("projects/p1/databases/d1/documents/c1/doc1"), + refval("projects/p1/databases/d1/documents/c1/doc2"), + refval("projects/p1/databases/d1/documents/c1/doc2/c2/doc1"), + refval("projects/p1/databases/d1/documents/c1/doc2/c2/doc2"), + refval("projects/p1/databases/d1/documents/c10/doc1"), + refval("projects/p1/databases/dkkkkklkjnjkkk1/documents/c2/doc1"), + refval("projects/p2/databases/d2/documents/c1/doc1"), + refval("projects/p2/databases/d2/documents/c1-/doc1"), + geopoint(-90, -180), + geopoint(-90, 0), + geopoint(-90, 180), + geopoint(0, -180), + geopoint(0, 0), + geopoint(0, 180), + geopoint(1, -180), + geopoint(1, 0), + geopoint(1, 180), + geopoint(90, -180), + geopoint(90, 0), + geopoint(90, 180), + arrayval(), + arrayval(strval("bar")), + arrayval(strval("foo")), + arrayval(strval("foo"), intval(1)), + arrayval(strval("foo"), intval(2)), + arrayval(strval("foo"), strval("0")), + mapval(map[string]*pb.Value{"bar": intval(0)}), + mapval(map[string]*pb.Value{"bar": intval(0), "foo": intval(1)}), + mapval(map[string]*pb.Value{"foo": intval(1)}), + mapval(map[string]*pb.Value{"foo": intval(2)}), + mapval(map[string]*pb.Value{"foo": strval("0")}), + } + + for i, v1 := range vals { + if got := compareValues(v1, v1); got != 0 { + t.Errorf("compare(%v, %v) == %d, want 0", v1, v1, got) + } + for _, v2 := range vals[i+1:] { + if got := compareValues(v1, v2); got != -1 { + t.Errorf("compare(%v, %v) == %d, want -1", v1, v2, got) + } + if got := compareValues(v2, v1); got != 1 { + t.Errorf("compare(%v, %v) == %d, want 1", v1, v2, got) + } + } + } + + // Integers and Doubles order the same. + n1 := intval(17) + n2 := floatval(17) + if got := compareValues(n1, n2); got != 0 { + t.Errorf("compare(%v, %v) == %d, want 0", n1, n2, got) + } +} + +func geopoint(lat, lng float64) *pb.Value { + return geoval(&latlng.LatLng{Latitude: lat, Longitude: lng}) +} diff --git a/vendor/cloud.google.com/go/firestore/query.go b/vendor/cloud.google.com/go/firestore/query.go new file mode 100644 index 00000000..71b0b3b5 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/query.go @@ -0,0 +1,781 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "errors" + "fmt" + "io" + "math" + "reflect" + "time" + + "cloud.google.com/go/internal/btree" + "github.com/golang/protobuf/ptypes/wrappers" + "google.golang.org/api/iterator" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +// Query represents a Firestore query. +// +// Query values are immutable. Each Query method creates +// a new Query; it does not modify the old. +type Query struct { + c *Client + parentPath string // path of the collection's parent + collectionID string + selection []FieldPath + filters []filter + orders []order + offset int32 + limit *wrappers.Int32Value + startVals, endVals []interface{} + startDoc, endDoc *DocumentSnapshot + startBefore, endBefore bool + err error +} + +func (q *Query) collectionPath() string { + return q.parentPath + "/documents/" + q.collectionID +} + +// DocumentID is the special field name representing the ID of a document +// in queries. +const DocumentID = "__name__" + +// Select returns a new Query that specifies the paths +// to return from the result documents. +// Each path argument can be a single field or a dot-separated sequence of +// fields, and must not contain any of the runes "˜*/[]". +// +// An empty Select call will produce a query that returns only document IDs. +func (q Query) Select(paths ...string) Query { + var fps []FieldPath + for _, s := range paths { + fp, err := parseDotSeparatedString(s) + if err != nil { + q.err = err + return q + } + fps = append(fps, fp) + } + return q.SelectPaths(fps...) +} + +// SelectPaths returns a new Query that specifies the field paths +// to return from the result documents. +// +// An empty SelectPaths call will produce a query that returns only document IDs. +func (q Query) SelectPaths(fieldPaths ...FieldPath) Query { + if len(fieldPaths) == 0 { + q.selection = []FieldPath{{DocumentID}} + } else { + q.selection = fieldPaths + } + return q +} + +// Where returns a new Query that filters the set of results. +// A Query can have multiple filters. +// The path argument can be a single field or a dot-separated sequence of +// fields, and must not contain any of the runes "˜*/[]". +// The op argument must be one of "==", "<", "<=", ">" or ">=". +func (q Query) Where(path, op string, value interface{}) Query { + fp, err := parseDotSeparatedString(path) + if err != nil { + q.err = err + return q + } + q.filters = append(append([]filter(nil), q.filters...), filter{fp, op, value}) + return q +} + +// WherePath returns a new Query that filters the set of results. +// A Query can have multiple filters. +// The op argument must be one of "==", "<", "<=", ">" or ">=". +func (q Query) WherePath(fp FieldPath, op string, value interface{}) Query { + q.filters = append(append([]filter(nil), q.filters...), filter{fp, op, value}) + return q +} + +// Direction is the sort direction for result ordering. +type Direction int32 + +const ( + // Asc sorts results from smallest to largest. + Asc Direction = Direction(pb.StructuredQuery_ASCENDING) + + // Desc sorts results from largest to smallest. + Desc Direction = Direction(pb.StructuredQuery_DESCENDING) +) + +// OrderBy returns a new Query that specifies the order in which results are +// returned. A Query can have multiple OrderBy/OrderByPath specifications. OrderBy +// appends the specification to the list of existing ones. +// +// The path argument can be a single field or a dot-separated sequence of +// fields, and must not contain any of the runes "˜*/[]". +// +// To order by document name, use the special field path DocumentID. +func (q Query) OrderBy(path string, dir Direction) Query { + fp, err := parseDotSeparatedString(path) + if err != nil { + q.err = err + return q + } + q.orders = append(q.copyOrders(), order{fp, dir}) + return q +} + +// OrderByPath returns a new Query that specifies the order in which results are +// returned. A Query can have multiple OrderBy/OrderByPath specifications. +// OrderByPath appends the specification to the list of existing ones. +func (q Query) OrderByPath(fp FieldPath, dir Direction) Query { + q.orders = append(q.copyOrders(), order{fp, dir}) + return q +} + +func (q *Query) copyOrders() []order { + return append([]order(nil), q.orders...) +} + +// Offset returns a new Query that specifies the number of initial results to skip. +// It must not be negative. +func (q Query) Offset(n int) Query { + q.offset = trunc32(n) + return q +} + +// Limit returns a new Query that specifies the maximum number of results to return. +// It must not be negative. +func (q Query) Limit(n int) Query { + q.limit = &wrappers.Int32Value{Value: trunc32(n)} + return q +} + +// StartAt returns a new Query that specifies that results should start at +// the document with the given field values. +// +// If StartAt is called with a single DocumentSnapshot, its field values are used. +// The DocumentSnapshot must have all the fields mentioned in the OrderBy clauses. +// +// Otherwise, StartAt should be called with one field value for each OrderBy clause, +// in the order that they appear. For example, in +// q.OrderBy("X", Asc).OrderBy("Y", Desc).StartAt(1, 2) +// results will begin at the first document where X = 1 and Y = 2. +// +// If an OrderBy call uses the special DocumentID field path, the corresponding value +// should be the document ID relative to the query's collection. For example, to +// start at the document "NewYork" in the "States" collection, write +// +// client.Collection("States").OrderBy(DocumentID, firestore.Asc).StartAt("NewYork") +// +// Calling StartAt overrides a previous call to StartAt or StartAfter. +func (q Query) StartAt(docSnapshotOrFieldValues ...interface{}) Query { + q.startBefore = true + q.startVals, q.startDoc, q.err = q.processCursorArg("StartAt", docSnapshotOrFieldValues) + return q +} + +// StartAfter returns a new Query that specifies that results should start just after +// the document with the given field values. See Query.StartAt for more information. +// +// Calling StartAfter overrides a previous call to StartAt or StartAfter. +func (q Query) StartAfter(docSnapshotOrFieldValues ...interface{}) Query { + q.startBefore = false + q.startVals, q.startDoc, q.err = q.processCursorArg("StartAfter", docSnapshotOrFieldValues) + return q +} + +// EndAt returns a new Query that specifies that results should end at the +// document with the given field values. See Query.StartAt for more information. +// +// Calling EndAt overrides a previous call to EndAt or EndBefore. +func (q Query) EndAt(docSnapshotOrFieldValues ...interface{}) Query { + q.endBefore = false + q.endVals, q.endDoc, q.err = q.processCursorArg("EndAt", docSnapshotOrFieldValues) + return q +} + +// EndBefore returns a new Query that specifies that results should end just before +// the document with the given field values. See Query.StartAt for more information. +// +// Calling EndBefore overrides a previous call to EndAt or EndBefore. +func (q Query) EndBefore(docSnapshotOrFieldValues ...interface{}) Query { + q.endBefore = true + q.endVals, q.endDoc, q.err = q.processCursorArg("EndBefore", docSnapshotOrFieldValues) + return q +} + +func (q *Query) processCursorArg(name string, docSnapshotOrFieldValues []interface{}) ([]interface{}, *DocumentSnapshot, error) { + for _, e := range docSnapshotOrFieldValues { + if ds, ok := e.(*DocumentSnapshot); ok { + if len(docSnapshotOrFieldValues) == 1 { + return nil, ds, nil + } + return nil, nil, fmt.Errorf("firestore: a document snapshot must be the only argument to %s", name) + } + } + return docSnapshotOrFieldValues, nil, nil +} + +func (q Query) query() *Query { return &q } + +func (q Query) toProto() (*pb.StructuredQuery, error) { + if q.err != nil { + return nil, q.err + } + if q.collectionID == "" { + return nil, errors.New("firestore: query created without CollectionRef") + } + if q.startBefore { + if len(q.startVals) == 0 && q.startDoc == nil { + return nil, errors.New("firestore: StartAt/StartAfter must be called with at least one value") + } + } + if q.endBefore { + if len(q.endVals) == 0 && q.endDoc == nil { + return nil, errors.New("firestore: EndAt/EndBefore must be called with at least one value") + } + } + p := &pb.StructuredQuery{ + From: []*pb.StructuredQuery_CollectionSelector{{CollectionId: q.collectionID}}, + Offset: q.offset, + Limit: q.limit, + } + if len(q.selection) > 0 { + p.Select = &pb.StructuredQuery_Projection{} + for _, fp := range q.selection { + if err := fp.validate(); err != nil { + return nil, err + } + p.Select.Fields = append(p.Select.Fields, fref(fp)) + } + } + // If there is only filter, use it directly. Otherwise, construct + // a CompositeFilter. + if len(q.filters) == 1 { + pf, err := q.filters[0].toProto() + if err != nil { + return nil, err + } + p.Where = pf + } else if len(q.filters) > 1 { + cf := &pb.StructuredQuery_CompositeFilter{ + Op: pb.StructuredQuery_CompositeFilter_AND, + } + p.Where = &pb.StructuredQuery_Filter{ + FilterType: &pb.StructuredQuery_Filter_CompositeFilter{cf}, + } + for _, f := range q.filters { + pf, err := f.toProto() + if err != nil { + return nil, err + } + cf.Filters = append(cf.Filters, pf) + } + } + orders := q.orders + if q.startDoc != nil || q.endDoc != nil { + orders = q.adjustOrders() + } + for _, ord := range orders { + po, err := ord.toProto() + if err != nil { + return nil, err + } + p.OrderBy = append(p.OrderBy, po) + } + + cursor, err := q.toCursor(q.startVals, q.startDoc, q.startBefore, orders) + if err != nil { + return nil, err + } + p.StartAt = cursor + cursor, err = q.toCursor(q.endVals, q.endDoc, q.endBefore, orders) + if err != nil { + return nil, err + } + p.EndAt = cursor + return p, nil +} + +// If there is a start/end that uses a Document Snapshot, we may need to adjust the OrderBy +// clauses that the user provided: we add OrderBy(__name__) if it isn't already present, and +// we make sure we don't invalidate the original query by adding an OrderBy for inequality filters. +func (q *Query) adjustOrders() []order { + // If the user is already ordering by document ID, don't change anything. + for _, ord := range q.orders { + if ord.isDocumentID() { + return q.orders + } + } + // If there are OrderBy clauses, append an OrderBy(DocumentID), using the direction of the last OrderBy clause. + if len(q.orders) > 0 { + return append(q.copyOrders(), order{ + fieldPath: FieldPath{DocumentID}, + dir: q.orders[len(q.orders)-1].dir, + }) + } + // If there are no OrderBy clauses but there is an inequality, add an OrderBy clause + // for the field of the first inequality. + var orders []order + for _, f := range q.filters { + if f.op != "==" { + orders = []order{{fieldPath: f.fieldPath, dir: Asc}} + break + } + } + // Add an ascending OrderBy(DocumentID). + return append(orders, order{fieldPath: FieldPath{DocumentID}, dir: Asc}) +} + +func (q *Query) toCursor(fieldValues []interface{}, ds *DocumentSnapshot, before bool, orders []order) (*pb.Cursor, error) { + var vals []*pb.Value + var err error + if ds != nil { + vals, err = q.docSnapshotToCursorValues(ds, orders) + } else if len(fieldValues) != 0 { + vals, err = q.fieldValuesToCursorValues(fieldValues) + } else { + return nil, nil + } + if err != nil { + return nil, err + } + return &pb.Cursor{Values: vals, Before: before}, nil +} + +// toPositionValues converts the field values to protos. +func (q *Query) fieldValuesToCursorValues(fieldValues []interface{}) ([]*pb.Value, error) { + if len(fieldValues) != len(q.orders) { + return nil, errors.New("firestore: number of field values in StartAt/StartAfter/EndAt/EndBefore does not match number of OrderBy fields") + } + vals := make([]*pb.Value, len(fieldValues)) + var err error + for i, ord := range q.orders { + fval := fieldValues[i] + if ord.isDocumentID() { + // TODO(jba): support DocumentRefs as well as strings. + // TODO(jba): error if document ref does not belong to the right collection. + docID, ok := fval.(string) + if !ok { + return nil, fmt.Errorf("firestore: expected doc ID for DocumentID field, got %T", fval) + } + vals[i] = &pb.Value{ValueType: &pb.Value_ReferenceValue{q.collectionPath() + "/" + docID}} + } else { + var sawTransform bool + vals[i], sawTransform, err = toProtoValue(reflect.ValueOf(fval)) + if err != nil { + return nil, err + } + if sawTransform { + return nil, errors.New("firestore: transforms disallowed in query value") + } + } + } + return vals, nil +} + +func (q *Query) docSnapshotToCursorValues(ds *DocumentSnapshot, orders []order) ([]*pb.Value, error) { + // TODO(jba): error if doc snap does not belong to the right collection. + vals := make([]*pb.Value, len(orders)) + for i, ord := range orders { + if ord.isDocumentID() { + dp, qp := ds.Ref.Parent.Path, q.collectionPath() + if dp != qp { + return nil, fmt.Errorf("firestore: document snapshot for %s passed to query on %s", dp, qp) + } + vals[i] = &pb.Value{ValueType: &pb.Value_ReferenceValue{ds.Ref.Path}} + } else { + val, err := valueAtPath(ord.fieldPath, ds.proto.Fields) + if err != nil { + return nil, err + } + vals[i] = val + } + } + return vals, nil +} + +// Returns a function that compares DocumentSnapshots according to q's ordering. +func (q Query) compareFunc() func(d1, d2 *DocumentSnapshot) (int, error) { + // Add implicit sorting by name, using the last specified direction. + lastDir := Asc + if len(q.orders) > 0 { + lastDir = q.orders[len(q.orders)-1].dir + } + orders := append(q.copyOrders(), order{[]string{DocumentID}, lastDir}) + return func(d1, d2 *DocumentSnapshot) (int, error) { + for _, ord := range orders { + var cmp int + if len(ord.fieldPath) == 1 && ord.fieldPath[0] == DocumentID { + cmp = compareReferences(d1.Ref.Path, d2.Ref.Path) + } else { + v1, err := valueAtPath(ord.fieldPath, d1.proto.Fields) + if err != nil { + return 0, err + } + v2, err := valueAtPath(ord.fieldPath, d2.proto.Fields) + if err != nil { + return 0, err + } + cmp = compareValues(v1, v2) + } + if cmp != 0 { + if ord.dir == Desc { + cmp = -cmp + } + return cmp, nil + } + } + return 0, nil + } +} + +type filter struct { + fieldPath FieldPath + op string + value interface{} +} + +func (f filter) toProto() (*pb.StructuredQuery_Filter, error) { + if err := f.fieldPath.validate(); err != nil { + return nil, err + } + if uop, ok := unaryOpFor(f.value); ok { + if f.op != "==" { + return nil, fmt.Errorf("firestore: must use '==' when comparing %v", f.value) + } + return &pb.StructuredQuery_Filter{ + FilterType: &pb.StructuredQuery_Filter_UnaryFilter{ + UnaryFilter: &pb.StructuredQuery_UnaryFilter{ + OperandType: &pb.StructuredQuery_UnaryFilter_Field{ + Field: fref(f.fieldPath), + }, + Op: uop, + }, + }, + }, nil + } + var op pb.StructuredQuery_FieldFilter_Operator + switch f.op { + case "<": + op = pb.StructuredQuery_FieldFilter_LESS_THAN + case "<=": + op = pb.StructuredQuery_FieldFilter_LESS_THAN_OR_EQUAL + case ">": + op = pb.StructuredQuery_FieldFilter_GREATER_THAN + case ">=": + op = pb.StructuredQuery_FieldFilter_GREATER_THAN_OR_EQUAL + case "==": + op = pb.StructuredQuery_FieldFilter_EQUAL + case "array-contains": + op = pb.StructuredQuery_FieldFilter_ARRAY_CONTAINS + default: + return nil, fmt.Errorf("firestore: invalid operator %q", f.op) + } + val, sawTransform, err := toProtoValue(reflect.ValueOf(f.value)) + if err != nil { + return nil, err + } + if sawTransform { + return nil, errors.New("firestore: transforms disallowed in query value") + } + return &pb.StructuredQuery_Filter{ + FilterType: &pb.StructuredQuery_Filter_FieldFilter{ + FieldFilter: &pb.StructuredQuery_FieldFilter{ + Field: fref(f.fieldPath), + Op: op, + Value: val, + }, + }, + }, nil +} + +func unaryOpFor(value interface{}) (pb.StructuredQuery_UnaryFilter_Operator, bool) { + switch { + case value == nil: + return pb.StructuredQuery_UnaryFilter_IS_NULL, true + case isNaN(value): + return pb.StructuredQuery_UnaryFilter_IS_NAN, true + default: + return pb.StructuredQuery_UnaryFilter_OPERATOR_UNSPECIFIED, false + } +} + +func isNaN(x interface{}) bool { + switch x := x.(type) { + case float32: + return math.IsNaN(float64(x)) + case float64: + return math.IsNaN(x) + default: + return false + } +} + +type order struct { + fieldPath FieldPath + dir Direction +} + +func (r order) isDocumentID() bool { + return len(r.fieldPath) == 1 && r.fieldPath[0] == DocumentID +} + +func (r order) toProto() (*pb.StructuredQuery_Order, error) { + if err := r.fieldPath.validate(); err != nil { + return nil, err + } + return &pb.StructuredQuery_Order{ + Field: fref(r.fieldPath), + Direction: pb.StructuredQuery_Direction(r.dir), + }, nil +} + +func fref(fp FieldPath) *pb.StructuredQuery_FieldReference { + return &pb.StructuredQuery_FieldReference{FieldPath: fp.toServiceFieldPath()} +} + +func trunc32(i int) int32 { + if i > math.MaxInt32 { + i = math.MaxInt32 + } + return int32(i) +} + +// Documents returns an iterator over the query's resulting documents. +func (q Query) Documents(ctx context.Context) *DocumentIterator { + return &DocumentIterator{ + iter: newQueryDocumentIterator(withResourceHeader(ctx, q.c.path()), &q, nil), + err: checkTransaction(ctx), + } +} + +// DocumentIterator is an iterator over documents returned by a query. +type DocumentIterator struct { + iter docIterator + err error +} + +// Unexported interface so we can have two different kinds of DocumentIterator: one +// for straight queries, and one for query snapshots. We do it this way instead of +// making DocumentIterator an interface because in the client libraries, iterators are +// always concrete types, and the fact that this one has two different implementations +// is an internal detail. +type docIterator interface { + next() (*DocumentSnapshot, error) + stop() +} + +// Next returns the next result. Its second return value is iterator.Done if there +// are no more results. Once Next returns Done, all subsequent calls will return +// Done. +func (it *DocumentIterator) Next() (*DocumentSnapshot, error) { + if it.err != nil { + return nil, it.err + } + ds, err := it.iter.next() + if err != nil { + it.err = err + } + return ds, err +} + +// Stop stops the iterator, freeing its resources. +// Always call Stop when you are done with a DocumentIterator. +// It is not safe to call Stop concurrently with Next. +func (it *DocumentIterator) Stop() { + if it.iter != nil { // possible in error cases + it.iter.stop() + } + if it.err == nil { + it.err = iterator.Done + } +} + +// GetAll returns all the documents remaining from the iterator. +// It is not necessary to call Stop on the iterator after calling GetAll. +func (it *DocumentIterator) GetAll() ([]*DocumentSnapshot, error) { + defer it.Stop() + var docs []*DocumentSnapshot + for { + doc, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + return nil, err + } + docs = append(docs, doc) + } + return docs, nil +} + +type queryDocumentIterator struct { + ctx context.Context + cancel func() + q *Query + tid []byte // transaction ID, if any + streamClient pb.Firestore_RunQueryClient +} + +func newQueryDocumentIterator(ctx context.Context, q *Query, tid []byte) *queryDocumentIterator { + ctx, cancel := context.WithCancel(ctx) + return &queryDocumentIterator{ + ctx: ctx, + cancel: cancel, + q: q, + tid: tid, + } +} + +func (it *queryDocumentIterator) next() (*DocumentSnapshot, error) { + client := it.q.c + if it.streamClient == nil { + sq, err := it.q.toProto() + if err != nil { + return nil, err + } + req := &pb.RunQueryRequest{ + Parent: it.q.parentPath, + QueryType: &pb.RunQueryRequest_StructuredQuery{sq}, + } + if it.tid != nil { + req.ConsistencySelector = &pb.RunQueryRequest_Transaction{it.tid} + } + it.streamClient, err = client.c.RunQuery(it.ctx, req) + if err != nil { + return nil, err + } + } + var res *pb.RunQueryResponse + var err error + for { + res, err = it.streamClient.Recv() + if err == io.EOF { + return nil, iterator.Done + } + if err != nil { + return nil, err + } + if res.Document != nil { + break + } + // No document => partial progress; keep receiving. + } + docRef, err := pathToDoc(res.Document.Name, client) + if err != nil { + return nil, err + } + doc, err := newDocumentSnapshot(docRef, res.Document, client, res.ReadTime) + if err != nil { + return nil, err + } + return doc, nil +} + +func (it *queryDocumentIterator) stop() { + it.cancel() +} + +// Snapshots returns an iterator over snapshots of the query. Each time the query +// results change, a new snapshot will be generated. +func (q Query) Snapshots(ctx context.Context) *QuerySnapshotIterator { + ws, err := newWatchStreamForQuery(ctx, q) + if err != nil { + return &QuerySnapshotIterator{err: err} + } + return &QuerySnapshotIterator{ + Query: q, + ws: ws, + } +} + +// QuerySnapshotIterator is an iterator over snapshots of a query. +// Call Next on the iterator to get a snapshot of the query's results each time they change. +// Call Stop on the iterator when done. +// +// For an example, see Query.Snapshots. +type QuerySnapshotIterator struct { + // The Query used to construct this iterator. + Query Query + + ws *watchStream + err error +} + +// Next blocks until the query's results change, then returns a QuerySnapshot for +// the current results. +// +// Next never returns iterator.Done unless it is called after Stop. +func (it *QuerySnapshotIterator) Next() (*QuerySnapshot, error) { + if it.err != nil { + return nil, it.err + } + btree, changes, readTime, err := it.ws.nextSnapshot() + if err != nil { + if err == io.EOF { + err = iterator.Done + } + it.err = err + return nil, it.err + } + return &QuerySnapshot{ + Documents: &DocumentIterator{ + iter: (*btreeDocumentIterator)(btree.BeforeIndex(0)), + }, + Size: btree.Len(), + Changes: changes, + ReadTime: readTime, + }, nil +} + +// Stop stops receiving snapshots. You should always call Stop when you are done with +// a QuerySnapshotIterator, to free up resources. It is not safe to call Stop +// concurrently with Next. +func (it *QuerySnapshotIterator) Stop() { + it.ws.stop() +} + +// A QuerySnapshot is a snapshot of query results. It is returned by +// QuerySnapshotIterator.Next whenever the results of a query change. +type QuerySnapshot struct { + // An iterator over the query results. + // It is not necessary to call Stop on this iterator. + Documents *DocumentIterator + + // The number of results in this snapshot. + Size int + + // The changes since the previous snapshot. + Changes []DocumentChange + + // The time at which this snapshot was obtained from Firestore. + ReadTime time.Time +} + +type btreeDocumentIterator btree.Iterator + +func (it *btreeDocumentIterator) next() (*DocumentSnapshot, error) { + if !(*btree.Iterator)(it).Next() { + return nil, iterator.Done + } + return it.Key.(*DocumentSnapshot), nil +} + +func (*btreeDocumentIterator) stop() {} diff --git a/vendor/cloud.google.com/go/firestore/query_test.go b/vendor/cloud.google.com/go/firestore/query_test.go new file mode 100644 index 00000000..4c25d95e --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/query_test.go @@ -0,0 +1,717 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "math" + "sort" + "testing" + + "cloud.google.com/go/internal/pretty" + tspb "github.com/golang/protobuf/ptypes/timestamp" + "github.com/golang/protobuf/ptypes/wrappers" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +func TestFilterToProto(t *testing.T) { + for _, test := range []struct { + in filter + want *pb.StructuredQuery_Filter + }{ + { + filter{[]string{"a"}, ">", 1}, + &pb.StructuredQuery_Filter{FilterType: &pb.StructuredQuery_Filter_FieldFilter{ + FieldFilter: &pb.StructuredQuery_FieldFilter{ + Field: &pb.StructuredQuery_FieldReference{FieldPath: "a"}, + Op: pb.StructuredQuery_FieldFilter_GREATER_THAN, + Value: intval(1), + }, + }}, + }, + { + filter{[]string{"a"}, "==", nil}, + &pb.StructuredQuery_Filter{FilterType: &pb.StructuredQuery_Filter_UnaryFilter{ + UnaryFilter: &pb.StructuredQuery_UnaryFilter{ + OperandType: &pb.StructuredQuery_UnaryFilter_Field{ + Field: &pb.StructuredQuery_FieldReference{FieldPath: "a"}, + }, + Op: pb.StructuredQuery_UnaryFilter_IS_NULL, + }, + }}, + }, + { + filter{[]string{"a"}, "==", math.NaN()}, + &pb.StructuredQuery_Filter{FilterType: &pb.StructuredQuery_Filter_UnaryFilter{ + UnaryFilter: &pb.StructuredQuery_UnaryFilter{ + OperandType: &pb.StructuredQuery_UnaryFilter_Field{ + Field: &pb.StructuredQuery_FieldReference{FieldPath: "a"}, + }, + Op: pb.StructuredQuery_UnaryFilter_IS_NAN, + }, + }}, + }, + } { + got, err := test.in.toProto() + if err != nil { + t.Fatal(err) + } + if !testEqual(got, test.want) { + t.Errorf("%+v:\ngot\n%v\nwant\n%v", test.in, pretty.Value(got), pretty.Value(test.want)) + } + } +} + +func TestQueryToProto(t *testing.T) { + filtr := func(path []string, op string, val interface{}) *pb.StructuredQuery_Filter { + f, err := filter{path, op, val}.toProto() + if err != nil { + t.Fatal(err) + } + return f + } + + c := &Client{projectID: "P", databaseID: "DB"} + coll := c.Collection("C") + q := coll.Query + docsnap := &DocumentSnapshot{ + Ref: coll.Doc("D"), + proto: &pb.Document{ + Fields: map[string]*pb.Value{"a": intval(7), "b": intval(8), "c": arrayval(intval(1), intval(2))}, + }, + } + for _, test := range []struct { + desc string + in Query + want *pb.StructuredQuery + }{ + { + desc: "q.Select()", + in: q.Select(), + want: &pb.StructuredQuery{ + Select: &pb.StructuredQuery_Projection{ + Fields: []*pb.StructuredQuery_FieldReference{fref1("__name__")}, + }, + }, + }, + { + desc: `q.Select("a", "b")`, + in: q.Select("a", "b"), + want: &pb.StructuredQuery{ + Select: &pb.StructuredQuery_Projection{ + Fields: []*pb.StructuredQuery_FieldReference{fref1("a"), fref1("b")}, + }, + }, + }, + { + desc: `q.Select("a", "b").Select("c")`, + in: q.Select("a", "b").Select("c"), // last wins + want: &pb.StructuredQuery{ + Select: &pb.StructuredQuery_Projection{ + Fields: []*pb.StructuredQuery_FieldReference{fref1("c")}, + }, + }, + }, + { + desc: `q.SelectPaths([]string{"*"}, []string{"/"})`, + in: q.SelectPaths([]string{"*"}, []string{"/"}), + want: &pb.StructuredQuery{ + Select: &pb.StructuredQuery_Projection{ + Fields: []*pb.StructuredQuery_FieldReference{fref1("*"), fref1("/")}, + }, + }, + }, + { + desc: `q.Where("a", ">", 5)`, + in: q.Where("a", ">", 5), + want: &pb.StructuredQuery{Where: filtr([]string{"a"}, ">", 5)}, + }, + { + desc: `q.Where("a", "==", NaN)`, + in: q.Where("a", "==", float32(math.NaN())), + want: &pb.StructuredQuery{Where: filtr([]string{"a"}, "==", math.NaN())}, + }, + { + desc: `q.Where("c", "array-contains", 1)`, + in: q.Where("c", "array-contains", 1), + want: &pb.StructuredQuery{Where: filtr([]string{"c"}, "array-contains", 1)}, + }, + { + desc: `q.Where("a", ">", 5).Where("b", "<", "foo")`, + in: q.Where("a", ">", 5).Where("b", "<", "foo"), + want: &pb.StructuredQuery{ + Where: &pb.StructuredQuery_Filter{ + FilterType: &pb.StructuredQuery_Filter_CompositeFilter{ + &pb.StructuredQuery_CompositeFilter{ + Op: pb.StructuredQuery_CompositeFilter_AND, + Filters: []*pb.StructuredQuery_Filter{ + filtr([]string{"a"}, ">", 5), filtr([]string{"b"}, "<", "foo"), + }, + }, + }, + }, + }, + }, + { + desc: ` q.WherePath([]string{"/", "*"}, ">", 5)`, + in: q.WherePath([]string{"/", "*"}, ">", 5), + want: &pb.StructuredQuery{Where: filtr([]string{"/", "*"}, ">", 5)}, + }, + { + desc: `q.OrderBy("b", Asc).OrderBy("a", Desc).OrderByPath([]string{"~"}, Asc)`, + in: q.OrderBy("b", Asc).OrderBy("a", Desc).OrderByPath([]string{"~"}, Asc), + want: &pb.StructuredQuery{ + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("b"), Direction: pb.StructuredQuery_ASCENDING}, + {Field: fref1("a"), Direction: pb.StructuredQuery_DESCENDING}, + {Field: fref1("~"), Direction: pb.StructuredQuery_ASCENDING}, + }, + }, + }, + { + desc: `q.Offset(2).Limit(3)`, + in: q.Offset(2).Limit(3), + want: &pb.StructuredQuery{ + Offset: 2, + Limit: &wrappers.Int32Value{Value: 3}, + }, + }, + { + desc: `q.Offset(2).Limit(3).Limit(4).Offset(5)`, + in: q.Offset(2).Limit(3).Limit(4).Offset(5), // last wins + want: &pb.StructuredQuery{ + Offset: 5, + Limit: &wrappers.Int32Value{Value: 4}, + }, + }, + { + desc: `q.OrderBy("a", Asc).StartAt(7).EndBefore(9)`, + in: q.OrderBy("a", Asc).StartAt(7).EndBefore(9), + want: &pb.StructuredQuery{ + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("a"), Direction: pb.StructuredQuery_ASCENDING}, + }, + StartAt: &pb.Cursor{ + Values: []*pb.Value{intval(7)}, + Before: true, + }, + EndAt: &pb.Cursor{ + Values: []*pb.Value{intval(9)}, + Before: true, + }, + }, + }, + { + desc: `q.OrderBy("a", Asc).StartAt(7).EndAt(9)`, + in: q.OrderBy("a", Asc).StartAt(7).EndAt(9), + want: &pb.StructuredQuery{ + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("a"), Direction: pb.StructuredQuery_ASCENDING}, + }, + StartAt: &pb.Cursor{ + Values: []*pb.Value{intval(7)}, + Before: true, + }, + EndAt: &pb.Cursor{ + Values: []*pb.Value{intval(9)}, + Before: false, + }, + }, + }, + { + desc: `q.OrderBy("a", Asc).StartAfter(7).EndAt(9)`, + in: q.OrderBy("a", Asc).StartAfter(7).EndAt(9), + want: &pb.StructuredQuery{ + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("a"), Direction: pb.StructuredQuery_ASCENDING}, + }, + StartAt: &pb.Cursor{ + Values: []*pb.Value{intval(7)}, + Before: false, + }, + EndAt: &pb.Cursor{ + Values: []*pb.Value{intval(9)}, + Before: false, + }, + }, + }, + { + desc: `q.OrderBy(DocumentID, Asc).StartAfter("foo").EndBefore("bar")`, + in: q.OrderBy(DocumentID, Asc).StartAfter("foo").EndBefore("bar"), + want: &pb.StructuredQuery{ + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("__name__"), Direction: pb.StructuredQuery_ASCENDING}, + }, + StartAt: &pb.Cursor{ + Values: []*pb.Value{refval(coll.parentPath + "/documents/C/foo")}, + Before: false, + }, + EndAt: &pb.Cursor{ + Values: []*pb.Value{refval(coll.parentPath + "/documents/C/bar")}, + Before: true, + }, + }, + }, + { + desc: `q.OrderBy("a", Asc).OrderBy("b", Desc).StartAfter(7, 8).EndAt(9, 10)`, + in: q.OrderBy("a", Asc).OrderBy("b", Desc).StartAfter(7, 8).EndAt(9, 10), + want: &pb.StructuredQuery{ + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("a"), Direction: pb.StructuredQuery_ASCENDING}, + {Field: fref1("b"), Direction: pb.StructuredQuery_DESCENDING}, + }, + StartAt: &pb.Cursor{ + Values: []*pb.Value{intval(7), intval(8)}, + Before: false, + }, + EndAt: &pb.Cursor{ + Values: []*pb.Value{intval(9), intval(10)}, + Before: false, + }, + }, + }, + { + // last of StartAt/After wins, same for End + desc: `q.OrderBy("a", Asc).StartAfter(1).StartAt(2).EndAt(3).EndBefore(4)`, + in: q.OrderBy("a", Asc). + StartAfter(1).StartAt(2). + EndAt(3).EndBefore(4), + want: &pb.StructuredQuery{ + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("a"), Direction: pb.StructuredQuery_ASCENDING}, + }, + StartAt: &pb.Cursor{ + Values: []*pb.Value{intval(2)}, + Before: true, + }, + EndAt: &pb.Cursor{ + Values: []*pb.Value{intval(4)}, + Before: true, + }, + }, + }, + // Start/End with DocumentSnapshot + // These tests are from the "Document Snapshot Cursors" doc. + { + desc: `q.StartAt(docsnap)`, + in: q.StartAt(docsnap), + want: &pb.StructuredQuery{ + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("__name__"), Direction: pb.StructuredQuery_ASCENDING}, + }, + StartAt: &pb.Cursor{ + Values: []*pb.Value{refval(coll.parentPath + "/documents/C/D")}, + Before: true, + }, + }, + }, + { + desc: `q.OrderBy("a", Asc).StartAt(docsnap)`, + in: q.OrderBy("a", Asc).StartAt(docsnap), + want: &pb.StructuredQuery{ + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("a"), Direction: pb.StructuredQuery_ASCENDING}, + {Field: fref1("__name__"), Direction: pb.StructuredQuery_ASCENDING}, + }, + StartAt: &pb.Cursor{ + Values: []*pb.Value{intval(7), refval(coll.parentPath + "/documents/C/D")}, + Before: true, + }, + }, + }, + + { + desc: `q.OrderBy("a", Desc).StartAt(docsnap)`, + in: q.OrderBy("a", Desc).StartAt(docsnap), + want: &pb.StructuredQuery{ + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("a"), Direction: pb.StructuredQuery_DESCENDING}, + {Field: fref1("__name__"), Direction: pb.StructuredQuery_DESCENDING}, + }, + StartAt: &pb.Cursor{ + Values: []*pb.Value{intval(7), refval(coll.parentPath + "/documents/C/D")}, + Before: true, + }, + }, + }, + { + desc: `q.OrderBy("a", Desc).OrderBy("b", Asc).StartAt(docsnap)`, + in: q.OrderBy("a", Desc).OrderBy("b", Asc).StartAt(docsnap), + want: &pb.StructuredQuery{ + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("a"), Direction: pb.StructuredQuery_DESCENDING}, + {Field: fref1("b"), Direction: pb.StructuredQuery_ASCENDING}, + {Field: fref1("__name__"), Direction: pb.StructuredQuery_ASCENDING}, + }, + StartAt: &pb.Cursor{ + Values: []*pb.Value{intval(7), intval(8), refval(coll.parentPath + "/documents/C/D")}, + Before: true, + }, + }, + }, + { + desc: `q.Where("a", "==", 3).StartAt(docsnap)`, + in: q.Where("a", "==", 3).StartAt(docsnap), + want: &pb.StructuredQuery{ + Where: filtr([]string{"a"}, "==", 3), + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("__name__"), Direction: pb.StructuredQuery_ASCENDING}, + }, + StartAt: &pb.Cursor{ + Values: []*pb.Value{refval(coll.parentPath + "/documents/C/D")}, + Before: true, + }, + }, + }, + { + desc: `q.Where("a", "<", 3).StartAt(docsnap)`, + in: q.Where("a", "<", 3).StartAt(docsnap), + want: &pb.StructuredQuery{ + Where: filtr([]string{"a"}, "<", 3), + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("a"), Direction: pb.StructuredQuery_ASCENDING}, + {Field: fref1("__name__"), Direction: pb.StructuredQuery_ASCENDING}, + }, + StartAt: &pb.Cursor{ + Values: []*pb.Value{intval(7), refval(coll.parentPath + "/documents/C/D")}, + Before: true, + }, + }, + }, + { + desc: `q.Where("b", "==", 1).Where("a", "<", 3).StartAt(docsnap)`, + in: q.Where("b", "==", 1).Where("a", "<", 3).StartAt(docsnap), + want: &pb.StructuredQuery{ + Where: &pb.StructuredQuery_Filter{ + FilterType: &pb.StructuredQuery_Filter_CompositeFilter{ + &pb.StructuredQuery_CompositeFilter{ + Op: pb.StructuredQuery_CompositeFilter_AND, + Filters: []*pb.StructuredQuery_Filter{ + filtr([]string{"b"}, "==", 1), + filtr([]string{"a"}, "<", 3), + }, + }, + }, + }, + OrderBy: []*pb.StructuredQuery_Order{ + {Field: fref1("a"), Direction: pb.StructuredQuery_ASCENDING}, + {Field: fref1("__name__"), Direction: pb.StructuredQuery_ASCENDING}, + }, + StartAt: &pb.Cursor{ + Values: []*pb.Value{intval(7), refval(coll.parentPath + "/documents/C/D")}, + Before: true, + }, + }, + }, + } { + got, err := test.in.toProto() + if err != nil { + t.Errorf("%s: %v", test.desc, err) + continue + } + test.want.From = []*pb.StructuredQuery_CollectionSelector{{CollectionId: "C"}} + if !testEqual(got, test.want) { + t.Errorf("%s:\ngot\n%v\nwant\n%v", test.desc, pretty.Value(got), pretty.Value(test.want)) + } + } +} + +func fref1(s string) *pb.StructuredQuery_FieldReference { + return fref([]string{s}) +} + +func TestQueryToProtoErrors(t *testing.T) { + st := map[string]interface{}{"a": ServerTimestamp} + del := map[string]interface{}{"a": Delete} + c := &Client{projectID: "P", databaseID: "DB"} + coll := c.Collection("C") + docsnap := &DocumentSnapshot{ + Ref: coll.Doc("D"), + proto: &pb.Document{ + Fields: map[string]*pb.Value{"a": intval(7)}, + }, + } + q := coll.Query + for i, query := range []Query{ + {}, // no collection ID + q.Where("x", "!=", 1), // invalid operator + q.Where("~", ">", 1), // invalid path + q.WherePath([]string{"*", ""}, ">", 1), // invalid path + q.StartAt(1), // no OrderBy + q.StartAt(2).OrderBy("x", Asc).OrderBy("y", Desc), // wrong # OrderBy + q.Select("*"), // invalid path + q.SelectPaths([]string{"/", "", "~"}), // invalid path + q.OrderBy("[", Asc), // invalid path + q.OrderByPath([]string{""}, Desc), // invalid path + q.Where("x", "==", st), // ServerTimestamp in filter + q.OrderBy("a", Asc).StartAt(st), // ServerTimestamp in Start + q.OrderBy("a", Asc).EndAt(st), // ServerTimestamp in End + q.Where("x", "==", del), // Delete in filter + q.OrderBy("a", Asc).StartAt(del), // Delete in Start + q.OrderBy("a", Asc).EndAt(del), // Delete in End + q.OrderBy(DocumentID, Asc).StartAt(7), // wrong type for __name__ + q.OrderBy(DocumentID, Asc).EndAt(7), // wrong type for __name__ + q.OrderBy("b", Asc).StartAt(docsnap), // doc snapshot does not have order-by field + q.StartAt(docsnap).EndAt("x"), // mixed doc snapshot and fields + q.StartAfter("x").EndBefore(docsnap), // mixed doc snapshot and fields + } { + _, err := query.toProto() + if err == nil { + t.Errorf("query %d \"%+v\": got nil, want error", i, query) + } + } +} + +func TestQueryMethodsDoNotModifyReceiver(t *testing.T) { + var empty Query + + q := Query{} + _ = q.Select("a", "b") + if !testEqual(q, empty) { + t.Errorf("got %+v, want empty", q) + } + + q = Query{} + q1 := q.Where("a", ">", 3) + if !testEqual(q, empty) { + t.Errorf("got %+v, want empty", q) + } + // Extra check because Where appends to a slice. + q1before := q.Where("a", ">", 3) // same as q1 + _ = q1.Where("b", "<", "foo") + if !testEqual(q1, q1before) { + t.Errorf("got %+v, want %+v", q1, q1before) + } + + q = Query{} + q1 = q.OrderBy("a", Asc) + if !testEqual(q, empty) { + t.Errorf("got %+v, want empty", q) + } + // Extra check because Where appends to a slice. + q1before = q.OrderBy("a", Asc) // same as q1 + _ = q1.OrderBy("b", Desc) + if !testEqual(q1, q1before) { + t.Errorf("got %+v, want %+v", q1, q1before) + } + + q = Query{} + _ = q.Offset(5) + if !testEqual(q, empty) { + t.Errorf("got %+v, want empty", q) + } + + q = Query{} + _ = q.Limit(5) + if !testEqual(q, empty) { + t.Errorf("got %+v, want empty", q) + } + + q = Query{} + _ = q.StartAt(5) + if !testEqual(q, empty) { + t.Errorf("got %+v, want empty", q) + } + + q = Query{} + _ = q.StartAfter(5) + if !testEqual(q, empty) { + t.Errorf("got %+v, want empty", q) + } + + q = Query{} + _ = q.EndAt(5) + if !testEqual(q, empty) { + t.Errorf("got %+v, want empty", q) + } + + q = Query{} + _ = q.EndBefore(5) + if !testEqual(q, empty) { + t.Errorf("got %+v, want empty", q) + } +} + +func TestQueryFromCollectionRef(t *testing.T) { + c := &Client{} + coll := c.Collection("C") + got := coll.Select("x").Offset(8) + want := Query{ + c: c, + parentPath: c.path(), + collectionID: "C", + selection: []FieldPath{{"x"}}, + offset: 8, + } + if !testEqual(got, want) { + t.Fatalf("got %+v, want %+v", got, want) + } +} + +func TestQueryGetAll(t *testing.T) { + // This implicitly tests DocumentIterator as well. + const dbPath = "projects/projectID/databases/(default)" + ctx := context.Background() + c, srv := newMock(t) + docNames := []string{"C/a", "C/b"} + wantPBDocs := []*pb.Document{ + { + Name: dbPath + "/documents/" + docNames[0], + CreateTime: aTimestamp, + UpdateTime: aTimestamp, + Fields: map[string]*pb.Value{"f": intval(2)}, + }, + { + Name: dbPath + "/documents/" + docNames[1], + CreateTime: aTimestamp2, + UpdateTime: aTimestamp3, + Fields: map[string]*pb.Value{"f": intval(1)}, + }, + } + wantReadTimes := []*tspb.Timestamp{aTimestamp, aTimestamp2} + srv.addRPC(nil, []interface{}{ + &pb.RunQueryResponse{Document: wantPBDocs[0], ReadTime: aTimestamp}, + &pb.RunQueryResponse{Document: wantPBDocs[1], ReadTime: aTimestamp2}, + }) + gotDocs, err := c.Collection("C").Documents(ctx).GetAll() + if err != nil { + t.Fatal(err) + } + if got, want := len(gotDocs), len(wantPBDocs); got != want { + t.Errorf("got %d docs, wanted %d", got, want) + } + for i, got := range gotDocs { + want, err := newDocumentSnapshot(c.Doc(docNames[i]), wantPBDocs[i], c, wantReadTimes[i]) + if err != nil { + t.Fatal(err) + } + if !testEqual(got, want) { + // avoid writing a cycle + got.c = nil + want.c = nil + t.Errorf("#%d: got %+v, want %+v", i, pretty.Value(got), pretty.Value(want)) + } + } +} + +func TestQueryCompareFunc(t *testing.T) { + mv := func(fields ...interface{}) map[string]*pb.Value { + m := map[string]*pb.Value{} + for i := 0; i < len(fields); i += 2 { + m[fields[i].(string)] = fields[i+1].(*pb.Value) + } + return m + } + snap := func(ref *DocumentRef, fields map[string]*pb.Value) *DocumentSnapshot { + return &DocumentSnapshot{Ref: ref, proto: &pb.Document{Fields: fields}} + } + + c := &Client{} + coll := c.Collection("C") + doc1 := coll.Doc("doc1") + doc2 := coll.Doc("doc2") + doc3 := coll.Doc("doc3") + doc4 := coll.Doc("doc4") + for _, test := range []struct { + q Query + in []*DocumentSnapshot + want []*DocumentSnapshot + }{ + { + q: coll.OrderBy("foo", Asc), + in: []*DocumentSnapshot{ + snap(doc3, mv("foo", intval(2))), + snap(doc4, mv("foo", intval(1))), + snap(doc2, mv("foo", intval(2))), + }, + want: []*DocumentSnapshot{ + snap(doc4, mv("foo", intval(1))), + snap(doc2, mv("foo", intval(2))), + snap(doc3, mv("foo", intval(2))), + }, + }, + { + q: coll.OrderBy("foo", Desc), + in: []*DocumentSnapshot{ + snap(doc3, mv("foo", intval(2))), + snap(doc4, mv("foo", intval(1))), + snap(doc2, mv("foo", intval(2))), + }, + want: []*DocumentSnapshot{ + snap(doc3, mv("foo", intval(2))), + snap(doc2, mv("foo", intval(2))), + snap(doc4, mv("foo", intval(1))), + }, + }, + { + q: coll.OrderBy("foo.bar", Asc), + in: []*DocumentSnapshot{ + snap(doc1, mv("foo", mapval(mv("bar", intval(1))))), + snap(doc2, mv("foo", mapval(mv("bar", intval(2))))), + snap(doc3, mv("foo", mapval(mv("bar", intval(2))))), + }, + want: []*DocumentSnapshot{ + snap(doc1, mv("foo", mapval(mv("bar", intval(1))))), + snap(doc2, mv("foo", mapval(mv("bar", intval(2))))), + snap(doc3, mv("foo", mapval(mv("bar", intval(2))))), + }, + }, + { + q: coll.OrderBy("foo.bar", Desc), + in: []*DocumentSnapshot{ + snap(doc1, mv("foo", mapval(mv("bar", intval(1))))), + snap(doc2, mv("foo", mapval(mv("bar", intval(2))))), + snap(doc3, mv("foo", mapval(mv("bar", intval(2))))), + }, + want: []*DocumentSnapshot{ + snap(doc3, mv("foo", mapval(mv("bar", intval(2))))), + snap(doc2, mv("foo", mapval(mv("bar", intval(2))))), + snap(doc1, mv("foo", mapval(mv("bar", intval(1))))), + }, + }, + } { + got := append([]*DocumentSnapshot(nil), test.in...) + sort.Sort(byQuery{test.q.compareFunc(), got}) + if diff := testDiff(got, test.want); diff != "" { + t.Errorf("%+v: %s", test.q, diff) + } + } + + // Want error on missing field. + q := coll.OrderBy("bar", Asc) + if q.err != nil { + t.Fatalf("bad query: %v", q.err) + } + cf := q.compareFunc() + s := snap(doc1, mv("foo", intval(1))) + if _, err := cf(s, s); err == nil { + t.Error("got nil, want error") + } +} + +type byQuery struct { + compare func(d1, d2 *DocumentSnapshot) (int, error) + docs []*DocumentSnapshot +} + +func (b byQuery) Len() int { return len(b.docs) } +func (b byQuery) Swap(i, j int) { b.docs[i], b.docs[j] = b.docs[j], b.docs[i] } +func (b byQuery) Less(i, j int) bool { + c, err := b.compare(b.docs[i], b.docs[j]) + if err != nil { + panic(err) + } + return c < 0 +} diff --git a/vendor/cloud.google.com/go/firestore/testdata/VERSION b/vendor/cloud.google.com/go/firestore/testdata/VERSION new file mode 100644 index 00000000..124b0049 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/VERSION @@ -0,0 +1 @@ +SHA1(/usr/local/google/home/jba/go/src/github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/testdata/test-suite.binproto)= fe95bb92912502ec3122c93ef687906911651f21 diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-all-transforms.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-all-transforms.textproto new file mode 100644 index 00000000..bbdf19e4 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-all-transforms.textproto @@ -0,0 +1,64 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can be created with any amount of transforms. + +description: "create: all transforms in a single call" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": \"ServerTimestamp\", \"c\": [\"ArrayUnion\", 1, 2, 3], \"d\": [\"ArrayRemove\", 4, 5, 6]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + current_document: < + exists: false + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + field_transforms: < + field_path: "c" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + field_transforms: < + field_path: "d" + remove_all_from_array: < + values: < + integer_value: 4 + > + values: < + integer_value: 5 + > + values: < + integer_value: 6 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-multi.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-multi.textproto new file mode 100644 index 00000000..f80d65b2 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-multi.textproto @@ -0,0 +1,61 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can have more than one ArrayRemove field. Since all the ArrayRemove +# fields are removed, the only field in the update is "a". + +description: "create: multiple ArrayRemove fields" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": [\"ArrayRemove\", 1, 2, 3], \"c\": {\"d\": [\"ArrayRemove\", 4, 5, 6]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + current_document: < + exists: false + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + field_transforms: < + field_path: "c.d" + remove_all_from_array: < + values: < + integer_value: 4 + > + values: < + integer_value: 5 + > + values: < + integer_value: 6 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-nested.textproto new file mode 100644 index 00000000..97756c30 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-nested.textproto @@ -0,0 +1,48 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# An ArrayRemove value can occur at any depth. In this case, the transform applies +# to the field path "b.c". Since "c" is removed from the update, "b" becomes +# empty, so it is also removed from the update. + +description: "create: nested ArrayRemove field" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": {\"c\": [\"ArrayRemove\", 1, 2, 3]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + current_document: < + exists: false + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b.c" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-noarray-nested.textproto new file mode 100644 index 00000000..4ec0cb3b --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-noarray-nested.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# There cannot be an array value anywhere on the path from the document root to +# the ArrayRemove. Firestore transforms don't support array indexing. + +description: "create: ArrayRemove cannot be anywhere inside an array value" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, {\"b\": [\"ArrayRemove\", 1, 2, 3]}]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-noarray.textproto new file mode 100644 index 00000000..969b8d9d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-noarray.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# ArrayRemove must be the value of a field. Firestore transforms don't support +# array indexing. + +description: "create: ArrayRemove cannot be in an array value" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2, [\"ArrayRemove\", 1, 2, 3]]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-with-st.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-with-st.textproto new file mode 100644 index 00000000..b6ea3224 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove-with-st.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The ServerTimestamp sentinel must be the value of a field. It may not appear in +# an ArrayUnion. + +description: "create: The ServerTimestamp sentinel cannot be in an ArrayUnion" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [\"ArrayRemove\", 1, \"ServerTimestamp\", 3]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove.textproto new file mode 100644 index 00000000..e8e4bb39 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-arrayremove.textproto @@ -0,0 +1,47 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A key with ArrayRemove is removed from the data in the update operation. Instead +# it appears in a separate Transform operation. + +description: "create: ArrayRemove with data" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": [\"ArrayRemove\", 1, 2, 3]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + current_document: < + exists: false + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-multi.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-multi.textproto new file mode 100644 index 00000000..ec3cb72f --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-multi.textproto @@ -0,0 +1,61 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can have more than one ArrayUnion field. Since all the ArrayUnion +# fields are removed, the only field in the update is "a". + +description: "create: multiple ArrayUnion fields" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": [\"ArrayUnion\", 1, 2, 3], \"c\": {\"d\": [\"ArrayUnion\", 4, 5, 6]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + current_document: < + exists: false + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + field_transforms: < + field_path: "c.d" + append_missing_elements: < + values: < + integer_value: 4 + > + values: < + integer_value: 5 + > + values: < + integer_value: 6 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-nested.textproto new file mode 100644 index 00000000..e6e81bc1 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-nested.textproto @@ -0,0 +1,48 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# An ArrayUnion value can occur at any depth. In this case, the transform applies +# to the field path "b.c". Since "c" is removed from the update, "b" becomes +# empty, so it is also removed from the update. + +description: "create: nested ArrayUnion field" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": {\"c\": [\"ArrayUnion\", 1, 2, 3]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + current_document: < + exists: false + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b.c" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-noarray-nested.textproto new file mode 100644 index 00000000..4c0afe44 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-noarray-nested.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# There cannot be an array value anywhere on the path from the document root to +# the ArrayUnion. Firestore transforms don't support array indexing. + +description: "create: ArrayUnion cannot be anywhere inside an array value" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, {\"b\": [\"ArrayUnion\", 1, 2, 3]}]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-noarray.textproto new file mode 100644 index 00000000..7b791fa4 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-noarray.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# ArrayUnion must be the value of a field. Firestore transforms don't support +# array indexing. + +description: "create: ArrayUnion cannot be in an array value" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2, [\"ArrayRemove\", 1, 2, 3]]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-with-st.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-with-st.textproto new file mode 100644 index 00000000..a1bf4a90 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion-with-st.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The ServerTimestamp sentinel must be the value of a field. It may not appear in +# an ArrayUnion. + +description: "create: The ServerTimestamp sentinel cannot be in an ArrayUnion" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [\"ArrayUnion\", 1, \"ServerTimestamp\", 3]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion.textproto new file mode 100644 index 00000000..98cb6ad8 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-arrayunion.textproto @@ -0,0 +1,47 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A key with ArrayUnion is removed from the data in the update operation. Instead +# it appears in a separate Transform operation. + +description: "create: ArrayUnion with data" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": [\"ArrayUnion\", 1, 2, 3]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + current_document: < + exists: false + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-basic.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-basic.textproto new file mode 100644 index 00000000..433ffda7 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-basic.textproto @@ -0,0 +1,27 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A simple call, resulting in a single update operation. + +description: "create: basic" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + current_document: < + exists: false + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-complex.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-complex.textproto new file mode 100644 index 00000000..00a994e2 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-complex.textproto @@ -0,0 +1,61 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A call to a write method with complicated input data. + +description: "create: complex" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2.5], \"b\": {\"c\": [\"three\", {\"d\": true}]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + array_value: < + values: < + integer_value: 1 + > + values: < + double_value: 2.5 + > + > + > + > + fields: < + key: "b" + value: < + map_value: < + fields: < + key: "c" + value: < + array_value: < + values: < + string_value: "three" + > + values: < + map_value: < + fields: < + key: "d" + value: < + boolean_value: true + > + > + > + > + > + > + > + > + > + > + > + current_document: < + exists: false + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-del-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-del-noarray-nested.textproto new file mode 100644 index 00000000..60694e13 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-del-noarray-nested.textproto @@ -0,0 +1,13 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Delete sentinel must be the value of a field. Deletes are implemented by +# turning the path to the Delete sentinel into a FieldPath, and FieldPaths do not +# support array indexing. + +description: "create: Delete cannot be anywhere inside an array value" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, {\"b\": \"Delete\"}]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-del-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-del-noarray.textproto new file mode 100644 index 00000000..5731be1c --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-del-noarray.textproto @@ -0,0 +1,13 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Delete sentinel must be the value of a field. Deletes are implemented by +# turning the path to the Delete sentinel into a FieldPath, and FieldPaths do not +# support array indexing. + +description: "create: Delete cannot be in an array value" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2, \"Delete\"]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-empty.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-empty.textproto new file mode 100644 index 00000000..2b6fec7e --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-empty.textproto @@ -0,0 +1,20 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + + +description: "create: creating or setting an empty map" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + > + current_document: < + exists: false + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-nodel.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-nodel.textproto new file mode 100644 index 00000000..c878814b --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-nodel.textproto @@ -0,0 +1,11 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Delete sentinel cannot be used in Create, or in Set without a Merge option. + +description: "create: Delete cannot appear in data" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": \"Delete\"}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-nosplit.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-nosplit.textproto new file mode 100644 index 00000000..e9e1ee27 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-nosplit.textproto @@ -0,0 +1,40 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Create and Set treat their map keys literally. They do not split on dots. + +description: "create: don\342\200\231t split on dots" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{ \"a.b\": { \"c.d\": 1 }, \"e\": 2 }" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a.b" + value: < + map_value: < + fields: < + key: "c.d" + value: < + integer_value: 1 + > + > + > + > + > + fields: < + key: "e" + value: < + integer_value: 2 + > + > + > + current_document: < + exists: false + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-special-chars.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-special-chars.textproto new file mode 100644 index 00000000..3a7acd30 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-special-chars.textproto @@ -0,0 +1,41 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Create and Set treat their map keys literally. They do not escape special +# characters. + +description: "create: non-alpha characters in map keys" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{ \"*\": { \".\": 1 }, \"~\": 2 }" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "*" + value: < + map_value: < + fields: < + key: "." + value: < + integer_value: 1 + > + > + > + > + > + fields: < + key: "~" + value: < + integer_value: 2 + > + > + > + current_document: < + exists: false + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-st-alone.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-st-alone.textproto new file mode 100644 index 00000000..9803a676 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-st-alone.textproto @@ -0,0 +1,26 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If the only values in the input are ServerTimestamps, then no update operation +# should be produced. + +description: "create: ServerTimestamp alone" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a" + set_to_server_value: REQUEST_TIME + > + > + current_document: < + exists: false + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-st-multi.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-st-multi.textproto new file mode 100644 index 00000000..cb3db480 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-st-multi.textproto @@ -0,0 +1,41 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can have more than one ServerTimestamp field. Since all the +# ServerTimestamp fields are removed, the only field in the update is "a". + +description: "create: multiple ServerTimestamp fields" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": \"ServerTimestamp\", \"c\": {\"d\": \"ServerTimestamp\"}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + current_document: < + exists: false + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + field_transforms: < + field_path: "c.d" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-st-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-st-nested.textproto new file mode 100644 index 00000000..6bc03e8e --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-st-nested.textproto @@ -0,0 +1,38 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A ServerTimestamp value can occur at any depth. In this case, the transform +# applies to the field path "b.c". Since "c" is removed from the update, "b" +# becomes empty, so it is also removed from the update. + +description: "create: nested ServerTimestamp field" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": {\"c\": \"ServerTimestamp\"}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + current_document: < + exists: false + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b.c" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-st-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-st-noarray-nested.textproto new file mode 100644 index 00000000..0cec0aeb --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-st-noarray-nested.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# There cannot be an array value anywhere on the path from the document root to +# the ServerTimestamp sentinel. Firestore transforms don't support array indexing. + +description: "create: ServerTimestamp cannot be anywhere inside an array value" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, {\"b\": \"ServerTimestamp\"}]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-st-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-st-noarray.textproto new file mode 100644 index 00000000..56d91c2c --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-st-noarray.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The ServerTimestamp sentinel must be the value of a field. Firestore transforms +# don't support array indexing. + +description: "create: ServerTimestamp cannot be in an array value" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2, \"ServerTimestamp\"]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-st-with-empty-map.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-st-with-empty-map.textproto new file mode 100644 index 00000000..37e7e074 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-st-with-empty-map.textproto @@ -0,0 +1,45 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# When a ServerTimestamp and a map both reside inside a map, the ServerTimestamp +# should be stripped out but the empty map should remain. + +description: "create: ServerTimestamp beside an empty map" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": {\"b\": {}, \"c\": \"ServerTimestamp\"}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + map_value: < + fields: < + key: "b" + value: < + map_value: < + > + > + > + > + > + > + > + current_document: < + exists: false + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a.c" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/create-st.textproto b/vendor/cloud.google.com/go/firestore/testdata/create-st.textproto new file mode 100644 index 00000000..ddfc6a17 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/create-st.textproto @@ -0,0 +1,39 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A key with the special ServerTimestamp sentinel is removed from the data in the +# update operation. Instead it appears in a separate Transform operation. Note +# that in these tests, the string "ServerTimestamp" should be replaced with the +# special ServerTimestamp value. + +description: "create: ServerTimestamp with data" +create: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + current_document: < + exists: false + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/delete-exists-precond.textproto b/vendor/cloud.google.com/go/firestore/testdata/delete-exists-precond.textproto new file mode 100644 index 00000000..c9cf2dde --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/delete-exists-precond.textproto @@ -0,0 +1,21 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Delete supports an exists precondition. + +description: "delete: delete with exists precondition" +delete: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + precondition: < + exists: true + > + request: < + database: "projects/projectID/databases/(default)" + writes: < + delete: "projects/projectID/databases/(default)/documents/C/d" + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/delete-no-precond.textproto b/vendor/cloud.google.com/go/firestore/testdata/delete-no-precond.textproto new file mode 100644 index 00000000..a396cdb8 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/delete-no-precond.textproto @@ -0,0 +1,15 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# An ordinary Delete call. + +description: "delete: delete without precondition" +delete: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + request: < + database: "projects/projectID/databases/(default)" + writes: < + delete: "projects/projectID/databases/(default)/documents/C/d" + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/delete-time-precond.textproto b/vendor/cloud.google.com/go/firestore/testdata/delete-time-precond.textproto new file mode 100644 index 00000000..5798f5f3 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/delete-time-precond.textproto @@ -0,0 +1,25 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Delete supports a last-update-time precondition. + +description: "delete: delete with last-update-time precondition" +delete: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + precondition: < + update_time: < + seconds: 42 + > + > + request: < + database: "projects/projectID/databases/(default)" + writes: < + delete: "projects/projectID/databases/(default)/documents/C/d" + current_document: < + update_time: < + seconds: 42 + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/get-basic.textproto b/vendor/cloud.google.com/go/firestore/testdata/get-basic.textproto new file mode 100644 index 00000000..2a448168 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/get-basic.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A call to DocumentRef.Get. + +description: "get: get a document" +get: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + request: < + name: "projects/projectID/databases/(default)/documents/C/d" + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-add-mod-del-add.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-add-mod-del-add.textproto new file mode 100644 index 00000000..1aa8dcbc --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-add-mod-del-add.textproto @@ -0,0 +1,246 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Various changes to a single document. + +description: "listen: add a doc, modify it, delete it, then add it again" +listen: < + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + read_time: < + seconds: 1 + > + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + read_time: < + seconds: 2 + > + > + > + responses: < + document_delete: < + document: "projects/projectID/databases/(default)/documents/C/d1" + > + > + responses: < + target_change: < + read_time: < + seconds: 3 + > + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + read_time: < + seconds: 4 + > + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + > + read_time: < + seconds: 1 + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + changes: < + kind: MODIFIED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + > + read_time: < + seconds: 2 + > + > + snapshots: < + changes: < + kind: REMOVED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + new_index: -1 + > + read_time: < + seconds: 3 + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + old_index: -1 + > + read_time: < + seconds: 4 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-add-one.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-add-one.textproto new file mode 100644 index 00000000..2ad1d8e9 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-add-one.textproto @@ -0,0 +1,79 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Snapshot with a single document. + +description: "listen: add a doc" +listen: < + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + read_time: < + seconds: 2 + > + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + > + read_time: < + seconds: 2 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-add-three.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-add-three.textproto new file mode 100644 index 00000000..ac846f76 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-add-three.textproto @@ -0,0 +1,190 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A snapshot with three documents. The documents are sorted first by the "a" +# field, then by their path. The changes are ordered the same way. + +description: "listen: add three documents" +listen: < + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + read_time: < + seconds: 2 + > + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + docs: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + new_index: 1 + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + new_index: 2 + > + read_time: < + seconds: 2 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-doc-remove.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-doc-remove.textproto new file mode 100644 index 00000000..975200f9 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-doc-remove.textproto @@ -0,0 +1,115 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The DocumentRemove response behaves exactly like DocumentDelete. + +description: "listen: DocumentRemove behaves like DocumentDelete" +listen: < + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + read_time: < + seconds: 1 + > + > + > + responses: < + document_remove: < + document: "projects/projectID/databases/(default)/documents/C/d1" + > + > + responses: < + target_change: < + read_time: < + seconds: 2 + > + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + > + read_time: < + seconds: 1 + > + > + snapshots: < + changes: < + kind: REMOVED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + new_index: -1 + > + read_time: < + seconds: 2 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-empty.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-empty.textproto new file mode 100644 index 00000000..4d04b790 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-empty.textproto @@ -0,0 +1,25 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# There are no changes, so the snapshot should be empty. + +description: "listen: no changes; empty snapshot" +listen: < + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + read_time: < + seconds: 1 + > + > + > + snapshots: < + read_time: < + seconds: 1 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-filter-nop.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-filter-nop.textproto new file mode 100644 index 00000000..48fd72d3 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-filter-nop.textproto @@ -0,0 +1,247 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A Filter response whose count matches the size of the current state (docs in +# last snapshot + docs added - docs deleted) is a no-op. + +description: "listen: Filter response with same size is a no-op" +listen: < + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + read_time: < + seconds: 1 + > + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + document_delete: < + document: "projects/projectID/databases/(default)/documents/C/d1" + > + > + responses: < + filter: < + count: 2 + > + > + responses: < + target_change: < + read_time: < + seconds: 2 + > + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + new_index: 1 + > + read_time: < + seconds: 1 + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + docs: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + changes: < + kind: REMOVED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: 1 + new_index: -1 + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + new_index: 1 + > + read_time: < + seconds: 2 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-multi-docs.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-multi-docs.textproto new file mode 100644 index 00000000..8778acc3 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-multi-docs.textproto @@ -0,0 +1,524 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Changes should be ordered with deletes first, then additions, then mods, each in +# query order. Old indices refer to the immediately previous state, not the +# previous snapshot + +description: "listen: multiple documents, added, deleted and updated" +listen: < + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d4" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + read_time: < + seconds: 2 + > + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d5" + fields: < + key: "a" + value: < + integer_value: 4 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + document_delete: < + document: "projects/projectID/databases/(default)/documents/C/d3" + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: -1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + target_ids: 1 + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d6" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + document_delete: < + document: "projects/projectID/databases/(default)/documents/C/d2" + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d4" + fields: < + key: "a" + value: < + integer_value: -2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + read_time: < + seconds: 4 + > + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + docs: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + docs: < + name: "projects/projectID/databases/(default)/documents/C/d4" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + new_index: 1 + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d4" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + new_index: 2 + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + new_index: 3 + > + read_time: < + seconds: 2 + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d4" + fields: < + key: "a" + value: < + integer_value: -2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: -1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + docs: < + name: "projects/projectID/databases/(default)/documents/C/d6" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + docs: < + name: "projects/projectID/databases/(default)/documents/C/d5" + fields: < + key: "a" + value: < + integer_value: 4 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + changes: < + kind: REMOVED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + new_index: -1 + > + changes: < + kind: REMOVED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + new_index: -1 + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d6" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + new_index: 2 + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d5" + fields: < + key: "a" + value: < + integer_value: 4 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + new_index: 3 + > + changes: < + kind: MODIFIED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d4" + fields: < + key: "a" + value: < + integer_value: -2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + > + changes: < + kind: MODIFIED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: -1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + old_index: 1 + new_index: 1 + > + read_time: < + seconds: 4 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-nocurrent.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-nocurrent.textproto new file mode 100644 index 00000000..24239b64 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-nocurrent.textproto @@ -0,0 +1,141 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If the watch state is not marked CURRENT, no snapshot is issued. + +description: "listen: no snapshot if we don't see CURRENT" +listen: < + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + read_time: < + seconds: 1 + > + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + read_time: < + seconds: 2 + > + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + docs: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + old_index: -1 + new_index: 1 + > + read_time: < + seconds: 2 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-nomod.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-nomod.textproto new file mode 100644 index 00000000..2a99edc3 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-nomod.textproto @@ -0,0 +1,143 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Document updates are recognized by a change in the update time, not the data. +# This shouldn't actually happen. It is just a test of the update logic. + +description: "listen: add a doc, then change it but without changing its update time" +listen: < + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + read_time: < + seconds: 1 + > + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + read_time: < + seconds: 2 + > + > + > + responses: < + document_delete: < + document: "projects/projectID/databases/(default)/documents/C/d1" + > + > + responses: < + target_change: < + read_time: < + seconds: 3 + > + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + > + read_time: < + seconds: 1 + > + > + snapshots: < + changes: < + kind: REMOVED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + new_index: -1 + > + read_time: < + seconds: 3 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-removed-target-ids.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-removed-target-ids.textproto new file mode 100644 index 00000000..1e8ead2d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-removed-target-ids.textproto @@ -0,0 +1,131 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A DocumentChange with the watch target ID in the removed_target_ids field is the +# same as deleting a document. + +description: "listen: DocumentChange with removed_target_id is like a delete." +listen: < + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + read_time: < + seconds: 1 + > + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + removed_target_ids: 1 + > + > + responses: < + target_change: < + read_time: < + seconds: 2 + > + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + > + read_time: < + seconds: 1 + > + > + snapshots: < + changes: < + kind: REMOVED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + new_index: -1 + > + read_time: < + seconds: 2 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-reset.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-reset.textproto new file mode 100644 index 00000000..89a75df2 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-reset.textproto @@ -0,0 +1,382 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A RESET message turns off the CURRENT state, and marks all documents as deleted. + +# If a document appeared on the stream but was never part of a snapshot ("d3" in +# this test), a reset will make it disappear completely. + +# For a snapshot to happen at a NO_CHANGE reponse, we need to have both seen a +# CURRENT response, and have a change from the previous snapshot. Here, after the +# reset, we see the same version of d2 again. That doesn't result in a snapshot. + +description: "listen: RESET turns off CURRENT" +listen: < + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + read_time: < + seconds: 1 + > + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: RESET + > + > + responses: < + target_change: < + read_time: < + seconds: 2 + > + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + read_time: < + seconds: 3 + > + > + > + responses: < + target_change: < + target_change_type: RESET + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + read_time: < + seconds: 4 + > + > + > + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + read_time: < + seconds: 5 + > + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + old_index: -1 + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + new_index: 1 + > + read_time: < + seconds: 1 + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + changes: < + kind: REMOVED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 2 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: 1 + new_index: -1 + > + changes: < + kind: MODIFIED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + > + read_time: < + seconds: 3 + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d2" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 3 + > + > + docs: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d3" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 2 + > + > + old_index: -1 + new_index: 1 + > + read_time: < + seconds: 5 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-target-add-nop.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-target-add-nop.textproto new file mode 100644 index 00000000..3fa7cce5 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-target-add-nop.textproto @@ -0,0 +1,88 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A TargetChange_ADD response must have the same watch target ID. + +description: "listen: TargetChange_ADD is a no-op if it has the same target ID" +listen: < + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + target_change_type: ADD + target_ids: 1 + read_time: < + seconds: 2 + > + > + > + responses: < + target_change: < + read_time: < + seconds: 1 + > + > + > + snapshots: < + docs: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + changes: < + kind: ADDED + doc: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + old_index: -1 + > + read_time: < + seconds: 1 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-target-add-wrong-id.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-target-add-wrong-id.textproto new file mode 100644 index 00000000..87544637 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-target-add-wrong-id.textproto @@ -0,0 +1,50 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A TargetChange_ADD response must have the same watch target ID. + +description: "listen: TargetChange_ADD is an error if it has a different target ID" +listen: < + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + target_change_type: ADD + target_ids: 2 + read_time: < + seconds: 2 + > + > + > + responses: < + target_change: < + read_time: < + seconds: 1 + > + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/listen-target-remove.textproto b/vendor/cloud.google.com/go/firestore/testdata/listen-target-remove.textproto new file mode 100644 index 00000000..f34b0890 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/listen-target-remove.textproto @@ -0,0 +1,46 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A TargetChange_REMOVE response should never be sent. + +description: "listen: TargetChange_REMOVE should not appear" +listen: < + responses: < + document_change: < + document: < + name: "projects/projectID/databases/(default)/documents/C/d1" + fields: < + key: "a" + value: < + integer_value: 3 + > + > + create_time: < + seconds: 1 + > + update_time: < + seconds: 1 + > + > + target_ids: 1 + > + > + responses: < + target_change: < + target_change_type: CURRENT + > + > + responses: < + target_change: < + target_change_type: REMOVE + > + > + responses: < + target_change: < + read_time: < + seconds: 1 + > + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-arrayremove-cursor.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-arrayremove-cursor.textproto new file mode 100644 index 00000000..3c926da9 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-arrayremove-cursor.textproto @@ -0,0 +1,23 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# ArrayRemove is not permitted in queries. + +description: "query: ArrayRemove in cursor method" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "asc" + > + > + clauses: < + end_before: < + json_values: "[\"ArrayRemove\", 1, 2, 3]" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-arrayremove-where.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-arrayremove-where.textproto new file mode 100644 index 00000000..000b7635 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-arrayremove-where.textproto @@ -0,0 +1,19 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# ArrayRemove is not permitted in queries. + +description: "query: ArrayRemove in Where" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "a" + > + op: "==" + json_value: "[\"ArrayRemove\", 1, 2, 3]" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-arrayunion-cursor.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-arrayunion-cursor.textproto new file mode 100644 index 00000000..e8a61104 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-arrayunion-cursor.textproto @@ -0,0 +1,23 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# ArrayUnion is not permitted in queries. + +description: "query: ArrayUnion in cursor method" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "asc" + > + > + clauses: < + end_before: < + json_values: "[\"ArrayUnion\", 1, 2, 3]" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-arrayunion-where.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-arrayunion-where.textproto new file mode 100644 index 00000000..94923134 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-arrayunion-where.textproto @@ -0,0 +1,19 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# ArrayUnion is not permitted in queries. + +description: "query: ArrayUnion in Where" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "a" + > + op: "==" + json_value: "[\"ArrayUnion\", 1, 2, 3]" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-bad-NaN.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-bad-NaN.textproto new file mode 100644 index 00000000..6806dd04 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-bad-NaN.textproto @@ -0,0 +1,19 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# You can only compare NaN for equality. + +description: "query: where clause with non-== comparison with NaN" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "a" + > + op: "<" + json_value: "\"NaN\"" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-bad-null.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-bad-null.textproto new file mode 100644 index 00000000..7fdfb3f2 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-bad-null.textproto @@ -0,0 +1,19 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# You can only compare Null for equality. + +description: "query: where clause with non-== comparison with Null" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "a" + > + op: ">" + json_value: "null" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-order.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-order.textproto new file mode 100644 index 00000000..bab8601e --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-order.textproto @@ -0,0 +1,68 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# When a document snapshot is used, the client appends a __name__ order-by clause +# with the direction of the last order-by clause. + +description: "query: cursor methods with a document snapshot, existing orderBy" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "asc" + > + > + clauses: < + order_by: < + path: < + field: "b" + > + direction: "desc" + > + > + clauses: < + start_after: < + doc_snapshot: < + path: "projects/projectID/databases/(default)/documents/C/D" + json_data: "{\"a\": 7, \"b\": 8}" + > + > + > + query: < + from: < + collection_id: "C" + > + order_by: < + field: < + field_path: "a" + > + direction: ASCENDING + > + order_by: < + field: < + field_path: "b" + > + direction: DESCENDING + > + order_by: < + field: < + field_path: "__name__" + > + direction: DESCENDING + > + start_at: < + values: < + integer_value: 7 + > + values: < + integer_value: 8 + > + values: < + reference_value: "projects/projectID/databases/(default)/documents/C/D" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-orderby-name.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-orderby-name.textproto new file mode 100644 index 00000000..d0ce3df4 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-orderby-name.textproto @@ -0,0 +1,76 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If there is an existing orderBy clause on __name__, no changes are made to the +# list of orderBy clauses. + +description: "query: cursor method, doc snapshot, existing orderBy __name__" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "desc" + > + > + clauses: < + order_by: < + path: < + field: "__name__" + > + direction: "asc" + > + > + clauses: < + start_at: < + doc_snapshot: < + path: "projects/projectID/databases/(default)/documents/C/D" + json_data: "{\"a\": 7, \"b\": 8}" + > + > + > + clauses: < + end_at: < + doc_snapshot: < + path: "projects/projectID/databases/(default)/documents/C/D" + json_data: "{\"a\": 7, \"b\": 8}" + > + > + > + query: < + from: < + collection_id: "C" + > + order_by: < + field: < + field_path: "a" + > + direction: DESCENDING + > + order_by: < + field: < + field_path: "__name__" + > + direction: ASCENDING + > + start_at: < + values: < + integer_value: 7 + > + values: < + reference_value: "projects/projectID/databases/(default)/documents/C/D" + > + before: true + > + end_at: < + values: < + integer_value: 7 + > + values: < + reference_value: "projects/projectID/databases/(default)/documents/C/D" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-where-eq.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-where-eq.textproto new file mode 100644 index 00000000..8b1e217d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-where-eq.textproto @@ -0,0 +1,53 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A Where clause using equality doesn't change the implicit orderBy clauses. + +description: "query: cursor methods with a document snapshot and an equality where clause" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "a" + > + op: "==" + json_value: "3" + > + > + clauses: < + end_at: < + doc_snapshot: < + path: "projects/projectID/databases/(default)/documents/C/D" + json_data: "{\"a\": 7, \"b\": 8}" + > + > + > + query: < + from: < + collection_id: "C" + > + where: < + field_filter: < + field: < + field_path: "a" + > + op: EQUAL + value: < + integer_value: 3 + > + > + > + order_by: < + field: < + field_path: "__name__" + > + direction: ASCENDING + > + end_at: < + values: < + reference_value: "projects/projectID/databases/(default)/documents/C/D" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-where-neq-orderby.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-where-neq-orderby.textproto new file mode 100644 index 00000000..a69edfc5 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-where-neq-orderby.textproto @@ -0,0 +1,72 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If there is an OrderBy clause, the inequality Where clause does not result in a +# new OrderBy clause. We still add a __name__ OrderBy clause + +description: "query: cursor method, doc snapshot, inequality where clause, and existing orderBy clause" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "desc" + > + > + clauses: < + where: < + path: < + field: "a" + > + op: "<" + json_value: "4" + > + > + clauses: < + start_at: < + doc_snapshot: < + path: "projects/projectID/databases/(default)/documents/C/D" + json_data: "{\"a\": 7, \"b\": 8}" + > + > + > + query: < + from: < + collection_id: "C" + > + where: < + field_filter: < + field: < + field_path: "a" + > + op: LESS_THAN + value: < + integer_value: 4 + > + > + > + order_by: < + field: < + field_path: "a" + > + direction: DESCENDING + > + order_by: < + field: < + field_path: "__name__" + > + direction: DESCENDING + > + start_at: < + values: < + integer_value: 7 + > + values: < + reference_value: "projects/projectID/databases/(default)/documents/C/D" + > + before: true + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-where-neq.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-where-neq.textproto new file mode 100644 index 00000000..871dd0ba --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap-where-neq.textproto @@ -0,0 +1,64 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A Where clause with an inequality results in an OrderBy clause on that clause's +# path, if there are no other OrderBy clauses. + +description: "query: cursor method with a document snapshot and an inequality where clause" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "a" + > + op: "<=" + json_value: "3" + > + > + clauses: < + end_before: < + doc_snapshot: < + path: "projects/projectID/databases/(default)/documents/C/D" + json_data: "{\"a\": 7, \"b\": 8}" + > + > + > + query: < + from: < + collection_id: "C" + > + where: < + field_filter: < + field: < + field_path: "a" + > + op: LESS_THAN_OR_EQUAL + value: < + integer_value: 3 + > + > + > + order_by: < + field: < + field_path: "a" + > + direction: ASCENDING + > + order_by: < + field: < + field_path: "__name__" + > + direction: ASCENDING + > + end_at: < + values: < + integer_value: 7 + > + values: < + reference_value: "projects/projectID/databases/(default)/documents/C/D" + > + before: true + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap.textproto new file mode 100644 index 00000000..184bffc2 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-docsnap.textproto @@ -0,0 +1,34 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# When a document snapshot is used, the client appends a __name__ order-by clause. + +description: "query: cursor methods with a document snapshot" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + start_at: < + doc_snapshot: < + path: "projects/projectID/databases/(default)/documents/C/D" + json_data: "{\"a\": 7, \"b\": 8}" + > + > + > + query: < + from: < + collection_id: "C" + > + order_by: < + field: < + field_path: "__name__" + > + direction: ASCENDING + > + start_at: < + values: < + reference_value: "projects/projectID/databases/(default)/documents/C/D" + > + before: true + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-endbefore-empty-map.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-endbefore-empty-map.textproto new file mode 100644 index 00000000..c197d23a --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-endbefore-empty-map.textproto @@ -0,0 +1,41 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Cursor methods are allowed to use empty maps with EndBefore. It should result in +# an empty map in the query. + +description: "query: EndBefore with explicit empty map" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "asc" + > + > + clauses: < + end_before: < + json_values: "{}" + > + > + query: < + from: < + collection_id: "C" + > + order_by: < + field: < + field_path: "a" + > + direction: ASCENDING + > + end_at: < + values: < + map_value: < + > + > + before: true + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-endbefore-empty.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-endbefore-empty.textproto new file mode 100644 index 00000000..a41775ab --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-endbefore-empty.textproto @@ -0,0 +1,23 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Cursor methods are not allowed to use empty values with EndBefore. It should +# result in an error. + +description: "query: EndBefore with empty values" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "asc" + > + > + clauses: < + end_before: < + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-no-order.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-no-order.textproto new file mode 100644 index 00000000..fb999dda --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-no-order.textproto @@ -0,0 +1,16 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If a cursor method with a list of values is provided, there must be at least as +# many explicit orderBy clauses as values. + +description: "query: cursor method without orderBy" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + start_at: < + json_values: "2" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-startat-empty-map.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-startat-empty-map.textproto new file mode 100644 index 00000000..557aca2c --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-startat-empty-map.textproto @@ -0,0 +1,41 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Cursor methods are allowed to use empty maps with StartAt. It should result in +# an empty map in the query. + +description: "query: StartAt with explicit empty map" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "asc" + > + > + clauses: < + start_at: < + json_values: "{}" + > + > + query: < + from: < + collection_id: "C" + > + order_by: < + field: < + field_path: "a" + > + direction: ASCENDING + > + start_at: < + values: < + map_value: < + > + > + before: true + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-startat-empty.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-startat-empty.textproto new file mode 100644 index 00000000..e0c54d98 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-startat-empty.textproto @@ -0,0 +1,23 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Cursor methods are not allowed to use empty values with StartAt. It should +# result in an error. + +description: "query: StartAt with empty values" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "asc" + > + > + clauses: < + start_at: < + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-1a.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-1a.textproto new file mode 100644 index 00000000..bb08ab7d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-1a.textproto @@ -0,0 +1,50 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Cursor methods take the same number of values as there are OrderBy clauses. + +description: "query: StartAt/EndBefore with values" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "asc" + > + > + clauses: < + start_at: < + json_values: "7" + > + > + clauses: < + end_before: < + json_values: "9" + > + > + query: < + from: < + collection_id: "C" + > + order_by: < + field: < + field_path: "a" + > + direction: ASCENDING + > + start_at: < + values: < + integer_value: 7 + > + before: true + > + end_at: < + values: < + integer_value: 9 + > + before: true + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-1b.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-1b.textproto new file mode 100644 index 00000000..41e69e9e --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-1b.textproto @@ -0,0 +1,48 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Cursor methods take the same number of values as there are OrderBy clauses. + +description: "query: StartAfter/EndAt with values" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "asc" + > + > + clauses: < + start_after: < + json_values: "7" + > + > + clauses: < + end_at: < + json_values: "9" + > + > + query: < + from: < + collection_id: "C" + > + order_by: < + field: < + field_path: "a" + > + direction: ASCENDING + > + start_at: < + values: < + integer_value: 7 + > + > + end_at: < + values: < + integer_value: 9 + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-2.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-2.textproto new file mode 100644 index 00000000..8e37ad00 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-2.textproto @@ -0,0 +1,71 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Cursor methods take the same number of values as there are OrderBy clauses. + +description: "query: Start/End with two values" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "asc" + > + > + clauses: < + order_by: < + path: < + field: "b" + > + direction: "desc" + > + > + clauses: < + start_at: < + json_values: "7" + json_values: "8" + > + > + clauses: < + end_at: < + json_values: "9" + json_values: "10" + > + > + query: < + from: < + collection_id: "C" + > + order_by: < + field: < + field_path: "a" + > + direction: ASCENDING + > + order_by: < + field: < + field_path: "b" + > + direction: DESCENDING + > + start_at: < + values: < + integer_value: 7 + > + values: < + integer_value: 8 + > + before: true + > + end_at: < + values: < + integer_value: 9 + > + values: < + integer_value: 10 + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-docid.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-docid.textproto new file mode 100644 index 00000000..91af3486 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-docid.textproto @@ -0,0 +1,50 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Cursor values corresponding to a __name__ field take the document path relative +# to the query's collection. + +description: "query: cursor methods with __name__" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "__name__" + > + direction: "asc" + > + > + clauses: < + start_after: < + json_values: "\"D1\"" + > + > + clauses: < + end_before: < + json_values: "\"D2\"" + > + > + query: < + from: < + collection_id: "C" + > + order_by: < + field: < + field_path: "__name__" + > + direction: ASCENDING + > + start_at: < + values: < + reference_value: "projects/projectID/databases/(default)/documents/C/D1" + > + > + end_at: < + values: < + reference_value: "projects/projectID/databases/(default)/documents/C/D2" + > + before: true + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-last-wins.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-last-wins.textproto new file mode 100644 index 00000000..9e8fbb19 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-cursor-vals-last-wins.textproto @@ -0,0 +1,60 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# When multiple Start* or End* calls occur, the values of the last one are used. + +description: "query: cursor methods, last one wins" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "asc" + > + > + clauses: < + start_after: < + json_values: "1" + > + > + clauses: < + start_at: < + json_values: "2" + > + > + clauses: < + end_at: < + json_values: "3" + > + > + clauses: < + end_before: < + json_values: "4" + > + > + query: < + from: < + collection_id: "C" + > + order_by: < + field: < + field_path: "a" + > + direction: ASCENDING + > + start_at: < + values: < + integer_value: 2 + > + before: true + > + end_at: < + values: < + integer_value: 4 + > + before: true + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-del-cursor.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-del-cursor.textproto new file mode 100644 index 00000000..c9d4adb7 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-del-cursor.textproto @@ -0,0 +1,23 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Sentinel values are not permitted in queries. + +description: "query: Delete in cursor method" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "asc" + > + > + clauses: < + end_before: < + json_values: "\"Delete\"" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-del-where.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-del-where.textproto new file mode 100644 index 00000000..8e925294 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-del-where.textproto @@ -0,0 +1,19 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Sentinel values are not permitted in queries. + +description: "query: Delete in Where" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "a" + > + op: "==" + json_value: "\"Delete\"" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-invalid-operator.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-invalid-operator.textproto new file mode 100644 index 00000000..e580c64a --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-invalid-operator.textproto @@ -0,0 +1,19 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The != operator is not supported. + +description: "query: invalid operator in Where clause" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "a" + > + op: "!=" + json_value: "4" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-invalid-path-order.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-invalid-path-order.textproto new file mode 100644 index 00000000..e0a72057 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-invalid-path-order.textproto @@ -0,0 +1,19 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The path has an empty component. + +description: "query: invalid path in OrderBy clause" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "*" + field: "" + > + direction: "asc" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-invalid-path-select.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-invalid-path-select.textproto new file mode 100644 index 00000000..944f984f --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-invalid-path-select.textproto @@ -0,0 +1,18 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The path has an empty component. + +description: "query: invalid path in Where clause" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + select: < + fields: < + field: "*" + field: "" + > + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-invalid-path-where.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-invalid-path-where.textproto new file mode 100644 index 00000000..527923b0 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-invalid-path-where.textproto @@ -0,0 +1,20 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The path has an empty component. + +description: "query: invalid path in Where clause" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "*" + field: "" + > + op: "==" + json_value: "4" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-offset-limit-last-wins.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-offset-limit-last-wins.textproto new file mode 100644 index 00000000..dc301f43 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-offset-limit-last-wins.textproto @@ -0,0 +1,30 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# With multiple Offset or Limit clauses, the last one wins. + +description: "query: multiple Offset and Limit clauses" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + offset: 2 + > + clauses: < + limit: 3 + > + clauses: < + limit: 4 + > + clauses: < + offset: 5 + > + query: < + from: < + collection_id: "C" + > + offset: 5 + limit: < + value: 4 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-offset-limit.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-offset-limit.textproto new file mode 100644 index 00000000..136d9d46 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-offset-limit.textproto @@ -0,0 +1,24 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Offset and Limit clauses. + +description: "query: Offset and Limit clauses" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + offset: 2 + > + clauses: < + limit: 3 + > + query: < + from: < + collection_id: "C" + > + offset: 2 + limit: < + value: 3 + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-order.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-order.textproto new file mode 100644 index 00000000..7ed4c4ea --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-order.textproto @@ -0,0 +1,42 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Multiple OrderBy clauses combine. + +description: "query: basic OrderBy clauses" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "b" + > + direction: "asc" + > + > + clauses: < + order_by: < + path: < + field: "a" + > + direction: "desc" + > + > + query: < + from: < + collection_id: "C" + > + order_by: < + field: < + field_path: "b" + > + direction: ASCENDING + > + order_by: < + field: < + field_path: "a" + > + direction: DESCENDING + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-select-empty.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-select-empty.textproto new file mode 100644 index 00000000..def8b55a --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-select-empty.textproto @@ -0,0 +1,23 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# An empty Select clause selects just the document ID. + +description: "query: empty Select clause" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + select: < + > + > + query: < + select: < + fields: < + field_path: "__name__" + > + > + from: < + collection_id: "C" + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-select-last-wins.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-select-last-wins.textproto new file mode 100644 index 00000000..bd78d09e --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-select-last-wins.textproto @@ -0,0 +1,36 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The last Select clause is the only one used. + +description: "query: two Select clauses" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + select: < + fields: < + field: "a" + > + fields: < + field: "b" + > + > + > + clauses: < + select: < + fields: < + field: "c" + > + > + > + query: < + select: < + fields: < + field_path: "c" + > + > + from: < + collection_id: "C" + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-select.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-select.textproto new file mode 100644 index 00000000..15e11249 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-select.textproto @@ -0,0 +1,32 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# An ordinary Select clause. + +description: "query: Select clause with some fields" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + select: < + fields: < + field: "a" + > + fields: < + field: "b" + > + > + > + query: < + select: < + fields: < + field_path: "a" + > + fields: < + field_path: "b" + > + > + from: < + collection_id: "C" + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-st-cursor.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-st-cursor.textproto new file mode 100644 index 00000000..66885d0d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-st-cursor.textproto @@ -0,0 +1,23 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Sentinel values are not permitted in queries. + +description: "query: ServerTimestamp in cursor method" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + order_by: < + path: < + field: "a" + > + direction: "asc" + > + > + clauses: < + end_before: < + json_values: "\"ServerTimestamp\"" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-st-where.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-st-where.textproto new file mode 100644 index 00000000..05da28d5 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-st-where.textproto @@ -0,0 +1,19 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Sentinel values are not permitted in queries. + +description: "query: ServerTimestamp in Where" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "a" + > + op: "==" + json_value: "\"ServerTimestamp\"" + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-where-2.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-where-2.textproto new file mode 100644 index 00000000..10344630 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-where-2.textproto @@ -0,0 +1,59 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Multiple Where clauses are combined into a composite filter. + +description: "query: two Where clauses" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "a" + > + op: ">=" + json_value: "5" + > + > + clauses: < + where: < + path: < + field: "b" + > + op: "<" + json_value: "\"foo\"" + > + > + query: < + from: < + collection_id: "C" + > + where: < + composite_filter: < + op: AND + filters: < + field_filter: < + field: < + field_path: "a" + > + op: GREATER_THAN_OR_EQUAL + value: < + integer_value: 5 + > + > + > + filters: < + field_filter: < + field: < + field_path: "b" + > + op: LESS_THAN + value: < + string_value: "foo" + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-where-NaN.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-where-NaN.textproto new file mode 100644 index 00000000..4a97ca7d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-where-NaN.textproto @@ -0,0 +1,31 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A Where clause that tests for equality with NaN results in a unary filter. + +description: "query: a Where clause comparing to NaN" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "a" + > + op: "==" + json_value: "\"NaN\"" + > + > + query: < + from: < + collection_id: "C" + > + where: < + unary_filter: < + op: IS_NAN + field: < + field_path: "a" + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-where-null.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-where-null.textproto new file mode 100644 index 00000000..1869c60c --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-where-null.textproto @@ -0,0 +1,31 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A Where clause that tests for equality with null results in a unary filter. + +description: "query: a Where clause comparing to null" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "a" + > + op: "==" + json_value: "null" + > + > + query: < + from: < + collection_id: "C" + > + where: < + unary_filter: < + op: IS_NULL + field: < + field_path: "a" + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-where.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-where.textproto new file mode 100644 index 00000000..045c2bef --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-where.textproto @@ -0,0 +1,34 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A simple Where clause. + +description: "query: Where clause" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + where: < + path: < + field: "a" + > + op: ">" + json_value: "5" + > + > + query: < + from: < + collection_id: "C" + > + where: < + field_filter: < + field: < + field_path: "a" + > + op: GREATER_THAN + value: < + integer_value: 5 + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/query-wrong-collection.textproto b/vendor/cloud.google.com/go/firestore/testdata/query-wrong-collection.textproto new file mode 100644 index 00000000..ad6f353d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/query-wrong-collection.textproto @@ -0,0 +1,19 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If a document snapshot is passed to a Start*/End* method, it must be in the same +# collection as the query. + +description: "query: doc snapshot with wrong collection in cursor method" +query: < + coll_path: "projects/projectID/databases/(default)/documents/C" + clauses: < + end_before: < + doc_snapshot: < + path: "projects/projectID/databases/(default)/documents/C2/D" + json_data: "{\"a\": 7, \"b\": 8}" + > + > + > + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-all-transforms.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-all-transforms.textproto new file mode 100644 index 00000000..bf18f9a5 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-all-transforms.textproto @@ -0,0 +1,61 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can be created with any amount of transforms. + +description: "set: all transforms in a single call" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": \"ServerTimestamp\", \"c\": [\"ArrayUnion\", 1, 2, 3], \"d\": [\"ArrayRemove\", 4, 5, 6]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + field_transforms: < + field_path: "c" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + field_transforms: < + field_path: "d" + remove_all_from_array: < + values: < + integer_value: 4 + > + values: < + integer_value: 5 + > + values: < + integer_value: 6 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-multi.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-multi.textproto new file mode 100644 index 00000000..9b62fe19 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-multi.textproto @@ -0,0 +1,58 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can have more than one ArrayRemove field. Since all the ArrayRemove +# fields are removed, the only field in the update is "a". + +description: "set: multiple ArrayRemove fields" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": [\"ArrayRemove\", 1, 2, 3], \"c\": {\"d\": [\"ArrayRemove\", 4, 5, 6]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + field_transforms: < + field_path: "c.d" + remove_all_from_array: < + values: < + integer_value: 4 + > + values: < + integer_value: 5 + > + values: < + integer_value: 6 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-nested.textproto new file mode 100644 index 00000000..617609c5 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-nested.textproto @@ -0,0 +1,45 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# An ArrayRemove value can occur at any depth. In this case, the transform applies +# to the field path "b.c". Since "c" is removed from the update, "b" becomes +# empty, so it is also removed from the update. + +description: "set: nested ArrayRemove field" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": {\"c\": [\"ArrayRemove\", 1, 2, 3]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b.c" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-noarray-nested.textproto new file mode 100644 index 00000000..2efa34a5 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-noarray-nested.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# There cannot be an array value anywhere on the path from the document root to +# the ArrayRemove. Firestore transforms don't support array indexing. + +description: "set: ArrayRemove cannot be anywhere inside an array value" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, {\"b\": [\"ArrayRemove\", 1, 2, 3]}]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-noarray.textproto new file mode 100644 index 00000000..e7aa209e --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-noarray.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# ArrayRemove must be the value of a field. Firestore transforms don't support +# array indexing. + +description: "set: ArrayRemove cannot be in an array value" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2, [\"ArrayRemove\", 1, 2, 3]]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-with-st.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-with-st.textproto new file mode 100644 index 00000000..353025b5 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove-with-st.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The ServerTimestamp sentinel must be the value of a field. It may not appear in +# an ArrayUnion. + +description: "set: The ServerTimestamp sentinel cannot be in an ArrayUnion" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [\"ArrayRemove\", 1, \"ServerTimestamp\", 3]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove.textproto new file mode 100644 index 00000000..8aa6b60d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-arrayremove.textproto @@ -0,0 +1,44 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A key with ArrayRemove is removed from the data in the update operation. Instead +# it appears in a separate Transform operation. + +description: "set: ArrayRemove with data" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": [\"ArrayRemove\", 1, 2, 3]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-multi.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-multi.textproto new file mode 100644 index 00000000..e515bfa8 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-multi.textproto @@ -0,0 +1,58 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can have more than one ArrayUnion field. Since all the ArrayUnion +# fields are removed, the only field in the update is "a". + +description: "set: multiple ArrayUnion fields" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": [\"ArrayUnion\", 1, 2, 3], \"c\": {\"d\": [\"ArrayUnion\", 4, 5, 6]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + field_transforms: < + field_path: "c.d" + append_missing_elements: < + values: < + integer_value: 4 + > + values: < + integer_value: 5 + > + values: < + integer_value: 6 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-nested.textproto new file mode 100644 index 00000000..f8abeb0d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-nested.textproto @@ -0,0 +1,45 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# An ArrayUnion value can occur at any depth. In this case, the transform applies +# to the field path "b.c". Since "c" is removed from the update, "b" becomes +# empty, so it is also removed from the update. + +description: "set: nested ArrayUnion field" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": {\"c\": [\"ArrayUnion\", 1, 2, 3]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b.c" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-noarray-nested.textproto new file mode 100644 index 00000000..2b4170f4 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-noarray-nested.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# There cannot be an array value anywhere on the path from the document root to +# the ArrayUnion. Firestore transforms don't support array indexing. + +description: "set: ArrayUnion cannot be anywhere inside an array value" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, {\"b\": [\"ArrayUnion\", 1, 2, 3]}]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-noarray.textproto new file mode 100644 index 00000000..e08af3a0 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-noarray.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# ArrayUnion must be the value of a field. Firestore transforms don't support +# array indexing. + +description: "set: ArrayUnion cannot be in an array value" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2, [\"ArrayRemove\", 1, 2, 3]]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-with-st.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-with-st.textproto new file mode 100644 index 00000000..37a7a132 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion-with-st.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The ServerTimestamp sentinel must be the value of a field. It may not appear in +# an ArrayUnion. + +description: "set: The ServerTimestamp sentinel cannot be in an ArrayUnion" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [\"ArrayUnion\", 1, \"ServerTimestamp\", 3]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion.textproto new file mode 100644 index 00000000..4751e0c0 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-arrayunion.textproto @@ -0,0 +1,44 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A key with ArrayUnion is removed from the data in the update operation. Instead +# it appears in a separate Transform operation. + +description: "set: ArrayUnion with data" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": [\"ArrayUnion\", 1, 2, 3]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-basic.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-basic.textproto new file mode 100644 index 00000000..e9b292e3 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-basic.textproto @@ -0,0 +1,24 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A simple call, resulting in a single update operation. + +description: "set: basic" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-complex.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-complex.textproto new file mode 100644 index 00000000..6ec19500 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-complex.textproto @@ -0,0 +1,58 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A call to a write method with complicated input data. + +description: "set: complex" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2.5], \"b\": {\"c\": [\"three\", {\"d\": true}]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + array_value: < + values: < + integer_value: 1 + > + values: < + double_value: 2.5 + > + > + > + > + fields: < + key: "b" + value: < + map_value: < + fields: < + key: "c" + value: < + array_value: < + values: < + string_value: "three" + > + values: < + map_value: < + fields: < + key: "d" + value: < + boolean_value: true + > + > + > + > + > + > + > + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-del-merge-alone.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-del-merge-alone.textproto new file mode 100644 index 00000000..811ab8df --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-del-merge-alone.textproto @@ -0,0 +1,28 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A Delete sentinel can appear with a merge option. If the delete paths are the +# only ones to be merged, then no document is sent, just an update mask. + +description: "set-merge: Delete with merge" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "b" + field: "c" + > + > + json_data: "{\"a\": 1, \"b\": {\"c\": \"Delete\"}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + > + update_mask: < + field_paths: "b.c" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-del-merge.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-del-merge.textproto new file mode 100644 index 00000000..b8d86310 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-del-merge.textproto @@ -0,0 +1,37 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A Delete sentinel can appear with a merge option. + +description: "set-merge: Delete with merge" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "a" + > + fields: < + field: "b" + field: "c" + > + > + json_data: "{\"a\": 1, \"b\": {\"c\": \"Delete\"}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b.c" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-del-mergeall.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-del-mergeall.textproto new file mode 100644 index 00000000..af1e8452 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-del-mergeall.textproto @@ -0,0 +1,31 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A Delete sentinel can appear with a mergeAll option. + +description: "set: Delete with MergeAll" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + all: true + > + json_data: "{\"a\": 1, \"b\": {\"c\": \"Delete\"}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b.c" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-del-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-del-noarray-nested.textproto new file mode 100644 index 00000000..bbf6a3d0 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-del-noarray-nested.textproto @@ -0,0 +1,13 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Delete sentinel must be the value of a field. Deletes are implemented by +# turning the path to the Delete sentinel into a FieldPath, and FieldPaths do not +# support array indexing. + +description: "set: Delete cannot be anywhere inside an array value" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, {\"b\": \"Delete\"}]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-del-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-del-noarray.textproto new file mode 100644 index 00000000..07fc6497 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-del-noarray.textproto @@ -0,0 +1,13 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Delete sentinel must be the value of a field. Deletes are implemented by +# turning the path to the Delete sentinel into a FieldPath, and FieldPaths do not +# support array indexing. + +description: "set: Delete cannot be in an array value" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2, \"Delete\"]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-del-nomerge.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-del-nomerge.textproto new file mode 100644 index 00000000..cb6ef4f8 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-del-nomerge.textproto @@ -0,0 +1,17 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The client signals an error if the Delete sentinel is in the input data, but not +# selected by a merge option, because this is most likely a programming bug. + +description: "set-merge: Delete cannot appear in an unmerged field" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "a" + > + > + json_data: "{\"a\": 1, \"b\": \"Delete\"}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-del-nonleaf.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-del-nonleaf.textproto new file mode 100644 index 00000000..54f22d95 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-del-nonleaf.textproto @@ -0,0 +1,19 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If a Delete is part of the value at a merge path, then the user is confused: +# their merge path says "replace this entire value" but their Delete says "delete +# this part of the value". This should be an error, just as if they specified +# Delete in a Set with no merge. + +description: "set-merge: Delete cannot appear as part of a merge path" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "h" + > + > + json_data: "{\"h\": {\"g\": \"Delete\"}}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-del-wo-merge.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-del-wo-merge.textproto new file mode 100644 index 00000000..29196628 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-del-wo-merge.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Without a merge option, Set replaces the document with the input data. A Delete +# sentinel in the data makes no sense in this case. + +description: "set: Delete cannot appear unless a merge option is specified" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": \"Delete\"}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-empty.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-empty.textproto new file mode 100644 index 00000000..c2b73d3f --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-empty.textproto @@ -0,0 +1,17 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + + +description: "set: creating or setting an empty map" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-merge-fp.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-merge-fp.textproto new file mode 100644 index 00000000..68690f6f --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-merge-fp.textproto @@ -0,0 +1,40 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A merge with fields that use special characters. + +description: "set-merge: Merge with FieldPaths" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "*" + field: "~" + > + > + json_data: "{\"*\": {\"~\": true}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "*" + value: < + map_value: < + fields: < + key: "~" + value: < + boolean_value: true + > + > + > + > + > + > + update_mask: < + field_paths: "`*`.`~`" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-merge-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-merge-nested.textproto new file mode 100644 index 00000000..0d128281 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-merge-nested.textproto @@ -0,0 +1,41 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A merge option where the field is not at top level. Only fields mentioned in the +# option are present in the update operation. + +description: "set-merge: Merge with a nested field" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "h" + field: "g" + > + > + json_data: "{\"h\": {\"g\": 4, \"f\": 5}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "h" + value: < + map_value: < + fields: < + key: "g" + value: < + integer_value: 4 + > + > + > + > + > + > + update_mask: < + field_paths: "h.g" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-merge-nonleaf.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-merge-nonleaf.textproto new file mode 100644 index 00000000..ca41cb03 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-merge-nonleaf.textproto @@ -0,0 +1,46 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If a field path is in a merge option, the value at that path replaces the stored +# value. That is true even if the value is complex. + +description: "set-merge: Merge field is not a leaf" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "h" + > + > + json_data: "{\"h\": {\"f\": 5, \"g\": 6}, \"e\": 7}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "h" + value: < + map_value: < + fields: < + key: "f" + value: < + integer_value: 5 + > + > + fields: < + key: "g" + value: < + integer_value: 6 + > + > + > + > + > + > + update_mask: < + field_paths: "h" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-merge-prefix.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-merge-prefix.textproto new file mode 100644 index 00000000..1e2c2c50 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-merge-prefix.textproto @@ -0,0 +1,21 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The prefix would make the other path meaningless, so this is probably a +# programming error. + +description: "set-merge: One merge path cannot be the prefix of another" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "a" + > + fields: < + field: "a" + field: "b" + > + > + json_data: "{\"a\": {\"b\": 1}}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-merge-present.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-merge-present.textproto new file mode 100644 index 00000000..f6665de5 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-merge-present.textproto @@ -0,0 +1,20 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The client signals an error if a merge option mentions a path that is not in the +# input data. + +description: "set-merge: Merge fields must all be present in data" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "b" + > + fields: < + field: "a" + > + > + json_data: "{\"a\": 1}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-merge.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-merge.textproto new file mode 100644 index 00000000..27912525 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-merge.textproto @@ -0,0 +1,32 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Fields in the input data but not in a merge option are pruned. + +description: "set-merge: Merge with a field" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "a" + > + > + json_data: "{\"a\": 1, \"b\": 2}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-mergeall-empty.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-mergeall-empty.textproto new file mode 100644 index 00000000..16df8a22 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-mergeall-empty.textproto @@ -0,0 +1,23 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# This is a valid call that can be used to ensure a document exists. + +description: "set: MergeAll can be specified with empty data." +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + all: true + > + json_data: "{}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + > + update_mask: < + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-mergeall-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-mergeall-nested.textproto new file mode 100644 index 00000000..1fbc6973 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-mergeall-nested.textproto @@ -0,0 +1,45 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# MergeAll with nested fields results in an update mask that includes entries for +# all the leaf fields. + +description: "set: MergeAll with nested fields" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + all: true + > + json_data: "{\"h\": { \"g\": 3, \"f\": 4 }}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "h" + value: < + map_value: < + fields: < + key: "f" + value: < + integer_value: 4 + > + > + fields: < + key: "g" + value: < + integer_value: 3 + > + > + > + > + > + > + update_mask: < + field_paths: "h.f" + field_paths: "h.g" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-mergeall.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-mergeall.textproto new file mode 100644 index 00000000..cb2ebc52 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-mergeall.textproto @@ -0,0 +1,37 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The MergeAll option with a simple piece of data. + +description: "set: MergeAll" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + all: true + > + json_data: "{\"a\": 1, \"b\": 2}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + fields: < + key: "b" + value: < + integer_value: 2 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-nodel.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-nodel.textproto new file mode 100644 index 00000000..0fb887d4 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-nodel.textproto @@ -0,0 +1,11 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Delete sentinel cannot be used in Create, or in Set without a Merge option. + +description: "set: Delete cannot appear in data" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": \"Delete\"}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-nosplit.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-nosplit.textproto new file mode 100644 index 00000000..0ff3fadc --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-nosplit.textproto @@ -0,0 +1,37 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Create and Set treat their map keys literally. They do not split on dots. + +description: "set: don\342\200\231t split on dots" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{ \"a.b\": { \"c.d\": 1 }, \"e\": 2 }" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a.b" + value: < + map_value: < + fields: < + key: "c.d" + value: < + integer_value: 1 + > + > + > + > + > + fields: < + key: "e" + value: < + integer_value: 2 + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-special-chars.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-special-chars.textproto new file mode 100644 index 00000000..f4122c9f --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-special-chars.textproto @@ -0,0 +1,38 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Create and Set treat their map keys literally. They do not escape special +# characters. + +description: "set: non-alpha characters in map keys" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{ \"*\": { \".\": 1 }, \"~\": 2 }" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "*" + value: < + map_value: < + fields: < + key: "." + value: < + integer_value: 1 + > + > + > + > + > + fields: < + key: "~" + value: < + integer_value: 2 + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st-alone-mergeall.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st-alone-mergeall.textproto new file mode 100644 index 00000000..16ce4cfb --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st-alone-mergeall.textproto @@ -0,0 +1,26 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If the only values in the input are ServerTimestamps, then no update operation +# should be produced. + +description: "set: ServerTimestamp alone with MergeAll" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + all: true + > + json_data: "{\"a\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st-alone.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st-alone.textproto new file mode 100644 index 00000000..6ce46d7f --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st-alone.textproto @@ -0,0 +1,28 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If the only values in the input are ServerTimestamps, then an update operation +# with an empty map should be produced. + +description: "set: ServerTimestamp alone" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st-merge-both.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st-merge-both.textproto new file mode 100644 index 00000000..5cc7bbc9 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st-merge-both.textproto @@ -0,0 +1,45 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Just as when no merge option is specified, ServerTimestamp sentinel values are +# removed from the data in the update operation and become transforms. + +description: "set-merge: ServerTimestamp with Merge of both fields" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "a" + > + fields: < + field: "b" + > + > + json_data: "{\"a\": 1, \"b\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st-merge-nonleaf-alone.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st-merge-nonleaf-alone.textproto new file mode 100644 index 00000000..f513b6c8 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st-merge-nonleaf-alone.textproto @@ -0,0 +1,37 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If a field path is in a merge option, the value at that path replaces the stored +# value. If the value has only ServerTimestamps, they become transforms and we +# clear the value by including the field path in the update mask. + +description: "set-merge: non-leaf merge field with ServerTimestamp alone" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "h" + > + > + json_data: "{\"h\": {\"g\": \"ServerTimestamp\"}, \"e\": 7}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + > + update_mask: < + field_paths: "h" + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "h.g" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st-merge-nonleaf.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st-merge-nonleaf.textproto new file mode 100644 index 00000000..e53e7e26 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st-merge-nonleaf.textproto @@ -0,0 +1,49 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If a field path is in a merge option, the value at that path replaces the stored +# value, and ServerTimestamps inside that value become transforms as usual. + +description: "set-merge: non-leaf merge field with ServerTimestamp" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "h" + > + > + json_data: "{\"h\": {\"f\": 5, \"g\": \"ServerTimestamp\"}, \"e\": 7}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "h" + value: < + map_value: < + fields: < + key: "f" + value: < + integer_value: 5 + > + > + > + > + > + > + update_mask: < + field_paths: "h" + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "h.g" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st-merge-nowrite.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st-merge-nowrite.textproto new file mode 100644 index 00000000..3222230d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st-merge-nowrite.textproto @@ -0,0 +1,28 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If all the fields in the merge option have ServerTimestamp values, then no +# update operation is produced, only a transform. + +description: "set-merge: If no ordinary values in Merge, no write" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "b" + > + > + json_data: "{\"a\": 1, \"b\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st-mergeall.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st-mergeall.textproto new file mode 100644 index 00000000..b8c53a56 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st-mergeall.textproto @@ -0,0 +1,40 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Just as when no merge option is specified, ServerTimestamp sentinel values are +# removed from the data in the update operation and become transforms. + +description: "set: ServerTimestamp with MergeAll" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + all: true + > + json_data: "{\"a\": 1, \"b\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st-multi.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st-multi.textproto new file mode 100644 index 00000000..375ec18d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st-multi.textproto @@ -0,0 +1,38 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can have more than one ServerTimestamp field. Since all the +# ServerTimestamp fields are removed, the only field in the update is "a". + +description: "set: multiple ServerTimestamp fields" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": \"ServerTimestamp\", \"c\": {\"d\": \"ServerTimestamp\"}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + field_transforms: < + field_path: "c.d" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st-nested.textproto new file mode 100644 index 00000000..abfd2e8f --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st-nested.textproto @@ -0,0 +1,35 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A ServerTimestamp value can occur at any depth. In this case, the transform +# applies to the field path "b.c". Since "c" is removed from the update, "b" +# becomes empty, so it is also removed from the update. + +description: "set: nested ServerTimestamp field" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": {\"c\": \"ServerTimestamp\"}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b.c" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st-noarray-nested.textproto new file mode 100644 index 00000000..241d7915 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st-noarray-nested.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# There cannot be an array value anywhere on the path from the document root to +# the ServerTimestamp sentinel. Firestore transforms don't support array indexing. + +description: "set: ServerTimestamp cannot be anywhere inside an array value" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, {\"b\": \"ServerTimestamp\"}]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st-noarray.textproto new file mode 100644 index 00000000..591fb034 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st-noarray.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The ServerTimestamp sentinel must be the value of a field. Firestore transforms +# don't support array indexing. + +description: "set: ServerTimestamp cannot be in an array value" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2, \"ServerTimestamp\"]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st-nomerge.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st-nomerge.textproto new file mode 100644 index 00000000..20c0ae1f --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st-nomerge.textproto @@ -0,0 +1,33 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If the ServerTimestamp value is not mentioned in a merge option, then it is +# pruned from the data but does not result in a transform. + +description: "set-merge: If is ServerTimestamp not in Merge, no transform" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + option: < + fields: < + field: "a" + > + > + json_data: "{\"a\": 1, \"b\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st-with-empty-map.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st-with-empty-map.textproto new file mode 100644 index 00000000..5e187983 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st-with-empty-map.textproto @@ -0,0 +1,42 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# When a ServerTimestamp and a map both reside inside a map, the ServerTimestamp +# should be stripped out but the empty map should remain. + +description: "set: ServerTimestamp beside an empty map" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": {\"b\": {}, \"c\": \"ServerTimestamp\"}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + map_value: < + fields: < + key: "b" + value: < + map_value: < + > + > + > + > + > + > + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a.c" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/set-st.textproto b/vendor/cloud.google.com/go/firestore/testdata/set-st.textproto new file mode 100644 index 00000000..8bceddce --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/set-st.textproto @@ -0,0 +1,36 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A key with the special ServerTimestamp sentinel is removed from the data in the +# update operation. Instead it appears in a separate Transform operation. Note +# that in these tests, the string "ServerTimestamp" should be replaced with the +# special ServerTimestamp value. + +description: "set: ServerTimestamp with data" +set: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/test-suite.binproto b/vendor/cloud.google.com/go/firestore/testdata/test-suite.binproto new file mode 100644 index 00000000..6e3ce397 Binary files /dev/null and b/vendor/cloud.google.com/go/firestore/testdata/test-suite.binproto differ diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-all-transforms.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-all-transforms.textproto new file mode 100644 index 00000000..225cc61e --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-all-transforms.textproto @@ -0,0 +1,67 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can be created with any amount of transforms. + +description: "update: all transforms in a single call" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": \"ServerTimestamp\", \"c\": [\"ArrayUnion\", 1, 2, 3], \"d\": [\"ArrayRemove\", 4, 5, 6]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + field_transforms: < + field_path: "c" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + field_transforms: < + field_path: "d" + remove_all_from_array: < + values: < + integer_value: 4 + > + values: < + integer_value: 5 + > + values: < + integer_value: 6 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-alone.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-alone.textproto new file mode 100644 index 00000000..8c79a31d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-alone.textproto @@ -0,0 +1,36 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If the only values in the input are ArrayRemove, then no update operation should +# be produced. + +description: "update: ArrayRemove alone" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [\"ArrayRemove\", 1, 2, 3]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-multi.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-multi.textproto new file mode 100644 index 00000000..2362b6e0 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-multi.textproto @@ -0,0 +1,69 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can have more than one ArrayRemove field. Since all the ArrayRemove +# fields are removed, the only field in the update is "a". + +# b is not in the mask because it will be set in the transform. c must be in the +# mask: it should be replaced entirely. The transform will set c.d to the +# timestamp, but the update will delete the rest of c. + +description: "update: multiple ArrayRemove fields" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": [\"ArrayRemove\", 1, 2, 3], \"c\": {\"d\": [\"ArrayRemove\", 4, 5, 6]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "c" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + field_transforms: < + field_path: "c.d" + remove_all_from_array: < + values: < + integer_value: 4 + > + values: < + integer_value: 5 + > + values: < + integer_value: 6 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-nested.textproto new file mode 100644 index 00000000..14379017 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-nested.textproto @@ -0,0 +1,52 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# An ArrayRemove value can occur at any depth. In this case, the transform applies +# to the field path "b.c". Since "c" is removed from the update, "b" becomes +# empty, so it is also removed from the update. + +description: "update: nested ArrayRemove field" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": {\"c\": [\"ArrayRemove\", 1, 2, 3]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b.c" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-noarray-nested.textproto new file mode 100644 index 00000000..04eca965 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-noarray-nested.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# There cannot be an array value anywhere on the path from the document root to +# the ArrayRemove. Firestore transforms don't support array indexing. + +description: "update: ArrayRemove cannot be anywhere inside an array value" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, {\"b\": [\"ArrayRemove\", 1, 2, 3]}]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-noarray.textproto new file mode 100644 index 00000000..bbd27bf0 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-noarray.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# ArrayRemove must be the value of a field. Firestore transforms don't support +# array indexing. + +description: "update: ArrayRemove cannot be in an array value" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2, [\"ArrayRemove\", 1, 2, 3]]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-with-st.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-with-st.textproto new file mode 100644 index 00000000..4888b44f --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove-with-st.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The ServerTimestamp sentinel must be the value of a field. It may not appear in +# an ArrayUnion. + +description: "update: The ServerTimestamp sentinel cannot be in an ArrayUnion" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [\"ArrayRemove\", 1, \"ServerTimestamp\", 3]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove.textproto new file mode 100644 index 00000000..3b767cf4 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayremove.textproto @@ -0,0 +1,50 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A key with ArrayRemove is removed from the data in the update operation. Instead +# it appears in a separate Transform operation. + +description: "update: ArrayRemove with data" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": [\"ArrayRemove\", 1, 2, 3]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-alone.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-alone.textproto new file mode 100644 index 00000000..ec12818d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-alone.textproto @@ -0,0 +1,36 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If the only values in the input are ArrayUnion, then no update operation should +# be produced. + +description: "update: ArrayUnion alone" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [\"ArrayUnion\", 1, 2, 3]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-multi.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-multi.textproto new file mode 100644 index 00000000..8edf6a3a --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-multi.textproto @@ -0,0 +1,69 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can have more than one ArrayUnion field. Since all the ArrayUnion +# fields are removed, the only field in the update is "a". + +# b is not in the mask because it will be set in the transform. c must be in the +# mask: it should be replaced entirely. The transform will set c.d to the +# timestamp, but the update will delete the rest of c. + +description: "update: multiple ArrayUnion fields" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": [\"ArrayUnion\", 1, 2, 3], \"c\": {\"d\": [\"ArrayUnion\", 4, 5, 6]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "c" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + field_transforms: < + field_path: "c.d" + append_missing_elements: < + values: < + integer_value: 4 + > + values: < + integer_value: 5 + > + values: < + integer_value: 6 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-nested.textproto new file mode 100644 index 00000000..217e2e2c --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-nested.textproto @@ -0,0 +1,52 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# An ArrayUnion value can occur at any depth. In this case, the transform applies +# to the field path "b.c". Since "c" is removed from the update, "b" becomes +# empty, so it is also removed from the update. + +description: "update: nested ArrayUnion field" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": {\"c\": [\"ArrayUnion\", 1, 2, 3]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b.c" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-noarray-nested.textproto new file mode 100644 index 00000000..03267818 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-noarray-nested.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# There cannot be an array value anywhere on the path from the document root to +# the ArrayUnion. Firestore transforms don't support array indexing. + +description: "update: ArrayUnion cannot be anywhere inside an array value" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, {\"b\": [\"ArrayUnion\", 1, 2, 3]}]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-noarray.textproto new file mode 100644 index 00000000..c199f9f7 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-noarray.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# ArrayUnion must be the value of a field. Firestore transforms don't support +# array indexing. + +description: "update: ArrayUnion cannot be in an array value" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2, [\"ArrayRemove\", 1, 2, 3]]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-with-st.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-with-st.textproto new file mode 100644 index 00000000..ee022f84 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion-with-st.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The ServerTimestamp sentinel must be the value of a field. It may not appear in +# an ArrayUnion. + +description: "update: The ServerTimestamp sentinel cannot be in an ArrayUnion" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [\"ArrayUnion\", 1, \"ServerTimestamp\", 3]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion.textproto new file mode 100644 index 00000000..81b240b8 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-arrayunion.textproto @@ -0,0 +1,50 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A key with ArrayUnion is removed from the data in the update operation. Instead +# it appears in a separate Transform operation. + +description: "update: ArrayUnion with data" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": [\"ArrayUnion\", 1, 2, 3]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-badchar.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-badchar.textproto new file mode 100644 index 00000000..656ff53b --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-badchar.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The keys of the data given to Update are interpreted, unlike those of Create and +# Set. They cannot contain special characters. + +description: "update: invalid character" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a~b\": 1}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-basic.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-basic.textproto new file mode 100644 index 00000000..9da316f5 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-basic.textproto @@ -0,0 +1,30 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A simple call, resulting in a single update operation. + +description: "update: basic" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-complex.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-complex.textproto new file mode 100644 index 00000000..1a6d9eff --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-complex.textproto @@ -0,0 +1,65 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A call to a write method with complicated input data. + +description: "update: complex" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2.5], \"b\": {\"c\": [\"three\", {\"d\": true}]}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + array_value: < + values: < + integer_value: 1 + > + values: < + double_value: 2.5 + > + > + > + > + fields: < + key: "b" + value: < + map_value: < + fields: < + key: "c" + value: < + array_value: < + values: < + string_value: "three" + > + values: < + map_value: < + fields: < + key: "d" + value: < + boolean_value: true + > + > + > + > + > + > + > + > + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-del-alone.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-del-alone.textproto new file mode 100644 index 00000000..8f558233 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-del-alone.textproto @@ -0,0 +1,25 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If the input data consists solely of Deletes, then the update operation has no +# map, just an update mask. + +description: "update: Delete alone" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": \"Delete\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-del-dot.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-del-dot.textproto new file mode 100644 index 00000000..c0ebdf61 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-del-dot.textproto @@ -0,0 +1,46 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# After expanding top-level dotted fields, fields with Delete values are pruned +# from the output data, but appear in the update mask. + +description: "update: Delete with a dotted field" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b.c\": \"Delete\", \"b.d\": 2}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + fields: < + key: "b" + value: < + map_value: < + fields: < + key: "d" + value: < + integer_value: 2 + > + > + > + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b.c" + field_paths: "b.d" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-del-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-del-nested.textproto new file mode 100644 index 00000000..ed102697 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-del-nested.textproto @@ -0,0 +1,11 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Delete sentinel must be the value of a top-level key. + +description: "update: Delete cannot be nested" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": {\"b\": \"Delete\"}}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-del-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-del-noarray-nested.textproto new file mode 100644 index 00000000..a2eec496 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-del-noarray-nested.textproto @@ -0,0 +1,13 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Delete sentinel must be the value of a field. Deletes are implemented by +# turning the path to the Delete sentinel into a FieldPath, and FieldPaths do not +# support array indexing. + +description: "update: Delete cannot be anywhere inside an array value" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, {\"b\": \"Delete\"}]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-del-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-del-noarray.textproto new file mode 100644 index 00000000..a7eea87e --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-del-noarray.textproto @@ -0,0 +1,13 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Delete sentinel must be the value of a field. Deletes are implemented by +# turning the path to the Delete sentinel into a FieldPath, and FieldPaths do not +# support array indexing. + +description: "update: Delete cannot be in an array value" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2, \"Delete\"]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-del.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-del.textproto new file mode 100644 index 00000000..ec443e6c --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-del.textproto @@ -0,0 +1,32 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If a field's value is the Delete sentinel, then it doesn't appear in the update +# data, but does in the mask. + +description: "update: Delete" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": \"Delete\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-exists-precond.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-exists-precond.textproto new file mode 100644 index 00000000..3c6fef4e --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-exists-precond.textproto @@ -0,0 +1,14 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Update method does not support an explicit exists precondition. + +description: "update: Exists precondition is invalid" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + precondition: < + exists: true + > + json_data: "{\"a\": 1}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-fp-empty-component.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-fp-empty-component.textproto new file mode 100644 index 00000000..c3bceff3 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-fp-empty-component.textproto @@ -0,0 +1,11 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Empty fields are not allowed. + +description: "update: empty field path component" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a..b\": 1}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-no-paths.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-no-paths.textproto new file mode 100644 index 00000000..b524b748 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-no-paths.textproto @@ -0,0 +1,11 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# It is a client-side error to call Update with empty data. + +description: "update: no paths" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-all-transforms.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-all-transforms.textproto new file mode 100644 index 00000000..8cfad473 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-all-transforms.textproto @@ -0,0 +1,82 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can be created with any amount of transforms. + +description: "update-paths: all transforms in a single call" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + field_paths: < + field: "c" + > + field_paths: < + field: "d" + > + json_values: "1" + json_values: "\"ServerTimestamp\"" + json_values: "[\"ArrayUnion\", 1, 2, 3]" + json_values: "[\"ArrayRemove\", 4, 5, 6]" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + field_transforms: < + field_path: "c" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + field_transforms: < + field_path: "d" + remove_all_from_array: < + values: < + integer_value: 4 + > + values: < + integer_value: 5 + > + values: < + integer_value: 6 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-alone.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-alone.textproto new file mode 100644 index 00000000..68f0e147 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-alone.textproto @@ -0,0 +1,39 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If the only values in the input are ArrayRemove, then no update operation should +# be produced. + +description: "update-paths: ArrayRemove alone" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "[\"ArrayRemove\", 1, 2, 3]" + request: < + database: "projects/projectID/databases/(default)" + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-multi.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-multi.textproto new file mode 100644 index 00000000..b60c3f36 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-multi.textproto @@ -0,0 +1,76 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can have more than one ArrayRemove field. Since all the ArrayRemove +# fields are removed, the only field in the update is "a". + +description: "update-paths: multiple ArrayRemove fields" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + field_paths: < + field: "c" + > + json_values: "1" + json_values: "[\"ArrayRemove\", 1, 2, 3]" + json_values: "{\"d\": [\"ArrayRemove\", 4, 5, 6]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "c" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + field_transforms: < + field_path: "c.d" + remove_all_from_array: < + values: < + integer_value: 4 + > + values: < + integer_value: 5 + > + values: < + integer_value: 6 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-nested.textproto new file mode 100644 index 00000000..381be19d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-nested.textproto @@ -0,0 +1,59 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# An ArrayRemove value can occur at any depth. In this case, the transform applies +# to the field path "b.c". Since "c" is removed from the update, "b" becomes +# empty, so it is also removed from the update. + +description: "update-paths: nested ArrayRemove field" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + json_values: "1" + json_values: "{\"c\": [\"ArrayRemove\", 1, 2, 3]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b.c" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-noarray-nested.textproto new file mode 100644 index 00000000..35f6c67b --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-noarray-nested.textproto @@ -0,0 +1,15 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# There cannot be an array value anywhere on the path from the document root to +# the ArrayRemove. Firestore transforms don't support array indexing. + +description: "update-paths: ArrayRemove cannot be anywhere inside an array value" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "[1, {\"b\": [\"ArrayRemove\", 1, 2, 3]}]" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-noarray.textproto new file mode 100644 index 00000000..45cab48d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-noarray.textproto @@ -0,0 +1,15 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# ArrayRemove must be the value of a field. Firestore transforms don't support +# array indexing. + +description: "update-paths: ArrayRemove cannot be in an array value" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "[1, 2, [\"ArrayRemove\", 1, 2, 3]]" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-with-st.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-with-st.textproto new file mode 100644 index 00000000..67b92a3e --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove-with-st.textproto @@ -0,0 +1,15 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The ServerTimestamp sentinel must be the value of a field. It may not appear in +# an ArrayUnion. + +description: "update-paths: The ServerTimestamp sentinel cannot be in an ArrayUnion" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "[\"ArrayRemove\", 1, \"ServerTimestamp\", 3]" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove.textproto new file mode 100644 index 00000000..d3866676 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayremove.textproto @@ -0,0 +1,57 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A key with ArrayRemove is removed from the data in the update operation. Instead +# it appears in a separate Transform operation. + +description: "update-paths: ArrayRemove with data" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + json_values: "1" + json_values: "[\"ArrayRemove\", 1, 2, 3]" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + remove_all_from_array: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-alone.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-alone.textproto new file mode 100644 index 00000000..48100e0a --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-alone.textproto @@ -0,0 +1,39 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If the only values in the input are ArrayUnion, then no update operation should +# be produced. + +description: "update-paths: ArrayUnion alone" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "[\"ArrayUnion\", 1, 2, 3]" + request: < + database: "projects/projectID/databases/(default)" + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-multi.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-multi.textproto new file mode 100644 index 00000000..03772e5d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-multi.textproto @@ -0,0 +1,76 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can have more than one ArrayUnion field. Since all the ArrayUnion +# fields are removed, the only field in the update is "a". + +description: "update-paths: multiple ArrayUnion fields" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + field_paths: < + field: "c" + > + json_values: "1" + json_values: "[\"ArrayUnion\", 1, 2, 3]" + json_values: "{\"d\": [\"ArrayUnion\", 4, 5, 6]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "c" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + field_transforms: < + field_path: "c.d" + append_missing_elements: < + values: < + integer_value: 4 + > + values: < + integer_value: 5 + > + values: < + integer_value: 6 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-nested.textproto new file mode 100644 index 00000000..1420e4e2 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-nested.textproto @@ -0,0 +1,59 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# An ArrayUnion value can occur at any depth. In this case, the transform applies +# to the field path "b.c". Since "c" is removed from the update, "b" becomes +# empty, so it is also removed from the update. + +description: "update-paths: nested ArrayUnion field" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + json_values: "1" + json_values: "{\"c\": [\"ArrayUnion\", 1, 2, 3]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b.c" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-noarray-nested.textproto new file mode 100644 index 00000000..ab75bf38 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-noarray-nested.textproto @@ -0,0 +1,15 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# There cannot be an array value anywhere on the path from the document root to +# the ArrayUnion. Firestore transforms don't support array indexing. + +description: "update-paths: ArrayUnion cannot be anywhere inside an array value" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "[1, {\"b\": [\"ArrayUnion\", 1, 2, 3]}]" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-noarray.textproto new file mode 100644 index 00000000..fac72644 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-noarray.textproto @@ -0,0 +1,15 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# ArrayUnion must be the value of a field. Firestore transforms don't support +# array indexing. + +description: "update-paths: ArrayUnion cannot be in an array value" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "[1, 2, [\"ArrayRemove\", 1, 2, 3]]" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-with-st.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-with-st.textproto new file mode 100644 index 00000000..d194c09b --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion-with-st.textproto @@ -0,0 +1,15 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The ServerTimestamp sentinel must be the value of a field. It may not appear in +# an ArrayUnion. + +description: "update-paths: The ServerTimestamp sentinel cannot be in an ArrayUnion" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "[\"ArrayUnion\", 1, \"ServerTimestamp\", 3]" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion.textproto new file mode 100644 index 00000000..fc56c1e2 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-arrayunion.textproto @@ -0,0 +1,57 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A key with ArrayUnion is removed from the data in the update operation. Instead +# it appears in a separate Transform operation. + +description: "update-paths: ArrayUnion with data" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + json_values: "1" + json_values: "[\"ArrayUnion\", 1, 2, 3]" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + append_missing_elements: < + values: < + integer_value: 1 + > + values: < + integer_value: 2 + > + values: < + integer_value: 3 + > + > + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-basic.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-basic.textproto new file mode 100644 index 00000000..515f29d6 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-basic.textproto @@ -0,0 +1,33 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A simple call, resulting in a single update operation. + +description: "update-paths: basic" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "1" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-complex.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-complex.textproto new file mode 100644 index 00000000..38a83223 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-complex.textproto @@ -0,0 +1,72 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A call to a write method with complicated input data. + +description: "update-paths: complex" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + json_values: "[1, 2.5]" + json_values: "{\"c\": [\"three\", {\"d\": true}]}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + array_value: < + values: < + integer_value: 1 + > + values: < + double_value: 2.5 + > + > + > + > + fields: < + key: "b" + value: < + map_value: < + fields: < + key: "c" + value: < + array_value: < + values: < + string_value: "three" + > + values: < + map_value: < + fields: < + key: "d" + value: < + boolean_value: true + > + > + > + > + > + > + > + > + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-del-alone.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-del-alone.textproto new file mode 100644 index 00000000..5dbb787d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-del-alone.textproto @@ -0,0 +1,28 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If the input data consists solely of Deletes, then the update operation has no +# map, just an update mask. + +description: "update-paths: Delete alone" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "\"Delete\"" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-del-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-del-nested.textproto new file mode 100644 index 00000000..bdf65fb0 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-del-nested.textproto @@ -0,0 +1,14 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Delete sentinel must be the value of a top-level key. + +description: "update-paths: Delete cannot be nested" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "{\"b\": \"Delete\"}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-del-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-del-noarray-nested.textproto new file mode 100644 index 00000000..d3da15dd --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-del-noarray-nested.textproto @@ -0,0 +1,16 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Delete sentinel must be the value of a field. Deletes are implemented by +# turning the path to the Delete sentinel into a FieldPath, and FieldPaths do not +# support array indexing. + +description: "update-paths: Delete cannot be anywhere inside an array value" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "[1, {\"b\": \"Delete\"}]" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-del-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-del-noarray.textproto new file mode 100644 index 00000000..9ebdd094 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-del-noarray.textproto @@ -0,0 +1,16 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Delete sentinel must be the value of a field. Deletes are implemented by +# turning the path to the Delete sentinel into a FieldPath, and FieldPaths do not +# support array indexing. + +description: "update-paths: Delete cannot be in an array value" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "[1, 2, \"Delete\"]" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-del.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-del.textproto new file mode 100644 index 00000000..5197a784 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-del.textproto @@ -0,0 +1,39 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If a field's value is the Delete sentinel, then it doesn't appear in the update +# data, but does in the mask. + +description: "update-paths: Delete" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + json_values: "1" + json_values: "\"Delete\"" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-exists-precond.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-exists-precond.textproto new file mode 100644 index 00000000..084e0772 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-exists-precond.textproto @@ -0,0 +1,17 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Update method does not support an explicit exists precondition. + +description: "update-paths: Exists precondition is invalid" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + precondition: < + exists: true + > + field_paths: < + field: "a" + > + json_values: "1" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-del.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-del.textproto new file mode 100644 index 00000000..5c92aeb8 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-del.textproto @@ -0,0 +1,47 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If one nested field is deleted, and another isn't, preserve the second. + +description: "update-paths: field paths with delete" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "foo" + field: "bar" + > + field_paths: < + field: "foo" + field: "delete" + > + json_values: "1" + json_values: "\"Delete\"" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "foo" + value: < + map_value: < + fields: < + key: "bar" + value: < + integer_value: 1 + > + > + > + > + > + > + update_mask: < + field_paths: "foo.bar" + field_paths: "foo.delete" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-dup-transforms.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-dup-transforms.textproto new file mode 100644 index 00000000..a84725a8 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-dup-transforms.textproto @@ -0,0 +1,23 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The same field cannot occur more than once, even if all the operations are +# transforms. + +description: "update-paths: duplicate field path with only transforms" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + field_paths: < + field: "a" + > + json_values: "[\"ArrayUnion\", 1, 2, 3]" + json_values: "\"ServerTimestamp\"" + json_values: "[\"ArrayUnion\", 4, 5, 6]" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-dup.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-dup.textproto new file mode 100644 index 00000000..fedbd3aa --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-dup.textproto @@ -0,0 +1,22 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The same field cannot occur more than once. + +description: "update-paths: duplicate field path" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + field_paths: < + field: "a" + > + json_values: "1" + json_values: "2" + json_values: "3" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-empty-component.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-empty-component.textproto new file mode 100644 index 00000000..7a5df25b --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-empty-component.textproto @@ -0,0 +1,15 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Empty fields are not allowed. + +description: "update-paths: empty field path component" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "*" + field: "" + > + json_values: "1" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-empty.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-empty.textproto new file mode 100644 index 00000000..311e3093 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-empty.textproto @@ -0,0 +1,13 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A FieldPath of length zero is invalid. + +description: "update-paths: empty field path" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + > + json_values: "1" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-multi.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-multi.textproto new file mode 100644 index 00000000..9ba41e39 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-multi.textproto @@ -0,0 +1,42 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The UpdatePaths or equivalent method takes a list of FieldPaths. Each FieldPath +# is a sequence of uninterpreted path components. + +description: "update-paths: multiple-element field path" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + field: "b" + > + json_values: "1" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + map_value: < + fields: < + key: "b" + value: < + integer_value: 1 + > + > + > + > + > + > + update_mask: < + field_paths: "a.b" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-nosplit.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-nosplit.textproto new file mode 100644 index 00000000..51649526 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-fp-nosplit.textproto @@ -0,0 +1,48 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# FieldPath components are not split on dots. + +description: "update-paths: FieldPath elements are not split on dots" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a.b" + field: "f.g" + > + json_values: "{\"n.o\": 7}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a.b" + value: < + map_value: < + fields: < + key: "f.g" + value: < + map_value: < + fields: < + key: "n.o" + value: < + integer_value: 7 + > + > + > + > + > + > + > + > + > + update_mask: < + field_paths: "`a.b`.`f.g`" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-no-paths.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-no-paths.textproto new file mode 100644 index 00000000..d9939dc9 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-no-paths.textproto @@ -0,0 +1,10 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# It is a client-side error to call Update with empty data. + +description: "update-paths: no paths" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-prefix-1.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-prefix-1.textproto new file mode 100644 index 00000000..1710b910 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-prefix-1.textproto @@ -0,0 +1,19 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# In the input data, one field cannot be a prefix of another. + +description: "update-paths: prefix #1" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + field: "b" + > + field_paths: < + field: "a" + > + json_values: "1" + json_values: "2" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-prefix-2.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-prefix-2.textproto new file mode 100644 index 00000000..be78ab58 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-prefix-2.textproto @@ -0,0 +1,19 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# In the input data, one field cannot be a prefix of another. + +description: "update-paths: prefix #2" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "a" + field: "b" + > + json_values: "1" + json_values: "2" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-prefix-3.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-prefix-3.textproto new file mode 100644 index 00000000..b8a84c9d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-prefix-3.textproto @@ -0,0 +1,20 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# In the input data, one field cannot be a prefix of another, even if the values +# could in principle be combined. + +description: "update-paths: prefix #3" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "a" + field: "d" + > + json_values: "{\"b\": 1}" + json_values: "2" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-special-chars.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-special-chars.textproto new file mode 100644 index 00000000..51cb33b3 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-special-chars.textproto @@ -0,0 +1,53 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# FieldPaths can contain special characters. + +description: "update-paths: special characters" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "*" + field: "~" + > + field_paths: < + field: "*" + field: "`" + > + json_values: "1" + json_values: "2" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "*" + value: < + map_value: < + fields: < + key: "`" + value: < + integer_value: 2 + > + > + fields: < + key: "~" + value: < + integer_value: 1 + > + > + > + > + > + > + update_mask: < + field_paths: "`*`.`\\``" + field_paths: "`*`.`~`" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-alone.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-alone.textproto new file mode 100644 index 00000000..abc44f55 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-alone.textproto @@ -0,0 +1,29 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If the only values in the input are ServerTimestamps, then no update operation +# should be produced. + +description: "update-paths: ServerTimestamp alone" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "\"ServerTimestamp\"" + request: < + database: "projects/projectID/databases/(default)" + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a" + set_to_server_value: REQUEST_TIME + > + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-multi.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-multi.textproto new file mode 100644 index 00000000..b0b7df17 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-multi.textproto @@ -0,0 +1,56 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can have more than one ServerTimestamp field. Since all the +# ServerTimestamp fields are removed, the only field in the update is "a". + +description: "update-paths: multiple ServerTimestamp fields" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + field_paths: < + field: "c" + > + json_values: "1" + json_values: "\"ServerTimestamp\"" + json_values: "{\"d\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "c" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + field_transforms: < + field_path: "c.d" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-nested.textproto new file mode 100644 index 00000000..30773683 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-nested.textproto @@ -0,0 +1,49 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A ServerTimestamp value can occur at any depth. In this case, the transform +# applies to the field path "b.c". Since "c" is removed from the update, "b" +# becomes empty, so it is also removed from the update. + +description: "update-paths: nested ServerTimestamp field" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + json_values: "1" + json_values: "{\"c\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b.c" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-noarray-nested.textproto new file mode 100644 index 00000000..2c2cb89b --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-noarray-nested.textproto @@ -0,0 +1,15 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# There cannot be an array value anywhere on the path from the document root to +# the ServerTimestamp sentinel. Firestore transforms don't support array indexing. + +description: "update-paths: ServerTimestamp cannot be anywhere inside an array value" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "[1, {\"b\": \"ServerTimestamp\"}]" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-noarray.textproto new file mode 100644 index 00000000..a2baa66f --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-noarray.textproto @@ -0,0 +1,15 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The ServerTimestamp sentinel must be the value of a field. Firestore transforms +# don't support array indexing. + +description: "update-paths: ServerTimestamp cannot be in an array value" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "[1, 2, \"ServerTimestamp\"]" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-with-empty-map.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-with-empty-map.textproto new file mode 100644 index 00000000..a54a2415 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st-with-empty-map.textproto @@ -0,0 +1,51 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# When a ServerTimestamp and a map both reside inside a map, the ServerTimestamp +# should be stripped out but the empty map should remain. + +description: "update-paths: ServerTimestamp beside an empty map" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + json_values: "{\"b\": {}, \"c\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + map_value: < + fields: < + key: "b" + value: < + map_value: < + > + > + > + > + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a.c" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-st.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st.textproto new file mode 100644 index 00000000..40634c16 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-st.textproto @@ -0,0 +1,49 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A key with the special ServerTimestamp sentinel is removed from the data in the +# update operation. Instead it appears in a separate Transform operation. Note +# that in these tests, the string "ServerTimestamp" should be replaced with the +# special ServerTimestamp value. + +description: "update-paths: ServerTimestamp with data" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + field_paths: < + field: "a" + > + field_paths: < + field: "b" + > + json_values: "1" + json_values: "\"ServerTimestamp\"" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-paths-uptime.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-paths-uptime.textproto new file mode 100644 index 00000000..7a15874b --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-paths-uptime.textproto @@ -0,0 +1,40 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Update call supports a last-update-time precondition. + +description: "update-paths: last-update-time precondition" +update_paths: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + precondition: < + update_time: < + seconds: 42 + > + > + field_paths: < + field: "a" + > + json_values: "1" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + update_time: < + seconds: 42 + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-prefix-1.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-prefix-1.textproto new file mode 100644 index 00000000..e5c895e7 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-prefix-1.textproto @@ -0,0 +1,11 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# In the input data, one field cannot be a prefix of another. + +description: "update: prefix #1" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a.b\": 1, \"a\": 2}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-prefix-2.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-prefix-2.textproto new file mode 100644 index 00000000..48701761 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-prefix-2.textproto @@ -0,0 +1,11 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# In the input data, one field cannot be a prefix of another. + +description: "update: prefix #2" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"a.b\": 2}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-prefix-3.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-prefix-3.textproto new file mode 100644 index 00000000..0c03b0d6 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-prefix-3.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# In the input data, one field cannot be a prefix of another, even if the values +# could in principle be combined. + +description: "update: prefix #3" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": {\"b\": 1}, \"a.d\": 2}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-quoting.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-quoting.textproto new file mode 100644 index 00000000..20e530a7 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-quoting.textproto @@ -0,0 +1,45 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# In a field path, any component beginning with a non-letter or underscore is +# quoted. + +description: "update: non-letter starting chars are quoted, except underscore" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"_0.1.+2\": 1}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "_0" + value: < + map_value: < + fields: < + key: "1" + value: < + map_value: < + fields: < + key: "+2" + value: < + integer_value: 1 + > + > + > + > + > + > + > + > + > + update_mask: < + field_paths: "_0.`1`.`+2`" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-split-top-level.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-split-top-level.textproto new file mode 100644 index 00000000..d1b0ca0d --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-split-top-level.textproto @@ -0,0 +1,45 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Update method splits only top-level keys at dots. Keys at other levels are +# taken literally. + +description: "update: Split on dots for top-level keys only" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"h.g\": {\"j.k\": 6}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "h" + value: < + map_value: < + fields: < + key: "g" + value: < + map_value: < + fields: < + key: "j.k" + value: < + integer_value: 6 + > + > + > + > + > + > + > + > + > + update_mask: < + field_paths: "h.g" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-split.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-split.textproto new file mode 100644 index 00000000..b96fd6a4 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-split.textproto @@ -0,0 +1,44 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Update method splits top-level keys at dots. + +description: "update: split on dots" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a.b.c\": 1}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + map_value: < + fields: < + key: "b" + value: < + map_value: < + fields: < + key: "c" + value: < + integer_value: 1 + > + > + > + > + > + > + > + > + > + update_mask: < + field_paths: "a.b.c" + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-st-alone.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-st-alone.textproto new file mode 100644 index 00000000..0d5ab6e9 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-st-alone.textproto @@ -0,0 +1,26 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# If the only values in the input are ServerTimestamps, then no update operation +# should be produced. + +description: "update: ServerTimestamp alone" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a" + set_to_server_value: REQUEST_TIME + > + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-st-dot.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-st-dot.textproto new file mode 100644 index 00000000..19d4d184 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-st-dot.textproto @@ -0,0 +1,27 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# Like other uses of ServerTimestamp, the data is pruned and the field does not +# appear in the update mask, because it is in the transform. In this case An +# update operation is produced just to hold the precondition. + +description: "update: ServerTimestamp with dotted field" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a.b.c\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a.b.c" + set_to_server_value: REQUEST_TIME + > + > + current_document: < + exists: true + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-st-multi.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-st-multi.textproto new file mode 100644 index 00000000..0434cb59 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-st-multi.textproto @@ -0,0 +1,49 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A document can have more than one ServerTimestamp field. Since all the +# ServerTimestamp fields are removed, the only field in the update is "a". + +# b is not in the mask because it will be set in the transform. c must be in the +# mask: it should be replaced entirely. The transform will set c.d to the +# timestamp, but the update will delete the rest of c. + +description: "update: multiple ServerTimestamp fields" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": \"ServerTimestamp\", \"c\": {\"d\": \"ServerTimestamp\"}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "c" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + field_transforms: < + field_path: "c.d" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-st-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-st-nested.textproto new file mode 100644 index 00000000..f79d9c6a --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-st-nested.textproto @@ -0,0 +1,42 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A ServerTimestamp value can occur at any depth. In this case, the transform +# applies to the field path "b.c". Since "c" is removed from the update, "b" +# becomes empty, so it is also removed from the update. + +description: "update: nested ServerTimestamp field" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": {\"c\": \"ServerTimestamp\"}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + field_paths: "b" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b.c" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-st-noarray-nested.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-st-noarray-nested.textproto new file mode 100644 index 00000000..2939dd64 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-st-noarray-nested.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# There cannot be an array value anywhere on the path from the document root to +# the ServerTimestamp sentinel. Firestore transforms don't support array indexing. + +description: "update: ServerTimestamp cannot be anywhere inside an array value" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, {\"b\": \"ServerTimestamp\"}]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-st-noarray.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-st-noarray.textproto new file mode 100644 index 00000000..f3879cdf --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-st-noarray.textproto @@ -0,0 +1,12 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The ServerTimestamp sentinel must be the value of a field. Firestore transforms +# don't support array indexing. + +description: "update: ServerTimestamp cannot be in an array value" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": [1, 2, \"ServerTimestamp\"]}" + is_error: true +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-st-with-empty-map.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-st-with-empty-map.textproto new file mode 100644 index 00000000..1901de2a --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-st-with-empty-map.textproto @@ -0,0 +1,48 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# When a ServerTimestamp and a map both reside inside a map, the ServerTimestamp +# should be stripped out but the empty map should remain. + +description: "update: ServerTimestamp beside an empty map" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": {\"b\": {}, \"c\": \"ServerTimestamp\"}}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + map_value: < + fields: < + key: "b" + value: < + map_value: < + > + > + > + > + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "a.c" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-st.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-st.textproto new file mode 100644 index 00000000..12045a92 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-st.textproto @@ -0,0 +1,42 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# A key with the special ServerTimestamp sentinel is removed from the data in the +# update operation. Instead it appears in a separate Transform operation. Note +# that in these tests, the string "ServerTimestamp" should be replaced with the +# special ServerTimestamp value. + +description: "update: ServerTimestamp with data" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + json_data: "{\"a\": 1, \"b\": \"ServerTimestamp\"}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + exists: true + > + > + writes: < + transform: < + document: "projects/projectID/databases/(default)/documents/C/d" + field_transforms: < + field_path: "b" + set_to_server_value: REQUEST_TIME + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/testdata/update-uptime.textproto b/vendor/cloud.google.com/go/firestore/testdata/update-uptime.textproto new file mode 100644 index 00000000..66119ac6 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/testdata/update-uptime.textproto @@ -0,0 +1,37 @@ +# DO NOT MODIFY. This file was generated by +# github.com/GoogleCloudPlatform/google-cloud-common/testing/firestore/cmd/generate-firestore-tests/generate-firestore-tests.go. + +# The Update call supports a last-update-time precondition. + +description: "update: last-update-time precondition" +update: < + doc_ref_path: "projects/projectID/databases/(default)/documents/C/d" + precondition: < + update_time: < + seconds: 42 + > + > + json_data: "{\"a\": 1}" + request: < + database: "projects/projectID/databases/(default)" + writes: < + update: < + name: "projects/projectID/databases/(default)/documents/C/d" + fields: < + key: "a" + value: < + integer_value: 1 + > + > + > + update_mask: < + field_paths: "a" + > + current_document: < + update_time: < + seconds: 42 + > + > + > + > +> diff --git a/vendor/cloud.google.com/go/firestore/to_value.go b/vendor/cloud.google.com/go/firestore/to_value.go new file mode 100644 index 00000000..03236b25 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/to_value.go @@ -0,0 +1,299 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "errors" + "fmt" + "reflect" + "time" + + "cloud.google.com/go/internal/fields" + "github.com/golang/protobuf/ptypes" + ts "github.com/golang/protobuf/ptypes/timestamp" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/genproto/googleapis/type/latlng" +) + +var nullValue = &pb.Value{ValueType: &pb.Value_NullValue{}} + +var ( + typeOfByteSlice = reflect.TypeOf([]byte{}) + typeOfGoTime = reflect.TypeOf(time.Time{}) + typeOfLatLng = reflect.TypeOf((*latlng.LatLng)(nil)) + typeOfDocumentRef = reflect.TypeOf((*DocumentRef)(nil)) + typeOfProtoTimestamp = reflect.TypeOf((*ts.Timestamp)(nil)) +) + +// toProtoValue converts a Go value to a Firestore Value protobuf. +// Some corner cases: +// - All nils (nil interface, nil slice, nil map, nil pointer) are converted to +// a NullValue (not a nil *pb.Value). toProtoValue never returns (nil, false, nil). +// It returns (nil, true, nil) if everything in the value is ServerTimestamp. +// - An error is returned for uintptr, uint and uint64, because Firestore uses +// an int64 to represent integral values, and those types can't be properly +// represented in an int64. +// - An error is returned for the special Delete value. +// +// toProtoValue also reports whether it recursively encountered a transform. +func toProtoValue(v reflect.Value) (pbv *pb.Value, sawTransform bool, err error) { + if !v.IsValid() { + return nullValue, false, nil + } + vi := v.Interface() + if vi == Delete { + return nil, false, errors.New("firestore: cannot use Delete in value") + } + if vi == ServerTimestamp { + return nil, false, errors.New("firestore: must use ServerTimestamp as a map value") + } + switch x := vi.(type) { + case []byte: + return &pb.Value{ValueType: &pb.Value_BytesValue{x}}, false, nil + case time.Time: + ts, err := ptypes.TimestampProto(x) + if err != nil { + return nil, false, err + } + return &pb.Value{ValueType: &pb.Value_TimestampValue{ts}}, false, nil + case *ts.Timestamp: + if x == nil { + // gRPC doesn't like nil oneofs. Use NullValue. + return nullValue, false, nil + } + return &pb.Value{ValueType: &pb.Value_TimestampValue{x}}, false, nil + case *latlng.LatLng: + if x == nil { + // gRPC doesn't like nil oneofs. Use NullValue. + return nullValue, false, nil + } + return &pb.Value{ValueType: &pb.Value_GeoPointValue{x}}, false, nil + case *DocumentRef: + if x == nil { + // gRPC doesn't like nil oneofs. Use NullValue. + return nullValue, false, nil + } + return &pb.Value{ValueType: &pb.Value_ReferenceValue{x.Path}}, false, nil + // Do not add bool, string, int, etc. to this switch; leave them in the + // reflect-based switch below. Moving them here would drop support for + // types whose underlying types are those primitives. + // E.g. Given "type mybool bool", an ordinary type switch on bool will + // not catch a mybool, but the reflect.Kind of a mybool is reflect.Bool. + } + switch v.Kind() { + case reflect.Bool: + return &pb.Value{ValueType: &pb.Value_BooleanValue{v.Bool()}}, false, nil + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return &pb.Value{ValueType: &pb.Value_IntegerValue{v.Int()}}, false, nil + case reflect.Uint8, reflect.Uint16, reflect.Uint32: + return &pb.Value{ValueType: &pb.Value_IntegerValue{int64(v.Uint())}}, false, nil + case reflect.Float32, reflect.Float64: + return &pb.Value{ValueType: &pb.Value_DoubleValue{v.Float()}}, false, nil + case reflect.String: + return &pb.Value{ValueType: &pb.Value_StringValue{v.String()}}, false, nil + case reflect.Slice: + return sliceToProtoValue(v) + case reflect.Map: + return mapToProtoValue(v) + case reflect.Struct: + return structToProtoValue(v) + case reflect.Ptr: + if v.IsNil() { + return nullValue, false, nil + } + return toProtoValue(v.Elem()) + case reflect.Interface: + if v.NumMethod() == 0 { // empty interface: recurse on its contents + return toProtoValue(v.Elem()) + } + fallthrough // any other interface value is an error + + default: + return nil, false, fmt.Errorf("firestore: cannot convert type %s to value", v.Type()) + } +} + +// sliceToProtoValue converts a slice to a Firestore Value protobuf and reports +// whether a transform was encountered. +func sliceToProtoValue(v reflect.Value) (*pb.Value, bool, error) { + // A nil slice is converted to a null value. + if v.IsNil() { + return nullValue, false, nil + } + vals := make([]*pb.Value, v.Len()) + for i := 0; i < v.Len(); i++ { + val, sawTransform, err := toProtoValue(v.Index(i)) + if err != nil { + return nil, false, err + } + if sawTransform { + return nil, false, fmt.Errorf("firestore: transforms cannot occur in an array, but saw some in %v", v.Index(i)) + } + vals[i] = val + } + return &pb.Value{ValueType: &pb.Value_ArrayValue{&pb.ArrayValue{Values: vals}}}, false, nil +} + +// mapToProtoValue converts a map to a Firestore Value protobuf and reports whether +// a transform was encountered. +func mapToProtoValue(v reflect.Value) (*pb.Value, bool, error) { + if v.Type().Key().Kind() != reflect.String { + return nil, false, errors.New("firestore: map key type must be string") + } + // A nil map is converted to a null value. + if v.IsNil() { + return nullValue, false, nil + } + m := map[string]*pb.Value{} + sawTransform := false + for _, k := range v.MapKeys() { + mi := v.MapIndex(k) + if mi.Interface() == ServerTimestamp { + sawTransform = true + continue + } else if _, ok := mi.Interface().(arrayUnion); ok { + sawTransform = true + continue + } else if _, ok := mi.Interface().(arrayRemove); ok { + sawTransform = true + continue + } + val, sst, err := toProtoValue(mi) + if err != nil { + return nil, false, err + } + if sst { + sawTransform = true + } + if val == nil { // value was a map with all ServerTimestamp values + continue + } + m[k.String()] = val + } + var pv *pb.Value + if len(m) == 0 && sawTransform { + // The entire map consisted of transform values. + pv = nil + } else { + pv = &pb.Value{ValueType: &pb.Value_MapValue{&pb.MapValue{Fields: m}}} + } + return pv, sawTransform, nil +} + +// structToProtoValue converts a struct to a Firestore Value protobuf and reports +// whether a transform was encountered. +func structToProtoValue(v reflect.Value) (*pb.Value, bool, error) { + m := map[string]*pb.Value{} + fields, err := fieldCache.Fields(v.Type()) + if err != nil { + return nil, false, err + } + sawTransform := false + if _, ok := v.Interface().(arrayUnion); ok { + return nil, false, errors.New("firestore: ArrayUnion may not be used in structs") + } + if _, ok := v.Interface().(arrayRemove); ok { + return nil, false, errors.New("firestore: ArrayRemove may not be used in structs") + } + + for _, f := range fields { + fv := v.FieldByIndex(f.Index) + opts := f.ParsedTag.(tagOptions) + if opts.serverTimestamp { + // TODO(jba): should we return a non-zero time? + sawTransform = true + continue + } + if opts.omitEmpty && isEmptyValue(fv) { + continue + } + val, sst, err := toProtoValue(fv) + if err != nil { + return nil, false, err + } + if sst { + sawTransform = true + } + if val == nil { // value was a map with all ServerTimestamp values + continue + } + m[f.Name] = val + } + var pv *pb.Value + if len(m) == 0 && sawTransform { + // The entire struct consisted of ServerTimestamp or omitempty values. + pv = nil + } else { + pv = &pb.Value{ValueType: &pb.Value_MapValue{&pb.MapValue{Fields: m}}} + } + return pv, sawTransform, nil +} + +type tagOptions struct { + omitEmpty bool // do not marshal value if empty + serverTimestamp bool // set time.Time to server timestamp on write +} + +// parseTag interprets firestore struct field tags. +func parseTag(t reflect.StructTag) (name string, keep bool, other interface{}, err error) { + name, keep, opts, err := fields.ParseStandardTag("firestore", t) + if err != nil { + return "", false, nil, fmt.Errorf("firestore: %v", err) + } + tagOpts := tagOptions{} + for _, opt := range opts { + switch opt { + case "omitempty": + tagOpts.omitEmpty = true + case "serverTimestamp": + tagOpts.serverTimestamp = true + default: + return "", false, nil, fmt.Errorf("firestore: unknown tag option: %q", opt) + } + } + return name, keep, tagOpts, nil +} + +// isLeafType determines whether or not a type is a 'leaf type' +// and should not be recursed into, but considered one field. +func isLeafType(t reflect.Type) bool { + return t == typeOfGoTime || t == typeOfLatLng || t == typeOfProtoTimestamp +} + +var fieldCache = fields.NewCache(parseTag, nil, isLeafType) + +// isEmptyValue is taken from the encoding/json package in the +// standard library. +// TODO(jba): move to the fields package +func isEmptyValue(v reflect.Value) bool { + switch v.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + } + if v.Type() == typeOfGoTime { + return v.Interface().(time.Time).IsZero() + } + return false +} diff --git a/vendor/cloud.google.com/go/firestore/to_value_test.go b/vendor/cloud.google.com/go/firestore/to_value_test.go new file mode 100644 index 00000000..24611022 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/to_value_test.go @@ -0,0 +1,307 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "fmt" + "reflect" + "testing" + "time" + + ts "github.com/golang/protobuf/ptypes/timestamp" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/genproto/googleapis/type/latlng" +) + +type testStruct1 struct { + B bool + I int + U uint32 + F float64 + S string + Y []byte + T time.Time + Ts *ts.Timestamp + G *latlng.LatLng + L []int + M map[string]int + P *int +} + +var ( + p = new(int) + + testVal1 = testStruct1{ + B: true, + I: 1, + U: 2, + F: 3.0, + S: "four", + Y: []byte{5}, + T: tm, + Ts: ptm, + G: ll, + L: []int{6}, + M: map[string]int{"a": 7}, + P: p, + } + + mapVal1 = mapval(map[string]*pb.Value{ + "B": boolval(true), + "I": intval(1), + "U": intval(2), + "F": floatval(3), + "S": {ValueType: &pb.Value_StringValue{"four"}}, + "Y": bytesval([]byte{5}), + "T": tsval(tm), + "Ts": {ValueType: &pb.Value_TimestampValue{ptm}}, + "G": geoval(ll), + "L": arrayval(intval(6)), + "M": mapval(map[string]*pb.Value{"a": intval(7)}), + "P": intval(8), + }) +) + +func TestToProtoValue(t *testing.T) { + *p = 8 + for _, test := range []struct { + in interface{} + want *pb.Value + }{ + {nil, nullValue}, + {[]int(nil), nullValue}, + {map[string]int(nil), nullValue}, + {(*testStruct1)(nil), nullValue}, + {(*ts.Timestamp)(nil), nullValue}, + {(*latlng.LatLng)(nil), nullValue}, + {(*DocumentRef)(nil), nullValue}, + {true, boolval(true)}, + {3, intval(3)}, + {uint32(3), intval(3)}, + {1.5, floatval(1.5)}, + {"str", strval("str")}, + {[]byte{1, 2}, bytesval([]byte{1, 2})}, + {tm, tsval(tm)}, + {ptm, &pb.Value{ValueType: &pb.Value_TimestampValue{ptm}}}, + {ll, geoval(ll)}, + {[]int{1, 2}, arrayval(intval(1), intval(2))}, + {&[]int{1, 2}, arrayval(intval(1), intval(2))}, + {[]int{}, arrayval()}, + {map[string]int{"a": 1, "b": 2}, + mapval(map[string]*pb.Value{"a": intval(1), "b": intval(2)})}, + {map[string]int{}, mapval(map[string]*pb.Value{})}, + {p, intval(8)}, + {&p, intval(8)}, + {map[string]interface{}{"a": 1, "p": p, "s": "str"}, + mapval(map[string]*pb.Value{"a": intval(1), "p": intval(8), "s": strval("str")})}, + {map[string]fmt.Stringer{"a": tm}, + mapval(map[string]*pb.Value{"a": tsval(tm)})}, + {testVal1, mapVal1}, + { + &DocumentRef{ + ID: "d", + Path: "projects/P/databases/D/documents/c/d", + Parent: &CollectionRef{ + ID: "c", + parentPath: "projects/P/databases/D", + Path: "projects/P/databases/D/documents/c", + Query: Query{collectionID: "c", parentPath: "projects/P/databases/D"}, + }, + }, + refval("projects/P/databases/D/documents/c/d"), + }, + // ServerTimestamps are removed, possibly leaving nil. + {map[string]interface{}{"a": ServerTimestamp}, nil}, + { + map[string]interface{}{ + "a": map[string]interface{}{ + "b": map[string]interface{}{ + "c": ServerTimestamp, + }, + }, + }, + nil, + }, + { + map[string]interface{}{ + "a": map[string]interface{}{ + "b": map[string]interface{}{ + "c": ServerTimestamp, + "d": ServerTimestamp, + }, + }, + }, + nil, + }, + { + map[string]interface{}{ + "a": map[string]interface{}{ + "b": map[string]interface{}{ + "c": ServerTimestamp, + "d": ServerTimestamp, + "e": 1, + }, + }, + }, + mapval(map[string]*pb.Value{ + "a": mapval(map[string]*pb.Value{ + "b": mapval(map[string]*pb.Value{"e": intval(1)}), + }), + }), + }, + + // Transforms are allowed in maps, but won't show up in the returned proto. Instead, we rely + // on seeing sawTransforms=true and a call to extractTransforms. + {map[string]interface{}{"a": ServerTimestamp, "b": 5}, mapval(map[string]*pb.Value{"b": intval(5)})}, + {map[string]interface{}{"a": ArrayUnion(1, 2, 3), "b": 5}, mapval(map[string]*pb.Value{"b": intval(5)})}, + {map[string]interface{}{"a": ArrayRemove(1, 2, 3), "b": 5}, mapval(map[string]*pb.Value{"b": intval(5)})}, + } { + got, _, err := toProtoValue(reflect.ValueOf(test.in)) + if err != nil { + t.Errorf("%v (%T): %v", test.in, test.in, err) + continue + } + if !testEqual(got, test.want) { + t.Errorf("%+v (%T):\ngot\n%+v\nwant\n%+v", test.in, test.in, got, test.want) + } + } +} + +type stringy struct{} + +func (stringy) String() string { return "stringy" } + +func TestToProtoValueErrors(t *testing.T) { + for _, in := range []interface{}{ + uint64(0), // a bad fit for int64 + map[int]bool{}, // map key type is not string + make(chan int), // can't handle type + map[string]fmt.Stringer{"a": stringy{}}, // only empty interfaces + ServerTimestamp, // ServerTimestamp can only be a field value + struct{ A interface{} }{A: ServerTimestamp}, + map[string]interface{}{"a": []interface{}{ServerTimestamp}}, + map[string]interface{}{"a": []interface{}{ + map[string]interface{}{"b": ServerTimestamp}, + }}, + Delete, // Delete should never appear + []interface{}{Delete}, + map[string]interface{}{"a": Delete}, + map[string]interface{}{"a": []interface{}{Delete}}, + + // Transforms are not allowed to occur in an array. + []interface{}{ServerTimestamp}, + []interface{}{ArrayUnion(1, 2, 3)}, + []interface{}{ArrayRemove(1, 2, 3)}, + + // Transforms are not allowed to occur in a struct. + struct{ A interface{} }{A: ServerTimestamp}, + struct{ A interface{} }{A: ArrayUnion()}, + struct{ A interface{} }{A: ArrayRemove()}, + } { + _, _, err := toProtoValue(reflect.ValueOf(in)) + if err == nil { + t.Errorf("%v: got nil, want error", in) + } + } +} + +func TestToProtoValue_SawTransform(t *testing.T) { + for i, in := range []interface{}{ + map[string]interface{}{"a": ServerTimestamp}, + map[string]interface{}{"a": ArrayUnion()}, + map[string]interface{}{"a": ArrayRemove()}, + } { + _, sawTransform, err := toProtoValue(reflect.ValueOf(in)) + if err != nil { + t.Fatalf("%d %v: got err %v\nexpected nil", i, in, err) + } + if !sawTransform { + t.Errorf("%d %v: got sawTransform=false, expected sawTransform=true", i, in) + } + } +} + +type testStruct2 struct { + Ignore int `firestore:"-"` + Rename int `firestore:"a"` + OmitEmpty int `firestore:",omitempty"` + OmitEmptyTime time.Time `firestore:",omitempty"` +} + +func TestToProtoValueTags(t *testing.T) { + in := &testStruct2{ + Ignore: 1, + Rename: 2, + OmitEmpty: 3, + OmitEmptyTime: aTime, + } + got, _, err := toProtoValue(reflect.ValueOf(in)) + if err != nil { + t.Fatal(err) + } + want := mapval(map[string]*pb.Value{ + "a": intval(2), + "OmitEmpty": intval(3), + "OmitEmptyTime": tsval(aTime), + }) + if !testEqual(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } + + got, _, err = toProtoValue(reflect.ValueOf(testStruct2{})) + if err != nil { + t.Fatal(err) + } + want = mapval(map[string]*pb.Value{"a": intval(0)}) + if !testEqual(got, want) { + t.Errorf("got\n%+v\nwant\n%+v", got, want) + } +} + +func TestToProtoValueEmbedded(t *testing.T) { + // Embedded time.Time, LatLng, or Timestamp should behave like non-embedded. + type embed struct { + time.Time + *latlng.LatLng + *ts.Timestamp + } + + got, _, err := toProtoValue(reflect.ValueOf(embed{tm, ll, ptm})) + if err != nil { + t.Fatal(err) + } + want := mapval(map[string]*pb.Value{ + "Time": tsval(tm), + "LatLng": geoval(ll), + "Timestamp": {ValueType: &pb.Value_TimestampValue{ptm}}, + }) + if !testEqual(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } +} + +func TestIsEmpty(t *testing.T) { + for _, e := range []interface{}{int(0), float32(0), false, "", []int{}, []int(nil), (*int)(nil)} { + if !isEmptyValue(reflect.ValueOf(e)) { + t.Errorf("%v (%T): want true, got false", e, e) + } + } + i := 3 + for _, n := range []interface{}{int(1), float32(1), true, "x", []int{1}, &i} { + if isEmptyValue(reflect.ValueOf(n)) { + t.Errorf("%v (%T): want false, got true", n, n) + } + } +} diff --git a/vendor/cloud.google.com/go/firestore/transaction.go b/vendor/cloud.google.com/go/firestore/transaction.go new file mode 100644 index 00000000..5bfe3e78 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/transaction.go @@ -0,0 +1,282 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "errors" + + gax "github.com/googleapis/gax-go" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// Transaction represents a Firestore transaction. +type Transaction struct { + c *Client + ctx context.Context + id []byte + writes []*pb.Write + maxAttempts int + readOnly bool + readAfterWrite bool +} + +// A TransactionOption is an option passed to Client.Transaction. +type TransactionOption interface { + config(t *Transaction) +} + +// MaxAttempts is a TransactionOption that configures the maximum number of times to +// try a transaction. In defaults to DefaultTransactionMaxAttempts. +func MaxAttempts(n int) maxAttempts { return maxAttempts(n) } + +type maxAttempts int + +func (m maxAttempts) config(t *Transaction) { t.maxAttempts = int(m) } + +// DefaultTransactionMaxAttempts is the default number of times to attempt a transaction. +const DefaultTransactionMaxAttempts = 5 + +// ReadOnly is a TransactionOption that makes the transaction read-only. Read-only +// transactions cannot issue write operations, but are more efficient. +var ReadOnly = ro{} + +type ro struct{} + +func (ro) config(t *Transaction) { t.readOnly = true } + +var ( + // Defined here for testing. + errReadAfterWrite = errors.New("firestore: read after write in transaction") + errWriteReadOnly = errors.New("firestore: write in read-only transaction") + errNonTransactionalOp = errors.New("firestore: non-transactional operation inside a transaction") + errNestedTransaction = errors.New("firestore: nested transaction") +) + +type transactionInProgressKey struct{} + +func checkTransaction(ctx context.Context) error { + if ctx.Value(transactionInProgressKey{}) != nil { + return errNonTransactionalOp + } + return nil +} + +// RunTransaction runs f in a transaction. f should use the transaction it is given +// for all Firestore operations. For any operation requiring a context, f should use +// the context it is passed, not the first argument to RunTransaction. +// +// f must not call Commit or Rollback on the provided Transaction. +// +// If f returns nil, RunTransaction commits the transaction. If the commit fails due +// to a conflicting transaction, RunTransaction retries f. It gives up and returns an +// error after a number of attempts that can be configured with the MaxAttempts +// option. If the commit succeeds, RunTransaction returns a nil error. +// +// If f returns non-nil, then the transaction will be rolled back and +// this method will return the same error. The function f is not retried. +// +// Note that when f returns, the transaction is not committed. Calling code +// must not assume that any of f's changes have been committed until +// RunTransaction returns nil. +// +// Since f may be called more than once, f should usually be idempotent – that is, it +// should have the same result when called multiple times. +func (c *Client) RunTransaction(ctx context.Context, f func(context.Context, *Transaction) error, opts ...TransactionOption) error { + if ctx.Value(transactionInProgressKey{}) != nil { + return errNestedTransaction + } + db := c.path() + t := &Transaction{ + c: c, + ctx: withResourceHeader(ctx, db), + maxAttempts: DefaultTransactionMaxAttempts, + } + for _, opt := range opts { + opt.config(t) + } + var txOpts *pb.TransactionOptions + if t.readOnly { + txOpts = &pb.TransactionOptions{ + Mode: &pb.TransactionOptions_ReadOnly_{&pb.TransactionOptions_ReadOnly{}}, + } + } + var backoff gax.Backoff + // TODO(jba): use other than the standard backoff parameters? + // TODO(jba): get backoff time from gRPC trailer metadata? See extractRetryDelay in https://code.googlesource.com/gocloud/+/master/spanner/retry.go. + var err error + for i := 0; i < t.maxAttempts; i++ { + var res *pb.BeginTransactionResponse + res, err = t.c.c.BeginTransaction(t.ctx, &pb.BeginTransactionRequest{ + Database: db, + Options: txOpts, + }) + if err != nil { + return err + } + t.id = res.Transaction + err = f(context.WithValue(ctx, transactionInProgressKey{}, 1), t) + // Read after write can only be checked client-side, so we make sure to check + // even if the user does not. + if err == nil && t.readAfterWrite { + err = errReadAfterWrite + } + if err != nil { + t.rollback() + // Prefer f's returned error to rollback error. + return err + } + _, err = t.c.c.Commit(t.ctx, &pb.CommitRequest{ + Database: t.c.path(), + Writes: t.writes, + Transaction: t.id, + }) + // If a read-write transaction returns Aborted, retry. + // On success or other failures, return here. + if t.readOnly || grpc.Code(err) != codes.Aborted { + // According to the Firestore team, we should not roll back here + // if err != nil. But spanner does. + // See https://code.googlesource.com/gocloud/+/master/spanner/transaction.go#740. + return err + } + + if txOpts == nil { + // txOpts can only be nil if is the first retry of a read-write transaction. + // (It is only set here and in the body of "if t.readOnly" above.) + // Mention the transaction ID in BeginTransaction so the service + // knows it is a retry. + txOpts = &pb.TransactionOptions{ + Mode: &pb.TransactionOptions_ReadWrite_{ + &pb.TransactionOptions_ReadWrite{RetryTransaction: t.id}, + }, + } + } + // Use exponential backoff to avoid contention with other running + // transactions. + if cerr := sleep(ctx, backoff.Pause()); cerr != nil { + err = cerr + break + } + } + // If we run out of retries, return the last error we saw (which should + // be the Aborted from Commit, or a context error). + if err != nil { + t.rollback() + } + return err +} + +func (t *Transaction) rollback() { + _ = t.c.c.Rollback(t.ctx, &pb.RollbackRequest{ + Database: t.c.path(), + Transaction: t.id, + }) + // Ignore the rollback error. + // TODO(jba): Log it? + // Note: Rollback is idempotent so it will be retried by the gapic layer. +} + +// Get gets the document in the context of the transaction. The transaction holds a +// pessimistic lock on the returned document. +func (t *Transaction) Get(dr *DocumentRef) (*DocumentSnapshot, error) { + docsnaps, err := t.GetAll([]*DocumentRef{dr}) + if err != nil { + return nil, err + } + ds := docsnaps[0] + if !ds.Exists() { + return ds, status.Errorf(codes.NotFound, "%q not found", dr.Path) + } + return ds, nil +} + +// GetAll retrieves multiple documents with a single call. The DocumentSnapshots are +// returned in the order of the given DocumentRefs. If a document is not present, the +// corresponding DocumentSnapshot's Exists method will return false. The transaction +// holds a pessimistic lock on all of the returned documents. +func (t *Transaction) GetAll(drs []*DocumentRef) ([]*DocumentSnapshot, error) { + if len(t.writes) > 0 { + t.readAfterWrite = true + return nil, errReadAfterWrite + } + return t.c.getAll(t.ctx, drs, t.id) +} + +// A Queryer is a Query or a CollectionRef. CollectionRefs act as queries whose +// results are all the documents in the collection. +type Queryer interface { + query() *Query +} + +// Documents returns a DocumentIterator based on given Query or CollectionRef. The +// results will be in the context of the transaction. +func (t *Transaction) Documents(q Queryer) *DocumentIterator { + if len(t.writes) > 0 { + t.readAfterWrite = true + return &DocumentIterator{err: errReadAfterWrite} + } + return &DocumentIterator{ + iter: newQueryDocumentIterator(t.ctx, q.query(), t.id), + } +} + +// DocumentRefs returns references to all the documents in the collection, including +// missing documents. A missing document is a document that does not exist but has +// sub-documents. +func (t *Transaction) DocumentRefs(cr *CollectionRef) *DocumentRefIterator { + if len(t.writes) > 0 { + t.readAfterWrite = true + return &DocumentRefIterator{err: errReadAfterWrite} + } + return newDocumentRefIterator(t.ctx, cr, t.id) +} + +// Create adds a Create operation to the Transaction. +// See DocumentRef.Create for details. +func (t *Transaction) Create(dr *DocumentRef, data interface{}) error { + return t.addWrites(dr.newCreateWrites(data)) +} + +// Set adds a Set operation to the Transaction. +// See DocumentRef.Set for details. +func (t *Transaction) Set(dr *DocumentRef, data interface{}, opts ...SetOption) error { + return t.addWrites(dr.newSetWrites(data, opts)) +} + +// Delete adds a Delete operation to the Transaction. +// See DocumentRef.Delete for details. +func (t *Transaction) Delete(dr *DocumentRef, opts ...Precondition) error { + return t.addWrites(dr.newDeleteWrites(opts)) +} + +// Update adds a new Update operation to the Transaction. +// See DocumentRef.Update for details. +func (t *Transaction) Update(dr *DocumentRef, data []Update, opts ...Precondition) error { + return t.addWrites(dr.newUpdatePathWrites(data, opts)) +} + +func (t *Transaction) addWrites(ws []*pb.Write, err error) error { + if t.readOnly { + return errWriteReadOnly + } + if err != nil { + return err + } + t.writes = append(t.writes, ws...) + return nil +} diff --git a/vendor/cloud.google.com/go/firestore/transaction_test.go b/vendor/cloud.google.com/go/firestore/transaction_test.go new file mode 100644 index 00000000..3955a1a3 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/transaction_test.go @@ -0,0 +1,394 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "testing" + + "github.com/golang/protobuf/ptypes/empty" + "google.golang.org/api/iterator" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestRunTransaction(t *testing.T) { + ctx := context.Background() + const db = "projects/projectID/databases/(default)" + tid := []byte{1} + c, srv := newMock(t) + beginReq := &pb.BeginTransactionRequest{Database: db} + beginRes := &pb.BeginTransactionResponse{Transaction: tid} + commitReq := &pb.CommitRequest{Database: db, Transaction: tid} + // Empty transaction. + srv.addRPC(beginReq, beginRes) + srv.addRPC(commitReq, &pb.CommitResponse{CommitTime: aTimestamp}) + err := c.RunTransaction(ctx, func(context.Context, *Transaction) error { return nil }) + if err != nil { + t.Fatal(err) + } + + // Transaction with read and write. + srv.reset() + srv.addRPC(beginReq, beginRes) + aDoc := &pb.Document{ + Name: db + "/documents/C/a", + CreateTime: aTimestamp, + UpdateTime: aTimestamp2, + Fields: map[string]*pb.Value{"count": intval(1)}, + } + srv.addRPC( + &pb.BatchGetDocumentsRequest{ + Database: c.path(), + Documents: []string{db + "/documents/C/a"}, + ConsistencySelector: &pb.BatchGetDocumentsRequest_Transaction{tid}, + }, []interface{}{ + &pb.BatchGetDocumentsResponse{ + Result: &pb.BatchGetDocumentsResponse_Found{aDoc}, + ReadTime: aTimestamp2, + }, + }) + aDoc2 := &pb.Document{ + Name: aDoc.Name, + Fields: map[string]*pb.Value{"count": intval(2)}, + } + srv.addRPC( + &pb.CommitRequest{ + Database: db, + Transaction: tid, + Writes: []*pb.Write{{ + Operation: &pb.Write_Update{aDoc2}, + UpdateMask: &pb.DocumentMask{FieldPaths: []string{"count"}}, + CurrentDocument: &pb.Precondition{ + ConditionType: &pb.Precondition_Exists{true}, + }, + }}, + }, + &pb.CommitResponse{CommitTime: aTimestamp3}, + ) + err = c.RunTransaction(ctx, func(_ context.Context, tx *Transaction) error { + docref := c.Collection("C").Doc("a") + doc, err := tx.Get(docref) + if err != nil { + return err + } + count, err := doc.DataAt("count") + if err != nil { + return err + } + return tx.Update(docref, []Update{{Path: "count", Value: count.(int64) + 1}}) + }) + if err != nil { + t.Fatal(err) + } + + // Query + srv.reset() + srv.addRPC(beginReq, beginRes) + srv.addRPC( + &pb.RunQueryRequest{ + Parent: db, + QueryType: &pb.RunQueryRequest_StructuredQuery{ + &pb.StructuredQuery{ + From: []*pb.StructuredQuery_CollectionSelector{{CollectionId: "C"}}, + }, + }, + ConsistencySelector: &pb.RunQueryRequest_Transaction{tid}, + }, + []interface{}{}, + ) + srv.addRPC(commitReq, &pb.CommitResponse{CommitTime: aTimestamp3}) + err = c.RunTransaction(ctx, func(_ context.Context, tx *Transaction) error { + it := tx.Documents(c.Collection("C")) + defer it.Stop() + _, err := it.Next() + if err != iterator.Done { + return err + } + return nil + }) + if err != nil { + t.Fatal(err) + } + + // Retry entire transaction. + srv.reset() + srv.addRPC(beginReq, beginRes) + srv.addRPC(commitReq, status.Errorf(codes.Aborted, "")) + srv.addRPC( + &pb.BeginTransactionRequest{ + Database: db, + Options: &pb.TransactionOptions{ + Mode: &pb.TransactionOptions_ReadWrite_{ + &pb.TransactionOptions_ReadWrite{RetryTransaction: tid}, + }, + }, + }, + beginRes, + ) + srv.addRPC(commitReq, &pb.CommitResponse{CommitTime: aTimestamp}) + err = c.RunTransaction(ctx, func(_ context.Context, tx *Transaction) error { return nil }) + if err != nil { + t.Fatal(err) + } +} + +func TestTransactionErrors(t *testing.T) { + ctx := context.Background() + const db = "projects/projectID/databases/(default)" + c, srv := newMock(t) + var ( + tid = []byte{1} + internalErr = status.Errorf(codes.Internal, "so sad") + beginReq = &pb.BeginTransactionRequest{ + Database: db, + } + beginRes = &pb.BeginTransactionResponse{Transaction: tid} + getReq = &pb.BatchGetDocumentsRequest{ + Database: c.path(), + Documents: []string{db + "/documents/C/a"}, + ConsistencySelector: &pb.BatchGetDocumentsRequest_Transaction{tid}, + } + rollbackReq = &pb.RollbackRequest{Database: db, Transaction: tid} + commitReq = &pb.CommitRequest{Database: db, Transaction: tid} + ) + + // BeginTransaction has a permanent error. + srv.addRPC(beginReq, internalErr) + err := c.RunTransaction(ctx, func(context.Context, *Transaction) error { return nil }) + if grpc.Code(err) != codes.Internal { + t.Errorf("got <%v>, want Internal", err) + } + + // Get has a permanent error. + get := func(_ context.Context, tx *Transaction) error { + _, err := tx.Get(c.Doc("C/a")) + return err + } + srv.reset() + srv.addRPC(beginReq, beginRes) + srv.addRPC(getReq, internalErr) + srv.addRPC(rollbackReq, &empty.Empty{}) + err = c.RunTransaction(ctx, get) + if grpc.Code(err) != codes.Internal { + t.Errorf("got <%v>, want Internal", err) + } + + // Get has a permanent error, but the rollback fails. We still + // return Get's error. + srv.reset() + srv.addRPC(beginReq, beginRes) + srv.addRPC(getReq, internalErr) + srv.addRPC(rollbackReq, status.Errorf(codes.FailedPrecondition, "")) + err = c.RunTransaction(ctx, get) + if grpc.Code(err) != codes.Internal { + t.Errorf("got <%v>, want Internal", err) + } + + // Commit has a permanent error. + srv.reset() + srv.addRPC(beginReq, beginRes) + srv.addRPC(getReq, []interface{}{ + &pb.BatchGetDocumentsResponse{ + Result: &pb.BatchGetDocumentsResponse_Found{&pb.Document{ + Name: "projects/projectID/databases/(default)/documents/C/a", + CreateTime: aTimestamp, + UpdateTime: aTimestamp2, + }}, + ReadTime: aTimestamp2, + }, + }) + srv.addRPC(commitReq, internalErr) + err = c.RunTransaction(ctx, get) + if grpc.Code(err) != codes.Internal { + t.Errorf("got <%v>, want Internal", err) + } + + // Read after write. + srv.reset() + srv.addRPC(beginReq, beginRes) + srv.addRPC(rollbackReq, &empty.Empty{}) + err = c.RunTransaction(ctx, func(_ context.Context, tx *Transaction) error { + if err := tx.Delete(c.Doc("C/a")); err != nil { + return err + } + if _, err := tx.Get(c.Doc("C/a")); err != nil { + return err + } + return nil + }) + if err != errReadAfterWrite { + t.Errorf("got <%v>, want <%v>", err, errReadAfterWrite) + } + + // Read after write, with query. + srv.reset() + srv.addRPC(beginReq, beginRes) + srv.addRPC(rollbackReq, &empty.Empty{}) + err = c.RunTransaction(ctx, func(_ context.Context, tx *Transaction) error { + if err := tx.Delete(c.Doc("C/a")); err != nil { + return err + } + it := tx.Documents(c.Collection("C").Select("x")) + defer it.Stop() + if _, err := it.Next(); err != iterator.Done { + return err + } + return nil + }) + if err != errReadAfterWrite { + t.Errorf("got <%v>, want <%v>", err, errReadAfterWrite) + } + + // Read after write fails even if the user ignores the read's error. + srv.reset() + srv.addRPC(beginReq, beginRes) + srv.addRPC(rollbackReq, &empty.Empty{}) + err = c.RunTransaction(ctx, func(_ context.Context, tx *Transaction) error { + if err := tx.Delete(c.Doc("C/a")); err != nil { + return err + } + if _, err := tx.Get(c.Doc("C/a")); err != nil { + return err + } + return nil + }) + if err != errReadAfterWrite { + t.Errorf("got <%v>, want <%v>", err, errReadAfterWrite) + } + + // Write in read-only transaction. + srv.reset() + srv.addRPC( + &pb.BeginTransactionRequest{ + Database: db, + Options: &pb.TransactionOptions{ + Mode: &pb.TransactionOptions_ReadOnly_{&pb.TransactionOptions_ReadOnly{}}, + }, + }, + beginRes, + ) + srv.addRPC(rollbackReq, &empty.Empty{}) + err = c.RunTransaction(ctx, func(_ context.Context, tx *Transaction) error { + return tx.Delete(c.Doc("C/a")) + }, ReadOnly) + if err != errWriteReadOnly { + t.Errorf("got <%v>, want <%v>", err, errWriteReadOnly) + } + + // Too many retries. + srv.reset() + srv.addRPC(beginReq, beginRes) + srv.addRPC(commitReq, status.Errorf(codes.Aborted, "")) + srv.addRPC( + &pb.BeginTransactionRequest{ + Database: db, + Options: &pb.TransactionOptions{ + Mode: &pb.TransactionOptions_ReadWrite_{ + &pb.TransactionOptions_ReadWrite{RetryTransaction: tid}, + }, + }, + }, + beginRes, + ) + srv.addRPC(commitReq, status.Errorf(codes.Aborted, "")) + srv.addRPC(rollbackReq, &empty.Empty{}) + err = c.RunTransaction(ctx, func(context.Context, *Transaction) error { return nil }, + MaxAttempts(2)) + if grpc.Code(err) != codes.Aborted { + t.Errorf("got <%v>, want Aborted", err) + } + + // Nested transaction. + srv.reset() + srv.addRPC(beginReq, beginRes) + srv.addRPC(rollbackReq, &empty.Empty{}) + err = c.RunTransaction(ctx, func(ctx context.Context, tx *Transaction) error { + return c.RunTransaction(ctx, func(context.Context, *Transaction) error { return nil }) + }) + if got, want := err, errNestedTransaction; got != want { + t.Errorf("got <%v>, want <%v>", got, want) + } + + // Non-transactional operation. + dr := c.Doc("C/d") + + for i, op := range []func(ctx context.Context) error{ + func(ctx context.Context) error { _, err := c.GetAll(ctx, []*DocumentRef{dr}); return err }, + func(ctx context.Context) error { _, _, err := c.Collection("C").Add(ctx, testData); return err }, + func(ctx context.Context) error { _, err := dr.Get(ctx); return err }, + func(ctx context.Context) error { _, err := dr.Create(ctx, testData); return err }, + func(ctx context.Context) error { _, err := dr.Set(ctx, testData); return err }, + func(ctx context.Context) error { _, err := dr.Delete(ctx); return err }, + func(ctx context.Context) error { + _, err := dr.Update(ctx, []Update{{FieldPath: []string{"*"}, Value: 1}}) + return err + }, + func(ctx context.Context) error { it := c.Collections(ctx); _, err := it.Next(); return err }, + func(ctx context.Context) error { it := dr.Collections(ctx); _, err := it.Next(); return err }, + func(ctx context.Context) error { + _, err := c.Batch().Set(dr, testData).Commit(ctx) + return err + }, + func(ctx context.Context) error { + it := c.Collection("C").Documents(ctx) + defer it.Stop() + _, err := it.Next() + return err + }, + } { + srv.reset() + srv.addRPC(beginReq, beginRes) + srv.addRPC(rollbackReq, &empty.Empty{}) + err = c.RunTransaction(ctx, func(ctx context.Context, _ *Transaction) error { + return op(ctx) + }) + if got, want := err, errNonTransactionalOp; got != want { + t.Errorf("#%d: got <%v>, want <%v>", i, got, want) + } + } +} + +func TestTransactionGetAll(t *testing.T) { + c, srv := newMock(t) + defer c.Close() + const dbPath = "projects/projectID/databases/(default)" + tid := []byte{1} + beginReq := &pb.BeginTransactionRequest{Database: dbPath} + beginRes := &pb.BeginTransactionResponse{Transaction: tid} + srv.addRPC(beginReq, beginRes) + req := &pb.BatchGetDocumentsRequest{ + Database: dbPath, + Documents: []string{ + dbPath + "/documents/C/a", + dbPath + "/documents/C/b", + dbPath + "/documents/C/c", + }, + ConsistencySelector: &pb.BatchGetDocumentsRequest_Transaction{tid}, + } + err := c.RunTransaction(context.Background(), func(_ context.Context, tx *Transaction) error { + testGetAll(t, c, srv, dbPath, + func(drs []*DocumentRef) ([]*DocumentSnapshot, error) { return tx.GetAll(drs) }, + req) + commitReq := &pb.CommitRequest{Database: dbPath, Transaction: tid} + srv.addRPC(commitReq, &pb.CommitResponse{CommitTime: aTimestamp}) + return nil + }) + if err != nil { + t.Fatal(err) + } +} diff --git a/vendor/cloud.google.com/go/firestore/util_test.go b/vendor/cloud.google.com/go/firestore/util_test.go new file mode 100644 index 00000000..b655d372 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/util_test.go @@ -0,0 +1,147 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "fmt" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "github.com/golang/protobuf/ptypes" + tspb "github.com/golang/protobuf/ptypes/timestamp" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "google.golang.org/api/option" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/genproto/googleapis/type/latlng" + "google.golang.org/grpc" +) + +var ( + aTime = time.Date(2017, 1, 26, 0, 0, 0, 0, time.UTC) + aTime2 = time.Date(2017, 2, 5, 0, 0, 0, 0, time.UTC) + aTime3 = time.Date(2017, 3, 20, 0, 0, 0, 0, time.UTC) + aTimestamp = mustTimestampProto(aTime) + aTimestamp2 = mustTimestampProto(aTime2) + aTimestamp3 = mustTimestampProto(aTime3) +) + +func mustTimestampProto(t time.Time) *tspb.Timestamp { + ts, err := ptypes.TimestampProto(t) + if err != nil { + panic(err) + } + return ts +} + +var cmpOpts = []cmp.Option{ + cmp.AllowUnexported(DocumentRef{}, CollectionRef{}, DocumentSnapshot{}, + Query{}, filter{}, order{}, fpv{}), + cmpopts.IgnoreTypes(Client{}, &Client{}), +} + +// testEqual implements equality for Firestore tests. +func testEqual(a, b interface{}) bool { + return testutil.Equal(a, b, cmpOpts...) +} + +func testDiff(a, b interface{}) string { + return testutil.Diff(a, b, cmpOpts...) +} + +func TestTestEqual(t *testing.T) { + for _, test := range []struct { + a, b interface{} + want bool + }{ + {nil, nil, true}, + {([]int)(nil), nil, false}, + {nil, ([]int)(nil), false}, + {([]int)(nil), ([]int)(nil), true}, + } { + if got := testEqual(test.a, test.b); got != test.want { + t.Errorf("testEqual(%#v, %#v) == %t, want %t", test.a, test.b, got, test.want) + } + } +} + +func newMock(t *testing.T) (*Client, *mockServer) { + srv, err := newMockServer() + if err != nil { + t.Fatal(err) + } + conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure(), grpc.WithBlock()) + if err != nil { + t.Fatal(err) + } + client, err := NewClient(context.Background(), "projectID", option.WithGRPCConn(conn)) + if err != nil { + t.Fatal(err) + } + return client, srv +} + +func intval(i int) *pb.Value { + return int64val(int64(i)) +} + +func int64val(i int64) *pb.Value { + return &pb.Value{ValueType: &pb.Value_IntegerValue{i}} +} + +func boolval(b bool) *pb.Value { + return &pb.Value{ValueType: &pb.Value_BooleanValue{b}} +} + +func floatval(f float64) *pb.Value { + return &pb.Value{ValueType: &pb.Value_DoubleValue{f}} +} + +func strval(s string) *pb.Value { + return &pb.Value{ValueType: &pb.Value_StringValue{s}} +} + +func bytesval(b []byte) *pb.Value { + return &pb.Value{ValueType: &pb.Value_BytesValue{b}} +} + +func tsval(t time.Time) *pb.Value { + ts, err := ptypes.TimestampProto(t) + if err != nil { + panic(fmt.Sprintf("bad time %s in test: %v", t, err)) + } + return &pb.Value{ValueType: &pb.Value_TimestampValue{ts}} +} + +func geoval(ll *latlng.LatLng) *pb.Value { + return &pb.Value{ValueType: &pb.Value_GeoPointValue{ll}} +} + +func arrayval(s ...*pb.Value) *pb.Value { + if s == nil { + s = []*pb.Value{} + } + return &pb.Value{ValueType: &pb.Value_ArrayValue{&pb.ArrayValue{Values: s}}} +} + +func mapval(m map[string]*pb.Value) *pb.Value { + return &pb.Value{ValueType: &pb.Value_MapValue{&pb.MapValue{Fields: m}}} +} + +func refval(path string) *pb.Value { + return &pb.Value{ValueType: &pb.Value_ReferenceValue{path}} +} diff --git a/vendor/cloud.google.com/go/firestore/watch.go b/vendor/cloud.google.com/go/firestore/watch.go new file mode 100644 index 00000000..ec31d983 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/watch.go @@ -0,0 +1,519 @@ +// Copyright 2018 Google LLC +// +// 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 firestore + +import ( + "context" + "errors" + "fmt" + "io" + "log" + "sort" + "time" + + "cloud.google.com/go/internal/btree" + "github.com/golang/protobuf/ptypes" + gax "github.com/googleapis/gax-go" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// LogWatchStreams controls whether watch stream status changes are logged. +// This feature is EXPERIMENTAL and may disappear at any time. +var LogWatchStreams = false + +// DocumentChangeKind describes the kind of change to a document between +// query snapshots. +type DocumentChangeKind int + +const ( + // DocumentAdded indicates that the document was added for the first time. + DocumentAdded DocumentChangeKind = iota + // DocumentRemoved indicates that the document was removed. + DocumentRemoved + // DocumentModified indicates that the document was modified. + DocumentModified +) + +// A DocumentChange describes the change to a document from one query snapshot to the next. +type DocumentChange struct { + Kind DocumentChangeKind + Doc *DocumentSnapshot + // The zero-based index of the document in the sequence of query results prior to this change, + // or -1 if the document was not present. + OldIndex int + // The zero-based index of the document in the sequence of query results after this change, + // or -1 if the document is no longer present. + NewIndex int +} + +// Implementation of realtime updates (a.k.a. watch). +// This code is closely based on the Node.js implementation, +// https://github.com/googleapis/nodejs-firestore/blob/master/src/watch.js. + +// The sole target ID for all streams from this client. +// Variable for testing. +var watchTargetID int32 = 'g' + 'o' + +var defaultBackoff = gax.Backoff{ + // Values from https://github.com/googleapis/nodejs-firestore/blob/master/src/backoff.js. + Initial: 1 * time.Second, + Max: 60 * time.Second, + Multiplier: 1.5, +} + +// not goroutine-safe +type watchStream struct { + ctx context.Context + c *Client + lc pb.Firestore_ListenClient // the gRPC stream + target *pb.Target // document or query being watched + backoff gax.Backoff // for stream retries + err error // sticky permanent error + readTime time.Time // time of most recent snapshot + current bool // saw CURRENT, but not RESET; precondition for a snapshot + hasReturned bool // have we returned a snapshot yet? + compare func(a, b *DocumentSnapshot) (int, error) // compare documents according to query + + // An ordered tree where DocumentSnapshots are the keys. + docTree *btree.BTree + // Map of document name to DocumentSnapshot for the last returned snapshot. + docMap map[string]*DocumentSnapshot + // Map of document name to DocumentSnapshot for accumulated changes for the current snapshot. + // A nil value means the document was removed. + changeMap map[string]*DocumentSnapshot +} + +func newWatchStreamForDocument(ctx context.Context, dr *DocumentRef) *watchStream { + // A single document is always equal to itself. + compare := func(_, _ *DocumentSnapshot) (int, error) { return 0, nil } + return newWatchStream(ctx, dr.Parent.c, compare, &pb.Target{ + TargetType: &pb.Target_Documents{ + Documents: &pb.Target_DocumentsTarget{Documents: []string{dr.Path}}, + }, + TargetId: watchTargetID, + }) +} + +func newWatchStreamForQuery(ctx context.Context, q Query) (*watchStream, error) { + qp, err := q.toProto() + if err != nil { + return nil, err + } + target := &pb.Target{ + TargetType: &pb.Target_Query{ + Query: &pb.Target_QueryTarget{ + Parent: q.parentPath, + QueryType: &pb.Target_QueryTarget_StructuredQuery{qp}, + }, + }, + TargetId: watchTargetID, + } + return newWatchStream(ctx, q.c, q.compareFunc(), target), nil +} + +const btreeDegree = 4 + +func newWatchStream(ctx context.Context, c *Client, compare func(_, _ *DocumentSnapshot) (int, error), target *pb.Target) *watchStream { + w := &watchStream{ + ctx: ctx, + c: c, + compare: compare, + target: target, + backoff: defaultBackoff, + docMap: map[string]*DocumentSnapshot{}, + changeMap: map[string]*DocumentSnapshot{}, + } + w.docTree = btree.New(btreeDegree, func(a, b interface{}) bool { + return w.less(a.(*DocumentSnapshot), b.(*DocumentSnapshot)) + }) + return w +} + +func (s *watchStream) less(a, b *DocumentSnapshot) bool { + c, err := s.compare(a, b) + if err != nil { + s.err = err + return false + } + return c < 0 +} + +// Once nextSnapshot returns an error, it will always return the same error. +func (s *watchStream) nextSnapshot() (*btree.BTree, []DocumentChange, time.Time, error) { + if s.err != nil { + return nil, nil, time.Time{}, s.err + } + var changes []DocumentChange + for { + // Process messages until we are in a consistent state. + for !s.handleNextMessage() { + } + if s.err != nil { + _ = s.close() // ignore error + return nil, nil, time.Time{}, s.err + } + var newDocTree *btree.BTree + newDocTree, changes = s.computeSnapshot(s.docTree, s.docMap, s.changeMap, s.readTime) + if s.err != nil { + return nil, nil, time.Time{}, s.err + } + // Only return a snapshot if something has changed, or this is the first snapshot. + if !s.hasReturned || newDocTree != s.docTree { + s.docTree = newDocTree + break + } + } + s.changeMap = map[string]*DocumentSnapshot{} + s.hasReturned = true + return s.docTree, changes, s.readTime, nil +} + +// Read a message from the stream and handle it. Return true when +// we're in a consistent state, or there is a permanent error. +func (s *watchStream) handleNextMessage() bool { + res, err := s.recv() + if err != nil { + s.err = err + // Errors returned by recv are permanent. + return true + } + switch r := res.ResponseType.(type) { + case *pb.ListenResponse_TargetChange: + return s.handleTargetChange(r.TargetChange) + + case *pb.ListenResponse_DocumentChange: + name := r.DocumentChange.Document.Name + s.logf("DocumentChange %q", name) + if hasWatchTargetID(r.DocumentChange.TargetIds) { // document changed + ref, err := pathToDoc(name, s.c) + if err == nil { + s.changeMap[name], err = newDocumentSnapshot(ref, r.DocumentChange.Document, s.c, nil) + } + if err != nil { + s.err = err + return true + } + } else if hasWatchTargetID(r.DocumentChange.RemovedTargetIds) { // document removed + s.changeMap[name] = nil + } + + case *pb.ListenResponse_DocumentDelete: + s.logf("Delete %q", r.DocumentDelete.Document) + s.changeMap[r.DocumentDelete.Document] = nil + + case *pb.ListenResponse_DocumentRemove: + s.logf("Remove %q", r.DocumentRemove.Document) + s.changeMap[r.DocumentRemove.Document] = nil + + case *pb.ListenResponse_Filter: + s.logf("Filter %d", r.Filter.Count) + if int(r.Filter.Count) != s.currentSize() { + s.resetDocs() // Remove all the current results. + // The filter didn't match; close the stream so it will be re-opened on the next + // call to nextSnapshot. + _ = s.close() // ignore error + s.lc = nil + } + + default: + s.err = fmt.Errorf("unknown response type %T", r) + return true + } + return false +} + +// Return true iff in a consistent state, or there is a permanent error. +func (s *watchStream) handleTargetChange(tc *pb.TargetChange) bool { + switch tc.TargetChangeType { + case pb.TargetChange_NO_CHANGE: + s.logf("TargetNoChange %d %v", len(tc.TargetIds), tc.ReadTime) + if len(tc.TargetIds) == 0 && tc.ReadTime != nil && s.current { + // Everything is up-to-date, so we are ready to return a snapshot. + rt, err := ptypes.Timestamp(tc.ReadTime) + if err != nil { + s.err = err + return true + } + s.readTime = rt + s.target.ResumeType = &pb.Target_ResumeToken{tc.ResumeToken} + return true + } + + case pb.TargetChange_ADD: + s.logf("TargetAdd") + if tc.TargetIds[0] != watchTargetID { + s.err = errors.New("unexpected target ID sent by server") + return true + } + + case pb.TargetChange_REMOVE: + s.logf("TargetRemove") + // We should never see a remove. + if tc.Cause != nil { + s.err = status.Error(codes.Code(tc.Cause.Code), tc.Cause.Message) + } else { + s.err = status.Error(codes.Internal, "firestore: client saw REMOVE") + } + return true + + // The targets reflect all changes committed before the targets were added + // to the stream. + case pb.TargetChange_CURRENT: + s.logf("TargetCurrent") + s.current = true + + // The targets have been reset, and a new initial state for the targets will be + // returned in subsequent changes. Whatever changes have happened so far no + // longer matter. + case pb.TargetChange_RESET: + s.logf("TargetReset") + s.resetDocs() + + default: + s.err = fmt.Errorf("firestore: unknown TargetChange type %s", tc.TargetChangeType) + return true + } + // If we see a resume token and our watch ID is affected, we assume the stream + // is now healthy, so we reset our backoff time to the minimum. + if tc.ResumeToken != nil && (len(tc.TargetIds) == 0 || hasWatchTargetID(tc.TargetIds)) { + s.backoff = defaultBackoff + } + return false // not in a consistent state, keep receiving +} + +func (s *watchStream) resetDocs() { + s.target.ResumeType = nil // clear resume token + s.current = false + s.changeMap = map[string]*DocumentSnapshot{} + // Mark each document as deleted. If documents are not deleted, they + // will be send again by the server. + it := s.docTree.BeforeIndex(0) + for it.Next() { + s.changeMap[it.Key.(*DocumentSnapshot).Ref.Path] = nil + } +} + +func (s *watchStream) currentSize() int { + _, adds, deletes := extractChanges(s.docMap, s.changeMap) + return len(s.docMap) + len(adds) - len(deletes) +} + +// Return the changes that have occurred since the last snapshot. +func extractChanges(docMap, changeMap map[string]*DocumentSnapshot) (updates, adds []*DocumentSnapshot, deletes []string) { + for name, doc := range changeMap { + switch { + case doc == nil: + if _, ok := docMap[name]; ok { + deletes = append(deletes, name) + } + case docMap[name] != nil: + updates = append(updates, doc) + default: + adds = append(adds, doc) + } + } + return updates, adds, deletes +} + +// For development only. +// TODO(jba): remove. +func assert(b bool) { + if !b { + panic("assertion failed") + } +} + +// Applies the mutations in changeMap to both the document tree and the +// document lookup map. Modifies docMap in place and returns a new docTree. +// If there were no changes, returns docTree unmodified. +func (s *watchStream) computeSnapshot(docTree *btree.BTree, docMap, changeMap map[string]*DocumentSnapshot, readTime time.Time) (*btree.BTree, []DocumentChange) { + var changes []DocumentChange + updatedTree := docTree + assert(docTree.Len() == len(docMap)) + updates, adds, deletes := extractChanges(docMap, changeMap) + if len(adds) > 0 || len(deletes) > 0 { + updatedTree = docTree.Clone() + } + // Process the sorted changes in the order that is expected by our clients + // (removals, additions, and then modifications). We also need to sort the + // individual changes to assure that oldIndex/newIndex keep incrementing. + deldocs := make([]*DocumentSnapshot, len(deletes)) + for i, d := range deletes { + deldocs[i] = docMap[d] + } + sort.Sort(byLess{deldocs, s.less}) + for _, oldDoc := range deldocs { + assert(oldDoc != nil) + delete(docMap, oldDoc.Ref.Path) + _, oldi := updatedTree.GetWithIndex(oldDoc) + // TODO(jba): have btree.Delete return old index + _, found := updatedTree.Delete(oldDoc) + assert(found) + changes = append(changes, DocumentChange{ + Kind: DocumentRemoved, + Doc: oldDoc, + OldIndex: oldi, + NewIndex: -1, + }) + } + sort.Sort(byLess{adds, s.less}) + for _, newDoc := range adds { + name := newDoc.Ref.Path + assert(docMap[name] == nil) + newDoc.ReadTime = readTime + docMap[name] = newDoc + updatedTree.Set(newDoc, nil) + // TODO(jba): change btree so Set returns index as second value. + _, newi := updatedTree.GetWithIndex(newDoc) + changes = append(changes, DocumentChange{ + Kind: DocumentAdded, + Doc: newDoc, + OldIndex: -1, + NewIndex: newi, + }) + } + sort.Sort(byLess{updates, s.less}) + for _, newDoc := range updates { + name := newDoc.Ref.Path + oldDoc := docMap[name] + assert(oldDoc != nil) + if newDoc.UpdateTime.Equal(oldDoc.UpdateTime) { + continue + } + if updatedTree == docTree { + updatedTree = docTree.Clone() + } + newDoc.ReadTime = readTime + docMap[name] = newDoc + _, oldi := updatedTree.GetWithIndex(oldDoc) + updatedTree.Delete(oldDoc) + updatedTree.Set(newDoc, nil) + _, newi := updatedTree.GetWithIndex(newDoc) + changes = append(changes, DocumentChange{ + Kind: DocumentModified, + Doc: newDoc, + OldIndex: oldi, + NewIndex: newi, + }) + } + assert(updatedTree.Len() == len(docMap)) + return updatedTree, changes +} + +type byLess struct { + s []*DocumentSnapshot + less func(a, b *DocumentSnapshot) bool +} + +func (b byLess) Len() int { return len(b.s) } +func (b byLess) Swap(i, j int) { b.s[i], b.s[j] = b.s[j], b.s[i] } +func (b byLess) Less(i, j int) bool { return b.less(b.s[i], b.s[j]) } + +func hasWatchTargetID(ids []int32) bool { + for _, id := range ids { + if id == watchTargetID { + return true + } + } + return false +} + +func (s *watchStream) logf(format string, args ...interface{}) { + if LogWatchStreams { + log.Printf(format, args...) + } +} + +// Close the stream. From this point on, calls to nextSnapshot will return +// io.EOF, or the error from CloseSend. +func (s *watchStream) stop() { + err := s.close() + if s.err != nil { // don't change existing error + return + } + if err != nil { + s.err = err + } + s.err = io.EOF // normal shutdown +} + +func (s *watchStream) close() error { + if s.lc == nil { + return nil + } + return s.lc.CloseSend() +} + +// recv receives the next message from the stream. It also handles opening the stream +// initially, and reopening it on non-permanent errors. +// recv doesn't have to be goroutine-safe. +func (s *watchStream) recv() (*pb.ListenResponse, error) { + var err error + for { + if s.lc == nil { + s.lc, err = s.open() + if err != nil { + // Do not retry if open fails. + return nil, err + } + } + res, err := s.lc.Recv() + if err == nil || isPermanentWatchError(err) { + return res, err + } + // Non-permanent error. Sleep and retry. + s.changeMap = map[string]*DocumentSnapshot{} // clear changeMap + dur := s.backoff.Pause() + // If we're out of quota, wait a long time before retrying. + if status.Code(err) == codes.ResourceExhausted { + dur = s.backoff.Max + } + if err := sleep(s.ctx, dur); err != nil { + return nil, err + } + s.lc = nil + } +} + +func (s *watchStream) open() (pb.Firestore_ListenClient, error) { + dbPath := s.c.path() + lc, err := s.c.c.Listen(withResourceHeader(s.ctx, dbPath)) + if err == nil { + err = lc.Send(&pb.ListenRequest{ + Database: dbPath, + TargetChange: &pb.ListenRequest_AddTarget{AddTarget: s.target}, + }) + } + if err != nil { + return nil, err + } + return lc, nil +} + +func isPermanentWatchError(err error) bool { + if err == io.EOF { + // Retry on normal end-of-stream. + return false + } + switch status.Code(err) { + case codes.Unknown, codes.DeadlineExceeded, codes.ResourceExhausted, + codes.Internal, codes.Unavailable, codes.Unauthenticated: + return false + default: + return true + } +} diff --git a/vendor/cloud.google.com/go/firestore/watch_test.go b/vendor/cloud.google.com/go/firestore/watch_test.go new file mode 100644 index 00000000..c7f163f0 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/watch_test.go @@ -0,0 +1,224 @@ +// Copyright 2018 Google LLC +// +// 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 firestore + +import ( + "context" + "sort" + "testing" + "time" + + "cloud.google.com/go/internal/btree" + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestWatchRecv(t *testing.T) { + ctx := context.Background() + c, srv := newMock(t) + db := defaultBackoff + defaultBackoff = gax.Backoff{Initial: 1, Max: 1, Multiplier: 1} + defer func() { defaultBackoff = db }() + + ws := newWatchStream(ctx, c, nil, &pb.Target{}) + request := &pb.ListenRequest{ + Database: "projects/projectID/databases/(default)", + TargetChange: &pb.ListenRequest_AddTarget{&pb.Target{}}, + } + response := &pb.ListenResponse{ResponseType: &pb.ListenResponse_DocumentChange{&pb.DocumentChange{}}} + // Stream should retry on non-permanent errors, returning only the responses. + srv.addRPC(request, []interface{}{response, status.Error(codes.Unknown, "")}) + srv.addRPC(request, []interface{}{response}) // stream will return io.EOF + srv.addRPC(request, []interface{}{response, status.Error(codes.DeadlineExceeded, "")}) + srv.addRPC(request, []interface{}{status.Error(codes.ResourceExhausted, "")}) + srv.addRPC(request, []interface{}{status.Error(codes.Internal, "")}) + srv.addRPC(request, []interface{}{status.Error(codes.Unavailable, "")}) + srv.addRPC(request, []interface{}{status.Error(codes.Unauthenticated, "")}) + srv.addRPC(request, []interface{}{response}) + for i := 0; i < 4; i++ { + res, err := ws.recv() + if err != nil { + t.Fatal(err) + } + if !proto.Equal(res, response) { + t.Fatalf("got %v, want %v", res, response) + } + } + + // Stream should not retry on a permanent error. + srv.addRPC(request, []interface{}{status.Error(codes.AlreadyExists, "")}) + _, err := ws.recv() + if got, want := status.Code(err), codes.AlreadyExists; got != want { + t.Fatalf("got %s, want %s", got, want) + } +} + +func TestComputeSnapshot(t *testing.T) { + c := &Client{ + projectID: "projID", + databaseID: "(database)", + } + ws := newWatchStream(context.Background(), c, nil, &pb.Target{}) + tm := time.Now() + i := 0 + doc := func(path, value string) *DocumentSnapshot { + i++ + return &DocumentSnapshot{ + Ref: c.Doc(path), + proto: &pb.Document{Fields: map[string]*pb.Value{"foo": strval(value)}}, + UpdateTime: tm.Add(time.Duration(i) * time.Second), // need unique time for updates + } + } + val := func(d *DocumentSnapshot) string { return d.proto.Fields["foo"].GetStringValue() } + less := func(a, b *DocumentSnapshot) bool { return val(a) < val(b) } + + type dmap map[string]*DocumentSnapshot + + ds1 := doc("C/d1", "a") + ds2 := doc("C/d2", "b") + ds2c := doc("C/d2", "c") + docTree := btree.New(4, func(a, b interface{}) bool { return less(a.(*DocumentSnapshot), b.(*DocumentSnapshot)) }) + var gotChanges []DocumentChange + docMap := dmap{} + // The following test cases are not independent; each builds on the output of the previous. + for _, test := range []struct { + desc string + changeMap dmap + wantDocs []*DocumentSnapshot + wantChanges []DocumentChange + }{ + { + "no changes", + nil, + nil, + nil, + }, + { + "add a doc", + dmap{ds1.Ref.Path: ds1}, + []*DocumentSnapshot{ds1}, + []DocumentChange{{Kind: DocumentAdded, Doc: ds1, OldIndex: -1, NewIndex: 0}}, + }, + { + "add, remove", + dmap{ds1.Ref.Path: nil, ds2.Ref.Path: ds2}, + []*DocumentSnapshot{ds2}, + []DocumentChange{ + {Kind: DocumentRemoved, Doc: ds1, OldIndex: 0, NewIndex: -1}, + {Kind: DocumentAdded, Doc: ds2, OldIndex: -1, NewIndex: 0}, + }, + }, + { + "add back, modify", + dmap{ds1.Ref.Path: ds1, ds2c.Ref.Path: ds2c}, + []*DocumentSnapshot{ds1, ds2c}, + []DocumentChange{ + {Kind: DocumentAdded, Doc: ds1, OldIndex: -1, NewIndex: 0}, + {Kind: DocumentModified, Doc: ds2c, OldIndex: 1, NewIndex: 1}, + }, + }, + } { + docTree, gotChanges = ws.computeSnapshot(docTree, docMap, test.changeMap, time.Time{}) + gotDocs := treeDocs(docTree) + if diff := testDiff(gotDocs, test.wantDocs); diff != "" { + t.Fatalf("%s: %s", test.desc, diff) + } + mgot := mapDocs(docMap, less) + if diff := testDiff(gotDocs, mgot); diff != "" { + t.Fatalf("%s: docTree and docMap disagree: %s", test.desc, diff) + } + if diff := testDiff(gotChanges, test.wantChanges); diff != "" { + t.Fatalf("%s: %s", test.desc, diff) + } + } + + // Verify that if there are no changes, the returned docTree is identical to the first arg. + // docTree already has ds2c. + got, _ := ws.computeSnapshot(docTree, docMap, dmap{ds2c.Ref.Path: ds2c}, time.Time{}) + if got != docTree { + t.Error("returned docTree != arg docTree") + } +} + +func treeDocs(bt *btree.BTree) []*DocumentSnapshot { + var ds []*DocumentSnapshot + it := bt.BeforeIndex(0) + for it.Next() { + ds = append(ds, it.Key.(*DocumentSnapshot)) + } + return ds +} + +func mapDocs(m map[string]*DocumentSnapshot, less func(a, b *DocumentSnapshot) bool) []*DocumentSnapshot { + var ds []*DocumentSnapshot + for _, d := range m { + ds = append(ds, d) + } + sort.Sort(byLess{ds, less}) + return ds +} + +func TestWatchCancel(t *testing.T) { + // Canceling the context of a watch should result in a codes.Canceled error from the next + // call to the iterator's Next method. + ctx := context.Background() + c, srv := newMock(t) + q := Query{c: c, collectionID: "x"} + + // Cancel before open. + ctx2, cancel := context.WithCancel(ctx) + ws, err := newWatchStreamForQuery(ctx2, q) + if err != nil { + t.Fatal(err) + } + cancel() + _, _, _, err = ws.nextSnapshot() + codeEq(t, "cancel before open", codes.Canceled, err) + + request := &pb.ListenRequest{ + Database: "projects/projectID/databases/(default)", + TargetChange: &pb.ListenRequest_AddTarget{ws.target}, + } + current := &pb.ListenResponse{ResponseType: &pb.ListenResponse_TargetChange{&pb.TargetChange{ + TargetChangeType: pb.TargetChange_CURRENT, + }}} + noChange := &pb.ListenResponse{ResponseType: &pb.ListenResponse_TargetChange{&pb.TargetChange{ + TargetChangeType: pb.TargetChange_NO_CHANGE, + ReadTime: aTimestamp, + }}} + + // Cancel from gax.Sleep. We should still see a gRPC error with codes.Canceled, not a + // context.Canceled error. + ctx2, cancel = context.WithCancel(ctx) + ws, err = newWatchStreamForQuery(ctx2, q) + if err != nil { + t.Fatal(err) + } + srv.addRPC(request, []interface{}{current, noChange}) + _, _, _, _ = ws.nextSnapshot() + cancel() + // Because of how the mock works, the following results in an EOF on the stream, which + // is a non-permanent error that causes a retry. That retry ends up in gax.Sleep, which + // finds that the context is done and returns ctx.Err(), which is context.Canceled. + // Verify that we transform that context.Canceled into a gRPC Status with code Canceled. + _, _, _, err = ws.nextSnapshot() + codeEq(t, "cancel from gax.Sleep", codes.Canceled, err) + + // TODO(jba): Test that we get codes.Canceled when canceling an RPC. + // We had a test for this in a21236af, but it was flaky for unclear reasons. +} diff --git a/vendor/cloud.google.com/go/firestore/writebatch.go b/vendor/cloud.google.com/go/firestore/writebatch.go new file mode 100644 index 00000000..5ed3429a --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/writebatch.go @@ -0,0 +1,81 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "errors" + + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +// A WriteBatch holds multiple database updates. Build a batch with the Create, Set, +// Update and Delete methods, then run it with the Commit method. Errors in Create, +// Set, Update or Delete are recorded instead of being returned immediately. The +// first such error is returned by Commit. +type WriteBatch struct { + c *Client + err error + writes []*pb.Write +} + +func (b *WriteBatch) add(ws []*pb.Write, err error) *WriteBatch { + if b.err != nil { + return b + } + if err != nil { + b.err = err + return b + } + b.writes = append(b.writes, ws...) + return b +} + +// Create adds a Create operation to the batch. +// See DocumentRef.Create for details. +func (b *WriteBatch) Create(dr *DocumentRef, data interface{}) *WriteBatch { + return b.add(dr.newCreateWrites(data)) +} + +// Set adds a Set operation to the batch. +// See DocumentRef.Set for details. +func (b *WriteBatch) Set(dr *DocumentRef, data interface{}, opts ...SetOption) *WriteBatch { + return b.add(dr.newSetWrites(data, opts)) +} + +// Delete adds a Delete operation to the batch. +// See DocumentRef.Delete for details. +func (b *WriteBatch) Delete(dr *DocumentRef, opts ...Precondition) *WriteBatch { + return b.add(dr.newDeleteWrites(opts)) +} + +// Update adds an Update operation to the batch. +// See DocumentRef.Update for details. +func (b *WriteBatch) Update(dr *DocumentRef, data []Update, opts ...Precondition) *WriteBatch { + return b.add(dr.newUpdatePathWrites(data, opts)) +} + +// Commit applies all the writes in the batch to the database atomically. Commit +// returns an error if there are no writes in the batch, if any errors occurred in +// constructing the writes, or if the Commmit operation fails. +func (b *WriteBatch) Commit(ctx context.Context) ([]*WriteResult, error) { + if b.err != nil { + return nil, b.err + } + if len(b.writes) == 0 { + return nil, errors.New("firestore: cannot commit empty WriteBatch") + } + return b.c.commit(ctx, b.writes) +} diff --git a/vendor/cloud.google.com/go/firestore/writebatch_test.go b/vendor/cloud.google.com/go/firestore/writebatch_test.go new file mode 100644 index 00000000..fa688c04 --- /dev/null +++ b/vendor/cloud.google.com/go/firestore/writebatch_test.go @@ -0,0 +1,118 @@ +// Copyright 2017 Google LLC +// +// 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 firestore + +import ( + "context" + "testing" + + pb "google.golang.org/genproto/googleapis/firestore/v1beta1" +) + +func TestWriteBatch(t *testing.T) { + type update struct{ A int } + + c, srv := newMock(t) + docPrefix := c.Collection("C").Path + "/" + srv.addRPC( + &pb.CommitRequest{ + Database: c.path(), + Writes: []*pb.Write{ + { // Create + Operation: &pb.Write_Update{ + Update: &pb.Document{ + Name: docPrefix + "a", + Fields: testFields, + }, + }, + CurrentDocument: &pb.Precondition{ + ConditionType: &pb.Precondition_Exists{false}, + }, + }, + { // Set + Operation: &pb.Write_Update{ + Update: &pb.Document{ + Name: docPrefix + "b", + Fields: testFields, + }, + }, + }, + { // Delete + Operation: &pb.Write_Delete{ + Delete: docPrefix + "c", + }, + }, + { // Update + Operation: &pb.Write_Update{ + Update: &pb.Document{ + Name: docPrefix + "f", + Fields: map[string]*pb.Value{"*": intval(3)}, + }, + }, + UpdateMask: &pb.DocumentMask{FieldPaths: []string{"`*`"}}, + CurrentDocument: &pb.Precondition{ + ConditionType: &pb.Precondition_Exists{true}, + }, + }, + }, + }, + &pb.CommitResponse{ + WriteResults: []*pb.WriteResult{ + {UpdateTime: aTimestamp}, + {UpdateTime: aTimestamp2}, + {UpdateTime: aTimestamp3}, + }, + }, + ) + gotWRs, err := c.Batch(). + Create(c.Doc("C/a"), testData). + Set(c.Doc("C/b"), testData). + Delete(c.Doc("C/c")). + Update(c.Doc("C/f"), []Update{{FieldPath: []string{"*"}, Value: 3}}). + Commit(context.Background()) + if err != nil { + t.Fatal(err) + } + wantWRs := []*WriteResult{{aTime}, {aTime2}, {aTime3}} + if !testEqual(gotWRs, wantWRs) { + t.Errorf("got %+v\nwant %+v", gotWRs, wantWRs) + } +} + +func TestWriteBatchErrors(t *testing.T) { + ctx := context.Background() + c, _ := newMock(t) + for _, test := range []struct { + desc string + batch *WriteBatch + }{ + { + "empty batch", + c.Batch(), + }, + { + "bad doc reference", + c.Batch().Create(c.Doc("a"), testData), + }, + { + "bad data", + c.Batch().Create(c.Doc("a/b"), 3), + }, + } { + if _, err := test.batch.Commit(ctx); err == nil { + t.Errorf("%s: got nil, want error", test.desc) + } + } +} diff --git a/vendor/cloud.google.com/go/functions/metadata/doc.go b/vendor/cloud.google.com/go/functions/metadata/doc.go new file mode 100644 index 00000000..8f5afef5 --- /dev/null +++ b/vendor/cloud.google.com/go/functions/metadata/doc.go @@ -0,0 +1,19 @@ +// Copyright 2018 Google LLC +// +// 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 metadata provides methods for creating and accessing context.Context +// objects with Google Cloud Functions metadata. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +package metadata // import "cloud.google.com/go/functions/metadata" diff --git a/vendor/cloud.google.com/go/functions/metadata/metadata.go b/vendor/cloud.google.com/go/functions/metadata/metadata.go new file mode 100644 index 00000000..26f44348 --- /dev/null +++ b/vendor/cloud.google.com/go/functions/metadata/metadata.go @@ -0,0 +1,98 @@ +// Copyright 2018 Google LLC +// +// 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 metadata + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "time" +) + +// Metadata holds Google Cloud Functions metadata. +type Metadata struct { + // EventID is a unique ID for the event. For example: "70172329041928". + EventID string `json:"eventId"` + // Timestamp is the date/time this event was created. + Timestamp time.Time `json:"timestamp"` + // EventType is the type of the event. For example: "google.pubsub.topic.publish". + EventType string `json:"eventType"` + // Resource is the resource that triggered the event. + // TODO(tbp): Make this a pointer. + Resource Resource `json:"resource"` +} + +// Resource holds Google Cloud Functions resource metadata. +// Resource values are dependent on the event type they're from. +type Resource struct { + // Service is the service that triggered the event. + Service string `json:"service"` + // Name is the name associated with the event. + Name string `json:"name"` + // Type is the type of event. + Type string `json:"type"` +} + +type contextKey string + +// GCFContextKey satisfies an interface to be able to use contextKey to read +// metadata from a Cloud Functions context.Context. +// +// Be careful making changes to this function. See FromContext. +func (k contextKey) GCFContextKey() string { + return string(k) +} + +const metadataContextKey = contextKey("metadata") + +// FromContext extracts the Metadata from the Context, if present. +func FromContext(ctx context.Context) (*Metadata, error) { + if ctx == nil { + return nil, errors.New("nil ctx") + } + // The original JSON is inserted by the Cloud Functions worker. So, the + // format must not change, or the message may fail to unmarshal. We use + // JSON as a common format between the worker and this package to ensure + // this package can be updated independently from the worker. The contextKey + // type and the metadataContextKey value use an interface to avoid using + // a built-in type as a context key (which is easy to have collisions with). + // If we need another value to be stored in the context, we can use a new + // key or interface and avoid needing to change this one. Similarly, if we + // need to change the format of the message, we should add an additional key + // to keep backward compatibility. + b, ok := ctx.Value(metadataContextKey).(json.RawMessage) + if !ok { + return nil, errors.New("unable to find metadata") + } + meta := &Metadata{} + if err := json.Unmarshal(b, meta); err != nil { + return nil, fmt.Errorf("json.Unmarshal: %v", err) + } + return meta, nil +} + +// NewContext returns a new Context carrying m. If m is nil, NewContext returns +// ctx. NewContext is only used for writing tests which rely on Metadata. +func NewContext(ctx context.Context, m *Metadata) context.Context { + if m == nil { + return ctx + } + b, err := json.Marshal(m) + if err != nil { + return ctx + } + return context.WithValue(ctx, metadataContextKey, json.RawMessage(b)) +} diff --git a/vendor/cloud.google.com/go/functions/metadata/metadata_test.go b/vendor/cloud.google.com/go/functions/metadata/metadata_test.go new file mode 100644 index 00000000..9f9d2e51 --- /dev/null +++ b/vendor/cloud.google.com/go/functions/metadata/metadata_test.go @@ -0,0 +1,53 @@ +// Copyright 2018 Google LLC +// +// 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 metadata + +import ( + "context" + "reflect" + "testing" +) + +func TestMetadata(t *testing.T) { + tests := []struct { + meta *Metadata + }{ + { + &Metadata{EventID: "test event ID"}, + }, + } + for _, test := range tests { + ctx := NewContext(context.Background(), test.meta) + got, err := FromContext(ctx) + if err != nil { + t.Fatalf("FromContext error: %v", err) + } + if !reflect.DeepEqual(got, test.meta) { + t.Fatalf("FromContext\nGot %v\nWant %v", got, test.meta) + } + } +} + +func TestMetadataError(t *testing.T) { + if _, err := FromContext(nil); err == nil { + t.Errorf("FromContext got no error, wanted an error") + } + if _, err := FromContext(context.Background()); err == nil { + t.Errorf("FromContext got no error, wanted an error") + } + if _, err := FromContext(NewContext(context.Background(), nil)); err == nil { + t.Errorf("FromContext got no error, wanted an error") + } +} diff --git a/vendor/cloud.google.com/go/httpreplay/cmd/httpr/README.md b/vendor/cloud.google.com/go/httpreplay/cmd/httpr/README.md new file mode 100644 index 00000000..3e25adec --- /dev/null +++ b/vendor/cloud.google.com/go/httpreplay/cmd/httpr/README.md @@ -0,0 +1,71 @@ +# httpr, a Record/Replay Proxy + +httpr is an HTTP proxy that records and replays traffic. It is designed +specifically for Google APIs that use HTTP exclusively. These include the Google +Cloud Storage and BigQuery clients, as well as the clients in the +`github.com/google/google-api-*-client` repos. + +If you are writing Go code, you should use the `cloud.google.com/go/httpreplay` package, which +is a simpler way to use the proxy. + +## Using a Record/Replay Proxy + +A record/replay proxy lets you run an "integration" test that accesses a +backend like a Google service and record the interaction. Subsequent runs of the +test can replay the server's responses without actually contacting the server, +turning the integration test into a fast and inexpensive unit test. + +## Usage + +First, obtain the `httpr` binary. If you have the Go toolchain, you can run `go +get -u cloud.google.com/go/httpreplay/cmd/httpr`. Otherwise, precompiled +binaries for various architectures and operating systems are available from [the +releases page](https://github.com/GoogleCloudPlatform/google-cloud-go/releases). + +### Recording + +1. Start `httpr` in record mode by passing it the `-record` flag with a filename: + ``` + httpr -record myclient.replay + ``` + By default, `httpr` will run on port 8080, and open a control port on 8181. + You can change these with the `-port` and `-control-port` flags. + You will want to run `httpr` in the background or in another window. +1. In order for `httpr` to record HTTPS traffic, your client must trust it. It + does so by installing a CA certificate created by `httpr` during the + recording session. To obtain the certificate in PEM form, GET the URL + `http://localhost:8181/authority.cer`. (If you changed the control port, use + it in place of 8181.) Consult your language to determine + how to install the certificate. Note that the certificate is different for each run + of `httpr`. +1. Arrange for your test program to use `httpr` as a proxy. This may be as + simple as setting the `HTTPS_PROXY` environment variable. +1. Run your test program, using whatever authentication for your Google API + clients that you wish. +1. Send `httpr` a SIGINT signal (`kill -2`). `httpr` will write + the replay file, then exit. + +### Replaying + +1. Start `httpr` in replay mode, in the background or another window: + ``` + httpr -replay myclient.replay + ``` +1. Install the CA certificate as described above. +1. Have your test program treat `httpr` as a proxy, as described above. +1. Run your test program. Your Google API clients should use no authentication. + +## Tips + +You must remove all randomness from your interaction while recording, +so that the replay is fully deterministic. + +Note that BigQuery clients choose random values for job IDs and insert ID if you +do not supply them. Either supply your own, or seed the client's random number +generator if possible. + +## Examples + +Examples of running `httpr` can be found in `examples` under this file's directory. + + diff --git a/vendor/cloud.google.com/go/httpreplay/cmd/httpr/examples/python/httpr-demo.py b/vendor/cloud.google.com/go/httpreplay/cmd/httpr/examples/python/httpr-demo.py new file mode 100644 index 00000000..5f68498f --- /dev/null +++ b/vendor/cloud.google.com/go/httpreplay/cmd/httpr/examples/python/httpr-demo.py @@ -0,0 +1,26 @@ +from __future__ import print_function + +import sys +from google.auth.credentials import AnonymousCredentials +from google.cloud import storage + + +if len(sys.argv)-1 != 3: + print('args: PROJECT BUCKET record|replay') + sys.exit(1) +project = sys.argv[1] +bucket_name = sys.argv[2] +mode = sys.argv[3] + +if mode == 'record': + creds = None # use default creds for demo purposes; not recommended + client = storage.Client(project=project) +elif mode == 'replay': + creds = AnonymousCredentials() +else: + print('want record or replay') + sys.exit(1) + +client = storage.Client(project=project, credentials=creds) +bucket = client.get_bucket(bucket_name) +print('bucket %s created %s' %(bucket.id, bucket.time_created)) diff --git a/vendor/cloud.google.com/go/httpreplay/cmd/httpr/examples/python/httpr-demo.sh b/vendor/cloud.google.com/go/httpreplay/cmd/httpr/examples/python/httpr-demo.sh new file mode 100755 index 00000000..aae45b87 --- /dev/null +++ b/vendor/cloud.google.com/go/httpreplay/cmd/httpr/examples/python/httpr-demo.sh @@ -0,0 +1,55 @@ +#!/bin/sh -e + +# This script and the accompanying program, httpr-demo.py, demonstrate how to use +# httpr with Python. +# +# Prerequisites: +# - httpr is on your path. +# - The google-cloud and google-auth Python packages have been installed: +# pip install --upgrade google-cloud +# pip install --upgrade google-auth + +# Execution: +# 1. Pick a project and a GCS bucket. +# 2. Invoke this script to record an interaction: +# http-demo.sh PROJECT BUCKET record +# 3. Invoke the script again to replay: +# http-demo.sh PROJECT BUCKET replay + +project=$1 +bucket=$2 +mode=$3 + +if [[ $mode != "record" && $mode != "replay" ]]; then + echo >&2 "usage: $0 PROJECT BUCKET record|replay" + exit 1 +fi + +if [[ $(which httpr) == "" ]]; then + echo >&2 "httpr is not on PATH" + exit 1 +fi + +# Start the proxy and wait for it to come up. +httpr -$mode /tmp/demo.replay & +proxy_pid=$! + +# Stop the proxy on exit. +# When the proxy is recording, this will cause it to write the replay file. +trap "kill -2 $proxy_pid" EXIT + +sleep 1 + +# Download the CA certificate from the proxy's control port +# and inform Python of the cert via an environment variable. +cert_file=/tmp/httpr.cer +curl -s localhost:8181/authority.cer > $cert_file +export REQUESTS_CA_BUNDLE=$cert_file + +# Tell Python to use the proxy. +# If you passed the -port argument to httpr, use that port here. +export HTTPS_PROXY=localhost:8080 + +# Run the program. +python httpr-demo.py $project $bucket $mode + diff --git a/vendor/cloud.google.com/go/httpreplay/cmd/httpr/httpr.go b/vendor/cloud.google.com/go/httpreplay/cmd/httpr/httpr.go new file mode 100644 index 00000000..cc734c45 --- /dev/null +++ b/vendor/cloud.google.com/go/httpreplay/cmd/httpr/httpr.go @@ -0,0 +1,110 @@ +// Copyright 2018 Google LLC +// +// 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. + +// httpr is a proxy that can record or replay HTTP requests. +// Start httpr with either the -record or -replay flags, providing a filename. +// Terminate the process with an interrupt (kill -2) to write the log file when recording. +// To get the CA certificate of the proxy, issue a GET to http://localhost:CP/authority.cer, where +// CP is the control port. + +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "log" + "net" + "net/http" + "os" + "os/signal" + + "cloud.google.com/go/httpreplay/internal/proxy" + "github.com/google/martian/martianhttp" +) + +var ( + port = flag.Int("port", 8080, "port of the proxy") + controlPort = flag.Int("control-port", 8181, "port for controlling the proxy") + record = flag.String("record", "", "record traffic and save to filename") + replay = flag.String("replay", "", "read filename and replay traffic") + debugHeaders = flag.Bool("debug-headers", false, "log header mismatches") +) + +func main() { + flag.Parse() + if *record == "" && *replay == "" { + log.Fatal("provide either -record or -replay") + } + if *record != "" && *replay != "" { + log.Fatal("provide only one of -record and -replay") + } + log.Printf("httpr: starting proxy on port %d and control on port %d", *port, *controlPort) + + var pr *proxy.Proxy + var err error + if *record != "" { + pr, err = proxy.ForRecording(*record, *port) + } else { + pr, err = proxy.ForReplaying(*replay, *port) + } + if err != nil { + log.Fatal(err) + } + proxy.DebugHeaders = *debugHeaders + + // Expose handlers on the control port. + mux := http.NewServeMux() + mux.Handle("/authority.cer", martianhttp.NewAuthorityHandler(pr.CACert)) + mux.HandleFunc("/initial", handleInitial(pr)) + lControl, err := net.Listen("tcp", fmt.Sprintf(":%d", *controlPort)) + if err != nil { + log.Fatal(err) + } + go http.Serve(lControl, mux) + + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, os.Interrupt) + + <-sigc + + log.Println("httpr: shutting down") + if err := pr.Close(); err != nil { + log.Fatal(err) + } +} + +func handleInitial(pr *proxy.Proxy) http.HandlerFunc { + return func(w http.ResponseWriter, req *http.Request) { + switch req.Method { + case "GET": + if pr.Initial != nil { + w.Write(pr.Initial) + } + + case "POST": + bytes, err := ioutil.ReadAll(req.Body) + req.Body.Close() + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "reading body: %v", err) + } + pr.Initial = bytes + + default: + w.WriteHeader(http.StatusBadRequest) + fmt.Fprint(w, "use GET to retrieve initial or POST to set it") + } + } +} diff --git a/vendor/cloud.google.com/go/httpreplay/cmd/httpr/integration_test.go b/vendor/cloud.google.com/go/httpreplay/cmd/httpr/integration_test.go new file mode 100644 index 00000000..bce29e61 --- /dev/null +++ b/vendor/cloud.google.com/go/httpreplay/cmd/httpr/integration_test.go @@ -0,0 +1,228 @@ +// Copyright 2018 Google LLC +// +// 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 main_test + +import ( + "context" + "crypto/tls" + "crypto/x509" + "errors" + "fmt" + "io/ioutil" + "net" + "net/http" + "net/url" + "os" + "os/exec" + "strings" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/storage" + "golang.org/x/oauth2" + "google.golang.org/api/option" +) + +const initial = "initial state" + +func TestIntegration_HTTPR(t *testing.T) { + if testing.Short() { + t.Skip("Integration tests skipped in short mode") + } + if testutil.ProjID() == "" { + t.Fatal("set GCLOUD_TESTS_GOLANG_PROJECT_ID and GCLOUD_TESTS_GOLANG_KEY") + } + // Get a unique temporary filename. + f, err := ioutil.TempFile("", "httpreplay") + if err != nil { + t.Fatal(err) + } + replayFilename := f.Name() + if err := f.Close(); err != nil { + t.Fatal(err) + } + defer os.Remove(replayFilename) + + if err := exec.Command("go", "build").Run(); err != nil { + t.Fatalf("running 'go build': %v", err) + } + defer os.Remove("./httpr") + want := runRecord(t, replayFilename) + got := runReplay(t, replayFilename) + if got != want { + t.Fatalf("got %q, want %q", got, want) + } +} + +func runRecord(t *testing.T, filename string) string { + cmd, tr, cport, err := start("-record", filename) + if err != nil { + t.Fatal(err) + } + defer stop(t, cmd) + + ctx := context.Background() + hc := &http.Client{ + Transport: &oauth2.Transport{ + Base: tr, + Source: testutil.TokenSource(ctx, storage.ScopeFullControl), + }, + } + res, err := http.Post( + fmt.Sprintf("http://localhost:%s/initial", cport), + "text/plain", + strings.NewReader(initial)) + if err != nil { + t.Fatal(err) + } + if res.StatusCode != 200 { + t.Fatalf("from POST: %s", res.Status) + } + info, err := getBucketInfo(ctx, hc) + if err != nil { + t.Fatal(err) + } + return info +} + +func runReplay(t *testing.T, filename string) string { + cmd, tr, cport, err := start("-replay", filename) + if err != nil { + t.Fatal(err) + } + defer stop(t, cmd) + + hc := &http.Client{Transport: tr} + res, err := http.Get(fmt.Sprintf("http://localhost:%s/initial", cport)) + if err != nil { + t.Fatal(err) + } + if res.StatusCode != 200 { + t.Fatalf("from GET: %s", res.Status) + } + bytes, err := ioutil.ReadAll(res.Body) + res.Body.Close() + if err != nil { + t.Fatal(err) + } + if got, want := string(bytes), initial; got != want { + t.Errorf("initial: got %q, want %q", got, want) + } + info, err := getBucketInfo(context.Background(), hc) + if err != nil { + t.Fatal(err) + } + return info +} + +// Start the proxy binary and wait for it to come up. +// Return a transport that talks to the proxy, as well as the control port. +// modeFlag must be either "-record" or "-replay". +func start(modeFlag, filename string) (*exec.Cmd, *http.Transport, string, error) { + pport, err := pickPort() + if err != nil { + return nil, nil, "", err + } + cport, err := pickPort() + if err != nil { + return nil, nil, "", err + } + cmd := exec.Command("./httpr", "-port", pport, "-control-port", cport, modeFlag, filename, "-debug-headers") + if err := cmd.Start(); err != nil { + return nil, nil, "", err + } + // Wait for the server to come up. + serverUp := false + for i := 0; i < 10; i++ { + if conn, err := net.Dial("tcp", "localhost:"+cport); err == nil { + conn.Close() + serverUp = true + break + } + time.Sleep(time.Second) + } + if !serverUp { + return nil, nil, "", errors.New("server never came up") + } + tr, err := proxyTransport(pport, cport) + if err != nil { + return nil, nil, "", err + } + return cmd, tr, cport, nil +} + +func stop(t *testing.T, cmd *exec.Cmd) { + if err := cmd.Process.Signal(os.Interrupt); err != nil { + t.Fatal(err) + } +} + +// pickPort picks an unused port. +func pickPort() (string, error) { + l, err := net.Listen("tcp", ":0") + if err != nil { + return "", err + } + addr := l.Addr().String() + _, port, err := net.SplitHostPort(addr) + if err != nil { + return "", err + } + l.Close() + return port, nil +} + +func proxyTransport(pport, cport string) (*http.Transport, error) { + caCert, err := getBody(fmt.Sprintf("http://localhost:%s/authority.cer", cport)) + if err != nil { + return nil, err + } + caCertPool := x509.NewCertPool() + if !caCertPool.AppendCertsFromPEM([]byte(caCert)) { + return nil, errors.New("bad CA Cert") + } + return &http.Transport{ + Proxy: http.ProxyURL(&url.URL{Host: "localhost:" + pport}), + TLSClientConfig: &tls.Config{RootCAs: caCertPool}, + }, nil +} + +func getBucketInfo(ctx context.Context, hc *http.Client) (string, error) { + client, err := storage.NewClient(ctx, option.WithHTTPClient(hc)) + if err != nil { + return "", err + } + defer client.Close() + b := client.Bucket(testutil.ProjID()) + attrs, err := b.Attrs(ctx) + if err != nil { + return "", err + } + return fmt.Sprintf("name:%s reqpays:%v location:%s sclass:%s", + attrs.Name, attrs.RequesterPays, attrs.Location, attrs.StorageClass), nil +} + +func getBody(url string) ([]byte, error) { + res, err := http.Get(url) + if err != nil { + return nil, err + } + if res.StatusCode != 200 { + return nil, fmt.Errorf("response: %s", res.Status) + } + defer res.Body.Close() + return ioutil.ReadAll(res.Body) +} diff --git a/vendor/cloud.google.com/go/httpreplay/httpreplay.go b/vendor/cloud.google.com/go/httpreplay/httpreplay.go new file mode 100644 index 00000000..7c4e9e3d --- /dev/null +++ b/vendor/cloud.google.com/go/httpreplay/httpreplay.go @@ -0,0 +1,129 @@ +// Copyright 2018 Google LLC +// +// 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 httpreplay provides an API for recording and replaying traffic +// from HTTP-based Google API clients. +// +// To record: +// 1. Call NewRecorder to get a Recorder. +// 2. Use its Client method to obtain an HTTP client to use when making API calls. +// 3. Close the Recorder when you're done. That will save the +// log of interactions to the file you provided to NewRecorder. +// +// To replay: +// 1. Call NewReplayer with the same filename you used to record to get a Replayer. +// 2. Call its Client method and use the client to make the same API calls. +// You will get back the recorded responses. +// 3. Close the Replayer when you're done. +// +// This package is EXPERIMENTAL and is subject to change or removal without notice. +// It requires Go version 1.8 or higher. +package httpreplay + +// TODO(jba): add examples. + +import ( + "context" + "net/http" + + "cloud.google.com/go/httpreplay/internal/proxy" + "google.golang.org/api/option" + htransport "google.golang.org/api/transport/http" +) + +// A Recorder records HTTP interactions. +type Recorder struct { + filename string + proxy *proxy.Proxy +} + +// NewRecorder creates a recorder that writes to filename. The file will +// also store initial state that can be retrieved to configure replay. +// +// You must call Close on the Recorder to ensure that all data is written. +func NewRecorder(filename string, initial []byte) (*Recorder, error) { + p, err := proxy.ForRecording(filename, 0) + if err != nil { + return nil, err + } + p.Initial = initial + return &Recorder{proxy: p}, nil +} + +// Client returns an http.Client to be used for recording. Provide authentication options +// like option.WithTokenSource as you normally would, or omit them to use Application Default +// Credentials. +func (r *Recorder) Client(ctx context.Context, opts ...option.ClientOption) (*http.Client, error) { + return proxyClient(ctx, r.proxy, opts...) +} + +func proxyClient(ctx context.Context, p *proxy.Proxy, opts ...option.ClientOption) (*http.Client, error) { + trans, err := htransport.NewTransport(ctx, p.Transport(), opts...) + if err != nil { + return nil, err + } + return &http.Client{Transport: trans}, nil +} + +// Close closes the Recorder and saves the log file. +func (r *Recorder) Close() error { + return r.proxy.Close() +} + +// A Replayer replays previously recorded HTTP interactions. +type Replayer struct { + proxy *proxy.Proxy +} + +// NewReplayer creates a replayer that reads from filename. +func NewReplayer(filename string) (*Replayer, error) { + p, err := proxy.ForReplaying(filename, 0) + if err != nil { + return nil, err + } + return &Replayer{proxy: p}, nil +} + +// Client returns an HTTP client for replaying. The client does not need to be +// configured with credentials for authenticating to a server, since it never +// contacts a real backend. +func (r *Replayer) Client(ctx context.Context) (*http.Client, error) { + return proxyClient(ctx, r.proxy, option.WithoutAuthentication()) +} + +// Initial returns the initial state saved by the Recorder. +func (r *Replayer) Initial() []byte { + return r.proxy.Initial +} + +// IgnoreHeader will not use h when matching requests. +func (r *Replayer) IgnoreHeader(h string) { + r.proxy.IgnoreHeader(h) +} + +// Close closes the replayer. +func (r *Replayer) Close() error { + return r.proxy.Close() +} + +// DebugHeaders helps to determine whether a header should be ignored. +// When true, if requests have the same method, URL and body but differ +// in a header, the first mismatched header is logged. +func DebugHeaders() { + proxy.DebugHeaders = true +} + +// Supported reports whether httpreplay is supported in the current version of Go. +// For Go 1.8 and above, the answer is true. +func Supported() bool { return true } diff --git a/vendor/cloud.google.com/go/httpreplay/httpreplay_test.go b/vendor/cloud.google.com/go/httpreplay/httpreplay_test.go new file mode 100644 index 00000000..1fa0f24b --- /dev/null +++ b/vendor/cloud.google.com/go/httpreplay/httpreplay_test.go @@ -0,0 +1,266 @@ +// Copyright 2018 Google LLC +// +// 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 httpreplay_test + +import ( + "bytes" + "context" + "encoding/json" + "io/ioutil" + "net/http" + "os" + "testing" + "time" + + "cloud.google.com/go/httpreplay" + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/storage" + "google.golang.org/api/option" +) + +func TestIntegration_RecordAndReplay(t *testing.T) { + httpreplay.DebugHeaders() + if testing.Short() { + t.Skip("Integration tests skipped in short mode") + } + f, err := ioutil.TempFile("", "httpreplay") + if err != nil { + t.Fatal(err) + } + replayFilename := f.Name() + if err := f.Close(); err != nil { + t.Fatal(err) + } + defer os.Remove(replayFilename) + projectID := testutil.ProjID() + if projectID == "" { + t.Skip("Need project ID. See CONTRIBUTING.md for details.") + } + ctx := context.Background() + + // Record. + initial := time.Now() + ibytes, err := json.Marshal(initial) + if err != nil { + t.Fatal(err) + } + rec, err := httpreplay.NewRecorder(replayFilename, ibytes) + if err != nil { + t.Fatal(err) + } + hc, err := rec.Client(ctx, option.WithTokenSource( + testutil.TokenSource(ctx, storage.ScopeFullControl))) + if err != nil { + t.Fatal(err) + } + wanta, wantc := run(t, hc) + testReadCRC(t, hc, "recording") + if err := rec.Close(); err != nil { + t.Fatalf("rec.Close: %v", err) + } + + // Replay. + rep, err := httpreplay.NewReplayer(replayFilename) + if err != nil { + t.Fatal(err) + } + defer rep.Close() + hc, err = rep.Client(ctx) + if err != nil { + t.Fatal(err) + } + gota, gotc := run(t, hc) + testReadCRC(t, hc, "replaying") + + if diff := testutil.Diff(gota, wanta); diff != "" { + t.Error(diff) + } + if !bytes.Equal(gotc, wantc) { + t.Errorf("got %q, want %q", gotc, wantc) + } + var gotInitial time.Time + if err := json.Unmarshal(rep.Initial(), &gotInitial); err != nil { + t.Fatal(err) + } + if !gotInitial.Equal(initial) { + t.Errorf("initial: got %v, want %v", gotInitial, initial) + } +} + +// TODO(jba): test errors + +func run(t *testing.T, hc *http.Client) (*storage.BucketAttrs, []byte) { + ctx := context.Background() + client, err := storage.NewClient(ctx, option.WithHTTPClient(hc)) + if err != nil { + t.Fatal(err) + } + defer client.Close() + b := client.Bucket(testutil.ProjID()) + attrs, err := b.Attrs(ctx) + if err != nil { + t.Fatal(err) + } + obj := b.Object("replay-test") + w := obj.NewWriter(ctx) + data := []byte{150, 151, 152} + if _, err := w.Write(data); err != nil { + t.Fatal(err) + } + if err := w.Close(); err != nil { + t.Fatal(err) + } + + r, err := obj.NewReader(ctx) + if err != nil { + t.Fatal(err) + } + defer r.Close() + contents, err := ioutil.ReadAll(r) + if err != nil { + t.Fatal(err) + } + + return attrs, contents +} + +func testReadCRC(t *testing.T, hc *http.Client, mode string) { + const ( + // This is an uncompressed file. + // See https://cloud.google.com/storage/docs/public-datasets/landsat + uncompressedBucket = "gcp-public-data-landsat" + uncompressedObject = "LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt" + + gzippedBucket = "storage-library-test-bucket" + gzippedObject = "gzipped-text.txt" + gzippedContents = "hello world" // uncompressed contents of the file + ) + ctx := context.Background() + client, err := storage.NewClient(ctx, option.WithHTTPClient(hc)) + if err != nil { + t.Fatalf("%s: %v", mode, err) + } + defer client.Close() + + uncompressedObj := client.Bucket(uncompressedBucket).Object(uncompressedObject) + gzippedObj := client.Bucket(gzippedBucket).Object(gzippedObject) + + for _, test := range []struct { + desc string + obj *storage.ObjectHandle + offset, length int64 + readCompressed bool // don't decompress a gzipped file + + wantErr bool + wantLen int // length of contents + }{ + { + desc: "uncompressed, entire file", + obj: uncompressedObj, + offset: 0, + length: -1, + readCompressed: false, + wantLen: 7903, + }, + { + desc: "uncompressed, entire file, don't decompress", + obj: uncompressedObj, + offset: 0, + length: -1, + readCompressed: true, + wantLen: 7903, + }, + { + desc: "uncompressed, suffix", + obj: uncompressedObj, + offset: 3, + length: -1, + readCompressed: false, + wantLen: 7900, + }, + { + desc: "uncompressed, prefix", + obj: uncompressedObj, + offset: 0, + length: 18, + readCompressed: false, + wantLen: 18, + }, + { + // When a gzipped file is unzipped by GCS, we can't verify the checksum + // because it was computed against the zipped contents. There is no + // header that indicates that a gzipped file is being served unzipped. + // But our CRC check only happens if there is a Content-Length header, + // and that header is absent for this read. + desc: "compressed, entire file, server unzips", + obj: gzippedObj, + offset: 0, + length: -1, + readCompressed: false, + wantLen: 11, + }, + { + // When we read a gzipped file uncompressed, it's like reading a regular file: + // the served content and the CRC match. + desc: "compressed, entire file, read compressed", + obj: gzippedObj, + offset: 0, + length: -1, + readCompressed: true, + wantLen: 31, + }, + { + desc: "compressed, partial, read compressed", + obj: gzippedObj, + offset: 1, + length: 8, + readCompressed: true, + wantLen: 8, + }, + { + desc: "uncompressed, HEAD", + obj: uncompressedObj, + offset: 0, + length: 0, + wantLen: 0, + }, + { + desc: "compressed, HEAD", + obj: gzippedObj, + offset: 0, + length: 0, + wantLen: 0, + }, + } { + obj := test.obj.ReadCompressed(test.readCompressed) + r, err := obj.NewRangeReader(ctx, test.offset, test.length) + if err != nil { + if test.wantErr { + continue + } + t.Errorf("%s: %s: %v", mode, test.desc, err) + continue + } + data, err := ioutil.ReadAll(r) + _ = r.Close() + if err != nil { + t.Errorf("%s: %s: %v", mode, test.desc, err) + continue + } + if got, want := len(data), test.wantLen; got != want { + t.Errorf("%s: %s: len: got %d, want %d", mode, test.desc, got, want) + } + } +} diff --git a/vendor/cloud.google.com/go/httpreplay/internal/proxy/debug.go b/vendor/cloud.google.com/go/httpreplay/internal/proxy/debug.go new file mode 100644 index 00000000..caf19973 --- /dev/null +++ b/vendor/cloud.google.com/go/httpreplay/internal/proxy/debug.go @@ -0,0 +1,61 @@ +// Copyright 2018 Google LLC +// +// 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 proxy + +import ( + "bytes" + "fmt" + "log" + "net/http" +) + +// Useful things for when we need to figure out what's actually going on under the hood. + +type debugTransport struct { + prefix string + t *http.Transport +} + +func (d debugTransport) RoundTrip(req *http.Request) (*http.Response, error) { + log.Printf("proxy %s: %s %s", d.prefix, req.Method, req.URL) + logHeaders(req.Header) + res, err := d.t.RoundTrip(req) + if err != nil { + log.Printf("proxy %s: error %v", d.prefix, err) + } else { + log.Printf("proxy %s: %s", d.prefix, res.Status) + log.Printf("Uncompressed = %v", res.Uncompressed) + log.Printf("ContentLength = %d", res.ContentLength) + logHeaders(res.Header) + log.Printf("Trailers:") + logHeaders(res.Trailer) + } + return res, err +} + +func logHeaders(hs http.Header) { + for k, v := range hs { + log.Printf(" %s: %s", k, v) + } +} + +func (r *requestBody) String() string { + buf := &bytes.Buffer{} + fmt.Fprintf(buf, "media type: %q\n", r.mediaType) + for i, p := range r.parts { + fmt.Fprintf(buf, "part #%d: %q\n", i, string(p)) + } + return buf.String() +} diff --git a/vendor/cloud.google.com/go/httpreplay/internal/proxy/log.go b/vendor/cloud.google.com/go/httpreplay/internal/proxy/log.go new file mode 100644 index 00000000..d1759ce9 --- /dev/null +++ b/vendor/cloud.google.com/go/httpreplay/internal/proxy/log.go @@ -0,0 +1,232 @@ +// Copyright 2018 Google LLC +// +// 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 proxy + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "net/http" + "strconv" + "sync" + + "github.com/google/martian" +) + +// Replacement for the HAR logging that comes with martian. HAR is not designed for +// replay. In particular, response bodies are interpreted (e.g. decompressed), and we +// just want them to be stored literally. This isn't something we can fix in martian: it +// is required in the HAR spec (http://www.softwareishard.com/blog/har-12-spec/#content). + +// LogVersion is the current version of the log format. It can be used to +// support changes to the format over time, so newer code can read older files. +const LogVersion = "0.1" + +// A Log is a record of HTTP interactions, suitable for replay. It can be serialized to JSON. +type Log struct { + Initial []byte // initial data for replay + Version string // version of this log format + Entries []*Entry +} + +// An Entry single request-response pair. +type Entry struct { + ID string // unique ID + Request *Request + Response *Response +} + +// A Request represents an http.Request in the log. +type Request struct { + Method string // http.Request.Method + URL string // http.Request.URL, as a string + Proto string // http.Request.Proto + Header http.Header // http.Request.Header + Body []byte // http.Request.Body, read to completion + Trailer http.Header `json:",omitempty"` // http.Request.Trailer +} + +// A Response represents an http.Response in the log. +type Response struct { + StatusCode int // http.Response.StatusCode + Proto string // http.Response.Proto + ProtoMajor int // http.Response.ProtoMajor + ProtoMinor int // http.Response.ProtoMinor + Header http.Header // http.Response.Header + Body []byte // http.Response.Body, read to completion + Trailer http.Header `json:",omitempty"` // http.Response.Trailer +} + +// A Logger maintains a request-response log. +type Logger struct { + mu sync.Mutex + entries map[string]*Entry // from ID + log *Log +} + +// NewLogger creates a new logger. +func NewLogger() *Logger { + return &Logger{ + log: &Log{Version: LogVersion}, + entries: map[string]*Entry{}, + } +} + +// ModifyRequest logs requests. +func (l *Logger) ModifyRequest(req *http.Request) error { + if req.Method == "CONNECT" { + return nil + } + ctx := martian.NewContext(req) + if ctx.SkippingLogging() { + return nil + } + lreq, err := fromHTTPRequest(req) + if err != nil { + return err + } + id := ctx.ID() + entry := &Entry{ID: id, Request: lreq} + + l.mu.Lock() + defer l.mu.Unlock() + + if _, ok := l.entries[id]; ok { + panic(fmt.Sprintf("proxy: duplicate request ID: %s", id)) + } + l.entries[id] = entry + l.log.Entries = append(l.log.Entries, entry) + return nil +} + +// ModifyResponse logs responses. +func (l *Logger) ModifyResponse(res *http.Response) error { + ctx := martian.NewContext(res.Request) + if ctx.SkippingLogging() { + return nil + } + id := ctx.ID() + lres, err := fromHTTPResponse(res) + if err != nil { + return err + } + + l.mu.Lock() + defer l.mu.Unlock() + + if e, ok := l.entries[id]; ok { + e.Response = lres + } + // Ignore the response if we haven't seen the request. + return nil +} + +// Extract returns the Log and removes it. The Logger is not usable +// after this call. +func (l *Logger) Extract() *Log { + l.mu.Lock() + defer l.mu.Unlock() + r := l.log + l.log = nil + l.entries = nil + return r +} + +func fromHTTPRequest(req *http.Request) (*Request, error) { + data, err := snapshotBody(&req.Body) + if err != nil { + return nil, err + } + return &Request{ + Method: req.Method, + URL: req.URL.String(), + Proto: req.Proto, + Header: redactHeaders(req.Header), + Body: data, + Trailer: req.Trailer, + }, nil +} + +func fromHTTPResponse(res *http.Response) (*Response, error) { + data, err := snapshotBody(&res.Body) + if err != nil { + return nil, err + } + return &Response{ + StatusCode: res.StatusCode, + Proto: res.Proto, + ProtoMajor: res.ProtoMajor, + ProtoMinor: res.ProtoMinor, + Header: res.Header, + Body: data, + Trailer: res.Trailer, + }, nil +} + +func toHTTPResponse(lr *Response, req *http.Request) *http.Response { + res := &http.Response{ + StatusCode: lr.StatusCode, + Proto: lr.Proto, + ProtoMajor: lr.ProtoMajor, + ProtoMinor: lr.ProtoMinor, + Header: lr.Header, + Body: ioutil.NopCloser(bytes.NewReader(lr.Body)), + ContentLength: int64(len(lr.Body)), + } + res.Request = req + // For HEAD, set ContentLength to the value of the Content-Length header, or -1 + // if there isn't one. + if req.Method == "HEAD" { + res.ContentLength = -1 + if c := res.Header["Content-Length"]; len(c) == 1 { + if c64, err := strconv.ParseInt(c[0], 10, 64); err == nil { + res.ContentLength = c64 + } + } + } + return res +} + +func snapshotBody(body *io.ReadCloser) ([]byte, error) { + data, err := ioutil.ReadAll(*body) + if err != nil { + return nil, err + } + (*body).Close() + *body = ioutil.NopCloser(bytes.NewReader(data)) + return data, nil +} + +// Headers that may contain sensitive data (auth tokens, keys). +var sensitiveHeaders = map[string]bool{ + "Authorization": true, + "Proxy-Authorization": true, + "X-Goog-Encryption-Key": true, // used by Cloud Storage for customer-supplied encryption + "X-Goog-Copy-Source-Encryption-Key": true, // ditto +} + +// Copy headers, redacting sensitive ones. +func redactHeaders(hs http.Header) http.Header { + rh := http.Header{} + for k, v := range hs { + if sensitiveHeaders[k] { + rh.Set(k, "REDACTED") + } else { + rh[k] = v + } + } + return rh +} diff --git a/vendor/cloud.google.com/go/httpreplay/internal/proxy/log_test.go b/vendor/cloud.google.com/go/httpreplay/internal/proxy/log_test.go new file mode 100644 index 00000000..327227c8 --- /dev/null +++ b/vendor/cloud.google.com/go/httpreplay/internal/proxy/log_test.go @@ -0,0 +1,182 @@ +// Copyright 2018 Google Inc. All Rights Reserved. +// +// 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 proxy + +import ( + "io/ioutil" + "net/http" + "net/url" + "strings" + "testing" + + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/google/martian" +) + +func TestRedactHeaders(t *testing.T) { + clone := func(h http.Header) http.Header { + h2 := http.Header{} + for k, v := range h { + h2[k] = v + } + return h2 + } + + in := http.Header{ + "Content-Type": {"text/plain"}, + "Authorization": {"oauth2-token"}, + "X-Goog-Encryption-Key": {"a-secret-key"}, + "X-Goog-Copy-Source-Encryption-Key": {"another-secret-key"}, + } + orig := clone(in) + got := redactHeaders(in) + // Logged headers should be redacted. + want := http.Header{ + "Content-Type": {"text/plain"}, + "Authorization": {"REDACTED"}, + "X-Goog-Encryption-Key": {"REDACTED"}, + "X-Goog-Copy-Source-Encryption-Key": {"REDACTED"}, + } + if !testutil.Equal(got, want) { + t.Errorf("got %+v\nwant %+v", got, want) + } + // The original headers should be the same. + if got, want := in, orig; !testutil.Equal(got, want) { + t.Errorf("got %+v\nwant %+v", got, want) + } +} + +func TestLogger(t *testing.T) { + req := &http.Request{ + Method: "POST", + URL: &url.URL{ + Scheme: "https", + Host: "example.com", + Path: "a/b/c", + }, + Header: http.Header{"H1": {"v1", "v2"}}, + Body: ioutil.NopCloser(strings.NewReader("hello")), + Trailer: http.Header{"T1": {"v3", "v4"}}, + } + res := &http.Response{ + Request: req, + StatusCode: 204, + Body: ioutil.NopCloser(strings.NewReader("goodbye")), + Header: http.Header{"H2": {"v5"}}, + Trailer: http.Header{"T2": {"v6", "v7"}}, + } + l := NewLogger() + _, remove, err := martian.TestContext(req, nil, nil) + if err != nil { + t.Fatal(err) + } + defer remove() + if err := l.ModifyRequest(req); err != nil { + t.Fatal(err) + } + if err := l.ModifyResponse(res); err != nil { + t.Fatal(err) + } + lg := l.Extract() + want := []*Entry{ + { + ID: lg.Entries[0].ID, + Request: &Request{ + Method: "POST", + URL: "https://example.com/a/b/c", + Header: http.Header{"H1": {"v1", "v2"}}, + Body: []byte("hello"), + Trailer: http.Header{"T1": {"v3", "v4"}}, + }, + Response: &Response{ + StatusCode: 204, + Body: []byte("goodbye"), + Header: http.Header{"H2": {"v5"}}, + Trailer: http.Header{"T2": {"v6", "v7"}}, + }, + }, + } + if diff := testutil.Diff(lg.Entries, want); diff != "" { + t.Error(diff) + } +} + +func TestToHTTPResponse(t *testing.T) { + for _, test := range []struct { + desc string + lr *Response + req *http.Request + want *http.Response + }{ + { + desc: "GET request", + lr: &Response{ + StatusCode: 201, + Proto: "1.1", + Header: http.Header{"h": {"v"}}, + Body: []byte("text"), + }, + req: &http.Request{Method: "GET"}, + want: &http.Response{ + Request: &http.Request{Method: "GET"}, + StatusCode: 201, + Proto: "1.1", + Header: http.Header{"h": {"v"}}, + ContentLength: 4, + }, + }, + { + desc: "HEAD request with no Content-Length header", + lr: &Response{ + StatusCode: 201, + Proto: "1.1", + Header: http.Header{"h": {"v"}}, + Body: []byte("text"), + }, + req: &http.Request{Method: "HEAD"}, + want: &http.Response{ + Request: &http.Request{Method: "HEAD"}, + StatusCode: 201, + Proto: "1.1", + Header: http.Header{"h": {"v"}}, + ContentLength: -1, + }, + }, + { + desc: "HEAD request with Content-Length header", + lr: &Response{ + StatusCode: 201, + Proto: "1.1", + Header: http.Header{"h": {"v"}, "Content-Length": {"17"}}, + Body: []byte("text"), + }, + req: &http.Request{Method: "HEAD"}, + want: &http.Response{ + Request: &http.Request{Method: "HEAD"}, + StatusCode: 201, + Proto: "1.1", + Header: http.Header{"h": {"v"}, "Content-Length": {"17"}}, + ContentLength: 17, + }, + }, + } { + got := toHTTPResponse(test.lr, test.req) + got.Body = nil + if diff := testutil.Diff(got, test.want, cmpopts.IgnoreUnexported(http.Request{})); diff != "" { + t.Errorf("%s: %s", test.desc, diff) + } + } +} diff --git a/vendor/cloud.google.com/go/httpreplay/internal/proxy/record.go b/vendor/cloud.google.com/go/httpreplay/internal/proxy/record.go new file mode 100644 index 00000000..57eacaf8 --- /dev/null +++ b/vendor/cloud.google.com/go/httpreplay/internal/proxy/record.go @@ -0,0 +1,188 @@ +// Copyright 2018 Google LLC +// +// 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 proxy provides a record/replay HTTP proxy. It is designed to support +// both an in-memory API (cloud.google.com/go/httpreplay) and a standalone server +// (cloud.google.com/go/httpreplay/cmd/httpr). +package proxy + +// See github.com/google/martian/cmd/proxy/main.go for the origin of much of this. + +import ( + "crypto/tls" + "crypto/x509" + "encoding/json" + "fmt" + "io/ioutil" + "net" + "net/http" + "net/url" + "strings" + "time" + + "github.com/google/martian" + "github.com/google/martian/fifo" + "github.com/google/martian/httpspec" + "github.com/google/martian/martianlog" + "github.com/google/martian/mitm" +) + +// A Proxy is an HTTP proxy that supports recording or replaying requests. +type Proxy struct { + // The certificate that the proxy uses to participate in TLS. + CACert *x509.Certificate + + // The URL of the proxy. + URL *url.URL + + // Initial state of the client. + Initial []byte + + mproxy *martian.Proxy + filename string // for log + logger *Logger // for recording only + ignoreHeaders map[string]bool // headers the user has asked to ignore +} + +// ForRecording returns a Proxy configured to record. +func ForRecording(filename string, port int) (*Proxy, error) { + p, err := newProxy(filename) + if err != nil { + return nil, err + } + + // Construct a group that performs the standard proxy stack of request/response + // modifications. + stack, _ := httpspec.NewStack("httpr") // second arg is an internal group that we don't need + p.mproxy.SetRequestModifier(stack) + p.mproxy.SetResponseModifier(stack) + + // Make a group for logging requests and responses. + logGroup := fifo.NewGroup() + skipAuth := skipLoggingByHost("accounts.google.com") + logGroup.AddRequestModifier(skipAuth) + logGroup.AddResponseModifier(skipAuth) + p.logger = NewLogger() + logGroup.AddRequestModifier(p.logger) + logGroup.AddResponseModifier(p.logger) + + stack.AddRequestModifier(logGroup) + stack.AddResponseModifier(logGroup) + + // Ordinary debug logging. + logger := martianlog.NewLogger() + logger.SetDecode(true) + stack.AddRequestModifier(logger) + stack.AddResponseModifier(logger) + + if err := p.start(port); err != nil { + return nil, err + } + return p, nil +} + +type hideTransport http.Transport + +func (t *hideTransport) RoundTrip(req *http.Request) (*http.Response, error) { + return (*http.Transport)(t).RoundTrip(req) +} + +func newProxy(filename string) (*Proxy, error) { + mproxy := martian.NewProxy() + // Set up a man-in-the-middle configuration with a CA certificate so the proxy can + // participate in TLS. + x509c, priv, err := mitm.NewAuthority("cloud.google.com/go/httpreplay", "HTTPReplay Authority", time.Hour) + if err != nil { + return nil, err + } + mc, err := mitm.NewConfig(x509c, priv) + if err != nil { + return nil, err + } + mc.SetValidity(time.Hour) + mc.SetOrganization("cloud.google.com/go/httpreplay") + mc.SkipTLSVerify(false) + if err != nil { + return nil, err + } + mproxy.SetMITM(mc) + ih := map[string]bool{} + for k, v := range ignoreHeaders { + ih[k] = v + } + return &Proxy{ + mproxy: mproxy, + CACert: x509c, + filename: filename, + ignoreHeaders: ih, + }, nil +} + +func (p *Proxy) start(port int) error { + l, err := net.Listen("tcp4", fmt.Sprintf(":%d", port)) + if err != nil { + return err + } + p.URL = &url.URL{Scheme: "http", Host: l.Addr().String()} + go p.mproxy.Serve(l) + return nil +} + +// Transport returns an http.Transport for clients who want to talk to the proxy. +func (p *Proxy) Transport() *http.Transport { + caCertPool := x509.NewCertPool() + caCertPool.AddCert(p.CACert) + return &http.Transport{ + TLSClientConfig: &tls.Config{RootCAs: caCertPool}, + Proxy: func(*http.Request) (*url.URL, error) { return p.URL, nil }, + } +} + +// IgnoreHeader will cause h to be ignored during matching on replay. +func (p *Proxy) IgnoreHeader(h string) { + p.ignoreHeaders[http.CanonicalHeaderKey(h)] = true +} + +// Close closes the proxy. If the proxy is recording, it also writes the log. +func (p *Proxy) Close() error { + p.mproxy.Close() + if p.logger != nil { + return p.writeLog() + } + return nil +} + +func (p *Proxy) writeLog() error { + lg := p.logger.Extract() + lg.Initial = p.Initial + bytes, err := json.MarshalIndent(lg, "", " ") + if err != nil { + return err + } + return ioutil.WriteFile(p.filename, bytes, 0600) // only accessible by owner +} + +// skipLoggingByHost disables logging for traffic to a particular host. +type skipLoggingByHost string + +func (s skipLoggingByHost) ModifyRequest(req *http.Request) error { + if strings.HasPrefix(req.Host, string(s)) { + martian.NewContext(req).SkipLogging() + } + return nil +} + +func (s skipLoggingByHost) ModifyResponse(res *http.Response) error { + return s.ModifyRequest(res.Request) +} diff --git a/vendor/cloud.google.com/go/httpreplay/internal/proxy/replay.go b/vendor/cloud.google.com/go/httpreplay/internal/proxy/replay.go new file mode 100644 index 00000000..e785c9ad --- /dev/null +++ b/vendor/cloud.google.com/go/httpreplay/internal/proxy/replay.go @@ -0,0 +1,313 @@ +// Copyright 2018 Google LLC +// +// 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 proxy + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "log" + "mime" + "mime/multipart" + "net/http" + "reflect" + "strings" + "sync" + + "github.com/google/martian/martianlog" +) + +// ForReplaying returns a Proxy configured to replay. +func ForReplaying(filename string, port int) (*Proxy, error) { + p, err := newProxy(filename) + if err != nil { + return nil, err + } + calls, initial, err := readLog(filename) + if err != nil { + return nil, err + } + p.mproxy.SetRoundTripper(&replayRoundTripper{ + calls: calls, + ignoreHeaders: p.ignoreHeaders, + }) + p.Initial = initial + + // Debug logging. + // TODO(jba): factor out from here and ForRecording. + logger := martianlog.NewLogger() + logger.SetDecode(true) + p.mproxy.SetRequestModifier(logger) + p.mproxy.SetResponseModifier(logger) + + if err := p.start(port); err != nil { + return nil, err + } + return p, nil +} + +// A call is an HTTP request and its matching response. +type call struct { + req *Request + reqBody *requestBody // parsed request body + res *Response +} + +func readLog(filename string) ([]*call, []byte, error) { + bytes, err := ioutil.ReadFile(filename) + if err != nil { + return nil, nil, err + } + var lg Log + if err := json.Unmarshal(bytes, &lg); err != nil { + return nil, nil, fmt.Errorf("%s: %v", filename, err) + } + if lg.Version != LogVersion { + return nil, nil, fmt.Errorf("httpreplay proxy: read log version %s but current version is %s", + lg.Version, LogVersion) + } + ignoreIDs := map[string]bool{} // IDs of requests to ignore + callsByID := map[string]*call{} + var calls []*call + for _, e := range lg.Entries { + if ignoreIDs[e.ID] { + continue + } + c, ok := callsByID[e.ID] + switch { + case !ok: + if e.Request == nil { + return nil, nil, fmt.Errorf("first entry for ID %s does not have a request", e.ID) + } + if e.Request.Method == "CONNECT" { + // Ignore CONNECT methods. + ignoreIDs[e.ID] = true + } else { + reqBody, err := newRequestBodyFromLog(e.Request) + if err != nil { + return nil, nil, err + } + c := &call{e.Request, reqBody, e.Response} + calls = append(calls, c) + callsByID[e.ID] = c + } + case e.Request != nil: + if e.Response != nil { + return nil, nil, errors.New("HAR entry has both request and response") + } + c.req = e.Request + case e.Response != nil: + c.res = e.Response + default: + return nil, nil, errors.New("HAR entry has neither request nor response") + } + } + for _, c := range calls { + if c.req == nil || c.res == nil { + return nil, nil, fmt.Errorf("missing request or response: %+v", c) + } + } + return calls, lg.Initial, nil +} + +type replayRoundTripper struct { + mu sync.Mutex + calls []*call + ignoreHeaders map[string]bool +} + +func (r *replayRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + reqBody, err := newRequestBodyFromHTTP(req) + if err != nil { + return nil, err + } + r.mu.Lock() + defer r.mu.Unlock() + for i, call := range r.calls { + if call == nil { + continue + } + if requestsMatch(req, reqBody, call.req, call.reqBody, r.ignoreHeaders) { + r.calls[i] = nil // nil out this call so we don't reuse it + return toHTTPResponse(call.res, req), nil + } + } + return nil, fmt.Errorf("no matching request for %+v", req) +} + +// Headers that shouldn't be compared, because they may differ on different executions +// of the same code, or may not be present during record or replay. +var ignoreHeaders = map[string]bool{} + +func init() { + // Sensitive headers are redacted in the log, so they won't be equal to incoming values. + for h := range sensitiveHeaders { + ignoreHeaders[h] = true + } + for _, h := range []string{ + "Content-Type", // handled by requestBody + "Connection", + "Date", + "Host", + "Transfer-Encoding", + "Via", + "X-Forwarded-For", + "X-Forwarded-Host", + "X-Forwarded-Proto", + "X-Forwarded-Url", + "X-Cloud-Trace-Context", // OpenCensus traces have a random ID + "X-Goog-Api-Client", // can differ for, e.g., different Go versions + } { + ignoreHeaders[h] = true + } +} + +// Report whether the incoming request in matches the candidate request cand. +func requestsMatch(in *http.Request, inBody *requestBody, cand *Request, candBody *requestBody, ignoreHeaders map[string]bool) bool { + if in.Method != cand.Method { + return false + } + if in.URL.String() != cand.URL { + return false + } + if !inBody.equal(candBody) { + return false + } + // Check headers last. See DebugHeaders. + return headersMatch(in.Header, cand.Header, ignoreHeaders) +} + +// A requestBody represents the body of a request. If the content type is multipart, the +// body is split into parts. +// +// The replaying proxy needs to understand multipart bodies because the boundaries are +// generated randomly, so we can't just compare the entire bodies for equality. +type requestBody struct { + mediaType string // the media type part of the Content-Type header + parts [][]byte // the parts of the body, or just a single []byte if not multipart +} + +func newRequestBodyFromHTTP(req *http.Request) (*requestBody, error) { + defer req.Body.Close() + return newRequestBody(req.Header.Get("Content-Type"), req.Body) +} + +func newRequestBodyFromLog(req *Request) (*requestBody, error) { + if req.Body == nil { + return nil, nil + } + return newRequestBody(req.Header.Get("Content-Type"), bytes.NewReader(req.Body)) +} + +// newRequestBody parses the Content-Type header, reads the body, and splits it into +// parts if necessary. +func newRequestBody(contentType string, body io.Reader) (*requestBody, error) { + if contentType == "" { + // No content-type header. There should not be a body. + if _, err := body.Read(make([]byte, 1)); err != io.EOF { + return nil, errors.New("no Content-Type, but body") + } + return nil, nil + } + mediaType, params, err := mime.ParseMediaType(contentType) + if err != nil { + return nil, err + } + rb := &requestBody{mediaType: mediaType} + if strings.HasPrefix(mediaType, "multipart/") { + mr := multipart.NewReader(body, params["boundary"]) + for { + p, err := mr.NextPart() + if err == io.EOF { + break + } + if err != nil { + return nil, err + } + part, err := ioutil.ReadAll(p) + if err != nil { + return nil, err + } + // TODO(jba): care about part headers? + rb.parts = append(rb.parts, part) + } + } else { + bytes, err := ioutil.ReadAll(body) + if err != nil { + return nil, err + } + rb.parts = [][]byte{bytes} + } + return rb, nil +} + +func (r1 *requestBody) equal(r2 *requestBody) bool { + if r1 == nil || r2 == nil { + return r1 == r2 + } + if r1.mediaType != r2.mediaType { + return false + } + if len(r1.parts) != len(r2.parts) { + return false + } + for i, p1 := range r1.parts { + if !bytes.Equal(p1, r2.parts[i]) { + return false + } + } + return true +} + +// DebugHeaders helps to determine whether a header should be ignored. +// When true, if requests have the same method, URL and body but differ +// in a header, the first mismatched header is logged. +var DebugHeaders = false + +func headersMatch(in, cand http.Header, ignores map[string]bool) bool { + for k1, v1 := range in { + if ignores[k1] { + continue + } + v2 := cand[k1] + if v2 == nil { + if DebugHeaders { + log.Printf("header %s: present in incoming request but not candidate", k1) + } + return false + } + if !reflect.DeepEqual(v1, v2) { + if DebugHeaders { + log.Printf("header %s: incoming %v, candidate %v", k1, v1, v2) + } + return false + } + } + for k2 := range cand { + if ignores[k2] { + continue + } + if in[k2] == nil { + if DebugHeaders { + log.Printf("header %s: not in incoming request but present in candidate", k2) + } + return false + } + } + return true +} diff --git a/vendor/cloud.google.com/go/httpreplay/internal/proxy/replay_test.go b/vendor/cloud.google.com/go/httpreplay/internal/proxy/replay_test.go new file mode 100644 index 00000000..72ce5828 --- /dev/null +++ b/vendor/cloud.google.com/go/httpreplay/internal/proxy/replay_test.go @@ -0,0 +1,112 @@ +// Copyright 2018 Google LLC +// +// 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 proxy + +import ( + "io/ioutil" + "net/http" + "strings" + "testing" + + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" +) + +func TestRequestBody(t *testing.T) { + req1 := &http.Request{ + Header: http.Header{"Content-Type": {"multipart/mixed; boundary=foo"}}, + Body: ioutil.NopCloser(strings.NewReader( + "--foo\r\nFoo: one\r\n\r\nA section\r\n" + + "--foo\r\nFoo: two\r\n\r\nAnd another\r\n" + + "--foo--\r\n")), + } + rb1, err := newRequestBodyFromHTTP(req1) + if err != nil { + t.Fatal(err) + } + want := &requestBody{ + mediaType: "multipart/mixed", + parts: [][]byte{ + []byte("A section"), + []byte("And another"), + }, + } + if diff := testutil.Diff(rb1, want, cmp.AllowUnexported(requestBody{})); diff != "" { + t.Error(diff) + } + + // Same contents, different boundary. + req2 := &http.Request{ + Header: http.Header{"Content-Type": {"multipart/mixed; boundary=bar"}}, + Body: ioutil.NopCloser(strings.NewReader( + "--bar\r\nFoo: one\r\n\r\nA section\r\n" + + "--bar\r\nFoo: two\r\n\r\nAnd another\r\n" + + "--bar--\r\n")), + } + rb2, err := newRequestBodyFromHTTP(req2) + if err != nil { + t.Fatal(err) + } + if diff := testutil.Diff(rb1, want, cmp.AllowUnexported(requestBody{})); diff != "" { + t.Error(diff) + } + + if !rb1.equal(rb2) { + t.Error("equal returned false, want true") + } +} + +func TestHeadersMatch(t *testing.T) { + for _, test := range []struct { + h1, h2 http.Header + want bool + }{ + { + http.Header{"A": {"x"}, "B": {"y", "z"}}, + http.Header{"A": {"x"}, "B": {"y", "z"}}, + true, + }, + { + http.Header{"A": {"x"}, "B": {"y", "z"}}, + http.Header{"A": {"x"}, "B": {"w"}}, + false, + }, + { + http.Header{"A": {"x"}, "B": {"y", "z"}, "I": {"foo"}}, + http.Header{"A": {"x"}, "B": {"y", "z"}, "I": {"bar"}}, + true, + }, + { + http.Header{"A": {"x"}, "B": {"y", "z"}}, + http.Header{"A": {"x"}, "B": {"y", "z"}, "I": {"bar"}}, + true, + }, + { + http.Header{"A": {"x"}, "B": {"y", "z"}, "I": {"foo"}}, + http.Header{"A": {"x"}, "I": {"bar"}}, + false, + }, + { + http.Header{"A": {"x"}, "I": {"foo"}}, + http.Header{"A": {"x"}, "B": {"y", "z"}, "I": {"bar"}}, + false, + }, + } { + got := headersMatch(test.h1, test.h2, map[string]bool{"I": true}) + if got != test.want { + t.Errorf("%v, %v: got %t, want %t", test.h1, test.h2, got, test.want) + } + } +} diff --git a/vendor/cloud.google.com/go/iam/admin/apiv1/doc.go b/vendor/cloud.google.com/go/iam/admin/apiv1/doc.go new file mode 100644 index 00000000..3dea8ce8 --- /dev/null +++ b/vendor/cloud.google.com/go/iam/admin/apiv1/doc.go @@ -0,0 +1,92 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package admin is an auto-generated package for the +// Google Identity and Access Management (IAM) API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Manages identity and access control for Google Cloud Platform resources, +// including the creation of service accounts, which you can use to +// authenticate to Google and make API calls. +package admin // import "cloud.google.com/go/iam/admin/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/iam", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/iam/admin/apiv1/iam_client.go b/vendor/cloud.google.com/go/iam/admin/apiv1/iam_client.go new file mode 100644 index 00000000..68622f6d --- /dev/null +++ b/vendor/cloud.google.com/go/iam/admin/apiv1/iam_client.go @@ -0,0 +1,475 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package admin + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + adminpb "google.golang.org/genproto/googleapis/iam/admin/v1" + iampb "google.golang.org/genproto/googleapis/iam/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// IamCallOptions contains the retry settings for each method of IamClient. +type IamCallOptions struct { + ListServiceAccounts []gax.CallOption + GetServiceAccount []gax.CallOption + CreateServiceAccount []gax.CallOption + UpdateServiceAccount []gax.CallOption + DeleteServiceAccount []gax.CallOption + ListServiceAccountKeys []gax.CallOption + GetServiceAccountKey []gax.CallOption + CreateServiceAccountKey []gax.CallOption + DeleteServiceAccountKey []gax.CallOption + SignBlob []gax.CallOption + GetIamPolicy []gax.CallOption + SetIamPolicy []gax.CallOption + TestIamPermissions []gax.CallOption + QueryGrantableRoles []gax.CallOption + SignJwt []gax.CallOption +} + +func defaultIamClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("iam.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultIamCallOptions() *IamCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &IamCallOptions{ + ListServiceAccounts: retry[[2]string{"default", "idempotent"}], + GetServiceAccount: retry[[2]string{"default", "idempotent"}], + CreateServiceAccount: retry[[2]string{"default", "non_idempotent"}], + UpdateServiceAccount: retry[[2]string{"default", "idempotent"}], + DeleteServiceAccount: retry[[2]string{"default", "idempotent"}], + ListServiceAccountKeys: retry[[2]string{"default", "idempotent"}], + GetServiceAccountKey: retry[[2]string{"default", "idempotent"}], + CreateServiceAccountKey: retry[[2]string{"default", "non_idempotent"}], + DeleteServiceAccountKey: retry[[2]string{"default", "idempotent"}], + SignBlob: retry[[2]string{"default", "non_idempotent"}], + GetIamPolicy: retry[[2]string{"default", "non_idempotent"}], + SetIamPolicy: retry[[2]string{"default", "non_idempotent"}], + TestIamPermissions: retry[[2]string{"default", "non_idempotent"}], + QueryGrantableRoles: retry[[2]string{"default", "non_idempotent"}], + SignJwt: retry[[2]string{"default", "non_idempotent"}], + } +} + +// IamClient is a client for interacting with Google Identity and Access Management (IAM) API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type IamClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + iamClient adminpb.IAMClient + + // The call options for this service. + CallOptions *IamCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewIamClient creates a new iam client. +// +// Creates and manages service account objects. +// +// Service account is an account that belongs to your project instead +// of to an individual end user. It is used to authenticate calls +// to a Google API. +// +// To create a service account, specify the project_id and account_id +// for the account. The account_id is unique within the project, and used +// to generate the service account email address and a stable +// unique_id. +// +// All other methods can identify accounts using the format +// projects/{PROJECT_ID}/serviceAccounts/{SERVICE_ACCOUNT_EMAIL}. +// Using - as a wildcard for the project will infer the project from +// the account. The account value can be the email address or the +// unique_id of the service account. +func NewIamClient(ctx context.Context, opts ...option.ClientOption) (*IamClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultIamClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &IamClient{ + conn: conn, + CallOptions: defaultIamCallOptions(), + + iamClient: adminpb.NewIAMClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *IamClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *IamClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *IamClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListServiceAccounts lists [ServiceAccounts][google.iam.admin.v1.ServiceAccount] for a project. +func (c *IamClient) ListServiceAccounts(ctx context.Context, req *adminpb.ListServiceAccountsRequest, opts ...gax.CallOption) *ServiceAccountIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListServiceAccounts[0:len(c.CallOptions.ListServiceAccounts):len(c.CallOptions.ListServiceAccounts)], opts...) + it := &ServiceAccountIterator{} + req = proto.Clone(req).(*adminpb.ListServiceAccountsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*adminpb.ServiceAccount, string, error) { + var resp *adminpb.ListServiceAccountsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamClient.ListServiceAccounts(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Accounts, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetServiceAccount gets a [ServiceAccount][google.iam.admin.v1.ServiceAccount]. +func (c *IamClient) GetServiceAccount(ctx context.Context, req *adminpb.GetServiceAccountRequest, opts ...gax.CallOption) (*adminpb.ServiceAccount, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetServiceAccount[0:len(c.CallOptions.GetServiceAccount):len(c.CallOptions.GetServiceAccount)], opts...) + var resp *adminpb.ServiceAccount + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamClient.GetServiceAccount(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateServiceAccount creates a [ServiceAccount][google.iam.admin.v1.ServiceAccount] +// and returns it. +func (c *IamClient) CreateServiceAccount(ctx context.Context, req *adminpb.CreateServiceAccountRequest, opts ...gax.CallOption) (*adminpb.ServiceAccount, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateServiceAccount[0:len(c.CallOptions.CreateServiceAccount):len(c.CallOptions.CreateServiceAccount)], opts...) + var resp *adminpb.ServiceAccount + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamClient.CreateServiceAccount(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateServiceAccount updates a [ServiceAccount][google.iam.admin.v1.ServiceAccount]. +// +// Currently, only the following fields are updatable: +// display_name . +// The etag is mandatory. +func (c *IamClient) UpdateServiceAccount(ctx context.Context, req *adminpb.ServiceAccount, opts ...gax.CallOption) (*adminpb.ServiceAccount, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateServiceAccount[0:len(c.CallOptions.UpdateServiceAccount):len(c.CallOptions.UpdateServiceAccount)], opts...) + var resp *adminpb.ServiceAccount + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamClient.UpdateServiceAccount(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteServiceAccount deletes a [ServiceAccount][google.iam.admin.v1.ServiceAccount]. +func (c *IamClient) DeleteServiceAccount(ctx context.Context, req *adminpb.DeleteServiceAccountRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteServiceAccount[0:len(c.CallOptions.DeleteServiceAccount):len(c.CallOptions.DeleteServiceAccount)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.iamClient.DeleteServiceAccount(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ListServiceAccountKeys lists [ServiceAccountKeys][google.iam.admin.v1.ServiceAccountKey]. +func (c *IamClient) ListServiceAccountKeys(ctx context.Context, req *adminpb.ListServiceAccountKeysRequest, opts ...gax.CallOption) (*adminpb.ListServiceAccountKeysResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListServiceAccountKeys[0:len(c.CallOptions.ListServiceAccountKeys):len(c.CallOptions.ListServiceAccountKeys)], opts...) + var resp *adminpb.ListServiceAccountKeysResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamClient.ListServiceAccountKeys(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetServiceAccountKey gets the [ServiceAccountKey][google.iam.admin.v1.ServiceAccountKey] +// by key id. +func (c *IamClient) GetServiceAccountKey(ctx context.Context, req *adminpb.GetServiceAccountKeyRequest, opts ...gax.CallOption) (*adminpb.ServiceAccountKey, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetServiceAccountKey[0:len(c.CallOptions.GetServiceAccountKey):len(c.CallOptions.GetServiceAccountKey)], opts...) + var resp *adminpb.ServiceAccountKey + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamClient.GetServiceAccountKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateServiceAccountKey creates a [ServiceAccountKey][google.iam.admin.v1.ServiceAccountKey] +// and returns it. +func (c *IamClient) CreateServiceAccountKey(ctx context.Context, req *adminpb.CreateServiceAccountKeyRequest, opts ...gax.CallOption) (*adminpb.ServiceAccountKey, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateServiceAccountKey[0:len(c.CallOptions.CreateServiceAccountKey):len(c.CallOptions.CreateServiceAccountKey)], opts...) + var resp *adminpb.ServiceAccountKey + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamClient.CreateServiceAccountKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteServiceAccountKey deletes a [ServiceAccountKey][google.iam.admin.v1.ServiceAccountKey]. +func (c *IamClient) DeleteServiceAccountKey(ctx context.Context, req *adminpb.DeleteServiceAccountKeyRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteServiceAccountKey[0:len(c.CallOptions.DeleteServiceAccountKey):len(c.CallOptions.DeleteServiceAccountKey)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.iamClient.DeleteServiceAccountKey(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// SignBlob signs a blob using a service account's system-managed private key. +func (c *IamClient) SignBlob(ctx context.Context, req *adminpb.SignBlobRequest, opts ...gax.CallOption) (*adminpb.SignBlobResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SignBlob[0:len(c.CallOptions.SignBlob):len(c.CallOptions.SignBlob)], opts...) + var resp *adminpb.SignBlobResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamClient.SignBlob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// getIamPolicy returns the IAM access control policy for a +// [ServiceAccount][google.iam.admin.v1.ServiceAccount]. +func (c *IamClient) getIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetIamPolicy[0:len(c.CallOptions.GetIamPolicy):len(c.CallOptions.GetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamClient.GetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// setIamPolicy sets the IAM access control policy for a +// [ServiceAccount][google.iam.admin.v1.ServiceAccount]. +func (c *IamClient) setIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetIamPolicy[0:len(c.CallOptions.SetIamPolicy):len(c.CallOptions.SetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamClient.SetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// TestIamPermissions tests the specified permissions against the IAM access control policy +// for a [ServiceAccount][google.iam.admin.v1.ServiceAccount]. +func (c *IamClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.TestIamPermissions[0:len(c.CallOptions.TestIamPermissions):len(c.CallOptions.TestIamPermissions)], opts...) + var resp *iampb.TestIamPermissionsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamClient.TestIamPermissions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// QueryGrantableRoles queries roles that can be granted on a particular resource. +// A role is grantable if it can be used as the role in a binding for a policy +// for that resource. +func (c *IamClient) QueryGrantableRoles(ctx context.Context, req *adminpb.QueryGrantableRolesRequest, opts ...gax.CallOption) (*adminpb.QueryGrantableRolesResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.QueryGrantableRoles[0:len(c.CallOptions.QueryGrantableRoles):len(c.CallOptions.QueryGrantableRoles)], opts...) + var resp *adminpb.QueryGrantableRolesResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamClient.QueryGrantableRoles(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SignJwt signs a JWT using a service account's system-managed private key. +// +// If no expiry time (exp) is provided in the SignJwtRequest, IAM sets an +// an expiry time of one hour by default. If you request an expiry time of +// more than one hour, the request will fail. +func (c *IamClient) SignJwt(ctx context.Context, req *adminpb.SignJwtRequest, opts ...gax.CallOption) (*adminpb.SignJwtResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SignJwt[0:len(c.CallOptions.SignJwt):len(c.CallOptions.SignJwt)], opts...) + var resp *adminpb.SignJwtResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamClient.SignJwt(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ServiceAccountIterator manages a stream of *adminpb.ServiceAccount. +type ServiceAccountIterator struct { + items []*adminpb.ServiceAccount + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*adminpb.ServiceAccount, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ServiceAccountIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ServiceAccountIterator) Next() (*adminpb.ServiceAccount, error) { + var item *adminpb.ServiceAccount + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ServiceAccountIterator) bufLen() int { + return len(it.items) +} + +func (it *ServiceAccountIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/iam/admin/apiv1/iam_client_example_test.go b/vendor/cloud.google.com/go/iam/admin/apiv1/iam_client_example_test.go new file mode 100644 index 00000000..1caa8c3d --- /dev/null +++ b/vendor/cloud.google.com/go/iam/admin/apiv1/iam_client_example_test.go @@ -0,0 +1,272 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package admin_test + +import ( + "context" + + admin "cloud.google.com/go/iam/admin/apiv1" + "google.golang.org/api/iterator" + adminpb "google.golang.org/genproto/googleapis/iam/admin/v1" + iampb "google.golang.org/genproto/googleapis/iam/v1" +) + +func ExampleNewIamClient() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleIamClient_ListServiceAccounts() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &adminpb.ListServiceAccountsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListServiceAccounts(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleIamClient_GetServiceAccount() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &adminpb.GetServiceAccountRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetServiceAccount(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIamClient_CreateServiceAccount() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &adminpb.CreateServiceAccountRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateServiceAccount(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIamClient_UpdateServiceAccount() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &adminpb.ServiceAccount{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateServiceAccount(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIamClient_DeleteServiceAccount() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &adminpb.DeleteServiceAccountRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteServiceAccount(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleIamClient_ListServiceAccountKeys() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &adminpb.ListServiceAccountKeysRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ListServiceAccountKeys(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIamClient_GetServiceAccountKey() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &adminpb.GetServiceAccountKeyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetServiceAccountKey(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIamClient_CreateServiceAccountKey() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &adminpb.CreateServiceAccountKeyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateServiceAccountKey(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIamClient_DeleteServiceAccountKey() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &adminpb.DeleteServiceAccountKeyRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteServiceAccountKey(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleIamClient_SignBlob() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &adminpb.SignBlobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SignBlob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIamClient_TestIamPermissions() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.TestIamPermissionsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.TestIamPermissions(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIamClient_QueryGrantableRoles() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &adminpb.QueryGrantableRolesRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.QueryGrantableRoles(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIamClient_SignJwt() { + ctx := context.Background() + c, err := admin.NewIamClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &adminpb.SignJwtRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SignJwt(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/iam/admin/apiv1/mock_test.go b/vendor/cloud.google.com/go/iam/admin/apiv1/mock_test.go new file mode 100644 index 00000000..5851b1e7 --- /dev/null +++ b/vendor/cloud.google.com/go/iam/admin/apiv1/mock_test.go @@ -0,0 +1,1223 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package admin + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + adminpb "google.golang.org/genproto/googleapis/iam/admin/v1" + iampb "google.golang.org/genproto/googleapis/iam/v1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockIamServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + adminpb.IAMServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockIamServer) ListServiceAccounts(ctx context.Context, req *adminpb.ListServiceAccountsRequest) (*adminpb.ListServiceAccountsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*adminpb.ListServiceAccountsResponse), nil +} + +func (s *mockIamServer) GetServiceAccount(ctx context.Context, req *adminpb.GetServiceAccountRequest) (*adminpb.ServiceAccount, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*adminpb.ServiceAccount), nil +} + +func (s *mockIamServer) CreateServiceAccount(ctx context.Context, req *adminpb.CreateServiceAccountRequest) (*adminpb.ServiceAccount, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*adminpb.ServiceAccount), nil +} + +func (s *mockIamServer) UpdateServiceAccount(ctx context.Context, req *adminpb.ServiceAccount) (*adminpb.ServiceAccount, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*adminpb.ServiceAccount), nil +} + +func (s *mockIamServer) DeleteServiceAccount(ctx context.Context, req *adminpb.DeleteServiceAccountRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockIamServer) ListServiceAccountKeys(ctx context.Context, req *adminpb.ListServiceAccountKeysRequest) (*adminpb.ListServiceAccountKeysResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*adminpb.ListServiceAccountKeysResponse), nil +} + +func (s *mockIamServer) GetServiceAccountKey(ctx context.Context, req *adminpb.GetServiceAccountKeyRequest) (*adminpb.ServiceAccountKey, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*adminpb.ServiceAccountKey), nil +} + +func (s *mockIamServer) CreateServiceAccountKey(ctx context.Context, req *adminpb.CreateServiceAccountKeyRequest) (*adminpb.ServiceAccountKey, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*adminpb.ServiceAccountKey), nil +} + +func (s *mockIamServer) DeleteServiceAccountKey(ctx context.Context, req *adminpb.DeleteServiceAccountKeyRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockIamServer) SignBlob(ctx context.Context, req *adminpb.SignBlobRequest) (*adminpb.SignBlobResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*adminpb.SignBlobResponse), nil +} + +func (s *mockIamServer) SignJwt(ctx context.Context, req *adminpb.SignJwtRequest) (*adminpb.SignJwtResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*adminpb.SignJwtResponse), nil +} + +func (s *mockIamServer) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockIamServer) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockIamServer) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest) (*iampb.TestIamPermissionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.TestIamPermissionsResponse), nil +} + +func (s *mockIamServer) QueryGrantableRoles(ctx context.Context, req *adminpb.QueryGrantableRolesRequest) (*adminpb.QueryGrantableRolesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*adminpb.QueryGrantableRolesResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockIam mockIamServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + adminpb.RegisterIAMServer(serv, &mockIam) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestIamListServiceAccounts(t *testing.T) { + var nextPageToken string = "" + var accountsElement *adminpb.ServiceAccount = &adminpb.ServiceAccount{} + var accounts = []*adminpb.ServiceAccount{accountsElement} + var expectedResponse = &adminpb.ListServiceAccountsResponse{ + NextPageToken: nextPageToken, + Accounts: accounts, + } + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &adminpb.ListServiceAccountsRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListServiceAccounts(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Accounts[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamListServiceAccountsError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &adminpb.ListServiceAccountsRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListServiceAccounts(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamGetServiceAccount(t *testing.T) { + var name2 string = "name2-1052831874" + var projectId string = "projectId-1969970175" + var uniqueId string = "uniqueId-538310583" + var email string = "email96619420" + var displayName string = "displayName1615086568" + var etag []byte = []byte("21") + var oauth2ClientId string = "oauth2ClientId-1833466037" + var expectedResponse = &adminpb.ServiceAccount{ + Name: name2, + ProjectId: projectId, + UniqueId: uniqueId, + Email: email, + DisplayName: displayName, + Etag: etag, + Oauth2ClientId: oauth2ClientId, + } + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var request = &adminpb.GetServiceAccountRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetServiceAccount(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamGetServiceAccountError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var request = &adminpb.GetServiceAccountRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetServiceAccount(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamCreateServiceAccount(t *testing.T) { + var name2 string = "name2-1052831874" + var projectId string = "projectId-1969970175" + var uniqueId string = "uniqueId-538310583" + var email string = "email96619420" + var displayName string = "displayName1615086568" + var etag []byte = []byte("21") + var oauth2ClientId string = "oauth2ClientId-1833466037" + var expectedResponse = &adminpb.ServiceAccount{ + Name: name2, + ProjectId: projectId, + UniqueId: uniqueId, + Email: email, + DisplayName: displayName, + Etag: etag, + Oauth2ClientId: oauth2ClientId, + } + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var accountId string = "accountId-803333011" + var request = &adminpb.CreateServiceAccountRequest{ + Name: formattedName, + AccountId: accountId, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateServiceAccount(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamCreateServiceAccountError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var accountId string = "accountId-803333011" + var request = &adminpb.CreateServiceAccountRequest{ + Name: formattedName, + AccountId: accountId, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateServiceAccount(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamUpdateServiceAccount(t *testing.T) { + var name string = "name3373707" + var projectId string = "projectId-1969970175" + var uniqueId string = "uniqueId-538310583" + var email string = "email96619420" + var displayName string = "displayName1615086568" + var etag2 []byte = []byte("-120") + var oauth2ClientId string = "oauth2ClientId-1833466037" + var expectedResponse = &adminpb.ServiceAccount{ + Name: name, + ProjectId: projectId, + UniqueId: uniqueId, + Email: email, + DisplayName: displayName, + Etag: etag2, + Oauth2ClientId: oauth2ClientId, + } + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var etag []byte = []byte("21") + var request = &adminpb.ServiceAccount{ + Etag: etag, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateServiceAccount(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamUpdateServiceAccountError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var etag []byte = []byte("21") + var request = &adminpb.ServiceAccount{ + Etag: etag, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateServiceAccount(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamDeleteServiceAccount(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var request = &adminpb.DeleteServiceAccountRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteServiceAccount(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestIamDeleteServiceAccountError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var request = &adminpb.DeleteServiceAccountRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteServiceAccount(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestIamListServiceAccountKeys(t *testing.T) { + var expectedResponse *adminpb.ListServiceAccountKeysResponse = &adminpb.ListServiceAccountKeysResponse{} + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var request = &adminpb.ListServiceAccountKeysRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListServiceAccountKeys(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamListServiceAccountKeysError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var request = &adminpb.ListServiceAccountKeysRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListServiceAccountKeys(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamGetServiceAccountKey(t *testing.T) { + var name2 string = "name2-1052831874" + var privateKeyData []byte = []byte("-58") + var publicKeyData []byte = []byte("-96") + var expectedResponse = &adminpb.ServiceAccountKey{ + Name: name2, + PrivateKeyData: privateKeyData, + PublicKeyData: publicKeyData, + } + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s/keys/%s", "[PROJECT]", "[SERVICE_ACCOUNT]", "[KEY]") + var request = &adminpb.GetServiceAccountKeyRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetServiceAccountKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamGetServiceAccountKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s/keys/%s", "[PROJECT]", "[SERVICE_ACCOUNT]", "[KEY]") + var request = &adminpb.GetServiceAccountKeyRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetServiceAccountKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamCreateServiceAccountKey(t *testing.T) { + var name2 string = "name2-1052831874" + var privateKeyData []byte = []byte("-58") + var publicKeyData []byte = []byte("-96") + var expectedResponse = &adminpb.ServiceAccountKey{ + Name: name2, + PrivateKeyData: privateKeyData, + PublicKeyData: publicKeyData, + } + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var request = &adminpb.CreateServiceAccountKeyRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateServiceAccountKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamCreateServiceAccountKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var request = &adminpb.CreateServiceAccountKeyRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateServiceAccountKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamDeleteServiceAccountKey(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s/keys/%s", "[PROJECT]", "[SERVICE_ACCOUNT]", "[KEY]") + var request = &adminpb.DeleteServiceAccountKeyRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteServiceAccountKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestIamDeleteServiceAccountKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s/keys/%s", "[PROJECT]", "[SERVICE_ACCOUNT]", "[KEY]") + var request = &adminpb.DeleteServiceAccountKeyRequest{ + Name: formattedName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteServiceAccountKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestIamSignBlob(t *testing.T) { + var keyId string = "keyId-1134673157" + var signature []byte = []byte("-72") + var expectedResponse = &adminpb.SignBlobResponse{ + KeyId: keyId, + Signature: signature, + } + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var bytesToSign []byte = []byte("45") + var request = &adminpb.SignBlobRequest{ + Name: formattedName, + BytesToSign: bytesToSign, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SignBlob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamSignBlobError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var bytesToSign []byte = []byte("45") + var request = &adminpb.SignBlobRequest{ + Name: formattedName, + BytesToSign: bytesToSign, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SignBlob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamGetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.getIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamGetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.getIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamSetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.setIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamSetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.setIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamTestIamPermissions(t *testing.T) { + var expectedResponse *iampb.TestIamPermissionsResponse = &iampb.TestIamPermissionsResponse{} + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamTestIamPermissionsError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamQueryGrantableRoles(t *testing.T) { + var nextPageToken string = "nextPageToken-1530815211" + var expectedResponse = &adminpb.QueryGrantableRolesResponse{ + NextPageToken: nextPageToken, + } + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var fullResourceName string = "fullResourceName1300993644" + var request = &adminpb.QueryGrantableRolesRequest{ + FullResourceName: fullResourceName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.QueryGrantableRoles(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamQueryGrantableRolesError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var fullResourceName string = "fullResourceName1300993644" + var request = &adminpb.QueryGrantableRolesRequest{ + FullResourceName: fullResourceName, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.QueryGrantableRoles(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamSignJwt(t *testing.T) { + var keyId string = "keyId-1134673157" + var signedJwt string = "signedJwt-979546844" + var expectedResponse = &adminpb.SignJwtResponse{ + KeyId: keyId, + SignedJwt: signedJwt, + } + + mockIam.err = nil + mockIam.reqs = nil + + mockIam.resps = append(mockIam.resps[:0], expectedResponse) + + var name string = "name3373707" + var payload string = "payload-786701938" + var request = &adminpb.SignJwtRequest{ + Name: name, + Payload: payload, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SignJwt(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIam.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamSignJwtError(t *testing.T) { + errCode := codes.PermissionDenied + mockIam.err = gstatus.Error(errCode, "test error") + + var name string = "name3373707" + var payload string = "payload-786701938" + var request = &adminpb.SignJwtRequest{ + Name: name, + Payload: payload, + } + + c, err := NewIamClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SignJwt(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/iam/admin/apiv1/path_funcs.go b/vendor/cloud.google.com/go/iam/admin/apiv1/path_funcs.go new file mode 100644 index 00000000..9818266f --- /dev/null +++ b/vendor/cloud.google.com/go/iam/admin/apiv1/path_funcs.go @@ -0,0 +1,45 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package admin + +// IamProjectPath returns the path for the project resource. +func IamProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} + +// IamServiceAccountPath returns the path for the service account resource. +func IamServiceAccountPath(project, serviceAccount string) string { + return "" + + "projects/" + + project + + "/serviceAccounts/" + + serviceAccount + + "" +} + +// IamKeyPath returns the path for the key resource. +func IamKeyPath(project, serviceAccount, key string) string { + return "" + + "projects/" + + project + + "/serviceAccounts/" + + serviceAccount + + "/keys/" + + key + + "" +} diff --git a/vendor/cloud.google.com/go/iam/admin/apiv1/policy_methods.go b/vendor/cloud.google.com/go/iam/admin/apiv1/policy_methods.go new file mode 100644 index 00000000..d61abb74 --- /dev/null +++ b/vendor/cloud.google.com/go/iam/admin/apiv1/policy_methods.go @@ -0,0 +1,53 @@ +// Copyright 2016 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This is handwritten code. These methods are implemented by hand so they can use +// the iam.Policy type. + +package admin + +import ( + "context" + + "cloud.google.com/go/iam" + iampb "google.golang.org/genproto/googleapis/iam/v1" +) + +// GetIamPolicy returns the IAM access control policy for a ServiceAccount. +func (c *IamClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest) (*iam.Policy, error) { + policy, err := c.getIamPolicy(ctx, req) + if err != nil { + return nil, err + } + return &iam.Policy{InternalProto: policy}, nil +} + +// SetIamPolicyRequest is the request type for the SetIamPolicy method. +type SetIamPolicyRequest struct { + Resource string + Policy *iam.Policy +} + +// SetIamPolicy sets the IAM access control policy for a ServiceAccount. +func (c *IamClient) SetIamPolicy(ctx context.Context, req *SetIamPolicyRequest) (*iam.Policy, error) { + preq := &iampb.SetIamPolicyRequest{ + Resource: req.Resource, + Policy: req.Policy.InternalProto, + } + policy, err := c.setIamPolicy(ctx, preq) + if err != nil { + return nil, err + } + return &iam.Policy{InternalProto: policy}, nil +} diff --git a/vendor/cloud.google.com/go/iam/credentials/apiv1/doc.go b/vendor/cloud.google.com/go/iam/credentials/apiv1/doc.go new file mode 100644 index 00000000..718b2b4f --- /dev/null +++ b/vendor/cloud.google.com/go/iam/credentials/apiv1/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package credentials is an auto-generated package for the +// IAM Service Account Credentials API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// IAM Service Account Credentials API +package credentials // import "cloud.google.com/go/iam/credentials/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/iam/credentials/apiv1/iam_credentials_client.go b/vendor/cloud.google.com/go/iam/credentials/apiv1/iam_credentials_client.go new file mode 100644 index 00000000..897d151e --- /dev/null +++ b/vendor/cloud.google.com/go/iam/credentials/apiv1/iam_credentials_client.go @@ -0,0 +1,214 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package credentials + +import ( + "context" + "time" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + credentialspb "google.golang.org/genproto/googleapis/iam/credentials/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// IamCredentialsCallOptions contains the retry settings for each method of IamCredentialsClient. +type IamCredentialsCallOptions struct { + GenerateAccessToken []gax.CallOption + GenerateIdToken []gax.CallOption + SignBlob []gax.CallOption + SignJwt []gax.CallOption + GenerateIdentityBindingAccessToken []gax.CallOption +} + +func defaultIamCredentialsClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("iamcredentials.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultIamCredentialsCallOptions() *IamCredentialsCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &IamCredentialsCallOptions{ + GenerateAccessToken: retry[[2]string{"default", "idempotent"}], + GenerateIdToken: retry[[2]string{"default", "idempotent"}], + SignBlob: retry[[2]string{"default", "idempotent"}], + SignJwt: retry[[2]string{"default", "idempotent"}], + GenerateIdentityBindingAccessToken: retry[[2]string{"default", "idempotent"}], + } +} + +// IamCredentialsClient is a client for interacting with IAM Service Account Credentials API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type IamCredentialsClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + iamCredentialsClient credentialspb.IAMCredentialsClient + + // The call options for this service. + CallOptions *IamCredentialsCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewIamCredentialsClient creates a new iam credentials client. +// +// A service account is a special type of Google account that belongs to your +// application or a virtual machine (VM), instead of to an individual end user. +// Your application assumes the identity of the service account to call Google +// APIs, so that the users aren't directly involved. +// +// Service account credentials are used to temporarily assume the identity +// of the service account. Supported credential types include OAuth 2.0 access +// tokens, OpenID Connect ID tokens, self-signed JSON Web Tokens (JWTs), and +// more. +func NewIamCredentialsClient(ctx context.Context, opts ...option.ClientOption) (*IamCredentialsClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultIamCredentialsClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &IamCredentialsClient{ + conn: conn, + CallOptions: defaultIamCredentialsCallOptions(), + + iamCredentialsClient: credentialspb.NewIAMCredentialsClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *IamCredentialsClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *IamCredentialsClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *IamCredentialsClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// GenerateAccessToken generates an OAuth 2.0 access token for a service account. +func (c *IamCredentialsClient) GenerateAccessToken(ctx context.Context, req *credentialspb.GenerateAccessTokenRequest, opts ...gax.CallOption) (*credentialspb.GenerateAccessTokenResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GenerateAccessToken[0:len(c.CallOptions.GenerateAccessToken):len(c.CallOptions.GenerateAccessToken)], opts...) + var resp *credentialspb.GenerateAccessTokenResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamCredentialsClient.GenerateAccessToken(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GenerateIdToken generates an OpenID Connect ID token for a service account. +func (c *IamCredentialsClient) GenerateIdToken(ctx context.Context, req *credentialspb.GenerateIdTokenRequest, opts ...gax.CallOption) (*credentialspb.GenerateIdTokenResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GenerateIdToken[0:len(c.CallOptions.GenerateIdToken):len(c.CallOptions.GenerateIdToken)], opts...) + var resp *credentialspb.GenerateIdTokenResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamCredentialsClient.GenerateIdToken(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SignBlob signs a blob using a service account's system-managed private key. +func (c *IamCredentialsClient) SignBlob(ctx context.Context, req *credentialspb.SignBlobRequest, opts ...gax.CallOption) (*credentialspb.SignBlobResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SignBlob[0:len(c.CallOptions.SignBlob):len(c.CallOptions.SignBlob)], opts...) + var resp *credentialspb.SignBlobResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamCredentialsClient.SignBlob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SignJwt signs a JWT using a service account's system-managed private key. +func (c *IamCredentialsClient) SignJwt(ctx context.Context, req *credentialspb.SignJwtRequest, opts ...gax.CallOption) (*credentialspb.SignJwtResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SignJwt[0:len(c.CallOptions.SignJwt):len(c.CallOptions.SignJwt)], opts...) + var resp *credentialspb.SignJwtResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamCredentialsClient.SignJwt(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GenerateIdentityBindingAccessToken exchange a JWT signed by third party identity provider to an OAuth 2.0 +// access token +func (c *IamCredentialsClient) GenerateIdentityBindingAccessToken(ctx context.Context, req *credentialspb.GenerateIdentityBindingAccessTokenRequest, opts ...gax.CallOption) (*credentialspb.GenerateIdentityBindingAccessTokenResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GenerateIdentityBindingAccessToken[0:len(c.CallOptions.GenerateIdentityBindingAccessToken):len(c.CallOptions.GenerateIdentityBindingAccessToken)], opts...) + var resp *credentialspb.GenerateIdentityBindingAccessTokenResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.iamCredentialsClient.GenerateIdentityBindingAccessToken(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/iam/credentials/apiv1/iam_credentials_client_example_test.go b/vendor/cloud.google.com/go/iam/credentials/apiv1/iam_credentials_client_example_test.go new file mode 100644 index 00000000..0aed2668 --- /dev/null +++ b/vendor/cloud.google.com/go/iam/credentials/apiv1/iam_credentials_client_example_test.go @@ -0,0 +1,124 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package credentials_test + +import ( + "context" + + credentials "cloud.google.com/go/iam/credentials/apiv1" + credentialspb "google.golang.org/genproto/googleapis/iam/credentials/v1" +) + +func ExampleNewIamCredentialsClient() { + ctx := context.Background() + c, err := credentials.NewIamCredentialsClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleIamCredentialsClient_GenerateAccessToken() { + ctx := context.Background() + c, err := credentials.NewIamCredentialsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &credentialspb.GenerateAccessTokenRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GenerateAccessToken(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIamCredentialsClient_GenerateIdToken() { + ctx := context.Background() + c, err := credentials.NewIamCredentialsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &credentialspb.GenerateIdTokenRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GenerateIdToken(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIamCredentialsClient_SignBlob() { + ctx := context.Background() + c, err := credentials.NewIamCredentialsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &credentialspb.SignBlobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SignBlob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIamCredentialsClient_SignJwt() { + ctx := context.Background() + c, err := credentials.NewIamCredentialsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &credentialspb.SignJwtRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SignJwt(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleIamCredentialsClient_GenerateIdentityBindingAccessToken() { + ctx := context.Background() + c, err := credentials.NewIamCredentialsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &credentialspb.GenerateIdentityBindingAccessTokenRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GenerateIdentityBindingAccessToken(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/iam/credentials/apiv1/mock_test.go b/vendor/cloud.google.com/go/iam/credentials/apiv1/mock_test.go new file mode 100644 index 00000000..14d81ae3 --- /dev/null +++ b/vendor/cloud.google.com/go/iam/credentials/apiv1/mock_test.go @@ -0,0 +1,474 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package credentials + +import ( + credentialspb "google.golang.org/genproto/googleapis/iam/credentials/v1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockIamCredentialsServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + credentialspb.IAMCredentialsServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockIamCredentialsServer) GenerateAccessToken(ctx context.Context, req *credentialspb.GenerateAccessTokenRequest) (*credentialspb.GenerateAccessTokenResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*credentialspb.GenerateAccessTokenResponse), nil +} + +func (s *mockIamCredentialsServer) GenerateIdToken(ctx context.Context, req *credentialspb.GenerateIdTokenRequest) (*credentialspb.GenerateIdTokenResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*credentialspb.GenerateIdTokenResponse), nil +} + +func (s *mockIamCredentialsServer) SignBlob(ctx context.Context, req *credentialspb.SignBlobRequest) (*credentialspb.SignBlobResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*credentialspb.SignBlobResponse), nil +} + +func (s *mockIamCredentialsServer) SignJwt(ctx context.Context, req *credentialspb.SignJwtRequest) (*credentialspb.SignJwtResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*credentialspb.SignJwtResponse), nil +} + +func (s *mockIamCredentialsServer) GenerateIdentityBindingAccessToken(ctx context.Context, req *credentialspb.GenerateIdentityBindingAccessTokenRequest) (*credentialspb.GenerateIdentityBindingAccessTokenResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*credentialspb.GenerateIdentityBindingAccessTokenResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockIamCredentials mockIamCredentialsServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + credentialspb.RegisterIAMCredentialsServer(serv, &mockIamCredentials) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestIamCredentialsGenerateAccessToken(t *testing.T) { + var accessToken string = "accessToken-1938933922" + var expectedResponse = &credentialspb.GenerateAccessTokenResponse{ + AccessToken: accessToken, + } + + mockIamCredentials.err = nil + mockIamCredentials.reqs = nil + + mockIamCredentials.resps = append(mockIamCredentials.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var scope []string = nil + var request = &credentialspb.GenerateAccessTokenRequest{ + Name: formattedName, + Scope: scope, + } + + c, err := NewIamCredentialsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GenerateAccessToken(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIamCredentials.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamCredentialsGenerateAccessTokenError(t *testing.T) { + errCode := codes.PermissionDenied + mockIamCredentials.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var scope []string = nil + var request = &credentialspb.GenerateAccessTokenRequest{ + Name: formattedName, + Scope: scope, + } + + c, err := NewIamCredentialsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GenerateAccessToken(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamCredentialsGenerateIdToken(t *testing.T) { + var token string = "token110541305" + var expectedResponse = &credentialspb.GenerateIdTokenResponse{ + Token: token, + } + + mockIamCredentials.err = nil + mockIamCredentials.reqs = nil + + mockIamCredentials.resps = append(mockIamCredentials.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var audience string = "audience975628804" + var request = &credentialspb.GenerateIdTokenRequest{ + Name: formattedName, + Audience: audience, + } + + c, err := NewIamCredentialsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GenerateIdToken(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIamCredentials.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamCredentialsGenerateIdTokenError(t *testing.T) { + errCode := codes.PermissionDenied + mockIamCredentials.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var audience string = "audience975628804" + var request = &credentialspb.GenerateIdTokenRequest{ + Name: formattedName, + Audience: audience, + } + + c, err := NewIamCredentialsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GenerateIdToken(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamCredentialsSignBlob(t *testing.T) { + var keyId string = "keyId-1134673157" + var signedBlob []byte = []byte("-32") + var expectedResponse = &credentialspb.SignBlobResponse{ + KeyId: keyId, + SignedBlob: signedBlob, + } + + mockIamCredentials.err = nil + mockIamCredentials.reqs = nil + + mockIamCredentials.resps = append(mockIamCredentials.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var payload []byte = []byte("-114") + var request = &credentialspb.SignBlobRequest{ + Name: formattedName, + Payload: payload, + } + + c, err := NewIamCredentialsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SignBlob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIamCredentials.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamCredentialsSignBlobError(t *testing.T) { + errCode := codes.PermissionDenied + mockIamCredentials.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var payload []byte = []byte("-114") + var request = &credentialspb.SignBlobRequest{ + Name: formattedName, + Payload: payload, + } + + c, err := NewIamCredentialsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SignBlob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamCredentialsSignJwt(t *testing.T) { + var keyId string = "keyId-1134673157" + var signedJwt string = "signedJwt-979546844" + var expectedResponse = &credentialspb.SignJwtResponse{ + KeyId: keyId, + SignedJwt: signedJwt, + } + + mockIamCredentials.err = nil + mockIamCredentials.reqs = nil + + mockIamCredentials.resps = append(mockIamCredentials.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var payload string = "-114" + var request = &credentialspb.SignJwtRequest{ + Name: formattedName, + Payload: payload, + } + + c, err := NewIamCredentialsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SignJwt(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIamCredentials.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamCredentialsSignJwtError(t *testing.T) { + errCode := codes.PermissionDenied + mockIamCredentials.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var payload string = "-114" + var request = &credentialspb.SignJwtRequest{ + Name: formattedName, + Payload: payload, + } + + c, err := NewIamCredentialsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SignJwt(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestIamCredentialsGenerateIdentityBindingAccessToken(t *testing.T) { + var accessToken string = "accessToken-1938933922" + var expectedResponse = &credentialspb.GenerateIdentityBindingAccessTokenResponse{ + AccessToken: accessToken, + } + + mockIamCredentials.err = nil + mockIamCredentials.reqs = nil + + mockIamCredentials.resps = append(mockIamCredentials.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var scope []string = nil + var jwt string = "jwt105671" + var request = &credentialspb.GenerateIdentityBindingAccessTokenRequest{ + Name: formattedName, + Scope: scope, + Jwt: jwt, + } + + c, err := NewIamCredentialsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GenerateIdentityBindingAccessToken(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockIamCredentials.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestIamCredentialsGenerateIdentityBindingAccessTokenError(t *testing.T) { + errCode := codes.PermissionDenied + mockIamCredentials.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/serviceAccounts/%s", "[PROJECT]", "[SERVICE_ACCOUNT]") + var scope []string = nil + var jwt string = "jwt105671" + var request = &credentialspb.GenerateIdentityBindingAccessTokenRequest{ + Name: formattedName, + Scope: scope, + Jwt: jwt, + } + + c, err := NewIamCredentialsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GenerateIdentityBindingAccessToken(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/iam/iam.go b/vendor/cloud.google.com/go/iam/iam.go new file mode 100644 index 00000000..76df6356 --- /dev/null +++ b/vendor/cloud.google.com/go/iam/iam.go @@ -0,0 +1,292 @@ +// Copyright 2016 Google LLC +// +// 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 iam supports the resource-specific operations of Google Cloud +// IAM (Identity and Access Management) for the Google Cloud Libraries. +// See https://cloud.google.com/iam for more about IAM. +// +// Users of the Google Cloud Libraries will typically not use this package +// directly. Instead they will begin with some resource that supports IAM, like +// a pubsub topic, and call its IAM method to get a Handle for that resource. +package iam + +import ( + "context" + "time" + + gax "github.com/googleapis/gax-go" + pb "google.golang.org/genproto/googleapis/iam/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" +) + +// client abstracts the IAMPolicy API to allow multiple implementations. +type client interface { + Get(ctx context.Context, resource string) (*pb.Policy, error) + Set(ctx context.Context, resource string, p *pb.Policy) error + Test(ctx context.Context, resource string, perms []string) ([]string, error) +} + +// grpcClient implements client for the standard gRPC-based IAMPolicy service. +type grpcClient struct { + c pb.IAMPolicyClient +} + +var withRetry = gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60 * time.Second, + Multiplier: 1.3, + }) +}) + +func (g *grpcClient) Get(ctx context.Context, resource string) (*pb.Policy, error) { + var proto *pb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error { + var err error + proto, err = g.c.GetIamPolicy(ctx, &pb.GetIamPolicyRequest{Resource: resource}) + return err + }, withRetry) + if err != nil { + return nil, err + } + return proto, nil +} + +func (g *grpcClient) Set(ctx context.Context, resource string, p *pb.Policy) error { + return gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error { + _, err := g.c.SetIamPolicy(ctx, &pb.SetIamPolicyRequest{ + Resource: resource, + Policy: p, + }) + return err + }, withRetry) +} + +func (g *grpcClient) Test(ctx context.Context, resource string, perms []string) ([]string, error) { + var res *pb.TestIamPermissionsResponse + err := gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error { + var err error + res, err = g.c.TestIamPermissions(ctx, &pb.TestIamPermissionsRequest{ + Resource: resource, + Permissions: perms, + }) + return err + }, withRetry) + if err != nil { + return nil, err + } + return res.Permissions, nil +} + +// A Handle provides IAM operations for a resource. +type Handle struct { + c client + resource string +} + +// InternalNewHandle is for use by the Google Cloud Libraries only. +// +// InternalNewHandle returns a Handle for resource. +// The conn parameter refers to a server that must support the IAMPolicy service. +func InternalNewHandle(conn *grpc.ClientConn, resource string) *Handle { + return InternalNewHandleGRPCClient(pb.NewIAMPolicyClient(conn), resource) +} + +// InternalNewHandleGRPCClient is for use by the Google Cloud Libraries only. +// +// InternalNewHandleClient returns a Handle for resource using the given +// grpc service that implements IAM as a mixin +func InternalNewHandleGRPCClient(c pb.IAMPolicyClient, resource string) *Handle { + return InternalNewHandleClient(&grpcClient{c: c}, resource) +} + +// InternalNewHandleClient is for use by the Google Cloud Libraries only. +// +// InternalNewHandleClient returns a Handle for resource using the given +// client implementation. +func InternalNewHandleClient(c client, resource string) *Handle { + return &Handle{ + c: c, + resource: resource, + } +} + +// Policy retrieves the IAM policy for the resource. +func (h *Handle) Policy(ctx context.Context) (*Policy, error) { + proto, err := h.c.Get(ctx, h.resource) + if err != nil { + return nil, err + } + return &Policy{InternalProto: proto}, nil +} + +// SetPolicy replaces the resource's current policy with the supplied Policy. +// +// If policy was created from a prior call to Get, then the modification will +// only succeed if the policy has not changed since the Get. +func (h *Handle) SetPolicy(ctx context.Context, policy *Policy) error { + return h.c.Set(ctx, h.resource, policy.InternalProto) +} + +// TestPermissions returns the subset of permissions that the caller has on the resource. +func (h *Handle) TestPermissions(ctx context.Context, permissions []string) ([]string, error) { + return h.c.Test(ctx, h.resource, permissions) +} + +// A RoleName is a name representing a collection of permissions. +type RoleName string + +// Common role names. +const ( + Owner RoleName = "roles/owner" + Editor RoleName = "roles/editor" + Viewer RoleName = "roles/viewer" +) + +const ( + // AllUsers is a special member that denotes all users, even unauthenticated ones. + AllUsers = "allUsers" + + // AllAuthenticatedUsers is a special member that denotes all authenticated users. + AllAuthenticatedUsers = "allAuthenticatedUsers" +) + +// A Policy is a list of Bindings representing roles +// granted to members. +// +// The zero Policy is a valid policy with no bindings. +type Policy struct { + // TODO(jba): when type aliases are available, put Policy into an internal package + // and provide an exported alias here. + + // This field is exported for use by the Google Cloud Libraries only. + // It may become unexported in a future release. + InternalProto *pb.Policy +} + +// Members returns the list of members with the supplied role. +// The return value should not be modified. Use Add and Remove +// to modify the members of a role. +func (p *Policy) Members(r RoleName) []string { + b := p.binding(r) + if b == nil { + return nil + } + return b.Members +} + +// HasRole reports whether member has role r. +func (p *Policy) HasRole(member string, r RoleName) bool { + return memberIndex(member, p.binding(r)) >= 0 +} + +// Add adds member member to role r if it is not already present. +// A new binding is created if there is no binding for the role. +func (p *Policy) Add(member string, r RoleName) { + b := p.binding(r) + if b == nil { + if p.InternalProto == nil { + p.InternalProto = &pb.Policy{} + } + p.InternalProto.Bindings = append(p.InternalProto.Bindings, &pb.Binding{ + Role: string(r), + Members: []string{member}, + }) + return + } + if memberIndex(member, b) < 0 { + b.Members = append(b.Members, member) + return + } +} + +// Remove removes member from role r if it is present. +func (p *Policy) Remove(member string, r RoleName) { + bi := p.bindingIndex(r) + if bi < 0 { + return + } + bindings := p.InternalProto.Bindings + b := bindings[bi] + mi := memberIndex(member, b) + if mi < 0 { + return + } + // Order doesn't matter for bindings or members, so to remove, move the last item + // into the removed spot and shrink the slice. + if len(b.Members) == 1 { + // Remove binding. + last := len(bindings) - 1 + bindings[bi] = bindings[last] + bindings[last] = nil + p.InternalProto.Bindings = bindings[:last] + return + } + // Remove member. + // TODO(jba): worry about multiple copies of m? + last := len(b.Members) - 1 + b.Members[mi] = b.Members[last] + b.Members[last] = "" + b.Members = b.Members[:last] +} + +// Roles returns the names of all the roles that appear in the Policy. +func (p *Policy) Roles() []RoleName { + if p.InternalProto == nil { + return nil + } + var rns []RoleName + for _, b := range p.InternalProto.Bindings { + rns = append(rns, RoleName(b.Role)) + } + return rns +} + +// binding returns the Binding for the suppied role, or nil if there isn't one. +func (p *Policy) binding(r RoleName) *pb.Binding { + i := p.bindingIndex(r) + if i < 0 { + return nil + } + return p.InternalProto.Bindings[i] +} + +func (p *Policy) bindingIndex(r RoleName) int { + if p.InternalProto == nil { + return -1 + } + for i, b := range p.InternalProto.Bindings { + if b.Role == string(r) { + return i + } + } + return -1 +} + +// memberIndex returns the index of m in b's Members, or -1 if not found. +func memberIndex(m string, b *pb.Binding) int { + if b == nil { + return -1 + } + for i, mm := range b.Members { + if mm == m { + return i + } + } + return -1 +} diff --git a/vendor/cloud.google.com/go/iam/iam_test.go b/vendor/cloud.google.com/go/iam/iam_test.go new file mode 100644 index 00000000..67a9f05c --- /dev/null +++ b/vendor/cloud.google.com/go/iam/iam_test.go @@ -0,0 +1,87 @@ +// Copyright 2016 Google LLC +// +// 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 iam + +import ( + "fmt" + "sort" + "testing" + + "cloud.google.com/go/internal/testutil" +) + +func TestPolicy(t *testing.T) { + p := &Policy{} + + add := func(member string, role RoleName) { + p.Add(member, role) + } + remove := func(member string, role RoleName) { + p.Remove(member, role) + } + + if msg, ok := checkMembers(p, Owner, nil); !ok { + t.Fatal(msg) + } + add("m1", Owner) + if msg, ok := checkMembers(p, Owner, []string{"m1"}); !ok { + t.Fatal(msg) + } + add("m2", Owner) + if msg, ok := checkMembers(p, Owner, []string{"m1", "m2"}); !ok { + t.Fatal(msg) + } + add("m1", Owner) // duplicate adds ignored + if msg, ok := checkMembers(p, Owner, []string{"m1", "m2"}); !ok { + t.Fatal(msg) + } + // No other roles populated yet. + if msg, ok := checkMembers(p, Viewer, nil); !ok { + t.Fatal(msg) + } + remove("m1", Owner) + if msg, ok := checkMembers(p, Owner, []string{"m2"}); !ok { + t.Fatal(msg) + } + if msg, ok := checkMembers(p, Viewer, nil); !ok { + t.Fatal(msg) + } + remove("m3", Owner) // OK to remove non-existent member. + if msg, ok := checkMembers(p, Owner, []string{"m2"}); !ok { + t.Fatal(msg) + } + remove("m2", Owner) + if msg, ok := checkMembers(p, Owner, nil); !ok { + t.Fatal(msg) + } + if got, want := p.Roles(), []RoleName(nil); !testutil.Equal(got, want) { + t.Fatalf("roles: got %v, want %v", got, want) + } +} + +func checkMembers(p *Policy, role RoleName, wantMembers []string) (string, bool) { + gotMembers := p.Members(role) + sort.Strings(gotMembers) + sort.Strings(wantMembers) + if !testutil.Equal(gotMembers, wantMembers) { + return fmt.Sprintf("got %v, want %v", gotMembers, wantMembers), false + } + for _, m := range wantMembers { + if !p.HasRole(m, role) { + return fmt.Sprintf("member %q should have role %s but does not", m, role), false + } + } + return "", true +} diff --git a/vendor/cloud.google.com/go/internal/annotate.go b/vendor/cloud.google.com/go/internal/annotate.go new file mode 100644 index 00000000..6435695b --- /dev/null +++ b/vendor/cloud.google.com/go/internal/annotate.go @@ -0,0 +1,54 @@ +// Copyright 2017 Google LLC +// +// 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 internal + +import ( + "fmt" + + "google.golang.org/api/googleapi" + "google.golang.org/grpc/status" +) + +// Annotate prepends msg to the error message in err, attempting +// to preserve other information in err, like an error code. +// +// Annotate panics if err is nil. +// +// Annotate knows about these error types: +// - "google.golang.org/grpc/status".Status +// - "google.golang.org/api/googleapi".Error +// If the error is not one of these types, Annotate behaves +// like +// fmt.Errorf("%s: %v", msg, err) +func Annotate(err error, msg string) error { + if err == nil { + panic("Annotate called with nil") + } + if s, ok := status.FromError(err); ok { + p := s.Proto() + p.Message = msg + ": " + p.Message + return status.ErrorProto(p) + } + if g, ok := err.(*googleapi.Error); ok { + g.Message = msg + ": " + g.Message + return g + } + return fmt.Errorf("%s: %v", msg, err) +} + +// Annotatef uses format and args to format a string, then calls Annotate. +func Annotatef(err error, format string, args ...interface{}) error { + return Annotate(err, fmt.Sprintf(format, args...)) +} diff --git a/vendor/cloud.google.com/go/internal/annotate_test.go b/vendor/cloud.google.com/go/internal/annotate_test.go new file mode 100644 index 00000000..7203f51a --- /dev/null +++ b/vendor/cloud.google.com/go/internal/annotate_test.go @@ -0,0 +1,65 @@ +// Copyright 2017 Google LLC +// +// 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 internal + +import ( + "errors" + "testing" + + "google.golang.org/api/googleapi" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const wantMessage = "prefix: msg" + +func TestAnnotateGRPC(t *testing.T) { + // grpc Status error + err := status.Error(codes.NotFound, "msg") + err = Annotate(err, "prefix") + got, ok := status.FromError(err) + if !ok { + t.Fatalf("got %T, wanted a status", got) + } + if g, w := got.Code(), codes.NotFound; g != w { + t.Errorf("got code %v, want %v", g, w) + } + if g, w := got.Message(), wantMessage; g != w { + t.Errorf("got message %q, want %q", g, w) + } +} + +func TestAnnotateGoogleapi(t *testing.T) { + // googleapi error + var err error = &googleapi.Error{Code: 403, Message: "msg"} + err = Annotate(err, "prefix") + got2, ok := err.(*googleapi.Error) + if !ok { + t.Fatalf("got %T, wanted a googleapi.Error", got2) + } + if g, w := got2.Code, 403; g != w { + t.Errorf("got code %d, want %d", g, w) + } + if g, w := got2.Message, wantMessage; g != w { + t.Errorf("got message %q, want %q", g, w) + } +} + +func TestAnnotateUnknownError(t *testing.T) { + err := Annotate(errors.New("msg"), "prefix") + if g, w := err.Error(), wantMessage; g != w { + t.Errorf("got message %q, want %q", g, w) + } +} diff --git a/vendor/cloud.google.com/go/internal/btree/README.md b/vendor/cloud.google.com/go/internal/btree/README.md new file mode 100644 index 00000000..601ff544 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/btree/README.md @@ -0,0 +1,11 @@ +This package is a fork of github.com/jba/btree at commit +d4edd57f39b8425fc2c631047ff4dc6024d82a4f, which itself was a fork of +github.com/google/btree at 316fb6d3f031ae8f4d457c6c5186b9e3ded70435. + +This directory makes the following modifications: + +- Updated copyright notice. +- removed LICENSE (it is the same as the repo-wide license, Apache 2.0) +- Removed examples_test.go and .travis.yml. +- Added this file. + diff --git a/vendor/cloud.google.com/go/internal/btree/benchmarks_test.go b/vendor/cloud.google.com/go/internal/btree/benchmarks_test.go new file mode 100644 index 00000000..4910cab3 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/btree/benchmarks_test.go @@ -0,0 +1,266 @@ +// Copyright 2014 Google LLC +// +// 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 btree + +import ( + "fmt" + "sort" + "testing" +) + +const benchmarkTreeSize = 10000 + +var degrees = []int{2, 8, 32, 64} + +func BenchmarkInsert(b *testing.B) { + insertP := perm(benchmarkTreeSize) + for _, d := range degrees { + b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) { + i := 0 + for i < b.N { + tr := New(d, less) + for _, m := range insertP { + tr.Set(m.Key, m.Value) + i++ + if i >= b.N { + return + } + } + } + }) + } +} + +func BenchmarkDeleteInsert(b *testing.B) { + insertP := perm(benchmarkTreeSize) + for _, d := range degrees { + b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) { + tr := New(d, less) + for _, m := range insertP { + tr.Set(m.Key, m.Value) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + m := insertP[i%benchmarkTreeSize] + tr.Delete(m.Key) + tr.Set(m.Key, m.Value) + } + }) + } +} + +func BenchmarkDeleteInsertCloneOnce(b *testing.B) { + insertP := perm(benchmarkTreeSize) + for _, d := range degrees { + b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) { + tr := New(d, less) + for _, m := range insertP { + tr.Set(m.Key, m.Value) + } + tr = tr.Clone() + b.ResetTimer() + for i := 0; i < b.N; i++ { + m := insertP[i%benchmarkTreeSize] + tr.Delete(m.Key) + tr.Set(m.Key, m.Value) + } + }) + } +} + +func BenchmarkDeleteInsertCloneEachTime(b *testing.B) { + insertP := perm(benchmarkTreeSize) + for _, d := range degrees { + b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) { + tr := New(d, less) + for _, m := range insertP { + tr.Set(m.Key, m.Value) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + tr = tr.Clone() + m := insertP[i%benchmarkTreeSize] + tr.Delete(m.Key) + tr.Set(m.Key, m.Value) + } + }) + } +} + +func BenchmarkDelete(b *testing.B) { + insertP := perm(benchmarkTreeSize) + removeP := perm(benchmarkTreeSize) + for _, d := range degrees { + b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) { + i := 0 + for i < b.N { + b.StopTimer() + tr := New(d, less) + for _, v := range insertP { + tr.Set(v.Key, v.Value) + } + b.StartTimer() + for _, m := range removeP { + tr.Delete(m.Key) + i++ + if i >= b.N { + return + } + } + if tr.Len() > 0 { + panic(tr.Len()) + } + } + }) + } +} + +func BenchmarkGet(b *testing.B) { + insertP := perm(benchmarkTreeSize) + getP := perm(benchmarkTreeSize) + for _, d := range degrees { + b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) { + i := 0 + for i < b.N { + b.StopTimer() + tr := New(d, less) + for _, v := range insertP { + tr.Set(v.Key, v.Value) + } + b.StartTimer() + for _, m := range getP { + tr.Get(m.Key) + i++ + if i >= b.N { + return + } + } + } + }) + } +} + +func BenchmarkGetWithIndex(b *testing.B) { + insertP := perm(benchmarkTreeSize) + getP := perm(benchmarkTreeSize) + for _, d := range degrees { + b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) { + i := 0 + for i < b.N { + b.StopTimer() + tr := New(d, less) + for _, v := range insertP { + tr.Set(v.Key, v.Value) + } + b.StartTimer() + for _, m := range getP { + tr.GetWithIndex(m.Key) + i++ + if i >= b.N { + return + } + } + } + }) + } +} + +func BenchmarkGetCloneEachTime(b *testing.B) { + insertP := perm(benchmarkTreeSize) + getP := perm(benchmarkTreeSize) + for _, d := range degrees { + b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) { + i := 0 + for i < b.N { + b.StopTimer() + tr := New(d, less) + for _, m := range insertP { + tr.Set(m.Key, m.Value) + } + b.StartTimer() + for _, m := range getP { + tr = tr.Clone() + tr.Get(m.Key) + i++ + if i >= b.N { + return + } + } + } + }) + } +} + +func BenchmarkFind(b *testing.B) { + for _, d := range degrees { + var items []item + for i := 0; i < 2*d; i++ { + items = append(items, item{i, i}) + } + b.Run(fmt.Sprintf("size=%d", len(items)), func(b *testing.B) { + for _, alg := range []struct { + name string + fun func(Key, []item) (int, bool) + }{ + {"binary", findBinary}, + {"linear", findLinear}, + } { + b.Run(alg.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + for j := 0; j < len(items); j++ { + alg.fun(items[j].key, items) + } + } + }) + } + }) + } +} + +func findBinary(k Key, s []item) (int, bool) { + i := sort.Search(len(s), func(i int) bool { return less(k, s[i].key) }) + // i is the smallest index of s for which key.Less(s[i].Key), or len(s). + if i > 0 && !less(s[i-1], k) { + return i - 1, true + } + return i, false +} + +func findLinear(k Key, s []item) (int, bool) { + var i int + for i = 0; i < len(s); i++ { + if less(k, s[i].key) { + break + } + } + if i > 0 && !less(s[i-1].key, k) { + return i - 1, true + } + return i, false +} + +type byInts []item + +func (a byInts) Len() int { + return len(a) +} + +func (a byInts) Less(i, j int) bool { + return a[i].key.(int) < a[j].key.(int) +} + +func (a byInts) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} diff --git a/vendor/cloud.google.com/go/internal/btree/btree.go b/vendor/cloud.google.com/go/internal/btree/btree.go new file mode 100644 index 00000000..60d419f5 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/btree/btree.go @@ -0,0 +1,1021 @@ +// Copyright 2014 Google LLC +// Modified 2018 by Jonathan Amsterdam (jbamsterdam@gmail.com) +// +// 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 btree implements in-memory B-Trees of arbitrary degree. +// +// This implementation is based on google/btree (http://github.com/google/btree), and +// much of the code is taken from there. But the API has been changed significantly, +// particularly around iteration, and support for indexing by position has been +// added. +// +// btree implements an in-memory B-Tree for use as an ordered data structure. +// It is not meant for persistent storage solutions. +// +// It has a flatter structure than an equivalent red-black or other binary tree, +// which in some cases yields better memory usage and/or performance. +// See some discussion on the matter here: +// http://google-opensource.blogspot.com/2013/01/c-containers-that-save-memory-and-time.html +// Note, though, that this project is in no way related to the C++ B-Tree +// implementation written about there. +// +// Within this tree, each node contains a slice of items and a (possibly nil) +// slice of children. For basic numeric values or raw structs, this can cause +// efficiency differences when compared to equivalent C++ template code that +// stores values in arrays within the node: +// * Due to the overhead of storing values as interfaces (each +// value needs to be stored as the value itself, then 2 words for the +// interface pointing to that value and its type), resulting in higher +// memory use. +// * Since interfaces can point to values anywhere in memory, values are +// most likely not stored in contiguous blocks, resulting in a higher +// number of cache misses. +// These issues don't tend to matter, though, when working with strings or other +// heap-allocated structures, since C++-equivalent structures also must store +// pointers and also distribute their values across the heap. +package btree + +import ( + "fmt" + "sort" + "sync" +) + +// Key represents a key into the tree. +type Key interface{} + +// Value represents a value in the tree. +type Value interface{} + +// item is a key-value pair. +type item struct { + key Key + value Value +} + +type lessFunc func(interface{}, interface{}) bool + +// New creates a new B-Tree with the given degree and comparison function. +// +// New(2, less), for example, will create a 2-3-4 tree (each node contains 1-3 items +// and 2-4 children). +// +// The less function tests whether the current item is less than the given argument. +// It must provide a strict weak ordering. +// If !less(a, b) && !less(b, a), we treat this to mean a == b (i.e. the tree +// can hold only one of a or b). +func New(degree int, less func(interface{}, interface{}) bool) *BTree { + if degree <= 1 { + panic("bad degree") + } + return &BTree{ + degree: degree, + less: less, + cow: ©OnWriteContext{}, + } +} + +// items stores items in a node. +type items []item + +// insertAt inserts a value into the given index, pushing all subsequent values +// forward. +func (s *items) insertAt(index int, m item) { + *s = append(*s, item{}) + if index < len(*s) { + copy((*s)[index+1:], (*s)[index:]) + } + (*s)[index] = m +} + +// removeAt removes a value at a given index, pulling all subsequent values +// back. +func (s *items) removeAt(index int) item { + m := (*s)[index] + copy((*s)[index:], (*s)[index+1:]) + (*s)[len(*s)-1] = item{} + *s = (*s)[:len(*s)-1] + return m +} + +// pop removes and returns the last element in the list. +func (s *items) pop() item { + index := len(*s) - 1 + out := (*s)[index] + (*s)[index] = item{} + *s = (*s)[:index] + return out +} + +var nilItems = make(items, 16) + +// truncate truncates this instance at index so that it contains only the +// first index items. index must be less than or equal to length. +func (s *items) truncate(index int) { + var toClear items + *s, toClear = (*s)[:index], (*s)[index:] + for len(toClear) > 0 { + toClear = toClear[copy(toClear, nilItems):] + } +} + +// find returns the index where an item with key should be inserted into this +// list. 'found' is true if the item already exists in the list at the given +// index. +func (s items) find(k Key, less lessFunc) (index int, found bool) { + i := sort.Search(len(s), func(i int) bool { return less(k, s[i].key) }) + // i is the smallest index of s for which k.Less(s[i].Key), or len(s). + if i > 0 && !less(s[i-1].key, k) { + return i - 1, true + } + return i, false +} + +// children stores child nodes in a node. +type children []*node + +// insertAt inserts a value into the given index, pushing all subsequent values +// forward. +func (s *children) insertAt(index int, n *node) { + *s = append(*s, nil) + if index < len(*s) { + copy((*s)[index+1:], (*s)[index:]) + } + (*s)[index] = n +} + +// removeAt removes a value at a given index, pulling all subsequent values +// back. +func (s *children) removeAt(index int) *node { + n := (*s)[index] + copy((*s)[index:], (*s)[index+1:]) + (*s)[len(*s)-1] = nil + *s = (*s)[:len(*s)-1] + return n +} + +// pop removes and returns the last element in the list. +func (s *children) pop() (out *node) { + index := len(*s) - 1 + out = (*s)[index] + (*s)[index] = nil + *s = (*s)[:index] + return +} + +var nilChildren = make(children, 16) + +// truncate truncates this instance at index so that it contains only the +// first index children. index must be less than or equal to length. +func (s *children) truncate(index int) { + var toClear children + *s, toClear = (*s)[:index], (*s)[index:] + for len(toClear) > 0 { + toClear = toClear[copy(toClear, nilChildren):] + } +} + +// node is an internal node in a tree. +// +// It must at all times maintain the invariant that either +// * len(children) == 0, len(items) unconstrained +// * len(children) == len(items) + 1 +type node struct { + items items + children children + size int // number of items in the subtree: len(items) + sum over i of children[i].size + cow *copyOnWriteContext +} + +func (n *node) computeSize() int { + sz := len(n.items) + for _, c := range n.children { + sz += c.size + } + return sz +} + +func (n *node) checkSize() { + sz := n.computeSize() + if n.size != sz { + panic(fmt.Sprintf("n.size = %d, computed size = %d", n.size, sz)) + } +} + +func (n *node) mutableFor(cow *copyOnWriteContext) *node { + if n.cow == cow { + return n + } + out := cow.newNode() + if cap(out.items) >= len(n.items) { + out.items = out.items[:len(n.items)] + } else { + out.items = make(items, len(n.items), cap(n.items)) + } + copy(out.items, n.items) + // Copy children + if cap(out.children) >= len(n.children) { + out.children = out.children[:len(n.children)] + } else { + out.children = make(children, len(n.children), cap(n.children)) + } + copy(out.children, n.children) + out.size = n.size + return out +} + +func (n *node) mutableChild(i int) *node { + c := n.children[i].mutableFor(n.cow) + n.children[i] = c + return c +} + +// split splits the given node at the given index. The current node shrinks, +// and this function returns the item that existed at that index and a new node +// containing all items/children after it. +func (n *node) split(i int) (item, *node) { + item := n.items[i] + next := n.cow.newNode() + next.items = append(next.items, n.items[i+1:]...) + n.items.truncate(i) + if len(n.children) > 0 { + next.children = append(next.children, n.children[i+1:]...) + n.children.truncate(i + 1) + } + n.size = n.computeSize() + next.size = next.computeSize() + return item, next +} + +// maybeSplitChild checks if a child should be split, and if so splits it. +// Returns whether or not a split occurred. +func (n *node) maybeSplitChild(i, maxItems int) bool { + if len(n.children[i].items) < maxItems { + return false + } + first := n.mutableChild(i) + item, second := first.split(maxItems / 2) + n.items.insertAt(i, item) + n.children.insertAt(i+1, second) + // The size of n doesn't change. + return true +} + +// insert inserts an item into the subtree rooted at this node, making sure +// no nodes in the subtree exceed maxItems items. Should an equivalent item be +// be found/replaced by insert, its value will be returned. +// +// If computeIndex is true, the third return value is the index of the value with respect to n. +func (n *node) insert(m item, maxItems int, less lessFunc, computeIndex bool) (old Value, present bool, idx int) { + i, found := n.items.find(m.key, less) + if found { + out := n.items[i] + n.items[i] = m + if computeIndex { + idx = n.itemIndex(i) + } + return out.value, true, idx + } + if len(n.children) == 0 { + n.items.insertAt(i, m) + n.size++ + return old, false, i + } + if n.maybeSplitChild(i, maxItems) { + inTree := n.items[i] + switch { + case less(m.key, inTree.key): + // no change, we want first split node + case less(inTree.key, m.key): + i++ // we want second split node + default: + out := n.items[i] + n.items[i] = m + if computeIndex { + idx = n.itemIndex(i) + } + return out.value, true, idx + } + } + old, present, idx = n.mutableChild(i).insert(m, maxItems, less, computeIndex) + if !present { + n.size++ + } + if computeIndex { + idx += n.partialSize(i) + } + return old, present, idx +} + +// get finds the given key in the subtree and returns the corresponding item, along with a boolean reporting +// whether it was found. +// If computeIndex is true, it also returns the index of the key relative to the node's subtree. +func (n *node) get(k Key, computeIndex bool, less lessFunc) (item, bool, int) { + i, found := n.items.find(k, less) + if found { + return n.items[i], true, n.itemIndex(i) + } + if len(n.children) > 0 { + m, found, idx := n.children[i].get(k, computeIndex, less) + if computeIndex && found { + idx += n.partialSize(i) + } + return m, found, idx + } + return item{}, false, -1 +} + +// itemIndex returns the index w.r.t. n of the ith item in n. +func (n *node) itemIndex(i int) int { + if len(n.children) == 0 { + return i + } + // Get the size of the node up to but not including the child to the right of + // item i. Subtract 1 because the index is 0-based. + return n.partialSize(i+1) - 1 +} + +// Returns the size of the non-leaf node up to but not including child i. +func (n *node) partialSize(i int) int { + var sz int + for j, c := range n.children { + if j == i { + break + } + sz += c.size + 1 + } + return sz +} + +// cursorStackForKey returns a stack of cursors for the key, along with whether the key was found and the index. +func (n *node) cursorStackForKey(k Key, cs cursorStack, less lessFunc) (cursorStack, bool, int) { + i, found := n.items.find(k, less) + cs.push(cursor{n, i}) + idx := i + if found { + if len(n.children) > 0 { + idx = n.partialSize(i+1) - 1 + } + return cs, true, idx + } + if len(n.children) > 0 { + cs, found, idx := n.children[i].cursorStackForKey(k, cs, less) + return cs, found, idx + n.partialSize(i) + } + return cs, false, idx +} + +// at returns the item at the i'th position in the subtree rooted at n. +// It assumes i is in range. +func (n *node) at(i int) item { + if len(n.children) == 0 { + return n.items[i] + } + for j, c := range n.children { + if i < c.size { + return c.at(i) + } + i -= c.size + if i == 0 { + return n.items[j] + } + i-- + } + panic("impossible") +} + +// cursorStackForIndex returns a stack of cursors for the index. +// It assumes i is in range. +func (n *node) cursorStackForIndex(i int, cs cursorStack) cursorStack { + if len(n.children) == 0 { + return cs.push(cursor{n, i}) + } + for j, c := range n.children { + if i < c.size { + return c.cursorStackForIndex(i, cs.push(cursor{n, j})) + } + i -= c.size + if i == 0 { + return cs.push(cursor{n, j}) + } + i-- + } + panic("impossible") +} + +// toRemove details what item to remove in a node.remove call. +type toRemove int + +const ( + removeItem toRemove = iota // removes the given item + removeMin // removes smallest item in the subtree + removeMax // removes largest item in the subtree +) + +// remove removes an item from the subtree rooted at this node. +func (n *node) remove(key Key, minItems int, typ toRemove, less lessFunc) (item, bool) { + var i int + var found bool + switch typ { + case removeMax: + if len(n.children) == 0 { + n.size-- + return n.items.pop(), true + + } + i = len(n.items) + case removeMin: + if len(n.children) == 0 { + n.size-- + return n.items.removeAt(0), true + } + i = 0 + case removeItem: + i, found = n.items.find(key, less) + if len(n.children) == 0 { + if found { + n.size-- + return n.items.removeAt(i), true + } + return item{}, false + } + default: + panic("invalid type") + } + // If we get to here, we have children. + if len(n.children[i].items) <= minItems { + return n.growChildAndRemove(i, key, minItems, typ, less) + } + child := n.mutableChild(i) + // Either we had enough items to begin with, or we've done some + // merging/stealing, because we've got enough now and we're ready to return + // stuff. + if found { + // The item exists at index 'i', and the child we've selected can give us a + // predecessor, since if we've gotten here it's got > minItems items in it. + out := n.items[i] + // We use our special-case 'remove' call with typ=maxItem to pull the + // predecessor of item i (the rightmost leaf of our immediate left child) + // and set it into where we pulled the item from. + n.items[i], _ = child.remove(nil, minItems, removeMax, less) + n.size-- + return out, true + } + // Final recursive call. Once we're here, we know that the item isn't in this + // node and that the child is big enough to remove from. + m, removed := child.remove(key, minItems, typ, less) + if removed { + n.size-- + } + return m, removed +} + +// growChildAndRemove grows child 'i' to make sure it's possible to remove an +// item from it while keeping it at minItems, then calls remove to actually +// remove it. +// +// Most documentation says we have to do two sets of special casing: +// 1) item is in this node +// 2) item is in child +// In both cases, we need to handle the two subcases: +// A) node has enough values that it can spare one +// B) node doesn't have enough values +// For the latter, we have to check: +// a) left sibling has node to spare +// b) right sibling has node to spare +// c) we must merge +// To simplify our code here, we handle cases #1 and #2 the same: +// If a node doesn't have enough items, we make sure it does (using a,b,c). +// We then simply redo our remove call, and the second time (regardless of +// whether we're in case 1 or 2), we'll have enough items and can guarantee +// that we hit case A. +func (n *node) growChildAndRemove(i int, key Key, minItems int, typ toRemove, less lessFunc) (item, bool) { + if i > 0 && len(n.children[i-1].items) > minItems { + // Steal from left child + child := n.mutableChild(i) + stealFrom := n.mutableChild(i - 1) + stolenItem := stealFrom.items.pop() + stealFrom.size-- + child.items.insertAt(0, n.items[i-1]) + child.size++ + n.items[i-1] = stolenItem + if len(stealFrom.children) > 0 { + c := stealFrom.children.pop() + stealFrom.size -= c.size + child.children.insertAt(0, c) + child.size += c.size + } + } else if i < len(n.items) && len(n.children[i+1].items) > minItems { + // steal from right child + child := n.mutableChild(i) + stealFrom := n.mutableChild(i + 1) + stolenItem := stealFrom.items.removeAt(0) + stealFrom.size-- + child.items = append(child.items, n.items[i]) + child.size++ + n.items[i] = stolenItem + if len(stealFrom.children) > 0 { + c := stealFrom.children.removeAt(0) + stealFrom.size -= c.size + child.children = append(child.children, c) + child.size += c.size + } + } else { + if i >= len(n.items) { + i-- + } + child := n.mutableChild(i) + // merge with right child + mergeItem := n.items.removeAt(i) + mergeChild := n.children.removeAt(i + 1) + child.items = append(child.items, mergeItem) + child.items = append(child.items, mergeChild.items...) + child.children = append(child.children, mergeChild.children...) + child.size = child.computeSize() + n.cow.freeNode(mergeChild) + } + return n.remove(key, minItems, typ, less) +} + +// BTree is an implementation of a B-Tree. +// +// BTree stores item instances in an ordered structure, allowing easy insertion, +// removal, and iteration. +// +// Write operations are not safe for concurrent mutation by multiple +// goroutines, but Read operations are. +type BTree struct { + degree int + less lessFunc + root *node + cow *copyOnWriteContext +} + +// copyOnWriteContext pointers determine node ownership. A tree with a cow +// context equivalent to a node's cow context is allowed to modify that node. +// A tree whose write context does not match a node's is not allowed to modify +// it, and must create a new, writable copy (IE: it's a Clone). +// +// When doing any write operation, we maintain the invariant that the current +// node's context is equal to the context of the tree that requested the write. +// We do this by, before we descend into any node, creating a copy with the +// correct context if the contexts don't match. +// +// Since the node we're currently visiting on any write has the requesting +// tree's context, that node is modifiable in place. Children of that node may +// not share context, but before we descend into them, we'll make a mutable +// copy. +type copyOnWriteContext struct{ byte } // non-empty, because empty structs may have same addr + +// Clone clones the btree, lazily. Clone should not be called concurrently, +// but the original tree (t) and the new tree (t2) can be used concurrently +// once the Clone call completes. +// +// The internal tree structure of b is marked read-only and shared between t and +// t2. Writes to both t and t2 use copy-on-write logic, creating new nodes +// whenever one of b's original nodes would have been modified. Read operations +// should have no performance degredation. Write operations for both t and t2 +// will initially experience minor slow-downs caused by additional allocs and +// copies due to the aforementioned copy-on-write logic, but should converge to +// the original performance characteristics of the original tree. +func (t *BTree) Clone() *BTree { + // Create two entirely new copy-on-write contexts. + // This operation effectively creates three trees: + // the original, shared nodes (old b.cow) + // the new b.cow nodes + // the new out.cow nodes + cow1, cow2 := *t.cow, *t.cow + out := *t + t.cow = &cow1 + out.cow = &cow2 + return &out +} + +// maxItems returns the max number of items to allow per node. +func (t *BTree) maxItems() int { + return t.degree*2 - 1 +} + +// minItems returns the min number of items to allow per node (ignored for the +// root node). +func (t *BTree) minItems() int { + return t.degree - 1 +} + +var nodePool = sync.Pool{New: func() interface{} { return new(node) }} + +func (c *copyOnWriteContext) newNode() *node { + n := nodePool.Get().(*node) + n.cow = c + return n +} + +func (c *copyOnWriteContext) freeNode(n *node) { + if n.cow == c { + // clear to allow GC + n.items.truncate(0) + n.children.truncate(0) + n.cow = nil + nodePool.Put(n) + } +} + +// Set sets the given key to the given value in the tree. If the key is present in +// the tree, its value is changed and the old value is returned along with a second +// return value of true. If the key is not in the tree, it is added, and the second +// return value is false. +func (t *BTree) Set(k Key, v Value) (old Value, present bool) { + old, present, _ = t.set(k, v, false) + return old, present +} + +// SetWithIndex sets the given key to the given value in the tree, and returns the +// index at which it was inserted. +func (t *BTree) SetWithIndex(k Key, v Value) (old Value, present bool, index int) { + return t.set(k, v, true) +} + +func (t *BTree) set(k Key, v Value, computeIndex bool) (old Value, present bool, idx int) { + if t.root == nil { + t.root = t.cow.newNode() + t.root.items = append(t.root.items, item{k, v}) + t.root.size = 1 + return old, false, 0 + } + t.root = t.root.mutableFor(t.cow) + if len(t.root.items) >= t.maxItems() { + sz := t.root.size + item2, second := t.root.split(t.maxItems() / 2) + oldroot := t.root + t.root = t.cow.newNode() + t.root.items = append(t.root.items, item2) + t.root.children = append(t.root.children, oldroot, second) + t.root.size = sz + } + + return t.root.insert(item{k, v}, t.maxItems(), t.less, computeIndex) +} + +// Delete removes the item with the given key, returning its value. The second return value +// reports whether the key was found. +func (t *BTree) Delete(k Key) (Value, bool) { + m, removed := t.deleteItem(k, removeItem) + return m.value, removed +} + +// DeleteMin removes the smallest item in the tree and returns its key and value. +// If the tree is empty, it returns zero values. +func (t *BTree) DeleteMin() (Key, Value) { + item, _ := t.deleteItem(nil, removeMin) + return item.key, item.value +} + +// DeleteMax removes the largest item in the tree and returns its key and value. +// If the tree is empty, it returns zero values. +func (t *BTree) DeleteMax() (Key, Value) { + item, _ := t.deleteItem(nil, removeMax) + return item.key, item.value +} + +func (t *BTree) deleteItem(key Key, typ toRemove) (item, bool) { + if t.root == nil || len(t.root.items) == 0 { + return item{}, false + } + t.root = t.root.mutableFor(t.cow) + out, removed := t.root.remove(key, t.minItems(), typ, t.less) + if len(t.root.items) == 0 && len(t.root.children) > 0 { + oldroot := t.root + t.root = t.root.children[0] + t.cow.freeNode(oldroot) + } + return out, removed +} + +// Get returns the value for the given key in the tree, or the zero value if the +// key is not in the tree. +// +// To distinguish a zero value from a key that is not present, use GetWithIndex. +func (t *BTree) Get(k Key) Value { + var z Value + if t.root == nil { + return z + } + item, ok, _ := t.root.get(k, false, t.less) + if !ok { + return z + } + return item.value +} + +// GetWithIndex returns the value and index for the given key in the tree, or the +// zero value and -1 if the key is not in the tree. +func (t *BTree) GetWithIndex(k Key) (Value, int) { + var z Value + if t.root == nil { + return z, -1 + } + item, _, index := t.root.get(k, true, t.less) + return item.value, index +} + +// At returns the key and value at index i. The minimum item has index 0. +// If i is outside the range [0, t.Len()), At panics. +func (t *BTree) At(i int) (Key, Value) { + if i < 0 || i >= t.Len() { + panic("btree: index out of range") + } + item := t.root.at(i) + return item.key, item.value +} + +// Has reports whether the given key is in the tree. +func (t *BTree) Has(k Key) bool { + if t.root == nil { + return false + } + _, ok, _ := t.root.get(k, false, t.less) + return ok +} + +// Min returns the smallest key in the tree and its value. If the tree is empty, it +// returns zero values. +func (t *BTree) Min() (Key, Value) { + var k Key + var v Value + if t.root == nil { + return k, v + } + n := t.root + for len(n.children) > 0 { + n = n.children[0] + } + if len(n.items) == 0 { + return k, v + } + return n.items[0].key, n.items[0].value +} + +// Max returns the largest key in the tree and its value. If the tree is empty, both +// return values are zero values. +func (t *BTree) Max() (Key, Value) { + var k Key + var v Value + if t.root == nil { + return k, v + } + n := t.root + for len(n.children) > 0 { + n = n.children[len(n.children)-1] + } + if len(n.items) == 0 { + return k, v + } + m := n.items[len(n.items)-1] + return m.key, m.value +} + +// Len returns the number of items currently in the tree. +func (t *BTree) Len() int { + if t.root == nil { + return 0 + } + return t.root.size +} + +// Before returns an iterator positioned just before k. After the first call to Next, +// the Iterator will be at k, or at the key just greater than k if k is not in the tree. +// Subsequent calls to Next will traverse the tree's items in ascending order. +func (t *BTree) Before(k Key) *Iterator { + if t.root == nil { + return &Iterator{} + } + var cs cursorStack + cs, found, idx := t.root.cursorStackForKey(k, cs, t.less) + // If we found the key, the cursor stack is pointing to it. Since that is + // the first element we want, don't advance the iterator on the initial call to Next. + // If we haven't found the key, then the top of the cursor stack is either pointing at the + // item just after k, in which case we do not want to move the iterator; or the index + // is past the end of the items slice, in which case we do. + var stay bool + top := cs[len(cs)-1] + if found { + stay = true + } else if top.index < len(top.node.items) { + stay = true + } else { + idx-- + } + return &Iterator{ + cursors: cs, + stay: stay, + descending: false, + Index: idx, + } +} + +// After returns an iterator positioned just after k. After the first call to Next, +// the Iterator will be at k, or at the key just less than k if k is not in the tree. +// Subsequent calls to Next will traverse the tree's items in descending order. +func (t *BTree) After(k Key) *Iterator { + if t.root == nil { + return &Iterator{} + } + var cs cursorStack + cs, found, idx := t.root.cursorStackForKey(k, cs, t.less) + // If we found the key, the cursor stack is pointing to it. Since that is + // the first element we want, don't advance the iterator on the initial call to Next. + // If we haven't found the key, the cursor stack is pointing just after the first item, + // so we do want to advance. + return &Iterator{ + cursors: cs, + stay: found, + descending: true, + Index: idx, + } +} + +// BeforeIndex returns an iterator positioned just before the item with the given index. +// The iterator will traverse the tree's items in ascending order. +// If i is not in the range [0, tr.Len()], BeforeIndex panics. +// Note that it is not an error to provide an index of tr.Len(). +func (t *BTree) BeforeIndex(i int) *Iterator { + return t.indexIterator(i, false) +} + +// AfterIndex returns an iterator positioned just after the item with the given index. +// The iterator will traverse the tree's items in descending order. +// If i is not in the range [0, tr.Len()], AfterIndex panics. +// Note that it is not an error to provide an index of tr.Len(). +func (t *BTree) AfterIndex(i int) *Iterator { + return t.indexIterator(i, true) +} + +func (t *BTree) indexIterator(i int, descending bool) *Iterator { + if i < 0 || i > t.Len() { + panic("btree: index out of range") + } + if i == t.Len() { + return &Iterator{} + } + var cs cursorStack + return &Iterator{ + cursors: t.root.cursorStackForIndex(i, cs), + stay: true, + descending: descending, + Index: i, + } +} + +// An Iterator supports traversing the items in the tree. +type Iterator struct { + Key Key + Value Value + // Index is the position of the item in the tree viewed as a sequence. + // The minimum item has index zero. + Index int + + cursors cursorStack // stack of nodes with indices; last element is the top + stay bool // don't do anything on the first call to Next. + descending bool // traverse the items in descending order +} + +// Next advances the Iterator to the next item in the tree. If Next returns true, +// the Iterator's Key, Value and Index fields refer to the next item. If Next returns +// false, there are no more items and the values of Key, Value and Index are undefined. +// +// If the tree is modified during iteration, the behavior is undefined. +func (it *Iterator) Next() bool { + var more bool + switch { + case len(it.cursors) == 0: + more = false + case it.stay: + it.stay = false + more = true + case it.descending: + more = it.dec() + default: + more = it.inc() + } + if !more { + return false + } + top := it.cursors[len(it.cursors)-1] + item := top.node.items[top.index] + it.Key = item.key + it.Value = item.value + return true +} + +// When inc returns true, the top cursor on the stack refers to the new current item. +func (it *Iterator) inc() bool { + // Useful invariants for understanding this function: + // - Leaf nodes have zero children, and zero or more items. + // - Nonleaf nodes have one more child than item, and children[i] < items[i] < children[i+1]. + // - The current item in the iterator is top.node.items[top.index]. + + it.Index++ + // If we are at a non-leaf node, the current item is items[i], so + // now we want to continue with children[i+1], which must exist + // by the node invariant. We want the minimum item in that child's subtree. + top := it.cursors.incTop(1) + for len(top.node.children) > 0 { + top = cursor{top.node.children[top.index], 0} + it.cursors.push(top) + } + // Here, we are at a leaf node. top.index points to + // the new current item, if it's within the items slice. + for top.index >= len(top.node.items) { + // We've gone through everything in this node. Pop it off the stack. + it.cursors.pop() + // If the stack is now empty,we're past the last item in the tree. + if it.cursors.empty() { + return false + } + top = it.cursors.top() + // The new top's index points to a child, which we've just finished + // exploring. The next item is the one at the same index in the items slice. + } + // Here, the top cursor on the stack points to the new current item. + return true +} + +func (it *Iterator) dec() bool { + // See the invariants for inc, above. + it.Index-- + top := it.cursors.top() + // If we are at a non-leaf node, the current item is items[i], so + // now we want to continue with children[i]. We want the maximum item in that child's subtree. + for len(top.node.children) > 0 { + c := top.node.children[top.index] + top = cursor{c, len(c.items)} + it.cursors.push(top) + } + top = it.cursors.incTop(-1) + // Here, we are at a leaf node. top.index points to + // the new current item, if it's within the items slice. + for top.index < 0 { + // We've gone through everything in this node. Pop it off the stack. + it.cursors.pop() + // If the stack is now empty,we're past the last item in the tree. + if it.cursors.empty() { + return false + } + // The new top's index points to a child, which we've just finished + // exploring. That child is to the right of the item we want to advance to, + // so decrement the index. + top = it.cursors.incTop(-1) + } + return true +} + +// A cursor is effectively a pointer into a node. A stack of cursors identifies an item in the tree, +// and makes it possible to move to the next or previous item efficiently. +// +// If the cursor is on the top of the stack, its index points into the node's items slice, selecting +// the current item. Otherwise, the index points into the children slice and identifies the child +// that is next in the stack. +type cursor struct { + node *node + index int +} + +// A cursorStack is a stack of cursors, representing a path of nodes from the root of the tree. +type cursorStack []cursor + +func (s *cursorStack) push(c cursor) cursorStack { + *s = append(*s, c) + return *s +} + +func (s *cursorStack) pop() cursor { + last := len(*s) - 1 + t := (*s)[last] + *s = (*s)[:last] + return t +} + +func (s *cursorStack) top() cursor { + return (*s)[len(*s)-1] +} + +func (s *cursorStack) empty() bool { + return len(*s) == 0 +} + +// incTop increments top's index by n and returns it. +func (s *cursorStack) incTop(n int) cursor { + (*s)[len(*s)-1].index += n // Don't call top: modify the original, not a copy. + return s.top() +} diff --git a/vendor/cloud.google.com/go/internal/btree/btree_test.go b/vendor/cloud.google.com/go/internal/btree/btree_test.go new file mode 100644 index 00000000..4e550355 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/btree/btree_test.go @@ -0,0 +1,422 @@ +// Copyright 2014 Google LLC +// Modified 2018 by Jonathan Amsterdam (jbamsterdam@gmail.com) +// +// 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 btree + +import ( + "flag" + "fmt" + "math/rand" + "os" + "sort" + "sync" + "testing" + "time" + + "github.com/google/go-cmp/cmp" +) + +func init() { + seed := time.Now().Unix() + fmt.Println(seed) + rand.Seed(seed) +} + +type itemWithIndex struct { + Key Key + Value Value + Index int +} + +// perm returns a random permutation of n Int items in the range [0, n). +func perm(n int) []itemWithIndex { + var out []itemWithIndex + for _, v := range rand.Perm(n) { + out = append(out, itemWithIndex{v, v, v}) + } + return out +} + +// rang returns an ordered list of Int items in the range [0, n). +func rang(n int) []itemWithIndex { + var out []itemWithIndex + for i := 0; i < n; i++ { + out = append(out, itemWithIndex{i, i, i}) + } + return out +} + +// all extracts all items from an iterator. +func all(it *Iterator) []itemWithIndex { + var out []itemWithIndex + for it.Next() { + out = append(out, itemWithIndex{it.Key, it.Value, it.Index}) + } + return out +} + +// rangerev returns a reversed ordered list of Int items in the range [0, n). +func rangrev(n int) []itemWithIndex { + var out []itemWithIndex + for i := n - 1; i >= 0; i-- { + out = append(out, itemWithIndex{i, i, i}) + } + return out +} + +func reverse(s []itemWithIndex) { + for i := 0; i < len(s)/2; i++ { + s[i], s[len(s)-i-1] = s[len(s)-i-1], s[i] + } +} + +var btreeDegree = flag.Int("degree", 32, "B-Tree degree") + +func TestBTree(t *testing.T) { + tr := New(*btreeDegree, less) + const treeSize = 10000 + for i := 0; i < 10; i++ { + if min, _ := tr.Min(); min != nil { + t.Fatalf("empty min, got %+v", min) + } + if max, _ := tr.Max(); max != nil { + t.Fatalf("empty max, got %+v", max) + } + for _, m := range perm(treeSize) { + if _, ok := tr.Set(m.Key, m.Value); ok { + t.Fatal("set found item", m) + } + } + for _, m := range perm(treeSize) { + _, ok, idx := tr.SetWithIndex(m.Key, m.Value) + if !ok { + t.Fatal("set didn't find item", m) + } + if idx != m.Index { + t.Fatalf("got index %d, want %d", idx, m.Index) + } + } + mink, minv := tr.Min() + if want := 0; mink != want || minv != want { + t.Fatalf("min: want %+v, got %+v, %+v", want, mink, minv) + } + maxk, maxv := tr.Max() + if want := treeSize - 1; maxk != want || maxv != want { + t.Fatalf("max: want %+v, got %+v, %+v", want, maxk, maxv) + } + got := all(tr.BeforeIndex(0)) + want := rang(treeSize) + if !cmp.Equal(got, want) { + t.Fatalf("mismatch:\n got: %v\nwant: %v", got, want) + } + + for _, m := range perm(treeSize) { + if _, removed := tr.Delete(m.Key); !removed { + t.Fatalf("didn't find %v", m) + } + } + if got = all(tr.BeforeIndex(0)); len(got) > 0 { + t.Fatalf("some left!: %v", got) + } + } +} + +func TestAt(t *testing.T) { + tr := New(*btreeDegree, less) + for _, m := range perm(100) { + tr.Set(m.Key, m.Value) + } + for i := 0; i < tr.Len(); i++ { + gotk, gotv := tr.At(i) + if want := i; gotk != want || gotv != want { + t.Fatalf("At(%d) = (%v, %v), want (%v, %v)", i, gotk, gotv, want, want) + } + } +} + +func TestGetWithIndex(t *testing.T) { + tr := New(*btreeDegree, less) + for _, m := range perm(100) { + tr.Set(m.Key, m.Value) + } + for i := 0; i < tr.Len(); i++ { + gotv, goti := tr.GetWithIndex(i) + wantv, wanti := i, i + if gotv != wantv || goti != wanti { + t.Errorf("GetWithIndex(%d) = (%v, %v), want (%v, %v)", + i, gotv, goti, wantv, wanti) + } + } + _, got := tr.GetWithIndex(100) + if want := -1; got != want { + t.Errorf("got %d, want %d", got, want) + } +} + +func TestSetWithIndex(t *testing.T) { + tr := New(4, less) // use a small degree to cover more cases + var contents []int + for _, m := range perm(100) { + _, _, idx := tr.SetWithIndex(m.Key, m.Value) + contents = append(contents, m.Index) + sort.Ints(contents) + want := -1 + for i, c := range contents { + if c == m.Index { + want = i + break + } + } + if idx != want { + t.Fatalf("got %d, want %d", idx, want) + } + } +} + +func TestDeleteMin(t *testing.T) { + tr := New(3, less) + for _, m := range perm(100) { + tr.Set(m.Key, m.Value) + } + var got []itemWithIndex + for i := 0; tr.Len() > 0; i++ { + k, v := tr.DeleteMin() + got = append(got, itemWithIndex{k, v, i}) + } + if want := rang(100); !cmp.Equal(got, want) { + t.Fatalf("got: %v\nwant: %v", got, want) + } +} + +func TestDeleteMax(t *testing.T) { + tr := New(3, less) + for _, m := range perm(100) { + tr.Set(m.Key, m.Value) + } + var got []itemWithIndex + for tr.Len() > 0 { + k, v := tr.DeleteMax() + got = append(got, itemWithIndex{k, v, tr.Len()}) + } + reverse(got) + if want := rang(100); !cmp.Equal(got, want) { + t.Fatalf("got: %v\nwant: %v", got, want) + } +} + +func TestIterator(t *testing.T) { + const size = 10 + + tr := New(2, less) + // Empty tree. + for i, it := range []*Iterator{ + tr.BeforeIndex(0), + tr.Before(3), + tr.After(3), + } { + if got, want := it.Next(), false; got != want { + t.Errorf("empty, #%d: got %t, want %t", i, got, want) + } + } + + // Root with zero children. + tr.Set(1, nil) + tr.Delete(1) + if !(tr.root != nil && len(tr.root.children) == 0 && len(tr.root.items) == 0) { + t.Fatal("wrong shape tree") + } + for i, it := range []*Iterator{ + tr.BeforeIndex(0), + tr.Before(3), + tr.After(3), + } { + if got, want := it.Next(), false; got != want { + t.Errorf("zero root, #%d: got %t, want %t", i, got, want) + } + } + + // Tree with size elements. + p := perm(size) + for _, v := range p { + tr.Set(v.Key, v.Value) + } + + it := tr.BeforeIndex(0) + got := all(it) + want := rang(size) + if !cmp.Equal(got, want) { + t.Fatalf("got %+v\nwant %+v\n", got, want) + } + + for i, w := range want { + it := tr.Before(w.Key) + got = all(it) + wn := want[w.Key.(int):] + if !cmp.Equal(got, wn) { + t.Fatalf("got %+v\nwant %+v\n", got, wn) + } + + it = tr.BeforeIndex(i) + got = all(it) + if !cmp.Equal(got, wn) { + t.Fatalf("got %+v\nwant %+v\n", got, wn) + } + + it = tr.After(w.Key) + got = all(it) + wn = append([]itemWithIndex(nil), want[:w.Key.(int)+1]...) + reverse(wn) + if !cmp.Equal(got, wn) { + t.Fatalf("got %+v\nwant %+v\n", got, wn) + } + + it = tr.AfterIndex(i) + got = all(it) + if !cmp.Equal(got, wn) { + t.Fatalf("got %+v\nwant %+v\n", got, wn) + } + } + + // Non-existent keys. + tr = New(2, less) + for _, v := range p { + tr.Set(v.Key.(int)*2, v.Value) + } + // tr has only even keys: 0, 2, 4, ... Iterate from odd keys. + for i := -1; i <= size+1; i += 2 { + it := tr.Before(i) + got := all(it) + var want []itemWithIndex + for j := (i + 1) / 2; j < size; j++ { + want = append(want, itemWithIndex{j * 2, j, j}) + } + if !cmp.Equal(got, want) { + tr.print(os.Stdout) + t.Fatalf("%d: got %+v\nwant %+v\n", i, got, want) + } + + it = tr.After(i) + got = all(it) + want = nil + for j := (i - 1) / 2; j >= 0; j-- { + want = append(want, itemWithIndex{j * 2, j, j}) + } + if !cmp.Equal(got, want) { + t.Fatalf("%d: got %+v\nwant %+v\n", i, got, want) + } + } +} + +func TestMixed(t *testing.T) { + // Test random, mixed insertions and deletions. + const maxSize = 1000 + tr := New(3, less) + has := map[int]bool{} + for i := 0; i < 10000; i++ { + r := rand.Intn(maxSize) + if r >= tr.Len() { + old, ok := tr.Set(r, r) + if has[r] != ok { + t.Fatalf("%d: has=%t, ok=%t", r, has[r], ok) + } + if ok && old.(int) != r { + t.Fatalf("%d: bad old", r) + } + has[r] = true + if got, want := tr.Get(r), r; got != want { + t.Fatalf("Get(%d) = %d, want %d", r, got, want) + } + } else { + // Expoit random map iteration order. + var d int + for d = range has { + break + } + old, removed := tr.Delete(d) + if !removed { + t.Fatalf("%d not found", d) + } + if old.(int) != d { + t.Fatalf("%d: bad old", d) + } + delete(has, d) + } + } +} + +const cloneTestSize = 10000 + +func cloneTest(t *testing.T, b *BTree, start int, p []itemWithIndex, wg *sync.WaitGroup, treec chan<- *BTree) { + treec <- b + for i := start; i < cloneTestSize; i++ { + b.Set(p[i].Key, p[i].Value) + if i%(cloneTestSize/5) == 0 { + wg.Add(1) + go cloneTest(t, b.Clone(), i+1, p, wg, treec) + } + } + wg.Done() +} + +func TestCloneConcurrentOperations(t *testing.T) { + b := New(*btreeDegree, less) + treec := make(chan *BTree) + p := perm(cloneTestSize) + var wg sync.WaitGroup + wg.Add(1) + go cloneTest(t, b, 0, p, &wg, treec) + var trees []*BTree + donec := make(chan struct{}) + go func() { + for t := range treec { + trees = append(trees, t) + } + close(donec) + }() + wg.Wait() + close(treec) + <-donec + want := rang(cloneTestSize) + for i, tree := range trees { + if !cmp.Equal(want, all(tree.BeforeIndex(0))) { + t.Errorf("tree %v mismatch", i) + } + } + toRemove := rang(cloneTestSize)[cloneTestSize/2:] + for i := 0; i < len(trees)/2; i++ { + tree := trees[i] + wg.Add(1) + go func() { + for _, m := range toRemove { + tree.Delete(m.Key) + } + wg.Done() + }() + } + wg.Wait() + for i, tree := range trees { + var wantpart []itemWithIndex + if i < len(trees)/2 { + wantpart = want[:cloneTestSize/2] + } else { + wantpart = want + } + if got := all(tree.BeforeIndex(0)); !cmp.Equal(wantpart, got) { + t.Errorf("tree %v mismatch, want %v got %v", i, len(want), len(got)) + } + } +} + +func less(a, b interface{}) bool { return a.(int) < b.(int) } diff --git a/vendor/cloud.google.com/go/internal/btree/debug.go b/vendor/cloud.google.com/go/internal/btree/debug.go new file mode 100644 index 00000000..e8a54df3 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/btree/debug.go @@ -0,0 +1,37 @@ +// Copyright 2014 Google LLC +// +// 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 btree + +import ( + "fmt" + "io" + "strings" +) + +func (t *BTree) print(w io.Writer) { + t.root.print(w, 0) +} + +func (n *node) print(w io.Writer, level int) { + indent := strings.Repeat(" ", level) + if n == nil { + fmt.Fprintf(w, "%s\n", indent) + return + } + fmt.Fprintf(w, "%s%v\n", indent, n.items) + for _, c := range n.children { + c.print(w, level+1) + } +} diff --git a/vendor/cloud.google.com/go/internal/fields/fields.go b/vendor/cloud.google.com/go/internal/fields/fields.go new file mode 100644 index 00000000..05f95eab --- /dev/null +++ b/vendor/cloud.google.com/go/internal/fields/fields.go @@ -0,0 +1,480 @@ +// Copyright 2016 Google LLC +// +// 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 fields provides a view of the fields of a struct that follows the Go +// rules, amended to consider tags and case insensitivity. +// +// Usage +// +// First define a function that interprets tags: +// +// func parseTag(st reflect.StructTag) (name string, keep bool, other interface{}, err error) { ... } +// +// The function's return values describe whether to ignore the field +// completely or provide an alternate name, as well as other data from the +// parse that is stored to avoid re-parsing. +// +// Then define a function to validate the type: +// +// func validate(t reflect.Type) error { ... } +// +// Then, if necessary, define a function to specify leaf types - types +// which should be considered one field and not be recursed into: +// +// func isLeafType(t reflect.Type) bool { ... } +// +// eg: +// +// func isLeafType(t reflect.Type) bool { +// return t == reflect.TypeOf(time.Time{}) +// } +// +// Next, construct a Cache, passing your functions. As its name suggests, a +// Cache remembers validation and field information for a type, so subsequent +// calls with the same type are very fast. +// +// cache := fields.NewCache(parseTag, validate, isLeafType) +// +// To get the fields of a struct type as determined by the above rules, call +// the Fields method: +// +// fields, err := cache.Fields(reflect.TypeOf(MyStruct{})) +// +// The return value can be treated as a slice of Fields. +// +// Given a string, such as a key or column name obtained during unmarshalling, +// call Match on the list of fields to find a field whose name is the best +// match: +// +// field := fields.Match(name) +// +// Match looks for an exact match first, then falls back to a case-insensitive +// comparison. +package fields + +import ( + "bytes" + "errors" + "reflect" + "sort" + "strings" + "sync" +) + +// A Field records information about a struct field. +type Field struct { + Name string // effective field name + NameFromTag bool // did Name come from a tag? + Type reflect.Type // field type + Index []int // index sequence, for reflect.Value.FieldByIndex + ParsedTag interface{} // third return value of the parseTag function + + nameBytes []byte + equalFold func(s, t []byte) bool +} + +// ParseTagFunc is a function that accepts a struct tag and returns four values: an alternative name for the field +// extracted from the tag, a boolean saying whether to keep the field or ignore it, additional data that is stored +// with the field information to avoid having to parse the tag again, and an error. +type ParseTagFunc func(reflect.StructTag) (name string, keep bool, other interface{}, err error) + +// ValidateFunc is a function that accepts a reflect.Type and returns an error if the struct type is invalid in any +// way. +type ValidateFunc func(reflect.Type) error + +// LeafTypesFunc is a function that accepts a reflect.Type and returns true if the struct type a leaf, or false if not. +// TODO(deklerk) is this description accurate? +type LeafTypesFunc func(reflect.Type) bool + +// A Cache records information about the fields of struct types. +// +// A Cache is safe for use by multiple goroutines. +type Cache struct { + parseTag ParseTagFunc + validate ValidateFunc + leafTypes LeafTypesFunc + cache sync.Map // from reflect.Type to cacheValue +} + +// NewCache constructs a Cache. +// +// Its first argument should be a function that accepts +// a struct tag and returns four values: an alternative name for the field +// extracted from the tag, a boolean saying whether to keep the field or ignore +// it, additional data that is stored with the field information to avoid +// having to parse the tag again, and an error. +// +// Its second argument should be a function that accepts a reflect.Type and +// returns an error if the struct type is invalid in any way. For example, it +// may check that all of the struct field tags are valid, or that all fields +// are of an appropriate type. +func NewCache(parseTag ParseTagFunc, validate ValidateFunc, leafTypes LeafTypesFunc) *Cache { + if parseTag == nil { + parseTag = func(reflect.StructTag) (string, bool, interface{}, error) { + return "", true, nil, nil + } + } + if validate == nil { + validate = func(reflect.Type) error { + return nil + } + } + if leafTypes == nil { + leafTypes = func(reflect.Type) bool { + return false + } + } + + return &Cache{ + parseTag: parseTag, + validate: validate, + leafTypes: leafTypes, + } +} + +// A fieldScan represents an item on the fieldByNameFunc scan work list. +type fieldScan struct { + typ reflect.Type + index []int +} + +// Fields returns all the exported fields of t, which must be a struct type. It +// follows the standard Go rules for embedded fields, modified by the presence +// of tags. The result is sorted lexicographically by index. +// +// These rules apply in the absence of tags: +// Anonymous struct fields are treated as if their inner exported fields were +// fields in the outer struct (embedding). The result includes all fields that +// aren't shadowed by fields at higher level of embedding. If more than one +// field with the same name exists at the same level of embedding, it is +// excluded. An anonymous field that is not of struct type is treated as having +// its type as its name. +// +// Tags modify these rules as follows: +// A field's tag is used as its name. +// An anonymous struct field with a name given in its tag is treated as +// a field having that name, rather than an embedded struct (the struct's +// fields will not be returned). +// If more than one field with the same name exists at the same level of embedding, +// but exactly one of them is tagged, then the tagged field is reported and the others +// are ignored. +func (c *Cache) Fields(t reflect.Type) (List, error) { + if t.Kind() != reflect.Struct { + panic("fields: Fields of non-struct type") + } + return c.cachedTypeFields(t) +} + +// A List is a list of Fields. +type List []Field + +// Match returns the field in the list whose name best matches the supplied +// name, nor nil if no field does. If there is a field with the exact name, it +// is returned. Otherwise the first field (sorted by index) whose name matches +// case-insensitively is returned. +func (l List) Match(name string) *Field { + return l.MatchBytes([]byte(name)) +} + +// MatchBytes is identical to Match, except that the argument is a byte slice. +func (l List) MatchBytes(name []byte) *Field { + var f *Field + for i := range l { + ff := &l[i] + if bytes.Equal(ff.nameBytes, name) { + return ff + } + if f == nil && ff.equalFold(ff.nameBytes, name) { + f = ff + } + } + return f +} + +type cacheValue struct { + fields List + err error +} + +// cachedTypeFields is like typeFields but uses a cache to avoid repeated work. +// This code has been copied and modified from +// https://go.googlesource.com/go/+/go1.7.3/src/encoding/json/encode.go. +func (c *Cache) cachedTypeFields(t reflect.Type) (List, error) { + var cv cacheValue + x, ok := c.cache.Load(t) + if ok { + cv = x.(cacheValue) + } else { + if err := c.validate(t); err != nil { + cv = cacheValue{nil, err} + } else { + f, err := c.typeFields(t) + cv = cacheValue{List(f), err} + } + c.cache.Store(t, cv) + } + return cv.fields, cv.err +} + +func (c *Cache) typeFields(t reflect.Type) ([]Field, error) { + fields, err := c.listFields(t) + if err != nil { + return nil, err + } + sort.Sort(byName(fields)) + // Delete all fields that are hidden by the Go rules for embedded fields. + + // The fields are sorted in primary order of name, secondary order of field + // index length. So the first field with a given name is the dominant one. + var out []Field + for advance, i := 0, 0; i < len(fields); i += advance { + // One iteration per name. + // Find the sequence of fields with the name of this first field. + fi := fields[i] + name := fi.Name + for advance = 1; i+advance < len(fields); advance++ { + fj := fields[i+advance] + if fj.Name != name { + break + } + } + // Find the dominant field, if any, out of all fields that have the same name. + dominant, ok := dominantField(fields[i : i+advance]) + if ok { + out = append(out, dominant) + } + } + sort.Sort(byIndex(out)) + return out, nil +} + +func (c *Cache) listFields(t reflect.Type) ([]Field, error) { + // This uses the same condition that the Go language does: there must be a unique instance + // of the match at a given depth level. If there are multiple instances of a match at the + // same depth, they annihilate each other and inhibit any possible match at a lower level. + // The algorithm is breadth first search, one depth level at a time. + + // The current and next slices are work queues: + // current lists the fields to visit on this depth level, + // and next lists the fields on the next lower level. + current := []fieldScan{} + next := []fieldScan{{typ: t}} + + // nextCount records the number of times an embedded type has been + // encountered and considered for queueing in the 'next' slice. + // We only queue the first one, but we increment the count on each. + // If a struct type T can be reached more than once at a given depth level, + // then it annihilates itself and need not be considered at all when we + // process that next depth level. + var nextCount map[reflect.Type]int + + // visited records the structs that have been considered already. + // Embedded pointer fields can create cycles in the graph of + // reachable embedded types; visited avoids following those cycles. + // It also avoids duplicated effort: if we didn't find the field in an + // embedded type T at level 2, we won't find it in one at level 4 either. + visited := map[reflect.Type]bool{} + + var fields []Field // Fields found. + + for len(next) > 0 { + current, next = next, current[:0] + count := nextCount + nextCount = nil + + // Process all the fields at this depth, now listed in 'current'. + // The loop queues embedded fields found in 'next', for processing during the next + // iteration. The multiplicity of the 'current' field counts is recorded + // in 'count'; the multiplicity of the 'next' field counts is recorded in 'nextCount'. + for _, scan := range current { + t := scan.typ + if visited[t] { + // We've looked through this type before, at a higher level. + // That higher level would shadow the lower level we're now at, + // so this one can't be useful to us. Ignore it. + continue + } + visited[t] = true + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + + exported := (f.PkgPath == "") + + // If a named field is unexported, ignore it. An anonymous + // unexported field is processed, because it may contain + // exported fields, which are visible. + if !exported && !f.Anonymous { + continue + } + + // Examine the tag. + tagName, keep, other, err := c.parseTag(f.Tag) + if err != nil { + return nil, err + } + if !keep { + continue + } + if c.leafTypes(f.Type) { + fields = append(fields, newField(f, tagName, other, scan.index, i)) + continue + } + + var ntyp reflect.Type + if f.Anonymous { + // Anonymous field of type T or *T. + ntyp = f.Type + if ntyp.Kind() == reflect.Ptr { + ntyp = ntyp.Elem() + } + } + + // Record fields with a tag name, non-anonymous fields, or + // anonymous non-struct fields. + if tagName != "" || ntyp == nil || ntyp.Kind() != reflect.Struct { + if !exported { + continue + } + fields = append(fields, newField(f, tagName, other, scan.index, i)) + if count[t] > 1 { + // If there were multiple instances, add a second, + // so that the annihilation code will see a duplicate. + fields = append(fields, fields[len(fields)-1]) + } + continue + } + + // Queue embedded struct fields for processing with next level, + // but only if the embedded types haven't already been queued. + if nextCount[ntyp] > 0 { + nextCount[ntyp] = 2 // exact multiple doesn't matter + continue + } + if nextCount == nil { + nextCount = map[reflect.Type]int{} + } + nextCount[ntyp] = 1 + if count[t] > 1 { + nextCount[ntyp] = 2 // exact multiple doesn't matter + } + var index []int + index = append(index, scan.index...) + index = append(index, i) + next = append(next, fieldScan{ntyp, index}) + } + } + } + return fields, nil +} + +func newField(f reflect.StructField, tagName string, other interface{}, index []int, i int) Field { + name := tagName + if name == "" { + name = f.Name + } + sf := Field{ + Name: name, + NameFromTag: tagName != "", + Type: f.Type, + ParsedTag: other, + nameBytes: []byte(name), + } + sf.equalFold = foldFunc(sf.nameBytes) + sf.Index = append(sf.Index, index...) + sf.Index = append(sf.Index, i) + return sf +} + +// byName sorts fields using the following criteria, in order: +// 1. name +// 2. embedding depth +// 3. tag presence (preferring a tagged field) +// 4. index sequence. +type byName []Field + +func (x byName) Len() int { return len(x) } + +func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func (x byName) Less(i, j int) bool { + if x[i].Name != x[j].Name { + return x[i].Name < x[j].Name + } + if len(x[i].Index) != len(x[j].Index) { + return len(x[i].Index) < len(x[j].Index) + } + if x[i].NameFromTag != x[j].NameFromTag { + return x[i].NameFromTag + } + return byIndex(x).Less(i, j) +} + +// byIndex sorts field by index sequence. +type byIndex []Field + +func (x byIndex) Len() int { return len(x) } + +func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } + +func (x byIndex) Less(i, j int) bool { + xi := x[i].Index + xj := x[j].Index + ln := len(xi) + if l := len(xj); l < ln { + ln = l + } + for k := 0; k < ln; k++ { + if xi[k] != xj[k] { + return xi[k] < xj[k] + } + } + return len(xi) < len(xj) +} + +// dominantField looks through the fields, all of which are known to have the +// same name, to find the single field that dominates the others using Go's +// embedding rules, modified by the presence of tags. If there are multiple +// top-level fields, the boolean will be false: This condition is an error in +// Go and we skip all the fields. +func dominantField(fs []Field) (Field, bool) { + // The fields are sorted in increasing index-length order, then by presence of tag. + // That means that the first field is the dominant one. We need only check + // for error cases: two fields at top level, either both tagged or neither tagged. + if len(fs) > 1 && len(fs[0].Index) == len(fs[1].Index) && fs[0].NameFromTag == fs[1].NameFromTag { + return Field{}, false + } + return fs[0], true +} + +// ParseStandardTag extracts the sub-tag named by key, then parses it using the +// de facto standard format introduced in encoding/json: +// "-" means "ignore this tag". It must occur by itself. (parseStandardTag returns an error +// in this case, whereas encoding/json accepts the "-" even if it is not alone.) +// "" provides an alternative name for the field +// ",opt1,opt2,..." specifies options after the name. +// The options are returned as a []string. +func ParseStandardTag(key string, t reflect.StructTag) (name string, keep bool, options []string, err error) { + s := t.Get(key) + parts := strings.Split(s, ",") + if parts[0] == "-" { + if len(parts) > 1 { + return "", false, nil, errors.New(`"-" field tag with options`) + } + return "", false, nil, nil + } + if len(parts) > 1 { + options = parts[1:] + } + return parts[0], true, options, nil +} diff --git a/vendor/cloud.google.com/go/internal/fields/fields_test.go b/vendor/cloud.google.com/go/internal/fields/fields_test.go new file mode 100644 index 00000000..6ef5a513 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/fields/fields_test.go @@ -0,0 +1,562 @@ +// Copyright 2016 Google LLC +// +// 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 fields + +import ( + "encoding/json" + "errors" + "fmt" + "reflect" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" +) + +type embed1 struct { + Em1 int + Dup int // annihilates with embed2.Dup + Shadow int + embed3 +} + +type embed2 struct { + Dup int + embed3 + embed4 +} + +type embed3 struct { + Em3 int // annihilated because embed3 is in both embed1 and embed2 + embed5 +} + +type embed4 struct { + Em4 int + Dup int // annihilation of Dup in embed1, embed2 hides this Dup + *embed1 // ignored because it occurs at a higher level +} + +type embed5 struct { + x int +} + +type Anonymous int + +type S1 struct { + Exported int + unexported int + Shadow int // shadows S1.Shadow + embed1 + *embed2 + Anonymous +} + +type Time struct { + time.Time +} + +var intType = reflect.TypeOf(int(0)) + +func field(name string, tval interface{}, index ...int) *Field { + return &Field{ + Name: name, + Type: reflect.TypeOf(tval), + Index: index, + ParsedTag: []string(nil), + } +} + +func tfield(name string, tval interface{}, index ...int) *Field { + return &Field{ + Name: name, + Type: reflect.TypeOf(tval), + Index: index, + NameFromTag: true, + ParsedTag: []string(nil), + } +} + +func TestFieldsNoTags(t *testing.T) { + c := NewCache(nil, nil, nil) + got, err := c.Fields(reflect.TypeOf(S1{})) + if err != nil { + t.Fatal(err) + } + want := []*Field{ + field("Exported", int(0), 0), + field("Shadow", int(0), 2), + field("Em1", int(0), 3, 0), + field("Em4", int(0), 4, 2, 0), + field("Anonymous", Anonymous(0), 5), + } + for _, f := range want { + f.ParsedTag = nil + } + if msg, ok := compareFields(got, want); !ok { + t.Error(msg) + } +} + +func TestAgainstJSONEncodingNoTags(t *testing.T) { + // Demonstrates that this package produces the same set of fields as encoding/json. + s1 := S1{ + Exported: 1, + unexported: 2, + Shadow: 3, + embed1: embed1{ + Em1: 4, + Dup: 5, + Shadow: 6, + embed3: embed3{ + Em3: 7, + embed5: embed5{x: 8}, + }, + }, + embed2: &embed2{ + Dup: 9, + embed3: embed3{ + Em3: 10, + embed5: embed5{x: 11}, + }, + embed4: embed4{ + Em4: 12, + Dup: 13, + embed1: &embed1{Em1: 14}, + }, + }, + Anonymous: Anonymous(15), + } + var want S1 + want.embed2 = &embed2{} // need this because reflection won't create it + jsonRoundTrip(t, s1, &want) + var got S1 + got.embed2 = &embed2{} + fields, err := NewCache(nil, nil, nil).Fields(reflect.TypeOf(got)) + if err != nil { + t.Fatal(err) + } + setFields(fields, &got, s1) + if !testutil.Equal(got, want, + cmp.AllowUnexported(S1{}, embed1{}, embed2{}, embed3{}, embed4{}, embed5{})) { + t.Errorf("got\n%+v\nwant\n%+v", got, want) + } +} + +// Tests use of LeafTypes parameter to NewCache +func TestAgainstJSONEncodingEmbeddedTime(t *testing.T) { + timeLeafFn := func(t reflect.Type) bool { + return t == reflect.TypeOf(time.Time{}) + } + // Demonstrates that this package can produce the same set of + // fields as encoding/json for a struct with an embedded time.Time. + now := time.Now().UTC() + myt := Time{ + now, + } + var want Time + jsonRoundTrip(t, myt, &want) + var got Time + fields, err := NewCache(nil, nil, timeLeafFn).Fields(reflect.TypeOf(got)) + if err != nil { + t.Fatal(err) + } + setFields(fields, &got, myt) + if !testutil.Equal(got, want) { + t.Errorf("got\n%+v\nwant\n%+v", got, want) + } +} + +type S2 struct { + NoTag int + XXX int `json:"tag"` // tag name takes precedence + Anonymous `json:"anon"` // anonymous non-structs also get their name from the tag + unexported int `json:"tag"` + Embed `json:"em"` // embedded structs with tags become fields + Tag int + YYY int `json:"Tag"` // tag takes precedence over untagged field of the same name + Empty int `json:""` // empty tag is noop + tEmbed1 + tEmbed2 +} + +type Embed struct { + Em int +} + +type tEmbed1 struct { + Dup int + X int `json:"Dup2"` +} + +type tEmbed2 struct { + Y int `json:"Dup"` // takes precedence over tEmbed1.Dup because it is tagged + Z int `json:"Dup2"` // same name as tEmbed1.X and both tagged, so ignored +} + +func jsonTagParser(t reflect.StructTag) (name string, keep bool, other interface{}, err error) { + return ParseStandardTag("json", t) +} + +func validateFunc(t reflect.Type) (err error) { + if t.Kind() != reflect.Struct { + return errors.New("non-struct type used") + } + + for i := 0; i < t.NumField(); i++ { + if t.Field(i).Type.Kind() == reflect.Slice { + return fmt.Errorf("slice field found at field %s on struct %s", t.Field(i).Name, t.Name()) + } + } + + return nil +} + +func TestFieldsWithTags(t *testing.T) { + got, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S2{})) + if err != nil { + t.Fatal(err) + } + want := []*Field{ + field("NoTag", int(0), 0), + tfield("tag", int(0), 1), + tfield("anon", Anonymous(0), 2), + tfield("em", Embed{}, 4), + tfield("Tag", int(0), 6), + field("Empty", int(0), 7), + tfield("Dup", int(0), 8, 0), + } + if msg, ok := compareFields(got, want); !ok { + t.Error(msg) + } +} + +func TestAgainstJSONEncodingWithTags(t *testing.T) { + // Demonstrates that this package produces the same set of fields as encoding/json. + s2 := S2{ + NoTag: 1, + XXX: 2, + Anonymous: 3, + Embed: Embed{ + Em: 4, + }, + tEmbed1: tEmbed1{ + Dup: 5, + X: 6, + }, + tEmbed2: tEmbed2{ + Y: 7, + Z: 8, + }, + } + var want S2 + jsonRoundTrip(t, s2, &want) + var got S2 + fields, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(got)) + if err != nil { + t.Fatal(err) + } + setFields(fields, &got, s2) + if !testutil.Equal(got, want, cmp.AllowUnexported(S2{})) { + t.Errorf("got\n%+v\nwant\n%+v", got, want) + } +} + +func TestUnexportedAnonymousNonStruct(t *testing.T) { + // An unexported anonymous non-struct field should not be recorded. + // This is currently a bug in encoding/json. + // https://github.com/golang/go/issues/18009 + type ( + u int + v int + S struct { + u + v `json:"x"` + int + } + ) + + got, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S{})) + if err != nil { + t.Fatal(err) + } + if len(got) != 0 { + t.Errorf("got %d fields, want 0", len(got)) + } +} + +func TestUnexportedAnonymousStruct(t *testing.T) { + // An unexported anonymous struct with a tag is ignored. + // This is currently a bug in encoding/json. + // https://github.com/golang/go/issues/18009 + type ( + s1 struct{ X int } + S2 struct { + s1 `json:"Y"` + } + ) + got, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S2{})) + if err != nil { + t.Fatal(err) + } + if len(got) != 0 { + t.Errorf("got %d fields, want 0", len(got)) + } +} + +func TestDominantField(t *testing.T) { + // With fields sorted by index length and then by tag presence, + // the dominant field is always the first. Make sure all error + // cases are caught. + for _, test := range []struct { + fields []Field + wantOK bool + }{ + // A single field is OK. + {[]Field{{Index: []int{0}}}, true}, + {[]Field{{Index: []int{0}, NameFromTag: true}}, true}, + // A single field at top level is OK. + {[]Field{{Index: []int{0}}, {Index: []int{1, 0}}}, true}, + {[]Field{{Index: []int{0}}, {Index: []int{1, 0}, NameFromTag: true}}, true}, + {[]Field{{Index: []int{0}, NameFromTag: true}, {Index: []int{1, 0}, NameFromTag: true}}, true}, + // A single tagged field is OK. + {[]Field{{Index: []int{0}, NameFromTag: true}, {Index: []int{1}}}, true}, + // Two untagged fields at the same level is an error. + {[]Field{{Index: []int{0}}, {Index: []int{1}}}, false}, + // Two tagged fields at the same level is an error. + {[]Field{{Index: []int{0}, NameFromTag: true}, {Index: []int{1}, NameFromTag: true}}, false}, + } { + _, gotOK := dominantField(test.fields) + if gotOK != test.wantOK { + t.Errorf("%v: got %t, want %t", test.fields, gotOK, test.wantOK) + } + } +} + +func TestIgnore(t *testing.T) { + type S struct { + X int `json:"-"` + } + got, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S{})) + if err != nil { + t.Fatal(err) + } + if len(got) != 0 { + t.Errorf("got %d fields, want 0", len(got)) + } +} + +func TestParsedTag(t *testing.T) { + type S struct { + X int `json:"name,omitempty"` + } + got, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S{})) + if err != nil { + t.Fatal(err) + } + want := []*Field{ + {Name: "name", NameFromTag: true, Type: intType, + Index: []int{0}, ParsedTag: []string{"omitempty"}}, + } + if msg, ok := compareFields(got, want); !ok { + t.Error(msg) + } +} + +func TestValidateFunc(t *testing.T) { + type MyInvalidStruct struct { + A string + B []int + } + + _, err := NewCache(nil, validateFunc, nil).Fields(reflect.TypeOf(MyInvalidStruct{})) + if err == nil { + t.Fatal("expected error, got nil") + } + + type MyValidStruct struct { + A string + B int + } + _, err = NewCache(nil, validateFunc, nil).Fields(reflect.TypeOf(MyValidStruct{})) + if err != nil { + t.Fatalf("expected nil, got error: %s\n", err) + } +} + +func compareFields(got []Field, want []*Field) (msg string, ok bool) { + if len(got) != len(want) { + return fmt.Sprintf("got %d fields, want %d", len(got), len(want)), false + } + for i, g := range got { + w := *want[i] + if !fieldsEqual(&g, &w) { + return fmt.Sprintf("got\n%+v\nwant\n%+v", g, w), false + } + } + return "", true +} + +// Need this because Field contains a function, which cannot be compared even +// by testutil.Equal. +func fieldsEqual(f1, f2 *Field) bool { + if f1 == nil || f2 == nil { + return f1 == f2 + } + return f1.Name == f2.Name && + f1.NameFromTag == f2.NameFromTag && + f1.Type == f2.Type && + testutil.Equal(f1.ParsedTag, f2.ParsedTag) +} + +// Set the fields of dst from those of src. +// dst must be a pointer to a struct value. +// src must be a struct value. +func setFields(fields []Field, dst, src interface{}) { + vsrc := reflect.ValueOf(src) + vdst := reflect.ValueOf(dst).Elem() + for _, f := range fields { + fdst := vdst.FieldByIndex(f.Index) + fsrc := vsrc.FieldByIndex(f.Index) + fdst.Set(fsrc) + } +} + +func jsonRoundTrip(t *testing.T, in, out interface{}) { + bytes, err := json.Marshal(in) + if err != nil { + t.Fatal(err) + } + if err := json.Unmarshal(bytes, out); err != nil { + t.Fatal(err) + } +} + +type S3 struct { + S4 + Abc int + AbC int + Tag int + X int `json:"Tag"` + unexported int +} + +type S4 struct { + ABc int + Y int `json:"Abc"` // ignored because of top-level Abc +} + +func TestMatchingField(t *testing.T) { + fields, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S3{})) + if err != nil { + t.Fatal(err) + } + for _, test := range []struct { + name string + want *Field + }{ + // Exact match wins. + {"Abc", field("Abc", int(0), 1)}, + {"AbC", field("AbC", int(0), 2)}, + {"ABc", field("ABc", int(0), 0, 0)}, + // If there are multiple matches but no exact match or tag, + // the first field wins, lexicographically by index. + // Here, "ABc" is at a deeper embedding level, but since S4 appears + // first in S3, its index precedes the other fields of S3. + {"abc", field("ABc", int(0), 0, 0)}, + // Tag name takes precedence over untagged field of the same name. + {"Tag", tfield("Tag", int(0), 4)}, + // Unexported fields disappear. + {"unexported", nil}, + // Untagged embedded structs disappear. + {"S4", nil}, + } { + if got := fields.Match(test.name); !fieldsEqual(got, test.want) { + t.Errorf("match %q:\ngot %+v\nwant %+v", test.name, got, test.want) + } + } +} + +func TestAgainstJSONMatchingField(t *testing.T) { + s3 := S3{ + S4: S4{ABc: 1, Y: 2}, + Abc: 3, + AbC: 4, + Tag: 5, + X: 6, + unexported: 7, + } + var want S3 + jsonRoundTrip(t, s3, &want) + v := reflect.ValueOf(want) + fields, err := NewCache(jsonTagParser, nil, nil).Fields(reflect.TypeOf(S3{})) + if err != nil { + t.Fatal(err) + } + for _, test := range []struct { + name string + got int + }{ + {"Abc", 3}, + {"AbC", 4}, + {"ABc", 1}, + {"abc", 1}, + {"Tag", 6}, + } { + f := fields.Match(test.name) + if f == nil { + t.Fatalf("%s: no match", test.name) + } + w := v.FieldByIndex(f.Index).Interface() + if test.got != w { + t.Errorf("%s: got %d, want %d", test.name, test.got, w) + } + } +} + +func TestTagErrors(t *testing.T) { + called := false + c := NewCache(func(t reflect.StructTag) (string, bool, interface{}, error) { + called = true + s := t.Get("f") + if s == "bad" { + return "", false, nil, errors.New("error") + } + return s, true, nil, nil + }, nil, nil) + + type T struct { + X int `f:"ok"` + Y int `f:"bad"` + } + + _, err := c.Fields(reflect.TypeOf(T{})) + if !called { + t.Fatal("tag parser not called") + } + if err == nil { + t.Error("want error, got nil") + } + // Second time, we should cache the error. + called = false + _, err = c.Fields(reflect.TypeOf(T{})) + if called { + t.Fatal("tag parser called on second time") + } + if err == nil { + t.Error("want error, got nil") + } +} diff --git a/vendor/cloud.google.com/go/internal/fields/fold.go b/vendor/cloud.google.com/go/internal/fields/fold.go new file mode 100644 index 00000000..68e2588c --- /dev/null +++ b/vendor/cloud.google.com/go/internal/fields/fold.go @@ -0,0 +1,156 @@ +// Copyright 2016 Google LLC +// +// 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 fields + +// This file was copied from https://go.googlesource.com/go/+/go1.7.3/src/encoding/json/fold.go. +// Only the license and package were changed. + +import ( + "bytes" + "unicode/utf8" +) + +const ( + caseMask = ^byte(0x20) // Mask to ignore case in ASCII. + kelvin = '\u212a' + smallLongEss = '\u017f' +) + +// foldFunc returns one of four different case folding equivalence +// functions, from most general (and slow) to fastest: +// +// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8 +// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S') +// 3) asciiEqualFold, no special, but includes non-letters (including _) +// 4) simpleLetterEqualFold, no specials, no non-letters. +// +// The letters S and K are special because they map to 3 runes, not just 2: +// * S maps to s and to U+017F 'ſ' Latin small letter long s +// * k maps to K and to U+212A 'K' Kelvin sign +// See https://play.golang.org/p/tTxjOc0OGo +// +// The returned function is specialized for matching against s and +// should only be given s. It's not curried for performance reasons. +func foldFunc(s []byte) func(s, t []byte) bool { + nonLetter := false + special := false // special letter + for _, b := range s { + if b >= utf8.RuneSelf { + return bytes.EqualFold + } + upper := b & caseMask + if upper < 'A' || upper > 'Z' { + nonLetter = true + } else if upper == 'K' || upper == 'S' { + // See above for why these letters are special. + special = true + } + } + if special { + return equalFoldRight + } + if nonLetter { + return asciiEqualFold + } + return simpleLetterEqualFold +} + +// equalFoldRight is a specialization of bytes.EqualFold when s is +// known to be all ASCII (including punctuation), but contains an 's', +// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t. +// See comments on foldFunc. +func equalFoldRight(s, t []byte) bool { + for _, sb := range s { + if len(t) == 0 { + return false + } + tb := t[0] + if tb < utf8.RuneSelf { + if sb != tb { + sbUpper := sb & caseMask + if 'A' <= sbUpper && sbUpper <= 'Z' { + if sbUpper != tb&caseMask { + return false + } + } else { + return false + } + } + t = t[1:] + continue + } + // sb is ASCII and t is not. t must be either kelvin + // sign or long s; sb must be s, S, k, or K. + tr, size := utf8.DecodeRune(t) + switch sb { + case 's', 'S': + if tr != smallLongEss { + return false + } + case 'k', 'K': + if tr != kelvin { + return false + } + default: + return false + } + t = t[size:] + + } + if len(t) > 0 { + return false + } + return true +} + +// asciiEqualFold is a specialization of bytes.EqualFold for use when +// s is all ASCII (but may contain non-letters) and contains no +// special-folding letters. +// See comments on foldFunc. +func asciiEqualFold(s, t []byte) bool { + if len(s) != len(t) { + return false + } + for i, sb := range s { + tb := t[i] + if sb == tb { + continue + } + if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') { + if sb&caseMask != tb&caseMask { + return false + } + } else { + return false + } + } + return true +} + +// simpleLetterEqualFold is a specialization of bytes.EqualFold for +// use when s is all ASCII letters (no underscores, etc) and also +// doesn't contain 'k', 'K', 's', or 'S'. +// See comments on foldFunc. +func simpleLetterEqualFold(s, t []byte) bool { + if len(s) != len(t) { + return false + } + for i, b := range s { + if b&caseMask != t[i]&caseMask { + return false + } + } + return true +} diff --git a/vendor/cloud.google.com/go/internal/fields/fold_test.go b/vendor/cloud.google.com/go/internal/fields/fold_test.go new file mode 100644 index 00000000..77cb80ba --- /dev/null +++ b/vendor/cloud.google.com/go/internal/fields/fold_test.go @@ -0,0 +1,129 @@ +// Copyright 2016 Google LLC +// +// 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 fields + +// This file was copied from https://go.googlesource.com/go/+/go1.7.3/src/encoding/json/fold_test.go. +// Only the license and package were changed. + +import ( + "bytes" + "strings" + "testing" + "unicode/utf8" +) + +var foldTests = []struct { + fn func(s, t []byte) bool + s, t string + want bool +}{ + {equalFoldRight, "", "", true}, + {equalFoldRight, "a", "a", true}, + {equalFoldRight, "", "a", false}, + {equalFoldRight, "a", "", false}, + {equalFoldRight, "a", "A", true}, + {equalFoldRight, "AB", "ab", true}, + {equalFoldRight, "AB", "ac", false}, + {equalFoldRight, "sbkKc", "ſbKKc", true}, + {equalFoldRight, "SbKkc", "ſbKKc", true}, + {equalFoldRight, "SbKkc", "ſbKK", false}, + {equalFoldRight, "e", "é", false}, + {equalFoldRight, "s", "S", true}, + + {simpleLetterEqualFold, "", "", true}, + {simpleLetterEqualFold, "abc", "abc", true}, + {simpleLetterEqualFold, "abc", "ABC", true}, + {simpleLetterEqualFold, "abc", "ABCD", false}, + {simpleLetterEqualFold, "abc", "xxx", false}, + + {asciiEqualFold, "a_B", "A_b", true}, + {asciiEqualFold, "aa@", "aa`", false}, // verify 0x40 and 0x60 aren't case-equivalent +} + +func TestFold(t *testing.T) { + for i, tt := range foldTests { + if got := tt.fn([]byte(tt.s), []byte(tt.t)); got != tt.want { + t.Errorf("%d. %q, %q = %v; want %v", i, tt.s, tt.t, got, tt.want) + } + truth := strings.EqualFold(tt.s, tt.t) + if truth != tt.want { + t.Errorf("strings.EqualFold doesn't agree with case %d", i) + } + } +} + +func TestFoldAgainstUnicode(t *testing.T) { + const bufSize = 5 + buf1 := make([]byte, 0, bufSize) + buf2 := make([]byte, 0, bufSize) + var runes []rune + for i := 0x20; i <= 0x7f; i++ { + runes = append(runes, rune(i)) + } + runes = append(runes, kelvin, smallLongEss) + + funcs := []struct { + name string + fold func(s, t []byte) bool + letter bool // must be ASCII letter + simple bool // must be simple ASCII letter (not 'S' or 'K') + }{ + { + name: "equalFoldRight", + fold: equalFoldRight, + }, + { + name: "asciiEqualFold", + fold: asciiEqualFold, + simple: true, + }, + { + name: "simpleLetterEqualFold", + fold: simpleLetterEqualFold, + simple: true, + letter: true, + }, + } + + for _, ff := range funcs { + for _, r := range runes { + if r >= utf8.RuneSelf { + continue + } + if ff.letter && !isASCIILetter(byte(r)) { + continue + } + if ff.simple && (r == 's' || r == 'S' || r == 'k' || r == 'K') { + continue + } + for _, r2 := range runes { + buf1 := append(buf1[:0], 'x') + buf2 := append(buf2[:0], 'x') + buf1 = buf1[:1+utf8.EncodeRune(buf1[1:bufSize], r)] + buf2 = buf2[:1+utf8.EncodeRune(buf2[1:bufSize], r2)] + buf1 = append(buf1, 'x') + buf2 = append(buf2, 'x') + want := bytes.EqualFold(buf1, buf2) + if got := ff.fold(buf1, buf2); got != want { + t.Errorf("%s(%q, %q) = %v; want %v", ff.name, buf1, buf2, got, want) + } + } + } + } +} + +func isASCIILetter(b byte) bool { + return ('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z') +} diff --git a/vendor/cloud.google.com/go/internal/kokoro/continuous.sh b/vendor/cloud.google.com/go/internal/kokoro/continuous.sh new file mode 100755 index 00000000..44f119bf --- /dev/null +++ b/vendor/cloud.google.com/go/internal/kokoro/continuous.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +export GOOGLE_APPLICATION_CREDENTIALS=$KOKORO_KEYSTORE_DIR/72523_go_integration_service_account +export GCLOUD_TESTS_GOLANG_PROJECT_ID=dulcet-port-762 +export GCLOUD_TESTS_GOLANG_KEY=$GOOGLE_APPLICATION_CREDENTIALS +export GCLOUD_TESTS_GOLANG_FIRESTORE_PROJECT_ID=gcloud-golang-firestore-tests +export GCLOUD_TESTS_GOLANG_FIRESTORE_KEY=$KOKORO_KEYSTORE_DIR/72523_go_firestore_integration_service_account +export GCLOUD_TESTS_API_KEY=`cat $KOKORO_KEYSTORE_DIR/72523_go_gcloud_tests_api_key` +export GCLOUD_TESTS_GOLANG_KEYRING=projects/dulcet-port-762/locations/global/keyRings/go-integration-test + +# Fail on any error +set -eo pipefail + +# Display commands being run +set -x + +# cd to project dir on Kokoro instance +cd git/gocloud + +go version + +# Set $GOPATH +export GOPATH="$HOME/go" +export GOCLOUD_HOME=$GOPATH/src/cloud.google.com/go/ +export PATH="$GOPATH/bin:$PATH" +mkdir -p $GOCLOUD_HOME + +# Move code into $GOPATH and get dependencies +git clone . $GOCLOUD_HOME +cd $GOCLOUD_HOME + +try3() { eval "$*" || eval "$*" || eval "$*"; } +try3 go get -v -t ./... + +./internal/kokoro/vet.sh + +# Run tests and tee output to log file, to be pushed to GCS as artifact. +go test -race -v -timeout 15m ./... 2>&1 | tee $KOKORO_ARTIFACTS_DIR/$KOKORO_GERRIT_CHANGE_NUMBER.txt \ No newline at end of file diff --git a/vendor/cloud.google.com/go/internal/kokoro/presubmit.sh b/vendor/cloud.google.com/go/internal/kokoro/presubmit.sh new file mode 100755 index 00000000..d0dd965c --- /dev/null +++ b/vendor/cloud.google.com/go/internal/kokoro/presubmit.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# TODO(deklerk) Add integration tests when it's secure to do so. b/64723143 + +# Fail on any error +set -eo pipefail + +# Display commands being run +set -x + +# cd to project dir on Kokoro instance +cd git/gocloud + +go version + +# Set $GOPATH +export GOPATH="$HOME/go" +export GOCLOUD_HOME=$GOPATH/src/cloud.google.com/go/ +export PATH="$GOPATH/bin:$PATH" +mkdir -p $GOCLOUD_HOME + +# Move code into $GOPATH and get dependencies +git clone . $GOCLOUD_HOME +cd $GOCLOUD_HOME + +try3() { eval "$*" || eval "$*" || eval "$*"; } +try3 go get -v -t ./... + +./internal/kokoro/vet.sh + +# Run tests and tee output to log file, to be pushed to GCS as artifact. +go test -race -v -timeout 15m -short ./... 2>&1 | tee $KOKORO_ARTIFACTS_DIR/$KOKORO_GERRIT_CHANGE_NUMBER.txt \ No newline at end of file diff --git a/vendor/cloud.google.com/go/internal/kokoro/trampoline.sh b/vendor/cloud.google.com/go/internal/kokoro/trampoline.sh new file mode 100644 index 00000000..ba17ce01 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/kokoro/trampoline.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Copyright 2018 Google 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. +set -eo pipefail +# Always run the cleanup script, regardless of the success of bouncing into +# the container. +function cleanup() { + chmod +x ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh + ${KOKORO_GFILE_DIR}/trampoline_cleanup.sh + echo "cleanup"; +} +trap cleanup EXIT +python3 "${KOKORO_GFILE_DIR}/trampoline_v1.py" diff --git a/vendor/cloud.google.com/go/internal/kokoro/vet.sh b/vendor/cloud.google.com/go/internal/kokoro/vet.sh new file mode 100755 index 00000000..f2381e0f --- /dev/null +++ b/vendor/cloud.google.com/go/internal/kokoro/vet.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +# Fail on any error +set -eo pipefail + +# Display commands being run +set -x + +# Only run the linter on go1.11, since it needs type aliases (and we only care about its output once). +# TODO(deklerk) We should pass an environment variable from kokoro to decide this logic instead. +if [[ `go version` != *"go1.11"* ]]; then + exit 0 +fi + +pwd + +try3() { eval "$*" || eval "$*" || eval "$*"; } + +try3 go get -u \ + golang.org/x/lint/golint \ + golang.org/x/tools/cmd/goimports \ + golang.org/x/lint/golint \ + honnef.co/go/tools/cmd/staticcheck + +# Look at all .go files (ignoring .pb.go files) and make sure they have a Copyright. Fail if any don't. +git ls-files "*[^.pb].go" | xargs grep -L "\(Copyright [0-9]\{4,\}\)" 2>&1 | tee /dev/stderr | (! read) +gofmt -s -d -l . 2>&1 | tee /dev/stderr | (! read) +goimports -l . 2>&1 | tee /dev/stderr | (! read) + +# Runs the linter. Regrettably the linter is very simple and does not provide the ability to exclude rules or files, +# so we rely on inverse grepping to do this for us. +# +# Piping a bunch of greps may be slower than `grep -vE (thing|otherthing|anotherthing|etc)`, but since we have a good +# amount of things we're excluding, it seems better to optimize for readability. +# +# Note: since we added the linter after-the-fact, some of the ignored errors here are because we can't change an +# existing interface. (as opposed to us not caring about the error) +golint ./... 2>&1 | ( \ + grep -vE "gen\.go" | \ + grep -vE "receiver name [a-zA-Z]+[0-9]* should be consistent with previous receiver name" | \ + grep -vE "exported const AllUsers|AllAuthenticatedUsers|RoleOwner|SSD|HDD|PRODUCTION|DEVELOPMENT should have comment" | \ + grep -v "exported func Value returns unexported type pretty.val, which can be annoying to use" | \ + grep -v "ExecuteStreamingSql" | \ + grep -v "ClusterId" | \ + grep -v "InstanceId" | \ + grep -v "firestore.arrayUnion" | \ + grep -v "firestore.arrayRemove" | \ + grep -v "maxAttempts" | \ + grep -v "UptimeCheckIpIterator" | \ + grep -vE "apiv[0-9]+" | \ + grep -v "ALL_CAPS" | \ + grep -v "go-cloud-debug-agent" | \ + grep -v "mock_test" | \ + grep -v "a blank import should be only in a main or test package" | \ + grep -vE "\.pb\.go:" || true) | tee /dev/stderr | (! read) + +# TODO(deklerk) It doesn't seem like it, but is it possible to glob both before +# and after the colon? Then we could do *go-cloud-debug-agent*:* +staticcheck -ignore ' +*:SA1019 +cloud.google.com/go/firestore/internal/doc-snippets.go:* +cloud.google.com/go/functions/metadata/metadata_test.go:SA1012 +cloud.google.com/go/cmd/go-cloud-debug-agent/internal/controller/client_test.go:* +cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/frame.go:* +cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/dwarf/typeunit.go:* +cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/elf/file.go:* +cloud.google.com/go/cmd/go-cloud-debug-agent/internal/debug/server/server.go:* +' ./... diff --git a/vendor/cloud.google.com/go/internal/leakcheck/leakcheck.go b/vendor/cloud.google.com/go/internal/leakcheck/leakcheck.go new file mode 100644 index 00000000..4184adc0 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/leakcheck/leakcheck.go @@ -0,0 +1,119 @@ +// Copyright 2018 Google LLC +// +// 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 leakcheck contains functions to check leaked goroutines. +// +// Call "defer leakcheck.Check(t)" at the beginning of tests. +// +// This is very closely based on grpc-go's leakcheck. +package leakcheck + +import ( + "runtime" + "sort" + "strings" + "time" +) + +var goroutinesToIgnore = []string{ + "net/http/transport.go", + "net/http/h2_bundle.go", + "src/go.opencensus.io/stats/view/worker.go", + "testing.Main(", + "testing.tRunner(", + "testing.(*M).", + "runtime.goexit", + "created by runtime.gc", + "created by runtime/trace.Start", + "interestingGoroutines", + "runtime.MHeap_Scavenger", + "signal.signal_recv", + "sigterm.handler", + "runtime_mcall", + "(*loggingT).flushDaemon", + "goroutine in C code", +} + +// RegisterIgnoreGoroutine appends s into the ignore goroutine list. The +// goroutines whose stack trace contains s will not be identified as leaked +// goroutines. Not thread-safe, only call this function in init(). +func RegisterIgnoreGoroutine(s string) { + goroutinesToIgnore = append(goroutinesToIgnore, s) +} + +func ignore(g string) bool { + sl := strings.SplitN(g, "\n", 2) + if len(sl) != 2 { + return true + } + stack := strings.TrimSpace(sl[1]) + if strings.HasPrefix(stack, "testing.RunTests") { + return true + } + + if stack == "" { + return true + } + + for _, s := range goroutinesToIgnore { + if strings.Contains(stack, s) { + return true + } + } + + return false +} + +// interestingGoroutines returns all goroutines we care about for the purpose of +// leak checking. It excludes testing or runtime ones. +func interestingGoroutines() (gs []string) { + buf := make([]byte, 2<<20) + buf = buf[:runtime.Stack(buf, true)] + for _, g := range strings.Split(string(buf), "\n\n") { + if !ignore(g) { + gs = append(gs, g) + } + } + sort.Strings(gs) + return +} + +// Errorfer is the interface that wraps the Errorf method. It's a subset of +// testing.TB to make it easy to use Check. +type Errorfer interface { + Errorf(format string, args ...interface{}) +} + +func check(efer Errorfer, timeout time.Duration) { + // Loop, waiting for goroutines to shut down. + // Wait up to timeout, but finish as quickly as possible. + deadline := time.Now().Add(timeout) + var leaked []string + for time.Now().Before(deadline) { + if leaked = interestingGoroutines(); len(leaked) == 0 { + return + } + time.Sleep(50 * time.Millisecond) + } + for _, g := range leaked { + efer.Errorf("Leaked goroutine: %v", g) + } +} + +// Check looks at the currently-running goroutines and checks if there are any +// interestring (created by gRPC) goroutines leaked. It waits up to 10 seconds +// in the error cases. +func Check(efer Errorfer) { + check(efer, 10*time.Second) +} diff --git a/vendor/cloud.google.com/go/internal/leakcheck/leakcheck_test.go b/vendor/cloud.google.com/go/internal/leakcheck/leakcheck_test.go new file mode 100644 index 00000000..2a8f1e65 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/leakcheck/leakcheck_test.go @@ -0,0 +1,72 @@ +// Copyright 2018 Google LLC +// +// 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 leakcheck + +import ( + "fmt" + "strings" + "testing" + "time" +) + +type testErrorfer struct { + errorCount int + errors []string +} + +func (e *testErrorfer) Errorf(format string, args ...interface{}) { + e.errors = append(e.errors, fmt.Sprintf(format, args...)) + e.errorCount++ +} + +func TestCheck(t *testing.T) { + const leakCount = 3 + for i := 0; i < leakCount; i++ { + go func() { time.Sleep(2 * time.Second) }() + } + if ig := interestingGoroutines(); len(ig) == 0 { + t.Error("blah") + } + e := &testErrorfer{} + check(e, time.Second) + if e.errorCount != leakCount { + t.Errorf("check found %v leaks, want %v leaks", e.errorCount, leakCount) + t.Logf("leaked goroutines:\n%v", strings.Join(e.errors, "\n")) + } + check(t, 3*time.Second) +} + +func ignoredTestingLeak(d time.Duration) { + time.Sleep(d) +} + +func TestCheckRegisterIgnore(t *testing.T) { + RegisterIgnoreGoroutine("ignoredTestingLeak") + const leakCount = 3 + for i := 0; i < leakCount; i++ { + go func() { time.Sleep(2 * time.Second) }() + } + go func() { ignoredTestingLeak(3 * time.Second) }() + if ig := interestingGoroutines(); len(ig) == 0 { + t.Error("blah") + } + e := &testErrorfer{} + check(e, time.Second) + if e.errorCount != leakCount { + t.Errorf("check found %v leaks, want %v leaks", e.errorCount, leakCount) + t.Logf("leaked goroutines:\n%v", strings.Join(e.errors, "\n")) + } + check(t, 3*time.Second) +} diff --git a/vendor/cloud.google.com/go/internal/optional/optional.go b/vendor/cloud.google.com/go/internal/optional/optional.go new file mode 100644 index 00000000..72780f76 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/optional/optional.go @@ -0,0 +1,108 @@ +// Copyright 2016 Google LLC +// +// 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 optional provides versions of primitive types that can +// be nil. These are useful in methods that update some of an API object's +// fields. +package optional + +import ( + "fmt" + "strings" + "time" +) + +type ( + // Bool is either a bool or nil. + Bool interface{} + + // String is either a string or nil. + String interface{} + + // Int is either an int or nil. + Int interface{} + + // Uint is either a uint or nil. + Uint interface{} + + // Float64 is either a float64 or nil. + Float64 interface{} + + // Duration is either a time.Duration or nil. + Duration interface{} +) + +// ToBool returns its argument as a bool. +// It panics if its argument is nil or not a bool. +func ToBool(v Bool) bool { + x, ok := v.(bool) + if !ok { + doPanic("Bool", v) + } + return x +} + +// ToString returns its argument as a string. +// It panics if its argument is nil or not a string. +func ToString(v String) string { + x, ok := v.(string) + if !ok { + doPanic("String", v) + } + return x +} + +// ToInt returns its argument as an int. +// It panics if its argument is nil or not an int. +func ToInt(v Int) int { + x, ok := v.(int) + if !ok { + doPanic("Int", v) + } + return x +} + +// ToUint returns its argument as a uint. +// It panics if its argument is nil or not a uint. +func ToUint(v Uint) uint { + x, ok := v.(uint) + if !ok { + doPanic("Uint", v) + } + return x +} + +// ToFloat64 returns its argument as a float64. +// It panics if its argument is nil or not a float64. +func ToFloat64(v Float64) float64 { + x, ok := v.(float64) + if !ok { + doPanic("Float64", v) + } + return x +} + +// ToDuration returns its argument as a time.Duration. +// It panics if its argument is nil or not a time.Duration. +func ToDuration(v Duration) time.Duration { + x, ok := v.(time.Duration) + if !ok { + doPanic("Duration", v) + } + return x +} + +func doPanic(capType string, v interface{}) { + panic(fmt.Sprintf("optional.%s value should be %s, got %T", capType, strings.ToLower(capType), v)) +} diff --git a/vendor/cloud.google.com/go/internal/optional/optional_test.go b/vendor/cloud.google.com/go/internal/optional/optional_test.go new file mode 100644 index 00000000..85b83aad --- /dev/null +++ b/vendor/cloud.google.com/go/internal/optional/optional_test.go @@ -0,0 +1,64 @@ +// Copyright 2016 Google LLC +// +// 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 optional + +import "testing" + +func TestConvertSuccess(t *testing.T) { + if got, want := ToBool(false), false; got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := ToString(""), ""; got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := ToInt(0), 0; got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := ToUint(uint(0)), uint(0); got != want { + t.Errorf("got %v, want %v", got, want) + } + if got, want := ToFloat64(0.0), 0.0; got != want { + t.Errorf("got %v, want %v", got, want) + } +} + +func TestConvertFailure(t *testing.T) { + for _, f := range []func(){ + func() { ToBool(nil) }, + func() { ToBool(3) }, + func() { ToString(nil) }, + func() { ToString(3) }, + func() { ToInt(nil) }, + func() { ToInt("") }, + func() { ToUint(nil) }, + func() { ToUint("") }, + func() { ToFloat64(nil) }, + func() { ToFloat64("") }, + } { + if !panics(f) { + t.Error("got no panic, want panic") + } + } +} + +func panics(f func()) (b bool) { + defer func() { + if recover() != nil { + b = true + } + }() + f() + return false +} diff --git a/vendor/cloud.google.com/go/internal/pretty/diff.go b/vendor/cloud.google.com/go/internal/pretty/diff.go new file mode 100644 index 00000000..2edea743 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/pretty/diff.go @@ -0,0 +1,78 @@ +// Copyright 2016 Google LLC +// +// 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 pretty + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "syscall" +) + +// Diff compares the pretty-printed representation of two values. The second +// return value reports whether the two values' representations are identical. +// If it is false, the first return value contains the diffs. +// +// The output labels the first value "want" and the second "got". +// +// Diff works by invoking the "diff" command. It will only succeed in +// environments where "diff" is on the shell path. +func Diff(want, got interface{}) (string, bool, error) { + fname1, err := writeToTemp(want) + if err != nil { + return "", false, err + } + defer os.Remove(fname1) + + fname2, err := writeToTemp(got) + if err != nil { + return "", false, err + } + defer os.Remove(fname2) + + cmd := exec.Command("diff", "-u", "--label=want", "--label=got", fname1, fname2) + out, err := cmd.Output() + if err == nil { + return string(out), true, nil + } + eerr, ok := err.(*exec.ExitError) + if !ok { + return "", false, err + } + ws, ok := eerr.Sys().(syscall.WaitStatus) + if !ok { + return "", false, err + } + if ws.ExitStatus() != 1 { + return "", false, err + } + // Exit status of 1 means no error, but diffs were found. + return string(out), false, nil +} + +func writeToTemp(v interface{}) (string, error) { + f, err := ioutil.TempFile("", "prettyDiff") + if err != nil { + return "", err + } + if _, err := fmt.Fprintf(f, "%+v\n", Value(v)); err != nil { + return "", err + } + if err := f.Close(); err != nil { + return "", err + } + return f.Name(), nil +} diff --git a/vendor/cloud.google.com/go/internal/pretty/diff_test.go b/vendor/cloud.google.com/go/internal/pretty/diff_test.go new file mode 100644 index 00000000..e6ef1790 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/pretty/diff_test.go @@ -0,0 +1,50 @@ +// Copyright 2016 Google LLC +// +// 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 pretty + +import "testing" + +func TestDiff(t *testing.T) { + for _, test := range []struct { + v1, v2 interface{} + ok bool + want string + }{ + {5, 5, true, ""}, + {"foo", "foo", true, ""}, + {[]int{1, 2, 3}, []int{1, 0, 3}, false, `--- want ++++ got +@@ -1,5 +1,5 @@ + []int{ + 1, +- 2, ++ 0, + 3, + } +`}, + } { + got, ok, err := Diff(test.v1, test.v2) + if err != nil { + t.Errorf("%v vs. %v: %v", test.v1, test.v2, err) + continue + } + if ok != test.ok { + t.Errorf("%v vs. %v: got %t, want %t", test.v1, test.v2, ok, test.ok) + } + if got != test.want { + t.Errorf("%v vs. %v: got:\n%q\nwant:\n%q", test.v1, test.v2, got, test.want) + } + } +} diff --git a/vendor/cloud.google.com/go/internal/pretty/pretty.go b/vendor/cloud.google.com/go/internal/pretty/pretty.go new file mode 100644 index 00000000..df981094 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/pretty/pretty.go @@ -0,0 +1,255 @@ +// Copyright 2016 Google LLC +// +// 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 pretty implements a simple pretty-printer. It is intended for +// debugging the output of tests. +// +// It follows pointers and produces multi-line output for complex values like +// slices, maps and structs. +package pretty + +import ( + "fmt" + "io" + "reflect" + "sort" + "strings" + "time" +) + +// Indent is the string output at each level of indentation. +var Indent = " " + +// Value returns a value that will print prettily when used as an +// argument for the %v or %s format specifiers. +// With no flags, struct fields and map keys with default values are omitted. +// With the '+' or '#' flags, all values are displayed. +// +// This package does not detect cycles. Attempting to print a Value that +// contains cycles will result in unbounded recursion. +func Value(v interface{}) val { return val{v: v} } + +// val is a value. +type val struct{ v interface{} } + +// Format implements the fmt.Formatter interface. +func (v val) Format(s fmt.State, c rune) { + if c == 'v' || c == 's' { + fprint(s, reflect.ValueOf(v.v), state{ + defaults: s.Flag('+') || s.Flag('#'), + }) + } else { + fmt.Fprintf(s, "%%!%c(pretty.val)", c) + } +} + +type state struct { + level int + prefix, suffix string + defaults bool +} + +const maxLevel = 100 + +var typeOfTime = reflect.TypeOf(time.Time{}) + +func fprint(w io.Writer, v reflect.Value, s state) { + if s.level > maxLevel { + fmt.Fprintln(w, "pretty: max nested depth exceeded") + return + } + indent := strings.Repeat(Indent, s.level) + fmt.Fprintf(w, "%s%s", indent, s.prefix) + if isNil(v) { + fmt.Fprintf(w, "nil%s", s.suffix) + return + } + if v.Type().Kind() == reflect.Interface { + v = v.Elem() + } + if v.Type() == typeOfTime { + fmt.Fprintf(w, "%s%s", v.Interface(), s.suffix) + return + } + for v.Type().Kind() == reflect.Ptr { + fmt.Fprintf(w, "&") + v = v.Elem() + } + switch v.Type().Kind() { + default: + fmt.Fprintf(w, "%s%s", short(v), s.suffix) + + case reflect.Array: + fmt.Fprintf(w, "%s{\n", v.Type()) + for i := 0; i < v.Len(); i++ { + fprint(w, v.Index(i), state{ + level: s.level + 1, + prefix: "", + suffix: ",", + defaults: s.defaults, + }) + fmt.Fprintln(w) + } + fmt.Fprintf(w, "%s}", indent) + + case reflect.Slice: + fmt.Fprintf(w, "%s{", v.Type()) + if v.Len() > 0 { + fmt.Fprintln(w) + for i := 0; i < v.Len(); i++ { + fprint(w, v.Index(i), state{ + level: s.level + 1, + prefix: "", + suffix: ",", + defaults: s.defaults, + }) + fmt.Fprintln(w) + } + } + fmt.Fprintf(w, "%s}%s", indent, s.suffix) + + case reflect.Map: + fmt.Fprintf(w, "%s{", v.Type()) + if v.Len() > 0 { + fmt.Fprintln(w) + keys := v.MapKeys() + maybeSort(keys, v.Type().Key()) + for _, key := range keys { + val := v.MapIndex(key) + if s.defaults || !isDefault(val) { + fprint(w, val, state{ + level: s.level + 1, + prefix: short(key) + ": ", + suffix: ",", + defaults: s.defaults, + }) + fmt.Fprintln(w) + } + } + } + fmt.Fprintf(w, "%s}%s", indent, s.suffix) + + case reflect.Struct: + t := v.Type() + fmt.Fprintf(w, "%s{\n", t) + for i := 0; i < t.NumField(); i++ { + f := v.Field(i) + if s.defaults || !isDefault(f) { + fprint(w, f, state{ + level: s.level + 1, + prefix: t.Field(i).Name + ": ", + suffix: ",", + defaults: s.defaults, + }) + fmt.Fprintln(w) + } + } + fmt.Fprintf(w, "%s}%s", indent, s.suffix) + } +} + +func isNil(v reflect.Value) bool { + if !v.IsValid() { + return true + } + switch v.Type().Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return v.IsNil() + default: + return false + } +} + +func isDefault(v reflect.Value) bool { + if !v.IsValid() { + return true + } + t := v.Type() + switch t.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + return v.IsNil() + default: + if !v.CanInterface() { + return false + } + return t.Comparable() && v.Interface() == reflect.Zero(t).Interface() + } +} + +// short returns a short, one-line string for v. +func short(v reflect.Value) string { + if !v.IsValid() { + return "nil" + } + if v.Type().Kind() == reflect.String { + return fmt.Sprintf("%q", v) + } + return fmt.Sprintf("%v", v) +} + +func indent(w io.Writer, level int) { + for i := 0; i < level; i++ { + io.WriteString(w, Indent) // ignore errors + } +} + +func maybeSort(vs []reflect.Value, t reflect.Type) { + if less := lessFunc(t); less != nil { + sort.Sort(&sorter{vs, less}) + } +} + +// lessFunc returns a function that implements the "<" operator +// for the given type, or nil if the type doesn't support "<" . +func lessFunc(t reflect.Type) func(v1, v2 interface{}) bool { + switch t.Kind() { + case reflect.String: + return func(v1, v2 interface{}) bool { return v1.(string) < v2.(string) } + case reflect.Int: + return func(v1, v2 interface{}) bool { return v1.(int) < v2.(int) } + case reflect.Int8: + return func(v1, v2 interface{}) bool { return v1.(int8) < v2.(int8) } + case reflect.Int16: + return func(v1, v2 interface{}) bool { return v1.(int16) < v2.(int16) } + case reflect.Int32: + return func(v1, v2 interface{}) bool { return v1.(int32) < v2.(int32) } + case reflect.Int64: + return func(v1, v2 interface{}) bool { return v1.(int64) < v2.(int64) } + case reflect.Uint: + return func(v1, v2 interface{}) bool { return v1.(uint) < v2.(uint) } + case reflect.Uint8: + return func(v1, v2 interface{}) bool { return v1.(uint8) < v2.(uint8) } + case reflect.Uint16: + return func(v1, v2 interface{}) bool { return v1.(uint16) < v2.(uint16) } + case reflect.Uint32: + return func(v1, v2 interface{}) bool { return v1.(uint32) < v2.(uint32) } + case reflect.Uint64: + return func(v1, v2 interface{}) bool { return v1.(uint64) < v2.(uint64) } + case reflect.Float32: + return func(v1, v2 interface{}) bool { return v1.(float32) < v2.(float32) } + case reflect.Float64: + return func(v1, v2 interface{}) bool { return v1.(float64) < v2.(float64) } + default: + return nil + } +} + +type sorter struct { + vs []reflect.Value + less func(v1, v2 interface{}) bool +} + +func (s *sorter) Len() int { return len(s.vs) } +func (s *sorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] } +func (s *sorter) Less(i, j int) bool { return s.less(s.vs[i].Interface(), s.vs[j].Interface()) } diff --git a/vendor/cloud.google.com/go/internal/pretty/pretty_test.go b/vendor/cloud.google.com/go/internal/pretty/pretty_test.go new file mode 100644 index 00000000..50984f93 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/pretty/pretty_test.go @@ -0,0 +1,105 @@ +// Copyright 2016 Google LLC +// +// 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 pretty + +import ( + "fmt" + "strings" + "testing" +) + +type S struct { + X int + Y bool + z *string +} + +func TestSprint(t *testing.T) { + Indent = "~" + i := 17 + + for _, test := range []struct { + value interface{} + want string + }{ + // primitives and pointer + {nil, "nil"}, + {3, "3"}, + {9.8, "9.8"}, + {true, "true"}, + {"foo", `"foo"`}, + {&i, "&17"}, + // array and slice + {[3]int{1, 2, 3}, "[3]int{\n~1,\n~2,\n~3,\n}"}, + {[]int{1, 2, 3}, "[]int{\n~1,\n~2,\n~3,\n}"}, + {[]int{}, "[]int{}"}, + {[]string{"foo"}, "[]string{\n~\"foo\",\n}"}, + // map + {map[int]bool{}, "map[int]bool{}"}, + {map[int]bool{1: true, 2: false, 3: true}, + "map[int]bool{\n~1: true,\n~3: true,\n}"}, + // struct + {S{}, "pretty.S{\n}"}, + {S{3, true, ptr("foo")}, + "pretty.S{\n~X: 3,\n~Y: true,\n~z: &\"foo\",\n}"}, + // interface + {[]interface{}{&i}, "[]interface {}{\n~&17,\n}"}, + // nesting + {[]S{{1, false, ptr("a")}, {2, true, ptr("b")}}, + `[]pretty.S{ +~pretty.S{ +~~X: 1, +~~z: &"a", +~}, +~pretty.S{ +~~X: 2, +~~Y: true, +~~z: &"b", +~}, +}`}, + } { + got := fmt.Sprintf("%v", Value(test.value)) + if got != test.want { + t.Errorf("%v: got:\n%q\nwant:\n%q", test.value, got, test.want) + } + } +} + +func TestWithDefaults(t *testing.T) { + Indent = "~" + for _, test := range []struct { + value interface{} + want string + }{ + {map[int]bool{1: true, 2: false, 3: true}, + "map[int]bool{\n~1: true,\n~2: false,\n~3: true,\n}"}, + {S{}, "pretty.S{\n~X: 0,\n~Y: false,\n~z: nil,\n}"}, + } { + got := fmt.Sprintf("%+v", Value(test.value)) + if got != test.want { + t.Errorf("%v: got:\n%q\nwant:\n%q", test.value, got, test.want) + } + } +} + +func TestBadVerb(t *testing.T) { + got := fmt.Sprintf("%d", Value(8)) + want := "%!d(" + if !strings.HasPrefix(got, want) { + t.Errorf("got %q, want prefix %q", got, want) + } +} + +func ptr(s string) *string { return &s } diff --git a/vendor/cloud.google.com/go/internal/protostruct/protostruct.go b/vendor/cloud.google.com/go/internal/protostruct/protostruct.go new file mode 100644 index 00000000..3f8ebfb5 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/protostruct/protostruct.go @@ -0,0 +1,56 @@ +// Copyright 2017 Google LLC +// +// 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 protostruct supports operations on the protocol buffer Struct message. +package protostruct + +import ( + pb "github.com/golang/protobuf/ptypes/struct" +) + +// DecodeToMap converts a pb.Struct to a map from strings to Go types. +// DecodeToMap panics if s is invalid. +func DecodeToMap(s *pb.Struct) map[string]interface{} { + if s == nil { + return nil + } + m := map[string]interface{}{} + for k, v := range s.Fields { + m[k] = decodeValue(v) + } + return m +} + +func decodeValue(v *pb.Value) interface{} { + switch k := v.Kind.(type) { + case *pb.Value_NullValue: + return nil + case *pb.Value_NumberValue: + return k.NumberValue + case *pb.Value_StringValue: + return k.StringValue + case *pb.Value_BoolValue: + return k.BoolValue + case *pb.Value_StructValue: + return DecodeToMap(k.StructValue) + case *pb.Value_ListValue: + s := make([]interface{}, len(k.ListValue.Values)) + for i, e := range k.ListValue.Values { + s[i] = decodeValue(e) + } + return s + default: + panic("protostruct: unknown kind") + } +} diff --git a/vendor/cloud.google.com/go/internal/protostruct/protostruct_test.go b/vendor/cloud.google.com/go/internal/protostruct/protostruct_test.go new file mode 100644 index 00000000..cec8876c --- /dev/null +++ b/vendor/cloud.google.com/go/internal/protostruct/protostruct_test.go @@ -0,0 +1,58 @@ +// Copyright 2017 Google LLC +// +// 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 protostruct supports operations on the protocol buffer Struct message. +package protostruct + +import ( + "testing" + + "cloud.google.com/go/internal/testutil" + pb "github.com/golang/protobuf/ptypes/struct" +) + +func TestDecodeToMap(t *testing.T) { + if got := DecodeToMap(nil); !testutil.Equal(got, map[string]interface{}(nil)) { + t.Errorf("DecodeToMap(nil) = %v, want nil", got) + } + nullv := &pb.Value{Kind: &pb.Value_NullValue{}} + stringv := &pb.Value{Kind: &pb.Value_StringValue{"x"}} + boolv := &pb.Value{Kind: &pb.Value_BoolValue{true}} + numberv := &pb.Value{Kind: &pb.Value_NumberValue{2.7}} + in := &pb.Struct{Fields: map[string]*pb.Value{ + "n": nullv, + "s": stringv, + "b": boolv, + "f": numberv, + "l": {Kind: &pb.Value_ListValue{&pb.ListValue{ + Values: []*pb.Value{nullv, stringv, boolv, numberv}, + }}}, + "S": {Kind: &pb.Value_StructValue{&pb.Struct{Fields: map[string]*pb.Value{ + "n1": nullv, + "b1": boolv, + }}}}, + }} + want := map[string]interface{}{ + "n": nil, + "s": "x", + "b": true, + "f": 2.7, + "l": []interface{}{nil, "x", true, 2.7}, + "S": map[string]interface{}{"n1": nil, "b1": true}, + } + got := DecodeToMap(in) + if diff := testutil.Diff(got, want); diff != "" { + t.Error(diff) + } +} diff --git a/vendor/cloud.google.com/go/internal/retry.go b/vendor/cloud.google.com/go/internal/retry.go new file mode 100644 index 00000000..99093cc4 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/retry.go @@ -0,0 +1,54 @@ +// Copyright 2016 Google LLC +// +// 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 internal + +import ( + "context" + "time" + + gax "github.com/googleapis/gax-go" +) + +// Retry calls the supplied function f repeatedly according to the provided +// backoff parameters. It returns when one of the following occurs: +// When f's first return value is true, Retry immediately returns with f's second +// return value. +// When the provided context is done, Retry returns with an error that +// includes both ctx.Error() and the last error returned by f. +func Retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error)) error { + return retry(ctx, bo, f, gax.Sleep) +} + +func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error), + sleep func(context.Context, time.Duration) error) error { + var lastErr error + for { + stop, err := f() + if stop { + return err + } + // Remember the last "real" error from f. + if err != nil && err != context.Canceled && err != context.DeadlineExceeded { + lastErr = err + } + p := bo.Pause() + if cerr := sleep(ctx, p); cerr != nil { + if lastErr != nil { + return Annotatef(lastErr, "retry failed with %v; last error", cerr) + } + return cerr + } + } +} diff --git a/vendor/cloud.google.com/go/internal/retry_test.go b/vendor/cloud.google.com/go/internal/retry_test.go new file mode 100644 index 00000000..367f52c9 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/retry_test.go @@ -0,0 +1,89 @@ +// Copyright 2016 Google LLC +// +// 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 internal + +import ( + "context" + "errors" + "fmt" + "testing" + "time" + + gax "github.com/googleapis/gax-go" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestRetry(t *testing.T) { + ctx := context.Background() + // Without a context deadline, retry will run until the function + // says not to retry any more. + n := 0 + endRetry := errors.New("end retry") + err := retry(ctx, gax.Backoff{}, + func() (bool, error) { + n++ + if n < 10 { + return false, nil + } + return true, endRetry + }, + func(context.Context, time.Duration) error { return nil }) + if got, want := err, endRetry; got != want { + t.Errorf("got %v, want %v", err, endRetry) + } + if n != 10 { + t.Errorf("n: got %d, want %d", n, 10) + } + + // If the context has a deadline, sleep will return an error + // and end the function. + n = 0 + err = retry(ctx, gax.Backoff{}, + func() (bool, error) { return false, nil }, + func(context.Context, time.Duration) error { + n++ + if n < 10 { + return nil + } + return context.DeadlineExceeded + }) + if err == nil { + t.Error("got nil, want error") + } +} + +func TestRetryPreserveError(t *testing.T) { + // Retry tries to preserve the type and other information from + // the last error returned by the function. + err := retry(context.Background(), gax.Backoff{}, + func() (bool, error) { + return false, status.Error(codes.NotFound, "not found") + }, + func(context.Context, time.Duration) error { + return context.DeadlineExceeded + }) + got, ok := status.FromError(err) + if !ok { + t.Fatalf("got %T, wanted a status", got) + } + if g, w := got.Code(), codes.NotFound; g != w { + t.Errorf("got code %v, want %v", g, w) + } + wantMessage := fmt.Sprintf("retry failed with %v; last error: not found", context.DeadlineExceeded) + if g, w := got.Message(), wantMessage; g != w { + t.Errorf("got message %q, want %q", g, w) + } +} diff --git a/vendor/cloud.google.com/go/internal/snipdoc/README.md b/vendor/cloud.google.com/go/internal/snipdoc/README.md new file mode 100644 index 00000000..5d284296 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/snipdoc/README.md @@ -0,0 +1,29 @@ +# Snipdoc + +Snipdoc is a simple tool for maintaining package documentation that contains +code samples. + +1. Create a subdirectory of your package to hold the following files. "internal" + is a good name. + +2. Write a template file (for example, "doc.template") with the text of your package documentation. The file +should look exactly like you want your doc.go file to look, except for code +snippets. +Instead of embedding a code snippet, write a line consisting solely of + + [NAME] + + for your choice of NAME. + +3. Write a snippets file (for example, "doc-snippets.go") as a valid Go source + file. Begin each snippet you'd like to appear in your package docs with + `//[ NAME` and end it with `//]`. + +4. Construct your doc.go file with the command + ``` + awk -f snipdoc.awk doc-snippets.go doc.template + ``` + The file "sample-makefile" in this directory verifies that the + snippets file compiles and safely constructs a doc.go file. + + diff --git a/vendor/cloud.google.com/go/internal/snipdoc/sample-makefile b/vendor/cloud.google.com/go/internal/snipdoc/sample-makefile new file mode 100644 index 00000000..6769cb36 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/snipdoc/sample-makefile @@ -0,0 +1,16 @@ +# Build doc.go from template and snippets. + +SHELL=/bin/bash + +../doc.go: build doc-snippets.go doc.template snipdoc.awk + @tmp=$$(mktemp) && \ + awk -f snipdoc.awk doc-snippets.go doc.template > $$tmp && \ + chmod +w $@ && \ + mv $$tmp $@ && \ + chmod -w $@ + @echo "wrote $@" + +.PHONY: build + +build: + go build doc-snippets.go diff --git a/vendor/cloud.google.com/go/internal/snipdoc/snipdoc.awk b/vendor/cloud.google.com/go/internal/snipdoc/snipdoc.awk new file mode 100644 index 00000000..98e788eb --- /dev/null +++ b/vendor/cloud.google.com/go/internal/snipdoc/snipdoc.awk @@ -0,0 +1,116 @@ +# Copyright 2017 Google LLC +# +# 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. + +# snipdoc merges code snippets from Go source files into a template to +# produce another go file (typically doc.go). +# +# Call with one or more .go files and a template file. +# +# awk -f snipmd.awk foo.go bar.go doc.template +# +# In the Go files, start a snippet with +# //[ NAME +# and end it with +# //] +# +# In the template, write +# [NAME] +# on a line by itself to insert the snippet NAME on that line. +# +# The following transformations are made to the Go code: +# - Trailing blank lines are removed. +# - `ELLIPSIS` and `_ = ELLIPSIS` are replaced by `...` + + +/^[ \t]*\/\/\[/ { # start snippet in Go file + if (inGo()) { + if ($2 == "") { + die("missing snippet name") + } + curSnip = $2 + next + } +} + +/^[ \t]*\/\/]/ { # end snippet in Go file + if (inGo()) { + if (curSnip != "") { + # Remove all trailing newlines. + gsub(/[\t\n]+$/, "", snips[curSnip]) + curSnip = "" + next + } else { + die("//] without corresponding //[") + } + } +} + +ENDFILE { + if (curSnip != "") { + die("unclosed snippet: " curSnip) + } +} + +/^\[.*\]$/ { # Snippet marker in template file. + if (inTemplate()) { + name = substr($1, 2, length($1)-2) + if (snips[name] == "") { + die("no snippet named " name) + } + printf("%s\n", snips[name]) + afterSnip = 1 + next + } +} + +# Matches every line. +{ + if (curSnip != "") { + # If the first line in the snip has no indent, add the indent. + if (snips[curSnip] == "") { + if (index($0, "\t") == 1) { + extraIndent = "" + } else { + extraIndent = "\t" + } + } + + line = $0 + # Replace ELLIPSIS. + gsub(/_ = ELLIPSIS/, "...", line) + gsub(/ELLIPSIS/, "...", line) + + snips[curSnip] = snips[curSnip] extraIndent line "\n" + } else if (inTemplate()) { + afterSnip = 0 + # Copy to output. + print + } +} + + + +function inTemplate() { + return match(FILENAME, /\.template$/) +} + +function inGo() { + return match(FILENAME, /\.go$/) +} + + +function die(msg) { + printf("%s:%d: %s\n", FILENAME, FNR, msg) > "/dev/stderr" + exit 1 +} diff --git a/vendor/cloud.google.com/go/internal/testutil/cmp.go b/vendor/cloud.google.com/go/internal/testutil/cmp.go new file mode 100644 index 00000000..9dd3d911 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/testutil/cmp.go @@ -0,0 +1,61 @@ +// Copyright 2017 Google LLC +// +// 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 testutil + +import ( + "math" + "math/big" + + "github.com/golang/protobuf/proto" + "github.com/google/go-cmp/cmp" +) + +var ( + alwaysEqual = cmp.Comparer(func(_, _ interface{}) bool { return true }) + + defaultCmpOptions = []cmp.Option{ + // Use proto.Equal for protobufs + cmp.Comparer(proto.Equal), + // Use big.Rat.Cmp for big.Rats + cmp.Comparer(func(x, y *big.Rat) bool { + if x == nil || y == nil { + return x == y + } + return x.Cmp(y) == 0 + }), + // NaNs compare equal + cmp.FilterValues(func(x, y float64) bool { + return math.IsNaN(x) && math.IsNaN(y) + }, alwaysEqual), + cmp.FilterValues(func(x, y float32) bool { + return math.IsNaN(float64(x)) && math.IsNaN(float64(y)) + }, alwaysEqual), + } +) + +// Equal tests two values for equality. +func Equal(x, y interface{}, opts ...cmp.Option) bool { + // Put default options at the end. Order doesn't matter. + opts = append(opts[:len(opts):len(opts)], defaultCmpOptions...) + return cmp.Equal(x, y, opts...) +} + +// Diff reports the differences between two values. +// Diff(x, y) == "" iff Equal(x, y). +func Diff(x, y interface{}, opts ...cmp.Option) string { + // Put default options at the end. Order doesn't matter. + opts = append(opts[:len(opts):len(opts)], defaultCmpOptions...) + return cmp.Diff(x, y, opts...) +} diff --git a/vendor/cloud.google.com/go/internal/testutil/context.go b/vendor/cloud.google.com/go/internal/testutil/context.go new file mode 100644 index 00000000..93797fa4 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/testutil/context.go @@ -0,0 +1,106 @@ +// Copyright 2014 Google LLC +// +// 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 testutil contains helper functions for writing tests. +package testutil + +import ( + "context" + "fmt" + "io/ioutil" + "log" + "os" + + "golang.org/x/oauth2" + "golang.org/x/oauth2/google" + "golang.org/x/oauth2/jwt" +) + +const ( + envProjID = "GCLOUD_TESTS_GOLANG_PROJECT_ID" + envPrivateKey = "GCLOUD_TESTS_GOLANG_KEY" +) + +// ProjID returns the project ID to use in integration tests, or the empty +// string if none is configured. +func ProjID() string { + return os.Getenv(envProjID) +} + +// TokenSource returns the OAuth2 token source to use in integration tests, +// or nil if none is configured. It uses the standard environment variable +// for tests in this repo. +func TokenSource(ctx context.Context, scopes ...string) oauth2.TokenSource { + return TokenSourceEnv(ctx, envPrivateKey, scopes...) +} + +// TokenSourceEnv returns the OAuth2 token source to use in integration tests. or nil +// if none is configured. It tries to get credentials from the filename in the +// environment variable envVar. If the environment variable is unset, TokenSourceEnv +// will try to find 'Application Default Credentials'. Else, TokenSourceEnv will +// return nil. TokenSourceEnv will log.Fatal if the token source is specified but +// missing or invalid. +func TokenSourceEnv(ctx context.Context, envVar string, scopes ...string) oauth2.TokenSource { + key := os.Getenv(envVar) + if key == "" { // Try for application default credentials. + ts, err := google.DefaultTokenSource(ctx, scopes...) + if err != nil { + log.Println("No 'Application Default Credentials' found.") + return nil + } + return ts + } + conf, err := jwtConfigFromFile(key, scopes) + if err != nil { + log.Fatal(err) + } + return conf.TokenSource(ctx) +} + +// JWTConfig reads the JSON private key file whose name is in the default +// environment variable, and returns the jwt.Config it contains. It ignores +// scopes. +// If the environment variable is empty, it returns (nil, nil). +func JWTConfig() (*jwt.Config, error) { + return jwtConfigFromFile(os.Getenv(envPrivateKey), nil) +} + +// jwtConfigFromFile reads the given JSON private key file, and returns the +// jwt.Config it contains. +// If the filename is empty, it returns (nil, nil). +func jwtConfigFromFile(filename string, scopes []string) (*jwt.Config, error) { + if filename == "" { + return nil, nil + } + jsonKey, err := ioutil.ReadFile(filename) + if err != nil { + return nil, fmt.Errorf("Cannot read the JSON key file, err: %v", err) + } + conf, err := google.JWTConfigFromJSON(jsonKey, scopes...) + if err != nil { + return nil, fmt.Errorf("google.JWTConfigFromJSON: %v", err) + } + return conf, nil +} + +// CanReplay reports whether an integration test can be run in replay mode. +// The replay file must exist, and the GCLOUD_TESTS_GOLANG_ENABLE_REPLAY +// environment variable must be non-empty. +func CanReplay(replayFilename string) bool { + if os.Getenv("GCLOUD_TESTS_GOLANG_ENABLE_REPLAY") == "" { + return false + } + _, err := os.Stat(replayFilename) + return err == nil +} diff --git a/vendor/cloud.google.com/go/internal/testutil/rand.go b/vendor/cloud.google.com/go/internal/testutil/rand.go new file mode 100644 index 00000000..57d6c140 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/testutil/rand.go @@ -0,0 +1,44 @@ +// Copyright 2018 Google LLC +// +// 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 testutil + +import ( + "math/rand" + "sync" + "time" +) + +// NewRand creates a new *rand.Rand seeded with t. The return value is safe for use +// with multiple goroutines. +func NewRand(t time.Time) *rand.Rand { + s := &lockedSource{src: rand.NewSource(t.UnixNano())} + return rand.New(s) +} + +// lockedSource makes a rand.Source safe for use by multiple goroutines. +type lockedSource struct { + mu sync.Mutex + src rand.Source +} + +func (ls *lockedSource) Int63() int64 { + ls.mu.Lock() + defer ls.mu.Unlock() + return ls.src.Int63() +} + +func (ls *lockedSource) Seed(int64) { + panic("shouldn't be calling Seed") +} diff --git a/vendor/cloud.google.com/go/internal/testutil/server.go b/vendor/cloud.google.com/go/internal/testutil/server.go new file mode 100644 index 00000000..d8b8649e --- /dev/null +++ b/vendor/cloud.google.com/go/internal/testutil/server.go @@ -0,0 +1,135 @@ +/* +Copyright 2016 Google LLC + +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 testutil + +import ( + "fmt" + "log" + "net" + "regexp" + "strconv" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// A Server is an in-process gRPC server, listening on a system-chosen port on +// the local loopback interface. Servers are for testing only and are not +// intended to be used in production code. +// +// To create a server, make a new Server, register your handlers, then call +// Start: +// +// srv, err := NewServer() +// ... +// mypb.RegisterMyServiceServer(srv.Gsrv, &myHandler) +// .... +// srv.Start() +// +// Clients should connect to the server with no security: +// +// conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure()) +// ... +type Server struct { + Addr string + Port int + l net.Listener + Gsrv *grpc.Server +} + +// NewServer creates a new Server. The Server will be listening for gRPC connections +// at the address named by the Addr field, without TLS. +func NewServer(opts ...grpc.ServerOption) (*Server, error) { + return NewServerWithPort(0, opts...) +} + +// NewServerWithPort creates a new Server at a specific port. The Server will be listening +// for gRPC connections at the address named by the Addr field, without TLS. +func NewServerWithPort(port int, opts ...grpc.ServerOption) (*Server, error) { + l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) + if err != nil { + return nil, err + } + s := &Server{ + Addr: l.Addr().String(), + Port: parsePort(l.Addr().String()), + l: l, + Gsrv: grpc.NewServer(opts...), + } + return s, nil +} + +// Start causes the server to start accepting incoming connections. +// Call Start after registering handlers. +func (s *Server) Start() { + go func() { + if err := s.Gsrv.Serve(s.l); err != nil { + log.Printf("testutil.Server.Start: %v", err) + } + }() +} + +// Close shuts down the server. +func (s *Server) Close() { + s.Gsrv.Stop() + s.l.Close() +} + +// PageBounds converts an incoming page size and token from an RPC request into +// slice bounds and the outgoing next-page token. +// +// PageBounds assumes that the complete, unpaginated list of items exists as a +// single slice. In addition to the page size and token, PageBounds needs the +// length of that slice. +// +// PageBounds's first two return values should be used to construct a sub-slice of +// the complete, unpaginated slice. E.g. if the complete slice is s, then +// s[from:to] is the desired page. Its third return value should be set as the +// NextPageToken field of the RPC response. +func PageBounds(pageSize int, pageToken string, length int) (from, to int, nextPageToken string, err error) { + from, to = 0, length + if pageToken != "" { + from, err = strconv.Atoi(pageToken) + if err != nil { + return 0, 0, "", status.Errorf(codes.InvalidArgument, "bad page token: %v", err) + } + if from >= length { + return length, length, "", nil + } + } + if pageSize > 0 && from+pageSize < length { + to = from + pageSize + nextPageToken = strconv.Itoa(to) + } + return from, to, nextPageToken, nil +} + +var portParser = regexp.MustCompile(`:[0-9]+`) + +func parsePort(addr string) int { + res := portParser.FindAllString(addr, -1) + if len(res) == 0 { + panic(fmt.Errorf("parsePort: found no numbers in %s", addr)) + } + stringPort := res[0][1:] // strip the : + p, err := strconv.ParseInt(stringPort, 10, 32) + if err != nil { + panic(err) + } + return int(p) +} diff --git a/vendor/cloud.google.com/go/internal/testutil/server_test.go b/vendor/cloud.google.com/go/internal/testutil/server_test.go new file mode 100644 index 00000000..1bb4c276 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/testutil/server_test.go @@ -0,0 +1,79 @@ +// Copyright 2016 Google LLC +// +// 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 testutil + +import ( + "testing" + + grpc "google.golang.org/grpc" + "google.golang.org/grpc/codes" +) + +func TestNewServer(t *testing.T) { + srv, err := NewServer() + if err != nil { + t.Fatal(err) + } + defer srv.Close() + srv.Start() + conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure()) + if err != nil { + t.Fatal(err) + } + defer conn.Close() +} + +func TestPageBounds(t *testing.T) { + const length = 10 + for _, test := range []struct { + size int + tok string + wantFrom int + wantTo int + wantTok string + }{ + {5, "", + 0, 5, "5"}, + {11, "", + 0, 10, ""}, + {5, "2", + 2, 7, "7"}, + {5, "8", + 8, 10, ""}, + {11, "8", + 8, 10, ""}, + {1, "11", + 10, 10, ""}, + } { + gotFrom, gotTo, gotTok, err := PageBounds(test.size, test.tok, length) + if err != nil { + t.Fatal(err) + } + if got, want := gotFrom, test.wantFrom; got != want { + t.Errorf("%+v: from: got %d, want %d", test, got, want) + } + if got, want := gotTo, test.wantTo; got != want { + t.Errorf("%+v: to: got %d, want %d", test, got, want) + } + if got, want := gotTok, test.wantTok; got != want { + t.Errorf("%+v: got %q, want %q", test, got, want) + } + } + + _, _, _, err := PageBounds(4, "xyz", 5) + if grpc.Code(err) != codes.InvalidArgument { + t.Errorf("want invalid argument, got <%v>", err) + } +} diff --git a/vendor/cloud.google.com/go/internal/testutil/trace.go b/vendor/cloud.google.com/go/internal/testutil/trace.go new file mode 100644 index 00000000..b0a7b775 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/testutil/trace.go @@ -0,0 +1,68 @@ +// Copyright 2018 Google LLC +// +// 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 testutil + +import ( + "log" + "time" + + "go.opencensus.io/plugin/ocgrpc" + "go.opencensus.io/stats/view" + "go.opencensus.io/trace" +) + +// TestExporter is a test utility exporter. It should be created with NewtestExporter. +type TestExporter struct { + Spans []*trace.SpanData + Stats chan *view.Data +} + +// NewTestExporter creates a TestExporter and registers it with OpenCensus. +func NewTestExporter() *TestExporter { + te := &TestExporter{Stats: make(chan *view.Data)} + + view.RegisterExporter(te) + view.SetReportingPeriod(time.Millisecond) + if err := view.Register(ocgrpc.DefaultClientViews...); err != nil { + log.Fatal(err) + } + + trace.RegisterExporter(te) + trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) + + return te +} + +// ExportSpan exports a span. +func (te *TestExporter) ExportSpan(s *trace.SpanData) { + te.Spans = append(te.Spans, s) +} + +// ExportView exports a view. +func (te *TestExporter) ExportView(vd *view.Data) { + if len(vd.Rows) > 0 { + select { + case te.Stats <- vd: + default: + } + } +} + +// Unregister unregisters the exporter from OpenCensus. +func (te *TestExporter) Unregister() { + view.UnregisterExporter(te) + trace.UnregisterExporter(te) + view.SetReportingPeriod(0) // reset to default value +} diff --git a/vendor/cloud.google.com/go/internal/trace/trace.go b/vendor/cloud.google.com/go/internal/trace/trace.go new file mode 100644 index 00000000..95c7821c --- /dev/null +++ b/vendor/cloud.google.com/go/internal/trace/trace.go @@ -0,0 +1,84 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace + +import ( + "context" + + "go.opencensus.io/trace" + "google.golang.org/api/googleapi" + "google.golang.org/genproto/googleapis/rpc/code" + "google.golang.org/grpc/status" +) + +// StartSpan adds a span to the trace with the given name. +func StartSpan(ctx context.Context, name string) context.Context { + ctx, _ = trace.StartSpan(ctx, name) + return ctx +} + +// EndSpan ends a span with the given error. +func EndSpan(ctx context.Context, err error) { + span := trace.FromContext(ctx) + if err != nil { + span.SetStatus(toStatus(err)) + } + span.End() +} + +// ToStatus interrogates an error and converts it to an appropriate +// OpenCensus status. +func toStatus(err error) trace.Status { + if err2, ok := err.(*googleapi.Error); ok { + return trace.Status{Code: httpStatusCodeToOCCode(err2.Code), Message: err2.Message} + } else if s, ok := status.FromError(err); ok { + return trace.Status{Code: int32(s.Code()), Message: s.Message()} + } else { + return trace.Status{Code: int32(code.Code_UNKNOWN), Message: err.Error()} + } +} + +// TODO (deklerk): switch to using OpenCensus function when it becomes available. +// Reference: https://github.com/googleapis/googleapis/blob/26b634d2724ac5dd30ae0b0cbfb01f07f2e4050e/google/rpc/code.proto +func httpStatusCodeToOCCode(httpStatusCode int) int32 { + switch httpStatusCode { + case 200: + return int32(code.Code_OK) + case 499: + return int32(code.Code_CANCELLED) + case 500: + return int32(code.Code_UNKNOWN) // Could also be Code_INTERNAL, Code_DATA_LOSS + case 400: + return int32(code.Code_INVALID_ARGUMENT) // Could also be Code_OUT_OF_RANGE + case 504: + return int32(code.Code_DEADLINE_EXCEEDED) + case 404: + return int32(code.Code_NOT_FOUND) + case 409: + return int32(code.Code_ALREADY_EXISTS) // Could also be Code_ABORTED + case 403: + return int32(code.Code_PERMISSION_DENIED) + case 401: + return int32(code.Code_UNAUTHENTICATED) + case 429: + return int32(code.Code_RESOURCE_EXHAUSTED) + case 501: + return int32(code.Code_UNIMPLEMENTED) + case 503: + return int32(code.Code_UNAVAILABLE) + default: + return int32(code.Code_UNKNOWN) + } +} diff --git a/vendor/cloud.google.com/go/internal/trace/trace_test.go b/vendor/cloud.google.com/go/internal/trace/trace_test.go new file mode 100644 index 00000000..2af9fb8b --- /dev/null +++ b/vendor/cloud.google.com/go/internal/trace/trace_test.go @@ -0,0 +1,53 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace + +import ( + "errors" + "net/http" + "testing" + + "cloud.google.com/go/internal/testutil" + octrace "go.opencensus.io/trace" + "google.golang.org/api/googleapi" + "google.golang.org/genproto/googleapis/rpc/code" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestToStatus(t *testing.T) { + for _, testcase := range []struct { + input error + want octrace.Status + }{ + { + errors.New("some random error"), + octrace.Status{Code: int32(code.Code_UNKNOWN), Message: "some random error"}, + }, + { + &googleapi.Error{Code: http.StatusConflict, Message: "some specific googleapi http error"}, + octrace.Status{Code: int32(code.Code_ALREADY_EXISTS), Message: "some specific googleapi http error"}, + }, + { + status.Error(codes.DataLoss, "some specific grpc error"), + octrace.Status{Code: int32(code.Code_DATA_LOSS), Message: "some specific grpc error"}, + }, + } { + got := toStatus(testcase.input) + if r := testutil.Diff(got, testcase.want); r != "" { + t.Errorf("got -, want +:\n%s", r) + } + } +} diff --git a/vendor/cloud.google.com/go/internal/tracecontext/tracecontext.go b/vendor/cloud.google.com/go/internal/tracecontext/tracecontext.go new file mode 100644 index 00000000..827ace2e --- /dev/null +++ b/vendor/cloud.google.com/go/internal/tracecontext/tracecontext.go @@ -0,0 +1,83 @@ +// Copyright 2017 Google LLC +// +// 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 tracecontext provides encoders and decoders for Stackdriver Trace contexts. +package tracecontext + +import "encoding/binary" + +const ( + versionID = 0 + traceIDField = 0 + spanIDField = 1 + optsField = 2 + + traceIDLen = 16 + spanIDLen = 8 + optsLen = 1 + + // Len represents the length of trace context. + Len = 1 + 1 + traceIDLen + 1 + spanIDLen + 1 + optsLen +) + +// Encode encodes trace ID, span ID and options into dst. The number of bytes +// written will be returned. If len(dst) isn't big enough to fit the trace context, +// a negative number is returned. +func Encode(dst []byte, traceID []byte, spanID uint64, opts byte) (n int) { + if len(dst) < Len { + return -1 + } + var offset = 0 + putByte := func(b byte) { dst[offset] = b; offset++ } + putUint64 := func(u uint64) { binary.LittleEndian.PutUint64(dst[offset:], u); offset += 8 } + + putByte(versionID) + putByte(traceIDField) + for _, b := range traceID { + putByte(b) + } + putByte(spanIDField) + putUint64(spanID) + putByte(optsField) + putByte(opts) + + return offset +} + +// Decode decodes the src into a trace ID, span ID and options. If src doesn't +// contain a valid trace context, ok = false is returned. +func Decode(src []byte) (traceID []byte, spanID uint64, opts byte, ok bool) { + if len(src) < Len { + return traceID, spanID, 0, false + } + var offset = 0 + readByte := func() byte { b := src[offset]; offset++; return b } + readUint64 := func() uint64 { v := binary.LittleEndian.Uint64(src[offset:]); offset += 8; return v } + + if readByte() != versionID { + return traceID, spanID, 0, false + } + for offset < len(src) { + switch readByte() { + case traceIDField: + traceID = src[offset : offset+traceIDLen] + offset += traceIDLen + case spanIDField: + spanID = readUint64() + case optsField: + opts = readByte() + } + } + return traceID, spanID, opts, true +} diff --git a/vendor/cloud.google.com/go/internal/tracecontext/tracecontext_test.go b/vendor/cloud.google.com/go/internal/tracecontext/tracecontext_test.go new file mode 100644 index 00000000..60c27b55 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/tracecontext/tracecontext_test.go @@ -0,0 +1,136 @@ +// Copyright 2014 Google LLC +// +// 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 tracecontext + +import ( + "testing" + + "cloud.google.com/go/internal/testutil" +) + +var validData = []byte{0, 0, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 1, 97, 98, 99, 100, 101, 102, 103, 104, 2, 1} + +func TestDecode(t *testing.T) { + tests := []struct { + name string + data []byte + wantTraceID []byte + wantSpanID uint64 + wantOpts byte + wantOk bool + }{ + { + name: "nil data", + data: nil, + wantTraceID: nil, + wantSpanID: 0, + wantOpts: 0, + wantOk: false, + }, + { + name: "short data", + data: []byte{0, 0, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77}, + wantTraceID: nil, + wantSpanID: 0, + wantOpts: 0, + wantOk: false, + }, + { + name: "wrong field number", + data: []byte{0, 1, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77}, + wantTraceID: nil, + wantSpanID: 0, + wantOpts: 0, + wantOk: false, + }, + { + name: "valid data", + data: validData, + wantTraceID: []byte{64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79}, + wantSpanID: 0x6867666564636261, + wantOpts: 1, + wantOk: true, + }, + } + for _, tt := range tests { + gotTraceID, gotSpanID, gotOpts, gotOk := Decode(tt.data) + if !testutil.Equal(gotTraceID, tt.wantTraceID) { + t.Errorf("%s: Decode() gotTraceID = %v, want %v", tt.name, gotTraceID, tt.wantTraceID) + } + if gotSpanID != tt.wantSpanID { + t.Errorf("%s: Decode() gotSpanID = %v, want %v", tt.name, gotSpanID, tt.wantSpanID) + } + if gotOpts != tt.wantOpts { + t.Errorf("%s: Decode() gotOpts = %v, want %v", tt.name, gotOpts, tt.wantOpts) + } + if gotOk != tt.wantOk { + t.Errorf("%s: Decode() gotOk = %v, want %v", tt.name, gotOk, tt.wantOk) + } + } +} + +func TestEncode(t *testing.T) { + tests := []struct { + name string + dst []byte + traceID []byte + spanID uint64 + opts byte + wantN int + wantData []byte + }{ + { + name: "short data", + dst: make([]byte, 0), + traceID: []byte("00112233445566"), + spanID: 0x6867666564636261, + opts: 1, + wantN: -1, + wantData: make([]byte, 0), + }, + { + name: "valid data", + dst: make([]byte, Len), + traceID: []byte{64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79}, + spanID: 0x6867666564636261, + opts: 1, + wantN: Len, + wantData: validData, + }, + } + for _, tt := range tests { + gotN := Encode(tt.dst, tt.traceID, tt.spanID, tt.opts) + if gotN != tt.wantN { + t.Errorf("%s: n = %v, want %v", tt.name, gotN, tt.wantN) + } + if gotData := tt.dst; !testutil.Equal(gotData, tt.wantData) { + t.Errorf("%s: dst = %v, want %v", tt.name, gotData, tt.wantData) + } + } +} + +func BenchmarkDecode(b *testing.B) { + for i := 0; i < b.N; i++ { + Decode(validData) + } +} + +func BenchmarkEncode(b *testing.B) { + for i := 0; i < b.N; i++ { + traceID := make([]byte, 16) + var opts byte + Encode(validData, traceID, 0, opts) + } +} diff --git a/vendor/cloud.google.com/go/internal/uid/uid.go b/vendor/cloud.google.com/go/internal/uid/uid.go new file mode 100644 index 00000000..2f229d64 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/uid/uid.go @@ -0,0 +1,149 @@ +// Copyright 2017 Google LLC +// +// 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 uid supports generating unique IDs. Its chief purpose is to prevent +// multiple test executions from interfering with each other, and to facilitate +// cleanup of old entities that may remain if tests exit early. +package uid + +import ( + "fmt" + "regexp" + "strconv" + "sync/atomic" + "time" +) + +// A Space manages a set of unique IDs distinguished by a prefix. +type Space struct { + Prefix string // Prefix of UIDs. Read-only. + Sep rune // Separates UID parts. Read-only. + Time time.Time // Timestamp for UIDs. Read-only. + re *regexp.Regexp + count int32 // atomic + short bool +} + +// Options are optional values for a Space. +type Options struct { + Sep rune // Separates parts of the UID. Defaults to '-'. + Time time.Time // Timestamp for all UIDs made with this space. Defaults to current time. + + // Short, if true, makes the result of space.New shorter by 6 characters. + // This can be useful for character restricted IDs. It will use a shorter + // but less readable time representation, and will only use two characters + // for the count suffix instead of four. + // + // e.x. normal: gotest-20181030-59751273685000-0001 + // e.x. short: gotest-1540917351273685000-01 + Short bool +} + +// NewSpace creates a new UID space. A UID Space is used to generate unique IDs. +func NewSpace(prefix string, opts *Options) *Space { + var short bool + sep := '-' + tm := time.Now().UTC() + if opts != nil { + short = opts.Short + if opts.Sep != 0 { + sep = opts.Sep + } + if !opts.Time.IsZero() { + tm = opts.Time + } + } + var re string + + if short { + re = fmt.Sprintf(`^%s%[2]c(\d+)%[2]c\d+$`, regexp.QuoteMeta(prefix), sep) + } else { + re = fmt.Sprintf(`^%s%[2]c(\d{4})(\d{2})(\d{2})%[2]c(\d+)%[2]c\d+$`, + regexp.QuoteMeta(prefix), sep) + } + + return &Space{ + Prefix: prefix, + Sep: sep, + Time: tm, + re: regexp.MustCompile(re), + short: short, + } +} + +// New generates a new unique ID. The ID consists of the Space's prefix, a +// timestamp, and a counter value. All unique IDs generated in the same test +// execution will have the same timestamp. +// +// Aside from the characters in the prefix, IDs contain only letters, numbers +// and sep. +func (s *Space) New() string { + c := atomic.AddInt32(&s.count, 1) + + if s.short && c > 99 { + // Short spaces only have space for 99 IDs. (two characters) + panic("Short space called New more than 99 times. Ran out of IDs.") + } else if c > 9999 { + // Spaces only have space for 9999 IDs. (four characters) + panic("New called more than 9999 times. Ran out of IDs.") + } + + if s.short { + return fmt.Sprintf("%s%c%d%c%02d", s.Prefix, s.Sep, s.Time.UnixNano(), s.Sep, c) + } + + // Write the time as a date followed by nanoseconds from midnight of that date. + // That makes it easier to see the approximate time of the ID when it is displayed. + y, m, d := s.Time.Date() + ns := s.Time.Sub(time.Date(y, m, d, 0, 0, 0, 0, time.UTC)) + // Zero-pad the counter for lexical sort order for IDs with the same timestamp. + return fmt.Sprintf("%s%c%04d%02d%02d%c%d%c%04d", + s.Prefix, s.Sep, y, m, d, s.Sep, ns, s.Sep, c) +} + +// Timestamp extracts the timestamp of uid, which must have been generated by +// s. The second return value is true on success, false if there was a problem. +func (s *Space) Timestamp(uid string) (time.Time, bool) { + subs := s.re.FindStringSubmatch(uid) + if subs == nil { + return time.Time{}, false + } + + if s.short { + ns, err := strconv.ParseInt(subs[1], 10, 64) + if err != nil { + return time.Time{}, false + } + return time.Unix(ns/1e9, ns%1e9), true + } + + y, err1 := strconv.Atoi(subs[1]) + m, err2 := strconv.Atoi(subs[2]) + d, err3 := strconv.Atoi(subs[3]) + ns, err4 := strconv.Atoi(subs[4]) + if err1 != nil || err2 != nil || err3 != nil || err4 != nil { + return time.Time{}, false + } + return time.Date(y, time.Month(m), d, 0, 0, 0, ns, time.UTC), true +} + +// Older reports whether uid was created by m and has a timestamp older than +// the current time by at least d. +func (s *Space) Older(uid string, d time.Duration) bool { + ts, ok := s.Timestamp(uid) + if !ok { + return false + } + return time.Since(ts) > d +} diff --git a/vendor/cloud.google.com/go/internal/uid/uid_test.go b/vendor/cloud.google.com/go/internal/uid/uid_test.go new file mode 100644 index 00000000..5a4a85a5 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/uid/uid_test.go @@ -0,0 +1,88 @@ +// Copyright 2017 Google LLC +// +// 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 uid + +import ( + "fmt" + "testing" + "time" +) + +func TestNew(t *testing.T) { + tm := time.Date(2017, 1, 6, 0, 0, 0, 21, time.UTC) + s := NewSpace("prefix", &Options{Time: tm}) + got := s.New() + want := "prefix-20170106-21-0001" + if got != want { + t.Errorf("got %q, want %q", got, want) + } + + s2 := NewSpace("prefix2", &Options{Sep: '_', Time: tm}) + got = s2.New() + want = "prefix2_20170106_21_0001" + if got != want { + t.Errorf("got %q, want %q", got, want) + } +} + +func TestTimestamp(t *testing.T) { + s := NewSpace("unique-ID", nil) + startTime := s.Time + uid := s.New() + got, ok := s.Timestamp(uid) + if !ok { + t.Fatal("got ok = false, want true") + } + if !startTime.Equal(got) { + t.Errorf("got %s, want %s", got, startTime) + } + + got, ok = s.Timestamp("unique-ID-20160308-123-8") + if !ok { + t.Fatal("got false, want true") + } + if want := time.Date(2016, 3, 8, 0, 0, 0, 123, time.UTC); !want.Equal(got) { + t.Errorf("got %s, want %s", got, want) + } + if _, ok = s.Timestamp("invalid-time-1234"); ok { + t.Error("got true, want false") + } +} + +func TestOlder(t *testing.T) { + s := NewSpace("uid", nil) + // A non-matching ID returns false. + id2 := NewSpace("different-prefix", nil).New() + if got, want := s.Older(id2, time.Second), false; got != want { + t.Errorf("got %t, want %t", got, want) + } +} + +func TestShorter(t *testing.T) { + now := time.Now() + shortSpace := NewSpace("uid", &Options{Short: true, Time: now}) + shortUID := shortSpace.New() + + want := fmt.Sprintf("uid-%d-01", now.UnixNano()) + if shortUID != want { + t.Fatalf("expected %s, got %s", want, shortUID) + } + + if got, ok := shortSpace.Timestamp(shortUID); !ok { + t.Fatal("expected to be able to parse timestamp from short space, but was unable to") + } else if got.UnixNano() != now.UnixNano() { + t.Fatalf("expected to get %v, got %v", now, got) + } +} diff --git a/vendor/cloud.google.com/go/internal/version/update_version.sh b/vendor/cloud.google.com/go/internal/version/update_version.sh new file mode 100755 index 00000000..fecf1f03 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/version/update_version.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +today=$(date +%Y%m%d) + +sed -i -r -e 's/const Repo = "([0-9]{8})"/const Repo = "'$today'"/' $GOFILE + diff --git a/vendor/cloud.google.com/go/internal/version/version.go b/vendor/cloud.google.com/go/internal/version/version.go new file mode 100644 index 00000000..220f02c1 --- /dev/null +++ b/vendor/cloud.google.com/go/internal/version/version.go @@ -0,0 +1,71 @@ +// Copyright 2016 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:generate ./update_version.sh + +// Package version contains version information for Google Cloud Client +// Libraries for Go, as reported in request headers. +package version + +import ( + "runtime" + "strings" + "unicode" +) + +// Repo is the current version of the client libraries in this +// repo. It should be a date in YYYYMMDD format. +const Repo = "20180226" + +// Go returns the Go runtime version. The returned string +// has no whitespace. +func Go() string { + return goVersion +} + +var goVersion = goVer(runtime.Version()) + +const develPrefix = "devel +" + +func goVer(s string) string { + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "" +} + +func notSemverRune(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 +} diff --git a/vendor/cloud.google.com/go/internal/version/version_test.go b/vendor/cloud.google.com/go/internal/version/version_test.go new file mode 100644 index 00000000..6253db8f --- /dev/null +++ b/vendor/cloud.google.com/go/internal/version/version_test.go @@ -0,0 +1,35 @@ +// Copyright 2016 Google LLC +// +// 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 version + +import "testing" + +func TestGoVer(t *testing.T) { + for _, tst := range []struct { + in, want string + }{ + {"go1.8", "1.8.0"}, + {"go1.7.3", "1.7.3"}, + {"go1.8.typealias", "1.8.0-typealias"}, + {"go1.8beta1", "1.8.0-beta1"}, + {"go1.8rc2", "1.8.0-rc2"}, + {"devel +824f981dd4b7 Tue Apr 29 21:41:54 2014 -0400", "824f981dd4b7"}, + {"foo bar zipzap", ""}, + } { + if got := goVer(tst.in); got != tst.want { + t.Errorf("goVer(%q) = %q, want %q", tst.in, got, tst.want) + } + } +} diff --git a/vendor/cloud.google.com/go/issue_template.md b/vendor/cloud.google.com/go/issue_template.md new file mode 100644 index 00000000..e2ccef3e --- /dev/null +++ b/vendor/cloud.google.com/go/issue_template.md @@ -0,0 +1,17 @@ +(delete this for feature requests) + +## Client + +e.g. PubSub + +## Describe Your Environment + +e.g. Alpine Docker on GKE + +## Expected Behavior + +e.g. Messages arrive really fast. + +## Actual Behavior + +e.g. Messages arrive really slowly. \ No newline at end of file diff --git a/vendor/cloud.google.com/go/keys.tar.enc b/vendor/cloud.google.com/go/keys.tar.enc new file mode 100644 index 00000000..c54408c9 Binary files /dev/null and b/vendor/cloud.google.com/go/keys.tar.enc differ diff --git a/vendor/cloud.google.com/go/kms/apiv1/doc.go b/vendor/cloud.google.com/go/kms/apiv1/doc.go new file mode 100644 index 00000000..2769e7f5 --- /dev/null +++ b/vendor/cloud.google.com/go/kms/apiv1/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package kms is an auto-generated package for the +// Cloud Key Management Service (KMS) API. + +// +// Manages keys and performs cryptographic operations in a central cloud +// service, for direct use by other cloud resources and applications. +package kms // import "cloud.google.com/go/kms/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/kms/apiv1/iam.go b/vendor/cloud.google.com/go/kms/apiv1/iam.go new file mode 100644 index 00000000..8c572a98 --- /dev/null +++ b/vendor/cloud.google.com/go/kms/apiv1/iam.go @@ -0,0 +1,30 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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 kms + +import ( + "cloud.google.com/go/iam" + kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1" +) + +// KeyRingIAM returns a handle to inspect and change permissions of a KeyRing. +func (c *KeyManagementClient) KeyRingIAM(keyRing *kmspb.KeyRing) *iam.Handle { + return iam.InternalNewHandle(c.Connection(), keyRing.Name) +} + +// CryptoKeyIAM returns a handle to inspect and change permissions of a CryptoKey. +func (c *KeyManagementClient) CryptoKeyIAM(cryptoKey *kmspb.CryptoKey) *iam.Handle { + return iam.InternalNewHandle(c.Connection(), cryptoKey.Name) +} diff --git a/vendor/cloud.google.com/go/kms/apiv1/key_management_client.go b/vendor/cloud.google.com/go/kms/apiv1/key_management_client.go new file mode 100644 index 00000000..a7a8b9e8 --- /dev/null +++ b/vendor/cloud.google.com/go/kms/apiv1/key_management_client.go @@ -0,0 +1,725 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package kms + +import ( + "context" + "fmt" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// KeyManagementCallOptions contains the retry settings for each method of KeyManagementClient. +type KeyManagementCallOptions struct { + ListKeyRings []gax.CallOption + ListCryptoKeys []gax.CallOption + ListCryptoKeyVersions []gax.CallOption + GetKeyRing []gax.CallOption + GetCryptoKey []gax.CallOption + GetCryptoKeyVersion []gax.CallOption + CreateKeyRing []gax.CallOption + CreateCryptoKey []gax.CallOption + CreateCryptoKeyVersion []gax.CallOption + UpdateCryptoKey []gax.CallOption + UpdateCryptoKeyVersion []gax.CallOption + Encrypt []gax.CallOption + Decrypt []gax.CallOption + UpdateCryptoKeyPrimaryVersion []gax.CallOption + DestroyCryptoKeyVersion []gax.CallOption + RestoreCryptoKeyVersion []gax.CallOption + GetPublicKey []gax.CallOption + AsymmetricDecrypt []gax.CallOption + AsymmetricSign []gax.CallOption +} + +func defaultKeyManagementClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("cloudkms.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultKeyManagementCallOptions() *KeyManagementCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &KeyManagementCallOptions{ + ListKeyRings: retry[[2]string{"default", "idempotent"}], + ListCryptoKeys: retry[[2]string{"default", "idempotent"}], + ListCryptoKeyVersions: retry[[2]string{"default", "idempotent"}], + GetKeyRing: retry[[2]string{"default", "idempotent"}], + GetCryptoKey: retry[[2]string{"default", "idempotent"}], + GetCryptoKeyVersion: retry[[2]string{"default", "idempotent"}], + CreateKeyRing: retry[[2]string{"default", "non_idempotent"}], + CreateCryptoKey: retry[[2]string{"default", "non_idempotent"}], + CreateCryptoKeyVersion: retry[[2]string{"default", "non_idempotent"}], + UpdateCryptoKey: retry[[2]string{"default", "non_idempotent"}], + UpdateCryptoKeyVersion: retry[[2]string{"default", "non_idempotent"}], + Encrypt: retry[[2]string{"default", "non_idempotent"}], + Decrypt: retry[[2]string{"default", "non_idempotent"}], + UpdateCryptoKeyPrimaryVersion: retry[[2]string{"default", "non_idempotent"}], + DestroyCryptoKeyVersion: retry[[2]string{"default", "non_idempotent"}], + RestoreCryptoKeyVersion: retry[[2]string{"default", "non_idempotent"}], + GetPublicKey: retry[[2]string{"default", "idempotent"}], + AsymmetricDecrypt: retry[[2]string{"default", "non_idempotent"}], + AsymmetricSign: retry[[2]string{"default", "non_idempotent"}], + } +} + +// KeyManagementClient is a client for interacting with Cloud Key Management Service (KMS) API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type KeyManagementClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + keyManagementClient kmspb.KeyManagementServiceClient + + // The call options for this service. + CallOptions *KeyManagementCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewKeyManagementClient creates a new key management service client. +// +// Google Cloud Key Management Service +// +// Manages cryptographic keys and operations using those keys. Implements a REST +// model with the following objects: +// +// [KeyRing][google.cloud.kms.v1.KeyRing] +// +// [CryptoKey][google.cloud.kms.v1.CryptoKey] +// +// [CryptoKeyVersion][google.cloud.kms.v1.CryptoKeyVersion] +// +// If you are using manual gRPC libraries, see +// Using gRPC with Cloud KMS (at https://cloud.google.com/kms/docs/grpc). +func NewKeyManagementClient(ctx context.Context, opts ...option.ClientOption) (*KeyManagementClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultKeyManagementClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &KeyManagementClient{ + conn: conn, + CallOptions: defaultKeyManagementCallOptions(), + + keyManagementClient: kmspb.NewKeyManagementServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *KeyManagementClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *KeyManagementClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *KeyManagementClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListKeyRings lists [KeyRings][google.cloud.kms.v1.KeyRing]. +func (c *KeyManagementClient) ListKeyRings(ctx context.Context, req *kmspb.ListKeyRingsRequest, opts ...gax.CallOption) *KeyRingIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ListKeyRings[0:len(c.CallOptions.ListKeyRings):len(c.CallOptions.ListKeyRings)], opts...) + it := &KeyRingIterator{} + req = proto.Clone(req).(*kmspb.ListKeyRingsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*kmspb.KeyRing, string, error) { + var resp *kmspb.ListKeyRingsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.ListKeyRings(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.KeyRings, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// ListCryptoKeys lists [CryptoKeys][google.cloud.kms.v1.CryptoKey]. +func (c *KeyManagementClient) ListCryptoKeys(ctx context.Context, req *kmspb.ListCryptoKeysRequest, opts ...gax.CallOption) *CryptoKeyIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ListCryptoKeys[0:len(c.CallOptions.ListCryptoKeys):len(c.CallOptions.ListCryptoKeys)], opts...) + it := &CryptoKeyIterator{} + req = proto.Clone(req).(*kmspb.ListCryptoKeysRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*kmspb.CryptoKey, string, error) { + var resp *kmspb.ListCryptoKeysResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.ListCryptoKeys(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.CryptoKeys, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// ListCryptoKeyVersions lists [CryptoKeyVersions][google.cloud.kms.v1.CryptoKeyVersion]. +func (c *KeyManagementClient) ListCryptoKeyVersions(ctx context.Context, req *kmspb.ListCryptoKeyVersionsRequest, opts ...gax.CallOption) *CryptoKeyVersionIterator { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.ListCryptoKeyVersions[0:len(c.CallOptions.ListCryptoKeyVersions):len(c.CallOptions.ListCryptoKeyVersions)], opts...) + it := &CryptoKeyVersionIterator{} + req = proto.Clone(req).(*kmspb.ListCryptoKeyVersionsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*kmspb.CryptoKeyVersion, string, error) { + var resp *kmspb.ListCryptoKeyVersionsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.ListCryptoKeyVersions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.CryptoKeyVersions, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetKeyRing returns metadata for a given [KeyRing][google.cloud.kms.v1.KeyRing]. +func (c *KeyManagementClient) GetKeyRing(ctx context.Context, req *kmspb.GetKeyRingRequest, opts ...gax.CallOption) (*kmspb.KeyRing, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.GetKeyRing[0:len(c.CallOptions.GetKeyRing):len(c.CallOptions.GetKeyRing)], opts...) + var resp *kmspb.KeyRing + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.GetKeyRing(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetCryptoKey returns metadata for a given [CryptoKey][google.cloud.kms.v1.CryptoKey], as well as its +// [primary][google.cloud.kms.v1.CryptoKey.primary] [CryptoKeyVersion][google.cloud.kms.v1.CryptoKeyVersion]. +func (c *KeyManagementClient) GetCryptoKey(ctx context.Context, req *kmspb.GetCryptoKeyRequest, opts ...gax.CallOption) (*kmspb.CryptoKey, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.GetCryptoKey[0:len(c.CallOptions.GetCryptoKey):len(c.CallOptions.GetCryptoKey)], opts...) + var resp *kmspb.CryptoKey + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.GetCryptoKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetCryptoKeyVersion returns metadata for a given [CryptoKeyVersion][google.cloud.kms.v1.CryptoKeyVersion]. +func (c *KeyManagementClient) GetCryptoKeyVersion(ctx context.Context, req *kmspb.GetCryptoKeyVersionRequest, opts ...gax.CallOption) (*kmspb.CryptoKeyVersion, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.GetCryptoKeyVersion[0:len(c.CallOptions.GetCryptoKeyVersion):len(c.CallOptions.GetCryptoKeyVersion)], opts...) + var resp *kmspb.CryptoKeyVersion + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.GetCryptoKeyVersion(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateKeyRing create a new [KeyRing][google.cloud.kms.v1.KeyRing] in a given Project and Location. +func (c *KeyManagementClient) CreateKeyRing(ctx context.Context, req *kmspb.CreateKeyRingRequest, opts ...gax.CallOption) (*kmspb.KeyRing, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.CreateKeyRing[0:len(c.CallOptions.CreateKeyRing):len(c.CallOptions.CreateKeyRing)], opts...) + var resp *kmspb.KeyRing + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.CreateKeyRing(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateCryptoKey create a new [CryptoKey][google.cloud.kms.v1.CryptoKey] within a [KeyRing][google.cloud.kms.v1.KeyRing]. +// +// [CryptoKey.purpose][google.cloud.kms.v1.CryptoKey.purpose] and +// [CryptoKey.version_template.algorithm][google.cloud.kms.v1.CryptoKeyVersionTemplate.algorithm] +// are required. +func (c *KeyManagementClient) CreateCryptoKey(ctx context.Context, req *kmspb.CreateCryptoKeyRequest, opts ...gax.CallOption) (*kmspb.CryptoKey, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.CreateCryptoKey[0:len(c.CallOptions.CreateCryptoKey):len(c.CallOptions.CreateCryptoKey)], opts...) + var resp *kmspb.CryptoKey + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.CreateCryptoKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateCryptoKeyVersion create a new [CryptoKeyVersion][google.cloud.kms.v1.CryptoKeyVersion] in a [CryptoKey][google.cloud.kms.v1.CryptoKey]. +// +// The server will assign the next sequential id. If unset, +// [state][google.cloud.kms.v1.CryptoKeyVersion.state] will be set to +// [ENABLED][google.cloud.kms.v1.CryptoKeyVersion.CryptoKeyVersionState.ENABLED]. +func (c *KeyManagementClient) CreateCryptoKeyVersion(ctx context.Context, req *kmspb.CreateCryptoKeyVersionRequest, opts ...gax.CallOption) (*kmspb.CryptoKeyVersion, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", req.GetParent())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.CreateCryptoKeyVersion[0:len(c.CallOptions.CreateCryptoKeyVersion):len(c.CallOptions.CreateCryptoKeyVersion)], opts...) + var resp *kmspb.CryptoKeyVersion + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.CreateCryptoKeyVersion(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateCryptoKey update a [CryptoKey][google.cloud.kms.v1.CryptoKey]. +func (c *KeyManagementClient) UpdateCryptoKey(ctx context.Context, req *kmspb.UpdateCryptoKeyRequest, opts ...gax.CallOption) (*kmspb.CryptoKey, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "crypto_key.name", req.GetCryptoKey().GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.UpdateCryptoKey[0:len(c.CallOptions.UpdateCryptoKey):len(c.CallOptions.UpdateCryptoKey)], opts...) + var resp *kmspb.CryptoKey + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.UpdateCryptoKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateCryptoKeyVersion update a [CryptoKeyVersion][google.cloud.kms.v1.CryptoKeyVersion]'s metadata. +// +// [state][google.cloud.kms.v1.CryptoKeyVersion.state] may be changed between +// [ENABLED][google.cloud.kms.v1.CryptoKeyVersion.CryptoKeyVersionState.ENABLED] and +// [DISABLED][google.cloud.kms.v1.CryptoKeyVersion.CryptoKeyVersionState.DISABLED] using this +// method. See [DestroyCryptoKeyVersion][google.cloud.kms.v1.KeyManagementService.DestroyCryptoKeyVersion] and [RestoreCryptoKeyVersion][google.cloud.kms.v1.KeyManagementService.RestoreCryptoKeyVersion] to +// move between other states. +func (c *KeyManagementClient) UpdateCryptoKeyVersion(ctx context.Context, req *kmspb.UpdateCryptoKeyVersionRequest, opts ...gax.CallOption) (*kmspb.CryptoKeyVersion, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "crypto_key_version.name", req.GetCryptoKeyVersion().GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.UpdateCryptoKeyVersion[0:len(c.CallOptions.UpdateCryptoKeyVersion):len(c.CallOptions.UpdateCryptoKeyVersion)], opts...) + var resp *kmspb.CryptoKeyVersion + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.UpdateCryptoKeyVersion(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Encrypt encrypts data, so that it can only be recovered by a call to [Decrypt][google.cloud.kms.v1.KeyManagementService.Decrypt]. +// The [CryptoKey.purpose][google.cloud.kms.v1.CryptoKey.purpose] must be +// [ENCRYPT_DECRYPT][google.cloud.kms.v1.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT]. +func (c *KeyManagementClient) Encrypt(ctx context.Context, req *kmspb.EncryptRequest, opts ...gax.CallOption) (*kmspb.EncryptResponse, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.Encrypt[0:len(c.CallOptions.Encrypt):len(c.CallOptions.Encrypt)], opts...) + var resp *kmspb.EncryptResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.Encrypt(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Decrypt decrypts data that was protected by [Encrypt][google.cloud.kms.v1.KeyManagementService.Encrypt]. The [CryptoKey.purpose][google.cloud.kms.v1.CryptoKey.purpose] +// must be [ENCRYPT_DECRYPT][google.cloud.kms.v1.CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT]. +func (c *KeyManagementClient) Decrypt(ctx context.Context, req *kmspb.DecryptRequest, opts ...gax.CallOption) (*kmspb.DecryptResponse, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.Decrypt[0:len(c.CallOptions.Decrypt):len(c.CallOptions.Decrypt)], opts...) + var resp *kmspb.DecryptResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.Decrypt(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateCryptoKeyPrimaryVersion update the version of a [CryptoKey][google.cloud.kms.v1.CryptoKey] that will be used in [Encrypt][google.cloud.kms.v1.KeyManagementService.Encrypt]. +// +// Returns an error if called on an asymmetric key. +func (c *KeyManagementClient) UpdateCryptoKeyPrimaryVersion(ctx context.Context, req *kmspb.UpdateCryptoKeyPrimaryVersionRequest, opts ...gax.CallOption) (*kmspb.CryptoKey, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.UpdateCryptoKeyPrimaryVersion[0:len(c.CallOptions.UpdateCryptoKeyPrimaryVersion):len(c.CallOptions.UpdateCryptoKeyPrimaryVersion)], opts...) + var resp *kmspb.CryptoKey + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.UpdateCryptoKeyPrimaryVersion(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DestroyCryptoKeyVersion schedule a [CryptoKeyVersion][google.cloud.kms.v1.CryptoKeyVersion] for destruction. +// +// Upon calling this method, [CryptoKeyVersion.state][google.cloud.kms.v1.CryptoKeyVersion.state] will be set to +// [DESTROY_SCHEDULED][google.cloud.kms.v1.CryptoKeyVersion.CryptoKeyVersionState.DESTROY_SCHEDULED] +// and [destroy_time][google.cloud.kms.v1.CryptoKeyVersion.destroy_time] will be set to a time 24 +// hours in the future, at which point the [state][google.cloud.kms.v1.CryptoKeyVersion.state] +// will be changed to +// [DESTROYED][google.cloud.kms.v1.CryptoKeyVersion.CryptoKeyVersionState.DESTROYED], and the key +// material will be irrevocably destroyed. +// +// Before the [destroy_time][google.cloud.kms.v1.CryptoKeyVersion.destroy_time] is reached, +// [RestoreCryptoKeyVersion][google.cloud.kms.v1.KeyManagementService.RestoreCryptoKeyVersion] may be called to reverse the process. +func (c *KeyManagementClient) DestroyCryptoKeyVersion(ctx context.Context, req *kmspb.DestroyCryptoKeyVersionRequest, opts ...gax.CallOption) (*kmspb.CryptoKeyVersion, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.DestroyCryptoKeyVersion[0:len(c.CallOptions.DestroyCryptoKeyVersion):len(c.CallOptions.DestroyCryptoKeyVersion)], opts...) + var resp *kmspb.CryptoKeyVersion + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.DestroyCryptoKeyVersion(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// RestoreCryptoKeyVersion restore a [CryptoKeyVersion][google.cloud.kms.v1.CryptoKeyVersion] in the +// [DESTROY_SCHEDULED][google.cloud.kms.v1.CryptoKeyVersion.CryptoKeyVersionState.DESTROY_SCHEDULED] +// state. +// +// Upon restoration of the CryptoKeyVersion, [state][google.cloud.kms.v1.CryptoKeyVersion.state] +// will be set to [DISABLED][google.cloud.kms.v1.CryptoKeyVersion.CryptoKeyVersionState.DISABLED], +// and [destroy_time][google.cloud.kms.v1.CryptoKeyVersion.destroy_time] will be cleared. +func (c *KeyManagementClient) RestoreCryptoKeyVersion(ctx context.Context, req *kmspb.RestoreCryptoKeyVersionRequest, opts ...gax.CallOption) (*kmspb.CryptoKeyVersion, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.RestoreCryptoKeyVersion[0:len(c.CallOptions.RestoreCryptoKeyVersion):len(c.CallOptions.RestoreCryptoKeyVersion)], opts...) + var resp *kmspb.CryptoKeyVersion + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.RestoreCryptoKeyVersion(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetPublicKey returns the public key for the given [CryptoKeyVersion][google.cloud.kms.v1.CryptoKeyVersion]. The +// [CryptoKey.purpose][google.cloud.kms.v1.CryptoKey.purpose] must be +// [ASYMMETRIC_SIGN][google.cloud.kms.v1.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_SIGN] or +// [ASYMMETRIC_DECRYPT][google.cloud.kms.v1.CryptoKey.CryptoKeyPurpose.ASYMMETRIC_DECRYPT]. +func (c *KeyManagementClient) GetPublicKey(ctx context.Context, req *kmspb.GetPublicKeyRequest, opts ...gax.CallOption) (*kmspb.PublicKey, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.GetPublicKey[0:len(c.CallOptions.GetPublicKey):len(c.CallOptions.GetPublicKey)], opts...) + var resp *kmspb.PublicKey + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.GetPublicKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// AsymmetricDecrypt decrypts data that was encrypted with a public key retrieved from +// [GetPublicKey][google.cloud.kms.v1.KeyManagementService.GetPublicKey] corresponding to a [CryptoKeyVersion][google.cloud.kms.v1.CryptoKeyVersion] with +// [CryptoKey.purpose][google.cloud.kms.v1.CryptoKey.purpose] ASYMMETRIC_DECRYPT. +func (c *KeyManagementClient) AsymmetricDecrypt(ctx context.Context, req *kmspb.AsymmetricDecryptRequest, opts ...gax.CallOption) (*kmspb.AsymmetricDecryptResponse, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.AsymmetricDecrypt[0:len(c.CallOptions.AsymmetricDecrypt):len(c.CallOptions.AsymmetricDecrypt)], opts...) + var resp *kmspb.AsymmetricDecryptResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.AsymmetricDecrypt(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// AsymmetricSign signs data using a [CryptoKeyVersion][google.cloud.kms.v1.CryptoKeyVersion] with [CryptoKey.purpose][google.cloud.kms.v1.CryptoKey.purpose] +// ASYMMETRIC_SIGN, producing a signature that can be verified with the public +// key retrieved from [GetPublicKey][google.cloud.kms.v1.KeyManagementService.GetPublicKey]. +func (c *KeyManagementClient) AsymmetricSign(ctx context.Context, req *kmspb.AsymmetricSignRequest, opts ...gax.CallOption) (*kmspb.AsymmetricSignResponse, error) { + md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", req.GetName())) + ctx = insertMetadata(ctx, c.xGoogMetadata, md) + opts = append(c.CallOptions.AsymmetricSign[0:len(c.CallOptions.AsymmetricSign):len(c.CallOptions.AsymmetricSign)], opts...) + var resp *kmspb.AsymmetricSignResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.keyManagementClient.AsymmetricSign(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CryptoKeyIterator manages a stream of *kmspb.CryptoKey. +type CryptoKeyIterator struct { + items []*kmspb.CryptoKey + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*kmspb.CryptoKey, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *CryptoKeyIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *CryptoKeyIterator) Next() (*kmspb.CryptoKey, error) { + var item *kmspb.CryptoKey + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *CryptoKeyIterator) bufLen() int { + return len(it.items) +} + +func (it *CryptoKeyIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// CryptoKeyVersionIterator manages a stream of *kmspb.CryptoKeyVersion. +type CryptoKeyVersionIterator struct { + items []*kmspb.CryptoKeyVersion + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*kmspb.CryptoKeyVersion, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *CryptoKeyVersionIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *CryptoKeyVersionIterator) Next() (*kmspb.CryptoKeyVersion, error) { + var item *kmspb.CryptoKeyVersion + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *CryptoKeyVersionIterator) bufLen() int { + return len(it.items) +} + +func (it *CryptoKeyVersionIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// KeyRingIterator manages a stream of *kmspb.KeyRing. +type KeyRingIterator struct { + items []*kmspb.KeyRing + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*kmspb.KeyRing, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *KeyRingIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *KeyRingIterator) Next() (*kmspb.KeyRing, error) { + var item *kmspb.KeyRing + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *KeyRingIterator) bufLen() int { + return len(it.items) +} + +func (it *KeyRingIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/kms/apiv1/key_management_client_example_test.go b/vendor/cloud.google.com/go/kms/apiv1/key_management_client_example_test.go new file mode 100644 index 00000000..77a9002b --- /dev/null +++ b/vendor/cloud.google.com/go/kms/apiv1/key_management_client_example_test.go @@ -0,0 +1,395 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package kms_test + +import ( + "context" + + kms "cloud.google.com/go/kms/apiv1" + "google.golang.org/api/iterator" + kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1" +) + +func ExampleNewKeyManagementClient() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleKeyManagementClient_ListKeyRings() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.ListKeyRingsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListKeyRings(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleKeyManagementClient_ListCryptoKeys() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.ListCryptoKeysRequest{ + // TODO: Fill request struct fields. + } + it := c.ListCryptoKeys(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleKeyManagementClient_ListCryptoKeyVersions() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.ListCryptoKeyVersionsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListCryptoKeyVersions(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleKeyManagementClient_GetKeyRing() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.GetKeyRingRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetKeyRing(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_GetCryptoKey() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.GetCryptoKeyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetCryptoKey(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_GetCryptoKeyVersion() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.GetCryptoKeyVersionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetCryptoKeyVersion(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_CreateKeyRing() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.CreateKeyRingRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateKeyRing(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_CreateCryptoKey() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.CreateCryptoKeyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateCryptoKey(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_CreateCryptoKeyVersion() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.CreateCryptoKeyVersionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateCryptoKeyVersion(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_UpdateCryptoKey() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.UpdateCryptoKeyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateCryptoKey(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_UpdateCryptoKeyVersion() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.UpdateCryptoKeyVersionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateCryptoKeyVersion(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_Encrypt() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.EncryptRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Encrypt(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_Decrypt() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.DecryptRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Decrypt(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_UpdateCryptoKeyPrimaryVersion() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.UpdateCryptoKeyPrimaryVersionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateCryptoKeyPrimaryVersion(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_DestroyCryptoKeyVersion() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.DestroyCryptoKeyVersionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.DestroyCryptoKeyVersion(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_RestoreCryptoKeyVersion() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.RestoreCryptoKeyVersionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.RestoreCryptoKeyVersion(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_GetPublicKey() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.GetPublicKeyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetPublicKey(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_AsymmetricDecrypt() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.AsymmetricDecryptRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.AsymmetricDecrypt(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleKeyManagementClient_AsymmetricSign() { + ctx := context.Background() + c, err := kms.NewKeyManagementClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &kmspb.AsymmetricSignRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.AsymmetricSign(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/kms/apiv1/mock_test.go b/vendor/cloud.google.com/go/kms/apiv1/mock_test.go new file mode 100644 index 00000000..6fd79881 --- /dev/null +++ b/vendor/cloud.google.com/go/kms/apiv1/mock_test.go @@ -0,0 +1,1622 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package kms + +import ( + durationpb "github.com/golang/protobuf/ptypes/duration" + timestamppb "github.com/golang/protobuf/ptypes/timestamp" + kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1" + iampb "google.golang.org/genproto/googleapis/iam/v1" + field_maskpb "google.golang.org/genproto/protobuf/field_mask" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockKeyManagementServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + kmspb.KeyManagementServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockKeyManagementServer) ListKeyRings(ctx context.Context, req *kmspb.ListKeyRingsRequest) (*kmspb.ListKeyRingsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.ListKeyRingsResponse), nil +} + +func (s *mockKeyManagementServer) ListCryptoKeys(ctx context.Context, req *kmspb.ListCryptoKeysRequest) (*kmspb.ListCryptoKeysResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.ListCryptoKeysResponse), nil +} + +func (s *mockKeyManagementServer) ListCryptoKeyVersions(ctx context.Context, req *kmspb.ListCryptoKeyVersionsRequest) (*kmspb.ListCryptoKeyVersionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.ListCryptoKeyVersionsResponse), nil +} + +func (s *mockKeyManagementServer) GetKeyRing(ctx context.Context, req *kmspb.GetKeyRingRequest) (*kmspb.KeyRing, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.KeyRing), nil +} + +func (s *mockKeyManagementServer) GetCryptoKey(ctx context.Context, req *kmspb.GetCryptoKeyRequest) (*kmspb.CryptoKey, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.CryptoKey), nil +} + +func (s *mockKeyManagementServer) GetCryptoKeyVersion(ctx context.Context, req *kmspb.GetCryptoKeyVersionRequest) (*kmspb.CryptoKeyVersion, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.CryptoKeyVersion), nil +} + +func (s *mockKeyManagementServer) GetPublicKey(ctx context.Context, req *kmspb.GetPublicKeyRequest) (*kmspb.PublicKey, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.PublicKey), nil +} + +func (s *mockKeyManagementServer) CreateKeyRing(ctx context.Context, req *kmspb.CreateKeyRingRequest) (*kmspb.KeyRing, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.KeyRing), nil +} + +func (s *mockKeyManagementServer) CreateCryptoKey(ctx context.Context, req *kmspb.CreateCryptoKeyRequest) (*kmspb.CryptoKey, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.CryptoKey), nil +} + +func (s *mockKeyManagementServer) CreateCryptoKeyVersion(ctx context.Context, req *kmspb.CreateCryptoKeyVersionRequest) (*kmspb.CryptoKeyVersion, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.CryptoKeyVersion), nil +} + +func (s *mockKeyManagementServer) UpdateCryptoKey(ctx context.Context, req *kmspb.UpdateCryptoKeyRequest) (*kmspb.CryptoKey, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.CryptoKey), nil +} + +func (s *mockKeyManagementServer) UpdateCryptoKeyVersion(ctx context.Context, req *kmspb.UpdateCryptoKeyVersionRequest) (*kmspb.CryptoKeyVersion, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.CryptoKeyVersion), nil +} + +func (s *mockKeyManagementServer) Encrypt(ctx context.Context, req *kmspb.EncryptRequest) (*kmspb.EncryptResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.EncryptResponse), nil +} + +func (s *mockKeyManagementServer) Decrypt(ctx context.Context, req *kmspb.DecryptRequest) (*kmspb.DecryptResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.DecryptResponse), nil +} + +func (s *mockKeyManagementServer) AsymmetricSign(ctx context.Context, req *kmspb.AsymmetricSignRequest) (*kmspb.AsymmetricSignResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.AsymmetricSignResponse), nil +} + +func (s *mockKeyManagementServer) AsymmetricDecrypt(ctx context.Context, req *kmspb.AsymmetricDecryptRequest) (*kmspb.AsymmetricDecryptResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.AsymmetricDecryptResponse), nil +} + +func (s *mockKeyManagementServer) UpdateCryptoKeyPrimaryVersion(ctx context.Context, req *kmspb.UpdateCryptoKeyPrimaryVersionRequest) (*kmspb.CryptoKey, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.CryptoKey), nil +} + +func (s *mockKeyManagementServer) DestroyCryptoKeyVersion(ctx context.Context, req *kmspb.DestroyCryptoKeyVersionRequest) (*kmspb.CryptoKeyVersion, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.CryptoKeyVersion), nil +} + +func (s *mockKeyManagementServer) RestoreCryptoKeyVersion(ctx context.Context, req *kmspb.RestoreCryptoKeyVersionRequest) (*kmspb.CryptoKeyVersion, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*kmspb.CryptoKeyVersion), nil +} + +type mockIamPolicyServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + iampb.IAMPolicyServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockIamPolicyServer) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockIamPolicyServer) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockIamPolicyServer) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest) (*iampb.TestIamPermissionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.TestIamPermissionsResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockKeyManagement mockKeyManagementServer + mockIamPolicy mockIamPolicyServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + kmspb.RegisterKeyManagementServiceServer(serv, &mockKeyManagement) + iampb.RegisterIAMPolicyServer(serv, &mockIamPolicy) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestKeyManagementServiceListKeyRings(t *testing.T) { + var nextPageToken string = "" + var totalSize int32 = 705419236 + var keyRingsElement *kmspb.KeyRing = &kmspb.KeyRing{} + var keyRings = []*kmspb.KeyRing{keyRingsElement} + var expectedResponse = &kmspb.ListKeyRingsResponse{ + NextPageToken: nextPageToken, + TotalSize: totalSize, + KeyRings: keyRings, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &kmspb.ListKeyRingsRequest{ + Parent: formattedParent, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListKeyRings(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.KeyRings[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceListKeyRingsError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &kmspb.ListKeyRingsRequest{ + Parent: formattedParent, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListKeyRings(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceListCryptoKeys(t *testing.T) { + var nextPageToken string = "" + var totalSize int32 = 705419236 + var cryptoKeysElement *kmspb.CryptoKey = &kmspb.CryptoKey{} + var cryptoKeys = []*kmspb.CryptoKey{cryptoKeysElement} + var expectedResponse = &kmspb.ListCryptoKeysResponse{ + NextPageToken: nextPageToken, + TotalSize: totalSize, + CryptoKeys: cryptoKeys, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]") + var request = &kmspb.ListCryptoKeysRequest{ + Parent: formattedParent, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListCryptoKeys(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.CryptoKeys[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceListCryptoKeysError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]") + var request = &kmspb.ListCryptoKeysRequest{ + Parent: formattedParent, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListCryptoKeys(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceListCryptoKeyVersions(t *testing.T) { + var nextPageToken string = "" + var totalSize int32 = 705419236 + var cryptoKeyVersionsElement *kmspb.CryptoKeyVersion = &kmspb.CryptoKeyVersion{} + var cryptoKeyVersions = []*kmspb.CryptoKeyVersion{cryptoKeyVersionsElement} + var expectedResponse = &kmspb.ListCryptoKeyVersionsResponse{ + NextPageToken: nextPageToken, + TotalSize: totalSize, + CryptoKeyVersions: cryptoKeyVersions, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]") + var request = &kmspb.ListCryptoKeyVersionsRequest{ + Parent: formattedParent, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListCryptoKeyVersions(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.CryptoKeyVersions[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceListCryptoKeyVersionsError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]") + var request = &kmspb.ListCryptoKeyVersionsRequest{ + Parent: formattedParent, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListCryptoKeyVersions(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceGetKeyRing(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &kmspb.KeyRing{ + Name: name2, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]") + var request = &kmspb.GetKeyRingRequest{ + Name: formattedName, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetKeyRing(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceGetKeyRingError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]") + var request = &kmspb.GetKeyRingRequest{ + Name: formattedName, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetKeyRing(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceGetCryptoKey(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &kmspb.CryptoKey{ + Name: name2, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]") + var request = &kmspb.GetCryptoKeyRequest{ + Name: formattedName, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetCryptoKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceGetCryptoKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]") + var request = &kmspb.GetCryptoKeyRequest{ + Name: formattedName, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetCryptoKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceGetCryptoKeyVersion(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &kmspb.CryptoKeyVersion{ + Name: name2, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]", "[CRYPTO_KEY_VERSION]") + var request = &kmspb.GetCryptoKeyVersionRequest{ + Name: formattedName, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetCryptoKeyVersion(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceGetCryptoKeyVersionError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]", "[CRYPTO_KEY_VERSION]") + var request = &kmspb.GetCryptoKeyVersionRequest{ + Name: formattedName, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetCryptoKeyVersion(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceCreateKeyRing(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &kmspb.KeyRing{ + Name: name, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var keyRingId string = "keyRingId-2056646742" + var keyRing *kmspb.KeyRing = &kmspb.KeyRing{} + var request = &kmspb.CreateKeyRingRequest{ + Parent: formattedParent, + KeyRingId: keyRingId, + KeyRing: keyRing, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateKeyRing(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceCreateKeyRingError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var keyRingId string = "keyRingId-2056646742" + var keyRing *kmspb.KeyRing = &kmspb.KeyRing{} + var request = &kmspb.CreateKeyRingRequest{ + Parent: formattedParent, + KeyRingId: keyRingId, + KeyRing: keyRing, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateKeyRing(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceCreateCryptoKey(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &kmspb.CryptoKey{ + Name: name, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]") + var cryptoKeyId string = "my-app-key" + var purpose kmspb.CryptoKey_CryptoKeyPurpose = kmspb.CryptoKey_ENCRYPT_DECRYPT + var seconds int64 = 2147483647 + var nextRotationTime = ×tamppb.Timestamp{ + Seconds: seconds, + } + var seconds2 int64 = 604800 + var rotationPeriod = &durationpb.Duration{ + Seconds: seconds2, + } + var cryptoKey = &kmspb.CryptoKey{ + Purpose: purpose, + NextRotationTime: nextRotationTime, + RotationSchedule: &kmspb.CryptoKey_RotationPeriod{ + RotationPeriod: rotationPeriod, + }, + } + var request = &kmspb.CreateCryptoKeyRequest{ + Parent: formattedParent, + CryptoKeyId: cryptoKeyId, + CryptoKey: cryptoKey, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateCryptoKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceCreateCryptoKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]") + var cryptoKeyId string = "my-app-key" + var purpose kmspb.CryptoKey_CryptoKeyPurpose = kmspb.CryptoKey_ENCRYPT_DECRYPT + var seconds int64 = 2147483647 + var nextRotationTime = ×tamppb.Timestamp{ + Seconds: seconds, + } + var seconds2 int64 = 604800 + var rotationPeriod = &durationpb.Duration{ + Seconds: seconds2, + } + var cryptoKey = &kmspb.CryptoKey{ + Purpose: purpose, + NextRotationTime: nextRotationTime, + RotationSchedule: &kmspb.CryptoKey_RotationPeriod{ + RotationPeriod: rotationPeriod, + }, + } + var request = &kmspb.CreateCryptoKeyRequest{ + Parent: formattedParent, + CryptoKeyId: cryptoKeyId, + CryptoKey: cryptoKey, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateCryptoKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceCreateCryptoKeyVersion(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &kmspb.CryptoKeyVersion{ + Name: name, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]") + var cryptoKeyVersion *kmspb.CryptoKeyVersion = &kmspb.CryptoKeyVersion{} + var request = &kmspb.CreateCryptoKeyVersionRequest{ + Parent: formattedParent, + CryptoKeyVersion: cryptoKeyVersion, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateCryptoKeyVersion(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceCreateCryptoKeyVersionError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]") + var cryptoKeyVersion *kmspb.CryptoKeyVersion = &kmspb.CryptoKeyVersion{} + var request = &kmspb.CreateCryptoKeyVersionRequest{ + Parent: formattedParent, + CryptoKeyVersion: cryptoKeyVersion, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateCryptoKeyVersion(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceUpdateCryptoKey(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &kmspb.CryptoKey{ + Name: name, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var cryptoKey *kmspb.CryptoKey = &kmspb.CryptoKey{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &kmspb.UpdateCryptoKeyRequest{ + CryptoKey: cryptoKey, + UpdateMask: updateMask, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateCryptoKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceUpdateCryptoKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var cryptoKey *kmspb.CryptoKey = &kmspb.CryptoKey{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &kmspb.UpdateCryptoKeyRequest{ + CryptoKey: cryptoKey, + UpdateMask: updateMask, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateCryptoKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceUpdateCryptoKeyVersion(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &kmspb.CryptoKeyVersion{ + Name: name, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var cryptoKeyVersion *kmspb.CryptoKeyVersion = &kmspb.CryptoKeyVersion{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &kmspb.UpdateCryptoKeyVersionRequest{ + CryptoKeyVersion: cryptoKeyVersion, + UpdateMask: updateMask, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateCryptoKeyVersion(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceUpdateCryptoKeyVersionError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var cryptoKeyVersion *kmspb.CryptoKeyVersion = &kmspb.CryptoKeyVersion{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &kmspb.UpdateCryptoKeyVersionRequest{ + CryptoKeyVersion: cryptoKeyVersion, + UpdateMask: updateMask, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateCryptoKeyVersion(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceEncrypt(t *testing.T) { + var name2 string = "name2-1052831874" + var ciphertext []byte = []byte("-72") + var expectedResponse = &kmspb.EncryptResponse{ + Name: name2, + Ciphertext: ciphertext, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY_PATH]") + var plaintext []byte = []byte("-9") + var request = &kmspb.EncryptRequest{ + Name: formattedName, + Plaintext: plaintext, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Encrypt(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceEncryptError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY_PATH]") + var plaintext []byte = []byte("-9") + var request = &kmspb.EncryptRequest{ + Name: formattedName, + Plaintext: plaintext, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Encrypt(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceDecrypt(t *testing.T) { + var plaintext []byte = []byte("-9") + var expectedResponse = &kmspb.DecryptResponse{ + Plaintext: plaintext, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]") + var ciphertext []byte = []byte("-72") + var request = &kmspb.DecryptRequest{ + Name: formattedName, + Ciphertext: ciphertext, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Decrypt(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceDecryptError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]") + var ciphertext []byte = []byte("-72") + var request = &kmspb.DecryptRequest{ + Name: formattedName, + Ciphertext: ciphertext, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Decrypt(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceUpdateCryptoKeyPrimaryVersion(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &kmspb.CryptoKey{ + Name: name2, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]") + var cryptoKeyVersionId string = "cryptoKeyVersionId729489152" + var request = &kmspb.UpdateCryptoKeyPrimaryVersionRequest{ + Name: formattedName, + CryptoKeyVersionId: cryptoKeyVersionId, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateCryptoKeyPrimaryVersion(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceUpdateCryptoKeyPrimaryVersionError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]") + var cryptoKeyVersionId string = "cryptoKeyVersionId729489152" + var request = &kmspb.UpdateCryptoKeyPrimaryVersionRequest{ + Name: formattedName, + CryptoKeyVersionId: cryptoKeyVersionId, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateCryptoKeyPrimaryVersion(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceDestroyCryptoKeyVersion(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &kmspb.CryptoKeyVersion{ + Name: name2, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]", "[CRYPTO_KEY_VERSION]") + var request = &kmspb.DestroyCryptoKeyVersionRequest{ + Name: formattedName, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.DestroyCryptoKeyVersion(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceDestroyCryptoKeyVersionError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]", "[CRYPTO_KEY_VERSION]") + var request = &kmspb.DestroyCryptoKeyVersionRequest{ + Name: formattedName, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.DestroyCryptoKeyVersion(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceRestoreCryptoKeyVersion(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &kmspb.CryptoKeyVersion{ + Name: name2, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]", "[CRYPTO_KEY_VERSION]") + var request = &kmspb.RestoreCryptoKeyVersionRequest{ + Name: formattedName, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RestoreCryptoKeyVersion(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceRestoreCryptoKeyVersionError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]", "[CRYPTO_KEY_VERSION]") + var request = &kmspb.RestoreCryptoKeyVersionRequest{ + Name: formattedName, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RestoreCryptoKeyVersion(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceGetPublicKey(t *testing.T) { + var pem string = "pem110872" + var expectedResponse = &kmspb.PublicKey{ + Pem: pem, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]", "[CRYPTO_KEY_VERSION]") + var request = &kmspb.GetPublicKeyRequest{ + Name: formattedName, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetPublicKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceGetPublicKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]", "[CRYPTO_KEY_VERSION]") + var request = &kmspb.GetPublicKeyRequest{ + Name: formattedName, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetPublicKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceAsymmetricDecrypt(t *testing.T) { + var plaintext []byte = []byte("-9") + var expectedResponse = &kmspb.AsymmetricDecryptResponse{ + Plaintext: plaintext, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]", "[CRYPTO_KEY_VERSION]") + var ciphertext []byte = []byte("-72") + var request = &kmspb.AsymmetricDecryptRequest{ + Name: formattedName, + Ciphertext: ciphertext, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AsymmetricDecrypt(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceAsymmetricDecryptError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]", "[CRYPTO_KEY_VERSION]") + var ciphertext []byte = []byte("-72") + var request = &kmspb.AsymmetricDecryptRequest{ + Name: formattedName, + Ciphertext: ciphertext, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AsymmetricDecrypt(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestKeyManagementServiceAsymmetricSign(t *testing.T) { + var signature []byte = []byte("106") + var expectedResponse = &kmspb.AsymmetricSignResponse{ + Signature: signature, + } + + mockKeyManagement.err = nil + mockKeyManagement.reqs = nil + + mockKeyManagement.resps = append(mockKeyManagement.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]", "[CRYPTO_KEY_VERSION]") + var digest *kmspb.Digest = &kmspb.Digest{} + var request = &kmspb.AsymmetricSignRequest{ + Name: formattedName, + Digest: digest, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AsymmetricSign(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockKeyManagement.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestKeyManagementServiceAsymmetricSignError(t *testing.T) { + errCode := codes.PermissionDenied + mockKeyManagement.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", "[PROJECT]", "[LOCATION]", "[KEY_RING]", "[CRYPTO_KEY]", "[CRYPTO_KEY_VERSION]") + var digest *kmspb.Digest = &kmspb.Digest{} + var request = &kmspb.AsymmetricSignRequest{ + Name: formattedName, + Digest: digest, + } + + c, err := NewKeyManagementClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AsymmetricSign(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/language/apiv1/AnalyzeSentiment_smoke_test.go b/vendor/cloud.google.com/go/language/apiv1/AnalyzeSentiment_smoke_test.go new file mode 100644 index 00000000..9a57ee94 --- /dev/null +++ b/vendor/cloud.google.com/go/language/apiv1/AnalyzeSentiment_smoke_test.go @@ -0,0 +1,73 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package language + +import ( + languagepb "google.golang.org/genproto/googleapis/cloud/language/v1" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestLanguageServiceSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var content string = "Hello, world!" + var type_ languagepb.Document_Type = languagepb.Document_PLAIN_TEXT + var document = &languagepb.Document{ + Source: &languagepb.Document_Content{ + Content: content, + }, + Type: type_, + } + var request = &languagepb.AnalyzeSentimentRequest{ + Document: document, + } + + if _, err := c.AnalyzeSentiment(ctx, request); err != nil { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/language/apiv1/doc.go b/vendor/cloud.google.com/go/language/apiv1/doc.go new file mode 100644 index 00000000..01bfeacf --- /dev/null +++ b/vendor/cloud.google.com/go/language/apiv1/doc.go @@ -0,0 +1,90 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package language is an auto-generated package for the +// Google Cloud Natural Language API. + +// +// Google Cloud Natural Language API provides natural language understanding +// technologies to developers. Examples include sentiment analysis, entity +// recognition, and text annotations. +package language // import "cloud.google.com/go/language/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/language/apiv1/language_client.go b/vendor/cloud.google.com/go/language/apiv1/language_client.go new file mode 100644 index 00000000..51627d9f --- /dev/null +++ b/vendor/cloud.google.com/go/language/apiv1/language_client.go @@ -0,0 +1,230 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package language + +import ( + "context" + "time" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + languagepb "google.golang.org/genproto/googleapis/cloud/language/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + AnalyzeSentiment []gax.CallOption + AnalyzeEntities []gax.CallOption + AnalyzeEntitySentiment []gax.CallOption + AnalyzeSyntax []gax.CallOption + ClassifyText []gax.CallOption + AnnotateText []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("language.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + AnalyzeSentiment: retry[[2]string{"default", "idempotent"}], + AnalyzeEntities: retry[[2]string{"default", "idempotent"}], + AnalyzeEntitySentiment: retry[[2]string{"default", "idempotent"}], + AnalyzeSyntax: retry[[2]string{"default", "idempotent"}], + ClassifyText: retry[[2]string{"default", "idempotent"}], + AnnotateText: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Google Cloud Natural Language API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client languagepb.LanguageServiceClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new language service client. +// +// Provides text analysis operations such as sentiment analysis and entity +// recognition. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: languagepb.NewLanguageServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// AnalyzeSentiment analyzes the sentiment of the provided text. +func (c *Client) AnalyzeSentiment(ctx context.Context, req *languagepb.AnalyzeSentimentRequest, opts ...gax.CallOption) (*languagepb.AnalyzeSentimentResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AnalyzeSentiment[0:len(c.CallOptions.AnalyzeSentiment):len(c.CallOptions.AnalyzeSentiment)], opts...) + var resp *languagepb.AnalyzeSentimentResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.AnalyzeSentiment(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// AnalyzeEntities finds named entities (currently proper names and common nouns) in the text +// along with entity types, salience, mentions for each entity, and +// other properties. +func (c *Client) AnalyzeEntities(ctx context.Context, req *languagepb.AnalyzeEntitiesRequest, opts ...gax.CallOption) (*languagepb.AnalyzeEntitiesResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AnalyzeEntities[0:len(c.CallOptions.AnalyzeEntities):len(c.CallOptions.AnalyzeEntities)], opts...) + var resp *languagepb.AnalyzeEntitiesResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.AnalyzeEntities(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// AnalyzeEntitySentiment finds entities, similar to [AnalyzeEntities][google.cloud.language.v1.LanguageService.AnalyzeEntities] in the text and analyzes +// sentiment associated with each entity and its mentions. +func (c *Client) AnalyzeEntitySentiment(ctx context.Context, req *languagepb.AnalyzeEntitySentimentRequest, opts ...gax.CallOption) (*languagepb.AnalyzeEntitySentimentResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AnalyzeEntitySentiment[0:len(c.CallOptions.AnalyzeEntitySentiment):len(c.CallOptions.AnalyzeEntitySentiment)], opts...) + var resp *languagepb.AnalyzeEntitySentimentResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.AnalyzeEntitySentiment(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// AnalyzeSyntax analyzes the syntax of the text and provides sentence boundaries and +// tokenization along with part of speech tags, dependency trees, and other +// properties. +func (c *Client) AnalyzeSyntax(ctx context.Context, req *languagepb.AnalyzeSyntaxRequest, opts ...gax.CallOption) (*languagepb.AnalyzeSyntaxResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AnalyzeSyntax[0:len(c.CallOptions.AnalyzeSyntax):len(c.CallOptions.AnalyzeSyntax)], opts...) + var resp *languagepb.AnalyzeSyntaxResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.AnalyzeSyntax(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ClassifyText classifies a document into categories. +func (c *Client) ClassifyText(ctx context.Context, req *languagepb.ClassifyTextRequest, opts ...gax.CallOption) (*languagepb.ClassifyTextResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ClassifyText[0:len(c.CallOptions.ClassifyText):len(c.CallOptions.ClassifyText)], opts...) + var resp *languagepb.ClassifyTextResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ClassifyText(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// AnnotateText a convenience method that provides all the features that analyzeSentiment, +// analyzeEntities, and analyzeSyntax provide in one call. +func (c *Client) AnnotateText(ctx context.Context, req *languagepb.AnnotateTextRequest, opts ...gax.CallOption) (*languagepb.AnnotateTextResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AnnotateText[0:len(c.CallOptions.AnnotateText):len(c.CallOptions.AnnotateText)], opts...) + var resp *languagepb.AnnotateTextResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.AnnotateText(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/language/apiv1/language_client_example_test.go b/vendor/cloud.google.com/go/language/apiv1/language_client_example_test.go new file mode 100644 index 00000000..df8c6e44 --- /dev/null +++ b/vendor/cloud.google.com/go/language/apiv1/language_client_example_test.go @@ -0,0 +1,142 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package language_test + +import ( + "context" + + language "cloud.google.com/go/language/apiv1" + languagepb "google.golang.org/genproto/googleapis/cloud/language/v1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_AnalyzeSentiment() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &languagepb.AnalyzeSentimentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.AnalyzeSentiment(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_AnalyzeEntities() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &languagepb.AnalyzeEntitiesRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.AnalyzeEntities(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_AnalyzeEntitySentiment() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &languagepb.AnalyzeEntitySentimentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.AnalyzeEntitySentiment(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_AnalyzeSyntax() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &languagepb.AnalyzeSyntaxRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.AnalyzeSyntax(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ClassifyText() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &languagepb.ClassifyTextRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ClassifyText(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_AnnotateText() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &languagepb.AnnotateTextRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.AnnotateText(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/language/apiv1/mock_test.go b/vendor/cloud.google.com/go/language/apiv1/mock_test.go new file mode 100644 index 00000000..eaeb0c39 --- /dev/null +++ b/vendor/cloud.google.com/go/language/apiv1/mock_test.go @@ -0,0 +1,518 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package language + +import ( + languagepb "google.golang.org/genproto/googleapis/cloud/language/v1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockLanguageServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + languagepb.LanguageServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockLanguageServer) AnalyzeSentiment(ctx context.Context, req *languagepb.AnalyzeSentimentRequest) (*languagepb.AnalyzeSentimentResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*languagepb.AnalyzeSentimentResponse), nil +} + +func (s *mockLanguageServer) AnalyzeEntities(ctx context.Context, req *languagepb.AnalyzeEntitiesRequest) (*languagepb.AnalyzeEntitiesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*languagepb.AnalyzeEntitiesResponse), nil +} + +func (s *mockLanguageServer) AnalyzeEntitySentiment(ctx context.Context, req *languagepb.AnalyzeEntitySentimentRequest) (*languagepb.AnalyzeEntitySentimentResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*languagepb.AnalyzeEntitySentimentResponse), nil +} + +func (s *mockLanguageServer) AnalyzeSyntax(ctx context.Context, req *languagepb.AnalyzeSyntaxRequest) (*languagepb.AnalyzeSyntaxResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*languagepb.AnalyzeSyntaxResponse), nil +} + +func (s *mockLanguageServer) ClassifyText(ctx context.Context, req *languagepb.ClassifyTextRequest) (*languagepb.ClassifyTextResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*languagepb.ClassifyTextResponse), nil +} + +func (s *mockLanguageServer) AnnotateText(ctx context.Context, req *languagepb.AnnotateTextRequest) (*languagepb.AnnotateTextResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*languagepb.AnnotateTextResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockLanguage mockLanguageServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + languagepb.RegisterLanguageServiceServer(serv, &mockLanguage) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestLanguageServiceAnalyzeSentiment(t *testing.T) { + var language string = "language-1613589672" + var expectedResponse = &languagepb.AnalyzeSentimentResponse{ + Language: language, + } + + mockLanguage.err = nil + mockLanguage.reqs = nil + + mockLanguage.resps = append(mockLanguage.resps[:0], expectedResponse) + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeSentimentRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeSentiment(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLanguage.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLanguageServiceAnalyzeSentimentError(t *testing.T) { + errCode := codes.PermissionDenied + mockLanguage.err = gstatus.Error(errCode, "test error") + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeSentimentRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeSentiment(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestLanguageServiceAnalyzeEntities(t *testing.T) { + var language string = "language-1613589672" + var expectedResponse = &languagepb.AnalyzeEntitiesResponse{ + Language: language, + } + + mockLanguage.err = nil + mockLanguage.reqs = nil + + mockLanguage.resps = append(mockLanguage.resps[:0], expectedResponse) + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeEntitiesRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeEntities(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLanguage.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLanguageServiceAnalyzeEntitiesError(t *testing.T) { + errCode := codes.PermissionDenied + mockLanguage.err = gstatus.Error(errCode, "test error") + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeEntitiesRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeEntities(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestLanguageServiceAnalyzeEntitySentiment(t *testing.T) { + var language string = "language-1613589672" + var expectedResponse = &languagepb.AnalyzeEntitySentimentResponse{ + Language: language, + } + + mockLanguage.err = nil + mockLanguage.reqs = nil + + mockLanguage.resps = append(mockLanguage.resps[:0], expectedResponse) + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeEntitySentimentRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeEntitySentiment(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLanguage.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLanguageServiceAnalyzeEntitySentimentError(t *testing.T) { + errCode := codes.PermissionDenied + mockLanguage.err = gstatus.Error(errCode, "test error") + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeEntitySentimentRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeEntitySentiment(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestLanguageServiceAnalyzeSyntax(t *testing.T) { + var language string = "language-1613589672" + var expectedResponse = &languagepb.AnalyzeSyntaxResponse{ + Language: language, + } + + mockLanguage.err = nil + mockLanguage.reqs = nil + + mockLanguage.resps = append(mockLanguage.resps[:0], expectedResponse) + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeSyntaxRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeSyntax(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLanguage.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLanguageServiceAnalyzeSyntaxError(t *testing.T) { + errCode := codes.PermissionDenied + mockLanguage.err = gstatus.Error(errCode, "test error") + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeSyntaxRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeSyntax(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestLanguageServiceClassifyText(t *testing.T) { + var expectedResponse *languagepb.ClassifyTextResponse = &languagepb.ClassifyTextResponse{} + + mockLanguage.err = nil + mockLanguage.reqs = nil + + mockLanguage.resps = append(mockLanguage.resps[:0], expectedResponse) + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.ClassifyTextRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ClassifyText(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLanguage.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLanguageServiceClassifyTextError(t *testing.T) { + errCode := codes.PermissionDenied + mockLanguage.err = gstatus.Error(errCode, "test error") + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.ClassifyTextRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ClassifyText(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestLanguageServiceAnnotateText(t *testing.T) { + var language string = "language-1613589672" + var expectedResponse = &languagepb.AnnotateTextResponse{ + Language: language, + } + + mockLanguage.err = nil + mockLanguage.reqs = nil + + mockLanguage.resps = append(mockLanguage.resps[:0], expectedResponse) + + var document *languagepb.Document = &languagepb.Document{} + var features *languagepb.AnnotateTextRequest_Features = &languagepb.AnnotateTextRequest_Features{} + var request = &languagepb.AnnotateTextRequest{ + Document: document, + Features: features, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnnotateText(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLanguage.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLanguageServiceAnnotateTextError(t *testing.T) { + errCode := codes.PermissionDenied + mockLanguage.err = gstatus.Error(errCode, "test error") + + var document *languagepb.Document = &languagepb.Document{} + var features *languagepb.AnnotateTextRequest_Features = &languagepb.AnnotateTextRequest_Features{} + var request = &languagepb.AnnotateTextRequest{ + Document: document, + Features: features, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnnotateText(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/language/apiv1beta2/AnalyzeSentiment_smoke_test.go b/vendor/cloud.google.com/go/language/apiv1beta2/AnalyzeSentiment_smoke_test.go new file mode 100644 index 00000000..c0db4ce1 --- /dev/null +++ b/vendor/cloud.google.com/go/language/apiv1beta2/AnalyzeSentiment_smoke_test.go @@ -0,0 +1,73 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package language + +import ( + languagepb "google.golang.org/genproto/googleapis/cloud/language/v1beta2" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestLanguageServiceSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var content string = "Hello, world!" + var type_ languagepb.Document_Type = languagepb.Document_PLAIN_TEXT + var document = &languagepb.Document{ + Source: &languagepb.Document_Content{ + Content: content, + }, + Type: type_, + } + var request = &languagepb.AnalyzeSentimentRequest{ + Document: document, + } + + if _, err := c.AnalyzeSentiment(ctx, request); err != nil { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/language/apiv1beta2/doc.go b/vendor/cloud.google.com/go/language/apiv1beta2/doc.go new file mode 100644 index 00000000..5c7ee030 --- /dev/null +++ b/vendor/cloud.google.com/go/language/apiv1beta2/doc.go @@ -0,0 +1,91 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package language is an auto-generated package for the +// Google Cloud Natural Language API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Google Cloud Natural Language API provides natural language understanding +// technologies to developers. Examples include sentiment analysis, entity +// recognition, and text annotations. +package language // import "cloud.google.com/go/language/apiv1beta2" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/language/apiv1beta2/language_client.go b/vendor/cloud.google.com/go/language/apiv1beta2/language_client.go new file mode 100644 index 00000000..19eeae3d --- /dev/null +++ b/vendor/cloud.google.com/go/language/apiv1beta2/language_client.go @@ -0,0 +1,230 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package language + +import ( + "context" + "time" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + languagepb "google.golang.org/genproto/googleapis/cloud/language/v1beta2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + AnalyzeSentiment []gax.CallOption + AnalyzeEntities []gax.CallOption + AnalyzeEntitySentiment []gax.CallOption + AnalyzeSyntax []gax.CallOption + ClassifyText []gax.CallOption + AnnotateText []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("language.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + AnalyzeSentiment: retry[[2]string{"default", "idempotent"}], + AnalyzeEntities: retry[[2]string{"default", "idempotent"}], + AnalyzeEntitySentiment: retry[[2]string{"default", "idempotent"}], + AnalyzeSyntax: retry[[2]string{"default", "idempotent"}], + ClassifyText: retry[[2]string{"default", "idempotent"}], + AnnotateText: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Google Cloud Natural Language API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client languagepb.LanguageServiceClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new language service client. +// +// Provides text analysis operations such as sentiment analysis and entity +// recognition. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: languagepb.NewLanguageServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// AnalyzeSentiment analyzes the sentiment of the provided text. +func (c *Client) AnalyzeSentiment(ctx context.Context, req *languagepb.AnalyzeSentimentRequest, opts ...gax.CallOption) (*languagepb.AnalyzeSentimentResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AnalyzeSentiment[0:len(c.CallOptions.AnalyzeSentiment):len(c.CallOptions.AnalyzeSentiment)], opts...) + var resp *languagepb.AnalyzeSentimentResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.AnalyzeSentiment(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// AnalyzeEntities finds named entities (currently proper names and common nouns) in the text +// along with entity types, salience, mentions for each entity, and +// other properties. +func (c *Client) AnalyzeEntities(ctx context.Context, req *languagepb.AnalyzeEntitiesRequest, opts ...gax.CallOption) (*languagepb.AnalyzeEntitiesResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AnalyzeEntities[0:len(c.CallOptions.AnalyzeEntities):len(c.CallOptions.AnalyzeEntities)], opts...) + var resp *languagepb.AnalyzeEntitiesResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.AnalyzeEntities(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// AnalyzeEntitySentiment finds entities, similar to [AnalyzeEntities][google.cloud.language.v1beta2.LanguageService.AnalyzeEntities] in the text and analyzes +// sentiment associated with each entity and its mentions. +func (c *Client) AnalyzeEntitySentiment(ctx context.Context, req *languagepb.AnalyzeEntitySentimentRequest, opts ...gax.CallOption) (*languagepb.AnalyzeEntitySentimentResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AnalyzeEntitySentiment[0:len(c.CallOptions.AnalyzeEntitySentiment):len(c.CallOptions.AnalyzeEntitySentiment)], opts...) + var resp *languagepb.AnalyzeEntitySentimentResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.AnalyzeEntitySentiment(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// AnalyzeSyntax analyzes the syntax of the text and provides sentence boundaries and +// tokenization along with part of speech tags, dependency trees, and other +// properties. +func (c *Client) AnalyzeSyntax(ctx context.Context, req *languagepb.AnalyzeSyntaxRequest, opts ...gax.CallOption) (*languagepb.AnalyzeSyntaxResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AnalyzeSyntax[0:len(c.CallOptions.AnalyzeSyntax):len(c.CallOptions.AnalyzeSyntax)], opts...) + var resp *languagepb.AnalyzeSyntaxResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.AnalyzeSyntax(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ClassifyText classifies a document into categories. +func (c *Client) ClassifyText(ctx context.Context, req *languagepb.ClassifyTextRequest, opts ...gax.CallOption) (*languagepb.ClassifyTextResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ClassifyText[0:len(c.CallOptions.ClassifyText):len(c.CallOptions.ClassifyText)], opts...) + var resp *languagepb.ClassifyTextResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ClassifyText(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// AnnotateText a convenience method that provides all syntax, sentiment, entity, and +// classification features in one call. +func (c *Client) AnnotateText(ctx context.Context, req *languagepb.AnnotateTextRequest, opts ...gax.CallOption) (*languagepb.AnnotateTextResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AnnotateText[0:len(c.CallOptions.AnnotateText):len(c.CallOptions.AnnotateText)], opts...) + var resp *languagepb.AnnotateTextResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.AnnotateText(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/language/apiv1beta2/language_client_example_test.go b/vendor/cloud.google.com/go/language/apiv1beta2/language_client_example_test.go new file mode 100644 index 00000000..2d4c0cf3 --- /dev/null +++ b/vendor/cloud.google.com/go/language/apiv1beta2/language_client_example_test.go @@ -0,0 +1,142 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package language_test + +import ( + "context" + + language "cloud.google.com/go/language/apiv1beta2" + languagepb "google.golang.org/genproto/googleapis/cloud/language/v1beta2" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_AnalyzeSentiment() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &languagepb.AnalyzeSentimentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.AnalyzeSentiment(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_AnalyzeEntities() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &languagepb.AnalyzeEntitiesRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.AnalyzeEntities(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_AnalyzeEntitySentiment() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &languagepb.AnalyzeEntitySentimentRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.AnalyzeEntitySentiment(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_AnalyzeSyntax() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &languagepb.AnalyzeSyntaxRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.AnalyzeSyntax(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ClassifyText() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &languagepb.ClassifyTextRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ClassifyText(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_AnnotateText() { + ctx := context.Background() + c, err := language.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &languagepb.AnnotateTextRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.AnnotateText(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/language/apiv1beta2/mock_test.go b/vendor/cloud.google.com/go/language/apiv1beta2/mock_test.go new file mode 100644 index 00000000..20ae2123 --- /dev/null +++ b/vendor/cloud.google.com/go/language/apiv1beta2/mock_test.go @@ -0,0 +1,518 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package language + +import ( + languagepb "google.golang.org/genproto/googleapis/cloud/language/v1beta2" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockLanguageServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + languagepb.LanguageServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockLanguageServer) AnalyzeSentiment(ctx context.Context, req *languagepb.AnalyzeSentimentRequest) (*languagepb.AnalyzeSentimentResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*languagepb.AnalyzeSentimentResponse), nil +} + +func (s *mockLanguageServer) AnalyzeEntities(ctx context.Context, req *languagepb.AnalyzeEntitiesRequest) (*languagepb.AnalyzeEntitiesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*languagepb.AnalyzeEntitiesResponse), nil +} + +func (s *mockLanguageServer) AnalyzeEntitySentiment(ctx context.Context, req *languagepb.AnalyzeEntitySentimentRequest) (*languagepb.AnalyzeEntitySentimentResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*languagepb.AnalyzeEntitySentimentResponse), nil +} + +func (s *mockLanguageServer) AnalyzeSyntax(ctx context.Context, req *languagepb.AnalyzeSyntaxRequest) (*languagepb.AnalyzeSyntaxResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*languagepb.AnalyzeSyntaxResponse), nil +} + +func (s *mockLanguageServer) ClassifyText(ctx context.Context, req *languagepb.ClassifyTextRequest) (*languagepb.ClassifyTextResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*languagepb.ClassifyTextResponse), nil +} + +func (s *mockLanguageServer) AnnotateText(ctx context.Context, req *languagepb.AnnotateTextRequest) (*languagepb.AnnotateTextResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*languagepb.AnnotateTextResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockLanguage mockLanguageServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + languagepb.RegisterLanguageServiceServer(serv, &mockLanguage) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestLanguageServiceAnalyzeSentiment(t *testing.T) { + var language string = "language-1613589672" + var expectedResponse = &languagepb.AnalyzeSentimentResponse{ + Language: language, + } + + mockLanguage.err = nil + mockLanguage.reqs = nil + + mockLanguage.resps = append(mockLanguage.resps[:0], expectedResponse) + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeSentimentRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeSentiment(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLanguage.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLanguageServiceAnalyzeSentimentError(t *testing.T) { + errCode := codes.PermissionDenied + mockLanguage.err = gstatus.Error(errCode, "test error") + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeSentimentRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeSentiment(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestLanguageServiceAnalyzeEntities(t *testing.T) { + var language string = "language-1613589672" + var expectedResponse = &languagepb.AnalyzeEntitiesResponse{ + Language: language, + } + + mockLanguage.err = nil + mockLanguage.reqs = nil + + mockLanguage.resps = append(mockLanguage.resps[:0], expectedResponse) + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeEntitiesRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeEntities(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLanguage.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLanguageServiceAnalyzeEntitiesError(t *testing.T) { + errCode := codes.PermissionDenied + mockLanguage.err = gstatus.Error(errCode, "test error") + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeEntitiesRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeEntities(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestLanguageServiceAnalyzeEntitySentiment(t *testing.T) { + var language string = "language-1613589672" + var expectedResponse = &languagepb.AnalyzeEntitySentimentResponse{ + Language: language, + } + + mockLanguage.err = nil + mockLanguage.reqs = nil + + mockLanguage.resps = append(mockLanguage.resps[:0], expectedResponse) + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeEntitySentimentRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeEntitySentiment(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLanguage.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLanguageServiceAnalyzeEntitySentimentError(t *testing.T) { + errCode := codes.PermissionDenied + mockLanguage.err = gstatus.Error(errCode, "test error") + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeEntitySentimentRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeEntitySentiment(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestLanguageServiceAnalyzeSyntax(t *testing.T) { + var language string = "language-1613589672" + var expectedResponse = &languagepb.AnalyzeSyntaxResponse{ + Language: language, + } + + mockLanguage.err = nil + mockLanguage.reqs = nil + + mockLanguage.resps = append(mockLanguage.resps[:0], expectedResponse) + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeSyntaxRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeSyntax(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLanguage.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLanguageServiceAnalyzeSyntaxError(t *testing.T) { + errCode := codes.PermissionDenied + mockLanguage.err = gstatus.Error(errCode, "test error") + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.AnalyzeSyntaxRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnalyzeSyntax(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestLanguageServiceClassifyText(t *testing.T) { + var expectedResponse *languagepb.ClassifyTextResponse = &languagepb.ClassifyTextResponse{} + + mockLanguage.err = nil + mockLanguage.reqs = nil + + mockLanguage.resps = append(mockLanguage.resps[:0], expectedResponse) + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.ClassifyTextRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ClassifyText(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLanguage.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLanguageServiceClassifyTextError(t *testing.T) { + errCode := codes.PermissionDenied + mockLanguage.err = gstatus.Error(errCode, "test error") + + var document *languagepb.Document = &languagepb.Document{} + var request = &languagepb.ClassifyTextRequest{ + Document: document, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ClassifyText(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestLanguageServiceAnnotateText(t *testing.T) { + var language string = "language-1613589672" + var expectedResponse = &languagepb.AnnotateTextResponse{ + Language: language, + } + + mockLanguage.err = nil + mockLanguage.reqs = nil + + mockLanguage.resps = append(mockLanguage.resps[:0], expectedResponse) + + var document *languagepb.Document = &languagepb.Document{} + var features *languagepb.AnnotateTextRequest_Features = &languagepb.AnnotateTextRequest_Features{} + var request = &languagepb.AnnotateTextRequest{ + Document: document, + Features: features, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnnotateText(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLanguage.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLanguageServiceAnnotateTextError(t *testing.T) { + errCode := codes.PermissionDenied + mockLanguage.err = gstatus.Error(errCode, "test error") + + var document *languagepb.Document = &languagepb.Document{} + var features *languagepb.AnnotateTextRequest_Features = &languagepb.AnnotateTextRequest_Features{} + var request = &languagepb.AnnotateTextRequest{ + Document: document, + Features: features, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.AnnotateText(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/license_test.go b/vendor/cloud.google.com/go/license_test.go new file mode 100644 index 00000000..a30cad19 --- /dev/null +++ b/vendor/cloud.google.com/go/license_test.go @@ -0,0 +1,74 @@ +// Copyright 2016 Google LLC +// +// 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 cloud + +import ( + "bytes" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" +) + +var sentinels = []string{ + "Copyright", + "Google", + `Licensed under the Apache License, Version 2.0 (the "License");`, +} + +func TestLicense(t *testing.T) { + t.Parallel() + err := filepath.Walk(".", func(path string, fi os.FileInfo, err error) error { + if err != nil { + return err + } + + if ext := filepath.Ext(path); ext != ".go" && ext != ".proto" { + return nil + } + if strings.HasSuffix(path, ".pb.go") { + // .pb.go files are generated from the proto files. + // .proto files must have license headers. + return nil + } + if path == "bigtable/cmd/cbt/cbtdoc.go" { + // Automatically generated. + return nil + } + if path == "cmd/go-cloud-debug-agent/internal/debug/elf/elf.go" { + // BSD license, which is compatible, is embedded in the file. + return nil + } + src, err := ioutil.ReadFile(path) + if err != nil { + return nil + } + src = src[:300] // Ensure all of the sentinel values are at the top of the file. + + // Find license + for _, sentinel := range sentinels { + if !bytes.Contains(src, []byte(sentinel)) { + t.Errorf("%v: license header not present. want %q", path, sentinel) + return nil + } + } + + return nil + }) + if err != nil { + t.Fatal(err) + } +} diff --git a/vendor/cloud.google.com/go/logging/apiv2/README.md b/vendor/cloud.google.com/go/logging/apiv2/README.md new file mode 100644 index 00000000..d2d9a176 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/apiv2/README.md @@ -0,0 +1,11 @@ +Auto-generated logging v2 clients +================================= + +This package includes auto-generated clients for the logging v2 API. + +Use the handwritten logging client (in the parent directory, +cloud.google.com/go/logging) in preference to this. + +This code is EXPERIMENTAL and subject to CHANGE AT ANY TIME. + + diff --git a/vendor/cloud.google.com/go/logging/apiv2/WriteLogEntries_smoke_test.go b/vendor/cloud.google.com/go/logging/apiv2/WriteLogEntries_smoke_test.go new file mode 100644 index 00000000..ed8d1d02 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/apiv2/WriteLogEntries_smoke_test.go @@ -0,0 +1,68 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package logging + +import ( + loggingpb "google.golang.org/genproto/googleapis/logging/v2" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestLoggingServiceV2Smoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var entries []*loggingpb.LogEntry = nil + var formattedLogName string = fmt.Sprintf("projects/%s/logs/%s", projectId, "test-"+strconv.FormatInt(time.Now().UnixNano(), 10)+"") + var request = &loggingpb.WriteLogEntriesRequest{ + Entries: entries, + LogName: formattedLogName, + } + + if _, err := c.WriteLogEntries(ctx, request); err != nil { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/logging/apiv2/config_client.go b/vendor/cloud.google.com/go/logging/apiv2/config_client.go new file mode 100644 index 00000000..b711c0aa --- /dev/null +++ b/vendor/cloud.google.com/go/logging/apiv2/config_client.go @@ -0,0 +1,427 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package logging + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + loggingpb "google.golang.org/genproto/googleapis/logging/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// ConfigCallOptions contains the retry settings for each method of ConfigClient. +type ConfigCallOptions struct { + ListSinks []gax.CallOption + GetSink []gax.CallOption + CreateSink []gax.CallOption + UpdateSink []gax.CallOption + DeleteSink []gax.CallOption + ListExclusions []gax.CallOption + GetExclusion []gax.CallOption + CreateExclusion []gax.CallOption + UpdateExclusion []gax.CallOption + DeleteExclusion []gax.CallOption +} + +func defaultConfigClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("logging.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultConfigCallOptions() *ConfigCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Internal, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &ConfigCallOptions{ + ListSinks: retry[[2]string{"default", "idempotent"}], + GetSink: retry[[2]string{"default", "idempotent"}], + CreateSink: retry[[2]string{"default", "non_idempotent"}], + UpdateSink: retry[[2]string{"default", "idempotent"}], + DeleteSink: retry[[2]string{"default", "idempotent"}], + ListExclusions: retry[[2]string{"default", "idempotent"}], + GetExclusion: retry[[2]string{"default", "idempotent"}], + CreateExclusion: retry[[2]string{"default", "non_idempotent"}], + UpdateExclusion: retry[[2]string{"default", "non_idempotent"}], + DeleteExclusion: retry[[2]string{"default", "idempotent"}], + } +} + +// ConfigClient is a client for interacting with Stackdriver Logging API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type ConfigClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + configClient loggingpb.ConfigServiceV2Client + + // The call options for this service. + CallOptions *ConfigCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewConfigClient creates a new config service v2 client. +// +// Service for configuring sinks used to export log entries out of +// Logging. +func NewConfigClient(ctx context.Context, opts ...option.ClientOption) (*ConfigClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultConfigClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &ConfigClient{ + conn: conn, + CallOptions: defaultConfigCallOptions(), + + configClient: loggingpb.NewConfigServiceV2Client(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *ConfigClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *ConfigClient) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *ConfigClient) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListSinks lists sinks. +func (c *ConfigClient) ListSinks(ctx context.Context, req *loggingpb.ListSinksRequest, opts ...gax.CallOption) *LogSinkIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListSinks[0:len(c.CallOptions.ListSinks):len(c.CallOptions.ListSinks)], opts...) + it := &LogSinkIterator{} + req = proto.Clone(req).(*loggingpb.ListSinksRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*loggingpb.LogSink, string, error) { + var resp *loggingpb.ListSinksResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.configClient.ListSinks(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Sinks, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetSink gets a sink. +func (c *ConfigClient) GetSink(ctx context.Context, req *loggingpb.GetSinkRequest, opts ...gax.CallOption) (*loggingpb.LogSink, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetSink[0:len(c.CallOptions.GetSink):len(c.CallOptions.GetSink)], opts...) + var resp *loggingpb.LogSink + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.configClient.GetSink(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateSink creates a sink that exports specified log entries to a destination. The +// export of newly-ingested log entries begins immediately, unless the sink's +// writer_identity is not permitted to write to the destination. A sink can +// export log entries only from the resource owning the sink. +func (c *ConfigClient) CreateSink(ctx context.Context, req *loggingpb.CreateSinkRequest, opts ...gax.CallOption) (*loggingpb.LogSink, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateSink[0:len(c.CallOptions.CreateSink):len(c.CallOptions.CreateSink)], opts...) + var resp *loggingpb.LogSink + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.configClient.CreateSink(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateSink updates a sink. This method replaces the following fields in the existing +// sink with values from the new sink: destination, and filter. +// The updated sink might also have a new writer_identity; see the +// unique_writer_identity field. +func (c *ConfigClient) UpdateSink(ctx context.Context, req *loggingpb.UpdateSinkRequest, opts ...gax.CallOption) (*loggingpb.LogSink, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateSink[0:len(c.CallOptions.UpdateSink):len(c.CallOptions.UpdateSink)], opts...) + var resp *loggingpb.LogSink + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.configClient.UpdateSink(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteSink deletes a sink. If the sink has a unique writer_identity, then that +// service account is also deleted. +func (c *ConfigClient) DeleteSink(ctx context.Context, req *loggingpb.DeleteSinkRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteSink[0:len(c.CallOptions.DeleteSink):len(c.CallOptions.DeleteSink)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.configClient.DeleteSink(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ListExclusions lists all the exclusions in a parent resource. +func (c *ConfigClient) ListExclusions(ctx context.Context, req *loggingpb.ListExclusionsRequest, opts ...gax.CallOption) *LogExclusionIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListExclusions[0:len(c.CallOptions.ListExclusions):len(c.CallOptions.ListExclusions)], opts...) + it := &LogExclusionIterator{} + req = proto.Clone(req).(*loggingpb.ListExclusionsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*loggingpb.LogExclusion, string, error) { + var resp *loggingpb.ListExclusionsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.configClient.ListExclusions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Exclusions, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetExclusion gets the description of an exclusion. +func (c *ConfigClient) GetExclusion(ctx context.Context, req *loggingpb.GetExclusionRequest, opts ...gax.CallOption) (*loggingpb.LogExclusion, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetExclusion[0:len(c.CallOptions.GetExclusion):len(c.CallOptions.GetExclusion)], opts...) + var resp *loggingpb.LogExclusion + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.configClient.GetExclusion(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateExclusion creates a new exclusion in a specified parent resource. +// Only log entries belonging to that resource can be excluded. +// You can have up to 10 exclusions in a resource. +func (c *ConfigClient) CreateExclusion(ctx context.Context, req *loggingpb.CreateExclusionRequest, opts ...gax.CallOption) (*loggingpb.LogExclusion, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateExclusion[0:len(c.CallOptions.CreateExclusion):len(c.CallOptions.CreateExclusion)], opts...) + var resp *loggingpb.LogExclusion + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.configClient.CreateExclusion(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateExclusion changes one or more properties of an existing exclusion. +func (c *ConfigClient) UpdateExclusion(ctx context.Context, req *loggingpb.UpdateExclusionRequest, opts ...gax.CallOption) (*loggingpb.LogExclusion, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateExclusion[0:len(c.CallOptions.UpdateExclusion):len(c.CallOptions.UpdateExclusion)], opts...) + var resp *loggingpb.LogExclusion + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.configClient.UpdateExclusion(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteExclusion deletes an exclusion. +func (c *ConfigClient) DeleteExclusion(ctx context.Context, req *loggingpb.DeleteExclusionRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteExclusion[0:len(c.CallOptions.DeleteExclusion):len(c.CallOptions.DeleteExclusion)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.configClient.DeleteExclusion(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// LogExclusionIterator manages a stream of *loggingpb.LogExclusion. +type LogExclusionIterator struct { + items []*loggingpb.LogExclusion + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*loggingpb.LogExclusion, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *LogExclusionIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *LogExclusionIterator) Next() (*loggingpb.LogExclusion, error) { + var item *loggingpb.LogExclusion + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *LogExclusionIterator) bufLen() int { + return len(it.items) +} + +func (it *LogExclusionIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// LogSinkIterator manages a stream of *loggingpb.LogSink. +type LogSinkIterator struct { + items []*loggingpb.LogSink + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*loggingpb.LogSink, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *LogSinkIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *LogSinkIterator) Next() (*loggingpb.LogSink, error) { + var item *loggingpb.LogSink + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *LogSinkIterator) bufLen() int { + return len(it.items) +} + +func (it *LogSinkIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/logging/apiv2/config_client_example_test.go b/vendor/cloud.google.com/go/logging/apiv2/config_client_example_test.go new file mode 100644 index 00000000..5462d589 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/apiv2/config_client_example_test.go @@ -0,0 +1,223 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package logging_test + +import ( + "context" + + logging "cloud.google.com/go/logging/apiv2" + "google.golang.org/api/iterator" + loggingpb "google.golang.org/genproto/googleapis/logging/v2" +) + +func ExampleNewConfigClient() { + ctx := context.Background() + c, err := logging.NewConfigClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleConfigClient_ListSinks() { + ctx := context.Background() + c, err := logging.NewConfigClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.ListSinksRequest{ + // TODO: Fill request struct fields. + } + it := c.ListSinks(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleConfigClient_GetSink() { + ctx := context.Background() + c, err := logging.NewConfigClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.GetSinkRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetSink(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleConfigClient_CreateSink() { + ctx := context.Background() + c, err := logging.NewConfigClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.CreateSinkRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateSink(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleConfigClient_UpdateSink() { + ctx := context.Background() + c, err := logging.NewConfigClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.UpdateSinkRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateSink(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleConfigClient_DeleteSink() { + ctx := context.Background() + c, err := logging.NewConfigClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.DeleteSinkRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteSink(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleConfigClient_ListExclusions() { + ctx := context.Background() + c, err := logging.NewConfigClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.ListExclusionsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListExclusions(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleConfigClient_GetExclusion() { + ctx := context.Background() + c, err := logging.NewConfigClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.GetExclusionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetExclusion(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleConfigClient_CreateExclusion() { + ctx := context.Background() + c, err := logging.NewConfigClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.CreateExclusionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateExclusion(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleConfigClient_UpdateExclusion() { + ctx := context.Background() + c, err := logging.NewConfigClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.UpdateExclusionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateExclusion(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleConfigClient_DeleteExclusion() { + ctx := context.Background() + c, err := logging.NewConfigClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.DeleteExclusionRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteExclusion(ctx, req) + if err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/logging/apiv2/doc.go b/vendor/cloud.google.com/go/logging/apiv2/doc.go new file mode 100644 index 00000000..6ee4c618 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/apiv2/doc.go @@ -0,0 +1,95 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package logging is an auto-generated package for the +// Stackdriver Logging API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Writes log entries and manages your Logging configuration. +// +// Use the client at cloud.google.com/go/logging in preference to this. +package logging // import "cloud.google.com/go/logging/apiv2" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/cloud-platform.read-only", + "https://www.googleapis.com/auth/logging.admin", + "https://www.googleapis.com/auth/logging.read", + "https://www.googleapis.com/auth/logging.write", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/logging/apiv2/logging_client.go b/vendor/cloud.google.com/go/logging/apiv2/logging_client.go new file mode 100644 index 00000000..39588c7c --- /dev/null +++ b/vendor/cloud.google.com/go/logging/apiv2/logging_client.go @@ -0,0 +1,407 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package logging + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres" + loggingpb "google.golang.org/genproto/googleapis/logging/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + DeleteLog []gax.CallOption + WriteLogEntries []gax.CallOption + ListLogEntries []gax.CallOption + ListMonitoredResourceDescriptors []gax.CallOption + ListLogs []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("logging.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Internal, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + DeleteLog: retry[[2]string{"default", "idempotent"}], + WriteLogEntries: retry[[2]string{"default", "non_idempotent"}], + ListLogEntries: retry[[2]string{"default", "idempotent"}], + ListMonitoredResourceDescriptors: retry[[2]string{"default", "idempotent"}], + ListLogs: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Stackdriver Logging API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client loggingpb.LoggingServiceV2Client + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new logging service v2 client. +// +// Service for ingesting and querying logs. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: loggingpb.NewLoggingServiceV2Client(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// DeleteLog deletes all the log entries in a log. +// The log reappears if it receives new entries. +// Log entries written shortly before the delete operation might not be +// deleted. +func (c *Client) DeleteLog(ctx context.Context, req *loggingpb.DeleteLogRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteLog[0:len(c.CallOptions.DeleteLog):len(c.CallOptions.DeleteLog)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteLog(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// WriteLogEntries writes log entries to Logging. This API method is the +// only way to send log entries to Logging. This method +// is used, directly or indirectly, by the Logging agent +// (fluentd) and all logging libraries configured to use Logging. +// A single request may contain log entries for a maximum of 1000 +// different resources (projects, organizations, billing accounts or +// folders) +func (c *Client) WriteLogEntries(ctx context.Context, req *loggingpb.WriteLogEntriesRequest, opts ...gax.CallOption) (*loggingpb.WriteLogEntriesResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.WriteLogEntries[0:len(c.CallOptions.WriteLogEntries):len(c.CallOptions.WriteLogEntries)], opts...) + var resp *loggingpb.WriteLogEntriesResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.WriteLogEntries(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListLogEntries lists log entries. Use this method to retrieve log entries from +// Logging. For ways to export log entries, see +// Exporting Logs (at /logging/docs/export). +func (c *Client) ListLogEntries(ctx context.Context, req *loggingpb.ListLogEntriesRequest, opts ...gax.CallOption) *LogEntryIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListLogEntries[0:len(c.CallOptions.ListLogEntries):len(c.CallOptions.ListLogEntries)], opts...) + it := &LogEntryIterator{} + req = proto.Clone(req).(*loggingpb.ListLogEntriesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*loggingpb.LogEntry, string, error) { + var resp *loggingpb.ListLogEntriesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListLogEntries(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Entries, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// ListMonitoredResourceDescriptors lists the descriptors for monitored resource types used by Logging. +func (c *Client) ListMonitoredResourceDescriptors(ctx context.Context, req *loggingpb.ListMonitoredResourceDescriptorsRequest, opts ...gax.CallOption) *MonitoredResourceDescriptorIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListMonitoredResourceDescriptors[0:len(c.CallOptions.ListMonitoredResourceDescriptors):len(c.CallOptions.ListMonitoredResourceDescriptors)], opts...) + it := &MonitoredResourceDescriptorIterator{} + req = proto.Clone(req).(*loggingpb.ListMonitoredResourceDescriptorsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoredrespb.MonitoredResourceDescriptor, string, error) { + var resp *loggingpb.ListMonitoredResourceDescriptorsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListMonitoredResourceDescriptors(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.ResourceDescriptors, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// ListLogs lists the logs in projects, organizations, folders, or billing accounts. +// Only logs that have entries are listed. +func (c *Client) ListLogs(ctx context.Context, req *loggingpb.ListLogsRequest, opts ...gax.CallOption) *StringIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListLogs[0:len(c.CallOptions.ListLogs):len(c.CallOptions.ListLogs)], opts...) + it := &StringIterator{} + req = proto.Clone(req).(*loggingpb.ListLogsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]string, string, error) { + var resp *loggingpb.ListLogsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListLogs(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.LogNames, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// LogEntryIterator manages a stream of *loggingpb.LogEntry. +type LogEntryIterator struct { + items []*loggingpb.LogEntry + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*loggingpb.LogEntry, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *LogEntryIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *LogEntryIterator) Next() (*loggingpb.LogEntry, error) { + var item *loggingpb.LogEntry + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *LogEntryIterator) bufLen() int { + return len(it.items) +} + +func (it *LogEntryIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// MonitoredResourceDescriptorIterator manages a stream of *monitoredrespb.MonitoredResourceDescriptor. +type MonitoredResourceDescriptorIterator struct { + items []*monitoredrespb.MonitoredResourceDescriptor + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*monitoredrespb.MonitoredResourceDescriptor, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *MonitoredResourceDescriptorIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *MonitoredResourceDescriptorIterator) Next() (*monitoredrespb.MonitoredResourceDescriptor, error) { + var item *monitoredrespb.MonitoredResourceDescriptor + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *MonitoredResourceDescriptorIterator) bufLen() int { + return len(it.items) +} + +func (it *MonitoredResourceDescriptorIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// StringIterator manages a stream of string. +type StringIterator struct { + items []string + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []string, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *StringIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *StringIterator) Next() (string, error) { + var item string + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *StringIterator) bufLen() int { + return len(it.items) +} + +func (it *StringIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/logging/apiv2/logging_client_example_test.go b/vendor/cloud.google.com/go/logging/apiv2/logging_client_example_test.go new file mode 100644 index 00000000..edaad8f3 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/apiv2/logging_client_example_test.go @@ -0,0 +1,141 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package logging_test + +import ( + "context" + + logging "cloud.google.com/go/logging/apiv2" + "google.golang.org/api/iterator" + loggingpb "google.golang.org/genproto/googleapis/logging/v2" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := logging.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_DeleteLog() { + ctx := context.Background() + c, err := logging.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.DeleteLogRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteLog(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_WriteLogEntries() { + ctx := context.Background() + c, err := logging.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.WriteLogEntriesRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.WriteLogEntries(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ListLogEntries() { + ctx := context.Background() + c, err := logging.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.ListLogEntriesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListLogEntries(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_ListMonitoredResourceDescriptors() { + ctx := context.Background() + c, err := logging.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.ListMonitoredResourceDescriptorsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListMonitoredResourceDescriptors(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_ListLogs() { + ctx := context.Background() + c, err := logging.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.ListLogsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListLogs(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} diff --git a/vendor/cloud.google.com/go/logging/apiv2/metrics_client.go b/vendor/cloud.google.com/go/logging/apiv2/metrics_client.go new file mode 100644 index 00000000..7e53526c --- /dev/null +++ b/vendor/cloud.google.com/go/logging/apiv2/metrics_client.go @@ -0,0 +1,268 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package logging + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + loggingpb "google.golang.org/genproto/googleapis/logging/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// MetricsCallOptions contains the retry settings for each method of MetricsClient. +type MetricsCallOptions struct { + ListLogMetrics []gax.CallOption + GetLogMetric []gax.CallOption + CreateLogMetric []gax.CallOption + UpdateLogMetric []gax.CallOption + DeleteLogMetric []gax.CallOption +} + +func defaultMetricsClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("logging.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultMetricsCallOptions() *MetricsCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Internal, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &MetricsCallOptions{ + ListLogMetrics: retry[[2]string{"default", "idempotent"}], + GetLogMetric: retry[[2]string{"default", "idempotent"}], + CreateLogMetric: retry[[2]string{"default", "non_idempotent"}], + UpdateLogMetric: retry[[2]string{"default", "idempotent"}], + DeleteLogMetric: retry[[2]string{"default", "idempotent"}], + } +} + +// MetricsClient is a client for interacting with Stackdriver Logging API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type MetricsClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + metricsClient loggingpb.MetricsServiceV2Client + + // The call options for this service. + CallOptions *MetricsCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewMetricsClient creates a new metrics service v2 client. +// +// Service for configuring logs-based metrics. +func NewMetricsClient(ctx context.Context, opts ...option.ClientOption) (*MetricsClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultMetricsClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &MetricsClient{ + conn: conn, + CallOptions: defaultMetricsCallOptions(), + + metricsClient: loggingpb.NewMetricsServiceV2Client(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *MetricsClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *MetricsClient) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *MetricsClient) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListLogMetrics lists logs-based metrics. +func (c *MetricsClient) ListLogMetrics(ctx context.Context, req *loggingpb.ListLogMetricsRequest, opts ...gax.CallOption) *LogMetricIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListLogMetrics[0:len(c.CallOptions.ListLogMetrics):len(c.CallOptions.ListLogMetrics)], opts...) + it := &LogMetricIterator{} + req = proto.Clone(req).(*loggingpb.ListLogMetricsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*loggingpb.LogMetric, string, error) { + var resp *loggingpb.ListLogMetricsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.metricsClient.ListLogMetrics(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Metrics, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetLogMetric gets a logs-based metric. +func (c *MetricsClient) GetLogMetric(ctx context.Context, req *loggingpb.GetLogMetricRequest, opts ...gax.CallOption) (*loggingpb.LogMetric, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetLogMetric[0:len(c.CallOptions.GetLogMetric):len(c.CallOptions.GetLogMetric)], opts...) + var resp *loggingpb.LogMetric + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.metricsClient.GetLogMetric(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateLogMetric creates a logs-based metric. +func (c *MetricsClient) CreateLogMetric(ctx context.Context, req *loggingpb.CreateLogMetricRequest, opts ...gax.CallOption) (*loggingpb.LogMetric, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateLogMetric[0:len(c.CallOptions.CreateLogMetric):len(c.CallOptions.CreateLogMetric)], opts...) + var resp *loggingpb.LogMetric + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.metricsClient.CreateLogMetric(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateLogMetric creates or updates a logs-based metric. +func (c *MetricsClient) UpdateLogMetric(ctx context.Context, req *loggingpb.UpdateLogMetricRequest, opts ...gax.CallOption) (*loggingpb.LogMetric, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateLogMetric[0:len(c.CallOptions.UpdateLogMetric):len(c.CallOptions.UpdateLogMetric)], opts...) + var resp *loggingpb.LogMetric + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.metricsClient.UpdateLogMetric(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteLogMetric deletes a logs-based metric. +func (c *MetricsClient) DeleteLogMetric(ctx context.Context, req *loggingpb.DeleteLogMetricRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteLogMetric[0:len(c.CallOptions.DeleteLogMetric):len(c.CallOptions.DeleteLogMetric)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.metricsClient.DeleteLogMetric(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// LogMetricIterator manages a stream of *loggingpb.LogMetric. +type LogMetricIterator struct { + items []*loggingpb.LogMetric + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*loggingpb.LogMetric, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *LogMetricIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *LogMetricIterator) Next() (*loggingpb.LogMetric, error) { + var item *loggingpb.LogMetric + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *LogMetricIterator) bufLen() int { + return len(it.items) +} + +func (it *LogMetricIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/logging/apiv2/metrics_client_example_test.go b/vendor/cloud.google.com/go/logging/apiv2/metrics_client_example_test.go new file mode 100644 index 00000000..404aea7e --- /dev/null +++ b/vendor/cloud.google.com/go/logging/apiv2/metrics_client_example_test.go @@ -0,0 +1,129 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package logging_test + +import ( + "context" + + logging "cloud.google.com/go/logging/apiv2" + "google.golang.org/api/iterator" + loggingpb "google.golang.org/genproto/googleapis/logging/v2" +) + +func ExampleNewMetricsClient() { + ctx := context.Background() + c, err := logging.NewMetricsClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleMetricsClient_ListLogMetrics() { + ctx := context.Background() + c, err := logging.NewMetricsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.ListLogMetricsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListLogMetrics(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleMetricsClient_GetLogMetric() { + ctx := context.Background() + c, err := logging.NewMetricsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.GetLogMetricRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetLogMetric(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleMetricsClient_CreateLogMetric() { + ctx := context.Background() + c, err := logging.NewMetricsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.CreateLogMetricRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateLogMetric(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleMetricsClient_UpdateLogMetric() { + ctx := context.Background() + c, err := logging.NewMetricsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.UpdateLogMetricRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateLogMetric(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleMetricsClient_DeleteLogMetric() { + ctx := context.Background() + c, err := logging.NewMetricsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &loggingpb.DeleteLogMetricRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteLogMetric(ctx, req) + if err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/logging/apiv2/mock_test.go b/vendor/cloud.google.com/go/logging/apiv2/mock_test.go new file mode 100644 index 00000000..aaaece4e --- /dev/null +++ b/vendor/cloud.google.com/go/logging/apiv2/mock_test.go @@ -0,0 +1,1677 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package logging + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres" + loggingpb "google.golang.org/genproto/googleapis/logging/v2" + field_maskpb "google.golang.org/genproto/protobuf/field_mask" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockLoggingServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + loggingpb.LoggingServiceV2Server + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockLoggingServer) DeleteLog(ctx context.Context, req *loggingpb.DeleteLogRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockLoggingServer) WriteLogEntries(ctx context.Context, req *loggingpb.WriteLogEntriesRequest) (*loggingpb.WriteLogEntriesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.WriteLogEntriesResponse), nil +} + +func (s *mockLoggingServer) ListLogEntries(ctx context.Context, req *loggingpb.ListLogEntriesRequest) (*loggingpb.ListLogEntriesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.ListLogEntriesResponse), nil +} + +func (s *mockLoggingServer) ListMonitoredResourceDescriptors(ctx context.Context, req *loggingpb.ListMonitoredResourceDescriptorsRequest) (*loggingpb.ListMonitoredResourceDescriptorsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.ListMonitoredResourceDescriptorsResponse), nil +} + +func (s *mockLoggingServer) ListLogs(ctx context.Context, req *loggingpb.ListLogsRequest) (*loggingpb.ListLogsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.ListLogsResponse), nil +} + +type mockConfigServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + loggingpb.ConfigServiceV2Server + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockConfigServer) ListSinks(ctx context.Context, req *loggingpb.ListSinksRequest) (*loggingpb.ListSinksResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.ListSinksResponse), nil +} + +func (s *mockConfigServer) GetSink(ctx context.Context, req *loggingpb.GetSinkRequest) (*loggingpb.LogSink, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.LogSink), nil +} + +func (s *mockConfigServer) CreateSink(ctx context.Context, req *loggingpb.CreateSinkRequest) (*loggingpb.LogSink, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.LogSink), nil +} + +func (s *mockConfigServer) UpdateSink(ctx context.Context, req *loggingpb.UpdateSinkRequest) (*loggingpb.LogSink, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.LogSink), nil +} + +func (s *mockConfigServer) DeleteSink(ctx context.Context, req *loggingpb.DeleteSinkRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockConfigServer) ListExclusions(ctx context.Context, req *loggingpb.ListExclusionsRequest) (*loggingpb.ListExclusionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.ListExclusionsResponse), nil +} + +func (s *mockConfigServer) GetExclusion(ctx context.Context, req *loggingpb.GetExclusionRequest) (*loggingpb.LogExclusion, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.LogExclusion), nil +} + +func (s *mockConfigServer) CreateExclusion(ctx context.Context, req *loggingpb.CreateExclusionRequest) (*loggingpb.LogExclusion, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.LogExclusion), nil +} + +func (s *mockConfigServer) UpdateExclusion(ctx context.Context, req *loggingpb.UpdateExclusionRequest) (*loggingpb.LogExclusion, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.LogExclusion), nil +} + +func (s *mockConfigServer) DeleteExclusion(ctx context.Context, req *loggingpb.DeleteExclusionRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +type mockMetricsServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + loggingpb.MetricsServiceV2Server + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockMetricsServer) ListLogMetrics(ctx context.Context, req *loggingpb.ListLogMetricsRequest) (*loggingpb.ListLogMetricsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.ListLogMetricsResponse), nil +} + +func (s *mockMetricsServer) GetLogMetric(ctx context.Context, req *loggingpb.GetLogMetricRequest) (*loggingpb.LogMetric, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.LogMetric), nil +} + +func (s *mockMetricsServer) CreateLogMetric(ctx context.Context, req *loggingpb.CreateLogMetricRequest) (*loggingpb.LogMetric, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.LogMetric), nil +} + +func (s *mockMetricsServer) UpdateLogMetric(ctx context.Context, req *loggingpb.UpdateLogMetricRequest) (*loggingpb.LogMetric, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*loggingpb.LogMetric), nil +} + +func (s *mockMetricsServer) DeleteLogMetric(ctx context.Context, req *loggingpb.DeleteLogMetricRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockLogging mockLoggingServer + mockConfig mockConfigServer + mockMetrics mockMetricsServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + loggingpb.RegisterLoggingServiceV2Server(serv, &mockLogging) + loggingpb.RegisterConfigServiceV2Server(serv, &mockConfig) + loggingpb.RegisterMetricsServiceV2Server(serv, &mockMetrics) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestLoggingServiceV2DeleteLog(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockLogging.err = nil + mockLogging.reqs = nil + + mockLogging.resps = append(mockLogging.resps[:0], expectedResponse) + + var formattedLogName string = fmt.Sprintf("projects/%s/logs/%s", "[PROJECT]", "[LOG]") + var request = &loggingpb.DeleteLogRequest{ + LogName: formattedLogName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteLog(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLogging.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestLoggingServiceV2DeleteLogError(t *testing.T) { + errCode := codes.PermissionDenied + mockLogging.err = gstatus.Error(errCode, "test error") + + var formattedLogName string = fmt.Sprintf("projects/%s/logs/%s", "[PROJECT]", "[LOG]") + var request = &loggingpb.DeleteLogRequest{ + LogName: formattedLogName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteLog(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestLoggingServiceV2WriteLogEntries(t *testing.T) { + var expectedResponse *loggingpb.WriteLogEntriesResponse = &loggingpb.WriteLogEntriesResponse{} + + mockLogging.err = nil + mockLogging.reqs = nil + + mockLogging.resps = append(mockLogging.resps[:0], expectedResponse) + + var entries []*loggingpb.LogEntry = nil + var request = &loggingpb.WriteLogEntriesRequest{ + Entries: entries, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.WriteLogEntries(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLogging.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLoggingServiceV2WriteLogEntriesError(t *testing.T) { + errCode := codes.PermissionDenied + mockLogging.err = gstatus.Error(errCode, "test error") + + var entries []*loggingpb.LogEntry = nil + var request = &loggingpb.WriteLogEntriesRequest{ + Entries: entries, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.WriteLogEntries(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestLoggingServiceV2ListLogEntries(t *testing.T) { + var nextPageToken string = "" + var entriesElement *loggingpb.LogEntry = &loggingpb.LogEntry{} + var entries = []*loggingpb.LogEntry{entriesElement} + var expectedResponse = &loggingpb.ListLogEntriesResponse{ + NextPageToken: nextPageToken, + Entries: entries, + } + + mockLogging.err = nil + mockLogging.reqs = nil + + mockLogging.resps = append(mockLogging.resps[:0], expectedResponse) + + var formattedResourceNames []string = nil + var request = &loggingpb.ListLogEntriesRequest{ + ResourceNames: formattedResourceNames, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListLogEntries(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLogging.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Entries[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLoggingServiceV2ListLogEntriesError(t *testing.T) { + errCode := codes.PermissionDenied + mockLogging.err = gstatus.Error(errCode, "test error") + + var formattedResourceNames []string = nil + var request = &loggingpb.ListLogEntriesRequest{ + ResourceNames: formattedResourceNames, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListLogEntries(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestLoggingServiceV2ListMonitoredResourceDescriptors(t *testing.T) { + var nextPageToken string = "" + var resourceDescriptorsElement *monitoredrespb.MonitoredResourceDescriptor = &monitoredrespb.MonitoredResourceDescriptor{} + var resourceDescriptors = []*monitoredrespb.MonitoredResourceDescriptor{resourceDescriptorsElement} + var expectedResponse = &loggingpb.ListMonitoredResourceDescriptorsResponse{ + NextPageToken: nextPageToken, + ResourceDescriptors: resourceDescriptors, + } + + mockLogging.err = nil + mockLogging.reqs = nil + + mockLogging.resps = append(mockLogging.resps[:0], expectedResponse) + + var request *loggingpb.ListMonitoredResourceDescriptorsRequest = &loggingpb.ListMonitoredResourceDescriptorsRequest{} + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListMonitoredResourceDescriptors(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLogging.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.ResourceDescriptors[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLoggingServiceV2ListMonitoredResourceDescriptorsError(t *testing.T) { + errCode := codes.PermissionDenied + mockLogging.err = gstatus.Error(errCode, "test error") + + var request *loggingpb.ListMonitoredResourceDescriptorsRequest = &loggingpb.ListMonitoredResourceDescriptorsRequest{} + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListMonitoredResourceDescriptors(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestLoggingServiceV2ListLogs(t *testing.T) { + var nextPageToken string = "" + var logNamesElement string = "logNamesElement-1079688374" + var logNames = []string{logNamesElement} + var expectedResponse = &loggingpb.ListLogsResponse{ + NextPageToken: nextPageToken, + LogNames: logNames, + } + + mockLogging.err = nil + mockLogging.reqs = nil + + mockLogging.resps = append(mockLogging.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &loggingpb.ListLogsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListLogs(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockLogging.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.LogNames[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestLoggingServiceV2ListLogsError(t *testing.T) { + errCode := codes.PermissionDenied + mockLogging.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &loggingpb.ListLogsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListLogs(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestConfigServiceV2ListSinks(t *testing.T) { + var nextPageToken string = "" + var sinksElement *loggingpb.LogSink = &loggingpb.LogSink{} + var sinks = []*loggingpb.LogSink{sinksElement} + var expectedResponse = &loggingpb.ListSinksResponse{ + NextPageToken: nextPageToken, + Sinks: sinks, + } + + mockConfig.err = nil + mockConfig.reqs = nil + + mockConfig.resps = append(mockConfig.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &loggingpb.ListSinksRequest{ + Parent: formattedParent, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListSinks(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Sinks[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestConfigServiceV2ListSinksError(t *testing.T) { + errCode := codes.PermissionDenied + mockConfig.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &loggingpb.ListSinksRequest{ + Parent: formattedParent, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListSinks(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestConfigServiceV2GetSink(t *testing.T) { + var name string = "name3373707" + var destination string = "destination-1429847026" + var filter string = "filter-1274492040" + var writerIdentity string = "writerIdentity775638794" + var includeChildren bool = true + var expectedResponse = &loggingpb.LogSink{ + Name: name, + Destination: destination, + Filter: filter, + WriterIdentity: writerIdentity, + IncludeChildren: includeChildren, + } + + mockConfig.err = nil + mockConfig.reqs = nil + + mockConfig.resps = append(mockConfig.resps[:0], expectedResponse) + + var formattedSinkName string = fmt.Sprintf("projects/%s/sinks/%s", "[PROJECT]", "[SINK]") + var request = &loggingpb.GetSinkRequest{ + SinkName: formattedSinkName, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSink(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestConfigServiceV2GetSinkError(t *testing.T) { + errCode := codes.PermissionDenied + mockConfig.err = gstatus.Error(errCode, "test error") + + var formattedSinkName string = fmt.Sprintf("projects/%s/sinks/%s", "[PROJECT]", "[SINK]") + var request = &loggingpb.GetSinkRequest{ + SinkName: formattedSinkName, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSink(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestConfigServiceV2CreateSink(t *testing.T) { + var name string = "name3373707" + var destination string = "destination-1429847026" + var filter string = "filter-1274492040" + var writerIdentity string = "writerIdentity775638794" + var includeChildren bool = true + var expectedResponse = &loggingpb.LogSink{ + Name: name, + Destination: destination, + Filter: filter, + WriterIdentity: writerIdentity, + IncludeChildren: includeChildren, + } + + mockConfig.err = nil + mockConfig.reqs = nil + + mockConfig.resps = append(mockConfig.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var sink *loggingpb.LogSink = &loggingpb.LogSink{} + var request = &loggingpb.CreateSinkRequest{ + Parent: formattedParent, + Sink: sink, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSink(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestConfigServiceV2CreateSinkError(t *testing.T) { + errCode := codes.PermissionDenied + mockConfig.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var sink *loggingpb.LogSink = &loggingpb.LogSink{} + var request = &loggingpb.CreateSinkRequest{ + Parent: formattedParent, + Sink: sink, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSink(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestConfigServiceV2UpdateSink(t *testing.T) { + var name string = "name3373707" + var destination string = "destination-1429847026" + var filter string = "filter-1274492040" + var writerIdentity string = "writerIdentity775638794" + var includeChildren bool = true + var expectedResponse = &loggingpb.LogSink{ + Name: name, + Destination: destination, + Filter: filter, + WriterIdentity: writerIdentity, + IncludeChildren: includeChildren, + } + + mockConfig.err = nil + mockConfig.reqs = nil + + mockConfig.resps = append(mockConfig.resps[:0], expectedResponse) + + var formattedSinkName string = fmt.Sprintf("projects/%s/sinks/%s", "[PROJECT]", "[SINK]") + var sink *loggingpb.LogSink = &loggingpb.LogSink{} + var request = &loggingpb.UpdateSinkRequest{ + SinkName: formattedSinkName, + Sink: sink, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSink(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestConfigServiceV2UpdateSinkError(t *testing.T) { + errCode := codes.PermissionDenied + mockConfig.err = gstatus.Error(errCode, "test error") + + var formattedSinkName string = fmt.Sprintf("projects/%s/sinks/%s", "[PROJECT]", "[SINK]") + var sink *loggingpb.LogSink = &loggingpb.LogSink{} + var request = &loggingpb.UpdateSinkRequest{ + SinkName: formattedSinkName, + Sink: sink, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSink(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestConfigServiceV2DeleteSink(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockConfig.err = nil + mockConfig.reqs = nil + + mockConfig.resps = append(mockConfig.resps[:0], expectedResponse) + + var formattedSinkName string = fmt.Sprintf("projects/%s/sinks/%s", "[PROJECT]", "[SINK]") + var request = &loggingpb.DeleteSinkRequest{ + SinkName: formattedSinkName, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSink(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestConfigServiceV2DeleteSinkError(t *testing.T) { + errCode := codes.PermissionDenied + mockConfig.err = gstatus.Error(errCode, "test error") + + var formattedSinkName string = fmt.Sprintf("projects/%s/sinks/%s", "[PROJECT]", "[SINK]") + var request = &loggingpb.DeleteSinkRequest{ + SinkName: formattedSinkName, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSink(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestConfigServiceV2ListExclusions(t *testing.T) { + var nextPageToken string = "" + var exclusionsElement *loggingpb.LogExclusion = &loggingpb.LogExclusion{} + var exclusions = []*loggingpb.LogExclusion{exclusionsElement} + var expectedResponse = &loggingpb.ListExclusionsResponse{ + NextPageToken: nextPageToken, + Exclusions: exclusions, + } + + mockConfig.err = nil + mockConfig.reqs = nil + + mockConfig.resps = append(mockConfig.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &loggingpb.ListExclusionsRequest{ + Parent: formattedParent, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListExclusions(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Exclusions[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestConfigServiceV2ListExclusionsError(t *testing.T) { + errCode := codes.PermissionDenied + mockConfig.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &loggingpb.ListExclusionsRequest{ + Parent: formattedParent, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListExclusions(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestConfigServiceV2GetExclusion(t *testing.T) { + var name2 string = "name2-1052831874" + var description string = "description-1724546052" + var filter string = "filter-1274492040" + var disabled bool = true + var expectedResponse = &loggingpb.LogExclusion{ + Name: name2, + Description: description, + Filter: filter, + Disabled: disabled, + } + + mockConfig.err = nil + mockConfig.reqs = nil + + mockConfig.resps = append(mockConfig.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/exclusions/%s", "[PROJECT]", "[EXCLUSION]") + var request = &loggingpb.GetExclusionRequest{ + Name: formattedName, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetExclusion(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestConfigServiceV2GetExclusionError(t *testing.T) { + errCode := codes.PermissionDenied + mockConfig.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/exclusions/%s", "[PROJECT]", "[EXCLUSION]") + var request = &loggingpb.GetExclusionRequest{ + Name: formattedName, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetExclusion(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestConfigServiceV2CreateExclusion(t *testing.T) { + var name string = "name3373707" + var description string = "description-1724546052" + var filter string = "filter-1274492040" + var disabled bool = true + var expectedResponse = &loggingpb.LogExclusion{ + Name: name, + Description: description, + Filter: filter, + Disabled: disabled, + } + + mockConfig.err = nil + mockConfig.reqs = nil + + mockConfig.resps = append(mockConfig.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var exclusion *loggingpb.LogExclusion = &loggingpb.LogExclusion{} + var request = &loggingpb.CreateExclusionRequest{ + Parent: formattedParent, + Exclusion: exclusion, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateExclusion(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestConfigServiceV2CreateExclusionError(t *testing.T) { + errCode := codes.PermissionDenied + mockConfig.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var exclusion *loggingpb.LogExclusion = &loggingpb.LogExclusion{} + var request = &loggingpb.CreateExclusionRequest{ + Parent: formattedParent, + Exclusion: exclusion, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateExclusion(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestConfigServiceV2UpdateExclusion(t *testing.T) { + var name2 string = "name2-1052831874" + var description string = "description-1724546052" + var filter string = "filter-1274492040" + var disabled bool = true + var expectedResponse = &loggingpb.LogExclusion{ + Name: name2, + Description: description, + Filter: filter, + Disabled: disabled, + } + + mockConfig.err = nil + mockConfig.reqs = nil + + mockConfig.resps = append(mockConfig.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/exclusions/%s", "[PROJECT]", "[EXCLUSION]") + var exclusion *loggingpb.LogExclusion = &loggingpb.LogExclusion{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &loggingpb.UpdateExclusionRequest{ + Name: formattedName, + Exclusion: exclusion, + UpdateMask: updateMask, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateExclusion(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestConfigServiceV2UpdateExclusionError(t *testing.T) { + errCode := codes.PermissionDenied + mockConfig.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/exclusions/%s", "[PROJECT]", "[EXCLUSION]") + var exclusion *loggingpb.LogExclusion = &loggingpb.LogExclusion{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &loggingpb.UpdateExclusionRequest{ + Name: formattedName, + Exclusion: exclusion, + UpdateMask: updateMask, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateExclusion(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestConfigServiceV2DeleteExclusion(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockConfig.err = nil + mockConfig.reqs = nil + + mockConfig.resps = append(mockConfig.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/exclusions/%s", "[PROJECT]", "[EXCLUSION]") + var request = &loggingpb.DeleteExclusionRequest{ + Name: formattedName, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteExclusion(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockConfig.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestConfigServiceV2DeleteExclusionError(t *testing.T) { + errCode := codes.PermissionDenied + mockConfig.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/exclusions/%s", "[PROJECT]", "[EXCLUSION]") + var request = &loggingpb.DeleteExclusionRequest{ + Name: formattedName, + } + + c, err := NewConfigClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteExclusion(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestMetricsServiceV2ListLogMetrics(t *testing.T) { + var nextPageToken string = "" + var metricsElement *loggingpb.LogMetric = &loggingpb.LogMetric{} + var metrics = []*loggingpb.LogMetric{metricsElement} + var expectedResponse = &loggingpb.ListLogMetricsResponse{ + NextPageToken: nextPageToken, + Metrics: metrics, + } + + mockMetrics.err = nil + mockMetrics.reqs = nil + + mockMetrics.resps = append(mockMetrics.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &loggingpb.ListLogMetricsRequest{ + Parent: formattedParent, + } + + c, err := NewMetricsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListLogMetrics(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockMetrics.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Metrics[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestMetricsServiceV2ListLogMetricsError(t *testing.T) { + errCode := codes.PermissionDenied + mockMetrics.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &loggingpb.ListLogMetricsRequest{ + Parent: formattedParent, + } + + c, err := NewMetricsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListLogMetrics(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestMetricsServiceV2GetLogMetric(t *testing.T) { + var name string = "name3373707" + var description string = "description-1724546052" + var filter string = "filter-1274492040" + var valueExtractor string = "valueExtractor2047672534" + var expectedResponse = &loggingpb.LogMetric{ + Name: name, + Description: description, + Filter: filter, + ValueExtractor: valueExtractor, + } + + mockMetrics.err = nil + mockMetrics.reqs = nil + + mockMetrics.resps = append(mockMetrics.resps[:0], expectedResponse) + + var formattedMetricName string = fmt.Sprintf("projects/%s/metrics/%s", "[PROJECT]", "[METRIC]") + var request = &loggingpb.GetLogMetricRequest{ + MetricName: formattedMetricName, + } + + c, err := NewMetricsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetLogMetric(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockMetrics.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestMetricsServiceV2GetLogMetricError(t *testing.T) { + errCode := codes.PermissionDenied + mockMetrics.err = gstatus.Error(errCode, "test error") + + var formattedMetricName string = fmt.Sprintf("projects/%s/metrics/%s", "[PROJECT]", "[METRIC]") + var request = &loggingpb.GetLogMetricRequest{ + MetricName: formattedMetricName, + } + + c, err := NewMetricsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetLogMetric(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestMetricsServiceV2CreateLogMetric(t *testing.T) { + var name string = "name3373707" + var description string = "description-1724546052" + var filter string = "filter-1274492040" + var valueExtractor string = "valueExtractor2047672534" + var expectedResponse = &loggingpb.LogMetric{ + Name: name, + Description: description, + Filter: filter, + ValueExtractor: valueExtractor, + } + + mockMetrics.err = nil + mockMetrics.reqs = nil + + mockMetrics.resps = append(mockMetrics.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var metric *loggingpb.LogMetric = &loggingpb.LogMetric{} + var request = &loggingpb.CreateLogMetricRequest{ + Parent: formattedParent, + Metric: metric, + } + + c, err := NewMetricsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateLogMetric(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockMetrics.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestMetricsServiceV2CreateLogMetricError(t *testing.T) { + errCode := codes.PermissionDenied + mockMetrics.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var metric *loggingpb.LogMetric = &loggingpb.LogMetric{} + var request = &loggingpb.CreateLogMetricRequest{ + Parent: formattedParent, + Metric: metric, + } + + c, err := NewMetricsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateLogMetric(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestMetricsServiceV2UpdateLogMetric(t *testing.T) { + var name string = "name3373707" + var description string = "description-1724546052" + var filter string = "filter-1274492040" + var valueExtractor string = "valueExtractor2047672534" + var expectedResponse = &loggingpb.LogMetric{ + Name: name, + Description: description, + Filter: filter, + ValueExtractor: valueExtractor, + } + + mockMetrics.err = nil + mockMetrics.reqs = nil + + mockMetrics.resps = append(mockMetrics.resps[:0], expectedResponse) + + var formattedMetricName string = fmt.Sprintf("projects/%s/metrics/%s", "[PROJECT]", "[METRIC]") + var metric *loggingpb.LogMetric = &loggingpb.LogMetric{} + var request = &loggingpb.UpdateLogMetricRequest{ + MetricName: formattedMetricName, + Metric: metric, + } + + c, err := NewMetricsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateLogMetric(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockMetrics.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestMetricsServiceV2UpdateLogMetricError(t *testing.T) { + errCode := codes.PermissionDenied + mockMetrics.err = gstatus.Error(errCode, "test error") + + var formattedMetricName string = fmt.Sprintf("projects/%s/metrics/%s", "[PROJECT]", "[METRIC]") + var metric *loggingpb.LogMetric = &loggingpb.LogMetric{} + var request = &loggingpb.UpdateLogMetricRequest{ + MetricName: formattedMetricName, + Metric: metric, + } + + c, err := NewMetricsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateLogMetric(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestMetricsServiceV2DeleteLogMetric(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockMetrics.err = nil + mockMetrics.reqs = nil + + mockMetrics.resps = append(mockMetrics.resps[:0], expectedResponse) + + var formattedMetricName string = fmt.Sprintf("projects/%s/metrics/%s", "[PROJECT]", "[METRIC]") + var request = &loggingpb.DeleteLogMetricRequest{ + MetricName: formattedMetricName, + } + + c, err := NewMetricsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteLogMetric(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockMetrics.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestMetricsServiceV2DeleteLogMetricError(t *testing.T) { + errCode := codes.PermissionDenied + mockMetrics.err = gstatus.Error(errCode, "test error") + + var formattedMetricName string = fmt.Sprintf("projects/%s/metrics/%s", "[PROJECT]", "[METRIC]") + var request = &loggingpb.DeleteLogMetricRequest{ + MetricName: formattedMetricName, + } + + c, err := NewMetricsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteLogMetric(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} diff --git a/vendor/cloud.google.com/go/logging/apiv2/path_funcs.go b/vendor/cloud.google.com/go/logging/apiv2/path_funcs.go new file mode 100644 index 00000000..37bbe9d4 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/apiv2/path_funcs.go @@ -0,0 +1,107 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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 logging + +// ConfigProjectPath returns the path for the project resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s", project) +// instead. +func ConfigProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} + +// ConfigSinkPath returns the path for the sink resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/sinks/%s", project, sink) +// instead. +func ConfigSinkPath(project, sink string) string { + return "" + + "projects/" + + project + + "/sinks/" + + sink + + "" +} + +// ConfigExclusionPath returns the path for the exclusion resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/exclusions/%s", project, exclusion) +// instead. +func ConfigExclusionPath(project, exclusion string) string { + return "" + + "projects/" + + project + + "/exclusions/" + + exclusion + + "" +} + +// ProjectPath returns the path for the project resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s", project) +// instead. +func ProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} + +// LogPath returns the path for the log resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/logs/%s", project, log) +// instead. +func LogPath(project, log string) string { + return "" + + "projects/" + + project + + "/logs/" + + log + + "" +} + +// MetricsProjectPath returns the path for the project resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s", project) +// instead. +func MetricsProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} + +// MetricsMetricPath returns the path for the metric resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/metrics/%s", project, metric) +// instead. +func MetricsMetricPath(project, metric string) string { + return "" + + "projects/" + + project + + "/metrics/" + + metric + + "" +} diff --git a/vendor/cloud.google.com/go/logging/doc.go b/vendor/cloud.google.com/go/logging/doc.go new file mode 100644 index 00000000..2f3c1815 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/doc.go @@ -0,0 +1,134 @@ +// Copyright 2016 Google LLC +// +// 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 logging contains a Stackdriver Logging client suitable for writing logs. +For reading logs, and working with sinks, metrics and monitored resources, +see package cloud.google.com/go/logging/logadmin. + +This client uses Logging API v2. +See https://cloud.google.com/logging/docs/api/v2/ for an introduction to the API. + + +Note: This package is in beta. Some backwards-incompatible changes may occur. + + +Creating a Client + +Use a Client to interact with the Stackdriver Logging API. + + // Create a Client + ctx := context.Background() + client, err := logging.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + + +Basic Usage + +For most use cases, you'll want to add log entries to a buffer to be periodically +flushed (automatically and asynchronously) to the Stackdriver Logging service. + + // Initialize a logger + lg := client.Logger("my-log") + + // Add entry to log buffer + lg.Log(logging.Entry{Payload: "something happened!"}) + + +Closing your Client + +You should call Client.Close before your program exits to flush any buffered log entries to the Stackdriver Logging service. + + // Close the client when finished. + err = client.Close() + if err != nil { + // TODO: Handle error. + } + + +Synchronous Logging + +For critical errors, you may want to send your log entries immediately. +LogSync is slow and will block until the log entry has been sent, so it is +not recommended for normal use. + + lg.LogSync(ctx, logging.Entry{Payload: "ALERT! Something critical happened!"}) + + +Payloads + +An entry payload can be a string, as in the examples above. It can also be any value +that can be marshaled to a JSON object, like a map[string]interface{} or a struct: + + type MyEntry struct { + Name string + Count int + } + lg.Log(logging.Entry{Payload: MyEntry{Name: "Bob", Count: 3}}) + +If you have a []byte of JSON, wrap it in json.RawMessage: + + j := []byte(`{"Name": "Bob", "Count": 3}`) + lg.Log(logging.Entry{Payload: json.RawMessage(j)}) + + +The Standard Logger Interface + +You may want use a standard log.Logger in your program. + + // stdlg implements log.Logger + stdlg := lg.StandardLogger(logging.Info) + stdlg.Println("some info") + + +Log Levels + +An Entry may have one of a number of severity levels associated with it. + + logging.Entry{ + Payload: "something terrible happened!", + Severity: logging.Critical, + } + + +Viewing Logs + +You can view Stackdriver logs for projects at +https://console.cloud.google.com/logs/viewer. Use the dropdown at the top left. When +running from a Google Cloud Platform VM, select "GCE VM Instance". Otherwise, select +"Google Project" and then the project ID. Logs for organizations, folders and billing +accounts can be viewed on the command line with the "gcloud logging read" command. + + +Grouping Logs by Request + +To group all the log entries written during a single HTTP request, create two +Loggers, a "parent" and a "child," with different log IDs. Both should be in the same +project, and have the same MonitoredResouce type and labels. + +- Parent entries must have HTTPRequest.Request populated. (Strictly speaking, only the URL is necessary.) + +- A child entry's timestamp must be within the time interval covered by the parent request (i.e., older +than parent.Timestamp, and newer than parent.Timestamp - parent.HTTPRequest.Latency, assuming the +parent timestamp marks the end of the request. + +- The trace field must be populated in all of the entries and match exactly. + +You should observe the child log entries grouped under the parent on the console. The +parent entry will not inherit the severity of its children; you must update the +parent severity yourself. +*/ +package logging // import "cloud.google.com/go/logging" diff --git a/vendor/cloud.google.com/go/logging/examples_test.go b/vendor/cloud.google.com/go/logging/examples_test.go new file mode 100644 index 00000000..b9623eea --- /dev/null +++ b/vendor/cloud.google.com/go/logging/examples_test.go @@ -0,0 +1,183 @@ +// Copyright 2016 Google LLC +// +// 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 logging_test + +import ( + "context" + "encoding/json" + "fmt" + "os" + + "cloud.google.com/go/logging" + "go.opencensus.io/trace" +) + +func ExampleNewClient() { + ctx := context.Background() + client, err := logging.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + // Use client to manage logs, metrics and sinks. + // Close the client when finished. + if err := client.Close(); err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_Ping() { + ctx := context.Background() + client, err := logging.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + if err := client.Ping(ctx); err != nil { + // TODO: Handle error. + } +} + +// Although Logger.Flush and Client.Close both return errors, they don't tell you +// whether the errors were frequent or significant. For most programs, it doesn't +// matter if there were a few errors while writing logs, although if those few errors +// indicated a bug in your program, you might want to know about them. The best way +// to handle errors is by setting the OnError function. If it runs quickly, it will +// see every error generated during logging. +func ExampleNewClient_errorFunc() { + ctx := context.Background() + client, err := logging.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + // Print all errors to stdout, and count them. Multiple calls to the OnError + // function never happen concurrently, so there is no need for locking nErrs, + // provided you don't read it until after the logging client is closed. + var nErrs int + client.OnError = func(e error) { + fmt.Fprintf(os.Stdout, "logging: %v", e) + nErrs++ + } + // Use client to manage logs, metrics and sinks. + // Close the client when finished. + if err := client.Close(); err != nil { + // TODO: Handle error. + } + fmt.Printf("saw %d errors\n", nErrs) +} + +func ExampleClient_Logger() { + ctx := context.Background() + client, err := logging.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + lg := client.Logger("my-log") + _ = lg // TODO: use the Logger. +} + +func ExampleLogger_LogSync() { + ctx := context.Background() + client, err := logging.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + lg := client.Logger("my-log") + err = lg.LogSync(ctx, logging.Entry{Payload: "red alert"}) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleLogger_Log() { + ctx := context.Background() + client, err := logging.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + lg := client.Logger("my-log") + lg.Log(logging.Entry{Payload: "something happened"}) +} + +// An Entry payload can be anything that marshals to a +// JSON object, like a struct. +func ExampleLogger_Log_struct() { + type MyEntry struct { + Name string + Count int + } + + ctx := context.Background() + client, err := logging.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + lg := client.Logger("my-log") + lg.Log(logging.Entry{Payload: MyEntry{Name: "Bob", Count: 3}}) +} + +// To log a JSON value, wrap it in json.RawMessage. +func ExampleLogger_Log_json() { + ctx := context.Background() + client, err := logging.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + lg := client.Logger("my-log") + j := []byte(`{"Name": "Bob", "Count": 3}`) + lg.Log(logging.Entry{Payload: json.RawMessage(j)}) +} + +func ExampleLogger_Flush() { + ctx := context.Background() + client, err := logging.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + lg := client.Logger("my-log") + lg.Log(logging.Entry{Payload: "something happened"}) + lg.Flush() +} + +func ExampleLogger_StandardLogger() { + ctx := context.Background() + client, err := logging.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + lg := client.Logger("my-log") + slg := lg.StandardLogger(logging.Info) + slg.Println("an informative message") +} + +func ExampleParseSeverity() { + sev := logging.ParseSeverity("ALERT") + fmt.Println(sev) + // Output: Alert +} + +// This example shows how to create a Logger that disables OpenCensus tracing of the +// WriteLogEntries RPC. +func ExampleContextFunc() { + ctx := context.Background() + client, err := logging.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + lg := client.Logger("logID", logging.ContextFunc(func() (context.Context, func()) { + ctx, span := trace.StartSpan(context.Background(), "this span will not be exported", + trace.WithSampler(trace.NeverSample())) + return ctx, span.End + })) + _ = lg // TODO: Use lg +} diff --git a/vendor/cloud.google.com/go/logging/internal/common.go b/vendor/cloud.google.com/go/logging/internal/common.go new file mode 100644 index 00000000..c5788feb --- /dev/null +++ b/vendor/cloud.google.com/go/logging/internal/common.go @@ -0,0 +1,41 @@ +// Copyright 2016 Google LLC +// +// 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 internal + +import ( + "fmt" + "strings" +) + +const ( + // ProdAddr is the production address. + ProdAddr = "logging.googleapis.com:443" +) + +// LogPath creates a formatted path from a parent and a logID. +func LogPath(parent, logID string) string { + logID = strings.Replace(logID, "/", "%2F", -1) + return fmt.Sprintf("%s/logs/%s", parent, logID) +} + +// LogIDFromPath parses and returns the ID from a log path. +func LogIDFromPath(parent, path string) string { + start := len(parent) + len("/logs/") + if len(path) < start { + return "" + } + logID := path[start:] + return strings.Replace(logID, "%2F", "/", -1) +} diff --git a/vendor/cloud.google.com/go/logging/internal/testing/equal.go b/vendor/cloud.google.com/go/logging/internal/testing/equal.go new file mode 100644 index 00000000..f87caf3a --- /dev/null +++ b/vendor/cloud.google.com/go/logging/internal/testing/equal.go @@ -0,0 +1,41 @@ +/* +Copyright 2017 Google LLC + +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 testing + +import ( + "fmt" + + "github.com/golang/protobuf/proto" +) + +// PayloadEqual compares two payloads, assuming they are both proto.Messages or both strings. +func PayloadEqual(a, b interface{}) bool { + if a == nil && b == nil { + return true + } + if a == nil || b == nil { + return false + } + switch a := a.(type) { + case proto.Message: + return proto.Equal(a, b.(proto.Message)) + case string: + return a == b.(string) + default: + panic(fmt.Sprintf("payloadEqual: unexpected type %T", a)) + } +} diff --git a/vendor/cloud.google.com/go/logging/internal/testing/fake.go b/vendor/cloud.google.com/go/logging/internal/testing/fake.go new file mode 100644 index 00000000..ecec835d --- /dev/null +++ b/vendor/cloud.google.com/go/logging/internal/testing/fake.go @@ -0,0 +1,438 @@ +/* +Copyright 2016 Google LLC + +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 testing provides support for testing the logging client. +package testing + +import ( + "context" + "errors" + "fmt" + "regexp" + "sort" + "strings" + "sync" + "time" + + "cloud.google.com/go/internal/testutil" + emptypb "github.com/golang/protobuf/ptypes/empty" + tspb "github.com/golang/protobuf/ptypes/timestamp" + lpb "google.golang.org/genproto/googleapis/api/label" + mrpb "google.golang.org/genproto/googleapis/api/monitoredres" + logpb "google.golang.org/genproto/googleapis/logging/v2" +) + +type loggingHandler struct { + logpb.LoggingServiceV2Server + + mu sync.Mutex + logs map[string][]*logpb.LogEntry // indexed by log name +} + +type configHandler struct { + logpb.ConfigServiceV2Server + + mu sync.Mutex + sinks map[string]*logpb.LogSink // indexed by (full) sink name +} + +type metricHandler struct { + logpb.MetricsServiceV2Server + + mu sync.Mutex + metrics map[string]*logpb.LogMetric // indexed by (full) metric name +} + +// NewServer creates a new in-memory fake server implementing the logging service. +// It returns the address of the server. +func NewServer() (string, error) { + srv, err := testutil.NewServer() + if err != nil { + return "", err + } + logpb.RegisterLoggingServiceV2Server(srv.Gsrv, &loggingHandler{ + logs: make(map[string][]*logpb.LogEntry), + }) + logpb.RegisterConfigServiceV2Server(srv.Gsrv, &configHandler{ + sinks: make(map[string]*logpb.LogSink), + }) + logpb.RegisterMetricsServiceV2Server(srv.Gsrv, &metricHandler{ + metrics: make(map[string]*logpb.LogMetric), + }) + srv.Start() + return srv.Addr, nil +} + +// DeleteLog deletes a log and all its log entries. The log will reappear if it +// receives new entries. +func (h *loggingHandler) DeleteLog(_ context.Context, req *logpb.DeleteLogRequest) (*emptypb.Empty, error) { + // TODO(jba): return NotFound if log isn't there? + h.mu.Lock() + defer h.mu.Unlock() + delete(h.logs, req.LogName) + return &emptypb.Empty{}, nil +} + +// The only IDs that WriteLogEntries will accept. +// Important for testing Ping. +const ( + ValidProjectID = "PROJECT_ID" + ValidOrgID = "433637338589" + + SharedServiceAccount = "serviceAccount:cloud-logs@system.gserviceaccount.com" +) + +// WriteLogEntries writes log entries to Stackdriver Logging. All log entries in +// Stackdriver Logging are written by this method. +func (h *loggingHandler) WriteLogEntries(_ context.Context, req *logpb.WriteLogEntriesRequest) (*logpb.WriteLogEntriesResponse, error) { + if !strings.HasPrefix(req.LogName, "projects/"+ValidProjectID+"/") && !strings.HasPrefix(req.LogName, "organizations/"+ValidOrgID+"/") { + return nil, fmt.Errorf("bad LogName: %q", req.LogName) + } + // TODO(jba): support insertId? + h.mu.Lock() + defer h.mu.Unlock() + for _, e := range req.Entries { + // Assign timestamp if missing. + if e.Timestamp == nil { + e.Timestamp = &tspb.Timestamp{Seconds: time.Now().Unix(), Nanos: 0} + } + // Fill from common fields in request. + if e.LogName == "" { + e.LogName = req.LogName + } + if e.Resource == nil { + // TODO(jba): use a global one if nil? + e.Resource = req.Resource + } + for k, v := range req.Labels { + if _, ok := e.Labels[k]; !ok { + e.Labels[k] = v + } + } + + // Store by log name. + h.logs[e.LogName] = append(h.logs[e.LogName], e) + } + return &logpb.WriteLogEntriesResponse{}, nil +} + +// ListLogEntries lists log entries. Use this method to retrieve log entries +// from Stackdriver Logging. +// +// This fake implementation ignores project IDs. It does not support full filtering, only +// expressions of the form "logName = NAME". +func (h *loggingHandler) ListLogEntries(_ context.Context, req *logpb.ListLogEntriesRequest) (*logpb.ListLogEntriesResponse, error) { + h.mu.Lock() + defer h.mu.Unlock() + entries, err := h.filterEntries(req.Filter) + if err != nil { + return nil, err + } + if err = sortEntries(entries, req.OrderBy); err != nil { + return nil, err + } + + from, to, nextPageToken, err := testutil.PageBounds(int(req.PageSize), req.PageToken, len(entries)) + if err != nil { + return nil, err + } + return &logpb.ListLogEntriesResponse{ + Entries: entries[from:to], + NextPageToken: nextPageToken, + }, nil +} + +func (h *loggingHandler) filterEntries(filter string) ([]*logpb.LogEntry, error) { + logName, err := parseFilter(filter) + if err != nil { + return nil, err + } + if logName != "" { + return h.logs[logName], nil + } + var entries []*logpb.LogEntry + for _, es := range h.logs { + entries = append(entries, es...) + } + return entries, nil +} + +var filterRegexp = regexp.MustCompile(`^logName\s*=\s*"?([-_/.%\w]+)"?`) + +// returns the log name, or "" for the empty filter +func parseFilter(filter string) (string, error) { + if filter == "" { + return "", nil + } + subs := filterRegexp.FindStringSubmatch(filter) + if subs == nil { + return "", invalidArgument(fmt.Sprintf("fake.go: failed to parse filter %s", filter)) + } + return subs[1], nil // cannot panic by construction of regexp +} + +func sortEntries(entries []*logpb.LogEntry, orderBy string) error { + switch orderBy { + case "", "timestamp asc": + sort.Sort(byTimestamp(entries)) + return nil + + case "timestamp desc": + sort.Sort(sort.Reverse(byTimestamp(entries))) + return nil + + default: + return invalidArgument("bad order_by") + } +} + +type byTimestamp []*logpb.LogEntry + +func (s byTimestamp) Len() int { return len(s) } +func (s byTimestamp) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s byTimestamp) Less(i, j int) bool { + c := compareTimestamps(s[i].Timestamp, s[j].Timestamp) + switch { + case c < 0: + return true + case c > 0: + return false + default: + return s[i].InsertId < s[j].InsertId + } +} + +func compareTimestamps(ts1, ts2 *tspb.Timestamp) int64 { + if ts1.Seconds != ts2.Seconds { + return ts1.Seconds - ts2.Seconds + } + return int64(ts1.Nanos - ts2.Nanos) +} + +// Lists monitored resource descriptors that are used by Stackdriver Logging. +func (h *loggingHandler) ListMonitoredResourceDescriptors(context.Context, *logpb.ListMonitoredResourceDescriptorsRequest) (*logpb.ListMonitoredResourceDescriptorsResponse, error) { + return &logpb.ListMonitoredResourceDescriptorsResponse{ + ResourceDescriptors: []*mrpb.MonitoredResourceDescriptor{ + { + Type: "global", + DisplayName: "Global", + Description: "... a log is not associated with any specific resource.", + Labels: []*lpb.LabelDescriptor{ + {Key: "project_id", Description: "The identifier of the GCP project..."}, + }, + }, + }, + }, nil +} + +// Lists logs. +func (h *loggingHandler) ListLogs(_ context.Context, req *logpb.ListLogsRequest) (*logpb.ListLogsResponse, error) { + // Return fixed, fake response. + logNames := []string{"a", "b", "c"} + from, to, npt, err := testutil.PageBounds(int(req.PageSize), req.PageToken, len(logNames)) + if err != nil { + return nil, err + } + var lns []string + for _, ln := range logNames[from:to] { + lns = append(lns, req.Parent+"/logs/"+ln) + } + return &logpb.ListLogsResponse{ + LogNames: lns, + NextPageToken: npt, + }, nil +} + +// Gets a sink. +func (h *configHandler) GetSink(_ context.Context, req *logpb.GetSinkRequest) (*logpb.LogSink, error) { + h.mu.Lock() + defer h.mu.Unlock() + if s, ok := h.sinks[req.SinkName]; ok { + return s, nil + } + // TODO(jba): use error codes + return nil, fmt.Errorf("sink %q not found", req.SinkName) +} + +// Creates a sink. +func (h *configHandler) CreateSink(_ context.Context, req *logpb.CreateSinkRequest) (*logpb.LogSink, error) { + h.mu.Lock() + defer h.mu.Unlock() + fullName := fmt.Sprintf("%s/sinks/%s", req.Parent, req.Sink.Name) + if _, ok := h.sinks[fullName]; ok { + return nil, fmt.Errorf("sink with name %q already exists", fullName) + } + h.setSink(fullName, req.Sink, req.UniqueWriterIdentity) + return req.Sink, nil +} + +func (h *configHandler) setSink(name string, s *logpb.LogSink, uniqueWriterIdentity bool) { + if uniqueWriterIdentity { + s.WriterIdentity = "serviceAccount:" + name + "@gmail.com" + } else { + s.WriterIdentity = SharedServiceAccount + } + h.sinks[name] = s +} + +// Creates or updates a sink. +func (h *configHandler) UpdateSink(_ context.Context, req *logpb.UpdateSinkRequest) (*logpb.LogSink, error) { + h.mu.Lock() + defer h.mu.Unlock() + sink := h.sinks[req.SinkName] + // Update of a non-existent sink will create it. + if sink == nil { + h.setSink(req.SinkName, req.Sink, req.UniqueWriterIdentity) + sink = req.Sink + } else { + // sink is the existing sink named req.SinkName. + // Update all and only the fields of sink that are specified in the update mask. + paths := req.UpdateMask.GetPaths() + if len(paths) == 0 { + // An empty update mask is considered to have these fields by default. + paths = []string{"destination", "filter", "include_children"} + } + for _, p := range paths { + switch p { + case "destination": + sink.Destination = req.Sink.Destination + case "filter": + sink.Filter = req.Sink.Filter + case "include_children": + sink.IncludeChildren = req.Sink.IncludeChildren + case "output_version_format": + // noop + default: + return nil, fmt.Errorf("unknown path in mask: %q", p) + } + } + if req.UniqueWriterIdentity { + if sink.WriterIdentity != SharedServiceAccount { + return nil, invalidArgument("cannot change unique writer identity") + } + sink.WriterIdentity = "serviceAccount:" + req.SinkName + "@gmail.com" + } + } + return sink, nil + +} + +// Deletes a sink. +func (h *configHandler) DeleteSink(_ context.Context, req *logpb.DeleteSinkRequest) (*emptypb.Empty, error) { + h.mu.Lock() + defer h.mu.Unlock() + delete(h.sinks, req.SinkName) + return &emptypb.Empty{}, nil +} + +// Lists sinks. This fake implementation ignores the Parent field of +// ListSinksRequest. All sinks are listed, regardless of their project. +func (h *configHandler) ListSinks(_ context.Context, req *logpb.ListSinksRequest) (*logpb.ListSinksResponse, error) { + h.mu.Lock() + var sinks []*logpb.LogSink + for _, s := range h.sinks { + sinks = append(sinks, s) + } + h.mu.Unlock() // safe because no *logpb.LogSink is ever modified + // Since map iteration varies, sort the sinks. + sort.Sort(sinksByName(sinks)) + from, to, nextPageToken, err := testutil.PageBounds(int(req.PageSize), req.PageToken, len(sinks)) + if err != nil { + return nil, err + } + return &logpb.ListSinksResponse{ + Sinks: sinks[from:to], + NextPageToken: nextPageToken, + }, nil +} + +type sinksByName []*logpb.LogSink + +func (s sinksByName) Len() int { return len(s) } +func (s sinksByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s sinksByName) Less(i, j int) bool { return s[i].Name < s[j].Name } + +// Gets a metric. +func (h *metricHandler) GetLogMetric(_ context.Context, req *logpb.GetLogMetricRequest) (*logpb.LogMetric, error) { + h.mu.Lock() + defer h.mu.Unlock() + if s, ok := h.metrics[req.MetricName]; ok { + return s, nil + } + // TODO(jba): use error codes + return nil, fmt.Errorf("metric %q not found", req.MetricName) +} + +// Creates a metric. +func (h *metricHandler) CreateLogMetric(_ context.Context, req *logpb.CreateLogMetricRequest) (*logpb.LogMetric, error) { + h.mu.Lock() + defer h.mu.Unlock() + fullName := fmt.Sprintf("%s/metrics/%s", req.Parent, req.Metric.Name) + if _, ok := h.metrics[fullName]; ok { + return nil, fmt.Errorf("metric with name %q already exists", fullName) + } + h.metrics[fullName] = req.Metric + return req.Metric, nil +} + +// Creates or updates a metric. +func (h *metricHandler) UpdateLogMetric(_ context.Context, req *logpb.UpdateLogMetricRequest) (*logpb.LogMetric, error) { + h.mu.Lock() + defer h.mu.Unlock() + // Update of a non-existent metric will create it. + h.metrics[req.MetricName] = req.Metric + return req.Metric, nil +} + +// Deletes a metric. +func (h *metricHandler) DeleteLogMetric(_ context.Context, req *logpb.DeleteLogMetricRequest) (*emptypb.Empty, error) { + h.mu.Lock() + defer h.mu.Unlock() + delete(h.metrics, req.MetricName) + return &emptypb.Empty{}, nil +} + +// Lists metrics. This fake implementation ignores the Parent field of +// ListMetricsRequest. All metrics are listed, regardless of their project. +func (h *metricHandler) ListLogMetrics(_ context.Context, req *logpb.ListLogMetricsRequest) (*logpb.ListLogMetricsResponse, error) { + h.mu.Lock() + var metrics []*logpb.LogMetric + for _, s := range h.metrics { + metrics = append(metrics, s) + } + h.mu.Unlock() // safe because no *logpb.LogMetric is ever modified + // Since map iteration varies, sort the metrics. + sort.Sort(metricsByName(metrics)) + from, to, nextPageToken, err := testutil.PageBounds(int(req.PageSize), req.PageToken, len(metrics)) + if err != nil { + return nil, err + } + return &logpb.ListLogMetricsResponse{ + Metrics: metrics[from:to], + NextPageToken: nextPageToken, + }, nil +} + +type metricsByName []*logpb.LogMetric + +func (s metricsByName) Len() int { return len(s) } +func (s metricsByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s metricsByName) Less(i, j int) bool { return s[i].Name < s[j].Name } + +func invalidArgument(msg string) error { + // TODO(jba): status codes + return errors.New(msg) +} diff --git a/vendor/cloud.google.com/go/logging/internal/testing/fake_test.go b/vendor/cloud.google.com/go/logging/internal/testing/fake_test.go new file mode 100644 index 00000000..1ef9cf12 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/internal/testing/fake_test.go @@ -0,0 +1,122 @@ +/* +Copyright 2016 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// This file contains only basic checks. The fake is effectively tested by the +// logging client unit tests. + +package testing + +import ( + "testing" + "time" + + "github.com/golang/protobuf/proto" + tspb "github.com/golang/protobuf/ptypes/timestamp" + logpb "google.golang.org/genproto/googleapis/logging/v2" + grpc "google.golang.org/grpc" +) + +func TestNewServer(t *testing.T) { + // Confirm that we can create and use a working gRPC server. + addr, err := NewServer() + if err != nil { + t.Fatal(err) + } + conn, err := grpc.Dial(addr, grpc.WithInsecure()) + if err != nil { + t.Fatal(err) + } + // Avoid "connection is closing; please retry" message from gRPC. + time.Sleep(300 * time.Millisecond) + conn.Close() +} + +func TestParseFilter(t *testing.T) { + for _, test := range []struct { + filter string + want string + wantErr bool + }{ + {"", "", false}, + {"logName = syslog", "syslog", false}, + {"logname = syslog", "", true}, + {"logName = 'syslog'", "", true}, + {"logName == syslog", "", true}, + } { + got, err := parseFilter(test.filter) + if err != nil { + if !test.wantErr { + t.Errorf("%q: got %v, want no error", test.filter, err) + } + continue + } + if test.wantErr { + t.Errorf("%q: got no error, want one", test.filter) + continue + } + if got != test.want { + t.Errorf("%q: got %q, want %q", test.filter, got, test.want) + } + } +} + +func TestSortEntries(t *testing.T) { + entries := []*logpb.LogEntry{ + /* 0 */ {Timestamp: &tspb.Timestamp{Seconds: 30}}, + /* 1 */ {Timestamp: &tspb.Timestamp{Seconds: 10}}, + /* 2 */ {Timestamp: &tspb.Timestamp{Seconds: 20}, InsertId: "b"}, + /* 3 */ {Timestamp: &tspb.Timestamp{Seconds: 20}, InsertId: "a"}, + /* 4 */ {Timestamp: &tspb.Timestamp{Seconds: 20}, InsertId: "c"}, + } + for _, test := range []struct { + orderBy string + want []int // slice of index into entries; nil == error + }{ + {"", []int{1, 3, 2, 4, 0}}, + {"timestamp asc", []int{1, 3, 2, 4, 0}}, + {"timestamp desc", []int{0, 4, 2, 3, 1}}, + {"something else", nil}, + } { + got := make([]*logpb.LogEntry, len(entries)) + copy(got, entries) + err := sortEntries(got, test.orderBy) + if err != nil { + if test.want != nil { + t.Errorf("%q: got %v, want nil error", test.orderBy, err) + } + continue + } + want := make([]*logpb.LogEntry, len(entries)) + for i, j := range test.want { + want[i] = entries[j] + } + if !logEntriesEqual(got, want) { + t.Errorf("%q: got %v, want %v", test.orderBy, got, want) + } + } +} + +func logEntriesEqual(a, b []*logpb.LogEntry) bool { + if len(a) != len(b) { + return false + } + for i, aa := range a { + if !proto.Equal(aa, b[i]) { + return false + } + } + return true +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/example_entry_iterator_test.go b/vendor/cloud.google.com/go/logging/logadmin/example_entry_iterator_test.go new file mode 100644 index 00000000..f0fe138e --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/example_entry_iterator_test.go @@ -0,0 +1,66 @@ +// Copyright 2016 Google LLC +// +// 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 logadmin_test + +import ( + "context" + "fmt" + "time" + + "cloud.google.com/go/logging/logadmin" + "google.golang.org/api/iterator" +) + +func ExampleClient_Entries() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + it := client.Entries(ctx, logadmin.Filter(`logName = "projects/my-project/logs/my-log"`)) + _ = it // TODO: iterate using Next or iterator.Pager. +} + +func ExampleFilter_timestamp() { + // This example demonstrates how to list the last 24 hours of log entries. + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + oneDayAgo := time.Now().Add(-24 * time.Hour) + t := oneDayAgo.Format(time.RFC3339) // Logging API wants timestamps in RFC 3339 format. + it := client.Entries(ctx, logadmin.Filter(fmt.Sprintf(`timestamp > "%s"`, t))) + _ = it // TODO: iterate using Next or iterator.Pager. +} + +func ExampleEntryIterator_Next() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + it := client.Entries(ctx) + for { + entry, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(entry) + } +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/example_metric_iterator_test.go b/vendor/cloud.google.com/go/logging/logadmin/example_metric_iterator_test.go new file mode 100644 index 00000000..91d1d00a --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/example_metric_iterator_test.go @@ -0,0 +1,52 @@ +// Copyright 2016 Google LLC +// +// 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 logadmin_test + +import ( + "context" + "fmt" + + "cloud.google.com/go/logging/logadmin" + "google.golang.org/api/iterator" +) + +func ExampleClient_Metrics() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + it := client.Metrics(ctx) + _ = it // TODO: iterate using Next or iterator.Pager. +} + +func ExampleMetricIterator_Next() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + it := client.Metrics(ctx) + for { + metric, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(metric) + } +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/example_paging_test.go b/vendor/cloud.google.com/go/logging/logadmin/example_paging_test.go new file mode 100644 index 00000000..4f71f492 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/example_paging_test.go @@ -0,0 +1,92 @@ +// Copyright 2016 Google LLC +// +// 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 logadmin_test + +import ( + "bytes" + "context" + "flag" + "fmt" + "html/template" + "log" + "net/http" + + "cloud.google.com/go/logging" + "cloud.google.com/go/logging/logadmin" + "google.golang.org/api/iterator" +) + +var ( + client *logadmin.Client + projectID = flag.String("project-id", "", "ID of the project to use") +) + +func ExampleClient_Entries_pagination() { + // This example demonstrates how to iterate through items a page at a time + // even if each successive page is fetched by a different process. It is a + // complete web server that displays pages of log entries. To run it as a + // standalone program, rename both the package and this function to "main". + ctx := context.Background() + flag.Parse() + if *projectID == "" { + log.Fatal("-project-id missing") + } + var err error + client, err = logadmin.NewClient(ctx, *projectID) + if err != nil { + log.Fatalf("creating logging client: %v", err) + } + + http.HandleFunc("/entries", handleEntries) + log.Print("listening on 8080") + log.Fatal(http.ListenAndServe(":8080", nil)) +} + +var pageTemplate = template.Must(template.New("").Parse(` +
+ {{range .Entries}} + + {{end}} +
{{.}}
+{{if .Next}} + Next Page +{{end}} +`)) + +func handleEntries(w http.ResponseWriter, r *http.Request) { + ctx := context.Background() + filter := fmt.Sprintf(`logName = "projects/%s/logs/testlog"`, *projectID) + it := client.Entries(ctx, logadmin.Filter(filter)) + var entries []*logging.Entry + nextTok, err := iterator.NewPager(it, 5, r.URL.Query().Get("pageToken")).NextPage(&entries) + if err != nil { + http.Error(w, fmt.Sprintf("problem getting the next page: %v", err), http.StatusInternalServerError) + return + } + data := struct { + Entries []*logging.Entry + Next string + }{ + entries, + nextTok, + } + var buf bytes.Buffer + if err := pageTemplate.Execute(&buf, data); err != nil { + http.Error(w, fmt.Sprintf("problem executing page template: %v", err), http.StatusInternalServerError) + } + if _, err := buf.WriteTo(w); err != nil { + log.Printf("writing response: %v", err) + } +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/example_resource_iterator_test.go b/vendor/cloud.google.com/go/logging/logadmin/example_resource_iterator_test.go new file mode 100644 index 00000000..208f95f4 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/example_resource_iterator_test.go @@ -0,0 +1,52 @@ +// Copyright 2016 Google LLC +// +// 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 logadmin_test + +import ( + "context" + "fmt" + + "cloud.google.com/go/logging/logadmin" + "google.golang.org/api/iterator" +) + +func ExampleClient_ResourceDescriptors() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + it := client.ResourceDescriptors(ctx) + _ = it // TODO: iterate using Next or iterator.Pager. +} + +func ExampleResourceDescriptorIterator_Next() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + it := client.ResourceDescriptors(ctx) + for { + rdesc, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(rdesc) + } +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/example_sink_iterator_test.go b/vendor/cloud.google.com/go/logging/logadmin/example_sink_iterator_test.go new file mode 100644 index 00000000..0cf333dd --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/example_sink_iterator_test.go @@ -0,0 +1,52 @@ +// Copyright 2016 Google LLC +// +// 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 logadmin_test + +import ( + "context" + "fmt" + + "cloud.google.com/go/logging/logadmin" + "google.golang.org/api/iterator" +) + +func ExampleClient_Sinks() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + it := client.Sinks(ctx) + _ = it // TODO: iterate using Next or iterator.Pager. +} + +func ExampleSinkIterator_Next() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + it := client.Sinks(ctx) + for { + sink, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(sink) + } +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/examples_test.go b/vendor/cloud.google.com/go/logging/logadmin/examples_test.go new file mode 100644 index 00000000..e950fe45 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/examples_test.go @@ -0,0 +1,161 @@ +// Copyright 2016 Google LLC +// +// 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 logadmin_test + +import ( + "context" + "fmt" + + "cloud.google.com/go/logging/logadmin" +) + +func ExampleNewClient() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + // Use client to manage logs, metrics and sinks. + // Close the client when finished. + if err := client.Close(); err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_DeleteLog() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + err = client.DeleteLog(ctx, "my-log") + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_CreateMetric() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + err = client.CreateMetric(ctx, &logadmin.Metric{ + ID: "severe-errors", + Description: "entries at ERROR or higher severities", + Filter: "severity >= ERROR", + }) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_DeleteMetric() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + if err := client.DeleteMetric(ctx, "severe-errors"); err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_Metric() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + m, err := client.Metric(ctx, "severe-errors") + if err != nil { + // TODO: Handle error. + } + fmt.Println(m) +} + +func ExampleClient_UpdateMetric() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + err = client.UpdateMetric(ctx, &logadmin.Metric{ + ID: "severe-errors", + Description: "entries at high severities", + Filter: "severity > ERROR", + }) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_CreateSink() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + sink, err := client.CreateSink(ctx, &logadmin.Sink{ + ID: "severe-errors-to-gcs", + Destination: "storage.googleapis.com/my-bucket", + Filter: "severity >= ERROR", + }) + if err != nil { + // TODO: Handle error. + } + fmt.Println(sink) +} + +func ExampleClient_DeleteSink() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + if err := client.DeleteSink(ctx, "severe-errors-to-gcs"); err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_Sink() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + s, err := client.Sink(ctx, "severe-errors-to-gcs") + if err != nil { + // TODO: Handle error. + } + fmt.Println(s) +} + +func ExampleClient_UpdateSink() { + ctx := context.Background() + client, err := logadmin.NewClient(ctx, "my-project") + if err != nil { + // TODO: Handle error. + } + sink, err := client.UpdateSink(ctx, &logadmin.Sink{ + ID: "severe-errors-to-gcs", + Destination: "storage.googleapis.com/my-other-bucket", + Filter: "severity >= ERROR", + }) + if err != nil { + // TODO: Handle error. + } + fmt.Println(sink) +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/logadmin.go b/vendor/cloud.google.com/go/logging/logadmin/logadmin.go new file mode 100644 index 00000000..d50f5e04 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/logadmin.go @@ -0,0 +1,405 @@ +// Copyright 2016 Google LLC +// +// 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. + +// These features are missing now, but will likely be added: +// - There is no way to specify CallOptions. + +// Package logadmin contains a Stackdriver Logging client that can be used +// for reading logs and working with sinks, metrics and monitored resources. +// For a client that can write logs, see package cloud.google.com/go/logging. +// +// The client uses Logging API v2. +// See https://cloud.google.com/logging/docs/api/v2/ for an introduction to the API. +// +// Note: This package is in beta. Some backwards-incompatible changes may occur. +package logadmin // import "cloud.google.com/go/logging/logadmin" + +import ( + "context" + "fmt" + "math" + "net/http" + "net/url" + "strings" + "time" + + "cloud.google.com/go/internal/version" + "cloud.google.com/go/logging" + vkit "cloud.google.com/go/logging/apiv2" + "cloud.google.com/go/logging/internal" + "github.com/golang/protobuf/ptypes" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + _ "google.golang.org/genproto/googleapis/appengine/logging/v1" // Import the following so EntryIterator can unmarshal log protos. + _ "google.golang.org/genproto/googleapis/cloud/audit" + logtypepb "google.golang.org/genproto/googleapis/logging/type" + logpb "google.golang.org/genproto/googleapis/logging/v2" + "google.golang.org/grpc/codes" +) + +// Client is a Logging client. A Client is associated with a single Cloud project. +type Client struct { + lClient *vkit.Client // logging client + sClient *vkit.ConfigClient // sink client + mClient *vkit.MetricsClient // metric client + parent string + closed bool +} + +// NewClient returns a new logging client associated with the provided project ID. +// +// By default NewClient uses AdminScope. To use a different scope, call +// NewClient using a WithScopes option (see https://godoc.org/google.golang.org/api/option#WithScopes). +func NewClient(ctx context.Context, parent string, opts ...option.ClientOption) (*Client, error) { + if !strings.ContainsRune(parent, '/') { + parent = "projects/" + parent + } + opts = append([]option.ClientOption{ + option.WithEndpoint(internal.ProdAddr), + option.WithScopes(logging.AdminScope), + }, opts...) + lc, err := vkit.NewClient(ctx, opts...) + if err != nil { + return nil, err + } + // TODO(jba): pass along any client options that should be provided to all clients. + sc, err := vkit.NewConfigClient(ctx, option.WithGRPCConn(lc.Connection())) + if err != nil { + return nil, err + } + mc, err := vkit.NewMetricsClient(ctx, option.WithGRPCConn(lc.Connection())) + if err != nil { + return nil, err + } + // Retry some non-idempotent methods on INTERNAL, because it happens sometimes + // and in all observed cases the operation did not complete. + retryerOnInternal := func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.Internal, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 1000 * time.Millisecond, + Multiplier: 1.2, + }) + } + mc.CallOptions.CreateLogMetric = []gax.CallOption{gax.WithRetry(retryerOnInternal)} + mc.CallOptions.UpdateLogMetric = []gax.CallOption{gax.WithRetry(retryerOnInternal)} + + lc.SetGoogleClientInfo("gccl", version.Repo) + sc.SetGoogleClientInfo("gccl", version.Repo) + mc.SetGoogleClientInfo("gccl", version.Repo) + client := &Client{ + lClient: lc, + sClient: sc, + mClient: mc, + parent: parent, + } + return client, nil +} + +// Close closes the client. +func (c *Client) Close() error { + if c.closed { + return nil + } + // Return only the first error. Since all clients share an underlying connection, + // Closes after the first always report a "connection is closing" error. + err := c.lClient.Close() + _ = c.sClient.Close() + _ = c.mClient.Close() + c.closed = true + return err +} + +// DeleteLog deletes a log and all its log entries. The log will reappear if it receives new entries. +// logID identifies the log within the project. An example log ID is "syslog". Requires AdminScope. +func (c *Client) DeleteLog(ctx context.Context, logID string) error { + return c.lClient.DeleteLog(ctx, &logpb.DeleteLogRequest{ + LogName: internal.LogPath(c.parent, logID), + }) +} + +func toHTTPRequest(p *logtypepb.HttpRequest) (*logging.HTTPRequest, error) { + if p == nil { + return nil, nil + } + u, err := url.Parse(p.RequestUrl) + if err != nil { + return nil, err + } + var dur time.Duration + if p.Latency != nil { + dur, err = ptypes.Duration(p.Latency) + if err != nil { + return nil, err + } + } + hr := &http.Request{ + Method: p.RequestMethod, + URL: u, + Header: map[string][]string{}, + } + if p.UserAgent != "" { + hr.Header.Set("User-Agent", p.UserAgent) + } + if p.Referer != "" { + hr.Header.Set("Referer", p.Referer) + } + return &logging.HTTPRequest{ + Request: hr, + RequestSize: p.RequestSize, + Status: int(p.Status), + ResponseSize: p.ResponseSize, + Latency: dur, + RemoteIP: p.RemoteIp, + CacheHit: p.CacheHit, + CacheValidatedWithOriginServer: p.CacheValidatedWithOriginServer, + }, nil +} + +// An EntriesOption is an option for listing log entries. +type EntriesOption interface { + set(*logpb.ListLogEntriesRequest) +} + +// ProjectIDs sets the project IDs or project numbers from which to retrieve +// log entries. Examples of a project ID: "my-project-1A", "1234567890". +func ProjectIDs(pids []string) EntriesOption { return projectIDs(pids) } + +type projectIDs []string + +func (p projectIDs) set(r *logpb.ListLogEntriesRequest) { + r.ResourceNames = make([]string, len(p)) + for i, v := range p { + r.ResourceNames[i] = fmt.Sprintf("projects/%s", v) + } +} + +// ResourceNames sets the resource names from which to retrieve +// log entries. Examples: "projects/my-project-1A", "organizations/my-org". +func ResourceNames(rns []string) EntriesOption { return resourceNames(rns) } + +type resourceNames []string + +func (rn resourceNames) set(r *logpb.ListLogEntriesRequest) { + r.ResourceNames = append([]string(nil), rn...) +} + +// Filter sets an advanced logs filter for listing log entries (see +// https://cloud.google.com/logging/docs/view/advanced_filters). The filter is +// compared against all log entries in the projects specified by ProjectIDs. +// Only entries that match the filter are retrieved. An empty filter (the +// default) matches all log entries. +// +// In the filter string, log names must be written in their full form, as +// "projects/PROJECT-ID/logs/LOG-ID". Forward slashes in LOG-ID must be +// replaced by %2F before calling Filter. +// +// Timestamps in the filter string must be written in RFC 3339 format. See the +// timestamp example. +func Filter(f string) EntriesOption { return filter(f) } + +type filter string + +func (f filter) set(r *logpb.ListLogEntriesRequest) { r.Filter = string(f) } + +// NewestFirst causes log entries to be listed from most recent (newest) to +// least recent (oldest). By default, they are listed from oldest to newest. +func NewestFirst() EntriesOption { return newestFirst{} } + +type newestFirst struct{} + +func (newestFirst) set(r *logpb.ListLogEntriesRequest) { r.OrderBy = "timestamp desc" } + +// Entries returns an EntryIterator for iterating over log entries. By default, +// the log entries will be restricted to those from the project passed to +// NewClient. This may be overridden by passing a ProjectIDs option. Requires ReadScope or AdminScope. +func (c *Client) Entries(ctx context.Context, opts ...EntriesOption) *EntryIterator { + it := &EntryIterator{ + it: c.lClient.ListLogEntries(ctx, listLogEntriesRequest(c.parent, opts)), + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.items) }, + func() interface{} { b := it.items; it.items = nil; return b }) + return it +} + +func listLogEntriesRequest(parent string, opts []EntriesOption) *logpb.ListLogEntriesRequest { + req := &logpb.ListLogEntriesRequest{ + ResourceNames: []string{parent}, + } + for _, opt := range opts { + opt.set(req) + } + return req +} + +// An EntryIterator iterates over log entries. +type EntryIterator struct { + it *vkit.LogEntryIterator + pageInfo *iterator.PageInfo + nextFunc func() error + items []*logging.Entry +} + +// PageInfo supports pagination. See https://godoc.org/google.golang.org/api/iterator package for details. +func (it *EntryIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } + +// Next returns the next result. Its second return value is iterator.Done +// (https://godoc.org/google.golang.org/api/iterator) if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *EntryIterator) Next() (*logging.Entry, error) { + if err := it.nextFunc(); err != nil { + return nil, err + } + item := it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *EntryIterator) fetch(pageSize int, pageToken string) (string, error) { + return iterFetch(pageSize, pageToken, it.it.PageInfo(), func() error { + item, err := it.it.Next() + if err != nil { + return err + } + e, err := fromLogEntry(item) + if err != nil { + return err + } + it.items = append(it.items, e) + return nil + }) +} + +func trunc32(i int) int32 { + if i > math.MaxInt32 { + i = math.MaxInt32 + } + return int32(i) +} + +var slashUnescaper = strings.NewReplacer("%2F", "/", "%2f", "/") + +func fromLogEntry(le *logpb.LogEntry) (*logging.Entry, error) { + time, err := ptypes.Timestamp(le.Timestamp) + if err != nil { + return nil, err + } + var payload interface{} + switch x := le.Payload.(type) { + case *logpb.LogEntry_TextPayload: + payload = x.TextPayload + + case *logpb.LogEntry_ProtoPayload: + var d ptypes.DynamicAny + if err := ptypes.UnmarshalAny(x.ProtoPayload, &d); err != nil { + return nil, fmt.Errorf("logging: unmarshalling proto payload: %v", err) + } + payload = d.Message + + case *logpb.LogEntry_JsonPayload: + // Leave this as a Struct. + // TODO(jba): convert to map[string]interface{}? + payload = x.JsonPayload + + default: + return nil, fmt.Errorf("logging: unknown payload type: %T", le.Payload) + } + hr, err := toHTTPRequest(le.HttpRequest) + if err != nil { + return nil, err + } + return &logging.Entry{ + Timestamp: time, + Severity: logging.Severity(le.Severity), + Payload: payload, + Labels: le.Labels, + InsertID: le.InsertId, + HTTPRequest: hr, + Operation: le.Operation, + LogName: slashUnescaper.Replace(le.LogName), + Resource: le.Resource, + Trace: le.Trace, + SourceLocation: le.SourceLocation, + }, nil +} + +// Logs lists the logs owned by the parent resource of the client. +func (c *Client) Logs(ctx context.Context) *LogIterator { + it := &LogIterator{ + parentResource: c.parent, + it: c.lClient.ListLogs(ctx, &logpb.ListLogsRequest{Parent: c.parent}), + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.items) }, + func() interface{} { b := it.items; it.items = nil; return b }) + return it +} + +// A LogIterator iterates over logs. +type LogIterator struct { + parentResource string + it *vkit.StringIterator + pageInfo *iterator.PageInfo + nextFunc func() error + items []string +} + +// PageInfo supports pagination. See https://godoc.org/google.golang.org/api/iterator package for details. +func (it *LogIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } + +// Next returns the next result. Its second return value is iterator.Done +// (https://godoc.org/google.golang.org/api/iterator) if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *LogIterator) Next() (string, error) { + if err := it.nextFunc(); err != nil { + return "", err + } + item := it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *LogIterator) fetch(pageSize int, pageToken string) (string, error) { + return iterFetch(pageSize, pageToken, it.it.PageInfo(), func() error { + logPath, err := it.it.Next() + if err != nil { + return err + } + logID := internal.LogIDFromPath(it.parentResource, logPath) + it.items = append(it.items, logID) + return nil + }) +} + +// Common fetch code for iterators that are backed by vkit iterators. +func iterFetch(pageSize int, pageToken string, pi *iterator.PageInfo, next func() error) (string, error) { + pi.MaxSize = pageSize + pi.Token = pageToken + // Get one item, which will fill the buffer. + if err := next(); err != nil { + return "", err + } + // Collect the rest of the buffer. + for pi.Remaining() > 0 { + if err := next(); err != nil { + return "", err + } + } + return pi.Token, nil +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/logadmin_test.go b/vendor/cloud.google.com/go/logging/logadmin/logadmin_test.go new file mode 100644 index 00000000..f493b68e --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/logadmin_test.go @@ -0,0 +1,277 @@ +// Copyright 2016 Google LLC +// +// 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. + +// TODO(jba): test that OnError is getting called appropriately. + +package logadmin + +import ( + "context" + "flag" + "log" + "net/http" + "net/url" + "os" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/logging" + ltesting "cloud.google.com/go/logging/internal/testing" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + durpb "github.com/golang/protobuf/ptypes/duration" + structpb "github.com/golang/protobuf/ptypes/struct" + "github.com/google/go-cmp/cmp/cmpopts" + "google.golang.org/api/option" + mrpb "google.golang.org/genproto/googleapis/api/monitoredres" + audit "google.golang.org/genproto/googleapis/cloud/audit" + logtypepb "google.golang.org/genproto/googleapis/logging/type" + logpb "google.golang.org/genproto/googleapis/logging/v2" + "google.golang.org/grpc" +) + +var ( + client *Client + testProjectID string +) + +var ( + // If true, this test is using the production service, not a fake. + integrationTest bool + + newClient func(ctx context.Context, projectID string) *Client +) + +func TestMain(m *testing.M) { + flag.Parse() // needed for testing.Short() + ctx := context.Background() + testProjectID = testutil.ProjID() + if testProjectID == "" || testing.Short() { + integrationTest = false + if testProjectID != "" { + log.Print("Integration tests skipped in short mode (using fake instead)") + } + testProjectID = "PROJECT_ID" + addr, err := ltesting.NewServer() + if err != nil { + log.Fatalf("creating fake server: %v", err) + } + newClient = func(ctx context.Context, projectID string) *Client { + conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithBlock()) + if err != nil { + log.Fatalf("dialing %q: %v", addr, err) + } + c, err := NewClient(ctx, projectID, option.WithGRPCConn(conn)) + if err != nil { + log.Fatalf("creating client for fake at %q: %v", addr, err) + } + return c + } + } else { + integrationTest = true + ts := testutil.TokenSource(ctx, logging.AdminScope) + if ts == nil { + log.Fatal("The project key must be set. See CONTRIBUTING.md for details") + } + log.Printf("running integration tests with project %s", testProjectID) + newClient = func(ctx context.Context, projectID string) *Client { + c, err := NewClient(ctx, projectID, option.WithTokenSource(ts), + option.WithGRPCDialOption(grpc.WithBlock())) + if err != nil { + log.Fatalf("creating prod client: %v", err) + } + return c + } + } + client = newClient(ctx, testProjectID) + initMetrics(ctx) + cleanup := initSinks(ctx) + exit := m.Run() + cleanup() + client.Close() + os.Exit(exit) +} + +// EntryIterator and DeleteLog are tested in the logging package. + +func TestClientClose(t *testing.T) { + c := newClient(context.Background(), testProjectID) + if err := c.Close(); err != nil { + t.Errorf("want got %v, want nil", err) + } +} + +func TestFromLogEntry(t *testing.T) { + now := time.Now() + res := &mrpb.MonitoredResource{Type: "global"} + ts, err := ptypes.TimestampProto(now) + if err != nil { + t.Fatal(err) + } + logEntry := logpb.LogEntry{ + LogName: "projects/PROJECT_ID/logs/LOG_ID", + Resource: res, + Payload: &logpb.LogEntry_TextPayload{TextPayload: "hello"}, + Timestamp: ts, + Severity: logtypepb.LogSeverity_INFO, + InsertId: "123", + HttpRequest: &logtypepb.HttpRequest{ + RequestMethod: "GET", + RequestUrl: "http:://example.com/path?q=1", + RequestSize: 100, + Status: 200, + ResponseSize: 25, + Latency: &durpb.Duration{Seconds: 100}, + UserAgent: "user-agent", + RemoteIp: "127.0.0.1", + Referer: "referer", + CacheHit: true, + CacheValidatedWithOriginServer: true, + }, + Labels: map[string]string{ + "a": "1", + "b": "two", + "c": "true", + }, + SourceLocation: &logpb.LogEntrySourceLocation{ + File: "some_file.go", + Line: 1, + Function: "someFunction", + }, + } + u, err := url.Parse("http:://example.com/path?q=1") + if err != nil { + t.Fatal(err) + } + want := &logging.Entry{ + LogName: "projects/PROJECT_ID/logs/LOG_ID", + Resource: res, + Timestamp: now.In(time.UTC), + Severity: logging.Info, + Payload: "hello", + Labels: map[string]string{ + "a": "1", + "b": "two", + "c": "true", + }, + InsertID: "123", + HTTPRequest: &logging.HTTPRequest{ + Request: &http.Request{ + Method: "GET", + URL: u, + Header: map[string][]string{ + "User-Agent": {"user-agent"}, + "Referer": {"referer"}, + }, + }, + RequestSize: 100, + Status: 200, + ResponseSize: 25, + Latency: 100 * time.Second, + RemoteIP: "127.0.0.1", + CacheHit: true, + CacheValidatedWithOriginServer: true, + }, + SourceLocation: &logpb.LogEntrySourceLocation{ + File: "some_file.go", + Line: 1, + Function: "someFunction", + }, + } + got, err := fromLogEntry(&logEntry) + if err != nil { + t.Fatal(err) + } + if diff := testutil.Diff(got, want, cmpopts.IgnoreUnexported(http.Request{})); diff != "" { + t.Errorf("FullEntry:\n%s", diff) + } + + // Proto payload. + alog := &audit.AuditLog{ + ServiceName: "svc", + MethodName: "method", + ResourceName: "shelves/S/books/B", + } + any, err := ptypes.MarshalAny(alog) + if err != nil { + t.Fatal(err) + } + logEntry = logpb.LogEntry{ + LogName: "projects/PROJECT_ID/logs/LOG_ID", + Resource: res, + Timestamp: ts, + Payload: &logpb.LogEntry_ProtoPayload{ProtoPayload: any}, + } + got, err = fromLogEntry(&logEntry) + if err != nil { + t.Fatal(err) + } + if !ltesting.PayloadEqual(got.Payload, alog) { + t.Errorf("got %+v, want %+v", got.Payload, alog) + } + + // JSON payload. + jstruct := &structpb.Struct{Fields: map[string]*structpb.Value{ + "f": {Kind: &structpb.Value_NumberValue{NumberValue: 3.1}}, + }} + logEntry = logpb.LogEntry{ + LogName: "projects/PROJECT_ID/logs/LOG_ID", + Resource: res, + Timestamp: ts, + Payload: &logpb.LogEntry_JsonPayload{JsonPayload: jstruct}, + } + got, err = fromLogEntry(&logEntry) + if err != nil { + t.Fatal(err) + } + if !ltesting.PayloadEqual(got.Payload, jstruct) { + t.Errorf("got %+v, want %+v", got.Payload, jstruct) + } +} + +func TestListLogEntriesRequest(t *testing.T) { + for _, test := range []struct { + opts []EntriesOption + resourceNames []string + filter string + orderBy string + }{ + // Default is client's project ID, empty filter and orderBy. + {nil, []string{"projects/PROJECT_ID"}, "", ""}, + {[]EntriesOption{NewestFirst(), Filter("f")}, + []string{"projects/PROJECT_ID"}, "f", "timestamp desc"}, + {[]EntriesOption{ProjectIDs([]string{"foo"})}, + []string{"projects/foo"}, "", ""}, + {[]EntriesOption{ResourceNames([]string{"folders/F", "organizations/O"})}, + []string{"folders/F", "organizations/O"}, "", ""}, + {[]EntriesOption{NewestFirst(), Filter("f"), ProjectIDs([]string{"foo"})}, + []string{"projects/foo"}, "f", "timestamp desc"}, + {[]EntriesOption{NewestFirst(), Filter("f"), ProjectIDs([]string{"foo"})}, + []string{"projects/foo"}, "f", "timestamp desc"}, + // If there are repeats, last one wins. + {[]EntriesOption{NewestFirst(), Filter("no"), ProjectIDs([]string{"foo"}), Filter("f")}, + []string{"projects/foo"}, "f", "timestamp desc"}, + } { + got := listLogEntriesRequest("projects/PROJECT_ID", test.opts) + want := &logpb.ListLogEntriesRequest{ + ResourceNames: test.resourceNames, + Filter: test.filter, + OrderBy: test.orderBy, + } + if !proto.Equal(got, want) { + t.Errorf("%v:\ngot %v\nwant %v", test.opts, got, want) + } + } +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/metrics.go b/vendor/cloud.google.com/go/logging/logadmin/metrics.go new file mode 100644 index 00000000..2f673b64 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/metrics.go @@ -0,0 +1,154 @@ +// Copyright 2016 Google LLC +// +// 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 logadmin + +import ( + "context" + "fmt" + + vkit "cloud.google.com/go/logging/apiv2" + "google.golang.org/api/iterator" + logpb "google.golang.org/genproto/googleapis/logging/v2" +) + +// Metric describes a logs-based metric. The value of the metric is the +// number of log entries that match a logs filter. +// +// Metrics are a feature of Stackdriver Monitoring. +// See https://cloud.google.com/monitoring/api/v3/metrics for more about them. +type Metric struct { + // ID is a client-assigned metric identifier. Example: + // "severe_errors". Metric identifiers are limited to 1000 + // characters and can include only the following characters: A-Z, + // a-z, 0-9, and the special characters _-.,+!*',()%/\. The + // forward-slash character (/) denotes a hierarchy of name pieces, + // and it cannot be the first character of the name. + ID string + + // Description describes this metric. It is used in documentation. + Description string + + // Filter is an advanced logs filter (see + // https://cloud.google.com/logging/docs/view/advanced_filters). + // Example: "logName:syslog AND severity>=ERROR". + Filter string +} + +// CreateMetric creates a logs-based metric. +func (c *Client) CreateMetric(ctx context.Context, m *Metric) error { + _, err := c.mClient.CreateLogMetric(ctx, &logpb.CreateLogMetricRequest{ + Parent: c.parent, + Metric: toLogMetric(m), + }) + return err +} + +// DeleteMetric deletes a log-based metric. +// The provided metric ID is the metric identifier. For example, "severe_errors". +func (c *Client) DeleteMetric(ctx context.Context, metricID string) error { + return c.mClient.DeleteLogMetric(ctx, &logpb.DeleteLogMetricRequest{ + MetricName: c.metricPath(metricID), + }) +} + +// Metric gets a logs-based metric. +// The provided metric ID is the metric identifier. For example, "severe_errors". +// Requires ReadScope or AdminScope. +func (c *Client) Metric(ctx context.Context, metricID string) (*Metric, error) { + lm, err := c.mClient.GetLogMetric(ctx, &logpb.GetLogMetricRequest{ + MetricName: c.metricPath(metricID), + }) + if err != nil { + return nil, err + } + return fromLogMetric(lm), nil +} + +// UpdateMetric creates a logs-based metric if it does not exist, or updates an +// existing one. +func (c *Client) UpdateMetric(ctx context.Context, m *Metric) error { + _, err := c.mClient.UpdateLogMetric(ctx, &logpb.UpdateLogMetricRequest{ + MetricName: c.metricPath(m.ID), + Metric: toLogMetric(m), + }) + return err +} + +func (c *Client) metricPath(metricID string) string { + return fmt.Sprintf("%s/metrics/%s", c.parent, metricID) +} + +// Metrics returns a MetricIterator for iterating over all Metrics in the Client's project. +// Requires ReadScope or AdminScope. +func (c *Client) Metrics(ctx context.Context) *MetricIterator { + it := &MetricIterator{ + it: c.mClient.ListLogMetrics(ctx, &logpb.ListLogMetricsRequest{Parent: c.parent}), + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.items) }, + func() interface{} { b := it.items; it.items = nil; return b }) + return it +} + +// A MetricIterator iterates over Metrics. +type MetricIterator struct { + it *vkit.LogMetricIterator + pageInfo *iterator.PageInfo + nextFunc func() error + items []*Metric +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *MetricIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } + +// Next returns the next result. Its second return value is Done if there are +// no more results. Once Next returns Done, all subsequent calls will return +// Done. +func (it *MetricIterator) Next() (*Metric, error) { + if err := it.nextFunc(); err != nil { + return nil, err + } + item := it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *MetricIterator) fetch(pageSize int, pageToken string) (string, error) { + return iterFetch(pageSize, pageToken, it.it.PageInfo(), func() error { + item, err := it.it.Next() + if err != nil { + return err + } + it.items = append(it.items, fromLogMetric(item)) + return nil + }) +} + +func toLogMetric(m *Metric) *logpb.LogMetric { + return &logpb.LogMetric{ + Name: m.ID, + Description: m.Description, + Filter: m.Filter, + } +} + +func fromLogMetric(lm *logpb.LogMetric) *Metric { + return &Metric{ + ID: lm.Name, + Description: lm.Description, + Filter: lm.Filter, + } +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/metrics_test.go b/vendor/cloud.google.com/go/logging/logadmin/metrics_test.go new file mode 100644 index 00000000..afcbe794 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/metrics_test.go @@ -0,0 +1,155 @@ +// Copyright 2016 Google LLC +// +// 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 logadmin + +import ( + "context" + "log" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/internal/uid" + "google.golang.org/api/iterator" +) + +var metricIDs = uid.NewSpace("GO-CLIENT-TEST-METRIC", nil) + +// Initializes the tests before they run. +func initMetrics(ctx context.Context) { + // Clean up from aborted tests. + it := client.Metrics(ctx) +loop: + for { + m, err := it.Next() + switch err { + case nil: + if metricIDs.Older(m.ID, 24*time.Hour) { + client.DeleteMetric(ctx, m.ID) + } + case iterator.Done: + break loop + default: + log.Printf("cleanupMetrics: %v", err) + return + } + } +} + +func TestCreateDeleteMetric(t *testing.T) { + ctx := context.Background() + metric := &Metric{ + ID: metricIDs.New(), + Description: "DESC", + Filter: "FILTER", + } + if err := client.CreateMetric(ctx, metric); err != nil { + t.Fatal(err) + } + defer client.DeleteMetric(ctx, metric.ID) + + got, err := client.Metric(ctx, metric.ID) + if err != nil { + t.Fatal(err) + } + if want := metric; !testutil.Equal(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } + + if err := client.DeleteMetric(ctx, metric.ID); err != nil { + t.Fatal(err) + } + + if _, err := client.Metric(ctx, metric.ID); err == nil { + t.Fatal("got no error, expected one") + } +} + +func TestUpdateMetric(t *testing.T) { + ctx := context.Background() + metric := &Metric{ + ID: metricIDs.New(), + Description: "DESC", + Filter: "FILTER", + } + + // Updating a non-existent metric creates a new one. + if err := client.UpdateMetric(ctx, metric); err != nil { + t.Fatal(err) + } + defer client.DeleteMetric(ctx, metric.ID) + got, err := client.Metric(ctx, metric.ID) + if err != nil { + t.Fatal(err) + } + if want := metric; !testutil.Equal(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } + + // Updating an existing metric changes it. + metric.Description = "CHANGED" + if err := client.UpdateMetric(ctx, metric); err != nil { + t.Fatal(err) + } + got, err = client.Metric(ctx, metric.ID) + if err != nil { + t.Fatal(err) + } + if want := metric; !testutil.Equal(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } +} + +func TestListMetrics(t *testing.T) { + ctx := context.Background() + + var metrics []*Metric + want := map[string]*Metric{} + for i := 0; i < 10; i++ { + m := &Metric{ + ID: metricIDs.New(), + Description: "DESC", + Filter: "FILTER", + } + metrics = append(metrics, m) + want[m.ID] = m + } + for _, m := range metrics { + if err := client.CreateMetric(ctx, m); err != nil { + t.Fatalf("Create(%q): %v", m.ID, err) + } + defer client.DeleteMetric(ctx, m.ID) + } + + got := map[string]*Metric{} + it := client.Metrics(ctx) + for { + m, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + t.Fatal(err) + } + // If tests run simultaneously, we may have more metrics than we + // created. So only check for our own. + if _, ok := want[m.ID]; ok { + got[m.ID] = m + } + } + if !testutil.Equal(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/resources.go b/vendor/cloud.google.com/go/logging/logadmin/resources.go new file mode 100644 index 00000000..924dee1a --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/resources.go @@ -0,0 +1,75 @@ +// Copyright 2016 Google LLC +// +// 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 logadmin + +import ( + "context" + + vkit "cloud.google.com/go/logging/apiv2" + "google.golang.org/api/iterator" + mrpb "google.golang.org/genproto/googleapis/api/monitoredres" + logpb "google.golang.org/genproto/googleapis/logging/v2" +) + +// ResourceDescriptors returns a ResourceDescriptorIterator +// for iterating over MonitoredResourceDescriptors. Requires ReadScope or AdminScope. +// See https://cloud.google.com/logging/docs/api/v2/#monitored-resources for an explanation of +// monitored resources. +// See https://cloud.google.com/logging/docs/api/v2/resource-list for a list of monitored resources. +func (c *Client) ResourceDescriptors(ctx context.Context) *ResourceDescriptorIterator { + it := &ResourceDescriptorIterator{ + it: c.lClient.ListMonitoredResourceDescriptors(ctx, + &logpb.ListMonitoredResourceDescriptorsRequest{}), + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.items) }, + func() interface{} { b := it.items; it.items = nil; return b }) + return it +} + +// ResourceDescriptorIterator is an iterator over MonitoredResourceDescriptors. +type ResourceDescriptorIterator struct { + it *vkit.MonitoredResourceDescriptorIterator + pageInfo *iterator.PageInfo + nextFunc func() error + items []*mrpb.MonitoredResourceDescriptor +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ResourceDescriptorIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } + +// Next returns the next result. Its second return value is Done if there are +// no more results. Once Next returns Done, all subsequent calls will return +// Done. +func (it *ResourceDescriptorIterator) Next() (*mrpb.MonitoredResourceDescriptor, error) { + if err := it.nextFunc(); err != nil { + return nil, err + } + item := it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ResourceDescriptorIterator) fetch(pageSize int, pageToken string) (string, error) { + return iterFetch(pageSize, pageToken, it.it.PageInfo(), func() error { + item, err := it.it.Next() + if err != nil { + return err + } + it.items = append(it.items, item) + return nil + }) +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/resources_test.go b/vendor/cloud.google.com/go/logging/logadmin/resources_test.go new file mode 100644 index 00000000..a1f1e87e --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/resources_test.go @@ -0,0 +1,46 @@ +// Copyright 2016 Google LLC +// +// 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 logadmin + +import ( + "context" + "testing" + + "google.golang.org/api/iterator" +) + +func TestMonitoredResourceDescriptors(t *testing.T) { + // We can't create MonitoredResourceDescriptors, and there is no guarantee + // about what the service will return. So we just check that the result is + // non-empty. + it := client.ResourceDescriptors(context.Background()) + n := 0 +loop: + for { + _, err := it.Next() + switch err { + case nil: + n++ + case iterator.Done: + break loop + default: + t.Fatal(err) + } + } + if n == 0 { + t.Fatal("Next: got no MetricResourceDescriptors, expected at least one") + } + // TODO(jba) test pagination. +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/sinks.go b/vendor/cloud.google.com/go/logging/logadmin/sinks.go new file mode 100644 index 00000000..2b54fe86 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/sinks.go @@ -0,0 +1,256 @@ +// Copyright 2016 Google LLC +// +// 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 logadmin + +import ( + "context" + "errors" + "fmt" + + vkit "cloud.google.com/go/logging/apiv2" + "google.golang.org/api/iterator" + logpb "google.golang.org/genproto/googleapis/logging/v2" + maskpb "google.golang.org/genproto/protobuf/field_mask" +) + +// Sink describes a sink used to export log entries outside Stackdriver +// Logging. Incoming log entries matching a filter are exported to a +// destination (a Cloud Storage bucket, BigQuery dataset or Cloud Pub/Sub +// topic). +// +// For more information, see https://cloud.google.com/logging/docs/export/using_exported_logs. +// (The Sinks in this package are what the documentation refers to as "project sinks".) +type Sink struct { + // ID is a client-assigned sink identifier. Example: + // "my-severe-errors-to-pubsub". + // Sink identifiers are limited to 1000 characters + // and can include only the following characters: A-Z, a-z, + // 0-9, and the special characters "_-.". + ID string + + // Destination is the export destination. See + // https://cloud.google.com/logging/docs/api/tasks/exporting-logs. + // Examples: "storage.googleapis.com/a-bucket", + // "bigquery.googleapis.com/projects/a-project-id/datasets/a-dataset". + Destination string + + // Filter optionally specifies an advanced logs filter (see + // https://cloud.google.com/logging/docs/view/advanced_filters) that + // defines the log entries to be exported. Example: "logName:syslog AND + // severity>=ERROR". If omitted, all entries are returned. + Filter string + + // WriterIdentity must be a service account name. When exporting logs, Logging + // adopts this identity for authorization. The export destination's owner must + // give this service account permission to write to the export destination. + WriterIdentity string + + // IncludeChildren, when set to true, allows the sink to export log entries from + // the organization or folder, plus (recursively) from any contained folders, billing + // accounts, or projects. IncludeChildren is false by default. You can use the sink's + // filter to choose log entries from specific projects, specific resource types, or + // specific named logs. + // + // Caution: If you enable this feature, your aggregated export sink might export + // a very large number of log entries. To avoid exporting too many log entries, + // design your aggregated export sink filter carefully, as described on + // https://cloud.google.com/logging/docs/export/aggregated_exports. + IncludeChildren bool +} + +// CreateSink creates a Sink. It returns an error if the Sink already exists. +// Requires AdminScope. +func (c *Client) CreateSink(ctx context.Context, sink *Sink) (*Sink, error) { + return c.CreateSinkOpt(ctx, sink, SinkOptions{}) +} + +// CreateSinkOpt creates a Sink using the provided options. It returns an +// error if the Sink already exists. Requires AdminScope. +func (c *Client) CreateSinkOpt(ctx context.Context, sink *Sink, opts SinkOptions) (*Sink, error) { + ls, err := c.sClient.CreateSink(ctx, &logpb.CreateSinkRequest{ + Parent: c.parent, + Sink: toLogSink(sink), + UniqueWriterIdentity: opts.UniqueWriterIdentity, + }) + if err != nil { + return nil, err + } + return fromLogSink(ls), nil +} + +// SinkOptions define options to be used when creating or updating a sink. +type SinkOptions struct { + // Determines the kind of IAM identity returned as WriterIdentity in the new + // sink. If this value is omitted or set to false, and if the sink's parent is a + // project, then the value returned as WriterIdentity is the same group or + // service account used by Stackdriver Logging before the addition of writer + // identities to the API. The sink's destination must be in the same project as + // the sink itself. + // + // If this field is set to true, or if the sink is owned by a non-project + // resource such as an organization, then the value of WriterIdentity will + // be a unique service account used only for exports from the new sink. + UniqueWriterIdentity bool + + // These fields apply only to UpdateSinkOpt calls. The corresponding sink field + // is updated if and only if the Update field is true. + UpdateDestination bool + UpdateFilter bool + UpdateIncludeChildren bool +} + +// DeleteSink deletes a sink. The provided sinkID is the sink's identifier, such as +// "my-severe-errors-to-pubsub". +// Requires AdminScope. +func (c *Client) DeleteSink(ctx context.Context, sinkID string) error { + return c.sClient.DeleteSink(ctx, &logpb.DeleteSinkRequest{ + SinkName: c.sinkPath(sinkID), + }) +} + +// Sink gets a sink. The provided sinkID is the sink's identifier, such as +// "my-severe-errors-to-pubsub". +// Requires ReadScope or AdminScope. +func (c *Client) Sink(ctx context.Context, sinkID string) (*Sink, error) { + ls, err := c.sClient.GetSink(ctx, &logpb.GetSinkRequest{ + SinkName: c.sinkPath(sinkID), + }) + if err != nil { + return nil, err + } + return fromLogSink(ls), nil +} + +// UpdateSink updates an existing Sink. Requires AdminScope. +// +// WARNING: UpdateSink will always update the Destination, Filter and IncludeChildren +// fields of the sink, even if they have their zero values. Use UpdateSinkOpt +// for more control over which fields to update. +func (c *Client) UpdateSink(ctx context.Context, sink *Sink) (*Sink, error) { + return c.UpdateSinkOpt(ctx, sink, SinkOptions{ + UpdateDestination: true, + UpdateFilter: true, + UpdateIncludeChildren: true, + }) +} + +// UpdateSinkOpt updates an existing Sink, using the provided options. Requires AdminScope. +// +// To change a sink's writer identity to a service account unique to the sink, set +// opts.UniqueWriterIdentity to true. It is not possible to change a sink's writer identity +// from a unique service account to a non-unique writer identity. +func (c *Client) UpdateSinkOpt(ctx context.Context, sink *Sink, opts SinkOptions) (*Sink, error) { + mask := &maskpb.FieldMask{} + if opts.UpdateDestination { + mask.Paths = append(mask.Paths, "destination") + } + if opts.UpdateFilter { + mask.Paths = append(mask.Paths, "filter") + } + if opts.UpdateIncludeChildren { + mask.Paths = append(mask.Paths, "include_children") + } + if opts.UniqueWriterIdentity && len(mask.Paths) == 0 { + // Hack: specify a deprecated, unchangeable field so that we have a non-empty + // field mask. (An empty field mask would cause the destination, filter and include_children + // fields to be changed.) + mask.Paths = append(mask.Paths, "output_version_format") + } + if len(mask.Paths) == 0 { + return nil, errors.New("logadmin: UpdateSinkOpt: nothing to update") + } + ls, err := c.sClient.UpdateSink(ctx, &logpb.UpdateSinkRequest{ + SinkName: c.sinkPath(sink.ID), + Sink: toLogSink(sink), + UniqueWriterIdentity: opts.UniqueWriterIdentity, + UpdateMask: mask, + }) + if err != nil { + return nil, err + } + return fromLogSink(ls), err +} + +func (c *Client) sinkPath(sinkID string) string { + return fmt.Sprintf("%s/sinks/%s", c.parent, sinkID) +} + +// Sinks returns a SinkIterator for iterating over all Sinks in the Client's project. +// Requires ReadScope or AdminScope. +func (c *Client) Sinks(ctx context.Context) *SinkIterator { + it := &SinkIterator{ + it: c.sClient.ListSinks(ctx, &logpb.ListSinksRequest{Parent: c.parent}), + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.items) }, + func() interface{} { b := it.items; it.items = nil; return b }) + return it +} + +// A SinkIterator iterates over Sinks. +type SinkIterator struct { + it *vkit.LogSinkIterator + pageInfo *iterator.PageInfo + nextFunc func() error + items []*Sink +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *SinkIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } + +// Next returns the next result. Its second return value is Done if there are +// no more results. Once Next returns Done, all subsequent calls will return +// Done. +func (it *SinkIterator) Next() (*Sink, error) { + if err := it.nextFunc(); err != nil { + return nil, err + } + item := it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *SinkIterator) fetch(pageSize int, pageToken string) (string, error) { + return iterFetch(pageSize, pageToken, it.it.PageInfo(), func() error { + item, err := it.it.Next() + if err != nil { + return err + } + it.items = append(it.items, fromLogSink(item)) + return nil + }) +} + +func toLogSink(s *Sink) *logpb.LogSink { + return &logpb.LogSink{ + Name: s.ID, + Destination: s.Destination, + Filter: s.Filter, + IncludeChildren: s.IncludeChildren, + OutputVersionFormat: logpb.LogSink_V2, + // omit WriterIdentity because it is output-only. + } +} + +func fromLogSink(ls *logpb.LogSink) *Sink { + return &Sink{ + ID: ls.Name, + Destination: ls.Destination, + Filter: ls.Filter, + WriterIdentity: ls.WriterIdentity, + IncludeChildren: ls.IncludeChildren, + } +} diff --git a/vendor/cloud.google.com/go/logging/logadmin/sinks_test.go b/vendor/cloud.google.com/go/logging/logadmin/sinks_test.go new file mode 100644 index 00000000..1762a6c1 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logadmin/sinks_test.go @@ -0,0 +1,284 @@ +// Copyright 2016 Google LLC +// +// 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. + +// TODO(jba): document in CONTRIBUTING.md that service account must be given "Logs Configuration Writer" IAM role for sink tests to pass. +// TODO(jba): [cont] (1) From top left menu, go to IAM & Admin. (2) In Roles dropdown for acct, select Logging > Logs Configuration Writer. (3) Save. +// TODO(jba): Also, cloud-logs@google.com must have Owner permission on the GCS bucket named for the test project. + +package logadmin + +import ( + "context" + "log" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/internal/uid" + ltest "cloud.google.com/go/logging/internal/testing" + "cloud.google.com/go/storage" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var sinkIDs = uid.NewSpace("GO-CLIENT-TEST-SINK", nil) + +const testFilter = "" + +var testSinkDestination string + +// Called just before TestMain calls m.Run. +// Returns a cleanup function to be called after the tests finish. +func initSinks(ctx context.Context) func() { + // Create a unique GCS bucket so concurrent tests don't interfere with each other. + bucketIDs := uid.NewSpace(testProjectID+"-log-sink", nil) + testBucket := bucketIDs.New() + testSinkDestination = "storage.googleapis.com/" + testBucket + var storageClient *storage.Client + if integrationTest { + // Create a unique bucket as a sink destination, and give the cloud logging account + // owner right. + ts := testutil.TokenSource(ctx, storage.ScopeFullControl) + var err error + storageClient, err = storage.NewClient(ctx, option.WithTokenSource(ts)) + if err != nil { + log.Fatalf("new storage client: %v", err) + } + bucket := storageClient.Bucket(testBucket) + if err := bucket.Create(ctx, testProjectID, nil); err != nil { + log.Fatalf("creating storage bucket %q: %v", testBucket, err) + } + log.Printf("successfully created bucket %s", testBucket) + if err := bucket.ACL().Set(ctx, "group-cloud-logs@google.com", storage.RoleOwner); err != nil { + log.Fatalf("setting owner role: %v", err) + } + } + // Clean up from aborted tests. + it := client.Sinks(ctx) + for { + s, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + log.Printf("listing sinks: %v", err) + break + } + if sinkIDs.Older(s.ID, time.Hour) { + client.DeleteSink(ctx, s.ID) // ignore error + } + } + if integrationTest { + for _, bn := range bucketNames(ctx, storageClient) { + if bucketIDs.Older(bn, 24*time.Hour) { + storageClient.Bucket(bn).Delete(ctx) // ignore error + } + } + return func() { + storageClient.Close() + } + } + return func() {} +} + +// Collect the name of all buckets for the test project. +func bucketNames(ctx context.Context, client *storage.Client) []string { + var names []string + it := client.Buckets(ctx, testProjectID) +loop: + for { + b, err := it.Next() + switch err { + case nil: + names = append(names, b.Name) + case iterator.Done: + break loop + default: + log.Printf("listing buckets: %v", err) + break loop + } + } + return names +} + +func TestCreateSink(t *testing.T) { + ctx := context.Background() + sink := &Sink{ + ID: sinkIDs.New(), + Destination: testSinkDestination, + Filter: testFilter, + IncludeChildren: true, + } + got, err := client.CreateSink(ctx, sink) + if err != nil { + t.Fatal(err) + } + sink.WriterIdentity = ltest.SharedServiceAccount + if want := sink; !testutil.Equal(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } + got, err = client.Sink(ctx, sink.ID) + if err != nil { + t.Fatal(err) + } + if want := sink; !testutil.Equal(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } + + // UniqueWriterIdentity + sink.ID = sinkIDs.New() + got, err = client.CreateSinkOpt(ctx, sink, SinkOptions{UniqueWriterIdentity: true}) + if err != nil { + t.Fatal(err) + } + // The WriterIdentity should be different. + if got.WriterIdentity == sink.WriterIdentity { + t.Errorf("got %s, want something different", got.WriterIdentity) + } +} + +func TestUpdateSink(t *testing.T) { + ctx := context.Background() + sink := &Sink{ + ID: sinkIDs.New(), + Destination: testSinkDestination, + Filter: testFilter, + IncludeChildren: true, + WriterIdentity: ltest.SharedServiceAccount, + } + + if _, err := client.CreateSink(ctx, sink); err != nil { + t.Fatal(err) + } + got, err := client.UpdateSink(ctx, sink) + if err != nil { + t.Fatal(err) + } + if want := sink; !testutil.Equal(got, want) { + t.Errorf("got\n%+v\nwant\n%+v", got, want) + } + got, err = client.Sink(ctx, sink.ID) + if err != nil { + t.Fatal(err) + } + if want := sink; !testutil.Equal(got, want) { + t.Errorf("got\n%+v\nwant\n%+v", got, want) + } + + // Updating an existing sink changes it. + sink.Filter = "" + sink.IncludeChildren = false + if _, err := client.UpdateSink(ctx, sink); err != nil { + t.Fatal(err) + } + got, err = client.Sink(ctx, sink.ID) + if err != nil { + t.Fatal(err) + } + if want := sink; !testutil.Equal(got, want) { + t.Errorf("got\n%+v\nwant\n%+v", got, want) + } +} + +func TestUpdateSinkOpt(t *testing.T) { + ctx := context.Background() + id := sinkIDs.New() + origSink := &Sink{ + ID: id, + Destination: testSinkDestination, + Filter: testFilter, + IncludeChildren: true, + WriterIdentity: ltest.SharedServiceAccount, + } + + if _, err := client.CreateSink(ctx, origSink); err != nil { + t.Fatal(err) + } + + // Updating with empty options is an error. + _, err := client.UpdateSinkOpt(ctx, &Sink{ID: id, Destination: testSinkDestination}, SinkOptions{}) + if err == nil { + t.Errorf("got %v, want nil", err) + } + + // Update selected fields. + got, err := client.UpdateSinkOpt(ctx, &Sink{ID: id}, SinkOptions{ + UpdateFilter: true, + UpdateIncludeChildren: true, + }) + if err != nil { + t.Fatal(err) + } + want := *origSink + want.Filter = "" + want.IncludeChildren = false + if !testutil.Equal(got, &want) { + t.Errorf("got\n%+v\nwant\n%+v", got, want) + } + + // Update writer identity. + got, err = client.UpdateSinkOpt(ctx, &Sink{ID: id, Filter: "foo"}, + SinkOptions{UniqueWriterIdentity: true}) + if err != nil { + t.Fatal(err) + } + if got.WriterIdentity == want.WriterIdentity { + t.Errorf("got %s, want something different", got.WriterIdentity) + } + want.WriterIdentity = got.WriterIdentity + if !testutil.Equal(got, &want) { + t.Errorf("got\n%+v\nwant\n%+v", got, want) + } +} + +func TestListSinks(t *testing.T) { + ctx := context.Background() + var sinks []*Sink + want := map[string]*Sink{} + for i := 0; i < 4; i++ { + s := &Sink{ + ID: sinkIDs.New(), + Destination: testSinkDestination, + Filter: testFilter, + WriterIdentity: "serviceAccount:cloud-logs@system.gserviceaccount.com", + } + sinks = append(sinks, s) + want[s.ID] = s + } + for _, s := range sinks { + if _, err := client.CreateSink(ctx, s); err != nil { + t.Fatalf("Create(%q): %v", s.ID, err) + } + } + + got := map[string]*Sink{} + it := client.Sinks(ctx) + for { + s, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + t.Fatal(err) + } + // If tests run simultaneously, we may have more sinks than we + // created. So only check for our own. + if _, ok := want[s.ID]; ok { + got[s.ID] = s + } + } + if !testutil.Equal(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } +} diff --git a/vendor/cloud.google.com/go/logging/logging.go b/vendor/cloud.google.com/go/logging/logging.go new file mode 100644 index 00000000..6cc3ebb5 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logging.go @@ -0,0 +1,842 @@ +// Copyright 2016 Google LLC +// +// 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. + +// API/gRPC features intentionally missing from this client: +// - You cannot have the server pick the time of the entry. This client +// always sends a time. +// - There is no way to provide a protocol buffer payload. +// - No support for the "partial success" feature when writing log entries. + +// TODO(jba): test whether forward-slash characters in the log ID must be URL-encoded. +// These features are missing now, but will likely be added: +// - There is no way to specify CallOptions. + +package logging + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "log" + "net/http" + "strconv" + "strings" + "sync" + "time" + + "cloud.google.com/go/compute/metadata" + "cloud.google.com/go/internal/version" + vkit "cloud.google.com/go/logging/apiv2" + "cloud.google.com/go/logging/internal" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + structpb "github.com/golang/protobuf/ptypes/struct" + tspb "github.com/golang/protobuf/ptypes/timestamp" + "google.golang.org/api/option" + "google.golang.org/api/support/bundler" + mrpb "google.golang.org/genproto/googleapis/api/monitoredres" + logtypepb "google.golang.org/genproto/googleapis/logging/type" + logpb "google.golang.org/genproto/googleapis/logging/v2" +) + +const ( + // ReadScope is the scope for reading from the logging service. + ReadScope = "https://www.googleapis.com/auth/logging.read" + + // WriteScope is the scope for writing to the logging service. + WriteScope = "https://www.googleapis.com/auth/logging.write" + + // AdminScope is the scope for administrative actions on the logging service. + AdminScope = "https://www.googleapis.com/auth/logging.admin" +) + +const ( + // defaultErrorCapacity is the capacity of the channel used to deliver + // errors to the OnError function. + defaultErrorCapacity = 10 + + // DefaultDelayThreshold is the default value for the DelayThreshold LoggerOption. + DefaultDelayThreshold = time.Second + + // DefaultEntryCountThreshold is the default value for the EntryCountThreshold LoggerOption. + DefaultEntryCountThreshold = 1000 + + // DefaultEntryByteThreshold is the default value for the EntryByteThreshold LoggerOption. + DefaultEntryByteThreshold = 1 << 20 // 1MiB + + // DefaultBufferedByteLimit is the default value for the BufferedByteLimit LoggerOption. + DefaultBufferedByteLimit = 1 << 30 // 1GiB + + // defaultWriteTimeout is the timeout for the underlying write API calls. As + // write API calls are not idempotent, they are not retried on timeout. This + // timeout is to allow clients to degrade gracefully if underlying logging + // service is temporarily impaired for some reason. + defaultWriteTimeout = 10 * time.Minute +) + +// For testing: +var now = time.Now + +// ErrOverflow signals that the number of buffered entries for a Logger +// exceeds its BufferLimit. +var ErrOverflow = bundler.ErrOverflow + +// ErrOversizedEntry signals that an entry's size exceeds the maximum number of +// bytes that will be sent in a single call to the logging service. +var ErrOversizedEntry = bundler.ErrOversizedItem + +// Client is a Logging client. A Client is associated with a single Cloud project. +type Client struct { + client *vkit.Client // client for the logging service + parent string // e.g. "projects/proj-id" + errc chan error // should be buffered to minimize dropped errors + donec chan struct{} // closed on Client.Close to close Logger bundlers + loggers sync.WaitGroup // so we can wait for loggers to close + closed bool + + mu sync.Mutex + nErrs int // number of errors we saw + lastErr error // last error we saw + + // OnError is called when an error occurs in a call to Log or Flush. The + // error may be due to an invalid Entry, an overflow because BufferLimit + // was reached (in which case the error will be ErrOverflow) or an error + // communicating with the logging service. OnError is called with errors + // from all Loggers. It is never called concurrently. OnError is expected + // to return quickly; if errors occur while OnError is running, some may + // not be reported. The default behavior is to call log.Printf. + // + // This field should be set only once, before any method of Client is called. + OnError func(err error) +} + +// NewClient returns a new logging client associated with the provided parent. +// A parent can take any of the following forms: +// projects/PROJECT_ID +// folders/FOLDER_ID +// billingAccounts/ACCOUNT_ID +// organizations/ORG_ID +// for backwards compatibility, a string with no '/' is also allowed and is interpreted +// as a project ID. +// +// By default NewClient uses WriteScope. To use a different scope, call +// NewClient using a WithScopes option (see https://godoc.org/google.golang.org/api/option#WithScopes). +func NewClient(ctx context.Context, parent string, opts ...option.ClientOption) (*Client, error) { + if !strings.ContainsRune(parent, '/') { + parent = "projects/" + parent + } + opts = append([]option.ClientOption{ + option.WithEndpoint(internal.ProdAddr), + option.WithScopes(WriteScope), + }, opts...) + c, err := vkit.NewClient(ctx, opts...) + if err != nil { + return nil, err + } + c.SetGoogleClientInfo("gccl", version.Repo) + client := &Client{ + client: c, + parent: parent, + errc: make(chan error, defaultErrorCapacity), // create a small buffer for errors + donec: make(chan struct{}), + OnError: func(e error) { log.Printf("logging client: %v", e) }, + } + // Call the user's function synchronously, to make life easier for them. + go func() { + for err := range client.errc { + // This reference to OnError is memory-safe if the user sets OnError before + // calling any client methods. The reference happens before the first read from + // client.errc, which happens before the first write to client.errc, which + // happens before any call, which happens before the user sets OnError. + if fn := client.OnError; fn != nil { + fn(err) + } else { + log.Printf("logging (parent %q): %v", parent, err) + } + } + }() + return client, nil +} + +var unixZeroTimestamp *tspb.Timestamp + +func init() { + var err error + unixZeroTimestamp, err = ptypes.TimestampProto(time.Unix(0, 0)) + if err != nil { + panic(err) + } +} + +// Ping reports whether the client's connection to the logging service and the +// authentication configuration are valid. To accomplish this, Ping writes a +// log entry "ping" to a log named "ping". +func (c *Client) Ping(ctx context.Context) error { + ent := &logpb.LogEntry{ + Payload: &logpb.LogEntry_TextPayload{TextPayload: "ping"}, + Timestamp: unixZeroTimestamp, // Identical timestamps and insert IDs are both + InsertId: "ping", // necessary for the service to dedup these entries. + } + _, err := c.client.WriteLogEntries(ctx, &logpb.WriteLogEntriesRequest{ + LogName: internal.LogPath(c.parent, "ping"), + Resource: monitoredResource(c.parent), + Entries: []*logpb.LogEntry{ent}, + }) + return err +} + +// error puts the error on the client's error channel +// without blocking, and records summary error info. +func (c *Client) error(err error) { + select { + case c.errc <- err: + default: + } + c.mu.Lock() + c.lastErr = err + c.nErrs++ + c.mu.Unlock() +} + +func (c *Client) extractErrorInfo() error { + var err error + c.mu.Lock() + if c.lastErr != nil { + err = fmt.Errorf("saw %d errors; last: %v", c.nErrs, c.lastErr) + c.nErrs = 0 + c.lastErr = nil + } + c.mu.Unlock() + return err +} + +// A Logger is used to write log messages to a single log. It can be configured +// with a log ID, common monitored resource, and a set of common labels. +type Logger struct { + client *Client + logName string // "projects/{projectID}/logs/{logID}" + stdLoggers map[Severity]*log.Logger + bundler *bundler.Bundler + + // Options + commonResource *mrpb.MonitoredResource + commonLabels map[string]string + writeTimeout time.Duration + ctxFunc func() (context.Context, func()) +} + +// A LoggerOption is a configuration option for a Logger. +type LoggerOption interface { + set(*Logger) +} + +// CommonResource sets the monitored resource associated with all log entries +// written from a Logger. If not provided, the resource is automatically +// detected based on the running environment. This value can be overridden +// per-entry by setting an Entry's Resource field. +func CommonResource(r *mrpb.MonitoredResource) LoggerOption { return commonResource{r} } + +type commonResource struct{ *mrpb.MonitoredResource } + +func (r commonResource) set(l *Logger) { l.commonResource = r.MonitoredResource } + +var detectedResource struct { + pb *mrpb.MonitoredResource + once sync.Once +} + +func detectResource() *mrpb.MonitoredResource { + detectedResource.once.Do(func() { + if !metadata.OnGCE() { + return + } + projectID, err := metadata.ProjectID() + if err != nil { + return + } + id, err := metadata.InstanceID() + if err != nil { + return + } + zone, err := metadata.Zone() + if err != nil { + return + } + detectedResource.pb = &mrpb.MonitoredResource{ + Type: "gce_instance", + Labels: map[string]string{ + "project_id": projectID, + "instance_id": id, + "zone": zone, + }, + } + }) + return detectedResource.pb +} + +var resourceInfo = map[string]struct{ rtype, label string }{ + "organizations": {"organization", "organization_id"}, + "folders": {"folder", "folder_id"}, + "projects": {"project", "project_id"}, + "billingAccounts": {"billing_account", "account_id"}, +} + +func monitoredResource(parent string) *mrpb.MonitoredResource { + parts := strings.SplitN(parent, "/", 2) + if len(parts) != 2 { + return globalResource(parent) + } + info, ok := resourceInfo[parts[0]] + if !ok { + return globalResource(parts[1]) + } + return &mrpb.MonitoredResource{ + Type: info.rtype, + Labels: map[string]string{info.label: parts[1]}, + } +} + +func globalResource(projectID string) *mrpb.MonitoredResource { + return &mrpb.MonitoredResource{ + Type: "global", + Labels: map[string]string{ + "project_id": projectID, + }, + } +} + +// CommonLabels are labels that apply to all log entries written from a Logger, +// so that you don't have to repeat them in each log entry's Labels field. If +// any of the log entries contains a (key, value) with the same key that is in +// CommonLabels, then the entry's (key, value) overrides the one in +// CommonLabels. +func CommonLabels(m map[string]string) LoggerOption { return commonLabels(m) } + +type commonLabels map[string]string + +func (c commonLabels) set(l *Logger) { l.commonLabels = c } + +// ConcurrentWriteLimit determines how many goroutines will send log entries to the +// underlying service. The default is 1. Set ConcurrentWriteLimit to a higher value to +// increase throughput. +func ConcurrentWriteLimit(n int) LoggerOption { return concurrentWriteLimit(n) } + +type concurrentWriteLimit int + +func (c concurrentWriteLimit) set(l *Logger) { l.bundler.HandlerLimit = int(c) } + +// DelayThreshold is the maximum amount of time that an entry should remain +// buffered in memory before a call to the logging service is triggered. Larger +// values of DelayThreshold will generally result in fewer calls to the logging +// service, while increasing the risk that log entries will be lost if the +// process crashes. +// The default is DefaultDelayThreshold. +func DelayThreshold(d time.Duration) LoggerOption { return delayThreshold(d) } + +type delayThreshold time.Duration + +func (d delayThreshold) set(l *Logger) { l.bundler.DelayThreshold = time.Duration(d) } + +// EntryCountThreshold is the maximum number of entries that will be buffered +// in memory before a call to the logging service is triggered. Larger values +// will generally result in fewer calls to the logging service, while +// increasing both memory consumption and the risk that log entries will be +// lost if the process crashes. +// The default is DefaultEntryCountThreshold. +func EntryCountThreshold(n int) LoggerOption { return entryCountThreshold(n) } + +type entryCountThreshold int + +func (e entryCountThreshold) set(l *Logger) { l.bundler.BundleCountThreshold = int(e) } + +// EntryByteThreshold is the maximum number of bytes of entries that will be +// buffered in memory before a call to the logging service is triggered. See +// EntryCountThreshold for a discussion of the tradeoffs involved in setting +// this option. +// The default is DefaultEntryByteThreshold. +func EntryByteThreshold(n int) LoggerOption { return entryByteThreshold(n) } + +type entryByteThreshold int + +func (e entryByteThreshold) set(l *Logger) { l.bundler.BundleByteThreshold = int(e) } + +// EntryByteLimit is the maximum number of bytes of entries that will be sent +// in a single call to the logging service. ErrOversizedEntry is returned if an +// entry exceeds EntryByteLimit. This option limits the size of a single RPC +// payload, to account for network or service issues with large RPCs. If +// EntryByteLimit is smaller than EntryByteThreshold, the latter has no effect. +// The default is zero, meaning there is no limit. +func EntryByteLimit(n int) LoggerOption { return entryByteLimit(n) } + +type entryByteLimit int + +func (e entryByteLimit) set(l *Logger) { l.bundler.BundleByteLimit = int(e) } + +// BufferedByteLimit is the maximum number of bytes that the Logger will keep +// in memory before returning ErrOverflow. This option limits the total memory +// consumption of the Logger (but note that each Logger has its own, separate +// limit). It is possible to reach BufferedByteLimit even if it is larger than +// EntryByteThreshold or EntryByteLimit, because calls triggered by the latter +// two options may be enqueued (and hence occupying memory) while new log +// entries are being added. +// The default is DefaultBufferedByteLimit. +func BufferedByteLimit(n int) LoggerOption { return bufferedByteLimit(n) } + +type bufferedByteLimit int + +func (b bufferedByteLimit) set(l *Logger) { l.bundler.BufferedByteLimit = int(b) } + +// ContextFunc is a function that will be called to obtain a context.Context for the +// WriteLogEntries RPC executed in the background for calls to Logger.Log. The +// default is a function that always returns context.Background. The second return +// value of the function is a function to call after the RPC completes. +// +// The function is not used for calls to Logger.LogSync, since the caller can pass +// in the context directly. +// +// This option is EXPERIMENTAL. It may be changed or removed. +func ContextFunc(f func() (ctx context.Context, afterCall func())) LoggerOption { + return contextFunc(f) +} + +type contextFunc func() (ctx context.Context, afterCall func()) + +func (c contextFunc) set(l *Logger) { l.ctxFunc = c } + +// Logger returns a Logger that will write entries with the given log ID, such as +// "syslog". A log ID must be less than 512 characters long and can only +// include the following characters: upper and lower case alphanumeric +// characters: [A-Za-z0-9]; and punctuation characters: forward-slash, +// underscore, hyphen, and period. +func (c *Client) Logger(logID string, opts ...LoggerOption) *Logger { + r := detectResource() + if r == nil { + r = monitoredResource(c.parent) + } + l := &Logger{ + client: c, + logName: internal.LogPath(c.parent, logID), + commonResource: r, + ctxFunc: func() (context.Context, func()) { return context.Background(), nil }, + } + l.bundler = bundler.NewBundler(&logpb.LogEntry{}, func(entries interface{}) { + l.writeLogEntries(entries.([]*logpb.LogEntry)) + }) + l.bundler.DelayThreshold = DefaultDelayThreshold + l.bundler.BundleCountThreshold = DefaultEntryCountThreshold + l.bundler.BundleByteThreshold = DefaultEntryByteThreshold + l.bundler.BufferedByteLimit = DefaultBufferedByteLimit + for _, opt := range opts { + opt.set(l) + } + l.stdLoggers = map[Severity]*log.Logger{} + for s := range severityName { + l.stdLoggers[s] = log.New(severityWriter{l, s}, "", 0) + } + + c.loggers.Add(1) + // Start a goroutine that cleans up the bundler, its channel + // and the writer goroutines when the client is closed. + go func() { + defer c.loggers.Done() + <-c.donec + l.bundler.Flush() + }() + return l +} + +type severityWriter struct { + l *Logger + s Severity +} + +func (w severityWriter) Write(p []byte) (n int, err error) { + w.l.Log(Entry{ + Severity: w.s, + Payload: string(p), + }) + return len(p), nil +} + +// Close waits for all opened loggers to be flushed and closes the client. +func (c *Client) Close() error { + if c.closed { + return nil + } + close(c.donec) // close Logger bundlers + c.loggers.Wait() // wait for all bundlers to flush and close + // Now there can be no more errors. + close(c.errc) // terminate error goroutine + // Prefer errors arising from logging to the error returned from Close. + err := c.extractErrorInfo() + err2 := c.client.Close() + if err == nil { + err = err2 + } + c.closed = true + return err +} + +// Severity is the severity of the event described in a log entry. These +// guideline severity levels are ordered, with numerically smaller levels +// treated as less severe than numerically larger levels. +type Severity int + +const ( + // Default means the log entry has no assigned severity level. + Default = Severity(logtypepb.LogSeverity_DEFAULT) + // Debug means debug or trace information. + Debug = Severity(logtypepb.LogSeverity_DEBUG) + // Info means routine information, such as ongoing status or performance. + Info = Severity(logtypepb.LogSeverity_INFO) + // Notice means normal but significant events, such as start up, shut down, or configuration. + Notice = Severity(logtypepb.LogSeverity_NOTICE) + // Warning means events that might cause problems. + Warning = Severity(logtypepb.LogSeverity_WARNING) + // Error means events that are likely to cause problems. + Error = Severity(logtypepb.LogSeverity_ERROR) + // Critical means events that cause more severe problems or brief outages. + Critical = Severity(logtypepb.LogSeverity_CRITICAL) + // Alert means a person must take an action immediately. + Alert = Severity(logtypepb.LogSeverity_ALERT) + // Emergency means one or more systems are unusable. + Emergency = Severity(logtypepb.LogSeverity_EMERGENCY) +) + +var severityName = map[Severity]string{ + Default: "Default", + Debug: "Debug", + Info: "Info", + Notice: "Notice", + Warning: "Warning", + Error: "Error", + Critical: "Critical", + Alert: "Alert", + Emergency: "Emergency", +} + +// String converts a severity level to a string. +func (v Severity) String() string { + // same as proto.EnumName + s, ok := severityName[v] + if ok { + return s + } + return strconv.Itoa(int(v)) +} + +// ParseSeverity returns the Severity whose name equals s, ignoring case. It +// returns Default if no Severity matches. +func ParseSeverity(s string) Severity { + sl := strings.ToLower(s) + for sev, name := range severityName { + if strings.ToLower(name) == sl { + return sev + } + } + return Default +} + +// Entry is a log entry. +// See https://cloud.google.com/logging/docs/view/logs_index for more about entries. +type Entry struct { + // Timestamp is the time of the entry. If zero, the current time is used. + Timestamp time.Time + + // Severity is the entry's severity level. + // The zero value is Default. + Severity Severity + + // Payload must be either a string, or something that marshals via the + // encoding/json package to a JSON object (and not any other type of JSON value). + Payload interface{} + + // Labels optionally specifies key/value labels for the log entry. + // The Logger.Log method takes ownership of this map. See Logger.CommonLabels + // for more about labels. + Labels map[string]string + + // InsertID is a unique ID for the log entry. If you provide this field, + // the logging service considers other log entries in the same log with the + // same ID as duplicates which can be removed. If omitted, the logging + // service will generate a unique ID for this log entry. Note that because + // this client retries RPCs automatically, it is possible (though unlikely) + // that an Entry without an InsertID will be written more than once. + InsertID string + + // HTTPRequest optionally specifies metadata about the HTTP request + // associated with this log entry, if applicable. It is optional. + HTTPRequest *HTTPRequest + + // Operation optionally provides information about an operation associated + // with the log entry, if applicable. + Operation *logpb.LogEntryOperation + + // LogName is the full log name, in the form + // "projects/{ProjectID}/logs/{LogID}". It is set by the client when + // reading entries. It is an error to set it when writing entries. + LogName string + + // Resource is the monitored resource associated with the entry. + Resource *mrpb.MonitoredResource + + // Trace is the resource name of the trace associated with the log entry, + // if any. If it contains a relative resource name, the name is assumed to + // be relative to //tracing.googleapis.com. + Trace string + + // Optional. Source code location information associated with the log entry, + // if any. + SourceLocation *logpb.LogEntrySourceLocation +} + +// HTTPRequest contains an http.Request as well as additional +// information about the request and its response. +type HTTPRequest struct { + // Request is the http.Request passed to the handler. + Request *http.Request + + // RequestSize is the size of the HTTP request message in bytes, including + // the request headers and the request body. + RequestSize int64 + + // Status is the response code indicating the status of the response. + // Examples: 200, 404. + Status int + + // ResponseSize is the size of the HTTP response message sent back to the client, in bytes, + // including the response headers and the response body. + ResponseSize int64 + + // Latency is the request processing latency on the server, from the time the request was + // received until the response was sent. + Latency time.Duration + + // LocalIP is the IP address (IPv4 or IPv6) of the origin server that the request + // was sent to. + LocalIP string + + // RemoteIP is the IP address (IPv4 or IPv6) of the client that issued the + // HTTP request. Examples: "192.168.1.1", "FE80::0202:B3FF:FE1E:8329". + RemoteIP string + + // CacheHit reports whether an entity was served from cache (with or without + // validation). + CacheHit bool + + // CacheValidatedWithOriginServer reports whether the response was + // validated with the origin server before being served from cache. This + // field is only meaningful if CacheHit is true. + CacheValidatedWithOriginServer bool +} + +func fromHTTPRequest(r *HTTPRequest) *logtypepb.HttpRequest { + if r == nil { + return nil + } + if r.Request == nil { + panic("HTTPRequest must have a non-nil Request") + } + u := *r.Request.URL + u.Fragment = "" + pb := &logtypepb.HttpRequest{ + RequestMethod: r.Request.Method, + RequestUrl: u.String(), + RequestSize: r.RequestSize, + Status: int32(r.Status), + ResponseSize: r.ResponseSize, + UserAgent: r.Request.UserAgent(), + ServerIp: r.LocalIP, + RemoteIp: r.RemoteIP, // TODO(jba): attempt to parse http.Request.RemoteAddr? + Referer: r.Request.Referer(), + CacheHit: r.CacheHit, + CacheValidatedWithOriginServer: r.CacheValidatedWithOriginServer, + } + if r.Latency != 0 { + pb.Latency = ptypes.DurationProto(r.Latency) + } + return pb +} + +// toProtoStruct converts v, which must marshal into a JSON object, +// into a Google Struct proto. +func toProtoStruct(v interface{}) (*structpb.Struct, error) { + // Fast path: if v is already a *structpb.Struct, nothing to do. + if s, ok := v.(*structpb.Struct); ok { + return s, nil + } + // v is a Go value that supports JSON marshalling. We want a Struct + // protobuf. Some day we may have a more direct way to get there, but right + // now the only way is to marshal the Go value to JSON, unmarshal into a + // map, and then build the Struct proto from the map. + var jb []byte + var err error + if raw, ok := v.(json.RawMessage); ok { // needed for Go 1.7 and below + jb = []byte(raw) + } else { + jb, err = json.Marshal(v) + if err != nil { + return nil, fmt.Errorf("logging: json.Marshal: %v", err) + } + } + var m map[string]interface{} + err = json.Unmarshal(jb, &m) + if err != nil { + return nil, fmt.Errorf("logging: json.Unmarshal: %v", err) + } + return jsonMapToProtoStruct(m), nil +} + +func jsonMapToProtoStruct(m map[string]interface{}) *structpb.Struct { + fields := map[string]*structpb.Value{} + for k, v := range m { + fields[k] = jsonValueToStructValue(v) + } + return &structpb.Struct{Fields: fields} +} + +func jsonValueToStructValue(v interface{}) *structpb.Value { + switch x := v.(type) { + case bool: + return &structpb.Value{Kind: &structpb.Value_BoolValue{BoolValue: x}} + case float64: + return &structpb.Value{Kind: &structpb.Value_NumberValue{NumberValue: x}} + case string: + return &structpb.Value{Kind: &structpb.Value_StringValue{StringValue: x}} + case nil: + return &structpb.Value{Kind: &structpb.Value_NullValue{}} + case map[string]interface{}: + return &structpb.Value{Kind: &structpb.Value_StructValue{StructValue: jsonMapToProtoStruct(x)}} + case []interface{}: + var vals []*structpb.Value + for _, e := range x { + vals = append(vals, jsonValueToStructValue(e)) + } + return &structpb.Value{Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{Values: vals}}} + default: + panic(fmt.Sprintf("bad type %T for JSON value", v)) + } +} + +// LogSync logs the Entry synchronously without any buffering. Because LogSync is slow +// and will block, it is intended primarily for debugging or critical errors. +// Prefer Log for most uses. +// TODO(jba): come up with a better name (LogNow?) or eliminate. +func (l *Logger) LogSync(ctx context.Context, e Entry) error { + ent, err := l.toLogEntry(e) + if err != nil { + return err + } + _, err = l.client.client.WriteLogEntries(ctx, &logpb.WriteLogEntriesRequest{ + LogName: l.logName, + Resource: l.commonResource, + Labels: l.commonLabels, + Entries: []*logpb.LogEntry{ent}, + }) + return err +} + +// Log buffers the Entry for output to the logging service. It never blocks. +func (l *Logger) Log(e Entry) { + ent, err := l.toLogEntry(e) + if err != nil { + l.client.error(err) + return + } + if err := l.bundler.Add(ent, proto.Size(ent)); err != nil { + l.client.error(err) + } +} + +// Flush blocks until all currently buffered log entries are sent. +// +// If any errors occurred since the last call to Flush from any Logger, or the +// creation of the client if this is the first call, then Flush returns a non-nil +// error with summary information about the errors. This information is unlikely to +// be actionable. For more accurate error reporting, set Client.OnError. +func (l *Logger) Flush() error { + l.bundler.Flush() + return l.client.extractErrorInfo() +} + +func (l *Logger) writeLogEntries(entries []*logpb.LogEntry) { + req := &logpb.WriteLogEntriesRequest{ + LogName: l.logName, + Resource: l.commonResource, + Labels: l.commonLabels, + Entries: entries, + } + ctx, afterCall := l.ctxFunc() + ctx, cancel := context.WithTimeout(ctx, defaultWriteTimeout) + defer cancel() + _, err := l.client.client.WriteLogEntries(ctx, req) + if err != nil { + l.client.error(err) + } + if afterCall != nil { + afterCall() + } +} + +// StandardLogger returns a *log.Logger for the provided severity. +// +// This method is cheap. A single log.Logger is pre-allocated for each +// severity level in each Logger. Callers may mutate the returned log.Logger +// (for example by calling SetFlags or SetPrefix). +func (l *Logger) StandardLogger(s Severity) *log.Logger { return l.stdLoggers[s] } + +func (l *Logger) toLogEntry(e Entry) (*logpb.LogEntry, error) { + if e.LogName != "" { + return nil, errors.New("logging: Entry.LogName should be not be set when writing") + } + t := e.Timestamp + if t.IsZero() { + t = now() + } + ts, err := ptypes.TimestampProto(t) + if err != nil { + return nil, err + } + if e.Trace == "" && e.HTTPRequest != nil && e.HTTPRequest.Request != nil { + traceHeader := e.HTTPRequest.Request.Header.Get("X-Cloud-Trace-Context") + if traceHeader != "" { + // Set to a relative resource name, as described at + // https://cloud.google.com/appengine/docs/flexible/go/writing-application-logs. + e.Trace = fmt.Sprintf("%s/traces/%s", l.client.parent, traceHeader) + } + } + ent := &logpb.LogEntry{ + Timestamp: ts, + Severity: logtypepb.LogSeverity(e.Severity), + InsertId: e.InsertID, + HttpRequest: fromHTTPRequest(e.HTTPRequest), + Operation: e.Operation, + Labels: e.Labels, + Trace: e.Trace, + Resource: e.Resource, + SourceLocation: e.SourceLocation, + } + switch p := e.Payload.(type) { + case string: + ent.Payload = &logpb.LogEntry_TextPayload{TextPayload: p} + default: + s, err := toProtoStruct(p) + if err != nil { + return nil, err + } + ent.Payload = &logpb.LogEntry_JsonPayload{JsonPayload: s} + } + return ent, nil +} diff --git a/vendor/cloud.google.com/go/logging/logging_test.go b/vendor/cloud.google.com/go/logging/logging_test.go new file mode 100644 index 00000000..bea566b0 --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logging_test.go @@ -0,0 +1,631 @@ +// Copyright 2016 Google LLC +// +// 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. + +// TODO(jba): test that OnError is getting called appropriately. + +package logging_test + +import ( + "context" + "flag" + "fmt" + "log" + "math/rand" + "os" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + cinternal "cloud.google.com/go/internal" + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/internal/uid" + "cloud.google.com/go/logging" + ltesting "cloud.google.com/go/logging/internal/testing" + "cloud.google.com/go/logging/logadmin" + gax "github.com/googleapis/gax-go" + "golang.org/x/oauth2" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + mrpb "google.golang.org/genproto/googleapis/api/monitoredres" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const testLogIDPrefix = "GO-LOGGING-CLIENT/TEST-LOG" + +var ( + client *logging.Client + aclient *logadmin.Client + testProjectID string + testLogID string + testFilter string + errorc chan error + ctx context.Context + + // Adjust the fields of a FullEntry received from the production service + // before comparing it with the expected result. We can't correctly + // compare certain fields, like times or server-generated IDs. + clean func(*logging.Entry) + + // Create a new client with the given project ID. + newClients func(ctx context.Context, projectID string) (*logging.Client, *logadmin.Client) + + uids = uid.NewSpace(testLogIDPrefix, nil) + + // If true, this test is using the production service, not a fake. + integrationTest bool +) + +func testNow() time.Time { + return time.Unix(1000, 0) +} + +func TestMain(m *testing.M) { + flag.Parse() // needed for testing.Short() + ctx = context.Background() + testProjectID = testutil.ProjID() + errorc = make(chan error, 100) + if testProjectID == "" || testing.Short() { + integrationTest = false + if testProjectID != "" { + log.Print("Integration tests skipped in short mode (using fake instead)") + } + testProjectID = ltesting.ValidProjectID + clean = func(e *logging.Entry) { + // Remove the insert ID for consistency with the integration test. + e.InsertID = "" + } + + addr, err := ltesting.NewServer() + if err != nil { + log.Fatalf("creating fake server: %v", err) + } + logging.SetNow(testNow) + + newClients = func(ctx context.Context, parent string) (*logging.Client, *logadmin.Client) { + conn, err := grpc.Dial(addr, grpc.WithInsecure()) + if err != nil { + log.Fatalf("dialing %q: %v", addr, err) + } + c, err := logging.NewClient(ctx, parent, option.WithGRPCConn(conn)) + if err != nil { + log.Fatalf("creating client for fake at %q: %v", addr, err) + } + ac, err := logadmin.NewClient(ctx, parent, option.WithGRPCConn(conn)) + if err != nil { + log.Fatalf("creating client for fake at %q: %v", addr, err) + } + return c, ac + } + + } else { + integrationTest = true + clean = func(e *logging.Entry) { + // We cannot compare timestamps, so set them to the test time. + // Also, remove the insert ID added by the service. + e.Timestamp = testNow().UTC() + e.InsertID = "" + } + ts := testutil.TokenSource(ctx, logging.AdminScope) + if ts == nil { + log.Fatal("The project key must be set. See CONTRIBUTING.md for details") + } + log.Printf("running integration tests with project %s", testProjectID) + newClients = func(ctx context.Context, parent string) (*logging.Client, *logadmin.Client) { + c, err := logging.NewClient(ctx, parent, option.WithTokenSource(ts)) + if err != nil { + log.Fatalf("creating prod client: %v", err) + } + ac, err := logadmin.NewClient(ctx, parent, option.WithTokenSource(ts)) + if err != nil { + log.Fatalf("creating prod client: %v", err) + } + return c, ac + } + + } + client, aclient = newClients(ctx, testProjectID) + client.OnError = func(e error) { errorc <- e } + + exit := m.Run() + os.Exit(exit) +} + +func initLogs() { + testLogID = uids.New() + hourAgo := time.Now().Add(-1 * time.Hour).UTC() + testFilter = fmt.Sprintf(`logName = "projects/%s/logs/%s" AND +timestamp >= "%s"`, + testProjectID, strings.Replace(testLogID, "/", "%2F", -1), hourAgo.Format(time.RFC3339)) +} + +func TestLogSync(t *testing.T) { + // TODO(deklerk) Un-flake and re-enable + t.Skip("Inherently flaky") + + initLogs() // Generate new testLogID + ctx := context.Background() + lg := client.Logger(testLogID) + err := lg.LogSync(ctx, logging.Entry{Payload: "hello"}) + if err != nil { + t.Fatal(err) + } + err = lg.LogSync(ctx, logging.Entry{Payload: "goodbye"}) + if err != nil { + t.Fatal(err) + } + // Allow overriding the MonitoredResource. + err = lg.LogSync(ctx, logging.Entry{Payload: "mr", Resource: &mrpb.MonitoredResource{Type: "global"}}) + if err != nil { + t.Fatal(err) + } + + want := []*logging.Entry{ + entryForTesting("hello"), + entryForTesting("goodbye"), + entryForTesting("mr"), + } + var got []*logging.Entry + ok := waitFor(func() bool { + got, err = allTestLogEntries(ctx) + if err != nil { + t.Log("fetching log entries: ", err) + return false + } + return len(got) == len(want) + }) + if !ok { + t.Fatalf("timed out; got: %d, want: %d\n", len(got), len(want)) + } + if msg, ok := compareEntries(got, want); !ok { + t.Error(msg) + } +} + +func TestLogAndEntries(t *testing.T) { + // TODO(deklerk) Un-flake and re-enable + t.Skip("Inherently flaky") + + initLogs() // Generate new testLogID + ctx := context.Background() + payloads := []string{"p1", "p2", "p3", "p4", "p5"} + lg := client.Logger(testLogID) + for _, p := range payloads { + // Use the insert ID to guarantee iteration order. + lg.Log(logging.Entry{Payload: p, InsertID: p}) + } + if err := lg.Flush(); err != nil { + t.Fatal(err) + } + var want []*logging.Entry + for _, p := range payloads { + want = append(want, entryForTesting(p)) + } + var got []*logging.Entry + ok := waitFor(func() bool { + var err error + got, err = allTestLogEntries(ctx) + if err != nil { + t.Log("fetching log entries: ", err) + return false + } + return len(got) == len(want) + }) + if !ok { + t.Fatalf("timed out; got: %d, want: %d\n", len(got), len(want)) + } + if msg, ok := compareEntries(got, want); !ok { + t.Error(msg) + } +} + +func TestContextFunc(t *testing.T) { + initLogs() + var contextFuncCalls, cleanupCalls int32 //atomic + + lg := client.Logger(testLogID, logging.ContextFunc(func() (context.Context, func()) { + atomic.AddInt32(&contextFuncCalls, 1) + return context.Background(), func() { atomic.AddInt32(&cleanupCalls, 1) } + })) + lg.Log(logging.Entry{Payload: "p"}) + if err := lg.Flush(); err != nil { + t.Fatal(err) + } + got1 := atomic.LoadInt32(&contextFuncCalls) + got2 := atomic.LoadInt32(&cleanupCalls) + if got1 != 1 || got1 != got2 { + t.Errorf("got %d calls to context func, %d calls to cleanup func; want 1, 1", got1, got2) + } +} + +// compareEntries compares most fields list of Entries against expected. compareEntries does not compare: +// - HTTPRequest +// - Operation +// - Resource +// - SourceLocation +func compareEntries(got, want []*logging.Entry) (string, bool) { + if len(got) != len(want) { + return fmt.Sprintf("got %d entries, want %d", len(got), len(want)), false + } + for i := range got { + if !compareEntry(got[i], want[i]) { + return fmt.Sprintf("#%d:\ngot %+v\nwant %+v", i, got[i], want[i]), false + } + } + return "", true +} + +func compareEntry(got, want *logging.Entry) bool { + if got.Timestamp.Unix() != want.Timestamp.Unix() { + return false + } + + if got.Severity != want.Severity { + return false + } + + if !ltesting.PayloadEqual(got.Payload, want.Payload) { + return false + } + if !testutil.Equal(got.Labels, want.Labels) { + return false + } + + if got.InsertID != want.InsertID { + return false + } + + if got.LogName != want.LogName { + return false + } + + return true +} + +func entryForTesting(payload interface{}) *logging.Entry { + return &logging.Entry{ + Timestamp: testNow().UTC(), + Payload: payload, + LogName: "projects/" + testProjectID + "/logs/" + testLogID, + Resource: &mrpb.MonitoredResource{Type: "global", Labels: map[string]string{"project_id": testProjectID}}, + } +} + +func allTestLogEntries(ctx context.Context) ([]*logging.Entry, error) { + return allEntries(ctx, aclient, testFilter) +} + +func allEntries(ctx context.Context, aclient *logadmin.Client, filter string) ([]*logging.Entry, error) { + var es []*logging.Entry + it := aclient.Entries(ctx, logadmin.Filter(filter)) + for { + e, err := cleanNext(it) + switch err { + case nil: + es = append(es, e) + case iterator.Done: + return es, nil + default: + return nil, err + } + } +} + +func cleanNext(it *logadmin.EntryIterator) (*logging.Entry, error) { + e, err := it.Next() + if err != nil { + return nil, err + } + clean(e) + return e, nil +} + +func TestStandardLogger(t *testing.T) { + // TODO(deklerk) Un-flake and re-enable + t.Skip("Inherently flaky") + + initLogs() // Generate new testLogID + ctx := context.Background() + lg := client.Logger(testLogID) + slg := lg.StandardLogger(logging.Info) + + if slg != lg.StandardLogger(logging.Info) { + t.Error("There should be only one standard logger at each severity.") + } + if slg == lg.StandardLogger(logging.Debug) { + t.Error("There should be a different standard logger for each severity.") + } + + slg.Print("info") + if err := lg.Flush(); err != nil { + t.Fatal(err) + } + var got []*logging.Entry + ok := waitFor(func() bool { + var err error + got, err = allTestLogEntries(ctx) + if err != nil { + t.Log("fetching log entries: ", err) + return false + } + return len(got) == 1 + }) + if !ok { + t.Fatalf("timed out; got: %d, want: %d\n", len(got), 1) + } + if len(got) != 1 { + t.Fatalf("expected non-nil request with one entry; got:\n%+v", got) + } + if got, want := got[0].Payload.(string), "info\n"; got != want { + t.Errorf("payload: got %q, want %q", got, want) + } + if got, want := logging.Severity(got[0].Severity), logging.Info; got != want { + t.Errorf("severity: got %s, want %s", got, want) + } +} + +func TestSeverity(t *testing.T) { + if got, want := logging.Info.String(), "Info"; got != want { + t.Errorf("got %q, want %q", got, want) + } + if got, want := logging.Severity(-99).String(), "-99"; got != want { + t.Errorf("got %q, want %q", got, want) + } +} + +func TestParseSeverity(t *testing.T) { + for _, test := range []struct { + in string + want logging.Severity + }{ + {"", logging.Default}, + {"whatever", logging.Default}, + {"Default", logging.Default}, + {"ERROR", logging.Error}, + {"Error", logging.Error}, + {"error", logging.Error}, + } { + got := logging.ParseSeverity(test.in) + if got != test.want { + t.Errorf("%q: got %s, want %s\n", test.in, got, test.want) + } + } +} + +func TestErrors(t *testing.T) { + initLogs() // Generate new testLogID + // Drain errors already seen. +loop: + for { + select { + case <-errorc: + default: + break loop + } + } + // Try to log something that can't be JSON-marshalled. + lg := client.Logger(testLogID) + lg.Log(logging.Entry{Payload: func() {}}) + // Expect an error from Flush. + err := lg.Flush() + if err == nil { + t.Fatal("expected error, got nil") + } +} + +type badTokenSource struct{} + +func (badTokenSource) Token() (*oauth2.Token, error) { + return &oauth2.Token{}, nil +} + +func TestPing(t *testing.T) { + // Ping twice, in case the service's InsertID logic messes with the error code. + ctx := context.Background() + // The global client should be valid. + if err := client.Ping(ctx); err != nil { + t.Errorf("project %s: got %v, expected nil", testProjectID, err) + } + if err := client.Ping(ctx); err != nil { + t.Errorf("project %s, #2: got %v, expected nil", testProjectID, err) + } + // nonexistent project + c, a := newClients(ctx, testProjectID+"-BAD") + defer c.Close() + defer a.Close() + if err := c.Ping(ctx); err == nil { + t.Errorf("nonexistent project: want error pinging logging api, got nil") + } + if err := c.Ping(ctx); err == nil { + t.Errorf("nonexistent project, #2: want error pinging logging api, got nil") + } + + // Bad creds. We cannot test this with the fake, since it doesn't do auth. + if integrationTest { + c, err := logging.NewClient(ctx, testProjectID, option.WithTokenSource(badTokenSource{})) + if err != nil { + t.Fatal(err) + } + if err := c.Ping(ctx); err == nil { + t.Errorf("bad creds: want error pinging logging api, got nil") + } + if err := c.Ping(ctx); err == nil { + t.Errorf("bad creds, #2: want error pinging logging api, got nil") + } + if err := c.Close(); err != nil { + t.Fatalf("error closing client: %v", err) + } + } +} + +func TestLogsAndDelete(t *testing.T) { + // This function tests both the Logs and DeleteLog methods. We only try to + // delete those logs that we can observe and that were generated by this + // test. This may not include the logs generated from the current test run, + // because the logging service is only eventually consistent. It's + // therefore possible that on some runs, this test will do nothing. + ctx := context.Background() + it := aclient.Logs(ctx) + nDeleted := 0 + for { + logID, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + t.Fatal(err) + } + if strings.HasPrefix(logID, testLogIDPrefix) { + if err := aclient.DeleteLog(ctx, logID); err != nil { + // Ignore NotFound. Sometimes, amazingly, DeleteLog cannot find + // a log that is returned by Logs. + if status.Code(err) != codes.NotFound { + t.Fatalf("deleting %q: %v", logID, err) + } + } else { + nDeleted++ + } + } + } + t.Logf("deleted %d logs", nDeleted) +} + +func TestNonProjectParent(t *testing.T) { + ctx := context.Background() + initLogs() + parent := "organizations/" + ltesting.ValidOrgID + c, a := newClients(ctx, parent) + defer c.Close() + defer a.Close() + lg := c.Logger(testLogID) + err := lg.LogSync(ctx, logging.Entry{Payload: "hello"}) + if integrationTest { + // We don't have permission to log to the organization. + if got, want := status.Code(err), codes.PermissionDenied; got != want { + t.Errorf("got code %s, want %s", got, want) + } + return + } + // Continue test against fake. + if err != nil { + t.Fatal(err) + } + want := []*logging.Entry{{ + Timestamp: testNow().UTC(), + Payload: "hello", + LogName: parent + "/logs/" + testLogID, + Resource: &mrpb.MonitoredResource{ + Type: "organization", + Labels: map[string]string{"organization_id": ltesting.ValidOrgID}, + }, + }} + var got []*logging.Entry + ok := waitFor(func() bool { + got, err = allEntries(ctx, a, fmt.Sprintf(`logName = "%s/logs/%s"`, parent, + strings.Replace(testLogID, "/", "%2F", -1))) + if err != nil { + t.Log("fetching log entries: ", err) + return false + } + return len(got) == len(want) + }) + if !ok { + t.Fatalf("timed out; got: %d, want: %d\n", len(got), len(want)) + } + if msg, ok := compareEntries(got, want); !ok { + t.Error(msg) + } +} + +// waitFor calls f repeatedly with exponential backoff, blocking until it returns true. +// It returns false after a while (if it times out). +func waitFor(f func() bool) bool { + // TODO(shadams): Find a better way to deflake these tests. + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) + defer cancel() + err := cinternal.Retry(ctx, + gax.Backoff{Initial: time.Second, Multiplier: 2, Max: 30 * time.Second}, + func() (bool, error) { return f(), nil }) + return err == nil +} + +// Interleave a lot of Log and Flush calls, to induce race conditions. +// Run this test with: +// go test -run LogFlushRace -race -count 100 +func TestLogFlushRace(t *testing.T) { + initLogs() // Generate new testLogID + lg := client.Logger(testLogID, + logging.ConcurrentWriteLimit(5), // up to 5 concurrent log writes + logging.EntryCountThreshold(100)) // small bundle size to increase interleaving + var wgf, wgl sync.WaitGroup + donec := make(chan struct{}) + for i := 0; i < 10; i++ { + wgl.Add(1) + go func() { + defer wgl.Done() + for j := 0; j < 1e4; j++ { + lg.Log(logging.Entry{Payload: "the payload"}) + } + }() + } + for i := 0; i < 5; i++ { + wgf.Add(1) + go func() { + defer wgf.Done() + for { + select { + case <-donec: + return + case <-time.After(time.Duration(rand.Intn(5)) * time.Millisecond): + if err := lg.Flush(); err != nil { + t.Error(err) + } + } + } + }() + } + wgl.Wait() + close(donec) + wgf.Wait() +} + +// Test the throughput of concurrent writers. +func BenchmarkConcurrentWrites(b *testing.B) { + if !integrationTest { + b.Skip("only makes sense when running against production service") + } + for n := 1; n <= 32; n *= 2 { + b.Run(fmt.Sprint(n), func(b *testing.B) { + b.StopTimer() + lg := client.Logger(testLogID, logging.ConcurrentWriteLimit(n), logging.EntryCountThreshold(1000)) + const ( + nEntries = 1e5 + payload = "the quick brown fox jumps over the lazy dog" + ) + b.SetBytes(int64(nEntries * len(payload))) + b.StartTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < nEntries; j++ { + lg.Log(logging.Entry{Payload: payload}) + } + if err := lg.Flush(); err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/vendor/cloud.google.com/go/logging/logging_unexported_test.go b/vendor/cloud.google.com/go/logging/logging_unexported_test.go new file mode 100644 index 00000000..265e59df --- /dev/null +++ b/vendor/cloud.google.com/go/logging/logging_unexported_test.go @@ -0,0 +1,386 @@ +// Copyright 2016 Google LLC +// +// 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. + +// Tests that require access to unexported names of the logging package. + +package logging + +import ( + "encoding/json" + "net/http" + "net/url" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "github.com/golang/protobuf/proto" + durpb "github.com/golang/protobuf/ptypes/duration" + structpb "github.com/golang/protobuf/ptypes/struct" + "google.golang.org/api/support/bundler" + mrpb "google.golang.org/genproto/googleapis/api/monitoredres" + logtypepb "google.golang.org/genproto/googleapis/logging/type" +) + +func TestLoggerCreation(t *testing.T) { + const logID = "testing" + c := &Client{parent: "projects/PROJECT_ID"} + customResource := &mrpb.MonitoredResource{ + Type: "global", + Labels: map[string]string{ + "project_id": "ANOTHER_PROJECT", + }, + } + defaultBundler := &bundler.Bundler{ + DelayThreshold: DefaultDelayThreshold, + BundleCountThreshold: DefaultEntryCountThreshold, + BundleByteThreshold: DefaultEntryByteThreshold, + BundleByteLimit: 0, + BufferedByteLimit: DefaultBufferedByteLimit, + } + for _, test := range []struct { + options []LoggerOption + wantLogger *Logger + defaultResource bool + wantBundler *bundler.Bundler + }{ + { + options: nil, + wantLogger: &Logger{}, + defaultResource: true, + wantBundler: defaultBundler, + }, + { + options: []LoggerOption{ + CommonResource(nil), + CommonLabels(map[string]string{"a": "1"}), + }, + wantLogger: &Logger{ + commonResource: nil, + commonLabels: map[string]string{"a": "1"}, + }, + wantBundler: defaultBundler, + }, + { + options: []LoggerOption{CommonResource(customResource)}, + wantLogger: &Logger{commonResource: customResource}, + wantBundler: defaultBundler, + }, + { + options: []LoggerOption{ + DelayThreshold(time.Minute), + EntryCountThreshold(99), + EntryByteThreshold(17), + EntryByteLimit(18), + BufferedByteLimit(19), + }, + wantLogger: &Logger{}, + defaultResource: true, + wantBundler: &bundler.Bundler{ + DelayThreshold: time.Minute, + BundleCountThreshold: 99, + BundleByteThreshold: 17, + BundleByteLimit: 18, + BufferedByteLimit: 19, + }, + }, + } { + gotLogger := c.Logger(logID, test.options...) + if got, want := gotLogger.commonResource, test.wantLogger.commonResource; !test.defaultResource && !proto.Equal(got, want) { + t.Errorf("%v: resource: got %v, want %v", test.options, got, want) + } + if got, want := gotLogger.commonLabels, test.wantLogger.commonLabels; !testutil.Equal(got, want) { + t.Errorf("%v: commonLabels: got %v, want %v", test.options, got, want) + } + if got, want := gotLogger.bundler.DelayThreshold, test.wantBundler.DelayThreshold; got != want { + t.Errorf("%v: DelayThreshold: got %v, want %v", test.options, got, want) + } + if got, want := gotLogger.bundler.BundleCountThreshold, test.wantBundler.BundleCountThreshold; got != want { + t.Errorf("%v: BundleCountThreshold: got %v, want %v", test.options, got, want) + } + if got, want := gotLogger.bundler.BundleByteThreshold, test.wantBundler.BundleByteThreshold; got != want { + t.Errorf("%v: BundleByteThreshold: got %v, want %v", test.options, got, want) + } + if got, want := gotLogger.bundler.BundleByteLimit, test.wantBundler.BundleByteLimit; got != want { + t.Errorf("%v: BundleByteLimit: got %v, want %v", test.options, got, want) + } + if got, want := gotLogger.bundler.BufferedByteLimit, test.wantBundler.BufferedByteLimit; got != want { + t.Errorf("%v: BufferedByteLimit: got %v, want %v", test.options, got, want) + } + } +} + +func TestToProtoStruct(t *testing.T) { + v := struct { + Foo string `json:"foo"` + Bar int `json:"bar,omitempty"` + Baz []float64 `json:"baz"` + Moo map[string]interface{} `json:"moo"` + }{ + Foo: "foovalue", + Baz: []float64{1.1}, + Moo: map[string]interface{}{ + "a": 1, + "b": "two", + "c": true, + }, + } + + got, err := toProtoStruct(v) + if err != nil { + t.Fatal(err) + } + want := &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "foo": {Kind: &structpb.Value_StringValue{StringValue: v.Foo}}, + "baz": {Kind: &structpb.Value_ListValue{ListValue: &structpb.ListValue{Values: []*structpb.Value{ + {Kind: &structpb.Value_NumberValue{NumberValue: 1.1}}, + }}}}, + "moo": {Kind: &structpb.Value_StructValue{ + StructValue: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "a": {Kind: &structpb.Value_NumberValue{NumberValue: 1}}, + "b": {Kind: &structpb.Value_StringValue{StringValue: "two"}}, + "c": {Kind: &structpb.Value_BoolValue{BoolValue: true}}, + }, + }, + }}, + }, + } + if !proto.Equal(got, want) { + t.Errorf("got %+v\nwant %+v", got, want) + } + + // Non-structs should fail to convert. + for v := range []interface{}{3, "foo", []int{1, 2, 3}} { + _, err := toProtoStruct(v) + if err == nil { + t.Errorf("%v: got nil, want error", v) + } + } + + // Test fast path. + got, err = toProtoStruct(want) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Error("got and want should be identical, but are not") + } +} + +func TestToLogEntryPayload(t *testing.T) { + var logger Logger + for _, test := range []struct { + in interface{} + wantText string + wantStruct *structpb.Struct + }{ + { + in: "string", + wantText: "string", + }, + { + in: map[string]interface{}{"a": 1, "b": true}, + wantStruct: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "a": {Kind: &structpb.Value_NumberValue{NumberValue: 1}}, + "b": {Kind: &structpb.Value_BoolValue{BoolValue: true}}, + }, + }, + }, + { + in: json.RawMessage([]byte(`{"a": 1, "b": true}`)), + wantStruct: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "a": {Kind: &structpb.Value_NumberValue{NumberValue: 1}}, + "b": {Kind: &structpb.Value_BoolValue{BoolValue: true}}, + }, + }, + }, + } { + e, err := logger.toLogEntry(Entry{Payload: test.in}) + if err != nil { + t.Fatalf("%+v: %v", test.in, err) + } + if test.wantStruct != nil { + got := e.GetJsonPayload() + if !proto.Equal(got, test.wantStruct) { + t.Errorf("%+v: got %s, want %s", test.in, got, test.wantStruct) + } + } else { + got := e.GetTextPayload() + if got != test.wantText { + t.Errorf("%+v: got %s, want %s", test.in, got, test.wantText) + } + } + } +} + +func TestToLogEntryTrace(t *testing.T) { + logger := &Logger{client: &Client{parent: "projects/P"}} + // Verify that we get the trace from the HTTP request if it isn't + // provided by the caller. + u := &url.URL{Scheme: "http"} + for _, test := range []struct { + in Entry + want string + }{ + {Entry{}, ""}, + {Entry{Trace: "t1"}, "t1"}, + { + Entry{ + HTTPRequest: &HTTPRequest{ + Request: &http.Request{URL: u, Header: http.Header{"foo": {"bar"}}}, + }, + }, + "", + }, + { + Entry{ + HTTPRequest: &HTTPRequest{ + Request: &http.Request{ + URL: u, + Header: http.Header{"X-Cloud-Trace-Context": {"t2"}}, + }, + }, + }, + "projects/P/traces/t2", + }, + { + Entry{ + HTTPRequest: &HTTPRequest{ + Request: &http.Request{ + URL: u, + Header: http.Header{"X-Cloud-Trace-Context": {"t3"}}, + }, + }, + Trace: "t4", + }, + "t4", + }, + } { + e, err := logger.toLogEntry(test.in) + if err != nil { + t.Fatalf("%+v: %v", test.in, err) + } + if got := e.Trace; got != test.want { + t.Errorf("%+v: got %q, want %q", test.in, got, test.want) + } + } +} + +func TestFromHTTPRequest(t *testing.T) { + const testURL = "http:://example.com/path?q=1" + u, err := url.Parse(testURL) + if err != nil { + t.Fatal(err) + } + req := &HTTPRequest{ + Request: &http.Request{ + Method: "GET", + URL: u, + Header: map[string][]string{ + "User-Agent": {"user-agent"}, + "Referer": {"referer"}, + }, + }, + RequestSize: 100, + Status: 200, + ResponseSize: 25, + Latency: 100 * time.Second, + LocalIP: "127.0.0.1", + RemoteIP: "10.0.1.1", + CacheHit: true, + CacheValidatedWithOriginServer: true, + } + got := fromHTTPRequest(req) + want := &logtypepb.HttpRequest{ + RequestMethod: "GET", + RequestUrl: testURL, + RequestSize: 100, + Status: 200, + ResponseSize: 25, + Latency: &durpb.Duration{Seconds: 100}, + UserAgent: "user-agent", + ServerIp: "127.0.0.1", + RemoteIp: "10.0.1.1", + Referer: "referer", + CacheHit: true, + CacheValidatedWithOriginServer: true, + } + if !proto.Equal(got, want) { + t.Errorf("got %+v\nwant %+v", got, want) + } +} + +func TestMonitoredResource(t *testing.T) { + for _, test := range []struct { + parent string + want *mrpb.MonitoredResource + }{ + { + "projects/P", + &mrpb.MonitoredResource{ + Type: "project", + Labels: map[string]string{"project_id": "P"}, + }, + }, + + { + "folders/F", + &mrpb.MonitoredResource{ + Type: "folder", + Labels: map[string]string{"folder_id": "F"}, + }, + }, + { + "billingAccounts/B", + &mrpb.MonitoredResource{ + Type: "billing_account", + Labels: map[string]string{"account_id": "B"}, + }, + }, + { + "organizations/123", + &mrpb.MonitoredResource{ + Type: "organization", + Labels: map[string]string{"organization_id": "123"}, + }, + }, + { + "unknown/X", + &mrpb.MonitoredResource{ + Type: "global", + Labels: map[string]string{"project_id": "X"}, + }, + }, + { + "whatever", + &mrpb.MonitoredResource{ + Type: "global", + Labels: map[string]string{"project_id": "whatever"}, + }, + }, + } { + got := monitoredResource(test.parent) + if !testutil.Equal(got, test.want) { + t.Errorf("%q: got %+v, want %+v", test.parent, got, test.want) + } + } +} + +// Used by the tests in logging_test. +func SetNow(f func() time.Time) { + now = f +} diff --git a/vendor/cloud.google.com/go/longrunning/autogen/doc.go b/vendor/cloud.google.com/go/longrunning/autogen/doc.go new file mode 100644 index 00000000..c5849a9c --- /dev/null +++ b/vendor/cloud.google.com/go/longrunning/autogen/doc.go @@ -0,0 +1,88 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package longrunning is an auto-generated package for the +// Google Long Running Operations API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// +// Use the client at cloud.google.com/go/longrunning in preference to this. +package longrunning // import "cloud.google.com/go/longrunning/autogen" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{} +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/longrunning/autogen/from_conn.go b/vendor/cloud.google.com/go/longrunning/autogen/from_conn.go new file mode 100644 index 00000000..9082b0a4 --- /dev/null +++ b/vendor/cloud.google.com/go/longrunning/autogen/from_conn.go @@ -0,0 +1,34 @@ +// Copyright 2017, Google LLC +// +// 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 longrunning + +import ( + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" +) + +// InternalFromConn is for use by the google Cloud Libraries only. +// +// InternalFromConn creates OperationsClient from available connection. +func InternalFromConn(conn *grpc.ClientConn) *OperationsClient { + c := &OperationsClient{ + conn: conn, + CallOptions: defaultOperationsCallOptions(), + + operationsClient: longrunningpb.NewOperationsClient(conn), + } + c.SetGoogleClientInfo() + return c +} diff --git a/vendor/cloud.google.com/go/longrunning/autogen/mock_test.go b/vendor/cloud.google.com/go/longrunning/autogen/mock_test.go new file mode 100644 index 00000000..705048ab --- /dev/null +++ b/vendor/cloud.google.com/go/longrunning/autogen/mock_test.go @@ -0,0 +1,381 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package longrunning + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockOperationsServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + longrunningpb.OperationsServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockOperationsServer) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest) (*longrunningpb.ListOperationsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.ListOperationsResponse), nil +} + +func (s *mockOperationsServer) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockOperationsServer) DeleteOperation(ctx context.Context, req *longrunningpb.DeleteOperationRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockOperationsServer) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockOperations mockOperationsServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + longrunningpb.RegisterOperationsServer(serv, &mockOperations) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestOperationsGetOperation(t *testing.T) { + var name2 string = "name2-1052831874" + var done bool = true + var expectedResponse = &longrunningpb.Operation{ + Name: name2, + Done: done, + } + + mockOperations.err = nil + mockOperations.reqs = nil + + mockOperations.resps = append(mockOperations.resps[:0], expectedResponse) + + var name string = "name3373707" + var request = &longrunningpb.GetOperationRequest{ + Name: name, + } + + c, err := NewOperationsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetOperation(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOperations.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestOperationsGetOperationError(t *testing.T) { + errCode := codes.PermissionDenied + mockOperations.err = gstatus.Error(errCode, "test error") + + var name string = "name3373707" + var request = &longrunningpb.GetOperationRequest{ + Name: name, + } + + c, err := NewOperationsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetOperation(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestOperationsListOperations(t *testing.T) { + var nextPageToken string = "" + var operationsElement *longrunningpb.Operation = &longrunningpb.Operation{} + var operations = []*longrunningpb.Operation{operationsElement} + var expectedResponse = &longrunningpb.ListOperationsResponse{ + NextPageToken: nextPageToken, + Operations: operations, + } + + mockOperations.err = nil + mockOperations.reqs = nil + + mockOperations.resps = append(mockOperations.resps[:0], expectedResponse) + + var name string = "name3373707" + var filter string = "filter-1274492040" + var request = &longrunningpb.ListOperationsRequest{ + Name: name, + Filter: filter, + } + + c, err := NewOperationsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListOperations(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOperations.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Operations[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestOperationsListOperationsError(t *testing.T) { + errCode := codes.PermissionDenied + mockOperations.err = gstatus.Error(errCode, "test error") + + var name string = "name3373707" + var filter string = "filter-1274492040" + var request = &longrunningpb.ListOperationsRequest{ + Name: name, + Filter: filter, + } + + c, err := NewOperationsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListOperations(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestOperationsCancelOperation(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockOperations.err = nil + mockOperations.reqs = nil + + mockOperations.resps = append(mockOperations.resps[:0], expectedResponse) + + var name string = "name3373707" + var request = &longrunningpb.CancelOperationRequest{ + Name: name, + } + + c, err := NewOperationsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.CancelOperation(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOperations.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestOperationsCancelOperationError(t *testing.T) { + errCode := codes.PermissionDenied + mockOperations.err = gstatus.Error(errCode, "test error") + + var name string = "name3373707" + var request = &longrunningpb.CancelOperationRequest{ + Name: name, + } + + c, err := NewOperationsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.CancelOperation(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestOperationsDeleteOperation(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockOperations.err = nil + mockOperations.reqs = nil + + mockOperations.resps = append(mockOperations.resps[:0], expectedResponse) + + var name string = "name3373707" + var request = &longrunningpb.DeleteOperationRequest{ + Name: name, + } + + c, err := NewOperationsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteOperation(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOperations.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestOperationsDeleteOperationError(t *testing.T) { + errCode := codes.PermissionDenied + mockOperations.err = gstatus.Error(errCode, "test error") + + var name string = "name3373707" + var request = &longrunningpb.DeleteOperationRequest{ + Name: name, + } + + c, err := NewOperationsClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteOperation(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} diff --git a/vendor/cloud.google.com/go/longrunning/autogen/operations_client.go b/vendor/cloud.google.com/go/longrunning/autogen/operations_client.go new file mode 100644 index 00000000..ebdf6f9f --- /dev/null +++ b/vendor/cloud.google.com/go/longrunning/autogen/operations_client.go @@ -0,0 +1,271 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package longrunning + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// OperationsCallOptions contains the retry settings for each method of OperationsClient. +type OperationsCallOptions struct { + GetOperation []gax.CallOption + ListOperations []gax.CallOption + CancelOperation []gax.CallOption + DeleteOperation []gax.CallOption +} + +func defaultOperationsClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("longrunning.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultOperationsCallOptions() *OperationsCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &OperationsCallOptions{ + GetOperation: retry[[2]string{"default", "idempotent"}], + ListOperations: retry[[2]string{"default", "idempotent"}], + CancelOperation: retry[[2]string{"default", "idempotent"}], + DeleteOperation: retry[[2]string{"default", "idempotent"}], + } +} + +// OperationsClient is a client for interacting with Google Long Running Operations API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type OperationsClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + operationsClient longrunningpb.OperationsClient + + // The call options for this service. + CallOptions *OperationsCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewOperationsClient creates a new operations client. +// +// Manages long-running operations with an API service. +// +// When an API method normally takes long time to complete, it can be designed +// to return [Operation][google.longrunning.Operation] to the client, and the client can use this +// interface to receive the real response asynchronously by polling the +// operation resource, or pass the operation resource to another API (such as +// Google Cloud Pub/Sub API) to receive the response. Any API service that +// returns long-running operations should implement the Operations interface +// so developers can have a consistent client experience. +func NewOperationsClient(ctx context.Context, opts ...option.ClientOption) (*OperationsClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultOperationsClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &OperationsClient{ + conn: conn, + CallOptions: defaultOperationsCallOptions(), + + operationsClient: longrunningpb.NewOperationsClient(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *OperationsClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *OperationsClient) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *OperationsClient) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// GetOperation gets the latest state of a long-running operation. Clients can use this +// method to poll the operation result at intervals as recommended by the API +// service. +func (c *OperationsClient) GetOperation(ctx context.Context, req *longrunningpb.GetOperationRequest, opts ...gax.CallOption) (*longrunningpb.Operation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetOperation[0:len(c.CallOptions.GetOperation):len(c.CallOptions.GetOperation)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.operationsClient.GetOperation(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListOperations lists operations that match the specified filter in the request. If the +// server doesn't support this method, it returns UNIMPLEMENTED. +// +// NOTE: the name binding below allows API services to override the binding +// to use different resource name schemes, such as users/*/operations. +func (c *OperationsClient) ListOperations(ctx context.Context, req *longrunningpb.ListOperationsRequest, opts ...gax.CallOption) *OperationIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListOperations[0:len(c.CallOptions.ListOperations):len(c.CallOptions.ListOperations)], opts...) + it := &OperationIterator{} + req = proto.Clone(req).(*longrunningpb.ListOperationsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*longrunningpb.Operation, string, error) { + var resp *longrunningpb.ListOperationsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.operationsClient.ListOperations(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Operations, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// CancelOperation starts asynchronous cancellation on a long-running operation. The server +// makes a best effort to cancel the operation, but success is not +// guaranteed. If the server doesn't support this method, it returns +// google.rpc.Code.UNIMPLEMENTED. Clients can use +// [Operations.GetOperation][google.longrunning.Operations.GetOperation] or +// other methods to check whether the cancellation succeeded or whether the +// operation completed despite cancellation. On successful cancellation, +// the operation is not deleted; instead, it becomes an operation with +// an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, +// corresponding to Code.CANCELLED. +func (c *OperationsClient) CancelOperation(ctx context.Context, req *longrunningpb.CancelOperationRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CancelOperation[0:len(c.CallOptions.CancelOperation):len(c.CallOptions.CancelOperation)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.operationsClient.CancelOperation(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// DeleteOperation deletes a long-running operation. This method indicates that the client is +// no longer interested in the operation result. It does not cancel the +// operation. If the server doesn't support this method, it returns +// google.rpc.Code.UNIMPLEMENTED. +func (c *OperationsClient) DeleteOperation(ctx context.Context, req *longrunningpb.DeleteOperationRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteOperation[0:len(c.CallOptions.DeleteOperation):len(c.CallOptions.DeleteOperation)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.operationsClient.DeleteOperation(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// OperationIterator manages a stream of *longrunningpb.Operation. +type OperationIterator struct { + items []*longrunningpb.Operation + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*longrunningpb.Operation, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *OperationIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *OperationIterator) Next() (*longrunningpb.Operation, error) { + var item *longrunningpb.Operation + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *OperationIterator) bufLen() int { + return len(it.items) +} + +func (it *OperationIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/longrunning/autogen/operations_client_example_test.go b/vendor/cloud.google.com/go/longrunning/autogen/operations_client_example_test.go new file mode 100644 index 00000000..a080e557 --- /dev/null +++ b/vendor/cloud.google.com/go/longrunning/autogen/operations_client_example_test.go @@ -0,0 +1,109 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package longrunning_test + +import ( + "context" + + longrunning "cloud.google.com/go/longrunning/autogen" + "google.golang.org/api/iterator" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" +) + +func ExampleNewOperationsClient() { + ctx := context.Background() + c, err := longrunning.NewOperationsClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleOperationsClient_GetOperation() { + ctx := context.Background() + c, err := longrunning.NewOperationsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &longrunningpb.GetOperationRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetOperation(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleOperationsClient_ListOperations() { + ctx := context.Background() + c, err := longrunning.NewOperationsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &longrunningpb.ListOperationsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListOperations(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleOperationsClient_CancelOperation() { + ctx := context.Background() + c, err := longrunning.NewOperationsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &longrunningpb.CancelOperationRequest{ + // TODO: Fill request struct fields. + } + err = c.CancelOperation(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleOperationsClient_DeleteOperation() { + ctx := context.Background() + c, err := longrunning.NewOperationsClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &longrunningpb.DeleteOperationRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteOperation(ctx, req) + if err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/longrunning/example_test.go b/vendor/cloud.google.com/go/longrunning/example_test.go new file mode 100644 index 00000000..c88c2e8c --- /dev/null +++ b/vendor/cloud.google.com/go/longrunning/example_test.go @@ -0,0 +1,116 @@ +// Copyright 2016 Google LLC +// +// 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 longrunning + +import ( + "context" + "fmt" + "time" + + "github.com/golang/protobuf/ptypes" + "github.com/golang/protobuf/ptypes/duration" + "github.com/golang/protobuf/ptypes/timestamp" + pb "google.golang.org/genproto/googleapis/longrunning" +) + +func bestMomentInHistory() (*Operation, error) { + t, err := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", "2009-11-10 23:00:00 +0000 UTC") + if err != nil { + return nil, err + } + resp, err := ptypes.TimestampProto(t) + if err != nil { + return nil, err + } + respAny, err := ptypes.MarshalAny(resp) + if err != nil { + return nil, err + } + metaAny, err := ptypes.MarshalAny(ptypes.DurationProto(1 * time.Hour)) + return &Operation{ + proto: &pb.Operation{ + Name: "best-moment", + Done: true, + Metadata: metaAny, + Result: &pb.Operation_Response{ + Response: respAny, + }, + }, + }, err +} + +func ExampleOperation_Wait() { + // Complex computation, might take a long time. + op, err := bestMomentInHistory() + if err != nil { + // TODO: Handle err. + } + var ts timestamp.Timestamp + err = op.Wait(context.TODO(), &ts) + if err != nil && !op.Done() { + fmt.Println("failed to fetch operation status", err) + } else if err != nil && op.Done() { + fmt.Println("operation completed with error", err) + } else { + fmt.Println(ptypes.TimestampString(&ts)) + } + // Output: + // 2009-11-10T23:00:00Z +} + +func ExampleOperation_Metadata() { + op, err := bestMomentInHistory() + if err != nil { + // TODO: Handle err. + } + + // The operation might contain metadata. + // In this example, the metadata contains the estimated length of time + // the operation might take to complete. + var meta duration.Duration + if err := op.Metadata(&meta); err != nil { + // TODO: Handle err. + } + d, err := ptypes.Duration(&meta) + if err == ErrNoMetadata { + fmt.Println("no metadata") + } else if err != nil { + // TODO: Handle err. + } else { + fmt.Println(d) + } + // Output: + // 1h0m0s +} + +func ExampleOperation_Cancel() { + op, err := bestMomentInHistory() + if err != nil { + // TODO: Handle err. + } + if err := op.Cancel(context.Background()); err != nil { + // TODO: Handle err. + } +} + +func ExampleOperation_Delete() { + op, err := bestMomentInHistory() + if err != nil { + // TODO: Handle err. + } + if err := op.Delete(context.Background()); err != nil { + // TODO: Handle err. + } +} diff --git a/vendor/cloud.google.com/go/longrunning/longrunning.go b/vendor/cloud.google.com/go/longrunning/longrunning.go new file mode 100644 index 00000000..639482af --- /dev/null +++ b/vendor/cloud.google.com/go/longrunning/longrunning.go @@ -0,0 +1,179 @@ +// Copyright 2016 Google LLC +// +// 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 longrunning supports Long Running Operations for the Google Cloud Libraries. +// See google.golang.org/genproto/googleapis/longrunning for its service definition. +// +// Users of the Google Cloud Libraries will typically not use this package directly. +// Instead they will call functions returning Operations and call their methods. +// +// This package is still experimental and subject to change. +package longrunning // import "cloud.google.com/go/longrunning" + +import ( + "context" + "errors" + "fmt" + "time" + + autogen "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + gax "github.com/googleapis/gax-go" + pb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// ErrNoMetadata is the error returned by Metadata if the operation contains no metadata. +var ErrNoMetadata = errors.New("operation contains no metadata") + +// Operation represents the result of an API call that may not be ready yet. +type Operation struct { + c operationsClient + proto *pb.Operation +} + +type operationsClient interface { + GetOperation(context.Context, *pb.GetOperationRequest, ...gax.CallOption) (*pb.Operation, error) + CancelOperation(context.Context, *pb.CancelOperationRequest, ...gax.CallOption) error + DeleteOperation(context.Context, *pb.DeleteOperationRequest, ...gax.CallOption) error +} + +// InternalNewOperation is for use by the google Cloud Libraries only. +// +// InternalNewOperation returns an long-running operation, abstracting the raw pb.Operation. +// The conn parameter refers to a server that proto was received from. +func InternalNewOperation(inner *autogen.OperationsClient, proto *pb.Operation) *Operation { + return &Operation{ + c: inner, + proto: proto, + } +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service +// from which the operation is created. +func (op *Operation) Name() string { + return op.proto.Name +} + +// Done reports whether the long-running operation has completed. +func (op *Operation) Done() bool { + return op.proto.Done +} + +// Metadata unmarshals op's metadata into meta. +// If op does not contain any metadata, Metadata returns ErrNoMetadata and meta is unmodified. +func (op *Operation) Metadata(meta proto.Message) error { + if m := op.proto.Metadata; m != nil { + return ptypes.UnmarshalAny(m, meta) + } + return ErrNoMetadata +} + +// Poll fetches the latest state of a long-running operation. +// +// If Poll fails, the error is returned and op is unmodified. +// If Poll succeeds and the operation has completed with failure, +// the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true; if resp != nil, the response of the operation +// is stored in resp. +func (op *Operation) Poll(ctx context.Context, resp proto.Message, opts ...gax.CallOption) error { + if !op.Done() { + p, err := op.c.GetOperation(ctx, &pb.GetOperationRequest{Name: op.Name()}, opts...) + if err != nil { + return err + } + op.proto = p + } + if !op.Done() { + return nil + } + + switch r := op.proto.Result.(type) { + case *pb.Operation_Error: + // TODO (pongad): r.Details may contain further information + return status.Errorf(codes.Code(r.Error.Code), "%s", r.Error.Message) + case *pb.Operation_Response: + if resp == nil { + return nil + } + return ptypes.UnmarshalAny(r.Response, resp) + default: + return fmt.Errorf("unsupported result type %[1]T: %[1]v", r) + } +} + +// DefaultWaitInterval is the polling interval used by Operation.Wait. +const DefaultWaitInterval = 60 * time.Second + +// Wait is equivalent to WaitWithInterval using DefaultWaitInterval. +func (op *Operation) Wait(ctx context.Context, resp proto.Message, opts ...gax.CallOption) error { + return op.WaitWithInterval(ctx, resp, DefaultWaitInterval, opts...) +} + +// WaitWithInterval blocks until the operation is completed. +// If resp != nil, Wait stores the response in resp. +// WaitWithInterval polls every interval, except initially +// when it polls using exponential backoff. +// +// See documentation of Poll for error-handling information. +func (op *Operation) WaitWithInterval(ctx context.Context, resp proto.Message, interval time.Duration, opts ...gax.CallOption) error { + bo := gax.Backoff{ + Initial: 1 * time.Second, + Max: interval, + } + if bo.Max < bo.Initial { + bo.Max = bo.Initial + } + return op.wait(ctx, resp, &bo, gax.Sleep, opts...) +} + +type sleeper func(context.Context, time.Duration) error + +// wait implements Wait, taking exponentialBackoff and sleeper arguments for testing. +func (op *Operation) wait(ctx context.Context, resp proto.Message, bo *gax.Backoff, sl sleeper, opts ...gax.CallOption) error { + for { + if err := op.Poll(ctx, resp, opts...); err != nil { + return err + } + if op.Done() { + return nil + } + if err := sl(ctx, bo.Pause()); err != nil { + return err + } + } +} + +// Cancel starts asynchronous cancellation on a long-running operation. The server +// makes a best effort to cancel the operation, but success is not +// guaranteed. If the server doesn't support this method, it returns +// grpc.Code(error) == codes.Unimplemented. Clients can use +// Poll or other methods to check whether the cancellation succeeded or whether the +// operation completed despite cancellation. On successful cancellation, +// the operation is not deleted; instead, op.Poll returns an error +// with code Canceled. +func (op *Operation) Cancel(ctx context.Context, opts ...gax.CallOption) error { + return op.c.CancelOperation(ctx, &pb.CancelOperationRequest{Name: op.Name()}, opts...) +} + +// Delete deletes a long-running operation. This method indicates that the client is +// no longer interested in the operation result. It does not cancel the +// operation. If the server doesn't support this method, grpc.Code(error) == codes.Unimplemented. +func (op *Operation) Delete(ctx context.Context, opts ...gax.CallOption) error { + return op.c.DeleteOperation(ctx, &pb.DeleteOperationRequest{Name: op.Name()}, opts...) +} diff --git a/vendor/cloud.google.com/go/longrunning/longrunning_test.go b/vendor/cloud.google.com/go/longrunning/longrunning_test.go new file mode 100644 index 00000000..7c07dd5c --- /dev/null +++ b/vendor/cloud.google.com/go/longrunning/longrunning_test.go @@ -0,0 +1,213 @@ +// Copyright 2016 Google LLC +// +// 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 lro supports Long Running Operations for the Google Cloud Libraries. +// +// This package is still experimental and subject to change. +package longrunning + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "github.com/golang/protobuf/ptypes/duration" + gax "github.com/googleapis/gax-go" + pb "google.golang.org/genproto/googleapis/longrunning" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" +) + +type getterService struct { + operationsClient + + // clock represents the fake current time of the service. + // It is the running sum of the of the duration we have slept. + clock time.Duration + + // getTimes records the times at which GetOperation is called. + getTimes []time.Duration + + // results are the fake results that GetOperation should return. + results []*pb.Operation +} + +func (s *getterService) GetOperation(context.Context, *pb.GetOperationRequest, ...gax.CallOption) (*pb.Operation, error) { + i := len(s.getTimes) + s.getTimes = append(s.getTimes, s.clock) + if i >= len(s.results) { + return nil, errors.New("unexpected call") + } + return s.results[i], nil +} + +func (s *getterService) sleeper() sleeper { + return func(_ context.Context, d time.Duration) error { + s.clock += d + return nil + } +} + +func TestWait(t *testing.T) { + responseDur := ptypes.DurationProto(42 * time.Second) + responseAny, err := ptypes.MarshalAny(responseDur) + if err != nil { + t.Fatal(err) + } + + s := &getterService{ + results: []*pb.Operation{ + {Name: "foo"}, + {Name: "foo"}, + {Name: "foo"}, + {Name: "foo"}, + {Name: "foo"}, + { + Name: "foo", + Done: true, + Result: &pb.Operation_Response{ + Response: responseAny, + }, + }, + }, + } + op := &Operation{ + c: s, + proto: &pb.Operation{Name: "foo"}, + } + if op.Done() { + t.Fatal("operation should not have completed yet") + } + + var resp duration.Duration + bo := gax.Backoff{ + Initial: 1 * time.Second, + Max: 3 * time.Second, + } + if err := op.wait(context.Background(), &resp, &bo, s.sleeper()); err != nil { + t.Fatal(err) + } + if !proto.Equal(&resp, responseDur) { + t.Errorf("response, got %v, want %v", resp, responseDur) + } + if !op.Done() { + t.Errorf("operation should have completed") + } + + maxWait := []time.Duration{ + 1 * time.Second, + 2 * time.Second, + 3 * time.Second, + 3 * time.Second, + 3 * time.Second, + } + for i := 0; i < len(s.getTimes)-1; i++ { + w := s.getTimes[i+1] - s.getTimes[i] + if mw := maxWait[i]; w > mw { + t.Errorf("backoff, waited %s, max %s", w, mw) + } + } +} + +func TestPollRequestError(t *testing.T) { + const opName = "foo" + + // All calls error. + s := &getterService{} + op := &Operation{ + c: s, + proto: &pb.Operation{Name: opName}, + } + if err := op.Poll(context.Background(), nil); err == nil { + t.Fatalf("Poll should error") + } + if n := op.Name(); n != opName { + t.Errorf("operation name, got %q, want %q", n, opName) + } + if op.Done() { + t.Errorf("operation should not have completed; we failed to fetch state") + } +} + +func TestPollErrorResult(t *testing.T) { + const ( + errCode = codes.NotFound + errMsg = "my error" + ) + op := &Operation{ + proto: &pb.Operation{ + Name: "foo", + Done: true, + Result: &pb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: errMsg, + }, + }, + }, + } + err := op.Poll(context.Background(), nil) + if got := grpc.Code(err); got != errCode { + t.Errorf("error code, want %s, got %s", errCode, got) + } + if got := grpc.ErrorDesc(err); got != errMsg { + t.Errorf("error code, want %s, got %s", errMsg, got) + } + if !op.Done() { + t.Errorf("operation should have completed") + } +} + +type errService struct { + operationsClient + errCancel, errDelete error +} + +func (s *errService) CancelOperation(context.Context, *pb.CancelOperationRequest, ...gax.CallOption) error { + return s.errCancel +} + +func (s *errService) DeleteOperation(context.Context, *pb.DeleteOperationRequest, ...gax.CallOption) error { + return s.errDelete +} + +func TestCancelReturnsError(t *testing.T) { + s := &errService{ + errCancel: errors.New("cancel error"), + } + op := &Operation{ + c: s, + proto: &pb.Operation{Name: "foo"}, + } + if got, want := op.Cancel(context.Background()), s.errCancel; got != want { + t.Errorf("cancel, got error %s, want %s", got, want) + } +} + +func TestDeleteReturnsError(t *testing.T) { + s := &errService{ + errDelete: errors.New("delete error"), + } + op := &Operation{ + c: s, + proto: &pb.Operation{Name: "foo"}, + } + if got, want := op.Delete(context.Background()), s.errDelete; got != want { + t.Errorf("cancel, got error %s, want %s", got, want) + } +} diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/ListMonitoredResourceDescriptors_smoke_test.go b/vendor/cloud.google.com/go/monitoring/apiv3/ListMonitoredResourceDescriptors_smoke_test.go new file mode 100644 index 00000000..7a8e1b4d --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/ListMonitoredResourceDescriptors_smoke_test.go @@ -0,0 +1,67 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package monitoring + +import ( + monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestMetricServiceSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewMetricClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var formattedName string = fmt.Sprintf("projects/%s", projectId) + var request = &monitoringpb.ListMonitoredResourceDescriptorsRequest{ + Name: formattedName, + } + + iter := c.ListMonitoredResourceDescriptors(ctx, request) + if _, err := iter.Next(); err != nil && err != iterator.Done { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/alert_policy_client.go b/vendor/cloud.google.com/go/monitoring/apiv3/alert_policy_client.go new file mode 100644 index 00000000..e3338793 --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/alert_policy_client.go @@ -0,0 +1,278 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package monitoring + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// AlertPolicyCallOptions contains the retry settings for each method of AlertPolicyClient. +type AlertPolicyCallOptions struct { + ListAlertPolicies []gax.CallOption + GetAlertPolicy []gax.CallOption + CreateAlertPolicy []gax.CallOption + DeleteAlertPolicy []gax.CallOption + UpdateAlertPolicy []gax.CallOption +} + +func defaultAlertPolicyClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("monitoring.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultAlertPolicyCallOptions() *AlertPolicyCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &AlertPolicyCallOptions{ + ListAlertPolicies: retry[[2]string{"default", "idempotent"}], + GetAlertPolicy: retry[[2]string{"default", "idempotent"}], + CreateAlertPolicy: retry[[2]string{"default", "non_idempotent"}], + DeleteAlertPolicy: retry[[2]string{"default", "idempotent"}], + UpdateAlertPolicy: retry[[2]string{"default", "non_idempotent"}], + } +} + +// AlertPolicyClient is a client for interacting with Stackdriver Monitoring API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type AlertPolicyClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + alertPolicyClient monitoringpb.AlertPolicyServiceClient + + // The call options for this service. + CallOptions *AlertPolicyCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewAlertPolicyClient creates a new alert policy service client. +// +// The AlertPolicyService API is used to manage (list, create, delete, +// edit) alert policies in Stackdriver Monitoring. An alerting policy is +// a description of the conditions under which some aspect of your +// system is considered to be "unhealthy" and the ways to notify +// people or services about this state. In addition to using this API, alert +// policies can also be managed through +// Stackdriver Monitoring (at https://cloud.google.com/monitoring/docs/), +// which can be reached by clicking the "Monitoring" tab in +// Cloud Console (at https://console.cloud.google.com/). +func NewAlertPolicyClient(ctx context.Context, opts ...option.ClientOption) (*AlertPolicyClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultAlertPolicyClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &AlertPolicyClient{ + conn: conn, + CallOptions: defaultAlertPolicyCallOptions(), + + alertPolicyClient: monitoringpb.NewAlertPolicyServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *AlertPolicyClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *AlertPolicyClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *AlertPolicyClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListAlertPolicies lists the existing alerting policies for the project. +func (c *AlertPolicyClient) ListAlertPolicies(ctx context.Context, req *monitoringpb.ListAlertPoliciesRequest, opts ...gax.CallOption) *AlertPolicyIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListAlertPolicies[0:len(c.CallOptions.ListAlertPolicies):len(c.CallOptions.ListAlertPolicies)], opts...) + it := &AlertPolicyIterator{} + req = proto.Clone(req).(*monitoringpb.ListAlertPoliciesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.AlertPolicy, string, error) { + var resp *monitoringpb.ListAlertPoliciesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.alertPolicyClient.ListAlertPolicies(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.AlertPolicies, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetAlertPolicy gets a single alerting policy. +func (c *AlertPolicyClient) GetAlertPolicy(ctx context.Context, req *monitoringpb.GetAlertPolicyRequest, opts ...gax.CallOption) (*monitoringpb.AlertPolicy, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetAlertPolicy[0:len(c.CallOptions.GetAlertPolicy):len(c.CallOptions.GetAlertPolicy)], opts...) + var resp *monitoringpb.AlertPolicy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.alertPolicyClient.GetAlertPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateAlertPolicy creates a new alerting policy. +func (c *AlertPolicyClient) CreateAlertPolicy(ctx context.Context, req *monitoringpb.CreateAlertPolicyRequest, opts ...gax.CallOption) (*monitoringpb.AlertPolicy, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateAlertPolicy[0:len(c.CallOptions.CreateAlertPolicy):len(c.CallOptions.CreateAlertPolicy)], opts...) + var resp *monitoringpb.AlertPolicy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.alertPolicyClient.CreateAlertPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteAlertPolicy deletes an alerting policy. +func (c *AlertPolicyClient) DeleteAlertPolicy(ctx context.Context, req *monitoringpb.DeleteAlertPolicyRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteAlertPolicy[0:len(c.CallOptions.DeleteAlertPolicy):len(c.CallOptions.DeleteAlertPolicy)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.alertPolicyClient.DeleteAlertPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// UpdateAlertPolicy updates an alerting policy. You can either replace the entire policy with +// a new one or replace only certain fields in the current alerting policy by +// specifying the fields to be updated via updateMask. Returns the +// updated alerting policy. +func (c *AlertPolicyClient) UpdateAlertPolicy(ctx context.Context, req *monitoringpb.UpdateAlertPolicyRequest, opts ...gax.CallOption) (*monitoringpb.AlertPolicy, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateAlertPolicy[0:len(c.CallOptions.UpdateAlertPolicy):len(c.CallOptions.UpdateAlertPolicy)], opts...) + var resp *monitoringpb.AlertPolicy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.alertPolicyClient.UpdateAlertPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// AlertPolicyIterator manages a stream of *monitoringpb.AlertPolicy. +type AlertPolicyIterator struct { + items []*monitoringpb.AlertPolicy + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*monitoringpb.AlertPolicy, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *AlertPolicyIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *AlertPolicyIterator) Next() (*monitoringpb.AlertPolicy, error) { + var item *monitoringpb.AlertPolicy + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *AlertPolicyIterator) bufLen() int { + return len(it.items) +} + +func (it *AlertPolicyIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/alert_policy_client_example_test.go b/vendor/cloud.google.com/go/monitoring/apiv3/alert_policy_client_example_test.go new file mode 100644 index 00000000..90c1420b --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/alert_policy_client_example_test.go @@ -0,0 +1,129 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package monitoring_test + +import ( + "context" + + monitoring "cloud.google.com/go/monitoring/apiv3" + "google.golang.org/api/iterator" + monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" +) + +func ExampleNewAlertPolicyClient() { + ctx := context.Background() + c, err := monitoring.NewAlertPolicyClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleAlertPolicyClient_ListAlertPolicies() { + ctx := context.Background() + c, err := monitoring.NewAlertPolicyClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.ListAlertPoliciesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListAlertPolicies(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleAlertPolicyClient_GetAlertPolicy() { + ctx := context.Background() + c, err := monitoring.NewAlertPolicyClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.GetAlertPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetAlertPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleAlertPolicyClient_CreateAlertPolicy() { + ctx := context.Background() + c, err := monitoring.NewAlertPolicyClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.CreateAlertPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateAlertPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleAlertPolicyClient_DeleteAlertPolicy() { + ctx := context.Background() + c, err := monitoring.NewAlertPolicyClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.DeleteAlertPolicyRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteAlertPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleAlertPolicyClient_UpdateAlertPolicy() { + ctx := context.Background() + c, err := monitoring.NewAlertPolicyClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.UpdateAlertPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateAlertPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/doc.go b/vendor/cloud.google.com/go/monitoring/apiv3/doc.go new file mode 100644 index 00000000..eb9ef7f5 --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/doc.go @@ -0,0 +1,94 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package monitoring is an auto-generated package for the +// Stackdriver Monitoring API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Manages your Stackdriver Monitoring data and configurations. Most projects +// must be associated with a Stackdriver account, with a few exceptions as +// noted on the individual method pages. +package monitoring // import "cloud.google.com/go/monitoring/apiv3" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/monitoring", + "https://www.googleapis.com/auth/monitoring.read", + "https://www.googleapis.com/auth/monitoring.write", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/group_client.go b/vendor/cloud.google.com/go/monitoring/apiv3/group_client.go new file mode 100644 index 00000000..2e37d23a --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/group_client.go @@ -0,0 +1,361 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package monitoring + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres" + monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// GroupCallOptions contains the retry settings for each method of GroupClient. +type GroupCallOptions struct { + ListGroups []gax.CallOption + GetGroup []gax.CallOption + CreateGroup []gax.CallOption + UpdateGroup []gax.CallOption + DeleteGroup []gax.CallOption + ListGroupMembers []gax.CallOption +} + +func defaultGroupClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("monitoring.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultGroupCallOptions() *GroupCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &GroupCallOptions{ + ListGroups: retry[[2]string{"default", "idempotent"}], + GetGroup: retry[[2]string{"default", "idempotent"}], + CreateGroup: retry[[2]string{"default", "non_idempotent"}], + UpdateGroup: retry[[2]string{"default", "idempotent"}], + DeleteGroup: retry[[2]string{"default", "idempotent"}], + ListGroupMembers: retry[[2]string{"default", "idempotent"}], + } +} + +// GroupClient is a client for interacting with Stackdriver Monitoring API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type GroupClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + groupClient monitoringpb.GroupServiceClient + + // The call options for this service. + CallOptions *GroupCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewGroupClient creates a new group service client. +// +// The Group API lets you inspect and manage your +// groups (at #google.monitoring.v3.Group). +// +// A group is a named filter that is used to identify +// a collection of monitored resources. Groups are typically used to +// mirror the physical and/or logical topology of the environment. +// Because group membership is computed dynamically, monitored +// resources that are started in the future are automatically placed +// in matching groups. By using a group to name monitored resources in, +// for example, an alert policy, the target of that alert policy is +// updated automatically as monitored resources are added and removed +// from the infrastructure. +func NewGroupClient(ctx context.Context, opts ...option.ClientOption) (*GroupClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultGroupClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &GroupClient{ + conn: conn, + CallOptions: defaultGroupCallOptions(), + + groupClient: monitoringpb.NewGroupServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *GroupClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *GroupClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *GroupClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListGroups lists the existing groups. +func (c *GroupClient) ListGroups(ctx context.Context, req *monitoringpb.ListGroupsRequest, opts ...gax.CallOption) *GroupIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListGroups[0:len(c.CallOptions.ListGroups):len(c.CallOptions.ListGroups)], opts...) + it := &GroupIterator{} + req = proto.Clone(req).(*monitoringpb.ListGroupsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.Group, string, error) { + var resp *monitoringpb.ListGroupsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.groupClient.ListGroups(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Group, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetGroup gets a single group. +func (c *GroupClient) GetGroup(ctx context.Context, req *monitoringpb.GetGroupRequest, opts ...gax.CallOption) (*monitoringpb.Group, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetGroup[0:len(c.CallOptions.GetGroup):len(c.CallOptions.GetGroup)], opts...) + var resp *monitoringpb.Group + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.groupClient.GetGroup(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateGroup creates a new group. +func (c *GroupClient) CreateGroup(ctx context.Context, req *monitoringpb.CreateGroupRequest, opts ...gax.CallOption) (*monitoringpb.Group, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateGroup[0:len(c.CallOptions.CreateGroup):len(c.CallOptions.CreateGroup)], opts...) + var resp *monitoringpb.Group + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.groupClient.CreateGroup(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateGroup updates an existing group. +// You can change any group attributes except name. +func (c *GroupClient) UpdateGroup(ctx context.Context, req *monitoringpb.UpdateGroupRequest, opts ...gax.CallOption) (*monitoringpb.Group, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateGroup[0:len(c.CallOptions.UpdateGroup):len(c.CallOptions.UpdateGroup)], opts...) + var resp *monitoringpb.Group + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.groupClient.UpdateGroup(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteGroup deletes an existing group. +func (c *GroupClient) DeleteGroup(ctx context.Context, req *monitoringpb.DeleteGroupRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteGroup[0:len(c.CallOptions.DeleteGroup):len(c.CallOptions.DeleteGroup)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.groupClient.DeleteGroup(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ListGroupMembers lists the monitored resources that are members of a group. +func (c *GroupClient) ListGroupMembers(ctx context.Context, req *monitoringpb.ListGroupMembersRequest, opts ...gax.CallOption) *MonitoredResourceIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListGroupMembers[0:len(c.CallOptions.ListGroupMembers):len(c.CallOptions.ListGroupMembers)], opts...) + it := &MonitoredResourceIterator{} + req = proto.Clone(req).(*monitoringpb.ListGroupMembersRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoredrespb.MonitoredResource, string, error) { + var resp *monitoringpb.ListGroupMembersResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.groupClient.ListGroupMembers(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Members, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GroupIterator manages a stream of *monitoringpb.Group. +type GroupIterator struct { + items []*monitoringpb.Group + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*monitoringpb.Group, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *GroupIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *GroupIterator) Next() (*monitoringpb.Group, error) { + var item *monitoringpb.Group + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *GroupIterator) bufLen() int { + return len(it.items) +} + +func (it *GroupIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// MonitoredResourceIterator manages a stream of *monitoredrespb.MonitoredResource. +type MonitoredResourceIterator struct { + items []*monitoredrespb.MonitoredResource + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*monitoredrespb.MonitoredResource, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *MonitoredResourceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *MonitoredResourceIterator) Next() (*monitoredrespb.MonitoredResource, error) { + var item *monitoredrespb.MonitoredResource + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *MonitoredResourceIterator) bufLen() int { + return len(it.items) +} + +func (it *MonitoredResourceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/group_client_example_test.go b/vendor/cloud.google.com/go/monitoring/apiv3/group_client_example_test.go new file mode 100644 index 00000000..7667acd6 --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/group_client_example_test.go @@ -0,0 +1,153 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package monitoring_test + +import ( + "context" + + monitoring "cloud.google.com/go/monitoring/apiv3" + "google.golang.org/api/iterator" + monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" +) + +func ExampleNewGroupClient() { + ctx := context.Background() + c, err := monitoring.NewGroupClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleGroupClient_ListGroups() { + ctx := context.Background() + c, err := monitoring.NewGroupClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.ListGroupsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListGroups(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleGroupClient_GetGroup() { + ctx := context.Background() + c, err := monitoring.NewGroupClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.GetGroupRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetGroup(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleGroupClient_CreateGroup() { + ctx := context.Background() + c, err := monitoring.NewGroupClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.CreateGroupRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateGroup(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleGroupClient_UpdateGroup() { + ctx := context.Background() + c, err := monitoring.NewGroupClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.UpdateGroupRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateGroup(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleGroupClient_DeleteGroup() { + ctx := context.Background() + c, err := monitoring.NewGroupClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.DeleteGroupRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteGroup(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleGroupClient_ListGroupMembers() { + ctx := context.Background() + c, err := monitoring.NewGroupClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.ListGroupMembersRequest{ + // TODO: Fill request struct fields. + } + it := c.ListGroupMembers(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/metric_client.go b/vendor/cloud.google.com/go/monitoring/apiv3/metric_client.go new file mode 100644 index 00000000..029e073f --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/metric_client.go @@ -0,0 +1,452 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package monitoring + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + metricpb "google.golang.org/genproto/googleapis/api/metric" + monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres" + monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// MetricCallOptions contains the retry settings for each method of MetricClient. +type MetricCallOptions struct { + ListMonitoredResourceDescriptors []gax.CallOption + GetMonitoredResourceDescriptor []gax.CallOption + ListMetricDescriptors []gax.CallOption + GetMetricDescriptor []gax.CallOption + CreateMetricDescriptor []gax.CallOption + DeleteMetricDescriptor []gax.CallOption + ListTimeSeries []gax.CallOption + CreateTimeSeries []gax.CallOption +} + +func defaultMetricClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("monitoring.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultMetricCallOptions() *MetricCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &MetricCallOptions{ + ListMonitoredResourceDescriptors: retry[[2]string{"default", "idempotent"}], + GetMonitoredResourceDescriptor: retry[[2]string{"default", "idempotent"}], + ListMetricDescriptors: retry[[2]string{"default", "idempotent"}], + GetMetricDescriptor: retry[[2]string{"default", "idempotent"}], + CreateMetricDescriptor: retry[[2]string{"default", "non_idempotent"}], + DeleteMetricDescriptor: retry[[2]string{"default", "idempotent"}], + ListTimeSeries: retry[[2]string{"default", "idempotent"}], + CreateTimeSeries: retry[[2]string{"default", "non_idempotent"}], + } +} + +// MetricClient is a client for interacting with Stackdriver Monitoring API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type MetricClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + metricClient monitoringpb.MetricServiceClient + + // The call options for this service. + CallOptions *MetricCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewMetricClient creates a new metric service client. +// +// Manages metric descriptors, monitored resource descriptors, and +// time series data. +func NewMetricClient(ctx context.Context, opts ...option.ClientOption) (*MetricClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultMetricClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &MetricClient{ + conn: conn, + CallOptions: defaultMetricCallOptions(), + + metricClient: monitoringpb.NewMetricServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *MetricClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *MetricClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *MetricClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListMonitoredResourceDescriptors lists monitored resource descriptors that match a filter. This method does not require a Stackdriver account. +func (c *MetricClient) ListMonitoredResourceDescriptors(ctx context.Context, req *monitoringpb.ListMonitoredResourceDescriptorsRequest, opts ...gax.CallOption) *MonitoredResourceDescriptorIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListMonitoredResourceDescriptors[0:len(c.CallOptions.ListMonitoredResourceDescriptors):len(c.CallOptions.ListMonitoredResourceDescriptors)], opts...) + it := &MonitoredResourceDescriptorIterator{} + req = proto.Clone(req).(*monitoringpb.ListMonitoredResourceDescriptorsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoredrespb.MonitoredResourceDescriptor, string, error) { + var resp *monitoringpb.ListMonitoredResourceDescriptorsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.metricClient.ListMonitoredResourceDescriptors(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.ResourceDescriptors, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetMonitoredResourceDescriptor gets a single monitored resource descriptor. This method does not require a Stackdriver account. +func (c *MetricClient) GetMonitoredResourceDescriptor(ctx context.Context, req *monitoringpb.GetMonitoredResourceDescriptorRequest, opts ...gax.CallOption) (*monitoredrespb.MonitoredResourceDescriptor, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetMonitoredResourceDescriptor[0:len(c.CallOptions.GetMonitoredResourceDescriptor):len(c.CallOptions.GetMonitoredResourceDescriptor)], opts...) + var resp *monitoredrespb.MonitoredResourceDescriptor + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.metricClient.GetMonitoredResourceDescriptor(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListMetricDescriptors lists metric descriptors that match a filter. This method does not require a Stackdriver account. +func (c *MetricClient) ListMetricDescriptors(ctx context.Context, req *monitoringpb.ListMetricDescriptorsRequest, opts ...gax.CallOption) *MetricDescriptorIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListMetricDescriptors[0:len(c.CallOptions.ListMetricDescriptors):len(c.CallOptions.ListMetricDescriptors)], opts...) + it := &MetricDescriptorIterator{} + req = proto.Clone(req).(*monitoringpb.ListMetricDescriptorsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*metricpb.MetricDescriptor, string, error) { + var resp *monitoringpb.ListMetricDescriptorsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.metricClient.ListMetricDescriptors(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.MetricDescriptors, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetMetricDescriptor gets a single metric descriptor. This method does not require a Stackdriver account. +func (c *MetricClient) GetMetricDescriptor(ctx context.Context, req *monitoringpb.GetMetricDescriptorRequest, opts ...gax.CallOption) (*metricpb.MetricDescriptor, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetMetricDescriptor[0:len(c.CallOptions.GetMetricDescriptor):len(c.CallOptions.GetMetricDescriptor)], opts...) + var resp *metricpb.MetricDescriptor + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.metricClient.GetMetricDescriptor(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateMetricDescriptor creates a new metric descriptor. +// User-created metric descriptors define +// custom metrics (at /monitoring/custom-metrics). +func (c *MetricClient) CreateMetricDescriptor(ctx context.Context, req *monitoringpb.CreateMetricDescriptorRequest, opts ...gax.CallOption) (*metricpb.MetricDescriptor, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateMetricDescriptor[0:len(c.CallOptions.CreateMetricDescriptor):len(c.CallOptions.CreateMetricDescriptor)], opts...) + var resp *metricpb.MetricDescriptor + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.metricClient.CreateMetricDescriptor(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteMetricDescriptor deletes a metric descriptor. Only user-created +// custom metrics (at /monitoring/custom-metrics) can be deleted. +func (c *MetricClient) DeleteMetricDescriptor(ctx context.Context, req *monitoringpb.DeleteMetricDescriptorRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteMetricDescriptor[0:len(c.CallOptions.DeleteMetricDescriptor):len(c.CallOptions.DeleteMetricDescriptor)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.metricClient.DeleteMetricDescriptor(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ListTimeSeries lists time series that match a filter. This method does not require a Stackdriver account. +func (c *MetricClient) ListTimeSeries(ctx context.Context, req *monitoringpb.ListTimeSeriesRequest, opts ...gax.CallOption) *TimeSeriesIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListTimeSeries[0:len(c.CallOptions.ListTimeSeries):len(c.CallOptions.ListTimeSeries)], opts...) + it := &TimeSeriesIterator{} + req = proto.Clone(req).(*monitoringpb.ListTimeSeriesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.TimeSeries, string, error) { + var resp *monitoringpb.ListTimeSeriesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.metricClient.ListTimeSeries(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.TimeSeries, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// CreateTimeSeries creates or adds data to one or more time series. +// The response is empty if all time series in the request were written. +// If any time series could not be written, a corresponding failure message is +// included in the error response. +func (c *MetricClient) CreateTimeSeries(ctx context.Context, req *monitoringpb.CreateTimeSeriesRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateTimeSeries[0:len(c.CallOptions.CreateTimeSeries):len(c.CallOptions.CreateTimeSeries)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.metricClient.CreateTimeSeries(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// MetricDescriptorIterator manages a stream of *metricpb.MetricDescriptor. +type MetricDescriptorIterator struct { + items []*metricpb.MetricDescriptor + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*metricpb.MetricDescriptor, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *MetricDescriptorIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *MetricDescriptorIterator) Next() (*metricpb.MetricDescriptor, error) { + var item *metricpb.MetricDescriptor + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *MetricDescriptorIterator) bufLen() int { + return len(it.items) +} + +func (it *MetricDescriptorIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// MonitoredResourceDescriptorIterator manages a stream of *monitoredrespb.MonitoredResourceDescriptor. +type MonitoredResourceDescriptorIterator struct { + items []*monitoredrespb.MonitoredResourceDescriptor + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*monitoredrespb.MonitoredResourceDescriptor, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *MonitoredResourceDescriptorIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *MonitoredResourceDescriptorIterator) Next() (*monitoredrespb.MonitoredResourceDescriptor, error) { + var item *monitoredrespb.MonitoredResourceDescriptor + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *MonitoredResourceDescriptorIterator) bufLen() int { + return len(it.items) +} + +func (it *MonitoredResourceDescriptorIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// TimeSeriesIterator manages a stream of *monitoringpb.TimeSeries. +type TimeSeriesIterator struct { + items []*monitoringpb.TimeSeries + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*monitoringpb.TimeSeries, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TimeSeriesIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TimeSeriesIterator) Next() (*monitoringpb.TimeSeries, error) { + var item *monitoringpb.TimeSeries + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TimeSeriesIterator) bufLen() int { + return len(it.items) +} + +func (it *TimeSeriesIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/metric_client_example_test.go b/vendor/cloud.google.com/go/monitoring/apiv3/metric_client_example_test.go new file mode 100644 index 00000000..4333792c --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/metric_client_example_test.go @@ -0,0 +1,193 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package monitoring_test + +import ( + "context" + + monitoring "cloud.google.com/go/monitoring/apiv3" + "google.golang.org/api/iterator" + monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" +) + +func ExampleNewMetricClient() { + ctx := context.Background() + c, err := monitoring.NewMetricClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleMetricClient_ListMonitoredResourceDescriptors() { + ctx := context.Background() + c, err := monitoring.NewMetricClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.ListMonitoredResourceDescriptorsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListMonitoredResourceDescriptors(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleMetricClient_GetMonitoredResourceDescriptor() { + ctx := context.Background() + c, err := monitoring.NewMetricClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.GetMonitoredResourceDescriptorRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetMonitoredResourceDescriptor(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleMetricClient_ListMetricDescriptors() { + ctx := context.Background() + c, err := monitoring.NewMetricClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.ListMetricDescriptorsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListMetricDescriptors(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleMetricClient_GetMetricDescriptor() { + ctx := context.Background() + c, err := monitoring.NewMetricClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.GetMetricDescriptorRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetMetricDescriptor(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleMetricClient_CreateMetricDescriptor() { + ctx := context.Background() + c, err := monitoring.NewMetricClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.CreateMetricDescriptorRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateMetricDescriptor(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleMetricClient_DeleteMetricDescriptor() { + ctx := context.Background() + c, err := monitoring.NewMetricClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.DeleteMetricDescriptorRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteMetricDescriptor(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleMetricClient_ListTimeSeries() { + ctx := context.Background() + c, err := monitoring.NewMetricClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.ListTimeSeriesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListTimeSeries(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleMetricClient_CreateTimeSeries() { + ctx := context.Background() + c, err := monitoring.NewMetricClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.CreateTimeSeriesRequest{ + // TODO: Fill request struct fields. + } + err = c.CreateTimeSeries(ctx, req) + if err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/mock_test.go b/vendor/cloud.google.com/go/monitoring/apiv3/mock_test.go new file mode 100644 index 00000000..f4939752 --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/mock_test.go @@ -0,0 +1,2644 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package monitoring + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + metricpb "google.golang.org/genproto/googleapis/api/metric" + monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres" + monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockAlertPolicyServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + monitoringpb.AlertPolicyServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockAlertPolicyServer) ListAlertPolicies(ctx context.Context, req *monitoringpb.ListAlertPoliciesRequest) (*monitoringpb.ListAlertPoliciesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.ListAlertPoliciesResponse), nil +} + +func (s *mockAlertPolicyServer) GetAlertPolicy(ctx context.Context, req *monitoringpb.GetAlertPolicyRequest) (*monitoringpb.AlertPolicy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.AlertPolicy), nil +} + +func (s *mockAlertPolicyServer) CreateAlertPolicy(ctx context.Context, req *monitoringpb.CreateAlertPolicyRequest) (*monitoringpb.AlertPolicy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.AlertPolicy), nil +} + +func (s *mockAlertPolicyServer) DeleteAlertPolicy(ctx context.Context, req *monitoringpb.DeleteAlertPolicyRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockAlertPolicyServer) UpdateAlertPolicy(ctx context.Context, req *monitoringpb.UpdateAlertPolicyRequest) (*monitoringpb.AlertPolicy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.AlertPolicy), nil +} + +type mockGroupServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + monitoringpb.GroupServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockGroupServer) ListGroups(ctx context.Context, req *monitoringpb.ListGroupsRequest) (*monitoringpb.ListGroupsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.ListGroupsResponse), nil +} + +func (s *mockGroupServer) GetGroup(ctx context.Context, req *monitoringpb.GetGroupRequest) (*monitoringpb.Group, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.Group), nil +} + +func (s *mockGroupServer) CreateGroup(ctx context.Context, req *monitoringpb.CreateGroupRequest) (*monitoringpb.Group, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.Group), nil +} + +func (s *mockGroupServer) UpdateGroup(ctx context.Context, req *monitoringpb.UpdateGroupRequest) (*monitoringpb.Group, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.Group), nil +} + +func (s *mockGroupServer) DeleteGroup(ctx context.Context, req *monitoringpb.DeleteGroupRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockGroupServer) ListGroupMembers(ctx context.Context, req *monitoringpb.ListGroupMembersRequest) (*monitoringpb.ListGroupMembersResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.ListGroupMembersResponse), nil +} + +type mockMetricServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + monitoringpb.MetricServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockMetricServer) ListMonitoredResourceDescriptors(ctx context.Context, req *monitoringpb.ListMonitoredResourceDescriptorsRequest) (*monitoringpb.ListMonitoredResourceDescriptorsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.ListMonitoredResourceDescriptorsResponse), nil +} + +func (s *mockMetricServer) GetMonitoredResourceDescriptor(ctx context.Context, req *monitoringpb.GetMonitoredResourceDescriptorRequest) (*monitoredrespb.MonitoredResourceDescriptor, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoredrespb.MonitoredResourceDescriptor), nil +} + +func (s *mockMetricServer) ListMetricDescriptors(ctx context.Context, req *monitoringpb.ListMetricDescriptorsRequest) (*monitoringpb.ListMetricDescriptorsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.ListMetricDescriptorsResponse), nil +} + +func (s *mockMetricServer) GetMetricDescriptor(ctx context.Context, req *monitoringpb.GetMetricDescriptorRequest) (*metricpb.MetricDescriptor, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*metricpb.MetricDescriptor), nil +} + +func (s *mockMetricServer) CreateMetricDescriptor(ctx context.Context, req *monitoringpb.CreateMetricDescriptorRequest) (*metricpb.MetricDescriptor, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*metricpb.MetricDescriptor), nil +} + +func (s *mockMetricServer) DeleteMetricDescriptor(ctx context.Context, req *monitoringpb.DeleteMetricDescriptorRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockMetricServer) ListTimeSeries(ctx context.Context, req *monitoringpb.ListTimeSeriesRequest) (*monitoringpb.ListTimeSeriesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.ListTimeSeriesResponse), nil +} + +func (s *mockMetricServer) CreateTimeSeries(ctx context.Context, req *monitoringpb.CreateTimeSeriesRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +type mockNotificationChannelServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + monitoringpb.NotificationChannelServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockNotificationChannelServer) ListNotificationChannelDescriptors(ctx context.Context, req *monitoringpb.ListNotificationChannelDescriptorsRequest) (*monitoringpb.ListNotificationChannelDescriptorsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.ListNotificationChannelDescriptorsResponse), nil +} + +func (s *mockNotificationChannelServer) GetNotificationChannelDescriptor(ctx context.Context, req *monitoringpb.GetNotificationChannelDescriptorRequest) (*monitoringpb.NotificationChannelDescriptor, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.NotificationChannelDescriptor), nil +} + +func (s *mockNotificationChannelServer) ListNotificationChannels(ctx context.Context, req *monitoringpb.ListNotificationChannelsRequest) (*monitoringpb.ListNotificationChannelsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.ListNotificationChannelsResponse), nil +} + +func (s *mockNotificationChannelServer) GetNotificationChannel(ctx context.Context, req *monitoringpb.GetNotificationChannelRequest) (*monitoringpb.NotificationChannel, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.NotificationChannel), nil +} + +func (s *mockNotificationChannelServer) CreateNotificationChannel(ctx context.Context, req *monitoringpb.CreateNotificationChannelRequest) (*monitoringpb.NotificationChannel, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.NotificationChannel), nil +} + +func (s *mockNotificationChannelServer) UpdateNotificationChannel(ctx context.Context, req *monitoringpb.UpdateNotificationChannelRequest) (*monitoringpb.NotificationChannel, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.NotificationChannel), nil +} + +func (s *mockNotificationChannelServer) DeleteNotificationChannel(ctx context.Context, req *monitoringpb.DeleteNotificationChannelRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +type mockUptimeCheckServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + monitoringpb.UptimeCheckServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockUptimeCheckServer) ListUptimeCheckConfigs(ctx context.Context, req *monitoringpb.ListUptimeCheckConfigsRequest) (*monitoringpb.ListUptimeCheckConfigsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.ListUptimeCheckConfigsResponse), nil +} + +func (s *mockUptimeCheckServer) GetUptimeCheckConfig(ctx context.Context, req *monitoringpb.GetUptimeCheckConfigRequest) (*monitoringpb.UptimeCheckConfig, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.UptimeCheckConfig), nil +} + +func (s *mockUptimeCheckServer) CreateUptimeCheckConfig(ctx context.Context, req *monitoringpb.CreateUptimeCheckConfigRequest) (*monitoringpb.UptimeCheckConfig, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.UptimeCheckConfig), nil +} + +func (s *mockUptimeCheckServer) UpdateUptimeCheckConfig(ctx context.Context, req *monitoringpb.UpdateUptimeCheckConfigRequest) (*monitoringpb.UptimeCheckConfig, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.UptimeCheckConfig), nil +} + +func (s *mockUptimeCheckServer) DeleteUptimeCheckConfig(ctx context.Context, req *monitoringpb.DeleteUptimeCheckConfigRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockUptimeCheckServer) ListUptimeCheckIps(ctx context.Context, req *monitoringpb.ListUptimeCheckIpsRequest) (*monitoringpb.ListUptimeCheckIpsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*monitoringpb.ListUptimeCheckIpsResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockAlertPolicy mockAlertPolicyServer + mockGroup mockGroupServer + mockMetric mockMetricServer + mockNotificationChannel mockNotificationChannelServer + mockUptimeCheck mockUptimeCheckServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + monitoringpb.RegisterAlertPolicyServiceServer(serv, &mockAlertPolicy) + monitoringpb.RegisterGroupServiceServer(serv, &mockGroup) + monitoringpb.RegisterMetricServiceServer(serv, &mockMetric) + monitoringpb.RegisterNotificationChannelServiceServer(serv, &mockNotificationChannel) + monitoringpb.RegisterUptimeCheckServiceServer(serv, &mockUptimeCheck) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestAlertPolicyServiceListAlertPolicies(t *testing.T) { + var nextPageToken string = "" + var alertPoliciesElement *monitoringpb.AlertPolicy = &monitoringpb.AlertPolicy{} + var alertPolicies = []*monitoringpb.AlertPolicy{alertPoliciesElement} + var expectedResponse = &monitoringpb.ListAlertPoliciesResponse{ + NextPageToken: nextPageToken, + AlertPolicies: alertPolicies, + } + + mockAlertPolicy.err = nil + mockAlertPolicy.reqs = nil + + mockAlertPolicy.resps = append(mockAlertPolicy.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListAlertPoliciesRequest{ + Name: formattedName, + } + + c, err := NewAlertPolicyClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListAlertPolicies(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAlertPolicy.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.AlertPolicies[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestAlertPolicyServiceListAlertPoliciesError(t *testing.T) { + errCode := codes.PermissionDenied + mockAlertPolicy.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListAlertPoliciesRequest{ + Name: formattedName, + } + + c, err := NewAlertPolicyClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListAlertPolicies(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestAlertPolicyServiceGetAlertPolicy(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var expectedResponse = &monitoringpb.AlertPolicy{ + Name: name2, + DisplayName: displayName, + } + + mockAlertPolicy.err = nil + mockAlertPolicy.reqs = nil + + mockAlertPolicy.resps = append(mockAlertPolicy.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/alertPolicies/%s", "[PROJECT]", "[ALERT_POLICY]") + var request = &monitoringpb.GetAlertPolicyRequest{ + Name: formattedName, + } + + c, err := NewAlertPolicyClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetAlertPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAlertPolicy.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestAlertPolicyServiceGetAlertPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockAlertPolicy.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/alertPolicies/%s", "[PROJECT]", "[ALERT_POLICY]") + var request = &monitoringpb.GetAlertPolicyRequest{ + Name: formattedName, + } + + c, err := NewAlertPolicyClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetAlertPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestAlertPolicyServiceCreateAlertPolicy(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var expectedResponse = &monitoringpb.AlertPolicy{ + Name: name2, + DisplayName: displayName, + } + + mockAlertPolicy.err = nil + mockAlertPolicy.reqs = nil + + mockAlertPolicy.resps = append(mockAlertPolicy.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var alertPolicy *monitoringpb.AlertPolicy = &monitoringpb.AlertPolicy{} + var request = &monitoringpb.CreateAlertPolicyRequest{ + Name: formattedName, + AlertPolicy: alertPolicy, + } + + c, err := NewAlertPolicyClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateAlertPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAlertPolicy.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestAlertPolicyServiceCreateAlertPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockAlertPolicy.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var alertPolicy *monitoringpb.AlertPolicy = &monitoringpb.AlertPolicy{} + var request = &monitoringpb.CreateAlertPolicyRequest{ + Name: formattedName, + AlertPolicy: alertPolicy, + } + + c, err := NewAlertPolicyClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateAlertPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestAlertPolicyServiceDeleteAlertPolicy(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockAlertPolicy.err = nil + mockAlertPolicy.reqs = nil + + mockAlertPolicy.resps = append(mockAlertPolicy.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/alertPolicies/%s", "[PROJECT]", "[ALERT_POLICY]") + var request = &monitoringpb.DeleteAlertPolicyRequest{ + Name: formattedName, + } + + c, err := NewAlertPolicyClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteAlertPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAlertPolicy.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestAlertPolicyServiceDeleteAlertPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockAlertPolicy.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/alertPolicies/%s", "[PROJECT]", "[ALERT_POLICY]") + var request = &monitoringpb.DeleteAlertPolicyRequest{ + Name: formattedName, + } + + c, err := NewAlertPolicyClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteAlertPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestAlertPolicyServiceUpdateAlertPolicy(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var expectedResponse = &monitoringpb.AlertPolicy{ + Name: name, + DisplayName: displayName, + } + + mockAlertPolicy.err = nil + mockAlertPolicy.reqs = nil + + mockAlertPolicy.resps = append(mockAlertPolicy.resps[:0], expectedResponse) + + var alertPolicy *monitoringpb.AlertPolicy = &monitoringpb.AlertPolicy{} + var request = &monitoringpb.UpdateAlertPolicyRequest{ + AlertPolicy: alertPolicy, + } + + c, err := NewAlertPolicyClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateAlertPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockAlertPolicy.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestAlertPolicyServiceUpdateAlertPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockAlertPolicy.err = gstatus.Error(errCode, "test error") + + var alertPolicy *monitoringpb.AlertPolicy = &monitoringpb.AlertPolicy{} + var request = &monitoringpb.UpdateAlertPolicyRequest{ + AlertPolicy: alertPolicy, + } + + c, err := NewAlertPolicyClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateAlertPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGroupServiceListGroups(t *testing.T) { + var nextPageToken string = "" + var groupElement *monitoringpb.Group = &monitoringpb.Group{} + var group = []*monitoringpb.Group{groupElement} + var expectedResponse = &monitoringpb.ListGroupsResponse{ + NextPageToken: nextPageToken, + Group: group, + } + + mockGroup.err = nil + mockGroup.reqs = nil + + mockGroup.resps = append(mockGroup.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListGroupsRequest{ + Name: formattedName, + } + + c, err := NewGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListGroups(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGroup.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Group[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGroupServiceListGroupsError(t *testing.T) { + errCode := codes.PermissionDenied + mockGroup.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListGroupsRequest{ + Name: formattedName, + } + + c, err := NewGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListGroups(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGroupServiceGetGroup(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var parentName string = "parentName1015022848" + var filter string = "filter-1274492040" + var isCluster bool = false + var expectedResponse = &monitoringpb.Group{ + Name: name2, + DisplayName: displayName, + ParentName: parentName, + Filter: filter, + IsCluster: isCluster, + } + + mockGroup.err = nil + mockGroup.reqs = nil + + mockGroup.resps = append(mockGroup.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/groups/%s", "[PROJECT]", "[GROUP]") + var request = &monitoringpb.GetGroupRequest{ + Name: formattedName, + } + + c, err := NewGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetGroup(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGroup.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGroupServiceGetGroupError(t *testing.T) { + errCode := codes.PermissionDenied + mockGroup.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/groups/%s", "[PROJECT]", "[GROUP]") + var request = &monitoringpb.GetGroupRequest{ + Name: formattedName, + } + + c, err := NewGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetGroup(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGroupServiceCreateGroup(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var parentName string = "parentName1015022848" + var filter string = "filter-1274492040" + var isCluster bool = false + var expectedResponse = &monitoringpb.Group{ + Name: name2, + DisplayName: displayName, + ParentName: parentName, + Filter: filter, + IsCluster: isCluster, + } + + mockGroup.err = nil + mockGroup.reqs = nil + + mockGroup.resps = append(mockGroup.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var group *monitoringpb.Group = &monitoringpb.Group{} + var request = &monitoringpb.CreateGroupRequest{ + Name: formattedName, + Group: group, + } + + c, err := NewGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateGroup(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGroup.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGroupServiceCreateGroupError(t *testing.T) { + errCode := codes.PermissionDenied + mockGroup.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var group *monitoringpb.Group = &monitoringpb.Group{} + var request = &monitoringpb.CreateGroupRequest{ + Name: formattedName, + Group: group, + } + + c, err := NewGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateGroup(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGroupServiceUpdateGroup(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var parentName string = "parentName1015022848" + var filter string = "filter-1274492040" + var isCluster bool = false + var expectedResponse = &monitoringpb.Group{ + Name: name, + DisplayName: displayName, + ParentName: parentName, + Filter: filter, + IsCluster: isCluster, + } + + mockGroup.err = nil + mockGroup.reqs = nil + + mockGroup.resps = append(mockGroup.resps[:0], expectedResponse) + + var group *monitoringpb.Group = &monitoringpb.Group{} + var request = &monitoringpb.UpdateGroupRequest{ + Group: group, + } + + c, err := NewGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateGroup(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGroup.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGroupServiceUpdateGroupError(t *testing.T) { + errCode := codes.PermissionDenied + mockGroup.err = gstatus.Error(errCode, "test error") + + var group *monitoringpb.Group = &monitoringpb.Group{} + var request = &monitoringpb.UpdateGroupRequest{ + Group: group, + } + + c, err := NewGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateGroup(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestGroupServiceDeleteGroup(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockGroup.err = nil + mockGroup.reqs = nil + + mockGroup.resps = append(mockGroup.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/groups/%s", "[PROJECT]", "[GROUP]") + var request = &monitoringpb.DeleteGroupRequest{ + Name: formattedName, + } + + c, err := NewGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteGroup(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGroup.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestGroupServiceDeleteGroupError(t *testing.T) { + errCode := codes.PermissionDenied + mockGroup.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/groups/%s", "[PROJECT]", "[GROUP]") + var request = &monitoringpb.DeleteGroupRequest{ + Name: formattedName, + } + + c, err := NewGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteGroup(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestGroupServiceListGroupMembers(t *testing.T) { + var nextPageToken string = "" + var totalSize int32 = 705419236 + var membersElement *monitoredrespb.MonitoredResource = &monitoredrespb.MonitoredResource{} + var members = []*monitoredrespb.MonitoredResource{membersElement} + var expectedResponse = &monitoringpb.ListGroupMembersResponse{ + NextPageToken: nextPageToken, + TotalSize: totalSize, + Members: members, + } + + mockGroup.err = nil + mockGroup.reqs = nil + + mockGroup.resps = append(mockGroup.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/groups/%s", "[PROJECT]", "[GROUP]") + var request = &monitoringpb.ListGroupMembersRequest{ + Name: formattedName, + } + + c, err := NewGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListGroupMembers(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockGroup.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Members[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestGroupServiceListGroupMembersError(t *testing.T) { + errCode := codes.PermissionDenied + mockGroup.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/groups/%s", "[PROJECT]", "[GROUP]") + var request = &monitoringpb.ListGroupMembersRequest{ + Name: formattedName, + } + + c, err := NewGroupClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListGroupMembers(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestMetricServiceListMonitoredResourceDescriptors(t *testing.T) { + var nextPageToken string = "" + var resourceDescriptorsElement *monitoredrespb.MonitoredResourceDescriptor = &monitoredrespb.MonitoredResourceDescriptor{} + var resourceDescriptors = []*monitoredrespb.MonitoredResourceDescriptor{resourceDescriptorsElement} + var expectedResponse = &monitoringpb.ListMonitoredResourceDescriptorsResponse{ + NextPageToken: nextPageToken, + ResourceDescriptors: resourceDescriptors, + } + + mockMetric.err = nil + mockMetric.reqs = nil + + mockMetric.resps = append(mockMetric.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListMonitoredResourceDescriptorsRequest{ + Name: formattedName, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListMonitoredResourceDescriptors(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockMetric.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.ResourceDescriptors[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestMetricServiceListMonitoredResourceDescriptorsError(t *testing.T) { + errCode := codes.PermissionDenied + mockMetric.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListMonitoredResourceDescriptorsRequest{ + Name: formattedName, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListMonitoredResourceDescriptors(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestMetricServiceGetMonitoredResourceDescriptor(t *testing.T) { + var name2 string = "name2-1052831874" + var type_ string = "type3575610" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &monitoredrespb.MonitoredResourceDescriptor{ + Name: name2, + Type: type_, + DisplayName: displayName, + Description: description, + } + + mockMetric.err = nil + mockMetric.reqs = nil + + mockMetric.resps = append(mockMetric.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/monitoredResourceDescriptors/%s", "[PROJECT]", "[MONITORED_RESOURCE_DESCRIPTOR]") + var request = &monitoringpb.GetMonitoredResourceDescriptorRequest{ + Name: formattedName, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetMonitoredResourceDescriptor(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockMetric.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestMetricServiceGetMonitoredResourceDescriptorError(t *testing.T) { + errCode := codes.PermissionDenied + mockMetric.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/monitoredResourceDescriptors/%s", "[PROJECT]", "[MONITORED_RESOURCE_DESCRIPTOR]") + var request = &monitoringpb.GetMonitoredResourceDescriptorRequest{ + Name: formattedName, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetMonitoredResourceDescriptor(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestMetricServiceListMetricDescriptors(t *testing.T) { + var nextPageToken string = "" + var metricDescriptorsElement *metricpb.MetricDescriptor = &metricpb.MetricDescriptor{} + var metricDescriptors = []*metricpb.MetricDescriptor{metricDescriptorsElement} + var expectedResponse = &monitoringpb.ListMetricDescriptorsResponse{ + NextPageToken: nextPageToken, + MetricDescriptors: metricDescriptors, + } + + mockMetric.err = nil + mockMetric.reqs = nil + + mockMetric.resps = append(mockMetric.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListMetricDescriptorsRequest{ + Name: formattedName, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListMetricDescriptors(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockMetric.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.MetricDescriptors[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestMetricServiceListMetricDescriptorsError(t *testing.T) { + errCode := codes.PermissionDenied + mockMetric.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListMetricDescriptorsRequest{ + Name: formattedName, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListMetricDescriptors(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestMetricServiceGetMetricDescriptor(t *testing.T) { + var name2 string = "name2-1052831874" + var type_ string = "type3575610" + var unit string = "unit3594628" + var description string = "description-1724546052" + var displayName string = "displayName1615086568" + var expectedResponse = &metricpb.MetricDescriptor{ + Name: name2, + Type: type_, + Unit: unit, + Description: description, + DisplayName: displayName, + } + + mockMetric.err = nil + mockMetric.reqs = nil + + mockMetric.resps = append(mockMetric.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/metricDescriptors/%s", "[PROJECT]", "[METRIC_DESCRIPTOR]") + var request = &monitoringpb.GetMetricDescriptorRequest{ + Name: formattedName, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetMetricDescriptor(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockMetric.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestMetricServiceGetMetricDescriptorError(t *testing.T) { + errCode := codes.PermissionDenied + mockMetric.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/metricDescriptors/%s", "[PROJECT]", "[METRIC_DESCRIPTOR]") + var request = &monitoringpb.GetMetricDescriptorRequest{ + Name: formattedName, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetMetricDescriptor(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestMetricServiceCreateMetricDescriptor(t *testing.T) { + var name2 string = "name2-1052831874" + var type_ string = "type3575610" + var unit string = "unit3594628" + var description string = "description-1724546052" + var displayName string = "displayName1615086568" + var expectedResponse = &metricpb.MetricDescriptor{ + Name: name2, + Type: type_, + Unit: unit, + Description: description, + DisplayName: displayName, + } + + mockMetric.err = nil + mockMetric.reqs = nil + + mockMetric.resps = append(mockMetric.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var metricDescriptor *metricpb.MetricDescriptor = &metricpb.MetricDescriptor{} + var request = &monitoringpb.CreateMetricDescriptorRequest{ + Name: formattedName, + MetricDescriptor: metricDescriptor, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateMetricDescriptor(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockMetric.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestMetricServiceCreateMetricDescriptorError(t *testing.T) { + errCode := codes.PermissionDenied + mockMetric.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var metricDescriptor *metricpb.MetricDescriptor = &metricpb.MetricDescriptor{} + var request = &monitoringpb.CreateMetricDescriptorRequest{ + Name: formattedName, + MetricDescriptor: metricDescriptor, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateMetricDescriptor(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestMetricServiceDeleteMetricDescriptor(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockMetric.err = nil + mockMetric.reqs = nil + + mockMetric.resps = append(mockMetric.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/metricDescriptors/%s", "[PROJECT]", "[METRIC_DESCRIPTOR]") + var request = &monitoringpb.DeleteMetricDescriptorRequest{ + Name: formattedName, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteMetricDescriptor(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockMetric.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestMetricServiceDeleteMetricDescriptorError(t *testing.T) { + errCode := codes.PermissionDenied + mockMetric.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/metricDescriptors/%s", "[PROJECT]", "[METRIC_DESCRIPTOR]") + var request = &monitoringpb.DeleteMetricDescriptorRequest{ + Name: formattedName, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteMetricDescriptor(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestMetricServiceListTimeSeries(t *testing.T) { + var nextPageToken string = "" + var timeSeriesElement *monitoringpb.TimeSeries = &monitoringpb.TimeSeries{} + var timeSeries = []*monitoringpb.TimeSeries{timeSeriesElement} + var expectedResponse = &monitoringpb.ListTimeSeriesResponse{ + NextPageToken: nextPageToken, + TimeSeries: timeSeries, + } + + mockMetric.err = nil + mockMetric.reqs = nil + + mockMetric.resps = append(mockMetric.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var filter string = "filter-1274492040" + var interval *monitoringpb.TimeInterval = &monitoringpb.TimeInterval{} + var view monitoringpb.ListTimeSeriesRequest_TimeSeriesView = monitoringpb.ListTimeSeriesRequest_FULL + var request = &monitoringpb.ListTimeSeriesRequest{ + Name: formattedName, + Filter: filter, + Interval: interval, + View: view, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTimeSeries(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockMetric.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.TimeSeries[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestMetricServiceListTimeSeriesError(t *testing.T) { + errCode := codes.PermissionDenied + mockMetric.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var filter string = "filter-1274492040" + var interval *monitoringpb.TimeInterval = &monitoringpb.TimeInterval{} + var view monitoringpb.ListTimeSeriesRequest_TimeSeriesView = monitoringpb.ListTimeSeriesRequest_FULL + var request = &monitoringpb.ListTimeSeriesRequest{ + Name: formattedName, + Filter: filter, + Interval: interval, + View: view, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTimeSeries(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestMetricServiceCreateTimeSeries(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockMetric.err = nil + mockMetric.reqs = nil + + mockMetric.resps = append(mockMetric.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var timeSeries []*monitoringpb.TimeSeries = nil + var request = &monitoringpb.CreateTimeSeriesRequest{ + Name: formattedName, + TimeSeries: timeSeries, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.CreateTimeSeries(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockMetric.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestMetricServiceCreateTimeSeriesError(t *testing.T) { + errCode := codes.PermissionDenied + mockMetric.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var timeSeries []*monitoringpb.TimeSeries = nil + var request = &monitoringpb.CreateTimeSeriesRequest{ + Name: formattedName, + TimeSeries: timeSeries, + } + + c, err := NewMetricClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.CreateTimeSeries(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestNotificationChannelServiceListNotificationChannelDescriptors(t *testing.T) { + var nextPageToken string = "" + var channelDescriptorsElement *monitoringpb.NotificationChannelDescriptor = &monitoringpb.NotificationChannelDescriptor{} + var channelDescriptors = []*monitoringpb.NotificationChannelDescriptor{channelDescriptorsElement} + var expectedResponse = &monitoringpb.ListNotificationChannelDescriptorsResponse{ + NextPageToken: nextPageToken, + ChannelDescriptors: channelDescriptors, + } + + mockNotificationChannel.err = nil + mockNotificationChannel.reqs = nil + + mockNotificationChannel.resps = append(mockNotificationChannel.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListNotificationChannelDescriptorsRequest{ + Name: formattedName, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListNotificationChannelDescriptors(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockNotificationChannel.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.ChannelDescriptors[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestNotificationChannelServiceListNotificationChannelDescriptorsError(t *testing.T) { + errCode := codes.PermissionDenied + mockNotificationChannel.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListNotificationChannelDescriptorsRequest{ + Name: formattedName, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListNotificationChannelDescriptors(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestNotificationChannelServiceGetNotificationChannelDescriptor(t *testing.T) { + var name2 string = "name2-1052831874" + var type_ string = "type3575610" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &monitoringpb.NotificationChannelDescriptor{ + Name: name2, + Type: type_, + DisplayName: displayName, + Description: description, + } + + mockNotificationChannel.err = nil + mockNotificationChannel.reqs = nil + + mockNotificationChannel.resps = append(mockNotificationChannel.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/notificationChannelDescriptors/%s", "[PROJECT]", "[CHANNEL_DESCRIPTOR]") + var request = &monitoringpb.GetNotificationChannelDescriptorRequest{ + Name: formattedName, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetNotificationChannelDescriptor(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockNotificationChannel.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestNotificationChannelServiceGetNotificationChannelDescriptorError(t *testing.T) { + errCode := codes.PermissionDenied + mockNotificationChannel.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/notificationChannelDescriptors/%s", "[PROJECT]", "[CHANNEL_DESCRIPTOR]") + var request = &monitoringpb.GetNotificationChannelDescriptorRequest{ + Name: formattedName, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetNotificationChannelDescriptor(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestNotificationChannelServiceListNotificationChannels(t *testing.T) { + var nextPageToken string = "" + var notificationChannelsElement *monitoringpb.NotificationChannel = &monitoringpb.NotificationChannel{} + var notificationChannels = []*monitoringpb.NotificationChannel{notificationChannelsElement} + var expectedResponse = &monitoringpb.ListNotificationChannelsResponse{ + NextPageToken: nextPageToken, + NotificationChannels: notificationChannels, + } + + mockNotificationChannel.err = nil + mockNotificationChannel.reqs = nil + + mockNotificationChannel.resps = append(mockNotificationChannel.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListNotificationChannelsRequest{ + Name: formattedName, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListNotificationChannels(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockNotificationChannel.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.NotificationChannels[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestNotificationChannelServiceListNotificationChannelsError(t *testing.T) { + errCode := codes.PermissionDenied + mockNotificationChannel.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListNotificationChannelsRequest{ + Name: formattedName, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListNotificationChannels(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestNotificationChannelServiceGetNotificationChannel(t *testing.T) { + var type_ string = "type3575610" + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &monitoringpb.NotificationChannel{ + Type: type_, + Name: name2, + DisplayName: displayName, + Description: description, + } + + mockNotificationChannel.err = nil + mockNotificationChannel.reqs = nil + + mockNotificationChannel.resps = append(mockNotificationChannel.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/notificationChannels/%s", "[PROJECT]", "[NOTIFICATION_CHANNEL]") + var request = &monitoringpb.GetNotificationChannelRequest{ + Name: formattedName, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetNotificationChannel(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockNotificationChannel.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestNotificationChannelServiceGetNotificationChannelError(t *testing.T) { + errCode := codes.PermissionDenied + mockNotificationChannel.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/notificationChannels/%s", "[PROJECT]", "[NOTIFICATION_CHANNEL]") + var request = &monitoringpb.GetNotificationChannelRequest{ + Name: formattedName, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetNotificationChannel(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestNotificationChannelServiceCreateNotificationChannel(t *testing.T) { + var type_ string = "type3575610" + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &monitoringpb.NotificationChannel{ + Type: type_, + Name: name2, + DisplayName: displayName, + Description: description, + } + + mockNotificationChannel.err = nil + mockNotificationChannel.reqs = nil + + mockNotificationChannel.resps = append(mockNotificationChannel.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var notificationChannel *monitoringpb.NotificationChannel = &monitoringpb.NotificationChannel{} + var request = &monitoringpb.CreateNotificationChannelRequest{ + Name: formattedName, + NotificationChannel: notificationChannel, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateNotificationChannel(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockNotificationChannel.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestNotificationChannelServiceCreateNotificationChannelError(t *testing.T) { + errCode := codes.PermissionDenied + mockNotificationChannel.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var notificationChannel *monitoringpb.NotificationChannel = &monitoringpb.NotificationChannel{} + var request = &monitoringpb.CreateNotificationChannelRequest{ + Name: formattedName, + NotificationChannel: notificationChannel, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateNotificationChannel(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestNotificationChannelServiceUpdateNotificationChannel(t *testing.T) { + var type_ string = "type3575610" + var name string = "name3373707" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &monitoringpb.NotificationChannel{ + Type: type_, + Name: name, + DisplayName: displayName, + Description: description, + } + + mockNotificationChannel.err = nil + mockNotificationChannel.reqs = nil + + mockNotificationChannel.resps = append(mockNotificationChannel.resps[:0], expectedResponse) + + var notificationChannel *monitoringpb.NotificationChannel = &monitoringpb.NotificationChannel{} + var request = &monitoringpb.UpdateNotificationChannelRequest{ + NotificationChannel: notificationChannel, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateNotificationChannel(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockNotificationChannel.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestNotificationChannelServiceUpdateNotificationChannelError(t *testing.T) { + errCode := codes.PermissionDenied + mockNotificationChannel.err = gstatus.Error(errCode, "test error") + + var notificationChannel *monitoringpb.NotificationChannel = &monitoringpb.NotificationChannel{} + var request = &monitoringpb.UpdateNotificationChannelRequest{ + NotificationChannel: notificationChannel, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateNotificationChannel(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestNotificationChannelServiceDeleteNotificationChannel(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockNotificationChannel.err = nil + mockNotificationChannel.reqs = nil + + mockNotificationChannel.resps = append(mockNotificationChannel.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/notificationChannels/%s", "[PROJECT]", "[NOTIFICATION_CHANNEL]") + var request = &monitoringpb.DeleteNotificationChannelRequest{ + Name: formattedName, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteNotificationChannel(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockNotificationChannel.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestNotificationChannelServiceDeleteNotificationChannelError(t *testing.T) { + errCode := codes.PermissionDenied + mockNotificationChannel.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/notificationChannels/%s", "[PROJECT]", "[NOTIFICATION_CHANNEL]") + var request = &monitoringpb.DeleteNotificationChannelRequest{ + Name: formattedName, + } + + c, err := NewNotificationChannelClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteNotificationChannel(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestUptimeCheckServiceListUptimeCheckConfigs(t *testing.T) { + var nextPageToken string = "" + var totalSize int32 = 705419236 + var uptimeCheckConfigsElement *monitoringpb.UptimeCheckConfig = &monitoringpb.UptimeCheckConfig{} + var uptimeCheckConfigs = []*monitoringpb.UptimeCheckConfig{uptimeCheckConfigsElement} + var expectedResponse = &monitoringpb.ListUptimeCheckConfigsResponse{ + NextPageToken: nextPageToken, + TotalSize: totalSize, + UptimeCheckConfigs: uptimeCheckConfigs, + } + + mockUptimeCheck.err = nil + mockUptimeCheck.reqs = nil + + mockUptimeCheck.resps = append(mockUptimeCheck.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListUptimeCheckConfigsRequest{ + Parent: formattedParent, + } + + c, err := NewUptimeCheckClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListUptimeCheckConfigs(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockUptimeCheck.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.UptimeCheckConfigs[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestUptimeCheckServiceListUptimeCheckConfigsError(t *testing.T) { + errCode := codes.PermissionDenied + mockUptimeCheck.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &monitoringpb.ListUptimeCheckConfigsRequest{ + Parent: formattedParent, + } + + c, err := NewUptimeCheckClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListUptimeCheckConfigs(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestUptimeCheckServiceGetUptimeCheckConfig(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var isInternal bool = true + var expectedResponse = &monitoringpb.UptimeCheckConfig{ + Name: name2, + DisplayName: displayName, + IsInternal: isInternal, + } + + mockUptimeCheck.err = nil + mockUptimeCheck.reqs = nil + + mockUptimeCheck.resps = append(mockUptimeCheck.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/uptimeCheckConfigs/%s", "[PROJECT]", "[UPTIME_CHECK_CONFIG]") + var request = &monitoringpb.GetUptimeCheckConfigRequest{ + Name: formattedName, + } + + c, err := NewUptimeCheckClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetUptimeCheckConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockUptimeCheck.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestUptimeCheckServiceGetUptimeCheckConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockUptimeCheck.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/uptimeCheckConfigs/%s", "[PROJECT]", "[UPTIME_CHECK_CONFIG]") + var request = &monitoringpb.GetUptimeCheckConfigRequest{ + Name: formattedName, + } + + c, err := NewUptimeCheckClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetUptimeCheckConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestUptimeCheckServiceCreateUptimeCheckConfig(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var isInternal bool = true + var expectedResponse = &monitoringpb.UptimeCheckConfig{ + Name: name, + DisplayName: displayName, + IsInternal: isInternal, + } + + mockUptimeCheck.err = nil + mockUptimeCheck.reqs = nil + + mockUptimeCheck.resps = append(mockUptimeCheck.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var uptimeCheckConfig *monitoringpb.UptimeCheckConfig = &monitoringpb.UptimeCheckConfig{} + var request = &monitoringpb.CreateUptimeCheckConfigRequest{ + Parent: formattedParent, + UptimeCheckConfig: uptimeCheckConfig, + } + + c, err := NewUptimeCheckClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateUptimeCheckConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockUptimeCheck.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestUptimeCheckServiceCreateUptimeCheckConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockUptimeCheck.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var uptimeCheckConfig *monitoringpb.UptimeCheckConfig = &monitoringpb.UptimeCheckConfig{} + var request = &monitoringpb.CreateUptimeCheckConfigRequest{ + Parent: formattedParent, + UptimeCheckConfig: uptimeCheckConfig, + } + + c, err := NewUptimeCheckClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateUptimeCheckConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestUptimeCheckServiceUpdateUptimeCheckConfig(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var isInternal bool = true + var expectedResponse = &monitoringpb.UptimeCheckConfig{ + Name: name, + DisplayName: displayName, + IsInternal: isInternal, + } + + mockUptimeCheck.err = nil + mockUptimeCheck.reqs = nil + + mockUptimeCheck.resps = append(mockUptimeCheck.resps[:0], expectedResponse) + + var uptimeCheckConfig *monitoringpb.UptimeCheckConfig = &monitoringpb.UptimeCheckConfig{} + var request = &monitoringpb.UpdateUptimeCheckConfigRequest{ + UptimeCheckConfig: uptimeCheckConfig, + } + + c, err := NewUptimeCheckClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateUptimeCheckConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockUptimeCheck.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestUptimeCheckServiceUpdateUptimeCheckConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockUptimeCheck.err = gstatus.Error(errCode, "test error") + + var uptimeCheckConfig *monitoringpb.UptimeCheckConfig = &monitoringpb.UptimeCheckConfig{} + var request = &monitoringpb.UpdateUptimeCheckConfigRequest{ + UptimeCheckConfig: uptimeCheckConfig, + } + + c, err := NewUptimeCheckClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateUptimeCheckConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestUptimeCheckServiceDeleteUptimeCheckConfig(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockUptimeCheck.err = nil + mockUptimeCheck.reqs = nil + + mockUptimeCheck.resps = append(mockUptimeCheck.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/uptimeCheckConfigs/%s", "[PROJECT]", "[UPTIME_CHECK_CONFIG]") + var request = &monitoringpb.DeleteUptimeCheckConfigRequest{ + Name: formattedName, + } + + c, err := NewUptimeCheckClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteUptimeCheckConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockUptimeCheck.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestUptimeCheckServiceDeleteUptimeCheckConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockUptimeCheck.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/uptimeCheckConfigs/%s", "[PROJECT]", "[UPTIME_CHECK_CONFIG]") + var request = &monitoringpb.DeleteUptimeCheckConfigRequest{ + Name: formattedName, + } + + c, err := NewUptimeCheckClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteUptimeCheckConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestUptimeCheckServiceListUptimeCheckIps(t *testing.T) { + var nextPageToken string = "" + var uptimeCheckIpsElement *monitoringpb.UptimeCheckIp = &monitoringpb.UptimeCheckIp{} + var uptimeCheckIps = []*monitoringpb.UptimeCheckIp{uptimeCheckIpsElement} + var expectedResponse = &monitoringpb.ListUptimeCheckIpsResponse{ + NextPageToken: nextPageToken, + UptimeCheckIps: uptimeCheckIps, + } + + mockUptimeCheck.err = nil + mockUptimeCheck.reqs = nil + + mockUptimeCheck.resps = append(mockUptimeCheck.resps[:0], expectedResponse) + + var request *monitoringpb.ListUptimeCheckIpsRequest = &monitoringpb.ListUptimeCheckIpsRequest{} + + c, err := NewUptimeCheckClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListUptimeCheckIps(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockUptimeCheck.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.UptimeCheckIps[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestUptimeCheckServiceListUptimeCheckIpsError(t *testing.T) { + errCode := codes.PermissionDenied + mockUptimeCheck.err = gstatus.Error(errCode, "test error") + + var request *monitoringpb.ListUptimeCheckIpsRequest = &monitoringpb.ListUptimeCheckIpsRequest{} + + c, err := NewUptimeCheckClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListUptimeCheckIps(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/notification_channel_client.go b/vendor/cloud.google.com/go/monitoring/apiv3/notification_channel_client.go new file mode 100644 index 00000000..eb82cc7b --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/notification_channel_client.go @@ -0,0 +1,375 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package monitoring + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// NotificationChannelCallOptions contains the retry settings for each method of NotificationChannelClient. +type NotificationChannelCallOptions struct { + ListNotificationChannelDescriptors []gax.CallOption + GetNotificationChannelDescriptor []gax.CallOption + ListNotificationChannels []gax.CallOption + GetNotificationChannel []gax.CallOption + CreateNotificationChannel []gax.CallOption + UpdateNotificationChannel []gax.CallOption + DeleteNotificationChannel []gax.CallOption +} + +func defaultNotificationChannelClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("monitoring.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultNotificationChannelCallOptions() *NotificationChannelCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &NotificationChannelCallOptions{ + ListNotificationChannelDescriptors: retry[[2]string{"default", "idempotent"}], + GetNotificationChannelDescriptor: retry[[2]string{"default", "idempotent"}], + ListNotificationChannels: retry[[2]string{"default", "idempotent"}], + GetNotificationChannel: retry[[2]string{"default", "idempotent"}], + CreateNotificationChannel: retry[[2]string{"default", "non_idempotent"}], + UpdateNotificationChannel: retry[[2]string{"default", "non_idempotent"}], + DeleteNotificationChannel: retry[[2]string{"default", "idempotent"}], + } +} + +// NotificationChannelClient is a client for interacting with Stackdriver Monitoring API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type NotificationChannelClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + notificationChannelClient monitoringpb.NotificationChannelServiceClient + + // The call options for this service. + CallOptions *NotificationChannelCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewNotificationChannelClient creates a new notification channel service client. +// +// The Notification Channel API provides access to configuration that +// controls how messages related to incidents are sent. +func NewNotificationChannelClient(ctx context.Context, opts ...option.ClientOption) (*NotificationChannelClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultNotificationChannelClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &NotificationChannelClient{ + conn: conn, + CallOptions: defaultNotificationChannelCallOptions(), + + notificationChannelClient: monitoringpb.NewNotificationChannelServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *NotificationChannelClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *NotificationChannelClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *NotificationChannelClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListNotificationChannelDescriptors lists the descriptors for supported channel types. The use of descriptors +// makes it possible for new channel types to be dynamically added. +func (c *NotificationChannelClient) ListNotificationChannelDescriptors(ctx context.Context, req *monitoringpb.ListNotificationChannelDescriptorsRequest, opts ...gax.CallOption) *NotificationChannelDescriptorIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListNotificationChannelDescriptors[0:len(c.CallOptions.ListNotificationChannelDescriptors):len(c.CallOptions.ListNotificationChannelDescriptors)], opts...) + it := &NotificationChannelDescriptorIterator{} + req = proto.Clone(req).(*monitoringpb.ListNotificationChannelDescriptorsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.NotificationChannelDescriptor, string, error) { + var resp *monitoringpb.ListNotificationChannelDescriptorsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.notificationChannelClient.ListNotificationChannelDescriptors(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.ChannelDescriptors, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetNotificationChannelDescriptor gets a single channel descriptor. The descriptor indicates which fields +// are expected / permitted for a notification channel of the given type. +func (c *NotificationChannelClient) GetNotificationChannelDescriptor(ctx context.Context, req *monitoringpb.GetNotificationChannelDescriptorRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannelDescriptor, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetNotificationChannelDescriptor[0:len(c.CallOptions.GetNotificationChannelDescriptor):len(c.CallOptions.GetNotificationChannelDescriptor)], opts...) + var resp *monitoringpb.NotificationChannelDescriptor + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.notificationChannelClient.GetNotificationChannelDescriptor(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListNotificationChannels lists the notification channels that have been created for the project. +func (c *NotificationChannelClient) ListNotificationChannels(ctx context.Context, req *monitoringpb.ListNotificationChannelsRequest, opts ...gax.CallOption) *NotificationChannelIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListNotificationChannels[0:len(c.CallOptions.ListNotificationChannels):len(c.CallOptions.ListNotificationChannels)], opts...) + it := &NotificationChannelIterator{} + req = proto.Clone(req).(*monitoringpb.ListNotificationChannelsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.NotificationChannel, string, error) { + var resp *monitoringpb.ListNotificationChannelsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.notificationChannelClient.ListNotificationChannels(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.NotificationChannels, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetNotificationChannel gets a single notification channel. The channel includes the relevant +// configuration details with which the channel was created. However, the +// response may truncate or omit passwords, API keys, or other private key +// matter and thus the response may not be 100% identical to the information +// that was supplied in the call to the create method. +func (c *NotificationChannelClient) GetNotificationChannel(ctx context.Context, req *monitoringpb.GetNotificationChannelRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannel, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetNotificationChannel[0:len(c.CallOptions.GetNotificationChannel):len(c.CallOptions.GetNotificationChannel)], opts...) + var resp *monitoringpb.NotificationChannel + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.notificationChannelClient.GetNotificationChannel(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateNotificationChannel creates a new notification channel, representing a single notification +// endpoint such as an email address, SMS number, or PagerDuty service. +func (c *NotificationChannelClient) CreateNotificationChannel(ctx context.Context, req *monitoringpb.CreateNotificationChannelRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannel, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateNotificationChannel[0:len(c.CallOptions.CreateNotificationChannel):len(c.CallOptions.CreateNotificationChannel)], opts...) + var resp *monitoringpb.NotificationChannel + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.notificationChannelClient.CreateNotificationChannel(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateNotificationChannel updates a notification channel. Fields not specified in the field mask +// remain unchanged. +func (c *NotificationChannelClient) UpdateNotificationChannel(ctx context.Context, req *monitoringpb.UpdateNotificationChannelRequest, opts ...gax.CallOption) (*monitoringpb.NotificationChannel, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateNotificationChannel[0:len(c.CallOptions.UpdateNotificationChannel):len(c.CallOptions.UpdateNotificationChannel)], opts...) + var resp *monitoringpb.NotificationChannel + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.notificationChannelClient.UpdateNotificationChannel(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteNotificationChannel deletes a notification channel. +func (c *NotificationChannelClient) DeleteNotificationChannel(ctx context.Context, req *monitoringpb.DeleteNotificationChannelRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteNotificationChannel[0:len(c.CallOptions.DeleteNotificationChannel):len(c.CallOptions.DeleteNotificationChannel)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.notificationChannelClient.DeleteNotificationChannel(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// NotificationChannelDescriptorIterator manages a stream of *monitoringpb.NotificationChannelDescriptor. +type NotificationChannelDescriptorIterator struct { + items []*monitoringpb.NotificationChannelDescriptor + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*monitoringpb.NotificationChannelDescriptor, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NotificationChannelDescriptorIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NotificationChannelDescriptorIterator) Next() (*monitoringpb.NotificationChannelDescriptor, error) { + var item *monitoringpb.NotificationChannelDescriptor + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *NotificationChannelDescriptorIterator) bufLen() int { + return len(it.items) +} + +func (it *NotificationChannelDescriptorIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// NotificationChannelIterator manages a stream of *monitoringpb.NotificationChannel. +type NotificationChannelIterator struct { + items []*monitoringpb.NotificationChannel + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*monitoringpb.NotificationChannel, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NotificationChannelIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NotificationChannelIterator) Next() (*monitoringpb.NotificationChannel, error) { + var item *monitoringpb.NotificationChannel + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *NotificationChannelIterator) bufLen() int { + return len(it.items) +} + +func (it *NotificationChannelIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/notification_channel_client_example_test.go b/vendor/cloud.google.com/go/monitoring/apiv3/notification_channel_client_example_test.go new file mode 100644 index 00000000..e1915edc --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/notification_channel_client_example_test.go @@ -0,0 +1,171 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package monitoring_test + +import ( + "context" + + monitoring "cloud.google.com/go/monitoring/apiv3" + "google.golang.org/api/iterator" + monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" +) + +func ExampleNewNotificationChannelClient() { + ctx := context.Background() + c, err := monitoring.NewNotificationChannelClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleNotificationChannelClient_ListNotificationChannelDescriptors() { + ctx := context.Background() + c, err := monitoring.NewNotificationChannelClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.ListNotificationChannelDescriptorsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListNotificationChannelDescriptors(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleNotificationChannelClient_GetNotificationChannelDescriptor() { + ctx := context.Background() + c, err := monitoring.NewNotificationChannelClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.GetNotificationChannelDescriptorRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetNotificationChannelDescriptor(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleNotificationChannelClient_ListNotificationChannels() { + ctx := context.Background() + c, err := monitoring.NewNotificationChannelClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.ListNotificationChannelsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListNotificationChannels(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleNotificationChannelClient_GetNotificationChannel() { + ctx := context.Background() + c, err := monitoring.NewNotificationChannelClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.GetNotificationChannelRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetNotificationChannel(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleNotificationChannelClient_CreateNotificationChannel() { + ctx := context.Background() + c, err := monitoring.NewNotificationChannelClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.CreateNotificationChannelRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateNotificationChannel(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleNotificationChannelClient_UpdateNotificationChannel() { + ctx := context.Background() + c, err := monitoring.NewNotificationChannelClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.UpdateNotificationChannelRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateNotificationChannel(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleNotificationChannelClient_DeleteNotificationChannel() { + ctx := context.Background() + c, err := monitoring.NewNotificationChannelClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.DeleteNotificationChannelRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteNotificationChannel(ctx, req) + if err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/path_funcs.go b/vendor/cloud.google.com/go/monitoring/apiv3/path_funcs.go new file mode 100644 index 00000000..b2b514ba --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/path_funcs.go @@ -0,0 +1,107 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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 monitoring + +// GroupProjectPath returns the path for the project resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s", project) +// instead. +func GroupProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} + +// GroupGroupPath returns the path for the group resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/groups/%s", project, group) +// instead. +func GroupGroupPath(project, group string) string { + return "" + + "projects/" + + project + + "/groups/" + + group + + "" +} + +// MetricProjectPath returns the path for the project resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s", project) +// instead. +func MetricProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} + +// MetricMetricDescriptorPath returns the path for the metric descriptor resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/metricDescriptors/%s", project, metricDescriptor) +// instead. +func MetricMetricDescriptorPath(project, metricDescriptor string) string { + return "" + + "projects/" + + project + + "/metricDescriptors/" + + metricDescriptor + + "" +} + +// MetricMonitoredResourceDescriptorPath returns the path for the monitored resource descriptor resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/monitoredResourceDescriptors/%s", project, monitoredResourceDescriptor) +// instead. +func MetricMonitoredResourceDescriptorPath(project, monitoredResourceDescriptor string) string { + return "" + + "projects/" + + project + + "/monitoredResourceDescriptors/" + + monitoredResourceDescriptor + + "" +} + +// UptimeCheckProjectPath returns the path for the project resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s", project) +// instead. +func UptimeCheckProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} + +// UptimeCheckUptimeCheckConfigPath returns the path for the uptime check config resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/uptimeCheckConfigs/%s", project, uptimeCheckConfig) +// instead. +func UptimeCheckUptimeCheckConfigPath(project, uptimeCheckConfig string) string { + return "" + + "projects/" + + project + + "/uptimeCheckConfigs/" + + uptimeCheckConfig + + "" +} diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/uptime_check_client.go b/vendor/cloud.google.com/go/monitoring/apiv3/uptime_check_client.go new file mode 100644 index 00000000..07a7ab81 --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/uptime_check_client.go @@ -0,0 +1,361 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package monitoring + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// UptimeCheckCallOptions contains the retry settings for each method of UptimeCheckClient. +type UptimeCheckCallOptions struct { + ListUptimeCheckConfigs []gax.CallOption + GetUptimeCheckConfig []gax.CallOption + CreateUptimeCheckConfig []gax.CallOption + UpdateUptimeCheckConfig []gax.CallOption + DeleteUptimeCheckConfig []gax.CallOption + ListUptimeCheckIps []gax.CallOption +} + +func defaultUptimeCheckClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("monitoring.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultUptimeCheckCallOptions() *UptimeCheckCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &UptimeCheckCallOptions{ + ListUptimeCheckConfigs: retry[[2]string{"default", "idempotent"}], + GetUptimeCheckConfig: retry[[2]string{"default", "idempotent"}], + CreateUptimeCheckConfig: retry[[2]string{"default", "non_idempotent"}], + UpdateUptimeCheckConfig: retry[[2]string{"default", "non_idempotent"}], + DeleteUptimeCheckConfig: retry[[2]string{"default", "idempotent"}], + ListUptimeCheckIps: retry[[2]string{"default", "idempotent"}], + } +} + +// UptimeCheckClient is a client for interacting with Stackdriver Monitoring API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type UptimeCheckClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + uptimeCheckClient monitoringpb.UptimeCheckServiceClient + + // The call options for this service. + CallOptions *UptimeCheckCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewUptimeCheckClient creates a new uptime check service client. +// +// The UptimeCheckService API is used to manage (list, create, delete, edit) +// uptime check configurations in the Stackdriver Monitoring product. An uptime +// check is a piece of configuration that determines which resources and +// services to monitor for availability. These configurations can also be +// configured interactively by navigating to the [Cloud Console] +// (http://console.cloud.google.com), selecting the appropriate project, +// clicking on "Monitoring" on the left-hand side to navigate to Stackdriver, +// and then clicking on "Uptime". +func NewUptimeCheckClient(ctx context.Context, opts ...option.ClientOption) (*UptimeCheckClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultUptimeCheckClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &UptimeCheckClient{ + conn: conn, + CallOptions: defaultUptimeCheckCallOptions(), + + uptimeCheckClient: monitoringpb.NewUptimeCheckServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *UptimeCheckClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *UptimeCheckClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *UptimeCheckClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListUptimeCheckConfigs lists the existing valid uptime check configurations for the project, +// leaving out any invalid configurations. +func (c *UptimeCheckClient) ListUptimeCheckConfigs(ctx context.Context, req *monitoringpb.ListUptimeCheckConfigsRequest, opts ...gax.CallOption) *UptimeCheckConfigIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListUptimeCheckConfigs[0:len(c.CallOptions.ListUptimeCheckConfigs):len(c.CallOptions.ListUptimeCheckConfigs)], opts...) + it := &UptimeCheckConfigIterator{} + req = proto.Clone(req).(*monitoringpb.ListUptimeCheckConfigsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.UptimeCheckConfig, string, error) { + var resp *monitoringpb.ListUptimeCheckConfigsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.uptimeCheckClient.ListUptimeCheckConfigs(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.UptimeCheckConfigs, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetUptimeCheckConfig gets a single uptime check configuration. +func (c *UptimeCheckClient) GetUptimeCheckConfig(ctx context.Context, req *monitoringpb.GetUptimeCheckConfigRequest, opts ...gax.CallOption) (*monitoringpb.UptimeCheckConfig, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetUptimeCheckConfig[0:len(c.CallOptions.GetUptimeCheckConfig):len(c.CallOptions.GetUptimeCheckConfig)], opts...) + var resp *monitoringpb.UptimeCheckConfig + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.uptimeCheckClient.GetUptimeCheckConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateUptimeCheckConfig creates a new uptime check configuration. +func (c *UptimeCheckClient) CreateUptimeCheckConfig(ctx context.Context, req *monitoringpb.CreateUptimeCheckConfigRequest, opts ...gax.CallOption) (*monitoringpb.UptimeCheckConfig, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateUptimeCheckConfig[0:len(c.CallOptions.CreateUptimeCheckConfig):len(c.CallOptions.CreateUptimeCheckConfig)], opts...) + var resp *monitoringpb.UptimeCheckConfig + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.uptimeCheckClient.CreateUptimeCheckConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateUptimeCheckConfig updates an uptime check configuration. You can either replace the entire +// configuration with a new one or replace only certain fields in the current +// configuration by specifying the fields to be updated via "updateMask". +// Returns the updated configuration. +func (c *UptimeCheckClient) UpdateUptimeCheckConfig(ctx context.Context, req *monitoringpb.UpdateUptimeCheckConfigRequest, opts ...gax.CallOption) (*monitoringpb.UptimeCheckConfig, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateUptimeCheckConfig[0:len(c.CallOptions.UpdateUptimeCheckConfig):len(c.CallOptions.UpdateUptimeCheckConfig)], opts...) + var resp *monitoringpb.UptimeCheckConfig + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.uptimeCheckClient.UpdateUptimeCheckConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteUptimeCheckConfig deletes an uptime check configuration. Note that this method will fail +// if the uptime check configuration is referenced by an alert policy or +// other dependent configs that would be rendered invalid by the deletion. +func (c *UptimeCheckClient) DeleteUptimeCheckConfig(ctx context.Context, req *monitoringpb.DeleteUptimeCheckConfigRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteUptimeCheckConfig[0:len(c.CallOptions.DeleteUptimeCheckConfig):len(c.CallOptions.DeleteUptimeCheckConfig)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.uptimeCheckClient.DeleteUptimeCheckConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ListUptimeCheckIps returns the list of IPs that checkers run from +func (c *UptimeCheckClient) ListUptimeCheckIps(ctx context.Context, req *monitoringpb.ListUptimeCheckIpsRequest, opts ...gax.CallOption) *UptimeCheckIpIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListUptimeCheckIps[0:len(c.CallOptions.ListUptimeCheckIps):len(c.CallOptions.ListUptimeCheckIps)], opts...) + it := &UptimeCheckIpIterator{} + req = proto.Clone(req).(*monitoringpb.ListUptimeCheckIpsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*monitoringpb.UptimeCheckIp, string, error) { + var resp *monitoringpb.ListUptimeCheckIpsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.uptimeCheckClient.ListUptimeCheckIps(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.UptimeCheckIps, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// UptimeCheckConfigIterator manages a stream of *monitoringpb.UptimeCheckConfig. +type UptimeCheckConfigIterator struct { + items []*monitoringpb.UptimeCheckConfig + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*monitoringpb.UptimeCheckConfig, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *UptimeCheckConfigIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *UptimeCheckConfigIterator) Next() (*monitoringpb.UptimeCheckConfig, error) { + var item *monitoringpb.UptimeCheckConfig + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *UptimeCheckConfigIterator) bufLen() int { + return len(it.items) +} + +func (it *UptimeCheckConfigIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// UptimeCheckIpIterator manages a stream of *monitoringpb.UptimeCheckIp. +type UptimeCheckIpIterator struct { + items []*monitoringpb.UptimeCheckIp + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*monitoringpb.UptimeCheckIp, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *UptimeCheckIpIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *UptimeCheckIpIterator) Next() (*monitoringpb.UptimeCheckIp, error) { + var item *monitoringpb.UptimeCheckIp + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *UptimeCheckIpIterator) bufLen() int { + return len(it.items) +} + +func (it *UptimeCheckIpIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/monitoring/apiv3/uptime_check_client_example_test.go b/vendor/cloud.google.com/go/monitoring/apiv3/uptime_check_client_example_test.go new file mode 100644 index 00000000..f04a3585 --- /dev/null +++ b/vendor/cloud.google.com/go/monitoring/apiv3/uptime_check_client_example_test.go @@ -0,0 +1,153 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package monitoring_test + +import ( + "context" + + monitoring "cloud.google.com/go/monitoring/apiv3" + "google.golang.org/api/iterator" + monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" +) + +func ExampleNewUptimeCheckClient() { + ctx := context.Background() + c, err := monitoring.NewUptimeCheckClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleUptimeCheckClient_ListUptimeCheckConfigs() { + ctx := context.Background() + c, err := monitoring.NewUptimeCheckClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.ListUptimeCheckConfigsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListUptimeCheckConfigs(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleUptimeCheckClient_GetUptimeCheckConfig() { + ctx := context.Background() + c, err := monitoring.NewUptimeCheckClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.GetUptimeCheckConfigRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetUptimeCheckConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleUptimeCheckClient_CreateUptimeCheckConfig() { + ctx := context.Background() + c, err := monitoring.NewUptimeCheckClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.CreateUptimeCheckConfigRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateUptimeCheckConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleUptimeCheckClient_UpdateUptimeCheckConfig() { + ctx := context.Background() + c, err := monitoring.NewUptimeCheckClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.UpdateUptimeCheckConfigRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateUptimeCheckConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleUptimeCheckClient_DeleteUptimeCheckConfig() { + ctx := context.Background() + c, err := monitoring.NewUptimeCheckClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.DeleteUptimeCheckConfigRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteUptimeCheckConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleUptimeCheckClient_ListUptimeCheckIps() { + ctx := context.Background() + c, err := monitoring.NewUptimeCheckClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &monitoringpb.ListUptimeCheckIpsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListUptimeCheckIps(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} diff --git a/vendor/cloud.google.com/go/old-news.md b/vendor/cloud.google.com/go/old-news.md new file mode 100644 index 00000000..6a8b84d7 --- /dev/null +++ b/vendor/cloud.google.com/go/old-news.md @@ -0,0 +1,698 @@ +_February 26, 2018_ + +*v0.19.0* + +- bigquery: + - Support customer-managed encryption keys. + +- bigtable: + - Improved emulator support. + - Support GetCluster. + +- datastore: + - Add general mutations. + - Support pointer struct fields. + - Support transaction options. + +- firestore: + - Add Transaction.GetAll. + - Support document cursors. + +- logging: + - Support concurrent RPCs to the service. + - Support per-entry resources. + +- profiler: + - Add config options to disable heap and thread profiling. + - Read the project ID from $GOOGLE_CLOUD_PROJECT when it's set. + +- pubsub: + - BEHAVIOR CHANGE: Release flow control after ack/nack (instead of after the + callback returns). + - Add SubscriptionInProject. + - Add OpenCensus instrumentation for streaming pull. + +- storage: + - Support CORS. + + +_January 18, 2018_ + +*v0.18.0* + +- bigquery: + - Marked stable. + - Schema inference of nullable fields supported. + - Added TimePartitioning to QueryConfig. + +- firestore: Data provided to DocumentRef.Set with a Merge option can contain + Delete sentinels. + +- logging: Clients can accept parent resources other than projects. + +- pubsub: + - pubsub/pstest: A lighweight fake for pubsub. Experimental; feedback welcome. + - Support updating more subscription metadata: AckDeadline, + RetainAckedMessages and RetentionDuration. + +- oslogin/apiv1beta: New client for the Cloud OS Login API. + +- rpcreplay: A package for recording and replaying gRPC traffic. + +- spanner: + - Add a ReadWithOptions that supports a row limit, as well as an index. + - Support query plan and execution statistics. + - Added [OpenCensus](http://opencensus.io) support. + +- storage: Clarify checksum validation for gzipped files (it is not validated + when the file is served uncompressed). + + +_December 11, 2017_ + +*v0.17.0* + +- firestore BREAKING CHANGES: + - Remove UpdateMap and UpdateStruct; rename UpdatePaths to Update. + Change + `docref.UpdateMap(ctx, map[string]interface{}{"a.b", 1})` + to + `docref.Update(ctx, []firestore.Update{{Path: "a.b", Value: 1}})` + + Change + `docref.UpdateStruct(ctx, []string{"Field"}, aStruct)` + to + `docref.Update(ctx, []firestore.Update{{Path: "Field", Value: aStruct.Field}})` + - Rename MergePaths to Merge; require args to be FieldPaths + - A value stored as an integer can be read into a floating-point field, and vice versa. +- bigtable/cmd/cbt: + - Support deleting a column. + - Add regex option for row read. +- spanner: Mark stable. +- storage: + - Add Reader.ContentEncoding method. + - Fix handling of SignedURL headers. +- bigquery: + - If Uploader.Put is called with no rows, it returns nil without making a + call. + - Schema inference supports the "nullable" option in struct tags for + non-required fields. + - TimePartitioning supports "Field". + + +_October 30, 2017_ + +*v0.16.0* + +- Other bigquery changes: + - `JobIterator.Next` returns `*Job`; removed `JobInfo` (BREAKING CHANGE). + - UseStandardSQL is deprecated; set UseLegacySQL to true if you need + Legacy SQL. + - Uploader.Put will generate a random insert ID if you do not provide one. + - Support time partitioning for load jobs. + - Support dry-run queries. + - A `Job` remembers its last retrieved status. + - Support retrieving job configuration. + - Support labels for jobs and tables. + - Support dataset access lists. + - Improve support for external data sources, including data from Bigtable and + Google Sheets, and tables with external data. + - Support updating a table's view configuration. + - Fix uploading civil times with nanoseconds. + +- storage: + - Support PubSub notifications. + - Support Requester Pays buckets. + +- profiler: Support goroutine and mutex profile types. + + +_October 3, 2017_ + +*v0.15.0* + +- firestore: beta release. See the + [announcement](https://firebase.googleblog.com/2017/10/introducing-cloud-firestore.html). + +- errorreporting: The existing package has been redesigned. + +- errors: This package has been removed. Use errorreporting. + + +_September 28, 2017_ + +*v0.14.0* + +- bigquery BREAKING CHANGES: + - Standard SQL is the default for queries and views. + - `Table.Create` takes `TableMetadata` as a second argument, instead of + options. + - `Dataset.Create` takes `DatasetMetadata` as a second argument. + - `DatasetMetadata` field `ID` renamed to `FullID` + - `TableMetadata` field `ID` renamed to `FullID` + +- Other bigquery changes: + - The client will append a random suffix to a provided job ID if you set + `AddJobIDSuffix` to true in a job config. + - Listing jobs is supported. + - Better retry logic. + +- vision, language, speech: clients are now stable + +- monitoring: client is now beta + +- profiler: + - Rename InstanceName to Instance, ZoneName to Zone + - Auto-detect service name and version on AppEngine. + +_September 8, 2017_ + +*v0.13.0* + +- bigquery: UseLegacySQL options for CreateTable and QueryConfig. Use these + options to continue using Legacy SQL after the client switches its default + to Standard SQL. + +- bigquery: Support for updating dataset labels. + +- bigquery: Set DatasetIterator.ProjectID to list datasets in a project other + than the client's. DatasetsInProject is no longer needed and is deprecated. + +- bigtable: Fail ListInstances when any zones fail. + +- spanner: support decoding of slices of basic types (e.g. []string, []int64, + etc.) + +- logging/logadmin: UpdateSink no longer creates a sink if it is missing + (actually a change to the underlying service, not the client) + +- profiler: Service and ServiceVersion replace Target in Config. + +_August 22, 2017_ + +*v0.12.0* + +- pubsub: Subscription.Receive now uses streaming pull. + +- pubsub: add Client.TopicInProject to access topics in a different project + than the client. + +- errors: renamed errorreporting. The errors package will be removed shortly. + +- datastore: improved retry behavior. + +- bigquery: support updates to dataset metadata, with etags. + +- bigquery: add etag support to Table.Update (BREAKING: etag argument added). + +- bigquery: generate all job IDs on the client. + +- storage: support bucket lifecycle configurations. + + +_July 31, 2017_ + +*v0.11.0* + +- Clients for spanner, pubsub and video are now in beta. + +- New client for DLP. + +- spanner: performance and testing improvements. + +- storage: requester-pays buckets are supported. + +- storage, profiler, bigtable, bigquery: bug fixes and other minor improvements. + +- pubsub: bug fixes and other minor improvements + +_June 17, 2017_ + + +*v0.10.0* + +- pubsub: Subscription.ModifyPushConfig replaced with Subscription.Update. + +- pubsub: Subscription.Receive now runs concurrently for higher throughput. + +- vision: cloud.google.com/go/vision is deprecated. Use +cloud.google.com/go/vision/apiv1 instead. + +- translation: now stable. + +- trace: several changes to the surface. See the link below. + +[Code changes required from v0.9.0.](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/master/MIGRATION.md) + + +_March 17, 2017_ + +Breaking Pubsub changes. +* Publish is now asynchronous +([announcement](https://groups.google.com/d/topic/google-api-go-announce/aaqRDIQ3rvU/discussion)). +* Subscription.Pull replaced by Subscription.Receive, which takes a callback ([announcement](https://groups.google.com/d/topic/google-api-go-announce/8pt6oetAdKc/discussion)). +* Message.Done replaced with Message.Ack and Message.Nack. + +_February 14, 2017_ + +Release of a client library for Spanner. See +the +[blog post](https://cloudplatform.googleblog.com/2017/02/introducing-Cloud-Spanner-a-global-database-service-for-mission-critical-applications.html). + +Note that although the Spanner service is beta, the Go client library is alpha. + +_December 12, 2016_ + +Beta release of BigQuery, DataStore, Logging and Storage. See the +[blog post](https://cloudplatform.googleblog.com/2016/12/announcing-new-google-cloud-client.html). + +Also, BigQuery now supports structs. Read a row directly into a struct with +`RowIterator.Next`, and upload a row directly from a struct with `Uploader.Put`. +You can also use field tags. See the [package documentation][cloud-bigquery-ref] +for details. + +_December 5, 2016_ + +More changes to BigQuery: + +* The `ValueList` type was removed. It is no longer necessary. Instead of + ```go + var v ValueList + ... it.Next(&v) .. + ``` + use + + ```go + var v []Value + ... it.Next(&v) ... + ``` + +* Previously, repeatedly calling `RowIterator.Next` on the same `[]Value` or + `ValueList` would append to the slice. Now each call resets the size to zero first. + +* Schema inference will infer the SQL type BYTES for a struct field of + type []byte. Previously it inferred STRING. + +* The types `uint`, `uint64` and `uintptr` are no longer supported in schema + inference. BigQuery's integer type is INT64, and those types may hold values + that are not correctly represented in a 64-bit signed integer. + +* The SQL types DATE, TIME and DATETIME are now supported. They correspond to + the `Date`, `Time` and `DateTime` types in the new `cloud.google.com/go/civil` + package. + +_November 17, 2016_ + +Change to BigQuery: values from INTEGER columns will now be returned as int64, +not int. This will avoid errors arising from large values on 32-bit systems. + +_November 8, 2016_ + +New datastore feature: datastore now encodes your nested Go structs as Entity values, +instead of a flattened list of the embedded struct's fields. +This means that you may now have twice-nested slices, eg. +```go +type State struct { + Cities []struct{ + Populations []int + } +} +``` + +See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/79jtrdeuJAg) for +more details. + +_November 8, 2016_ + +Breaking changes to datastore: contexts no longer hold namespaces; instead you +must set a key's namespace explicitly. Also, key functions have been changed +and renamed. + +* The WithNamespace function has been removed. To specify a namespace in a Query, use the Query.Namespace method: + ```go + q := datastore.NewQuery("Kind").Namespace("ns") + ``` + +* All the fields of Key are exported. That means you can construct any Key with a struct literal: + ```go + k := &Key{Kind: "Kind", ID: 37, Namespace: "ns"} + ``` + +* As a result of the above, the Key methods Kind, ID, d.Name, Parent, SetParent and Namespace have been removed. + +* `NewIncompleteKey` has been removed, replaced by `IncompleteKey`. Replace + ```go + NewIncompleteKey(ctx, kind, parent) + ``` + with + ```go + IncompleteKey(kind, parent) + ``` + and if you do use namespaces, make sure you set the namespace on the returned key. + +* `NewKey` has been removed, replaced by `NameKey` and `IDKey`. Replace + ```go + NewKey(ctx, kind, name, 0, parent) + NewKey(ctx, kind, "", id, parent) + ``` + with + ```go + NameKey(kind, name, parent) + IDKey(kind, id, parent) + ``` + and if you do use namespaces, make sure you set the namespace on the returned key. + +* The `Done` variable has been removed. Replace `datastore.Done` with `iterator.Done`, from the package `google.golang.org/api/iterator`. + +* The `Client.Close` method will have a return type of error. It will return the result of closing the underlying gRPC connection. + +See [the announcement](https://groups.google.com/forum/#!topic/google-api-go-announce/hqXtM_4Ix-0) for +more details. + +_October 27, 2016_ + +Breaking change to bigquery: `NewGCSReference` is now a function, +not a method on `Client`. + +New bigquery feature: `Table.LoaderFrom` now accepts a `ReaderSource`, enabling +loading data into a table from a file or any `io.Reader`. + +_October 21, 2016_ + +Breaking change to pubsub: removed `pubsub.Done`. + +Use `iterator.Done` instead, where `iterator` is the package +`google.golang.org/api/iterator`. + +_October 19, 2016_ + +Breaking changes to cloud.google.com/go/bigquery: + +* Client.Table and Client.OpenTable have been removed. + Replace + ```go + client.OpenTable("project", "dataset", "table") + ``` + with + ```go + client.DatasetInProject("project", "dataset").Table("table") + ``` + +* Client.CreateTable has been removed. + Replace + ```go + client.CreateTable(ctx, "project", "dataset", "table") + ``` + with + ```go + client.DatasetInProject("project", "dataset").Table("table").Create(ctx) + ``` + +* Dataset.ListTables have been replaced with Dataset.Tables. + Replace + ```go + tables, err := ds.ListTables(ctx) + ``` + with + ```go + it := ds.Tables(ctx) + for { + table, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: use table. + } + ``` + +* Client.Read has been replaced with Job.Read, Table.Read and Query.Read. + Replace + ```go + it, err := client.Read(ctx, job) + ``` + with + ```go + it, err := job.Read(ctx) + ``` + and similarly for reading from tables or queries. + +* The iterator returned from the Read methods is now named RowIterator. Its + behavior is closer to the other iterators in these libraries. It no longer + supports the Schema method; see the next item. + Replace + ```go + for it.Next(ctx) { + var vals ValueList + if err := it.Get(&vals); err != nil { + // TODO: Handle error. + } + // TODO: use vals. + } + if err := it.Err(); err != nil { + // TODO: Handle error. + } + ``` + with + ``` + for { + var vals ValueList + err := it.Next(&vals) + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: use vals. + } + ``` + Instead of the `RecordsPerRequest(n)` option, write + ```go + it.PageInfo().MaxSize = n + ``` + Instead of the `StartIndex(i)` option, write + ```go + it.StartIndex = i + ``` + +* ValueLoader.Load now takes a Schema in addition to a slice of Values. + Replace + ```go + func (vl *myValueLoader) Load(v []bigquery.Value) + ``` + with + ```go + func (vl *myValueLoader) Load(v []bigquery.Value, s bigquery.Schema) + ``` + + +* Table.Patch is replace by Table.Update. + Replace + ```go + p := table.Patch() + p.Description("new description") + metadata, err := p.Apply(ctx) + ``` + with + ```go + metadata, err := table.Update(ctx, bigquery.TableMetadataToUpdate{ + Description: "new description", + }) + ``` + +* Client.Copy is replaced by separate methods for each of its four functions. + All options have been replaced by struct fields. + + * To load data from Google Cloud Storage into a table, use Table.LoaderFrom. + + Replace + ```go + client.Copy(ctx, table, gcsRef) + ``` + with + ```go + table.LoaderFrom(gcsRef).Run(ctx) + ``` + Instead of passing options to Copy, set fields on the Loader: + ```go + loader := table.LoaderFrom(gcsRef) + loader.WriteDisposition = bigquery.WriteTruncate + ``` + + * To extract data from a table into Google Cloud Storage, use + Table.ExtractorTo. Set fields on the returned Extractor instead of + passing options. + + Replace + ```go + client.Copy(ctx, gcsRef, table) + ``` + with + ```go + table.ExtractorTo(gcsRef).Run(ctx) + ``` + + * To copy data into a table from one or more other tables, use + Table.CopierFrom. Set fields on the returned Copier instead of passing options. + + Replace + ```go + client.Copy(ctx, dstTable, srcTable) + ``` + with + ```go + dst.Table.CopierFrom(srcTable).Run(ctx) + ``` + + * To start a query job, create a Query and call its Run method. Set fields + on the query instead of passing options. + + Replace + ```go + client.Copy(ctx, table, query) + ``` + with + ```go + query.Run(ctx) + ``` + +* Table.NewUploader has been renamed to Table.Uploader. Instead of options, + configure an Uploader by setting its fields. + Replace + ```go + u := table.NewUploader(bigquery.UploadIgnoreUnknownValues()) + ``` + with + ```go + u := table.NewUploader(bigquery.UploadIgnoreUnknownValues()) + u.IgnoreUnknownValues = true + ``` + +_October 10, 2016_ + +Breaking changes to cloud.google.com/go/storage: + +* AdminClient replaced by methods on Client. + Replace + ```go + adminClient.CreateBucket(ctx, bucketName, attrs) + ``` + with + ```go + client.Bucket(bucketName).Create(ctx, projectID, attrs) + ``` + +* BucketHandle.List replaced by BucketHandle.Objects. + Replace + ```go + for query != nil { + objs, err := bucket.List(d.ctx, query) + if err != nil { ... } + query = objs.Next + for _, obj := range objs.Results { + fmt.Println(obj) + } + } + ``` + with + ```go + iter := bucket.Objects(d.ctx, query) + for { + obj, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { ... } + fmt.Println(obj) + } + ``` + (The `iterator` package is at `google.golang.org/api/iterator`.) + + Replace `Query.Cursor` with `ObjectIterator.PageInfo().Token`. + + Replace `Query.MaxResults` with `ObjectIterator.PageInfo().MaxSize`. + + +* ObjectHandle.CopyTo replaced by ObjectHandle.CopierFrom. + Replace + ```go + attrs, err := src.CopyTo(ctx, dst, nil) + ``` + with + ```go + attrs, err := dst.CopierFrom(src).Run(ctx) + ``` + + Replace + ```go + attrs, err := src.CopyTo(ctx, dst, &storage.ObjectAttrs{ContextType: "text/html"}) + ``` + with + ```go + c := dst.CopierFrom(src) + c.ContextType = "text/html" + attrs, err := c.Run(ctx) + ``` + +* ObjectHandle.ComposeFrom replaced by ObjectHandle.ComposerFrom. + Replace + ```go + attrs, err := dst.ComposeFrom(ctx, []*storage.ObjectHandle{src1, src2}, nil) + ``` + with + ```go + attrs, err := dst.ComposerFrom(src1, src2).Run(ctx) + ``` + +* ObjectHandle.Update's ObjectAttrs argument replaced by ObjectAttrsToUpdate. + Replace + ```go + attrs, err := obj.Update(ctx, &storage.ObjectAttrs{ContextType: "text/html"}) + ``` + with + ```go + attrs, err := obj.Update(ctx, storage.ObjectAttrsToUpdate{ContextType: "text/html"}) + ``` + +* ObjectHandle.WithConditions replaced by ObjectHandle.If. + Replace + ```go + obj.WithConditions(storage.Generation(gen), storage.IfMetaGenerationMatch(mgen)) + ``` + with + ```go + obj.Generation(gen).If(storage.Conditions{MetagenerationMatch: mgen}) + ``` + + Replace + ```go + obj.WithConditions(storage.IfGenerationMatch(0)) + ``` + with + ```go + obj.If(storage.Conditions{DoesNotExist: true}) + ``` + +* `storage.Done` replaced by `iterator.Done` (from package `google.golang.org/api/iterator`). + +_October 6, 2016_ + +Package preview/logging deleted. Use logging instead. + +_September 27, 2016_ + +Logging client replaced with preview version (see below). + +_September 8, 2016_ + +* New clients for some of Google's Machine Learning APIs: Vision, Speech, and +Natural Language. + +* Preview version of a new [Stackdriver Logging][cloud-logging] client in +[`cloud.google.com/go/preview/logging`](https://godoc.org/cloud.google.com/go/preview/logging). +This client uses gRPC as its transport layer, and supports log reading, sinks +and metrics. It will replace the current client at `cloud.google.com/go/logging` shortly. + diff --git a/vendor/cloud.google.com/go/oslogin/apiv1/doc.go b/vendor/cloud.google.com/go/oslogin/apiv1/doc.go new file mode 100644 index 00000000..0e4e2f9a --- /dev/null +++ b/vendor/cloud.google.com/go/oslogin/apiv1/doc.go @@ -0,0 +1,92 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package oslogin is an auto-generated package for the +// Google Cloud OS Login API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Manages OS login configuration for Google account users. +package oslogin // import "cloud.google.com/go/oslogin/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/cloud-platform.read-only", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/oslogin/apiv1/mock_test.go b/vendor/cloud.google.com/go/oslogin/apiv1/mock_test.go new file mode 100644 index 00000000..705fa48e --- /dev/null +++ b/vendor/cloud.google.com/go/oslogin/apiv1/mock_test.go @@ -0,0 +1,520 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package oslogin + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + commonpb "google.golang.org/genproto/googleapis/cloud/oslogin/common" + osloginpb "google.golang.org/genproto/googleapis/cloud/oslogin/v1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockOsLoginServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + osloginpb.OsLoginServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockOsLoginServer) DeletePosixAccount(ctx context.Context, req *osloginpb.DeletePosixAccountRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockOsLoginServer) DeleteSshPublicKey(ctx context.Context, req *osloginpb.DeleteSshPublicKeyRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockOsLoginServer) GetLoginProfile(ctx context.Context, req *osloginpb.GetLoginProfileRequest) (*osloginpb.LoginProfile, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*osloginpb.LoginProfile), nil +} + +func (s *mockOsLoginServer) GetSshPublicKey(ctx context.Context, req *osloginpb.GetSshPublicKeyRequest) (*commonpb.SshPublicKey, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*commonpb.SshPublicKey), nil +} + +func (s *mockOsLoginServer) ImportSshPublicKey(ctx context.Context, req *osloginpb.ImportSshPublicKeyRequest) (*osloginpb.ImportSshPublicKeyResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*osloginpb.ImportSshPublicKeyResponse), nil +} + +func (s *mockOsLoginServer) UpdateSshPublicKey(ctx context.Context, req *osloginpb.UpdateSshPublicKeyRequest) (*commonpb.SshPublicKey, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*commonpb.SshPublicKey), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockOsLogin mockOsLoginServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + osloginpb.RegisterOsLoginServiceServer(serv, &mockOsLogin) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestOsLoginServiceDeletePosixAccount(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockOsLogin.err = nil + mockOsLogin.reqs = nil + + mockOsLogin.resps = append(mockOsLogin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("users/%s/projects/%s", "[USER]", "[PROJECT]") + var request = &osloginpb.DeletePosixAccountRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeletePosixAccount(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOsLogin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestOsLoginServiceDeletePosixAccountError(t *testing.T) { + errCode := codes.PermissionDenied + mockOsLogin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("users/%s/projects/%s", "[USER]", "[PROJECT]") + var request = &osloginpb.DeletePosixAccountRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeletePosixAccount(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestOsLoginServiceDeleteSshPublicKey(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockOsLogin.err = nil + mockOsLogin.reqs = nil + + mockOsLogin.resps = append(mockOsLogin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("users/%s/sshPublicKeys/%s", "[USER]", "[FINGERPRINT]") + var request = &osloginpb.DeleteSshPublicKeyRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSshPublicKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOsLogin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestOsLoginServiceDeleteSshPublicKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockOsLogin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("users/%s/sshPublicKeys/%s", "[USER]", "[FINGERPRINT]") + var request = &osloginpb.DeleteSshPublicKeyRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSshPublicKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestOsLoginServiceGetLoginProfile(t *testing.T) { + var name2 string = "name2-1052831874" + var suspended bool = false + var expectedResponse = &osloginpb.LoginProfile{ + Name: name2, + Suspended: suspended, + } + + mockOsLogin.err = nil + mockOsLogin.reqs = nil + + mockOsLogin.resps = append(mockOsLogin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("users/%s", "[USER]") + var request = &osloginpb.GetLoginProfileRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetLoginProfile(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOsLogin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestOsLoginServiceGetLoginProfileError(t *testing.T) { + errCode := codes.PermissionDenied + mockOsLogin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("users/%s", "[USER]") + var request = &osloginpb.GetLoginProfileRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetLoginProfile(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestOsLoginServiceGetSshPublicKey(t *testing.T) { + var key string = "key106079" + var expirationTimeUsec int64 = 2058878882 + var fingerprint string = "fingerprint-1375934236" + var expectedResponse = &commonpb.SshPublicKey{ + Key: key, + ExpirationTimeUsec: expirationTimeUsec, + Fingerprint: fingerprint, + } + + mockOsLogin.err = nil + mockOsLogin.reqs = nil + + mockOsLogin.resps = append(mockOsLogin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("users/%s/sshPublicKeys/%s", "[USER]", "[FINGERPRINT]") + var request = &osloginpb.GetSshPublicKeyRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSshPublicKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOsLogin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestOsLoginServiceGetSshPublicKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockOsLogin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("users/%s/sshPublicKeys/%s", "[USER]", "[FINGERPRINT]") + var request = &osloginpb.GetSshPublicKeyRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSshPublicKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestOsLoginServiceImportSshPublicKey(t *testing.T) { + var expectedResponse *osloginpb.ImportSshPublicKeyResponse = &osloginpb.ImportSshPublicKeyResponse{} + + mockOsLogin.err = nil + mockOsLogin.reqs = nil + + mockOsLogin.resps = append(mockOsLogin.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("users/%s", "[USER]") + var sshPublicKey *commonpb.SshPublicKey = &commonpb.SshPublicKey{} + var request = &osloginpb.ImportSshPublicKeyRequest{ + Parent: formattedParent, + SshPublicKey: sshPublicKey, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ImportSshPublicKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOsLogin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestOsLoginServiceImportSshPublicKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockOsLogin.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("users/%s", "[USER]") + var sshPublicKey *commonpb.SshPublicKey = &commonpb.SshPublicKey{} + var request = &osloginpb.ImportSshPublicKeyRequest{ + Parent: formattedParent, + SshPublicKey: sshPublicKey, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ImportSshPublicKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestOsLoginServiceUpdateSshPublicKey(t *testing.T) { + var key string = "key106079" + var expirationTimeUsec int64 = 2058878882 + var fingerprint string = "fingerprint-1375934236" + var expectedResponse = &commonpb.SshPublicKey{ + Key: key, + ExpirationTimeUsec: expirationTimeUsec, + Fingerprint: fingerprint, + } + + mockOsLogin.err = nil + mockOsLogin.reqs = nil + + mockOsLogin.resps = append(mockOsLogin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("users/%s/sshPublicKeys/%s", "[USER]", "[FINGERPRINT]") + var sshPublicKey *commonpb.SshPublicKey = &commonpb.SshPublicKey{} + var request = &osloginpb.UpdateSshPublicKeyRequest{ + Name: formattedName, + SshPublicKey: sshPublicKey, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSshPublicKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOsLogin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestOsLoginServiceUpdateSshPublicKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockOsLogin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("users/%s/sshPublicKeys/%s", "[USER]", "[FINGERPRINT]") + var sshPublicKey *commonpb.SshPublicKey = &commonpb.SshPublicKey{} + var request = &osloginpb.UpdateSshPublicKeyRequest{ + Name: formattedName, + SshPublicKey: sshPublicKey, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSshPublicKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/oslogin/apiv1/os_login_client.go b/vendor/cloud.google.com/go/oslogin/apiv1/os_login_client.go new file mode 100644 index 00000000..ee0a09c2 --- /dev/null +++ b/vendor/cloud.google.com/go/oslogin/apiv1/os_login_client.go @@ -0,0 +1,223 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package oslogin + +import ( + "context" + "time" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + commonpb "google.golang.org/genproto/googleapis/cloud/oslogin/common" + osloginpb "google.golang.org/genproto/googleapis/cloud/oslogin/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + DeletePosixAccount []gax.CallOption + DeleteSshPublicKey []gax.CallOption + GetLoginProfile []gax.CallOption + GetSshPublicKey []gax.CallOption + ImportSshPublicKey []gax.CallOption + UpdateSshPublicKey []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("oslogin.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + DeletePosixAccount: retry[[2]string{"default", "idempotent"}], + DeleteSshPublicKey: retry[[2]string{"default", "idempotent"}], + GetLoginProfile: retry[[2]string{"default", "idempotent"}], + GetSshPublicKey: retry[[2]string{"default", "idempotent"}], + ImportSshPublicKey: retry[[2]string{"default", "idempotent"}], + UpdateSshPublicKey: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Google Cloud OS Login API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client osloginpb.OsLoginServiceClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new os login service client. +// +// Cloud OS Login API +// +// The Cloud OS Login API allows you to manage users and their associated SSH +// public keys for logging into virtual machines on Google Cloud Platform. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: osloginpb.NewOsLoginServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// DeletePosixAccount deletes a POSIX account. +func (c *Client) DeletePosixAccount(ctx context.Context, req *osloginpb.DeletePosixAccountRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeletePosixAccount[0:len(c.CallOptions.DeletePosixAccount):len(c.CallOptions.DeletePosixAccount)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeletePosixAccount(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// DeleteSshPublicKey deletes an SSH public key. +func (c *Client) DeleteSshPublicKey(ctx context.Context, req *osloginpb.DeleteSshPublicKeyRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteSshPublicKey[0:len(c.CallOptions.DeleteSshPublicKey):len(c.CallOptions.DeleteSshPublicKey)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteSshPublicKey(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// GetLoginProfile retrieves the profile information used for logging in to a virtual machine +// on Google Compute Engine. +func (c *Client) GetLoginProfile(ctx context.Context, req *osloginpb.GetLoginProfileRequest, opts ...gax.CallOption) (*osloginpb.LoginProfile, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetLoginProfile[0:len(c.CallOptions.GetLoginProfile):len(c.CallOptions.GetLoginProfile)], opts...) + var resp *osloginpb.LoginProfile + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetLoginProfile(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetSshPublicKey retrieves an SSH public key. +func (c *Client) GetSshPublicKey(ctx context.Context, req *osloginpb.GetSshPublicKeyRequest, opts ...gax.CallOption) (*commonpb.SshPublicKey, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetSshPublicKey[0:len(c.CallOptions.GetSshPublicKey):len(c.CallOptions.GetSshPublicKey)], opts...) + var resp *commonpb.SshPublicKey + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetSshPublicKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ImportSshPublicKey adds an SSH public key and returns the profile information. Default POSIX +// account information is set when no username and UID exist as part of the +// login profile. +func (c *Client) ImportSshPublicKey(ctx context.Context, req *osloginpb.ImportSshPublicKeyRequest, opts ...gax.CallOption) (*osloginpb.ImportSshPublicKeyResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ImportSshPublicKey[0:len(c.CallOptions.ImportSshPublicKey):len(c.CallOptions.ImportSshPublicKey)], opts...) + var resp *osloginpb.ImportSshPublicKeyResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ImportSshPublicKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateSshPublicKey updates an SSH public key and returns the profile information. This method +// supports patch semantics. +func (c *Client) UpdateSshPublicKey(ctx context.Context, req *osloginpb.UpdateSshPublicKeyRequest, opts ...gax.CallOption) (*commonpb.SshPublicKey, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateSshPublicKey[0:len(c.CallOptions.UpdateSshPublicKey):len(c.CallOptions.UpdateSshPublicKey)], opts...) + var resp *commonpb.SshPublicKey + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateSshPublicKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/oslogin/apiv1/os_login_client_example_test.go b/vendor/cloud.google.com/go/oslogin/apiv1/os_login_client_example_test.go new file mode 100644 index 00000000..86da7f11 --- /dev/null +++ b/vendor/cloud.google.com/go/oslogin/apiv1/os_login_client_example_test.go @@ -0,0 +1,138 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package oslogin_test + +import ( + "context" + + oslogin "cloud.google.com/go/oslogin/apiv1" + osloginpb "google.golang.org/genproto/googleapis/cloud/oslogin/v1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_DeletePosixAccount() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &osloginpb.DeletePosixAccountRequest{ + // TODO: Fill request struct fields. + } + err = c.DeletePosixAccount(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_DeleteSshPublicKey() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &osloginpb.DeleteSshPublicKeyRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteSshPublicKey(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_GetLoginProfile() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &osloginpb.GetLoginProfileRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetLoginProfile(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_GetSshPublicKey() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &osloginpb.GetSshPublicKeyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetSshPublicKey(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ImportSshPublicKey() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &osloginpb.ImportSshPublicKeyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ImportSshPublicKey(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_UpdateSshPublicKey() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &osloginpb.UpdateSshPublicKeyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateSshPublicKey(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/oslogin/apiv1beta/doc.go b/vendor/cloud.google.com/go/oslogin/apiv1beta/doc.go new file mode 100644 index 00000000..fa88aff3 --- /dev/null +++ b/vendor/cloud.google.com/go/oslogin/apiv1beta/doc.go @@ -0,0 +1,92 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package oslogin is an auto-generated package for the +// Google Cloud OS Login API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Manages OS login configuration for Google account users. +package oslogin // import "cloud.google.com/go/oslogin/apiv1beta" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/cloud-platform.read-only", + "https://www.googleapis.com/auth/compute", + "https://www.googleapis.com/auth/compute.readonly", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/oslogin/apiv1beta/mock_test.go b/vendor/cloud.google.com/go/oslogin/apiv1beta/mock_test.go new file mode 100644 index 00000000..e3719293 --- /dev/null +++ b/vendor/cloud.google.com/go/oslogin/apiv1beta/mock_test.go @@ -0,0 +1,520 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package oslogin + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + commonpb "google.golang.org/genproto/googleapis/cloud/oslogin/common" + osloginpb "google.golang.org/genproto/googleapis/cloud/oslogin/v1beta" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockOsLoginServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + osloginpb.OsLoginServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockOsLoginServer) DeletePosixAccount(ctx context.Context, req *osloginpb.DeletePosixAccountRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockOsLoginServer) DeleteSshPublicKey(ctx context.Context, req *osloginpb.DeleteSshPublicKeyRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockOsLoginServer) GetLoginProfile(ctx context.Context, req *osloginpb.GetLoginProfileRequest) (*osloginpb.LoginProfile, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*osloginpb.LoginProfile), nil +} + +func (s *mockOsLoginServer) GetSshPublicKey(ctx context.Context, req *osloginpb.GetSshPublicKeyRequest) (*commonpb.SshPublicKey, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*commonpb.SshPublicKey), nil +} + +func (s *mockOsLoginServer) ImportSshPublicKey(ctx context.Context, req *osloginpb.ImportSshPublicKeyRequest) (*osloginpb.ImportSshPublicKeyResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*osloginpb.ImportSshPublicKeyResponse), nil +} + +func (s *mockOsLoginServer) UpdateSshPublicKey(ctx context.Context, req *osloginpb.UpdateSshPublicKeyRequest) (*commonpb.SshPublicKey, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*commonpb.SshPublicKey), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockOsLogin mockOsLoginServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + osloginpb.RegisterOsLoginServiceServer(serv, &mockOsLogin) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestOsLoginServiceDeletePosixAccount(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockOsLogin.err = nil + mockOsLogin.reqs = nil + + mockOsLogin.resps = append(mockOsLogin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("users/%s/projects/%s", "[USER]", "[PROJECT]") + var request = &osloginpb.DeletePosixAccountRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeletePosixAccount(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOsLogin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestOsLoginServiceDeletePosixAccountError(t *testing.T) { + errCode := codes.PermissionDenied + mockOsLogin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("users/%s/projects/%s", "[USER]", "[PROJECT]") + var request = &osloginpb.DeletePosixAccountRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeletePosixAccount(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestOsLoginServiceDeleteSshPublicKey(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockOsLogin.err = nil + mockOsLogin.reqs = nil + + mockOsLogin.resps = append(mockOsLogin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("users/%s/sshPublicKeys/%s", "[USER]", "[FINGERPRINT]") + var request = &osloginpb.DeleteSshPublicKeyRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSshPublicKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOsLogin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestOsLoginServiceDeleteSshPublicKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockOsLogin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("users/%s/sshPublicKeys/%s", "[USER]", "[FINGERPRINT]") + var request = &osloginpb.DeleteSshPublicKeyRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSshPublicKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestOsLoginServiceGetLoginProfile(t *testing.T) { + var name2 string = "name2-1052831874" + var suspended bool = false + var expectedResponse = &osloginpb.LoginProfile{ + Name: name2, + Suspended: suspended, + } + + mockOsLogin.err = nil + mockOsLogin.reqs = nil + + mockOsLogin.resps = append(mockOsLogin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("users/%s", "[USER]") + var request = &osloginpb.GetLoginProfileRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetLoginProfile(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOsLogin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestOsLoginServiceGetLoginProfileError(t *testing.T) { + errCode := codes.PermissionDenied + mockOsLogin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("users/%s", "[USER]") + var request = &osloginpb.GetLoginProfileRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetLoginProfile(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestOsLoginServiceGetSshPublicKey(t *testing.T) { + var key string = "key106079" + var expirationTimeUsec int64 = 2058878882 + var fingerprint string = "fingerprint-1375934236" + var expectedResponse = &commonpb.SshPublicKey{ + Key: key, + ExpirationTimeUsec: expirationTimeUsec, + Fingerprint: fingerprint, + } + + mockOsLogin.err = nil + mockOsLogin.reqs = nil + + mockOsLogin.resps = append(mockOsLogin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("users/%s/sshPublicKeys/%s", "[USER]", "[FINGERPRINT]") + var request = &osloginpb.GetSshPublicKeyRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSshPublicKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOsLogin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestOsLoginServiceGetSshPublicKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockOsLogin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("users/%s/sshPublicKeys/%s", "[USER]", "[FINGERPRINT]") + var request = &osloginpb.GetSshPublicKeyRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSshPublicKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestOsLoginServiceImportSshPublicKey(t *testing.T) { + var expectedResponse *osloginpb.ImportSshPublicKeyResponse = &osloginpb.ImportSshPublicKeyResponse{} + + mockOsLogin.err = nil + mockOsLogin.reqs = nil + + mockOsLogin.resps = append(mockOsLogin.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("users/%s", "[USER]") + var sshPublicKey *commonpb.SshPublicKey = &commonpb.SshPublicKey{} + var request = &osloginpb.ImportSshPublicKeyRequest{ + Parent: formattedParent, + SshPublicKey: sshPublicKey, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ImportSshPublicKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOsLogin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestOsLoginServiceImportSshPublicKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockOsLogin.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("users/%s", "[USER]") + var sshPublicKey *commonpb.SshPublicKey = &commonpb.SshPublicKey{} + var request = &osloginpb.ImportSshPublicKeyRequest{ + Parent: formattedParent, + SshPublicKey: sshPublicKey, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ImportSshPublicKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestOsLoginServiceUpdateSshPublicKey(t *testing.T) { + var key string = "key106079" + var expirationTimeUsec int64 = 2058878882 + var fingerprint string = "fingerprint-1375934236" + var expectedResponse = &commonpb.SshPublicKey{ + Key: key, + ExpirationTimeUsec: expirationTimeUsec, + Fingerprint: fingerprint, + } + + mockOsLogin.err = nil + mockOsLogin.reqs = nil + + mockOsLogin.resps = append(mockOsLogin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("users/%s/sshPublicKeys/%s", "[USER]", "[FINGERPRINT]") + var sshPublicKey *commonpb.SshPublicKey = &commonpb.SshPublicKey{} + var request = &osloginpb.UpdateSshPublicKeyRequest{ + Name: formattedName, + SshPublicKey: sshPublicKey, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSshPublicKey(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockOsLogin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestOsLoginServiceUpdateSshPublicKeyError(t *testing.T) { + errCode := codes.PermissionDenied + mockOsLogin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("users/%s/sshPublicKeys/%s", "[USER]", "[FINGERPRINT]") + var sshPublicKey *commonpb.SshPublicKey = &commonpb.SshPublicKey{} + var request = &osloginpb.UpdateSshPublicKeyRequest{ + Name: formattedName, + SshPublicKey: sshPublicKey, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSshPublicKey(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/oslogin/apiv1beta/os_login_client.go b/vendor/cloud.google.com/go/oslogin/apiv1beta/os_login_client.go new file mode 100644 index 00000000..78a7be00 --- /dev/null +++ b/vendor/cloud.google.com/go/oslogin/apiv1beta/os_login_client.go @@ -0,0 +1,223 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package oslogin + +import ( + "context" + "time" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + commonpb "google.golang.org/genproto/googleapis/cloud/oslogin/common" + osloginpb "google.golang.org/genproto/googleapis/cloud/oslogin/v1beta" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + DeletePosixAccount []gax.CallOption + DeleteSshPublicKey []gax.CallOption + GetLoginProfile []gax.CallOption + GetSshPublicKey []gax.CallOption + ImportSshPublicKey []gax.CallOption + UpdateSshPublicKey []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("oslogin.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + DeletePosixAccount: retry[[2]string{"default", "idempotent"}], + DeleteSshPublicKey: retry[[2]string{"default", "idempotent"}], + GetLoginProfile: retry[[2]string{"default", "idempotent"}], + GetSshPublicKey: retry[[2]string{"default", "idempotent"}], + ImportSshPublicKey: retry[[2]string{"default", "idempotent"}], + UpdateSshPublicKey: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Google Cloud OS Login API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client osloginpb.OsLoginServiceClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new os login service client. +// +// Cloud OS Login API +// +// The Cloud OS Login API allows you to manage users and their associated SSH +// public keys for logging into virtual machines on Google Cloud Platform. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: osloginpb.NewOsLoginServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// DeletePosixAccount deletes a POSIX account. +func (c *Client) DeletePosixAccount(ctx context.Context, req *osloginpb.DeletePosixAccountRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeletePosixAccount[0:len(c.CallOptions.DeletePosixAccount):len(c.CallOptions.DeletePosixAccount)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeletePosixAccount(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// DeleteSshPublicKey deletes an SSH public key. +func (c *Client) DeleteSshPublicKey(ctx context.Context, req *osloginpb.DeleteSshPublicKeyRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteSshPublicKey[0:len(c.CallOptions.DeleteSshPublicKey):len(c.CallOptions.DeleteSshPublicKey)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteSshPublicKey(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// GetLoginProfile retrieves the profile information used for logging in to a virtual machine +// on Google Compute Engine. +func (c *Client) GetLoginProfile(ctx context.Context, req *osloginpb.GetLoginProfileRequest, opts ...gax.CallOption) (*osloginpb.LoginProfile, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetLoginProfile[0:len(c.CallOptions.GetLoginProfile):len(c.CallOptions.GetLoginProfile)], opts...) + var resp *osloginpb.LoginProfile + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetLoginProfile(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetSshPublicKey retrieves an SSH public key. +func (c *Client) GetSshPublicKey(ctx context.Context, req *osloginpb.GetSshPublicKeyRequest, opts ...gax.CallOption) (*commonpb.SshPublicKey, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetSshPublicKey[0:len(c.CallOptions.GetSshPublicKey):len(c.CallOptions.GetSshPublicKey)], opts...) + var resp *commonpb.SshPublicKey + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetSshPublicKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ImportSshPublicKey adds an SSH public key and returns the profile information. Default POSIX +// account information is set when no username and UID exist as part of the +// login profile. +func (c *Client) ImportSshPublicKey(ctx context.Context, req *osloginpb.ImportSshPublicKeyRequest, opts ...gax.CallOption) (*osloginpb.ImportSshPublicKeyResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ImportSshPublicKey[0:len(c.CallOptions.ImportSshPublicKey):len(c.CallOptions.ImportSshPublicKey)], opts...) + var resp *osloginpb.ImportSshPublicKeyResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ImportSshPublicKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateSshPublicKey updates an SSH public key and returns the profile information. This method +// supports patch semantics. +func (c *Client) UpdateSshPublicKey(ctx context.Context, req *osloginpb.UpdateSshPublicKeyRequest, opts ...gax.CallOption) (*commonpb.SshPublicKey, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateSshPublicKey[0:len(c.CallOptions.UpdateSshPublicKey):len(c.CallOptions.UpdateSshPublicKey)], opts...) + var resp *commonpb.SshPublicKey + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateSshPublicKey(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/oslogin/apiv1beta/os_login_client_example_test.go b/vendor/cloud.google.com/go/oslogin/apiv1beta/os_login_client_example_test.go new file mode 100644 index 00000000..d4851fb6 --- /dev/null +++ b/vendor/cloud.google.com/go/oslogin/apiv1beta/os_login_client_example_test.go @@ -0,0 +1,138 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package oslogin_test + +import ( + "context" + + oslogin "cloud.google.com/go/oslogin/apiv1beta" + osloginpb "google.golang.org/genproto/googleapis/cloud/oslogin/v1beta" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_DeletePosixAccount() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &osloginpb.DeletePosixAccountRequest{ + // TODO: Fill request struct fields. + } + err = c.DeletePosixAccount(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_DeleteSshPublicKey() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &osloginpb.DeleteSshPublicKeyRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteSshPublicKey(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_GetLoginProfile() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &osloginpb.GetLoginProfileRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetLoginProfile(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_GetSshPublicKey() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &osloginpb.GetSshPublicKeyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetSshPublicKey(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ImportSshPublicKey() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &osloginpb.ImportSshPublicKeyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ImportSshPublicKey(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_UpdateSshPublicKey() { + ctx := context.Background() + c, err := oslogin.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &osloginpb.UpdateSshPublicKeyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateSshPublicKey(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/profiler/busybench/busybench.go b/vendor/cloud.google.com/go/profiler/busybench/busybench.go new file mode 100644 index 00000000..d99e6f5c --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/busybench/busybench.go @@ -0,0 +1,101 @@ +// Copyright 2017 Google LLC +// +// 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. + +// Busybench is a tool that runs a benchmark with the profiler enabled. +package main + +import ( + "bytes" + "compress/gzip" + "flag" + "log" + "math/rand" + "sync" + "time" + + "cloud.google.com/go/profiler" +) + +var ( + service = flag.String("service", "", "service name") + mutexProfiling = flag.Bool("mutex_profiling", false, "enable mutex profiling") + duration = flag.Int("duration", 600, "duration of the benchmark in seconds") + apiAddr = flag.String("api_address", "", "API address of the profiler (e.g. 'cloudprofiler.googleapis.com:443')") + projectID = flag.String("project_id", "", "cloud project ID") +) + +// busywork continuously generates 1MiB of random data and compresses it +// throwing away the result. +func busywork(mu *sync.Mutex) { + ticker := time.NewTicker(time.Duration(*duration) * time.Second) + defer ticker.Stop() + for { + select { + case <-ticker.C: + return + default: + mu.Lock() + busyworkOnce() + mu.Unlock() + } + } +} + +func busyworkOnce() { + data := make([]byte, 1024*1024) + rand.Read(data) + + var b bytes.Buffer + gz := gzip.NewWriter(&b) + if _, err := gz.Write(data); err != nil { + log.Printf("Failed to write to gzip stream: %v", err) + return + } + if err := gz.Flush(); err != nil { + log.Printf("Failed to flush to gzip stream: %v", err) + return + } + if err := gz.Close(); err != nil { + log.Printf("Failed to close gzip stream: %v", err) + } + // Throw away the result. +} + +func main() { + flag.Parse() + defer log.Printf("busybench finished profiling.") + + if *service == "" { + log.Print("Service name must be configured using --service flag.") + return + } + if err := profiler.Start(profiler.Config{Service: *service, + MutexProfiling: *mutexProfiling, + DebugLogging: true, + APIAddr: *apiAddr, + ProjectID: *projectID}); err != nil { + log.Printf("Failed to start the profiler: %v", err) + return + } + mu := new(sync.Mutex) + var wg sync.WaitGroup + wg.Add(5) + for i := 0; i < 5; i++ { + go func() { + defer wg.Done() + busywork(mu) + }() + } + wg.Wait() +} diff --git a/vendor/cloud.google.com/go/profiler/heap.go b/vendor/cloud.google.com/go/profiler/heap.go new file mode 100644 index 00000000..704e72e1 --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/heap.go @@ -0,0 +1,116 @@ +// Copyright 2018 Google LLC +// +// 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 profiler + +import ( + "bytes" + "context" + "fmt" + "runtime" + "time" + + "github.com/google/pprof/profile" +) + +// heapProfile collects an in-use heap profile. The heap profiles returned by +// the runtime also include the heap allocation metrics. We zero those out +// since all allocations since program start are recorded, so these make the +// profile large and there is a separate alloc profile type which shows +// allocations from a set duration. +func heapProfile(prof *bytes.Buffer) error { + p, err := goHeapProfile() + if err != nil { + return err + } + for _, s := range p.Sample { + s.Value[0] = 0 + s.Value[1] = 0 + } + + // Merge profile with itself to remove samples with only zero values and + // reduce profile size. + p, err = profile.Merge([]*profile.Profile{p}) + if err != nil { + return err + } + return p.Write(prof) +} + +// deltaAllocProfile collects an allocation profile by gathering a heap profile, +// sleeping for the specified duration, gathering another heap profile and +// subtracting the initial one from that. It then drops the in-use metrics from +// the profile. If requested, it forces the GC before taking each of the heap +// profiles, which improves the profile accuracy (see docs in +// https://golang.org/src/runtime/mprof.go on why). +func deltaAllocProfile(ctx context.Context, duration time.Duration, forceGC bool, prof *bytes.Buffer) error { + p1, err := allocProfile(forceGC) + if err != nil { + return err + } + + sleep(ctx, duration) + + p2, err := allocProfile(forceGC) + if err != nil { + return err + } + + p1.Scale(-1) + p, err := profile.Merge([]*profile.Profile{p1, p2}) + if err != nil { + return err + } + p.DurationNanos = duration.Nanoseconds() + return p.Write(prof) +} + +// allocProfile collects a single heap profile, and removes all metrics but +// allocation metrics. +func allocProfile(forceGC bool) (*profile.Profile, error) { + if forceGC { + runtime.GC() + } + p, err := goHeapProfile() + if err != nil { + return nil, err + } + p.SampleType = p.SampleType[:2] + for _, s := range p.Sample { + s.Value = s.Value[:2] + } + return p, nil +} + +// goHeapProfile collects a heap profile. It returns an error if the metrics +// in the collected heap profile do not match the expected metrics. +func goHeapProfile() (*profile.Profile, error) { + var prof bytes.Buffer + if err := writeHeapProfile(&prof); err != nil { + return nil, fmt.Errorf("failed to write heap profile: %v", err) + } + p, err := profile.Parse(&prof) + if err != nil { + return nil, err + } + if got := len(p.SampleType); got != 4 { + return nil, fmt.Errorf("invalid heap profile: got %d sample types, want 4", got) + } + for i, want := range []string{"alloc_objects", "alloc_space", "inuse_objects", "inuse_space"} { + if got := p.SampleType[i].Type; got != want { + return nil, fmt.Errorf("invalid heap profile: got %q sample type at index %d, want %q", got, i, want) + } + } + return p, nil +} diff --git a/vendor/cloud.google.com/go/profiler/heap_test.go b/vendor/cloud.google.com/go/profiler/heap_test.go new file mode 100644 index 00000000..e6db51ef --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/heap_test.go @@ -0,0 +1,79 @@ +// Copyright 2018 Google LLC +// +// 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 profiler + +import ( + "bytes" + "io" + "testing" + + "cloud.google.com/go/profiler/testdata" + "github.com/google/pprof/profile" +) + +func TestGoHeapProfile(t *testing.T) { + oldStartCPUProfile, oldStopCPUProfile, oldWriteHeapProfile, oldSleep := startCPUProfile, stopCPUProfile, writeHeapProfile, sleep + defer func() { + startCPUProfile, stopCPUProfile, writeHeapProfile, sleep = oldStartCPUProfile, oldStopCPUProfile, oldWriteHeapProfile, oldSleep + }() + + tests := []struct { + name string + profile *profile.Profile + wantErr bool + }{ + { + name: "valid heap profile", + profile: testdata.HeapProfileCollected1, + }, + { + name: "profile with too few sample types", + profile: testdata.AllocProfileUploaded, + wantErr: true, + }, + { + name: "profile with incorrect sample types", + profile: &profile.Profile{ + DurationNanos: 10e9, + SampleType: []*profile.ValueType{ + {Type: "objects", Unit: "count"}, + {Type: "alloc_space", Unit: "bytes"}, + {Type: "inuse_objects", Unit: "count"}, + {Type: "inuse_space", Unit: "bytes"}, + }, + }, + wantErr: true, + }, + } + + for _, tc := range tests { + var profileBytes bytes.Buffer + tc.profile.Write(&profileBytes) + writeHeapProfile = func(w io.Writer) error { + w.Write(profileBytes.Bytes()) + return nil + } + _, err := goHeapProfile() + if tc.wantErr { + if err == nil { + t.Errorf("%s: goHeapProfile() got no error, want error", tc.name) + } + continue + } + if err != nil { + t.Errorf("%s: goHeapProfile() got %q, want no error", tc.name, err) + } + } +} diff --git a/vendor/cloud.google.com/go/profiler/integration-test.sh b/vendor/cloud.google.com/go/profiler/integration-test.sh new file mode 100644 index 00000000..bb29f111 --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/integration-test.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +retry() { + for i in {1..3}; do + "${@}" && return 0 + done + return 1 +} + +# Fail on any error. +set -eo pipefail + +# Display commands being run. +set -x + +cd git/gocloud +COMMIT=$(git rev-parse HEAD) + +# Set $GOPATH +export GOPATH="$HOME/go" +GOCLOUD_HOME=$GOPATH/src/cloud.google.com/go +mkdir -p $GOCLOUD_HOME + +# Move code into $GOPATH and get dependencies +cp -R ./* $GOCLOUD_HOME +cd $GOCLOUD_HOME/internal/kokoro +# Don't print out encryption keys, etc +set +x +key=$(cat "$KOKORO_ARTIFACTS_DIR/keystore/72523_encrypted_ba2d6f7723ed_key") +iv=$(cat "$KOKORO_ARTIFACTS_DIR/keystore/72523_encrypted_ba2d6f7723ed_iv") +pass=$(cat "$KOKORO_ARTIFACTS_DIR/keystore/72523_encrypted_ba2d6f7723ed_pass") + +openssl aes-256-cbc -K $key -iv $iv -pass pass:$pass -in kokoro-key.json.enc -out key.json -d +set -x + +export GOOGLE_APPLICATION_CREDENTIALS="$(pwd)/key.json" +export GCLOUD_TESTS_GOLANG_PROJECT_ID="dulcet-port-762" +export GCLOUD_TESTS_GOLANG_ZONE="us-west1-b" +export GCLOUD_TESTS_GOLANG_BUCKET="dulcet-port-762-go-cloud-profiler-test" + +cd $GOCLOUD_HOME/profiler +retry go get -t -tags=integration . +go test -timeout=60m -tags=integration -run TestAgentIntegration -commit="$COMMIT" diff --git a/vendor/cloud.google.com/go/profiler/integration_test.go b/vendor/cloud.google.com/go/profiler/integration_test.go new file mode 100644 index 00000000..8f1ea35f --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/integration_test.go @@ -0,0 +1,294 @@ +// Copyright 2017 Google LLC +// +// 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. + +// +build integration,go1.7 + +package profiler + +import ( + "bytes" + "context" + "flag" + "fmt" + "os" + "runtime" + "strings" + "testing" + "text/template" + "time" + + "cloud.google.com/go/profiler/proftest" + "golang.org/x/oauth2/google" + compute "google.golang.org/api/compute/v1" +) + +var ( + commit = flag.String("commit", "", "git commit to test") + runID = strings.Replace(time.Now().Format("2006-01-02-15-04-05.000000-0700"), ".", "-", -1) +) + +const ( + cloudScope = "https://www.googleapis.com/auth/cloud-platform" + benchFinishString = "busybench finished profiling" + errorString = "failed to set up or run the benchmark" +) + +const startupTemplate = ` +#! /bin/bash + +# Signal any unexpected error. +trap 'echo "{{.ErrorString}}"' ERR + +( +# Shut down the VM in 5 minutes after this script exits +# to stop accounting the VM for billing and cores quota. +trap "sleep 300 && poweroff" EXIT + +retry() { + for i in {1..3}; do + "${@}" && return 0 + done + return 1 +} + +# Fail on any error. +set -eo pipefail + +# Display commands being run. +set -x + +# Install git +retry apt-get update >/dev/null +retry apt-get -y -q install git >/dev/null + +# Install desired Go version +mkdir -p /tmp/bin +retry curl -sL -o /tmp/bin/gimme https://raw.githubusercontent.com/travis-ci/gimme/master/gimme +chmod +x /tmp/bin/gimme +export PATH=$PATH:/tmp/bin + +retry eval "$(gimme {{.GoVersion}})" + +# Set $GOPATH +export GOPATH="$HOME/go" + +export GOCLOUD_HOME=$GOPATH/src/cloud.google.com/go +mkdir -p $GOCLOUD_HOME + +# Install agent +retry git clone https://code.googlesource.com/gocloud $GOCLOUD_HOME >/dev/null + +cd $GOCLOUD_HOME/profiler/busybench +git reset --hard {{.Commit}} +retry go get >/dev/null + +# Run benchmark with agent +go run busybench.go --service="{{.Service}}" --mutex_profiling="{{.MutexProfiling}}" + +# Write output to serial port 2 with timestamp. +) 2>&1 | while read line; do echo "$(date): ${line}"; done >/dev/ttyS1 +` + +const dockerfileFmt = `FROM golang +RUN git clone https://code.googlesource.com/gocloud /go/src/cloud.google.com/go \ + && cd /go/src/cloud.google.com/go/profiler/busybench && git reset --hard %s \ + && go get && go install +CMD ["busybench", "--service", "%s"] + ` + +type goGCETestCase struct { + proftest.InstanceConfig + name string + goVersion string + mutexProfiling bool + wantProfileTypes []string +} + +func (tc *goGCETestCase) initializeStartupScript(template *template.Template) error { + var buf bytes.Buffer + err := template.Execute(&buf, + struct { + Service string + GoVersion string + Commit string + ErrorString string + MutexProfiling bool + }{ + Service: tc.name, + GoVersion: tc.goVersion, + Commit: *commit, + ErrorString: errorString, + MutexProfiling: tc.mutexProfiling, + }) + if err != nil { + return fmt.Errorf("failed to render startup script for %s: %v", tc.name, err) + } + tc.StartupScript = buf.String() + return nil +} + +func TestAgentIntegration(t *testing.T) { + projectID := os.Getenv("GCLOUD_TESTS_GOLANG_PROJECT_ID") + if projectID == "" { + t.Fatalf("Getenv(GCLOUD_TESTS_GOLANG_PROJECT_ID) got empty string") + } + + zone := os.Getenv("GCLOUD_TESTS_GOLANG_ZONE") + if zone == "" { + t.Fatalf("Getenv(GCLOUD_TESTS_GOLANG_ZONE) got empty string") + } + + if *commit == "" { + t.Fatal("commit flag is not set") + } + + ctx := context.Background() + + client, err := google.DefaultClient(ctx, cloudScope) + if err != nil { + t.Fatalf("failed to get default client: %v", err) + } + + computeService, err := compute.New(client) + if err != nil { + t.Fatalf("failed to initialize compute service: %v", err) + } + + template, err := template.New("startupScript").Parse(startupTemplate) + if err != nil { + t.Fatalf("failed to parse startup script template: %v", err) + } + + tr := proftest.TestRunner{ + Client: client, + } + + gceTr := proftest.GCETestRunner{ + TestRunner: tr, + ComputeService: computeService, + } + + testcases := []goGCETestCase{ + { + InstanceConfig: proftest.InstanceConfig{ + ProjectID: projectID, + Zone: zone, + Name: fmt.Sprintf("profiler-test-go111-%s", runID), + MachineType: "n1-standard-1", + }, + name: fmt.Sprintf("profiler-test-go111-%s-gce", runID), + wantProfileTypes: []string{"CPU", "HEAP", "THREADS", "CONTENTION", "HEAP_ALLOC"}, + goVersion: "1.11", + mutexProfiling: true, + }, + { + InstanceConfig: proftest.InstanceConfig{ + ProjectID: projectID, + Zone: zone, + Name: fmt.Sprintf("profiler-test-go110-%s", runID), + MachineType: "n1-standard-1", + }, + name: fmt.Sprintf("profiler-test-go110-%s-gce", runID), + wantProfileTypes: []string{"CPU", "HEAP", "THREADS", "CONTENTION", "HEAP_ALLOC"}, + goVersion: "1.10", + mutexProfiling: true, + }, + { + InstanceConfig: proftest.InstanceConfig{ + ProjectID: projectID, + Zone: zone, + Name: fmt.Sprintf("profiler-test-go19-%s", runID), + MachineType: "n1-standard-1", + }, + name: fmt.Sprintf("profiler-test-go19-%s-gce", runID), + wantProfileTypes: []string{"CPU", "HEAP", "THREADS", "CONTENTION", "HEAP_ALLOC"}, + goVersion: "1.9", + mutexProfiling: true, + }, + { + InstanceConfig: proftest.InstanceConfig{ + ProjectID: projectID, + Zone: zone, + Name: fmt.Sprintf("profiler-test-go18-%s", runID), + MachineType: "n1-standard-1", + }, + name: fmt.Sprintf("profiler-test-go18-%s-gce", runID), + wantProfileTypes: []string{"CPU", "HEAP", "THREADS", "CONTENTION", "HEAP_ALLOC"}, + goVersion: "1.8", + mutexProfiling: true, + }, + { + InstanceConfig: proftest.InstanceConfig{ + ProjectID: projectID, + Zone: zone, + Name: fmt.Sprintf("profiler-test-go17-%s", runID), + MachineType: "n1-standard-1", + }, + name: fmt.Sprintf("profiler-test-go17-%s-gce", runID), + wantProfileTypes: []string{"CPU", "HEAP", "THREADS", "HEAP_ALLOC"}, + goVersion: "1.7", + }, + { + InstanceConfig: proftest.InstanceConfig{ + ProjectID: projectID, + Zone: zone, + Name: fmt.Sprintf("profiler-test-go16-%s", runID), + MachineType: "n1-standard-1", + }, + name: fmt.Sprintf("profiler-test-go16-%s-gce", runID), + wantProfileTypes: []string{"CPU", "HEAP", "THREADS", "HEAP_ALLOC"}, + goVersion: "1.6", + }, + } + // The number of tests run in parallel is the current value of GOMAXPROCS. + runtime.GOMAXPROCS(len(testcases)) + for _, tc := range testcases { + tc := tc // capture range variable + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + if err := tc.initializeStartupScript(template); err != nil { + t.Fatalf("failed to initialize startup script") + } + + if err := gceTr.StartInstance(ctx, &tc.InstanceConfig); err != nil { + t.Fatal(err) + } + defer func() { + if gceTr.DeleteInstance(ctx, &tc.InstanceConfig); err != nil { + t.Fatal(err) + } + }() + + timeoutCtx, cancel := context.WithTimeout(ctx, time.Minute*25) + defer cancel() + if err := gceTr.PollForSerialOutput(timeoutCtx, &tc.InstanceConfig, benchFinishString, errorString); err != nil { + t.Fatalf("PollForSerialOutput() got error: %v", err) + } + + timeNow := time.Now() + endTime := timeNow.Format(time.RFC3339) + startTime := timeNow.Add(-1 * time.Hour).Format(time.RFC3339) + for _, pType := range tc.wantProfileTypes { + pr, err := tr.QueryProfiles(tc.ProjectID, tc.name, startTime, endTime, pType) + if err != nil { + t.Errorf("QueryProfiles(%s, %s, %s, %s, %s) got error: %v", tc.ProjectID, tc.name, startTime, endTime, pType, err) + continue + } + if err := pr.HasFunction("busywork"); err != nil { + t.Error(err) + } + } + }) + } +} diff --git a/vendor/cloud.google.com/go/profiler/mocks/README.md b/vendor/cloud.google.com/go/profiler/mocks/README.md new file mode 100644 index 00000000..50cdd78a --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/mocks/README.md @@ -0,0 +1,14 @@ +This directory contains auto-generated mocks for the ProfilerService interface. + +To regenerate the mocks, install https://github.com/golang/mock tool and run +the command below while in the `mocks` directory. + +``` +mockgen -package mocks google.golang.org/genproto/googleapis/devtools/cloudprofiler/v2 \ + ProfilerServiceClient \ + > mock_profiler_client.go +``` + +Then re-add the copyright header in the file. You also need to either run the +commands above using Golang 1.6 or manually change the "context" import to +"context" to ensure the compatibility with Go 1.6. diff --git a/vendor/cloud.google.com/go/profiler/mocks/mock_profiler_client.go b/vendor/cloud.google.com/go/profiler/mocks/mock_profiler_client.go new file mode 100644 index 00000000..7a8ecf3e --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/mocks/mock_profiler_client.go @@ -0,0 +1,105 @@ +// Copyright 2017 Google LLC +// +// 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. + +// Code generated by MockGen. DO NOT EDIT. +// Source: google.golang.org/genproto/googleapis/devtools/cloudprofiler/v2 (interfaces: ProfilerServiceClient) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + v2 "google.golang.org/genproto/googleapis/devtools/cloudprofiler/v2" + grpc "google.golang.org/grpc" +) + +// MockProfilerServiceClient is a mock of ProfilerServiceClient interface +type MockProfilerServiceClient struct { + ctrl *gomock.Controller + recorder *MockProfilerServiceClientMockRecorder +} + +// MockProfilerServiceClientMockRecorder is the mock recorder for MockProfilerServiceClient +type MockProfilerServiceClientMockRecorder struct { + mock *MockProfilerServiceClient +} + +// NewMockProfilerServiceClient creates a new mock instance +func NewMockProfilerServiceClient(ctrl *gomock.Controller) *MockProfilerServiceClient { + mock := &MockProfilerServiceClient{ctrl: ctrl} + mock.recorder = &MockProfilerServiceClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockProfilerServiceClient) EXPECT() *MockProfilerServiceClientMockRecorder { + return m.recorder +} + +// CreateOfflineProfile mocks base method +func (m *MockProfilerServiceClient) CreateOfflineProfile(arg0 context.Context, arg1 *v2.CreateOfflineProfileRequest, arg2 ...grpc.CallOption) (*v2.Profile, error) { + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateOfflineProfile", varargs...) + ret0, _ := ret[0].(*v2.Profile) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateOfflineProfile indicates an expected call of CreateOfflineProfile +func (mr *MockProfilerServiceClientMockRecorder) CreateOfflineProfile(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOfflineProfile", reflect.TypeOf((*MockProfilerServiceClient)(nil).CreateOfflineProfile), varargs...) +} + +// CreateProfile mocks base method +func (m *MockProfilerServiceClient) CreateProfile(arg0 context.Context, arg1 *v2.CreateProfileRequest, arg2 ...grpc.CallOption) (*v2.Profile, error) { + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateProfile", varargs...) + ret0, _ := ret[0].(*v2.Profile) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateProfile indicates an expected call of CreateProfile +func (mr *MockProfilerServiceClientMockRecorder) CreateProfile(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateProfile", reflect.TypeOf((*MockProfilerServiceClient)(nil).CreateProfile), varargs...) +} + +// UpdateProfile mocks base method +func (m *MockProfilerServiceClient) UpdateProfile(arg0 context.Context, arg1 *v2.UpdateProfileRequest, arg2 ...grpc.CallOption) (*v2.Profile, error) { + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "UpdateProfile", varargs...) + ret0, _ := ret[0].(*v2.Profile) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateProfile indicates an expected call of UpdateProfile +func (mr *MockProfilerServiceClientMockRecorder) UpdateProfile(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateProfile", reflect.TypeOf((*MockProfilerServiceClient)(nil).UpdateProfile), varargs...) +} diff --git a/vendor/cloud.google.com/go/profiler/mutex.go b/vendor/cloud.google.com/go/profiler/mutex.go new file mode 100644 index 00000000..c432adb2 --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/mutex.go @@ -0,0 +1,23 @@ +// Copyright 2017 Google LLC +// +// 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 profiler + +import "runtime" + +func enableMutexProfiling() bool { + // One percent of mutex contention events are profiled. + runtime.SetMutexProfileFraction(100) + return true +} diff --git a/vendor/cloud.google.com/go/profiler/profiler.go b/vendor/cloud.google.com/go/profiler/profiler.go new file mode 100644 index 00000000..40116061 --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/profiler.go @@ -0,0 +1,529 @@ +// Copyright 2017 Google LLC +// +// 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 profiler is a client for the Stackdriver Profiler service. +// +// This package is still experimental and subject to change. +// +// Usage example: +// +// import "cloud.google.com/go/profiler" +// ... +// if err := profiler.Start(profiler.Config{Service: "my-service"}); err != nil { +// // TODO: Handle error. +// } +// +// Calling Start will start a goroutine to collect profiles and upload to +// the profiler server, at the rhythm specified by the server. +// +// The caller must provide the service string in the config, and may provide +// other information as well. See Config for details. +// +// Profiler has CPU, heap and goroutine profiling enabled by default. Mutex +// profiling can be enabled in the config. Note that goroutine and mutex +// profiles are shown as "threads" and "contention" profiles in the profiler +// UI. +package profiler + +import ( + "bytes" + "context" + "errors" + "fmt" + "log" + "os" + "regexp" + "runtime" + "runtime/pprof" + "sync" + "time" + + gcemd "cloud.google.com/go/compute/metadata" + "cloud.google.com/go/internal/version" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "github.com/google/pprof/profile" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + gtransport "google.golang.org/api/transport/grpc" + pb "google.golang.org/genproto/googleapis/devtools/cloudprofiler/v2" + edpb "google.golang.org/genproto/googleapis/rpc/errdetails" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + grpcmd "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +var ( + config Config + startOnce sync.Once + mutexEnabled bool + // The functions below are stubbed to be overrideable for testing. + getProjectID = gcemd.ProjectID + getInstanceName = gcemd.InstanceName + getZone = gcemd.Zone + startCPUProfile = pprof.StartCPUProfile + stopCPUProfile = pprof.StopCPUProfile + writeHeapProfile = pprof.WriteHeapProfile + sleep = gax.Sleep + dialGRPC = gtransport.Dial + onGCE = gcemd.OnGCE + serviceRegexp = regexp.MustCompile(`^[a-z]([-a-z0-9_.]{0,253}[a-z0-9])?$`) +) + +const ( + apiAddress = "cloudprofiler.googleapis.com:443" + xGoogAPIMetadata = "x-goog-api-client" + zoneNameLabel = "zone" + versionLabel = "version" + languageLabel = "language" + instanceLabel = "instance" + scope = "https://www.googleapis.com/auth/monitoring.write" + + initialBackoff = time.Minute + // Ensure the agent will recover within 1 hour. + maxBackoff = time.Hour + backoffMultiplier = 1.3 // Backoff envelope increases by this factor on each retry. + retryInfoMetadata = "google.rpc.retryinfo-bin" +) + +// Config is the profiler configuration. +type Config struct { + // Service must be provided to start the profiler. It specifies the name of + // the service under which the profiled data will be recorded and exposed at + // the Profiler UI for the project. You can specify an arbitrary string, but + // see Deployment.target at + // https://github.com/googleapis/googleapis/blob/master/google/devtools/cloudprofiler/v2/profiler.proto + // for restrictions. If the parameter is not set, the agent will probe + // GAE_SERVICE environment variable which is present in Google App Engine + // environment. + // NOTE: The string should be the same across different replicas of + // your service so that the globally constant profiling rate is + // maintained. Do not put things like PID or unique pod ID in the name. + Service string + + // ServiceVersion is an optional field specifying the version of the + // service. It can be an arbitrary string. Profiler profiles + // once per minute for each version of each service in each zone. + // ServiceVersion defaults to GAE_VERSION environment variable if that is + // set, or to empty string otherwise. + ServiceVersion string + + // DebugLogging enables detailed debug logging from profiler. It + // defaults to false. + DebugLogging bool + + // MutexProfiling enables mutex profiling. It defaults to false. + // Note that mutex profiling is not supported by Go versions older + // than Go 1.8. + MutexProfiling bool + + // When true, collecting the allocation profiles is disabled. + NoAllocProfiling bool + + // AllocForceGC forces garbage collection before the collection of each heap + // profile collected to produce the allocation profile. This increases the + // accuracy of allocation profiling. It defaults to false. + AllocForceGC bool + + // When true, collecting the heap profiles is disabled. + NoHeapProfiling bool + + // When true, collecting the goroutine profiles is disabled. + NoGoroutineProfiling bool + + // ProjectID is the Cloud Console project ID to use instead of the one set by + // GOOGLE_CLOUD_PROJECT environment variable or read from the VM metadata + // server. + // + // Set this if you are running the agent in your local environment + // or anywhere else outside of Google Cloud Platform. + ProjectID string + + // APIAddr is the HTTP endpoint to use to connect to the profiler + // agent API. Defaults to the production environment, overridable + // for testing. + APIAddr string + + instance string + zone string +} + +// startError represents the error occurred during the +// initializating and starting of the agent. +var startError error + +// Start starts a goroutine to collect and upload profiles. The +// caller must provide the service string in the config. See +// Config for details. Start should only be called once. Any +// additional calls will be ignored. +func Start(cfg Config, options ...option.ClientOption) error { + startOnce.Do(func() { + startError = start(cfg, options...) + }) + return startError +} + +func start(cfg Config, options ...option.ClientOption) error { + if err := initializeConfig(cfg); err != nil { + debugLog("failed to initialize config: %v", err) + return err + } + if config.MutexProfiling { + if mutexEnabled = enableMutexProfiling(); !mutexEnabled { + return fmt.Errorf("mutex profiling is not supported by %s, requires Go 1.8 or later", runtime.Version()) + } + } + + ctx := context.Background() + + opts := []option.ClientOption{ + option.WithEndpoint(config.APIAddr), + option.WithScopes(scope), + } + opts = append(opts, options...) + + conn, err := dialGRPC(ctx, opts...) + if err != nil { + debugLog("failed to dial GRPC: %v", err) + return err + } + + a := initializeAgent(pb.NewProfilerServiceClient(conn)) + go pollProfilerService(withXGoogHeader(ctx), a) + return nil +} + +func debugLog(format string, e ...interface{}) { + if config.DebugLogging { + log.Printf(format, e...) + } +} + +// agent polls the profiler server for instructions on behalf of a task, +// and collects and uploads profiles as requested. +type agent struct { + client pb.ProfilerServiceClient + deployment *pb.Deployment + profileLabels map[string]string + profileTypes []pb.ProfileType +} + +// abortedBackoffDuration retrieves the retry duration from gRPC trailing +// metadata, which is set by the profiler server. +func abortedBackoffDuration(md grpcmd.MD) (time.Duration, error) { + elem := md[retryInfoMetadata] + if len(elem) <= 0 { + return 0, errors.New("no retry info") + } + + var retryInfo edpb.RetryInfo + if err := proto.Unmarshal([]byte(elem[0]), &retryInfo); err != nil { + return 0, err + } else if time, err := ptypes.Duration(retryInfo.RetryDelay); err != nil { + return 0, err + } else { + if time < 0 { + return 0, errors.New("negative retry duration") + } + return time, nil + } +} + +type retryer struct { + backoff gax.Backoff + md grpcmd.MD +} + +func (r *retryer) Retry(err error) (time.Duration, bool) { + st, _ := status.FromError(err) + if st != nil && st.Code() == codes.Aborted { + dur, err := abortedBackoffDuration(r.md) + if err == nil { + return dur, true + } + debugLog("failed to get backoff duration: %v", err) + } + return r.backoff.Pause(), true +} + +// createProfile talks to the profiler server to create profile. In +// case of error, the goroutine will sleep and retry. Sleep duration may +// be specified by the server. Otherwise it will be an exponentially +// increasing value, bounded by maxBackoff. +func (a *agent) createProfile(ctx context.Context) *pb.Profile { + req := pb.CreateProfileRequest{ + Deployment: a.deployment, + ProfileType: a.profileTypes, + } + + var p *pb.Profile + md := grpcmd.New(map[string]string{}) + + gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + p, err = a.client.CreateProfile(ctx, &req, grpc.Trailer(&md)) + if err != nil { + debugLog("failed to create a profile, will retry: %v", err) + } + return err + }, gax.WithRetry(func() gax.Retryer { + return &retryer{ + backoff: gax.Backoff{ + Initial: initialBackoff, + Max: maxBackoff, + Multiplier: backoffMultiplier, + }, + md: md, + } + })) + + debugLog("successfully created profile %v", p.GetProfileType()) + return p +} + +func (a *agent) profileAndUpload(ctx context.Context, p *pb.Profile) { + var prof bytes.Buffer + pt := p.GetProfileType() + + switch pt { + case pb.ProfileType_CPU: + duration, err := ptypes.Duration(p.Duration) + if err != nil { + debugLog("failed to get profile duration for CPU profile: %v", err) + return + } + if err := startCPUProfile(&prof); err != nil { + debugLog("failed to start CPU profile: %v", err) + return + } + sleep(ctx, duration) + stopCPUProfile() + case pb.ProfileType_HEAP: + if err := heapProfile(&prof); err != nil { + debugLog("failed to write heap profile: %v", err) + return + } + case pb.ProfileType_HEAP_ALLOC: + duration, err := ptypes.Duration(p.Duration) + if err != nil { + debugLog("failed to get profile duration for allocation profile: %v", err) + return + } + if err := deltaAllocProfile(ctx, duration, config.AllocForceGC, &prof); err != nil { + debugLog("failed to collect allocation profile: %v", err) + return + } + case pb.ProfileType_THREADS: + if err := pprof.Lookup("goroutine").WriteTo(&prof, 0); err != nil { + debugLog("failed to collect goroutine profile: %v", err) + return + } + case pb.ProfileType_CONTENTION: + duration, err := ptypes.Duration(p.Duration) + if err != nil { + debugLog("failed to get profile duration: %v", err) + return + } + if err := deltaMutexProfile(ctx, duration, &prof); err != nil { + debugLog("failed to collect mutex profile: %v", err) + return + } + default: + debugLog("unexpected profile type: %v", pt) + return + } + + // Starting Go 1.9 the profiles are symbolized by runtime/pprof. + // TODO(jianqiaoli): Remove the symbolization code when we decide to + // stop supporting Go 1.8. + if !shouldAssumeSymbolized && pt != pb.ProfileType_CONTENTION { + if err := parseAndSymbolize(&prof); err != nil { + debugLog("failed to symbolize profile: %v", err) + } + } + + p.ProfileBytes = prof.Bytes() + p.Labels = a.profileLabels + req := pb.UpdateProfileRequest{Profile: p} + + // Upload profile, discard profile in case of error. + debugLog("start uploading profile") + if _, err := a.client.UpdateProfile(ctx, &req); err != nil { + debugLog("failed to upload profile: %v", err) + } +} + +// deltaMutexProfile writes mutex profile changes over a time period specified +// with 'duration' to 'prof'. +func deltaMutexProfile(ctx context.Context, duration time.Duration, prof *bytes.Buffer) error { + if !mutexEnabled { + return errors.New("mutex profiling is not enabled") + } + p0, err := mutexProfile() + if err != nil { + return err + } + sleep(ctx, duration) + p, err := mutexProfile() + if err != nil { + return err + } + + p0.Scale(-1) + p, err = profile.Merge([]*profile.Profile{p0, p}) + if err != nil { + return err + } + + // The mutex profile is not symbolized by runtime.pprof until + // golang.org/issue/21474 is fixed in go1.10. + symbolize(p) + return p.Write(prof) +} + +func mutexProfile() (*profile.Profile, error) { + p := pprof.Lookup("mutex") + if p == nil { + return nil, errors.New("mutex profiling is not supported") + } + var buf bytes.Buffer + if err := p.WriteTo(&buf, 0); err != nil { + return nil, err + } + return profile.Parse(&buf) +} + +// withXGoogHeader sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func withXGoogHeader(ctx context.Context, keyval ...string) context.Context { + kv := append([]string{"gl-go", version.Go(), "gccl", version.Repo}, keyval...) + kv = append(kv, "gax", gax.Version, "grpc", grpc.Version) + + md, _ := grpcmd.FromOutgoingContext(ctx) + md = md.Copy() + md[xGoogAPIMetadata] = []string{gax.XGoogHeader(kv...)} + return grpcmd.NewOutgoingContext(ctx, md) +} + +func initializeAgent(c pb.ProfilerServiceClient) *agent { + labels := map[string]string{languageLabel: "go"} + if config.zone != "" { + labels[zoneNameLabel] = config.zone + } + if config.ServiceVersion != "" { + labels[versionLabel] = config.ServiceVersion + } + d := &pb.Deployment{ + ProjectId: config.ProjectID, + Target: config.Service, + Labels: labels, + } + + profileLabels := map[string]string{} + + if config.instance != "" { + profileLabels[instanceLabel] = config.instance + } + + profileTypes := []pb.ProfileType{pb.ProfileType_CPU} + if !config.NoHeapProfiling { + profileTypes = append(profileTypes, pb.ProfileType_HEAP) + } + if !config.NoGoroutineProfiling { + profileTypes = append(profileTypes, pb.ProfileType_THREADS) + } + if !config.NoAllocProfiling { + profileTypes = append(profileTypes, pb.ProfileType_HEAP_ALLOC) + } + if mutexEnabled { + profileTypes = append(profileTypes, pb.ProfileType_CONTENTION) + } + + return &agent{ + client: c, + deployment: d, + profileLabels: profileLabels, + profileTypes: profileTypes, + } +} + +func initializeConfig(cfg Config) error { + config = cfg + + if config.Service == "" { + config.Service = os.Getenv("GAE_SERVICE") + } + if config.Service == "" { + return errors.New("service name must be configured") + } + if !serviceRegexp.MatchString(config.Service) { + return fmt.Errorf("service name %q does not match regular expression %v", config.Service, serviceRegexp) + } + + if config.ServiceVersion == "" { + config.ServiceVersion = os.Getenv("GAE_VERSION") + } + + if projectID := os.Getenv("GOOGLE_CLOUD_PROJECT"); config.ProjectID == "" && projectID != "" { + // Cloud Shell and App Engine set this environment variable to the project + // ID, so use it if present. In case of App Engine the project ID is also + // available from the GCE metadata server, but by using the environment + // variable saves one request to the metadata server. The environment + // project ID is only used if no project ID is provided in the + // configuration. + config.ProjectID = projectID + } + if onGCE() { + var err error + if config.ProjectID == "" { + if config.ProjectID, err = getProjectID(); err != nil { + return fmt.Errorf("failed to get the project ID from Compute Engine metadata: %v", err) + } + } + + if config.zone, err = getZone(); err != nil { + return fmt.Errorf("failed to get zone from Compute Engine metadata: %v", err) + } + + if config.instance, err = getInstanceName(); err != nil { + if _, ok := err.(gcemd.NotDefinedError); !ok { + return fmt.Errorf("failed to get instance name from Compute Engine metadata: %v", err) + } + debugLog("failed to get instance name from Compute Engine metadata, will use empty name: %v", err) + } + + } else { + if config.ProjectID == "" { + return fmt.Errorf("project ID must be specified in the configuration if running outside of GCP") + } + } + + if config.APIAddr == "" { + config.APIAddr = apiAddress + } + return nil +} + +// pollProfilerService starts an endless loop to poll the profiler +// server for instructions, and collects and uploads profiles as +// requested. +func pollProfilerService(ctx context.Context, a *agent) { + debugLog("profiler has started") + for { + p := a.createProfile(ctx) + a.profileAndUpload(ctx, p) + } +} diff --git a/vendor/cloud.google.com/go/profiler/profiler_example_test.go b/vendor/cloud.google.com/go/profiler/profiler_example_test.go new file mode 100644 index 00000000..c56f1a57 --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/profiler_example_test.go @@ -0,0 +1,25 @@ +// Copyright 2017 Google LLC +// +// 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 profiler_test + +import ( + "cloud.google.com/go/profiler" +) + +func ExampleStart() { + if err := profiler.Start(profiler.Config{Service: "my-service", ServiceVersion: "v1"}); err != nil { + //TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/profiler/profiler_test.go b/vendor/cloud.google.com/go/profiler/profiler_test.go new file mode 100644 index 00000000..6fdad03c --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/profiler_test.go @@ -0,0 +1,883 @@ +// Copyright 2017 Google LLC +// +// 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 profiler + +import ( + "bytes" + "compress/gzip" + "context" + "errors" + "fmt" + "io" + "log" + "math/rand" + "os" + "runtime" + "strings" + "sync" + "testing" + "time" + + gcemd "cloud.google.com/go/compute/metadata" + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/profiler/mocks" + "cloud.google.com/go/profiler/testdata" + "github.com/golang/mock/gomock" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "github.com/google/pprof/profile" + gax "github.com/googleapis/gax-go" + gtransport "google.golang.org/api/transport/grpc" + pb "google.golang.org/genproto/googleapis/devtools/cloudprofiler/v2" + edpb "google.golang.org/genproto/googleapis/rpc/errdetails" + "google.golang.org/grpc/codes" + grpcmd "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +const ( + testProjectID = "test-project-ID" + testInstance = "test-instance" + testZone = "test-zone" + testService = "test-service" + testSvcVersion = "test-service-version" + testProfileDuration = time.Second * 10 + testServerTimeout = time.Second * 15 +) + +func createTestDeployment() *pb.Deployment { + labels := map[string]string{ + zoneNameLabel: testZone, + versionLabel: testSvcVersion, + } + return &pb.Deployment{ + ProjectId: testProjectID, + Target: testService, + Labels: labels, + } +} + +func createTestAgent(psc pb.ProfilerServiceClient) *agent { + return &agent{ + client: psc, + deployment: createTestDeployment(), + profileLabels: map[string]string{instanceLabel: testInstance}, + profileTypes: []pb.ProfileType{pb.ProfileType_CPU, pb.ProfileType_HEAP, pb.ProfileType_THREADS}, + } +} + +func createTrailers(dur time.Duration) map[string]string { + b, _ := proto.Marshal(&edpb.RetryInfo{ + RetryDelay: ptypes.DurationProto(dur), + }) + return map[string]string{ + retryInfoMetadata: string(b), + } +} + +func TestCreateProfile(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + mpc := mocks.NewMockProfilerServiceClient(ctrl) + a := createTestAgent(mpc) + p := &pb.Profile{Name: "test_profile"} + wantRequest := pb.CreateProfileRequest{ + Deployment: a.deployment, + ProfileType: a.profileTypes, + } + + mpc.EXPECT().CreateProfile(ctx, gomock.Eq(&wantRequest), gomock.Any()).Times(1).Return(p, nil) + + gotP := a.createProfile(ctx) + + if !testutil.Equal(gotP, p) { + t.Errorf("CreateProfile() got wrong profile, got %v, want %v", gotP, p) + } +} + +func TestProfileAndUpload(t *testing.T) { + oldStartCPUProfile, oldStopCPUProfile, oldWriteHeapProfile, oldSleep := startCPUProfile, stopCPUProfile, writeHeapProfile, sleep + defer func() { + startCPUProfile, stopCPUProfile, writeHeapProfile, sleep = oldStartCPUProfile, oldStopCPUProfile, oldWriteHeapProfile, oldSleep + }() + + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + var heapCollected1, heapCollected2, heapUploaded, allocUploaded bytes.Buffer + testdata.HeapProfileCollected1.Write(&heapCollected1) + testdata.HeapProfileCollected2.Write(&heapCollected2) + testdata.HeapProfileUploaded.Write(&heapUploaded) + testdata.AllocProfileUploaded.Write(&allocUploaded) + callCount := 0 + writeTwoHeapFunc := func(w io.Writer) error { + callCount++ + if callCount%2 == 1 { + w.Write(heapCollected1.Bytes()) + return nil + } + w.Write(heapCollected2.Bytes()) + return nil + } + + errFunc := func(io.Writer) error { return errors.New("") } + testDuration := time.Second * 5 + tests := []struct { + profileType pb.ProfileType + duration *time.Duration + startCPUProfileFunc func(io.Writer) error + writeHeapProfileFunc func(io.Writer) error + wantBytes []byte + }{ + { + profileType: pb.ProfileType_CPU, + duration: &testDuration, + startCPUProfileFunc: func(w io.Writer) error { + w.Write([]byte{1}) + return nil + }, + writeHeapProfileFunc: errFunc, + wantBytes: []byte{1}, + }, + { + profileType: pb.ProfileType_CPU, + startCPUProfileFunc: errFunc, + writeHeapProfileFunc: errFunc, + }, + { + profileType: pb.ProfileType_CPU, + duration: &testDuration, + startCPUProfileFunc: func(w io.Writer) error { + w.Write([]byte{2}) + return nil + }, + writeHeapProfileFunc: func(w io.Writer) error { + w.Write([]byte{3}) + return nil + }, + wantBytes: []byte{2}, + }, + { + profileType: pb.ProfileType_HEAP, + startCPUProfileFunc: errFunc, + writeHeapProfileFunc: func(w io.Writer) error { + w.Write(heapCollected1.Bytes()) + return nil + }, + wantBytes: heapUploaded.Bytes(), + }, + { + profileType: pb.ProfileType_HEAP_ALLOC, + startCPUProfileFunc: errFunc, + writeHeapProfileFunc: writeTwoHeapFunc, + duration: &testDuration, + wantBytes: allocUploaded.Bytes(), + }, + { + profileType: pb.ProfileType_HEAP, + startCPUProfileFunc: errFunc, + writeHeapProfileFunc: errFunc, + }, + { + profileType: pb.ProfileType_HEAP, + startCPUProfileFunc: func(w io.Writer) error { + w.Write([]byte{5}) + return nil + }, + writeHeapProfileFunc: func(w io.Writer) error { + w.Write(heapCollected1.Bytes()) + return nil + }, + wantBytes: heapUploaded.Bytes(), + }, + { + profileType: pb.ProfileType_PROFILE_TYPE_UNSPECIFIED, + startCPUProfileFunc: func(w io.Writer) error { + w.Write([]byte{7}) + return nil + }, + writeHeapProfileFunc: func(w io.Writer) error { + w.Write(heapCollected1.Bytes()) + return nil + }, + }, + } + + for _, tt := range tests { + mpc := mocks.NewMockProfilerServiceClient(ctrl) + a := createTestAgent(mpc) + startCPUProfile = tt.startCPUProfileFunc + stopCPUProfile = func() {} + writeHeapProfile = tt.writeHeapProfileFunc + var gotSleep *time.Duration + sleep = func(ctx context.Context, d time.Duration) error { + gotSleep = &d + return nil + } + p := &pb.Profile{ProfileType: tt.profileType} + if tt.duration != nil { + p.Duration = ptypes.DurationProto(*tt.duration) + } + if tt.wantBytes != nil { + wantProfile := &pb.Profile{ + ProfileType: p.ProfileType, + Duration: p.Duration, + ProfileBytes: tt.wantBytes, + Labels: a.profileLabels, + } + wantRequest := pb.UpdateProfileRequest{ + Profile: wantProfile, + } + mpc.EXPECT().UpdateProfile(ctx, gomock.Eq(&wantRequest)).Times(1) + } else { + mpc.EXPECT().UpdateProfile(gomock.Any(), gomock.Any()).MaxTimes(0) + } + + a.profileAndUpload(ctx, p) + + if tt.duration == nil { + if gotSleep != nil { + t.Errorf("profileAndUpload(%v) slept for: %v, want no sleep", p, gotSleep) + } + } else { + if gotSleep == nil { + t.Errorf("profileAndUpload(%v) didn't sleep, want sleep for: %v", p, tt.duration) + } else if *gotSleep != *tt.duration { + t.Errorf("profileAndUpload(%v) slept for wrong duration, got: %v, want: %v", p, gotSleep, tt.duration) + } + } + } +} + +func TestRetry(t *testing.T) { + normalDuration := time.Second * 3 + negativeDuration := time.Second * -3 + + tests := []struct { + trailers map[string]string + wantPause *time.Duration + }{ + { + createTrailers(normalDuration), + &normalDuration, + }, + { + createTrailers(negativeDuration), + nil, + }, + { + map[string]string{retryInfoMetadata: "wrong format"}, + nil, + }, + { + map[string]string{}, + nil, + }, + } + + for _, tt := range tests { + md := grpcmd.New(tt.trailers) + r := &retryer{ + backoff: gax.Backoff{ + Initial: initialBackoff, + Max: maxBackoff, + Multiplier: backoffMultiplier, + }, + md: md, + } + + pause, shouldRetry := r.Retry(status.Error(codes.Aborted, "")) + + if !shouldRetry { + t.Error("retryer.Retry() returned shouldRetry false, want true") + } + + if tt.wantPause != nil { + if pause != *tt.wantPause { + t.Errorf("retryer.Retry() returned wrong pause, got: %v, want: %v", pause, tt.wantPause) + } + } else { + if pause > initialBackoff { + t.Errorf("retryer.Retry() returned wrong pause, got: %v, want: < %v", pause, initialBackoff) + } + } + } + + md := grpcmd.New(map[string]string{}) + + r := &retryer{ + backoff: gax.Backoff{ + Initial: initialBackoff, + Max: maxBackoff, + Multiplier: backoffMultiplier, + }, + md: md, + } + for i := 0; i < 100; i++ { + pause, shouldRetry := r.Retry(errors.New("")) + if !shouldRetry { + t.Errorf("retryer.Retry() called %v times, returned shouldRetry false, want true", i) + } + if pause > maxBackoff { + t.Errorf("retryer.Retry() called %v times, returned wrong pause, got: %v, want: < %v", i, pause, maxBackoff) + } + } +} + +func TestWithXGoogHeader(t *testing.T) { + ctx := withXGoogHeader(context.Background()) + md, _ := grpcmd.FromOutgoingContext(ctx) + + if xg := md[xGoogAPIMetadata]; len(xg) == 0 { + t.Errorf("withXGoogHeader() sets empty xGoogHeader") + } else { + if !strings.Contains(xg[0], "gl-go/") { + t.Errorf("withXGoogHeader() got: %v, want gl-go key", xg[0]) + } + if !strings.Contains(xg[0], "gccl/") { + t.Errorf("withXGoogHeader() got: %v, want gccl key", xg[0]) + } + if !strings.Contains(xg[0], "gax/") { + t.Errorf("withXGoogHeader() got: %v, want gax key", xg[0]) + } + if !strings.Contains(xg[0], "grpc/") { + t.Errorf("withXGoogHeader() got: %v, want grpc key", xg[0]) + } + } +} + +func TestInitializeAgent(t *testing.T) { + oldConfig, oldMutexEnabled := config, mutexEnabled + defer func() { + config, mutexEnabled = oldConfig, oldMutexEnabled + }() + + for _, tt := range []struct { + config Config + enableMutex bool + wantProfileTypes []pb.ProfileType + wantDeploymentLabels map[string]string + wantProfileLabels map[string]string + }{ + { + config: Config{ServiceVersion: testSvcVersion, zone: testZone}, + wantProfileTypes: []pb.ProfileType{pb.ProfileType_CPU, pb.ProfileType_HEAP, pb.ProfileType_THREADS, pb.ProfileType_HEAP_ALLOC}, + wantDeploymentLabels: map[string]string{zoneNameLabel: testZone, versionLabel: testSvcVersion, languageLabel: "go"}, + wantProfileLabels: map[string]string{}, + }, + { + config: Config{zone: testZone}, + wantProfileTypes: []pb.ProfileType{pb.ProfileType_CPU, pb.ProfileType_HEAP, pb.ProfileType_THREADS, pb.ProfileType_HEAP_ALLOC}, + wantDeploymentLabels: map[string]string{zoneNameLabel: testZone, languageLabel: "go"}, + wantProfileLabels: map[string]string{}, + }, + { + config: Config{ServiceVersion: testSvcVersion}, + wantProfileTypes: []pb.ProfileType{pb.ProfileType_CPU, pb.ProfileType_HEAP, pb.ProfileType_THREADS, pb.ProfileType_HEAP_ALLOC}, + wantDeploymentLabels: map[string]string{versionLabel: testSvcVersion, languageLabel: "go"}, + wantProfileLabels: map[string]string{}, + }, + { + config: Config{instance: testInstance}, + wantProfileTypes: []pb.ProfileType{pb.ProfileType_CPU, pb.ProfileType_HEAP, pb.ProfileType_THREADS, pb.ProfileType_HEAP_ALLOC}, + wantDeploymentLabels: map[string]string{languageLabel: "go"}, + wantProfileLabels: map[string]string{instanceLabel: testInstance}, + }, + { + config: Config{instance: testInstance}, + enableMutex: true, + wantProfileTypes: []pb.ProfileType{pb.ProfileType_CPU, pb.ProfileType_HEAP, pb.ProfileType_THREADS, pb.ProfileType_HEAP_ALLOC, pb.ProfileType_CONTENTION}, + wantDeploymentLabels: map[string]string{languageLabel: "go"}, + wantProfileLabels: map[string]string{instanceLabel: testInstance}, + }, + { + config: Config{NoHeapProfiling: true}, + wantProfileTypes: []pb.ProfileType{pb.ProfileType_CPU, pb.ProfileType_THREADS, pb.ProfileType_HEAP_ALLOC}, + wantDeploymentLabels: map[string]string{languageLabel: "go"}, + wantProfileLabels: map[string]string{}, + }, + { + config: Config{NoHeapProfiling: true, NoGoroutineProfiling: true, NoAllocProfiling: true}, + wantProfileTypes: []pb.ProfileType{pb.ProfileType_CPU}, + wantDeploymentLabels: map[string]string{languageLabel: "go"}, + wantProfileLabels: map[string]string{}, + }, + } { + + config = tt.config + config.ProjectID = testProjectID + config.Service = testService + mutexEnabled = tt.enableMutex + a := initializeAgent(nil) + + wantDeployment := &pb.Deployment{ + ProjectId: testProjectID, + Target: testService, + Labels: tt.wantDeploymentLabels, + } + if !testutil.Equal(a.deployment, wantDeployment) { + t.Errorf("initializeAgent() got deployment: %v, want %v", a.deployment, wantDeployment) + } + if !testutil.Equal(a.profileLabels, tt.wantProfileLabels) { + t.Errorf("initializeAgent() got profile labels: %v, want %v", a.profileLabels, tt.wantProfileLabels) + } + if !testutil.Equal(a.profileTypes, tt.wantProfileTypes) { + t.Errorf("initializeAgent() got profile types: %v, want %v", a.profileTypes, tt.wantProfileTypes) + } + } +} + +func TestInitializeConfig(t *testing.T) { + oldConfig, oldService, oldVersion, oldEnvProjectID, oldGetProjectID, oldGetInstanceName, oldGetZone, oldOnGCE := config, os.Getenv("GAE_SERVICE"), os.Getenv("GAE_VERSION"), os.Getenv("GOOGLE_CLOUD_PROJECT"), getProjectID, getInstanceName, getZone, onGCE + defer func() { + config, getProjectID, getInstanceName, getZone, onGCE = oldConfig, oldGetProjectID, oldGetInstanceName, oldGetZone, oldOnGCE + if err := os.Setenv("GAE_SERVICE", oldService); err != nil { + t.Fatal(err) + } + if err := os.Setenv("GAE_VERSION", oldVersion); err != nil { + t.Fatal(err) + } + if err := os.Setenv("GOOGLE_CLOUD_PROJECT", oldEnvProjectID); err != nil { + t.Fatal(err) + } + }() + const ( + testGAEService = "test-gae-service" + testGAEVersion = "test-gae-version" + testGCEProjectID = "test-gce-project-id" + testEnvProjectID = "test-env-project-id" + ) + for _, tt := range []struct { + desc string + config Config + wantConfig Config + wantErrorString string + onGAE bool + onGCE bool + envProjectID bool + }{ + { + "accepts service name", + Config{Service: testService}, + Config{Service: testService, ProjectID: testGCEProjectID, zone: testZone, instance: testInstance}, + "", + false, + true, + false, + }, + { + "env project overrides GCE project", + Config{Service: testService}, + Config{Service: testService, ProjectID: testEnvProjectID, zone: testZone, instance: testInstance}, + "", + false, + true, + true, + }, + { + "requires service name", + Config{}, + Config{}, + "service name must be configured", + false, + true, + false, + }, + { + "requires valid service name", + Config{Service: "Service"}, + Config{Service: "Service"}, + "service name \"Service\" does not match regular expression ^[a-z]([-a-z0-9_.]{0,253}[a-z0-9])?$", + false, + true, + false, + }, + { + "accepts service name from config and service version from GAE", + Config{Service: testService}, + Config{Service: testService, ServiceVersion: testGAEVersion, ProjectID: testGCEProjectID, zone: testZone, instance: testInstance}, + "", + true, + true, + false, + }, + { + "reads both service name and version from GAE env vars", + Config{}, + Config{Service: testGAEService, ServiceVersion: testGAEVersion, ProjectID: testGCEProjectID, zone: testZone, instance: testInstance}, + "", + true, + true, + false, + }, + { + "accepts service version from config", + Config{Service: testService, ServiceVersion: testSvcVersion}, + Config{Service: testService, ServiceVersion: testSvcVersion, ProjectID: testGCEProjectID, zone: testZone, instance: testInstance}, + "", + false, + true, + false, + }, + { + "configured version has priority over GAE-provided version", + Config{Service: testService, ServiceVersion: testSvcVersion}, + Config{Service: testService, ServiceVersion: testSvcVersion, ProjectID: testGCEProjectID, zone: testZone, instance: testInstance}, + "", + true, + true, + false, + }, + { + "configured project ID has priority over metadata-provided project ID", + Config{Service: testService, ProjectID: testProjectID}, + Config{Service: testService, ProjectID: testProjectID, zone: testZone, instance: testInstance}, + "", + false, + true, + false, + }, + { + "configured project ID has priority over environment project ID", + Config{Service: testService, ProjectID: testProjectID}, + Config{Service: testService, ProjectID: testProjectID}, + "", + false, + false, + true, + }, + { + "requires project ID if not on GCE", + Config{Service: testService}, + Config{Service: testService}, + "project ID must be specified in the configuration if running outside of GCP", + false, + false, + false, + }, + } { + t.Logf("Running test: %s", tt.desc) + envService, envVersion := "", "" + if tt.onGAE { + envService, envVersion = testGAEService, testGAEVersion + } + if err := os.Setenv("GAE_SERVICE", envService); err != nil { + t.Fatal(err) + } + if err := os.Setenv("GAE_VERSION", envVersion); err != nil { + t.Fatal(err) + } + if tt.onGCE { + onGCE = func() bool { return true } + getProjectID = func() (string, error) { return testGCEProjectID, nil } + getZone = func() (string, error) { return testZone, nil } + getInstanceName = func() (string, error) { return testInstance, nil } + } else { + onGCE = func() bool { return false } + getProjectID = func() (string, error) { return "", fmt.Errorf("test get project id error") } + getZone = func() (string, error) { return "", fmt.Errorf("test get zone error") } + getInstanceName = func() (string, error) { return "", fmt.Errorf("test get instance error") } + } + envProjectID := "" + if tt.envProjectID { + envProjectID = testEnvProjectID + } + if err := os.Setenv("GOOGLE_CLOUD_PROJECT", envProjectID); err != nil { + t.Fatal(err) + } + + errorString := "" + if err := initializeConfig(tt.config); err != nil { + errorString = err.Error() + } + + if !strings.Contains(errorString, tt.wantErrorString) { + t.Errorf("initializeConfig(%v) got error: %v, want contain %v", tt.config, errorString, tt.wantErrorString) + } + if tt.wantErrorString == "" { + tt.wantConfig.APIAddr = apiAddress + } + if config != tt.wantConfig { + t.Errorf("initializeConfig(%v) got: %v, want %v", tt.config, config, tt.wantConfig) + } + } + + for _, tt := range []struct { + desc string + wantErr bool + getProjectIDError error + getZoneError error + getInstanceError error + }{ + { + desc: "metadata returns error for project ID", + wantErr: true, + getProjectIDError: errors.New("fake get project ID error"), + }, + { + desc: "metadata returns error for zone", + wantErr: true, + getZoneError: errors.New("fake get zone error"), + }, + { + desc: "metadata returns error for instance", + wantErr: true, + getInstanceError: errors.New("fake get instance error"), + }, + { + desc: "metadata returns NotDefinedError for instance", + getInstanceError: gcemd.NotDefinedError("fake GCE metadata NotDefinedError error"), + }, + } { + onGCE = func() bool { return true } + getProjectID = func() (string, error) { return testGCEProjectID, tt.getProjectIDError } + getZone = func() (string, error) { return testZone, tt.getZoneError } + getInstanceName = func() (string, error) { return testInstance, tt.getInstanceError } + + if err := initializeConfig(Config{Service: testService}); (err != nil) != tt.wantErr { + t.Errorf("%s: initializeConfig() got error: %v, want error %t", tt.desc, err, tt.wantErr) + } + } +} + +type fakeProfilerServer struct { + count int + gotProfiles map[string][]byte + done chan bool +} + +func (fs *fakeProfilerServer) CreateProfile(ctx context.Context, in *pb.CreateProfileRequest) (*pb.Profile, error) { + fs.count++ + switch fs.count { + case 1: + return &pb.Profile{Name: "testCPU", ProfileType: pb.ProfileType_CPU, Duration: ptypes.DurationProto(testProfileDuration)}, nil + case 2: + return &pb.Profile{Name: "testHeap", ProfileType: pb.ProfileType_HEAP}, nil + default: + select {} + } +} + +func (fs *fakeProfilerServer) UpdateProfile(ctx context.Context, in *pb.UpdateProfileRequest) (*pb.Profile, error) { + switch in.Profile.ProfileType { + case pb.ProfileType_CPU: + fs.gotProfiles["CPU"] = in.Profile.ProfileBytes + case pb.ProfileType_HEAP: + fs.gotProfiles["HEAP"] = in.Profile.ProfileBytes + fs.done <- true + } + + return in.Profile, nil +} + +func (fs *fakeProfilerServer) CreateOfflineProfile(_ context.Context, _ *pb.CreateOfflineProfileRequest) (*pb.Profile, error) { + return nil, status.Error(codes.Unimplemented, "") +} + +func profileeLoop(quit chan bool) { + for { + select { + case <-quit: + return + default: + profileeWork() + } + } +} + +func profileeWork() { + data := make([]byte, 1024*1024) + rand.Read(data) + + var b bytes.Buffer + gz := gzip.NewWriter(&b) + if _, err := gz.Write(data); err != nil { + log.Println("failed to write to gzip stream", err) + return + } + if err := gz.Flush(); err != nil { + log.Println("failed to flush to gzip stream", err) + return + } + if err := gz.Close(); err != nil { + log.Println("failed to close gzip stream", err) + } +} + +func validateProfile(rawData []byte, wantFunctionName string) error { + p, err := profile.ParseData(rawData) + if err != nil { + return fmt.Errorf("ParseData failed: %v", err) + } + + if len(p.Sample) == 0 { + return fmt.Errorf("profile contains zero samples: %v", p) + } + + if len(p.Location) == 0 { + return fmt.Errorf("profile contains zero locations: %v", p) + } + + if len(p.Function) == 0 { + return fmt.Errorf("profile contains zero functions: %v", p) + } + + for _, l := range p.Location { + if len(l.Line) > 0 && l.Line[0].Function != nil && strings.Contains(l.Line[0].Function.Name, wantFunctionName) { + return nil + } + } + return fmt.Errorf("wanted function name %s not found in the profile", wantFunctionName) +} + +func TestDeltaMutexProfile(t *testing.T) { + oldMutexEnabled, oldMaxProcs := mutexEnabled, runtime.GOMAXPROCS(10) + defer func() { + mutexEnabled = oldMutexEnabled + runtime.GOMAXPROCS(oldMaxProcs) + }() + if mutexEnabled = enableMutexProfiling(); !mutexEnabled { + t.Skip("Go too old - mutex profiling not supported.") + } + + hog(time.Second, mutexHog) + go func() { + hog(2*time.Second, backgroundHog) + }() + + var prof bytes.Buffer + if err := deltaMutexProfile(context.Background(), time.Second, &prof); err != nil { + t.Fatalf("deltaMutexProfile() got error: %v", err) + } + p, err := profile.Parse(&prof) + if err != nil { + t.Fatalf("profile.Parse() got error: %v", err) + } + + if s := sum(p, "mutexHog"); s != 0 { + t.Errorf("mutexHog found in the delta mutex profile (sum=%d):\n%s", s, p) + } + if s := sum(p, "backgroundHog"); s <= 0 { + t.Errorf("backgroundHog not in the delta mutex profile (sum=%d):\n%s", s, p) + } +} + +// sum returns the sum of all mutex counts from the samples whose +// stacks include the specified function name. +func sum(p *profile.Profile, fname string) int64 { + locIDs := map[*profile.Location]bool{} + for _, loc := range p.Location { + for _, l := range loc.Line { + if strings.Contains(l.Function.Name, fname) { + locIDs[loc] = true + break + } + } + } + var s int64 + for _, sample := range p.Sample { + for _, loc := range sample.Location { + if locIDs[loc] { + s += sample.Value[0] + break + } + } + } + return s +} + +func mutexHog(mu1, mu2 *sync.Mutex, start time.Time, dt time.Duration) { + for time.Since(start) < dt { + mu1.Lock() + runtime.Gosched() + mu2.Lock() + mu1.Unlock() + mu2.Unlock() + } +} + +// backgroundHog is identical to mutexHog. We keep them separate +// in order to distinguish them with function names in the stack trace. +func backgroundHog(mu1, mu2 *sync.Mutex, start time.Time, dt time.Duration) { + for time.Since(start) < dt { + mu1.Lock() + runtime.Gosched() + mu2.Lock() + mu1.Unlock() + mu2.Unlock() + } +} + +func hog(dt time.Duration, hogger func(mu1, mu2 *sync.Mutex, start time.Time, dt time.Duration)) { + start := time.Now() + mu1 := new(sync.Mutex) + mu2 := new(sync.Mutex) + var wg sync.WaitGroup + wg.Add(10) + for i := 0; i < 10; i++ { + go func() { + defer wg.Done() + hogger(mu1, mu2, start, dt) + }() + } + wg.Wait() +} + +func TestAgentWithServer(t *testing.T) { + oldDialGRPC, oldConfig := dialGRPC, config + defer func() { + dialGRPC, config = oldDialGRPC, oldConfig + }() + + srv, err := testutil.NewServer() + if err != nil { + t.Fatalf("testutil.NewServer(): %v", err) + } + fakeServer := &fakeProfilerServer{gotProfiles: map[string][]byte{}, done: make(chan bool)} + pb.RegisterProfilerServiceServer(srv.Gsrv, fakeServer) + + srv.Start() + + dialGRPC = gtransport.DialInsecure + if err := Start(Config{ + Service: testService, + ProjectID: testProjectID, + APIAddr: srv.Addr, + instance: testInstance, + zone: testZone, + }); err != nil { + t.Fatalf("Start(): %v", err) + } + + quitProfilee := make(chan bool) + go profileeLoop(quitProfilee) + + select { + case <-fakeServer.done: + case <-time.After(testServerTimeout): + t.Errorf("got timeout after %v, want fake server done", testServerTimeout) + } + quitProfilee <- true + + for _, pType := range []string{"CPU", "HEAP"} { + if profile, ok := fakeServer.gotProfiles[pType]; !ok { + t.Errorf("fakeServer.gotProfiles[%s] got no profile, want profile", pType) + } else if err := validateProfile(profile, "profilee"); err != nil { + t.Errorf("validateProfile(%s) got error: %v", pType, err) + } + } +} diff --git a/vendor/cloud.google.com/go/profiler/proftest/proftest.go b/vendor/cloud.google.com/go/profiler/proftest/proftest.go new file mode 100644 index 00000000..b103dd5a --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/proftest/proftest.go @@ -0,0 +1,556 @@ +// Copyright 2018 Google LLC +// +// 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 proftest contains test helpers for profiler agent integration tests. +// This package is experimental. + +package proftest + +import ( + "archive/zip" + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "log" + "net/http" + "strings" + "time" + + "cloud.google.com/go/storage" + gax "github.com/googleapis/gax-go" + "golang.org/x/build/kubernetes" + k8sapi "golang.org/x/build/kubernetes/api" + "golang.org/x/build/kubernetes/gke" + cloudbuild "google.golang.org/api/cloudbuild/v1" + compute "google.golang.org/api/compute/v1" + container "google.golang.org/api/container/v1" + "google.golang.org/api/googleapi" +) + +const ( + monitorWriteScope = "https://www.googleapis.com/auth/monitoring.write" + storageReadScope = "https://www.googleapis.com/auth/devstorage.read_only" +) + +// TestRunner has common elements used for testing profiling agents on a range +// of environments. +type TestRunner struct { + Client *http.Client +} + +// GCETestRunner supports testing a profiling agent on GCE. +type GCETestRunner struct { + TestRunner + ComputeService *compute.Service +} + +// GKETestRunner supports testing a profiling agent on GKE. +type GKETestRunner struct { + TestRunner + ContainerService *container.Service + StorageClient *storage.Client + Dockerfile string +} + +// ProfileResponse contains the response produced when querying profile server. +type ProfileResponse struct { + Profile ProfileData `json:"profile"` + NumProfiles int32 `json:"numProfiles"` + Deployments []interface{} `json:"deployments"` +} + +// ProfileData has data of a single profile. +type ProfileData struct { + Samples []int32 `json:"samples"` + SampleMetrics interface{} `json:"sampleMetrics"` + DefaultMetricType string `json:"defaultMetricType"` + TreeNodes interface{} `json:"treeNodes"` + Functions functionArray `json:"functions"` + SourceFiles interface{} `json:"sourceFiles"` +} + +type functionArray struct { + Name []string `json:"name"` + Sourcefile []int32 `json:"sourceFile"` +} + +// InstanceConfig is configuration for starting single GCE instance for +// profiling agent test case. +type InstanceConfig struct { + ProjectID string + Zone string + Name string + StartupScript string + MachineType string +} + +// ClusterConfig is configuration for starting single GKE cluster for profiling +// agent test case. +type ClusterConfig struct { + ProjectID string + Zone string + ClusterName string + PodName string + ImageSourceName string + ImageName string + Bucket string + Dockerfile string +} + +// HasFunction returns nil if the function is present, or, if the function is +// not present, and error providing more details why the function is not +// present. +func (pr *ProfileResponse) HasFunction(functionName string) error { + if pr.NumProfiles == 0 { + return fmt.Errorf("failed to find function name %s in profile: profile response contains zero profiles: %v", functionName, pr) + } + if len(pr.Deployments) == 0 { + return fmt.Errorf("failed to find function name %s in profile: profile response contains zero deployments: %v", functionName, pr) + } + if len(pr.Profile.Functions.Name) == 0 { + return fmt.Errorf("failed to find function name %s in profile: profile does not have function data", functionName) + } + + for _, name := range pr.Profile.Functions.Name { + if strings.Contains(name, functionName) { + return nil + } + } + return fmt.Errorf("failed to find function name %s in profile", functionName) +} + +// StartInstance starts a GCE Instance with name, zone, and projectId specified +// by the inst, and which runs the startup script specified in inst. +func (tr *GCETestRunner) StartInstance(ctx context.Context, inst *InstanceConfig) error { + img, err := tr.ComputeService.Images.GetFromFamily("debian-cloud", "debian-9").Context(ctx).Do() + if err != nil { + return err + } + + op, err := tr.ComputeService.Instances.Insert(inst.ProjectID, inst.Zone, &compute.Instance{ + MachineType: fmt.Sprintf("zones/%s/machineTypes/%s", inst.Zone, inst.MachineType), + Name: inst.Name, + Disks: []*compute.AttachedDisk{{ + AutoDelete: true, // delete the disk when the VM is deleted. + Boot: true, + Type: "PERSISTENT", + Mode: "READ_WRITE", + InitializeParams: &compute.AttachedDiskInitializeParams{ + SourceImage: img.SelfLink, + DiskType: fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%s/zones/%s/diskTypes/pd-standard", inst.ProjectID, inst.Zone), + }, + }}, + NetworkInterfaces: []*compute.NetworkInterface{{ + Network: fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%s/global/networks/default", inst.ProjectID), + AccessConfigs: []*compute.AccessConfig{{ + Name: "External NAT", + }}, + }}, + Metadata: &compute.Metadata{ + Items: []*compute.MetadataItems{{ + Key: "startup-script", + Value: googleapi.String(inst.StartupScript), + }}, + }, + ServiceAccounts: []*compute.ServiceAccount{{ + Email: "default", + Scopes: []string{ + monitorWriteScope, + }, + }}, + }).Do() + + if err != nil { + return fmt.Errorf("failed to create instance: %v", err) + } + + // Poll status of the operation to create the instance. + getOpCall := tr.ComputeService.ZoneOperations.Get(inst.ProjectID, inst.Zone, op.Name) + for { + if err := checkOpErrors(op); err != nil { + return fmt.Errorf("failed to create instance: %v", err) + } + if op.Status == "DONE" { + return nil + } + + if err := gax.Sleep(ctx, 5*time.Second); err != nil { + return err + } + + op, err = getOpCall.Do() + if err != nil { + return fmt.Errorf("failed to get operation: %v", err) + } + } +} + +// checkOpErrors returns nil if the operation does not have any errors and an +// error summarizing all errors encountered if the operation has errored. +func checkOpErrors(op *compute.Operation) error { + if op.Error == nil || len(op.Error.Errors) == 0 { + return nil + } + + var errs []string + for _, e := range op.Error.Errors { + if e.Message != "" { + errs = append(errs, e.Message) + } else { + errs = append(errs, e.Code) + } + } + return errors.New(strings.Join(errs, ",")) +} + +// DeleteInstance deletes an instance with project id, name, and zone matched +// by inst. +func (tr *GCETestRunner) DeleteInstance(ctx context.Context, inst *InstanceConfig) error { + if _, err := tr.ComputeService.Instances.Delete(inst.ProjectID, inst.Zone, inst.Name).Context(ctx).Do(); err != nil { + return fmt.Errorf("Instances.Delete(%s) got error: %v", inst.Name, err) + } + return nil +} + +// PollForSerialOutput polls serial port 2 of the GCE instance specified by +// inst and returns when the finishString appears in the serial output +// of the instance, or when the context times out. +func (tr *GCETestRunner) PollForSerialOutput(ctx context.Context, inst *InstanceConfig, finishString, errorString string) error { + var output string + defer func() { + log.Printf("Serial port output for %s:\n%s", inst.Name, output) + }() + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(20 * time.Second): + resp, err := tr.ComputeService.Instances.GetSerialPortOutput(inst.ProjectID, inst.Zone, inst.Name).Port(2).Context(ctx).Do() + if err != nil { + // Transient failure. + log.Printf("Transient error getting serial port output from instance %s (will retry): %v", inst.Name, err) + continue + } + if resp.Contents == "" { + log.Printf("Ignoring empty serial port output from instance %s (will retry)", inst.Name) + continue + } + if output = resp.Contents; strings.Contains(output, finishString) { + return nil + } + if strings.Contains(output, errorString) { + return fmt.Errorf("failed to execute the prober benchmark script") + } + } + } +} + +// QueryProfiles retrieves profiles of a specific type, from a specific time +// range, associated with a particular service and project. +func (tr *TestRunner) QueryProfiles(projectID, service, startTime, endTime, profileType string) (ProfileResponse, error) { + queryURL := fmt.Sprintf("https://cloudprofiler.googleapis.com/v2/projects/%s/profiles:query", projectID) + const queryJSONFmt = `{"endTime": "%s", "profileType": "%s","startTime": "%s", "target": "%s"}` + + queryRequest := fmt.Sprintf(queryJSONFmt, endTime, profileType, startTime, service) + + resp, err := tr.Client.Post(queryURL, "application/json", strings.NewReader(queryRequest)) + if err != nil { + return ProfileResponse{}, fmt.Errorf("failed to query API: %v", err) + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return ProfileResponse{}, fmt.Errorf("failed to read response body: %v", err) + } + + if resp.StatusCode != 200 { + return ProfileResponse{}, fmt.Errorf("failed to query API: status: %s, response body: %s", resp.Status, string(body)) + } + + var pr ProfileResponse + if err := json.Unmarshal(body, &pr); err != nil { + return ProfileResponse{}, err + } + + return pr, nil +} + +// createAndPublishDockerImage creates a docker image from source code in a GCS +// bucket and pushes the image to Google Container Registry. +func (tr *GKETestRunner) createAndPublishDockerImage(ctx context.Context, projectID, sourceBucket, sourceObject, ImageName string) error { + cloudbuildService, err := cloudbuild.New(tr.Client) + if err != nil { + return err + } + + build := &cloudbuild.Build{ + Source: &cloudbuild.Source{ + StorageSource: &cloudbuild.StorageSource{ + Bucket: sourceBucket, + Object: sourceObject, + }, + }, + Steps: []*cloudbuild.BuildStep{ + { + Name: "gcr.io/cloud-builders/docker", + Args: []string{"build", "-t", ImageName, "."}, + }, + }, + Images: []string{ImageName}, + } + + op, err := cloudbuildService.Projects.Builds.Create(projectID, build).Context(ctx).Do() + if err != nil { + return fmt.Errorf("failed to create image: %v", err) + } + opID := op.Name + + // Wait for creating image. + for { + select { + case <-ctx.Done(): + return fmt.Errorf("timed out waiting creating image") + + case <-time.After(10 * time.Second): + op, err := cloudbuildService.Operations.Get(opID).Context(ctx).Do() + if err != nil { + log.Printf("Transient error getting operation (will retry): %v", err) + break + } + if op.Done == true { + log.Printf("Published image %s to Google Container Registry.", ImageName) + return nil + } + } + } +} + +type imageResponse struct { + Manifest map[string]interface{} `json:"manifest"` + Name string `json:"name"` + Tags []string `json:"tags"` +} + +// deleteDockerImage deletes a docker image from Google Container Registry. +func (tr *GKETestRunner) deleteDockerImage(ctx context.Context, ImageName string) []error { + queryImageURL := fmt.Sprintf("https://gcr.io/v2/%s/tags/list", ImageName) + resp, err := tr.Client.Get(queryImageURL) + if err != nil { + return []error{fmt.Errorf("failed to list tags: %v", err)} + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return []error{err} + } + var ir imageResponse + if err := json.Unmarshal(body, &ir); err != nil { + return []error{err} + } + + const deleteImageURLFmt = "https://gcr.io/v2/%s/manifests/%s" + var errs []error + for _, tag := range ir.Tags { + if err := deleteDockerImageResource(tr.Client, fmt.Sprintf(deleteImageURLFmt, ImageName, tag)); err != nil { + errs = append(errs, fmt.Errorf("failed to delete tag %s: %v", tag, err)) + } + } + + for manifest := range ir.Manifest { + if err := deleteDockerImageResource(tr.Client, fmt.Sprintf(deleteImageURLFmt, ImageName, manifest)); err != nil { + errs = append(errs, fmt.Errorf("failed to delete manifest %s: %v", manifest, err)) + } + } + return errs +} + +func deleteDockerImageResource(client *http.Client, url string) error { + req, err := http.NewRequest("DELETE", url, nil) + if err != nil { + return fmt.Errorf("failed to get request: %v", err) + } + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("failed to delete resource: %v", err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted { + return fmt.Errorf("failed to delete resource: status code = %d", resp.StatusCode) + } + return nil +} + +func (tr *GKETestRunner) createCluster(ctx context.Context, client *http.Client, projectID, zone, ClusterName string) error { + request := &container.CreateClusterRequest{Cluster: &container.Cluster{ + Name: ClusterName, + InitialNodeCount: 3, + NodeConfig: &container.NodeConfig{ + OauthScopes: []string{ + storageReadScope, + }, + }, + }} + op, err := tr.ContainerService.Projects.Zones.Clusters.Create(projectID, zone, request).Context(ctx).Do() + if err != nil { + return fmt.Errorf("failed to create cluster %s: %v", ClusterName, err) + } + opID := op.Name + + // Wait for creating cluster. + for { + select { + case <-ctx.Done(): + return fmt.Errorf("timed out waiting creating cluster") + + case <-time.After(10 * time.Second): + op, err := tr.ContainerService.Projects.Zones.Operations.Get(projectID, zone, opID).Context(ctx).Do() + if err != nil { + log.Printf("Transient error getting operation (will retry): %v", err) + break + } + if op.Status == "DONE" { + log.Printf("Created cluster %s.", ClusterName) + return nil + } + if op.Status == "ABORTING" { + return fmt.Errorf("create cluster operation is aborted") + } + } + } +} + +func (tr *GKETestRunner) deployContainer(ctx context.Context, kubernetesClient *kubernetes.Client, podName, ImageName string) error { + // TODO: Pod restart policy defaults to "Always". Previous logs will disappear + // after restarting. Always restart causes the test not be able to see the + // finish signal. Should probably set the restart policy to "OnFailure" when + // we get the GKE workflow working and testable. + pod := &k8sapi.Pod{ + ObjectMeta: k8sapi.ObjectMeta{ + Name: podName, + }, + Spec: k8sapi.PodSpec{ + Containers: []k8sapi.Container{ + { + Name: "profiler-test", + Image: fmt.Sprintf("gcr.io/%s:latest", ImageName), + }, + }, + }, + } + if _, err := kubernetesClient.RunLongLivedPod(ctx, pod); err != nil { + return fmt.Errorf("failed to run pod %s: %v", podName, err) + } + return nil +} + +// PollPodLog polls the log of the kubernetes client and returns when the +// finishString appears in the log, or when the context times out. +func (tr *GKETestRunner) PollPodLog(ctx context.Context, kubernetesClient *kubernetes.Client, podName, finishString string) error { + var output string + defer func() { + log.Printf("Log for pod %s:\n%s", podName, output) + }() + + for { + select { + case <-ctx.Done(): + return fmt.Errorf("timed out waiting profiling finishing on container") + + case <-time.After(20 * time.Second): + var err error + output, err = kubernetesClient.PodLog(ctx, podName) + if err != nil { + // Transient failure. + log.Printf("Transient error getting log (will retry): %v", err) + continue + } + if strings.Contains(output, finishString) { + return nil + } + } + } +} + +// DeleteClusterAndImage deletes cluster and images used to create cluster. +func (tr *GKETestRunner) DeleteClusterAndImage(ctx context.Context, cfg *ClusterConfig) []error { + var errs []error + if err := tr.StorageClient.Bucket(cfg.Bucket).Object(cfg.ImageSourceName).Delete(ctx); err != nil { + errs = append(errs, fmt.Errorf("failed to delete storage client: %v", err)) + } + for _, err := range tr.deleteDockerImage(ctx, cfg.ImageName) { + errs = append(errs, fmt.Errorf("failed to delete docker image: %v", err)) + } + if _, err := tr.ContainerService.Projects.Zones.Clusters.Delete(cfg.ProjectID, cfg.Zone, cfg.ClusterName).Context(ctx).Do(); err != nil { + errs = append(errs, fmt.Errorf("failed to delete cluster %s: %v", cfg.ClusterName, err)) + } + + return errs +} + +// StartAndDeployCluster creates image needed for cluster, then starts and +// deploys to cluster. +func (tr *GKETestRunner) StartAndDeployCluster(ctx context.Context, cfg *ClusterConfig) error { + if err := tr.uploadImageSource(ctx, cfg.Bucket, cfg.ImageSourceName, cfg.Dockerfile); err != nil { + return fmt.Errorf("failed to upload image source: %v", err) + } + + createImageCtx, cancel := context.WithTimeout(ctx, 5*time.Minute) + defer cancel() + if err := tr.createAndPublishDockerImage(createImageCtx, cfg.ProjectID, cfg.Bucket, cfg.ImageSourceName, fmt.Sprintf("gcr.io/%s", cfg.ImageName)); err != nil { + return fmt.Errorf("failed to create and publish docker image %s: %v", cfg.ImageName, err) + } + + kubernetesClient, err := gke.NewClient(ctx, cfg.ClusterName, gke.OptZone(cfg.Zone), gke.OptProject(cfg.ProjectID)) + if err != nil { + return fmt.Errorf("failed to create new GKE client: %v", err) + } + + deployContainerCtx, cancel := context.WithTimeout(ctx, 5*time.Minute) + defer cancel() + if err := tr.deployContainer(deployContainerCtx, kubernetesClient, cfg.PodName, cfg.ImageName); err != nil { + return fmt.Errorf("failed to deploy image %q to pod %q: %v", cfg.PodName, cfg.ImageName, err) + } + return nil +} + +// uploadImageSource uploads source code for building docker image to GCS. +func (tr *GKETestRunner) uploadImageSource(ctx context.Context, bucket, objectName, dockerfile string) error { + zipBuf := new(bytes.Buffer) + z := zip.NewWriter(zipBuf) + f, err := z.Create("Dockerfile") + if err != nil { + return err + } + + if _, err := f.Write([]byte(dockerfile)); err != nil { + return err + } + + if err := z.Close(); err != nil { + return err + } + wc := tr.StorageClient.Bucket(bucket).Object(objectName).NewWriter(ctx) + wc.ContentType = "application/zip" + wc.ACL = []storage.ACLRule{{Entity: storage.AllUsers, Role: storage.RoleReader}} + if _, err := wc.Write(zipBuf.Bytes()); err != nil { + return err + } + return wc.Close() +} diff --git a/vendor/cloud.google.com/go/profiler/symbolizer.go b/vendor/cloud.google.com/go/profiler/symbolizer.go new file mode 100644 index 00000000..4d3d5220 --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/symbolizer.go @@ -0,0 +1,140 @@ +// Copyright 2017 Google LLC +// +// 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 profiler + +import ( + "bytes" + "regexp" + "runtime" + "strings" + + "github.com/google/pprof/profile" +) + +var shouldAssumeSymbolized = isSymbolizedGoVersion(runtime.Version()) + +type function interface { + Name() string + FileLine(pc uintptr) (string, int) +} + +// funcForPC is a wrapper for runtime.FuncForPC. Defined as var for testing. +var funcForPC = func(pc uintptr) function { + return runtime.FuncForPC(pc) +} + +// parseAndSymbolize parses a profile from a buffer, symbolizes it +// if it's not yet symbolized, and writes the profile back as a +// gzip-compressed marshaled protobuf. +func parseAndSymbolize(data *bytes.Buffer) error { + p, err := profile.ParseData(data.Bytes()) + if err != nil { + return err + } + + // Do nothing if the profile is already symbolized. + if symbolized(p) { + return nil + } + // Clear the profile functions to avoid creating duplicates. + p.Function = nil + symbolize(p) + data.Reset() + return p.Write(data) +} + +// isSymbolizedGoVersion returns true if Go version equals to or is +// higher than Go 1.9. Starting Go 1.9 the profiles are symbolized +// by runtime/pprof. +func isSymbolizedGoVersion(goVersion string) bool { + r, err := regexp.Compile(`go(1\.9|1\.[1-9][0-9]|[2-9]).*`) + if err == nil && r.MatchString(goVersion) { + return true + } + return false +} + +// symbolized checks if all locations have symbolized function +// information. +func symbolized(p *profile.Profile) bool { + for _, l := range p.Location { + if len(l.Line) == 0 || l.Line[0].Function == nil { + return false + } + } + return true +} + +func symbolize(p *profile.Profile) { + fns := profileFunctionMap{} + for _, l := range p.Location { + pc := uintptr(l.Address) + f := funcForPC(pc) + if f == nil { + continue + } + file, lineno := f.FileLine(pc) + l.Line = []profile.Line{ + { + Function: fns.findOrAddFunction(f.Name(), file, p), + Line: int64(lineno), + }, + } + } + // Trim runtime functions. Always hide runtime.goexit. Other runtime + // functions are only hidden for heap profile when they appear at the beginning. + isHeapProfile := p.PeriodType != nil && p.PeriodType.Type == "space" + for _, s := range p.Sample { + show := !isHeapProfile + var i int + for _, l := range s.Location { + if len(l.Line) > 0 && l.Line[0].Function != nil { + name := l.Line[0].Function.Name + if name == "runtime.goexit" || !show && strings.HasPrefix(name, "runtime.") { + continue + } + } + show = true + s.Location[i] = l + i++ + } + // If all locations of a sample are trimmed, keep the root location. + if i == 0 && len(s.Location) > 0 { + s.Location[0] = s.Location[len(s.Location)-1] + i = 1 + } + s.Location = s.Location[:i] + } +} + +type profileFunctionMap map[profile.Function]*profile.Function + +func (fns profileFunctionMap) findOrAddFunction(name, filename string, p *profile.Profile) *profile.Function { + f := profile.Function{ + Name: name, + SystemName: name, + Filename: filename, + } + if fp := fns[f]; fp != nil { + return fp + } + fp := new(profile.Function) + fns[f] = fp + + *fp = f + fp.ID = uint64(len(p.Function) + 1) + p.Function = append(p.Function, fp) + return fp +} diff --git a/vendor/cloud.google.com/go/profiler/symbolizer_test.go b/vendor/cloud.google.com/go/profiler/symbolizer_test.go new file mode 100644 index 00000000..bdcf808c --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/symbolizer_test.go @@ -0,0 +1,229 @@ +// Copyright 2017 Google LLC +// +// 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 profiler + +import ( + "bytes" + "testing" + + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/google/pprof/profile" +) + +type fakeFunc struct { + name string + file string + lineno int +} + +func (f *fakeFunc) Name() string { + return f.name +} +func (f *fakeFunc) FileLine(_ uintptr) (string, int) { + return f.file, f.lineno +} + +var cmpOpt = cmpopts.IgnoreUnexported(profile.Profile{}, profile.Function{}, + profile.Line{}, profile.Location{}, profile.Sample{}, profile.ValueType{}) + +// TestRuntimeFunctionTrimming tests if symbolize trims runtime functions as intended. +func TestRuntimeFunctionTrimming(t *testing.T) { + fakeFuncMap := map[uintptr]*fakeFunc{ + 0x10: {"runtime.goexit", "runtime.go", 10}, + 0x20: {"runtime.other", "runtime.go", 20}, + 0x30: {"foo", "foo.go", 30}, + 0x40: {"bar", "bar.go", 40}, + } + backupFuncForPC := funcForPC + funcForPC = func(pc uintptr) function { + return fakeFuncMap[pc] + } + defer func() { + funcForPC = backupFuncForPC + }() + testLoc := []*profile.Location{ + {ID: 1, Address: 0x10}, + {ID: 2, Address: 0x20}, + {ID: 3, Address: 0x30}, + {ID: 4, Address: 0x40}, + } + testProfile := &profile.Profile{ + Sample: []*profile.Sample{ + {Location: []*profile.Location{testLoc[0], testLoc[1], testLoc[3], testLoc[2]}}, + {Location: []*profile.Location{testLoc[1], testLoc[3], testLoc[2]}}, + {Location: []*profile.Location{testLoc[3], testLoc[2], testLoc[1]}}, + {Location: []*profile.Location{testLoc[3], testLoc[2], testLoc[0]}}, + {Location: []*profile.Location{testLoc[0], testLoc[1], testLoc[3], testLoc[0]}}, + {Location: []*profile.Location{testLoc[1], testLoc[0]}}, + }, + Location: testLoc, + } + testProfiles := make([]*profile.Profile, 2) + testProfiles[0] = testProfile.Copy() + testProfiles[1] = testProfile.Copy() + // Test case for CPU profile. + testProfiles[0].PeriodType = &profile.ValueType{Type: "cpu", Unit: "nanoseconds"} + // Test case for heap profile. + testProfiles[1].PeriodType = &profile.ValueType{Type: "space", Unit: "bytes"} + wantFunc := []*profile.Function{ + {ID: 1, Name: "runtime.goexit", SystemName: "runtime.goexit", Filename: "runtime.go"}, + {ID: 2, Name: "runtime.other", SystemName: "runtime.other", Filename: "runtime.go"}, + {ID: 3, Name: "foo", SystemName: "foo", Filename: "foo.go"}, + {ID: 4, Name: "bar", SystemName: "bar", Filename: "bar.go"}, + } + wantLoc := []*profile.Location{ + {ID: 1, Address: 0x10, Line: []profile.Line{{Function: wantFunc[0], Line: 10}}}, + {ID: 2, Address: 0x20, Line: []profile.Line{{Function: wantFunc[1], Line: 20}}}, + {ID: 3, Address: 0x30, Line: []profile.Line{{Function: wantFunc[2], Line: 30}}}, + {ID: 4, Address: 0x40, Line: []profile.Line{{Function: wantFunc[3], Line: 40}}}, + } + wantProfiles := []*profile.Profile{ + { + PeriodType: &profile.ValueType{Type: "cpu", Unit: "nanoseconds"}, + Sample: []*profile.Sample{ + {Location: []*profile.Location{wantLoc[1], wantLoc[3], wantLoc[2]}}, + {Location: []*profile.Location{wantLoc[1], wantLoc[3], wantLoc[2]}}, + {Location: []*profile.Location{wantLoc[3], wantLoc[2], wantLoc[1]}}, + {Location: []*profile.Location{wantLoc[3], wantLoc[2]}}, + {Location: []*profile.Location{wantLoc[1], wantLoc[3]}}, + {Location: []*profile.Location{wantLoc[1]}}, + }, + Location: wantLoc, + Function: wantFunc, + }, + { + PeriodType: &profile.ValueType{Type: "space", Unit: "bytes"}, + Sample: []*profile.Sample{ + {Location: []*profile.Location{wantLoc[3], wantLoc[2]}}, + {Location: []*profile.Location{wantLoc[3], wantLoc[2]}}, + {Location: []*profile.Location{wantLoc[3], wantLoc[2], wantLoc[1]}}, + {Location: []*profile.Location{wantLoc[3], wantLoc[2]}}, + {Location: []*profile.Location{wantLoc[3]}}, + {Location: []*profile.Location{wantLoc[0]}}, + }, + Location: wantLoc, + Function: wantFunc, + }, + } + for i := 0; i < 2; i++ { + symbolize(testProfiles[i]) + if !testutil.Equal(testProfiles[i], wantProfiles[i], cmpOpt) { + t.Errorf("incorrect trimming (testcase = %d): got {%v}, want {%v}", i, testProfiles[i], wantProfiles[i]) + } + } +} + +// TestParseAndSymbolize tests if parseAndSymbolize parses and symbolizes +// profiles as intended. +func TestParseAndSymbolize(t *testing.T) { + fakeFuncMap := map[uintptr]*fakeFunc{ + 0x10: {"foo", "foo.go", 10}, + 0x20: {"bar", "bar.go", 20}, + } + backupFuncForPC := funcForPC + funcForPC = func(pc uintptr) function { + return fakeFuncMap[pc] + } + defer func() { + funcForPC = backupFuncForPC + }() + + testLoc := []*profile.Location{ + {ID: 1, Address: 0x10}, + {ID: 2, Address: 0x20}, + } + testProfile := &profile.Profile{ + SampleType: []*profile.ValueType{ + {Type: "cpu", Unit: "nanoseconds"}, + }, + PeriodType: &profile.ValueType{Type: "cpu", Unit: "nanoseconds"}, + Sample: []*profile.Sample{ + {Location: []*profile.Location{testLoc[0], testLoc[1]}, Value: []int64{1}}, + {Location: []*profile.Location{testLoc[1]}, Value: []int64{1}}, + }, + Location: testLoc, + } + testProfiles := make([]*profile.Profile, 2) + testProfiles[0] = testProfile.Copy() + testProfiles[1] = testProfile.Copy() + + wantFunc := []*profile.Function{ + {ID: 1, Name: "foo", SystemName: "foo", Filename: "foo.go"}, + {ID: 2, Name: "bar", SystemName: "bar", Filename: "bar.go"}, + } + wantLoc := []*profile.Location{ + {ID: 1, Address: 0x10, Line: []profile.Line{{Function: wantFunc[0], Line: 10}}}, + {ID: 2, Address: 0x20, Line: []profile.Line{{Function: wantFunc[1], Line: 20}}}, + } + wantProfile := &profile.Profile{ + SampleType: []*profile.ValueType{ + {Type: "cpu", Unit: "nanoseconds"}, + }, + PeriodType: &profile.ValueType{Type: "cpu", Unit: "nanoseconds"}, + Sample: []*profile.Sample{ + {Location: []*profile.Location{wantLoc[0], wantLoc[1]}, Value: []int64{1}}, + {Location: []*profile.Location{wantLoc[1]}, Value: []int64{1}}, + }, + Location: wantLoc, + Function: wantFunc, + } + + // Profile already symbolized. + testProfiles[1].Location = []*profile.Location{ + {ID: 1, Address: 0x10, Line: []profile.Line{{Function: wantFunc[0], Line: 10}}}, + {ID: 2, Address: 0x20, Line: []profile.Line{{Function: wantFunc[1], Line: 20}}}, + } + testProfiles[1].Function = []*profile.Function{ + {ID: 1, Name: "foo", SystemName: "foo", Filename: "foo.go"}, + {ID: 2, Name: "bar", SystemName: "bar", Filename: "bar.go"}, + } + for i := 0; i < 2; i++ { + var prof bytes.Buffer + testProfiles[i].Write(&prof) + + parseAndSymbolize(&prof) + gotProfile, err := profile.ParseData(prof.Bytes()) + if err != nil { + t.Errorf("parsing symbolized profile (testcase = %d) got err: %v, want no error", i, err) + } + if !testutil.Equal(gotProfile, wantProfile, cmpOpt) { + t.Errorf("incorrect symbolization (testcase = %d): got {%v}, want {%v}", i, gotProfile, wantProfile) + } + } +} + +func TestIsSymbolizedGoVersion(t *testing.T) { + for _, tc := range []struct { + input string + want bool + }{ + {"go1.9beta2", true}, + {"go1.9", true}, + {"go1.9.1", true}, + {"go1.10", true}, + {"go1.10.1", true}, + {"go2.0", true}, + {"go3.1", true}, + {"go1.8", false}, + {"go1.8.1", false}, + {"go1.7", false}, + {"devel ", false}, + } { + if got := isSymbolizedGoVersion(tc.input); got != tc.want { + t.Errorf("isSymbolizedGoVersion(%v) got %v, want %v", tc.input, got, tc.want) + } + } +} diff --git a/vendor/cloud.google.com/go/profiler/testdata/testdata.go b/vendor/cloud.google.com/go/profiler/testdata/testdata.go new file mode 100644 index 00000000..defa7dee --- /dev/null +++ b/vendor/cloud.google.com/go/profiler/testdata/testdata.go @@ -0,0 +1,126 @@ +// Copyright 2018 Google LLC +// +// 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 testdata provides some useful data sets for testing purposes. +package testdata + +import ( + "github.com/google/pprof/profile" +) + +var functions = []*profile.Function{ + {ID: 1, Name: "main", SystemName: "main", Filename: "main.go"}, + {ID: 2, Name: "foo", SystemName: "foo", Filename: "foo.go"}, + {ID: 3, Name: "foo_caller", SystemName: "foo_caller", Filename: "foo.go"}, +} + +const mainBinary = "/bin/main" + +var mappings = []*profile.Mapping{ + { + ID: 1, + Start: 0x10000, + Limit: 0x40000, + File: mainBinary, + HasFunctions: true, + HasFilenames: true, + HasLineNumbers: true, + HasInlineFrames: true, + }, + { + ID: 2, + Start: 0x1000, + Limit: 0x4000, + File: "/lib/lib.so", + HasFunctions: true, + HasFilenames: true, + HasLineNumbers: true, + HasInlineFrames: true, + }, +} + +var locations = []*profile.Location{ + { + ID: 1, + Mapping: mappings[1], + Address: 0x1000, + Line: []profile.Line{ + {Function: functions[0], Line: 1}, + }, + }, + { + ID: 2, + Mapping: mappings[0], + Address: 0x2000, + Line: []profile.Line{ + {Function: functions[1], Line: 2}, + {Function: functions[2], Line: 1}, + }, + }, +} + +// HeapProfileCollected1 represents a heap profile which could be collected using +// pprof.WriteHeapProfile(). +var HeapProfileCollected1 = &profile.Profile{ + DurationNanos: 10e9, + SampleType: []*profile.ValueType{ + {Type: "alloc_objects", Unit: "count"}, + {Type: "alloc_space", Unit: "bytes"}, + {Type: "inuse_objects", Unit: "count"}, + {Type: "inuse_space", Unit: "bytes"}, + }, + Sample: []*profile.Sample{{ + Location: []*profile.Location{locations[0], locations[1]}, + Value: []int64{10, 160, 10, 160}, + NumLabel: map[string][]int64{ + "bytes": {16}, + }, + NumUnit: map[string][]string{ + "bytes": {"bytes"}, + }, + }}, + Location: locations, + Function: functions, + Mapping: mappings, +} + +// HeapProfileUploaded represents the heap profile bytes we would expect to +// be uploaded if HeapProfileCollected1 were returned when profiling. +var HeapProfileUploaded = func() *profile.Profile { + p := HeapProfileCollected1.Copy() + p.Sample[0].Value = []int64{0, 0, 10, 160} + return p +}() + +// HeapProfileCollected2 represents a heap profile which could be collected using +// pprof.WriteHeapProfile(). +var HeapProfileCollected2 = func() *profile.Profile { + p := HeapProfileCollected1.Copy() + p.Sample[0].Value = []int64{11, 176, 11, 176} + return p +}() + +// AllocProfileUploaded represents the allocation profile bytes we would expect +// to be uploaded if HeapProfileCollected1 was returned when first profiling +// and HeapProfileCollect2 was return when profiling the second time. +var AllocProfileUploaded = func() *profile.Profile { + p := HeapProfileCollected1.Copy() + p.DurationNanos = 5e9 + p.SampleType = []*profile.ValueType{ + {Type: "alloc_objects", Unit: "count"}, + {Type: "alloc_space", Unit: "bytes"}, + } + p.Sample[0].Value = []int64{1, 16} + return p +}() diff --git a/vendor/cloud.google.com/go/pubsub/apiv1/ListTopics_smoke_test.go b/vendor/cloud.google.com/go/pubsub/apiv1/ListTopics_smoke_test.go new file mode 100644 index 00000000..991d0a94 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/apiv1/ListTopics_smoke_test.go @@ -0,0 +1,67 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package pubsub + +import ( + pubsubpb "google.golang.org/genproto/googleapis/pubsub/v1" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestPublisherSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewPublisherClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var formattedProject string = fmt.Sprintf("projects/%s", projectId) + var request = &pubsubpb.ListTopicsRequest{ + Project: formattedProject, + } + + iter := c.ListTopics(ctx, request) + if _, err := iter.Next(); err != nil && err != iterator.Done { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/pubsub/apiv1/README.md b/vendor/cloud.google.com/go/pubsub/apiv1/README.md new file mode 100644 index 00000000..b5967ab9 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/apiv1/README.md @@ -0,0 +1,9 @@ +Auto-generated pubsub v1 clients +================================= + +This package includes auto-generated clients for the pubsub v1 API. + +Use the handwritten client (in the parent directory, +cloud.google.com/go/pubsub) in preference to this. + +This code is EXPERIMENTAL and subject to CHANGE AT ANY TIME. diff --git a/vendor/cloud.google.com/go/pubsub/apiv1/doc.go b/vendor/cloud.google.com/go/pubsub/apiv1/doc.go new file mode 100644 index 00000000..5081693f --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/apiv1/doc.go @@ -0,0 +1,93 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package pubsub is an auto-generated package for the +// Google Cloud Pub/Sub API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Provides reliable, many-to-many, asynchronous messaging between +// applications. +// +// Use the client at cloud.google.com/go/pubsub in preference to this. +package pubsub // import "cloud.google.com/go/pubsub/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/pubsub", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/pubsub/apiv1/iam.go b/vendor/cloud.google.com/go/pubsub/apiv1/iam.go new file mode 100644 index 00000000..4a0c231d --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/apiv1/iam.go @@ -0,0 +1,36 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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 pubsub + +import ( + "cloud.google.com/go/iam" + pubsubpb "google.golang.org/genproto/googleapis/pubsub/v1" +) + +func (c *PublisherClient) SubscriptionIAM(subscription *pubsubpb.Subscription) *iam.Handle { + return iam.InternalNewHandle(c.Connection(), subscription.Name) +} + +func (c *PublisherClient) TopicIAM(topic *pubsubpb.Topic) *iam.Handle { + return iam.InternalNewHandle(c.Connection(), topic.Name) +} + +func (c *SubscriberClient) SubscriptionIAM(subscription *pubsubpb.Subscription) *iam.Handle { + return iam.InternalNewHandle(c.Connection(), subscription.Name) +} + +func (c *SubscriberClient) TopicIAM(topic *pubsubpb.Topic) *iam.Handle { + return iam.InternalNewHandle(c.Connection(), topic.Name) +} diff --git a/vendor/cloud.google.com/go/pubsub/apiv1/mock_test.go b/vendor/cloud.google.com/go/pubsub/apiv1/mock_test.go new file mode 100644 index 00000000..6dee0d81 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/apiv1/mock_test.go @@ -0,0 +1,1878 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package pubsub + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + timestamppb "github.com/golang/protobuf/ptypes/timestamp" + iampb "google.golang.org/genproto/googleapis/iam/v1" + pubsubpb "google.golang.org/genproto/googleapis/pubsub/v1" + field_maskpb "google.golang.org/genproto/protobuf/field_mask" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockPublisherServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + pubsubpb.PublisherServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockPublisherServer) CreateTopic(ctx context.Context, req *pubsubpb.Topic) (*pubsubpb.Topic, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.Topic), nil +} + +func (s *mockPublisherServer) UpdateTopic(ctx context.Context, req *pubsubpb.UpdateTopicRequest) (*pubsubpb.Topic, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.Topic), nil +} + +func (s *mockPublisherServer) Publish(ctx context.Context, req *pubsubpb.PublishRequest) (*pubsubpb.PublishResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.PublishResponse), nil +} + +func (s *mockPublisherServer) GetTopic(ctx context.Context, req *pubsubpb.GetTopicRequest) (*pubsubpb.Topic, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.Topic), nil +} + +func (s *mockPublisherServer) ListTopics(ctx context.Context, req *pubsubpb.ListTopicsRequest) (*pubsubpb.ListTopicsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.ListTopicsResponse), nil +} + +func (s *mockPublisherServer) ListTopicSubscriptions(ctx context.Context, req *pubsubpb.ListTopicSubscriptionsRequest) (*pubsubpb.ListTopicSubscriptionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.ListTopicSubscriptionsResponse), nil +} + +func (s *mockPublisherServer) DeleteTopic(ctx context.Context, req *pubsubpb.DeleteTopicRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +type mockIamPolicyServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + iampb.IAMPolicyServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockIamPolicyServer) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockIamPolicyServer) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockIamPolicyServer) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest) (*iampb.TestIamPermissionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.TestIamPermissionsResponse), nil +} + +type mockSubscriberServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + pubsubpb.SubscriberServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockSubscriberServer) CreateSubscription(ctx context.Context, req *pubsubpb.Subscription) (*pubsubpb.Subscription, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.Subscription), nil +} + +func (s *mockSubscriberServer) GetSubscription(ctx context.Context, req *pubsubpb.GetSubscriptionRequest) (*pubsubpb.Subscription, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.Subscription), nil +} + +func (s *mockSubscriberServer) UpdateSubscription(ctx context.Context, req *pubsubpb.UpdateSubscriptionRequest) (*pubsubpb.Subscription, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.Subscription), nil +} + +func (s *mockSubscriberServer) ListSubscriptions(ctx context.Context, req *pubsubpb.ListSubscriptionsRequest) (*pubsubpb.ListSubscriptionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.ListSubscriptionsResponse), nil +} + +func (s *mockSubscriberServer) DeleteSubscription(ctx context.Context, req *pubsubpb.DeleteSubscriptionRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockSubscriberServer) ModifyAckDeadline(ctx context.Context, req *pubsubpb.ModifyAckDeadlineRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockSubscriberServer) Acknowledge(ctx context.Context, req *pubsubpb.AcknowledgeRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockSubscriberServer) Pull(ctx context.Context, req *pubsubpb.PullRequest) (*pubsubpb.PullResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.PullResponse), nil +} + +func (s *mockSubscriberServer) StreamingPull(stream pubsubpb.Subscriber_StreamingPullServer) error { + md, _ := metadata.FromIncomingContext(stream.Context()) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + for { + if req, err := stream.Recv(); err == io.EOF { + break + } else if err != nil { + return err + } else { + s.reqs = append(s.reqs, req) + } + } + if s.err != nil { + return s.err + } + for _, v := range s.resps { + if err := stream.Send(v.(*pubsubpb.StreamingPullResponse)); err != nil { + return err + } + } + return nil +} + +func (s *mockSubscriberServer) ModifyPushConfig(ctx context.Context, req *pubsubpb.ModifyPushConfigRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockSubscriberServer) ListSnapshots(ctx context.Context, req *pubsubpb.ListSnapshotsRequest) (*pubsubpb.ListSnapshotsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.ListSnapshotsResponse), nil +} + +func (s *mockSubscriberServer) CreateSnapshot(ctx context.Context, req *pubsubpb.CreateSnapshotRequest) (*pubsubpb.Snapshot, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.Snapshot), nil +} + +func (s *mockSubscriberServer) UpdateSnapshot(ctx context.Context, req *pubsubpb.UpdateSnapshotRequest) (*pubsubpb.Snapshot, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.Snapshot), nil +} + +func (s *mockSubscriberServer) DeleteSnapshot(ctx context.Context, req *pubsubpb.DeleteSnapshotRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockSubscriberServer) Seek(ctx context.Context, req *pubsubpb.SeekRequest) (*pubsubpb.SeekResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*pubsubpb.SeekResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockPublisher mockPublisherServer + mockIamPolicy mockIamPolicyServer + mockSubscriber mockSubscriberServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + pubsubpb.RegisterPublisherServer(serv, &mockPublisher) + iampb.RegisterIAMPolicyServer(serv, &mockIamPolicy) + pubsubpb.RegisterSubscriberServer(serv, &mockSubscriber) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestPublisherCreateTopic(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &pubsubpb.Topic{ + Name: name2, + } + + mockPublisher.err = nil + mockPublisher.reqs = nil + + mockPublisher.resps = append(mockPublisher.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/topics/%s", "[PROJECT]", "[TOPIC]") + var request = &pubsubpb.Topic{ + Name: formattedName, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateTopic(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockPublisher.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestPublisherCreateTopicError(t *testing.T) { + errCode := codes.PermissionDenied + mockPublisher.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/topics/%s", "[PROJECT]", "[TOPIC]") + var request = &pubsubpb.Topic{ + Name: formattedName, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateTopic(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestPublisherUpdateTopic(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &pubsubpb.Topic{ + Name: name, + } + + mockPublisher.err = nil + mockPublisher.reqs = nil + + mockPublisher.resps = append(mockPublisher.resps[:0], expectedResponse) + + var topic *pubsubpb.Topic = &pubsubpb.Topic{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &pubsubpb.UpdateTopicRequest{ + Topic: topic, + UpdateMask: updateMask, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateTopic(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockPublisher.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestPublisherUpdateTopicError(t *testing.T) { + errCode := codes.PermissionDenied + mockPublisher.err = gstatus.Error(errCode, "test error") + + var topic *pubsubpb.Topic = &pubsubpb.Topic{} + var updateMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &pubsubpb.UpdateTopicRequest{ + Topic: topic, + UpdateMask: updateMask, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateTopic(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestPublisherPublish(t *testing.T) { + var messageIdsElement string = "messageIdsElement-744837059" + var messageIds = []string{messageIdsElement} + var expectedResponse = &pubsubpb.PublishResponse{ + MessageIds: messageIds, + } + + mockPublisher.err = nil + mockPublisher.reqs = nil + + mockPublisher.resps = append(mockPublisher.resps[:0], expectedResponse) + + var formattedTopic string = fmt.Sprintf("projects/%s/topics/%s", "[PROJECT]", "[TOPIC]") + var data []byte = []byte("-86") + var messagesElement = &pubsubpb.PubsubMessage{ + Data: data, + } + var messages = []*pubsubpb.PubsubMessage{messagesElement} + var request = &pubsubpb.PublishRequest{ + Topic: formattedTopic, + Messages: messages, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Publish(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockPublisher.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestPublisherPublishError(t *testing.T) { + errCode := codes.PermissionDenied + mockPublisher.err = gstatus.Error(errCode, "test error") + + var formattedTopic string = fmt.Sprintf("projects/%s/topics/%s", "[PROJECT]", "[TOPIC]") + var data []byte = []byte("-86") + var messagesElement = &pubsubpb.PubsubMessage{ + Data: data, + } + var messages = []*pubsubpb.PubsubMessage{messagesElement} + var request = &pubsubpb.PublishRequest{ + Topic: formattedTopic, + Messages: messages, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Publish(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestPublisherGetTopic(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &pubsubpb.Topic{ + Name: name, + } + + mockPublisher.err = nil + mockPublisher.reqs = nil + + mockPublisher.resps = append(mockPublisher.resps[:0], expectedResponse) + + var formattedTopic string = fmt.Sprintf("projects/%s/topics/%s", "[PROJECT]", "[TOPIC]") + var request = &pubsubpb.GetTopicRequest{ + Topic: formattedTopic, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetTopic(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockPublisher.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestPublisherGetTopicError(t *testing.T) { + errCode := codes.PermissionDenied + mockPublisher.err = gstatus.Error(errCode, "test error") + + var formattedTopic string = fmt.Sprintf("projects/%s/topics/%s", "[PROJECT]", "[TOPIC]") + var request = &pubsubpb.GetTopicRequest{ + Topic: formattedTopic, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetTopic(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestPublisherListTopics(t *testing.T) { + var nextPageToken string = "" + var topicsElement *pubsubpb.Topic = &pubsubpb.Topic{} + var topics = []*pubsubpb.Topic{topicsElement} + var expectedResponse = &pubsubpb.ListTopicsResponse{ + NextPageToken: nextPageToken, + Topics: topics, + } + + mockPublisher.err = nil + mockPublisher.reqs = nil + + mockPublisher.resps = append(mockPublisher.resps[:0], expectedResponse) + + var formattedProject string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &pubsubpb.ListTopicsRequest{ + Project: formattedProject, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTopics(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockPublisher.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Topics[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestPublisherListTopicsError(t *testing.T) { + errCode := codes.PermissionDenied + mockPublisher.err = gstatus.Error(errCode, "test error") + + var formattedProject string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &pubsubpb.ListTopicsRequest{ + Project: formattedProject, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTopics(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestPublisherListTopicSubscriptions(t *testing.T) { + var nextPageToken string = "" + var subscriptionsElement string = "subscriptionsElement1698708147" + var subscriptions = []string{subscriptionsElement} + var expectedResponse = &pubsubpb.ListTopicSubscriptionsResponse{ + NextPageToken: nextPageToken, + Subscriptions: subscriptions, + } + + mockPublisher.err = nil + mockPublisher.reqs = nil + + mockPublisher.resps = append(mockPublisher.resps[:0], expectedResponse) + + var formattedTopic string = fmt.Sprintf("projects/%s/topics/%s", "[PROJECT]", "[TOPIC]") + var request = &pubsubpb.ListTopicSubscriptionsRequest{ + Topic: formattedTopic, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTopicSubscriptions(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockPublisher.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Subscriptions[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestPublisherListTopicSubscriptionsError(t *testing.T) { + errCode := codes.PermissionDenied + mockPublisher.err = gstatus.Error(errCode, "test error") + + var formattedTopic string = fmt.Sprintf("projects/%s/topics/%s", "[PROJECT]", "[TOPIC]") + var request = &pubsubpb.ListTopicSubscriptionsRequest{ + Topic: formattedTopic, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTopicSubscriptions(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestPublisherDeleteTopic(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockPublisher.err = nil + mockPublisher.reqs = nil + + mockPublisher.resps = append(mockPublisher.resps[:0], expectedResponse) + + var formattedTopic string = fmt.Sprintf("projects/%s/topics/%s", "[PROJECT]", "[TOPIC]") + var request = &pubsubpb.DeleteTopicRequest{ + Topic: formattedTopic, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteTopic(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockPublisher.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestPublisherDeleteTopicError(t *testing.T) { + errCode := codes.PermissionDenied + mockPublisher.err = gstatus.Error(errCode, "test error") + + var formattedTopic string = fmt.Sprintf("projects/%s/topics/%s", "[PROJECT]", "[TOPIC]") + var request = &pubsubpb.DeleteTopicRequest{ + Topic: formattedTopic, + } + + c, err := NewPublisherClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteTopic(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestSubscriberCreateSubscription(t *testing.T) { + var name2 string = "name2-1052831874" + var topic2 string = "topic2-1139259102" + var ackDeadlineSeconds int32 = 2135351438 + var retainAckedMessages bool = false + var expectedResponse = &pubsubpb.Subscription{ + Name: name2, + Topic: topic2, + AckDeadlineSeconds: ackDeadlineSeconds, + RetainAckedMessages: retainAckedMessages, + } + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var formattedTopic string = fmt.Sprintf("projects/%s/topics/%s", "[PROJECT]", "[TOPIC]") + var request = &pubsubpb.Subscription{ + Name: formattedName, + Topic: formattedTopic, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSubscription(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSubscriberCreateSubscriptionError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var formattedTopic string = fmt.Sprintf("projects/%s/topics/%s", "[PROJECT]", "[TOPIC]") + var request = &pubsubpb.Subscription{ + Name: formattedName, + Topic: formattedTopic, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSubscription(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSubscriberGetSubscription(t *testing.T) { + var name string = "name3373707" + var topic string = "topic110546223" + var ackDeadlineSeconds int32 = 2135351438 + var retainAckedMessages bool = false + var expectedResponse = &pubsubpb.Subscription{ + Name: name, + Topic: topic, + AckDeadlineSeconds: ackDeadlineSeconds, + RetainAckedMessages: retainAckedMessages, + } + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var request = &pubsubpb.GetSubscriptionRequest{ + Subscription: formattedSubscription, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSubscription(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSubscriberGetSubscriptionError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var request = &pubsubpb.GetSubscriptionRequest{ + Subscription: formattedSubscription, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSubscription(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSubscriberUpdateSubscription(t *testing.T) { + var name string = "name3373707" + var topic string = "topic110546223" + var ackDeadlineSeconds2 int32 = 921632575 + var retainAckedMessages bool = false + var expectedResponse = &pubsubpb.Subscription{ + Name: name, + Topic: topic, + AckDeadlineSeconds: ackDeadlineSeconds2, + RetainAckedMessages: retainAckedMessages, + } + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var ackDeadlineSeconds int32 = 42 + var subscription = &pubsubpb.Subscription{ + AckDeadlineSeconds: ackDeadlineSeconds, + } + var pathsElement string = "ack_deadline_seconds" + var paths = []string{pathsElement} + var updateMask = &field_maskpb.FieldMask{ + Paths: paths, + } + var request = &pubsubpb.UpdateSubscriptionRequest{ + Subscription: subscription, + UpdateMask: updateMask, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSubscription(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSubscriberUpdateSubscriptionError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var ackDeadlineSeconds int32 = 42 + var subscription = &pubsubpb.Subscription{ + AckDeadlineSeconds: ackDeadlineSeconds, + } + var pathsElement string = "ack_deadline_seconds" + var paths = []string{pathsElement} + var updateMask = &field_maskpb.FieldMask{ + Paths: paths, + } + var request = &pubsubpb.UpdateSubscriptionRequest{ + Subscription: subscription, + UpdateMask: updateMask, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSubscription(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSubscriberListSubscriptions(t *testing.T) { + var nextPageToken string = "" + var subscriptionsElement *pubsubpb.Subscription = &pubsubpb.Subscription{} + var subscriptions = []*pubsubpb.Subscription{subscriptionsElement} + var expectedResponse = &pubsubpb.ListSubscriptionsResponse{ + NextPageToken: nextPageToken, + Subscriptions: subscriptions, + } + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var formattedProject string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &pubsubpb.ListSubscriptionsRequest{ + Project: formattedProject, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListSubscriptions(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Subscriptions[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSubscriberListSubscriptionsError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var formattedProject string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &pubsubpb.ListSubscriptionsRequest{ + Project: formattedProject, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListSubscriptions(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSubscriberDeleteSubscription(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var request = &pubsubpb.DeleteSubscriptionRequest{ + Subscription: formattedSubscription, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSubscription(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestSubscriberDeleteSubscriptionError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var request = &pubsubpb.DeleteSubscriptionRequest{ + Subscription: formattedSubscription, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSubscription(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestSubscriberModifyAckDeadline(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var ackIds []string = nil + var ackDeadlineSeconds int32 = 2135351438 + var request = &pubsubpb.ModifyAckDeadlineRequest{ + Subscription: formattedSubscription, + AckIds: ackIds, + AckDeadlineSeconds: ackDeadlineSeconds, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.ModifyAckDeadline(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestSubscriberModifyAckDeadlineError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var ackIds []string = nil + var ackDeadlineSeconds int32 = 2135351438 + var request = &pubsubpb.ModifyAckDeadlineRequest{ + Subscription: formattedSubscription, + AckIds: ackIds, + AckDeadlineSeconds: ackDeadlineSeconds, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.ModifyAckDeadline(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestSubscriberAcknowledge(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var ackIds []string = nil + var request = &pubsubpb.AcknowledgeRequest{ + Subscription: formattedSubscription, + AckIds: ackIds, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.Acknowledge(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestSubscriberAcknowledgeError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var ackIds []string = nil + var request = &pubsubpb.AcknowledgeRequest{ + Subscription: formattedSubscription, + AckIds: ackIds, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.Acknowledge(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestSubscriberPull(t *testing.T) { + var expectedResponse *pubsubpb.PullResponse = &pubsubpb.PullResponse{} + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var maxMessages int32 = 496131527 + var request = &pubsubpb.PullRequest{ + Subscription: formattedSubscription, + MaxMessages: maxMessages, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Pull(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSubscriberPullError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var maxMessages int32 = 496131527 + var request = &pubsubpb.PullRequest{ + Subscription: formattedSubscription, + MaxMessages: maxMessages, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Pull(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSubscriberStreamingPull(t *testing.T) { + var receivedMessagesElement *pubsubpb.ReceivedMessage = &pubsubpb.ReceivedMessage{} + var receivedMessages = []*pubsubpb.ReceivedMessage{receivedMessagesElement} + var expectedResponse = &pubsubpb.StreamingPullResponse{ + ReceivedMessages: receivedMessages, + } + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var streamAckDeadlineSeconds int32 = 1875467245 + var request = &pubsubpb.StreamingPullRequest{ + Subscription: formattedSubscription, + StreamAckDeadlineSeconds: streamAckDeadlineSeconds, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.StreamingPull(context.Background()) + if err != nil { + t.Fatal(err) + } + if err := stream.Send(request); err != nil { + t.Fatal(err) + } + if err := stream.CloseSend(); err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSubscriberStreamingPullError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var streamAckDeadlineSeconds int32 = 1875467245 + var request = &pubsubpb.StreamingPullRequest{ + Subscription: formattedSubscription, + StreamAckDeadlineSeconds: streamAckDeadlineSeconds, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.StreamingPull(context.Background()) + if err != nil { + t.Fatal(err) + } + if err := stream.Send(request); err != nil { + t.Fatal(err) + } + if err := stream.CloseSend(); err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSubscriberModifyPushConfig(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var pushConfig *pubsubpb.PushConfig = &pubsubpb.PushConfig{} + var request = &pubsubpb.ModifyPushConfigRequest{ + Subscription: formattedSubscription, + PushConfig: pushConfig, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.ModifyPushConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestSubscriberModifyPushConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var pushConfig *pubsubpb.PushConfig = &pubsubpb.PushConfig{} + var request = &pubsubpb.ModifyPushConfigRequest{ + Subscription: formattedSubscription, + PushConfig: pushConfig, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.ModifyPushConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestSubscriberListSnapshots(t *testing.T) { + var nextPageToken string = "" + var snapshotsElement *pubsubpb.Snapshot = &pubsubpb.Snapshot{} + var snapshots = []*pubsubpb.Snapshot{snapshotsElement} + var expectedResponse = &pubsubpb.ListSnapshotsResponse{ + NextPageToken: nextPageToken, + Snapshots: snapshots, + } + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var formattedProject string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &pubsubpb.ListSnapshotsRequest{ + Project: formattedProject, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListSnapshots(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Snapshots[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSubscriberListSnapshotsError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var formattedProject string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &pubsubpb.ListSnapshotsRequest{ + Project: formattedProject, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListSnapshots(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSubscriberCreateSnapshot(t *testing.T) { + var name2 string = "name2-1052831874" + var topic string = "topic110546223" + var expectedResponse = &pubsubpb.Snapshot{ + Name: name2, + Topic: topic, + } + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/snapshots/%s", "[PROJECT]", "[SNAPSHOT]") + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var request = &pubsubpb.CreateSnapshotRequest{ + Name: formattedName, + Subscription: formattedSubscription, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSnapshot(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSubscriberCreateSnapshotError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/snapshots/%s", "[PROJECT]", "[SNAPSHOT]") + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var request = &pubsubpb.CreateSnapshotRequest{ + Name: formattedName, + Subscription: formattedSubscription, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSnapshot(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSubscriberUpdateSnapshot(t *testing.T) { + var name string = "name3373707" + var topic string = "topic110546223" + var expectedResponse = &pubsubpb.Snapshot{ + Name: name, + Topic: topic, + } + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var seconds int64 = 123456 + var expireTime = ×tamppb.Timestamp{ + Seconds: seconds, + } + var snapshot = &pubsubpb.Snapshot{ + ExpireTime: expireTime, + } + var pathsElement string = "expire_time" + var paths = []string{pathsElement} + var updateMask = &field_maskpb.FieldMask{ + Paths: paths, + } + var request = &pubsubpb.UpdateSnapshotRequest{ + Snapshot: snapshot, + UpdateMask: updateMask, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSnapshot(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSubscriberUpdateSnapshotError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var seconds int64 = 123456 + var expireTime = ×tamppb.Timestamp{ + Seconds: seconds, + } + var snapshot = &pubsubpb.Snapshot{ + ExpireTime: expireTime, + } + var pathsElement string = "expire_time" + var paths = []string{pathsElement} + var updateMask = &field_maskpb.FieldMask{ + Paths: paths, + } + var request = &pubsubpb.UpdateSnapshotRequest{ + Snapshot: snapshot, + UpdateMask: updateMask, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSnapshot(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSubscriberDeleteSnapshot(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var formattedSnapshot string = fmt.Sprintf("projects/%s/snapshots/%s", "[PROJECT]", "[SNAPSHOT]") + var request = &pubsubpb.DeleteSnapshotRequest{ + Snapshot: formattedSnapshot, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSnapshot(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestSubscriberDeleteSnapshotError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var formattedSnapshot string = fmt.Sprintf("projects/%s/snapshots/%s", "[PROJECT]", "[SNAPSHOT]") + var request = &pubsubpb.DeleteSnapshotRequest{ + Snapshot: formattedSnapshot, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSnapshot(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestSubscriberSeek(t *testing.T) { + var expectedResponse *pubsubpb.SeekResponse = &pubsubpb.SeekResponse{} + + mockSubscriber.err = nil + mockSubscriber.reqs = nil + + mockSubscriber.resps = append(mockSubscriber.resps[:0], expectedResponse) + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var request = &pubsubpb.SeekRequest{ + Subscription: formattedSubscription, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Seek(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSubscriber.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSubscriberSeekError(t *testing.T) { + errCode := codes.PermissionDenied + mockSubscriber.err = gstatus.Error(errCode, "test error") + + var formattedSubscription string = fmt.Sprintf("projects/%s/subscriptions/%s", "[PROJECT]", "[SUBSCRIPTION]") + var request = &pubsubpb.SeekRequest{ + Subscription: formattedSubscription, + } + + c, err := NewSubscriberClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Seek(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/pubsub/apiv1/path_funcs.go b/vendor/cloud.google.com/go/pubsub/apiv1/path_funcs.go new file mode 100644 index 00000000..b9ab4848 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/apiv1/path_funcs.go @@ -0,0 +1,95 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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 pubsub + +// PublisherProjectPath returns the path for the project resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s", project) +// instead. +func PublisherProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} + +// PublisherTopicPath returns the path for the topic resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/topics/%s", project, topic) +// instead. +func PublisherTopicPath(project, topic string) string { + return "" + + "projects/" + + project + + "/topics/" + + topic + + "" +} + +// SubscriberProjectPath returns the path for the project resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s", project) +// instead. +func SubscriberProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} + +// SubscriberSnapshotPath returns the path for the snapshot resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/snapshots/%s", project, snapshot) +// instead. +func SubscriberSnapshotPath(project, snapshot string) string { + return "" + + "projects/" + + project + + "/snapshots/" + + snapshot + + "" +} + +// SubscriberSubscriptionPath returns the path for the subscription resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/subscriptions/%s", project, subscription) +// instead. +func SubscriberSubscriptionPath(project, subscription string) string { + return "" + + "projects/" + + project + + "/subscriptions/" + + subscription + + "" +} + +// SubscriberTopicPath returns the path for the topic resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/topics/%s", project, topic) +// instead. +func SubscriberTopicPath(project, topic string) string { + return "" + + "projects/" + + project + + "/topics/" + + topic + + "" +} diff --git a/vendor/cloud.google.com/go/pubsub/apiv1/publisher_client.go b/vendor/cloud.google.com/go/pubsub/apiv1/publisher_client.go new file mode 100644 index 00000000..c33566e6 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/apiv1/publisher_client.go @@ -0,0 +1,391 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package pubsub + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + pubsubpb "google.golang.org/genproto/googleapis/pubsub/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// PublisherCallOptions contains the retry settings for each method of PublisherClient. +type PublisherCallOptions struct { + CreateTopic []gax.CallOption + UpdateTopic []gax.CallOption + Publish []gax.CallOption + GetTopic []gax.CallOption + ListTopics []gax.CallOption + ListTopicSubscriptions []gax.CallOption + DeleteTopic []gax.CallOption +} + +func defaultPublisherClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("pubsub.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultPublisherCallOptions() *PublisherCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + {"messaging", "one_plus_delivery"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.Aborted, + codes.Canceled, + codes.DeadlineExceeded, + codes.Internal, + codes.ResourceExhausted, + codes.Unavailable, + codes.Unknown, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &PublisherCallOptions{ + CreateTopic: retry[[2]string{"default", "idempotent"}], + UpdateTopic: retry[[2]string{"default", "idempotent"}], + Publish: retry[[2]string{"messaging", "one_plus_delivery"}], + GetTopic: retry[[2]string{"default", "idempotent"}], + ListTopics: retry[[2]string{"default", "idempotent"}], + ListTopicSubscriptions: retry[[2]string{"default", "idempotent"}], + DeleteTopic: retry[[2]string{"default", "idempotent"}], + } +} + +// PublisherClient is a client for interacting with Google Cloud Pub/Sub API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type PublisherClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + publisherClient pubsubpb.PublisherClient + + // The call options for this service. + CallOptions *PublisherCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewPublisherClient creates a new publisher client. +// +// The service that an application uses to manipulate topics, and to send +// messages to a topic. +func NewPublisherClient(ctx context.Context, opts ...option.ClientOption) (*PublisherClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultPublisherClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &PublisherClient{ + conn: conn, + CallOptions: defaultPublisherCallOptions(), + + publisherClient: pubsubpb.NewPublisherClient(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *PublisherClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *PublisherClient) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *PublisherClient) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// CreateTopic creates the given topic with the given name. See the +// resource name rules. +func (c *PublisherClient) CreateTopic(ctx context.Context, req *pubsubpb.Topic, opts ...gax.CallOption) (*pubsubpb.Topic, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateTopic[0:len(c.CallOptions.CreateTopic):len(c.CallOptions.CreateTopic)], opts...) + var resp *pubsubpb.Topic + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.publisherClient.CreateTopic(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateTopic updates an existing topic. Note that certain properties of a +// topic are not modifiable. +func (c *PublisherClient) UpdateTopic(ctx context.Context, req *pubsubpb.UpdateTopicRequest, opts ...gax.CallOption) (*pubsubpb.Topic, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateTopic[0:len(c.CallOptions.UpdateTopic):len(c.CallOptions.UpdateTopic)], opts...) + var resp *pubsubpb.Topic + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.publisherClient.UpdateTopic(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Publish adds one or more messages to the topic. Returns NOT_FOUND if the topic +// does not exist. +func (c *PublisherClient) Publish(ctx context.Context, req *pubsubpb.PublishRequest, opts ...gax.CallOption) (*pubsubpb.PublishResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Publish[0:len(c.CallOptions.Publish):len(c.CallOptions.Publish)], opts...) + var resp *pubsubpb.PublishResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.publisherClient.Publish(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetTopic gets the configuration of a topic. +func (c *PublisherClient) GetTopic(ctx context.Context, req *pubsubpb.GetTopicRequest, opts ...gax.CallOption) (*pubsubpb.Topic, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetTopic[0:len(c.CallOptions.GetTopic):len(c.CallOptions.GetTopic)], opts...) + var resp *pubsubpb.Topic + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.publisherClient.GetTopic(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListTopics lists matching topics. +func (c *PublisherClient) ListTopics(ctx context.Context, req *pubsubpb.ListTopicsRequest, opts ...gax.CallOption) *TopicIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListTopics[0:len(c.CallOptions.ListTopics):len(c.CallOptions.ListTopics)], opts...) + it := &TopicIterator{} + req = proto.Clone(req).(*pubsubpb.ListTopicsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*pubsubpb.Topic, string, error) { + var resp *pubsubpb.ListTopicsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.publisherClient.ListTopics(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Topics, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// ListTopicSubscriptions lists the names of the subscriptions on this topic. +func (c *PublisherClient) ListTopicSubscriptions(ctx context.Context, req *pubsubpb.ListTopicSubscriptionsRequest, opts ...gax.CallOption) *StringIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListTopicSubscriptions[0:len(c.CallOptions.ListTopicSubscriptions):len(c.CallOptions.ListTopicSubscriptions)], opts...) + it := &StringIterator{} + req = proto.Clone(req).(*pubsubpb.ListTopicSubscriptionsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]string, string, error) { + var resp *pubsubpb.ListTopicSubscriptionsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.publisherClient.ListTopicSubscriptions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Subscriptions, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DeleteTopic deletes the topic with the given name. Returns NOT_FOUND if the topic +// does not exist. After a topic is deleted, a new topic may be created with +// the same name; this is an entirely new topic with none of the old +// configuration or subscriptions. Existing subscriptions to this topic are +// not deleted, but their topic field is set to _deleted-topic_. +func (c *PublisherClient) DeleteTopic(ctx context.Context, req *pubsubpb.DeleteTopicRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteTopic[0:len(c.CallOptions.DeleteTopic):len(c.CallOptions.DeleteTopic)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.publisherClient.DeleteTopic(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// StringIterator manages a stream of string. +type StringIterator struct { + items []string + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []string, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *StringIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *StringIterator) Next() (string, error) { + var item string + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *StringIterator) bufLen() int { + return len(it.items) +} + +func (it *StringIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// TopicIterator manages a stream of *pubsubpb.Topic. +type TopicIterator struct { + items []*pubsubpb.Topic + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*pubsubpb.Topic, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TopicIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TopicIterator) Next() (*pubsubpb.Topic, error) { + var item *pubsubpb.Topic + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TopicIterator) bufLen() int { + return len(it.items) +} + +func (it *TopicIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/pubsub/apiv1/publisher_client_example_test.go b/vendor/cloud.google.com/go/pubsub/apiv1/publisher_client_example_test.go new file mode 100644 index 00000000..560623ad --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/apiv1/publisher_client_example_test.go @@ -0,0 +1,171 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package pubsub_test + +import ( + "context" + + pubsub "cloud.google.com/go/pubsub/apiv1" + "google.golang.org/api/iterator" + pubsubpb "google.golang.org/genproto/googleapis/pubsub/v1" +) + +func ExampleNewPublisherClient() { + ctx := context.Background() + c, err := pubsub.NewPublisherClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExamplePublisherClient_CreateTopic() { + ctx := context.Background() + c, err := pubsub.NewPublisherClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.Topic{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateTopic(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExamplePublisherClient_UpdateTopic() { + ctx := context.Background() + c, err := pubsub.NewPublisherClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.UpdateTopicRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateTopic(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExamplePublisherClient_Publish() { + ctx := context.Background() + c, err := pubsub.NewPublisherClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.PublishRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Publish(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExamplePublisherClient_GetTopic() { + ctx := context.Background() + c, err := pubsub.NewPublisherClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.GetTopicRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetTopic(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExamplePublisherClient_ListTopics() { + ctx := context.Background() + c, err := pubsub.NewPublisherClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.ListTopicsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListTopics(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExamplePublisherClient_ListTopicSubscriptions() { + ctx := context.Background() + c, err := pubsub.NewPublisherClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.ListTopicSubscriptionsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListTopicSubscriptions(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExamplePublisherClient_DeleteTopic() { + ctx := context.Background() + c, err := pubsub.NewPublisherClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.DeleteTopicRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteTopic(ctx, req) + if err != nil { + // TODO: Handle error. + } +} diff --git a/vendor/cloud.google.com/go/pubsub/apiv1/pubsub_pull_example_test.go b/vendor/cloud.google.com/go/pubsub/apiv1/pubsub_pull_example_test.go new file mode 100644 index 00000000..c44a473a --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/apiv1/pubsub_pull_example_test.go @@ -0,0 +1,106 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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 pubsub_test + +import ( + "context" + "fmt" + "log" + "time" + + pubsub "cloud.google.com/go/pubsub/apiv1" + pubsubpb "google.golang.org/genproto/googleapis/pubsub/v1" +) + +func ExampleSubscriberClient_Pull_lengthyClientProcessing() { + projectID := "some-project" + subscriptionID := "some-subscription" + + ctx := context.Background() + client, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + log.Fatal(err) + } + defer client.Close() + + sub := fmt.Sprintf("projects/%s/subscriptions/%s", projectID, subscriptionID) + // Be sure to tune the MaxMessages parameter per your project's needs, and accordingly + // adjust the ack behavior below to batch acknowledgements. + req := pubsubpb.PullRequest{ + Subscription: sub, + MaxMessages: 1, + } + + fmt.Println("Listening..") + + for { + res, err := client.Pull(ctx, &req) + if err != nil { + log.Fatal(err) + } + + // client.Pull returns an empty list if there are no messages available in the + // backlog. We should skip processing steps when that happens. + if len(res.ReceivedMessages) == 0 { + continue + } + + var recvdAckIDs []string + for _, m := range res.ReceivedMessages { + recvdAckIDs = append(recvdAckIDs, m.AckId) + } + + var done = make(chan struct{}) + var delay = 0 * time.Second // Tick immediately upon reception + var ackDeadline = 10 * time.Second + + // Continuously notify the server that processing is still happening on this batch. + go func() { + for { + select { + case <-ctx.Done(): + return + case <-done: + return + case <-time.After(delay): + err := client.ModifyAckDeadline(ctx, &pubsubpb.ModifyAckDeadlineRequest{ + Subscription: sub, + AckIds: recvdAckIDs, + AckDeadlineSeconds: int32(ackDeadline.Seconds()), + }) + if err != nil { + log.Fatal(err) + } + delay = ackDeadline - 5*time.Second // 5 seconds grace period. + } + } + }() + + for _, m := range res.ReceivedMessages { + // Process the message here, possibly in a goroutine. + log.Printf("Got message: %s", string(m.Message.Data)) + + err := client.Acknowledge(ctx, &pubsubpb.AcknowledgeRequest{ + Subscription: sub, + AckIds: []string{m.AckId}, + }) + if err != nil { + log.Fatal(err) + } + } + + close(done) + } +} diff --git a/vendor/cloud.google.com/go/pubsub/apiv1/subscriber_client.go b/vendor/cloud.google.com/go/pubsub/apiv1/subscriber_client.go new file mode 100644 index 00000000..dd644894 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/apiv1/subscriber_client.go @@ -0,0 +1,606 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package pubsub + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + pubsubpb "google.golang.org/genproto/googleapis/pubsub/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// SubscriberCallOptions contains the retry settings for each method of SubscriberClient. +type SubscriberCallOptions struct { + CreateSubscription []gax.CallOption + GetSubscription []gax.CallOption + UpdateSubscription []gax.CallOption + ListSubscriptions []gax.CallOption + DeleteSubscription []gax.CallOption + ModifyAckDeadline []gax.CallOption + Acknowledge []gax.CallOption + Pull []gax.CallOption + StreamingPull []gax.CallOption + ModifyPushConfig []gax.CallOption + ListSnapshots []gax.CallOption + CreateSnapshot []gax.CallOption + UpdateSnapshot []gax.CallOption + DeleteSnapshot []gax.CallOption + Seek []gax.CallOption +} + +func defaultSubscriberClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("pubsub.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultSubscriberCallOptions() *SubscriberCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + {"messaging", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + {"messaging", "pull"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Internal, + codes.ResourceExhausted, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + {"streaming_messaging", "pull"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Internal, + codes.ResourceExhausted, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &SubscriberCallOptions{ + CreateSubscription: retry[[2]string{"default", "idempotent"}], + GetSubscription: retry[[2]string{"default", "idempotent"}], + UpdateSubscription: retry[[2]string{"default", "idempotent"}], + ListSubscriptions: retry[[2]string{"default", "idempotent"}], + DeleteSubscription: retry[[2]string{"default", "idempotent"}], + ModifyAckDeadline: retry[[2]string{"default", "non_idempotent"}], + Acknowledge: retry[[2]string{"messaging", "idempotent"}], + Pull: retry[[2]string{"messaging", "pull"}], + StreamingPull: retry[[2]string{"streaming_messaging", "pull"}], + ModifyPushConfig: retry[[2]string{"default", "non_idempotent"}], + ListSnapshots: retry[[2]string{"default", "idempotent"}], + CreateSnapshot: retry[[2]string{"default", "idempotent"}], + UpdateSnapshot: retry[[2]string{"default", "idempotent"}], + DeleteSnapshot: retry[[2]string{"default", "idempotent"}], + Seek: retry[[2]string{"default", "non_idempotent"}], + } +} + +// SubscriberClient is a client for interacting with Google Cloud Pub/Sub API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type SubscriberClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + subscriberClient pubsubpb.SubscriberClient + + // The call options for this service. + CallOptions *SubscriberCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewSubscriberClient creates a new subscriber client. +// +// The service that an application uses to manipulate subscriptions and to +// consume messages from a subscription via the Pull method or by +// establishing a bi-directional stream using the StreamingPull method. +func NewSubscriberClient(ctx context.Context, opts ...option.ClientOption) (*SubscriberClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultSubscriberClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &SubscriberClient{ + conn: conn, + CallOptions: defaultSubscriberCallOptions(), + + subscriberClient: pubsubpb.NewSubscriberClient(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *SubscriberClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *SubscriberClient) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *SubscriberClient) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// CreateSubscription creates a subscription to a given topic. See the +// resource name rules. +// If the subscription already exists, returns ALREADY_EXISTS. +// If the corresponding topic doesn't exist, returns NOT_FOUND. +// +// If the name is not provided in the request, the server will assign a random +// name for this subscription on the same project as the topic, conforming +// to the +// resource name format (at https://cloud.google.com/pubsub/docs/overview#names). +// The generated name is populated in the returned Subscription object. +// Note that for REST API requests, you must specify a name in the request. +func (c *SubscriberClient) CreateSubscription(ctx context.Context, req *pubsubpb.Subscription, opts ...gax.CallOption) (*pubsubpb.Subscription, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateSubscription[0:len(c.CallOptions.CreateSubscription):len(c.CallOptions.CreateSubscription)], opts...) + var resp *pubsubpb.Subscription + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.subscriberClient.CreateSubscription(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetSubscription gets the configuration details of a subscription. +func (c *SubscriberClient) GetSubscription(ctx context.Context, req *pubsubpb.GetSubscriptionRequest, opts ...gax.CallOption) (*pubsubpb.Subscription, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetSubscription[0:len(c.CallOptions.GetSubscription):len(c.CallOptions.GetSubscription)], opts...) + var resp *pubsubpb.Subscription + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.subscriberClient.GetSubscription(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateSubscription updates an existing subscription. Note that certain properties of a +// subscription, such as its topic, are not modifiable. +func (c *SubscriberClient) UpdateSubscription(ctx context.Context, req *pubsubpb.UpdateSubscriptionRequest, opts ...gax.CallOption) (*pubsubpb.Subscription, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateSubscription[0:len(c.CallOptions.UpdateSubscription):len(c.CallOptions.UpdateSubscription)], opts...) + var resp *pubsubpb.Subscription + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.subscriberClient.UpdateSubscription(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListSubscriptions lists matching subscriptions. +func (c *SubscriberClient) ListSubscriptions(ctx context.Context, req *pubsubpb.ListSubscriptionsRequest, opts ...gax.CallOption) *SubscriptionIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListSubscriptions[0:len(c.CallOptions.ListSubscriptions):len(c.CallOptions.ListSubscriptions)], opts...) + it := &SubscriptionIterator{} + req = proto.Clone(req).(*pubsubpb.ListSubscriptionsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*pubsubpb.Subscription, string, error) { + var resp *pubsubpb.ListSubscriptionsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.subscriberClient.ListSubscriptions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Subscriptions, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DeleteSubscription deletes an existing subscription. All messages retained in the subscription +// are immediately dropped. Calls to Pull after deletion will return +// NOT_FOUND. After a subscription is deleted, a new one may be created with +// the same name, but the new one has no association with the old +// subscription or its topic unless the same topic is specified. +func (c *SubscriberClient) DeleteSubscription(ctx context.Context, req *pubsubpb.DeleteSubscriptionRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteSubscription[0:len(c.CallOptions.DeleteSubscription):len(c.CallOptions.DeleteSubscription)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.subscriberClient.DeleteSubscription(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ModifyAckDeadline modifies the ack deadline for a specific message. This method is useful +// to indicate that more time is needed to process a message by the +// subscriber, or to make the message available for redelivery if the +// processing was interrupted. Note that this does not modify the +// subscription-level ackDeadlineSeconds used for subsequent messages. +func (c *SubscriberClient) ModifyAckDeadline(ctx context.Context, req *pubsubpb.ModifyAckDeadlineRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ModifyAckDeadline[0:len(c.CallOptions.ModifyAckDeadline):len(c.CallOptions.ModifyAckDeadline)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.subscriberClient.ModifyAckDeadline(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// Acknowledge acknowledges the messages associated with the ack_ids in the +// AcknowledgeRequest. The Pub/Sub system can remove the relevant messages +// from the subscription. +// +// Acknowledging a message whose ack deadline has expired may succeed, +// but such a message may be redelivered later. Acknowledging a message more +// than once will not result in an error. +func (c *SubscriberClient) Acknowledge(ctx context.Context, req *pubsubpb.AcknowledgeRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Acknowledge[0:len(c.CallOptions.Acknowledge):len(c.CallOptions.Acknowledge)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.subscriberClient.Acknowledge(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// Pull pulls messages from the server. The server may return UNAVAILABLE if +// there are too many concurrent pull requests pending for the given +// subscription. +func (c *SubscriberClient) Pull(ctx context.Context, req *pubsubpb.PullRequest, opts ...gax.CallOption) (*pubsubpb.PullResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Pull[0:len(c.CallOptions.Pull):len(c.CallOptions.Pull)], opts...) + var resp *pubsubpb.PullResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.subscriberClient.Pull(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// StreamingPull establishes a stream with the server, which sends messages down to the +// client. The client streams acknowledgements and ack deadline modifications +// back to the server. The server will close the stream and return the status +// on any error. The server may close the stream with status UNAVAILABLE to +// reassign server-side resources, in which case, the client should +// re-establish the stream. Flow control can be achieved by configuring the +// underlying RPC channel. +func (c *SubscriberClient) StreamingPull(ctx context.Context, opts ...gax.CallOption) (pubsubpb.Subscriber_StreamingPullClient, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.StreamingPull[0:len(c.CallOptions.StreamingPull):len(c.CallOptions.StreamingPull)], opts...) + var resp pubsubpb.Subscriber_StreamingPullClient + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.subscriberClient.StreamingPull(ctx, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ModifyPushConfig modifies the PushConfig for a specified subscription. +// +// This may be used to change a push subscription to a pull one (signified by +// an empty PushConfig) or vice versa, or change the endpoint URL and other +// attributes of a push subscription. Messages will accumulate for delivery +// continuously through the call regardless of changes to the PushConfig. +func (c *SubscriberClient) ModifyPushConfig(ctx context.Context, req *pubsubpb.ModifyPushConfigRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ModifyPushConfig[0:len(c.CallOptions.ModifyPushConfig):len(c.CallOptions.ModifyPushConfig)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.subscriberClient.ModifyPushConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ListSnapshots lists the existing snapshots.

+// ALPHA: This feature is part of an alpha release. This API might be +// changed in backward-incompatible ways and is not recommended for production +// use. It is not subject to any SLA or deprecation policy. +func (c *SubscriberClient) ListSnapshots(ctx context.Context, req *pubsubpb.ListSnapshotsRequest, opts ...gax.CallOption) *SnapshotIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListSnapshots[0:len(c.CallOptions.ListSnapshots):len(c.CallOptions.ListSnapshots)], opts...) + it := &SnapshotIterator{} + req = proto.Clone(req).(*pubsubpb.ListSnapshotsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*pubsubpb.Snapshot, string, error) { + var resp *pubsubpb.ListSnapshotsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.subscriberClient.ListSnapshots(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Snapshots, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// CreateSnapshot creates a snapshot from the requested subscription.

+// ALPHA: This feature is part of an alpha release. This API might be +// changed in backward-incompatible ways and is not recommended for production +// use. It is not subject to any SLA or deprecation policy.

+// If the snapshot already exists, returns ALREADY_EXISTS. +// If the requested subscription doesn't exist, returns NOT_FOUND. +// If the backlog in the subscription is too old -- and the resulting snapshot +// would expire in less than 1 hour -- then FAILED_PRECONDITION is returned. +// See also the Snapshot.expire_time field. If the name is not provided in +// the request, the server will assign a random +// name for this snapshot on the same project as the subscription, conforming +// to the resource name format (at https://cloud.google.com/pubsub/docs/overview#names). +// The generated +// name is populated in the returned Snapshot object. Note that for REST API +// requests, you must specify a name in the request. +func (c *SubscriberClient) CreateSnapshot(ctx context.Context, req *pubsubpb.CreateSnapshotRequest, opts ...gax.CallOption) (*pubsubpb.Snapshot, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateSnapshot[0:len(c.CallOptions.CreateSnapshot):len(c.CallOptions.CreateSnapshot)], opts...) + var resp *pubsubpb.Snapshot + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.subscriberClient.CreateSnapshot(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateSnapshot updates an existing snapshot.

+// ALPHA: This feature is part of an alpha release. This API might be +// changed in backward-incompatible ways and is not recommended for production +// use. It is not subject to any SLA or deprecation policy. +// Note that certain properties of a snapshot are not modifiable. +func (c *SubscriberClient) UpdateSnapshot(ctx context.Context, req *pubsubpb.UpdateSnapshotRequest, opts ...gax.CallOption) (*pubsubpb.Snapshot, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateSnapshot[0:len(c.CallOptions.UpdateSnapshot):len(c.CallOptions.UpdateSnapshot)], opts...) + var resp *pubsubpb.Snapshot + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.subscriberClient.UpdateSnapshot(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteSnapshot removes an existing snapshot.

+// ALPHA: This feature is part of an alpha release. This API might be +// changed in backward-incompatible ways and is not recommended for production +// use. It is not subject to any SLA or deprecation policy. +// When the snapshot is deleted, all messages retained in the snapshot +// are immediately dropped. After a snapshot is deleted, a new one may be +// created with the same name, but the new one has no association with the old +// snapshot or its subscription, unless the same subscription is specified. +func (c *SubscriberClient) DeleteSnapshot(ctx context.Context, req *pubsubpb.DeleteSnapshotRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteSnapshot[0:len(c.CallOptions.DeleteSnapshot):len(c.CallOptions.DeleteSnapshot)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.subscriberClient.DeleteSnapshot(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// Seek seeks an existing subscription to a point in time or to a given snapshot, +// whichever is provided in the request.

+// ALPHA: This feature is part of an alpha release. This API might be +// changed in backward-incompatible ways and is not recommended for production +// use. It is not subject to any SLA or deprecation policy. +func (c *SubscriberClient) Seek(ctx context.Context, req *pubsubpb.SeekRequest, opts ...gax.CallOption) (*pubsubpb.SeekResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Seek[0:len(c.CallOptions.Seek):len(c.CallOptions.Seek)], opts...) + var resp *pubsubpb.SeekResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.subscriberClient.Seek(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SnapshotIterator manages a stream of *pubsubpb.Snapshot. +type SnapshotIterator struct { + items []*pubsubpb.Snapshot + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*pubsubpb.Snapshot, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *SnapshotIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *SnapshotIterator) Next() (*pubsubpb.Snapshot, error) { + var item *pubsubpb.Snapshot + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *SnapshotIterator) bufLen() int { + return len(it.items) +} + +func (it *SnapshotIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// SubscriptionIterator manages a stream of *pubsubpb.Subscription. +type SubscriptionIterator struct { + items []*pubsubpb.Subscription + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*pubsubpb.Subscription, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *SubscriptionIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *SubscriptionIterator) Next() (*pubsubpb.Subscription, error) { + var item *pubsubpb.Subscription + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *SubscriptionIterator) bufLen() int { + return len(it.items) +} + +func (it *SubscriptionIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/pubsub/apiv1/subscriber_client_example_test.go b/vendor/cloud.google.com/go/pubsub/apiv1/subscriber_client_example_test.go new file mode 100644 index 00000000..cd12f01e --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/apiv1/subscriber_client_example_test.go @@ -0,0 +1,324 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package pubsub_test + +import ( + "context" + "io" + + pubsub "cloud.google.com/go/pubsub/apiv1" + "google.golang.org/api/iterator" + pubsubpb "google.golang.org/genproto/googleapis/pubsub/v1" +) + +func ExampleNewSubscriberClient() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleSubscriberClient_CreateSubscription() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.Subscription{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateSubscription(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleSubscriberClient_GetSubscription() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.GetSubscriptionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetSubscription(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleSubscriberClient_UpdateSubscription() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.UpdateSubscriptionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateSubscription(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleSubscriberClient_ListSubscriptions() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.ListSubscriptionsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListSubscriptions(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleSubscriberClient_DeleteSubscription() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.DeleteSubscriptionRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteSubscription(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleSubscriberClient_ModifyAckDeadline() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.ModifyAckDeadlineRequest{ + // TODO: Fill request struct fields. + } + err = c.ModifyAckDeadline(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleSubscriberClient_Acknowledge() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.AcknowledgeRequest{ + // TODO: Fill request struct fields. + } + err = c.Acknowledge(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleSubscriberClient_Pull() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.PullRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Pull(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleSubscriberClient_StreamingPull() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + stream, err := c.StreamingPull(ctx) + if err != nil { + // TODO: Handle error. + } + go func() { + reqs := []*pubsubpb.StreamingPullRequest{ + // TODO: Create requests. + } + for _, req := range reqs { + if err := stream.Send(req); err != nil { + // TODO: Handle error. + } + } + stream.CloseSend() + }() + for { + resp, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + // TODO: handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleSubscriberClient_ModifyPushConfig() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.ModifyPushConfigRequest{ + // TODO: Fill request struct fields. + } + err = c.ModifyPushConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleSubscriberClient_ListSnapshots() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.ListSnapshotsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListSnapshots(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleSubscriberClient_CreateSnapshot() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.CreateSnapshotRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateSnapshot(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleSubscriberClient_UpdateSnapshot() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.UpdateSnapshotRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateSnapshot(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleSubscriberClient_DeleteSnapshot() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.DeleteSnapshotRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteSnapshot(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleSubscriberClient_Seek() { + ctx := context.Background() + c, err := pubsub.NewSubscriberClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &pubsubpb.SeekRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Seek(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/pubsub/debug.go b/vendor/cloud.google.com/go/pubsub/debug.go new file mode 100644 index 00000000..977ae577 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/debug.go @@ -0,0 +1,72 @@ +// Copyright 2018 Google LLC +// +// 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. + +// +build psdebug + +package pubsub + +import ( + "sync" + "time" +) + +var ( + dmu sync.Mutex + msgTraces = map[string][]Event{} + ackIDToMsgID = map[string]string{} +) + +type Event struct { + Desc string + At time.Time +} + +func MessageEvents(msgID string) []Event { + dmu.Lock() + defer dmu.Unlock() + return msgTraces[msgID] +} + +func addRecv(msgID, ackID string, t time.Time) { + dmu.Lock() + defer dmu.Unlock() + ackIDToMsgID[ackID] = msgID + addEvent(msgID, "recv", t) +} + +func addAcks(ackIDs []string) { + dmu.Lock() + defer dmu.Unlock() + now := time.Now() + for _, id := range ackIDs { + addEvent(ackIDToMsgID[id], "ack", now) + } +} + +func addModAcks(ackIDs []string, deadlineSecs int32) { + dmu.Lock() + defer dmu.Unlock() + desc := "modack" + if deadlineSecs == 0 { + desc = "nack" + } + now := time.Now() + for _, id := range ackIDs { + addEvent(ackIDToMsgID[id], desc, now) + } +} + +func addEvent(msgID, desc string, t time.Time) { + msgTraces[msgID] = append(msgTraces[msgID], Event{desc, t}) +} diff --git a/vendor/cloud.google.com/go/pubsub/doc.go b/vendor/cloud.google.com/go/pubsub/doc.go new file mode 100644 index 00000000..eb2c9068 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/doc.go @@ -0,0 +1,137 @@ +// Copyright 2016 Google LLC +// +// 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 pubsub provides an easy way to publish and receive Google Cloud Pub/Sub +messages, hiding the details of the underlying server RPCs. Google Cloud +Pub/Sub is a many-to-many, asynchronous messaging system that decouples senders +and receivers. + +More information about Google Cloud Pub/Sub is available at +https://cloud.google.com/pubsub/docs + +See https://godoc.org/cloud.google.com/go for authentication, timeouts, +connection pooling and similar aspects of this package. + + +Publishing + +Google Cloud Pub/Sub messages are published to topics. Topics may be created +using the pubsub package like so: + + topic, err := pubsubClient.CreateTopic(context.Background(), "topic-name") + +Messages may then be published to a topic: + + res := topic.Publish(ctx, &pubsub.Message{Data: []byte("payload")}) + +Publish queues the message for publishing and returns immediately. When enough +messages have accumulated, or enough time has elapsed, the batch of messages is +sent to the Pub/Sub service. + +Publish returns a PublishResult, which behaves like a future: its Get method +blocks until the message has been sent to the service. + +The first time you call Publish on a topic, goroutines are started in the +background. To clean up these goroutines, call Stop: + + topic.Stop() + +Receiving + +To receive messages published to a topic, clients create subscriptions +to the topic. There may be more than one subscription per topic; each message +that is published to the topic will be delivered to all of its subscriptions. + +Subsciptions may be created like so: + + sub, err := pubsubClient.CreateSubscription(context.Background(), "sub-name", + pubsub.SubscriptionConfig{Topic: topic}) + +Messages are then consumed from a subscription via callback. + + err := sub.Receive(context.Background(), func(ctx context.Context, m *Message) { + log.Printf("Got message: %s", m.Data) + m.Ack() + }) + if err != nil { + // Handle error. + } + +The callback is invoked concurrently by multiple goroutines, maximizing +throughput. To terminate a call to Receive, cancel its context. + +Once client code has processed the message, it must call Message.Ack, otherwise +the message will eventually be redelivered. As an optimization, if the client +cannot or doesn't want to process the message, it can call Message.Nack to +speed redelivery. For more information and configuration options, see +"Deadlines" below. + +Note: It is possible for Messages to be redelivered, even if Message.Ack has +been called. Client code must be robust to multiple deliveries of messages. + +Note: This uses pubsub's streaming pull feature. This feature properties that +may be surprising. Please take a look at https://cloud.google.com/pubsub/docs/pull#streamingpull +for more details on how streaming pull behaves compared to the synchronous +pull method. + +Deadlines + +The default pubsub deadlines are suitable for most use cases, but may be +overridden. This section describes the tradeoffs that should be considered +when overriding the defaults. + +Behind the scenes, each message returned by the Pub/Sub server has an +associated lease, known as an "ACK deadline". Unless a message is +acknowledged within the ACK deadline, or the client requests that +the ACK deadline be extended, the message will become eligible for redelivery. + +As a convenience, the pubsub client will automatically extend deadlines until +either: + * Message.Ack or Message.Nack is called, or + * The "MaxExtension" period elapses from the time the message is fetched from the server. + +ACK deadlines are extended periodically by the client. The initial ACK +deadline given to messages is 10s. The period between extensions, as well as the +length of the extension, automatically adjust depending on the time it takes to ack +messages, up to 10m. This has the effect that subscribers that process messages +quickly have their message ack deadlines extended for a short amount, whereas +subscribers that process message slowly have their message ack deadlines extended +for a large amount. The net effect is fewer RPCs sent from the client library. + +For example, consider a subscriber that takes 3 minutes to process each message. +Since the library has already recorded several 3 minute "time to ack"s in a +percentile distribution, future message extensions are sent with a value of 3 +minutes, every 3 minutes. Suppose the application crashes 5 seconds after the +library sends such an extension: the Pub/Sub server would wait the remaining +2m55s before re-sending the messages out to other subscribers. + +Please note that the client library does not use the subscription's AckDeadline +by default. To enforce the subscription AckDeadline, set MaxExtension to the +subscription's AckDeadline: + + cfg, err := sub.Config(ctx) + if err != nil { + // TODO handle err + } + + sub.ReceiveSettings.MaxExtension = cfg.AckDeadline + +Slow Message Processing + +For use cases where message processing exceeds 30 minutes, we recommend using +the base client in a pull model, since long-lived streams are periodically killed +by firewalls. See the example at https://godoc.org/cloud.google.com/go/pubsub/apiv1#example-SubscriberClient-Pull-LengthyClientProcessing +*/ +package pubsub // import "cloud.google.com/go/pubsub" diff --git a/vendor/cloud.google.com/go/pubsub/endtoend_test.go b/vendor/cloud.google.com/go/pubsub/endtoend_test.go new file mode 100644 index 00000000..d522f368 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/endtoend_test.go @@ -0,0 +1,230 @@ +// Copyright 2014 Google LLC +// +// 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 pubsub + +import ( + "bytes" + "context" + "fmt" + "log" + "math/rand" + "os" + "sync" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/option" +) + +const ( + timeout = time.Minute * 10 + ackDeadline = time.Second * 10 + nMessages = 1e4 + acceptableDupPercentage = 1 + numAcceptableDups = int(nMessages * acceptableDupPercentage / 100) +) + +// Buffer log messages to debug failures. +var logBuf bytes.Buffer + +// The end-to-end pumps many messages into a topic and tests that they are all +// delivered to each subscription for the topic. It also tests that messages +// are not unexpectedly redelivered. +func TestIntegration_EndToEnd(t *testing.T) { + if testing.Short() { + t.Skip("Integration tests skipped in short mode") + } + log.SetOutput(&logBuf) + ctx := context.Background() + ts := testutil.TokenSource(ctx, ScopePubSub, ScopeCloudPlatform) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + now := time.Now() + topicName := fmt.Sprintf("endtoend-%d", now.UnixNano()) + subPrefix := fmt.Sprintf("endtoend-%d", now.UnixNano()) + + client, err := NewClient(ctx, testutil.ProjID(), option.WithTokenSource(ts)) + if err != nil { + t.Fatalf("Creating client error: %v", err) + } + + var topic *Topic + if topic, err = client.CreateTopic(ctx, topicName); err != nil { + t.Fatalf("CreateTopic error: %v", err) + } + defer topic.Delete(ctx) + + // Two subscriptions to the same topic. + var subs [2]*Subscription + for i := 0; i < len(subs); i++ { + subs[i], err = client.CreateSubscription(ctx, fmt.Sprintf("%s-%d", subPrefix, i), SubscriptionConfig{ + Topic: topic, + AckDeadline: ackDeadline, + }) + if err != nil { + t.Fatalf("CreateSub error: %v", err) + } + defer subs[i].Delete(ctx) + } + + err = publish(ctx, topic, nMessages) + topic.Stop() + if err != nil { + t.Fatalf("publish: %v", err) + } + + // recv provides an indication that messages are still arriving. + recv := make(chan struct{}) + // We have two subscriptions to our topic. + // Each subscription will get a copy of each published message. + var wg sync.WaitGroup + cctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + consumers := []*consumer{ + {counts: make(map[string]int), recv: recv, durations: []time.Duration{time.Hour}}, + {counts: make(map[string]int), recv: recv, + durations: []time.Duration{ackDeadline, ackDeadline, ackDeadline / 2, ackDeadline / 2, time.Hour}}, + } + for i, con := range consumers { + con := con + sub := subs[i] + wg.Add(1) + go func() { + defer wg.Done() + con.consume(cctx, t, sub) + }() + } + // Wait for a while after the last message before declaring quiescence. + // We wait a multiple of the ack deadline, for two reasons: + // 1. To detect if messages are redelivered after having their ack + // deadline extended. + // 2. To wait for redelivery of messages that were en route when a Receive + // is canceled. This can take considerably longer than the ack deadline. + quiescenceDur := ackDeadline * 6 + quiescenceTimer := time.NewTimer(quiescenceDur) + +loop: + for { + select { + case <-recv: + // Reset timer so we wait quiescenceDur after the last message. + // See https://godoc.org/time#Timer.Reset for why the Stop + // and channel drain are necessary. + if !quiescenceTimer.Stop() { + <-quiescenceTimer.C + } + quiescenceTimer.Reset(quiescenceDur) + + case <-quiescenceTimer.C: + cancel() + log.Println("quiesced") + break loop + + case <-cctx.Done(): + t.Fatal("timed out") + } + } + wg.Wait() + ok := true + for i, con := range consumers { + var numDups int + var zeroes int + for _, v := range con.counts { + if v == 0 { + zeroes++ + } + numDups += v - 1 + } + + if zeroes > 0 { + t.Errorf("Consumer %d: %d messages never arrived", i, zeroes) + ok = false + } else if numDups > numAcceptableDups { + t.Errorf("Consumer %d: Willing to accept %d dups (%v duplicated of %d messages), but got %d", i, numAcceptableDups, acceptableDupPercentage, int(nMessages), numDups) + ok = false + } + } + if !ok { + logBuf.WriteTo(os.Stdout) + } +} + +// publish publishes n messages to topic. +func publish(ctx context.Context, topic *Topic, n int) error { + var rs []*PublishResult + for i := 0; i < n; i++ { + m := &Message{Data: []byte(fmt.Sprintf("msg %d", i))} + rs = append(rs, topic.Publish(ctx, m)) + } + for _, r := range rs { + _, err := r.Get(ctx) + if err != nil { + return err + } + } + return nil +} + +// consumer consumes messages according to its configuration. +type consumer struct { + durations []time.Duration + + // A value is sent to recv each time Inc is called. + recv chan struct{} + + mu sync.Mutex + counts map[string]int + total int +} + +// consume reads messages from a subscription, and keeps track of what it receives in mc. +// After consume returns, the caller should wait on wg to ensure that no more updates to mc will be made. +func (c *consumer) consume(ctx context.Context, t *testing.T, sub *Subscription) { + for _, dur := range c.durations { + ctx2, cancel := context.WithTimeout(ctx, dur) + defer cancel() + id := sub.name[len(sub.name)-1:] + log.Printf("%s: start receive", id) + prev := c.total + err := sub.Receive(ctx2, c.process) + log.Printf("%s: end receive; read %d", id, c.total-prev) + if err != nil { + t.Errorf("error from Receive: %v", err) + return + } + select { + case <-ctx.Done(): + return + default: + } + } +} + +// process handles a message and records it in mc. +func (c *consumer) process(_ context.Context, m *Message) { + c.mu.Lock() + c.counts[m.ID]++ + c.total++ + c.mu.Unlock() + c.recv <- struct{}{} + // Simulate time taken to process m, while continuing to process more messages. + // Some messages will need to have their ack deadline extended due to this delay. + delay := rand.Intn(int(ackDeadline * 3)) + time.AfterFunc(time.Duration(delay), m.Ack) +} diff --git a/vendor/cloud.google.com/go/pubsub/example_subscription_iterator_test.go b/vendor/cloud.google.com/go/pubsub/example_subscription_iterator_test.go new file mode 100644 index 00000000..edf7a7ac --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/example_subscription_iterator_test.go @@ -0,0 +1,54 @@ +// Copyright 2016 Google LLC +// +// 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 pubsub_test + +import ( + "context" + "fmt" + + "cloud.google.com/go/pubsub" + "google.golang.org/api/iterator" +) + +func ExampleClient_Subscriptions() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + // List all subscriptions of the project. + it := client.Subscriptions(ctx) + _ = it // TODO: iterate using Next. +} + +func ExampleSubscriptionIterator_Next() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + // List all subscriptions of the project. + it := client.Subscriptions(ctx) + for { + sub, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(sub) + } +} diff --git a/vendor/cloud.google.com/go/pubsub/example_test.go b/vendor/cloud.google.com/go/pubsub/example_test.go new file mode 100644 index 00000000..f77c957f --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/example_test.go @@ -0,0 +1,369 @@ +// Copyright 2014 Google LLC +// +// 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 pubsub_test + +import ( + "context" + "fmt" + "time" + + "cloud.google.com/go/pubsub" + "google.golang.org/api/iterator" +) + +func ExampleNewClient() { + ctx := context.Background() + _, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + // See the other examples to learn how to use the Client. +} + +func ExampleClient_CreateTopic() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + // Create a new topic with the given name. + topic, err := client.CreateTopic(ctx, "topicName") + if err != nil { + // TODO: Handle error. + } + + _ = topic // TODO: use the topic. +} + +// Use TopicInProject to refer to a topic that is not in the client's project, such +// as a public topic. +func ExampleClient_TopicInProject() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + topic := client.TopicInProject("topicName", "another-project-id") + _ = topic // TODO: use the topic. +} + +func ExampleClient_CreateSubscription() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + // Create a new topic with the given name. + topic, err := client.CreateTopic(ctx, "topicName") + if err != nil { + // TODO: Handle error. + } + + // Create a new subscription to the previously created topic + // with the given name. + sub, err := client.CreateSubscription(ctx, "subName", pubsub.SubscriptionConfig{ + Topic: topic, + AckDeadline: 10 * time.Second, + }) + if err != nil { + // TODO: Handle error. + } + + _ = sub // TODO: use the subscription. +} + +func ExampleTopic_Delete() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + topic := client.Topic("topicName") + if err := topic.Delete(ctx); err != nil { + // TODO: Handle error. + } +} + +func ExampleTopic_Exists() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + topic := client.Topic("topicName") + ok, err := topic.Exists(ctx) + if err != nil { + // TODO: Handle error. + } + if !ok { + // Topic doesn't exist. + } +} + +func ExampleTopic_Publish() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + topic := client.Topic("topicName") + defer topic.Stop() + var results []*pubsub.PublishResult + r := topic.Publish(ctx, &pubsub.Message{ + Data: []byte("hello world"), + }) + results = append(results, r) + // Do other work ... + for _, r := range results { + id, err := r.Get(ctx) + if err != nil { + // TODO: Handle error. + } + fmt.Printf("Published a message with a message ID: %s\n", id) + } +} + +func ExampleTopic_Subscriptions() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + topic := client.Topic("topic-name") + // List all subscriptions of the topic (maybe of multiple projects). + for subs := topic.Subscriptions(ctx); ; { + sub, err := subs.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + _ = sub // TODO: use the subscription. + } +} + +func ExampleSubscription_Delete() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + sub := client.Subscription("subName") + if err := sub.Delete(ctx); err != nil { + // TODO: Handle error. + } +} + +func ExampleSubscription_Exists() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + sub := client.Subscription("subName") + ok, err := sub.Exists(ctx) + if err != nil { + // TODO: Handle error. + } + if !ok { + // Subscription doesn't exist. + } +} + +func ExampleSubscription_Config() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + sub := client.Subscription("subName") + config, err := sub.Config(ctx) + if err != nil { + // TODO: Handle error. + } + fmt.Println(config) +} + +func ExampleSubscription_Receive() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + sub := client.Subscription("subName") + err = sub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) { + // TODO: Handle message. + // NOTE: May be called concurrently; synchronize access to shared memory. + m.Ack() + }) + if err != context.Canceled { + // TODO: Handle error. + } +} + +// This example shows how to configure keepalive so that unacknoweldged messages +// expire quickly, allowing other subscribers to take them. +func ExampleSubscription_Receive_maxExtension() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + sub := client.Subscription("subName") + // This program is expected to process and acknowledge messages in 30 seconds. If + // not, the Pub/Sub API will assume the message is not acknowledged. + sub.ReceiveSettings.MaxExtension = 30 * time.Second + err = sub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) { + // TODO: Handle message. + m.Ack() + }) + if err != context.Canceled { + // TODO: Handle error. + } +} + +// This example shows how to throttle Subscription.Receive, which aims for high +// throughput by default. By limiting the number of messages and/or bytes being +// processed at once, you can bound your program's resource consumption. +func ExampleSubscription_Receive_maxOutstanding() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + sub := client.Subscription("subName") + sub.ReceiveSettings.MaxOutstandingMessages = 5 + sub.ReceiveSettings.MaxOutstandingBytes = 10e6 + err = sub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) { + // TODO: Handle message. + m.Ack() + }) + if err != context.Canceled { + // TODO: Handle error. + } +} + +func ExampleSubscription_Update() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + sub := client.Subscription("subName") + subConfig, err := sub.Update(ctx, pubsub.SubscriptionConfigToUpdate{ + PushConfig: &pubsub.PushConfig{Endpoint: "https://example.com/push"}, + }) + if err != nil { + // TODO: Handle error. + } + _ = subConfig // TODO: Use SubscriptionConfig. +} + +func ExampleSubscription_CreateSnapshot() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + sub := client.Subscription("subName") + snapConfig, err := sub.CreateSnapshot(ctx, "snapshotName") + if err != nil { + // TODO: Handle error. + } + _ = snapConfig // TODO: Use SnapshotConfig. +} + +func ExampleSubscription_SeekToSnapshot() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + sub := client.Subscription("subName") + snap := client.Snapshot("snapshotName") + if err := sub.SeekToSnapshot(ctx, snap); err != nil { + // TODO: Handle error. + } +} + +func ExampleSubscription_SeekToTime() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + sub := client.Subscription("subName") + if err := sub.SeekToTime(ctx, time.Now().Add(-time.Hour)); err != nil { + // TODO: Handle error. + } +} + +func ExampleSnapshot_Delete() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + + snap := client.Snapshot("snapshotName") + if err := snap.Delete(ctx); err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_Snapshots() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + // List all snapshots for the project. + iter := client.Snapshots(ctx) + _ = iter // TODO: iterate using Next. +} + +func ExampleSnapshotConfigIterator_Next() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + // List all snapshots for the project. + iter := client.Snapshots(ctx) + for { + snapConfig, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + _ = snapConfig // TODO: use the SnapshotConfig. + } +} + +// TODO(jba): write an example for PublishResult.Ready +// TODO(jba): write an example for Subscription.IAM +// TODO(jba): write an example for Topic.IAM +// TODO(jba): write an example for Topic.Stop diff --git a/vendor/cloud.google.com/go/pubsub/example_topic_iterator_test.go b/vendor/cloud.google.com/go/pubsub/example_topic_iterator_test.go new file mode 100644 index 00000000..e480d0e3 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/example_topic_iterator_test.go @@ -0,0 +1,53 @@ +// Copyright 2016 Google LLC +// +// 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 pubsub_test + +import ( + "context" + "fmt" + + "cloud.google.com/go/pubsub" + "google.golang.org/api/iterator" +) + +func ExampleClient_Topics() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + it := client.Topics(ctx) + _ = it // TODO: iterate using Next. +} + +func ExampleTopicIterator_Next() { + ctx := context.Background() + client, err := pubsub.NewClient(ctx, "project-id") + if err != nil { + // TODO: Handle error. + } + // List all topics. + it := client.Topics(ctx) + for { + t, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(t) + } +} diff --git a/vendor/cloud.google.com/go/pubsub/flow_controller.go b/vendor/cloud.google.com/go/pubsub/flow_controller.go new file mode 100644 index 00000000..3f165a0a --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/flow_controller.go @@ -0,0 +1,122 @@ +// Copyright 2017 Google LLC +// +// 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 pubsub + +import ( + "context" + "sync/atomic" + + "golang.org/x/sync/semaphore" +) + +// flowController implements flow control for Subscription.Receive. +type flowController struct { + maxCount int + maxSize int // max total size of messages + semCount, semSize *semaphore.Weighted // enforces max number and size of messages + // Number of calls to acquire - number of calls to release. This can go + // negative if semCount == nil and a large acquire is followed by multiple + // small releases. + // Atomic. + countRemaining int64 +} + +// newFlowController creates a new flowController that ensures no more than +// maxCount messages or maxSize bytes are outstanding at once. If maxCount or +// maxSize is < 1, then an unlimited number of messages or bytes is permitted, +// respectively. +func newFlowController(maxCount, maxSize int) *flowController { + fc := &flowController{ + maxCount: maxCount, + maxSize: maxSize, + semCount: nil, + semSize: nil, + } + if maxCount > 0 { + fc.semCount = semaphore.NewWeighted(int64(maxCount)) + } + if maxSize > 0 { + fc.semSize = semaphore.NewWeighted(int64(maxSize)) + } + return fc +} + +// acquire blocks until one message of size bytes can proceed or ctx is done. +// It returns nil in the first case, or ctx.Err() in the second. +// +// acquire allows large messages to proceed by treating a size greater than maxSize +// as if it were equal to maxSize. +func (f *flowController) acquire(ctx context.Context, size int) error { + if f.semCount != nil { + if err := f.semCount.Acquire(ctx, 1); err != nil { + return err + } + } + if f.semSize != nil { + if err := f.semSize.Acquire(ctx, f.bound(size)); err != nil { + if f.semCount != nil { + f.semCount.Release(1) + } + return err + } + } + atomic.AddInt64(&f.countRemaining, 1) + return nil +} + +// tryAcquire returns false if acquire would block. Otherwise, it behaves like +// acquire and returns true. +// +// tryAcquire allows large messages to proceed by treating a size greater than +// maxSize as if it were equal to maxSize. +func (f *flowController) tryAcquire(size int) bool { + if f.semCount != nil { + if !f.semCount.TryAcquire(1) { + return false + } + } + if f.semSize != nil { + if !f.semSize.TryAcquire(f.bound(size)) { + if f.semCount != nil { + f.semCount.Release(1) + } + return false + } + } + atomic.AddInt64(&f.countRemaining, 1) + return true +} + +// release notes that one message of size bytes is no longer outstanding. +func (f *flowController) release(size int) { + atomic.AddInt64(&f.countRemaining, -1) + if f.semCount != nil { + f.semCount.Release(1) + } + if f.semSize != nil { + f.semSize.Release(f.bound(size)) + } +} + +func (f *flowController) bound(size int) int64 { + if size > f.maxSize { + return int64(f.maxSize) + } + return int64(size) +} + +func (f *flowController) count() int { + return int(atomic.LoadInt64(&f.countRemaining)) +} diff --git a/vendor/cloud.google.com/go/pubsub/flow_controller_test.go b/vendor/cloud.google.com/go/pubsub/flow_controller_test.go new file mode 100644 index 00000000..71c41cbf --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/flow_controller_test.go @@ -0,0 +1,255 @@ +// Copyright 2017 Google LLC +// +// 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 pubsub + +import ( + "context" + "errors" + "fmt" + "sync/atomic" + "testing" + "time" + + "golang.org/x/sync/errgroup" +) + +func TestFlowControllerCancel(t *testing.T) { + // Test canceling a flow controller's context. + t.Parallel() + fc := newFlowController(3, 10) + if err := fc.acquire(context.Background(), 5); err != nil { + t.Fatal(err) + } + // Experiment: a context that times out should always return an error. + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Millisecond) + defer cancel() + if err := fc.acquire(ctx, 6); err != context.DeadlineExceeded { + t.Fatalf("got %v, expected DeadlineExceeded", err) + } + // Control: a context that is not done should always return nil. + go func() { + time.Sleep(5 * time.Millisecond) + fc.release(5) + }() + if err := fc.acquire(context.Background(), 6); err != nil { + t.Errorf("got %v, expected nil", err) + } +} + +func TestFlowControllerLargeRequest(t *testing.T) { + // Large requests succeed, consuming the entire allotment. + t.Parallel() + fc := newFlowController(3, 10) + err := fc.acquire(context.Background(), 11) + if err != nil { + t.Fatal(err) + } +} + +func TestFlowControllerNoStarve(t *testing.T) { + // A large request won't starve, because the flowController is + // (best-effort) FIFO. + t.Parallel() + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + fc := newFlowController(10, 10) + first := make(chan int) + for i := 0; i < 20; i++ { + go func() { + for { + if err := fc.acquire(ctx, 1); err != nil { + if err != context.Canceled { + t.Error(err) + } + return + } + select { + case first <- 1: + default: + } + fc.release(1) + } + }() + } + <-first // Wait until the flowController's state is non-zero. + if err := fc.acquire(ctx, 11); err != nil { + t.Errorf("got %v, want nil", err) + } +} + +func TestFlowControllerSaturation(t *testing.T) { + t.Parallel() + const ( + maxCount = 6 + maxSize = 10 + ) + for _, test := range []struct { + acquireSize int + wantCount, wantSize int64 + }{ + { + // Many small acquires cause the flow controller to reach its max count. + acquireSize: 1, + wantCount: 6, + wantSize: 6, + }, + { + // Five acquires of size 2 will cause the flow controller to reach its max size, + // but not its max count. + acquireSize: 2, + wantCount: 5, + wantSize: 10, + }, + { + // If the requests are the right size (relatively prime to maxSize), + // the flow controller will not saturate on size. (In this case, not on count either.) + acquireSize: 3, + wantCount: 3, + wantSize: 9, + }, + } { + fc := newFlowController(maxCount, maxSize) + // Atomically track flow controller state. + // The flowController itself tracks count. + var curSize int64 + success := errors.New("") + // Time out if wantSize or wantCount is never reached. + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + g, ctx := errgroup.WithContext(ctx) + for i := 0; i < 10; i++ { + g.Go(func() error { + var hitCount, hitSize bool + // Run at least until we hit the expected values, and at least + // for enough iterations to exceed them if the flow controller + // is broken. + for i := 0; i < 100 || !hitCount || !hitSize; i++ { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + if err := fc.acquire(ctx, test.acquireSize); err != nil { + return err + } + c := int64(fc.count()) + if c > test.wantCount { + return fmt.Errorf("count %d exceeds want %d", c, test.wantCount) + } + if c == test.wantCount { + hitCount = true + } + s := atomic.AddInt64(&curSize, int64(test.acquireSize)) + if s > test.wantSize { + return fmt.Errorf("size %d exceeds want %d", s, test.wantSize) + } + if s == test.wantSize { + hitSize = true + } + time.Sleep(5 * time.Millisecond) // Let other goroutines make progress. + if atomic.AddInt64(&curSize, -int64(test.acquireSize)) < 0 { + return errors.New("negative size") + } + fc.release(test.acquireSize) + } + return success + }) + } + if err := g.Wait(); err != success { + t.Errorf("%+v: %v", test, err) + continue + } + } +} + +func TestFlowControllerTryAcquire(t *testing.T) { + t.Parallel() + fc := newFlowController(3, 10) + + // Successfully tryAcquire 4 bytes. + if !fc.tryAcquire(4) { + t.Error("got false, wanted true") + } + + // Fail to tryAcquire 7 bytes. + if fc.tryAcquire(7) { + t.Error("got true, wanted false") + } + + // Successfully tryAcquire 6 byte. + if !fc.tryAcquire(6) { + t.Error("got false, wanted true") + } +} + +func TestFlowControllerUnboundedCount(t *testing.T) { + t.Parallel() + ctx := context.Background() + fc := newFlowController(0, 10) + + // Successfully acquire 4 bytes. + if err := fc.acquire(ctx, 4); err != nil { + t.Errorf("got %v, wanted no error", err) + } + + // Successfully tryAcquire 4 bytes. + if !fc.tryAcquire(4) { + t.Error("got false, wanted true") + } + + // Fail to tryAcquire 3 bytes. + if fc.tryAcquire(3) { + t.Error("got true, wanted false") + } +} + +func TestFlowControllerUnboundedCount2(t *testing.T) { + t.Parallel() + ctx := context.Background() + fc := newFlowController(0, 0) + // Successfully acquire 4 bytes. + if err := fc.acquire(ctx, 4); err != nil { + t.Errorf("got %v, wanted no error", err) + } + fc.release(1) + fc.release(1) + fc.release(1) + wantCount := int64(-2) + c := int64(fc.count()) + if c != wantCount { + t.Fatalf("got count %d, want %d", c, wantCount) + } +} + +func TestFlowControllerUnboundedBytes(t *testing.T) { + t.Parallel() + ctx := context.Background() + fc := newFlowController(2, 0) + + // Successfully acquire 4GB. + if err := fc.acquire(ctx, 4e9); err != nil { + t.Errorf("got %v, wanted no error", err) + } + + // Successfully tryAcquire 4GB bytes. + if !fc.tryAcquire(4e9) { + t.Error("got false, wanted true") + } + + // Fail to tryAcquire a third message. + if fc.tryAcquire(3) { + t.Error("got true, wanted false") + } +} diff --git a/vendor/cloud.google.com/go/pubsub/integration_test.go b/vendor/cloud.google.com/go/pubsub/integration_test.go new file mode 100644 index 00000000..5880c633 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/integration_test.go @@ -0,0 +1,627 @@ +// Copyright 2014 Google LLC +// +// 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 pubsub + +import ( + "context" + "fmt" + "testing" + "time" + + "cloud.google.com/go/iam" + "cloud.google.com/go/internal" + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/internal/uid" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var ( + topicIDs = uid.NewSpace("topic", nil) + subIDs = uid.NewSpace("sub", nil) +) + +// messageData is used to hold the contents of a message so that it can be compared against the contents +// of another message without regard to irrelevant fields. +type messageData struct { + ID string + Data []byte + Attributes map[string]string +} + +func extractMessageData(m *Message) *messageData { + return &messageData{ + ID: m.ID, + Data: m.Data, + Attributes: m.Attributes, + } +} + +func integrationTestClient(ctx context.Context, t *testing.T) *Client { + if testing.Short() { + t.Skip("Integration tests skipped in short mode") + } + projID := testutil.ProjID() + if projID == "" { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + ts := testutil.TokenSource(ctx, ScopePubSub, ScopeCloudPlatform) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + client, err := NewClient(ctx, projID, option.WithTokenSource(ts)) + if err != nil { + t.Fatalf("Creating client error: %v", err) + } + return client +} + +func TestIntegration_All(t *testing.T) { + t.Parallel() + ctx := context.Background() + client := integrationTestClient(ctx, t) + defer client.Close() + + topic, err := client.CreateTopic(ctx, topicIDs.New()) + if err != nil { + t.Errorf("CreateTopic error: %v", err) + } + defer topic.Stop() + exists, err := topic.Exists(ctx) + if err != nil { + t.Fatalf("TopicExists error: %v", err) + } + if !exists { + t.Errorf("topic %v should exist, but it doesn't", topic) + } + + var sub *Subscription + if sub, err = client.CreateSubscription(ctx, subIDs.New(), SubscriptionConfig{Topic: topic}); err != nil { + t.Errorf("CreateSub error: %v", err) + } + exists, err = sub.Exists(ctx) + if err != nil { + t.Fatalf("SubExists error: %v", err) + } + if !exists { + t.Errorf("subscription %s should exist, but it doesn't", sub.ID()) + } + + for _, sync := range []bool{false, true} { + for _, maxMsgs := range []int{0, 3, -1} { // MaxOutstandingMessages = default, 3, unlimited + testPublishAndReceive(t, topic, sub, maxMsgs, sync) + } + } + if msg, ok := testIAM(ctx, topic.IAM(), "pubsub.topics.get"); !ok { + t.Errorf("topic IAM: %s", msg) + } + if msg, ok := testIAM(ctx, sub.IAM(), "pubsub.subscriptions.get"); !ok { + t.Errorf("sub IAM: %s", msg) + } + + snap, err := sub.CreateSnapshot(ctx, "") + if err != nil { + t.Fatalf("CreateSnapshot error: %v", err) + } + + timeoutCtx, cancel := context.WithTimeout(ctx, time.Minute) + defer cancel() + err = internal.Retry(timeoutCtx, gax.Backoff{}, func() (bool, error) { + snapIt := client.Snapshots(timeoutCtx) + for { + s, err := snapIt.Next() + if err == nil && s.name == snap.name { + return true, nil + } + if err == iterator.Done { + return false, fmt.Errorf("cannot find snapshot: %q", snap.name) + } + if err != nil { + return false, err + } + } + }) + if err != nil { + t.Error(err) + } + + err = internal.Retry(timeoutCtx, gax.Backoff{}, func() (bool, error) { + err := sub.SeekToSnapshot(timeoutCtx, snap.Snapshot) + return err == nil, err + }) + if err != nil { + t.Error(err) + } + + err = internal.Retry(timeoutCtx, gax.Backoff{}, func() (bool, error) { + err := sub.SeekToTime(timeoutCtx, time.Now()) + return err == nil, err + }) + if err != nil { + t.Error(err) + } + + err = internal.Retry(timeoutCtx, gax.Backoff{}, func() (bool, error) { + snapHandle := client.Snapshot(snap.ID()) + err := snapHandle.Delete(timeoutCtx) + return err == nil, err + }) + if err != nil { + t.Error(err) + } + + if err := sub.Delete(ctx); err != nil { + t.Errorf("DeleteSub error: %v", err) + } + + if err := topic.Delete(ctx); err != nil { + t.Errorf("DeleteTopic error: %v", err) + } +} + +func testPublishAndReceive(t *testing.T, topic *Topic, sub *Subscription, maxMsgs int, synchronous bool) { + ctx := context.Background() + var msgs []*Message + for i := 0; i < 10; i++ { + text := fmt.Sprintf("a message with an index %d", i) + attrs := make(map[string]string) + attrs["foo"] = "bar" + msgs = append(msgs, &Message{ + Data: []byte(text), + Attributes: attrs, + }) + } + + // Publish some messages. + type pubResult struct { + m *Message + r *PublishResult + } + var rs []pubResult + for _, m := range msgs { + r := topic.Publish(ctx, m) + rs = append(rs, pubResult{m, r}) + } + want := make(map[string]*messageData) + for _, res := range rs { + id, err := res.r.Get(ctx) + if err != nil { + t.Fatal(err) + } + md := extractMessageData(res.m) + md.ID = id + want[md.ID] = md + } + + sub.ReceiveSettings.MaxOutstandingMessages = maxMsgs + sub.ReceiveSettings.Synchronous = synchronous + + // Use a timeout to ensure that Pull does not block indefinitely if there are + // unexpectedly few messages available. + now := time.Now() + timeoutCtx, _ := context.WithTimeout(ctx, time.Minute) + gotMsgs, err := pullN(timeoutCtx, sub, len(want), func(ctx context.Context, m *Message) { + m.Ack() + }) + if err != nil { + if c := status.Convert(err); c.Code() == codes.Canceled { + if time.Now().Sub(now) >= time.Minute { + t.Fatal("pullN took too long") + } + } else { + t.Fatalf("Pull: %v", err) + } + } + got := make(map[string]*messageData) + for _, m := range gotMsgs { + md := extractMessageData(m) + got[md.ID] = md + } + if !testutil.Equal(got, want) { + t.Fatalf("MaxOutstandingMessages=%d, Synchronous=%t, messages got: %v, messages want: %v", + maxMsgs, synchronous, got, want) + } +} + +// IAM tests. +// NOTE: for these to succeed, the test runner identity must have the Pub/Sub Admin or Owner roles. +// To set, visit https://console.developers.google.com, select "IAM & Admin" from the top-left +// menu, choose the account, click the Roles dropdown, and select "Pub/Sub > Pub/Sub Admin". +// TODO(jba): move this to a testing package within cloud.google.com/iam, so we can re-use it. +func testIAM(ctx context.Context, h *iam.Handle, permission string) (msg string, ok bool) { + // Attempting to add an non-existent identity (e.g. "alice@example.com") causes the service + // to return an internal error, so use a real identity. + const member = "domain:google.com" + + var policy *iam.Policy + var err error + + if policy, err = h.Policy(ctx); err != nil { + return fmt.Sprintf("Policy: %v", err), false + } + // The resource is new, so the policy should be empty. + if got := policy.Roles(); len(got) > 0 { + return fmt.Sprintf("initially: got roles %v, want none", got), false + } + // Add a member, set the policy, then check that the member is present. + policy.Add(member, iam.Viewer) + if err := h.SetPolicy(ctx, policy); err != nil { + return fmt.Sprintf("SetPolicy: %v", err), false + } + if policy, err = h.Policy(ctx); err != nil { + return fmt.Sprintf("Policy: %v", err), false + } + if got, want := policy.Members(iam.Viewer), []string{member}; !testutil.Equal(got, want) { + return fmt.Sprintf("after Add: got %v, want %v", got, want), false + } + // Now remove that member, set the policy, and check that it's empty again. + policy.Remove(member, iam.Viewer) + if err := h.SetPolicy(ctx, policy); err != nil { + return fmt.Sprintf("SetPolicy: %v", err), false + } + if policy, err = h.Policy(ctx); err != nil { + return fmt.Sprintf("Policy: %v", err), false + } + if got := policy.Roles(); len(got) > 0 { + return fmt.Sprintf("after Remove: got roles %v, want none", got), false + } + // Call TestPermissions. + // Because this user is an admin, it has all the permissions on the + // resource type. Note: the service fails if we ask for inapplicable + // permissions (e.g. a subscription permission on a topic, or a topic + // create permission on a topic rather than its parent). + wantPerms := []string{permission} + gotPerms, err := h.TestPermissions(ctx, wantPerms) + if err != nil { + return fmt.Sprintf("TestPermissions: %v", err), false + } + if !testutil.Equal(gotPerms, wantPerms) { + return fmt.Sprintf("TestPermissions: got %v, want %v", gotPerms, wantPerms), false + } + return "", true +} + +func TestIntegration_CancelReceive(t *testing.T) { + t.Parallel() + ctx, cancel := context.WithCancel(context.Background()) + client := integrationTestClient(ctx, t) + defer client.Close() + + topic, err := client.CreateTopic(ctx, topicIDs.New()) + if err != nil { + t.Fatal(err) + } + defer topic.Delete(ctx) + defer topic.Stop() + + var sub *Subscription + if sub, err = client.CreateSubscription(ctx, subIDs.New(), SubscriptionConfig{Topic: topic}); err != nil { + t.Fatal(err) + } + defer sub.Delete(ctx) + + sub.ReceiveSettings.MaxOutstandingMessages = -1 + sub.ReceiveSettings.MaxOutstandingBytes = -1 + sub.ReceiveSettings.NumGoroutines = 1 + + doneReceiving := make(chan struct{}) + + // Publish the messages. + go func() { + for { + select { + case <-doneReceiving: + return + default: + topic.Publish(ctx, &Message{Data: []byte("some msg")}) + time.Sleep(time.Second) + } + } + }() + + go func() { + defer close(doneReceiving) + err = sub.Receive(ctx, func(_ context.Context, msg *Message) { + cancel() + time.AfterFunc(5*time.Second, msg.Ack) + }) + if err != nil { + t.Error(err) + } + }() + + select { + case <-time.After(60 * time.Second): + t.Fatalf("Waited 60 seconds for Receive to finish, should have finished sooner") + case <-doneReceiving: + } +} + +func TestIntegration_UpdateSubscription(t *testing.T) { + t.Parallel() + ctx := context.Background() + client := integrationTestClient(ctx, t) + defer client.Close() + + topic, err := client.CreateTopic(ctx, topicIDs.New()) + if err != nil { + t.Fatalf("CreateTopic error: %v", err) + } + defer topic.Stop() + defer topic.Delete(ctx) + + var sub *Subscription + if sub, err = client.CreateSubscription(ctx, subIDs.New(), SubscriptionConfig{Topic: topic}); err != nil { + t.Fatalf("CreateSub error: %v", err) + } + defer sub.Delete(ctx) + + got, err := sub.Config(ctx) + if err != nil { + t.Fatal(err) + } + want := SubscriptionConfig{ + Topic: topic, + AckDeadline: 10 * time.Second, + RetainAckedMessages: false, + RetentionDuration: defaultRetentionDuration, + } + if !testutil.Equal(got, want) { + t.Fatalf("\ngot %+v\nwant %+v", got, want) + } + // Add a PushConfig and change other fields. + projID := testutil.ProjID() + pc := PushConfig{ + Endpoint: "https://" + projID + ".appspot.com/_ah/push-handlers/push", + Attributes: map[string]string{"x-goog-version": "v1"}, + } + got, err = sub.Update(ctx, SubscriptionConfigToUpdate{ + PushConfig: &pc, + AckDeadline: 2 * time.Minute, + RetainAckedMessages: true, + RetentionDuration: 2 * time.Hour, + Labels: map[string]string{"label": "value"}, + }) + if err != nil { + t.Fatal(err) + } + want = SubscriptionConfig{ + Topic: topic, + PushConfig: pc, + AckDeadline: 2 * time.Minute, + RetainAckedMessages: true, + RetentionDuration: 2 * time.Hour, + Labels: map[string]string{"label": "value"}, + } + + if !testutil.Equal(got, want) { + t.Fatalf("\ngot %+v\nwant %+v", got, want) + } + + // Remove the PushConfig, turning the subscription back into pull mode. + // Change AckDeadline, remove labels. + pc = PushConfig{} + got, err = sub.Update(ctx, SubscriptionConfigToUpdate{ + PushConfig: &pc, + AckDeadline: 30 * time.Second, + Labels: map[string]string{}, + }) + if err != nil { + t.Fatal(err) + } + want.PushConfig = pc + want.AckDeadline = 30 * time.Second + want.Labels = nil + // service issue: PushConfig attributes are not removed. + // TODO(jba): remove when issue resolved. + want.PushConfig.Attributes = map[string]string{"x-goog-version": "v1"} + if !testutil.Equal(got, want) { + t.Fatalf("\ngot %+v\nwant %+v", got, want) + } + // If nothing changes, our client returns an error. + _, err = sub.Update(ctx, SubscriptionConfigToUpdate{}) + if err == nil { + t.Fatal("got nil, wanted error") + } +} + +// NOTE: This test should be skipped by open source contributors. It requires +// whitelisting, a (gsuite) organization project, and specific permissions. +func TestIntegration_UpdateTopic(t *testing.T) { + t.Parallel() + ctx := context.Background() + client := integrationTestClient(ctx, t) + defer client.Close() + + compareConfig := func(got TopicConfig, wantLabels map[string]string) bool { + if !testutil.Equal(got.Labels, wantLabels) { + return false + } + // For MessageStoragePolicy, we don't want to check for an exact set of regions. + // That set may change at any time. Instead, just make sure that the set isn't empty. + if len(got.MessageStoragePolicy.AllowedPersistenceRegions) == 0 { + return false + } + return true + } + + topic, err := client.CreateTopic(ctx, topicIDs.New()) + if err != nil { + t.Fatalf("CreateTopic error: %v", err) + } + defer topic.Stop() + defer topic.Delete(ctx) + + got, err := topic.Config(ctx) + if err != nil { + t.Fatal(err) + } + if !compareConfig(got, nil) { + t.Fatalf("\ngot %+v\nwant no labels", got) + } + + labels := map[string]string{"label": "value"} + got, err = topic.Update(ctx, TopicConfigToUpdate{Labels: labels}) + if err != nil { + t.Fatal(err) + } + if !compareConfig(got, labels) { + t.Fatalf("\ngot %+v\nwant labels %+v", got, labels) + } + // Remove all labels. + got, err = topic.Update(ctx, TopicConfigToUpdate{Labels: map[string]string{}}) + if err != nil { + t.Fatal(err) + } + if !compareConfig(got, nil) { + t.Fatalf("\ngot %+v\nwant no labels", got) + } +} + +func TestIntegration_PublicTopic(t *testing.T) { + t.Parallel() + ctx := context.Background() + client := integrationTestClient(ctx, t) + defer client.Close() + + sub, err := client.CreateSubscription(ctx, subIDs.New(), SubscriptionConfig{ + Topic: client.TopicInProject("taxirides-realtime", "pubsub-public-data"), + }) + if err != nil { + t.Fatal(err) + } + defer sub.Delete(ctx) + // Confirm that Receive works. It doesn't matter if we actually get any + // messages. + ctxt, cancel := context.WithTimeout(ctx, 5*time.Second) + err = sub.Receive(ctxt, func(_ context.Context, msg *Message) { + msg.Ack() + cancel() + }) + if err != nil { + t.Fatal(err) + } +} + +func TestIntegration_Errors(t *testing.T) { + // Test various edge conditions. + t.Parallel() + ctx := context.Background() + client := integrationTestClient(ctx, t) + defer client.Close() + + topic, err := client.CreateTopic(ctx, topicIDs.New()) + if err != nil { + t.Fatalf("CreateTopic error: %v", err) + } + defer topic.Stop() + defer topic.Delete(ctx) + + // Out-of-range retention duration. + sub, err := client.CreateSubscription(ctx, subIDs.New(), SubscriptionConfig{ + Topic: topic, + RetentionDuration: 1 * time.Second, + }) + if want := codes.InvalidArgument; grpc.Code(err) != want { + t.Errorf("got <%v>, want %s", err, want) + } + if err == nil { + sub.Delete(ctx) + } + + // Ack deadline less than minimum. + sub, err = client.CreateSubscription(ctx, subIDs.New(), SubscriptionConfig{ + Topic: topic, + AckDeadline: 5 * time.Second, + }) + if want := codes.Unknown; grpc.Code(err) != want { + t.Errorf("got <%v>, want %s", err, want) + } + if err == nil { + sub.Delete(ctx) + } + + // Updating a non-existent subscription. + sub = client.Subscription(subIDs.New()) + _, err = sub.Update(ctx, SubscriptionConfigToUpdate{AckDeadline: 20 * time.Second}) + if want := codes.NotFound; grpc.Code(err) != want { + t.Errorf("got <%v>, want %s", err, want) + } + // Deleting a non-existent subscription. + err = sub.Delete(ctx) + if want := codes.NotFound; grpc.Code(err) != want { + t.Errorf("got <%v>, want %s", err, want) + } + + // Updating out-of-range retention duration. + sub, err = client.CreateSubscription(ctx, subIDs.New(), SubscriptionConfig{Topic: topic}) + if err != nil { + t.Fatal(err) + } + defer sub.Delete(ctx) + _, err = sub.Update(ctx, SubscriptionConfigToUpdate{RetentionDuration: 1000 * time.Hour}) + if want := codes.InvalidArgument; grpc.Code(err) != want { + t.Errorf("got <%v>, want %s", err, want) + } +} + +// NOTE: This test should be skipped by open source contributors. It requires +// whitelisting, a (gsuite) organization project, and specific permissions. +// +// Googlers, see internal bug 77920644. Furthermore, be sure to add your +// service account as an owner of ps-geofencing-test. +func TestIntegration_MessageStoragePolicy(t *testing.T) { + // Verify that the message storage policy is populated. + if testing.Short() { + t.Skip("Integration tests skipped in short mode") + } + ctx := context.Background() + // The message storage policy depends on the Resource Location Restriction org policy. + // The usual testing project is in the google.com org, which has no resource location restrictions, + // so we will always see an empty MessageStoragePolicy. Use a project in another org that does + // have a restriction set ("us-east1"). + projID := "ps-geofencing-test" + // We can use the same creds as always because the service account of the default testing project + // has permission to use the above project. This test will fail if a different service account + // is used for testing. + ts := testutil.TokenSource(ctx, ScopePubSub, ScopeCloudPlatform) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + client, err := NewClient(ctx, projID, option.WithTokenSource(ts)) + if err != nil { + t.Fatalf("Creating client error: %v", err) + } + topic, err := client.CreateTopic(ctx, topicIDs.New()) + if err != nil { + t.Fatalf("CreateTopic error: %v", err) + } + defer topic.Stop() + defer topic.Delete(ctx) + + config, err := topic.Config(ctx) + if err != nil { + t.Fatal(err) + } + got := config.MessageStoragePolicy.AllowedPersistenceRegions + want := []string{"us-east1"} + if !testutil.Equal(got, want) { + t.Errorf("got %v, want %v", got, want) + } +} diff --git a/vendor/cloud.google.com/go/pubsub/internal/distribution/distribution.go b/vendor/cloud.google.com/go/pubsub/internal/distribution/distribution.go new file mode 100644 index 00000000..6571c90a --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/internal/distribution/distribution.go @@ -0,0 +1,69 @@ +// Copyright 2017 Google LLC +// +// 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 distribution + +import ( + "log" + "math" + "sort" + "sync/atomic" +) + +// D is a distribution. Methods of D can be called concurrently by multiple +// goroutines. +type D struct { + buckets []uint64 +} + +// New creates a new distribution capable of holding values from 0 to n-1. +func New(n int) *D { + return &D{ + buckets: make([]uint64, n), + } +} + +// Record records value v to the distribution. +// To help with distributions with long tails, if v is larger than the maximum value, +// Record records the maximum value instead. +// If v is negative, Record panics. +func (d *D) Record(v int) { + if v < 0 { + log.Panicf("Record: value out of range: %d", v) + } else if v >= len(d.buckets) { + v = len(d.buckets) - 1 + } + atomic.AddUint64(&d.buckets[v], 1) +} + +// Percentile computes the p-th percentile of the distribution where +// p is between 0 and 1. This method is thread-safe. +func (d *D) Percentile(p float64) int { + // NOTE: This implementation uses the nearest-rank method. + // https://en.wikipedia.org/wiki/Percentile#The_nearest-rank_method + + if p < 0 || p > 1 { + log.Panicf("Percentile: percentile out of range: %f", p) + } + + sums := make([]uint64, len(d.buckets)) + var sum uint64 + for i := range sums { + sum += atomic.LoadUint64(&d.buckets[i]) + sums[i] = sum + } + + target := uint64(math.Ceil(float64(sum) * p)) + return sort.Search(len(sums), func(i int) bool { return sums[i] >= target }) +} diff --git a/vendor/cloud.google.com/go/pubsub/internal/distribution/distribution_test.go b/vendor/cloud.google.com/go/pubsub/internal/distribution/distribution_test.go new file mode 100644 index 00000000..5e9296d2 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/internal/distribution/distribution_test.go @@ -0,0 +1,94 @@ +// Copyright 2017 Google LLC +// +// 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 distribution + +import ( + "sync" + "testing" +) + +func TestDistribution(t *testing.T) { + // These tests come from examples in https://en.wikipedia.org/wiki/Percentile#The_nearest-rank_method + tests := []struct { + // values in distribution + vals []int + + // percentiles and expected percentile values + pp []float64 + vv []int + }{ + { + vals: []int{15, 20, 35, 40, 50}, + pp: []float64{0.05, 0.3, 0.4, 0.5, 1}, + vv: []int{15, 20, 20, 35, 50}, + }, + { + vals: []int{3, 6, 7, 8, 8, 10, 13, 15, 16, 20}, + pp: []float64{0.25, 0.5, 0.75, 1}, + vv: []int{7, 8, 15, 20}, + }, + { + vals: []int{3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20}, + pp: []float64{0.25, 0.5, 0.75, 1}, + vv: []int{7, 9, 15, 20}, + }, + } + + maxVal := 0 + for _, tst := range tests { + for _, v := range tst.vals { + if maxVal < v { + maxVal = v + } + } + } + + for _, tst := range tests { + d := New(maxVal + 1) + for _, v := range tst.vals { + d.Record(v) + } + for i, p := range tst.pp { + got, want := d.Percentile(p), tst.vv[i] + if got != want { + t.Errorf("d=%v, d.Percentile(%f)=%d, want %d", d, p, got, want) + } + } + } +} + +func TestRace(t *testing.T) { + const N int = 1e3 + const parallel = 2 + + d := New(N) + + var wg sync.WaitGroup + wg.Add(parallel) + for i := 0; i < parallel; i++ { + go func() { + for i := 0; i < N; i++ { + d.Record(i) + } + wg.Done() + }() + } + + for i := 0; i < N; i++ { + if p := d.Percentile(0.5); p > N { + t.Fatalf("d.Percentile(0.5)=%d, expected to be at most %d", p, N) + } + } +} diff --git a/vendor/cloud.google.com/go/pubsub/iterator.go b/vendor/cloud.google.com/go/pubsub/iterator.go new file mode 100644 index 00000000..5b3415e4 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/iterator.go @@ -0,0 +1,498 @@ +// Copyright 2016 Google LLC +// +// 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 pubsub + +import ( + "context" + "io" + "sync" + "time" + + vkit "cloud.google.com/go/pubsub/apiv1" + "cloud.google.com/go/pubsub/internal/distribution" + gax "github.com/googleapis/gax-go" + pb "google.golang.org/genproto/googleapis/pubsub/v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// Between message receipt and ack (that is, the time spent processing a message) we want to extend the message +// deadline by way of modack. However, we don't want to extend the deadline right as soon as the deadline expires; +// instead, we'd want to extend the deadline a little bit of time ahead. gracePeriod is that amount of time ahead +// of the actual deadline. +const gracePeriod = 5 * time.Second + +type messageIterator struct { + ctx context.Context + cancel func() // the function that will cancel ctx; called in stop + po *pullOptions + ps *pullStream + subc *vkit.SubscriberClient + subName string + kaTick <-chan time.Time // keep-alive (deadline extensions) + ackTicker *time.Ticker // message acks + nackTicker *time.Ticker // message nacks (more frequent than acks) + pingTicker *time.Ticker // sends to the stream to keep it open + failed chan struct{} // closed on stream error + drained chan struct{} // closed when stopped && no more pending messages + wg sync.WaitGroup + + mu sync.Mutex + ackTimeDist *distribution.D // dist uses seconds + + // keepAliveDeadlines is a map of id to expiration time. This map is used in conjunction with + // subscription.ReceiveSettings.MaxExtension to record the maximum amount of time (the + // deadline, more specifically) we're willing to extend a message's ack deadline. As each + // message arrives, we'll record now+MaxExtension in this table; whenever we have a chance + // to update ack deadlines (via modack), we'll consult this table and only include IDs + // that are not beyond their deadline. + keepAliveDeadlines map[string]time.Time + pendingAcks map[string]bool + pendingNacks map[string]bool + pendingModAcks map[string]bool // ack IDs whose ack deadline is to be modified + err error // error from stream failure + + minAckDeadline time.Duration +} + +// newMessageIterator starts and returns a new messageIterator. +// subName is the full name of the subscription to pull messages from. +// Stop must be called on the messageIterator when it is no longer needed. +// The iterator always uses the background context for acking messages and extending message deadlines. +func newMessageIterator(subc *vkit.SubscriberClient, subName string, po *pullOptions) *messageIterator { + var ps *pullStream + if !po.synchronous { + ps = newPullStream(context.Background(), subc.StreamingPull, subName) + } + // The period will update each tick based on the distribution of acks. We'll start by arbitrarily sending + // the first keepAlive halfway towards the minimum ack deadline. + keepAlivePeriod := minAckDeadline / 2 + + // Ack promptly so users don't lose work if client crashes. + ackTicker := time.NewTicker(100 * time.Millisecond) + nackTicker := time.NewTicker(100 * time.Millisecond) + pingTicker := time.NewTicker(30 * time.Second) + cctx, cancel := context.WithCancel(context.Background()) + it := &messageIterator{ + ctx: cctx, + cancel: cancel, + ps: ps, + po: po, + subc: subc, + subName: subName, + kaTick: time.After(keepAlivePeriod), + ackTicker: ackTicker, + nackTicker: nackTicker, + pingTicker: pingTicker, + failed: make(chan struct{}), + drained: make(chan struct{}), + ackTimeDist: distribution.New(int(maxAckDeadline/time.Second) + 1), + keepAliveDeadlines: map[string]time.Time{}, + pendingAcks: map[string]bool{}, + pendingNacks: map[string]bool{}, + pendingModAcks: map[string]bool{}, + } + it.wg.Add(1) + go it.sender() + return it +} + +// Subscription.receive will call stop on its messageIterator when finished with it. +// Stop will block until Done has been called on all Messages that have been +// returned by Next, or until the context with which the messageIterator was created +// is cancelled or exceeds its deadline. +func (it *messageIterator) stop() { + it.cancel() + it.mu.Lock() + it.checkDrained() + it.mu.Unlock() + it.wg.Wait() +} + +// checkDrained closes the drained channel if the iterator has been stopped and all +// pending messages have either been n/acked or expired. +// +// Called with the lock held. +func (it *messageIterator) checkDrained() { + select { + case <-it.drained: + return + default: + } + select { + case <-it.ctx.Done(): + if len(it.keepAliveDeadlines) == 0 { + close(it.drained) + } + default: + } +} + +// Called when a message is acked/nacked. +func (it *messageIterator) done(ackID string, ack bool, receiveTime time.Time) { + it.ackTimeDist.Record(int(time.Since(receiveTime) / time.Second)) + it.mu.Lock() + defer it.mu.Unlock() + delete(it.keepAliveDeadlines, ackID) + if ack { + it.pendingAcks[ackID] = true + } else { + it.pendingNacks[ackID] = true + } + it.checkDrained() +} + +// fail is called when a stream method returns a permanent error. +// fail returns it.err. This may be err, or it may be the error +// set by an earlier call to fail. +func (it *messageIterator) fail(err error) error { + it.mu.Lock() + defer it.mu.Unlock() + if it.err == nil { + it.err = err + close(it.failed) + } + return it.err +} + +// receive makes a call to the stream's Recv method, or the Pull RPC, and returns +// its messages. +// maxToPull is the maximum number of messages for the Pull RPC. +func (it *messageIterator) receive(maxToPull int32) ([]*Message, error) { + it.mu.Lock() + ierr := it.err + it.mu.Unlock() + if ierr != nil { + return nil, ierr + } + + // Stop retrieving messages if the iterator's Stop method was called. + select { + case <-it.ctx.Done(): + it.wg.Wait() + return nil, io.EOF + default: + } + + var rmsgs []*pb.ReceivedMessage + var err error + if it.po.synchronous { + rmsgs, err = it.pullMessages(maxToPull) + } else { + rmsgs, err = it.recvMessages() + } + // Any error here is fatal. + if err != nil { + return nil, it.fail(err) + } + msgs, err := convertMessages(rmsgs) + if err != nil { + return nil, it.fail(err) + } + // We received some messages. Remember them so we can keep them alive. Also, + // do a receipt mod-ack when streaming. + maxExt := time.Now().Add(it.po.maxExtension) + ackIDs := map[string]bool{} + it.mu.Lock() + now := time.Now() + for _, m := range msgs { + m.receiveTime = now + addRecv(m.ID, m.ackID, now) + m.doneFunc = it.done + it.keepAliveDeadlines[m.ackID] = maxExt + // Don't change the mod-ack if the message is going to be nacked. This is + // possible if there are retries. + if !it.pendingNacks[m.ackID] && !it.po.synchronous { + ackIDs[m.ackID] = true + } + } + deadline := it.ackDeadline() + it.mu.Unlock() + if len(ackIDs) > 0 { + if !it.sendModAck(ackIDs, deadline) { + return nil, it.err + } + } + return msgs, nil +} + +// Get messages using the Pull RPC. +// This may block indefinitely. It may also return zero messages, after some time waiting. +func (it *messageIterator) pullMessages(maxToPull int32) ([]*pb.ReceivedMessage, error) { + // Use it.ctx as the RPC context, so that if the iterator is stopped, the call + // will return immediately. + res, err := it.subc.Pull(it.ctx, &pb.PullRequest{ + Subscription: it.subName, + MaxMessages: maxToPull, + }) + switch { + case err == context.Canceled: + return nil, nil + case err != nil: + return nil, err + default: + return res.ReceivedMessages, nil + } +} + +func (it *messageIterator) recvMessages() ([]*pb.ReceivedMessage, error) { + res, err := it.ps.Recv() + if err != nil { + return nil, err + } + return res.ReceivedMessages, nil +} + +// sender runs in a goroutine and handles all sends to the stream. +func (it *messageIterator) sender() { + defer it.wg.Done() + defer it.ackTicker.Stop() + defer it.nackTicker.Stop() + defer it.pingTicker.Stop() + defer func() { + if it.ps != nil { + it.ps.CloseSend() + } + }() + + done := false + for !done { + sendAcks := false + sendNacks := false + sendModAcks := false + sendPing := false + + dl := it.ackDeadline() + + select { + case <-it.failed: + // Stream failed: nothing to do, so stop immediately. + return + + case <-it.drained: + // All outstanding messages have been marked done: + // nothing left to do except make the final calls. + it.mu.Lock() + sendAcks = (len(it.pendingAcks) > 0) + sendNacks = (len(it.pendingNacks) > 0) + // No point in sending modacks. + done = true + + case <-it.kaTick: + it.mu.Lock() + it.handleKeepAlives() + sendModAcks = (len(it.pendingModAcks) > 0) + + nextTick := dl - gracePeriod + if nextTick <= 0 { + // If the deadline is <= gracePeriod, let's tick again halfway to + // the deadline. + nextTick = dl / 2 + } + it.kaTick = time.After(nextTick) + + case <-it.nackTicker.C: + it.mu.Lock() + sendNacks = (len(it.pendingNacks) > 0) + + case <-it.ackTicker.C: + it.mu.Lock() + sendAcks = (len(it.pendingAcks) > 0) + + case <-it.pingTicker.C: + it.mu.Lock() + // Ping only if we are processing messages via streaming. + sendPing = !it.po.synchronous && (len(it.keepAliveDeadlines) > 0) + } + // Lock is held here. + var acks, nacks, modAcks map[string]bool + if sendAcks { + acks = it.pendingAcks + it.pendingAcks = map[string]bool{} + } + if sendNacks { + nacks = it.pendingNacks + it.pendingNacks = map[string]bool{} + } + if sendModAcks { + modAcks = it.pendingModAcks + it.pendingModAcks = map[string]bool{} + } + it.mu.Unlock() + // Make Ack and ModAck RPCs. + if sendAcks { + if !it.sendAck(acks) { + return + } + } + if sendNacks { + // Nack indicated by modifying the deadline to zero. + if !it.sendModAck(nacks, 0) { + return + } + } + if sendModAcks { + if !it.sendModAck(modAcks, dl) { + return + } + } + if sendPing { + it.pingStream() + } + } +} + +// handleKeepAlives modifies the pending request to include deadline extensions +// for live messages. It also purges expired messages. +// +// Called with the lock held. +func (it *messageIterator) handleKeepAlives() { + now := time.Now() + for id, expiry := range it.keepAliveDeadlines { + if expiry.Before(now) { + // This delete will not result in skipping any map items, as implied by + // the spec at https://golang.org/ref/spec#For_statements, "For + // statements with range clause", note 3, and stated explicitly at + // https://groups.google.com/forum/#!msg/golang-nuts/UciASUb03Js/pzSq5iVFAQAJ. + delete(it.keepAliveDeadlines, id) + } else { + // This will not conflict with a nack, because nacking removes the ID from keepAliveDeadlines. + it.pendingModAcks[id] = true + } + } + it.checkDrained() +} + +func (it *messageIterator) sendAck(m map[string]bool) bool { + return it.sendAckIDRPC(m, func(ids []string) error { + recordStat(it.ctx, AckCount, int64(len(ids))) + addAcks(ids) + // Use context.Background() as the call's context, not it.ctx. We don't + // want to cancel this RPC when the iterator is stopped. + return it.subc.Acknowledge(context.Background(), &pb.AcknowledgeRequest{ + Subscription: it.subName, + AckIds: ids, + }) + }) +} + +// The receipt mod-ack amount is derived from a percentile distribution based +// on the time it takes to process messages. The percentile chosen is the 99%th +// percentile in order to capture the highest amount of time necessary without +// considering 1% outliers. +func (it *messageIterator) sendModAck(m map[string]bool, deadline time.Duration) bool { + return it.sendAckIDRPC(m, func(ids []string) error { + if deadline == 0 { + recordStat(it.ctx, NackCount, int64(len(ids))) + } else { + recordStat(it.ctx, ModAckCount, int64(len(ids))) + } + addModAcks(ids, int32(deadline/time.Second)) + // Retry this RPC on Unavailable for a short amount of time, then give up + // without returning a fatal error. The utility of this RPC is by nature + // transient (since the deadline is relative to the current time) and it + // isn't crucial for correctness (since expired messages will just be + // resent). + cctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + bo := gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: time.Second, + Multiplier: 2, + } + for { + err := it.subc.ModifyAckDeadline(cctx, &pb.ModifyAckDeadlineRequest{ + Subscription: it.subName, + AckDeadlineSeconds: int32(deadline / time.Second), + AckIds: ids, + }) + switch status.Code(err) { + case codes.Unavailable: + if err := gax.Sleep(cctx, bo.Pause()); err == nil { + continue + } + // Treat sleep timeout like RPC timeout. + fallthrough + case codes.DeadlineExceeded: + // Timeout. Not a fatal error, but note that it happened. + recordStat(it.ctx, ModAckTimeoutCount, 1) + return nil + default: + // Any other error is fatal. + return err + } + } + }) +} + +func (it *messageIterator) sendAckIDRPC(ackIDSet map[string]bool, call func([]string) error) bool { + ackIDs := make([]string, 0, len(ackIDSet)) + for k := range ackIDSet { + ackIDs = append(ackIDs, k) + } + var toSend []string + for len(ackIDs) > 0 { + toSend, ackIDs = splitRequestIDs(ackIDs, maxPayload) + if err := call(toSend); err != nil { + // The underlying client handles retries, so any error is fatal to the + // iterator. + it.fail(err) + return false + } + } + return true +} + +// Send a message to the stream to keep it open. The stream will close if there's no +// traffic on it for a while. By keeping it open, we delay the start of the +// expiration timer on messages that are buffered by gRPC or elsewhere in the +// network. This matters if it takes a long time to process messages relative to the +// default ack deadline, and if the messages are small enough so that many can fit +// into the buffer. +func (it *messageIterator) pingStream() { + // Ignore error; if the stream is broken, this doesn't matter anyway. + _ = it.ps.Send(&pb.StreamingPullRequest{}) +} + +func splitRequestIDs(ids []string, maxSize int) (prefix, remainder []string) { + size := reqFixedOverhead + i := 0 + for size < maxSize && i < len(ids) { + size += overheadPerID + len(ids[i]) + i++ + } + if size > maxSize { + i-- + } + return ids[:i], ids[i:] +} + +// The deadline to ack is derived from a percentile distribution based +// on the time it takes to process messages. The percentile chosen is the 99%th +// percentile - that is, processing times up to the 99%th longest processing +// times should be safe. The highest 1% may expire. This number was chosen +// as a way to cover most users' usecases without losing the value of +// expiration. +func (it *messageIterator) ackDeadline() time.Duration { + pt := time.Duration(it.ackTimeDist.Percentile(.99)) * time.Second + + if pt > maxAckDeadline { + return maxAckDeadline + } + if pt < minAckDeadline { + return minAckDeadline + } + return pt +} diff --git a/vendor/cloud.google.com/go/pubsub/iterator_test.go b/vendor/cloud.google.com/go/pubsub/iterator_test.go new file mode 100644 index 00000000..6ed4fb64 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/iterator_test.go @@ -0,0 +1,297 @@ +// Copyright 2017 Google LLC +// +// 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 pubsub + +import ( + "context" + "errors" + "fmt" + "reflect" + "sync" + "sync/atomic" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/pubsub/pstest" + "google.golang.org/api/option" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var ( + projName = "some-project" + topicName = "some-topic" + fullyQualifiedTopicName = fmt.Sprintf("projects/%s/topics/%s", projName, topicName) +) + +func TestSplitRequestIDs(t *testing.T) { + t.Parallel() + ids := []string{"aaaa", "bbbb", "cccc", "dddd", "eeee"} + for _, test := range []struct { + ids []string + splitIndex int + }{ + {[]string{}, 0}, + {ids, 2}, + {ids[:2], 2}, + } { + got1, got2 := splitRequestIDs(test.ids, reqFixedOverhead+20) + want1, want2 := test.ids[:test.splitIndex], test.ids[test.splitIndex:] + if !testutil.Equal(got1, want1) { + t.Errorf("%v, 1: got %v, want %v", test, got1, want1) + } + if !testutil.Equal(got2, want2) { + t.Errorf("%v, 2: got %v, want %v", test, got2, want2) + } + } +} + +func TestAckDistribution(t *testing.T) { + if testing.Short() { + t.SkipNow() + } + t.Skip("broken") + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + minAckDeadline = 1 * time.Second + pstest.SetMinAckDeadline(minAckDeadline) + srv := pstest.NewServer() + defer srv.Close() + defer pstest.ResetMinAckDeadline() + + // Create the topic via a Publish. It's convenient to do it here as opposed to client.CreateTopic because the client + // has not been established yet, and also because we want to create the topic once whereas the client is established + // below twice. + srv.Publish(fullyQualifiedTopicName, []byte("creating a topic"), nil) + + queuedMsgs := make(chan int32, 1024) + go continuouslySend(ctx, srv, queuedMsgs) + + for _, testcase := range []struct { + initialProcessSecs int32 + finalProcessSecs int32 + }{ + {initialProcessSecs: 3, finalProcessSecs: 5}, // Process time goes up + {initialProcessSecs: 5, finalProcessSecs: 3}, // Process time goes down + } { + t.Logf("Testing %d -> %d", testcase.initialProcessSecs, testcase.finalProcessSecs) + + // processTimeSecs is used by the sender to coordinate with the receiver how long the receiver should + // pretend to process for. e.g. if we test 3s -> 5s, processTimeSecs will start at 3, causing receiver + // to process messages received for 3s while sender sends the first batch. Then, as sender begins to + // send the next batch, sender will swap processTimeSeconds to 5s and begin sending, and receiver will + // process each message for 5s. In this way we simulate a client whose time-to-ack (process time) changes. + processTimeSecs := testcase.initialProcessSecs + + s, client, err := initConn(ctx, srv.Addr) + if err != nil { + t.Fatal(err) + } + + // recvdWg increments for each message sent, and decrements for each message received. + recvdWg := &sync.WaitGroup{} + + go startReceiving(ctx, t, s, recvdWg, &processTimeSecs) + startSending(t, queuedMsgs, &processTimeSecs, testcase.initialProcessSecs, testcase.finalProcessSecs, recvdWg) + + recvdWg.Wait() + time.Sleep(100 * time.Millisecond) // Wait a bit more for resources to clean up + err = client.Close() + if err != nil { + t.Fatal(err) + } + + modacks := modacksByTime(srv.Messages()) + u := modackDeadlines(modacks) + initialDL := int32(minAckDeadline / time.Second) + if !setsAreEqual(u, []int32{initialDL, testcase.initialProcessSecs, testcase.finalProcessSecs}) { + t.Fatalf("Expected modack deadlines to contain (exactly, and only) %ds, %ds, %ds. Instead, got %v", + initialDL, testcase.initialProcessSecs, testcase.finalProcessSecs, toSet(u)) + } + } +} + +// modacksByTime buckets modacks by time. +func modacksByTime(msgs []*pstest.Message) map[time.Time][]pstest.Modack { + modacks := map[time.Time][]pstest.Modack{} + + for _, msg := range msgs { + for _, m := range msg.Modacks { + modacks[m.ReceivedAt] = append(modacks[m.ReceivedAt], m) + } + } + return modacks +} + +// setsAreEqual reports whether a and b contain the same values, ignoring duplicates. +func setsAreEqual(haystack, needles []int32) bool { + hMap := map[int32]bool{} + nMap := map[int32]bool{} + + for _, n := range needles { + nMap[n] = true + } + + for _, n := range haystack { + hMap[n] = true + } + + return reflect.DeepEqual(nMap, hMap) +} + +// startReceiving pretends to be a client. It calls s.Receive and acks messages after some random delay. It also +// looks out for dupes - any message that arrives twice will cause a failure. +func startReceiving(ctx context.Context, t *testing.T, s *Subscription, recvdWg *sync.WaitGroup, processTimeSecs *int32) { + t.Log("Receiving..") + + var recvdMu sync.Mutex + recvd := map[string]bool{} + + err := s.Receive(ctx, func(ctx context.Context, msg *Message) { + msgData := string(msg.Data) + recvdMu.Lock() + _, ok := recvd[msgData] + if ok { + recvdMu.Unlock() + t.Fatalf("already saw \"%s\"\n", msgData) + return + } + recvd[msgData] = true + recvdMu.Unlock() + + select { + case <-ctx.Done(): + msg.Nack() + recvdWg.Done() + case <-time.After(time.Duration(atomic.LoadInt32(processTimeSecs)) * time.Second): + msg.Ack() + recvdWg.Done() + } + }) + if err != nil { + if status.Code(err) != codes.Canceled { + t.Error(err) + } + } +} + +// startSending sends four batches of messages broken up by minDeadline, initialProcessSecs, and finalProcessSecs. +func startSending(t *testing.T, queuedMsgs chan int32, processTimeSecs *int32, initialProcessSecs int32, finalProcessSecs int32, recvdWg *sync.WaitGroup) { + var msg int32 + + // We must send this block to force the receiver to send its initially-configured modack time. The time that + // gets sent should be ignorant of the distribution, since there haven't been enough (any, actually) messages + // to create a distribution yet. + t.Log("minAckDeadlineSecsSending an initial message") + recvdWg.Add(1) + msg++ + queuedMsgs <- msg + <-time.After(minAckDeadline) + + t.Logf("Sending some messages to update distribution to %d. This new distribution will be used "+ + "when the next batch of messages go out.", initialProcessSecs) + for i := 0; i < 10; i++ { + recvdWg.Add(1) + msg++ + queuedMsgs <- msg + } + atomic.SwapInt32(processTimeSecs, finalProcessSecs) + <-time.After(time.Duration(initialProcessSecs) * time.Second) + + t.Logf("Sending many messages to update distribution to %d. This new distribution will be used "+ + "when the next batch of messages go out.", finalProcessSecs) + for i := 0; i < 100; i++ { + recvdWg.Add(1) + msg++ + queuedMsgs <- msg // Send many messages to drastically change distribution + } + <-time.After(time.Duration(finalProcessSecs) * time.Second) + + t.Logf("Last message going out, whose deadline should be %d.", finalProcessSecs) + recvdWg.Add(1) + msg++ + queuedMsgs <- msg +} + +// continuouslySend continuously sends messages that exist on the queuedMsgs chan. +func continuouslySend(ctx context.Context, srv *pstest.Server, queuedMsgs chan int32) { + for { + select { + case <-ctx.Done(): + return + case m := <-queuedMsgs: + srv.Publish(fullyQualifiedTopicName, []byte(fmt.Sprintf("message %d", m)), nil) + } + } +} + +func toSet(arr []int32) []int32 { + var s []int32 + m := map[int32]bool{} + + for _, v := range arr { + _, ok := m[v] + if !ok { + s = append(s, v) + m[v] = true + } + } + + return s + +} + +func initConn(ctx context.Context, addr string) (*Subscription, *Client, error) { + conn, err := grpc.Dial(addr, grpc.WithInsecure()) + if err != nil { + return nil, nil, err + } + client, err := NewClient(ctx, projName, option.WithGRPCConn(conn)) + if err != nil { + return nil, nil, err + } + + topic := client.Topic(topicName) + s, err := client.CreateSubscription(ctx, fmt.Sprintf("sub-%d", time.Now().UnixNano()), SubscriptionConfig{Topic: topic}) + if err != nil { + return nil, nil, err + } + + exists, err := s.Exists(ctx) + if !exists { + return nil, nil, errors.New("Subscription does not exist") + } + if err != nil { + return nil, nil, err + } + + return s, client, nil +} + +// modackDeadlines takes a map of time => Modack, gathers all the Modack.AckDeadlines, +// and returns them as a slice +func modackDeadlines(m map[time.Time][]pstest.Modack) []int32 { + var u []int32 + for _, vv := range m { + for _, v := range vv { + u = append(u, v.AckDeadline) + } + } + return u +} diff --git a/vendor/cloud.google.com/go/pubsub/loadtest/benchmark_test.go b/vendor/cloud.google.com/go/pubsub/loadtest/benchmark_test.go new file mode 100644 index 00000000..885caa2d --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/loadtest/benchmark_test.go @@ -0,0 +1,175 @@ +// Copyright 2017 Google LLC +// +// 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 loadtest + +// Performance benchmarks for pubsub. +// Run with +// go test -bench . -cpu 1 + +import ( + "context" + "log" + "sync" + "sync/atomic" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/pubsub" + "google.golang.org/api/option" + gtransport "google.golang.org/api/transport/grpc" + pb "google.golang.org/genproto/googleapis/pubsub/v1" + "google.golang.org/grpc" +) + +// These constants are designed to match the "throughput" test in +// https://github.com/GoogleCloudPlatform/pubsub/blob/master/load-test-framework/run.py +// and +// https://github.com/GoogleCloudPlatform/pubsub/blob/master/load-test-framework/src/main/java/com/google/pubsub/clients/experimental/CPSPublisherTask.java + +const ( + nMessages = 1e5 + messageSize = 10000 // size of msg data in bytes + batchSize = 10 + batchDuration = 50 * time.Millisecond + serverDelay = 200 * time.Millisecond + maxOutstandingPublishes = 1600 // max_outstanding_messages in run.py +) + +func BenchmarkPublishThroughput(b *testing.B) { + b.SetBytes(nMessages * messageSize) + client := perfClient(serverDelay, 1, b) + + lts := &PubServer{ID: "xxx"} + lts.init(client, "t", messageSize, batchSize, batchDuration) + b.ResetTimer() + for i := 0; i < b.N; i++ { + runOnce(lts) + } +} + +func runOnce(lts *PubServer) { + nRequests := int64(nMessages / batchSize) + var nPublished int64 + var wg sync.WaitGroup + // The Java loadtest framework is rate-limited to 1 billion Execute calls a + // second (each Execute call corresponding to a publishBatch call here), + // but we can ignore this because of the following. + // The framework runs 10,000 threads, each calling Execute in a loop, but + // we can ignore this too. + // The framework caps the number of outstanding calls to Execute at + // maxOutstandingPublishes. That is what we simulate here. + for i := 0; i < maxOutstandingPublishes; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for atomic.AddInt64(&nRequests, -1) >= 0 { + latencies, err := lts.publishBatch() + if err != nil { + log.Fatalf("publishBatch: %v", err) + } + atomic.AddInt64(&nPublished, int64(len(latencies))) + } + }() + } + wg.Wait() + sent := atomic.LoadInt64(&nPublished) + if sent != nMessages { + log.Fatalf("sent %d messages, expected %d", sent, int(nMessages)) + } +} + +func perfClient(pubDelay time.Duration, nConns int, f interface { + Fatal(...interface{}) +}) *pubsub.Client { + ctx := context.Background() + srv, err := newPerfServer(pubDelay) + if err != nil { + f.Fatal(err) + } + conn, err := gtransport.DialInsecure(ctx, + option.WithEndpoint(srv.Addr), + option.WithGRPCConnectionPool(nConns), + + // TODO(grpc/grpc-go#1388) using connection pool without WithBlock + // can cause RPCs to fail randomly. We can delete this after the issue is fixed. + option.WithGRPCDialOption(grpc.WithBlock())) + if err != nil { + f.Fatal(err) + } + client, err := pubsub.NewClient(ctx, "projectID", option.WithGRPCConn(conn)) + if err != nil { + f.Fatal(err) + } + return client +} + +type perfServer struct { + pb.PublisherServer + pb.SubscriberServer + + Addr string + pubDelay time.Duration + + mu sync.Mutex + activePubs int + maxActivePubs int +} + +func newPerfServer(pubDelay time.Duration) (*perfServer, error) { + srv, err := testutil.NewServer(grpc.MaxMsgSize(pubsub.MaxPublishRequestBytes)) + if err != nil { + return nil, err + } + perf := &perfServer{Addr: srv.Addr, pubDelay: pubDelay} + pb.RegisterPublisherServer(srv.Gsrv, perf) + pb.RegisterSubscriberServer(srv.Gsrv, perf) + srv.Start() + return perf, nil +} + +var doLog = false + +func (p *perfServer) incActivePubs(n int) (int, bool) { + p.mu.Lock() + defer p.mu.Unlock() + p.activePubs += n + newMax := false + if p.activePubs > p.maxActivePubs { + p.maxActivePubs = p.activePubs + newMax = true + } + return p.activePubs, newMax +} + +func (p *perfServer) Publish(ctx context.Context, req *pb.PublishRequest) (*pb.PublishResponse, error) { + a, newMax := p.incActivePubs(1) + defer p.incActivePubs(-1) + if newMax && doLog { + log.Printf("max %d active publish calls", a) + } + if doLog { + log.Printf("%p -> Publish %d", p, len(req.Messages)) + } + res := &pb.PublishResponse{MessageIds: make([]string, len(req.Messages))} + for i := range res.MessageIds { + res.MessageIds[i] = "x" + } + time.Sleep(p.pubDelay) + if doLog { + log.Printf("%p <- Publish %d", p, len(req.Messages)) + } + return res, nil +} diff --git a/vendor/cloud.google.com/go/pubsub/loadtest/cmd/loadtest.go b/vendor/cloud.google.com/go/pubsub/loadtest/cmd/loadtest.go new file mode 100644 index 00000000..6451959d --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/loadtest/cmd/loadtest.go @@ -0,0 +1,53 @@ +// Copyright 2017 Google LLC +// +// 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 main + +import ( + "flag" + "fmt" + "log" + "math/rand" + "net" + "strconv" + + "cloud.google.com/go/pubsub/loadtest" + pb "cloud.google.com/go/pubsub/loadtest/pb" + "google.golang.org/grpc" +) + +func main() { + port := flag.Uint("worker_port", 6000, "port to bind worker to") + role := flag.String("r", "", "role: pub/sub") + flag.Parse() + + var lts pb.LoadtestWorkerServer + switch *role { + case "pub": + lts = &loadtest.PubServer{ID: strconv.Itoa(rand.Int())} + case "sub": + lts = &loadtest.SubServer{} + default: + log.Fatalf("unknown role: %q", *role) + } + + serv := grpc.NewServer() + pb.RegisterLoadtestWorkerServer(serv, lts) + + lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port)) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + serv.Serve(lis) +} diff --git a/vendor/cloud.google.com/go/pubsub/loadtest/loadtest.go b/vendor/cloud.google.com/go/pubsub/loadtest/loadtest.go new file mode 100644 index 00000000..1daa21e1 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/loadtest/loadtest.go @@ -0,0 +1,220 @@ +// Copyright 2017 Google LLC +// +// 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 loadtest implements load testing for pubsub, +// following the interface defined in https://github.com/GoogleCloudPlatform/pubsub/tree/master/load-test-framework/ . +// +// This package is experimental. +package loadtest + +import ( + "bytes" + "context" + "errors" + "log" + "runtime" + "strconv" + "sync" + "sync/atomic" + "time" + + "cloud.google.com/go/pubsub" + pb "cloud.google.com/go/pubsub/loadtest/pb" + "github.com/golang/protobuf/ptypes" + "golang.org/x/time/rate" +) + +type pubServerConfig struct { + topic *pubsub.Topic + msgData []byte + batchSize int32 +} + +// PubServer is a dummy Pub/Sub server for load testing. +type PubServer struct { + ID string + + cfg atomic.Value + seqNum int32 +} + +// Start starts the server. +func (l *PubServer) Start(ctx context.Context, req *pb.StartRequest) (*pb.StartResponse, error) { + log.Println("received start") + c, err := pubsub.NewClient(ctx, req.Project) + if err != nil { + return nil, err + } + dur, err := ptypes.Duration(req.PublishBatchDuration) + if err != nil { + return nil, err + } + l.init(c, req.Topic, req.MessageSize, req.PublishBatchSize, dur) + log.Println("started") + return &pb.StartResponse{}, nil +} + +func (l *PubServer) init(c *pubsub.Client, topicName string, msgSize, batchSize int32, batchDur time.Duration) { + topic := c.Topic(topicName) + topic.PublishSettings = pubsub.PublishSettings{ + DelayThreshold: batchDur, + CountThreshold: 950, + ByteThreshold: 9500000, + } + + l.cfg.Store(pubServerConfig{ + topic: topic, + msgData: bytes.Repeat([]byte{'A'}, int(msgSize)), + batchSize: batchSize, + }) +} + +// Execute executes a request. +func (l *PubServer) Execute(ctx context.Context, _ *pb.ExecuteRequest) (*pb.ExecuteResponse, error) { + latencies, err := l.publishBatch() + if err != nil { + log.Printf("error: %v", err) + return nil, err + } + return &pb.ExecuteResponse{Latencies: latencies}, nil +} + +func (l *PubServer) publishBatch() ([]int64, error) { + var cfg pubServerConfig + if c, ok := l.cfg.Load().(pubServerConfig); ok { + cfg = c + } else { + return nil, errors.New("config not loaded") + } + + start := time.Now() + latencies := make([]int64, cfg.batchSize) + startStr := strconv.FormatInt(start.UnixNano()/1e6, 10) + seqNum := atomic.AddInt32(&l.seqNum, cfg.batchSize) - cfg.batchSize + + rs := make([]*pubsub.PublishResult, cfg.batchSize) + for i := int32(0); i < cfg.batchSize; i++ { + rs[i] = cfg.topic.Publish(context.TODO(), &pubsub.Message{ + Data: cfg.msgData, + Attributes: map[string]string{ + "sendTime": startStr, + "clientId": l.ID, + "sequenceNumber": strconv.Itoa(int(seqNum + i)), + }, + }) + } + for i, r := range rs { + _, err := r.Get(context.Background()) + if err != nil { + return nil, err + } + // TODO(jba,pongad): fix latencies + // Later values will be skewed by earlier ones, since we wait for the + // results in order. (On the other hand, it may not matter much, since + // messages are added to bundles in order and bundles get sent more or + // less in order.) If we want more accurate values, we can either start + // a goroutine for each result (similar to the original code using a + // callback), or call reflect.Select with the Ready channels of the + // results. + latencies[i] = time.Since(start).Nanoseconds() / 1e6 + } + return latencies, nil +} + +// SubServer is a dummy Pub/Sub server for load testing. +type SubServer struct { + // TODO(deklerk) what is this actually for? + lim *rate.Limiter + + mu sync.Mutex + idents []*pb.MessageIdentifier + latencies []int64 +} + +// Start starts the server. +func (s *SubServer) Start(ctx context.Context, req *pb.StartRequest) (*pb.StartResponse, error) { + log.Println("received start") + s.lim = rate.NewLimiter(rate.Every(time.Second), 1) + + c, err := pubsub.NewClient(ctx, req.Project) + if err != nil { + return nil, err + } + + // Load test API doesn't define any way to stop right now. + go func() { + sub := c.Subscription(req.GetPubsubOptions().Subscription) + sub.ReceiveSettings.NumGoroutines = 10 * runtime.GOMAXPROCS(0) + err := sub.Receive(context.Background(), s.callback) + log.Fatal(err) + }() + + log.Println("started") + return &pb.StartResponse{}, nil +} + +func (s *SubServer) callback(_ context.Context, m *pubsub.Message) { + id, err := strconv.ParseInt(m.Attributes["clientId"], 10, 64) + if err != nil { + log.Println(err) + m.Nack() + return + } + + seqNum, err := strconv.ParseInt(m.Attributes["sequenceNumber"], 10, 32) + if err != nil { + log.Println(err) + m.Nack() + return + } + + sendTimeMillis, err := strconv.ParseInt(m.Attributes["sendTime"], 10, 64) + if err != nil { + log.Println(err) + m.Nack() + return + } + + latency := time.Now().UnixNano()/1e6 - sendTimeMillis + ident := &pb.MessageIdentifier{ + PublisherClientId: id, + SequenceNumber: int32(seqNum), + } + + s.mu.Lock() + s.idents = append(s.idents, ident) + s.latencies = append(s.latencies, latency) + s.mu.Unlock() + m.Ack() +} + +// Execute executes the request. +func (s *SubServer) Execute(ctx context.Context, _ *pb.ExecuteRequest) (*pb.ExecuteResponse, error) { + // Throttle so the load tester doesn't spam us and consume all our CPU. + if err := s.lim.Wait(ctx); err != nil { + return nil, err + } + + s.mu.Lock() + idents := s.idents + s.idents = nil + latencies := s.latencies + s.latencies = nil + s.mu.Unlock() + + return &pb.ExecuteResponse{ + Latencies: latencies, + ReceivedMessages: idents, + }, nil +} diff --git a/vendor/cloud.google.com/go/pubsub/loadtest/pb/loadtest.pb.go b/vendor/cloud.google.com/go/pubsub/loadtest/pb/loadtest.pb.go new file mode 100644 index 00000000..055db455 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/loadtest/pb/loadtest.pb.go @@ -0,0 +1,793 @@ +// Code generated by protoc-gen-go. +// source: loadtest.proto +// DO NOT EDIT! + +/* +Package google_pubsub_loadtest is a generated protocol buffer package. + +It is generated from these files: + loadtest.proto + +It has these top-level messages: + StartRequest + StartResponse + PubsubOptions + KafkaOptions + MessageIdentifier + CheckRequest + CheckResponse + ExecuteRequest + ExecuteResponse +*/ +package google_pubsub_loadtest + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import google_protobuf "github.com/golang/protobuf/ptypes/duration" +import google_protobuf1 "github.com/golang/protobuf/ptypes/timestamp" + +import ( + "context" + + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type StartRequest struct { + // The GCP project. This must be set even for Kafka, as we use it to export metrics. + Project string `protobuf:"bytes,1,opt,name=project" json:"project,omitempty"` + // The Pub/Sub or Kafka topic name. + Topic string `protobuf:"bytes,2,opt,name=topic" json:"topic,omitempty"` + // The number of requests that can be made, each second, per client. + RequestRate int32 `protobuf:"varint,3,opt,name=request_rate,json=requestRate" json:"request_rate,omitempty"` + // The size of each user message to publish + MessageSize int32 `protobuf:"varint,4,opt,name=message_size,json=messageSize" json:"message_size,omitempty"` + // The maximum outstanding requests, per client. + MaxOutstandingRequests int32 `protobuf:"varint,5,opt,name=max_outstanding_requests,json=maxOutstandingRequests" json:"max_outstanding_requests,omitempty"` + // The time at which the load test should start. If this is less than the current time, we start immediately. + StartTime *google_protobuf1.Timestamp `protobuf:"bytes,6,opt,name=start_time,json=startTime" json:"start_time,omitempty"` + // The burn-in duration, before which results should not be reported. + BurnInDuration *google_protobuf.Duration `protobuf:"bytes,12,opt,name=burn_in_duration,json=burnInDuration" json:"burn_in_duration,omitempty"` + // The number of user messages of size message_size to publish together. + PublishBatchSize int32 `protobuf:"varint,11,opt,name=publish_batch_size,json=publishBatchSize" json:"publish_batch_size,omitempty"` + // The max duration for coalescing a batch of published messages. + PublishBatchDuration *google_protobuf.Duration `protobuf:"bytes,13,opt,name=publish_batch_duration,json=publishBatchDuration" json:"publish_batch_duration,omitempty"` + // Types that are valid to be assigned to StopConditions: + // *StartRequest_TestDuration + // *StartRequest_NumberOfMessages + StopConditions isStartRequest_StopConditions `protobuf_oneof:"stop_conditions"` + // Types that are valid to be assigned to Options: + // *StartRequest_PubsubOptions + // *StartRequest_KafkaOptions + Options isStartRequest_Options `protobuf_oneof:"options"` +} + +func (m *StartRequest) Reset() { *m = StartRequest{} } +func (m *StartRequest) String() string { return proto.CompactTextString(m) } +func (*StartRequest) ProtoMessage() {} +func (*StartRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +type isStartRequest_StopConditions interface { + isStartRequest_StopConditions() +} +type isStartRequest_Options interface { + isStartRequest_Options() +} + +type StartRequest_TestDuration struct { + TestDuration *google_protobuf.Duration `protobuf:"bytes,7,opt,name=test_duration,json=testDuration,oneof"` +} +type StartRequest_NumberOfMessages struct { + NumberOfMessages int32 `protobuf:"varint,8,opt,name=number_of_messages,json=numberOfMessages,oneof"` +} +type StartRequest_PubsubOptions struct { + PubsubOptions *PubsubOptions `protobuf:"bytes,9,opt,name=pubsub_options,json=pubsubOptions,oneof"` +} +type StartRequest_KafkaOptions struct { + KafkaOptions *KafkaOptions `protobuf:"bytes,10,opt,name=kafka_options,json=kafkaOptions,oneof"` +} + +func (*StartRequest_TestDuration) isStartRequest_StopConditions() {} +func (*StartRequest_NumberOfMessages) isStartRequest_StopConditions() {} +func (*StartRequest_PubsubOptions) isStartRequest_Options() {} +func (*StartRequest_KafkaOptions) isStartRequest_Options() {} + +func (m *StartRequest) GetStopConditions() isStartRequest_StopConditions { + if m != nil { + return m.StopConditions + } + return nil +} +func (m *StartRequest) GetOptions() isStartRequest_Options { + if m != nil { + return m.Options + } + return nil +} + +func (m *StartRequest) GetProject() string { + if m != nil { + return m.Project + } + return "" +} + +func (m *StartRequest) GetTopic() string { + if m != nil { + return m.Topic + } + return "" +} + +func (m *StartRequest) GetRequestRate() int32 { + if m != nil { + return m.RequestRate + } + return 0 +} + +func (m *StartRequest) GetMessageSize() int32 { + if m != nil { + return m.MessageSize + } + return 0 +} + +func (m *StartRequest) GetMaxOutstandingRequests() int32 { + if m != nil { + return m.MaxOutstandingRequests + } + return 0 +} + +func (m *StartRequest) GetStartTime() *google_protobuf1.Timestamp { + if m != nil { + return m.StartTime + } + return nil +} + +func (m *StartRequest) GetBurnInDuration() *google_protobuf.Duration { + if m != nil { + return m.BurnInDuration + } + return nil +} + +func (m *StartRequest) GetPublishBatchSize() int32 { + if m != nil { + return m.PublishBatchSize + } + return 0 +} + +func (m *StartRequest) GetPublishBatchDuration() *google_protobuf.Duration { + if m != nil { + return m.PublishBatchDuration + } + return nil +} + +func (m *StartRequest) GetTestDuration() *google_protobuf.Duration { + if x, ok := m.GetStopConditions().(*StartRequest_TestDuration); ok { + return x.TestDuration + } + return nil +} + +func (m *StartRequest) GetNumberOfMessages() int32 { + if x, ok := m.GetStopConditions().(*StartRequest_NumberOfMessages); ok { + return x.NumberOfMessages + } + return 0 +} + +func (m *StartRequest) GetPubsubOptions() *PubsubOptions { + if x, ok := m.GetOptions().(*StartRequest_PubsubOptions); ok { + return x.PubsubOptions + } + return nil +} + +func (m *StartRequest) GetKafkaOptions() *KafkaOptions { + if x, ok := m.GetOptions().(*StartRequest_KafkaOptions); ok { + return x.KafkaOptions + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*StartRequest) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _StartRequest_OneofMarshaler, _StartRequest_OneofUnmarshaler, _StartRequest_OneofSizer, []interface{}{ + (*StartRequest_TestDuration)(nil), + (*StartRequest_NumberOfMessages)(nil), + (*StartRequest_PubsubOptions)(nil), + (*StartRequest_KafkaOptions)(nil), + } +} + +func _StartRequest_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*StartRequest) + // stop_conditions + switch x := m.StopConditions.(type) { + case *StartRequest_TestDuration: + b.EncodeVarint(7<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.TestDuration); err != nil { + return err + } + case *StartRequest_NumberOfMessages: + b.EncodeVarint(8<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.NumberOfMessages)) + case nil: + default: + return fmt.Errorf("StartRequest.StopConditions has unexpected type %T", x) + } + // options + switch x := m.Options.(type) { + case *StartRequest_PubsubOptions: + b.EncodeVarint(9<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.PubsubOptions); err != nil { + return err + } + case *StartRequest_KafkaOptions: + b.EncodeVarint(10<<3 | proto.WireBytes) + if err := b.EncodeMessage(x.KafkaOptions); err != nil { + return err + } + case nil: + default: + return fmt.Errorf("StartRequest.Options has unexpected type %T", x) + } + return nil +} + +func _StartRequest_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*StartRequest) + switch tag { + case 7: // stop_conditions.test_duration + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(google_protobuf.Duration) + err := b.DecodeMessage(msg) + m.StopConditions = &StartRequest_TestDuration{msg} + return true, err + case 8: // stop_conditions.number_of_messages + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.StopConditions = &StartRequest_NumberOfMessages{int32(x)} + return true, err + case 9: // options.pubsub_options + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(PubsubOptions) + err := b.DecodeMessage(msg) + m.Options = &StartRequest_PubsubOptions{msg} + return true, err + case 10: // options.kafka_options + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + msg := new(KafkaOptions) + err := b.DecodeMessage(msg) + m.Options = &StartRequest_KafkaOptions{msg} + return true, err + default: + return false, nil + } +} + +func _StartRequest_OneofSizer(msg proto.Message) (n int) { + m := msg.(*StartRequest) + // stop_conditions + switch x := m.StopConditions.(type) { + case *StartRequest_TestDuration: + s := proto.Size(x.TestDuration) + n += proto.SizeVarint(7<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *StartRequest_NumberOfMessages: + n += proto.SizeVarint(8<<3 | proto.WireVarint) + n += proto.SizeVarint(uint64(x.NumberOfMessages)) + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + // options + switch x := m.Options.(type) { + case *StartRequest_PubsubOptions: + s := proto.Size(x.PubsubOptions) + n += proto.SizeVarint(9<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case *StartRequest_KafkaOptions: + s := proto.Size(x.KafkaOptions) + n += proto.SizeVarint(10<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(s)) + n += s + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +type StartResponse struct { +} + +func (m *StartResponse) Reset() { *m = StartResponse{} } +func (m *StartResponse) String() string { return proto.CompactTextString(m) } +func (*StartResponse) ProtoMessage() {} +func (*StartResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +type PubsubOptions struct { + // The Cloud Pub/Sub subscription name + Subscription string `protobuf:"bytes,1,opt,name=subscription" json:"subscription,omitempty"` + // The maximum number of messages to pull which each request. + MaxMessagesPerPull int32 `protobuf:"varint,2,opt,name=max_messages_per_pull,json=maxMessagesPerPull" json:"max_messages_per_pull,omitempty"` +} + +func (m *PubsubOptions) Reset() { *m = PubsubOptions{} } +func (m *PubsubOptions) String() string { return proto.CompactTextString(m) } +func (*PubsubOptions) ProtoMessage() {} +func (*PubsubOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *PubsubOptions) GetSubscription() string { + if m != nil { + return m.Subscription + } + return "" +} + +func (m *PubsubOptions) GetMaxMessagesPerPull() int32 { + if m != nil { + return m.MaxMessagesPerPull + } + return 0 +} + +type KafkaOptions struct { + // The network address of the Kafka broker. + Broker string `protobuf:"bytes,1,opt,name=broker" json:"broker,omitempty"` + // The length of time to poll for. + PollDuration *google_protobuf.Duration `protobuf:"bytes,2,opt,name=poll_duration,json=pollDuration" json:"poll_duration,omitempty"` +} + +func (m *KafkaOptions) Reset() { *m = KafkaOptions{} } +func (m *KafkaOptions) String() string { return proto.CompactTextString(m) } +func (*KafkaOptions) ProtoMessage() {} +func (*KafkaOptions) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *KafkaOptions) GetBroker() string { + if m != nil { + return m.Broker + } + return "" +} + +func (m *KafkaOptions) GetPollDuration() *google_protobuf.Duration { + if m != nil { + return m.PollDuration + } + return nil +} + +type MessageIdentifier struct { + // The unique id of the client that published the message. + PublisherClientId int64 `protobuf:"varint,1,opt,name=publisher_client_id,json=publisherClientId" json:"publisher_client_id,omitempty"` + // Sequence number of the published message with the given publish_client_id. + SequenceNumber int32 `protobuf:"varint,2,opt,name=sequence_number,json=sequenceNumber" json:"sequence_number,omitempty"` +} + +func (m *MessageIdentifier) Reset() { *m = MessageIdentifier{} } +func (m *MessageIdentifier) String() string { return proto.CompactTextString(m) } +func (*MessageIdentifier) ProtoMessage() {} +func (*MessageIdentifier) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func (m *MessageIdentifier) GetPublisherClientId() int64 { + if m != nil { + return m.PublisherClientId + } + return 0 +} + +func (m *MessageIdentifier) GetSequenceNumber() int32 { + if m != nil { + return m.SequenceNumber + } + return 0 +} + +type CheckRequest struct { + // Duplicate messages that should not be reported for throughput and latency. + Duplicates []*MessageIdentifier `protobuf:"bytes,1,rep,name=duplicates" json:"duplicates,omitempty"` +} + +func (m *CheckRequest) Reset() { *m = CheckRequest{} } +func (m *CheckRequest) String() string { return proto.CompactTextString(m) } +func (*CheckRequest) ProtoMessage() {} +func (*CheckRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +func (m *CheckRequest) GetDuplicates() []*MessageIdentifier { + if m != nil { + return m.Duplicates + } + return nil +} + +type CheckResponse struct { + // Histogram of latencies, each one a delta from the previous CheckResponse sent. + BucketValues []int64 `protobuf:"varint,1,rep,packed,name=bucket_values,json=bucketValues" json:"bucket_values,omitempty"` + // The duration from the start of the loadtest to its completion or now if is_finished is false. + RunningDuration *google_protobuf.Duration `protobuf:"bytes,2,opt,name=running_duration,json=runningDuration" json:"running_duration,omitempty"` + // True if the load test has finished running. + IsFinished bool `protobuf:"varint,3,opt,name=is_finished,json=isFinished" json:"is_finished,omitempty"` + // MessageIdentifiers of all received messages since the last Check + ReceivedMessages []*MessageIdentifier `protobuf:"bytes,4,rep,name=received_messages,json=receivedMessages" json:"received_messages,omitempty"` +} + +func (m *CheckResponse) Reset() { *m = CheckResponse{} } +func (m *CheckResponse) String() string { return proto.CompactTextString(m) } +func (*CheckResponse) ProtoMessage() {} +func (*CheckResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } + +func (m *CheckResponse) GetBucketValues() []int64 { + if m != nil { + return m.BucketValues + } + return nil +} + +func (m *CheckResponse) GetRunningDuration() *google_protobuf.Duration { + if m != nil { + return m.RunningDuration + } + return nil +} + +func (m *CheckResponse) GetIsFinished() bool { + if m != nil { + return m.IsFinished + } + return false +} + +func (m *CheckResponse) GetReceivedMessages() []*MessageIdentifier { + if m != nil { + return m.ReceivedMessages + } + return nil +} + +type ExecuteRequest struct { +} + +func (m *ExecuteRequest) Reset() { *m = ExecuteRequest{} } +func (m *ExecuteRequest) String() string { return proto.CompactTextString(m) } +func (*ExecuteRequest) ProtoMessage() {} +func (*ExecuteRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +type ExecuteResponse struct { + // Latencies of the completed operations + Latencies []int64 `protobuf:"varint,1,rep,packed,name=latencies" json:"latencies,omitempty"` + // MessageIdentifiers of all received messages since the last Execute + ReceivedMessages []*MessageIdentifier `protobuf:"bytes,2,rep,name=received_messages,json=receivedMessages" json:"received_messages,omitempty"` +} + +func (m *ExecuteResponse) Reset() { *m = ExecuteResponse{} } +func (m *ExecuteResponse) String() string { return proto.CompactTextString(m) } +func (*ExecuteResponse) ProtoMessage() {} +func (*ExecuteResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } + +func (m *ExecuteResponse) GetLatencies() []int64 { + if m != nil { + return m.Latencies + } + return nil +} + +func (m *ExecuteResponse) GetReceivedMessages() []*MessageIdentifier { + if m != nil { + return m.ReceivedMessages + } + return nil +} + +func init() { + proto.RegisterType((*StartRequest)(nil), "google.pubsub.loadtest.StartRequest") + proto.RegisterType((*StartResponse)(nil), "google.pubsub.loadtest.StartResponse") + proto.RegisterType((*PubsubOptions)(nil), "google.pubsub.loadtest.PubsubOptions") + proto.RegisterType((*KafkaOptions)(nil), "google.pubsub.loadtest.KafkaOptions") + proto.RegisterType((*MessageIdentifier)(nil), "google.pubsub.loadtest.MessageIdentifier") + proto.RegisterType((*CheckRequest)(nil), "google.pubsub.loadtest.CheckRequest") + proto.RegisterType((*CheckResponse)(nil), "google.pubsub.loadtest.CheckResponse") + proto.RegisterType((*ExecuteRequest)(nil), "google.pubsub.loadtest.ExecuteRequest") + proto.RegisterType((*ExecuteResponse)(nil), "google.pubsub.loadtest.ExecuteResponse") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for Loadtest service + +type LoadtestClient interface { + // Starts a load test + Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*StartResponse, error) + // Checks the status of a load test + Check(ctx context.Context, in *CheckRequest, opts ...grpc.CallOption) (*CheckResponse, error) +} + +type loadtestClient struct { + cc *grpc.ClientConn +} + +func NewLoadtestClient(cc *grpc.ClientConn) LoadtestClient { + return &loadtestClient{cc} +} + +func (c *loadtestClient) Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*StartResponse, error) { + out := new(StartResponse) + err := grpc.Invoke(ctx, "/google.pubsub.loadtest.Loadtest/Start", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *loadtestClient) Check(ctx context.Context, in *CheckRequest, opts ...grpc.CallOption) (*CheckResponse, error) { + out := new(CheckResponse) + err := grpc.Invoke(ctx, "/google.pubsub.loadtest.Loadtest/Check", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Loadtest service + +type LoadtestServer interface { + // Starts a load test + Start(context.Context, *StartRequest) (*StartResponse, error) + // Checks the status of a load test + Check(context.Context, *CheckRequest) (*CheckResponse, error) +} + +func RegisterLoadtestServer(s *grpc.Server, srv LoadtestServer) { + s.RegisterService(&_Loadtest_serviceDesc, srv) +} + +func _Loadtest_Start_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StartRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LoadtestServer).Start(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.pubsub.loadtest.Loadtest/Start", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LoadtestServer).Start(ctx, req.(*StartRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Loadtest_Check_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CheckRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LoadtestServer).Check(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.pubsub.loadtest.Loadtest/Check", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LoadtestServer).Check(ctx, req.(*CheckRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Loadtest_serviceDesc = grpc.ServiceDesc{ + ServiceName: "google.pubsub.loadtest.Loadtest", + HandlerType: (*LoadtestServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Start", + Handler: _Loadtest_Start_Handler, + }, + { + MethodName: "Check", + Handler: _Loadtest_Check_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "loadtest.proto", +} + +// Client API for LoadtestWorker service + +type LoadtestWorkerClient interface { + // Starts a worker + Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*StartResponse, error) + // Executes a command on the worker, returning the latencies of the operations. Since some + // commands consist of multiple operations (i.e. pulls contain many received messages with + // different end to end latencies) a single command can have multiple latencies returned. + Execute(ctx context.Context, in *ExecuteRequest, opts ...grpc.CallOption) (*ExecuteResponse, error) +} + +type loadtestWorkerClient struct { + cc *grpc.ClientConn +} + +func NewLoadtestWorkerClient(cc *grpc.ClientConn) LoadtestWorkerClient { + return &loadtestWorkerClient{cc} +} + +func (c *loadtestWorkerClient) Start(ctx context.Context, in *StartRequest, opts ...grpc.CallOption) (*StartResponse, error) { + out := new(StartResponse) + err := grpc.Invoke(ctx, "/google.pubsub.loadtest.LoadtestWorker/Start", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *loadtestWorkerClient) Execute(ctx context.Context, in *ExecuteRequest, opts ...grpc.CallOption) (*ExecuteResponse, error) { + out := new(ExecuteResponse) + err := grpc.Invoke(ctx, "/google.pubsub.loadtest.LoadtestWorker/Execute", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for LoadtestWorker service + +type LoadtestWorkerServer interface { + // Starts a worker + Start(context.Context, *StartRequest) (*StartResponse, error) + // Executes a command on the worker, returning the latencies of the operations. Since some + // commands consist of multiple operations (i.e. pulls contain many received messages with + // different end to end latencies) a single command can have multiple latencies returned. + Execute(context.Context, *ExecuteRequest) (*ExecuteResponse, error) +} + +func RegisterLoadtestWorkerServer(s *grpc.Server, srv LoadtestWorkerServer) { + s.RegisterService(&_LoadtestWorker_serviceDesc, srv) +} + +func _LoadtestWorker_Start_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StartRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LoadtestWorkerServer).Start(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.pubsub.loadtest.LoadtestWorker/Start", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LoadtestWorkerServer).Start(ctx, req.(*StartRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _LoadtestWorker_Execute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ExecuteRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LoadtestWorkerServer).Execute(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/google.pubsub.loadtest.LoadtestWorker/Execute", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LoadtestWorkerServer).Execute(ctx, req.(*ExecuteRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _LoadtestWorker_serviceDesc = grpc.ServiceDesc{ + ServiceName: "google.pubsub.loadtest.LoadtestWorker", + HandlerType: (*LoadtestWorkerServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Start", + Handler: _LoadtestWorker_Start_Handler, + }, + { + MethodName: "Execute", + Handler: _LoadtestWorker_Execute_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "loadtest.proto", +} + +func init() { proto.RegisterFile("loadtest.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 847 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xdd, 0x6e, 0xdc, 0x44, + 0x14, 0xae, 0x93, 0x6e, 0x92, 0x3d, 0x6b, 0xef, 0x6e, 0x86, 0x12, 0x99, 0x15, 0xd0, 0x60, 0x28, + 0x0d, 0x12, 0x72, 0x45, 0xb8, 0x81, 0x1b, 0x84, 0x92, 0x82, 0x12, 0x15, 0x9a, 0xc8, 0x8d, 0x8a, + 0xe0, 0x66, 0x34, 0xb6, 0x67, 0x93, 0x61, 0xed, 0x19, 0x33, 0x3f, 0x55, 0xd4, 0x17, 0xe0, 0x8d, + 0x78, 0x00, 0x1e, 0x87, 0x5b, 0x5e, 0x00, 0xcd, 0x78, 0xbc, 0x3f, 0x6d, 0x57, 0x0b, 0x42, 0xbd, + 0x3c, 0xdf, 0xf9, 0xce, 0x37, 0xe7, 0xd7, 0x86, 0x61, 0x25, 0x48, 0xa9, 0xa9, 0xd2, 0x69, 0x23, + 0x85, 0x16, 0xe8, 0xe0, 0x5a, 0x88, 0xeb, 0x8a, 0xa6, 0x8d, 0xc9, 0x95, 0xc9, 0xd3, 0xce, 0x3b, + 0xf9, 0xb0, 0xc5, 0x1f, 0x39, 0x56, 0x6e, 0xa6, 0x8f, 0x4a, 0x23, 0x89, 0x66, 0x82, 0xb7, 0x71, + 0x93, 0xfb, 0xaf, 0xfa, 0x35, 0xab, 0xa9, 0xd2, 0xa4, 0x6e, 0x5a, 0x42, 0xf2, 0x57, 0x0f, 0xc2, + 0x67, 0x9a, 0x48, 0x9d, 0xd1, 0xdf, 0x0c, 0x55, 0x1a, 0xc5, 0xb0, 0xdb, 0x48, 0xf1, 0x2b, 0x2d, + 0x74, 0x1c, 0x1c, 0x06, 0x47, 0xfd, 0xac, 0x33, 0xd1, 0x3d, 0xe8, 0x69, 0xd1, 0xb0, 0x22, 0xde, + 0x72, 0x78, 0x6b, 0xa0, 0x8f, 0x20, 0x94, 0x6d, 0x28, 0x96, 0x44, 0xd3, 0x78, 0xfb, 0x30, 0x38, + 0xea, 0x65, 0x03, 0x8f, 0x65, 0x44, 0x53, 0x4b, 0xa9, 0xa9, 0x52, 0xe4, 0x9a, 0x62, 0xc5, 0x5e, + 0xd2, 0xf8, 0x6e, 0x4b, 0xf1, 0xd8, 0x33, 0xf6, 0x92, 0xa2, 0xaf, 0x20, 0xae, 0xc9, 0x2d, 0x16, + 0x46, 0x2b, 0x4d, 0x78, 0xc9, 0xf8, 0x35, 0xf6, 0x0a, 0x2a, 0xee, 0x39, 0xfa, 0x41, 0x4d, 0x6e, + 0x2f, 0x16, 0x6e, 0x9f, 0xae, 0x42, 0x5f, 0x03, 0x28, 0x9b, 0x3f, 0xb6, 0x95, 0xc5, 0x3b, 0x87, + 0xc1, 0xd1, 0xe0, 0x78, 0x92, 0x76, 0xed, 0xf2, 0x65, 0xa7, 0x57, 0x5d, 0xd9, 0x59, 0xdf, 0xb1, + 0xad, 0x8d, 0x4e, 0x61, 0x9c, 0x1b, 0xc9, 0x31, 0xe3, 0xb8, 0x6b, 0x5b, 0x1c, 0x3a, 0x81, 0xf7, + 0x5e, 0x13, 0x78, 0xec, 0x09, 0xd9, 0xd0, 0x86, 0x9c, 0xf3, 0xce, 0x46, 0x9f, 0x03, 0x6a, 0x4c, + 0x5e, 0x31, 0x75, 0x83, 0x73, 0xa2, 0x8b, 0x9b, 0xb6, 0xc4, 0x81, 0xcb, 0x79, 0xec, 0x3d, 0x27, + 0xd6, 0xe1, 0xea, 0xbc, 0x80, 0x83, 0x55, 0xf6, 0xfc, 0xe1, 0x68, 0xd3, 0xc3, 0xf7, 0x96, 0xc5, + 0xe6, 0xcf, 0x7f, 0x0b, 0x91, 0x5d, 0x84, 0x85, 0xce, 0xee, 0x06, 0x9d, 0xb3, 0x3b, 0x59, 0x68, + 0x23, 0xe6, 0x0a, 0x29, 0x20, 0x6e, 0xea, 0x9c, 0x4a, 0x2c, 0xa6, 0xd8, 0xcf, 0x44, 0xc5, 0x7b, + 0xb6, 0x80, 0xb3, 0x3b, 0xd9, 0xb8, 0xf5, 0x5d, 0x4c, 0x7f, 0xf4, 0x1e, 0xf4, 0x14, 0x86, 0xed, + 0x16, 0x62, 0xd1, 0x58, 0x01, 0x15, 0xf7, 0xdd, 0x93, 0x0f, 0xd2, 0x37, 0xef, 0x68, 0x7a, 0xe9, + 0xec, 0x8b, 0x96, 0x7c, 0x16, 0x64, 0x51, 0xb3, 0x0c, 0xa0, 0x27, 0x10, 0xcd, 0xc8, 0x74, 0x46, + 0xe6, 0x72, 0xe0, 0xe4, 0x3e, 0x59, 0x27, 0xf7, 0xc4, 0x92, 0x17, 0x6a, 0xe1, 0x6c, 0xc9, 0x3e, + 0xd9, 0x87, 0x91, 0xd2, 0xa2, 0xc1, 0x85, 0xe0, 0x25, 0x6b, 0xa1, 0x3e, 0xec, 0x7a, 0xe5, 0x64, + 0x04, 0x91, 0xdf, 0x75, 0xd5, 0x08, 0xae, 0x68, 0x32, 0x85, 0x68, 0x25, 0x3b, 0x94, 0x40, 0xa8, + 0x4c, 0xae, 0x0a, 0xc9, 0x1c, 0xe0, 0x4f, 0x60, 0x05, 0x43, 0x5f, 0xc0, 0xbb, 0x76, 0x57, 0xbb, + 0x56, 0xe1, 0x86, 0x4a, 0xdc, 0x98, 0xaa, 0x72, 0x77, 0xd1, 0xcb, 0x50, 0x4d, 0x6e, 0xbb, 0x66, + 0x5d, 0x52, 0x79, 0x69, 0xaa, 0x2a, 0x99, 0x42, 0xb8, 0x9c, 0x36, 0x3a, 0x80, 0x9d, 0x5c, 0x8a, + 0x19, 0x95, 0xfe, 0x01, 0x6f, 0xa1, 0x6f, 0x20, 0x6a, 0x44, 0x55, 0x2d, 0xa6, 0xb9, 0xb5, 0x69, + 0x2b, 0x42, 0xcb, 0xef, 0xac, 0xa4, 0x82, 0x7d, 0xff, 0xf4, 0x79, 0x49, 0xb9, 0x66, 0x53, 0x46, + 0x25, 0x4a, 0xe1, 0x1d, 0xbf, 0x3a, 0x54, 0xe2, 0xa2, 0x62, 0x94, 0x6b, 0xcc, 0x4a, 0xf7, 0xf2, + 0x76, 0xb6, 0x3f, 0x77, 0x9d, 0x3a, 0xcf, 0x79, 0x89, 0x1e, 0xc2, 0x48, 0xd9, 0xeb, 0xe2, 0x05, + 0xc5, 0xed, 0xf4, 0x7d, 0x65, 0xc3, 0x0e, 0x7e, 0xea, 0xd0, 0xe4, 0x67, 0x08, 0x4f, 0x6f, 0x68, + 0x31, 0xeb, 0x3e, 0x1d, 0xe7, 0x00, 0xa5, 0x69, 0x2a, 0x56, 0x10, 0x4d, 0x55, 0x1c, 0x1c, 0x6e, + 0x1f, 0x0d, 0x8e, 0x3f, 0x5b, 0x37, 0xc6, 0xd7, 0xf2, 0xcc, 0x96, 0x82, 0x93, 0xbf, 0x03, 0x88, + 0xbc, 0x76, 0x3b, 0x2a, 0xf4, 0x31, 0x44, 0xb9, 0x29, 0x66, 0x54, 0xe3, 0x17, 0xa4, 0x32, 0x5e, + 0x7f, 0x3b, 0x0b, 0x5b, 0xf0, 0xb9, 0xc3, 0xd0, 0x63, 0x18, 0x4b, 0xc3, 0xb9, 0xfd, 0x7c, 0xfc, + 0xfb, 0x16, 0x8e, 0x7c, 0xc8, 0xfc, 0x22, 0xee, 0xc3, 0x80, 0x29, 0x3c, 0x65, 0xdc, 0xf6, 0xa5, + 0x74, 0x5f, 0xb4, 0xbd, 0x0c, 0x98, 0xfa, 0xde, 0x23, 0xe8, 0x39, 0xec, 0x4b, 0x5a, 0x50, 0xf6, + 0x82, 0x96, 0x8b, 0x8b, 0xb9, 0xfb, 0x5f, 0xeb, 0x1d, 0x77, 0x1a, 0xdd, 0xb6, 0x24, 0x63, 0x18, + 0x7e, 0x77, 0x4b, 0x0b, 0xa3, 0xa9, 0x6f, 0x69, 0xf2, 0x7b, 0x00, 0xa3, 0x39, 0xe4, 0x3b, 0xf1, + 0x3e, 0xf4, 0x2b, 0xa2, 0x29, 0x2f, 0xd8, 0xbc, 0x0b, 0x0b, 0xe0, 0xcd, 0xb9, 0x6d, 0xfd, 0xef, + 0xdc, 0x8e, 0xff, 0x08, 0x60, 0xef, 0x07, 0x1f, 0x80, 0xae, 0xa0, 0xe7, 0x0e, 0x09, 0xad, 0xbd, + 0xd2, 0xe5, 0x7f, 0xca, 0xe4, 0xc1, 0x06, 0x96, 0x2f, 0xec, 0x0a, 0x7a, 0x6e, 0xe6, 0xeb, 0x55, + 0x97, 0xd7, 0x6d, 0xbd, 0xea, 0xca, 0xe2, 0x1c, 0xff, 0x19, 0xc0, 0xb0, 0x4b, 0xfc, 0x27, 0x21, + 0xed, 0x99, 0xbd, 0x9d, 0xf4, 0x7f, 0x81, 0x5d, 0x3f, 0x2a, 0xf4, 0xe9, 0xba, 0x88, 0xd5, 0xf1, + 0x4e, 0x1e, 0x6e, 0xe4, 0xb5, 0xda, 0x27, 0x29, 0x7c, 0x50, 0x88, 0xfa, 0x15, 0xf6, 0xb4, 0x62, + 0x45, 0x5a, 0x88, 0xba, 0x16, 0xfc, 0x24, 0xea, 0x4a, 0xbc, 0x74, 0xfb, 0xbd, 0xe3, 0xd6, 0xfc, + 0xcb, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xfc, 0xdc, 0x27, 0x48, 0x08, 0x00, 0x00, +} diff --git a/vendor/cloud.google.com/go/pubsub/message.go b/vendor/cloud.google.com/go/pubsub/message.go new file mode 100644 index 00000000..c4b16e95 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/message.go @@ -0,0 +1,100 @@ +// Copyright 2016 Google LLC +// +// 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 pubsub + +import ( + "time" + + "github.com/golang/protobuf/ptypes" + pb "google.golang.org/genproto/googleapis/pubsub/v1" +) + +// Message represents a Pub/Sub message. +type Message struct { + // ID identifies this message. + // This ID is assigned by the server and is populated for Messages obtained from a subscription. + // This field is read-only. + ID string + + // Data is the actual data in the message. + Data []byte + + // Attributes represents the key-value pairs the current message + // is labelled with. + Attributes map[string]string + + // ackID is the identifier to acknowledge this message. + ackID string + + // The time at which the message was published. + // This is populated by the server for Messages obtained from a subscription. + // This field is read-only. + PublishTime time.Time + + // receiveTime is the time the message was received by the client. + receiveTime time.Time + + // size is the approximate size of the message's data and attributes. + size int + + calledDone bool + + // The done method of the iterator that created this Message. + doneFunc func(string, bool, time.Time) +} + +func toMessage(resp *pb.ReceivedMessage) (*Message, error) { + if resp.Message == nil { + return &Message{ackID: resp.AckId}, nil + } + + pubTime, err := ptypes.Timestamp(resp.Message.PublishTime) + if err != nil { + return nil, err + } + return &Message{ + ackID: resp.AckId, + Data: resp.Message.Data, + Attributes: resp.Message.Attributes, + ID: resp.Message.MessageId, + PublishTime: pubTime, + }, nil +} + +// Ack indicates successful processing of a Message passed to the Subscriber.Receive callback. +// It should not be called on any other Message value. +// If message acknowledgement fails, the Message will be redelivered. +// Client code must call Ack or Nack when finished for each received Message. +// Calls to Ack or Nack have no effect after the first call. +func (m *Message) Ack() { + m.done(true) +} + +// Nack indicates that the client will not or cannot process a Message passed to the Subscriber.Receive callback. +// It should not be called on any other Message value. +// Nack will result in the Message being redelivered more quickly than if it were allowed to expire. +// Client code must call Ack or Nack when finished for each received Message. +// Calls to Ack or Nack have no effect after the first call. +func (m *Message) Nack() { + m.done(false) +} + +func (m *Message) done(ack bool) { + if m.calledDone { + return + } + m.calledDone = true + m.doneFunc(m.ackID, ack, m.receiveTime) +} diff --git a/vendor/cloud.google.com/go/pubsub/mock_test.go b/vendor/cloud.google.com/go/pubsub/mock_test.go new file mode 100644 index 00000000..52da1740 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/mock_test.go @@ -0,0 +1,200 @@ +// Copyright 2017 Google LLC +// +// 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 pubsub + +// This file provides a mock in-memory pubsub server for streaming pull testing. + +import ( + "context" + "io" + "sync" + "time" + + "cloud.google.com/go/internal/testutil" + emptypb "github.com/golang/protobuf/ptypes/empty" + pb "google.golang.org/genproto/googleapis/pubsub/v1" +) + +type mockServer struct { + srv *testutil.Server + + pb.SubscriberServer + + Addr string + + mu sync.Mutex + Acked map[string]bool // acked message IDs + Deadlines map[string]int32 // deadlines by message ID + pullResponses []*pullResponse + ackErrs []error + modAckErrs []error + wg sync.WaitGroup + sub *pb.Subscription +} + +type pullResponse struct { + msgs []*pb.ReceivedMessage + err error +} + +func newMockServer(port int) (*mockServer, error) { + srv, err := testutil.NewServerWithPort(port) + if err != nil { + return nil, err + } + mock := &mockServer{ + srv: srv, + Addr: srv.Addr, + Acked: map[string]bool{}, + Deadlines: map[string]int32{}, + sub: &pb.Subscription{ + AckDeadlineSeconds: 10, + PushConfig: &pb.PushConfig{}, + }, + } + pb.RegisterSubscriberServer(srv.Gsrv, mock) + srv.Start() + return mock, nil +} + +// Each call to addStreamingPullMessages results in one StreamingPullResponse. +func (s *mockServer) addStreamingPullMessages(msgs []*pb.ReceivedMessage) { + s.mu.Lock() + s.pullResponses = append(s.pullResponses, &pullResponse{msgs, nil}) + s.mu.Unlock() +} + +func (s *mockServer) addStreamingPullError(err error) { + s.mu.Lock() + s.pullResponses = append(s.pullResponses, &pullResponse{nil, err}) + s.mu.Unlock() +} + +func (s *mockServer) addAckResponse(err error) { + s.mu.Lock() + s.ackErrs = append(s.ackErrs, err) + s.mu.Unlock() +} + +func (s *mockServer) addModAckResponse(err error) { + s.mu.Lock() + s.modAckErrs = append(s.modAckErrs, err) + s.mu.Unlock() +} + +func (s *mockServer) wait() { + s.wg.Wait() +} + +func (s *mockServer) StreamingPull(stream pb.Subscriber_StreamingPullServer) error { + s.wg.Add(1) + defer s.wg.Done() + errc := make(chan error, 1) + s.wg.Add(1) + go func() { + defer s.wg.Done() + for { + req, err := stream.Recv() + if err != nil { + errc <- err + return + } + s.mu.Lock() + for _, id := range req.AckIds { + s.Acked[id] = true + } + for i, id := range req.ModifyDeadlineAckIds { + s.Deadlines[id] = req.ModifyDeadlineSeconds[i] + } + s.mu.Unlock() + } + }() + // Send responses. + for { + s.mu.Lock() + if len(s.pullResponses) == 0 { + s.mu.Unlock() + // Nothing to send, so wait for the client to shut down the stream. + err := <-errc // a real error, or at least EOF + if err == io.EOF { + return nil + } + return err + } + pr := s.pullResponses[0] + s.pullResponses = s.pullResponses[1:] + s.mu.Unlock() + if pr.err != nil { + // Add a slight delay to ensure the server receives any + // messages en route from the client before shutting down the stream. + // This reduces flakiness of tests involving retry. + time.Sleep(200 * time.Millisecond) + } + if pr.err == io.EOF { + return nil + } + if pr.err != nil { + return pr.err + } + // Return any error from Recv. + select { + case err := <-errc: + return err + default: + } + res := &pb.StreamingPullResponse{ReceivedMessages: pr.msgs} + if err := stream.Send(res); err != nil { + return err + } + } +} + +func (s *mockServer) Acknowledge(ctx context.Context, req *pb.AcknowledgeRequest) (*emptypb.Empty, error) { + var err error + s.mu.Lock() + if len(s.ackErrs) > 0 { + err = s.ackErrs[0] + s.ackErrs = s.ackErrs[1:] + } + s.mu.Unlock() + if err != nil { + return nil, err + } + for _, id := range req.AckIds { + s.Acked[id] = true + } + return &emptypb.Empty{}, nil +} + +func (s *mockServer) ModifyAckDeadline(ctx context.Context, req *pb.ModifyAckDeadlineRequest) (*emptypb.Empty, error) { + var err error + s.mu.Lock() + if len(s.modAckErrs) > 0 { + err = s.modAckErrs[0] + s.modAckErrs = s.modAckErrs[1:] + } + s.mu.Unlock() + if err != nil { + return nil, err + } + for _, id := range req.AckIds { + s.Deadlines[id] = req.AckDeadlineSeconds + } + return &emptypb.Empty{}, nil +} + +func (s *mockServer) GetSubscription(ctx context.Context, req *pb.GetSubscriptionRequest) (*pb.Subscription, error) { + return s.sub, nil +} diff --git a/vendor/cloud.google.com/go/pubsub/nodebug.go b/vendor/cloud.google.com/go/pubsub/nodebug.go new file mode 100644 index 00000000..774a74a5 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/nodebug.go @@ -0,0 +1,25 @@ +// Copyright 2018 Google LLC +// +// 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. + +// +build !psdebug + +package pubsub + +import "time" + +func addRecv(string, string, time.Time) {} + +func addAcks([]string) {} + +func addModAcks([]string, int32) {} diff --git a/vendor/cloud.google.com/go/pubsub/pstest/examples_test.go b/vendor/cloud.google.com/go/pubsub/pstest/examples_test.go new file mode 100644 index 00000000..56a30c12 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/pstest/examples_test.go @@ -0,0 +1,44 @@ +// Copyright 2018 Google LLC +// +// 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 pstest_test + +import ( + "context" + + "cloud.google.com/go/pubsub" + "cloud.google.com/go/pubsub/pstest" + "google.golang.org/api/option" + "google.golang.org/grpc" +) + +func ExampleNewServer() { + ctx := context.Background() + // Start a fake server running locally. + srv := pstest.NewServer() + defer srv.Close() + // Connect to the server without using TLS. + conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure()) + if err != nil { + // TODO: Handle error. + } + defer conn.Close() + // Use the connection when creating a pubsub client. + client, err := pubsub.NewClient(ctx, "project", option.WithGRPCConn(conn)) + if err != nil { + // TODO: Handle error. + } + defer client.Close() + _ = client // TODO: Use the client. +} diff --git a/vendor/cloud.google.com/go/pubsub/pstest/fake.go b/vendor/cloud.google.com/go/pubsub/pstest/fake.go new file mode 100644 index 00000000..448c4c93 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/pstest/fake.go @@ -0,0 +1,996 @@ +// Copyright 2017 Google LLC +// +// 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 pstest provides a fake Cloud PubSub service for testing. It implements a +// simplified form of the service, suitable for unit tests. It may behave +// differently from the actual service in ways in which the service is +// non-deterministic or unspecified: timing, delivery order, etc. +// +// This package is EXPERIMENTAL and is subject to change without notice. +// +// See the example for usage. +package pstest + +import ( + "context" + "fmt" + "io" + "path" + "sort" + "strings" + "sync" + "sync/atomic" + "time" + + "cloud.google.com/go/internal/testutil" + "github.com/golang/protobuf/ptypes" + durpb "github.com/golang/protobuf/ptypes/duration" + emptypb "github.com/golang/protobuf/ptypes/empty" + pb "google.golang.org/genproto/googleapis/pubsub/v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// For testing. Note that even though changes to the now variable are atomic, a call +// to the stored function can race with a change to that function. This could be a +// problem if tests are run in parallel, or even if concurrent parts of the same test +// change the value of the variable. +var now atomic.Value + +func init() { + now.Store(time.Now) + ResetMinAckDeadline() +} + +func timeNow() time.Time { + return now.Load().(func() time.Time)() +} + +// Server is a fake Pub/Sub server. +type Server struct { + srv *testutil.Server + Addr string // The address that the server is listening on. + gServer gServer +} + +type gServer struct { + pb.PublisherServer + pb.SubscriberServer + + mu sync.Mutex + topics map[string]*topic + subs map[string]*subscription + msgs []*Message // all messages ever published + msgsByID map[string]*Message + wg sync.WaitGroup + nextID int + streamTimeout time.Duration +} + +// NewServer creates a new fake server running in the current process. +func NewServer() *Server { + srv, err := testutil.NewServer() + if err != nil { + panic(fmt.Sprintf("pstest.NewServer: %v", err)) + } + s := &Server{ + srv: srv, + Addr: srv.Addr, + gServer: gServer{ + topics: map[string]*topic{}, + subs: map[string]*subscription{}, + msgsByID: map[string]*Message{}, + }, + } + pb.RegisterPublisherServer(srv.Gsrv, &s.gServer) + pb.RegisterSubscriberServer(srv.Gsrv, &s.gServer) + srv.Start() + return s +} + +// Publish behaves as if the Publish RPC was called with a message with the given +// data and attrs. It returns the ID of the message. +// The topic will be created if it doesn't exist. +// +// Publish panics if there is an error, which is appropriate for testing. +func (s *Server) Publish(topic string, data []byte, attrs map[string]string) string { + const topicPattern = "projects/*/topics/*" + ok, err := path.Match(topicPattern, topic) + if err != nil { + panic(err) + } + if !ok { + panic(fmt.Sprintf("topic name must be of the form %q", topicPattern)) + } + _, _ = s.gServer.CreateTopic(context.TODO(), &pb.Topic{Name: topic}) + req := &pb.PublishRequest{ + Topic: topic, + Messages: []*pb.PubsubMessage{{Data: data, Attributes: attrs}}, + } + res, err := s.gServer.Publish(context.TODO(), req) + if err != nil { + panic(fmt.Sprintf("pstest.Server.Publish: %v", err)) + } + return res.MessageIds[0] +} + +// SetStreamTimeout sets the amount of time a stream will be active before it shuts +// itself down. This mimics the real service's behavior of closing streams after 30 +// minutes. If SetStreamTimeout is never called or is passed zero, streams never shut +// down. +func (s *Server) SetStreamTimeout(d time.Duration) { + s.gServer.mu.Lock() + defer s.gServer.mu.Unlock() + s.gServer.streamTimeout = d +} + +// A Message is a message that was published to the server. +type Message struct { + ID string + Data []byte + Attributes map[string]string + PublishTime time.Time + Deliveries int // number of times delivery of the message was attempted + Acks int // number of acks received from clients + + // protected by server mutex + deliveries int + acks int + Modacks []Modack // modacks received by server for this message + +} + +// Modack represents a modack sent to the server. +type Modack struct { + AckID string + AckDeadline int32 + ReceivedAt time.Time +} + +// Messages returns information about all messages ever published. +func (s *Server) Messages() []*Message { + s.gServer.mu.Lock() + defer s.gServer.mu.Unlock() + + var msgs []*Message + for _, m := range s.gServer.msgs { + m.Deliveries = m.deliveries + m.Acks = m.acks + msgs = append(msgs, m) + } + return msgs +} + +// Message returns the message with the given ID, or nil if no message +// with that ID was published. +func (s *Server) Message(id string) *Message { + s.gServer.mu.Lock() + defer s.gServer.mu.Unlock() + + m := s.gServer.msgsByID[id] + if m != nil { + m.Deliveries = m.deliveries + m.Acks = m.acks + } + return m +} + +// Wait blocks until all server activity has completed. +func (s *Server) Wait() { + s.gServer.wg.Wait() +} + +// Close shuts down the server and releases all resources. +func (s *Server) Close() error { + s.srv.Close() + s.gServer.mu.Lock() + defer s.gServer.mu.Unlock() + for _, sub := range s.gServer.subs { + sub.stop() + } + return nil +} + +func (s *gServer) CreateTopic(_ context.Context, t *pb.Topic) (*pb.Topic, error) { + s.mu.Lock() + defer s.mu.Unlock() + + if s.topics[t.Name] != nil { + return nil, status.Errorf(codes.AlreadyExists, "topic %q", t.Name) + } + top := newTopic(t) + s.topics[t.Name] = top + return top.proto, nil +} + +func (s *gServer) GetTopic(_ context.Context, req *pb.GetTopicRequest) (*pb.Topic, error) { + s.mu.Lock() + defer s.mu.Unlock() + + if t := s.topics[req.Topic]; t != nil { + return t.proto, nil + } + return nil, status.Errorf(codes.NotFound, "topic %q", req.Topic) +} + +func (s *gServer) UpdateTopic(_ context.Context, req *pb.UpdateTopicRequest) (*pb.Topic, error) { + s.mu.Lock() + defer s.mu.Unlock() + + t := s.topics[req.Topic.Name] + if t == nil { + return nil, status.Errorf(codes.NotFound, "topic %q", req.Topic.Name) + } + for _, path := range req.UpdateMask.Paths { + switch path { + case "labels": + t.proto.Labels = req.Topic.Labels + case "message_storage_policy": // "fetch" the policy + t.proto.MessageStoragePolicy = &pb.MessageStoragePolicy{AllowedPersistenceRegions: []string{"US"}} + default: + return nil, status.Errorf(codes.InvalidArgument, "unknown field name %q", path) + } + } + return t.proto, nil +} + +func (s *gServer) ListTopics(_ context.Context, req *pb.ListTopicsRequest) (*pb.ListTopicsResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + + var names []string + for n := range s.topics { + if strings.HasPrefix(n, req.Project) { + names = append(names, n) + } + } + sort.Strings(names) + from, to, nextToken, err := testutil.PageBounds(int(req.PageSize), req.PageToken, len(names)) + if err != nil { + return nil, err + } + res := &pb.ListTopicsResponse{NextPageToken: nextToken} + for i := from; i < to; i++ { + res.Topics = append(res.Topics, s.topics[names[i]].proto) + } + return res, nil +} + +func (s *gServer) ListTopicSubscriptions(_ context.Context, req *pb.ListTopicSubscriptionsRequest) (*pb.ListTopicSubscriptionsResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + + var names []string + for name, sub := range s.subs { + if sub.topic.proto.Name == req.Topic { + names = append(names, name) + } + } + sort.Strings(names) + from, to, nextToken, err := testutil.PageBounds(int(req.PageSize), req.PageToken, len(names)) + if err != nil { + return nil, err + } + return &pb.ListTopicSubscriptionsResponse{ + Subscriptions: names[from:to], + NextPageToken: nextToken, + }, nil +} + +func (s *gServer) DeleteTopic(_ context.Context, req *pb.DeleteTopicRequest) (*emptypb.Empty, error) { + s.mu.Lock() + defer s.mu.Unlock() + + t := s.topics[req.Topic] + if t == nil { + return nil, status.Errorf(codes.NotFound, "topic %q", req.Topic) + } + t.stop() + delete(s.topics, req.Topic) + return &emptypb.Empty{}, nil +} + +func (s *gServer) CreateSubscription(_ context.Context, ps *pb.Subscription) (*pb.Subscription, error) { + s.mu.Lock() + defer s.mu.Unlock() + + if ps.Name == "" { + return nil, status.Errorf(codes.InvalidArgument, "missing name") + } + if s.subs[ps.Name] != nil { + return nil, status.Errorf(codes.AlreadyExists, "subscription %q", ps.Name) + } + if ps.Topic == "" { + return nil, status.Errorf(codes.InvalidArgument, "missing topic") + } + top := s.topics[ps.Topic] + if top == nil { + return nil, status.Errorf(codes.NotFound, "topic %q", ps.Topic) + } + if err := checkAckDeadline(ps.AckDeadlineSeconds); err != nil { + return nil, err + } + if ps.MessageRetentionDuration == nil { + ps.MessageRetentionDuration = defaultMessageRetentionDuration + } + if err := checkMRD(ps.MessageRetentionDuration); err != nil { + return nil, err + } + if ps.PushConfig == nil { + ps.PushConfig = &pb.PushConfig{} + } + + sub := newSubscription(top, &s.mu, ps) + top.subs[ps.Name] = sub + s.subs[ps.Name] = sub + sub.start(&s.wg) + return ps, nil +} + +// Can be set for testing. +var minAckDeadlineSecs int32 + +// SetMinAckDeadline changes the minack deadline to n. Must be +// greater than or equal to 1 second. Remember to reset this value +// to the default after your test changes it. Example usage: +// pstest.SetMinAckDeadlineSecs(1) +// defer pstest.ResetMinAckDeadlineSecs() +func SetMinAckDeadline(n time.Duration) { + if n < time.Second { + panic("SetMinAckDeadline expects a value greater than 1 second") + } + + minAckDeadlineSecs = int32(n / time.Second) +} + +// ResetMinAckDeadline resets the minack deadline to the default. +func ResetMinAckDeadline() { + minAckDeadlineSecs = 10 +} + +func checkAckDeadline(ads int32) error { + if ads < minAckDeadlineSecs || ads > 600 { + // PubSub service returns Unknown. + return status.Errorf(codes.Unknown, "bad ack_deadline_seconds: %d", ads) + } + return nil +} + +const ( + minMessageRetentionDuration = 10 * time.Minute + maxMessageRetentionDuration = 168 * time.Hour +) + +var defaultMessageRetentionDuration = ptypes.DurationProto(maxMessageRetentionDuration) + +func checkMRD(pmrd *durpb.Duration) error { + mrd, err := ptypes.Duration(pmrd) + if err != nil || mrd < minMessageRetentionDuration || mrd > maxMessageRetentionDuration { + return status.Errorf(codes.InvalidArgument, "bad message_retention_duration %+v", pmrd) + } + return nil +} + +func (s *gServer) GetSubscription(_ context.Context, req *pb.GetSubscriptionRequest) (*pb.Subscription, error) { + s.mu.Lock() + defer s.mu.Unlock() + sub, err := s.findSubscription(req.Subscription) + if err != nil { + return nil, err + } + return sub.proto, nil +} + +func (s *gServer) UpdateSubscription(_ context.Context, req *pb.UpdateSubscriptionRequest) (*pb.Subscription, error) { + if req.Subscription == nil { + return nil, status.Errorf(codes.InvalidArgument, "missing subscription") + } + s.mu.Lock() + defer s.mu.Unlock() + sub, err := s.findSubscription(req.Subscription.Name) + if err != nil { + return nil, err + } + for _, path := range req.UpdateMask.Paths { + switch path { + case "push_config": + sub.proto.PushConfig = req.Subscription.PushConfig + + case "ack_deadline_seconds": + a := req.Subscription.AckDeadlineSeconds + if err := checkAckDeadline(a); err != nil { + return nil, err + } + sub.proto.AckDeadlineSeconds = a + + case "retain_acked_messages": + sub.proto.RetainAckedMessages = req.Subscription.RetainAckedMessages + + case "message_retention_duration": + if err := checkMRD(req.Subscription.MessageRetentionDuration); err != nil { + return nil, err + } + sub.proto.MessageRetentionDuration = req.Subscription.MessageRetentionDuration + + case "labels": + sub.proto.Labels = req.Subscription.Labels + + default: + return nil, status.Errorf(codes.InvalidArgument, "unknown field name %q", path) + } + } + return sub.proto, nil +} + +func (s *gServer) ListSubscriptions(_ context.Context, req *pb.ListSubscriptionsRequest) (*pb.ListSubscriptionsResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + + var names []string + for name := range s.subs { + if strings.HasPrefix(name, req.Project) { + names = append(names, name) + } + } + sort.Strings(names) + from, to, nextToken, err := testutil.PageBounds(int(req.PageSize), req.PageToken, len(names)) + if err != nil { + return nil, err + } + res := &pb.ListSubscriptionsResponse{NextPageToken: nextToken} + for i := from; i < to; i++ { + res.Subscriptions = append(res.Subscriptions, s.subs[names[i]].proto) + } + return res, nil +} + +func (s *gServer) DeleteSubscription(_ context.Context, req *pb.DeleteSubscriptionRequest) (*emptypb.Empty, error) { + s.mu.Lock() + defer s.mu.Unlock() + sub, err := s.findSubscription(req.Subscription) + if err != nil { + return nil, err + } + sub.stop() + delete(s.subs, req.Subscription) + sub.topic.deleteSub(sub) + return &emptypb.Empty{}, nil +} + +func (s *gServer) Publish(_ context.Context, req *pb.PublishRequest) (*pb.PublishResponse, error) { + s.mu.Lock() + defer s.mu.Unlock() + + if req.Topic == "" { + return nil, status.Errorf(codes.InvalidArgument, "missing topic") + } + top := s.topics[req.Topic] + if top == nil { + return nil, status.Errorf(codes.NotFound, "topic %q", req.Topic) + } + var ids []string + for _, pm := range req.Messages { + id := fmt.Sprintf("m%d", s.nextID) + s.nextID++ + pm.MessageId = id + pubTime := timeNow() + tsPubTime, err := ptypes.TimestampProto(pubTime) + if err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + pm.PublishTime = tsPubTime + m := &Message{ + ID: id, + Data: pm.Data, + Attributes: pm.Attributes, + PublishTime: pubTime, + } + top.publish(pm, m) + ids = append(ids, id) + s.msgs = append(s.msgs, m) + s.msgsByID[id] = m + } + return &pb.PublishResponse{MessageIds: ids}, nil +} + +type topic struct { + proto *pb.Topic + subs map[string]*subscription +} + +func newTopic(pt *pb.Topic) *topic { + return &topic{ + proto: pt, + subs: map[string]*subscription{}, + } +} + +func (t *topic) stop() { + for _, sub := range t.subs { + sub.proto.Topic = "_deleted-topic_" + sub.stop() + } +} + +func (t *topic) deleteSub(sub *subscription) { + delete(t.subs, sub.proto.Name) +} + +func (t *topic) publish(pm *pb.PubsubMessage, m *Message) { + for _, s := range t.subs { + s.msgs[pm.MessageId] = &message{ + publishTime: m.PublishTime, + proto: &pb.ReceivedMessage{ + AckId: pm.MessageId, + Message: pm, + }, + deliveries: &m.deliveries, + acks: &m.acks, + streamIndex: -1, + } + } +} + +type subscription struct { + topic *topic + mu *sync.Mutex // the server mutex, here for convenience + proto *pb.Subscription + ackTimeout time.Duration + msgs map[string]*message // unacked messages by message ID + streams []*stream + done chan struct{} +} + +func newSubscription(t *topic, mu *sync.Mutex, ps *pb.Subscription) *subscription { + at := time.Duration(ps.AckDeadlineSeconds) * time.Second + if at == 0 { + at = 10 * time.Second + } + return &subscription{ + topic: t, + mu: mu, + proto: ps, + ackTimeout: at, + msgs: map[string]*message{}, + done: make(chan struct{}), + } +} + +func (s *subscription) start(wg *sync.WaitGroup) { + wg.Add(1) + go func() { + defer wg.Done() + for { + select { + case <-s.done: + return + case <-time.After(10 * time.Millisecond): + s.deliver() + } + } + }() +} + +func (s *subscription) stop() { + close(s.done) +} + +func (s *gServer) Acknowledge(_ context.Context, req *pb.AcknowledgeRequest) (*emptypb.Empty, error) { + s.mu.Lock() + defer s.mu.Unlock() + + sub, err := s.findSubscription(req.Subscription) + if err != nil { + return nil, err + } + for _, id := range req.AckIds { + sub.ack(id) + } + return &emptypb.Empty{}, nil +} + +func (s *gServer) ModifyAckDeadline(_ context.Context, req *pb.ModifyAckDeadlineRequest) (*emptypb.Empty, error) { + s.mu.Lock() + defer s.mu.Unlock() + sub, err := s.findSubscription(req.Subscription) + if err != nil { + return nil, err + } + now := time.Now() + for _, id := range req.AckIds { + s.msgsByID[id].Modacks = append(s.msgsByID[id].Modacks, Modack{AckID: id, AckDeadline: req.AckDeadlineSeconds, ReceivedAt: now}) + } + dur := secsToDur(req.AckDeadlineSeconds) + for _, id := range req.AckIds { + sub.modifyAckDeadline(id, dur) + } + return &emptypb.Empty{}, nil +} + +func (s *gServer) Pull(ctx context.Context, req *pb.PullRequest) (*pb.PullResponse, error) { + s.mu.Lock() + sub, err := s.findSubscription(req.Subscription) + if err != nil { + s.mu.Unlock() + return nil, err + } + max := int(req.MaxMessages) + if max < 0 { + s.mu.Unlock() + return nil, status.Error(codes.InvalidArgument, "MaxMessages cannot be negative") + } + if max == 0 { // MaxMessages not specified; use a default. + max = 1000 + } + msgs := sub.pull(max) + s.mu.Unlock() + // Implement the spec from the pubsub proto: + // "If ReturnImmediately set to true, the system will respond immediately even if + // it there are no messages available to return in the `Pull` response. + // Otherwise, the system may wait (for a bounded amount of time) until at + // least one message is available, rather than returning no messages." + if len(msgs) == 0 && !req.ReturnImmediately { + // Wait for a short amount of time for a message. + // TODO: signal when a message arrives, so we don't wait the whole time. + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(500 * time.Millisecond): + s.mu.Lock() + msgs = sub.pull(max) + s.mu.Unlock() + } + } + return &pb.PullResponse{ReceivedMessages: msgs}, nil +} + +func (s *gServer) StreamingPull(sps pb.Subscriber_StreamingPullServer) error { + // Receive initial message configuring the pull. + req, err := sps.Recv() + if err != nil { + return err + } + s.mu.Lock() + sub, err := s.findSubscription(req.Subscription) + s.mu.Unlock() + if err != nil { + return err + } + // Create a new stream to handle the pull. + st := sub.newStream(sps, s.streamTimeout) + err = st.pull(&s.wg) + sub.deleteStream(st) + return err +} + +func (s *gServer) Seek(ctx context.Context, req *pb.SeekRequest) (*pb.SeekResponse, error) { + // Only handle time-based seeking for now. + // This fake doesn't deal with snapshots. + var target time.Time + switch v := req.Target.(type) { + case nil: + return nil, status.Errorf(codes.InvalidArgument, "missing Seek target type") + case *pb.SeekRequest_Time: + var err error + target, err = ptypes.Timestamp(v.Time) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "bad Time target: %v", err) + } + default: + return nil, status.Errorf(codes.Unimplemented, "unhandled Seek target type %T", v) + } + + // The entire server must be locked while doing the work below, + // because the messages don't have any other synchronization. + s.mu.Lock() + defer s.mu.Unlock() + sub, err := s.findSubscription(req.Subscription) + if err != nil { + return nil, err + } + // Drop all messages from sub that were published before the target time. + for id, m := range sub.msgs { + if m.publishTime.Before(target) { + delete(sub.msgs, id) + (*m.acks)++ + } + } + // Un-ack any already-acked messages after this time; + // redelivering them to the subscription is the closest analogue here. + for _, m := range s.msgs { + if m.PublishTime.Before(target) { + continue + } + sub.msgs[m.ID] = &message{ + publishTime: m.PublishTime, + proto: &pb.ReceivedMessage{ + AckId: m.ID, + // This was not preserved! + //Message: pm, + }, + deliveries: &m.deliveries, + acks: &m.acks, + streamIndex: -1, + } + } + return &pb.SeekResponse{}, nil +} + +// Gets a subscription that must exist. +// Must be called with the lock held. +func (s *gServer) findSubscription(name string) (*subscription, error) { + if name == "" { + return nil, status.Errorf(codes.InvalidArgument, "missing subscription") + } + sub := s.subs[name] + if sub == nil { + return nil, status.Errorf(codes.NotFound, "subscription %s", name) + } + return sub, nil +} + +// Must be called with the lock held. +func (s *subscription) pull(max int) []*pb.ReceivedMessage { + now := timeNow() + s.maintainMessages(now) + var msgs []*pb.ReceivedMessage + for _, m := range s.msgs { + if m.outstanding() { + continue + } + (*m.deliveries)++ + m.ackDeadline = now.Add(s.ackTimeout) + msgs = append(msgs, m.proto) + if len(msgs) >= max { + break + } + } + return msgs +} + +func (s *subscription) deliver() { + s.mu.Lock() + defer s.mu.Unlock() + + now := timeNow() + s.maintainMessages(now) + // Try to deliver each remaining message. + curIndex := 0 + for _, m := range s.msgs { + if m.outstanding() { + continue + } + // If the message was never delivered before, start with the stream at + // curIndex. If it was delivered before, start with the stream after the one + // that owned it. + if m.streamIndex < 0 { + delIndex, ok := s.tryDeliverMessage(m, curIndex, now) + if !ok { + break + } + curIndex = delIndex + 1 + m.streamIndex = curIndex + } else { + delIndex, ok := s.tryDeliverMessage(m, m.streamIndex, now) + if !ok { + break + } + m.streamIndex = delIndex + } + } +} + +// tryDeliverMessage attempts to deliver m to the stream at index i. If it can't, it +// tries streams i+1, i+2, ..., wrapping around. Once it's tried all streams, it +// exits. +// +// It returns the index of the stream it delivered the message to, or 0, false if +// it didn't deliver the message. +// +// Must be called with the lock held. +func (s *subscription) tryDeliverMessage(m *message, start int, now time.Time) (int, bool) { + for i := 0; i < len(s.streams); i++ { + idx := (i + start) % len(s.streams) + + st := s.streams[idx] + select { + case <-st.done: + s.streams = deleteStreamAt(s.streams, idx) + i-- + + case st.msgc <- m.proto: + (*m.deliveries)++ + m.ackDeadline = now.Add(st.ackTimeout) + return idx, true + + default: + } + } + return 0, false +} + +var retentionDuration = 10 * time.Minute + +// Must be called with the lock held. +func (s *subscription) maintainMessages(now time.Time) { + for id, m := range s.msgs { + // Mark a message as re-deliverable if its ack deadline has expired. + if m.outstanding() && now.After(m.ackDeadline) { + m.makeAvailable() + } + pubTime, err := ptypes.Timestamp(m.proto.Message.PublishTime) + if err != nil { + panic(err) + } + // Remove messages that have been undelivered for a long time. + if !m.outstanding() && now.Sub(pubTime) > retentionDuration { + delete(s.msgs, id) + } + } +} + +func (s *subscription) newStream(gs pb.Subscriber_StreamingPullServer, timeout time.Duration) *stream { + st := &stream{ + sub: s, + done: make(chan struct{}), + msgc: make(chan *pb.ReceivedMessage), + gstream: gs, + ackTimeout: s.ackTimeout, + timeout: timeout, + } + s.mu.Lock() + s.streams = append(s.streams, st) + s.mu.Unlock() + return st +} + +func (s *subscription) deleteStream(st *stream) { + s.mu.Lock() + defer s.mu.Unlock() + var i int + for i = 0; i < len(s.streams); i++ { + if s.streams[i] == st { + break + } + } + if i < len(s.streams) { + s.streams = deleteStreamAt(s.streams, i) + } +} +func deleteStreamAt(s []*stream, i int) []*stream { + // Preserve order for round-robin delivery. + return append(s[:i], s[i+1:]...) +} + +type message struct { + proto *pb.ReceivedMessage + publishTime time.Time + ackDeadline time.Time + deliveries *int + acks *int + streamIndex int // index of stream that currently owns msg, for round-robin delivery +} + +// A message is outstanding if it is owned by some stream. +func (m *message) outstanding() bool { + return !m.ackDeadline.IsZero() +} + +func (m *message) makeAvailable() { + m.ackDeadline = time.Time{} +} + +type stream struct { + sub *subscription + done chan struct{} // closed when the stream is finished + msgc chan *pb.ReceivedMessage + gstream pb.Subscriber_StreamingPullServer + ackTimeout time.Duration + timeout time.Duration +} + +// pull manages the StreamingPull interaction for the life of the stream. +func (st *stream) pull(wg *sync.WaitGroup) error { + errc := make(chan error, 2) + wg.Add(2) + go func() { + defer wg.Done() + errc <- st.sendLoop() + }() + go func() { + defer wg.Done() + errc <- st.recvLoop() + }() + var tchan <-chan time.Time + if st.timeout > 0 { + tchan = time.After(st.timeout) + } + // Wait until one of the goroutines returns an error, or we time out. + var err error + select { + case err = <-errc: + if err == io.EOF { + err = nil + } + case <-tchan: + } + close(st.done) // stop the other goroutine + return err +} + +func (st *stream) sendLoop() error { + for { + select { + case <-st.done: + return nil + case rm := <-st.msgc: + res := &pb.StreamingPullResponse{ReceivedMessages: []*pb.ReceivedMessage{rm}} + if err := st.gstream.Send(res); err != nil { + return err + } + } + } +} + +func (st *stream) recvLoop() error { + for { + req, err := st.gstream.Recv() + if err != nil { + return err + } + st.sub.handleStreamingPullRequest(st, req) + } +} + +func (s *subscription) handleStreamingPullRequest(st *stream, req *pb.StreamingPullRequest) { + // Lock the entire server. + s.mu.Lock() + defer s.mu.Unlock() + + for _, ackID := range req.AckIds { + s.ack(ackID) + } + for i, id := range req.ModifyDeadlineAckIds { + s.modifyAckDeadline(id, secsToDur(req.ModifyDeadlineSeconds[i])) + } + if req.StreamAckDeadlineSeconds > 0 { + st.ackTimeout = secsToDur(req.StreamAckDeadlineSeconds) + } +} + +// Must be called with the lock held. +func (s *subscription) ack(id string) { + m := s.msgs[id] + if m != nil { + (*m.acks)++ + delete(s.msgs, id) + } +} + +// Must be called with the lock held. +func (s *subscription) modifyAckDeadline(id string, d time.Duration) { + m := s.msgs[id] + if m == nil { // already acked: ignore. + return + } + if d == 0 { // nack + m.makeAvailable() + } else { // extend the deadline by d + m.ackDeadline = timeNow().Add(d) + } +} + +func secsToDur(secs int32) time.Duration { + return time.Duration(secs) * time.Second +} diff --git a/vendor/cloud.google.com/go/pubsub/pstest/fake_test.go b/vendor/cloud.google.com/go/pubsub/pstest/fake_test.go new file mode 100644 index 00000000..b1c99bca --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/pstest/fake_test.go @@ -0,0 +1,715 @@ +// Copyright 2017 Google LLC +// +// 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 pstest + +import ( + "context" + "fmt" + "io" + "sync" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "github.com/golang/protobuf/ptypes" + pb "google.golang.org/genproto/googleapis/pubsub/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestTopics(t *testing.T) { + pclient, _, server, cleanup := newFake(context.TODO(), t) + defer cleanup() + + ctx := context.Background() + var topics []*pb.Topic + for i := 1; i < 3; i++ { + topics = append(topics, mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{ + Name: fmt.Sprintf("projects/P/topics/T%d", i), + Labels: map[string]string{"num": fmt.Sprintf("%d", i)}, + })) + } + if got, want := len(server.gServer.topics), len(topics); got != want { + t.Fatalf("got %d topics, want %d", got, want) + } + for _, top := range topics { + got, err := pclient.GetTopic(ctx, &pb.GetTopicRequest{Topic: top.Name}) + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(got, top) { + t.Errorf("\ngot %+v\nwant %+v", got, top) + } + } + + res, err := pclient.ListTopics(ctx, &pb.ListTopicsRequest{Project: "projects/P"}) + if err != nil { + t.Fatal(err) + } + if got, want := res.Topics, topics; !testutil.Equal(got, want) { + t.Errorf("\ngot %+v\nwant %+v", got, want) + } + + for _, top := range topics { + if _, err := pclient.DeleteTopic(ctx, &pb.DeleteTopicRequest{Topic: top.Name}); err != nil { + t.Fatal(err) + } + } + if got, want := len(server.gServer.topics), 0; got != want { + t.Fatalf("got %d topics, want %d", got, want) + } +} + +func TestSubscriptions(t *testing.T) { + pclient, sclient, server, cleanup := newFake(context.TODO(), t) + defer cleanup() + + ctx := context.Background() + topic := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"}) + var subs []*pb.Subscription + for i := 0; i < 3; i++ { + subs = append(subs, mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{ + Name: fmt.Sprintf("projects/P/subscriptions/S%d", i), + Topic: topic.Name, + AckDeadlineSeconds: int32(10 * (i + 1)), + })) + } + + if got, want := len(server.gServer.subs), len(subs); got != want { + t.Fatalf("got %d subscriptions, want %d", got, want) + } + for _, s := range subs { + got, err := sclient.GetSubscription(ctx, &pb.GetSubscriptionRequest{Subscription: s.Name}) + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(got, s) { + t.Errorf("\ngot %+v\nwant %+v", got, s) + } + } + + res, err := sclient.ListSubscriptions(ctx, &pb.ListSubscriptionsRequest{Project: "projects/P"}) + if err != nil { + t.Fatal(err) + } + if got, want := res.Subscriptions, subs; !testutil.Equal(got, want) { + t.Errorf("\ngot %+v\nwant %+v", got, want) + } + + res2, err := pclient.ListTopicSubscriptions(ctx, &pb.ListTopicSubscriptionsRequest{Topic: topic.Name}) + if err != nil { + t.Fatal(err) + } + if got, want := len(res2.Subscriptions), len(subs); got != want { + t.Fatalf("got %d subs, want %d", got, want) + } + for i, got := range res2.Subscriptions { + want := subs[i].Name + if !testutil.Equal(got, want) { + t.Errorf("\ngot %+v\nwant %+v", got, want) + } + } + + for _, s := range subs { + if _, err := sclient.DeleteSubscription(ctx, &pb.DeleteSubscriptionRequest{Subscription: s.Name}); err != nil { + t.Fatal(err) + } + } + if got, want := len(server.gServer.subs), 0; got != want { + t.Fatalf("got %d subscriptions, want %d", got, want) + } +} + +func TestSubscriptionErrors(t *testing.T) { + _, sclient, _, cleanup := newFake(context.TODO(), t) + defer cleanup() + + ctx := context.Background() + + checkCode := func(err error, want codes.Code) { + t.Helper() + if status.Code(err) != want { + t.Errorf("got %v, want code %s", err, want) + } + } + + _, err := sclient.GetSubscription(ctx, &pb.GetSubscriptionRequest{}) + checkCode(err, codes.InvalidArgument) + _, err = sclient.GetSubscription(ctx, &pb.GetSubscriptionRequest{Subscription: "s"}) + checkCode(err, codes.NotFound) + _, err = sclient.UpdateSubscription(ctx, &pb.UpdateSubscriptionRequest{}) + checkCode(err, codes.InvalidArgument) + _, err = sclient.UpdateSubscription(ctx, &pb.UpdateSubscriptionRequest{Subscription: &pb.Subscription{}}) + checkCode(err, codes.InvalidArgument) + _, err = sclient.UpdateSubscription(ctx, &pb.UpdateSubscriptionRequest{Subscription: &pb.Subscription{Name: "s"}}) + checkCode(err, codes.NotFound) + _, err = sclient.DeleteSubscription(ctx, &pb.DeleteSubscriptionRequest{}) + checkCode(err, codes.InvalidArgument) + _, err = sclient.DeleteSubscription(ctx, &pb.DeleteSubscriptionRequest{Subscription: "s"}) + checkCode(err, codes.NotFound) + _, err = sclient.Acknowledge(ctx, &pb.AcknowledgeRequest{}) + checkCode(err, codes.InvalidArgument) + _, err = sclient.Acknowledge(ctx, &pb.AcknowledgeRequest{Subscription: "s"}) + checkCode(err, codes.NotFound) + _, err = sclient.ModifyAckDeadline(ctx, &pb.ModifyAckDeadlineRequest{}) + checkCode(err, codes.InvalidArgument) + _, err = sclient.ModifyAckDeadline(ctx, &pb.ModifyAckDeadlineRequest{Subscription: "s"}) + checkCode(err, codes.NotFound) + _, err = sclient.Pull(ctx, &pb.PullRequest{}) + checkCode(err, codes.InvalidArgument) + _, err = sclient.Pull(ctx, &pb.PullRequest{Subscription: "s"}) + checkCode(err, codes.NotFound) + _, err = sclient.Seek(ctx, &pb.SeekRequest{}) + checkCode(err, codes.InvalidArgument) + srt := &pb.SeekRequest_Time{Time: ptypes.TimestampNow()} + _, err = sclient.Seek(ctx, &pb.SeekRequest{Target: srt}) + checkCode(err, codes.InvalidArgument) + _, err = sclient.Seek(ctx, &pb.SeekRequest{Target: srt, Subscription: "s"}) + checkCode(err, codes.NotFound) +} + +func TestPublish(t *testing.T) { + s := NewServer() + defer s.Close() + + var ids []string + for i := 0; i < 3; i++ { + ids = append(ids, s.Publish("projects/p/topics/t", []byte("hello"), nil)) + } + s.Wait() + ms := s.Messages() + if got, want := len(ms), len(ids); got != want { + t.Errorf("got %d messages, want %d", got, want) + } + for i, id := range ids { + if got, want := ms[i].ID, id; got != want { + t.Errorf("got %s, want %s", got, want) + } + } + + m := s.Message(ids[1]) + if m == nil { + t.Error("got nil, want a message") + } +} + +// Note: this sets the fake's "now" time, so it is sensitive to concurrent changes to "now". +func publish(t *testing.T, pclient pb.PublisherClient, topic *pb.Topic, messages []*pb.PubsubMessage) map[string]*pb.PubsubMessage { + pubTime := time.Now() + now.Store(func() time.Time { return pubTime }) + defer func() { now.Store(time.Now) }() + + res, err := pclient.Publish(context.Background(), &pb.PublishRequest{ + Topic: topic.Name, + Messages: messages, + }) + if err != nil { + t.Fatal(err) + } + tsPubTime, err := ptypes.TimestampProto(pubTime) + if err != nil { + t.Fatal(err) + } + want := map[string]*pb.PubsubMessage{} + for i, id := range res.MessageIds { + want[id] = &pb.PubsubMessage{ + Data: messages[i].Data, + Attributes: messages[i].Attributes, + MessageId: id, + PublishTime: tsPubTime, + } + } + return want +} + +func TestPull(t *testing.T) { + pclient, sclient, _, cleanup := newFake(context.TODO(), t) + defer cleanup() + + top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"}) + sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{ + Name: "projects/P/subscriptions/S", + Topic: top.Name, + AckDeadlineSeconds: 10, + }) + + want := publish(t, pclient, top, []*pb.PubsubMessage{ + {Data: []byte("d1")}, + {Data: []byte("d2")}, + {Data: []byte("d3")}, + }) + got := pubsubMessages(pullN(context.TODO(), t, len(want), sclient, sub)) + if diff := testutil.Diff(got, want); diff != "" { + t.Error(diff) + } + + res, err := sclient.Pull(context.Background(), &pb.PullRequest{Subscription: sub.Name}) + if err != nil { + t.Fatal(err) + } + if len(res.ReceivedMessages) != 0 { + t.Errorf("got %d messages, want zero", len(res.ReceivedMessages)) + } +} + +func TestStreamingPull(t *testing.T) { + // A simple test of streaming pull. + pclient, sclient, _, cleanup := newFake(context.TODO(), t) + defer cleanup() + + top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"}) + sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{ + Name: "projects/P/subscriptions/S", + Topic: top.Name, + AckDeadlineSeconds: 10, + }) + + want := publish(t, pclient, top, []*pb.PubsubMessage{ + {Data: []byte("d1")}, + {Data: []byte("d2")}, + {Data: []byte("d3")}, + }) + got := pubsubMessages(streamingPullN(context.TODO(), t, len(want), sclient, sub)) + if diff := testutil.Diff(got, want); diff != "" { + t.Error(diff) + } +} + +// This test acks each message as it arrives and makes sure we don't see dups. +func TestStreamingPullAck(t *testing.T) { + minAckDeadlineSecs = 1 + pclient, sclient, _, cleanup := newFake(context.TODO(), t) + defer cleanup() + + top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"}) + sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{ + Name: "projects/P/subscriptions/S", + Topic: top.Name, + AckDeadlineSeconds: 1, + }) + + _ = publish(t, pclient, top, []*pb.PubsubMessage{ + {Data: []byte("d1")}, + {Data: []byte("d2")}, + {Data: []byte("d3")}, + }) + + got := map[string]bool{} + ctx, cancel := context.WithCancel(context.Background()) + spc := mustStartStreamingPull(ctx, t, sclient, sub) + time.AfterFunc(time.Duration(2*minAckDeadlineSecs)*time.Second, cancel) + + for i := 0; i < 4; i++ { + res, err := spc.Recv() + if err == io.EOF { + break + } + if err != nil { + if status.Code(err) == codes.Canceled { + break + } + t.Fatal(err) + } + if i == 3 { + t.Fatal("expected to only see 3 messages, got 4") + } + req := &pb.StreamingPullRequest{} + for _, m := range res.ReceivedMessages { + if got[m.Message.MessageId] { + t.Fatal("duplicate message") + } + got[m.Message.MessageId] = true + req.AckIds = append(req.AckIds, m.AckId) + } + if err := spc.Send(req); err != nil { + t.Fatal(err) + } + } +} + +func TestAcknowledge(t *testing.T) { + ctx := context.Background() + pclient, sclient, srv, cleanup := newFake(context.TODO(), t) + defer cleanup() + + top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"}) + sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{ + Name: "projects/P/subscriptions/S", + Topic: top.Name, + AckDeadlineSeconds: 10, + }) + + publish(t, pclient, top, []*pb.PubsubMessage{ + {Data: []byte("d1")}, + {Data: []byte("d2")}, + {Data: []byte("d3")}, + }) + msgs := streamingPullN(context.TODO(), t, 3, sclient, sub) + var ackIDs []string + for _, m := range msgs { + ackIDs = append(ackIDs, m.AckId) + } + if _, err := sclient.Acknowledge(ctx, &pb.AcknowledgeRequest{ + Subscription: sub.Name, + AckIds: ackIDs, + }); err != nil { + t.Fatal(err) + } + smsgs := srv.Messages() + if got, want := len(smsgs), 3; got != want { + t.Fatalf("got %d messages, want %d", got, want) + } + for _, sm := range smsgs { + if sm.Acks != 1 { + t.Errorf("message %s: got %d acks, want 1", sm.ID, sm.Acks) + } + } +} + +func TestModAck(t *testing.T) { + ctx := context.Background() + pclient, sclient, _, cleanup := newFake(context.TODO(), t) + defer cleanup() + + top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"}) + sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{ + Name: "projects/P/subscriptions/S", + Topic: top.Name, + AckDeadlineSeconds: 10, + }) + + publish(t, pclient, top, []*pb.PubsubMessage{ + {Data: []byte("d1")}, + {Data: []byte("d2")}, + {Data: []byte("d3")}, + }) + msgs := streamingPullN(context.TODO(), t, 3, sclient, sub) + var ackIDs []string + for _, m := range msgs { + ackIDs = append(ackIDs, m.AckId) + } + if _, err := sclient.ModifyAckDeadline(ctx, &pb.ModifyAckDeadlineRequest{ + Subscription: sub.Name, + AckIds: ackIDs, + AckDeadlineSeconds: 0, + }); err != nil { + t.Fatal(err) + } + // Having nacked all three messages, we should see them again. + msgs = streamingPullN(context.TODO(), t, 3, sclient, sub) + if got, want := len(msgs), 3; got != want { + t.Errorf("got %d messages, want %d", got, want) + } +} + +func TestAckDeadline(t *testing.T) { + // Messages should be resent after they expire. + pclient, sclient, _, cleanup := newFake(context.TODO(), t) + defer cleanup() + + minAckDeadlineSecs = 2 + top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"}) + sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{ + Name: "projects/P/subscriptions/S", + Topic: top.Name, + AckDeadlineSeconds: minAckDeadlineSecs, + }) + + _ = publish(t, pclient, top, []*pb.PubsubMessage{ + {Data: []byte("d1")}, + {Data: []byte("d2")}, + {Data: []byte("d3")}, + }) + + got := map[string]int{} + spc := mustStartStreamingPull(context.TODO(), t, sclient, sub) + // In 5 seconds the ack deadline will expire twice, so we should see each message + // exactly three times. + time.AfterFunc(5*time.Second, func() { + if err := spc.CloseSend(); err != nil { + t.Errorf("CloseSend: %v", err) + } + }) + for { + res, err := spc.Recv() + if err == io.EOF { + break + } + if err != nil { + t.Fatal(err) + } + for _, m := range res.ReceivedMessages { + got[m.Message.MessageId]++ + } + } + for id, n := range got { + if n != 3 { + t.Errorf("message %s: saw %d times, want 3", id, n) + } + } +} + +func TestMultiSubs(t *testing.T) { + // Each subscription gets every message. + pclient, sclient, _, cleanup := newFake(context.TODO(), t) + defer cleanup() + + top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"}) + sub1 := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{ + Name: "projects/P/subscriptions/S1", + Topic: top.Name, + AckDeadlineSeconds: 10, + }) + sub2 := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{ + Name: "projects/P/subscriptions/S2", + Topic: top.Name, + AckDeadlineSeconds: 10, + }) + + want := publish(t, pclient, top, []*pb.PubsubMessage{ + {Data: []byte("d1")}, + {Data: []byte("d2")}, + {Data: []byte("d3")}, + }) + got1 := pubsubMessages(streamingPullN(context.TODO(), t, len(want), sclient, sub1)) + got2 := pubsubMessages(streamingPullN(context.TODO(), t, len(want), sclient, sub2)) + if diff := testutil.Diff(got1, want); diff != "" { + t.Error(diff) + } + if diff := testutil.Diff(got2, want); diff != "" { + t.Error(diff) + } +} + +// Messages are handed out to all streams of a subscription in a best-effort +// round-robin behavior. The fake server prefers to fail-fast onto another +// stream when one stream is already busy, though, so we're unable to test +// strict round robin behavior. +func TestMultiStreams(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + pclient, sclient, _, cleanup := newFake(ctx, t) + defer cleanup() + + top := mustCreateTopic(ctx, t, pclient, &pb.Topic{Name: "projects/P/topics/T"}) + sub := mustCreateSubscription(ctx, t, sclient, &pb.Subscription{ + Name: "projects/P/subscriptions/S", + Topic: top.Name, + AckDeadlineSeconds: 10, + }) + st1 := mustStartStreamingPull(ctx, t, sclient, sub) + defer st1.CloseSend() + st1Received := make(chan struct{}) + go func() { + _, err := st1.Recv() + if err != nil { + t.Error(err) + } + close(st1Received) + }() + + st2 := mustStartStreamingPull(ctx, t, sclient, sub) + defer st2.CloseSend() + st2Received := make(chan struct{}) + go func() { + _, err := st2.Recv() + if err != nil { + t.Error(err) + } + close(st2Received) + }() + + publish(t, pclient, top, []*pb.PubsubMessage{ + {Data: []byte("d1")}, + {Data: []byte("d2")}, + }) + + timeout := time.After(5 * time.Second) + select { + case <-timeout: + t.Fatal("timed out waiting for stream 1 to receive any message") + case <-st1Received: + } + select { + case <-timeout: + t.Fatal("timed out waiting for stream 1 to receive any message") + case <-st2Received: + } +} + +func TestStreamingPullTimeout(t *testing.T) { + pclient, sclient, srv, cleanup := newFake(context.TODO(), t) + defer cleanup() + + timeout := 200 * time.Millisecond + srv.SetStreamTimeout(timeout) + top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"}) + sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{ + Name: "projects/P/subscriptions/S", + Topic: top.Name, + AckDeadlineSeconds: 10, + }) + stream := mustStartStreamingPull(context.TODO(), t, sclient, sub) + time.Sleep(2 * timeout) + _, err := stream.Recv() + if err != io.EOF { + t.Errorf("got %v, want io.EOF", err) + } +} + +func TestSeek(t *testing.T) { + pclient, sclient, _, cleanup := newFake(context.TODO(), t) + defer cleanup() + + top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"}) + sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{ + Name: "projects/P/subscriptions/S", + Topic: top.Name, + AckDeadlineSeconds: 10, + }) + ts := ptypes.TimestampNow() + _, err := sclient.Seek(context.Background(), &pb.SeekRequest{ + Subscription: sub.Name, + Target: &pb.SeekRequest_Time{Time: ts}, + }) + if err != nil { + t.Errorf("Seeking: %v", err) + } +} + +func TestTryDeliverMessage(t *testing.T) { + for _, test := range []struct { + desc string + availStreamIdx int + expectedOutIdx int + }{ + {availStreamIdx: 0, expectedOutIdx: 0}, + // Stream 1 will always be marked for deletion. + {availStreamIdx: 2, expectedOutIdx: 1}, // s0, s1 (deleted), s2, s3 becomes s0, s2, s3. So we expect outIdx=1. + {availStreamIdx: 3, expectedOutIdx: 2}, // s0, s1 (deleted), s2, s3 becomes s0, s2, s3. So we expect outIdx=2. + } { + top := newTopic(&pb.Topic{Name: "some-topic"}) + sub := newSubscription(top, &sync.Mutex{}, &pb.Subscription{Name: "some-sub", Topic: "some-topic"}) + + done := make(chan struct{}, 1) + done <- struct{}{} + sub.streams = []*stream{{}, {done: done}, {}, {}} + + msgc := make(chan *pb.ReceivedMessage, 1) + sub.streams[test.availStreamIdx].msgc = msgc + + var d int + idx, ok := sub.tryDeliverMessage(&message{deliveries: &d}, 0, time.Now()) + if !ok { + t.Fatalf("[avail=%d]: expected msg to be put on stream %d's channel, but it was not", test.availStreamIdx, test.expectedOutIdx) + } + if idx != test.expectedOutIdx { + t.Fatalf("[avail=%d]: expected msg to be put on stream %d, but it was put on %d", test.availStreamIdx, test.expectedOutIdx, idx) + } + select { + case <-msgc: + default: + t.Fatalf("[avail=%d]: expected msg to be put on stream %d's channel, but it was not", test.availStreamIdx, idx) + } + } +} + +func mustStartStreamingPull(ctx context.Context, t *testing.T, sc pb.SubscriberClient, sub *pb.Subscription) pb.Subscriber_StreamingPullClient { + spc, err := sc.StreamingPull(ctx) + if err != nil { + t.Fatal(err) + } + if err := spc.Send(&pb.StreamingPullRequest{Subscription: sub.Name}); err != nil { + t.Fatal(err) + } + return spc +} + +func pullN(ctx context.Context, t *testing.T, n int, sc pb.SubscriberClient, sub *pb.Subscription) map[string]*pb.ReceivedMessage { + got := map[string]*pb.ReceivedMessage{} + for i := 0; len(got) < n; i++ { + res, err := sc.Pull(ctx, &pb.PullRequest{Subscription: sub.Name, MaxMessages: int32(n - len(got))}) + if err != nil { + t.Fatal(err) + } + for _, m := range res.ReceivedMessages { + got[m.Message.MessageId] = m + } + } + return got +} + +func streamingPullN(ctx context.Context, t *testing.T, n int, sc pb.SubscriberClient, sub *pb.Subscription) map[string]*pb.ReceivedMessage { + spc := mustStartStreamingPull(ctx, t, sc, sub) + got := map[string]*pb.ReceivedMessage{} + for i := 0; i < n; i++ { + res, err := spc.Recv() + if err != nil { + t.Fatal(err) + } + for _, m := range res.ReceivedMessages { + got[m.Message.MessageId] = m + } + } + if err := spc.CloseSend(); err != nil { + t.Fatal(err) + } + res, err := spc.Recv() + if err != io.EOF { + t.Fatalf("Recv returned <%v> instead of EOF; res = %v", err, res) + } + return got +} + +func pubsubMessages(rms map[string]*pb.ReceivedMessage) map[string]*pb.PubsubMessage { + ms := map[string]*pb.PubsubMessage{} + for k, rm := range rms { + ms[k] = rm.Message + } + return ms +} + +func mustCreateTopic(ctx context.Context, t *testing.T, pc pb.PublisherClient, topic *pb.Topic) *pb.Topic { + top, err := pc.CreateTopic(ctx, topic) + if err != nil { + t.Fatal(err) + } + return top +} + +func mustCreateSubscription(ctx context.Context, t *testing.T, sc pb.SubscriberClient, sub *pb.Subscription) *pb.Subscription { + sub, err := sc.CreateSubscription(ctx, sub) + if err != nil { + t.Fatal(err) + } + return sub +} + +// newFake creates a new fake server along with a publisher and subscriber +// client. Its final return is a cleanup function. +// +// Note: be sure to call cleanup! +func newFake(ctx context.Context, t *testing.T) (pb.PublisherClient, pb.SubscriberClient, *Server, func()) { + srv := NewServer() + conn, err := grpc.DialContext(ctx, srv.Addr, grpc.WithInsecure()) + if err != nil { + t.Fatal(err) + } + return pb.NewPublisherClient(conn), pb.NewSubscriberClient(conn), srv, func() { + srv.Close() + conn.Close() + } +} diff --git a/vendor/cloud.google.com/go/pubsub/pstest_test.go b/vendor/cloud.google.com/go/pubsub/pstest_test.go new file mode 100644 index 00000000..0a1e4c37 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/pstest_test.go @@ -0,0 +1,78 @@ +// Copyright 2018 Google LLC +// +// 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 pubsub_test + +import ( + "context" + "strconv" + "sync" + "testing" + + "cloud.google.com/go/pubsub" + "cloud.google.com/go/pubsub/pstest" + "google.golang.org/api/option" + "google.golang.org/grpc" +) + +func TestPSTest(t *testing.T) { + t.Parallel() + ctx := context.Background() + srv := pstest.NewServer() + defer srv.Close() + + conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure()) + if err != nil { + panic(err) + } + defer conn.Close() + + client, err := pubsub.NewClient(ctx, "some-project", option.WithGRPCConn(conn)) + if err != nil { + panic(err) + } + defer client.Close() + + topic, err := client.CreateTopic(ctx, "test-topic") + if err != nil { + panic(err) + } + + sub, err := client.CreateSubscription(ctx, "sub-name", pubsub.SubscriptionConfig{Topic: topic}) + if err != nil { + panic(err) + } + + go func() { + for i := 0; i < 10; i++ { + srv.Publish("projects/some-project/topics/test-topic", []byte(strconv.Itoa(i)), nil) + } + }() + + ctx, cancel := context.WithCancel(ctx) + var mu sync.Mutex + count := 0 + err = sub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) { + mu.Lock() + count++ + if count >= 10 { + cancel() + } + mu.Unlock() + m.Ack() + }) + if err != nil { + panic(err) + } +} diff --git a/vendor/cloud.google.com/go/pubsub/pubsub.go b/vendor/cloud.google.com/go/pubsub/pubsub.go new file mode 100644 index 00000000..83f6731d --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/pubsub.go @@ -0,0 +1,111 @@ +// Copyright 2014 Google LLC +// +// 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 pubsub // import "cloud.google.com/go/pubsub" + +import ( + "context" + "fmt" + "os" + "runtime" + "time" + + "cloud.google.com/go/internal/version" + vkit "cloud.google.com/go/pubsub/apiv1" + "google.golang.org/api/option" + "google.golang.org/grpc" + "google.golang.org/grpc/keepalive" +) + +const ( + // ScopePubSub grants permissions to view and manage Pub/Sub + // topics and subscriptions. + ScopePubSub = "https://www.googleapis.com/auth/pubsub" + + // ScopeCloudPlatform grants permissions to view and manage your data + // across Google Cloud Platform services. + ScopeCloudPlatform = "https://www.googleapis.com/auth/cloud-platform" + + prodAddr = "https://pubsub.googleapis.com/" + + maxAckDeadline = 10 * time.Minute +) + +// Client is a Google Pub/Sub client scoped to a single project. +// +// Clients should be reused rather than being created as needed. +// A Client may be shared by multiple goroutines. +type Client struct { + projectID string + pubc *vkit.PublisherClient + subc *vkit.SubscriberClient +} + +// NewClient creates a new PubSub client. +func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (c *Client, err error) { + var o []option.ClientOption + // Environment variables for gcloud emulator: + // https://cloud.google.com/sdk/gcloud/reference/beta/emulators/pubsub/ + if addr := os.Getenv("PUBSUB_EMULATOR_HOST"); addr != "" { + conn, err := grpc.Dial(addr, grpc.WithInsecure()) + if err != nil { + return nil, fmt.Errorf("grpc.Dial: %v", err) + } + o = []option.ClientOption{option.WithGRPCConn(conn)} + } else { + o = []option.ClientOption{ + // Create multiple connections to increase throughput. + option.WithGRPCConnectionPool(runtime.GOMAXPROCS(0)), + option.WithGRPCDialOption(grpc.WithKeepaliveParams(keepalive.ClientParameters{ + Time: 5 * time.Minute, + })), + } + o = append(o, openCensusOptions()...) + } + o = append(o, opts...) + pubc, err := vkit.NewPublisherClient(ctx, o...) + if err != nil { + return nil, fmt.Errorf("pubsub: %v", err) + } + subc, err := vkit.NewSubscriberClient(ctx, option.WithGRPCConn(pubc.Connection())) + if err != nil { + // Should never happen, since we are passing in the connection. + // If it does, we cannot close, because the user may have passed in their + // own connection originally. + return nil, fmt.Errorf("pubsub: %v", err) + } + pubc.SetGoogleClientInfo("gccl", version.Repo) + subc.SetGoogleClientInfo("gccl", version.Repo) + return &Client{ + projectID: projectID, + pubc: pubc, + subc: subc, + }, nil +} + +// Close releases any resources held by the client, +// such as memory and goroutines. +// +// If the client is available for the lifetime of the program, then Close need not be +// called at exit. +func (c *Client) Close() error { + // Return the first error, because the first call closes the connection. + err := c.pubc.Close() + _ = c.subc.Close() + return err +} + +func (c *Client) fullyQualifiedProjectName() string { + return fmt.Sprintf("projects/%s", c.projectID) +} diff --git a/vendor/cloud.google.com/go/pubsub/pullstream.go b/vendor/cloud.google.com/go/pubsub/pullstream.go new file mode 100644 index 00000000..5a50ff99 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/pullstream.go @@ -0,0 +1,182 @@ +// Copyright 2018 Google LLC +// +// 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 pubsub + +import ( + "context" + "io" + "sync" + "time" + + gax "github.com/googleapis/gax-go" + pb "google.golang.org/genproto/googleapis/pubsub/v1" + "google.golang.org/grpc" +) + +// A pullStream supports the methods of a StreamingPullClient, but re-opens +// the stream on a retryable error. +type pullStream struct { + ctx context.Context + open func() (pb.Subscriber_StreamingPullClient, error) + + mu sync.Mutex + spc *pb.Subscriber_StreamingPullClient + err error // permanent error +} + +// for testing +type streamingPullFunc func(context.Context, ...gax.CallOption) (pb.Subscriber_StreamingPullClient, error) + +func newPullStream(ctx context.Context, streamingPull streamingPullFunc, subName string) *pullStream { + ctx = withSubscriptionKey(ctx, subName) + return &pullStream{ + ctx: ctx, + open: func() (pb.Subscriber_StreamingPullClient, error) { + spc, err := streamingPull(ctx, gax.WithGRPCOptions(grpc.MaxCallRecvMsgSize(maxSendRecvBytes))) + if err == nil { + recordStat(ctx, StreamRequestCount, 1) + err = spc.Send(&pb.StreamingPullRequest{ + Subscription: subName, + // We modack messages when we receive them, so this value doesn't matter too much. + StreamAckDeadlineSeconds: 60, + }) + } + if err != nil { + return nil, err + } + return spc, nil + }, + } +} + +// get returns either a valid *StreamingPullClient (SPC), or a permanent error. +// If the argument is nil, this is the first call for an RPC, and the current +// SPC will be returned (or a new one will be opened). Otherwise, this call is a +// request to re-open the stream because of a retryable error, and the argument +// is a pointer to the SPC that returned the error. +func (s *pullStream) get(spc *pb.Subscriber_StreamingPullClient) (*pb.Subscriber_StreamingPullClient, error) { + s.mu.Lock() + defer s.mu.Unlock() + // A stored error is permanent. + if s.err != nil { + return nil, s.err + } + // If the context is done, so are we. + s.err = s.ctx.Err() + if s.err != nil { + return nil, s.err + } + + // If the current and argument SPCs differ, return the current one. This subsumes two cases: + // 1. We have an SPC and the caller is getting the stream for the first time. + // 2. The caller wants to retry, but they have an older SPC; we've already retried. + if spc != s.spc { + return s.spc, nil + } + // Either this is the very first call on this stream (s.spc == nil), or we have a valid + // retry request. Either way, open a new stream. + // The lock is held here for a long time, but it doesn't matter because no callers could get + // anything done anyway. + s.spc = new(pb.Subscriber_StreamingPullClient) + *s.spc, s.err = s.openWithRetry() // Any error from openWithRetry is permanent. + return s.spc, s.err +} + +func (s *pullStream) openWithRetry() (pb.Subscriber_StreamingPullClient, error) { + var bo gax.Backoff + for { + recordStat(s.ctx, StreamOpenCount, 1) + spc, err := s.open() + if err != nil && isRetryable(err) { + recordStat(s.ctx, StreamRetryCount, 1) + if err := gax.Sleep(s.ctx, bo.Pause()); err != nil { + return nil, err + } + continue + } + return spc, err + } +} + +func (s *pullStream) call(f func(pb.Subscriber_StreamingPullClient) error) error { + var ( + spc *pb.Subscriber_StreamingPullClient + err error + bo gax.Backoff + ) + for { + spc, err = s.get(spc) + if err != nil { + return err + } + start := time.Now() + err = f(*spc) + if err != nil { + if isRetryable(err) { + recordStat(s.ctx, StreamRetryCount, 1) + if time.Since(start) < 30*time.Second { // don't sleep if we've been blocked for a while + if err := gax.Sleep(s.ctx, bo.Pause()); err != nil { + return err + } + } + continue + } + s.mu.Lock() + s.err = err + s.mu.Unlock() + } + return err + } +} + +func (s *pullStream) Send(req *pb.StreamingPullRequest) error { + return s.call(func(spc pb.Subscriber_StreamingPullClient) error { + recordStat(s.ctx, AckCount, int64(len(req.AckIds))) + zeroes := 0 + for _, mds := range req.ModifyDeadlineSeconds { + if mds == 0 { + zeroes++ + } + } + recordStat(s.ctx, NackCount, int64(zeroes)) + recordStat(s.ctx, ModAckCount, int64(len(req.ModifyDeadlineSeconds)-zeroes)) + recordStat(s.ctx, StreamRequestCount, 1) + return spc.Send(req) + }) +} + +func (s *pullStream) Recv() (*pb.StreamingPullResponse, error) { + var res *pb.StreamingPullResponse + err := s.call(func(spc pb.Subscriber_StreamingPullClient) error { + var err error + recordStat(s.ctx, StreamResponseCount, 1) + res, err = spc.Recv() + if err == nil { + recordStat(s.ctx, PullCount, int64(len(res.ReceivedMessages))) + } + return err + }) + return res, err +} + +func (s *pullStream) CloseSend() error { + err := s.call(func(spc pb.Subscriber_StreamingPullClient) error { + return spc.CloseSend() + }) + s.mu.Lock() + s.err = io.EOF // should not be retried + s.mu.Unlock() + return err +} diff --git a/vendor/cloud.google.com/go/pubsub/pullstream_test.go b/vendor/cloud.google.com/go/pubsub/pullstream_test.go new file mode 100644 index 00000000..05948084 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/pullstream_test.go @@ -0,0 +1,78 @@ +// Copyright 2018 Google LLC +// +// 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 pubsub + +import ( + "context" + "testing" + + gax "github.com/googleapis/gax-go" + pb "google.golang.org/genproto/googleapis/pubsub/v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestPullStreamGet(t *testing.T) { + // Test that we retry on the initial Send call from pullstream.get. We don't do this + // test with the server in fake_test.go because there's no clear way to get Send + // to fail from the server. + t.Parallel() + for _, test := range []struct { + desc string + errors []error + wantCode codes.Code + }{ + { + desc: "nil error", + errors: []error{nil}, + wantCode: codes.OK, + }, + { + desc: "non-retryable error", + errors: []error{status.Errorf(codes.InvalidArgument, "")}, + wantCode: codes.InvalidArgument, + }, + { + desc: "retryable errors", + errors: []error{ + status.Errorf(codes.Unavailable, "first"), + status.Errorf(codes.Unavailable, "second"), + nil, + }, + wantCode: codes.OK, + }, + } { + streamingPull := func(context.Context, ...gax.CallOption) (pb.Subscriber_StreamingPullClient, error) { + if len(test.errors) == 0 { + panic("out of errors") + } + err := test.errors[0] + test.errors = test.errors[1:] + return &testStreamingPullClient{sendError: err}, nil + } + ps := newPullStream(context.Background(), streamingPull, "") + _, err := ps.get(nil) + if got := status.Code(err); got != test.wantCode { + t.Errorf("%s: got %s, want %s", test.desc, got, test.wantCode) + } + } +} + +type testStreamingPullClient struct { + pb.Subscriber_StreamingPullClient + sendError error +} + +func (c *testStreamingPullClient) Send(*pb.StreamingPullRequest) error { return c.sendError } diff --git a/vendor/cloud.google.com/go/pubsub/service.go b/vendor/cloud.google.com/go/pubsub/service.go new file mode 100644 index 00000000..63d4aa4e --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/service.go @@ -0,0 +1,78 @@ +// Copyright 2016 Google LLC +// +// 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 pubsub + +import ( + "fmt" + "math" + "strings" + + pb "google.golang.org/genproto/googleapis/pubsub/v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// maxPayload is the maximum number of bytes to devote to actual ids in +// acknowledgement or modifyAckDeadline requests. A serialized +// AcknowledgeRequest proto has a small constant overhead, plus the size of the +// subscription name, plus 3 bytes per ID (a tag byte and two size bytes). A +// ModifyAckDeadlineRequest has an additional few bytes for the deadline. We +// don't know the subscription name here, so we just assume the size exclusive +// of ids is 100 bytes. +// +// With gRPC there is no way for the client to know the server's max message size (it is +// configurable on the server). We know from experience that it +// it 512K. +const ( + maxPayload = 512 * 1024 + reqFixedOverhead = 100 + overheadPerID = 3 + maxSendRecvBytes = 20 * 1024 * 1024 // 20M +) + +func convertMessages(rms []*pb.ReceivedMessage) ([]*Message, error) { + msgs := make([]*Message, 0, len(rms)) + for i, m := range rms { + msg, err := toMessage(m) + if err != nil { + return nil, fmt.Errorf("pubsub: cannot decode the retrieved message at index: %d, message: %+v", i, m) + } + msgs = append(msgs, msg) + } + return msgs, nil +} + +func trunc32(i int64) int32 { + if i > math.MaxInt32 { + i = math.MaxInt32 + } + return int32(i) +} + +// Logic from https://github.com/GoogleCloudPlatform/google-cloud-java/blob/master/google-cloud-clients/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/StatusUtil.java +func isRetryable(err error) bool { + s, ok := status.FromError(err) + if !ok { // includes io.EOF, normal stream close, which causes us to reopen + return true + } + switch s.Code() { + case codes.DeadlineExceeded, codes.Internal, codes.ResourceExhausted: + return true + case codes.Unavailable: + return !strings.Contains(s.Message(), "Server shutdownNow invoked") + default: + return false + } +} diff --git a/vendor/cloud.google.com/go/pubsub/snapshot.go b/vendor/cloud.google.com/go/pubsub/snapshot.go new file mode 100644 index 00000000..d662f0d2 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/snapshot.go @@ -0,0 +1,160 @@ +// Copyright 2017 Google LLC +// +// 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 pubsub + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/golang/protobuf/ptypes" + pb "google.golang.org/genproto/googleapis/pubsub/v1" +) + +// Snapshot is a reference to a PubSub snapshot. +type Snapshot struct { + c *Client + + // The fully qualified identifier for the snapshot, in the format "projects//snapshots/" + name string +} + +// ID returns the unique identifier of the snapshot within its project. +func (s *Snapshot) ID() string { + slash := strings.LastIndex(s.name, "/") + if slash == -1 { + // name is not a fully-qualified name. + panic("bad snapshot name") + } + return s.name[slash+1:] +} + +// SnapshotConfig contains the details of a Snapshot. +type SnapshotConfig struct { + *Snapshot + Topic *Topic + Expiration time.Time +} + +// Snapshot creates a reference to a snapshot. +func (c *Client) Snapshot(id string) *Snapshot { + return &Snapshot{ + c: c, + name: fmt.Sprintf("projects/%s/snapshots/%s", c.projectID, id), + } +} + +// Snapshots returns an iterator which returns snapshots for this project. +func (c *Client) Snapshots(ctx context.Context) *SnapshotConfigIterator { + it := c.subc.ListSnapshots(ctx, &pb.ListSnapshotsRequest{ + Project: c.fullyQualifiedProjectName(), + }) + next := func() (*SnapshotConfig, error) { + snap, err := it.Next() + if err != nil { + return nil, err + } + return toSnapshotConfig(snap, c) + } + return &SnapshotConfigIterator{next: next} +} + +// SnapshotConfigIterator is an iterator that returns a series of snapshots. +type SnapshotConfigIterator struct { + next func() (*SnapshotConfig, error) +} + +// Next returns the next SnapshotConfig. Its second return value is iterator.Done if there are no more results. +// Once Next returns iterator.Done, all subsequent calls will return iterator.Done. +func (snaps *SnapshotConfigIterator) Next() (*SnapshotConfig, error) { + return snaps.next() +} + +// Delete deletes a snapshot. +func (s *Snapshot) Delete(ctx context.Context) error { + return s.c.subc.DeleteSnapshot(ctx, &pb.DeleteSnapshotRequest{Snapshot: s.name}) +} + +// SeekToTime seeks the subscription to a point in time. +// +// Messages retained in the subscription that were published before this +// time are marked as acknowledged, and messages retained in the +// subscription that were published after this time are marked as +// unacknowledged. Note that this operation affects only those messages +// retained in the subscription (configured by SnapshotConfig). For example, +// if `time` corresponds to a point before the message retention +// window (or to a point before the system's notion of the subscription +// creation time), only retained messages will be marked as unacknowledged, +// and already-expunged messages will not be restored. +func (s *Subscription) SeekToTime(ctx context.Context, t time.Time) error { + ts, err := ptypes.TimestampProto(t) + if err != nil { + return err + } + _, err = s.c.subc.Seek(ctx, &pb.SeekRequest{ + Subscription: s.name, + Target: &pb.SeekRequest_Time{ts}, + }) + return err +} + +// CreateSnapshot creates a new snapshot from this subscription. +// The snapshot will be for the topic this subscription is subscribed to. +// If the name is empty string, a unique name is assigned. +// +// The created snapshot is guaranteed to retain: +// (a) The existing backlog on the subscription. More precisely, this is +// defined as the messages in the subscription's backlog that are +// unacknowledged when Snapshot returns without error. +// (b) Any messages published to the subscription's topic following +// Snapshot returning without error. +func (s *Subscription) CreateSnapshot(ctx context.Context, name string) (*SnapshotConfig, error) { + if name != "" { + name = fmt.Sprintf("projects/%s/snapshots/%s", strings.Split(s.name, "/")[1], name) + } + snap, err := s.c.subc.CreateSnapshot(ctx, &pb.CreateSnapshotRequest{ + Name: name, + Subscription: s.name, + }) + if err != nil { + return nil, err + } + return toSnapshotConfig(snap, s.c) +} + +// SeekToSnapshot seeks the subscription to a snapshot. +// +// The snapshot need not be created from this subscription, +// but it must be for the topic this subscription is subscribed to. +func (s *Subscription) SeekToSnapshot(ctx context.Context, snap *Snapshot) error { + _, err := s.c.subc.Seek(ctx, &pb.SeekRequest{ + Subscription: s.name, + Target: &pb.SeekRequest_Snapshot{snap.name}, + }) + return err +} + +func toSnapshotConfig(snap *pb.Snapshot, c *Client) (*SnapshotConfig, error) { + exp, err := ptypes.Timestamp(snap.ExpireTime) + if err != nil { + return nil, err + } + return &SnapshotConfig{ + Snapshot: &Snapshot{c: c, name: snap.Name}, + Topic: newTopic(c, snap.Topic), + Expiration: exp, + }, nil +} diff --git a/vendor/cloud.google.com/go/pubsub/streaming_pull_test.go b/vendor/cloud.google.com/go/pubsub/streaming_pull_test.go new file mode 100644 index 00000000..ab382e76 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/streaming_pull_test.go @@ -0,0 +1,462 @@ +// Copyright 2017 Google LLC +// +// 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 pubsub + +// TODO(jba): test keepalive +// TODO(jba): test that expired messages are not kept alive +// TODO(jba): test that when all messages expire, Stop returns. + +import ( + "context" + "io" + "strconv" + "sync" + "sync/atomic" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + tspb "github.com/golang/protobuf/ptypes/timestamp" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "google.golang.org/api/option" + pb "google.golang.org/genproto/googleapis/pubsub/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var ( + timestamp = &tspb.Timestamp{} + testMessages = []*pb.ReceivedMessage{ + {AckId: "0", Message: &pb.PubsubMessage{Data: []byte{1}, PublishTime: timestamp}}, + {AckId: "1", Message: &pb.PubsubMessage{Data: []byte{2}, PublishTime: timestamp}}, + {AckId: "2", Message: &pb.PubsubMessage{Data: []byte{3}, PublishTime: timestamp}}, + } +) + +func TestStreamingPullBasic(t *testing.T) { + client, server := newMock(t) + defer server.srv.Close() + defer client.Close() + server.addStreamingPullMessages(testMessages) + testStreamingPullIteration(t, client, server, testMessages) +} + +func TestStreamingPullMultipleFetches(t *testing.T) { + client, server := newMock(t) + defer server.srv.Close() + defer client.Close() + server.addStreamingPullMessages(testMessages[:1]) + server.addStreamingPullMessages(testMessages[1:]) + testStreamingPullIteration(t, client, server, testMessages) +} + +func testStreamingPullIteration(t *testing.T, client *Client, server *mockServer, msgs []*pb.ReceivedMessage) { + sub := client.Subscription("S") + gotMsgs, err := pullN(context.Background(), sub, len(msgs), func(_ context.Context, m *Message) { + id, err := strconv.Atoi(m.ackID) + if err != nil { + panic(err) + } + // ack evens, nack odds + if id%2 == 0 { + m.Ack() + } else { + m.Nack() + } + }) + if c := status.Convert(err); err != nil && c.Code() != codes.Canceled { + t.Fatalf("Pull: %v", err) + } + gotMap := map[string]*Message{} + for _, m := range gotMsgs { + gotMap[m.ackID] = m + } + for i, msg := range msgs { + want, err := toMessage(msg) + if err != nil { + t.Fatal(err) + } + want.calledDone = true + got := gotMap[want.ackID] + if got == nil { + t.Errorf("%d: no message for ackID %q", i, want.ackID) + continue + } + if !testutil.Equal(got, want, cmp.AllowUnexported(Message{}), cmpopts.IgnoreTypes(time.Time{}, func(string, bool, time.Time) {})) { + t.Errorf("%d: got\n%#v\nwant\n%#v", i, got, want) + } + } + server.wait() + for i := 0; i < len(msgs); i++ { + id := msgs[i].AckId + if i%2 == 0 { + if !server.Acked[id] { + t.Errorf("msg %q should have been acked but wasn't", id) + } + } else { + if dl, ok := server.Deadlines[id]; !ok || dl != 0 { + t.Errorf("msg %q should have been nacked but wasn't", id) + } + } + } +} + +func TestStreamingPullError(t *testing.T) { + // If an RPC to the service returns a non-retryable error, Pull should + // return after all callbacks return, without waiting for messages to be + // acked. + client, server := newMock(t) + defer server.srv.Close() + defer client.Close() + server.addStreamingPullMessages(testMessages[:1]) + server.addStreamingPullError(status.Errorf(codes.Unknown, "")) + sub := client.Subscription("S") + // Use only one goroutine, since the fake server is configured to + // return only one error. + sub.ReceiveSettings.NumGoroutines = 1 + callbackDone := make(chan struct{}) + ctx, _ := context.WithTimeout(context.Background(), time.Second) + err := sub.Receive(ctx, func(ctx context.Context, m *Message) { + defer close(callbackDone) + select { + case <-ctx.Done(): + return + } + }) + select { + case <-callbackDone: + default: + t.Fatal("Receive returned but callback was not done") + } + if want := codes.Unknown; grpc.Code(err) != want { + t.Fatalf("got <%v>, want code %v", err, want) + } +} + +func TestStreamingPullCancel(t *testing.T) { + // If Receive's context is canceled, it should return after all callbacks + // return and all messages have been acked. + client, server := newMock(t) + defer server.srv.Close() + defer client.Close() + server.addStreamingPullMessages(testMessages) + sub := client.Subscription("S") + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + var n int32 + err := sub.Receive(ctx, func(ctx2 context.Context, m *Message) { + atomic.AddInt32(&n, 1) + defer atomic.AddInt32(&n, -1) + cancel() + m.Ack() + }) + if got := atomic.LoadInt32(&n); got != 0 { + t.Errorf("Receive returned with %d callbacks still running", got) + } + if err != nil { + t.Fatalf("Receive got <%v>, want nil", err) + } +} + +func TestStreamingPullRetry(t *testing.T) { + // Check that we retry on io.EOF or Unavailable. + t.Parallel() + client, server := newMock(t) + defer server.srv.Close() + defer client.Close() + server.addStreamingPullMessages(testMessages[:1]) + server.addStreamingPullError(io.EOF) + server.addStreamingPullError(io.EOF) + server.addStreamingPullMessages(testMessages[1:2]) + server.addStreamingPullError(status.Errorf(codes.Unavailable, "")) + server.addStreamingPullError(status.Errorf(codes.Unavailable, "")) + server.addStreamingPullMessages(testMessages[2:]) + + testStreamingPullIteration(t, client, server, testMessages) +} + +func TestStreamingPullOneActive(t *testing.T) { + // Only one call to Pull can be active at a time. + client, srv := newMock(t) + defer client.Close() + defer srv.srv.Close() + srv.addStreamingPullMessages(testMessages[:1]) + sub := client.Subscription("S") + ctx, cancel := context.WithCancel(context.Background()) + err := sub.Receive(ctx, func(ctx context.Context, m *Message) { + m.Ack() + err := sub.Receive(ctx, func(context.Context, *Message) {}) + if err != errReceiveInProgress { + t.Errorf("got <%v>, want <%v>", err, errReceiveInProgress) + } + cancel() + }) + if err != nil { + t.Fatalf("got <%v>, want nil", err) + } +} + +func TestStreamingPullConcurrent(t *testing.T) { + newMsg := func(i int) *pb.ReceivedMessage { + return &pb.ReceivedMessage{ + AckId: strconv.Itoa(i), + Message: &pb.PubsubMessage{Data: []byte{byte(i)}, PublishTime: timestamp}, + } + } + + // Multiple goroutines should be able to read from the same iterator. + client, server := newMock(t) + defer server.srv.Close() + defer client.Close() + // Add a lot of messages, a few at a time, to make sure both threads get a chance. + nMessages := 100 + for i := 0; i < nMessages; i += 2 { + server.addStreamingPullMessages([]*pb.ReceivedMessage{newMsg(i), newMsg(i + 1)}) + } + sub := client.Subscription("S") + ctx, _ := context.WithTimeout(context.Background(), time.Second) + gotMsgs, err := pullN(ctx, sub, nMessages, func(ctx context.Context, m *Message) { + m.Ack() + }) + if c := status.Convert(err); err != nil && c.Code() != codes.Canceled { + t.Fatalf("Pull: %v", err) + } + seen := map[string]bool{} + for _, gm := range gotMsgs { + if seen[gm.ackID] { + t.Fatalf("duplicate ID %q", gm.ackID) + } + seen[gm.ackID] = true + } + if len(seen) != nMessages { + t.Fatalf("got %d messages, want %d", len(seen), nMessages) + } +} + +func TestStreamingPullFlowControl(t *testing.T) { + // Callback invocations should not occur if flow control limits are exceeded. + client, server := newMock(t) + defer server.srv.Close() + defer client.Close() + server.addStreamingPullMessages(testMessages) + sub := client.Subscription("S") + sub.ReceiveSettings.MaxOutstandingMessages = 2 + ctx, cancel := context.WithCancel(context.Background()) + activec := make(chan int) + waitc := make(chan int) + errc := make(chan error) + go func() { + errc <- sub.Receive(ctx, func(_ context.Context, m *Message) { + activec <- 1 + <-waitc + m.Ack() + }) + }() + // Here, two callbacks are active. Receive should be blocked in the flow + // control acquire method on the third message. + <-activec + <-activec + select { + case <-activec: + t.Fatal("third callback in progress") + case <-time.After(100 * time.Millisecond): + } + cancel() + // Receive still has not returned, because both callbacks are still blocked on waitc. + select { + case err := <-errc: + t.Fatalf("Receive returned early with error %v", err) + case <-time.After(100 * time.Millisecond): + } + // Let both callbacks proceed. + waitc <- 1 + waitc <- 1 + // The third callback will never run, because acquire returned a non-nil + // error, causing Receive to return. So now Receive should end. + if err := <-errc; err != nil { + t.Fatalf("got %v from Receive, want nil", err) + } +} + +func TestStreamingPull_ClosedClient(t *testing.T) { + ctx := context.Background() + client, server := newMock(t) + defer server.srv.Close() + defer client.Close() + server.addStreamingPullMessages(testMessages) + sub := client.Subscription("S") + sub.ReceiveSettings.MaxOutstandingBytes = 1 + recvFinished := make(chan error) + + go func() { + err := sub.Receive(ctx, func(_ context.Context, m *Message) { + m.Ack() + }) + recvFinished <- err + }() + + // wait for receives to happen + time.Sleep(100 * time.Millisecond) + + err := client.Close() + if err != nil { + t.Fatal(err) + } + + // wait for things to close + time.Sleep(100 * time.Millisecond) + + select { + case recvErr := <-recvFinished: + s, ok := status.FromError(recvErr) + if !ok { + t.Fatalf("Expected a gRPC failure, got %v", err) + } + if s.Code() != codes.Canceled { + t.Fatalf("Expected canceled, got %v", s.Code()) + } + case <-time.After(time.Second): + t.Fatal("Receive should have exited immediately after the client was closed, but it did not") + } +} + +func TestStreamingPull_RetriesAfterUnavailable(t *testing.T) { + ctx := context.Background() + client, server := newMock(t) + defer server.srv.Close() + defer client.Close() + + unavail := status.Error(codes.Unavailable, "There is no connection available") + server.addStreamingPullMessages(testMessages) + server.addStreamingPullError(unavail) + server.addAckResponse(unavail) + server.addModAckResponse(unavail) + server.addStreamingPullMessages(testMessages) + server.addStreamingPullError(unavail) + + sub := client.Subscription("S") + sub.ReceiveSettings.MaxOutstandingBytes = 1 + recvErr := make(chan error, 1) + recvdMsgs := make(chan *Message, len(testMessages)*2) + + go func() { + recvErr <- sub.Receive(ctx, func(_ context.Context, m *Message) { + m.Ack() + recvdMsgs <- m + }) + }() + + // wait for receive to happen + var n int + for { + select { + case <-time.After(10 * time.Second): + t.Fatalf("timed out waiting for all message to arrive. got %d messages total", n) + case err := <-recvErr: + t.Fatal(err) + case <-recvdMsgs: + n++ + if n == len(testMessages)*2 { + return + } + } + } +} + +func TestStreamingPull_ReconnectsAfterServerDies(t *testing.T) { + ctx := context.Background() + client, server := newMock(t) + defer server.srv.Close() + defer client.Close() + server.addStreamingPullMessages(testMessages) + sub := client.Subscription("S") + sub.ReceiveSettings.MaxOutstandingBytes = 1 + recvErr := make(chan error, 1) + recvdMsgs := make(chan interface{}, len(testMessages)*2) + + go func() { + recvErr <- sub.Receive(ctx, func(_ context.Context, m *Message) { + m.Ack() + recvdMsgs <- struct{}{} + }) + }() + + // wait for receive to happen + var n int + for { + select { + case <-time.After(5 * time.Second): + t.Fatalf("timed out waiting for all message to arrive. got %d messages total", n) + case err := <-recvErr: + t.Fatal(err) + case <-recvdMsgs: + n++ + if n == len(testMessages) { + // Restart the server + server.srv.Close() + server2, err := newMockServer(server.srv.Port) + if err != nil { + t.Fatal(err) + } + defer server2.srv.Close() + server2.addStreamingPullMessages(testMessages) + } + + if n == len(testMessages)*2 { + return + } + } + } +} + +func newMock(t *testing.T) (*Client, *mockServer) { + srv, err := newMockServer(0) + if err != nil { + t.Fatal(err) + } + conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure()) + if err != nil { + t.Fatal(err) + } + client, err := NewClient(context.Background(), "P", option.WithGRPCConn(conn)) + if err != nil { + t.Fatal(err) + } + return client, srv +} + +// pullN calls sub.Receive until at least n messages are received. +func pullN(ctx context.Context, sub *Subscription, n int, f func(context.Context, *Message)) ([]*Message, error) { + var ( + mu sync.Mutex + msgs []*Message + ) + cctx, cancel := context.WithCancel(ctx) + err := sub.Receive(cctx, func(ctx context.Context, m *Message) { + mu.Lock() + msgs = append(msgs, m) + nSeen := len(msgs) + mu.Unlock() + f(ctx, m) + if nSeen >= n { + cancel() + } + }) + if err != nil { + return msgs, err + } + return msgs, nil +} diff --git a/vendor/cloud.google.com/go/pubsub/subscription.go b/vendor/cloud.google.com/go/pubsub/subscription.go new file mode 100644 index 00000000..09f9dbc4 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/subscription.go @@ -0,0 +1,587 @@ +// Copyright 2016 Google LLC +// +// 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 pubsub + +import ( + "context" + "errors" + "fmt" + "io" + "strings" + "sync" + "time" + + "cloud.google.com/go/iam" + "cloud.google.com/go/internal/optional" + "github.com/golang/protobuf/ptypes" + durpb "github.com/golang/protobuf/ptypes/duration" + gax "github.com/googleapis/gax-go" + "golang.org/x/sync/errgroup" + pb "google.golang.org/genproto/googleapis/pubsub/v1" + fmpb "google.golang.org/genproto/protobuf/field_mask" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" +) + +// Subscription is a reference to a PubSub subscription. +type Subscription struct { + c *Client + + // The fully qualified identifier for the subscription, in the format "projects//subscriptions/" + name string + + // Settings for pulling messages. Configure these before calling Receive. + ReceiveSettings ReceiveSettings + + mu sync.Mutex + receiveActive bool +} + +// Subscription creates a reference to a subscription. +func (c *Client) Subscription(id string) *Subscription { + return c.SubscriptionInProject(id, c.projectID) +} + +// SubscriptionInProject creates a reference to a subscription in a given project. +func (c *Client) SubscriptionInProject(id, projectID string) *Subscription { + return &Subscription{ + c: c, + name: fmt.Sprintf("projects/%s/subscriptions/%s", projectID, id), + } +} + +// String returns the globally unique printable name of the subscription. +func (s *Subscription) String() string { + return s.name +} + +// ID returns the unique identifier of the subscription within its project. +func (s *Subscription) ID() string { + slash := strings.LastIndex(s.name, "/") + if slash == -1 { + // name is not a fully-qualified name. + panic("bad subscription name") + } + return s.name[slash+1:] +} + +// Subscriptions returns an iterator which returns all of the subscriptions for the client's project. +func (c *Client) Subscriptions(ctx context.Context) *SubscriptionIterator { + it := c.subc.ListSubscriptions(ctx, &pb.ListSubscriptionsRequest{ + Project: c.fullyQualifiedProjectName(), + }) + return &SubscriptionIterator{ + c: c, + next: func() (string, error) { + sub, err := it.Next() + if err != nil { + return "", err + } + return sub.Name, nil + }, + } +} + +// SubscriptionIterator is an iterator that returns a series of subscriptions. +type SubscriptionIterator struct { + c *Client + next func() (string, error) +} + +// Next returns the next subscription. If there are no more subscriptions, iterator.Done will be returned. +func (subs *SubscriptionIterator) Next() (*Subscription, error) { + subName, err := subs.next() + if err != nil { + return nil, err + } + return &Subscription{c: subs.c, name: subName}, nil +} + +// PushConfig contains configuration for subscriptions that operate in push mode. +type PushConfig struct { + // A URL locating the endpoint to which messages should be pushed. + Endpoint string + + // Endpoint configuration attributes. See https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions#pushconfig for more details. + Attributes map[string]string +} + +func (pc *PushConfig) toProto() *pb.PushConfig { + return &pb.PushConfig{ + Attributes: pc.Attributes, + PushEndpoint: pc.Endpoint, + } +} + +// SubscriptionConfig describes the configuration of a subscription. +type SubscriptionConfig struct { + Topic *Topic + PushConfig PushConfig + + // The default maximum time after a subscriber receives a message before + // the subscriber should acknowledge the message. Note: messages which are + // obtained via Subscription.Receive need not be acknowledged within this + // deadline, as the deadline will be automatically extended. + AckDeadline time.Duration + + // Whether to retain acknowledged messages. If true, acknowledged messages + // will not be expunged until they fall out of the RetentionDuration window. + RetainAckedMessages bool + + // How long to retain messages in backlog, from the time of publish. If + // RetainAckedMessages is true, this duration affects the retention of + // acknowledged messages, otherwise only unacknowledged messages are retained. + // Defaults to 7 days. Cannot be longer than 7 days or shorter than 10 minutes. + RetentionDuration time.Duration + + // The set of labels for the subscription. + Labels map[string]string +} + +func (cfg *SubscriptionConfig) toProto(name string) *pb.Subscription { + var pbPushConfig *pb.PushConfig + if cfg.PushConfig.Endpoint != "" || len(cfg.PushConfig.Attributes) != 0 { + pbPushConfig = &pb.PushConfig{ + Attributes: cfg.PushConfig.Attributes, + PushEndpoint: cfg.PushConfig.Endpoint, + } + } + var retentionDuration *durpb.Duration + if cfg.RetentionDuration != 0 { + retentionDuration = ptypes.DurationProto(cfg.RetentionDuration) + } + return &pb.Subscription{ + Name: name, + Topic: cfg.Topic.name, + PushConfig: pbPushConfig, + AckDeadlineSeconds: trunc32(int64(cfg.AckDeadline.Seconds())), + RetainAckedMessages: cfg.RetainAckedMessages, + MessageRetentionDuration: retentionDuration, + Labels: cfg.Labels, + } +} + +func protoToSubscriptionConfig(pbSub *pb.Subscription, c *Client) (SubscriptionConfig, error) { + rd := time.Hour * 24 * 7 + var err error + if pbSub.MessageRetentionDuration != nil { + rd, err = ptypes.Duration(pbSub.MessageRetentionDuration) + if err != nil { + return SubscriptionConfig{}, err + } + } + return SubscriptionConfig{ + Topic: newTopic(c, pbSub.Topic), + AckDeadline: time.Second * time.Duration(pbSub.AckDeadlineSeconds), + PushConfig: PushConfig{ + Endpoint: pbSub.PushConfig.PushEndpoint, + Attributes: pbSub.PushConfig.Attributes, + }, + RetainAckedMessages: pbSub.RetainAckedMessages, + RetentionDuration: rd, + Labels: pbSub.Labels, + }, nil +} + +// ReceiveSettings configure the Receive method. +// A zero ReceiveSettings will result in values equivalent to DefaultReceiveSettings. +type ReceiveSettings struct { + // MaxExtension is the maximum period for which the Subscription should + // automatically extend the ack deadline for each message. + // + // The Subscription will automatically extend the ack deadline of all + // fetched Messages up to the duration specified. Automatic deadline + // extension beyond the initial receipt may be disabled by specifying a + // duration less than 0. + MaxExtension time.Duration + + // MaxOutstandingMessages is the maximum number of unprocessed messages + // (unacknowledged but not yet expired). If MaxOutstandingMessages is 0, it + // will be treated as if it were DefaultReceiveSettings.MaxOutstandingMessages. + // If the value is negative, then there will be no limit on the number of + // unprocessed messages. + MaxOutstandingMessages int + + // MaxOutstandingBytes is the maximum size of unprocessed messages + // (unacknowledged but not yet expired). If MaxOutstandingBytes is 0, it will + // be treated as if it were DefaultReceiveSettings.MaxOutstandingBytes. If + // the value is negative, then there will be no limit on the number of bytes + // for unprocessed messages. + MaxOutstandingBytes int + + // NumGoroutines is the number of goroutines Receive will spawn to pull + // messages concurrently. If NumGoroutines is less than 1, it will be treated + // as if it were DefaultReceiveSettings.NumGoroutines. + // + // NumGoroutines does not limit the number of messages that can be processed + // concurrently. Even with one goroutine, many messages might be processed at + // once, because that goroutine may continually receive messages and invoke the + // function passed to Receive on them. To limit the number of messages being + // processed concurrently, set MaxOutstandingMessages. + NumGoroutines int + + // If Synchronous is true, then no more than MaxOutstandingMessages will be in + // memory at one time. (In contrast, when Synchronous is false, more than + // MaxOutstandingMessages may have been received from the service and in memory + // before being processed.) MaxOutstandingBytes still refers to the total bytes + // processed, rather than in memory. NumGoroutines is ignored. + // The default is false. + Synchronous bool +} + +// For synchronous receive, the time to wait if we are already processing +// MaxOutstandingMessages. There is no point calling Pull and asking for zero +// messages, so we pause to allow some message-processing callbacks to finish. +// +// The wait time is large enough to avoid consuming significant CPU, but +// small enough to provide decent throughput. Users who want better +// throughput should not be using synchronous mode. +// +// Waiting might seem like polling, so it's natural to think we could do better by +// noticing when a callback is finished and immediately calling Pull. But if +// callbacks finish in quick succession, this will result in frequent Pull RPCs that +// request a single message, which wastes network bandwidth. Better to wait for a few +// callbacks to finish, so we make fewer RPCs fetching more messages. +// +// This value is unexported so the user doesn't have another knob to think about. Note that +// it is the same value as the one used for nackTicker, so it matches this client's +// idea of a duration that is short, but not so short that we perform excessive RPCs. +const synchronousWaitTime = 100 * time.Millisecond + +// This is a var so that tests can change it. +var minAckDeadline = 10 * time.Second + +// DefaultReceiveSettings holds the default values for ReceiveSettings. +var DefaultReceiveSettings = ReceiveSettings{ + MaxExtension: 10 * time.Minute, + MaxOutstandingMessages: 1000, + MaxOutstandingBytes: 1e9, // 1G + NumGoroutines: 1, +} + +// Delete deletes the subscription. +func (s *Subscription) Delete(ctx context.Context) error { + return s.c.subc.DeleteSubscription(ctx, &pb.DeleteSubscriptionRequest{Subscription: s.name}) +} + +// Exists reports whether the subscription exists on the server. +func (s *Subscription) Exists(ctx context.Context) (bool, error) { + _, err := s.c.subc.GetSubscription(ctx, &pb.GetSubscriptionRequest{Subscription: s.name}) + if err == nil { + return true, nil + } + if grpc.Code(err) == codes.NotFound { + return false, nil + } + return false, err +} + +// Config fetches the current configuration for the subscription. +func (s *Subscription) Config(ctx context.Context) (SubscriptionConfig, error) { + pbSub, err := s.c.subc.GetSubscription(ctx, &pb.GetSubscriptionRequest{Subscription: s.name}) + if err != nil { + return SubscriptionConfig{}, err + } + cfg, err := protoToSubscriptionConfig(pbSub, s.c) + if err != nil { + return SubscriptionConfig{}, err + } + return cfg, nil +} + +// SubscriptionConfigToUpdate describes how to update a subscription. +type SubscriptionConfigToUpdate struct { + // If non-nil, the push config is changed. + PushConfig *PushConfig + + // If non-zero, the ack deadline is changed. + AckDeadline time.Duration + + // If set, RetainAckedMessages is changed. + RetainAckedMessages optional.Bool + + // If non-zero, RetentionDuration is changed. + RetentionDuration time.Duration + + // If non-nil, the current set of labels is completely + // replaced by the new set. + // This field has beta status. It is not subject to the stability guarantee + // and may change. + Labels map[string]string +} + +// Update changes an existing subscription according to the fields set in cfg. +// It returns the new SubscriptionConfig. +// +// Update returns an error if no fields were modified. +func (s *Subscription) Update(ctx context.Context, cfg SubscriptionConfigToUpdate) (SubscriptionConfig, error) { + req := s.updateRequest(&cfg) + if len(req.UpdateMask.Paths) == 0 { + return SubscriptionConfig{}, errors.New("pubsub: UpdateSubscription call with nothing to update") + } + rpsub, err := s.c.subc.UpdateSubscription(ctx, req) + if err != nil { + return SubscriptionConfig{}, err + } + return protoToSubscriptionConfig(rpsub, s.c) +} + +func (s *Subscription) updateRequest(cfg *SubscriptionConfigToUpdate) *pb.UpdateSubscriptionRequest { + psub := &pb.Subscription{Name: s.name} + var paths []string + if cfg.PushConfig != nil { + psub.PushConfig = cfg.PushConfig.toProto() + paths = append(paths, "push_config") + } + if cfg.AckDeadline != 0 { + psub.AckDeadlineSeconds = trunc32(int64(cfg.AckDeadline.Seconds())) + paths = append(paths, "ack_deadline_seconds") + } + if cfg.RetainAckedMessages != nil { + psub.RetainAckedMessages = optional.ToBool(cfg.RetainAckedMessages) + paths = append(paths, "retain_acked_messages") + } + if cfg.RetentionDuration != 0 { + psub.MessageRetentionDuration = ptypes.DurationProto(cfg.RetentionDuration) + paths = append(paths, "message_retention_duration") + } + if cfg.Labels != nil { + psub.Labels = cfg.Labels + paths = append(paths, "labels") + } + return &pb.UpdateSubscriptionRequest{ + Subscription: psub, + UpdateMask: &fmpb.FieldMask{Paths: paths}, + } +} + +// IAM returns the subscription's IAM handle. +func (s *Subscription) IAM() *iam.Handle { + return iam.InternalNewHandle(s.c.subc.Connection(), s.name) +} + +// CreateSubscription creates a new subscription on a topic. +// +// id is the name of the subscription to create. It must start with a letter, +// and contain only letters ([A-Za-z]), numbers ([0-9]), dashes (-), +// underscores (_), periods (.), tildes (~), plus (+) or percent signs (%). It +// must be between 3 and 255 characters in length, and must not start with +// "goog". +// +// cfg.Topic is the topic from which the subscription should receive messages. It +// need not belong to the same project as the subscription. This field is required. +// +// cfg.AckDeadline is the maximum time after a subscriber receives a message before +// the subscriber should acknowledge the message. It must be between 10 and 600 +// seconds (inclusive), and is rounded down to the nearest second. If the +// provided ackDeadline is 0, then the default value of 10 seconds is used. +// Note: messages which are obtained via Subscription.Receive need not be +// acknowledged within this deadline, as the deadline will be automatically +// extended. +// +// cfg.PushConfig may be set to configure this subscription for push delivery. +// +// If the subscription already exists an error will be returned. +func (c *Client) CreateSubscription(ctx context.Context, id string, cfg SubscriptionConfig) (*Subscription, error) { + if cfg.Topic == nil { + return nil, errors.New("pubsub: require non-nil Topic") + } + if cfg.AckDeadline == 0 { + cfg.AckDeadline = 10 * time.Second + } + if d := cfg.AckDeadline; d < 10*time.Second || d > 600*time.Second { + return nil, fmt.Errorf("ack deadline must be between 10 and 600 seconds; got: %v", d) + } + + sub := c.Subscription(id) + _, err := c.subc.CreateSubscription(ctx, cfg.toProto(sub.name)) + if err != nil { + return nil, err + } + return sub, nil +} + +var errReceiveInProgress = errors.New("pubsub: Receive already in progress for this subscription") + +// Receive calls f with the outstanding messages from the subscription. +// It blocks until ctx is done, or the service returns a non-retryable error. +// +// The standard way to terminate a Receive is to cancel its context: +// +// cctx, cancel := context.WithCancel(ctx) +// err := sub.Receive(cctx, callback) +// // Call cancel from callback, or another goroutine. +// +// If the service returns a non-retryable error, Receive returns that error after +// all of the outstanding calls to f have returned. If ctx is done, Receive +// returns nil after all of the outstanding calls to f have returned and +// all messages have been acknowledged or have expired. +// +// Receive calls f concurrently from multiple goroutines. It is encouraged to +// process messages synchronously in f, even if that processing is relatively +// time-consuming; Receive will spawn new goroutines for incoming messages, +// limited by MaxOutstandingMessages and MaxOutstandingBytes in ReceiveSettings. +// +// The context passed to f will be canceled when ctx is Done or there is a +// fatal service error. +// +// Receive will send an ack deadline extension on message receipt, then +// automatically extend the ack deadline of all fetched Messages up to the +// period specified by s.ReceiveSettings.MaxExtension. +// +// Each Subscription may have only one invocation of Receive active at a time. +func (s *Subscription) Receive(ctx context.Context, f func(context.Context, *Message)) error { + s.mu.Lock() + if s.receiveActive { + s.mu.Unlock() + return errReceiveInProgress + } + s.receiveActive = true + s.mu.Unlock() + defer func() { s.mu.Lock(); s.receiveActive = false; s.mu.Unlock() }() + + maxCount := s.ReceiveSettings.MaxOutstandingMessages + if maxCount == 0 { + maxCount = DefaultReceiveSettings.MaxOutstandingMessages + } + maxBytes := s.ReceiveSettings.MaxOutstandingBytes + if maxBytes == 0 { + maxBytes = DefaultReceiveSettings.MaxOutstandingBytes + } + maxExt := s.ReceiveSettings.MaxExtension + if maxExt == 0 { + maxExt = DefaultReceiveSettings.MaxExtension + } else if maxExt < 0 { + // If MaxExtension is negative, disable automatic extension. + maxExt = 0 + } + var numGoroutines int + switch { + case s.ReceiveSettings.Synchronous: + numGoroutines = 1 + case s.ReceiveSettings.NumGoroutines >= 1: + numGoroutines = s.ReceiveSettings.NumGoroutines + default: + numGoroutines = DefaultReceiveSettings.NumGoroutines + } + // TODO(jba): add tests that verify that ReceiveSettings are correctly processed. + po := &pullOptions{ + maxExtension: maxExt, + maxPrefetch: trunc32(int64(maxCount)), + synchronous: s.ReceiveSettings.Synchronous, + } + fc := newFlowController(maxCount, maxBytes) + + // Wait for all goroutines started by Receive to return, so instead of an + // obscure goroutine leak we have an obvious blocked call to Receive. + group, gctx := errgroup.WithContext(ctx) + for i := 0; i < numGoroutines; i++ { + group.Go(func() error { + return s.receive(gctx, po, fc, f) + }) + } + return group.Wait() +} + +func (s *Subscription) receive(ctx context.Context, po *pullOptions, fc *flowController, f func(context.Context, *Message)) error { + // Cancel a sub-context when we return, to kick the context-aware callbacks + // and the goroutine below. + ctx2, cancel := context.WithCancel(ctx) + // The iterator does not use the context passed to Receive. If it did, canceling + // that context would immediately stop the iterator without waiting for unacked + // messages. + iter := newMessageIterator(s.c.subc, s.name, po) + + // We cannot use errgroup from Receive here. Receive might already be calling group.Wait, + // and group.Wait cannot be called concurrently with group.Go. We give each receive() its + // own WaitGroup instead. + // Since wg.Add is only called from the main goroutine, wg.Wait is guaranteed + // to be called after all Adds. + var wg sync.WaitGroup + wg.Add(1) + go func() { + <-ctx2.Done() + // Call stop when Receive's context is done. + // Stop will block until all outstanding messages have been acknowledged + // or there was a fatal service error. + iter.stop() + wg.Done() + }() + defer wg.Wait() + + defer cancel() + for { + var maxToPull int32 // maximum number of messages to pull + if po.synchronous { + if po.maxPrefetch < 0 { + // If there is no limit on the number of messages to pull, use a reasonable default. + maxToPull = 1000 + } else { + // Limit the number of messages in memory to MaxOutstandingMessages + // (here, po.maxPrefetch). For each message currently in memory, we have + // called fc.acquire but not fc.release: this is fc.count(). The next + // call to Pull should fetch no more than the difference between these + // values. + maxToPull = po.maxPrefetch - int32(fc.count()) + if maxToPull <= 0 { + // Wait for some callbacks to finish. + if err := gax.Sleep(ctx, synchronousWaitTime); err != nil { + // Return nil if the context is done, not err. + return nil + } + continue + } + } + } + msgs, err := iter.receive(maxToPull) + if err == io.EOF { + return nil + } + if err != nil { + return err + } + for i, msg := range msgs { + msg := msg + // TODO(jba): call acquire closer to when the message is allocated. + if err := fc.acquire(ctx, len(msg.Data)); err != nil { + // TODO(jba): test that these "orphaned" messages are nacked immediately when ctx is done. + for _, m := range msgs[i:] { + m.Nack() + } + // Return nil if the context is done, not err. + return nil + } + old := msg.doneFunc + msgLen := len(msg.Data) + msg.doneFunc = func(ackID string, ack bool, receiveTime time.Time) { + defer fc.release(msgLen) + old(ackID, ack, receiveTime) + } + wg.Add(1) + go func() { + defer wg.Done() + f(ctx2, msg) + }() + } + } +} + +type pullOptions struct { + maxExtension time.Duration + maxPrefetch int32 + // If true, use unary Pull instead of StreamingPull, and never pull more + // than maxPrefetch messages. + synchronous bool +} diff --git a/vendor/cloud.google.com/go/pubsub/subscription_test.go b/vendor/cloud.google.com/go/pubsub/subscription_test.go new file mode 100644 index 00000000..4ff5426a --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/subscription_test.go @@ -0,0 +1,245 @@ +// Copyright 2016 Google LLC +// +// 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 pubsub + +import ( + "context" + "fmt" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/pubsub/pstest" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// All returns the remaining subscriptions from this iterator. +func slurpSubs(it *SubscriptionIterator) ([]*Subscription, error) { + var subs []*Subscription + for { + switch sub, err := it.Next(); err { + case nil: + subs = append(subs, sub) + case iterator.Done: + return subs, nil + default: + return nil, err + } + } +} + +func TestSubscriptionID(t *testing.T) { + const id = "id" + c := &Client{projectID: "projid"} + s := c.Subscription(id) + if got, want := s.ID(), id; got != want { + t.Errorf("Subscription.ID() = %q; want %q", got, want) + } +} + +func TestListProjectSubscriptions(t *testing.T) { + ctx := context.Background() + c, srv := newFake(t) + defer c.Close() + defer srv.Close() + + topic := mustCreateTopic(t, c, "t") + var want []string + for i := 1; i <= 2; i++ { + id := fmt.Sprintf("s%d", i) + want = append(want, id) + _, err := c.CreateSubscription(ctx, id, SubscriptionConfig{Topic: topic}) + if err != nil { + t.Fatal(err) + } + } + subs, err := slurpSubs(c.Subscriptions(ctx)) + if err != nil { + t.Fatal(err) + } + + got := getSubIDs(subs) + if !testutil.Equal(got, want) { + t.Errorf("got %v, want %v", got, want) + } +} + +func getSubIDs(subs []*Subscription) []string { + var names []string + for _, sub := range subs { + names = append(names, sub.ID()) + } + return names +} + +func TestListTopicSubscriptions(t *testing.T) { + ctx := context.Background() + c, srv := newFake(t) + defer c.Close() + defer srv.Close() + + topics := []*Topic{ + mustCreateTopic(t, c, "t0"), + mustCreateTopic(t, c, "t1"), + } + wants := make([][]string, 2) + for i := 0; i < 5; i++ { + id := fmt.Sprintf("s%d", i) + sub, err := c.CreateSubscription(ctx, id, SubscriptionConfig{Topic: topics[i%2]}) + if err != nil { + t.Fatal(err) + } + wants[i%2] = append(wants[i%2], sub.ID()) + } + + for i, topic := range topics { + subs, err := slurpSubs(topic.Subscriptions(ctx)) + if err != nil { + t.Fatal(err) + } + got := getSubIDs(subs) + if !testutil.Equal(got, wants[i]) { + t.Errorf("#%d: got %v, want %v", i, got, wants[i]) + } + } +} + +const defaultRetentionDuration = 168 * time.Hour + +func TestUpdateSubscription(t *testing.T) { + ctx := context.Background() + client, srv := newFake(t) + defer client.Close() + defer srv.Close() + + topic := mustCreateTopic(t, client, "t") + sub, err := client.CreateSubscription(ctx, "s", SubscriptionConfig{Topic: topic}) + if err != nil { + t.Fatal(err) + } + cfg, err := sub.Config(ctx) + if err != nil { + t.Fatal(err) + } + want := SubscriptionConfig{ + Topic: topic, + AckDeadline: 10 * time.Second, + RetainAckedMessages: false, + RetentionDuration: defaultRetentionDuration, + } + if !testutil.Equal(cfg, want) { + t.Fatalf("\ngot %+v\nwant %+v", cfg, want) + } + + got, err := sub.Update(ctx, SubscriptionConfigToUpdate{ + AckDeadline: 20 * time.Second, + RetainAckedMessages: true, + Labels: map[string]string{"label": "value"}, + }) + if err != nil { + t.Fatal(err) + } + want = SubscriptionConfig{ + Topic: topic, + AckDeadline: 20 * time.Second, + RetainAckedMessages: true, + RetentionDuration: defaultRetentionDuration, + Labels: map[string]string{"label": "value"}, + } + if !testutil.Equal(got, want) { + t.Fatalf("\ngot %+v\nwant %+v", got, want) + } + + got, err = sub.Update(ctx, SubscriptionConfigToUpdate{ + RetentionDuration: 2 * time.Hour, + Labels: map[string]string{}, + }) + if err != nil { + t.Fatal(err) + } + want.RetentionDuration = 2 * time.Hour + want.Labels = nil + if !testutil.Equal(got, want) { + t.Fatalf("\ngot %+v\nwant %+v", got, want) + } + + _, err = sub.Update(ctx, SubscriptionConfigToUpdate{}) + if err == nil { + t.Fatal("got nil, want error") + } +} + +func TestReceive(t *testing.T) { + testReceive(t, true) + testReceive(t, false) +} + +func testReceive(t *testing.T, synchronous bool) { + ctx := context.Background() + client, srv := newFake(t) + defer client.Close() + defer srv.Close() + + topic := mustCreateTopic(t, client, "t") + sub, err := client.CreateSubscription(ctx, "s", SubscriptionConfig{Topic: topic}) + if err != nil { + t.Fatal(err) + } + for i := 0; i < 256; i++ { + srv.Publish(topic.name, []byte{byte(i)}, nil) + } + sub.ReceiveSettings.Synchronous = synchronous + msgs, err := pullN(ctx, sub, 256, func(_ context.Context, m *Message) { m.Ack() }) + if c := status.Convert(err); err != nil && c.Code() != codes.Canceled { + t.Fatalf("Pull: %v", err) + } + var seen [256]bool + for _, m := range msgs { + seen[m.Data[0]] = true + } + for i, saw := range seen { + if !saw { + t.Errorf("sync=%t: did not see message #%d", synchronous, i) + } + } +} + +func (t1 *Topic) Equal(t2 *Topic) bool { + if t1 == nil && t2 == nil { + return true + } + if t1 == nil || t2 == nil { + return false + } + return t1.c == t2.c && t1.name == t2.name +} + +// Note: be sure to close client and server! +func newFake(t *testing.T) (*Client, *pstest.Server) { + ctx := context.Background() + srv := pstest.NewServer() + client, err := NewClient(ctx, "P", + option.WithEndpoint(srv.Addr), + option.WithoutAuthentication(), + option.WithGRPCDialOption(grpc.WithInsecure())) + if err != nil { + t.Fatal(err) + } + return client, srv +} diff --git a/vendor/cloud.google.com/go/pubsub/timeout_test.go b/vendor/cloud.google.com/go/pubsub/timeout_test.go new file mode 100644 index 00000000..3418011d --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/timeout_test.go @@ -0,0 +1,93 @@ +// Copyright 2018 Google LLC +// +// 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 pubsub + +import ( + "context" + "log" + "sync/atomic" + "testing" + "time" + + "cloud.google.com/go/pubsub/pstest" + "google.golang.org/api/option" + "google.golang.org/grpc" +) + +// Using the fake PubSub server in the pstest package, verify that streaming +// pull resumes if the server stream times out. +func TestStreamTimeout(t *testing.T) { + t.Parallel() + log.SetFlags(log.Lmicroseconds) + ctx := context.Background() + srv := pstest.NewServer() + defer srv.Close() + + srv.SetStreamTimeout(2 * time.Second) + conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure()) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + + client, err := NewClient(ctx, "P", option.WithGRPCConn(conn)) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + topic, err := client.CreateTopic(ctx, "T") + if err != nil { + t.Fatal(err) + } + sub, err := client.CreateSubscription(ctx, "sub", SubscriptionConfig{Topic: topic, AckDeadline: 10 * time.Second}) + if err != nil { + t.Fatal(err) + } + const nPublish = 8 + rctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() + errc := make(chan error) + var nSeen int64 + go func() { + errc <- sub.Receive(rctx, func(ctx context.Context, m *Message) { + m.Ack() + n := atomic.AddInt64(&nSeen, 1) + if n >= nPublish { + cancel() + } + }) + }() + + for i := 0; i < nPublish; i++ { + pr := topic.Publish(ctx, &Message{Data: []byte("msg")}) + _, err := pr.Get(ctx) + if err != nil { + t.Fatal(err) + } + time.Sleep(250 * time.Millisecond) + } + + if err := <-errc; err != nil { + t.Fatal(err) + } + if err := sub.Delete(ctx); err != nil { + t.Fatal(err) + } + n := atomic.LoadInt64(&nSeen) + if n < nPublish { + t.Errorf("got %d messages, want %d", n, nPublish) + } +} diff --git a/vendor/cloud.google.com/go/pubsub/topic.go b/vendor/cloud.google.com/go/pubsub/topic.go new file mode 100644 index 00000000..a9dc97e2 --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/topic.go @@ -0,0 +1,463 @@ +// Copyright 2016 Google LLC +// +// 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 pubsub + +import ( + "context" + "errors" + "fmt" + "runtime" + "strings" + "sync" + "time" + + "cloud.google.com/go/iam" + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/support/bundler" + pb "google.golang.org/genproto/googleapis/pubsub/v1" + fmpb "google.golang.org/genproto/protobuf/field_mask" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" +) + +const ( + // MaxPublishRequestCount is the maximum number of messages that can be in a single publish request, as + // defined by the PubSub service. + MaxPublishRequestCount = 1000 + + // MaxPublishRequestBytes is the maximum size of a single publish request in bytes, as defined by the PubSub + // service. + MaxPublishRequestBytes = 1e7 + + maxInt = int(^uint(0) >> 1) +) + +// ErrOversizedMessage indicates that a message's size exceeds MaxPublishRequestBytes. +var ErrOversizedMessage = bundler.ErrOversizedItem + +// Topic is a reference to a PubSub topic. +// +// The methods of Topic are safe for use by multiple goroutines. +type Topic struct { + c *Client + // The fully qualified identifier for the topic, in the format "projects//topics/" + name string + + // Settings for publishing messages. All changes must be made before the + // first call to Publish. The default is DefaultPublishSettings. + PublishSettings PublishSettings + + mu sync.RWMutex + stopped bool + bundler *bundler.Bundler + + wg sync.WaitGroup +} + +// PublishSettings control the bundling of published messages. +type PublishSettings struct { + + // Publish a non-empty batch after this delay has passed. + DelayThreshold time.Duration + + // Publish a batch when it has this many messages. The maximum is + // MaxPublishRequestCount. + CountThreshold int + + // Publish a batch when its size in bytes reaches this value. + ByteThreshold int + + // The number of goroutines that invoke the Publish RPC concurrently. + // Defaults to a multiple of GOMAXPROCS. + NumGoroutines int + + // The maximum time that the client will attempt to publish a bundle of messages. + Timeout time.Duration +} + +// DefaultPublishSettings holds the default values for topics' PublishSettings. +var DefaultPublishSettings = PublishSettings{ + DelayThreshold: 1 * time.Millisecond, + CountThreshold: 100, + ByteThreshold: 1e6, + Timeout: 60 * time.Second, +} + +// CreateTopic creates a new topic. +// The specified topic ID must start with a letter, and contain only letters +// ([A-Za-z]), numbers ([0-9]), dashes (-), underscores (_), periods (.), +// tildes (~), plus (+) or percent signs (%). It must be between 3 and 255 +// characters in length, and must not start with "goog". +// If the topic already exists an error will be returned. +func (c *Client) CreateTopic(ctx context.Context, id string) (*Topic, error) { + t := c.Topic(id) + _, err := c.pubc.CreateTopic(ctx, &pb.Topic{Name: t.name}) + if err != nil { + return nil, err + } + return t, nil +} + +// Topic creates a reference to a topic in the client's project. +// +// If a Topic's Publish method is called, it has background goroutines +// associated with it. Clean them up by calling Topic.Stop. +// +// Avoid creating many Topic instances if you use them to publish. +func (c *Client) Topic(id string) *Topic { + return c.TopicInProject(id, c.projectID) +} + +// TopicInProject creates a reference to a topic in the given project. +// +// If a Topic's Publish method is called, it has background goroutines +// associated with it. Clean them up by calling Topic.Stop. +// +// Avoid creating many Topic instances if you use them to publish. +func (c *Client) TopicInProject(id, projectID string) *Topic { + return newTopic(c, fmt.Sprintf("projects/%s/topics/%s", projectID, id)) +} + +func newTopic(c *Client, name string) *Topic { + return &Topic{ + c: c, + name: name, + PublishSettings: DefaultPublishSettings, + } +} + +// TopicConfig describes the configuration of a topic. +type TopicConfig struct { + // The set of labels for the topic. + Labels map[string]string + // The topic's message storage policy. + MessageStoragePolicy MessageStoragePolicy +} + +// TopicConfigToUpdate describes how to update a topic. +type TopicConfigToUpdate struct { + // If non-nil, the current set of labels is completely + // replaced by the new set. + // This field has beta status. It is not subject to the stability guarantee + // and may change. + Labels map[string]string +} + +func protoToTopicConfig(pbt *pb.Topic) TopicConfig { + return TopicConfig{ + Labels: pbt.Labels, + MessageStoragePolicy: protoToMessageStoragePolicy(pbt.MessageStoragePolicy), + } +} + +// MessageStoragePolicy constrains how messages published to the topic may be stored. It +// is determined when the topic is created based on the policy configured at +// the project level. +type MessageStoragePolicy struct { + // The list of GCP regions where messages that are published to the topic may + // be persisted in storage. Messages published by publishers running in + // non-allowed GCP regions (or running outside of GCP altogether) will be + // routed for storage in one of the allowed regions. An empty list indicates a + // misconfiguration at the project or organization level, which will result in + // all Publish operations failing. + AllowedPersistenceRegions []string +} + +func protoToMessageStoragePolicy(msp *pb.MessageStoragePolicy) MessageStoragePolicy { + if msp == nil { + return MessageStoragePolicy{} + } + return MessageStoragePolicy{AllowedPersistenceRegions: msp.AllowedPersistenceRegions} +} + +// Config returns the TopicConfig for the topic. +func (t *Topic) Config(ctx context.Context) (TopicConfig, error) { + pbt, err := t.c.pubc.GetTopic(ctx, &pb.GetTopicRequest{Topic: t.name}) + if err != nil { + return TopicConfig{}, err + } + return protoToTopicConfig(pbt), nil +} + +// Update changes an existing topic according to the fields set in cfg. It returns +// the new TopicConfig. +// +// Any call to Update (even with an empty TopicConfigToUpdate) will update the +// MessageStoragePolicy for the topic from the organization's settings. +func (t *Topic) Update(ctx context.Context, cfg TopicConfigToUpdate) (TopicConfig, error) { + req := t.updateRequest(cfg) + if len(req.UpdateMask.Paths) == 0 { + return TopicConfig{}, errors.New("pubsub: UpdateTopic call with nothing to update") + } + rpt, err := t.c.pubc.UpdateTopic(ctx, req) + if err != nil { + return TopicConfig{}, err + } + return protoToTopicConfig(rpt), nil +} + +func (t *Topic) updateRequest(cfg TopicConfigToUpdate) *pb.UpdateTopicRequest { + pt := &pb.Topic{Name: t.name} + paths := []string{"message_storage_policy"} // always fetch + if cfg.Labels != nil { + pt.Labels = cfg.Labels + paths = append(paths, "labels") + } + return &pb.UpdateTopicRequest{ + Topic: pt, + UpdateMask: &fmpb.FieldMask{Paths: paths}, + } +} + +// Topics returns an iterator which returns all of the topics for the client's project. +func (c *Client) Topics(ctx context.Context) *TopicIterator { + it := c.pubc.ListTopics(ctx, &pb.ListTopicsRequest{Project: c.fullyQualifiedProjectName()}) + return &TopicIterator{ + c: c, + next: func() (string, error) { + topic, err := it.Next() + if err != nil { + return "", err + } + return topic.Name, nil + }, + } +} + +// TopicIterator is an iterator that returns a series of topics. +type TopicIterator struct { + c *Client + next func() (string, error) +} + +// Next returns the next topic. If there are no more topics, iterator.Done will be returned. +func (tps *TopicIterator) Next() (*Topic, error) { + topicName, err := tps.next() + if err != nil { + return nil, err + } + return newTopic(tps.c, topicName), nil +} + +// ID returns the unique identifier of the topic within its project. +func (t *Topic) ID() string { + slash := strings.LastIndex(t.name, "/") + if slash == -1 { + // name is not a fully-qualified name. + panic("bad topic name") + } + return t.name[slash+1:] +} + +// String returns the printable globally unique name for the topic. +func (t *Topic) String() string { + return t.name +} + +// Delete deletes the topic. +func (t *Topic) Delete(ctx context.Context) error { + return t.c.pubc.DeleteTopic(ctx, &pb.DeleteTopicRequest{Topic: t.name}) +} + +// Exists reports whether the topic exists on the server. +func (t *Topic) Exists(ctx context.Context) (bool, error) { + if t.name == "_deleted-topic_" { + return false, nil + } + _, err := t.c.pubc.GetTopic(ctx, &pb.GetTopicRequest{Topic: t.name}) + if err == nil { + return true, nil + } + if grpc.Code(err) == codes.NotFound { + return false, nil + } + return false, err +} + +// IAM returns the topic's IAM handle. +func (t *Topic) IAM() *iam.Handle { + return iam.InternalNewHandle(t.c.pubc.Connection(), t.name) +} + +// Subscriptions returns an iterator which returns the subscriptions for this topic. +// +// Some of the returned subscriptions may belong to a project other than t. +func (t *Topic) Subscriptions(ctx context.Context) *SubscriptionIterator { + it := t.c.pubc.ListTopicSubscriptions(ctx, &pb.ListTopicSubscriptionsRequest{ + Topic: t.name, + }) + return &SubscriptionIterator{ + c: t.c, + next: it.Next, + } +} + +var errTopicStopped = errors.New("pubsub: Stop has been called for this topic") + +// Publish publishes msg to the topic asynchronously. Messages are batched and +// sent according to the topic's PublishSettings. Publish never blocks. +// +// Publish returns a non-nil PublishResult which will be ready when the +// message has been sent (or has failed to be sent) to the server. +// +// Publish creates goroutines for batching and sending messages. These goroutines +// need to be stopped by calling t.Stop(). Once stopped, future calls to Publish +// will immediately return a PublishResult with an error. +func (t *Topic) Publish(ctx context.Context, msg *Message) *PublishResult { + // TODO(jba): if this turns out to take significant time, try to approximate it. + // Or, convert the messages to protos in Publish, instead of in the service. + msg.size = proto.Size(&pb.PubsubMessage{ + Data: msg.Data, + Attributes: msg.Attributes, + }) + r := &PublishResult{ready: make(chan struct{})} + t.initBundler() + t.mu.RLock() + defer t.mu.RUnlock() + // TODO(aboulhosn) [from bcmills] consider changing the semantics of bundler to perform this logic so we don't have to do it here + if t.stopped { + r.set("", errTopicStopped) + return r + } + + // TODO(jba) [from bcmills] consider using a shared channel per bundle + // (requires Bundler API changes; would reduce allocations) + // The call to Add should never return an error because the bundler's + // BufferedByteLimit is set to maxInt; we do not perform any flow + // control in the client. + err := t.bundler.Add(&bundledMessage{msg, r}, msg.size) + if err != nil { + r.set("", err) + } + return r +} + +// Stop sends all remaining published messages and stop goroutines created for handling +// publishing. Returns once all outstanding messages have been sent or have +// failed to be sent. +func (t *Topic) Stop() { + t.mu.Lock() + noop := t.stopped || t.bundler == nil + t.stopped = true + t.mu.Unlock() + if noop { + return + } + t.bundler.Flush() +} + +// A PublishResult holds the result from a call to Publish. +type PublishResult struct { + ready chan struct{} + serverID string + err error +} + +// Ready returns a channel that is closed when the result is ready. +// When the Ready channel is closed, Get is guaranteed not to block. +func (r *PublishResult) Ready() <-chan struct{} { return r.ready } + +// Get returns the server-generated message ID and/or error result of a Publish call. +// Get blocks until the Publish call completes or the context is done. +func (r *PublishResult) Get(ctx context.Context) (serverID string, err error) { + // If the result is already ready, return it even if the context is done. + select { + case <-r.Ready(): + return r.serverID, r.err + default: + } + select { + case <-ctx.Done(): + return "", ctx.Err() + case <-r.Ready(): + return r.serverID, r.err + } +} + +func (r *PublishResult) set(sid string, err error) { + r.serverID = sid + r.err = err + close(r.ready) +} + +type bundledMessage struct { + msg *Message + res *PublishResult +} + +func (t *Topic) initBundler() { + t.mu.RLock() + noop := t.stopped || t.bundler != nil + t.mu.RUnlock() + if noop { + return + } + t.mu.Lock() + defer t.mu.Unlock() + // Must re-check, since we released the lock. + if t.stopped || t.bundler != nil { + return + } + + timeout := t.PublishSettings.Timeout + t.bundler = bundler.NewBundler(&bundledMessage{}, func(items interface{}) { + // TODO(jba): use a context detached from the one passed to NewClient. + ctx := context.TODO() + if timeout != 0 { + var cancel func() + ctx, cancel = context.WithTimeout(ctx, timeout) + defer cancel() + } + t.publishMessageBundle(ctx, items.([]*bundledMessage)) + }) + t.bundler.DelayThreshold = t.PublishSettings.DelayThreshold + t.bundler.BundleCountThreshold = t.PublishSettings.CountThreshold + if t.bundler.BundleCountThreshold > MaxPublishRequestCount { + t.bundler.BundleCountThreshold = MaxPublishRequestCount + } + t.bundler.BundleByteThreshold = t.PublishSettings.ByteThreshold + t.bundler.BufferedByteLimit = maxInt + t.bundler.BundleByteLimit = MaxPublishRequestBytes + // Unless overridden, allow many goroutines per CPU to call the Publish RPC concurrently. + // The default value was determined via extensive load testing (see the loadtest subdirectory). + if t.PublishSettings.NumGoroutines > 0 { + t.bundler.HandlerLimit = t.PublishSettings.NumGoroutines + } else { + t.bundler.HandlerLimit = 25 * runtime.GOMAXPROCS(0) + } +} + +func (t *Topic) publishMessageBundle(ctx context.Context, bms []*bundledMessage) { + pbMsgs := make([]*pb.PubsubMessage, len(bms)) + for i, bm := range bms { + pbMsgs[i] = &pb.PubsubMessage{ + Data: bm.msg.Data, + Attributes: bm.msg.Attributes, + } + bm.msg = nil // release bm.msg for GC + } + res, err := t.c.pubc.Publish(ctx, &pb.PublishRequest{ + Topic: t.name, + Messages: pbMsgs, + }, gax.WithGRPCOptions(grpc.MaxCallSendMsgSize(maxSendRecvBytes))) + for i, bm := range bms { + if err != nil { + bm.res.set("", err) + } else { + bm.res.set(res.MessageIds[i], nil) + } + } +} diff --git a/vendor/cloud.google.com/go/pubsub/topic_test.go b/vendor/cloud.google.com/go/pubsub/topic_test.go new file mode 100644 index 00000000..d6cd0ecf --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/topic_test.go @@ -0,0 +1,195 @@ +// Copyright 2016 Google LLC +// +// 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 pubsub + +import ( + "context" + "fmt" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + pubsubpb "google.golang.org/genproto/googleapis/pubsub/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func checkTopicListing(t *testing.T, c *Client, want []string) { + topics, err := slurpTopics(c.Topics(context.Background())) + if err != nil { + t.Fatalf("error listing topics: %v", err) + } + var got []string + for _, topic := range topics { + got = append(got, topic.ID()) + } + if !testutil.Equal(got, want) { + t.Errorf("topic list: got: %v, want: %v", got, want) + } +} + +// All returns the remaining topics from this iterator. +func slurpTopics(it *TopicIterator) ([]*Topic, error) { + var topics []*Topic + for { + switch topic, err := it.Next(); err { + case nil: + topics = append(topics, topic) + case iterator.Done: + return topics, nil + default: + return nil, err + } + } +} + +func TestTopicID(t *testing.T) { + const id = "id" + c, srv := newFake(t) + defer c.Close() + defer srv.Close() + + s := c.Topic(id) + if got, want := s.ID(), id; got != want { + t.Errorf("Token.ID() = %q; want %q", got, want) + } +} + +func TestListTopics(t *testing.T) { + c, srv := newFake(t) + defer c.Close() + defer srv.Close() + + var ids []string + for i := 1; i <= 4; i++ { + id := fmt.Sprintf("t%d", i) + ids = append(ids, id) + mustCreateTopic(t, c, id) + } + checkTopicListing(t, c, ids) +} + +func TestListCompletelyEmptyTopics(t *testing.T) { + c, srv := newFake(t) + defer c.Close() + defer srv.Close() + + checkTopicListing(t, c, nil) +} + +func TestStopPublishOrder(t *testing.T) { + // Check that Stop doesn't panic if called before Publish. + // Also that Publish after Stop returns the right error. + ctx := context.Background() + c := &Client{projectID: "projid"} + topic := c.Topic("t") + topic.Stop() + r := topic.Publish(ctx, &Message{}) + _, err := r.Get(ctx) + if err != errTopicStopped { + t.Errorf("got %v, want errTopicStopped", err) + } +} + +func TestPublishTimeout(t *testing.T) { + ctx := context.Background() + serv, err := testutil.NewServer() + if err != nil { + t.Fatal(err) + } + pubsubpb.RegisterPublisherServer(serv.Gsrv, &alwaysFailPublish{}) + conn, err := grpc.Dial(serv.Addr, grpc.WithInsecure()) + if err != nil { + t.Fatal(err) + } + c, err := NewClient(ctx, "projectID", option.WithGRPCConn(conn)) + if err != nil { + t.Fatal(err) + } + topic := c.Topic("t") + topic.PublishSettings.Timeout = 3 * time.Second + r := topic.Publish(ctx, &Message{}) + defer topic.Stop() + select { + case <-r.Ready(): + _, err = r.Get(ctx) + if err != context.DeadlineExceeded { + t.Fatalf("got %v, want context.DeadlineExceeded", err) + } + case <-time.After(2 * topic.PublishSettings.Timeout): + t.Fatal("timed out") + } +} + +func TestUpdateTopic(t *testing.T) { + ctx := context.Background() + client, srv := newFake(t) + defer client.Close() + defer srv.Close() + + topic := mustCreateTopic(t, client, "T") + config, err := topic.Config(ctx) + if err != nil { + t.Fatal(err) + } + want := TopicConfig{} + if !testutil.Equal(config, want) { + t.Errorf("got %+v, want %+v", config, want) + } + + // replace labels + labels := map[string]string{"label": "value"} + config2, err := topic.Update(ctx, TopicConfigToUpdate{Labels: labels}) + if err != nil { + t.Fatal(err) + } + want = TopicConfig{ + Labels: labels, + MessageStoragePolicy: MessageStoragePolicy{[]string{"US"}}, + } + if !testutil.Equal(config2, want) { + t.Errorf("got %+v, want %+v", config2, want) + } + + // delete all labels + labels = map[string]string{} + config3, err := topic.Update(ctx, TopicConfigToUpdate{Labels: labels}) + if err != nil { + t.Fatal(err) + } + want.Labels = nil + if !testutil.Equal(config3, want) { + t.Errorf("got %+v, want %+v", config3, want) + } +} + +type alwaysFailPublish struct { + pubsubpb.PublisherServer +} + +func (s *alwaysFailPublish) Publish(ctx context.Context, req *pubsubpb.PublishRequest) (*pubsubpb.PublishResponse, error) { + return nil, status.Errorf(codes.Unavailable, "try again") +} + +func mustCreateTopic(t *testing.T, c *Client, id string) *Topic { + topic, err := c.CreateTopic(context.Background(), id) + if err != nil { + t.Fatal(err) + } + return topic +} diff --git a/vendor/cloud.google.com/go/pubsub/trace.go b/vendor/cloud.google.com/go/pubsub/trace.go new file mode 100644 index 00000000..06965c2a --- /dev/null +++ b/vendor/cloud.google.com/go/pubsub/trace.go @@ -0,0 +1,157 @@ +// Copyright 2018 Google LLC +// +// 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 pubsub + +import ( + "context" + "log" + "sync" + + "go.opencensus.io/plugin/ocgrpc" + "go.opencensus.io/stats" + "go.opencensus.io/stats/view" + "go.opencensus.io/tag" + "google.golang.org/api/option" + "google.golang.org/grpc" +) + +func openCensusOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithGRPCDialOption(grpc.WithStatsHandler(&ocgrpc.ClientHandler{})), + } +} + +var subscriptionKey tag.Key + +func init() { + var err error + if subscriptionKey, err = tag.NewKey("subscription"); err != nil { + log.Fatal("cannot create 'subscription' key") + } +} + +const statsPrefix = "cloud.google.com/go/pubsub/" + +var ( + // PullCount is a measure of the number of messages pulled. + // It is EXPERIMENTAL and subject to change or removal without notice. + PullCount = stats.Int64(statsPrefix+"pull_count", "Number of PubSub messages pulled", stats.UnitDimensionless) + + // AckCount is a measure of the number of messages acked. + // It is EXPERIMENTAL and subject to change or removal without notice. + AckCount = stats.Int64(statsPrefix+"ack_count", "Number of PubSub messages acked", stats.UnitDimensionless) + + // NackCount is a measure of the number of messages nacked. + // It is EXPERIMENTAL and subject to change or removal without notice. + NackCount = stats.Int64(statsPrefix+"nack_count", "Number of PubSub messages nacked", stats.UnitDimensionless) + + // ModAckCount is a measure of the number of messages whose ack-deadline was modified. + // It is EXPERIMENTAL and subject to change or removal without notice. + ModAckCount = stats.Int64(statsPrefix+"mod_ack_count", "Number of ack-deadlines modified", stats.UnitDimensionless) + + // ModAckTimeoutCount is a measure of the number ModifyAckDeadline RPCs that timed out. + // It is EXPERIMENTAL and subject to change or removal without notice. + ModAckTimeoutCount = stats.Int64(statsPrefix+"mod_ack_timeout_count", "Number of ModifyAckDeadline RPCs that timed out", stats.UnitDimensionless) + + // StreamOpenCount is a measure of the number of times a streaming-pull stream was opened. + // It is EXPERIMENTAL and subject to change or removal without notice. + StreamOpenCount = stats.Int64(statsPrefix+"stream_open_count", "Number of calls opening a new streaming pull", stats.UnitDimensionless) + + // StreamRetryCount is a measure of the number of times a streaming-pull operation was retried. + // It is EXPERIMENTAL and subject to change or removal without notice. + StreamRetryCount = stats.Int64(statsPrefix+"stream_retry_count", "Number of retries of a stream send or receive", stats.UnitDimensionless) + + // StreamRequestCount is a measure of the number of requests sent on a streaming-pull stream. + // It is EXPERIMENTAL and subject to change or removal without notice. + StreamRequestCount = stats.Int64(statsPrefix+"stream_request_count", "Number gRPC StreamingPull request messages sent", stats.UnitDimensionless) + + // StreamResponseCount is a measure of the number of responses received on a streaming-pull stream. + // It is EXPERIMENTAL and subject to change or removal without notice. + StreamResponseCount = stats.Int64(statsPrefix+"stream_response_count", "Number of gRPC StreamingPull response messages received", stats.UnitDimensionless) + + // PullCountView is a cumulative sum of PullCount. + // It is EXPERIMENTAL and subject to change or removal without notice. + PullCountView *view.View + + // AckCountView is a cumulative sum of AckCount. + // It is EXPERIMENTAL and subject to change or removal without notice. + AckCountView *view.View + + // NackCountView is a cumulative sum of NackCount. + // It is EXPERIMENTAL and subject to change or removal without notice. + NackCountView *view.View + + // ModAckCountView is a cumulative sum of ModAckCount. + // It is EXPERIMENTAL and subject to change or removal without notice. + ModAckCountView *view.View + + // ModAckTimeoutCountView is a cumulative sum of ModAckTimeoutCount. + // It is EXPERIMENTAL and subject to change or removal without notice. + ModAckTimeoutCountView *view.View + + // StreamOpenCountView is a cumulative sum of StreamOpenCount. + // It is EXPERIMENTAL and subject to change or removal without notice. + StreamOpenCountView *view.View + + // StreamRetryCountView is a cumulative sum of StreamRetryCount. + // It is EXPERIMENTAL and subject to change or removal without notice. + StreamRetryCountView *view.View + + // StreamRequestCountView is a cumulative sum of StreamRequestCount. + // It is EXPERIMENTAL and subject to change or removal without notice. + StreamRequestCountView *view.View + + // StreamResponseCountView is a cumulative sum of StreamResponseCount. + // It is EXPERIMENTAL and subject to change or removal without notice. + StreamResponseCountView *view.View +) + +func init() { + PullCountView = countView(PullCount) + AckCountView = countView(AckCount) + NackCountView = countView(NackCount) + ModAckCountView = countView(ModAckCount) + ModAckTimeoutCountView = countView(ModAckTimeoutCount) + StreamOpenCountView = countView(StreamOpenCount) + StreamRetryCountView = countView(StreamRetryCount) + StreamRequestCountView = countView(StreamRequestCount) + StreamResponseCountView = countView(StreamResponseCount) +} + +func countView(m *stats.Int64Measure) *view.View { + return &view.View{ + Name: m.Name(), + Description: m.Description(), + TagKeys: []tag.Key{subscriptionKey}, + Measure: m, + Aggregation: view.Sum(), + } +} + +var logOnce sync.Once + +func withSubscriptionKey(ctx context.Context, subName string) context.Context { + ctx, err := tag.New(ctx, tag.Upsert(subscriptionKey, subName)) + if err != nil { + logOnce.Do(func() { + log.Printf("pubsub: error creating tag map: %v", err) + }) + } + return ctx +} + +func recordStat(ctx context.Context, m *stats.Int64Measure, n int64) { + stats.Record(ctx, m.M(n)) +} diff --git a/vendor/cloud.google.com/go/redis/apiv1/cloud_redis_client.go b/vendor/cloud.google.com/go/redis/apiv1/cloud_redis_client.go new file mode 100644 index 00000000..e7d421cb --- /dev/null +++ b/vendor/cloud.google.com/go/redis/apiv1/cloud_redis_client.go @@ -0,0 +1,519 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package redis + +import ( + "context" + "math" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + redispb "google.golang.org/genproto/googleapis/cloud/redis/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +// CloudRedisCallOptions contains the retry settings for each method of CloudRedisClient. +type CloudRedisCallOptions struct { + ListInstances []gax.CallOption + GetInstance []gax.CallOption + CreateInstance []gax.CallOption + UpdateInstance []gax.CallOption + DeleteInstance []gax.CallOption +} + +func defaultCloudRedisClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("redis.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCloudRedisCallOptions() *CloudRedisCallOptions { + retry := map[[2]string][]gax.CallOption{} + return &CloudRedisCallOptions{ + ListInstances: retry[[2]string{"default", "non_idempotent"}], + GetInstance: retry[[2]string{"default", "non_idempotent"}], + CreateInstance: retry[[2]string{"default", "non_idempotent"}], + UpdateInstance: retry[[2]string{"default", "non_idempotent"}], + DeleteInstance: retry[[2]string{"default", "non_idempotent"}], + } +} + +// CloudRedisClient is a client for interacting with Google Cloud Memorystore for Redis API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type CloudRedisClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + cloudRedisClient redispb.CloudRedisClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *CloudRedisCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewCloudRedisClient creates a new cloud redis client. +// +// Configures and manages Cloud Memorystore for Redis instances +// +// Google Cloud Memorystore for Redis v1 +// +// The redis.googleapis.com service implements the Google Cloud Memorystore +// for Redis API and defines the following resource model for managing Redis +// instances: +// +// The service works with a collection of cloud projects, named: /projects/* +// +// Each project has a collection of available locations, named: /locations/* +// +// Each location has a collection of Redis instances, named: /instances/* +// +// As such, Redis instances are resources of the form: +// /projects/{project_id}/locations/{location_id}/instances/{instance_id} +// +// Note that location_id must be refering to a GCP region; for example: +// +// projects/redpepper-1290/locations/us-central1/instances/my-redis +func NewCloudRedisClient(ctx context.Context, opts ...option.ClientOption) (*CloudRedisClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultCloudRedisClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &CloudRedisClient{ + conn: conn, + CallOptions: defaultCloudRedisCallOptions(), + + cloudRedisClient: redispb.NewCloudRedisClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *CloudRedisClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *CloudRedisClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *CloudRedisClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListInstances lists all Redis instances owned by a project in either the specified +// location (region) or all locations. +// +// The location should have the following format: +// +// projects/{project_id}/locations/{location_id} +// +// If location_id is specified as - (wildcard), then all regions +// available to the project are queried, and the results are aggregated. +func (c *CloudRedisClient) ListInstances(ctx context.Context, req *redispb.ListInstancesRequest, opts ...gax.CallOption) *InstanceIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListInstances[0:len(c.CallOptions.ListInstances):len(c.CallOptions.ListInstances)], opts...) + it := &InstanceIterator{} + req = proto.Clone(req).(*redispb.ListInstancesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*redispb.Instance, string, error) { + var resp *redispb.ListInstancesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudRedisClient.ListInstances(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Instances, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetInstance gets the details of a specific Redis instance. +func (c *CloudRedisClient) GetInstance(ctx context.Context, req *redispb.GetInstanceRequest, opts ...gax.CallOption) (*redispb.Instance, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetInstance[0:len(c.CallOptions.GetInstance):len(c.CallOptions.GetInstance)], opts...) + var resp *redispb.Instance + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudRedisClient.GetInstance(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateInstance creates a Redis instance based on the specified tier and memory size. +// +// By default, the instance is accessible from the project's +// default network (at /compute/docs/networks-and-firewalls#networks). +// +// The creation is executed asynchronously and callers may check the returned +// operation to track its progress. Once the operation is completed the Redis +// instance will be fully functional. Completed longrunning.Operation will +// contain the new instance object in the response field. +// +// The returned operation is automatically deleted after a few hours, so there +// is no need to call DeleteOperation. +func (c *CloudRedisClient) CreateInstance(ctx context.Context, req *redispb.CreateInstanceRequest, opts ...gax.CallOption) (*CreateInstanceOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateInstance[0:len(c.CallOptions.CreateInstance):len(c.CallOptions.CreateInstance)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudRedisClient.CreateInstance(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &CreateInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// UpdateInstance updates the metadata and configuration of a specific Redis instance. +// +// Completed longrunning.Operation will contain the new instance object +// in the response field. The returned operation is automatically deleted +// after a few hours, so there is no need to call DeleteOperation. +func (c *CloudRedisClient) UpdateInstance(ctx context.Context, req *redispb.UpdateInstanceRequest, opts ...gax.CallOption) (*UpdateInstanceOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateInstance[0:len(c.CallOptions.UpdateInstance):len(c.CallOptions.UpdateInstance)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudRedisClient.UpdateInstance(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &UpdateInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// DeleteInstance deletes a specific Redis instance. Instance stops serving and data is +// deleted. +func (c *CloudRedisClient) DeleteInstance(ctx context.Context, req *redispb.DeleteInstanceRequest, opts ...gax.CallOption) (*DeleteInstanceOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteInstance[0:len(c.CallOptions.DeleteInstance):len(c.CallOptions.DeleteInstance)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudRedisClient.DeleteInstance(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &DeleteInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// InstanceIterator manages a stream of *redispb.Instance. +type InstanceIterator struct { + items []*redispb.Instance + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*redispb.Instance, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InstanceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InstanceIterator) Next() (*redispb.Instance, error) { + var item *redispb.Instance + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InstanceIterator) bufLen() int { + return len(it.items) +} + +func (it *InstanceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// CreateInstanceOperation manages a long-running operation from CreateInstance. +type CreateInstanceOperation struct { + lro *longrunning.Operation +} + +// CreateInstanceOperation returns a new CreateInstanceOperation from a given name. +// The name must be that of a previously created CreateInstanceOperation, possibly from a different process. +func (c *CloudRedisClient) CreateInstanceOperation(name string) *CreateInstanceOperation { + return &CreateInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + var resp redispb.Instance + if err := op.lro.WaitWithInterval(ctx, &resp, 360000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + var resp redispb.Instance + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateInstanceOperation) Metadata() (*redispb.OperationMetadata, error) { + var meta redispb.OperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateInstanceOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *CreateInstanceOperation) Name() string { + return op.lro.Name() +} + +// DeleteInstanceOperation manages a long-running operation from DeleteInstance. +type DeleteInstanceOperation struct { + lro *longrunning.Operation +} + +// DeleteInstanceOperation returns a new DeleteInstanceOperation from a given name. +// The name must be that of a previously created DeleteInstanceOperation, possibly from a different process. +func (c *CloudRedisClient) DeleteInstanceOperation(name string) *DeleteInstanceOperation { + return &DeleteInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *DeleteInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 360000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *DeleteInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *DeleteInstanceOperation) Metadata() (*redispb.OperationMetadata, error) { + var meta redispb.OperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *DeleteInstanceOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *DeleteInstanceOperation) Name() string { + return op.lro.Name() +} + +// UpdateInstanceOperation manages a long-running operation from UpdateInstance. +type UpdateInstanceOperation struct { + lro *longrunning.Operation +} + +// UpdateInstanceOperation returns a new UpdateInstanceOperation from a given name. +// The name must be that of a previously created UpdateInstanceOperation, possibly from a different process. +func (c *CloudRedisClient) UpdateInstanceOperation(name string) *UpdateInstanceOperation { + return &UpdateInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *UpdateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + var resp redispb.Instance + if err := op.lro.WaitWithInterval(ctx, &resp, 360000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *UpdateInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + var resp redispb.Instance + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *UpdateInstanceOperation) Metadata() (*redispb.OperationMetadata, error) { + var meta redispb.OperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *UpdateInstanceOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *UpdateInstanceOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/redis/apiv1/cloud_redis_client_example_test.go b/vendor/cloud.google.com/go/redis/apiv1/cloud_redis_client_example_test.go new file mode 100644 index 00000000..182ea80a --- /dev/null +++ b/vendor/cloud.google.com/go/redis/apiv1/cloud_redis_client_example_test.go @@ -0,0 +1,142 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package redis_test + +import ( + "context" + + redis "cloud.google.com/go/redis/apiv1" + "google.golang.org/api/iterator" + redispb "google.golang.org/genproto/googleapis/cloud/redis/v1" +) + +func ExampleNewCloudRedisClient() { + ctx := context.Background() + c, err := redis.NewCloudRedisClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleCloudRedisClient_ListInstances() { + ctx := context.Background() + c, err := redis.NewCloudRedisClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &redispb.ListInstancesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListInstances(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleCloudRedisClient_GetInstance() { + ctx := context.Background() + c, err := redis.NewCloudRedisClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &redispb.GetInstanceRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetInstance(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleCloudRedisClient_CreateInstance() { + ctx := context.Background() + c, err := redis.NewCloudRedisClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &redispb.CreateInstanceRequest{ + // TODO: Fill request struct fields. + } + op, err := c.CreateInstance(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleCloudRedisClient_UpdateInstance() { + ctx := context.Background() + c, err := redis.NewCloudRedisClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &redispb.UpdateInstanceRequest{ + // TODO: Fill request struct fields. + } + op, err := c.UpdateInstance(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleCloudRedisClient_DeleteInstance() { + ctx := context.Background() + c, err := redis.NewCloudRedisClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &redispb.DeleteInstanceRequest{ + // TODO: Fill request struct fields. + } + op, err := c.DeleteInstance(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} diff --git a/vendor/cloud.google.com/go/redis/apiv1/doc.go b/vendor/cloud.google.com/go/redis/apiv1/doc.go new file mode 100644 index 00000000..641394b6 --- /dev/null +++ b/vendor/cloud.google.com/go/redis/apiv1/doc.go @@ -0,0 +1,90 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package redis is an auto-generated package for the +// Google Cloud Memorystore for Redis API. + +// +// The Google Cloud Memorystore for Redis API is used for creating and +// managing +// Redis instances on the Google Cloud Platform. +package redis // import "cloud.google.com/go/redis/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/redis/apiv1/mock_test.go b/vendor/cloud.google.com/go/redis/apiv1/mock_test.go new file mode 100644 index 00000000..a900e79e --- /dev/null +++ b/vendor/cloud.google.com/go/redis/apiv1/mock_test.go @@ -0,0 +1,641 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package redis + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + redispb "google.golang.org/genproto/googleapis/cloud/redis/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + field_maskpb "google.golang.org/genproto/protobuf/field_mask" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockCloudRedisServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + redispb.CloudRedisServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockCloudRedisServer) ListInstances(ctx context.Context, req *redispb.ListInstancesRequest) (*redispb.ListInstancesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*redispb.ListInstancesResponse), nil +} + +func (s *mockCloudRedisServer) GetInstance(ctx context.Context, req *redispb.GetInstanceRequest) (*redispb.Instance, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*redispb.Instance), nil +} + +func (s *mockCloudRedisServer) CreateInstance(ctx context.Context, req *redispb.CreateInstanceRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockCloudRedisServer) UpdateInstance(ctx context.Context, req *redispb.UpdateInstanceRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockCloudRedisServer) DeleteInstance(ctx context.Context, req *redispb.DeleteInstanceRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockCloudRedis mockCloudRedisServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + redispb.RegisterCloudRedisServer(serv, &mockCloudRedis) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestCloudRedisListInstances(t *testing.T) { + var nextPageToken string = "" + var instancesElement *redispb.Instance = &redispb.Instance{} + var instances = []*redispb.Instance{instancesElement} + var expectedResponse = &redispb.ListInstancesResponse{ + NextPageToken: nextPageToken, + Instances: instances, + } + + mockCloudRedis.err = nil + mockCloudRedis.reqs = nil + + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &redispb.ListInstancesRequest{ + Parent: formattedParent, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListInstances(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudRedis.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Instances[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudRedisListInstancesError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudRedis.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &redispb.ListInstancesRequest{ + Parent: formattedParent, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListInstances(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudRedisGetInstance(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var locationId string = "locationId552319461" + var alternativeLocationId string = "alternativeLocationId-718920621" + var redisVersion string = "redisVersion-685310444" + var reservedIpRange string = "reservedIpRange-1082940580" + var host string = "host3208616" + var port int32 = 3446913 + var currentLocationId string = "currentLocationId1312712735" + var statusMessage string = "statusMessage-239442758" + var memorySizeGb int32 = 34199707 + var authorizedNetwork string = "authorizedNetwork-1733809270" + var expectedResponse = &redispb.Instance{ + Name: name2, + DisplayName: displayName, + LocationId: locationId, + AlternativeLocationId: alternativeLocationId, + RedisVersion: redisVersion, + ReservedIpRange: reservedIpRange, + Host: host, + Port: port, + CurrentLocationId: currentLocationId, + StatusMessage: statusMessage, + MemorySizeGb: memorySizeGb, + AuthorizedNetwork: authorizedNetwork, + } + + mockCloudRedis.err = nil + mockCloudRedis.reqs = nil + + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/instances/%s", "[PROJECT]", "[LOCATION]", "[INSTANCE]") + var request = &redispb.GetInstanceRequest{ + Name: formattedName, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetInstance(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudRedis.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudRedisGetInstanceError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudRedis.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/instances/%s", "[PROJECT]", "[LOCATION]", "[INSTANCE]") + var request = &redispb.GetInstanceRequest{ + Name: formattedName, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetInstance(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudRedisCreateInstance(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var locationId string = "locationId552319461" + var alternativeLocationId string = "alternativeLocationId-718920621" + var redisVersion string = "redisVersion-685310444" + var reservedIpRange string = "reservedIpRange-1082940580" + var host string = "host3208616" + var port int32 = 3446913 + var currentLocationId string = "currentLocationId1312712735" + var statusMessage string = "statusMessage-239442758" + var memorySizeGb2 int32 = 1493816946 + var authorizedNetwork string = "authorizedNetwork-1733809270" + var expectedResponse = &redispb.Instance{ + Name: name, + DisplayName: displayName, + LocationId: locationId, + AlternativeLocationId: alternativeLocationId, + RedisVersion: redisVersion, + ReservedIpRange: reservedIpRange, + Host: host, + Port: port, + CurrentLocationId: currentLocationId, + StatusMessage: statusMessage, + MemorySizeGb: memorySizeGb2, + AuthorizedNetwork: authorizedNetwork, + } + + mockCloudRedis.err = nil + mockCloudRedis.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var instanceId string = "test_instance" + var tier redispb.Instance_Tier = redispb.Instance_BASIC + var memorySizeGb int32 = 1 + var instance = &redispb.Instance{ + Tier: tier, + MemorySizeGb: memorySizeGb, + } + var request = &redispb.CreateInstanceRequest{ + Parent: formattedParent, + InstanceId: instanceId, + Instance: instance, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.CreateInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudRedis.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudRedisCreateInstanceError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudRedis.err = nil + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var instanceId string = "test_instance" + var tier redispb.Instance_Tier = redispb.Instance_BASIC + var memorySizeGb int32 = 1 + var instance = &redispb.Instance{ + Tier: tier, + MemorySizeGb: memorySizeGb, + } + var request = &redispb.CreateInstanceRequest{ + Parent: formattedParent, + InstanceId: instanceId, + Instance: instance, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.CreateInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudRedisUpdateInstance(t *testing.T) { + var name string = "name3373707" + var displayName2 string = "displayName21615000987" + var locationId string = "locationId552319461" + var alternativeLocationId string = "alternativeLocationId-718920621" + var redisVersion string = "redisVersion-685310444" + var reservedIpRange string = "reservedIpRange-1082940580" + var host string = "host3208616" + var port int32 = 3446913 + var currentLocationId string = "currentLocationId1312712735" + var statusMessage string = "statusMessage-239442758" + var memorySizeGb2 int32 = 1493816946 + var authorizedNetwork string = "authorizedNetwork-1733809270" + var expectedResponse = &redispb.Instance{ + Name: name, + DisplayName: displayName2, + LocationId: locationId, + AlternativeLocationId: alternativeLocationId, + RedisVersion: redisVersion, + ReservedIpRange: reservedIpRange, + Host: host, + Port: port, + CurrentLocationId: currentLocationId, + StatusMessage: statusMessage, + MemorySizeGb: memorySizeGb2, + AuthorizedNetwork: authorizedNetwork, + } + + mockCloudRedis.err = nil + mockCloudRedis.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var pathsElement string = "display_name" + var pathsElement2 string = "memory_size_gb" + var paths = []string{pathsElement, pathsElement2} + var updateMask = &field_maskpb.FieldMask{ + Paths: paths, + } + var displayName string = "UpdatedDisplayName" + var memorySizeGb int32 = 4 + var instance = &redispb.Instance{ + DisplayName: displayName, + MemorySizeGb: memorySizeGb, + } + var request = &redispb.UpdateInstanceRequest{ + UpdateMask: updateMask, + Instance: instance, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.UpdateInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudRedis.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudRedisUpdateInstanceError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudRedis.err = nil + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var pathsElement string = "display_name" + var pathsElement2 string = "memory_size_gb" + var paths = []string{pathsElement, pathsElement2} + var updateMask = &field_maskpb.FieldMask{ + Paths: paths, + } + var displayName string = "UpdatedDisplayName" + var memorySizeGb int32 = 4 + var instance = &redispb.Instance{ + DisplayName: displayName, + MemorySizeGb: memorySizeGb, + } + var request = &redispb.UpdateInstanceRequest{ + UpdateMask: updateMask, + Instance: instance, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.UpdateInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudRedisDeleteInstance(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockCloudRedis.err = nil + mockCloudRedis.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/instances/%s", "[PROJECT]", "[LOCATION]", "[INSTANCE]") + var request = &redispb.DeleteInstanceRequest{ + Name: formattedName, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.DeleteInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudRedis.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestCloudRedisDeleteInstanceError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudRedis.err = nil + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/instances/%s", "[PROJECT]", "[LOCATION]", "[INSTANCE]") + var request = &redispb.DeleteInstanceRequest{ + Name: formattedName, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.DeleteInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} diff --git a/vendor/cloud.google.com/go/redis/apiv1beta1/cloud_redis_client.go b/vendor/cloud.google.com/go/redis/apiv1beta1/cloud_redis_client.go new file mode 100644 index 00000000..a3d4ff0f --- /dev/null +++ b/vendor/cloud.google.com/go/redis/apiv1beta1/cloud_redis_client.go @@ -0,0 +1,520 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package redis + +import ( + "context" + "math" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + anypb "github.com/golang/protobuf/ptypes/any" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + redispb "google.golang.org/genproto/googleapis/cloud/redis/v1beta1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +// CloudRedisCallOptions contains the retry settings for each method of CloudRedisClient. +type CloudRedisCallOptions struct { + ListInstances []gax.CallOption + GetInstance []gax.CallOption + CreateInstance []gax.CallOption + UpdateInstance []gax.CallOption + DeleteInstance []gax.CallOption +} + +func defaultCloudRedisClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("redis.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCloudRedisCallOptions() *CloudRedisCallOptions { + retry := map[[2]string][]gax.CallOption{} + return &CloudRedisCallOptions{ + ListInstances: retry[[2]string{"default", "non_idempotent"}], + GetInstance: retry[[2]string{"default", "non_idempotent"}], + CreateInstance: retry[[2]string{"default", "non_idempotent"}], + UpdateInstance: retry[[2]string{"default", "non_idempotent"}], + DeleteInstance: retry[[2]string{"default", "non_idempotent"}], + } +} + +// CloudRedisClient is a client for interacting with Google Cloud Memorystore for Redis API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type CloudRedisClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + cloudRedisClient redispb.CloudRedisClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *CloudRedisCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewCloudRedisClient creates a new cloud redis client. +// +// Configures and manages Cloud Memorystore for Redis instances +// +// Google Cloud Memorystore for Redis v1beta1 +// +// The redis.googleapis.com service implements the Google Cloud Memorystore +// for Redis API and defines the following resource model for managing Redis +// instances: +// +// The service works with a collection of cloud projects, named: /projects/* +// +// Each project has a collection of available locations, named: /locations/* +// +// Each location has a collection of Redis instances, named: /instances/* +// +// As such, Redis instances are resources of the form: +// /projects/{project_id}/locations/{location_id}/instances/{instance_id} +// +// Note that location_id must be refering to a GCP region; for example: +// +// projects/redpepper-1290/locations/us-central1/instances/my-redis +func NewCloudRedisClient(ctx context.Context, opts ...option.ClientOption) (*CloudRedisClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultCloudRedisClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &CloudRedisClient{ + conn: conn, + CallOptions: defaultCloudRedisCallOptions(), + + cloudRedisClient: redispb.NewCloudRedisClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *CloudRedisClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *CloudRedisClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *CloudRedisClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListInstances lists all Redis instances owned by a project in either the specified +// location (region) or all locations. +// +// The location should have the following format: +// +// projects/{project_id}/locations/{location_id} +// +// If location_id is specified as - (wildcard), then all regions +// available to the project are queried, and the results are aggregated. +func (c *CloudRedisClient) ListInstances(ctx context.Context, req *redispb.ListInstancesRequest, opts ...gax.CallOption) *InstanceIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListInstances[0:len(c.CallOptions.ListInstances):len(c.CallOptions.ListInstances)], opts...) + it := &InstanceIterator{} + req = proto.Clone(req).(*redispb.ListInstancesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*redispb.Instance, string, error) { + var resp *redispb.ListInstancesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudRedisClient.ListInstances(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Instances, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetInstance gets the details of a specific Redis instance. +func (c *CloudRedisClient) GetInstance(ctx context.Context, req *redispb.GetInstanceRequest, opts ...gax.CallOption) (*redispb.Instance, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetInstance[0:len(c.CallOptions.GetInstance):len(c.CallOptions.GetInstance)], opts...) + var resp *redispb.Instance + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudRedisClient.GetInstance(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateInstance creates a Redis instance based on the specified tier and memory size. +// +// By default, the instance is peered to the project's +// default network (at /compute/docs/networks-and-firewalls#networks). +// +// The creation is executed asynchronously and callers may check the returned +// operation to track its progress. Once the operation is completed the Redis +// instance will be fully functional. Completed longrunning.Operation will +// contain the new instance object in the response field. +// +// The returned operation is automatically deleted after a few hours, so there +// is no need to call DeleteOperation. +func (c *CloudRedisClient) CreateInstance(ctx context.Context, req *redispb.CreateInstanceRequest, opts ...gax.CallOption) (*CreateInstanceOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateInstance[0:len(c.CallOptions.CreateInstance):len(c.CallOptions.CreateInstance)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudRedisClient.CreateInstance(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &CreateInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// UpdateInstance updates the metadata and configuration of a specific Redis instance. +// +// Completed longrunning.Operation will contain the new instance object +// in the response field. The returned operation is automatically deleted +// after a few hours, so there is no need to call DeleteOperation. +func (c *CloudRedisClient) UpdateInstance(ctx context.Context, req *redispb.UpdateInstanceRequest, opts ...gax.CallOption) (*UpdateInstanceOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateInstance[0:len(c.CallOptions.UpdateInstance):len(c.CallOptions.UpdateInstance)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudRedisClient.UpdateInstance(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &UpdateInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// DeleteInstance deletes a specific Redis instance. Instance stops serving and data is +// deleted. +func (c *CloudRedisClient) DeleteInstance(ctx context.Context, req *redispb.DeleteInstanceRequest, opts ...gax.CallOption) (*DeleteInstanceOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteInstance[0:len(c.CallOptions.DeleteInstance):len(c.CallOptions.DeleteInstance)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudRedisClient.DeleteInstance(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &DeleteInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// InstanceIterator manages a stream of *redispb.Instance. +type InstanceIterator struct { + items []*redispb.Instance + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*redispb.Instance, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InstanceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InstanceIterator) Next() (*redispb.Instance, error) { + var item *redispb.Instance + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InstanceIterator) bufLen() int { + return len(it.items) +} + +func (it *InstanceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// CreateInstanceOperation manages a long-running operation from CreateInstance. +type CreateInstanceOperation struct { + lro *longrunning.Operation +} + +// CreateInstanceOperation returns a new CreateInstanceOperation from a given name. +// The name must be that of a previously created CreateInstanceOperation, possibly from a different process. +func (c *CloudRedisClient) CreateInstanceOperation(name string) *CreateInstanceOperation { + return &CreateInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + var resp redispb.Instance + if err := op.lro.WaitWithInterval(ctx, &resp, 360000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + var resp redispb.Instance + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateInstanceOperation) Metadata() (*anypb.Any, error) { + var meta anypb.Any + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateInstanceOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *CreateInstanceOperation) Name() string { + return op.lro.Name() +} + +// DeleteInstanceOperation manages a long-running operation from DeleteInstance. +type DeleteInstanceOperation struct { + lro *longrunning.Operation +} + +// DeleteInstanceOperation returns a new DeleteInstanceOperation from a given name. +// The name must be that of a previously created DeleteInstanceOperation, possibly from a different process. +func (c *CloudRedisClient) DeleteInstanceOperation(name string) *DeleteInstanceOperation { + return &DeleteInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *DeleteInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 360000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *DeleteInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *DeleteInstanceOperation) Metadata() (*anypb.Any, error) { + var meta anypb.Any + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *DeleteInstanceOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *DeleteInstanceOperation) Name() string { + return op.lro.Name() +} + +// UpdateInstanceOperation manages a long-running operation from UpdateInstance. +type UpdateInstanceOperation struct { + lro *longrunning.Operation +} + +// UpdateInstanceOperation returns a new UpdateInstanceOperation from a given name. +// The name must be that of a previously created UpdateInstanceOperation, possibly from a different process. +func (c *CloudRedisClient) UpdateInstanceOperation(name string) *UpdateInstanceOperation { + return &UpdateInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *UpdateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + var resp redispb.Instance + if err := op.lro.WaitWithInterval(ctx, &resp, 360000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *UpdateInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*redispb.Instance, error) { + var resp redispb.Instance + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *UpdateInstanceOperation) Metadata() (*anypb.Any, error) { + var meta anypb.Any + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *UpdateInstanceOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *UpdateInstanceOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/redis/apiv1beta1/cloud_redis_client_example_test.go b/vendor/cloud.google.com/go/redis/apiv1beta1/cloud_redis_client_example_test.go new file mode 100644 index 00000000..07412677 --- /dev/null +++ b/vendor/cloud.google.com/go/redis/apiv1beta1/cloud_redis_client_example_test.go @@ -0,0 +1,142 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package redis_test + +import ( + "context" + + redis "cloud.google.com/go/redis/apiv1beta1" + "google.golang.org/api/iterator" + redispb "google.golang.org/genproto/googleapis/cloud/redis/v1beta1" +) + +func ExampleNewCloudRedisClient() { + ctx := context.Background() + c, err := redis.NewCloudRedisClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleCloudRedisClient_ListInstances() { + ctx := context.Background() + c, err := redis.NewCloudRedisClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &redispb.ListInstancesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListInstances(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleCloudRedisClient_GetInstance() { + ctx := context.Background() + c, err := redis.NewCloudRedisClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &redispb.GetInstanceRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetInstance(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleCloudRedisClient_CreateInstance() { + ctx := context.Background() + c, err := redis.NewCloudRedisClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &redispb.CreateInstanceRequest{ + // TODO: Fill request struct fields. + } + op, err := c.CreateInstance(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleCloudRedisClient_UpdateInstance() { + ctx := context.Background() + c, err := redis.NewCloudRedisClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &redispb.UpdateInstanceRequest{ + // TODO: Fill request struct fields. + } + op, err := c.UpdateInstance(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleCloudRedisClient_DeleteInstance() { + ctx := context.Background() + c, err := redis.NewCloudRedisClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &redispb.DeleteInstanceRequest{ + // TODO: Fill request struct fields. + } + op, err := c.DeleteInstance(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} diff --git a/vendor/cloud.google.com/go/redis/apiv1beta1/doc.go b/vendor/cloud.google.com/go/redis/apiv1beta1/doc.go new file mode 100644 index 00000000..951cfb5c --- /dev/null +++ b/vendor/cloud.google.com/go/redis/apiv1beta1/doc.go @@ -0,0 +1,91 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package redis is an auto-generated package for the +// Google Cloud Memorystore for Redis API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// The Google Cloud Memorystore for Redis API is used for creating and +// managing +// Redis instances on the Google Cloud Platform. +package redis // import "cloud.google.com/go/redis/apiv1beta1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/redis/apiv1beta1/mock_test.go b/vendor/cloud.google.com/go/redis/apiv1beta1/mock_test.go new file mode 100644 index 00000000..3c93d342 --- /dev/null +++ b/vendor/cloud.google.com/go/redis/apiv1beta1/mock_test.go @@ -0,0 +1,641 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package redis + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + redispb "google.golang.org/genproto/googleapis/cloud/redis/v1beta1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + field_maskpb "google.golang.org/genproto/protobuf/field_mask" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockCloudRedisServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + redispb.CloudRedisServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockCloudRedisServer) ListInstances(ctx context.Context, req *redispb.ListInstancesRequest) (*redispb.ListInstancesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*redispb.ListInstancesResponse), nil +} + +func (s *mockCloudRedisServer) GetInstance(ctx context.Context, req *redispb.GetInstanceRequest) (*redispb.Instance, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*redispb.Instance), nil +} + +func (s *mockCloudRedisServer) CreateInstance(ctx context.Context, req *redispb.CreateInstanceRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockCloudRedisServer) UpdateInstance(ctx context.Context, req *redispb.UpdateInstanceRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockCloudRedisServer) DeleteInstance(ctx context.Context, req *redispb.DeleteInstanceRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockCloudRedis mockCloudRedisServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + redispb.RegisterCloudRedisServer(serv, &mockCloudRedis) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestCloudRedisListInstances(t *testing.T) { + var nextPageToken string = "" + var instancesElement *redispb.Instance = &redispb.Instance{} + var instances = []*redispb.Instance{instancesElement} + var expectedResponse = &redispb.ListInstancesResponse{ + NextPageToken: nextPageToken, + Instances: instances, + } + + mockCloudRedis.err = nil + mockCloudRedis.reqs = nil + + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &redispb.ListInstancesRequest{ + Parent: formattedParent, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListInstances(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudRedis.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Instances[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudRedisListInstancesError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudRedis.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &redispb.ListInstancesRequest{ + Parent: formattedParent, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListInstances(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudRedisGetInstance(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var locationId string = "locationId552319461" + var alternativeLocationId string = "alternativeLocationId-718920621" + var redisVersion string = "redisVersion-685310444" + var reservedIpRange string = "reservedIpRange-1082940580" + var host string = "host3208616" + var port int32 = 3446913 + var currentLocationId string = "currentLocationId1312712735" + var statusMessage string = "statusMessage-239442758" + var memorySizeGb int32 = 34199707 + var authorizedNetwork string = "authorizedNetwork-1733809270" + var expectedResponse = &redispb.Instance{ + Name: name2, + DisplayName: displayName, + LocationId: locationId, + AlternativeLocationId: alternativeLocationId, + RedisVersion: redisVersion, + ReservedIpRange: reservedIpRange, + Host: host, + Port: port, + CurrentLocationId: currentLocationId, + StatusMessage: statusMessage, + MemorySizeGb: memorySizeGb, + AuthorizedNetwork: authorizedNetwork, + } + + mockCloudRedis.err = nil + mockCloudRedis.reqs = nil + + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/instances/%s", "[PROJECT]", "[LOCATION]", "[INSTANCE]") + var request = &redispb.GetInstanceRequest{ + Name: formattedName, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetInstance(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudRedis.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudRedisGetInstanceError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudRedis.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/instances/%s", "[PROJECT]", "[LOCATION]", "[INSTANCE]") + var request = &redispb.GetInstanceRequest{ + Name: formattedName, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetInstance(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudRedisCreateInstance(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var locationId string = "locationId552319461" + var alternativeLocationId string = "alternativeLocationId-718920621" + var redisVersion string = "redisVersion-685310444" + var reservedIpRange string = "reservedIpRange-1082940580" + var host string = "host3208616" + var port int32 = 3446913 + var currentLocationId string = "currentLocationId1312712735" + var statusMessage string = "statusMessage-239442758" + var memorySizeGb2 int32 = 1493816946 + var authorizedNetwork string = "authorizedNetwork-1733809270" + var expectedResponse = &redispb.Instance{ + Name: name, + DisplayName: displayName, + LocationId: locationId, + AlternativeLocationId: alternativeLocationId, + RedisVersion: redisVersion, + ReservedIpRange: reservedIpRange, + Host: host, + Port: port, + CurrentLocationId: currentLocationId, + StatusMessage: statusMessage, + MemorySizeGb: memorySizeGb2, + AuthorizedNetwork: authorizedNetwork, + } + + mockCloudRedis.err = nil + mockCloudRedis.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var instanceId string = "test_instance" + var tier redispb.Instance_Tier = redispb.Instance_BASIC + var memorySizeGb int32 = 1 + var instance = &redispb.Instance{ + Tier: tier, + MemorySizeGb: memorySizeGb, + } + var request = &redispb.CreateInstanceRequest{ + Parent: formattedParent, + InstanceId: instanceId, + Instance: instance, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.CreateInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudRedis.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudRedisCreateInstanceError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudRedis.err = nil + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var instanceId string = "test_instance" + var tier redispb.Instance_Tier = redispb.Instance_BASIC + var memorySizeGb int32 = 1 + var instance = &redispb.Instance{ + Tier: tier, + MemorySizeGb: memorySizeGb, + } + var request = &redispb.CreateInstanceRequest{ + Parent: formattedParent, + InstanceId: instanceId, + Instance: instance, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.CreateInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudRedisUpdateInstance(t *testing.T) { + var name string = "name3373707" + var displayName2 string = "displayName21615000987" + var locationId string = "locationId552319461" + var alternativeLocationId string = "alternativeLocationId-718920621" + var redisVersion string = "redisVersion-685310444" + var reservedIpRange string = "reservedIpRange-1082940580" + var host string = "host3208616" + var port int32 = 3446913 + var currentLocationId string = "currentLocationId1312712735" + var statusMessage string = "statusMessage-239442758" + var memorySizeGb2 int32 = 1493816946 + var authorizedNetwork string = "authorizedNetwork-1733809270" + var expectedResponse = &redispb.Instance{ + Name: name, + DisplayName: displayName2, + LocationId: locationId, + AlternativeLocationId: alternativeLocationId, + RedisVersion: redisVersion, + ReservedIpRange: reservedIpRange, + Host: host, + Port: port, + CurrentLocationId: currentLocationId, + StatusMessage: statusMessage, + MemorySizeGb: memorySizeGb2, + AuthorizedNetwork: authorizedNetwork, + } + + mockCloudRedis.err = nil + mockCloudRedis.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var pathsElement string = "display_name" + var pathsElement2 string = "memory_size_gb" + var paths = []string{pathsElement, pathsElement2} + var updateMask = &field_maskpb.FieldMask{ + Paths: paths, + } + var displayName string = "UpdatedDisplayName" + var memorySizeGb int32 = 4 + var instance = &redispb.Instance{ + DisplayName: displayName, + MemorySizeGb: memorySizeGb, + } + var request = &redispb.UpdateInstanceRequest{ + UpdateMask: updateMask, + Instance: instance, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.UpdateInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudRedis.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudRedisUpdateInstanceError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudRedis.err = nil + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var pathsElement string = "display_name" + var pathsElement2 string = "memory_size_gb" + var paths = []string{pathsElement, pathsElement2} + var updateMask = &field_maskpb.FieldMask{ + Paths: paths, + } + var displayName string = "UpdatedDisplayName" + var memorySizeGb int32 = 4 + var instance = &redispb.Instance{ + DisplayName: displayName, + MemorySizeGb: memorySizeGb, + } + var request = &redispb.UpdateInstanceRequest{ + UpdateMask: updateMask, + Instance: instance, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.UpdateInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudRedisDeleteInstance(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockCloudRedis.err = nil + mockCloudRedis.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/instances/%s", "[PROJECT]", "[LOCATION]", "[INSTANCE]") + var request = &redispb.DeleteInstanceRequest{ + Name: formattedName, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.DeleteInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudRedis.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestCloudRedisDeleteInstanceError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudRedis.err = nil + mockCloudRedis.resps = append(mockCloudRedis.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/instances/%s", "[PROJECT]", "[LOCATION]", "[INSTANCE]") + var request = &redispb.DeleteInstanceRequest{ + Name: formattedName, + } + + c, err := NewCloudRedisClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.DeleteInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} diff --git a/vendor/cloud.google.com/go/regen-gapic.sh b/vendor/cloud.google.com/go/regen-gapic.sh new file mode 100755 index 00000000..252c9be0 --- /dev/null +++ b/vendor/cloud.google.com/go/regen-gapic.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +# This script generates all GAPIC clients in this repo. +# One-time setup: +# cd path/to/googleapis # https://github.com/googleapis/googleapis +# virtualenv env +# . env/bin/activate +# pip install googleapis-artman +# deactivate +# +# Regenerate: +# cd path/to/googleapis +# . env/bin/activate +# $GOPATH/src/cloud.google.com/go/regen-gapic.sh +# deactivate +# +# Being in googleapis directory is important; +# that's where we find YAML files and where artman puts the "artman-genfiles" directory. +# +# NOTE: This script does not generate the "raw" gRPC client found in google.golang.org/genproto. +# To do that, use the regen.sh script in the genproto repo instead. + +set -ex + +APIS=( +google/api/expr/artman_cel.yaml +google/iam/artman_iam_admin.yaml +google/cloud/asset/artman_cloudasset_v1beta1.yaml +google/iam/credentials/artman_iamcredentials_v1.yaml +google/cloud/bigquery/datatransfer/artman_bigquerydatatransfer.yaml +google/cloud/dataproc/artman_dataproc_v1.yaml +google/cloud/dataproc/artman_dataproc_v1beta2.yaml +google/cloud/dialogflow/artman_dialogflow_v2.yaml +google/cloud/kms/artman_cloudkms.yaml +google/cloud/language/artman_language_v1.yaml +google/cloud/language/artman_language_v1beta2.yaml +google/cloud/oslogin/artman_oslogin_v1.yaml +google/cloud/oslogin/artman_oslogin_v1beta.yaml +google/cloud/redis/artman_redis_v1beta1.yaml +google/cloud/redis/artman_redis_v1.yaml +google/cloud/scheduler/artman_cloudscheduler_v1beta1.yaml +google/cloud/securitycenter/artman_securitycenter_v1beta1.yaml +google/cloud/speech/artman_speech_v1.yaml +google/cloud/speech/artman_speech_v1p1beta1.yaml +google/cloud/tasks/artman_cloudtasks_v2beta2.yaml +google/cloud/tasks/artman_cloudtasks_v2beta3.yaml +google/cloud/texttospeech/artman_texttospeech_v1.yaml +google/cloud/videointelligence/artman_videointelligence_v1.yaml +google/cloud/videointelligence/artman_videointelligence_v1beta1.yaml +google/cloud/videointelligence/artman_videointelligence_v1beta2.yaml +google/cloud/vision/artman_vision_v1.yaml +google/cloud/vision/artman_vision_v1p1beta1.yaml +google/devtools/artman_clouddebugger.yaml +google/devtools/clouderrorreporting/artman_errorreporting.yaml +google/devtools/cloudtrace/artman_cloudtrace_v1.yaml +google/devtools/cloudtrace/artman_cloudtrace_v2.yaml +google/devtools/containeranalysis/artman_containeranalysis_v1beta1.yaml +google/firestore/artman_firestore.yaml +google/logging/artman_logging.yaml +google/longrunning/artman_longrunning.yaml +google/monitoring/artman_monitoring.yaml +google/privacy/dlp/artman_dlp_v2.yaml +google/pubsub/artman_pubsub.yaml +google/spanner/admin/database/artman_spanner_admin_database.yaml +google/spanner/admin/instance/artman_spanner_admin_instance.yaml +google/spanner/artman_spanner.yaml +) + +for api in "${APIS[@]}"; do + rm -rf artman-genfiles/* + artman --config "$api" generate go_gapic + cp -r artman-genfiles/gapi-*/cloud.google.com/go/* $GOPATH/src/cloud.google.com/go/ +done + +# NOTE(pongad): `sed -i` doesn't work on Macs, because -i option needs an argument. +# `-i ''` doesn't work on GNU, since the empty string is treated as a file name. +# So we just create the backup and delete it after. +ver=$(date +%Y%m%d) +find $GOPATH/src/cloud.google.com/go/ -name '*.go' -exec sed -i.backup -e "s/^const versionClient.*/const versionClient = \"$ver\"/" '{}' + +find $GOPATH/src/cloud.google.com/go/ -name '*.backup' -delete + +#go list cloud.google.com/go/... | grep apiv | xargs go test + +#go test -short cloud.google.com/go/... + +#echo "googleapis version: $(git rev-parse HEAD)" diff --git a/vendor/cloud.google.com/go/rpcreplay/Makefile b/vendor/cloud.google.com/go/rpcreplay/Makefile new file mode 100644 index 00000000..cb05a7b7 --- /dev/null +++ b/vendor/cloud.google.com/go/rpcreplay/Makefile @@ -0,0 +1,32 @@ +# Copyright 2017 Google LLC +# +# 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. + +# Makefile for building Go files from protos. + +# Change these to match your environment. +PROTOC=$(HOME)/bin/protoc +PROTOC_GO_PLUGIN_DIR=$(GOPATH)/bin +PROTOBUF_REPO=$(HOME)/git-repos/protobuf + +gen-protos: sync-protobuf + for d in proto/*; do \ + PATH=$(PATH):$(PROTOC_GO_PLUGIN_DIR) \ + $(PROTOC) --go_out=plugins=grpc:$$d \ + -I $$d -I $(PROTOBUF_REPO)/src $$d/*.proto; \ + done + + +sync-protobuf: + cd $(PROTOBUF_REPO); git pull + diff --git a/vendor/cloud.google.com/go/rpcreplay/doc.go b/vendor/cloud.google.com/go/rpcreplay/doc.go new file mode 100644 index 00000000..90455555 --- /dev/null +++ b/vendor/cloud.google.com/go/rpcreplay/doc.go @@ -0,0 +1,145 @@ +// Copyright 2017 Google LLC +// +// 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 rpcreplay supports the capture and replay of gRPC calls. Its main goal is +to improve testing. Once you capture the calls of a test that runs against a real +service, you have an "automatic mock" that can be replayed against the same test, +yielding a unit test that is fast and flake-free. + +This package is EXPERIMENTAL and subject to change without notice. + + +Recording + +To record a sequence of gRPC calls to a file, create a Recorder and pass its +DialOptions to grpc.Dial: + + rec, err := rpcreplay.NewRecorder("service.replay", nil) + if err != nil { ... } + defer func() { + if err := rec.Close(); err != nil { ... } + }() + conn, err := grpc.Dial(serverAddress, rec.DialOptions()...) + +It is essential to close the Recorder when the interaction is finished. + +There is also a NewRecorderWriter function for capturing to an arbitrary +io.Writer. + + +Replaying + +Replaying a captured file looks almost identical: create a Replayer and use +its DialOptions. (Since we're reading the file and not writing it, we don't +have to be as careful about the error returned from Close). + + rep, err := rpcreplay.NewReplayer("service.replay") + if err != nil { ... } + defer rep.Close() + conn, err := grpc.Dial(serverAddress, rep.DialOptions()...) + + +Initial State + +A test might use random or time-sensitive values, for instance to create unique +resources for isolation from other tests. The test therefore has initial values, such +as the current time, or a random seed, that differ from run to run. You must record +this initial state and re-establish it on replay. + +To record the initial state, serialize it into a []byte and pass it as the second +argument to NewRecorder: + + timeNow := time.Now() + b, err := timeNow.MarshalBinary() + if err != nil { ... } + rec, err := rpcreplay.NewRecorder("service.replay", b) + +On replay, get the bytes from Replayer.Initial: + + rep, err := rpcreplay.NewReplayer("service.replay") + if err != nil { ... } + defer rep.Close() + err = timeNow.UnmarshalBinary(rep.Initial()) + if err != nil { ... } + + +Callbacks that modify what is saved and matched from the replay file + +Recorders and replayers have support for running callbacks before messages are written/read +from the replay file. A Recorder has a BeforeFunc that can modify a request or response +before it is written to the replay file. The actual RPCs sent to the service during recording +remain unaltered; only what is saved in the replay file can be changed.A Replayer has a +BeforeFunc that can modify a request before it is sent for matching. + +Example uses for these callbacks include customized logging, or scrubbing data +before RPCs are written to the replay file. If requests are modified by the callbacks during recording, +it is important to perform the same modifications to the requests when replaying, or RPC +matching on replay will fail. + +A common way to analyze and modify the various messages is to use a type switch. + + // Assume these types implement proto.Message. + type Greeting struct { + line string + } + + type Farewell struct { + line string + } + + func sayings(method string, msg proto.Message) error { + switch m := msg.(type) { + case Greeting: + msg.line = "Hi!" + return nil + case Farewell: + msg.line = "Bye bye!" + return nil + default: + return fmt.Errorf("unknown message type") + } + } + +Nondeterminism + +A nondeterministic program may invoke RPCs in a different order each time +it is run. The order in which RPCs are called during recording may differ +from the order during replay. + +The replayer matches incoming to recorded requests by method name and request +contents, so nondeterminism is only a concern for identical requests that result +in different responses. A nondeterministic program whose behavior differs +depending on the order of such RPCs probably has a race condition: since both the +recorded sequence of RPCs and the sequence during replay are valid orderings, the +program should behave the same under both. + + +Other Replayer Differences + +Besides the differences in replay mentioned above, other differences may cause issues +for some programs. We list them here. + +The Replayer delivers a response to an RPC immediately, without waiting for other +incoming RPCs. This can violate causality. For example, in a Pub/Sub program where +one goroutine publishes and another subscribes, during replay the Subscribe call may +finish before the Publish call begins. + +For streaming RPCs, the Replayer delivers the result of Send and Recv calls in +the order they were recorded. No attempt is made to match message contents. + +At present, this package does not record or replay stream headers and trailers, or +the result of the CloseSend method. +*/ +package rpcreplay // import "cloud.google.com/go/rpcreplay" diff --git a/vendor/cloud.google.com/go/rpcreplay/example_test.go b/vendor/cloud.google.com/go/rpcreplay/example_test.go new file mode 100644 index 00000000..912db206 --- /dev/null +++ b/vendor/cloud.google.com/go/rpcreplay/example_test.go @@ -0,0 +1,47 @@ +// Copyright 2017 Google LLC +// +// 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 rpcreplay_test + +var serverAddress string + +// func Example_NewRecorder() { +// rec, err := rpcreplay.NewRecorder("service.replay", nil) +// if err != nil { +// // TODO: Handle error. +// } +// defer func() { +// if err := rec.Close(); err != nil { +// // TODO: Handle error. +// } +// }() +// conn, err := grpc.Dial(serverAddress, rec.DialOptions()...) +// if err != nil { +// // TODO: Handle error. +// } +// _ = conn // TODO: use connection +// } + +// func Example_NewReplayer() { +// rep, err := rpcreplay.NewReplayer("service.replay") +// if err != nil { +// // TODO: Handle error. +// } +// defer rep.Close() +// conn, err := grpc.Dial(serverAddress, rep.DialOptions()...) +// if err != nil { +// // TODO: Handle error. +// } +// _ = conn // TODO: use connection +// } diff --git a/vendor/cloud.google.com/go/rpcreplay/fake_test.go b/vendor/cloud.google.com/go/rpcreplay/fake_test.go new file mode 100644 index 00000000..837ab3d6 --- /dev/null +++ b/vendor/cloud.google.com/go/rpcreplay/fake_test.go @@ -0,0 +1,121 @@ +// Copyright 2017 Google LLC +// +// 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 rpcreplay + +import ( + "context" + "io" + "log" + "net" + + pb "cloud.google.com/go/rpcreplay/proto/intstore" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// intStoreServer is an in-memory implementation of IntStore. +type intStoreServer struct { + pb.IntStoreServer + + Addr string + l net.Listener + gsrv *grpc.Server + + items map[string]int32 +} + +func newIntStoreServer() *intStoreServer { + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + log.Fatal(err) + } + s := &intStoreServer{ + Addr: l.Addr().String(), + l: l, + gsrv: grpc.NewServer(), + } + pb.RegisterIntStoreServer(s.gsrv, s) + go s.gsrv.Serve(s.l) + return s +} + +func (s *intStoreServer) stop() { + s.gsrv.Stop() + s.l.Close() +} + +func (s *intStoreServer) Set(_ context.Context, item *pb.Item) (*pb.SetResponse, error) { + old := s.setItem(item) + return &pb.SetResponse{PrevValue: old}, nil +} + +func (s *intStoreServer) setItem(item *pb.Item) int32 { + if s.items == nil { + s.items = map[string]int32{} + } + old := s.items[item.Name] + s.items[item.Name] = item.Value + return old +} + +func (s *intStoreServer) Get(_ context.Context, req *pb.GetRequest) (*pb.Item, error) { + val, ok := s.items[req.Name] + if !ok { + return nil, status.Errorf(codes.NotFound, "%q", req.Name) + } + return &pb.Item{Name: req.Name, Value: val}, nil +} + +func (s *intStoreServer) ListItems(_ *pb.ListItemsRequest, ss pb.IntStore_ListItemsServer) error { + for name, val := range s.items { + if err := ss.Send(&pb.Item{Name: name, Value: val}); err != nil { + return err + } + } + return nil +} + +func (s *intStoreServer) SetStream(ss pb.IntStore_SetStreamServer) error { + n := 0 + for { + item, err := ss.Recv() + if err == io.EOF { + break + } + if err != nil { + return err + } + s.setItem(item) + n++ + } + return ss.SendAndClose(&pb.Summary{Count: int32(n)}) +} + +func (s *intStoreServer) StreamChat(ss pb.IntStore_StreamChatServer) error { + for { + item, err := ss.Recv() + if err == io.EOF { + break + } + if err != nil { + return err + } + if err := ss.Send(item); err != nil { + return err + } + } + return nil +} diff --git a/vendor/cloud.google.com/go/rpcreplay/proto/intstore/intstore.pb.go b/vendor/cloud.google.com/go/rpcreplay/proto/intstore/intstore.pb.go new file mode 100644 index 00000000..cac66078 --- /dev/null +++ b/vendor/cloud.google.com/go/rpcreplay/proto/intstore/intstore.pb.go @@ -0,0 +1,455 @@ +// Code generated by protoc-gen-go. +// source: intstore.proto +// DO NOT EDIT! + +/* +Package intstore is a generated protocol buffer package. + +It is generated from these files: + intstore.proto + +It has these top-level messages: + Item + SetResponse + GetRequest + Summary + ListItemsRequest +*/ +package intstore + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + "context" + + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Item struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Value int32 `protobuf:"varint,2,opt,name=value" json:"value,omitempty"` +} + +func (m *Item) Reset() { *m = Item{} } +func (m *Item) String() string { return proto.CompactTextString(m) } +func (*Item) ProtoMessage() {} +func (*Item) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *Item) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Item) GetValue() int32 { + if m != nil { + return m.Value + } + return 0 +} + +type SetResponse struct { + PrevValue int32 `protobuf:"varint,1,opt,name=prev_value,json=prevValue" json:"prev_value,omitempty"` +} + +func (m *SetResponse) Reset() { *m = SetResponse{} } +func (m *SetResponse) String() string { return proto.CompactTextString(m) } +func (*SetResponse) ProtoMessage() {} +func (*SetResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *SetResponse) GetPrevValue() int32 { + if m != nil { + return m.PrevValue + } + return 0 +} + +type GetRequest struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` +} + +func (m *GetRequest) Reset() { *m = GetRequest{} } +func (m *GetRequest) String() string { return proto.CompactTextString(m) } +func (*GetRequest) ProtoMessage() {} +func (*GetRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *GetRequest) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +type Summary struct { + Count int32 `protobuf:"varint,1,opt,name=count" json:"count,omitempty"` +} + +func (m *Summary) Reset() { *m = Summary{} } +func (m *Summary) String() string { return proto.CompactTextString(m) } +func (*Summary) ProtoMessage() {} +func (*Summary) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *Summary) GetCount() int32 { + if m != nil { + return m.Count + } + return 0 +} + +type ListItemsRequest struct { +} + +func (m *ListItemsRequest) Reset() { *m = ListItemsRequest{} } +func (m *ListItemsRequest) String() string { return proto.CompactTextString(m) } +func (*ListItemsRequest) ProtoMessage() {} +func (*ListItemsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func init() { + proto.RegisterType((*Item)(nil), "intstore.Item") + proto.RegisterType((*SetResponse)(nil), "intstore.SetResponse") + proto.RegisterType((*GetRequest)(nil), "intstore.GetRequest") + proto.RegisterType((*Summary)(nil), "intstore.Summary") + proto.RegisterType((*ListItemsRequest)(nil), "intstore.ListItemsRequest") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for IntStore service + +type IntStoreClient interface { + Set(ctx context.Context, in *Item, opts ...grpc.CallOption) (*SetResponse, error) + Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*Item, error) + // A server-to-client streaming RPC. + ListItems(ctx context.Context, in *ListItemsRequest, opts ...grpc.CallOption) (IntStore_ListItemsClient, error) + // A client-to-server streaming RPC. + SetStream(ctx context.Context, opts ...grpc.CallOption) (IntStore_SetStreamClient, error) + // A Bidirectional streaming RPC. + StreamChat(ctx context.Context, opts ...grpc.CallOption) (IntStore_StreamChatClient, error) +} + +type intStoreClient struct { + cc *grpc.ClientConn +} + +func NewIntStoreClient(cc *grpc.ClientConn) IntStoreClient { + return &intStoreClient{cc} +} + +func (c *intStoreClient) Set(ctx context.Context, in *Item, opts ...grpc.CallOption) (*SetResponse, error) { + out := new(SetResponse) + err := grpc.Invoke(ctx, "/intstore.IntStore/Set", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *intStoreClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*Item, error) { + out := new(Item) + err := grpc.Invoke(ctx, "/intstore.IntStore/Get", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *intStoreClient) ListItems(ctx context.Context, in *ListItemsRequest, opts ...grpc.CallOption) (IntStore_ListItemsClient, error) { + stream, err := grpc.NewClientStream(ctx, &_IntStore_serviceDesc.Streams[0], c.cc, "/intstore.IntStore/ListItems", opts...) + if err != nil { + return nil, err + } + x := &intStoreListItemsClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type IntStore_ListItemsClient interface { + Recv() (*Item, error) + grpc.ClientStream +} + +type intStoreListItemsClient struct { + grpc.ClientStream +} + +func (x *intStoreListItemsClient) Recv() (*Item, error) { + m := new(Item) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *intStoreClient) SetStream(ctx context.Context, opts ...grpc.CallOption) (IntStore_SetStreamClient, error) { + stream, err := grpc.NewClientStream(ctx, &_IntStore_serviceDesc.Streams[1], c.cc, "/intstore.IntStore/SetStream", opts...) + if err != nil { + return nil, err + } + x := &intStoreSetStreamClient{stream} + return x, nil +} + +type IntStore_SetStreamClient interface { + Send(*Item) error + CloseAndRecv() (*Summary, error) + grpc.ClientStream +} + +type intStoreSetStreamClient struct { + grpc.ClientStream +} + +func (x *intStoreSetStreamClient) Send(m *Item) error { + return x.ClientStream.SendMsg(m) +} + +func (x *intStoreSetStreamClient) CloseAndRecv() (*Summary, error) { + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + m := new(Summary) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *intStoreClient) StreamChat(ctx context.Context, opts ...grpc.CallOption) (IntStore_StreamChatClient, error) { + stream, err := grpc.NewClientStream(ctx, &_IntStore_serviceDesc.Streams[2], c.cc, "/intstore.IntStore/StreamChat", opts...) + if err != nil { + return nil, err + } + x := &intStoreStreamChatClient{stream} + return x, nil +} + +type IntStore_StreamChatClient interface { + Send(*Item) error + Recv() (*Item, error) + grpc.ClientStream +} + +type intStoreStreamChatClient struct { + grpc.ClientStream +} + +func (x *intStoreStreamChatClient) Send(m *Item) error { + return x.ClientStream.SendMsg(m) +} + +func (x *intStoreStreamChatClient) Recv() (*Item, error) { + m := new(Item) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// Server API for IntStore service + +type IntStoreServer interface { + Set(context.Context, *Item) (*SetResponse, error) + Get(context.Context, *GetRequest) (*Item, error) + // A server-to-client streaming RPC. + ListItems(*ListItemsRequest, IntStore_ListItemsServer) error + // A client-to-server streaming RPC. + SetStream(IntStore_SetStreamServer) error + // A Bidirectional streaming RPC. + StreamChat(IntStore_StreamChatServer) error +} + +func RegisterIntStoreServer(s *grpc.Server, srv IntStoreServer) { + s.RegisterService(&_IntStore_serviceDesc, srv) +} + +func _IntStore_Set_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Item) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IntStoreServer).Set(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/intstore.IntStore/Set", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IntStoreServer).Set(ctx, req.(*Item)) + } + return interceptor(ctx, in, info, handler) +} + +func _IntStore_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(IntStoreServer).Get(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/intstore.IntStore/Get", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(IntStoreServer).Get(ctx, req.(*GetRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _IntStore_ListItems_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(ListItemsRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(IntStoreServer).ListItems(m, &intStoreListItemsServer{stream}) +} + +type IntStore_ListItemsServer interface { + Send(*Item) error + grpc.ServerStream +} + +type intStoreListItemsServer struct { + grpc.ServerStream +} + +func (x *intStoreListItemsServer) Send(m *Item) error { + return x.ServerStream.SendMsg(m) +} + +func _IntStore_SetStream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(IntStoreServer).SetStream(&intStoreSetStreamServer{stream}) +} + +type IntStore_SetStreamServer interface { + SendAndClose(*Summary) error + Recv() (*Item, error) + grpc.ServerStream +} + +type intStoreSetStreamServer struct { + grpc.ServerStream +} + +func (x *intStoreSetStreamServer) SendAndClose(m *Summary) error { + return x.ServerStream.SendMsg(m) +} + +func (x *intStoreSetStreamServer) Recv() (*Item, error) { + m := new(Item) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _IntStore_StreamChat_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(IntStoreServer).StreamChat(&intStoreStreamChatServer{stream}) +} + +type IntStore_StreamChatServer interface { + Send(*Item) error + Recv() (*Item, error) + grpc.ServerStream +} + +type intStoreStreamChatServer struct { + grpc.ServerStream +} + +func (x *intStoreStreamChatServer) Send(m *Item) error { + return x.ServerStream.SendMsg(m) +} + +func (x *intStoreStreamChatServer) Recv() (*Item, error) { + m := new(Item) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +var _IntStore_serviceDesc = grpc.ServiceDesc{ + ServiceName: "intstore.IntStore", + HandlerType: (*IntStoreServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Set", + Handler: _IntStore_Set_Handler, + }, + { + MethodName: "Get", + Handler: _IntStore_Get_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "ListItems", + Handler: _IntStore_ListItems_Handler, + ServerStreams: true, + }, + { + StreamName: "SetStream", + Handler: _IntStore_SetStream_Handler, + ClientStreams: true, + }, + { + StreamName: "StreamChat", + Handler: _IntStore_StreamChat_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "intstore.proto", +} + +func init() { proto.RegisterFile("intstore.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 273 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x91, 0x4f, 0x4b, 0xc3, 0x40, + 0x10, 0xc5, 0xb3, 0xfd, 0xa3, 0xcd, 0x08, 0x45, 0x87, 0x0a, 0x25, 0x20, 0x86, 0x3d, 0xe5, 0xa0, + 0x21, 0xd4, 0xa3, 0x47, 0x0f, 0xa5, 0xe0, 0x29, 0x0b, 0x5e, 0x25, 0xca, 0x80, 0x05, 0xb3, 0x1b, + 0x77, 0x27, 0x05, 0xbf, 0x84, 0x9f, 0x59, 0x36, 0x5b, 0x9b, 0xd2, 0x78, 0xdb, 0xb7, 0xf3, 0x66, + 0xde, 0x6f, 0x76, 0x61, 0xbe, 0xd5, 0xec, 0xd8, 0x58, 0xca, 0x1b, 0x6b, 0xd8, 0xe0, 0xec, 0x4f, + 0xcb, 0x02, 0x26, 0x1b, 0xa6, 0x1a, 0x11, 0x26, 0xba, 0xaa, 0x69, 0x29, 0x52, 0x91, 0xc5, 0x65, + 0x77, 0xc6, 0x05, 0x4c, 0x77, 0xd5, 0x67, 0x4b, 0xcb, 0x51, 0x2a, 0xb2, 0x69, 0x19, 0x84, 0xbc, + 0x83, 0x0b, 0x45, 0x5c, 0x92, 0x6b, 0x8c, 0x76, 0x84, 0x37, 0x00, 0x8d, 0xa5, 0xdd, 0x6b, 0x70, + 0x8a, 0xce, 0x19, 0xfb, 0x9b, 0x97, 0xce, 0x9d, 0x02, 0xac, 0xbd, 0xfb, 0xab, 0x25, 0xc7, 0xff, + 0xa5, 0xc8, 0x5b, 0x38, 0x57, 0x6d, 0x5d, 0x57, 0xf6, 0xdb, 0x07, 0xbe, 0x9b, 0x56, 0xf3, 0x7e, + 0x4c, 0x10, 0x12, 0xe1, 0xf2, 0x79, 0xeb, 0xd8, 0x63, 0xba, 0xfd, 0xa0, 0xd5, 0xcf, 0x08, 0x66, + 0x1b, 0xcd, 0xca, 0xef, 0x80, 0x39, 0x8c, 0x15, 0x31, 0xce, 0xf3, 0xc3, 0x96, 0xde, 0x9b, 0x5c, + 0xf7, 0xfa, 0x08, 0x58, 0x46, 0x78, 0x0f, 0xe3, 0x35, 0x31, 0x2e, 0xfa, 0x7a, 0x8f, 0x98, 0x9c, + 0x4c, 0x91, 0x11, 0x3e, 0x42, 0x7c, 0xc8, 0xc7, 0xa4, 0x2f, 0x9f, 0x42, 0x0d, 0x5b, 0x0b, 0x81, + 0x2b, 0x88, 0x15, 0xb1, 0x62, 0x4b, 0x55, 0x3d, 0x20, 0xbc, 0x3a, 0x22, 0x0c, 0x4f, 0x20, 0xa3, + 0xcc, 0xf7, 0x40, 0x68, 0x78, 0xfa, 0xa8, 0x86, 0x6b, 0x0d, 0x52, 0x32, 0x51, 0x88, 0xb7, 0xb3, + 0xee, 0x63, 0x1f, 0x7e, 0x03, 0x00, 0x00, 0xff, 0xff, 0x22, 0x28, 0xa0, 0x49, 0xea, 0x01, 0x00, + 0x00, +} diff --git a/vendor/cloud.google.com/go/rpcreplay/proto/intstore/intstore.proto b/vendor/cloud.google.com/go/rpcreplay/proto/intstore/intstore.proto new file mode 100644 index 00000000..b3f66431 --- /dev/null +++ b/vendor/cloud.google.com/go/rpcreplay/proto/intstore/intstore.proto @@ -0,0 +1,54 @@ +// Copyright 2017 Google LLC +// +// 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. + +// IntStore is a service for testing the rpcreplay package. +// It is a simple key-value store for integers. + +syntax = "proto3"; + +package intstore; + +service IntStore { + rpc Set(Item) returns (SetResponse) {} + + rpc Get(GetRequest) returns (Item) {} + + // A server-to-client streaming RPC. + rpc ListItems(ListItemsRequest) returns (stream Item) {} + + // A client-to-server streaming RPC. + rpc SetStream(stream Item) returns (Summary) {} + + // A Bidirectional streaming RPC. + rpc StreamChat(stream Item) returns (stream Item) {} +} + +message Item { + string name = 1; + int32 value = 2; +} + +message SetResponse { + int32 prev_value = 1; +} + +message GetRequest { + string name = 1; +} + +message Summary { + int32 count = 1; +} + +message ListItemsRequest {} diff --git a/vendor/cloud.google.com/go/rpcreplay/proto/rpcreplay/rpcreplay.pb.go b/vendor/cloud.google.com/go/rpcreplay/proto/rpcreplay/rpcreplay.pb.go new file mode 100644 index 00000000..8e76a395 --- /dev/null +++ b/vendor/cloud.google.com/go/rpcreplay/proto/rpcreplay/rpcreplay.pb.go @@ -0,0 +1,170 @@ +// Code generated by protoc-gen-go. +// source: rpcreplay.proto +// DO NOT EDIT! + +/* +Package rpcreplay is a generated protocol buffer package. + +It is generated from these files: + rpcreplay.proto + +It has these top-level messages: + Entry +*/ +package rpcreplay + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" +import google_protobuf "github.com/golang/protobuf/ptypes/any" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type Entry_Kind int32 + +const ( + Entry_TYPE_UNSPECIFIED Entry_Kind = 0 + // A unary request. + // method: the full name of the method + // message: the request proto + // is_error: false + // ref_index: 0 + Entry_REQUEST Entry_Kind = 1 + // A unary response. + // method: the full name of the method + // message: + // if is_error: a google.rpc.Status proto + // else: the response proto + // ref_index: index in the sequence of Entries of matching request (1-based) + Entry_RESPONSE Entry_Kind = 2 + // A method that creates a stream. + // method: the full name of the method + // message: + // if is_error: a google.rpc.Status proto + // else: nil + // ref_index: 0 + Entry_CREATE_STREAM Entry_Kind = 3 + // A call to Send on the client returned by a stream-creating method. + // method: unset + // message: the proto being sent + // is_error: false + // ref_index: index of matching CREATE_STREAM entry (1-based) + Entry_SEND Entry_Kind = 4 + // A call to Recv on the client returned by a stream-creating method. + // method: unset + // message: + // if is_error: a google.rpc.Status proto, or nil on EOF + // else: the received message + // ref_index: index of matching CREATE_STREAM entry + Entry_RECV Entry_Kind = 5 +) + +var Entry_Kind_name = map[int32]string{ + 0: "TYPE_UNSPECIFIED", + 1: "REQUEST", + 2: "RESPONSE", + 3: "CREATE_STREAM", + 4: "SEND", + 5: "RECV", +} +var Entry_Kind_value = map[string]int32{ + "TYPE_UNSPECIFIED": 0, + "REQUEST": 1, + "RESPONSE": 2, + "CREATE_STREAM": 3, + "SEND": 4, + "RECV": 5, +} + +func (x Entry_Kind) String() string { + return proto.EnumName(Entry_Kind_name, int32(x)) +} +func (Entry_Kind) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} } + +// An Entry represents a single RPC activity, typically a request or response. +type Entry struct { + Kind Entry_Kind `protobuf:"varint,1,opt,name=kind,enum=rpcreplay.Entry_Kind" json:"kind,omitempty"` + Method string `protobuf:"bytes,2,opt,name=method" json:"method,omitempty"` + Message *google_protobuf.Any `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` + IsError bool `protobuf:"varint,4,opt,name=is_error,json=isError" json:"is_error,omitempty"` + RefIndex int32 `protobuf:"varint,5,opt,name=ref_index,json=refIndex" json:"ref_index,omitempty"` +} + +func (m *Entry) Reset() { *m = Entry{} } +func (m *Entry) String() string { return proto.CompactTextString(m) } +func (*Entry) ProtoMessage() {} +func (*Entry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *Entry) GetKind() Entry_Kind { + if m != nil { + return m.Kind + } + return Entry_TYPE_UNSPECIFIED +} + +func (m *Entry) GetMethod() string { + if m != nil { + return m.Method + } + return "" +} + +func (m *Entry) GetMessage() *google_protobuf.Any { + if m != nil { + return m.Message + } + return nil +} + +func (m *Entry) GetIsError() bool { + if m != nil { + return m.IsError + } + return false +} + +func (m *Entry) GetRefIndex() int32 { + if m != nil { + return m.RefIndex + } + return 0 +} + +func init() { + proto.RegisterType((*Entry)(nil), "rpcreplay.Entry") + proto.RegisterEnum("rpcreplay.Entry_Kind", Entry_Kind_name, Entry_Kind_value) +} + +func init() { proto.RegisterFile("rpcreplay.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 289 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x44, 0x8e, 0xdf, 0x4e, 0xc2, 0x30, + 0x14, 0xc6, 0x2d, 0x6c, 0x30, 0x0e, 0xfe, 0xa9, 0x0d, 0x9a, 0xa1, 0x37, 0x0b, 0x57, 0xf3, 0xa6, + 0x24, 0xf8, 0x04, 0x04, 0x8e, 0x09, 0x31, 0x22, 0xb6, 0xc3, 0xc4, 0x1b, 0x17, 0x70, 0x05, 0x17, + 0xa1, 0x25, 0xdd, 0x4c, 0xdc, 0x6b, 0xf8, 0xc4, 0x66, 0x13, 0xf4, 0xae, 0xbf, 0x7e, 0xbf, 0x9c, + 0xef, 0x83, 0x33, 0xbb, 0x7b, 0xb3, 0x6a, 0xb7, 0x59, 0x14, 0x7c, 0x67, 0x4d, 0x6e, 0x58, 0xeb, + 0xef, 0xe3, 0xaa, 0xbb, 0x36, 0x66, 0xbd, 0x51, 0xfd, 0x2a, 0x58, 0x7e, 0xae, 0xfa, 0x0b, 0xbd, + 0xb7, 0x7a, 0xdf, 0x35, 0x70, 0x51, 0xe7, 0xb6, 0x60, 0x37, 0xe0, 0x7c, 0xa4, 0x3a, 0xf1, 0x49, + 0x40, 0xc2, 0xd3, 0xc1, 0x05, 0xff, 0xbf, 0x57, 0xe5, 0xfc, 0x3e, 0xd5, 0x89, 0xa8, 0x14, 0x76, + 0x09, 0x8d, 0xad, 0xca, 0xdf, 0x4d, 0xe2, 0xd7, 0x02, 0x12, 0xb6, 0xc4, 0x9e, 0x18, 0x87, 0xe6, + 0x56, 0x65, 0xd9, 0x62, 0xad, 0xfc, 0x7a, 0x40, 0xc2, 0xf6, 0xa0, 0xc3, 0x7f, 0x9b, 0xf9, 0xa1, + 0x99, 0x0f, 0x75, 0x21, 0x0e, 0x12, 0xeb, 0x82, 0x97, 0x66, 0xb1, 0xb2, 0xd6, 0x58, 0xdf, 0x09, + 0x48, 0xe8, 0x89, 0x66, 0x9a, 0x61, 0x89, 0xec, 0x1a, 0x5a, 0x56, 0xad, 0xe2, 0x54, 0x27, 0xea, + 0xcb, 0x77, 0x03, 0x12, 0xba, 0xc2, 0xb3, 0x6a, 0x35, 0x29, 0xb9, 0xf7, 0x0a, 0x4e, 0xb9, 0x86, + 0x75, 0x80, 0x46, 0x2f, 0x33, 0x8c, 0xe7, 0x53, 0x39, 0xc3, 0xd1, 0xe4, 0x6e, 0x82, 0x63, 0x7a, + 0xc4, 0xda, 0xd0, 0x14, 0xf8, 0x34, 0x47, 0x19, 0x51, 0xc2, 0x8e, 0xc1, 0x13, 0x28, 0x67, 0x8f, + 0x53, 0x89, 0xb4, 0xc6, 0xce, 0xe1, 0x64, 0x24, 0x70, 0x18, 0x61, 0x2c, 0x23, 0x81, 0xc3, 0x07, + 0x5a, 0x67, 0x1e, 0x38, 0x12, 0xa7, 0x63, 0xea, 0x94, 0x2f, 0x81, 0xa3, 0x67, 0xea, 0x2e, 0x1b, + 0xd5, 0xdc, 0xdb, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe7, 0x9b, 0x9d, 0x4f, 0x54, 0x01, 0x00, + 0x00, +} diff --git a/vendor/cloud.google.com/go/rpcreplay/proto/rpcreplay/rpcreplay.proto b/vendor/cloud.google.com/go/rpcreplay/proto/rpcreplay/rpcreplay.proto new file mode 100644 index 00000000..8abbff92 --- /dev/null +++ b/vendor/cloud.google.com/go/rpcreplay/proto/rpcreplay/rpcreplay.proto @@ -0,0 +1,71 @@ +// Copyright 2017 Google LLC +// +// 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. + +syntax = "proto3"; + +package rpcreplay; + +import "google/protobuf/any.proto"; + +// An Entry represents a single RPC activity, typically a request or response. +message Entry { + enum Kind { + TYPE_UNSPECIFIED = 0; + + // A unary request. + // method: the full name of the method + // message: the request proto + // is_error: false + // ref_index: 0 + REQUEST = 1; + + // A unary response. + // method: the full name of the method + // message: + // if is_error: a google.rpc.Status proto + // else: the response proto + // ref_index: index in the sequence of Entries of matching request (1-based) + RESPONSE = 2; + + // A method that creates a stream. + // method: the full name of the method + // message: + // if is_error: a google.rpc.Status proto + // else: nil + // ref_index: 0 + CREATE_STREAM = 3; + + // A call to Send on the client returned by a stream-creating method. + // method: unset + // message: the proto being sent + // is_error: false + // ref_index: index of matching CREATE_STREAM entry (1-based) + SEND = 4; // message sent on stream + + // A call to Recv on the client returned by a stream-creating method. + // method: unset + // message: + // if is_error: a google.rpc.Status proto, or nil on EOF + // else: the received message + // ref_index: index of matching CREATE_STREAM entry + RECV = 5; // message received from stream + } + + Kind kind = 1; + string method = 2; // method name + google.protobuf.Any message = 3; // request, response or error status + bool is_error = 4; // was response an error? + int32 ref_index = 5; // for RESPONSE, index of matching request; + // for SEND/RECV, index of CREATE_STREAM +} diff --git a/vendor/cloud.google.com/go/rpcreplay/rpcreplay.go b/vendor/cloud.google.com/go/rpcreplay/rpcreplay.go new file mode 100644 index 00000000..215b9686 --- /dev/null +++ b/vendor/cloud.google.com/go/rpcreplay/rpcreplay.go @@ -0,0 +1,716 @@ +// Copyright 2017 Google LLC +// +// 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 rpcreplay + +import ( + "bufio" + "context" + "encoding/binary" + "errors" + "fmt" + "io" + "log" + "os" + "sync" + + pb "cloud.google.com/go/rpcreplay/proto/rpcreplay" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "github.com/golang/protobuf/ptypes/any" + spb "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// A Recorder records RPCs for later playback. +type Recorder struct { + mu sync.Mutex + w *bufio.Writer + f *os.File + next int + err error + // BeforeFunc defines a function that can inspect and modify requests and responses + // written to the replay file. It does not modify messages sent to the service. + // It is run once before a request is written to the replay file, and once before a response + // is written to the replay file. + // The function is called with the method name and the message that triggered the callback. + // If the function returns an error, the error will be returned to the client. + // This is only executed for unary RPCs; streaming RPCs are not supported. + BeforeFunc func(string, proto.Message) error +} + +// NewRecorder creates a recorder that writes to filename. The file will +// also store the initial bytes for retrieval during replay. +// +// You must call Close on the Recorder to ensure that all data is written. +func NewRecorder(filename string, initial []byte) (*Recorder, error) { + f, err := os.Create(filename) + if err != nil { + return nil, err + } + rec, err := NewRecorderWriter(f, initial) + if err != nil { + _ = f.Close() + return nil, err + } + rec.f = f + return rec, nil +} + +// NewRecorderWriter creates a recorder that writes to w. The initial +// bytes will also be written to w for retrieval during replay. +// +// You must call Close on the Recorder to ensure that all data is written. +func NewRecorderWriter(w io.Writer, initial []byte) (*Recorder, error) { + bw := bufio.NewWriter(w) + if err := writeHeader(bw, initial); err != nil { + return nil, err + } + return &Recorder{w: bw, next: 1}, nil +} + +// DialOptions returns the options that must be passed to grpc.Dial +// to enable recording. +func (r *Recorder) DialOptions() []grpc.DialOption { + return []grpc.DialOption{ + grpc.WithUnaryInterceptor(r.interceptUnary), + grpc.WithStreamInterceptor(r.interceptStream), + } +} + +// Close saves any unwritten information. +func (r *Recorder) Close() error { + r.mu.Lock() + defer r.mu.Unlock() + if r.err != nil { + return r.err + } + err := r.w.Flush() + if r.f != nil { + if err2 := r.f.Close(); err == nil { + err = err2 + } + } + return err +} + +// Intercepts all unary (non-stream) RPCs. +func (r *Recorder) interceptUnary(ctx context.Context, method string, req, res interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + ereq := &entry{ + kind: pb.Entry_REQUEST, + method: method, + msg: message{msg: proto.Clone(req.(proto.Message))}, + } + + if r.BeforeFunc != nil { + if err := r.BeforeFunc(method, ereq.msg.msg); err != nil { + return err + } + } + refIndex, err := r.writeEntry(ereq) + if err != nil { + return err + } + ierr := invoker(ctx, method, req, res, cc, opts...) + eres := &entry{ + kind: pb.Entry_RESPONSE, + refIndex: refIndex, + } + // If the error is not a gRPC status, then something more + // serious is wrong. More significantly, we have no way + // of serializing an arbitrary error. So just return it + // without recording the response. + if _, ok := status.FromError(ierr); !ok { + r.mu.Lock() + r.err = fmt.Errorf("saw non-status error in %s response: %v (%T)", method, ierr, ierr) + r.mu.Unlock() + return ierr + } + eres.msg.set(proto.Clone(res.(proto.Message)), ierr) + if r.BeforeFunc != nil { + if err := r.BeforeFunc(method, eres.msg.msg); err != nil { + return err + } + } + if _, err := r.writeEntry(eres); err != nil { + return err + } + return ierr +} + +func (r *Recorder) writeEntry(e *entry) (int, error) { + r.mu.Lock() + defer r.mu.Unlock() + if r.err != nil { + return 0, r.err + } + err := writeEntry(r.w, e) + if err != nil { + r.err = err + return 0, err + } + n := r.next + r.next++ + return n, nil +} + +func (r *Recorder) interceptStream(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { + cstream, serr := streamer(ctx, desc, cc, method, opts...) + e := &entry{ + kind: pb.Entry_CREATE_STREAM, + method: method, + } + e.msg.set(nil, serr) + refIndex, err := r.writeEntry(e) + if err != nil { + return nil, err + } + return &recClientStream{ + ctx: ctx, + rec: r, + cstream: cstream, + refIndex: refIndex, + }, serr +} + +// A recClientStream implements the gprc.ClientStream interface. +// It behaves exactly like the default ClientStream, but also +// records all messages sent and received. +type recClientStream struct { + ctx context.Context + rec *Recorder + cstream grpc.ClientStream + refIndex int +} + +func (rcs *recClientStream) Context() context.Context { return rcs.ctx } + +func (rcs *recClientStream) SendMsg(m interface{}) error { + serr := rcs.cstream.SendMsg(m) + e := &entry{ + kind: pb.Entry_SEND, + refIndex: rcs.refIndex, + } + e.msg.set(m, serr) + if _, err := rcs.rec.writeEntry(e); err != nil { + return err + } + return serr +} + +func (rcs *recClientStream) RecvMsg(m interface{}) error { + serr := rcs.cstream.RecvMsg(m) + e := &entry{ + kind: pb.Entry_RECV, + refIndex: rcs.refIndex, + } + e.msg.set(m, serr) + if _, err := rcs.rec.writeEntry(e); err != nil { + return err + } + return serr +} + +func (rcs *recClientStream) Header() (metadata.MD, error) { + // TODO(jba): record. + return rcs.cstream.Header() +} + +func (rcs *recClientStream) Trailer() metadata.MD { + // TODO(jba): record. + return rcs.cstream.Trailer() +} + +func (rcs *recClientStream) CloseSend() error { + // TODO(jba): record. + return rcs.cstream.CloseSend() +} + +// A Replayer replays a set of RPCs saved by a Recorder. +type Replayer struct { + initial []byte // initial state + log func(format string, v ...interface{}) // for debugging + + mu sync.Mutex + calls []*call + streams []*stream + // BeforeFunc defines a function that can inspect and modify requests before they + // are matched for responses from the replay file. + // The function is called with the method name and the message that triggered the callback. + // If the function returns an error, the error will be returned to the client. + // This is only executed for unary RPCs; streaming RPCs are not supported. + BeforeFunc func(string, proto.Message) error +} + +// A call represents a unary RPC, with a request and response (or error). +type call struct { + method string + request proto.Message + response message +} + +// A stream represents a gRPC stream, with an initial create-stream call, followed by +// zero or more sends and/or receives. +type stream struct { + method string + createIndex int + createErr error // error from create call + sends []message + recvs []message +} + +// NewReplayer creates a Replayer that reads from filename. +func NewReplayer(filename string) (*Replayer, error) { + f, err := os.Open(filename) + if err != nil { + return nil, err + } + defer f.Close() + return NewReplayerReader(f) +} + +// NewReplayerReader creates a Replayer that reads from r. +func NewReplayerReader(r io.Reader) (*Replayer, error) { + rep := &Replayer{ + log: func(string, ...interface{}) {}, + } + if err := rep.read(r); err != nil { + return nil, err + } + return rep, nil +} + +// read reads the stream of recorded entries. +// It matches requests with responses, with each pair grouped +// into a call struct. +func (rep *Replayer) read(r io.Reader) error { + r = bufio.NewReader(r) + bytes, err := readHeader(r) + if err != nil { + return err + } + rep.initial = bytes + + callsByIndex := map[int]*call{} + streamsByIndex := map[int]*stream{} + for i := 1; ; i++ { + e, err := readEntry(r) + if err != nil { + return err + } + if e == nil { + break + } + switch e.kind { + case pb.Entry_REQUEST: + callsByIndex[i] = &call{ + method: e.method, + request: e.msg.msg, + } + + case pb.Entry_RESPONSE: + call := callsByIndex[e.refIndex] + if call == nil { + return fmt.Errorf("replayer: no request for response #%d", i) + } + delete(callsByIndex, e.refIndex) + call.response = e.msg + rep.calls = append(rep.calls, call) + + case pb.Entry_CREATE_STREAM: + s := &stream{method: e.method, createIndex: i} + s.createErr = e.msg.err + streamsByIndex[i] = s + rep.streams = append(rep.streams, s) + + case pb.Entry_SEND: + s := streamsByIndex[e.refIndex] + if s == nil { + return fmt.Errorf("replayer: no stream for send #%d", i) + } + s.sends = append(s.sends, e.msg) + + case pb.Entry_RECV: + s := streamsByIndex[e.refIndex] + if s == nil { + return fmt.Errorf("replayer: no stream for recv #%d", i) + } + s.recvs = append(s.recvs, e.msg) + + default: + return fmt.Errorf("replayer: unknown kind %s", e.kind) + } + } + if len(callsByIndex) > 0 { + return fmt.Errorf("replayer: %d unmatched requests", len(callsByIndex)) + } + return nil +} + +// DialOptions returns the options that must be passed to grpc.Dial +// to enable replaying. +func (rep *Replayer) DialOptions() []grpc.DialOption { + return []grpc.DialOption{ + // On replay, we make no RPCs, which means the connection may be closed + // before the normally async Dial completes. Making the Dial synchronous + // fixes that. + grpc.WithBlock(), + grpc.WithUnaryInterceptor(rep.interceptUnary), + grpc.WithStreamInterceptor(rep.interceptStream), + } +} + +// Initial returns the initial state saved by the Recorder. +func (rep *Replayer) Initial() []byte { return rep.initial } + +// SetLogFunc sets a function to be used for debug logging. The function +// should be safe to be called from multiple goroutines. +func (rep *Replayer) SetLogFunc(f func(format string, v ...interface{})) { + rep.log = f +} + +// Close closes the Replayer. +func (rep *Replayer) Close() error { + return nil +} + +func (rep *Replayer) interceptUnary(_ context.Context, method string, req, res interface{}, _ *grpc.ClientConn, _ grpc.UnaryInvoker, _ ...grpc.CallOption) error { + mreq := req.(proto.Message) + if rep.BeforeFunc != nil { + if err := rep.BeforeFunc(method, mreq); err != nil { + return err + } + } + rep.log("request %s (%s)", method, req) + call := rep.extractCall(method, mreq) + if call == nil { + return fmt.Errorf("replayer: request not found: %s", mreq) + } + rep.log("returning %v", call.response) + if call.response.err != nil { + return call.response.err + } + proto.Merge(res.(proto.Message), call.response.msg) // copy msg into res + return nil +} + +func (rep *Replayer) interceptStream(ctx context.Context, _ *grpc.StreamDesc, _ *grpc.ClientConn, method string, _ grpc.Streamer, _ ...grpc.CallOption) (grpc.ClientStream, error) { + rep.log("create-stream %s", method) + str := rep.extractStream(method) + if str == nil { + return nil, fmt.Errorf("replayer: stream not found for method %s", method) + } + if str.createErr != nil { + return nil, str.createErr + } + return &repClientStream{ctx: ctx, str: str}, nil +} + +type repClientStream struct { + ctx context.Context + str *stream +} + +func (rcs *repClientStream) Context() context.Context { return rcs.ctx } + +func (rcs *repClientStream) SendMsg(m interface{}) error { + if len(rcs.str.sends) == 0 { + return fmt.Errorf("replayer: no more sends for stream %s, created at index %d", + rcs.str.method, rcs.str.createIndex) + } + // TODO(jba): Do not assume that the sends happen in the same order on replay. + msg := rcs.str.sends[0] + rcs.str.sends = rcs.str.sends[1:] + return msg.err +} + +func (rcs *repClientStream) RecvMsg(m interface{}) error { + if len(rcs.str.recvs) == 0 { + return fmt.Errorf("replayer: no more receives for stream %s, created at index %d", + rcs.str.method, rcs.str.createIndex) + } + msg := rcs.str.recvs[0] + rcs.str.recvs = rcs.str.recvs[1:] + if msg.err != nil { + return msg.err + } + proto.Merge(m.(proto.Message), msg.msg) // copy msg into m + return nil +} + +func (rcs *repClientStream) Header() (metadata.MD, error) { + log.Printf("replay: stream metadata not supported") + return nil, nil +} + +func (rcs *repClientStream) Trailer() metadata.MD { + log.Printf("replay: stream metadata not supported") + return nil +} + +func (rcs *repClientStream) CloseSend() error { + return nil +} + +// extractCall finds the first call in the list with the same method +// and request. It returns nil if it can't find such a call. +func (rep *Replayer) extractCall(method string, req proto.Message) *call { + rep.mu.Lock() + defer rep.mu.Unlock() + for i, call := range rep.calls { + if call == nil { + continue + } + if method == call.method && proto.Equal(req, call.request) { + rep.calls[i] = nil // nil out this call so we don't reuse it + return call + } + } + return nil +} + +func (rep *Replayer) extractStream(method string) *stream { + rep.mu.Lock() + defer rep.mu.Unlock() + for i, stream := range rep.streams { + if stream == nil { + continue + } + if method == stream.method { + rep.streams[i] = nil + return stream + } + } + return nil +} + +// Fprint reads the entries from filename and writes them to w in human-readable form. +// It is intended for debugging. +func Fprint(w io.Writer, filename string) error { + f, err := os.Open(filename) + if err != nil { + return err + } + defer f.Close() + return FprintReader(w, f) +} + +// FprintReader reads the entries from r and writes them to w in human-readable form. +// It is intended for debugging. +func FprintReader(w io.Writer, r io.Reader) error { + initial, err := readHeader(r) + if err != nil { + return err + } + fmt.Fprintf(w, "initial state: %q\n", string(initial)) + for i := 1; ; i++ { + e, err := readEntry(r) + if err != nil { + return err + } + if e == nil { + return nil + } + + s := "message" + if e.msg.err != nil { + s = "error" + } + fmt.Fprintf(w, "#%d: kind: %s, method: %s, ref index: %d, %s:\n", + i, e.kind, e.method, e.refIndex, s) + if e.msg.err == nil { + if err := proto.MarshalText(w, e.msg.msg); err != nil { + return err + } + } else { + fmt.Fprintf(w, "%v\n", e.msg.err) + } + } +} + +// An entry holds one gRPC action (request, response, etc.). +type entry struct { + kind pb.Entry_Kind + method string + msg message + refIndex int // index of corresponding request or create-stream +} + +func (e1 *entry) equal(e2 *entry) bool { + if e1 == nil && e2 == nil { + return true + } + if e1 == nil || e2 == nil { + return false + } + return e1.kind == e2.kind && + e1.method == e2.method && + proto.Equal(e1.msg.msg, e2.msg.msg) && + errEqual(e1.msg.err, e2.msg.err) && + e1.refIndex == e2.refIndex +} + +func errEqual(e1, e2 error) bool { + if e1 == e2 { + return true + } + s1, ok1 := status.FromError(e1) + s2, ok2 := status.FromError(e2) + if !ok1 || !ok2 { + return false + } + return proto.Equal(s1.Proto(), s2.Proto()) +} + +// message holds either a single proto.Message or an error. +type message struct { + msg proto.Message + err error +} + +func (m *message) set(msg interface{}, err error) { + m.err = err + if err != io.EOF && msg != nil { + m.msg = msg.(proto.Message) + } +} + +// File format: +// header +// sequence of Entry protos +// +// Header format: +// magic string +// a record containing the bytes of the initial state + +const magic = "RPCReplay" + +func writeHeader(w io.Writer, initial []byte) error { + if _, err := io.WriteString(w, magic); err != nil { + return err + } + return writeRecord(w, initial) +} + +func readHeader(r io.Reader) ([]byte, error) { + var buf [len(magic)]byte + if _, err := io.ReadFull(r, buf[:]); err != nil { + if err == io.EOF { + err = errors.New("rpcreplay: empty replay file") + } + return nil, err + } + if string(buf[:]) != magic { + return nil, errors.New("rpcreplay: not a replay file (does not begin with magic string)") + } + bytes, err := readRecord(r) + if err == io.EOF { + err = errors.New("rpcreplay: missing initial state") + } + return bytes, err +} + +func writeEntry(w io.Writer, e *entry) error { + var m proto.Message + if e.msg.err != nil && e.msg.err != io.EOF { + s, ok := status.FromError(e.msg.err) + if !ok { + return fmt.Errorf("rpcreplay: error %v is not a Status", e.msg.err) + } + m = s.Proto() + } else { + m = e.msg.msg + } + var a *any.Any + var err error + if m != nil { + a, err = ptypes.MarshalAny(m) + if err != nil { + return err + } + } + pe := &pb.Entry{ + Kind: e.kind, + Method: e.method, + Message: a, + IsError: e.msg.err != nil, + RefIndex: int32(e.refIndex), + } + bytes, err := proto.Marshal(pe) + if err != nil { + return err + } + return writeRecord(w, bytes) +} + +func readEntry(r io.Reader) (*entry, error) { + buf, err := readRecord(r) + if err == io.EOF { + return nil, nil + } + if err != nil { + return nil, err + } + var pe pb.Entry + if err := proto.Unmarshal(buf, &pe); err != nil { + return nil, err + } + var msg message + if pe.Message != nil { + var any ptypes.DynamicAny + if err := ptypes.UnmarshalAny(pe.Message, &any); err != nil { + return nil, err + } + if pe.IsError { + msg.err = status.ErrorProto(any.Message.(*spb.Status)) + } else { + msg.msg = any.Message + } + } else if pe.IsError { + msg.err = io.EOF + } else if pe.Kind != pb.Entry_CREATE_STREAM { + return nil, errors.New("rpcreplay: entry with nil message and false is_error") + } + return &entry{ + kind: pe.Kind, + method: pe.Method, + msg: msg, + refIndex: int(pe.RefIndex), + }, nil +} + +// A record consists of an unsigned 32-bit little-endian length L followed by L +// bytes. + +func writeRecord(w io.Writer, data []byte) error { + if err := binary.Write(w, binary.LittleEndian, uint32(len(data))); err != nil { + return err + } + _, err := w.Write(data) + return err +} + +func readRecord(r io.Reader) ([]byte, error) { + var size uint32 + if err := binary.Read(r, binary.LittleEndian, &size); err != nil { + return nil, err + } + buf := make([]byte, size) + if _, err := io.ReadFull(r, buf); err != nil { + return nil, err + } + return buf, nil +} diff --git a/vendor/cloud.google.com/go/rpcreplay/rpcreplay_test.go b/vendor/cloud.google.com/go/rpcreplay/rpcreplay_test.go new file mode 100644 index 00000000..64616c40 --- /dev/null +++ b/vendor/cloud.google.com/go/rpcreplay/rpcreplay_test.go @@ -0,0 +1,564 @@ +// Copyright 2017 Google LLC +// +// 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 rpcreplay + +import ( + "bytes" + "context" + "errors" + "io" + "strings" + "testing" + + "cloud.google.com/go/internal/testutil" + ipb "cloud.google.com/go/rpcreplay/proto/intstore" + rpb "cloud.google.com/go/rpcreplay/proto/rpcreplay" + "github.com/golang/protobuf/proto" + "github.com/google/go-cmp/cmp" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestRecordIO(t *testing.T) { + buf := &bytes.Buffer{} + want := []byte{1, 2, 3} + if err := writeRecord(buf, want); err != nil { + t.Fatal(err) + } + got, err := readRecord(buf) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(got, want) { + t.Errorf("got %v, want %v", got, want) + } +} + +func TestHeaderIO(t *testing.T) { + buf := &bytes.Buffer{} + want := []byte{1, 2, 3} + if err := writeHeader(buf, want); err != nil { + t.Fatal(err) + } + got, err := readHeader(buf) + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(got, want) { + t.Errorf("got %v, want %v", got, want) + } + + // readHeader errors + for _, contents := range []string{"", "badmagic", "gRPCReplay"} { + if _, err := readHeader(bytes.NewBufferString(contents)); err == nil { + t.Errorf("%q: got nil, want error", contents) + } + } +} + +func TestEntryIO(t *testing.T) { + for i, want := range []*entry{ + { + kind: rpb.Entry_REQUEST, + method: "method", + msg: message{msg: &rpb.Entry{}}, + refIndex: 7, + }, + { + kind: rpb.Entry_RESPONSE, + method: "method", + msg: message{err: status.Error(codes.NotFound, "not found")}, + refIndex: 8, + }, + { + kind: rpb.Entry_RECV, + method: "method", + msg: message{err: io.EOF}, + refIndex: 3, + }, + } { + buf := &bytes.Buffer{} + if err := writeEntry(buf, want); err != nil { + t.Fatal(err) + } + got, err := readEntry(buf) + if err != nil { + t.Fatal(err) + } + if !got.equal(want) { + t.Errorf("#%d: got %v, want %v", i, got, want) + } + } +} + +var initialState = []byte{1, 2, 3} + +func TestRecord(t *testing.T) { + srv := newIntStoreServer() + defer srv.stop() + buf := record(t, srv) + + gotIstate, err := readHeader(buf) + if err != nil { + t.Fatal(err) + } + if !testutil.Equal(gotIstate, initialState) { + t.Fatalf("got %v, want %v", gotIstate, initialState) + } + item := &ipb.Item{Name: "a", Value: 1} + wantEntries := []*entry{ + // Set + { + kind: rpb.Entry_REQUEST, + method: "/intstore.IntStore/Set", + msg: message{msg: item}, + }, + { + kind: rpb.Entry_RESPONSE, + msg: message{msg: &ipb.SetResponse{PrevValue: 0}}, + refIndex: 1, + }, + // Get + { + kind: rpb.Entry_REQUEST, + method: "/intstore.IntStore/Get", + msg: message{msg: &ipb.GetRequest{Name: "a"}}, + }, + { + kind: rpb.Entry_RESPONSE, + msg: message{msg: item}, + refIndex: 3, + }, + { + kind: rpb.Entry_REQUEST, + method: "/intstore.IntStore/Get", + msg: message{msg: &ipb.GetRequest{Name: "x"}}, + }, + { + kind: rpb.Entry_RESPONSE, + msg: message{err: status.Error(codes.NotFound, `"x"`)}, + refIndex: 5, + }, + // ListItems + { // entry #7 + kind: rpb.Entry_CREATE_STREAM, + method: "/intstore.IntStore/ListItems", + }, + { + kind: rpb.Entry_SEND, + msg: message{msg: &ipb.ListItemsRequest{}}, + refIndex: 7, + }, + { + kind: rpb.Entry_RECV, + msg: message{msg: item}, + refIndex: 7, + }, + { + kind: rpb.Entry_RECV, + msg: message{err: io.EOF}, + refIndex: 7, + }, + // SetStream + { // entry #11 + kind: rpb.Entry_CREATE_STREAM, + method: "/intstore.IntStore/SetStream", + }, + { + kind: rpb.Entry_SEND, + msg: message{msg: &ipb.Item{Name: "b", Value: 2}}, + refIndex: 11, + }, + { + kind: rpb.Entry_SEND, + msg: message{msg: &ipb.Item{Name: "c", Value: 3}}, + refIndex: 11, + }, + { + kind: rpb.Entry_RECV, + msg: message{msg: &ipb.Summary{Count: 2}}, + refIndex: 11, + }, + + // StreamChat + { // entry #15 + kind: rpb.Entry_CREATE_STREAM, + method: "/intstore.IntStore/StreamChat", + }, + { + kind: rpb.Entry_SEND, + msg: message{msg: &ipb.Item{Name: "d", Value: 4}}, + refIndex: 15, + }, + { + kind: rpb.Entry_RECV, + msg: message{msg: &ipb.Item{Name: "d", Value: 4}}, + refIndex: 15, + }, + { + kind: rpb.Entry_SEND, + msg: message{msg: &ipb.Item{Name: "e", Value: 5}}, + refIndex: 15, + }, + { + kind: rpb.Entry_RECV, + msg: message{msg: &ipb.Item{Name: "e", Value: 5}}, + refIndex: 15, + }, + { + kind: rpb.Entry_RECV, + msg: message{err: io.EOF}, + refIndex: 15, + }, + } + for i, w := range wantEntries { + g, err := readEntry(buf) + if err != nil { + t.Fatalf("#%d: %v", i+1, err) + } + if !g.equal(w) { + t.Errorf("#%d:\ngot %+v\nwant %+v", i+1, g, w) + } + } + g, err := readEntry(buf) + if err != nil { + t.Fatal(err) + } + if g != nil { + t.Errorf("\ngot %+v\nwant nil", g) + } +} + +func TestReplay(t *testing.T) { + srv := newIntStoreServer() + defer srv.stop() + + buf := record(t, srv) + rep, err := NewReplayerReader(buf) + if err != nil { + t.Fatal(err) + } + if got, want := rep.Initial(), initialState; !testutil.Equal(got, want) { + t.Fatalf("got %v, want %v", got, want) + } + // Replay the test. + testService(t, srv.Addr, rep.DialOptions()) +} + +func record(t *testing.T, srv *intStoreServer) *bytes.Buffer { + buf := &bytes.Buffer{} + rec, err := NewRecorderWriter(buf, initialState) + if err != nil { + t.Fatal(err) + } + testService(t, srv.Addr, rec.DialOptions()) + if err := rec.Close(); err != nil { + t.Fatal(err) + } + return buf +} + +func testService(t *testing.T, addr string, opts []grpc.DialOption) { + conn, err := grpc.Dial(addr, + append([]grpc.DialOption{grpc.WithInsecure()}, opts...)...) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + client := ipb.NewIntStoreClient(conn) + ctx := context.Background() + item := &ipb.Item{Name: "a", Value: 1} + res, err := client.Set(ctx, item) + if err != nil { + t.Fatal(err) + } + if res.PrevValue != 0 { + t.Errorf("got %d, want 0", res.PrevValue) + } + got, err := client.Get(ctx, &ipb.GetRequest{Name: "a"}) + if err != nil { + t.Fatal(err) + } + if !proto.Equal(got, item) { + t.Errorf("got %v, want %v", got, item) + } + _, err = client.Get(ctx, &ipb.GetRequest{Name: "x"}) + if err == nil { + t.Fatal("got nil, want error") + } + if _, ok := status.FromError(err); !ok { + t.Errorf("got error type %T, want a grpc/status.Status", err) + } + + wantItems := []*ipb.Item{item} + lic, err := client.ListItems(ctx, &ipb.ListItemsRequest{}) + if err != nil { + t.Fatal(err) + } + for i := 0; ; i++ { + item, err := lic.Recv() + if err == io.EOF { + break + } + if err != nil { + t.Fatal(err) + } + if i >= len(wantItems) || !proto.Equal(item, wantItems[i]) { + t.Fatalf("%d: bad item", i) + } + } + + ssc, err := client.SetStream(ctx) + if err != nil { + t.Fatal(err) + } + + must := func(err error) { + if err != nil { + t.Fatal(err) + } + } + + for i, name := range []string{"b", "c"} { + must(ssc.Send(&ipb.Item{Name: name, Value: int32(i + 2)})) + } + summary, err := ssc.CloseAndRecv() + if err != nil { + t.Fatal(err) + } + if got, want := summary.Count, int32(2); got != want { + t.Fatalf("got %d, want %d", got, want) + } + + chatc, err := client.StreamChat(ctx) + if err != nil { + t.Fatal(err) + } + for i, name := range []string{"d", "e"} { + item := &ipb.Item{Name: name, Value: int32(i + 4)} + must(chatc.Send(item)) + got, err := chatc.Recv() + if err != nil { + t.Fatal(err) + } + if !proto.Equal(got, item) { + t.Errorf("got %v, want %v", got, item) + } + } + must(chatc.CloseSend()) + if _, err := chatc.Recv(); err != io.EOF { + t.Fatalf("got %v, want EOF", err) + } +} + +func TestRecorderBeforeFunc(t *testing.T) { + var tests = []struct { + name string + msg, wantRespMsg, wantEntryMsg *ipb.Item + f func(string, proto.Message) error + wantErr bool + }{ + { + name: "BeforeFunc should modify messages saved, but not alter what is sent/received to/from services", + msg: &ipb.Item{Name: "foo", Value: 1}, + wantEntryMsg: &ipb.Item{Name: "bar", Value: 2}, + wantRespMsg: &ipb.Item{Name: "foo", Value: 1}, + f: func(method string, m proto.Message) error { + // This callback only runs when Set is called. + if !strings.HasSuffix(method, "Set") { + return nil + } + if _, ok := m.(*ipb.Item); !ok { + return nil + } + + item := m.(*ipb.Item) + item.Name = "bar" + item.Value = 2 + return nil + }, + }, + { + name: "BeforeFunc should not be able to alter returned responses", + msg: &ipb.Item{Name: "foo", Value: 1}, + wantRespMsg: &ipb.Item{Name: "foo", Value: 1}, + f: func(method string, m proto.Message) error { + // This callback only runs when Get is called. + if !strings.HasSuffix(method, "Get") { + return nil + } + if _, ok := m.(*ipb.Item); !ok { + return nil + } + + item := m.(*ipb.Item) + item.Value = 2 + return nil + }, + }, + { + name: "Errors should cause the RPC send to fail", + msg: &ipb.Item{}, + f: func(_ string, _ proto.Message) error { + return errors.New("err") + }, + wantErr: true, + }, + } + + for _, tc := range tests { + // Wrap test cases in a func so defers execute correctly. + func() { + srv := newIntStoreServer() + defer srv.stop() + + var b bytes.Buffer + r, err := NewRecorderWriter(&b, nil) + if err != nil { + t.Error(err) + return + } + r.BeforeFunc = tc.f + ctx := context.Background() + conn, err := grpc.DialContext(ctx, srv.Addr, append([]grpc.DialOption{grpc.WithInsecure()}, r.DialOptions()...)...) + if err != nil { + t.Error(err) + return + } + defer conn.Close() + + client := ipb.NewIntStoreClient(conn) + _, err = client.Set(ctx, tc.msg) + switch { + case err != nil && !tc.wantErr: + t.Error(err) + return + case err == nil && tc.wantErr: + t.Errorf("got nil; want error") + return + case err != nil: + // Error found as expected, don't check Get(). + return + } + + if tc.wantRespMsg != nil { + got, err := client.Get(ctx, &ipb.GetRequest{Name: tc.msg.GetName()}) + if err != nil { + t.Error(err) + return + } + if !cmp.Equal(got, tc.wantRespMsg) { + t.Errorf("got %+v; want %+v", got, tc.wantRespMsg) + } + } + + r.Close() + + if tc.wantEntryMsg != nil { + _, _ = readHeader(&b) + e, err := readEntry(&b) + if err != nil { + t.Error(err) + return + } + got := e.msg.msg.(*ipb.Item) + if !cmp.Equal(got, tc.wantEntryMsg) { + t.Errorf("got %v; want %v", got, tc.wantEntryMsg) + } + } + }() + } +} + +func TestReplayerBeforeFunc(t *testing.T) { + var tests = []struct { + name string + msg, reqMsg *ipb.Item + f func(string, proto.Message) error + wantErr bool + }{ + { + name: "BeforeFunc should modify messages sent before they are passed to the replayer", + msg: &ipb.Item{Name: "foo", Value: 1}, + reqMsg: &ipb.Item{Name: "bar", Value: 1}, + f: func(method string, m proto.Message) error { + item := m.(*ipb.Item) + item.Name = "foo" + return nil + }, + }, + { + name: "Errors should cause the RPC send to fail", + msg: &ipb.Item{}, + f: func(_ string, _ proto.Message) error { + return errors.New("err") + }, + wantErr: true, + }, + } + + for _, tc := range tests { + // Wrap test cases in a func so defers execute correctly. + func() { + srv := newIntStoreServer() + defer srv.stop() + + var b bytes.Buffer + rec, err := NewRecorderWriter(&b, nil) + if err != nil { + t.Error(err) + return + } + ctx := context.Background() + conn, err := grpc.DialContext(ctx, srv.Addr, append([]grpc.DialOption{grpc.WithInsecure()}, rec.DialOptions()...)...) + if err != nil { + t.Error(err) + return + } + defer conn.Close() + + client := ipb.NewIntStoreClient(conn) + _, err = client.Set(ctx, tc.msg) + if err != nil { + t.Error(err) + return + } + rec.Close() + + rep, err := NewReplayerReader(&b) + if err != nil { + t.Error(err) + return + } + rep.BeforeFunc = tc.f + conn, err = grpc.DialContext(ctx, srv.Addr, append([]grpc.DialOption{grpc.WithInsecure()}, rep.DialOptions()...)...) + if err != nil { + t.Error(err) + return + } + defer conn.Close() + + client = ipb.NewIntStoreClient(conn) + _, err = client.Set(ctx, tc.reqMsg) + switch { + case err != nil && !tc.wantErr: + t.Error(err) + case err == nil && tc.wantErr: + t.Errorf("got nil; want error") + } + }() + } +} diff --git a/vendor/cloud.google.com/go/run-tests.sh b/vendor/cloud.google.com/go/run-tests.sh new file mode 100755 index 00000000..a643e61c --- /dev/null +++ b/vendor/cloud.google.com/go/run-tests.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +# Selectively run tests for this repo, based on what has changed +# in a commit. Runs short tests for the whole repo, and full tests +# for changed directories. + +set -e + +prefix=cloud.google.com/go + +dryrun=false +if [[ $1 == "-n" ]]; then + dryrun=true + shift +fi + +if [[ $1 == "" ]]; then + echo >&2 "usage: $0 [-n] COMMIT" + exit 1 +fi + +# Files or directories that cause all tests to run if modified. +declare -A run_all +run_all=([.travis.yml]=1 [run-tests.sh]=1) + +function run { + if $dryrun; then + echo $* + else + (set -x; $*) + fi +} + + +# Find all the packages that have changed in this commit. +declare -A changed_packages + +for f in $(git diff-tree --no-commit-id --name-only -r $1); do + if [[ ${run_all[$f]} == 1 ]]; then + # This change requires a full test. Do it and exit. + run go test -race -v $prefix/... + exit + fi + # Map, e.g., "spanner/client.go" to "$prefix/spanner". + d=$(dirname $f) + if [[ $d == "." ]]; then + pkg=$prefix + else + pkg=$prefix/$d + fi + changed_packages[$pkg]=1 +done + +echo "changed packages: ${!changed_packages[*]}" + + +# Reports whether its argument, a package name, depends (recursively) +# on a changed package. +function depends_on_changed_package { + # According to go list, a package does not depend on itself, so + # we test that separately. + if [[ ${changed_packages[$1]} == 1 ]]; then + return 0 + fi + for dep in $(go list -f '{{range .Deps}}{{.}} {{end}}' $1); do + if [[ ${changed_packages[$dep]} == 1 ]]; then + return 0 + fi + done + return 1 +} + +# Collect the packages into two separate lists. (It is faster to call "go test" on a +# list of packages than to individually "go test" each one.) + +shorts= +fulls= +for pkg in $(go list $prefix/...); do # for each package in the repo + if depends_on_changed_package $pkg; then # if it depends on a changed package + fulls="$fulls $pkg" # run the full test + else # otherwise + shorts="$shorts $pkg" # run the short test + fi +done +run go test -race -v -short $shorts +if [[ $fulls != "" ]]; then + run go test -race -v $fulls +fi diff --git a/vendor/cloud.google.com/go/scheduler/apiv1beta1/cloud_scheduler_client.go b/vendor/cloud.google.com/go/scheduler/apiv1beta1/cloud_scheduler_client.go new file mode 100644 index 00000000..c14c48c4 --- /dev/null +++ b/vendor/cloud.google.com/go/scheduler/apiv1beta1/cloud_scheduler_client.go @@ -0,0 +1,344 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package scheduler + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + schedulerpb "google.golang.org/genproto/googleapis/cloud/scheduler/v1beta1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CloudSchedulerCallOptions contains the retry settings for each method of CloudSchedulerClient. +type CloudSchedulerCallOptions struct { + ListJobs []gax.CallOption + GetJob []gax.CallOption + CreateJob []gax.CallOption + UpdateJob []gax.CallOption + DeleteJob []gax.CallOption + PauseJob []gax.CallOption + ResumeJob []gax.CallOption + RunJob []gax.CallOption +} + +func defaultCloudSchedulerClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("cloudscheduler.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCloudSchedulerCallOptions() *CloudSchedulerCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CloudSchedulerCallOptions{ + ListJobs: retry[[2]string{"default", "idempotent"}], + GetJob: retry[[2]string{"default", "idempotent"}], + CreateJob: retry[[2]string{"default", "non_idempotent"}], + UpdateJob: retry[[2]string{"default", "non_idempotent"}], + DeleteJob: retry[[2]string{"default", "idempotent"}], + PauseJob: retry[[2]string{"default", "idempotent"}], + ResumeJob: retry[[2]string{"default", "idempotent"}], + RunJob: retry[[2]string{"default", "non_idempotent"}], + } +} + +// CloudSchedulerClient is a client for interacting with Cloud Scheduler API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type CloudSchedulerClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + cloudSchedulerClient schedulerpb.CloudSchedulerClient + + // The call options for this service. + CallOptions *CloudSchedulerCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewCloudSchedulerClient creates a new cloud scheduler client. +// +// The Cloud Scheduler API allows external entities to reliably +// schedule asynchronous jobs. +func NewCloudSchedulerClient(ctx context.Context, opts ...option.ClientOption) (*CloudSchedulerClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultCloudSchedulerClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &CloudSchedulerClient{ + conn: conn, + CallOptions: defaultCloudSchedulerCallOptions(), + + cloudSchedulerClient: schedulerpb.NewCloudSchedulerClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *CloudSchedulerClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *CloudSchedulerClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *CloudSchedulerClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListJobs lists jobs. +func (c *CloudSchedulerClient) ListJobs(ctx context.Context, req *schedulerpb.ListJobsRequest, opts ...gax.CallOption) *JobIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListJobs[0:len(c.CallOptions.ListJobs):len(c.CallOptions.ListJobs)], opts...) + it := &JobIterator{} + req = proto.Clone(req).(*schedulerpb.ListJobsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*schedulerpb.Job, string, error) { + var resp *schedulerpb.ListJobsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudSchedulerClient.ListJobs(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Jobs, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetJob gets a job. +func (c *CloudSchedulerClient) GetJob(ctx context.Context, req *schedulerpb.GetJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetJob[0:len(c.CallOptions.GetJob):len(c.CallOptions.GetJob)], opts...) + var resp *schedulerpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudSchedulerClient.GetJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateJob creates a job. +func (c *CloudSchedulerClient) CreateJob(ctx context.Context, req *schedulerpb.CreateJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateJob[0:len(c.CallOptions.CreateJob):len(c.CallOptions.CreateJob)], opts...) + var resp *schedulerpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudSchedulerClient.CreateJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateJob updates a job. +// +// If successful, the updated [Job][google.cloud.scheduler.v1beta1.Job] is returned. If the job does +// not exist, NOT_FOUND is returned. +// +// If UpdateJob does not successfully return, it is possible for the +// job to be in an [Job.State.UPDATE_FAILED][google.cloud.scheduler.v1beta1.Job.State.UPDATE_FAILED] state. A job in this state may +// not be executed. If this happens, retry the UpdateJob request +// until a successful response is received. +func (c *CloudSchedulerClient) UpdateJob(ctx context.Context, req *schedulerpb.UpdateJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateJob[0:len(c.CallOptions.UpdateJob):len(c.CallOptions.UpdateJob)], opts...) + var resp *schedulerpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudSchedulerClient.UpdateJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteJob deletes a job. +func (c *CloudSchedulerClient) DeleteJob(ctx context.Context, req *schedulerpb.DeleteJobRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteJob[0:len(c.CallOptions.DeleteJob):len(c.CallOptions.DeleteJob)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.cloudSchedulerClient.DeleteJob(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// PauseJob pauses a job. +// +// If a job is paused then the system will stop executing the job +// until it is re-enabled via [ResumeJob][google.cloud.scheduler.v1beta1.CloudScheduler.ResumeJob]. The +// state of the job is stored in [state][google.cloud.scheduler.v1beta1.Job.state]; if paused it +// will be set to [Job.State.PAUSED][google.cloud.scheduler.v1beta1.Job.State.PAUSED]. A job must be in [Job.State.ENABLED][google.cloud.scheduler.v1beta1.Job.State.ENABLED] +// to be paused. +func (c *CloudSchedulerClient) PauseJob(ctx context.Context, req *schedulerpb.PauseJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.PauseJob[0:len(c.CallOptions.PauseJob):len(c.CallOptions.PauseJob)], opts...) + var resp *schedulerpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudSchedulerClient.PauseJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ResumeJob resume a job. +// +// This method reenables a job after it has been [Job.State.PAUSED][google.cloud.scheduler.v1beta1.Job.State.PAUSED]. The +// state of a job is stored in [Job.state][google.cloud.scheduler.v1beta1.Job.state]; after calling this method it +// will be set to [Job.State.ENABLED][google.cloud.scheduler.v1beta1.Job.State.ENABLED]. A job must be in +// [Job.State.PAUSED][google.cloud.scheduler.v1beta1.Job.State.PAUSED] to be resumed. +func (c *CloudSchedulerClient) ResumeJob(ctx context.Context, req *schedulerpb.ResumeJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ResumeJob[0:len(c.CallOptions.ResumeJob):len(c.CallOptions.ResumeJob)], opts...) + var resp *schedulerpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudSchedulerClient.ResumeJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// RunJob forces a job to run now. +// +// When this method is called, Cloud Scheduler will dispatch the job, even +// if the job is already running. +func (c *CloudSchedulerClient) RunJob(ctx context.Context, req *schedulerpb.RunJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.RunJob[0:len(c.CallOptions.RunJob):len(c.CallOptions.RunJob)], opts...) + var resp *schedulerpb.Job + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.cloudSchedulerClient.RunJob(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// JobIterator manages a stream of *schedulerpb.Job. +type JobIterator struct { + items []*schedulerpb.Job + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*schedulerpb.Job, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *JobIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *JobIterator) Next() (*schedulerpb.Job, error) { + var item *schedulerpb.Job + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *JobIterator) bufLen() int { + return len(it.items) +} + +func (it *JobIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/scheduler/apiv1beta1/cloud_scheduler_client_example_test.go b/vendor/cloud.google.com/go/scheduler/apiv1beta1/cloud_scheduler_client_example_test.go new file mode 100644 index 00000000..f748ba05 --- /dev/null +++ b/vendor/cloud.google.com/go/scheduler/apiv1beta1/cloud_scheduler_client_example_test.go @@ -0,0 +1,183 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package scheduler_test + +import ( + "context" + + scheduler "cloud.google.com/go/scheduler/apiv1beta1" + "google.golang.org/api/iterator" + schedulerpb "google.golang.org/genproto/googleapis/cloud/scheduler/v1beta1" +) + +func ExampleNewCloudSchedulerClient() { + ctx := context.Background() + c, err := scheduler.NewCloudSchedulerClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleCloudSchedulerClient_ListJobs() { + ctx := context.Background() + c, err := scheduler.NewCloudSchedulerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &schedulerpb.ListJobsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListJobs(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleCloudSchedulerClient_GetJob() { + ctx := context.Background() + c, err := scheduler.NewCloudSchedulerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &schedulerpb.GetJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleCloudSchedulerClient_CreateJob() { + ctx := context.Background() + c, err := scheduler.NewCloudSchedulerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &schedulerpb.CreateJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleCloudSchedulerClient_UpdateJob() { + ctx := context.Background() + c, err := scheduler.NewCloudSchedulerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &schedulerpb.UpdateJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleCloudSchedulerClient_DeleteJob() { + ctx := context.Background() + c, err := scheduler.NewCloudSchedulerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &schedulerpb.DeleteJobRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteJob(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleCloudSchedulerClient_PauseJob() { + ctx := context.Background() + c, err := scheduler.NewCloudSchedulerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &schedulerpb.PauseJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.PauseJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleCloudSchedulerClient_ResumeJob() { + ctx := context.Background() + c, err := scheduler.NewCloudSchedulerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &schedulerpb.ResumeJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ResumeJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleCloudSchedulerClient_RunJob() { + ctx := context.Background() + c, err := scheduler.NewCloudSchedulerClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &schedulerpb.RunJobRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.RunJob(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/scheduler/apiv1beta1/doc.go b/vendor/cloud.google.com/go/scheduler/apiv1beta1/doc.go new file mode 100644 index 00000000..1fbb60a8 --- /dev/null +++ b/vendor/cloud.google.com/go/scheduler/apiv1beta1/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package scheduler is an auto-generated package for the +// Cloud Scheduler API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Creates and manages jobs run on a regular recurring schedule. +package scheduler // import "cloud.google.com/go/scheduler/apiv1beta1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/scheduler/apiv1beta1/mock_test.go b/vendor/cloud.google.com/go/scheduler/apiv1beta1/mock_test.go new file mode 100644 index 00000000..19fd1f9c --- /dev/null +++ b/vendor/cloud.google.com/go/scheduler/apiv1beta1/mock_test.go @@ -0,0 +1,706 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package scheduler + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + schedulerpb "google.golang.org/genproto/googleapis/cloud/scheduler/v1beta1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockCloudSchedulerServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + schedulerpb.CloudSchedulerServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockCloudSchedulerServer) ListJobs(ctx context.Context, req *schedulerpb.ListJobsRequest) (*schedulerpb.ListJobsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*schedulerpb.ListJobsResponse), nil +} + +func (s *mockCloudSchedulerServer) GetJob(ctx context.Context, req *schedulerpb.GetJobRequest) (*schedulerpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*schedulerpb.Job), nil +} + +func (s *mockCloudSchedulerServer) CreateJob(ctx context.Context, req *schedulerpb.CreateJobRequest) (*schedulerpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*schedulerpb.Job), nil +} + +func (s *mockCloudSchedulerServer) UpdateJob(ctx context.Context, req *schedulerpb.UpdateJobRequest) (*schedulerpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*schedulerpb.Job), nil +} + +func (s *mockCloudSchedulerServer) DeleteJob(ctx context.Context, req *schedulerpb.DeleteJobRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockCloudSchedulerServer) PauseJob(ctx context.Context, req *schedulerpb.PauseJobRequest) (*schedulerpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*schedulerpb.Job), nil +} + +func (s *mockCloudSchedulerServer) ResumeJob(ctx context.Context, req *schedulerpb.ResumeJobRequest) (*schedulerpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*schedulerpb.Job), nil +} + +func (s *mockCloudSchedulerServer) RunJob(ctx context.Context, req *schedulerpb.RunJobRequest) (*schedulerpb.Job, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*schedulerpb.Job), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockCloudScheduler mockCloudSchedulerServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + schedulerpb.RegisterCloudSchedulerServer(serv, &mockCloudScheduler) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestCloudSchedulerListJobs(t *testing.T) { + var nextPageToken string = "" + var jobsElement *schedulerpb.Job = &schedulerpb.Job{} + var jobs = []*schedulerpb.Job{jobsElement} + var expectedResponse = &schedulerpb.ListJobsResponse{ + NextPageToken: nextPageToken, + Jobs: jobs, + } + + mockCloudScheduler.err = nil + mockCloudScheduler.reqs = nil + + mockCloudScheduler.resps = append(mockCloudScheduler.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &schedulerpb.ListJobsRequest{ + Parent: formattedParent, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListJobs(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudScheduler.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Jobs[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudSchedulerListJobsError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudScheduler.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &schedulerpb.ListJobsRequest{ + Parent: formattedParent, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListJobs(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudSchedulerGetJob(t *testing.T) { + var name2 string = "name2-1052831874" + var description string = "description-1724546052" + var schedule string = "schedule-697920873" + var timeZone string = "timeZone36848094" + var expectedResponse = &schedulerpb.Job{ + Name: name2, + Description: description, + Schedule: schedule, + TimeZone: timeZone, + } + + mockCloudScheduler.err = nil + mockCloudScheduler.reqs = nil + + mockCloudScheduler.resps = append(mockCloudScheduler.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/jobs/%s", "[PROJECT]", "[LOCATION]", "[JOB]") + var request = &schedulerpb.GetJobRequest{ + Name: formattedName, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudScheduler.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudSchedulerGetJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudScheduler.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/jobs/%s", "[PROJECT]", "[LOCATION]", "[JOB]") + var request = &schedulerpb.GetJobRequest{ + Name: formattedName, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudSchedulerCreateJob(t *testing.T) { + var name string = "name3373707" + var description string = "description-1724546052" + var schedule string = "schedule-697920873" + var timeZone string = "timeZone36848094" + var expectedResponse = &schedulerpb.Job{ + Name: name, + Description: description, + Schedule: schedule, + TimeZone: timeZone, + } + + mockCloudScheduler.err = nil + mockCloudScheduler.reqs = nil + + mockCloudScheduler.resps = append(mockCloudScheduler.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var job *schedulerpb.Job = &schedulerpb.Job{} + var request = &schedulerpb.CreateJobRequest{ + Parent: formattedParent, + Job: job, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudScheduler.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudSchedulerCreateJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudScheduler.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var job *schedulerpb.Job = &schedulerpb.Job{} + var request = &schedulerpb.CreateJobRequest{ + Parent: formattedParent, + Job: job, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudSchedulerUpdateJob(t *testing.T) { + var name string = "name3373707" + var description string = "description-1724546052" + var schedule string = "schedule-697920873" + var timeZone string = "timeZone36848094" + var expectedResponse = &schedulerpb.Job{ + Name: name, + Description: description, + Schedule: schedule, + TimeZone: timeZone, + } + + mockCloudScheduler.err = nil + mockCloudScheduler.reqs = nil + + mockCloudScheduler.resps = append(mockCloudScheduler.resps[:0], expectedResponse) + + var job *schedulerpb.Job = &schedulerpb.Job{} + var request = &schedulerpb.UpdateJobRequest{ + Job: job, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudScheduler.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudSchedulerUpdateJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudScheduler.err = gstatus.Error(errCode, "test error") + + var job *schedulerpb.Job = &schedulerpb.Job{} + var request = &schedulerpb.UpdateJobRequest{ + Job: job, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudSchedulerDeleteJob(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockCloudScheduler.err = nil + mockCloudScheduler.reqs = nil + + mockCloudScheduler.resps = append(mockCloudScheduler.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/jobs/%s", "[PROJECT]", "[LOCATION]", "[JOB]") + var request = &schedulerpb.DeleteJobRequest{ + Name: formattedName, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudScheduler.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestCloudSchedulerDeleteJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudScheduler.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/jobs/%s", "[PROJECT]", "[LOCATION]", "[JOB]") + var request = &schedulerpb.DeleteJobRequest{ + Name: formattedName, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestCloudSchedulerPauseJob(t *testing.T) { + var name2 string = "name2-1052831874" + var description string = "description-1724546052" + var schedule string = "schedule-697920873" + var timeZone string = "timeZone36848094" + var expectedResponse = &schedulerpb.Job{ + Name: name2, + Description: description, + Schedule: schedule, + TimeZone: timeZone, + } + + mockCloudScheduler.err = nil + mockCloudScheduler.reqs = nil + + mockCloudScheduler.resps = append(mockCloudScheduler.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/jobs/%s", "[PROJECT]", "[LOCATION]", "[JOB]") + var request = &schedulerpb.PauseJobRequest{ + Name: formattedName, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PauseJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudScheduler.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudSchedulerPauseJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudScheduler.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/jobs/%s", "[PROJECT]", "[LOCATION]", "[JOB]") + var request = &schedulerpb.PauseJobRequest{ + Name: formattedName, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PauseJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudSchedulerResumeJob(t *testing.T) { + var name2 string = "name2-1052831874" + var description string = "description-1724546052" + var schedule string = "schedule-697920873" + var timeZone string = "timeZone36848094" + var expectedResponse = &schedulerpb.Job{ + Name: name2, + Description: description, + Schedule: schedule, + TimeZone: timeZone, + } + + mockCloudScheduler.err = nil + mockCloudScheduler.reqs = nil + + mockCloudScheduler.resps = append(mockCloudScheduler.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/jobs/%s", "[PROJECT]", "[LOCATION]", "[JOB]") + var request = &schedulerpb.ResumeJobRequest{ + Name: formattedName, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ResumeJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudScheduler.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudSchedulerResumeJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudScheduler.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/jobs/%s", "[PROJECT]", "[LOCATION]", "[JOB]") + var request = &schedulerpb.ResumeJobRequest{ + Name: formattedName, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ResumeJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestCloudSchedulerRunJob(t *testing.T) { + var name2 string = "name2-1052831874" + var description string = "description-1724546052" + var schedule string = "schedule-697920873" + var timeZone string = "timeZone36848094" + var expectedResponse = &schedulerpb.Job{ + Name: name2, + Description: description, + Schedule: schedule, + TimeZone: timeZone, + } + + mockCloudScheduler.err = nil + mockCloudScheduler.reqs = nil + + mockCloudScheduler.resps = append(mockCloudScheduler.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/jobs/%s", "[PROJECT]", "[LOCATION]", "[JOB]") + var request = &schedulerpb.RunJobRequest{ + Name: formattedName, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RunJob(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockCloudScheduler.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestCloudSchedulerRunJobError(t *testing.T) { + errCode := codes.PermissionDenied + mockCloudScheduler.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/jobs/%s", "[PROJECT]", "[LOCATION]", "[JOB]") + var request = &schedulerpb.RunJobRequest{ + Name: formattedName, + } + + c, err := NewCloudSchedulerClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.RunJob(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/securitycenter/apiv1beta1/doc.go b/vendor/cloud.google.com/go/securitycenter/apiv1beta1/doc.go new file mode 100644 index 00000000..65c6e995 --- /dev/null +++ b/vendor/cloud.google.com/go/securitycenter/apiv1beta1/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package securitycenter is an auto-generated package for the +// Cloud Security Command Center API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// The public Cloud Security Command Center API. +package securitycenter // import "cloud.google.com/go/securitycenter/apiv1beta1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/securitycenter/apiv1beta1/mock_test.go b/vendor/cloud.google.com/go/securitycenter/apiv1beta1/mock_test.go new file mode 100644 index 00000000..195c7103 --- /dev/null +++ b/vendor/cloud.google.com/go/securitycenter/apiv1beta1/mock_test.go @@ -0,0 +1,1538 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package securitycenter + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + timestamppb "github.com/golang/protobuf/ptypes/timestamp" + securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1beta1" + iampb "google.golang.org/genproto/googleapis/iam/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockSecurityCenterServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + securitycenterpb.SecurityCenterServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockSecurityCenterServer) CreateSource(ctx context.Context, req *securitycenterpb.CreateSourceRequest) (*securitycenterpb.Source, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.Source), nil +} + +func (s *mockSecurityCenterServer) CreateFinding(ctx context.Context, req *securitycenterpb.CreateFindingRequest) (*securitycenterpb.Finding, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.Finding), nil +} + +func (s *mockSecurityCenterServer) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockSecurityCenterServer) GetOrganizationSettings(ctx context.Context, req *securitycenterpb.GetOrganizationSettingsRequest) (*securitycenterpb.OrganizationSettings, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.OrganizationSettings), nil +} + +func (s *mockSecurityCenterServer) GetSource(ctx context.Context, req *securitycenterpb.GetSourceRequest) (*securitycenterpb.Source, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.Source), nil +} + +func (s *mockSecurityCenterServer) GroupAssets(ctx context.Context, req *securitycenterpb.GroupAssetsRequest) (*securitycenterpb.GroupAssetsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.GroupAssetsResponse), nil +} + +func (s *mockSecurityCenterServer) GroupFindings(ctx context.Context, req *securitycenterpb.GroupFindingsRequest) (*securitycenterpb.GroupFindingsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.GroupFindingsResponse), nil +} + +func (s *mockSecurityCenterServer) ListAssets(ctx context.Context, req *securitycenterpb.ListAssetsRequest) (*securitycenterpb.ListAssetsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.ListAssetsResponse), nil +} + +func (s *mockSecurityCenterServer) ListFindings(ctx context.Context, req *securitycenterpb.ListFindingsRequest) (*securitycenterpb.ListFindingsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.ListFindingsResponse), nil +} + +func (s *mockSecurityCenterServer) ListSources(ctx context.Context, req *securitycenterpb.ListSourcesRequest) (*securitycenterpb.ListSourcesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.ListSourcesResponse), nil +} + +func (s *mockSecurityCenterServer) RunAssetDiscovery(ctx context.Context, req *securitycenterpb.RunAssetDiscoveryRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockSecurityCenterServer) SetFindingState(ctx context.Context, req *securitycenterpb.SetFindingStateRequest) (*securitycenterpb.Finding, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.Finding), nil +} + +func (s *mockSecurityCenterServer) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockSecurityCenterServer) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest) (*iampb.TestIamPermissionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.TestIamPermissionsResponse), nil +} + +func (s *mockSecurityCenterServer) UpdateFinding(ctx context.Context, req *securitycenterpb.UpdateFindingRequest) (*securitycenterpb.Finding, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.Finding), nil +} + +func (s *mockSecurityCenterServer) UpdateOrganizationSettings(ctx context.Context, req *securitycenterpb.UpdateOrganizationSettingsRequest) (*securitycenterpb.OrganizationSettings, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.OrganizationSettings), nil +} + +func (s *mockSecurityCenterServer) UpdateSource(ctx context.Context, req *securitycenterpb.UpdateSourceRequest) (*securitycenterpb.Source, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.Source), nil +} + +func (s *mockSecurityCenterServer) UpdateSecurityMarks(ctx context.Context, req *securitycenterpb.UpdateSecurityMarksRequest) (*securitycenterpb.SecurityMarks, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*securitycenterpb.SecurityMarks), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockSecurityCenter mockSecurityCenterServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + securitycenterpb.RegisterSecurityCenterServer(serv, &mockSecurityCenter) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestSecurityCenterCreateSource(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &securitycenterpb.Source{ + Name: name, + DisplayName: displayName, + Description: description, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var source *securitycenterpb.Source = &securitycenterpb.Source{} + var request = &securitycenterpb.CreateSourceRequest{ + Parent: formattedParent, + Source: source, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSource(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterCreateSourceError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var source *securitycenterpb.Source = &securitycenterpb.Source{} + var request = &securitycenterpb.CreateSourceRequest{ + Parent: formattedParent, + Source: source, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSource(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterCreateFinding(t *testing.T) { + var name string = "name3373707" + var parent2 string = "parent21175163357" + var resourceName string = "resourceName979421212" + var category string = "category50511102" + var externalUri string = "externalUri-1385596168" + var expectedResponse = &securitycenterpb.Finding{ + Name: name, + Parent: parent2, + ResourceName: resourceName, + Category: category, + ExternalUri: externalUri, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var findingId string = "findingId728776081" + var finding *securitycenterpb.Finding = &securitycenterpb.Finding{} + var request = &securitycenterpb.CreateFindingRequest{ + Parent: formattedParent, + FindingId: findingId, + Finding: finding, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateFinding(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterCreateFindingError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var findingId string = "findingId728776081" + var finding *securitycenterpb.Finding = &securitycenterpb.Finding{} + var request = &securitycenterpb.CreateFindingRequest{ + Parent: formattedParent, + FindingId: findingId, + Finding: finding, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateFinding(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterGetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterGetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterGetOrganizationSettings(t *testing.T) { + var name2 string = "name2-1052831874" + var enableAssetDiscovery bool = false + var expectedResponse = &securitycenterpb.OrganizationSettings{ + Name: name2, + EnableAssetDiscovery: enableAssetDiscovery, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("organizations/%s/organizationSettings", "[ORGANIZATION]") + var request = &securitycenterpb.GetOrganizationSettingsRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetOrganizationSettings(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterGetOrganizationSettingsError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("organizations/%s/organizationSettings", "[ORGANIZATION]") + var request = &securitycenterpb.GetOrganizationSettingsRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetOrganizationSettings(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterGetSource(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &securitycenterpb.Source{ + Name: name2, + DisplayName: displayName, + Description: description, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var request = &securitycenterpb.GetSourceRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSource(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterGetSourceError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var request = &securitycenterpb.GetSourceRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSource(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterGroupAssets(t *testing.T) { + var nextPageToken string = "" + var groupByResultsElement *securitycenterpb.GroupResult = &securitycenterpb.GroupResult{} + var groupByResults = []*securitycenterpb.GroupResult{groupByResultsElement} + var expectedResponse = &securitycenterpb.GroupAssetsResponse{ + NextPageToken: nextPageToken, + GroupByResults: groupByResults, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var groupBy string = "groupBy506361367" + var request = &securitycenterpb.GroupAssetsRequest{ + Parent: formattedParent, + GroupBy: groupBy, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GroupAssets(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.GroupByResults[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterGroupAssetsError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var groupBy string = "groupBy506361367" + var request = &securitycenterpb.GroupAssetsRequest{ + Parent: formattedParent, + GroupBy: groupBy, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GroupAssets(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterGroupFindings(t *testing.T) { + var nextPageToken string = "" + var groupByResultsElement *securitycenterpb.GroupResult = &securitycenterpb.GroupResult{} + var groupByResults = []*securitycenterpb.GroupResult{groupByResultsElement} + var expectedResponse = &securitycenterpb.GroupFindingsResponse{ + NextPageToken: nextPageToken, + GroupByResults: groupByResults, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var groupBy string = "groupBy506361367" + var request = &securitycenterpb.GroupFindingsRequest{ + Parent: formattedParent, + GroupBy: groupBy, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GroupFindings(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.GroupByResults[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterGroupFindingsError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var groupBy string = "groupBy506361367" + var request = &securitycenterpb.GroupFindingsRequest{ + Parent: formattedParent, + GroupBy: groupBy, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GroupFindings(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterListAssets(t *testing.T) { + var nextPageToken string = "" + var totalSize int32 = 705419236 + var listAssetsResultsElement *securitycenterpb.ListAssetsResponse_ListAssetsResult = &securitycenterpb.ListAssetsResponse_ListAssetsResult{} + var listAssetsResults = []*securitycenterpb.ListAssetsResponse_ListAssetsResult{listAssetsResultsElement} + var expectedResponse = &securitycenterpb.ListAssetsResponse{ + NextPageToken: nextPageToken, + TotalSize: totalSize, + ListAssetsResults: listAssetsResults, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &securitycenterpb.ListAssetsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListAssets(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.ListAssetsResults[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterListAssetsError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &securitycenterpb.ListAssetsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListAssets(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterListFindings(t *testing.T) { + var nextPageToken string = "" + var totalSize int32 = 705419236 + var findingsElement *securitycenterpb.Finding = &securitycenterpb.Finding{} + var findings = []*securitycenterpb.Finding{findingsElement} + var expectedResponse = &securitycenterpb.ListFindingsResponse{ + NextPageToken: nextPageToken, + TotalSize: totalSize, + Findings: findings, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var request = &securitycenterpb.ListFindingsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListFindings(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Findings[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterListFindingsError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var request = &securitycenterpb.ListFindingsRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListFindings(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterListSources(t *testing.T) { + var nextPageToken string = "" + var sourcesElement *securitycenterpb.Source = &securitycenterpb.Source{} + var sources = []*securitycenterpb.Source{sourcesElement} + var expectedResponse = &securitycenterpb.ListSourcesResponse{ + NextPageToken: nextPageToken, + Sources: sources, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &securitycenterpb.ListSourcesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListSources(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Sources[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterListSourcesError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &securitycenterpb.ListSourcesRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListSources(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterRunAssetDiscovery(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &securitycenterpb.RunAssetDiscoveryRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.RunAssetDiscovery(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestSecurityCenterRunAssetDiscoveryError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = nil + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("organizations/%s", "[ORGANIZATION]") + var request = &securitycenterpb.RunAssetDiscoveryRequest{ + Parent: formattedParent, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.RunAssetDiscovery(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestSecurityCenterSetFindingState(t *testing.T) { + var name2 string = "name2-1052831874" + var parent string = "parent-995424086" + var resourceName string = "resourceName979421212" + var category string = "category50511102" + var externalUri string = "externalUri-1385596168" + var expectedResponse = &securitycenterpb.Finding{ + Name: name2, + Parent: parent, + ResourceName: resourceName, + Category: category, + ExternalUri: externalUri, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("organizations/%s/sources/%s/findings/%s", "[ORGANIZATION]", "[SOURCE]", "[FINDING]") + var state securitycenterpb.Finding_State = securitycenterpb.Finding_STATE_UNSPECIFIED + var startTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var request = &securitycenterpb.SetFindingStateRequest{ + Name: formattedName, + State: state, + StartTime: startTime, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetFindingState(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterSetFindingStateError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("organizations/%s/sources/%s/findings/%s", "[ORGANIZATION]", "[SOURCE]", "[FINDING]") + var state securitycenterpb.Finding_State = securitycenterpb.Finding_STATE_UNSPECIFIED + var startTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var request = &securitycenterpb.SetFindingStateRequest{ + Name: formattedName, + State: state, + StartTime: startTime, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetFindingState(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterSetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterSetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterTestIamPermissions(t *testing.T) { + var expectedResponse *iampb.TestIamPermissionsResponse = &iampb.TestIamPermissionsResponse{} + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterTestIamPermissionsError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("organizations/%s/sources/%s", "[ORGANIZATION]", "[SOURCE]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterUpdateFinding(t *testing.T) { + var name string = "name3373707" + var parent string = "parent-995424086" + var resourceName string = "resourceName979421212" + var category string = "category50511102" + var externalUri string = "externalUri-1385596168" + var expectedResponse = &securitycenterpb.Finding{ + Name: name, + Parent: parent, + ResourceName: resourceName, + Category: category, + ExternalUri: externalUri, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var finding *securitycenterpb.Finding = &securitycenterpb.Finding{} + var request = &securitycenterpb.UpdateFindingRequest{ + Finding: finding, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateFinding(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterUpdateFindingError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var finding *securitycenterpb.Finding = &securitycenterpb.Finding{} + var request = &securitycenterpb.UpdateFindingRequest{ + Finding: finding, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateFinding(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterUpdateOrganizationSettings(t *testing.T) { + var name string = "name3373707" + var enableAssetDiscovery bool = false + var expectedResponse = &securitycenterpb.OrganizationSettings{ + Name: name, + EnableAssetDiscovery: enableAssetDiscovery, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var organizationSettings *securitycenterpb.OrganizationSettings = &securitycenterpb.OrganizationSettings{} + var request = &securitycenterpb.UpdateOrganizationSettingsRequest{ + OrganizationSettings: organizationSettings, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateOrganizationSettings(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterUpdateOrganizationSettingsError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var organizationSettings *securitycenterpb.OrganizationSettings = &securitycenterpb.OrganizationSettings{} + var request = &securitycenterpb.UpdateOrganizationSettingsRequest{ + OrganizationSettings: organizationSettings, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateOrganizationSettings(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterUpdateSource(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var expectedResponse = &securitycenterpb.Source{ + Name: name, + DisplayName: displayName, + Description: description, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var source *securitycenterpb.Source = &securitycenterpb.Source{} + var request = &securitycenterpb.UpdateSourceRequest{ + Source: source, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSource(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterUpdateSourceError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var source *securitycenterpb.Source = &securitycenterpb.Source{} + var request = &securitycenterpb.UpdateSourceRequest{ + Source: source, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSource(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSecurityCenterUpdateSecurityMarks(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &securitycenterpb.SecurityMarks{ + Name: name, + } + + mockSecurityCenter.err = nil + mockSecurityCenter.reqs = nil + + mockSecurityCenter.resps = append(mockSecurityCenter.resps[:0], expectedResponse) + + var securityMarks *securitycenterpb.SecurityMarks = &securitycenterpb.SecurityMarks{} + var request = &securitycenterpb.UpdateSecurityMarksRequest{ + SecurityMarks: securityMarks, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSecurityMarks(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSecurityCenter.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSecurityCenterUpdateSecurityMarksError(t *testing.T) { + errCode := codes.PermissionDenied + mockSecurityCenter.err = gstatus.Error(errCode, "test error") + + var securityMarks *securitycenterpb.SecurityMarks = &securitycenterpb.SecurityMarks{} + var request = &securitycenterpb.UpdateSecurityMarksRequest{ + SecurityMarks: securityMarks, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateSecurityMarks(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/securitycenter/apiv1beta1/security_center_client.go b/vendor/cloud.google.com/go/securitycenter/apiv1beta1/security_center_client.go new file mode 100644 index 00000000..4318fe8e --- /dev/null +++ b/vendor/cloud.google.com/go/securitycenter/apiv1beta1/security_center_client.go @@ -0,0 +1,792 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package securitycenter + +import ( + "context" + "math" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1beta1" + iampb "google.golang.org/genproto/googleapis/iam/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + CreateSource []gax.CallOption + CreateFinding []gax.CallOption + GetIamPolicy []gax.CallOption + GetOrganizationSettings []gax.CallOption + GetSource []gax.CallOption + GroupAssets []gax.CallOption + GroupFindings []gax.CallOption + ListAssets []gax.CallOption + ListFindings []gax.CallOption + ListSources []gax.CallOption + RunAssetDiscovery []gax.CallOption + SetFindingState []gax.CallOption + SetIamPolicy []gax.CallOption + TestIamPermissions []gax.CallOption + UpdateFinding []gax.CallOption + UpdateOrganizationSettings []gax.CallOption + UpdateSource []gax.CallOption + UpdateSecurityMarks []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("securitycenter.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + CreateSource: retry[[2]string{"default", "non_idempotent"}], + CreateFinding: retry[[2]string{"default", "non_idempotent"}], + GetIamPolicy: retry[[2]string{"default", "idempotent"}], + GetOrganizationSettings: retry[[2]string{"default", "idempotent"}], + GetSource: retry[[2]string{"default", "idempotent"}], + GroupAssets: retry[[2]string{"default", "idempotent"}], + GroupFindings: retry[[2]string{"default", "idempotent"}], + ListAssets: retry[[2]string{"default", "idempotent"}], + ListFindings: retry[[2]string{"default", "idempotent"}], + ListSources: retry[[2]string{"default", "idempotent"}], + RunAssetDiscovery: retry[[2]string{"default", "non_idempotent"}], + SetFindingState: retry[[2]string{"default", "non_idempotent"}], + SetIamPolicy: retry[[2]string{"default", "non_idempotent"}], + TestIamPermissions: retry[[2]string{"default", "idempotent"}], + UpdateFinding: retry[[2]string{"default", "non_idempotent"}], + UpdateOrganizationSettings: retry[[2]string{"default", "non_idempotent"}], + UpdateSource: retry[[2]string{"default", "non_idempotent"}], + UpdateSecurityMarks: retry[[2]string{"default", "non_idempotent"}], + } +} + +// Client is a client for interacting with Cloud Security Command Center API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client securitycenterpb.SecurityCenterClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new security center client. +// +// V1 Beta APIs for Security Center service. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: securitycenterpb.NewSecurityCenterClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// CreateSource creates a source. +func (c *Client) CreateSource(ctx context.Context, req *securitycenterpb.CreateSourceRequest, opts ...gax.CallOption) (*securitycenterpb.Source, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateSource[0:len(c.CallOptions.CreateSource):len(c.CallOptions.CreateSource)], opts...) + var resp *securitycenterpb.Source + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateSource(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateFinding creates a finding. The corresponding source must exist for finding creation +// to succeed. +func (c *Client) CreateFinding(ctx context.Context, req *securitycenterpb.CreateFindingRequest, opts ...gax.CallOption) (*securitycenterpb.Finding, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateFinding[0:len(c.CallOptions.CreateFinding):len(c.CallOptions.CreateFinding)], opts...) + var resp *securitycenterpb.Finding + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateFinding(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetIamPolicy gets the access control policy on the specified Source. +func (c *Client) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetIamPolicy[0:len(c.CallOptions.GetIamPolicy):len(c.CallOptions.GetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetOrganizationSettings gets the settings for an organization. +func (c *Client) GetOrganizationSettings(ctx context.Context, req *securitycenterpb.GetOrganizationSettingsRequest, opts ...gax.CallOption) (*securitycenterpb.OrganizationSettings, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetOrganizationSettings[0:len(c.CallOptions.GetOrganizationSettings):len(c.CallOptions.GetOrganizationSettings)], opts...) + var resp *securitycenterpb.OrganizationSettings + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetOrganizationSettings(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetSource gets a source. +func (c *Client) GetSource(ctx context.Context, req *securitycenterpb.GetSourceRequest, opts ...gax.CallOption) (*securitycenterpb.Source, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetSource[0:len(c.CallOptions.GetSource):len(c.CallOptions.GetSource)], opts...) + var resp *securitycenterpb.Source + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetSource(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GroupAssets filters an organization's assets and groups them by their specified +// properties. +func (c *Client) GroupAssets(ctx context.Context, req *securitycenterpb.GroupAssetsRequest, opts ...gax.CallOption) *GroupResultIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GroupAssets[0:len(c.CallOptions.GroupAssets):len(c.CallOptions.GroupAssets)], opts...) + it := &GroupResultIterator{} + req = proto.Clone(req).(*securitycenterpb.GroupAssetsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*securitycenterpb.GroupResult, string, error) { + var resp *securitycenterpb.GroupAssetsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GroupAssets(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.GroupByResults, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GroupFindings filters an organization or source's findings and groups them by their +// specified properties. +// +// To group across all sources provide a - as the source id. +// Example: /v1beta1/organizations/123/sources/-/findings +func (c *Client) GroupFindings(ctx context.Context, req *securitycenterpb.GroupFindingsRequest, opts ...gax.CallOption) *GroupResultIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GroupFindings[0:len(c.CallOptions.GroupFindings):len(c.CallOptions.GroupFindings)], opts...) + it := &GroupResultIterator{} + req = proto.Clone(req).(*securitycenterpb.GroupFindingsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*securitycenterpb.GroupResult, string, error) { + var resp *securitycenterpb.GroupFindingsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GroupFindings(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.GroupByResults, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// ListAssets lists an organization's assets. +func (c *Client) ListAssets(ctx context.Context, req *securitycenterpb.ListAssetsRequest, opts ...gax.CallOption) *ListAssetsResponse_ListAssetsResultIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListAssets[0:len(c.CallOptions.ListAssets):len(c.CallOptions.ListAssets)], opts...) + it := &ListAssetsResponse_ListAssetsResultIterator{} + req = proto.Clone(req).(*securitycenterpb.ListAssetsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*securitycenterpb.ListAssetsResponse_ListAssetsResult, string, error) { + var resp *securitycenterpb.ListAssetsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListAssets(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.ListAssetsResults, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// ListFindings lists an organization or source's findings. +// +// To list across all sources provide a - as the source id. +// Example: /v1beta1/organizations/123/sources/-/findings +func (c *Client) ListFindings(ctx context.Context, req *securitycenterpb.ListFindingsRequest, opts ...gax.CallOption) *FindingIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListFindings[0:len(c.CallOptions.ListFindings):len(c.CallOptions.ListFindings)], opts...) + it := &FindingIterator{} + req = proto.Clone(req).(*securitycenterpb.ListFindingsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*securitycenterpb.Finding, string, error) { + var resp *securitycenterpb.ListFindingsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListFindings(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Findings, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// ListSources lists all sources belonging to an organization. +func (c *Client) ListSources(ctx context.Context, req *securitycenterpb.ListSourcesRequest, opts ...gax.CallOption) *SourceIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListSources[0:len(c.CallOptions.ListSources):len(c.CallOptions.ListSources)], opts...) + it := &SourceIterator{} + req = proto.Clone(req).(*securitycenterpb.ListSourcesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*securitycenterpb.Source, string, error) { + var resp *securitycenterpb.ListSourcesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListSources(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Sources, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// RunAssetDiscovery runs asset discovery. The discovery is tracked with a long-running +// operation. +// +// This API can only be called with limited frequency for an organization. If +// it is called too frequently the caller will receive a TOO_MANY_REQUESTS +// error. +func (c *Client) RunAssetDiscovery(ctx context.Context, req *securitycenterpb.RunAssetDiscoveryRequest, opts ...gax.CallOption) (*RunAssetDiscoveryOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.RunAssetDiscovery[0:len(c.CallOptions.RunAssetDiscovery):len(c.CallOptions.RunAssetDiscovery)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.RunAssetDiscovery(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &RunAssetDiscoveryOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// SetFindingState updates the state of a finding. +func (c *Client) SetFindingState(ctx context.Context, req *securitycenterpb.SetFindingStateRequest, opts ...gax.CallOption) (*securitycenterpb.Finding, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetFindingState[0:len(c.CallOptions.SetFindingState):len(c.CallOptions.SetFindingState)], opts...) + var resp *securitycenterpb.Finding + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.SetFindingState(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetIamPolicy sets the access control policy on the specified Source. +func (c *Client) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetIamPolicy[0:len(c.CallOptions.SetIamPolicy):len(c.CallOptions.SetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.SetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// TestIamPermissions returns the permissions that a caller has on the specified source. +func (c *Client) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.TestIamPermissions[0:len(c.CallOptions.TestIamPermissions):len(c.CallOptions.TestIamPermissions)], opts...) + var resp *iampb.TestIamPermissionsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.TestIamPermissions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateFinding creates or updates a finding. The corresponding source must exist for a +// finding creation to succeed. +func (c *Client) UpdateFinding(ctx context.Context, req *securitycenterpb.UpdateFindingRequest, opts ...gax.CallOption) (*securitycenterpb.Finding, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateFinding[0:len(c.CallOptions.UpdateFinding):len(c.CallOptions.UpdateFinding)], opts...) + var resp *securitycenterpb.Finding + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateFinding(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateOrganizationSettings updates an organization's settings. +func (c *Client) UpdateOrganizationSettings(ctx context.Context, req *securitycenterpb.UpdateOrganizationSettingsRequest, opts ...gax.CallOption) (*securitycenterpb.OrganizationSettings, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateOrganizationSettings[0:len(c.CallOptions.UpdateOrganizationSettings):len(c.CallOptions.UpdateOrganizationSettings)], opts...) + var resp *securitycenterpb.OrganizationSettings + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateOrganizationSettings(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateSource updates a source. +func (c *Client) UpdateSource(ctx context.Context, req *securitycenterpb.UpdateSourceRequest, opts ...gax.CallOption) (*securitycenterpb.Source, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateSource[0:len(c.CallOptions.UpdateSource):len(c.CallOptions.UpdateSource)], opts...) + var resp *securitycenterpb.Source + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateSource(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateSecurityMarks updates security marks. +func (c *Client) UpdateSecurityMarks(ctx context.Context, req *securitycenterpb.UpdateSecurityMarksRequest, opts ...gax.CallOption) (*securitycenterpb.SecurityMarks, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateSecurityMarks[0:len(c.CallOptions.UpdateSecurityMarks):len(c.CallOptions.UpdateSecurityMarks)], opts...) + var resp *securitycenterpb.SecurityMarks + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.UpdateSecurityMarks(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// FindingIterator manages a stream of *securitycenterpb.Finding. +type FindingIterator struct { + items []*securitycenterpb.Finding + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*securitycenterpb.Finding, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *FindingIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *FindingIterator) Next() (*securitycenterpb.Finding, error) { + var item *securitycenterpb.Finding + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *FindingIterator) bufLen() int { + return len(it.items) +} + +func (it *FindingIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// GroupResultIterator manages a stream of *securitycenterpb.GroupResult. +type GroupResultIterator struct { + items []*securitycenterpb.GroupResult + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*securitycenterpb.GroupResult, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *GroupResultIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *GroupResultIterator) Next() (*securitycenterpb.GroupResult, error) { + var item *securitycenterpb.GroupResult + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *GroupResultIterator) bufLen() int { + return len(it.items) +} + +func (it *GroupResultIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// ListAssetsResponse_ListAssetsResultIterator manages a stream of *securitycenterpb.ListAssetsResponse_ListAssetsResult. +type ListAssetsResponse_ListAssetsResultIterator struct { + items []*securitycenterpb.ListAssetsResponse_ListAssetsResult + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*securitycenterpb.ListAssetsResponse_ListAssetsResult, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ListAssetsResponse_ListAssetsResultIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ListAssetsResponse_ListAssetsResultIterator) Next() (*securitycenterpb.ListAssetsResponse_ListAssetsResult, error) { + var item *securitycenterpb.ListAssetsResponse_ListAssetsResult + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ListAssetsResponse_ListAssetsResultIterator) bufLen() int { + return len(it.items) +} + +func (it *ListAssetsResponse_ListAssetsResultIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// SourceIterator manages a stream of *securitycenterpb.Source. +type SourceIterator struct { + items []*securitycenterpb.Source + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*securitycenterpb.Source, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *SourceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *SourceIterator) Next() (*securitycenterpb.Source, error) { + var item *securitycenterpb.Source + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *SourceIterator) bufLen() int { + return len(it.items) +} + +func (it *SourceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// RunAssetDiscoveryOperation manages a long-running operation from RunAssetDiscovery. +type RunAssetDiscoveryOperation struct { + lro *longrunning.Operation +} + +// RunAssetDiscoveryOperation returns a new RunAssetDiscoveryOperation from a given name. +// The name must be that of a previously created RunAssetDiscoveryOperation, possibly from a different process. +func (c *Client) RunAssetDiscoveryOperation(name string) *RunAssetDiscoveryOperation { + return &RunAssetDiscoveryOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *RunAssetDiscoveryOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 5000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *RunAssetDiscoveryOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Done reports whether the long-running operation has completed. +func (op *RunAssetDiscoveryOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *RunAssetDiscoveryOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/securitycenter/apiv1beta1/security_center_client_example_test.go b/vendor/cloud.google.com/go/securitycenter/apiv1beta1/security_center_client_example_test.go new file mode 100644 index 00000000..33209b64 --- /dev/null +++ b/vendor/cloud.google.com/go/securitycenter/apiv1beta1/security_center_client_example_test.go @@ -0,0 +1,391 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package securitycenter_test + +import ( + "context" + + securitycenter "cloud.google.com/go/securitycenter/apiv1beta1" + "google.golang.org/api/iterator" + securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1beta1" + iampb "google.golang.org/genproto/googleapis/iam/v1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_CreateSource() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.CreateSourceRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateSource(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_CreateFinding() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.CreateFindingRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateFinding(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_GetIamPolicy() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.GetIamPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetIamPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_GetOrganizationSettings() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.GetOrganizationSettingsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetOrganizationSettings(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_GetSource() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.GetSourceRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetSource(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_GroupAssets() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.GroupAssetsRequest{ + // TODO: Fill request struct fields. + } + it := c.GroupAssets(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_GroupFindings() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.GroupFindingsRequest{ + // TODO: Fill request struct fields. + } + it := c.GroupFindings(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_ListAssets() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.ListAssetsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListAssets(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_ListFindings() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.ListFindingsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListFindings(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_ListSources() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.ListSourcesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListSources(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_RunAssetDiscovery() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.RunAssetDiscoveryRequest{ + // TODO: Fill request struct fields. + } + op, err := c.RunAssetDiscovery(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} + +func ExampleClient_SetFindingState() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.SetFindingStateRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetFindingState(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_SetIamPolicy() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.SetIamPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetIamPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_TestIamPermissions() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.TestIamPermissionsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.TestIamPermissions(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_UpdateFinding() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.UpdateFindingRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateFinding(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_UpdateOrganizationSettings() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.UpdateOrganizationSettingsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateOrganizationSettings(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_UpdateSource() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.UpdateSourceRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateSource(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_UpdateSecurityMarks() { + ctx := context.Background() + c, err := securitycenter.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &securitycenterpb.UpdateSecurityMarksRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateSecurityMarks(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/spanner/admin/database/apiv1/database_admin_client.go b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/database_admin_client.go new file mode 100644 index 00000000..a75dfebd --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/database_admin_client.go @@ -0,0 +1,520 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package database + +import ( + "context" + "math" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + iampb "google.golang.org/genproto/googleapis/iam/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + databasepb "google.golang.org/genproto/googleapis/spanner/admin/database/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// DatabaseAdminCallOptions contains the retry settings for each method of DatabaseAdminClient. +type DatabaseAdminCallOptions struct { + ListDatabases []gax.CallOption + CreateDatabase []gax.CallOption + GetDatabase []gax.CallOption + UpdateDatabaseDdl []gax.CallOption + DropDatabase []gax.CallOption + GetDatabaseDdl []gax.CallOption + SetIamPolicy []gax.CallOption + GetIamPolicy []gax.CallOption + TestIamPermissions []gax.CallOption +} + +func defaultDatabaseAdminClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("spanner.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultDatabaseAdminCallOptions() *DatabaseAdminCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 32000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &DatabaseAdminCallOptions{ + ListDatabases: retry[[2]string{"default", "idempotent"}], + CreateDatabase: retry[[2]string{"default", "non_idempotent"}], + GetDatabase: retry[[2]string{"default", "idempotent"}], + UpdateDatabaseDdl: retry[[2]string{"default", "idempotent"}], + DropDatabase: retry[[2]string{"default", "idempotent"}], + GetDatabaseDdl: retry[[2]string{"default", "idempotent"}], + SetIamPolicy: retry[[2]string{"default", "non_idempotent"}], + GetIamPolicy: retry[[2]string{"default", "idempotent"}], + TestIamPermissions: retry[[2]string{"default", "non_idempotent"}], + } +} + +// DatabaseAdminClient is a client for interacting with Cloud Spanner Database Admin API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type DatabaseAdminClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + databaseAdminClient databasepb.DatabaseAdminClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *DatabaseAdminCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewDatabaseAdminClient creates a new database admin client. +// +// Cloud Spanner Database Admin API +// +// The Cloud Spanner Database Admin API can be used to create, drop, and +// list databases. It also enables updating the schema of pre-existing +// databases. +func NewDatabaseAdminClient(ctx context.Context, opts ...option.ClientOption) (*DatabaseAdminClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultDatabaseAdminClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &DatabaseAdminClient{ + conn: conn, + CallOptions: defaultDatabaseAdminCallOptions(), + + databaseAdminClient: databasepb.NewDatabaseAdminClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *DatabaseAdminClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *DatabaseAdminClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *DatabaseAdminClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListDatabases lists Cloud Spanner databases. +func (c *DatabaseAdminClient) ListDatabases(ctx context.Context, req *databasepb.ListDatabasesRequest, opts ...gax.CallOption) *DatabaseIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListDatabases[0:len(c.CallOptions.ListDatabases):len(c.CallOptions.ListDatabases)], opts...) + it := &DatabaseIterator{} + req = proto.Clone(req).(*databasepb.ListDatabasesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*databasepb.Database, string, error) { + var resp *databasepb.ListDatabasesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.databaseAdminClient.ListDatabases(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Databases, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// CreateDatabase creates a new Cloud Spanner database and starts to prepare it for serving. +// The returned [long-running operation][google.longrunning.Operation] will +// have a name of the format /operations/ and +// can be used to track preparation of the database. The +// [metadata][google.longrunning.Operation.metadata] field type is +// [CreateDatabaseMetadata][google.spanner.admin.database.v1.CreateDatabaseMetadata]. The +// [response][google.longrunning.Operation.response] field type is +// [Database][google.spanner.admin.database.v1.Database], if successful. +func (c *DatabaseAdminClient) CreateDatabase(ctx context.Context, req *databasepb.CreateDatabaseRequest, opts ...gax.CallOption) (*CreateDatabaseOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateDatabase[0:len(c.CallOptions.CreateDatabase):len(c.CallOptions.CreateDatabase)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.databaseAdminClient.CreateDatabase(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &CreateDatabaseOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// GetDatabase gets the state of a Cloud Spanner database. +func (c *DatabaseAdminClient) GetDatabase(ctx context.Context, req *databasepb.GetDatabaseRequest, opts ...gax.CallOption) (*databasepb.Database, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetDatabase[0:len(c.CallOptions.GetDatabase):len(c.CallOptions.GetDatabase)], opts...) + var resp *databasepb.Database + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.databaseAdminClient.GetDatabase(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateDatabaseDdl updates the schema of a Cloud Spanner database by +// creating/altering/dropping tables, columns, indexes, etc. The returned +// [long-running operation][google.longrunning.Operation] will have a name of +// the format /operations/ and can be used to +// track execution of the schema change(s). The +// [metadata][google.longrunning.Operation.metadata] field type is +// [UpdateDatabaseDdlMetadata][google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata]. The operation has no response. +func (c *DatabaseAdminClient) UpdateDatabaseDdl(ctx context.Context, req *databasepb.UpdateDatabaseDdlRequest, opts ...gax.CallOption) (*UpdateDatabaseDdlOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateDatabaseDdl[0:len(c.CallOptions.UpdateDatabaseDdl):len(c.CallOptions.UpdateDatabaseDdl)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.databaseAdminClient.UpdateDatabaseDdl(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &UpdateDatabaseDdlOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// DropDatabase drops (aka deletes) a Cloud Spanner database. +func (c *DatabaseAdminClient) DropDatabase(ctx context.Context, req *databasepb.DropDatabaseRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DropDatabase[0:len(c.CallOptions.DropDatabase):len(c.CallOptions.DropDatabase)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.databaseAdminClient.DropDatabase(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// GetDatabaseDdl returns the schema of a Cloud Spanner database as a list of formatted +// DDL statements. This method does not show pending schema updates, those may +// be queried using the [Operations][google.longrunning.Operations] API. +func (c *DatabaseAdminClient) GetDatabaseDdl(ctx context.Context, req *databasepb.GetDatabaseDdlRequest, opts ...gax.CallOption) (*databasepb.GetDatabaseDdlResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetDatabaseDdl[0:len(c.CallOptions.GetDatabaseDdl):len(c.CallOptions.GetDatabaseDdl)], opts...) + var resp *databasepb.GetDatabaseDdlResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.databaseAdminClient.GetDatabaseDdl(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SetIamPolicy sets the access control policy on a database resource. Replaces any +// existing policy. +// +// Authorization requires spanner.databases.setIamPolicy permission on +// [resource][google.iam.v1.SetIamPolicyRequest.resource]. +func (c *DatabaseAdminClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetIamPolicy[0:len(c.CallOptions.SetIamPolicy):len(c.CallOptions.SetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.databaseAdminClient.SetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetIamPolicy gets the access control policy for a database resource. Returns an empty +// policy if a database exists but does not have a policy set. +// +// Authorization requires spanner.databases.getIamPolicy permission on +// [resource][google.iam.v1.GetIamPolicyRequest.resource]. +func (c *DatabaseAdminClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetIamPolicy[0:len(c.CallOptions.GetIamPolicy):len(c.CallOptions.GetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.databaseAdminClient.GetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// TestIamPermissions returns permissions that the caller has on the specified database resource. +// +// Attempting this RPC on a non-existent Cloud Spanner database will result in +// a NOT_FOUND error if the user has spanner.databases.list permission on +// the containing Cloud Spanner instance. Otherwise returns an empty set of +// permissions. +func (c *DatabaseAdminClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.TestIamPermissions[0:len(c.CallOptions.TestIamPermissions):len(c.CallOptions.TestIamPermissions)], opts...) + var resp *iampb.TestIamPermissionsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.databaseAdminClient.TestIamPermissions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DatabaseIterator manages a stream of *databasepb.Database. +type DatabaseIterator struct { + items []*databasepb.Database + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*databasepb.Database, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *DatabaseIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *DatabaseIterator) Next() (*databasepb.Database, error) { + var item *databasepb.Database + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *DatabaseIterator) bufLen() int { + return len(it.items) +} + +func (it *DatabaseIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// CreateDatabaseOperation manages a long-running operation from CreateDatabase. +type CreateDatabaseOperation struct { + lro *longrunning.Operation +} + +// CreateDatabaseOperation returns a new CreateDatabaseOperation from a given name. +// The name must be that of a previously created CreateDatabaseOperation, possibly from a different process. +func (c *DatabaseAdminClient) CreateDatabaseOperation(name string) *CreateDatabaseOperation { + return &CreateDatabaseOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateDatabaseOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*databasepb.Database, error) { + var resp databasepb.Database + if err := op.lro.WaitWithInterval(ctx, &resp, 45000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateDatabaseOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*databasepb.Database, error) { + var resp databasepb.Database + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateDatabaseOperation) Metadata() (*databasepb.CreateDatabaseMetadata, error) { + var meta databasepb.CreateDatabaseMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateDatabaseOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *CreateDatabaseOperation) Name() string { + return op.lro.Name() +} + +// UpdateDatabaseDdlOperation manages a long-running operation from UpdateDatabaseDdl. +type UpdateDatabaseDdlOperation struct { + lro *longrunning.Operation +} + +// UpdateDatabaseDdlOperation returns a new UpdateDatabaseDdlOperation from a given name. +// The name must be that of a previously created UpdateDatabaseDdlOperation, possibly from a different process. +func (c *DatabaseAdminClient) UpdateDatabaseDdlOperation(name string) *UpdateDatabaseDdlOperation { + return &UpdateDatabaseDdlOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning any error encountered. +// +// See documentation of Poll for error-handling information. +func (op *UpdateDatabaseDdlOperation) Wait(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.WaitWithInterval(ctx, nil, 45000*time.Millisecond, opts...) +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, op.Done will return true. +func (op *UpdateDatabaseDdlOperation) Poll(ctx context.Context, opts ...gax.CallOption) error { + return op.lro.Poll(ctx, nil, opts...) +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *UpdateDatabaseDdlOperation) Metadata() (*databasepb.UpdateDatabaseDdlMetadata, error) { + var meta databasepb.UpdateDatabaseDdlMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *UpdateDatabaseDdlOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *UpdateDatabaseDdlOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/spanner/admin/database/apiv1/database_admin_client_example_test.go b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/database_admin_client_example_test.go new file mode 100644 index 00000000..6fdb9d33 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/database_admin_client_example_test.go @@ -0,0 +1,208 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package database_test + +import ( + "context" + + database "cloud.google.com/go/spanner/admin/database/apiv1" + "google.golang.org/api/iterator" + iampb "google.golang.org/genproto/googleapis/iam/v1" + databasepb "google.golang.org/genproto/googleapis/spanner/admin/database/v1" +) + +func ExampleNewDatabaseAdminClient() { + ctx := context.Background() + c, err := database.NewDatabaseAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleDatabaseAdminClient_ListDatabases() { + ctx := context.Background() + c, err := database.NewDatabaseAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &databasepb.ListDatabasesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListDatabases(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleDatabaseAdminClient_CreateDatabase() { + ctx := context.Background() + c, err := database.NewDatabaseAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &databasepb.CreateDatabaseRequest{ + // TODO: Fill request struct fields. + } + op, err := c.CreateDatabase(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleDatabaseAdminClient_GetDatabase() { + ctx := context.Background() + c, err := database.NewDatabaseAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &databasepb.GetDatabaseRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetDatabase(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleDatabaseAdminClient_UpdateDatabaseDdl() { + ctx := context.Background() + c, err := database.NewDatabaseAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &databasepb.UpdateDatabaseDdlRequest{ + // TODO: Fill request struct fields. + } + op, err := c.UpdateDatabaseDdl(ctx, req) + if err != nil { + // TODO: Handle error. + } + + err = op.Wait(ctx) + // TODO: Handle error. +} + +func ExampleDatabaseAdminClient_DropDatabase() { + ctx := context.Background() + c, err := database.NewDatabaseAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &databasepb.DropDatabaseRequest{ + // TODO: Fill request struct fields. + } + err = c.DropDatabase(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleDatabaseAdminClient_GetDatabaseDdl() { + ctx := context.Background() + c, err := database.NewDatabaseAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &databasepb.GetDatabaseDdlRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetDatabaseDdl(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleDatabaseAdminClient_SetIamPolicy() { + ctx := context.Background() + c, err := database.NewDatabaseAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.SetIamPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetIamPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleDatabaseAdminClient_GetIamPolicy() { + ctx := context.Background() + c, err := database.NewDatabaseAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.GetIamPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetIamPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleDatabaseAdminClient_TestIamPermissions() { + ctx := context.Background() + c, err := database.NewDatabaseAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.TestIamPermissionsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.TestIamPermissions(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/spanner/admin/database/apiv1/doc.go b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/doc.go new file mode 100644 index 00000000..55fbf1e0 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package database is an auto-generated package for the +// Cloud Spanner Database Admin API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +package database // import "cloud.google.com/go/spanner/admin/database/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/spanner.admin", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/spanner/admin/database/apiv1/mock_test.go b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/mock_test.go new file mode 100644 index 00000000..63ba16ba --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/mock_test.go @@ -0,0 +1,798 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package database + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + iampb "google.golang.org/genproto/googleapis/iam/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + databasepb "google.golang.org/genproto/googleapis/spanner/admin/database/v1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockDatabaseAdminServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + databasepb.DatabaseAdminServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockDatabaseAdminServer) ListDatabases(ctx context.Context, req *databasepb.ListDatabasesRequest) (*databasepb.ListDatabasesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*databasepb.ListDatabasesResponse), nil +} + +func (s *mockDatabaseAdminServer) CreateDatabase(ctx context.Context, req *databasepb.CreateDatabaseRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockDatabaseAdminServer) GetDatabase(ctx context.Context, req *databasepb.GetDatabaseRequest) (*databasepb.Database, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*databasepb.Database), nil +} + +func (s *mockDatabaseAdminServer) UpdateDatabaseDdl(ctx context.Context, req *databasepb.UpdateDatabaseDdlRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockDatabaseAdminServer) DropDatabase(ctx context.Context, req *databasepb.DropDatabaseRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockDatabaseAdminServer) GetDatabaseDdl(ctx context.Context, req *databasepb.GetDatabaseDdlRequest) (*databasepb.GetDatabaseDdlResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*databasepb.GetDatabaseDdlResponse), nil +} + +func (s *mockDatabaseAdminServer) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockDatabaseAdminServer) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockDatabaseAdminServer) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest) (*iampb.TestIamPermissionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.TestIamPermissionsResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockDatabaseAdmin mockDatabaseAdminServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + databasepb.RegisterDatabaseAdminServer(serv, &mockDatabaseAdmin) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestDatabaseAdminListDatabases(t *testing.T) { + var nextPageToken string = "" + var databasesElement *databasepb.Database = &databasepb.Database{} + var databases = []*databasepb.Database{databasesElement} + var expectedResponse = &databasepb.ListDatabasesResponse{ + NextPageToken: nextPageToken, + Databases: databases, + } + + mockDatabaseAdmin.err = nil + mockDatabaseAdmin.reqs = nil + + mockDatabaseAdmin.resps = append(mockDatabaseAdmin.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var request = &databasepb.ListDatabasesRequest{ + Parent: formattedParent, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListDatabases(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDatabaseAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Databases[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDatabaseAdminListDatabasesError(t *testing.T) { + errCode := codes.PermissionDenied + mockDatabaseAdmin.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var request = &databasepb.ListDatabasesRequest{ + Parent: formattedParent, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListDatabases(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDatabaseAdminCreateDatabase(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &databasepb.Database{ + Name: name, + } + + mockDatabaseAdmin.err = nil + mockDatabaseAdmin.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockDatabaseAdmin.resps = append(mockDatabaseAdmin.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var createStatement string = "createStatement552974828" + var request = &databasepb.CreateDatabaseRequest{ + Parent: formattedParent, + CreateStatement: createStatement, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.CreateDatabase(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDatabaseAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDatabaseAdminCreateDatabaseError(t *testing.T) { + errCode := codes.PermissionDenied + mockDatabaseAdmin.err = nil + mockDatabaseAdmin.resps = append(mockDatabaseAdmin.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var createStatement string = "createStatement552974828" + var request = &databasepb.CreateDatabaseRequest{ + Parent: formattedParent, + CreateStatement: createStatement, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.CreateDatabase(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDatabaseAdminGetDatabase(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &databasepb.Database{ + Name: name2, + } + + mockDatabaseAdmin.err = nil + mockDatabaseAdmin.reqs = nil + + mockDatabaseAdmin.resps = append(mockDatabaseAdmin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var request = &databasepb.GetDatabaseRequest{ + Name: formattedName, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetDatabase(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDatabaseAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDatabaseAdminGetDatabaseError(t *testing.T) { + errCode := codes.PermissionDenied + mockDatabaseAdmin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var request = &databasepb.GetDatabaseRequest{ + Name: formattedName, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetDatabase(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDatabaseAdminUpdateDatabaseDdl(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockDatabaseAdmin.err = nil + mockDatabaseAdmin.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockDatabaseAdmin.resps = append(mockDatabaseAdmin.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedDatabase string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var statements []string = nil + var request = &databasepb.UpdateDatabaseDdlRequest{ + Database: formattedDatabase, + Statements: statements, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.UpdateDatabaseDdl(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDatabaseAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestDatabaseAdminUpdateDatabaseDdlError(t *testing.T) { + errCode := codes.PermissionDenied + mockDatabaseAdmin.err = nil + mockDatabaseAdmin.resps = append(mockDatabaseAdmin.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedDatabase string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var statements []string = nil + var request = &databasepb.UpdateDatabaseDdlRequest{ + Database: formattedDatabase, + Statements: statements, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.UpdateDatabaseDdl(context.Background(), request) + if err != nil { + t.Fatal(err) + } + err = respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestDatabaseAdminDropDatabase(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockDatabaseAdmin.err = nil + mockDatabaseAdmin.reqs = nil + + mockDatabaseAdmin.resps = append(mockDatabaseAdmin.resps[:0], expectedResponse) + + var formattedDatabase string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var request = &databasepb.DropDatabaseRequest{ + Database: formattedDatabase, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DropDatabase(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDatabaseAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestDatabaseAdminDropDatabaseError(t *testing.T) { + errCode := codes.PermissionDenied + mockDatabaseAdmin.err = gstatus.Error(errCode, "test error") + + var formattedDatabase string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var request = &databasepb.DropDatabaseRequest{ + Database: formattedDatabase, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DropDatabase(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestDatabaseAdminGetDatabaseDdl(t *testing.T) { + var expectedResponse *databasepb.GetDatabaseDdlResponse = &databasepb.GetDatabaseDdlResponse{} + + mockDatabaseAdmin.err = nil + mockDatabaseAdmin.reqs = nil + + mockDatabaseAdmin.resps = append(mockDatabaseAdmin.resps[:0], expectedResponse) + + var formattedDatabase string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var request = &databasepb.GetDatabaseDdlRequest{ + Database: formattedDatabase, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetDatabaseDdl(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDatabaseAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDatabaseAdminGetDatabaseDdlError(t *testing.T) { + errCode := codes.PermissionDenied + mockDatabaseAdmin.err = gstatus.Error(errCode, "test error") + + var formattedDatabase string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var request = &databasepb.GetDatabaseDdlRequest{ + Database: formattedDatabase, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetDatabaseDdl(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDatabaseAdminSetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockDatabaseAdmin.err = nil + mockDatabaseAdmin.reqs = nil + + mockDatabaseAdmin.resps = append(mockDatabaseAdmin.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDatabaseAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDatabaseAdminSetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockDatabaseAdmin.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDatabaseAdminGetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockDatabaseAdmin.err = nil + mockDatabaseAdmin.reqs = nil + + mockDatabaseAdmin.resps = append(mockDatabaseAdmin.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDatabaseAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDatabaseAdminGetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockDatabaseAdmin.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestDatabaseAdminTestIamPermissions(t *testing.T) { + var expectedResponse *iampb.TestIamPermissionsResponse = &iampb.TestIamPermissionsResponse{} + + mockDatabaseAdmin.err = nil + mockDatabaseAdmin.reqs = nil + + mockDatabaseAdmin.resps = append(mockDatabaseAdmin.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockDatabaseAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestDatabaseAdminTestIamPermissionsError(t *testing.T) { + errCode := codes.PermissionDenied + mockDatabaseAdmin.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewDatabaseAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/spanner/admin/database/apiv1/path_funcs.go b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/path_funcs.go new file mode 100644 index 00000000..5490f57c --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/admin/database/apiv1/path_funcs.go @@ -0,0 +1,45 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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 database + +// DatabaseAdminInstancePath returns the path for the instance resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/instances/%s", project, instance) +// instead. +func DatabaseAdminInstancePath(project, instance string) string { + return "" + + "projects/" + + project + + "/instances/" + + instance + + "" +} + +// DatabaseAdminDatabasePath returns the path for the database resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/instances/%s/databases/%s", project, instance, database) +// instead. +func DatabaseAdminDatabasePath(project, instance, database string) string { + return "" + + "projects/" + + project + + "/instances/" + + instance + + "/databases/" + + database + + "" +} diff --git a/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/doc.go b/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/doc.go new file mode 100644 index 00000000..49cda55b --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package instance is an auto-generated package for the +// Cloud Spanner Instance Admin API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +package instance // import "cloud.google.com/go/spanner/admin/instance/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/spanner.admin", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/instance_admin_client.go b/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/instance_admin_client.go new file mode 100644 index 00000000..1a7df8fc --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/instance_admin_client.go @@ -0,0 +1,706 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package instance + +import ( + "context" + "math" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + iampb "google.golang.org/genproto/googleapis/iam/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + instancepb "google.golang.org/genproto/googleapis/spanner/admin/instance/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// InstanceAdminCallOptions contains the retry settings for each method of InstanceAdminClient. +type InstanceAdminCallOptions struct { + ListInstanceConfigs []gax.CallOption + GetInstanceConfig []gax.CallOption + ListInstances []gax.CallOption + GetInstance []gax.CallOption + CreateInstance []gax.CallOption + UpdateInstance []gax.CallOption + DeleteInstance []gax.CallOption + SetIamPolicy []gax.CallOption + GetIamPolicy []gax.CallOption + TestIamPermissions []gax.CallOption +} + +func defaultInstanceAdminClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("spanner.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultInstanceAdminCallOptions() *InstanceAdminCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 32000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &InstanceAdminCallOptions{ + ListInstanceConfigs: retry[[2]string{"default", "idempotent"}], + GetInstanceConfig: retry[[2]string{"default", "idempotent"}], + ListInstances: retry[[2]string{"default", "idempotent"}], + GetInstance: retry[[2]string{"default", "idempotent"}], + CreateInstance: retry[[2]string{"default", "non_idempotent"}], + UpdateInstance: retry[[2]string{"default", "non_idempotent"}], + DeleteInstance: retry[[2]string{"default", "idempotent"}], + SetIamPolicy: retry[[2]string{"default", "non_idempotent"}], + GetIamPolicy: retry[[2]string{"default", "idempotent"}], + TestIamPermissions: retry[[2]string{"default", "non_idempotent"}], + } +} + +// InstanceAdminClient is a client for interacting with Cloud Spanner Instance Admin API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type InstanceAdminClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + instanceAdminClient instancepb.InstanceAdminClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *InstanceAdminCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewInstanceAdminClient creates a new instance admin client. +// +// Cloud Spanner Instance Admin API +// +// The Cloud Spanner Instance Admin API can be used to create, delete, +// modify and list instances. Instances are dedicated Cloud Spanner serving +// and storage resources to be used by Cloud Spanner databases. +// +// Each instance has a "configuration", which dictates where the +// serving resources for the Cloud Spanner instance are located (e.g., +// US-central, Europe). Configurations are created by Google based on +// resource availability. +// +// Cloud Spanner billing is based on the instances that exist and their +// sizes. After an instance exists, there are no additional +// per-database or per-operation charges for use of the instance +// (though there may be additional network bandwidth charges). +// Instances offer isolation: problems with databases in one instance +// will not affect other instances. However, within an instance +// databases can affect each other. For example, if one database in an +// instance receives a lot of requests and consumes most of the +// instance resources, fewer resources are available for other +// databases in that instance, and their performance may suffer. +func NewInstanceAdminClient(ctx context.Context, opts ...option.ClientOption) (*InstanceAdminClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultInstanceAdminClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &InstanceAdminClient{ + conn: conn, + CallOptions: defaultInstanceAdminCallOptions(), + + instanceAdminClient: instancepb.NewInstanceAdminClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *InstanceAdminClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *InstanceAdminClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *InstanceAdminClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListInstanceConfigs lists the supported instance configurations for a given project. +func (c *InstanceAdminClient) ListInstanceConfigs(ctx context.Context, req *instancepb.ListInstanceConfigsRequest, opts ...gax.CallOption) *InstanceConfigIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListInstanceConfigs[0:len(c.CallOptions.ListInstanceConfigs):len(c.CallOptions.ListInstanceConfigs)], opts...) + it := &InstanceConfigIterator{} + req = proto.Clone(req).(*instancepb.ListInstanceConfigsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*instancepb.InstanceConfig, string, error) { + var resp *instancepb.ListInstanceConfigsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.instanceAdminClient.ListInstanceConfigs(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.InstanceConfigs, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetInstanceConfig gets information about a particular instance configuration. +func (c *InstanceAdminClient) GetInstanceConfig(ctx context.Context, req *instancepb.GetInstanceConfigRequest, opts ...gax.CallOption) (*instancepb.InstanceConfig, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetInstanceConfig[0:len(c.CallOptions.GetInstanceConfig):len(c.CallOptions.GetInstanceConfig)], opts...) + var resp *instancepb.InstanceConfig + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.instanceAdminClient.GetInstanceConfig(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListInstances lists all instances in the given project. +func (c *InstanceAdminClient) ListInstances(ctx context.Context, req *instancepb.ListInstancesRequest, opts ...gax.CallOption) *InstanceIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListInstances[0:len(c.CallOptions.ListInstances):len(c.CallOptions.ListInstances)], opts...) + it := &InstanceIterator{} + req = proto.Clone(req).(*instancepb.ListInstancesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*instancepb.Instance, string, error) { + var resp *instancepb.ListInstancesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.instanceAdminClient.ListInstances(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Instances, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetInstance gets information about a particular instance. +func (c *InstanceAdminClient) GetInstance(ctx context.Context, req *instancepb.GetInstanceRequest, opts ...gax.CallOption) (*instancepb.Instance, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetInstance[0:len(c.CallOptions.GetInstance):len(c.CallOptions.GetInstance)], opts...) + var resp *instancepb.Instance + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.instanceAdminClient.GetInstance(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateInstance creates an instance and begins preparing it to begin serving. The +// returned [long-running operation][google.longrunning.Operation] +// can be used to track the progress of preparing the new +// instance. The instance name is assigned by the caller. If the +// named instance already exists, CreateInstance returns +// ALREADY_EXISTS. +// +// Immediately upon completion of this request: +// +// The instance is readable via the API, with all requested attributes +// but no allocated resources. Its state is CREATING. +// +// Until completion of the returned operation: +// +// Cancelling the operation renders the instance immediately unreadable +// via the API. +// +// The instance can be deleted. +// +// All other attempts to modify the instance are rejected. +// +// Upon completion of the returned operation: +// +// Billing for all successfully-allocated resources begins (some types +// may have lower than the requested levels). +// +// Databases can be created in the instance. +// +// The instance's allocated resource levels are readable via the API. +// +// The instance's state becomes READY. +// +// The returned [long-running operation][google.longrunning.Operation] will +// have a name of the format /operations/ and +// can be used to track creation of the instance. The +// [metadata][google.longrunning.Operation.metadata] field type is +// [CreateInstanceMetadata][google.spanner.admin.instance.v1.CreateInstanceMetadata]. +// The [response][google.longrunning.Operation.response] field type is +// [Instance][google.spanner.admin.instance.v1.Instance], if successful. +func (c *InstanceAdminClient) CreateInstance(ctx context.Context, req *instancepb.CreateInstanceRequest, opts ...gax.CallOption) (*CreateInstanceOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateInstance[0:len(c.CallOptions.CreateInstance):len(c.CallOptions.CreateInstance)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.instanceAdminClient.CreateInstance(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &CreateInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// UpdateInstance updates an instance, and begins allocating or releasing resources +// as requested. The returned [long-running +// operation][google.longrunning.Operation] can be used to track the +// progress of updating the instance. If the named instance does not +// exist, returns NOT_FOUND. +// +// Immediately upon completion of this request: +// +// For resource types for which a decrease in the instance's allocation +// has been requested, billing is based on the newly-requested level. +// +// Until completion of the returned operation: +// +// Cancelling the operation sets its metadata's +// [cancel_time][google.spanner.admin.instance.v1.UpdateInstanceMetadata.cancel_time], and begins +// restoring resources to their pre-request values. The operation +// is guaranteed to succeed at undoing all resource changes, +// after which point it terminates with a CANCELLED status. +// +// All other attempts to modify the instance are rejected. +// +// Reading the instance via the API continues to give the pre-request +// resource levels. +// +// Upon completion of the returned operation: +// +// Billing begins for all successfully-allocated resources (some types +// may have lower than the requested levels). +// +// All newly-reserved resources are available for serving the instance's +// tables. +// +// The instance's new resource levels are readable via the API. +// +// The returned [long-running operation][google.longrunning.Operation] will +// have a name of the format /operations/ and +// can be used to track the instance modification. The +// [metadata][google.longrunning.Operation.metadata] field type is +// [UpdateInstanceMetadata][google.spanner.admin.instance.v1.UpdateInstanceMetadata]. +// The [response][google.longrunning.Operation.response] field type is +// [Instance][google.spanner.admin.instance.v1.Instance], if successful. +// +// Authorization requires spanner.instances.update permission on +// resource [name][google.spanner.admin.instance.v1.Instance.name]. +func (c *InstanceAdminClient) UpdateInstance(ctx context.Context, req *instancepb.UpdateInstanceRequest, opts ...gax.CallOption) (*UpdateInstanceOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateInstance[0:len(c.CallOptions.UpdateInstance):len(c.CallOptions.UpdateInstance)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.instanceAdminClient.UpdateInstance(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &UpdateInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// DeleteInstance deletes an instance. +// +// Immediately upon completion of the request: +// +// Billing ceases for all of the instance's reserved resources. +// +// Soon afterward: +// +// The instance and all of its databases immediately and +// irrevocably disappear from the API. All data in the databases +// is permanently deleted. +func (c *InstanceAdminClient) DeleteInstance(ctx context.Context, req *instancepb.DeleteInstanceRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteInstance[0:len(c.CallOptions.DeleteInstance):len(c.CallOptions.DeleteInstance)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.instanceAdminClient.DeleteInstance(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// SetIamPolicy sets the access control policy on an instance resource. Replaces any +// existing policy. +// +// Authorization requires spanner.instances.setIamPolicy on +// [resource][google.iam.v1.SetIamPolicyRequest.resource]. +func (c *InstanceAdminClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SetIamPolicy[0:len(c.CallOptions.SetIamPolicy):len(c.CallOptions.SetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.instanceAdminClient.SetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetIamPolicy gets the access control policy for an instance resource. Returns an empty +// policy if an instance exists but does not have a policy set. +// +// Authorization requires spanner.instances.getIamPolicy on +// [resource][google.iam.v1.GetIamPolicyRequest.resource]. +func (c *InstanceAdminClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetIamPolicy[0:len(c.CallOptions.GetIamPolicy):len(c.CallOptions.GetIamPolicy)], opts...) + var resp *iampb.Policy + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.instanceAdminClient.GetIamPolicy(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// TestIamPermissions returns permissions that the caller has on the specified instance resource. +// +// Attempting this RPC on a non-existent Cloud Spanner instance resource will +// result in a NOT_FOUND error if the user has spanner.instances.list +// permission on the containing Google Cloud Project. Otherwise returns an +// empty set of permissions. +func (c *InstanceAdminClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.TestIamPermissions[0:len(c.CallOptions.TestIamPermissions):len(c.CallOptions.TestIamPermissions)], opts...) + var resp *iampb.TestIamPermissionsResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.instanceAdminClient.TestIamPermissions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// InstanceConfigIterator manages a stream of *instancepb.InstanceConfig. +type InstanceConfigIterator struct { + items []*instancepb.InstanceConfig + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*instancepb.InstanceConfig, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InstanceConfigIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InstanceConfigIterator) Next() (*instancepb.InstanceConfig, error) { + var item *instancepb.InstanceConfig + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InstanceConfigIterator) bufLen() int { + return len(it.items) +} + +func (it *InstanceConfigIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// InstanceIterator manages a stream of *instancepb.Instance. +type InstanceIterator struct { + items []*instancepb.Instance + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*instancepb.Instance, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InstanceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InstanceIterator) Next() (*instancepb.Instance, error) { + var item *instancepb.Instance + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InstanceIterator) bufLen() int { + return len(it.items) +} + +func (it *InstanceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// CreateInstanceOperation manages a long-running operation from CreateInstance. +type CreateInstanceOperation struct { + lro *longrunning.Operation +} + +// CreateInstanceOperation returns a new CreateInstanceOperation from a given name. +// The name must be that of a previously created CreateInstanceOperation, possibly from a different process. +func (c *InstanceAdminClient) CreateInstanceOperation(name string) *CreateInstanceOperation { + return &CreateInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *CreateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*instancepb.Instance, error) { + var resp instancepb.Instance + if err := op.lro.WaitWithInterval(ctx, &resp, 45000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *CreateInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*instancepb.Instance, error) { + var resp instancepb.Instance + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *CreateInstanceOperation) Metadata() (*instancepb.CreateInstanceMetadata, error) { + var meta instancepb.CreateInstanceMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *CreateInstanceOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *CreateInstanceOperation) Name() string { + return op.lro.Name() +} + +// UpdateInstanceOperation manages a long-running operation from UpdateInstance. +type UpdateInstanceOperation struct { + lro *longrunning.Operation +} + +// UpdateInstanceOperation returns a new UpdateInstanceOperation from a given name. +// The name must be that of a previously created UpdateInstanceOperation, possibly from a different process. +func (c *InstanceAdminClient) UpdateInstanceOperation(name string) *UpdateInstanceOperation { + return &UpdateInstanceOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *UpdateInstanceOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*instancepb.Instance, error) { + var resp instancepb.Instance + if err := op.lro.WaitWithInterval(ctx, &resp, 45000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *UpdateInstanceOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*instancepb.Instance, error) { + var resp instancepb.Instance + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *UpdateInstanceOperation) Metadata() (*instancepb.UpdateInstanceMetadata, error) { + var meta instancepb.UpdateInstanceMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *UpdateInstanceOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *UpdateInstanceOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/instance_admin_client_example_test.go b/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/instance_admin_client_example_test.go new file mode 100644 index 00000000..3e6576dd --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/instance_admin_client_example_test.go @@ -0,0 +1,236 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package instance_test + +import ( + "context" + + instance "cloud.google.com/go/spanner/admin/instance/apiv1" + "google.golang.org/api/iterator" + iampb "google.golang.org/genproto/googleapis/iam/v1" + instancepb "google.golang.org/genproto/googleapis/spanner/admin/instance/v1" +) + +func ExampleNewInstanceAdminClient() { + ctx := context.Background() + c, err := instance.NewInstanceAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleInstanceAdminClient_ListInstanceConfigs() { + ctx := context.Background() + c, err := instance.NewInstanceAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &instancepb.ListInstanceConfigsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListInstanceConfigs(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleInstanceAdminClient_GetInstanceConfig() { + ctx := context.Background() + c, err := instance.NewInstanceAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &instancepb.GetInstanceConfigRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetInstanceConfig(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleInstanceAdminClient_ListInstances() { + ctx := context.Background() + c, err := instance.NewInstanceAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &instancepb.ListInstancesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListInstances(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleInstanceAdminClient_GetInstance() { + ctx := context.Background() + c, err := instance.NewInstanceAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &instancepb.GetInstanceRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetInstance(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleInstanceAdminClient_CreateInstance() { + ctx := context.Background() + c, err := instance.NewInstanceAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &instancepb.CreateInstanceRequest{ + // TODO: Fill request struct fields. + } + op, err := c.CreateInstance(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleInstanceAdminClient_UpdateInstance() { + ctx := context.Background() + c, err := instance.NewInstanceAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &instancepb.UpdateInstanceRequest{ + // TODO: Fill request struct fields. + } + op, err := c.UpdateInstance(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleInstanceAdminClient_DeleteInstance() { + ctx := context.Background() + c, err := instance.NewInstanceAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &instancepb.DeleteInstanceRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteInstance(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleInstanceAdminClient_SetIamPolicy() { + ctx := context.Background() + c, err := instance.NewInstanceAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.SetIamPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SetIamPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleInstanceAdminClient_GetIamPolicy() { + ctx := context.Background() + c, err := instance.NewInstanceAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.GetIamPolicyRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetIamPolicy(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleInstanceAdminClient_TestIamPermissions() { + ctx := context.Background() + c, err := instance.NewInstanceAdminClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &iampb.TestIamPermissionsRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.TestIamPermissions(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/mock_test.go b/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/mock_test.go new file mode 100644 index 00000000..696e78b3 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/mock_test.go @@ -0,0 +1,917 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package instance + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + iampb "google.golang.org/genproto/googleapis/iam/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + instancepb "google.golang.org/genproto/googleapis/spanner/admin/instance/v1" + field_maskpb "google.golang.org/genproto/protobuf/field_mask" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockInstanceAdminServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + instancepb.InstanceAdminServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockInstanceAdminServer) ListInstanceConfigs(ctx context.Context, req *instancepb.ListInstanceConfigsRequest) (*instancepb.ListInstanceConfigsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*instancepb.ListInstanceConfigsResponse), nil +} + +func (s *mockInstanceAdminServer) GetInstanceConfig(ctx context.Context, req *instancepb.GetInstanceConfigRequest) (*instancepb.InstanceConfig, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*instancepb.InstanceConfig), nil +} + +func (s *mockInstanceAdminServer) ListInstances(ctx context.Context, req *instancepb.ListInstancesRequest) (*instancepb.ListInstancesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*instancepb.ListInstancesResponse), nil +} + +func (s *mockInstanceAdminServer) GetInstance(ctx context.Context, req *instancepb.GetInstanceRequest) (*instancepb.Instance, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*instancepb.Instance), nil +} + +func (s *mockInstanceAdminServer) CreateInstance(ctx context.Context, req *instancepb.CreateInstanceRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockInstanceAdminServer) UpdateInstance(ctx context.Context, req *instancepb.UpdateInstanceRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockInstanceAdminServer) DeleteInstance(ctx context.Context, req *instancepb.DeleteInstanceRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockInstanceAdminServer) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockInstanceAdminServer) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest) (*iampb.Policy, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.Policy), nil +} + +func (s *mockInstanceAdminServer) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest) (*iampb.TestIamPermissionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*iampb.TestIamPermissionsResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockInstanceAdmin mockInstanceAdminServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + instancepb.RegisterInstanceAdminServer(serv, &mockInstanceAdmin) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestInstanceAdminListInstanceConfigs(t *testing.T) { + var nextPageToken string = "" + var instanceConfigsElement *instancepb.InstanceConfig = &instancepb.InstanceConfig{} + var instanceConfigs = []*instancepb.InstanceConfig{instanceConfigsElement} + var expectedResponse = &instancepb.ListInstanceConfigsResponse{ + NextPageToken: nextPageToken, + InstanceConfigs: instanceConfigs, + } + + mockInstanceAdmin.err = nil + mockInstanceAdmin.reqs = nil + + mockInstanceAdmin.resps = append(mockInstanceAdmin.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &instancepb.ListInstanceConfigsRequest{ + Parent: formattedParent, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListInstanceConfigs(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockInstanceAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.InstanceConfigs[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestInstanceAdminListInstanceConfigsError(t *testing.T) { + errCode := codes.PermissionDenied + mockInstanceAdmin.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &instancepb.ListInstanceConfigsRequest{ + Parent: formattedParent, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListInstanceConfigs(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestInstanceAdminGetInstanceConfig(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var expectedResponse = &instancepb.InstanceConfig{ + Name: name2, + DisplayName: displayName, + } + + mockInstanceAdmin.err = nil + mockInstanceAdmin.reqs = nil + + mockInstanceAdmin.resps = append(mockInstanceAdmin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/instanceConfigs/%s", "[PROJECT]", "[INSTANCE_CONFIG]") + var request = &instancepb.GetInstanceConfigRequest{ + Name: formattedName, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetInstanceConfig(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockInstanceAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestInstanceAdminGetInstanceConfigError(t *testing.T) { + errCode := codes.PermissionDenied + mockInstanceAdmin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/instanceConfigs/%s", "[PROJECT]", "[INSTANCE_CONFIG]") + var request = &instancepb.GetInstanceConfigRequest{ + Name: formattedName, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetInstanceConfig(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestInstanceAdminListInstances(t *testing.T) { + var nextPageToken string = "" + var instancesElement *instancepb.Instance = &instancepb.Instance{} + var instances = []*instancepb.Instance{instancesElement} + var expectedResponse = &instancepb.ListInstancesResponse{ + NextPageToken: nextPageToken, + Instances: instances, + } + + mockInstanceAdmin.err = nil + mockInstanceAdmin.reqs = nil + + mockInstanceAdmin.resps = append(mockInstanceAdmin.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &instancepb.ListInstancesRequest{ + Parent: formattedParent, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListInstances(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockInstanceAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Instances[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestInstanceAdminListInstancesError(t *testing.T) { + errCode := codes.PermissionDenied + mockInstanceAdmin.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var request = &instancepb.ListInstancesRequest{ + Parent: formattedParent, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListInstances(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestInstanceAdminGetInstance(t *testing.T) { + var name2 string = "name2-1052831874" + var config string = "config-1354792126" + var displayName string = "displayName1615086568" + var nodeCount int32 = 1539922066 + var expectedResponse = &instancepb.Instance{ + Name: name2, + Config: config, + DisplayName: displayName, + NodeCount: nodeCount, + } + + mockInstanceAdmin.err = nil + mockInstanceAdmin.reqs = nil + + mockInstanceAdmin.resps = append(mockInstanceAdmin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var request = &instancepb.GetInstanceRequest{ + Name: formattedName, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetInstance(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockInstanceAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestInstanceAdminGetInstanceError(t *testing.T) { + errCode := codes.PermissionDenied + mockInstanceAdmin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var request = &instancepb.GetInstanceRequest{ + Name: formattedName, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetInstance(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestInstanceAdminCreateInstance(t *testing.T) { + var name string = "name3373707" + var config string = "config-1354792126" + var displayName string = "displayName1615086568" + var nodeCount int32 = 1539922066 + var expectedResponse = &instancepb.Instance{ + Name: name, + Config: config, + DisplayName: displayName, + NodeCount: nodeCount, + } + + mockInstanceAdmin.err = nil + mockInstanceAdmin.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockInstanceAdmin.resps = append(mockInstanceAdmin.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var instanceId string = "instanceId-2101995259" + var instance *instancepb.Instance = &instancepb.Instance{} + var request = &instancepb.CreateInstanceRequest{ + Parent: formattedParent, + InstanceId: instanceId, + Instance: instance, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.CreateInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockInstanceAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestInstanceAdminCreateInstanceError(t *testing.T) { + errCode := codes.PermissionDenied + mockInstanceAdmin.err = nil + mockInstanceAdmin.resps = append(mockInstanceAdmin.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s", "[PROJECT]") + var instanceId string = "instanceId-2101995259" + var instance *instancepb.Instance = &instancepb.Instance{} + var request = &instancepb.CreateInstanceRequest{ + Parent: formattedParent, + InstanceId: instanceId, + Instance: instance, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.CreateInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestInstanceAdminUpdateInstance(t *testing.T) { + var name string = "name3373707" + var config string = "config-1354792126" + var displayName string = "displayName1615086568" + var nodeCount int32 = 1539922066 + var expectedResponse = &instancepb.Instance{ + Name: name, + Config: config, + DisplayName: displayName, + NodeCount: nodeCount, + } + + mockInstanceAdmin.err = nil + mockInstanceAdmin.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockInstanceAdmin.resps = append(mockInstanceAdmin.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var instance *instancepb.Instance = &instancepb.Instance{} + var fieldMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &instancepb.UpdateInstanceRequest{ + Instance: instance, + FieldMask: fieldMask, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.UpdateInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockInstanceAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestInstanceAdminUpdateInstanceError(t *testing.T) { + errCode := codes.PermissionDenied + mockInstanceAdmin.err = nil + mockInstanceAdmin.resps = append(mockInstanceAdmin.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var instance *instancepb.Instance = &instancepb.Instance{} + var fieldMask *field_maskpb.FieldMask = &field_maskpb.FieldMask{} + var request = &instancepb.UpdateInstanceRequest{ + Instance: instance, + FieldMask: fieldMask, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.UpdateInstance(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestInstanceAdminDeleteInstance(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockInstanceAdmin.err = nil + mockInstanceAdmin.reqs = nil + + mockInstanceAdmin.resps = append(mockInstanceAdmin.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var request = &instancepb.DeleteInstanceRequest{ + Name: formattedName, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteInstance(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockInstanceAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestInstanceAdminDeleteInstanceError(t *testing.T) { + errCode := codes.PermissionDenied + mockInstanceAdmin.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var request = &instancepb.DeleteInstanceRequest{ + Name: formattedName, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteInstance(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestInstanceAdminSetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockInstanceAdmin.err = nil + mockInstanceAdmin.reqs = nil + + mockInstanceAdmin.resps = append(mockInstanceAdmin.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockInstanceAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestInstanceAdminSetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockInstanceAdmin.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var policy *iampb.Policy = &iampb.Policy{} + var request = &iampb.SetIamPolicyRequest{ + Resource: formattedResource, + Policy: policy, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SetIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestInstanceAdminGetIamPolicy(t *testing.T) { + var version int32 = 351608024 + var etag []byte = []byte("21") + var expectedResponse = &iampb.Policy{ + Version: version, + Etag: etag, + } + + mockInstanceAdmin.err = nil + mockInstanceAdmin.reqs = nil + + mockInstanceAdmin.resps = append(mockInstanceAdmin.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIamPolicy(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockInstanceAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestInstanceAdminGetIamPolicyError(t *testing.T) { + errCode := codes.PermissionDenied + mockInstanceAdmin.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var request = &iampb.GetIamPolicyRequest{ + Resource: formattedResource, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetIamPolicy(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestInstanceAdminTestIamPermissions(t *testing.T) { + var expectedResponse *iampb.TestIamPermissionsResponse = &iampb.TestIamPermissionsResponse{} + + mockInstanceAdmin.err = nil + mockInstanceAdmin.reqs = nil + + mockInstanceAdmin.resps = append(mockInstanceAdmin.resps[:0], expectedResponse) + + var formattedResource string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockInstanceAdmin.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestInstanceAdminTestIamPermissionsError(t *testing.T) { + errCode := codes.PermissionDenied + mockInstanceAdmin.err = gstatus.Error(errCode, "test error") + + var formattedResource string = fmt.Sprintf("projects/%s/instances/%s", "[PROJECT]", "[INSTANCE]") + var permissions []string = nil + var request = &iampb.TestIamPermissionsRequest{ + Resource: formattedResource, + Permissions: permissions, + } + + c, err := NewInstanceAdminClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.TestIamPermissions(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/path_funcs.go b/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/path_funcs.go new file mode 100644 index 00000000..a2255805 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/admin/instance/apiv1/path_funcs.go @@ -0,0 +1,55 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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 instance + +// InstanceAdminProjectPath returns the path for the project resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s", project) +// instead. +func InstanceAdminProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} + +// InstanceAdminInstanceConfigPath returns the path for the instance config resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/instanceConfigs/%s", project, instanceConfig) +// instead. +func InstanceAdminInstanceConfigPath(project, instanceConfig string) string { + return "" + + "projects/" + + project + + "/instanceConfigs/" + + instanceConfig + + "" +} + +// InstanceAdminInstancePath returns the path for the instance resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/instances/%s", project, instance) +// instead. +func InstanceAdminInstancePath(project, instance string) string { + return "" + + "projects/" + + project + + "/instances/" + + instance + + "" +} diff --git a/vendor/cloud.google.com/go/spanner/apiv1/doc.go b/vendor/cloud.google.com/go/spanner/apiv1/doc.go new file mode 100644 index 00000000..34fdd0bf --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/apiv1/doc.go @@ -0,0 +1,93 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package spanner is an auto-generated package for the +// Cloud Spanner API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Cloud Spanner is a managed, mission-critical, globally consistent and +// scalable relational database service. +// +// Use the client at cloud.google.com/go/spanner in preference to this. +package spanner // import "cloud.google.com/go/spanner/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/spanner.data", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/spanner/apiv1/mock_test.go b/vendor/cloud.google.com/go/spanner/apiv1/mock_test.go new file mode 100644 index 00000000..e451c872 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/apiv1/mock_test.go @@ -0,0 +1,1085 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package spanner + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + spannerpb "google.golang.org/genproto/googleapis/spanner/v1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockSpannerServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + spannerpb.SpannerServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockSpannerServer) CreateSession(ctx context.Context, req *spannerpb.CreateSessionRequest) (*spannerpb.Session, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*spannerpb.Session), nil +} + +func (s *mockSpannerServer) GetSession(ctx context.Context, req *spannerpb.GetSessionRequest) (*spannerpb.Session, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*spannerpb.Session), nil +} + +func (s *mockSpannerServer) ListSessions(ctx context.Context, req *spannerpb.ListSessionsRequest) (*spannerpb.ListSessionsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*spannerpb.ListSessionsResponse), nil +} + +func (s *mockSpannerServer) DeleteSession(ctx context.Context, req *spannerpb.DeleteSessionRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockSpannerServer) ExecuteSql(ctx context.Context, req *spannerpb.ExecuteSqlRequest) (*spannerpb.ResultSet, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*spannerpb.ResultSet), nil +} + +func (s *mockSpannerServer) ExecuteStreamingSql(req *spannerpb.ExecuteSqlRequest, stream spannerpb.Spanner_ExecuteStreamingSqlServer) error { + md, _ := metadata.FromIncomingContext(stream.Context()) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return s.err + } + for _, v := range s.resps { + if err := stream.Send(v.(*spannerpb.PartialResultSet)); err != nil { + return err + } + } + return nil +} + +func (s *mockSpannerServer) Read(ctx context.Context, req *spannerpb.ReadRequest) (*spannerpb.ResultSet, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*spannerpb.ResultSet), nil +} + +func (s *mockSpannerServer) StreamingRead(req *spannerpb.ReadRequest, stream spannerpb.Spanner_StreamingReadServer) error { + md, _ := metadata.FromIncomingContext(stream.Context()) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return s.err + } + for _, v := range s.resps { + if err := stream.Send(v.(*spannerpb.PartialResultSet)); err != nil { + return err + } + } + return nil +} + +func (s *mockSpannerServer) BeginTransaction(ctx context.Context, req *spannerpb.BeginTransactionRequest) (*spannerpb.Transaction, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*spannerpb.Transaction), nil +} + +func (s *mockSpannerServer) Commit(ctx context.Context, req *spannerpb.CommitRequest) (*spannerpb.CommitResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*spannerpb.CommitResponse), nil +} + +func (s *mockSpannerServer) Rollback(ctx context.Context, req *spannerpb.RollbackRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockSpannerServer) PartitionQuery(ctx context.Context, req *spannerpb.PartitionQueryRequest) (*spannerpb.PartitionResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*spannerpb.PartitionResponse), nil +} + +func (s *mockSpannerServer) PartitionRead(ctx context.Context, req *spannerpb.PartitionReadRequest) (*spannerpb.PartitionResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*spannerpb.PartitionResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockSpanner mockSpannerServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + spannerpb.RegisterSpannerServer(serv, &mockSpanner) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestSpannerCreateSession(t *testing.T) { + var name string = "name3373707" + var expectedResponse = &spannerpb.Session{ + Name: name, + } + + mockSpanner.err = nil + mockSpanner.reqs = nil + + mockSpanner.resps = append(mockSpanner.resps[:0], expectedResponse) + + var formattedDatabase string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var request = &spannerpb.CreateSessionRequest{ + Database: formattedDatabase, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSession(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpanner.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpannerCreateSessionError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpanner.err = gstatus.Error(errCode, "test error") + + var formattedDatabase string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var request = &spannerpb.CreateSessionRequest{ + Database: formattedDatabase, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSession(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpannerGetSession(t *testing.T) { + var name2 string = "name2-1052831874" + var expectedResponse = &spannerpb.Session{ + Name: name2, + } + + mockSpanner.err = nil + mockSpanner.reqs = nil + + mockSpanner.resps = append(mockSpanner.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var request = &spannerpb.GetSessionRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSession(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpanner.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpannerGetSessionError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpanner.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var request = &spannerpb.GetSessionRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetSession(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpannerListSessions(t *testing.T) { + var nextPageToken string = "" + var sessionsElement *spannerpb.Session = &spannerpb.Session{} + var sessions = []*spannerpb.Session{sessionsElement} + var expectedResponse = &spannerpb.ListSessionsResponse{ + NextPageToken: nextPageToken, + Sessions: sessions, + } + + mockSpanner.err = nil + mockSpanner.reqs = nil + + mockSpanner.resps = append(mockSpanner.resps[:0], expectedResponse) + + var formattedDatabase string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var request = &spannerpb.ListSessionsRequest{ + Database: formattedDatabase, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListSessions(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpanner.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Sessions[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpannerListSessionsError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpanner.err = gstatus.Error(errCode, "test error") + + var formattedDatabase string = fmt.Sprintf("projects/%s/instances/%s/databases/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]") + var request = &spannerpb.ListSessionsRequest{ + Database: formattedDatabase, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListSessions(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpannerDeleteSession(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockSpanner.err = nil + mockSpanner.reqs = nil + + mockSpanner.resps = append(mockSpanner.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var request = &spannerpb.DeleteSessionRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSession(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpanner.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestSpannerDeleteSessionError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpanner.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var request = &spannerpb.DeleteSessionRequest{ + Name: formattedName, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteSession(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestSpannerExecuteSql(t *testing.T) { + var expectedResponse *spannerpb.ResultSet = &spannerpb.ResultSet{} + + mockSpanner.err = nil + mockSpanner.reqs = nil + + mockSpanner.resps = append(mockSpanner.resps[:0], expectedResponse) + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var sql string = "sql114126" + var request = &spannerpb.ExecuteSqlRequest{ + Session: formattedSession, + Sql: sql, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ExecuteSql(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpanner.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpannerExecuteSqlError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpanner.err = gstatus.Error(errCode, "test error") + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var sql string = "sql114126" + var request = &spannerpb.ExecuteSqlRequest{ + Session: formattedSession, + Sql: sql, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ExecuteSql(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpannerExecuteStreamingSql(t *testing.T) { + var chunkedValue bool = true + var resumeToken []byte = []byte("103") + var expectedResponse = &spannerpb.PartialResultSet{ + ChunkedValue: chunkedValue, + ResumeToken: resumeToken, + } + + mockSpanner.err = nil + mockSpanner.reqs = nil + + mockSpanner.resps = append(mockSpanner.resps[:0], expectedResponse) + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var sql string = "sql114126" + var request = &spannerpb.ExecuteSqlRequest{ + Session: formattedSession, + Sql: sql, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.ExecuteStreamingSql(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpanner.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpannerExecuteStreamingSqlError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpanner.err = gstatus.Error(errCode, "test error") + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var sql string = "sql114126" + var request = &spannerpb.ExecuteSqlRequest{ + Session: formattedSession, + Sql: sql, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.ExecuteStreamingSql(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpannerRead(t *testing.T) { + var expectedResponse *spannerpb.ResultSet = &spannerpb.ResultSet{} + + mockSpanner.err = nil + mockSpanner.reqs = nil + + mockSpanner.resps = append(mockSpanner.resps[:0], expectedResponse) + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var table string = "table110115790" + var columns []string = nil + var keySet *spannerpb.KeySet = &spannerpb.KeySet{} + var request = &spannerpb.ReadRequest{ + Session: formattedSession, + Table: table, + Columns: columns, + KeySet: keySet, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Read(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpanner.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpannerReadError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpanner.err = gstatus.Error(errCode, "test error") + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var table string = "table110115790" + var columns []string = nil + var keySet *spannerpb.KeySet = &spannerpb.KeySet{} + var request = &spannerpb.ReadRequest{ + Session: formattedSession, + Table: table, + Columns: columns, + KeySet: keySet, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Read(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpannerStreamingRead(t *testing.T) { + var chunkedValue bool = true + var resumeToken []byte = []byte("103") + var expectedResponse = &spannerpb.PartialResultSet{ + ChunkedValue: chunkedValue, + ResumeToken: resumeToken, + } + + mockSpanner.err = nil + mockSpanner.reqs = nil + + mockSpanner.resps = append(mockSpanner.resps[:0], expectedResponse) + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var table string = "table110115790" + var columns []string = nil + var keySet *spannerpb.KeySet = &spannerpb.KeySet{} + var request = &spannerpb.ReadRequest{ + Session: formattedSession, + Table: table, + Columns: columns, + KeySet: keySet, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.StreamingRead(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpanner.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpannerStreamingReadError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpanner.err = gstatus.Error(errCode, "test error") + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var table string = "table110115790" + var columns []string = nil + var keySet *spannerpb.KeySet = &spannerpb.KeySet{} + var request = &spannerpb.ReadRequest{ + Session: formattedSession, + Table: table, + Columns: columns, + KeySet: keySet, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.StreamingRead(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpannerBeginTransaction(t *testing.T) { + var id []byte = []byte("27") + var expectedResponse = &spannerpb.Transaction{ + Id: id, + } + + mockSpanner.err = nil + mockSpanner.reqs = nil + + mockSpanner.resps = append(mockSpanner.resps[:0], expectedResponse) + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var options *spannerpb.TransactionOptions = &spannerpb.TransactionOptions{} + var request = &spannerpb.BeginTransactionRequest{ + Session: formattedSession, + Options: options, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BeginTransaction(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpanner.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpannerBeginTransactionError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpanner.err = gstatus.Error(errCode, "test error") + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var options *spannerpb.TransactionOptions = &spannerpb.TransactionOptions{} + var request = &spannerpb.BeginTransactionRequest{ + Session: formattedSession, + Options: options, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BeginTransaction(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpannerCommit(t *testing.T) { + var expectedResponse *spannerpb.CommitResponse = &spannerpb.CommitResponse{} + + mockSpanner.err = nil + mockSpanner.reqs = nil + + mockSpanner.resps = append(mockSpanner.resps[:0], expectedResponse) + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var mutations []*spannerpb.Mutation = nil + var request = &spannerpb.CommitRequest{ + Session: formattedSession, + Mutations: mutations, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Commit(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpanner.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpannerCommitError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpanner.err = gstatus.Error(errCode, "test error") + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var mutations []*spannerpb.Mutation = nil + var request = &spannerpb.CommitRequest{ + Session: formattedSession, + Mutations: mutations, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Commit(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpannerRollback(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockSpanner.err = nil + mockSpanner.reqs = nil + + mockSpanner.resps = append(mockSpanner.resps[:0], expectedResponse) + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var transactionId []byte = []byte("28") + var request = &spannerpb.RollbackRequest{ + Session: formattedSession, + TransactionId: transactionId, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.Rollback(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpanner.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestSpannerRollbackError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpanner.err = gstatus.Error(errCode, "test error") + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var transactionId []byte = []byte("28") + var request = &spannerpb.RollbackRequest{ + Session: formattedSession, + TransactionId: transactionId, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.Rollback(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestSpannerPartitionQuery(t *testing.T) { + var expectedResponse *spannerpb.PartitionResponse = &spannerpb.PartitionResponse{} + + mockSpanner.err = nil + mockSpanner.reqs = nil + + mockSpanner.resps = append(mockSpanner.resps[:0], expectedResponse) + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var sql string = "sql114126" + var request = &spannerpb.PartitionQueryRequest{ + Session: formattedSession, + Sql: sql, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PartitionQuery(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpanner.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpannerPartitionQueryError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpanner.err = gstatus.Error(errCode, "test error") + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var sql string = "sql114126" + var request = &spannerpb.PartitionQueryRequest{ + Session: formattedSession, + Sql: sql, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PartitionQuery(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpannerPartitionRead(t *testing.T) { + var expectedResponse *spannerpb.PartitionResponse = &spannerpb.PartitionResponse{} + + mockSpanner.err = nil + mockSpanner.reqs = nil + + mockSpanner.resps = append(mockSpanner.resps[:0], expectedResponse) + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var table string = "table110115790" + var keySet *spannerpb.KeySet = &spannerpb.KeySet{} + var request = &spannerpb.PartitionReadRequest{ + Session: formattedSession, + Table: table, + KeySet: keySet, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PartitionRead(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpanner.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpannerPartitionReadError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpanner.err = gstatus.Error(errCode, "test error") + + var formattedSession string = fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", "[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") + var table string = "table110115790" + var keySet *spannerpb.KeySet = &spannerpb.KeySet{} + var request = &spannerpb.PartitionReadRequest{ + Session: formattedSession, + Table: table, + KeySet: keySet, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.PartitionRead(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/spanner/apiv1/path_funcs.go b/vendor/cloud.google.com/go/spanner/apiv1/path_funcs.go new file mode 100644 index 00000000..19f30adb --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/apiv1/path_funcs.go @@ -0,0 +1,49 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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 spanner + +// DatabasePath returns the path for the database resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/instances/%s/databases/%s", project, instance, database) +// instead. +func DatabasePath(project, instance, database string) string { + return "" + + "projects/" + + project + + "/instances/" + + instance + + "/databases/" + + database + + "" +} + +// SessionPath returns the path for the session resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/instances/%s/databases/%s/sessions/%s", project, instance, database, session) +// instead. +func SessionPath(project, instance, database, session string) string { + return "" + + "projects/" + + project + + "/instances/" + + instance + + "/databases/" + + database + + "/sessions/" + + session + + "" +} diff --git a/vendor/cloud.google.com/go/spanner/apiv1/spanner_client.go b/vendor/cloud.google.com/go/spanner/apiv1/spanner_client.go new file mode 100644 index 00000000..8db16f2c --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/apiv1/spanner_client.go @@ -0,0 +1,510 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package spanner + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + spannerpb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + CreateSession []gax.CallOption + GetSession []gax.CallOption + ListSessions []gax.CallOption + DeleteSession []gax.CallOption + ExecuteSql []gax.CallOption + ExecuteStreamingSql []gax.CallOption + Read []gax.CallOption + StreamingRead []gax.CallOption + BeginTransaction []gax.CallOption + Commit []gax.CallOption + Rollback []gax.CallOption + PartitionQuery []gax.CallOption + PartitionRead []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("spanner.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 32000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + {"long_running", "long_running"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.Unavailable, + }, gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 32000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + CreateSession: retry[[2]string{"default", "idempotent"}], + GetSession: retry[[2]string{"default", "idempotent"}], + ListSessions: retry[[2]string{"default", "idempotent"}], + DeleteSession: retry[[2]string{"default", "idempotent"}], + ExecuteSql: retry[[2]string{"default", "idempotent"}], + ExecuteStreamingSql: retry[[2]string{"streaming", "non_idempotent"}], + Read: retry[[2]string{"default", "idempotent"}], + StreamingRead: retry[[2]string{"streaming", "non_idempotent"}], + BeginTransaction: retry[[2]string{"default", "idempotent"}], + Commit: retry[[2]string{"long_running", "long_running"}], + Rollback: retry[[2]string{"default", "idempotent"}], + PartitionQuery: retry[[2]string{"default", "idempotent"}], + PartitionRead: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Cloud Spanner API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client spannerpb.SpannerClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new spanner client. +// +// Cloud Spanner API +// +// The Cloud Spanner API can be used to manage sessions and execute +// transactions on data stored in Cloud Spanner databases. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: spannerpb.NewSpannerClient(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// CreateSession creates a new session. A session can be used to perform +// transactions that read and/or modify data in a Cloud Spanner database. +// Sessions are meant to be reused for many consecutive +// transactions. +// +// Sessions can only execute one transaction at a time. To execute +// multiple concurrent read-write/write-only transactions, create +// multiple sessions. Note that standalone reads and queries use a +// transaction internally, and count toward the one transaction +// limit. +// +// Cloud Spanner limits the number of sessions that can exist at any given +// time; thus, it is a good idea to delete idle and/or unneeded sessions. +// Aside from explicit deletes, Cloud Spanner can delete sessions for which no +// operations are sent for more than an hour. If a session is deleted, +// requests to it return NOT_FOUND. +// +// Idle sessions can be kept alive by sending a trivial SQL query +// periodically, e.g., "SELECT 1". +func (c *Client) CreateSession(ctx context.Context, req *spannerpb.CreateSessionRequest, opts ...gax.CallOption) (*spannerpb.Session, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateSession[0:len(c.CallOptions.CreateSession):len(c.CallOptions.CreateSession)], opts...) + var resp *spannerpb.Session + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateSession(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// GetSession gets a session. Returns NOT_FOUND if the session does not exist. +// This is mainly useful for determining whether a session is still +// alive. +func (c *Client) GetSession(ctx context.Context, req *spannerpb.GetSessionRequest, opts ...gax.CallOption) (*spannerpb.Session, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetSession[0:len(c.CallOptions.GetSession):len(c.CallOptions.GetSession)], opts...) + var resp *spannerpb.Session + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetSession(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListSessions lists all sessions in a given database. +func (c *Client) ListSessions(ctx context.Context, req *spannerpb.ListSessionsRequest, opts ...gax.CallOption) *SessionIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListSessions[0:len(c.CallOptions.ListSessions):len(c.CallOptions.ListSessions)], opts...) + it := &SessionIterator{} + req = proto.Clone(req).(*spannerpb.ListSessionsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*spannerpb.Session, string, error) { + var resp *spannerpb.ListSessionsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListSessions(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Sessions, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// DeleteSession ends a session, releasing server resources associated with it. +func (c *Client) DeleteSession(ctx context.Context, req *spannerpb.DeleteSessionRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteSession[0:len(c.CallOptions.DeleteSession):len(c.CallOptions.DeleteSession)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.DeleteSession(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ExecuteSql executes an SQL statement, returning all results in a single reply. This +// method cannot be used to return a result set larger than 10 MiB; +// if the query yields more data than that, the query fails with +// a FAILED_PRECONDITION error. +// +// Operations inside read-write transactions might return ABORTED. If +// this occurs, the application should restart the transaction from +// the beginning. See [Transaction][google.spanner.v1.Transaction] for more details. +// +// Larger result sets can be fetched in streaming fashion by calling +// [ExecuteStreamingSql][google.spanner.v1.Spanner.ExecuteStreamingSql] instead. +func (c *Client) ExecuteSql(ctx context.Context, req *spannerpb.ExecuteSqlRequest, opts ...gax.CallOption) (*spannerpb.ResultSet, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ExecuteSql[0:len(c.CallOptions.ExecuteSql):len(c.CallOptions.ExecuteSql)], opts...) + var resp *spannerpb.ResultSet + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ExecuteSql(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ExecuteStreamingSql like [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql], except returns the result +// set as a stream. Unlike [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql], there +// is no limit on the size of the returned result set. However, no +// individual row in the result set can exceed 100 MiB, and no +// column value can exceed 10 MiB. +func (c *Client) ExecuteStreamingSql(ctx context.Context, req *spannerpb.ExecuteSqlRequest, opts ...gax.CallOption) (spannerpb.Spanner_ExecuteStreamingSqlClient, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ExecuteStreamingSql[0:len(c.CallOptions.ExecuteStreamingSql):len(c.CallOptions.ExecuteStreamingSql)], opts...) + var resp spannerpb.Spanner_ExecuteStreamingSqlClient + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ExecuteStreamingSql(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Read reads rows from the database using key lookups and scans, as a +// simple key/value style alternative to +// [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql]. This method cannot be used to +// return a result set larger than 10 MiB; if the read matches more +// data than that, the read fails with a FAILED_PRECONDITION +// error. +// +// Reads inside read-write transactions might return ABORTED. If +// this occurs, the application should restart the transaction from +// the beginning. See [Transaction][google.spanner.v1.Transaction] for more details. +// +// Larger result sets can be yielded in streaming fashion by calling +// [StreamingRead][google.spanner.v1.Spanner.StreamingRead] instead. +func (c *Client) Read(ctx context.Context, req *spannerpb.ReadRequest, opts ...gax.CallOption) (*spannerpb.ResultSet, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Read[0:len(c.CallOptions.Read):len(c.CallOptions.Read)], opts...) + var resp *spannerpb.ResultSet + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.Read(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// StreamingRead like [Read][google.spanner.v1.Spanner.Read], except returns the result set as a +// stream. Unlike [Read][google.spanner.v1.Spanner.Read], there is no limit on the +// size of the returned result set. However, no individual row in +// the result set can exceed 100 MiB, and no column value can exceed +// 10 MiB. +func (c *Client) StreamingRead(ctx context.Context, req *spannerpb.ReadRequest, opts ...gax.CallOption) (spannerpb.Spanner_StreamingReadClient, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.StreamingRead[0:len(c.CallOptions.StreamingRead):len(c.CallOptions.StreamingRead)], opts...) + var resp spannerpb.Spanner_StreamingReadClient + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.StreamingRead(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// BeginTransaction begins a new transaction. This step can often be skipped: +// [Read][google.spanner.v1.Spanner.Read], [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql] and +// [Commit][google.spanner.v1.Spanner.Commit] can begin a new transaction as a +// side-effect. +func (c *Client) BeginTransaction(ctx context.Context, req *spannerpb.BeginTransactionRequest, opts ...gax.CallOption) (*spannerpb.Transaction, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BeginTransaction[0:len(c.CallOptions.BeginTransaction):len(c.CallOptions.BeginTransaction)], opts...) + var resp *spannerpb.Transaction + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.BeginTransaction(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Commit commits a transaction. The request includes the mutations to be +// applied to rows in the database. +// +// Commit might return an ABORTED error. This can occur at any time; +// commonly, the cause is conflicts with concurrent +// transactions. However, it can also happen for a variety of other +// reasons. If Commit returns ABORTED, the caller should re-attempt +// the transaction from the beginning, re-using the same session. +func (c *Client) Commit(ctx context.Context, req *spannerpb.CommitRequest, opts ...gax.CallOption) (*spannerpb.CommitResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Commit[0:len(c.CallOptions.Commit):len(c.CallOptions.Commit)], opts...) + var resp *spannerpb.CommitResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.Commit(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// Rollback rolls back a transaction, releasing any locks it holds. It is a good +// idea to call this for any transaction that includes one or more +// [Read][google.spanner.v1.Spanner.Read] or [ExecuteSql][google.spanner.v1.Spanner.ExecuteSql] requests and +// ultimately decides not to commit. +// +// Rollback returns OK if it successfully aborts the transaction, the +// transaction was already aborted, or the transaction is not +// found. Rollback never returns ABORTED. +func (c *Client) Rollback(ctx context.Context, req *spannerpb.RollbackRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Rollback[0:len(c.CallOptions.Rollback):len(c.CallOptions.Rollback)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.Rollback(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// PartitionQuery creates a set of partition tokens that can be used to execute a query +// operation in parallel. Each of the returned partition tokens can be used +// by [ExecuteStreamingSql][google.spanner.v1.Spanner.ExecuteStreamingSql] to specify a subset +// of the query result to read. The same session and read-only transaction +// must be used by the PartitionQueryRequest used to create the +// partition tokens and the ExecuteSqlRequests that use the partition tokens. +// +// Partition tokens become invalid when the session used to create them +// is deleted, is idle for too long, begins a new transaction, or becomes too +// old. When any of these happen, it is not possible to resume the query, and +// the whole operation must be restarted from the beginning. +func (c *Client) PartitionQuery(ctx context.Context, req *spannerpb.PartitionQueryRequest, opts ...gax.CallOption) (*spannerpb.PartitionResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.PartitionQuery[0:len(c.CallOptions.PartitionQuery):len(c.CallOptions.PartitionQuery)], opts...) + var resp *spannerpb.PartitionResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.PartitionQuery(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// PartitionRead creates a set of partition tokens that can be used to execute a read +// operation in parallel. Each of the returned partition tokens can be used +// by [StreamingRead][google.spanner.v1.Spanner.StreamingRead] to specify a subset of the read +// result to read. The same session and read-only transaction must be used by +// the PartitionReadRequest used to create the partition tokens and the +// ReadRequests that use the partition tokens. There are no ordering +// guarantees on rows returned among the returned partition tokens, or even +// within each individual StreamingRead call issued with a partition_token. +// +// Partition tokens become invalid when the session used to create them +// is deleted, is idle for too long, begins a new transaction, or becomes too +// old. When any of these happen, it is not possible to resume the read, and +// the whole operation must be restarted from the beginning. +func (c *Client) PartitionRead(ctx context.Context, req *spannerpb.PartitionReadRequest, opts ...gax.CallOption) (*spannerpb.PartitionResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.PartitionRead[0:len(c.CallOptions.PartitionRead):len(c.CallOptions.PartitionRead)], opts...) + var resp *spannerpb.PartitionResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.PartitionRead(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SessionIterator manages a stream of *spannerpb.Session. +type SessionIterator struct { + items []*spannerpb.Session + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*spannerpb.Session, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *SessionIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *SessionIterator) Next() (*spannerpb.Session, error) { + var item *spannerpb.Session + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *SessionIterator) bufLen() int { + return len(it.items) +} + +func (it *SessionIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/spanner/apiv1/spanner_client_example_test.go b/vendor/cloud.google.com/go/spanner/apiv1/spanner_client_example_test.go new file mode 100644 index 00000000..b4c2311d --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/apiv1/spanner_client_example_test.go @@ -0,0 +1,290 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package spanner_test + +import ( + "context" + "io" + + spanner "cloud.google.com/go/spanner/apiv1" + "google.golang.org/api/iterator" + spannerpb "google.golang.org/genproto/googleapis/spanner/v1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_CreateSession() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &spannerpb.CreateSessionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateSession(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_GetSession() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &spannerpb.GetSessionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetSession(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ListSessions() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &spannerpb.ListSessionsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListSessions(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_DeleteSession() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &spannerpb.DeleteSessionRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteSession(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_ExecuteSql() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &spannerpb.ExecuteSqlRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ExecuteSql(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ExecuteStreamingSql() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &spannerpb.ExecuteSqlRequest{ + // TODO: Fill request struct fields. + } + stream, err := c.ExecuteStreamingSql(ctx, req) + if err != nil { + // TODO: Handle error. + } + for { + resp, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + // TODO: handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_Read() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &spannerpb.ReadRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Read(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_StreamingRead() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &spannerpb.ReadRequest{ + // TODO: Fill request struct fields. + } + stream, err := c.StreamingRead(ctx, req) + if err != nil { + // TODO: Handle error. + } + for { + resp, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + // TODO: handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleClient_BeginTransaction() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &spannerpb.BeginTransactionRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.BeginTransaction(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_Commit() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &spannerpb.CommitRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Commit(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_Rollback() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &spannerpb.RollbackRequest{ + // TODO: Fill request struct fields. + } + err = c.Rollback(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_PartitionQuery() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &spannerpb.PartitionQueryRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.PartitionQuery(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_PartitionRead() { + ctx := context.Background() + c, err := spanner.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &spannerpb.PartitionReadRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.PartitionRead(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/spanner/appengine.go b/vendor/cloud.google.com/go/spanner/appengine.go new file mode 100644 index 00000000..c7ce1b4d --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/appengine.go @@ -0,0 +1,20 @@ +// Copyright 2017 Google LLC +// +// 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. + +// +build appengine + +package spanner + +// numChannels is the default value for NumChannels of client +const numChannels = 1 diff --git a/vendor/cloud.google.com/go/spanner/backoff.go b/vendor/cloud.google.com/go/spanner/backoff.go new file mode 100644 index 00000000..b2e13e9e --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/backoff.go @@ -0,0 +1,58 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "math/rand" + "time" +) + +const ( + // minBackoff is the minimum backoff used by default. + minBackoff = 1 * time.Second + // maxBackoff is the maximum backoff used by default. + maxBackoff = 32 * time.Second + // jitter is the jitter factor. + jitter = 0.4 + // rate is the rate of exponential increase in the backoff. + rate = 1.3 +) + +var defaultBackoff = exponentialBackoff{minBackoff, maxBackoff} + +type exponentialBackoff struct { + min, max time.Duration +} + +// delay calculates the delay that should happen at n-th +// exponential backoff in a series. +func (b exponentialBackoff) delay(retries int) time.Duration { + min, max := float64(b.min), float64(b.max) + delay := min + for delay < max && retries > 0 { + delay *= rate + retries-- + } + if delay > max { + delay = max + } + delay -= delay * jitter * rand.Float64() + if delay < min { + delay = min + } + return time.Duration(delay) +} diff --git a/vendor/cloud.google.com/go/spanner/backoff_test.go b/vendor/cloud.google.com/go/spanner/backoff_test.go new file mode 100644 index 00000000..150af0ae --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/backoff_test.go @@ -0,0 +1,61 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "math" + "testing" + "time" +) + +// Test if exponential backoff helper can produce correct series of +// retry delays. +func TestBackoff(t *testing.T) { + b := exponentialBackoff{minBackoff, maxBackoff} + tests := []struct { + retries int + min time.Duration + max time.Duration + }{ + { + retries: 0, + min: minBackoff, + max: minBackoff, + }, + { + retries: 1, + min: minBackoff, + max: time.Duration(rate * float64(minBackoff)), + }, + { + retries: 3, + min: time.Duration(math.Pow(rate, 3) * (1 - jitter) * float64(minBackoff)), + max: time.Duration(math.Pow(rate, 3) * float64(minBackoff)), + }, + { + retries: 1000, + min: time.Duration((1 - jitter) * float64(maxBackoff)), + max: maxBackoff, + }, + } + for _, test := range tests { + got := b.delay(test.retries) + if float64(got) < float64(test.min) || float64(got) > float64(test.max) { + t.Errorf("delay(%v) = %v, want in range [%v, %v]", test.retries, got, test.min, test.max) + } + } +} diff --git a/vendor/cloud.google.com/go/spanner/batch.go b/vendor/cloud.google.com/go/spanner/batch.go new file mode 100644 index 00000000..eceaed0a --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/batch.go @@ -0,0 +1,347 @@ +/* +Copyright 2018 Google LLC + +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 spanner + +import ( + "bytes" + "context" + "encoding/gob" + "log" + "time" + + "github.com/golang/protobuf/proto" + sppb "google.golang.org/genproto/googleapis/spanner/v1" +) + +// BatchReadOnlyTransaction is a ReadOnlyTransaction that allows for exporting +// arbitrarily large amounts of data from Cloud Spanner databases. +// BatchReadOnlyTransaction partitions a read/query request. Read/query request +// can then be executed independently over each partition while observing the +// same snapshot of the database. BatchReadOnlyTransaction can also be shared +// across multiple clients by passing around the BatchReadOnlyTransactionID and +// then recreating the transaction using Client.BatchReadOnlyTransactionFromID. +// +// Note: if a client is used only to run partitions, you can +// create it using a ClientConfig with both MinOpened and MaxIdle set to +// zero to avoid creating unnecessary sessions. You can also avoid excess +// gRPC channels by setting ClientConfig.NumChannels to the number of +// concurrently active BatchReadOnlyTransactions you expect to have. +type BatchReadOnlyTransaction struct { + ReadOnlyTransaction + ID BatchReadOnlyTransactionID +} + +// BatchReadOnlyTransactionID is a unique identifier for a +// BatchReadOnlyTransaction. It can be used to re-create a +// BatchReadOnlyTransaction on a different machine or process by calling +// Client.BatchReadOnlyTransactionFromID. +type BatchReadOnlyTransactionID struct { + // unique ID for the transaction. + tid transactionID + // sid is the id of the Cloud Spanner session used for this transaction. + sid string + // rts is the read timestamp of this transaction. + rts time.Time +} + +// Partition defines a segment of data to be read in a batch read or query. A +// partition can be serialized and processed across several different machines +// or processes. +type Partition struct { + pt []byte + qreq *sppb.ExecuteSqlRequest + rreq *sppb.ReadRequest +} + +// PartitionOptions specifies options for a PartitionQueryRequest and +// PartitionReadRequest. See +// https://godoc.org/google.golang.org/genproto/googleapis/spanner/v1#PartitionOptions +// for more details. +type PartitionOptions struct { + // The desired data size for each partition generated. + PartitionBytes int64 + // The desired maximum number of partitions to return. + MaxPartitions int64 +} + +// toProto converts a spanner.PartitionOptions into a sppb.PartitionOptions +func (opt PartitionOptions) toProto() *sppb.PartitionOptions { + return &sppb.PartitionOptions{ + PartitionSizeBytes: opt.PartitionBytes, + MaxPartitions: opt.MaxPartitions, + } +} + +// PartitionRead returns a list of Partitions that can be used to read rows from +// the database. These partitions can be executed across multiple processes, +// even across different machines. The partition size and count hints can be +// configured using PartitionOptions. +func (t *BatchReadOnlyTransaction) PartitionRead(ctx context.Context, table string, keys KeySet, columns []string, opt PartitionOptions) ([]*Partition, error) { + return t.PartitionReadUsingIndex(ctx, table, "", keys, columns, opt) +} + +// PartitionReadUsingIndex returns a list of Partitions that can be used to read +// rows from the database using an index. +func (t *BatchReadOnlyTransaction) PartitionReadUsingIndex(ctx context.Context, table, index string, keys KeySet, columns []string, opt PartitionOptions) ([]*Partition, error) { + sh, ts, err := t.acquire(ctx) + if err != nil { + return nil, err + } + sid, client := sh.getID(), sh.getClient() + var ( + kset *sppb.KeySet + resp *sppb.PartitionResponse + partitions []*Partition + ) + kset, err = keys.keySetProto() + // request Partitions + if err != nil { + return nil, err + } + resp, err = client.PartitionRead(ctx, &sppb.PartitionReadRequest{ + Session: sid, + Transaction: ts, + Table: table, + Index: index, + Columns: columns, + KeySet: kset, + PartitionOptions: opt.toProto(), + }) + // prepare ReadRequest + req := &sppb.ReadRequest{ + Session: sid, + Transaction: ts, + Table: table, + Index: index, + Columns: columns, + KeySet: kset, + } + // generate Partitions + for _, p := range resp.GetPartitions() { + partitions = append(partitions, &Partition{ + pt: p.PartitionToken, + rreq: req, + }) + } + return partitions, err +} + +// PartitionQuery returns a list of Partitions that can be used to execute a query against the database. +func (t *BatchReadOnlyTransaction) PartitionQuery(ctx context.Context, statement Statement, opt PartitionOptions) ([]*Partition, error) { + sh, ts, err := t.acquire(ctx) + if err != nil { + return nil, err + } + sid, client := sh.getID(), sh.getClient() + params, paramTypes, err := statement.convertParams() + if err != nil { + return nil, err + } + + // request Partitions + req := &sppb.PartitionQueryRequest{ + Session: sid, + Transaction: ts, + Sql: statement.SQL, + PartitionOptions: opt.toProto(), + Params: params, + ParamTypes: paramTypes, + } + resp, err := client.PartitionQuery(ctx, req) + + // prepare ExecuteSqlRequest + r := &sppb.ExecuteSqlRequest{ + Session: sid, + Transaction: ts, + Sql: statement.SQL, + Params: params, + ParamTypes: paramTypes, + } + + // generate Partitions + var partitions []*Partition + for _, p := range resp.GetPartitions() { + partitions = append(partitions, &Partition{ + pt: p.PartitionToken, + qreq: r, + }) + } + return partitions, err +} + +// release implements txReadEnv.release, noop. +func (t *BatchReadOnlyTransaction) release(err error) { +} + +// setTimestamp implements txReadEnv.setTimestamp, noop. +// read timestamp is ready on txn initialization, avoid contending writing to it with future partitions. +func (t *BatchReadOnlyTransaction) setTimestamp(ts time.Time) { +} + +// Close marks the txn as closed. +func (t *BatchReadOnlyTransaction) Close() { + t.mu.Lock() + defer t.mu.Unlock() + t.state = txClosed +} + +// Cleanup cleans up all the resources used by this transaction and makes +// it unusable. Once this method is invoked, the transaction is no longer +// usable anywhere, including other clients/processes with which this +// transaction was shared. +// +// Calling Cleanup is optional, but recommended. If Cleanup is not called, the +// transaction's resources will be freed when the session expires on the backend and +// is deleted. For more information about recycled sessions, see +// https://cloud.google.com/spanner/docs/sessions. +func (t *BatchReadOnlyTransaction) Cleanup(ctx context.Context) { + t.Close() + t.mu.Lock() + defer t.mu.Unlock() + sh := t.sh + if sh == nil { + return + } + t.sh = nil + sid, client := sh.getID(), sh.getClient() + err := runRetryable(ctx, func(ctx context.Context) error { + _, e := client.DeleteSession(ctx, &sppb.DeleteSessionRequest{Name: sid}) + return e + }) + if err != nil { + log.Printf("Failed to delete session %v. Error: %v", sid, err) + } +} + +// Execute runs a single Partition obtained from PartitionRead or PartitionQuery. +func (t *BatchReadOnlyTransaction) Execute(ctx context.Context, p *Partition) *RowIterator { + var ( + sh *sessionHandle + err error + rpc func(ct context.Context, resumeToken []byte) (streamingReceiver, error) + ) + if sh, _, err = t.acquire(ctx); err != nil { + return &RowIterator{err: err} + } + client := sh.getClient() + if client == nil { + // Might happen if transaction is closed in the middle of a API call. + return &RowIterator{err: errSessionClosed(sh)} + } + // read or query partition + if p.rreq != nil { + p.rreq.PartitionToken = p.pt + rpc = func(ctx context.Context, resumeToken []byte) (streamingReceiver, error) { + p.rreq.ResumeToken = resumeToken + return client.StreamingRead(ctx, p.rreq) + } + } else { + p.qreq.PartitionToken = p.pt + rpc = func(ctx context.Context, resumeToken []byte) (streamingReceiver, error) { + p.qreq.ResumeToken = resumeToken + return client.ExecuteStreamingSql(ctx, p.qreq) + } + } + return stream( + contextWithOutgoingMetadata(ctx, sh.getMetadata()), + rpc, + t.setTimestamp, + t.release) +} + +// MarshalBinary implements BinaryMarshaler. +func (tid BatchReadOnlyTransactionID) MarshalBinary() (data []byte, err error) { + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + if err := enc.Encode(tid.tid); err != nil { + return nil, err + } + if err := enc.Encode(tid.sid); err != nil { + return nil, err + } + if err := enc.Encode(tid.rts); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// UnmarshalBinary implements BinaryUnmarshaler. +func (tid *BatchReadOnlyTransactionID) UnmarshalBinary(data []byte) error { + dec := gob.NewDecoder(bytes.NewReader(data)) + if err := dec.Decode(&tid.tid); err != nil { + return err + } + if err := dec.Decode(&tid.sid); err != nil { + return err + } + return dec.Decode(&tid.rts) +} + +// MarshalBinary implements BinaryMarshaler. +func (p Partition) MarshalBinary() (data []byte, err error) { + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + if err := enc.Encode(p.pt); err != nil { + return nil, err + } + var isReadPartition bool + var req proto.Message + if p.rreq != nil { + isReadPartition = true + req = p.rreq + } else { + isReadPartition = false + req = p.qreq + } + if err := enc.Encode(isReadPartition); err != nil { + return nil, err + } + if data, err = proto.Marshal(req); err != nil { + return nil, err + } + if err := enc.Encode(data); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +// UnmarshalBinary implements BinaryUnmarshaler. +func (p *Partition) UnmarshalBinary(data []byte) error { + var ( + isReadPartition bool + d []byte + err error + ) + dec := gob.NewDecoder(bytes.NewReader(data)) + if err := dec.Decode(&p.pt); err != nil { + return err + } + if err := dec.Decode(&isReadPartition); err != nil { + return err + } + if err := dec.Decode(&d); err != nil { + return err + } + if isReadPartition { + p.rreq = &sppb.ReadRequest{} + err = proto.Unmarshal(d, p.rreq) + } else { + p.qreq = &sppb.ExecuteSqlRequest{} + err = proto.Unmarshal(d, p.qreq) + } + return err +} diff --git a/vendor/cloud.google.com/go/spanner/batch_test.go b/vendor/cloud.google.com/go/spanner/batch_test.go new file mode 100644 index 00000000..fbae25cb --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/batch_test.go @@ -0,0 +1,73 @@ +/* +Copyright 2018 Google LLC + +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 spanner + +import ( + "testing" + "time" + + sppb "google.golang.org/genproto/googleapis/spanner/v1" +) + +func TestPartitionRoundTrip(t *testing.T) { + t.Parallel() + for i, want := range []Partition{ + {rreq: &sppb.ReadRequest{Table: "t"}}, + {qreq: &sppb.ExecuteSqlRequest{Sql: "sql"}}, + } { + got := serdesPartition(t, i, &want) + if !testEqual(got, want) { + t.Errorf("got: %#v\nwant:%#v", got, want) + } + } +} + +func TestBROTIDRoundTrip(t *testing.T) { + t.Parallel() + tm := time.Now() + want := BatchReadOnlyTransactionID{ + tid: []byte("tid"), + sid: "sid", + rts: tm, + } + data, err := want.MarshalBinary() + if err != nil { + t.Fatal(err) + } + var got BatchReadOnlyTransactionID + if err := got.UnmarshalBinary(data); err != nil { + t.Fatal(err) + } + if !testEqual(got, want) { + t.Errorf("got: %#v\nwant:%#v", got, want) + } +} + +// serdesPartition is a helper that serialize a Partition then deserialize it +func serdesPartition(t *testing.T, i int, p1 *Partition) (p2 Partition) { + var ( + data []byte + err error + ) + if data, err = p1.MarshalBinary(); err != nil { + t.Fatalf("#%d: encoding failed %v", i, err) + } + if err = p2.UnmarshalBinary(data); err != nil { + t.Fatalf("#%d: decoding failed %v", i, err) + } + return p2 +} diff --git a/vendor/cloud.google.com/go/spanner/big_pdml_test.go b/vendor/cloud.google.com/go/spanner/big_pdml_test.go new file mode 100644 index 00000000..262ededd --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/big_pdml_test.go @@ -0,0 +1,60 @@ +// Copyright 2018 Google LLC +// +// 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. + +// +build bigtest + +// An integration test for PDML using a relatively large database. + +package spanner + +import ( + "context" + "fmt" + "testing" +) + +func TestBigPDML(t *testing.T) { + const nRows int = 1e4 + + ctx := context.Background() + client, _, cleanup := prepare(ctx, t, singerDBStatements) + defer cleanup() + + columns := []string{"SingerId", "FirstName", "LastName"} + + // Populate the Singers table with random data. + const rowsPerApply = 1000 + for i := 0; i < nRows; i += rowsPerApply { + var muts []*Mutation + for j := 0; j < rowsPerApply; j++ { + id := i + j + row := []interface{}{id, fmt.Sprintf("FirstName%d", id), fmt.Sprintf("LastName%d", id)} + muts = append(muts, Insert("Singers", columns, row)) + } + if _, err := client.Apply(ctx, muts); err != nil { + t.Fatal(err) + } + } + + // Run a PDML statement. + count, err := client.PartitionedUpdate(ctx, Statement{ + SQL: `UPDATE Singers SET Singers.FirstName = "changed" WHERE Singers.SingerId != -1`, + }) + if err != nil { + t.Fatal(err) + } + if want := int64(nRows); count != want { + t.Errorf("got %d, want %d", count, want) + } +} diff --git a/vendor/cloud.google.com/go/spanner/client.go b/vendor/cloud.google.com/go/spanner/client.go new file mode 100644 index 00000000..44ffbac0 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/client.go @@ -0,0 +1,443 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "context" + "fmt" + "regexp" + "sync/atomic" + "time" + + "cloud.google.com/go/internal/version" + "google.golang.org/api/option" + gtransport "google.golang.org/api/transport/grpc" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +const ( + endpoint = "spanner.googleapis.com:443" + + // resourcePrefixHeader is the name of the metadata header used to indicate + // the resource being operated on. + resourcePrefixHeader = "google-cloud-resource-prefix" + // xGoogHeaderKey is the name of the metadata header used to indicate client + // information. + xGoogHeaderKey = "x-goog-api-client" +) + +const ( + // Scope is the scope for Cloud Spanner Data API. + Scope = "https://www.googleapis.com/auth/spanner.data" + + // AdminScope is the scope for Cloud Spanner Admin APIs. + AdminScope = "https://www.googleapis.com/auth/spanner.admin" +) + +var ( + validDBPattern = regexp.MustCompile("^projects/[^/]+/instances/[^/]+/databases/[^/]+$") + xGoogHeaderVal = fmt.Sprintf("gl-go/%s gccl/%s grpc/%s", version.Go(), version.Repo, grpc.Version) +) + +func validDatabaseName(db string) error { + if matched := validDBPattern.MatchString(db); !matched { + return fmt.Errorf("database name %q should conform to pattern %q", + db, validDBPattern.String()) + } + return nil +} + +// Client is a client for reading and writing data to a Cloud Spanner database. A +// client is safe to use concurrently, except for its Close method. +type Client struct { + // rr must be accessed through atomic operations. + rr uint32 + // TODO(deklerk): we should not keep multiple ClientConns / SpannerClients. Instead, we should + // have a single ClientConn that has many connections: https://github.com/googleapis/google-api-go-client/blob/003c13302b3ea5ae44344459ba080364bd46155f/internal/pool.go + conns []*grpc.ClientConn + clients []sppb.SpannerClient + + database string + // Metadata to be sent with each request. + md metadata.MD + idleSessions *sessionPool + // sessionLabels for the sessions created by this client. + sessionLabels map[string]string +} + +// ClientConfig has configurations for the client. +type ClientConfig struct { + // NumChannels is the number of gRPC channels. + // If zero, a reasonable default is used based on the execution environment. + NumChannels int + co []option.ClientOption + // SessionPoolConfig is the configuration for session pool. + SessionPoolConfig + // SessionLabels for the sessions created by this client. + // See https://cloud.google.com/spanner/docs/reference/rpc/google.spanner.v1#session for more info. + SessionLabels map[string]string +} + +// errDial returns error for dialing to Cloud Spanner. +func errDial(ci int, err error) error { + e := toSpannerError(err).(*Error) + e.decorate(fmt.Sprintf("dialing fails for channel[%v]", ci)) + return e +} + +func contextWithOutgoingMetadata(ctx context.Context, md metadata.MD) context.Context { + existing, ok := metadata.FromOutgoingContext(ctx) + if ok { + md = metadata.Join(existing, md) + } + return metadata.NewOutgoingContext(ctx, md) +} + +// NewClient creates a client to a database. A valid database name has the +// form projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID. It uses a default +// configuration. +func NewClient(ctx context.Context, database string, opts ...option.ClientOption) (*Client, error) { + return NewClientWithConfig(ctx, database, ClientConfig{}, opts...) +} + +// NewClientWithConfig creates a client to a database. A valid database name has the +// form projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID. +func NewClientWithConfig(ctx context.Context, database string, config ClientConfig, opts ...option.ClientOption) (c *Client, err error) { + ctx = traceStartSpan(ctx, "cloud.google.com/go/spanner.NewClient") + defer func() { traceEndSpan(ctx, err) }() + + // Validate database path. + if err := validDatabaseName(database); err != nil { + return nil, err + } + c = &Client{ + database: database, + md: metadata.Pairs( + resourcePrefixHeader, database, + xGoogHeaderKey, xGoogHeaderVal), + } + // Make a copy of labels. + c.sessionLabels = make(map[string]string) + for k, v := range config.SessionLabels { + c.sessionLabels[k] = v + } + // gRPC options + allOpts := []option.ClientOption{ + option.WithEndpoint(endpoint), + option.WithScopes(Scope), + option.WithGRPCDialOption( + grpc.WithDefaultCallOptions( + grpc.MaxCallSendMsgSize(100<<20), + grpc.MaxCallRecvMsgSize(100<<20), + ), + ), + } + allOpts = append(allOpts, opts...) + // Prepare gRPC channels. + if config.NumChannels == 0 { + config.NumChannels = numChannels + } + // Default configs for session pool. + if config.MaxOpened == 0 { + config.MaxOpened = uint64(config.NumChannels * 100) + } + if config.MaxBurst == 0 { + config.MaxBurst = 10 + } + // TODO(deklerk) This should be replaced with a balancer with config.NumChannels + // connections, instead of config.NumChannels clientconns. + for i := 0; i < config.NumChannels; i++ { + conn, err := gtransport.Dial(ctx, allOpts...) + if err != nil { + return nil, errDial(i, err) + } + c.conns = append(c.conns, conn) + c.clients = append(c.clients, sppb.NewSpannerClient(conn)) + } + // Prepare session pool. + config.SessionPoolConfig.getRPCClient = func() (sppb.SpannerClient, error) { + // TODO: support more loadbalancing options. + return c.rrNext(), nil + } + config.SessionPoolConfig.sessionLabels = c.sessionLabels + sp, err := newSessionPool(database, config.SessionPoolConfig, c.md) + if err != nil { + c.Close() + return nil, err + } + c.idleSessions = sp + return c, nil +} + +// rrNext returns the next available Cloud Spanner RPC client in a round-robin manner. +func (c *Client) rrNext() sppb.SpannerClient { + return c.clients[atomic.AddUint32(&c.rr, 1)%uint32(len(c.clients))] +} + +// Close closes the client. +func (c *Client) Close() { + if c.idleSessions != nil { + c.idleSessions.close() + } + for _, conn := range c.conns { + conn.Close() + } +} + +// Single provides a read-only snapshot transaction optimized for the case +// where only a single read or query is needed. This is more efficient than +// using ReadOnlyTransaction() for a single read or query. +// +// Single will use a strong TimestampBound by default. Use +// ReadOnlyTransaction.WithTimestampBound to specify a different +// TimestampBound. A non-strong bound can be used to reduce latency, or +// "time-travel" to prior versions of the database, see the documentation of +// TimestampBound for details. +func (c *Client) Single() *ReadOnlyTransaction { + t := &ReadOnlyTransaction{singleUse: true, sp: c.idleSessions} + t.txReadOnly.txReadEnv = t + return t +} + +// ReadOnlyTransaction returns a ReadOnlyTransaction that can be used for +// multiple reads from the database. You must call Close() when the +// ReadOnlyTransaction is no longer needed to release resources on the server. +// +// ReadOnlyTransaction will use a strong TimestampBound by default. Use +// ReadOnlyTransaction.WithTimestampBound to specify a different +// TimestampBound. A non-strong bound can be used to reduce latency, or +// "time-travel" to prior versions of the database, see the documentation of +// TimestampBound for details. +func (c *Client) ReadOnlyTransaction() *ReadOnlyTransaction { + t := &ReadOnlyTransaction{ + singleUse: false, + sp: c.idleSessions, + txReadyOrClosed: make(chan struct{}), + } + t.txReadOnly.txReadEnv = t + return t +} + +// BatchReadOnlyTransaction returns a BatchReadOnlyTransaction that can be used +// for partitioned reads or queries from a snapshot of the database. This is +// useful in batch processing pipelines where one wants to divide the work of +// reading from the database across multiple machines. +// +// Note: This transaction does not use the underlying session pool but creates a +// new session each time, and the session is reused across clients. +// +// You should call Close() after the txn is no longer needed on local +// client, and call Cleanup() when the txn is finished for all clients, to free +// the session. +func (c *Client) BatchReadOnlyTransaction(ctx context.Context, tb TimestampBound) (*BatchReadOnlyTransaction, error) { + var ( + tx transactionID + rts time.Time + s *session + sh *sessionHandle + err error + ) + defer func() { + if err != nil && sh != nil { + s.delete(ctx) + } + }() + // create session + sc := c.rrNext() + s, err = createSession(ctx, sc, c.database, c.sessionLabels, c.md) + if err != nil { + return nil, err + } + sh = &sessionHandle{session: s} + // begin transaction + err = runRetryable(contextWithOutgoingMetadata(ctx, sh.getMetadata()), func(ctx context.Context) error { + res, e := sh.getClient().BeginTransaction(ctx, &sppb.BeginTransactionRequest{ + Session: sh.getID(), + Options: &sppb.TransactionOptions{ + Mode: &sppb.TransactionOptions_ReadOnly_{ + ReadOnly: buildTransactionOptionsReadOnly(tb, true), + }, + }, + }) + if e != nil { + return e + } + tx = res.Id + if res.ReadTimestamp != nil { + rts = time.Unix(res.ReadTimestamp.Seconds, int64(res.ReadTimestamp.Nanos)) + } + return nil + }) + if err != nil { + return nil, err + } + + t := &BatchReadOnlyTransaction{ + ReadOnlyTransaction: ReadOnlyTransaction{ + tx: tx, + txReadyOrClosed: make(chan struct{}), + state: txActive, + sh: sh, + rts: rts, + }, + ID: BatchReadOnlyTransactionID{ + tid: tx, + sid: sh.getID(), + rts: rts, + }, + } + t.txReadOnly.txReadEnv = t + return t, nil +} + +// BatchReadOnlyTransactionFromID reconstruct a BatchReadOnlyTransaction from BatchReadOnlyTransactionID +func (c *Client) BatchReadOnlyTransactionFromID(tid BatchReadOnlyTransactionID) *BatchReadOnlyTransaction { + sc := c.rrNext() + s := &session{valid: true, client: sc, id: tid.sid, createTime: time.Now(), md: c.md} + sh := &sessionHandle{session: s} + + t := &BatchReadOnlyTransaction{ + ReadOnlyTransaction: ReadOnlyTransaction{ + tx: tid.tid, + txReadyOrClosed: make(chan struct{}), + state: txActive, + sh: sh, + rts: tid.rts, + }, + ID: tid, + } + t.txReadOnly.txReadEnv = t + return t +} + +type transactionInProgressKey struct{} + +func checkNestedTxn(ctx context.Context) error { + if ctx.Value(transactionInProgressKey{}) != nil { + return spannerErrorf(codes.FailedPrecondition, "Cloud Spanner does not support nested transactions") + } + return nil +} + +// ReadWriteTransaction executes a read-write transaction, with retries as +// necessary. +// +// The function f will be called one or more times. It must not maintain +// any state between calls. +// +// If the transaction cannot be committed or if f returns an IsAborted error, +// ReadWriteTransaction will call f again. It will continue to call f until the +// transaction can be committed or the Context times out or is cancelled. If f +// returns an error other than IsAborted, ReadWriteTransaction will abort the +// transaction and return the error. +// +// To limit the number of retries, set a deadline on the Context rather than +// using a fixed limit on the number of attempts. ReadWriteTransaction will +// retry as needed until that deadline is met. +func (c *Client) ReadWriteTransaction(ctx context.Context, f func(context.Context, *ReadWriteTransaction) error) (commitTimestamp time.Time, err error) { + ctx = traceStartSpan(ctx, "cloud.google.com/go/spanner.ReadWriteTransaction") + defer func() { traceEndSpan(ctx, err) }() + if err := checkNestedTxn(ctx); err != nil { + return time.Time{}, err + } + var ( + ts time.Time + sh *sessionHandle + ) + err = runRetryableNoWrap(ctx, func(ctx context.Context) error { + var ( + err error + t *ReadWriteTransaction + ) + if sh == nil || sh.getID() == "" || sh.getClient() == nil { + // Session handle hasn't been allocated or has been destroyed. + sh, err = c.idleSessions.takeWriteSession(ctx) + if err != nil { + // If session retrieval fails, just fail the transaction. + return err + } + t = &ReadWriteTransaction{ + sh: sh, + tx: sh.getTransactionID(), + } + } else { + t = &ReadWriteTransaction{ + sh: sh, + } + } + t.txReadOnly.txReadEnv = t + tracePrintf(ctx, map[string]interface{}{"transactionID": string(sh.getTransactionID())}, + "Starting transaction attempt") + if err = t.begin(ctx); err != nil { + // Mask error from begin operation as retryable error. + return errRetry(err) + } + ts, err = t.runInTransaction(ctx, f) + return err + }) + if sh != nil { + sh.recycle() + } + return ts, err +} + +// applyOption controls the behavior of Client.Apply. +type applyOption struct { + // If atLeastOnce == true, Client.Apply will execute the mutations on Cloud Spanner at least once. + atLeastOnce bool +} + +// An ApplyOption is an optional argument to Apply. +type ApplyOption func(*applyOption) + +// ApplyAtLeastOnce returns an ApplyOption that removes replay protection. +// +// With this option, Apply may attempt to apply mutations more than once; if +// the mutations are not idempotent, this may lead to a failure being reported +// when the mutation was applied more than once. For example, an insert may +// fail with ALREADY_EXISTS even though the row did not exist before Apply was +// called. For this reason, most users of the library will prefer not to use +// this option. However, ApplyAtLeastOnce requires only a single RPC, whereas +// Apply's default replay protection may require an additional RPC. So this +// option may be appropriate for latency sensitive and/or high throughput blind +// writing. +func ApplyAtLeastOnce() ApplyOption { + return func(ao *applyOption) { + ao.atLeastOnce = true + } +} + +// Apply applies a list of mutations atomically to the database. +func (c *Client) Apply(ctx context.Context, ms []*Mutation, opts ...ApplyOption) (commitTimestamp time.Time, err error) { + ao := &applyOption{} + for _, opt := range opts { + opt(ao) + } + if !ao.atLeastOnce { + return c.ReadWriteTransaction(ctx, func(ctx context.Context, t *ReadWriteTransaction) error { + return t.BufferWrite(ms) + }) + } + + ctx = traceStartSpan(ctx, "cloud.google.com/go/spanner.Apply") + defer func() { traceEndSpan(ctx, err) }() + t := &writeOnlyTransaction{c.idleSessions} + return t.applyAtLeastOnce(ctx, ms...) +} diff --git a/vendor/cloud.google.com/go/spanner/client_test.go b/vendor/cloud.google.com/go/spanner/client_test.go new file mode 100644 index 00000000..54c52631 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/client_test.go @@ -0,0 +1,50 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "strings" + "testing" +) + +// Test validDatabaseName() +func TestValidDatabaseName(t *testing.T) { + validDbURI := "projects/spanner-cloud-test/instances/foo/databases/foodb" + invalidDbUris := []string{ + // Completely wrong DB URI. + "foobarDB", + // Project ID contains "/". + "projects/spanner-cloud/test/instances/foo/databases/foodb", + // No instance ID. + "projects/spanner-cloud-test/instances//databases/foodb", + } + if err := validDatabaseName(validDbURI); err != nil { + t.Errorf("validateDatabaseName(%q) = %v, want nil", validDbURI, err) + } + for _, d := range invalidDbUris { + if err, wantErr := validDatabaseName(d), "should conform to pattern"; !strings.Contains(err.Error(), wantErr) { + t.Errorf("validateDatabaseName(%q) = %q, want error pattern %q", validDbURI, err, wantErr) + } + } +} + +func TestReadOnlyTransactionClose(t *testing.T) { + // Closing a ReadOnlyTransaction shouldn't panic. + c := &Client{} + tx := c.ReadOnlyTransaction() + tx.Close() +} diff --git a/vendor/cloud.google.com/go/spanner/doc.go b/vendor/cloud.google.com/go/spanner/doc.go new file mode 100644 index 00000000..4954082e --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/doc.go @@ -0,0 +1,328 @@ +/* +Copyright 2017 Google LLC + +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 spanner provides a client for reading and writing to Cloud Spanner +databases. See the packages under admin for clients that operate on databases +and instances. + +Note: This package is in beta. Some backwards-incompatible changes may occur. + +See https://cloud.google.com/spanner/docs/getting-started/go/ for an introduction +to Cloud Spanner and additional help on using this API. + +See https://godoc.org/cloud.google.com/go for authentication, timeouts, +connection pooling and similar aspects of this package. + + +Creating a Client + +To start working with this package, create a client that refers to the database +of interest: + + ctx := context.Background() + client, err := spanner.NewClient(ctx, "projects/P/instances/I/databases/D") + if err != nil { + // TODO: Handle error. + } + defer client.Close() + +Remember to close the client after use to free up the sessions in the session +pool. + + +Simple Reads and Writes + +Two Client methods, Apply and Single, work well for simple reads and writes. As +a quick introduction, here we write a new row to the database and read it back: + + _, err := client.Apply(ctx, []*spanner.Mutation{ + spanner.Insert("Users", + []string{"name", "email"}, + []interface{}{"alice", "a@example.com"})}) + if err != nil { + // TODO: Handle error. + } + row, err := client.Single().ReadRow(ctx, "Users", + spanner.Key{"alice"}, []string{"email"}) + if err != nil { + // TODO: Handle error. + } + +All the methods used above are discussed in more detail below. + + +Keys + +Every Cloud Spanner row has a unique key, composed of one or more columns. +Construct keys with a literal of type Key: + + key1 := spanner.Key{"alice"} + + +KeyRanges + +The keys of a Cloud Spanner table are ordered. You can specify ranges of keys +using the KeyRange type: + + kr1 := spanner.KeyRange{Start: key1, End: key2} + +By default, a KeyRange includes its start key but not its end key. Use +the Kind field to specify other boundary conditions: + + // include both keys + kr2 := spanner.KeyRange{Start: key1, End: key2, Kind: spanner.ClosedClosed} + + +KeySets + +A KeySet represents a set of keys. A single Key or KeyRange can act as a KeySet. Use +the KeySets function to build the union of several KeySets: + + ks1 := spanner.KeySets(key1, key2, kr1, kr2) + +AllKeys returns a KeySet that refers to all the keys in a table: + + ks2 := spanner.AllKeys() + + +Transactions + +All Cloud Spanner reads and writes occur inside transactions. There are two +types of transactions, read-only and read-write. Read-only transactions cannot +change the database, do not acquire locks, and may access either the current +database state or states in the past. Read-write transactions can read the +database before writing to it, and always apply to the most recent database +state. + + +Single Reads + +The simplest and fastest transaction is a ReadOnlyTransaction that supports a +single read operation. Use Client.Single to create such a transaction. You can +chain the call to Single with a call to a Read method. + +When you only want one row whose key you know, use ReadRow. Provide the table +name, key, and the columns you want to read: + + row, err := client.Single().ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"balance"}) + +Read multiple rows with the Read method. It takes a table name, KeySet, and list +of columns: + + iter := client.Single().Read(ctx, "Accounts", keyset1, columns) + +Read returns a RowIterator. You can call the Do method on the iterator and pass +a callback: + + err := iter.Do(func(row *Row) error { + // TODO: use row + return nil + }) + +RowIterator also follows the standard pattern for the Google +Cloud Client Libraries: + + defer iter.Stop() + for { + row, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: use row + } + +Always call Stop when you finish using an iterator this way, whether or not you +iterate to the end. (Failing to call Stop could lead you to exhaust the +database's session quota.) + +To read rows with an index, use ReadUsingIndex. + +Statements + +The most general form of reading uses SQL statements. Construct a Statement +with NewStatement, setting any parameters using the Statement's Params map: + + stmt := spanner.NewStatement("SELECT First, Last FROM SINGERS WHERE Last >= @start") + stmt.Params["start"] = "Dylan" + +You can also construct a Statement directly with a struct literal, providing +your own map of parameters. + +Use the Query method to run the statement and obtain an iterator: + + iter := client.Single().Query(ctx, stmt) + + +Rows + +Once you have a Row, via an iterator or a call to ReadRow, you can extract +column values in several ways. Pass in a pointer to a Go variable of the +appropriate type when you extract a value. + +You can extract by column position or name: + + err := row.Column(0, &name) + err = row.ColumnByName("balance", &balance) + +You can extract all the columns at once: + + err = row.Columns(&name, &balance) + +Or you can define a Go struct that corresponds to your columns, and extract +into that: + + var s struct { Name string; Balance int64 } + err = row.ToStruct(&s) + + +For Cloud Spanner columns that may contain NULL, use one of the NullXXX types, +like NullString: + + var ns spanner.NullString + if err := row.Column(0, &ns); err != nil { + // TODO: Handle error. + } + if ns.Valid { + fmt.Println(ns.StringVal) + } else { + fmt.Println("column is NULL") + } + + +Multiple Reads + +To perform more than one read in a transaction, use ReadOnlyTransaction: + + txn := client.ReadOnlyTransaction() + defer txn.Close() + iter := txn.Query(ctx, stmt1) + // ... + iter = txn.Query(ctx, stmt2) + // ... + +You must call Close when you are done with the transaction. + + +Timestamps and Timestamp Bounds + +Cloud Spanner read-only transactions conceptually perform all their reads at a +single moment in time, called the transaction's read timestamp. Once a read has +started, you can call ReadOnlyTransaction's Timestamp method to obtain the read +timestamp. + +By default, a transaction will pick the most recent time (a time where all +previously committed transactions are visible) for its reads. This provides the +freshest data, but may involve some delay. You can often get a quicker response +if you are willing to tolerate "stale" data. You can control the read timestamp +selected by a transaction by calling the WithTimestampBound method on the +transaction before using it. For example, to perform a query on data that is at +most one minute stale, use + + client.Single(). + WithTimestampBound(spanner.MaxStaleness(1*time.Minute)). + Query(ctx, stmt) + +See the documentation of TimestampBound for more details. + + +Mutations + +To write values to a Cloud Spanner database, construct a Mutation. The spanner +package has functions for inserting, updating and deleting rows. Except for the +Delete methods, which take a Key or KeyRange, each mutation-building function +comes in three varieties. + +One takes lists of columns and values along with the table name: + + m1 := spanner.Insert("Users", + []string{"name", "email"}, + []interface{}{"alice", "a@example.com"}) + +One takes a map from column names to values: + + m2 := spanner.InsertMap("Users", map[string]interface{}{ + "name": "alice", + "email": "a@example.com", + }) + +And the third accepts a struct value, and determines the columns from the +struct field names: + + type User struct { Name, Email string } + u := User{Name: "alice", Email: "a@example.com"} + m3, err := spanner.InsertStruct("Users", u) + + +Writes + +To apply a list of mutations to the database, use Apply: + + _, err := client.Apply(ctx, []*spanner.Mutation{m1, m2, m3}) + +If you need to read before writing in a single transaction, use a +ReadWriteTransaction. ReadWriteTransactions may abort and need to be retried. +You pass in a function to ReadWriteTransaction, and the client will handle the +retries automatically. Use the transaction's BufferWrite method to buffer +mutations, which will all be executed at the end of the transaction: + + _, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error { + var balance int64 + row, err := txn.ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"balance"}) + if err != nil { + // This function will be called again if this is an IsAborted error. + return err + } + if err := row.Column(0, &balance); err != nil { + return err + } + + if balance <= 10 { + return errors.New("insufficient funds in account") + } + balance -= 10 + m := spanner.Update("Accounts", []string{"user", "balance"}, []interface{}{"alice", balance}) + txn.BufferWrite([]*spanner.Mutation{m}) + + // The buffered mutation will be committed. If the commit + // fails with an IsAborted error, this function will be called + // again. + return nil + }) + + +DML and Partitioned DML + +Spanner supports DML statements like INSERT, UPDATE and DELETE. Use +ReadWriteTransaction.Update to run DML statements. It returns the number of rows +affected. (You can call use ReadWriteTransaction.Query with a DML statement. The first +call to Next on the resulting RowIterator will return iterator.Done, and the RowCount +field of the iterator will hold the number of affected rows.) + +For large databases, it may be more efficient to partition the DML statement. Use +client.PartitionedUpdate to run a DML statement in this way. Not all DML statements +can be partitioned. + +Tracing + +This client has been instrumented to use OpenCensus tracing (http://opencensus.io). +To enable tracing, see "Enabling Tracing for a Program" at +https://godoc.org/go.opencensus.io/trace. OpenCensus tracing requires Go 1.8 or higher. +*/ +package spanner // import "cloud.google.com/go/spanner" diff --git a/vendor/cloud.google.com/go/spanner/errors.go b/vendor/cloud.google.com/go/spanner/errors.go new file mode 100644 index 00000000..fb58ae08 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/errors.go @@ -0,0 +1,115 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "context" + "fmt" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// Error is the structured error returned by Cloud Spanner client. +type Error struct { + // Code is the canonical error code for describing the nature of a + // particular error. + Code codes.Code + // Desc explains more details of the error. + Desc string + // trailers are the trailers returned in the response, if any. + trailers metadata.MD +} + +// Error implements error.Error. +func (e *Error) Error() string { + if e == nil { + return fmt.Sprintf("spanner: OK") + } + return fmt.Sprintf("spanner: code = %q, desc = %q", e.Code, e.Desc) +} + +// decorate decorates an existing spanner.Error with more information. +func (e *Error) decorate(info string) { + e.Desc = fmt.Sprintf("%v, %v", info, e.Desc) +} + +// spannerErrorf generates a *spanner.Error with the given error code and +// description. +func spannerErrorf(ec codes.Code, format string, args ...interface{}) error { + return &Error{ + Code: ec, + Desc: fmt.Sprintf(format, args...), + } +} + +// toSpannerError converts general Go error to *spanner.Error. +func toSpannerError(err error) error { + return toSpannerErrorWithMetadata(err, nil) +} + +// toSpannerErrorWithMetadata converts general Go error and grpc trailers to *spanner.Error. +// Note: modifies original error if trailers aren't nil +func toSpannerErrorWithMetadata(err error, trailers metadata.MD) error { + if err == nil { + return nil + } + if se, ok := err.(*Error); ok { + if trailers != nil { + se.trailers = metadata.Join(se.trailers, trailers) + } + return se + } + switch { + case err == context.DeadlineExceeded: + return &Error{codes.DeadlineExceeded, err.Error(), trailers} + case err == context.Canceled: + return &Error{codes.Canceled, err.Error(), trailers} + case grpc.Code(err) == codes.Unknown: + return &Error{codes.Unknown, err.Error(), trailers} + default: + return &Error{grpc.Code(err), grpc.ErrorDesc(err), trailers} + } +} + +// ErrCode extracts the canonical error code from a Go error. +func ErrCode(err error) codes.Code { + se, ok := toSpannerError(err).(*Error) + if !ok { + return codes.Unknown + } + return se.Code +} + +// ErrDesc extracts the Cloud Spanner error description from a Go error. +func ErrDesc(err error) string { + se, ok := toSpannerError(err).(*Error) + if !ok { + return err.Error() + } + return se.Desc +} + +// errTrailers extracts the grpc trailers if present from a Go error. +func errTrailers(err error) metadata.MD { + se, ok := err.(*Error) + if !ok { + return nil + } + return se.trailers +} diff --git a/vendor/cloud.google.com/go/spanner/errors_test.go b/vendor/cloud.google.com/go/spanner/errors_test.go new file mode 100644 index 00000000..9dd7f7f0 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/errors_test.go @@ -0,0 +1,44 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "context" + "errors" + "testing" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestToSpannerError(t *testing.T) { + for _, test := range []struct { + err error + wantCode codes.Code + }{ + {errors.New("wha?"), codes.Unknown}, + {context.Canceled, codes.Canceled}, + {context.DeadlineExceeded, codes.DeadlineExceeded}, + {status.Errorf(codes.ResourceExhausted, "so tired"), codes.ResourceExhausted}, + {spannerErrorf(codes.InvalidArgument, "bad"), codes.InvalidArgument}, + } { + err := toSpannerError(test.err) + if got, want := err.(*Error).Code, test.wantCode; got != want { + t.Errorf("%v: got %s, want %s", test.err, got, want) + } + } +} diff --git a/vendor/cloud.google.com/go/spanner/examples_test.go b/vendor/cloud.google.com/go/spanner/examples_test.go new file mode 100644 index 00000000..e8bb1bb7 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/examples_test.go @@ -0,0 +1,668 @@ +/* +Copyright 2017 Google LLC + +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 spanner_test + +import ( + "context" + "errors" + "fmt" + "sync" + "time" + + "cloud.google.com/go/spanner" + "google.golang.org/api/iterator" + sppb "google.golang.org/genproto/googleapis/spanner/v1" +) + +func ExampleNewClient() { + ctx := context.Background() + const myDB = "projects/my-project/instances/my-instance/database/my-db" + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + _ = client // TODO: Use client. +} + +const myDB = "projects/my-project/instances/my-instance/database/my-db" + +func ExampleNewClientWithConfig() { + ctx := context.Background() + const myDB = "projects/my-project/instances/my-instance/database/my-db" + client, err := spanner.NewClientWithConfig(ctx, myDB, spanner.ClientConfig{ + NumChannels: 10, + }) + if err != nil { + // TODO: Handle error. + } + _ = client // TODO: Use client. + client.Close() // Close client when done. +} + +func ExampleClient_Single() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + iter := client.Single().Query(ctx, spanner.NewStatement("SELECT FirstName FROM Singers")) + _ = iter // TODO: iterate using Next or Do. +} + +func ExampleClient_ReadOnlyTransaction() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + t := client.ReadOnlyTransaction() + defer t.Close() + // TODO: Read with t using Read, ReadRow, ReadUsingIndex, or Query. +} + +func ExampleClient_ReadWriteTransaction() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + _, err = client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error { + var balance int64 + row, err := txn.ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"balance"}) + if err != nil { + // This function will be called again if this is an + // IsAborted error. + return err + } + if err := row.Column(0, &balance); err != nil { + return err + } + + if balance <= 10 { + return errors.New("insufficient funds in account") + } + balance -= 10 + m := spanner.Update("Accounts", []string{"user", "balance"}, []interface{}{"alice", balance}) + return txn.BufferWrite([]*spanner.Mutation{m}) + // The buffered mutation will be committed. If the commit + // fails with an IsAborted error, this function will be called + // again. + }) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleUpdate() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + _, err = client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error { + row, err := txn.ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"balance"}) + if err != nil { + return err + } + var balance int64 + if err := row.Column(0, &balance); err != nil { + return err + } + return txn.BufferWrite([]*spanner.Mutation{ + spanner.Update("Accounts", []string{"user", "balance"}, []interface{}{"alice", balance + 10}), + }) + }) + if err != nil { + // TODO: Handle error. + } +} + +// This example is the same as the one for Update, except for the use of UpdateMap. +func ExampleUpdateMap() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + _, err = client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error { + row, err := txn.ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"balance"}) + if err != nil { + return err + } + var balance int64 + if err := row.Column(0, &balance); err != nil { + return err + } + return txn.BufferWrite([]*spanner.Mutation{ + spanner.UpdateMap("Accounts", map[string]interface{}{ + "user": "alice", + "balance": balance + 10, + }), + }) + }) + if err != nil { + // TODO: Handle error. + } +} + +// This example is the same as the one for Update, except for the use of UpdateStruct. +func ExampleUpdateStruct() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + type account struct { + User string `spanner:"user"` + Balance int64 `spanner:"balance"` + } + _, err = client.ReadWriteTransaction(ctx, func(ctx context.Context, txn *spanner.ReadWriteTransaction) error { + row, err := txn.ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"balance"}) + if err != nil { + return err + } + var balance int64 + if err := row.Column(0, &balance); err != nil { + return err + } + m, err := spanner.UpdateStruct("Accounts", account{ + User: "alice", + Balance: balance + 10, + }) + if err != nil { + return err + } + return txn.BufferWrite([]*spanner.Mutation{m}) + }) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_Apply() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + m := spanner.Update("Users", []string{"name", "email"}, []interface{}{"alice", "a@example.com"}) + _, err = client.Apply(ctx, []*spanner.Mutation{m}) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleInsert() { + m := spanner.Insert("Users", []string{"name", "email"}, []interface{}{"alice", "a@example.com"}) + _ = m // TODO: use with Client.Apply or in a ReadWriteTransaction. +} + +func ExampleInsertMap() { + m := spanner.InsertMap("Users", map[string]interface{}{ + "name": "alice", + "email": "a@example.com", + }) + _ = m // TODO: use with Client.Apply or in a ReadWriteTransaction. +} + +func ExampleInsertStruct() { + type User struct { + Name, Email string + } + u := User{Name: "alice", Email: "a@example.com"} + m, err := spanner.InsertStruct("Users", u) + if err != nil { + // TODO: Handle error. + } + _ = m // TODO: use with Client.Apply or in a ReadWriteTransaction. +} + +func ExampleDelete() { + m := spanner.Delete("Users", spanner.Key{"alice"}) + _ = m // TODO: use with Client.Apply or in a ReadWriteTransaction. +} + +func ExampleDelete_keyRange() { + m := spanner.Delete("Users", spanner.KeyRange{ + Start: spanner.Key{"alice"}, + End: spanner.Key{"bob"}, + Kind: spanner.ClosedClosed, + }) + _ = m // TODO: use with Client.Apply or in a ReadWriteTransaction. +} + +func ExampleRowIterator_Next() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + iter := client.Single().Query(ctx, spanner.NewStatement("SELECT FirstName FROM Singers")) + defer iter.Stop() + for { + row, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + var firstName string + if err := row.Column(0, &firstName); err != nil { + // TODO: Handle error. + } + fmt.Println(firstName) + } +} + +func ExampleRowIterator_Do() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + iter := client.Single().Query(ctx, spanner.NewStatement("SELECT FirstName FROM Singers")) + err = iter.Do(func(r *spanner.Row) error { + var firstName string + if err := r.Column(0, &firstName); err != nil { + return err + } + fmt.Println(firstName) + return nil + }) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleRow_Size() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + row, err := client.Single().ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"name", "balance"}) + if err != nil { + // TODO: Handle error. + } + fmt.Println(row.Size()) // size is 2 +} + +func ExampleRow_ColumnName() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + row, err := client.Single().ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"name", "balance"}) + if err != nil { + // TODO: Handle error. + } + fmt.Println(row.ColumnName(1)) // prints "balance" +} + +func ExampleRow_ColumnIndex() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + row, err := client.Single().ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"name", "balance"}) + if err != nil { + // TODO: Handle error. + } + index, err := row.ColumnIndex("balance") + if err != nil { + // TODO: Handle error. + } + fmt.Println(index) +} + +func ExampleRow_ColumnNames() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + row, err := client.Single().ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"name", "balance"}) + if err != nil { + // TODO: Handle error. + } + fmt.Println(row.ColumnNames()) +} + +func ExampleRow_ColumnByName() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + row, err := client.Single().ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"name", "balance"}) + if err != nil { + // TODO: Handle error. + } + var balance int64 + if err := row.ColumnByName("balance", &balance); err != nil { + // TODO: Handle error. + } + fmt.Println(balance) +} + +func ExampleRow_Columns() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + row, err := client.Single().ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"name", "balance"}) + if err != nil { + // TODO: Handle error. + } + var name string + var balance int64 + if err := row.Columns(&name, &balance); err != nil { + // TODO: Handle error. + } + fmt.Println(name, balance) +} + +func ExampleRow_ToStruct() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + row, err := client.Single().ReadRow(ctx, "Accounts", spanner.Key{"alice"}, []string{"name", "balance"}) + if err != nil { + // TODO: Handle error. + } + + type Account struct { + Name string + Balance int64 + } + + var acct Account + if err := row.ToStruct(&acct); err != nil { + // TODO: Handle error. + } + fmt.Println(acct) +} + +func ExampleReadOnlyTransaction_Read() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + iter := client.Single().Read(ctx, "Users", + spanner.KeySets(spanner.Key{"alice"}, spanner.Key{"bob"}), + []string{"name", "email"}) + _ = iter // TODO: iterate using Next or Do. +} + +func ExampleReadOnlyTransaction_ReadUsingIndex() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + iter := client.Single().ReadUsingIndex(ctx, "Users", + "UsersByEmail", + spanner.KeySets(spanner.Key{"a@example.com"}, spanner.Key{"b@example.com"}), + []string{"name", "email"}) + _ = iter // TODO: iterate using Next or Do. +} + +func ExampleReadOnlyTransaction_ReadWithOptions() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + // Use an index, and limit to 100 rows at most. + iter := client.Single().ReadWithOptions(ctx, "Users", + spanner.KeySets(spanner.Key{"a@example.com"}, spanner.Key{"b@example.com"}), + []string{"name", "email"}, &spanner.ReadOptions{ + Index: "UsersByEmail", + Limit: 100, + }) + _ = iter // TODO: iterate using Next or Do. +} + +func ExampleReadOnlyTransaction_ReadRow() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + row, err := client.Single().ReadRow(ctx, "Users", spanner.Key{"alice"}, + []string{"name", "email"}) + if err != nil { + // TODO: Handle error. + } + _ = row // TODO: use row +} + +func ExampleReadOnlyTransaction_Query() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + iter := client.Single().Query(ctx, spanner.NewStatement("SELECT FirstName FROM Singers")) + _ = iter // TODO: iterate using Next or Do. +} + +func ExampleNewStatement() { + stmt := spanner.NewStatement("SELECT FirstName, LastName FROM SINGERS WHERE LastName >= @start") + stmt.Params["start"] = "Dylan" + // TODO: Use stmt in Query. +} + +func ExampleNewStatement_structLiteral() { + stmt := spanner.Statement{ + SQL: `SELECT FirstName, LastName FROM SINGERS WHERE LastName = ("Lea", "Martin")`, + } + _ = stmt // TODO: Use stmt in Query. +} + +func ExampleStructParam() { + stmt := spanner.Statement{ + SQL: "SELECT * FROM SINGERS WHERE (FirstName, LastName) = @singerinfo", + Params: map[string]interface{}{ + "singerinfo": struct { + FirstName string + LastName string + }{"Bob", "Dylan"}, + }, + } + _ = stmt // TODO: Use stmt in Query. +} + +func ExampleArrayOfStructParam() { + stmt := spanner.Statement{ + SQL: "SELECT * FROM SINGERS WHERE (FirstName, LastName) IN UNNEST(@singerinfo)", + Params: map[string]interface{}{ + "singerinfo": []struct { + FirstName string + LastName string + }{ + {"Ringo", "Starr"}, + {"John", "Lennon"}, + }, + }, + } + _ = stmt // TODO: Use stmt in Query. +} + +func ExampleReadOnlyTransaction_Timestamp() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + txn := client.Single() + row, err := txn.ReadRow(ctx, "Users", spanner.Key{"alice"}, + []string{"name", "email"}) + if err != nil { + // TODO: Handle error. + } + readTimestamp, err := txn.Timestamp() + if err != nil { + // TODO: Handle error. + } + fmt.Println("read happened at", readTimestamp) + _ = row // TODO: use row +} + +func ExampleReadOnlyTransaction_WithTimestampBound() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + txn := client.Single().WithTimestampBound(spanner.MaxStaleness(30 * time.Second)) + row, err := txn.ReadRow(ctx, "Users", spanner.Key{"alice"}, []string{"name", "email"}) + if err != nil { + // TODO: Handle error. + } + _ = row // TODO: use row + readTimestamp, err := txn.Timestamp() + if err != nil { + // TODO: Handle error. + } + fmt.Println("read happened at", readTimestamp) +} + +func ExampleGenericColumnValue_Decode() { + // In real applications, rows can be retrieved by methods like client.Single().ReadRow(). + row, err := spanner.NewRow([]string{"intCol", "strCol"}, []interface{}{42, "my-text"}) + if err != nil { + // TODO: Handle error. + } + for i := 0; i < row.Size(); i++ { + var col spanner.GenericColumnValue + if err := row.Column(i, &col); err != nil { + // TODO: Handle error. + } + switch col.Type.Code { + case sppb.TypeCode_INT64: + var v int64 + if err := col.Decode(&v); err != nil { + // TODO: Handle error. + } + fmt.Println("int", v) + case sppb.TypeCode_STRING: + var v string + if err := col.Decode(&v); err != nil { + // TODO: Handle error. + } + fmt.Println("string", v) + } + } + // Output: + // int 42 + // string my-text +} + +func ExampleClient_BatchReadOnlyTransaction() { + ctx := context.Background() + var ( + client *spanner.Client + txn *spanner.BatchReadOnlyTransaction + err error + ) + if client, err = spanner.NewClient(ctx, myDB); err != nil { + // TODO: Handle error. + } + defer client.Close() + if txn, err = client.BatchReadOnlyTransaction(ctx, spanner.StrongRead()); err != nil { + // TODO: Handle error. + } + defer txn.Close() + + // Singer represents the elements in a row from the Singers table. + type Singer struct { + SingerID int64 + FirstName string + LastName string + SingerInfo []byte + } + stmt := spanner.Statement{SQL: "SELECT * FROM Singers;"} + partitions, err := txn.PartitionQuery(ctx, stmt, spanner.PartitionOptions{}) + if err != nil { + // TODO: Handle error. + } + // Note: here we use multiple goroutines, but you should use separate processes/machines. + wg := sync.WaitGroup{} + for i, p := range partitions { + wg.Add(1) + go func(i int, p *spanner.Partition) { + defer wg.Done() + iter := txn.Execute(ctx, p) + defer iter.Stop() + for { + row, err := iter.Next() + if err == iterator.Done { + break + } else if err != nil { + // TODO: Handle error. + } + var s Singer + if err := row.ToStruct(&s); err != nil { + // TODO: Handle error. + } + _ = s // TODO: Process the row. + } + }(i, p) + } + wg.Wait() +} + +func ExampleCommitTimestamp() { + ctx := context.Background() + client, err := spanner.NewClient(ctx, myDB) + if err != nil { + // TODO: Handle error. + } + + type account struct { + User string + Creation spanner.NullTime // time.Time can also be used if column is NOT NULL + } + + a := account{User: "Joe", Creation: spanner.NullTime{spanner.CommitTimestamp, true}} + m, err := spanner.InsertStruct("Accounts", a) + if err != nil { + // TODO: Handle error. + } + _, err = client.Apply(ctx, []*spanner.Mutation{m}, spanner.ApplyAtLeastOnce()) + if err != nil { + // TODO: Handle error. + } + + if r, e := client.Single().ReadRow(ctx, "Accounts", spanner.Key{"Joe"}, []string{"User", "Creation"}); e != nil { + // TODO: Handle error. + } else { + var got account + if err := r.ToStruct(&got); err != nil { + // TODO: Handle error. + } + _ = got // TODO: Process row. + } +} diff --git a/vendor/cloud.google.com/go/spanner/integration_test.go b/vendor/cloud.google.com/go/spanner/integration_test.go new file mode 100644 index 00000000..694f9e0d --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/integration_test.go @@ -0,0 +1,2142 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "context" + "errors" + "flag" + "fmt" + "log" + "math" + "os" + "reflect" + "strings" + "sync" + "testing" + "time" + + "cloud.google.com/go/civil" + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/internal/uid" + database "cloud.google.com/go/spanner/admin/database/apiv1" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + adminpb "google.golang.org/genproto/googleapis/spanner/admin/database/v1" + "google.golang.org/grpc/codes" +) + +var ( + // testProjectID specifies the project used for testing. + // It can be changed by setting environment variable GCLOUD_TESTS_GOLANG_PROJECT_ID. + testProjectID = testutil.ProjID() + + dbNameSpace = uid.NewSpace("gotest", &uid.Options{Sep: '_', Short: true}) + + // TODO(deklerk) When we can programmatically create instances, we should use + // uid.New as the test instance name. + // testInstanceID specifies the Cloud Spanner instance used for testing. + testInstanceID = "go-integration-test" + + testTable = "TestTable" + testTableIndex = "TestTableByValue" + testTableColumns = []string{"Key", "StringValue"} + + // admin is a spanner.DatabaseAdminClient. + admin *database.DatabaseAdminClient + + singerDBStatements = []string{ + `CREATE TABLE Singers ( + SingerId INT64 NOT NULL, + FirstName STRING(1024), + LastName STRING(1024), + SingerInfo BYTES(MAX) + ) PRIMARY KEY (SingerId)`, + `CREATE INDEX SingerByName ON Singers(FirstName, LastName)`, + `CREATE TABLE Accounts ( + AccountId INT64 NOT NULL, + Nickname STRING(100), + Balance INT64 NOT NULL, + ) PRIMARY KEY (AccountId)`, + `CREATE INDEX AccountByNickname ON Accounts(Nickname) STORING (Balance)`, + `CREATE TABLE Types ( + RowID INT64 NOT NULL, + String STRING(MAX), + StringArray ARRAY, + Bytes BYTES(MAX), + BytesArray ARRAY, + Int64a INT64, + Int64Array ARRAY, + Bool BOOL, + BoolArray ARRAY, + Float64 FLOAT64, + Float64Array ARRAY, + Date DATE, + DateArray ARRAY, + Timestamp TIMESTAMP, + TimestampArray ARRAY, + ) PRIMARY KEY (RowID)`, + } + + readDBStatements = []string{ + `CREATE TABLE TestTable ( + Key STRING(MAX) NOT NULL, + StringValue STRING(MAX) + ) PRIMARY KEY (Key)`, + `CREATE INDEX TestTableByValue ON TestTable(StringValue)`, + `CREATE INDEX TestTableByValueDesc ON TestTable(StringValue DESC)`, + } + + simpleDBStatements = []string{ + `CREATE TABLE test ( + a STRING(1024), + b STRING(1024), + ) PRIMARY KEY (a)`, + } + simpleDBTableColumns = []string{"a", "b"} + + ctsDBStatements = []string{ + `CREATE TABLE TestTable ( + Key STRING(MAX) NOT NULL, + Ts TIMESTAMP OPTIONS (allow_commit_timestamp = true), + ) PRIMARY KEY (Key)`, + } +) + +const ( + str1 = "alice" + str2 = "a@example.com" +) + +func TestMain(m *testing.M) { + flag.Parse() // needed for testing.Short() + if testing.Short() { + log.Println("Integration tests skipped in -short mode.") + return + } + if testProjectID == "" { + log.Println("Integration tests skipped: GCLOUD_TESTS_GOLANG_PROJECT_ID is missing") + return + } + ctx := context.Background() + + ts := testutil.TokenSource(ctx, AdminScope, Scope) + if ts == nil { + log.Printf("Integration test skipped: cannot get service account credential from environment variable %v", "GCLOUD_TESTS_GOLANG_KEY") + return + } + var err error + + // Create Admin client and Data client. + admin, err = database.NewDatabaseAdminClient(ctx, option.WithTokenSource(ts), option.WithEndpoint(endpoint)) + if err != nil { + log.Fatalf("cannot create admin client: %v", err) + } + + res := m.Run() + cleanupDatabases() + os.Exit(res) +} + +// Test SingleUse transaction. +func TestSingleUse(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + // Set up testing environment. + client, _, cleanup := prepare(ctx, t, singerDBStatements) + defer cleanup() + + writes := []struct { + row []interface{} + ts time.Time + }{ + {row: []interface{}{1, "Marc", "Foo"}}, + {row: []interface{}{2, "Tars", "Bar"}}, + {row: []interface{}{3, "Alpha", "Beta"}}, + {row: []interface{}{4, "Last", "End"}}, + } + // Try to write four rows through the Apply API. + for i, w := range writes { + var err error + m := InsertOrUpdate("Singers", + []string{"SingerId", "FirstName", "LastName"}, + w.row) + if writes[i].ts, err = client.Apply(ctx, []*Mutation{m}, ApplyAtLeastOnce()); err != nil { + t.Fatal(err) + } + } + + // For testing timestamp bound staleness. + <-time.After(time.Second) + + // Test reading rows with different timestamp bounds. + for i, test := range []struct { + want [][]interface{} + tb TimestampBound + checkTs func(time.Time) error + }{ + { + // strong + [][]interface{}{{int64(1), "Marc", "Foo"}, {int64(3), "Alpha", "Beta"}, {int64(4), "Last", "End"}}, + StrongRead(), + func(ts time.Time) error { + // writes[3] is the last write, all subsequent strong read should have a timestamp larger than that. + if ts.Before(writes[3].ts) { + return fmt.Errorf("read got timestamp %v, want it to be no later than %v", ts, writes[3].ts) + } + return nil + }, + }, + { + // min_read_timestamp + [][]interface{}{{int64(1), "Marc", "Foo"}, {int64(3), "Alpha", "Beta"}, {int64(4), "Last", "End"}}, + MinReadTimestamp(writes[3].ts), + func(ts time.Time) error { + if ts.Before(writes[3].ts) { + return fmt.Errorf("read got timestamp %v, want it to be no later than %v", ts, writes[3].ts) + } + return nil + }, + }, + { + // max_staleness + [][]interface{}{{int64(1), "Marc", "Foo"}, {int64(3), "Alpha", "Beta"}, {int64(4), "Last", "End"}}, + MaxStaleness(time.Second), + func(ts time.Time) error { + if ts.Before(writes[3].ts) { + return fmt.Errorf("read got timestamp %v, want it to be no later than %v", ts, writes[3].ts) + } + return nil + }, + }, + { + // read_timestamp + [][]interface{}{{int64(1), "Marc", "Foo"}, {int64(3), "Alpha", "Beta"}}, + ReadTimestamp(writes[2].ts), + func(ts time.Time) error { + if ts != writes[2].ts { + return fmt.Errorf("read got timestamp %v, want %v", ts, writes[2].ts) + } + return nil + }, + }, + { + // exact_staleness + nil, + // Specify a staleness which should be already before this test because + // context timeout is set to be 10s. + ExactStaleness(11 * time.Second), + func(ts time.Time) error { + if ts.After(writes[0].ts) { + return fmt.Errorf("read got timestamp %v, want it to be no earlier than %v", ts, writes[0].ts) + } + return nil + }, + }, + } { + // SingleUse.Query + su := client.Single().WithTimestampBound(test.tb) + got, err := readAll(su.Query( + ctx, + Statement{ + "SELECT SingerId, FirstName, LastName FROM Singers WHERE SingerId IN (@id1, @id3, @id4)", + map[string]interface{}{"id1": int64(1), "id3": int64(3), "id4": int64(4)}, + })) + if err != nil { + t.Errorf("%d: SingleUse.Query returns error %v, want nil", i, err) + } + if !testEqual(got, test.want) { + t.Errorf("%d: got unexpected result from SingleUse.Query: %v, want %v", i, got, test.want) + } + rts, err := su.Timestamp() + if err != nil { + t.Errorf("%d: SingleUse.Query doesn't return a timestamp, error: %v", i, err) + } + if err := test.checkTs(rts); err != nil { + t.Errorf("%d: SingleUse.Query doesn't return expected timestamp: %v", i, err) + } + // SingleUse.Read + su = client.Single().WithTimestampBound(test.tb) + got, err = readAll(su.Read(ctx, "Singers", KeySets(Key{1}, Key{3}, Key{4}), []string{"SingerId", "FirstName", "LastName"})) + if err != nil { + t.Errorf("%d: SingleUse.Read returns error %v, want nil", i, err) + } + if !testEqual(got, test.want) { + t.Errorf("%d: got unexpected result from SingleUse.Read: %v, want %v", i, got, test.want) + } + rts, err = su.Timestamp() + if err != nil { + t.Errorf("%d: SingleUse.Read doesn't return a timestamp, error: %v", i, err) + } + if err := test.checkTs(rts); err != nil { + t.Errorf("%d: SingleUse.Read doesn't return expected timestamp: %v", i, err) + } + // SingleUse.ReadRow + got = nil + for _, k := range []Key{{1}, {3}, {4}} { + su = client.Single().WithTimestampBound(test.tb) + r, err := su.ReadRow(ctx, "Singers", k, []string{"SingerId", "FirstName", "LastName"}) + if err != nil { + continue + } + v, err := rowToValues(r) + if err != nil { + continue + } + got = append(got, v) + rts, err = su.Timestamp() + if err != nil { + t.Errorf("%d: SingleUse.ReadRow(%v) doesn't return a timestamp, error: %v", i, k, err) + } + if err := test.checkTs(rts); err != nil { + t.Errorf("%d: SingleUse.ReadRow(%v) doesn't return expected timestamp: %v", i, k, err) + } + } + if !testEqual(got, test.want) { + t.Errorf("%d: got unexpected results from SingleUse.ReadRow: %v, want %v", i, got, test.want) + } + // SingleUse.ReadUsingIndex + su = client.Single().WithTimestampBound(test.tb) + got, err = readAll(su.ReadUsingIndex(ctx, "Singers", "SingerByName", KeySets(Key{"Marc", "Foo"}, Key{"Alpha", "Beta"}, Key{"Last", "End"}), []string{"SingerId", "FirstName", "LastName"})) + if err != nil { + t.Errorf("%d: SingleUse.ReadUsingIndex returns error %v, want nil", i, err) + } + // The results from ReadUsingIndex is sorted by the index rather than primary key. + if len(got) != len(test.want) { + t.Errorf("%d: got unexpected result from SingleUse.ReadUsingIndex: %v, want %v", i, got, test.want) + } + for j, g := range got { + if j > 0 { + prev := got[j-1][1].(string) + got[j-1][2].(string) + curr := got[j][1].(string) + got[j][2].(string) + if strings.Compare(prev, curr) > 0 { + t.Errorf("%d: SingleUse.ReadUsingIndex fails to order rows by index keys, %v should be after %v", i, got[j-1], got[j]) + } + } + found := false + for _, w := range test.want { + if testEqual(g, w) { + found = true + } + } + if !found { + t.Errorf("%d: got unexpected result from SingleUse.ReadUsingIndex: %v, want %v", i, got, test.want) + break + } + } + rts, err = su.Timestamp() + if err != nil { + t.Errorf("%d: SingleUse.ReadUsingIndex doesn't return a timestamp, error: %v", i, err) + } + if err := test.checkTs(rts); err != nil { + t.Errorf("%d: SingleUse.ReadUsingIndex doesn't return expected timestamp: %v", i, err) + } + } + + // Reading with limit. + su := client.Single() + const limit = 1 + gotRows, err := readAll(su.ReadWithOptions(ctx, "Singers", KeySets(Key{1}, Key{3}, Key{4}), + []string{"SingerId", "FirstName", "LastName"}, &ReadOptions{Limit: limit})) + if err != nil { + t.Errorf("SingleUse.ReadWithOptions returns error %v, want nil", err) + } + if got, want := len(gotRows), limit; got != want { + t.Errorf("got %d, want %d", got, want) + } + +} + +// Test ReadOnlyTransaction. The testsuite is mostly like SingleUse, except it +// also tests for a single timestamp across multiple reads. +func TestReadOnlyTransaction(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + // Set up testing environment. + client, _, cleanup := prepare(ctx, t, singerDBStatements) + defer cleanup() + + writes := []struct { + row []interface{} + ts time.Time + }{ + {row: []interface{}{1, "Marc", "Foo"}}, + {row: []interface{}{2, "Tars", "Bar"}}, + {row: []interface{}{3, "Alpha", "Beta"}}, + {row: []interface{}{4, "Last", "End"}}, + } + // Try to write four rows through the Apply API. + for i, w := range writes { + var err error + m := InsertOrUpdate("Singers", + []string{"SingerId", "FirstName", "LastName"}, + w.row) + if writes[i].ts, err = client.Apply(ctx, []*Mutation{m}, ApplyAtLeastOnce()); err != nil { + t.Fatal(err) + } + } + + // For testing timestamp bound staleness. + <-time.After(time.Second) + + // Test reading rows with different timestamp bounds. + for i, test := range []struct { + want [][]interface{} + tb TimestampBound + checkTs func(time.Time) error + }{ + // Note: min_read_timestamp and max_staleness are not supported by ReadOnlyTransaction. See + // API document for more details. + { + // strong + [][]interface{}{{int64(1), "Marc", "Foo"}, {int64(3), "Alpha", "Beta"}, {int64(4), "Last", "End"}}, + StrongRead(), + func(ts time.Time) error { + if ts.Before(writes[3].ts) { + return fmt.Errorf("read got timestamp %v, want it to be no later than %v", ts, writes[3].ts) + } + return nil + }, + }, + { + // read_timestamp + [][]interface{}{{int64(1), "Marc", "Foo"}, {int64(3), "Alpha", "Beta"}}, + ReadTimestamp(writes[2].ts), + func(ts time.Time) error { + if ts != writes[2].ts { + return fmt.Errorf("read got timestamp %v, expect %v", ts, writes[2].ts) + } + return nil + }, + }, + { + // exact_staleness + nil, + // Specify a staleness which should be already before this test because + // context timeout is set to be 10s. + ExactStaleness(11 * time.Second), + func(ts time.Time) error { + if ts.After(writes[0].ts) { + return fmt.Errorf("read got timestamp %v, want it to be no earlier than %v", ts, writes[0].ts) + } + return nil + }, + }, + } { + // ReadOnlyTransaction.Query + ro := client.ReadOnlyTransaction().WithTimestampBound(test.tb) + got, err := readAll(ro.Query( + ctx, + Statement{ + "SELECT SingerId, FirstName, LastName FROM Singers WHERE SingerId IN (@id1, @id3, @id4)", + map[string]interface{}{"id1": int64(1), "id3": int64(3), "id4": int64(4)}, + })) + if err != nil { + t.Errorf("%d: ReadOnlyTransaction.Query returns error %v, want nil", i, err) + } + if !testEqual(got, test.want) { + t.Errorf("%d: got unexpected result from ReadOnlyTransaction.Query: %v, want %v", i, got, test.want) + } + rts, err := ro.Timestamp() + if err != nil { + t.Errorf("%d: ReadOnlyTransaction.Query doesn't return a timestamp, error: %v", i, err) + } + if err := test.checkTs(rts); err != nil { + t.Errorf("%d: ReadOnlyTransaction.Query doesn't return expected timestamp: %v", i, err) + } + roTs := rts + // ReadOnlyTransaction.Read + got, err = readAll(ro.Read(ctx, "Singers", KeySets(Key{1}, Key{3}, Key{4}), []string{"SingerId", "FirstName", "LastName"})) + if err != nil { + t.Errorf("%d: ReadOnlyTransaction.Read returns error %v, want nil", i, err) + } + if !testEqual(got, test.want) { + t.Errorf("%d: got unexpected result from ReadOnlyTransaction.Read: %v, want %v", i, got, test.want) + } + rts, err = ro.Timestamp() + if err != nil { + t.Errorf("%d: ReadOnlyTransaction.Read doesn't return a timestamp, error: %v", i, err) + } + if err := test.checkTs(rts); err != nil { + t.Errorf("%d: ReadOnlyTransaction.Read doesn't return expected timestamp: %v", i, err) + } + if roTs != rts { + t.Errorf("%d: got two read timestamps: %v, %v, want ReadOnlyTransaction to return always the same read timestamp", i, roTs, rts) + } + // ReadOnlyTransaction.ReadRow + got = nil + for _, k := range []Key{{1}, {3}, {4}} { + r, err := ro.ReadRow(ctx, "Singers", k, []string{"SingerId", "FirstName", "LastName"}) + if err != nil { + continue + } + v, err := rowToValues(r) + if err != nil { + continue + } + got = append(got, v) + rts, err = ro.Timestamp() + if err != nil { + t.Errorf("%d: ReadOnlyTransaction.ReadRow(%v) doesn't return a timestamp, error: %v", i, k, err) + } + if err := test.checkTs(rts); err != nil { + t.Errorf("%d: ReadOnlyTransaction.ReadRow(%v) doesn't return expected timestamp: %v", i, k, err) + } + if roTs != rts { + t.Errorf("%d: got two read timestamps: %v, %v, want ReadOnlyTransaction to return always the same read timestamp", i, roTs, rts) + } + } + if !testEqual(got, test.want) { + t.Errorf("%d: got unexpected results from ReadOnlyTransaction.ReadRow: %v, want %v", i, got, test.want) + } + // SingleUse.ReadUsingIndex + got, err = readAll(ro.ReadUsingIndex(ctx, "Singers", "SingerByName", KeySets(Key{"Marc", "Foo"}, Key{"Alpha", "Beta"}, Key{"Last", "End"}), []string{"SingerId", "FirstName", "LastName"})) + if err != nil { + t.Errorf("%d: ReadOnlyTransaction.ReadUsingIndex returns error %v, want nil", i, err) + } + // The results from ReadUsingIndex is sorted by the index rather than primary key. + if len(got) != len(test.want) { + t.Errorf("%d: got unexpected result from ReadOnlyTransaction.ReadUsingIndex: %v, want %v", i, got, test.want) + } + for j, g := range got { + if j > 0 { + prev := got[j-1][1].(string) + got[j-1][2].(string) + curr := got[j][1].(string) + got[j][2].(string) + if strings.Compare(prev, curr) > 0 { + t.Errorf("%d: ReadOnlyTransaction.ReadUsingIndex fails to order rows by index keys, %v should be after %v", i, got[j-1], got[j]) + } + } + found := false + for _, w := range test.want { + if testEqual(g, w) { + found = true + } + } + if !found { + t.Errorf("%d: got unexpected result from ReadOnlyTransaction.ReadUsingIndex: %v, want %v", i, got, test.want) + break + } + } + rts, err = ro.Timestamp() + if err != nil { + t.Errorf("%d: ReadOnlyTransaction.ReadUsingIndex doesn't return a timestamp, error: %v", i, err) + } + if err := test.checkTs(rts); err != nil { + t.Errorf("%d: ReadOnlyTransaction.ReadUsingIndex doesn't return expected timestamp: %v", i, err) + } + if roTs != rts { + t.Errorf("%d: got two read timestamps: %v, %v, want ReadOnlyTransaction to return always the same read timestamp", i, roTs, rts) + } + ro.Close() + } +} + +// Test ReadOnlyTransaction with different timestamp bound when there's an update at the same time. +func TestUpdateDuringRead(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + client, _, cleanup := prepare(ctx, t, singerDBStatements) + defer cleanup() + + for i, tb := range []TimestampBound{ + StrongRead(), + ReadTimestamp(time.Now().Add(-time.Minute * 30)), // version GC is 1 hour + ExactStaleness(time.Minute * 30), + } { + ro := client.ReadOnlyTransaction().WithTimestampBound(tb) + _, err := ro.ReadRow(ctx, "Singers", Key{i}, []string{"SingerId"}) + if ErrCode(err) != codes.NotFound { + t.Errorf("%d: ReadOnlyTransaction.ReadRow before write returns error: %v, want NotFound", i, err) + } + + m := InsertOrUpdate("Singers", []string{"SingerId"}, []interface{}{i}) + if _, err := client.Apply(ctx, []*Mutation{m}, ApplyAtLeastOnce()); err != nil { + t.Fatal(err) + } + + _, err = ro.ReadRow(ctx, "Singers", Key{i}, []string{"SingerId"}) + if ErrCode(err) != codes.NotFound { + t.Errorf("%d: ReadOnlyTransaction.ReadRow after write returns error: %v, want NotFound", i, err) + } + } +} + +// Test ReadWriteTransaction. +func TestReadWriteTransaction(t *testing.T) { + // Give a longer deadline because of transaction backoffs. + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) + defer cancel() + client, _, cleanup := prepare(ctx, t, singerDBStatements) + defer cleanup() + + // Set up two accounts + accounts := []*Mutation{ + Insert("Accounts", []string{"AccountId", "Nickname", "Balance"}, []interface{}{int64(1), "Foo", int64(50)}), + Insert("Accounts", []string{"AccountId", "Nickname", "Balance"}, []interface{}{int64(2), "Bar", int64(1)}), + } + if _, err := client.Apply(ctx, accounts, ApplyAtLeastOnce()); err != nil { + t.Fatal(err) + } + wg := sync.WaitGroup{} + + readBalance := func(iter *RowIterator) (int64, error) { + defer iter.Stop() + var bal int64 + for { + row, err := iter.Next() + if err == iterator.Done { + return bal, nil + } + if err != nil { + return 0, err + } + if err := row.Column(0, &bal); err != nil { + return 0, err + } + } + } + + for i := 0; i < 20; i++ { + wg.Add(1) + go func(iter int) { + defer wg.Done() + _, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, tx *ReadWriteTransaction) error { + // Query Foo's balance and Bar's balance. + bf, e := readBalance(tx.Query(ctx, + Statement{"SELECT Balance FROM Accounts WHERE AccountId = @id", map[string]interface{}{"id": int64(1)}})) + if e != nil { + return e + } + bb, e := readBalance(tx.Read(ctx, "Accounts", KeySets(Key{int64(2)}), []string{"Balance"})) + if e != nil { + return e + } + if bf <= 0 { + return nil + } + bf-- + bb++ + return tx.BufferWrite([]*Mutation{ + Update("Accounts", []string{"AccountId", "Balance"}, []interface{}{int64(1), bf}), + Update("Accounts", []string{"AccountId", "Balance"}, []interface{}{int64(2), bb}), + }) + }) + if err != nil { + t.Errorf("%d: failed to execute transaction: %v", iter, err) + } + }(i) + } + // Because of context timeout, all goroutines will eventually return. + wg.Wait() + _, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, tx *ReadWriteTransaction) error { + var bf, bb int64 + r, e := tx.ReadRow(ctx, "Accounts", Key{int64(1)}, []string{"Balance"}) + if e != nil { + return e + } + if ce := r.Column(0, &bf); ce != nil { + return ce + } + bb, e = readBalance(tx.ReadUsingIndex(ctx, "Accounts", "AccountByNickname", KeySets(Key{"Bar"}), []string{"Balance"})) + if e != nil { + return e + } + if bf != 30 || bb != 21 { + t.Errorf("Foo's balance is now %v and Bar's balance is now %v, want %v and %v", bf, bb, 30, 21) + } + return nil + }) + if err != nil { + t.Errorf("failed to check balances: %v", err) + } +} + +func TestReads(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + // Set up testing environment. + client, _, cleanup := prepare(ctx, t, readDBStatements) + defer cleanup() + + // Includes k0..k14. Strings sort lexically, eg "k1" < "k10" < "k2". + var ms []*Mutation + for i := 0; i < 15; i++ { + ms = append(ms, InsertOrUpdate(testTable, + testTableColumns, + []interface{}{fmt.Sprintf("k%d", i), fmt.Sprintf("v%d", i)})) + } + // Don't use ApplyAtLeastOnce, so we can test the other code path. + if _, err := client.Apply(ctx, ms); err != nil { + t.Fatal(err) + } + + // Empty read. + rows, err := readAllTestTable(client.Single().Read(ctx, testTable, + KeyRange{Start: Key{"k99"}, End: Key{"z"}}, testTableColumns)) + if err != nil { + t.Fatal(err) + } + if got, want := len(rows), 0; got != want { + t.Errorf("got %d, want %d", got, want) + } + + // Index empty read. + rows, err = readAllTestTable(client.Single().ReadUsingIndex(ctx, testTable, testTableIndex, + KeyRange{Start: Key{"v99"}, End: Key{"z"}}, testTableColumns)) + if err != nil { + t.Fatal(err) + } + if got, want := len(rows), 0; got != want { + t.Errorf("got %d, want %d", got, want) + } + + // Point read. + row, err := client.Single().ReadRow(ctx, testTable, Key{"k1"}, testTableColumns) + if err != nil { + t.Fatal(err) + } + var got testTableRow + if err := row.ToStruct(&got); err != nil { + t.Fatal(err) + } + if want := (testTableRow{"k1", "v1"}); got != want { + t.Errorf("got %v, want %v", got, want) + } + + // Point read not found. + _, err = client.Single().ReadRow(ctx, testTable, Key{"k999"}, testTableColumns) + if ErrCode(err) != codes.NotFound { + t.Fatalf("got %v, want NotFound", err) + } + + // No index point read not found, because Go does not have ReadRowUsingIndex. + + rangeReads(ctx, t, client) + indexRangeReads(ctx, t, client) +} + +func TestEarlyTimestamp(t *testing.T) { + // Test that we can get the timestamp from a read-only transaction as + // soon as we have read at least one row. + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + // Set up testing environment. + client, _, cleanup := prepare(ctx, t, readDBStatements) + defer cleanup() + + var ms []*Mutation + for i := 0; i < 3; i++ { + ms = append(ms, InsertOrUpdate(testTable, + testTableColumns, + []interface{}{fmt.Sprintf("k%d", i), fmt.Sprintf("v%d", i)})) + } + if _, err := client.Apply(ctx, ms, ApplyAtLeastOnce()); err != nil { + t.Fatal(err) + } + + txn := client.Single() + iter := txn.Read(ctx, testTable, AllKeys(), testTableColumns) + defer iter.Stop() + // In single-use transaction, we should get an error before reading anything. + if _, err := txn.Timestamp(); err == nil { + t.Error("wanted error, got nil") + } + // After reading one row, the timestamp should be available. + _, err := iter.Next() + if err != nil { + t.Fatal(err) + } + if _, err := txn.Timestamp(); err != nil { + t.Errorf("got %v, want nil", err) + } + + txn = client.ReadOnlyTransaction() + defer txn.Close() + iter = txn.Read(ctx, testTable, AllKeys(), testTableColumns) + defer iter.Stop() + // In an ordinary read-only transaction, the timestamp should be + // available immediately. + if _, err := txn.Timestamp(); err != nil { + t.Errorf("got %v, want nil", err) + } +} + +func TestNestedTransaction(t *testing.T) { + // You cannot use a transaction from inside a read-write transaction. + ctx := context.Background() + client, _, cleanup := prepare(ctx, t, singerDBStatements) + defer cleanup() + + _, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, tx *ReadWriteTransaction) error { + _, err := client.ReadWriteTransaction(ctx, + func(context.Context, *ReadWriteTransaction) error { return nil }) + if ErrCode(err) != codes.FailedPrecondition { + t.Fatalf("got %v, want FailedPrecondition", err) + } + _, err = client.Single().ReadRow(ctx, "Singers", Key{1}, []string{"SingerId"}) + if ErrCode(err) != codes.FailedPrecondition { + t.Fatalf("got %v, want FailedPrecondition", err) + } + rot := client.ReadOnlyTransaction() + defer rot.Close() + _, err = rot.ReadRow(ctx, "Singers", Key{1}, []string{"SingerId"}) + if ErrCode(err) != codes.FailedPrecondition { + t.Fatalf("got %v, want FailedPrecondition", err) + } + return nil + }) + if err != nil { + t.Fatal(err) + } +} + +// Test client recovery on database recreation. +func TestDbRemovalRecovery(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) + defer cancel() + client, dbPath, cleanup := prepare(ctx, t, singerDBStatements) + defer cleanup() + + // Drop the testing database. + if err := admin.DropDatabase(ctx, &adminpb.DropDatabaseRequest{Database: dbPath}); err != nil { + t.Fatalf("failed to drop testing database %v: %v", dbPath, err) + } + + // Now, send the query. + iter := client.Single().Query(ctx, Statement{SQL: "SELECT SingerId FROM Singers"}) + defer iter.Stop() + if _, err := iter.Next(); err == nil { + t.Errorf("client sends query to removed database successfully, want it to fail") + } + + // Recreate database and table. + dbName := dbPath[strings.LastIndex(dbPath, "/")+1:] + op, err := admin.CreateDatabase(ctx, &adminpb.CreateDatabaseRequest{ + Parent: fmt.Sprintf("projects/%v/instances/%v", testProjectID, testInstanceID), + CreateStatement: "CREATE DATABASE " + dbName, + ExtraStatements: []string{ + `CREATE TABLE Singers ( + SingerId INT64 NOT NULL, + FirstName STRING(1024), + LastName STRING(1024), + SingerInfo BYTES(MAX) + ) PRIMARY KEY (SingerId)`, + }, + }) + if err != nil { + t.Fatalf("cannot recreate testing DB %v: %v", dbPath, err) + } + if _, err := op.Wait(ctx); err != nil { + t.Fatalf("cannot recreate testing DB %v: %v", dbPath, err) + } + + // Now, send the query again. + iter = client.Single().Query(ctx, Statement{SQL: "SELECT SingerId FROM Singers"}) + defer iter.Stop() + _, err = iter.Next() + if err != nil && err != iterator.Done { + t.Errorf("failed to send query to database %v: %v", dbPath, err) + } +} + +// Test encoding/decoding non-struct Cloud Spanner types. +func TestBasicTypes(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + client, _, cleanup := prepare(ctx, t, singerDBStatements) + defer cleanup() + + t1, _ := time.Parse(time.RFC3339Nano, "2016-11-15T15:04:05.999999999Z") + // Boundaries + t2, _ := time.Parse(time.RFC3339Nano, "0001-01-01T00:00:00.000000000Z") + t3, _ := time.Parse(time.RFC3339Nano, "9999-12-31T23:59:59.999999999Z") + d1, _ := civil.ParseDate("2016-11-15") + // Boundaries + d2, _ := civil.ParseDate("0001-01-01") + d3, _ := civil.ParseDate("9999-12-31") + + tests := []struct { + col string + val interface{} + want interface{} + }{ + {col: "String", val: ""}, + {col: "String", val: "", want: NullString{"", true}}, + {col: "String", val: "foo"}, + {col: "String", val: "foo", want: NullString{"foo", true}}, + {col: "String", val: NullString{"bar", true}, want: "bar"}, + {col: "String", val: NullString{"bar", false}, want: NullString{"", false}}, + {col: "String", val: nil, want: NullString{}}, + {col: "StringArray", val: []string(nil), want: []NullString(nil)}, + {col: "StringArray", val: []string{}, want: []NullString{}}, + {col: "StringArray", val: []string{"foo", "bar"}, want: []NullString{{"foo", true}, {"bar", true}}}, + {col: "StringArray", val: []NullString(nil)}, + {col: "StringArray", val: []NullString{}}, + {col: "StringArray", val: []NullString{{"foo", true}, {}}}, + {col: "Bytes", val: []byte{}}, + {col: "Bytes", val: []byte{1, 2, 3}}, + {col: "Bytes", val: []byte(nil)}, + {col: "BytesArray", val: [][]byte(nil)}, + {col: "BytesArray", val: [][]byte{}}, + {col: "BytesArray", val: [][]byte{{1}, {2, 3}}}, + {col: "Int64a", val: 0, want: int64(0)}, + {col: "Int64a", val: -1, want: int64(-1)}, + {col: "Int64a", val: 2, want: int64(2)}, + {col: "Int64a", val: int64(3)}, + {col: "Int64a", val: 4, want: NullInt64{4, true}}, + {col: "Int64a", val: NullInt64{5, true}, want: int64(5)}, + {col: "Int64a", val: NullInt64{6, true}, want: int64(6)}, + {col: "Int64a", val: NullInt64{7, false}, want: NullInt64{0, false}}, + {col: "Int64a", val: nil, want: NullInt64{}}, + {col: "Int64Array", val: []int(nil), want: []NullInt64(nil)}, + {col: "Int64Array", val: []int{}, want: []NullInt64{}}, + {col: "Int64Array", val: []int{1, 2}, want: []NullInt64{{1, true}, {2, true}}}, + {col: "Int64Array", val: []int64(nil), want: []NullInt64(nil)}, + {col: "Int64Array", val: []int64{}, want: []NullInt64{}}, + {col: "Int64Array", val: []int64{1, 2}, want: []NullInt64{{1, true}, {2, true}}}, + {col: "Int64Array", val: []NullInt64(nil)}, + {col: "Int64Array", val: []NullInt64{}}, + {col: "Int64Array", val: []NullInt64{{1, true}, {}}}, + {col: "Bool", val: false}, + {col: "Bool", val: true}, + {col: "Bool", val: false, want: NullBool{false, true}}, + {col: "Bool", val: true, want: NullBool{true, true}}, + {col: "Bool", val: NullBool{true, true}}, + {col: "Bool", val: NullBool{false, false}}, + {col: "Bool", val: nil, want: NullBool{}}, + {col: "BoolArray", val: []bool(nil), want: []NullBool(nil)}, + {col: "BoolArray", val: []bool{}, want: []NullBool{}}, + {col: "BoolArray", val: []bool{true, false}, want: []NullBool{{true, true}, {false, true}}}, + {col: "BoolArray", val: []NullBool(nil)}, + {col: "BoolArray", val: []NullBool{}}, + {col: "BoolArray", val: []NullBool{{false, true}, {true, true}, {}}}, + {col: "Float64", val: 0.0}, + {col: "Float64", val: 3.14}, + {col: "Float64", val: math.NaN()}, + {col: "Float64", val: math.Inf(1)}, + {col: "Float64", val: math.Inf(-1)}, + {col: "Float64", val: 2.78, want: NullFloat64{2.78, true}}, + {col: "Float64", val: NullFloat64{2.71, true}, want: 2.71}, + {col: "Float64", val: NullFloat64{1.41, true}, want: NullFloat64{1.41, true}}, + {col: "Float64", val: NullFloat64{0, false}}, + {col: "Float64", val: nil, want: NullFloat64{}}, + {col: "Float64Array", val: []float64(nil), want: []NullFloat64(nil)}, + {col: "Float64Array", val: []float64{}, want: []NullFloat64{}}, + {col: "Float64Array", val: []float64{2.72, 3.14, math.Inf(1)}, want: []NullFloat64{{2.72, true}, {3.14, true}, {math.Inf(1), true}}}, + {col: "Float64Array", val: []NullFloat64(nil)}, + {col: "Float64Array", val: []NullFloat64{}}, + {col: "Float64Array", val: []NullFloat64{{2.72, true}, {math.Inf(1), true}, {}}}, + {col: "Date", val: d1}, + {col: "Date", val: d1, want: NullDate{d1, true}}, + {col: "Date", val: NullDate{d1, true}}, + {col: "Date", val: NullDate{d1, true}, want: d1}, + {col: "Date", val: NullDate{civil.Date{}, false}}, + {col: "DateArray", val: []civil.Date(nil), want: []NullDate(nil)}, + {col: "DateArray", val: []civil.Date{}, want: []NullDate{}}, + {col: "DateArray", val: []civil.Date{d1, d2, d3}, want: []NullDate{{d1, true}, {d2, true}, {d3, true}}}, + {col: "Timestamp", val: t1}, + {col: "Timestamp", val: t1, want: NullTime{t1, true}}, + {col: "Timestamp", val: NullTime{t1, true}}, + {col: "Timestamp", val: NullTime{t1, true}, want: t1}, + {col: "Timestamp", val: NullTime{}}, + {col: "Timestamp", val: nil, want: NullTime{}}, + {col: "TimestampArray", val: []time.Time(nil), want: []NullTime(nil)}, + {col: "TimestampArray", val: []time.Time{}, want: []NullTime{}}, + {col: "TimestampArray", val: []time.Time{t1, t2, t3}, want: []NullTime{{t1, true}, {t2, true}, {t3, true}}}, + } + + // Write rows into table first. + var muts []*Mutation + for i, test := range tests { + muts = append(muts, InsertOrUpdate("Types", []string{"RowID", test.col}, []interface{}{i, test.val})) + } + if _, err := client.Apply(ctx, muts, ApplyAtLeastOnce()); err != nil { + t.Fatal(err) + } + + for i, test := range tests { + row, err := client.Single().ReadRow(ctx, "Types", []interface{}{i}, []string{test.col}) + if err != nil { + t.Fatalf("Unable to fetch row %v: %v", i, err) + } + // Create new instance of type of test.want. + want := test.want + if want == nil { + want = test.val + } + gotp := reflect.New(reflect.TypeOf(want)) + if err := row.Column(0, gotp.Interface()); err != nil { + t.Errorf("%d: col:%v val:%#v, %v", i, test.col, test.val, err) + continue + } + got := reflect.Indirect(gotp).Interface() + + // One of the test cases is checking NaN handling. Given + // NaN!=NaN, we can't use reflect to test for it. + if isNaN(got) && isNaN(want) { + continue + } + + // Check non-NaN cases. + if !testEqual(got, want) { + t.Errorf("%d: col:%v val:%#v, got %#v, want %#v", i, test.col, test.val, got, want) + continue + } + } +} + +// Test decoding Cloud Spanner STRUCT type. +func TestStructTypes(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + client, _, cleanup := prepare(ctx, t, singerDBStatements) + defer cleanup() + + tests := []struct { + q Statement + want func(r *Row) error + }{ + { + q: Statement{SQL: `SELECT ARRAY(SELECT STRUCT(1, 2))`}, + want: func(r *Row) error { + // Test STRUCT ARRAY decoding to []NullRow. + var rows []NullRow + if err := r.Column(0, &rows); err != nil { + return err + } + if len(rows) != 1 { + return fmt.Errorf("len(rows) = %d; want 1", len(rows)) + } + if !rows[0].Valid { + return fmt.Errorf("rows[0] is NULL") + } + var i, j int64 + if err := rows[0].Row.Columns(&i, &j); err != nil { + return err + } + if i != 1 || j != 2 { + return fmt.Errorf("got (%d,%d), want (1,2)", i, j) + } + return nil + }, + }, + { + q: Statement{SQL: `SELECT ARRAY(SELECT STRUCT(1 as foo, 2 as bar)) as col1`}, + want: func(r *Row) error { + // Test Row.ToStruct. + s := struct { + Col1 []*struct { + Foo int64 `spanner:"foo"` + Bar int64 `spanner:"bar"` + } `spanner:"col1"` + }{} + if err := r.ToStruct(&s); err != nil { + return err + } + want := struct { + Col1 []*struct { + Foo int64 `spanner:"foo"` + Bar int64 `spanner:"bar"` + } `spanner:"col1"` + }{ + Col1: []*struct { + Foo int64 `spanner:"foo"` + Bar int64 `spanner:"bar"` + }{ + { + Foo: 1, + Bar: 2, + }, + }, + } + if !testEqual(want, s) { + return fmt.Errorf("unexpected decoding result: %v, want %v", s, want) + } + return nil + }, + }, + } + for i, test := range tests { + iter := client.Single().Query(ctx, test.q) + defer iter.Stop() + row, err := iter.Next() + if err != nil { + t.Errorf("%d: %v", i, err) + continue + } + if err := test.want(row); err != nil { + t.Errorf("%d: %v", i, err) + continue + } + } +} + +func TestStructParametersUnsupported(t *testing.T) { + ctx := context.Background() + client, _, cleanup := prepare(ctx, t, nil) + defer cleanup() + + for _, test := range []struct { + param interface{} + wantCode codes.Code + wantMsgPart string + }{ + { + struct { + Field int + }{10}, + codes.Unimplemented, + "Unsupported query shape: " + + "A struct value cannot be returned as a column value. " + + "Rewrite the query to flatten the struct fields in the result.", + }, + { + []struct { + Field int + }{{10}, {20}}, + codes.Unimplemented, + "Unsupported query shape: " + + "This query can return a null-valued array of struct, " + + "which is not supported by Spanner.", + }, + } { + iter := client.Single().Query(ctx, Statement{ + SQL: "SELECT @p", + Params: map[string]interface{}{"p": test.param}, + }) + _, err := iter.Next() + iter.Stop() + if msg, ok := matchError(err, test.wantCode, test.wantMsgPart); !ok { + t.Fatal(msg) + } + } +} + +// Test queries of the form "SELECT expr". +func TestQueryExpressions(t *testing.T) { + ctx := context.Background() + client, _, cleanup := prepare(ctx, t, nil) + defer cleanup() + + newRow := func(vals []interface{}) *Row { + row, err := NewRow(make([]string, len(vals)), vals) + if err != nil { + t.Fatal(err) + } + return row + } + + tests := []struct { + expr string + want interface{} + }{ + {"1", int64(1)}, + {"[1, 2, 3]", []NullInt64{{1, true}, {2, true}, {3, true}}}, + {"[1, NULL, 3]", []NullInt64{{1, true}, {0, false}, {3, true}}}, + {"IEEE_DIVIDE(1, 0)", math.Inf(1)}, + {"IEEE_DIVIDE(-1, 0)", math.Inf(-1)}, + {"IEEE_DIVIDE(0, 0)", math.NaN()}, + // TODO(jba): add IEEE_DIVIDE(0, 0) to the following array when we have a better equality predicate. + {"[IEEE_DIVIDE(1, 0), IEEE_DIVIDE(-1, 0)]", []NullFloat64{{math.Inf(1), true}, {math.Inf(-1), true}}}, + {"ARRAY(SELECT AS STRUCT * FROM (SELECT 'a', 1) WHERE 0 = 1)", []NullRow{}}, + {"ARRAY(SELECT STRUCT(1, 2))", []NullRow{{Row: *newRow([]interface{}{1, 2}), Valid: true}}}, + } + for _, test := range tests { + iter := client.Single().Query(ctx, Statement{SQL: "SELECT " + test.expr}) + defer iter.Stop() + row, err := iter.Next() + if err != nil { + t.Errorf("%q: %v", test.expr, err) + continue + } + // Create new instance of type of test.want. + gotp := reflect.New(reflect.TypeOf(test.want)) + if err := row.Column(0, gotp.Interface()); err != nil { + t.Errorf("%q: Column returned error %v", test.expr, err) + continue + } + got := reflect.Indirect(gotp).Interface() + // TODO(jba): remove isNaN special case when we have a better equality predicate. + if isNaN(got) && isNaN(test.want) { + continue + } + if !testEqual(got, test.want) { + t.Errorf("%q\n got %#v\nwant %#v", test.expr, got, test.want) + } + } +} + +func TestQueryStats(t *testing.T) { + ctx := context.Background() + client, _, cleanup := prepare(ctx, t, singerDBStatements) + defer cleanup() + + accounts := []*Mutation{ + Insert("Accounts", []string{"AccountId", "Nickname", "Balance"}, []interface{}{int64(1), "Foo", int64(50)}), + Insert("Accounts", []string{"AccountId", "Nickname", "Balance"}, []interface{}{int64(2), "Bar", int64(1)}), + } + if _, err := client.Apply(ctx, accounts, ApplyAtLeastOnce()); err != nil { + t.Fatal(err) + } + const sql = "SELECT Balance FROM Accounts" + + qp, err := client.Single().AnalyzeQuery(ctx, Statement{sql, nil}) + if err != nil { + t.Fatal(err) + } + if len(qp.PlanNodes) == 0 { + t.Error("got zero plan nodes, expected at least one") + } + + iter := client.Single().QueryWithStats(ctx, Statement{sql, nil}) + defer iter.Stop() + for { + _, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + t.Fatal(err) + } + } + if iter.QueryPlan == nil { + t.Error("got nil QueryPlan, expected one") + } + if iter.QueryStats == nil { + t.Error("got nil QueryStats, expected some") + } +} + +func TestInvalidDatabase(t *testing.T) { + if testProjectID == "" { + t.Skip("Integration tests skipped: GCLOUD_TESTS_GOLANG_PROJECT_ID is missing") + } + ctx := context.Background() + dbPath := fmt.Sprintf("projects/%v/instances/%v/databases/invalid", testProjectID, testInstanceID) + c, err := createClient(ctx, dbPath) + // Client creation should succeed even if the database is invalid. + if err != nil { + t.Fatal(err) + } + _, err = c.Single().ReadRow(ctx, "TestTable", Key{1}, []string{"col1"}) + if msg, ok := matchError(err, codes.NotFound, ""); !ok { + t.Fatal(msg) + } +} + +func TestReadErrors(t *testing.T) { + ctx := context.Background() + client, _, cleanup := prepare(ctx, t, readDBStatements) + defer cleanup() + + // Read over invalid table fails + _, err := client.Single().ReadRow(ctx, "badTable", Key{1}, []string{"StringValue"}) + if msg, ok := matchError(err, codes.NotFound, "badTable"); !ok { + t.Error(msg) + } + // Read over invalid column fails + _, err = client.Single().ReadRow(ctx, "TestTable", Key{1}, []string{"badcol"}) + if msg, ok := matchError(err, codes.NotFound, "badcol"); !ok { + t.Error(msg) + } + + // Invalid query fails + iter := client.Single().Query(ctx, Statement{SQL: "SELECT Apples AND Oranges"}) + defer iter.Stop() + _, err = iter.Next() + if msg, ok := matchError(err, codes.InvalidArgument, "unrecognized name"); !ok { + t.Error(msg) + } + + // Read should fail on cancellation. + cctx, cancel := context.WithCancel(ctx) + cancel() + _, err = client.Single().ReadRow(cctx, "TestTable", Key{1}, []string{"StringValue"}) + if msg, ok := matchError(err, codes.Canceled, ""); !ok { + t.Error(msg) + } + // Read should fail if deadline exceeded. + dctx, cancel := context.WithTimeout(ctx, time.Nanosecond) + defer cancel() + <-dctx.Done() + _, err = client.Single().ReadRow(dctx, "TestTable", Key{1}, []string{"StringValue"}) + if msg, ok := matchError(err, codes.DeadlineExceeded, ""); !ok { + t.Error(msg) + } +} + +// Test TransactionRunner. Test that transactions are aborted and retried as expected. +func TestTransactionRunner(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + client, _, cleanup := prepare(ctx, t, singerDBStatements) + defer cleanup() + + // Test 1: User error should abort the transaction. + _, _ = client.ReadWriteTransaction(ctx, func(ctx context.Context, tx *ReadWriteTransaction) error { + tx.BufferWrite([]*Mutation{ + Insert("Accounts", []string{"AccountId", "Nickname", "Balance"}, []interface{}{int64(1), "Foo", int64(50)})}) + return errors.New("user error") + }) + // Empty read. + rows, err := readAllTestTable(client.Single().Read(ctx, "Accounts", Key{1}, []string{"AccountId", "Nickname", "Balance"})) + if err != nil { + t.Fatal(err) + } + if got, want := len(rows), 0; got != want { + t.Errorf("Empty read, got %d, want %d.", got, want) + } + + // Test 2: Expect abort and retry. + // We run two ReadWriteTransactions concurrently and make txn1 abort txn2 by committing writes to the column txn2 have read, + // and expect the following read to abort and txn2 retries. + + // Set up two accounts + accounts := []*Mutation{ + Insert("Accounts", []string{"AccountId", "Balance"}, []interface{}{int64(1), int64(0)}), + Insert("Accounts", []string{"AccountId", "Balance"}, []interface{}{int64(2), int64(1)}), + } + if _, err := client.Apply(ctx, accounts, ApplyAtLeastOnce()); err != nil { + t.Fatal(err) + } + + var ( + cTxn1Start = make(chan struct{}) + cTxn1Commit = make(chan struct{}) + cTxn2Start = make(chan struct{}) + wg sync.WaitGroup + ) + + // read balance, check error if we don't expect abort. + readBalance := func(tx interface { + ReadRow(ctx context.Context, table string, key Key, columns []string) (*Row, error) + }, key int64, expectAbort bool) (int64, error) { + var b int64 + r, e := tx.ReadRow(ctx, "Accounts", Key{int64(key)}, []string{"Balance"}) + if e != nil { + if expectAbort && !isAbortErr(e) { + t.Errorf("ReadRow got %v, want Abort error.", e) + } + return b, e + } + if ce := r.Column(0, &b); ce != nil { + return b, ce + } + return b, nil + } + + wg.Add(2) + // Txn 1 + go func() { + defer wg.Done() + var once sync.Once + _, e := client.ReadWriteTransaction(ctx, func(ctx context.Context, tx *ReadWriteTransaction) error { + b, e := readBalance(tx, 1, false) + if e != nil { + return e + } + // txn 1 can abort, in that case we skip closing the channel on retry. + once.Do(func() { close(cTxn1Start) }) + e = tx.BufferWrite([]*Mutation{ + Update("Accounts", []string{"AccountId", "Balance"}, []interface{}{int64(1), int64(b + 1)})}) + if e != nil { + return e + } + // Wait for second transaction. + <-cTxn2Start + return nil + }) + close(cTxn1Commit) + if e != nil { + t.Errorf("Transaction 1 commit, got %v, want nil.", e) + } + }() + // Txn 2 + go func() { + // Wait until txn 1 starts. + <-cTxn1Start + defer wg.Done() + var ( + once sync.Once + b1 int64 + b2 int64 + e error + ) + _, e = client.ReadWriteTransaction(ctx, func(ctx context.Context, tx *ReadWriteTransaction) error { + if b1, e = readBalance(tx, 1, false); e != nil { + return e + } + // Skip closing channel on retry. + once.Do(func() { close(cTxn2Start) }) + // Wait until txn 1 successfully commits. + <-cTxn1Commit + // Txn1 has committed and written a balance to the account. + // Now this transaction (txn2) reads and re-writes the balance. + // The first time through, it will abort because it overlaps with txn1. + // Then it will retry after txn1 commits, and succeed. + if b2, e = readBalance(tx, 2, true); e != nil { + return e + } + return tx.BufferWrite([]*Mutation{ + Update("Accounts", []string{"AccountId", "Balance"}, []interface{}{int64(2), int64(b1 + b2)})}) + }) + if e != nil { + t.Errorf("Transaction 2 commit, got %v, want nil.", e) + } + }() + wg.Wait() + // Check that both transactions' effects are visible. + for i := int64(1); i <= int64(2); i++ { + if b, e := readBalance(client.Single(), i, false); e != nil { + t.Fatalf("ReadBalance for key %d error %v.", i, e) + } else if b != i { + t.Errorf("Balance for key %d, got %d, want %d.", i, b, i) + } + } +} + +// Test PartitionQuery of BatchReadOnlyTransaction, create partitions then +// serialize and deserialize both transaction and partition to be used in +// execution on another client, and compare results. +func TestBatchQuery(t *testing.T) { + // Set up testing environment. + var ( + client2 *Client + err error + ) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + client, dbPath, cleanup := prepare(ctx, t, simpleDBStatements) + defer cleanup() + + if err = populate(ctx, client); err != nil { + t.Fatal(err) + } + if client2, err = createClient(ctx, dbPath); err != nil { + t.Fatal(err) + } + defer client2.Close() + + // PartitionQuery + var ( + txn *BatchReadOnlyTransaction + partitions []*Partition + stmt = Statement{SQL: "SELECT * FROM test;"} + ) + + if txn, err = client.BatchReadOnlyTransaction(ctx, StrongRead()); err != nil { + t.Fatal(err) + } + defer txn.Cleanup(ctx) + if partitions, err = txn.PartitionQuery(ctx, stmt, PartitionOptions{0, 3}); err != nil { + t.Fatal(err) + } + + // Reconstruct BatchReadOnlyTransactionID and execute partitions + var ( + tid2 BatchReadOnlyTransactionID + data []byte + gotResult bool // if we get matching result from two separate txns + ) + if data, err = txn.ID.MarshalBinary(); err != nil { + t.Fatalf("encoding failed %v", err) + } + if err = tid2.UnmarshalBinary(data); err != nil { + t.Fatalf("decoding failed %v", err) + } + txn2 := client2.BatchReadOnlyTransactionFromID(tid2) + + // Execute Partitions and compare results + for i, p := range partitions { + iter := txn.Execute(ctx, p) + defer iter.Stop() + p2 := serdesPartition(t, i, p) + iter2 := txn2.Execute(ctx, &p2) + defer iter2.Stop() + + row1, err1 := iter.Next() + row2, err2 := iter2.Next() + if err1 != err2 { + t.Fatalf("execution failed for different reasons: %v, %v", err1, err2) + continue + } + if !testEqual(row1, row2) { + t.Fatalf("execution returned different values: %v, %v", row1, row2) + continue + } + if row1 == nil { + continue + } + var a, b string + if err = row1.Columns(&a, &b); err != nil { + t.Fatalf("failed to parse row %v", err) + continue + } + if a == str1 && b == str2 { + gotResult = true + } + } + if !gotResult { + t.Fatalf("execution didn't return expected values") + } +} + +// Test PartitionRead of BatchReadOnlyTransaction, similar to TestBatchQuery +func TestBatchRead(t *testing.T) { + // Set up testing environment. + var ( + client2 *Client + err error + ) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + client, dbPath, cleanup := prepare(ctx, t, simpleDBStatements) + defer cleanup() + + if err = populate(ctx, client); err != nil { + t.Fatal(err) + } + if client2, err = createClient(ctx, dbPath); err != nil { + t.Fatal(err) + } + defer client2.Close() + + // PartitionRead + var ( + txn *BatchReadOnlyTransaction + partitions []*Partition + ) + + if txn, err = client.BatchReadOnlyTransaction(ctx, StrongRead()); err != nil { + t.Fatal(err) + } + defer txn.Cleanup(ctx) + if partitions, err = txn.PartitionRead(ctx, "test", AllKeys(), simpleDBTableColumns, PartitionOptions{0, 3}); err != nil { + t.Fatal(err) + } + + // Reconstruct BatchReadOnlyTransactionID and execute partitions + var ( + tid2 BatchReadOnlyTransactionID + data []byte + gotResult bool // if we get matching result from two separate txns + ) + if data, err = txn.ID.MarshalBinary(); err != nil { + t.Fatalf("encoding failed %v", err) + } + if err = tid2.UnmarshalBinary(data); err != nil { + t.Fatalf("decoding failed %v", err) + } + txn2 := client2.BatchReadOnlyTransactionFromID(tid2) + + // Execute Partitions and compare results + for i, p := range partitions { + iter := txn.Execute(ctx, p) + defer iter.Stop() + p2 := serdesPartition(t, i, p) + iter2 := txn2.Execute(ctx, &p2) + defer iter2.Stop() + + row1, err1 := iter.Next() + row2, err2 := iter2.Next() + if err1 != err2 { + t.Fatalf("execution failed for different reasons: %v, %v", err1, err2) + continue + } + if !testEqual(row1, row2) { + t.Fatalf("execution returned different values: %v, %v", row1, row2) + continue + } + if row1 == nil { + continue + } + var a, b string + if err = row1.Columns(&a, &b); err != nil { + t.Fatalf("failed to parse row %v", err) + continue + } + if a == str1 && b == str2 { + gotResult = true + } + } + if !gotResult { + t.Fatalf("execution didn't return expected values") + } +} + +// Test normal txReadEnv method on BatchReadOnlyTransaction. +func TestBROTNormal(t *testing.T) { + // Set up testing environment and create txn. + var ( + txn *BatchReadOnlyTransaction + err error + row *Row + i int64 + ) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + client, _, cleanup := prepare(ctx, t, simpleDBStatements) + defer cleanup() + + if txn, err = client.BatchReadOnlyTransaction(ctx, StrongRead()); err != nil { + t.Fatal(err) + } + defer txn.Cleanup(ctx) + if _, err := txn.PartitionRead(ctx, "test", AllKeys(), simpleDBTableColumns, PartitionOptions{0, 3}); err != nil { + t.Fatal(err) + } + // Normal query should work with BatchReadOnlyTransaction + stmt2 := Statement{SQL: "SELECT 1"} + iter := txn.Query(ctx, stmt2) + defer iter.Stop() + + row, err = iter.Next() + if err != nil { + t.Errorf("query failed with %v", err) + } + if err = row.Columns(&i); err != nil { + t.Errorf("failed to parse row %v", err) + } +} + +func TestCommitTimestamp(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + client, _, cleanup := prepare(ctx, t, ctsDBStatements) + defer cleanup() + + type testTableRow struct { + Key string + Ts NullTime + } + + var ( + cts1, cts2, ts1, ts2 time.Time + err error + ) + + // Apply mutation in sequence, expect to see commit timestamp in good order, check also the commit timestamp returned + for _, it := range []struct { + k string + t *time.Time + }{ + {"a", &cts1}, + {"b", &cts2}, + } { + tt := testTableRow{Key: it.k, Ts: NullTime{CommitTimestamp, true}} + m, err := InsertStruct("TestTable", tt) + if err != nil { + t.Fatal(err) + } + *it.t, err = client.Apply(ctx, []*Mutation{m}, ApplyAtLeastOnce()) + if err != nil { + t.Fatal(err) + } + } + + txn := client.ReadOnlyTransaction() + for _, it := range []struct { + k string + t *time.Time + }{ + {"a", &ts1}, + {"b", &ts2}, + } { + if r, e := txn.ReadRow(ctx, "TestTable", Key{it.k}, []string{"Ts"}); e != nil { + t.Fatal(err) + } else { + var got testTableRow + if err := r.ToStruct(&got); err != nil { + t.Fatal(err) + } + *it.t = got.Ts.Time + } + } + if !cts1.Equal(ts1) { + t.Errorf("Expect commit timestamp returned and read to match for txn1, got %v and %v.", cts1, ts1) + } + if !cts2.Equal(ts2) { + t.Errorf("Expect commit timestamp returned and read to match for txn2, got %v and %v.", cts2, ts2) + } + + // Try writing a timestamp in the future to commit timestamp, expect error + _, err = client.Apply(ctx, []*Mutation{InsertOrUpdate("TestTable", []string{"Key", "Ts"}, []interface{}{"a", time.Now().Add(time.Hour)})}, ApplyAtLeastOnce()) + if msg, ok := matchError(err, codes.FailedPrecondition, "Cannot write timestamps in the future"); !ok { + t.Error(msg) + } +} + +func TestDML(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + client, _, cleanup := prepare(ctx, t, singerDBStatements) + defer cleanup() + + // Function that reads a single row's first name from within a transaction. + readFirstName := func(tx *ReadWriteTransaction, key int) (string, error) { + row, err := tx.ReadRow(ctx, "Singers", Key{key}, []string{"FirstName"}) + if err != nil { + return "", err + } + var fn string + if err := row.Column(0, &fn); err != nil { + return "", err + } + return fn, nil + } + + // Function that reads multiple rows' first names from outside a read/write transaction. + readFirstNames := func(keys ...int) []string { + var ks []KeySet + for _, k := range keys { + ks = append(ks, Key{k}) + } + iter := client.Single().Read(ctx, "Singers", KeySets(ks...), []string{"FirstName"}) + var got []string + var fn string + err := iter.Do(func(row *Row) error { + if err := row.Column(0, &fn); err != nil { + return err + } + got = append(got, fn) + return nil + }) + if err != nil { + t.Fatalf("readFirstNames(%v): %v", keys, err) + } + return got + } + + // Use ReadWriteTransaction.Query to execute a DML statement. + _, err := client.ReadWriteTransaction(ctx, func(ctx context.Context, tx *ReadWriteTransaction) error { + iter := tx.Query(ctx, Statement{ + SQL: `INSERT INTO Singers (SingerId, FirstName, LastName) VALUES (1, "Umm", "Kulthum")`, + }) + defer iter.Stop() + if row, err := iter.Next(); err != iterator.Done { + t.Fatalf("got results from iterator, want none: %#v, err = %v\n", row, err) + } + if iter.RowCount != 1 { + t.Errorf("row count: got %d, want 1", iter.RowCount) + } + // The results of the DML statement should be visible to the transaction. + got, err := readFirstName(tx, 1) + if err != nil { + return err + } + if want := "Umm"; got != want { + t.Errorf("got %q, want %q", got, want) + } + return nil + }) + if err != nil { + t.Fatal(err) + } + + // Use ReadWriteTransaction.Update to execute a DML statement. + _, err = client.ReadWriteTransaction(ctx, func(ctx context.Context, tx *ReadWriteTransaction) error { + count, err := tx.Update(ctx, Statement{ + SQL: `Insert INTO Singers (SingerId, FirstName, LastName) VALUES (2, "Eduard", "Khil")`, + }) + if err != nil { + t.Fatal(err) + } + if count != 1 { + t.Errorf("row count: got %d, want 1", count) + } + got, err := readFirstName(tx, 2) + if err != nil { + return err + } + if want := "Eduard"; got != want { + t.Errorf("got %q, want %q", got, want) + } + return nil + + }) + if err != nil { + t.Fatal(err) + } + + // Roll back a DML statement and confirm that it didn't happen. + var fail = errors.New("fail") + _, err = client.ReadWriteTransaction(ctx, func(ctx context.Context, tx *ReadWriteTransaction) error { + _, err := tx.Update(ctx, Statement{ + SQL: `INSERT INTO Singers (SingerId, FirstName, LastName) VALUES (3, "Audra", "McDonald")`, + }) + if err != nil { + return err + } + return fail + }) + if err != fail { + t.Fatalf("rolling back: got error %v, want the error 'fail'", err) + } + _, err = client.Single().ReadRow(ctx, "Singers", Key{3}, []string{"FirstName"}) + if got, want := ErrCode(err), codes.NotFound; got != want { + t.Errorf("got %s, want %s", got, want) + } + + // Run two DML statements in the same transaction. + _, err = client.ReadWriteTransaction(ctx, func(ctx context.Context, tx *ReadWriteTransaction) error { + _, err := tx.Update(ctx, Statement{SQL: `UPDATE Singers SET FirstName = "Oum" WHERE SingerId = 1`}) + if err != nil { + return err + } + _, err = tx.Update(ctx, Statement{SQL: `UPDATE Singers SET FirstName = "Eddie" WHERE SingerId = 2`}) + if err != nil { + return err + } + return nil + }) + if err != nil { + t.Fatal(err) + } + got := readFirstNames(1, 2) + want := []string{"Oum", "Eddie"} + if !testEqual(got, want) { + t.Errorf("got %v, want %v", got, want) + } + + // Run a DML statement and an ordinary mutation in the same transaction. + _, err = client.ReadWriteTransaction(ctx, func(ctx context.Context, tx *ReadWriteTransaction) error { + _, err := tx.Update(ctx, Statement{ + SQL: `INSERT INTO Singers (SingerId, FirstName, LastName) VALUES (3, "Audra", "McDonald")`, + }) + if err != nil { + return err + } + tx.BufferWrite([]*Mutation{ + Insert("Singers", []string{"SingerId", "FirstName", "LastName"}, + []interface{}{4, "Andy", "Irvine"}), + }) + return nil + }) + if err != nil { + t.Fatal(err) + } + got = readFirstNames(3, 4) + want = []string{"Audra", "Andy"} + if !testEqual(got, want) { + t.Errorf("got %v, want %v", got, want) + } + + // Attempt to run a query using update. + _, err = client.ReadWriteTransaction(ctx, func(ctx context.Context, tx *ReadWriteTransaction) error { + _, err := tx.Update(ctx, Statement{SQL: `SELECT FirstName from Singers`}) + return err + }) + if got, want := ErrCode(err), codes.InvalidArgument; got != want { + t.Errorf("got %s, want %s", got, want) + } +} + +func TestPDML(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + client, _, cleanup := prepare(ctx, t, singerDBStatements) + defer cleanup() + + columns := []string{"SingerId", "FirstName", "LastName"} + + // Populate the Singers table. + var muts []*Mutation + for _, row := range [][]interface{}{ + {1, "Umm", "Kulthum"}, + {2, "Eduard", "Khil"}, + {3, "Audra", "McDonald"}, + } { + muts = append(muts, Insert("Singers", columns, row)) + } + if _, err := client.Apply(ctx, muts); err != nil { + t.Fatal(err) + } + // Identifiers in PDML statements must be fully qualified. + // TODO(jba): revisit the above. + count, err := client.PartitionedUpdate(ctx, Statement{ + SQL: `UPDATE Singers SET Singers.FirstName = "changed" WHERE Singers.SingerId >= 1 AND Singers.SingerId <= 3`, + }) + if err != nil { + t.Fatal(err) + } + if want := int64(3); count != want { + t.Errorf("got %d, want %d", count, want) + } + got, err := readAll(client.Single().Read(ctx, "Singers", AllKeys(), columns)) + if err != nil { + t.Fatal(err) + } + want := [][]interface{}{ + {int64(1), "changed", "Kulthum"}, + {int64(2), "changed", "Khil"}, + {int64(3), "changed", "McDonald"}, + } + if !testEqual(got, want) { + t.Errorf("\ngot %v\nwant%v", got, want) + } +} + +// Prepare initializes Cloud Spanner testing DB and clients. +func prepare(ctx context.Context, t *testing.T, statements []string) (*Client, string, func()) { + if admin == nil { + t.Skip("Integration tests skipped") + } + // Construct a unique test DB name. + dbName := dbNameSpace.New() + + dbPath := fmt.Sprintf("projects/%v/instances/%v/databases/%v", testProjectID, testInstanceID, dbName) + // Create database and tables. + op, err := admin.CreateDatabase(ctx, &adminpb.CreateDatabaseRequest{ + Parent: fmt.Sprintf("projects/%v/instances/%v", testProjectID, testInstanceID), + CreateStatement: "CREATE DATABASE " + dbName, + ExtraStatements: statements, + }) + if err != nil { + t.Fatalf("cannot create testing DB %v: %v", dbPath, err) + } + if _, err := op.Wait(ctx); err != nil { + t.Fatalf("cannot create testing DB %v: %v", dbPath, err) + } + client, err := createClient(ctx, dbPath) + if err != nil { + t.Fatalf("cannot create data client on DB %v: %v", dbPath, err) + } + return client, dbPath, func() { + client.Close() + if err := admin.DropDatabase(ctx, &adminpb.DropDatabaseRequest{Database: dbPath}); err != nil { + t.Logf("failed to drop database %s (error %v), might need a manual removal", + dbPath, err) + } + } +} + +func cleanupDatabases() { + if admin == nil { + // Integration tests skipped. + return + } + + ctx := context.Background() + dbsParent := fmt.Sprintf("projects/%v/instances/%v", testProjectID, testInstanceID) + dbsIter := admin.ListDatabases(ctx, &adminpb.ListDatabasesRequest{Parent: dbsParent}) + expireAge := 24 * time.Hour + + for { + db, err := dbsIter.Next() + if err == iterator.Done { + break + } + if err != nil { + panic(err) + } + // TODO(deklerk) When we have the ability to programmatically create + // instances, we can create an instance with uid.New and delete all + // tables in it. For now, we rely on matching prefixes. + if dbNameSpace.Older(db.Name, expireAge) { + log.Printf("Dropping database %s", db.Name) + + if err := admin.DropDatabase(ctx, &adminpb.DropDatabaseRequest{Database: db.Name}); err != nil { + log.Printf("failed to drop database %s (error %v), might need a manual removal", + db.Name, err) + } + } + } +} + +func rangeReads(ctx context.Context, t *testing.T, client *Client) { + checkRange := func(ks KeySet, wantNums ...int) { + if msg, ok := compareRows(client.Single().Read(ctx, testTable, ks, testTableColumns), wantNums); !ok { + t.Errorf("key set %+v: %s", ks, msg) + } + } + + checkRange(Key{"k1"}, 1) + checkRange(KeyRange{Key{"k3"}, Key{"k5"}, ClosedOpen}, 3, 4) + checkRange(KeyRange{Key{"k3"}, Key{"k5"}, ClosedClosed}, 3, 4, 5) + checkRange(KeyRange{Key{"k3"}, Key{"k5"}, OpenClosed}, 4, 5) + checkRange(KeyRange{Key{"k3"}, Key{"k5"}, OpenOpen}, 4) + + // Partial key specification. + checkRange(KeyRange{Key{"k7"}, Key{}, ClosedClosed}, 7, 8, 9) + checkRange(KeyRange{Key{"k7"}, Key{}, OpenClosed}, 8, 9) + checkRange(KeyRange{Key{}, Key{"k11"}, ClosedOpen}, 0, 1, 10) + checkRange(KeyRange{Key{}, Key{"k11"}, ClosedClosed}, 0, 1, 10, 11) + + // The following produce empty ranges. + // TODO(jba): Consider a multi-part key to illustrate partial key behavior. + // checkRange(KeyRange{Key{"k7"}, Key{}, ClosedOpen}) + // checkRange(KeyRange{Key{"k7"}, Key{}, OpenOpen}) + // checkRange(KeyRange{Key{}, Key{"k11"}, OpenOpen}) + // checkRange(KeyRange{Key{}, Key{"k11"}, OpenClosed}) + + // Prefix is component-wise, not string prefix. + checkRange(Key{"k1"}.AsPrefix(), 1) + checkRange(KeyRange{Key{"k1"}, Key{"k2"}, ClosedOpen}, 1, 10, 11, 12, 13, 14) + + checkRange(AllKeys(), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) +} + +func indexRangeReads(ctx context.Context, t *testing.T, client *Client) { + checkRange := func(ks KeySet, wantNums ...int) { + if msg, ok := compareRows(client.Single().ReadUsingIndex(ctx, testTable, testTableIndex, ks, testTableColumns), + wantNums); !ok { + t.Errorf("key set %+v: %s", ks, msg) + } + } + + checkRange(Key{"v1"}, 1) + checkRange(KeyRange{Key{"v3"}, Key{"v5"}, ClosedOpen}, 3, 4) + checkRange(KeyRange{Key{"v3"}, Key{"v5"}, ClosedClosed}, 3, 4, 5) + checkRange(KeyRange{Key{"v3"}, Key{"v5"}, OpenClosed}, 4, 5) + checkRange(KeyRange{Key{"v3"}, Key{"v5"}, OpenOpen}, 4) + + // // Partial key specification. + checkRange(KeyRange{Key{"v7"}, Key{}, ClosedClosed}, 7, 8, 9) + checkRange(KeyRange{Key{"v7"}, Key{}, OpenClosed}, 8, 9) + checkRange(KeyRange{Key{}, Key{"v11"}, ClosedOpen}, 0, 1, 10) + checkRange(KeyRange{Key{}, Key{"v11"}, ClosedClosed}, 0, 1, 10, 11) + + // // The following produce empty ranges. + // checkRange(KeyRange{Key{"v7"}, Key{}, ClosedOpen}) + // checkRange(KeyRange{Key{"v7"}, Key{}, OpenOpen}) + // checkRange(KeyRange{Key{}, Key{"v11"}, OpenOpen}) + // checkRange(KeyRange{Key{}, Key{"v11"}, OpenClosed}) + + // // Prefix is component-wise, not string prefix. + checkRange(Key{"v1"}.AsPrefix(), 1) + checkRange(KeyRange{Key{"v1"}, Key{"v2"}, ClosedOpen}, 1, 10, 11, 12, 13, 14) + checkRange(AllKeys(), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) + + // Read from an index with DESC ordering. + wantNums := []int{14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0} + if msg, ok := compareRows(client.Single().ReadUsingIndex(ctx, testTable, "TestTableByValueDesc", AllKeys(), testTableColumns), + wantNums); !ok { + t.Errorf("desc: %s", msg) + } +} + +type testTableRow struct{ Key, StringValue string } + +func compareRows(iter *RowIterator, wantNums []int) (string, bool) { + rows, err := readAllTestTable(iter) + if err != nil { + return err.Error(), false + } + want := map[string]string{} + for _, n := range wantNums { + want[fmt.Sprintf("k%d", n)] = fmt.Sprintf("v%d", n) + } + got := map[string]string{} + for _, r := range rows { + got[r.Key] = r.StringValue + } + if !testEqual(got, want) { + return fmt.Sprintf("got %v, want %v", got, want), false + } + return "", true +} + +func isNaN(x interface{}) bool { + f, ok := x.(float64) + if !ok { + return false + } + return math.IsNaN(f) +} + +// createClient creates Cloud Spanner data client. +func createClient(ctx context.Context, dbPath string) (client *Client, err error) { + client, err = NewClientWithConfig(ctx, dbPath, ClientConfig{ + SessionPoolConfig: SessionPoolConfig{WriteSessions: 0.2}, + }, option.WithTokenSource(testutil.TokenSource(ctx, Scope)), option.WithEndpoint(endpoint)) + if err != nil { + return nil, fmt.Errorf("cannot create data client on DB %v: %v", dbPath, err) + } + return client, nil +} + +// populate prepares the database with some data. +func populate(ctx context.Context, client *Client) error { + // Populate data + var err error + m := InsertMap("test", map[string]interface{}{ + "a": str1, + "b": str2, + }) + _, err = client.Apply(ctx, []*Mutation{m}) + return err +} + +func matchError(got error, wantCode codes.Code, wantMsgPart string) (string, bool) { + if ErrCode(got) != wantCode || !strings.Contains(strings.ToLower(ErrDesc(got)), strings.ToLower(wantMsgPart)) { + return fmt.Sprintf("got error <%v>\n"+`want `, got, wantCode, wantMsgPart), false + } + return "", true +} + +func rowToValues(r *Row) ([]interface{}, error) { + var x int64 + var y, z string + if err := r.Column(0, &x); err != nil { + return nil, err + } + if err := r.Column(1, &y); err != nil { + return nil, err + } + if err := r.Column(2, &z); err != nil { + return nil, err + } + return []interface{}{x, y, z}, nil +} + +func readAll(iter *RowIterator) ([][]interface{}, error) { + defer iter.Stop() + var vals [][]interface{} + for { + row, err := iter.Next() + if err == iterator.Done { + return vals, nil + } + if err != nil { + return nil, err + } + v, err := rowToValues(row) + if err != nil { + return nil, err + } + vals = append(vals, v) + } +} + +func readAllTestTable(iter *RowIterator) ([]testTableRow, error) { + defer iter.Stop() + var vals []testTableRow + for { + row, err := iter.Next() + if err == iterator.Done { + return vals, nil + } + if err != nil { + return nil, err + } + var ttr testTableRow + if err := row.ToStruct(&ttr); err != nil { + return nil, err + } + vals = append(vals, ttr) + } +} diff --git a/vendor/cloud.google.com/go/spanner/internal/testutil/mockclient.go b/vendor/cloud.google.com/go/spanner/internal/testutil/mockclient.go new file mode 100644 index 00000000..c2d498af --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/internal/testutil/mockclient.go @@ -0,0 +1,381 @@ +/* +Copyright 2017 Google LLC + +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 testutil + +import ( + "context" + "errors" + "fmt" + "sync" + "testing" + "time" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/empty" + proto3 "github.com/golang/protobuf/ptypes/struct" + pbt "github.com/golang/protobuf/ptypes/timestamp" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// Action is a mocked RPC activity that MockCloudSpannerClient will take. +type Action struct { + Method string + Err error +} + +// MockCloudSpannerClient is a mock implementation of sppb.SpannerClient. +type MockCloudSpannerClient struct { + sppb.SpannerClient + + mu sync.Mutex + t *testing.T + // Live sessions on the client. + sessions map[string]bool + // Expected set of actions that will be executed by the client. + actions []Action + // Session ping history. + pings []string + // Injected error, will be returned by all APIs. + injErr map[string]error + // Client will not fail on any request. + nice bool + // Client will stall on any requests. + freezed chan struct{} +} + +// NewMockCloudSpannerClient creates new MockCloudSpannerClient instance. +func NewMockCloudSpannerClient(t *testing.T, acts ...Action) *MockCloudSpannerClient { + mc := &MockCloudSpannerClient{t: t, sessions: map[string]bool{}, injErr: map[string]error{}} + mc.SetActions(acts...) + // Produce a closed channel, so the default action of ready is to not block. + mc.Freeze() + mc.Unfreeze() + return mc +} + +// MakeNice makes this a nice mock which will not fail on any request. +func (m *MockCloudSpannerClient) MakeNice() { + m.mu.Lock() + defer m.mu.Unlock() + m.nice = true +} + +// MakeStrict makes this a strict mock which will fail on any unexpected request. +func (m *MockCloudSpannerClient) MakeStrict() { + m.mu.Lock() + defer m.mu.Unlock() + m.nice = false +} + +// InjectError injects a global error that will be returned by all calls to method +// regardless of the actions array. +func (m *MockCloudSpannerClient) InjectError(method string, err error) { + m.mu.Lock() + defer m.mu.Unlock() + m.injErr[method] = err +} + +// SetActions sets the new set of expected actions to MockCloudSpannerClient. +func (m *MockCloudSpannerClient) SetActions(acts ...Action) { + m.mu.Lock() + defer m.mu.Unlock() + m.actions = nil + for _, act := range acts { + m.actions = append(m.actions, act) + } +} + +// DumpPings dumps the ping history. +func (m *MockCloudSpannerClient) DumpPings() []string { + m.mu.Lock() + defer m.mu.Unlock() + return append([]string(nil), m.pings...) +} + +// DumpSessions dumps the internal session table. +func (m *MockCloudSpannerClient) DumpSessions() map[string]bool { + m.mu.Lock() + defer m.mu.Unlock() + st := map[string]bool{} + for s, v := range m.sessions { + st[s] = v + } + return st +} + +// CreateSession is a placeholder for SpannerClient.CreateSession. +func (m *MockCloudSpannerClient) CreateSession(c context.Context, r *sppb.CreateSessionRequest, opts ...grpc.CallOption) (*sppb.Session, error) { + m.ready() + m.mu.Lock() + defer m.mu.Unlock() + if err := m.injErr["CreateSession"]; err != nil { + return nil, err + } + s := &sppb.Session{} + if r.Database != "mockdb" { + // Reject other databases + return s, status.Errorf(codes.NotFound, fmt.Sprintf("database not found: %v", r.Database)) + } + // Generate & record session name. + s.Name = fmt.Sprintf("mockdb-%v", time.Now().UnixNano()) + m.sessions[s.Name] = true + return s, nil +} + +// GetSession is a placeholder for SpannerClient.GetSession. +func (m *MockCloudSpannerClient) GetSession(c context.Context, r *sppb.GetSessionRequest, opts ...grpc.CallOption) (*sppb.Session, error) { + m.ready() + m.mu.Lock() + defer m.mu.Unlock() + if err := m.injErr["GetSession"]; err != nil { + return nil, err + } + m.pings = append(m.pings, r.Name) + if _, ok := m.sessions[r.Name]; !ok { + return nil, status.Errorf(codes.NotFound, fmt.Sprintf("Session not found: %v", r.Name)) + } + return &sppb.Session{Name: r.Name}, nil +} + +// DeleteSession is a placeholder for SpannerClient.DeleteSession. +func (m *MockCloudSpannerClient) DeleteSession(c context.Context, r *sppb.DeleteSessionRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + m.ready() + m.mu.Lock() + defer m.mu.Unlock() + if err := m.injErr["DeleteSession"]; err != nil { + return nil, err + } + if _, ok := m.sessions[r.Name]; !ok { + // Session not found. + return &empty.Empty{}, status.Errorf(codes.NotFound, fmt.Sprintf("Session not found: %v", r.Name)) + } + // Delete session from in-memory table. + delete(m.sessions, r.Name) + return &empty.Empty{}, nil +} + +// ExecuteStreamingSql is a mock implementation of SpannerClient.ExecuteStreamingSql. +func (m *MockCloudSpannerClient) ExecuteStreamingSql(c context.Context, r *sppb.ExecuteSqlRequest, opts ...grpc.CallOption) (sppb.Spanner_ExecuteStreamingSqlClient, error) { + m.ready() + m.mu.Lock() + defer m.mu.Unlock() + act, err := m.expectAction("ExecuteStreamingSql") + if err != nil { + return nil, err + } + wantReq := &sppb.ExecuteSqlRequest{ + Session: "mocksession", + Transaction: &sppb.TransactionSelector{ + Selector: &sppb.TransactionSelector_SingleUse{ + SingleUse: &sppb.TransactionOptions{ + Mode: &sppb.TransactionOptions_ReadOnly_{ + ReadOnly: &sppb.TransactionOptions_ReadOnly{ + TimestampBound: &sppb.TransactionOptions_ReadOnly_Strong{ + Strong: true, + }, + ReturnReadTimestamp: false, + }, + }, + }, + }, + }, + Sql: "mockquery", + Params: &proto3.Struct{ + Fields: map[string]*proto3.Value{"var1": {Kind: &proto3.Value_StringValue{StringValue: "abc"}}}, + }, + ParamTypes: map[string]*sppb.Type{"var1": {Code: sppb.TypeCode_STRING}}, + } + if !proto.Equal(r, wantReq) { + return nil, fmt.Errorf("got query request: %v, want: %v", r, wantReq) + } + if act.Err != nil { + return nil, act.Err + } + return nil, errors.New("query never succeeds on mock client") +} + +// StreamingRead is a placeholder for SpannerClient.StreamingRead. +func (m *MockCloudSpannerClient) StreamingRead(c context.Context, r *sppb.ReadRequest, opts ...grpc.CallOption) (sppb.Spanner_StreamingReadClient, error) { + m.ready() + m.mu.Lock() + defer m.mu.Unlock() + act, err := m.expectAction("StreamingRead", "StreamingReadIndex") + if err != nil { + return nil, err + } + wantReq := &sppb.ReadRequest{ + Session: "mocksession", + Transaction: &sppb.TransactionSelector{ + Selector: &sppb.TransactionSelector_SingleUse{ + SingleUse: &sppb.TransactionOptions{ + Mode: &sppb.TransactionOptions_ReadOnly_{ + ReadOnly: &sppb.TransactionOptions_ReadOnly{ + TimestampBound: &sppb.TransactionOptions_ReadOnly_Strong{ + Strong: true, + }, + ReturnReadTimestamp: false, + }, + }, + }, + }, + }, + Table: "t_mock", + Columns: []string{"col1", "col2"}, + KeySet: &sppb.KeySet{ + Keys: []*proto3.ListValue{ + { + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "foo"}}, + }, + }, + }, + Ranges: []*sppb.KeyRange{}, + All: false, + }, + } + if act.Method == "StreamingIndexRead" { + wantReq.Index = "idx1" + } + if !proto.Equal(r, wantReq) { + return nil, fmt.Errorf("got query request: %v, want: %v", r, wantReq) + } + if act.Err != nil { + return nil, act.Err + } + return nil, errors.New("read never succeeds on mock client") +} + +// BeginTransaction is a placeholder for SpannerClient.BeginTransaction. +func (m *MockCloudSpannerClient) BeginTransaction(c context.Context, r *sppb.BeginTransactionRequest, opts ...grpc.CallOption) (*sppb.Transaction, error) { + m.ready() + m.mu.Lock() + defer m.mu.Unlock() + if !m.nice { + act, err := m.expectAction("BeginTransaction") + if err != nil { + return nil, err + } + if act.Err != nil { + return nil, act.Err + } + } + resp := &sppb.Transaction{Id: []byte("transaction-1")} + if _, ok := r.Options.Mode.(*sppb.TransactionOptions_ReadOnly_); ok { + resp.ReadTimestamp = &pbt.Timestamp{Seconds: 3, Nanos: 4} + } + return resp, nil +} + +// Commit is a placeholder for SpannerClient.Commit. +func (m *MockCloudSpannerClient) Commit(c context.Context, r *sppb.CommitRequest, opts ...grpc.CallOption) (*sppb.CommitResponse, error) { + m.ready() + m.mu.Lock() + defer m.mu.Unlock() + if !m.nice { + act, err := m.expectAction("Commit") + if err != nil { + return nil, err + } + if act.Err != nil { + return nil, act.Err + } + } + return &sppb.CommitResponse{CommitTimestamp: &pbt.Timestamp{Seconds: 1, Nanos: 2}}, nil +} + +// Rollback is a placeholder for SpannerClient.Rollback. +func (m *MockCloudSpannerClient) Rollback(c context.Context, r *sppb.RollbackRequest, opts ...grpc.CallOption) (*empty.Empty, error) { + m.ready() + m.mu.Lock() + defer m.mu.Unlock() + if !m.nice { + act, err := m.expectAction("Rollback") + if err != nil { + return nil, err + } + if act.Err != nil { + return nil, act.Err + } + } + return nil, nil +} + +// PartitionQuery is a placeholder for SpannerServer.PartitionQuery. +func (m *MockCloudSpannerClient) PartitionQuery(ctx context.Context, r *sppb.PartitionQueryRequest, opts ...grpc.CallOption) (*sppb.PartitionResponse, error) { + m.ready() + return nil, errors.New("Unimplemented") +} + +// PartitionRead is a placeholder for SpannerServer.PartitionRead. +func (m *MockCloudSpannerClient) PartitionRead(ctx context.Context, r *sppb.PartitionReadRequest, opts ...grpc.CallOption) (*sppb.PartitionResponse, error) { + m.ready() + return nil, errors.New("Unimplemented") +} + +func (m *MockCloudSpannerClient) expectAction(methods ...string) (Action, error) { + for _, me := range methods { + if err := m.injErr[me]; err != nil { + return Action{}, err + } + } + if len(m.actions) == 0 { + m.t.Fatalf("unexpected %v executed", methods) + } + act := m.actions[0] + m.actions = m.actions[1:] + for _, me := range methods { + if me == act.Method { + return act, nil + } + } + m.t.Fatalf("unexpected call of one of %v, want method %s", methods, act.Method) + return Action{}, nil +} + +// Freeze stalls all requests. +func (m *MockCloudSpannerClient) Freeze() { + m.mu.Lock() + defer m.mu.Unlock() + m.freezed = make(chan struct{}) +} + +// Unfreeze restores processing requests. +func (m *MockCloudSpannerClient) Unfreeze() { + m.mu.Lock() + defer m.mu.Unlock() + close(m.freezed) +} + +// CheckActionsConsumed checks that all actions have been consumed. +func (m *MockCloudSpannerClient) CheckActionsConsumed() { + if len(m.actions) != 0 { + m.t.Fatalf("unconsumed mock client actions: %v", m.actions) + } +} + +// ready checks conditions before executing requests +// TODO: add checks for injected errors, actions +func (m *MockCloudSpannerClient) ready() { + m.mu.Lock() + freezed := m.freezed + m.mu.Unlock() + // check if client should be freezed + <-freezed +} diff --git a/vendor/cloud.google.com/go/spanner/internal/testutil/mockserver.go b/vendor/cloud.google.com/go/spanner/internal/testutil/mockserver.go new file mode 100644 index 00000000..b5a6f5e5 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/internal/testutil/mockserver.go @@ -0,0 +1,265 @@ +/* +Copyright 2017 Google LLC + +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 testutil + +import ( + "context" + "encoding/binary" + "fmt" + "io" + "net" + "sync" + "testing" + "time" + + "github.com/golang/protobuf/ptypes/empty" + proto3 "github.com/golang/protobuf/ptypes/struct" + pbt "github.com/golang/protobuf/ptypes/timestamp" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var ( + // KvMeta is the Metadata for mocked KV table. + KvMeta = sppb.ResultSetMetadata{ + RowType: &sppb.StructType{ + Fields: []*sppb.StructType_Field{ + { + Name: "Key", + Type: &sppb.Type{Code: sppb.TypeCode_STRING}, + }, + { + Name: "Value", + Type: &sppb.Type{Code: sppb.TypeCode_STRING}, + }, + }, + }, + } +) + +// MockCtlMsg encapsulates PartialResultSet/error that might be sent to +// client +type MockCtlMsg struct { + // If ResumeToken == true, mock server will generate a row with + // resume token. + ResumeToken bool + // If Err != nil, mock server will return error in RPC response. + Err error +} + +// MockCloudSpanner is a mock implementation of SpannerServer interface. +// TODO: make MockCloudSpanner a full-fleged Cloud Spanner implementation. +type MockCloudSpanner struct { + sppb.SpannerServer + + s *grpc.Server + t *testing.T + addr string + msgs chan MockCtlMsg + readTs time.Time + + mu sync.Mutex + next int + nextSession int + sessions map[string]*sppb.Session +} + +// Addr returns the listening address of mock server. +func (m *MockCloudSpanner) Addr() string { + return m.addr +} + +// AddMsg generates a new mocked row which can be received by client. +func (m *MockCloudSpanner) AddMsg(err error, resumeToken bool) { + msg := MockCtlMsg{ + ResumeToken: resumeToken, + Err: err, + } + if err == io.EOF { + close(m.msgs) + } else { + m.msgs <- msg + } +} + +// Done signals an end to a mocked stream. +func (m *MockCloudSpanner) Done() { + close(m.msgs) +} + +// CreateSession is a placeholder for SpannerServer.CreateSession. +func (m *MockCloudSpanner) CreateSession(c context.Context, r *sppb.CreateSessionRequest) (*sppb.Session, error) { + m.mu.Lock() + defer m.mu.Unlock() + name := fmt.Sprintf("session-%d", m.nextSession) + m.nextSession++ + s := &sppb.Session{Name: name} + m.sessions[name] = s + return s, nil +} + +// GetSession is a placeholder for SpannerServer.GetSession. +func (m *MockCloudSpanner) GetSession(c context.Context, r *sppb.GetSessionRequest) (*sppb.Session, error) { + m.mu.Lock() + defer m.mu.Unlock() + if s, ok := m.sessions[r.Name]; ok { + return s, nil + } + return nil, status.Errorf(codes.NotFound, "not found") +} + +// DeleteSession is a placeholder for SpannerServer.DeleteSession. +func (m *MockCloudSpanner) DeleteSession(c context.Context, r *sppb.DeleteSessionRequest) (*empty.Empty, error) { + m.mu.Lock() + defer m.mu.Unlock() + delete(m.sessions, r.Name) + return &empty.Empty{}, nil +} + +// EncodeResumeToken return mock resume token encoding for an uint64 integer. +func EncodeResumeToken(t uint64) []byte { + rt := make([]byte, 16) + binary.PutUvarint(rt, t) + return rt +} + +// DecodeResumeToken decodes a mock resume token into an uint64 integer. +func DecodeResumeToken(t []byte) (uint64, error) { + s, n := binary.Uvarint(t) + if n <= 0 { + return 0, fmt.Errorf("invalid resume token: %v", t) + } + return s, nil +} + +// ExecuteStreamingSql is a mock implementation of SpannerServer.ExecuteStreamingSql. +func (m *MockCloudSpanner) ExecuteStreamingSql(r *sppb.ExecuteSqlRequest, s sppb.Spanner_ExecuteStreamingSqlServer) error { + switch r.Sql { + case "SELECT * from t_unavailable": + return status.Errorf(codes.Unavailable, "mock table unavailable") + + case "UPDATE t SET x = 2 WHERE x = 1": + err := s.Send(&sppb.PartialResultSet{ + Stats: &sppb.ResultSetStats{RowCount: &sppb.ResultSetStats_RowCountLowerBound{3}}, + }) + if err != nil { + panic(err) + } + return nil + + case "SELECT t.key key, t.value value FROM t_mock t": + if r.ResumeToken != nil { + s, err := DecodeResumeToken(r.ResumeToken) + if err != nil { + return err + } + m.mu.Lock() + m.next = int(s) + 1 + m.mu.Unlock() + } + for { + msg, more := <-m.msgs + if !more { + break + } + if msg.Err == nil { + var rt []byte + if msg.ResumeToken { + m.mu.Lock() + rt = EncodeResumeToken(uint64(m.next)) + m.mu.Unlock() + } + meta := KvMeta + meta.Transaction = &sppb.Transaction{ + ReadTimestamp: &pbt.Timestamp{ + Seconds: m.readTs.Unix(), + Nanos: int32(m.readTs.Nanosecond()), + }, + } + m.mu.Lock() + next := m.next + m.next++ + m.mu.Unlock() + err := s.Send(&sppb.PartialResultSet{ + Metadata: &meta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: fmt.Sprintf("foo-%02d", next)}}, + {Kind: &proto3.Value_StringValue{StringValue: fmt.Sprintf("bar-%02d", next)}}, + }, + ResumeToken: rt, + }) + if err != nil { + return err + } + continue + } + return msg.Err + } + return nil + default: + return fmt.Errorf("unsupported SQL: %v", r.Sql) + } +} + +// StreamingRead is a placeholder for SpannerServer.StreamingRead. +func (m *MockCloudSpanner) StreamingRead(r *sppb.ReadRequest, s sppb.Spanner_StreamingReadServer) error { + return s.Send(&sppb.PartialResultSet{}) +} + +// Serve runs a MockCloudSpanner listening on a random localhost address. +func (m *MockCloudSpanner) Serve() { + m.s = grpc.NewServer() + if m.addr == "" { + m.addr = "localhost:0" + } + lis, err := net.Listen("tcp", m.addr) + if err != nil { + m.t.Fatalf("Failed to listen: %v", err) + } + _, port, err := net.SplitHostPort(lis.Addr().String()) + if err != nil { + m.t.Fatalf("Failed to parse listener address: %v", err) + } + sppb.RegisterSpannerServer(m.s, m) + m.addr = "localhost:" + port + go m.s.Serve(lis) +} + +// BeginTransaction is a placeholder for SpannerServer.BeginTransaction. +func (m *MockCloudSpanner) BeginTransaction(_ context.Context, r *sppb.BeginTransactionRequest) (*sppb.Transaction, error) { + m.mu.Lock() + defer m.mu.Unlock() + return &sppb.Transaction{}, nil +} + +// Stop terminates MockCloudSpanner and closes the serving port. +func (m *MockCloudSpanner) Stop() { + m.s.Stop() +} + +// NewMockCloudSpanner creates a new MockCloudSpanner instance. +func NewMockCloudSpanner(t *testing.T, ts time.Time) *MockCloudSpanner { + mcs := &MockCloudSpanner{ + t: t, + msgs: make(chan MockCtlMsg, 1000), + readTs: ts, + sessions: map[string]*sppb.Session{}, + } + return mcs +} diff --git a/vendor/cloud.google.com/go/spanner/key.go b/vendor/cloud.google.com/go/spanner/key.go new file mode 100644 index 00000000..60344e75 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/key.go @@ -0,0 +1,397 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "bytes" + "fmt" + "time" + + "cloud.google.com/go/civil" + proto3 "github.com/golang/protobuf/ptypes/struct" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc/codes" +) + +// A Key can be either a Cloud Spanner row's primary key or a secondary index key. +// It is essentially an interface{} array, which represents a set of Cloud Spanner +// columns. A Key can be used as: +// +// - A primary key which uniquely identifies a Cloud Spanner row. +// - A secondary index key which maps to a set of Cloud Spanner rows indexed under it. +// - An endpoint of primary key/secondary index ranges; see the KeyRange type. +// +// Rows that are identified by the Key type are outputs of read operation or targets of +// delete operation in a mutation. Note that for Insert/Update/InsertOrUpdate/Update +// mutation types, although they don't require a primary key explicitly, the column list +// provided must contain enough columns that can comprise a primary key. +// +// Keys are easy to construct. For example, suppose you have a table with a +// primary key of username and product ID. To make a key for this table: +// +// key := spanner.Key{"john", 16} +// +// See the description of Row and Mutation types for how Go types are +// mapped to Cloud Spanner types. For convenience, Key type supports a wide range +// of Go types: +// - int, int8, int16, int32, int64, and NullInt64 are mapped to Cloud Spanner's INT64 type. +// - uint8, uint16 and uint32 are also mapped to Cloud Spanner's INT64 type. +// - float32, float64, NullFloat64 are mapped to Cloud Spanner's FLOAT64 type. +// - bool and NullBool are mapped to Cloud Spanner's BOOL type. +// - []byte is mapped to Cloud Spanner's BYTES type. +// - string and NullString are mapped to Cloud Spanner's STRING type. +// - time.Time and NullTime are mapped to Cloud Spanner's TIMESTAMP type. +// - civil.Date and NullDate are mapped to Cloud Spanner's DATE type. +type Key []interface{} + +// errInvdKeyPartType returns error for unsupported key part type. +func errInvdKeyPartType(part interface{}) error { + return spannerErrorf(codes.InvalidArgument, "key part has unsupported type %T", part) +} + +// keyPartValue converts a part of the Key (which is a valid Cloud Spanner type) +// into a proto3.Value. Used for encoding Key type into protobuf. +func keyPartValue(part interface{}) (pb *proto3.Value, err error) { + switch v := part.(type) { + case int: + pb, _, err = encodeValue(int64(v)) + case int8: + pb, _, err = encodeValue(int64(v)) + case int16: + pb, _, err = encodeValue(int64(v)) + case int32: + pb, _, err = encodeValue(int64(v)) + case uint8: + pb, _, err = encodeValue(int64(v)) + case uint16: + pb, _, err = encodeValue(int64(v)) + case uint32: + pb, _, err = encodeValue(int64(v)) + case float32: + pb, _, err = encodeValue(float64(v)) + case int64, float64, NullInt64, NullFloat64, bool, NullBool, []byte, string, NullString, time.Time, civil.Date, NullTime, NullDate: + pb, _, err = encodeValue(v) + default: + return nil, errInvdKeyPartType(v) + } + return pb, err +} + +// proto converts a spanner.Key into a proto3.ListValue. +func (key Key) proto() (*proto3.ListValue, error) { + lv := &proto3.ListValue{} + lv.Values = make([]*proto3.Value, 0, len(key)) + for _, part := range key { + v, err := keyPartValue(part) + if err != nil { + return nil, err + } + lv.Values = append(lv.Values, v) + } + return lv, nil +} + +// keySetProto lets a single Key act as a KeySet. +func (key Key) keySetProto() (*sppb.KeySet, error) { + kp, err := key.proto() + if err != nil { + return nil, err + } + return &sppb.KeySet{Keys: []*proto3.ListValue{kp}}, nil +} + +// String implements fmt.Stringer for Key. For string, []byte and NullString, it +// prints the uninterpreted bytes of their contents, leaving caller with the +// opportunity to escape the output. +func (key Key) String() string { + b := &bytes.Buffer{} + fmt.Fprint(b, "(") + for i, part := range []interface{}(key) { + if i != 0 { + fmt.Fprint(b, ",") + } + switch v := part.(type) { + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, float32, float64, bool: + // Use %v to print numeric types and bool. + fmt.Fprintf(b, "%v", v) + case string: + fmt.Fprintf(b, "%q", v) + case []byte: + if v != nil { + fmt.Fprintf(b, "%q", v) + } else { + fmt.Fprint(b, "") + } + case NullInt64, NullFloat64, NullBool, NullString, NullTime, NullDate: + // The above types implement fmt.Stringer. + fmt.Fprintf(b, "%s", v) + case civil.Date: + fmt.Fprintf(b, "%q", v) + case time.Time: + fmt.Fprintf(b, "%q", v.Format(time.RFC3339Nano)) + default: + fmt.Fprintf(b, "%v", v) + } + } + fmt.Fprint(b, ")") + return b.String() +} + +// AsPrefix returns a KeyRange for all keys where k is the prefix. +func (key Key) AsPrefix() KeyRange { + return KeyRange{ + Start: key, + End: key, + Kind: ClosedClosed, + } +} + +// KeyRangeKind describes the kind of interval represented by a KeyRange: +// whether it is open or closed on the left and right. +type KeyRangeKind int + +const ( + // ClosedOpen is closed on the left and open on the right: the Start + // key is included, the End key is excluded. + ClosedOpen KeyRangeKind = iota + + // ClosedClosed is closed on the left and the right: both keys are included. + ClosedClosed + + // OpenClosed is open on the left and closed on the right: the Start + // key is excluded, the End key is included. + OpenClosed + + // OpenOpen is open on the left and the right: neither key is included. + OpenOpen +) + +// A KeyRange represents a range of rows in a table or index. +// +// A range has a Start key and an End key. IncludeStart and IncludeEnd +// indicate whether the Start and End keys are included in the range. +// +// For example, consider the following table definition: +// +// CREATE TABLE UserEvents ( +// UserName STRING(MAX), +// EventDate STRING(10), +// ) PRIMARY KEY(UserName, EventDate); +// +// The following keys name rows in this table: +// +// spanner.Key{"Bob", "2014-09-23"} +// spanner.Key{"Alfred", "2015-06-12"} +// +// Since the UserEvents table's PRIMARY KEY clause names two columns, each +// UserEvents key has two elements; the first is the UserName, and the second +// is the EventDate. +// +// Key ranges with multiple components are interpreted lexicographically by +// component using the table or index key's declared sort order. For example, +// the following range returns all events for user "Bob" that occurred in the +// year 2015: +// +// spanner.KeyRange{ +// Start: spanner.Key{"Bob", "2015-01-01"}, +// End: spanner.Key{"Bob", "2015-12-31"}, +// Kind: ClosedClosed, +// } +// +// Start and end keys can omit trailing key components. This affects the +// inclusion and exclusion of rows that exactly match the provided key +// components: if IncludeStart is true, then rows that exactly match the +// provided components of the Start key are included; if IncludeStart is false +// then rows that exactly match are not included. IncludeEnd and End key +// behave in the same fashion. +// +// For example, the following range includes all events for "Bob" that occurred +// during and after the year 2000: +// +// spanner.KeyRange{ +// Start: spanner.Key{"Bob", "2000-01-01"}, +// End: spanner.Key{"Bob"}, +// Kind: ClosedClosed, +// } +// +// The next example retrieves all events for "Bob": +// +// spanner.Key{"Bob"}.AsPrefix() +// +// To retrieve events before the year 2000: +// +// spanner.KeyRange{ +// Start: spanner.Key{"Bob"}, +// End: spanner.Key{"Bob", "2000-01-01"}, +// Kind: ClosedOpen, +// } +// +// Although we specified a Kind for this KeyRange, we didn't need to, because +// the default is ClosedOpen. In later examples we'll omit Kind if it is +// ClosedOpen. +// +// The following range includes all rows in a table or under a +// index: +// +// spanner.AllKeys() +// +// This range returns all users whose UserName begins with any +// character from A to C: +// +// spanner.KeyRange{ +// Start: spanner.Key{"A"}, +// End: spanner.Key{"D"}, +// } +// +// This range returns all users whose UserName begins with B: +// +// spanner.KeyRange{ +// Start: spanner.Key{"B"}, +// End: spanner.Key{"C"}, +// } +// +// Key ranges honor column sort order. For example, suppose a table is defined +// as follows: +// +// CREATE TABLE DescendingSortedTable { +// Key INT64, +// ... +// ) PRIMARY KEY(Key DESC); +// +// The following range retrieves all rows with key values between 1 and 100 +// inclusive: +// +// spanner.KeyRange{ +// Start: spanner.Key{100}, +// End: spanner.Key{1}, +// Kind: ClosedClosed, +// } +// +// Note that 100 is passed as the start, and 1 is passed as the end, because +// Key is a descending column in the schema. +type KeyRange struct { + // Start specifies the left boundary of the key range; End specifies + // the right boundary of the key range. + Start, End Key + + // Kind describes whether the boundaries of the key range include + // their keys. + Kind KeyRangeKind +} + +// String implements fmt.Stringer for KeyRange type. +func (r KeyRange) String() string { + var left, right string + switch r.Kind { + case ClosedClosed: + left, right = "[", "]" + case ClosedOpen: + left, right = "[", ")" + case OpenClosed: + left, right = "(", "]" + case OpenOpen: + left, right = "(", ")" + default: + left, right = "?", "?" + } + return fmt.Sprintf("%s%s,%s%s", left, r.Start, r.End, right) +} + +// proto converts KeyRange into sppb.KeyRange. +func (r KeyRange) proto() (*sppb.KeyRange, error) { + var err error + var start, end *proto3.ListValue + pb := &sppb.KeyRange{} + if start, err = r.Start.proto(); err != nil { + return nil, err + } + if end, err = r.End.proto(); err != nil { + return nil, err + } + if r.Kind == ClosedClosed || r.Kind == ClosedOpen { + pb.StartKeyType = &sppb.KeyRange_StartClosed{StartClosed: start} + } else { + pb.StartKeyType = &sppb.KeyRange_StartOpen{StartOpen: start} + } + if r.Kind == ClosedClosed || r.Kind == OpenClosed { + pb.EndKeyType = &sppb.KeyRange_EndClosed{EndClosed: end} + } else { + pb.EndKeyType = &sppb.KeyRange_EndOpen{EndOpen: end} + } + return pb, nil +} + +// keySetProto lets a KeyRange act as a KeySet. +func (r KeyRange) keySetProto() (*sppb.KeySet, error) { + rp, err := r.proto() + if err != nil { + return nil, err + } + return &sppb.KeySet{Ranges: []*sppb.KeyRange{rp}}, nil +} + +// A KeySet defines a collection of Cloud Spanner keys and/or key ranges. All the +// keys are expected to be in the same table or index. The keys need not be sorted in +// any particular way. +// +// An individual Key can act as a KeySet, as can a KeyRange. Use the KeySets function +// to create a KeySet consisting of multiple Keys and KeyRanges. To obtain an empty +// KeySet, call KeySets with no arguments. +// +// If the same key is specified multiple times in the set (for example if two +// ranges, two keys, or a key and a range overlap), the Cloud Spanner backend behaves +// as if the key were only specified once. +type KeySet interface { + keySetProto() (*sppb.KeySet, error) +} + +// AllKeys returns a KeySet that represents all Keys of a table or a index. +func AllKeys() KeySet { + return all{} +} + +type all struct{} + +func (all) keySetProto() (*sppb.KeySet, error) { + return &sppb.KeySet{All: true}, nil +} + +// KeySets returns the union of the KeySets. If any of the KeySets is AllKeys, then +// the resulting KeySet will be equivalent to AllKeys. +func KeySets(keySets ...KeySet) KeySet { + u := make(union, len(keySets)) + copy(u, keySets) + return u +} + +type union []KeySet + +func (u union) keySetProto() (*sppb.KeySet, error) { + upb := &sppb.KeySet{} + for _, ks := range u { + pb, err := ks.keySetProto() + if err != nil { + return nil, err + } + if pb.All { + return pb, nil + } + upb.Keys = append(upb.Keys, pb.Keys...) + upb.Ranges = append(upb.Ranges, pb.Ranges...) + } + return upb, nil +} diff --git a/vendor/cloud.google.com/go/spanner/key_test.go b/vendor/cloud.google.com/go/spanner/key_test.go new file mode 100644 index 00000000..32b67b45 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/key_test.go @@ -0,0 +1,372 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "testing" + "time" + + "cloud.google.com/go/civil" + proto3 "github.com/golang/protobuf/ptypes/struct" + sppb "google.golang.org/genproto/googleapis/spanner/v1" +) + +// Test Key.String() and Key.proto(). +func TestKey(t *testing.T) { + tm, _ := time.Parse(time.RFC3339Nano, "2016-11-15T15:04:05.999999999Z") + dt, _ := civil.ParseDate("2016-11-15") + for _, test := range []struct { + k Key + wantProto *proto3.ListValue + wantStr string + }{ + { + k: Key{int(1)}, + wantProto: listValueProto(stringProto("1")), + wantStr: "(1)", + }, + { + k: Key{int8(1)}, + wantProto: listValueProto(stringProto("1")), + wantStr: "(1)", + }, + { + k: Key{int16(1)}, + wantProto: listValueProto(stringProto("1")), + wantStr: "(1)", + }, + { + k: Key{int32(1)}, + wantProto: listValueProto(stringProto("1")), + wantStr: "(1)", + }, + { + k: Key{int64(1)}, + wantProto: listValueProto(stringProto("1")), + wantStr: "(1)", + }, + { + k: Key{uint8(1)}, + wantProto: listValueProto(stringProto("1")), + wantStr: "(1)", + }, + { + k: Key{uint16(1)}, + wantProto: listValueProto(stringProto("1")), + wantStr: "(1)", + }, + { + k: Key{uint32(1)}, + wantProto: listValueProto(stringProto("1")), + wantStr: "(1)", + }, + { + k: Key{true}, + wantProto: listValueProto(boolProto(true)), + wantStr: "(true)", + }, + { + k: Key{float32(1.5)}, + wantProto: listValueProto(floatProto(1.5)), + wantStr: "(1.5)", + }, + { + k: Key{float64(1.5)}, + wantProto: listValueProto(floatProto(1.5)), + wantStr: "(1.5)", + }, + { + k: Key{"value"}, + wantProto: listValueProto(stringProto("value")), + wantStr: `("value")`, + }, + { + k: Key{[]byte(nil)}, + wantProto: listValueProto(nullProto()), + wantStr: "()", + }, + { + k: Key{[]byte{}}, + wantProto: listValueProto(stringProto("")), + wantStr: `("")`, + }, + { + k: Key{tm}, + wantProto: listValueProto(stringProto("2016-11-15T15:04:05.999999999Z")), + wantStr: `("2016-11-15T15:04:05.999999999Z")`, + }, + {k: Key{dt}, + wantProto: listValueProto(stringProto("2016-11-15")), + wantStr: `("2016-11-15")`, + }, + { + k: Key{[]byte("value")}, + wantProto: listValueProto(bytesProto([]byte("value"))), + wantStr: `("value")`, + }, + { + k: Key{NullInt64{1, true}}, + wantProto: listValueProto(stringProto("1")), + wantStr: "(1)", + }, + { + k: Key{NullInt64{2, false}}, + wantProto: listValueProto(nullProto()), + wantStr: "()", + }, + { + k: Key{NullFloat64{1.5, true}}, + wantProto: listValueProto(floatProto(1.5)), + wantStr: "(1.5)", + }, + { + k: Key{NullFloat64{2.0, false}}, + wantProto: listValueProto(nullProto()), + wantStr: "()", + }, + { + k: Key{NullBool{true, true}}, + wantProto: listValueProto(boolProto(true)), + wantStr: "(true)", + }, + { + k: Key{NullBool{true, false}}, + wantProto: listValueProto(nullProto()), + wantStr: "()", + }, + { + k: Key{NullString{"value", true}}, + wantProto: listValueProto(stringProto("value")), + wantStr: `("value")`, + }, + { + k: Key{NullString{"value", false}}, + wantProto: listValueProto(nullProto()), + wantStr: "()", + }, + { + k: Key{NullTime{tm, true}}, + wantProto: listValueProto(timeProto(tm)), + wantStr: `("2016-11-15T15:04:05.999999999Z")`, + }, + + { + k: Key{NullTime{time.Now(), false}}, + wantProto: listValueProto(nullProto()), + wantStr: "()", + }, + { + k: Key{NullDate{dt, true}}, + wantProto: listValueProto(dateProto(dt)), + wantStr: `("2016-11-15")`, + }, + { + k: Key{NullDate{civil.Date{}, false}}, + wantProto: listValueProto(nullProto()), + wantStr: "()", + }, + { + k: Key{int(1), NullString{"value", false}, "value", 1.5, true}, + wantProto: listValueProto(stringProto("1"), nullProto(), stringProto("value"), floatProto(1.5), boolProto(true)), + wantStr: `(1,,"value",1.5,true)`, + }, + } { + if got := test.k.String(); got != test.wantStr { + t.Errorf("%v.String() = %v, want %v", test.k, got, test.wantStr) + } + gotProto, err := test.k.proto() + if err != nil { + t.Errorf("%v.proto() returns error %v; want nil error", test.k, err) + } + if !testEqual(gotProto, test.wantProto) { + t.Errorf("%v.proto() = \n%v\nwant:\n%v", test.k, gotProto, test.wantProto) + } + } +} + +// Test KeyRange.String() and KeyRange.proto(). +func TestKeyRange(t *testing.T) { + for _, test := range []struct { + kr KeyRange + wantProto *sppb.KeyRange + wantStr string + }{ + { + kr: KeyRange{Key{"A"}, Key{"D"}, OpenOpen}, + wantProto: &sppb.KeyRange{ + StartKeyType: &sppb.KeyRange_StartOpen{StartOpen: listValueProto(stringProto("A"))}, + EndKeyType: &sppb.KeyRange_EndOpen{EndOpen: listValueProto(stringProto("D"))}, + }, + wantStr: `(("A"),("D"))`, + }, + { + kr: KeyRange{Key{1}, Key{10}, OpenClosed}, + wantProto: &sppb.KeyRange{ + StartKeyType: &sppb.KeyRange_StartOpen{StartOpen: listValueProto(stringProto("1"))}, + EndKeyType: &sppb.KeyRange_EndClosed{EndClosed: listValueProto(stringProto("10"))}, + }, + wantStr: "((1),(10)]", + }, + { + kr: KeyRange{Key{1.5, 2.1, 0.2}, Key{1.9, 0.7}, ClosedOpen}, + wantProto: &sppb.KeyRange{ + StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(floatProto(1.5), floatProto(2.1), floatProto(0.2))}, + EndKeyType: &sppb.KeyRange_EndOpen{EndOpen: listValueProto(floatProto(1.9), floatProto(0.7))}, + }, + wantStr: "[(1.5,2.1,0.2),(1.9,0.7))", + }, + { + kr: KeyRange{Key{NullInt64{1, true}}, Key{10}, ClosedClosed}, + wantProto: &sppb.KeyRange{ + StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(stringProto("1"))}, + EndKeyType: &sppb.KeyRange_EndClosed{EndClosed: listValueProto(stringProto("10"))}, + }, + wantStr: "[(1),(10)]", + }, + } { + if got := test.kr.String(); got != test.wantStr { + t.Errorf("%v.String() = %v, want %v", test.kr, got, test.wantStr) + } + gotProto, err := test.kr.proto() + if err != nil { + t.Errorf("%v.proto() returns error %v; want nil error", test.kr, err) + } + if !testEqual(gotProto, test.wantProto) { + t.Errorf("%v.proto() = \n%v\nwant:\n%v", test.kr, gotProto.String(), test.wantProto.String()) + } + } +} + +func TestPrefixRange(t *testing.T) { + got := Key{1}.AsPrefix() + want := KeyRange{Start: Key{1}, End: Key{1}, Kind: ClosedClosed} + if !testEqual(got, want) { + t.Errorf("got %v, want %v", got, want) + } +} + +func TestKeySets(t *testing.T) { + int1 := intProto(1) + int2 := intProto(2) + int3 := intProto(3) + int4 := intProto(4) + for i, test := range []struct { + ks KeySet + wantProto *sppb.KeySet + }{ + { + KeySets(), + &sppb.KeySet{}, + }, + { + Key{4}, + &sppb.KeySet{ + Keys: []*proto3.ListValue{listValueProto(int4)}, + }, + }, + { + AllKeys(), + &sppb.KeySet{All: true}, + }, + { + KeySets(Key{1, 2}, Key{3, 4}), + &sppb.KeySet{ + Keys: []*proto3.ListValue{ + listValueProto(int1, int2), + listValueProto(int3, int4), + }, + }, + }, + { + KeyRange{Key{1}, Key{2}, ClosedOpen}, + &sppb.KeySet{Ranges: []*sppb.KeyRange{ + { + StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(int1)}, + EndKeyType: &sppb.KeyRange_EndOpen{EndOpen: listValueProto(int2)}, + }, + }}, + }, + { + Key{2}.AsPrefix(), + &sppb.KeySet{Ranges: []*sppb.KeyRange{ + { + StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(int2)}, + EndKeyType: &sppb.KeyRange_EndClosed{EndClosed: listValueProto(int2)}, + }, + }}, + }, + { + KeySets( + KeyRange{Key{1}, Key{2}, ClosedClosed}, + KeyRange{Key{3}, Key{4}, OpenClosed}, + ), + &sppb.KeySet{ + Ranges: []*sppb.KeyRange{ + { + StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(int1)}, + EndKeyType: &sppb.KeyRange_EndClosed{EndClosed: listValueProto(int2)}, + }, + { + StartKeyType: &sppb.KeyRange_StartOpen{StartOpen: listValueProto(int3)}, + EndKeyType: &sppb.KeyRange_EndClosed{EndClosed: listValueProto(int4)}, + }, + }, + }, + }, + { + KeySets( + Key{1}, + KeyRange{Key{2}, Key{3}, ClosedClosed}, + KeyRange{Key{4}, Key{5}, OpenClosed}, + KeySets(), + Key{6}), + &sppb.KeySet{ + Keys: []*proto3.ListValue{ + listValueProto(int1), + listValueProto(intProto(6)), + }, + Ranges: []*sppb.KeyRange{ + { + StartKeyType: &sppb.KeyRange_StartClosed{StartClosed: listValueProto(int2)}, + EndKeyType: &sppb.KeyRange_EndClosed{EndClosed: listValueProto(int3)}, + }, + { + StartKeyType: &sppb.KeyRange_StartOpen{StartOpen: listValueProto(int4)}, + EndKeyType: &sppb.KeyRange_EndClosed{EndClosed: listValueProto(intProto(5))}, + }, + }, + }, + }, + { + KeySets( + Key{1}, + KeyRange{Key{2}, Key{3}, ClosedClosed}, + AllKeys(), + KeyRange{Key{4}, Key{5}, OpenClosed}, + Key{6}), + &sppb.KeySet{All: true}, + }, + } { + gotProto, err := test.ks.keySetProto() + if err != nil { + t.Errorf("#%d: %v.proto() returns error %v; want nil error", i, test.ks, err) + } + if !testEqual(gotProto, test.wantProto) { + t.Errorf("#%d: %v.proto() = \n%v\nwant:\n%v", i, test.ks, gotProto.String(), test.wantProto.String()) + } + } +} diff --git a/vendor/cloud.google.com/go/spanner/mutation.go b/vendor/cloud.google.com/go/spanner/mutation.go new file mode 100644 index 00000000..b2dbaf56 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/mutation.go @@ -0,0 +1,430 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "reflect" + + proto3 "github.com/golang/protobuf/ptypes/struct" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc/codes" +) + +// op is the mutation operation. +type op int + +const ( + // opDelete removes a row from a table. Succeeds whether or not the + // key was present. + opDelete op = iota + // opInsert inserts a row into a table. If the row already exists, the + // write or transaction fails. + opInsert + // opInsertOrUpdate inserts a row into a table. If the row already + // exists, it updates it instead. Any column values not explicitly + // written are preserved. + opInsertOrUpdate + // opReplace inserts a row into a table, deleting any existing row. + // Unlike InsertOrUpdate, this means any values not explicitly written + // become NULL. + opReplace + // opUpdate updates a row in a table. If the row does not already + // exist, the write or transaction fails. + opUpdate +) + +// A Mutation describes a modification to one or more Cloud Spanner rows. The +// mutation represents an insert, update, delete, etc on a table. +// +// Many mutations can be applied in a single atomic commit. For purposes of +// constraint checking (such as foreign key constraints), the operations can be +// viewed as applying in the same order as the mutations are provided (so that, e.g., +// a row and its logical "child" can be inserted in the same commit). +// +// The Apply function applies series of mutations. For example, +// +// m := spanner.Insert("User", +// []string{"user_id", "profile"}, +// []interface{}{UserID, profile}) +// _, err := client.Apply(ctx, []*spanner.Mutation{m}) +// +// inserts a new row into the User table. The primary key +// for the new row is UserID (presuming that "user_id" has been declared as the +// primary key of the "User" table). +// +// To apply a series of mutations as part of an atomic read-modify-write operation, +// use ReadWriteTransaction. +// +// Updating a row +// +// Changing the values of columns in an existing row is very similar to +// inserting a new row: +// +// m := spanner.Update("User", +// []string{"user_id", "profile"}, +// []interface{}{UserID, profile}) +// _, err := client.Apply(ctx, []*spanner.Mutation{m}) +// +// Deleting a row +// +// To delete a row, use spanner.Delete: +// +// m := spanner.Delete("User", spanner.Key{UserId}) +// _, err := client.Apply(ctx, []*spanner.Mutation{m}) +// +// spanner.Delete accepts a KeySet, so you can also pass in a KeyRange, or use the +// spanner.KeySets function to build any combination of Keys and KeyRanges. +// +// Note that deleting a row in a table may also delete rows from other tables +// if cascading deletes are specified in those tables' schemas. Delete does +// nothing if the named row does not exist (does not yield an error). +// +// Deleting a field +// +// To delete/clear a field within a row, use spanner.Update with the value nil: +// +// m := spanner.Update("User", +// []string{"user_id", "profile"}, +// []interface{}{UserID, nil}) +// _, err := client.Apply(ctx, []*spanner.Mutation{m}) +// +// The valid Go types and their corresponding Cloud Spanner types that can be +// used in the Insert/Update/InsertOrUpdate functions are: +// +// string, NullString - STRING +// []string, []NullString - STRING ARRAY +// []byte - BYTES +// [][]byte - BYTES ARRAY +// int, int64, NullInt64 - INT64 +// []int, []int64, []NullInt64 - INT64 ARRAY +// bool, NullBool - BOOL +// []bool, []NullBool - BOOL ARRAY +// float64, NullFloat64 - FLOAT64 +// []float64, []NullFloat64 - FLOAT64 ARRAY +// time.Time, NullTime - TIMESTAMP +// []time.Time, []NullTime - TIMESTAMP ARRAY +// Date, NullDate - DATE +// []Date, []NullDate - DATE ARRAY +// +// To compare two Mutations for testing purposes, use reflect.DeepEqual. +type Mutation struct { + // op is the operation type of the mutation. + // See documentation for spanner.op for more details. + op op + // Table is the name of the target table to be modified. + table string + // keySet is a set of primary keys that names the rows + // in a delete operation. + keySet KeySet + // columns names the set of columns that are going to be + // modified by Insert, InsertOrUpdate, Replace or Update + // operations. + columns []string + // values specifies the new values for the target columns + // named by Columns. + values []interface{} +} + +// mapToMutationParams converts Go map into mutation parameters. +func mapToMutationParams(in map[string]interface{}) ([]string, []interface{}) { + cols := []string{} + vals := []interface{}{} + for k, v := range in { + cols = append(cols, k) + vals = append(vals, v) + } + return cols, vals +} + +// errNotStruct returns error for not getting a go struct type. +func errNotStruct(in interface{}) error { + return spannerErrorf(codes.InvalidArgument, "%T is not a go struct type", in) +} + +// structToMutationParams converts Go struct into mutation parameters. +// If the input is not a valid Go struct type, structToMutationParams +// returns error. +func structToMutationParams(in interface{}) ([]string, []interface{}, error) { + if in == nil { + return nil, nil, errNotStruct(in) + } + v := reflect.ValueOf(in) + t := v.Type() + if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct { + // t is a pointer to a struct. + if v.IsNil() { + // Return empty results. + return nil, nil, nil + } + // Get the struct value that in points to. + v = v.Elem() + t = t.Elem() + } + if t.Kind() != reflect.Struct { + return nil, nil, errNotStruct(in) + } + fields, err := fieldCache.Fields(t) + if err != nil { + return nil, nil, toSpannerError(err) + } + var cols []string + var vals []interface{} + for _, f := range fields { + cols = append(cols, f.Name) + vals = append(vals, v.FieldByIndex(f.Index).Interface()) + } + return cols, vals, nil +} + +// Insert returns a Mutation to insert a row into a table. If the row already +// exists, the write or transaction fails. +func Insert(table string, cols []string, vals []interface{}) *Mutation { + return &Mutation{ + op: opInsert, + table: table, + columns: cols, + values: vals, + } +} + +// InsertMap returns a Mutation to insert a row into a table, specified by +// a map of column name to value. If the row already exists, the write or +// transaction fails. +func InsertMap(table string, in map[string]interface{}) *Mutation { + cols, vals := mapToMutationParams(in) + return Insert(table, cols, vals) +} + +// InsertStruct returns a Mutation to insert a row into a table, specified by +// a Go struct. If the row already exists, the write or transaction fails. +// +// The in argument must be a struct or a pointer to a struct. Its exported +// fields specify the column names and values. Use a field tag like "spanner:name" +// to provide an alternative column name, or use "spanner:-" to ignore the field. +func InsertStruct(table string, in interface{}) (*Mutation, error) { + cols, vals, err := structToMutationParams(in) + if err != nil { + return nil, err + } + return Insert(table, cols, vals), nil +} + +// Update returns a Mutation to update a row in a table. If the row does not +// already exist, the write or transaction fails. +func Update(table string, cols []string, vals []interface{}) *Mutation { + return &Mutation{ + op: opUpdate, + table: table, + columns: cols, + values: vals, + } +} + +// UpdateMap returns a Mutation to update a row in a table, specified by +// a map of column to value. If the row does not already exist, the write or +// transaction fails. +func UpdateMap(table string, in map[string]interface{}) *Mutation { + cols, vals := mapToMutationParams(in) + return Update(table, cols, vals) +} + +// UpdateStruct returns a Mutation to update a row in a table, specified by a Go +// struct. If the row does not already exist, the write or transaction fails. +func UpdateStruct(table string, in interface{}) (*Mutation, error) { + cols, vals, err := structToMutationParams(in) + if err != nil { + return nil, err + } + return Update(table, cols, vals), nil +} + +// InsertOrUpdate returns a Mutation to insert a row into a table. If the row +// already exists, it updates it instead. Any column values not explicitly +// written are preserved. +// +// For a similar example, See Update. +func InsertOrUpdate(table string, cols []string, vals []interface{}) *Mutation { + return &Mutation{ + op: opInsertOrUpdate, + table: table, + columns: cols, + values: vals, + } +} + +// InsertOrUpdateMap returns a Mutation to insert a row into a table, +// specified by a map of column to value. If the row already exists, it +// updates it instead. Any column values not explicitly written are preserved. +// +// For a similar example, See UpdateMap. +func InsertOrUpdateMap(table string, in map[string]interface{}) *Mutation { + cols, vals := mapToMutationParams(in) + return InsertOrUpdate(table, cols, vals) +} + +// InsertOrUpdateStruct returns a Mutation to insert a row into a table, +// specified by a Go struct. If the row already exists, it updates it instead. +// Any column values not explicitly written are preserved. +// +// The in argument must be a struct or a pointer to a struct. Its exported +// fields specify the column names and values. Use a field tag like "spanner:name" +// to provide an alternative column name, or use "spanner:-" to ignore the field. +// +// For a similar example, See UpdateStruct. +func InsertOrUpdateStruct(table string, in interface{}) (*Mutation, error) { + cols, vals, err := structToMutationParams(in) + if err != nil { + return nil, err + } + return InsertOrUpdate(table, cols, vals), nil +} + +// Replace returns a Mutation to insert a row into a table, deleting any +// existing row. Unlike InsertOrUpdate, this means any values not explicitly +// written become NULL. +// +// For a similar example, See Update. +func Replace(table string, cols []string, vals []interface{}) *Mutation { + return &Mutation{ + op: opReplace, + table: table, + columns: cols, + values: vals, + } +} + +// ReplaceMap returns a Mutation to insert a row into a table, deleting any +// existing row. Unlike InsertOrUpdateMap, this means any values not explicitly +// written become NULL. The row is specified by a map of column to value. +// +// For a similar example, See UpdateMap. +func ReplaceMap(table string, in map[string]interface{}) *Mutation { + cols, vals := mapToMutationParams(in) + return Replace(table, cols, vals) +} + +// ReplaceStruct returns a Mutation to insert a row into a table, deleting any +// existing row. Unlike InsertOrUpdateMap, this means any values not explicitly +// written become NULL. The row is specified by a Go struct. +// +// The in argument must be a struct or a pointer to a struct. Its exported +// fields specify the column names and values. Use a field tag like "spanner:name" +// to provide an alternative column name, or use "spanner:-" to ignore the field. +// +// For a similar example, See UpdateStruct. +func ReplaceStruct(table string, in interface{}) (*Mutation, error) { + cols, vals, err := structToMutationParams(in) + if err != nil { + return nil, err + } + return Replace(table, cols, vals), nil +} + +// Delete removes the rows described by the KeySet from the table. It succeeds +// whether or not the keys were present. +func Delete(table string, ks KeySet) *Mutation { + return &Mutation{ + op: opDelete, + table: table, + keySet: ks, + } +} + +// prepareWrite generates sppb.Mutation_Write from table name, column names +// and new column values. +func prepareWrite(table string, columns []string, vals []interface{}) (*sppb.Mutation_Write, error) { + v, err := encodeValueArray(vals) + if err != nil { + return nil, err + } + return &sppb.Mutation_Write{ + Table: table, + Columns: columns, + Values: []*proto3.ListValue{v}, + }, nil +} + +// errInvdMutationOp returns error for unrecognized mutation operation. +func errInvdMutationOp(m Mutation) error { + return spannerErrorf(codes.InvalidArgument, "Unknown op type: %d", m.op) +} + +// proto converts spanner.Mutation to sppb.Mutation, in preparation to send +// RPCs. +func (m Mutation) proto() (*sppb.Mutation, error) { + var pb *sppb.Mutation + switch m.op { + case opDelete: + var kp *sppb.KeySet + if m.keySet != nil { + var err error + kp, err = m.keySet.keySetProto() + if err != nil { + return nil, err + } + } + pb = &sppb.Mutation{ + Operation: &sppb.Mutation_Delete_{ + Delete: &sppb.Mutation_Delete{ + Table: m.table, + KeySet: kp, + }, + }, + } + case opInsert: + w, err := prepareWrite(m.table, m.columns, m.values) + if err != nil { + return nil, err + } + pb = &sppb.Mutation{Operation: &sppb.Mutation_Insert{Insert: w}} + case opInsertOrUpdate: + w, err := prepareWrite(m.table, m.columns, m.values) + if err != nil { + return nil, err + } + pb = &sppb.Mutation{Operation: &sppb.Mutation_InsertOrUpdate{InsertOrUpdate: w}} + case opReplace: + w, err := prepareWrite(m.table, m.columns, m.values) + if err != nil { + return nil, err + } + pb = &sppb.Mutation{Operation: &sppb.Mutation_Replace{Replace: w}} + case opUpdate: + w, err := prepareWrite(m.table, m.columns, m.values) + if err != nil { + return nil, err + } + pb = &sppb.Mutation{Operation: &sppb.Mutation_Update{Update: w}} + default: + return nil, errInvdMutationOp(m) + } + return pb, nil +} + +// mutationsProto turns a spanner.Mutation array into a sppb.Mutation array, +// it is convenient for sending batch mutations to Cloud Spanner. +func mutationsProto(ms []*Mutation) ([]*sppb.Mutation, error) { + l := make([]*sppb.Mutation, 0, len(ms)) + for _, m := range ms { + pb, err := m.proto() + if err != nil { + return nil, err + } + l = append(l, pb) + } + return l, nil +} diff --git a/vendor/cloud.google.com/go/spanner/mutation_test.go b/vendor/cloud.google.com/go/spanner/mutation_test.go new file mode 100644 index 00000000..afbcb326 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/mutation_test.go @@ -0,0 +1,570 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "sort" + "strings" + "testing" + + proto3 "github.com/golang/protobuf/ptypes/struct" + sppb "google.golang.org/genproto/googleapis/spanner/v1" +) + +// keysetProto returns protobuf encoding of valid spanner.KeySet. +func keysetProto(t *testing.T, ks KeySet) *sppb.KeySet { + k, err := ks.keySetProto() + if err != nil { + t.Fatalf("cannot convert keyset %v to protobuf: %v", ks, err) + } + return k +} + +// Test encoding from spanner.Mutation to protobuf. +func TestMutationToProto(t *testing.T) { + for i, test := range []struct { + m *Mutation + want *sppb.Mutation + }{ + // Delete Mutation + { + &Mutation{opDelete, "t_foo", Key{"foo"}, nil, nil}, + &sppb.Mutation{ + Operation: &sppb.Mutation_Delete_{ + Delete: &sppb.Mutation_Delete{ + Table: "t_foo", + KeySet: keysetProto(t, Key{"foo"}), + }, + }, + }, + }, + // Insert Mutation + { + &Mutation{opInsert, "t_foo", KeySets(), []string{"col1", "col2"}, []interface{}{int64(1), int64(2)}}, + &sppb.Mutation{ + Operation: &sppb.Mutation_Insert{ + Insert: &sppb.Mutation_Write{ + Table: "t_foo", + Columns: []string{"col1", "col2"}, + Values: []*proto3.ListValue{ + { + Values: []*proto3.Value{intProto(1), intProto(2)}, + }, + }, + }, + }, + }, + }, + // InsertOrUpdate Mutation + { + &Mutation{opInsertOrUpdate, "t_foo", KeySets(), []string{"col1", "col2"}, []interface{}{1.0, 2.0}}, + &sppb.Mutation{ + Operation: &sppb.Mutation_InsertOrUpdate{ + InsertOrUpdate: &sppb.Mutation_Write{ + Table: "t_foo", + Columns: []string{"col1", "col2"}, + Values: []*proto3.ListValue{ + { + Values: []*proto3.Value{floatProto(1.0), floatProto(2.0)}, + }, + }, + }, + }, + }, + }, + // Replace Mutation + { + &Mutation{opReplace, "t_foo", KeySets(), []string{"col1", "col2"}, []interface{}{"one", 2.0}}, + &sppb.Mutation{ + Operation: &sppb.Mutation_Replace{ + Replace: &sppb.Mutation_Write{ + Table: "t_foo", + Columns: []string{"col1", "col2"}, + Values: []*proto3.ListValue{ + { + Values: []*proto3.Value{stringProto("one"), floatProto(2.0)}, + }, + }, + }, + }, + }, + }, + // Update Mutation + { + &Mutation{opUpdate, "t_foo", KeySets(), []string{"col1", "col2"}, []interface{}{"one", []byte(nil)}}, + &sppb.Mutation{ + Operation: &sppb.Mutation_Update{ + Update: &sppb.Mutation_Write{ + Table: "t_foo", + Columns: []string{"col1", "col2"}, + Values: []*proto3.ListValue{ + { + Values: []*proto3.Value{stringProto("one"), nullProto()}, + }, + }, + }, + }, + }, + }, + } { + if got, err := test.m.proto(); err != nil || !testEqual(got, test.want) { + t.Errorf("%d: (%#v).proto() = (%v, %v), want (%v, nil)", i, test.m, got, err, test.want) + } + } +} + +// mutationColumnSorter implements sort.Interface for sorting column-value pairs in a Mutation by column names. +type mutationColumnSorter struct { + Mutation +} + +// newMutationColumnSorter creates new instance of mutationColumnSorter by duplicating the input Mutation so that +// sorting won't change the input Mutation. +func newMutationColumnSorter(m *Mutation) *mutationColumnSorter { + return &mutationColumnSorter{ + Mutation{ + m.op, + m.table, + m.keySet, + append([]string(nil), m.columns...), + append([]interface{}(nil), m.values...), + }, + } +} + +// Len implements sort.Interface.Len. +func (ms *mutationColumnSorter) Len() int { + return len(ms.columns) +} + +// Swap implements sort.Interface.Swap. +func (ms *mutationColumnSorter) Swap(i, j int) { + ms.columns[i], ms.columns[j] = ms.columns[j], ms.columns[i] + ms.values[i], ms.values[j] = ms.values[j], ms.values[i] +} + +// Less implements sort.Interface.Less. +func (ms *mutationColumnSorter) Less(i, j int) bool { + return strings.Compare(ms.columns[i], ms.columns[j]) < 0 +} + +// mutationEqual returns true if two mutations in question are equal +// to each other. +func mutationEqual(t *testing.T, m1, m2 Mutation) bool { + // Two mutations are considered to be equal even if their column values have different + // orders. + ms1 := newMutationColumnSorter(&m1) + ms2 := newMutationColumnSorter(&m2) + sort.Sort(ms1) + sort.Sort(ms2) + return testEqual(ms1, ms2) +} + +// Test helper functions which help to generate spanner.Mutation. +func TestMutationHelpers(t *testing.T) { + for _, test := range []struct { + m string + got *Mutation + want *Mutation + }{ + { + "Insert", + Insert("t_foo", []string{"col1", "col2"}, []interface{}{int64(1), int64(2)}), + &Mutation{opInsert, "t_foo", nil, []string{"col1", "col2"}, []interface{}{int64(1), int64(2)}}, + }, + { + "InsertMap", + InsertMap("t_foo", map[string]interface{}{"col1": int64(1), "col2": int64(2)}), + &Mutation{opInsert, "t_foo", nil, []string{"col1", "col2"}, []interface{}{int64(1), int64(2)}}, + }, + { + "InsertStruct", + func() *Mutation { + m, err := InsertStruct( + "t_foo", + struct { + notCol bool + Col1 int64 `spanner:"col1"` + Col2 int64 `spanner:"col2"` + }{false, int64(1), int64(2)}, + ) + if err != nil { + t.Errorf("cannot convert struct into mutation: %v", err) + } + return m + }(), + &Mutation{opInsert, "t_foo", nil, []string{"col1", "col2"}, []interface{}{int64(1), int64(2)}}, + }, + { + "Update", + Update("t_foo", []string{"col1", "col2"}, []interface{}{"one", []byte(nil)}), + &Mutation{opUpdate, "t_foo", nil, []string{"col1", "col2"}, []interface{}{"one", []byte(nil)}}, + }, + { + "UpdateMap", + UpdateMap("t_foo", map[string]interface{}{"col1": "one", "col2": []byte(nil)}), + &Mutation{opUpdate, "t_foo", nil, []string{"col1", "col2"}, []interface{}{"one", []byte(nil)}}, + }, + { + "UpdateStruct", + func() *Mutation { + m, err := UpdateStruct( + "t_foo", + struct { + Col1 string `spanner:"col1"` + notCol int + Col2 []byte `spanner:"col2"` + }{"one", 1, nil}, + ) + if err != nil { + t.Errorf("cannot convert struct into mutation: %v", err) + } + return m + }(), + &Mutation{opUpdate, "t_foo", nil, []string{"col1", "col2"}, []interface{}{"one", []byte(nil)}}, + }, + { + "InsertOrUpdate", + InsertOrUpdate("t_foo", []string{"col1", "col2"}, []interface{}{1.0, 2.0}), + &Mutation{opInsertOrUpdate, "t_foo", nil, []string{"col1", "col2"}, []interface{}{1.0, 2.0}}, + }, + { + "InsertOrUpdateMap", + InsertOrUpdateMap("t_foo", map[string]interface{}{"col1": 1.0, "col2": 2.0}), + &Mutation{opInsertOrUpdate, "t_foo", nil, []string{"col1", "col2"}, []interface{}{1.0, 2.0}}, + }, + { + "InsertOrUpdateStruct", + func() *Mutation { + m, err := InsertOrUpdateStruct( + "t_foo", + struct { + Col1 float64 `spanner:"col1"` + Col2 float64 `spanner:"col2"` + notCol float64 + }{1.0, 2.0, 3.0}, + ) + if err != nil { + t.Errorf("cannot convert struct into mutation: %v", err) + } + return m + }(), + &Mutation{opInsertOrUpdate, "t_foo", nil, []string{"col1", "col2"}, []interface{}{1.0, 2.0}}, + }, + { + "Replace", + Replace("t_foo", []string{"col1", "col2"}, []interface{}{"one", 2.0}), + &Mutation{opReplace, "t_foo", nil, []string{"col1", "col2"}, []interface{}{"one", 2.0}}, + }, + { + "ReplaceMap", + ReplaceMap("t_foo", map[string]interface{}{"col1": "one", "col2": 2.0}), + &Mutation{opReplace, "t_foo", nil, []string{"col1", "col2"}, []interface{}{"one", 2.0}}, + }, + { + "ReplaceStruct", + func() *Mutation { + m, err := ReplaceStruct( + "t_foo", + struct { + Col1 string `spanner:"col1"` + Col2 float64 `spanner:"col2"` + notCol string + }{"one", 2.0, "foo"}, + ) + if err != nil { + t.Errorf("cannot convert struct into mutation: %v", err) + } + return m + }(), + &Mutation{opReplace, "t_foo", nil, []string{"col1", "col2"}, []interface{}{"one", 2.0}}, + }, + { + "Delete", + Delete("t_foo", Key{"foo"}), + &Mutation{opDelete, "t_foo", Key{"foo"}, nil, nil}, + }, + { + "DeleteRange", + Delete("t_foo", KeyRange{Key{"bar"}, Key{"foo"}, ClosedClosed}), + &Mutation{opDelete, "t_foo", KeyRange{Key{"bar"}, Key{"foo"}, ClosedClosed}, nil, nil}, + }, + } { + if !mutationEqual(t, *test.got, *test.want) { + t.Errorf("%v: got Mutation %v, want %v", test.m, test.got, test.want) + } + } +} + +// Test encoding non-struct types by using *Struct helpers. +func TestBadStructs(t *testing.T) { + val := "i_am_not_a_struct" + wantErr := errNotStruct(val) + if _, gotErr := InsertStruct("t_test", val); !testEqual(gotErr, wantErr) { + t.Errorf("InsertStruct(%q) returns error %v, want %v", val, gotErr, wantErr) + } + if _, gotErr := InsertOrUpdateStruct("t_test", val); !testEqual(gotErr, wantErr) { + t.Errorf("InsertOrUpdateStruct(%q) returns error %v, want %v", val, gotErr, wantErr) + } + if _, gotErr := UpdateStruct("t_test", val); !testEqual(gotErr, wantErr) { + t.Errorf("UpdateStruct(%q) returns error %v, want %v", val, gotErr, wantErr) + } + if _, gotErr := ReplaceStruct("t_test", val); !testEqual(gotErr, wantErr) { + t.Errorf("ReplaceStruct(%q) returns error %v, want %v", val, gotErr, wantErr) + } +} + +func TestStructToMutationParams(t *testing.T) { + // Tests cases not covered elsewhere. + type S struct{ F interface{} } + + for _, test := range []struct { + in interface{} + wantCols []string + wantVals []interface{} + wantErr error + }{ + {nil, nil, nil, errNotStruct(nil)}, + {3, nil, nil, errNotStruct(3)}, + {(*S)(nil), nil, nil, nil}, + {&S{F: 1}, []string{"F"}, []interface{}{1}, nil}, + {&S{F: CommitTimestamp}, []string{"F"}, []interface{}{CommitTimestamp}, nil}, + } { + gotCols, gotVals, gotErr := structToMutationParams(test.in) + if !testEqual(gotCols, test.wantCols) { + t.Errorf("%#v: got cols %v, want %v", test.in, gotCols, test.wantCols) + } + if !testEqual(gotVals, test.wantVals) { + t.Errorf("%#v: got vals %v, want %v", test.in, gotVals, test.wantVals) + } + if !testEqual(gotErr, test.wantErr) { + t.Errorf("%#v: got err %v, want %v", test.in, gotErr, test.wantErr) + } + } +} + +// Test encoding Mutation into proto. +func TestEncodeMutation(t *testing.T) { + for _, test := range []struct { + name string + mutation Mutation + wantProto *sppb.Mutation + wantErr error + }{ + { + "OpDelete", + Mutation{opDelete, "t_test", Key{1}, nil, nil}, + &sppb.Mutation{ + Operation: &sppb.Mutation_Delete_{ + Delete: &sppb.Mutation_Delete{ + Table: "t_test", + KeySet: &sppb.KeySet{ + Keys: []*proto3.ListValue{listValueProto(intProto(1))}, + }, + }, + }, + }, + nil, + }, + { + "OpDelete - Key error", + Mutation{opDelete, "t_test", Key{struct{}{}}, nil, nil}, + &sppb.Mutation{ + Operation: &sppb.Mutation_Delete_{ + Delete: &sppb.Mutation_Delete{ + Table: "t_test", + KeySet: &sppb.KeySet{}, + }, + }, + }, + errInvdKeyPartType(struct{}{}), + }, + { + "OpInsert", + Mutation{opInsert, "t_test", nil, []string{"key", "val"}, []interface{}{"foo", 1}}, + &sppb.Mutation{ + Operation: &sppb.Mutation_Insert{ + Insert: &sppb.Mutation_Write{ + Table: "t_test", + Columns: []string{"key", "val"}, + Values: []*proto3.ListValue{listValueProto(stringProto("foo"), intProto(1))}, + }, + }, + }, + nil, + }, + { + "OpInsert - Value Type Error", + Mutation{opInsert, "t_test", nil, []string{"key", "val"}, []interface{}{struct{}{}, 1}}, + &sppb.Mutation{ + Operation: &sppb.Mutation_Insert{ + Insert: &sppb.Mutation_Write{}, + }, + }, + errEncoderUnsupportedType(struct{}{}), + }, + { + "OpInsertOrUpdate", + Mutation{opInsertOrUpdate, "t_test", nil, []string{"key", "val"}, []interface{}{"foo", 1}}, + &sppb.Mutation{ + Operation: &sppb.Mutation_InsertOrUpdate{ + InsertOrUpdate: &sppb.Mutation_Write{ + Table: "t_test", + Columns: []string{"key", "val"}, + Values: []*proto3.ListValue{listValueProto(stringProto("foo"), intProto(1))}, + }, + }, + }, + nil, + }, + { + "OpInsertOrUpdate - Value Type Error", + Mutation{opInsertOrUpdate, "t_test", nil, []string{"key", "val"}, []interface{}{struct{}{}, 1}}, + &sppb.Mutation{ + Operation: &sppb.Mutation_InsertOrUpdate{ + InsertOrUpdate: &sppb.Mutation_Write{}, + }, + }, + errEncoderUnsupportedType(struct{}{}), + }, + { + "OpReplace", + Mutation{opReplace, "t_test", nil, []string{"key", "val"}, []interface{}{"foo", 1}}, + &sppb.Mutation{ + Operation: &sppb.Mutation_Replace{ + Replace: &sppb.Mutation_Write{ + Table: "t_test", + Columns: []string{"key", "val"}, + Values: []*proto3.ListValue{listValueProto(stringProto("foo"), intProto(1))}, + }, + }, + }, + nil, + }, + { + "OpReplace - Value Type Error", + Mutation{opReplace, "t_test", nil, []string{"key", "val"}, []interface{}{struct{}{}, 1}}, + &sppb.Mutation{ + Operation: &sppb.Mutation_Replace{ + Replace: &sppb.Mutation_Write{}, + }, + }, + errEncoderUnsupportedType(struct{}{}), + }, + { + "OpUpdate", + Mutation{opUpdate, "t_test", nil, []string{"key", "val"}, []interface{}{"foo", 1}}, + &sppb.Mutation{ + Operation: &sppb.Mutation_Update{ + Update: &sppb.Mutation_Write{ + Table: "t_test", + Columns: []string{"key", "val"}, + Values: []*proto3.ListValue{listValueProto(stringProto("foo"), intProto(1))}, + }, + }, + }, + nil, + }, + { + "OpUpdate - Value Type Error", + Mutation{opUpdate, "t_test", nil, []string{"key", "val"}, []interface{}{struct{}{}, 1}}, + &sppb.Mutation{ + Operation: &sppb.Mutation_Update{ + Update: &sppb.Mutation_Write{}, + }, + }, + errEncoderUnsupportedType(struct{}{}), + }, + { + "OpKnown - Unknown Mutation Operation Code", + Mutation{op(100), "t_test", nil, nil, nil}, + &sppb.Mutation{}, + errInvdMutationOp(Mutation{op(100), "t_test", nil, nil, nil}), + }, + } { + gotProto, gotErr := test.mutation.proto() + if gotErr != nil { + if !testEqual(gotErr, test.wantErr) { + t.Errorf("%s: %v.proto() returns error %v, want %v", test.name, test.mutation, gotErr, test.wantErr) + } + continue + } + if !testEqual(gotProto, test.wantProto) { + t.Errorf("%s: %v.proto() = (%v, nil), want (%v, nil)", test.name, test.mutation, gotProto, test.wantProto) + } + } +} + +// Test Encoding an array of mutations. +func TestEncodeMutationArray(t *testing.T) { + for _, test := range []struct { + name string + ms []*Mutation + want []*sppb.Mutation + wantErr error + }{ + { + "Multiple Mutations", + []*Mutation{ + {opDelete, "t_test", Key{"bar"}, nil, nil}, + {opInsertOrUpdate, "t_test", nil, []string{"key", "val"}, []interface{}{"foo", 1}}, + }, + []*sppb.Mutation{ + { + Operation: &sppb.Mutation_Delete_{ + Delete: &sppb.Mutation_Delete{ + Table: "t_test", + KeySet: &sppb.KeySet{ + Keys: []*proto3.ListValue{listValueProto(stringProto("bar"))}, + }, + }, + }, + }, + { + Operation: &sppb.Mutation_InsertOrUpdate{ + InsertOrUpdate: &sppb.Mutation_Write{ + Table: "t_test", + Columns: []string{"key", "val"}, + Values: []*proto3.ListValue{listValueProto(stringProto("foo"), intProto(1))}, + }, + }, + }, + }, + nil, + }, + { + "Multiple Mutations - Bad Mutation", + []*Mutation{ + {opDelete, "t_test", Key{"bar"}, nil, nil}, + {opInsertOrUpdate, "t_test", nil, []string{"key", "val"}, []interface{}{"foo", struct{}{}}}, + }, + []*sppb.Mutation{}, + errEncoderUnsupportedType(struct{}{}), + }, + } { + gotProto, gotErr := mutationsProto(test.ms) + if gotErr != nil { + if !testEqual(gotErr, test.wantErr) { + t.Errorf("%v: mutationsProto(%v) returns error %v, want %v", test.name, test.ms, gotErr, test.wantErr) + } + continue + } + if !testEqual(gotProto, test.want) { + t.Errorf("%v: mutationsProto(%v) = (%v, nil), want (%v, nil)", test.name, test.ms, gotProto, test.want) + } + } +} diff --git a/vendor/cloud.google.com/go/spanner/not_appengine.go b/vendor/cloud.google.com/go/spanner/not_appengine.go new file mode 100644 index 00000000..687e4335 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/not_appengine.go @@ -0,0 +1,20 @@ +// Copyright 2017 Google LLC +// +// 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. + +// +build !appengine + +package spanner + +// numChannels is the default value for NumChannels of client +const numChannels = 4 diff --git a/vendor/cloud.google.com/go/spanner/oc_test.go b/vendor/cloud.google.com/go/spanner/oc_test.go new file mode 100644 index 00000000..7e957139 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/oc_test.go @@ -0,0 +1,52 @@ +// Copyright 2018 Google LLC +// +// 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 spanner + +import ( + "context" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + stestutil "cloud.google.com/go/spanner/internal/testutil" + "google.golang.org/api/option" + "google.golang.org/grpc" +) + +// Check that stats are being exported. +func TestOCStats(t *testing.T) { + te := testutil.NewTestExporter() + defer te.Unregister() + + ms := stestutil.NewMockCloudSpanner(t, trxTs) + ms.Serve() + ctx := context.Background() + c, err := NewClient(ctx, "projects/P/instances/I/databases/D", + option.WithEndpoint(ms.Addr()), + option.WithGRPCDialOption(grpc.WithInsecure()), + option.WithoutAuthentication()) + if err != nil { + t.Fatal(err) + } + defer c.Close() + + c.Single().ReadRow(ctx, "Users", Key{"alice"}, []string{"email"}) + // Wait until we see data from the view. + select { + case <-te.Stats: + case <-time.After(1 * time.Second): + t.Fatal("no stats were exported before timeout") + } +} diff --git a/vendor/cloud.google.com/go/spanner/pdml.go b/vendor/cloud.google.com/go/spanner/pdml.go new file mode 100644 index 00000000..4beb7913 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/pdml.go @@ -0,0 +1,101 @@ +// Copyright 2018 Google LLC +// +// 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 spanner + +import ( + "context" + "time" + + "google.golang.org/api/iterator" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc/codes" +) + +// PartitionedUpdate executes a DML statement in parallel across the database, using +// separate, internal transactions that commit independently. The DML statement must +// be fully partitionable: it must be expressible as the union of many statements +// each of which accesses only a single row of the table. The statement should also be +// idempotent, because it may be applied more than once. +// +// PartitionedUpdate returns an estimated count of the number of rows affected. The actual +// number of affected rows may be greater than the estimate. +func (c *Client) PartitionedUpdate(ctx context.Context, statement Statement) (count int64, err error) { + ctx = traceStartSpan(ctx, "cloud.google.com/go/spanner.PartitionedUpdate") + defer func() { traceEndSpan(ctx, err) }() + if err := checkNestedTxn(ctx); err != nil { + return 0, err + } + + var ( + tx transactionID + s *session + sh *sessionHandle + ) + // create session + sc := c.rrNext() + s, err = createSession(ctx, sc, c.database, c.sessionLabels, c.md) + if err != nil { + return 0, toSpannerError(err) + } + defer s.delete(ctx) + sh = &sessionHandle{session: s} + // begin transaction + err = runRetryable(contextWithOutgoingMetadata(ctx, sh.getMetadata()), func(ctx context.Context) error { + res, e := sc.BeginTransaction(ctx, &sppb.BeginTransactionRequest{ + Session: sh.getID(), + Options: &sppb.TransactionOptions{ + Mode: &sppb.TransactionOptions_PartitionedDml_{PartitionedDml: &sppb.TransactionOptions_PartitionedDml{}}, + }, + }) + if e != nil { + return e + } + tx = res.Id + return nil + }) + if err != nil { + return 0, toSpannerError(err) + } + req := &sppb.ExecuteSqlRequest{ + Session: sh.getID(), + Transaction: &sppb.TransactionSelector{ + Selector: &sppb.TransactionSelector_Id{Id: tx}, + }, + Sql: statement.SQL, + } + rpc := func(ctx context.Context, resumeToken []byte) (streamingReceiver, error) { + req.ResumeToken = resumeToken + return sc.ExecuteStreamingSql(ctx, req) + } + iter := stream(contextWithOutgoingMetadata(ctx, sh.getMetadata()), + rpc, func(time.Time) {}, func(error) {}) + // TODO(jba): factor out the following code from here and ReadWriteTransaction.Update. + defer iter.Stop() + for { + _, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + return 0, toSpannerError(err) + } + time.Sleep(time.Second) + } + + if !iter.sawStats { + return 0, spannerErrorf(codes.InvalidArgument, "query passed to Update: %q", statement.SQL) + } + return iter.RowCount, nil +} diff --git a/vendor/cloud.google.com/go/spanner/pdml_test.go b/vendor/cloud.google.com/go/spanner/pdml_test.go new file mode 100644 index 00000000..4c5a743e --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/pdml_test.go @@ -0,0 +1,61 @@ +// Copyright 2018 Google LLC +// +// 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 spanner + +import ( + "context" + "io" + "testing" + + "cloud.google.com/go/spanner/internal/testutil" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc/codes" +) + +func TestMockPartitionedUpdate(t *testing.T) { + t.Parallel() + ctx := context.Background() + ms := testutil.NewMockCloudSpanner(t, trxTs) + ms.Serve() + mc := sppb.NewSpannerClient(dialMock(t, ms)) + client := &Client{database: "mockdb"} + client.clients = append(client.clients, mc) + stmt := NewStatement("UPDATE t SET x = 2 WHERE x = 1") + rowCount, err := client.PartitionedUpdate(ctx, stmt) + if err != nil { + t.Fatal(err) + } + want := int64(3) + if rowCount != want { + t.Errorf("got %d, want %d", rowCount, want) + } +} + +func TestMockPartitionedUpdateWithQuery(t *testing.T) { + t.Parallel() + ctx := context.Background() + ms := testutil.NewMockCloudSpanner(t, trxTs) + ms.AddMsg(io.EOF, true) + ms.Serve() + mc := sppb.NewSpannerClient(dialMock(t, ms)) + client := &Client{database: "mockdb"} + client.clients = append(client.clients, mc) + stmt := NewStatement("SELECT t.key key, t.value value FROM t_mock t") + _, err := client.PartitionedUpdate(ctx, stmt) + wantCode := codes.InvalidArgument + if serr, ok := err.(*Error); !ok || serr.Code != wantCode { + t.Errorf("got error %v, want code %s", err, wantCode) + } +} diff --git a/vendor/cloud.google.com/go/spanner/protoutils.go b/vendor/cloud.google.com/go/spanner/protoutils.go new file mode 100644 index 00000000..3797980a --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/protoutils.go @@ -0,0 +1,113 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "encoding/base64" + "strconv" + "time" + + "cloud.google.com/go/civil" + proto3 "github.com/golang/protobuf/ptypes/struct" + sppb "google.golang.org/genproto/googleapis/spanner/v1" +) + +// Helpers to generate protobuf values and Cloud Spanner types. + +func stringProto(s string) *proto3.Value { + return &proto3.Value{Kind: stringKind(s)} +} + +func stringKind(s string) *proto3.Value_StringValue { + return &proto3.Value_StringValue{StringValue: s} +} + +func stringType() *sppb.Type { + return &sppb.Type{Code: sppb.TypeCode_STRING} +} + +func boolProto(b bool) *proto3.Value { + return &proto3.Value{Kind: &proto3.Value_BoolValue{BoolValue: b}} +} + +func boolType() *sppb.Type { + return &sppb.Type{Code: sppb.TypeCode_BOOL} +} + +func intProto(n int64) *proto3.Value { + return &proto3.Value{Kind: &proto3.Value_StringValue{StringValue: strconv.FormatInt(n, 10)}} +} + +func intType() *sppb.Type { + return &sppb.Type{Code: sppb.TypeCode_INT64} +} + +func floatProto(n float64) *proto3.Value { + return &proto3.Value{Kind: &proto3.Value_NumberValue{NumberValue: n}} +} + +func floatType() *sppb.Type { + return &sppb.Type{Code: sppb.TypeCode_FLOAT64} +} + +func bytesProto(b []byte) *proto3.Value { + return &proto3.Value{Kind: &proto3.Value_StringValue{StringValue: base64.StdEncoding.EncodeToString(b)}} +} + +func bytesType() *sppb.Type { + return &sppb.Type{Code: sppb.TypeCode_BYTES} +} + +func timeProto(t time.Time) *proto3.Value { + return stringProto(t.UTC().Format(time.RFC3339Nano)) +} + +func timeType() *sppb.Type { + return &sppb.Type{Code: sppb.TypeCode_TIMESTAMP} +} + +func dateProto(d civil.Date) *proto3.Value { + return stringProto(d.String()) +} + +func dateType() *sppb.Type { + return &sppb.Type{Code: sppb.TypeCode_DATE} +} + +func listProto(p ...*proto3.Value) *proto3.Value { + return &proto3.Value{Kind: &proto3.Value_ListValue{ListValue: &proto3.ListValue{Values: p}}} +} + +func listValueProto(p ...*proto3.Value) *proto3.ListValue { + return &proto3.ListValue{Values: p} +} + +func listType(t *sppb.Type) *sppb.Type { + return &sppb.Type{Code: sppb.TypeCode_ARRAY, ArrayElementType: t} +} + +func mkField(n string, t *sppb.Type) *sppb.StructType_Field { + return &sppb.StructType_Field{Name: n, Type: t} +} + +func structType(fields ...*sppb.StructType_Field) *sppb.Type { + return &sppb.Type{Code: sppb.TypeCode_STRUCT, StructType: &sppb.StructType{Fields: fields}} +} + +func nullProto() *proto3.Value { + return &proto3.Value{Kind: &proto3.Value_NullValue{NullValue: proto3.NullValue_NULL_VALUE}} +} diff --git a/vendor/cloud.google.com/go/spanner/read.go b/vendor/cloud.google.com/go/spanner/read.go new file mode 100644 index 00000000..8d23892e --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/read.go @@ -0,0 +1,731 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "bytes" + "context" + "io" + "log" + "sync/atomic" + "time" + + "cloud.google.com/go/internal/protostruct" + proto "github.com/golang/protobuf/proto" + proto3 "github.com/golang/protobuf/ptypes/struct" + "google.golang.org/api/iterator" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc/codes" +) + +// streamingReceiver is the interface for receiving data from a client side +// stream. +type streamingReceiver interface { + Recv() (*sppb.PartialResultSet, error) +} + +// errEarlyReadEnd returns error for read finishes when gRPC stream is still active. +func errEarlyReadEnd() error { + return spannerErrorf(codes.FailedPrecondition, "read completed with active stream") +} + +// stream is the internal fault tolerant method for streaming data from +// Cloud Spanner. +func stream(ctx context.Context, rpc func(ct context.Context, resumeToken []byte) (streamingReceiver, error), setTimestamp func(time.Time), release func(error)) *RowIterator { + ctx, cancel := context.WithCancel(ctx) + ctx = traceStartSpan(ctx, "cloud.google.com/go/spanner.RowIterator") + return &RowIterator{ + streamd: newResumableStreamDecoder(ctx, rpc), + rowd: &partialResultSetDecoder{}, + setTimestamp: setTimestamp, + release: release, + cancel: cancel, + } +} + +// RowIterator is an iterator over Rows. +type RowIterator struct { + // The plan for the query. Available after RowIterator.Next returns iterator.Done + // if QueryWithStats was called. + QueryPlan *sppb.QueryPlan + + // Execution statistics for the query. Available after RowIterator.Next returns iterator.Done + // if QueryWithStats was called. + QueryStats map[string]interface{} + + // For a DML statement, the number of rows affected. For PDML, this is a lower bound. + // Available for DML statements after RowIterator.Next returns iterator.Done. + RowCount int64 + + streamd *resumableStreamDecoder + rowd *partialResultSetDecoder + setTimestamp func(time.Time) + release func(error) + cancel func() + err error + rows []*Row + sawStats bool +} + +// Next returns the next result. Its second return value is iterator.Done if +// there are no more results. Once Next returns Done, all subsequent calls +// will return Done. +func (r *RowIterator) Next() (*Row, error) { + if r.err != nil { + return nil, r.err + } + for len(r.rows) == 0 && r.streamd.next() { + prs := r.streamd.get() + if prs.Stats != nil { + r.sawStats = true + r.QueryPlan = prs.Stats.QueryPlan + r.QueryStats = protostruct.DecodeToMap(prs.Stats.QueryStats) + if prs.Stats.RowCount != nil { + rc, err := extractRowCount(prs.Stats) + if err != nil { + return nil, err + } + r.RowCount = rc + } + } + r.rows, r.err = r.rowd.add(prs) + if r.err != nil { + return nil, r.err + } + if !r.rowd.ts.IsZero() && r.setTimestamp != nil { + r.setTimestamp(r.rowd.ts) + r.setTimestamp = nil + } + } + if len(r.rows) > 0 { + row := r.rows[0] + r.rows = r.rows[1:] + return row, nil + } + if err := r.streamd.lastErr(); err != nil { + r.err = toSpannerError(err) + } else if !r.rowd.done() { + r.err = errEarlyReadEnd() + } else { + r.err = iterator.Done + } + return nil, r.err +} + +func extractRowCount(stats *sppb.ResultSetStats) (int64, error) { + if stats.RowCount == nil { + return 0, spannerErrorf(codes.Internal, "missing RowCount") + } + switch rc := stats.RowCount.(type) { + case *sppb.ResultSetStats_RowCountExact: + return rc.RowCountExact, nil + case *sppb.ResultSetStats_RowCountLowerBound: + return rc.RowCountLowerBound, nil + default: + return 0, spannerErrorf(codes.Internal, "unknown RowCount type %T", stats.RowCount) + } +} + +// Do calls the provided function once in sequence for each row in the iteration. If the +// function returns a non-nil error, Do immediately returns that error. +// +// If there are no rows in the iterator, Do will return nil without calling the +// provided function. +// +// Do always calls Stop on the iterator. +func (r *RowIterator) Do(f func(r *Row) error) error { + defer r.Stop() + for { + row, err := r.Next() + switch err { + case iterator.Done: + return nil + case nil: + if err = f(row); err != nil { + return err + } + default: + return err + } + } +} + +// Stop terminates the iteration. It should be called after you finish using the iterator. +func (r *RowIterator) Stop() { + if r.streamd != nil { + defer traceEndSpan(r.streamd.ctx, r.err) + } + if r.cancel != nil { + r.cancel() + } + if r.release != nil { + r.release(r.err) + if r.err == nil { + r.err = spannerErrorf(codes.FailedPrecondition, "Next called after Stop") + } + r.release = nil + + } +} + +// partialResultQueue implements a simple FIFO queue. The zero value is a +// valid queue. +type partialResultQueue struct { + q []*sppb.PartialResultSet + first int + last int + n int // number of elements in queue +} + +// empty returns if the partialResultQueue is empty. +func (q *partialResultQueue) empty() bool { + return q.n == 0 +} + +// errEmptyQueue returns error for dequeuing an empty queue. +func errEmptyQueue() error { + return spannerErrorf(codes.OutOfRange, "empty partialResultQueue") +} + +// peekLast returns the last item in partialResultQueue; if the queue +// is empty, it returns error. +func (q *partialResultQueue) peekLast() (*sppb.PartialResultSet, error) { + if q.empty() { + return nil, errEmptyQueue() + } + return q.q[(q.last+cap(q.q)-1)%cap(q.q)], nil +} + +// push adds an item to the tail of partialResultQueue. +func (q *partialResultQueue) push(r *sppb.PartialResultSet) { + if q.q == nil { + q.q = make([]*sppb.PartialResultSet, 8 /* arbitrary */) + } + if q.n == cap(q.q) { + buf := make([]*sppb.PartialResultSet, cap(q.q)*2) + for i := 0; i < q.n; i++ { + buf[i] = q.q[(q.first+i)%cap(q.q)] + } + q.q = buf + q.first = 0 + q.last = q.n + } + q.q[q.last] = r + q.last = (q.last + 1) % cap(q.q) + q.n++ +} + +// pop removes an item from the head of partialResultQueue and returns +// it. +func (q *partialResultQueue) pop() *sppb.PartialResultSet { + if q.n == 0 { + return nil + } + r := q.q[q.first] + q.q[q.first] = nil + q.first = (q.first + 1) % cap(q.q) + q.n-- + return r +} + +// clear empties partialResultQueue. +func (q *partialResultQueue) clear() { + *q = partialResultQueue{} +} + +// dump retrieves all items from partialResultQueue and return them in a slice. +// It is used only in tests. +func (q *partialResultQueue) dump() []*sppb.PartialResultSet { + var dq []*sppb.PartialResultSet + for i := q.first; len(dq) < q.n; i = (i + 1) % cap(q.q) { + dq = append(dq, q.q[i]) + } + return dq +} + +// resumableStreamDecoderState encodes resumableStreamDecoder's status. +// See also the comments for resumableStreamDecoder.Next. +type resumableStreamDecoderState int + +const ( + unConnected resumableStreamDecoderState = iota // 0 + queueingRetryable // 1 + queueingUnretryable // 2 + aborted // 3 + finished // 4 +) + +// resumableStreamDecoder provides a resumable interface for receiving +// sppb.PartialResultSet(s) from a given query wrapped by +// resumableStreamDecoder.rpc(). +type resumableStreamDecoder struct { + // state is the current status of resumableStreamDecoder, see also + // the comments for resumableStreamDecoder.Next. + state resumableStreamDecoderState + // stateWitness when non-nil is called to observe state change, + // used for testing. + stateWitness func(resumableStreamDecoderState) + // ctx is the caller's context, used for cancel/timeout Next(). + ctx context.Context + // rpc is a factory of streamingReceiver, which might resume + // a previous stream from the point encoded in restartToken. + // rpc is always a wrapper of a Cloud Spanner query which is + // resumable. + rpc func(ctx context.Context, restartToken []byte) (streamingReceiver, error) + // stream is the current RPC streaming receiver. + stream streamingReceiver + // q buffers received yet undecoded partial results. + q partialResultQueue + // bytesBetweenResumeTokens is the proxy of the byte size of PartialResultSets being queued + // between two resume tokens. Once bytesBetweenResumeTokens is greater than + // maxBytesBetweenResumeTokens, resumableStreamDecoder goes into queueingUnretryable state. + bytesBetweenResumeTokens int32 + // maxBytesBetweenResumeTokens is the max number of bytes that can be buffered + // between two resume tokens. It is always copied from the global maxBytesBetweenResumeTokens + // atomically. + maxBytesBetweenResumeTokens int32 + // np is the next sppb.PartialResultSet ready to be returned + // to caller of resumableStreamDecoder.Get(). + np *sppb.PartialResultSet + // resumeToken stores the resume token that resumableStreamDecoder has + // last revealed to caller. + resumeToken []byte + // retryCount is the number of retries that have been carried out so far + retryCount int + // err is the last error resumableStreamDecoder has encountered so far. + err error + // backoff to compute delays between retries. + backoff exponentialBackoff +} + +// newResumableStreamDecoder creates a new resumeableStreamDecoder instance. +// Parameter rpc should be a function that creates a new stream +// beginning at the restartToken if non-nil. +func newResumableStreamDecoder(ctx context.Context, rpc func(ct context.Context, restartToken []byte) (streamingReceiver, error)) *resumableStreamDecoder { + return &resumableStreamDecoder{ + ctx: ctx, + rpc: rpc, + maxBytesBetweenResumeTokens: atomic.LoadInt32(&maxBytesBetweenResumeTokens), + backoff: defaultBackoff, + } +} + +// changeState fulfills state transition for resumableStateDecoder. +func (d *resumableStreamDecoder) changeState(target resumableStreamDecoderState) { + if d.state == queueingRetryable && d.state != target { + // Reset bytesBetweenResumeTokens because it is only meaningful/changed under + // queueingRetryable state. + d.bytesBetweenResumeTokens = 0 + } + d.state = target + if d.stateWitness != nil { + d.stateWitness(target) + } +} + +// isNewResumeToken returns if the observed resume token is different from +// the one returned from server last time. +func (d *resumableStreamDecoder) isNewResumeToken(rt []byte) bool { + if rt == nil { + return false + } + if bytes.Compare(rt, d.resumeToken) == 0 { + return false + } + return true +} + +// Next advances to the next available partial result set. If error or no +// more, returns false, call Err to determine if an error was encountered. +// The following diagram illustrates the state machine of resumableStreamDecoder +// that Next() implements. Note that state transition can be only triggered by +// RPC activities. +/* + rpc() fails retryable + +---------+ + | | rpc() fails unretryable/ctx timeouts or cancelled + | | +------------------------------------------------+ + | | | | + | v | v + | +---+---+---+ +--------+ +------+--+ + +-----+unConnected| |finished| | aborted |<----+ + | | ++-----+-+ +------+--+ | + +---+----+--+ ^ ^ ^ | + | ^ | | | | + | | | | recv() fails | + | | | | | | + | |recv() fails retryable | | | | + | |with valid ctx | | | | + | | | | | | + rpc() succeeds | +-----------------------+ | | | + | | | recv EOF recv EOF | | + | | | | | | + v | | Queue size exceeds | | | + +---+----+---+----+threshold +-------+-----------+ | | ++---------->+ +--------------->+ +-+ | +| |queueingRetryable| |queueingUnretryable| | +| | +<---------------+ | | +| +---+----------+--+ pop() returns +--+----+-----------+ | +| | | resume token | ^ | +| | | | | | +| | | | | | ++---------------+ | | | | + recv() succeeds | +----+ | + | recv() succeeds | + | | + | | + | | + | | + | | + +--------------------------------------------------+ + recv() fails unretryable + +*/ +var ( + // maxBytesBetweenResumeTokens is the maximum amount of bytes that resumableStreamDecoder + // in queueingRetryable state can use to queue PartialResultSets before getting + // into queueingUnretryable state. + maxBytesBetweenResumeTokens = int32(128 * 1024 * 1024) +) + +func (d *resumableStreamDecoder) next() bool { + for { + select { + case <-d.ctx.Done(): + // Do context check here so that even gRPC failed to do + // so, resumableStreamDecoder can still break the loop + // as expected. + d.err = errContextCanceled(d.ctx, d.err) + d.changeState(aborted) + default: + } + switch d.state { + case unConnected: + // If no gRPC stream is available, try to initiate one. + if d.stream, d.err = d.rpc(d.ctx, d.resumeToken); d.err != nil { + if isRetryable(d.err) { + d.doBackOff() + // Be explicit about state transition, although the + // state doesn't actually change. State transition + // will be triggered only by RPC activity, regardless of + // whether there is an actual state change or not. + d.changeState(unConnected) + continue + } + d.changeState(aborted) + continue + } + d.resetBackOff() + d.changeState(queueingRetryable) + continue + case queueingRetryable: + fallthrough + case queueingUnretryable: + // Receiving queue is not empty. + last, err := d.q.peekLast() + if err != nil { + // Only the case that receiving queue is empty could cause peekLast to + // return error and in such case, we should try to receive from stream. + d.tryRecv() + continue + } + if d.isNewResumeToken(last.ResumeToken) { + // Got new resume token, return buffered sppb.PartialResultSets to caller. + d.np = d.q.pop() + if d.q.empty() { + d.bytesBetweenResumeTokens = 0 + // The new resume token was just popped out from queue, record it. + d.resumeToken = d.np.ResumeToken + d.changeState(queueingRetryable) + } + return true + } + if d.bytesBetweenResumeTokens >= d.maxBytesBetweenResumeTokens && d.state == queueingRetryable { + d.changeState(queueingUnretryable) + continue + } + if d.state == queueingUnretryable { + // When there is no resume token observed, + // only yield sppb.PartialResultSets to caller under + // queueingUnretryable state. + d.np = d.q.pop() + return true + } + // Needs to receive more from gRPC stream till a new resume token + // is observed. + d.tryRecv() + continue + case aborted: + // Discard all pending items because none of them + // should be yield to caller. + d.q.clear() + return false + case finished: + // If query has finished, check if there are still buffered messages. + if d.q.empty() { + // No buffered PartialResultSet. + return false + } + // Although query has finished, there are still buffered PartialResultSets. + d.np = d.q.pop() + return true + + default: + log.Printf("Unexpected resumableStreamDecoder.state: %v", d.state) + return false + } + } +} + +// tryRecv attempts to receive a PartialResultSet from gRPC stream. +func (d *resumableStreamDecoder) tryRecv() { + var res *sppb.PartialResultSet + if res, d.err = d.stream.Recv(); d.err != nil { + if d.err == io.EOF { + d.err = nil + d.changeState(finished) + return + } + if isRetryable(d.err) && d.state == queueingRetryable { + d.err = nil + // Discard all queue items (none have resume tokens). + d.q.clear() + d.stream = nil + d.changeState(unConnected) + d.doBackOff() + return + } + d.changeState(aborted) + return + } + d.q.push(res) + if d.state == queueingRetryable && !d.isNewResumeToken(res.ResumeToken) { + // adjusting d.bytesBetweenResumeTokens + d.bytesBetweenResumeTokens += int32(proto.Size(res)) + } + d.resetBackOff() + d.changeState(d.state) +} + +// resetBackOff clears the internal retry counter of +// resumableStreamDecoder so that the next exponential +// backoff will start at a fresh state. +func (d *resumableStreamDecoder) resetBackOff() { + d.retryCount = 0 +} + +// doBackoff does an exponential backoff sleep. +func (d *resumableStreamDecoder) doBackOff() { + delay := d.backoff.delay(d.retryCount) + tracePrintf(d.ctx, nil, "Backing off stream read for %s", delay) + ticker := time.NewTicker(delay) + defer ticker.Stop() + d.retryCount++ + select { + case <-d.ctx.Done(): + case <-ticker.C: + } +} + +// get returns the most recent PartialResultSet generated by a call to next. +func (d *resumableStreamDecoder) get() *sppb.PartialResultSet { + return d.np +} + +// lastErr returns the last non-EOF error encountered. +func (d *resumableStreamDecoder) lastErr() error { + return d.err +} + +// partialResultSetDecoder assembles PartialResultSet(s) into Cloud Spanner +// Rows. +type partialResultSetDecoder struct { + row Row + tx *sppb.Transaction + chunked bool // if true, next value should be merged with last values entry. + ts time.Time // read timestamp +} + +// yield checks we have a complete row, and if so returns it. A row is not +// complete if it doesn't have enough columns, or if this is a chunked response +// and there are no further values to process. +func (p *partialResultSetDecoder) yield(chunked, last bool) *Row { + if len(p.row.vals) == len(p.row.fields) && (!chunked || !last) { + // When partialResultSetDecoder gets enough number of + // Column values, There are two cases that a new Row + // should be yield: + // 1. The incoming PartialResultSet is not chunked; + // 2. The incoming PartialResultSet is chunked, but the + // proto3.Value being merged is not the last one in + // the PartialResultSet. + // + // Use a fresh Row to simplify clients that want to use yielded results + // after the next row is retrieved. Note that fields is never changed + // so it doesn't need to be copied. + fresh := Row{ + fields: p.row.fields, + vals: make([]*proto3.Value, len(p.row.vals)), + } + copy(fresh.vals, p.row.vals) + p.row.vals = p.row.vals[:0] // empty and reuse slice + return &fresh + } + return nil +} + +// yieldTx returns transaction information via caller supplied callback. +func errChunkedEmptyRow() error { + return spannerErrorf(codes.FailedPrecondition, "got invalid chunked PartialResultSet with empty Row") +} + +// add tries to merge a new PartialResultSet into buffered Row. It returns +// any rows that have been completed as a result. +func (p *partialResultSetDecoder) add(r *sppb.PartialResultSet) ([]*Row, error) { + var rows []*Row + if r.Metadata != nil { + // Metadata should only be returned in the first result. + if p.row.fields == nil { + p.row.fields = r.Metadata.RowType.Fields + } + if p.tx == nil && r.Metadata.Transaction != nil { + p.tx = r.Metadata.Transaction + if p.tx.ReadTimestamp != nil { + p.ts = time.Unix(p.tx.ReadTimestamp.Seconds, int64(p.tx.ReadTimestamp.Nanos)) + } + } + } + if len(r.Values) == 0 { + return nil, nil + } + if p.chunked { + p.chunked = false + // Try to merge first value in r.Values into + // uncompleted row. + last := len(p.row.vals) - 1 + if last < 0 { // sanity check + return nil, errChunkedEmptyRow() + } + var err error + // If p is chunked, then we should always try to merge p.last with r.first. + if p.row.vals[last], err = p.merge(p.row.vals[last], r.Values[0]); err != nil { + return nil, err + } + r.Values = r.Values[1:] + // Merge is done, try to yield a complete Row. + if row := p.yield(r.ChunkedValue, len(r.Values) == 0); row != nil { + rows = append(rows, row) + } + } + for i, v := range r.Values { + // The rest values in r can be appened into p directly. + p.row.vals = append(p.row.vals, v) + // Again, check to see if a complete Row can be yielded because of + // the newly added value. + if row := p.yield(r.ChunkedValue, i == len(r.Values)-1); row != nil { + rows = append(rows, row) + } + } + if r.ChunkedValue { + // After dealing with all values in r, if r is chunked then p must + // be also chunked. + p.chunked = true + } + return rows, nil +} + +// isMergeable returns if a protobuf Value can be potentially merged with +// other protobuf Values. +func (p *partialResultSetDecoder) isMergeable(a *proto3.Value) bool { + switch a.Kind.(type) { + case *proto3.Value_StringValue: + return true + case *proto3.Value_ListValue: + return true + default: + return false + } +} + +// errIncompatibleMergeTypes returns error for incompatible protobuf types +// that cannot be merged by partialResultSetDecoder. +func errIncompatibleMergeTypes(a, b *proto3.Value) error { + return spannerErrorf(codes.FailedPrecondition, "incompatible type in chunked PartialResultSet. expected (%T), got (%T)", a.Kind, b.Kind) +} + +// errUnsupportedMergeType returns error for protobuf type that cannot be +// merged to other protobufs. +func errUnsupportedMergeType(a *proto3.Value) error { + return spannerErrorf(codes.FailedPrecondition, "unsupported type merge (%T)", a.Kind) +} + +// merge tries to combine two protobuf Values if possible. +func (p *partialResultSetDecoder) merge(a, b *proto3.Value) (*proto3.Value, error) { + var err error + typeErr := errIncompatibleMergeTypes(a, b) + switch t := a.Kind.(type) { + case *proto3.Value_StringValue: + s, ok := b.Kind.(*proto3.Value_StringValue) + if !ok { + return nil, typeErr + } + return &proto3.Value{ + Kind: &proto3.Value_StringValue{StringValue: t.StringValue + s.StringValue}, + }, nil + case *proto3.Value_ListValue: + l, ok := b.Kind.(*proto3.Value_ListValue) + if !ok { + return nil, typeErr + } + if l.ListValue == nil || len(l.ListValue.Values) <= 0 { + // b is an empty list, just return a. + return a, nil + } + if t.ListValue == nil || len(t.ListValue.Values) <= 0 { + // a is an empty list, just return b. + return b, nil + } + if la := len(t.ListValue.Values) - 1; p.isMergeable(t.ListValue.Values[la]) { + // When the last item in a is of type String, + // List or Struct(encoded into List by Cloud Spanner), + // try to Merge last item in a and first item in b. + t.ListValue.Values[la], err = p.merge(t.ListValue.Values[la], l.ListValue.Values[0]) + if err != nil { + return nil, err + } + l.ListValue.Values = l.ListValue.Values[1:] + } + return &proto3.Value{ + Kind: &proto3.Value_ListValue{ + ListValue: &proto3.ListValue{ + Values: append(t.ListValue.Values, l.ListValue.Values...), + }, + }, + }, nil + default: + return nil, errUnsupportedMergeType(a) + } + +} + +// Done returns if partialResultSetDecoder has already done with all buffered +// values. +func (p *partialResultSetDecoder) done() bool { + // There is no explicit end of stream marker, but ending part way + // through a row is obviously bad, or ending with the last column still + // awaiting completion. + return len(p.row.vals) == 0 && !p.chunked +} diff --git a/vendor/cloud.google.com/go/spanner/read_test.go b/vendor/cloud.google.com/go/spanner/read_test.go new file mode 100644 index 00000000..2c661b37 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/read_test.go @@ -0,0 +1,1732 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "context" + "errors" + "fmt" + "io" + "sync/atomic" + "testing" + "time" + + "cloud.google.com/go/spanner/internal/testutil" + "github.com/golang/protobuf/proto" + proto3 "github.com/golang/protobuf/ptypes/struct" + "google.golang.org/api/iterator" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var ( + // Mocked transaction timestamp. + trxTs = time.Unix(1, 2) + // Metadata for mocked KV table, its rows are returned by SingleUse transactions. + kvMeta = func() *sppb.ResultSetMetadata { + meta := testutil.KvMeta + meta.Transaction = &sppb.Transaction{ + ReadTimestamp: timestampProto(trxTs), + } + return &meta + }() + // Metadata for mocked ListKV table, which uses List for its key and value. + // Its rows are returned by snapshot readonly transactions, as indicated in the transaction metadata. + kvListMeta = &sppb.ResultSetMetadata{ + RowType: &sppb.StructType{ + Fields: []*sppb.StructType_Field{ + { + Name: "Key", + Type: &sppb.Type{ + Code: sppb.TypeCode_ARRAY, + ArrayElementType: &sppb.Type{ + Code: sppb.TypeCode_STRING, + }, + }, + }, + { + Name: "Value", + Type: &sppb.Type{ + Code: sppb.TypeCode_ARRAY, + ArrayElementType: &sppb.Type{ + Code: sppb.TypeCode_STRING, + }, + }, + }, + }, + }, + Transaction: &sppb.Transaction{ + Id: transactionID{5, 6, 7, 8, 9}, + ReadTimestamp: timestampProto(trxTs), + }, + } + // Metadata for mocked schema of a query result set, which has two struct + // columns named "Col1" and "Col2", the struct's schema is like the + // following: + // + // STRUCT { + // INT + // LIST + // } + // + // Its rows are returned in readwrite transaction, as indicated in the transaction metadata. + kvObjectMeta = &sppb.ResultSetMetadata{ + RowType: &sppb.StructType{ + Fields: []*sppb.StructType_Field{ + { + Name: "Col1", + Type: &sppb.Type{ + Code: sppb.TypeCode_STRUCT, + StructType: &sppb.StructType{ + Fields: []*sppb.StructType_Field{ + { + Name: "foo-f1", + Type: &sppb.Type{ + Code: sppb.TypeCode_INT64, + }, + }, + { + Name: "foo-f2", + Type: &sppb.Type{ + Code: sppb.TypeCode_ARRAY, + ArrayElementType: &sppb.Type{ + Code: sppb.TypeCode_STRING, + }, + }, + }, + }, + }, + }, + }, + { + Name: "Col2", + Type: &sppb.Type{ + Code: sppb.TypeCode_STRUCT, + StructType: &sppb.StructType{ + Fields: []*sppb.StructType_Field{ + { + Name: "bar-f1", + Type: &sppb.Type{ + Code: sppb.TypeCode_INT64, + }, + }, + { + Name: "bar-f2", + Type: &sppb.Type{ + Code: sppb.TypeCode_ARRAY, + ArrayElementType: &sppb.Type{ + Code: sppb.TypeCode_STRING, + }, + }, + }, + }, + }, + }, + }, + }, + }, + Transaction: &sppb.Transaction{ + Id: transactionID{1, 2, 3, 4, 5}, + }, + } +) + +// String implements fmt.stringer. +func (r *Row) String() string { + return fmt.Sprintf("{fields: %s, val: %s}", r.fields, r.vals) +} + +func describeRows(l []*Row) string { + // generate a nice test failure description + var s = "[" + for i, r := range l { + if i != 0 { + s += ",\n " + } + s += fmt.Sprint(r) + } + s += "]" + return s +} + +// Helper for generating proto3 Value_ListValue instances, making +// test code shorter and readable. +func genProtoListValue(v ...string) *proto3.Value_ListValue { + r := &proto3.Value_ListValue{ + ListValue: &proto3.ListValue{ + Values: []*proto3.Value{}, + }, + } + for _, e := range v { + r.ListValue.Values = append( + r.ListValue.Values, + &proto3.Value{ + Kind: &proto3.Value_StringValue{StringValue: e}, + }, + ) + } + return r +} + +// Test Row generation logics of partialResultSetDecoder. +func TestPartialResultSetDecoder(t *testing.T) { + restore := setMaxBytesBetweenResumeTokens() + defer restore() + var tests = []struct { + input []*sppb.PartialResultSet + wantF []*Row + wantTxID transactionID + wantTs time.Time + wantD bool + }{ + { + // Empty input. + wantD: true, + }, + // String merging examples. + { + // Single KV result. + input: []*sppb.PartialResultSet{ + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "foo"}}, + {Kind: &proto3.Value_StringValue{StringValue: "bar"}}, + }, + }, + }, + wantF: []*Row{ + { + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "foo"}}, + {Kind: &proto3.Value_StringValue{StringValue: "bar"}}, + }, + }, + }, + wantTs: trxTs, + wantD: true, + }, + { + // Incomplete partial result. + input: []*sppb.PartialResultSet{ + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "foo"}}, + }, + }, + }, + wantTs: trxTs, + wantD: false, + }, + { + // Complete splitted result. + input: []*sppb.PartialResultSet{ + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "foo"}}, + }, + }, + { + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "bar"}}, + }, + }, + }, + wantF: []*Row{ + { + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "foo"}}, + {Kind: &proto3.Value_StringValue{StringValue: "bar"}}, + }, + }, + }, + wantTs: trxTs, + wantD: true, + }, + { + // Multi-row example with splitted row in the middle. + input: []*sppb.PartialResultSet{ + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "foo"}}, + {Kind: &proto3.Value_StringValue{StringValue: "bar"}}, + {Kind: &proto3.Value_StringValue{StringValue: "A"}}, + }, + }, + { + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "1"}}, + {Kind: &proto3.Value_StringValue{StringValue: "B"}}, + {Kind: &proto3.Value_StringValue{StringValue: "2"}}, + }, + }, + }, + wantF: []*Row{ + { + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "foo"}}, + {Kind: &proto3.Value_StringValue{StringValue: "bar"}}, + }, + }, + { + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "A"}}, + {Kind: &proto3.Value_StringValue{StringValue: "1"}}, + }, + }, + { + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "B"}}, + {Kind: &proto3.Value_StringValue{StringValue: "2"}}, + }, + }, + }, + wantTs: trxTs, + wantD: true, + }, + { + // Merging example in result_set.proto. + input: []*sppb.PartialResultSet{ + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "Hello"}}, + {Kind: &proto3.Value_StringValue{StringValue: "W"}}, + }, + ChunkedValue: true, + }, + { + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "orl"}}, + }, + ChunkedValue: true, + }, + { + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "d"}}, + }, + }, + }, + wantF: []*Row{ + { + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "Hello"}}, + {Kind: &proto3.Value_StringValue{StringValue: "World"}}, + }, + }, + }, + wantTs: trxTs, + wantD: true, + }, + { + // More complex example showing completing a merge and + // starting a new merge in the same partialResultSet. + input: []*sppb.PartialResultSet{ + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "Hello"}}, + {Kind: &proto3.Value_StringValue{StringValue: "W"}}, // start split in value + }, + ChunkedValue: true, + }, + { + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "orld"}}, // complete value + {Kind: &proto3.Value_StringValue{StringValue: "i"}}, // start split in key + }, + ChunkedValue: true, + }, + { + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "s"}}, // complete key + {Kind: &proto3.Value_StringValue{StringValue: "not"}}, + {Kind: &proto3.Value_StringValue{StringValue: "a"}}, + {Kind: &proto3.Value_StringValue{StringValue: "qu"}}, // split in value + }, + ChunkedValue: true, + }, + { + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "estion"}}, // complete value + }, + }, + }, + wantF: []*Row{ + { + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "Hello"}}, + {Kind: &proto3.Value_StringValue{StringValue: "World"}}, + }, + }, + { + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "is"}}, + {Kind: &proto3.Value_StringValue{StringValue: "not"}}, + }, + }, + { + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: "a"}}, + {Kind: &proto3.Value_StringValue{StringValue: "question"}}, + }, + }, + }, + wantTs: trxTs, + wantD: true, + }, + // List merging examples. + { + // Non-splitting Lists. + input: []*sppb.PartialResultSet{ + { + Metadata: kvListMeta, + Values: []*proto3.Value{ + { + Kind: genProtoListValue("foo-1", "foo-2"), + }, + }, + }, + { + Values: []*proto3.Value{ + { + Kind: genProtoListValue("bar-1", "bar-2"), + }, + }, + }, + }, + wantF: []*Row{ + { + fields: kvListMeta.RowType.Fields, + vals: []*proto3.Value{ + { + Kind: genProtoListValue("foo-1", "foo-2"), + }, + { + Kind: genProtoListValue("bar-1", "bar-2"), + }, + }, + }, + }, + wantTxID: transactionID{5, 6, 7, 8, 9}, + wantTs: trxTs, + wantD: true, + }, + { + // Simple List merge case: splitted string element. + input: []*sppb.PartialResultSet{ + { + Metadata: kvListMeta, + Values: []*proto3.Value{ + { + Kind: genProtoListValue("foo-1", "foo-"), + }, + }, + ChunkedValue: true, + }, + { + Values: []*proto3.Value{ + { + Kind: genProtoListValue("2"), + }, + }, + }, + { + Values: []*proto3.Value{ + { + Kind: genProtoListValue("bar-1", "bar-2"), + }, + }, + }, + }, + wantF: []*Row{ + { + fields: kvListMeta.RowType.Fields, + vals: []*proto3.Value{ + { + Kind: genProtoListValue("foo-1", "foo-2"), + }, + { + Kind: genProtoListValue("bar-1", "bar-2"), + }, + }, + }, + }, + wantTxID: transactionID{5, 6, 7, 8, 9}, + wantTs: trxTs, + wantD: true, + }, + { + // Struct merging is also implemented by List merging. Note that + // Cloud Spanner uses proto.ListValue to encode Structs as well. + input: []*sppb.PartialResultSet{ + { + Metadata: kvObjectMeta, + Values: []*proto3.Value{ + { + Kind: &proto3.Value_ListValue{ + ListValue: &proto3.ListValue{ + Values: []*proto3.Value{ + {Kind: &proto3.Value_NumberValue{NumberValue: 23}}, + {Kind: genProtoListValue("foo-1", "fo")}, + }, + }, + }, + }, + }, + ChunkedValue: true, + }, + { + Values: []*proto3.Value{ + { + Kind: &proto3.Value_ListValue{ + ListValue: &proto3.ListValue{ + Values: []*proto3.Value{ + {Kind: genProtoListValue("o-2", "f")}, + }, + }, + }, + }, + }, + ChunkedValue: true, + }, + { + Values: []*proto3.Value{ + { + Kind: &proto3.Value_ListValue{ + ListValue: &proto3.ListValue{ + Values: []*proto3.Value{ + {Kind: genProtoListValue("oo-3")}, + }, + }, + }, + }, + { + Kind: &proto3.Value_ListValue{ + ListValue: &proto3.ListValue{ + Values: []*proto3.Value{ + {Kind: &proto3.Value_NumberValue{NumberValue: 45}}, + {Kind: genProtoListValue("bar-1")}, + }, + }, + }, + }, + }, + }, + }, + wantF: []*Row{ + { + fields: kvObjectMeta.RowType.Fields, + vals: []*proto3.Value{ + { + Kind: &proto3.Value_ListValue{ + ListValue: &proto3.ListValue{ + Values: []*proto3.Value{ + {Kind: &proto3.Value_NumberValue{NumberValue: 23}}, + {Kind: genProtoListValue("foo-1", "foo-2", "foo-3")}, + }, + }, + }, + }, + { + Kind: &proto3.Value_ListValue{ + ListValue: &proto3.ListValue{ + Values: []*proto3.Value{ + {Kind: &proto3.Value_NumberValue{NumberValue: 45}}, + {Kind: genProtoListValue("bar-1")}, + }, + }, + }, + }, + }, + }, + }, + wantTxID: transactionID{1, 2, 3, 4, 5}, + wantD: true, + }, + } + +nextTest: + for i, test := range tests { + var rows []*Row + p := &partialResultSetDecoder{} + for j, v := range test.input { + rs, err := p.add(v) + if err != nil { + t.Errorf("test %d.%d: partialResultSetDecoder.add(%v) = %v; want nil", i, j, v, err) + continue nextTest + } + rows = append(rows, rs...) + } + if !testEqual(p.ts, test.wantTs) { + t.Errorf("got transaction(%v), want %v", p.ts, test.wantTs) + } + if !testEqual(rows, test.wantF) { + t.Errorf("test %d: rows=\n%v\n; want\n%v\n; p.row:\n%v\n", i, describeRows(rows), describeRows(test.wantF), p.row) + } + if got := p.done(); got != test.wantD { + t.Errorf("test %d: partialResultSetDecoder.done() = %v", i, got) + } + } +} + +const ( + maxBuffers = 16 // max number of PartialResultSets that will be buffered in tests. +) + +// setMaxBytesBetweenResumeTokens sets the global maxBytesBetweenResumeTokens to a smaller +// value more suitable for tests. It returns a function which should be called to restore +// the maxBytesBetweenResumeTokens to its old value +func setMaxBytesBetweenResumeTokens() func() { + o := atomic.LoadInt32(&maxBytesBetweenResumeTokens) + atomic.StoreInt32(&maxBytesBetweenResumeTokens, int32(maxBuffers*proto.Size(&sppb.PartialResultSet{ + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(0)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(0)}}, + }, + }))) + return func() { + atomic.StoreInt32(&maxBytesBetweenResumeTokens, o) + } +} + +// keyStr generates key string for kvMeta schema. +func keyStr(i int) string { + return fmt.Sprintf("foo-%02d", i) +} + +// valStr generates value string for kvMeta schema. +func valStr(i int) string { + return fmt.Sprintf("bar-%02d", i) +} + +// Test state transitions of resumableStreamDecoder where state machine +// ends up to a non-blocking state(resumableStreamDecoder.Next returns +// on non-blocking state). +func TestRsdNonblockingStates(t *testing.T) { + restore := setMaxBytesBetweenResumeTokens() + defer restore() + tests := []struct { + name string + msgs []testutil.MockCtlMsg + rpc func(ct context.Context, resumeToken []byte) (streamingReceiver, error) + sql string + // Expected values + want []*sppb.PartialResultSet // PartialResultSets that should be returned to caller + queue []*sppb.PartialResultSet // PartialResultSets that should be buffered + resumeToken []byte // Resume token that is maintained by resumableStreamDecoder + stateHistory []resumableStreamDecoderState // State transition history of resumableStreamDecoder + wantErr error + }{ + { + // unConnected->queueingRetryable->finished + name: "unConnected->queueingRetryable->finished", + msgs: []testutil.MockCtlMsg{ + {}, + {}, + {Err: io.EOF, ResumeToken: false}, + }, + sql: "SELECT t.key key, t.value value FROM t_mock t", + want: []*sppb.PartialResultSet{ + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(0)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(0)}}, + }, + }, + }, + queue: []*sppb.PartialResultSet{ + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(1)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(1)}}, + }, + }, + }, + stateHistory: []resumableStreamDecoderState{ + queueingRetryable, // do RPC + queueingRetryable, // got foo-00 + queueingRetryable, // got foo-01 + finished, // got EOF + }, + }, + { + // unConnected->queueingRetryable->aborted + name: "unConnected->queueingRetryable->aborted", + msgs: []testutil.MockCtlMsg{ + {}, + {Err: nil, ResumeToken: true}, + {}, + {Err: errors.New("I quit"), ResumeToken: false}, + }, + sql: "SELECT t.key key, t.value value FROM t_mock t", + want: []*sppb.PartialResultSet{ + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(0)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(0)}}, + }, + }, + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(1)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(1)}}, + }, + ResumeToken: testutil.EncodeResumeToken(1), + }, + }, + stateHistory: []resumableStreamDecoderState{ + queueingRetryable, // do RPC + queueingRetryable, // got foo-00 + queueingRetryable, // got foo-01 + queueingRetryable, // foo-01, resume token + queueingRetryable, // got foo-02 + aborted, // got error + }, + wantErr: status.Errorf(codes.Unknown, "I quit"), + }, + { + // unConnected->queueingRetryable->queueingUnretryable->queueingUnretryable + name: "unConnected->queueingRetryable->queueingUnretryable->queueingUnretryable", + msgs: func() (m []testutil.MockCtlMsg) { + for i := 0; i < maxBuffers+1; i++ { + m = append(m, testutil.MockCtlMsg{}) + } + return m + }(), + sql: "SELECT t.key key, t.value value FROM t_mock t", + want: func() (s []*sppb.PartialResultSet) { + for i := 0; i < maxBuffers+1; i++ { + s = append(s, &sppb.PartialResultSet{ + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(i)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(i)}}, + }, + }) + } + return s + }(), + stateHistory: func() (s []resumableStreamDecoderState) { + s = append(s, queueingRetryable) // RPC + for i := 0; i < maxBuffers; i++ { + s = append(s, queueingRetryable) // the internal queue of resumableStreamDecoder fills up + } + // the first item fills up the queue and triggers state transition; + // the second item is received under queueingUnretryable state. + s = append(s, queueingUnretryable) + s = append(s, queueingUnretryable) + return s + }(), + }, + { + // unConnected->queueingRetryable->queueingUnretryable->aborted + name: "unConnected->queueingRetryable->queueingUnretryable->aborted", + msgs: func() (m []testutil.MockCtlMsg) { + for i := 0; i < maxBuffers; i++ { + m = append(m, testutil.MockCtlMsg{}) + } + m = append(m, testutil.MockCtlMsg{Err: errors.New("Just Abort It"), ResumeToken: false}) + return m + }(), + sql: "SELECT t.key key, t.value value FROM t_mock t", + want: func() (s []*sppb.PartialResultSet) { + for i := 0; i < maxBuffers; i++ { + s = append(s, &sppb.PartialResultSet{ + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(i)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(i)}}, + }, + }) + } + return s + }(), + stateHistory: func() (s []resumableStreamDecoderState) { + s = append(s, queueingRetryable) // RPC + for i := 0; i < maxBuffers; i++ { + s = append(s, queueingRetryable) // internal queue of resumableStreamDecoder fills up + } + s = append(s, queueingUnretryable) // the last row triggers state change + s = append(s, aborted) // Error happens + return s + }(), + wantErr: status.Errorf(codes.Unknown, "Just Abort It"), + }, + } +nextTest: + for _, test := range tests { + ms := testutil.NewMockCloudSpanner(t, trxTs) + ms.Serve() + mc := sppb.NewSpannerClient(dialMock(t, ms)) + if test.rpc == nil { + test.rpc = func(ct context.Context, resumeToken []byte) (streamingReceiver, error) { + return mc.ExecuteStreamingSql(ct, &sppb.ExecuteSqlRequest{ + Sql: test.sql, + ResumeToken: resumeToken, + }) + } + } + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + r := newResumableStreamDecoder( + ctx, + test.rpc, + ) + st := []resumableStreamDecoderState{} + var lastErr error + // Once the expected number of state transitions are observed, + // send a signal by setting stateDone = true. + stateDone := false + // Set stateWitness to listen to state changes. + hl := len(test.stateHistory) // To avoid data race on test. + r.stateWitness = func(rs resumableStreamDecoderState) { + if !stateDone { + // Record state transitions. + st = append(st, rs) + if len(st) == hl { + lastErr = r.lastErr() + stateDone = true + } + } + } + // Let mock server stream given messages to resumableStreamDecoder. + for _, m := range test.msgs { + ms.AddMsg(m.Err, m.ResumeToken) + } + var rs []*sppb.PartialResultSet + for { + select { + case <-ctx.Done(): + t.Errorf("context cancelled or timeout during test") + continue nextTest + default: + } + if stateDone { + // Check if resumableStreamDecoder carried out expected + // state transitions. + if !testEqual(st, test.stateHistory) { + t.Errorf("%v: observed state transitions: \n%v\n, want \n%v\n", + test.name, st, test.stateHistory) + } + // Check if resumableStreamDecoder returns expected array of + // PartialResultSets. + if !testEqual(rs, test.want) { + t.Errorf("%v: received PartialResultSets: \n%v\n, want \n%v\n", test.name, rs, test.want) + } + // Verify that resumableStreamDecoder's internal buffering is also correct. + var q []*sppb.PartialResultSet + for { + item := r.q.pop() + if item == nil { + break + } + q = append(q, item) + } + if !testEqual(q, test.queue) { + t.Errorf("%v: PartialResultSets still queued: \n%v\n, want \n%v\n", test.name, q, test.queue) + } + // Verify resume token. + if test.resumeToken != nil && !testEqual(r.resumeToken, test.resumeToken) { + t.Errorf("%v: Resume token is %v, want %v\n", test.name, r.resumeToken, test.resumeToken) + } + // Verify error message. + if !testEqual(lastErr, test.wantErr) { + t.Errorf("%v: got error %v, want %v", test.name, lastErr, test.wantErr) + } + // Proceed to next test + continue nextTest + } + // Receive next decoded item. + if r.next() { + rs = append(rs, r.get()) + } + } + } +} + +// Test state transitions of resumableStreamDecoder where state machine +// ends up to a blocking state(resumableStreamDecoder.Next blocks +// on blocking state). +func TestRsdBlockingStates(t *testing.T) { + restore := setMaxBytesBetweenResumeTokens() + defer restore() + tests := []struct { + name string + msgs []testutil.MockCtlMsg + rpc func(ct context.Context, resumeToken []byte) (streamingReceiver, error) + sql string + // Expected values + want []*sppb.PartialResultSet // PartialResultSets that should be returned to caller + queue []*sppb.PartialResultSet // PartialResultSets that should be buffered + resumeToken []byte // Resume token that is maintained by resumableStreamDecoder + stateHistory []resumableStreamDecoderState // State transition history of resumableStreamDecoder + wantErr error + }{ + { + // unConnected -> unConnected + name: "unConnected -> unConnected", + rpc: func(ct context.Context, resumeToken []byte) (streamingReceiver, error) { + return nil, status.Errorf(codes.Unavailable, "trust me: server is unavailable") + }, + sql: "SELECT * from t_whatever", + stateHistory: []resumableStreamDecoderState{unConnected, unConnected, unConnected}, + wantErr: status.Errorf(codes.Unavailable, "trust me: server is unavailable"), + }, + { + // unConnected -> queueingRetryable + name: "unConnected -> queueingRetryable", + sql: "SELECT t.key key, t.value value FROM t_mock t", + stateHistory: []resumableStreamDecoderState{queueingRetryable}, + }, + { + // unConnected->queueingRetryable->queueingRetryable + name: "unConnected->queueingRetryable->queueingRetryable", + msgs: []testutil.MockCtlMsg{ + {}, + {Err: nil, ResumeToken: true}, + {Err: nil, ResumeToken: true}, + {}, + }, + sql: "SELECT t.key key, t.value value FROM t_mock t", + want: []*sppb.PartialResultSet{ + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(0)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(0)}}, + }, + }, + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(1)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(1)}}, + }, + ResumeToken: testutil.EncodeResumeToken(1), + }, + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(2)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(2)}}, + }, + ResumeToken: testutil.EncodeResumeToken(2), + }, + }, + queue: []*sppb.PartialResultSet{ + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(3)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(3)}}, + }, + }, + }, + resumeToken: testutil.EncodeResumeToken(2), + stateHistory: []resumableStreamDecoderState{ + queueingRetryable, // do RPC + queueingRetryable, // got foo-00 + queueingRetryable, // got foo-01 + queueingRetryable, // foo-01, resume token + queueingRetryable, // got foo-02 + queueingRetryable, // foo-02, resume token + queueingRetryable, // got foo-03 + }, + }, + { + // unConnected->queueingRetryable->queueingUnretryable->queueingRetryable->queueingRetryable + name: "unConnected->queueingRetryable->queueingUnretryable->queueingRetryable->queueingRetryable", + msgs: func() (m []testutil.MockCtlMsg) { + for i := 0; i < maxBuffers+1; i++ { + m = append(m, testutil.MockCtlMsg{}) + } + m = append(m, testutil.MockCtlMsg{Err: nil, ResumeToken: true}) + m = append(m, testutil.MockCtlMsg{}) + return m + }(), + sql: "SELECT t.key key, t.value value FROM t_mock t", + want: func() (s []*sppb.PartialResultSet) { + for i := 0; i < maxBuffers+2; i++ { + s = append(s, &sppb.PartialResultSet{ + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(i)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(i)}}, + }, + }) + } + s[maxBuffers+1].ResumeToken = testutil.EncodeResumeToken(maxBuffers + 1) + return s + }(), + resumeToken: testutil.EncodeResumeToken(maxBuffers + 1), + queue: []*sppb.PartialResultSet{ + { + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(maxBuffers + 2)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(maxBuffers + 2)}}, + }, + }, + }, + stateHistory: func() (s []resumableStreamDecoderState) { + s = append(s, queueingRetryable) // RPC + for i := 0; i < maxBuffers; i++ { + s = append(s, queueingRetryable) // internal queue of resumableStreamDecoder filles up + } + for i := maxBuffers - 1; i < maxBuffers+1; i++ { + // the first item fills up the queue and triggers state change; + // the second item is received under queueingUnretryable state. + s = append(s, queueingUnretryable) + } + s = append(s, queueingUnretryable) // got (maxBuffers+1)th row under Unretryable state + s = append(s, queueingRetryable) // (maxBuffers+1)th row has resume token + s = append(s, queueingRetryable) // (maxBuffers+2)th row has no resume token + return s + }(), + }, + { + // unConnected->queueingRetryable->queueingUnretryable->finished + name: "unConnected->queueingRetryable->queueingUnretryable->finished", + msgs: func() (m []testutil.MockCtlMsg) { + for i := 0; i < maxBuffers; i++ { + m = append(m, testutil.MockCtlMsg{}) + } + m = append(m, testutil.MockCtlMsg{Err: io.EOF, ResumeToken: false}) + return m + }(), + sql: "SELECT t.key key, t.value value FROM t_mock t", + want: func() (s []*sppb.PartialResultSet) { + for i := 0; i < maxBuffers; i++ { + s = append(s, &sppb.PartialResultSet{ + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(i)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(i)}}, + }, + }) + } + return s + }(), + stateHistory: func() (s []resumableStreamDecoderState) { + s = append(s, queueingRetryable) // RPC + for i := 0; i < maxBuffers; i++ { + s = append(s, queueingRetryable) // internal queue of resumableStreamDecoder fills up + } + s = append(s, queueingUnretryable) // last row triggers state change + s = append(s, finished) // query finishes + return s + }(), + }, + } + for _, test := range tests { + ms := testutil.NewMockCloudSpanner(t, trxTs) + ms.Serve() + cc := dialMock(t, ms) + mc := sppb.NewSpannerClient(cc) + if test.rpc == nil { + // Avoid using test.sql directly in closure because for loop changes test. + sql := test.sql + test.rpc = func(ct context.Context, resumeToken []byte) (streamingReceiver, error) { + return mc.ExecuteStreamingSql(ct, &sppb.ExecuteSqlRequest{ + Sql: sql, + ResumeToken: resumeToken, + }) + } + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + r := newResumableStreamDecoder( + ctx, + test.rpc, + ) + // Override backoff to make the test run faster. + r.backoff = exponentialBackoff{1 * time.Nanosecond, 1 * time.Nanosecond} + // st is the set of observed state transitions. + st := []resumableStreamDecoderState{} + // q is the content of the decoder's partial result queue when expected number of state transitions are done. + q := []*sppb.PartialResultSet{} + var lastErr error + // Once the expected number of state transitions are observed, + // send a signal to channel stateDone. + stateDone := make(chan int) + // Set stateWitness to listen to state changes. + hl := len(test.stateHistory) // To avoid data race on test. + r.stateWitness = func(rs resumableStreamDecoderState) { + select { + case <-stateDone: + // Noop after expected number of state transitions + default: + // Record state transitions. + st = append(st, rs) + if len(st) == hl { + lastErr = r.lastErr() + q = r.q.dump() + close(stateDone) + } + } + } + // Let mock server stream given messages to resumableStreamDecoder. + for _, m := range test.msgs { + ms.AddMsg(m.Err, m.ResumeToken) + } + var rs []*sppb.PartialResultSet + go func() { + for { + if !r.next() { + // Note that r.Next also exits on context cancel/timeout. + return + } + rs = append(rs, r.get()) + } + }() + // Verify that resumableStreamDecoder reaches expected state. + select { + case <-stateDone: // Note that at this point, receiver is still blocking on r.next(). + // Check if resumableStreamDecoder carried out expected + // state transitions. + if !testEqual(st, test.stateHistory) { + t.Errorf("%v: observed state transitions: \n%v\n, want \n%v\n", + test.name, st, test.stateHistory) + } + // Check if resumableStreamDecoder returns expected array of + // PartialResultSets. + if !testEqual(rs, test.want) { + t.Errorf("%v: received PartialResultSets: \n%v\n, want \n%v\n", test.name, rs, test.want) + } + // Verify that resumableStreamDecoder's internal buffering is also correct. + if !testEqual(q, test.queue) { + t.Errorf("%v: PartialResultSets still queued: \n%v\n, want \n%v\n", test.name, q, test.queue) + } + // Verify resume token. + if test.resumeToken != nil && !testEqual(r.resumeToken, test.resumeToken) { + t.Errorf("%v: Resume token is %v, want %v\n", test.name, r.resumeToken, test.resumeToken) + } + // Verify error message. + if !testEqual(lastErr, test.wantErr) { + t.Errorf("%v: got error %v, want %v", test.name, lastErr, test.wantErr) + } + case <-time.After(1 * time.Second): + t.Errorf("%v: Timeout in waiting for state change", test.name) + } + ms.Stop() + cc.Close() + } +} + +// sReceiver signals every receiving attempt through a channel, +// used by TestResumeToken to determine if the receiving of a certain +// PartialResultSet will be attempted next. +type sReceiver struct { + c chan int + rpcReceiver sppb.Spanner_ExecuteStreamingSqlClient +} + +// Recv() implements streamingReceiver.Recv for sReceiver. +func (sr *sReceiver) Recv() (*sppb.PartialResultSet, error) { + sr.c <- 1 + return sr.rpcReceiver.Recv() +} + +// waitn waits for nth receiving attempt from now on, until +// the signal for nth Recv() attempts is received or timeout. +// Note that because the way stream() works, the signal for the +// nth Recv() means that the previous n - 1 PartialResultSets +// has already been returned to caller or queued, if no error happened. +func (sr *sReceiver) waitn(n int) error { + for i := 0; i < n; i++ { + select { + case <-sr.c: + case <-time.After(10 * time.Second): + return fmt.Errorf("timeout in waiting for %v-th Recv()", i+1) + } + } + return nil +} + +// Test the handling of resumableStreamDecoder.bytesBetweenResumeTokens. +func TestQueueBytes(t *testing.T) { + restore := setMaxBytesBetweenResumeTokens() + defer restore() + ms := testutil.NewMockCloudSpanner(t, trxTs) + ms.Serve() + defer ms.Stop() + cc := dialMock(t, ms) + defer cc.Close() + mc := sppb.NewSpannerClient(cc) + sr := &sReceiver{ + c: make(chan int, 1000), // will never block in this test + } + wantQueueBytes := 0 + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + r := newResumableStreamDecoder( + ctx, + func(ct context.Context, resumeToken []byte) (streamingReceiver, error) { + r, err := mc.ExecuteStreamingSql(ct, &sppb.ExecuteSqlRequest{ + Sql: "SELECT t.key key, t.value value FROM t_mock t", + ResumeToken: resumeToken, + }) + sr.rpcReceiver = r + return sr, err + }, + ) + go func() { + for r.next() { + } + }() + // Let server send maxBuffers / 2 rows. + for i := 0; i < maxBuffers/2; i++ { + wantQueueBytes += proto.Size(&sppb.PartialResultSet{ + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(i)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(i)}}, + }, + }) + ms.AddMsg(nil, false) + } + if err := sr.waitn(maxBuffers/2 + 1); err != nil { + t.Fatalf("failed to wait for the first %v recv() calls: %v", maxBuffers, err) + } + if int32(wantQueueBytes) != r.bytesBetweenResumeTokens { + t.Errorf("r.bytesBetweenResumeTokens = %v, want %v", r.bytesBetweenResumeTokens, wantQueueBytes) + } + // Now send a resume token to drain the queue. + ms.AddMsg(nil, true) + // Wait for all rows to be processes. + if err := sr.waitn(1); err != nil { + t.Fatalf("failed to wait for rows to be processed: %v", err) + } + if r.bytesBetweenResumeTokens != 0 { + t.Errorf("r.bytesBetweenResumeTokens = %v, want 0", r.bytesBetweenResumeTokens) + } + // Let server send maxBuffers - 1 rows. + wantQueueBytes = 0 + for i := 0; i < maxBuffers-1; i++ { + wantQueueBytes += proto.Size(&sppb.PartialResultSet{ + Metadata: kvMeta, + Values: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(i)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(i)}}, + }, + }) + ms.AddMsg(nil, false) + } + if err := sr.waitn(maxBuffers - 1); err != nil { + t.Fatalf("failed to wait for %v rows to be processed: %v", maxBuffers-1, err) + } + if int32(wantQueueBytes) != r.bytesBetweenResumeTokens { + t.Errorf("r.bytesBetweenResumeTokens = %v, want 0", r.bytesBetweenResumeTokens) + } + // Trigger a state transition: queueingRetryable -> queueingUnretryable. + ms.AddMsg(nil, false) + if err := sr.waitn(1); err != nil { + t.Fatalf("failed to wait for state transition: %v", err) + } + if r.bytesBetweenResumeTokens != 0 { + t.Errorf("r.bytesBetweenResumeTokens = %v, want 0", r.bytesBetweenResumeTokens) + } +} + +// Verify that client can deal with resume token correctly +func TestResumeToken(t *testing.T) { + restore := setMaxBytesBetweenResumeTokens() + defer restore() + ms := testutil.NewMockCloudSpanner(t, trxTs) + ms.Serve() + defer ms.Stop() + cc := dialMock(t, ms) + defer cc.Close() + mc := sppb.NewSpannerClient(cc) + sr := &sReceiver{ + c: make(chan int, 1000), // will never block in this test + } + rows := []*Row{} + done := make(chan error) + streaming := func() { + // Establish a stream to mock cloud spanner server. + iter := stream(context.Background(), + func(ct context.Context, resumeToken []byte) (streamingReceiver, error) { + r, err := mc.ExecuteStreamingSql(ct, &sppb.ExecuteSqlRequest{ + Sql: "SELECT t.key key, t.value value FROM t_mock t", + ResumeToken: resumeToken, + }) + sr.rpcReceiver = r + return sr, err + }, + nil, + func(error) {}) + defer iter.Stop() + var err error + for { + var row *Row + row, err = iter.Next() + if err == iterator.Done { + err = nil + break + } + if err != nil { + break + } + rows = append(rows, row) + } + done <- err + } + go streaming() + // Server streaming row 0 - 2, only row 1 has resume token. + // Client will receive row 0 - 2, so it will try receiving for + // 4 times (the last recv will block), and only row 0 - 1 will + // be yielded. + for i := 0; i < 3; i++ { + if i == 1 { + ms.AddMsg(nil, true) + } else { + ms.AddMsg(nil, false) + } + } + // Wait for 4 receive attempts, as explained above. + if err := sr.waitn(4); err != nil { + t.Fatalf("failed to wait for row 0 - 2: %v", err) + } + want := []*Row{ + { + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(0)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(0)}}, + }, + }, + { + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(1)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(1)}}, + }, + }, + } + if !testEqual(rows, want) { + t.Errorf("received rows: \n%v\n; but want\n%v\n", rows, want) + } + // Inject resumable failure. + ms.AddMsg( + status.Errorf(codes.Unavailable, "mock server unavailable"), + false, + ) + // Test if client detects the resumable failure and retries. + if err := sr.waitn(1); err != nil { + t.Fatalf("failed to wait for client to retry: %v", err) + } + // Client has resumed the query, now server resend row 2. + ms.AddMsg(nil, true) + if err := sr.waitn(1); err != nil { + t.Fatalf("failed to wait for resending row 2: %v", err) + } + // Now client should have received row 0 - 2. + want = append(want, &Row{ + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(2)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(2)}}, + }, + }) + if !testEqual(rows, want) { + t.Errorf("received rows: \n%v\n, want\n%v\n", rows, want) + } + // Sending 3rd - (maxBuffers+1)th rows without resume tokens, client should buffer them. + for i := 3; i < maxBuffers+2; i++ { + ms.AddMsg(nil, false) + } + if err := sr.waitn(maxBuffers - 1); err != nil { + t.Fatalf("failed to wait for row 3-%v: %v", maxBuffers+1, err) + } + // Received rows should be unchanged. + if !testEqual(rows, want) { + t.Errorf("receive rows: \n%v\n, want\n%v\n", rows, want) + } + // Send (maxBuffers+2)th row to trigger state change of resumableStreamDecoder: + // queueingRetryable -> queueingUnretryable + ms.AddMsg(nil, false) + if err := sr.waitn(1); err != nil { + t.Fatalf("failed to wait for row %v: %v", maxBuffers+2, err) + } + // Client should yield row 3rd - (maxBuffers+2)th to application. Therefore, application should + // see row 0 - (maxBuffers+2)th so far. + for i := 3; i < maxBuffers+3; i++ { + want = append(want, &Row{ + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(i)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(i)}}, + }, + }) + } + if !testEqual(rows, want) { + t.Errorf("received rows: \n%v\n; want\n%v\n", rows, want) + } + // Inject resumable error, but since resumableStreamDecoder is already at queueingUnretryable + // state, query will just fail. + ms.AddMsg( + status.Errorf(codes.Unavailable, "mock server wants some sleep"), + false, + ) + var gotErr error + select { + case gotErr = <-done: + case <-time.After(10 * time.Second): + t.Fatalf("timeout in waiting for failed query to return.") + } + if wantErr := toSpannerError(status.Errorf(codes.Unavailable, "mock server wants some sleep")); !testEqual(gotErr, wantErr) { + t.Fatalf("stream() returns error: %v, but want error: %v", gotErr, wantErr) + } + + // Reconnect to mock Cloud Spanner. + rows = []*Row{} + go streaming() + // Let server send two rows without resume token. + for i := maxBuffers + 3; i < maxBuffers+5; i++ { + ms.AddMsg(nil, false) + } + if err := sr.waitn(3); err != nil { + t.Fatalf("failed to wait for row %v - %v: %v", maxBuffers+3, maxBuffers+5, err) + } + if len(rows) > 0 { + t.Errorf("client received some rows unexpectedly: %v, want nothing", rows) + } + // Let server end the query. + ms.AddMsg(io.EOF, false) + select { + case gotErr = <-done: + case <-time.After(10 * time.Second): + t.Fatalf("timeout in waiting for failed query to return") + } + if gotErr != nil { + t.Fatalf("stream() returns unexpected error: %v, but want no error", gotErr) + } + // Verify if a normal server side EOF flushes all queued rows. + want = []*Row{ + { + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(maxBuffers + 3)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(maxBuffers + 3)}}, + }, + }, + { + fields: kvMeta.RowType.Fields, + vals: []*proto3.Value{ + {Kind: &proto3.Value_StringValue{StringValue: keyStr(maxBuffers + 4)}}, + {Kind: &proto3.Value_StringValue{StringValue: valStr(maxBuffers + 4)}}, + }, + }, + } + if !testEqual(rows, want) { + t.Errorf("received rows: \n%v\n; but want\n%v\n", rows, want) + } +} + +// Verify that streaming query get retried upon real gRPC server transport failures. +func TestGrpcReconnect(t *testing.T) { + restore := setMaxBytesBetweenResumeTokens() + defer restore() + ms := testutil.NewMockCloudSpanner(t, trxTs) + ms.Serve() + defer ms.Stop() + cc := dialMock(t, ms) + defer cc.Close() + mc := sppb.NewSpannerClient(cc) + retry := make(chan int) + row := make(chan int) + var err error + go func() { + r := 0 + // Establish a stream to mock cloud spanner server. + iter := stream(context.Background(), + func(ct context.Context, resumeToken []byte) (streamingReceiver, error) { + if r > 0 { + // This RPC attempt is a retry, signal it. + retry <- r + } + r++ + return mc.ExecuteStreamingSql(ct, &sppb.ExecuteSqlRequest{ + Sql: "SELECT t.key key, t.value value FROM t_mock t", + ResumeToken: resumeToken, + }) + + }, + nil, + func(error) {}) + defer iter.Stop() + for { + _, err = iter.Next() + if err == iterator.Done { + err = nil + break + } + if err != nil { + break + } + row <- 0 + } + }() + // Add a message and wait for the receipt. + ms.AddMsg(nil, true) + select { + case <-row: + case <-time.After(10 * time.Second): + t.Fatalf("expect stream to be established within 10 seconds, but it didn't") + } + // Error injection: force server to close all connections. + ms.Stop() + // Test to see if client respond to the real RPC failure correctly by + // retrying RPC. + select { + case r, ok := <-retry: + if ok && r == 1 { + break + } + t.Errorf("retry count = %v, want 1", r) + case <-time.After(10 * time.Second): + t.Errorf("client library failed to respond after 10 seconds, aborting") + return + } +} + +// Test cancel/timeout for client operations. +func TestCancelTimeout(t *testing.T) { + restore := setMaxBytesBetweenResumeTokens() + defer restore() + ms := testutil.NewMockCloudSpanner(t, trxTs) + ms.Serve() + defer ms.Stop() + cc := dialMock(t, ms) + defer cc.Close() + mc := sppb.NewSpannerClient(cc) + done := make(chan int) + go func() { + for { + ms.AddMsg(nil, true) + } + }() + // Test cancelling query. + ctx, cancel := context.WithCancel(context.Background()) + var err error + go func() { + // Establish a stream to mock cloud spanner server. + iter := stream(ctx, + func(ct context.Context, resumeToken []byte) (streamingReceiver, error) { + return mc.ExecuteStreamingSql(ct, &sppb.ExecuteSqlRequest{ + Sql: "SELECT t.key key, t.value value FROM t_mock t", + ResumeToken: resumeToken, + }) + }, + nil, + func(error) {}) + defer iter.Stop() + for { + _, err = iter.Next() + if err == iterator.Done { + break + } + if err != nil { + done <- 0 + break + } + } + }() + cancel() + select { + case <-done: + if ErrCode(err) != codes.Canceled { + t.Errorf("streaming query is canceled and returns error %v, want error code %v", err, codes.Canceled) + } + case <-time.After(1 * time.Second): + t.Errorf("query doesn't exit timely after being cancelled") + } + // Test query timeout. + ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + go func() { + // Establish a stream to mock cloud spanner server. + iter := stream(ctx, + func(ct context.Context, resumeToken []byte) (streamingReceiver, error) { + return mc.ExecuteStreamingSql(ct, &sppb.ExecuteSqlRequest{ + Sql: "SELECT t.key key, t.value value FROM t_mock t", + ResumeToken: resumeToken, + }) + }, + nil, + func(error) {}) + defer iter.Stop() + for { + _, err = iter.Next() + if err == iterator.Done { + err = nil + break + } + if err != nil { + break + } + } + done <- 0 + }() + select { + case <-done: + if wantErr := codes.DeadlineExceeded; ErrCode(err) != wantErr { + t.Errorf("streaming query timeout returns error %v, want error code %v", err, wantErr) + } + case <-time.After(2 * time.Second): + t.Errorf("query doesn't timeout as expected") + } +} + +func TestRowIteratorDo(t *testing.T) { + restore := setMaxBytesBetweenResumeTokens() + defer restore() + ms := testutil.NewMockCloudSpanner(t, trxTs) + ms.Serve() + defer ms.Stop() + cc := dialMock(t, ms) + defer cc.Close() + mc := sppb.NewSpannerClient(cc) + + for i := 0; i < 3; i++ { + ms.AddMsg(nil, false) + } + ms.AddMsg(io.EOF, true) + nRows := 0 + iter := stream(context.Background(), + func(ct context.Context, resumeToken []byte) (streamingReceiver, error) { + return mc.ExecuteStreamingSql(ct, &sppb.ExecuteSqlRequest{ + Sql: "SELECT t.key key, t.value value FROM t_mock t", + ResumeToken: resumeToken, + }) + }, + nil, + func(error) {}) + err := iter.Do(func(r *Row) error { nRows++; return nil }) + if err != nil { + t.Errorf("Using Do: %v", err) + } + if nRows != 3 { + t.Errorf("got %d rows, want 3", nRows) + } +} + +func TestRowIteratorDoWithError(t *testing.T) { + restore := setMaxBytesBetweenResumeTokens() + defer restore() + ms := testutil.NewMockCloudSpanner(t, trxTs) + ms.Serve() + defer ms.Stop() + cc := dialMock(t, ms) + defer cc.Close() + mc := sppb.NewSpannerClient(cc) + + for i := 0; i < 3; i++ { + ms.AddMsg(nil, false) + } + ms.AddMsg(io.EOF, true) + iter := stream(context.Background(), + func(ct context.Context, resumeToken []byte) (streamingReceiver, error) { + return mc.ExecuteStreamingSql(ct, &sppb.ExecuteSqlRequest{ + Sql: "SELECT t.key key, t.value value FROM t_mock t", + ResumeToken: resumeToken, + }) + }, + nil, + func(error) {}) + injected := errors.New("Failed iterator") + err := iter.Do(func(r *Row) error { return injected }) + if err != injected { + t.Errorf("got <%v>, want <%v>", err, injected) + } +} + +func TestIteratorStopEarly(t *testing.T) { + ctx := context.Background() + restore := setMaxBytesBetweenResumeTokens() + defer restore() + ms := testutil.NewMockCloudSpanner(t, trxTs) + ms.Serve() + defer ms.Stop() + cc := dialMock(t, ms) + defer cc.Close() + mc := sppb.NewSpannerClient(cc) + + ms.AddMsg(nil, false) + ms.AddMsg(nil, false) + ms.AddMsg(io.EOF, true) + + iter := stream(ctx, + func(ct context.Context, resumeToken []byte) (streamingReceiver, error) { + return mc.ExecuteStreamingSql(ct, &sppb.ExecuteSqlRequest{ + Sql: "SELECT t.key key, t.value value FROM t_mock t", + ResumeToken: resumeToken, + }) + }, + nil, + func(error) {}) + _, err := iter.Next() + if err != nil { + t.Fatalf("before Stop: %v", err) + } + iter.Stop() + // Stop sets r.err to the FailedPrecondition error "Next called after Stop". + // Override that here so this test can observe the Canceled error from the stream. + iter.err = nil + iter.Next() + if ErrCode(iter.streamd.lastErr()) != codes.Canceled { + t.Errorf("after Stop: got %v, wanted Canceled", err) + } +} + +func TestIteratorWithError(t *testing.T) { + injected := errors.New("Failed iterator") + iter := RowIterator{err: injected} + defer iter.Stop() + if _, err := iter.Next(); err != injected { + t.Fatalf("Expected error: %v, got %v", injected, err) + } +} + +func dialMock(t *testing.T, ms *testutil.MockCloudSpanner) *grpc.ClientConn { + cc, err := grpc.Dial(ms.Addr(), grpc.WithInsecure(), grpc.WithBlock()) + if err != nil { + t.Fatalf("Dial(%q) = %v", ms.Addr(), err) + } + return cc +} diff --git a/vendor/cloud.google.com/go/spanner/retry.go b/vendor/cloud.google.com/go/spanner/retry.go new file mode 100644 index 00000000..08ae920d --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/retry.go @@ -0,0 +1,199 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + edpb "google.golang.org/genproto/googleapis/rpc/errdetails" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +const ( + retryInfoKey = "google.rpc.retryinfo-bin" +) + +// errRetry returns an unavailable error under error namespace EsOther. It is a +// generic retryable error that is used to mask and recover unretryable errors +// in a retry loop. +func errRetry(err error) error { + if se, ok := err.(*Error); ok { + return &Error{codes.Unavailable, fmt.Sprintf("generic Cloud Spanner retryable error: { %v }", se.Error()), se.trailers} + } + return spannerErrorf(codes.Unavailable, "generic Cloud Spanner retryable error: { %v }", err.Error()) +} + +// isErrorClosing reports whether the error is generated by gRPC layer talking to a closed server. +func isErrorClosing(err error) bool { + if err == nil { + return false + } + if ErrCode(err) == codes.Internal && strings.Contains(ErrDesc(err), "transport is closing") { + // Handle the case when connection is closed unexpectedly. + // TODO: once gRPC is able to categorize + // this as retryable error, we should stop parsing the + // error message here. + return true + } + return false +} + +// isErrorRST reports whether the error is generated by gRPC client receiving a RST frame from server. +func isErrorRST(err error) bool { + if err == nil { + return false + } + if ErrCode(err) == codes.Internal && strings.Contains(ErrDesc(err), "stream terminated by RST_STREAM") { + // TODO: once gRPC is able to categorize this error as "go away" or "retryable", + // we should stop parsing the error message. + return true + } + return false +} + +// isErrorUnexpectedEOF returns true if error is generated by gRPC layer receiving io.EOF unexpectedly. +func isErrorUnexpectedEOF(err error) bool { + if err == nil { + return false + } + // Unexpected EOF is a transport layer issue that could be recovered by + // retries. The most likely scenario is a flaky RecvMsg() call due to + // network issues. + // For grpc version >= 1.14.0, the error code is Internal. + // (https://github.com/grpc/grpc-go/releases/tag/v1.14.0) + if ErrCode(err) == codes.Internal && strings.Contains(ErrDesc(err), "unexpected EOF") { + return true + } + // For grpc version < 1.14.0, the error code in Unknown. + if ErrCode(err) == codes.Unknown && strings.Contains(ErrDesc(err), "unexpected EOF") { + return true + } + return false +} + +// isErrorUnavailable returns true if the error is about server being unavailable. +func isErrorUnavailable(err error) bool { + if err == nil { + return false + } + if ErrCode(err) == codes.Unavailable { + return true + } + return false +} + +// isRetryable returns true if the Cloud Spanner error being checked is a retryable error. +func isRetryable(err error) bool { + if isErrorClosing(err) { + return true + } + if isErrorUnexpectedEOF(err) { + return true + } + if isErrorRST(err) { + return true + } + if isErrorUnavailable(err) { + return true + } + return false +} + +// errContextCanceled returns *spanner.Error for canceled context. +func errContextCanceled(ctx context.Context, lastErr error) error { + if ctx.Err() == context.DeadlineExceeded { + return spannerErrorf(codes.DeadlineExceeded, "%v, lastErr is <%v>", ctx.Err(), lastErr) + } + return spannerErrorf(codes.Canceled, "%v, lastErr is <%v>", ctx.Err(), lastErr) +} + +// extractRetryDelay extracts retry backoff if present. +func extractRetryDelay(err error) (time.Duration, bool) { + trailers := errTrailers(err) + if trailers == nil { + return 0, false + } + elem, ok := trailers[retryInfoKey] + if !ok || len(elem) <= 0 { + return 0, false + } + _, b, err := metadata.DecodeKeyValue(retryInfoKey, elem[0]) + if err != nil { + return 0, false + } + var retryInfo edpb.RetryInfo + if proto.Unmarshal([]byte(b), &retryInfo) != nil { + return 0, false + } + delay, err := ptypes.Duration(retryInfo.RetryDelay) + if err != nil { + return 0, false + } + return delay, true +} + +// runRetryable keeps attempting to run f until one of the following happens: +// 1) f returns nil error or an unretryable error; +// 2) context is cancelled or timeout. +// TODO: consider using https://github.com/googleapis/gax-go once it +// becomes available internally. +func runRetryable(ctx context.Context, f func(context.Context) error) error { + return toSpannerError(runRetryableNoWrap(ctx, f)) +} + +// Like runRetryable, but doesn't wrap the returned error in a spanner.Error. +func runRetryableNoWrap(ctx context.Context, f func(context.Context) error) error { + var funcErr error + retryCount := 0 + for { + select { + case <-ctx.Done(): + // Do context check here so that even f() failed to do + // so (for example, gRPC implementation bug), the loop + // can still have a chance to exit as expected. + return errContextCanceled(ctx, funcErr) + default: + } + funcErr = f(ctx) + if funcErr == nil { + return nil + } + if isRetryable(funcErr) { + // Error is retryable, do exponential backoff and continue. + b, ok := extractRetryDelay(funcErr) + if !ok { + b = defaultBackoff.delay(retryCount) + } + tracePrintf(ctx, nil, "Backing off for %s, then retrying", b) + select { + case <-ctx.Done(): + return errContextCanceled(ctx, funcErr) + case <-time.After(b): + } + retryCount++ + continue + } + // Error isn't retryable / no error, return immediately. + return funcErr + } +} diff --git a/vendor/cloud.google.com/go/spanner/retry_test.go b/vendor/cloud.google.com/go/spanner/retry_test.go new file mode 100644 index 00000000..737bc847 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/retry_test.go @@ -0,0 +1,108 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "context" + "errors" + "fmt" + "testing" + "time" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + edpb "google.golang.org/genproto/googleapis/rpc/errdetails" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Test if runRetryable loop deals with various errors correctly. +func TestRetry(t *testing.T) { + if testing.Short() { + t.SkipNow() + } + responses := []error{ + status.Errorf(codes.Internal, "transport is closing"), + status.Errorf(codes.Unknown, "unexpected EOF"), + status.Errorf(codes.Internal, "unexpected EOF"), + status.Errorf(codes.Internal, "stream terminated by RST_STREAM with error code: 2"), + status.Errorf(codes.Unavailable, "service is currently unavailable"), + errRetry(fmt.Errorf("just retry it")), + } + err := runRetryable(context.Background(), func(ct context.Context) error { + var r error + if len(responses) > 0 { + r = responses[0] + responses = responses[1:] + } + return r + }) + if err != nil { + t.Errorf("runRetryable should be able to survive all retryable errors, but it returns %v", err) + } + // Unretryable errors + injErr := errors.New("this is unretryable") + err = runRetryable(context.Background(), func(ct context.Context) error { + return injErr + }) + if wantErr := toSpannerError(injErr); !testEqual(err, wantErr) { + t.Errorf("runRetryable returns error %v, want %v", err, wantErr) + } + // Timeout + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + retryErr := errRetry(fmt.Errorf("still retrying")) + err = runRetryable(ctx, func(ct context.Context) error { + // Expect to trigger timeout in retryable runner after 10 executions. + <-time.After(100 * time.Millisecond) + // Let retryable runner to retry so that timeout will eventually happen. + return retryErr + }) + // Check error code and error message + if wantErrCode, wantErr := codes.DeadlineExceeded, errContextCanceled(ctx, retryErr); ErrCode(err) != wantErrCode || !testEqual(err, wantErr) { + t.Errorf("=\n<%v, %v>, want:\n<%v, %v>", ErrCode(err), err, wantErrCode, wantErr) + } + // Cancellation + ctx, cancel = context.WithCancel(context.Background()) + retries := 3 + retryErr = errRetry(fmt.Errorf("retry before cancel")) + err = runRetryable(ctx, func(ct context.Context) error { + retries-- + if retries == 0 { + cancel() + } + return retryErr + }) + // Check error code, error message, retry count + if wantErrCode, wantErr := codes.Canceled, errContextCanceled(ctx, retryErr); ErrCode(err) != wantErrCode || !testEqual(err, wantErr) || retries != 0 { + t.Errorf("=\n<%v, %v, %v>, want:\n<%v, %v, %v>", ErrCode(err), err, retries, wantErrCode, wantErr, 0) + } +} + +func TestRetryInfo(t *testing.T) { + b, _ := proto.Marshal(&edpb.RetryInfo{ + RetryDelay: ptypes.DurationProto(time.Second), + }) + trailers := map[string]string{ + retryInfoKey: string(b), + } + gotDelay, ok := extractRetryDelay(errRetry(toSpannerErrorWithMetadata(status.Errorf(codes.Aborted, ""), metadata.New(trailers)))) + if !ok || !testEqual(time.Second, gotDelay) { + t.Errorf(" = <%t, %v>, want ", ok, gotDelay, time.Second) + } +} diff --git a/vendor/cloud.google.com/go/spanner/row.go b/vendor/cloud.google.com/go/spanner/row.go new file mode 100644 index 00000000..0c2337d0 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/row.go @@ -0,0 +1,308 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "fmt" + "reflect" + + proto3 "github.com/golang/protobuf/ptypes/struct" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc/codes" +) + +// A Row is a view of a row of data returned by a Cloud Spanner read. +// It consists of a number of columns; the number depends on the columns +// used to construct the read. +// +// The column values can be accessed by index. For instance, if the read specified +// []string{"photo_id", "caption"}, then each row will contain two +// columns: "photo_id" with index 0, and "caption" with index 1. +// +// Column values are decoded by using one of the Column, ColumnByName, or +// Columns methods. The valid values passed to these methods depend on the +// column type. For example: +// +// var photoID int64 +// err := row.Column(0, &photoID) // Decode column 0 as an integer. +// +// var caption string +// err := row.Column(1, &caption) // Decode column 1 as a string. +// +// // Decode all the columns. +// err := row.Columns(&photoID, &caption) +// +// Supported types and their corresponding Cloud Spanner column type(s) are: +// +// *string(not NULL), *NullString - STRING +// *[]string, *[]NullString - STRING ARRAY +// *[]byte - BYTES +// *[][]byte - BYTES ARRAY +// *int64(not NULL), *NullInt64 - INT64 +// *[]int64, *[]NullInt64 - INT64 ARRAY +// *bool(not NULL), *NullBool - BOOL +// *[]bool, *[]NullBool - BOOL ARRAY +// *float64(not NULL), *NullFloat64 - FLOAT64 +// *[]float64, *[]NullFloat64 - FLOAT64 ARRAY +// *time.Time(not NULL), *NullTime - TIMESTAMP +// *[]time.Time, *[]NullTime - TIMESTAMP ARRAY +// *Date(not NULL), *NullDate - DATE +// *[]civil.Date, *[]NullDate - DATE ARRAY +// *[]*some_go_struct, *[]NullRow - STRUCT ARRAY +// *GenericColumnValue - any Cloud Spanner type +// +// For TIMESTAMP columns, the returned time.Time object will be in UTC. +// +// To fetch an array of BYTES, pass a *[][]byte. To fetch an array of (sub)rows, pass +// a *[]spanner.NullRow or a *[]*some_go_struct where some_go_struct holds all +// information of the subrow, see spanner.Row.ToStruct for the mapping between a +// Cloud Spanner row and a Go struct. To fetch an array of other types, pass a +// *[]spanner.NullXXX type of the appropriate type. Use GenericColumnValue when you +// don't know in advance what column type to expect. +// +// Row decodes the row contents lazily; as a result, each call to a getter has +// a chance of returning an error. +// +// A column value may be NULL if the corresponding value is not present in +// Cloud Spanner. The spanner.NullXXX types (spanner.NullInt64 et al.) allow fetching +// values that may be null. A NULL BYTES can be fetched into a *[]byte as nil. +// It is an error to fetch a NULL value into any other type. +type Row struct { + fields []*sppb.StructType_Field + vals []*proto3.Value // keep decoded for now +} + +// errNamesValuesMismatch returns error for when columnNames count is not equal +// to columnValues count. +func errNamesValuesMismatch(columnNames []string, columnValues []interface{}) error { + return spannerErrorf(codes.FailedPrecondition, + "different number of names(%v) and values(%v)", len(columnNames), len(columnValues)) +} + +// NewRow returns a Row containing the supplied data. This can be useful for +// mocking Cloud Spanner Read and Query responses for unit testing. +func NewRow(columnNames []string, columnValues []interface{}) (*Row, error) { + if len(columnValues) != len(columnNames) { + return nil, errNamesValuesMismatch(columnNames, columnValues) + } + r := Row{ + fields: make([]*sppb.StructType_Field, len(columnValues)), + vals: make([]*proto3.Value, len(columnValues)), + } + for i := range columnValues { + val, typ, err := encodeValue(columnValues[i]) + if err != nil { + return nil, err + } + r.fields[i] = &sppb.StructType_Field{ + Name: columnNames[i], + Type: typ, + } + r.vals[i] = val + } + return &r, nil +} + +// Size is the number of columns in the row. +func (r *Row) Size() int { + return len(r.fields) +} + +// ColumnName returns the name of column i, or empty string for invalid column. +func (r *Row) ColumnName(i int) string { + if i < 0 || i >= len(r.fields) { + return "" + } + return r.fields[i].Name +} + +// ColumnIndex returns the index of the column with the given name. The +// comparison is case-sensitive. +func (r *Row) ColumnIndex(name string) (int, error) { + found := false + var index int + if len(r.vals) != len(r.fields) { + return 0, errFieldsMismatchVals(r) + } + for i, f := range r.fields { + if f == nil { + return 0, errNilColType(i) + } + if name == f.Name { + if found { + return 0, errDupColName(name) + } + found = true + index = i + } + } + if !found { + return 0, errColNotFound(name) + } + return index, nil +} + +// ColumnNames returns all column names of the row. +func (r *Row) ColumnNames() []string { + var n []string + for _, c := range r.fields { + n = append(n, c.Name) + } + return n +} + +// errColIdxOutOfRange returns error for requested column index is out of the +// range of the target Row's columns. +func errColIdxOutOfRange(i int, r *Row) error { + return spannerErrorf(codes.OutOfRange, "column index %d out of range [0,%d)", i, len(r.vals)) +} + +// errDecodeColumn returns error for not being able to decode a indexed column. +func errDecodeColumn(i int, err error) error { + if err == nil { + return nil + } + se, ok := toSpannerError(err).(*Error) + if !ok { + return spannerErrorf(codes.InvalidArgument, "failed to decode column %v, error = <%v>", i, err) + } + se.decorate(fmt.Sprintf("failed to decode column %v", i)) + return se +} + +// errFieldsMismatchVals returns error for field count isn't equal to value count in a Row. +func errFieldsMismatchVals(r *Row) error { + return spannerErrorf(codes.FailedPrecondition, "row has different number of fields(%v) and values(%v)", + len(r.fields), len(r.vals)) +} + +// errNilColType returns error for column type for column i being nil in the row. +func errNilColType(i int) error { + return spannerErrorf(codes.FailedPrecondition, "column(%v)'s type is nil", i) +} + +// Column fetches the value from the ith column, decoding it into ptr. +// See the Row documentation for the list of acceptable argument types. +// see Client.ReadWriteTransaction for an example. +func (r *Row) Column(i int, ptr interface{}) error { + if len(r.vals) != len(r.fields) { + return errFieldsMismatchVals(r) + } + if i < 0 || i >= len(r.fields) { + return errColIdxOutOfRange(i, r) + } + if r.fields[i] == nil { + return errNilColType(i) + } + if err := decodeValue(r.vals[i], r.fields[i].Type, ptr); err != nil { + return errDecodeColumn(i, err) + } + return nil +} + +// errDupColName returns error for duplicated column name in the same row. +func errDupColName(n string) error { + return spannerErrorf(codes.FailedPrecondition, "ambiguous column name %q", n) +} + +// errColNotFound returns error for not being able to find a named column. +func errColNotFound(n string) error { + return spannerErrorf(codes.NotFound, "column %q not found", n) +} + +// ColumnByName fetches the value from the named column, decoding it into ptr. +// See the Row documentation for the list of acceptable argument types. +func (r *Row) ColumnByName(name string, ptr interface{}) error { + index, err := r.ColumnIndex(name) + if err != nil { + return err + } + return r.Column(index, ptr) +} + +// errNumOfColValue returns error for providing wrong number of values to Columns. +func errNumOfColValue(n int, r *Row) error { + return spannerErrorf(codes.InvalidArgument, + "Columns(): number of arguments (%d) does not match row size (%d)", n, len(r.vals)) +} + +// Columns fetches all the columns in the row at once. +// +// The value of the kth column will be decoded into the kth argument to Columns. See +// Row for the list of acceptable argument types. The number of arguments must be +// equal to the number of columns. Pass nil to specify that a column should be +// ignored. +func (r *Row) Columns(ptrs ...interface{}) error { + if len(ptrs) != len(r.vals) { + return errNumOfColValue(len(ptrs), r) + } + if len(r.vals) != len(r.fields) { + return errFieldsMismatchVals(r) + } + for i, p := range ptrs { + if p == nil { + continue + } + if err := r.Column(i, p); err != nil { + return err + } + } + return nil +} + +// errToStructArgType returns error for p not having the correct data type(pointer to Go struct) to +// be the argument of Row.ToStruct. +func errToStructArgType(p interface{}) error { + return spannerErrorf(codes.InvalidArgument, "ToStruct(): type %T is not a valid pointer to Go struct", p) +} + +// ToStruct fetches the columns in a row into the fields of a struct. +// The rules for mapping a row's columns into a struct's exported fields +// are: +// +// 1. If a field has a `spanner: "column_name"` tag, then decode column +// 'column_name' into the field. A special case is the `spanner: "-"` +// tag, which instructs ToStruct to ignore the field during decoding. +// +// 2. Otherwise, if the name of a field matches the name of a column (ignoring case), +// decode the column into the field. +// +// The fields of the destination struct can be of any type that is acceptable +// to spanner.Row.Column. +// +// Slice and pointer fields will be set to nil if the source column is NULL, and a +// non-nil value if the column is not NULL. To decode NULL values of other types, use +// one of the spanner.NullXXX types as the type of the destination field. +// +// If ToStruct returns an error, the contents of p are undefined. Some fields may +// have been successfully populated, while others were not; you should not use any of +// the fields. +func (r *Row) ToStruct(p interface{}) error { + // Check if p is a pointer to a struct + if t := reflect.TypeOf(p); t == nil || t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct { + return errToStructArgType(p) + } + if len(r.vals) != len(r.fields) { + return errFieldsMismatchVals(r) + } + // Call decodeStruct directly to decode the row as a typed proto.ListValue. + return decodeStruct( + &sppb.StructType{Fields: r.fields}, + &proto3.ListValue{Values: r.vals}, + p, + ) +} diff --git a/vendor/cloud.google.com/go/spanner/row_test.go b/vendor/cloud.google.com/go/spanner/row_test.go new file mode 100644 index 00000000..2a3ab8fd --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/row_test.go @@ -0,0 +1,1636 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "encoding/base64" + "reflect" + "strconv" + "strings" + "testing" + "time" + + "cloud.google.com/go/civil" + proto "github.com/golang/protobuf/proto" + proto3 "github.com/golang/protobuf/ptypes/struct" + sppb "google.golang.org/genproto/googleapis/spanner/v1" +) + +var ( + tm = time.Date(2016, 11, 15, 0, 0, 0, 0, time.UTC) + dt, _ = civil.ParseDate("2016-11-15") + // row contains a column for each unique Cloud Spanner type. + row = Row{ + []*sppb.StructType_Field{ + // STRING / STRING ARRAY + {Name: "STRING", Type: stringType()}, + {Name: "NULL_STRING", Type: stringType()}, + {Name: "STRING_ARRAY", Type: listType(stringType())}, + {Name: "NULL_STRING_ARRAY", Type: listType(stringType())}, + // BYTES / BYTES ARRAY + {Name: "BYTES", Type: bytesType()}, + {Name: "NULL_BYTES", Type: bytesType()}, + {Name: "BYTES_ARRAY", Type: listType(bytesType())}, + {Name: "NULL_BYTES_ARRAY", Type: listType(bytesType())}, + // INT64 / INT64 ARRAY + {Name: "INT64", Type: intType()}, + {Name: "NULL_INT64", Type: intType()}, + {Name: "INT64_ARRAY", Type: listType(intType())}, + {Name: "NULL_INT64_ARRAY", Type: listType(intType())}, + // BOOL / BOOL ARRAY + {Name: "BOOL", Type: boolType()}, + {Name: "NULL_BOOL", Type: boolType()}, + {Name: "BOOL_ARRAY", Type: listType(boolType())}, + {Name: "NULL_BOOL_ARRAY", Type: listType(boolType())}, + // FLOAT64 / FLOAT64 ARRAY + {Name: "FLOAT64", Type: floatType()}, + {Name: "NULL_FLOAT64", Type: floatType()}, + {Name: "FLOAT64_ARRAY", Type: listType(floatType())}, + {Name: "NULL_FLOAT64_ARRAY", Type: listType(floatType())}, + // TIMESTAMP / TIMESTAMP ARRAY + {Name: "TIMESTAMP", Type: timeType()}, + {Name: "NULL_TIMESTAMP", Type: timeType()}, + {Name: "TIMESTAMP_ARRAY", Type: listType(timeType())}, + {Name: "NULL_TIMESTAMP_ARRAY", Type: listType(timeType())}, + // DATE / DATE ARRAY + {Name: "DATE", Type: dateType()}, + {Name: "NULL_DATE", Type: dateType()}, + {Name: "DATE_ARRAY", Type: listType(dateType())}, + {Name: "NULL_DATE_ARRAY", Type: listType(dateType())}, + + // STRUCT ARRAY + { + Name: "STRUCT_ARRAY", + Type: listType( + structType( + mkField("Col1", intType()), + mkField("Col2", floatType()), + mkField("Col3", stringType()), + ), + ), + }, + { + Name: "NULL_STRUCT_ARRAY", + Type: listType( + structType( + mkField("Col1", intType()), + mkField("Col2", floatType()), + mkField("Col3", stringType()), + ), + ), + }, + }, + []*proto3.Value{ + // STRING / STRING ARRAY + stringProto("value"), + nullProto(), + listProto(stringProto("value1"), nullProto(), stringProto("value3")), + nullProto(), + // BYTES / BYTES ARRAY + bytesProto([]byte("value")), + nullProto(), + listProto(bytesProto([]byte("value1")), nullProto(), bytesProto([]byte("value3"))), + nullProto(), + // INT64 / INT64 ARRAY + intProto(17), + nullProto(), + listProto(intProto(1), intProto(2), nullProto()), + nullProto(), + // BOOL / BOOL ARRAY + boolProto(true), + nullProto(), + listProto(nullProto(), boolProto(true), boolProto(false)), + nullProto(), + // FLOAT64 / FLOAT64 ARRAY + floatProto(1.7), + nullProto(), + listProto(nullProto(), nullProto(), floatProto(1.7)), + nullProto(), + // TIMESTAMP / TIMESTAMP ARRAY + timeProto(tm), + nullProto(), + listProto(nullProto(), timeProto(tm)), + nullProto(), + // DATE / DATE ARRAY + dateProto(dt), + nullProto(), + listProto(nullProto(), dateProto(dt)), + nullProto(), + // STRUCT ARRAY + listProto( + nullProto(), + listProto(intProto(3), floatProto(33.3), stringProto("three")), + nullProto(), + ), + nullProto(), + }, + } +) + +// Test helpers for getting column values. +func TestColumnValues(t *testing.T) { + vals := []interface{}{} + wantVals := []interface{}{} + // Test getting column values. + for i, wants := range [][]interface{}{ + // STRING / STRING ARRAY + {"value", NullString{"value", true}}, + {NullString{}}, + {[]NullString{{"value1", true}, {}, {"value3", true}}}, + {[]NullString(nil)}, + // BYTES / BYTES ARRAY + {[]byte("value")}, + {[]byte(nil)}, + {[][]byte{[]byte("value1"), nil, []byte("value3")}}, + {[][]byte(nil)}, + // INT64 / INT64 ARRAY + {int64(17), NullInt64{17, true}}, + {NullInt64{}}, + {[]NullInt64{{1, true}, {2, true}, {}}}, + {[]NullInt64(nil)}, + // BOOL / BOOL ARRAY + {true, NullBool{true, true}}, + {NullBool{}}, + {[]NullBool{{}, {true, true}, {false, true}}}, + {[]NullBool(nil)}, + // FLOAT64 / FLOAT64 ARRAY + {1.7, NullFloat64{1.7, true}}, + {NullFloat64{}}, + {[]NullFloat64{{}, {}, {1.7, true}}}, + {[]NullFloat64(nil)}, + // TIMESTAMP / TIMESTAMP ARRAY + {tm, NullTime{tm, true}}, + {NullTime{}}, + {[]NullTime{{}, {tm, true}}}, + {[]NullTime(nil)}, + // DATE / DATE ARRAY + {dt, NullDate{dt, true}}, + {NullDate{}}, + {[]NullDate{{}, {dt, true}}}, + {[]NullDate(nil)}, + // STRUCT ARRAY + { + []*struct { + Col1 NullInt64 + Col2 NullFloat64 + Col3 string + }{ + nil, + + { + NullInt64{3, true}, + NullFloat64{33.3, true}, + "three", + }, + nil, + }, + []NullRow{ + {}, + { + Row: Row{ + fields: []*sppb.StructType_Field{ + mkField("Col1", intType()), + mkField("Col2", floatType()), + mkField("Col3", stringType()), + }, + vals: []*proto3.Value{ + intProto(3), + floatProto(33.3), + stringProto("three"), + }, + }, + Valid: true, + }, + {}, + }, + }, + { + []*struct { + Col1 NullInt64 + Col2 NullFloat64 + Col3 string + }(nil), + []NullRow(nil), + }, + } { + for j, want := range wants { + // Prepare Value vector to test Row.Columns. + if j == 0 { + vals = append(vals, reflect.New(reflect.TypeOf(want)).Interface()) + wantVals = append(wantVals, want) + } + // Column + gotp := reflect.New(reflect.TypeOf(want)) + err := row.Column(i, gotp.Interface()) + if err != nil { + t.Errorf("\t row.Column(%v, %T) returns error: %v, want nil", i, gotp.Interface(), err) + } + if got := reflect.Indirect(gotp).Interface(); !testEqual(got, want) { + t.Errorf("\t row.Column(%v, %T) retrives %v, want %v", i, gotp.Interface(), got, want) + } + // ColumnByName + gotp = reflect.New(reflect.TypeOf(want)) + err = row.ColumnByName(row.fields[i].Name, gotp.Interface()) + if err != nil { + t.Errorf("\t row.ColumnByName(%v, %T) returns error: %v, want nil", row.fields[i].Name, gotp.Interface(), err) + } + if got := reflect.Indirect(gotp).Interface(); !testEqual(got, want) { + t.Errorf("\t row.ColumnByName(%v, %T) retrives %v, want %v", row.fields[i].Name, gotp.Interface(), got, want) + } + } + } + // Test Row.Columns. + if err := row.Columns(vals...); err != nil { + t.Errorf("row.Columns() returns error: %v, want nil", err) + } + for i, want := range wantVals { + if got := reflect.Indirect(reflect.ValueOf(vals[i])).Interface(); !testEqual(got, want) { + t.Errorf("\t got %v(%T) for column[%v], want %v(%T)", got, got, row.fields[i].Name, want, want) + } + } +} + +// Test decoding into nil destination. +func TestNilDst(t *testing.T) { + for i, test := range []struct { + r *Row + dst interface{} + wantErr error + structDst interface{} + wantToStructErr error + }{ + { + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: stringType()}, + }, + []*proto3.Value{stringProto("value")}, + }, + nil, + errDecodeColumn(0, errNilDst(nil)), + nil, + errToStructArgType(nil), + }, + { + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: stringType()}, + }, + []*proto3.Value{stringProto("value")}, + }, + (*string)(nil), + errDecodeColumn(0, errNilDst((*string)(nil))), + (*struct{ STRING string })(nil), + errNilDst((*struct{ STRING string })(nil)), + }, + { + &Row{ + []*sppb.StructType_Field{ + { + Name: "Col0", + Type: listType( + structType( + mkField("Col1", intType()), + mkField("Col2", floatType()), + ), + ), + }, + }, + []*proto3.Value{listProto( + listProto(intProto(3), floatProto(33.3)), + )}, + }, + (*[]*struct { + Col1 int + Col2 float64 + })(nil), + errDecodeColumn(0, errNilDst((*[]*struct { + Col1 int + Col2 float64 + })(nil))), + (*struct { + StructArray []*struct { + Col1 int + Col2 float64 + } `spanner:"STRUCT_ARRAY"` + })(nil), + errNilDst((*struct { + StructArray []*struct { + Col1 int + Col2 float64 + } `spanner:"STRUCT_ARRAY"` + })(nil)), + }, + } { + if gotErr := test.r.Column(0, test.dst); !testEqual(gotErr, test.wantErr) { + t.Errorf("%v: test.r.Column() returns error %v, want %v", i, gotErr, test.wantErr) + } + if gotErr := test.r.ColumnByName("Col0", test.dst); !testEqual(gotErr, test.wantErr) { + t.Errorf("%v: test.r.ColumnByName() returns error %v, want %v", i, gotErr, test.wantErr) + } + // Row.Columns(T) should return nil on T == nil, otherwise, it should return test.wantErr. + wantColumnsErr := test.wantErr + if test.dst == nil { + wantColumnsErr = nil + } + if gotErr := test.r.Columns(test.dst); !testEqual(gotErr, wantColumnsErr) { + t.Errorf("%v: test.r.Columns() returns error %v, want %v", i, gotErr, wantColumnsErr) + } + if gotErr := test.r.ToStruct(test.structDst); !testEqual(gotErr, test.wantToStructErr) { + t.Errorf("%v: test.r.ToStruct() returns error %v, want %v", i, gotErr, test.wantToStructErr) + } + } +} + +// Test decoding NULL columns using Go types that don't support NULL. +func TestNullTypeErr(t *testing.T) { + var tm time.Time + ntoi := func(n string) int { + for i, f := range row.fields { + if f.Name == n { + return i + } + } + t.Errorf("cannot find column name %q in row", n) + return 0 + } + for _, test := range []struct { + colName string + dst interface{} + }{ + { + "NULL_STRING", + proto.String(""), + }, + { + "NULL_INT64", + proto.Int64(0), + }, + { + "NULL_BOOL", + proto.Bool(false), + }, + { + "NULL_FLOAT64", + proto.Float64(0.0), + }, + { + "NULL_TIMESTAMP", + &tm, + }, + { + "NULL_DATE", + &dt, + }, + } { + wantErr := errDecodeColumn(ntoi(test.colName), errDstNotForNull(test.dst)) + if gotErr := row.ColumnByName(test.colName, test.dst); !testEqual(gotErr, wantErr) { + t.Errorf("row.ColumnByName(%v) returns error %v, want %v", test.colName, gotErr, wantErr) + } + } +} + +// Test using wrong destination type in column decoders. +func TestColumnTypeErr(t *testing.T) { + // badDst cannot hold any of the column values. + badDst := &struct{}{} + for i, f := range row.fields { // For each of the columns, try to decode it into badDst. + tc := f.Type.Code + var etc sppb.TypeCode + if strings.Contains(f.Name, "ARRAY") { + etc = f.Type.ArrayElementType.Code + } + wantErr := errDecodeColumn(i, errTypeMismatch(tc, etc, badDst)) + if gotErr := row.Column(i, badDst); !testEqual(gotErr, wantErr) { + t.Errorf("Column(%v): decoding into destination with wrong type %T returns error %v, want %v", + i, badDst, gotErr, wantErr) + } + if gotErr := row.ColumnByName(f.Name, badDst); !testEqual(gotErr, wantErr) { + t.Errorf("ColumnByName(%v): decoding into destination with wrong type %T returns error %v, want %v", + f.Name, badDst, gotErr, wantErr) + } + } + wantErr := errDecodeColumn(1, errTypeMismatch(sppb.TypeCode_STRING, sppb.TypeCode_TYPE_CODE_UNSPECIFIED, badDst)) + // badDst is used to receive column 1. + vals := []interface{}{nil, badDst} // Row.Column() is expected to fail at column 1. + // Skip decoding the rest columns by providing nils as the destinations. + for i := 2; i < len(row.fields); i++ { + vals = append(vals, nil) + } + if gotErr := row.Columns(vals...); !testEqual(gotErr, wantErr) { + t.Errorf("Columns(): decoding column 1 with wrong type %T returns error %v, want %v", + badDst, gotErr, wantErr) + } +} + +// Test the handling of invalid column decoding requests which cannot be mapped to correct column(s). +func TestInvalidColumnRequest(t *testing.T) { + for _, test := range []struct { + desc string + f func() error + wantErr error + }{ + { + "Request column index is out of range", + func() error { + return row.Column(10000, &struct{}{}) + }, + errColIdxOutOfRange(10000, &row), + }, + { + "Cannot find the named column", + func() error { + return row.ColumnByName("string", &struct{}{}) + }, + errColNotFound("string"), + }, + { + "Not enough arguments to call row.Columns()", + func() error { + return row.Columns(nil, nil) + }, + errNumOfColValue(2, &row), + }, + { + "Call ColumnByName on row with duplicated column names", + func() error { + var s string + r := &Row{ + []*sppb.StructType_Field{ + {Name: "Val", Type: stringType()}, + {Name: "Val", Type: stringType()}, + }, + []*proto3.Value{stringProto("value1"), stringProto("value2")}, + } + return r.ColumnByName("Val", &s) + }, + errDupColName("Val"), + }, + { + "Call ToStruct on row with duplicated column names", + func() error { + s := &struct { + Val string + }{} + r := &Row{ + []*sppb.StructType_Field{ + {Name: "Val", Type: stringType()}, + {Name: "Val", Type: stringType()}, + }, + []*proto3.Value{stringProto("value1"), stringProto("value2")}, + } + return r.ToStruct(s) + }, + errDupSpannerField("Val", &sppb.StructType{ + Fields: []*sppb.StructType_Field{ + {Name: "Val", Type: stringType()}, + {Name: "Val", Type: stringType()}, + }, + }), + }, + { + "Call ToStruct on a row with unnamed field", + func() error { + s := &struct { + Val string + }{} + r := &Row{ + []*sppb.StructType_Field{ + {Name: "", Type: stringType()}, + }, + []*proto3.Value{stringProto("value1")}, + } + return r.ToStruct(s) + }, + errUnnamedField(&sppb.StructType{Fields: []*sppb.StructType_Field{ + {Name: "", Type: stringType()}, + }}, 0), + }, + } { + if gotErr := test.f(); !testEqual(gotErr, test.wantErr) { + t.Errorf("%v: test.f() returns error %v, want %v", test.desc, gotErr, test.wantErr) + } + } +} + +// Test decoding the row with row.ToStruct into an invalid destination. +func TestToStructInvalidDst(t *testing.T) { + for _, test := range []struct { + desc string + dst interface{} + wantErr error + }{ + { + "Decode row as STRUCT into int32", + proto.Int(1), + errToStructArgType(proto.Int(1)), + }, + { + "Decode row as STRUCT to nil Go struct", + (*struct{})(nil), + errNilDst((*struct{})(nil)), + }, + { + "Decode row as STRUCT to Go struct with duplicated fields for the PK column", + &struct { + PK1 string `spanner:"STRING"` + PK2 string `spanner:"STRING"` + }{}, + errNoOrDupGoField(&struct { + PK1 string `spanner:"STRING"` + PK2 string `spanner:"STRING"` + }{}, "STRING"), + }, + { + "Decode row as STRUCT to Go struct with no field for the PK column", + &struct { + PK1 string `spanner:"_STRING"` + }{}, + errNoOrDupGoField(&struct { + PK1 string `spanner:"_STRING"` + }{}, "STRING"), + }, + { + "Decode row as STRUCT to Go struct with wrong type for the PK column", + &struct { + PK1 int64 `spanner:"STRING"` + }{}, + errDecodeStructField(&sppb.StructType{Fields: row.fields}, "STRING", + errTypeMismatch(sppb.TypeCode_STRING, sppb.TypeCode_TYPE_CODE_UNSPECIFIED, proto.Int64(0))), + }, + } { + if gotErr := row.ToStruct(test.dst); !testEqual(gotErr, test.wantErr) { + t.Errorf("%v: decoding:\ngot %v\nwant %v", test.desc, gotErr, test.wantErr) + } + } +} + +// Test decoding a broken row. +func TestBrokenRow(t *testing.T) { + for i, test := range []struct { + row *Row + dst interface{} + wantErr error + }{ + { + // A row with no field. + &Row{ + []*sppb.StructType_Field{}, + []*proto3.Value{stringProto("value")}, + }, + &NullString{"value", true}, + errFieldsMismatchVals(&Row{ + []*sppb.StructType_Field{}, + []*proto3.Value{stringProto("value")}, + }), + }, + { + // A row with nil field. + &Row{ + []*sppb.StructType_Field{nil}, + []*proto3.Value{stringProto("value")}, + }, + &NullString{"value", true}, + errNilColType(0), + }, + { + // Field is not nil, but its type is nil. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: nil}, + }, + []*proto3.Value{listProto(stringProto("value1"), stringProto("value2"))}, + }, + &[]NullString{}, + errDecodeColumn(0, errNilSpannerType()), + }, + { + // Field is not nil, field type is not nil, but it is an array and its array element type is nil. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: &sppb.Type{Code: sppb.TypeCode_ARRAY}}, + }, + []*proto3.Value{listProto(stringProto("value1"), stringProto("value2"))}, + }, + &[]NullString{}, + errDecodeColumn(0, errNilArrElemType(&sppb.Type{Code: sppb.TypeCode_ARRAY})), + }, + { + // Field specifies valid type, value is nil. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: intType()}, + }, + []*proto3.Value{nil}, + }, + &NullInt64{1, true}, + errDecodeColumn(0, errNilSrc()), + }, + { + // Field specifies INT64 type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: intType()}, + }, + []*proto3.Value{{Kind: (*proto3.Value_StringValue)(nil)}}, + }, + &NullInt64{1, true}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_StringValue)(nil)}, "String")), + }, + { + // Field specifies INT64 type, but value is for Number type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: intType()}, + }, + []*proto3.Value{floatProto(1.0)}, + }, + &NullInt64{1, true}, + errDecodeColumn(0, errSrcVal(floatProto(1.0), "String")), + }, + { + // Field specifies INT64 type, but value is wrongly encoded. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: intType()}, + }, + []*proto3.Value{stringProto("&1")}, + }, + proto.Int64(0), + errDecodeColumn(0, errBadEncoding(stringProto("&1"), func() error { + _, err := strconv.ParseInt("&1", 10, 64) + return err + }())), + }, + { + // Field specifies INT64 type, but value is wrongly encoded. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: intType()}, + }, + []*proto3.Value{stringProto("&1")}, + }, + &NullInt64{}, + errDecodeColumn(0, errBadEncoding(stringProto("&1"), func() error { + _, err := strconv.ParseInt("&1", 10, 64) + return err + }())), + }, + { + // Field specifies STRING type, but value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: stringType()}, + }, + []*proto3.Value{{Kind: (*proto3.Value_StringValue)(nil)}}, + }, + &NullString{"value", true}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_StringValue)(nil)}, "String")), + }, + { + // Field specifies STRING type, but value is for ARRAY type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: stringType()}, + }, + []*proto3.Value{listProto(stringProto("value"))}, + }, + &NullString{"value", true}, + errDecodeColumn(0, errSrcVal(listProto(stringProto("value")), "String")), + }, + { + // Field specifies FLOAT64 type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: floatType()}, + }, + []*proto3.Value{{Kind: (*proto3.Value_NumberValue)(nil)}}, + }, + &NullFloat64{1.0, true}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_NumberValue)(nil)}, "Number")), + }, + { + // Field specifies FLOAT64 type, but value is for BOOL type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: floatType()}, + }, + []*proto3.Value{boolProto(true)}, + }, + &NullFloat64{1.0, true}, + errDecodeColumn(0, errSrcVal(boolProto(true), "Number")), + }, + { + // Field specifies FLOAT64 type, but value is wrongly encoded. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: floatType()}, + }, + []*proto3.Value{stringProto("nan")}, + }, + &NullFloat64{}, + errDecodeColumn(0, errUnexpectedNumStr("nan")), + }, + { + // Field specifies FLOAT64 type, but value is wrongly encoded. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: floatType()}, + }, + []*proto3.Value{stringProto("nan")}, + }, + proto.Float64(0), + errDecodeColumn(0, errUnexpectedNumStr("nan")), + }, + { + // Field specifies BYTES type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: bytesType()}, + }, + []*proto3.Value{{Kind: (*proto3.Value_StringValue)(nil)}}, + }, + &[]byte{}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_StringValue)(nil)}, "String")), + }, + { + // Field specifies BYTES type, but value is for BOOL type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: bytesType()}, + }, + []*proto3.Value{boolProto(false)}, + }, + &[]byte{}, + errDecodeColumn(0, errSrcVal(boolProto(false), "String")), + }, + { + // Field specifies BYTES type, but value is wrongly encoded. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: bytesType()}, + }, + []*proto3.Value{stringProto("&&")}, + }, + &[]byte{}, + errDecodeColumn(0, errBadEncoding(stringProto("&&"), func() error { + _, err := base64.StdEncoding.DecodeString("&&") + return err + }())), + }, + { + // Field specifies BOOL type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: boolType()}, + }, + []*proto3.Value{{Kind: (*proto3.Value_BoolValue)(nil)}}, + }, + &NullBool{false, true}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_BoolValue)(nil)}, "Bool")), + }, + { + // Field specifies BOOL type, but value is for STRING type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: boolType()}, + }, + []*proto3.Value{stringProto("false")}, + }, + &NullBool{false, true}, + errDecodeColumn(0, errSrcVal(stringProto("false"), "Bool")), + }, + { + // Field specifies TIMESTAMP type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: timeType()}, + }, + []*proto3.Value{{Kind: (*proto3.Value_StringValue)(nil)}}, + }, + &NullTime{time.Now(), true}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_StringValue)(nil)}, "String")), + }, + { + // Field specifies TIMESTAMP type, but value is for BOOL type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: timeType()}, + }, + []*proto3.Value{boolProto(false)}, + }, + &NullTime{time.Now(), true}, + errDecodeColumn(0, errSrcVal(boolProto(false), "String")), + }, + { + // Field specifies TIMESTAMP type, but value is invalid timestamp. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: timeType()}, + }, + []*proto3.Value{stringProto("junk")}, + }, + &NullTime{time.Now(), true}, + errDecodeColumn(0, errBadEncoding(stringProto("junk"), func() error { + _, err := time.Parse(time.RFC3339Nano, "junk") + return err + }())), + }, + { + // Field specifies DATE type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: dateType()}, + }, + []*proto3.Value{{Kind: (*proto3.Value_StringValue)(nil)}}, + }, + &NullDate{civil.Date{}, true}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_StringValue)(nil)}, "String")), + }, + { + // Field specifies DATE type, but value is for BOOL type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: dateType()}, + }, + []*proto3.Value{boolProto(false)}, + }, + &NullDate{civil.Date{}, true}, + errDecodeColumn(0, errSrcVal(boolProto(false), "String")), + }, + { + // Field specifies DATE type, but value is invalid timestamp. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: dateType()}, + }, + []*proto3.Value{stringProto("junk")}, + }, + &NullDate{civil.Date{}, true}, + errDecodeColumn(0, errBadEncoding(stringProto("junk"), func() error { + _, err := civil.ParseDate("junk") + return err + }())), + }, + + { + // Field specifies ARRAY type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(intType())}, + }, + []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, + }, + &[]NullInt64{}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), + }, + { + // Field specifies ARRAY type, value is having a nil ListValue. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(intType())}, + }, + []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, + }, + &[]NullInt64{}, + errDecodeColumn(0, errNilListValue("INT64")), + }, + { + // Field specifies ARRAY type, but value is for BYTES type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(intType())}, + }, + []*proto3.Value{bytesProto([]byte("value"))}, + }, + &[]NullInt64{}, + errDecodeColumn(0, errSrcVal(bytesProto([]byte("value")), "List")), + }, + { + // Field specifies ARRAY type, but value is for ARRAY type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(intType())}, + }, + []*proto3.Value{listProto(boolProto(true))}, + }, + &[]NullInt64{}, + errDecodeColumn(0, errDecodeArrayElement(0, boolProto(true), + "INT64", errSrcVal(boolProto(true), "String"))), + }, + { + // Field specifies ARRAY type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(stringType())}, + }, + []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, + }, + &[]NullString{}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), + }, + { + // Field specifies ARRAY type, value is having a nil ListValue. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(stringType())}, + }, + []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, + }, + &[]NullString{}, + errDecodeColumn(0, errNilListValue("STRING")), + }, + { + // Field specifies ARRAY type, but value is for BOOL type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(stringType())}, + }, + []*proto3.Value{boolProto(true)}, + }, + &[]NullString{}, + errDecodeColumn(0, errSrcVal(boolProto(true), "List")), + }, + { + // Field specifies ARRAY type, but value is for ARRAY type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(stringType())}, + }, + []*proto3.Value{listProto(boolProto(true))}, + }, + &[]NullString{}, + errDecodeColumn(0, errDecodeArrayElement(0, boolProto(true), + "STRING", errSrcVal(boolProto(true), "String"))), + }, + { + // Field specifies ARRAY type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(floatType())}, + }, + []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, + }, + &[]NullFloat64{}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), + }, + { + // Field specifies ARRAY type, value is having a nil ListValue. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(floatType())}, + }, + []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, + }, + &[]NullFloat64{}, + errDecodeColumn(0, errNilListValue("FLOAT64")), + }, + { + // Field specifies ARRAY type, but value is for STRING type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(floatType())}, + }, + []*proto3.Value{stringProto("value")}, + }, + &[]NullFloat64{}, + errDecodeColumn(0, errSrcVal(stringProto("value"), "List")), + }, + { + // Field specifies ARRAY type, but value is for ARRAY type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(floatType())}, + }, + []*proto3.Value{listProto(boolProto(true))}, + }, + &[]NullFloat64{}, + errDecodeColumn(0, errDecodeArrayElement(0, boolProto(true), + "FLOAT64", errSrcVal(boolProto(true), "Number"))), + }, + { + // Field specifies ARRAY type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(bytesType())}, + }, + []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, + }, + &[][]byte{}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), + }, + { + // Field specifies ARRAY type, value is having a nil ListValue. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(bytesType())}, + }, + []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, + }, + &[][]byte{}, + errDecodeColumn(0, errNilListValue("BYTES")), + }, + { + // Field specifies ARRAY type, but value is for FLOAT64 type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(bytesType())}, + }, + []*proto3.Value{floatProto(1.0)}, + }, + &[][]byte{}, + errDecodeColumn(0, errSrcVal(floatProto(1.0), "List")), + }, + { + // Field specifies ARRAY type, but value is for ARRAY type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(bytesType())}, + }, + []*proto3.Value{listProto(floatProto(1.0))}, + }, + &[][]byte{}, + errDecodeColumn(0, errDecodeArrayElement(0, floatProto(1.0), + "BYTES", errSrcVal(floatProto(1.0), "String"))), + }, + { + // Field specifies ARRAY type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(boolType())}, + }, + []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, + }, + &[]NullBool{}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), + }, + { + // Field specifies ARRAY type, value is having a nil ListValue. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(boolType())}, + }, + []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, + }, + &[]NullBool{}, + errDecodeColumn(0, errNilListValue("BOOL")), + }, + { + // Field specifies ARRAY type, but value is for FLOAT64 type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(boolType())}, + }, + []*proto3.Value{floatProto(1.0)}, + }, + &[]NullBool{}, + errDecodeColumn(0, errSrcVal(floatProto(1.0), "List")), + }, + { + // Field specifies ARRAY type, but value is for ARRAY type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(boolType())}, + }, + []*proto3.Value{listProto(floatProto(1.0))}, + }, + &[]NullBool{}, + errDecodeColumn(0, errDecodeArrayElement(0, floatProto(1.0), + "BOOL", errSrcVal(floatProto(1.0), "Bool"))), + }, + { + // Field specifies ARRAY type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(timeType())}, + }, + []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, + }, + &[]NullTime{}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), + }, + { + // Field specifies ARRAY type, value is having a nil ListValue. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(timeType())}, + }, + []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, + }, + &[]NullTime{}, + errDecodeColumn(0, errNilListValue("TIMESTAMP")), + }, + { + // Field specifies ARRAY type, but value is for FLOAT64 type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(timeType())}, + }, + []*proto3.Value{floatProto(1.0)}, + }, + &[]NullTime{}, + errDecodeColumn(0, errSrcVal(floatProto(1.0), "List")), + }, + { + // Field specifies ARRAY type, but value is for ARRAY type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(timeType())}, + }, + []*proto3.Value{listProto(floatProto(1.0))}, + }, + &[]NullTime{}, + errDecodeColumn(0, errDecodeArrayElement(0, floatProto(1.0), + "TIMESTAMP", errSrcVal(floatProto(1.0), "String"))), + }, + { + // Field specifies ARRAY type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(dateType())}, + }, + []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, + }, + &[]NullDate{}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), + }, + { + // Field specifies ARRAY type, value is having a nil ListValue. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(dateType())}, + }, + []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, + }, + &[]NullDate{}, + errDecodeColumn(0, errNilListValue("DATE")), + }, + { + // Field specifies ARRAY type, but value is for FLOAT64 type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(dateType())}, + }, + []*proto3.Value{floatProto(1.0)}, + }, + &[]NullDate{}, + errDecodeColumn(0, errSrcVal(floatProto(1.0), "List")), + }, + { + // Field specifies ARRAY type, but value is for ARRAY type. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(dateType())}, + }, + []*proto3.Value{listProto(floatProto(1.0))}, + }, + &[]NullDate{}, + errDecodeColumn(0, errDecodeArrayElement(0, floatProto(1.0), + "DATE", errSrcVal(floatProto(1.0), "String"))), + }, + { + // Field specifies ARRAY type, value is having a nil Kind. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(structType( + mkField("Col1", intType()), + mkField("Col2", floatType()), + mkField("Col3", stringType()), + ))}, + }, + []*proto3.Value{{Kind: (*proto3.Value_ListValue)(nil)}}, + }, + &[]*struct { + Col1 int64 + Col2 float64 + Col3 string + }{}, + errDecodeColumn(0, errSrcVal(&proto3.Value{Kind: (*proto3.Value_ListValue)(nil)}, "List")), + }, + { + // Field specifies ARRAY type, value is having a nil ListValue. + &Row{ + []*sppb.StructType_Field{ + {Name: "Col0", Type: listType(structType( + mkField("Col1", intType()), + mkField("Col2", floatType()), + mkField("Col3", stringType()), + ))}, + }, + []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, + }, + &[]*struct { + Col1 int64 + Col2 float64 + Col3 string + }{}, + errDecodeColumn(0, errNilListValue("STRUCT")), + }, + { + // Field specifies ARRAY type, value is having a nil ListValue. + &Row{ + []*sppb.StructType_Field{ + { + Name: "Col0", + Type: listType( + structType( + mkField("Col1", intType()), + mkField("Col2", floatType()), + mkField("Col3", stringType()), + ), + ), + }, + }, + []*proto3.Value{{Kind: &proto3.Value_ListValue{}}}, + }, + &[]NullRow{}, + errDecodeColumn(0, errNilListValue("STRUCT")), + }, + { + // Field specifies ARRAY type, value is for BYTES type. + &Row{ + []*sppb.StructType_Field{ + { + Name: "Col0", + Type: listType( + structType( + mkField("Col1", intType()), + mkField("Col2", floatType()), + mkField("Col3", stringType()), + ), + ), + }, + }, + []*proto3.Value{bytesProto([]byte("value"))}, + }, + &[]*struct { + Col1 int64 + Col2 float64 + Col3 string + }{}, + errDecodeColumn(0, errSrcVal(bytesProto([]byte("value")), "List")), + }, + { + // Field specifies ARRAY type, value is for BYTES type. + &Row{ + []*sppb.StructType_Field{ + { + Name: "Col0", + Type: listType( + structType( + mkField("Col1", intType()), + mkField("Col2", floatType()), + mkField("Col3", stringType()), + ), + ), + }, + }, + []*proto3.Value{listProto(bytesProto([]byte("value")))}, + }, + &[]NullRow{}, + errDecodeColumn(0, errNotStructElement(0, bytesProto([]byte("value")))), + }, + { + // Field specifies ARRAY type, value is for ARRAY type. + &Row{ + []*sppb.StructType_Field{ + { + Name: "Col0", + Type: listType( + structType( + mkField("Col1", intType()), + mkField("Col2", floatType()), + mkField("Col3", stringType()), + ), + ), + }, + }, + []*proto3.Value{listProto(bytesProto([]byte("value")))}, + }, + &[]*struct { + Col1 int64 + Col2 float64 + Col3 string + }{}, + errDecodeColumn(0, errDecodeArrayElement(0, bytesProto([]byte("value")), + "STRUCT", errSrcVal(bytesProto([]byte("value")), "List"))), + }, + { + // Field specifies ARRAY, but is having nil StructType. + &Row{ + []*sppb.StructType_Field{ + { + Name: "Col0", Type: listType(&sppb.Type{Code: sppb.TypeCode_STRUCT}), + }, + }, + []*proto3.Value{listProto(listProto(intProto(1), floatProto(2.0), stringProto("3")))}, + }, + &[]*struct { + Col1 int64 + Col2 float64 + Col3 string + }{}, + errDecodeColumn(0, errDecodeArrayElement(0, listProto(intProto(1), floatProto(2.0), stringProto("3")), + "STRUCT", errNilSpannerStructType())), + }, + { + // Field specifies ARRAY, but the second struct value is for BOOL type instead of FLOAT64. + &Row{ + []*sppb.StructType_Field{ + { + Name: "Col0", + Type: listType( + structType( + mkField("Col1", intType()), + mkField("Col2", floatType()), + mkField("Col3", stringType()), + ), + ), + }, + }, + []*proto3.Value{listProto(listProto(intProto(1), boolProto(true), stringProto("3")))}, + }, + &[]*struct { + Col1 int64 + Col2 float64 + Col3 string + }{}, + errDecodeColumn( + 0, + errDecodeArrayElement( + 0, listProto(intProto(1), boolProto(true), stringProto("3")), "STRUCT", + errDecodeStructField( + &sppb.StructType{ + Fields: []*sppb.StructType_Field{ + mkField("Col1", intType()), + mkField("Col2", floatType()), + mkField("Col3", stringType()), + }, + }, + "Col2", + errSrcVal(boolProto(true), "Number"), + ), + ), + ), + }, + } { + if gotErr := test.row.Column(0, test.dst); !testEqual(gotErr, test.wantErr) { + t.Errorf("%v: test.row.Column(0) got error %v, want %v", i, gotErr, test.wantErr) + } + if gotErr := test.row.ColumnByName("Col0", test.dst); !testEqual(gotErr, test.wantErr) { + t.Errorf("%v: test.row.ColumnByName(%q) got error %v, want %v", i, "Col0", gotErr, test.wantErr) + } + if gotErr := test.row.Columns(test.dst); !testEqual(gotErr, test.wantErr) { + t.Errorf("%v: test.row.Columns(%T) got error %v, want %v", i, test.dst, gotErr, test.wantErr) + } + } +} + +// Test Row.ToStruct(). +func TestToStruct(t *testing.T) { + s := []struct { + // STRING / STRING ARRAY + PrimaryKey string `spanner:"STRING"` + NullString NullString `spanner:"NULL_STRING"` + StringArray []NullString `spanner:"STRING_ARRAY"` + NullStringArray []NullString `spanner:"NULL_STRING_ARRAY"` + // BYTES / BYTES ARRAY + Bytes []byte `spanner:"BYTES"` + NullBytes []byte `spanner:"NULL_BYTES"` + BytesArray [][]byte `spanner:"BYTES_ARRAY"` + NullBytesArray [][]byte `spanner:"NULL_BYTES_ARRAY"` + // INT64 / INT64 ARRAY + Int64 int64 `spanner:"INT64"` + NullInt64 NullInt64 `spanner:"NULL_INT64"` + Int64Array []NullInt64 `spanner:"INT64_ARRAY"` + NullInt64Array []NullInt64 `spanner:"NULL_INT64_ARRAY"` + // BOOL / BOOL ARRAY + Bool bool `spanner:"BOOL"` + NullBool NullBool `spanner:"NULL_BOOL"` + BoolArray []NullBool `spanner:"BOOL_ARRAY"` + NullBoolArray []NullBool `spanner:"NULL_BOOL_ARRAY"` + // FLOAT64 / FLOAT64 ARRAY + Float64 float64 `spanner:"FLOAT64"` + NullFloat64 NullFloat64 `spanner:"NULL_FLOAT64"` + Float64Array []NullFloat64 `spanner:"FLOAT64_ARRAY"` + NullFloat64Array []NullFloat64 `spanner:"NULL_FLOAT64_ARRAY"` + // TIMESTAMP / TIMESTAMP ARRAY + Timestamp time.Time `spanner:"TIMESTAMP"` + NullTimestamp NullTime `spanner:"NULL_TIMESTAMP"` + TimestampArray []NullTime `spanner:"TIMESTAMP_ARRAY"` + NullTimestampArray []NullTime `spanner:"NULL_TIMESTAMP_ARRAY"` + // DATE / DATE ARRAY + Date civil.Date `spanner:"DATE"` + NullDate NullDate `spanner:"NULL_DATE"` + DateArray []NullDate `spanner:"DATE_ARRAY"` + NullDateArray []NullDate `spanner:"NULL_DATE_ARRAY"` + + // STRUCT ARRAY + StructArray []*struct { + Col1 int64 + Col2 float64 + Col3 string + } `spanner:"STRUCT_ARRAY"` + NullStructArray []*struct { + Col1 int64 + Col2 float64 + Col3 string + } `spanner:"NULL_STRUCT_ARRAY"` + }{ + {}, // got + { + // STRING / STRING ARRAY + "value", + NullString{}, + []NullString{{"value1", true}, {}, {"value3", true}}, + []NullString(nil), + // BYTES / BYTES ARRAY + []byte("value"), + []byte(nil), + [][]byte{[]byte("value1"), nil, []byte("value3")}, + [][]byte(nil), + // INT64 / INT64 ARRAY + int64(17), + NullInt64{}, + []NullInt64{{int64(1), true}, {int64(2), true}, {}}, + []NullInt64(nil), + // BOOL / BOOL ARRAY + true, + NullBool{}, + []NullBool{{}, {true, true}, {false, true}}, + []NullBool(nil), + // FLOAT64 / FLOAT64 ARRAY + 1.7, + NullFloat64{}, + []NullFloat64{{}, {}, {1.7, true}}, + []NullFloat64(nil), + // TIMESTAMP / TIMESTAMP ARRAY + tm, + NullTime{}, + []NullTime{{}, {tm, true}}, + []NullTime(nil), + // DATE / DATE ARRAY + dt, + NullDate{}, + []NullDate{{}, {dt, true}}, + []NullDate(nil), + // STRUCT ARRAY + []*struct { + Col1 int64 + Col2 float64 + Col3 string + }{ + nil, + + {3, 33.3, "three"}, + nil, + }, + []*struct { + Col1 int64 + Col2 float64 + Col3 string + }(nil), + }, // want + } + err := row.ToStruct(&s[0]) + if err != nil { + t.Errorf("row.ToStruct() returns error: %v, want nil", err) + } else if !testEqual(s[0], s[1]) { + t.Errorf("row.ToStruct() fetches struct %v, want %v", s[0], s[1]) + } +} + +func TestToStructEmbedded(t *testing.T) { + type ( + S1 struct{ F1 string } + S2 struct { + S1 + F2 string + } + ) + r := Row{ + []*sppb.StructType_Field{ + {Name: "F1", Type: stringType()}, + {Name: "F2", Type: stringType()}, + }, + []*proto3.Value{ + stringProto("v1"), + stringProto("v2"), + }, + } + var got S2 + if err := r.ToStruct(&got); err != nil { + t.Fatal(err) + } + want := S2{S1: S1{F1: "v1"}, F2: "v2"} + if !testEqual(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } +} + +// Test helpers for getting column names. +func TestColumnNameAndIndex(t *testing.T) { + // Test Row.Size(). + if rs := row.Size(); rs != len(row.fields) { + t.Errorf("row.Size() returns %v, want %v", rs, len(row.fields)) + } + // Test Row.Size() on empty Row. + if rs := (&Row{}).Size(); rs != 0 { + t.Errorf("empty_row.Size() returns %v, want %v", rs, 0) + } + // Test Row.ColumnName() + for i, col := range row.fields { + if cn := row.ColumnName(i); cn != col.Name { + t.Errorf("row.ColumnName(%v) returns %q, want %q", i, cn, col.Name) + } + goti, err := row.ColumnIndex(col.Name) + if err != nil { + t.Errorf("ColumnIndex(%q) error %v", col.Name, err) + continue + } + if goti != i { + t.Errorf("ColumnIndex(%q) = %d, want %d", col.Name, goti, i) + } + } + // Test Row.ColumnName on empty Row. + if cn := (&Row{}).ColumnName(0); cn != "" { + t.Errorf("empty_row.ColumnName(%v) returns %q, want %q", 0, cn, "") + } + // Test Row.ColumnIndex on empty Row. + if _, err := (&Row{}).ColumnIndex(""); err == nil { + t.Error("empty_row.ColumnIndex returns nil, want error") + } +} + +func TestNewRow(t *testing.T) { + for _, test := range []struct { + names []string + values []interface{} + want *Row + wantErr error + }{ + { + want: &Row{fields: []*sppb.StructType_Field{}, vals: []*proto3.Value{}}, + }, + { + names: []string{}, + values: []interface{}{}, + want: &Row{fields: []*sppb.StructType_Field{}, vals: []*proto3.Value{}}, + }, + { + names: []string{"a", "b"}, + values: []interface{}{}, + want: nil, + wantErr: errNamesValuesMismatch([]string{"a", "b"}, []interface{}{}), + }, + { + names: []string{"a", "b", "c"}, + values: []interface{}{5, "abc", GenericColumnValue{listType(intType()), listProto(intProto(91), nullProto(), intProto(87))}}, + want: &Row{ + []*sppb.StructType_Field{ + {Name: "a", Type: intType()}, + {Name: "b", Type: stringType()}, + {Name: "c", Type: listType(intType())}, + }, + []*proto3.Value{ + intProto(5), + stringProto("abc"), + listProto(intProto(91), nullProto(), intProto(87)), + }, + }, + }, + } { + got, err := NewRow(test.names, test.values) + if !testEqual(err, test.wantErr) { + t.Errorf("NewRow(%v,%v).err = %s, want %s", test.names, test.values, err, test.wantErr) + continue + } + if !testEqual(got, test.want) { + t.Errorf("NewRow(%v,%v) = %s, want %s", test.names, test.values, got, test.want) + continue + } + } +} + +func BenchmarkColumn(b *testing.B) { + var s string + for i := 0; i < b.N; i++ { + if err := row.Column(0, &s); err != nil { + b.Fatal(err) + } + } +} diff --git a/vendor/cloud.google.com/go/spanner/session.go b/vendor/cloud.google.com/go/spanner/session.go new file mode 100644 index 00000000..d058e57b --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/session.go @@ -0,0 +1,1093 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "container/heap" + "container/list" + "context" + "fmt" + "log" + "math/rand" + "strings" + "sync" + "time" + + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// sessionHandle is an interface for transactions to access Cloud Spanner sessions safely. It is generated by sessionPool.take(). +type sessionHandle struct { + // mu guarantees that the inner session object is returned / destroyed only once. + mu sync.Mutex + // session is a pointer to a session object. Transactions never need to access it directly. + session *session +} + +// recycle gives the inner session object back to its home session pool. It is safe to call recycle multiple times but only the first one would take effect. +func (sh *sessionHandle) recycle() { + sh.mu.Lock() + defer sh.mu.Unlock() + if sh.session == nil { + // sessionHandle has already been recycled. + return + } + sh.session.recycle() + sh.session = nil +} + +// getID gets the Cloud Spanner session ID from the internal session object. getID returns empty string if the sessionHandle is nil or the inner session +// object has been released by recycle / destroy. +func (sh *sessionHandle) getID() string { + sh.mu.Lock() + defer sh.mu.Unlock() + if sh.session == nil { + // sessionHandle has already been recycled/destroyed. + return "" + } + return sh.session.getID() +} + +// getClient gets the Cloud Spanner RPC client associated with the session ID in sessionHandle. +func (sh *sessionHandle) getClient() sppb.SpannerClient { + sh.mu.Lock() + defer sh.mu.Unlock() + if sh.session == nil { + return nil + } + return sh.session.client +} + +// getMetadata returns the metadata associated with the session in sessionHandle. +func (sh *sessionHandle) getMetadata() metadata.MD { + sh.mu.Lock() + defer sh.mu.Unlock() + if sh.session == nil { + return nil + } + return sh.session.md +} + +// getTransactionID returns the transaction id in the session if available. +func (sh *sessionHandle) getTransactionID() transactionID { + sh.mu.Lock() + defer sh.mu.Unlock() + if sh.session == nil { + return nil + } + return sh.session.tx +} + +// destroy destroys the inner session object. It is safe to call destroy multiple times and only the first call would attempt to +// destroy the inner session object. +func (sh *sessionHandle) destroy() { + sh.mu.Lock() + s := sh.session + sh.session = nil + sh.mu.Unlock() + if s == nil { + // sessionHandle has already been destroyed. + return + } + s.destroy(false) +} + +// session wraps a Cloud Spanner session ID through which transactions are created and executed. +type session struct { + // client is the RPC channel to Cloud Spanner. It is set only once during session's creation. + client sppb.SpannerClient + // id is the unique id of the session in Cloud Spanner. It is set only once during session's creation. + id string + // pool is the session's home session pool where it was created. It is set only once during session's creation. + pool *sessionPool + // createTime is the timestamp of the session's creation. It is set only once during session's creation. + createTime time.Time + + // mu protects the following fields from concurrent access: both healthcheck workers and transactions can modify them. + mu sync.Mutex + // valid marks the validity of a session. + valid bool + // hcIndex is the index of the session inside the global healthcheck queue. If hcIndex < 0, session has been unregistered from the queue. + hcIndex int + // idleList is the linkedlist node which links the session to its home session pool's idle list. If idleList == nil, the + // session is not in idle list. + idleList *list.Element + // nextCheck is the timestamp of next scheduled healthcheck of the session. It is maintained by the global health checker. + nextCheck time.Time + // checkingHelath is true if currently this session is being processed by health checker. Must be modified under health checker lock. + checkingHealth bool + // md is the Metadata to be sent with each request. + md metadata.MD + // tx contains the transaction id if the session has been prepared for write. + tx transactionID +} + +// isValid returns true if the session is still valid for use. +func (s *session) isValid() bool { + s.mu.Lock() + defer s.mu.Unlock() + return s.valid +} + +// isWritePrepared returns true if the session is prepared for write. +func (s *session) isWritePrepared() bool { + s.mu.Lock() + defer s.mu.Unlock() + return s.tx != nil +} + +// String implements fmt.Stringer for session. +func (s *session) String() string { + s.mu.Lock() + defer s.mu.Unlock() + return fmt.Sprintf("", + s.id, s.hcIndex, s.idleList, s.valid, s.createTime, s.nextCheck) +} + +// ping verifies if the session is still alive in Cloud Spanner. +func (s *session) ping() error { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + return runRetryable(ctx, func(ctx context.Context) error { + _, err := s.client.GetSession(contextWithOutgoingMetadata(ctx, s.pool.md), &sppb.GetSessionRequest{Name: s.getID()}) // s.getID is safe even when s is invalid. + return err + }) +} + +// setHcIndex atomically sets the session's index in the healthcheck queue and returns the old index. +func (s *session) setHcIndex(i int) int { + s.mu.Lock() + defer s.mu.Unlock() + oi := s.hcIndex + s.hcIndex = i + return oi +} + +// setIdleList atomically sets the session's idle list link and returns the old link. +func (s *session) setIdleList(le *list.Element) *list.Element { + s.mu.Lock() + defer s.mu.Unlock() + old := s.idleList + s.idleList = le + return old +} + +// invalidate marks a session as invalid and returns the old validity. +func (s *session) invalidate() bool { + s.mu.Lock() + defer s.mu.Unlock() + ov := s.valid + s.valid = false + return ov +} + +// setNextCheck sets the timestamp for next healthcheck on the session. +func (s *session) setNextCheck(t time.Time) { + s.mu.Lock() + defer s.mu.Unlock() + s.nextCheck = t +} + +// setTransactionID sets the transaction id in the session +func (s *session) setTransactionID(tx transactionID) { + s.mu.Lock() + defer s.mu.Unlock() + s.tx = tx +} + +// getID returns the session ID which uniquely identifies the session in Cloud Spanner. +func (s *session) getID() string { + s.mu.Lock() + defer s.mu.Unlock() + return s.id +} + +// getHcIndex returns the session's index into the global healthcheck priority queue. +func (s *session) getHcIndex() int { + s.mu.Lock() + defer s.mu.Unlock() + return s.hcIndex +} + +// getIdleList returns the session's link in its home session pool's idle list. +func (s *session) getIdleList() *list.Element { + s.mu.Lock() + defer s.mu.Unlock() + return s.idleList +} + +// getNextCheck returns the timestamp for next healthcheck on the session. +func (s *session) getNextCheck() time.Time { + s.mu.Lock() + defer s.mu.Unlock() + return s.nextCheck +} + +// recycle turns the session back to its home session pool. +func (s *session) recycle() { + s.setTransactionID(nil) + if !s.pool.recycle(s) { + // s is rejected by its home session pool because it expired and the session pool currently has enough open sessions. + s.destroy(false) + } +} + +// destroy removes the session from its home session pool, healthcheck queue and Cloud Spanner service. +func (s *session) destroy(isExpire bool) bool { + // Remove s from session pool. + if !s.pool.remove(s, isExpire) { + return false + } + // Unregister s from healthcheck queue. + s.pool.hc.unregister(s) + // Remove s from Cloud Spanner service. + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + s.delete(ctx) + return true +} + +func (s *session) delete(ctx context.Context) { + // Ignore the error returned by runRetryable because even if we fail to explicitly destroy the session, + // it will be eventually garbage collected by Cloud Spanner. + err := runRetryable(ctx, func(ctx context.Context) error { + _, e := s.client.DeleteSession(ctx, &sppb.DeleteSessionRequest{Name: s.getID()}) + return e + }) + if err != nil { + log.Printf("Failed to delete session %v. Error: %v", s.getID(), err) + } +} + +// prepareForWrite prepares the session for write if it is not already in that state. +func (s *session) prepareForWrite(ctx context.Context) error { + if s.isWritePrepared() { + return nil + } + tx, err := beginTransaction(ctx, s.getID(), s.client) + if err != nil { + return err + } + s.setTransactionID(tx) + return nil +} + +// SessionPoolConfig stores configurations of a session pool. +type SessionPoolConfig struct { + // getRPCClient is the caller supplied method for getting a gRPC client to Cloud Spanner, this makes session pool able to use client pooling. + getRPCClient func() (sppb.SpannerClient, error) + // MaxOpened is the maximum number of opened sessions allowed by the session + // pool. Defaults to NumChannels * 100. If the client tries to open a session and + // there are already MaxOpened sessions, it will block until one becomes + // available or the context passed to the client method is canceled or times out. + MaxOpened uint64 + // MinOpened is the minimum number of opened sessions that the session pool + // tries to maintain. Session pool won't continue to expire sessions if number + // of opened connections drops below MinOpened. However, if a session is found + // to be broken, it will still be evicted from the session pool, therefore it is + // posssible that the number of opened sessions drops below MinOpened. + MinOpened uint64 + // MaxIdle is the maximum number of idle sessions, pool is allowed to keep. Defaults to 0. + MaxIdle uint64 + // MaxBurst is the maximum number of concurrent session creation requests. Defaults to 10. + MaxBurst uint64 + // WriteSessions is the fraction of sessions we try to keep prepared for write. + WriteSessions float64 + // HealthCheckWorkers is number of workers used by health checker for this pool. + HealthCheckWorkers int + // HealthCheckInterval is how often the health checker pings a session. Defaults to 5 min. + HealthCheckInterval time.Duration + // healthCheckSampleInterval is how often the health checker samples live session (for use in maintaining session pool size). Defaults to 1 min. + healthCheckSampleInterval time.Duration + // sessionLabels for the sessions created in the session pool. + sessionLabels map[string]string +} + +// errNoRPCGetter returns error for SessionPoolConfig missing getRPCClient method. +func errNoRPCGetter() error { + return spannerErrorf(codes.InvalidArgument, "require SessionPoolConfig.getRPCClient != nil, got nil") +} + +// errMinOpenedGTMapOpened returns error for SessionPoolConfig.MaxOpened < SessionPoolConfig.MinOpened when SessionPoolConfig.MaxOpened is set. +func errMinOpenedGTMaxOpened(maxOpened, minOpened uint64) error { + return spannerErrorf(codes.InvalidArgument, + "require SessionPoolConfig.MaxOpened >= SessionPoolConfig.MinOpened, got %v and %v", maxOpened, minOpened) +} + +// validate verifies that the SessionPoolConfig is good for use. +func (spc *SessionPoolConfig) validate() error { + if spc.getRPCClient == nil { + return errNoRPCGetter() + } + if spc.MinOpened > spc.MaxOpened && spc.MaxOpened > 0 { + return errMinOpenedGTMaxOpened(spc.MaxOpened, spc.MinOpened) + } + return nil +} + +// sessionPool creates and caches Cloud Spanner sessions. +type sessionPool struct { + // mu protects sessionPool from concurrent access. + mu sync.Mutex + // valid marks the validity of the session pool. + valid bool + // db is the database name that all sessions in the pool are associated with. + db string + // idleList caches idle session IDs. Session IDs in this list can be allocated for use. + idleList list.List + // idleWriteList caches idle sessions which have been prepared for write. + idleWriteList list.List + // mayGetSession is for broadcasting that session retrival/creation may proceed. + mayGetSession chan struct{} + // numOpened is the total number of open sessions from the session pool. + numOpened uint64 + // createReqs is the number of ongoing session creation requests. + createReqs uint64 + // prepareReqs is the number of ongoing session preparation request. + prepareReqs uint64 + // configuration of the session pool. + SessionPoolConfig + // Metadata to be sent with each request + md metadata.MD + // hc is the health checker + hc *healthChecker +} + +// newSessionPool creates a new session pool. +func newSessionPool(db string, config SessionPoolConfig, md metadata.MD) (*sessionPool, error) { + if err := config.validate(); err != nil { + return nil, err + } + pool := &sessionPool{ + db: db, + valid: true, + mayGetSession: make(chan struct{}), + SessionPoolConfig: config, + md: md, + } + if config.HealthCheckWorkers == 0 { + // With 10 workers and assuming average latency of 5 ms for BeginTransaction, we will be able to + // prepare 2000 tx/sec in advance. If the rate of takeWriteSession is more than that, it will + // degrade to doing BeginTransaction inline. + // TODO: consider resizing the worker pool dynamically according to the load. + config.HealthCheckWorkers = 10 + } + if config.HealthCheckInterval == 0 { + config.HealthCheckInterval = 5 * time.Minute + } + if config.healthCheckSampleInterval == 0 { + config.healthCheckSampleInterval = time.Minute + } + // On GCE VM, within the same region an healthcheck ping takes on average 10ms to finish, given a 5 minutes interval and + // 10 healthcheck workers, a healthChecker can effectively mantain 100 checks_per_worker/sec * 10 workers * 300 seconds = 300K sessions. + pool.hc = newHealthChecker(config.HealthCheckInterval, config.HealthCheckWorkers, config.healthCheckSampleInterval, pool) + close(pool.hc.ready) + return pool, nil +} + +// isValid checks if the session pool is still valid. +func (p *sessionPool) isValid() bool { + if p == nil { + return false + } + p.mu.Lock() + defer p.mu.Unlock() + return p.valid +} + +// close marks the session pool as closed. +func (p *sessionPool) close() { + if p == nil { + return + } + p.mu.Lock() + if !p.valid { + p.mu.Unlock() + return + } + p.valid = false + p.mu.Unlock() + p.hc.close() + // destroy all the sessions + p.hc.mu.Lock() + allSessions := make([]*session, len(p.hc.queue.sessions)) + copy(allSessions, p.hc.queue.sessions) + p.hc.mu.Unlock() + for _, s := range allSessions { + s.destroy(false) + } +} + +// errInvalidSessionPool returns error for using an invalid session pool. +func errInvalidSessionPool() error { + return spannerErrorf(codes.InvalidArgument, "invalid session pool") +} + +// errGetSessionTimeout returns error for context timeout during sessionPool.take(). +func errGetSessionTimeout() error { + return spannerErrorf(codes.Canceled, "timeout / context canceled during getting session") +} + +// shouldPrepareWrite returns true if we should prepare more sessions for write. +func (p *sessionPool) shouldPrepareWrite() bool { + return float64(p.numOpened)*p.WriteSessions > float64(p.idleWriteList.Len()+int(p.prepareReqs)) +} + +func (p *sessionPool) createSession(ctx context.Context) (*session, error) { + tracePrintf(ctx, nil, "Creating a new session") + doneCreate := func(done bool) { + p.mu.Lock() + if !done { + // Session creation failed, give budget back. + p.numOpened-- + recordStat(ctx, OpenSessionCount, int64(p.numOpened)) + } + p.createReqs-- + // Notify other waiters blocking on session creation. + close(p.mayGetSession) + p.mayGetSession = make(chan struct{}) + p.mu.Unlock() + } + sc, err := p.getRPCClient() + if err != nil { + doneCreate(false) + return nil, err + } + s, err := createSession(ctx, sc, p.db, p.sessionLabels, p.md) + if err != nil { + doneCreate(false) + // Should return error directly because of the previous retries on CreateSession RPC. + return nil, err + } + s.pool = p + p.hc.register(s) + doneCreate(true) + return s, nil +} + +func createSession(ctx context.Context, sc sppb.SpannerClient, db string, labels map[string]string, md metadata.MD) (*session, error) { + var s *session + err := runRetryable(ctx, func(ctx context.Context) error { + sid, e := sc.CreateSession(ctx, &sppb.CreateSessionRequest{ + Database: db, + Session: &sppb.Session{Labels: labels}, + }) + if e != nil { + return e + } + // If no error, construct the new session. + s = &session{valid: true, client: sc, id: sid.Name, createTime: time.Now(), md: md} + return nil + }) + if err != nil { + return nil, err + } + return s, nil +} + +func (p *sessionPool) isHealthy(s *session) bool { + if s.getNextCheck().Add(2 * p.hc.getInterval()).Before(time.Now()) { + // TODO: figure out if we need to schedule a new healthcheck worker here. + if err := s.ping(); shouldDropSession(err) { + // The session is already bad, continue to fetch/create a new one. + s.destroy(false) + return false + } + p.hc.scheduledHC(s) + } + return true +} + +// take returns a cached session if there are available ones; if there isn't any, it tries to allocate a new one. +// Session returned by take should be used for read operations. +func (p *sessionPool) take(ctx context.Context) (*sessionHandle, error) { + tracePrintf(ctx, nil, "Acquiring a read-only session") + ctx = contextWithOutgoingMetadata(ctx, p.md) + for { + var ( + s *session + err error + ) + + p.mu.Lock() + if !p.valid { + p.mu.Unlock() + return nil, errInvalidSessionPool() + } + if p.idleList.Len() > 0 { + // Idle sessions are available, get one from the top of the idle list. + s = p.idleList.Remove(p.idleList.Front()).(*session) + tracePrintf(ctx, map[string]interface{}{"sessionID": s.getID()}, + "Acquired read-only session") + } else if p.idleWriteList.Len() > 0 { + s = p.idleWriteList.Remove(p.idleWriteList.Front()).(*session) + tracePrintf(ctx, map[string]interface{}{"sessionID": s.getID()}, + "Acquired read-write session") + } + if s != nil { + s.setIdleList(nil) + p.mu.Unlock() + // From here, session is no longer in idle list, so healthcheck workers won't destroy it. + // If healthcheck workers failed to schedule healthcheck for the session timely, do the check here. + // Because session check is still much cheaper than session creation, they should be reused as much as possible. + if !p.isHealthy(s) { + continue + } + return &sessionHandle{session: s}, nil + } + // Idle list is empty, block if session pool has reached max session creation concurrency or max number of open sessions. + if (p.MaxOpened > 0 && p.numOpened >= p.MaxOpened) || (p.MaxBurst > 0 && p.createReqs >= p.MaxBurst) { + mayGetSession := p.mayGetSession + p.mu.Unlock() + tracePrintf(ctx, nil, "Waiting for read-only session to become available") + select { + case <-ctx.Done(): + tracePrintf(ctx, nil, "Context done waiting for session") + return nil, errGetSessionTimeout() + case <-mayGetSession: + } + continue + } + // Take budget before the actual session creation. + p.numOpened++ + recordStat(ctx, OpenSessionCount, int64(p.numOpened)) + p.createReqs++ + p.mu.Unlock() + if s, err = p.createSession(ctx); err != nil { + tracePrintf(ctx, nil, "Error creating session: %v", err) + return nil, toSpannerError(err) + } + tracePrintf(ctx, map[string]interface{}{"sessionID": s.getID()}, + "Created session") + return &sessionHandle{session: s}, nil + } +} + +// takeWriteSession returns a write prepared cached session if there are available ones; if there isn't any, it tries to allocate a new one. +// Session returned should be used for read write transactions. +func (p *sessionPool) takeWriteSession(ctx context.Context) (*sessionHandle, error) { + tracePrintf(ctx, nil, "Acquiring a read-write session") + ctx = contextWithOutgoingMetadata(ctx, p.md) + for { + var ( + s *session + err error + ) + + p.mu.Lock() + if !p.valid { + p.mu.Unlock() + return nil, errInvalidSessionPool() + } + if p.idleWriteList.Len() > 0 { + // Idle sessions are available, get one from the top of the idle list. + s = p.idleWriteList.Remove(p.idleWriteList.Front()).(*session) + tracePrintf(ctx, map[string]interface{}{"sessionID": s.getID()}, "Acquired read-write session") + } else if p.idleList.Len() > 0 { + s = p.idleList.Remove(p.idleList.Front()).(*session) + tracePrintf(ctx, map[string]interface{}{"sessionID": s.getID()}, "Acquired read-only session") + } + if s != nil { + s.setIdleList(nil) + p.mu.Unlock() + // From here, session is no longer in idle list, so healthcheck workers won't destroy it. + // If healthcheck workers failed to schedule healthcheck for the session timely, do the check here. + // Because session check is still much cheaper than session creation, they should be reused as much as possible. + if !p.isHealthy(s) { + continue + } + } else { + // Idle list is empty, block if session pool has reached max session creation concurrency or max number of open sessions. + if (p.MaxOpened > 0 && p.numOpened >= p.MaxOpened) || (p.MaxBurst > 0 && p.createReqs >= p.MaxBurst) { + mayGetSession := p.mayGetSession + p.mu.Unlock() + tracePrintf(ctx, nil, "Waiting for read-write session to become available") + select { + case <-ctx.Done(): + tracePrintf(ctx, nil, "Context done waiting for session") + return nil, errGetSessionTimeout() + case <-mayGetSession: + } + continue + } + + // Take budget before the actual session creation. + p.numOpened++ + recordStat(ctx, OpenSessionCount, int64(p.numOpened)) + p.createReqs++ + p.mu.Unlock() + if s, err = p.createSession(ctx); err != nil { + tracePrintf(ctx, nil, "Error creating session: %v", err) + return nil, toSpannerError(err) + } + tracePrintf(ctx, map[string]interface{}{"sessionID": s.getID()}, + "Created session") + } + if !s.isWritePrepared() { + if err = s.prepareForWrite(ctx); err != nil { + s.recycle() + tracePrintf(ctx, map[string]interface{}{"sessionID": s.getID()}, + "Error preparing session for write") + return nil, toSpannerError(err) + } + } + return &sessionHandle{session: s}, nil + } +} + +// recycle puts session s back to the session pool's idle list, it returns true if the session pool successfully recycles session s. +func (p *sessionPool) recycle(s *session) bool { + p.mu.Lock() + defer p.mu.Unlock() + if !s.isValid() || !p.valid { + // Reject the session if session is invalid or pool itself is invalid. + return false + } + // Put session at the back of the list to round robin for load balancing across channels. + if s.isWritePrepared() { + s.setIdleList(p.idleWriteList.PushBack(s)) + } else { + s.setIdleList(p.idleList.PushBack(s)) + } + // Broadcast that a session has been returned to idle list. + close(p.mayGetSession) + p.mayGetSession = make(chan struct{}) + return true +} + +// remove atomically removes session s from the session pool and invalidates s. +// If isExpire == true, the removal is triggered by session expiration and in such cases, only idle sessions can be removed. +func (p *sessionPool) remove(s *session, isExpire bool) bool { + p.mu.Lock() + defer p.mu.Unlock() + if isExpire && (p.numOpened <= p.MinOpened || s.getIdleList() == nil) { + // Don't expire session if the session is not in idle list (in use), or if number of open sessions is going below p.MinOpened. + return false + } + ol := s.setIdleList(nil) + // If the session is in the idlelist, remove it. + if ol != nil { + // Remove from whichever list it is in. + p.idleList.Remove(ol) + p.idleWriteList.Remove(ol) + } + if s.invalidate() { + // Decrease the number of opened sessions. + p.numOpened-- + recordStat(context.Background(), OpenSessionCount, int64(p.numOpened)) + // Broadcast that a session has been destroyed. + close(p.mayGetSession) + p.mayGetSession = make(chan struct{}) + return true + } + return false +} + +// hcHeap implements heap.Interface. It is used to create the priority queue for session healthchecks. +type hcHeap struct { + sessions []*session +} + +// Len impelemnts heap.Interface.Len. +func (h hcHeap) Len() int { + return len(h.sessions) +} + +// Less implements heap.Interface.Less. +func (h hcHeap) Less(i, j int) bool { + return h.sessions[i].getNextCheck().Before(h.sessions[j].getNextCheck()) +} + +// Swap implements heap.Interface.Swap. +func (h hcHeap) Swap(i, j int) { + h.sessions[i], h.sessions[j] = h.sessions[j], h.sessions[i] + h.sessions[i].setHcIndex(i) + h.sessions[j].setHcIndex(j) +} + +// Push implements heap.Interface.Push. +func (h *hcHeap) Push(s interface{}) { + ns := s.(*session) + ns.setHcIndex(len(h.sessions)) + h.sessions = append(h.sessions, ns) +} + +// Pop implements heap.Interface.Pop. +func (h *hcHeap) Pop() interface{} { + old := h.sessions + n := len(old) + s := old[n-1] + h.sessions = old[:n-1] + s.setHcIndex(-1) + return s +} + +// healthChecker performs periodical healthchecks on registered sessions. +type healthChecker struct { + // mu protects concurrent access to hcQueue. + mu sync.Mutex + // queue is the priority queue for session healthchecks. Sessions with lower nextCheck rank higher in the queue. + queue hcHeap + // interval is the average interval between two healthchecks on a session. + interval time.Duration + // workers is the number of concurrent healthcheck workers. + workers int + // waitWorkers waits for all healthcheck workers to exit + waitWorkers sync.WaitGroup + // pool is the underlying session pool. + pool *sessionPool + // sampleInterval is the interval of sampling by the maintainer. + sampleInterval time.Duration + // ready is used to signal that maintainer can start running. + ready chan struct{} + // done is used to signal that health checker should be closed. + done chan struct{} + // once is used for closing channel done only once. + once sync.Once +} + +// newHealthChecker initializes new instance of healthChecker. +func newHealthChecker(interval time.Duration, workers int, sampleInterval time.Duration, pool *sessionPool) *healthChecker { + if workers <= 0 { + workers = 1 + } + hc := &healthChecker{ + interval: interval, + workers: workers, + pool: pool, + sampleInterval: sampleInterval, + ready: make(chan struct{}), + done: make(chan struct{}), + } + hc.waitWorkers.Add(1) + go hc.maintainer() + for i := 1; i <= hc.workers; i++ { + hc.waitWorkers.Add(1) + go hc.worker(i) + } + return hc +} + +// close closes the healthChecker and waits for all healthcheck workers to exit. +func (hc *healthChecker) close() { + hc.once.Do(func() { close(hc.done) }) + hc.waitWorkers.Wait() +} + +// isClosing checks if a healthChecker is already closing. +func (hc *healthChecker) isClosing() bool { + select { + case <-hc.done: + return true + default: + return false + } +} + +// getInterval gets the healthcheck interval. +func (hc *healthChecker) getInterval() time.Duration { + hc.mu.Lock() + defer hc.mu.Unlock() + return hc.interval +} + +// scheduledHCLocked schedules next healthcheck on session s with the assumption that hc.mu is being held. +func (hc *healthChecker) scheduledHCLocked(s *session) { + // The next healthcheck will be scheduled after [interval*0.5, interval*1.5) nanoseconds. + nsFromNow := rand.Int63n(int64(hc.interval)) + int64(hc.interval)/2 + s.setNextCheck(time.Now().Add(time.Duration(nsFromNow))) + if hi := s.getHcIndex(); hi != -1 { + // Session is still being tracked by healthcheck workers. + heap.Fix(&hc.queue, hi) + } +} + +// scheduledHC schedules next healthcheck on session s. It is safe to be called concurrently. +func (hc *healthChecker) scheduledHC(s *session) { + hc.mu.Lock() + defer hc.mu.Unlock() + hc.scheduledHCLocked(s) +} + +// register registers a session with healthChecker for periodical healthcheck. +func (hc *healthChecker) register(s *session) { + hc.mu.Lock() + defer hc.mu.Unlock() + hc.scheduledHCLocked(s) + heap.Push(&hc.queue, s) +} + +// unregister unregisters a session from healthcheck queue. +func (hc *healthChecker) unregister(s *session) { + hc.mu.Lock() + defer hc.mu.Unlock() + oi := s.setHcIndex(-1) + if oi >= 0 { + heap.Remove(&hc.queue, oi) + } +} + +// markDone marks that health check for session has been performed. +func (hc *healthChecker) markDone(s *session) { + hc.mu.Lock() + defer hc.mu.Unlock() + s.checkingHealth = false +} + +// healthCheck checks the health of the session and pings it if needed. +func (hc *healthChecker) healthCheck(s *session) { + defer hc.markDone(s) + if !s.pool.isValid() { + // Session pool is closed, perform a garbage collection. + s.destroy(false) + return + } + if err := s.ping(); shouldDropSession(err) { + // Ping failed, destroy the session. + s.destroy(false) + } +} + +// worker performs the healthcheck on sessions in healthChecker's priority queue. +func (hc *healthChecker) worker(i int) { + // Returns a session which we should ping to keep it alive. + getNextForPing := func() *session { + hc.pool.mu.Lock() + defer hc.pool.mu.Unlock() + hc.mu.Lock() + defer hc.mu.Unlock() + if hc.queue.Len() <= 0 { + // Queue is empty. + return nil + } + s := hc.queue.sessions[0] + if s.getNextCheck().After(time.Now()) && hc.pool.valid { + // All sessions have been checked recently. + return nil + } + hc.scheduledHCLocked(s) + if !s.checkingHealth { + s.checkingHealth = true + return s + } + return nil + } + + // Returns a session which we should prepare for write. + getNextForTx := func() *session { + hc.pool.mu.Lock() + defer hc.pool.mu.Unlock() + if hc.pool.shouldPrepareWrite() { + if hc.pool.idleList.Len() > 0 && hc.pool.valid { + hc.mu.Lock() + defer hc.mu.Unlock() + if hc.pool.idleList.Front().Value.(*session).checkingHealth { + return nil + } + session := hc.pool.idleList.Remove(hc.pool.idleList.Front()).(*session) + session.checkingHealth = true + hc.pool.prepareReqs++ + return session + } + } + return nil + } + + for { + if hc.isClosing() { + // Exit when the pool has been closed and all sessions have been destroyed + // or when health checker has been closed. + hc.waitWorkers.Done() + return + } + ws := getNextForTx() + if ws != nil { + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + err := ws.prepareForWrite(contextWithOutgoingMetadata(ctx, hc.pool.md)) + cancel() + if err != nil { + // Skip handling prepare error, session can be prepared in next cycle + log.Printf("Failed to prepare session, error: %v", toSpannerError(err)) + } + hc.pool.recycle(ws) + hc.pool.mu.Lock() + hc.pool.prepareReqs-- + hc.pool.mu.Unlock() + hc.markDone(ws) + } + rs := getNextForPing() + if rs == nil { + if ws == nil { + // No work to be done so sleep to avoid burning cpu + pause := int64(100 * time.Millisecond) + if pause > int64(hc.interval) { + pause = int64(hc.interval) + } + select { + case <-time.After(time.Duration(rand.Int63n(pause) + pause/2)): + case <-hc.done: + } + + } + continue + } + hc.healthCheck(rs) + } +} + +// maintainer maintains the maxSessionsInUse by a window of kWindowSize * sampleInterval. +// Based on this information, health checker will try to maintain the number of sessions by hc.. +func (hc *healthChecker) maintainer() { + // Wait so that pool is ready. + <-hc.ready + + var ( + windowSize uint64 = 10 + iteration uint64 + timeout <-chan time.Time + ) + + // replenishPool is run if numOpened is less than sessionsToKeep, timeouts on sampleInterval. + replenishPool := func(sessionsToKeep uint64) { + ctx, _ := context.WithTimeout(context.Background(), hc.sampleInterval) + for { + select { + case <-timeout: + return + default: + } + + p := hc.pool + p.mu.Lock() + // Take budget before the actual session creation. + if sessionsToKeep <= p.numOpened { + p.mu.Unlock() + break + } + p.numOpened++ + recordStat(ctx, OpenSessionCount, int64(p.numOpened)) + p.createReqs++ + shouldPrepareWrite := p.shouldPrepareWrite() + p.mu.Unlock() + var ( + s *session + err error + ) + if s, err = p.createSession(ctx); err != nil { + log.Printf("Failed to create session, error: %v", toSpannerError(err)) + continue + } + if shouldPrepareWrite { + if err = s.prepareForWrite(ctx); err != nil { + p.recycle(s) + log.Printf("Failed to prepare session, error: %v", toSpannerError(err)) + continue + } + } + p.recycle(s) + } + } + + // shrinkPool, scales down the session pool. + shrinkPool := func(sessionsToKeep uint64) { + for { + select { + case <-timeout: + return + default: + } + + p := hc.pool + p.mu.Lock() + + if sessionsToKeep >= p.numOpened { + p.mu.Unlock() + break + } + + var s *session + if p.idleList.Len() > 0 { + s = p.idleList.Front().Value.(*session) + } else if p.idleWriteList.Len() > 0 { + s = p.idleWriteList.Front().Value.(*session) + } + p.mu.Unlock() + if s != nil { + // destroy session as expire. + s.destroy(true) + } else { + break + } + } + } + + for { + if hc.isClosing() { + hc.waitWorkers.Done() + return + } + + // maxSessionsInUse is the maximum number of sessions in use concurrently over a period of time. + var maxSessionsInUse uint64 + + // Updates metrics. + hc.pool.mu.Lock() + currSessionsInUse := hc.pool.numOpened - uint64(hc.pool.idleList.Len()) - uint64(hc.pool.idleWriteList.Len()) + currSessionsOpened := hc.pool.numOpened + hc.pool.mu.Unlock() + + hc.mu.Lock() + if iteration%windowSize == 0 || maxSessionsInUse < currSessionsInUse { + maxSessionsInUse = currSessionsInUse + } + sessionsToKeep := maxUint64(hc.pool.MinOpened, + minUint64(currSessionsOpened, hc.pool.MaxIdle+maxSessionsInUse)) + hc.mu.Unlock() + + timeout = time.After(hc.sampleInterval) + // Replenish or Shrink pool if needed. + // Note: we don't need to worry about pending create session requests, we only need to sample the current sessions in use. + // the routines will not try to create extra / delete creating sessions. + if sessionsToKeep > currSessionsOpened { + replenishPool(sessionsToKeep) + } else { + shrinkPool(sessionsToKeep) + } + + select { + case <-timeout: + case <-hc.done: + } + iteration++ + } +} + +// shouldDropSession returns true if a particular error leads to the removal of a session +func shouldDropSession(err error) bool { + if err == nil { + return false + } + // If a Cloud Spanner can no longer locate the session (for example, if session is garbage collected), then caller + // should not try to return the session back into the session pool. + // TODO: once gRPC can return auxiliary error information, stop parsing the error message. + if ErrCode(err) == codes.NotFound && strings.Contains(ErrDesc(err), "Session not found:") { + return true + } + return false +} diff --git a/vendor/cloud.google.com/go/spanner/session_test.go b/vendor/cloud.google.com/go/spanner/session_test.go new file mode 100644 index 00000000..932d635d --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/session_test.go @@ -0,0 +1,963 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "bytes" + "container/heap" + "context" + "fmt" + "math/rand" + "sync" + "testing" + "time" + + "cloud.google.com/go/spanner/internal/testutil" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// setup prepares test environment for regular session pool tests. +// +// Note: be sure to call cleanup! +func setup(t *testing.T, spc SessionPoolConfig) (sp *sessionPool, sc *testutil.MockCloudSpannerClient, cleanup func()) { + sc = testutil.NewMockCloudSpannerClient(t) + spc.getRPCClient = func() (sppb.SpannerClient, error) { + return sc, nil + } + if spc.HealthCheckInterval == 0 { + spc.HealthCheckInterval = 50 * time.Millisecond + } + if spc.healthCheckSampleInterval == 0 { + spc.healthCheckSampleInterval = 10 * time.Millisecond + } + sp, err := newSessionPool("mockdb", spc, nil) + if err != nil { + t.Fatalf("cannot create session pool: %v", err) + } + cleanup = func() { + sp.hc.close() + sp.close() + } + return +} + +// TestSessionPoolConfigValidation tests session pool config validation. +func TestSessionPoolConfigValidation(t *testing.T) { + t.Parallel() + sc := testutil.NewMockCloudSpannerClient(t) + for _, test := range []struct { + spc SessionPoolConfig + err error + }{ + { + SessionPoolConfig{}, + errNoRPCGetter(), + }, + { + SessionPoolConfig{ + getRPCClient: func() (sppb.SpannerClient, error) { + return sc, nil + }, + MinOpened: 10, + MaxOpened: 5, + }, + errMinOpenedGTMaxOpened(5, 10), + }, + } { + if _, err := newSessionPool("mockdb", test.spc, nil); !testEqual(err, test.err) { + t.Errorf("want %v, got %v", test.err, err) + } + } +} + +// TestSessionCreation tests session creation during sessionPool.Take(). +func TestSessionCreation(t *testing.T) { + t.Parallel() + + sp, sc, cleanup := setup(t, SessionPoolConfig{}) + defer cleanup() + + // Take three sessions from session pool, this should trigger session pool to create three new sessions. + shs := make([]*sessionHandle, 3) + // gotDs holds the unique sessions taken from session pool. + gotDs := map[string]bool{} + for i := 0; i < len(shs); i++ { + var err error + shs[i], err = sp.take(context.Background()) + if err != nil { + t.Errorf("failed to get session(%v): %v", i, err) + } + gotDs[shs[i].getID()] = true + } + if len(gotDs) != len(shs) { + t.Errorf("session pool created %v sessions, want %v", len(gotDs), len(shs)) + } + if wantDs := sc.DumpSessions(); !testEqual(gotDs, wantDs) { + t.Errorf("session pool creates sessions %v, want %v", gotDs, wantDs) + } + // Verify that created sessions are recorded correctly in session pool. + sp.mu.Lock() + if int(sp.numOpened) != len(shs) { + t.Errorf("session pool reports %v open sessions, want %v", sp.numOpened, len(shs)) + } + if sp.createReqs != 0 { + t.Errorf("session pool reports %v session create requests, want 0", int(sp.createReqs)) + } + sp.mu.Unlock() + // Verify that created sessions are tracked correctly by healthcheck queue. + hc := sp.hc + hc.mu.Lock() + if hc.queue.Len() != len(shs) { + t.Errorf("healthcheck queue length = %v, want %v", hc.queue.Len(), len(shs)) + } + for _, s := range hc.queue.sessions { + if !gotDs[s.getID()] { + t.Errorf("session %v is in healthcheck queue, but it is not created by session pool", s.getID()) + } + } + hc.mu.Unlock() +} + +// TestTakeFromIdleList tests taking sessions from session pool's idle list. +func TestTakeFromIdleList(t *testing.T) { + t.Parallel() + + sp, sc, cleanup := setup(t, SessionPoolConfig{MaxIdle: 10}) // make sure maintainer keeps the idle sessions + defer cleanup() + + // Take ten sessions from session pool and recycle them. + shs := make([]*sessionHandle, 10) + for i := 0; i < len(shs); i++ { + var err error + shs[i], err = sp.take(context.Background()) + if err != nil { + t.Errorf("failed to get session(%v): %v", i, err) + } + } + // Make sure it's sampled once before recycling, otherwise it will be cleaned up. + <-time.After(sp.SessionPoolConfig.healthCheckSampleInterval) + for i := 0; i < len(shs); i++ { + shs[i].recycle() + } + // Further session requests from session pool won't cause mockclient to create more sessions. + wantSessions := sc.DumpSessions() + // Take ten sessions from session pool again, this time all sessions should come from idle list. + gotSessions := map[string]bool{} + for i := 0; i < len(shs); i++ { + sh, err := sp.take(context.Background()) + if err != nil { + t.Errorf("cannot take session from session pool: %v", err) + } + gotSessions[sh.getID()] = true + } + if len(gotSessions) != 10 { + t.Errorf("got %v unique sessions, want 10", len(gotSessions)) + } + if !testEqual(gotSessions, wantSessions) { + t.Errorf("got sessions: %v, want %v", gotSessions, wantSessions) + } +} + +// TesttakeWriteSessionFromIdleList tests taking write sessions from session pool's idle list. +func TestTakeWriteSessionFromIdleList(t *testing.T) { + t.Parallel() + + sp, sc, cleanup := setup(t, SessionPoolConfig{MaxIdle: 20}) // make sure maintainer keeps the idle sessions + defer cleanup() + + acts := make([]testutil.Action, 20) + for i := 0; i < len(acts); i++ { + acts[i] = testutil.Action{"BeginTransaction", nil} + } + sc.SetActions(acts...) + // Take ten sessions from session pool and recycle them. + shs := make([]*sessionHandle, 10) + for i := 0; i < len(shs); i++ { + var err error + shs[i], err = sp.takeWriteSession(context.Background()) + if err != nil { + t.Errorf("failed to get session(%v): %v", i, err) + } + } + // Make sure it's sampled once before recycling, otherwise it will be cleaned up. + <-time.After(sp.SessionPoolConfig.healthCheckSampleInterval) + for i := 0; i < len(shs); i++ { + shs[i].recycle() + } + // Further session requests from session pool won't cause mockclient to create more sessions. + wantSessions := sc.DumpSessions() + // Take ten sessions from session pool again, this time all sessions should come from idle list. + gotSessions := map[string]bool{} + for i := 0; i < len(shs); i++ { + sh, err := sp.takeWriteSession(context.Background()) + if err != nil { + t.Errorf("cannot take session from session pool: %v", err) + } + gotSessions[sh.getID()] = true + } + if len(gotSessions) != 10 { + t.Errorf("got %v unique sessions, want 10", len(gotSessions)) + } + if !testEqual(gotSessions, wantSessions) { + t.Errorf("got sessions: %v, want %v", gotSessions, wantSessions) + } +} + +// TestTakeFromIdleListChecked tests taking sessions from session pool's idle list, but with a extra ping check. +func TestTakeFromIdleListChecked(t *testing.T) { + t.Parallel() + if testing.Short() { + t.SkipNow() + } + + sp, sc, cleanup := setup(t, SessionPoolConfig{MaxIdle: 1}) // make sure maintainer keeps the idle sessions + defer cleanup() + + // Stop healthcheck workers to simulate slow pings. + sp.hc.close() + // Create a session and recycle it. + sh, err := sp.take(context.Background()) + if err != nil { + t.Errorf("failed to get session: %v", err) + } + // Make sure it's sampled once before recycling, otherwise it will be cleaned up. + <-time.After(sp.SessionPoolConfig.healthCheckSampleInterval) + wantSid := sh.getID() + sh.recycle() + <-time.After(time.Second) + // Two back-to-back session requests, both of them should return the same session created before and + // none of them should trigger a session ping. + for i := 0; i < 2; i++ { + // Take the session from the idle list and recycle it. + sh, err = sp.take(context.Background()) + if err != nil { + t.Errorf("%v - failed to get session: %v", i, err) + } + if gotSid := sh.getID(); gotSid != wantSid { + t.Errorf("%v - got session id: %v, want %v", i, gotSid, wantSid) + } + // The two back-to-back session requests shouldn't trigger any session pings because sessionPool.Take + // reschedules the next healthcheck. + if got, want := sc.DumpPings(), ([]string{wantSid}); !testEqual(got, want) { + t.Errorf("%v - got ping session requests: %v, want %v", i, got, want) + } + sh.recycle() + } + // Inject session error to mockclient, and take the session from the session pool, the old session should be destroyed and + // the session pool will create a new session. + sc.InjectError("GetSession", status.Errorf(codes.NotFound, "Session not found:")) + // Delay to trigger sessionPool.Take to ping the session. + <-time.After(time.Second) + sh, err = sp.take(context.Background()) + if err != nil { + t.Errorf("failed to get session: %v", err) + } + ds := sc.DumpSessions() + if len(ds) != 1 { + t.Errorf("dumped sessions from mockclient: %v, want %v", ds, sh.getID()) + } + if sh.getID() == wantSid { + t.Errorf("sessionPool.Take still returns the same session %v, want it to create a new one", wantSid) + } +} + +// TestTakeFromIdleWriteListChecked tests taking sessions from session pool's idle list, but with a extra ping check. +func TestTakeFromIdleWriteListChecked(t *testing.T) { + t.Parallel() + if testing.Short() { + t.SkipNow() + } + + sp, sc, cleanup := setup(t, SessionPoolConfig{MaxIdle: 1}) // make sure maintainer keeps the idle sessions + defer cleanup() + + sc.MakeNice() + // Stop healthcheck workers to simulate slow pings. + sp.hc.close() + // Create a session and recycle it. + sh, err := sp.takeWriteSession(context.Background()) + if err != nil { + t.Errorf("failed to get session: %v", err) + } + wantSid := sh.getID() + // Make sure it's sampled once before recycling, otherwise it will be cleaned up. + <-time.After(sp.SessionPoolConfig.healthCheckSampleInterval) + sh.recycle() + <-time.After(time.Second) + // Two back-to-back session requests, both of them should return the same session created before and + // none of them should trigger a session ping. + for i := 0; i < 2; i++ { + // Take the session from the idle list and recycle it. + sh, err = sp.takeWriteSession(context.Background()) + if err != nil { + t.Errorf("%v - failed to get session: %v", i, err) + } + if gotSid := sh.getID(); gotSid != wantSid { + t.Errorf("%v - got session id: %v, want %v", i, gotSid, wantSid) + } + // The two back-to-back session requests shouldn't trigger any session pings because sessionPool.Take + // reschedules the next healthcheck. + if got, want := sc.DumpPings(), ([]string{wantSid}); !testEqual(got, want) { + t.Errorf("%v - got ping session requests: %v, want %v", i, got, want) + } + sh.recycle() + } + // Inject session error to mockclient, and take the session from the session pool, the old session should be destroyed and + // the session pool will create a new session. + sc.InjectError("GetSession", status.Errorf(codes.NotFound, "Session not found:")) + // Delay to trigger sessionPool.Take to ping the session. + <-time.After(time.Second) + sh, err = sp.takeWriteSession(context.Background()) + if err != nil { + t.Errorf("failed to get session: %v", err) + } + ds := sc.DumpSessions() + if len(ds) != 1 { + t.Errorf("dumped sessions from mockclient: %v, want %v", ds, sh.getID()) + } + if sh.getID() == wantSid { + t.Errorf("sessionPool.Take still returns the same session %v, want it to create a new one", wantSid) + } +} + +// TestMaxOpenedSessions tests max open sessions constraint. +func TestMaxOpenedSessions(t *testing.T) { + t.Parallel() + if testing.Short() { + t.SkipNow() + } + + sp, _, cleanup := setup(t, SessionPoolConfig{MaxOpened: 1}) + defer cleanup() + + sh1, err := sp.take(context.Background()) + if err != nil { + t.Errorf("cannot take session from session pool: %v", err) + } + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + // Session request will timeout due to the max open sessions constraint. + _, gotErr := sp.take(ctx) + if wantErr := errGetSessionTimeout(); !testEqual(gotErr, wantErr) { + t.Errorf("the second session retrival returns error %v, want %v", gotErr, wantErr) + } + go func() { + <-time.After(time.Second) + // destroy the first session to allow the next session request to proceed. + sh1.destroy() + }() + // Now session request can be processed because the first session will be destroyed. + sh2, err := sp.take(context.Background()) + if err != nil { + t.Errorf("after the first session is destroyed, session retrival still returns error %v, want nil", err) + } + if !sh2.session.isValid() || sh2.getID() == "" { + t.Errorf("got invalid session: %v", sh2.session) + } +} + +// TestMinOpenedSessions tests min open session constraint. +func TestMinOpenedSessions(t *testing.T) { + sp, _, cleanup := setup(t, SessionPoolConfig{MinOpened: 1}) + defer cleanup() + + // Take ten sessions from session pool and recycle them. + var ss []*session + var shs []*sessionHandle + for i := 0; i < 10; i++ { + sh, err := sp.take(context.Background()) + if err != nil { + t.Errorf("failed to get session(%v): %v", i, err) + } + ss = append(ss, sh.session) + shs = append(shs, sh) + sh.recycle() + } + for _, sh := range shs { + sh.recycle() + } + // Simulate session expiration. + for _, s := range ss { + s.destroy(true) + } + sp.mu.Lock() + defer sp.mu.Unlock() + // There should be still one session left in idle list due to the min open sessions constraint. + if sp.idleList.Len() != 1 { + t.Errorf("got %v sessions in idle list, want 1 %d", sp.idleList.Len(), sp.numOpened) + } +} + +// TestMaxBurst tests max burst constraint. +func TestMaxBurst(t *testing.T) { + t.Parallel() + if testing.Short() { + t.SkipNow() + } + + sp, sc, cleanup := setup(t, SessionPoolConfig{MaxBurst: 1}) + defer cleanup() + + // Will cause session creation RPC to be retried forever. + sc.InjectError("CreateSession", status.Errorf(codes.Unavailable, "try later")) + // This session request will never finish until the injected error is cleared. + go sp.take(context.Background()) + // Poll for the execution of the first session request. + for { + sp.mu.Lock() + cr := sp.createReqs + sp.mu.Unlock() + if cr == 0 { + <-time.After(time.Second) + continue + } + // The first session request is being executed. + break + } + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + _, gotErr := sp.take(ctx) + // Since MaxBurst == 1, the second session request should block. + if wantErr := errGetSessionTimeout(); !testEqual(gotErr, wantErr) { + t.Errorf("session retrival returns error %v, want %v", gotErr, wantErr) + } + // Let the first session request succeed. + sc.InjectError("CreateSession", nil) + // Now new session request can proceed because the first session request will eventually succeed. + sh, err := sp.take(context.Background()) + if err != nil { + t.Errorf("session retrival returns error %v, want nil", err) + } + if !sh.session.isValid() || sh.getID() == "" { + t.Errorf("got invalid session: %v", sh.session) + } +} + +// TestSessionrecycle tests recycling sessions. +func TestSessionRecycle(t *testing.T) { + t.Parallel() + if testing.Short() { + t.SkipNow() + } + + // Set MaxIdle to ensure shs[0] is not destroyed from scale down. + sp, _, cleanup := setup(t, SessionPoolConfig{MinOpened: 1, MaxIdle: 2}) + defer cleanup() + + // Test session is correctly recycled and reused. + for i := 0; i < 20; i++ { + s, err := sp.take(context.Background()) + if err != nil { + t.Errorf("cannot get the session %v: %v", i, err) + } + s.recycle() + } + if sp.numOpened != 1 { + t.Errorf("Expect session pool size %d, got %d", 1, sp.numOpened) + } +} + +// TODO(deklerk) Investigate why s.destroy(true) is flakey. +// TestSessionDestroy tests destroying sessions. +func TestSessionDestroy(t *testing.T) { + t.Skip("s.destroy(true) is flakey") + t.Parallel() + + sp, _, cleanup := setup(t, SessionPoolConfig{MinOpened: 1}) + defer cleanup() + + <-time.After(10 * time.Millisecond) // maintainer will create one session, we wait for it create session to avoid flakiness in test + sh, err := sp.take(context.Background()) + if err != nil { + t.Errorf("cannot get session from session pool: %v", err) + } + s := sh.session + sh.recycle() + if d := s.destroy(true); d || !s.isValid() { + // Session should be remaining because of min open sessions constraint. + t.Errorf("session %s invalid, want it to stay alive. (destroy in expiration mode, success: %v)", s.id, d) + } + if d := s.destroy(false); !d || s.isValid() { + // Session should be destroyed. + t.Errorf("failed to destroy session %s. (destroy in default mode, success: %v)", s.id, d) + } +} + +// TestHcHeap tests heap operation on top of hcHeap. +func TestHcHeap(t *testing.T) { + in := []*session{ + {nextCheck: time.Unix(10, 0)}, + {nextCheck: time.Unix(0, 5)}, + {nextCheck: time.Unix(1, 8)}, + {nextCheck: time.Unix(11, 7)}, + {nextCheck: time.Unix(6, 3)}, + } + want := []*session{ + {nextCheck: time.Unix(1, 8), hcIndex: 0}, + {nextCheck: time.Unix(6, 3), hcIndex: 1}, + {nextCheck: time.Unix(8, 2), hcIndex: 2}, + {nextCheck: time.Unix(10, 0), hcIndex: 3}, + {nextCheck: time.Unix(11, 7), hcIndex: 4}, + } + hh := hcHeap{} + for _, s := range in { + heap.Push(&hh, s) + } + // Change top of the heap and do a adjustment. + hh.sessions[0].nextCheck = time.Unix(8, 2) + heap.Fix(&hh, 0) + for idx := 0; hh.Len() > 0; idx++ { + got := heap.Pop(&hh).(*session) + want[idx].hcIndex = -1 + if !testEqual(got, want[idx]) { + t.Errorf("%v: heap.Pop returns %v, want %v", idx, got, want[idx]) + } + } +} + +// TestHealthCheckScheduler tests if healthcheck workers can schedule and +// perform healthchecks properly. +func TestHealthCheckScheduler(t *testing.T) { + t.Parallel() + if testing.Short() { + t.SkipNow() + } + + sp, sc, cleanup := setup(t, SessionPoolConfig{}) + defer cleanup() + + // Create 50 sessions. + ss := []string{} + for i := 0; i < 50; i++ { + sh, err := sp.take(context.Background()) + if err != nil { + t.Fatalf("cannot get session from session pool: %v", err) + } + ss = append(ss, sh.getID()) + } + + // Wait for 10-30 pings per session. + waitFor(t, func() error { + dp := sc.DumpPings() + gotPings := map[string]int64{} + for _, p := range dp { + gotPings[p]++ + } + for _, s := range ss { + want := int64(20) + if got := gotPings[s]; got < want/2 || got > want+want/2 { + // This is an unnacceptable amount of pings. + return fmt.Errorf("got %v healthchecks on session %v, want it between (%v, %v)", got, s, want/2, want+want/2) + } + } + return nil + }) +} + +// Tests that a fractions of sessions are prepared for write by health checker. +func TestWriteSessionsPrepared(t *testing.T) { + if testing.Short() { + t.SkipNow() + } + + sp, sc, cleanup := setup(t, SessionPoolConfig{WriteSessions: 0.5, MaxIdle: 20}) + defer cleanup() + + sc.MakeNice() + shs := make([]*sessionHandle, 10) + var err error + for i := 0; i < 10; i++ { + shs[i], err = sp.take(context.Background()) + if err != nil { + t.Errorf("cannot get session from session pool: %v", err) + } + } + // Now there are 10 sessions in the pool. Release them. + for _, sh := range shs { + sh.recycle() + } + // Sleep for 1s, allowing healthcheck workers to invoke begin transaction. + <-time.After(time.Second) + wshs := make([]*sessionHandle, 5) + for i := 0; i < 5; i++ { + wshs[i], err = sp.takeWriteSession(context.Background()) + if err != nil { + t.Errorf("cannot get session from session pool: %v", err) + } + if wshs[i].getTransactionID() == nil { + t.Errorf("got nil transaction id from session pool") + } + } + for _, sh := range wshs { + sh.recycle() + } + <-time.After(time.Second) + // Now force creation of 10 more sessions. + shs = make([]*sessionHandle, 20) + for i := 0; i < 20; i++ { + shs[i], err = sp.take(context.Background()) + if err != nil { + t.Errorf("cannot get session from session pool: %v", err) + } + } + // Now there are 20 sessions in the pool. Release them. + for _, sh := range shs { + sh.recycle() + } + <-time.After(time.Second) + if sp.idleWriteList.Len() != 10 { + t.Errorf("Expect 10 write prepared session, got: %d", sp.idleWriteList.Len()) + } +} + +// TestTakeFromWriteQueue tests that sessionPool.take() returns write prepared sessions as well. +func TestTakeFromWriteQueue(t *testing.T) { + t.Parallel() + if testing.Short() { + t.SkipNow() + } + + sp, sc, cleanup := setup(t, SessionPoolConfig{MaxOpened: 1, WriteSessions: 1.0, MaxIdle: 1}) + defer cleanup() + + sc.MakeNice() + sh, err := sp.take(context.Background()) + if err != nil { + t.Errorf("cannot get session from session pool: %v", err) + } + sh.recycle() + <-time.After(time.Second) + // The session should now be in write queue but take should also return it. + if sp.idleWriteList.Len() == 0 { + t.Errorf("write queue unexpectedly empty") + } + if sp.idleList.Len() != 0 { + t.Errorf("read queue not empty") + } + sh, err = sp.take(context.Background()) + if err != nil { + t.Errorf("cannot get session from session pool: %v", err) + } + sh.recycle() +} + +// TestSessionHealthCheck tests healthchecking cases. +func TestSessionHealthCheck(t *testing.T) { + t.Parallel() + if testing.Short() { + t.SkipNow() + } + + sp, sc, cleanup := setup(t, SessionPoolConfig{}) + defer cleanup() + + // Test pinging sessions. + sh, err := sp.take(context.Background()) + if err != nil { + t.Errorf("cannot get session from session pool: %v", err) + } + // Wait for healthchecker to send pings to session. + waitFor(t, func() error { + pings := sc.DumpPings() + if len(pings) == 0 || pings[0] != sh.getID() { + return fmt.Errorf("healthchecker didn't send any ping to session %v", sh.getID()) + } + return nil + }) + // Test broken session detection. + sh, err = sp.take(context.Background()) + if err != nil { + t.Errorf("cannot get session from session pool: %v", err) + } + sc.InjectError("GetSession", status.Errorf(codes.NotFound, "Session not found:")) + // Wait for healthcheck workers to find the broken session and tear it down. + <-time.After(1 * time.Second) + s := sh.session + if sh.session.isValid() { + t.Errorf("session(%v) is still alive, want it to be dropped by healthcheck workers", s) + } + sc.InjectError("GetSession", nil) + // Test garbage collection. + sh, err = sp.take(context.Background()) + if err != nil { + t.Errorf("cannot get session from session pool: %v", err) + } + sp.close() + if sh.session.isValid() { + t.Errorf("session(%v) is still alive, want it to be garbage collected", s) + } +} + +// TestStressSessionPool does stress test on session pool by the following concurrent operations: +// 1) Test worker gets a session from the pool. +// 2) Test worker turns a session back into the pool. +// 3) Test worker destroys a session got from the pool. +// 4) Healthcheck destroys a broken session (because a worker has already destroyed it). +// 5) Test worker closes the session pool. +// +// During the test, the session pool maintainer maintains the number of sessions, +// and it is expected that all sessions that are taken from session pool remains valid. +// When all test workers and healthcheck workers exit, mockclient, session pool +// and healthchecker should be in consistent state. + +func TestStressSessionPool(t *testing.T) { + t.Parallel() + // Use concurrent workers to test different session pool built from different configurations. + if testing.Short() { + t.SkipNow() + } + for ti, cfg := range []SessionPoolConfig{ + {}, + {MinOpened: 10, MaxOpened: 100}, + {MaxBurst: 50}, + {MinOpened: 10, MaxOpened: 200, MaxBurst: 5}, + {MinOpened: 10, MaxOpened: 200, MaxBurst: 5, WriteSessions: 0.2}, + } { + var wg sync.WaitGroup + // Create a more aggressive session healthchecker to increase test concurrency. + cfg.HealthCheckInterval = 50 * time.Millisecond + cfg.healthCheckSampleInterval = 10 * time.Millisecond + cfg.HealthCheckWorkers = 50 + sc := testutil.NewMockCloudSpannerClient(t) + sc.MakeNice() + cfg.getRPCClient = func() (sppb.SpannerClient, error) { + return sc, nil + } + sp, _ := newSessionPool("mockdb", cfg, nil) + defer sp.hc.close() + defer sp.close() + + for i := 0; i < 100; i++ { + wg.Add(1) + // Schedule a test worker. + go func(idx int, pool *sessionPool, client sppb.SpannerClient) { + defer wg.Done() + // Test worker iterates 1K times and tries different session / session pool operations. + for j := 0; j < 1000; j++ { + if idx%10 == 0 && j >= 900 { + // Close the pool in selected set of workers during the middle of the test. + pool.close() + } + // Take a write sessions ~ 20% of the times. + takeWrite := rand.Intn(5) == 4 + var ( + sh *sessionHandle + gotErr error + ) + if takeWrite { + sh, gotErr = pool.takeWriteSession(context.Background()) + } else { + sh, gotErr = pool.take(context.Background()) + } + if gotErr != nil { + if pool.isValid() { + t.Errorf("%v.%v: pool.take returns error when pool is still valid: %v", ti, idx, gotErr) + } + if wantErr := errInvalidSessionPool(); !testEqual(gotErr, wantErr) { + t.Errorf("%v.%v: got error when pool is closed: %v, want %v", ti, idx, gotErr, wantErr) + } + continue + } + // Verify if session is valid when session pool is valid. Note that if session pool is invalid after sh is taken, + // then sh might be invalidated by healthcheck workers. + if (sh.getID() == "" || sh.session == nil || !sh.session.isValid()) && pool.isValid() { + t.Errorf("%v.%v.%v: pool.take returns invalid session %v", ti, idx, takeWrite, sh.session) + } + if takeWrite && sh.getTransactionID() == nil { + t.Errorf("%v.%v: pool.takeWriteSession returns session %v without transaction", ti, idx, sh.session) + } + if rand.Intn(100) < idx { + // Random sleep before destroying/recycling the session, to give healthcheck worker a chance to step in. + <-time.After(time.Duration(rand.Int63n(int64(cfg.HealthCheckInterval)))) + } + if rand.Intn(100) < idx { + // destroy the session. + sh.destroy() + continue + } + // recycle the session. + sh.recycle() + } + }(i, sp, sc) + } + wg.Wait() + sp.hc.close() + // Here the states of healthchecker, session pool and mockclient are stable. + idleSessions := map[string]bool{} + hcSessions := map[string]bool{} + mockSessions := sc.DumpSessions() + // Dump session pool's idle list. + for sl := sp.idleList.Front(); sl != nil; sl = sl.Next() { + s := sl.Value.(*session) + if idleSessions[s.getID()] { + t.Errorf("%v: found duplicated session in idle list: %v", ti, s.getID()) + } + idleSessions[s.getID()] = true + } + for sl := sp.idleWriteList.Front(); sl != nil; sl = sl.Next() { + s := sl.Value.(*session) + if idleSessions[s.getID()] { + t.Errorf("%v: found duplicated session in idle write list: %v", ti, s.getID()) + } + idleSessions[s.getID()] = true + } + sp.mu.Lock() + if int(sp.numOpened) != len(idleSessions) { + t.Errorf("%v: number of opened sessions (%v) != number of idle sessions (%v)", ti, sp.numOpened, len(idleSessions)) + } + if sp.createReqs != 0 { + t.Errorf("%v: number of pending session creations = %v, want 0", ti, sp.createReqs) + } + // Dump healthcheck queue. + for _, s := range sp.hc.queue.sessions { + if hcSessions[s.getID()] { + t.Errorf("%v: found duplicated session in healthcheck queue: %v", ti, s.getID()) + } + hcSessions[s.getID()] = true + } + sp.mu.Unlock() + + // Verify that idleSessions == hcSessions == mockSessions. + if !testEqual(idleSessions, hcSessions) { + t.Errorf("%v: sessions in idle list (%v) != sessions in healthcheck queue (%v)", ti, idleSessions, hcSessions) + } + if !testEqual(hcSessions, mockSessions) { + t.Errorf("%v: sessions in healthcheck queue (%v) != sessions in mockclient (%v)", ti, hcSessions, mockSessions) + } + sp.close() + mockSessions = sc.DumpSessions() + if len(mockSessions) != 0 { + t.Errorf("Found live sessions: %v", mockSessions) + } + } +} + +// TODO(deklerk) Investigate why this test is flakey, even with waitFor. Example +// flakey failure: session_test.go:946: after 15s waiting, got Scale down. Expect 5 open, got 6 +// +// TestMaintainer checks the session pool maintainer maintains the number of sessions in the following cases +// 1. On initialization of session pool, replenish session pool to meet MinOpened or MaxIdle. +// 2. On increased session usage, provision extra MaxIdle sessions. +// 3. After the surge passes, scale down the session pool accordingly. +func TestMaintainer(t *testing.T) { + t.Skip("asserting session state seems flakey") + t.Parallel() + if testing.Short() { + t.SkipNow() + } + var ( + minOpened uint64 = 5 + maxIdle uint64 = 4 + ) + + sp, _, cleanup := setup(t, SessionPoolConfig{MinOpened: minOpened, MaxIdle: maxIdle}) + defer cleanup() + + sampleInterval := sp.SessionPoolConfig.healthCheckSampleInterval + + waitFor(t, func() error { + sp.mu.Lock() + defer sp.mu.Unlock() + if sp.numOpened != 5 { + return fmt.Errorf("Replenish. Expect %d open, got %d", sp.MinOpened, sp.numOpened) + } + return nil + }) + + // To save test time, we are not creating many sessions, because the time + // to create sessions will have impact on the decision on sessionsToKeep. + // We also parallelize the take and recycle process. + shs := make([]*sessionHandle, 10) + for i := 0; i < len(shs); i++ { + var err error + shs[i], err = sp.take(context.Background()) + if err != nil { + t.Errorf("cannot get session from session pool: %v", err) + } + } + sp.mu.Lock() + if sp.numOpened != 10 { + t.Errorf("Scale out from normal use. Expect %d open, got %d", 10, sp.numOpened) + } + sp.mu.Unlock() + + <-time.After(sampleInterval) + for _, sh := range shs[:7] { + sh.recycle() + } + + waitFor(t, func() error { + sp.mu.Lock() + defer sp.mu.Unlock() + if sp.numOpened != 7 { + return fmt.Errorf("Keep extra MaxIdle sessions. Expect %d open, got %d", 7, sp.numOpened) + } + return nil + }) + + for _, sh := range shs[7:] { + sh.recycle() + } + waitFor(t, func() error { + sp.mu.Lock() + defer sp.mu.Unlock() + if sp.numOpened != minOpened { + return fmt.Errorf("Scale down. Expect %d open, got %d", minOpened, sp.numOpened) + } + return nil + }) +} + +func (s1 *session) Equal(s2 *session) bool { + return s1.client == s2.client && + s1.id == s2.id && + s1.pool == s2.pool && + s1.createTime == s2.createTime && + s1.valid == s2.valid && + s1.hcIndex == s2.hcIndex && + s1.idleList == s2.idleList && + s1.nextCheck.Equal(s2.nextCheck) && + s1.checkingHealth == s2.checkingHealth && + testEqual(s1.md, s2.md) && + bytes.Equal(s1.tx, s2.tx) +} + +func waitFor(t *testing.T, assert func() error) { + timeout := 15 * time.Second + ta := time.After(timeout) + + for { + select { + case <-ta: + if err := assert(); err != nil { + t.Fatalf("after %v waiting, got %v", timeout, err) + } + return + default: + } + + if err := assert(); err != nil { + // Fail. Let's pause and retry. + time.Sleep(10 * time.Millisecond) + continue + } + + return + } +} diff --git a/vendor/cloud.google.com/go/spanner/statement.go b/vendor/cloud.google.com/go/spanner/statement.go new file mode 100644 index 00000000..9b5a6118 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/statement.go @@ -0,0 +1,92 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "errors" + "fmt" + + proto3 "github.com/golang/protobuf/ptypes/struct" + structpb "github.com/golang/protobuf/ptypes/struct" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc/codes" +) + +// A Statement is a SQL query with named parameters. +// +// A parameter placeholder consists of '@' followed by the parameter name. +// Parameter names consist of any combination of letters, numbers, and +// underscores. Names may be entirely numeric (e.g., "WHERE m.id = @5"). +// Parameters may appear anywhere that a literal value is expected. The same +// parameter name may be used more than once. It is an error to execute a +// statement with unbound parameters. On the other hand, it is allowable to +// bind parameter names that are not used. +// +// See the documentation of the Row type for how Go types are mapped to Cloud +// Spanner types. +type Statement struct { + SQL string + Params map[string]interface{} +} + +// NewStatement returns a Statement with the given SQL and an empty Params map. +func NewStatement(sql string) Statement { + return Statement{SQL: sql, Params: map[string]interface{}{}} +} + +var ( + errNilParam = errors.New("use T(nil), not nil") + errNoType = errors.New("no type information") +) + +// convertParams converts a statement's parameters into proto Param and +// ParamTypes. +func (s *Statement) convertParams() (*structpb.Struct, map[string]*sppb.Type, error) { + params := &proto3.Struct{ + Fields: map[string]*proto3.Value{}, + } + paramTypes := map[string]*sppb.Type{} + for k, v := range s.Params { + if v == nil { + return nil, nil, errBindParam(k, v, errNilParam) + } + val, t, err := encodeValue(v) + if err != nil { + return nil, nil, errBindParam(k, v, err) + } + if t == nil { // should not happen, because of nil check above + return nil, nil, errBindParam(k, v, errNoType) + } + params.Fields[k] = val + paramTypes[k] = t + } + + return params, paramTypes, nil +} + +// errBindParam returns error for not being able to bind parameter to query request. +func errBindParam(k string, v interface{}, err error) error { + if err == nil { + return nil + } + se, ok := toSpannerError(err).(*Error) + if !ok { + return spannerErrorf(codes.InvalidArgument, "failed to bind query parameter(name: %q, value: %v), error = <%v>", k, v, err) + } + se.decorate(fmt.Sprintf("failed to bind query parameter(name: %q, value: %v)", k, v)) + return se +} diff --git a/vendor/cloud.google.com/go/spanner/statement_test.go b/vendor/cloud.google.com/go/spanner/statement_test.go new file mode 100644 index 00000000..2cadb974 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/statement_test.go @@ -0,0 +1,196 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "math" + "testing" + "time" + + "cloud.google.com/go/civil" + "github.com/golang/protobuf/proto" + proto3 "github.com/golang/protobuf/ptypes/struct" + sppb "google.golang.org/genproto/googleapis/spanner/v1" +) + +func TestConvertParams(t *testing.T) { + st := Statement{ + SQL: "SELECT id from t_foo WHERE col = @var", + Params: map[string]interface{}{"var": nil}, + } + var ( + t1, _ = time.Parse(time.RFC3339Nano, "2016-11-15T15:04:05.999999999Z") + // Boundaries + t2, _ = time.Parse(time.RFC3339Nano, "0001-01-01T00:00:00.000000000Z") + t3, _ = time.Parse(time.RFC3339Nano, "9999-12-31T23:59:59.999999999Z") + d1, _ = civil.ParseDate("2016-11-15") + // Boundaries + d2, _ = civil.ParseDate("0001-01-01") + d3, _ = civil.ParseDate("9999-12-31") + ) + + type staticStruct struct { + Field int `spanner:"field"` + } + + var ( + s1 = staticStruct{10} + s2 = staticStruct{20} + ) + + for _, test := range []struct { + val interface{} + wantField *proto3.Value + wantType *sppb.Type + }{ + // bool + {true, boolProto(true), boolType()}, + {NullBool{true, true}, boolProto(true), boolType()}, + {NullBool{true, false}, nullProto(), boolType()}, + {[]bool(nil), nullProto(), listType(boolType())}, + {[]bool{}, listProto(), listType(boolType())}, + {[]bool{true, false}, listProto(boolProto(true), boolProto(false)), listType(boolType())}, + {[]NullBool(nil), nullProto(), listType(boolType())}, + {[]NullBool{}, listProto(), listType(boolType())}, + {[]NullBool{{true, true}, {}}, listProto(boolProto(true), nullProto()), listType(boolType())}, + // int + {int(1), intProto(1), intType()}, + {[]int(nil), nullProto(), listType(intType())}, + {[]int{}, listProto(), listType(intType())}, + {[]int{1, 2}, listProto(intProto(1), intProto(2)), listType(intType())}, + // int64 + {int64(1), intProto(1), intType()}, + {NullInt64{5, true}, intProto(5), intType()}, + {NullInt64{5, false}, nullProto(), intType()}, + {[]int64(nil), nullProto(), listType(intType())}, + {[]int64{}, listProto(), listType(intType())}, + {[]int64{1, 2}, listProto(intProto(1), intProto(2)), listType(intType())}, + {[]NullInt64(nil), nullProto(), listType(intType())}, + {[]NullInt64{}, listProto(), listType(intType())}, + {[]NullInt64{{1, true}, {}}, listProto(intProto(1), nullProto()), listType(intType())}, + // float64 + {0.0, floatProto(0.0), floatType()}, + {math.Inf(1), floatProto(math.Inf(1)), floatType()}, + {math.Inf(-1), floatProto(math.Inf(-1)), floatType()}, + {math.NaN(), floatProto(math.NaN()), floatType()}, + {NullFloat64{2.71, true}, floatProto(2.71), floatType()}, + {NullFloat64{1.41, false}, nullProto(), floatType()}, + {[]float64(nil), nullProto(), listType(floatType())}, + {[]float64{}, listProto(), listType(floatType())}, + {[]float64{2.72, math.Inf(1)}, listProto(floatProto(2.72), floatProto(math.Inf(1))), listType(floatType())}, + {[]NullFloat64(nil), nullProto(), listType(floatType())}, + {[]NullFloat64{}, listProto(), listType(floatType())}, + {[]NullFloat64{{2.72, true}, {}}, listProto(floatProto(2.72), nullProto()), listType(floatType())}, + // string + {"", stringProto(""), stringType()}, + {"foo", stringProto("foo"), stringType()}, + {NullString{"bar", true}, stringProto("bar"), stringType()}, + {NullString{"bar", false}, nullProto(), stringType()}, + {[]string(nil), nullProto(), listType(stringType())}, + {[]string{}, listProto(), listType(stringType())}, + {[]string{"foo", "bar"}, listProto(stringProto("foo"), stringProto("bar")), listType(stringType())}, + {[]NullString(nil), nullProto(), listType(stringType())}, + {[]NullString{}, listProto(), listType(stringType())}, + {[]NullString{{"foo", true}, {}}, listProto(stringProto("foo"), nullProto()), listType(stringType())}, + // bytes + {[]byte{}, bytesProto([]byte{}), bytesType()}, + {[]byte{1, 2, 3}, bytesProto([]byte{1, 2, 3}), bytesType()}, + {[]byte(nil), nullProto(), bytesType()}, + {[][]byte(nil), nullProto(), listType(bytesType())}, + {[][]byte{}, listProto(), listType(bytesType())}, + {[][]byte{{1}, []byte(nil)}, listProto(bytesProto([]byte{1}), nullProto()), listType(bytesType())}, + // date + {d1, dateProto(d1), dateType()}, + {NullDate{civil.Date{}, false}, nullProto(), dateType()}, + {[]civil.Date(nil), nullProto(), listType(dateType())}, + {[]civil.Date{}, listProto(), listType(dateType())}, + {[]civil.Date{d1, d2, d3}, listProto(dateProto(d1), dateProto(d2), dateProto(d3)), listType(dateType())}, + {[]NullDate{{d2, true}, {}}, listProto(dateProto(d2), nullProto()), listType(dateType())}, + // timestamp + {t1, timeProto(t1), timeType()}, + {NullTime{}, nullProto(), timeType()}, + {[]time.Time(nil), nullProto(), listType(timeType())}, + {[]time.Time{}, listProto(), listType(timeType())}, + {[]time.Time{t1, t2, t3}, listProto(timeProto(t1), timeProto(t2), timeProto(t3)), listType(timeType())}, + {[]NullTime{{t2, true}, {}}, listProto(timeProto(t2), nullProto()), listType(timeType())}, + // Struct + { + s1, + listProto(intProto(10)), + structType(mkField("field", intType())), + }, + { + (*struct { + F1 civil.Date `spanner:""` + F2 bool + })(nil), + nullProto(), + structType( + mkField("", dateType()), + mkField("F2", boolType())), + }, + // Array-of-struct + { + []staticStruct{s1, s2}, + listProto(listProto(intProto(10)), listProto(intProto(20))), + listType(structType(mkField("field", intType()))), + }, + } { + st.Params["var"] = test.val + gotParams, gotParamTypes, gotErr := st.convertParams() + if gotErr != nil { + t.Error(gotErr) + continue + } + gotParamField := gotParams.Fields["var"] + if !proto.Equal(gotParamField, test.wantField) { + // handle NaN + if test.wantType.Code == floatType().Code && proto.MarshalTextString(gotParamField) == proto.MarshalTextString(test.wantField) { + continue + } + t.Errorf("%#v: got %v, want %v\n", test.val, gotParamField, test.wantField) + } + gotParamType := gotParamTypes["var"] + if !proto.Equal(gotParamType, test.wantType) { + t.Errorf("%#v: got %v, want %v\n", test.val, gotParamType, test.wantField) + } + } + + // Verify type error reporting. + for _, test := range []struct { + val interface{} + wantErr error + }{ + { + nil, + errBindParam("var", nil, errNilParam), + }, + } { + st.Params["var"] = test.val + _, _, gotErr := st.convertParams() + if !testEqual(gotErr, test.wantErr) { + t.Errorf("value %#v:\ngot: %v\nwant: %v", test.val, gotErr, test.wantErr) + } + } +} + +func TestNewStatement(t *testing.T) { + s := NewStatement("query") + if got, want := s.SQL, "query"; got != want { + t.Errorf("got %q, want %q", got, want) + } +} diff --git a/vendor/cloud.google.com/go/spanner/timestampbound.go b/vendor/cloud.google.com/go/spanner/timestampbound.go new file mode 100644 index 00000000..064e110d --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/timestampbound.go @@ -0,0 +1,240 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "fmt" + "time" + + pbd "github.com/golang/protobuf/ptypes/duration" + pbt "github.com/golang/protobuf/ptypes/timestamp" + sppb "google.golang.org/genproto/googleapis/spanner/v1" +) + +// timestampBoundType specifies the timestamp bound mode. +type timestampBoundType int + +const ( + strong timestampBoundType = iota // strong reads + exactStaleness // read with exact staleness + maxStaleness // read with max staleness + minReadTimestamp // read with min freshness + readTimestamp // read data at exact timestamp +) + +// TimestampBound defines how Cloud Spanner will choose a timestamp for a single +// read/query or read-only transaction. +// +// There are three types of timestamp bound: strong, bounded staleness and exact +// staleness. Strong is the default. +// +// If the Cloud Spanner database to be read is geographically distributed, stale +// read-only transactions can execute more quickly than strong or read-write +// transactions, because they are able to execute far from the leader replica. +// +// Each type of timestamp bound is discussed in detail below. A TimestampBound +// can be specified when creating transactions, see the documentation of +// spanner.Client for an example. +// +// Strong reads +// +// Strong reads are guaranteed to see the effects of all transactions that have +// committed before the start of the read. Furthermore, all rows yielded by a +// single read are consistent with each other: if any part of the read +// observes a transaction, all parts of the read see the transaction. +// +// Strong reads are not repeatable: two consecutive strong read-only +// transactions might return inconsistent results if there are concurrent +// writes. If consistency across reads is required, the reads should be +// executed within a transaction or at an exact read timestamp. +// +// Use StrongRead to create a bound of this type. +// +// Exact staleness +// +// An exact staleness timestamp bound executes reads at a user-specified timestamp. +// Reads at a timestamp are guaranteed to see a consistent prefix of the global +// transaction history: they observe modifications done by all transactions with a +// commit timestamp less than or equal to the read timestamp, and observe none of the +// modifications done by transactions with a larger commit timestamp. They will block +// until all conflicting transactions that may be assigned commit timestamps less +// than or equal to the read timestamp have finished. +// +// The timestamp can either be expressed as an absolute Cloud Spanner commit +// timestamp or a staleness relative to the current time. +// +// These modes do not require a "negotiation phase" to pick a timestamp. As a +// result, they execute slightly faster than the equivalent boundedly stale +// concurrency modes. On the other hand, boundedly stale reads usually return +// fresher results. +// +// Use ReadTimestamp and ExactStaleness to create a bound of this type. +// +// Bounded staleness +// +// Bounded staleness modes allow Cloud Spanner to pick the read timestamp, subject to +// a user-provided staleness bound. Cloud Spanner chooses the newest timestamp within +// the staleness bound that allows execution of the reads at the closest +// available replica without blocking. +// +// All rows yielded are consistent with each other: if any part of the read +// observes a transaction, all parts of the read see the transaction. Boundedly +// stale reads are not repeatable: two stale reads, even if they use the same +// staleness bound, can execute at different timestamps and thus return +// inconsistent results. +// +// Boundedly stale reads execute in two phases. The first phase negotiates a +// timestamp among all replicas needed to serve the read. In the second phase, +// reads are executed at the negotiated timestamp. +// +// As a result of this two-phase execution, bounded staleness reads are usually +// a little slower than comparable exact staleness reads. However, they are +// typically able to return fresher results, and are more likely to execute at +// the closest replica. +// +// Because the timestamp negotiation requires up-front knowledge of which rows +// will be read, it can only be used with single-use reads and single-use +// read-only transactions. +// +// Use MinReadTimestamp and MaxStaleness to create a bound of this type. +// +// Old read timestamps and garbage collection +// +// Cloud Spanner continuously garbage collects deleted and overwritten data in the +// background to reclaim storage space. This process is known as "version +// GC". By default, version GC reclaims versions after they are four hours +// old. Because of this, Cloud Spanner cannot perform reads at read timestamps more +// than four hours in the past. This restriction also applies to in-progress +// reads and/or SQL queries whose timestamps become too old while +// executing. Reads and SQL queries with too-old read timestamps fail with the +// error ErrorCode.FAILED_PRECONDITION. +type TimestampBound struct { + mode timestampBoundType + d time.Duration + t time.Time +} + +// StrongRead returns a TimestampBound that will perform reads and queries at a +// timestamp where all previously committed transactions are visible. +func StrongRead() TimestampBound { + return TimestampBound{mode: strong} +} + +// ExactStaleness returns a TimestampBound that will perform reads and queries +// at an exact staleness. +func ExactStaleness(d time.Duration) TimestampBound { + return TimestampBound{ + mode: exactStaleness, + d: d, + } +} + +// MaxStaleness returns a TimestampBound that will perform reads and queries at +// a time chosen to be at most "d" stale. +func MaxStaleness(d time.Duration) TimestampBound { + return TimestampBound{ + mode: maxStaleness, + d: d, + } +} + +// MinReadTimestamp returns a TimestampBound that bound that will perform reads +// and queries at a time chosen to be at least "t". +func MinReadTimestamp(t time.Time) TimestampBound { + return TimestampBound{ + mode: minReadTimestamp, + t: t, + } +} + +// ReadTimestamp returns a TimestampBound that will peform reads and queries at +// the given time. +func ReadTimestamp(t time.Time) TimestampBound { + return TimestampBound{ + mode: readTimestamp, + t: t, + } +} + +func (tb TimestampBound) String() string { + switch tb.mode { + case strong: + return fmt.Sprintf("(strong)") + case exactStaleness: + return fmt.Sprintf("(exactStaleness: %s)", tb.d) + case maxStaleness: + return fmt.Sprintf("(maxStaleness: %s)", tb.d) + case minReadTimestamp: + return fmt.Sprintf("(minReadTimestamp: %s)", tb.t) + case readTimestamp: + return fmt.Sprintf("(readTimestamp: %s)", tb.t) + default: + return fmt.Sprintf("{mode=%v, d=%v, t=%v}", tb.mode, tb.d, tb.t) + } +} + +// durationProto takes a time.Duration and converts it into pdb.Duration for +// calling gRPC APIs. +func durationProto(d time.Duration) *pbd.Duration { + n := d.Nanoseconds() + return &pbd.Duration{ + Seconds: n / int64(time.Second), + Nanos: int32(n % int64(time.Second)), + } +} + +// timestampProto takes a time.Time and converts it into pbt.Timestamp for calling +// gRPC APIs. +func timestampProto(t time.Time) *pbt.Timestamp { + return &pbt.Timestamp{ + Seconds: t.Unix(), + Nanos: int32(t.Nanosecond()), + } +} + +// buildTransactionOptionsReadOnly converts a spanner.TimestampBound into a sppb.TransactionOptions_ReadOnly +// transaction option, which is then used in transactional reads. +func buildTransactionOptionsReadOnly(tb TimestampBound, returnReadTimestamp bool) *sppb.TransactionOptions_ReadOnly { + pb := &sppb.TransactionOptions_ReadOnly{ + ReturnReadTimestamp: returnReadTimestamp, + } + switch tb.mode { + case strong: + pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_Strong{ + Strong: true, + } + case exactStaleness: + pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_ExactStaleness{ + ExactStaleness: durationProto(tb.d), + } + case maxStaleness: + pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_MaxStaleness{ + MaxStaleness: durationProto(tb.d), + } + case minReadTimestamp: + pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_MinReadTimestamp{ + MinReadTimestamp: timestampProto(tb.t), + } + case readTimestamp: + pb.TimestampBound = &sppb.TransactionOptions_ReadOnly_ReadTimestamp{ + ReadTimestamp: timestampProto(tb.t), + } + default: + panic(fmt.Sprintf("buildTransactionOptionsReadOnly(%v,%v)", tb, returnReadTimestamp)) + } + return pb +} diff --git a/vendor/cloud.google.com/go/spanner/timestampbound_test.go b/vendor/cloud.google.com/go/spanner/timestampbound_test.go new file mode 100644 index 00000000..7cfe364d --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/timestampbound_test.go @@ -0,0 +1,206 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "testing" + "time" + + pbd "github.com/golang/protobuf/ptypes/duration" + pbt "github.com/golang/protobuf/ptypes/timestamp" + sppb "google.golang.org/genproto/googleapis/spanner/v1" +) + +// Test generating TimestampBound for strong reads. +func TestStrong(t *testing.T) { + got := StrongRead() + want := TimestampBound{mode: strong} + if !testEqual(got, want) { + t.Errorf("Strong() = %v; want %v", got, want) + } +} + +// Test generating TimestampBound for reads with exact staleness. +func TestExactStaleness(t *testing.T) { + got := ExactStaleness(10 * time.Second) + want := TimestampBound{mode: exactStaleness, d: 10 * time.Second} + if !testEqual(got, want) { + t.Errorf("ExactStaleness(10*time.Second) = %v; want %v", got, want) + } +} + +// Test generating TimestampBound for reads with max staleness. +func TestMaxStaleness(t *testing.T) { + got := MaxStaleness(10 * time.Second) + want := TimestampBound{mode: maxStaleness, d: 10 * time.Second} + if !testEqual(got, want) { + t.Errorf("MaxStaleness(10*time.Second) = %v; want %v", got, want) + } +} + +// Test generating TimestampBound for reads with minimum freshness requirement. +func TestMinReadTimestamp(t *testing.T) { + ts := time.Now() + got := MinReadTimestamp(ts) + want := TimestampBound{mode: minReadTimestamp, t: ts} + if !testEqual(got, want) { + t.Errorf("MinReadTimestamp(%v) = %v; want %v", ts, got, want) + } +} + +// Test generating TimestampBound for reads requesting data at a exact timestamp. +func TestReadTimestamp(t *testing.T) { + ts := time.Now() + got := ReadTimestamp(ts) + want := TimestampBound{mode: readTimestamp, t: ts} + if !testEqual(got, want) { + t.Errorf("ReadTimestamp(%v) = %v; want %v", ts, got, want) + } +} + +// Test TimestampBound.String. +func TestTimestampBoundString(t *testing.T) { + ts := time.Unix(1136239445, 0).UTC() + var tests = []struct { + tb TimestampBound + want string + }{ + { + tb: TimestampBound{mode: strong}, + want: "(strong)", + }, + { + tb: TimestampBound{mode: exactStaleness, d: 10 * time.Second}, + want: "(exactStaleness: 10s)", + }, + { + tb: TimestampBound{mode: maxStaleness, d: 10 * time.Second}, + want: "(maxStaleness: 10s)", + }, + { + tb: TimestampBound{mode: minReadTimestamp, t: ts}, + want: "(minReadTimestamp: 2006-01-02 22:04:05 +0000 UTC)", + }, + { + tb: TimestampBound{mode: readTimestamp, t: ts}, + want: "(readTimestamp: 2006-01-02 22:04:05 +0000 UTC)", + }, + } + for _, test := range tests { + got := test.tb.String() + if got != test.want { + t.Errorf("%#v.String():\ngot %q\nwant %q", test.tb, got, test.want) + } + } +} + +// Test time.Duration to pdb.Duration conversion. +func TestDurationProto(t *testing.T) { + var tests = []struct { + d time.Duration + want pbd.Duration + }{ + {time.Duration(0), pbd.Duration{Seconds: 0, Nanos: 0}}, + {time.Second, pbd.Duration{Seconds: 1, Nanos: 0}}, + {time.Millisecond, pbd.Duration{Seconds: 0, Nanos: 1e6}}, + {15 * time.Nanosecond, pbd.Duration{Seconds: 0, Nanos: 15}}, + {42 * time.Hour, pbd.Duration{Seconds: 151200}}, + {-(1*time.Hour + 4*time.Millisecond), pbd.Duration{Seconds: -3600, Nanos: -4e6}}, + } + for _, test := range tests { + got := durationProto(test.d) + if !testEqual(got, &test.want) { + t.Errorf("durationProto(%v) = %v; want %v", test.d, got, test.want) + } + } +} + +// Test time.Time to pbt.Timestamp conversion. +func TestTimeProto(t *testing.T) { + var tests = []struct { + t time.Time + want pbt.Timestamp + }{ + {time.Unix(0, 0), pbt.Timestamp{}}, + {time.Unix(1136239445, 12345), pbt.Timestamp{Seconds: 1136239445, Nanos: 12345}}, + {time.Unix(-1000, 12345), pbt.Timestamp{Seconds: -1000, Nanos: 12345}}, + } + for _, test := range tests { + got := timestampProto(test.t) + if !testEqual(got, &test.want) { + t.Errorf("timestampProto(%v) = %v; want %v", test.t, got, test.want) + } + } +} + +// Test readonly transaction option builder. +func TestBuildTransactionOptionsReadOnly(t *testing.T) { + ts := time.Unix(1136239445, 12345) + var tests = []struct { + tb TimestampBound + ts bool + want sppb.TransactionOptions_ReadOnly + }{ + { + StrongRead(), false, + sppb.TransactionOptions_ReadOnly{ + TimestampBound: &sppb.TransactionOptions_ReadOnly_Strong{ + Strong: true}, + ReturnReadTimestamp: false, + }, + }, + { + ExactStaleness(10 * time.Second), true, + sppb.TransactionOptions_ReadOnly{ + TimestampBound: &sppb.TransactionOptions_ReadOnly_ExactStaleness{ + ExactStaleness: &pbd.Duration{Seconds: 10}}, + ReturnReadTimestamp: true, + }, + }, + { + MaxStaleness(10 * time.Second), true, + sppb.TransactionOptions_ReadOnly{ + TimestampBound: &sppb.TransactionOptions_ReadOnly_MaxStaleness{ + MaxStaleness: &pbd.Duration{Seconds: 10}}, + ReturnReadTimestamp: true, + }, + }, + + { + MinReadTimestamp(ts), true, + sppb.TransactionOptions_ReadOnly{ + TimestampBound: &sppb.TransactionOptions_ReadOnly_MinReadTimestamp{ + MinReadTimestamp: &pbt.Timestamp{Seconds: 1136239445, Nanos: 12345}}, + ReturnReadTimestamp: true, + }, + }, + { + ReadTimestamp(ts), true, + sppb.TransactionOptions_ReadOnly{ + TimestampBound: &sppb.TransactionOptions_ReadOnly_ReadTimestamp{ + ReadTimestamp: &pbt.Timestamp{Seconds: 1136239445, Nanos: 12345}}, + ReturnReadTimestamp: true, + }, + }, + } + for _, test := range tests { + got := buildTransactionOptionsReadOnly(test.tb, test.ts) + if !testEqual(got, &test.want) { + t.Errorf("buildTransactionOptionsReadOnly(%v,%v) = %v; want %v", test.tb, test.ts, got, test.want) + } + } +} diff --git a/vendor/cloud.google.com/go/spanner/trace.go b/vendor/cloud.google.com/go/spanner/trace.go new file mode 100644 index 00000000..6fdbae41 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/trace.go @@ -0,0 +1,81 @@ +// Copyright 2017 Google LLC +// +// 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 spanner + +import ( + "context" + "fmt" + + "go.opencensus.io/stats" + "go.opencensus.io/stats/view" + "go.opencensus.io/trace" +) + +func traceStartSpan(ctx context.Context, name string) context.Context { + ctx, _ = trace.StartSpan(ctx, name) + return ctx +} + +func traceEndSpan(ctx context.Context, err error) { + span := trace.FromContext(ctx) + if err != nil { + // TODO(jba): Add error code to the status. + span.SetStatus(trace.Status{Message: err.Error()}) + } + span.End() +} + +func tracePrintf(ctx context.Context, attrMap map[string]interface{}, format string, args ...interface{}) { + var attrs []trace.Attribute + for k, v := range attrMap { + var a trace.Attribute + switch v := v.(type) { + case string: + a = trace.StringAttribute(k, v) + case bool: + a = trace.BoolAttribute(k, v) + case int: + a = trace.Int64Attribute(k, int64(v)) + case int64: + a = trace.Int64Attribute(k, v) + default: + a = trace.StringAttribute(k, fmt.Sprintf("%#v", v)) + } + attrs = append(attrs, a) + } + trace.FromContext(ctx).Annotatef(attrs, format, args...) +} + +const statsPrefix = "cloud.google.com/go/spanner/" + +func recordStat(ctx context.Context, m *stats.Int64Measure, n int64) { + stats.Record(ctx, m.M(n)) +} + +var ( + // OpenSessionCount is a measure of the number of sessions currently opened. + // It is EXPERIMENTAL and subject to change or removal without notice. + OpenSessionCount = stats.Int64(statsPrefix+"open_session_count", "Number of sessions currently opened", + stats.UnitDimensionless) + + // OpenSessionCountView is a view of the last value of OpenSessionCount. + // It is EXPERIMENTAL and subject to change or removal without notice. + OpenSessionCountView = &view.View{ + Name: OpenSessionCount.Name(), + Description: OpenSessionCount.Description(), + Measure: OpenSessionCount, + Aggregation: view.LastValue(), + } +) diff --git a/vendor/cloud.google.com/go/spanner/transaction.go b/vendor/cloud.google.com/go/spanner/transaction.go new file mode 100644 index 00000000..a77f452d --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/transaction.go @@ -0,0 +1,913 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "context" + "sync" + "sync/atomic" + "time" + + "google.golang.org/api/iterator" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// transactionID stores a transaction ID which uniquely identifies a transaction in Cloud Spanner. +type transactionID []byte + +// txReadEnv manages a read-transaction environment consisting of a session handle and a transaction selector. +type txReadEnv interface { + // acquire returns a read-transaction environment that can be used to perform a transactional read. + acquire(ctx context.Context) (*sessionHandle, *sppb.TransactionSelector, error) + // sets the transaction's read timestamp + setTimestamp(time.Time) + // release should be called at the end of every transactional read to deal with session recycling. + release(error) +} + +// txReadOnly contains methods for doing transactional reads. +type txReadOnly struct { + // read-transaction environment for performing transactional read operations. + txReadEnv + + sequenceNumber int64 // Atomic. Only needed for DML statements, but used for all. +} + +// errSessionClosed returns error for using a recycled/destroyed session +func errSessionClosed(sh *sessionHandle) error { + return spannerErrorf(codes.FailedPrecondition, + "session is already recycled / destroyed: session_id = %q, rpc_client = %v", sh.getID(), sh.getClient()) +} + +// Read returns a RowIterator for reading multiple rows from the database. +func (t *txReadOnly) Read(ctx context.Context, table string, keys KeySet, columns []string) *RowIterator { + return t.ReadWithOptions(ctx, table, keys, columns, nil) +} + +// ReadUsingIndex calls ReadWithOptions with ReadOptions{Index: index}. +func (t *txReadOnly) ReadUsingIndex(ctx context.Context, table, index string, keys KeySet, columns []string) (ri *RowIterator) { + return t.ReadWithOptions(ctx, table, keys, columns, &ReadOptions{Index: index}) +} + +// ReadOptions provides options for reading rows from a database. +type ReadOptions struct { + // The index to use for reading. If non-empty, you can only read columns that are + // part of the index key, part of the primary key, or stored in the index due to + // a STORING clause in the index definition. + Index string + + // The maximum number of rows to read. A limit value less than 1 means no limit. + Limit int +} + +// ReadWithOptions returns a RowIterator for reading multiple rows from the database. +// Pass a ReadOptions to modify the read operation. +func (t *txReadOnly) ReadWithOptions(ctx context.Context, table string, keys KeySet, columns []string, opts *ReadOptions) (ri *RowIterator) { + ctx = traceStartSpan(ctx, "cloud.google.com/go/spanner.Read") + defer func() { traceEndSpan(ctx, ri.err) }() + var ( + sh *sessionHandle + ts *sppb.TransactionSelector + err error + ) + kset, err := keys.keySetProto() + if err != nil { + return &RowIterator{err: err} + } + if sh, ts, err = t.acquire(ctx); err != nil { + return &RowIterator{err: err} + } + // Cloud Spanner will return "Session not found" on bad sessions. + sid, client := sh.getID(), sh.getClient() + if sid == "" || client == nil { + // Might happen if transaction is closed in the middle of a API call. + return &RowIterator{err: errSessionClosed(sh)} + } + index := "" + limit := 0 + if opts != nil { + index = opts.Index + if opts.Limit > 0 { + limit = opts.Limit + } + } + return stream( + contextWithOutgoingMetadata(ctx, sh.getMetadata()), + func(ctx context.Context, resumeToken []byte) (streamingReceiver, error) { + return client.StreamingRead(ctx, + &sppb.ReadRequest{ + Session: sid, + Transaction: ts, + Table: table, + Index: index, + Columns: columns, + KeySet: kset, + ResumeToken: resumeToken, + Limit: int64(limit), + }) + }, + t.setTimestamp, + t.release, + ) +} + +// errRowNotFound returns error for not being able to read the row identified by key. +func errRowNotFound(table string, key Key) error { + return spannerErrorf(codes.NotFound, "row not found(Table: %v, PrimaryKey: %v)", table, key) +} + +// ReadRow reads a single row from the database. +// +// If no row is present with the given key, then ReadRow returns an error where +// spanner.ErrCode(err) is codes.NotFound. +func (t *txReadOnly) ReadRow(ctx context.Context, table string, key Key, columns []string) (*Row, error) { + iter := t.Read(ctx, table, key, columns) + defer iter.Stop() + row, err := iter.Next() + switch err { + case iterator.Done: + return nil, errRowNotFound(table, key) + case nil: + return row, nil + default: + return nil, err + } +} + +// Query executes a query against the database. It returns a RowIterator +// for retrieving the resulting rows. +// +// Query returns only row data, without a query plan or execution statistics. +// Use QueryWithStats to get rows along with the plan and statistics. +// Use AnalyzeQuery to get just the plan. +func (t *txReadOnly) Query(ctx context.Context, statement Statement) *RowIterator { + return t.query(ctx, statement, sppb.ExecuteSqlRequest_NORMAL) +} + +// Query executes a SQL statement against the database. It returns a RowIterator +// for retrieving the resulting rows. The RowIterator will also be populated +// with a query plan and execution statistics. +func (t *txReadOnly) QueryWithStats(ctx context.Context, statement Statement) *RowIterator { + return t.query(ctx, statement, sppb.ExecuteSqlRequest_PROFILE) +} + +// AnalyzeQuery returns the query plan for statement. +func (t *txReadOnly) AnalyzeQuery(ctx context.Context, statement Statement) (*sppb.QueryPlan, error) { + iter := t.query(ctx, statement, sppb.ExecuteSqlRequest_PLAN) + defer iter.Stop() + for { + _, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + return nil, err + } + } + if iter.QueryPlan == nil { + return nil, spannerErrorf(codes.Internal, "query plan unavailable") + } + return iter.QueryPlan, nil +} + +func (t *txReadOnly) query(ctx context.Context, statement Statement, mode sppb.ExecuteSqlRequest_QueryMode) (ri *RowIterator) { + ctx = traceStartSpan(ctx, "cloud.google.com/go/spanner.Query") + defer func() { traceEndSpan(ctx, ri.err) }() + req, sh, err := t.prepareExecuteSQL(ctx, statement, mode) + if err != nil { + return &RowIterator{err: err} + } + client := sh.getClient() + return stream( + contextWithOutgoingMetadata(ctx, sh.getMetadata()), + func(ctx context.Context, resumeToken []byte) (streamingReceiver, error) { + req.ResumeToken = resumeToken + return client.ExecuteStreamingSql(ctx, req) + }, + t.setTimestamp, + t.release) +} + +func (t *txReadOnly) prepareExecuteSQL(ctx context.Context, stmt Statement, mode sppb.ExecuteSqlRequest_QueryMode) ( + *sppb.ExecuteSqlRequest, *sessionHandle, error) { + sh, ts, err := t.acquire(ctx) + if err != nil { + return nil, nil, err + } + // Cloud Spanner will return "Session not found" on bad sessions. + sid := sh.getID() + if sid == "" { + // Might happen if transaction is closed in the middle of a API call. + return nil, nil, errSessionClosed(sh) + } + params, paramTypes, err := stmt.convertParams() + if err != nil { + return nil, nil, err + } + req := &sppb.ExecuteSqlRequest{ + Session: sid, + Transaction: ts, + Sql: stmt.SQL, + QueryMode: mode, + Seqno: atomic.AddInt64(&t.sequenceNumber, 1), + Params: params, + ParamTypes: paramTypes, + } + return req, sh, nil +} + +// txState is the status of a transaction. +type txState int + +const ( + // transaction is new, waiting to be initialized. + txNew txState = iota + // transaction is being initialized. + txInit + // transaction is active and can perform read/write. + txActive + // transaction is closed, cannot be used anymore. + txClosed +) + +// errRtsUnavailable returns error for read transaction's read timestamp being unavailable. +func errRtsUnavailable() error { + return spannerErrorf(codes.Internal, "read timestamp is unavailable") +} + +// errTxNotInitialized returns error for using an uninitialized transaction. +func errTxNotInitialized() error { + return spannerErrorf(codes.InvalidArgument, "cannot use a uninitialized transaction") +} + +// errTxClosed returns error for using a closed transaction. +func errTxClosed() error { + return spannerErrorf(codes.InvalidArgument, "cannot use a closed transaction") +} + +// errUnexpectedTxState returns error for transaction enters an unexpected state. +func errUnexpectedTxState(ts txState) error { + return spannerErrorf(codes.FailedPrecondition, "unexpected transaction state: %v", ts) +} + +// ReadOnlyTransaction provides a snapshot transaction with guaranteed +// consistency across reads, but does not allow writes. Read-only +// transactions can be configured to read at timestamps in the past. +// +// Read-only transactions do not take locks. Instead, they work by choosing a +// Cloud Spanner timestamp, then executing all reads at that timestamp. Since they do +// not acquire locks, they do not block concurrent read-write transactions. +// +// Unlike locking read-write transactions, read-only transactions never +// abort. They can fail if the chosen read timestamp is garbage collected; +// however, the default garbage collection policy is generous enough that most +// applications do not need to worry about this in practice. See the +// documentation of TimestampBound for more details. +// +// A ReadOnlyTransaction consumes resources on the server until Close is +// called. +type ReadOnlyTransaction struct { + // txReadOnly contains methods for performing transactional reads. + txReadOnly + + // singleUse indicates that the transaction can be used for only one read. + singleUse bool + + // sp is the session pool for allocating a session to execute the read-only transaction. It is set only once during initialization of the ReadOnlyTransaction. + sp *sessionPool + // mu protects concurrent access to the internal states of ReadOnlyTransaction. + mu sync.Mutex + // tx is the transaction ID in Cloud Spanner that uniquely identifies the ReadOnlyTransaction. + tx transactionID + // txReadyOrClosed is for broadcasting that transaction ID has been returned by Cloud Spanner or that transaction is closed. + txReadyOrClosed chan struct{} + // state is the current transaction status of the ReadOnly transaction. + state txState + // sh is the sessionHandle allocated from sp. + sh *sessionHandle + // rts is the read timestamp returned by transactional reads. + rts time.Time + // tb is the read staleness bound specification for transactional reads. + tb TimestampBound +} + +// errTxInitTimeout returns error for timeout in waiting for initialization of the transaction. +func errTxInitTimeout() error { + return spannerErrorf(codes.Canceled, "timeout/context canceled in waiting for transaction's initialization") +} + +// getTimestampBound returns the read staleness bound specified for the ReadOnlyTransaction. +func (t *ReadOnlyTransaction) getTimestampBound() TimestampBound { + t.mu.Lock() + defer t.mu.Unlock() + return t.tb +} + +// begin starts a snapshot read-only Transaction on Cloud Spanner. +func (t *ReadOnlyTransaction) begin(ctx context.Context) error { + var ( + locked bool + tx transactionID + rts time.Time + sh *sessionHandle + err error + ) + defer func() { + if !locked { + t.mu.Lock() + // Not necessary, just to make it clear that t.mu is being held when locked == true. + locked = true + } + if t.state != txClosed { + // Signal other initialization routines. + close(t.txReadyOrClosed) + t.txReadyOrClosed = make(chan struct{}) + } + t.mu.Unlock() + if err != nil && sh != nil { + // Got a valid session handle, but failed to initialize transaction on Cloud Spanner. + if shouldDropSession(err) { + sh.destroy() + } + // If sh.destroy was already executed, this becomes a noop. + sh.recycle() + } + }() + sh, err = t.sp.take(ctx) + if err != nil { + return err + } + err = runRetryable(contextWithOutgoingMetadata(ctx, sh.getMetadata()), func(ctx context.Context) error { + res, e := sh.getClient().BeginTransaction(ctx, &sppb.BeginTransactionRequest{ + Session: sh.getID(), + Options: &sppb.TransactionOptions{ + Mode: &sppb.TransactionOptions_ReadOnly_{ + ReadOnly: buildTransactionOptionsReadOnly(t.getTimestampBound(), true), + }, + }, + }) + if e != nil { + return e + } + tx = res.Id + if res.ReadTimestamp != nil { + rts = time.Unix(res.ReadTimestamp.Seconds, int64(res.ReadTimestamp.Nanos)) + } + return nil + }) + t.mu.Lock() + locked = true // defer function will be executed with t.mu being held. + if t.state == txClosed { // During the execution of t.begin(), t.Close() was invoked. + return errSessionClosed(sh) + } + // If begin() fails, this allows other queries to take over the initialization. + t.tx = nil + if err == nil { + t.tx = tx + t.rts = rts + t.sh = sh + // State transite to txActive. + t.state = txActive + } + return err +} + +// acquire implements txReadEnv.acquire. +func (t *ReadOnlyTransaction) acquire(ctx context.Context) (*sessionHandle, *sppb.TransactionSelector, error) { + if err := checkNestedTxn(ctx); err != nil { + return nil, nil, err + } + if t.singleUse { + return t.acquireSingleUse(ctx) + } + return t.acquireMultiUse(ctx) +} + +func (t *ReadOnlyTransaction) acquireSingleUse(ctx context.Context) (*sessionHandle, *sppb.TransactionSelector, error) { + t.mu.Lock() + defer t.mu.Unlock() + switch t.state { + case txClosed: + // A closed single-use transaction can never be reused. + return nil, nil, errTxClosed() + case txNew: + t.state = txClosed + ts := &sppb.TransactionSelector{ + Selector: &sppb.TransactionSelector_SingleUse{ + SingleUse: &sppb.TransactionOptions{ + Mode: &sppb.TransactionOptions_ReadOnly_{ + ReadOnly: buildTransactionOptionsReadOnly(t.tb, true), + }, + }, + }, + } + sh, err := t.sp.take(ctx) + if err != nil { + return nil, nil, err + } + // Install session handle into t, which can be used for readonly operations later. + t.sh = sh + return sh, ts, nil + } + us := t.state + // SingleUse transaction should only be in either txNew state or txClosed state. + return nil, nil, errUnexpectedTxState(us) +} + +func (t *ReadOnlyTransaction) acquireMultiUse(ctx context.Context) (*sessionHandle, *sppb.TransactionSelector, error) { + for { + t.mu.Lock() + switch t.state { + case txClosed: + t.mu.Unlock() + return nil, nil, errTxClosed() + case txNew: + // State transit to txInit so that no further TimestampBound change is accepted. + t.state = txInit + t.mu.Unlock() + continue + case txInit: + if t.tx != nil { + // Wait for a transaction ID to become ready. + txReadyOrClosed := t.txReadyOrClosed + t.mu.Unlock() + select { + case <-txReadyOrClosed: + // Need to check transaction state again. + continue + case <-ctx.Done(): + // The waiting for initialization is timeout, return error directly. + return nil, nil, errTxInitTimeout() + } + } + // Take the ownership of initializing the transaction. + t.tx = transactionID{} + t.mu.Unlock() + // Begin a read-only transaction. + // TODO: consider adding a transaction option which allow queries to initiate transactions by themselves. Note that this option might not be + // always good because the ID of the new transaction won't be ready till the query returns some data or completes. + if err := t.begin(ctx); err != nil { + return nil, nil, err + } + // If t.begin() succeeded, t.state should have been changed to txActive, so we can just continue here. + continue + case txActive: + sh := t.sh + ts := &sppb.TransactionSelector{ + Selector: &sppb.TransactionSelector_Id{ + Id: t.tx, + }, + } + t.mu.Unlock() + return sh, ts, nil + } + state := t.state + t.mu.Unlock() + return nil, nil, errUnexpectedTxState(state) + } +} + +func (t *ReadOnlyTransaction) setTimestamp(ts time.Time) { + t.mu.Lock() + defer t.mu.Unlock() + if t.rts.IsZero() { + t.rts = ts + } +} + +// release implements txReadEnv.release. +func (t *ReadOnlyTransaction) release(err error) { + t.mu.Lock() + sh := t.sh + t.mu.Unlock() + if sh != nil { // sh could be nil if t.acquire() fails. + if shouldDropSession(err) { + sh.destroy() + } + if t.singleUse { + // If session handle is already destroyed, this becomes a noop. + sh.recycle() + } + } +} + +// Close closes a ReadOnlyTransaction, the transaction cannot perform any reads after being closed. +func (t *ReadOnlyTransaction) Close() { + if t.singleUse { + return + } + t.mu.Lock() + if t.state != txClosed { + t.state = txClosed + close(t.txReadyOrClosed) + } + sh := t.sh + t.mu.Unlock() + if sh == nil { + return + } + // If session handle is already destroyed, this becomes a noop. + // If there are still active queries and if the recycled session is reused before they complete, Cloud Spanner will cancel them + // on behalf of the new transaction on the session. + if sh != nil { + sh.recycle() + } +} + +// Timestamp returns the timestamp chosen to perform reads and +// queries in this transaction. The value can only be read after some +// read or query has either returned some data or completed without +// returning any data. +func (t *ReadOnlyTransaction) Timestamp() (time.Time, error) { + t.mu.Lock() + defer t.mu.Unlock() + if t.rts.IsZero() { + return t.rts, errRtsUnavailable() + } + return t.rts, nil +} + +// WithTimestampBound specifies the TimestampBound to use for read or query. +// This can only be used before the first read or query is invoked. Note: +// bounded staleness is not available with general ReadOnlyTransactions; use a +// single-use ReadOnlyTransaction instead. +// +// The returned value is the ReadOnlyTransaction so calls can be chained. +func (t *ReadOnlyTransaction) WithTimestampBound(tb TimestampBound) *ReadOnlyTransaction { + t.mu.Lock() + defer t.mu.Unlock() + if t.state == txNew { + // Only allow to set TimestampBound before the first query. + t.tb = tb + } + return t +} + +// ReadWriteTransaction provides a locking read-write transaction. +// +// This type of transaction is the only way to write data into Cloud Spanner; +// (*Client).Apply and (*Client).ApplyAtLeastOnce use transactions +// internally. These transactions rely on pessimistic locking and, if +// necessary, two-phase commit. Locking read-write transactions may abort, +// requiring the application to retry. However, the interface exposed by +// (*Client).ReadWriteTransaction eliminates the need for applications to write +// retry loops explicitly. +// +// Locking transactions may be used to atomically read-modify-write data +// anywhere in a database. This type of transaction is externally consistent. +// +// Clients should attempt to minimize the amount of time a transaction is +// active. Faster transactions commit with higher probability and cause less +// contention. Cloud Spanner attempts to keep read locks active as long as the +// transaction continues to do reads. Long periods of inactivity at the client +// may cause Cloud Spanner to release a transaction's locks and abort it. +// +// Reads performed within a transaction acquire locks on the data being +// read. Writes can only be done at commit time, after all reads have been +// completed. Conceptually, a read-write transaction consists of zero or more +// reads or SQL queries followed by a commit. +// +// See (*Client).ReadWriteTransaction for an example. +// +// Semantics +// +// Cloud Spanner can commit the transaction if all read locks it acquired are still +// valid at commit time, and it is able to acquire write locks for all +// writes. Cloud Spanner can abort the transaction for any reason. If a commit +// attempt returns ABORTED, Cloud Spanner guarantees that the transaction has not +// modified any user data in Cloud Spanner. +// +// Unless the transaction commits, Cloud Spanner makes no guarantees about how long +// the transaction's locks were held for. It is an error to use Cloud Spanner locks +// for any sort of mutual exclusion other than between Cloud Spanner transactions +// themselves. +// +// Aborted transactions +// +// Application code does not need to retry explicitly; RunInTransaction will +// automatically retry a transaction if an attempt results in an abort. The +// lock priority of a transaction increases after each prior aborted +// transaction, meaning that the next attempt has a slightly better chance of +// success than before. +// +// Under some circumstances (e.g., many transactions attempting to modify the +// same row(s)), a transaction can abort many times in a short period before +// successfully committing. Thus, it is not a good idea to cap the number of +// retries a transaction can attempt; instead, it is better to limit the total +// amount of wall time spent retrying. +// +// Idle transactions +// +// A transaction is considered idle if it has no outstanding reads or SQL +// queries and has not started a read or SQL query within the last 10 +// seconds. Idle transactions can be aborted by Cloud Spanner so that they don't hold +// on to locks indefinitely. In that case, the commit will fail with error +// ABORTED. +// +// If this behavior is undesirable, periodically executing a simple SQL query +// in the transaction (e.g., SELECT 1) prevents the transaction from becoming +// idle. +type ReadWriteTransaction struct { + // txReadOnly contains methods for performing transactional reads. + txReadOnly + // sh is the sessionHandle allocated from sp. It is set only once during the initialization of ReadWriteTransaction. + sh *sessionHandle + // tx is the transaction ID in Cloud Spanner that uniquely identifies the ReadWriteTransaction. + // It is set only once in ReadWriteTransaction.begin() during the initialization of ReadWriteTransaction. + tx transactionID + // mu protects concurrent access to the internal states of ReadWriteTransaction. + mu sync.Mutex + // state is the current transaction status of the read-write transaction. + state txState + // wb is the set of buffered mutations waiting to be committed. + wb []*Mutation +} + +// BufferWrite adds a list of mutations to the set of updates that will be +// applied when the transaction is committed. It does not actually apply the +// write until the transaction is committed, so the operation does not +// block. The effects of the write won't be visible to any reads (including +// reads done in the same transaction) until the transaction commits. +// +// See the example for Client.ReadWriteTransaction. +func (t *ReadWriteTransaction) BufferWrite(ms []*Mutation) error { + t.mu.Lock() + defer t.mu.Unlock() + if t.state == txClosed { + return errTxClosed() + } + if t.state != txActive { + return errUnexpectedTxState(t.state) + } + t.wb = append(t.wb, ms...) + return nil +} + +// Update executes a DML statement against the database. It returns the number of +// affected rows. +// Update returns an error if the statement is a query. However, the +// query is executed, and any data read will be validated upon commit. +func (t *ReadWriteTransaction) Update(ctx context.Context, stmt Statement) (rowCount int64, err error) { + ctx = traceStartSpan(ctx, "cloud.google.com/go/spanner.Update") + defer func() { traceEndSpan(ctx, err) }() + req, sh, err := t.prepareExecuteSQL(ctx, stmt, sppb.ExecuteSqlRequest_NORMAL) + if err != nil { + return 0, err + } + resultSet, err := sh.getClient().ExecuteSql(ctx, req) + if err != nil { + return 0, err + } + if resultSet.Stats == nil { + return 0, spannerErrorf(codes.InvalidArgument, "query passed to Update: %q", stmt.SQL) + } + return extractRowCount(resultSet.Stats) +} + +// acquire implements txReadEnv.acquire. +func (t *ReadWriteTransaction) acquire(ctx context.Context) (*sessionHandle, *sppb.TransactionSelector, error) { + ts := &sppb.TransactionSelector{ + Selector: &sppb.TransactionSelector_Id{ + Id: t.tx, + }, + } + t.mu.Lock() + defer t.mu.Unlock() + switch t.state { + case txClosed: + return nil, nil, errTxClosed() + case txActive: + return t.sh, ts, nil + } + return nil, nil, errUnexpectedTxState(t.state) +} + +// release implements txReadEnv.release. +func (t *ReadWriteTransaction) release(err error) { + t.mu.Lock() + sh := t.sh + t.mu.Unlock() + if sh != nil && shouldDropSession(err) { + sh.destroy() + } +} + +func beginTransaction(ctx context.Context, sid string, client sppb.SpannerClient) (transactionID, error) { + var tx transactionID + err := runRetryable(ctx, func(ctx context.Context) error { + res, e := client.BeginTransaction(ctx, &sppb.BeginTransactionRequest{ + Session: sid, + Options: &sppb.TransactionOptions{ + Mode: &sppb.TransactionOptions_ReadWrite_{ + ReadWrite: &sppb.TransactionOptions_ReadWrite{}, + }, + }, + }) + if e != nil { + return e + } + tx = res.Id + return nil + }) + if err != nil { + return nil, err + } + return tx, nil +} + +// begin starts a read-write transacton on Cloud Spanner, it is always called before any of the public APIs. +func (t *ReadWriteTransaction) begin(ctx context.Context) error { + if t.tx != nil { + t.state = txActive + return nil + } + tx, err := beginTransaction(contextWithOutgoingMetadata(ctx, t.sh.getMetadata()), t.sh.getID(), t.sh.getClient()) + if err == nil { + t.tx = tx + t.state = txActive + return nil + } + if shouldDropSession(err) { + t.sh.destroy() + } + return err +} + +// commit tries to commit a readwrite transaction to Cloud Spanner. It also returns the commit timestamp for the transactions. +func (t *ReadWriteTransaction) commit(ctx context.Context) (time.Time, error) { + var ts time.Time + t.mu.Lock() + t.state = txClosed // No further operations after commit. + mPb, err := mutationsProto(t.wb) + t.mu.Unlock() + if err != nil { + return ts, err + } + // In case that sessionHandle was destroyed but transaction body fails to report it. + sid, client := t.sh.getID(), t.sh.getClient() + if sid == "" || client == nil { + return ts, errSessionClosed(t.sh) + } + err = runRetryable(contextWithOutgoingMetadata(ctx, t.sh.getMetadata()), func(ctx context.Context) error { + var trailer metadata.MD + res, e := client.Commit(ctx, &sppb.CommitRequest{ + Session: sid, + Transaction: &sppb.CommitRequest_TransactionId{ + TransactionId: t.tx, + }, + Mutations: mPb, + }, grpc.Trailer(&trailer)) + if e != nil { + return toSpannerErrorWithMetadata(e, trailer) + } + if tstamp := res.GetCommitTimestamp(); tstamp != nil { + ts = time.Unix(tstamp.Seconds, int64(tstamp.Nanos)) + } + return nil + }) + if shouldDropSession(err) { + t.sh.destroy() + } + return ts, err +} + +// rollback is called when a commit is aborted or the transaction body runs into error. +func (t *ReadWriteTransaction) rollback(ctx context.Context) { + t.mu.Lock() + // Forbid further operations on rollbacked transaction. + t.state = txClosed + t.mu.Unlock() + // In case that sessionHandle was destroyed but transaction body fails to report it. + sid, client := t.sh.getID(), t.sh.getClient() + if sid == "" || client == nil { + return + } + err := runRetryable(contextWithOutgoingMetadata(ctx, t.sh.getMetadata()), func(ctx context.Context) error { + _, e := client.Rollback(ctx, &sppb.RollbackRequest{ + Session: sid, + TransactionId: t.tx, + }) + return e + }) + if shouldDropSession(err) { + t.sh.destroy() + } + return +} + +// runInTransaction executes f under a read-write transaction context. +func (t *ReadWriteTransaction) runInTransaction(ctx context.Context, f func(context.Context, *ReadWriteTransaction) error) (time.Time, error) { + var ( + ts time.Time + err error + ) + if err = f(context.WithValue(ctx, transactionInProgressKey{}, 1), t); err == nil { + // Try to commit if transaction body returns no error. + ts, err = t.commit(ctx) + } + if err != nil { + if isAbortErr(err) { + // Retry the transaction using the same session on ABORT error. + // Cloud Spanner will create the new transaction with the previous one's wound-wait priority. + err = errRetry(err) + return ts, err + } + // Not going to commit, according to API spec, should rollback the transaction. + t.rollback(ctx) + return ts, err + } + // err == nil, return commit timestamp. + return ts, nil +} + +// writeOnlyTransaction provides the most efficient way of doing write-only transactions. It essentially does blind writes to Cloud Spanner. +type writeOnlyTransaction struct { + // sp is the session pool which writeOnlyTransaction uses to get Cloud Spanner sessions for blind writes. + sp *sessionPool +} + +// applyAtLeastOnce commits a list of mutations to Cloud Spanner at least once, unless one of the following happens: +// 1) Context times out. +// 2) An unretryable error (e.g. database not found) occurs. +// 3) There is a malformed Mutation object. +func (t *writeOnlyTransaction) applyAtLeastOnce(ctx context.Context, ms ...*Mutation) (time.Time, error) { + var ( + ts time.Time + sh *sessionHandle + ) + mPb, err := mutationsProto(ms) + if err != nil { + // Malformed mutation found, just return the error. + return ts, err + } + err = runRetryable(ctx, func(ct context.Context) error { + var e error + var trailers metadata.MD + if sh == nil || sh.getID() == "" || sh.getClient() == nil { + // No usable session for doing the commit, take one from pool. + sh, e = t.sp.take(ctx) + if e != nil { + // sessionPool.Take already retries for session creations/retrivals. + return e + } + } + res, e := sh.getClient().Commit(contextWithOutgoingMetadata(ctx, sh.getMetadata()), &sppb.CommitRequest{ + Session: sh.getID(), + Transaction: &sppb.CommitRequest_SingleUseTransaction{ + SingleUseTransaction: &sppb.TransactionOptions{ + Mode: &sppb.TransactionOptions_ReadWrite_{ + ReadWrite: &sppb.TransactionOptions_ReadWrite{}, + }, + }, + }, + Mutations: mPb, + }, grpc.Trailer(&trailers)) + if e != nil { + if isAbortErr(e) { + // Mask ABORT error as retryable, because aborted transactions are allowed to be retried. + return errRetry(toSpannerErrorWithMetadata(e, trailers)) + } + if shouldDropSession(e) { + // Discard the bad session. + sh.destroy() + } + return e + } + if tstamp := res.GetCommitTimestamp(); tstamp != nil { + ts = time.Unix(tstamp.Seconds, int64(tstamp.Nanos)) + } + return nil + }) + if sh != nil { + sh.recycle() + } + return ts, err +} + +// isAbortedErr returns true if the error indicates that an gRPC call is aborted on the server side. +func isAbortErr(err error) bool { + if err == nil { + return false + } + if ErrCode(err) == codes.Aborted { + return true + } + return false +} diff --git a/vendor/cloud.google.com/go/spanner/transaction_test.go b/vendor/cloud.google.com/go/spanner/transaction_test.go new file mode 100644 index 00000000..9ac6c766 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/transaction_test.go @@ -0,0 +1,221 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "context" + "errors" + "sync" + "testing" + "time" + + "cloud.google.com/go/spanner/internal/testutil" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc/codes" +) + +var ( + errAbrt = spannerErrorf(codes.Aborted, "") + errUsr = errors.New("error") +) + +// setup sets up a Client using mockclient +func mockClient(t *testing.T) (*sessionPool, *testutil.MockCloudSpannerClient, *Client) { + var ( + mc = testutil.NewMockCloudSpannerClient(t) + spc = SessionPoolConfig{} + database = "mockdb" + ) + spc.getRPCClient = func() (sppb.SpannerClient, error) { + return mc, nil + } + sp, err := newSessionPool(database, spc, nil) + if err != nil { + t.Fatalf("cannot create session pool: %v", err) + } + return sp, mc, &Client{ + database: database, + idleSessions: sp, + } +} + +// TestReadOnlyAcquire tests acquire for ReadOnlyTransaction. +func TestReadOnlyAcquire(t *testing.T) { + t.Parallel() + _, mc, client := mockClient(t) + defer client.Close() + mc.SetActions( + testutil.Action{"BeginTransaction", errUsr}, + testutil.Action{"BeginTransaction", nil}, + testutil.Action{"BeginTransaction", nil}, + ) + + // Singleuse should only be used once. + txn := client.Single() + defer txn.Close() + _, _, e := txn.acquire(context.Background()) + if e != nil { + t.Errorf("Acquire for single use, got %v, want nil.", e) + } + _, _, e = txn.acquire(context.Background()) + if wantErr := errTxClosed(); !testEqual(e, wantErr) { + t.Errorf("Second acquire for single use, got %v, want %v.", e, wantErr) + } + // Multiuse can recover from acquire failure. + txn = client.ReadOnlyTransaction() + _, _, e = txn.acquire(context.Background()) + if wantErr := toSpannerError(errUsr); !testEqual(e, wantErr) { + t.Errorf("Acquire for multi use, got %v, want %v.", e, wantErr) + } + _, _, e = txn.acquire(context.Background()) + if e != nil { + t.Errorf("Acquire for multi use, got %v, want nil.", e) + } + txn.Close() + // Multiuse can not be used after close. + _, _, e = txn.acquire(context.Background()) + if wantErr := errTxClosed(); !testEqual(e, wantErr) { + t.Errorf("Second acquire for multi use, got %v, want %v.", e, wantErr) + } + // Multiuse can be acquired concurrently. + txn = client.ReadOnlyTransaction() + defer txn.Close() + mc.Freeze() + var ( + sh1 *sessionHandle + sh2 *sessionHandle + ts1 *sppb.TransactionSelector + ts2 *sppb.TransactionSelector + wg = sync.WaitGroup{} + ) + acquire := func(sh **sessionHandle, ts **sppb.TransactionSelector) { + defer wg.Done() + var e error + *sh, *ts, e = txn.acquire(context.Background()) + if e != nil { + t.Errorf("Concurrent acquire for multiuse, got %v, expect nil.", e) + } + } + wg.Add(2) + go acquire(&sh1, &ts1) + go acquire(&sh2, &ts2) + <-time.After(100 * time.Millisecond) + mc.Unfreeze() + wg.Wait() + if !testEqual(sh1.session, sh2.session) { + t.Errorf("Expect acquire to get same session handle, got %v and %v.", sh1, sh2) + } + if !testEqual(ts1, ts2) { + t.Errorf("Expect acquire to get same transaction selector, got %v and %v.", ts1, ts2) + } +} + +// TestRetryOnAbort tests transaction retries on abort. +func TestRetryOnAbort(t *testing.T) { + t.Parallel() + _, mc, client := mockClient(t) + defer client.Close() + // commit in writeOnlyTransaction + mc.SetActions( + testutil.Action{"Commit", errAbrt}, // abort on first commit + testutil.Action{"Commit", nil}, + ) + + ms := []*Mutation{ + Insert("Accounts", []string{"AccountId", "Nickname", "Balance"}, []interface{}{int64(1), "Foo", int64(50)}), + Insert("Accounts", []string{"AccountId", "Nickname", "Balance"}, []interface{}{int64(2), "Bar", int64(1)}), + } + if _, e := client.Apply(context.Background(), ms, ApplyAtLeastOnce()); e != nil { + t.Errorf("applyAtLeastOnce retry on abort, got %v, want nil.", e) + } + // begin and commit in ReadWriteTransaction + mc.SetActions( + testutil.Action{"BeginTransaction", nil}, // let takeWriteSession succeed and get a session handle + testutil.Action{"Commit", errAbrt}, // let first commit fail and retry will begin new transaction + testutil.Action{"BeginTransaction", errAbrt}, // this time we can fail the begin attempt + testutil.Action{"BeginTransaction", nil}, + testutil.Action{"Commit", nil}, + ) + + if _, e := client.Apply(context.Background(), ms); e != nil { + t.Errorf("ReadWriteTransaction retry on abort, got %v, want nil.", e) + } +} + +// TestBadSession tests bad session (session not found error). +// TODO: session closed from transaction close +func TestBadSession(t *testing.T) { + t.Parallel() + ctx := context.Background() + sp, mc, client := mockClient(t) + defer client.Close() + var sid string + // Prepare a session, get the session id for use in testing. + if s, e := sp.take(ctx); e != nil { + t.Fatal("Prepare session failed.") + } else { + sid = s.getID() + s.recycle() + } + + wantErr := spannerErrorf(codes.NotFound, "Session not found: %v", sid) + // ReadOnlyTransaction + mc.SetActions( + testutil.Action{"BeginTransaction", wantErr}, + testutil.Action{"BeginTransaction", wantErr}, + testutil.Action{"BeginTransaction", wantErr}, + ) + txn := client.ReadOnlyTransaction() + defer txn.Close() + if _, _, got := txn.acquire(ctx); !testEqual(wantErr, got) { + t.Errorf("Expect acquire to fail, got %v, want %v.", got, wantErr) + } + // The failure should recycle the session, we expect it to be used in following requests. + if got := txn.Query(ctx, NewStatement("SELECT 1")); !testEqual(wantErr, got.err) { + t.Errorf("Expect Query to fail, got %v, want %v.", got.err, wantErr) + } + if got := txn.Read(ctx, "Users", KeySets(Key{"alice"}, Key{"bob"}), []string{"name", "email"}); !testEqual(wantErr, got.err) { + t.Errorf("Expect Read to fail, got %v, want %v.", got.err, wantErr) + } + // writeOnlyTransaction + ms := []*Mutation{ + Insert("Accounts", []string{"AccountId", "Nickname", "Balance"}, []interface{}{int64(1), "Foo", int64(50)}), + Insert("Accounts", []string{"AccountId", "Nickname", "Balance"}, []interface{}{int64(2), "Bar", int64(1)}), + } + mc.SetActions(testutil.Action{"Commit", wantErr}) + if _, got := client.Apply(context.Background(), ms, ApplyAtLeastOnce()); !testEqual(wantErr, got) { + t.Errorf("Expect applyAtLeastOnce to fail, got %v, want %v.", got, wantErr) + } +} + +func TestFunctionErrorReturned(t *testing.T) { + t.Parallel() + _, mc, client := mockClient(t) + defer client.Close() + mc.SetActions( + testutil.Action{"BeginTransaction", nil}, + testutil.Action{"Rollback", nil}, + ) + + want := errors.New("an error") + _, got := client.ReadWriteTransaction(context.Background(), + func(context.Context, *ReadWriteTransaction) error { return want }) + if got != want { + t.Errorf("got <%v>, want <%v>", got, want) + } + mc.CheckActionsConsumed() +} diff --git a/vendor/cloud.google.com/go/spanner/util.go b/vendor/cloud.google.com/go/spanner/util.go new file mode 100644 index 00000000..f4f2b25b --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/util.go @@ -0,0 +1,33 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +// maxUint64 returns the maximum of two uint64 +func maxUint64(a, b uint64) uint64 { + if a > b { + return a + } + return b +} + +// minUint64 returns the minimum of two uint64 +func minUint64(a, b uint64) uint64 { + if a > b { + return b + } + return a +} diff --git a/vendor/cloud.google.com/go/spanner/util_test.go b/vendor/cloud.google.com/go/spanner/util_test.go new file mode 100644 index 00000000..270d2ae2 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/util_test.go @@ -0,0 +1,28 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" +) + +func testEqual(a, b interface{}) bool { + return testutil.Equal(a, b, + cmp.AllowUnexported(TimestampBound{}, Error{}, Mutation{}, Row{}, + Partition{}, BatchReadOnlyTransactionID{})) +} diff --git a/vendor/cloud.google.com/go/spanner/value.go b/vendor/cloud.google.com/go/spanner/value.go new file mode 100644 index 00000000..8e049d37 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/value.go @@ -0,0 +1,1608 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "encoding/base64" + "fmt" + "math" + "reflect" + "strconv" + "time" + + "cloud.google.com/go/civil" + "cloud.google.com/go/internal/fields" + proto "github.com/golang/protobuf/proto" + proto3 "github.com/golang/protobuf/ptypes/struct" + sppb "google.golang.org/genproto/googleapis/spanner/v1" + "google.golang.org/grpc/codes" +) + +const commitTimestampPlaceholderString = "spanner.commit_timestamp()" + +var ( + // CommitTimestamp is a special value used to tell Cloud Spanner + // to insert the commit timestamp of the transaction into a column. + // It can be used in a Mutation, or directly used in + // InsertStruct or InsertMap. See ExampleCommitTimestamp. + // This is just a placeholder and the actual value stored in this + // variable has no meaning. + CommitTimestamp = commitTimestamp + commitTimestamp = time.Unix(0, 0).In(time.FixedZone("CommitTimestamp placeholder", 0xDB)) +) + +// NullInt64 represents a Cloud Spanner INT64 that may be NULL. +type NullInt64 struct { + Int64 int64 + Valid bool // Valid is true if Int64 is not NULL. +} + +// String implements Stringer.String for NullInt64 +func (n NullInt64) String() string { + if !n.Valid { + return fmt.Sprintf("%v", "") + } + return fmt.Sprintf("%v", n.Int64) +} + +// NullString represents a Cloud Spanner STRING that may be NULL. +type NullString struct { + StringVal string + Valid bool // Valid is true if StringVal is not NULL. +} + +// String implements Stringer.String for NullString +func (n NullString) String() string { + if !n.Valid { + return fmt.Sprintf("%v", "") + } + return fmt.Sprintf("%q", n.StringVal) +} + +// NullFloat64 represents a Cloud Spanner FLOAT64 that may be NULL. +type NullFloat64 struct { + Float64 float64 + Valid bool // Valid is true if Float64 is not NULL. +} + +// Cloud Spanner STRUCT (aka STRUCT) values (https://cloud.google.com/spanner/docs/data-types#struct-type) +// can be represented by a Go struct value. +// The spanner.StructType of such values is built from the field types and field tag information +// of the Go struct. If a field in the struct type definition has a "spanner:" tag, +// then the value of the "spanner" key in the tag is used as the name for that field in the +// built spanner.StructType, otherwise the field name in the struct definition is used. To specify a +// field with an empty field name in a Cloud Spanner STRUCT type, use the `spanner:""` tag +// annotation against the corresponding field in the Go struct's type definition. +// +// A STRUCT value can contain STRUCT-typed and Array-of-STRUCT typed fields and these can be +// specified using named struct-typed and []struct-typed fields inside a Go struct. However, +// embedded struct fields are not allowed. Unexported struct fields are ignored. +// +// NULL STRUCT values in Cloud Spanner are typed. A nil pointer to a Go struct value can be used to +// specify a NULL STRUCT value of the corresponding spanner.StructType. Nil and empty slices of a +// Go STRUCT type can be used to specify NULL and empty array values respectively of the +// corresponding spanner.StructType. A slice of pointers to a Go struct type can be used to specify +// an array of NULL-able STRUCT values. + +// String implements Stringer.String for NullFloat64 +func (n NullFloat64) String() string { + if !n.Valid { + return fmt.Sprintf("%v", "") + } + return fmt.Sprintf("%v", n.Float64) +} + +// NullBool represents a Cloud Spanner BOOL that may be NULL. +type NullBool struct { + Bool bool + Valid bool // Valid is true if Bool is not NULL. +} + +// String implements Stringer.String for NullBool +func (n NullBool) String() string { + if !n.Valid { + return fmt.Sprintf("%v", "") + } + return fmt.Sprintf("%v", n.Bool) +} + +// NullTime represents a Cloud Spanner TIMESTAMP that may be null. +type NullTime struct { + Time time.Time + Valid bool // Valid is true if Time is not NULL. +} + +// String implements Stringer.String for NullTime +func (n NullTime) String() string { + if !n.Valid { + return fmt.Sprintf("%s", "") + } + return fmt.Sprintf("%q", n.Time.Format(time.RFC3339Nano)) +} + +// NullDate represents a Cloud Spanner DATE that may be null. +type NullDate struct { + Date civil.Date + Valid bool // Valid is true if Date is not NULL. +} + +// String implements Stringer.String for NullDate +func (n NullDate) String() string { + if !n.Valid { + return fmt.Sprintf("%s", "") + } + return fmt.Sprintf("%q", n.Date) +} + +// NullRow represents a Cloud Spanner STRUCT that may be NULL. +// See also the document for Row. +// Note that NullRow is not a valid Cloud Spanner column Type. +type NullRow struct { + Row Row + Valid bool // Valid is true if Row is not NULL. +} + +// GenericColumnValue represents the generic encoded value and type of the +// column. See google.spanner.v1.ResultSet proto for details. This can be +// useful for proxying query results when the result types are not known in +// advance. +// +// If you populate a GenericColumnValue from a row using Row.Column or related +// methods, do not modify the contents of Type and Value. +type GenericColumnValue struct { + Type *sppb.Type + Value *proto3.Value +} + +// Decode decodes a GenericColumnValue. The ptr argument should be a pointer +// to a Go value that can accept v. +func (v GenericColumnValue) Decode(ptr interface{}) error { + return decodeValue(v.Value, v.Type, ptr) +} + +// NewGenericColumnValue creates a GenericColumnValue from Go value that is +// valid for Cloud Spanner. +func newGenericColumnValue(v interface{}) (*GenericColumnValue, error) { + value, typ, err := encodeValue(v) + if err != nil { + return nil, err + } + return &GenericColumnValue{Value: value, Type: typ}, nil +} + +// errTypeMismatch returns error for destination not having a compatible type +// with source Cloud Spanner type. +func errTypeMismatch(srcCode, elCode sppb.TypeCode, dst interface{}) error { + s := srcCode.String() + if srcCode == sppb.TypeCode_ARRAY { + s = fmt.Sprintf("%v[%v]", srcCode, elCode) + } + return spannerErrorf(codes.InvalidArgument, "type %T cannot be used for decoding %s", dst, s) +} + +// errNilSpannerType returns error for nil Cloud Spanner type in decoding. +func errNilSpannerType() error { + return spannerErrorf(codes.FailedPrecondition, "unexpected nil Cloud Spanner data type in decoding") +} + +// errNilSrc returns error for decoding from nil proto value. +func errNilSrc() error { + return spannerErrorf(codes.FailedPrecondition, "unexpected nil Cloud Spanner value in decoding") +} + +// errNilDst returns error for decoding into nil interface{}. +func errNilDst(dst interface{}) error { + return spannerErrorf(codes.InvalidArgument, "cannot decode into nil type %T", dst) +} + +// errNilArrElemType returns error for input Cloud Spanner data type being a array but without a +// non-nil array element type. +func errNilArrElemType(t *sppb.Type) error { + return spannerErrorf(codes.FailedPrecondition, "array type %v is with nil array element type", t) +} + +func errUnsupportedEmbeddedStructFields(fname string) error { + return spannerErrorf(codes.InvalidArgument, "Embedded field: %s. Embedded and anonymous fields are not allowed "+ + "when converting Go structs to Cloud Spanner STRUCT values. To create a STRUCT value with an "+ + "unnamed field, use a `spanner:\"\"` field tag.", fname) +} + +// errDstNotForNull returns error for decoding a SQL NULL value into a destination which doesn't +// support NULL values. +func errDstNotForNull(dst interface{}) error { + return spannerErrorf(codes.InvalidArgument, "destination %T cannot support NULL SQL values", dst) +} + +// errBadEncoding returns error for decoding wrongly encoded types. +func errBadEncoding(v *proto3.Value, err error) error { + return spannerErrorf(codes.FailedPrecondition, "%v wasn't correctly encoded: <%v>", v, err) +} + +func parseNullTime(v *proto3.Value, p *NullTime, code sppb.TypeCode, isNull bool) error { + if p == nil { + return errNilDst(p) + } + if code != sppb.TypeCode_TIMESTAMP { + return errTypeMismatch(code, sppb.TypeCode_TYPE_CODE_UNSPECIFIED, p) + } + if isNull { + *p = NullTime{} + return nil + } + x, err := getStringValue(v) + if err != nil { + return err + } + y, err := time.Parse(time.RFC3339Nano, x) + if err != nil { + return errBadEncoding(v, err) + } + p.Valid = true + p.Time = y + return nil +} + +// decodeValue decodes a protobuf Value into a pointer to a Go value, as +// specified by sppb.Type. +func decodeValue(v *proto3.Value, t *sppb.Type, ptr interface{}) error { + if v == nil { + return errNilSrc() + } + if t == nil { + return errNilSpannerType() + } + code := t.Code + acode := sppb.TypeCode_TYPE_CODE_UNSPECIFIED + if code == sppb.TypeCode_ARRAY { + if t.ArrayElementType == nil { + return errNilArrElemType(t) + } + acode = t.ArrayElementType.Code + } + _, isNull := v.Kind.(*proto3.Value_NullValue) + + // Do the decoding based on the type of ptr. + switch p := ptr.(type) { + case nil: + return errNilDst(nil) + case *string: + if p == nil { + return errNilDst(p) + } + if code != sppb.TypeCode_STRING { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + return errDstNotForNull(ptr) + } + x, err := getStringValue(v) + if err != nil { + return err + } + *p = x + case *NullString: + if p == nil { + return errNilDst(p) + } + if code != sppb.TypeCode_STRING { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = NullString{} + break + } + x, err := getStringValue(v) + if err != nil { + return err + } + p.Valid = true + p.StringVal = x + case *[]NullString: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_STRING { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeNullStringArray(x) + if err != nil { + return err + } + *p = y + case *[]string: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_STRING { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeStringArray(x) + if err != nil { + return err + } + *p = y + case *[]byte: + if p == nil { + return errNilDst(p) + } + if code != sppb.TypeCode_BYTES { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getStringValue(v) + if err != nil { + return err + } + y, err := base64.StdEncoding.DecodeString(x) + if err != nil { + return errBadEncoding(v, err) + } + *p = y + case *[][]byte: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_BYTES { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeByteArray(x) + if err != nil { + return err + } + *p = y + case *int64: + if p == nil { + return errNilDst(p) + } + if code != sppb.TypeCode_INT64 { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + return errDstNotForNull(ptr) + } + x, err := getStringValue(v) + if err != nil { + return err + } + y, err := strconv.ParseInt(x, 10, 64) + if err != nil { + return errBadEncoding(v, err) + } + *p = y + case *NullInt64: + if p == nil { + return errNilDst(p) + } + if code != sppb.TypeCode_INT64 { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = NullInt64{} + break + } + x, err := getStringValue(v) + if err != nil { + return err + } + y, err := strconv.ParseInt(x, 10, 64) + if err != nil { + return errBadEncoding(v, err) + } + p.Valid = true + p.Int64 = y + case *[]NullInt64: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_INT64 { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeNullInt64Array(x) + if err != nil { + return err + } + *p = y + case *[]int64: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_INT64 { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeInt64Array(x) + if err != nil { + return err + } + *p = y + case *bool: + if p == nil { + return errNilDst(p) + } + if code != sppb.TypeCode_BOOL { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + return errDstNotForNull(ptr) + } + x, err := getBoolValue(v) + if err != nil { + return err + } + *p = x + case *NullBool: + if p == nil { + return errNilDst(p) + } + if code != sppb.TypeCode_BOOL { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = NullBool{} + break + } + x, err := getBoolValue(v) + if err != nil { + return err + } + p.Valid = true + p.Bool = x + case *[]NullBool: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_BOOL { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeNullBoolArray(x) + if err != nil { + return err + } + *p = y + case *[]bool: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_BOOL { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeBoolArray(x) + if err != nil { + return err + } + *p = y + case *float64: + if p == nil { + return errNilDst(p) + } + if code != sppb.TypeCode_FLOAT64 { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + return errDstNotForNull(ptr) + } + x, err := getFloat64Value(v) + if err != nil { + return err + } + *p = x + case *NullFloat64: + if p == nil { + return errNilDst(p) + } + if code != sppb.TypeCode_FLOAT64 { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = NullFloat64{} + break + } + x, err := getFloat64Value(v) + if err != nil { + return err + } + p.Valid = true + p.Float64 = x + case *[]NullFloat64: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_FLOAT64 { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeNullFloat64Array(x) + if err != nil { + return err + } + *p = y + case *[]float64: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_FLOAT64 { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeFloat64Array(x) + if err != nil { + return err + } + *p = y + case *time.Time: + var nt NullTime + if isNull { + return errDstNotForNull(ptr) + } + err := parseNullTime(v, &nt, code, isNull) + if err != nil { + return nil + } + *p = nt.Time + case *NullTime: + err := parseNullTime(v, p, code, isNull) + if err != nil { + return err + } + case *[]NullTime: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_TIMESTAMP { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeNullTimeArray(x) + if err != nil { + return err + } + *p = y + case *[]time.Time: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_TIMESTAMP { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeTimeArray(x) + if err != nil { + return err + } + *p = y + case *civil.Date: + if p == nil { + return errNilDst(p) + } + if code != sppb.TypeCode_DATE { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + return errDstNotForNull(ptr) + } + x, err := getStringValue(v) + if err != nil { + return err + } + y, err := civil.ParseDate(x) + if err != nil { + return errBadEncoding(v, err) + } + *p = y + case *NullDate: + if p == nil { + return errNilDst(p) + } + if code != sppb.TypeCode_DATE { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = NullDate{} + break + } + x, err := getStringValue(v) + if err != nil { + return err + } + y, err := civil.ParseDate(x) + if err != nil { + return errBadEncoding(v, err) + } + p.Valid = true + p.Date = y + case *[]NullDate: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_DATE { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeNullDateArray(x) + if err != nil { + return err + } + *p = y + case *[]civil.Date: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_DATE { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeDateArray(x) + if err != nil { + return err + } + *p = y + case *[]NullRow: + if p == nil { + return errNilDst(p) + } + if acode != sppb.TypeCode_STRUCT { + return errTypeMismatch(code, acode, ptr) + } + if isNull { + *p = nil + break + } + x, err := getListValue(v) + if err != nil { + return err + } + y, err := decodeRowArray(t.ArrayElementType.StructType, x) + if err != nil { + return err + } + *p = y + case *GenericColumnValue: + *p = GenericColumnValue{Type: t, Value: v} + default: + // Check if the proto encoding is for an array of structs. + if !(code == sppb.TypeCode_ARRAY && acode == sppb.TypeCode_STRUCT) { + return errTypeMismatch(code, acode, ptr) + } + vp := reflect.ValueOf(p) + if !vp.IsValid() { + return errNilDst(p) + } + if !isPtrStructPtrSlice(vp.Type()) { + // The container is not a pointer to a struct pointer slice. + return errTypeMismatch(code, acode, ptr) + } + // Only use reflection for nil detection on slow path. + // Also, IsNil panics on many types, so check it after the type check. + if vp.IsNil() { + return errNilDst(p) + } + if isNull { + // The proto Value is encoding NULL, set the pointer to struct + // slice to nil as well. + vp.Elem().Set(reflect.Zero(vp.Elem().Type())) + break + } + x, err := getListValue(v) + if err != nil { + return err + } + if err = decodeStructArray(t.ArrayElementType.StructType, x, p); err != nil { + return err + } + } + return nil +} + +// errSrvVal returns an error for getting a wrong source protobuf value in decoding. +func errSrcVal(v *proto3.Value, want string) error { + return spannerErrorf(codes.FailedPrecondition, "cannot use %v(Kind: %T) as %s Value", + v, v.GetKind(), want) +} + +// getStringValue returns the string value encoded in proto3.Value v whose +// kind is proto3.Value_StringValue. +func getStringValue(v *proto3.Value) (string, error) { + if x, ok := v.GetKind().(*proto3.Value_StringValue); ok && x != nil { + return x.StringValue, nil + } + return "", errSrcVal(v, "String") +} + +// getBoolValue returns the bool value encoded in proto3.Value v whose +// kind is proto3.Value_BoolValue. +func getBoolValue(v *proto3.Value) (bool, error) { + if x, ok := v.GetKind().(*proto3.Value_BoolValue); ok && x != nil { + return x.BoolValue, nil + } + return false, errSrcVal(v, "Bool") +} + +// getListValue returns the proto3.ListValue contained in proto3.Value v whose +// kind is proto3.Value_ListValue. +func getListValue(v *proto3.Value) (*proto3.ListValue, error) { + if x, ok := v.GetKind().(*proto3.Value_ListValue); ok && x != nil { + return x.ListValue, nil + } + return nil, errSrcVal(v, "List") +} + +// errUnexpectedNumStr returns error for decoder getting a unexpected string for +// representing special float values. +func errUnexpectedNumStr(s string) error { + return spannerErrorf(codes.FailedPrecondition, "unexpected string value %q for number", s) +} + +// getFloat64Value returns the float64 value encoded in proto3.Value v whose +// kind is proto3.Value_NumberValue / proto3.Value_StringValue. +// Cloud Spanner uses string to encode NaN, Infinity and -Infinity. +func getFloat64Value(v *proto3.Value) (float64, error) { + switch x := v.GetKind().(type) { + case *proto3.Value_NumberValue: + if x == nil { + break + } + return x.NumberValue, nil + case *proto3.Value_StringValue: + if x == nil { + break + } + switch x.StringValue { + case "NaN": + return math.NaN(), nil + case "Infinity": + return math.Inf(1), nil + case "-Infinity": + return math.Inf(-1), nil + default: + return 0, errUnexpectedNumStr(x.StringValue) + } + } + return 0, errSrcVal(v, "Number") +} + +// errNilListValue returns error for unexpected nil ListValue in decoding Cloud Spanner ARRAYs. +func errNilListValue(sqlType string) error { + return spannerErrorf(codes.FailedPrecondition, "unexpected nil ListValue in decoding %v array", sqlType) +} + +// errDecodeArrayElement returns error for failure in decoding single array element. +func errDecodeArrayElement(i int, v proto.Message, sqlType string, err error) error { + se, ok := toSpannerError(err).(*Error) + if !ok { + return spannerErrorf(codes.Unknown, + "cannot decode %v(array element %v) as %v, error = <%v>", v, i, sqlType, err) + } + se.decorate(fmt.Sprintf("cannot decode %v(array element %v) as %v", v, i, sqlType)) + return se +} + +// decodeNullStringArray decodes proto3.ListValue pb into a NullString slice. +func decodeNullStringArray(pb *proto3.ListValue) ([]NullString, error) { + if pb == nil { + return nil, errNilListValue("STRING") + } + a := make([]NullString, len(pb.Values)) + for i, v := range pb.Values { + if err := decodeValue(v, stringType(), &a[i]); err != nil { + return nil, errDecodeArrayElement(i, v, "STRING", err) + } + } + return a, nil +} + +// decodeStringArray decodes proto3.ListValue pb into a string slice. +func decodeStringArray(pb *proto3.ListValue) ([]string, error) { + if pb == nil { + return nil, errNilListValue("STRING") + } + a := make([]string, len(pb.Values)) + st := stringType() + for i, v := range pb.Values { + if err := decodeValue(v, st, &a[i]); err != nil { + return nil, errDecodeArrayElement(i, v, "STRING", err) + } + } + return a, nil +} + +// decodeNullInt64Array decodes proto3.ListValue pb into a NullInt64 slice. +func decodeNullInt64Array(pb *proto3.ListValue) ([]NullInt64, error) { + if pb == nil { + return nil, errNilListValue("INT64") + } + a := make([]NullInt64, len(pb.Values)) + for i, v := range pb.Values { + if err := decodeValue(v, intType(), &a[i]); err != nil { + return nil, errDecodeArrayElement(i, v, "INT64", err) + } + } + return a, nil +} + +// decodeInt64Array decodes proto3.ListValue pb into a int64 slice. +func decodeInt64Array(pb *proto3.ListValue) ([]int64, error) { + if pb == nil { + return nil, errNilListValue("INT64") + } + a := make([]int64, len(pb.Values)) + for i, v := range pb.Values { + if err := decodeValue(v, intType(), &a[i]); err != nil { + return nil, errDecodeArrayElement(i, v, "INT64", err) + } + } + return a, nil +} + +// decodeNullBoolArray decodes proto3.ListValue pb into a NullBool slice. +func decodeNullBoolArray(pb *proto3.ListValue) ([]NullBool, error) { + if pb == nil { + return nil, errNilListValue("BOOL") + } + a := make([]NullBool, len(pb.Values)) + for i, v := range pb.Values { + if err := decodeValue(v, boolType(), &a[i]); err != nil { + return nil, errDecodeArrayElement(i, v, "BOOL", err) + } + } + return a, nil +} + +// decodeBoolArray decodes proto3.ListValue pb into a bool slice. +func decodeBoolArray(pb *proto3.ListValue) ([]bool, error) { + if pb == nil { + return nil, errNilListValue("BOOL") + } + a := make([]bool, len(pb.Values)) + for i, v := range pb.Values { + if err := decodeValue(v, boolType(), &a[i]); err != nil { + return nil, errDecodeArrayElement(i, v, "BOOL", err) + } + } + return a, nil +} + +// decodeNullFloat64Array decodes proto3.ListValue pb into a NullFloat64 slice. +func decodeNullFloat64Array(pb *proto3.ListValue) ([]NullFloat64, error) { + if pb == nil { + return nil, errNilListValue("FLOAT64") + } + a := make([]NullFloat64, len(pb.Values)) + for i, v := range pb.Values { + if err := decodeValue(v, floatType(), &a[i]); err != nil { + return nil, errDecodeArrayElement(i, v, "FLOAT64", err) + } + } + return a, nil +} + +// decodeFloat64Array decodes proto3.ListValue pb into a float64 slice. +func decodeFloat64Array(pb *proto3.ListValue) ([]float64, error) { + if pb == nil { + return nil, errNilListValue("FLOAT64") + } + a := make([]float64, len(pb.Values)) + for i, v := range pb.Values { + if err := decodeValue(v, floatType(), &a[i]); err != nil { + return nil, errDecodeArrayElement(i, v, "FLOAT64", err) + } + } + return a, nil +} + +// decodeByteArray decodes proto3.ListValue pb into a slice of byte slice. +func decodeByteArray(pb *proto3.ListValue) ([][]byte, error) { + if pb == nil { + return nil, errNilListValue("BYTES") + } + a := make([][]byte, len(pb.Values)) + for i, v := range pb.Values { + if err := decodeValue(v, bytesType(), &a[i]); err != nil { + return nil, errDecodeArrayElement(i, v, "BYTES", err) + } + } + return a, nil +} + +// decodeNullTimeArray decodes proto3.ListValue pb into a NullTime slice. +func decodeNullTimeArray(pb *proto3.ListValue) ([]NullTime, error) { + if pb == nil { + return nil, errNilListValue("TIMESTAMP") + } + a := make([]NullTime, len(pb.Values)) + for i, v := range pb.Values { + if err := decodeValue(v, timeType(), &a[i]); err != nil { + return nil, errDecodeArrayElement(i, v, "TIMESTAMP", err) + } + } + return a, nil +} + +// decodeTimeArray decodes proto3.ListValue pb into a time.Time slice. +func decodeTimeArray(pb *proto3.ListValue) ([]time.Time, error) { + if pb == nil { + return nil, errNilListValue("TIMESTAMP") + } + a := make([]time.Time, len(pb.Values)) + for i, v := range pb.Values { + if err := decodeValue(v, timeType(), &a[i]); err != nil { + return nil, errDecodeArrayElement(i, v, "TIMESTAMP", err) + } + } + return a, nil +} + +// decodeNullDateArray decodes proto3.ListValue pb into a NullDate slice. +func decodeNullDateArray(pb *proto3.ListValue) ([]NullDate, error) { + if pb == nil { + return nil, errNilListValue("DATE") + } + a := make([]NullDate, len(pb.Values)) + for i, v := range pb.Values { + if err := decodeValue(v, dateType(), &a[i]); err != nil { + return nil, errDecodeArrayElement(i, v, "DATE", err) + } + } + return a, nil +} + +// decodeDateArray decodes proto3.ListValue pb into a civil.Date slice. +func decodeDateArray(pb *proto3.ListValue) ([]civil.Date, error) { + if pb == nil { + return nil, errNilListValue("DATE") + } + a := make([]civil.Date, len(pb.Values)) + for i, v := range pb.Values { + if err := decodeValue(v, dateType(), &a[i]); err != nil { + return nil, errDecodeArrayElement(i, v, "DATE", err) + } + } + return a, nil +} + +func errNotStructElement(i int, v *proto3.Value) error { + return errDecodeArrayElement(i, v, "STRUCT", + spannerErrorf(codes.FailedPrecondition, "%v(type: %T) doesn't encode Cloud Spanner STRUCT", v, v)) +} + +// decodeRowArray decodes proto3.ListValue pb into a NullRow slice according to +// the structural information given in sppb.StructType ty. +func decodeRowArray(ty *sppb.StructType, pb *proto3.ListValue) ([]NullRow, error) { + if pb == nil { + return nil, errNilListValue("STRUCT") + } + a := make([]NullRow, len(pb.Values)) + for i := range pb.Values { + switch v := pb.Values[i].GetKind().(type) { + case *proto3.Value_ListValue: + a[i] = NullRow{ + Row: Row{ + fields: ty.Fields, + vals: v.ListValue.Values, + }, + Valid: true, + } + // Null elements not currently supported by the server, see + // https://cloud.google.com/spanner/docs/query-syntax#using-structs-with-select + case *proto3.Value_NullValue: + // no-op, a[i] is NullRow{} already + default: + return nil, errNotStructElement(i, pb.Values[i]) + } + } + return a, nil +} + +// errNilSpannerStructType returns error for unexpected nil Cloud Spanner STRUCT schema type in decoding. +func errNilSpannerStructType() error { + return spannerErrorf(codes.FailedPrecondition, "unexpected nil StructType in decoding Cloud Spanner STRUCT") +} + +// errUnnamedField returns error for decoding a Cloud Spanner STRUCT with unnamed field into a Go struct. +func errUnnamedField(ty *sppb.StructType, i int) error { + return spannerErrorf(codes.InvalidArgument, "unnamed field %v in Cloud Spanner STRUCT %+v", i, ty) +} + +// errNoOrDupGoField returns error for decoding a Cloud Spanner +// STRUCT into a Go struct which is either missing a field, or has duplicate fields. +func errNoOrDupGoField(s interface{}, f string) error { + return spannerErrorf(codes.InvalidArgument, "Go struct %+v(type %T) has no or duplicate fields for Cloud Spanner STRUCT field %v", s, s, f) +} + +// errDupColNames returns error for duplicated Cloud Spanner STRUCT field names found in decoding a Cloud Spanner STRUCT into a Go struct. +func errDupSpannerField(f string, ty *sppb.StructType) error { + return spannerErrorf(codes.InvalidArgument, "duplicated field name %q in Cloud Spanner STRUCT %+v", f, ty) +} + +// errDecodeStructField returns error for failure in decoding a single field of a Cloud Spanner STRUCT. +func errDecodeStructField(ty *sppb.StructType, f string, err error) error { + se, ok := toSpannerError(err).(*Error) + if !ok { + return spannerErrorf(codes.Unknown, + "cannot decode field %v of Cloud Spanner STRUCT %+v, error = <%v>", f, ty, err) + } + se.decorate(fmt.Sprintf("cannot decode field %v of Cloud Spanner STRUCT %+v", f, ty)) + return se +} + +// decodeStruct decodes proto3.ListValue pb into struct referenced by pointer ptr, according to +// the structural information given in sppb.StructType ty. +func decodeStruct(ty *sppb.StructType, pb *proto3.ListValue, ptr interface{}) error { + if reflect.ValueOf(ptr).IsNil() { + return errNilDst(ptr) + } + if ty == nil { + return errNilSpannerStructType() + } + // t holds the structural information of ptr. + t := reflect.TypeOf(ptr).Elem() + // v is the actual value that ptr points to. + v := reflect.ValueOf(ptr).Elem() + + fields, err := fieldCache.Fields(t) + if err != nil { + return toSpannerError(err) + } + seen := map[string]bool{} + for i, f := range ty.Fields { + if f.Name == "" { + return errUnnamedField(ty, i) + } + sf := fields.Match(f.Name) + if sf == nil { + return errNoOrDupGoField(ptr, f.Name) + } + if seen[f.Name] { + // We don't allow duplicated field name. + return errDupSpannerField(f.Name, ty) + } + // Try to decode a single field. + if err := decodeValue(pb.Values[i], f.Type, v.FieldByIndex(sf.Index).Addr().Interface()); err != nil { + return errDecodeStructField(ty, f.Name, err) + } + // Mark field f.Name as processed. + seen[f.Name] = true + } + return nil +} + +// isPtrStructPtrSlice returns true if ptr is a pointer to a slice of struct pointers. +func isPtrStructPtrSlice(t reflect.Type) bool { + if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Slice { + // t is not a pointer to a slice. + return false + } + if t = t.Elem(); t.Elem().Kind() != reflect.Ptr || t.Elem().Elem().Kind() != reflect.Struct { + // the slice that t points to is not a slice of struct pointers. + return false + } + return true +} + +// decodeStructArray decodes proto3.ListValue pb into struct slice referenced by pointer ptr, according to the +// structural information given in a sppb.StructType. +func decodeStructArray(ty *sppb.StructType, pb *proto3.ListValue, ptr interface{}) error { + if pb == nil { + return errNilListValue("STRUCT") + } + // Type of the struct pointers stored in the slice that ptr points to. + ts := reflect.TypeOf(ptr).Elem().Elem() + // The slice that ptr points to, might be nil at this point. + v := reflect.ValueOf(ptr).Elem() + // Allocate empty slice. + v.Set(reflect.MakeSlice(v.Type(), 0, len(pb.Values))) + // Decode every struct in pb.Values. + for i, pv := range pb.Values { + // Check if pv is a NULL value. + if _, isNull := pv.Kind.(*proto3.Value_NullValue); isNull { + // Append a nil pointer to the slice. + v.Set(reflect.Append(v, reflect.New(ts).Elem())) + continue + } + // Allocate empty struct. + s := reflect.New(ts.Elem()) + // Get proto3.ListValue l from proto3.Value pv. + l, err := getListValue(pv) + if err != nil { + return errDecodeArrayElement(i, pv, "STRUCT", err) + } + // Decode proto3.ListValue l into struct referenced by s.Interface(). + if err = decodeStruct(ty, l, s.Interface()); err != nil { + return errDecodeArrayElement(i, pv, "STRUCT", err) + } + // Append the decoded struct back into the slice. + v.Set(reflect.Append(v, s)) + } + return nil +} + +// errEncoderUnsupportedType returns error for not being able to encode a value of +// certain type. +func errEncoderUnsupportedType(v interface{}) error { + return spannerErrorf(codes.InvalidArgument, "client doesn't support type %T", v) +} + +// encodeValue encodes a Go native type into a proto3.Value. +func encodeValue(v interface{}) (*proto3.Value, *sppb.Type, error) { + pb := &proto3.Value{ + Kind: &proto3.Value_NullValue{NullValue: proto3.NullValue_NULL_VALUE}, + } + var pt *sppb.Type + var err error + switch v := v.(type) { + case nil: + case string: + pb.Kind = stringKind(v) + pt = stringType() + case NullString: + if v.Valid { + return encodeValue(v.StringVal) + } + pt = stringType() + case []string: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(stringType()) + case []NullString: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(stringType()) + case []byte: + if v != nil { + pb.Kind = stringKind(base64.StdEncoding.EncodeToString(v)) + } + pt = bytesType() + case [][]byte: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(bytesType()) + case int: + pb.Kind = stringKind(strconv.FormatInt(int64(v), 10)) + pt = intType() + case []int: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(intType()) + case int64: + pb.Kind = stringKind(strconv.FormatInt(v, 10)) + pt = intType() + case []int64: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(intType()) + case NullInt64: + if v.Valid { + return encodeValue(v.Int64) + } + pt = intType() + case []NullInt64: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(intType()) + case bool: + pb.Kind = &proto3.Value_BoolValue{BoolValue: v} + pt = boolType() + case []bool: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(boolType()) + case NullBool: + if v.Valid { + return encodeValue(v.Bool) + } + pt = boolType() + case []NullBool: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(boolType()) + case float64: + pb.Kind = &proto3.Value_NumberValue{NumberValue: v} + pt = floatType() + case []float64: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(floatType()) + case NullFloat64: + if v.Valid { + return encodeValue(v.Float64) + } + pt = floatType() + case []NullFloat64: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(floatType()) + case time.Time: + if v == commitTimestamp { + pb.Kind = stringKind(commitTimestampPlaceholderString) + } else { + pb.Kind = stringKind(v.UTC().Format(time.RFC3339Nano)) + } + pt = timeType() + case []time.Time: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(timeType()) + case NullTime: + if v.Valid { + return encodeValue(v.Time) + } + pt = timeType() + case []NullTime: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(timeType()) + case civil.Date: + pb.Kind = stringKind(v.String()) + pt = dateType() + case []civil.Date: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(dateType()) + case NullDate: + if v.Valid { + return encodeValue(v.Date) + } + pt = dateType() + case []NullDate: + if v != nil { + pb, err = encodeArray(len(v), func(i int) interface{} { return v[i] }) + if err != nil { + return nil, nil, err + } + } + pt = listType(dateType()) + case GenericColumnValue: + // Deep clone to ensure subsequent changes to v before + // transmission don't affect our encoded value. + pb = proto.Clone(v.Value).(*proto3.Value) + pt = proto.Clone(v.Type).(*sppb.Type) + case []GenericColumnValue: + return nil, nil, errEncoderUnsupportedType(v) + default: + if !isStructOrArrayOfStructValue(v) { + return nil, nil, errEncoderUnsupportedType(v) + } + typ := reflect.TypeOf(v) + + // Value is a Go struct value/ptr. + if (typ.Kind() == reflect.Struct) || + (typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct) { + return encodeStruct(v) + } + + // Value is a slice of Go struct values/ptrs. + if typ.Kind() == reflect.Slice { + return encodeStructArray(v) + } + } + return pb, pt, nil +} + +// Encodes a Go struct value/ptr in v to the spanner Value and Type protos. v itself must +// be non-nil. +func encodeStruct(v interface{}) (*proto3.Value, *sppb.Type, error) { + typ := reflect.TypeOf(v) + val := reflect.ValueOf(v) + + // Pointer to struct. + if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct { + typ = typ.Elem() + if val.IsNil() { + // nil pointer to struct, representing a NULL STRUCT value. Use a dummy value to + // get the type. + _, st, err := encodeStruct(reflect.Zero(typ).Interface()) + if err != nil { + return nil, nil, err + } + return nullProto(), st, nil + } + val = val.Elem() + } + + if typ.Kind() != reflect.Struct { + return nil, nil, errEncoderUnsupportedType(v) + } + + stf := make([]*sppb.StructType_Field, 0, typ.NumField()) + stv := make([]*proto3.Value, 0, typ.NumField()) + + for i := 0; i < typ.NumField(); i++ { + // If the field has a 'spanner' tag, use the value of that tag as the field name. + // This is used to build STRUCT types with unnamed/duplicate fields. + sf := typ.Field(i) + fval := val.Field(i) + + // Embedded fields are not allowed. + if sf.Anonymous { + return nil, nil, errUnsupportedEmbeddedStructFields(sf.Name) + } + + // Unexported fields are ignored. + if !fval.CanInterface() { + continue + } + + fname, ok := sf.Tag.Lookup("spanner") + if !ok { + fname = sf.Name + } + + eval, etype, err := encodeValue(fval.Interface()) + if err != nil { + return nil, nil, err + } + + stf = append(stf, mkField(fname, etype)) + stv = append(stv, eval) + } + + return listProto(stv...), structType(stf...), nil +} + +// Encodes a slice of Go struct values/ptrs in v to the spanner Value and Type protos. v itself +// must be non-nil. +func encodeStructArray(v interface{}) (*proto3.Value, *sppb.Type, error) { + etyp := reflect.TypeOf(v).Elem() + sliceval := reflect.ValueOf(v) + + // Slice of pointers to structs. + if etyp.Kind() == reflect.Ptr { + etyp = etyp.Elem() + } + + // Use a dummy struct value to get the element type + _, elemTyp, err := encodeStruct(reflect.Zero(etyp).Interface()) + if err != nil { + return nil, nil, err + } + + // nil slice represents a NULL array-of-struct. + if sliceval.IsNil() { + return nullProto(), listType(elemTyp), nil + } + + values := make([]*proto3.Value, 0, sliceval.Len()) + + for i := 0; i < sliceval.Len(); i++ { + ev, _, err := encodeStruct(sliceval.Index(i).Interface()) + if err != nil { + return nil, nil, err + } + values = append(values, ev) + } + return listProto(values...), listType(elemTyp), nil +} + +func isStructOrArrayOfStructValue(v interface{}) bool { + typ := reflect.TypeOf(v) + if typ.Kind() == reflect.Slice { + typ = typ.Elem() + } + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + } + return typ.Kind() == reflect.Struct +} + +func isSupportedMutationType(v interface{}) bool { + switch v.(type) { + case nil, string, NullString, []string, []NullString, + []byte, [][]byte, + int, []int, int64, []int64, NullInt64, []NullInt64, + bool, []bool, NullBool, []NullBool, + float64, []float64, NullFloat64, []NullFloat64, + time.Time, []time.Time, NullTime, []NullTime, + civil.Date, []civil.Date, NullDate, []NullDate, + GenericColumnValue: + return true + default: + return false + } +} + +// encodeValueArray encodes a Value array into a proto3.ListValue. +func encodeValueArray(vs []interface{}) (*proto3.ListValue, error) { + lv := &proto3.ListValue{} + lv.Values = make([]*proto3.Value, 0, len(vs)) + for _, v := range vs { + if !isSupportedMutationType(v) { + return nil, errEncoderUnsupportedType(v) + } + pb, _, err := encodeValue(v) + if err != nil { + return nil, err + } + lv.Values = append(lv.Values, pb) + } + return lv, nil +} + +// encodeArray assumes that all values of the array element type encode without error. +func encodeArray(len int, at func(int) interface{}) (*proto3.Value, error) { + vs := make([]*proto3.Value, len) + var err error + for i := 0; i < len; i++ { + vs[i], _, err = encodeValue(at(i)) + if err != nil { + return nil, err + } + } + return listProto(vs...), nil +} + +func spannerTagParser(t reflect.StructTag) (name string, keep bool, other interface{}, err error) { + if s := t.Get("spanner"); s != "" { + if s == "-" { + return "", false, nil, nil + } + return s, true, nil, nil + } + return "", true, nil, nil +} + +var fieldCache = fields.NewCache(spannerTagParser, nil, nil) diff --git a/vendor/cloud.google.com/go/spanner/value_benchmarks_test.go b/vendor/cloud.google.com/go/spanner/value_benchmarks_test.go new file mode 100644 index 00000000..32ea2d7d --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/value_benchmarks_test.go @@ -0,0 +1,211 @@ +// Copyright 2017 Google LLC +// +// 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 spanner + +import ( + "reflect" + "strconv" + "testing" + + "cloud.google.com/go/civil" + proto3 "github.com/golang/protobuf/ptypes/struct" + sppb "google.golang.org/genproto/googleapis/spanner/v1" +) + +func BenchmarkEncodeIntArray(b *testing.B) { + for _, s := range []struct { + name string + f func(a []int) (*proto3.Value, *sppb.Type, error) + }{ + {"Orig", encodeIntArrayOrig}, + {"Func", encodeIntArrayFunc}, + {"Reflect", encodeIntArrayReflect}, + } { + b.Run(s.name, func(b *testing.B) { + for _, size := range []int{1, 10, 100, 1000} { + a := make([]int, size) + b.Run(strconv.Itoa(size), func(b *testing.B) { + for i := 0; i < b.N; i++ { + s.f(a) + } + }) + } + }) + } +} + +func encodeIntArrayOrig(a []int) (*proto3.Value, *sppb.Type, error) { + vs := make([]*proto3.Value, len(a)) + var err error + for i := range a { + vs[i], _, err = encodeValue(a[i]) + if err != nil { + return nil, nil, err + } + } + return listProto(vs...), listType(intType()), nil +} + +func encodeIntArrayFunc(a []int) (*proto3.Value, *sppb.Type, error) { + v, err := encodeArray(len(a), func(i int) interface{} { return a[i] }) + if err != nil { + return nil, nil, err + } + return v, listType(intType()), nil +} + +func encodeIntArrayReflect(a []int) (*proto3.Value, *sppb.Type, error) { + v, err := encodeArrayReflect(a) + if err != nil { + return nil, nil, err + } + return v, listType(intType()), nil +} + +func encodeArrayReflect(a interface{}) (*proto3.Value, error) { + va := reflect.ValueOf(a) + len := va.Len() + vs := make([]*proto3.Value, len) + var err error + for i := 0; i < len; i++ { + vs[i], _, err = encodeValue(va.Index(i).Interface()) + if err != nil { + return nil, err + } + } + return listProto(vs...), nil +} + +func BenchmarkDecodeGeneric(b *testing.B) { + v := stringProto("test") + t := stringType() + var g GenericColumnValue + b.ResetTimer() + for i := 0; i < b.N; i++ { + decodeValue(v, t, &g) + } +} + +func BenchmarkDecodeArray(b *testing.B) { + for _, size := range []int{1, 10, 100, 1000} { + vals := make([]*proto3.Value, size) + for i := 0; i < size; i++ { + vals[i] = dateProto(d1) + } + lv := &proto3.ListValue{Values: vals} + b.Run(strconv.Itoa(size), func(b *testing.B) { + for _, s := range []struct { + name string + decode func(*proto3.ListValue) + }{ + {"DateDirect", decodeArrayDateDirect}, + {"DateFunc", decodeArrayDateFunc}, + {"DateReflect", decodeArrayDateReflect}, + {"StringDecodeStringArray", decodeStringArrayWrap}, + {"StringDirect", decodeArrayStringDirect}, + {"StringFunc", decodeArrayStringFunc}, + {"StringReflect", decodeArrayStringReflect}, + } { + b.Run(s.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + s.decode(lv) + } + }) + } + }) + + } +} + +func decodeArrayDateDirect(pb *proto3.ListValue) { + a := make([]civil.Date, len(pb.Values)) + t := dateType() + for i, v := range pb.Values { + if err := decodeValue(v, t, &a[i]); err != nil { + panic(err) + } + } +} + +func decodeArrayDateFunc(pb *proto3.ListValue) { + a := make([]civil.Date, len(pb.Values)) + if err := decodeArrayFunc(pb, "DATE", dateType(), func(i int) interface{} { return &a[i] }); err != nil { + panic(err) + } +} + +func decodeArrayDateReflect(pb *proto3.ListValue) { + var a []civil.Date + if err := decodeArrayReflect(pb, "DATE", dateType(), &a); err != nil { + panic(err) + } +} + +func decodeStringArrayWrap(pb *proto3.ListValue) { + if _, err := decodeStringArray(pb); err != nil { + panic(err) + } +} + +func decodeArrayStringDirect(pb *proto3.ListValue) { + a := make([]string, len(pb.Values)) + t := stringType() + for i, v := range pb.Values { + if err := decodeValue(v, t, &a[i]); err != nil { + panic(err) + } + } +} + +func decodeArrayStringFunc(pb *proto3.ListValue) { + a := make([]string, len(pb.Values)) + if err := decodeArrayFunc(pb, "STRING", stringType(), func(i int) interface{} { return &a[i] }); err != nil { + panic(err) + } +} + +func decodeArrayStringReflect(pb *proto3.ListValue) { + var a []string + if err := decodeArrayReflect(pb, "STRING", stringType(), &a); err != nil { + panic(err) + } +} + +func decodeArrayFunc(pb *proto3.ListValue, name string, typ *sppb.Type, elptr func(int) interface{}) error { + if pb == nil { + return errNilListValue(name) + } + for i, v := range pb.Values { + if err := decodeValue(v, typ, elptr(i)); err != nil { + return errDecodeArrayElement(i, v, name, err) + } + } + return nil +} + +func decodeArrayReflect(pb *proto3.ListValue, name string, typ *sppb.Type, aptr interface{}) error { + if pb == nil { + return errNilListValue(name) + } + av := reflect.ValueOf(aptr).Elem() + av.Set(reflect.MakeSlice(av.Type(), len(pb.Values), len(pb.Values))) + for i, v := range pb.Values { + if err := decodeValue(v, typ, av.Index(i).Addr().Interface()); err != nil { + av.Set(reflect.Zero(av.Type())) // reset slice to nil + return errDecodeArrayElement(i, v, name, err) + } + } + return nil +} diff --git a/vendor/cloud.google.com/go/spanner/value_test.go b/vendor/cloud.google.com/go/spanner/value_test.go new file mode 100644 index 00000000..4e114220 --- /dev/null +++ b/vendor/cloud.google.com/go/spanner/value_test.go @@ -0,0 +1,1564 @@ +/* +Copyright 2017 Google LLC + +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 spanner + +import ( + "context" + "math" + "reflect" + "testing" + "time" + + "cloud.google.com/go/civil" + proto "github.com/golang/protobuf/proto" + proto3 "github.com/golang/protobuf/ptypes/struct" + sppb "google.golang.org/genproto/googleapis/spanner/v1" +) + +var ( + t1 = mustParseTime("2016-11-15T15:04:05.999999999Z") + // Boundaries + t2 = mustParseTime("0000-01-01T00:00:00.000000000Z") + t3 = mustParseTime("9999-12-31T23:59:59.999999999Z") + // Local timezone + t4 = time.Now() + d1 = mustParseDate("2016-11-15") + d2 = mustParseDate("1678-01-01") +) + +func mustParseTime(s string) time.Time { + t, err := time.Parse(time.RFC3339Nano, s) + if err != nil { + panic(err) + } + return t +} + +func mustParseDate(s string) civil.Date { + d, err := civil.ParseDate(s) + if err != nil { + panic(err) + } + return d +} + +// Test encoding Values. +func TestEncodeValue(t *testing.T) { + var ( + tString = stringType() + tInt = intType() + tBool = boolType() + tFloat = floatType() + tBytes = bytesType() + tTime = timeType() + tDate = dateType() + ) + for i, test := range []struct { + in interface{} + want *proto3.Value + wantType *sppb.Type + }{ + // STRING / STRING ARRAY + {"abc", stringProto("abc"), tString}, + {NullString{"abc", true}, stringProto("abc"), tString}, + {NullString{"abc", false}, nullProto(), tString}, + {[]string(nil), nullProto(), listType(tString)}, + {[]string{"abc", "bcd"}, listProto(stringProto("abc"), stringProto("bcd")), listType(tString)}, + {[]NullString{{"abcd", true}, {"xyz", false}}, listProto(stringProto("abcd"), nullProto()), listType(tString)}, + // BYTES / BYTES ARRAY + {[]byte("foo"), bytesProto([]byte("foo")), tBytes}, + {[]byte(nil), nullProto(), tBytes}, + {[][]byte{nil, []byte("ab")}, listProto(nullProto(), bytesProto([]byte("ab"))), listType(tBytes)}, + {[][]byte(nil), nullProto(), listType(tBytes)}, + // INT64 / INT64 ARRAY + {7, intProto(7), tInt}, + {[]int(nil), nullProto(), listType(tInt)}, + {[]int{31, 127}, listProto(intProto(31), intProto(127)), listType(tInt)}, + {int64(81), intProto(81), tInt}, + {[]int64(nil), nullProto(), listType(tInt)}, + {[]int64{33, 129}, listProto(intProto(33), intProto(129)), listType(tInt)}, + {NullInt64{11, true}, intProto(11), tInt}, + {NullInt64{11, false}, nullProto(), tInt}, + {[]NullInt64{{35, true}, {131, false}}, listProto(intProto(35), nullProto()), listType(tInt)}, + // BOOL / BOOL ARRAY + {true, boolProto(true), tBool}, + {NullBool{true, true}, boolProto(true), tBool}, + {NullBool{true, false}, nullProto(), tBool}, + {[]bool{true, false}, listProto(boolProto(true), boolProto(false)), listType(tBool)}, + {[]NullBool{{true, true}, {true, false}}, listProto(boolProto(true), nullProto()), listType(tBool)}, + // FLOAT64 / FLOAT64 ARRAY + {3.14, floatProto(3.14), tFloat}, + {NullFloat64{3.1415, true}, floatProto(3.1415), tFloat}, + {NullFloat64{math.Inf(1), true}, floatProto(math.Inf(1)), tFloat}, + {NullFloat64{3.14159, false}, nullProto(), tFloat}, + {[]float64(nil), nullProto(), listType(tFloat)}, + {[]float64{3.141, 0.618, math.Inf(-1)}, listProto(floatProto(3.141), floatProto(0.618), floatProto(math.Inf(-1))), listType(tFloat)}, + {[]NullFloat64{{3.141, true}, {0.618, false}}, listProto(floatProto(3.141), nullProto()), listType(tFloat)}, + // TIMESTAMP / TIMESTAMP ARRAY + {t1, timeProto(t1), tTime}, + {NullTime{t1, true}, timeProto(t1), tTime}, + {NullTime{t1, false}, nullProto(), tTime}, + {[]time.Time(nil), nullProto(), listType(tTime)}, + {[]time.Time{t1, t2, t3, t4}, listProto(timeProto(t1), timeProto(t2), timeProto(t3), timeProto(t4)), listType(tTime)}, + {[]NullTime{{t1, true}, {t1, false}}, listProto(timeProto(t1), nullProto()), listType(tTime)}, + // DATE / DATE ARRAY + {d1, dateProto(d1), tDate}, + {NullDate{d1, true}, dateProto(d1), tDate}, + {NullDate{civil.Date{}, false}, nullProto(), tDate}, + {[]civil.Date(nil), nullProto(), listType(tDate)}, + {[]civil.Date{d1, d2}, listProto(dateProto(d1), dateProto(d2)), listType(tDate)}, + {[]NullDate{{d1, true}, {civil.Date{}, false}}, listProto(dateProto(d1), nullProto()), listType(tDate)}, + // GenericColumnValue + {GenericColumnValue{tString, stringProto("abc")}, stringProto("abc"), tString}, + {GenericColumnValue{tString, nullProto()}, nullProto(), tString}, + // not actually valid (stringProto inside int list), but demonstrates pass-through. + { + GenericColumnValue{ + Type: listType(tInt), + Value: listProto(intProto(5), nullProto(), stringProto("bcd")), + }, + listProto(intProto(5), nullProto(), stringProto("bcd")), + listType(tInt), + }, + // placeholder + {CommitTimestamp, stringProto(commitTimestampPlaceholderString), tTime}, + } { + got, gotType, err := encodeValue(test.in) + if err != nil { + t.Fatalf("#%d: got error during encoding: %v, want nil", i, err) + } + if !testEqual(got, test.want) { + t.Errorf("#%d: got encode result: %v, want %v", i, got, test.want) + } + if !testEqual(gotType, test.wantType) { + t.Errorf("#%d: got encode type: %v, want %v", i, gotType, test.wantType) + } + } +} + +type encodeTest struct { + desc string + in interface{} + want *proto3.Value + wantType *sppb.Type +} + +func checkStructEncoding(desc string, got *proto3.Value, gotType *sppb.Type, + want *proto3.Value, wantType *sppb.Type, t *testing.T) { + if !testEqual(got, want) { + t.Errorf("Test %s: got encode result: %v, want %v", desc, got, want) + } + if !testEqual(gotType, wantType) { + t.Errorf("Test %s: got encode type: %v, want %v", desc, gotType, wantType) + } +} + +// Testcase code +func encodeStructValue(test encodeTest, t *testing.T) { + got, gotType, err := encodeValue(test.in) + if err != nil { + t.Fatalf("Test %s: got error during encoding: %v, want nil", test.desc, err) + } + checkStructEncoding(test.desc, got, gotType, test.want, test.wantType, t) +} + +func TestEncodeStructValuePointers(t *testing.T) { + type structf struct { + F int `spanner:"ff2"` + } + nestedStructProto := structType(mkField("ff2", intType())) + + type testType struct { + Stringf string + Structf *structf + ArrStructf []*structf + } + testTypeProto := structType( + mkField("Stringf", stringType()), + mkField("Structf", nestedStructProto), + mkField("ArrStructf", listType(nestedStructProto))) + + for _, test := range []encodeTest{ + { + "Pointer to Go struct with pointers-to-(array)-struct fields.", + &testType{"hello", &structf{50}, []*structf{{30}, {40}}}, + listProto( + stringProto("hello"), + listProto(intProto(50)), + listProto( + listProto(intProto(30)), + listProto(intProto(40)))), + testTypeProto, + }, + { + "Nil pointer to Go struct representing a NULL struct value.", + (*testType)(nil), + nullProto(), + testTypeProto, + }, + { + "Slice of pointers to Go structs with NULL and non-NULL elements.", + []*testType{ + (*testType)(nil), + {"hello", nil, []*structf{nil, {40}}}, + {"world", &structf{70}, nil}, + }, + listProto( + nullProto(), + listProto( + stringProto("hello"), + nullProto(), + listProto(nullProto(), listProto(intProto(40)))), + listProto( + stringProto("world"), + listProto(intProto(70)), + nullProto())), + listType(testTypeProto), + }, + { + "Nil slice of pointers to structs representing a NULL array of structs.", + []*testType(nil), + nullProto(), + listType(testTypeProto), + }, + { + "Empty slice of pointers to structs representing an empty array of structs.", + []*testType{}, + listProto(), + listType(testTypeProto), + }, + } { + encodeStructValue(test, t) + } +} + +func TestEncodeStructValueErrors(t *testing.T) { + type Embedded struct { + A int + } + type embedded struct { + B bool + } + x := 0 + + for _, test := range []struct { + desc string + in interface{} + wantErr error + }{ + { + "Unsupported embedded fields.", + struct{ Embedded }{Embedded{10}}, + errUnsupportedEmbeddedStructFields("Embedded"), + }, + { + "Unsupported pointer to embedded fields.", + struct{ *Embedded }{&Embedded{10}}, + errUnsupportedEmbeddedStructFields("Embedded"), + }, + { + "Unsupported embedded + unexported fields.", + struct { + int + *bool + embedded + }{10, nil, embedded{false}}, + errUnsupportedEmbeddedStructFields("int"), + }, + { + "Unsupported type.", + (**struct{})(nil), + errEncoderUnsupportedType((**struct{})(nil)), + }, + { + "Unsupported type.", + 3, + errEncoderUnsupportedType(3), + }, + { + "Unsupported type.", + &x, + errEncoderUnsupportedType(&x), + }, + } { + _, _, got := encodeStruct(test.in) + if got == nil || !testEqual(test.wantErr, got) { + t.Errorf("Test: %s, expected error %v during decoding, got %v", test.desc, test.wantErr, got) + } + } +} + +func TestEncodeStructValueArrayStructFields(t *testing.T) { + type structf struct { + Intff int + } + + structfType := structType(mkField("Intff", intType())) + for _, test := range []encodeTest{ + { + "Unnamed array-of-struct-typed field.", + struct { + Intf int + ArrStructf []structf `spanner:""` + }{10, []structf{{1}, {2}}}, + listProto( + intProto(10), + listProto( + listProto(intProto(1)), + listProto(intProto(2)))), + structType( + mkField("Intf", intType()), + mkField("", listType(structfType))), + }, + { + "Null array-of-struct-typed field.", + struct { + Intf int + ArrStructf []structf + }{10, []structf(nil)}, + listProto(intProto(10), nullProto()), + structType( + mkField("Intf", intType()), + mkField("ArrStructf", listType(structfType))), + }, + { + "Array-of-struct-typed field representing empty array.", + struct { + Intf int + ArrStructf []structf + }{10, []structf{}}, + listProto(intProto(10), listProto([]*proto3.Value{}...)), + structType( + mkField("Intf", intType()), + mkField("ArrStructf", listType(structfType))), + }, + { + "Array-of-struct-typed field with nullable struct elements.", + struct { + Intf int + ArrStructf []*structf + }{ + 10, + []*structf{(*structf)(nil), {1}}, + }, + listProto( + intProto(10), + listProto( + nullProto(), + listProto(intProto(1)))), + structType( + mkField("Intf", intType()), + mkField("ArrStructf", listType(structfType))), + }, + } { + encodeStructValue(test, t) + } +} + +func TestEncodeStructValueStructFields(t *testing.T) { + type structf struct { + Intff int + } + structfType := structType(mkField("Intff", intType())) + for _, test := range []encodeTest{ + { + "Named struct-type field.", + struct { + Intf int + Structf structf + }{10, structf{10}}, + listProto(intProto(10), listProto(intProto(10))), + structType( + mkField("Intf", intType()), + mkField("Structf", structfType)), + }, + { + "Unnamed struct-type field.", + struct { + Intf int + Structf structf `spanner:""` + }{10, structf{10}}, + listProto(intProto(10), listProto(intProto(10))), + structType( + mkField("Intf", intType()), + mkField("", structfType)), + }, + { + "Duplicate struct-typed field.", + struct { + Structf1 structf `spanner:""` + Structf2 structf `spanner:""` + }{structf{10}, structf{20}}, + listProto(listProto(intProto(10)), listProto(intProto(20))), + structType( + mkField("", structfType), + mkField("", structfType)), + }, + { + "Null struct-typed field.", + struct { + Intf int + Structf *structf + }{10, nil}, + listProto(intProto(10), nullProto()), + structType( + mkField("Intf", intType()), + mkField("Structf", structfType)), + }, + { + "Empty struct-typed field.", + struct { + Intf int + Structf struct{} + }{10, struct{}{}}, + listProto(intProto(10), listProto([]*proto3.Value{}...)), + structType( + mkField("Intf", intType()), + mkField("Structf", structType([]*sppb.StructType_Field{}...))), + }, + } { + encodeStructValue(test, t) + } +} + +func TestEncodeStructValueFieldNames(t *testing.T) { + type embedded struct { + B bool + } + + for _, test := range []encodeTest{ + { + "Duplicate fields.", + struct { + Field1 int `spanner:"field"` + DupField1 int `spanner:"field"` + }{10, 20}, + listProto(intProto(10), intProto(20)), + structType( + mkField("field", intType()), + mkField("field", intType())), + }, + { + "Duplicate Fields (different types).", + struct { + IntField int `spanner:"field"` + StringField string `spanner:"field"` + }{10, "abc"}, + listProto(intProto(10), stringProto("abc")), + structType( + mkField("field", intType()), + mkField("field", stringType())), + }, + { + "Duplicate unnamed fields.", + struct { + Dup int `spanner:""` + Dup1 int `spanner:""` + }{10, 20}, + listProto(intProto(10), intProto(20)), + structType( + mkField("", intType()), + mkField("", intType())), + }, + { + "Named and unnamed fields.", + struct { + Field string + Field1 int `spanner:""` + Field2 string `spanner:"field"` + }{"abc", 10, "def"}, + listProto(stringProto("abc"), intProto(10), stringProto("def")), + structType( + mkField("Field", stringType()), + mkField("", intType()), + mkField("field", stringType())), + }, + { + "Ignored unexported fields.", + struct { + Field int + field bool + Field1 string `spanner:"field"` + }{10, false, "abc"}, + listProto(intProto(10), stringProto("abc")), + structType( + mkField("Field", intType()), + mkField("field", stringType())), + }, + { + "Ignored unexported struct/slice fields.", + struct { + a []*embedded + b []embedded + c embedded + d *embedded + Field1 string `spanner:"field"` + }{nil, nil, embedded{}, nil, "def"}, + listProto(stringProto("def")), + structType( + mkField("field", stringType())), + }, + } { + encodeStructValue(test, t) + } +} + +func TestEncodeStructValueBasicFields(t *testing.T) { + StructTypeProto := structType( + mkField("Stringf", stringType()), + mkField("Intf", intType()), + mkField("Boolf", boolType()), + mkField("Floatf", floatType()), + mkField("Bytef", bytesType()), + mkField("Timef", timeType()), + mkField("Datef", dateType())) + + for _, test := range []encodeTest{ + { + "Basic types.", + struct { + Stringf string + Intf int + Boolf bool + Floatf float64 + Bytef []byte + Timef time.Time + Datef civil.Date + }{"abc", 300, false, 3.45, []byte("foo"), t1, d1}, + listProto( + stringProto("abc"), + intProto(300), + boolProto(false), + floatProto(3.45), + bytesProto([]byte("foo")), + timeProto(t1), + dateProto(d1)), + StructTypeProto, + }, + { + "Basic types null values.", + struct { + Stringf NullString + Intf NullInt64 + Boolf NullBool + Floatf NullFloat64 + Bytef []byte + Timef NullTime + Datef NullDate + }{ + NullString{"abc", false}, + NullInt64{4, false}, + NullBool{false, false}, + NullFloat64{5.6, false}, + nil, + NullTime{t1, false}, + NullDate{d1, false}, + }, + listProto( + nullProto(), + nullProto(), + nullProto(), + nullProto(), + nullProto(), + nullProto(), + nullProto()), + StructTypeProto, + }, + } { + encodeStructValue(test, t) + } +} + +func TestEncodeStructValueArrayFields(t *testing.T) { + StructTypeProto := structType( + mkField("Stringf", listType(stringType())), + mkField("Intf", listType(intType())), + mkField("Int64f", listType(intType())), + mkField("Boolf", listType(boolType())), + mkField("Floatf", listType(floatType())), + mkField("Bytef", listType(bytesType())), + mkField("Timef", listType(timeType())), + mkField("Datef", listType(dateType()))) + + for _, test := range []encodeTest{ + { + "Arrays of basic types with non-nullable elements", + struct { + Stringf []string + Intf []int + Int64f []int64 + Boolf []bool + Floatf []float64 + Bytef [][]byte + Timef []time.Time + Datef []civil.Date + }{ + []string{"abc", "def"}, + []int{4, 67}, + []int64{5, 68}, + []bool{false, true}, + []float64{3.45, 0.93}, + [][]byte{[]byte("foo"), nil}, + []time.Time{t1, t2}, + []civil.Date{d1, d2}, + }, + listProto( + listProto(stringProto("abc"), stringProto("def")), + listProto(intProto(4), intProto(67)), + listProto(intProto(5), intProto(68)), + listProto(boolProto(false), boolProto(true)), + listProto(floatProto(3.45), floatProto(0.93)), + listProto(bytesProto([]byte("foo")), nullProto()), + listProto(timeProto(t1), timeProto(t2)), + listProto(dateProto(d1), dateProto(d2))), + StructTypeProto, + }, + { + "Arrays of basic types with nullable elements.", + struct { + Stringf []NullString + Intf []NullInt64 + Int64f []NullInt64 + Boolf []NullBool + Floatf []NullFloat64 + Bytef [][]byte + Timef []NullTime + Datef []NullDate + }{ + []NullString{{"abc", false}, {"def", true}}, + []NullInt64{{4, false}, {67, true}}, + []NullInt64{{5, false}, {68, true}}, + []NullBool{{true, false}, {false, true}}, + []NullFloat64{{3.45, false}, {0.93, true}}, + [][]byte{[]byte("foo"), nil}, + []NullTime{{t1, false}, {t2, true}}, + []NullDate{{d1, false}, {d2, true}}, + }, + listProto( + listProto(nullProto(), stringProto("def")), + listProto(nullProto(), intProto(67)), + listProto(nullProto(), intProto(68)), + listProto(nullProto(), boolProto(false)), + listProto(nullProto(), floatProto(0.93)), + listProto(bytesProto([]byte("foo")), nullProto()), + listProto(nullProto(), timeProto(t2)), + listProto(nullProto(), dateProto(d2))), + StructTypeProto, + }, + { + "Null arrays of basic types.", + struct { + Stringf []NullString + Intf []NullInt64 + Int64f []NullInt64 + Boolf []NullBool + Floatf []NullFloat64 + Bytef [][]byte + Timef []NullTime + Datef []NullDate + }{ + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + }, + listProto( + nullProto(), + nullProto(), + nullProto(), + nullProto(), + nullProto(), + nullProto(), + nullProto(), + nullProto()), + StructTypeProto, + }, + } { + encodeStructValue(test, t) + } +} + +// Test decoding Values. +func TestDecodeValue(t *testing.T) { + for i, test := range []struct { + in *proto3.Value + t *sppb.Type + want interface{} + fail bool + }{ + // STRING + {stringProto("abc"), stringType(), "abc", false}, + {nullProto(), stringType(), "abc", true}, + {stringProto("abc"), stringType(), NullString{"abc", true}, false}, + {nullProto(), stringType(), NullString{}, false}, + // STRING ARRAY with []NullString + { + listProto(stringProto("abc"), nullProto(), stringProto("bcd")), + listType(stringType()), + []NullString{{"abc", true}, {}, {"bcd", true}}, + false, + }, + {nullProto(), listType(stringType()), []NullString(nil), false}, + // STRING ARRAY with []string + { + listProto(stringProto("abc"), stringProto("bcd")), + listType(stringType()), + []string{"abc", "bcd"}, + false, + }, + // BYTES + {bytesProto([]byte("ab")), bytesType(), []byte("ab"), false}, + {nullProto(), bytesType(), []byte(nil), false}, + // BYTES ARRAY + {listProto(bytesProto([]byte("ab")), nullProto()), listType(bytesType()), [][]byte{[]byte("ab"), nil}, false}, + {nullProto(), listType(bytesType()), [][]byte(nil), false}, + //INT64 + {intProto(15), intType(), int64(15), false}, + {nullProto(), intType(), int64(0), true}, + {intProto(15), intType(), NullInt64{15, true}, false}, + {nullProto(), intType(), NullInt64{}, false}, + // INT64 ARRAY with []NullInt64 + {listProto(intProto(91), nullProto(), intProto(87)), listType(intType()), []NullInt64{{91, true}, {}, {87, true}}, false}, + {nullProto(), listType(intType()), []NullInt64(nil), false}, + // INT64 ARRAY with []int64 + {listProto(intProto(91), intProto(87)), listType(intType()), []int64{91, 87}, false}, + // BOOL + {boolProto(true), boolType(), true, false}, + {nullProto(), boolType(), true, true}, + {boolProto(true), boolType(), NullBool{true, true}, false}, + {nullProto(), boolType(), NullBool{}, false}, + // BOOL ARRAY with []NullBool + {listProto(boolProto(true), boolProto(false), nullProto()), listType(boolType()), []NullBool{{true, true}, {false, true}, {}}, false}, + {nullProto(), listType(boolType()), []NullBool(nil), false}, + // BOOL ARRAY with []bool + {listProto(boolProto(true), boolProto(false)), listType(boolType()), []bool{true, false}, false}, + // FLOAT64 + {floatProto(3.14), floatType(), 3.14, false}, + {nullProto(), floatType(), 0.00, true}, + {floatProto(3.14), floatType(), NullFloat64{3.14, true}, false}, + {nullProto(), floatType(), NullFloat64{}, false}, + // FLOAT64 ARRAY with []NullFloat64 + { + listProto(floatProto(math.Inf(1)), floatProto(math.Inf(-1)), nullProto(), floatProto(3.1)), + listType(floatType()), + []NullFloat64{{math.Inf(1), true}, {math.Inf(-1), true}, {}, {3.1, true}}, + false, + }, + {nullProto(), listType(floatType()), []NullFloat64(nil), false}, + // FLOAT64 ARRAY with []float64 + { + listProto(floatProto(math.Inf(1)), floatProto(math.Inf(-1)), floatProto(3.1)), + listType(floatType()), + []float64{math.Inf(1), math.Inf(-1), 3.1}, + false, + }, + // TIMESTAMP + {timeProto(t1), timeType(), t1, false}, + {timeProto(t1), timeType(), NullTime{t1, true}, false}, + {nullProto(), timeType(), NullTime{}, false}, + // TIMESTAMP ARRAY with []NullTime + {listProto(timeProto(t1), timeProto(t2), timeProto(t3), nullProto()), listType(timeType()), []NullTime{{t1, true}, {t2, true}, {t3, true}, {}}, false}, + {nullProto(), listType(timeType()), []NullTime(nil), false}, + // TIMESTAMP ARRAY with []time.Time + {listProto(timeProto(t1), timeProto(t2), timeProto(t3)), listType(timeType()), []time.Time{t1, t2, t3}, false}, + // DATE + {dateProto(d1), dateType(), d1, false}, + {dateProto(d1), dateType(), NullDate{d1, true}, false}, + {nullProto(), dateType(), NullDate{}, false}, + // DATE ARRAY with []NullDate + {listProto(dateProto(d1), dateProto(d2), nullProto()), listType(dateType()), []NullDate{{d1, true}, {d2, true}, {}}, false}, + {nullProto(), listType(dateType()), []NullDate(nil), false}, + // DATE ARRAY with []civil.Date + {listProto(dateProto(d1), dateProto(d2)), listType(dateType()), []civil.Date{d1, d2}, false}, + // STRUCT ARRAY + // STRUCT schema is equal to the following Go struct: + // type s struct { + // Col1 NullInt64 + // Col2 []struct { + // SubCol1 float64 + // SubCol2 string + // } + // } + { + in: listProto( + listProto( + intProto(3), + listProto( + listProto(floatProto(3.14), stringProto("this")), + listProto(floatProto(0.57), stringProto("siht")), + ), + ), + listProto( + nullProto(), + nullProto(), + ), + nullProto(), + ), + t: listType( + structType( + mkField("Col1", intType()), + mkField( + "Col2", + listType( + structType( + mkField("SubCol1", floatType()), + mkField("SubCol2", stringType()), + ), + ), + ), + ), + ), + want: []NullRow{ + { + Row: Row{ + fields: []*sppb.StructType_Field{ + mkField("Col1", intType()), + mkField( + "Col2", + listType( + structType( + mkField("SubCol1", floatType()), + mkField("SubCol2", stringType()), + ), + ), + ), + }, + vals: []*proto3.Value{ + intProto(3), + listProto( + listProto(floatProto(3.14), stringProto("this")), + listProto(floatProto(0.57), stringProto("siht")), + ), + }, + }, + Valid: true, + }, + { + Row: Row{ + fields: []*sppb.StructType_Field{ + mkField("Col1", intType()), + mkField( + "Col2", + listType( + structType( + mkField("SubCol1", floatType()), + mkField("SubCol2", stringType()), + ), + ), + ), + }, + vals: []*proto3.Value{ + nullProto(), + nullProto(), + }, + }, + Valid: true, + }, + {}, + }, + fail: false, + }, + { + in: listProto( + listProto( + intProto(3), + listProto( + listProto(floatProto(3.14), stringProto("this")), + listProto(floatProto(0.57), stringProto("siht")), + ), + ), + listProto( + nullProto(), + nullProto(), + ), + nullProto(), + ), + t: listType( + structType( + mkField("Col1", intType()), + mkField( + "Col2", + listType( + structType( + mkField("SubCol1", floatType()), + mkField("SubCol2", stringType()), + ), + ), + ), + ), + ), + want: []*struct { + Col1 NullInt64 + StructCol []*struct { + SubCol1 NullFloat64 + SubCol2 string + } `spanner:"Col2"` + }{ + { + Col1: NullInt64{3, true}, + StructCol: []*struct { + SubCol1 NullFloat64 + SubCol2 string + }{ + { + SubCol1: NullFloat64{3.14, true}, + SubCol2: "this", + }, + { + SubCol1: NullFloat64{0.57, true}, + SubCol2: "siht", + }, + }, + }, + { + Col1: NullInt64{}, + StructCol: []*struct { + SubCol1 NullFloat64 + SubCol2 string + }(nil), + }, + nil, + }, + fail: false, + }, + // GenericColumnValue + {stringProto("abc"), stringType(), GenericColumnValue{stringType(), stringProto("abc")}, false}, + {nullProto(), stringType(), GenericColumnValue{stringType(), nullProto()}, false}, + // not actually valid (stringProto inside int list), but demonstrates pass-through. + { + in: listProto(intProto(5), nullProto(), stringProto("bcd")), + t: listType(intType()), + want: GenericColumnValue{ + Type: listType(intType()), + Value: listProto(intProto(5), nullProto(), stringProto("bcd")), + }, + fail: false, + }, + } { + gotp := reflect.New(reflect.TypeOf(test.want)) + if err := decodeValue(test.in, test.t, gotp.Interface()); err != nil { + if !test.fail { + t.Errorf("%d: cannot decode %v(%v): %v", i, test.in, test.t, err) + } + continue + } + if test.fail { + t.Errorf("%d: decoding %v(%v) succeeds unexpectedly, want error", i, test.in, test.t) + continue + } + got := reflect.Indirect(gotp).Interface() + if !testEqual(got, test.want) { + t.Errorf("%d: unexpected decoding result - got %v, want %v", i, got, test.want) + continue + } + } +} + +// Test error cases for decodeValue. +func TestDecodeValueErrors(t *testing.T) { + var s string + for i, test := range []struct { + in *proto3.Value + t *sppb.Type + v interface{} + }{ + {nullProto(), stringType(), nil}, + {nullProto(), stringType(), 1}, + {timeProto(t1), timeType(), &s}, + } { + err := decodeValue(test.in, test.t, test.v) + if err == nil { + t.Errorf("#%d: want error, got nil", i) + } + } +} + +// Test NaN encoding/decoding. +func TestNaN(t *testing.T) { + // Decode NaN value. + f := 0.0 + nf := NullFloat64{} + // To float64 + if err := decodeValue(floatProto(math.NaN()), floatType(), &f); err != nil { + t.Errorf("decodeValue returns %q for %v, want nil", err, floatProto(math.NaN())) + } + if !math.IsNaN(f) { + t.Errorf("f = %v, want %v", f, math.NaN()) + } + // To NullFloat64 + if err := decodeValue(floatProto(math.NaN()), floatType(), &nf); err != nil { + t.Errorf("decodeValue returns %q for %v, want nil", err, floatProto(math.NaN())) + } + if !math.IsNaN(nf.Float64) || !nf.Valid { + t.Errorf("f = %v, want %v", f, NullFloat64{math.NaN(), true}) + } + // Encode NaN value + // From float64 + v, _, err := encodeValue(math.NaN()) + if err != nil { + t.Errorf("encodeValue returns %q for NaN, want nil", err) + } + x, ok := v.GetKind().(*proto3.Value_NumberValue) + if !ok { + t.Errorf("incorrect type for v.GetKind(): %T, want *proto3.Value_NumberValue", v.GetKind()) + } + if !math.IsNaN(x.NumberValue) { + t.Errorf("x.NumberValue = %v, want %v", x.NumberValue, math.NaN()) + } + // From NullFloat64 + v, _, err = encodeValue(NullFloat64{math.NaN(), true}) + if err != nil { + t.Errorf("encodeValue returns %q for NaN, want nil", err) + } + x, ok = v.GetKind().(*proto3.Value_NumberValue) + if !ok { + t.Errorf("incorrect type for v.GetKind(): %T, want *proto3.Value_NumberValue", v.GetKind()) + } + if !math.IsNaN(x.NumberValue) { + t.Errorf("x.NumberValue = %v, want %v", x.NumberValue, math.NaN()) + } +} + +func TestGenericColumnValue(t *testing.T) { + for _, test := range []struct { + in GenericColumnValue + want interface{} + fail bool + }{ + {GenericColumnValue{stringType(), stringProto("abc")}, "abc", false}, + {GenericColumnValue{stringType(), stringProto("abc")}, 5, true}, + {GenericColumnValue{listType(intType()), listProto(intProto(91), nullProto(), intProto(87))}, []NullInt64{{91, true}, {}, {87, true}}, false}, + {GenericColumnValue{intType(), intProto(42)}, GenericColumnValue{intType(), intProto(42)}, false}, // trippy! :-) + } { + gotp := reflect.New(reflect.TypeOf(test.want)) + if err := test.in.Decode(gotp.Interface()); err != nil { + if !test.fail { + t.Errorf("cannot decode %v to %v: %v", test.in, test.want, err) + } + continue + } + if test.fail { + t.Errorf("decoding %v to %v succeeds unexpectedly", test.in, test.want) + } + + // Test we can go backwards as well. + v, err := newGenericColumnValue(test.want) + if err != nil { + t.Errorf("NewGenericColumnValue failed: %v", err) + continue + } + if !testEqual(*v, test.in) { + t.Errorf("unexpected encode result - got %v, want %v", v, test.in) + } + } +} + +func TestDecodeStruct(t *testing.T) { + stype := &sppb.StructType{Fields: []*sppb.StructType_Field{ + {Name: "Id", Type: stringType()}, + {Name: "Time", Type: timeType()}, + }} + lv := listValueProto(stringProto("id"), timeProto(t1)) + + type ( + S1 struct { + ID string + Time time.Time + } + S2 struct { + ID string + Time string + } + ) + var ( + s1 S1 + s2 S2 + ) + + for i, test := range []struct { + ptr interface{} + want interface{} + fail bool + }{ + { + ptr: &s1, + want: &S1{ID: "id", Time: t1}, + }, + { + ptr: &s2, + fail: true, + }, + } { + err := decodeStruct(stype, lv, test.ptr) + if (err != nil) != test.fail { + t.Errorf("#%d: got error %v, wanted fail: %v", i, err, test.fail) + } + if err == nil && !testEqual(test.ptr, test.want) { + t.Errorf("#%d: got %+v, want %+v", i, test.ptr, test.want) + } + } +} + +func TestEncodeStructValueDynamicStructs(t *testing.T) { + dynStructType := reflect.StructOf([]reflect.StructField{ + {Name: "A", Type: reflect.TypeOf(0), Tag: `spanner:"a"`}, + {Name: "B", Type: reflect.TypeOf(""), Tag: `spanner:"b"`}, + }) + dynNullableStructType := reflect.PtrTo(dynStructType) + dynStructArrType := reflect.SliceOf(dynStructType) + dynNullableStructArrType := reflect.SliceOf(dynNullableStructType) + + dynStructValue := reflect.New(dynStructType) + dynStructValue.Elem().Field(0).SetInt(10) + dynStructValue.Elem().Field(1).SetString("abc") + + dynStructArrValue := reflect.MakeSlice(dynNullableStructArrType, 2, 2) + dynStructArrValue.Index(0).Set(reflect.Zero(dynNullableStructType)) + dynStructArrValue.Index(1).Set(dynStructValue) + + structProtoType := structType( + mkField("a", intType()), + mkField("b", stringType())) + + arrProtoType := listType(structProtoType) + + for _, test := range []encodeTest{ + { + "Dynanic non-NULL struct value.", + dynStructValue.Elem().Interface(), + listProto(intProto(10), stringProto("abc")), + structProtoType, + }, + { + "Dynanic NULL struct value.", + reflect.Zero(dynNullableStructType).Interface(), + nullProto(), + structProtoType, + }, + { + "Empty array of dynamic structs.", + reflect.MakeSlice(dynStructArrType, 0, 0).Interface(), + listProto([]*proto3.Value{}...), + arrProtoType, + }, + { + "NULL array of non-NULL-able dynamic structs.", + reflect.Zero(dynStructArrType).Interface(), + nullProto(), + arrProtoType, + }, + { + "NULL array of NULL-able(nil) dynamic structs.", + reflect.Zero(dynNullableStructArrType).Interface(), + nullProto(), + arrProtoType, + }, + { + "Array containing NULL(nil) dynamic-typed struct elements.", + dynStructArrValue.Interface(), + listProto( + nullProto(), + listProto(intProto(10), stringProto("abc"))), + arrProtoType, + }, + } { + encodeStructValue(test, t) + } +} + +func TestEncodeStructValueEmptyStruct(t *testing.T) { + emptyListValue := listProto([]*proto3.Value{}...) + emptyStructType := structType([]*sppb.StructType_Field{}...) + emptyStruct := struct{}{} + nullEmptyStruct := (*struct{})(nil) + + dynamicEmptyStructType := reflect.StructOf(make([]reflect.StructField, 0, 0)) + dynamicStructArrType := reflect.SliceOf(reflect.PtrTo((dynamicEmptyStructType))) + + dynamicEmptyStruct := reflect.New(dynamicEmptyStructType) + dynamicNullEmptyStruct := reflect.Zero(reflect.PtrTo(dynamicEmptyStructType)) + + dynamicStructArrValue := reflect.MakeSlice(dynamicStructArrType, 2, 2) + dynamicStructArrValue.Index(0).Set(dynamicNullEmptyStruct) + dynamicStructArrValue.Index(1).Set(dynamicEmptyStruct) + + for _, test := range []encodeTest{ + { + "Go empty struct.", + emptyStruct, + emptyListValue, + emptyStructType, + }, + { + "Dynamic empty struct.", + dynamicEmptyStruct.Interface(), + emptyListValue, + emptyStructType, + }, + { + "Go NULL empty struct.", + nullEmptyStruct, + nullProto(), + emptyStructType, + }, + { + "Dynamic NULL empty struct.", + dynamicNullEmptyStruct.Interface(), + nullProto(), + emptyStructType, + }, + { + "Non-empty array of dynamic NULL and non-NULL empty structs.", + dynamicStructArrValue.Interface(), + listProto(nullProto(), emptyListValue), + listType(emptyStructType), + }, + { + "Non-empty array of nullable empty structs.", + []*struct{}{nullEmptyStruct, &emptyStruct}, + listProto(nullProto(), emptyListValue), + listType(emptyStructType), + }, + { + "Empty array of empty struct.", + []struct{}{}, + emptyListValue, + listType(emptyStructType), + }, + { + "Null array of empty structs.", + []struct{}(nil), + nullProto(), + listType(emptyStructType), + }, + } { + encodeStructValue(test, t) + } +} + +func TestEncodeStructValueMixedStructTypes(t *testing.T) { + type staticStruct struct { + F int `spanner:"fStatic"` + } + s1 := staticStruct{10} + s2 := (*staticStruct)(nil) + + var f float64 + dynStructType := reflect.StructOf([]reflect.StructField{ + {Name: "A", Type: reflect.TypeOf(f), Tag: `spanner:"fDynamic"`}, + }) + s3 := reflect.New(dynStructType) + s3.Elem().Field(0).SetFloat(3.14) + + for _, test := range []encodeTest{ + { + "'struct' with static and dynamic *struct, []*struct, []struct fields", + struct { + A []staticStruct + B []*staticStruct + C interface{} + }{ + []staticStruct{s1, s1}, + []*staticStruct{&s1, s2}, + s3.Interface(), + }, + listProto( + listProto(listProto(intProto(10)), listProto(intProto(10))), + listProto(listProto(intProto(10)), nullProto()), + listProto(floatProto(3.14))), + structType( + mkField("A", listType(structType(mkField("fStatic", intType())))), + mkField("B", listType(structType(mkField("fStatic", intType())))), + mkField("C", structType(mkField("fDynamic", floatType())))), + }, + } { + encodeStructValue(test, t) + } +} + +func TestBindParamsDynamic(t *testing.T) { + // Verify Statement.bindParams generates correct values and types. + st := Statement{ + SQL: "SELECT id from t_foo WHERE col = @var", + Params: map[string]interface{}{"var": nil}, + } + want := &sppb.ExecuteSqlRequest{ + Params: &proto3.Struct{ + Fields: map[string]*proto3.Value{"var": nil}, + }, + ParamTypes: map[string]*sppb.Type{"var": nil}, + } + var ( + t1, _ = time.Parse(time.RFC3339Nano, "2016-11-15T15:04:05.999999999Z") + // Boundaries + t2, _ = time.Parse(time.RFC3339Nano, "0001-01-01T00:00:00.000000000Z") + ) + dynamicStructType := reflect.StructOf([]reflect.StructField{ + {Name: "A", Type: reflect.TypeOf(t1), Tag: `spanner:"field"`}, + {Name: "B", Type: reflect.TypeOf(3.14), Tag: `spanner:""`}, + }) + dynamicStructArrType := reflect.SliceOf(reflect.PtrTo(dynamicStructType)) + dynamicEmptyStructType := reflect.StructOf(make([]reflect.StructField, 0, 0)) + + dynamicStructTypeProto := structType( + mkField("field", timeType()), + mkField("", floatType())) + + s3 := reflect.New(dynamicStructType) + s3.Elem().Field(0).Set(reflect.ValueOf(t1)) + s3.Elem().Field(1).SetFloat(1.4) + + s4 := reflect.New(dynamicStructType) + s4.Elem().Field(0).Set(reflect.ValueOf(t2)) + s4.Elem().Field(1).SetFloat(-13.3) + + dynamicStructArrayVal := reflect.MakeSlice(dynamicStructArrType, 2, 2) + dynamicStructArrayVal.Index(0).Set(s3) + dynamicStructArrayVal.Index(1).Set(s4) + + for _, test := range []struct { + val interface{} + wantField *proto3.Value + wantType *sppb.Type + }{ + { + s3.Interface(), + listProto(timeProto(t1), floatProto(1.4)), + structType( + mkField("field", timeType()), + mkField("", floatType())), + }, + { + reflect.Zero(reflect.PtrTo(dynamicEmptyStructType)).Interface(), + nullProto(), + structType([]*sppb.StructType_Field{}...), + }, + { + dynamicStructArrayVal.Interface(), + listProto( + listProto(timeProto(t1), floatProto(1.4)), + listProto(timeProto(t2), floatProto(-13.3))), + listType(dynamicStructTypeProto), + }, + { + []*struct { + F1 time.Time `spanner:"field"` + F2 float64 `spanner:""` + }{ + nil, + {t1, 1.4}, + }, + listProto( + nullProto(), + listProto(timeProto(t1), floatProto(1.4))), + listType(dynamicStructTypeProto), + }, + } { + st.Params["var"] = test.val + want.Params.Fields["var"] = test.wantField + want.ParamTypes["var"] = test.wantType + gotParams, gotParamTypes, gotErr := st.convertParams() + if gotErr != nil { + t.Error(gotErr) + continue + } + gotParamField := gotParams.Fields["var"] + if !proto.Equal(gotParamField, test.wantField) { + // handle NaN + if test.wantType.Code == floatType().Code && proto.MarshalTextString(gotParamField) == proto.MarshalTextString(test.wantField) { + continue + } + t.Errorf("%#v: got %v, want %v\n", test.val, gotParamField, test.wantField) + } + gotParamType := gotParamTypes["var"] + if !proto.Equal(gotParamType, test.wantType) { + t.Errorf("%#v: got %v, want %v\n", test.val, gotParamType, test.wantField) + } + } +} + +func TestStructParametersBind(t *testing.T) { + t.Parallel() + ctx := context.Background() + client, _, cleanup := prepare(ctx, t, nil) + defer cleanup() + + type tRow []interface{} + type tRows []struct{ trow tRow } + + type allFields struct { + Stringf string + Intf int + Boolf bool + Floatf float64 + Bytef []byte + Timef time.Time + Datef civil.Date + } + allColumns := []string{ + "Stringf", + "Intf", + "Boolf", + "Floatf", + "Bytef", + "Timef", + "Datef", + } + s1 := allFields{"abc", 300, false, 3.45, []byte("foo"), t1, d1} + s2 := allFields{"def", -300, false, -3.45, []byte("bar"), t2, d2} + + dynamicStructType := reflect.StructOf([]reflect.StructField{ + {Name: "A", Type: reflect.TypeOf(t1), Tag: `spanner:"ff1"`}, + }) + s3 := reflect.New(dynamicStructType) + s3.Elem().Field(0).Set(reflect.ValueOf(t1)) + + for i, test := range []struct { + param interface{} + sql string + cols []string + trows tRows + }{ + // Struct value. + { + s1, + "SELECT" + + " @p.Stringf," + + " @p.Intf," + + " @p.Boolf," + + " @p.Floatf," + + " @p.Bytef," + + " @p.Timef," + + " @p.Datef", + allColumns, + tRows{ + {tRow{"abc", 300, false, 3.45, []byte("foo"), t1, d1}}, + }, + }, + // Array of struct value. + { + []allFields{s1, s2}, + "SELECT * FROM UNNEST(@p)", + allColumns, + tRows{ + {tRow{"abc", 300, false, 3.45, []byte("foo"), t1, d1}}, + {tRow{"def", -300, false, -3.45, []byte("bar"), t2, d2}}, + }, + }, + // Null struct. + { + (*allFields)(nil), + "SELECT @p IS NULL", + []string{""}, + tRows{ + {tRow{true}}, + }, + }, + // Null Array of struct. + { + []allFields(nil), + "SELECT @p IS NULL", + []string{""}, + tRows{ + {tRow{true}}, + }, + }, + // Empty struct. + { + struct{}{}, + "SELECT @p IS NULL ", + []string{""}, + tRows{ + {tRow{false}}, + }, + }, + // Empty array of struct. + { + []allFields{}, + "SELECT * FROM UNNEST(@p) ", + allColumns, + tRows{}, + }, + // Struct with duplicate fields. + { + struct { + A int `spanner:"field"` + B int `spanner:"field"` + }{10, 20}, + "SELECT * FROM UNNEST([@p]) ", + []string{"field", "field"}, + tRows{ + {tRow{10, 20}}, + }, + }, + // Struct with unnamed fields. + { + struct { + A string `spanner:""` + }{"hello"}, + "SELECT * FROM UNNEST([@p]) ", + []string{""}, + tRows{ + {tRow{"hello"}}, + }, + }, + // Mixed struct. + { + struct { + DynamicStructField interface{} `spanner:"f1"` + ArrayStructField []*allFields `spanner:"f2"` + }{ + DynamicStructField: s3.Interface(), + ArrayStructField: []*allFields{nil}, + }, + "SELECT @p.f1.ff1, ARRAY_LENGTH(@p.f2), @p.f2[OFFSET(0)] IS NULL ", + []string{"ff1", "", ""}, + tRows{ + {tRow{t1, 1, true}}, + }, + }, + } { + iter := client.Single().Query(ctx, Statement{ + SQL: test.sql, + Params: map[string]interface{}{"p": test.param}, + }) + var gotRows []*Row + err := iter.Do(func(r *Row) error { + gotRows = append(gotRows, r) + return nil + }) + if err != nil { + t.Errorf("Failed to execute test case %d, error: %v", i, err) + } + + var wantRows []*Row + for j, row := range test.trows { + r, err := NewRow(test.cols, row.trow) + if err != nil { + t.Errorf("Invalid row %d in test case %d", j, i) + } + wantRows = append(wantRows, r) + } + if !testEqual(gotRows, wantRows) { + t.Errorf("%d: Want result %v, got result %v", i, wantRows, gotRows) + } + } +} diff --git a/vendor/cloud.google.com/go/speech/apiv1/Recognize_smoke_test.go b/vendor/cloud.google.com/go/speech/apiv1/Recognize_smoke_test.go new file mode 100644 index 00000000..292be9ec --- /dev/null +++ b/vendor/cloud.google.com/go/speech/apiv1/Recognize_smoke_test.go @@ -0,0 +1,80 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package speech + +import ( + speechpb "google.golang.org/genproto/googleapis/cloud/speech/v1" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestSpeechSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var languageCode string = "en-US" + var sampleRateHertz int32 = 44100 + var encoding speechpb.RecognitionConfig_AudioEncoding = speechpb.RecognitionConfig_FLAC + var config = &speechpb.RecognitionConfig{ + LanguageCode: languageCode, + SampleRateHertz: sampleRateHertz, + Encoding: encoding, + } + var uri string = "gs://gapic-toolkit/hello.flac" + var audio = &speechpb.RecognitionAudio{ + AudioSource: &speechpb.RecognitionAudio_Uri{ + Uri: uri, + }, + } + var request = &speechpb.RecognizeRequest{ + Config: config, + Audio: audio, + } + + if _, err := c.Recognize(ctx, request); err != nil { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/speech/apiv1/doc.go b/vendor/cloud.google.com/go/speech/apiv1/doc.go new file mode 100644 index 00000000..550d3bff --- /dev/null +++ b/vendor/cloud.google.com/go/speech/apiv1/doc.go @@ -0,0 +1,88 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package speech is an auto-generated package for the +// Cloud Speech API. + +// +// Converts audio to text by applying powerful neural network models. +package speech // import "cloud.google.com/go/speech/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/speech/apiv1/mock_test.go b/vendor/cloud.google.com/go/speech/apiv1/mock_test.go new file mode 100644 index 00000000..9e32b7c1 --- /dev/null +++ b/vendor/cloud.google.com/go/speech/apiv1/mock_test.go @@ -0,0 +1,405 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package speech + +import ( + speechpb "google.golang.org/genproto/googleapis/cloud/speech/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockSpeechServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + speechpb.SpeechServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockSpeechServer) Recognize(ctx context.Context, req *speechpb.RecognizeRequest) (*speechpb.RecognizeResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*speechpb.RecognizeResponse), nil +} + +func (s *mockSpeechServer) LongRunningRecognize(ctx context.Context, req *speechpb.LongRunningRecognizeRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockSpeechServer) StreamingRecognize(stream speechpb.Speech_StreamingRecognizeServer) error { + md, _ := metadata.FromIncomingContext(stream.Context()) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + for { + if req, err := stream.Recv(); err == io.EOF { + break + } else if err != nil { + return err + } else { + s.reqs = append(s.reqs, req) + } + } + if s.err != nil { + return s.err + } + for _, v := range s.resps { + if err := stream.Send(v.(*speechpb.StreamingRecognizeResponse)); err != nil { + return err + } + } + return nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockSpeech mockSpeechServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + speechpb.RegisterSpeechServer(serv, &mockSpeech) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestSpeechRecognize(t *testing.T) { + var expectedResponse *speechpb.RecognizeResponse = &speechpb.RecognizeResponse{} + + mockSpeech.err = nil + mockSpeech.reqs = nil + + mockSpeech.resps = append(mockSpeech.resps[:0], expectedResponse) + + var encoding speechpb.RecognitionConfig_AudioEncoding = speechpb.RecognitionConfig_FLAC + var sampleRateHertz int32 = 44100 + var languageCode string = "en-US" + var config = &speechpb.RecognitionConfig{ + Encoding: encoding, + SampleRateHertz: sampleRateHertz, + LanguageCode: languageCode, + } + var uri string = "gs://bucket_name/file_name.flac" + var audio = &speechpb.RecognitionAudio{ + AudioSource: &speechpb.RecognitionAudio_Uri{ + Uri: uri, + }, + } + var request = &speechpb.RecognizeRequest{ + Config: config, + Audio: audio, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Recognize(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpeech.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpeechRecognizeError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpeech.err = gstatus.Error(errCode, "test error") + + var encoding speechpb.RecognitionConfig_AudioEncoding = speechpb.RecognitionConfig_FLAC + var sampleRateHertz int32 = 44100 + var languageCode string = "en-US" + var config = &speechpb.RecognitionConfig{ + Encoding: encoding, + SampleRateHertz: sampleRateHertz, + LanguageCode: languageCode, + } + var uri string = "gs://bucket_name/file_name.flac" + var audio = &speechpb.RecognitionAudio{ + AudioSource: &speechpb.RecognitionAudio_Uri{ + Uri: uri, + }, + } + var request = &speechpb.RecognizeRequest{ + Config: config, + Audio: audio, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Recognize(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpeechLongRunningRecognize(t *testing.T) { + var expectedResponse *speechpb.LongRunningRecognizeResponse = &speechpb.LongRunningRecognizeResponse{} + + mockSpeech.err = nil + mockSpeech.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockSpeech.resps = append(mockSpeech.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var encoding speechpb.RecognitionConfig_AudioEncoding = speechpb.RecognitionConfig_FLAC + var sampleRateHertz int32 = 44100 + var languageCode string = "en-US" + var config = &speechpb.RecognitionConfig{ + Encoding: encoding, + SampleRateHertz: sampleRateHertz, + LanguageCode: languageCode, + } + var uri string = "gs://bucket_name/file_name.flac" + var audio = &speechpb.RecognitionAudio{ + AudioSource: &speechpb.RecognitionAudio_Uri{ + Uri: uri, + }, + } + var request = &speechpb.LongRunningRecognizeRequest{ + Config: config, + Audio: audio, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.LongRunningRecognize(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpeech.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpeechLongRunningRecognizeError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpeech.err = nil + mockSpeech.resps = append(mockSpeech.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var encoding speechpb.RecognitionConfig_AudioEncoding = speechpb.RecognitionConfig_FLAC + var sampleRateHertz int32 = 44100 + var languageCode string = "en-US" + var config = &speechpb.RecognitionConfig{ + Encoding: encoding, + SampleRateHertz: sampleRateHertz, + LanguageCode: languageCode, + } + var uri string = "gs://bucket_name/file_name.flac" + var audio = &speechpb.RecognitionAudio{ + AudioSource: &speechpb.RecognitionAudio_Uri{ + Uri: uri, + }, + } + var request = &speechpb.LongRunningRecognizeRequest{ + Config: config, + Audio: audio, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.LongRunningRecognize(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpeechStreamingRecognize(t *testing.T) { + var expectedResponse *speechpb.StreamingRecognizeResponse = &speechpb.StreamingRecognizeResponse{} + + mockSpeech.err = nil + mockSpeech.reqs = nil + + mockSpeech.resps = append(mockSpeech.resps[:0], expectedResponse) + + var request *speechpb.StreamingRecognizeRequest = &speechpb.StreamingRecognizeRequest{} + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.StreamingRecognize(context.Background()) + if err != nil { + t.Fatal(err) + } + if err := stream.Send(request); err != nil { + t.Fatal(err) + } + if err := stream.CloseSend(); err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpeech.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpeechStreamingRecognizeError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpeech.err = gstatus.Error(errCode, "test error") + + var request *speechpb.StreamingRecognizeRequest = &speechpb.StreamingRecognizeRequest{} + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.StreamingRecognize(context.Background()) + if err != nil { + t.Fatal(err) + } + if err := stream.Send(request); err != nil { + t.Fatal(err) + } + if err := stream.CloseSend(); err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/speech/apiv1/speech_client.go b/vendor/cloud.google.com/go/speech/apiv1/speech_client.go new file mode 100644 index 00000000..0ea5deab --- /dev/null +++ b/vendor/cloud.google.com/go/speech/apiv1/speech_client.go @@ -0,0 +1,264 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package speech + +import ( + "context" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + speechpb "google.golang.org/genproto/googleapis/cloud/speech/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + Recognize []gax.CallOption + LongRunningRecognize []gax.CallOption + StreamingRecognize []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("speech.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + Recognize: retry[[2]string{"default", "idempotent"}], + LongRunningRecognize: retry[[2]string{"default", "non_idempotent"}], + StreamingRecognize: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Cloud Speech API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client speechpb.SpeechClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new speech client. +// +// Service that implements Google Cloud Speech API. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: speechpb.NewSpeechClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Recognize performs synchronous speech recognition: receive results after all audio +// has been sent and processed. +func (c *Client) Recognize(ctx context.Context, req *speechpb.RecognizeRequest, opts ...gax.CallOption) (*speechpb.RecognizeResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Recognize[0:len(c.CallOptions.Recognize):len(c.CallOptions.Recognize)], opts...) + var resp *speechpb.RecognizeResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.Recognize(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// LongRunningRecognize performs asynchronous speech recognition: receive results via the +// google.longrunning.Operations interface. Returns either an +// Operation.error or an Operation.response which contains +// a LongRunningRecognizeResponse message. +func (c *Client) LongRunningRecognize(ctx context.Context, req *speechpb.LongRunningRecognizeRequest, opts ...gax.CallOption) (*LongRunningRecognizeOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.LongRunningRecognize[0:len(c.CallOptions.LongRunningRecognize):len(c.CallOptions.LongRunningRecognize)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.LongRunningRecognize(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &LongRunningRecognizeOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// StreamingRecognize performs bidirectional streaming speech recognition: receive results while +// sending audio. This method is only available via the gRPC API (not REST). +func (c *Client) StreamingRecognize(ctx context.Context, opts ...gax.CallOption) (speechpb.Speech_StreamingRecognizeClient, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.StreamingRecognize[0:len(c.CallOptions.StreamingRecognize):len(c.CallOptions.StreamingRecognize)], opts...) + var resp speechpb.Speech_StreamingRecognizeClient + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.StreamingRecognize(ctx, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// LongRunningRecognizeOperation manages a long-running operation from LongRunningRecognize. +type LongRunningRecognizeOperation struct { + lro *longrunning.Operation +} + +// LongRunningRecognizeOperation returns a new LongRunningRecognizeOperation from a given name. +// The name must be that of a previously created LongRunningRecognizeOperation, possibly from a different process. +func (c *Client) LongRunningRecognizeOperation(name string) *LongRunningRecognizeOperation { + return &LongRunningRecognizeOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *LongRunningRecognizeOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*speechpb.LongRunningRecognizeResponse, error) { + var resp speechpb.LongRunningRecognizeResponse + if err := op.lro.WaitWithInterval(ctx, &resp, 45000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *LongRunningRecognizeOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*speechpb.LongRunningRecognizeResponse, error) { + var resp speechpb.LongRunningRecognizeResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *LongRunningRecognizeOperation) Metadata() (*speechpb.LongRunningRecognizeMetadata, error) { + var meta speechpb.LongRunningRecognizeMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *LongRunningRecognizeOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *LongRunningRecognizeOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/speech/apiv1/speech_client_example_test.go b/vendor/cloud.google.com/go/speech/apiv1/speech_client_example_test.go new file mode 100644 index 00000000..db8ddc11 --- /dev/null +++ b/vendor/cloud.google.com/go/speech/apiv1/speech_client_example_test.go @@ -0,0 +1,110 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package speech_test + +import ( + "context" + "io" + + speech "cloud.google.com/go/speech/apiv1" + speechpb "google.golang.org/genproto/googleapis/cloud/speech/v1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := speech.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_Recognize() { + ctx := context.Background() + c, err := speech.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &speechpb.RecognizeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Recognize(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_LongRunningRecognize() { + ctx := context.Background() + c, err := speech.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &speechpb.LongRunningRecognizeRequest{ + // TODO: Fill request struct fields. + } + op, err := c.LongRunningRecognize(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_StreamingRecognize() { + ctx := context.Background() + c, err := speech.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + stream, err := c.StreamingRecognize(ctx) + if err != nil { + // TODO: Handle error. + } + go func() { + reqs := []*speechpb.StreamingRecognizeRequest{ + // TODO: Create requests. + } + for _, req := range reqs { + if err := stream.Send(req); err != nil { + // TODO: Handle error. + } + } + stream.CloseSend() + }() + for { + resp, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + // TODO: handle error. + } + // TODO: Use resp. + _ = resp + } +} diff --git a/vendor/cloud.google.com/go/speech/apiv1p1beta1/Recognize_smoke_test.go b/vendor/cloud.google.com/go/speech/apiv1p1beta1/Recognize_smoke_test.go new file mode 100644 index 00000000..874b6c2e --- /dev/null +++ b/vendor/cloud.google.com/go/speech/apiv1p1beta1/Recognize_smoke_test.go @@ -0,0 +1,80 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package speech + +import ( + speechpb "google.golang.org/genproto/googleapis/cloud/speech/v1p1beta1" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestSpeechSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var languageCode string = "en-US" + var sampleRateHertz int32 = 44100 + var encoding speechpb.RecognitionConfig_AudioEncoding = speechpb.RecognitionConfig_FLAC + var config = &speechpb.RecognitionConfig{ + LanguageCode: languageCode, + SampleRateHertz: sampleRateHertz, + Encoding: encoding, + } + var uri string = "gs://gapic-toolkit/hello.flac" + var audio = &speechpb.RecognitionAudio{ + AudioSource: &speechpb.RecognitionAudio_Uri{ + Uri: uri, + }, + } + var request = &speechpb.RecognizeRequest{ + Config: config, + Audio: audio, + } + + if _, err := c.Recognize(ctx, request); err != nil { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/speech/apiv1p1beta1/doc.go b/vendor/cloud.google.com/go/speech/apiv1p1beta1/doc.go new file mode 100644 index 00000000..58edeae3 --- /dev/null +++ b/vendor/cloud.google.com/go/speech/apiv1p1beta1/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package speech is an auto-generated package for the +// Cloud Speech API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Converts audio to text by applying powerful neural network models. +package speech // import "cloud.google.com/go/speech/apiv1p1beta1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/speech/apiv1p1beta1/mock_test.go b/vendor/cloud.google.com/go/speech/apiv1p1beta1/mock_test.go new file mode 100644 index 00000000..4852fa87 --- /dev/null +++ b/vendor/cloud.google.com/go/speech/apiv1p1beta1/mock_test.go @@ -0,0 +1,405 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package speech + +import ( + speechpb "google.golang.org/genproto/googleapis/cloud/speech/v1p1beta1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockSpeechServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + speechpb.SpeechServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockSpeechServer) Recognize(ctx context.Context, req *speechpb.RecognizeRequest) (*speechpb.RecognizeResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*speechpb.RecognizeResponse), nil +} + +func (s *mockSpeechServer) LongRunningRecognize(ctx context.Context, req *speechpb.LongRunningRecognizeRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +func (s *mockSpeechServer) StreamingRecognize(stream speechpb.Speech_StreamingRecognizeServer) error { + md, _ := metadata.FromIncomingContext(stream.Context()) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + for { + if req, err := stream.Recv(); err == io.EOF { + break + } else if err != nil { + return err + } else { + s.reqs = append(s.reqs, req) + } + } + if s.err != nil { + return s.err + } + for _, v := range s.resps { + if err := stream.Send(v.(*speechpb.StreamingRecognizeResponse)); err != nil { + return err + } + } + return nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockSpeech mockSpeechServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + speechpb.RegisterSpeechServer(serv, &mockSpeech) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestSpeechRecognize(t *testing.T) { + var expectedResponse *speechpb.RecognizeResponse = &speechpb.RecognizeResponse{} + + mockSpeech.err = nil + mockSpeech.reqs = nil + + mockSpeech.resps = append(mockSpeech.resps[:0], expectedResponse) + + var encoding speechpb.RecognitionConfig_AudioEncoding = speechpb.RecognitionConfig_FLAC + var sampleRateHertz int32 = 44100 + var languageCode string = "en-US" + var config = &speechpb.RecognitionConfig{ + Encoding: encoding, + SampleRateHertz: sampleRateHertz, + LanguageCode: languageCode, + } + var uri string = "gs://bucket_name/file_name.flac" + var audio = &speechpb.RecognitionAudio{ + AudioSource: &speechpb.RecognitionAudio_Uri{ + Uri: uri, + }, + } + var request = &speechpb.RecognizeRequest{ + Config: config, + Audio: audio, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Recognize(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpeech.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpeechRecognizeError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpeech.err = gstatus.Error(errCode, "test error") + + var encoding speechpb.RecognitionConfig_AudioEncoding = speechpb.RecognitionConfig_FLAC + var sampleRateHertz int32 = 44100 + var languageCode string = "en-US" + var config = &speechpb.RecognitionConfig{ + Encoding: encoding, + SampleRateHertz: sampleRateHertz, + LanguageCode: languageCode, + } + var uri string = "gs://bucket_name/file_name.flac" + var audio = &speechpb.RecognitionAudio{ + AudioSource: &speechpb.RecognitionAudio_Uri{ + Uri: uri, + }, + } + var request = &speechpb.RecognizeRequest{ + Config: config, + Audio: audio, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.Recognize(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpeechLongRunningRecognize(t *testing.T) { + var expectedResponse *speechpb.LongRunningRecognizeResponse = &speechpb.LongRunningRecognizeResponse{} + + mockSpeech.err = nil + mockSpeech.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockSpeech.resps = append(mockSpeech.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var encoding speechpb.RecognitionConfig_AudioEncoding = speechpb.RecognitionConfig_FLAC + var sampleRateHertz int32 = 44100 + var languageCode string = "en-US" + var config = &speechpb.RecognitionConfig{ + Encoding: encoding, + SampleRateHertz: sampleRateHertz, + LanguageCode: languageCode, + } + var uri string = "gs://bucket_name/file_name.flac" + var audio = &speechpb.RecognitionAudio{ + AudioSource: &speechpb.RecognitionAudio_Uri{ + Uri: uri, + }, + } + var request = &speechpb.LongRunningRecognizeRequest{ + Config: config, + Audio: audio, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.LongRunningRecognize(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpeech.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpeechLongRunningRecognizeError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpeech.err = nil + mockSpeech.resps = append(mockSpeech.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var encoding speechpb.RecognitionConfig_AudioEncoding = speechpb.RecognitionConfig_FLAC + var sampleRateHertz int32 = 44100 + var languageCode string = "en-US" + var config = &speechpb.RecognitionConfig{ + Encoding: encoding, + SampleRateHertz: sampleRateHertz, + LanguageCode: languageCode, + } + var uri string = "gs://bucket_name/file_name.flac" + var audio = &speechpb.RecognitionAudio{ + AudioSource: &speechpb.RecognitionAudio_Uri{ + Uri: uri, + }, + } + var request = &speechpb.LongRunningRecognizeRequest{ + Config: config, + Audio: audio, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.LongRunningRecognize(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestSpeechStreamingRecognize(t *testing.T) { + var expectedResponse *speechpb.StreamingRecognizeResponse = &speechpb.StreamingRecognizeResponse{} + + mockSpeech.err = nil + mockSpeech.reqs = nil + + mockSpeech.resps = append(mockSpeech.resps[:0], expectedResponse) + + var request *speechpb.StreamingRecognizeRequest = &speechpb.StreamingRecognizeRequest{} + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.StreamingRecognize(context.Background()) + if err != nil { + t.Fatal(err) + } + if err := stream.Send(request); err != nil { + t.Fatal(err) + } + if err := stream.CloseSend(); err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockSpeech.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestSpeechStreamingRecognizeError(t *testing.T) { + errCode := codes.PermissionDenied + mockSpeech.err = gstatus.Error(errCode, "test error") + + var request *speechpb.StreamingRecognizeRequest = &speechpb.StreamingRecognizeRequest{} + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + stream, err := c.StreamingRecognize(context.Background()) + if err != nil { + t.Fatal(err) + } + if err := stream.Send(request); err != nil { + t.Fatal(err) + } + if err := stream.CloseSend(); err != nil { + t.Fatal(err) + } + resp, err := stream.Recv() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/speech/apiv1p1beta1/speech_client.go b/vendor/cloud.google.com/go/speech/apiv1p1beta1/speech_client.go new file mode 100644 index 00000000..15e7b052 --- /dev/null +++ b/vendor/cloud.google.com/go/speech/apiv1p1beta1/speech_client.go @@ -0,0 +1,264 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package speech + +import ( + "context" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + speechpb "google.golang.org/genproto/googleapis/cloud/speech/v1p1beta1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + Recognize []gax.CallOption + LongRunningRecognize []gax.CallOption + StreamingRecognize []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("speech.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + Recognize: retry[[2]string{"default", "idempotent"}], + LongRunningRecognize: retry[[2]string{"default", "non_idempotent"}], + StreamingRecognize: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Cloud Speech API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client speechpb.SpeechClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new speech client. +// +// Service that implements Google Cloud Speech API. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: speechpb.NewSpeechClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// Recognize performs synchronous speech recognition: receive results after all audio +// has been sent and processed. +func (c *Client) Recognize(ctx context.Context, req *speechpb.RecognizeRequest, opts ...gax.CallOption) (*speechpb.RecognizeResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.Recognize[0:len(c.CallOptions.Recognize):len(c.CallOptions.Recognize)], opts...) + var resp *speechpb.RecognizeResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.Recognize(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// LongRunningRecognize performs asynchronous speech recognition: receive results via the +// google.longrunning.Operations interface. Returns either an +// Operation.error or an Operation.response which contains +// a LongRunningRecognizeResponse message. +func (c *Client) LongRunningRecognize(ctx context.Context, req *speechpb.LongRunningRecognizeRequest, opts ...gax.CallOption) (*LongRunningRecognizeOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.LongRunningRecognize[0:len(c.CallOptions.LongRunningRecognize):len(c.CallOptions.LongRunningRecognize)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.LongRunningRecognize(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &LongRunningRecognizeOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// StreamingRecognize performs bidirectional streaming speech recognition: receive results while +// sending audio. This method is only available via the gRPC API (not REST). +func (c *Client) StreamingRecognize(ctx context.Context, opts ...gax.CallOption) (speechpb.Speech_StreamingRecognizeClient, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.StreamingRecognize[0:len(c.CallOptions.StreamingRecognize):len(c.CallOptions.StreamingRecognize)], opts...) + var resp speechpb.Speech_StreamingRecognizeClient + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.StreamingRecognize(ctx, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// LongRunningRecognizeOperation manages a long-running operation from LongRunningRecognize. +type LongRunningRecognizeOperation struct { + lro *longrunning.Operation +} + +// LongRunningRecognizeOperation returns a new LongRunningRecognizeOperation from a given name. +// The name must be that of a previously created LongRunningRecognizeOperation, possibly from a different process. +func (c *Client) LongRunningRecognizeOperation(name string) *LongRunningRecognizeOperation { + return &LongRunningRecognizeOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *LongRunningRecognizeOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*speechpb.LongRunningRecognizeResponse, error) { + var resp speechpb.LongRunningRecognizeResponse + if err := op.lro.WaitWithInterval(ctx, &resp, 45000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *LongRunningRecognizeOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*speechpb.LongRunningRecognizeResponse, error) { + var resp speechpb.LongRunningRecognizeResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *LongRunningRecognizeOperation) Metadata() (*speechpb.LongRunningRecognizeMetadata, error) { + var meta speechpb.LongRunningRecognizeMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *LongRunningRecognizeOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *LongRunningRecognizeOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/speech/apiv1p1beta1/speech_client_example_test.go b/vendor/cloud.google.com/go/speech/apiv1p1beta1/speech_client_example_test.go new file mode 100644 index 00000000..d44ab5dd --- /dev/null +++ b/vendor/cloud.google.com/go/speech/apiv1p1beta1/speech_client_example_test.go @@ -0,0 +1,110 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package speech_test + +import ( + "context" + "io" + + speech "cloud.google.com/go/speech/apiv1p1beta1" + speechpb "google.golang.org/genproto/googleapis/cloud/speech/v1p1beta1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := speech.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_Recognize() { + ctx := context.Background() + c, err := speech.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &speechpb.RecognizeRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.Recognize(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_LongRunningRecognize() { + ctx := context.Background() + c, err := speech.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &speechpb.LongRunningRecognizeRequest{ + // TODO: Fill request struct fields. + } + op, err := c.LongRunningRecognize(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_StreamingRecognize() { + ctx := context.Background() + c, err := speech.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + stream, err := c.StreamingRecognize(ctx) + if err != nil { + // TODO: Handle error. + } + go func() { + reqs := []*speechpb.StreamingRecognizeRequest{ + // TODO: Create requests. + } + for _, req := range reqs { + if err := stream.Send(req); err != nil { + // TODO: Handle error. + } + } + stream.CloseSend() + }() + for { + resp, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + // TODO: handle error. + } + // TODO: Use resp. + _ = resp + } +} diff --git a/vendor/cloud.google.com/go/storage/acl.go b/vendor/cloud.google.com/go/storage/acl.go new file mode 100644 index 00000000..7855d110 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/acl.go @@ -0,0 +1,335 @@ +// Copyright 2014 Google LLC +// +// 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 storage + +import ( + "context" + "net/http" + "reflect" + + "cloud.google.com/go/internal/trace" + "google.golang.org/api/googleapi" + raw "google.golang.org/api/storage/v1" +) + +// ACLRole is the level of access to grant. +type ACLRole string + +const ( + RoleOwner ACLRole = "OWNER" + RoleReader ACLRole = "READER" + RoleWriter ACLRole = "WRITER" +) + +// ACLEntity refers to a user or group. +// They are sometimes referred to as grantees. +// +// It could be in the form of: +// "user-", "user-", "group-", "group-", +// "domain-" and "project-team-". +// +// Or one of the predefined constants: AllUsers, AllAuthenticatedUsers. +type ACLEntity string + +const ( + AllUsers ACLEntity = "allUsers" + AllAuthenticatedUsers ACLEntity = "allAuthenticatedUsers" +) + +// ACLRule represents a grant for a role to an entity (user, group or team) for a +// Google Cloud Storage object or bucket. +type ACLRule struct { + Entity ACLEntity + EntityID string + Role ACLRole + Domain string + Email string + ProjectTeam *ProjectTeam +} + +// ProjectTeam is the project team associated with the entity, if any. +type ProjectTeam struct { + ProjectNumber string + Team string +} + +// ACLHandle provides operations on an access control list for a Google Cloud Storage bucket or object. +type ACLHandle struct { + c *Client + bucket string + object string + isDefault bool + userProject string // for requester-pays buckets +} + +// Delete permanently deletes the ACL entry for the given entity. +func (a *ACLHandle) Delete(ctx context.Context, entity ACLEntity) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.Delete") + defer func() { trace.EndSpan(ctx, err) }() + + if a.object != "" { + return a.objectDelete(ctx, entity) + } + if a.isDefault { + return a.bucketDefaultDelete(ctx, entity) + } + return a.bucketDelete(ctx, entity) +} + +// Set sets the role for the given entity. +func (a *ACLHandle) Set(ctx context.Context, entity ACLEntity, role ACLRole) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.Set") + defer func() { trace.EndSpan(ctx, err) }() + + if a.object != "" { + return a.objectSet(ctx, entity, role, false) + } + if a.isDefault { + return a.objectSet(ctx, entity, role, true) + } + return a.bucketSet(ctx, entity, role) +} + +// List retrieves ACL entries. +func (a *ACLHandle) List(ctx context.Context) (rules []ACLRule, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.ACL.List") + defer func() { trace.EndSpan(ctx, err) }() + + if a.object != "" { + return a.objectList(ctx) + } + if a.isDefault { + return a.bucketDefaultList(ctx) + } + return a.bucketList(ctx) +} + +func (a *ACLHandle) bucketDefaultList(ctx context.Context) ([]ACLRule, error) { + var acls *raw.ObjectAccessControls + var err error + err = runWithRetry(ctx, func() error { + req := a.c.raw.DefaultObjectAccessControls.List(a.bucket) + a.configureCall(ctx, req) + acls, err = req.Do() + return err + }) + if err != nil { + return nil, err + } + return toObjectACLRules(acls.Items), nil +} + +func (a *ACLHandle) bucketDefaultDelete(ctx context.Context, entity ACLEntity) error { + return runWithRetry(ctx, func() error { + req := a.c.raw.DefaultObjectAccessControls.Delete(a.bucket, string(entity)) + a.configureCall(ctx, req) + return req.Do() + }) +} + +func (a *ACLHandle) bucketList(ctx context.Context) ([]ACLRule, error) { + var acls *raw.BucketAccessControls + var err error + err = runWithRetry(ctx, func() error { + req := a.c.raw.BucketAccessControls.List(a.bucket) + a.configureCall(ctx, req) + acls, err = req.Do() + return err + }) + if err != nil { + return nil, err + } + return toBucketACLRules(acls.Items), nil +} + +func (a *ACLHandle) bucketSet(ctx context.Context, entity ACLEntity, role ACLRole) error { + acl := &raw.BucketAccessControl{ + Bucket: a.bucket, + Entity: string(entity), + Role: string(role), + } + err := runWithRetry(ctx, func() error { + req := a.c.raw.BucketAccessControls.Update(a.bucket, string(entity), acl) + a.configureCall(ctx, req) + _, err := req.Do() + return err + }) + if err != nil { + return err + } + return nil +} + +func (a *ACLHandle) bucketDelete(ctx context.Context, entity ACLEntity) error { + return runWithRetry(ctx, func() error { + req := a.c.raw.BucketAccessControls.Delete(a.bucket, string(entity)) + a.configureCall(ctx, req) + return req.Do() + }) +} + +func (a *ACLHandle) objectList(ctx context.Context) ([]ACLRule, error) { + var acls *raw.ObjectAccessControls + var err error + err = runWithRetry(ctx, func() error { + req := a.c.raw.ObjectAccessControls.List(a.bucket, a.object) + a.configureCall(ctx, req) + acls, err = req.Do() + return err + }) + if err != nil { + return nil, err + } + return toObjectACLRules(acls.Items), nil +} + +func (a *ACLHandle) objectSet(ctx context.Context, entity ACLEntity, role ACLRole, isBucketDefault bool) error { + type setRequest interface { + Do(opts ...googleapi.CallOption) (*raw.ObjectAccessControl, error) + Header() http.Header + } + + acl := &raw.ObjectAccessControl{ + Bucket: a.bucket, + Entity: string(entity), + Role: string(role), + } + var req setRequest + if isBucketDefault { + req = a.c.raw.DefaultObjectAccessControls.Update(a.bucket, string(entity), acl) + } else { + req = a.c.raw.ObjectAccessControls.Update(a.bucket, a.object, string(entity), acl) + } + a.configureCall(ctx, req) + return runWithRetry(ctx, func() error { + _, err := req.Do() + return err + }) +} + +func (a *ACLHandle) objectDelete(ctx context.Context, entity ACLEntity) error { + return runWithRetry(ctx, func() error { + req := a.c.raw.ObjectAccessControls.Delete(a.bucket, a.object, string(entity)) + a.configureCall(ctx, req) + return req.Do() + }) +} + +func (a *ACLHandle) configureCall(ctx context.Context, call interface{ Header() http.Header }) { + vc := reflect.ValueOf(call) + vc.MethodByName("Context").Call([]reflect.Value{reflect.ValueOf(ctx)}) + if a.userProject != "" { + vc.MethodByName("UserProject").Call([]reflect.Value{reflect.ValueOf(a.userProject)}) + } + setClientHeader(call.Header()) +} + +func toObjectACLRules(items []*raw.ObjectAccessControl) []ACLRule { + var rs []ACLRule + for _, item := range items { + rs = append(rs, toObjectACLRule(item)) + } + return rs +} + +func toBucketACLRules(items []*raw.BucketAccessControl) []ACLRule { + var rs []ACLRule + for _, item := range items { + rs = append(rs, toBucketACLRule(item)) + } + return rs +} + +func toObjectACLRule(a *raw.ObjectAccessControl) ACLRule { + return ACLRule{ + Entity: ACLEntity(a.Entity), + EntityID: a.EntityId, + Role: ACLRole(a.Role), + Domain: a.Domain, + Email: a.Email, + ProjectTeam: toObjectProjectTeam(a.ProjectTeam), + } +} + +func toBucketACLRule(a *raw.BucketAccessControl) ACLRule { + return ACLRule{ + Entity: ACLEntity(a.Entity), + EntityID: a.EntityId, + Role: ACLRole(a.Role), + Domain: a.Domain, + Email: a.Email, + ProjectTeam: toBucketProjectTeam(a.ProjectTeam), + } +} + +func toRawObjectACL(rules []ACLRule) []*raw.ObjectAccessControl { + if len(rules) == 0 { + return nil + } + r := make([]*raw.ObjectAccessControl, 0, len(rules)) + for _, rule := range rules { + r = append(r, rule.toRawObjectAccessControl("")) // bucket name unnecessary + } + return r +} + +func toRawBucketACL(rules []ACLRule) []*raw.BucketAccessControl { + if len(rules) == 0 { + return nil + } + r := make([]*raw.BucketAccessControl, 0, len(rules)) + for _, rule := range rules { + r = append(r, rule.toRawBucketAccessControl("")) // bucket name unnecessary + } + return r +} + +func (r ACLRule) toRawBucketAccessControl(bucket string) *raw.BucketAccessControl { + return &raw.BucketAccessControl{ + Bucket: bucket, + Entity: string(r.Entity), + Role: string(r.Role), + // The other fields are not settable. + } +} + +func (r ACLRule) toRawObjectAccessControl(bucket string) *raw.ObjectAccessControl { + return &raw.ObjectAccessControl{ + Bucket: bucket, + Entity: string(r.Entity), + Role: string(r.Role), + // The other fields are not settable. + } +} + +func toBucketProjectTeam(p *raw.BucketAccessControlProjectTeam) *ProjectTeam { + if p == nil { + return nil + } + return &ProjectTeam{ + ProjectNumber: p.ProjectNumber, + Team: p.Team, + } +} + +func toObjectProjectTeam(p *raw.ObjectAccessControlProjectTeam) *ProjectTeam { + if p == nil { + return nil + } + return &ProjectTeam{ + ProjectNumber: p.ProjectNumber, + Team: p.Team, + } +} diff --git a/vendor/cloud.google.com/go/storage/acl_test.go b/vendor/cloud.google.com/go/storage/acl_test.go new file mode 100644 index 00000000..9b725127 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/acl_test.go @@ -0,0 +1,65 @@ +// Copyright 2014 Google LLC +// +// 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 storage + +import ( + "context" + "net/http" + "testing" + + "cloud.google.com/go/internal/testutil" +) + +func TestSetACL(t *testing.T) { + ctx := context.Background() + mt := &mockTransport{} + client := mockClient(t, mt) + bh := &ACLHandle{c: client, bucket: "B"} + oh := &ACLHandle{c: client, bucket: "B", object: "O"} + for _, test := range []struct { + desc string + f func() error + want map[string]interface{} + }{ + { + desc: "bucket Set", + f: func() error { return bh.Set(ctx, AllUsers, RoleReader) }, + want: map[string]interface{}{ + "bucket": "B", + "entity": "allUsers", + "role": "READER", + }, + }, + + { + desc: "object Set", + f: func() error { return oh.Set(ctx, ACLEntity("e"), RoleWriter) }, + want: map[string]interface{}{ + "bucket": "B", + "entity": "e", + "role": "WRITER", + }, + }} { + + mt.addResult(&http.Response{StatusCode: 200, Body: bodyReader("{}")}, nil) + if err := test.f(); err != nil { + t.Fatal(err) + } + got := mt.gotJSONBody() + if diff := testutil.Diff(got, test.want); diff != "" { + t.Errorf("%s: %s", test.desc, diff) + } + } +} diff --git a/vendor/cloud.google.com/go/storage/bucket.go b/vendor/cloud.google.com/go/storage/bucket.go new file mode 100644 index 00000000..3b0018af --- /dev/null +++ b/vendor/cloud.google.com/go/storage/bucket.go @@ -0,0 +1,1129 @@ +// Copyright 2014 Google LLC +// +// 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 storage + +import ( + "context" + "fmt" + "net/http" + "reflect" + "time" + + "cloud.google.com/go/internal/optional" + "cloud.google.com/go/internal/trace" + "google.golang.org/api/googleapi" + "google.golang.org/api/iterator" + raw "google.golang.org/api/storage/v1" +) + +// BucketHandle provides operations on a Google Cloud Storage bucket. +// Use Client.Bucket to get a handle. +type BucketHandle struct { + c *Client + name string + acl ACLHandle + defaultObjectACL ACLHandle + conds *BucketConditions + userProject string // project for Requester Pays buckets +} + +// Bucket returns a BucketHandle, which provides operations on the named bucket. +// This call does not perform any network operations. +// +// The supplied name must contain only lowercase letters, numbers, dashes, +// underscores, and dots. The full specification for valid bucket names can be +// found at: +// https://cloud.google.com/storage/docs/bucket-naming +func (c *Client) Bucket(name string) *BucketHandle { + return &BucketHandle{ + c: c, + name: name, + acl: ACLHandle{ + c: c, + bucket: name, + }, + defaultObjectACL: ACLHandle{ + c: c, + bucket: name, + isDefault: true, + }, + } +} + +// Create creates the Bucket in the project. +// If attrs is nil the API defaults will be used. +func (b *BucketHandle) Create(ctx context.Context, projectID string, attrs *BucketAttrs) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create") + defer func() { trace.EndSpan(ctx, err) }() + + var bkt *raw.Bucket + if attrs != nil { + bkt = attrs.toRawBucket() + } else { + bkt = &raw.Bucket{} + } + bkt.Name = b.name + // If there is lifecycle information but no location, explicitly set + // the location. This is a GCS quirk/bug. + if bkt.Location == "" && bkt.Lifecycle != nil { + bkt.Location = "US" + } + req := b.c.raw.Buckets.Insert(projectID, bkt) + setClientHeader(req.Header()) + if attrs != nil && attrs.PredefinedACL != "" { + req.PredefinedAcl(attrs.PredefinedACL) + } + if attrs != nil && attrs.PredefinedDefaultObjectACL != "" { + req.PredefinedDefaultObjectAcl(attrs.PredefinedDefaultObjectACL) + } + return runWithRetry(ctx, func() error { _, err := req.Context(ctx).Do(); return err }) +} + +// Delete deletes the Bucket. +func (b *BucketHandle) Delete(ctx context.Context) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Delete") + defer func() { trace.EndSpan(ctx, err) }() + + req, err := b.newDeleteCall() + if err != nil { + return err + } + return runWithRetry(ctx, func() error { return req.Context(ctx).Do() }) +} + +func (b *BucketHandle) newDeleteCall() (*raw.BucketsDeleteCall, error) { + req := b.c.raw.Buckets.Delete(b.name) + setClientHeader(req.Header()) + if err := applyBucketConds("BucketHandle.Delete", b.conds, req); err != nil { + return nil, err + } + if b.userProject != "" { + req.UserProject(b.userProject) + } + return req, nil +} + +// ACL returns an ACLHandle, which provides access to the bucket's access control list. +// This controls who can list, create or overwrite the objects in a bucket. +// This call does not perform any network operations. +func (b *BucketHandle) ACL() *ACLHandle { + return &b.acl +} + +// DefaultObjectACL returns an ACLHandle, which provides access to the bucket's default object ACLs. +// These ACLs are applied to newly created objects in this bucket that do not have a defined ACL. +// This call does not perform any network operations. +func (b *BucketHandle) DefaultObjectACL() *ACLHandle { + return &b.defaultObjectACL +} + +// Object returns an ObjectHandle, which provides operations on the named object. +// This call does not perform any network operations. +// +// name must consist entirely of valid UTF-8-encoded runes. The full specification +// for valid object names can be found at: +// https://cloud.google.com/storage/docs/bucket-naming +func (b *BucketHandle) Object(name string) *ObjectHandle { + return &ObjectHandle{ + c: b.c, + bucket: b.name, + object: name, + acl: ACLHandle{ + c: b.c, + bucket: b.name, + object: name, + userProject: b.userProject, + }, + gen: -1, + userProject: b.userProject, + } +} + +// Attrs returns the metadata for the bucket. +func (b *BucketHandle) Attrs(ctx context.Context) (attrs *BucketAttrs, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Attrs") + defer func() { trace.EndSpan(ctx, err) }() + + req, err := b.newGetCall() + if err != nil { + return nil, err + } + var resp *raw.Bucket + err = runWithRetry(ctx, func() error { + resp, err = req.Context(ctx).Do() + return err + }) + if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { + return nil, ErrBucketNotExist + } + if err != nil { + return nil, err + } + return newBucket(resp) +} + +func (b *BucketHandle) newGetCall() (*raw.BucketsGetCall, error) { + req := b.c.raw.Buckets.Get(b.name).Projection("full") + setClientHeader(req.Header()) + if err := applyBucketConds("BucketHandle.Attrs", b.conds, req); err != nil { + return nil, err + } + if b.userProject != "" { + req.UserProject(b.userProject) + } + return req, nil +} + +// Update updates a bucket's attributes. +func (b *BucketHandle) Update(ctx context.Context, uattrs BucketAttrsToUpdate) (attrs *BucketAttrs, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Create") + defer func() { trace.EndSpan(ctx, err) }() + + req, err := b.newPatchCall(&uattrs) + if err != nil { + return nil, err + } + if uattrs.PredefinedACL != "" { + req.PredefinedAcl(uattrs.PredefinedACL) + } + if uattrs.PredefinedDefaultObjectACL != "" { + req.PredefinedDefaultObjectAcl(uattrs.PredefinedDefaultObjectACL) + } + // TODO(jba): retry iff metagen is set? + rb, err := req.Context(ctx).Do() + if err != nil { + return nil, err + } + return newBucket(rb) +} + +func (b *BucketHandle) newPatchCall(uattrs *BucketAttrsToUpdate) (*raw.BucketsPatchCall, error) { + rb := uattrs.toRawBucket() + req := b.c.raw.Buckets.Patch(b.name, rb).Projection("full") + setClientHeader(req.Header()) + if err := applyBucketConds("BucketHandle.Update", b.conds, req); err != nil { + return nil, err + } + if b.userProject != "" { + req.UserProject(b.userProject) + } + return req, nil +} + +// BucketAttrs represents the metadata for a Google Cloud Storage bucket. +// Read-only fields are ignored by BucketHandle.Create. +type BucketAttrs struct { + // Name is the name of the bucket. + // This field is read-only. + Name string + + // ACL is the list of access control rules on the bucket. + ACL []ACLRule + + // DefaultObjectACL is the list of access controls to + // apply to new objects when no object ACL is provided. + DefaultObjectACL []ACLRule + + // DefaultEventBasedHold is the default value for event-based hold on + // newly created objects in this bucket. It defaults to false. + DefaultEventBasedHold bool + + // If not empty, applies a predefined set of access controls. It should be set + // only when creating a bucket. + // It is always empty for BucketAttrs returned from the service. + // See https://cloud.google.com/storage/docs/json_api/v1/buckets/insert + // for valid values. + PredefinedACL string + + // If not empty, applies a predefined set of default object access controls. + // It should be set only when creating a bucket. + // It is always empty for BucketAttrs returned from the service. + // See https://cloud.google.com/storage/docs/json_api/v1/buckets/insert + // for valid values. + PredefinedDefaultObjectACL string + + // Location is the location of the bucket. It defaults to "US". + Location string + + // MetaGeneration is the metadata generation of the bucket. + // This field is read-only. + MetaGeneration int64 + + // StorageClass is the default storage class of the bucket. This defines + // how objects in the bucket are stored and determines the SLA + // and the cost of storage. Typical values are "MULTI_REGIONAL", + // "REGIONAL", "NEARLINE", "COLDLINE", "STANDARD" and + // "DURABLE_REDUCED_AVAILABILITY". Defaults to "STANDARD", which + // is equivalent to "MULTI_REGIONAL" or "REGIONAL" depending on + // the bucket's location settings. + StorageClass string + + // Created is the creation time of the bucket. + // This field is read-only. + Created time.Time + + // VersioningEnabled reports whether this bucket has versioning enabled. + VersioningEnabled bool + + // Labels are the bucket's labels. + Labels map[string]string + + // RequesterPays reports whether the bucket is a Requester Pays bucket. + // Clients performing operations on Requester Pays buckets must provide + // a user project (see BucketHandle.UserProject), which will be billed + // for the operations. + RequesterPays bool + + // Lifecycle is the lifecycle configuration for objects in the bucket. + Lifecycle Lifecycle + + // Retention policy enforces a minimum retention time for all objects + // contained in the bucket. A RetentionPolicy of nil implies the bucket + // has no minimum data retention. + // + // This feature is in private alpha release. It is not currently available to + // most customers. It might be changed in backwards-incompatible ways and is not + // subject to any SLA or deprecation policy. + RetentionPolicy *RetentionPolicy + + // The bucket's Cross-Origin Resource Sharing (CORS) configuration. + CORS []CORS + + // The encryption configuration used by default for newly inserted objects. + Encryption *BucketEncryption + + // The logging configuration. + Logging *BucketLogging + + // The website configuration. + Website *BucketWebsite +} + +// Lifecycle is the lifecycle configuration for objects in the bucket. +type Lifecycle struct { + Rules []LifecycleRule +} + +// RetentionPolicy enforces a minimum retention time for all objects +// contained in the bucket. +// +// Any attempt to overwrite or delete objects younger than the retention +// period will result in an error. An unlocked retention policy can be +// modified or removed from the bucket via the Update method. A +// locked retention policy cannot be removed or shortened in duration +// for the lifetime of the bucket. +// +// This feature is in private alpha release. It is not currently available to +// most customers. It might be changed in backwards-incompatible ways and is not +// subject to any SLA or deprecation policy. +type RetentionPolicy struct { + // RetentionPeriod specifies the duration that objects need to be + // retained. Retention duration must be greater than zero and less than + // 100 years. Note that enforcement of retention periods less than a day + // is not guaranteed. Such periods should only be used for testing + // purposes. + RetentionPeriod time.Duration + + // EffectiveTime is the time from which the policy was enforced and + // effective. This field is read-only. + EffectiveTime time.Time + + // IsLocked describes whether the bucket is locked. Once locked, an + // object retention policy cannot be modified. + // This field is read-only. + IsLocked bool +} + +const ( + // RFC3339 date with only the date segment, used for CreatedBefore in LifecycleRule. + rfc3339Date = "2006-01-02" + + // DeleteAction is a lifecycle action that deletes a live and/or archived + // objects. Takes precedence over SetStorageClass actions. + DeleteAction = "Delete" + + // SetStorageClassAction changes the storage class of live and/or archived + // objects. + SetStorageClassAction = "SetStorageClass" +) + +// LifecycleRule is a lifecycle configuration rule. +// +// When all the configured conditions are met by an object in the bucket, the +// configured action will automatically be taken on that object. +type LifecycleRule struct { + // Action is the action to take when all of the associated conditions are + // met. + Action LifecycleAction + + // Condition is the set of conditions that must be met for the associated + // action to be taken. + Condition LifecycleCondition +} + +// LifecycleAction is a lifecycle configuration action. +type LifecycleAction struct { + // Type is the type of action to take on matching objects. + // + // Acceptable values are "Delete" to delete matching objects and + // "SetStorageClass" to set the storage class defined in StorageClass on + // matching objects. + Type string + + // StorageClass is the storage class to set on matching objects if the Action + // is "SetStorageClass". + StorageClass string +} + +// Liveness specifies whether the object is live or not. +type Liveness int + +const ( + // LiveAndArchived includes both live and archived objects. + LiveAndArchived Liveness = iota + // Live specifies that the object is still live. + Live + // Archived specifies that the object is archived. + Archived +) + +// LifecycleCondition is a set of conditions used to match objects and take an +// action automatically. +// +// All configured conditions must be met for the associated action to be taken. +type LifecycleCondition struct { + // AgeInDays is the age of the object in days. + AgeInDays int64 + + // CreatedBefore is the time the object was created. + // + // This condition is satisfied when an object is created before midnight of + // the specified date in UTC. + CreatedBefore time.Time + + // Liveness specifies the object's liveness. Relevant only for versioned objects + Liveness Liveness + + // MatchesStorageClasses is the condition matching the object's storage + // class. + // + // Values include "MULTI_REGIONAL", "REGIONAL", "NEARLINE", "COLDLINE", + // "STANDARD", and "DURABLE_REDUCED_AVAILABILITY". + MatchesStorageClasses []string + + // NumNewerVersions is the condition matching objects with a number of newer versions. + // + // If the value is N, this condition is satisfied when there are at least N + // versions (including the live version) newer than this version of the + // object. + NumNewerVersions int64 +} + +// BucketLogging holds the bucket's logging configuration, which defines the +// destination bucket and optional name prefix for the current bucket's +// logs. +type BucketLogging struct { + // The destination bucket where the current bucket's logs + // should be placed. + LogBucket string + + // A prefix for log object names. + LogObjectPrefix string +} + +// BucketWebsite holds the bucket's website configuration, controlling how the +// service behaves when accessing bucket contents as a web site. See +// https://cloud.google.com/storage/docs/static-website for more information. +type BucketWebsite struct { + // If the requested object path is missing, the service will ensure the path has + // a trailing '/', append this suffix, and attempt to retrieve the resulting + // object. This allows the creation of index.html objects to represent directory + // pages. + MainPageSuffix string + + // If the requested object path is missing, and any mainPageSuffix object is + // missing, if applicable, the service will return the named object from this + // bucket as the content for a 404 Not Found result. + NotFoundPage string +} + +func newBucket(b *raw.Bucket) (*BucketAttrs, error) { + if b == nil { + return nil, nil + } + rp, err := toRetentionPolicy(b.RetentionPolicy) + if err != nil { + return nil, err + } + return &BucketAttrs{ + Name: b.Name, + Location: b.Location, + MetaGeneration: b.Metageneration, + DefaultEventBasedHold: b.DefaultEventBasedHold, + StorageClass: b.StorageClass, + Created: convertTime(b.TimeCreated), + VersioningEnabled: b.Versioning != nil && b.Versioning.Enabled, + ACL: toBucketACLRules(b.Acl), + DefaultObjectACL: toObjectACLRules(b.DefaultObjectAcl), + Labels: b.Labels, + RequesterPays: b.Billing != nil && b.Billing.RequesterPays, + Lifecycle: toLifecycle(b.Lifecycle), + RetentionPolicy: rp, + CORS: toCORS(b.Cors), + Encryption: toBucketEncryption(b.Encryption), + Logging: toBucketLogging(b.Logging), + Website: toBucketWebsite(b.Website), + }, nil +} + +// toRawBucket copies the editable attribute from b to the raw library's Bucket type. +func (b *BucketAttrs) toRawBucket() *raw.Bucket { + // Copy label map. + var labels map[string]string + if len(b.Labels) > 0 { + labels = make(map[string]string, len(b.Labels)) + for k, v := range b.Labels { + labels[k] = v + } + } + // Ignore VersioningEnabled if it is false. This is OK because + // we only call this method when creating a bucket, and by default + // new buckets have versioning off. + var v *raw.BucketVersioning + if b.VersioningEnabled { + v = &raw.BucketVersioning{Enabled: true} + } + var bb *raw.BucketBilling + if b.RequesterPays { + bb = &raw.BucketBilling{RequesterPays: true} + } + return &raw.Bucket{ + Name: b.Name, + Location: b.Location, + StorageClass: b.StorageClass, + Acl: toRawBucketACL(b.ACL), + DefaultObjectAcl: toRawObjectACL(b.DefaultObjectACL), + Versioning: v, + Labels: labels, + Billing: bb, + Lifecycle: toRawLifecycle(b.Lifecycle), + RetentionPolicy: b.RetentionPolicy.toRawRetentionPolicy(), + Cors: toRawCORS(b.CORS), + Encryption: b.Encryption.toRawBucketEncryption(), + Logging: b.Logging.toRawBucketLogging(), + Website: b.Website.toRawBucketWebsite(), + } +} + +// CORS is the bucket's Cross-Origin Resource Sharing (CORS) configuration. +type CORS struct { + // MaxAge is the value to return in the Access-Control-Max-Age + // header used in preflight responses. + MaxAge time.Duration + + // Methods is the list of HTTP methods on which to include CORS response + // headers, (GET, OPTIONS, POST, etc) Note: "*" is permitted in the list + // of methods, and means "any method". + Methods []string + + // Origins is the list of Origins eligible to receive CORS response + // headers. Note: "*" is permitted in the list of origins, and means + // "any Origin". + Origins []string + + // ResponseHeaders is the list of HTTP headers other than the simple + // response headers to give permission for the user-agent to share + // across domains. + ResponseHeaders []string +} + +// BucketEncryption is a bucket's encryption configuration. +type BucketEncryption struct { + // A Cloud KMS key name, in the form + // projects/P/locations/L/keyRings/R/cryptoKeys/K, that will be used to encrypt + // objects inserted into this bucket, if no encryption method is specified. + // The key's location must be the same as the bucket's. + DefaultKMSKeyName string +} + +// BucketAttrsToUpdate define the attributes to update during an Update call. +type BucketAttrsToUpdate struct { + // If set, updates whether the bucket uses versioning. + VersioningEnabled optional.Bool + + // If set, updates whether the bucket is a Requester Pays bucket. + RequesterPays optional.Bool + + // DefaultEventBasedHold is the default value for event-based hold on + // newly created objects in this bucket. + DefaultEventBasedHold optional.Bool + + // If set, updates the retention policy of the bucket. Using + // RetentionPolicy.RetentionPeriod = 0 will delete the existing policy. + // + // This feature is in private alpha release. It is not currently available to + // most customers. It might be changed in backwards-incompatible ways and is not + // subject to any SLA or deprecation policy. + RetentionPolicy *RetentionPolicy + + // If set, replaces the CORS configuration with a new configuration. + // An empty (rather than nil) slice causes all CORS policies to be removed. + CORS []CORS + + // If set, replaces the encryption configuration of the bucket. Using + // BucketEncryption.DefaultKMSKeyName = "" will delete the existing + // configuration. + Encryption *BucketEncryption + + // If set, replaces the lifecycle configuration of the bucket. + Lifecycle *Lifecycle + + // If set, replaces the logging configuration of the bucket. + Logging *BucketLogging + + // If set, replaces the website configuration of the bucket. + Website *BucketWebsite + + // If not empty, applies a predefined set of access controls. + // See https://cloud.google.com/storage/docs/json_api/v1/buckets/patch. + PredefinedACL string + + // If not empty, applies a predefined set of default object access controls. + // See https://cloud.google.com/storage/docs/json_api/v1/buckets/patch. + PredefinedDefaultObjectACL string + + setLabels map[string]string + deleteLabels map[string]bool +} + +// SetLabel causes a label to be added or modified when ua is used +// in a call to Bucket.Update. +func (ua *BucketAttrsToUpdate) SetLabel(name, value string) { + if ua.setLabels == nil { + ua.setLabels = map[string]string{} + } + ua.setLabels[name] = value +} + +// DeleteLabel causes a label to be deleted when ua is used in a +// call to Bucket.Update. +func (ua *BucketAttrsToUpdate) DeleteLabel(name string) { + if ua.deleteLabels == nil { + ua.deleteLabels = map[string]bool{} + } + ua.deleteLabels[name] = true +} + +func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket { + rb := &raw.Bucket{} + if ua.CORS != nil { + rb.Cors = toRawCORS(ua.CORS) + rb.ForceSendFields = append(rb.ForceSendFields, "Cors") + } + if ua.DefaultEventBasedHold != nil { + rb.DefaultEventBasedHold = optional.ToBool(ua.DefaultEventBasedHold) + rb.ForceSendFields = append(rb.ForceSendFields, "DefaultEventBasedHold") + } + if ua.RetentionPolicy != nil { + if ua.RetentionPolicy.RetentionPeriod == 0 { + rb.NullFields = append(rb.NullFields, "RetentionPolicy") + rb.RetentionPolicy = nil + } else { + rb.RetentionPolicy = ua.RetentionPolicy.toRawRetentionPolicy() + } + } + if ua.VersioningEnabled != nil { + rb.Versioning = &raw.BucketVersioning{ + Enabled: optional.ToBool(ua.VersioningEnabled), + ForceSendFields: []string{"Enabled"}, + } + } + if ua.RequesterPays != nil { + rb.Billing = &raw.BucketBilling{ + RequesterPays: optional.ToBool(ua.RequesterPays), + ForceSendFields: []string{"RequesterPays"}, + } + } + if ua.Encryption != nil { + if ua.Encryption.DefaultKMSKeyName == "" { + rb.NullFields = append(rb.NullFields, "Encryption") + rb.Encryption = nil + } else { + rb.Encryption = ua.Encryption.toRawBucketEncryption() + } + } + if ua.Lifecycle != nil { + rb.Lifecycle = toRawLifecycle(*ua.Lifecycle) + } + if ua.Logging != nil { + if *ua.Logging == (BucketLogging{}) { + rb.NullFields = append(rb.NullFields, "Logging") + rb.Logging = nil + } else { + rb.Logging = ua.Logging.toRawBucketLogging() + } + } + if ua.Website != nil { + if *ua.Website == (BucketWebsite{}) { + rb.NullFields = append(rb.NullFields, "Website") + rb.Website = nil + } else { + rb.Website = ua.Website.toRawBucketWebsite() + } + } + if ua.PredefinedACL != "" { + // Clear ACL or the call will fail. + rb.Acl = nil + rb.ForceSendFields = append(rb.ForceSendFields, "Acl") + } + if ua.PredefinedDefaultObjectACL != "" { + // Clear ACLs or the call will fail. + rb.DefaultObjectAcl = nil + rb.ForceSendFields = append(rb.ForceSendFields, "DefaultObjectAcl") + } + if ua.setLabels != nil || ua.deleteLabels != nil { + rb.Labels = map[string]string{} + for k, v := range ua.setLabels { + rb.Labels[k] = v + } + if len(rb.Labels) == 0 && len(ua.deleteLabels) > 0 { + rb.ForceSendFields = append(rb.ForceSendFields, "Labels") + } + for l := range ua.deleteLabels { + rb.NullFields = append(rb.NullFields, "Labels."+l) + } + } + return rb +} + +// If returns a new BucketHandle that applies a set of preconditions. +// Preconditions already set on the BucketHandle are ignored. +// Operations on the new handle will return an error if the preconditions are not +// satisfied. The only valid preconditions for buckets are MetagenerationMatch +// and MetagenerationNotMatch. +func (b *BucketHandle) If(conds BucketConditions) *BucketHandle { + b2 := *b + b2.conds = &conds + return &b2 +} + +// BucketConditions constrain bucket methods to act on specific metagenerations. +// +// The zero value is an empty set of constraints. +type BucketConditions struct { + // MetagenerationMatch specifies that the bucket must have the given + // metageneration for the operation to occur. + // If MetagenerationMatch is zero, it has no effect. + MetagenerationMatch int64 + + // MetagenerationNotMatch specifies that the bucket must not have the given + // metageneration for the operation to occur. + // If MetagenerationNotMatch is zero, it has no effect. + MetagenerationNotMatch int64 +} + +func (c *BucketConditions) validate(method string) error { + if *c == (BucketConditions{}) { + return fmt.Errorf("storage: %s: empty conditions", method) + } + if c.MetagenerationMatch != 0 && c.MetagenerationNotMatch != 0 { + return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method) + } + return nil +} + +// UserProject returns a new BucketHandle that passes the project ID as the user +// project for all subsequent calls. Calls with a user project will be billed to that +// project rather than to the bucket's owning project. +// +// A user project is required for all operations on Requester Pays buckets. +func (b *BucketHandle) UserProject(projectID string) *BucketHandle { + b2 := *b + b2.userProject = projectID + b2.acl.userProject = projectID + b2.defaultObjectACL.userProject = projectID + return &b2 +} + +// LockRetentionPolicy locks a bucket's retention policy until a previously-configured +// RetentionPeriod past the EffectiveTime. Note that if RetentionPeriod is set to less +// than a day, the retention policy is treated as a development configuration and locking +// will have no effect. The BucketHandle must have a metageneration condition that +// matches the bucket's metageneration. See BucketHandle.If. +// +// This feature is in private alpha release. It is not currently available to +// most customers. It might be changed in backwards-incompatible ways and is not +// subject to any SLA or deprecation policy. +func (b *BucketHandle) LockRetentionPolicy(ctx context.Context) error { + var metageneration int64 + if b.conds != nil { + metageneration = b.conds.MetagenerationMatch + } + req := b.c.raw.Buckets.LockRetentionPolicy(b.name, metageneration) + _, err := req.Context(ctx).Do() + return err +} + +// applyBucketConds modifies the provided call using the conditions in conds. +// call is something that quacks like a *raw.WhateverCall. +func applyBucketConds(method string, conds *BucketConditions, call interface{}) error { + if conds == nil { + return nil + } + if err := conds.validate(method); err != nil { + return err + } + cval := reflect.ValueOf(call) + switch { + case conds.MetagenerationMatch != 0: + if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) { + return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method) + } + case conds.MetagenerationNotMatch != 0: + if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) { + return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method) + } + } + return nil +} + +func (rp *RetentionPolicy) toRawRetentionPolicy() *raw.BucketRetentionPolicy { + if rp == nil { + return nil + } + return &raw.BucketRetentionPolicy{ + RetentionPeriod: int64(rp.RetentionPeriod / time.Second), + } +} + +func toRetentionPolicy(rp *raw.BucketRetentionPolicy) (*RetentionPolicy, error) { + if rp == nil { + return nil, nil + } + t, err := time.Parse(time.RFC3339, rp.EffectiveTime) + if err != nil { + return nil, err + } + return &RetentionPolicy{ + RetentionPeriod: time.Duration(rp.RetentionPeriod) * time.Second, + EffectiveTime: t, + IsLocked: rp.IsLocked, + }, nil +} + +func toRawCORS(c []CORS) []*raw.BucketCors { + var out []*raw.BucketCors + for _, v := range c { + out = append(out, &raw.BucketCors{ + MaxAgeSeconds: int64(v.MaxAge / time.Second), + Method: v.Methods, + Origin: v.Origins, + ResponseHeader: v.ResponseHeaders, + }) + } + return out +} + +func toCORS(rc []*raw.BucketCors) []CORS { + var out []CORS + for _, v := range rc { + out = append(out, CORS{ + MaxAge: time.Duration(v.MaxAgeSeconds) * time.Second, + Methods: v.Method, + Origins: v.Origin, + ResponseHeaders: v.ResponseHeader, + }) + } + return out +} + +func toRawLifecycle(l Lifecycle) *raw.BucketLifecycle { + var rl raw.BucketLifecycle + if len(l.Rules) == 0 { + return nil + } + for _, r := range l.Rules { + rr := &raw.BucketLifecycleRule{ + Action: &raw.BucketLifecycleRuleAction{ + Type: r.Action.Type, + StorageClass: r.Action.StorageClass, + }, + Condition: &raw.BucketLifecycleRuleCondition{ + Age: r.Condition.AgeInDays, + MatchesStorageClass: r.Condition.MatchesStorageClasses, + NumNewerVersions: r.Condition.NumNewerVersions, + }, + } + + switch r.Condition.Liveness { + case LiveAndArchived: + rr.Condition.IsLive = nil + case Live: + rr.Condition.IsLive = googleapi.Bool(true) + case Archived: + rr.Condition.IsLive = googleapi.Bool(false) + } + + if !r.Condition.CreatedBefore.IsZero() { + rr.Condition.CreatedBefore = r.Condition.CreatedBefore.Format(rfc3339Date) + } + rl.Rule = append(rl.Rule, rr) + } + return &rl +} + +func toLifecycle(rl *raw.BucketLifecycle) Lifecycle { + var l Lifecycle + if rl == nil { + return l + } + for _, rr := range rl.Rule { + r := LifecycleRule{ + Action: LifecycleAction{ + Type: rr.Action.Type, + StorageClass: rr.Action.StorageClass, + }, + Condition: LifecycleCondition{ + AgeInDays: rr.Condition.Age, + MatchesStorageClasses: rr.Condition.MatchesStorageClass, + NumNewerVersions: rr.Condition.NumNewerVersions, + }, + } + + switch { + case rr.Condition.IsLive == nil: + r.Condition.Liveness = LiveAndArchived + case *rr.Condition.IsLive == true: + r.Condition.Liveness = Live + case *rr.Condition.IsLive == false: + r.Condition.Liveness = Archived + } + + if rr.Condition.CreatedBefore != "" { + r.Condition.CreatedBefore, _ = time.Parse(rfc3339Date, rr.Condition.CreatedBefore) + } + l.Rules = append(l.Rules, r) + } + return l +} + +func (e *BucketEncryption) toRawBucketEncryption() *raw.BucketEncryption { + if e == nil { + return nil + } + return &raw.BucketEncryption{ + DefaultKmsKeyName: e.DefaultKMSKeyName, + } +} + +func toBucketEncryption(e *raw.BucketEncryption) *BucketEncryption { + if e == nil { + return nil + } + return &BucketEncryption{DefaultKMSKeyName: e.DefaultKmsKeyName} +} + +func (b *BucketLogging) toRawBucketLogging() *raw.BucketLogging { + if b == nil { + return nil + } + return &raw.BucketLogging{ + LogBucket: b.LogBucket, + LogObjectPrefix: b.LogObjectPrefix, + } +} + +func toBucketLogging(b *raw.BucketLogging) *BucketLogging { + if b == nil { + return nil + } + return &BucketLogging{ + LogBucket: b.LogBucket, + LogObjectPrefix: b.LogObjectPrefix, + } +} + +func (w *BucketWebsite) toRawBucketWebsite() *raw.BucketWebsite { + if w == nil { + return nil + } + return &raw.BucketWebsite{ + MainPageSuffix: w.MainPageSuffix, + NotFoundPage: w.NotFoundPage, + } +} + +func toBucketWebsite(w *raw.BucketWebsite) *BucketWebsite { + if w == nil { + return nil + } + return &BucketWebsite{ + MainPageSuffix: w.MainPageSuffix, + NotFoundPage: w.NotFoundPage, + } +} + +// Objects returns an iterator over the objects in the bucket that match the Query q. +// If q is nil, no filtering is done. +func (b *BucketHandle) Objects(ctx context.Context, q *Query) *ObjectIterator { + it := &ObjectIterator{ + ctx: ctx, + bucket: b, + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.items) }, + func() interface{} { b := it.items; it.items = nil; return b }) + if q != nil { + it.query = *q + } + return it +} + +// An ObjectIterator is an iterator over ObjectAttrs. +type ObjectIterator struct { + ctx context.Context + bucket *BucketHandle + query Query + pageInfo *iterator.PageInfo + nextFunc func() error + items []*ObjectAttrs +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ObjectIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } + +// Next returns the next result. Its second return value is iterator.Done if +// there are no more results. Once Next returns iterator.Done, all subsequent +// calls will return iterator.Done. +// +// If Query.Delimiter is non-empty, some of the ObjectAttrs returned by Next will +// have a non-empty Prefix field, and a zero value for all other fields. These +// represent prefixes. +func (it *ObjectIterator) Next() (*ObjectAttrs, error) { + if err := it.nextFunc(); err != nil { + return nil, err + } + item := it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ObjectIterator) fetch(pageSize int, pageToken string) (string, error) { + req := it.bucket.c.raw.Objects.List(it.bucket.name) + setClientHeader(req.Header()) + req.Projection("full") + req.Delimiter(it.query.Delimiter) + req.Prefix(it.query.Prefix) + req.Versions(it.query.Versions) + req.PageToken(pageToken) + if it.bucket.userProject != "" { + req.UserProject(it.bucket.userProject) + } + if pageSize > 0 { + req.MaxResults(int64(pageSize)) + } + var resp *raw.Objects + var err error + err = runWithRetry(it.ctx, func() error { + resp, err = req.Context(it.ctx).Do() + return err + }) + if err != nil { + if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { + err = ErrBucketNotExist + } + return "", err + } + for _, item := range resp.Items { + it.items = append(it.items, newObject(item)) + } + for _, prefix := range resp.Prefixes { + it.items = append(it.items, &ObjectAttrs{Prefix: prefix}) + } + return resp.NextPageToken, nil +} + +// Buckets returns an iterator over the buckets in the project. You may +// optionally set the iterator's Prefix field to restrict the list to buckets +// whose names begin with the prefix. By default, all buckets in the project +// are returned. +func (c *Client) Buckets(ctx context.Context, projectID string) *BucketIterator { + it := &BucketIterator{ + ctx: ctx, + client: c, + projectID: projectID, + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo( + it.fetch, + func() int { return len(it.buckets) }, + func() interface{} { b := it.buckets; it.buckets = nil; return b }) + return it +} + +// A BucketIterator is an iterator over BucketAttrs. +type BucketIterator struct { + // Prefix restricts the iterator to buckets whose names begin with it. + Prefix string + + ctx context.Context + client *Client + projectID string + buckets []*BucketAttrs + pageInfo *iterator.PageInfo + nextFunc func() error +} + +// Next returns the next result. Its second return value is iterator.Done if +// there are no more results. Once Next returns iterator.Done, all subsequent +// calls will return iterator.Done. +func (it *BucketIterator) Next() (*BucketAttrs, error) { + if err := it.nextFunc(); err != nil { + return nil, err + } + b := it.buckets[0] + it.buckets = it.buckets[1:] + return b, nil +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *BucketIterator) PageInfo() *iterator.PageInfo { return it.pageInfo } + +func (it *BucketIterator) fetch(pageSize int, pageToken string) (token string, err error) { + req := it.client.raw.Buckets.List(it.projectID) + setClientHeader(req.Header()) + req.Projection("full") + req.Prefix(it.Prefix) + req.PageToken(pageToken) + if pageSize > 0 { + req.MaxResults(int64(pageSize)) + } + var resp *raw.Buckets + err = runWithRetry(it.ctx, func() error { + resp, err = req.Context(it.ctx).Do() + return err + }) + if err != nil { + return "", err + } + for _, item := range resp.Items { + b, err := newBucket(item) + if err != nil { + return "", err + } + it.buckets = append(it.buckets, b) + } + return resp.NextPageToken, nil +} diff --git a/vendor/cloud.google.com/go/storage/bucket_test.go b/vendor/cloud.google.com/go/storage/bucket_test.go new file mode 100644 index 00000000..9df3ead1 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/bucket_test.go @@ -0,0 +1,441 @@ +// Copyright 2017 Google LLC +// +// 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 storage + +import ( + "net/http" + "reflect" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "google.golang.org/api/googleapi" + raw "google.golang.org/api/storage/v1" +) + +func TestBucketAttrsToRawBucket(t *testing.T) { + t.Parallel() + attrs := &BucketAttrs{ + Name: "name", + ACL: []ACLRule{{Entity: "bob@example.com", Role: RoleOwner, Domain: "d", Email: "e"}}, + DefaultObjectACL: []ACLRule{{Entity: AllUsers, Role: RoleReader, EntityID: "eid", + ProjectTeam: &ProjectTeam{ProjectNumber: "17", Team: "t"}}}, + Location: "loc", + StorageClass: "class", + RetentionPolicy: &RetentionPolicy{ + RetentionPeriod: 3 * time.Second, + }, + VersioningEnabled: false, + // should be ignored: + MetaGeneration: 39, + Created: time.Now(), + Labels: map[string]string{"label": "value"}, + CORS: []CORS{ + { + MaxAge: time.Hour, + Methods: []string{"GET", "POST"}, + Origins: []string{"*"}, + ResponseHeaders: []string{"FOO"}, + }, + }, + Encryption: &BucketEncryption{DefaultKMSKeyName: "key"}, + Logging: &BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, + Website: &BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, + Lifecycle: Lifecycle{ + Rules: []LifecycleRule{{ + Action: LifecycleAction{ + Type: SetStorageClassAction, + StorageClass: "NEARLINE", + }, + Condition: LifecycleCondition{ + AgeInDays: 10, + Liveness: Live, + CreatedBefore: time.Date(2017, 1, 2, 3, 4, 5, 6, time.UTC), + MatchesStorageClasses: []string{"MULTI_REGIONAL", "REGIONAL", "STANDARD"}, + NumNewerVersions: 3, + }, + }, { + Action: LifecycleAction{ + Type: DeleteAction, + }, + Condition: LifecycleCondition{ + AgeInDays: 30, + Liveness: Live, + CreatedBefore: time.Date(2017, 1, 2, 3, 4, 5, 6, time.UTC), + MatchesStorageClasses: []string{"NEARLINE"}, + NumNewerVersions: 10, + }, + }, { + Action: LifecycleAction{ + Type: DeleteAction, + }, + Condition: LifecycleCondition{ + Liveness: Archived, + }, + }}, + }, + } + got := attrs.toRawBucket() + want := &raw.Bucket{ + Name: "name", + Acl: []*raw.BucketAccessControl{ + {Entity: "bob@example.com", Role: "OWNER"}, // other fields ignored on create/update + }, + DefaultObjectAcl: []*raw.ObjectAccessControl{ + {Entity: "allUsers", Role: "READER"}, // other fields ignored on create/update + }, + Location: "loc", + StorageClass: "class", + RetentionPolicy: &raw.BucketRetentionPolicy{ + RetentionPeriod: 3, + }, + Versioning: nil, // ignore VersioningEnabled if false + Labels: map[string]string{"label": "value"}, + Cors: []*raw.BucketCors{ + { + MaxAgeSeconds: 3600, + Method: []string{"GET", "POST"}, + Origin: []string{"*"}, + ResponseHeader: []string{"FOO"}, + }, + }, + Encryption: &raw.BucketEncryption{DefaultKmsKeyName: "key"}, + Logging: &raw.BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, + Website: &raw.BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, + Lifecycle: &raw.BucketLifecycle{ + Rule: []*raw.BucketLifecycleRule{{ + Action: &raw.BucketLifecycleRuleAction{ + Type: SetStorageClassAction, + StorageClass: "NEARLINE", + }, + Condition: &raw.BucketLifecycleRuleCondition{ + Age: 10, + IsLive: googleapi.Bool(true), + CreatedBefore: "2017-01-02", + MatchesStorageClass: []string{"MULTI_REGIONAL", "REGIONAL", "STANDARD"}, + NumNewerVersions: 3, + }, + }, { + Action: &raw.BucketLifecycleRuleAction{ + Type: DeleteAction, + }, + Condition: &raw.BucketLifecycleRuleCondition{ + Age: 30, + IsLive: googleapi.Bool(true), + CreatedBefore: "2017-01-02", + MatchesStorageClass: []string{"NEARLINE"}, + NumNewerVersions: 10, + }, + }, { + Action: &raw.BucketLifecycleRuleAction{ + Type: DeleteAction, + }, + Condition: &raw.BucketLifecycleRuleCondition{ + IsLive: googleapi.Bool(false), + }, + }}, + }, + } + if msg := testutil.Diff(got, want); msg != "" { + t.Error(msg) + } + + attrs.VersioningEnabled = true + attrs.RequesterPays = true + got = attrs.toRawBucket() + want.Versioning = &raw.BucketVersioning{Enabled: true} + want.Billing = &raw.BucketBilling{RequesterPays: true} + if msg := testutil.Diff(got, want); msg != "" { + t.Error(msg) + } +} + +func TestBucketAttrsToUpdateToRawBucket(t *testing.T) { + t.Parallel() + au := &BucketAttrsToUpdate{ + VersioningEnabled: false, + RequesterPays: false, + DefaultEventBasedHold: false, + RetentionPolicy: &RetentionPolicy{RetentionPeriod: time.Hour}, + Encryption: &BucketEncryption{DefaultKMSKeyName: "key2"}, + Lifecycle: &Lifecycle{ + Rules: []LifecycleRule{ + { + Action: LifecycleAction{Type: "Delete"}, + Condition: LifecycleCondition{AgeInDays: 30}, + }, + }, + }, + Logging: &BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, + Website: &BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, + } + au.SetLabel("a", "foo") + au.DeleteLabel("b") + au.SetLabel("c", "") + got := au.toRawBucket() + want := &raw.Bucket{ + Versioning: &raw.BucketVersioning{ + Enabled: false, + ForceSendFields: []string{"Enabled"}, + }, + Labels: map[string]string{ + "a": "foo", + "c": "", + }, + Billing: &raw.BucketBilling{ + RequesterPays: false, + ForceSendFields: []string{"RequesterPays"}, + }, + DefaultEventBasedHold: false, + RetentionPolicy: &raw.BucketRetentionPolicy{RetentionPeriod: 3600}, + Encryption: &raw.BucketEncryption{DefaultKmsKeyName: "key2"}, + NullFields: []string{"Labels.b"}, + Lifecycle: &raw.BucketLifecycle{ + Rule: []*raw.BucketLifecycleRule{ + { + Action: &raw.BucketLifecycleRuleAction{Type: "Delete"}, + Condition: &raw.BucketLifecycleRuleCondition{Age: 30}, + }, + }, + }, + Logging: &raw.BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, + Website: &raw.BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, + ForceSendFields: []string{"DefaultEventBasedHold"}, + } + if msg := testutil.Diff(got, want); msg != "" { + t.Error(msg) + } + + var au2 BucketAttrsToUpdate + au2.DeleteLabel("b") + got = au2.toRawBucket() + want = &raw.Bucket{ + Labels: map[string]string{}, + ForceSendFields: []string{"Labels"}, + NullFields: []string{"Labels.b"}, + } + if msg := testutil.Diff(got, want); msg != "" { + t.Error(msg) + } + + // Test nulls. + au3 := &BucketAttrsToUpdate{ + RetentionPolicy: &RetentionPolicy{}, + Encryption: &BucketEncryption{}, + Logging: &BucketLogging{}, + Website: &BucketWebsite{}, + } + got = au3.toRawBucket() + want = &raw.Bucket{ + NullFields: []string{"RetentionPolicy", "Encryption", "Logging", "Website"}, + } + if msg := testutil.Diff(got, want); msg != "" { + t.Error(msg) + } +} + +func TestCallBuilders(t *testing.T) { + rc, err := raw.New(&http.Client{}) + if err != nil { + t.Fatal(err) + } + c := &Client{raw: rc} + const metagen = 17 + + b := c.Bucket("name") + bm := b.If(BucketConditions{MetagenerationMatch: metagen}).UserProject("p") + + equal := func(x, y interface{}) bool { + return testutil.Equal(x, y, + cmp.AllowUnexported( + raw.BucketsGetCall{}, + raw.BucketsDeleteCall{}, + raw.BucketsPatchCall{}, + ), + cmp.FilterPath(func(p cmp.Path) bool { + return p[len(p)-1].Type() == reflect.TypeOf(&raw.Service{}) + }, cmp.Ignore()), + ) + } + + for i, test := range []struct { + callFunc func(*BucketHandle) (interface{}, error) + want interface { + Header() http.Header + } + metagenFunc func(interface{}) + }{ + { + func(b *BucketHandle) (interface{}, error) { return b.newGetCall() }, + rc.Buckets.Get("name").Projection("full"), + func(req interface{}) { req.(*raw.BucketsGetCall).IfMetagenerationMatch(metagen).UserProject("p") }, + }, + { + func(b *BucketHandle) (interface{}, error) { return b.newDeleteCall() }, + rc.Buckets.Delete("name"), + func(req interface{}) { req.(*raw.BucketsDeleteCall).IfMetagenerationMatch(metagen).UserProject("p") }, + }, + { + func(b *BucketHandle) (interface{}, error) { + return b.newPatchCall(&BucketAttrsToUpdate{ + VersioningEnabled: false, + RequesterPays: false, + }) + }, + rc.Buckets.Patch("name", &raw.Bucket{ + Versioning: &raw.BucketVersioning{ + Enabled: false, + ForceSendFields: []string{"Enabled"}, + }, + Billing: &raw.BucketBilling{ + RequesterPays: false, + ForceSendFields: []string{"RequesterPays"}, + }, + }).Projection("full"), + func(req interface{}) { req.(*raw.BucketsPatchCall).IfMetagenerationMatch(metagen).UserProject("p") }, + }, + } { + got, err := test.callFunc(b) + if err != nil { + t.Fatal(err) + } + setClientHeader(test.want.Header()) + if !equal(got, test.want) { + t.Errorf("#%d: got %#v, want %#v", i, got, test.want) + } + got, err = test.callFunc(bm) + if err != nil { + t.Fatal(err) + } + test.metagenFunc(test.want) + if !equal(got, test.want) { + t.Errorf("#%d:\ngot %#v\nwant %#v", i, got, test.want) + } + } + + // Error. + bm = b.If(BucketConditions{MetagenerationMatch: 1, MetagenerationNotMatch: 2}) + if _, err := bm.newGetCall(); err == nil { + t.Errorf("got nil, want error") + } + if _, err := bm.newDeleteCall(); err == nil { + t.Errorf("got nil, want error") + } + if _, err := bm.newPatchCall(&BucketAttrsToUpdate{}); err == nil { + t.Errorf("got nil, want error") + } +} + +func TestNewBucket(t *testing.T) { + labels := map[string]string{"a": "b"} + matchClasses := []string{"MULTI_REGIONAL", "REGIONAL", "STANDARD"} + rb := &raw.Bucket{ + Name: "name", + Location: "loc", + DefaultEventBasedHold: true, + Metageneration: 3, + StorageClass: "sc", + TimeCreated: "2017-10-23T04:05:06Z", + Versioning: &raw.BucketVersioning{Enabled: true}, + Labels: labels, + Billing: &raw.BucketBilling{RequesterPays: true}, + Lifecycle: &raw.BucketLifecycle{ + Rule: []*raw.BucketLifecycleRule{{ + Action: &raw.BucketLifecycleRuleAction{ + Type: "SetStorageClass", + StorageClass: "NEARLINE", + }, + Condition: &raw.BucketLifecycleRuleCondition{ + Age: 10, + IsLive: googleapi.Bool(true), + CreatedBefore: "2017-01-02", + MatchesStorageClass: matchClasses, + NumNewerVersions: 3, + }, + }}, + }, + RetentionPolicy: &raw.BucketRetentionPolicy{ + RetentionPeriod: 3, + EffectiveTime: time.Now().Format(time.RFC3339), + }, + Cors: []*raw.BucketCors{ + { + MaxAgeSeconds: 3600, + Method: []string{"GET", "POST"}, + Origin: []string{"*"}, + ResponseHeader: []string{"FOO"}, + }, + }, + Acl: []*raw.BucketAccessControl{ + {Bucket: "name", Role: "READER", Email: "joe@example.com", Entity: "allUsers"}, + }, + Encryption: &raw.BucketEncryption{DefaultKmsKeyName: "key"}, + Logging: &raw.BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, + Website: &raw.BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, + } + want := &BucketAttrs{ + Name: "name", + Location: "loc", + DefaultEventBasedHold: true, + MetaGeneration: 3, + StorageClass: "sc", + Created: time.Date(2017, 10, 23, 4, 5, 6, 0, time.UTC), + VersioningEnabled: true, + Labels: labels, + RequesterPays: true, + Lifecycle: Lifecycle{ + Rules: []LifecycleRule{ + { + Action: LifecycleAction{ + Type: SetStorageClassAction, + StorageClass: "NEARLINE", + }, + Condition: LifecycleCondition{ + AgeInDays: 10, + Liveness: Live, + CreatedBefore: time.Date(2017, 1, 2, 0, 0, 0, 0, time.UTC), + MatchesStorageClasses: matchClasses, + NumNewerVersions: 3, + }, + }, + }, + }, + RetentionPolicy: &RetentionPolicy{ + RetentionPeriod: 3 * time.Second, + }, + CORS: []CORS{ + { + MaxAge: time.Hour, + Methods: []string{"GET", "POST"}, + Origins: []string{"*"}, + ResponseHeaders: []string{"FOO"}, + }, + }, + Encryption: &BucketEncryption{DefaultKMSKeyName: "key"}, + Logging: &BucketLogging{LogBucket: "lb", LogObjectPrefix: "p"}, + Website: &BucketWebsite{MainPageSuffix: "mps", NotFoundPage: "404"}, + ACL: []ACLRule{{Entity: "allUsers", Role: RoleReader, Email: "joe@example.com"}}, + DefaultObjectACL: nil, + } + got, err := newBucket(rb) + if err != nil { + t.Fatal(err) + } + if diff := testutil.Diff(got, want, cmpopts.IgnoreTypes(time.Time{})); diff != "" { + t.Errorf("got=-, want=+:\n%s", diff) + } +} diff --git a/vendor/cloud.google.com/go/storage/copy.go b/vendor/cloud.google.com/go/storage/copy.go new file mode 100644 index 00000000..52162e72 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/copy.go @@ -0,0 +1,228 @@ +// Copyright 2016 Google LLC +// +// 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 storage + +import ( + "context" + "errors" + "fmt" + + "cloud.google.com/go/internal/trace" + raw "google.golang.org/api/storage/v1" +) + +// CopierFrom creates a Copier that can copy src to dst. +// You can immediately call Run on the returned Copier, or +// you can configure it first. +// +// For Requester Pays buckets, the user project of dst is billed, unless it is empty, +// in which case the user project of src is billed. +func (dst *ObjectHandle) CopierFrom(src *ObjectHandle) *Copier { + return &Copier{dst: dst, src: src} +} + +// A Copier copies a source object to a destination. +type Copier struct { + // ObjectAttrs are optional attributes to set on the destination object. + // Any attributes must be initialized before any calls on the Copier. Nil + // or zero-valued attributes are ignored. + ObjectAttrs + + // RewriteToken can be set before calling Run to resume a copy + // operation. After Run returns a non-nil error, RewriteToken will + // have been updated to contain the value needed to resume the copy. + RewriteToken string + + // ProgressFunc can be used to monitor the progress of a multi-RPC copy + // operation. If ProgressFunc is not nil and copying requires multiple + // calls to the underlying service (see + // https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite), then + // ProgressFunc will be invoked after each call with the number of bytes of + // content copied so far and the total size in bytes of the source object. + // + // ProgressFunc is intended to make upload progress available to the + // application. For example, the implementation of ProgressFunc may update + // a progress bar in the application's UI, or log the result of + // float64(copiedBytes)/float64(totalBytes). + // + // ProgressFunc should return quickly without blocking. + ProgressFunc func(copiedBytes, totalBytes uint64) + + // The Cloud KMS key, in the form projects/P/locations/L/keyRings/R/cryptoKeys/K, + // that will be used to encrypt the object. Overrides the object's KMSKeyName, if + // any. + // + // Providing both a DestinationKMSKeyName and a customer-supplied encryption key + // (via ObjectHandle.Key) on the destination object will result in an error when + // Run is called. + DestinationKMSKeyName string + + dst, src *ObjectHandle +} + +// Run performs the copy. +func (c *Copier) Run(ctx context.Context) (attrs *ObjectAttrs, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Copier.Run") + defer func() { trace.EndSpan(ctx, err) }() + + if err := c.src.validate(); err != nil { + return nil, err + } + if err := c.dst.validate(); err != nil { + return nil, err + } + if c.DestinationKMSKeyName != "" && c.dst.encryptionKey != nil { + return nil, errors.New("storage: cannot use DestinationKMSKeyName with a customer-supplied encryption key") + } + // Convert destination attributes to raw form, omitting the bucket. + // If the bucket is included but name or content-type aren't, the service + // returns a 400 with "Required" as the only message. Omitting the bucket + // does not cause any problems. + rawObject := c.ObjectAttrs.toRawObject("") + for { + res, err := c.callRewrite(ctx, rawObject) + if err != nil { + return nil, err + } + if c.ProgressFunc != nil { + c.ProgressFunc(uint64(res.TotalBytesRewritten), uint64(res.ObjectSize)) + } + if res.Done { // Finished successfully. + return newObject(res.Resource), nil + } + } +} + +func (c *Copier) callRewrite(ctx context.Context, rawObj *raw.Object) (*raw.RewriteResponse, error) { + call := c.dst.c.raw.Objects.Rewrite(c.src.bucket, c.src.object, c.dst.bucket, c.dst.object, rawObj) + + call.Context(ctx).Projection("full") + if c.RewriteToken != "" { + call.RewriteToken(c.RewriteToken) + } + if c.DestinationKMSKeyName != "" { + call.DestinationKmsKeyName(c.DestinationKMSKeyName) + } + if c.PredefinedACL != "" { + call.DestinationPredefinedAcl(c.PredefinedACL) + } + if err := applyConds("Copy destination", c.dst.gen, c.dst.conds, call); err != nil { + return nil, err + } + if c.dst.userProject != "" { + call.UserProject(c.dst.userProject) + } else if c.src.userProject != "" { + call.UserProject(c.src.userProject) + } + if err := applySourceConds(c.src.gen, c.src.conds, call); err != nil { + return nil, err + } + if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil { + return nil, err + } + if err := setEncryptionHeaders(call.Header(), c.src.encryptionKey, true); err != nil { + return nil, err + } + var res *raw.RewriteResponse + var err error + setClientHeader(call.Header()) + err = runWithRetry(ctx, func() error { res, err = call.Do(); return err }) + if err != nil { + return nil, err + } + c.RewriteToken = res.RewriteToken + return res, nil +} + +// ComposerFrom creates a Composer that can compose srcs into dst. +// You can immediately call Run on the returned Composer, or you can +// configure it first. +// +// The encryption key for the destination object will be used to decrypt all +// source objects and encrypt the destination object. It is an error +// to specify an encryption key for any of the source objects. +func (dst *ObjectHandle) ComposerFrom(srcs ...*ObjectHandle) *Composer { + return &Composer{dst: dst, srcs: srcs} +} + +// A Composer composes source objects into a destination object. +// +// For Requester Pays buckets, the user project of dst is billed. +type Composer struct { + // ObjectAttrs are optional attributes to set on the destination object. + // Any attributes must be initialized before any calls on the Composer. Nil + // or zero-valued attributes are ignored. + ObjectAttrs + + dst *ObjectHandle + srcs []*ObjectHandle +} + +// Run performs the compose operation. +func (c *Composer) Run(ctx context.Context) (attrs *ObjectAttrs, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Composer.Run") + defer func() { trace.EndSpan(ctx, err) }() + + if err := c.dst.validate(); err != nil { + return nil, err + } + if len(c.srcs) == 0 { + return nil, errors.New("storage: at least one source object must be specified") + } + + req := &raw.ComposeRequest{} + // Compose requires a non-empty Destination, so we always set it, + // even if the caller-provided ObjectAttrs is the zero value. + req.Destination = c.ObjectAttrs.toRawObject(c.dst.bucket) + for _, src := range c.srcs { + if err := src.validate(); err != nil { + return nil, err + } + if src.bucket != c.dst.bucket { + return nil, fmt.Errorf("storage: all source objects must be in bucket %q, found %q", c.dst.bucket, src.bucket) + } + if src.encryptionKey != nil { + return nil, fmt.Errorf("storage: compose source %s.%s must not have encryption key", src.bucket, src.object) + } + srcObj := &raw.ComposeRequestSourceObjects{ + Name: src.object, + } + if err := applyConds("ComposeFrom source", src.gen, src.conds, composeSourceObj{srcObj}); err != nil { + return nil, err + } + req.SourceObjects = append(req.SourceObjects, srcObj) + } + + call := c.dst.c.raw.Objects.Compose(c.dst.bucket, c.dst.object, req).Context(ctx) + if err := applyConds("ComposeFrom destination", c.dst.gen, c.dst.conds, call); err != nil { + return nil, err + } + if c.dst.userProject != "" { + call.UserProject(c.dst.userProject) + } + if c.PredefinedACL != "" { + call.DestinationPredefinedAcl(c.PredefinedACL) + } + if err := setEncryptionHeaders(call.Header(), c.dst.encryptionKey, false); err != nil { + return nil, err + } + var obj *raw.Object + setClientHeader(call.Header()) + err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) + if err != nil { + return nil, err + } + return newObject(obj), nil +} diff --git a/vendor/cloud.google.com/go/storage/copy_test.go b/vendor/cloud.google.com/go/storage/copy_test.go new file mode 100644 index 00000000..5f151564 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/copy_test.go @@ -0,0 +1,71 @@ +// Copyright 2018 Google LLC +// +// 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 storage + +import ( + "context" + "strings" + "testing" +) + +func TestCopyMissingFields(t *testing.T) { + // Verify that copying checks for missing fields.a + t.Parallel() + var tests = []struct { + srcBucket, srcName, destBucket, destName string + errMsg string + }{ + { + "mybucket", "", "mybucket", "destname", + "name is empty", + }, + { + "mybucket", "srcname", "mybucket", "", + "name is empty", + }, + { + "", "srcfile", "mybucket", "destname", + "name is empty", + }, + { + "mybucket", "srcfile", "", "destname", + "name is empty", + }, + } + ctx := context.Background() + client := mockClient(t, &mockTransport{}) + for i, test := range tests { + src := client.Bucket(test.srcBucket).Object(test.srcName) + dst := client.Bucket(test.destBucket).Object(test.destName) + _, err := dst.CopierFrom(src).Run(ctx) + if !strings.Contains(err.Error(), test.errMsg) { + t.Errorf("CopyTo test #%v:\ngot err %q\nwant err %q", i, err, test.errMsg) + } + } +} + +func TestCopyBothEncryptionKeys(t *testing.T) { + // Test that using both a customer-supplied key and a KMS key is an error. + ctx := context.Background() + client := mockClient(t, &mockTransport{}) + dest := client.Bucket("b").Object("d").Key(testEncryptionKey) + c := dest.CopierFrom(client.Bucket("b").Object("s")) + c.DestinationKMSKeyName = "key" + if _, err := c.Run(ctx); err == nil { + t.Error("got nil, want error") + } else if !strings.Contains(err.Error(), "KMS") { + t.Errorf(`got %q, want it to contain "KMS"`, err) + } +} diff --git a/vendor/cloud.google.com/go/storage/doc.go b/vendor/cloud.google.com/go/storage/doc.go new file mode 100644 index 00000000..e277f1d9 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/doc.go @@ -0,0 +1,176 @@ +// Copyright 2016 Google LLC +// +// 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 storage provides an easy way to work with Google Cloud Storage. +Google Cloud Storage stores data in named objects, which are grouped into buckets. + +More information about Google Cloud Storage is available at +https://cloud.google.com/storage/docs. + +See https://godoc.org/cloud.google.com/go for authentication, timeouts, +connection pooling and similar aspects of this package. + +All of the methods of this package use exponential backoff to retry calls that fail +with certain errors, as described in +https://cloud.google.com/storage/docs/exponential-backoff. Retrying continues +indefinitely unless the controlling context is canceled or the client is closed. See +context.WithTimeout and context.WithCancel. + + +Creating a Client + +To start working with this package, create a client: + + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + +The client will use your default application credentials. + +If you only wish to access public data, you can create +an unauthenticated client with + + client, err := storage.NewClient(ctx, option.WithoutAuthentication()) + +Buckets + +A Google Cloud Storage bucket is a collection of objects. To work with a +bucket, make a bucket handle: + + bkt := client.Bucket(bucketName) + +A handle is a reference to a bucket. You can have a handle even if the +bucket doesn't exist yet. To create a bucket in Google Cloud Storage, +call Create on the handle: + + if err := bkt.Create(ctx, projectID, nil); err != nil { + // TODO: Handle error. + } + +Note that although buckets are associated with projects, bucket names are +global across all projects. + +Each bucket has associated metadata, represented in this package by +BucketAttrs. The third argument to BucketHandle.Create allows you to set +the initial BucketAttrs of a bucket. To retrieve a bucket's attributes, use +Attrs: + + attrs, err := bkt.Attrs(ctx) + if err != nil { + // TODO: Handle error. + } + fmt.Printf("bucket %s, created at %s, is located in %s with storage class %s\n", + attrs.Name, attrs.Created, attrs.Location, attrs.StorageClass) + +Objects + +An object holds arbitrary data as a sequence of bytes, like a file. You +refer to objects using a handle, just as with buckets, but unlike buckets +you don't explicitly create an object. Instead, the first time you write +to an object it will be created. You can use the standard Go io.Reader +and io.Writer interfaces to read and write object data: + + obj := bkt.Object("data") + // Write something to obj. + // w implements io.Writer. + w := obj.NewWriter(ctx) + // Write some text to obj. This will either create the object or overwrite whatever is there already. + if _, err := fmt.Fprintf(w, "This object contains text.\n"); err != nil { + // TODO: Handle error. + } + // Close, just like writing a file. + if err := w.Close(); err != nil { + // TODO: Handle error. + } + + // Read it back. + r, err := obj.NewReader(ctx) + if err != nil { + // TODO: Handle error. + } + defer r.Close() + if _, err := io.Copy(os.Stdout, r); err != nil { + // TODO: Handle error. + } + // Prints "This object contains text." + +Objects also have attributes, which you can fetch with Attrs: + + objAttrs, err := obj.Attrs(ctx) + if err != nil { + // TODO: Handle error. + } + fmt.Printf("object %s has size %d and can be read using %s\n", + objAttrs.Name, objAttrs.Size, objAttrs.MediaLink) + +ACLs + +Both objects and buckets have ACLs (Access Control Lists). An ACL is a list of +ACLRules, each of which specifies the role of a user, group or project. ACLs +are suitable for fine-grained control, but you may prefer using IAM to control +access at the project level (see +https://cloud.google.com/storage/docs/access-control/iam). + +To list the ACLs of a bucket or object, obtain an ACLHandle and call its List method: + + acls, err := obj.ACL().List(ctx) + if err != nil { + // TODO: Handle error. + } + for _, rule := range acls { + fmt.Printf("%s has role %s\n", rule.Entity, rule.Role) + } + +You can also set and delete ACLs. + +Conditions + +Every object has a generation and a metageneration. The generation changes +whenever the content changes, and the metageneration changes whenever the +metadata changes. Conditions let you check these values before an operation; +the operation only executes if the conditions match. You can use conditions to +prevent race conditions in read-modify-write operations. + +For example, say you've read an object's metadata into objAttrs. Now +you want to write to that object, but only if its contents haven't changed +since you read it. Here is how to express that: + + w = obj.If(storage.Conditions{GenerationMatch: objAttrs.Generation}).NewWriter(ctx) + // Proceed with writing as above. + +Signed URLs + +You can obtain a URL that lets anyone read or write an object for a limited time. +You don't need to create a client to do this. See the documentation of +SignedURL for details. + + url, err := storage.SignedURL(bucketName, "shared-object", opts) + if err != nil { + // TODO: Handle error. + } + fmt.Println(url) + +Errors + +Errors returned by this client are often of the type [`googleapi.Error`](https://godoc.org/google.golang.org/api/googleapi#Error). +These errors can be introspected for more information by type asserting to the richer `googleapi.Error` type. For example: + + if e, ok := err.(*googleapi.Error); ok { + if e.Code = 409 { ... } + } +*/ +package storage // import "cloud.google.com/go/storage" diff --git a/vendor/cloud.google.com/go/storage/example_test.go b/vendor/cloud.google.com/go/storage/example_test.go new file mode 100644 index 00000000..5162f95c --- /dev/null +++ b/vendor/cloud.google.com/go/storage/example_test.go @@ -0,0 +1,665 @@ +// Copyright 2014 Google LLC +// +// 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 storage_test + +import ( + "context" + "fmt" + "hash/crc32" + "io" + "io/ioutil" + "log" + "os" + "time" + + "cloud.google.com/go/storage" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +func ExampleNewClient() { + ctx := context.Background() + // Use Google Application Default Credentials to authorize and authenticate the client. + // More information about Application Default Credentials and how to enable is at + // https://developers.google.com/identity/protocols/application-default-credentials. + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + // Use the client. + + // Close the client when finished. + if err := client.Close(); err != nil { + // TODO: handle error. + } +} + +// This example shows how to create an unauthenticated client, which +// can be used to access public data. +func ExampleNewClient_unauthenticated() { + ctx := context.Background() + client, err := storage.NewClient(ctx, option.WithoutAuthentication()) + if err != nil { + // TODO: handle error. + } + // Use the client. + + // Close the client when finished. + if err := client.Close(); err != nil { + // TODO: handle error. + } +} + +func ExampleBucketHandle_Create() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + if err := client.Bucket("my-bucket").Create(ctx, "my-project", nil); err != nil { + // TODO: handle error. + } +} + +func ExampleBucketHandle_Delete() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + if err := client.Bucket("my-bucket").Delete(ctx); err != nil { + // TODO: handle error. + } +} + +func ExampleBucketHandle_Attrs() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + attrs, err := client.Bucket("my-bucket").Attrs(ctx) + if err != nil { + // TODO: handle error. + } + fmt.Println(attrs) +} + +func ExampleBucketHandle_Update() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + // Enable versioning in the bucket, regardless of its previous value. + attrs, err := client.Bucket("my-bucket").Update(ctx, + storage.BucketAttrsToUpdate{VersioningEnabled: true}) + if err != nil { + // TODO: handle error. + } + fmt.Println(attrs) +} + +// If your update is based on the bucket's previous attributes, match the +// metageneration number to make sure the bucket hasn't changed since you read it. +func ExampleBucketHandle_Update_readModifyWrite() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + b := client.Bucket("my-bucket") + attrs, err := b.Attrs(ctx) + if err != nil { + // TODO: handle error. + } + var au storage.BucketAttrsToUpdate + au.SetLabel("lab", attrs.Labels["lab"]+"-more") + if attrs.Labels["delete-me"] == "yes" { + au.DeleteLabel("delete-me") + } + attrs, err = b. + If(storage.BucketConditions{MetagenerationMatch: attrs.MetaGeneration}). + Update(ctx, au) + if err != nil { + // TODO: handle error. + } + fmt.Println(attrs) +} + +func ExampleClient_Buckets() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + it := client.Buckets(ctx, "my-bucket") + _ = it // TODO: iterate using Next or iterator.Pager. +} + +func ExampleBucketIterator_Next() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + it := client.Buckets(ctx, "my-project") + for { + bucketAttrs, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(bucketAttrs) + } +} + +func ExampleBucketHandle_Objects() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + it := client.Bucket("my-bucket").Objects(ctx, nil) + _ = it // TODO: iterate using Next or iterator.Pager. +} + +func ExampleBucketHandle_AddNotification() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + b := client.Bucket("my-bucket") + n, err := b.AddNotification(ctx, &storage.Notification{ + TopicProjectID: "my-project", + TopicID: "my-topic", + PayloadFormat: storage.JSONPayload, + }) + if err != nil { + // TODO: handle error. + } + fmt.Println(n.ID) +} + +func ExampleBucketHandle_LockRetentionPolicy() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + b := client.Bucket("my-bucket") + attrs, err := b.Attrs(ctx) + if err != nil { + // TODO: handle error. + } + // Note that locking the bucket without first attaching a RetentionPolicy + // that's at least 1 day is a no-op + err = b.If(storage.BucketConditions{MetagenerationMatch: attrs.MetaGeneration}).LockRetentionPolicy(ctx) + if err != nil { + // TODO: handle err + } +} + +func ExampleBucketHandle_Notifications() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + b := client.Bucket("my-bucket") + ns, err := b.Notifications(ctx) + if err != nil { + // TODO: handle error. + } + for id, n := range ns { + fmt.Printf("%s: %+v\n", id, n) + } +} + +var notificationID string + +func ExampleBucketHandle_DeleteNotification() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + b := client.Bucket("my-bucket") + // TODO: Obtain notificationID from BucketHandle.AddNotification + // or BucketHandle.Notifications. + err = b.DeleteNotification(ctx, notificationID) + if err != nil { + // TODO: handle error. + } +} + +func ExampleObjectIterator_Next() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + it := client.Bucket("my-bucket").Objects(ctx, nil) + for { + objAttrs, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + fmt.Println(objAttrs) + } +} + +func ExampleSignedURL() { + pkey, err := ioutil.ReadFile("my-private-key.pem") + if err != nil { + // TODO: handle error. + } + url, err := storage.SignedURL("my-bucket", "my-object", &storage.SignedURLOptions{ + GoogleAccessID: "xxx@developer.gserviceaccount.com", + PrivateKey: pkey, + Method: "GET", + Expires: time.Now().Add(48 * time.Hour), + }) + if err != nil { + // TODO: handle error. + } + fmt.Println(url) +} + +func ExampleObjectHandle_Attrs() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + objAttrs, err := client.Bucket("my-bucket").Object("my-object").Attrs(ctx) + if err != nil { + // TODO: handle error. + } + fmt.Println(objAttrs) +} + +func ExampleObjectHandle_Attrs_withConditions() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + obj := client.Bucket("my-bucket").Object("my-object") + // Read the object. + objAttrs1, err := obj.Attrs(ctx) + if err != nil { + // TODO: handle error. + } + // Do something else for a while. + time.Sleep(5 * time.Minute) + // Now read the same contents, even if the object has been written since the last read. + objAttrs2, err := obj.Generation(objAttrs1.Generation).Attrs(ctx) + if err != nil { + // TODO: handle error. + } + fmt.Println(objAttrs1, objAttrs2) +} + +func ExampleObjectHandle_Update() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + // Change only the content type of the object. + objAttrs, err := client.Bucket("my-bucket").Object("my-object").Update(ctx, storage.ObjectAttrsToUpdate{ + ContentType: "text/html", + ContentDisposition: "", // delete ContentDisposition + }) + if err != nil { + // TODO: handle error. + } + fmt.Println(objAttrs) +} + +func ExampleObjectHandle_NewReader() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + rc, err := client.Bucket("my-bucket").Object("my-object").NewReader(ctx) + if err != nil { + // TODO: handle error. + } + slurp, err := ioutil.ReadAll(rc) + rc.Close() + if err != nil { + // TODO: handle error. + } + fmt.Println("file contents:", slurp) +} + +func ExampleObjectHandle_NewRangeReader() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + // Read only the first 64K. + rc, err := client.Bucket("bucketname").Object("filename1").NewRangeReader(ctx, 0, 64*1024) + if err != nil { + // TODO: handle error. + } + slurp, err := ioutil.ReadAll(rc) + rc.Close() + if err != nil { + // TODO: handle error. + } + fmt.Println("first 64K of file contents:", slurp) +} + +func ExampleObjectHandle_NewWriter() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + wc := client.Bucket("bucketname").Object("filename1").NewWriter(ctx) + _ = wc // TODO: Use the Writer. +} + +func ExampleWriter_Write() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + wc := client.Bucket("bucketname").Object("filename1").NewWriter(ctx) + wc.ContentType = "text/plain" + wc.ACL = []storage.ACLRule{{Entity: storage.AllUsers, Role: storage.RoleReader}} + if _, err := wc.Write([]byte("hello world")); err != nil { + // TODO: handle error. + // Note that Write may return nil in some error situations, + // so always check the error from Close. + } + if err := wc.Close(); err != nil { + // TODO: handle error. + } + fmt.Println("updated object:", wc.Attrs()) +} + +// To limit the time to write an object (or do anything else +// that takes a context), use context.WithTimeout. +func ExampleWriter_Write_timeout() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + tctx, cancel := context.WithTimeout(ctx, 30*time.Second) + defer cancel() // Cancel when done, whether we time out or not. + wc := client.Bucket("bucketname").Object("filename1").NewWriter(tctx) + wc.ContentType = "text/plain" + wc.ACL = []storage.ACLRule{{Entity: storage.AllUsers, Role: storage.RoleReader}} + if _, err := wc.Write([]byte("hello world")); err != nil { + // TODO: handle error. + // Note that Write may return nil in some error situations, + // so always check the error from Close. + } + if err := wc.Close(); err != nil { + // TODO: handle error. + } + fmt.Println("updated object:", wc.Attrs()) +} + +// To make sure the data you write is uncorrupted, use an MD5 or CRC32c +// checksum. This example illustrates CRC32c. +func ExampleWriter_Write_checksum() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + data := []byte("verify me") + wc := client.Bucket("bucketname").Object("filename1").NewWriter(ctx) + wc.CRC32C = crc32.Checksum(data, crc32.MakeTable(crc32.Castagnoli)) + wc.SendCRC32C = true + if _, err := wc.Write([]byte("hello world")); err != nil { + // TODO: handle error. + // Note that Write may return nil in some error situations, + // so always check the error from Close. + } + if err := wc.Close(); err != nil { + // TODO: handle error. + } + fmt.Println("updated object:", wc.Attrs()) +} + +func ExampleObjectHandle_Delete() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + // To delete multiple objects in a bucket, list them with an + // ObjectIterator, then Delete them. + + // If you are using this package on the App Engine Flex runtime, + // you can init a bucket client with your app's default bucket name. + // See http://godoc.org/google.golang.org/appengine/file#DefaultBucketName. + bucket := client.Bucket("my-bucket") + it := bucket.Objects(ctx, nil) + for { + objAttrs, err := it.Next() + if err != nil && err != iterator.Done { + // TODO: Handle error. + } + if err == iterator.Done { + break + } + if err := bucket.Object(objAttrs.Name).Delete(ctx); err != nil { + // TODO: Handle error. + } + } + fmt.Println("deleted all object items in the bucket specified.") +} + +func ExampleACLHandle_Delete() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + // No longer grant access to the bucket to everyone on the Internet. + if err := client.Bucket("my-bucket").ACL().Delete(ctx, storage.AllUsers); err != nil { + // TODO: handle error. + } +} + +func ExampleACLHandle_Set() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + // Let any authenticated user read my-bucket/my-object. + obj := client.Bucket("my-bucket").Object("my-object") + if err := obj.ACL().Set(ctx, storage.AllAuthenticatedUsers, storage.RoleReader); err != nil { + // TODO: handle error. + } +} + +func ExampleACLHandle_List() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + // List the default object ACLs for my-bucket. + aclRules, err := client.Bucket("my-bucket").DefaultObjectACL().List(ctx) + if err != nil { + // TODO: handle error. + } + fmt.Println(aclRules) +} + +func ExampleCopier_Run() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + src := client.Bucket("bucketname").Object("file1") + dst := client.Bucket("another-bucketname").Object("file2") + + // Copy content and modify metadata. + copier := dst.CopierFrom(src) + copier.ContentType = "text/plain" + attrs, err := copier.Run(ctx) + if err != nil { + // TODO: Handle error, possibly resuming with copier.RewriteToken. + } + fmt.Println(attrs) + + // Just copy content. + attrs, err = dst.CopierFrom(src).Run(ctx) + if err != nil { + // TODO: Handle error. No way to resume. + } + fmt.Println(attrs) +} + +func ExampleCopier_Run_progress() { + // Display progress across multiple rewrite RPCs. + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + src := client.Bucket("bucketname").Object("file1") + dst := client.Bucket("another-bucketname").Object("file2") + + copier := dst.CopierFrom(src) + copier.ProgressFunc = func(copiedBytes, totalBytes uint64) { + log.Printf("copy %.1f%% done", float64(copiedBytes)/float64(totalBytes)*100) + } + if _, err := copier.Run(ctx); err != nil { + // TODO: handle error. + } +} + +var key1, key2 []byte + +func ExampleObjectHandle_CopierFrom_rotateEncryptionKeys() { + // To rotate the encryption key on an object, copy it onto itself. + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + obj := client.Bucket("bucketname").Object("obj") + // Assume obj is encrypted with key1, and we want to change to key2. + _, err = obj.Key(key2).CopierFrom(obj.Key(key1)).Run(ctx) + if err != nil { + // TODO: handle error. + } +} + +func ExampleComposer_Run() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + bkt := client.Bucket("bucketname") + src1 := bkt.Object("o1") + src2 := bkt.Object("o2") + dst := bkt.Object("o3") + // Compose and modify metadata. + c := dst.ComposerFrom(src1, src2) + c.ContentType = "text/plain" + attrs, err := c.Run(ctx) + if err != nil { + // TODO: Handle error. + } + fmt.Println(attrs) + // Just compose. + attrs, err = dst.ComposerFrom(src1, src2).Run(ctx) + if err != nil { + // TODO: Handle error. + } + fmt.Println(attrs) +} + +var gen int64 + +func ExampleObjectHandle_Generation() { + // Read an object's contents from generation gen, regardless of the + // current generation of the object. + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + obj := client.Bucket("my-bucket").Object("my-object") + rc, err := obj.Generation(gen).NewReader(ctx) + if err != nil { + // TODO: handle error. + } + defer rc.Close() + if _, err := io.Copy(os.Stdout, rc); err != nil { + // TODO: handle error. + } +} + +func ExampleObjectHandle_If() { + // Read from an object only if the current generation is gen. + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + obj := client.Bucket("my-bucket").Object("my-object") + rc, err := obj.If(storage.Conditions{GenerationMatch: gen}).NewReader(ctx) + if err != nil { + // TODO: handle error. + } + defer rc.Close() + if _, err := io.Copy(os.Stdout, rc); err != nil { + // TODO: handle error. + } +} + +var secretKey []byte + +func ExampleObjectHandle_Key() { + ctx := context.Background() + client, err := storage.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + obj := client.Bucket("my-bucket").Object("my-object") + // Encrypt the object's contents. + w := obj.Key(secretKey).NewWriter(ctx) + if _, err := w.Write([]byte("top secret")); err != nil { + // TODO: handle error. + } + if err := w.Close(); err != nil { + // TODO: handle error. + } +} diff --git a/vendor/cloud.google.com/go/storage/go110.go b/vendor/cloud.google.com/go/storage/go110.go new file mode 100644 index 00000000..206813f0 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/go110.go @@ -0,0 +1,32 @@ +// Copyright 2017 Google LLC +// +// 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. + +// +build go1.10 + +package storage + +import "google.golang.org/api/googleapi" + +func shouldRetry(err error) bool { + switch e := err.(type) { + case *googleapi.Error: + // Retry on 429 and 5xx, according to + // https://cloud.google.com/storage/docs/exponential-backoff. + return e.Code == 429 || (e.Code >= 500 && e.Code < 600) + case interface{ Temporary() bool }: + return e.Temporary() + default: + return false + } +} diff --git a/vendor/cloud.google.com/go/storage/iam.go b/vendor/cloud.google.com/go/storage/iam.go new file mode 100644 index 00000000..9d936067 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/iam.go @@ -0,0 +1,130 @@ +// Copyright 2017 Google LLC +// +// 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 storage + +import ( + "context" + + "cloud.google.com/go/iam" + "cloud.google.com/go/internal/trace" + raw "google.golang.org/api/storage/v1" + iampb "google.golang.org/genproto/googleapis/iam/v1" +) + +// IAM provides access to IAM access control for the bucket. +func (b *BucketHandle) IAM() *iam.Handle { + return iam.InternalNewHandleClient(&iamClient{ + raw: b.c.raw, + userProject: b.userProject, + }, b.name) +} + +// iamClient implements the iam.client interface. +type iamClient struct { + raw *raw.Service + userProject string +} + +func (c *iamClient) Get(ctx context.Context, resource string) (p *iampb.Policy, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Get") + defer func() { trace.EndSpan(ctx, err) }() + + call := c.raw.Buckets.GetIamPolicy(resource) + setClientHeader(call.Header()) + if c.userProject != "" { + call.UserProject(c.userProject) + } + var rp *raw.Policy + err = runWithRetry(ctx, func() error { + rp, err = call.Context(ctx).Do() + return err + }) + if err != nil { + return nil, err + } + return iamFromStoragePolicy(rp), nil +} + +func (c *iamClient) Set(ctx context.Context, resource string, p *iampb.Policy) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Set") + defer func() { trace.EndSpan(ctx, err) }() + + rp := iamToStoragePolicy(p) + call := c.raw.Buckets.SetIamPolicy(resource, rp) + setClientHeader(call.Header()) + if c.userProject != "" { + call.UserProject(c.userProject) + } + return runWithRetry(ctx, func() error { + _, err := call.Context(ctx).Do() + return err + }) +} + +func (c *iamClient) Test(ctx context.Context, resource string, perms []string) (permissions []string, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.IAM.Test") + defer func() { trace.EndSpan(ctx, err) }() + + call := c.raw.Buckets.TestIamPermissions(resource, perms) + setClientHeader(call.Header()) + if c.userProject != "" { + call.UserProject(c.userProject) + } + var res *raw.TestIamPermissionsResponse + err = runWithRetry(ctx, func() error { + res, err = call.Context(ctx).Do() + return err + }) + if err != nil { + return nil, err + } + return res.Permissions, nil +} + +func iamToStoragePolicy(ip *iampb.Policy) *raw.Policy { + return &raw.Policy{ + Bindings: iamToStorageBindings(ip.Bindings), + Etag: string(ip.Etag), + } +} + +func iamToStorageBindings(ibs []*iampb.Binding) []*raw.PolicyBindings { + var rbs []*raw.PolicyBindings + for _, ib := range ibs { + rbs = append(rbs, &raw.PolicyBindings{ + Role: ib.Role, + Members: ib.Members, + }) + } + return rbs +} + +func iamFromStoragePolicy(rp *raw.Policy) *iampb.Policy { + return &iampb.Policy{ + Bindings: iamFromStorageBindings(rp.Bindings), + Etag: []byte(rp.Etag), + } +} + +func iamFromStorageBindings(rbs []*raw.PolicyBindings) []*iampb.Binding { + var ibs []*iampb.Binding + for _, rb := range rbs { + ibs = append(ibs, &iampb.Binding{ + Role: rb.Role, + Members: rb.Members, + }) + } + return ibs +} diff --git a/vendor/cloud.google.com/go/storage/integration_test.go b/vendor/cloud.google.com/go/storage/integration_test.go new file mode 100644 index 00000000..c7de8cdf --- /dev/null +++ b/vendor/cloud.google.com/go/storage/integration_test.go @@ -0,0 +1,2704 @@ +// Copyright 2014 Google LLC +// +// 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 storage + +import ( + "bytes" + "compress/gzip" + "context" + "crypto/md5" + "crypto/sha256" + "encoding/base64" + "encoding/json" + "flag" + "fmt" + "hash/crc32" + "io" + "io/ioutil" + "log" + "math/rand" + "net/http" + "os" + "path/filepath" + "runtime" + "sort" + "strconv" + "strings" + "testing" + "time" + + "cloud.google.com/go/httpreplay" + "cloud.google.com/go/iam" + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/internal/uid" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "google.golang.org/api/googleapi" + "google.golang.org/api/iterator" + itesting "google.golang.org/api/iterator/testing" + "google.golang.org/api/option" +) + +const ( + testPrefix = "go-integration-test" + replayFilename = "storage.replay" +) + +var ( + record = flag.Bool("record", false, "record RPCs") + + uidSpace *uid.Space + bucketName string + // Use our own random number generator to isolate the sequence of random numbers from + // other packages. This makes it possible to use HTTP replay and draw the same sequence + // of numbers as during recording. + rng *rand.Rand + newTestClient func(ctx context.Context, opts ...option.ClientOption) (*Client, error) + replaying bool + testTime time.Time +) + +func TestMain(m *testing.M) { + cleanup := initIntegrationTest() + exit := m.Run() + if err := cleanup(); err != nil { + // Don't fail the test if cleanup fails. + log.Printf("Post-test cleanup failed: %v", err) + } + os.Exit(exit) +} + +// If integration tests will be run, create a unique bucket for them. +// Also, set newTestClient to handle record/replay. +// Return a cleanup function. +func initIntegrationTest() func() error { + flag.Parse() // needed for testing.Short() + switch { + case testing.Short() && *record: + log.Fatal("cannot combine -short and -record") + return nil + + case testing.Short() && httpreplay.Supported() && testutil.CanReplay(replayFilename) && testutil.ProjID() != "": + // go test -short with a replay file will replay the integration tests, if + // the appropriate environment variables have been set. + replaying = true + httpreplay.DebugHeaders() + replayer, err := httpreplay.NewReplayer(replayFilename) + if err != nil { + log.Fatal(err) + } + var t time.Time + if err := json.Unmarshal(replayer.Initial(), &t); err != nil { + log.Fatal(err) + } + initUIDsAndRand(t) + newTestClient = func(ctx context.Context, _ ...option.ClientOption) (*Client, error) { + hc, err := replayer.Client(ctx) // no creds needed + if err != nil { + return nil, err + } + return NewClient(ctx, option.WithHTTPClient(hc)) + } + log.Printf("replaying from %s", replayFilename) + return func() error { return replayer.Close() } + + case testing.Short(): + // go test -short without a replay file skips the integration tests. + if testutil.CanReplay(replayFilename) && testutil.ProjID() != "" { + log.Print("replay not supported for Go versions before 1.8") + } + newTestClient = nil + return func() error { return nil } + + default: // Run integration tests against a real backend. + now := time.Now().UTC() + initUIDsAndRand(now) + var cleanup func() error + if *record && httpreplay.Supported() { + // Remember the time for replay. + nowBytes, err := json.Marshal(now) + if err != nil { + log.Fatal(err) + } + recorder, err := httpreplay.NewRecorder(replayFilename, nowBytes) + if err != nil { + log.Fatalf("could not record: %v", err) + } + newTestClient = func(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + hc, err := recorder.Client(ctx, opts...) + if err != nil { + return nil, err + } + return NewClient(ctx, option.WithHTTPClient(hc)) + } + cleanup = func() error { + err1 := cleanupBuckets() + err2 := recorder.Close() + if err1 != nil { + return err1 + } + return err2 + } + log.Printf("recording to %s", replayFilename) + } else { + if *record { + log.Print("record not supported for Go versions before 1.8") + } + newTestClient = NewClient + cleanup = cleanupBuckets + } + ctx := context.Background() + client := config(ctx) + if client == nil { + return func() error { return nil } + } + defer client.Close() + if err := client.Bucket(bucketName).Create(ctx, testutil.ProjID(), nil); err != nil { + log.Fatalf("creating bucket %q: %v", bucketName, err) + } + return cleanup + } +} + +func initUIDsAndRand(t time.Time) { + uidSpace = uid.NewSpace(testPrefix, &uid.Options{Time: t}) + bucketName = uidSpace.New() + // Use our own random source, to avoid other parts of the program taking + // random numbers from the global source and putting record and replay + // out of sync. + rng = testutil.NewRand(t) + testTime = t +} + +// testConfig returns the Client used to access GCS. testConfig skips +// the current test if credentials are not available or when being run +// in Short mode. +func testConfig(ctx context.Context, t *testing.T) *Client { + if testing.Short() && !replaying { + t.Skip("Integration tests skipped in short mode") + } + client := config(ctx) + if client == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + return client +} + +// config is like testConfig, but it doesn't need a *testing.T. +func config(ctx context.Context) *Client { + ts := testutil.TokenSource(ctx, ScopeFullControl) + if ts == nil { + return nil + } + client, err := newTestClient(ctx, option.WithTokenSource(ts)) + if err != nil { + log.Fatalf("NewClient: %v", err) + } + return client +} + +func TestIntegration_BucketMethods(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + projectID := testutil.ProjID() + newBucketName := uidSpace.New() + b := client.Bucket(newBucketName) + // Test Create and Delete. + h.mustCreate(b, projectID, nil) + attrs := h.mustBucketAttrs(b) + if got, want := attrs.MetaGeneration, int64(1); got != want { + t.Errorf("got metagen %d, want %d", got, want) + } + if got, want := attrs.StorageClass, "STANDARD"; got != want { + t.Errorf("got storage class %q, want %q", got, want) + } + if attrs.VersioningEnabled { + t.Error("got versioning enabled, wanted it disabled") + } + h.mustDeleteBucket(b) + + // Test Create and Delete with attributes. + labels := map[string]string{ + "l1": "v1", + "empty": "", + } + attrs = &BucketAttrs{ + StorageClass: "NEARLINE", + VersioningEnabled: true, + Labels: labels, + Lifecycle: Lifecycle{ + Rules: []LifecycleRule{{ + Action: LifecycleAction{ + Type: SetStorageClassAction, + StorageClass: "NEARLINE", + }, + Condition: LifecycleCondition{ + AgeInDays: 10, + Liveness: Archived, + CreatedBefore: time.Date(2017, 1, 1, 0, 0, 0, 0, time.UTC), + MatchesStorageClasses: []string{"MULTI_REGIONAL", "STANDARD"}, + NumNewerVersions: 3, + }, + }, { + Action: LifecycleAction{ + Type: DeleteAction, + }, + Condition: LifecycleCondition{ + AgeInDays: 30, + Liveness: Live, + CreatedBefore: time.Date(2017, 1, 1, 0, 0, 0, 0, time.UTC), + MatchesStorageClasses: []string{"NEARLINE"}, + NumNewerVersions: 10, + }, + }}, + }, + } + h.mustCreate(b, projectID, attrs) + attrs = h.mustBucketAttrs(b) + if got, want := attrs.MetaGeneration, int64(1); got != want { + t.Errorf("got metagen %d, want %d", got, want) + } + if got, want := attrs.StorageClass, "NEARLINE"; got != want { + t.Errorf("got storage class %q, want %q", got, want) + } + if !attrs.VersioningEnabled { + t.Error("got versioning disabled, wanted it enabled") + } + if got, want := attrs.Labels, labels; !testutil.Equal(got, want) { + t.Errorf("labels: got %v, want %v", got, want) + } + h.mustDeleteBucket(b) +} + +func TestIntegration_BucketUpdate(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + b := client.Bucket(bucketName) + attrs := h.mustBucketAttrs(b) + if attrs.VersioningEnabled { + t.Fatal("bucket should not have versioning by default") + } + if len(attrs.Labels) > 0 { + t.Fatal("bucket should not have labels initially") + } + + // Using empty BucketAttrsToUpdate should be a no-nop. + attrs = h.mustUpdateBucket(b, BucketAttrsToUpdate{}) + if attrs.VersioningEnabled { + t.Fatal("should not have versioning") + } + if len(attrs.Labels) > 0 { + t.Fatal("should not have labels") + } + + // Turn on versioning, add some labels. + ua := BucketAttrsToUpdate{VersioningEnabled: true} + ua.SetLabel("l1", "v1") + ua.SetLabel("empty", "") + attrs = h.mustUpdateBucket(b, ua) + if !attrs.VersioningEnabled { + t.Fatal("should have versioning now") + } + wantLabels := map[string]string{ + "l1": "v1", + "empty": "", + } + if !testutil.Equal(attrs.Labels, wantLabels) { + t.Fatalf("got %v, want %v", attrs.Labels, wantLabels) + } + + // Turn off versioning again; add and remove some more labels. + ua = BucketAttrsToUpdate{VersioningEnabled: false} + ua.SetLabel("l1", "v2") // update + ua.SetLabel("new", "new") // create + ua.DeleteLabel("empty") // delete + ua.DeleteLabel("absent") // delete non-existent + attrs = h.mustUpdateBucket(b, ua) + if attrs.VersioningEnabled { + t.Fatal("should have versioning off") + } + wantLabels = map[string]string{ + "l1": "v2", + "new": "new", + } + if !testutil.Equal(attrs.Labels, wantLabels) { + t.Fatalf("got %v, want %v", attrs.Labels, wantLabels) + } + + // Configure a lifecycle + wantLifecycle := Lifecycle{ + Rules: []LifecycleRule{ + { + Action: LifecycleAction{Type: "Delete"}, + Condition: LifecycleCondition{AgeInDays: 30}, + }, + }, + } + ua = BucketAttrsToUpdate{Lifecycle: &wantLifecycle} + attrs = h.mustUpdateBucket(b, ua) + if !testutil.Equal(attrs.Lifecycle, wantLifecycle) { + t.Fatalf("got %v, want %v", attrs.Lifecycle, wantLifecycle) + } +} + +func TestIntegration_ConditionalDelete(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + o := client.Bucket(bucketName).Object("conddel") + + wc := o.NewWriter(ctx) + wc.ContentType = "text/plain" + h.mustWrite(wc, []byte("foo")) + + gen := wc.Attrs().Generation + metaGen := wc.Attrs().Metageneration + + if err := o.Generation(gen - 1).Delete(ctx); err == nil { + t.Fatalf("Unexpected successful delete with Generation") + } + if err := o.If(Conditions{MetagenerationMatch: metaGen + 1}).Delete(ctx); err == nil { + t.Fatalf("Unexpected successful delete with IfMetaGenerationMatch") + } + if err := o.If(Conditions{MetagenerationNotMatch: metaGen}).Delete(ctx); err == nil { + t.Fatalf("Unexpected successful delete with IfMetaGenerationNotMatch") + } + if err := o.Generation(gen).Delete(ctx); err != nil { + t.Fatalf("final delete failed: %v", err) + } +} + +func TestIntegration_Objects(t *testing.T) { + // TODO(jba): Use subtests (Go 1.7). + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + bkt := client.Bucket(bucketName) + + const defaultType = "text/plain" + + // Populate object names and make a map for their contents. + objects := []string{ + "obj1", + "obj2", + "obj/with/slashes", + } + contents := make(map[string][]byte) + + // Test Writer. + for _, obj := range objects { + c := randomContents() + if err := writeObject(ctx, bkt.Object(obj), defaultType, c); err != nil { + t.Errorf("Write for %v failed with %v", obj, err) + } + contents[obj] = c + } + + testObjectIterator(t, bkt, objects) + + // Test Reader. + for _, obj := range objects { + rc, err := bkt.Object(obj).NewReader(ctx) + if err != nil { + t.Errorf("Can't create a reader for %v, errored with %v", obj, err) + continue + } + if !rc.checkCRC { + t.Errorf("%v: not checking CRC", obj) + } + slurp, err := ioutil.ReadAll(rc) + if err != nil { + t.Errorf("Can't ReadAll object %v, errored with %v", obj, err) + } + if got, want := slurp, contents[obj]; !bytes.Equal(got, want) { + t.Errorf("Contents (%q) = %q; want %q", obj, got, want) + } + if got, want := rc.Size(), len(contents[obj]); got != int64(want) { + t.Errorf("Size (%q) = %d; want %d", obj, got, want) + } + if got, want := rc.ContentType(), "text/plain"; got != want { + t.Errorf("ContentType (%q) = %q; want %q", obj, got, want) + } + if got, want := rc.CacheControl(), "public, max-age=60"; got != want { + t.Errorf("CacheControl (%q) = %q; want %q", obj, got, want) + } + // We just wrote these objects, so they should have a recent last-modified time. + lm, err := rc.LastModified() + // Accept a time within +/- of the test time, to account for natural + // variation and the fact that testTime is set at the start of the test run. + expectedVariance := 5 * time.Minute + if err != nil { + t.Errorf("LastModified (%q): got error %v", obj, err) + } else if lm.Before(testTime.Add(-expectedVariance)) || lm.After(testTime.Add(expectedVariance)) { + t.Errorf("LastModified (%q): got %s, which not the %v from now (%v)", obj, lm, expectedVariance, testTime) + } + rc.Close() + + // Check early close. + buf := make([]byte, 1) + rc, err = bkt.Object(obj).NewReader(ctx) + if err != nil { + t.Fatalf("%v: %v", obj, err) + } + _, err = rc.Read(buf) + if err != nil { + t.Fatalf("%v: %v", obj, err) + } + if got, want := buf, contents[obj][:1]; !bytes.Equal(got, want) { + t.Errorf("Contents[0] (%q) = %q; want %q", obj, got, want) + } + if err := rc.Close(); err != nil { + t.Errorf("%v Close: %v", obj, err) + } + } + + obj := objects[0] + objlen := int64(len(contents[obj])) + // Test Range Reader. + for i, r := range []struct { + offset, length, want int64 + }{ + {0, objlen, objlen}, + {0, objlen / 2, objlen / 2}, + {objlen / 2, objlen, objlen / 2}, + {0, 0, 0}, + {objlen / 2, 0, 0}, + {objlen / 2, -1, objlen / 2}, + {0, objlen * 2, objlen}, + } { + rc, err := bkt.Object(obj).NewRangeReader(ctx, r.offset, r.length) + if err != nil { + t.Errorf("%+v: Can't create a range reader for %v, errored with %v", i, obj, err) + continue + } + if rc.Size() != objlen { + t.Errorf("%+v: Reader has a content-size of %d, want %d", i, rc.Size(), objlen) + } + if rc.Remain() != r.want { + t.Errorf("%+v: Reader's available bytes reported as %d, want %d", i, rc.Remain(), r.want) + } + slurp, err := ioutil.ReadAll(rc) + if err != nil { + t.Errorf("%+v: can't ReadAll object %v, errored with %v", r, obj, err) + continue + } + if len(slurp) != int(r.want) { + t.Errorf("%+v: RangeReader (%d, %d): Read %d bytes, wanted %d bytes", i, r.offset, r.length, len(slurp), r.want) + continue + } + if got, want := slurp, contents[obj][r.offset:r.offset+r.want]; !bytes.Equal(got, want) { + t.Errorf("RangeReader (%d, %d) = %q; want %q", r.offset, r.length, got, want) + } + rc.Close() + } + + objName := objects[0] + + // Test NewReader googleapi.Error. + // Since a 429 or 5xx is hard to cause, we trigger a 416. + realLen := len(contents[objName]) + _, err := bkt.Object(objName).NewRangeReader(ctx, int64(realLen*2), 10) + if err, ok := err.(*googleapi.Error); !ok { + t.Error("NewRangeReader did not return a googleapi.Error") + } else { + if err.Code != 416 { + t.Errorf("Code = %d; want %d", err.Code, 416) + } + if len(err.Header) == 0 { + t.Error("Missing googleapi.Error.Header") + } + if len(err.Body) == 0 { + t.Error("Missing googleapi.Error.Body") + } + } + + // Test StatObject. + o := h.mustObjectAttrs(bkt.Object(objName)) + if got, want := o.Name, objName; got != want { + t.Errorf("Name (%v) = %q; want %q", objName, got, want) + } + if got, want := o.ContentType, defaultType; got != want { + t.Errorf("ContentType (%v) = %q; want %q", objName, got, want) + } + created := o.Created + // Check that the object is newer than its containing bucket. + bAttrs := h.mustBucketAttrs(bkt) + if o.Created.Before(bAttrs.Created) { + t.Errorf("Object %v is older than its containing bucket, %v", o, bAttrs) + } + + // Test object copy. + copyName := "copy-" + objName + copyObj, err := bkt.Object(copyName).CopierFrom(bkt.Object(objName)).Run(ctx) + if err != nil { + t.Errorf("Copier.Run failed with %v", err) + } else if !namesEqual(copyObj, bucketName, copyName) { + t.Errorf("Copy object bucket, name: got %q.%q, want %q.%q", + copyObj.Bucket, copyObj.Name, bucketName, copyName) + } + + // Copying with attributes. + const contentEncoding = "identity" + copier := bkt.Object(copyName).CopierFrom(bkt.Object(objName)) + copier.ContentEncoding = contentEncoding + copyObj, err = copier.Run(ctx) + if err != nil { + t.Errorf("Copier.Run failed with %v", err) + } else { + if !namesEqual(copyObj, bucketName, copyName) { + t.Errorf("Copy object bucket, name: got %q.%q, want %q.%q", + copyObj.Bucket, copyObj.Name, bucketName, copyName) + } + if copyObj.ContentEncoding != contentEncoding { + t.Errorf("Copy ContentEncoding: got %q, want %q", copyObj.ContentEncoding, contentEncoding) + } + } + + // Test UpdateAttrs. + metadata := map[string]string{"key": "value"} + updated := h.mustUpdateObject(bkt.Object(objName), ObjectAttrsToUpdate{ + ContentType: "text/html", + ContentLanguage: "en", + Metadata: metadata, + ACL: []ACLRule{{Entity: "domain-google.com", Role: RoleReader}}, + }) + if got, want := updated.ContentType, "text/html"; got != want { + t.Errorf("updated.ContentType == %q; want %q", got, want) + } + if got, want := updated.ContentLanguage, "en"; got != want { + t.Errorf("updated.ContentLanguage == %q; want %q", updated.ContentLanguage, want) + } + if got, want := updated.Metadata, metadata; !testutil.Equal(got, want) { + t.Errorf("updated.Metadata == %+v; want %+v", updated.Metadata, want) + } + if got, want := updated.Created, created; got != want { + t.Errorf("updated.Created == %q; want %q", got, want) + } + if !updated.Created.Before(updated.Updated) { + t.Errorf("updated.Updated should be newer than update.Created") + } + + // Delete ContentType and ContentLanguage. + updated = h.mustUpdateObject(bkt.Object(objName), ObjectAttrsToUpdate{ + ContentType: "", + ContentLanguage: "", + Metadata: map[string]string{}, + }) + if got, want := updated.ContentType, ""; got != want { + t.Errorf("updated.ContentType == %q; want %q", got, want) + } + if got, want := updated.ContentLanguage, ""; got != want { + t.Errorf("updated.ContentLanguage == %q; want %q", updated.ContentLanguage, want) + } + if updated.Metadata != nil { + t.Errorf("updated.Metadata == %+v; want nil", updated.Metadata) + } + if got, want := updated.Created, created; got != want { + t.Errorf("updated.Created == %q; want %q", got, want) + } + if !updated.Created.Before(updated.Updated) { + t.Errorf("updated.Updated should be newer than update.Created") + } + + // Test checksums. + checksumCases := []struct { + name string + contents [][]byte + size int64 + md5 string + crc32c uint32 + }{ + { + name: "checksum-object", + contents: [][]byte{[]byte("hello"), []byte("world")}, + size: 10, + md5: "fc5e038d38a57032085441e7fe7010b0", + crc32c: 1456190592, + }, + { + name: "zero-object", + contents: [][]byte{}, + size: 0, + md5: "d41d8cd98f00b204e9800998ecf8427e", + crc32c: 0, + }, + } + for _, c := range checksumCases { + wc := bkt.Object(c.name).NewWriter(ctx) + for _, data := range c.contents { + if _, err := wc.Write(data); err != nil { + t.Errorf("Write(%q) failed with %q", data, err) + } + } + if err = wc.Close(); err != nil { + t.Errorf("%q: close failed with %q", c.name, err) + } + obj := wc.Attrs() + if got, want := obj.Size, c.size; got != want { + t.Errorf("Object (%q) Size = %v; want %v", c.name, got, want) + } + if got, want := fmt.Sprintf("%x", obj.MD5), c.md5; got != want { + t.Errorf("Object (%q) MD5 = %q; want %q", c.name, got, want) + } + if got, want := obj.CRC32C, c.crc32c; got != want { + t.Errorf("Object (%q) CRC32C = %v; want %v", c.name, got, want) + } + } + + // Test public ACL. + publicObj := objects[0] + if err = bkt.Object(publicObj).ACL().Set(ctx, AllUsers, RoleReader); err != nil { + t.Errorf("PutACLEntry failed with %v", err) + } + publicClient, err := newTestClient(ctx, option.WithoutAuthentication()) + if err != nil { + t.Fatal(err) + } + + slurp := h.mustRead(publicClient.Bucket(bucketName).Object(publicObj)) + if !bytes.Equal(slurp, contents[publicObj]) { + t.Errorf("Public object's content: got %q, want %q", slurp, contents[publicObj]) + } + + // Test writer error handling. + wc := publicClient.Bucket(bucketName).Object(publicObj).NewWriter(ctx) + if _, err := wc.Write([]byte("hello")); err != nil { + t.Errorf("Write unexpectedly failed with %v", err) + } + if err = wc.Close(); err == nil { + t.Error("Close expected an error, found none") + } + + // Test deleting the copy object. + h.mustDeleteObject(bkt.Object(copyName)) + // Deleting it a second time should return ErrObjectNotExist. + if err := bkt.Object(copyName).Delete(ctx); err != ErrObjectNotExist { + t.Errorf("second deletion of %v = %v; want ErrObjectNotExist", copyName, err) + } + _, err = bkt.Object(copyName).Attrs(ctx) + if err != ErrObjectNotExist { + t.Errorf("Copy is expected to be deleted, stat errored with %v", err) + } + + // Test object composition. + var compSrcs []*ObjectHandle + var wantContents []byte + for _, obj := range objects { + compSrcs = append(compSrcs, bkt.Object(obj)) + wantContents = append(wantContents, contents[obj]...) + } + checkCompose := func(obj *ObjectHandle, wantContentType string) { + rc := h.mustNewReader(obj) + slurp, err = ioutil.ReadAll(rc) + if err != nil { + t.Fatalf("ioutil.ReadAll: %v", err) + } + defer rc.Close() + if !bytes.Equal(slurp, wantContents) { + t.Errorf("Composed object contents\ngot: %q\nwant: %q", slurp, wantContents) + } + if got := rc.ContentType(); got != wantContentType { + t.Errorf("Composed object content-type = %q, want %q", got, wantContentType) + } + } + + // Compose should work even if the user sets no destination attributes. + compDst := bkt.Object("composed1") + c := compDst.ComposerFrom(compSrcs...) + if _, err := c.Run(ctx); err != nil { + t.Fatalf("ComposeFrom error: %v", err) + } + checkCompose(compDst, "application/octet-stream") + + // It should also work if we do. + compDst = bkt.Object("composed2") + c = compDst.ComposerFrom(compSrcs...) + c.ContentType = "text/json" + if _, err := c.Run(ctx); err != nil { + t.Fatalf("ComposeFrom error: %v", err) + } + checkCompose(compDst, "text/json") +} + +func TestIntegration_Encoding(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + bkt := client.Bucket(bucketName) + + // Test content encoding + const zeroCount = 20 << 1 // TODO: should be 20 << 20 + obj := bkt.Object("gzip-test") + w := obj.NewWriter(ctx) + w.ContentEncoding = "gzip" + gw := gzip.NewWriter(w) + if _, err := io.Copy(gw, io.LimitReader(zeros{}, zeroCount)); err != nil { + t.Fatalf("io.Copy, upload: %v", err) + } + if err := gw.Close(); err != nil { + t.Errorf("gzip.Close(): %v", err) + } + if err := w.Close(); err != nil { + t.Errorf("w.Close(): %v", err) + } + r, err := obj.NewReader(ctx) + if err != nil { + t.Fatalf("NewReader(gzip-test): %v", err) + } + n, err := io.Copy(ioutil.Discard, r) + if err != nil { + t.Errorf("io.Copy, download: %v", err) + } + if n != zeroCount { + t.Errorf("downloaded bad data: got %d bytes, want %d", n, zeroCount) + } + + // Test NotFound. + _, err = bkt.Object("obj-not-exists").NewReader(ctx) + if err != ErrObjectNotExist { + t.Errorf("Object should not exist, err found to be %v", err) + } +} + +func namesEqual(obj *ObjectAttrs, bucketName, objectName string) bool { + return obj.Bucket == bucketName && obj.Name == objectName +} + +func testObjectIterator(t *testing.T, bkt *BucketHandle, objects []string) { + ctx := context.Background() + h := testHelper{t} + // Collect the list of items we expect: ObjectAttrs in lexical order by name. + names := make([]string, len(objects)) + copy(names, objects) + sort.Strings(names) + var attrs []*ObjectAttrs + for _, name := range names { + attrs = append(attrs, h.mustObjectAttrs(bkt.Object(name))) + } + msg, ok := itesting.TestIterator(attrs, + func() interface{} { return bkt.Objects(ctx, &Query{Prefix: "obj"}) }, + func(it interface{}) (interface{}, error) { return it.(*ObjectIterator).Next() }) + if !ok { + t.Errorf("ObjectIterator.Next: %s", msg) + } + // TODO(jba): test query.Delimiter != "" +} + +func TestIntegration_SignedURL(t *testing.T) { + if testing.Short() { // do not test during replay + t.Skip("Integration tests skipped in short mode") + } + // To test SignedURL, we need a real user email and private key. Extract them + // from the JSON key file. + jwtConf, err := testutil.JWTConfig() + if err != nil { + t.Fatal(err) + } + if jwtConf == nil { + t.Skip("JSON key file is not present") + } + + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + + bkt := client.Bucket(bucketName) + obj := "signedURL" + contents := []byte("This is a test of SignedURL.\n") + md5 := "Jyxvgwm9n2MsrGTMPbMeYA==" // base64-encoded MD5 of contents + if err := writeObject(ctx, bkt.Object(obj), "text/plain", contents); err != nil { + t.Fatalf("writing: %v", err) + } + for _, test := range []struct { + desc string + opts SignedURLOptions + headers map[string][]string + fail bool + }{ + { + desc: "basic", + }, + { + desc: "MD5 sent and matches", + opts: SignedURLOptions{MD5: md5}, + headers: map[string][]string{"Content-MD5": {md5}}, + }, + { + desc: "MD5 not sent", + opts: SignedURLOptions{MD5: md5}, + fail: true, + }, + { + desc: "Content-Type sent and matches", + opts: SignedURLOptions{ContentType: "text/plain"}, + headers: map[string][]string{"Content-Type": {"text/plain"}}, + }, + { + desc: "Content-Type sent but does not match", + opts: SignedURLOptions{ContentType: "text/plain"}, + headers: map[string][]string{"Content-Type": {"application/json"}}, + fail: true, + }, + { + desc: "Canonical headers sent and match", + opts: SignedURLOptions{Headers: []string{ + " X-Goog-Foo: Bar baz ", + "X-Goog-Novalue", // ignored: no value + "X-Google-Foo", // ignored: wrong prefix + }}, + headers: map[string][]string{"X-Goog-foo": {"Bar baz "}}, + }, + { + desc: "Canonical headers sent but don't match", + opts: SignedURLOptions{Headers: []string{" X-Goog-Foo: Bar baz"}}, + headers: map[string][]string{"X-Goog-Foo": {"bar baz"}}, + fail: true, + }, + } { + opts := test.opts + opts.GoogleAccessID = jwtConf.Email + opts.PrivateKey = jwtConf.PrivateKey + opts.Method = "GET" + opts.Expires = time.Now().Add(time.Hour) + u, err := SignedURL(bucketName, obj, &opts) + if err != nil { + t.Errorf("%s: SignedURL: %v", test.desc, err) + continue + } + got, err := getURL(u, test.headers) + if err != nil && !test.fail { + t.Errorf("%s: getURL %q: %v", test.desc, u, err) + } else if err == nil && !bytes.Equal(got, contents) { + t.Errorf("%s: got %q, want %q", test.desc, got, contents) + } + } +} + +// Make a GET request to a URL using an unauthenticated client, and return its contents. +func getURL(url string, headers map[string][]string) ([]byte, error) { + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + req.Header = headers + res, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + bytes, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err + } + if res.StatusCode != 200 { + return nil, fmt.Errorf("code=%d, body=%s", res.StatusCode, string(bytes)) + } + return bytes, nil +} + +func TestIntegration_ACL(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + + bkt := client.Bucket(bucketName) + + entity := ACLEntity("domain-google.com") + rule := ACLRule{Entity: entity, Role: RoleReader, Domain: "google.com"} + if err := bkt.DefaultObjectACL().Set(ctx, entity, RoleReader); err != nil { + t.Errorf("Can't put default ACL rule for the bucket, errored with %v", err) + } + + acl, err := bkt.DefaultObjectACL().List(ctx) + if err != nil { + t.Errorf("DefaultObjectACL.List for bucket %q: %v", bucketName, err) + } else if !hasRule(acl, rule) { + t.Errorf("default ACL missing %#v", rule) + } + aclObjects := []string{"acl1", "acl2"} + for _, obj := range aclObjects { + c := randomContents() + if err := writeObject(ctx, bkt.Object(obj), "", c); err != nil { + t.Errorf("Write for %v failed with %v", obj, err) + } + } + name := aclObjects[0] + o := bkt.Object(name) + acl, err = o.ACL().List(ctx) + if err != nil { + t.Errorf("Can't retrieve ACL of %v", name) + } else if !hasRule(acl, rule) { + t.Errorf("object ACL missing %+v", rule) + } + if err := o.ACL().Delete(ctx, entity); err != nil { + t.Errorf("object ACL: could not delete entity %s", entity) + } + // Delete the default ACL rule. We can't move this code earlier in the + // test, because the test depends on the fact that the object ACL inherits + // it. + if err := bkt.DefaultObjectACL().Delete(ctx, entity); err != nil { + t.Errorf("default ACL: could not delete entity %s", entity) + } + + entity2 := ACLEntity("user-jbd@google.com") + rule2 := ACLRule{Entity: entity2, Role: RoleReader, Email: "jbd@google.com"} + if err := bkt.ACL().Set(ctx, entity2, RoleReader); err != nil { + t.Errorf("Error while putting bucket ACL rule: %v", err) + } + bACL, err := bkt.ACL().List(ctx) + if err != nil { + t.Errorf("Error while getting the ACL of the bucket: %v", err) + } else if !hasRule(bACL, rule2) { + t.Errorf("bucket ACL missing %+v", rule2) + } + if err := bkt.ACL().Delete(ctx, entity2); err != nil { + t.Errorf("Error while deleting bucket ACL rule: %v", err) + } + +} + +func hasRule(acl []ACLRule, rule ACLRule) bool { + for _, r := range acl { + if cmp.Equal(r, rule) { + return true + } + } + return false +} + +func TestIntegration_ValidObjectNames(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + + bkt := client.Bucket(bucketName) + + validNames := []string{ + "gopher", + "Гоферови", + "a", + strings.Repeat("a", 1024), + } + for _, name := range validNames { + if err := writeObject(ctx, bkt.Object(name), "", []byte("data")); err != nil { + t.Errorf("Object %q write failed: %v. Want success", name, err) + continue + } + defer bkt.Object(name).Delete(ctx) + } + + invalidNames := []string{ + "", // Too short. + strings.Repeat("a", 1025), // Too long. + "new\nlines", + "bad\xffunicode", + } + for _, name := range invalidNames { + // Invalid object names will either cause failure during Write or Close. + if err := writeObject(ctx, bkt.Object(name), "", []byte("data")); err != nil { + continue + } + defer bkt.Object(name).Delete(ctx) + t.Errorf("%q should have failed. Didn't", name) + } +} + +func TestIntegration_WriterContentType(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + + obj := client.Bucket(bucketName).Object("content") + testCases := []struct { + content string + setType, wantType string + }{ + { + content: "It was the best of times, it was the worst of times.", + wantType: "text/plain; charset=utf-8", + }, + { + content: "My first page", + wantType: "text/html; charset=utf-8", + }, + { + content: "My first page", + setType: "text/html", + wantType: "text/html", + }, + { + content: "My first page", + setType: "image/jpeg", + wantType: "image/jpeg", + }, + } + for i, tt := range testCases { + if err := writeObject(ctx, obj, tt.setType, []byte(tt.content)); err != nil { + t.Errorf("writing #%d: %v", i, err) + } + attrs, err := obj.Attrs(ctx) + if err != nil { + t.Errorf("obj.Attrs: %v", err) + continue + } + if got := attrs.ContentType; got != tt.wantType { + t.Errorf("Content-Type = %q; want %q\nContent: %q\nSet Content-Type: %q", got, tt.wantType, tt.content, tt.setType) + } + } +} + +func TestIntegration_ZeroSizedObject(t *testing.T) { + t.Parallel() + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + obj := client.Bucket(bucketName).Object("zero") + + // Check writing it works as expected. + w := obj.NewWriter(ctx) + if err := w.Close(); err != nil { + t.Fatalf("Writer.Close: %v", err) + } + defer obj.Delete(ctx) + + // Check we can read it too. + body := h.mustRead(obj) + if len(body) != 0 { + t.Errorf("Body is %v, want empty []byte{}", body) + } +} + +func TestIntegration_Encryption(t *testing.T) { + // This function tests customer-supplied encryption keys for all operations + // involving objects. Bucket and ACL operations aren't tested because they + // aren't affected by customer encryption. Neither is deletion. + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + obj := client.Bucket(bucketName).Object("customer-encryption") + key := []byte("my-secret-AES-256-encryption-key") + keyHash := sha256.Sum256(key) + keyHashB64 := base64.StdEncoding.EncodeToString(keyHash[:]) + key2 := []byte("My-Secret-AES-256-Encryption-Key") + contents := "top secret." + + checkMetadataCall := func(msg string, f func(o *ObjectHandle) (*ObjectAttrs, error)) { + // Performing a metadata operation without the key should succeed. + attrs, err := f(obj) + if err != nil { + t.Fatalf("%s: %v", msg, err) + } + // The key hash should match... + if got, want := attrs.CustomerKeySHA256, keyHashB64; got != want { + t.Errorf("%s: key hash: got %q, want %q", msg, got, want) + } + // ...but CRC and MD5 should not be present. + if attrs.CRC32C != 0 { + t.Errorf("%s: CRC: got %v, want 0", msg, attrs.CRC32C) + } + if len(attrs.MD5) > 0 { + t.Errorf("%s: MD5: got %v, want len == 0", msg, attrs.MD5) + } + + // Performing a metadata operation with the key should succeed. + attrs, err = f(obj.Key(key)) + if err != nil { + t.Fatalf("%s: %v", msg, err) + } + // Check the key and content hashes. + if got, want := attrs.CustomerKeySHA256, keyHashB64; got != want { + t.Errorf("%s: key hash: got %q, want %q", msg, got, want) + } + if attrs.CRC32C == 0 { + t.Errorf("%s: CRC: got 0, want non-zero", msg) + } + if len(attrs.MD5) == 0 { + t.Errorf("%s: MD5: got len == 0, want len > 0", msg) + } + } + + checkRead := func(msg string, o *ObjectHandle, k []byte, wantContents string) { + // Reading the object without the key should fail. + if _, err := readObject(ctx, o); err == nil { + t.Errorf("%s: reading without key: want error, got nil", msg) + } + // Reading the object with the key should succeed. + got := h.mustRead(o.Key(k)) + gotContents := string(got) + // And the contents should match what we wrote. + if gotContents != wantContents { + t.Errorf("%s: contents: got %q, want %q", msg, gotContents, wantContents) + } + } + + checkReadUnencrypted := func(msg string, obj *ObjectHandle, wantContents string) { + got := h.mustRead(obj) + gotContents := string(got) + if gotContents != wantContents { + t.Errorf("%s: got %q, want %q", msg, gotContents, wantContents) + } + } + + // Write to obj using our own encryption key, which is a valid 32-byte + // AES-256 key. + h.mustWrite(obj.Key(key).NewWriter(ctx), []byte(contents)) + + checkMetadataCall("Attrs", func(o *ObjectHandle) (*ObjectAttrs, error) { + return o.Attrs(ctx) + }) + + checkMetadataCall("Update", func(o *ObjectHandle) (*ObjectAttrs, error) { + return o.Update(ctx, ObjectAttrsToUpdate{ContentLanguage: "en"}) + }) + + checkRead("first object", obj, key, contents) + + obj2 := client.Bucket(bucketName).Object("customer-encryption-2") + // Copying an object without the key should fail. + if _, err := obj2.CopierFrom(obj).Run(ctx); err == nil { + t.Fatal("want error, got nil") + } + // Copying an object with the key should succeed. + if _, err := obj2.CopierFrom(obj.Key(key)).Run(ctx); err != nil { + t.Fatal(err) + } + // The destination object is not encrypted; we can read it without a key. + checkReadUnencrypted("copy dest", obj2, contents) + + // Providing a key on the destination but not the source should fail, + // since the source is encrypted. + if _, err := obj2.Key(key2).CopierFrom(obj).Run(ctx); err == nil { + t.Fatal("want error, got nil") + } + + // But copying with keys for both source and destination should succeed. + if _, err := obj2.Key(key2).CopierFrom(obj.Key(key)).Run(ctx); err != nil { + t.Fatal(err) + } + // And the destination should be encrypted, meaning we can only read it + // with a key. + checkRead("copy destination", obj2, key2, contents) + + // Change obj2's key to prepare for compose, where all objects must have + // the same key. Also illustrates key rotation: copy an object to itself + // with a different key. + if _, err := obj2.Key(key).CopierFrom(obj2.Key(key2)).Run(ctx); err != nil { + t.Fatal(err) + } + obj3 := client.Bucket(bucketName).Object("customer-encryption-3") + // Composing without keys should fail. + if _, err := obj3.ComposerFrom(obj, obj2).Run(ctx); err == nil { + t.Fatal("want error, got nil") + } + // Keys on the source objects result in an error. + if _, err := obj3.ComposerFrom(obj.Key(key), obj2).Run(ctx); err == nil { + t.Fatal("want error, got nil") + } + // A key on the destination object both decrypts the source objects + // and encrypts the destination. + if _, err := obj3.Key(key).ComposerFrom(obj, obj2).Run(ctx); err != nil { + t.Fatalf("got %v, want nil", err) + } + // Check that the destination in encrypted. + checkRead("compose destination", obj3, key, contents+contents) + + // You can't compose one or more unencrypted source objects into an + // encrypted destination object. + _, err := obj2.CopierFrom(obj2.Key(key)).Run(ctx) // unencrypt obj2 + if err != nil { + t.Fatal(err) + } + if _, err := obj3.Key(key).ComposerFrom(obj2).Run(ctx); err == nil { + t.Fatal("got nil, want error") + } +} + +func TestIntegration_NonexistentBucket(t *testing.T) { + t.Parallel() + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + + bkt := client.Bucket(uidSpace.New()) + if _, err := bkt.Attrs(ctx); err != ErrBucketNotExist { + t.Errorf("Attrs: got %v, want ErrBucketNotExist", err) + } + it := bkt.Objects(ctx, nil) + if _, err := it.Next(); err != ErrBucketNotExist { + t.Errorf("Objects: got %v, want ErrBucketNotExist", err) + } +} + +func TestIntegration_PerObjectStorageClass(t *testing.T) { + const ( + defaultStorageClass = "STANDARD" + newStorageClass = "MULTI_REGIONAL" + ) + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + bkt := client.Bucket(bucketName) + + // The bucket should have the default storage class. + battrs := h.mustBucketAttrs(bkt) + if battrs.StorageClass != defaultStorageClass { + t.Fatalf("bucket storage class: got %q, want %q", + battrs.StorageClass, defaultStorageClass) + } + // Write an object; it should start with the bucket's storage class. + obj := bkt.Object("posc") + h.mustWrite(obj.NewWriter(ctx), []byte("foo")) + oattrs, err := obj.Attrs(ctx) + if err != nil { + t.Fatal(err) + } + if oattrs.StorageClass != defaultStorageClass { + t.Fatalf("object storage class: got %q, want %q", + oattrs.StorageClass, defaultStorageClass) + } + // Now use Copy to change the storage class. + copier := obj.CopierFrom(obj) + copier.StorageClass = newStorageClass + oattrs2, err := copier.Run(ctx) + if err != nil { + log.Fatal(err) + } + if oattrs2.StorageClass != newStorageClass { + t.Fatalf("new object storage class: got %q, want %q", + oattrs2.StorageClass, newStorageClass) + } + + // We can also write a new object using a non-default storage class. + obj2 := bkt.Object("posc2") + w := obj2.NewWriter(ctx) + w.StorageClass = newStorageClass + h.mustWrite(w, []byte("xxx")) + if w.Attrs().StorageClass != newStorageClass { + t.Fatalf("new object storage class: got %q, want %q", + w.Attrs().StorageClass, newStorageClass) + } +} + +func TestIntegration_BucketInCopyAttrs(t *testing.T) { + // Confirm that if bucket is included in the object attributes of a rewrite + // call, but object name and content-type aren't, then we get an error. See + // the comment in Copier.Run. + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + bkt := client.Bucket(bucketName) + obj := bkt.Object("bucketInCopyAttrs") + h.mustWrite(obj.NewWriter(ctx), []byte("foo")) + copier := obj.CopierFrom(obj) + rawObject := copier.ObjectAttrs.toRawObject(bucketName) + _, err := copier.callRewrite(ctx, rawObject) + if err == nil { + t.Errorf("got nil, want error") + } +} + +func TestIntegration_NoUnicodeNormalization(t *testing.T) { + t.Parallel() + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + bkt := client.Bucket("storage-library-test-bucket") + h := testHelper{t} + + for _, tst := range []struct { + nameQuoted, content string + }{ + {`"Caf\u00e9"`, "Normalization Form C"}, + {`"Cafe\u0301"`, "Normalization Form D"}, + } { + name, err := strconv.Unquote(tst.nameQuoted) + if err != nil { + t.Fatalf("invalid name: %s: %v", tst.nameQuoted, err) + } + if got := string(h.mustRead(bkt.Object(name))); got != tst.content { + t.Errorf("content of %s is %q, want %q", tst.nameQuoted, got, tst.content) + } + } +} + +func TestIntegration_HashesOnUpload(t *testing.T) { + // Check that the user can provide hashes on upload, and that these are checked. + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + obj := client.Bucket(bucketName).Object("hashesOnUpload-1") + data := []byte("I can't wait to be verified") + + write := func(w *Writer) error { + if _, err := w.Write(data); err != nil { + _ = w.Close() + return err + } + return w.Close() + } + + crc32c := crc32.Checksum(data, crc32cTable) + // The correct CRC should succeed. + w := obj.NewWriter(ctx) + w.CRC32C = crc32c + w.SendCRC32C = true + if err := write(w); err != nil { + t.Fatal(err) + } + + // If we change the CRC, validation should fail. + w = obj.NewWriter(ctx) + w.CRC32C = crc32c + 1 + w.SendCRC32C = true + if err := write(w); err == nil { + t.Fatal("write with bad CRC32c: want error, got nil") + } + + // If we have the wrong CRC but forget to send it, we succeed. + w = obj.NewWriter(ctx) + w.CRC32C = crc32c + 1 + if err := write(w); err != nil { + t.Fatal(err) + } + + // MD5 + md5 := md5.Sum(data) + // The correct MD5 should succeed. + w = obj.NewWriter(ctx) + w.MD5 = md5[:] + if err := write(w); err != nil { + t.Fatal(err) + } + + // If we change the MD5, validation should fail. + w = obj.NewWriter(ctx) + w.MD5 = append([]byte(nil), md5[:]...) + w.MD5[0]++ + if err := write(w); err == nil { + t.Fatal("write with bad MD5: want error, got nil") + } +} + +func TestIntegration_BucketIAM(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + + bkt := client.Bucket(bucketName) + + // This bucket is unique to this test run. So we don't have + // to worry about other runs interfering with our IAM policy + // changes. + + member := "projectViewer:" + testutil.ProjID() + role := iam.RoleName("roles/storage.objectViewer") + // Get the bucket's IAM policy. + policy, err := bkt.IAM().Policy(ctx) + if err != nil { + t.Fatalf("Getting policy: %v", err) + } + // The member should not have the role. + if policy.HasRole(member, role) { + t.Errorf("member %q has role %q", member, role) + } + // Change the policy. + policy.Add(member, role) + if err := bkt.IAM().SetPolicy(ctx, policy); err != nil { + t.Fatalf("SetPolicy: %v", err) + } + // Confirm that the binding was added. + policy, err = bkt.IAM().Policy(ctx) + if err != nil { + t.Fatalf("Getting policy: %v", err) + } + if !policy.HasRole(member, role) { + t.Errorf("member %q does not have role %q", member, role) + } + + // Check TestPermissions. + // This client should have all these permissions (and more). + perms := []string{"storage.buckets.get", "storage.buckets.delete"} + got, err := bkt.IAM().TestPermissions(ctx, perms) + if err != nil { + t.Fatalf("TestPermissions: %v", err) + } + sort.Strings(perms) + sort.Strings(got) + if !testutil.Equal(got, perms) { + t.Errorf("got %v, want %v", got, perms) + } +} + +func TestIntegration_RequesterPays(t *testing.T) { + // This test needs a second project and user (token source) to test + // all possibilities. Since we need these things for Firestore already, + // we use them here. + // + // There are up to three entities involved in a requester-pays call: + // + // 1. The user making the request. Here, we use + // a. The account used to create the token source used for all our + // integration tests (see testutil.TokenSource). + // b. The account used for the Firestore tests. + // 2. The project that owns the requester-pays bucket. Here, that + // is the test project ID (see testutil.ProjID). + // 3. The project provided as the userProject parameter of the request; + // the project to be billed. This test uses: + // a. The project that owns the requester-pays bucket (same as (2)) + // b. Another project (the Firestore project). + // + // The following must hold for this test to work: + // - (1a) must have resourcemanager.projects.createBillingAssignment permission + // (Owner role) on (2) (the project, not the bucket). + // - (1b) must NOT have that permission on (2). + // - (1b) must have serviceusage.services.use permission (Editor role) on (3b). + // - (1b) must NOT have that permission on (3a). + // - (1a) must NOT have that permission on (3b). + const wantErrorCode = 400 + + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + bucketName2 := uidSpace.New() + b1 := client.Bucket(bucketName2) + projID := testutil.ProjID() + // Use Firestore project as a project that does not contain the bucket. + otherProjID := os.Getenv(envFirestoreProjID) + if otherProjID == "" { + t.Fatalf("need a second project (env var %s)", envFirestoreProjID) + } + ts := testutil.TokenSourceEnv(ctx, envFirestorePrivateKey, ScopeFullControl) + if ts == nil { + t.Fatalf("need a second account (env var %s)", envFirestorePrivateKey) + } + otherClient, err := newTestClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + defer otherClient.Close() + b2 := otherClient.Bucket(bucketName2) + user, err := keyFileEmail(os.Getenv("GCLOUD_TESTS_GOLANG_KEY")) + if err != nil { + t.Fatal(err) + } + otherUser, err := keyFileEmail(os.Getenv(envFirestorePrivateKey)) + if err != nil { + t.Fatal(err) + } + + // Create a requester-pays bucket. The bucket is contained in the project projID. + h.mustCreate(b1, projID, &BucketAttrs{RequesterPays: true}) + if err := b1.ACL().Set(ctx, ACLEntity("user-"+otherUser), RoleOwner); err != nil { + t.Fatal(err) + } + + // Extract the error code from err if it's a googleapi.Error. + errCode := func(err error) int { + if err == nil { + return 0 + } + if err, ok := err.(*googleapi.Error); ok { + return err.Code + } + return -1 + } + + // Call f under various conditions. + // Here b and ob refer to the same bucket, but b is bound to client, + // while ob is bound to otherClient. The clients differ in their credentials, + // i.e. the identity of the user making the RPC: b's user is an Owner on the + // bucket's containing project, ob's is not. + call := func(msg string, f func(*BucketHandle) error) { + // user: an Owner on the containing project + // userProject: absent + // result: success, by the rule permitting access by owners of the containing bucket. + if err := f(b1); err != nil { + t.Errorf("%s: %v, want nil\n"+ + "confirm that %s is an Owner on %s", + msg, err, user, projID) + } + // user: an Owner on the containing project + // userProject: containing project + // result: success, by the same rule as above; userProject is unnecessary but allowed. + if err := f(b1.UserProject(projID)); err != nil { + t.Errorf("%s: got %v, want nil", msg, err) + } + // user: not an Owner on the containing project + // userProject: absent + // result: failure, by the standard requester-pays rule + err := f(b2) + if got, want := errCode(err), wantErrorCode; got != want { + t.Errorf("%s: got error %v with code %d, want code %d\n"+ + "confirm that %s is NOT an Owner on %s", + msg, err, got, want, otherUser, projID) + } + // user: not an Owner on the containing project + // userProject: not the containing one, but user has Editor role on it + // result: success, by the standard requester-pays rule + if err := f(b2.UserProject(otherProjID)); err != nil { + t.Errorf("%s: got %v, want nil\n"+ + "confirm that %s is an Editor on %s and that that project has billing enabled", + msg, err, otherUser, otherProjID) + } + // user: not an Owner on the containing project + // userProject: the containing one, on which the user does NOT have Editor permission. + // result: failure + err = f(b2.UserProject("veener-jba")) + if got, want := errCode(err), 403; got != want { + t.Errorf("%s: got error %v, want code %d\n"+ + "confirm that %s is NOT an Editor on %s", + msg, err, want, otherUser, "veener-jba") + } + } + + // Getting its attributes requires a user project. + var attrs *BucketAttrs + call("Bucket attrs", func(b *BucketHandle) error { + a, err := b.Attrs(ctx) + if a != nil { + attrs = a + } + return err + }) + if attrs != nil { + if got, want := attrs.RequesterPays, true; got != want { + t.Fatalf("attr.RequesterPays = %t, want %t", got, want) + } + } + // Object operations. + call("write object", func(b *BucketHandle) error { + return writeObject(ctx, b.Object("foo"), "text/plain", []byte("hello")) + }) + call("read object", func(b *BucketHandle) error { + _, err := readObject(ctx, b.Object("foo")) + return err + }) + call("object attrs", func(b *BucketHandle) error { + _, err := b.Object("foo").Attrs(ctx) + return err + }) + call("update object", func(b *BucketHandle) error { + _, err := b.Object("foo").Update(ctx, ObjectAttrsToUpdate{ContentLanguage: "en"}) + return err + }) + + // ACL operations. + entity := ACLEntity("domain-google.com") + call("bucket acl set", func(b *BucketHandle) error { + return b.ACL().Set(ctx, entity, RoleReader) + }) + call("bucket acl list", func(b *BucketHandle) error { + _, err := b.ACL().List(ctx) + return err + }) + call("bucket acl delete", func(b *BucketHandle) error { + err := b.ACL().Delete(ctx, entity) + if errCode(err) == 404 { + // Since we call the function multiple times, it will + // fail with NotFound for all but the first. + return nil + } + return err + }) + call("default object acl set", func(b *BucketHandle) error { + return b.DefaultObjectACL().Set(ctx, entity, RoleReader) + }) + call("default object acl list", func(b *BucketHandle) error { + _, err := b.DefaultObjectACL().List(ctx) + return err + }) + call("default object acl delete", func(b *BucketHandle) error { + err := b.DefaultObjectACL().Delete(ctx, entity) + if errCode(err) == 404 { + return nil + } + return err + }) + call("object acl set", func(b *BucketHandle) error { + return b.Object("foo").ACL().Set(ctx, entity, RoleReader) + }) + call("object acl list", func(b *BucketHandle) error { + _, err := b.Object("foo").ACL().List(ctx) + return err + }) + call("object acl delete", func(b *BucketHandle) error { + err := b.Object("foo").ACL().Delete(ctx, entity) + if errCode(err) == 404 { + return nil + } + return err + }) + + // Copy and compose. + call("copy", func(b *BucketHandle) error { + _, err := b.Object("copy").CopierFrom(b.Object("foo")).Run(ctx) + return err + }) + call("compose", func(b *BucketHandle) error { + _, err := b.Object("compose").ComposerFrom(b.Object("foo"), b.Object("copy")).Run(ctx) + return err + }) + call("delete object", func(b *BucketHandle) error { + // Make sure the object exists, so we don't get confused by ErrObjectNotExist. + // The storage service may perform validation in any order (perhaps in parallel), + // so if we delete an object that doesn't exist and for which we lack permission, + // we could see either of those two errors. (See Google-internal bug 78341001.) + h.mustWrite(b1.Object("foo").NewWriter(ctx), []byte("hello")) // note: b1, not b. + return b.Object("foo").Delete(ctx) + }) + b1.Object("foo").Delete(ctx) // Make sure object is deleted. + for _, obj := range []string{"copy", "compose"} { + if err := b1.UserProject(projID).Object(obj).Delete(ctx); err != nil { + t.Fatalf("could not delete %q: %v", obj, err) + } + } + + h.mustDeleteBucket(b1) +} + +// TODO(jba): move to testutil, factor out from firestore/integration_test.go. +const ( + envFirestoreProjID = "GCLOUD_TESTS_GOLANG_FIRESTORE_PROJECT_ID" + envFirestorePrivateKey = "GCLOUD_TESTS_GOLANG_FIRESTORE_KEY" +) + +func keyFileEmail(filename string) (string, error) { + bytes, err := ioutil.ReadFile(filename) + if err != nil { + return "", err + } + var v struct { + ClientEmail string `json:"client_email"` + } + if err := json.Unmarshal(bytes, &v); err != nil { + return "", err + } + return v.ClientEmail, nil +} + +func TestIntegration_Notifications(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + bkt := client.Bucket(bucketName) + + checkNotifications := func(msg string, want map[string]*Notification) { + got, err := bkt.Notifications(ctx) + if err != nil { + t.Fatal(err) + } + if diff := testutil.Diff(got, want); diff != "" { + t.Errorf("%s: got=-, want=+:\n%s", msg, diff) + } + } + checkNotifications("initial", map[string]*Notification{}) + + nArg := &Notification{ + TopicProjectID: testutil.ProjID(), + TopicID: "go-storage-notification-test", + PayloadFormat: NoPayload, + } + n, err := bkt.AddNotification(ctx, nArg) + if err != nil { + t.Fatal(err) + } + nArg.ID = n.ID + if !testutil.Equal(n, nArg) { + t.Errorf("got %+v, want %+v", n, nArg) + } + checkNotifications("after add", map[string]*Notification{n.ID: n}) + + if err := bkt.DeleteNotification(ctx, n.ID); err != nil { + t.Fatal(err) + } + checkNotifications("after delete", map[string]*Notification{}) +} + +func TestIntegration_PublicBucket(t *testing.T) { + // Confirm that an unauthenticated client can access a public bucket. + // See https://cloud.google.com/storage/docs/public-datasets/landsat + if testing.Short() && !replaying { + t.Skip("Integration tests skipped in short mode") + } + + const landsatBucket = "gcp-public-data-landsat" + const landsatPrefix = "LC08/PRE/044/034/LC80440342016259LGN00/" + const landsatObject = landsatPrefix + "LC80440342016259LGN00_MTL.txt" + + // Create an unauthenticated client. + ctx := context.Background() + client, err := newTestClient(ctx, option.WithoutAuthentication()) + if err != nil { + t.Fatal(err) + } + defer client.Close() + h := testHelper{t} + bkt := client.Bucket(landsatBucket) + obj := bkt.Object(landsatObject) + + // Read a public object. + bytes := h.mustRead(obj) + if got, want := len(bytes), 7903; got != want { + t.Errorf("len(bytes) = %d, want %d", got, want) + } + + // List objects in a public bucket. + iter := bkt.Objects(ctx, &Query{Prefix: landsatPrefix}) + gotCount := 0 + for { + _, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + t.Fatal(err) + } + gotCount++ + } + if wantCount := 13; gotCount != wantCount { + t.Errorf("object count: got %d, want %d", gotCount, wantCount) + } + + errCode := func(err error) int { + err2, ok := err.(*googleapi.Error) + if !ok { + return -1 + } + return err2.Code + } + + // Reading from or writing to a non-public bucket fails. + c := testConfig(ctx, t) + defer c.Close() + nonPublicObj := client.Bucket(bucketName).Object("noauth") + // Oddly, reading returns 403 but writing returns 401. + _, err = readObject(ctx, nonPublicObj) + if got, want := errCode(err), 403; got != want { + t.Errorf("got code %d; want %d\nerror: %v", got, want, err) + } + err = writeObject(ctx, nonPublicObj, "text/plain", []byte("b")) + if got, want := errCode(err), 401; got != want { + t.Errorf("got code %d; want %d\nerror: %v", got, want, err) + } +} + +func TestIntegration_ReadCRC(t *testing.T) { + // Test that the checksum is handled correctly when reading files. + // For gzipped files, see https://github.com/GoogleCloudPlatform/google-cloud-dotnet/issues/1641. + if testing.Short() && !replaying { + t.Skip("Integration tests skipped in short mode") + } + + const ( + // This is an uncompressed file. + // See https://cloud.google.com/storage/docs/public-datasets/landsat + uncompressedBucket = "gcp-public-data-landsat" + uncompressedObject = "LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt" + + gzippedBucket = "storage-library-test-bucket" + gzippedObject = "gzipped-text.txt" + gzippedContents = "hello world" // uncompressed contents of the file + ) + ctx := context.Background() + client, err := newTestClient(ctx, option.WithoutAuthentication()) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + for _, test := range []struct { + desc string + obj *ObjectHandle + offset, length int64 + readCompressed bool // don't decompress a gzipped file + + wantErr bool + wantCheck bool // Should Reader try to check the CRC? + }{ + { + desc: "uncompressed, entire file", + obj: client.Bucket(uncompressedBucket).Object(uncompressedObject), + offset: 0, + length: -1, + readCompressed: false, + wantCheck: true, + }, + { + desc: "uncompressed, entire file, don't decompress", + obj: client.Bucket(uncompressedBucket).Object(uncompressedObject), + offset: 0, + length: -1, + readCompressed: true, + wantCheck: true, + }, + { + desc: "uncompressed, suffix", + obj: client.Bucket(uncompressedBucket).Object(uncompressedObject), + offset: 1, + length: -1, + readCompressed: false, + wantCheck: false, + }, + { + desc: "uncompressed, prefix", + obj: client.Bucket(uncompressedBucket).Object(uncompressedObject), + offset: 0, + length: 18, + readCompressed: false, + wantCheck: false, + }, + { + // When a gzipped file is unzipped on read, we can't verify the checksum + // because it was computed against the zipped contents. We can detect + // this case using http.Response.Uncompressed. + desc: "compressed, entire file, unzipped", + obj: client.Bucket(gzippedBucket).Object(gzippedObject), + offset: 0, + length: -1, + readCompressed: false, + wantCheck: false, + }, + { + // When we read a gzipped file uncompressed, it's like reading a regular file: + // the served content and the CRC match. + desc: "compressed, entire file, read compressed", + obj: client.Bucket(gzippedBucket).Object(gzippedObject), + offset: 0, + length: -1, + readCompressed: true, + wantCheck: true, + }, + { + desc: "compressed, partial, server unzips", + obj: client.Bucket(gzippedBucket).Object(gzippedObject), + offset: 1, + length: 8, + readCompressed: false, + wantErr: true, // GCS can't serve part of a gzipped object + wantCheck: false, + }, + { + desc: "compressed, partial, read compressed", + obj: client.Bucket(gzippedBucket).Object(gzippedObject), + offset: 1, + length: 8, + readCompressed: true, + wantCheck: false, + }, + } { + obj := test.obj.ReadCompressed(test.readCompressed) + r, err := obj.NewRangeReader(ctx, test.offset, test.length) + if err != nil { + if test.wantErr { + continue + } + t.Fatalf("%s: %v", test.desc, err) + } + if got, want := r.checkCRC, test.wantCheck; got != want { + t.Errorf("%s, checkCRC: got %t, want %t", test.desc, got, want) + } + _, err = ioutil.ReadAll(r) + _ = r.Close() + if err != nil { + t.Fatalf("%s: %v", test.desc, err) + } + } +} + +func TestIntegration_CancelWrite(t *testing.T) { + // Verify that canceling the writer's context immediately stops uploading an object. + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + bkt := client.Bucket(bucketName) + + cctx, cancel := context.WithCancel(ctx) + defer cancel() + obj := bkt.Object("cancel-write") + w := obj.NewWriter(cctx) + w.ChunkSize = googleapi.MinUploadChunkSize + buf := make([]byte, w.ChunkSize) + // Write the first chunk. This is read in its entirety before sending the request + // (see google.golang.org/api/gensupport.PrepareUpload), so we expect it to return + // without error. + _, err := w.Write(buf) + if err != nil { + t.Fatal(err) + } + // Now cancel the context. + cancel() + // The next Write should return context.Canceled. + _, err = w.Write(buf) + if err != context.Canceled { + t.Fatalf("got %v, wanted context.Canceled", err) + } + // The Close should too. + err = w.Close() + if err != context.Canceled { + t.Fatalf("got %v, wanted context.Canceled", err) + } +} + +func TestIntegration_UpdateCORS(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + initialSettings := []CORS{ + { + MaxAge: time.Hour, + Methods: []string{"POST"}, + Origins: []string{"some-origin.com"}, + ResponseHeaders: []string{"foo-bar"}, + }, + } + + for _, test := range []struct { + input []CORS + want []CORS + }{ + { + input: []CORS{ + { + MaxAge: time.Hour, + Methods: []string{"GET"}, + Origins: []string{"*"}, + ResponseHeaders: []string{"some-header"}, + }, + }, + want: []CORS{ + { + MaxAge: time.Hour, + Methods: []string{"GET"}, + Origins: []string{"*"}, + ResponseHeaders: []string{"some-header"}, + }, + }, + }, + { + input: []CORS{}, + want: nil, + }, + { + input: nil, + want: []CORS{ + { + MaxAge: time.Hour, + Methods: []string{"POST"}, + Origins: []string{"some-origin.com"}, + ResponseHeaders: []string{"foo-bar"}, + }, + }, + }, + } { + bkt := client.Bucket(uidSpace.New()) + h.mustCreate(bkt, testutil.ProjID(), &BucketAttrs{CORS: initialSettings}) + defer h.mustDeleteBucket(bkt) + h.mustUpdateBucket(bkt, BucketAttrsToUpdate{CORS: test.input}) + attrs := h.mustBucketAttrs(bkt) + if diff := testutil.Diff(attrs.CORS, test.want); diff != "" { + t.Errorf("input: %v\ngot=-, want=+:\n%s", test.input, diff) + } + } +} + +func TestIntegration_UpdateDefaultEventBasedHold(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + bkt := client.Bucket(uidSpace.New()) + h.mustCreate(bkt, testutil.ProjID(), &BucketAttrs{}) + defer h.mustDeleteBucket(bkt) + attrs := h.mustBucketAttrs(bkt) + if attrs.DefaultEventBasedHold != false { + t.Errorf("got=%v, want=%v", attrs.DefaultEventBasedHold, false) + } + + h.mustUpdateBucket(bkt, BucketAttrsToUpdate{DefaultEventBasedHold: true}) + attrs = h.mustBucketAttrs(bkt) + if attrs.DefaultEventBasedHold != true { + t.Errorf("got=%v, want=%v", attrs.DefaultEventBasedHold, true) + } + + // Omitting it should leave the value unchanged. + h.mustUpdateBucket(bkt, BucketAttrsToUpdate{RequesterPays: true}) + attrs = h.mustBucketAttrs(bkt) + if attrs.DefaultEventBasedHold != true { + t.Errorf("got=%v, want=%v", attrs.DefaultEventBasedHold, true) + } +} + +func TestIntegration_UpdateEventBasedHold(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + bkt := client.Bucket(uidSpace.New()) + h.mustCreate(bkt, testutil.ProjID(), &BucketAttrs{}) + obj := bkt.Object("some-obj") + h.mustWrite(obj.NewWriter(ctx), randomContents()) + + defer func() { + h.mustUpdateObject(obj, ObjectAttrsToUpdate{EventBasedHold: false}) + h.mustDeleteObject(obj) + h.mustDeleteBucket(bkt) + }() + + attrs := h.mustObjectAttrs(obj) + if attrs.EventBasedHold != false { + t.Fatalf("got=%v, want=%v", attrs.EventBasedHold, false) + } + + h.mustUpdateObject(obj, ObjectAttrsToUpdate{EventBasedHold: true}) + attrs = h.mustObjectAttrs(obj) + if attrs.EventBasedHold != true { + t.Fatalf("got=%v, want=%v", attrs.EventBasedHold, true) + } + + // Omitting it should leave the value unchanged. + h.mustUpdateObject(obj, ObjectAttrsToUpdate{ContentType: "foo"}) + attrs = h.mustObjectAttrs(obj) + if attrs.EventBasedHold != true { + t.Fatalf("got=%v, want=%v", attrs.EventBasedHold, true) + } +} + +func TestIntegration_UpdateTemporaryHold(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + bkt := client.Bucket(uidSpace.New()) + h.mustCreate(bkt, testutil.ProjID(), &BucketAttrs{}) + obj := bkt.Object("some-obj") + h.mustWrite(obj.NewWriter(ctx), randomContents()) + + defer func() { + h.mustUpdateObject(obj, ObjectAttrsToUpdate{TemporaryHold: false}) + h.mustDeleteObject(obj) + h.mustDeleteBucket(bkt) + }() + + attrs := h.mustObjectAttrs(obj) + if attrs.TemporaryHold != false { + t.Fatalf("got=%v, want=%v", attrs.TemporaryHold, false) + } + + h.mustUpdateObject(obj, ObjectAttrsToUpdate{TemporaryHold: true}) + attrs = h.mustObjectAttrs(obj) + if attrs.TemporaryHold != true { + t.Fatalf("got=%v, want=%v", attrs.TemporaryHold, true) + } + + // Omitting it should leave the value unchanged. + h.mustUpdateObject(obj, ObjectAttrsToUpdate{ContentType: "foo"}) + attrs = h.mustObjectAttrs(obj) + if attrs.TemporaryHold != true { + t.Fatalf("got=%v, want=%v", attrs.TemporaryHold, true) + } +} + +func TestIntegration_UpdateRetentionExpirationTime(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + bkt := client.Bucket(uidSpace.New()) + h.mustCreate(bkt, testutil.ProjID(), &BucketAttrs{RetentionPolicy: &RetentionPolicy{RetentionPeriod: time.Hour}}) + obj := bkt.Object("some-obj") + h.mustWrite(obj.NewWriter(ctx), randomContents()) + + defer func() { + h.mustUpdateBucket(bkt, BucketAttrsToUpdate{RetentionPolicy: &RetentionPolicy{RetentionPeriod: 0}}) + h.mustDeleteObject(obj) + h.mustDeleteBucket(bkt) + }() + + attrs := h.mustObjectAttrs(obj) + if attrs.RetentionExpirationTime == (time.Time{}) { + t.Fatalf("got=%v, wanted a non-zero value", attrs.RetentionExpirationTime) + } +} + +func TestIntegration_UpdateRetentionPolicy(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + initial := &RetentionPolicy{RetentionPeriod: time.Minute} + + for _, test := range []struct { + input *RetentionPolicy + want *RetentionPolicy + }{ + { // Update + input: &RetentionPolicy{RetentionPeriod: time.Hour}, + want: &RetentionPolicy{RetentionPeriod: time.Hour}, + }, + { // Update even with timestamp (EffectiveTime should be ignored) + input: &RetentionPolicy{RetentionPeriod: time.Hour, EffectiveTime: time.Now()}, + want: &RetentionPolicy{RetentionPeriod: time.Hour}, + }, + { // Remove + input: &RetentionPolicy{}, + want: nil, + }, + { // Remove even with timestamp (EffectiveTime should be ignored) + input: &RetentionPolicy{EffectiveTime: time.Now()}, + want: nil, + }, + { // Ignore + input: nil, + want: initial, + }, + } { + bkt := client.Bucket(uidSpace.New()) + h.mustCreate(bkt, testutil.ProjID(), &BucketAttrs{RetentionPolicy: initial}) + defer h.mustDeleteBucket(bkt) + h.mustUpdateBucket(bkt, BucketAttrsToUpdate{RetentionPolicy: test.input}) + attrs := h.mustBucketAttrs(bkt) + if attrs.RetentionPolicy != nil && attrs.RetentionPolicy.EffectiveTime.Unix() == 0 { + // Should be set by the server and parsed by the client + t.Fatal("EffectiveTime should be set, but it was not") + } + if diff := testutil.Diff(attrs.RetentionPolicy, test.want, cmpopts.IgnoreTypes(time.Time{})); diff != "" { + t.Errorf("input: %v\ngot=-, want=+:\n%s", test.input, diff) + } + } +} + +func TestIntegration_DeleteObjectInBucketWithRetentionPolicy(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + bkt := client.Bucket(uidSpace.New()) + h.mustCreate(bkt, testutil.ProjID(), &BucketAttrs{RetentionPolicy: &RetentionPolicy{RetentionPeriod: 25 * time.Hour}}) + + oh := bkt.Object("some-object") + if err := writeObject(ctx, oh, "text/plain", []byte("hello world")); err != nil { + t.Fatal(err) + } + + if err := oh.Delete(ctx); err == nil { + t.Fatal("expected to err deleting an object in a bucket with retention period, but got nil") + } + + // Remove the retention period + h.mustUpdateBucket(bkt, BucketAttrsToUpdate{RetentionPolicy: &RetentionPolicy{RetentionPeriod: 0}}) + h.mustDeleteObject(oh) + h.mustDeleteBucket(bkt) +} + +func TestIntegration_LockBucket(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + bkt := client.Bucket(uidSpace.New()) + h.mustCreate(bkt, testutil.ProjID(), &BucketAttrs{RetentionPolicy: &RetentionPolicy{RetentionPeriod: time.Hour * 25}}) + attrs := h.mustBucketAttrs(bkt) + if attrs.RetentionPolicy.IsLocked { + t.Fatal("Expected bucket to begin unlocked, but it was not") + } + err := bkt.If(BucketConditions{MetagenerationMatch: attrs.MetaGeneration}).LockRetentionPolicy(ctx) + if err != nil { + t.Fatal("could not lock", err) + } + + attrs = h.mustBucketAttrs(bkt) + if !attrs.RetentionPolicy.IsLocked { + t.Fatal("Expected bucket to be locked, but it was not") + } + + _, err = bkt.Update(ctx, BucketAttrsToUpdate{RetentionPolicy: &RetentionPolicy{RetentionPeriod: time.Hour}}) + if err == nil { + t.Fatal("Expected error updating locked bucket, got nil") + } +} + +func TestIntegration_LockBucket_MetagenerationRequired(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + bkt := client.Bucket(uidSpace.New()) + h.mustCreate(bkt, testutil.ProjID(), &BucketAttrs{ + RetentionPolicy: &RetentionPolicy{RetentionPeriod: time.Hour * 25}, + }) + err := bkt.LockRetentionPolicy(ctx) + if err == nil { + t.Fatal("expected error locking bucket without metageneration condition, got nil") + } +} + +func TestIntegration_KMS(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + keyRingName := os.Getenv("GCLOUD_TESTS_GOLANG_KEYRING") + if keyRingName == "" { + t.Fatal("GCLOUD_TESTS_GOLANG_KEYRING must be set. See CONTRIBUTING.md for details") + } + keyName1 := keyRingName + "/cryptoKeys/key1" + keyName2 := keyRingName + "/cryptoKeys/key2" + contents := []byte("my secret") + + write := func(obj *ObjectHandle, setKey bool) { + w := obj.NewWriter(ctx) + if setKey { + w.KMSKeyName = keyName1 + } + h.mustWrite(w, contents) + } + + checkRead := func(obj *ObjectHandle) { + got := h.mustRead(obj) + if !bytes.Equal(got, contents) { + t.Errorf("got %v, want %v", got, contents) + } + attrs := h.mustObjectAttrs(obj) + if len(attrs.KMSKeyName) < len(keyName1) || attrs.KMSKeyName[:len(keyName1)] != keyName1 { + t.Errorf("got %q, want %q", attrs.KMSKeyName, keyName1) + } + } + + // Write an object with a key, then read it to verify its contents and the presence of the key name. + bkt := client.Bucket(bucketName) + obj := bkt.Object("kms") + write(obj, true) + checkRead(obj) + h.mustDeleteObject(obj) + + // Encrypt an object with a CSEK, then copy it using a CMEK. + src := bkt.Object("csek").Key(testEncryptionKey) + if err := writeObject(ctx, src, "text/plain", contents); err != nil { + t.Fatal(err) + } + dest := bkt.Object("cmek") + c := dest.CopierFrom(src) + c.DestinationKMSKeyName = keyName1 + if _, err := c.Run(ctx); err != nil { + t.Fatal(err) + } + checkRead(dest) + src.Delete(ctx) + dest.Delete(ctx) + + // Create a bucket with a default key, then write and read an object. + bkt = client.Bucket(uidSpace.New()) + h.mustCreate(bkt, testutil.ProjID(), &BucketAttrs{ + Location: "US", + Encryption: &BucketEncryption{DefaultKMSKeyName: keyName1}, + }) + defer h.mustDeleteBucket(bkt) + + attrs := h.mustBucketAttrs(bkt) + if got, want := attrs.Encryption.DefaultKMSKeyName, keyName1; got != want { + t.Fatalf("got %q, want %q", got, want) + } + obj = bkt.Object("kms") + write(obj, false) + checkRead(obj) + h.mustDeleteObject(obj) + + // Update the bucket's default key to a different name. + // (This key doesn't have to exist.) + attrs = h.mustUpdateBucket(bkt, BucketAttrsToUpdate{Encryption: &BucketEncryption{DefaultKMSKeyName: keyName2}}) + if got, want := attrs.Encryption.DefaultKMSKeyName, keyName2; got != want { + t.Fatalf("got %q, want %q", got, want) + } + attrs = h.mustBucketAttrs(bkt) + if got, want := attrs.Encryption.DefaultKMSKeyName, keyName2; got != want { + t.Fatalf("got %q, want %q", got, want) + } + + // Remove the default KMS key. + attrs = h.mustUpdateBucket(bkt, BucketAttrsToUpdate{Encryption: &BucketEncryption{DefaultKMSKeyName: ""}}) + if attrs.Encryption != nil { + t.Fatalf("got %#v, want nil", attrs.Encryption) + } +} + +func TestIntegration_PredefinedACLs(t *testing.T) { + check := func(msg string, rs []ACLRule, i int, wantEntity ACLEntity, wantRole ACLRole) { + if i >= len(rs) { + t.Errorf("%s: no rule at index %d", msg, i) + return + } + got := rs[i] + if got.Entity != wantEntity || got.Role != wantRole { + t.Errorf("%s[%d]: got %+v, want Entity %s and Role %s", + msg, i, got, wantEntity, wantRole) + } + } + checkPrefix := func(msg string, rs []ACLRule, i int, wantPrefix string, wantRole ACLRole) { + if i >= len(rs) { + t.Errorf("%s: no rule at index %d", msg, i) + return + } + got := rs[i] + if !strings.HasPrefix(string(got.Entity), wantPrefix) || got.Role != wantRole { + t.Errorf("%s[%d]: got %+v, want Entity %s... and Role %s", + msg, i, got, wantPrefix, wantRole) + } + } + + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + h := testHelper{t} + + bkt := client.Bucket(uidSpace.New()) + h.mustCreate(bkt, testutil.ProjID(), &BucketAttrs{ + PredefinedACL: "authenticatedRead", + PredefinedDefaultObjectACL: "publicRead", + }) + defer h.mustDeleteBucket(bkt) + attrs := h.mustBucketAttrs(bkt) + checkPrefix("Bucket.ACL", attrs.ACL, 0, "project-owners", RoleOwner) + check("Bucket.ACL", attrs.ACL, 1, AllAuthenticatedUsers, RoleReader) + check("DefaultObjectACL", attrs.DefaultObjectACL, 0, AllUsers, RoleReader) + + // Bucket update + attrs = h.mustUpdateBucket(bkt, BucketAttrsToUpdate{ + PredefinedACL: "private", + PredefinedDefaultObjectACL: "authenticatedRead", + }) + checkPrefix("Bucket.ACL update", attrs.ACL, 0, "project-owners", RoleOwner) + check("DefaultObjectACL update", attrs.DefaultObjectACL, 0, AllAuthenticatedUsers, RoleReader) + + // Object creation + obj := bkt.Object("private") + w := obj.NewWriter(ctx) + w.PredefinedACL = "authenticatedRead" + h.mustWrite(w, []byte("hello")) + defer h.mustDeleteObject(obj) + checkPrefix("Object.ACL", w.Attrs().ACL, 0, "user", RoleOwner) + check("Object.ACL", w.Attrs().ACL, 1, AllAuthenticatedUsers, RoleReader) + + // Object update + oattrs := h.mustUpdateObject(obj, ObjectAttrsToUpdate{PredefinedACL: "private"}) + checkPrefix("Object.ACL update", oattrs.ACL, 0, "user", RoleOwner) + if got := len(oattrs.ACL); got != 1 { + t.Errorf("got %d ACLs, want 1", got) + } + + // Copy + dst := bkt.Object("dst") + copier := dst.CopierFrom(obj) + copier.PredefinedACL = "publicRead" + oattrs, err := copier.Run(ctx) + if err != nil { + t.Fatal(err) + } + defer h.mustDeleteObject(dst) + // The copied object still retains the "private" ACL of the source object. + checkPrefix("Copy dest", oattrs.ACL, 0, "user", RoleOwner) + check("Copy dest", oattrs.ACL, 1, AllUsers, RoleReader) + + // Compose + comp := bkt.Object("comp") + composer := comp.ComposerFrom(obj, dst) + composer.PredefinedACL = "authenticatedRead" + oattrs, err = composer.Run(ctx) + if err != nil { + t.Fatal(err) + } + defer h.mustDeleteObject(comp) + // The composed object still retains the "private" ACL. + checkPrefix("Copy dest", oattrs.ACL, 0, "user", RoleOwner) + check("Copy dest", oattrs.ACL, 1, AllAuthenticatedUsers, RoleReader) +} + +func TestIntegration_ServiceAccount(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + + s, err := client.ServiceAccount(ctx, testutil.ProjID()) + if err != nil { + t.Fatal(err) + } + want := "@gs-project-accounts.iam.gserviceaccount.com" + if !strings.Contains(s, want) { + t.Fatalf("got %v, want to contain %v", s, want) + } +} + +func TestIntegration_ReaderAttrs(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + bkt := client.Bucket(bucketName) + + const defaultType = "text/plain" + obj := "some-object" + c := randomContents() + if err := writeObject(ctx, bkt.Object(obj), defaultType, c); err != nil { + t.Errorf("Write for %v failed with %v", obj, err) + } + oh := bkt.Object(obj) + + rc, err := oh.NewReader(ctx) + if err != nil { + t.Fatal(err) + } + + attrs, err := oh.Attrs(ctx) + if err != nil { + t.Fatal(err) + } + + got := rc.Attrs + want := ReaderObjectAttrs{ + Size: attrs.Size, + ContentType: attrs.ContentType, + ContentEncoding: attrs.ContentEncoding, + CacheControl: attrs.CacheControl, + LastModified: got.LastModified, // ignored, tested separately + Generation: attrs.Generation, + Metageneration: attrs.Metageneration, + } + if got != want { + t.Fatalf("got %v, wanted %v", got, want) + } + + if got.LastModified.IsZero() { + t.Fatal("LastModified is 0, should be >0") + } +} + +type testHelper struct { + t *testing.T +} + +func (h testHelper) mustCreate(b *BucketHandle, projID string, attrs *BucketAttrs) { + if err := b.Create(context.Background(), projID, attrs); err != nil { + h.t.Fatalf("%s: bucket create: %v", loc(), err) + } +} + +func (h testHelper) mustDeleteBucket(b *BucketHandle) { + if err := b.Delete(context.Background()); err != nil { + h.t.Fatalf("%s: bucket delete: %v", loc(), err) + } +} + +func (h testHelper) mustBucketAttrs(b *BucketHandle) *BucketAttrs { + attrs, err := b.Attrs(context.Background()) + if err != nil { + h.t.Fatalf("%s: bucket attrs: %v", loc(), err) + } + return attrs +} + +func (h testHelper) mustUpdateBucket(b *BucketHandle, ua BucketAttrsToUpdate) *BucketAttrs { + attrs, err := b.Update(context.Background(), ua) + if err != nil { + h.t.Fatalf("%s: update: %v", loc(), err) + } + return attrs +} + +func (h testHelper) mustObjectAttrs(o *ObjectHandle) *ObjectAttrs { + attrs, err := o.Attrs(context.Background()) + if err != nil { + h.t.Fatalf("%s: object attrs: %v", loc(), err) + } + return attrs +} + +func (h testHelper) mustDeleteObject(o *ObjectHandle) { + if err := o.Delete(context.Background()); err != nil { + h.t.Fatalf("%s: object delete: %v", loc(), err) + } +} + +func (h testHelper) mustUpdateObject(o *ObjectHandle, ua ObjectAttrsToUpdate) *ObjectAttrs { + attrs, err := o.Update(context.Background(), ua) + if err != nil { + h.t.Fatalf("%s: update: %v", loc(), err) + } + return attrs +} + +func (h testHelper) mustWrite(w *Writer, data []byte) { + if _, err := w.Write(data); err != nil { + w.Close() + h.t.Fatalf("%s: write: %v", loc(), err) + } + if err := w.Close(); err != nil { + h.t.Fatalf("%s: close write: %v", loc(), err) + } +} + +func (h testHelper) mustRead(obj *ObjectHandle) []byte { + data, err := readObject(context.Background(), obj) + if err != nil { + h.t.Fatalf("%s: read: %v", loc(), err) + } + return data +} + +func (h testHelper) mustNewReader(obj *ObjectHandle) *Reader { + r, err := obj.NewReader(context.Background()) + if err != nil { + h.t.Fatalf("%s: new reader: %v", loc(), err) + } + return r +} + +func writeObject(ctx context.Context, obj *ObjectHandle, contentType string, contents []byte) error { + w := obj.NewWriter(ctx) + w.ContentType = contentType + w.CacheControl = "public, max-age=60" + if contents != nil { + if _, err := w.Write(contents); err != nil { + _ = w.Close() + return err + } + } + return w.Close() +} + +// loc returns a string describing the file and line of its caller's call site. In +// other words, if a test function calls a helper, and the helper calls loc, then the +// string will refer to the line on which the test function called the helper. +// TODO(jba): use t.Helper once we drop go 1.6. +func loc() string { + _, file, line, ok := runtime.Caller(2) + if !ok { + return "???" + } + return fmt.Sprintf("%s:%d", filepath.Base(file), line) +} + +func readObject(ctx context.Context, obj *ObjectHandle) ([]byte, error) { + r, err := obj.NewReader(ctx) + if err != nil { + return nil, err + } + defer r.Close() + return ioutil.ReadAll(r) +} + +// cleanupBuckets deletes the bucket used for testing, as well as old +// testing buckets that weren't cleaned previously. +func cleanupBuckets() error { + if testing.Short() { + return nil // Don't clean up in short mode. + } + ctx := context.Background() + client := config(ctx) + if client == nil { + return nil // Don't cleanup if we're not configured correctly. + } + defer client.Close() + if err := killBucket(ctx, client, bucketName); err != nil { + return err + } + + // Delete buckets whose name begins with our test prefix, and which were + // created a while ago. (Unfortunately GCS doesn't provide last-modified + // time, which would be a better way to check for staleness.) + const expireAge = 24 * time.Hour + projectID := testutil.ProjID() + it := client.Buckets(ctx, projectID) + it.Prefix = testPrefix + for { + bktAttrs, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + return err + } + if time.Since(bktAttrs.Created) > expireAge { + log.Printf("deleting bucket %q, which is more than %s old", bktAttrs.Name, expireAge) + if err := killBucket(ctx, client, bktAttrs.Name); err != nil { + return err + } + } + } + return nil +} + +// killBucket deletes a bucket and all its objects. +func killBucket(ctx context.Context, client *Client, bucketName string) error { + bkt := client.Bucket(bucketName) + // Bucket must be empty to delete. + it := bkt.Objects(ctx, nil) + for { + objAttrs, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + return err + } + if err := bkt.Object(objAttrs.Name).Delete(ctx); err != nil { + return fmt.Errorf("deleting %q: %v", bucketName+"/"+objAttrs.Name, err) + } + } + // GCS is eventually consistent, so this delete may fail because the + // replica still sees an object in the bucket. We log the error and expect + // a later test run to delete the bucket. + if err := bkt.Delete(ctx); err != nil { + log.Printf("deleting %q: %v", bucketName, err) + } + return nil +} + +func randomContents() []byte { + h := md5.New() + io.WriteString(h, fmt.Sprintf("hello world%d", rng.Intn(100000))) + return h.Sum(nil) +} + +type zeros struct{} + +func (zeros) Read(p []byte) (int, error) { return len(p), nil } diff --git a/vendor/cloud.google.com/go/storage/invoke.go b/vendor/cloud.google.com/go/storage/invoke.go new file mode 100644 index 00000000..0a03f110 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/invoke.go @@ -0,0 +1,37 @@ +// Copyright 2014 Google LLC +// +// 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 storage + +import ( + "context" + + "cloud.google.com/go/internal" + gax "github.com/googleapis/gax-go" +) + +// runWithRetry calls the function until it returns nil or a non-retryable error, or +// the context is done. +func runWithRetry(ctx context.Context, call func() error) error { + return internal.Retry(ctx, gax.Backoff{}, func() (stop bool, err error) { + err = call() + if err == nil { + return true, nil + } + if shouldRetry(err) { + return false, nil + } + return true, err + }) +} diff --git a/vendor/cloud.google.com/go/storage/invoke_test.go b/vendor/cloud.google.com/go/storage/invoke_test.go new file mode 100644 index 00000000..c24e10ff --- /dev/null +++ b/vendor/cloud.google.com/go/storage/invoke_test.go @@ -0,0 +1,56 @@ +// Copyright 2014 Google LLC +// +// 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 storage + +import ( + "context" + "errors" + "testing" + + "google.golang.org/api/googleapi" +) + +func TestInvoke(t *testing.T) { + t.Parallel() + ctx := context.Background() + // Time-based tests are flaky. We just make sure that invoke eventually + // returns with the right error. + + for _, test := range []struct { + count int // number of times to return retryable error + retryCode int // error code for retryable error + err error // error to return after count returns of retryCode + }{ + {0, 0, nil}, + {0, 0, errors.New("foo")}, + {1, 429, nil}, + {1, 429, errors.New("bar")}, + {2, 518, nil}, + {2, 599, &googleapi.Error{Code: 428}}, + } { + counter := 0 + call := func() error { + counter++ + if counter <= test.count { + return &googleapi.Error{Code: test.retryCode} + } + return test.err + } + got := runWithRetry(ctx, call) + if got != test.err { + t.Errorf("%v: got %v, want %v", test, got, test.err) + } + } +} diff --git a/vendor/cloud.google.com/go/storage/mock_test.go b/vendor/cloud.google.com/go/storage/mock_test.go new file mode 100644 index 00000000..af571430 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/mock_test.go @@ -0,0 +1,81 @@ +// Copyright 2018 Google LLC +// +// 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 storage + +import ( + "context" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "strings" + "testing" + + "google.golang.org/api/option" +) + +type mockTransport struct { + gotReq *http.Request + gotBody []byte + results []transportResult +} + +type transportResult struct { + res *http.Response + err error +} + +func (t *mockTransport) addResult(res *http.Response, err error) { + t.results = append(t.results, transportResult{res, err}) +} + +func (t *mockTransport) RoundTrip(req *http.Request) (*http.Response, error) { + t.gotReq = req + t.gotBody = nil + if req.Body != nil { + bytes, err := ioutil.ReadAll(req.Body) + if err != nil { + return nil, err + } + t.gotBody = bytes + } + if len(t.results) == 0 { + return nil, fmt.Errorf("error handling request") + } + result := t.results[0] + t.results = t.results[1:] + return result.res, result.err +} + +func (t *mockTransport) gotJSONBody() map[string]interface{} { + m := map[string]interface{}{} + if err := json.Unmarshal(t.gotBody, &m); err != nil { + panic(err) + } + return m +} + +func mockClient(t *testing.T, m *mockTransport) *Client { + client, err := NewClient(context.Background(), option.WithHTTPClient(&http.Client{Transport: m})) + if err != nil { + t.Fatal(err) + } + return client +} + +func bodyReader(s string) io.ReadCloser { + return ioutil.NopCloser(strings.NewReader(s)) +} diff --git a/vendor/cloud.google.com/go/storage/not_go110.go b/vendor/cloud.google.com/go/storage/not_go110.go new file mode 100644 index 00000000..66fa45be --- /dev/null +++ b/vendor/cloud.google.com/go/storage/not_go110.go @@ -0,0 +1,42 @@ +// Copyright 2017 Google LLC +// +// 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. + +// +build !go1.10 + +package storage + +import ( + "net/url" + "strings" + + "google.golang.org/api/googleapi" +) + +func shouldRetry(err error) bool { + switch e := err.(type) { + case *googleapi.Error: + // Retry on 429 and 5xx, according to + // https://cloud.google.com/storage/docs/exponential-backoff. + return e.Code == 429 || (e.Code >= 500 && e.Code < 600) + case *url.Error: + // Retry on REFUSED_STREAM. + // Unfortunately the error type is unexported, so we resort to string + // matching. + return strings.Contains(e.Error(), "REFUSED_STREAM") + case interface{ Temporary() bool }: + return e.Temporary() + default: + return false + } +} diff --git a/vendor/cloud.google.com/go/storage/notifications.go b/vendor/cloud.google.com/go/storage/notifications.go new file mode 100644 index 00000000..84619b6d --- /dev/null +++ b/vendor/cloud.google.com/go/storage/notifications.go @@ -0,0 +1,188 @@ +// Copyright 2017 Google LLC +// +// 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 storage + +import ( + "context" + "errors" + "fmt" + "regexp" + + "cloud.google.com/go/internal/trace" + raw "google.golang.org/api/storage/v1" +) + +// A Notification describes how to send Cloud PubSub messages when certain +// events occur in a bucket. +type Notification struct { + //The ID of the notification. + ID string + + // The ID of the topic to which this subscription publishes. + TopicID string + + // The ID of the project to which the topic belongs. + TopicProjectID string + + // Only send notifications about listed event types. If empty, send notifications + // for all event types. + // See https://cloud.google.com/storage/docs/pubsub-notifications#events. + EventTypes []string + + // If present, only apply this notification configuration to object names that + // begin with this prefix. + ObjectNamePrefix string + + // An optional list of additional attributes to attach to each Cloud PubSub + // message published for this notification subscription. + CustomAttributes map[string]string + + // The contents of the message payload. + // See https://cloud.google.com/storage/docs/pubsub-notifications#payload. + PayloadFormat string +} + +// Values for Notification.PayloadFormat. +const ( + // Send no payload with notification messages. + NoPayload = "NONE" + + // Send object metadata as JSON with notification messages. + JSONPayload = "JSON_API_V1" +) + +// Values for Notification.EventTypes. +const ( + // Event that occurs when an object is successfully created. + ObjectFinalizeEvent = "OBJECT_FINALIZE" + + // Event that occurs when the metadata of an existing object changes. + ObjectMetadataUpdateEvent = "OBJECT_METADATA_UPDATE" + + // Event that occurs when an object is permanently deleted. + ObjectDeleteEvent = "OBJECT_DELETE" + + // Event that occurs when the live version of an object becomes an + // archived version. + ObjectArchiveEvent = "OBJECT_ARCHIVE" +) + +func toNotification(rn *raw.Notification) *Notification { + n := &Notification{ + ID: rn.Id, + EventTypes: rn.EventTypes, + ObjectNamePrefix: rn.ObjectNamePrefix, + CustomAttributes: rn.CustomAttributes, + PayloadFormat: rn.PayloadFormat, + } + n.TopicProjectID, n.TopicID = parseNotificationTopic(rn.Topic) + return n +} + +var topicRE = regexp.MustCompile("^//pubsub.googleapis.com/projects/([^/]+)/topics/([^/]+)") + +// parseNotificationTopic extracts the project and topic IDs from from the full +// resource name returned by the service. If the name is malformed, it returns +// "?" for both IDs. +func parseNotificationTopic(nt string) (projectID, topicID string) { + matches := topicRE.FindStringSubmatch(nt) + if matches == nil { + return "?", "?" + } + return matches[1], matches[2] +} + +func toRawNotification(n *Notification) *raw.Notification { + return &raw.Notification{ + Id: n.ID, + Topic: fmt.Sprintf("//pubsub.googleapis.com/projects/%s/topics/%s", + n.TopicProjectID, n.TopicID), + EventTypes: n.EventTypes, + ObjectNamePrefix: n.ObjectNamePrefix, + CustomAttributes: n.CustomAttributes, + PayloadFormat: string(n.PayloadFormat), + } +} + +// AddNotification adds a notification to b. You must set n's TopicProjectID, TopicID +// and PayloadFormat, and must not set its ID. The other fields are all optional. The +// returned Notification's ID can be used to refer to it. +func (b *BucketHandle) AddNotification(ctx context.Context, n *Notification) (ret *Notification, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.AddNotification") + defer func() { trace.EndSpan(ctx, err) }() + + if n.ID != "" { + return nil, errors.New("storage: AddNotification: ID must not be set") + } + if n.TopicProjectID == "" { + return nil, errors.New("storage: AddNotification: missing TopicProjectID") + } + if n.TopicID == "" { + return nil, errors.New("storage: AddNotification: missing TopicID") + } + call := b.c.raw.Notifications.Insert(b.name, toRawNotification(n)) + setClientHeader(call.Header()) + if b.userProject != "" { + call.UserProject(b.userProject) + } + rn, err := call.Context(ctx).Do() + if err != nil { + return nil, err + } + return toNotification(rn), nil +} + +// Notifications returns all the Notifications configured for this bucket, as a map +// indexed by notification ID. +func (b *BucketHandle) Notifications(ctx context.Context) (n map[string]*Notification, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Notifications") + defer func() { trace.EndSpan(ctx, err) }() + + call := b.c.raw.Notifications.List(b.name) + setClientHeader(call.Header()) + if b.userProject != "" { + call.UserProject(b.userProject) + } + var res *raw.Notifications + err = runWithRetry(ctx, func() error { + res, err = call.Context(ctx).Do() + return err + }) + if err != nil { + return nil, err + } + return notificationsToMap(res.Items), nil +} + +func notificationsToMap(rns []*raw.Notification) map[string]*Notification { + m := map[string]*Notification{} + for _, rn := range rns { + m[rn.Id] = toNotification(rn) + } + return m +} + +// DeleteNotification deletes the notification with the given ID. +func (b *BucketHandle) DeleteNotification(ctx context.Context, id string) (err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.DeleteNotification") + defer func() { trace.EndSpan(ctx, err) }() + + call := b.c.raw.Notifications.Delete(b.name, id) + setClientHeader(call.Header()) + if b.userProject != "" { + call.UserProject(b.userProject) + } + return call.Context(ctx).Do() +} diff --git a/vendor/cloud.google.com/go/storage/notifications_test.go b/vendor/cloud.google.com/go/storage/notifications_test.go new file mode 100644 index 00000000..e96ff4fd --- /dev/null +++ b/vendor/cloud.google.com/go/storage/notifications_test.go @@ -0,0 +1,98 @@ +// Copyright 2017 Google LLC +// +// 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 storage + +import ( + "context" + "testing" + + "cloud.google.com/go/internal/testutil" + raw "google.golang.org/api/storage/v1" +) + +func TestParseNotificationTopic(t *testing.T) { + for _, test := range []struct { + in string + wantProjectID string + wantTopicID string + }{ + {"", "?", "?"}, + {"foobar", "?", "?"}, + {"//pubsub.googleapis.com/projects/foo", "?", "?"}, + {"//pubsub.googleapis.com/projects/my-project/topics/my-topic", + "my-project", "my-topic"}, + } { + gotProjectID, gotTopicID := parseNotificationTopic(test.in) + if gotProjectID != test.wantProjectID || gotTopicID != test.wantTopicID { + t.Errorf("%q: got (%q, %q), want (%q, %q)", + test.in, gotProjectID, gotTopicID, test.wantProjectID, test.wantTopicID) + } + } + +} + +func TestConvertNotification(t *testing.T) { + want := &Notification{ + ID: "id", + TopicProjectID: "my-project", + TopicID: "my-topic", + EventTypes: []string{ObjectFinalizeEvent}, + ObjectNamePrefix: "prefix", + CustomAttributes: map[string]string{"a": "b"}, + PayloadFormat: JSONPayload, + } + got := toNotification(toRawNotification(want)) + if diff := testutil.Diff(got, want); diff != "" { + t.Errorf("got=-, want=+:\n%s", diff) + } +} + +func TestNotificationsToMap(t *testing.T) { + got := notificationsToMap(nil) + want := map[string]*Notification{} + if !testutil.Equal(got, want) { + t.Errorf("got %+v, want %+v", got, want) + } + + in := []*raw.Notification{ + {Id: "a", Topic: "//pubsub.googleapis.com/projects/P1/topics/T1"}, + {Id: "b", Topic: "//pubsub.googleapis.com/projects/P2/topics/T2"}, + {Id: "c", Topic: "//pubsub.googleapis.com/projects/P3/topics/T3"}, + } + got = notificationsToMap(in) + want = map[string]*Notification{ + "a": {ID: "a", TopicProjectID: "P1", TopicID: "T1"}, + "b": {ID: "b", TopicProjectID: "P2", TopicID: "T2"}, + "c": {ID: "c", TopicProjectID: "P3", TopicID: "T3"}, + } + if diff := testutil.Diff(got, want); diff != "" { + t.Errorf("got=-, want=+:\n%s", diff) + } +} + +func TestAddNotificationsErrors(t *testing.T) { + c := &Client{} + b := c.Bucket("b") + for _, n := range []*Notification{ + {ID: "foo", TopicProjectID: "p", TopicID: "t"}, // has ID + {TopicProjectID: "p"}, // missing TopicID + {TopicID: "t"}, // missing TopicProjectID + } { + _, err := b.AddNotification(context.Background(), n) + if err == nil { + t.Errorf("%+v: got nil, want error", n) + } + } +} diff --git a/vendor/cloud.google.com/go/storage/oc_test.go b/vendor/cloud.google.com/go/storage/oc_test.go new file mode 100644 index 00000000..21433969 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/oc_test.go @@ -0,0 +1,38 @@ +// Copyright 2018 Google LLC +// +// 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 storage + +import ( + "context" + "testing" + + "cloud.google.com/go/internal/testutil" +) + +func TestIntegration_OCTracing(t *testing.T) { + ctx := context.Background() + client := testConfig(ctx, t) + defer client.Close() + + te := testutil.NewTestExporter() + defer te.Unregister() + + bkt := client.Bucket(bucketName) + bkt.Attrs(ctx) + + if len(te.Spans) == 0 { + t.Fatalf("Expected some spans to be created, but got %d", 0) + } +} diff --git a/vendor/cloud.google.com/go/storage/reader.go b/vendor/cloud.google.com/go/storage/reader.go new file mode 100644 index 00000000..50f381f9 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/reader.go @@ -0,0 +1,385 @@ +// Copyright 2016 Google LLC +// +// 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 storage + +import ( + "context" + "errors" + "fmt" + "hash/crc32" + "io" + "io/ioutil" + "net/http" + "net/url" + "reflect" + "strconv" + "strings" + "time" + + "cloud.google.com/go/internal/trace" + "google.golang.org/api/googleapi" +) + +var crc32cTable = crc32.MakeTable(crc32.Castagnoli) + +// ReaderObjectAttrs are attributes about the object being read. These are populated +// during the New call. This struct only holds a subset of object attributes: to +// get the full set of attributes, use ObjectHandle.Attrs. +// +// Each field is read-only. +type ReaderObjectAttrs struct { + // Size is the length of the object's content. + Size int64 + + // ContentType is the MIME type of the object's content. + ContentType string + + // ContentEncoding is the encoding of the object's content. + ContentEncoding string + + // CacheControl specifies whether and for how long browser and Internet + // caches are allowed to cache your objects. + CacheControl string + + // LastModified is the time that the object was last modified. + LastModified time.Time + + // Generation is the generation number of the object's content. + Generation int64 + + // Metageneration is the version of the metadata for this object at + // this generation. This field is used for preconditions and for + // detecting changes in metadata. A metageneration number is only + // meaningful in the context of a particular generation of a + // particular object. + Metageneration int64 +} + +// NewReader creates a new Reader to read the contents of the +// object. +// ErrObjectNotExist will be returned if the object is not found. +// +// The caller must call Close on the returned Reader when done reading. +func (o *ObjectHandle) NewReader(ctx context.Context) (*Reader, error) { + return o.NewRangeReader(ctx, 0, -1) +} + +// NewRangeReader reads part of an object, reading at most length bytes +// starting at the given offset. If length is negative, the object is read +// until the end. +func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) (r *Reader, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.NewRangeReader") + defer func() { trace.EndSpan(ctx, err) }() + + if err := o.validate(); err != nil { + return nil, err + } + if offset < 0 { + return nil, fmt.Errorf("storage: invalid offset %d < 0", offset) + } + if o.conds != nil { + if err := o.conds.validate("NewRangeReader"); err != nil { + return nil, err + } + } + u := &url.URL{ + Scheme: "https", + Host: "storage.googleapis.com", + Path: fmt.Sprintf("/%s/%s", o.bucket, o.object), + } + verb := "GET" + if length == 0 { + verb = "HEAD" + } + req, err := http.NewRequest(verb, u.String(), nil) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if o.userProject != "" { + req.Header.Set("X-Goog-User-Project", o.userProject) + } + if o.readCompressed { + req.Header.Set("Accept-Encoding", "gzip") + } + if err := setEncryptionHeaders(req.Header, o.encryptionKey, false); err != nil { + return nil, err + } + + gen := o.gen + + // Define a function that initiates a Read with offset and length, assuming we + // have already read seen bytes. + reopen := func(seen int64) (*http.Response, error) { + start := offset + seen + if length < 0 && start > 0 { + req.Header.Set("Range", fmt.Sprintf("bytes=%d-", start)) + } else if length > 0 { + // The end character isn't affected by how many bytes we've seen. + req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, offset+length-1)) + } + // We wait to assign conditions here because the generation number can change in between reopen() runs. + req.URL.RawQuery = conditionsQuery(gen, o.conds) + var res *http.Response + err = runWithRetry(ctx, func() error { + res, err = o.c.hc.Do(req) + if err != nil { + return err + } + if res.StatusCode == http.StatusNotFound { + res.Body.Close() + return ErrObjectNotExist + } + if res.StatusCode < 200 || res.StatusCode > 299 { + body, _ := ioutil.ReadAll(res.Body) + res.Body.Close() + return &googleapi.Error{ + Code: res.StatusCode, + Header: res.Header, + Body: string(body), + } + } + if start > 0 && length != 0 && res.StatusCode != http.StatusPartialContent { + res.Body.Close() + return errors.New("storage: partial request not satisfied") + } + // If a generation hasn't been specified, and this is the first response we get, let's record the + // generation. In future requests we'll use this generation as a precondition to avoid data races. + if gen < 0 && res.Header.Get("X-Goog-Generation") != "" { + gen64, err := strconv.ParseInt(res.Header.Get("X-Goog-Generation"), 10, 64) + if err != nil { + return err + } + gen = gen64 + } + return nil + }) + if err != nil { + return nil, err + } + return res, nil + } + + res, err := reopen(0) + if err != nil { + return nil, err + } + var ( + size int64 // total size of object, even if a range was requested. + checkCRC bool + crc uint32 + ) + if res.StatusCode == http.StatusPartialContent { + cr := strings.TrimSpace(res.Header.Get("Content-Range")) + if !strings.HasPrefix(cr, "bytes ") || !strings.Contains(cr, "/") { + + return nil, fmt.Errorf("storage: invalid Content-Range %q", cr) + } + size, err = strconv.ParseInt(cr[strings.LastIndex(cr, "/")+1:], 10, 64) + if err != nil { + return nil, fmt.Errorf("storage: invalid Content-Range %q", cr) + } + } else { + size = res.ContentLength + // Check the CRC iff all of the following hold: + // - We asked for content (length != 0). + // - We got all the content (status != PartialContent). + // - The server sent a CRC header. + // - The Go http stack did not uncompress the file. + // - We were not served compressed data that was uncompressed on download. + // The problem with the last two cases is that the CRC will not match -- GCS + // computes it on the compressed contents, but we compute it on the + // uncompressed contents. + if length != 0 && !res.Uncompressed && !uncompressedByServer(res) { + crc, checkCRC = parseCRC32c(res) + } + } + + remain := res.ContentLength + body := res.Body + if length == 0 { + remain = 0 + body.Close() + body = emptyBody + } + var metaGen int64 + if res.Header.Get("X-Goog-Generation") != "" { + metaGen, err = strconv.ParseInt(res.Header.Get("X-Goog-Metageneration"), 10, 64) + if err != nil { + return nil, err + } + } + + var lm time.Time + if res.Header.Get("Last-Modified") != "" { + lm, err = http.ParseTime(res.Header.Get("Last-Modified")) + if err != nil { + return nil, err + } + } + + attrs := ReaderObjectAttrs{ + Size: size, + ContentType: res.Header.Get("Content-Type"), + ContentEncoding: res.Header.Get("Content-Encoding"), + CacheControl: res.Header.Get("Cache-Control"), + LastModified: lm, + Generation: gen, + Metageneration: metaGen, + } + return &Reader{ + Attrs: attrs, + body: body, + size: size, + remain: remain, + wantCRC: crc, + checkCRC: checkCRC, + reopen: reopen, + }, nil +} + +func uncompressedByServer(res *http.Response) bool { + // If the data is stored as gzip but is not encoded as gzip, then it + // was uncompressed by the server. + return res.Header.Get("X-Goog-Stored-Content-Encoding") == "gzip" && + res.Header.Get("Content-Encoding") != "gzip" +} + +func parseCRC32c(res *http.Response) (uint32, bool) { + const prefix = "crc32c=" + for _, spec := range res.Header["X-Goog-Hash"] { + if strings.HasPrefix(spec, prefix) { + c, err := decodeUint32(spec[len(prefix):]) + if err == nil { + return c, true + } + } + } + return 0, false +} + +var emptyBody = ioutil.NopCloser(strings.NewReader("")) + +// Reader reads a Cloud Storage object. +// It implements io.Reader. +// +// Typically, a Reader computes the CRC of the downloaded content and compares it to +// the stored CRC, returning an error from Read if there is a mismatch. This integrity check +// is skipped if transcoding occurs. See https://cloud.google.com/storage/docs/transcoding. +type Reader struct { + Attrs ReaderObjectAttrs + body io.ReadCloser + seen, remain, size int64 + checkCRC bool // should we check the CRC? + wantCRC uint32 // the CRC32c value the server sent in the header + gotCRC uint32 // running crc + reopen func(seen int64) (*http.Response, error) +} + +// Close closes the Reader. It must be called when done reading. +func (r *Reader) Close() error { + return r.body.Close() +} + +func (r *Reader) Read(p []byte) (int, error) { + n, err := r.readWithRetry(p) + if r.remain != -1 { + r.remain -= int64(n) + } + if r.checkCRC { + r.gotCRC = crc32.Update(r.gotCRC, crc32cTable, p[:n]) + // Check CRC here. It would be natural to check it in Close, but + // everybody defers Close on the assumption that it doesn't return + // anything worth looking at. + if err == io.EOF { + if r.gotCRC != r.wantCRC { + return n, fmt.Errorf("storage: bad CRC on read: got %d, want %d", + r.gotCRC, r.wantCRC) + } + } + } + return n, err +} + +func (r *Reader) readWithRetry(p []byte) (int, error) { + n := 0 + for len(p[n:]) > 0 { + m, err := r.body.Read(p[n:]) + n += m + r.seen += int64(m) + if !shouldRetryRead(err) { + return n, err + } + // Read failed, but we will try again. Send a ranged read request that takes + // into account the number of bytes we've already seen. + res, err := r.reopen(r.seen) + if err != nil { + // reopen already retries + return n, err + } + r.body.Close() + r.body = res.Body + } + return n, nil +} + +func shouldRetryRead(err error) bool { + if err == nil { + return false + } + return strings.HasSuffix(err.Error(), "INTERNAL_ERROR") && strings.Contains(reflect.TypeOf(err).String(), "http2") +} + +// Size returns the size of the object in bytes. +// The returned value is always the same and is not affected by +// calls to Read or Close. +// +// Deprecated: use Reader.Attrs.Size. +func (r *Reader) Size() int64 { + return r.Attrs.Size +} + +// Remain returns the number of bytes left to read, or -1 if unknown. +func (r *Reader) Remain() int64 { + return r.remain +} + +// ContentType returns the content type of the object. +// +// Deprecated: use Reader.Attrs.ContentType. +func (r *Reader) ContentType() string { + return r.Attrs.ContentType +} + +// ContentEncoding returns the content encoding of the object. +// +// Deprecated: use Reader.Attrs.ContentEncoding. +func (r *Reader) ContentEncoding() string { + return r.Attrs.ContentEncoding +} + +// CacheControl returns the cache control of the object. +// +// Deprecated: use Reader.Attrs.CacheControl. +func (r *Reader) CacheControl() string { + return r.Attrs.CacheControl +} + +// LastModified returns the value of the Last-Modified header. +// +// Deprecated: use Reader.Attrs.LastModified. +func (r *Reader) LastModified() (time.Time, error) { + return r.Attrs.LastModified, nil +} diff --git a/vendor/cloud.google.com/go/storage/reader_test.go b/vendor/cloud.google.com/go/storage/reader_test.go new file mode 100644 index 00000000..47dbf014 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/reader_test.go @@ -0,0 +1,297 @@ +// Copyright 2018 Google LLC +// +// 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 storage + +import ( + "context" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "strconv" + "strings" + "testing" + + "google.golang.org/api/option" +) + +const readData = "0123456789" + +func TestRangeReader(t *testing.T) { + hc, close := newTestServer(handleRangeRead) + defer close() + ctx := context.Background() + c, err := NewClient(ctx, option.WithHTTPClient(hc)) + if err != nil { + t.Fatal(err) + } + obj := c.Bucket("b").Object("o") + for _, test := range []struct { + offset, length int64 + want string + }{ + {0, -1, readData}, + {0, 10, readData}, + {0, 5, readData[:5]}, + {1, 3, readData[1:4]}, + {6, -1, readData[6:]}, + {4, 20, readData[4:]}, + } { + r, err := obj.NewRangeReader(ctx, test.offset, test.length) + if err != nil { + t.Errorf("%d/%d: %v", test.offset, test.length, err) + continue + } + gotb, err := ioutil.ReadAll(r) + if err != nil { + t.Errorf("%d/%d: %v", test.offset, test.length, err) + continue + } + if got := string(gotb); got != test.want { + t.Errorf("%d/%d: got %q, want %q", test.offset, test.length, got, test.want) + } + } +} + +func handleRangeRead(w http.ResponseWriter, r *http.Request) { + rh := strings.TrimSpace(r.Header.Get("Range")) + data := readData + var from, to int + if rh == "" { + from = 0 + to = len(data) + } else { + // assume "bytes=N-" or "bytes=N-M" + var err error + i := strings.IndexRune(rh, '=') + j := strings.IndexRune(rh, '-') + from, err = strconv.Atoi(rh[i+1 : j]) + if err != nil { + w.WriteHeader(500) + return + } + to = len(data) + if j+1 < len(rh) { + to, err = strconv.Atoi(rh[j+1:]) + if err != nil { + w.WriteHeader(500) + return + } + to++ // Range header is inclusive, Go slice is exclusive + } + if from >= len(data) && to != from { + w.WriteHeader(416) + return + } + if from > len(data) { + from = len(data) + } + if to > len(data) { + to = len(data) + } + } + data = data[from:to] + if data != readData { + w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", from, to-1, len(readData))) + w.WriteHeader(http.StatusPartialContent) + } + if _, err := w.Write([]byte(data)); err != nil { + panic(err) + } +} + +type http2Error string + +func (h http2Error) Error() string { + return string(h) +} + +func TestRangeReaderRetry(t *testing.T) { + retryErr := http2Error("blah blah INTERNAL_ERROR") + readBytes := []byte(readData) + hc, close := newTestServer(handleRangeRead) + defer close() + ctx := context.Background() + c, err := NewClient(ctx, option.WithHTTPClient(hc)) + if err != nil { + t.Fatal(err) + } + + obj := c.Bucket("b").Object("o") + for i, test := range []struct { + offset, length int64 + bodies []fakeReadCloser + want string + }{ + { + offset: 0, + length: -1, + bodies: []fakeReadCloser{ + {data: readBytes, counts: []int{10}, err: io.EOF}, + }, + want: readData, + }, + { + offset: 0, + length: -1, + bodies: []fakeReadCloser{ + {data: readBytes, counts: []int{3}, err: retryErr}, + {data: readBytes[3:], counts: []int{5, 2}, err: io.EOF}, + }, + want: readData, + }, + { + offset: 0, + length: -1, + bodies: []fakeReadCloser{ + {data: readBytes, counts: []int{5}, err: retryErr}, + {data: readBytes[5:], counts: []int{1, 3}, err: retryErr}, + {data: readBytes[9:], counts: []int{1}, err: io.EOF}, + }, + want: readData, + }, + { + offset: 0, + length: 5, + bodies: []fakeReadCloser{ + {data: readBytes, counts: []int{3}, err: retryErr}, + {data: readBytes[3:], counts: []int{2}, err: io.EOF}, + }, + want: readData[:5], + }, + { + offset: 1, + length: 5, + bodies: []fakeReadCloser{ + {data: readBytes, counts: []int{3}, err: retryErr}, + {data: readBytes[3:], counts: []int{2}, err: io.EOF}, + }, + want: readData[:5], + }, + { + offset: 1, + length: 3, + bodies: []fakeReadCloser{ + {data: readBytes[1:], counts: []int{1}, err: retryErr}, + {data: readBytes[2:], counts: []int{2}, err: io.EOF}, + }, + want: readData[1:4], + }, + { + offset: 4, + length: -1, + bodies: []fakeReadCloser{ + {data: readBytes[4:], counts: []int{1}, err: retryErr}, + {data: readBytes[5:], counts: []int{4}, err: retryErr}, + {data: readBytes[9:], counts: []int{1}, err: io.EOF}, + }, + want: readData[4:], + }, + } { + r, err := obj.NewRangeReader(ctx, test.offset, test.length) + if err != nil { + t.Errorf("#%d: %v", i, err) + continue + } + r.body = &test.bodies[0] + b := 0 + r.reopen = func(int64) (*http.Response, error) { + b++ + return &http.Response{Body: &test.bodies[b]}, nil + } + buf := make([]byte, len(readData)/2) + var gotb []byte + for { + n, err := r.Read(buf) + gotb = append(gotb, buf[:n]...) + if err == io.EOF { + break + } + if err != nil { + t.Fatalf("#%d: %v", i, err) + } + } + if err != nil { + t.Errorf("#%d: %v", i, err) + continue + } + if got := string(gotb); got != test.want { + t.Errorf("#%d: got %q, want %q", i, got, test.want) + } + } +} + +type fakeReadCloser struct { + data []byte + counts []int // how much of data to deliver on each read + err error // error to return with last count + + d int // current position in data + c int // current position in counts +} + +func (f *fakeReadCloser) Close() error { + return nil +} + +func (f *fakeReadCloser) Read(buf []byte) (int, error) { + i := f.c + n := 0 + if i < len(f.counts) { + n = f.counts[i] + } + var err error + if i >= len(f.counts)-1 { + err = f.err + } + copy(buf, f.data[f.d:f.d+n]) + if len(buf) < n { + n = len(buf) + f.counts[i] -= n + err = nil + } else { + f.c++ + } + f.d += n + return n, err +} + +func TestFakeReadCloser(t *testing.T) { + e := errors.New("") + f := &fakeReadCloser{ + data: []byte(readData), + counts: []int{1, 2, 3}, + err: e, + } + wants := []string{"0", "12", "345"} + buf := make([]byte, 10) + for i := 0; i < 3; i++ { + n, err := f.Read(buf) + if got, want := n, f.counts[i]; got != want { + t.Fatalf("i=%d: got %d, want %d", i, got, want) + } + var wantErr error + if i == 2 { + wantErr = e + } + if err != wantErr { + t.Fatalf("i=%d: got error %v, want %v", i, err, wantErr) + } + if got, want := string(buf[:n]), wants[i]; got != want { + t.Fatalf("i=%d: got %q, want %q", i, got, want) + } + } +} diff --git a/vendor/cloud.google.com/go/storage/storage.go b/vendor/cloud.google.com/go/storage/storage.go new file mode 100644 index 00000000..6c62e3e1 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/storage.go @@ -0,0 +1,1123 @@ +// Copyright 2014 Google LLC +// +// 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 storage + +import ( + "bytes" + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "reflect" + "regexp" + "sort" + "strconv" + "strings" + "time" + "unicode/utf8" + + "cloud.google.com/go/internal/optional" + "cloud.google.com/go/internal/trace" + "cloud.google.com/go/internal/version" + "google.golang.org/api/googleapi" + "google.golang.org/api/option" + raw "google.golang.org/api/storage/v1" + htransport "google.golang.org/api/transport/http" +) + +var ( + // ErrBucketNotExist indicates that the bucket does not exist. + ErrBucketNotExist = errors.New("storage: bucket doesn't exist") + // ErrObjectNotExist indicates that the object does not exist. + ErrObjectNotExist = errors.New("storage: object doesn't exist") +) + +const userAgent = "gcloud-golang-storage/20151204" + +const ( + // ScopeFullControl grants permissions to manage your + // data and permissions in Google Cloud Storage. + ScopeFullControl = raw.DevstorageFullControlScope + + // ScopeReadOnly grants permissions to + // view your data in Google Cloud Storage. + ScopeReadOnly = raw.DevstorageReadOnlyScope + + // ScopeReadWrite grants permissions to manage your + // data in Google Cloud Storage. + ScopeReadWrite = raw.DevstorageReadWriteScope +) + +var xGoogHeader = fmt.Sprintf("gl-go/%s gccl/%s", version.Go(), version.Repo) + +func setClientHeader(headers http.Header) { + headers.Set("x-goog-api-client", xGoogHeader) +} + +// Client is a client for interacting with Google Cloud Storage. +// +// Clients should be reused instead of created as needed. +// The methods of Client are safe for concurrent use by multiple goroutines. +type Client struct { + hc *http.Client + raw *raw.Service +} + +// NewClient creates a new Google Cloud Storage client. +// The default scope is ScopeFullControl. To use a different scope, like ScopeReadOnly, use option.WithScopes. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + o := []option.ClientOption{ + option.WithScopes(ScopeFullControl), + option.WithUserAgent(userAgent), + } + opts = append(o, opts...) + hc, ep, err := htransport.NewClient(ctx, opts...) + if err != nil { + return nil, fmt.Errorf("dialing: %v", err) + } + rawService, err := raw.New(hc) + if err != nil { + return nil, fmt.Errorf("storage client: %v", err) + } + if ep != "" { + rawService.BasePath = ep + } + return &Client{ + hc: hc, + raw: rawService, + }, nil +} + +// Close closes the Client. +// +// Close need not be called at program exit. +func (c *Client) Close() error { + // Set fields to nil so that subsequent uses will panic. + c.hc = nil + c.raw = nil + return nil +} + +// SignedURLOptions allows you to restrict the access to the signed URL. +type SignedURLOptions struct { + // GoogleAccessID represents the authorizer of the signed URL generation. + // It is typically the Google service account client email address from + // the Google Developers Console in the form of "xxx@developer.gserviceaccount.com". + // Required. + GoogleAccessID string + + // PrivateKey is the Google service account private key. It is obtainable + // from the Google Developers Console. + // At https://console.developers.google.com/project//apiui/credential, + // create a service account client ID or reuse one of your existing service account + // credentials. Click on the "Generate new P12 key" to generate and download + // a new private key. Once you download the P12 file, use the following command + // to convert it into a PEM file. + // + // $ openssl pkcs12 -in key.p12 -passin pass:notasecret -out key.pem -nodes + // + // Provide the contents of the PEM file as a byte slice. + // Exactly one of PrivateKey or SignBytes must be non-nil. + PrivateKey []byte + + // SignBytes is a function for implementing custom signing. + // If your application is running on Google App Engine, you can use appengine's internal signing function: + // ctx := appengine.NewContext(request) + // acc, _ := appengine.ServiceAccount(ctx) + // url, err := SignedURL("bucket", "object", &SignedURLOptions{ + // GoogleAccessID: acc, + // SignBytes: func(b []byte) ([]byte, error) { + // _, signedBytes, err := appengine.SignBytes(ctx, b) + // return signedBytes, err + // }, + // // etc. + // }) + // + // Exactly one of PrivateKey or SignBytes must be non-nil. + SignBytes func([]byte) ([]byte, error) + + // Method is the HTTP method to be used with the signed URL. + // Signed URLs can be used with GET, HEAD, PUT, and DELETE requests. + // Required. + Method string + + // Expires is the expiration time on the signed URL. It must be + // a datetime in the future. + // Required. + Expires time.Time + + // ContentType is the content type header the client must provide + // to use the generated signed URL. + // Optional. + ContentType string + + // Headers is a list of extension headers the client must provide + // in order to use the generated signed URL. + // Optional. + Headers []string + + // MD5 is the base64 encoded MD5 checksum of the file. + // If provided, the client should provide the exact value on the request + // header in order to use the signed URL. + // Optional. + MD5 string +} + +var ( + canonicalHeaderRegexp = regexp.MustCompile(`(?i)^(x-goog-[^:]+):(.*)?$`) + excludedCanonicalHeaders = map[string]bool{ + "x-goog-encryption-key": true, + "x-goog-encryption-key-sha256": true, + } +) + +// sanitizeHeaders applies the specifications for canonical extension headers at +// https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers. +func sanitizeHeaders(hdrs []string) []string { + headerMap := map[string][]string{} + for _, hdr := range hdrs { + // No leading or trailing whitespaces. + sanitizedHeader := strings.TrimSpace(hdr) + + // Only keep canonical headers, discard any others. + headerMatches := canonicalHeaderRegexp.FindStringSubmatch(sanitizedHeader) + if len(headerMatches) == 0 { + continue + } + + header := strings.ToLower(strings.TrimSpace(headerMatches[1])) + if excludedCanonicalHeaders[headerMatches[1]] { + // Do not keep any deliberately excluded canonical headers when signing. + continue + } + value := strings.TrimSpace(headerMatches[2]) + if len(value) > 0 { + // Remove duplicate headers by appending the values of duplicates + // in their order of appearance. + headerMap[header] = append(headerMap[header], value) + } + } + + var sanitizedHeaders []string + for header, values := range headerMap { + // There should be no spaces around the colon separating the + // header name from the header value or around the values + // themselves. The values should be separated by commas. + // NOTE: The semantics for headers without a value are not clear. + // However from specifications these should be edge-cases + // anyway and we should assume that there will be no + // canonical headers using empty values. Any such headers + // are discarded at the regexp stage above. + sanitizedHeaders = append( + sanitizedHeaders, + fmt.Sprintf("%s:%s", header, strings.Join(values, ",")), + ) + } + sort.Strings(sanitizedHeaders) + return sanitizedHeaders +} + +// SignedURL returns a URL for the specified object. Signed URLs allow +// the users access to a restricted resource for a limited time without having a +// Google account or signing in. For more information about the signed +// URLs, see https://cloud.google.com/storage/docs/accesscontrol#Signed-URLs. +func SignedURL(bucket, name string, opts *SignedURLOptions) (string, error) { + if opts == nil { + return "", errors.New("storage: missing required SignedURLOptions") + } + if opts.GoogleAccessID == "" { + return "", errors.New("storage: missing required GoogleAccessID") + } + if (opts.PrivateKey == nil) == (opts.SignBytes == nil) { + return "", errors.New("storage: exactly one of PrivateKey or SignedBytes must be set") + } + if opts.Method == "" { + return "", errors.New("storage: missing required method option") + } + if opts.Expires.IsZero() { + return "", errors.New("storage: missing required expires option") + } + if opts.MD5 != "" { + md5, err := base64.StdEncoding.DecodeString(opts.MD5) + if err != nil || len(md5) != 16 { + return "", errors.New("storage: invalid MD5 checksum") + } + } + opts.Headers = sanitizeHeaders(opts.Headers) + + signBytes := opts.SignBytes + if opts.PrivateKey != nil { + key, err := parseKey(opts.PrivateKey) + if err != nil { + return "", err + } + signBytes = func(b []byte) ([]byte, error) { + sum := sha256.Sum256(b) + return rsa.SignPKCS1v15( + rand.Reader, + key, + crypto.SHA256, + sum[:], + ) + } + } + + u := &url.URL{ + Path: fmt.Sprintf("/%s/%s", bucket, name), + } + + buf := &bytes.Buffer{} + fmt.Fprintf(buf, "%s\n", opts.Method) + fmt.Fprintf(buf, "%s\n", opts.MD5) + fmt.Fprintf(buf, "%s\n", opts.ContentType) + fmt.Fprintf(buf, "%d\n", opts.Expires.Unix()) + if len(opts.Headers) > 0 { + fmt.Fprintf(buf, "%s\n", strings.Join(opts.Headers, "\n")) + } + fmt.Fprintf(buf, "%s", u.String()) + + b, err := signBytes(buf.Bytes()) + if err != nil { + return "", err + } + encoded := base64.StdEncoding.EncodeToString(b) + u.Scheme = "https" + u.Host = "storage.googleapis.com" + q := u.Query() + q.Set("GoogleAccessId", opts.GoogleAccessID) + q.Set("Expires", fmt.Sprintf("%d", opts.Expires.Unix())) + q.Set("Signature", string(encoded)) + u.RawQuery = q.Encode() + return u.String(), nil +} + +// ObjectHandle provides operations on an object in a Google Cloud Storage bucket. +// Use BucketHandle.Object to get a handle. +type ObjectHandle struct { + c *Client + bucket string + object string + acl ACLHandle + gen int64 // a negative value indicates latest + conds *Conditions + encryptionKey []byte // AES-256 key + userProject string // for requester-pays buckets + readCompressed bool // Accept-Encoding: gzip +} + +// ACL provides access to the object's access control list. +// This controls who can read and write this object. +// This call does not perform any network operations. +func (o *ObjectHandle) ACL() *ACLHandle { + return &o.acl +} + +// Generation returns a new ObjectHandle that operates on a specific generation +// of the object. +// By default, the handle operates on the latest generation. Not +// all operations work when given a specific generation; check the API +// endpoints at https://cloud.google.com/storage/docs/json_api/ for details. +func (o *ObjectHandle) Generation(gen int64) *ObjectHandle { + o2 := *o + o2.gen = gen + return &o2 +} + +// If returns a new ObjectHandle that applies a set of preconditions. +// Preconditions already set on the ObjectHandle are ignored. +// Operations on the new handle will return an error if the preconditions are not +// satisfied. See https://cloud.google.com/storage/docs/generations-preconditions +// for more details. +func (o *ObjectHandle) If(conds Conditions) *ObjectHandle { + o2 := *o + o2.conds = &conds + return &o2 +} + +// Key returns a new ObjectHandle that uses the supplied encryption +// key to encrypt and decrypt the object's contents. +// +// Encryption key must be a 32-byte AES-256 key. +// See https://cloud.google.com/storage/docs/encryption for details. +func (o *ObjectHandle) Key(encryptionKey []byte) *ObjectHandle { + o2 := *o + o2.encryptionKey = encryptionKey + return &o2 +} + +// Attrs returns meta information about the object. +// ErrObjectNotExist will be returned if the object is not found. +func (o *ObjectHandle) Attrs(ctx context.Context) (attrs *ObjectAttrs, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.Attrs") + defer func() { trace.EndSpan(ctx, err) }() + + if err := o.validate(); err != nil { + return nil, err + } + call := o.c.raw.Objects.Get(o.bucket, o.object).Projection("full").Context(ctx) + if err := applyConds("Attrs", o.gen, o.conds, call); err != nil { + return nil, err + } + if o.userProject != "" { + call.UserProject(o.userProject) + } + if err := setEncryptionHeaders(call.Header(), o.encryptionKey, false); err != nil { + return nil, err + } + var obj *raw.Object + setClientHeader(call.Header()) + err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) + if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { + return nil, ErrObjectNotExist + } + if err != nil { + return nil, err + } + return newObject(obj), nil +} + +// Update updates an object with the provided attributes. +// All zero-value attributes are ignored. +// ErrObjectNotExist will be returned if the object is not found. +func (o *ObjectHandle) Update(ctx context.Context, uattrs ObjectAttrsToUpdate) (oa *ObjectAttrs, err error) { + ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.Update") + defer func() { trace.EndSpan(ctx, err) }() + + if err := o.validate(); err != nil { + return nil, err + } + var attrs ObjectAttrs + // Lists of fields to send, and set to null, in the JSON. + var forceSendFields, nullFields []string + if uattrs.ContentType != nil { + attrs.ContentType = optional.ToString(uattrs.ContentType) + // For ContentType, sending the empty string is a no-op. + // Instead we send a null. + if attrs.ContentType == "" { + nullFields = append(nullFields, "ContentType") + } else { + forceSendFields = append(forceSendFields, "ContentType") + } + } + if uattrs.ContentLanguage != nil { + attrs.ContentLanguage = optional.ToString(uattrs.ContentLanguage) + // For ContentLanguage it's an error to send the empty string. + // Instead we send a null. + if attrs.ContentLanguage == "" { + nullFields = append(nullFields, "ContentLanguage") + } else { + forceSendFields = append(forceSendFields, "ContentLanguage") + } + } + if uattrs.ContentEncoding != nil { + attrs.ContentEncoding = optional.ToString(uattrs.ContentEncoding) + forceSendFields = append(forceSendFields, "ContentEncoding") + } + if uattrs.ContentDisposition != nil { + attrs.ContentDisposition = optional.ToString(uattrs.ContentDisposition) + forceSendFields = append(forceSendFields, "ContentDisposition") + } + if uattrs.CacheControl != nil { + attrs.CacheControl = optional.ToString(uattrs.CacheControl) + forceSendFields = append(forceSendFields, "CacheControl") + } + if uattrs.EventBasedHold != nil { + attrs.EventBasedHold = optional.ToBool(uattrs.EventBasedHold) + forceSendFields = append(forceSendFields, "EventBasedHold") + } + if uattrs.TemporaryHold != nil { + attrs.TemporaryHold = optional.ToBool(uattrs.TemporaryHold) + forceSendFields = append(forceSendFields, "TemporaryHold") + } + if uattrs.Metadata != nil { + attrs.Metadata = uattrs.Metadata + if len(attrs.Metadata) == 0 { + // Sending the empty map is a no-op. We send null instead. + nullFields = append(nullFields, "Metadata") + } else { + forceSendFields = append(forceSendFields, "Metadata") + } + } + if uattrs.ACL != nil { + attrs.ACL = uattrs.ACL + // It's an error to attempt to delete the ACL, so + // we don't append to nullFields here. + forceSendFields = append(forceSendFields, "Acl") + } + rawObj := attrs.toRawObject(o.bucket) + rawObj.ForceSendFields = forceSendFields + rawObj.NullFields = nullFields + call := o.c.raw.Objects.Patch(o.bucket, o.object, rawObj).Projection("full").Context(ctx) + if err := applyConds("Update", o.gen, o.conds, call); err != nil { + return nil, err + } + if o.userProject != "" { + call.UserProject(o.userProject) + } + if uattrs.PredefinedACL != "" { + call.PredefinedAcl(uattrs.PredefinedACL) + } + if err := setEncryptionHeaders(call.Header(), o.encryptionKey, false); err != nil { + return nil, err + } + var obj *raw.Object + setClientHeader(call.Header()) + err = runWithRetry(ctx, func() error { obj, err = call.Do(); return err }) + if e, ok := err.(*googleapi.Error); ok && e.Code == http.StatusNotFound { + return nil, ErrObjectNotExist + } + if err != nil { + return nil, err + } + return newObject(obj), nil +} + +// BucketName returns the name of the bucket. +func (o *ObjectHandle) BucketName() string { + return o.bucket +} + +// ObjectName returns the name of the object. +func (o *ObjectHandle) ObjectName() string { + return o.object +} + +// ObjectAttrsToUpdate is used to update the attributes of an object. +// Only fields set to non-nil values will be updated. +// Set a field to its zero value to delete it. +// +// For example, to change ContentType and delete ContentEncoding and +// Metadata, use +// ObjectAttrsToUpdate{ +// ContentType: "text/html", +// ContentEncoding: "", +// Metadata: map[string]string{}, +// } +type ObjectAttrsToUpdate struct { + EventBasedHold optional.Bool + TemporaryHold optional.Bool + ContentType optional.String + ContentLanguage optional.String + ContentEncoding optional.String + ContentDisposition optional.String + CacheControl optional.String + Metadata map[string]string // set to map[string]string{} to delete + ACL []ACLRule + + // If not empty, applies a predefined set of access controls. ACL must be nil. + // See https://cloud.google.com/storage/docs/json_api/v1/objects/patch. + PredefinedACL string +} + +// Delete deletes the single specified object. +func (o *ObjectHandle) Delete(ctx context.Context) error { + if err := o.validate(); err != nil { + return err + } + call := o.c.raw.Objects.Delete(o.bucket, o.object).Context(ctx) + if err := applyConds("Delete", o.gen, o.conds, call); err != nil { + return err + } + if o.userProject != "" { + call.UserProject(o.userProject) + } + // Encryption doesn't apply to Delete. + setClientHeader(call.Header()) + err := runWithRetry(ctx, func() error { return call.Do() }) + switch e := err.(type) { + case nil: + return nil + case *googleapi.Error: + if e.Code == http.StatusNotFound { + return ErrObjectNotExist + } + } + return err +} + +// ReadCompressed when true causes the read to happen without decompressing. +func (o *ObjectHandle) ReadCompressed(compressed bool) *ObjectHandle { + o2 := *o + o2.readCompressed = compressed + return &o2 +} + +// NewWriter returns a storage Writer that writes to the GCS object +// associated with this ObjectHandle. +// +// A new object will be created unless an object with this name already exists. +// Otherwise any previous object with the same name will be replaced. +// The object will not be available (and any previous object will remain) +// until Close has been called. +// +// Attributes can be set on the object by modifying the returned Writer's +// ObjectAttrs field before the first call to Write. If no ContentType +// attribute is specified, the content type will be automatically sniffed +// using net/http.DetectContentType. +// +// It is the caller's responsibility to call Close when writing is done. To +// stop writing without saving the data, cancel the context. +func (o *ObjectHandle) NewWriter(ctx context.Context) *Writer { + return &Writer{ + ctx: ctx, + o: o, + donec: make(chan struct{}), + ObjectAttrs: ObjectAttrs{Name: o.object}, + ChunkSize: googleapi.DefaultUploadChunkSize, + } +} + +func (o *ObjectHandle) validate() error { + if o.bucket == "" { + return errors.New("storage: bucket name is empty") + } + if o.object == "" { + return errors.New("storage: object name is empty") + } + if !utf8.ValidString(o.object) { + return fmt.Errorf("storage: object name %q is not valid UTF-8", o.object) + } + return nil +} + +// parseKey converts the binary contents of a private key file to an +// *rsa.PrivateKey. It detects whether the private key is in a PEM container or +// not. If so, it extracts the private key from PEM container before +// conversion. It only supports PEM containers with no passphrase. +func parseKey(key []byte) (*rsa.PrivateKey, error) { + if block, _ := pem.Decode(key); block != nil { + key = block.Bytes + } + parsedKey, err := x509.ParsePKCS8PrivateKey(key) + if err != nil { + parsedKey, err = x509.ParsePKCS1PrivateKey(key) + if err != nil { + return nil, err + } + } + parsed, ok := parsedKey.(*rsa.PrivateKey) + if !ok { + return nil, errors.New("oauth2: private key is invalid") + } + return parsed, nil +} + +// toRawObject copies the editable attributes from o to the raw library's Object type. +func (o *ObjectAttrs) toRawObject(bucket string) *raw.Object { + var ret string + if !o.RetentionExpirationTime.IsZero() { + ret = o.RetentionExpirationTime.Format(time.RFC3339) + } + return &raw.Object{ + Bucket: bucket, + Name: o.Name, + EventBasedHold: o.EventBasedHold, + TemporaryHold: o.TemporaryHold, + RetentionExpirationTime: ret, + ContentType: o.ContentType, + ContentEncoding: o.ContentEncoding, + ContentLanguage: o.ContentLanguage, + CacheControl: o.CacheControl, + ContentDisposition: o.ContentDisposition, + StorageClass: o.StorageClass, + Acl: toRawObjectACL(o.ACL), + Metadata: o.Metadata, + } +} + +// ObjectAttrs represents the metadata for a Google Cloud Storage (GCS) object. +type ObjectAttrs struct { + // Bucket is the name of the bucket containing this GCS object. + // This field is read-only. + Bucket string + + // Name is the name of the object within the bucket. + // This field is read-only. + Name string + + // ContentType is the MIME type of the object's content. + ContentType string + + // ContentLanguage is the content language of the object's content. + ContentLanguage string + + // CacheControl is the Cache-Control header to be sent in the response + // headers when serving the object data. + CacheControl string + + // EventBasedHold specifies whether an object is under event-based hold. New + // objects created in a bucket whose DefaultEventBasedHold is set will + // default to that value. + EventBasedHold bool + + // TemporaryHold specifies whether an object is under temporary hold. While + // this flag is set to true, the object is protected against deletion and + // overwrites. + TemporaryHold bool + + // RetentionExpirationTime is a server-determined value that specifies the + // earliest time that the object's retention period expires. + // This is a read-only field. + RetentionExpirationTime time.Time + + // ACL is the list of access control rules for the object. + ACL []ACLRule + + // If not empty, applies a predefined set of access controls. It should be set + // only when writing, copying or composing an object. When copying or composing, + // it acts as the destinationPredefinedAcl parameter. + // PredefinedACL is always empty for ObjectAttrs returned from the service. + // See https://cloud.google.com/storage/docs/json_api/v1/objects/insert + // for valid values. + PredefinedACL string + + // Owner is the owner of the object. This field is read-only. + // + // If non-zero, it is in the form of "user-". + Owner string + + // Size is the length of the object's content. This field is read-only. + Size int64 + + // ContentEncoding is the encoding of the object's content. + ContentEncoding string + + // ContentDisposition is the optional Content-Disposition header of the object + // sent in the response headers. + ContentDisposition string + + // MD5 is the MD5 hash of the object's content. This field is read-only, + // except when used from a Writer. If set on a Writer, the uploaded + // data is rejected if its MD5 hash does not match this field. + MD5 []byte + + // CRC32C is the CRC32 checksum of the object's content using + // the Castagnoli93 polynomial. This field is read-only, except when + // used from a Writer. If set on a Writer and Writer.SendCRC32C + // is true, the uploaded data is rejected if its CRC32c hash does not + // match this field. + CRC32C uint32 + + // MediaLink is an URL to the object's content. This field is read-only. + MediaLink string + + // Metadata represents user-provided metadata, in key/value pairs. + // It can be nil if no metadata is provided. + Metadata map[string]string + + // Generation is the generation number of the object's content. + // This field is read-only. + Generation int64 + + // Metageneration is the version of the metadata for this + // object at this generation. This field is used for preconditions + // and for detecting changes in metadata. A metageneration number + // is only meaningful in the context of a particular generation + // of a particular object. This field is read-only. + Metageneration int64 + + // StorageClass is the storage class of the object. + // This value defines how objects in the bucket are stored and + // determines the SLA and the cost of storage. Typical values are + // "MULTI_REGIONAL", "REGIONAL", "NEARLINE", "COLDLINE", "STANDARD" + // and "DURABLE_REDUCED_AVAILABILITY". + // It defaults to "STANDARD", which is equivalent to "MULTI_REGIONAL" + // or "REGIONAL" depending on the bucket's location settings. + StorageClass string + + // Created is the time the object was created. This field is read-only. + Created time.Time + + // Deleted is the time the object was deleted. + // If not deleted, it is the zero value. This field is read-only. + Deleted time.Time + + // Updated is the creation or modification time of the object. + // For buckets with versioning enabled, changing an object's + // metadata does not change this property. This field is read-only. + Updated time.Time + + // CustomerKeySHA256 is the base64-encoded SHA-256 hash of the + // customer-supplied encryption key for the object. It is empty if there is + // no customer-supplied encryption key. + // See // https://cloud.google.com/storage/docs/encryption for more about + // encryption in Google Cloud Storage. + CustomerKeySHA256 string + + // Cloud KMS key name, in the form + // projects/P/locations/L/keyRings/R/cryptoKeys/K, used to encrypt this object, + // if the object is encrypted by such a key. + // + // Providing both a KMSKeyName and a customer-supplied encryption key (via + // ObjectHandle.Key) will result in an error when writing an object. + KMSKeyName string + + // Prefix is set only for ObjectAttrs which represent synthetic "directory + // entries" when iterating over buckets using Query.Delimiter. See + // ObjectIterator.Next. When set, no other fields in ObjectAttrs will be + // populated. + Prefix string +} + +// convertTime converts a time in RFC3339 format to time.Time. +// If any error occurs in parsing, the zero-value time.Time is silently returned. +func convertTime(t string) time.Time { + var r time.Time + if t != "" { + r, _ = time.Parse(time.RFC3339, t) + } + return r +} + +func newObject(o *raw.Object) *ObjectAttrs { + if o == nil { + return nil + } + owner := "" + if o.Owner != nil { + owner = o.Owner.Entity + } + md5, _ := base64.StdEncoding.DecodeString(o.Md5Hash) + crc32c, _ := decodeUint32(o.Crc32c) + var sha256 string + if o.CustomerEncryption != nil { + sha256 = o.CustomerEncryption.KeySha256 + } + return &ObjectAttrs{ + Bucket: o.Bucket, + Name: o.Name, + ContentType: o.ContentType, + ContentLanguage: o.ContentLanguage, + CacheControl: o.CacheControl, + EventBasedHold: o.EventBasedHold, + TemporaryHold: o.TemporaryHold, + RetentionExpirationTime: convertTime(o.RetentionExpirationTime), + ACL: toObjectACLRules(o.Acl), + Owner: owner, + ContentEncoding: o.ContentEncoding, + ContentDisposition: o.ContentDisposition, + Size: int64(o.Size), + MD5: md5, + CRC32C: crc32c, + MediaLink: o.MediaLink, + Metadata: o.Metadata, + Generation: o.Generation, + Metageneration: o.Metageneration, + StorageClass: o.StorageClass, + CustomerKeySHA256: sha256, + KMSKeyName: o.KmsKeyName, + Created: convertTime(o.TimeCreated), + Deleted: convertTime(o.TimeDeleted), + Updated: convertTime(o.Updated), + } +} + +// Decode a uint32 encoded in Base64 in big-endian byte order. +func decodeUint32(b64 string) (uint32, error) { + d, err := base64.StdEncoding.DecodeString(b64) + if err != nil { + return 0, err + } + if len(d) != 4 { + return 0, fmt.Errorf("storage: %q does not encode a 32-bit value", d) + } + return uint32(d[0])<<24 + uint32(d[1])<<16 + uint32(d[2])<<8 + uint32(d[3]), nil +} + +// Encode a uint32 as Base64 in big-endian byte order. +func encodeUint32(u uint32) string { + b := []byte{byte(u >> 24), byte(u >> 16), byte(u >> 8), byte(u)} + return base64.StdEncoding.EncodeToString(b) +} + +// Query represents a query to filter objects from a bucket. +type Query struct { + // Delimiter returns results in a directory-like fashion. + // Results will contain only objects whose names, aside from the + // prefix, do not contain delimiter. Objects whose names, + // aside from the prefix, contain delimiter will have their name, + // truncated after the delimiter, returned in prefixes. + // Duplicate prefixes are omitted. + // Optional. + Delimiter string + + // Prefix is the prefix filter to query objects + // whose names begin with this prefix. + // Optional. + Prefix string + + // Versions indicates whether multiple versions of the same + // object will be included in the results. + Versions bool +} + +// contentTyper implements ContentTyper to enable an +// io.ReadCloser to specify its MIME type. +type contentTyper struct { + io.Reader + t string +} + +func (c *contentTyper) ContentType() string { + return c.t +} + +// Conditions constrain methods to act on specific generations of +// objects. +// +// The zero value is an empty set of constraints. Not all conditions or +// combinations of conditions are applicable to all methods. +// See https://cloud.google.com/storage/docs/generations-preconditions +// for details on how these operate. +type Conditions struct { + // Generation constraints. + // At most one of the following can be set to a non-zero value. + + // GenerationMatch specifies that the object must have the given generation + // for the operation to occur. + // If GenerationMatch is zero, it has no effect. + // Use DoesNotExist to specify that the object does not exist in the bucket. + GenerationMatch int64 + + // GenerationNotMatch specifies that the object must not have the given + // generation for the operation to occur. + // If GenerationNotMatch is zero, it has no effect. + GenerationNotMatch int64 + + // DoesNotExist specifies that the object must not exist in the bucket for + // the operation to occur. + // If DoesNotExist is false, it has no effect. + DoesNotExist bool + + // Metadata generation constraints. + // At most one of the following can be set to a non-zero value. + + // MetagenerationMatch specifies that the object must have the given + // metageneration for the operation to occur. + // If MetagenerationMatch is zero, it has no effect. + MetagenerationMatch int64 + + // MetagenerationNotMatch specifies that the object must not have the given + // metageneration for the operation to occur. + // If MetagenerationNotMatch is zero, it has no effect. + MetagenerationNotMatch int64 +} + +func (c *Conditions) validate(method string) error { + if *c == (Conditions{}) { + return fmt.Errorf("storage: %s: empty conditions", method) + } + if !c.isGenerationValid() { + return fmt.Errorf("storage: %s: multiple conditions specified for generation", method) + } + if !c.isMetagenerationValid() { + return fmt.Errorf("storage: %s: multiple conditions specified for metageneration", method) + } + return nil +} + +func (c *Conditions) isGenerationValid() bool { + n := 0 + if c.GenerationMatch != 0 { + n++ + } + if c.GenerationNotMatch != 0 { + n++ + } + if c.DoesNotExist { + n++ + } + return n <= 1 +} + +func (c *Conditions) isMetagenerationValid() bool { + return c.MetagenerationMatch == 0 || c.MetagenerationNotMatch == 0 +} + +// applyConds modifies the provided call using the conditions in conds. +// call is something that quacks like a *raw.WhateverCall. +func applyConds(method string, gen int64, conds *Conditions, call interface{}) error { + cval := reflect.ValueOf(call) + if gen >= 0 { + if !setConditionField(cval, "Generation", gen) { + return fmt.Errorf("storage: %s: generation not supported", method) + } + } + if conds == nil { + return nil + } + if err := conds.validate(method); err != nil { + return err + } + switch { + case conds.GenerationMatch != 0: + if !setConditionField(cval, "IfGenerationMatch", conds.GenerationMatch) { + return fmt.Errorf("storage: %s: ifGenerationMatch not supported", method) + } + case conds.GenerationNotMatch != 0: + if !setConditionField(cval, "IfGenerationNotMatch", conds.GenerationNotMatch) { + return fmt.Errorf("storage: %s: ifGenerationNotMatch not supported", method) + } + case conds.DoesNotExist: + if !setConditionField(cval, "IfGenerationMatch", int64(0)) { + return fmt.Errorf("storage: %s: DoesNotExist not supported", method) + } + } + switch { + case conds.MetagenerationMatch != 0: + if !setConditionField(cval, "IfMetagenerationMatch", conds.MetagenerationMatch) { + return fmt.Errorf("storage: %s: ifMetagenerationMatch not supported", method) + } + case conds.MetagenerationNotMatch != 0: + if !setConditionField(cval, "IfMetagenerationNotMatch", conds.MetagenerationNotMatch) { + return fmt.Errorf("storage: %s: ifMetagenerationNotMatch not supported", method) + } + } + return nil +} + +func applySourceConds(gen int64, conds *Conditions, call *raw.ObjectsRewriteCall) error { + if gen >= 0 { + call.SourceGeneration(gen) + } + if conds == nil { + return nil + } + if err := conds.validate("CopyTo source"); err != nil { + return err + } + switch { + case conds.GenerationMatch != 0: + call.IfSourceGenerationMatch(conds.GenerationMatch) + case conds.GenerationNotMatch != 0: + call.IfSourceGenerationNotMatch(conds.GenerationNotMatch) + case conds.DoesNotExist: + call.IfSourceGenerationMatch(0) + } + switch { + case conds.MetagenerationMatch != 0: + call.IfSourceMetagenerationMatch(conds.MetagenerationMatch) + case conds.MetagenerationNotMatch != 0: + call.IfSourceMetagenerationNotMatch(conds.MetagenerationNotMatch) + } + return nil +} + +// setConditionField sets a field on a *raw.WhateverCall. +// We can't use anonymous interfaces because the return type is +// different, since the field setters are builders. +func setConditionField(call reflect.Value, name string, value interface{}) bool { + m := call.MethodByName(name) + if !m.IsValid() { + return false + } + m.Call([]reflect.Value{reflect.ValueOf(value)}) + return true +} + +// conditionsQuery returns the generation and conditions as a URL query +// string suitable for URL.RawQuery. It assumes that the conditions +// have been validated. +func conditionsQuery(gen int64, conds *Conditions) string { + // URL escapes are elided because integer strings are URL-safe. + var buf []byte + + appendParam := func(s string, n int64) { + if len(buf) > 0 { + buf = append(buf, '&') + } + buf = append(buf, s...) + buf = strconv.AppendInt(buf, n, 10) + } + + if gen >= 0 { + appendParam("generation=", gen) + } + if conds == nil { + return string(buf) + } + switch { + case conds.GenerationMatch != 0: + appendParam("ifGenerationMatch=", conds.GenerationMatch) + case conds.GenerationNotMatch != 0: + appendParam("ifGenerationNotMatch=", conds.GenerationNotMatch) + case conds.DoesNotExist: + appendParam("ifGenerationMatch=", 0) + } + switch { + case conds.MetagenerationMatch != 0: + appendParam("ifMetagenerationMatch=", conds.MetagenerationMatch) + case conds.MetagenerationNotMatch != 0: + appendParam("ifMetagenerationNotMatch=", conds.MetagenerationNotMatch) + } + return string(buf) +} + +// composeSourceObj wraps a *raw.ComposeRequestSourceObjects, but adds the methods +// that modifyCall searches for by name. +type composeSourceObj struct { + src *raw.ComposeRequestSourceObjects +} + +func (c composeSourceObj) Generation(gen int64) { + c.src.Generation = gen +} + +func (c composeSourceObj) IfGenerationMatch(gen int64) { + // It's safe to overwrite ObjectPreconditions, since its only field is + // IfGenerationMatch. + c.src.ObjectPreconditions = &raw.ComposeRequestSourceObjectsObjectPreconditions{ + IfGenerationMatch: gen, + } +} + +func setEncryptionHeaders(headers http.Header, key []byte, copySource bool) error { + if key == nil { + return nil + } + // TODO(jbd): Ask the API team to return a more user-friendly error + // and avoid doing this check at the client level. + if len(key) != 32 { + return errors.New("storage: not a 32-byte AES-256 key") + } + var cs string + if copySource { + cs = "copy-source-" + } + headers.Set("x-goog-"+cs+"encryption-algorithm", "AES256") + headers.Set("x-goog-"+cs+"encryption-key", base64.StdEncoding.EncodeToString(key)) + keyHash := sha256.Sum256(key) + headers.Set("x-goog-"+cs+"encryption-key-sha256", base64.StdEncoding.EncodeToString(keyHash[:])) + return nil +} + +// ServiceAccount fetches the email address of the given project's Google Cloud Storage service account. +func (c *Client) ServiceAccount(ctx context.Context, projectID string) (string, error) { + r := c.raw.Projects.ServiceAccount.Get(projectID) + res, err := r.Context(ctx).Do() + if err != nil { + return "", err + } + return res.EmailAddress, nil +} diff --git a/vendor/cloud.google.com/go/storage/storage.replay b/vendor/cloud.google.com/go/storage/storage.replay new file mode 100644 index 00000000..079b162e --- /dev/null +++ b/vendor/cloud.google.com/go/storage/storage.replay @@ -0,0 +1,53540 @@ +{ + "Initial": "IjIwMTgtMDktMjdUMTI6MjM6NTAuOTExODYzNjRaIg==", + "Version": "0.1", + "Entries": [ + { + "ID": "4a867507b0f3dbee", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "60" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "324cf8b8639b6b4631e5c4cafd0e2c16/986732864287226636;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIn0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "426" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:23:52 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051331000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdk3:4341,/bns/yr/borg/yr/bns/blobstore2/bitpusher/44.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=18usW9v6OMTvkAPC4IGgCQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/44.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/44:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWUNKdzJzd0Q5dnlBOGFHdHN2YzZ3MzJpem1SRXNRUWZaZl94RkpWbU84VFRyeEJfc2ZaRkZsdjBhUlRLZC1zLWtJc2pLcWd6ZGVJejkwZGMtUFlSVFZQVTdrTkNJbHllUmVhSlRldU9sb1YyWl94aFdFQkoxNGN2VHhyZDl4Uk03RFViN0tra09hd1NlVkdqLWU0V2FZU0ZOTW16U1dDS3NSZUtDTUhaRDFEc1g3djM3RmZGMmw1RXcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpcHZthlQWJ5OdoRGpk5Js3AAogojVNWvlmo_v3oIqaVxRiH0Y5STeX-fVrzNltY06kjYMaSo3O9iTiJWw3AvtVVLy8UA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjM6NTIuMzU1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjIzOjUyLjM1NVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "ba85864b53e935df", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "60" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "cbd945887a7e22a66506ae96bde01c15/4926593637547890840;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAyIn0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "426" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:23:53 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051332000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrc82:4164,/bns/yw/borg/yw/bns/blobstore2/bitpusher/49.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=2MusW73YLMOwhgT23rH4CQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/49.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/49:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYkFaSE11YVZ6S2lnNDcyVW5lcUNPRzBMMmlCekJVY0NGaTB1c3o4ekE0Uk5kQ1A5aW1wbE1vcTcyVlQzLUJlVlhUaU9Mb0F0VURYRHpwb0lYZkpMMjVTZzFYTk9KZ1dJbV9QNHlaV0pGY1hHNFMxeGxnbDlmMkpXRkRUbjFfLTdweHFYNGJudndGM0JXTzZ5Y1ROdWtqX3NqS29kanRJMW9HQTBnbmVTM0RaMF9HX1B0bWpmSFlYanMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoGCVnjOfC9cVkP546g8csLoUI7KRTsrnTDPV2wpbnLpOKwP6qKGpLkqkFg0Vp1ez-KuxdvHzgxloaoqFZ3GjWVzOYtZA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDIiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjM6NTMuMTYyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjIzOjUzLjE2MloiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "486bc9edab67455b", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0002?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "336221695c86fb5324eaf6a7d4e2082c/6516722971421670967;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0002?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2353" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:23:53 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:23:53 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051333000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrqe25:4313,/bns/yr/borg/yr/bns/blobstore2/bitpusher/9.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=2cusW4yhGLLm4QS0iZ9I" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/9.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/9:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYkFaSE11YVZ6S2lnNDcyVW5lcUNPRzBMMmlCekJVY0NGaTB1c3o4ekE0Uk5kQ1A5aW1wbE1vcTcyVlQzLUJlVlhUaU9Mb0F0VURYRHpwb0lYZkpMMjVTZzFYTk9KZ1dJbV9QNHlaV0pGY1hHNFMxeGxnbDlmMkpXRkRUbjFfLTdweHFYNGJudndGM0JXTzZ5Y1ROdWtqX3NqS29kanRJMW9HQTBnbmVTM0RaMF9HX1B0bWpmSFlYanMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqvlMRQ1xVQ4ay63D5G54td8G9spIJDhN4kzGHZvTEW8sdjRs4_h5P6FVP_xUKNsLv38Rt6frdE6DohTYKJzwvZ78xSdQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDIiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjM6NTMuMTYyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjIzOjUzLjE2MloiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMi9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDIvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDIvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAyL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" + } + }, + { + "ID": "18c04b894e7914ca", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0002?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "99cc7479d127b305fe0a7955f514551c/8107134871193920470;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0002?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:23:54 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051332000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrjm12:4359,/bns/yv/borg/yv/bns/blobstore2/bitpusher/250.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=2cusW_-dM9X8gQS2j5UY" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/250.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/250:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYkFaSE11YVZ6S2lnNDcyVW5lcUNPRzBMMmlCekJVY0NGaTB1c3o4ekE0Uk5kQ1A5aW1wbE1vcTcyVlQzLUJlVlhUaU9Mb0F0VURYRHpwb0lYZkpMMjVTZzFYTk9KZ1dJbV9QNHlaV0pGY1hHNFMxeGxnbDlmMkpXRkRUbjFfLTdweHFYNGJudndGM0JXTzZ5Y1ROdWtqX3NqS29kanRJMW9HQTBnbmVTM0RaMF9HX1B0bWpmSFlYanMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Upwbe_KfHSmvQWFmYWTIHi1QxfU6aaP320Hi2YakvoHiu9eV6n6yebxLDKyLyKL6GKAaXGv1GJpYo-cx8S2qNo8kqpI0Q" + ] + }, + "Body": "" + } + }, + { + "ID": "3f65476279d8f2a4", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "543" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "811fa6ca0d68c12f4f50698dff145469/9697546775244360052;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJsYWJlbHMiOnsiZW1wdHkiOiIiLCJsMSI6InYxIn0sImxpZmVjeWNsZSI6eyJydWxlIjpbeyJhY3Rpb24iOnsic3RvcmFnZUNsYXNzIjoiTkVBUkxJTkUiLCJ0eXBlIjoiU2V0U3RvcmFnZUNsYXNzIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjEwLCJjcmVhdGVkQmVmb3JlIjoiMjAxNy0wMS0wMSIsImlzTGl2ZSI6ZmFsc2UsIm1hdGNoZXNTdG9yYWdlQ2xhc3MiOlsiTVVMVElfUkVHSU9OQUwiLCJTVEFOREFSRCJdLCJudW1OZXdlclZlcnNpb25zIjozfX0seyJhY3Rpb24iOnsidHlwZSI6IkRlbGV0ZSJ9LCJjb25kaXRpb24iOnsiYWdlIjozMCwiY3JlYXRlZEJlZm9yZSI6IjIwMTctMDEtMDEiLCJpc0xpdmUiOnRydWUsIm1hdGNoZXNTdG9yYWdlQ2xhc3MiOlsiTkVBUkxJTkUiXSwibnVtTmV3ZXJWZXJzaW9ucyI6MTB9fV19LCJsb2NhdGlvbiI6IlVTIiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMiIsInN0b3JhZ2VDbGFzcyI6Ik5FQVJMSU5FIiwidmVyc2lvbmluZyI6eyJlbmFibGVkIjp0cnVlfX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "867" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:23:54 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051332000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrak11:4291,/bns/yw/borg/yw/bns/blobstore2/bitpusher/50.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=2susW6jMDsHAhATs75PIDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/50.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/50:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYkFaSE11YVZ6S2lnNDcyVW5lcUNPRzBMMmlCekJVY0NGaTB1c3o4ekE0Uk5kQ1A5aW1wbE1vcTcyVlQzLUJlVlhUaU9Mb0F0VURYRHpwb0lYZkpMMjVTZzFYTk9KZ1dJbV9QNHlaV0pGY1hHNFMxeGxnbDlmMkpXRkRUbjFfLTdweHFYNGJudndGM0JXTzZ5Y1ROdWtqX3NqS29kanRJMW9HQTBnbmVTM0RaMF9HX1B0bWpmSFlYanMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrCe3wG3NZcYEUACuZktBQLRW8Eg5sflTKX7uRVrmzCJuksbsdtl6DtdqUJwPAyaemH-HkA-RDCjA0STJNKBXwv1k1w6w" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDIiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjM6NTQuNjY2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjIzOjU0LjY2NloiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwidmVyc2lvbmluZyI6eyJlbmFibGVkIjp0cnVlfSwibGlmZWN5Y2xlIjp7InJ1bGUiOlt7ImFjdGlvbiI6eyJ0eXBlIjoiU2V0U3RvcmFnZUNsYXNzIiwic3RvcmFnZUNsYXNzIjoiTkVBUkxJTkUifSwiY29uZGl0aW9uIjp7ImFnZSI6MTAsImNyZWF0ZWRCZWZvcmUiOiIyMDE3LTAxLTAxIiwiaXNMaXZlIjpmYWxzZSwibWF0Y2hlc1N0b3JhZ2VDbGFzcyI6WyJNVUxUSV9SRUdJT05BTCIsIlNUQU5EQVJEIl0sIm51bU5ld2VyVmVyc2lvbnMiOjN9fSx7ImFjdGlvbiI6eyJ0eXBlIjoiRGVsZXRlIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjMwLCJjcmVhdGVkQmVmb3JlIjoiMjAxNy0wMS0wMSIsImlzTGl2ZSI6dHJ1ZSwibWF0Y2hlc1N0b3JhZ2VDbGFzcyI6WyJORUFSTElORSJdLCJudW1OZXdlclZlcnNpb25zIjoxMH19XX0sImxhYmVscyI6eyJsMSI6InYxIiwiZW1wdHkiOiIifSwic3RvcmFnZUNsYXNzIjoiTkVBUkxJTkUiLCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "959d26ad1031b8fe", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0002?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "591e17a835f0e96a9eefadf22d09a1ee/11287958679311511059;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0002?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2794" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:23:55 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:23:55 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051334000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnss7:4006,/bns/yx/borg/yx/bns/blobstore2/bitpusher/121.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=2susW6OUNMuRzgLBuZuAAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/121.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/121:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYkFaSE11YVZ6S2lnNDcyVW5lcUNPRzBMMmlCekJVY0NGaTB1c3o4ekE0Uk5kQ1A5aW1wbE1vcTcyVlQzLUJlVlhUaU9Mb0F0VURYRHpwb0lYZkpMMjVTZzFYTk9KZ1dJbV9QNHlaV0pGY1hHNFMxeGxnbDlmMkpXRkRUbjFfLTdweHFYNGJudndGM0JXTzZ5Y1ROdWtqX3NqS29kanRJMW9HQTBnbmVTM0RaMF9HX1B0bWpmSFlYanMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpesIKnG6nWNHsdZuWGkdrt7L_1eeDmsUHLIRTQMb_9EX567zcXF2uU50jLaVK4WZtH0ZO0rG2RWY-20o1Y3aJCImfm_w" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDIiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjM6NTQuNjY2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjIzOjU0LjY2NloiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMi9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDIvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDIvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAyL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInZlcnNpb25pbmciOnsiZW5hYmxlZCI6dHJ1ZX0sImxpZmVjeWNsZSI6eyJydWxlIjpbeyJhY3Rpb24iOnsidHlwZSI6IlNldFN0b3JhZ2VDbGFzcyIsInN0b3JhZ2VDbGFzcyI6Ik5FQVJMSU5FIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjEwLCJjcmVhdGVkQmVmb3JlIjoiMjAxNy0wMS0wMSIsImlzTGl2ZSI6ZmFsc2UsIm1hdGNoZXNTdG9yYWdlQ2xhc3MiOlsiTVVMVElfUkVHSU9OQUwiLCJTVEFOREFSRCJdLCJudW1OZXdlclZlcnNpb25zIjozfX0seyJhY3Rpb24iOnsidHlwZSI6IkRlbGV0ZSJ9LCJjb25kaXRpb24iOnsiYWdlIjozMCwiY3JlYXRlZEJlZm9yZSI6IjIwMTctMDEtMDEiLCJpc0xpdmUiOnRydWUsIm1hdGNoZXNTdG9yYWdlQ2xhc3MiOlsiTkVBUkxJTkUiXSwibnVtTmV3ZXJWZXJzaW9ucyI6MTB9fV19LCJsYWJlbHMiOnsibDEiOiJ2MSIsImVtcHR5IjoiIn0sInN0b3JhZ2VDbGFzcyI6Ik5FQVJMSU5FIiwiZXRhZyI6IkNBRT0ifQ==" + } + }, + { + "ID": "5c5a9394a6df293c", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0002?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "5fc569e90e1807b37ae8b7e2261abfd9/12878089108385240242;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0002?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:23:55 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051332000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrgg80:4282,/bns/yr/borg/yr/bns/blobstore2/bitpusher/65.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=28usW7GPB4SGkASB5ob4BQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/65.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/65:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYkFaSE11YVZ6S2lnNDcyVW5lcUNPRzBMMmlCekJVY0NGaTB1c3o4ekE0Uk5kQ1A5aW1wbE1vcTcyVlQzLUJlVlhUaU9Mb0F0VURYRHpwb0lYZkpMMjVTZzFYTk9KZ1dJbV9QNHlaV0pGY1hHNFMxeGxnbDlmMkpXRkRUbjFfLTdweHFYNGJudndGM0JXTzZ5Y1ROdWtqX3NqS29kanRJMW9HQTBnbmVTM0RaMF9HX1B0bWpmSFlYanMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpCJff1tEGhyDbHTx3PppR8ezK_fjgJCuPocttNzHKB98UqFv38y6-CrTard9dk51CY0fizSV9S8XaEMBMpevmhBShQSQ" + ] + }, + "Body": "" + } + }, + { + "ID": "e4ab887b5dddc69b", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "8715d6d92b86b13e7fba448ddf7d3604/14468499912957606224;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2353" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:23:55 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:23:55 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051335000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrv189:4445,/bns/yv/borg/yv/bns/blobstore2/bitpusher/374.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=28usW47vJY3yggSq27_4CQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/374.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/374:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYkJ1dHF6dE1zd2lVYzFqbFhQblk4Zk1vWTU0dzJzYmZicXh1bEFiRjdFVkZTVWFCY3liY3hyY1RmRXFuX0tCOTYxZ2pONXJrYzFseHJtUGV1YnZMY2JQUVlrYjA4bnFVOGN5UVE0VDlGdy1UdTNSV2dhbWdnVDU3bl80YnpwWDU3ZjZycDJ0ejcyWXgxQnc5c2ppQmtOWlJIcGhMbEpuRHFKRC1IaXF4RllzUWpld3Ewc3RiWDRzQ2MwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Upt9LBuQWdif5NPssRtVxoi9j0KQELZ1rCKjIN56roTgjIH7mZ0A1ZHDuPB6c4XdqIgoZprVYGMT7pFQEGD08luMOkKlw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjM6NTIuMzU1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjIzOjUyLjM1NVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" + } + }, + { + "ID": "9fe8f52448faf49d", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ebc497d92bd029c51a5c96b957211d37/16058911817007980527;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2353" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:23:57 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051336000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbq123:4158,/bns/yw/borg/yw/bns/blobstore2/bitpusher/161.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=28usW7OEOI-2N_7Un8gF" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/161.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/161:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYkJ1dHF6dE1zd2lVYzFqbFhQblk4Zk1vWTU0dzJzYmZicXh1bEFiRjdFVkZTVWFCY3liY3hyY1RmRXFuX0tCOTYxZ2pONXJrYzFseHJtUGV1YnZMY2JQUVlrYjA4bnFVOGN5UVE0VDlGdy1UdTNSV2dhbWdnVDU3bl80YnpwWDU3ZjZycDJ0ejcyWXgxQnc5c2ppQmtOWlJIcGhMbEpuRHFKRC1IaXF4RllzUWpld3Ewc3RiWDRzQ2MwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqOH7YWz4uHeB7Zu_HYqn6JkWYP_j5bSoYFsj7yER0-RUIcDaA3Bv3eYs-dj8feSewfT-dR1pQWwMV8yE_E_oap5YU9zw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjM6NTIuMzU1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjIzOjU3LjQyN1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "44db27d29c1e0abe", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "64" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "8c93187dec5f14a9c6a2260dfd519d5d/17649323716780229774;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJsYWJlbHMiOnsiZW1wdHkiOiIiLCJsMSI6InYxIn0sInZlcnNpb25pbmciOnsiZW5hYmxlZCI6dHJ1ZX19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2415" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:23:58 GMT" + ], + "Etag": [ + "CAM=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051336000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrmm26:4177,/bns/yv/borg/yv/bns/blobstore2/bitpusher/211.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=3cusW9DxJsfWgwSThbvoBw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/211.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/211:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYkJ1dHF6dE1zd2lVYzFqbFhQblk4Zk1vWTU0dzJzYmZicXh1bEFiRjdFVkZTVWFCY3liY3hyY1RmRXFuX0tCOTYxZ2pONXJrYzFseHJtUGV1YnZMY2JQUVlrYjA4bnFVOGN5UVE0VDlGdy1UdTNSV2dhbWdnVDU3bl80YnpwWDU3ZjZycDJ0ejcyWXgxQnc5c2ppQmtOWlJIcGhMbEpuRHFKRC1IaXF4RllzUWpld3Ewc3RiWDRzQ2MwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Upvu77QBhzvRw1piNR-X93WTmdCSybBSWbAm_HIAco5vSyg0E3M69iewocziGyHJBL7GVmnNIcGAeyxETWYUuRlS2z5TQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjM6NTIuMzU1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjIzOjU4LjcyM1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjMiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBTT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FNPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInZlcnNpb25pbmciOnsiZW5hYmxlZCI6dHJ1ZX0sImxhYmVscyI6eyJlbXB0eSI6IiIsImwxIjoidjEifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FNPSJ9" + } + }, + { + "ID": "f51861aaca48496f", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "93" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "06ae89cc69c52d58c7caa6672fbf6225/720935056889784876;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJsYWJlbHMiOnsiYWJzZW50IjpudWxsLCJlbXB0eSI6bnVsbCwibDEiOiJ2MiIsIm5ldyI6Im5ldyJ9LCJ2ZXJzaW9uaW5nIjp7ImVuYWJsZWQiOmZhbHNlfX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2417" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:00 GMT" + ], + "Etag": [ + "CAQ=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051336000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrpw19:4348,/bns/yw/borg/yw/bns/blobstore2/bitpusher/40.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=3susW7z_OIvFhgSUoLf4Ag" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/40.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/40:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYkJ1dHF6dE1zd2lVYzFqbFhQblk4Zk1vWTU0dzJzYmZicXh1bEFiRjdFVkZTVWFCY3liY3hyY1RmRXFuX0tCOTYxZ2pONXJrYzFseHJtUGV1YnZMY2JQUVlrYjA4bnFVOGN5UVE0VDlGdy1UdTNSV2dhbWdnVDU3bl80YnpwWDU3ZjZycDJ0ejcyWXgxQnc5c2ppQmtOWlJIcGhMbEpuRHFKRC1IaXF4RllzUWpld3Ewc3RiWDRzQ2MwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqjrhFVd9uFgXPlY_Y-sPlqWx_zSWqwKmIwnXnWUQ02LsnvtCgpyuv71-now-QWBq_fdOf_GVkWzaBEje5_8W2gQliO-Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjM6NTIuMzU1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjAwLjMyMloiLCJtZXRhZ2VuZXJhdGlvbiI6IjQiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBUT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQVE9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBUT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBUT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FRPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FRPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInZlcnNpb25pbmciOnsiZW5hYmxlZCI6ZmFsc2V9LCJsYWJlbHMiOnsibDEiOiJ2MiIsIm5ldyI6Im5ldyJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQVE9In0=" + } + }, + { + "ID": "b64b55060955d79c", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "77" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "303b222cd26f932b6132314f2ae7055e/2311346960956936139;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJsaWZlY3ljbGUiOnsicnVsZSI6W3siYWN0aW9uIjp7InR5cGUiOiJEZWxldGUifSwiY29uZGl0aW9uIjp7ImFnZSI6MzB9fV19fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2492" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:02 GMT" + ], + "Etag": [ + "CAU=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051336000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrjp9:4258,/bns/yv/borg/yv/bns/blobstore2/bitpusher/58.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=4MusW77VIJOOgQTGxbr4Cg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/58.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/58:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYkJ1dHF6dE1zd2lVYzFqbFhQblk4Zk1vWTU0dzJzYmZicXh1bEFiRjdFVkZTVWFCY3liY3hyY1RmRXFuX0tCOTYxZ2pONXJrYzFseHJtUGV1YnZMY2JQUVlrYjA4bnFVOGN5UVE0VDlGdy1UdTNSV2dhbWdnVDU3bl80YnpwWDU3ZjZycDJ0ejcyWXgxQnc5c2ppQmtOWlJIcGhMbEpuRHFKRC1IaXF4RllzUWpld3Ewc3RiWDRzQ2MwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo-IbtKMtWZK12VIWm36H83fcYySjH7jSBOoH02cdECp8fasNymRIEHTBg4xzPYF2DtVWoKVAzpHVWxLGUvyVf3imyL8QGR-cuBgIoN4s32gE6AgY0" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjM6NTIuMzU1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjAyLjEyOVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjUiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQVU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBVT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FVPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FVPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInZlcnNpb25pbmciOnsiZW5hYmxlZCI6ZmFsc2V9LCJsaWZlY3ljbGUiOnsicnVsZSI6W3siYWN0aW9uIjp7InR5cGUiOiJEZWxldGUifSwiY29uZGl0aW9uIjp7ImFnZSI6MzB9fV19LCJsYWJlbHMiOnsibDEiOiJ2MiIsIm5ldyI6Im5ldyJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQVU9In0=" + } + }, + { + "ID": "214ff250647b9b45", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=ddc31edea4b16a31d614ee7de096bb732d74bb8c75462aad8a02b6dd0098" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "c63fd227fd0ef1001c1768b1dee0d0f7/3142440424904434202;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS1kZGMzMWVkZWE0YjE2YTMxZDYxNGVlN2RlMDk2YmI3MzJkNzRiYjhjNzU0NjJhYWQ4YTAyYjZkZDAwOTgNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJjb25kZGVsIn0KDQotLWRkYzMxZWRlYTRiMTZhMzFkNjE0ZWU3ZGUwOTZiYjczMmQ3NGJiOGM3NTQ2MmFhZDhhMDJiNmRkMDA5OA0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluDQoNCmZvbw0KLS1kZGMzMWVkZWE0YjE2YTMxZDYxNGVlN2RlMDk2YmI3MzJkNzRiYjhjNzU0NjJhYWQ4YTAyYjZkZDAwOTgtLQ0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3254" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:02 GMT" + ], + "Etag": [ + "CICps9CW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051342000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlh82:4312,/bns/yv/borg/yv/bns/blobstore2/bitpusher/384.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=4susW5GSGtiiggSxqYa4Dw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/384.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/384:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWXY2MTJyUVRiNE1ZWEtqdTZPQnktbmItdVBNRDJaTWRzU01HMFpSR3hiSUNwbUhWbXVFRlVEYjNkTURQUjc1OFJLMUtDNmEtZllTQWE5RWNYMXNaSlY3M0xWLXRnRmNOZFphckJMak9JSWRJRG5vSG4ySzcwTHpLdXhZNzBBSWU1TlFzU0F3WWIwLWU1WHlKZDk4WFlQLXBBT2tTVzBraFdXblVlZnpmYzExdWZUeHZnN2llS0hTWGswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqfAXKlaBbrgYFw53CCPGs3Fc_7Oyg0ltyrmvfu-XsEw3WBnui0YnKufuulHx-futBxiHniFMJLM6i2SHoPuvKFI2mmOQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb25kZGVsLzE1MzgwNTEwNDI3NTk4MDgiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb25kZGVsIiwibmFtZSI6ImNvbmRkZWwiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0Mjc1OTgwOCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowMi43NThaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDIuNzU4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjAyLjc1OFoiLCJzaXplIjoiMyIsIm1kNUhhc2giOiJyTDBZMjB6QytGenQ3MlZQek1TazJBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29uZGRlbD9nZW5lcmF0aW9uPTE1MzgwNTEwNDI3NTk4MDgmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29uZGRlbC8xNTM4MDUxMDQyNzU5ODA4L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29uZGRlbC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjb25kZGVsIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDI3NTk4MDgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJQ3BzOUNXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb25kZGVsLzE1MzgwNTEwNDI3NTk4MDgvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29uZGRlbC9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29uZGRlbCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQyNzU5ODA4IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNJQ3BzOUNXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb25kZGVsLzE1MzgwNTEwNDI3NTk4MDgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29uZGRlbC9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29uZGRlbCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQyNzU5ODA4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSUNwczlDVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29uZGRlbC8xNTM4MDUxMDQyNzU5ODA4L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb25kZGVsL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29uZGRlbCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQyNzU5ODA4IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0lDcHM5Q1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJ6OFN1SFE9PSIsImV0YWciOiJDSUNwczlDVzI5MENFQUU9In0=" + } + }, + { + "ID": "6dbba13fcd47d71f", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/conddel?alt=json\u0026generation=1538051042759807\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3b8bffeb25986a949f398d3644170d39/3901757765529302121;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/conddel?alt=json\u0026generation=1538051042759807\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "12141" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:02 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:02 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051342000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrcf20:4198,/bns/yr/borg/yr/bns/blobstore2/bitpusher/0.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=4susW6KXNsSxkATZ74bIAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/0.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/0:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWXY2MTJyUVRiNE1ZWEtqdTZPQnktbmItdVBNRDJaTWRzU01HMFpSR3hiSUNwbUhWbXVFRlVEYjNkTURQUjc1OFJLMUtDNmEtZllTQWE5RWNYMXNaSlY3M0xWLXRnRmNOZFphckJMak9JSWRJRG5vSG4ySzcwTHpLdXhZNzBBSWU1TlFzU0F3WWIwLWU1WHlKZDk4WFlQLXBBT2tTVzBraFdXblVlZnpmYzExdWZUeHZnN2llS0hTWGswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqwKNtC0lvvXvOJjHGNLri9TO3nTa-DXd6rZS0MXi720b899Swzs8NBB5krLGaiWnNU-xfLgFxZkpEx1KGeC5pOwR2jhg" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29uZGRlbCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfTk9UX0ZPVU5EOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbmRkZWxcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo3Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb25kZGVsXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPU5PVF9GT1VORCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfTk9UX0ZPVU5EOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbmRkZWxcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo3Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb25kZGVsXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPW5vdEZvdW5kLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5OT1RfRk9VTkQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfTk9UX0ZPVU5EOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbmRkZWxcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo3Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb25kZGVsXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5uYW1lLCBtZXNzYWdlPU5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29uZGRlbCwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5uYW1lLCBtZXNzYWdlPU5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29uZGRlbCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb25kZGVsOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6T0JKRUNUX05PVF9GT1VORDogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb25kZGVsXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6NzcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjIzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5kZWxldGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjExMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29uZGRlbFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDA0LCJtZXNzYWdlIjoiTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb25kZGVsIn19" + } + }, + { + "ID": "dc490fa6bbb48c34", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/conddel?alt=json\u0026ifMetagenerationMatch=2\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0e0594c6a559ad76638088af4a82573c/4732851225181833145;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/conddel?alt=json\u0026ifMetagenerationMatch=2\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 412, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "11943" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:03 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:03 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051342000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlh82:4312,/bns/yw/borg/yw/bns/blobstore2/bitpusher/115.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=4susW6SoPI-jhQTSyrfwDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/115.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/115:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWXY2MTJyUVRiNE1ZWEtqdTZPQnktbmItdVBNRDJaTWRzU01HMFpSR3hiSUNwbUhWbXVFRlVEYjNkTURQUjc1OFJLMUtDNmEtZllTQWE5RWNYMXNaSlY3M0xWLXRnRmNOZFphckJMak9JSWRJRG5vSG4ySzcwTHpLdXhZNzBBSWU1TlFzU0F3WWIwLWU1WHlKZDk4WFlQLXBBT2tTVzBraFdXblVlZnpmYzExdWZUeHZnN2llS0hTWGswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpW9PNlTnX1_YvdYKwOuxuOLQ-G9xx8dVMlb7UazrnA4HBJpJsWjEmrvJ67r6x6o2wfh82shQUEuCJjClvBiQayN7R-Tg" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImNvbmRpdGlvbk5vdE1ldCIsIm1lc3NhZ2UiOiJQcmVjb25kaXRpb24gRmFpbGVkIiwibG9jYXRpb25UeXBlIjoiaGVhZGVyIiwibG9jYXRpb24iOiJJZi1NYXRjaCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpJTkNPUlJFQ1RfTUVUQV9HRU5FUkFUSU9OX1NQRUNJRklFRDogRXhwZWN0ZWQgbWV0YWRhdGEgZ2VuZXJhdGlvbiB0byBtYXRjaCAyLCBidXQgYWN0dWFsIHZhbHVlIHdhcyAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjc3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBFeHBlY3RlZCBtZXRhZGF0YSBnZW5lcmF0aW9uIHRvIG1hdGNoIDIsIGJ1dCBhY3R1YWwgdmFsdWUgd2FzIDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVBSRUNPTkRJVElPTl9GQUlMRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6SU5DT1JSRUNUX01FVEFfR0VORVJBVElPTl9TUEVDSUZJRUQ6IEV4cGVjdGVkIG1ldGFkYXRhIGdlbmVyYXRpb24gdG8gbWF0Y2ggMiwgYnV0IGFjdHVhbCB2YWx1ZSB3YXMgMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo3Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogRXhwZWN0ZWQgbWV0YWRhdGEgZ2VuZXJhdGlvbiB0byBtYXRjaCAyLCBidXQgYWN0dWFsIHZhbHVlIHdhcyAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1wcmVjb25kaXRpb25GYWlsZWQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkNPTkRJVElPTl9OT1RfTUVULCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6SU5DT1JSRUNUX01FVEFfR0VORVJBVElPTl9TUEVDSUZJRUQ6IEV4cGVjdGVkIG1ldGFkYXRhIGdlbmVyYXRpb24gdG8gbWF0Y2ggMiwgYnV0IGFjdHVhbCB2YWx1ZSB3YXMgMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo3Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogRXhwZWN0ZWQgbWV0YWRhdGEgZ2VuZXJhdGlvbiB0byBtYXRjaCAyLCBidXQgYWN0dWFsIHZhbHVlIHdhcyAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUNPTkRJVElPTl9OT1RfTUVULCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9bnVsbCwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWhlYWRlcnMuSWYtTWF0Y2gsIG1lc3NhZ2U9UHJlY29uZGl0aW9uIEZhaWxlZCwgcmVhc29uPWNvbmRpdGlvbk5vdE1ldCwgcnBjQ29kZT00MTJ9IFByZWNvbmRpdGlvbiBGYWlsZWQ6IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpJTkNPUlJFQ1RfTUVUQV9HRU5FUkFUSU9OX1NQRUNJRklFRDogRXhwZWN0ZWQgbWV0YWRhdGEgZ2VuZXJhdGlvbiB0byBtYXRjaCAyLCBidXQgYWN0dWFsIHZhbHVlIHdhcyAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjc3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBFeHBlY3RlZCBtZXRhZGF0YSBnZW5lcmF0aW9uIHRvIG1hdGNoIDIsIGJ1dCBhY3R1YWwgdmFsdWUgd2FzIDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MTIsIm1lc3NhZ2UiOiJQcmVjb25kaXRpb24gRmFpbGVkIn19" + } + }, + { + "ID": "7b4d64f669c0333c", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/conddel?alt=json\u0026ifMetagenerationNotMatch=1\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1f52dac0b93933518d0bdbf98d760edf/5491888194603031048;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/conddel?alt=json\u0026ifMetagenerationNotMatch=1\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 304, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:03 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:03 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051342000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrhr16:4228,/bns/yw/borg/yw/bns/blobstore2/bitpusher/147.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=48usW-HOEMnxhQTc04vYDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/147.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/147:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWXY2MTJyUVRiNE1ZWEtqdTZPQnktbmItdVBNRDJaTWRzU01HMFpSR3hiSUNwbUhWbXVFRlVEYjNkTURQUjc1OFJLMUtDNmEtZllTQWE5RWNYMXNaSlY3M0xWLXRnRmNOZFphckJMak9JSWRJRG5vSG4ySzcwTHpLdXhZNzBBSWU1TlFzU0F3WWIwLWU1WHlKZDk4WFlQLXBBT2tTVzBraFdXblVlZnpmYzExdWZUeHZnN2llS0hTWGswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqXbCw-65-mGU7N9rqCcQdeR9L7gyLR3middMRmDYhL4PflAyi-fWZKa2_Hn6fC_MmZNwUUJhhbQiptY53-x322rayLLA" + ] + }, + "Body": "" + } + }, + { + "ID": "3a3d4e799b1d4ff1", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/conddel?alt=json\u0026generation=1538051042759808\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3614b8bee4c582fd5d488e1e6b9c6a83/6323263129232272727;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/conddel?alt=json\u0026generation=1538051042759808\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:03 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051342000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrih14:4363,/bns/yw/borg/yw/bns/blobstore2/bitpusher/63.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=48usW5qOI4fuN9ytj-AL" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/63.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/63:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWXY2MTJyUVRiNE1ZWEtqdTZPQnktbmItdVBNRDJaTWRzU01HMFpSR3hiSUNwbUhWbXVFRlVEYjNkTURQUjc1OFJLMUtDNmEtZllTQWE5RWNYMXNaSlY3M0xWLXRnRmNOZFphckJMak9JSWRJRG5vSG4ySzcwTHpLdXhZNzBBSWU1TlFzU0F3WWIwLWU1WHlKZDk4WFlQLXBBT2tTVzBraFdXblVlZnpmYzExdWZUeHZnN2llS0hTWGswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoJHiQpNZ-qEzatUz59hED1GW-yo-BCmNHyDwotCZGRLIkp6_KPIVZkVrtmVVKlKI-NqP7C1VOZCKWq1JSFxSk32uIAcw" + ] + }, + "Body": "" + } + }, + { + "ID": "a09383dd9bc5920c", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=7834c061d4a46c74dc809f40f72ea21bc28430ca21d42af796b7c56f7090" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "29f22ce3f51c65ee421feee1bd46b233/7082300098670182311;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS03ODM0YzA2MWQ0YTQ2Yzc0ZGM4MDlmNDBmNzJlYTIxYmMyODQzMGNhMjFkNDJhZjc5NmI3YzU2ZjcwOTANCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJvYmoxIn0KDQotLTc4MzRjMDYxZDRhNDZjNzRkYzgwOWY0MGY3MmVhMjFiYzI4NDMwY2EyMWQ0MmFmNzk2YjdjNTZmNzA5MA0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluDQoNChu2BO3eJ9HctT16IRSaVJ8NCi0tNzgzNGMwNjFkNGE0NmM3NGRjODA5ZjQwZjcyZWEyMWJjMjg0MzBjYTIxZDQyYWY3OTZiN2M1NmY3MDkwLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3243" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:04 GMT" + ], + "Etag": [ + "CI7Bn9GW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051344000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrjm12:4359,/bns/yv/borg/yv/bns/blobstore2/bitpusher/50.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=5MusW-JakcuzBviUvZAD" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/50.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/50:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqZK45KDcXNpqKxs7RM4nR3KIPATeLgKgB8XtPJRm8ykneziFgQBwXknvRchuyv76v14eoyX1QNT6vGNYl16Tcg_5AEWw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNC41MzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiN3dVRkg4bUREd0hGWXFvN29seGRQZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ0NTMyMzY2JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiKzdSMTFnPT0iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "415cbbb4c411d828", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=51ce82224b1617abfd90683ffa66b3773319b1a8364c2f78256a0cfc75c1" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "73bdb84b0db761fac19f7226ea21ad8b/7913393562617680630;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS01MWNlODIyMjRiMTYxN2FiZmQ5MDY4M2ZmYTY2YjM3NzMzMTliMWE4MzY0YzJmNzgyNTZhMGNmYzc1YzENCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJvYmoyIn0KDQotLTUxY2U4MjIyNGIxNjE3YWJmZDkwNjgzZmZhNjZiMzc3MzMxOWIxYTgzNjRjMmY3ODI1NmEwY2ZjNzVjMQ0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluDQoNCsPZcNJccaSrouZ5qGqfKcMNCi0tNTFjZTgyMjI0YjE2MTdhYmZkOTA2ODNmZmE2NmIzNzczMzE5YjFhODM2NGMyZjc4MjU2YTBjZmM3NWMxLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3243" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:05 GMT" + ], + "Etag": [ + "CNeSxNGW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051344000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnna19:4148,/bns/yx/borg/yx/bns/blobstore2/bitpusher/15.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=5MusW8WsL8bPzwLJ_o3YCA" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/15.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/15:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up2wgYdgpOZhxiQEfC9zZYmEfyDtJdlztDtjrpklLhwzZZlQFaOHUULevuaKs257Y9xrXUNEZ1BHjxOk8Dt_vUcduWQpA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyIiwibmFtZSI6Im9iajIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS4xMzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuMTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjEzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiaDY0bVlxSjJPNTRqcnhHT0pOeUd4UT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajI/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ1MTMyNjMxJmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiM0RLRHFnPT0iLCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "f67034946dd9c5a8", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=090845640f43d87c92783246d30b6758c9a71a1c48bf1fa3f421832a1a1d" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "35e219d1230ad747c0ffbd9bacfec0b6/8672712002720621893;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0wOTA4NDU2NDBmNDNkODdjOTI3ODMyNDZkMzBiNjc1OGM5YTcxYTFjNDhiZjFmYTNmNDIxODMyYTFhMWQNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJvYmovd2l0aC9zbGFzaGVzIn0KDQotLTA5MDg0NTY0MGY0M2Q4N2M5Mjc4MzI0NmQzMGI2NzU4YzlhNzFhMWM0OGJmMWZhM2Y0MjE4MzJhMWExZA0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluDQoNClj7FIqgnZiH3EyVHy/zHpENCi0tMDkwODQ1NjQwZjQzZDg3YzkyNzgzMjQ2ZDMwYjY3NThjOWE3MWExYzQ4YmYxZmEzZjQyMTgzMmExYTFkLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3459" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:05 GMT" + ], + "Etag": [ + "CL6q4tGW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051344000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vril72:4228,/bns/yr/borg/yr/bns/blobstore2/bitpusher/35.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=5cusW6rBFpDv4QSx-464CQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/35.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/35:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqAi9M8gXtYgNBppM0_5Qy48gHgCeBJ2rQNhX_bVIUqNMThN5aQcO9mO1s4tsGd860po8SPIq6U8i8Tp2c-QFHY0S36-Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcyIsIm5hbWUiOiJvYmovd2l0aC9zbGFzaGVzIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuNjI3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjYyN1oiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS42MjdaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6Iis3bVZuNkxUd0RuVjN0Zy9wQ3Jpb3c9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcz9nZW5lcmF0aW9uPTE1MzgwNTEwNDU2MjcxOTgmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoia1NzV1FnPT0iLCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "db2ba221d4332295", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj%2Fwith%2Fslashes?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "55f8bad62f3127c0ef5fccc806d398c4/10263123902492871396;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj%2Fwith%2Fslashes?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3459" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:05 GMT" + ], + "Etag": [ + "CL6q4tGW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnob6:4175,/bns/yx/borg/yx/bns/blobstore2/bitpusher/60.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=5cusW472MoG_zALtjKnABA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/60.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/60:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrrNXgt6uywwej2qFhVm9mxQCs98f0CyuSuOI3cx9Dstby13tllyGHQ1Gsz00qGk2VQyvqv9OnpgVqajrJsHYhsCvoiDg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcyIsIm5hbWUiOiJvYmovd2l0aC9zbGFzaGVzIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuNjI3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjYyN1oiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS42MjdaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6Iis3bVZuNkxUd0RuVjN0Zy9wQ3Jpb3c9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcz9nZW5lcmF0aW9uPTE1MzgwNTEwNDU2MjcxOTgmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoia1NzV1FnPT0iLCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "dc21ca1708a6ecef", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "959f74f11da0fe031209c5ee56fc9a65/11853253236366651523;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3243" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:06 GMT" + ], + "Etag": [ + "CI7Bn9GW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrat7:4174,/bns/yv/borg/yv/bns/blobstore2/bitpusher/349.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=5cusW4DVOdPXgATL46nICA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/349.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/349:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uqglj1Cm20uhsQlokYmNGcuPEqqziisZ8SNgl_7G8Wsygq5_8LpH3AzZgZGyMjI3ollcwmB_Fu3jr2EmRVk1Nr0sEPg5A" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNC41MzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiN3dVRkg4bUREd0hGWXFvN29seGRQZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ0NTMyMzY2JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiKzdSMTFnPT0iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "fd29f689761e4b31", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj2?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "5ef1744d10c7648379162c035275d3ce/13443665140433868065;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj2?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3243" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:06 GMT" + ], + "Etag": [ + "CNeSxNGW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrjd27:4293,/bns/yw/borg/yw/bns/blobstore2/bitpusher/199.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=5susW-XiAsi7N6meoOAN" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/199.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/199:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqgmMt-wtS-BgBfPzVeYLqOCQ0Qmx2zZ1U1FHnzAkejIWwPi4nApt9w5rDFHnWQ1IcBGrR-SRfChmDHctco-1F1ILIAKQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyIiwibmFtZSI6Im9iajIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS4xMzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuMTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjEzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiaDY0bVlxSjJPNTRqcnhHT0pOeUd4UT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajI/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ1MTMyNjMxJmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiM0RLRHFnPT0iLCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "3a99a037e206464a", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "a25e5213318efa4ed40e3e176bf3f0a8/14202702109855000689;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "9984" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:06 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:06 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnfg189:4335,/bns/yx/borg/yx/bns/blobstore2/bitpusher/126.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=5susW4qoB4yRzgKW0YXoBw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/126.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/126:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq8-aSvhpGNPv1tZlVtCWggTQXXV-f_thkZHH9rzlZP4_417Hx7jMyrGCez1n-6RObqAxU6Ykn6e93l54fIxaqB2KyWNg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS42MjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuNjI3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjYyN1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiKzdtVm42TFR3RG5WM3RnL3BDcmlvdz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTUzODA1MTA0NTYyNzE5OCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJrU3NXUWc9PSIsImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNC41MzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiN3dVRkg4bUREd0hGWXFvN29seGRQZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ0NTMyMzY2JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiKzdSMTFnPT0iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMiIsIm5hbWUiOiJvYmoyIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuMTMyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjEzMloiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS4xMzJaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6Img2NG1ZcUoyTzU0anJ4R09KTnlHeFE9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyP2dlbmVyYXRpb249MTUzODA1MTA0NTEzMjYzMSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IjNES0RxZz09IiwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifV19" + } + }, + { + "ID": "87bd688d342c7b80", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ac7c5ab79ebed4a783e660562aa2bb30/15034077040189340608;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "3539" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:06 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:06 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vref6:4304,/bns/yr/borg/yr/bns/blobstore2/bitpusher/7.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=5susW9n6H6WLkAT2zYCwBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/7.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/7:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UodVTmI8-rEEYuBuGV3NiJB5_ZJMdLVpSon2_dvC4U7PFLgToJlhr6reTs3-Fy_euNgshBmySmDhaywOqXEM45PX4Pj4Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwibmV4dFBhZ2VUb2tlbiI6IkNoQnZZbW92ZDJsMGFDOXpiR0Z6YUdWeiIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcyIsIm5hbWUiOiJvYmovd2l0aC9zbGFzaGVzIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuNjI3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjYyN1oiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS42MjdaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6Iis3bVZuNkxUd0RuVjN0Zy9wQ3Jpb3c9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcz9nZW5lcmF0aW9uPTE1MzgwNTEwNDU2MjcxOTgmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoia1NzV1FnPT0iLCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9XX0=" + } + }, + { + "ID": "7b63dd3875d7c28c", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=ChBvYmovd2l0aC9zbGFzaGVz\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "937f7093bd739fcc09bb93cd0d47a9da/15793114009610538511;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=ChBvYmovd2l0aC9zbGFzaGVz\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "3307" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:07 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:07 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrmt5:4328,/bns/yv/borg/yv/bns/blobstore2/bitpusher/272.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=5susW5u9OIWYNtLmguAE" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/272.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/272:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrviMDK5gl_QwiDaGX3mzHAHBar0t6nLEe_ZgxZFdBvPDPwZoNEb0G5YHcmXZ3oxTt2tZcg58WXTi5sLL3cdKn52R-rww" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwibmV4dFBhZ2VUb2tlbiI6IkNnUnZZbW94IiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2NiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEiLCJuYW1lIjoib2JqMSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNC41MzJaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiI3d1VGSDhtRER3SEZZcW83b2x4ZFBnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMT9nZW5lcmF0aW9uPTE1MzgwNTEwNDQ1MzIzNjYmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDQ1MzIzNjYiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiIrN1IxMWc9PSIsImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In1dfQ==" + } + }, + { + "ID": "59779a32ce3325d0", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=CgRvYmox\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d06f76647120968faf6801e7f847bcc2/16624207473574748255;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=CgRvYmox\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "3280" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:07 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:07 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdz80:4263,/bns/yr/borg/yr/bns/blobstore2/bitpusher/117.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=58usW6y2E8KnkASClZioBg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/117.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/117:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq40wlm8PHg-66CKFvxN1syf6zO6TMU7Xj-aJ7JDRDW9tYTHZL1z-WYOQaoHQzcI9BoMQyck1-Q3_V0qsPeeOAqdja9DA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIiLCJuYW1lIjoib2JqMiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjEzMloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS4xMzJaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuMTMyWiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJoNjRtWXFKMk81NGpyeEdPSk55R3hRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMj9nZW5lcmF0aW9uPTE1MzgwNTEwNDUxMzI2MzEmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiIzREtEcWc9PSIsImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In1dfQ==" + } + }, + { + "ID": "46a89f8b19abcfdf", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ce942d957abe25aa51aff8c6a8902b6b/17383525913677689774;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "3539" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:07 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:07 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbs9:4050,/bns/yw/borg/yw/bns/blobstore2/bitpusher/189.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=58usW4OzH9X4hASTgpuYBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/189.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/189:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpQMRp8raCulwW2LTGhYSz7tHVHxIJbJ2q8npzOrKBD6muvVlF2UE51EYCDu_VrFVYkI0Vif55kF4HrCCcrG1sIMrNAqA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwibmV4dFBhZ2VUb2tlbiI6IkNoQnZZbW92ZDJsMGFDOXpiR0Z6YUdWeiIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcyIsIm5hbWUiOiJvYmovd2l0aC9zbGFzaGVzIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuNjI3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjYyN1oiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS42MjdaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6Iis3bVZuNkxUd0RuVjN0Zy9wQ3Jpb3c9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcz9nZW5lcmF0aW9uPTE1MzgwNTEwNDU2MjcxOTgmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoia1NzV1FnPT0iLCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9XX0=" + } + }, + { + "ID": "4af251bb107b46bd", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=ChBvYmovd2l0aC9zbGFzaGVz\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "61ba81076b6b0450edaa3960a50b144b/18214619377625188093;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=ChBvYmovd2l0aC9zbGFzaGVz\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "3307" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:08 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:08 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnbn6:4287,/bns/yx/borg/yx/bns/blobstore2/bitpusher/64.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=58usW8eJOMeMzQK1zJDgDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/64.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/64:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uoi7JdVKHjUAAoH_OUZ1lBy-m08Ahe2SVpkEcrEN8fXfs2-GztOUpsnFM0j4d2DWAVN_wpcAi2bZB8SZ9gaEORasVy2Bw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwibmV4dFBhZ2VUb2tlbiI6IkNnUnZZbW94IiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2NiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEiLCJuYW1lIjoib2JqMSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNC41MzJaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiI3d1VGSDhtRER3SEZZcW83b2x4ZFBnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMT9nZW5lcmF0aW9uPTE1MzgwNTEwNDQ1MzIzNjYmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDQ1MzIzNjYiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiIrN1IxMWc9PSIsImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In1dfQ==" + } + }, + { + "ID": "60d1026a4e479c3a", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=CgRvYmox\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "efd38d87265a668abdf5e34ef236c3d7/527475218995222861;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=1\u0026pageToken=CgRvYmox\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "3280" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:08 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:08 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbp63:4132,/bns/yr/borg/yr/bns/blobstore2/bitpusher/1.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=6MusW4fdE4eTkATnw5OYAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/1.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/1:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UooQI_nQGXwTtfxZywLyy4MI3ZXK3zGGOxqVcN34fwGrkHZvYi96r1Wo-XBskmWVEGXA_QFGBrdOVDNoW-oQ2ruqqXFQw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIiLCJuYW1lIjoib2JqMiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjEzMloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS4xMzJaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuMTMyWiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJoNjRtWXFKMk81NGpyeEdPSk55R3hRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMj9nZW5lcmF0aW9uPTE1MzgwNTEwNDUxMzI2MzEmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiIzREtEcWc9PSIsImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In1dfQ==" + } + }, + { + "ID": "d8d0c6f8532afe45", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=2\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "23aa59ef8b1a656a7a57764481f249e3/1358567583464647580;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=2\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "6767" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:09 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:09 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrd1:4212,/bns/yv/borg/yv/bns/blobstore2/bitpusher/270.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=6MusW6ytLIykNvW7uMAB" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/270.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/270:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqHH0Mn1RwMLRxs4f-RMGTZOM5qbCkUl9e7I3Lom4_LvmRJYFMuxPiPCLqx21QFNhAu6O32MjvHzGYk-Oce_hQ1ILQzoQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwibmV4dFBhZ2VUb2tlbiI6IkNnUnZZbW94IiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS42MjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuNjI3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjYyN1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiKzdtVm42TFR3RG5WM3RnL3BDcmlvdz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTUzODA1MTA0NTYyNzE5OCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJrU3NXUWc9PSIsImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNC41MzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiN3dVRkg4bUREd0hGWXFvN29seGRQZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ0NTMyMzY2JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiKzdSMTFnPT0iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9XX0=" + } + }, + { + "ID": "f3574d5c0c1dda72", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=2\u0026pageToken=CgRvYmox\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "bb79afa8303a06e95456399e4c28d835/2117604548590943979;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=2\u0026pageToken=CgRvYmox\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "3280" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:09 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:09 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrub8:4298,/bns/yv/borg/yv/bns/blobstore2/bitpusher/178.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=6cusW_K_B8TIggSEmZeoDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/178.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/178:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrOkBdaiMksr3Jzhg2qzo2Y0Z8zDuc8pB6dc1y4WcrURwCdoy16OrCLApc-xnSLoDqbIb6Qo3DspgAOuKPTwweB3uT-iQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIiLCJuYW1lIjoib2JqMiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjEzMloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS4xMzJaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuMTMyWiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJoNjRtWXFKMk81NGpyeEdPSk55R3hRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMj9nZW5lcmF0aW9uPTE1MzgwNTEwNDUxMzI2MzEmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiIzREtEcWc9PSIsImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In1dfQ==" + } + }, + { + "ID": "f2f711bb69faeb45", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=2\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9f42f8b63cd1e8a51789f59550f90a39/2948979483220119867;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=2\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "6767" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:09 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:09 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbp63:4132,/bns/yv/borg/yv/bns/blobstore2/bitpusher/140.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=6cusW_faH5KCgwS2iqKgDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/140.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/140:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpR3T9vRuVsBcJqCxFkxMS1393TLzXnM1FmvP76TVSQezRyyfupQfblGucwkpaj_g19hxNbevh1tp8ZTfn1r2Bc4_fikA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwibmV4dFBhZ2VUb2tlbiI6IkNnUnZZbW94IiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS42MjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuNjI3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjYyN1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiKzdtVm42TFR3RG5WM3RnL3BDcmlvdz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTUzODA1MTA0NTYyNzE5OCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJrU3NXUWc9PSIsImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNC41MzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiN3dVRkg4bUREd0hGWXFvN29seGRQZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ0NTMyMzY2JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiKzdSMTFnPT0iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9XX0=" + } + }, + { + "ID": "8808fafb9637c238", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=2\u0026pageToken=CgRvYmox\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "a783f696c9821dde0fd569cacc970f59/3708016452658094986;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=2\u0026pageToken=CgRvYmox\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "3280" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:10 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:10 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlh9:4090,/bns/yr/borg/yr/bns/blobstore2/bitpusher/84.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=6cusW6PyOczukAPMwpbQAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/84.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/84:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoiYRTaEq7pO9cBg2viegrNBjlBrmXfkEMJiWvA6FcAMx4uUrVvCmUdM93Uhqx9YmCu6E3EXlUUzXOssXx0WjUTvGIrtQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIiLCJuYW1lIjoib2JqMiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjEzMloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS4xMzJaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuMTMyWiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJoNjRtWXFKMk81NGpyeEdPSk55R3hRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMj9nZW5lcmF0aW9uPTE1MzgwNTEwNDUxMzI2MzEmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiIzREtEcWc9PSIsImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In1dfQ==" + } + }, + { + "ID": "177ae0685adc2ee1", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=3\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "5f216de33683069c9803469708b404e9/4539109916605593305;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=3\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "9984" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:10 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:10 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vreb18:4023,/bns/yr/borg/yr/bns/blobstore2/bitpusher/12.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=6susW8W5E9COkATL9oqABA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/12.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/12:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrxfEZ8Nc3yr1LWDWGqnj6D1KUzIsYSBf26j_M5guMAuvNENKt2tnFliV-C-5T7Y7GZ2oz11YTDoU3V2iiJnXoWOT7tgA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS42MjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuNjI3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjYyN1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiKzdtVm42TFR3RG5WM3RnL3BDcmlvdz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTUzODA1MTA0NTYyNzE5OCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJrU3NXUWc9PSIsImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNC41MzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiN3dVRkg4bUREd0hGWXFvN29seGRQZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ0NTMyMzY2JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiKzdSMTFnPT0iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMiIsIm5hbWUiOiJvYmoyIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuMTMyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjEzMloiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS4xMzJaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6Img2NG1ZcUoyTzU0anJ4R09KTnlHeFE9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyP2dlbmVyYXRpb249MTUzODA1MTA0NTEzMjYzMSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IjNES0RxZz09IiwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifV19" + } + }, + { + "ID": "4c5d5ec2f5ac82a1", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=3\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "290553f278ed99d3bfaaa4e200ee8a41/5298428356708469033;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=3\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "9984" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:11 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:11 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrvu4:4011,/bns/yw/borg/yw/bns/blobstore2/bitpusher/68.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=6susW9aYLIHrhATap5foAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/68.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/68:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqqTZWUEdY633nBYemRmInVkovwfiLLhIYWVskV7mfCjnjlUvTl5hlDPCd2sCOQGKvDPLnR0g6w_Kak_vUGtjET-5a5WA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS42MjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuNjI3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjYyN1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiKzdtVm42TFR3RG5WM3RnL3BDcmlvdz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTUzODA1MTA0NTYyNzE5OCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJrU3NXUWc9PSIsImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNC41MzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiN3dVRkg4bUREd0hGWXFvN29seGRQZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ0NTMyMzY2JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiKzdSMTFnPT0iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMiIsIm5hbWUiOiJvYmoyIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuMTMyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjEzMloiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS4xMzJaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6Img2NG1ZcUoyTzU0anJ4R09KTnlHeFE9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyP2dlbmVyYXRpb249MTUzODA1MTA0NTEzMjYzMSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IjNES0RxZz09IiwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifV19" + } + }, + { + "ID": "dbf2b3beca4073fe", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=13\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d4daed5dc66c10342d5068cd5717a2ab/6057465326129667192;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=13\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "9984" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:11 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:11 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrnb2:4089,/bns/yv/borg/yv/bns/blobstore2/bitpusher/59.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=68usW_LfB8jAggTmnbjABA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/59.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/59:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpVhzCQ4FNrnsz83C_F7ZJW_zkPRALyju0_LUrPz4dA0kD5-W_YcNRRB5ipUN8YDQ2ZOVdJeF9f5Ead7ZrYd-yS_oOJrw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS42MjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuNjI3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjYyN1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiKzdtVm42TFR3RG5WM3RnL3BDcmlvdz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTUzODA1MTA0NTYyNzE5OCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJrU3NXUWc9PSIsImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNC41MzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiN3dVRkg4bUREd0hGWXFvN29seGRQZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ0NTMyMzY2JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiKzdSMTFnPT0iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMiIsIm5hbWUiOiJvYmoyIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuMTMyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjEzMloiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS4xMzJaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6Img2NG1ZcUoyTzU0anJ4R09KTnlHeFE9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyP2dlbmVyYXRpb249MTUzODA1MTA0NTEzMjYzMSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IjNES0RxZz09IiwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifV19" + } + }, + { + "ID": "e8813cef66890896", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=13\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "62aa9d0cab4f9a0da9ef03336c517f21/6888558790093942471;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026maxResults=13\u0026pageToken=\u0026prefix=obj\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "9984" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:11 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:11 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnlz21:4176,/bns/yx/borg/yx/bns/blobstore2/bitpusher/98.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=68usW_HzH5C5zwK1qK7ABg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/98.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/98:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrkNNiEw_PwZc-Zf2lHJ96tTZm1AUqfzqSG48wX2_Lyzi-K-RPTcM4QEfUyXYjSKbb_SWOe1xSTGRQBMnW95mGmeG8pAQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzIiwibmFtZSI6Im9iai93aXRoL3NsYXNoZXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS42MjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuNjI3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjYyN1oiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiKzdtVm42TFR3RG5WM3RnL3BDcmlvdz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzP2dlbmVyYXRpb249MTUzODA1MTA0NTYyNzE5OCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJrU3NXUWc9PSIsImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNC41MzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiN3dVRkg4bUREd0hGWXFvN29seGRQZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ0NTMyMzY2JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiKzdSMTFnPT0iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMiIsIm5hbWUiOiJvYmoyIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuMTMyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjEzMloiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS4xMzJaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6Img2NG1ZcUoyTzU0anJ4R09KTnlHeFE9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyP2dlbmVyYXRpb249MTUzODA1MTA0NTEzMjYzMSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDUxMzI2MzEiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IjNES0RxZz09IiwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifV19" + } + }, + { + "ID": "d8438a79406c3ee7", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e34a37eefc5f30bda40070484796f0c8/8478970689849414758;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"ef05051fc9830f01c562aa3ba25c5d3e\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:04 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:04 GMT" + ], + "X-Goog-Generation": [ + "1538051044532366" + ], + "X-Goog-Hash": [ + "crc32c=+7R11g==", + "md5=7wUFH8mDDwHFYqo7olxdPg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/36,/bns/xh/borg/xh/bns/blobstore2/bitpusher/67.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=68usW-PjO8atswaMgIygCQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/67.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/67:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoN20jwQv6iqBStn8N8_-tHO-IskyynbFbYmE1mHi1U9xJb6Y2n3w85qIy_ia8QkIr7pFOugsjvxJjlyeGqhAvDrPmvpQ" + ] + }, + "Body": "G7YE7d4n0dy1PXohFJpUnw==" + } + }, + { + "ID": "fd51799008bfea12", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b351f3135416bf5a89a34b654a1b3303/10069381494421780740;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"ef05051fc9830f01c562aa3ba25c5d3e\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:04 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:04 GMT" + ], + "X-Goog-Generation": [ + "1538051044532366" + ], + "X-Goog-Hash": [ + "crc32c=+7R11g==", + "md5=7wUFH8mDDwHFYqo7olxdPg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/25,/bns/xh/borg/xh/bns/blobstore2/bitpusher/80.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW9CDCs6kswbMy5uwDQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/80.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/80:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo5sFr6jrRtig10NXjMHaOuCabFiHZyrLqEZXpEdYTzqQD2zOhEp6iVt_78e54QX32MpRWEinlwSQbwTIdqrl9IOW_eUQ" + ] + }, + "Body": "G7YE7d4n0dy1PXohFJpUnw==" + } + }, + { + "ID": "6c56bc3a2067d53c", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj2", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "fbdec27742a732b75803ee6a32401901/11659793398472155043;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj2" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"87ae2662a2763b9e23af118e24dc86c5\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:05 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:05 GMT" + ], + "X-Goog-Generation": [ + "1538051045132631" + ], + "X-Goog-Hash": [ + "crc32c=3DKDqg==", + "md5=h64mYqJ2O54jrxGOJNyGxQ==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/8,/bns/xh/borg/xh/bns/blobstore2/bitpusher/28.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW4aSDYuhswbl1qKYBg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/28.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/28:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpfFy79R8hO4AoIDRUlP96iSXUSqB11GvlDhxq4NcGDXbTVxdErTejn5DnMjFhugLOAuP-p9uQDPyFy4be5vpakmpIg0w" + ] + }, + "Body": "w9lw0lxxpKui5nmoap8pww==" + } + }, + { + "ID": "e68e0aa406a7ace6", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj2", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "436c06c3631f6877cb6b0adeb4d42c30/13249923827562660930;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj2" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"87ae2662a2763b9e23af118e24dc86c5\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:05 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:05 GMT" + ], + "X-Goog-Generation": [ + "1538051045132631" + ], + "X-Goog-Hash": [ + "crc32c=3DKDqg==", + "md5=h64mYqJ2O54jrxGOJNyGxQ==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/10,/bns/xh/borg/xh/bns/blobstore2/bitpusher/86.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW7OVE-6oswaP1oK4DA" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/86.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/86:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrkIt55pMPwjOM5myY8ijTv9lEmVrnGGv9NO_S-cG3qqvbRihzY7EKU2bhQVR1P9es7xJ7zsET3Av7yqTQ05O7kSs8vHA" + ] + }, + "Body": "w9lw0lxxpKui5nmoap8pww==" + } + }, + { + "ID": "0908749e71e23161", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj/with/slashes", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "46b71c05144a5810a4f56acc0f1e1817/14840335731613100768;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj/with/slashes" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"fbb9959fa2d3c039d5ded83fa42ae2a3\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:05 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:05 GMT" + ], + "X-Goog-Generation": [ + "1538051045627198" + ], + "X-Goog-Hash": [ + "crc32c=kSsWQg==", + "md5=+7mVn6LTwDnV3tg/pCriow==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/34,/bns/xh/borg/xh/bns/blobstore2/bitpusher/64.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW5yxFsKmswayqIGIDg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/64.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/64:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo7UsAfQNdMNAdb2cU08Ktr6iNP4KbzoyHv46mQTZhM3d4zXlwFI8AcTFAPnQBWXJ_AUMDTKPS3LKGs617c7Shqv8l-rg" + ] + }, + "Body": "WPsUiqCdmIfcTJUfL/MekQ==" + } + }, + { + "ID": "3a6945ba8c54d3d0", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj/with/slashes", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e18289f7643f0221c20d31d88e440330/16358691141153951615;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj/with/slashes" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"fbb9959fa2d3c039d5ded83fa42ae2a3\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:05 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:05 GMT" + ], + "X-Goog-Generation": [ + "1538051045627198" + ], + "X-Goog-Hash": [ + "crc32c=kSsWQg==", + "md5=+7mVn6LTwDnV3tg/pCriow==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/10,/bns/xh/borg/xh/bns/blobstore2/bitpusher/62.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW9KVHMSmswaLopWwDA" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/62.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/62:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq1_6wNvDu73BRMfGjIe95yVvDDKtlIqWWmlfUxcAWUAI5ZYPk8bBJS5SzvrFzdt-g5gRdnfa1S1wWBolex4S0h4SuWRQ" + ] + }, + "Body": "WPsUiqCdmIfcTJUfL/MekQ==" + } + }, + { + "ID": "55395569801967d3", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1", + "Proto": "HTTP/1.1", + "Header": { + "Authorization": [ + "REDACTED" + ], + "Range": [ + "bytes=0-15" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "835d9af2500c84822019536da352936f/17948820470732829982;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"ef05051fc9830f01c562aa3ba25c5d3e\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:04 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:04 GMT" + ], + "X-Goog-Generation": [ + "1538051044532366" + ], + "X-Goog-Hash": [ + "crc32c=+7R11g==", + "md5=7wUFH8mDDwHFYqo7olxdPg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/6,/bns/xh/borg/xh/bns/blobstore2/bitpusher/52.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW6XiH7Cqswa-pIPADw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/52.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/52:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur7qd9oilYQm2rBqGKum--l_-DYiYr2wxV2HJ9nTGE4RjGaDoqeOfB5G5nmQkUR3Tq5M6AzVrwD5yKlNjiyN4-R2MFMNA" + ] + }, + "Body": "G7YE7d4n0dy1PXohFJpUnw==" + } + }, + { + "ID": "d869b9305381b8dc", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1", + "Proto": "HTTP/1.1", + "Header": { + "Authorization": [ + "REDACTED" + ], + "Range": [ + "bytes=0-7" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4402daf1c2931122ca6c23a4457c8567/1092769776067205820;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 206, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "8" + ], + "Content-Range": [ + "bytes 0-7/16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"ef05051fc9830f01c562aa3ba25c5d3e\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:04 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:04 GMT" + ], + "X-Goog-Generation": [ + "1538051044532366" + ], + "X-Goog-Hash": [ + "crc32c=+7R11g==", + "md5=7wUFH8mDDwHFYqo7olxdPg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/15,/bns/xh/borg/xh/bns/blobstore2/bitpusher/39.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW5uYIouoswbSkZD4Bg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/39.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/39:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur7al2tIDOVB8w1OYnq2HBh8-8N1uPecM3R2P83XNw62Pj2fwUZJ5gH9hLQ6Jcyl8MA_3jTwOes2TDZayRnvMI8GTe6ng" + ] + }, + "Body": "G7YE7d4n0dw=" + } + }, + { + "ID": "0a535e86355c12ac", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1", + "Proto": "HTTP/1.1", + "Header": { + "Authorization": [ + "REDACTED" + ], + "Range": [ + "bytes=8-23" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b0441aa4a7eab03a43e60c8b286ebd0f/2683181680117579867;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 206, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "8" + ], + "Content-Range": [ + "bytes 8-15/16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"ef05051fc9830f01c562aa3ba25c5d3e\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:04 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:04 GMT" + ], + "X-Goog-Generation": [ + "1538051044532366" + ], + "X-Goog-Hash": [ + "crc32c=+7R11g==", + "md5=7wUFH8mDDwHFYqo7olxdPg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/3,/bns/xh/borg/xh/bns/blobstore2/bitpusher/55.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW-L2JO2kswaT64GQDQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/55.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/55:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrmRn0K293XJuaEyQYPoTS5Bbd-uKT12V8mzmrOYMj5aMCOa6ndse3iLY_TY5wzWyI4I38vJ3A0G6T7MTHHfrIxetCXaw" + ] + }, + "Body": "tT16IRSaVJ8=" + } + }, + { + "ID": "ad1c8f3bf07175cb", + "Request": { + "Method": "HEAD", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1", + "Proto": "HTTP/1.1", + "Header": { + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d6872a13ef19e6aded259a214ad6449e/4273593584184731130;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"ef05051fc9830f01c562aa3ba25c5d3e\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:04 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:04 GMT" + ], + "X-Goog-Generation": [ + "1538051044532366" + ], + "X-Goog-Hash": [ + "crc32c=+7R11g==", + "md5=7wUFH8mDDwHFYqo7olxdPg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/35,/bns/xh/borg/xh/bns/blobstore2/bitpusher/59.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW-XcJ4OhswbwjYa4Bw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/59.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/59:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrOJk9tHBq0OUCi9A8y0xXe7IslqrVOVGYdH5Mbp-7Snhb8xEW8qc8GIb9lIWnFCETqHRZh7ONRc1Xzf5HG9W0jws0QSA" + ] + }, + "Body": "" + } + }, + { + "ID": "3c4f9ce008c97f86", + "Request": { + "Method": "HEAD", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1", + "Proto": "HTTP/1.1", + "Header": { + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "72e113b79d3ca5d01ad7071131993c6b/5863724013258525592;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"ef05051fc9830f01c562aa3ba25c5d3e\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:04 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:04 GMT" + ], + "X-Goog-Generation": [ + "1538051044532366" + ], + "X-Goog-Hash": [ + "crc32c=+7R11g==", + "md5=7wUFH8mDDwHFYqo7olxdPg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/21,/bns/xh/borg/xh/bns/blobstore2/bitpusher/2.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW9GTKo6kswbkhYKoAQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/2.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/2:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ura7_vBiJ9u_QXx62sETf4NCB8WaOdF-C-fdKE7JvfU4jceQVdFuFPknKkVLmlPbkF6-w60s3MPUSr_WZEW6hi7welwbg" + ] + }, + "Body": "" + } + }, + { + "ID": "649ec0e8258f8230", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1", + "Proto": "HTTP/1.1", + "Header": { + "Authorization": [ + "REDACTED" + ], + "Range": [ + "bytes=8-" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "312d714b782e4823e2766239e9764a82/7454134817830826039;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 206, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "8" + ], + "Content-Range": [ + "bytes 8-15/16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"ef05051fc9830f01c562aa3ba25c5d3e\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:04 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:04 GMT" + ], + "X-Goog-Generation": [ + "1538051044532366" + ], + "X-Goog-Hash": [ + "crc32c=+7R11g==", + "md5=7wUFH8mDDwHFYqo7olxdPg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/24,/bns/xh/borg/xh/bns/blobstore2/bitpusher/26.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW8nZLOusswbax6LwDA" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/26.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/26:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpK-jwiYqScQfGxJj6D6ewVKGX-nZjT0EmiiH4Tfi66bSPjtZh5-kVGuI6Ckly3VoTzW_sJD6d_YuMNo3fLYyALhrBNyA" + ] + }, + "Body": "tT16IRSaVJ8=" + } + }, + { + "ID": "be676a0036e215e9", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1", + "Proto": "HTTP/1.1", + "Header": { + "Authorization": [ + "REDACTED" + ], + "Range": [ + "bytes=0-31" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "f92a4564cfdb1f40093f36bf14fcf5ab/9044546721881200342;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"ef05051fc9830f01c562aa3ba25c5d3e\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:04 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:04 GMT" + ], + "X-Goog-Generation": [ + "1538051044532366" + ], + "X-Goog-Hash": [ + "crc32c=+7R11g==", + "md5=7wUFH8mDDwHFYqo7olxdPg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/9,/bns/xh/borg/xh/bns/blobstore2/bitpusher/21.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW4m5L8msswb5q6WgAg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/21.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/21:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UppB6wgT197zLhkNdO97CZkj9y76ysWm6rz4qIrigBJOHEncPQvnSZDWNtkK6WWA1RmDPZuTTbqvJNssVtWwNLVMAAUxA" + ] + }, + "Body": "G7YE7d4n0dy1PXohFJpUnw==" + } + }, + { + "ID": "563f2298ed35180b", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1", + "Proto": "HTTP/1.1", + "Header": { + "Authorization": [ + "REDACTED" + ], + "Range": [ + "bytes=32-41" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "2cf3892a10fb83adcb8a69720664c6a0/10634958621653515124;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 416, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "167" + ], + "Content-Type": [ + "application/xml; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "\"ef05051fc9830f01c562aa3ba25c5d3e\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:04 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:04 GMT" + ], + "X-Goog-Generation": [ + "1538051044532366" + ], + "X-Goog-Hash": [ + "crc32c=+7R11g==", + "md5=7wUFH8mDDwHFYqo7olxdPg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/34,/bns/xh/borg/xh/bns/blobstore2/bitpusher/56.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW5XDMoqlswbzlYawCw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/56.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/56:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoID9l6tyltcSHgLV69E97wXKAD-WE81yY0iXvNFvdpm015fzIqnhV2V7ZMBUN7MDdQrniSPTv19biVJsQbMFKmQuXGeA" + ] + }, + "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+SW52YWxpZFJhbmdlPC9Db2RlPjxNZXNzYWdlPlRoZSByZXF1ZXN0ZWQgcmFuZ2UgY2Fubm90IGJlIHNhdGlzZmllZC48L01lc3NhZ2U+PERldGFpbHM+Ynl0ZXM9MzItNDE8L0RldGFpbHM+PC9FcnJvcj4=" + } + }, + { + "ID": "5f4b31aaff5df0cc", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "21c5e6e73109926f023bb79cdaafcc44/12225089055022145811;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3243" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:12 GMT" + ], + "Etag": [ + "CI7Bn9GW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbq123:4158,/bns/yr/borg/yr/bns/blobstore2/bitpusher/55.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW6y8Ncir4QTO6IXwDg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/55.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/55:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrAONkHQISdEo7cEP4cm1vetvXWVS9a80QVkqu9SZg59_a9lpik1K4gnAkyp_eO4UAV121zCztwRsueq59YHW-EBBWI4w" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNC41MzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiN3dVRkg4bUREd0hGWXFvN29seGRQZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ0NTMyMzY2JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSTdCbjlHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiKzdSMTFnPT0iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "e47f597968365398", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3076aa16329e4789b551e820d99ef754/13815500959089297074;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2492" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:13 GMT" + ], + "Etag": [ + "CAU=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:13 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbo6:4135,/bns/yv/borg/yv/bns/blobstore2/bitpusher/181.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7MusW6jMOcfugwS5tIzoDQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/181.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/181:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up1-8QHizF8BXIhjqFiS8CwZD-iwIM6O8OdKS_SE-Vh6DpGI70tPsNdURqd04DRDsV-RUrtM6T-zuesc7-KgKVw6mMOhw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjM6NTIuMzU1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjAyLjEyOVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjUiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQVU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBVT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FVPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FVPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInZlcnNpb25pbmciOnsiZW5hYmxlZCI6ZmFsc2V9LCJsaWZlY3ljbGUiOnsicnVsZSI6W3siYWN0aW9uIjp7InR5cGUiOiJEZWxldGUifSwiY29uZGl0aW9uIjp7ImFnZSI6MzB9fV19LCJsYWJlbHMiOnsibDEiOiJ2MiIsIm5ldyI6Im5ldyJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQVU9In0=" + } + }, + { + "ID": "40317a730e582890", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/copy-obj1?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "808117ec5164e049873a57f9d75f176c/15405911759349984336;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/copy-obj1?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3426" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:13 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051353000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrwe17:4005,/bns/yr/borg/yr/bns/blobstore2/bitpusher/112.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7cusW7_8DoiVkASQyLSgCw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/112.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/112:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoUNvhhQ0zd70YwDbOepu-hwK9grkIt_2RiEejT3Rj3AMn9HDTHdDZ-5r6mOw20lJBouR5jU8fLFoy7vo9bNAnCUOQGTQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMTYiLCJvYmplY3RTaXplIjoiMTYiLCJkb25lIjp0cnVlLCJyZXNvdXJjZSI6eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajEvMTUzODA1MTA1MzcyNjgyOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvcHktb2JqMSIsIm5hbWUiOiJjb3B5LW9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1MzcyNjgyOCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxMy43MjZaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MTMuNzI2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjEzLjcyNloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiN3dVRkg4bUREd0hGWXFvN29seGRQZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvcHktb2JqMT9nZW5lcmF0aW9uPTE1MzgwNTEwNTM3MjY4MjgmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29weS1vYmoxLzE1MzgwNTEwNTM3MjY4MjgvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb3B5LW9iajEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29weS1vYmoxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTM3MjY4MjgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNPelkwTldXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajEvMTUzODA1MTA1MzcyNjgyOC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb3B5LW9iajEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvcHktb2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDUzNzI2ODI4IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNPelkwTldXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajEvMTUzODA1MTA1MzcyNjgyOC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb3B5LW9iajEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvcHktb2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDUzNzI2ODI4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDT3pZME5XVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29weS1vYmoxLzE1MzgwNTEwNTM3MjY4MjgvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvcHktb2JqMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvcHktb2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDUzNzI2ODI4IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ096WTBOV1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiIrN1IxMWc9PSIsImV0YWciOiJDT3pZME5XVzI5MENFQUU9In19" + } + }, + { + "ID": "7c3fbfa4c28e7623", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/copy-obj1?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "31" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1efea7e671407b24046cb68f9467a222/16996042192735392239;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/copy-obj1?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJjb250ZW50RW5jb2RpbmciOiJpZGVudGl0eSJ9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3392" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:14 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051353000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnv70:4268,/bns/yw/borg/yw/bns/blobstore2/bitpusher/172.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7cusW9PCO4GQhwSdyY-ADQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/172.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/172:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up33epgf_s87PSifY-y8vQLl43RsrHASyr8ALFMlZw8YfpoG2NAwQES9MZmUZyba-yAq30TyHZ99rRIenUr9Dc1ui9rsw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMTYiLCJvYmplY3RTaXplIjoiMTYiLCJkb25lIjp0cnVlLCJyZXNvdXJjZSI6eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajEvMTUzODA1MTA1NDQyODYzOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvcHktb2JqMSIsIm5hbWUiOiJjb3B5LW9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1NDQyODYzOCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxNC40MjhaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MTQuNDI4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjE0LjQyOFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiN3dVRkg4bUREd0hGWXFvN29seGRQZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvcHktb2JqMT9nZW5lcmF0aW9uPTE1MzgwNTEwNTQ0Mjg2MzgmYWx0PW1lZGlhIiwiY29udGVudEVuY29kaW5nIjoiaWRlbnRpdHkiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajEvMTUzODA1MTA1NDQyODYzOC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvcHktb2JqMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjb3B5LW9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1NDQyODYzOCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ043RCs5V1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvcHktb2JqMS8xNTM4MDUxMDU0NDI4NjM4L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvcHktb2JqMS9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29weS1vYmoxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTQ0Mjg2MzgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ043RCs5V1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvcHktb2JqMS8xNTM4MDUxMDU0NDI4NjM4L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvcHktb2JqMS9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29weS1vYmoxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTQ0Mjg2MzgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNON0QrOVdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajEvMTUzODA1MTA1NDQyODYzOC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29weS1vYmoxL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29weS1vYmoxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTQ0Mjg2MzgiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTjdEKzlXVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Iis3UjExZz09IiwiZXRhZyI6IkNON0QrOVdXMjkwQ0VBRT0ifX0=" + } + }, + { + "ID": "1784d4812eaeaade", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "193" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "818f5c53c45ebea5a3d0031cb5bfdc65/139991498052990861;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJhY2wiOlt7ImVudGl0eSI6ImRvbWFpbi1nb29nbGUuY29tIiwicm9sZSI6IlJFQURFUiJ9XSwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJjb250ZW50VHlwZSI6InRleHQvaHRtbCIsIm1ldGFkYXRhIjp7ImtleSI6InZhbHVlIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2151" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:14 GMT" + ], + "Etag": [ + "CI7Bn9GW290CEAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051354000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrs186:4456,/bns/yw/borg/yw/bns/blobstore2/bitpusher/88.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7susW4HKIYHThATpoLP4DQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/88.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/88:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoYxKDkKtLtPDhSLnUQOcGlMYcLsZCmb_BMAWiEx4kPh-aSCKvKxmxQ2Pyx3GmtzGPQfEH1BDK7SXJINgP-EsUMPejF4g" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoidGV4dC9odG1sIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxNC42NzBaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiI3d1VGSDhtRER3SEZZcW83b2x4ZFBnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMT9nZW5lcmF0aW9uPTE1MzgwNTEwNDQ1MzIzNjYmYWx0PW1lZGlhIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJtZXRhZGF0YSI6eyJrZXkiOiJ2YWx1ZSJ9LCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxL2FjbC9kb21haW4tZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6ImRvbWFpbi1nb29nbGUuY29tIiwicm9sZSI6IlJFQURFUiIsImRvbWFpbiI6Imdvb2dsZS5jb20iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiKzdSMTFnPT0iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFJPSJ9" + } + }, + { + "ID": "ed8837066cd682d4", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "120" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e31962cb701aec17955519bbc8994ef5/1658346907593841708;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJjb250ZW50TGFuZ3VhZ2UiOm51bGwsImNvbnRlbnRUeXBlIjpudWxsLCJtZXRhZGF0YSI6bnVsbH0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2075" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:14 GMT" + ], + "Etag": [ + "CI7Bn9GW290CEAM=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051354000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnen196:4410,/bns/yx/borg/yx/bns/blobstore2/bitpusher/115.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=7susW7KPMIigzALuzLGYBQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/115.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/115:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uqbu1PynGWlbjSeyTQwegY8fK2Ywxed0wJDknj_zqpsVed8gDtlvoWg8oM4ZKcNajzVapPj-mNAsDPj42T-Uc4lmxcHFg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxIiwibmFtZSI6Im9iajEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NDUzMjM2NiIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNC41MzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MTQuODg4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiN3dVRkg4bUREd0hGWXFvN29seGRQZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajE/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ0NTMyMzY2JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2Ni9kb21haW4tZ29vZ2xlLmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDSTdCbjlHVzI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoxL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFNPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiIrN1IxMWc9PSIsImV0YWciOiJDSTdCbjlHVzI5MENFQU09In0=" + } + }, + { + "ID": "2da4d03d65e44aff", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=29bfc48d421eb985742aa3c01fa02a8f4f07eb13a9df1f3a6d2ffbabd8c2" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4b38b821542f76a1d762740d02b631d9/2489440367246438267;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0yOWJmYzQ4ZDQyMWViOTg1NzQyYWEzYzAxZmEwMmE4ZjRmMDdlYjEzYTlkZjFmM2E2ZDJmZmJhYmQ4YzINCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm5hbWUiOiJjaGVja3N1bS1vYmplY3QifQoNCi0tMjliZmM0OGQ0MjFlYjk4NTc0MmFhM2MwMWZhMDJhOGY0ZjA3ZWIxM2E5ZGYxZjNhNmQyZmZiYWJkOGMyDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgNCg0KaGVsbG93b3JsZA0KLS0yOWJmYzQ4ZDQyMWViOTg1NzQyYWEzYzAxZmEwMmE4ZjRmMDdlYjEzYTlkZjFmM2E2ZDJmZmJhYmQ4YzItLQ0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3398" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:15 GMT" + ], + "Etag": [ + "CK+As9aW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051344000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrp62:4379,/bns/yv/borg/yv/bns/blobstore2/bitpusher/111.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=78usW-1oz5yBBLWtmIgB" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/111.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/111:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UowJsm6E91bsGVBm6CM-mz8rDfoul1oIecNfHPOUKCznqaR9zK2zwL7-0GmZY0j80eiUDC7pO726ekxFHOv4yM7p6uzug" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jaGVja3N1bS1vYmplY3QvMTUzODA1MTA1NTMzNzUxOSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NoZWNrc3VtLW9iamVjdCIsIm5hbWUiOiJjaGVja3N1bS1vYmplY3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1NTMzNzUxOSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxNS4zMzdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MTUuMzM3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjE1LjMzN1oiLCJzaXplIjoiMTAiLCJtZDVIYXNoIjoiL0Y0RGpUaWxjRElJVkVIbi9uQVFzQT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NoZWNrc3VtLW9iamVjdD9nZW5lcmF0aW9uPTE1MzgwNTEwNTUzMzc1MTkmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY2hlY2tzdW0tb2JqZWN0LzE1MzgwNTEwNTUzMzc1MTkvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jaGVja3N1bS1vYmplY3QvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY2hlY2tzdW0tb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTUzMzc1MTkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNLK0FzOWFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jaGVja3N1bS1vYmplY3QvMTUzODA1MTA1NTMzNzUxOS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jaGVja3N1bS1vYmplY3QvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNoZWNrc3VtLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU1MzM3NTE5IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNLK0FzOWFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jaGVja3N1bS1vYmplY3QvMTUzODA1MTA1NTMzNzUxOS9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jaGVja3N1bS1vYmplY3QvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNoZWNrc3VtLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU1MzM3NTE5IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSytBczlhVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY2hlY2tzdW0tb2JqZWN0LzE1MzgwNTEwNTUzMzc1MTkvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NoZWNrc3VtLW9iamVjdC9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNoZWNrc3VtLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU1MzM3NTE5IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0srQXM5YVcyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJWc3UwZ0E9PSIsImV0YWciOiJDSytBczlhVzI5MENFQUU9In0=" + } + }, + { + "ID": "7493d7564de97c32", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=83686c59a67e3a3090aacc06f8cc35bc689e1130c5abb2208114560bd462" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ade53e256843f2179ea331cc5e743445/3248758807366091211;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS04MzY4NmM1OWE2N2UzYTMwOTBhYWNjMDZmOGNjMzViYzY4OWUxMTMwYzVhYmIyMjA4MTE0NTYwYmQ0NjINCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm5hbWUiOiJ6ZXJvLW9iamVjdCJ9Cg0KLS04MzY4NmM1OWE2N2UzYTMwOTBhYWNjMDZmOGNjMzViYzY4OWUxMTMwYzVhYmIyMjA4MTE0NTYwYmQ0NjINCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOA0KDQoNCi0tODM2ODZjNTlhNjdlM2EzMDkwYWFjYzA2ZjhjYzM1YmM2ODllMTEzMGM1YWJiMjIwODExNDU2MGJkNDYyLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3333" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:16 GMT" + ], + "Etag": [ + "CPbJ19aW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051344000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrks2:4058,/bns/yv/borg/yv/bns/blobstore2/bitpusher/323.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=78usW4eCI5XYgQTfuLnICg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/323.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/323:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqhWY1Ab_R5DZveNFpWX2c-1hrdM8jXZdJRqFjpgtkI00Ya1DA0RgxrWCZI9zbGnWSoD1CFZn3oBDKQMDdbLLqOW3zihw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS96ZXJvLW9iamVjdC8xNTM4MDUxMDU1OTM2NzU4Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vemVyby1vYmplY3QiLCJuYW1lIjoiemVyby1vYmplY3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1NTkzNjc1OCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxNS45MzZaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MTUuOTM2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjE1LjkzNloiLCJzaXplIjoiMCIsIm1kNUhhc2giOiIxQjJNMlk4QXNnVHBnQW1ZN1BoQ2ZnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vemVyby1vYmplY3Q/Z2VuZXJhdGlvbj0xNTM4MDUxMDU1OTM2NzU4JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3plcm8tb2JqZWN0LzE1MzgwNTEwNTU5MzY3NTgvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby96ZXJvLW9iamVjdC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJ6ZXJvLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU1OTM2NzU4IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUGJKMTlhVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvemVyby1vYmplY3QvMTUzODA1MTA1NTkzNjc1OC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby96ZXJvLW9iamVjdC9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiemVyby1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1NTkzNjc1OCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUGJKMTlhVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvemVyby1vYmplY3QvMTUzODA1MTA1NTkzNjc1OC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby96ZXJvLW9iamVjdC9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiemVyby1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1NTkzNjc1OCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1BiSjE5YVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3plcm8tb2JqZWN0LzE1MzgwNTEwNTU5MzY3NTgvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3plcm8tb2JqZWN0L2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiemVyby1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1NTkzNjc1OCIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQYkoxOWFXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiQUFBQUFBPT0iLCJldGFnIjoiQ1BiSjE5YVcyOTBDRUFFPSJ9" + } + }, + { + "ID": "cc0322fc546d79b7", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1/acl/allUsers?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "98" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "33f9664c55b05032698ecc2d6673d6bf/4838888141239936873;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1/acl/allUsers?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJhbGxVc2VycyIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "417" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:16 GMT" + ], + "Etag": [ + "CI7Bn9GW290CEAQ=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051354000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnbf187:4310,/bns/yx/borg/yx/bns/blobstore2/bitpusher/100.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=8MusW4rgA8rpzgLno6zgCQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/100.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/100:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrpvmIybpBCVebTDqqsidgrv6r5XJxfkgIb_b4OdZyS6TDxQJumscogNbWOP14ydRFDoIao0YBIztO_mFhZHqa_FtHANw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L2FsbFVzZXJzIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvYWxsVXNlcnMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDQ1MzIzNjYiLCJlbnRpdHkiOiJhbGxVc2VycyIsInJvbGUiOiJSRUFERVIiLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFRPSJ9" + } + }, + { + "ID": "3d0b287f3cb38a1a", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "690d0db937791a93fb309e862ad54704/6429300045307087880;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj1" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "16" + ], + "Content-Type": [ + "application/octet-stream" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:16 GMT" + ], + "Etag": [ + "\"ef05051fc9830f01c562aa3ba25c5d3e\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:16 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:04 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:04 GMT" + ], + "X-Goog-Generation": [ + "1538051044532366" + ], + "X-Goog-Hash": [ + "crc32c=+7R11g==", + "md5=7wUFH8mDDwHFYqo7olxdPg==" + ], + "X-Goog-Metageneration": [ + "4" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/36,/bns/xh/borg/xh/bns/blobstore2/bitpusher/14.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=8MusW9aLFMKgswasv66gCg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/14.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/14:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UodxwoKYGU9MxqABteUDaXQqlKGdhkVHcajT7guddfpYQr1LRepGJXYbFR9Qs2gdcsSHWrgNx6HyMYR6YLY5M456Mko7w" + ] + }, + "Body": "G7YE7d4n0dy1PXohFJpUnw==" + } + }, + { + "ID": "cae829cdb9b34f3e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Content-Type": [ + "multipart/related; boundary=29bb3acea632c820a568e150cb4a4bf04415fd1bdf63309db1e96c525d7a" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "8a62594ad456c247ec2bd76dc9e52f57/7260393509254586199;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0yOWJiM2FjZWE2MzJjODIwYTU2OGUxNTBjYjRhNGJmMDQ0MTVmZDFiZGY2MzMwOWRiMWU5NmM1MjVkN2ENCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm5hbWUiOiJvYmoxIn0KDQotLTI5YmIzYWNlYTYzMmM4MjBhNTY4ZTE1MGNiNGE0YmYwNDQxNWZkMWJkZjYzMzA5ZGIxZTk2YzUyNWQ3YQ0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04DQoNCmhlbGxvDQotLTI5YmIzYWNlYTYzMmM4MjBhNTY4ZTE1MGNiNGE0YmYwNDQxNWZkMWJkZjYzMzA5ZGIxZTk2YzUyNWQ3YS0tDQo=" + }, + "Response": { + "StatusCode": 401, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "30139" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:16 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "Www-Authenticate": [ + "Bearer realm=\"https://accounts.google.com/\"" + ], + "X-Google-Backends": [ + "vrqp19:4117,/bns/yv/borg/yv/bns/blobstore2/bitpusher/203.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=8MusW5PmF5C0ggSujK6wDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/203.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/203:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "GgIYBiAB" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqWr2rfS-bwg-Gq7do_pbFNKm2Y8I25oad-2ZZG3L56Sy5jUKoxRp1icBi27T5FiJu6D5V0nkc7qgcMqJALSN9rMHPscQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS4iLCJsb2NhdGlvblR5cGUiOiJoZWFkZXIiLCJsb2NhdGlvbiI6IkF1dGhvcml6YXRpb24iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIxNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NTEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUxPR0lOX1JFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9TE9HSU5fUkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIxNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NTEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPXVuYXV0aG9yaXplZCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjE3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo1MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1SRVFVSVJFRCwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkuYXV0aGVudGljYXRlZF91c2VyLCBtZXNzYWdlPUFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS4sIHVubmFtZWRBcmd1bWVudHM9W119LCBsb2NhdGlvbj1oZWFkZXJzLkF1dGhvcml6YXRpb24sIG1lc3NhZ2U9QW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMX0gQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMTcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjUxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIxNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NTEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXtXV1ctQXV0aGVudGljYXRlPVtCZWFyZXIgcmVhbG09XCJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20vXCJdfSwgaHR0cFN0YXR1cz11bmF1dGhvcml6ZWQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLlJFUVVJUkVELCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIxNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NTEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9UkVRVUlSRUQsIGVycm9yUHJvdG9Eb21haW49Z2RhdGEuQ29yZUVycm9yRG9tYWluLCBmaWx0ZXJlZE1lc3NhZ2U9bnVsbCwgbG9jYXRpb249ZW50aXR5LmF1dGhlbnRpY2F0ZWRfdXNlciwgbWVzc2FnZT1Bbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249aGVhZGVycy5BdXRob3JpemF0aW9uLCBtZXNzYWdlPUFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS4sIHJlYXNvbj1yZXF1aXJlZCwgcnBjQ29kZT00MDF9IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS46IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjE3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo1MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5hdXRoLkF1dGhlbnRpY2F0b3JJbnRlcmNlcHRvci5hZGRDaGFsbGVuZ2VIZWFkZXIoQXV0aGVudGljYXRvckludGVyY2VwdG9yLmphdmE6MjY0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuYXV0aC5BdXRoZW50aWNhdG9ySW50ZXJjZXB0b3IucHJvY2Vzc0Vycm9yUmVzcG9uc2UoQXV0aGVudGljYXRvckludGVyY2VwdG9yLmphdmE6MjMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuYXV0aC5HYWlhTWludEludGVyY2VwdG9yLnByb2Nlc3NFcnJvclJlc3BvbnNlKEdhaWFNaW50SW50ZXJjZXB0b3IuamF2YTo3NjQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLmludGVyY2VwdC5Bcm91bmRJbnRlcmNlcHRvcldyYXBwZXIucHJvY2Vzc0Vycm9yUmVzcG9uc2UoQXJvdW5kSW50ZXJjZXB0b3JXcmFwcGVyLmphdmE6MjgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zdGF0cy5TdGF0c0Jvb3RzdHJhcCRJbnRlcmNlcHRvclN0YXRzUmVjb3JkZXIucHJvY2Vzc0Vycm9yUmVzcG9uc2UoU3RhdHNCb290c3RyYXAuamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLmludGVyY2VwdC5JbnRlcmNlcHRpb25zJEFyb3VuZEludGVyY2VwdGlvbi5oYW5kbGVFcnJvclJlc3BvbnNlKEludGVyY2VwdGlvbnMuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLmludGVyY2VwdC5JbnRlcmNlcHRpb25zJEFyb3VuZEludGVyY2VwdGlvbi5hY2Nlc3MkMjAwKEludGVyY2VwdGlvbnMuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLmludGVyY2VwdC5JbnRlcmNlcHRpb25zJEFyb3VuZEludGVyY2VwdGlvbiQxLmNhbGwoSW50ZXJjZXB0aW9ucy5qYXZhOjE0NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuaW50ZXJjZXB0LkludGVyY2VwdGlvbnMkQXJvdW5kSW50ZXJjZXB0aW9uJDEuY2FsbChJbnRlcmNlcHRpb25zLmphdmE6MTM3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0RXhjZXB0aW9uKEFic3RyYWN0RnV0dXJlLmphdmE6NzUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjY4KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1MT0dJTl9SRVFVSVJFRCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjE3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo1MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9dW5hdXRob3JpemVkLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMTcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjUxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5hdXRoZW50aWNhdGVkX3VzZXIsIG1lc3NhZ2U9QW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWhlYWRlcnMuQXV0aG9yaXphdGlvbiwgbWVzc2FnZT1Bbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEuLCByZWFzb249cmVxdWlyZWQsIHJwY0NvZGU9NDAxfSBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIxNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NTEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0Li4uIDE5IG1vcmVcbiJ9XSwiY29kZSI6NDAxLCJtZXNzYWdlIjoiQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLiJ9fQ==" + } + }, + { + "ID": "8758aed3ba16e613", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/copy-obj1?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "6afbb969fe0885a2b78dd5858f886be6/8019711945062560423;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/copy-obj1?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:16 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051344000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdg20:4229,/bns/yw/borg/yw/bns/blobstore2/bitpusher/70.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=8MusW6TyLMP_N8WAs9AK" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/70.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/70:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo_WB_TIzYXheVC2PJxwKX79DTZxYv5LtBQXsHamFWDNH7tEHd8DHlpDI9Jo2cqRV5n41EYgQ8qbNPMD5IQCnn-ClF1g5EMIraE8-GyrOhLPzDudG0" + ] + }, + "Body": "" + } + }, + { + "ID": "9b9733451f86c731", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/copy-obj1?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4ed613e1f2dd59d68cc9f92a23ace1da/8850805409010058742;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/copy-obj1?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "12167" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:17 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:17 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051344000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnes8:4151,/bns/yx/borg/yx/bns/blobstore2/bitpusher/113.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=8MusW96TO8P9zALA9KDoCQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/113.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/113:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpQL7qcvVzjYBgZfUSe7_5liX8MrrghnugMlAYRFFtlEiR6qULOiIf42xoZ5ufqXErot0V89XuVLD6JnhdYSiKdu0Q3IQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29weS1vYmoxIiwiZGVidWdJbmZvIjoiY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6Ok9CSkVDVF9OT1RfRk9VTkQ6IE5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29weS1vYmoxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6NzcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjIzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5kZWxldGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjExMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29weS1vYmoxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPU5PVF9GT1VORCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfTk9UX0ZPVU5EOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjc3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1ub3RGb3VuZCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uTk9UX0ZPVU5ELCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6T0JKRUNUX05PVF9GT1VORDogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo3Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1OT1RfRk9VTkQsIGVycm9yUHJvdG9Eb21haW49Z2RhdGEuQ29yZUVycm9yRG9tYWluLCBmaWx0ZXJlZE1lc3NhZ2U9bnVsbCwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLm5hbWUsIG1lc3NhZ2U9Tm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajEsIHVubmFtZWRBcmd1bWVudHM9W119LCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2VfaWQubmFtZSwgbWVzc2FnZT1ObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvcHktb2JqMSwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajE6IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfTk9UX0ZPVU5EOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjc3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDA0LCJtZXNzYWdlIjoiTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajEifX0=" + } + }, + { + "ID": "d6873ffc79300971", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/copy-obj1?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "08e7bf5864621c4b488ed652bb33efa8/10441217313077209749;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/copy-obj1?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "12107" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:17 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:17 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051345000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnnl20:4294,/bns/yx/borg/yx/bns/blobstore2/bitpusher/86.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=8cusW9T2AsK0zALEw4ygDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/86.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/86:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UokNGRr71RRY51b_oxACRzHO0T0SKYySfLa0FwXM-OtehDW-Ck9X2Q17U8IVWtiH3JL37eb5NYUCBv065INRRt6SnW2ZA" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29weS1vYmoxIiwiZGVidWdJbmZvIjoiY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6Ok9CSkVDVF9OT1RfRk9VTkQ6IE5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29weS1vYmoxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6Mjk4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZ2V0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo4MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE5vIHN1Y2ggb2JqZWN0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29weS1vYmoxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPU5PVF9GT1VORCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfTk9UX0ZPVU5EOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjI5OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmdldChPYmplY3RzRGVsZWdhdG9yLmphdmE6ODEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1ub3RGb3VuZCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uTk9UX0ZPVU5ELCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6T0JKRUNUX05PVF9GT1VORDogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YToyOTgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjcxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5nZXQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjgxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1OT1RfRk9VTkQsIGVycm9yUHJvdG9Eb21haW49Z2RhdGEuQ29yZUVycm9yRG9tYWluLCBmaWx0ZXJlZE1lc3NhZ2U9bnVsbCwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLm5hbWUsIG1lc3NhZ2U9Tm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajEsIHVubmFtZWRBcmd1bWVudHM9W119LCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2VfaWQubmFtZSwgbWVzc2FnZT1ObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvcHktb2JqMSwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajE6IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfTk9UX0ZPVU5EOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjI5OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmdldChPYmplY3RzRGVsZWdhdG9yLmphdmE6ODEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvcHktb2JqMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDA0LCJtZXNzYWdlIjoiTm8gc3VjaCBvYmplY3Q6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb3B5LW9iajEifX0=" + } + }, + { + "ID": "6cc70dcba7bada17", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/composed1/compose?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "156" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9863e2969d42a229b723aedca5070485/12031628117632798771;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/composed1/compose?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6Im9iajEifSx7Im5hbWUiOiJvYmoyIn0seyJuYW1lIjoib2JqL3dpdGgvc2xhc2hlcyJ9XX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "750" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:17 GMT" + ], + "Etag": [ + "CPK8wteW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051353000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrmu6:4354,/bns/yr/borg/yr/bns/blobstore2/bitpusher/80.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=8cusW4fEE9L6kAP667DgBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/80.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/80:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqVIeiy4Si_0YNKLwY3IG9GOLU0P0n1CkorBkpJAR_BfS1jk_56Sw6HKwDphzFjNssouMyenjo7arMSaMAmsUdvFlYB9w" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb21wb3NlZDEvMTUzODA1MTA1NzY4ODE3OCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbXBvc2VkMSIsIm5hbWUiOiJjb21wb3NlZDEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1NzY4ODE3OCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxNy42ODhaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MTcuNjg4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjE3LjY4OFoiLCJzaXplIjoiNDgiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29tcG9zZWQxP2dlbmVyYXRpb249MTUzODA1MTA1NzY4ODE3OCZhbHQ9bWVkaWEiLCJjcmMzMmMiOiJib0I4bXc9PSIsImNvbXBvbmVudENvdW50IjozLCJldGFnIjoiQ1BLOHd0ZVcyOTBDRUFFPSJ9" + } + }, + { + "ID": "50f8730f385d030c", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/composed1", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "760c277df2c97acc454ce434914ee9e8/13549702052197004754;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/composed1" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "48" + ], + "Content-Type": [ + "application/octet-stream" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:17 GMT" + ], + "Etag": [ + "\"-CPK8wteW290CEAE=\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:17 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:17 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Component-Count": [ + "3" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:17 GMT" + ], + "X-Goog-Generation": [ + "1538051057688178" + ], + "X-Goog-Hash": [ + "crc32c=boB8mw==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "48" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/18,/bns/xh/borg/xh/bns/blobstore2/bitpusher/34.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=8cusW9ebMdCoswa6y4HoAw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/34.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/34:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoX-eaOWQ9wa_8D4JqhxXvp57Z8lKcw7mTxFIfWfaKu1KAUgjL9WuATvzG1v-OCqywESusNWkTDMqjoDaCDrd7JK3sf0A" + ] + }, + "Body": "G7YE7d4n0dy1PXohFJpUn8PZcNJccaSrouZ5qGqfKcNY+xSKoJ2Yh9xMlR8v8x6R" + } + }, + { + "ID": "4f10cc8a4c605e16", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/composed2/compose?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "182" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "2a7e45e04c9b2ba8510787a4626e0409/15140113956247378801;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/composed2/compose?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJjb250ZW50VHlwZSI6InRleHQvanNvbiJ9LCJzb3VyY2VPYmplY3RzIjpbeyJuYW1lIjoib2JqMSJ9LHsibmFtZSI6Im9iajIifSx7Im5hbWUiOiJvYmovd2l0aC9zbGFzaGVzIn1dfQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "776" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:18 GMT" + ], + "Etag": [ + "CNnn7NeW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051353000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrfx72:4146,/bns/yv/borg/yv/bns/blobstore2/bitpusher/63.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=8cusW5aPOMeCNruzofgP" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/63.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/63:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRYnFLZDRCTjBkdm9mZm9PZVZZS0p1VDRROFVJT3NhUTljbFFvbW42UElpcDBpenczVUc1ZHZUMVZlZE1OWGp3cHJDNUUyam9FUUZwbldFellKMWd5Tlp1T3o4dy16UUMxaXAtb3VNMjdkM0JqNGR4SmNfUDVYRXRjeHNYWVN3LXNuNXEtcXpLZ1NvM3BKMGx4Ym9YaGNlZHBiR2t6VGVSdlc5QnVxZDFESV9pbE84ZEFXSDVOLVJnNDQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrggIUXoQRGOBqCG_DLynaYwpyl_4lENPEOVra5582u9rZmF-icWSkCFTlLj14A0wP6_ZaqI_ZgXHPSrgXC2GkiLC3MWw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb21wb3NlZDIvMTUzODA1MTA1ODM4MTc4NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbXBvc2VkMiIsIm5hbWUiOiJjb21wb3NlZDIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1ODM4MTc4NSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9qc29uIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjE4LjM3OVoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxOC4zNzlaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MTguMzc5WiIsInNpemUiOiI0OCIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb21wb3NlZDI/Z2VuZXJhdGlvbj0xNTM4MDUxMDU4MzgxNzg1JmFsdD1tZWRpYSIsImNyYzMyYyI6ImJvQjhtdz09IiwiY29tcG9uZW50Q291bnQiOjMsImV0YWciOiJDTm5uN05lVzI5MENFQUU9In0=" + } + }, + { + "ID": "0139c847dd24ca22", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/composed2", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "43c359bcc9599df1fa41050f8c44953f/16730525860314595343;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/composed2" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "48" + ], + "Content-Type": [ + "text/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:18 GMT" + ], + "Etag": [ + "\"-CNnn7NeW290CEAE=\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:18 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:18 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Component-Count": [ + "3" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:18 GMT" + ], + "X-Goog-Generation": [ + "1538051058381785" + ], + "X-Goog-Hash": [ + "crc32c=boB8mw==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "48" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/27,/bns/xh/borg/xh/bns/blobstore2/bitpusher/1.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=8susW7SaJfCoswa-l4W4Dw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/1.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/1:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpIx0vuK5NPFu7_CxRMZ61vPnJlQWjZ6ejYGdikaD8AawSgJJPLhcBGALUiFI3jv-gCL18r8Mig_JKoDCCxy0-LmuQ85A" + ] + }, + "Body": "G7YE7d4n0dy1PXohFJpUn8PZcNJccaSrouZ5qGqfKcNY+xSKoJ2Yh9xMlR8v8x6R" + } + }, + { + "ID": "8da163d5370e63a2", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=44415e54fcdbc755b78a8ae8f64c45c109d270e3315c08e5b5ab2a272972" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "bfc01e37d4ef5d0f121b282467264d29/17561619324262028127;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS00NDQxNWU1NGZjZGJjNzU1Yjc4YThhZThmNjRjNDVjMTA5ZDI3MGUzMzE1YzA4ZTViNWFiMmEyNzI5NzINCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNvbnRlbnRFbmNvZGluZyI6Imd6aXAiLCJuYW1lIjoiZ3ppcC10ZXN0In0KDQotLTQ0NDE1ZTU0ZmNkYmM3NTViNzhhOGFlOGY2NGM0NWMxMDlkMjcwZTMzMTVjMDhlNWI1YWIyYTI3Mjk3Mg0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94LWd6aXANCg0KH4sIAAAAAAAA/2IgEgACAAD//7E97OkoAAAADQotLTQ0NDE1ZTU0ZmNkYmM3NTViNzhhOGFlOGY2NGM0NWMxMDlkMjcwZTMzMTVjMDhlNWI1YWIyYTI3Mjk3Mi0tDQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3320" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:19 GMT" + ], + "Etag": [ + "CND/mtiW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051358000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrnb2:4089,/bns/yw/borg/yw/bns/blobstore2/bitpusher/224.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=8susW7LLL4-chASN_IugDw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/224.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/224:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYmxNeVZwMGdUN0o0YlgxVmMtQTlEaHc0eV9GbmdDSHlYYUt0U0VxRHJZV1RVWUxpYnBGRzJxTTlKYTdLNURwTk1hV0ZIaVFoc2tDN1pTaGhHSW53eHJWMHN2bnpGdGZnNmpMc2pjVFdLZU16eUs0c2RRNEo4S3pTMk9kSGxJYmZVVmZTd0pQQjVuRTRrYWxxVjRhbkF4eC1nRUxIU19pTU5nVFVGam5ZOFJTNlFwT2hGdHB6bHBGUG8wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoUbsWpAqL_JeVZbn_zAy2jD-kFzPJRAaxYSNgmnXwpw3SguayQhxx1ULy41CNY5eZP0vxXwt5U5vHHasuOQZLDq18GpA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9nemlwLXRlc3QvMTUzODA1MTA1OTEzODUxMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2d6aXAtdGVzdCIsIm5hbWUiOiJnemlwLXRlc3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1OTEzODUxMiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24veC1nemlwIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjE5LjEzOFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxOS4xMzhaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MTkuMTM4WiIsInNpemUiOiIyNyIsIm1kNUhhc2giOiJPdEN3K2FSUklScUtHRkFFT2F4K3F3PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vZ3ppcC10ZXN0P2dlbmVyYXRpb249MTUzODA1MTA1OTEzODUxMiZhbHQ9bWVkaWEiLCJjb250ZW50RW5jb2RpbmciOiJnemlwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvZ3ppcC10ZXN0LzE1MzgwNTEwNTkxMzg1MTIvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9nemlwLXRlc3QvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiZ3ppcC10ZXN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTkxMzg1MTIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNORC9tdGlXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9nemlwLXRlc3QvMTUzODA1MTA1OTEzODUxMi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9nemlwLXRlc3QvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imd6aXAtdGVzdCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU5MTM4NTEyIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNORC9tdGlXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9nemlwLXRlc3QvMTUzODA1MTA1OTEzODUxMi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9nemlwLXRlc3QvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imd6aXAtdGVzdCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU5MTM4NTEyIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTkQvbXRpVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvZ3ppcC10ZXN0LzE1MzgwNTEwNTkxMzg1MTIvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2d6aXAtdGVzdC9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imd6aXAtdGVzdCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU5MTM4NTEyIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ05EL210aVcyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiI5RGh3QkE9PSIsImV0YWciOiJDTkQvbXRpVzI5MENFQUU9In0=" + } + }, + { + "ID": "3b90c911e5184c72", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/gzip-test", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "8dcb355604083d45976f1b6230e58bae/705568625301502205;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/gzip-test" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "none" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Type": [ + "application/x-gzip" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:19 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:19 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:19 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Accept-Encoding" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:19 GMT" + ], + "X-Goog-Generation": [ + "1538051059138512" + ], + "X-Goog-Hash": [ + "crc32c=9DhwBA==", + "md5=OtCw+aRRIRqKGFAEOax+qw==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "gzip" + ], + "X-Goog-Stored-Content-Length": [ + "27" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/33,/bns/xh/borg/xh/bns/blobstore2/bitpusher/32.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=88usW9nbFseoswbavqfIAQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/32.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Body-Transformations": [ + "gunzipped,chunked" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/32:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrqJq-PaCwRos5X_sDmM2fxtLX2i9NL56DXNhSP4KJAtDQpYHyiYPTEtmGOC2Qwvj0qlphWquvmwpMQiznCoS7DuYCYKA" + ] + }, + "Body": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + } + }, + { + "ID": "68d9c7cc86eac452", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj-not-exists", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "452523ae4fe3e75b632b9c7aca76ddab/2295979429857025692;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/obj-not-exists" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "225" + ], + "Content-Type": [ + "application/xml; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:19 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:19 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/43,/bns/xh/borg/xh/bns/blobstore2/bitpusher/20.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=88usW5S8HMesswbQ_qAo" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/20.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/20:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur0o8XTl6cwQYgCGmxXT4871JIv-OvohYl-kWfphF7WUjyN0lnJFPDbq3EcGXMmlMZAkD3NsbPQ5enswas8sWhAD_pw8Q" + ] + }, + "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+Tm9TdWNoS2V5PC9Db2RlPjxNZXNzYWdlPlRoZSBzcGVjaWZpZWQga2V5IGRvZXMgbm90IGV4aXN0LjwvTWVzc2FnZT48RGV0YWlscz5ObyBzdWNoIG9iamVjdDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai1ub3QtZXhpc3RzPC9EZXRhaWxzPjwvRXJyb3I+" + } + }, + { + "ID": "3b10b1db50d2db0b", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=1442371c68bf0f93dba7b4d3265c434f493a6e71f9331861397c4d652891" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "148ee3c75f4f071e711419694ce354a8/3055016399295000811;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0xNDQyMzcxYzY4YmYwZjkzZGJhN2I0ZDMyNjVjNDM0ZjQ5M2E2ZTcxZjkzMzE4NjEzOTdjNGQ2NTI4OTENCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJzaWduZWRVUkwifQoNCi0tMTQ0MjM3MWM2OGJmMGY5M2RiYTdiNGQzMjY1YzQzNGY0OTNhNmU3MWY5MzMxODYxMzk3YzRkNjUyODkxDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW4NCg0KVGhpcyBpcyBhIHRlc3Qgb2YgU2lnbmVkVVJMLgoNCi0tMTQ0MjM3MWM2OGJmMGY5M2RiYTdiNGQzMjY1YzQzNGY0OTNhNmU3MWY5MzMxODYxMzk3YzRkNjUyODkxLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3323" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:20 GMT" + ], + "Etag": [ + "CMS019iW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051359000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlh9:4090,/bns/yw/borg/yw/bns/blobstore2/bitpusher/202.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=88usW5ejMdjmhATG4KKIBA" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/202.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/202:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYlVHbHo5aEdpZEl3eXlKS0N0RXMyRVBVdWRfaVJncG1hTkFvQmlGVmNzQ3B2dnNuRFZfTlc0aWF2YmtHTURVWW9QZHE5UThXRlNQbWZ5YzFlZUtmTnNmV3d2Q2J4R3RoS2FaWm5NUzdBMmdJM0FydU5tbHhTLXAwY2lOdzdwdTFXRkg3TnhSYmowUThZQ3FrcERoU0RIUkMyYllobWhoZXlKaEhEUk5GNkJyT2hHOFRaTm81QUlvbFUwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uqjnuu0O7kv5rFkyxOHMrOB8DkSNtM4n6d1jpNnSmIIVL7XXmSRa78auaiUOyo4-qafkT3xdqmKEFjGLwSp8TgycKb0dw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9zaWduZWRVUkwvMTUzODA1MTA2MDEyODMyNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3NpZ25lZFVSTCIsIm5hbWUiOiJzaWduZWRVUkwiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA2MDEyODMyNCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoyMC4xMjhaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MjAuMTI4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjIwLjEyOFoiLCJzaXplIjoiMjkiLCJtZDVIYXNoIjoiSnl4dmd3bTluMk1zckdUTVBiTWVZQT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3NpZ25lZFVSTD9nZW5lcmF0aW9uPTE1MzgwNTEwNjAxMjgzMjQmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvc2lnbmVkVVJMLzE1MzgwNTEwNjAxMjgzMjQvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9zaWduZWRVUkwvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoic2lnbmVkVVJMIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjAxMjgzMjQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNNUzAxOWlXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9zaWduZWRVUkwvMTUzODA1MTA2MDEyODMyNC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9zaWduZWRVUkwvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InNpZ25lZFVSTCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDYwMTI4MzI0IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNNUzAxOWlXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9zaWduZWRVUkwvMTUzODA1MTA2MDEyODMyNC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9zaWduZWRVUkwvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InNpZ25lZFVSTCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDYwMTI4MzI0IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTVMwMTlpVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvc2lnbmVkVVJMLzE1MzgwNTEwNjAxMjgzMjQvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3NpZ25lZFVSTC9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InNpZ25lZFVSTCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDYwMTI4MzI0IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ01TMDE5aVcyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJaVHFBTHc9PSIsImV0YWciOiJDTVMwMTlpVzI5MENFQUU9In0=" + } + }, + { + "ID": "23beecdc4886db0d", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e45c86a08dfdca44f43e256839e02da6/4645428303345374858;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "119" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:22 GMT" + ], + "Etag": [ + "CAY=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051361000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrjk75:4456,/bns/yv/borg/yv/bns/blobstore2/bitpusher/268.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=9cusW8i_BtKeggS9oqBY" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/268.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/268:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWW5wTmtlLU9kVkRTVDlqMDhzYkVvZ2hLYjlqRzhpWDJuQm5JM01lY1Z4VHg3Nnl6Z3lXb3hkeTZQNk43bDc3WlFuNmVUUm5mcnpKX1VUNEpvV05pcmpXTGxCT2gteHBPQVFpMTQ3NnU5ak9IZEVNVElfSTVrQzJQV2tBcUxmWXpDVjIwN041aXgweGItdW1NQkJKN1ExUFdFSEtyNE1pS3JZTjhteWdELUVxRjVDS2w2eTl5NjFTZ0EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq3lv20s_T1WTNLRb4NTrmOZgRAwMwC72Ie5cc_1yk34PGxL_K-AylFLpjvdcIKkq9QNwiDcsKH9lrb8KnFfeYict3K5w" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQVk9In0=" + } + }, + { + "ID": "8087b8417cc402c5", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/defaultObjectAcl?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3e3d9d350b89e4de9e2dc4a451e4be0b/6235558732435946280;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/defaultObjectAcl?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "678" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:22 GMT" + ], + "Etag": [ + "CAY=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:22 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051361000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vryy5:4338,/bns/yv/borg/yv/bns/blobstore2/bitpusher/360.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=9susW6HtI5fJgASEx7egAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/360.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/360:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWW5wTmtlLU9kVkRTVDlqMDhzYkVvZ2hLYjlqRzhpWDJuQm5JM01lY1Z4VHg3Nnl6Z3lXb3hkeTZQNk43bDc3WlFuNmVUUm5mcnpKX1VUNEpvV05pcmpXTGxCT2gteHBPQVFpMTQ3NnU5ak9IZEVNVElfSTVrQzJQV2tBcUxmWXpDVjIwN041aXgweGItdW1NQkJKN1ExUFdFSEtyNE1pS3JZTjhteWdELUVxRjVDS2w2eTl5NjFTZ0EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UozGaSoDn-YihIPaUMVTDXgWpSz9PKEcpp3TLb1cFU6g8v8A1cOtx7L8qLF1aB2Z15qRD89do749K8f9Sx22l_Pydij6Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQVk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBWT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBWT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBWT0ifV19" + } + }, + { + "ID": "634c2d25d926440d", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=3ddfe24a6384ff14089cd949180c2222a1402c31668eda555039fa69e9bf" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e2548d029256a26c6b18f6073fe21adf/6994877172538822264;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0zZGRmZTI0YTYzODRmZjE0MDg5Y2Q5NDkxODBjMjIyMmExNDAyYzMxNjY4ZWRhNTU1MDM5ZmE2OWU5YmYNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsIm5hbWUiOiJhY2wxIn0KDQotLTNkZGZlMjRhNjM4NGZmMTQwODljZDk0OTE4MGMyMjIyYTE0MDJjMzE2NjhlZGE1NTUwMzlmYTY5ZTliZg0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0NCg0KR8dXiQCBOn5esIR367SwUA0KLS0zZGRmZTI0YTYzODRmZjE0MDg5Y2Q5NDkxODBjMjIyMmExNDAyYzMxNjY4ZWRhNTU1MDM5ZmE2OWU5YmYtLQ0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3724" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:23 GMT" + ], + "Etag": [ + "CNXmlNqW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051362000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbv14:4486,/bns/yv/borg/yv/bns/blobstore2/bitpusher/176.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=9susW6n9N4GjgATktYzACw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/176.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/176:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWW5wTmtlLU9kVkRTVDlqMDhzYkVvZ2hLYjlqRzhpWDJuQm5JM01lY1Z4VHg3Nnl6Z3lXb3hkeTZQNk43bDc3WlFuNmVUUm5mcnpKX1VUNEpvV05pcmpXTGxCT2gteHBPQVFpMTQ3NnU5ak9IZEVNVElfSTVrQzJQV2tBcUxmWXpDVjIwN041aXgweGItdW1NQkJKN1ExUFdFSEtyNE1pS3JZTjhteWdELUVxRjVDS2w2eTl5NjFTZ0EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpxBKcmuCe-OuHfbZcZvw2Kdf8HCiIhoicR-fibw-U04VOSzFXZgl_rIFsqwTwrsBvt5t-Zlr7P67XF7mgTXboogFCwAw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wxLzE1MzgwNTEwNjMyMzEzMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hY2wxIiwibmFtZSI6ImFjbDEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA2MzIzMTMxNyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjIzLjIzMFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoyMy4yMzBaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MjMuMjMwWiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJ6cENKM29yUTk1eXh2ZnorUXE3dlFBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMT9nZW5lcmF0aW9uPTE1MzgwNTEwNjMyMzEzMTcmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsMS8xNTM4MDUxMDYzMjMxMzE3L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjMyMzEzMTciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNOWG1sTnFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wxLzE1MzgwNTEwNjMyMzEzMTcvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMS9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYWNsMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDYzMjMxMzE3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNOWG1sTnFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wxLzE1MzgwNTEwNjMyMzEzMTcvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMS9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYWNsMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDYzMjMxMzE3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTlhtbE5xVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsMS8xNTM4MDUxMDYzMjMxMzE3L2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMS9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjMyMzEzMTciLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNOWG1sTnFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wxLzE1MzgwNTEwNjMyMzEzMTcvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2FjbDEvYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjMyMzEzMTciLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTlhtbE5xVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IjViL2ltZz09IiwiZXRhZyI6IkNOWG1sTnFXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "7d274cd0b9fb4e9e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=c110552d9287f2e64b941bf461feade0f6f61300ba49538ce5357cfffdb7" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "cf1e26c269814cea3ac75b3510540c63/7825970636486320583;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS1jMTEwNTUyZDkyODdmMmU2NGI5NDFiZjQ2MWZlYWRlMGY2ZjYxMzAwYmE0OTUzOGNlNTM1N2NmZmZkYjcNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsIm5hbWUiOiJhY2wyIn0KDQotLWMxMTA1NTJkOTI4N2YyZTY0Yjk0MWJmNDYxZmVhZGUwZjZmNjEzMDBiYTQ5NTM4Y2U1MzU3Y2ZmZmRiNw0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0NCg0KYU6zehRNzcF55tSq9gS0EA0KLS1jMTEwNTUyZDkyODdmMmU2NGI5NDFiZjQ2MWZlYWRlMGY2ZjYxMzAwYmE0OTUzOGNlNTM1N2NmZmZkYjctLQ0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3724" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:24 GMT" + ], + "Etag": [ + "CIvhwNqW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051363000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrjo80:4463,/bns/yv/borg/yv/bns/blobstore2/bitpusher/227.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=98usW4bHHMTDswat-Z-oBg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/227.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/227:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWW5wTmtlLU9kVkRTVDlqMDhzYkVvZ2hLYjlqRzhpWDJuQm5JM01lY1Z4VHg3Nnl6Z3lXb3hkeTZQNk43bDc3WlFuNmVUUm5mcnpKX1VUNEpvV05pcmpXTGxCT2gteHBPQVFpMTQ3NnU5ak9IZEVNVElfSTVrQzJQV2tBcUxmWXpDVjIwN041aXgweGItdW1NQkJKN1ExUFdFSEtyNE1pS3JZTjhteWdELUVxRjVDS2w2eTl5NjFTZ0EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up8vhQLTWrrLCJUmodPR52LzVY3pyY11BUbmWjHUWFWwG_PE_9vZUSZpSouGDBDWbFRxivAE0aMqb9hA38xDT0xE_6sSg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wyLzE1MzgwNTEwNjM5NTE0OTkiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hY2wyIiwibmFtZSI6ImFjbDIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA2Mzk1MTQ5OSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjIzLjk1MVoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoyMy45NTFaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MjMuOTUxWiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJhbXRjMGpVZloyQ0VGMEdWZjVUemV3PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMj9nZW5lcmF0aW9uPTE1MzgwNTEwNjM5NTE0OTkmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsMi8xNTM4MDUxMDYzOTUxNDk5L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjM5NTE0OTkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJdmh3TnFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wyLzE1MzgwNTEwNjM5NTE0OTkvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMi9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYWNsMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDYzOTUxNDk5IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNJdmh3TnFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wyLzE1MzgwNTEwNjM5NTE0OTkvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYWNsMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDYzOTUxNDk5IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSXZod05xVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsMi8xNTM4MDUxMDYzOTUxNDk5L2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMi9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjM5NTE0OTkiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNJdmh3TnFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wyLzE1MzgwNTEwNjM5NTE0OTkvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2FjbDIvYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjM5NTE0OTkiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSXZod05xVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Illkcmp4Zz09IiwiZXRhZyI6IkNJdmh3TnFXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "a7899fab4dae114e", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/acl1/acl?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "c8c8a1cb5d5b081bd731d3092162697c/9416381441058621030;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/acl1/acl?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2839" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:24 GMT" + ], + "Etag": [ + "CNXmlNqW290CEAE=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:24 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051364000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnlk21:4416,/bns/yx/borg/yx/bns/blobstore2/bitpusher/170.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=-MusW-KiC4TEzALh36GYDg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/170.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/170:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWW5wTmtlLU9kVkRTVDlqMDhzYkVvZ2hLYjlqRzhpWDJuQm5JM01lY1Z4VHg3Nnl6Z3lXb3hkeTZQNk43bDc3WlFuNmVUUm5mcnpKX1VUNEpvV05pcmpXTGxCT2gteHBPQVFpMTQ3NnU5ak9IZEVNVElfSTVrQzJQV2tBcUxmWXpDVjIwN041aXgweGItdW1NQkJKN1ExUFdFSEtyNE1pS3JZTjhteWdELUVxRjVDS2w2eTl5NjFTZ0EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpFRiGkVMXwsRyEVHcvreKGdfu1e4GRGxDKzqQzqicudPyGfU1oNimPJublOVcvpSMPGbFW3PG3R_cChKGjcMDAka_o6-u5l8M_0QCRcCL5jrK7YPE" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsMS8xNTM4MDUxMDYzMjMxMzE3L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjMyMzEzMTciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNOWG1sTnFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wxLzE1MzgwNTEwNjMyMzEzMTcvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMS9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYWNsMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDYzMjMxMzE3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNOWG1sTnFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wxLzE1MzgwNTEwNjMyMzEzMTcvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMS9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYWNsMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDYzMjMxMzE3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTlhtbE5xVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsMS8xNTM4MDUxMDYzMjMxMzE3L2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMS9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjMyMzEzMTciLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNOWG1sTnFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wxLzE1MzgwNTEwNjMyMzEzMTcvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2FjbDEvYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjMyMzEzMTciLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTlhtbE5xVzI5MENFQUU9In1dfQ==" + } + }, + { + "ID": "71bd060a33809794", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/acl1/acl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "40eb07e858b191346b807395316f863c/11006793340814158852;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/acl1/acl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:24 GMT" + ], + "Etag": [ + "CNXmlNqW290CEAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051361000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrkq2:4275,/bns/yv/borg/yv/bns/blobstore2/bitpusher/66.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=-MusW9feEYutgATw86vwBw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/66.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/66:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWW5wTmtlLU9kVkRTVDlqMDhzYkVvZ2hLYjlqRzhpWDJuQm5JM01lY1Z4VHg3Nnl6Z3lXb3hkeTZQNk43bDc3WlFuNmVUUm5mcnpKX1VUNEpvV05pcmpXTGxCT2gteHBPQVFpMTQ3NnU5ak9IZEVNVElfSTVrQzJQV2tBcUxmWXpDVjIwN041aXgweGItdW1NQkJKN1ExUFdFSEtyNE1pS3JZTjhteWdELUVxRjVDS2w2eTl5NjFTZ0EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpWcAHikAmqOg613kF4GLJiEtCXxxIqN3tffPAx8FWSaOAq_FpvPloU22Ug_XvB_KhhecqbFCXQB6pcuta5ItyeOmLNeg" + ] + }, + "Body": "" + } + }, + { + "ID": "c8ad252a6aa45862", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "be850e2dc6a30f10d7d84d57edf55b35/12596923774199566755;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:26 GMT" + ], + "Etag": [ + "CAc=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051361000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrub8:4298,/bns/yr/borg/yr/bns/blobstore2/bitpusher/74.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=-MusW-uRKtC64QSEt534Cw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/74.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/74:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWW5wTmtlLU9kVkRTVDlqMDhzYkVvZ2hLYjlqRzhpWDJuQm5JM01lY1Z4VHg3Nnl6Z3lXb3hkeTZQNk43bDc3WlFuNmVUUm5mcnpKX1VUNEpvV05pcmpXTGxCT2gteHBPQVFpMTQ3NnU5ak9IZEVNVElfSTVrQzJQV2tBcUxmWXpDVjIwN041aXgweGItdW1NQkJKN1ExUFdFSEtyNE1pS3JZTjhteWdELUVxRjVDS2w2eTl5NjFTZ0EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpSjnNG8skCQpRLGO9ra7v9LGpcH7MJ7zZvV2z1z7mtvPZnVOI_c_4hoHzqBZK4BKOYIXZv29JlLxle7OIksM783IQ7xQ" + ] + }, + "Body": "" + } + }, + { + "ID": "ae6f08a80bb80c90", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/acl/user-jbd%40google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "109" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "2c258adc583f7fd54fabdbd920701d4d/14187335678249940802;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/acl/user-jbd%40google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJ1c2VyLWpiZEBnb29nbGUuY29tIiwicm9sZSI6IlJFQURFUiJ9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "386" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:27 GMT" + ], + "Etag": [ + "CAg=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051364000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vneu135:4203,/bns/yx/borg/yx/bns/blobstore2/bitpusher/117.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=-susW9jWCsW4zALG9Lq4BQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/117.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/117:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWW5wTmtlLU9kVkRTVDlqMDhzYkVvZ2hLYjlqRzhpWDJuQm5JM01lY1Z4VHg3Nnl6Z3lXb3hkeTZQNk43bDc3WlFuNmVUUm5mcnpKX1VUNEpvV05pcmpXTGxCT2gteHBPQVFpMTQ3NnU5ak9IZEVNVElfSTVrQzJQV2tBcUxmWXpDVjIwN041aXgweGItdW1NQkJKN1ExUFdFSEtyNE1pS3JZTjhteWdELUVxRjVDS2w2eTl5NjFTZ0EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqTGiHMpN75V5boQOPvlbb2tLzUDUklf0wZc3HxAlGV7OG9Ugvl6ubQcDvmN80QOLwaKd4b_iV8jP3oLXAQRaTr13Q-hA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvdXNlci1qYmRAZ29vZ2xlLmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wvdXNlci1qYmRAZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImVudGl0eSI6InVzZXItamJkQGdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZW1haWwiOiJqYmRAZ29vZ2xlLmNvbSIsImV0YWciOiJDQWc9In0=" + } + }, + { + "ID": "dc66ea5c887df293", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/acl?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "7e111448e87fe73618a269734d491d61/15777747582317157600;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/acl?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "1777" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:27 GMT" + ], + "Etag": [ + "CAg=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:27 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051364000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnhp2:4092,/bns/yx/borg/yx/bns/blobstore2/bitpusher/50.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=-8usW62lKI-IzgKe0Y_gAg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/50.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/50:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWW5wTmtlLU9kVkRTVDlqMDhzYkVvZ2hLYjlqRzhpWDJuQm5JM01lY1Z4VHg3Nnl6Z3lXb3hkeTZQNk43bDc3WlFuNmVUUm5mcnpKX1VUNEpvV05pcmpXTGxCT2gteHBPQVFpMTQ3NnU5ak9IZEVNVElfSTVrQzJQV2tBcUxmWXpDVjIwN041aXgweGItdW1NQkJKN1ExUFdFSEtyNE1pS3JZTjhteWdELUVxRjVDS2w2eTl5NjFTZ0EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrflKaiPlva3DQV4NWxxnOa2hfduPuphSMtQD2OmKfWIDBhU1BPZpFeTcuNqMIOVwsC-M9G3R5XRryG0CapLuunYg3wng" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQWc9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FnPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQWc9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvdXNlci1qYmRAZ29vZ2xlLmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wvdXNlci1qYmRAZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImVudGl0eSI6InVzZXItamJkQGdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZW1haWwiOiJqYmRAZ29vZ2xlLmNvbSIsImV0YWciOiJDQWc9In1dfQ==" + } + }, + { + "ID": "6988c44cbcd63252", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/acl/user-jbd%40google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "7824d8a22901b6dc78f094369cee52a4/17295820417369735807;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/acl/user-jbd%40google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:29 GMT" + ], + "Etag": [ + "CAk=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051361000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlh82:4312,/bns/yv/borg/yv/bns/blobstore2/bitpusher/293.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=_MusW-ubAYrHggTf2qigAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/293.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/293:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWW5wTmtlLU9kVkRTVDlqMDhzYkVvZ2hLYjlqRzhpWDJuQm5JM01lY1Z4VHg3Nnl6Z3lXb3hkeTZQNk43bDc3WlFuNmVUUm5mcnpKX1VUNEpvV05pcmpXTGxCT2gteHBPQVFpMTQ3NnU5ak9IZEVNVElfSTVrQzJQV2tBcUxmWXpDVjIwN041aXgweGItdW1NQkJKN1ExUFdFSEtyNE1pS3JZTjhteWdELUVxRjVDS2w2eTl5NjFTZ0EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq_n1FZwk3gYg6nAGXjBoIOUouelYbfFQqmodyBNo_ulBDapPpDibBCuyMxYoXTJP2tEN-TdzDpGLiZwNbDloq2veRMyg" + ] + }, + "Body": "" + } + }, + { + "ID": "eac7250806cf8014", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=c6748b629d4eae76c06554d06fdeedfb8a51d443f380a3b048fd306bb5f0" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "fed836e58a3445cb457b56c538559402/18127195351998977486;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS1jNjc0OGI2MjlkNGVhZTc2YzA2NTU0ZDA2ZmRlZWRmYjhhNTFkNDQzZjM4MGEzYjA0OGZkMzA2YmI1ZjANCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsIm5hbWUiOiJnb3BoZXIifQoNCi0tYzY3NDhiNjI5ZDRlYWU3NmMwNjU1NGQwNmZkZWVkZmI4YTUxZDQ0M2YzODBhM2IwNDhmZDMwNmJiNWYwDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgNCg0KZGF0YQ0KLS1jNjc0OGI2MjlkNGVhZTc2YzA2NTU0ZDA2ZmRlZWRmYjhhNTFkNDQzZjM4MGEzYjA0OGZkMzA2YmI1ZjAtLQ0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3289" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:29 GMT" + ], + "Etag": [ + "CMDsot2W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051369000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlh82:4312,/bns/yw/borg/yw/bns/blobstore2/bitpusher/85.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=_cusW8DTG8j0hQSdnoHgBg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/85.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/85:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYWpXSE1RZzgtWC1YcW42akZrMFVnT1pjQ2Rvc2J1RUtOdTFmNUpqa2xzSm0xUHllZVo1SEJlMG90M2RIanQ4V3RuaVVQNVNWR1JZOHd3eHhrUG5xV0ZOZkVnYl9YOWNNWUZuZ1R6bGhMQ05wZlZjM2ozYWZqQTgxM0VFSDVVeDlOdnRTalZyb1F4aFF0dW1SMTF5bVB0N0lLYjE3Q01LLVhtcVFtVVRlWWVkYTVsdkptOVR0R29RdjQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uodf8xTcx7etvqc3f4RRRu3WMp7IuuKJts9MRsx9NWjdzStcROpLMOWPCAEtzxu7s5M0DASp3Ci_Oo8NlRpnqCFkPOtIQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9nb3BoZXIvMTUzODA1MTA2OTc1Mjg5NiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2dvcGhlciIsIm5hbWUiOiJnb3BoZXIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA2OTc1Mjg5NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoyOS43NTJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MjkuNzUyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjI5Ljc1MloiLCJzaXplIjoiNCIsIm1kNUhhc2giOiJqWGQvT0YwOS9zaUJYU0QzU1dBbTNBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vZ29waGVyP2dlbmVyYXRpb249MTUzODA1MTA2OTc1Mjg5NiZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9nb3BoZXIvMTUzODA1MTA2OTc1Mjg5Ni9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2dvcGhlci9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJnb3BoZXIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA2OTc1Mjg5NiIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ01Ec290MlcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2dvcGhlci8xNTM4MDUxMDY5NzUyODk2L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2dvcGhlci9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiZ29waGVyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjk3NTI4OTYiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ01Ec290MlcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2dvcGhlci8xNTM4MDUxMDY5NzUyODk2L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2dvcGhlci9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiZ29waGVyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjk3NTI4OTYiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNNRHNvdDJXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9nb3BoZXIvMTUzODA1MTA2OTc1Mjg5Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vZ29waGVyL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiZ29waGVyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjk3NTI4OTYiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTURzb3QyVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6InJ0aDkwUT09IiwiZXRhZyI6IkNNRHNvdDJXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "4ef441b851b9a7a5", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=f04625b0d2c2814594fbfad64c8c764f2a0494d870f89d82505f7f18263e" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "7196054bc52c5e48e243ecf0a0692ab4/439769722704045854;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS1mMDQ2MjViMGQyYzI4MTQ1OTRmYmZhZDY0YzhjNzY0ZjJhMDQ5NGQ4NzBmODlkODI1MDVmN2YxODI2M2UNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsIm5hbWUiOiLQk9C+0YTQtdGA0L7QstC4In0KDQotLWYwNDYyNWIwZDJjMjgxNDU5NGZiZmFkNjRjOGM3NjRmMmEwNDk0ZDg3MGY4OWQ4MjUwNWY3ZjE4MjYzZQ0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04DQoNCmRhdGENCi0tZjA0NjI1YjBkMmMyODE0NTk0ZmJmYWQ2NGM4Yzc2NGYyYTA0OTRkODcwZjg5ZDgyNTA1ZjdmMTgyNjNlLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3641" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:30 GMT" + ], + "Etag": [ + "CJWewd2W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051369000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbj128:4260,/bns/yv/borg/yv/bns/blobstore2/bitpusher/243.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=_cusW6G9OoGngASMt5uwAw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/243.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/243:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYWpXSE1RZzgtWC1YcW42akZrMFVnT1pjQ2Rvc2J1RUtOdTFmNUpqa2xzSm0xUHllZVo1SEJlMG90M2RIanQ4V3RuaVVQNVNWR1JZOHd3eHhrUG5xV0ZOZkVnYl9YOWNNWUZuZ1R6bGhMQ05wZlZjM2ozYWZqQTgxM0VFSDVVeDlOdnRTalZyb1F4aFF0dW1SMTF5bVB0N0lLYjE3Q01LLVhtcVFtVVRlWWVkYTVsdkptOVR0R29RdjQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoymSoCfGxXc7APKQXbmtsRQ5lzh2kvwdBa2Vk-i19BsKrjJdAKre3OMjddfdx92y6qJM6ifd_otz5K-1VT5fbVgGVktA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS/Qk9C+0YTQtdGA0L7QstC4LzE1MzgwNTEwNzAyNTA3NzMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby8lRDAlOTMlRDAlQkUlRDElODQlRDAlQjUlRDElODAlRDAlQkUlRDAlQjIlRDAlQjgiLCJuYW1lIjoi0JPQvtGE0LXRgNC+0LLQuCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDcwMjUwNzczIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjMwLjI1MFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozMC4yNTBaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzAuMjUwWiIsInNpemUiOiI0IiwibWQ1SGFzaCI6ImpYZC9PRjA5L3NpQlhTRDNTV0FtM0E9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby8lRDAlOTMlRDAlQkUlRDElODQlRDAlQjUlRDElODAlRDAlQkUlRDAlQjIlRDAlQjg/Z2VuZXJhdGlvbj0xNTM4MDUxMDcwMjUwNzczJmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL9CT0L7RhNC10YDQvtCy0LgvMTUzODA1MTA3MDI1MDc3My9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vLyVEMCU5MyVEMCVCRSVEMSU4NCVEMCVCNSVEMSU4MCVEMCVCRSVEMCVCMiVEMCVCOC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiLQk9C+0YTQtdGA0L7QstC4IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzAyNTA3NzMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKV2V3ZDJXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS/Qk9C+0YTQtdGA0L7QstC4LzE1MzgwNTEwNzAyNTA3NzMvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vJUQwJTkzJUQwJUJFJUQxJTg0JUQwJUI1JUQxJTgwJUQwJUJFJUQwJUIyJUQwJUI4L2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiLQk9C+0YTQtdGA0L7QstC4IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzAyNTA3NzMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0pXZXdkMlcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL9CT0L7RhNC10YDQvtCy0LgvMTUzODA1MTA3MDI1MDc3My9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby8lRDAlOTMlRDAlQkUlRDElODQlRDAlQjUlRDElODAlRDAlQkUlRDAlQjIlRDAlQjgvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ItCT0L7RhNC10YDQvtCy0LgiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3MDI1MDc3MyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0pXZXdkMlcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL9CT0L7RhNC10YDQvtCy0LgvMTUzODA1MTA3MDI1MDc3My91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vJUQwJTkzJUQwJUJFJUQxJTg0JUQwJUI1JUQxJTgwJUQwJUJFJUQwJUIyJUQwJUI4L2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoi0JPQvtGE0LXRgNC+0LLQuCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDcwMjUwNzczIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0pXZXdkMlcyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJydGg5MFE9PSIsImV0YWciOiJDSldld2QyVzI5MENFQUU9In0=" + } + }, + { + "ID": "9b6f1ab259dce928", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=5b1027ba28d1f511cf08fc457ba061ff4b2b59813cc7f9ec4cee9e9f594f" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9ab324a2eab6d04c2e87770ac63723b7/1270863186651544173;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS01YjEwMjdiYTI4ZDFmNTExY2YwOGZjNDU3YmEwNjFmZjRiMmI1OTgxM2NjN2Y5ZWM0Y2VlOWU5ZjU5NGYNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsIm5hbWUiOiJhIn0KDQotLTViMTAyN2JhMjhkMWY1MTFjZjA4ZmM0NTdiYTA2MWZmNGIyYjU5ODEzY2M3ZjllYzRjZWU5ZTlmNTk0Zg0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04DQoNCmRhdGENCi0tNWIxMDI3YmEyOGQxZjUxMWNmMDhmYzQ1N2JhMDYxZmY0YjJiNTk4MTNjYzdmOWVjNGNlZTllOWY1OTRmLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3209" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:31 GMT" + ], + "Etag": [ + "CIDy6t2W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051370000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vncw67:4172,/bns/yx/borg/yx/bns/blobstore2/bitpusher/105.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=_susW5zyHYbjzAKq95zACQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/105.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/105:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYWpXSE1RZzgtWC1YcW42akZrMFVnT1pjQ2Rvc2J1RUtOdTFmNUpqa2xzSm0xUHllZVo1SEJlMG90M2RIanQ4V3RuaVVQNVNWR1JZOHd3eHhrUG5xV0ZOZkVnYl9YOWNNWUZuZ1R6bGhMQ05wZlZjM2ozYWZqQTgxM0VFSDVVeDlOdnRTalZyb1F4aFF0dW1SMTF5bVB0N0lLYjE3Q01LLVhtcVFtVVRlWWVkYTVsdkptOVR0R29RdjQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo0atLVtSxYUq5rmgP5HeIiR7gyuLMhuEPkA-fQusOaxV0362YXm0oSsaVYF_Smh_-XKQJb8Yaf04_lO7ndJ2-Pv-9uew" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hLzE1MzgwNTEwNzA5MzMyNDgiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hIiwibmFtZSI6ImEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3MDkzMzI0OCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozMC45MzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzAuOTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjMwLjkzMloiLCJzaXplIjoiNCIsIm1kNUhhc2giOiJqWGQvT0YwOS9zaUJYU0QzU1dBbTNBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYT9nZW5lcmF0aW9uPTE1MzgwNTEwNzA5MzMyNDgmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYS8xNTM4MDUxMDcwOTMzMjQ4L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzA5MzMyNDgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJRHk2dDJXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hLzE1MzgwNTEwNzA5MzMyNDgvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYS9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDcwOTMzMjQ4IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNJRHk2dDJXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hLzE1MzgwNTEwNzA5MzMyNDgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYS9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDcwOTMzMjQ4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSUR5NnQyVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYS8xNTM4MDUxMDcwOTMzMjQ4L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDcwOTMzMjQ4IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0lEeTZ0MlcyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJydGg5MFE9PSIsImV0YWciOiJDSUR5NnQyVzI5MENFQUU9In0=" + } + }, + { + "ID": "56e95f3da4f5347b", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=0798d81003f7bb4b09cf4ac08a194cf5f0d0f6a9a00f2deda8bd5d67fbe5" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "f590d185300c39d7a14ebc4e9eb2d352/2030181626754485692;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0wNzk4ZDgxMDAzZjdiYjRiMDljZjRhYzA4YTE5NGNmNWYwZDBmNmE5YTAwZjJkZWRhOGJkNWQ2N2ZiZTUNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsIm5hbWUiOiJhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhIn0KDQotLTA3OThkODEwMDNmN2JiNGIwOWNmNGFjMDhhMTk0Y2Y1ZjBkMGY2YTlhMDBmMmRlZGE4YmQ1ZDY3ZmJlNQ0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04DQoNCmRhdGENCi0tMDc5OGQ4MTAwM2Y3YmI0YjA5Y2Y0YWMwOGExOTRjZjVmMGQwZjZhOWEwMGYyZGVkYThiZDVkNjdmYmU1LS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "19577" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:31 GMT" + ], + "Etag": [ + "CKaqkN6W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051369000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrda18:4093,/bns/yv/borg/yv/bns/blobstore2/bitpusher/135.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=_8usW-OlBoiRNq7qqOgL" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/135.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/135:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYWpXSE1RZzgtWC1YcW42akZrMFVnT1pjQ2Rvc2J1RUtOdTFmNUpqa2xzSm0xUHllZVo1SEJlMG90M2RIanQ4V3RuaVVQNVNWR1JZOHd3eHhrUG5xV0ZOZkVnYl9YOWNNWUZuZ1R6bGhMQ05wZlZjM2ozYWZqQTgxM0VFSDVVeDlOdnRTalZyb1F4aFF0dW1SMTF5bVB0N0lLYjE3Q01LLVhtcVFtVVRlWWVkYTVsdkptOVR0R29RdjQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqitVkCUeUSJ0G4bi61MMByLVbIbbL-Xbw8R9bTZw4DcXcbckZu_ElUFTC7Up_z7JML2BBtH7edDzXjDj6yKygUj3t_3w" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhLzE1MzgwNTEwNzE1NDY2NjIiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhIiwibmFtZSI6ImFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3MTU0NjY2MiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozMS41NDVaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzEuNTQ1WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjMxLjU0NVoiLCJzaXplIjoiNCIsIm1kNUhhc2giOiJqWGQvT0YwOS9zaUJYU0QzU1dBbTNBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYT9nZW5lcmF0aW9uPTE1MzgwNTEwNzE1NDY2NjImYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYS8xNTM4MDUxMDcxNTQ2NjYyL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzE1NDY2NjIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNLYXFrTjZXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhLzE1MzgwNTEwNzE1NDY2NjIvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYS9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDcxNTQ2NjYyIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNLYXFrTjZXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhLzE1MzgwNTEwNzE1NDY2NjIvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYS9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDcxNTQ2NjYyIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDS2Fxa042VzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYS8xNTM4MDUxMDcxNTQ2NjYyL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDcxNTQ2NjYyIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0thcWtONlcyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJydGg5MFE9PSIsImV0YWciOiJDS2Fxa042VzI5MENFQUU9In0=" + } + }, + { + "ID": "50a6fa719716e926", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=0f0345a33370001633096093c9ee25e720b209d560d3c5ec8e17c6144f51" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d767ee61a2940cecbb7f6b2d1bc29950/2861275086423793420;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0wZjAzNDVhMzMzNzAwMDE2MzMwOTYwOTNjOWVlMjVlNzIwYjIwOWQ1NjBkM2M1ZWM4ZTE3YzYxNDRmNTENCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCJ9Cg0KLS0wZjAzNDVhMzMzNzAwMDE2MzMwOTYwOTNjOWVlMjVlNzIwYjIwOWQ1NjBkM2M1ZWM4ZTE3YzYxNDRmNTENCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOA0KDQpkYXRhDQotLTBmMDM0NWEzMzM3MDAwMTYzMzA5NjA5M2M5ZWUyNWU3MjBiMjA5ZDU2MGQzYzVlYzhlMTdjNjE0NGY1MS0tDQo=" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "2904" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:31 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051369000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrt3:4124,/bns/yr/borg/yr/bns/blobstore2/bitpusher/83.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=_8usW5bEKszg4QTBwYGIAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/83.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/83:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYWpXSE1RZzgtWC1YcW42akZrMFVnT1pjQ2Rvc2J1RUtOdTFmNUpqa2xzSm0xUHllZVo1SEJlMG90M2RIanQ4V3RuaVVQNVNWR1JZOHd3eHhrUG5xV0ZOZkVnYl9YOWNNWUZuZ1R6bGhMQ05wZlZjM2ozYWZqQTgxM0VFSDVVeDlOdnRTalZyb1F4aFF0dW1SMTF5bVB0N0lLYjE3Q01LLVhtcVFtVVRlWWVkYTVsdkptOVR0R29RdjQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqJW-7_6r7bI9eCj-JXqdY3BwbF-5mq1pbODJxD5tB34ilLdpKSYdEv7K0rLVA3hZMwyxbrlwJLEvD07ShK4YL90xl-WQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IlJlcXVpcmVkIiwiZGVidWdJbmZvIjoiY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89bnVsbCwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWJhZFJlcXVlc3QsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLlJFUVVJUkVELCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1udWxsLCBlcnJvclByb3RvQ29kZT1SRVFVSVJFRCwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UuaWQubmFtZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlLmlkLm5hbWUsIG1lc3NhZ2U9UmVxdWlyZWQsIHJlYXNvbj1yZXF1aXJlZCwgcnBjQ29kZT00MDB9IFJlcXVpcmVkXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMCwibWVzc2FnZSI6IlJlcXVpcmVkIn19" + } + }, + { + "ID": "0ae9542b9ce49562", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=bcdca74de9a098617ef24a96ac27659fd795f59257d9d3c5216fc1ead110" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9cb312c9ed3dcb4d3eb2dfd968e32e2e/3620593526526734939;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS1iY2RjYTc0ZGU5YTA5ODYxN2VmMjRhOTZhYzI3NjU5ZmQ3OTVmNTkyNTdkOWQzYzUyMTZmYzFlYWQxMTANCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsIm5hbWUiOiJhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYSJ9Cg0KLS1iY2RjYTc0ZGU5YTA5ODYxN2VmMjRhOTZhYzI3NjU5ZmQ3OTVmNTkyNTdkOWQzYzUyMTZmYzFlYWQxMTANCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOA0KDQpkYXRhDQotLWJjZGNhNzRkZTlhMDk4NjE3ZWYyNGE5NmFjMjc2NTlmZDc5NWY1OTI1N2Q5ZDNjNTIxNmZjMWVhZDExMC0tDQo=" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "4741" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:31 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051369000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrhl7:4484,/bns/yr/borg/yr/bns/blobstore2/bitpusher/103.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=_8usW6jXLcbo4QTkprCgCA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/103.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/103:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYWpXSE1RZzgtWC1YcW42akZrMFVnT1pjQ2Rvc2J1RUtOdTFmNUpqa2xzSm0xUHllZVo1SEJlMG90M2RIanQ4V3RuaVVQNVNWR1JZOHd3eHhrUG5xV0ZOZkVnYl9YOWNNWUZuZ1R6bGhMQ05wZlZjM2ozYWZqQTgxM0VFSDVVeDlOdnRTalZyb1F4aFF0dW1SMTF5bVB0N0lLYjE3Q01LLVhtcVFtVVRlWWVkYTVsdkptOVR0R29RdjQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrwiJOmyTbYn2nlEF1jPhSu_VazrdoOwJr2lCIC0mrJbSxlG2HMan9jQZe_-TpkuFPxrsS_ZN7W54ZgE9cQNrDjgeESBw" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImludmFsaWQiLCJtZXNzYWdlIjoiVGhlIG1heGltdW0gb2JqZWN0IGxlbmd0aCBpcyAxMDI0IGNoYXJhY3RlcnMsIGJ1dCBnb3QgYSBuYW1lIHdpdGggMTAyNSBjaGFyYWN0ZXJzOiAnJ2FhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhLi4uJyciLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9SU5WQUxJRF9WQUxVRSwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPW51bGwsIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5JTlZBTElEX1ZBTFVFLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1udWxsLCBlcnJvclByb3RvQ29kZT1JTlZBTElEX1ZBTFVFLCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5pZC5uYW1lLCBtZXNzYWdlPVRoZSBtYXhpbXVtIG9iamVjdCBsZW5ndGggaXMgMTAyNCBjaGFyYWN0ZXJzLCBidXQgZ290IGEgbmFtZSB3aXRoIDEwMjUgY2hhcmFjdGVyczogJydhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYS4uLicnLCB1bm5hbWVkQXJndW1lbnRzPVthYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYV19LCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UuaWQubmFtZSwgbWVzc2FnZT1UaGUgbWF4aW11bSBvYmplY3QgbGVuZ3RoIGlzIDEwMjQgY2hhcmFjdGVycywgYnV0IGdvdCBhIG5hbWUgd2l0aCAxMDI1IGNoYXJhY3RlcnM6ICcnYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEuLi4nJywgcmVhc29uPWludmFsaWQsIHJwY0NvZGU9NDAwfSBUaGUgbWF4aW11bSBvYmplY3QgbGVuZ3RoIGlzIDEwMjQgY2hhcmFjdGVycywgYnV0IGdvdCBhIG5hbWUgd2l0aCAxMDI1IGNoYXJhY3RlcnM6ICcnYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEuLi4nJ1xuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJUaGUgbWF4aW11bSBvYmplY3QgbGVuZ3RoIGlzIDEwMjQgY2hhcmFjdGVycywgYnV0IGdvdCBhIG5hbWUgd2l0aCAxMDI1IGNoYXJhY3RlcnM6ICcnYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEuLi4nJyJ9fQ==" + } + }, + { + "ID": "1f03f6aec789f628", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=190e7ca1112dfae89a1cc94346bd93ebccf5adb1d3ed48a35941130b41ef" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1c95398a95c726e69ab68d3262faba63/4451686990474233258;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0xOTBlN2NhMTExMmRmYWU4OWExY2M5NDM0NmJkOTNlYmNjZjVhZGIxZDNlZDQ4YTM1OTQxMTMwYjQxZWYNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsIm5hbWUiOiJuZXdcbmxpbmVzIn0KDQotLTE5MGU3Y2ExMTEyZGZhZTg5YTFjYzk0MzQ2YmQ5M2ViY2NmNWFkYjFkM2VkNDhhMzU5NDExMzBiNDFlZg0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04DQoNCmRhdGENCi0tMTkwZTdjYTExMTJkZmFlODlhMWNjOTQzNDZiZDkzZWJjY2Y1YWRiMWQzZWQ0OGEzNTk0MTEzMGI0MWVmLS0NCg==" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "3226" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:31 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051369000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrwe17:4005,/bns/yw/borg/yw/bns/blobstore2/bitpusher/148.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=_8usW5H7MIfzhASA9r_IDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/148.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/148:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYWpXSE1RZzgtWC1YcW42akZrMFVnT1pjQ2Rvc2J1RUtOdTFmNUpqa2xzSm0xUHllZVo1SEJlMG90M2RIanQ4V3RuaVVQNVNWR1JZOHd3eHhrUG5xV0ZOZkVnYl9YOWNNWUZuZ1R6bGhMQ05wZlZjM2ozYWZqQTgxM0VFSDVVeDlOdnRTalZyb1F4aFF0dW1SMTF5bVB0N0lLYjE3Q01LLVhtcVFtVVRlWWVkYTVsdkptOVR0R29RdjQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoAw4fjAOMtenHDXGbbkruczcQ5b8dIlEWdgiUXDyk4sWlmuMwgGtMVolvIBmrtajzJFtIYHNLBbIUWsXruMmnk2Hlwpw" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImludmFsaWQiLCJtZXNzYWdlIjoiRGlzYWxsb3dlZCB1bmljb2RlIGNoYXJhY3RlcnMgcHJlc2VudCBpbiBvYmplY3QgbmFtZSAnJ25ld1xubGluZXMnJyIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1JTlZBTElEX1ZBTFVFLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89bnVsbCwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWJhZFJlcXVlc3QsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLklOVkFMSURfVkFMVUUsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPW51bGwsIGVycm9yUHJvdG9Db2RlPUlOVkFMSURfVkFMVUUsIGVycm9yUHJvdG9Eb21haW49Z2RhdGEuQ29yZUVycm9yRG9tYWluLCBmaWx0ZXJlZE1lc3NhZ2U9bnVsbCwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlLmlkLm5hbWUsIG1lc3NhZ2U9RGlzYWxsb3dlZCB1bmljb2RlIGNoYXJhY3RlcnMgcHJlc2VudCBpbiBvYmplY3QgbmFtZSAnJ25ld1xubGluZXMnJywgdW5uYW1lZEFyZ3VtZW50cz1bbmV3XG5saW5lc119LCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UuaWQubmFtZSwgbWVzc2FnZT1EaXNhbGxvd2VkIHVuaWNvZGUgY2hhcmFjdGVycyBwcmVzZW50IGluIG9iamVjdCBuYW1lICcnbmV3XG5saW5lcycnLCByZWFzb249aW52YWxpZCwgcnBjQ29kZT00MDB9IERpc2FsbG93ZWQgdW5pY29kZSBjaGFyYWN0ZXJzIHByZXNlbnQgaW4gb2JqZWN0IG5hbWUgJyduZXdcbmxpbmVzJydcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAwLCJtZXNzYWdlIjoiRGlzYWxsb3dlZCB1bmljb2RlIGNoYXJhY3RlcnMgcHJlc2VudCBpbiBvYmplY3QgbmFtZSAnJ25ld1xubGluZXMnJyJ9fQ==" + } + }, + { + "ID": "77888c98dd46c50f", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "6a67c18da7762883b55d939f73d65794/5210723959895365882;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:32 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051369000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrnx7:4114,/bns/yw/borg/yw/bns/blobstore2/bitpusher/219.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=_8usW97SM5LfhASR57fgCA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/219.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/219:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYWpXSE1RZzgtWC1YcW42akZrMFVnT1pjQ2Rvc2J1RUtOdTFmNUpqa2xzSm0xUHllZVo1SEJlMG90M2RIanQ4V3RuaVVQNVNWR1JZOHd3eHhrUG5xV0ZOZkVnYl9YOWNNWUZuZ1R6bGhMQ05wZlZjM2ozYWZqQTgxM0VFSDVVeDlOdnRTalZyb1F4aFF0dW1SMTF5bVB0N0lLYjE3Q01LLVhtcVFtVVRlWWVkYTVsdkptOVR0R29RdjQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoMc9F9yE2HeDdmEyOjq_-pQVZkOPldnsVVz6TZ3F8Mzo0k_Pw5pjoQds9zzYbTnyrARRx-JKmlMCz2Ct6Zxuk-XTwiog" + ] + }, + "Body": "" + } + }, + { + "ID": "1e9c96c18d261238", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/a?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "2ffd36f41fda2e22f7b334d1571d73db/6042098894541384265;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/a?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:32 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051369000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrgm187:4292,/bns/yr/borg/yr/bns/blobstore2/bitpusher/53.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=AMysW97oE8X4kAOu3LKIDg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/53.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/53:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYWpXSE1RZzgtWC1YcW42akZrMFVnT1pjQ2Rvc2J1RUtOdTFmNUpqa2xzSm0xUHllZVo1SEJlMG90M2RIanQ4V3RuaVVQNVNWR1JZOHd3eHhrUG5xV0ZOZkVnYl9YOWNNWUZuZ1R6bGhMQ05wZlZjM2ozYWZqQTgxM0VFSDVVeDlOdnRTalZyb1F4aFF0dW1SMTF5bVB0N0lLYjE3Q01LLVhtcVFtVVRlWWVkYTVsdkptOVR0R29RdjQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq_TALy4oWt6x7_UhdJcTrDd-XeBpQCTuE_VL6gZAVdlJrsyEVmfzEimkElArzI936P6aIYOGxvtUg1KAvmtRwrd1DkFA" + ] + }, + "Body": "" + } + }, + { + "ID": "ee39c82f0126f7df", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/%D0%93%D0%BE%D1%84%D0%B5%D1%80%D0%BE%D0%B2%D0%B8?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "f17bd9206bec1c206ae08560a1123fc7/6801134764467731864;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/%D0%93%D0%BE%D1%84%D0%B5%D1%80%D0%BE%D0%B2%D0%B8?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:32 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051369000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrtj9:4196,/bns/yr/borg/yr/bns/blobstore2/bitpusher/71.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=AMysW8PRJ4_k4QTxpY3ICg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/71.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/71:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYWpXSE1RZzgtWC1YcW42akZrMFVnT1pjQ2Rvc2J1RUtOdTFmNUpqa2xzSm0xUHllZVo1SEJlMG90M2RIanQ4V3RuaVVQNVNWR1JZOHd3eHhrUG5xV0ZOZkVnYl9YOWNNWUZuZ1R6bGhMQ05wZlZjM2ozYWZqQTgxM0VFSDVVeDlOdnRTalZyb1F4aFF0dW1SMTF5bVB0N0lLYjE3Q01LLVhtcVFtVVRlWWVkYTVsdkptOVR0R29RdjQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpcuhQp3DVIylZVBiYUzlifqq6BCn60_Q9aODaQvOV57lTYDXmbWGOQWx6g7oXxCQSixgDxuXhWjEsD2NWOQrGVjiKbrA" + ] + }, + "Body": "" + } + }, + { + "ID": "7b050c6c970e744f", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/gopher?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4e3ba0b43bf75c16b32d162fa5dc35ff/7632228228415164648;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/gopher?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:33 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051369000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrvr22:4007,/bns/yr/borg/yr/bns/blobstore2/bitpusher/100.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=AMysW43oOc3WkAPE_IHQBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/100.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/100:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYWpXSE1RZzgtWC1YcW42akZrMFVnT1pjQ2Rvc2J1RUtOdTFmNUpqa2xzSm0xUHllZVo1SEJlMG90M2RIanQ4V3RuaVVQNVNWR1JZOHd3eHhrUG5xV0ZOZkVnYl9YOWNNWUZuZ1R6bGhMQ05wZlZjM2ozYWZqQTgxM0VFSDVVeDlOdnRTalZyb1F4aFF0dW1SMTF5bVB0N0lLYjE3Q01LLVhtcVFtVVRlWWVkYTVsdkptOVR0R29RdjQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo8308ofp3thGvMbSzyEx7nd1KdasYsdKvP0E4v7TM_frJ4pKcQm6YU2wFVXsdXCn4X2Na4TrqZS-l9SB5jhAxZpl4c4A" + ] + }, + "Body": "" + } + }, + { + "ID": "f24404f9531c7e01", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=79457bd469f23815a10c54bd62cf8a97d11ef0e4f79358930776cd29e128" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "c98f2d57e237dd67a4cceceb3b4423a9/8391546664223204151;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS03OTQ1N2JkNDY5ZjIzODE1YTEwYzU0YmQ2MmNmOGE5N2QxMWVmMGU0Zjc5MzU4OTMwNzc2Y2QyOWUxMjgNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsIm5hbWUiOiJjb250ZW50In0KDQotLTc5NDU3YmQ0NjlmMjM4MTVhMTBjNTRiZDYyY2Y4YTk3ZDExZWYwZTRmNzkzNTg5MzA3NzZjZDI5ZTEyOA0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04DQoNCkl0IHdhcyB0aGUgYmVzdCBvZiB0aW1lcywgaXQgd2FzIHRoZSB3b3JzdCBvZiB0aW1lcy4NCi0tNzk0NTdiZDQ2OWYyMzgxNWExMGM1NGJkNjJjZjhhOTdkMTFlZjBlNGY3OTM1ODkzMDc3NmNkMjllMTI4LS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3306" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:33 GMT" + ], + "Etag": [ + "COOykd+W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051373000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrl7:4233,/bns/yr/borg/yr/bns/blobstore2/bitpusher/69.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=AcysW7zkFMzx4QSiqbCQCw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/69.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/69:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWTdKaTNpQUtFYXBEb2hLZmRaV2FzVEpZLWRqMW43X1dRLUlwOGVYZ0cxOE93NE5IYkEwUHZlX0paQnd6b0pUNE9JRUYwcjVzM01Fa1ZQbHpvSnpXT1VOOUtsQV9OSENJcDl4QlRucmgtYU4wcDhuYkxwOTI2SHdRY0ZWRGQtMVBIclZQUVhZck9pQ3o1WUI1bkw4UjZpNWFJb3NHTUl4Qk4xV1ZUOWlCZW5malJ1TTF5SkUyQ2VTMDAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur4QwSCgclPX6trpMIhT0vdtpmHrRu46ea8c1Ic6bXrHSLHx81tT13NQ4Pp0hdYA8XatyZAwmgUb4WFY3qyapXMVLO_1w" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzM2NjEyODMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3MzY2MTI4MyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozMy42NjFaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzMuNjYxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjMzLjY2MVoiLCJzaXplIjoiNTIiLCJtZDVIYXNoIjoiSzI4NUF3S1dXZlZSZEJjQ1VYaHpOZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQ/Z2VuZXJhdGlvbj0xNTM4MDUxMDczNjYxMjgzJmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbnRlbnQvMTUzODA1MTA3MzY2MTI4My9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDczNjYxMjgzIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT095a2QrVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDczNjYxMjgzL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3MzY2MTI4MyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT095a2QrVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDczNjYxMjgzL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3MzY2MTI4MyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ09PeWtkK1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbnRlbnQvMTUzODA1MTA3MzY2MTI4My91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3MzY2MTI4MyIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPT3lrZCtXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiRmNYTThRPT0iLCJldGFnIjoiQ09PeWtkK1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "e9d49ef6cb2edd09", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/content?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3bff2347d8fb90f52b03b63484c816c2/9981677097608612054;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/content?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3306" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:33 GMT" + ], + "Etag": [ + "COOykd+W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051373000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrv5:4481,/bns/yv/borg/yv/bns/blobstore2/bitpusher/182.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=AcysW4SxL9WFgQSM1K-oDQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/182.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/182:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWTdKaTNpQUtFYXBEb2hLZmRaV2FzVEpZLWRqMW43X1dRLUlwOGVYZ0cxOE93NE5IYkEwUHZlX0paQnd6b0pUNE9JRUYwcjVzM01Fa1ZQbHpvSnpXT1VOOUtsQV9OSENJcDl4QlRucmgtYU4wcDhuYkxwOTI2SHdRY0ZWRGQtMVBIclZQUVhZck9pQ3o1WUI1bkw4UjZpNWFJb3NHTUl4Qk4xV1ZUOWlCZW5malJ1TTF5SkUyQ2VTMDAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpKyKaISEWquueFV4lfr3BrKEbt91VU2X2w7V9LAq9yelzjZBmz-oC-cQzyVvn0C0eLYGwXBVxtpNEKR4av7BY4G2BRfZAfM10r9K-cVmNkKBG3gZo" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzM2NjEyODMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3MzY2MTI4MyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozMy42NjFaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzMuNjYxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjMzLjY2MVoiLCJzaXplIjoiNTIiLCJtZDVIYXNoIjoiSzI4NUF3S1dXZlZSZEJjQ1VYaHpOZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQ/Z2VuZXJhdGlvbj0xNTM4MDUxMDczNjYxMjgzJmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbnRlbnQvMTUzODA1MTA3MzY2MTI4My9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDczNjYxMjgzIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT095a2QrVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDczNjYxMjgzL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3MzY2MTI4MyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT095a2QrVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDczNjYxMjgzL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3MzY2MTI4MyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ09PeWtkK1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbnRlbnQvMTUzODA1MTA3MzY2MTI4My91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3MzY2MTI4MyIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPT3lrZCtXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiRmNYTThRPT0iLCJldGFnIjoiQ09PeWtkK1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "151fc10cc5fad9fd", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=988437801ee1a9246232838eec36a9a90e52a9a42f54ffe7c8b6e41a5972" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "fcd3d5168b79bde9c2fce272a552a779/10740995537711553317;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS05ODg0Mzc4MDFlZTFhOTI0NjIzMjgzOGVlYzM2YTlhOTBlNTJhOWE0MmY1NGZmZTdjOGI2ZTQxYTU5NzINCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsIm5hbWUiOiJjb250ZW50In0KDQotLTk4ODQzNzgwMWVlMWE5MjQ2MjMyODM4ZWVjMzZhOWE5MGU1MmE5YTQyZjU0ZmZlN2M4YjZlNDFhNTk3Mg0KQ29udGVudC1UeXBlOiB0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLTgNCg0KPGh0bWw+PGhlYWQ+PHRpdGxlPk15IGZpcnN0IHBhZ2U8L3RpdGxlPjwvaGVhZD48L2h0bWw+DQotLTk4ODQzNzgwMWVlMWE5MjQ2MjMyODM4ZWVjMzZhOWE5MGU1MmE5YTQyZjU0ZmZlN2M4YjZlNDFhNTk3Mi0tDQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3305" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:34 GMT" + ], + "Etag": [ + "CLLBtN+W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051373000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vraw6:4495,/bns/yr/borg/yr/bns/blobstore2/bitpusher/99.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=AcysW9foNYi44QT15L5A" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/99.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/99:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWTdKaTNpQUtFYXBEb2hLZmRaV2FzVEpZLWRqMW43X1dRLUlwOGVYZ0cxOE93NE5IYkEwUHZlX0paQnd6b0pUNE9JRUYwcjVzM01Fa1ZQbHpvSnpXT1VOOUtsQV9OSENJcDl4QlRucmgtYU4wcDhuYkxwOTI2SHdRY0ZWRGQtMVBIclZQUVhZck9pQ3o1WUI1bkw4UjZpNWFJb3NHTUl4Qk4xV1ZUOWlCZW5malJ1TTF5SkUyQ2VTMDAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq0AeI4jGor5HSsfQM95EEyapL69zFATtcCRzvjOwNAcDuFOz94hOPLrpRQzUqLAGqS4q8DOEzE-xnP5WD64o-UkoR5bg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzQyMzY1OTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NDIzNjU5NCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM0LjIzNloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNC4yMzZaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzQuMjM2WiIsInNpemUiOiI1NCIsIm1kNUhhc2giOiJOOHA4L3M5RndkQUFubHZyL2xFQWpRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudD9nZW5lcmF0aW9uPTE1MzgwNTEwNzQyMzY1OTQmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDc0MjM2NTk0L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzQyMzY1OTQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMTEJ0TitXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzQyMzY1OTQvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc0MjM2NTk0IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMTEJ0TitXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzQyMzY1OTQvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc0MjM2NTk0IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTExCdE4rVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDc0MjM2NTk0L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50L2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc0MjM2NTk0IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0xMQnROK1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJHb1Vic1E9PSIsImV0YWciOiJDTExCdE4rVzI5MENFQUU9In0=" + } + }, + { + "ID": "7a91c5fbf00267a1", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/content?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "f27bc1c9491d357a63da36391e4159dd/12331407441778704580;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/content?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3305" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:34 GMT" + ], + "Etag": [ + "CLLBtN+W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051373000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrat7:4174,/bns/yv/borg/yv/bns/blobstore2/bitpusher/129.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=AsysW5bFFdP-gASw_pngAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/129.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/129:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWTdKaTNpQUtFYXBEb2hLZmRaV2FzVEpZLWRqMW43X1dRLUlwOGVYZ0cxOE93NE5IYkEwUHZlX0paQnd6b0pUNE9JRUYwcjVzM01Fa1ZQbHpvSnpXT1VOOUtsQV9OSENJcDl4QlRucmgtYU4wcDhuYkxwOTI2SHdRY0ZWRGQtMVBIclZQUVhZck9pQ3o1WUI1bkw4UjZpNWFJb3NHTUl4Qk4xV1ZUOWlCZW5malJ1TTF5SkUyQ2VTMDAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqNYY40vODTXqZDpfJEqECTQgqog4KbGxuycuszoFuk-7fVUd6p446qgHeljXPOeNB44EDswGxKxpWPX-PX_FrzqFU41g" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzQyMzY1OTQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NDIzNjU5NCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM0LjIzNloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNC4yMzZaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzQuMjM2WiIsInNpemUiOiI1NCIsIm1kNUhhc2giOiJOOHA4L3M5RndkQUFubHZyL2xFQWpRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudD9nZW5lcmF0aW9uPTE1MzgwNTEwNzQyMzY1OTQmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDc0MjM2NTk0L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzQyMzY1OTQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMTEJ0TitXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzQyMzY1OTQvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc0MjM2NTk0IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMTEJ0TitXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzQyMzY1OTQvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc0MjM2NTk0IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTExCdE4rVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDc0MjM2NTk0L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50L2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc0MjM2NTk0IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0xMQnROK1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJHb1Vic1E9PSIsImV0YWciOiJDTExCdE4rVzI5MENFQUU9In0=" + } + }, + { + "ID": "4c7ff4fe8be88426", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=2bc3dd5645f4717661991904c39270871075913fb3be34dd4fb00e9fb533" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "37b1664652a23037c645c3f3dfac05d5/13162500905726202643;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0yYmMzZGQ1NjQ1ZjQ3MTc2NjE5OTE5MDRjMzkyNzA4NzEwNzU5MTNmYjNiZTM0ZGQ0ZmIwMGU5ZmI1MzMNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9odG1sIiwibmFtZSI6ImNvbnRlbnQifQoNCi0tMmJjM2RkNTY0NWY0NzE3NjYxOTkxOTA0YzM5MjcwODcxMDc1OTEzZmIzYmUzNGRkNGZiMDBlOWZiNTMzDQpDb250ZW50LVR5cGU6IHRleHQvaHRtbA0KDQo8aHRtbD48aGVhZD48dGl0bGU+TXkgZmlyc3QgcGFnZTwvdGl0bGU+PC9oZWFkPjwvaHRtbD4NCi0tMmJjM2RkNTY0NWY0NzE3NjYxOTkxOTA0YzM5MjcwODcxMDc1OTEzZmIzYmUzNGRkNGZiMDBlOWZiNTMzLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3290" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:34 GMT" + ], + "Etag": [ + "CKia1N+W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051374000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnau137:4408,/bns/yx/borg/yx/bns/blobstore2/bitpusher/84.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=AsysW-vzGcO1zALTr7lY" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/84.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/84:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWTdKaTNpQUtFYXBEb2hLZmRaV2FzVEpZLWRqMW43X1dRLUlwOGVYZ0cxOE93NE5IYkEwUHZlX0paQnd6b0pUNE9JRUYwcjVzM01Fa1ZQbHpvSnpXT1VOOUtsQV9OSENJcDl4QlRucmgtYU4wcDhuYkxwOTI2SHdRY0ZWRGQtMVBIclZQUVhZck9pQ3o1WUI1bkw4UjZpNWFJb3NHTUl4Qk4xV1ZUOWlCZW5malJ1TTF5SkUyQ2VTMDAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoNJgqctgeYS02cdv67cIAhN4zbfhd5Igx0oOKU3ZYQnBDRFSS_YnaxjWfyGJpyzUYK-492G_o2VbkSQZ9hKyGVQecFtQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzQ3NTU4ODAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NDc1NTg4MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9odG1sIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM0Ljc1NVoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNC43NTVaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzQuNzU1WiIsInNpemUiOiI1NCIsIm1kNUhhc2giOiJOOHA4L3M5RndkQUFubHZyL2xFQWpRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudD9nZW5lcmF0aW9uPTE1MzgwNTEwNzQ3NTU4ODAmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDc0NzU1ODgwL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzQ3NTU4ODAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNLaWExTitXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzQ3NTU4ODAvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc0NzU1ODgwIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNLaWExTitXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzQ3NTU4ODAvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc0NzU1ODgwIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDS2lhMU4rVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDc0NzU1ODgwL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50L2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc0NzU1ODgwIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0tpYTFOK1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJHb1Vic1E9PSIsImV0YWciOiJDS2lhMU4rVzI5MENFQUU9In0=" + } + }, + { + "ID": "b6e9d9ae9b9ab978", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/content?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "2a9df9fee84fe18940299e1e19b963f3/14752911705986890161;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/content?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3290" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:34 GMT" + ], + "Etag": [ + "CKia1N+W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051373000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrnb2:4089,/bns/yv/borg/yv/bns/blobstore2/bitpusher/259.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=AsysW9TQNsmngASFkp7wAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/259.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/259:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWTdKaTNpQUtFYXBEb2hLZmRaV2FzVEpZLWRqMW43X1dRLUlwOGVYZ0cxOE93NE5IYkEwUHZlX0paQnd6b0pUNE9JRUYwcjVzM01Fa1ZQbHpvSnpXT1VOOUtsQV9OSENJcDl4QlRucmgtYU4wcDhuYkxwOTI2SHdRY0ZWRGQtMVBIclZQUVhZck9pQ3o1WUI1bkw4UjZpNWFJb3NHTUl4Qk4xV1ZUOWlCZW5malJ1TTF5SkUyQ2VTMDAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo2QCAedXJWZRu0_FYQQyJ9LFvRMq2tC7QKpClrN37a6mnhCEudZtWqGhevEpEYba9YwKYwez8KFNv0vso_czdyYI0IRQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzQ3NTU4ODAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NDc1NTg4MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9odG1sIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM0Ljc1NVoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNC43NTVaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzQuNzU1WiIsInNpemUiOiI1NCIsIm1kNUhhc2giOiJOOHA4L3M5RndkQUFubHZyL2xFQWpRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudD9nZW5lcmF0aW9uPTE1MzgwNTEwNzQ3NTU4ODAmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDc0NzU1ODgwL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzQ3NTU4ODAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNLaWExTitXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzQ3NTU4ODAvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc0NzU1ODgwIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNLaWExTitXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzQ3NTU4ODAvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc0NzU1ODgwIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDS2lhMU4rVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDc0NzU1ODgwL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50L2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc0NzU1ODgwIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0tpYTFOK1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJHb1Vic1E9PSIsImV0YWciOiJDS2lhMU4rVzI5MENFQUU9In0=" + } + }, + { + "ID": "7d1ddfc4a79aed5c", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=51b79aa9dfea162830fbd443aaeec47fe3d21d207f16c34b06ad6efaba79" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "994ad2d293093b6ed73587008f24a071/15511948675424799489;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS01MWI3OWFhOWRmZWExNjI4MzBmYmQ0NDNhYWVlYzQ3ZmUzZDIxZDIwN2YxNmMzNGIwNmFkNmVmYWJhNzkNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoiaW1hZ2UvanBlZyIsIm5hbWUiOiJjb250ZW50In0KDQotLTUxYjc5YWE5ZGZlYTE2MjgzMGZiZDQ0M2FhZWVjNDdmZTNkMjFkMjA3ZjE2YzM0YjA2YWQ2ZWZhYmE3OQ0KQ29udGVudC1UeXBlOiBpbWFnZS9qcGVnDQoNCjxodG1sPjxoZWFkPjx0aXRsZT5NeSBmaXJzdCBwYWdlPC90aXRsZT48L2hlYWQ+PC9odG1sPg0KLS01MWI3OWFhOWRmZWExNjI4MzBmYmQ0NDNhYWVlYzQ3ZmUzZDIxZDIwN2YxNmMzNGIwNmFkNmVmYWJhNzktLQ0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3291" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:35 GMT" + ], + "Etag": [ + "CIGg99+W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051373000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrmk5:4135,/bns/yr/borg/yr/bns/blobstore2/bitpusher/58.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=AsysW4yKPKyRkAS0ioHgCQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/58.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/58:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWTdKaTNpQUtFYXBEb2hLZmRaV2FzVEpZLWRqMW43X1dRLUlwOGVYZ0cxOE93NE5IYkEwUHZlX0paQnd6b0pUNE9JRUYwcjVzM01Fa1ZQbHpvSnpXT1VOOUtsQV9OSENJcDl4QlRucmgtYU4wcDhuYkxwOTI2SHdRY0ZWRGQtMVBIclZQUVhZck9pQ3o1WUI1bkw4UjZpNWFJb3NHTUl4Qk4xV1ZUOWlCZW5malJ1TTF5SkUyQ2VTMDAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up2B0gN0Tp-hZeNdZzqXr32fqBuXEdF_UfypqatMEY_Z8FElRH7MLrj1Q-6Li1qrYCd5lWBQDs0wz5FpqsHjBN_hytJyQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzUzMzAwNDkiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTMzMDA0OSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiaW1hZ2UvanBlZyIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNS4zMjlaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzUuMzI5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM1LjMyOVoiLCJzaXplIjoiNTQiLCJtZDVIYXNoIjoiTjhwOC9zOUZ3ZEFBbmx2ci9sRUFqUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQ/Z2VuZXJhdGlvbj0xNTM4MDUxMDc1MzMwMDQ5JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbnRlbnQvMTUzODA1MTA3NTMzMDA0OS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc1MzMwMDQ5IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSUdnOTkrVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDc1MzMwMDQ5L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTMzMDA0OSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSUdnOTkrVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDc1MzMwMDQ5L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTMzMDA0OSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0lHZzk5K1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbnRlbnQvMTUzODA1MTA3NTMzMDA0OS91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTMzMDA0OSIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJR2c5OStXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiR29VYnNRPT0iLCJldGFnIjoiQ0lHZzk5K1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "9b9ff11a993b6af6", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/content?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "c0c6e81b82b832c7e7354ea55a133407/17102360579475239327;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/content?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3291" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:35 GMT" + ], + "Etag": [ + "CIGg99+W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051373000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrb20:4129,/bns/yv/borg/yv/bns/blobstore2/bitpusher/82.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=A8ysW4nMHYOlgASf-Jco" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/82.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/82:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWTdKaTNpQUtFYXBEb2hLZmRaV2FzVEpZLWRqMW43X1dRLUlwOGVYZ0cxOE93NE5IYkEwUHZlX0paQnd6b0pUNE9JRUYwcjVzM01Fa1ZQbHpvSnpXT1VOOUtsQV9OSENJcDl4QlRucmgtYU4wcDhuYkxwOTI2SHdRY0ZWRGQtMVBIclZQUVhZck9pQ3o1WUI1bkw4UjZpNWFJb3NHTUl4Qk4xV1ZUOWlCZW5malJ1TTF5SkUyQ2VTMDAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Urvkgc7dWXoce48Vak9OxsOqstuo9yJWf7VkQKIC7EoQ9ElFapB3F4vwy8RWd6rYlRY_A0lHq2d09QlQyMfn83kYVuG3A" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzUzMzAwNDkiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50IiwibmFtZSI6ImNvbnRlbnQiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTMzMDA0OSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiaW1hZ2UvanBlZyIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNS4zMjlaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzUuMzI5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM1LjMyOVoiLCJzaXplIjoiNTQiLCJtZDVIYXNoIjoiTjhwOC9zOUZ3ZEFBbmx2ci9sRUFqUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQ/Z2VuZXJhdGlvbj0xNTM4MDUxMDc1MzMwMDQ5JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbnRlbnQvMTUzODA1MTA3NTMzMDA0OS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29udGVudCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc1MzMwMDQ5IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSUdnOTkrVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDc1MzMwMDQ5L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTMzMDA0OSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSUdnOTkrVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDc1MzMwMDQ5L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTMzMDA0OSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0lHZzk5K1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbnRlbnQvMTUzODA1MTA3NTMzMDA0OS91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudC9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTMzMDA0OSIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJR2c5OStXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiR29VYnNRPT0iLCJldGFnIjoiQ0lHZzk5K1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "7915606f6c21576d", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=48c8e7da3f6b7f4e8dcc258f6ef3c4c7de9547cf4235aa7c2ed097aeedd4" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b29b46c9f037a69e7b0959bc8004045b/17933454043422672111;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Encryption-Key-Sha256": [ + "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" + ] + }, + "Body": "LS00OGM4ZTdkYTNmNmI3ZjRlOGRjYzI1OGY2ZWYzYzRjN2RlOTU0N2NmNDIzNWFhN2MyZWQwOTdhZWVkZDQNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uIn0KDQotLTQ4YzhlN2RhM2Y2YjdmNGU4ZGNjMjU4ZjZlZjNjNGM3ZGU5NTQ3Y2Y0MjM1YWE3YzJlZDA5N2FlZWRkNA0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04DQoNCnRvcCBzZWNyZXQuDQotLTQ4YzhlN2RhM2Y2YjdmNGU4ZGNjMjU4ZjZlZjNjNGM3ZGU5NTQ3Y2Y0MjM1YWE3YzJlZDA5N2FlZWRkNC0tDQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3575" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:36 GMT" + ], + "Etag": [ + "CP+9neCW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051375000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdv17:4351,/bns/yv/borg/yv/bns/blobstore2/bitpusher/17.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=A8ysW4qiJ8XJswaz7rjgBA" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/17.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/17:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqzvI3XEU4LsqPtTfuuCmlZUYL5YtpZotdBHPMzeBjObeeIK9wicxApkA1uLnmxXHG3wXe79KGzi_z0-7UOlOA8R7dfcQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1MzgwNTEwNzU5NTY0NzkiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uIiwibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNS45NTZaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzUuOTU2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM1Ljk1NloiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24/Z2VuZXJhdGlvbj0xNTM4MDUxMDc1OTU2NDc5JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTUzODA1MTA3NTk1NjQ3OS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc1OTU2NDc5IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUCs5bmVDVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTM4MDUxMDc1OTU2NDc5L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUCs5bmVDVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTM4MDUxMDc1OTU2NDc5L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1ArOW5lQ1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTUzODA1MTA3NTk1NjQ3OS91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQKzluZUNXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoicjBOR3JnPT0iLCJldGFnIjoiQ1ArOW5lQ1cyOTBDRUFFPSIsImN1c3RvbWVyRW5jcnlwdGlvbiI6eyJlbmNyeXB0aW9uQWxnb3JpdGhtIjoiQUVTMjU2Iiwia2V5U2hhMjU2IjoiSCtMbW5YaFJvZUk2VE1XNWJzVjZIeVVrNnB5R2MySU1icVliQVhCY3BzMD0ifX0=" + } + }, + { + "ID": "27279c404174cd0f", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "2541c367ad31712ca166ba1982148194/1077403344462145933;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3518" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:36 GMT" + ], + "Etag": [ + "CP+9neCW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051376000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrd2:4398,/bns/yv/borg/yv/bns/blobstore2/bitpusher/289.scotty,yxfg3-v6:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=BMysW4rOC4b-gQTynLpY" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/289.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/289:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UobHr4iNFO6-9r3IkOShNUf7Rv82BaZMVlrnByS60R0XqB5gy7QwJuuI674ibIkITsLByBS3t5I3kadR6J7CZ03HgwNTQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1MzgwNTEwNzU5NTY0NzkiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uIiwibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNS45NTZaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzUuOTU2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM1Ljk1NloiLCJzaXplIjoiMTEiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbj9nZW5lcmF0aW9uPTE1MzgwNTEwNzU5NTY0NzkmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTM4MDUxMDc1OTU2NDc5L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzU5NTY0NzkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNQKzluZUNXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1MzgwNTEwNzU5NTY0NzkvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc1OTU2NDc5IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNQKzluZUNXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1MzgwNTEwNzU5NTY0NzkvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc1OTU2NDc5IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDUCs5bmVDVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTM4MDUxMDc1OTU2NDc5L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc1OTU2NDc5IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1ArOW5lQ1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJldGFnIjoiQ1ArOW5lQ1cyOTBDRUFFPSIsImN1c3RvbWVyRW5jcnlwdGlvbiI6eyJlbmNyeXB0aW9uQWxnb3JpdGhtIjoiQUVTMjU2Iiwia2V5U2hhMjU2IjoiSCtMbW5YaFJvZUk2VE1XNWJzVjZIeVVrNnB5R2MySU1icVliQVhCY3BzMD0ifX0=" + } + }, + { + "ID": "9682ead127083c80", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "2a7f95940036c65e3640342fae7c93c4/2595758754002996780;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Encryption-Key-Sha256": [ + "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3575" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:36 GMT" + ], + "Etag": [ + "CP+9neCW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051376000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlj28:4249,/bns/yv/borg/yv/bns/blobstore2/bitpusher/301.scotty,yxfg3-v6:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=BMysW9z8D8aPgQTXw4nIBw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/301.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/301:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Urk5p961WUKAYqlreEga30c6yCAbsJOf9uK54oZVhHgQWkBTEaU0MOuITSi7FEkYeMOcd1opYywE1gTpHfv04nDNAA7bQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1MzgwNTEwNzU5NTY0NzkiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uIiwibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNS45NTZaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzUuOTU2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM1Ljk1NloiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24/Z2VuZXJhdGlvbj0xNTM4MDUxMDc1OTU2NDc5JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTUzODA1MTA3NTk1NjQ3OS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc1OTU2NDc5IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUCs5bmVDVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTM4MDUxMDc1OTU2NDc5L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUCs5bmVDVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTM4MDUxMDc1OTU2NDc5L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1ArOW5lQ1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTUzODA1MTA3NTk1NjQ3OS91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQKzluZUNXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoicjBOR3JnPT0iLCJldGFnIjoiQ1ArOW5lQ1cyOTBDRUFFPSIsImN1c3RvbWVyRW5jcnlwdGlvbiI6eyJlbmNyeXB0aW9uQWxnb3JpdGhtIjoiQUVTMjU2Iiwia2V5U2hhMjU2IjoiSCtMbW5YaFJvZUk2VE1XNWJzVjZIeVVrNnB5R2MySU1icVliQVhCY3BzMD0ifX0=" + } + }, + { + "ID": "54252acc3c2342bf", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "85" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4952355c1972efdbeeb6168001442c8d/4185888087876777163;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3541" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:36 GMT" + ], + "Etag": [ + "CP+9neCW290CEAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051376000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlm74:4305,/bns/yw/borg/yw/bns/blobstore2/bitpusher/206.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=BMysW7COFIzohASsnZDICw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/206.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/206:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UquZDDN58SJOlHG4q0ngzir-KWmWbmxlvTSDL3P_jtECyMoB_2ZDlcTEUZ7lVHBrykjtsUvSPWGdnlUnXukeMLh4jKHjw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1MzgwNTEwNzU5NTY0NzkiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uIiwibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNS45NTZaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzYuMzk5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM1Ljk1NloiLCJzaXplIjoiMTEiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbj9nZW5lcmF0aW9uPTE1MzgwNTEwNzU5NTY0NzkmYWx0PW1lZGlhIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1MzgwNTEwNzU5NTY0NzkvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1ArOW5lQ1cyOTBDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTUzODA1MTA3NTk1NjQ3OS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzU5NTY0NzkiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1ArOW5lQ1cyOTBDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTUzODA1MTA3NTk1NjQ3OS9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzU5NTY0NzkiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQKzluZUNXMjkwQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1MzgwNTEwNzU5NTY0NzkvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzU5NTY0NzkiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUCs5bmVDVzI5MENFQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImV0YWciOiJDUCs5bmVDVzI5MENFQUk9IiwiY3VzdG9tZXJFbmNyeXB0aW9uIjp7ImVuY3J5cHRpb25BbGdvcml0aG0iOiJBRVMyNTYiLCJrZXlTaGEyNTYiOiJIK0xtblhoUm9lSTZUTVc1YnNWNkh5VWs2cHlHYzJJTWJxWWJBWEJjcHMwPSJ9fQ==" + } + }, + { + "ID": "1e4409ff71b6579d", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "85" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "c5ac5a686caeb5faf7bf1484a2414f90/5776299987649091945;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Encryption-Key-Sha256": [ + "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3598" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:36 GMT" + ], + "Etag": [ + "CP+9neCW290CEAM=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051376000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vru68:4179,/bns/yv/borg/yv/bns/blobstore2/bitpusher/118.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=BMysW67PH9-wggTBqo3gCg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/118.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/118:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrPSaT_6vjBr5ZzV4WDMHPA_SSvFO-ebrb6xmFNECjX9cUZ-ZoC56VvHY8gL7uwHfUHPqeOaXwM9qnMLA0MlGHobq1-gg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1MzgwNTEwNzU5NTY0NzkiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uIiwibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNS45NTZaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzYuNzQ3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM1Ljk1NloiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24/Z2VuZXJhdGlvbj0xNTM4MDUxMDc1OTU2NDc5JmFsdD1tZWRpYSIsImNvbnRlbnRMYW5ndWFnZSI6ImVuIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTM4MDUxMDc1OTU2NDc5L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzU5NTY0NzkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNQKzluZUNXMjkwQ0VBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1MzgwNTEwNzU5NTY0NzkvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc1OTU2NDc5IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNQKzluZUNXMjkwQ0VBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLzE1MzgwNTEwNzU5NTY0NzkvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc1OTU2NDc5IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDUCs5bmVDVzI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTM4MDUxMDc1OTU2NDc5L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc1OTU2NDc5IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1ArOW5lQ1cyOTBDRUFNPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJyME5Hcmc9PSIsImV0YWciOiJDUCs5bmVDVzI5MENFQU09IiwiY3VzdG9tZXJFbmNyeXB0aW9uIjp7ImVuY3J5cHRpb25BbGdvcml0aG0iOiJBRVMyNTYiLCJrZXlTaGEyNTYiOiJIK0xtblhoUm9lSTZUTVc1YnNWNkh5VWs2cHlHYzJJTWJxWWJBWEJjcHMwPSJ9fQ==" + } + }, + { + "ID": "1b79858ccfded5e8", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "28f1c3700c8886948e9777b86c1da2a1/7366711891699465992;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "277" + ], + "Content-Type": [ + "application/xml; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:36 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:36 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/33,/bns/xh/borg/xh/bns/blobstore2/bitpusher/17.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=BMysW6asNe6mswbty7iIBg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/17.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/17:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpnPufth4dWvXWf0zY7TjZqhN75O9EPTouUOvwS7Q06UHww3586YUbdsiY8VBWkFg3YoB1n7DK1n6Xf6hJ0zAnB_lajBA" + ] + }, + "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+UmVzb3VyY2VJc0VuY3J5cHRlZFdpdGhDdXN0b21lckVuY3J5cHRpb25LZXk8L0NvZGU+PE1lc3NhZ2U+VGhlIHJlc291cmNlIGlzIGVuY3J5cHRlZCB3aXRoIGEgY3VzdG9tZXIgZW5jcnlwdGlvbiBrZXkuPC9NZXNzYWdlPjxEZXRhaWxzPlRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LjwvRGV0YWlscz48L0Vycm9yPg==" + } + }, + { + "ID": "93cabc57ce6ec56f", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "46b21c18c1b22de8bcb7c8e6cad0fed5/8956842325084873895;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Encryption-Key-Sha256": [ + "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Language": [ + "en" + ], + "Content-Length": [ + "11" + ], + "Content-Type": [ + "text/plain; charset=utf-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:36 GMT" + ], + "Etag": [ + "\"-CP+9neCW290CEAM=\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:35 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key-Sha256": [ + "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:35 GMT" + ], + "X-Goog-Generation": [ + "1538051075956479" + ], + "X-Goog-Hash": [ + "crc32c=r0NGrg==", + "md5=xwWNFa0VdXPmlAwrlcAJcg==" + ], + "X-Goog-Metageneration": [ + "3" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "11" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/45,/bns/xh/borg/xh/bns/blobstore2/bitpusher/15.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=BMysW_qrOOShswbYw67IAw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/15.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/15:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Upxs5C49MvrZj6aa9oojSto4f-3W7bgZwh4NhcGuxb2573bjz2bjoHbVnCmMJFeX12t4lCearSUmPPgKbZ5YlE7wCjeOQ" + ] + }, + "Body": "dG9wIHNlY3JldC4=" + } + }, + { + "ID": "61df6bb6e1b0ad73", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d4b09a52787ac8818e2cfd1ddf37a52d/10547254229135313477;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "14271" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:37 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051377000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vno63:4474,/bns/yx/borg/yx/bns/blobstore2/bitpusher/70.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=BcysW6euAYTbzAKpmb-YBw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/70.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/70:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uqs1CpXLAmyRtjb9DQCQZQiZKmFmaJNTEtGuC4e4UDlMkZKcyFOc8R_Tee_amgXHR66SM_zYyIUaHvjAAdLWElZ3F7oyg" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlc291cmNlSXNFbmNyeXB0ZWRXaXRoQ3VzdG9tZXJFbmNyeXB0aW9uS2V5IiwibWVzc2FnZSI6IlRoZSB0YXJnZXQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LiIsImV4dGVuZGVkSGVscCI6Imh0dHBzOi8vY2xvdWQuZ29vZ2xlLmNvbS9zdG9yYWdlL2RvY3MvZW5jcnlwdGlvbiNjdXN0b21lci1zdXBwbGllZF9lbmNyeXB0aW9uX2tleXMiLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVTT1VSQ0VfSVNfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVk6IFRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnJld3JpdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IFRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5QcmVwYXJlUmV3cml0ZU9wZXJhdGlvbi52YWxpZGF0ZVNvdXJjZUVuY3J5cHRpb24oUHJlcGFyZVJld3JpdGVPcGVyYXRpb24uamF2YTo2MTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlByZXBhcmVSZXdyaXRlT3BlcmF0aW9uLnJ1bihQcmVwYXJlUmV3cml0ZU9wZXJhdGlvbi5qYXZhOjM0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24ucmV3cml0ZXIuUmV3cml0ZXIucmV3cml0ZU9iamVjdEludGVybmFsKFJld3JpdGVyLmphdmE6NDA1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzYzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzMzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5yZXdyaXRlSW5Gcm9udGVuZChSZXdyaXRlT2JqZWN0LmphdmE6MzQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjI0MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHQuLi4gMTQgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9SU5WQUxJRF9WQUxVRSwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWTogVGhlIHJlcXVlc3RlZCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IucmV3cml0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogVGhlIHJlcXVlc3RlZCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlByZXBhcmVSZXdyaXRlT3BlcmF0aW9uLnZhbGlkYXRlU291cmNlRW5jcnlwdGlvbihQcmVwYXJlUmV3cml0ZU9wZXJhdGlvbi5qYXZhOjYxMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24ucmV3cml0ZXIuUHJlcGFyZVJld3JpdGVPcGVyYXRpb24ucnVuKFByZXBhcmVSZXdyaXRlT3BlcmF0aW9uLmphdmE6MzQyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0SW50ZXJuYWwoUmV3cml0ZXIuamF2YTo0MDUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozNjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozMzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGVJbkZyb250ZW5kKFJld3JpdGVPYmplY3QuamF2YTozNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MjQwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdC4uLiAxNCBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1odHRwczovL2Nsb3VkLmdvb2dsZS5jb20vc3RvcmFnZS9kb2NzL2VuY3J5cHRpb24jY3VzdG9tZXItc3VwcGxpZWRfZW5jcnlwdGlvbl9rZXlzLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWNsb3VkLmJpZ3N0b3JlLmFwaS5CaWdzdG9yZUVycm9yRG9tYWluLlJFU09VUkNFX0lTX0VOQ1JZUFRFRF9XSVRIX0NVU1RPTUVSX0VOQ1JZUFRJT05fS0VZLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVTT1VSQ0VfSVNfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVk6IFRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnJld3JpdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IFRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5QcmVwYXJlUmV3cml0ZU9wZXJhdGlvbi52YWxpZGF0ZVNvdXJjZUVuY3J5cHRpb24oUHJlcGFyZVJld3JpdGVPcGVyYXRpb24uamF2YTo2MTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlByZXBhcmVSZXdyaXRlT3BlcmF0aW9uLnJ1bihQcmVwYXJlUmV3cml0ZU9wZXJhdGlvbi5qYXZhOjM0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24ucmV3cml0ZXIuUmV3cml0ZXIucmV3cml0ZU9iamVjdEludGVybmFsKFJld3JpdGVyLmphdmE6NDA1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzYzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzMzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5yZXdyaXRlSW5Gcm9udGVuZChSZXdyaXRlT2JqZWN0LmphdmE6MzQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjI0MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHQuLi4gMTQgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1SRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWSwgZXJyb3JQcm90b0RvbWFpbj1jbG91ZC5iaWdzdG9yZS5hcGkuQmlnc3RvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9bnVsbCwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9VGhlIHRhcmdldCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuLCByZWFzb249cmVzb3VyY2VJc0VuY3J5cHRlZFdpdGhDdXN0b21lckVuY3J5cHRpb25LZXksIHJwY0NvZGU9NDAwfSBUaGUgdGFyZ2V0IG9iamVjdCBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS46IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWTogVGhlIHJlcXVlc3RlZCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IucmV3cml0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogVGhlIHJlcXVlc3RlZCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlByZXBhcmVSZXdyaXRlT3BlcmF0aW9uLnZhbGlkYXRlU291cmNlRW5jcnlwdGlvbihQcmVwYXJlUmV3cml0ZU9wZXJhdGlvbi5qYXZhOjYxMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24ucmV3cml0ZXIuUHJlcGFyZVJld3JpdGVPcGVyYXRpb24ucnVuKFByZXBhcmVSZXdyaXRlT3BlcmF0aW9uLmphdmE6MzQyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0SW50ZXJuYWwoUmV3cml0ZXIuamF2YTo0MDUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozNjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozMzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGVJbkZyb250ZW5kKFJld3JpdGVPYmplY3QuamF2YTozNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MjQwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdC4uLiAxNCBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAwLCJtZXNzYWdlIjoiVGhlIHRhcmdldCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuIn19" + } + }, + { + "ID": "ce84af2c6aa2d36d", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "bea423105d717ad175861ccbc2324689/12137665029412712420;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ], + "X-Goog-Copy-Source-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Copy-Source-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Copy-Source-Encryption-Key-Sha256": [ + "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3620" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:38 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051377000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbc184:4336,/bns/yv/borg/yv/bns/blobstore2/bitpusher/20.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=BcysW4-eE8nMgASG3IeoCQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/20.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/20:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Upxx3BvvnZJYIHgJTz9kSp10vjMWjJtn9_uAWAKe5an6Od-3BSGt6Q6RED4-Ibtc3RC0jJPGpi0Tw_Z-wkl16heHnuLAUEsBBV_adZ79hofU-Hx2Kc" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMTEiLCJvYmplY3RTaXplIjoiMTEiLCJkb25lIjp0cnVlLCJyZXNvdXJjZSI6eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA3NzgyNzk4MSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMiIsIm5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NzgyNzk4MSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNy44MjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzcuODI3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM3LjgyN1oiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMj9nZW5lcmF0aW9uPTE1MzgwNTEwNzc4Mjc5ODEmYWx0PW1lZGlhIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA3NzgyNzk4MS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NzgyNzk4MSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0kzYmorR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMi8xNTM4MDUxMDc3ODI3OTgxL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzc4Mjc5ODEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0kzYmorR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMi8xNTM4MDUxMDc3ODI3OTgxL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzc4Mjc5ODEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJM2JqK0dXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA3NzgyNzk4MS91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0yL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzc4Mjc5ODEiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSTNiaitHVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6InIwTkdyZz09IiwiZXRhZyI6IkNJM2JqK0dXMjkwQ0VBRT0ifX0=" + } + }, + { + "ID": "a999df3690b6e237", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption-2", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1705b1e6484692b737affea080b35228/13728076933463086467;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption-2" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Language": [ + "en" + ], + "Content-Length": [ + "11" + ], + "Content-Type": [ + "text/plain; charset=utf-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:38 GMT" + ], + "Etag": [ + "\"c7058d15ad157573e6940c2b95c00972\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:38 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:37 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:37 GMT" + ], + "X-Goog-Generation": [ + "1538051077827981" + ], + "X-Goog-Hash": [ + "crc32c=r0NGrg==", + "md5=xwWNFa0VdXPmlAwrlcAJcg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "11" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/28,/bns/xh/borg/xh/bns/blobstore2/bitpusher/8.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=BsysW8LLA--pswargaYo" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/8.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/8:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq1CdxdvfAVgPz36drluRR3XOAVGxbcXHZLLuNRWrH_TRabeapqxPWBPlHbXA-EGVnBdA358uiErdYzW3U0Wz14YviqaA" + ] + }, + "Body": "dG9wIHNlY3JldC4=" + } + }, + { + "ID": "61481b2562659560", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "c8dad96b48876570d28a024bb8a5820f/15318207366848559649;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Encryption-Key-Sha256": [ + "FnBvfQ1dDsyS8kHD+aB6HHIglDoQ5Im7WYDm3XYTGrQ=" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "14271" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:38 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051377000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrng11:4017,/bns/yr/borg/yr/bns/blobstore2/bitpusher/28.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=BsysW-27CaiWkATJhbDgBQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/28.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/28:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqLzeVXHyiNFMW3buLUpS_VSAbJU_2CwoEyGNKNBA8qGutAt-VmjsPfYO7yYHUxzQBVn4BYg5g-gG5rKWvp_qn1-N_rlQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlc291cmNlSXNFbmNyeXB0ZWRXaXRoQ3VzdG9tZXJFbmNyeXB0aW9uS2V5IiwibWVzc2FnZSI6IlRoZSB0YXJnZXQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LiIsImV4dGVuZGVkSGVscCI6Imh0dHBzOi8vY2xvdWQuZ29vZ2xlLmNvbS9zdG9yYWdlL2RvY3MvZW5jcnlwdGlvbiNjdXN0b21lci1zdXBwbGllZF9lbmNyeXB0aW9uX2tleXMiLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVTT1VSQ0VfSVNfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVk6IFRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnJld3JpdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IFRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5QcmVwYXJlUmV3cml0ZU9wZXJhdGlvbi52YWxpZGF0ZVNvdXJjZUVuY3J5cHRpb24oUHJlcGFyZVJld3JpdGVPcGVyYXRpb24uamF2YTo2MTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlByZXBhcmVSZXdyaXRlT3BlcmF0aW9uLnJ1bihQcmVwYXJlUmV3cml0ZU9wZXJhdGlvbi5qYXZhOjM0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24ucmV3cml0ZXIuUmV3cml0ZXIucmV3cml0ZU9iamVjdEludGVybmFsKFJld3JpdGVyLmphdmE6NDA1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzYzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzMzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5yZXdyaXRlSW5Gcm9udGVuZChSZXdyaXRlT2JqZWN0LmphdmE6MzQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjI0MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHQuLi4gMTQgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9SU5WQUxJRF9WQUxVRSwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWTogVGhlIHJlcXVlc3RlZCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IucmV3cml0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogVGhlIHJlcXVlc3RlZCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlByZXBhcmVSZXdyaXRlT3BlcmF0aW9uLnZhbGlkYXRlU291cmNlRW5jcnlwdGlvbihQcmVwYXJlUmV3cml0ZU9wZXJhdGlvbi5qYXZhOjYxMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24ucmV3cml0ZXIuUHJlcGFyZVJld3JpdGVPcGVyYXRpb24ucnVuKFByZXBhcmVSZXdyaXRlT3BlcmF0aW9uLmphdmE6MzQyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0SW50ZXJuYWwoUmV3cml0ZXIuamF2YTo0MDUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozNjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozMzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGVJbkZyb250ZW5kKFJld3JpdGVPYmplY3QuamF2YTozNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MjQwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdC4uLiAxNCBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1odHRwczovL2Nsb3VkLmdvb2dsZS5jb20vc3RvcmFnZS9kb2NzL2VuY3J5cHRpb24jY3VzdG9tZXItc3VwcGxpZWRfZW5jcnlwdGlvbl9rZXlzLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWNsb3VkLmJpZ3N0b3JlLmFwaS5CaWdzdG9yZUVycm9yRG9tYWluLlJFU09VUkNFX0lTX0VOQ1JZUFRFRF9XSVRIX0NVU1RPTUVSX0VOQ1JZUFRJT05fS0VZLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVTT1VSQ0VfSVNfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVk6IFRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnJld3JpdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IFRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5QcmVwYXJlUmV3cml0ZU9wZXJhdGlvbi52YWxpZGF0ZVNvdXJjZUVuY3J5cHRpb24oUHJlcGFyZVJld3JpdGVPcGVyYXRpb24uamF2YTo2MTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlByZXBhcmVSZXdyaXRlT3BlcmF0aW9uLnJ1bihQcmVwYXJlUmV3cml0ZU9wZXJhdGlvbi5qYXZhOjM0Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24ucmV3cml0ZXIuUmV3cml0ZXIucmV3cml0ZU9iamVjdEludGVybmFsKFJld3JpdGVyLmphdmE6NDA1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzYzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzMzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5yZXdyaXRlSW5Gcm9udGVuZChSZXdyaXRlT2JqZWN0LmphdmE6MzQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjI0MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHQuLi4gMTQgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1SRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWSwgZXJyb3JQcm90b0RvbWFpbj1jbG91ZC5iaWdzdG9yZS5hcGkuQmlnc3RvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9bnVsbCwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9VGhlIHRhcmdldCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuLCByZWFzb249cmVzb3VyY2VJc0VuY3J5cHRlZFdpdGhDdXN0b21lckVuY3J5cHRpb25LZXksIHJwY0NvZGU9NDAwfSBUaGUgdGFyZ2V0IG9iamVjdCBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS46IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWTogVGhlIHJlcXVlc3RlZCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IucmV3cml0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogVGhlIHJlcXVlc3RlZCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlByZXBhcmVSZXdyaXRlT3BlcmF0aW9uLnZhbGlkYXRlU291cmNlRW5jcnlwdGlvbihQcmVwYXJlUmV3cml0ZU9wZXJhdGlvbi5qYXZhOjYxMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24ucmV3cml0ZXIuUHJlcGFyZVJld3JpdGVPcGVyYXRpb24ucnVuKFByZXBhcmVSZXdyaXRlT3BlcmF0aW9uLmphdmE6MzQyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0SW50ZXJuYWwoUmV3cml0ZXIuamF2YTo0MDUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozNjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozMzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGVJbkZyb250ZW5kKFJld3JpdGVPYmplY3QuamF2YTozNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MjQwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdC4uLiAxNCBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAwLCJtZXNzYWdlIjoiVGhlIHRhcmdldCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuIn19" + } + }, + { + "ID": "b6ec99f6d81fabb4", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "902f8072774afaa43e582fad4756347f/16908619266604032192;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ], + "X-Goog-Copy-Source-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Copy-Source-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Copy-Source-Encryption-Key-Sha256": [ + "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Encryption-Key-Sha256": [ + "FnBvfQ1dDsyS8kHD+aB6HHIglDoQ5Im7WYDm3XYTGrQ=" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3733" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:38 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051377000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vngu25:4297,/bns/yx/borg/yx/bns/blobstore2/bitpusher/103.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=BsysW9atE8-SzAKwt734Bg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/103.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/103:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqAvNR3Fv4vliLe4057vGGJi3tYRwNVOtnOpX_n2kGwJVcvjq5HUkZ3ILlNbaiotOJX5pekim3kpy0YBBvTw1is7X9k1A" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMTEiLCJvYmplY3RTaXplIjoiMTEiLCJkb25lIjp0cnVlLCJyZXNvdXJjZSI6eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA3ODgyODE1MyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMiIsIm5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3ODgyODE1MyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozOC44MjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzguODI3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM4LjgyN1oiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMj9nZW5lcmF0aW9uPTE1MzgwNTEwNzg4MjgxNTMmYWx0PW1lZGlhIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA3ODgyODE1My9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3ODgyODE1MyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1BuZ3pPR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMi8xNTM4MDUxMDc4ODI4MTUzL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzg4MjgxNTMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1BuZ3pPR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMi8xNTM4MDUxMDc4ODI4MTUzL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzg4MjgxNTMiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQbmd6T0dXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA3ODgyODE1My91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0yL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzg4MjgxNTMiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUG5nek9HVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6InIwTkdyZz09IiwiZXRhZyI6IkNQbmd6T0dXMjkwQ0VBRT0iLCJjdXN0b21lckVuY3J5cHRpb24iOnsiZW5jcnlwdGlvbkFsZ29yaXRobSI6IkFFUzI1NiIsImtleVNoYTI1NiI6IkZuQnZmUTFkRHN5UzhrSEQrYUI2SEhJZ2xEb1E1SW03V1lEbTNYWVRHclE9In19fQ==" + } + }, + { + "ID": "af6300f23cc6c27c", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption-2", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "34eb30af8a5d023668ef3bfebecd46df/52568571938342239;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption-2" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "277" + ], + "Content-Type": [ + "application/xml; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:38 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:38 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/0,/bns/xh/borg/xh/bns/blobstore2/bitpusher/28.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=BsysW7-yOYuhswbl1qKYBg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/28.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/28:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrjoQiF7Wn9tm0yro8yG5Q_IlGNtcRWwGXNmf76WCfoPNtEjykhr4I2C2Z7IMJu69JC7Ug7VKK_eCSeLk-GpliSCYK52Q" + ] + }, + "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+UmVzb3VyY2VJc0VuY3J5cHRlZFdpdGhDdXN0b21lckVuY3J5cHRpb25LZXk8L0NvZGU+PE1lc3NhZ2U+VGhlIHJlc291cmNlIGlzIGVuY3J5cHRlZCB3aXRoIGEgY3VzdG9tZXIgZW5jcnlwdGlvbiBrZXkuPC9NZXNzYWdlPjxEZXRhaWxzPlRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LjwvRGV0YWlscz48L0Vycm9yPg==" + } + }, + { + "ID": "13b7d249a22c3226", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption-2", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "6ec04258e9f0bf885bd0d408ba9d4a85/1642697905812188157;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption-2" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Encryption-Key-Sha256": [ + "FnBvfQ1dDsyS8kHD+aB6HHIglDoQ5Im7WYDm3XYTGrQ=" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Language": [ + "en" + ], + "Content-Length": [ + "11" + ], + "Content-Type": [ + "text/plain; charset=utf-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:39 GMT" + ], + "Etag": [ + "\"-CPngzOGW290CEAE=\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:38 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key-Sha256": [ + "FnBvfQ1dDsyS8kHD+aB6HHIglDoQ5Im7WYDm3XYTGrQ=" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:38 GMT" + ], + "X-Goog-Generation": [ + "1538051078828153" + ], + "X-Goog-Hash": [ + "crc32c=r0NGrg==", + "md5=xwWNFa0VdXPmlAwrlcAJcg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "11" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/12,/bns/xh/borg/xh/bns/blobstore2/bitpusher/52.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=B8ysW6cIsKqzBr6kg8AP" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/52.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/52:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uogb9TrmaLESy0ok976HRo5Lcn2MEURdtotgODsMtPI9-W2lNDP6Xu951WGKM8lOEapQi_54VQ9XaY6faPuZz8_AUyXlw" + ] + }, + "Body": "dG9wIHNlY3JldC4=" + } + }, + { + "ID": "3f85e3abeccd12ee", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "790fd5e30e72862f5207a85bf97442a8/3233109805584437404;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ], + "X-Goog-Copy-Source-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Copy-Source-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Copy-Source-Encryption-Key-Sha256": [ + "FnBvfQ1dDsyS8kHD+aB6HHIglDoQ5Im7WYDm3XYTGrQ=" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Encryption-Key-Sha256": [ + "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3733" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:39 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051377000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrno9:4295,/bns/yv/borg/yv/bns/blobstore2/bitpusher/88.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=B8ysW5XXB8KZgQTw9ZIQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/88.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/88:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrXkelifrzmM_ZibiAKC7mLpFqUeNomFI8UJ8PFAqN8RD84AJ-A1I8E6RE4RzsKdJC9Gi5dMDbBKV8rVm5YLLWXXo1Caw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMTEiLCJvYmplY3RTaXplIjoiMTEiLCJkb25lIjp0cnVlLCJyZXNvdXJjZSI6eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA3OTUxNTI1MyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMiIsIm5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3OTUxNTI1MyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozOS41MTVaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzkuNTE1WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM5LjUxNVoiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMj9nZW5lcmF0aW9uPTE1MzgwNTEwNzk1MTUyNTMmYWx0PW1lZGlhIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA3OTUxNTI1My9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3OTUxNTI1MyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1BYWTl1R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMi8xNTM4MDUxMDc5NTE1MjUzL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzk1MTUyNTMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1BYWTl1R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMi8xNTM4MDUxMDc5NTE1MjUzL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzk1MTUyNTMiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQWFk5dUdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA3OTUxNTI1My91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0yL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzk1MTUyNTMiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUFhZOXVHVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6InIwTkdyZz09IiwiZXRhZyI6IkNQWFk5dUdXMjkwQ0VBRT0iLCJjdXN0b21lckVuY3J5cHRpb24iOnsiZW5jcnlwdGlvbkFsZ29yaXRobSI6IkFFUzI1NiIsImtleVNoYTI1NiI6IkgrTG1uWGhSb2VJNlRNVzVic1Y2SHlVazZweUdjMklNYnFZYkFYQmNwczA9In19fQ==" + } + }, + { + "ID": "082a7091d1ed2007", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-3/compose?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "160" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "32ccef1e750b13cb8ebb9b1411568f72/4823521709634876986;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-3/compose?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24ifSx7Im5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIifV19Cg==" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "13226" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:39 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051377000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrmi1:4383,/bns/yw/borg/yw/bns/blobstore2/bitpusher/2.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=B8ysW9fRJpbRhASP5ryIBw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/2.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/2:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqnSH1S0DzV-Tzbn9uZFehFnzCR3q7Tu5p04nCaneV0wfauN_YQTYLZCyLntmuHEkFeYFM1lLgwVSKjBYfRf7ED95Goug" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlc291cmNlSXNFbmNyeXB0ZWRXaXRoQ3VzdG9tZXJFbmNyeXB0aW9uS2V5IiwibWVzc2FnZSI6IlRoZSB0YXJnZXQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LiIsImV4dGVuZGVkSGVscCI6Imh0dHBzOi8vY2xvdWQuZ29vZ2xlLmNvbS9zdG9yYWdlL2RvY3MvZW5jcnlwdGlvbiNjdXN0b21lci1zdXBwbGllZF9lbmNyeXB0aW9uX2tleXMiLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVTT1VSQ0VfSVNfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVk6IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uKSBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuY29tcG9zZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ29tcG9uZW50IG9iamVjdCAoZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24pIGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1JTlZBTElEX1ZBTFVFLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlJFU09VUkNFX0lTX0VOQ1JZUFRFRF9XSVRIX0NVU1RPTUVSX0VOQ1JZUFRJT05fS0VZOiBDb21wb25lbnQgb2JqZWN0IChnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbikgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YToxOTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6NDUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmNvbXBvc2UoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uKSBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9aHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3N0b3JhZ2UvZG9jcy9lbmNyeXB0aW9uI2N1c3RvbWVyLXN1cHBsaWVkX2VuY3J5cHRpb25fa2V5cywgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1jbG91ZC5iaWdzdG9yZS5hcGkuQmlnc3RvcmVFcnJvckRvbWFpbi5SRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWSwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlJFU09VUkNFX0lTX0VOQ1JZUFRFRF9XSVRIX0NVU1RPTUVSX0VOQ1JZUFRJT05fS0VZOiBDb21wb25lbnQgb2JqZWN0IChnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbikgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YToxOTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6NDUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmNvbXBvc2UoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uKSBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1SRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWSwgZXJyb3JQcm90b0RvbWFpbj1jbG91ZC5iaWdzdG9yZS5hcGkuQmlnc3RvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9Q29tcG9uZW50IG9iamVjdCAoZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24pIGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9VGhlIHRhcmdldCBvYmplY3QgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuLCByZWFzb249cmVzb3VyY2VJc0VuY3J5cHRlZFdpdGhDdXN0b21lckVuY3J5cHRpb25LZXksIHJwY0NvZGU9NDAwfSBUaGUgdGFyZ2V0IG9iamVjdCBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS46IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9JU19FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWTogQ29tcG9uZW50IG9iamVjdCAoZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24pIGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6MTk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjQ1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDb21wb25lbnQgb2JqZWN0IChnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbikgaXMgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJUaGUgdGFyZ2V0IG9iamVjdCBpcyBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS4ifX0=" + } + }, + { + "ID": "f38450f7b6994359", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-3/compose?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "160" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d80e51262f252122efbaf143063fec84/7172970583123226152;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-3/compose?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Encryption-Key-Sha256": [ + "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" + ] + }, + "Body": "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24ifSx7Im5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIifV19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "911" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:40 GMT" + ], + "Etag": [ + "CPPmruKW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051377000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlb12:4251,/bns/yv/borg/yv/bns/blobstore2/bitpusher/43.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=B8ysW4izOIOegwTq3L2ADw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/43.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/43:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrylLVTdrDh4f0Vfz7f7uc-9JeMykJ4U6tLGFt1hxOEFQDcYOlrv4zBfNQWHFKEOybb0y9327li2CcTac2VQbWW2VVKsg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTMvMTUzODA1MTA4MDQzNDU0NyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMyIsIm5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MDQzNDU0NyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0MC40MzRaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDAuNDM0WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQwLjQzNFoiLCJzaXplIjoiMjIiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0zP2dlbmVyYXRpb249MTUzODA1MTA4MDQzNDU0NyZhbHQ9bWVkaWEiLCJjcmMzMmMiOiI1ajF5cGc9PSIsImNvbXBvbmVudENvdW50IjoyLCJldGFnIjoiQ1BQbXJ1S1cyOTBDRUFFPSIsImN1c3RvbWVyRW5jcnlwdGlvbiI6eyJlbmNyeXB0aW9uQWxnb3JpdGhtIjoiQUVTMjU2Iiwia2V5U2hhMjU2IjoiSCtMbW5YaFJvZUk2VE1XNWJzVjZIeVVrNnB5R2MySU1icVliQVhCY3BzMD0ifX0=" + } + }, + { + "ID": "9e7050ed002cb668", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption-3", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "73a2be99b8acfc1dee817e64a6745ea9/8763382482895475655;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption-3" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "277" + ], + "Content-Type": [ + "application/xml; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:40 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:40 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/47,/bns/xh/borg/xh/bns/blobstore2/bitpusher/60.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=CMysW4i9IsWhswa5mIuQAg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/60.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/60:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrCCK9bVrOWH7ud3eW9W3iMCeh8Qx_fEx62BWAY7Dz4jTrVQJP8pMyvE9WqwAMVLcsnZ4V2KTogN111cHGLj6rHRWoWLg" + ] + }, + "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+UmVzb3VyY2VJc0VuY3J5cHRlZFdpdGhDdXN0b21lckVuY3J5cHRpb25LZXk8L0NvZGU+PE1lc3NhZ2U+VGhlIHJlc291cmNlIGlzIGVuY3J5cHRlZCB3aXRoIGEgY3VzdG9tZXIgZW5jcnlwdGlvbiBrZXkuPC9NZXNzYWdlPjxEZXRhaWxzPlRoZSByZXF1ZXN0ZWQgb2JqZWN0IGlzIGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LjwvRGV0YWlscz48L0Vycm9yPg==" + } + }, + { + "ID": "0fbb222f2534ff7a", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption-3", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "6331c1e1f7b03eb25a98f3fc46f36369/10353511816769255782;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/customer-encryption-3" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Encryption-Key-Sha256": [ + "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "22" + ], + "Content-Type": [ + "application/octet-stream" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:40 GMT" + ], + "Etag": [ + "\"-CPPmruKW290CEAE=\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:40 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Component-Count": [ + "2" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key-Sha256": [ + "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:24:40 GMT" + ], + "X-Goog-Generation": [ + "1538051080434547" + ], + "X-Goog-Hash": [ + "crc32c=5j1ypg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "22" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/34,/bns/xh/borg/xh/bns/blobstore2/bitpusher/86.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=CMysW-ycJe6oswaP1oK4DA" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/86.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/86:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpuCcU3sd6d5b3_CAmlabI6q2Y6u8mNw58JWRfKayJ4R6dbktGbpQ-hZyXbWI9zCfwEr-ZA_-azw7Q8-WtMuO2xAI-8uA" + ] + }, + "Body": "dG9wIHNlY3JldC50b3Agc2VjcmV0Lg==" + } + }, + { + "ID": "2674faa2be795765", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "96c928b3b824c63fe7484440c436c936/11943923720836472324;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ], + "X-Goog-Copy-Source-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Copy-Source-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Copy-Source-Encryption-Key-Sha256": [ + "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3620" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:41 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051377000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrae1:4130,/bns/yr/borg/yr/bns/blobstore2/bitpusher/72.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=CMysW4b8LM3ikAO8k6i4Cg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/72.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/72:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqiHnplkYoA54YhU9ArFoa4wXcCr0oXVB1HTdzE_nCqLyPj3048fN0-OX3_eM3xHOmxELgRjw88jTxkXPQW6kTqXoaZBA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMTEiLCJvYmplY3RTaXplIjoiMTEiLCJkb25lIjp0cnVlLCJyZXNvdXJjZSI6eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA4MTIxNTYwNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMiIsIm5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MTIxNTYwNyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0MS4yMTRaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDEuMjE0WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQxLjIxNFoiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoieHdXTkZhMFZkWFBtbEF3cmxjQUpjZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMj9nZW5lcmF0aW9uPTE1MzgwNTEwODEyMTU2MDcmYWx0PW1lZGlhIiwiY29udGVudExhbmd1YWdlIjoiZW4iLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA4MTIxNTYwNy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uLTIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MTIxNTYwNyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1BlODN1S1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMi8xNTM4MDUxMDgxMjE1NjA3L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODEyMTU2MDciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1BlODN1S1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMi8xNTM4MDUxMDgxMjE1NjA3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODEyMTU2MDciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQZTgzdUtXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA4MTIxNTYwNy91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0yL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODEyMTU2MDciLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUGU4M3VLVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6InIwTkdyZz09IiwiZXRhZyI6IkNQZTgzdUtXMjkwQ0VBRT0ifX0=" + } + }, + { + "ID": "a69acbcb815e9a98", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-3/compose?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "129" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "a7cd921f95aff6168c1cdf2558bbb8c2/13534335624886846627;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-3/compose?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Encryption-Key-Sha256": [ + "H+LmnXhRoeI6TMW5bsV6HyUk6pyGc2IMbqYbAXBcps0=" + ] + }, + "Body": "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiJ9XX0K" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "13336" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:41 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051377000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vns194:4293,/bns/yx/borg/yx/bns/blobstore2/bitpusher/80.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=CcysW6u5FYTBzAKH6JOIAg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/80.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/80:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWUs4TEVnZzc0SE1jc2k2MENjN2doVUNwYXhuZlplOGJXWW1xSDdtR3h4UFFoVFo0OHVKNE9hSzBMbmltRms1bTFKRGNYOS1VS2FNNzlNaDNKNnRzb0JmVGt2MkxxTEJtM1RXMVJ2RGFiQTV6VlV1VHJUR2xMMTZlVjRNWG5oZGxDbEZMQmZtcWNvZU9CVzlDNkUwemVWVDUtTXFsU29OTUtsaG5iOGdlanREQW55QkZNWUVTb3pIa1kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrsewdwW9EJ0NcTaSD_uyyIskMhpsLlaImKZ_i0_-K6dCZQMXFB0P-8yHmIIOwuyNOq33P9ahzJ6_YlsOilZA0aRMlLDA" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlc291cmNlTm90RW5jcnlwdGVkV2l0aEN1c3RvbWVyRW5jcnlwdGlvbktleSIsIm1lc3NhZ2UiOiJUaGUgdGFyZ2V0IG9iamVjdCBpcyBub3QgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuIiwiZXh0ZW5kZWRIZWxwIjoiaHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL3N0b3JhZ2UvZG9jcy9lbmNyeXB0aW9uI2N1c3RvbWVyLXN1cHBsaWVkX2VuY3J5cHRpb25fa2V5cyIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9OT1RfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVk6IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIpIHVzIG5vdCBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuY29tcG9zZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ29tcG9uZW50IG9iamVjdCAoZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMikgdXMgbm90IGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1JTlZBTElEX1ZBTFVFLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlJFU09VUkNFX05PVF9FTkNSWVBURURfV0lUSF9DVVNUT01FUl9FTkNSWVBUSU9OX0tFWTogQ29tcG9uZW50IG9iamVjdCAoZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMikgdXMgbm90IGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6MTk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjQ1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDb21wb25lbnQgb2JqZWN0IChnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yKSB1cyBub3QgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPWh0dHBzOi8vY2xvdWQuZ29vZ2xlLmNvbS9zdG9yYWdlL2RvY3MvZW5jcnlwdGlvbiNjdXN0b21lci1zdXBwbGllZF9lbmNyeXB0aW9uX2tleXMsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWJhZFJlcXVlc3QsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4uUkVTT1VSQ0VfTk9UX0VOQ1JZUFRFRF9XSVRIX0NVU1RPTUVSX0VOQ1JZUFRJT05fS0VZLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVTT1VSQ0VfTk9UX0VOQ1JZUFRFRF9XSVRIX0NVU1RPTUVSX0VOQ1JZUFRJT05fS0VZOiBDb21wb25lbnQgb2JqZWN0IChnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yKSB1cyBub3QgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YToxOTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6NDUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmNvbXBvc2UoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIpIHVzIG5vdCBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1SRVNPVVJDRV9OT1RfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVksIGVycm9yUHJvdG9Eb21haW49Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkuZW5jcnlwdGlvbktleSwgbWVzc2FnZT1Db21wb25lbnQgb2JqZWN0IChnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yKSB1cyBub3QgZW5jcnlwdGVkIGJ5IGEgY3VzdG9tZXItc3VwcGxpZWQgZW5jcnlwdGlvbiBrZXkuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LmVuY3J5cHRpb25LZXksIG1lc3NhZ2U9VGhlIHRhcmdldCBvYmplY3QgaXMgbm90IGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LiwgcmVhc29uPXJlc291cmNlTm90RW5jcnlwdGVkV2l0aEN1c3RvbWVyRW5jcnlwdGlvbktleSwgcnBjQ29kZT00MDB9IFRoZSB0YXJnZXQgb2JqZWN0IGlzIG5vdCBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS46IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVNPVVJDRV9OT1RfRU5DUllQVEVEX1dJVEhfQ1VTVE9NRVJfRU5DUllQVElPTl9LRVk6IENvbXBvbmVudCBvYmplY3QgKGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIpIHVzIG5vdCBlbmNyeXB0ZWQgYnkgYSBjdXN0b21lci1zdXBwbGllZCBlbmNyeXB0aW9uIGtleS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuY29tcG9zZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ29tcG9uZW50IG9iamVjdCAoZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMikgdXMgbm90IGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAwLCJtZXNzYWdlIjoiVGhlIHRhcmdldCBvYmplY3QgaXMgbm90IGVuY3J5cHRlZCBieSBhIGN1c3RvbWVyLXN1cHBsaWVkIGVuY3J5cHRpb24ga2V5LiJ9fQ==" + } + }, + { + "ID": "6f9c244b2d250c5e", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "31eada18413479da75d3925cc7108f96/15124747524659095874;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2492" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:42 GMT" + ], + "Etag": [ + "CAk=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:42 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051381000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vngu25:4297,/bns/yx/borg/yx/bns/blobstore2/bitpusher/156.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=CcysW4nWKs6EzALbtZ-gDg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/156.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/156:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnBxTXlCbWNNWUVoeVpDak45TUl5alRkV2U4Tkd3bWM0RktJRUk1NGNIWmhyVTNrbmhKU0pwc1FISTJCQkVVSUdaV29YZ3FhajlBV2hIMEF2TVlYN3V6YVdPRkxfR0hTNnJrcEFrRFZRMzBUdF9uUWFEb1QybXVGRkxYRXBNdnYxOExuX2R1aFZnVnRkdHJlWm9hN21jU3JnMXEtejlocnV2SGxiTzFYbzVvTDRoRUExd3BFOFZ6R1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrZI72BrP6aXYwfG9Rnz_oveTk2w4RM4JsRUBErv5nhrD_CbfL-4BN_PU1l3IXj320SM9dp9j7Po-u9bTOr19l7NVQAQA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjM6NTIuMzU1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjI5LjE0NVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjkiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBaz0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQWs9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBaz0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBaz0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FrPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FrPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInZlcnNpb25pbmciOnsiZW5hYmxlZCI6ZmFsc2V9LCJsaWZlY3ljbGUiOnsicnVsZSI6W3siYWN0aW9uIjp7InR5cGUiOiJEZWxldGUifSwiY29uZGl0aW9uIjp7ImFnZSI6MzB9fV19LCJsYWJlbHMiOnsibmV3IjoibmV3IiwibDEiOiJ2MiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQWs9In0=" + } + }, + { + "ID": "9133d063a35c30e5", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=a11b044a99f2443cf5038003dedb8e668d7fe177eab13c4a0b90234adb2e" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1a85ca3ba39da04007da15869a2499c0/15883784494080294033;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS1hMTFiMDQ0YTk5ZjI0NDNjZjUwMzgwMDNkZWRiOGU2NjhkN2ZlMTc3ZWFiMTNjNGEwYjkwMjM0YWRiMmUNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm5hbWUiOiJwb3NjIn0KDQotLWExMWIwNDRhOTlmMjQ0M2NmNTAzODAwM2RlZGI4ZTY2OGQ3ZmUxNzdlYWIxM2M0YTBiOTAyMzRhZGIyZQ0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04DQoNCmZvbw0KLS1hMTFiMDQ0YTk5ZjI0NDNjZjUwMzgwMDNkZWRiOGU2NjhkN2ZlMTc3ZWFiMTNjNGEwYjkwMjM0YWRiMmUtLQ0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3221" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:42 GMT" + ], + "Etag": [ + "CPf3qOOW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051382000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrkm9:4009,/bns/yw/borg/yw/bns/blobstore2/bitpusher/139.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=CsysW5GnB9LfhAT69p74BQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/139.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/139:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYnBxTXlCbWNNWUVoeVpDak45TUl5alRkV2U4Tkd3bWM0RktJRUk1NGNIWmhyVTNrbmhKU0pwc1FISTJCQkVVSUdaV29YZ3FhajlBV2hIMEF2TVlYN3V6YVdPRkxfR0hTNnJrcEFrRFZRMzBUdF9uUWFEb1QybXVGRkxYRXBNdnYxOExuX2R1aFZnVnRkdHJlWm9hN21jU3JnMXEtejlocnV2SGxiTzFYbzVvTDRoRUExd3BFOFZ6R1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrjPZMs7lUyqu-BOU0UoEmJXSWt1nW1nznNnZyqbG7_XTwii-4DpkHyIRbgkfrZjwIom3uj1F31_r8i18UBQxWL7scHxg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wb3NjLzE1MzgwNTEwODI0MzU1NzUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9wb3NjIiwibmFtZSI6InBvc2MiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MjQzNTU3NSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0Mi40MzVaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDIuNDM1WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQyLjQzNVoiLCJzaXplIjoiMyIsIm1kNUhhc2giOiJyTDBZMjB6QytGenQ3MlZQek1TazJBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYz9nZW5lcmF0aW9uPTE1MzgwNTEwODI0MzU1NzUmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcG9zYy8xNTM4MDUxMDgyNDM1NTc1L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJwb3NjIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODI0MzU1NzUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNQZjNxT09XMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wb3NjLzE1MzgwNTEwODI0MzU1NzUvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYy9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoicG9zYyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDgyNDM1NTc1IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNQZjNxT09XMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wb3NjLzE1MzgwNTEwODI0MzU1NzUvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoicG9zYyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDgyNDM1NTc1IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDUGYzcU9PVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcG9zYy8xNTM4MDUxMDgyNDM1NTc1L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9wb3NjL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoicG9zYyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDgyNDM1NTc1IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1BmM3FPT1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJ6OFN1SFE9PSIsImV0YWciOiJDUGYzcU9PVzI5MENFQUU9In0=" + } + }, + { + "ID": "793ce49241ead072", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/posc?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "737703d157645287eed0cf2d581c1afe/17474195298652594480;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/posc?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3221" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:42 GMT" + ], + "Etag": [ + "CPf3qOOW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051382000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrmk10:4329,/bns/yr/borg/yr/bns/blobstore2/bitpusher/22.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=CsysW6T5KYfwkAOekpvQCA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/22.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/22:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYnBxTXlCbWNNWUVoeVpDak45TUl5alRkV2U4Tkd3bWM0RktJRUk1NGNIWmhyVTNrbmhKU0pwc1FISTJCQkVVSUdaV29YZ3FhajlBV2hIMEF2TVlYN3V6YVdPRkxfR0hTNnJrcEFrRFZRMzBUdF9uUWFEb1QybXVGRkxYRXBNdnYxOExuX2R1aFZnVnRkdHJlWm9hN21jU3JnMXEtejlocnV2SGxiTzFYbzVvTDRoRUExd3BFOFZ6R1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Upl0M0TYF99JpqqHFMfFDcvOI3Kyy2zWEV_5XuTlzdzzvhSphgs--na7KgwhJnlBmAbPwkJ-kQjZ_S2KSNY1WeGO3jt8w" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wb3NjLzE1MzgwNTEwODI0MzU1NzUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9wb3NjIiwibmFtZSI6InBvc2MiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MjQzNTU3NSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0Mi40MzVaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDIuNDM1WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQyLjQzNVoiLCJzaXplIjoiMyIsIm1kNUhhc2giOiJyTDBZMjB6QytGenQ3MlZQek1TazJBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYz9nZW5lcmF0aW9uPTE1MzgwNTEwODI0MzU1NzUmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcG9zYy8xNTM4MDUxMDgyNDM1NTc1L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJwb3NjIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODI0MzU1NzUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNQZjNxT09XMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wb3NjLzE1MzgwNTEwODI0MzU1NzUvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYy9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoicG9zYyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDgyNDM1NTc1IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNQZjNxT09XMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wb3NjLzE1MzgwNTEwODI0MzU1NzUvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoicG9zYyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDgyNDM1NTc1IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDUGYzcU9PVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcG9zYy8xNTM4MDUxMDgyNDM1NTc1L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9wb3NjL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoicG9zYyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDgyNDM1NTc1IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1BmM3FPT1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJ6OFN1SFE9PSIsImV0YWciOiJDUGYzcU9PVzI5MENFQUU9In0=" + } + }, + { + "ID": "7c3235e94e5f1d49", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/posc/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/posc?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "34" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "045d3b6b50ecd5f20e668145d7067f65/617863128993548238;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/posc/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/posc?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJzdG9yYWdlQ2xhc3MiOiJNVUxUSV9SRUdJT05BTCJ9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3286" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:43 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051382000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrip90:4121,/bns/yr/borg/yr/bns/blobstore2/bitpusher/62.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=CsysW_zAL9Ge4QSorrjYCg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/62.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/62:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRYnBxTXlCbWNNWUVoeVpDak45TUl5alRkV2U4Tkd3bWM0RktJRUk1NGNIWmhyVTNrbmhKU0pwc1FISTJCQkVVSUdaV29YZ3FhajlBV2hIMEF2TVlYN3V6YVdPRkxfR0hTNnJrcEFrRFZRMzBUdF9uUWFEb1QybXVGRkxYRXBNdnYxOExuX2R1aFZnVnRkdHJlWm9hN21jU3JnMXEtejlocnV2SGxiTzFYbzVvTDRoRUExd3BFOFZ6R1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpBrEawAqmOFoyRSCwYrTqRiIMbZKnMzvTDTGGVXxV4EvhLJB06Pf06EFZdrIULrUqftTRnOu7rKWfe6FocLDponokX4A" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiMyIsIm9iamVjdFNpemUiOiIzIiwiZG9uZSI6dHJ1ZSwicmVzb3VyY2UiOnsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcG9zYy8xNTM4MDUxMDgzMjI3NTQ3Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYyIsIm5hbWUiOiJwb3NjIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODMyMjc1NDciLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDMuMjI1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQzLjIyNVoiLCJzdG9yYWdlQ2xhc3MiOiJNVUxUSV9SRUdJT05BTCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0My4yMjVaIiwic2l6ZSI6IjMiLCJtZDVIYXNoIjoickwwWTIwekMrRnp0NzJWUHpNU2syQT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3Bvc2M/Z2VuZXJhdGlvbj0xNTM4MDUxMDgzMjI3NTQ3JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3Bvc2MvMTUzODA1MTA4MzIyNzU0Ny9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3Bvc2MvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoicG9zYyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDgzMjI3NTQ3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSnVqMmVPVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcG9zYy8xNTM4MDUxMDgzMjI3NTQ3L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3Bvc2MvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MzIyNzU0NyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSnVqMmVPVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcG9zYy8xNTM4MDUxMDgzMjI3NTQ3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3Bvc2MvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MzIyNzU0NyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0p1ajJlT1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3Bvc2MvMTUzODA1MTA4MzIyNzU0Ny91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYy9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MzIyNzU0NyIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNKdWoyZU9XMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiejhTdUhRPT0iLCJldGFnIjoiQ0p1ajJlT1cyOTBDRUFFPSJ9fQ==" + } + }, + { + "ID": "7f37efaaa4a10ba0", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=f7d76450fb503dd31762a093ee2938e9271649529336ad7573571e65208b" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "5c75bb9317f75305458ad9b585bd658c/1377181569096423966;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS1mN2Q3NjQ1MGZiNTAzZGQzMTc2MmEwOTNlZTI5MzhlOTI3MTY0OTUyOTMzNmFkNzU3MzU3MWU2NTIwOGINCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm5hbWUiOiJwb3NjMiIsInN0b3JhZ2VDbGFzcyI6Ik1VTFRJX1JFR0lPTkFMIn0KDQotLWY3ZDc2NDUwZmI1MDNkZDMxNzYyYTA5M2VlMjkzOGU5MjcxNjQ5NTI5MzM2YWQ3NTczNTcxZTY1MjA4Yg0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04DQoNCnh4eA0KLS1mN2Q3NjQ1MGZiNTAzZGQzMTc2MmEwOTNlZTI5MzhlOTI3MTY0OTUyOTMzNmFkNzU3MzU3MWU2NTIwOGItLQ0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3243" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:43 GMT" + ], + "Etag": [ + "CMvl9+OW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051382000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrl7:4233,/bns/yv/borg/yv/bns/blobstore2/bitpusher/286.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=C8ysW9TdFsnNgASH64bQDA" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/286.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/286:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYnBxTXlCbWNNWUVoeVpDak45TUl5alRkV2U4Tkd3bWM0RktJRUk1NGNIWmhyVTNrbmhKU0pwc1FISTJCQkVVSUdaV29YZ3FhajlBV2hIMEF2TVlYN3V6YVdPRkxfR0hTNnJrcEFrRFZRMzBUdF9uUWFEb1QybXVGRkxYRXBNdnYxOExuX2R1aFZnVnRkdHJlWm9hN21jU3JnMXEtejlocnV2SGxiTzFYbzVvTDRoRUExd3BFOFZ6R1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqQ8mwwlOeS-eMuzlQ-XHX2qnrG-A6DWwm5QKOhddYR2imhlwNxhnpDPJ6_5YhcFF03hm8mYxhq6GM87N4FasQmXuiPiA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wb3NjMi8xNTM4MDUxMDgzNzI3NTYzIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYzIiLCJuYW1lIjoicG9zYzIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MzcyNzU2MyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0My43MjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDMuNzI3WiIsInN0b3JhZ2VDbGFzcyI6Ik1VTFRJX1JFR0lPTkFMIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQzLjcyN1oiLCJzaXplIjoiMyIsIm1kNUhhc2giOiI5V0dxOXU4TDhVMUNDTHRHcE15enJRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYzI/Z2VuZXJhdGlvbj0xNTM4MDUxMDgzNzI3NTYzJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3Bvc2MyLzE1MzgwNTEwODM3Mjc1NjMvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9wb3NjMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJwb3NjMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDgzNzI3NTYzIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTXZsOStPVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcG9zYzIvMTUzODA1MTA4MzcyNzU2My9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9wb3NjMi9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoicG9zYzIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MzcyNzU2MyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTXZsOStPVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcG9zYzIvMTUzODA1MTA4MzcyNzU2My9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9wb3NjMi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoicG9zYzIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MzcyNzU2MyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ012bDkrT1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3Bvc2MyLzE1MzgwNTEwODM3Mjc1NjMvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3Bvc2MyL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoicG9zYzIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MzcyNzU2MyIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNNdmw5K09XMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiMTdxQUJRPT0iLCJldGFnIjoiQ012bDkrT1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "b7982318c88f63e2", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=aa69c137381c6410b1a82a7f891a07638054c96a3999bbab84aa50e35e5e" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "5aefb8960730d3277415ebd22c08f057/2208275033060699245;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS1hYTY5YzEzNzM4MWM2NDEwYjFhODJhN2Y4OTFhMDc2MzgwNTRjOTZhMzk5OWJiYWI4NGFhNTBlMzVlNWUNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm5hbWUiOiJidWNrZXRJbkNvcHlBdHRycyJ9Cg0KLS1hYTY5YzEzNzM4MWM2NDEwYjFhODJhN2Y4OTFhMDc2MzgwNTRjOTZhMzk5OWJiYWI4NGFhNTBlMzVlNWUNCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOA0KDQpmb28NCi0tYWE2OWMxMzczODFjNjQxMGIxYTgyYTdmODkxYTA3NjM4MDU0Yzk2YTM5OTliYmFiODRhYTUwZTM1ZTVlLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3429" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:44 GMT" + ], + "Etag": [ + "CNiQluSW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051383000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrnm19:4486,/bns/yr/borg/yr/bns/blobstore2/bitpusher/32.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=C8ysW9uROMH5kAPknaPwAQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/32.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/32:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWTViWV96Nk5YcmI0c3JCbmd1Z0dCRHZSeldidE5ERFcwb201SUtrUENMdWdqUXRtR3dvd1JHbzlCcGtob2NnVEV3dXRLUUpRYXo2UXdNcVpNVGd6UFVzSmpJY3h0OThDVXhQQXpMcGJsUEE4Q1I5ZkNhSmU5bWc3X2pSQ3BJTzRpNWpNbHRfN2w5RnBsbUhqcGl6LVdKSXZ0TDBta1duRVFRR2dmQkJjLXBhbEhleFpWNElHcVQ0YTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrYaPW-mVsy9yVtUYn-Xa4rHX25K84ldGpiSoDCXIKpmhvHpfE65GhDhdZtVnQnd91KAuaSxTJRfiUwx-4d0WkTWEuKDw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9idWNrZXRJbkNvcHlBdHRycy8xNTM4MDUxMDg0MjI0NjAwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYnVja2V0SW5Db3B5QXR0cnMiLCJuYW1lIjoiYnVja2V0SW5Db3B5QXR0cnMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NDIyNDYwMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0NC4yMjRaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDQuMjI0WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQ0LjIyNFoiLCJzaXplIjoiMyIsIm1kNUhhc2giOiJyTDBZMjB6QytGenQ3MlZQek1TazJBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYnVja2V0SW5Db3B5QXR0cnM/Z2VuZXJhdGlvbj0xNTM4MDUxMDg0MjI0NjAwJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2J1Y2tldEluQ29weUF0dHJzLzE1MzgwNTEwODQyMjQ2MDAvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9idWNrZXRJbkNvcHlBdHRycy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJidWNrZXRJbkNvcHlBdHRycyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDg0MjI0NjAwIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTmlRbHVTVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYnVja2V0SW5Db3B5QXR0cnMvMTUzODA1MTA4NDIyNDYwMC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9idWNrZXRJbkNvcHlBdHRycy9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYnVja2V0SW5Db3B5QXR0cnMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NDIyNDYwMCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTmlRbHVTVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYnVja2V0SW5Db3B5QXR0cnMvMTUzODA1MTA4NDIyNDYwMC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9idWNrZXRJbkNvcHlBdHRycy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYnVja2V0SW5Db3B5QXR0cnMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NDIyNDYwMCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ05pUWx1U1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2J1Y2tldEluQ29weUF0dHJzLzE1MzgwNTEwODQyMjQ2MDAvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2J1Y2tldEluQ29weUF0dHJzL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYnVja2V0SW5Db3B5QXR0cnMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NDIyNDYwMCIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNOaVFsdVNXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiejhTdUhRPT0iLCJldGFnIjoiQ05pUWx1U1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "b63232023ceca5a0", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/bucketInCopyAttrs/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/bucketInCopyAttrs?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "62" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b359f31e9eda65b74dd2328cf1897da5/2967312002481897404;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/bucketInCopyAttrs/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/bucketInCopyAttrs?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEifQo=" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "2928" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:44 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051384000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrhj8:4264,/bns/yv/borg/yv/bns/blobstore2/bitpusher/235.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=DMysW_maFYnuggSJ1Lr4CQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/235.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/235:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWTViWV96Nk5YcmI0c3JCbmd1Z0dCRHZSeldidE5ERFcwb201SUtrUENMdWdqUXRtR3dvd1JHbzlCcGtob2NnVEV3dXRLUUpRYXo2UXdNcVpNVGd6UFVzSmpJY3h0OThDVXhQQXpMcGJsUEE4Q1I5ZkNhSmU5bWc3X2pSQ3BJTzRpNWpNbHRfN2w5RnBsbUhqcGl6LVdKSXZ0TDBta1duRVFRR2dmQkJjLXBhbEhleFpWNElHcVQ0YTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoDa0ITv4m8GBWZHkTRpUkhju59P-najn0K-qoegCn7bEUdjhc_c1kkm7BxbRXNMyCnqbLk4SjpJ8HgfxmBi4jHK9s8RQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IlJlcXVpcmVkIiwiZGVidWdJbmZvIjoiY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89bnVsbCwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWJhZFJlcXVlc3QsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLlJFUVVJUkVELCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1udWxsLCBlcnJvclByb3RvQ29kZT1SRVFVSVJFRCwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkuZGVzdGluYXRpb25fcmVzb3VyY2UuaWQubmFtZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LmRlc3RpbmF0aW9uX3Jlc291cmNlLmlkLm5hbWUsIG1lc3NhZ2U9UmVxdWlyZWQsIHJlYXNvbj1yZXF1aXJlZCwgcnBjQ29kZT00MDB9IFJlcXVpcmVkXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMCwibWVzc2FnZSI6IlJlcXVpcmVkIn19" + } + }, + { + "ID": "f39634171d163619", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=9c11bb8c567eb4b2238e0f29baabdad7310c3407295239aab1f1ba158385" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "02e34d54248307bc8698501b08b37d8b/3798686937111073292;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS05YzExYmI4YzU2N2ViNGIyMjM4ZTBmMjliYWFiZGFkNzMxMGMzNDA3Mjk1MjM5YWFiMWYxYmExNTgzODUNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNyYzMyYyI6ImNIK0Erdz09IiwibmFtZSI6Imhhc2hlc09uVXBsb2FkLTEifQoNCi0tOWMxMWJiOGM1NjdlYjRiMjIzOGUwZjI5YmFhYmRhZDczMTBjMzQwNzI5NTIzOWFhYjFmMWJhMTU4Mzg1DQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgNCg0KSSBjYW4ndCB3YWl0IHRvIGJlIHZlcmlmaWVkDQotLTljMTFiYjhjNTY3ZWI0YjIyMzhlMGYyOWJhYWJkYWQ3MzEwYzM0MDcyOTUyMzlhYWIxZjFiYTE1ODM4NS0tDQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3414" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:45 GMT" + ], + "Etag": [ + "CLmKweSW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051384000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrat7:4174,/bns/yv/borg/yv/bns/blobstore2/bitpusher/208.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=DMysW7TbHcvWgwSzu6-IBw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/208.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/208:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYXdSQ1M2WXgtYjJEdmpBazA2dXVSS2FmSHRBSDFRYVk3ZmNZa3VsaXNyU19rbDJRRjJNMU1oUG5UX0wwelFUa1cwbkNkQ282RXlfckF5Y2J4aFdVQzh6SXIwMFZTaXJWaElfSWgzWlljc3VRQXR6eXk3ZXdYUTlYemJ0VjM0Tm9yZzBlUFNmaWFJTjlOVWtXY0NUbWY3cXczRkNWZWhHSFZUaW1OY1hFOXhyV3ZYY0FMZzR4N2JXV3MwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrPbPHpxg2xi0jHMzfoGOksYnVbrNPFBA79OwbWop7GQk-hQCVhdQHH2oJuWzqkHO0nR-jdQzk7DI2SD2lwslSB7r16lg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9oYXNoZXNPblVwbG9hZC0xLzE1MzgwNTEwODQ5MjgzMTMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9oYXNoZXNPblVwbG9hZC0xIiwibmFtZSI6Imhhc2hlc09uVXBsb2FkLTEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NDkyODMxMyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0NC45MjhaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDQuOTI4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQ0LjkyOFoiLCJzaXplIjoiMjciLCJtZDVIYXNoIjoib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTE/Z2VuZXJhdGlvbj0xNTM4MDUxMDg0OTI4MzEzJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTUzODA1MTA4NDkyODMxMy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiaGFzaGVzT25VcGxvYWQtMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDg0OTI4MzEzIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTG1Ld2VTVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvaGFzaGVzT25VcGxvYWQtMS8xNTM4MDUxMDg0OTI4MzEzL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NDkyODMxMyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTG1Ld2VTVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvaGFzaGVzT25VcGxvYWQtMS8xNTM4MDUxMDg0OTI4MzEzL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NDkyODMxMyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0xtS3dlU1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTUzODA1MTA4NDkyODMxMy91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vaGFzaGVzT25VcGxvYWQtMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NDkyODMxMyIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNMbUt3ZVNXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiY0grQSt3PT0iLCJldGFnIjoiQ0xtS3dlU1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "a769205b3700f7a4", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=24b4b20cd70ea2c753252870eee82bd68cf04ff437d12f5e2a35bf547a58" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d8ef1d10c2ba55e62a6a721e3236b56c/4557723906532271451;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0yNGI0YjIwY2Q3MGVhMmM3NTMyNTI4NzBlZWU4MmJkNjhjZjA0ZmY0MzdkMTJmNWUyYTM1YmY1NDdhNTgNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNyYzMyYyI6ImNIK0EvQT09IiwibmFtZSI6Imhhc2hlc09uVXBsb2FkLTEifQoNCi0tMjRiNGIyMGNkNzBlYTJjNzUzMjUyODcwZWVlODJiZDY4Y2YwNGZmNDM3ZDEyZjVlMmEzNWJmNTQ3YTU4DQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgNCg0KSSBjYW4ndCB3YWl0IHRvIGJlIHZlcmlmaWVkDQotLTI0YjRiMjBjZDcwZWEyYzc1MzI1Mjg3MGVlZTgyYmQ2OGNmMDRmZjQzN2QxMmY1ZTJhMzViZjU0N2E1OC0tDQo=" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "3257" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:45 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051384000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrgb22:4240,/bns/yv/borg/yv/bns/blobstore2/bitpusher/396.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=DcysW66WCpGegQT-37-ACg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/396.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/396:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYXdSQ1M2WXgtYjJEdmpBazA2dXVSS2FmSHRBSDFRYVk3ZmNZa3VsaXNyU19rbDJRRjJNMU1oUG5UX0wwelFUa1cwbkNkQ282RXlfckF5Y2J4aFdVQzh6SXIwMFZTaXJWaElfSWgzWlljc3VRQXR6eXk3ZXdYUTlYemJ0VjM0Tm9yZzBlUFNmaWFJTjlOVWtXY0NUbWY3cXczRkNWZWhHSFZUaW1OY1hFOXhyV3ZYY0FMZzR4N2JXV3MwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Upo2Hgvl8XFud5oC3c-w4GBCnJ2pRoOuEIWiuJzNB7V_G-pdPLCzNdA4b9hBDqGf0zxjHaI7YyjF1fa5PoVg6u0GtAvkA" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImludmFsaWQiLCJtZXNzYWdlIjoiUHJvdmlkZWQgQ1JDMzJDIFwiY0grQS9BPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgQ1JDMzJDIFwiY0grQSt3PT1cIi4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9SU5WQUxJRF9WQUxVRSwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPW51bGwsIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5JTlZBTElEX1ZBTFVFLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1udWxsLCBlcnJvclByb3RvQ29kZT1JTlZBTElEX1ZBTFVFLCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5jcmMzMmMsIG1lc3NhZ2U9UHJvdmlkZWQgQ1JDMzJDIFwiY0grQS9BPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgQ1JDMzJDIFwiY0grQSt3PT1cIi4sIHVubmFtZWRBcmd1bWVudHM9W2NIK0EvQT09XX0sIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5jcmMzMmMsIG1lc3NhZ2U9UHJvdmlkZWQgQ1JDMzJDIFwiY0grQS9BPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgQ1JDMzJDIFwiY0grQSt3PT1cIi4sIHJlYXNvbj1pbnZhbGlkLCBycGNDb2RlPTQwMH0gUHJvdmlkZWQgQ1JDMzJDIFwiY0grQS9BPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgQ1JDMzJDIFwiY0grQSt3PT1cIi5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAwLCJtZXNzYWdlIjoiUHJvdmlkZWQgQ1JDMzJDIFwiY0grQS9BPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgQ1JDMzJDIFwiY0grQSt3PT1cIi4ifX0=" + } + }, + { + "ID": "ef48f17d06d0157a", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=810d5c6fdc019b24eacbdf8682c8627d6590a79b617cff6feb47a044a0b1" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "07d0fdae8f7007415ffc49d93dd59bb2/5389098841178290090;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS04MTBkNWM2ZmRjMDE5YjI0ZWFjYmRmODY4MmM4NjI3ZDY1OTBhNzliNjE3Y2ZmNmZlYjQ3YTA0NGEwYjENCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm5hbWUiOiJoYXNoZXNPblVwbG9hZC0xIn0KDQotLTgxMGQ1YzZmZGMwMTliMjRlYWNiZGY4NjgyYzg2MjdkNjU5MGE3OWI2MTdjZmY2ZmViNDdhMDQ0YTBiMQ0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04DQoNCkkgY2FuJ3Qgd2FpdCB0byBiZSB2ZXJpZmllZA0KLS04MTBkNWM2ZmRjMDE5YjI0ZWFjYmRmODY4MmM4NjI3ZDY1OTBhNzliNjE3Y2ZmNmZlYjQ3YTA0NGEwYjEtLQ0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3414" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:45 GMT" + ], + "Etag": [ + "CN6r5uSW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051384000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrkb18:4313,/bns/yr/borg/yr/bns/blobstore2/bitpusher/108.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=DcysW86fDYSf4QTOgaLYAg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/108.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/108:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYXdSQ1M2WXgtYjJEdmpBazA2dXVSS2FmSHRBSDFRYVk3ZmNZa3VsaXNyU19rbDJRRjJNMU1oUG5UX0wwelFUa1cwbkNkQ282RXlfckF5Y2J4aFdVQzh6SXIwMFZTaXJWaElfSWgzWlljc3VRQXR6eXk3ZXdYUTlYemJ0VjM0Tm9yZzBlUFNmaWFJTjlOVWtXY0NUbWY3cXczRkNWZWhHSFZUaW1OY1hFOXhyV3ZYY0FMZzR4N2JXV3MwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrS6-Vhz80rJNSjtGGXmdL55rkkvP0-kGTd4jruD1fpNr1WUVbnNm2DyoUOF72Xjr7cMMKCr4SLBMAy0rLCnjApMSNnOg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9oYXNoZXNPblVwbG9hZC0xLzE1MzgwNTEwODU1Mzg3ODIiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9oYXNoZXNPblVwbG9hZC0xIiwibmFtZSI6Imhhc2hlc09uVXBsb2FkLTEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NTUzODc4MiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0NS41MzhaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDUuNTM4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQ1LjUzOFoiLCJzaXplIjoiMjciLCJtZDVIYXNoIjoib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTE/Z2VuZXJhdGlvbj0xNTM4MDUxMDg1NTM4NzgyJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTUzODA1MTA4NTUzODc4Mi9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiaGFzaGVzT25VcGxvYWQtMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDg1NTM4NzgyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTjZyNXVTVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvaGFzaGVzT25VcGxvYWQtMS8xNTM4MDUxMDg1NTM4NzgyL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NTUzODc4MiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTjZyNXVTVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvaGFzaGVzT25VcGxvYWQtMS8xNTM4MDUxMDg1NTM4NzgyL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NTUzODc4MiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ042cjV1U1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTUzODA1MTA4NTUzODc4Mi91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vaGFzaGVzT25VcGxvYWQtMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NTUzODc4MiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNONnI1dVNXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiY0grQSt3PT0iLCJldGFnIjoiQ042cjV1U1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "aeb6be04bcc74ba0", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=ae418d65701db297ce527d2c120467ecb1ee80f563d94aee4866cbc0fd1b" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "25460195dd401365eac6bbd3a60d65a6/6148135806304520954;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS1hZTQxOGQ2NTcwMWRiMjk3Y2U1MjdkMmMxMjA0NjdlY2IxZWU4MGY1NjNkOTRhZWU0ODY2Y2JjMGZkMWINCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm1kNUhhc2giOiJvZlpqR2xjWFBKaUdPQWZLRmJKbDFRPT0iLCJuYW1lIjoiaGFzaGVzT25VcGxvYWQtMSJ9Cg0KLS1hZTQxOGQ2NTcwMWRiMjk3Y2U1MjdkMmMxMjA0NjdlY2IxZWU4MGY1NjNkOTRhZWU0ODY2Y2JjMGZkMWINCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOA0KDQpJIGNhbid0IHdhaXQgdG8gYmUgdmVyaWZpZWQNCi0tYWU0MThkNjU3MDFkYjI5N2NlNTI3ZDJjMTIwNDY3ZWNiMWVlODBmNTYzZDk0YWVlNDg2NmNiYzBmZDFiLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3414" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:46 GMT" + ], + "Etag": [ + "CP+iiuWW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051384000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrv5:4481,/bns/yv/borg/yv/bns/blobstore2/bitpusher/192.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=DcysW4P-L8HMggTy3YG4Bw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/192.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/192:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYXdSQ1M2WXgtYjJEdmpBazA2dXVSS2FmSHRBSDFRYVk3ZmNZa3VsaXNyU19rbDJRRjJNMU1oUG5UX0wwelFUa1cwbkNkQ282RXlfckF5Y2J4aFdVQzh6SXIwMFZTaXJWaElfSWgzWlljc3VRQXR6eXk3ZXdYUTlYemJ0VjM0Tm9yZzBlUFNmaWFJTjlOVWtXY0NUbWY3cXczRkNWZWhHSFZUaW1OY1hFOXhyV3ZYY0FMZzR4N2JXV3MwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uri8JdVC7RYskcBM7EGhdtoW5uklcAnOgF98hGO545bvZD8IZyoFJ244dd5cMUw1-BPBoJPZvrk2B9_Lpki5xeRUxX_tw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9oYXNoZXNPblVwbG9hZC0xLzE1MzgwNTEwODYxMjc0ODciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9oYXNoZXNPblVwbG9hZC0xIiwibmFtZSI6Imhhc2hlc09uVXBsb2FkLTEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NjEyNzQ4NyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0Ni4xMjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDYuMTI3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQ2LjEyN1oiLCJzaXplIjoiMjciLCJtZDVIYXNoIjoib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTE/Z2VuZXJhdGlvbj0xNTM4MDUxMDg2MTI3NDg3JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTUzODA1MTA4NjEyNzQ4Ny9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiaGFzaGVzT25VcGxvYWQtMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDg2MTI3NDg3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUCtpaXVXVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvaGFzaGVzT25VcGxvYWQtMS8xNTM4MDUxMDg2MTI3NDg3L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NjEyNzQ4NyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUCtpaXVXVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvaGFzaGVzT25VcGxvYWQtMS8xNTM4MDUxMDg2MTI3NDg3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NjEyNzQ4NyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1AraWl1V1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTUzODA1MTA4NjEyNzQ4Ny91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vaGFzaGVzT25VcGxvYWQtMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NjEyNzQ4NyIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQK2lpdVdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiY0grQSt3PT0iLCJldGFnIjoiQ1AraWl1V1cyOTBDRUFFPSJ9" + } + }, + { + "ID": "25cfb3bb34ff59eb", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=0624f19c3413a5672f41d77972dec9fc931b569bfd152be7463506856c40" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "7b7d2972cae2d70e4f634e9d1c57cd4b/6979228170757168457;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0wNjI0ZjE5YzM0MTNhNTY3MmY0MWQ3Nzk3MmRlYzlmYzkzMWI1NjliZmQxNTJiZTc0NjM1MDY4NTZjNDANCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm1kNUhhc2giOiJvdlpqR2xjWFBKaUdPQWZLRmJKbDFRPT0iLCJuYW1lIjoiaGFzaGVzT25VcGxvYWQtMSJ9Cg0KLS0wNjI0ZjE5YzM0MTNhNTY3MmY0MWQ3Nzk3MmRlYzlmYzkzMWI1NjliZmQxNTJiZTc0NjM1MDY4NTZjNDANCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOA0KDQpJIGNhbid0IHdhaXQgdG8gYmUgdmVyaWZpZWQNCi0tMDYyNGYxOWMzNDEzYTU2NzJmNDFkNzc5NzJkZWM5ZmM5MzFiNTY5YmZkMTUyYmU3NDYzNTA2ODU2YzQwLS0NCg==" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "3471" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:46 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051384000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrmj23:4408,/bns/yv/borg/yv/bns/blobstore2/bitpusher/357.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=DsysW_WBD5CDgQS0t7uoDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/357.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/357:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYXdSQ1M2WXgtYjJEdmpBazA2dXVSS2FmSHRBSDFRYVk3ZmNZa3VsaXNyU19rbDJRRjJNMU1oUG5UX0wwelFUa1cwbkNkQ282RXlfckF5Y2J4aFdVQzh6SXIwMFZTaXJWaElfSWgzWlljc3VRQXR6eXk3ZXdYUTlYemJ0VjM0Tm9yZzBlUFNmaWFJTjlOVWtXY0NUbWY3cXczRkNWZWhHSFZUaW1OY1hFOXhyV3ZYY0FMZzR4N2JXV3MwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq8erhdm1paZ3UEIZubqTKU1EnYYuNgJe_aTfqhN8EodeBZORHefCWBiS9HdJUW3k020eEt1eOLWzuCC5gofjTnHsco7A" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImludmFsaWQiLCJtZXNzYWdlIjoiUHJvdmlkZWQgTUQ1IGhhc2ggXCJvdlpqR2xjWFBKaUdPQWZLRmJKbDFRPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgTUQ1IGhhc2ggXCJvZlpqR2xjWFBKaUdPQWZLRmJKbDFRPT1cIi4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9SU5WQUxJRF9WQUxVRSwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPW51bGwsIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5JTlZBTElEX1ZBTFVFLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1udWxsLCBlcnJvclByb3RvQ29kZT1JTlZBTElEX1ZBTFVFLCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZS5tZDVfaGFzaF9iYXNlNjQsIG1lc3NhZ2U9UHJvdmlkZWQgTUQ1IGhhc2ggXCJvdlpqR2xjWFBKaUdPQWZLRmJKbDFRPT1cIiBkb2Vzbid0IG1hdGNoIGNhbGN1bGF0ZWQgTUQ1IGhhc2ggXCJvZlpqR2xjWFBKaUdPQWZLRmJKbDFRPT1cIi4sIHVubmFtZWRBcmd1bWVudHM9W292WmpHbGNYUEppR09BZktGYkpsMVE9PV19LCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2UubWQ1X2hhc2hfYmFzZTY0LCBtZXNzYWdlPVByb3ZpZGVkIE1ENSBoYXNoIFwib3ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09XCIgZG9lc24ndCBtYXRjaCBjYWxjdWxhdGVkIE1ENSBoYXNoIFwib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09XCIuLCByZWFzb249aW52YWxpZCwgcnBjQ29kZT00MDB9IFByb3ZpZGVkIE1ENSBoYXNoIFwib3ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09XCIgZG9lc24ndCBtYXRjaCBjYWxjdWxhdGVkIE1ENSBoYXNoIFwib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09XCIuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMCwibWVzc2FnZSI6IlByb3ZpZGVkIE1ENSBoYXNoIFwib3ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09XCIgZG9lc24ndCBtYXRjaCBjYWxjdWxhdGVkIE1ENSBoYXNoIFwib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09XCIuIn19" + } + }, + { + "ID": "a9c389a0eb73daac", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/iam?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "cdb1ae8a9c42469760476bfb84eddd22/8569640074824319720;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/iam?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "341" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:46 GMT" + ], + "Etag": [ + "CAk=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:46 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051386000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrae1:4130,/bns/yw/borg/yw/bns/blobstore2/bitpusher/82.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=DsysW_KeFtbyhQTW3Ls4" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/82.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/82:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYTRrVFBYeTRJSTVPN2VpalFwWjI0ZFpXMU1Ka1poUnI5WWRHUWg1V1NzZHAzWDh4M0RSZ2pvZ1pUVHJVa0M1ZzJGa2hNY1ZyNVFrTmRLaXdVWjg5UXY0T2hlaUhtR2d3RlU0ekY1djJWVFp3Unh5ZEs2Z1ZpVnRaRG1SZUp6VmkyYlhNVjVlQmdhcVQ1aGlDWEdLUl9VYmdJTDlXOVl5dWUteEpIVXNSR0JiRm0tSFhJN0VTWVhaSzgwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqBlHo09PoYV5xODCs727aMaz6gcs8xf5X07yZ7EjlXbKW2xwoDRGr4rew96LrtIrP7TfqFxvPETZbtq9gAiKDN8IReWA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNwb2xpY3kiLCJyZXNvdXJjZUlkIjoicHJvamVjdHMvXy9idWNrZXRzL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImJpbmRpbmdzIjpbeyJyb2xlIjoicm9sZXMvc3RvcmFnZS5sZWdhY3lCdWNrZXRPd25lciIsIm1lbWJlcnMiOlsicHJvamVjdEVkaXRvcjpkdWxjZXQtcG9ydC03NjIiLCJwcm9qZWN0T3duZXI6ZHVsY2V0LXBvcnQtNzYyIl19LHsicm9sZSI6InJvbGVzL3N0b3JhZ2UubGVnYWN5QnVja2V0UmVhZGVyIiwibWVtYmVycyI6WyJwcm9qZWN0Vmlld2VyOmR1bGNldC1wb3J0LTc2MiJdfV0sImV0YWciOiJDQWs9In0=" + } + }, + { + "ID": "a0c231629f1b0830", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/iam?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "317" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "45dd37de1332888471197c7ded953d2b/10160051978874759302;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/iam?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJiaW5kaW5ncyI6W3sibWVtYmVycyI6WyJwcm9qZWN0RWRpdG9yOmR1bGNldC1wb3J0LTc2MiIsInByb2plY3RPd25lcjpkdWxjZXQtcG9ydC03NjIiXSwicm9sZSI6InJvbGVzL3N0b3JhZ2UubGVnYWN5QnVja2V0T3duZXIifSx7Im1lbWJlcnMiOlsicHJvamVjdFZpZXdlcjpkdWxjZXQtcG9ydC03NjIiXSwicm9sZSI6InJvbGVzL3N0b3JhZ2UubGVnYWN5QnVja2V0UmVhZGVyIn0seyJtZW1iZXJzIjpbInByb2plY3RWaWV3ZXI6ZHVsY2V0LXBvcnQtNzYyIl0sInJvbGUiOiJyb2xlcy9zdG9yYWdlLm9iamVjdFZpZXdlciJ9XSwiZXRhZyI6IkNBaz0ifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "423" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:47 GMT" + ], + "Etag": [ + "CAo=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051386000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrsn11:4209,/bns/yv/borg/yv/bns/blobstore2/bitpusher/290.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=DsysW5mCJYvRgQTe5JKYDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/290.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/290:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYTRrVFBYeTRJSTVPN2VpalFwWjI0ZFpXMU1Ka1poUnI5WWRHUWg1V1NzZHAzWDh4M0RSZ2pvZ1pUVHJVa0M1ZzJGa2hNY1ZyNVFrTmRLaXdVWjg5UXY0T2hlaUhtR2d3RlU0ekY1djJWVFp3Unh5ZEs2Z1ZpVnRaRG1SZUp6VmkyYlhNVjVlQmdhcVQ1aGlDWEdLUl9VYmdJTDlXOVl5dWUteEpIVXNSR0JiRm0tSFhJN0VTWVhaSzgwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UouvH87NAtIZRYuefULe5I19LMPKuAlFjo8gRWzOW2m8ywZl8NHM6ym9LuvwbH0mpAukabVKwFOpi6wbATQSLR6HnJdBw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNwb2xpY3kiLCJyZXNvdXJjZUlkIjoicHJvamVjdHMvXy9idWNrZXRzL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImJpbmRpbmdzIjpbeyJyb2xlIjoicm9sZXMvc3RvcmFnZS5sZWdhY3lCdWNrZXRPd25lciIsIm1lbWJlcnMiOlsicHJvamVjdEVkaXRvcjpkdWxjZXQtcG9ydC03NjIiLCJwcm9qZWN0T3duZXI6ZHVsY2V0LXBvcnQtNzYyIl19LHsicm9sZSI6InJvbGVzL3N0b3JhZ2UubGVnYWN5QnVja2V0UmVhZGVyIiwibWVtYmVycyI6WyJwcm9qZWN0Vmlld2VyOmR1bGNldC1wb3J0LTc2MiJdfSx7InJvbGUiOiJyb2xlcy9zdG9yYWdlLm9iamVjdFZpZXdlciIsIm1lbWJlcnMiOlsicHJvamVjdFZpZXdlcjpkdWxjZXQtcG9ydC03NjIiXX1dLCJldGFnIjoiQ0FvPSJ9" + } + }, + { + "ID": "144b6da1d9241efb", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/iam?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b1e1650a9d8d34458c16d574cfc635f7/11678125913438965029;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/iam?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "423" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:47 GMT" + ], + "Etag": [ + "CAo=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:47 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051386000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrwa10:4354,/bns/yr/borg/yr/bns/blobstore2/bitpusher/24.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=D8ysW6bVKY-7kASf45LYDQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/24.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/24:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYTRrVFBYeTRJSTVPN2VpalFwWjI0ZFpXMU1Ka1poUnI5WWRHUWg1V1NzZHAzWDh4M0RSZ2pvZ1pUVHJVa0M1ZzJGa2hNY1ZyNVFrTmRLaXdVWjg5UXY0T2hlaUhtR2d3RlU0ekY1djJWVFp3Unh5ZEs2Z1ZpVnRaRG1SZUp6VmkyYlhNVjVlQmdhcVQ1aGlDWEdLUl9VYmdJTDlXOVl5dWUteEpIVXNSR0JiRm0tSFhJN0VTWVhaSzgwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrORn0AA37Z-krQlzExepj1CiRXgkBL-ohkvMSncFboI2PxjqFbfe-kAqtndNv8kCO8nVJdwF0QL9kTRQsw7Z1UWaou5g" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNwb2xpY3kiLCJyZXNvdXJjZUlkIjoicHJvamVjdHMvXy9idWNrZXRzL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImJpbmRpbmdzIjpbeyJyb2xlIjoicm9sZXMvc3RvcmFnZS5sZWdhY3lCdWNrZXRPd25lciIsIm1lbWJlcnMiOlsicHJvamVjdEVkaXRvcjpkdWxjZXQtcG9ydC03NjIiLCJwcm9qZWN0T3duZXI6ZHVsY2V0LXBvcnQtNzYyIl19LHsicm9sZSI6InJvbGVzL3N0b3JhZ2UubGVnYWN5QnVja2V0UmVhZGVyIiwibWVtYmVycyI6WyJwcm9qZWN0Vmlld2VyOmR1bGNldC1wb3J0LTc2MiJdfSx7InJvbGUiOiJyb2xlcy9zdG9yYWdlLm9iamVjdFZpZXdlciIsIm1lbWJlcnMiOlsicHJvamVjdFZpZXdlcjpkdWxjZXQtcG9ydC03NjIiXX1dLCJldGFnIjoiQ0FvPSJ9" + } + }, + { + "ID": "75ef487a8b257113", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/iam/testPermissions?alt=json\u0026permissions=storage.buckets.get\u0026permissions=storage.buckets.delete\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "08ca66e09b16381170a05dabd28c307f/13268537817489404867;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/iam/testPermissions?alt=json\u0026permissions=storage.buckets.get\u0026permissions=storage.buckets.delete\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "108" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:48 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:48 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051386000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrgb22:4240,/bns/yw/borg/yw/bns/blobstore2/bitpusher/167.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=D8ysW-TXPIPwhAT094D4Cw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/167.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/167:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYTRrVFBYeTRJSTVPN2VpalFwWjI0ZFpXMU1Ka1poUnI5WWRHUWg1V1NzZHAzWDh4M0RSZ2pvZ1pUVHJVa0M1ZzJGa2hNY1ZyNVFrTmRLaXdVWjg5UXY0T2hlaUhtR2d3RlU0ekY1djJWVFp3Unh5ZEs2Z1ZpVnRaRG1SZUp6VmkyYlhNVjVlQmdhcVQ1aGlDWEdLUl9VYmdJTDlXOVl5dWUteEpIVXNSR0JiRm0tSFhJN0VTWVhaSzgwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoC8Y01kEJQMNndrzzPlPKFhvQgzyA3VhI6oytWf7ncjE_esF2ymE5i-_dPkHhV9HepRXk9dgA1pri0GaTC3OIBTsv0UQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSN0ZXN0SWFtUGVybWlzc2lvbnNSZXNwb25zZSIsInBlcm1pc3Npb25zIjpbInN0b3JhZ2UuYnVja2V0cy5nZXQiLCJzdG9yYWdlLmJ1Y2tldHMuZGVsZXRlIl19" + } + }, + { + "ID": "8c636bdcc9eea5d0", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "93" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "651a6846b9563d5640c8d4c98b925186/14858948622061705314;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9LCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIn0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "459" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:49 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051388000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrt186:4143,/bns/yv/borg/yv/bns/blobstore2/bitpusher/50.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=EMysW--5FJHLswb4lL2QAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/50.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/50:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpweAHP2xx7tNgquA6NRVU_gdpSeklRzOtSWuzv7KACvxgqSJo8lMglTq923iAXBathqwAmYY0AXW6tjE4Wv7T6G_TxHw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDguODg2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQ4Ljg4NloiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9LCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "db9e9aa20b3f272d", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/user-integration%40gcloud-golang-firestore-tests.iam.gserviceaccount.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "159" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ebbbe915bf015ecfc551f82528f67153/16449360526112079361;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/user-integration%40gcloud-golang-firestore-tests.iam.gserviceaccount.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIn0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "589" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:51 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051389000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnnr1:4426,/bns/yx/borg/yx/bns/blobstore2/bitpusher/74.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=EcysW7CiCYO9zgLGiKCYAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/74.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/74:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpWAHw7IVeXEMZ_GnQKXv6PGvEtBLRnR7sTaAivOc7U2HSPZEMQycXnbcXRlp6kH8tsmEqyVTQ8rSia2NHJeoDFpZMwgQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "9376ae75abf3dc2d", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "946e42b81d2942871e88dd356cd216c4/18039490955202651039;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2976" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:51 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:51 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051391000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbd63:4301,/bns/yr/borg/yr/bns/blobstore2/bitpusher/4.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=E8ysW8zbAY-AkATj4oWoBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/4.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/4:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqB_1uMwyjpyvhwCFL8KjtRxVDOjP1z4Nu7W0c1hElpAf6YeNBN9lzM-wpX7ZXWj43ntFXdHhlyxVuLLXRQVABWkI6CXA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDguODg2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjUwLjgxOVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2FjbC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZW50aXR5IjoidXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0FJPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9LCJldGFnIjoiQ0FJPSJ9" + } + }, + { + "ID": "128bb0d838dfcf9f", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "58f6f6f433a012e66ccd520abdf51915/1183440260520184126;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2976" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:51 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:51 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051391000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrtw20:4200,/bns/yv/borg/yv/bns/blobstore2/bitpusher/233.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=E8ysW6L4GYruggSr-I3oCQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/233.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/233:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur0_BMChIpY89D5SIxg1IX7Mzvg9U-PsS9-1yP65Iz9rnXfhp367PanBonVPXZeldon4CD6ad3ZHvy-jDfGh2g2kjuDXQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDguODg2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjUwLjgxOVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2FjbC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZW50aXR5IjoidXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0FJPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9LCJldGFnIjoiQ0FJPSJ9" + } + }, + { + "ID": "1d28c60b2c1aaa62", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "da28f10a14d9659d366cb18aa5d6d591/2773852164587335389;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "12071" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:52 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:52 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051391000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vnba207:4324,/bns/yx/borg/yx/bns/blobstore2/bitpusher/135.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=E8ysW53eL8btzAKs_rD4CA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/135.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/135:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpFChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErMOIrSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq7QZN5rGXMozsX4ASIM0yxatYCGxmDwDjDNFgy0g83ZPIvkJHrneIYGTsC9WssyRG14bT4ipnP5eCcYpLLXd1pLEJK0g" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjk5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YTozMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IuZ2V0KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YTo4Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1SRVFVSVJFRCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6OTkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjMxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5nZXQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjgzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWJhZFJlcXVlc3QsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLlJFUVVJUkVELCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjk5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YTozMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IuZ2V0KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YTo4Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YTo5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6MzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmdldChCdWNrZXRzRGVsZWdhdG9yLmphdmE6ODMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMCwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4ifX0=" + } + }, + { + "ID": "5ac686ece3e25d68", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "bd4deb7c00fc6498c75a32d0d5bf5eef/4364262964848022651;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2976" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:52 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:52 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051392000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrcf25:4489,/bns/yr/borg/yr/bns/blobstore2/bitpusher/38.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FMysW6ObAq-NkAS0m4uIDQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/38.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/38:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpFChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErMOIrSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrP1A6KQZYe1fSfdQklQD3Li6UV647Oa2MVILnNtCnDCjzZnmXniTW3emikNnz1oiPQBa6rlnhFSmeh_tUg3Xn7uMcNjw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDguODg2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjUwLjgxOVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2FjbC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZW50aXR5IjoidXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0FJPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9LCJldGFnIjoiQ0FJPSJ9" + } + }, + { + "ID": "01d97c7a0e0c6ad6", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "951a587dc6dd7039ad69e1977096a8c0/5954393398233430298;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "12927" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:52 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:52 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051392000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vray62:4018,/bns/yr/borg/yr/bns/blobstore2/bitpusher/49.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FMysW8m4B43q4QSDmZy4Ag" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/49.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/49:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpFChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErMOIrSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpgFD6v6LBuWvl36FBHOwD0dgc-Iy4UFOJ0HZ_er9KgJJtoQwQP7EPy-gBByK6x9f-sOmzxQ_rg9ZJHf6RaVlrEUtRdwQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YTo5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6MzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmdldChCdWNrZXRzRGVsZWdhdG9yLmphdmE6ODMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1GT1JCSURERU4sIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6OTkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjMxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5nZXQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjgzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9Zm9yYmlkZGVuLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5GT1JCSURERU4sIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YTo5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6MzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmdldChCdWNrZXRzRGVsZWdhdG9yLmphdmE6ODMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6OTkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjMxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5nZXQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjgzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMywibWVzc2FnZSI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuIn19" + } + }, + { + "ID": "f381b18f194a2f5c", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=2a42e09cb0222d57d0cdbda1a68340bdb1fdca64a8c063a41cf471868a60" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "cdaf842a27589d153e2b9d276966c883/6713711838336371817;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0yYTQyZTA5Y2IwMjIyZDU3ZDBjZGJkYTFhNjgzNDBiZGIxZmRjYTY0YThjMDYzYTQxY2Y0NzE4NjhhNjANCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJmb28ifQoNCi0tMmE0MmUwOWNiMDIyMmQ1N2QwY2RiZGExYTY4MzQwYmRiMWZkY2E2NGE4YzA2M2E0MWNmNDcxODY4YTYwDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW4NCg0KaGVsbG8NCi0tMmE0MmUwOWNiMDIyMmQ1N2QwY2RiZGExYTY4MzQwYmRiMWZkY2E2NGE4YzA2M2E0MWNmNDcxODY4YTYwLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3226" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:52 GMT" + ], + "Etag": [ + "COSsl+iW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051388000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrqm14:4229,/bns/yw/borg/yw/bns/blobstore2/bitpusher/203.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FMysW-C5FJW6N5Kzm8gE" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/203.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/203:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqkxLDMvcle5zEJBY34RLPtNVKJ1fnbATAahxz6t3qxFKd95_AEw1vsPKhIMG-xQA9v7eqd3F12o1YJnnGyCUclEv4f-A" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MjYzMzE4OCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MjYzMzE4OCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo1Mi42MzNaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NTIuNjMzWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjUyLjYzM1oiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTA5MjYzMzE4OCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MjYzMzE4OC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MjYzMzE4OCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ09Tc2wraVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkyNjMzMTg4L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTI2MzMxODgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ09Tc2wraVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkyNjMzMTg4L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTI2MzMxODgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNPU3NsK2lXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MjYzMzE4OC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTI2MzMxODgiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDT1NzbCtpVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNPU3NsK2lXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "adbe5cfd07f61e80", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=7106bfacec7d6a09fd14fd37931b02367585ee2e8c64645316750dfde543" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "238f7c250ffab02d2bd5182bfd9cc71f/7544805302283804601;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS03MTA2YmZhY2VjN2Q2YTA5ZmQxNGZkMzc5MzFiMDIzNjc1ODVlZTJlOGM2NDY0NTMxNjc1MGRmZGU1NDMNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJmb28ifQoNCi0tNzEwNmJmYWNlYzdkNmEwOWZkMTRmZDM3OTMxYjAyMzY3NTg1ZWUyZThjNjQ2NDUzMTY3NTBkZmRlNTQzDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW4NCg0KaGVsbG8NCi0tNzEwNmJmYWNlYzdkNmEwOWZkMTRmZDM3OTMxYjAyMzY3NTg1ZWUyZThjNjQ2NDUzMTY3NTBkZmRlNTQzLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3226" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:53 GMT" + ], + "Etag": [ + "CMT2r+iW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051388000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbp5:4114,/bns/yr/borg/yr/bns/blobstore2/bitpusher/105.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FMysW-CJLpCMkATtpaSoDA" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/105.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/105:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Urq35CFbyHuYnJMS9wNKdQPD54VQ9oePAyRAi6YWIppfLMcQ_Wiub0-7o8EIeaVGmFFTRiO_XIo5Btdzb2K3DwSZJNqXg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzAzNTg0NCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzAzNTg0NCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo1My4wMzRaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NTMuMDM0WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjUzLjAzNFoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTA5MzAzNTg0NCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzAzNTg0NC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzAzNTg0NCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ01UMnIraVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzMDM1ODQ0L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTMwMzU4NDQiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ01UMnIraVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzMDM1ODQ0L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTMwMzU4NDQiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNNVDJyK2lXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzAzNTg0NC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTMwMzU4NDQiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTVQycitpVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNNVDJyK2lXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "6974381989098ccd", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=237260ec54bf8dc245243faeb66dd61b18510d622730eeecd6b6a1afcc5d" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1aed5d989e814f60adeabf2f067063e6/8303842271721779464;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0yMzcyNjBlYzU0YmY4ZGMyNDUyNDNmYWViNjZkZDYxYjE4NTEwZDYyMjczMGVlZWNkNmI2YTFhZmNjNWQNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJmb28ifQoNCi0tMjM3MjYwZWM1NGJmOGRjMjQ1MjQzZmFlYjY2ZGQ2MWIxODUxMGQ2MjI3MzBlZWVjZDZiNmExYWZjYzVkDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW4NCg0KaGVsbG8NCi0tMjM3MjYwZWM1NGJmOGRjMjQ1MjQzZmFlYjY2ZGQ2MWIxODUxMGQ2MjI3MzBlZWVjZDZiNmExYWZjYzVkLS0NCg==" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "12135" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:53 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051393000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrow18:4419,/bns/yv/borg/yv/bns/blobstore2/bitpusher/140.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FcysW6OhCpKCgwS2iqKgDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/140.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/140:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpFChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErMOMrSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq7BisLbYLLhOtKX-mgm0uHF_EpDdlc9SsVqVhxUDic-GBgzAoE7XUNzqShAPyuJo_tMYfFtXlNE0F8qnAFCl579XxCCw" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIxNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NTEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIxNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NTEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjE3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo1MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMTcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjUxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" + } + }, + { + "ID": "2708a38f17248e4e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=21fc50710a2e85a9df16ae976a592eee89a3bf61d5a3cc00d589f4ea436b" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "c835286d2a2f023e4587c8da313787d1/9135217202056119383;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0yMWZjNTA3MTBhMmU4NWE5ZGYxNmFlOTc2YTU5MmVlZTg5YTNiZjYxZDVhM2NjMDBkNTg5ZjRlYTQzNmINCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJmb28ifQoNCi0tMjFmYzUwNzEwYTJlODVhOWRmMTZhZTk3NmE1OTJlZWU4OWEzYmY2MWQ1YTNjYzAwZDU4OWY0ZWE0MzZiDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW4NCg0KaGVsbG8NCi0tMjFmYzUwNzEwYTJlODVhOWRmMTZhZTk3NmE1OTJlZWU4OWEzYmY2MWQ1YTNjYzAwZDU4OWY0ZWE0MzZiLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3181" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:53 GMT" + ], + "Etag": [ + "CISC0OiW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051393000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vnpb10:4017,/bns/yx/borg/yx/bns/blobstore2/bitpusher/49.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FcysW-mhGoqIzQKVwKT4Aw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/49.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/49:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpFChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErMOMrSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoNEzfQSF71KAopZ_IPoXU_ysPiMxX66AcMFT8VzLfFCCP-ZNcVBHqt60lvdWZMihDQq4TALbx_UZJwzMoH7ZB-Y7tmfg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo1My41NjFaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NTMuNTYxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjUzLjU2MVoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTA5MzU2MTYwNCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSVNDME9pVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "3528b2e1f97481d7", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=1683011057ae3f3e81c417873b5bac49a2246cb943117ba7e6822fbe4dba" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "18ff62e9ecc16f2dd761505112b6b3f2/9894254171477252007;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0xNjgzMDExMDU3YWUzZjNlODFjNDE3ODczYjViYWM0OWEyMjQ2Y2I5NDMxMTdiYTdlNjgyMmZiZTRkYmENCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJmb28ifQoNCi0tMTY4MzAxMTA1N2FlM2YzZTgxYzQxNzg3M2I1YmFjNDlhMjI0NmNiOTQzMTE3YmE3ZTY4MjJmYmU0ZGJhDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW4NCg0KaGVsbG8NCi0tMTY4MzAxMTA1N2FlM2YzZTgxYzQxNzg3M2I1YmFjNDlhMjI0NmNiOTQzMTE3YmE3ZTY4MjJmYmU0ZGJhLS0NCg==" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "12991" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:53 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051393000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vnbe67:4474,/bns/yx/borg/yx/bns/blobstore2/bitpusher/55.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FcysW9bbKcKPzALhvZOIDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/55.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/55:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpFChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErMOMrSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UryciEENEv-7rhlVHwecRoi4eIpPLkD9snDJxBdIg21D_qc_UQsZpaChX7XUPxFv4qrYSgtLftJ_LWGxBvbvjJBToeaqg" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMTcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjUxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIxNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NTEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIxNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NTEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjE3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo1MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" + } + }, + { + "ID": "93dbfc48d4e0ae67", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0003/foo", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b7f3940371552e2fe7340e3824bb07ef/11484666075544468549;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0003/foo" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "5" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:53 GMT" + ], + "Etag": [ + "\"5d41402abc4b2a76b9719d911017c592\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:53 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Generation": [ + "1538051093561604" + ], + "X-Goog-Hash": [ + "crc32c=mnG7TA==", + "md5=XUFAKrxLKna5cZ2REBfFkg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "5" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/43,/bns/xh/borg/xh/bns/blobstore2/bitpusher/64.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FcysW_nbOMKmswayqIGIDg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/64.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/64:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UobYLQCVAXDkWBxGuaLG3DcCe_4MnWObiBBQ3HESP7N-QS5GnqnFP4_tMrgvjZ9QyyllwC0UGwfoeVUplyqoPXVM8af3w" + ] + }, + "Body": "aGVsbG8=" + } + }, + { + "ID": "ed6543d15a309ca2", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0003/foo", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "74c8e0a2cd370f802a2c638fad744a1e/13074795409418248932;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0003/foo" + ], + "X-Goog-User-Project": [ + "dulcet-port-762" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "5" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:54 GMT" + ], + "Etag": [ + "\"5d41402abc4b2a76b9719d911017c592\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:53 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Generation": [ + "1538051093561604" + ], + "X-Goog-Hash": [ + "crc32c=mnG7TA==", + "md5=XUFAKrxLKna5cZ2REBfFkg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "5" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/12,/bns/xh/borg/xh/bns/blobstore2/bitpusher/28.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FsysW4mqAouhswbl1qKYBg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/28.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/28:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur7qo9qqOxLPqeOJg3_hC6Lw6aEFXRvIfjwfeJ60wJcvPZkkUlHiIGTpY9BY1Av4e8U2DJH2LL0G6dUQ9iYWAqlb0GiIA" + ] + }, + "Body": "aGVsbG8=" + } + }, + { + "ID": "e1568d1781fe6674", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0003/foo", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "14d9ea9e4c04369d531fe44c64494f92/14665207309190498179;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0003/foo" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "266" + ], + "Content-Type": [ + "application/xml; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:54 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:54 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/45,/bns/xh/borg/xh/bns/blobstore2/bitpusher/52.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FsysW-vABbCqswa-pIPADw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/52.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/52:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrhJXGAWNxkg2lwZ7HPMDSI-cZdGgnrHDLOt-Vn4GIt6Py6SXjBikyUW--bL8PD6_H-VDdhf90i-L0t6SMFjJvfOx4vaQ" + ] + }, + "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+VXNlclByb2plY3RNaXNzaW5nPC9Db2RlPjxNZXNzYWdlPkJ1Y2tldCBpcyBhIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjwvTWVzc2FnZT48RGV0YWlscz5CdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci48L0RldGFpbHM+PC9FcnJvcj4=" + } + }, + { + "ID": "6408084335935ff1", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0003/foo", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e96ce5b68f60f903ab1b5198c8f9f580/16255619213240937761;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0003/foo" + ], + "X-Goog-User-Project": [ + "gcloud-golang-firestore-tests" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "5" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:54 GMT" + ], + "Etag": [ + "\"5d41402abc4b2a76b9719d911017c592\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:24:53 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Generation": [ + "1538051093561604" + ], + "X-Goog-Hash": [ + "crc32c=mnG7TA==", + "md5=XUFAKrxLKna5cZ2REBfFkg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "5" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/12,/bns/xh/borg/xh/bns/blobstore2/bitpusher/79.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FsysW7bnE-6jswbStIHACg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/79.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/79:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoVhfv-eFV4ZRHB30hin-A2fc9MasLv3xA4ppkx8fs1rqGq5kaqhAwHg2LHt1HBr-7TjnfZTbDFTpfyUBdCX42usFy41w" + ] + }, + "Body": "aGVsbG8=" + } + }, + { + "ID": "c5b24411d8fb2531", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0003/foo", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9733323f0f15db56551241ac7d27e645/17846031117308089024;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0003/foo" + ], + "X-Goog-User-Project": [ + "veener-jba" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "342" + ], + "Content-Type": [ + "application/xml; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:54 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:54 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/47,/bns/xh/borg/xh/bns/blobstore2/bitpusher/62.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FsysW6CcF8SmswaLopWwDA" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/62.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/62:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpUnfRLufy7QUE_x8D4JMhXS7A6KYYHAUkUJA-0_EiWVsKAOCcy6GDqTTNo_wExvSNqJq_MgNWUhaA1shGpfMMAXVCxsA" + ] + }, + "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+VXNlclByb2plY3RBY2Nlc3NEZW5pZWQ8L0NvZGU+PE1lc3NhZ2U+UmVxdWVzdGVyIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBwZXJtaXNzaW9ucyBvbiB1c2VyIHByb2plY3QuPC9NZXNzYWdlPjxEZXRhaWxzPmludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuPC9EZXRhaWxzPjwvRXJyb3I+" + } + }, + { + "ID": "8df5a8e8cb3018e1", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4ba0fb6a6b4f3829036eec3ca23cbeda/989698947649042526;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3181" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:54 GMT" + ], + "Etag": [ + "CISC0OiW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051394000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vncd130:4493,/bns/yx/borg/yx/bns/blobstore2/bitpusher/122.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FsysW5auJsGRzgLopLngBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/122.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/122:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Upoxk0CnjyS_LCHnK0OHBf9KRPtZkRYgFF1U7mN-8kApCVZhYjcu-mLlcXBuZcvu5XZmu6xV1i3kiwVJ0chtx9tsfqucQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo1My41NjFaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NTMuNTYxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjUzLjU2MVoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTA5MzU2MTYwNCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSVNDME9pVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "c9a00d099267754b", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "12bc837e44bbea07fcd1c9cae382a949/2580109752221343229;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3181" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:54 GMT" + ], + "Etag": [ + "CISC0OiW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051391000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrti20:4165,/bns/yv/borg/yv/bns/blobstore2/bitpusher/243.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FsysW6vgK4GngASMt5uwAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/243.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/243:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur7tVi6j5IKT88SZhVKIWnUX_O-9IBWvMpw9b7nG_MsOiFfb_ZAEJ8WMbvtPnRCuooB3MuHPNjvgYUM7iqQNkeEK-O7hA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo1My41NjFaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NTMuNTYxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjUzLjU2MVoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTA5MzU2MTYwNCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSVNDME9pVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "9a3b957752d48171", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ecd1f92caab5532b924399a8f7e47269/4170521656271717276;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "12075" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:55 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:55 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051392000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vraf24:4012,/bns/yv/borg/yv/bns/blobstore2/bitpusher/260.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=FsysW6_EMMSZggTQn4ToBw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/260.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/260:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpFChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErMOIrSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UowTKPdmDqhsfA5eNzNslz7TvPHBzdXXEvZjn8SG_TrCALt9fBKzEgyUmaz3PySAxarLaEjBXM_ON7hUxuKkEmt4YKC0z4Z8_aZWNQbjHp7V9tptTY" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjI5OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmdldChPYmplY3RzRGVsZWdhdG9yLmphdmE6ODEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjI5OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmdldChPYmplY3RzRGVsZWdhdG9yLmphdmE6ODEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6Mjk4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZ2V0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo4MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YToyOTgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjcxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5nZXQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjgxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" + } + }, + { + "ID": "3bc47ee9c62df6c9", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "112b4515ed2175eacbd1552e9e0df785/5760933560338933818;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3181" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:55 GMT" + ], + "Etag": [ + "CISC0OiW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051392000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrpz1:4175,/bns/yr/borg/yr/bns/blobstore2/bitpusher/50.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=F8ysW5LoAc_44QSlq4TwBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/50.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/50:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpFChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErMOIrSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpBML43rDsc3BbW5t3GZgCV1N2yVVsV3lXOGGpwJ6pnuDNngAuI9haDrqdayPI4-QWT_n2MLiw9D7weWUPzXkOmFExouA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo1My41NjFaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NTMuNTYxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjUzLjU2MVoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTA5MzU2MTYwNCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSVNDME9pVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "f8fb7a2aa56abc06", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "744a7cbe721801da11024f6426d65bbf/7279007494886362841;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "12931" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:55 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:55 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051392000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vran71:4007,/bns/yr/borg/yr/bns/blobstore2/bitpusher/10.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=F8ysW43DBtHnkAOQzqSwAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/10.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/10:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpFChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErMOIrSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrTKHn4uUFleoyjMlSfAfhUxBkxAtGuk7BwCbGrjX9yU3lyN0fySLoL5-MG2kB4m1KtKVbociQOQbbtm4xEHIs5yByaYw" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YToyOTgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjcxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5nZXQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjgxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjI5OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmdldChPYmplY3RzRGVsZWdhdG9yLmphdmE6ODEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5HZXRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldE9iamVjdC5qYXZhOjI5OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmdldChPYmplY3RzRGVsZWdhdG9yLmphdmE6ODEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkdldE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0T2JqZWN0LmphdmE6Mjk4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuR2V0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRPYmplY3QuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZ2V0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo4MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" + } + }, + { + "ID": "2b1325dbeea3872c", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "85" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "dc89e7f65b102435e4a85a2c6f3d0fe1/8869419398953513848;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3204" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:55 GMT" + ], + "Etag": [ + "CISC0OiW290CEAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051389000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnap189:4365,/bns/yx/borg/yx/bns/blobstore2/bitpusher/57.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=F8ysW5T4E4qJzAKRg7nIAg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/57.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/57:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up-47Gg-U0R8d-RLZoqr0iirAWrSZKYpf1bvmSFFRKVEL0OT2hoDOMTUj46Ame11lFsY3aGMuv14up8TGKyQKvdhnCqqQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo1My41NjFaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NTUuNDMwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjUzLjU2MVoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTA5MzU2MTYwNCZhbHQ9bWVkaWEiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSVNDME9pVzI5MENFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSVNDME9pVzI5MENFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibW5HN1RBPT0iLCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFJPSJ9" + } + }, + { + "ID": "a519c18e9f0f3556", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "85" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "00762968e68ef9b348fedb6bec219c24/10459830203509102870;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3204" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:55 GMT" + ], + "Etag": [ + "CISC0OiW290CEAM=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrcf25:4489,/bns/yv/borg/yv/bns/blobstore2/bitpusher/358.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=F8ysW-WHIsSCgQTU6r3QDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/358.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/358:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq0-3_a-xcQuKPTmZwhCGyz98TpMddMzH9WhBX0BX6-pSaBjKeo6G2eV8LS7gmCZBLp0Rj2EXkBswc12Wecd0Ecw3Dv8Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo1My41NjFaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NTUuNjUyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjUzLjU2MVoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTA5MzU2MTYwNCZhbHQ9bWVkaWEiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSVNDME9pVzI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSVNDME9pVzI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBTT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibW5HN1RBPT0iLCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFNPSJ9" + } + }, + { + "ID": "c3cce5ec7cc787d6", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "85" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9e18d8b893776dab3395aa50220c672a/12049960632599609013;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "12267" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:56 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vraz3:4225,/bns/yw/borg/yw/bns/blobstore2/bitpusher/168.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=F8ysW6y0L4bShQS_rrGoAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/168.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/168:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqCww9J5OJXbjsyOgthOsXt3HmpChxjzf0o2zldcFmEHWWogW74ItLioX44a7LE8TOEIeVT5b5F8Woc-pDN1uqe3PXA__eDRxpoQtcr9JUpytjdAIo" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5VcGRhdGVBbmRQYXRjaE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQW5kUGF0Y2hPYmplY3QuamF2YTozMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5VcGRhdGVBbmRQYXRjaE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQW5kUGF0Y2hPYmplY3QuamF2YTo1Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IudXBkYXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMDYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5VcGRhdGVBbmRQYXRjaE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQW5kUGF0Y2hPYmplY3QuamF2YTozMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5VcGRhdGVBbmRQYXRjaE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQW5kUGF0Y2hPYmplY3QuamF2YTo1Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IudXBkYXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMDYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlVwZGF0ZUFuZFBhdGNoT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBbmRQYXRjaE9iamVjdC5qYXZhOjMzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlVwZGF0ZUFuZFBhdGNoT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBbmRQYXRjaE9iamVjdC5qYXZhOjUyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci51cGRhdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEwNilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6MzM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6NTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnVwZGF0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTA2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" + } + }, + { + "ID": "752f44d89c504490", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "85" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "fbf85c1c6cad40a2542fd31defb3775c/13640372536649983060;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3204" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:56 GMT" + ], + "Etag": [ + "CISC0OiW290CEAQ=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vral124:4458,/bns/yv/borg/yv/bns/blobstore2/bitpusher/270.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=GMysW77MAoykNvW7uMAB" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/270.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/270:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq5s8h_ClmvAT1wvmhEg6lcQZi4y5nQBDFtjp5Xc8aSPQ1d_Gzr4jPlw6R6Mh2t9Rmm2BQsim7mcgUzDhWSkberqA9QoA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsIm1ldGFnZW5lcmF0aW9uIjoiNCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo1My41NjFaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NTYuMTI2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjUzLjU2MVoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTA5MzU2MTYwNCZhbHQ9bWVkaWEiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSVNDME9pVzI5MENFQVE9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSVNDME9pVzI5MENFQVE9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFRPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA5MzU2MTYwNCIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBUT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibW5HN1RBPT0iLCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFRPSJ9" + } + }, + { + "ID": "fdf00574ab80e155", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "85" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "8d2a0740d223b423b497bc4917e09558/15230784440717199858;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiJ9Cg==" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "13123" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:56 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrbj128:4260,/bns/yv/borg/yv/bns/blobstore2/bitpusher/266.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=GMysW8aBD5CcNsOPmzA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/266.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/266:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqbgqQTG9YR1fSqJ3ZOa8nTDVoLdEfeP_eYQL1M9VymnALeOi2fekzhEIS0D2KbKg0S1c0AE1i0UoUcDhzaysqUcZcVaA" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6MzM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuVXBkYXRlQW5kUGF0Y2hPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFuZFBhdGNoT2JqZWN0LmphdmE6NTIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnVwZGF0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTA2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5VcGRhdGVBbmRQYXRjaE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQW5kUGF0Y2hPYmplY3QuamF2YTozMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5VcGRhdGVBbmRQYXRjaE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQW5kUGF0Y2hPYmplY3QuamF2YTo1Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IudXBkYXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMDYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5VcGRhdGVBbmRQYXRjaE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQW5kUGF0Y2hPYmplY3QuamF2YTozMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5VcGRhdGVBbmRQYXRjaE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQW5kUGF0Y2hPYmplY3QuamF2YTo1Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IudXBkYXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMDYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlVwZGF0ZUFuZFBhdGNoT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBbmRQYXRjaE9iamVjdC5qYXZhOjMzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlVwZGF0ZUFuZFBhdGNoT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBbmRQYXRjaE9iamVjdC5qYXZhOjUyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci51cGRhdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEwNilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" + } + }, + { + "ID": "733f05aa99a1b338", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "7439171b6a0e81d123cfb2ed26494232/16821196344784350865;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "377" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:57 GMT" + ], + "Etag": [ + "CAM=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrm69:4161,/bns/yr/borg/yr/bns/blobstore2/bitpusher/88.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=GMysW6ewGpLM4QSw77fYDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/88.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/88:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoG9K7qu7HNcJwAGEehEQ7PUq-KVQmO_y1KTGmEbkmtpzFkaLuby68m1a_c81S2oFw1zwOVQ2XyO6zIEyfnUccAQNv2oA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQU09In0=" + } + }, + { + "ID": "2a8d19324f3c9a1b", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1012d9e9a711e5d8ac2dfaae707d9658/18411325674363229232;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "377" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:58 GMT" + ], + "Etag": [ + "CAM=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrhq15:4330,/bns/yr/borg/yr/bns/blobstore2/bitpusher/66.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=GsysW_uuAYj8kAPe152IBg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/66.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/66:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UruXPkBA8n56dNnA2rFK5H30i18sXuEkReZ5SWOkW0lzsEVNDxsFREolod7ciOW26miWa0UTbY1kmC930gm5bLHNzxb-A" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQU09In0=" + } + }, + { + "ID": "a94b33412193c147", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3a2fbf6422f153a7d7cb3057fd94190d/1555274979697605070;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "13131" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:58 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrru15:4107,/bns/yw/borg/yw/bns/blobstore2/bitpusher/57.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=GsysW8q9GZLLhATvipagBg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/57.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/57:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrOao8jJ1teh9dHDWUI-K-002Cucy8JK26kUqzzX2lLUno91zLpC5q-rHAJh4WsGcxLelf_fw9-EY14Ojls4JjYzY71SQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRCdWNrZXQoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo3Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YToxNilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLnVwZGF0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjE2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IudXBkYXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" + } + }, + { + "ID": "d84fb6a7fe4c8fad", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "81a103413c23ff6cf6de52c36bbf5f9a/3145686883747979117;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "377" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:58 GMT" + ], + "Etag": [ + "CAM=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vru185:4374,/bns/yv/borg/yv/bns/blobstore2/bitpusher/273.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=GsysW8LPJ5CgNoeNtLgB" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/273.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/273:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpDBLUF8C0Y8OC3VIC_pa2-kudAgnEbLAaOCeCCraNcDIKCBS3elQhDKmQpnUPnIgJxUysgDOZc2NNdT2EYaUdRumPFig" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQU09In0=" + } + }, + { + "ID": "223d5c2655c135ad", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "a2acc7d03c2bb940dcf519dcff4d5ef8/4735817312838485004;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "13987" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:58 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vreu27:4180,/bns/yv/borg/yv/bns/blobstore2/bitpusher/323.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=GsysW8mRLZXYgQTfuLnICg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/323.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/323:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrYarqP1zBRQ0XDrYASRc0_1B57L8sj9h2pl4o_doKHgHbXjF3neb2cqJU3Rkjs8fPNt0lJz_oqqlN2oiieVgExrvyHxA" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjE2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IudXBkYXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRCdWNrZXQoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo3Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YToxNilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLnVwZGF0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" + } + }, + { + "ID": "fd2973ecddb39533", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "684a595153fa158043719a1da2804263/6326229216888924842;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2358" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:59 GMT" + ], + "Etag": [ + "CAM=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:59 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrw127:4318,/bns/yv/borg/yv/bns/blobstore2/bitpusher/374.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=GsysW7bJOI3yggSq27_4CQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/374.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/374:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrQx-txpbMl8OqvGmdlxHHfAZg3zsAgfwVcRJG2cKduZ2fIHtPj9qC9G80sPT15MxGu97kkUtzdWLrv9KOcVWR-Q8LPGA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9kb21haW4tZ29vZ2xlLmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBTT0ifV19" + } + }, + { + "ID": "e12f623c305cecb4", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4f93cb578b023a363759bb2cf52452d7/7916640021461225289;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2358" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:59 GMT" + ], + "Etag": [ + "CAM=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:59 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrgm3:4392,/bns/yr/borg/yr/bns/blobstore2/bitpusher/68.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=G8ysW-GCD4-FkATrn62QAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/68.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/68:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uqm3U3bqQ3x6UMYoVpEZxvM0-E1gmInWQXEj9VeCg4Bwv6SPEjSsnR1OCjqVhJoRCs3b_cghZ_Y7i8c_0ZsR-kcE4X_tjx1ucHO5cJrkZs9XL1xglo" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9kb21haW4tZ29vZ2xlLmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBTT0ifV19" + } + }, + { + "ID": "ad0ba2871af45600", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "c9dff7f46b3df0aa1bbccf636668360a/9507051921216763367;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13087" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:59 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:59 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrnc2:4232,/bns/yw/borg/yw/bns/blobstore2/bitpusher/132.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=G8ysW9WlIdXDhgSTua7ADg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/132.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/132:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpVPdoAQNx8mY5oiRnxgWk2nkKFdrVTTRq29jCQvw3554R8GGx0yM4GUdPkPYoKGeP3BSqNKhpYLO9kbLMih062cmL5fA" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YTo4NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjIwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAwLCJtZXNzYWdlIjoiQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiJ9fQ==" + } + }, + { + "ID": "fbc79d3e312230b2", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "6aa77ecbf8f3d32317e07bd499079dc0/11025125860075870854;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2358" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:24:59 GMT" + ], + "Etag": [ + "CAM=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:24:59 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrbo128:4296,/bns/yv/borg/yv/bns/blobstore2/bitpusher/384.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=G8ysW73lLNiiggSxqYa4Dw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/384.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/384:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Urb__NQ3g47uGEfOrLr43toLu4FlQw7kkLcnl-COQ--VPh4esMxEf4Sesu6sfGKnw5u8WTCQzQ0j3mgfoeReN5DW1PhlQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsImVudGl0eSI6InVzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9kb21haW4tZ29vZ2xlLmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBTT0ifV19" + } + }, + { + "ID": "8ff0e0d3db0c20a4", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "bdc8a5e50646d0f066f3d3c96d71c25e/12615537764126244901;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13943" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:00 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:00 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrmm19:4379,/bns/yr/borg/yr/bns/blobstore2/bitpusher/52.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=G8ysW-XWMYT7kAOk1pngDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/52.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/52:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up4dLfyWyLDoGO56z8m9cKIZ3k2wRD5rnKGG7y--EG92D6uEWqzCq--42QVg9CHbcNtTAYUb4Qif8m7V5O-8s5jW9v63A" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRCdWNrZXQoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo3Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjg1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRCdWNrZXQoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo3Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjg1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAzLCJtZXNzYWdlIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS4ifX0=" + } + }, + { + "ID": "a482ab45717781c9", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3e8fda45931e40ef507c08cfe5a4d675/14205949668193461699;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:01 GMT" + ], + "Etag": [ + "CAQ=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdv10:4196,/bns/yr/borg/yr/bns/blobstore2/bitpusher/13.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=HMysW7nnAc7xkAPuvp3IAg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/13.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/13:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uqq7-AXWbJ0OfAwZWNX54cXmSHu9KZetg5qN7jzZYUwihM1Q9OZ-NssVvQwAjUhAUaOA2FZ2gFK919FB3RX8_XohAQlqA" + ] + }, + "Body": "" + } + }, + { + "ID": "8d610a271816662c", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "8616123ddfd273b957e5fab502ff479b/15796360468454083426;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "2911" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:01 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:01 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051389000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vngv135:4098,/bns/yw/borg/yw/bns/blobstore2/bitpusher/222.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=HcysW7PZLIXohQTO7ZzgCw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/222.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/222:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoshQyC_SknxM5jDHjC2fHZEznd9i3BMQptowju6Ij-NvIoJet5fCn7gQBeLpZJPvyjGLrRfJcYdpM9aQPkSHmfDylkTw" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1udWxsLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9bnVsbCwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5zY29wZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLnNjb3BlLCBtZXNzYWdlPU5vdCBGb3VuZCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm90IEZvdW5kXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwNCwibWVzc2FnZSI6Ik5vdCBGb3VuZCJ9fQ==" + } + }, + { + "ID": "da83794caa4cf088", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "16b54007f6478160a8f0ca7d0ea6dfb9/17386490901839491073;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13131" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:02 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:02 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrpa10:4240,/bns/yr/borg/yr/bns/blobstore2/bitpusher/102.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=HsysW8V0zfXhBJuDq9AG" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/102.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/102:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrqtMgL_uL-y75dcnPJSXmWL_i3QakTUsacyGhn2Jerx2hBwWeSxAvHsILqt9BUkmRDPBgnR-FgNxtaPpBH_4UIYWajlQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRCdWNrZXQoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo3Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjcxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjIwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" + } + }, + { + "ID": "d8dfe5f8f7f4842e", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0885ca0712dc00c110d60f29bae6a524/530440207157089951;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "2911" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:02 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:02 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051402000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vns199:4031,/bns/yx/borg/yx/bns/blobstore2/bitpusher/12.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=HsysW-eWDsjSzwKA9KbAAg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/12.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/12:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq6oz_XgowJEUjm6QcOHJUWfE1d-fqMb-vVQ9PhPGZ45k5NfaDFpeb0lbznhh-rs-Xl114pu9dF2UJ-zMDkvp8HpggrgQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1udWxsLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9bnVsbCwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5zY29wZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLnNjb3BlLCBtZXNzYWdlPU5vdCBGb3VuZCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm90IEZvdW5kXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwNCwibWVzc2FnZSI6Ik5vdCBGb3VuZCJ9fQ==" + } + }, + { + "ID": "774de9a795d77c1a", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e3c01d1072ccb8ae60f233fe68026958/2120852106929339198;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13987" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:02 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:02 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051402000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vnay63:4225,/bns/yx/borg/yx/bns/blobstore2/bitpusher/71.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=HsysW63YF9KWzALm4bbIAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/71.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/71:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq2nRMSlpzIEyWLHepcu3uZTN0ze61Pgp76Y_QcFtaTBw6XipXJDnMwGvyMr2CctSdUs_T2O78pfbHqJWhG44EGgQQzSg" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjcxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjIwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRCdWNrZXQoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo3Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" + } + }, + { + "ID": "ab058975d1817bd7", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "10c17f347603960c73c3c64e530e12f5/3710982540297970141;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "119" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:04 GMT" + ], + "Etag": [ + "CAU=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051389000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vngv21:4425,/bns/yx/borg/yx/bns/blobstore2/bitpusher/24.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=HsysW6CSJ5DkzgKJ5ryQBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/24.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/24:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoBF56ICh2ijLjfqU1iq3_fIrTTjexZ2BBn2PaVwVYeg4B5mIEJ7T0U2dnfeafp2dDc2KWpY2mnIvyGKqOYWZhbLoVymA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQVU9In0=" + } + }, + { + "ID": "f1fcc196e93e6463", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "db1ff6db6ea98613c69f1676559359ef/5301393344870336123;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "119" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:04 GMT" + ], + "Etag": [ + "CAU=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrcw65:4312,/bns/yr/borg/yr/bns/blobstore2/bitpusher/59.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=IMysW4eNFMuLkATz_I_4CQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/59.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/59:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up43Er14jJ287pQViDVRcpFGGZdP0AxcfJ5uR5znBju0lUN0PpfVd170bFXkNJtysbjPOiQ7ogsM9889HB7QTnl8S-ijg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQVU9In0=" + } + }, + { + "ID": "e3ff4129f99086aa", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1a701ecf80451edb1613f5c17144086b/6891805244625808410;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "13131" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:04 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrs123:4010,/bns/yr/borg/yr/bns/blobstore2/bitpusher/31.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=IMysW7rFJci84QSQ-ZF4" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/31.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/31:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UppIr8QoNk9y3W_-3bxKLmujYEgzMdEaN4VVg5rK-gtx1kEwLnh4qW-opHhL80TrnuyGBMpA11rTr2vHaE97_4WXOZDKA" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRCdWNrZXQoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo3Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YToxNilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLnVwZGF0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjE2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IudXBkYXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" + } + }, + { + "ID": "fd3d4b6eabba272c", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "6d2983fb613e0d14f1016b3156d1f2c0/8482217148692959673;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "119" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:04 GMT" + ], + "Etag": [ + "CAU=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051402000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vnnl21:4346,/bns/yx/borg/yx/bns/blobstore2/bitpusher/166.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=IMysW-rKMsHWzALm5oewDg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/166.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/166:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpaVesITKhatH2M-FF0nr35PGOmXxdEH2KkpMDZQSj-VyYNi7b4ZCw0_0iVK1Ss5Tk-1YLPbW-N87O94cay4CR2tc15ww" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDQVU9In0=" + } + }, + { + "ID": "6cef2d0fe616a1cb", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "41470592c6b358127c9e6adb19653c80/10072347582061655895;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "13987" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:05 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051402000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vnss23:4187,/bns/yw/borg/yw/bns/blobstore2/bitpusher/119.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=IMysW_vNOND4hASGt7eoDQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/119.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/119:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpJk7sPAiyUYXHIX3b7pUdx9Tbz4oUoggFEX6PGqfqD8OFLdIoKUyPLIjsSqkc_W8s7BaWLDxprHLNVZvlrdNRi8dL25Q" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjE2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IudXBkYXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRCdWNrZXQoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo3Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YToxNilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLnVwZGF0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" + } + }, + { + "ID": "bb9370a582ea35c1", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "8d13bbf15b8d9e35da61ec13ef0e93b3/11662759486128807158;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "678" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:05 GMT" + ], + "Etag": [ + "CAU=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:05 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrb20:4129,/bns/yw/borg/yw/bns/blobstore2/bitpusher/92.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=IcysW9-gCI6ihgSxjr6wDQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/92.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/92:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrZmpWXIqiS9e6JgaqJiMGL30-HJaSgAUfANzdlVtP-GiI--njgNt8qDy-LT1yu47R5C_f0X4ArHWNC-OXuizlu2OoNHg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBVT0ifV19" + } + }, + { + "ID": "24b48182f16f05b6", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3bf956ba1efb5a77c3b978c0abf5a331/13253170286389428885;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "678" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:05 GMT" + ], + "Etag": [ + "CAU=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:05 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051389000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnr74:4261,/bns/yx/borg/yx/bns/blobstore2/bitpusher/53.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=IcysW6CoGYKLzgKstYqwBg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/53.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/53:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UonBZeDWAS_5Xu3_JmgDldw4OBggGFhY08awH4tPbbcjtN2P0YNvAPPRM1Yx9HlZU8iEgUbR7QkE3xFzZaP3Yosb8LYPA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBVT0ifV19" + } + }, + { + "ID": "ce844c26f10c0e3b", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d5c7b6eaaa27d2b42f81b33c9de5cedc/14843582190456645427;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13087" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:06 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:06 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrcb130:4200,/bns/yv/borg/yv/bns/blobstore2/bitpusher/26.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=IcysW4DtMZPMgwTatbbQAg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/26.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/26:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UotQ-yZb_9zj9TYZYqpQNrytARZW-m2uHS9_ifyhpLIvSqktqIJboultvlXy8j4pdBnvnmfWDDNoyeewfOgLC9XJAOckg" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YTo4NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjIwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAwLCJtZXNzYWdlIjoiQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiJ9fQ==" + } + }, + { + "ID": "ff92114e4faebe3b", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "06faed11abba0b027858e49c6ddf6a29/16361656129315753170;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "678" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:06 GMT" + ], + "Etag": [ + "CAU=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:06 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrbd63:4301,/bns/yr/borg/yr/bns/blobstore2/bitpusher/21.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=IsysW5DQAc-M4QTB1K2YAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/21.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/21:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq9Kb4Jr0nsQHMgXynyXRsWFwmHcVDFVL1weQDJIiWnadnHl4wU7pIGAbTmZ7GL9YeHKX4nLJL8GPuTkz3DQSh-z9WXfw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNBVT0ifV19" + } + }, + { + "ID": "7f3358fa545fcd20", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4d8caf7f58e94fb261d8a3d56590928b/17952068029071290992;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13943" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:06 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:06 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrwa10:4354,/bns/yv/borg/yv/bns/blobstore2/bitpusher/182.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=IsysW42tBtWFgQSM1K-oDQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/182.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/182:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrpCrljVA9hmFfcCUZ6ginYuMdaH-ak_I_6bNEq0ajgeC9v9yvTUmHRt5JF9futhNCB1d2AgmMOvfvjrT0q38ONS_dGhojwkaJq1TthxI2Q3GFSu_M" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRCdWNrZXQoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo3Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjg1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRCdWNrZXQoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo3Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjg1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAzLCJtZXNzYWdlIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS4ifX0=" + } + }, + { + "ID": "4e0072677d6e9243", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1410259a9e5a5a3240d8b80567abc4dd/1096017334405601039;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:07 GMT" + ], + "Etag": [ + "CAY=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vris74:4141,/bns/yr/borg/yr/bns/blobstore2/bitpusher/87.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=IsysW_CqFMmu4QTjqoH4BQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/87.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/87:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqcfHghFeLYicAx1xZoOFYz9sF8hHTKLCp36QA9xhiJZ2VRR0CNnO0sZ9owfC8KLGPOVfAfuS8ZxhUTIwxoV96BHRwAcg" + ] + }, + "Body": "" + } + }, + { + "ID": "bdca30b60af963e6", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "6227da00c3d57bbb80499c2419e84418/2686146668279381422;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "2911" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:08 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:08 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrqv16:4123,/bns/yr/borg/yr/bns/blobstore2/bitpusher/16.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JMysW7ZCw_WQA6PVsMAN" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/16.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/16:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Urb2qaGQHZsAxqnNJP3mvqPEQOiw0ZQHSCAgKtSJqPZoEKN8Wz2vXlUt2zQH0okIVgs0A2_XxWrSvUf6p4YiN9wc3fv5g" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1udWxsLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9bnVsbCwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5zY29wZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLnNjb3BlLCBtZXNzYWdlPU5vdCBGb3VuZCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm90IEZvdW5kXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwNCwibWVzc2FnZSI6Ik5vdCBGb3VuZCJ9fQ==" + } + }, + { + "ID": "9452e5677cd8763e", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "70a998644dfcd91da217e42b1d7b2d2e/4276558568051696204;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13131" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:08 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:08 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrls9:4235,/bns/yv/borg/yv/bns/blobstore2/bitpusher/272.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JMysW5CsE4WYNtLmguAE" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/272.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/272:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoS5A_Ur5pecY5WkXvVZ-WyFRTYSKqumzpHMDRUS9GQU_9lswTJztBB3jyIuq6dqAIGQlJi3ZvEGCcbumiiyxDu31QPAg" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRCdWNrZXQoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo3Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjcxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjIwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" + } + }, + { + "ID": "69453ac394695e48", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "40295f9b87f0f18ad0e9ff0e6fb99330/5866970472102070507;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "2911" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:08 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:08 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrbh67:4361,/bns/yv/borg/yv/bns/blobstore2/bitpusher/259.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JMysW-aOIMmngASFkp7wAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/259.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/259:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoAIy7VG2gOhNoHOLq09jywLkL6GqJBFh12dcwNvIYHlc2RjT6csXgnyyOlgOpUEd0DmFu84oEVta-tKvkj4fhR_E255A" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1udWxsLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9bnVsbCwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5zY29wZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLnNjb3BlLCBtZXNzYWdlPU5vdCBGb3VuZCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm90IEZvdW5kXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwNCwibWVzc2FnZSI6Ik5vdCBGb3VuZCJ9fQ==" + } + }, + { + "ID": "4e81fa1d549dd7d1", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e7961ff53ec44511ed91686f7343d103/7457382376169221514;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/defaultObjectAcl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13987" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:08 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:08 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrng11:4017,/bns/yr/borg/yr/bns/blobstore2/bitpusher/34.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JMysW_6AJ8GlkATKoZr4CA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/34.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/34:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqqFd_29T2_H_95CurwBBNSdJkTcPsStuCJ-y30twVICigUMCZDDGuZQzqiDSF_N8EH0diT0_WkrCovZ_LDkaDH_YKmQg" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZEJ1Y2tldChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjczKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjcxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjIwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkQnVja2V0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRCdWNrZXQoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo3Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" + } + }, + { + "ID": "7df91939b16a2c81", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b2716cf9b5aa6106b6d3d84e155dd3a6/9047512809537917736;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "463" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:09 GMT" + ], + "Etag": [ + "CISC0OiW290CEAU=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbr88:4353,/bns/yv/borg/yv/bns/blobstore2/bitpusher/193.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JMysW5r_ONOSgwS845_ACg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/193.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/193:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur9ztnAX_J_zFeQE4_hRnQ7btIzyA7VxKK0HAhiVm2EEWBKqUlImVx8tuF0RV3DtIeQ1c3_TZsw25NUDRWcGqPLxRIw4Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBVT0ifQ==" + } + }, + { + "ID": "7d4b183a11bce139", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ed4c07520b33a6edeccca7e43cbd2b59/10637923609815316679;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "463" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:09 GMT" + ], + "Etag": [ + "CISC0OiW290CEAU=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrta22:4161,/bns/yv/borg/yv/bns/blobstore2/bitpusher/372.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JcysW6yZDcflgQSplIvgBw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/372.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/372:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpJrq84lbv5EUPgf6THcIVagDI8PK2rgrYCRntGvroWRZvZ3SfUfd2sHPmkck7SuQlCffNYbH0k97QCysZK0do7CzwK8A" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBVT0ifQ==" + } + }, + { + "ID": "830be57d8d5b034e", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "47beea259ddd2b4ce2f3abd8d7dc99bc/12228335513865690726;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "13131" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:09 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrti20:4165,/bns/yw/borg/yw/bns/blobstore2/bitpusher/44.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JcysW_mJEte8hgSCg6LoCA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/44.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/44:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpdIdGeWvzEPEhxanvKVaOS9s30-Ks08qtwPfKpcUgEvujPfnyww57z0FCERZ2_qwzT68OwihUV926Vyq4Kb4frc6nuCA" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkT2JqZWN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzMxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkT2JqZWN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzMxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRPYmplY3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YToxNilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLnVwZGF0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZE9iamVjdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMzMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjE2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IudXBkYXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" + } + }, + { + "ID": "a813a7a74b51212b", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e31f23b0bbd0536807020a4116896372/13818465947251163908;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "463" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:09 GMT" + ], + "Etag": [ + "CISC0OiW290CEAU=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrkx5:4004,/bns/yv/borg/yv/bns/blobstore2/bitpusher/210.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JcysW9OaIJLWgwSI4rWoBg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/210.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/210:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UparWf6waxsZzPSiInxkNT-tYiY9T7YcRChH9lHB29YNw_LvBYyQN5RVNVa0PA3tEd31Har-YzV8SG9c216FVNesZYb7Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL2RvbWFpbi1nb29nbGUuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBVT0ifQ==" + } + }, + { + "ID": "876de65442e97d90", + "Request": { + "Method": "PUT", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "107" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "92b1d8b4d4646c948ae20f5d76daeddc/15408877847006636451;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIifQo=" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "13987" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:09 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrga66:4480,/bns/yw/borg/yw/bns/blobstore2/bitpusher/129.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JcysW7yZJcLYN-_yv-gJ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/129.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/129:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpzYeinxYvUcF89GNgxzHiwRGzRSiOPh8lXsF8Ui7yYuzaYzTYa1sdbSYFYW0mg6VMgQO1a8jcG50JRjKPSkwXB5S1zPg" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZE9iamVjdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMzMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuVXBkYXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQWNscy5qYXZhOjE2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IudXBkYXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkT2JqZWN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzMxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkT2JqZWN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzMxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5VcGRhdGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVBY2xzLmphdmE6MTYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci51cGRhdGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRPYmplY3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLlVwZGF0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUFjbHMuamF2YToxNilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLnVwZGF0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" + } + }, + { + "ID": "e99d5454df27e734", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "7f483e09cc86f574831ee0421c35e5fa/16999289751073787458;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2788" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:09 GMT" + ], + "Etag": [ + "CISC0OiW290CEAU=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:09 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051389000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnfw23:4201,/bns/yx/borg/yx/bns/blobstore2/bitpusher/9.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JcysW4XqM4aHzgLkspKIAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/9.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/9:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqFw4JZAQYCIoQGiC7YzARGdUVRclLSastcA-IAYPl1bPk7zoXPFij4lSO9h4-TbRz8X60Ra30Z25QAmogMkZrnIrI_3Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSVNDME9pVzI5MENFQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoidXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFVPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC9kb21haW4tZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDSVNDME9pVzI5MENFQVU9In1dfQ==" + } + }, + { + "ID": "bbbff1cdd72a26e1", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "bd9b2393642462b5c8bdce455c561af9/143237956896535776;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2788" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:10 GMT" + ], + "Etag": [ + "CISC0OiW290CEAU=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:10 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrnn4:4418,/bns/yr/borg/yr/bns/blobstore2/bitpusher/46.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JcysW9fdOcnF4QTguLLQCg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/46.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/46:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up-qKjKEvLs8mhoIBZjn644PJsEbock0wyZqP8NEPka0nZsHh6rwl__6LRjjPXz7RjZQvSOgYhfyoOpQfeCDnqWNMLS5hFmmPaEnzetwARYdsDJSsM" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSVNDME9pVzI5MENFQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoidXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFVPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC9kb21haW4tZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDSVNDME9pVzI5MENFQVU9In1dfQ==" + } + }, + { + "ID": "fb158f6c638e4fd6", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "178ed4ffd76e625ae8bdeebf4cdf500c/1661311895755643263;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13087" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:10 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:10 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrsq4:4180,/bns/yr/borg/yr/bns/blobstore2/bitpusher/109.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JsysW4fJAc2TkATewpPoBg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/109.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/109:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrLqMkF52b9YI5CWStirR3Vx8PSHOZLqsWPvlYejebN9HGI6BlPhip2U0WLxvWfEETUtnYyqKPjq5X8CxS83-22QWB9LA" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkT2JqZWN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzMxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YTo4NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjIwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IubGlzdChBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPVJFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZE9iamVjdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMzMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1iYWRSZXF1ZXN0LCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZE9iamVjdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMzMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZE9iamVjdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMzMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAwLCJtZXNzYWdlIjoiQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiJ9fQ==" + } + }, + { + "ID": "693609fc63a880a4", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "8b22dec014f63a2e09a65e7c874c6748/3251723795511181085;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2788" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:10 GMT" + ], + "Etag": [ + "CISC0OiW290CEAU=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:10 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051402000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vndz193:4319,/bns/yx/borg/yx/bns/blobstore2/bitpusher/140.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JsysW_aKD4aPzgLKg4SoDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/140.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/140:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrCrxz4Y9yMZaxH9kPNeKc4g8xHIDxwP8VRABr_owQG37mhGZmX6zaxL6F7NumpXRxx1PcDxTqpZOs883WeJaV6OOphiQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9scyIsIml0ZW1zIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwOTM1NjE2MDQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNJU0MwT2lXMjkwQ0VBVT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTA5MzU2MTYwNC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9mb28vYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSVNDME9pVzI5MENFQVU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvZm9vLzE1MzgwNTEwOTM1NjE2MDQvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvdXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoidXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0lTQzBPaVcyOTBDRUFVPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMDkzNTYxNjA0L2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC9kb21haW4tZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm9iamVjdCI6ImZvbyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDkzNTYxNjA0IiwiZW50aXR5IjoiZG9tYWluLWdvb2dsZS5jb20iLCJyb2xlIjoiUkVBREVSIiwiZG9tYWluIjoiZ29vZ2xlLmNvbSIsImV0YWciOiJDSVNDME9pVzI5MENFQVU9In1dfQ==" + } + }, + { + "ID": "49029dea88229164", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3c62f541a3ae01cd6be129967cac3585/4842135699578332348;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13943" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:10 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:10 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrlj28:4249,/bns/yr/borg/yr/bns/blobstore2/bitpusher/9.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JsysW4HPE7Lm4QS0iZ9I" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/9.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/9:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpZ4wlQKc6jj-9k6xSk9TQKMTHvk4TESMFYPNCoKiuH4Al89gLex9FpSev5P7meDHYF63-FRR9ZZMcy1rSFyfh9JtVEEw" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZE9iamVjdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMzMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZE9iamVjdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMzMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6ODUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5MaXN0QWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdEFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmxpc3QoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRPYmplY3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjg1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRPYmplY3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkxpc3RBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0QWNscy5qYXZhOjg1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuTGlzdEFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5saXN0KEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAzLCJtZXNzYWdlIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS4ifX0=" + } + }, + { + "ID": "0bbffc509aa58e86", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9d5b4009a62181db92bb7fa0d649ded2/6432547603628706395;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:10 GMT" + ], + "Etag": [ + "CISC0OiW290CEAY=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrmt5:4328,/bns/yr/borg/yr/bns/blobstore2/bitpusher/18.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JsysW8_mH86x4QTpi5mYDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/18.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/18:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrkIesSXHaDQvjErkm-acBua1UtOmcpvV-fYBGu2-zEFeRu3-06b0Edan4rTIQdT4ALc5dtMnMvRz-wsO5y-DT2jHEHjQ" + ] + }, + "Body": "" + } + }, + { + "ID": "288d5c2ae22a0cf0", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "942e217b3d85e1854cbd33d54d01cda3/8022676933224427513;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "2911" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:10 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:10 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrjy17:4329,/bns/yw/borg/yw/bns/blobstore2/bitpusher/67.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JsysW9mwM9jdhATbvJjQBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/67.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/67:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpwCfg1tfuHO6z9s2bgjLvSiNnbc_vMT2qmOOj1c4I0DhiJ46RI6sySBd8gte-AwJBFOhANbtvKXuz1Bq6S18z47aPrFA" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1udWxsLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9bnVsbCwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5zY29wZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLnNjb3BlLCBtZXNzYWdlPU5vdCBGb3VuZCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm90IEZvdW5kXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwNCwibWVzc2FnZSI6Ik5vdCBGb3VuZCJ9fQ==" + } + }, + { + "ID": "096f174db397deb0", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1a6d483de945e889227f26e82c9b2130/9613088837274801560;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13131" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:11 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:11 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrjo80:4463,/bns/yv/borg/yv/bns/blobstore2/bitpusher/165.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=JsysW6auOo2MNtHGrBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/165.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/165:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqoWzqmrIL9nx-7PA1ttiQoj5BezEBJr40Xc0d0FypqBUUG9UeaFFFGk4g_mlpFryQTNJZBHRgLlrVJuvQzW9cb-AMBxA" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkT2JqZWN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzMxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkT2JqZWN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzMxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRPYmplY3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZE9iamVjdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMzMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjcxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjIwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" + } + }, + { + "ID": "9a6144618da834c7", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9b4ccb516b0ed7601e591296cf1453ba/11203500741341952567;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "2911" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:11 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:11 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051395000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrhq4:4312,/bns/yv/borg/yv/bns/blobstore2/bitpusher/111.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=J8ysW6HbB8-cgQS1rZiIAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/111.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/111:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpLOFQ92MklcwxjQqPryjDyxnQlsUd23ini1iIR7nX2UvjxF_jcqx_zsF7NG8QzDitrsVr_W2-wuJsTeHCRk6ZDMjBaDQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1udWxsLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9bnVsbCwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5zY29wZSwgbWVzc2FnZT1udWxsLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLnNjb3BlLCBtZXNzYWdlPU5vdCBGb3VuZCwgcmVhc29uPW5vdEZvdW5kLCBycGNDb2RlPTQwNH0gTm90IEZvdW5kXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwNCwibWVzc2FnZSI6Ik5vdCBGb3VuZCJ9fQ==" + } + }, + { + "ID": "c52b7f33ca3920d5", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "f0700b25c7e12a6b9dec52fbd6091dee/12793631170432524245;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/acl/domain-google.com?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13987" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:11 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:11 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051402000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vnlu1:4025,/bns/yx/borg/yx/bns/blobstore2/bitpusher/90.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=J8ysW97FDMTnzAKpnrCABg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/90.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/90:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATo_ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrmFjyyAPppeAl4NIJZEu0UFkt54qMbRjRWm_O014wmEJVzEZVPqDwfNrVFaKI6Xx_ULf38vu9EUup85Ce8EcuZeMkDIQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIubG9hZE9iamVjdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjMzMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmdldEFjbFJlc291cmNlRm9yUmVxdWVzdChBY2Nlc3NDb250cm9sc0hlbHBlci5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjcxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuRGVsZXRlQWNscy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQWNscy5qYXZhOjIwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuZGVsZXRlKEFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTkgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkT2JqZWN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzMxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5sb2FkT2JqZWN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6MzMxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmFjbHMuQWNjZXNzQ29udHJvbHNIZWxwZXIuZ2V0QWNsUmVzb3VyY2VGb3JSZXF1ZXN0KEFjY2Vzc0NvbnRyb2xzSGVscGVyLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5EZWxldGVBY2xzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVBY2xzLmphdmE6MjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5BY2Nlc3NDb250cm9sc0RlbGVnYXRvci5kZWxldGUoQWNjZXNzQ29udHJvbHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOSBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkFjY2Vzc0NvbnRyb2xzSGVscGVyLmxvYWRPYmplY3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTozMzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYWNscy5BY2Nlc3NDb250cm9sc0hlbHBlci5nZXRBY2xSZXNvdXJjZUZvclJlcXVlc3QoQWNjZXNzQ29udHJvbHNIZWxwZXIuamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5hY2xzLkRlbGV0ZUFjbHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUFjbHMuamF2YToyMClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkFjY2Vzc0NvbnRyb2xzRGVsZWdhdG9yLmRlbGV0ZShBY2Nlc3NDb250cm9sc0RlbGVnYXRvci5qYXZhOjEwOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE5IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" + } + }, + { + "ID": "35caaa1961758473", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/rewriteTo/b/go-integration-test-20180927-44630911863640-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9d039fe48c3d6d31e978c142d65f7278/14384043074482898292;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/rewriteTo/b/go-integration-test-20180927-44630911863640-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3366" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051411000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnaz77:4273,/bns/yx/borg/yx/bns/blobstore2/bitpusher/128.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=J8ysW9jcGoGKzQKK-Yv4CQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/128.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/128:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoLVz1xVnB7DeGhm_uQ-fvJJcGqAvxf9eVPqr9nZ6F2T2v7hQViOoF6MMD9KhOv1w9uev9CbEiD5z80sBjc1OEbaTgsQA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiNSIsIm9iamVjdFNpemUiOiI1IiwiZG9uZSI6dHJ1ZSwicmVzb3VyY2UiOnsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvY29weS8xNTM4MDUxMTExOTM1MzgxIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29weSIsIm5hbWUiOiJjb3B5IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTE5MzUzODEiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MTEuOTM0WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjExLjkzNFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNToxMS45MzRaIiwic2l6ZSI6IjUiLCJtZDVIYXNoIjoiWFVGQUtyeExLbmE1Y1oyUkVCZkZrZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2NvcHk/Z2VuZXJhdGlvbj0xNTM4MDUxMTExOTM1MzgxJmFsdD1tZWRpYSIsImNvbnRlbnRMYW5ndWFnZSI6ImVuIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvY29weS8xNTM4MDUxMTExOTM1MzgxL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29weS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJjb3B5IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTE5MzUzODEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKVzdzZkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9jb3B5LzE1MzgwNTExMTE5MzUzODEvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29weS9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTExOTM1MzgxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNKVzdzZkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9jb3B5LzE1MzgwNTExMTE5MzUzODEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29weS9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTExOTM1MzgxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSlc3c2ZHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvY29weS8xNTM4MDUxMTExOTM1MzgxL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9jb3B5L2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTExOTM1MzgxIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0pXN3NmR1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJtbkc3VEE9PSIsImV0YWciOiJDSlc3c2ZHVzI5MENFQUU9In19" + } + }, + { + "ID": "0fd88baa3033f493", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/rewriteTo/b/go-integration-test-20180927-44630911863640-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "09f1f12c42b7c8149240acb13b43935d/15974453879055198739;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/rewriteTo/b/go-integration-test-20180927-44630911863640-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3366" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051412000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vro189:4159,/bns/yr/borg/yr/bns/blobstore2/bitpusher/3.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=KMysW7WoBIPTkAOc94W4BQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/3.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/3:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq0ghIYIN0eHwuJHKVrDV7rhoHUiSGfwYvCq0Tbab-5NbHWPI_zlvjPKSpYTTnU2-LwWmJCJQdTXOYEEVFoNsjHCHLdTQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiNSIsIm9iamVjdFNpemUiOiI1IiwiZG9uZSI6dHJ1ZSwicmVzb3VyY2UiOnsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvY29weS8xNTM4MDUxMTEyNTM1MTQyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29weSIsIm5hbWUiOiJjb3B5IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTI1MzUxNDIiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MTIuNTMzWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjEyLjUzM1oiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNToxMi41MzNaIiwic2l6ZSI6IjUiLCJtZDVIYXNoIjoiWFVGQUtyeExLbmE1Y1oyUkVCZkZrZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2NvcHk/Z2VuZXJhdGlvbj0xNTM4MDUxMTEyNTM1MTQyJmFsdD1tZWRpYSIsImNvbnRlbnRMYW5ndWFnZSI6ImVuIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvY29weS8xNTM4MDUxMTEyNTM1MTQyL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29weS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJjb3B5IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTI1MzUxNDIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNPYUkxdkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9jb3B5LzE1MzgwNTExMTI1MzUxNDIvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29weS9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTEyNTM1MTQyIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNPYUkxdkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9jb3B5LzE1MzgwNTExMTI1MzUxNDIvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29weS9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTEyNTM1MTQyIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDT2FJMXZHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvY29weS8xNTM4MDUxMTEyNTM1MTQyL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9jb3B5L2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTEyNTM1MTQyIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09hSTF2R1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJtbkc3VEE9PSIsImV0YWciOiJDT2FJMXZHVzI5MENFQUU9In19" + } + }, + { + "ID": "53fbb33131b2c479", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/rewriteTo/b/go-integration-test-20180927-44630911863640-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "82868f26ec5b6e299b4474b2cfae6959/17564865783105638577;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/rewriteTo/b/go-integration-test-20180927-44630911863640-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "13391" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:12 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051412000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrbd126:4463,/bns/yr/borg/yr/bns/blobstore2/bitpusher/6.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=KMysW8GPKITi4QTTsIOoBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/6.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/6:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpCChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur-3PRMrpJH_qpKJfXYAc9NIi9qSUo9fN7ClGHRFbFLuUxvgBIf6Igeo-jEzfIDVBbyTmScU7Q_P1pMxZCt9DvTQlxFng" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnJld3JpdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLkZyb250ZW5kUmV3cml0ZUFjdGlvbnMuZ2V0U291cmNlT2JqZWN0KEZyb250ZW5kUmV3cml0ZUFjdGlvbnMuamF2YToxODYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozNjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozMzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGVJbkZyb250ZW5kKFJld3JpdGVPYmplY3QuamF2YTozNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MjQwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdC4uLiAxNCBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1SRVFVSVJFRCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IucmV3cml0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24ucmV3cml0ZXIuRnJvbnRlbmRSZXdyaXRlQWN0aW9ucy5nZXRTb3VyY2VPYmplY3QoRnJvbnRlbmRSZXdyaXRlQWN0aW9ucy5qYXZhOjE4Nilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24ucmV3cml0ZXIuUmV3cml0ZXIucmV3cml0ZU9iamVjdChSZXdyaXRlci5qYXZhOjM2Milcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24ucmV3cml0ZXIuUmV3cml0ZXIucmV3cml0ZU9iamVjdChSZXdyaXRlci5qYXZhOjMzMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QucmV3cml0ZUluRnJvbnRlbmQoUmV3cml0ZU9iamVjdC5qYXZhOjM0Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YToyNDApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0Li4uIDE0IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWJhZFJlcXVlc3QsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLlJFUVVJUkVELCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjMwMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLnJld3JpdGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyNClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLkZyb250ZW5kUmV3cml0ZUFjdGlvbnMuZ2V0U291cmNlT2JqZWN0KEZyb250ZW5kUmV3cml0ZUFjdGlvbnMuamF2YToxODYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozNjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozMzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGVJbkZyb250ZW5kKFJld3JpdGVPYmplY3QuamF2YTozNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MjQwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdC4uLiAxNCBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5yZXdyaXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5Gcm9udGVuZFJld3JpdGVBY3Rpb25zLmdldFNvdXJjZU9iamVjdChGcm9udGVuZFJld3JpdGVBY3Rpb25zLmphdmE6MTg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzYyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzMzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5yZXdyaXRlSW5Gcm9udGVuZChSZXdyaXRlT2JqZWN0LmphdmE6MzQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjI0MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHQuLi4gMTQgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMCwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4ifX0=" + } + }, + { + "ID": "f86365df7b93f43c", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/rewriteTo/b/go-integration-test-20180927-44630911863640-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9ddfb31e3f881c845551040d149daa03/708533613463303504;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/rewriteTo/b/go-integration-test-20180927-44630911863640-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3321" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:13 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051412000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrlw11:4360,/bns/yv/borg/yv/bns/blobstore2/bitpusher/67.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=KMysW5WjMoqOgwTBuI7wDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/67.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/67:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpCChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrovVDo882mWpoavyshb6LknBxbQkL6Ya9AnN5uoVuTl1lfogtISVulQ2qAStL-GJMjMMnY3YCHK4yUm5jOG7JBH8Ub4A" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiNSIsIm9iamVjdFNpemUiOiI1IiwiZG9uZSI6dHJ1ZSwicmVzb3VyY2UiOnsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvY29weS8xNTM4MDUxMTEyOTQxMjM1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29weSIsIm5hbWUiOiJjb3B5IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTI5NDEyMzUiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MTIuOTQxWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjEyLjk0MVoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNToxMi45NDFaIiwic2l6ZSI6IjUiLCJtZDVIYXNoIjoiWFVGQUtyeExLbmE1Y1oyUkVCZkZrZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2NvcHk/Z2VuZXJhdGlvbj0xNTM4MDUxMTEyOTQxMjM1JmFsdD1tZWRpYSIsImNvbnRlbnRMYW5ndWFnZSI6ImVuIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvY29weS8xNTM4MDUxMTEyOTQxMjM1L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29weS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJjb3B5IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTI5NDEyMzUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNMUHQ3dkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9jb3B5LzE1MzgwNTExMTI5NDEyMzUvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29weS9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTEyOTQxMjM1IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMUHQ3dkdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9jb3B5LzE1MzgwNTExMTI5NDEyMzUvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29weS9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTEyOTQxMjM1IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTFB0N3ZHVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvY29weS8xNTM4MDUxMTEyOTQxMjM1L3VzZXItaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9jb3B5L2FjbC91c2VyLWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiY29weSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTEyOTQxMjM1IiwiZW50aXR5IjoidXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0xQdDd2R1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJtbkc3VEE9PSIsImV0YWciOiJDTFB0N3ZHVzI5MENFQUU9In19" + } + }, + { + "ID": "5879616fb9645b35", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/rewriteTo/b/go-integration-test-20180927-44630911863640-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b83e165b179c0491707d79c900744d04/2298945517513677807;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo/rewriteTo/b/go-integration-test-20180927-44630911863640-0003/o/copy?alt=json\u0026prettyPrint=false\u0026projection=full\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "14247" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:13 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051412000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrua10:4104,/bns/yv/borg/yv/bns/blobstore2/bitpusher/268.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=KcysW_rQA9KeggS9oqBY" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/268.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/268:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpCChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrFsS7uheKWICgicbUs1cp26n1d1UfjI-Zyvhd_j3EOO7rhY-n1p44ri63jTHbJcoBVsPrvnFxkdQ7M9nfEkgyBNH3lyw" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5yZXdyaXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLkZyb250ZW5kUmV3cml0ZUFjdGlvbnMuZ2V0U291cmNlT2JqZWN0KEZyb250ZW5kUmV3cml0ZUFjdGlvbnMuamF2YToxODYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozNjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozMzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGVJbkZyb250ZW5kKFJld3JpdGVPYmplY3QuamF2YTozNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MjQwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdC4uLiAxNCBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1GT1JCSURERU4sIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IucmV3cml0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5Gcm9udGVuZFJld3JpdGVBY3Rpb25zLmdldFNvdXJjZU9iamVjdChGcm9udGVuZFJld3JpdGVBY3Rpb25zLmphdmE6MTg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzYyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzMzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5yZXdyaXRlSW5Gcm9udGVuZChSZXdyaXRlT2JqZWN0LmphdmE6MzQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjI0MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHQuLi4gMTQgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9Zm9yYmlkZGVuLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5GT1JCSURERU4sIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YTozMDIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5yZXdyaXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLkZyb250ZW5kUmV3cml0ZUFjdGlvbnMuZ2V0U291cmNlT2JqZWN0KEZyb250ZW5kUmV3cml0ZUFjdGlvbnMuamF2YToxODYpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozNjIpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLnJld3JpdGVyLlJld3JpdGVyLnJld3JpdGVPYmplY3QoUmV3cml0ZXIuamF2YTozMzMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LnJld3JpdGVJbkZyb250ZW5kKFJld3JpdGVPYmplY3QuamF2YTozNDcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5SZXdyaXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChSZXdyaXRlT2JqZWN0LmphdmE6MjQwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdC4uLiAxNCBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6MzAyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IucmV3cml0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5Gcm9udGVuZFJld3JpdGVBY3Rpb25zLmdldFNvdXJjZU9iamVjdChGcm9udGVuZFJld3JpdGVBY3Rpb25zLmphdmE6MTg2KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzYyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5yZXdyaXRlci5SZXdyaXRlci5yZXdyaXRlT2JqZWN0KFJld3JpdGVyLmphdmE6MzMzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5yZXdyaXRlSW5Gcm9udGVuZChSZXdyaXRlT2JqZWN0LmphdmE6MzQ3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuUmV3cml0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoUmV3cml0ZU9iamVjdC5qYXZhOjI0MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLlJld3JpdGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFJld3JpdGVPYmplY3QuamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHQuLi4gMTQgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMywibWVzc2FnZSI6ImludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuIn19" + } + }, + { + "ID": "d58b6d243a768de2", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/compose/compose?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "127" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "af35fdd27845b2cb356c7bc7026838b3/3889357421580894349;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/compose/compose?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImZvbyJ9LHsibmFtZSI6ImNvcHkifV19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "742" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:13 GMT" + ], + "Etag": [ + "CJeim/KW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051412000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbf23:4359,/bns/yv/borg/yv/bns/blobstore2/bitpusher/164.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=KcysW5CYEJCAgwTX26HYCw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/164.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/164:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq0XH95_bvjP8WCkrA3pEAug5FEKD-6kMcOQN8UBPYQvggU93eZabBmIcjCp0AcvnZyHYRIt8a_d6oH8Y_Cdp1nTKhPvg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9jb21wb3NlLzE1MzgwNTExMTM2Njg4ODciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9jb21wb3NlIiwibmFtZSI6ImNvbXBvc2UiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTExMzY2ODg4NyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNToxMy42NjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MTMuNjY3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjEzLjY2N1oiLCJzaXplIjoiMTAiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29tcG9zZT9nZW5lcmF0aW9uPTE1MzgwNTExMTM2Njg4ODcmYWx0PW1lZGlhIiwiY3JjMzJjIjoiL1JDT2dnPT0iLCJjb21wb25lbnRDb3VudCI6MiwiZXRhZyI6IkNKZWltL0tXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "82f9c7e73e26169f", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/compose/compose?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "127" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "88656daa72f3a44c8d1036302cce6ab8/5407430256633472556;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/compose/compose?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImZvbyJ9LHsibmFtZSI6ImNvcHkifV19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "742" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:14 GMT" + ], + "Etag": [ + "CLjYwPKW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051412000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrt187:4251,/bns/yv/borg/yv/bns/blobstore2/bitpusher/82.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=KcysW9CAN4OlgASf-Jco" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/82.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/82:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoaT4viYqVfzBgidvfngr5I3dfnvBo_Q97aJ53xZZHVShVI9-ajQVC6y5nJ7D6UaetBaaqvIMuyyPtISMa-XjlL4Fk3qg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9jb21wb3NlLzE1MzgwNTExMTQyODIwNDAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9jb21wb3NlIiwibmFtZSI6ImNvbXBvc2UiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTExNDI4MjA0MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNToxNC4yODFaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MTQuMjgxWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjE0LjI4MVoiLCJzaXplIjoiMTAiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29tcG9zZT9nZW5lcmF0aW9uPTE1MzgwNTExMTQyODIwNDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoiL1JDT2dnPT0iLCJjb21wb25lbnRDb3VudCI6MiwiZXRhZyI6IkNMall3UEtXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "e6671b4e33cec5f9", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/compose/compose?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "127" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "57be10b174302620db439bb9e5bd529e/6997842160700623819;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/compose/compose?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImZvbyJ9LHsibmFtZSI6ImNvcHkifV19Cg==" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "12159" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:14 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051412000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrch124:4064,/bns/yv/borg/yv/bns/blobstore2/bitpusher/203.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=KsysW9-vGJC0ggSujK6wDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/203.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/203:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpCChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqACTq5n8sFNIiVA2h8aH3Vj_ZswPTuWjjESekvJFvdlKomAhXobltpqY4fsj2szRDB9frX-PjOv9hytKgpgnK0_P6CZg" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6MTk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjQ1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6MTk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjQ1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YToxOTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6NDUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmNvbXBvc2UoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuY29tcG9zZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" + } + }, + { + "ID": "d5dec65b14d1e564", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/compose/compose?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "127" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e3b2ca3ee9799fdbcd67edea72cb2b13/8588254064751063401;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/compose/compose?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImZvbyJ9LHsibmFtZSI6ImNvcHkifV19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "742" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:14 GMT" + ], + "Etag": [ + "CPPa3fKW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051412000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vray3:4145,/bns/yr/borg/yr/bns/blobstore2/bitpusher/1.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=KsysW-D8JYeTkATnw5OYAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/1.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/1:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpCChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uqw7poK3DL_KB2b-NGyg3S_etaxdZOQT8tM1CB3Njtjp5I5cTq4IkFxXrlPXslCK4wfycAl4MApkddYSmiVeRaX2IXCvQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9jb21wb3NlLzE1MzgwNTExMTQ3NTc0OTEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMvby9jb21wb3NlIiwibmFtZSI6ImNvbXBvc2UiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTExNDc1NzQ5MSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNToxNC43NTdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MTQuNzU3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjE0Ljc1N1oiLCJzaXplIjoiMTAiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vY29tcG9zZT9nZW5lcmF0aW9uPTE1MzgwNTExMTQ3NTc0OTEmYWx0PW1lZGlhIiwiY3JjMzJjIjoiL1JDT2dnPT0iLCJjb21wb25lbnRDb3VudCI6MiwiZXRhZyI6IkNQUGEzZktXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "24c660b93668472d", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/compose/compose?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "127" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "be05ebeb28473769bdebf0265c356dd1/10178665964523312648;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/compose/compose?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6ImZvbyJ9LHsibmFtZSI6ImNvcHkifV19Cg==" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "13015" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:15 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051412000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrmm26:4177,/bns/yv/borg/yv/bns/blobstore2/bitpusher/113.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=KsysW8vBNsLygwT0jIrYCA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/113.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/113:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpCChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoEj3IamdTcELhnX6VeqX7ghzI3eYDEPV8bpculXR797zpQlEOtsuXWVEwCdLTnbT5jN26sovoxVnQ3kVIP4zvetR60xg" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjE5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YTo0NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuY29tcG9zZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTI5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6MTk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjQ1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6MTk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuQ29tcG9zZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoQ29tcG9zZU9iamVjdC5qYXZhOjQ1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5jb21wb3NlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMjkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkNvbXBvc2VPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKENvbXBvc2VPYmplY3QuamF2YToxOTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5Db21wb3NlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChDb21wb3NlT2JqZWN0LmphdmE6NDUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmNvbXBvc2UoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjEyOSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" + } + }, + { + "ID": "8258f8e2dc12967c", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=a689dc23618e3f3e66aa43d96c5419cf130f3b626c9fa0e4d4c51e49c721" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0df3a8a5e79adbc213ad94e8657ffc2f/11009759428470810967;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS1hNjg5ZGMyMzYxOGUzZjNlNjZhYTQzZDk2YzU0MTljZjEzMGYzYjYyNmM5ZmEwZTRkNGM1MWU0OWM3MjENCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm5hbWUiOiJmb28ifQoNCi0tYTY4OWRjMjM2MThlM2YzZTY2YWE0M2Q5NmM1NDE5Y2YxMzBmM2I2MjZjOWZhMGU0ZDRjNTFlNDljNzIxDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgNCg0KaGVsbG8NCi0tYTY4OWRjMjM2MThlM2YzZTY2YWE0M2Q5NmM1NDE5Y2YxMzBmM2I2MjZjOWZhMGU0ZDRjNTFlNDljNzIxLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3205" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:15 GMT" + ], + "Etag": [ + "CKeVh/OW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051388000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrnk23:4310,/bns/yr/borg/yr/bns/blobstore2/bitpusher/0.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=K8ysW_iHCMSxkATZ74bIAQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/0.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/0:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrK68i4wgUfs8FAKX_CTgQ_yQHjxuVG81WoqFKLDV_C_STun4Y3x3F7rBPIWnouByRLYZyIwwnJPGmZe5PDKq0vps65DA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExNTQzNjcxMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTExNTQzNjcxMSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNToxNS40MzZaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MTUuNDM2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjE1LjQzNloiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTExNTQzNjcxMSZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExNTQzNjcxMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTExNTQzNjcxMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0tlVmgvT1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMTE1NDM2NzExL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTU0MzY3MTEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0tlVmgvT1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMTE1NDM2NzExL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTU0MzY3MTEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNLZVZoL09XMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExNTQzNjcxMS91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTU0MzY3MTEiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDS2VWaC9PVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNLZVZoL09XMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "3610413c1a01c96c", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "51d5a9571886ff76af7257bedf96bf1b/11768796397892009126;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:15 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051388000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrhr16:4228,/bns/yv/borg/yv/bns/blobstore2/bitpusher/58.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=K8ysW-zxIZOOgQTGxbr4Cg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/58.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/58:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqE55aemrYjdFA8FkDCwW812jfM5D0wZd7golIxJUOE-xP3suwjn4V7dwR978-yKqkJ5Fjz2xxYKRTVPTq9qS8yfeB02OKDwOjsuNxmtVMKA-0A8KI" + ] + }, + "Body": "" + } + }, + { + "ID": "49aa8c8fefb3577a", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=ab6dfb15520815f8119effd1b1d5f7dec91a7e7b8477b1ac4492c7f9a037" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "5662dde3618e05ad28aa32d8645d4e42/12600170233043111670;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS1hYjZkZmIxNTUyMDgxNWY4MTE5ZWZmZDFiMWQ1ZjdkZWM5MWE3ZTdiODQ3N2IxYWM0NDkyYzdmOWEwMzcNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm5hbWUiOiJmb28ifQoNCi0tYWI2ZGZiMTU1MjA4MTVmODExOWVmZmQxYjFkNWY3ZGVjOTFhN2U3Yjg0NzdiMWFjNDQ5MmM3ZjlhMDM3DQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgNCg0KaGVsbG8NCi0tYWI2ZGZiMTU1MjA4MTVmODExOWVmZmQxYjFkNWY3ZGVjOTFhN2U3Yjg0NzdiMWFjNDQ5MmM3ZjlhMDM3LS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3205" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:16 GMT" + ], + "Etag": [ + "CJa+sfOW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051388000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vraz3:4225,/bns/yr/borg/yr/bns/blobstore2/bitpusher/37.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=K8ysW87ENNHD4QTY_bTQDA" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/37.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/37:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uqs6PH1tPVOygCthX3HcFpiXsTBPsOE0XUzHj3uRrIEmDTAKhT8TiGBcBSVXXv6lgRWAkfRmYxErnNfB7r5P_Rnx84vhQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExNjEzMDA3MCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTExNjEzMDA3MCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNToxNi4xMjlaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MTYuMTI5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjE2LjEyOVoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTExNjEzMDA3MCZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExNjEzMDA3MC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTExNjEzMDA3MCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0phK3NmT1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMTE2MTMwMDcwL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTYxMzAwNzAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0phK3NmT1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMTE2MTMwMDcwL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTYxMzAwNzAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKYStzZk9XMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExNjEzMDA3MC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTYxMzAwNzAiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSmErc2ZPVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNKYStzZk9XMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "07c8a1555393f910", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d007af7835e7bbb949a25b07284eca47/13359207202464309573;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:16 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051388000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vra74:4154,/bns/yv/borg/yv/bns/blobstore2/bitpusher/129.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=LMysW_T0DtP-gASw_pngAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/129.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/129:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur-j16n2uzB3mZoBZM424vIBmsK2vOIC3mwutsAMtqFqwEa2_PgKKWN_ZBQzGq-8Yd6wNWnTQtGMgvom3GAi-BBhY1Q2w" + ] + }, + "Body": "" + } + }, + { + "ID": "2defffbcd8976267", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=75a80d9841f4290d47e65be40815577244a41e66a9a9cf3df47372ffb308" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "f3b9c63bf79fa11cdaabdbb76d9a0bd2/14190300666411807892;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS03NWE4MGQ5ODQxZjQyOTBkNDdlNjViZTQwODE1NTc3MjQ0YTQxZTY2YTlhOWNmM2RmNDczNzJmZmIzMDgNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm5hbWUiOiJmb28ifQoNCi0tNzVhODBkOTg0MWY0MjkwZDQ3ZTY1YmU0MDgxNTU3NzI0NGE0MWU2NmE5YTljZjNkZjQ3MzcyZmZiMzA4DQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgNCg0KaGVsbG8NCi0tNzVhODBkOTg0MWY0MjkwZDQ3ZTY1YmU0MDgxNTU3NzI0NGE0MWU2NmE5YTljZjNkZjQ3MzcyZmZiMzA4LS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3205" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:16 GMT" + ], + "Etag": [ + "CPqF3POW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051388000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrud24:4012,/bns/yr/borg/yr/bns/blobstore2/bitpusher/90.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=LMysW_6rItCBkATK14bwDg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/90.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/90:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoIxj06L4-s3I6oVItW3TiAANXDlYSURjREeXxJ2GhVRJSrZsuU5X4YSySqZ-BrklVUdF0QIgUxqu4ng18fcrEHYKgsoA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExNjgyNzM4NiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTExNjgyNzM4NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNToxNi44MjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MTYuODI3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjE2LjgyN1oiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTExNjgyNzM4NiZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExNjgyNzM4Ni9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTExNjgyNzM4NiIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1BxRjNQT1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMTE2ODI3Mzg2L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTY4MjczODYiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1BxRjNQT1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMTE2ODI3Mzg2L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTY4MjczODYiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQcUYzUE9XMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExNjgyNzM4Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTY4MjczODYiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUHFGM1BPVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNQcUYzUE9XMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "a778a38a339a93e4", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "71d26a27642e73b3cd6be125433435a2/14949619106514683876;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 400, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "12135" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:17 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:17 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051393000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrud24:4012,/bns/yv/borg/yv/bns/blobstore2/bitpusher/59.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=LMysW5vuOcjAggTmnbjABA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/59.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/59:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpFChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErMOMrSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoVnK5NfmwNaxGyeQ_rxmtw2pIfr-rNJNSvRUsZHttcvwhswcNcgXCauYsMiUo3GB2K8ydgQ0-KHfu05d22wU_DGlJTaQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkJ1Y2tldCBpcyByZXF1ZXN0ZXIgcGF5cyBidWNrZXQgYnV0IG5vIHVzZXIgcHJvamVjdCBwcm92aWRlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjc3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX01JU1NJTkc6IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjc3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9YmFkUmVxdWVzdCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfTUlTU0lORzogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6NzcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjIzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5kZWxldGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjExMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEJ1Y2tldCBpcyBSZXF1ZXN0ZXIgUGF5cyBidWNrZXQgYnV0IG5vIGJpbGxpbmcgcHJvamVjdCBpZCBwcm92aWRlZCBmb3Igbm9uLW93bmVyLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9QnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMH0gQnVja2V0IGlzIHJlcXVlc3RlciBwYXlzIGJ1Y2tldCBidXQgbm8gdXNlciBwcm9qZWN0IHByb3ZpZGVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9NSVNTSU5HOiBCdWNrZXQgaXMgUmVxdWVzdGVyIFBheXMgYnVja2V0IGJ1dCBubyBiaWxsaW5nIHByb2plY3QgaWQgcHJvdmlkZWQgZm9yIG5vbi1vd25lci5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo3Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQnVja2V0IGlzIFJlcXVlc3RlciBQYXlzIGJ1Y2tldCBidXQgbm8gYmlsbGluZyBwcm9qZWN0IGlkIHByb3ZpZGVkIGZvciBub24tb3duZXIuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDAsIm1lc3NhZ2UiOiJCdWNrZXQgaXMgcmVxdWVzdGVyIHBheXMgYnVja2V0IGJ1dCBubyB1c2VyIHByb2plY3QgcHJvdmlkZWQuIn19" + } + }, + { + "ID": "2a8fd68359cb1958", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=4f6e9b78f5a8b7e850386764f72a73c816d0f8dc26327ea4d10da74cc35d" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b7aa87d2a9c5480b8c28fa68dd906821/15708656071657756979;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS00ZjZlOWI3OGY1YThiN2U4NTAzODY3NjRmNzJhNzNjODE2ZDBmOGRjMjYzMjdlYTRkMTBkYTc0Y2MzNWQNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm5hbWUiOiJmb28ifQoNCi0tNGY2ZTliNzhmNWE4YjdlODUwMzg2NzY0ZjcyYTczYzgxNmQwZjhkYzI2MzI3ZWE0ZDEwZGE3NGNjMzVkDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgNCg0KaGVsbG8NCi0tNGY2ZTliNzhmNWE4YjdlODUwMzg2NzY0ZjcyYTczYzgxNmQwZjhkYzI2MzI3ZWE0ZDEwZGE3NGNjMzVkLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3205" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:17 GMT" + ], + "Etag": [ + "CNGxgfSW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051388000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vreu27:4180,/bns/yv/borg/yv/bns/blobstore2/bitpusher/296.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=LcysW5DkB8u0gASSk5bYAQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/296.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/296:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqupdeNHxKM38dADbCeH8nI7nmyi0vHoWSYlJ0PAgo11y3jQ1rPgq5MBoKWmfN2F_34QBdaOSTTs3SlTrlTGozCPBuYVA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExNzQzOTE4NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTExNzQzOTE4NSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNToxNy40MzhaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MTcuNDM4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjE3LjQzOFoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTExNzQzOTE4NSZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExNzQzOTE4NS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTExNzQzOTE4NSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ05HeGdmU1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMTE3NDM5MTg1L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTc0MzkxODUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ05HeGdmU1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMTE3NDM5MTg1L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTc0MzkxODUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOR3hnZlNXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExNzQzOTE4NS91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTc0MzkxODUiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTkd4Z2ZTVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNOR3hnZlNXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "9c087f5dea9ff46c", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "fe3cb9d98b5c4a69974af372d060dcd6/16540031006286998658;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026userProject=gcloud-golang-firestore-tests" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:17 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051393000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrvp14:4177,/bns/yr/borg/yr/bns/blobstore2/bitpusher/47.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=LcysW7eCIpGBkAS56Iz4BQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/47.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/47:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpFChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErMOMrSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpKOP9rXNco4uzsEObaLaIwSS_pvKPoR_hIfr8ARW6YDpAg5SvCHTDLc9x0bBHmSQOdoBISIPL2ExjWg_f7idxUZICJAw" + ] + }, + "Body": "" + } + }, + { + "ID": "3939dd32424044e0", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=85973a0d1061499ceaef6ac4ba7dca168f9fea012e335225842463125991" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0b26e241919815ac6310bc678ab9ee93/17299067975708131282;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS04NTk3M2EwZDEwNjE0OTljZWFlZjZhYzRiYTdkY2ExNjhmOWZlYTAxMmUzMzUyMjU4NDI0NjMxMjU5OTENCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMyIsIm5hbWUiOiJmb28ifQoNCi0tODU5NzNhMGQxMDYxNDk5Y2VhZWY2YWM0YmE3ZGNhMTY4ZjlmZWEwMTJlMzM1MjI1ODQyNDYzMTI1OTkxDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgNCg0KaGVsbG8NCi0tODU5NzNhMGQxMDYxNDk5Y2VhZWY2YWM0YmE3ZGNhMTY4ZjlmZWEwMTJlMzM1MjI1ODQyNDYzMTI1OTkxLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3205" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:18 GMT" + ], + "Etag": [ + "CPDLpvSW290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051388000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrde80:4389,/bns/yv/borg/yv/bns/blobstore2/bitpusher/334.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=LcysW7ShLpLsgQT85IbADw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/334.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/334:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqDXeA-_PCymYgmewqvC4l3Gbco2LCE5-vGB4Kb1wbr-7oBYEHShdOTDNW8t1PhNwvA0Z-Y1rO1b-A5vDAXffu1UKLqHg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExODA0ODc1MiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2ZvbyIsIm5hbWUiOiJmb28iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTExODA0ODc1MiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNToxOC4wNDhaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MTguMDQ4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjE4LjA0OFoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vP2dlbmVyYXRpb249MTUzODA1MTExODA0ODc1MiZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExODA0ODc1Mi9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDMiLCJvYmplY3QiOiJmb28iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTExODA0ODc1MiIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1BETHB2U1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMTE4MDQ4NzUyL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTgwNDg3NTIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1BETHB2U1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL2Zvby8xNTM4MDUxMTE4MDQ4NzUyL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9vL2Zvby9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTgwNDg3NTIiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQRExwdlNXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMy9mb28vMTUzODA1MTExODA0ODc1Mi91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzL28vZm9vL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAzIiwib2JqZWN0IjoiZm9vIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExMTgwNDg3NTIiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUERMcHZTVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Im1uRzdUQT09IiwiZXRhZyI6IkNQRExwdlNXMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "74c09e371d29ac29", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "a676d7c79d62a934a91a442e50088d50/18130161439655629345;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false\u0026userProject=veener-jba" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "12991" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:18 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:18 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051393000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "471383502717" + ], + "X-Google-Backends": [ + "vrny26:4047,/bns/yr/borg/yr/bns/blobstore2/bitpusher/40.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=LsysW7WDCo_s4QS_yY3QBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/40.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/40:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CP3elYXcDRoCGAYoATpFChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGM6ropHgHCIVMTE3MjM4MDU4ODYxOTM3NTE5MTQ0MOArMOErMOMrSp8BEoIBeWEyOS5jLkVsb2xCcldWbUZlX1AxVDdUOHVpTXdFMHBZUjdTc2NVMDBFdEZkc2tSenBQY0NLWkhUeEZaYXI0Q25tZmR6bXFRLTNVV0kzOF9wdEx5VTZ2Z1Q3dlRBeW42Z3g4dUcyd0szSHIzaTZrV1JBZkozc1pNMGQ1allkNHpWQTAEOhZOT1RfQV9QRVJTSVNURU5UX1RPS0VO" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrpZwGPce9nNsZPGsv95kJIkHK0LTBKS0xq9-VuVNdTJGloUo7xESD3m8qGC5o_TwJ73P4MLGzp2V-K8W2dO7pqIQkQyA" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpVU0VSX1BST0pFQ1RfQUNDRVNTX0RFTklFRDogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo3Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogaW50ZWdyYXRpb25AZ2Nsb3VkLWdvbGFuZy1maXJlc3RvcmUtdGVzdHMuaWFtLmdzZXJ2aWNlYWNjb3VudC5jb20gZG9lcyBub3QgaGF2ZSBzZXJ2aWNldXNhZ2Uuc2VydmljZXMudXNlIGFjY2VzcyB0byBwcm9qZWN0IDY0MjA4MDkxODEwMS5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Rk9SQklEREVOLCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjc3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1mb3JiaWRkZW4sIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLkZPUkJJRERFTiwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlVTRVJfUFJPSkVDVF9BQ0NFU1NfREVOSUVEOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjc3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUZPUkJJRERFTiwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPWludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1pbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6VVNFUl9QUk9KRUNUX0FDQ0VTU19ERU5JRUQ6IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6NzcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjIzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5kZWxldGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjExMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IGludGVncmF0aW9uQGdjbG91ZC1nb2xhbmctZmlyZXN0b3JlLXRlc3RzLmlhbS5nc2VydmljZWFjY291bnQuY29tIGRvZXMgbm90IGhhdmUgc2VydmljZXVzYWdlLnNlcnZpY2VzLnVzZSBhY2Nlc3MgdG8gcHJvamVjdCA2NDIwODA5MTgxMDEuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDMsIm1lc3NhZ2UiOiJpbnRlZ3JhdGlvbkBnY2xvdWQtZ29sYW5nLWZpcmVzdG9yZS10ZXN0cy5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSBkb2VzIG5vdCBoYXZlIHNlcnZpY2V1c2FnZS5zZXJ2aWNlcy51c2UgYWNjZXNzIHRvIHByb2plY3QgNjQyMDgwOTE4MTAxLiJ9fQ==" + } + }, + { + "ID": "a0e8258aaf3c4072", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "68b50c9729fbc325a856f265c14e1399/443017281042506864;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/foo?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:18 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051418000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnme26:4110,/bns/yx/borg/yx/bns/blobstore2/bitpusher/111.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=LsysW9-NFNXGzALmmI6YCg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/111.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/111:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Upq5TGgZ6pXmvluXnywBJQS6092UwP-6DQjN7OPoqrkN2EtcixAs_aS9wo2eAwA5GO2eorSBVmZNdBvNZDnaR7FAXTqog" + ] + }, + "Body": "" + } + }, + { + "ID": "13d08364d3e115a4", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/copy?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "042ea18a0bf0a95e4096fc95e538efa7/1274110744989939648;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/copy?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:18 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051388000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vras90:4259,/bns/yv/borg/yv/bns/blobstore2/bitpusher/20.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=LsysW6-QJ8nMgASG3IeoCQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/20.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/20:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpW2F7l42ObaHTrp9Vow9C8oBA8ztqz41L3FLxjdhBOflM_KB5TyMH4CmJuSt83v9PPhYLC3H8qMnXrt2vTF7AVKwFNbMy8HC4JGEIw45kwP5ZwA00" + ] + }, + "Body": "" + } + }, + { + "ID": "ff21a30a8097c589", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/compose?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b90515bb73861fb4787571a44e507185/2033146614916286991;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003/o/compose?alt=json\u0026prettyPrint=false\u0026userProject=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:19 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051388000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbx80:4064,/bns/yw/borg/yw/bns/blobstore2/bitpusher/109.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=LsysW7emOYq-N6XaqtAB" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/109.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/109:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoqsotiuhmzO_3f-9ZFLFk8eV3K4K8QrlFJ-bJPr6u3w2s-12Xg44-XhDrluV1kKFGWvvDybBkaCVmbGH0leIcmJv44pg" + ] + }, + "Body": "" + } + }, + { + "ID": "de4b252e5c956234", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3209c3194428722334c6c8069b679a20/3623558514688536494;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0003?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:19 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051388000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrk2:4119,/bns/yv/borg/yv/bns/blobstore2/bitpusher/277.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=L8ysW9GjEcjogAThu5aQBg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/277.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/277:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWVNNdC1OVDFNYTJvWXBrbG1qcDlJMlZaUFZ5bFl5Z2Q3Nk5tQXlXbWR3WVBoMm00dGI3ZmZjOUlzcTU4MmVFcFBhNzhNWGpNZmIzaE9WTE9xRHpNTUFfTG9NQXVJZkdkMGgzSWowZ1dxdW5DS1g3Qk1mQlJxM001TUtMMXBHOWNyU0ZBT29lVkZpTDhpWlBsUDI0VjE5THdzZ0d1ZnVrQTFtVzVJcTJUUkVXeWQyNjRKZC1lS2UxdTAwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrP-Q3OW_tl4K9YltEXTmq5_0_su8TykvlsV5YsalIA9InwpPJmCmdw0Cv2uroid62PFvdUiXZm6xlMQksd9UouJ8buBw" + ] + }, + "Body": "" + } + }, + { + "ID": "e3fcdc643d6a955f", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/notificationConfigs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9cf6f621d3ad5b7a0129dfd00640fe3f/5213970418738976076;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/notificationConfigs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "32" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:20 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:20 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051419000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vro66:4347,/bns/yv/borg/yv/bns/blobstore2/bitpusher/289.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=L8ysW5rnM4b-gQTynLpY" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/289.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/289:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWmMyX1YxcnlBTVZvR05vX19MeXBsclFqc1ZqRm5OZGFfaTNuekctMlgycHRhcERKcHluWjB0MWVWTzB4bWtOLXIwOE9ra3NCbUdkR3dxTEJjYmhMRXhqYzdwVVdDbGRWSjNoVW55ZEdfVE03b01kVnVNajhsU0xvMW9Bcm5EMVpEejJOeGhWeXRqSzc1OWNGc28yTGY5cE1LX3NGWUdtcGlxWVUwQXBPODNVMDJsVms4UHEwRlhWMzQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoDy81ffYtqpt9Im4ag9xtAsE3bkApK6xGw22mK0W4mKIahbq3sQHkR7qHzsIDLDTYzeiWuLYxnHM6ftzE_eI3avG7btw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNub3RpZmljYXRpb25zIn0=" + } + }, + { + "ID": "30df2ed678a1bc12", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/notificationConfigs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "121" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0f92d17533d4f481259e5042dae0f8be/6804100852124383979;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/notificationConfigs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJwYXlsb2FkX2Zvcm1hdCI6Ik5PTkUiLCJ0b3BpYyI6Ii8vcHVic3ViLmdvb2dsZWFwaXMuY29tL3Byb2plY3RzL2R1bGNldC1wb3J0LTc2Mi90b3BpY3MvZ28tc3RvcmFnZS1ub3RpZmljYXRpb24tdGVzdCJ9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "297" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:20 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051420000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrsq4:4180,/bns/yr/borg/yr/bns/blobstore2/bitpusher/12.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=MMysW6LQAtCOkATL9oqABA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/12.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/12:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWmMyX1YxcnlBTVZvR05vX19MeXBsclFqc1ZqRm5OZGFfaTNuekctMlgycHRhcERKcHluWjB0MWVWTzB4bWtOLXIwOE9ra3NCbUdkR3dxTEJjYmhMRXhqYzdwVVdDbGRWSjNoVW55ZEdfVE03b01kVnVNajhsU0xvMW9Bcm5EMVpEejJOeGhWeXRqSzc1OWNGc28yTGY5cE1LX3NGWUdtcGlxWVUwQXBPODNVMDJsVms4UHEwRlhWMzQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqZ0JCvZ3jCfAdQU0U4oQQTdO4SSYDOnWO1_zcfk84rmXsRwywDGCcL3QeFDLvrXQ1kx8U7Kalb86sIQ1JhGV1yRC7G4Q" + ] + }, + "Body": "eyJpZCI6IjEwIiwidG9waWMiOiIvL3B1YnN1Yi5nb29nbGVhcGlzLmNvbS9wcm9qZWN0cy9kdWxjZXQtcG9ydC03NjIvdG9waWNzL2dvLXN0b3JhZ2Utbm90aWZpY2F0aW9uLXRlc3QiLCJwYXlsb2FkX2Zvcm1hdCI6Ik5PTkUiLCJldGFnIjoiMTAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvbm90aWZpY2F0aW9uQ29uZmlncy8xMCIsImtpbmQiOiJzdG9yYWdlI25vdGlmaWNhdGlvbiJ9" + } + }, + { + "ID": "1a20023489e65b39", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/notificationConfigs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b707fc96aa6ecc8d21d239a9bf2ca897/8394512751879856266;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/notificationConfigs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "340" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:21 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:21 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051419000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrp184:4188,/bns/yr/borg/yr/bns/blobstore2/bitpusher/91.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=MMysW9XCN8zn4QSk5KsQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/91.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/91:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWmMyX1YxcnlBTVZvR05vX19MeXBsclFqc1ZqRm5OZGFfaTNuekctMlgycHRhcERKcHluWjB0MWVWTzB4bWtOLXIwOE9ra3NCbUdkR3dxTEJjYmhMRXhqYzdwVVdDbGRWSjNoVW55ZEdfVE03b01kVnVNajhsU0xvMW9Bcm5EMVpEejJOeGhWeXRqSzc1OWNGc28yTGY5cE1LX3NGWUdtcGlxWVUwQXBPODNVMDJsVms4UHEwRlhWMzQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrZMY5eFlGX9fTrWRJIZeUIwwpdodFT4ZAfmEWr8ZhnCpaqyDq4XZ6tkLLfnutcc80V5OA2fVD7YkN9a3Ty65mVW9X88Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNub3RpZmljYXRpb25zIiwiaXRlbXMiOlt7ImlkIjoiMTAiLCJ0b3BpYyI6Ii8vcHVic3ViLmdvb2dsZWFwaXMuY29tL3Byb2plY3RzL2R1bGNldC1wb3J0LTc2Mi90b3BpY3MvZ28tc3RvcmFnZS1ub3RpZmljYXRpb24tdGVzdCIsInBheWxvYWRfZm9ybWF0IjoiTk9ORSIsImV0YWciOiIxMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9ub3RpZmljYXRpb25Db25maWdzLzEwIiwia2luZCI6InN0b3JhZ2Ujbm90aWZpY2F0aW9uIn1dfQ==" + } + }, + { + "ID": "1a78aa71539ea1f2", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/notificationConfigs/10?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "fe55897f2f9774caed6c3609bac29dab/9984923556452222248;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/notificationConfigs/10?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:21 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051421000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrns19:4209,/bns/yr/borg/yr/bns/blobstore2/bitpusher/7.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=McysW7rGCKWLkAT2zYCwBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/7.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/7:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWmMyX1YxcnlBTVZvR05vX19MeXBsclFqc1ZqRm5OZGFfaTNuekctMlgycHRhcERKcHluWjB0MWVWTzB4bWtOLXIwOE9ra3NCbUdkR3dxTEJjYmhMRXhqYzdwVVdDbGRWSjNoVW55ZEdfVE03b01kVnVNajhsU0xvMW9Bcm5EMVpEejJOeGhWeXRqSzc1OWNGc28yTGY5cE1LX3NGWUdtcGlxWVUwQXBPODNVMDJsVms4UHEwRlhWMzQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo63KcORunH_frqXvDI7JVgIHDXzKXeJIoPivdBBNwv00ZNga7njUlQ5sJF3SxO0qTklKAE0kPJr1AZGFQZ2Y50dATW_w" + ] + }, + "Body": "" + } + }, + { + "ID": "147eb7c7f24b19bf", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/notificationConfigs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "54ed24aadb7c2ae57e8c970c5e6bb756/11575335460502596551;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/notificationConfigs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "32" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:22 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:22 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051421000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnbc62:4021,/bns/yx/borg/yx/bns/blobstore2/bitpusher/14.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=McysW42ZM8vnzgLItoTIAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/14.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/14:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWmMyX1YxcnlBTVZvR05vX19MeXBsclFqc1ZqRm5OZGFfaTNuekctMlgycHRhcERKcHluWjB0MWVWTzB4bWtOLXIwOE9ra3NCbUdkR3dxTEJjYmhMRXhqYzdwVVdDbGRWSjNoVW55ZEdfVE03b01kVnVNajhsU0xvMW9Bcm5EMVpEejJOeGhWeXRqSzc1OWNGc28yTGY5cE1LX3NGWUdtcGlxWVUwQXBPODNVMDJsVms4UHEwRlhWMzQwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoK37MBtKFjmQyT21pKKOfUeYJPKIc9VRKGvr-_P3kPVbGZ3u7KB6Xvh6XJ6LHjL-v9I8DWk2U9TfGo1XceVRalOdU1fQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNub3RpZmljYXRpb25zIn0=" + } + }, + { + "ID": "45d0a5288a60555b", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "dbb282b28e87168b0a46837000c32388/13165465889593102438;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=3600" + ], + "Content-Length": [ + "7903" + ], + "Content-Type": [ + "application/octet-stream" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:22 GMT" + ], + "Etag": [ + "\"7a5fd4743bd647485f88496fadb05c51\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 13:25:22 GMT" + ], + "Last-Modified": [ + "Tue, 04 Oct 2016 16:42:07 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Generation": [ + "1475599327662000" + ], + "X-Goog-Hash": [ + "crc32c=PWBt8g==", + "md5=el/UdDvWR0hfiElvrbBcUQ==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "7903" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/48,/bns/xh/borg/xh/bns/blobstore2/bitpusher/51.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=MsysW6OkAo6jswaw3ZvYCg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "570399209098" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/51.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/51:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up6rXgTbuekXkWVQ0gCgVQ02Dr2-EROq2XGin7Ib3JLF9JHP_es5VxOpiGKZkBg_YEIA3jtZa4qxBjcX7UdqHLs_PGzsw" + ] + }, + "Body": "R1JPVVAgPSBMMV9NRVRBREFUQV9GSUxFCiAgR1JPVVAgPSBNRVRBREFUQV9GSUxFX0lORk8KICAgIE9SSUdJTiA9ICJJbWFnZSBjb3VydGVzeSBvZiB0aGUgVS5TLiBHZW9sb2dpY2FsIFN1cnZleSIKICAgIFJFUVVFU1RfSUQgPSAiMDcwMTYwOTE5MTA1MV8wMDAwNCIKICAgIExBTkRTQVRfU0NFTkVfSUQgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwIgogICAgRklMRV9EQVRFID0gMjAxNi0wOS0yMFQwMzoxMzowMloKICAgIFNUQVRJT05fSUQgPSAiTEdOIgogICAgUFJPQ0VTU0lOR19TT0ZUV0FSRV9WRVJTSU9OID0gIkxQR1NfMi42LjIiCiAgRU5EX0dST1VQID0gTUVUQURBVEFfRklMRV9JTkZPCiAgR1JPVVAgPSBQUk9EVUNUX01FVEFEQVRBCiAgICBEQVRBX1RZUEUgPSAiTDFUIgogICAgRUxFVkFUSU9OX1NPVVJDRSA9ICJHTFMyMDAwIgogICAgT1VUUFVUX0ZPUk1BVCA9ICJHRU9USUZGIgogICAgU1BBQ0VDUkFGVF9JRCA9ICJMQU5EU0FUXzgiCiAgICBTRU5TT1JfSUQgPSAiT0xJX1RJUlMiCiAgICBXUlNfUEFUSCA9IDQ0CiAgICBXUlNfUk9XID0gMzQKICAgIE5BRElSX09GRk5BRElSID0gIk5BRElSIgogICAgVEFSR0VUX1dSU19QQVRIID0gNDQKICAgIFRBUkdFVF9XUlNfUk9XID0gMzQKICAgIERBVEVfQUNRVUlSRUQgPSAyMDE2LTA5LTE1CiAgICBTQ0VORV9DRU5URVJfVElNRSA9ICIxODo0NjoxOC42ODY3MzgwWiIKICAgIENPUk5FUl9VTF9MQVRfUFJPRFVDVCA9IDM4LjUyODE5CiAgICBDT1JORVJfVUxfTE9OX1BST0RVQ1QgPSAtMTIzLjQwODQzCiAgICBDT1JORVJfVVJfTEFUX1BST0RVQ1QgPSAzOC41MDc2NQogICAgQ09STkVSX1VSX0xPTl9QUk9EVUNUID0gLTEyMC43NjkzMwogICAgQ09STkVSX0xMX0xBVF9QUk9EVUNUID0gMzYuNDE2MzMKICAgIENPUk5FUl9MTF9MT05fUFJPRFVDVCA9IC0xMjMuMzk3MDkKICAgIENPUk5FUl9MUl9MQVRfUFJPRFVDVCA9IDM2LjM5NzI5CiAgICBDT1JORVJfTFJfTE9OX1BST0RVQ1QgPSAtMTIwLjgzMTE3CiAgICBDT1JORVJfVUxfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA0NjQ0MDAuMDAwCiAgICBDT1JORVJfVUxfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MjY0NTAwLjAwMAogICAgQ09STkVSX1VSX1BST0pFQ1RJT05fWF9QUk9EVUNUID0gNjk0NTAwLjAwMAogICAgQ09STkVSX1VSX1BST0pFQ1RJT05fWV9QUk9EVUNUID0gNDI2NDUwMC4wMDAKICAgIENPUk5FUl9MTF9QUk9KRUNUSU9OX1hfUFJPRFVDVCA9IDQ2NDQwMC4wMDAKICAgIENPUk5FUl9MTF9QUk9KRUNUSU9OX1lfUFJPRFVDVCA9IDQwMzAyMDAuMDAwCiAgICBDT1JORVJfTFJfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA2OTQ1MDAuMDAwCiAgICBDT1JORVJfTFJfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MDMwMjAwLjAwMAogICAgUEFOQ0hST01BVElDX0xJTkVTID0gMTU2MjEKICAgIFBBTkNIUk9NQVRJQ19TQU1QTEVTID0gMTUzNDEKICAgIFJFRkxFQ1RJVkVfTElORVMgPSA3ODExCiAgICBSRUZMRUNUSVZFX1NBTVBMRVMgPSA3NjcxCiAgICBUSEVSTUFMX0xJTkVTID0gNzgxMQogICAgVEhFUk1BTF9TQU1QTEVTID0gNzY3MQogICAgRklMRV9OQU1FX0JBTkRfMSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMiA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjIuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMyA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjMuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjQuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjUuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNiA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjYuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNyA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjcuVElGIgogICAgRklMRV9OQU1FX0JBTkRfOCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjguVElGIgogICAgRklMRV9OQU1FX0JBTkRfOSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjkuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMTAgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMC5USUYiCiAgICBGSUxFX05BTUVfQkFORF8xMSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjExLlRJRiIKICAgIEZJTEVfTkFNRV9CQU5EX1FVQUxJVFkgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0JRQS5USUYiCiAgICBNRVRBREFUQV9GSUxFX05BTUUgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX01UTC50eHQiCiAgICBCUEZfTkFNRV9PTEkgPSAiTE84QlBGMjAxNjA5MTUxODMwNTdfMjAxNjA5MTUyMDA5NTAuMDEiCiAgICBCUEZfTkFNRV9USVJTID0gIkxUOEJQRjIwMTYwOTAyMDg0MTIyXzIwMTYwOTE3MDc0MDI3LjAyIgogICAgQ1BGX05BTUUgPSAiTDhDUEYyMDE2MDcwMV8yMDE2MDkzMC4wMiIKICAgIFJMVVRfRklMRV9OQU1FID0gIkw4UkxVVDIwMTUwMzAzXzIwNDMxMjMxdjExLmg1IgogIEVORF9HUk9VUCA9IFBST0RVQ1RfTUVUQURBVEEKICBHUk9VUCA9IElNQUdFX0FUVFJJQlVURVMKICAgIENMT1VEX0NPVkVSID0gMjkuNTYKICAgIENMT1VEX0NPVkVSX0xBTkQgPSAzLjMzCiAgICBJTUFHRV9RVUFMSVRZX09MSSA9IDkKICAgIElNQUdFX1FVQUxJVFlfVElSUyA9IDkKICAgIFRJUlNfU1NNX01PREVMID0gIkZJTkFMIgogICAgVElSU19TU01fUE9TSVRJT05fU1RBVFVTID0gIkVTVElNQVRFRCIKICAgIFJPTExfQU5HTEUgPSAtMC4wMDEKICAgIFNVTl9BWklNVVRIID0gMTQ4LjQ4MDQ5Mzk2CiAgICBTVU5fRUxFVkFUSU9OID0gNTAuOTM3NjgzOTkKICAgIEVBUlRIX1NVTl9ESVNUQU5DRSA9IDEuMDA1Mzc1MgogICAgR1JPVU5EX0NPTlRST0xfUE9JTlRTX1ZFUlNJT04gPSA0CiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfTU9ERUwgPSA1NDgKICAgIEdFT01FVFJJQ19STVNFX01PREVMID0gNS44NTcKICAgIEdFT01FVFJJQ19STVNFX01PREVMX1kgPSAzLjg0MQogICAgR0VPTUVUUklDX1JNU0VfTU9ERUxfWCA9IDQuNDIyCiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfVkVSSUZZID0gMjI4CiAgICBHRU9NRVRSSUNfUk1TRV9WRVJJRlkgPSAzLjM4MgogIEVORF9HUk9VUCA9IElNQUdFX0FUVFJJQlVURVMKICBHUk9VUCA9IE1JTl9NQVhfUkFESUFOQ0UKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8xID0gNzUxLjk1NzA5CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMSA9IC02Mi4wOTY4NgogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzIgPSA3NzAuMDEzMTgKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8yID0gLTYzLjU4Nzk0CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfMyA9IDcwOS41NjA2MQogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzMgPSAtNTguNTk1NzUKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF80ID0gNTk4LjM0MTQ5CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNCA9IC00OS40MTEyMwogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzUgPSAzNjYuMTU1MTUKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF81ID0gLTMwLjIzNzIxCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNiA9IDkxLjA1OTQ2CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNiA9IC03LjUxOTcyCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNyA9IDMwLjY5MTkxCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNyA9IC0yLjUzNDU1CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfOCA9IDY3Ny4xNTc4NAogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzggPSAtNTUuOTE5OTIKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF85ID0gMTQzLjEwMTczCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfOSA9IC0xMS44MTczOQogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzEwID0gMjIuMDAxODAKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8xMCA9IDAuMTAwMzMKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8xMSA9IDIyLjAwMTgwCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMTEgPSAwLjEwMDMzCiAgRU5EX0dST1VQID0gTUlOX01BWF9SQURJQU5DRQogIEdST1VQID0gTUlOX01BWF9SRUZMRUNUQU5DRQogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzEgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzEgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF8yID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF8yID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfMyA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfMyA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzQgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzQgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF81ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF81ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfNiA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfNiA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzcgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzcgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF84ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF84ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfOSA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfOSA9IC0wLjA5OTk4MAogIEVORF9HUk9VUCA9IE1JTl9NQVhfUkVGTEVDVEFOQ0UKICBHUk9VUCA9IE1JTl9NQVhfUElYRUxfVkFMVUUKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF8xID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzIgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzIgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMyA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMyA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF80ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF80ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzUgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzUgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfNiA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfNiA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF83ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF83ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzggPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzggPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfOSA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfOSA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xMCA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMTAgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMTEgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzExID0gMQogIEVORF9HUk9VUCA9IE1JTl9NQVhfUElYRUxfVkFMVUUKICBHUk9VUCA9IFJBRElPTUVUUklDX1JFU0NBTElORwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzEgPSAxLjI0MjJFLTAyCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfMiA9IDEuMjcyMEUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF8zID0gMS4xNzIxRS0wMgogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzQgPSA5Ljg4NDJFLTAzCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfNSA9IDYuMDQ4N0UtMDMKICAgIFJBRElBTkNFX01VTFRfQkFORF82ID0gMS41MDQyRS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzcgPSA1LjA3MDFFLTA0CiAgICBSQURJQU5DRV9NVUxUX0JBTkRfOCA9IDEuMTE4NkUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF85ID0gMi4zNjQwRS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzEwID0gMy4zNDIwRS0wNAogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzExID0gMy4zNDIwRS0wNAogICAgUkFESUFOQ0VfQUREX0JBTkRfMSA9IC02Mi4xMDkyOAogICAgUkFESUFOQ0VfQUREX0JBTkRfMiA9IC02My42MDA2NgogICAgUkFESUFOQ0VfQUREX0JBTkRfMyA9IC01OC42MDc0NwogICAgUkFESUFOQ0VfQUREX0JBTkRfNCA9IC00OS40MjExMgogICAgUkFESUFOQ0VfQUREX0JBTkRfNSA9IC0zMC4yNDMyNgogICAgUkFESUFOQ0VfQUREX0JBTkRfNiA9IC03LjUyMTIyCiAgICBSQURJQU5DRV9BRERfQkFORF83ID0gLTIuNTM1MDUKICAgIFJBRElBTkNFX0FERF9CQU5EXzggPSAtNTUuOTMxMTAKICAgIFJBRElBTkNFX0FERF9CQU5EXzkgPSAtMTEuODE5NzUKICAgIFJBRElBTkNFX0FERF9CQU5EXzEwID0gMC4xMDAwMAogICAgUkFESUFOQ0VfQUREX0JBTkRfMTEgPSAwLjEwMDAwCiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfMSA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF8yID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzMgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNCA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF81ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzYgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNyA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF84ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzkgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8xID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8yID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8zID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF80ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF81ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF82ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF83ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF84ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF85ID0gLTAuMTAwMDAwCiAgRU5EX0dST1VQID0gUkFESU9NRVRSSUNfUkVTQ0FMSU5HCiAgR1JPVVAgPSBUSVJTX1RIRVJNQUxfQ09OU1RBTlRTCiAgICBLMV9DT05TVEFOVF9CQU5EXzEwID0gNzc0Ljg4NTMKICAgIEsxX0NPTlNUQU5UX0JBTkRfMTEgPSA0ODAuODg4MwogICAgSzJfQ09OU1RBTlRfQkFORF8xMCA9IDEzMjEuMDc4OQogICAgSzJfQ09OU1RBTlRfQkFORF8xMSA9IDEyMDEuMTQ0MgogIEVORF9HUk9VUCA9IFRJUlNfVEhFUk1BTF9DT05TVEFOVFMKICBHUk9VUCA9IFBST0pFQ1RJT05fUEFSQU1FVEVSUwogICAgTUFQX1BST0pFQ1RJT04gPSAiVVRNIgogICAgREFUVU0gPSAiV0dTODQiCiAgICBFTExJUFNPSUQgPSAiV0dTODQiCiAgICBVVE1fWk9ORSA9IDEwCiAgICBHUklEX0NFTExfU0laRV9QQU5DSFJPTUFUSUMgPSAxNS4wMAogICAgR1JJRF9DRUxMX1NJWkVfUkVGTEVDVElWRSA9IDMwLjAwCiAgICBHUklEX0NFTExfU0laRV9USEVSTUFMID0gMzAuMDAKICAgIE9SSUVOVEFUSU9OID0gIk5PUlRIX1VQIgogICAgUkVTQU1QTElOR19PUFRJT04gPSAiQ1VCSUNfQ09OVk9MVVRJT04iCiAgRU5EX0dST1VQID0gUFJPSkVDVElPTl9QQVJBTUVURVJTCkVORF9HUk9VUCA9IEwxX01FVEFEQVRBX0ZJTEUKRU5ECg==" + } + }, + { + "ID": "bae7504164fe4568", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/gcp-public-data-landsat/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=LC08%2FPRE%2F044%2F034%2FLC80440342016259LGN00%2F\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3371507263865add4d1078e8a59589e5/13924784329696043957;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/gcp-public-data-landsat/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=LC08%2FPRE%2F044%2F034%2FLC80440342016259LGN00%2F\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "12632" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:22 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:22 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Backends": [ + "vnns10:4437,/bns/yx/borg/yx/bns/blobstore2/bitpusher/171.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=MsysW7-rDoGczAK_vZWoDg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/171.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/171:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "GgIYBiAB" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoPpNMEoNzIsY9-tnx866qa9IS5nAVGL55dhuiLW3p0lfLVPHAlqtcguROClEpmEaHifrioDUOBOYq-N7-Al1bMt599WQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxLlRJRi8xNDc1NTk5MTQ0NTc5MDAwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxLlRJRiIsIm5hbWUiOiJMQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEuVElGIiwiYnVja2V0IjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQiLCJnZW5lcmF0aW9uIjoiMTQ3NTU5OTE0NDU3OTAwMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE2LTEwLTA0VDE2OjM5OjA0LjU0NVoiLCJ1cGRhdGVkIjoiMjAxNi0xMC0wNFQxNjozOTowNC41NDVaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6Mzk6MDQuNTQ1WiIsInNpemUiOiI3NDcyMTczNiIsIm1kNUhhc2giOiI4MzVMNkI1ZnJCMHpDQjZzMjJyMlN3PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxLlRJRj9nZW5lcmF0aW9uPTE0NzU1OTkxNDQ1NzkwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoiOTM0QnJnPT0iLCJldGFnIjoiQ0xqZjM1Ykx3YzhDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdC9MQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEwLlRJRi8xNDc1NTk5MzEwMDQyMDAwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMC5USUYiLCJuYW1lIjoiTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMC5USUYiLCJidWNrZXQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdCIsImdlbmVyYXRpb24iOiIxNDc1NTk5MzEwMDQyMDAwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDE6NTAuMDAyWiIsInVwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQxOjUwLjAwMloiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MTo1MC4wMDJaIiwic2l6ZSI6IjU4NjgxMjI4IiwibWQ1SGFzaCI6IkJXNjIzeEhnMTVJaFYyNG1ickwrQXc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEwLlRJRj9nZW5lcmF0aW9uPTE0NzU1OTkzMTAwNDIwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoieHpWMmZnPT0iLCJldGFnIjoiQ0pEbjB1WEx3YzhDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdC9MQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjExLlRJRi8xNDc1NTk5MzE5MTg4MDAwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMS5USUYiLCJuYW1lIjoiTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMS5USUYiLCJidWNrZXQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdCIsImdlbmVyYXRpb24iOiIxNDc1NTk5MzE5MTg4MDAwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDE6NTkuMTQ5WiIsInVwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQxOjU5LjE0OVoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MTo1OS4xNDlaIiwic2l6ZSI6IjU2Nzk2NDM5IiwibWQ1SGFzaCI6IkZPeGl5eEpYcUFmbFJUOGxGblNkT2c9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjExLlRJRj9nZW5lcmF0aW9uPTE0NzU1OTkzMTkxODgwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoicC9IRlZ3PT0iLCJldGFnIjoiQ0tDRWdlckx3YzhDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdC9MQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjIuVElGLzE0NzU1OTkxNjEyMjQwMDAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjIuVElGIiwibmFtZSI6IkxDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9CMi5USUYiLCJidWNrZXQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdCIsImdlbmVyYXRpb24iOiIxNDc1NTk5MTYxMjI0MDAwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTYtMTAtMDRUMTY6Mzk6MjEuMTYwWiIsInVwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjM5OjIxLjE2MFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxNi0xMC0wNFQxNjozOToyMS4xNjBaIiwic2l6ZSI6Ijc3MTQ5NzcxIiwibWQ1SGFzaCI6Ik1QMjJ6ak9vMk5zMGlZNE1UUEpSd0E9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjIuVElGP2dlbmVyYXRpb249MTQ3NTU5OTE2MTIyNDAwMCZhbHQ9bWVkaWEiLCJjcmMzMmMiOiJySThZUmc9PSIsImV0YWciOiJDTURXMTU3THdjOENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdjcC1wdWJsaWMtZGF0YS1sYW5kc2F0L0xDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9CMy5USUYvMTQ3NTU5OTE3ODQzNTAwMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2djcC1wdWJsaWMtZGF0YS1sYW5kc2F0L28vTEMwOCUyRlBSRSUyRjA0NCUyRjAzNCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMF9CMy5USUYiLCJuYW1lIjoiTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IzLlRJRiIsImJ1Y2tldCI6ImdjcC1wdWJsaWMtZGF0YS1sYW5kc2F0IiwiZ2VuZXJhdGlvbiI6IjE0NzU1OTkxNzg0MzUwMDAiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6ImFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbSIsInRpbWVDcmVhdGVkIjoiMjAxNi0xMC0wNFQxNjozOTozOC4zNzZaIiwidXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6Mzk6MzguMzc2WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjM5OjM4LjM3NloiLCJzaXplIjoiODAyOTM2ODciLCJtZDVIYXNoIjoidlFNaUdlRHVCZzZjcjNYc2ZJRWpvUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2djcC1wdWJsaWMtZGF0YS1sYW5kc2F0L28vTEMwOCUyRlBSRSUyRjA0NCUyRjAzNCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMF9CMy5USUY/Z2VuZXJhdGlvbj0xNDc1NTk5MTc4NDM1MDAwJmFsdD1tZWRpYSIsImNyYzMyYyI6InVaQnJuQT09IiwiZXRhZyI6IkNMaVQ4cWJMd2M4Q0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I0LlRJRi8xNDc1NTk5MTk0MjY4MDAwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I0LlRJRiIsIm5hbWUiOiJMQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjQuVElGIiwiYnVja2V0IjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQiLCJnZW5lcmF0aW9uIjoiMTQ3NTU5OTE5NDI2ODAwMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE2LTEwLTA0VDE2OjM5OjU0LjIxMVoiLCJ1cGRhdGVkIjoiMjAxNi0xMC0wNFQxNjozOTo1NC4yMTFaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6Mzk6NTQuMjExWiIsInNpemUiOiI4NDQ5NDM3NSIsIm1kNUhhc2giOiJGV2VWQTAxWk8wK21BK0VSRmN6dWhBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I0LlRJRj9nZW5lcmF0aW9uPTE0NzU1OTkxOTQyNjgwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoiV2VzNW9RPT0iLCJldGFnIjoiQ09EQ3VLN0x3YzhDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdC9MQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjUuVElGLzE0NzU1OTkyMDI5NzkwMDAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjUuVElGIiwibmFtZSI6IkxDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9CNS5USUYiLCJidWNrZXQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdCIsImdlbmVyYXRpb24iOiIxNDc1NTk5MjAyOTc5MDAwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDA6MDIuOTM3WiIsInVwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQwOjAyLjkzN1oiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MDowMi45MzdaIiwic2l6ZSI6Ijg5MzE4NDY3IiwibWQ1SGFzaCI6InA0b3lLSEFHbzVLeTNLZzFUSzFaUXc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjUuVElGP2dlbmVyYXRpb249MTQ3NTU5OTIwMjk3OTAwMCZhbHQ9bWVkaWEiLCJjcmMzMmMiOiJwVFl1dXc9PSIsImV0YWciOiJDTGlaekxMTHdjOENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdjcC1wdWJsaWMtZGF0YS1sYW5kc2F0L0xDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9CNi5USUYvMTQ3NTU5OTIzMzQ4MTAwMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2djcC1wdWJsaWMtZGF0YS1sYW5kc2F0L28vTEMwOCUyRlBSRSUyRjA0NCUyRjAzNCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMF9CNi5USUYiLCJuYW1lIjoiTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I2LlRJRiIsImJ1Y2tldCI6ImdjcC1wdWJsaWMtZGF0YS1sYW5kc2F0IiwiZ2VuZXJhdGlvbiI6IjE0NzU1OTkyMzM0ODEwMDAiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6ImFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbSIsInRpbWVDcmVhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MDozMy4zNDlaIiwidXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDA6MzMuMzQ5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQwOjMzLjM0OVoiLCJzaXplIjoiODk0NjU3NjciLCJtZDVIYXNoIjoiMlo3MkdVT0t0bGd6VDlWUlNHWVhqQT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2djcC1wdWJsaWMtZGF0YS1sYW5kc2F0L28vTEMwOCUyRlBSRSUyRjA0NCUyRjAzNCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMF9CNi5USUY/Z2VuZXJhdGlvbj0xNDc1NTk5MjMzNDgxMDAwJmFsdD1tZWRpYSIsImNyYzMyYyI6IklOWEhiUT09IiwiZXRhZyI6IkNLanlrY0hMd2M4Q0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I3LlRJRi8xNDc1NTk5MjQxMDU1MDAwIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I3LlRJRiIsIm5hbWUiOiJMQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjcuVElGIiwiYnVja2V0IjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQiLCJnZW5lcmF0aW9uIjoiMTQ3NTU5OTI0MTA1NTAwMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQwOjQxLjAyMVoiLCJ1cGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MDo0MS4wMjFaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDA6NDEuMDIxWiIsInNpemUiOiI4NjQ2MjYxNCIsIm1kNUhhc2giOiI4Z1BOUTdRWm9GMkNOWlo5RW1ybG9nPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I3LlRJRj9nZW5lcmF0aW9uPTE0NzU1OTkyNDEwNTUwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoidXdDRCtBPT0iLCJldGFnIjoiQ0ppVzRNVEx3YzhDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdC9MQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjguVElGLzE0NzU1OTkyODEzMzgwMDAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjguVElGIiwibmFtZSI6IkxDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9COC5USUYiLCJidWNrZXQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdCIsImdlbmVyYXRpb24iOiIxNDc1NTk5MjgxMzM4MDAwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDE6MjEuMzAwWiIsInVwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQxOjIxLjMwMFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MToyMS4zMDBaIiwic2l6ZSI6IjMxODg4Nzc3NCIsIm1kNUhhc2giOiJ5Nzk1THJVekJ3azJ0TDZQTTAxY0VBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0I4LlRJRj9nZW5lcmF0aW9uPTE0NzU1OTkyODEzMzgwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoiWjMrWmhRPT0iLCJldGFnIjoiQ0pEdCt0Zkx3YzhDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdC9MQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjkuVElGLzE0NzU1OTkyOTE0MjUwMDAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjkuVElGIiwibmFtZSI6IkxDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9COS5USUYiLCJidWNrZXQiOiJnY3AtcHVibGljLWRhdGEtbGFuZHNhdCIsImdlbmVyYXRpb24iOiIxNDc1NTk5MjkxNDI1MDAwIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDE6MzEuMzYxWiIsInVwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQxOjMxLjM2MVoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MTozMS4zNjFaIiwic2l6ZSI6IjQ0MzA4MjA1IiwibWQ1SGFzaCI6IjVCNDFFMkRCYlk1MnBZUFVHVmg5NWc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjkuVElGP2dlbmVyYXRpb249MTQ3NTU5OTI5MTQyNTAwMCZhbHQ9bWVkaWEiLCJjcmMzMmMiOiJhME9EUXc9PSIsImV0YWciOiJDT2pCNHR6THdjOENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdjcC1wdWJsaWMtZGF0YS1sYW5kc2F0L0xDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9CUUEuVElGLzE0NzU1OTkzMjcyMjIwMDAiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQlFBLlRJRiIsIm5hbWUiOiJMQzA4L1BSRS8wNDQvMDM0L0xDODA0NDAzNDIwMTYyNTlMR04wMC9MQzgwNDQwMzQyMDE2MjU5TEdOMDBfQlFBLlRJRiIsImJ1Y2tldCI6ImdjcC1wdWJsaWMtZGF0YS1sYW5kc2F0IiwiZ2VuZXJhdGlvbiI6IjE0NzU1OTkzMjcyMjIwMDAiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6ImFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbSIsInRpbWVDcmVhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MjowNy4xNTlaIiwidXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDI6MDcuMTU5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQyOjA3LjE1OVoiLCJzaXplIjoiMzM1NDcxOSIsIm1kNUhhc2giOiJ6cWlndmw1RW52bWkvR0xjOHlINTFBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvby9MQzA4JTJGUFJFJTJGMDQ0JTJGMDM0JTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwJTJGTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0JRQS5USUY/Z2VuZXJhdGlvbj0xNDc1NTk5MzI3MjIyMDAwJmFsdD1tZWRpYSIsImNyYzMyYyI6IldPQmdLQT09IiwiZXRhZyI6IkNQQ3g2KzNMd2M4Q0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQvTEMwOC9QUkUvMDQ0LzAzNC9MQzgwNDQwMzQyMDE2MjU5TEdOMDAvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX01UTC50eHQvMTQ3NTU5OTMyNzY2MjAwMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2djcC1wdWJsaWMtZGF0YS1sYW5kc2F0L28vTEMwOCUyRlBSRSUyRjA0NCUyRjAzNCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMCUyRkxDODA0NDAzNDIwMTYyNTlMR04wMF9NVEwudHh0IiwibmFtZSI6IkxDMDgvUFJFLzA0NC8wMzQvTEM4MDQ0MDM0MjAxNjI1OUxHTjAwL0xDODA0NDAzNDIwMTYyNTlMR04wMF9NVEwudHh0IiwiYnVja2V0IjoiZ2NwLXB1YmxpYy1kYXRhLWxhbmRzYXQiLCJnZW5lcmF0aW9uIjoiMTQ3NTU5OTMyNzY2MjAwMCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE2LTEwLTA0VDE2OjQyOjA3LjYxOFoiLCJ1cGRhdGVkIjoiMjAxNi0xMC0wNFQxNjo0MjowNy42MThaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTYtMTAtMDRUMTY6NDI6MDcuNjE4WiIsInNpemUiOiI3OTAzIiwibWQ1SGFzaCI6ImVsL1VkRHZXUjBoZmlFbHZyYkJjVVE9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nY3AtcHVibGljLWRhdGEtbGFuZHNhdC9vL0xDMDglMkZQUkUlMkYwNDQlMkYwMzQlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDAlMkZMQzgwNDQwMzQyMDE2MjU5TEdOMDBfTVRMLnR4dD9nZW5lcmF0aW9uPTE0NzU1OTkzMjc2NjIwMDAmYWx0PW1lZGlhIiwiY3JjMzJjIjoiUFdCdDhnPT0iLCJldGFnIjoiQ0xDZmh1N0x3YzhDRUFFPSJ9XX0=" + } + }, + { + "ID": "c7689e7bd54ed467", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/noauth", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0662fa93d955eeb17a6331e1cf6e0447/15514914763081451604;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/noauth" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "247" + ], + "Content-Type": [ + "application/xml; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:22 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:22 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/2,/bns/xh/borg/xh/bns/blobstore2/bitpusher/8.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=MsysW9eyIO-pswargaYo" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/8.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/8:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqSWX6bbSACxWtisyOqrB0FFhXZvIKKF-1cOgd0ZqNByKVEy5Q1lWj1qHMWRQt3MxzCYbUkOAR2SUmGHE5OR-FZX-WY6Q" + ] + }, + "Body": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0nVVRGLTgnPz48RXJyb3I+PENvZGU+QWNjZXNzRGVuaWVkPC9Db2RlPjxNZXNzYWdlPkFjY2VzcyBkZW5pZWQuPC9NZXNzYWdlPjxEZXRhaWxzPkFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuZ2V0IGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvbm9hdXRoLjwvRGV0YWlscz48L0Vycm9yPg==" + } + }, + { + "ID": "96502a977c21b138", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Content-Type": [ + "multipart/related; boundary=00e007d7435d4eaf0875edb23883d9d4bbfaded1bae201e5f54a947851a5" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "38c6656bc98c27aef7b61563fb1e9022/16346289697710693283;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0wMGUwMDdkNzQzNWQ0ZWFmMDg3NWVkYjIzODgzZDlkNGJiZmFkZWQxYmFlMjAxZTVmNTRhOTQ3ODUxYTUNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJub2F1dGgifQoNCi0tMDBlMDA3ZDc0MzVkNGVhZjA4NzVlZGIyMzg4M2Q5ZDRiYmZhZGVkMWJhZTIwMWU1ZjU0YTk0Nzg1MWE1DQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW4NCg0KYg0KLS0wMGUwMDdkNzQzNWQ0ZWFmMDg3NWVkYjIzODgzZDlkNGJiZmFkZWQxYmFlMjAxZTVmNTRhOTQ3ODUxYTUtLQ0K" + }, + "Response": { + "StatusCode": 401, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "30201" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:23 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "Www-Authenticate": [ + "Bearer realm=\"https://accounts.google.com/\"" + ], + "X-Google-Backends": [ + "vrqn25:4154,/bns/yv/borg/yv/bns/blobstore2/bitpusher/382.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=MsysW8ieMteFggSMxJTIBQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/382.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/382:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "GgIYBiAB" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uqp-fy5ql5YosFNoW2Ob6gd1EZdom7gCNISKx9v42hqbTrP0Q0Cry_pxzCAPHGXPMO8LuXmBEIylU3Z5u2Xcl57AYd52A" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6InJlcXVpcmVkIiwibWVzc2FnZSI6IkFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvbm9hdXRoLiIsImxvY2F0aW9uVHlwZSI6ImhlYWRlciIsImxvY2F0aW9uIjoiQXV0aG9yaXphdGlvbiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL25vYXV0aC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMTcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjUxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUxPR0lOX1JFUVVJUkVELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9TE9HSU5fUkVRVUlSRUQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjE3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo1MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvbm9hdXRoLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz11bmF1dGhvcml6ZWQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLlJFUVVJUkVELCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjE3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo1MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvbm9hdXRoLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPVJFUVVJUkVELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5hdXRoZW50aWNhdGVkX3VzZXIsIG1lc3NhZ2U9QW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9ub2F1dGguLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249aGVhZGVycy5BdXRob3JpemF0aW9uLCBtZXNzYWdlPUFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvbm9hdXRoLiwgcmVhc29uPXJlcXVpcmVkLCBycGNDb2RlPTQwMX0gQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9ub2F1dGguOiBjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjE3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo1MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvbm9hdXRoLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6MjE3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YTo1MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuaW5zZXJ0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo5NSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvbm9hdXRoLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17V1dXLUF1dGhlbnRpY2F0ZT1bQmVhcmVyIHJlYWxtPVwiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tL1wiXX0sIGh0dHBTdGF0dXM9dW5hdXRob3JpemVkLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5SRVFVSVJFRCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvbm9hdXRoLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIxNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NTEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL25vYXV0aC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1SRVFVSVJFRCwgZXJyb3JQcm90b0RvbWFpbj1nZGF0YS5Db3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkuYXV0aGVudGljYXRlZF91c2VyLCBtZXNzYWdlPUFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvbm9hdXRoLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWhlYWRlcnMuQXV0aG9yaXphdGlvbiwgbWVzc2FnZT1Bbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL25vYXV0aC4sIHJlYXNvbj1yZXF1aXJlZCwgcnBjQ29kZT00MDF9IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvbm9hdXRoLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IEFub255bW91cyBjYWxsZXIgZG9lcyBub3QgaGF2ZSBzdG9yYWdlLm9iamVjdHMuY3JlYXRlIGFjY2VzcyB0byBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvbm9hdXRoLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjIxNylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkluc2VydE9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoSW5zZXJ0T2JqZWN0LmphdmE6NTEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmluc2VydChPYmplY3RzRGVsZWdhdG9yLmphdmE6OTUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL25vYXV0aC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5hdXRoLkF1dGhlbnRpY2F0b3JJbnRlcmNlcHRvci5hZGRDaGFsbGVuZ2VIZWFkZXIoQXV0aGVudGljYXRvckludGVyY2VwdG9yLmphdmE6MjY0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuYXV0aC5BdXRoZW50aWNhdG9ySW50ZXJjZXB0b3IucHJvY2Vzc0Vycm9yUmVzcG9uc2UoQXV0aGVudGljYXRvckludGVyY2VwdG9yLmphdmE6MjMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuYXV0aC5HYWlhTWludEludGVyY2VwdG9yLnByb2Nlc3NFcnJvclJlc3BvbnNlKEdhaWFNaW50SW50ZXJjZXB0b3IuamF2YTo3NjQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLmludGVyY2VwdC5Bcm91bmRJbnRlcmNlcHRvcldyYXBwZXIucHJvY2Vzc0Vycm9yUmVzcG9uc2UoQXJvdW5kSW50ZXJjZXB0b3JXcmFwcGVyLmphdmE6MjgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zdGF0cy5TdGF0c0Jvb3RzdHJhcCRJbnRlcmNlcHRvclN0YXRzUmVjb3JkZXIucHJvY2Vzc0Vycm9yUmVzcG9uc2UoU3RhdHNCb290c3RyYXAuamF2YTozMTIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLmludGVyY2VwdC5JbnRlcmNlcHRpb25zJEFyb3VuZEludGVyY2VwdGlvbi5oYW5kbGVFcnJvclJlc3BvbnNlKEludGVyY2VwdGlvbnMuamF2YToyMDIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLmludGVyY2VwdC5JbnRlcmNlcHRpb25zJEFyb3VuZEludGVyY2VwdGlvbi5hY2Nlc3MkMjAwKEludGVyY2VwdGlvbnMuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLmludGVyY2VwdC5JbnRlcmNlcHRpb25zJEFyb3VuZEludGVyY2VwdGlvbiQxLmNhbGwoSW50ZXJjZXB0aW9ucy5qYXZhOjE0NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuaW50ZXJjZXB0LkludGVyY2VwdGlvbnMkQXJvdW5kSW50ZXJjZXB0aW9uJDEuY2FsbChJbnRlcmNlcHRpb25zLmphdmE6MTM3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0RXhjZXB0aW9uKEFic3RyYWN0RnV0dXJlLmphdmE6NzUzKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjY4KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1MT0dJTl9SRVFVSVJFRCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL25vYXV0aC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMTcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjUxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPXVuYXV0aG9yaXplZCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uUkVRVUlSRUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL25vYXV0aC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMTcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjUxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9UkVRVUlSRUQsIGVycm9yUHJvdG9Eb21haW49Z2RhdGEuQ29yZUVycm9yRG9tYWluLCBmaWx0ZXJlZE1lc3NhZ2U9bnVsbCwgbG9jYXRpb249ZW50aXR5LmF1dGhlbnRpY2F0ZWRfdXNlciwgbWVzc2FnZT1Bbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL25vYXV0aC4sIHVubmFtZWRBcmd1bWVudHM9W119LCBsb2NhdGlvbj1oZWFkZXJzLkF1dGhvcml6YXRpb24sIG1lc3NhZ2U9QW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9ub2F1dGguLCByZWFzb249cmVxdWlyZWQsIHJwY0NvZGU9NDAxfSBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL25vYXV0aC46IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBBbm9ueW1vdXMgY2FsbGVyIGRvZXMgbm90IGhhdmUgc3RvcmFnZS5vYmplY3RzLmNyZWF0ZSBhY2Nlc3MgdG8gZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL25vYXV0aC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuSW5zZXJ0T2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChJbnNlcnRPYmplY3QuamF2YToyMTcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5JbnNlcnRPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEluc2VydE9iamVjdC5qYXZhOjUxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5pbnNlcnQoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjk1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9ub2F1dGguXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0Li4uIDE5IG1vcmVcbiJ9XSwiY29kZSI6NDAxLCJtZXNzYWdlIjoiQW5vbnltb3VzIGNhbGxlciBkb2VzIG5vdCBoYXZlIHN0b3JhZ2Uub2JqZWN0cy5jcmVhdGUgYWNjZXNzIHRvIGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9ub2F1dGguIn19" + } + }, + { + "ID": "8607aa9eb0964439", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d93163707f2d013836306547b4dbcd8e/17936700502266216770;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=3600" + ], + "Content-Length": [ + "7903" + ], + "Content-Type": [ + "application/octet-stream" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:23 GMT" + ], + "Etag": [ + "\"7a5fd4743bd647485f88496fadb05c51\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 13:25:23 GMT" + ], + "Last-Modified": [ + "Tue, 04 Oct 2016 16:42:07 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Generation": [ + "1475599327662000" + ], + "X-Goog-Hash": [ + "crc32c=PWBt8g==", + "md5=el/UdDvWR0hfiElvrbBcUQ==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "7903" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/46,/bns/xh/borg/xh/bns/blobstore2/bitpusher/15.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=M8ysW8T2B-ShswbYw67IAw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "570399209098" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/15.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/15:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo3fxL6bHvnU8nsWyoPO4uYF9iyasj5Qltu6jAK4p0aCtdJC8ETwmXOR7L7KeIRvEUUt8ty9hzcDNO535kFdMIU7RPaCg" + ] + }, + "Body": "R1JPVVAgPSBMMV9NRVRBREFUQV9GSUxFCiAgR1JPVVAgPSBNRVRBREFUQV9GSUxFX0lORk8KICAgIE9SSUdJTiA9ICJJbWFnZSBjb3VydGVzeSBvZiB0aGUgVS5TLiBHZW9sb2dpY2FsIFN1cnZleSIKICAgIFJFUVVFU1RfSUQgPSAiMDcwMTYwOTE5MTA1MV8wMDAwNCIKICAgIExBTkRTQVRfU0NFTkVfSUQgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwIgogICAgRklMRV9EQVRFID0gMjAxNi0wOS0yMFQwMzoxMzowMloKICAgIFNUQVRJT05fSUQgPSAiTEdOIgogICAgUFJPQ0VTU0lOR19TT0ZUV0FSRV9WRVJTSU9OID0gIkxQR1NfMi42LjIiCiAgRU5EX0dST1VQID0gTUVUQURBVEFfRklMRV9JTkZPCiAgR1JPVVAgPSBQUk9EVUNUX01FVEFEQVRBCiAgICBEQVRBX1RZUEUgPSAiTDFUIgogICAgRUxFVkFUSU9OX1NPVVJDRSA9ICJHTFMyMDAwIgogICAgT1VUUFVUX0ZPUk1BVCA9ICJHRU9USUZGIgogICAgU1BBQ0VDUkFGVF9JRCA9ICJMQU5EU0FUXzgiCiAgICBTRU5TT1JfSUQgPSAiT0xJX1RJUlMiCiAgICBXUlNfUEFUSCA9IDQ0CiAgICBXUlNfUk9XID0gMzQKICAgIE5BRElSX09GRk5BRElSID0gIk5BRElSIgogICAgVEFSR0VUX1dSU19QQVRIID0gNDQKICAgIFRBUkdFVF9XUlNfUk9XID0gMzQKICAgIERBVEVfQUNRVUlSRUQgPSAyMDE2LTA5LTE1CiAgICBTQ0VORV9DRU5URVJfVElNRSA9ICIxODo0NjoxOC42ODY3MzgwWiIKICAgIENPUk5FUl9VTF9MQVRfUFJPRFVDVCA9IDM4LjUyODE5CiAgICBDT1JORVJfVUxfTE9OX1BST0RVQ1QgPSAtMTIzLjQwODQzCiAgICBDT1JORVJfVVJfTEFUX1BST0RVQ1QgPSAzOC41MDc2NQogICAgQ09STkVSX1VSX0xPTl9QUk9EVUNUID0gLTEyMC43NjkzMwogICAgQ09STkVSX0xMX0xBVF9QUk9EVUNUID0gMzYuNDE2MzMKICAgIENPUk5FUl9MTF9MT05fUFJPRFVDVCA9IC0xMjMuMzk3MDkKICAgIENPUk5FUl9MUl9MQVRfUFJPRFVDVCA9IDM2LjM5NzI5CiAgICBDT1JORVJfTFJfTE9OX1BST0RVQ1QgPSAtMTIwLjgzMTE3CiAgICBDT1JORVJfVUxfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA0NjQ0MDAuMDAwCiAgICBDT1JORVJfVUxfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MjY0NTAwLjAwMAogICAgQ09STkVSX1VSX1BST0pFQ1RJT05fWF9QUk9EVUNUID0gNjk0NTAwLjAwMAogICAgQ09STkVSX1VSX1BST0pFQ1RJT05fWV9QUk9EVUNUID0gNDI2NDUwMC4wMDAKICAgIENPUk5FUl9MTF9QUk9KRUNUSU9OX1hfUFJPRFVDVCA9IDQ2NDQwMC4wMDAKICAgIENPUk5FUl9MTF9QUk9KRUNUSU9OX1lfUFJPRFVDVCA9IDQwMzAyMDAuMDAwCiAgICBDT1JORVJfTFJfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA2OTQ1MDAuMDAwCiAgICBDT1JORVJfTFJfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MDMwMjAwLjAwMAogICAgUEFOQ0hST01BVElDX0xJTkVTID0gMTU2MjEKICAgIFBBTkNIUk9NQVRJQ19TQU1QTEVTID0gMTUzNDEKICAgIFJFRkxFQ1RJVkVfTElORVMgPSA3ODExCiAgICBSRUZMRUNUSVZFX1NBTVBMRVMgPSA3NjcxCiAgICBUSEVSTUFMX0xJTkVTID0gNzgxMQogICAgVEhFUk1BTF9TQU1QTEVTID0gNzY3MQogICAgRklMRV9OQU1FX0JBTkRfMSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMiA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjIuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMyA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjMuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjQuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjUuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNiA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjYuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNyA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjcuVElGIgogICAgRklMRV9OQU1FX0JBTkRfOCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjguVElGIgogICAgRklMRV9OQU1FX0JBTkRfOSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjkuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMTAgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMC5USUYiCiAgICBGSUxFX05BTUVfQkFORF8xMSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjExLlRJRiIKICAgIEZJTEVfTkFNRV9CQU5EX1FVQUxJVFkgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0JRQS5USUYiCiAgICBNRVRBREFUQV9GSUxFX05BTUUgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX01UTC50eHQiCiAgICBCUEZfTkFNRV9PTEkgPSAiTE84QlBGMjAxNjA5MTUxODMwNTdfMjAxNjA5MTUyMDA5NTAuMDEiCiAgICBCUEZfTkFNRV9USVJTID0gIkxUOEJQRjIwMTYwOTAyMDg0MTIyXzIwMTYwOTE3MDc0MDI3LjAyIgogICAgQ1BGX05BTUUgPSAiTDhDUEYyMDE2MDcwMV8yMDE2MDkzMC4wMiIKICAgIFJMVVRfRklMRV9OQU1FID0gIkw4UkxVVDIwMTUwMzAzXzIwNDMxMjMxdjExLmg1IgogIEVORF9HUk9VUCA9IFBST0RVQ1RfTUVUQURBVEEKICBHUk9VUCA9IElNQUdFX0FUVFJJQlVURVMKICAgIENMT1VEX0NPVkVSID0gMjkuNTYKICAgIENMT1VEX0NPVkVSX0xBTkQgPSAzLjMzCiAgICBJTUFHRV9RVUFMSVRZX09MSSA9IDkKICAgIElNQUdFX1FVQUxJVFlfVElSUyA9IDkKICAgIFRJUlNfU1NNX01PREVMID0gIkZJTkFMIgogICAgVElSU19TU01fUE9TSVRJT05fU1RBVFVTID0gIkVTVElNQVRFRCIKICAgIFJPTExfQU5HTEUgPSAtMC4wMDEKICAgIFNVTl9BWklNVVRIID0gMTQ4LjQ4MDQ5Mzk2CiAgICBTVU5fRUxFVkFUSU9OID0gNTAuOTM3NjgzOTkKICAgIEVBUlRIX1NVTl9ESVNUQU5DRSA9IDEuMDA1Mzc1MgogICAgR1JPVU5EX0NPTlRST0xfUE9JTlRTX1ZFUlNJT04gPSA0CiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfTU9ERUwgPSA1NDgKICAgIEdFT01FVFJJQ19STVNFX01PREVMID0gNS44NTcKICAgIEdFT01FVFJJQ19STVNFX01PREVMX1kgPSAzLjg0MQogICAgR0VPTUVUUklDX1JNU0VfTU9ERUxfWCA9IDQuNDIyCiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfVkVSSUZZID0gMjI4CiAgICBHRU9NRVRSSUNfUk1TRV9WRVJJRlkgPSAzLjM4MgogIEVORF9HUk9VUCA9IElNQUdFX0FUVFJJQlVURVMKICBHUk9VUCA9IE1JTl9NQVhfUkFESUFOQ0UKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8xID0gNzUxLjk1NzA5CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMSA9IC02Mi4wOTY4NgogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzIgPSA3NzAuMDEzMTgKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8yID0gLTYzLjU4Nzk0CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfMyA9IDcwOS41NjA2MQogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzMgPSAtNTguNTk1NzUKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF80ID0gNTk4LjM0MTQ5CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNCA9IC00OS40MTEyMwogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzUgPSAzNjYuMTU1MTUKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF81ID0gLTMwLjIzNzIxCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNiA9IDkxLjA1OTQ2CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNiA9IC03LjUxOTcyCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNyA9IDMwLjY5MTkxCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNyA9IC0yLjUzNDU1CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfOCA9IDY3Ny4xNTc4NAogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzggPSAtNTUuOTE5OTIKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF85ID0gMTQzLjEwMTczCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfOSA9IC0xMS44MTczOQogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzEwID0gMjIuMDAxODAKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8xMCA9IDAuMTAwMzMKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8xMSA9IDIyLjAwMTgwCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMTEgPSAwLjEwMDMzCiAgRU5EX0dST1VQID0gTUlOX01BWF9SQURJQU5DRQogIEdST1VQID0gTUlOX01BWF9SRUZMRUNUQU5DRQogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzEgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzEgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF8yID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF8yID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfMyA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfMyA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzQgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzQgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF81ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF81ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfNiA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfNiA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzcgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzcgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF84ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF84ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfOSA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfOSA9IC0wLjA5OTk4MAogIEVORF9HUk9VUCA9IE1JTl9NQVhfUkVGTEVDVEFOQ0UKICBHUk9VUCA9IE1JTl9NQVhfUElYRUxfVkFMVUUKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF8xID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzIgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzIgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMyA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMyA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF80ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF80ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzUgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzUgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfNiA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfNiA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF83ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF83ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzggPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzggPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfOSA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfOSA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xMCA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMTAgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMTEgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzExID0gMQogIEVORF9HUk9VUCA9IE1JTl9NQVhfUElYRUxfVkFMVUUKICBHUk9VUCA9IFJBRElPTUVUUklDX1JFU0NBTElORwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzEgPSAxLjI0MjJFLTAyCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfMiA9IDEuMjcyMEUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF8zID0gMS4xNzIxRS0wMgogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzQgPSA5Ljg4NDJFLTAzCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfNSA9IDYuMDQ4N0UtMDMKICAgIFJBRElBTkNFX01VTFRfQkFORF82ID0gMS41MDQyRS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzcgPSA1LjA3MDFFLTA0CiAgICBSQURJQU5DRV9NVUxUX0JBTkRfOCA9IDEuMTE4NkUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF85ID0gMi4zNjQwRS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzEwID0gMy4zNDIwRS0wNAogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzExID0gMy4zNDIwRS0wNAogICAgUkFESUFOQ0VfQUREX0JBTkRfMSA9IC02Mi4xMDkyOAogICAgUkFESUFOQ0VfQUREX0JBTkRfMiA9IC02My42MDA2NgogICAgUkFESUFOQ0VfQUREX0JBTkRfMyA9IC01OC42MDc0NwogICAgUkFESUFOQ0VfQUREX0JBTkRfNCA9IC00OS40MjExMgogICAgUkFESUFOQ0VfQUREX0JBTkRfNSA9IC0zMC4yNDMyNgogICAgUkFESUFOQ0VfQUREX0JBTkRfNiA9IC03LjUyMTIyCiAgICBSQURJQU5DRV9BRERfQkFORF83ID0gLTIuNTM1MDUKICAgIFJBRElBTkNFX0FERF9CQU5EXzggPSAtNTUuOTMxMTAKICAgIFJBRElBTkNFX0FERF9CQU5EXzkgPSAtMTEuODE5NzUKICAgIFJBRElBTkNFX0FERF9CQU5EXzEwID0gMC4xMDAwMAogICAgUkFESUFOQ0VfQUREX0JBTkRfMTEgPSAwLjEwMDAwCiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfMSA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF8yID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzMgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNCA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF81ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzYgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNyA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF84ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzkgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8xID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8yID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8zID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF80ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF81ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF82ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF83ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF84ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF85ID0gLTAuMTAwMDAwCiAgRU5EX0dST1VQID0gUkFESU9NRVRSSUNfUkVTQ0FMSU5HCiAgR1JPVVAgPSBUSVJTX1RIRVJNQUxfQ09OU1RBTlRTCiAgICBLMV9DT05TVEFOVF9CQU5EXzEwID0gNzc0Ljg4NTMKICAgIEsxX0NPTlNUQU5UX0JBTkRfMTEgPSA0ODAuODg4MwogICAgSzJfQ09OU1RBTlRfQkFORF8xMCA9IDEzMjEuMDc4OQogICAgSzJfQ09OU1RBTlRfQkFORF8xMSA9IDEyMDEuMTQ0MgogIEVORF9HUk9VUCA9IFRJUlNfVEhFUk1BTF9DT05TVEFOVFMKICBHUk9VUCA9IFBST0pFQ1RJT05fUEFSQU1FVEVSUwogICAgTUFQX1BST0pFQ1RJT04gPSAiVVRNIgogICAgREFUVU0gPSAiV0dTODQiCiAgICBFTExJUFNPSUQgPSAiV0dTODQiCiAgICBVVE1fWk9ORSA9IDEwCiAgICBHUklEX0NFTExfU0laRV9QQU5DSFJPTUFUSUMgPSAxNS4wMAogICAgR1JJRF9DRUxMX1NJWkVfUkVGTEVDVElWRSA9IDMwLjAwCiAgICBHUklEX0NFTExfU0laRV9USEVSTUFMID0gMzAuMDAKICAgIE9SSUVOVEFUSU9OID0gIk5PUlRIX1VQIgogICAgUkVTQU1QTElOR19PUFRJT04gPSAiQ1VCSUNfQ09OVk9MVVRJT04iCiAgRU5EX0dST1VQID0gUFJPSkVDVElPTl9QQVJBTUVURVJTCkVORF9HUk9VUCA9IEwxX01FVEFEQVRBX0ZJTEUKRU5ECg==" + } + }, + { + "ID": "e2c9f4af9bbfcf61", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "69db1d4acd1dab1a05e8020d75e69a96/1080368332623947488;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=3600" + ], + "Content-Length": [ + "7903" + ], + "Content-Type": [ + "application/octet-stream" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:23 GMT" + ], + "Etag": [ + "\"7a5fd4743bd647485f88496fadb05c51\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 13:25:23 GMT" + ], + "Last-Modified": [ + "Tue, 04 Oct 2016 16:42:07 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Generation": [ + "1475599327662000" + ], + "X-Goog-Hash": [ + "crc32c=PWBt8g==", + "md5=el/UdDvWR0hfiElvrbBcUQ==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "7903" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/38,/bns/xh/borg/xh/bns/blobstore2/bitpusher/68.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=M8ysW9CvC8GtswbB8IvgCQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "570399209098" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/68.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/68:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrHSEfW3gOHJga9kM0Pmg6J0nyVfHMmECSPbLUU9cgmDPy1u4tlWjQr1iWWGrmDplvE3AqXPnIH9B0qW2KILY169X1coQ" + ] + }, + "Body": "R1JPVVAgPSBMMV9NRVRBREFUQV9GSUxFCiAgR1JPVVAgPSBNRVRBREFUQV9GSUxFX0lORk8KICAgIE9SSUdJTiA9ICJJbWFnZSBjb3VydGVzeSBvZiB0aGUgVS5TLiBHZW9sb2dpY2FsIFN1cnZleSIKICAgIFJFUVVFU1RfSUQgPSAiMDcwMTYwOTE5MTA1MV8wMDAwNCIKICAgIExBTkRTQVRfU0NFTkVfSUQgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwIgogICAgRklMRV9EQVRFID0gMjAxNi0wOS0yMFQwMzoxMzowMloKICAgIFNUQVRJT05fSUQgPSAiTEdOIgogICAgUFJPQ0VTU0lOR19TT0ZUV0FSRV9WRVJTSU9OID0gIkxQR1NfMi42LjIiCiAgRU5EX0dST1VQID0gTUVUQURBVEFfRklMRV9JTkZPCiAgR1JPVVAgPSBQUk9EVUNUX01FVEFEQVRBCiAgICBEQVRBX1RZUEUgPSAiTDFUIgogICAgRUxFVkFUSU9OX1NPVVJDRSA9ICJHTFMyMDAwIgogICAgT1VUUFVUX0ZPUk1BVCA9ICJHRU9USUZGIgogICAgU1BBQ0VDUkFGVF9JRCA9ICJMQU5EU0FUXzgiCiAgICBTRU5TT1JfSUQgPSAiT0xJX1RJUlMiCiAgICBXUlNfUEFUSCA9IDQ0CiAgICBXUlNfUk9XID0gMzQKICAgIE5BRElSX09GRk5BRElSID0gIk5BRElSIgogICAgVEFSR0VUX1dSU19QQVRIID0gNDQKICAgIFRBUkdFVF9XUlNfUk9XID0gMzQKICAgIERBVEVfQUNRVUlSRUQgPSAyMDE2LTA5LTE1CiAgICBTQ0VORV9DRU5URVJfVElNRSA9ICIxODo0NjoxOC42ODY3MzgwWiIKICAgIENPUk5FUl9VTF9MQVRfUFJPRFVDVCA9IDM4LjUyODE5CiAgICBDT1JORVJfVUxfTE9OX1BST0RVQ1QgPSAtMTIzLjQwODQzCiAgICBDT1JORVJfVVJfTEFUX1BST0RVQ1QgPSAzOC41MDc2NQogICAgQ09STkVSX1VSX0xPTl9QUk9EVUNUID0gLTEyMC43NjkzMwogICAgQ09STkVSX0xMX0xBVF9QUk9EVUNUID0gMzYuNDE2MzMKICAgIENPUk5FUl9MTF9MT05fUFJPRFVDVCA9IC0xMjMuMzk3MDkKICAgIENPUk5FUl9MUl9MQVRfUFJPRFVDVCA9IDM2LjM5NzI5CiAgICBDT1JORVJfTFJfTE9OX1BST0RVQ1QgPSAtMTIwLjgzMTE3CiAgICBDT1JORVJfVUxfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA0NjQ0MDAuMDAwCiAgICBDT1JORVJfVUxfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MjY0NTAwLjAwMAogICAgQ09STkVSX1VSX1BST0pFQ1RJT05fWF9QUk9EVUNUID0gNjk0NTAwLjAwMAogICAgQ09STkVSX1VSX1BST0pFQ1RJT05fWV9QUk9EVUNUID0gNDI2NDUwMC4wMDAKICAgIENPUk5FUl9MTF9QUk9KRUNUSU9OX1hfUFJPRFVDVCA9IDQ2NDQwMC4wMDAKICAgIENPUk5FUl9MTF9QUk9KRUNUSU9OX1lfUFJPRFVDVCA9IDQwMzAyMDAuMDAwCiAgICBDT1JORVJfTFJfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA2OTQ1MDAuMDAwCiAgICBDT1JORVJfTFJfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MDMwMjAwLjAwMAogICAgUEFOQ0hST01BVElDX0xJTkVTID0gMTU2MjEKICAgIFBBTkNIUk9NQVRJQ19TQU1QTEVTID0gMTUzNDEKICAgIFJFRkxFQ1RJVkVfTElORVMgPSA3ODExCiAgICBSRUZMRUNUSVZFX1NBTVBMRVMgPSA3NjcxCiAgICBUSEVSTUFMX0xJTkVTID0gNzgxMQogICAgVEhFUk1BTF9TQU1QTEVTID0gNzY3MQogICAgRklMRV9OQU1FX0JBTkRfMSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMiA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjIuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMyA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjMuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjQuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjUuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNiA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjYuVElGIgogICAgRklMRV9OQU1FX0JBTkRfNyA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjcuVElGIgogICAgRklMRV9OQU1FX0JBTkRfOCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjguVElGIgogICAgRklMRV9OQU1FX0JBTkRfOSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjkuVElGIgogICAgRklMRV9OQU1FX0JBTkRfMTAgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0IxMC5USUYiCiAgICBGSUxFX05BTUVfQkFORF8xMSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjExLlRJRiIKICAgIEZJTEVfTkFNRV9CQU5EX1FVQUxJVFkgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX0JRQS5USUYiCiAgICBNRVRBREFUQV9GSUxFX05BTUUgPSAiTEM4MDQ0MDM0MjAxNjI1OUxHTjAwX01UTC50eHQiCiAgICBCUEZfTkFNRV9PTEkgPSAiTE84QlBGMjAxNjA5MTUxODMwNTdfMjAxNjA5MTUyMDA5NTAuMDEiCiAgICBCUEZfTkFNRV9USVJTID0gIkxUOEJQRjIwMTYwOTAyMDg0MTIyXzIwMTYwOTE3MDc0MDI3LjAyIgogICAgQ1BGX05BTUUgPSAiTDhDUEYyMDE2MDcwMV8yMDE2MDkzMC4wMiIKICAgIFJMVVRfRklMRV9OQU1FID0gIkw4UkxVVDIwMTUwMzAzXzIwNDMxMjMxdjExLmg1IgogIEVORF9HUk9VUCA9IFBST0RVQ1RfTUVUQURBVEEKICBHUk9VUCA9IElNQUdFX0FUVFJJQlVURVMKICAgIENMT1VEX0NPVkVSID0gMjkuNTYKICAgIENMT1VEX0NPVkVSX0xBTkQgPSAzLjMzCiAgICBJTUFHRV9RVUFMSVRZX09MSSA9IDkKICAgIElNQUdFX1FVQUxJVFlfVElSUyA9IDkKICAgIFRJUlNfU1NNX01PREVMID0gIkZJTkFMIgogICAgVElSU19TU01fUE9TSVRJT05fU1RBVFVTID0gIkVTVElNQVRFRCIKICAgIFJPTExfQU5HTEUgPSAtMC4wMDEKICAgIFNVTl9BWklNVVRIID0gMTQ4LjQ4MDQ5Mzk2CiAgICBTVU5fRUxFVkFUSU9OID0gNTAuOTM3NjgzOTkKICAgIEVBUlRIX1NVTl9ESVNUQU5DRSA9IDEuMDA1Mzc1MgogICAgR1JPVU5EX0NPTlRST0xfUE9JTlRTX1ZFUlNJT04gPSA0CiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfTU9ERUwgPSA1NDgKICAgIEdFT01FVFJJQ19STVNFX01PREVMID0gNS44NTcKICAgIEdFT01FVFJJQ19STVNFX01PREVMX1kgPSAzLjg0MQogICAgR0VPTUVUUklDX1JNU0VfTU9ERUxfWCA9IDQuNDIyCiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfVkVSSUZZID0gMjI4CiAgICBHRU9NRVRSSUNfUk1TRV9WRVJJRlkgPSAzLjM4MgogIEVORF9HUk9VUCA9IElNQUdFX0FUVFJJQlVURVMKICBHUk9VUCA9IE1JTl9NQVhfUkFESUFOQ0UKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8xID0gNzUxLjk1NzA5CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMSA9IC02Mi4wOTY4NgogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzIgPSA3NzAuMDEzMTgKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8yID0gLTYzLjU4Nzk0CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfMyA9IDcwOS41NjA2MQogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzMgPSAtNTguNTk1NzUKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF80ID0gNTk4LjM0MTQ5CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNCA9IC00OS40MTEyMwogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzUgPSAzNjYuMTU1MTUKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF81ID0gLTMwLjIzNzIxCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNiA9IDkxLjA1OTQ2CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNiA9IC03LjUxOTcyCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNyA9IDMwLjY5MTkxCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfNyA9IC0yLjUzNDU1CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfOCA9IDY3Ny4xNTc4NAogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzggPSAtNTUuOTE5OTIKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF85ID0gMTQzLjEwMTczCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfOSA9IC0xMS44MTczOQogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzEwID0gMjIuMDAxODAKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8xMCA9IDAuMTAwMzMKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8xMSA9IDIyLjAwMTgwCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMTEgPSAwLjEwMDMzCiAgRU5EX0dST1VQID0gTUlOX01BWF9SQURJQU5DRQogIEdST1VQID0gTUlOX01BWF9SRUZMRUNUQU5DRQogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzEgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzEgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF8yID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF8yID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfMyA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfMyA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzQgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzQgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF81ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF81ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfNiA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfNiA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzcgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzcgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF84ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF84ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfOSA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfOSA9IC0wLjA5OTk4MAogIEVORF9HUk9VUCA9IE1JTl9NQVhfUkVGTEVDVEFOQ0UKICBHUk9VUCA9IE1JTl9NQVhfUElYRUxfVkFMVUUKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF8xID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzIgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzIgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMyA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMyA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF80ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF80ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzUgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzUgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfNiA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfNiA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF83ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF83ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzggPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzggPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfOSA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfOSA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xMCA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMTAgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMTEgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzExID0gMQogIEVORF9HUk9VUCA9IE1JTl9NQVhfUElYRUxfVkFMVUUKICBHUk9VUCA9IFJBRElPTUVUUklDX1JFU0NBTElORwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzEgPSAxLjI0MjJFLTAyCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfMiA9IDEuMjcyMEUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF8zID0gMS4xNzIxRS0wMgogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzQgPSA5Ljg4NDJFLTAzCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfNSA9IDYuMDQ4N0UtMDMKICAgIFJBRElBTkNFX01VTFRfQkFORF82ID0gMS41MDQyRS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzcgPSA1LjA3MDFFLTA0CiAgICBSQURJQU5DRV9NVUxUX0JBTkRfOCA9IDEuMTE4NkUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF85ID0gMi4zNjQwRS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzEwID0gMy4zNDIwRS0wNAogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzExID0gMy4zNDIwRS0wNAogICAgUkFESUFOQ0VfQUREX0JBTkRfMSA9IC02Mi4xMDkyOAogICAgUkFESUFOQ0VfQUREX0JBTkRfMiA9IC02My42MDA2NgogICAgUkFESUFOQ0VfQUREX0JBTkRfMyA9IC01OC42MDc0NwogICAgUkFESUFOQ0VfQUREX0JBTkRfNCA9IC00OS40MjExMgogICAgUkFESUFOQ0VfQUREX0JBTkRfNSA9IC0zMC4yNDMyNgogICAgUkFESUFOQ0VfQUREX0JBTkRfNiA9IC03LjUyMTIyCiAgICBSQURJQU5DRV9BRERfQkFORF83ID0gLTIuNTM1MDUKICAgIFJBRElBTkNFX0FERF9CQU5EXzggPSAtNTUuOTMxMTAKICAgIFJBRElBTkNFX0FERF9CQU5EXzkgPSAtMTEuODE5NzUKICAgIFJBRElBTkNFX0FERF9CQU5EXzEwID0gMC4xMDAwMAogICAgUkFESUFOQ0VfQUREX0JBTkRfMTEgPSAwLjEwMDAwCiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfMSA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF8yID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzMgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNCA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF81ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzYgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNyA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF84ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzkgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8xID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8yID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF8zID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF80ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF81ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF82ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF83ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF84ID0gLTAuMTAwMDAwCiAgICBSRUZMRUNUQU5DRV9BRERfQkFORF85ID0gLTAuMTAwMDAwCiAgRU5EX0dST1VQID0gUkFESU9NRVRSSUNfUkVTQ0FMSU5HCiAgR1JPVVAgPSBUSVJTX1RIRVJNQUxfQ09OU1RBTlRTCiAgICBLMV9DT05TVEFOVF9CQU5EXzEwID0gNzc0Ljg4NTMKICAgIEsxX0NPTlNUQU5UX0JBTkRfMTEgPSA0ODAuODg4MwogICAgSzJfQ09OU1RBTlRfQkFORF8xMCA9IDEzMjEuMDc4OQogICAgSzJfQ09OU1RBTlRfQkFORF8xMSA9IDEyMDEuMTQ0MgogIEVORF9HUk9VUCA9IFRJUlNfVEhFUk1BTF9DT05TVEFOVFMKICBHUk9VUCA9IFBST0pFQ1RJT05fUEFSQU1FVEVSUwogICAgTUFQX1BST0pFQ1RJT04gPSAiVVRNIgogICAgREFUVU0gPSAiV0dTODQiCiAgICBFTExJUFNPSUQgPSAiV0dTODQiCiAgICBVVE1fWk9ORSA9IDEwCiAgICBHUklEX0NFTExfU0laRV9QQU5DSFJPTUFUSUMgPSAxNS4wMAogICAgR1JJRF9DRUxMX1NJWkVfUkVGTEVDVElWRSA9IDMwLjAwCiAgICBHUklEX0NFTExfU0laRV9USEVSTUFMID0gMzAuMDAKICAgIE9SSUVOVEFUSU9OID0gIk5PUlRIX1VQIgogICAgUkVTQU1QTElOR19PUFRJT04gPSAiQ1VCSUNfQ09OVk9MVVRJT04iCiAgRU5EX0dST1VQID0gUFJPSkVDVElPTl9QQVJBTUVURVJTCkVORF9HUk9VUCA9IEwxX01FVEFEQVRBX0ZJTEUKRU5ECg==" + } + }, + { + "ID": "29af8223e2f49bec", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt", + "Proto": "HTTP/1.1", + "Header": { + "Range": [ + "bytes=1-" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4db663877b8e7c5ce86381f47f69dc9b/2598723742148021375;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 206, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=3600" + ], + "Content-Length": [ + "7902" + ], + "Content-Range": [ + "bytes 1-7902/7903" + ], + "Content-Type": [ + "application/octet-stream" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:23 GMT" + ], + "Etag": [ + "\"7a5fd4743bd647485f88496fadb05c51\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 13:25:23 GMT" + ], + "Last-Modified": [ + "Tue, 04 Oct 2016 16:42:07 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Generation": [ + "1475599327662000" + ], + "X-Goog-Hash": [ + "crc32c=PWBt8g==", + "md5=el/UdDvWR0hfiElvrbBcUQ==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "7903" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/11,/bns/xh/borg/xh/bns/blobstore2/bitpusher/20.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=M8ysW_K3DsesswbQ_qAo" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "570399209098" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/20.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/20:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrRbfvlTsqaOds6NXN9V0K3HKwwKP_aBuUP58gtsNFXA6Gi_ax4I6i1qLfhCvzKZkkBnu7C5O-C1rd5h_N3_zzQjwYIhg" + ] + }, + "Body": "Uk9VUCA9IEwxX01FVEFEQVRBX0ZJTEUKICBHUk9VUCA9IE1FVEFEQVRBX0ZJTEVfSU5GTwogICAgT1JJR0lOID0gIkltYWdlIGNvdXJ0ZXN5IG9mIHRoZSBVLlMuIEdlb2xvZ2ljYWwgU3VydmV5IgogICAgUkVRVUVTVF9JRCA9ICIwNzAxNjA5MTkxMDUxXzAwMDA0IgogICAgTEFORFNBVF9TQ0VORV9JRCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDAiCiAgICBGSUxFX0RBVEUgPSAyMDE2LTA5LTIwVDAzOjEzOjAyWgogICAgU1RBVElPTl9JRCA9ICJMR04iCiAgICBQUk9DRVNTSU5HX1NPRlRXQVJFX1ZFUlNJT04gPSAiTFBHU18yLjYuMiIKICBFTkRfR1JPVVAgPSBNRVRBREFUQV9GSUxFX0lORk8KICBHUk9VUCA9IFBST0RVQ1RfTUVUQURBVEEKICAgIERBVEFfVFlQRSA9ICJMMVQiCiAgICBFTEVWQVRJT05fU09VUkNFID0gIkdMUzIwMDAiCiAgICBPVVRQVVRfRk9STUFUID0gIkdFT1RJRkYiCiAgICBTUEFDRUNSQUZUX0lEID0gIkxBTkRTQVRfOCIKICAgIFNFTlNPUl9JRCA9ICJPTElfVElSUyIKICAgIFdSU19QQVRIID0gNDQKICAgIFdSU19ST1cgPSAzNAogICAgTkFESVJfT0ZGTkFESVIgPSAiTkFESVIiCiAgICBUQVJHRVRfV1JTX1BBVEggPSA0NAogICAgVEFSR0VUX1dSU19ST1cgPSAzNAogICAgREFURV9BQ1FVSVJFRCA9IDIwMTYtMDktMTUKICAgIFNDRU5FX0NFTlRFUl9USU1FID0gIjE4OjQ2OjE4LjY4NjczODBaIgogICAgQ09STkVSX1VMX0xBVF9QUk9EVUNUID0gMzguNTI4MTkKICAgIENPUk5FUl9VTF9MT05fUFJPRFVDVCA9IC0xMjMuNDA4NDMKICAgIENPUk5FUl9VUl9MQVRfUFJPRFVDVCA9IDM4LjUwNzY1CiAgICBDT1JORVJfVVJfTE9OX1BST0RVQ1QgPSAtMTIwLjc2OTMzCiAgICBDT1JORVJfTExfTEFUX1BST0RVQ1QgPSAzNi40MTYzMwogICAgQ09STkVSX0xMX0xPTl9QUk9EVUNUID0gLTEyMy4zOTcwOQogICAgQ09STkVSX0xSX0xBVF9QUk9EVUNUID0gMzYuMzk3MjkKICAgIENPUk5FUl9MUl9MT05fUFJPRFVDVCA9IC0xMjAuODMxMTcKICAgIENPUk5FUl9VTF9QUk9KRUNUSU9OX1hfUFJPRFVDVCA9IDQ2NDQwMC4wMDAKICAgIENPUk5FUl9VTF9QUk9KRUNUSU9OX1lfUFJPRFVDVCA9IDQyNjQ1MDAuMDAwCiAgICBDT1JORVJfVVJfUFJPSkVDVElPTl9YX1BST0RVQ1QgPSA2OTQ1MDAuMDAwCiAgICBDT1JORVJfVVJfUFJPSkVDVElPTl9ZX1BST0RVQ1QgPSA0MjY0NTAwLjAwMAogICAgQ09STkVSX0xMX1BST0pFQ1RJT05fWF9QUk9EVUNUID0gNDY0NDAwLjAwMAogICAgQ09STkVSX0xMX1BST0pFQ1RJT05fWV9QUk9EVUNUID0gNDAzMDIwMC4wMDAKICAgIENPUk5FUl9MUl9QUk9KRUNUSU9OX1hfUFJPRFVDVCA9IDY5NDUwMC4wMDAKICAgIENPUk5FUl9MUl9QUk9KRUNUSU9OX1lfUFJPRFVDVCA9IDQwMzAyMDAuMDAwCiAgICBQQU5DSFJPTUFUSUNfTElORVMgPSAxNTYyMQogICAgUEFOQ0hST01BVElDX1NBTVBMRVMgPSAxNTM0MQogICAgUkVGTEVDVElWRV9MSU5FUyA9IDc4MTEKICAgIFJFRkxFQ1RJVkVfU0FNUExFUyA9IDc2NzEKICAgIFRIRVJNQUxfTElORVMgPSA3ODExCiAgICBUSEVSTUFMX1NBTVBMRVMgPSA3NjcxCiAgICBGSUxFX05BTUVfQkFORF8xID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CMS5USUYiCiAgICBGSUxFX05BTUVfQkFORF8yID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CMi5USUYiCiAgICBGSUxFX05BTUVfQkFORF8zID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CMy5USUYiCiAgICBGSUxFX05BTUVfQkFORF80ID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CNC5USUYiCiAgICBGSUxFX05BTUVfQkFORF81ID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CNS5USUYiCiAgICBGSUxFX05BTUVfQkFORF82ID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CNi5USUYiCiAgICBGSUxFX05BTUVfQkFORF83ID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CNy5USUYiCiAgICBGSUxFX05BTUVfQkFORF84ID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9COC5USUYiCiAgICBGSUxFX05BTUVfQkFORF85ID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9COS5USUYiCiAgICBGSUxFX05BTUVfQkFORF8xMCA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQjEwLlRJRiIKICAgIEZJTEVfTkFNRV9CQU5EXzExID0gIkxDODA0NDAzNDIwMTYyNTlMR04wMF9CMTEuVElGIgogICAgRklMRV9OQU1FX0JBTkRfUVVBTElUWSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfQlFBLlRJRiIKICAgIE1FVEFEQVRBX0ZJTEVfTkFNRSA9ICJMQzgwNDQwMzQyMDE2MjU5TEdOMDBfTVRMLnR4dCIKICAgIEJQRl9OQU1FX09MSSA9ICJMTzhCUEYyMDE2MDkxNTE4MzA1N18yMDE2MDkxNTIwMDk1MC4wMSIKICAgIEJQRl9OQU1FX1RJUlMgPSAiTFQ4QlBGMjAxNjA5MDIwODQxMjJfMjAxNjA5MTcwNzQwMjcuMDIiCiAgICBDUEZfTkFNRSA9ICJMOENQRjIwMTYwNzAxXzIwMTYwOTMwLjAyIgogICAgUkxVVF9GSUxFX05BTUUgPSAiTDhSTFVUMjAxNTAzMDNfMjA0MzEyMzF2MTEuaDUiCiAgRU5EX0dST1VQID0gUFJPRFVDVF9NRVRBREFUQQogIEdST1VQID0gSU1BR0VfQVRUUklCVVRFUwogICAgQ0xPVURfQ09WRVIgPSAyOS41NgogICAgQ0xPVURfQ09WRVJfTEFORCA9IDMuMzMKICAgIElNQUdFX1FVQUxJVFlfT0xJID0gOQogICAgSU1BR0VfUVVBTElUWV9USVJTID0gOQogICAgVElSU19TU01fTU9ERUwgPSAiRklOQUwiCiAgICBUSVJTX1NTTV9QT1NJVElPTl9TVEFUVVMgPSAiRVNUSU1BVEVEIgogICAgUk9MTF9BTkdMRSA9IC0wLjAwMQogICAgU1VOX0FaSU1VVEggPSAxNDguNDgwNDkzOTYKICAgIFNVTl9FTEVWQVRJT04gPSA1MC45Mzc2ODM5OQogICAgRUFSVEhfU1VOX0RJU1RBTkNFID0gMS4wMDUzNzUyCiAgICBHUk9VTkRfQ09OVFJPTF9QT0lOVFNfVkVSU0lPTiA9IDQKICAgIEdST1VORF9DT05UUk9MX1BPSU5UU19NT0RFTCA9IDU0OAogICAgR0VPTUVUUklDX1JNU0VfTU9ERUwgPSA1Ljg1NwogICAgR0VPTUVUUklDX1JNU0VfTU9ERUxfWSA9IDMuODQxCiAgICBHRU9NRVRSSUNfUk1TRV9NT0RFTF9YID0gNC40MjIKICAgIEdST1VORF9DT05UUk9MX1BPSU5UU19WRVJJRlkgPSAyMjgKICAgIEdFT01FVFJJQ19STVNFX1ZFUklGWSA9IDMuMzgyCiAgRU5EX0dST1VQID0gSU1BR0VfQVRUUklCVVRFUwogIEdST1VQID0gTUlOX01BWF9SQURJQU5DRQogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzEgPSA3NTEuOTU3MDkKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8xID0gLTYyLjA5Njg2CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfMiA9IDc3MC4wMTMxOAogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzIgPSAtNjMuNTg3OTQKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF8zID0gNzA5LjU2MDYxCiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfMyA9IC01OC41OTU3NQogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzQgPSA1OTguMzQxNDkKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF80ID0gLTQ5LjQxMTIzCiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfNSA9IDM2Ni4xNTUxNQogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzUgPSAtMzAuMjM3MjEKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF82ID0gOTEuMDU5NDYKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF82ID0gLTcuNTE5NzIKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF83ID0gMzAuNjkxOTEKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF83ID0gLTIuNTM0NTUKICAgIFJBRElBTkNFX01BWElNVU1fQkFORF84ID0gNjc3LjE1Nzg0CiAgICBSQURJQU5DRV9NSU5JTVVNX0JBTkRfOCA9IC01NS45MTk5MgogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzkgPSAxNDMuMTAxNzMKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF85ID0gLTExLjgxNzM5CiAgICBSQURJQU5DRV9NQVhJTVVNX0JBTkRfMTAgPSAyMi4wMDE4MAogICAgUkFESUFOQ0VfTUlOSU1VTV9CQU5EXzEwID0gMC4xMDAzMwogICAgUkFESUFOQ0VfTUFYSU1VTV9CQU5EXzExID0gMjIuMDAxODAKICAgIFJBRElBTkNFX01JTklNVU1fQkFORF8xMSA9IDAuMTAwMzMKICBFTkRfR1JPVVAgPSBNSU5fTUFYX1JBRElBTkNFCiAgR1JPVVAgPSBNSU5fTUFYX1JFRkxFQ1RBTkNFCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfMSA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfMSA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzIgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzIgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF8zID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF8zID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfNCA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfNCA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzUgPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzUgPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF82ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF82ID0gLTAuMDk5OTgwCiAgICBSRUZMRUNUQU5DRV9NQVhJTVVNX0JBTkRfNyA9IDEuMjEwNzAwCiAgICBSRUZMRUNUQU5DRV9NSU5JTVVNX0JBTkRfNyA9IC0wLjA5OTk4MAogICAgUkVGTEVDVEFOQ0VfTUFYSU1VTV9CQU5EXzggPSAxLjIxMDcwMAogICAgUkVGTEVDVEFOQ0VfTUlOSU1VTV9CQU5EXzggPSAtMC4wOTk5ODAKICAgIFJFRkxFQ1RBTkNFX01BWElNVU1fQkFORF85ID0gMS4yMTA3MDAKICAgIFJFRkxFQ1RBTkNFX01JTklNVU1fQkFORF85ID0gLTAuMDk5OTgwCiAgRU5EX0dST1VQID0gTUlOX01BWF9SRUZMRUNUQU5DRQogIEdST1VQID0gTUlOX01BWF9QSVhFTF9WQUxVRQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzEgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzEgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfMiA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMiA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8zID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF8zID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzQgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzQgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfNSA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfNSA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF82ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF82ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzcgPSA2NTUzNQogICAgUVVBTlRJWkVfQ0FMX01JTl9CQU5EXzcgPSAxCiAgICBRVUFOVElaRV9DQUxfTUFYX0JBTkRfOCA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfOCA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF85ID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF85ID0gMQogICAgUVVBTlRJWkVfQ0FMX01BWF9CQU5EXzEwID0gNjU1MzUKICAgIFFVQU5USVpFX0NBTF9NSU5fQkFORF8xMCA9IDEKICAgIFFVQU5USVpFX0NBTF9NQVhfQkFORF8xMSA9IDY1NTM1CiAgICBRVUFOVElaRV9DQUxfTUlOX0JBTkRfMTEgPSAxCiAgRU5EX0dST1VQID0gTUlOX01BWF9QSVhFTF9WQUxVRQogIEdST1VQID0gUkFESU9NRVRSSUNfUkVTQ0FMSU5HCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfMSA9IDEuMjQyMkUtMDIKICAgIFJBRElBTkNFX01VTFRfQkFORF8yID0gMS4yNzIwRS0wMgogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzMgPSAxLjE3MjFFLTAyCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfNCA9IDkuODg0MkUtMDMKICAgIFJBRElBTkNFX01VTFRfQkFORF81ID0gNi4wNDg3RS0wMwogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzYgPSAxLjUwNDJFLTAzCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfNyA9IDUuMDcwMUUtMDQKICAgIFJBRElBTkNFX01VTFRfQkFORF84ID0gMS4xMTg2RS0wMgogICAgUkFESUFOQ0VfTVVMVF9CQU5EXzkgPSAyLjM2NDBFLTAzCiAgICBSQURJQU5DRV9NVUxUX0JBTkRfMTAgPSAzLjM0MjBFLTA0CiAgICBSQURJQU5DRV9NVUxUX0JBTkRfMTEgPSAzLjM0MjBFLTA0CiAgICBSQURJQU5DRV9BRERfQkFORF8xID0gLTYyLjEwOTI4CiAgICBSQURJQU5DRV9BRERfQkFORF8yID0gLTYzLjYwMDY2CiAgICBSQURJQU5DRV9BRERfQkFORF8zID0gLTU4LjYwNzQ3CiAgICBSQURJQU5DRV9BRERfQkFORF80ID0gLTQ5LjQyMTEyCiAgICBSQURJQU5DRV9BRERfQkFORF81ID0gLTMwLjI0MzI2CiAgICBSQURJQU5DRV9BRERfQkFORF82ID0gLTcuNTIxMjIKICAgIFJBRElBTkNFX0FERF9CQU5EXzcgPSAtMi41MzUwNQogICAgUkFESUFOQ0VfQUREX0JBTkRfOCA9IC01NS45MzExMAogICAgUkFESUFOQ0VfQUREX0JBTkRfOSA9IC0xMS44MTk3NQogICAgUkFESUFOQ0VfQUREX0JBTkRfMTAgPSAwLjEwMDAwCiAgICBSQURJQU5DRV9BRERfQkFORF8xMSA9IDAuMTAwMDAKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF8xID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzIgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfMyA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF80ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzUgPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfNiA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX01VTFRfQkFORF83ID0gMi4wMDAwRS0wNQogICAgUkVGTEVDVEFOQ0VfTVVMVF9CQU5EXzggPSAyLjAwMDBFLTA1CiAgICBSRUZMRUNUQU5DRV9NVUxUX0JBTkRfOSA9IDIuMDAwMEUtMDUKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzEgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzIgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzMgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzQgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzUgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzYgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzcgPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzggPSAtMC4xMDAwMDAKICAgIFJFRkxFQ1RBTkNFX0FERF9CQU5EXzkgPSAtMC4xMDAwMDAKICBFTkRfR1JPVVAgPSBSQURJT01FVFJJQ19SRVNDQUxJTkcKICBHUk9VUCA9IFRJUlNfVEhFUk1BTF9DT05TVEFOVFMKICAgIEsxX0NPTlNUQU5UX0JBTkRfMTAgPSA3NzQuODg1MwogICAgSzFfQ09OU1RBTlRfQkFORF8xMSA9IDQ4MC44ODgzCiAgICBLMl9DT05TVEFOVF9CQU5EXzEwID0gMTMyMS4wNzg5CiAgICBLMl9DT05TVEFOVF9CQU5EXzExID0gMTIwMS4xNDQyCiAgRU5EX0dST1VQID0gVElSU19USEVSTUFMX0NPTlNUQU5UUwogIEdST1VQID0gUFJPSkVDVElPTl9QQVJBTUVURVJTCiAgICBNQVBfUFJPSkVDVElPTiA9ICJVVE0iCiAgICBEQVRVTSA9ICJXR1M4NCIKICAgIEVMTElQU09JRCA9ICJXR1M4NCIKICAgIFVUTV9aT05FID0gMTAKICAgIEdSSURfQ0VMTF9TSVpFX1BBTkNIUk9NQVRJQyA9IDE1LjAwCiAgICBHUklEX0NFTExfU0laRV9SRUZMRUNUSVZFID0gMzAuMDAKICAgIEdSSURfQ0VMTF9TSVpFX1RIRVJNQUwgPSAzMC4wMAogICAgT1JJRU5UQVRJT04gPSAiTk9SVEhfVVAiCiAgICBSRVNBTVBMSU5HX09QVElPTiA9ICJDVUJJQ19DT05WT0xVVElPTiIKICBFTkRfR1JPVVAgPSBQUk9KRUNUSU9OX1BBUkFNRVRFUlMKRU5EX0dST1VQID0gTDFfTUVUQURBVEFfRklMRQpFTkQK" + } + }, + { + "ID": "a5cc268bb6d1901b", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt", + "Proto": "HTTP/1.1", + "Header": { + "Range": [ + "bytes=0-17" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "09ad91b6f03772df950fe8e60e38b515/4189135646215237917;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/gcp-public-data-landsat/LC08/PRE/044/034/LC80440342016259LGN00/LC80440342016259LGN00_MTL.txt" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 206, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=3600" + ], + "Content-Length": [ + "18" + ], + "Content-Range": [ + "bytes 0-17/7903" + ], + "Content-Type": [ + "application/octet-stream" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:23 GMT" + ], + "Etag": [ + "\"7a5fd4743bd647485f88496fadb05c51\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 13:25:23 GMT" + ], + "Last-Modified": [ + "Tue, 04 Oct 2016 16:42:07 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Generation": [ + "1475599327662000" + ], + "X-Goog-Hash": [ + "crc32c=PWBt8g==", + "md5=el/UdDvWR0hfiElvrbBcUQ==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "7903" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/9,/bns/xh/borg/xh/bns/blobstore2/bitpusher/84.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=M8ysW6m8Ee6iswap5okY" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "570399209098" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/84.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/84:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqkVgj_WF9UVLkpunOc4f5drxYHK8wCMGJ7_8XXUZHjlPkkeMgAoXxEItBA_PzaL4caKEF9IdpCYBJ3TGiRJVImw-TsSw" + ] + }, + "Body": "R1JPVVAgPSBMMV9NRVRBREFU" + } + }, + { + "ID": "574c045ea3cf3804", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/storage-library-test-bucket/gzipped-text.txt", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "da531b177a2f61995e226a1dbd8bddba/5779266075288967100;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/storage-library-test-bucket/gzipped-text.txt" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=3600" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:23 GMT" + ], + "Etag": [ + "\"c6117833aa4d1510d09ef69144d56790\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 13:25:23 GMT" + ], + "Last-Modified": [ + "Tue, 14 Nov 2017 13:07:32 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Accept-Encoding" + ], + "X-Goog-Generation": [ + "1510664852486988" + ], + "X-Goog-Hash": [ + "crc32c=T1s5RQ==", + "md5=xhF4M6pNFRDQnvaRRNVnkA==" + ], + "X-Goog-Metageneration": [ + "2" + ], + "X-Goog-Storage-Class": [ + "MULTI_REGIONAL" + ], + "X-Goog-Stored-Content-Encoding": [ + "gzip" + ], + "X-Goog-Stored-Content-Length": [ + "31" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/34,/bns/xh/borg/xh/bns/blobstore2/bitpusher/70.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=M8ysW4fJE4-nswav84G4Aw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "149776848335" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/70.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Body-Transformations": [ + "chunked" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/70:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo9Aj65b1Br7RgKAI30zOrcX8vmaoramy1cI5Ecx8HOMYG4EgpcqnaTGYdlH3irWvCrEeseqO2eVWcLhXryI224usemaQ" + ] + }, + "Body": "H4sIAAAAAAAAC8tIzcnJVyjPL8pJAQCFEUoNCwAAAA==" + } + }, + { + "ID": "027b227c73085f2e", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/storage-library-test-bucket/gzipped-text.txt", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "6e48de6be47e1726efca75ecf91cc67f/7369676879861267547;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/storage-library-test-bucket/gzipped-text.txt" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=3600" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:23 GMT" + ], + "Etag": [ + "\"c6117833aa4d1510d09ef69144d56790\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 13:25:23 GMT" + ], + "Last-Modified": [ + "Tue, 14 Nov 2017 13:07:32 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Accept-Encoding" + ], + "X-Goog-Generation": [ + "1510664852486988" + ], + "X-Goog-Hash": [ + "crc32c=T1s5RQ==", + "md5=xhF4M6pNFRDQnvaRRNVnkA==" + ], + "X-Goog-Metageneration": [ + "2" + ], + "X-Goog-Storage-Class": [ + "MULTI_REGIONAL" + ], + "X-Goog-Stored-Content-Encoding": [ + "gzip" + ], + "X-Goog-Stored-Content-Length": [ + "31" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/10,/bns/xh/borg/xh/bns/blobstore2/bitpusher/29.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=M8ysW42-IqunswbA1YPwDQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "149776848335" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/29.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Body-Transformations": [ + "chunked" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/29:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqNTsfcXgqxyenoWbH8XJlTngFOKqu9awa6fdF9AQIuGB20Yt5aSpNaZW5_v89qJTm-X1F0f9wI_IuIjUYNTUmTc5uHYw" + ] + }, + "Body": "H4sIAAAAAAAAC8tIzcnJVyjPL8pJAQCFEUoNCwAAAA==" + } + }, + { + "ID": "65a7840a56398b21", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/storage-library-test-bucket/gzipped-text.txt", + "Proto": "HTTP/1.1", + "Header": { + "Range": [ + "bytes=1-8" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3766269e952d05c271145eb0fd87c8ee/8960088783911707385;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/storage-library-test-bucket/gzipped-text.txt" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=3600" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:23 GMT" + ], + "Etag": [ + "W/\"c6117833aa4d1510d09ef69144d56790\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 13:25:23 GMT" + ], + "Last-Modified": [ + "Tue, 14 Nov 2017 13:07:32 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Accept-Encoding" + ], + "Warning": [ + "214 UploadServer gunzipped" + ], + "X-Goog-Generation": [ + "1510664852486988" + ], + "X-Goog-Hash": [ + "crc32c=T1s5RQ==", + "md5=xhF4M6pNFRDQnvaRRNVnkA==" + ], + "X-Goog-Metageneration": [ + "2" + ], + "X-Goog-Storage-Class": [ + "MULTI_REGIONAL" + ], + "X-Goog-Stored-Content-Encoding": [ + "gzip" + ], + "X-Goog-Stored-Content-Length": [ + "31" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/45,/bns/xh/borg/xh/bns/blobstore2/bitpusher/80.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=M8ysW57NJc6kswbMy5uwDQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "149776848335" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/80.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/80:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Response-Body-Transformations": [ + "gunzipped" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoCc2I6_fp7BwCazBRuRPMhs5e3Cb1CjNL8hf2WwiHrn7M9O2VYBnD8dGiXXE7OjpzmNwMs_p79POAwtNGqirsz6xeq_g" + ] + }, + "Body": "aGVsbG8gd29ybGQ=" + } + }, + { + "ID": "f4246d20764d26ad", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/storage-library-test-bucket/gzipped-text.txt", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Range": [ + "bytes=1-8" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e75f866fd5e45b56d113d16373ec968e/10550500683683956632;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/storage-library-test-bucket/gzipped-text.txt" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 206, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=3600" + ], + "Content-Encoding": [ + "gzip" + ], + "Content-Range": [ + "bytes 1-8/31" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:23 GMT" + ], + "Etag": [ + "\"c6117833aa4d1510d09ef69144d56790\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 13:25:23 GMT" + ], + "Last-Modified": [ + "Tue, 14 Nov 2017 13:07:32 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Accept-Encoding" + ], + "X-Goog-Generation": [ + "1510664852486988" + ], + "X-Goog-Hash": [ + "crc32c=T1s5RQ==", + "md5=xhF4M6pNFRDQnvaRRNVnkA==" + ], + "X-Goog-Metageneration": [ + "2" + ], + "X-Goog-Storage-Class": [ + "MULTI_REGIONAL" + ], + "X-Goog-Stored-Content-Encoding": [ + "gzip" + ], + "X-Goog-Stored-Content-Length": [ + "31" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/36,/bns/xh/borg/xh/bns/blobstore2/bitpusher/25.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=M8ysW7TbLsuiswbL5ISoCw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "149776848335" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/25.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Body-Transformations": [ + "chunked" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/25:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqAL855d-gxFgB7THGC-650cvXihw5lB59ggNnDFfjg6XIgDXyuFTpLW-pmFjXgB8CNqbblqfCMo_-TRThQ1RXYXnsZvA" + ] + }, + "Body": "iwgAAAAAAAA=" + } + }, + { + "ID": "a51b58139c178bc6", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "168" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e7e4e8d35d137df1fe1d2c0195b8596f/12899949557172305798;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJjb3JzIjpbeyJtYXhBZ2VTZWNvbmRzIjozNjAwLCJtZXRob2QiOlsiUE9TVCJdLCJvcmlnaW4iOlsic29tZS1vcmlnaW4uY29tIl0sInJlc3BvbnNlSGVhZGVyIjpbImZvby1iYXIiXX1dLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA0In0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "534" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:24 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051423000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vncf185:4324,/bns/yx/borg/yx/bns/blobstore2/bitpusher/43.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=M8ysW5ehOszUzwKklI3gBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/43.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/43:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWXA3ZUxTdWNBTVN4aWpIaGJ4VldlcTlheV9Zb3I5dEQ4cFplQ0NNUklKLXJMQ29yX2JvaXdtdVhYRGNISTRfdURWYUtTRHVfVFhtWTl4dXBBOC1JUGZudFFaRnRLOTNlbTg3ZTNlbUFkYjFaUVA3cWo5Mjg0YmM3cllER3ZKRUFrZ0tVT1FiWUZJcmtReWs5WFZIZEpKOHd2NmJPX3FGNl9pZ2Uxcl8yX0pLb2dfenJSUHJlU2JnYUEwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up-M82G1RCRAc4_k2TYOnb54Ji0mbQimQSLP7qmP1TJf7ZRPv4LLs5J5r7Hq4Rdkww8v4v9YsGo_Un_5Pzb_4JhXoxKGg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDQiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MjQuNTg1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjI0LjU4NVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwiY29ycyI6W3sib3JpZ2luIjpbInNvbWUtb3JpZ2luLmNvbSJdLCJtZXRob2QiOlsiUE9TVCJdLCJyZXNwb25zZUhlYWRlciI6WyJmb28tYmFyIl0sIm1heEFnZVNlY29uZHMiOjM2MDB9XSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "42f28f433400a58f", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0004?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "99" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3f718e5ff9b55972984cc82b6fbdcae7/14490079990540936485;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0004?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJjb3JzIjpbeyJtYXhBZ2VTZWNvbmRzIjozNjAwLCJtZXRob2QiOlsiR0VUIl0sIm9yaWdpbiI6WyIqIl0sInJlc3BvbnNlSGVhZGVyIjpbInNvbWUtaGVhZGVyIl19XX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2450" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:26 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051425000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnu199:4210,/bns/yx/borg/yx/bns/blobstore2/bitpusher/22.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=NMysW-G4MY3kzgKkyrfoBQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/22.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/22:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWXA3ZUxTdWNBTVN4aWpIaGJ4VldlcTlheV9Zb3I5dEQ4cFplQ0NNUklKLXJMQ29yX2JvaXdtdVhYRGNISTRfdURWYUtTRHVfVFhtWTl4dXBBOC1JUGZudFFaRnRLOTNlbTg3ZTNlbUFkYjFaUVA3cWo5Mjg0YmM3cllER3ZKRUFrZ0tVT1FiWUZJcmtReWs5WFZIZEpKOHd2NmJPX3FGNl9pZ2Uxcl8yX0pLb2dfenJSUHJlU2JnYUEwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpCe8icExj8XMpYK1TObRcXWmSYabbYDaYeKKLNa4ElTNYmug1iz39xmlHlwvVla0d8DUorCDA1nCJfEmcy28KN9CoA-A" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDQiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MjQuNTg1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjI2LjI4NloiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDQvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDQvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA0L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDQiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsImNvcnMiOlt7Im9yaWdpbiI6WyIqIl0sIm1ldGhvZCI6WyJHRVQiXSwicmVzcG9uc2VIZWFkZXIiOlsic29tZS1oZWFkZXIiXSwibWF4QWdlU2Vjb25kcyI6MzYwMH1dLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" + } + }, + { + "ID": "38e349c8d229e705", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0004?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "95faa0d1e208bca5ba1106e6ea570244/16080490790818400963;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0004?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2450" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:26 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:26 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051426000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrcb128:4027,/bns/yv/borg/yv/bns/blobstore2/bitpusher/190.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=NsysW8OWHoOxgAT7pqv4Bg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/190.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/190:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWXA3ZUxTdWNBTVN4aWpIaGJ4VldlcTlheV9Zb3I5dEQ4cFplQ0NNUklKLXJMQ29yX2JvaXdtdVhYRGNISTRfdURWYUtTRHVfVFhtWTl4dXBBOC1JUGZudFFaRnRLOTNlbTg3ZTNlbUFkYjFaUVA3cWo5Mjg0YmM3cllER3ZKRUFrZ0tVT1FiWUZJcmtReWs5WFZIZEpKOHd2NmJPX3FGNl9pZ2Uxcl8yX0pLb2dfenJSUHJlU2JnYUEwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur_SZVOmSR3gw9aBQWrXPXpmAsXUZBMfCAN8ENQ_RN82GUM4ABJX22dwPm4swzz7-fMmky7rvfvKnYnl6_c6YJ9j07hrw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDQiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MjQuNTg1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjI2LjI4NloiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDQvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDQvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA0L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDQiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsImNvcnMiOlt7Im9yaWdpbiI6WyIqIl0sIm1ldGhvZCI6WyJHRVQiXSwicmVzcG9uc2VIZWFkZXIiOlsic29tZS1oZWFkZXIiXSwibWF4QWdlU2Vjb25kcyI6MzYwMH1dLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" + } + }, + { + "ID": "201a3cf4195f61d8", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "168" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "c3052cb0ee7da0aa57130dd12681b838/17670902694868775010;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJjb3JzIjpbeyJtYXhBZ2VTZWNvbmRzIjozNjAwLCJtZXRob2QiOlsiUE9TVCJdLCJvcmlnaW4iOlsic29tZS1vcmlnaW4uY29tIl0sInJlc3BvbnNlSGVhZGVyIjpbImZvby1iYXIiXX1dLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA1In0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "534" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:27 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051426000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrnj6:4466,/bns/yr/borg/yr/bns/blobstore2/bitpusher/84.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=NsysW5DdN8zukAPMwpbQAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/84.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/84:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWXA3ZUxTdWNBTVN4aWpIaGJ4VldlcTlheV9Zb3I5dEQ4cFplQ0NNUklKLXJMQ29yX2JvaXdtdVhYRGNISTRfdURWYUtTRHVfVFhtWTl4dXBBOC1JUGZudFFaRnRLOTNlbTg3ZTNlbUFkYjFaUVA3cWo5Mjg0YmM3cllER3ZKRUFrZ0tVT1FiWUZJcmtReWs5WFZIZEpKOHd2NmJPX3FGNl9pZ2Uxcl8yX0pLb2dfenJSUHJlU2JnYUEwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoG59nolJu6P0lapnCNLBjPlFcDG0CVkGRFPV3BFR1UfhJQCi9yzi6WMFaNAMnYw9Bb3a-9hRBOBzwpOb4uVLG_EE92Eg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDUiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MjcuMzU5WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjI3LjM1OVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwiY29ycyI6W3sib3JpZ2luIjpbInNvbWUtb3JpZ2luLmNvbSJdLCJtZXRob2QiOlsiUE9TVCJdLCJyZXNwb25zZUhlYWRlciI6WyJmb28tYmFyIl0sIm1heEFnZVNlY29uZHMiOjM2MDB9XSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "eb6d0b7663c27948", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0005?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "12" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b6ba08a729c3d3528af9897e48ea3fa4/814852000203085057;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0005?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJjb3JzIjpbXX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2353" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:29 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051428000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbj188:4240,/bns/yv/borg/yv/bns/blobstore2/bitpusher/68.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=N8ysW_irKov0ggTO1KqQAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/68.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/68:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWXA3ZUxTdWNBTVN4aWpIaGJ4VldlcTlheV9Zb3I5dEQ4cFplQ0NNUklKLXJMQ29yX2JvaXdtdVhYRGNISTRfdURWYUtTRHVfVFhtWTl4dXBBOC1JUGZudFFaRnRLOTNlbTg3ZTNlbUFkYjFaUVA3cWo5Mjg0YmM3cllER3ZKRUFrZ0tVT1FiWUZJcmtReWs5WFZIZEpKOHd2NmJPX3FGNl9pZ2Uxcl8yX0pLb2dfenJSUHJlU2JnYUEwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpV3QRgy3NWsoMryLKJvL-m47BJL6PJuLe0N1ojy-oAm-7ejokRnRHuXMf5DomXVKnET0EIQVCK6D2oh0QWy5bDHA9vYg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDUiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MjcuMzU5WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjI5LjEyNloiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDUvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDUvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA1L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "cdf00ab26a2eecdb", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0005?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1cea50076c2bab86b3ce930141093eab/2404982433571781535;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0005?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2353" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:29 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:29 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051426000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vryy20:4108,/bns/yv/borg/yv/bns/blobstore2/bitpusher/192.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=OcysW7DjFMHMggTy3YG4Bw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/192.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/192:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWXA3ZUxTdWNBTVN4aWpIaGJ4VldlcTlheV9Zb3I5dEQ4cFplQ0NNUklKLXJMQ29yX2JvaXdtdVhYRGNISTRfdURWYUtTRHVfVFhtWTl4dXBBOC1JUGZudFFaRnRLOTNlbTg3ZTNlbUFkYjFaUVA3cWo5Mjg0YmM3cllER3ZKRUFrZ0tVT1FiWUZJcmtReWs5WFZIZEpKOHd2NmJPX3FGNl9pZ2Uxcl8yX0pLb2dfenJSUHJlU2JnYUEwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpyfPH9R-BUYTQzVBjOfEEm9o1nvg54Vz71KBk2t11KwyBI2oi6DYTIPU9Cup_5FPyy5kh-VfhAstvK1mjD1YQx-RPgkw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDUiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MjcuMzU5WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjI5LjEyNloiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDUvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDUvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA1L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "f9c38c019794b168", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "168" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "8295ef2a2a15de2124b88197b9465c54/3995394333344030782;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJjb3JzIjpbeyJtYXhBZ2VTZWNvbmRzIjozNjAwLCJtZXRob2QiOlsiUE9TVCJdLCJvcmlnaW4iOlsic29tZS1vcmlnaW4uY29tIl0sInJlc3BvbnNlSGVhZGVyIjpbImZvby1iYXIiXX1dLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA2In0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "534" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:30 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051426000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrqe11:4421,/bns/yv/borg/yv/bns/blobstore2/bitpusher/396.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=OcysW86nJZGegQT-37-ACg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/396.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/396:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWXA3ZUxTdWNBTVN4aWpIaGJ4VldlcTlheV9Zb3I5dEQ4cFplQ0NNUklKLXJMQ29yX2JvaXdtdVhYRGNISTRfdURWYUtTRHVfVFhtWTl4dXBBOC1JUGZudFFaRnRLOTNlbTg3ZTNlbUFkYjFaUVA3cWo5Mjg0YmM3cllER3ZKRUFrZ0tVT1FiWUZJcmtReWs5WFZIZEpKOHd2NmJPX3FGNl9pZ2Uxcl8yX0pLb2dfenJSUHJlU2JnYUEwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo_my9bAu29KvP4rzQoJzMdiiYYqWd8m1uzJtVPqV3kOjqBRbGx8OquWEnvo1F7y7f6PVuoXBgsm9NPw2yJ6o6aWH2PkA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDYiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MzAuMDczWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjMwLjA3M1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwiY29ycyI6W3sib3JpZ2luIjpbInNvbWUtb3JpZ2luLmNvbSJdLCJtZXRob2QiOlsiUE9TVCJdLCJyZXNwb25zZUhlYWRlciI6WyJmb28tYmFyIl0sIm1heEFnZVNlY29uZHMiOjM2MDB9XSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "5d0109fed5cee25f", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0006?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4a0a65366ac125c025782d5fd149b821/5585805137899554525;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0006?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2461" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:31 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051425000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnqq187:4192,/bns/yx/borg/yx/bns/blobstore2/bitpusher/119.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=OsysW7_8EcTazALWu7ngBw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/119.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/119:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWXA3ZUxTdWNBTVN4aWpIaGJ4VldlcTlheV9Zb3I5dEQ4cFplQ0NNUklKLXJMQ29yX2JvaXdtdVhYRGNISTRfdURWYUtTRHVfVFhtWTl4dXBBOC1JUGZudFFaRnRLOTNlbTg3ZTNlbUFkYjFaUVA3cWo5Mjg0YmM3cllER3ZKRUFrZ0tVT1FiWUZJcmtReWs5WFZIZEpKOHd2NmJPX3FGNl9pZ2Uxcl8yX0pLb2dfenJSUHJlU2JnYUEwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoOkjse13ks1uQtqU-WbIvtpBa6yVJ6A5Qp1A2-N34QjdmA2cc9r6ndxNskGAEOHhNXZUOmh8jUb5P9eV9ZEMwkMiG7IQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDYiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MzAuMDczWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjMxLjcxOVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNi9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDYiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDYvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDYvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA2L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDYiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsImNvcnMiOlt7Im9yaWdpbiI6WyJzb21lLW9yaWdpbi5jb20iXSwibWV0aG9kIjpbIlBPU1QiXSwicmVzcG9uc2VIZWFkZXIiOlsiZm9vLWJhciJdLCJtYXhBZ2VTZWNvbmRzIjozNjAwfV0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "483300c086bf9ae9", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0006?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "675dc0a89aa84ed882e3a11dfc3730f2/7175935571285027707;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0006?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2461" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:32 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:32 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051426000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrnb2:4089,/bns/yr/borg/yr/bns/blobstore2/bitpusher/100.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=O8ysW7TNOM3WkAPE_IHQBA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/100.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/100:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWXA3ZUxTdWNBTVN4aWpIaGJ4VldlcTlheV9Zb3I5dEQ4cFplQ0NNUklKLXJMQ29yX2JvaXdtdVhYRGNISTRfdURWYUtTRHVfVFhtWTl4dXBBOC1JUGZudFFaRnRLOTNlbTg3ZTNlbUFkYjFaUVA3cWo5Mjg0YmM3cllER3ZKRUFrZ0tVT1FiWUZJcmtReWs5WFZIZEpKOHd2NmJPX3FGNl9pZ2Uxcl8yX0pLb2dfenJSUHJlU2JnYUEwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpRsZHqvgZPQpv14ylowOLinJDJpespKmK-QjuUL3ZKrxs7YV-WnDO6S7a3PpiKRf66PPEkvVIGhKLNYbHcQlZS8oOq0Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDYiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MzAuMDczWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjMxLjcxOVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNi9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDYiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDYvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDYvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA2L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDYiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsImNvcnMiOlt7Im9yaWdpbiI6WyJzb21lLW9yaWdpbi5jb20iXSwibWV0aG9kIjpbIlBPU1QiXSwicmVzcG9uc2VIZWFkZXIiOlsiZm9vLWJhciJdLCJtYXhBZ2VTZWNvbmRzIjozNjAwfV0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "0a993f21217a7c27", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0006?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e4ddf1ae658880bee0b64eeb36e42981/8766347471040499994;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0006?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:32 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051426000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrfn8:4395,/bns/yv/borg/yv/bns/blobstore2/bitpusher/181.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=PMysW_LpDMfugwS5tIzoDQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/181.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/181:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWXA3ZUxTdWNBTVN4aWpIaGJ4VldlcTlheV9Zb3I5dEQ4cFplQ0NNUklKLXJMQ29yX2JvaXdtdVhYRGNISTRfdURWYUtTRHVfVFhtWTl4dXBBOC1JUGZudFFaRnRLOTNlbTg3ZTNlbUFkYjFaUVA3cWo5Mjg0YmM3cllER3ZKRUFrZ0tVT1FiWUZJcmtReWs5WFZIZEpKOHd2NmJPX3FGNl9pZ2Uxcl8yX0pLb2dfenJSUHJlU2JnYUEwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpYoiT9dFZEe3bYZpKBDdNo1qGJBj162YN_q2mfCF_Cu5UIhC_Ib0VD7PPM6Z1VcjdiHoVEw9wba5WuX-B3x5i3I9fm9Q" + ] + }, + "Body": "" + } + }, + { + "ID": "e8642f6985fa8167", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0005?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4a1637b431168dd8d2277b2854b6f278/10356759375107716792;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0005?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:33 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051426000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdm4:4150,/bns/yw/borg/yw/bns/blobstore2/bitpusher/164.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=PMysW9aXKc22hAS_5bvYCw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/164.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/164:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWXA3ZUxTdWNBTVN4aWpIaGJ4VldlcTlheV9Zb3I5dEQ4cFplQ0NNUklKLXJMQ29yX2JvaXdtdVhYRGNISTRfdURWYUtTRHVfVFhtWTl4dXBBOC1JUGZudFFaRnRLOTNlbTg3ZTNlbUFkYjFaUVA3cWo5Mjg0YmM3cllER3ZKRUFrZ0tVT1FiWUZJcmtReWs5WFZIZEpKOHd2NmJPX3FGNl9pZ2Uxcl8yX0pLb2dfenJSUHJlU2JnYUEwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrlJunYzNiZ4k0A_LqRHm4z2KBn7d1n1oGjjxubNDFJyV2A-_4zxyOnt2gruJckXZXPqElJtv2294941mmIre0KfiIXrg" + ] + }, + "Body": "" + } + }, + { + "ID": "1311ecad1f217ee7", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0004?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "86e26ae2e91c98c6d858aa23da3cb616/11947171279174867799;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0004?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:33 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051426000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlj28:4249,/bns/yv/borg/yv/bns/blobstore2/bitpusher/28.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=PcysW_HtCaGeggTshbKAAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/28.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/28:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWXA3ZUxTdWNBTVN4aWpIaGJ4VldlcTlheV9Zb3I5dEQ4cFplQ0NNUklKLXJMQ29yX2JvaXdtdVhYRGNISTRfdURWYUtTRHVfVFhtWTl4dXBBOC1JUGZudFFaRnRLOTNlbTg3ZTNlbUFkYjFaUVA3cWo5Mjg0YmM3cllER3ZKRUFrZ0tVT1FiWUZJcmtReWs5WFZIZEpKOHd2NmJPX3FGNl9pZ2Uxcl8yX0pLb2dfenJSUHJlU2JnYUEwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqLJGRwcwdpiAlh0ePB0ISuYu9FlsEpZ3h5iTHzsEVGBUhR7u_OU3vT_S8kXM9NBplmomCJEJnrR4UEd6FnPhbPMtCG8A" + ] + }, + "Body": "" + } + }, + { + "ID": "f30064255790a2af", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "60" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3c8bd795d7c1a203f1bae8d0ab810313/13537300608753746422;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA3In0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "426" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:34 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051433000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrks2:4058,/bns/yv/borg/yv/bns/blobstore2/bitpusher/13.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=PcysW8CfJtCuggSokbuwAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/13.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/13:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYi1PQjdMLThUMnZyYTB2bmdDZG5Fcy1LcUZWSXdtNkVRelFHbGZaVklXSU5rZW13RTJrNFBMVXh1UWo0RFRtYVBCdWxseXRyRXpsT0lHU2xzN1dEemZKM19Ra01WNmpHamVLUGJ1Z1RvZlhMTGtwNjFocHVIMV9nQTBLb01jdUJ3V092OUdPaXo5Slk0Vzh4M09EVUhFa00tQjFYSGxHQXpzWlhkT0VOenZPOXBHWm1oRklaODBwaE0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrX9H1l8bHhu8BqnaOvrWr7wtB68Ft1FDeOFpqId9pv3vtPqFJjXeFBLQSvGYWFQ3ZN8EQsk7AnKRjU3u2iE9xhK5vykQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MzQuMDcyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjM0LjA3MloiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "59578f52a5f0077e", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0007?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "bc0ab534806ff533a56aec2f744ee2b5/15127712512820962964;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0007?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2353" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:34 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:34 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051434000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrhq4:4312,/bns/yr/borg/yr/bns/blobstore2/bitpusher/115.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=PsysW-KPHIvykAO0grpg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/115.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/115:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYi1PQjdMLThUMnZyYTB2bmdDZG5Fcy1LcUZWSXdtNkVRelFHbGZaVklXSU5rZW13RTJrNFBMVXh1UWo0RFRtYVBCdWxseXRyRXpsT0lHU2xzN1dEemZKM19Ra01WNmpHamVLUGJ1Z1RvZlhMTGtwNjFocHVIMV9nQTBLb01jdUJ3V092OUdPaXo5Slk0Vzh4M09EVUhFa00tQjFYSGxHQXpzWlhkT0VOenZPOXBHWm1oRklaODBwaE0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqwryHXSpXa_3TP9lnjG7MuIY4Q5mztKCJrgUSoYoDze9zLlxy1hZ2v9u1kRpBHROyDnBQ70gC3JhfY4GF-uMl6d51JLg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MzQuMDcyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjM0LjA3MloiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDcvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDcvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA3L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" + } + }, + { + "ID": "1fc47512e39433d9", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0007?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "31" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "f56bd42d61719e5d5394eb0093b2999b/16646067922345036851;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0007?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJkZWZhdWx0RXZlbnRCYXNlZEhvbGQiOnRydWV9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2382" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:36 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051435000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlm74:4305,/bns/yv/borg/yv/bns/blobstore2/bitpusher/290.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=PsysW_XeLIvRgQTe5JKYDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/290.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/290:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYi1PQjdMLThUMnZyYTB2bmdDZG5Fcy1LcUZWSXdtNkVRelFHbGZaVklXSU5rZW13RTJrNFBMVXh1UWo0RFRtYVBCdWxseXRyRXpsT0lHU2xzN1dEemZKM19Ra01WNmpHamVLUGJ1Z1RvZlhMTGtwNjFocHVIMV9nQTBLb01jdUJ3V092OUdPaXo5Slk0Vzh4M09EVUhFa00tQjFYSGxHQXpzWlhkT0VOenZPOXBHWm1oRklaODBwaE0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoRKpiybYkviqDw7fneNk_UqWCvNv7c_YIwoSOkNKZy7vD8vPynoCS3vuKPgXgpTIRom4njyLpqFT2D7omgRPQqiv0PKw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MzQuMDcyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjM2LjEyMloiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDcvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDcvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA3L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsImRlZmF1bHRFdmVudEJhc2VkSG9sZCI6dHJ1ZSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FJPSJ9" + } + }, + { + "ID": "71f85ffea051d16c", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0007?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "09d86e943aa5cba8e06dd981791e0a0e/18236479826412188114;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0007?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2382" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:36 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:36 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051434000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrtg21:4099,/bns/yr/borg/yr/bns/blobstore2/bitpusher/29.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=QMysW_CjFISz4QT5n6jACQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/29.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/29:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYi1PQjdMLThUMnZyYTB2bmdDZG5Fcy1LcUZWSXdtNkVRelFHbGZaVklXSU5rZW13RTJrNFBMVXh1UWo0RFRtYVBCdWxseXRyRXpsT0lHU2xzN1dEemZKM19Ra01WNmpHamVLUGJ1Z1RvZlhMTGtwNjFocHVIMV9nQTBLb01jdUJ3V092OUdPaXo5Slk0Vzh4M09EVUhFa00tQjFYSGxHQXpzWlhkT0VOenZPOXBHWm1oRklaODBwaE0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UowVyCkB2mA474S_48RgPdZ2QPyUaTI8UwGuVPpNhCLh8yU9jJCxtTsTyFvI1pg5jtqGhx-TRklbSiIVcsU5MZbIDzc3A" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MzQuMDcyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjM2LjEyMloiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDcvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDcvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA3L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsImRlZmF1bHRFdmVudEJhc2VkSG9sZCI6dHJ1ZSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FJPSJ9" + } + }, + { + "ID": "730e0f88fcfb808c", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0007?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "35" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ff1adbcb58c978e9ea27b7abbc181386/1380147656753141616;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0007?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2415" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:38 GMT" + ], + "Etag": [ + "CAM=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051435000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrw127:4318,/bns/yv/borg/yv/bns/blobstore2/bitpusher/178.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=QMysW_nCJcTIggSEmZeoDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/178.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/178:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYi1PQjdMLThUMnZyYTB2bmdDZG5Fcy1LcUZWSXdtNkVRelFHbGZaVklXSU5rZW13RTJrNFBMVXh1UWo0RFRtYVBCdWxseXRyRXpsT0lHU2xzN1dEemZKM19Ra01WNmpHamVLUGJ1Z1RvZlhMTGtwNjFocHVIMV9nQTBLb01jdUJ3V092OUdPaXo5Slk0Vzh4M09EVUhFa00tQjFYSGxHQXpzWlhkT0VOenZPOXBHWm1oRklaODBwaE0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq79m0pVSBsXB0mmUTWEnrP1CqxwCQzUZUOAZCkXG-y4JXjctCThCoxM8yjvmJfnanm-nZ-USf3cXWOpF0M6PSknqeVdg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MzQuMDcyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjM4LjEzNFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjMiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDcvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDcvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA3L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBTT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FNPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsImRlZmF1bHRFdmVudEJhc2VkSG9sZCI6dHJ1ZSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9LCJldGFnIjoiQ0FNPSJ9" + } + }, + { + "ID": "a02f1f35cab4348d", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0007?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "cf218679be1b3e915c329ce5ba4659e3/2970558461325442063;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0007?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2415" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:38 GMT" + ], + "Etag": [ + "CAM=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:38 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051434000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrea4:4208,/bns/yv/borg/yv/bns/blobstore2/bitpusher/227.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=QsysW__5FMTDswat-Z-oBg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/227.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/227:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYi1PQjdMLThUMnZyYTB2bmdDZG5Fcy1LcUZWSXdtNkVRelFHbGZaVklXSU5rZW13RTJrNFBMVXh1UWo0RFRtYVBCdWxseXRyRXpsT0lHU2xzN1dEemZKM19Ra01WNmpHamVLUGJ1Z1RvZlhMTGtwNjFocHVIMV9nQTBLb01jdUJ3V092OUdPaXo5Slk0Vzh4M09EVUhFa00tQjFYSGxHQXpzWlhkT0VOenZPOXBHWm1oRklaODBwaE0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqO7KixMVW5oE-Z7rTf-05a3MQ7VchJb6xKl00oDhmuidN9aTQxAk6MHGDdLfH0VHouT8tPJQ970eKq17raRD5PRlAJNw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MzQuMDcyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjM4LjEzNFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjMiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDcvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwNyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDcvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA3L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBTT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FNPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsImRlZmF1bHRFdmVudEJhc2VkSG9sZCI6dHJ1ZSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJiaWxsaW5nIjp7InJlcXVlc3RlclBheXMiOnRydWV9LCJldGFnIjoiQ0FNPSJ9" + } + }, + { + "ID": "e1a268e954e19280", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0007?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3b85dca22884f6881cd7a4358ea80207/4560970365375816366;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0007?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:39 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051433000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbv22:4137,/bns/yv/borg/yv/bns/blobstore2/bitpusher/243.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=QsysW5qeJYGngASMt5uwAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/243.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/243:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYi1PQjdMLThUMnZyYTB2bmdDZG5Fcy1LcUZWSXdtNkVRelFHbGZaVklXSU5rZW13RTJrNFBMVXh1UWo0RFRtYVBCdWxseXRyRXpsT0lHU2xzN1dEemZKM19Ra01WNmpHamVLUGJ1Z1RvZlhMTGtwNjFocHVIMV9nQTBLb01jdUJ3V092OUdPaXo5Slk0Vzh4M09EVUhFa00tQjFYSGxHQXpzWlhkT0VOenZPOXBHWm1oRklaODBwaE0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UozX15bN75-vGZh_C0BLNyjVXwQGxTMEvRMmqkwiAsFxzfvp3GD9EWWWWdhKj7q5B3eNGH5KXxPXIT29zNUZR0qwIvOAg" + ] + }, + "Body": "" + } + }, + { + "ID": "4dd057f60283835e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "60" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "bac2f7e7df855709cfa2912eec59313f/6151100794466387788;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4In0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "426" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:39 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051439000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrm128:4106,/bns/yv/borg/yv/bns/blobstore2/bitpusher/286.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=Q8ysW8W1DMnNgASH64bQDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/286.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/286:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYW8tTi1VN3BXbjFWaEhPYml5Z2FjMzBQSzdFQXpIUlJHYkl1WkdrUl9hNE9PM3dOeFk1bFdBWFB2WTFJQ2FuWDlxSXZqeHFXZ0VHcUtueDdUQ1dMMm5INkZTY0dITnM3ZTMxMjcyc3lrLUZVdEFlNWNyekNrN0l1OVdUZ3BSVHFPdDVMYjBrSTVHdF9LbWtQTnN2M2FBVFJ6Q1VvdlRaYWUxeFAwdUJZSjNud0VOcTllS3JCZ3ZZWk0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqPxwA-ixx9ZAr4xf2ZQ3g4Aeh9jaFfgwKTM_fr3eh-ik43c09moeWAUeoQvn9S9AhnDzxYTBfRwij5e4HFASVemXjsGg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6MzkuODAxWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjM5LjgwMVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "37d7110f7cc94406", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=0a2912504a9ce020eae7958dfe430a523c7be1ecf30776eef91e989784f6" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "fa2c5b7c49cfad80d49fbbf42d27145d/6982475729095563932;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0wYTI5MTI1MDRhOWNlMDIwZWFlNzk1OGRmZTQzMGE1MjNjN2JlMWVjZjMwNzc2ZWVmOTFlOTg5Nzg0ZjYNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOCIsIm5hbWUiOiJzb21lLW9iaiJ9Cg0KLS0wYTI5MTI1MDRhOWNlMDIwZWFlNzk1OGRmZTQzMGE1MjNjN2JlMWVjZjMwNzc2ZWVmOTFlOTg5Nzg0ZjYNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtDQoNCiHe8gVi7cUy1yj2YdH/SBwNCi0tMGEyOTEyNTA0YTljZTAyMGVhZTc5NThkZmU0MzBhNTIzYzdiZTFlY2YzMDc3NmVlZjkxZTk4OTc4NGY2LS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3285" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:40 GMT" + ], + "Etag": [ + "CIbX9/6W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051439000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbq123:4158,/bns/yv/borg/yv/bns/blobstore2/bitpusher/293.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=Q8ysW7iWPIrHggTf2qigAw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/293.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/293:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYW8tTi1VN3BXbjFWaEhPYml5Z2FjMzBQSzdFQXpIUlJHYkl1WkdrUl9hNE9PM3dOeFk1bFdBWFB2WTFJQ2FuWDlxSXZqeHFXZ0VHcUtueDdUQ1dMMm5INkZTY0dITnM3ZTMxMjcyc3lrLUZVdEFlNWNyekNrN0l1OVdUZ3BSVHFPdDVMYjBrSTVHdF9LbWtQTnN2M2FBVFJ6Q1VvdlRaYWUxeFAwdUJZSjNud0VOcTllS3JCZ3ZZWk0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur6aYjGujjKgLW1Bhh-arBoYeTSpBZn1ncAgDZ3jqg5e4U9kuQhNPLKlfULMw23Tfheb7-2Csjg1cwUOBbywxBMKdpP-g" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9zb21lLW9iai8xNTM4MDUxMTQwMzQ4ODA2Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQwLjM0OFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0MC4zNDhaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDAuMzQ4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJZU0dkNy9lVm56cmFJM285MGorUDdBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQwMzQ4ODA2JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQwMzQ4ODA2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0liWDkvNlcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJYlg5LzZXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibU1SVG5nPT0iLCJldGFnIjoiQ0liWDkvNlcyOTBDRUFFPSJ9" + } + }, + { + "ID": "a5e7a973054cd9eb", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "72b674888ea6ba2e2000c02ed2425059/8572606162464260154;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3285" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:40 GMT" + ], + "Etag": [ + "CIbX9/6W290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051440000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnat135:4299,/bns/yx/borg/yx/bns/blobstore2/bitpusher/155.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=RMysW9yGHZGezQLUipSACw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/155.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/155:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYW8tTi1VN3BXbjFWaEhPYml5Z2FjMzBQSzdFQXpIUlJHYkl1WkdrUl9hNE9PM3dOeFk1bFdBWFB2WTFJQ2FuWDlxSXZqeHFXZ0VHcUtueDdUQ1dMMm5INkZTY0dITnM3ZTMxMjcyc3lrLUZVdEFlNWNyekNrN0l1OVdUZ3BSVHFPdDVMYjBrSTVHdF9LbWtQTnN2M2FBVFJ6Q1VvdlRaYWUxeFAwdUJZSjNud0VOcTllS3JCZ3ZZWk0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpbUSEl8lVOXpkbanVm3TZbe3inmlKBD8z0dxTDy0Jmws3ee-ZbsIcCS3UCPp4UnOysMml-2tROHVKDfUhOzZRF1fW6DA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9zb21lLW9iai8xNTM4MDUxMTQwMzQ4ODA2Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQwLjM0OFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0MC4zNDhaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDAuMzQ4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJZU0dkNy9lVm56cmFJM285MGorUDdBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQwMzQ4ODA2JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQwMzQ4ODA2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0liWDkvNlcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJYlg5LzZXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibU1SVG5nPT0iLCJldGFnIjoiQ0liWDkvNlcyOTBDRUFFPSJ9" + } + }, + { + "ID": "aaacb912d25964e2", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "84" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "f36e3abdbbb5cd513afef505376b0b55/10090960472510260697;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJldmVudEJhc2VkSG9sZCI6dHJ1ZX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3307" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:40 GMT" + ], + "Etag": [ + "CIbX9/6W290CEAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051440000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrnm23:4163,/bns/yw/borg/yw/bns/blobstore2/bitpusher/33.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=RMysW8ezJJS8hgSYgLfICQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/33.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/33:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYW8tTi1VN3BXbjFWaEhPYml5Z2FjMzBQSzdFQXpIUlJHYkl1WkdrUl9hNE9PM3dOeFk1bFdBWFB2WTFJQ2FuWDlxSXZqeHFXZ0VHcUtueDdUQ1dMMm5INkZTY0dITnM3ZTMxMjcyc3lrLUZVdEFlNWNyekNrN0l1OVdUZ3BSVHFPdDVMYjBrSTVHdF9LbWtQTnN2M2FBVFJ6Q1VvdlRaYWUxeFAwdUJZSjNud0VOcTllS3JCZ3ZZWk0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur79Q63MXhT1ocHhwJI-YRY2WVWTCXb82hlaPk7243LyKIdSCWWwKf2ACbFhLI_TKRmh94UJkNYheGo38lWBmG91M_Esw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9zb21lLW9iai8xNTM4MDUxMTQwMzQ4ODA2Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQwLjM0OFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0MC42ODlaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDAuMzQ4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJZU0dkNy9lVm56cmFJM285MGorUDdBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQwMzQ4ODA2JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQwMzQ4ODA2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0liWDkvNlcyOTBDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJYlg5LzZXMjkwQ0VBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibU1SVG5nPT0iLCJldGFnIjoiQ0liWDkvNlcyOTBDRUFJPSIsImV2ZW50QmFzZWRIb2xkIjp0cnVlfQ==" + } + }, + { + "ID": "76fbc9f0b99b2f49", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "669db8763b6bd4dd603ecdcace4864c6/11681372372282509944;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3307" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:40 GMT" + ], + "Etag": [ + "CIbX9/6W290CEAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051440000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrrr16:4447,/bns/yv/borg/yv/bns/blobstore2/bitpusher/88.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=RMysW9iUMcKZgQTw9ZIQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/88.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/88:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYW8tTi1VN3BXbjFWaEhPYml5Z2FjMzBQSzdFQXpIUlJHYkl1WkdrUl9hNE9PM3dOeFk1bFdBWFB2WTFJQ2FuWDlxSXZqeHFXZ0VHcUtueDdUQ1dMMm5INkZTY0dITnM3ZTMxMjcyc3lrLUZVdEFlNWNyekNrN0l1OVdUZ3BSVHFPdDVMYjBrSTVHdF9LbWtQTnN2M2FBVFJ6Q1VvdlRaYWUxeFAwdUJZSjNud0VOcTllS3JCZ3ZZWk0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpypyDzoPkWQvudGbMqnEjZPiWP2UshpaXFL0GnKW3XMLtJGzWDVn0M1Zgu2dMjPaY7fj86Y5MnB33QfPfPk7Ox1CLdfg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9zb21lLW9iai8xNTM4MDUxMTQwMzQ4ODA2Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQwLjM0OFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0MC42ODlaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDAuMzQ4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJZU0dkNy9lVm56cmFJM285MGorUDdBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQwMzQ4ODA2JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQwMzQ4ODA2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0liWDkvNlcyOTBDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJYlg5LzZXMjkwQ0VBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibU1SVG5nPT0iLCJldGFnIjoiQ0liWDkvNlcyOTBDRUFJPSIsImV2ZW50QmFzZWRIb2xkIjp0cnVlfQ==" + } + }, + { + "ID": "78aae384aa961deb", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "82" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "7d56df310958932c8e9f768c4f493f3f/13271784276332949526;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJjb250ZW50VHlwZSI6ImZvbyJ9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3286" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:41 GMT" + ], + "Etag": [ + "CIbX9/6W290CEAM=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051440000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdv10:4196,/bns/yv/borg/yv/bns/blobstore2/bitpusher/21.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=RMysW4izN4quggSVlrrQAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/21.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/21:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYW8tTi1VN3BXbjFWaEhPYml5Z2FjMzBQSzdFQXpIUlJHYkl1WkdrUl9hNE9PM3dOeFk1bFdBWFB2WTFJQ2FuWDlxSXZqeHFXZ0VHcUtueDdUQ1dMMm5INkZTY0dITnM3ZTMxMjcyc3lrLUZVdEFlNWNyekNrN0l1OVdUZ3BSVHFPdDVMYjBrSTVHdF9LbWtQTnN2M2FBVFJ6Q1VvdlRaYWUxeFAwdUJZSjNud0VOcTllS3JCZ3ZZWk0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpZzkXCMOe7dNiTX_3OFre5VukWstUkiWl2b0wgLfUBOd285bNQ2ztHV883ZEFh_lyekWInaXl0JH8CiJ40u4gen6707A" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9zb21lLW9iai8xNTM4MDUxMTQwMzQ4ODA2Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsImNvbnRlbnRUeXBlIjoiZm9vIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQwLjM0OFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0MC45ODNaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDAuMzQ4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJZU0dkNy9lVm56cmFJM285MGorUDdBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQwMzQ4ODA2JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQwMzQ4ODA2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0liWDkvNlcyOTBDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJYlg5LzZXMjkwQ0VBTT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibU1SVG5nPT0iLCJldGFnIjoiQ0liWDkvNlcyOTBDRUFNPSIsImV2ZW50QmFzZWRIb2xkIjp0cnVlfQ==" + } + }, + { + "ID": "b6f9e84970bde86e", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "69fd5e5c0a5397d780834aa8ca559a36/14861914709718357429;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3286" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:41 GMT" + ], + "Etag": [ + "CIbX9/6W290CEAM=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051440000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnpp189:4374,/bns/yx/borg/yx/bns/blobstore2/bitpusher/45.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=RcysW9ijBpKrzALq86GoBg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/45.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/45:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYW8tTi1VN3BXbjFWaEhPYml5Z2FjMzBQSzdFQXpIUlJHYkl1WkdrUl9hNE9PM3dOeFk1bFdBWFB2WTFJQ2FuWDlxSXZqeHFXZ0VHcUtueDdUQ1dMMm5INkZTY0dITnM3ZTMxMjcyc3lrLUZVdEFlNWNyekNrN0l1OVdUZ3BSVHFPdDVMYjBrSTVHdF9LbWtQTnN2M2FBVFJ6Q1VvdlRaYWUxeFAwdUJZSjNud0VOcTllS3JCZ3ZZWk0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Urhrjx4L0FkFYcxk3TEaGXYaCAz_Iwa_R_TsU9fwVuFkO7FpYAB1LKwqWqO0TocvFMeGFwyd_7ke352CB7-cnX_Dsr04Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9zb21lLW9iai8xNTM4MDUxMTQwMzQ4ODA2Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsImNvbnRlbnRUeXBlIjoiZm9vIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQwLjM0OFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0MC45ODNaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDAuMzQ4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJZU0dkNy9lVm56cmFJM285MGorUDdBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQwMzQ4ODA2JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQwMzQ4ODA2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0liWDkvNlcyOTBDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJYlg5LzZXMjkwQ0VBTT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibU1SVG5nPT0iLCJldGFnIjoiQ0liWDkvNlcyOTBDRUFNPSIsImV2ZW50QmFzZWRIb2xkIjp0cnVlfQ==" + } + }, + { + "ID": "6e80bc4210ff38e8", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "85" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "908b325ceff7af773f3ae514b5d7fdeb/16452326609473895251;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJldmVudEJhc2VkSG9sZCI6ZmFsc2V9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3287" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:41 GMT" + ], + "Etag": [ + "CIbX9/6W290CEAQ=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051440000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrhq15:4330,/bns/yv/borg/yv/bns/blobstore2/bitpusher/4.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=RcysW6q5C4OlggT477xY" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/4.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/4:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYW8tTi1VN3BXbjFWaEhPYml5Z2FjMzBQSzdFQXpIUlJHYkl1WkdrUl9hNE9PM3dOeFk1bFdBWFB2WTFJQ2FuWDlxSXZqeHFXZ0VHcUtueDdUQ1dMMm5INkZTY0dITnM3ZTMxMjcyc3lrLUZVdEFlNWNyekNrN0l1OVdUZ3BSVHFPdDVMYjBrSTVHdF9LbWtQTnN2M2FBVFJ6Q1VvdlRaYWUxeFAwdUJZSjNud0VOcTllS3JCZ3ZZWk0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqR4YYdh9xEeNHy3xSzUablg3lgP_gFT4RbOP8RgJFz-sQ9ugVz8WuHUSLmtuItC_hyR_AvyhkZimBD005OZvEPPWGtNA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9zb21lLW9iai8xNTM4MDUxMTQwMzQ4ODA2Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsIm1ldGFnZW5lcmF0aW9uIjoiNCIsImNvbnRlbnRUeXBlIjoiZm9vIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQwLjM0OFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0MS4yNTZaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDAuMzQ4WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJZU0dkNy9lVm56cmFJM285MGorUDdBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQwMzQ4ODA2JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQwMzQ4ODA2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQVE9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSWJYOS82VzI5MENFQVE9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvc29tZS1vYmovMTUzODA1MTE0MDM0ODgwNi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDgvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0liWDkvNlcyOTBDRUFRPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4L3NvbWUtb2JqLzE1MzgwNTExNDAzNDg4MDYvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOC9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA4Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MDM0ODgwNiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJYlg5LzZXMjkwQ0VBUT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibU1SVG5nPT0iLCJldGFnIjoiQ0liWDkvNlcyOTBDRUFRPSIsImV2ZW50QmFzZWRIb2xkIjpmYWxzZX0=" + } + }, + { + "ID": "97d438b968fe32c8", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "2ae0c9abf22f8613130b760ed0f25db8/17283420073421328035;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008/o/some-obj?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:41 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051439000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlw11:4360,/bns/yv/borg/yv/bns/blobstore2/bitpusher/235.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=RcysW_r4FonuggSJ1Lr4CQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/235.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/235:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYW8tTi1VN3BXbjFWaEhPYml5Z2FjMzBQSzdFQXpIUlJHYkl1WkdrUl9hNE9PM3dOeFk1bFdBWFB2WTFJQ2FuWDlxSXZqeHFXZ0VHcUtueDdUQ1dMMm5INkZTY0dITnM3ZTMxMjcyc3lrLUZVdEFlNWNyekNrN0l1OVdUZ3BSVHFPdDVMYjBrSTVHdF9LbWtQTnN2M2FBVFJ6Q1VvdlRaYWUxeFAwdUJZSjNud0VOcTllS3JCZ3ZZWk0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrdiEc0xjlqkDsbTeOVLT489iN9y6sLywT23V6xAxTn2LpfZSlYEcJpJ-9Gog_DBTNVFBs0pJkQJKJG0iykjVNOO2uyYw" + ] + }, + "Body": "" + } + }, + { + "ID": "f80d68a7124d0884", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "92467cd80ac62acc5f3fdfd1f0b095bc/427368279260853057;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0008?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:42 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051439000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vray3:4145,/bns/yv/borg/yv/bns/blobstore2/bitpusher/360.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=RcysW9PrLJfJgASEx7egAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/360.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/360:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYW8tTi1VN3BXbjFWaEhPYml5Z2FjMzBQSzdFQXpIUlJHYkl1WkdrUl9hNE9PM3dOeFk1bFdBWFB2WTFJQ2FuWDlxSXZqeHFXZ0VHcUtueDdUQ1dMMm5INkZTY0dITnM3ZTMxMjcyc3lrLUZVdEFlNWNyekNrN0l1OVdUZ3BSVHFPdDVMYjBrSTVHdF9LbWtQTnN2M2FBVFJ6Q1VvdlRaYWUxeFAwdUJZSjNud0VOcTllS3JCZ3ZZWk0wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoSGI76du_R-KAywyZHtMJCD98ezW_k2SyAXFJU1hNQs_4Gmef8a8PRhUnVR0vq4UtMsNRYTZvsueKQpnfFbkMsAYaeUA" + ] + }, + "Body": "" + } + }, + { + "ID": "16c9b99ace40675c", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "60" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3192e57753f54de047527a0f7c734937/1945723688784927200;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5In0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "426" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:43 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051442000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrli74:4433,/bns/yv/borg/yv/bns/blobstore2/bitpusher/329.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=RsysW6nYEMHSggSJ44SQDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/329.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/329:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYm55eUhjUWpNWkU0aTFCOGpNWG9GOHRvNDlSNWRjTUJnOFRGMDJkT2lZdHhhZ3MzVklHZmVzXzByNTlISDRvNEtudW96RTBQa2FVZVIzNkRlelFXcnlfMXpKUjRScTRYcFdDYjJKUkl3NTFYUW8yc2hncy0td1duX1B3Vk9hSy1hWUVQLVN6Uk1zcmlUN0ZtaFZ2WUxRRHhSTy1nd29sRXlFNWJCWXhqQmJybkxfZ3pxTTNQREZFZ0kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrNyakak05lR1Q2WId23z_m1L9zXqPQG42itWpjchRBWAuwh51w0ufLjK7GnNIdUwsmpT6kzUdtz66v9-_iZWp69aOP9w" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDIuOTAwWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQyLjkwMFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "125a0f566fb957a2", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=28057963d603e97cd943670bb09dea0b37721dcbee4de7f44ddce95f66d3" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "23787329c84d271578a4b254783707aa/2776817152749202223;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0yODA1Nzk2M2Q2MDNlOTdjZDk0MzY3MGJiMDlkZWEwYjM3NzIxZGNiZWU0ZGU3ZjQ0ZGRjZTk1ZjY2ZDMNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOSIsIm5hbWUiOiJzb21lLW9iaiJ9Cg0KLS0yODA1Nzk2M2Q2MDNlOTdjZDk0MzY3MGJiMDlkZWEwYjM3NzIxZGNiZWU0ZGU3ZjQ0ZGRjZTk1ZjY2ZDMNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtDQoNCh3phU9nPeKTspnhdkB1G0oNCi0tMjgwNTc5NjNkNjAzZTk3Y2Q5NDM2NzBiYjA5ZGVhMGIzNzcyMWRjYmVlNGRlN2Y0NGRkY2U5NWY2NmQzLS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3285" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:43 GMT" + ], + "Etag": [ + "COLHs4CX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051442000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlv9:4242,/bns/yr/borg/yr/bns/blobstore2/bitpusher/112.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=R8ysW7yABYiVkASQyLSgCw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/112.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/112:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYm55eUhjUWpNWkU0aTFCOGpNWG9GOHRvNDlSNWRjTUJnOFRGMDJkT2lZdHhhZ3MzVklHZmVzXzByNTlISDRvNEtudW96RTBQa2FVZVIzNkRlelFXcnlfMXpKUjRScTRYcFdDYjJKUkl3NTFYUW8yc2hncy0td1duX1B3Vk9hSy1hWUVQLVN6Uk1zcmlUN0ZtaFZ2WUxRRHhSTy1nd29sRXlFNWJCWXhqQmJybkxfZ3pxTTNQREZFZ0kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Urul9azluGg9ubAfjVZBRTvxzf-9xDlfuKHaTDYFJmzn-4UQlkJt_LJyOU2Y-yfGMr-pdfjbTVxT0vujaoIVra1WyliEA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9zb21lLW9iai8xNTM4MDUxMTQzNDI3MDQyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQzLjQyNloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0My40MjZaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDMuNDI2WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJVT2h5QmY1OHg2VElzaGNIS1FvNmpBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQzNDI3MDQyJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQzNDI3MDQyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPTEhzNENYMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiVk5jdHBnPT0iLCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFFPSJ9" + } + }, + { + "ID": "e83fd8d4a5d6afd3", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ef9e1f91badb126602160267cee85176/4367229052504674766;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3285" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:43 GMT" + ], + "Etag": [ + "COLHs4CX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051443000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrtj9:4196,/bns/yv/borg/yv/bns/blobstore2/bitpusher/208.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=R8ysW9isKMvWgwSzu6-IBw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/208.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/208:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYm55eUhjUWpNWkU0aTFCOGpNWG9GOHRvNDlSNWRjTUJnOFRGMDJkT2lZdHhhZ3MzVklHZmVzXzByNTlISDRvNEtudW96RTBQa2FVZVIzNkRlelFXcnlfMXpKUjRScTRYcFdDYjJKUkl3NTFYUW8yc2hncy0td1duX1B3Vk9hSy1hWUVQLVN6Uk1zcmlUN0ZtaFZ2WUxRRHhSTy1nd29sRXlFNWJCWXhqQmJybkxfZ3pxTTNQREZFZ0kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Urbmysb5MvX3wH-2EyUwAeomINPZbRZpMP_aDaTJjYffjWZrxE-vaZ6QPh4MxX9nvgUSEyOBtJErQ-JZ3GXBaqR9Gatrw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9zb21lLW9iai8xNTM4MDUxMTQzNDI3MDQyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQzLjQyNloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0My40MjZaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDMuNDI2WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJVT2h5QmY1OHg2VElzaGNIS1FvNmpBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQzNDI3MDQyJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQzNDI3MDQyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPTEhzNENYMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiVk5jdHBnPT0iLCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFFPSJ9" + } + }, + { + "ID": "21a66e45cdb8667d", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "83" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "570f7ccbf052f85a5e3a8e354bfba434/5957640956571825773;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJ0ZW1wb3JhcnlIb2xkIjp0cnVlfQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3306" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:43 GMT" + ], + "Etag": [ + "COLHs4CX290CEAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051443000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrsw14:4204,/bns/yv/borg/yv/bns/blobstore2/bitpusher/388.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=R8ysW_eLMJTOgASAo6ugAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/388.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/388:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYm55eUhjUWpNWkU0aTFCOGpNWG9GOHRvNDlSNWRjTUJnOFRGMDJkT2lZdHhhZ3MzVklHZmVzXzByNTlISDRvNEtudW96RTBQa2FVZVIzNkRlelFXcnlfMXpKUjRScTRYcFdDYjJKUkl3NTFYUW8yc2hncy0td1duX1B3Vk9hSy1hWUVQLVN6Uk1zcmlUN0ZtaFZ2WUxRRHhSTy1nd29sRXlFNWJCWXhqQmJybkxfZ3pxTTNQREZFZ0kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoUSJsAp4AliWt6x8Y7V9BKhu6YRa_3kTlmIlHRBXeKe39DdevzD3oH8vIstiigiJkx0jLGaQUbBYRkZINHby4RAQqDUA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9zb21lLW9iai8xNTM4MDUxMTQzNDI3MDQyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQzLjQyNloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0My44NjVaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDMuNDI2WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJVT2h5QmY1OHg2VElzaGNIS1FvNmpBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQzNDI3MDQyJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQzNDI3MDQyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPTEhzNENYMjkwQ0VBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiVk5jdHBnPT0iLCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFJPSIsInRlbXBvcmFyeUhvbGQiOnRydWV9" + } + }, + { + "ID": "88e95beed2c0ec76", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "3bf057c037eafaa278687db43e4b09d9/7547770290445671435;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3306" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:44 GMT" + ], + "Etag": [ + "COLHs4CX290CEAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051443000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrda17:4188,/bns/yv/borg/yv/bns/blobstore2/bitpusher/118.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=SMysW78N37CCBMGqjeAK" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/118.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/118:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYm55eUhjUWpNWkU0aTFCOGpNWG9GOHRvNDlSNWRjTUJnOFRGMDJkT2lZdHhhZ3MzVklHZmVzXzByNTlISDRvNEtudW96RTBQa2FVZVIzNkRlelFXcnlfMXpKUjRScTRYcFdDYjJKUkl3NTFYUW8yc2hncy0td1duX1B3Vk9hSy1hWUVQLVN6Uk1zcmlUN0ZtaFZ2WUxRRHhSTy1nd29sRXlFNWJCWXhqQmJybkxfZ3pxTTNQREZFZ0kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpGFZ1rGj8u2nmVl9wHkhlgWycEQUTNBfnjLfBazqJeL52WiB5_5_uT9vqKlddCeAULH0E0KsJBrsXr3k2iWlWstsGvUg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9zb21lLW9iai8xNTM4MDUxMTQzNDI3MDQyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQzLjQyNloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0My44NjVaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDMuNDI2WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJVT2h5QmY1OHg2VElzaGNIS1FvNmpBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQzNDI3MDQyJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQzNDI3MDQyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPTEhzNENYMjkwQ0VBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiVk5jdHBnPT0iLCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFJPSIsInRlbXBvcmFyeUhvbGQiOnRydWV9" + } + }, + { + "ID": "139aa9cf44ba2500", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "82" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "2ed4cfa83cda4c4f833e638e5a3acab8/9138182190217920938;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJjb250ZW50VHlwZSI6ImZvbyJ9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3285" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:44 GMT" + ], + "Etag": [ + "COLHs4CX290CEAM=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051443000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vruh3:4140,/bns/yv/borg/yv/bns/blobstore2/bitpusher/140.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=SMysW-qCBZKCgwS2iqKgDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/140.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/140:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYm55eUhjUWpNWkU0aTFCOGpNWG9GOHRvNDlSNWRjTUJnOFRGMDJkT2lZdHhhZ3MzVklHZmVzXzByNTlISDRvNEtudW96RTBQa2FVZVIzNkRlelFXcnlfMXpKUjRScTRYcFdDYjJKUkl3NTFYUW8yc2hncy0td1duX1B3Vk9hSy1hWUVQLVN6Uk1zcmlUN0ZtaFZ2WUxRRHhSTy1nd29sRXlFNWJCWXhqQmJybkxfZ3pxTTNQREZFZ0kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Upn6yFG5Mlqp-GofUkiY0KgjJBckaYdHghjSruHNtANQIY94tfqerEqXVz-Y18pWQtDuxkJEr09eJ26sjVyPp9llinNpw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9zb21lLW9iai8xNTM4MDUxMTQzNDI3MDQyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsImNvbnRlbnRUeXBlIjoiZm9vIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQzLjQyNloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0NC4xNTFaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDMuNDI2WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJVT2h5QmY1OHg2VElzaGNIS1FvNmpBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQzNDI3MDQyJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQzNDI3MDQyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPTEhzNENYMjkwQ0VBTT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiVk5jdHBnPT0iLCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFNPSIsInRlbXBvcmFyeUhvbGQiOnRydWV9" + } + }, + { + "ID": "2bf008511cf7f3ca", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "a515f52484a43b168274b74481a46e8e/10728594094268294985;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3285" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:44 GMT" + ], + "Etag": [ + "COLHs4CX290CEAM=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051443000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrqj25:4236,/bns/yr/borg/yr/bns/blobstore2/bitpusher/44.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=SMysW-PJEcTvkAPC4IGgCQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/44.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/44:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYm55eUhjUWpNWkU0aTFCOGpNWG9GOHRvNDlSNWRjTUJnOFRGMDJkT2lZdHhhZ3MzVklHZmVzXzByNTlISDRvNEtudW96RTBQa2FVZVIzNkRlelFXcnlfMXpKUjRScTRYcFdDYjJKUkl3NTFYUW8yc2hncy0td1duX1B3Vk9hSy1hWUVQLVN6Uk1zcmlUN0ZtaFZ2WUxRRHhSTy1nd29sRXlFNWJCWXhqQmJybkxfZ3pxTTNQREZFZ0kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UomllJXP0WL8d5rWkRPZE8tECJWI63BBawFctUcrI2eVu2DPtJf8AIWjJvmORIpDaq76cuFqfbfZ3yuuBFd9qoTYdafKw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9zb21lLW9iai8xNTM4MDUxMTQzNDI3MDQyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsIm1ldGFnZW5lcmF0aW9uIjoiMyIsImNvbnRlbnRUeXBlIjoiZm9vIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQzLjQyNloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0NC4xNTFaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDMuNDI2WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJVT2h5QmY1OHg2VElzaGNIS1FvNmpBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQzNDI3MDQyJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQzNDI3MDQyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPTEhzNENYMjkwQ0VBTT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiVk5jdHBnPT0iLCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFNPSIsInRlbXBvcmFyeUhvbGQiOnRydWV9" + } + }, + { + "ID": "b7766305bfa56d5a", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "84" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "736de9a2bdf5c8988d3d2b206d31dfe0/12319005998335511783;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJ0ZW1wb3JhcnlIb2xkIjpmYWxzZX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3286" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:44 GMT" + ], + "Etag": [ + "COLHs4CX290CEAQ=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051443000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrk4:4182,/bns/yv/borg/yv/bns/blobstore2/bitpusher/349.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=SMysW5KeF9PXgATL46nICA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/349.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/349:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYm55eUhjUWpNWkU0aTFCOGpNWG9GOHRvNDlSNWRjTUJnOFRGMDJkT2lZdHhhZ3MzVklHZmVzXzByNTlISDRvNEtudW96RTBQa2FVZVIzNkRlelFXcnlfMXpKUjRScTRYcFdDYjJKUkl3NTFYUW8yc2hncy0td1duX1B3Vk9hSy1hWUVQLVN6Uk1zcmlUN0ZtaFZ2WUxRRHhSTy1nd29sRXlFNWJCWXhqQmJybkxfZ3pxTTNQREZFZ0kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoKsb53RjbCrsBQdPjt_eu8_pnouQqM-A4nUtfknw5u5dzQXJ_Hsv8B0j-DTtjN9PDfqh-iKDNvh5QpFb54dc4oDg6t_g" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9zb21lLW9iai8xNTM4MDUxMTQzNDI3MDQyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsIm1ldGFnZW5lcmF0aW9uIjoiNCIsImNvbnRlbnRUeXBlIjoiZm9vIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQzLjQyNloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0NC40ODNaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDMuNDI2WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJVT2h5QmY1OHg2VElzaGNIS1FvNmpBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQzNDI3MDQyJmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQzNDI3MDQyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQVE9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDT0xIczRDWDI5MENFQVE9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvc29tZS1vYmovMTUzODA1MTE0MzQyNzA0Mi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDkvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFRPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5L3NvbWUtb2JqLzE1MzgwNTExNDM0MjcwNDIvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwOS9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDA5Iiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0MzQyNzA0MiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNPTEhzNENYMjkwQ0VBUT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiVk5jdHBnPT0iLCJldGFnIjoiQ09MSHM0Q1gyOTBDRUFRPSIsInRlbXBvcmFyeUhvbGQiOmZhbHNlfQ==" + } + }, + { + "ID": "4d4bf3d6a690c4ad", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "6196048cde2e4d6c53fd5cb570b00693/13078042967756644151;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009/o/some-obj?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:44 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051444000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnch65:4276,/bns/yx/borg/yx/bns/blobstore2/bitpusher/26.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=SMysW_zuJIqvzwLJp5_ABw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/26.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/26:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYm55eUhjUWpNWkU0aTFCOGpNWG9GOHRvNDlSNWRjTUJnOFRGMDJkT2lZdHhhZ3MzVklHZmVzXzByNTlISDRvNEtudW96RTBQa2FVZVIzNkRlelFXcnlfMXpKUjRScTRYcFdDYjJKUkl3NTFYUW8yc2hncy0td1duX1B3Vk9hSy1hWUVQLVN6Uk1zcmlUN0ZtaFZ2WUxRRHhSTy1nd29sRXlFNWJCWXhqQmJybkxfZ3pxTTNQREZFZ0kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoT9Ov0jDXHY9uhhhBStlSHg2jyEeNKw2MCJCdrOoF3PgmfOTr2X1r0HPd9xSO4x_WgY6C_ydyWxG1PH9TG3ZZ-rT4sKw" + ] + }, + "Body": "" + } + }, + { + "ID": "8a63a72d8af7ceba", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "cb299b1ebb95e40d39867cbc9543231a/14668454867528959189;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0009?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:45 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051442000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdm189:4345,/bns/yr/borg/yr/bns/blobstore2/bitpusher/117.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=SMysW9-XOcKnkASClZioBg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/117.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/117:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYm55eUhjUWpNWkU0aTFCOGpNWG9GOHRvNDlSNWRjTUJnOFRGMDJkT2lZdHhhZ3MzVklHZmVzXzByNTlISDRvNEtudW96RTBQa2FVZVIzNkRlelFXcnlfMXpKUjRScTRYcFdDYjJKUkl3NTFYUW8yc2hncy0td1duX1B3Vk9hSy1hWUVQLVN6Uk1zcmlUN0ZtaFZ2WUxRRHhSTy1nd29sRXlFNWJCWXhqQmJybkxfZ3pxTTNQREZFZ0kwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UruDTxj-5sNUNL5TgdK2N8Y5h_ubbWt_65r-y1dKu9-7GSNIld2Ii1hrFsyLY-by8sNpTzoshjKed_fvWtm_4qDcgA_Vg" + ] + }, + "Body": "" + } + }, + { + "ID": "6ed823f9572a2abb", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "105" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "5d64adfcef1874b28e27c12b019bfbd9/16258584201402739316;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjM2MDAifX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "514" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:46 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051445000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnll124:4447,/bns/yx/borg/yx/bns/blobstore2/bitpusher/118.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=ScysW_ynGdbQzAL6lov4DQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/118.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/118:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWWhLRWRJS21GUEgxdEtyUnZ6LTVHcEpFV2I3OTF6d2FCanpvT0REdnVuTmhHVVBINWJHX1BHc1ljQ2JIS0hpR1QtR1ZSOHdaTlZqMFJQdml6U2NZUnRQUWg3QkdWU1UzbXNkXzNJSERFRUFoQVVXU3ZQZHNMSmZocVBubWZlZUgtb3pCMEtxQ3hFRTBob2FQbTRqQmlvMXVidF9WSlVuZmVvcl9sZkhCLTMxWkpsNENCQ1dIRXVRQ1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uol_YBnpQvchvCCc4fF4UAzRDezAG-jZp1Q5dR-8d3_56yA5lZp2tYMVP9VBnPA8rc9-g99iXEA5muatm50TW0VfftSmQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDUuODU3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQ1Ljg1N1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjM2MDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0yN1QxMjoyNTo0NS44NTdaIn0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" + } + }, + { + "ID": "07b5dd5807cb4e76", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0010/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=60f031f9c7f83e6753f9064062bf236631fe19faf4e9f2501b9a1cf4e8e8" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ba4c24b367d04339d0eb4e34c234e7e2/17017902641505680835;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0010/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS02MGYwMzFmOWM3ZjgzZTY3NTNmOTA2NDA2MmJmMjM2NjMxZmUxOWZhZjRlOWYyNTAxYjlhMWNmNGU4ZTgNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMCIsIm5hbWUiOiJzb21lLW9iaiJ9Cg0KLS02MGYwMzFmOWM3ZjgzZTY3NTNmOTA2NDA2MmJmMjM2NjMxZmUxOWZhZjRlOWYyNTAxYjlhMWNmNGU4ZTgNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtDQoNCku3Qm/7wRsR3az70rmpwPANCi0tNjBmMDMxZjljN2Y4M2U2NzUzZjkwNjQwNjJiZjIzNjYzMWZlMTlmYWY0ZTlmMjUwMWI5YTFjZjRlOGU4LS0NCg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3338" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:46 GMT" + ], + "Etag": [ + "CPq47IGX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051446000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdg20:4229,/bns/yr/borg/yr/bns/blobstore2/bitpusher/99.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=SsysW7SWB4i44QT15L5A" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/99.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/99:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWWhLRWRJS21GUEgxdEtyUnZ6LTVHcEpFV2I3OTF6d2FCanpvT0REdnVuTmhHVVBINWJHX1BHc1ljQ2JIS0hpR1QtR1ZSOHdaTlZqMFJQdml6U2NZUnRQUWg3QkdWU1UzbXNkXzNJSERFRUFoQVVXU3ZQZHNMSmZocVBubWZlZUgtb3pCMEtxQ3hFRTBob2FQbTRqQmlvMXVidF9WSlVuZmVvcl9sZkhCLTMxWkpsNENCQ1dIRXVRQ1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoVq1g900fUkQrYVUWxjF80ZfcD75WfF1p0bn_P3bXv1wH-zRd-vMpaPLWBfYQS90SCPPb1fc0gTkjxsuc_fy74O6R2aw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMC9zb21lLW9iai8xNTM4MDUxMTQ2NDU2MTg2Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwL28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0NjQ1NjE4NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQ2LjQ1NFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0Ni40NTRaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDYuNDU0WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJRWm5CNUtSZSs4aTJ4d2w3K2pGMVJRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwL28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQ2NDU2MTg2JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwL3NvbWUtb2JqLzE1MzgwNTExNDY0NTYxODYvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQ2NDU2MTg2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUHE0N0lHWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAvc29tZS1vYmovMTUzODA1MTE0NjQ1NjE4Ni9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwIiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0NjQ1NjE4NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUHE0N0lHWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAvc29tZS1vYmovMTUzODA1MTE0NjQ1NjE4Ni9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwIiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0NjQ1NjE4NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1BxNDdJR1gyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwL3NvbWUtb2JqLzE1MzgwNTExNDY0NTYxODYvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMC9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwIiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0NjQ1NjE4NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQcTQ3SUdYMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoid2VWZjBRPT0iLCJldGFnIjoiQ1BxNDdJR1gyOTBDRUFFPSIsInJldGVudGlvbkV4cGlyYXRpb25UaW1lIjoiMjAxOC0wOS0yN1QxMzoyNTo0Ni40NTRaIn0=" + } + }, + { + "ID": "6cd308150938c9ed", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b7b72476a97dc563ea515dd0419a2d50/161570476158247522;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010/o/some-obj?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3338" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:46 GMT" + ], + "Etag": [ + "CPq47IGX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051446000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vneg3:4091,/bns/yx/borg/yx/bns/blobstore2/bitpusher/152.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=SsysW9ykKoaJzgLa9JeAAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/152.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/152:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWWhLRWRJS21GUEgxdEtyUnZ6LTVHcEpFV2I3OTF6d2FCanpvT0REdnVuTmhHVVBINWJHX1BHc1ljQ2JIS0hpR1QtR1ZSOHdaTlZqMFJQdml6U2NZUnRQUWg3QkdWU1UzbXNkXzNJSERFRUFoQVVXU3ZQZHNMSmZocVBubWZlZUgtb3pCMEtxQ3hFRTBob2FQbTRqQmlvMXVidF9WSlVuZmVvcl9sZkhCLTMxWkpsNENCQ1dIRXVRQ1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Upwz4yjfKZJQXT-HE1cBx9y61M5M7GcsWo_go1oLuR8khJs4XxiRj3nJg-ujAWf-tnN7hNKuXHv8p9abUc27DobK2BkcA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMC9zb21lLW9iai8xNTM4MDUxMTQ2NDU2MTg2Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwL28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0NjQ1NjE4NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQ2LjQ1NFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNTo0Ni40NTRaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDYuNDU0WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJRWm5CNUtSZSs4aTJ4d2w3K2pGMVJRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwL28vc29tZS1vYmo/Z2VuZXJhdGlvbj0xNTM4MDUxMTQ2NDU2MTg2JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwL3NvbWUtb2JqLzE1MzgwNTExNDY0NTYxODYvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAvby9zb21lLW9iai9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAiLCJvYmplY3QiOiJzb21lLW9iaiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTQ2NDU2MTg2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUHE0N0lHWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAvc29tZS1vYmovMTUzODA1MTE0NjQ1NjE4Ni9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAvby9zb21lLW9iai9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwIiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0NjQ1NjE4NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUHE0N0lHWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAvc29tZS1vYmovMTUzODA1MTE0NjQ1NjE4Ni9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAvby9zb21lLW9iai9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwIiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0NjQ1NjE4NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1BxNDdJR1gyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwL3NvbWUtb2JqLzE1MzgwNTExNDY0NTYxODYvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMC9vL3NvbWUtb2JqL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwIiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE0NjQ1NjE4NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQcTQ3SUdYMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoid2VWZjBRPT0iLCJldGFnIjoiQ1BxNDdJR1gyOTBDRUFFPSIsInJldGVudGlvbkV4cGlyYXRpb25UaW1lIjoiMjAxOC0wOS0yN1QxMzoyNTo0Ni40NTRaIn0=" + } + }, + { + "ID": "f52f400fa7e43a90", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "25" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b86e7859e62fb9ea4a7c82cbf53f7e0b/1751982375913719809;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJyZXRlbnRpb25Qb2xpY3kiOm51bGx9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2353" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:48 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051447000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnaz64:4220,/bns/yx/borg/yx/bns/blobstore2/bitpusher/147.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=SsysW_bNL46YzQKvubuIDg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/147.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/147:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWWhLRWRJS21GUEgxdEtyUnZ6LTVHcEpFV2I3OTF6d2FCanpvT0REdnVuTmhHVVBINWJHX1BHc1ljQ2JIS0hpR1QtR1ZSOHdaTlZqMFJQdml6U2NZUnRQUWg3QkdWU1UzbXNkXzNJSERFRUFoQVVXU3ZQZHNMSmZocVBubWZlZUgtb3pCMEtxQ3hFRTBob2FQbTRqQmlvMXVidF9WSlVuZmVvcl9sZkhCLTMxWkpsNENCQ1dIRXVRQ1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpDMEyndQWEVKJnGEtbhRAyCqFEjYGH6cqgGiUAmmrf4CTeY9phBbXpQxFAl0RLmwwilggpY04j79eA0cxPBBnZCG3lIQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NDUuODU3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjQ4LjEyMFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEwL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "b2ec087cf2118f91", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010/o/some-obj?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d6b2b26a710f3d11142874553579d124/2583357310559738448;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010/o/some-obj?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:48 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051446000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdx87:4375,/bns/yv/borg/yv/bns/blobstore2/bitpusher/339.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=TMysW92LFMrqgwTa5YP4AQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/339.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/339:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWWhLRWRJS21GUEgxdEtyUnZ6LTVHcEpFV2I3OTF6d2FCanpvT0REdnVuTmhHVVBINWJHX1BHc1ljQ2JIS0hpR1QtR1ZSOHdaTlZqMFJQdml6U2NZUnRQUWg3QkdWU1UzbXNkXzNJSERFRUFoQVVXU3ZQZHNMSmZocVBubWZlZUgtb3pCMEtxQ3hFRTBob2FQbTRqQmlvMXVidF9WSlVuZmVvcl9sZkhCLTMxWkpsNENCQ1dIRXVRQ1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UodSFemSWw3f41ZGelIJMWcecf1K1IJI-BDg-FGF7JngeV5eeYZY1QJbmlh6M3HYaBxdOadLCvOH-CMy1xYTZflI3cPFA" + ] + }, + "Body": "" + } + }, + { + "ID": "350aa556ebfb5939", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0c824b79369ca5b0582093808bcfc251/4173487743928369391;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 429, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "12085" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:48 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:48 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051446000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrl7:4233,/bns/yw/borg/yw/bns/blobstore2/bitpusher/117.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=TMysW5vmJsWThQT875SgCg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/117.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/117:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWWhLRWRJS21GUEgxdEtyUnZ6LTVHcEpFV2I3OTF6d2FCanpvT0REdnVuTmhHVVBINWJHX1BHc1ljQ2JIS0hpR1QtR1ZSOHdaTlZqMFJQdml6U2NZUnRQUWg3QkdWU1UzbXNkXzNJSERFRUFoQVVXU3ZQZHNMSmZocVBubWZlZUgtb3pCMEtxQ3hFRTBob2FQbTRqQmlvMXVidF9WSlVuZmVvcl9sZkhCLTMxWkpsNENCQ1dIRXVRQ1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo3ylDcXvoHItOtoj6RY5otQx8n7iP_-eEGL30SzZrQeFXj3J1cwR69rTGuf6rY9RzGK2sHqAPBdd-gQLsua2H81DOkFQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6InVzYWdlTGltaXRzIiwicmVhc29uIjoicmF0ZUxpbWl0RXhjZWVkZWQiLCJtZXNzYWdlIjoiVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBEZWxldGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkRlbGV0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQnVja2V0LmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5EZWxldGVCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUJ1Y2tldC5qYXZhOjIzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5kZWxldGUoQnVja2V0c0RlbGVnYXRvci5qYXZhOjExNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IERlbGV0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9VE9PX01BTllfUkVRVUVTVFMsIGNhdGVnb3J5PVFVT1RBX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlBST0pFQ1RfQlVDS0VUX09QX1JBVEVfVE9PX0hJR0g6IERlbGV0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuRGVsZXRlQnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVCdWNrZXQuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkRlbGV0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQnVja2V0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmRlbGV0ZShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTE1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogRGVsZXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj11c2FnZUxpbWl0cywgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPXRvb01hbnlSZXF1ZXN0cywgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1jbG91ZC5iaWdzdG9yZS5hcGkuQmlnc3RvcmVFcnJvckRvbWFpbi5DTElFTlRfUVVPVEFfRVhDRUVERUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBEZWxldGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkRlbGV0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQnVja2V0LmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5EZWxldGVCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUJ1Y2tldC5qYXZhOjIzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5kZWxldGUoQnVja2V0c0RlbGVnYXRvci5qYXZhOjExNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IERlbGV0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1DTElFTlRfUVVPVEFfRVhDRUVERUQsIGVycm9yUHJvdG9Eb21haW49Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2VfaWQubmFtZSwgbWVzc2FnZT1UaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLm5hbWUsIG1lc3NhZ2U9VGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiwgcmVhc29uPXJhdGVMaW1pdEV4Y2VlZGVkLCBycGNDb2RlPTQyOX0gVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlBST0pFQ1RfQlVDS0VUX09QX1JBVEVfVE9PX0hJR0g6IERlbGV0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuRGVsZXRlQnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVCdWNrZXQuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkRlbGV0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQnVja2V0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmRlbGV0ZShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTE1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogRGVsZXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDI5LCJtZXNzYWdlIjoiVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiJ9fQ==" + } + }, + { + "ID": "7aaeb5b6064014cf", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0c824b79369ca5b0582093808bcfc251/4932805084536460094;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 429, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "12085" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:49 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:49 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051446000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrce189:4322,/bns/yr/borg/yr/bns/blobstore2/bitpusher/74.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=TcysW7VS0LrhBIS3nfgL" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/74.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/74:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWWhLRWRJS21GUEgxdEtyUnZ6LTVHcEpFV2I3OTF6d2FCanpvT0REdnVuTmhHVVBINWJHX1BHc1ljQ2JIS0hpR1QtR1ZSOHdaTlZqMFJQdml6U2NZUnRQUWg3QkdWU1UzbXNkXzNJSERFRUFoQVVXU3ZQZHNMSmZocVBubWZlZUgtb3pCMEtxQ3hFRTBob2FQbTRqQmlvMXVidF9WSlVuZmVvcl9sZkhCLTMxWkpsNENCQ1dIRXVRQ1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoHEannxoQgJHDWnyc3VdxrvGoBWcWYnpGbLyOcR9hKEOc4ujSkrKiQTv7WEwa595fMdZxHTDEZDX9WhbXdhMYvhS465w" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6InVzYWdlTGltaXRzIiwicmVhc29uIjoicmF0ZUxpbWl0RXhjZWVkZWQiLCJtZXNzYWdlIjoiVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBEZWxldGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkRlbGV0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQnVja2V0LmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5EZWxldGVCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUJ1Y2tldC5qYXZhOjIzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5kZWxldGUoQnVja2V0c0RlbGVnYXRvci5qYXZhOjExNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IERlbGV0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9VE9PX01BTllfUkVRVUVTVFMsIGNhdGVnb3J5PVFVT1RBX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlBST0pFQ1RfQlVDS0VUX09QX1JBVEVfVE9PX0hJR0g6IERlbGV0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuRGVsZXRlQnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVCdWNrZXQuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkRlbGV0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQnVja2V0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmRlbGV0ZShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTE1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogRGVsZXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj11c2FnZUxpbWl0cywgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPXRvb01hbnlSZXF1ZXN0cywgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1jbG91ZC5iaWdzdG9yZS5hcGkuQmlnc3RvcmVFcnJvckRvbWFpbi5DTElFTlRfUVVPVEFfRVhDRUVERUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBEZWxldGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkRlbGV0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQnVja2V0LmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5EZWxldGVCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUJ1Y2tldC5qYXZhOjIzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5kZWxldGUoQnVja2V0c0RlbGVnYXRvci5qYXZhOjExNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IERlbGV0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1DTElFTlRfUVVPVEFfRVhDRUVERUQsIGVycm9yUHJvdG9Eb21haW49Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2VfaWQubmFtZSwgbWVzc2FnZT1UaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLm5hbWUsIG1lc3NhZ2U9VGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiwgcmVhc29uPXJhdGVMaW1pdEV4Y2VlZGVkLCBycGNDb2RlPTQyOX0gVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlBST0pFQ1RfQlVDS0VUX09QX1JBVEVfVE9PX0hJR0g6IERlbGV0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuRGVsZXRlQnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVCdWNrZXQuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkRlbGV0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQnVja2V0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmRlbGV0ZShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTE1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogRGVsZXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDI5LCJtZXNzYWdlIjoiVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiJ9fQ==" + } + }, + { + "ID": "2ebbcc95335f4f93", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0c824b79369ca5b0582093808bcfc251/5763898544205833613;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 429, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "12085" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:49 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:49 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051446000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrp62:4379,/bns/yv/borg/yv/bns/blobstore2/bitpusher/357.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=TcysW7_eK5CDgQS0t7uoDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/357.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/357:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWWhLRWRJS21GUEgxdEtyUnZ6LTVHcEpFV2I3OTF6d2FCanpvT0REdnVuTmhHVVBINWJHX1BHc1ljQ2JIS0hpR1QtR1ZSOHdaTlZqMFJQdml6U2NZUnRQUWg3QkdWU1UzbXNkXzNJSERFRUFoQVVXU3ZQZHNMSmZocVBubWZlZUgtb3pCMEtxQ3hFRTBob2FQbTRqQmlvMXVidF9WSlVuZmVvcl9sZkhCLTMxWkpsNENCQ1dIRXVRQ1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrregfVY1sg5Sp_yURvbA5_SFSGMdDtgIbhnq8lhUf0vZbfw7xFwy8ew6Z2q7pHEKyfkuLasT2ZtE7GUr7X6j8CPGtb_g" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6InVzYWdlTGltaXRzIiwicmVhc29uIjoicmF0ZUxpbWl0RXhjZWVkZWQiLCJtZXNzYWdlIjoiVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBEZWxldGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkRlbGV0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQnVja2V0LmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5EZWxldGVCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUJ1Y2tldC5qYXZhOjIzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5kZWxldGUoQnVja2V0c0RlbGVnYXRvci5qYXZhOjExNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IERlbGV0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9VE9PX01BTllfUkVRVUVTVFMsIGNhdGVnb3J5PVFVT1RBX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlBST0pFQ1RfQlVDS0VUX09QX1JBVEVfVE9PX0hJR0g6IERlbGV0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuRGVsZXRlQnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVCdWNrZXQuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkRlbGV0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQnVja2V0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmRlbGV0ZShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTE1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogRGVsZXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj11c2FnZUxpbWl0cywgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPXRvb01hbnlSZXF1ZXN0cywgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1jbG91ZC5iaWdzdG9yZS5hcGkuQmlnc3RvcmVFcnJvckRvbWFpbi5DTElFTlRfUVVPVEFfRVhDRUVERUQsIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpQUk9KRUNUX0JVQ0tFVF9PUF9SQVRFX1RPT19ISUdIOiBEZWxldGluZyBidWNrZXRzIHRvbyBxdWlja2x5LCBwbGVhc2Ugc2xvdyBkb3duXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkRlbGV0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQnVja2V0LmphdmE6NzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5EZWxldGVCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZUJ1Y2tldC5qYXZhOjIzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5kZWxldGUoQnVja2V0c0RlbGVnYXRvci5qYXZhOjExNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IERlbGV0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1DTElFTlRfUVVPVEFfRVhDRUVERUQsIGVycm9yUHJvdG9Eb21haW49Y2xvdWQuYmlnc3RvcmUuYXBpLkJpZ3N0b3JlRXJyb3JEb21haW4sIGZpbHRlcmVkTWVzc2FnZT1udWxsLCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2VfaWQubmFtZSwgbWVzc2FnZT1UaGUgcHJvamVjdCBleGNlZWRlZCB0aGUgcmF0ZSBsaW1pdCBmb3IgY3JlYXRpbmcgYW5kIGRlbGV0aW5nIGJ1Y2tldHMuLCB1bm5hbWVkQXJndW1lbnRzPVtdfSwgbG9jYXRpb249ZW50aXR5LnJlc291cmNlX2lkLm5hbWUsIG1lc3NhZ2U9VGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiwgcmVhc29uPXJhdGVMaW1pdEV4Y2VlZGVkLCBycGNDb2RlPTQyOX0gVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlBST0pFQ1RfQlVDS0VUX09QX1JBVEVfVE9PX0hJR0g6IERlbGV0aW5nIGJ1Y2tldHMgdG9vIHF1aWNrbHksIHBsZWFzZSBzbG93IGRvd25cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuRGVsZXRlQnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVCdWNrZXQuamF2YTo3MSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkRlbGV0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlQnVja2V0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmRlbGV0ZShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTE1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogRGVsZXRpbmcgYnVja2V0cyB0b28gcXVpY2tseSwgcGxlYXNlIHNsb3cgZG93blxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDI5LCJtZXNzYWdlIjoiVGhlIHByb2plY3QgZXhjZWVkZWQgdGhlIHJhdGUgbGltaXQgZm9yIGNyZWF0aW5nIGFuZCBkZWxldGluZyBidWNrZXRzLiJ9fQ==" + } + }, + { + "ID": "3edc73005530733b", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0c824b79369ca5b0582093808bcfc251/6522935513627031772;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0010?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:53 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051445000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vntt133:4318,/bns/yw/borg/yw/bns/blobstore2/bitpusher/157.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=UMysW7elKYLnN5zigqgK" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/157.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/157:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWWhLRWRJS21GUEgxdEtyUnZ6LTVHcEpFV2I3OTF6d2FCanpvT0REdnVuTmhHVVBINWJHX1BHc1ljQ2JIS0hpR1QtR1ZSOHdaTlZqMFJQdml6U2NZUnRQUWg3QkdWU1UzbXNkXzNJSERFRUFoQVVXU3ZQZHNMSmZocVBubWZlZUgtb3pCMEtxQ3hFRTBob2FQbTRqQmlvMXVidF9WSlVuZmVvcl9sZkhCLTMxWkpsNENCQ1dIRXVRQ1EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UocdzltEwu8I8TD_NoAYID4E9DjuZ0ms_uu-qjIUWzE5LhuXYKS0lxfzfKyBPrns-r3ZIMU10abKbPF0wAd25p04JqFXw" + ] + }, + "Body": "" + } + }, + { + "ID": "16fa5da19588dcb2", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "103" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "f223250479f9326d3120a77d446cfcc0/8113347417694182779;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDExIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "512" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:53 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051453000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vri14:4058,/bns/yr/borg/yr/bns/blobstore2/bitpusher/56.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=UcysW8mmEIu-4QSu3Jz4Aw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/56.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/56:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrobIhiXco9A_-oMp2VoLDQLC5201S_4RyjRRZxpMTx2Zv8ZQIy5Nit2onYj9_d72nRNL9xdxtJRI-TI2FXlJEbhkAzwg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NTMuNzY5WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjUzLjc2OVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMjdUMTI6MjU6NTMuNzY5WiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" + } + }, + { + "ID": "fde3f1916684ed66", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0011?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "47" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0d879cc229c3bee2bb0b0a9783868213/9703759321744556826;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0011?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiMzYwMCJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2441" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:55 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051454000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnno9:4384,/bns/yw/borg/yw/bns/blobstore2/bitpusher/150.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=UcysW-6JOsPJhASY15bgDQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/150.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/150:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqgSqPtAP9ja5GplqzD5idak2DxVIHfikqXTwLl-RQfR82NbOjWTMMCHClKja8qnc59jKReVtM0g_SaSDptgLgpVxWGOg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NTMuNzY5WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjU1LjIzOVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDExL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiIzNjAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMjdUMTI6MjU6NTMuNzY5WiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" + } + }, + { + "ID": "8a91697bbe3e6511", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0011?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "6db55bdaeee6d1b5348ac0cb62d8c887/11294171221516871864;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0011?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2441" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:55 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:55 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051453000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnz126:4460,/bns/yx/borg/yx/bns/blobstore2/bitpusher/39.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=U8ysW63uHMbUzwLGrZrQAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/39.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/39:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqjdbmLX5yJrLPaS36C6KBnXWtkd3J95Z_ftw6bzTcSkCNgUwj3IpOgLOOTh5eH2ltPmePXC_XyuZZsyce_xjfVTGXMmQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NTMuNzY5WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjU1LjIzOVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTEiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDExL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTEiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiIzNjAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMjdUMTI6MjU6NTMuNzY5WiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" + } + }, + { + "ID": "9bbed24b50a1eaa1", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "103" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "802d3dc20f903c593a444cdd814956c7/12884300555390651991;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEyIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "512" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:56 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051453000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vruw21:4201,/bns/yv/borg/yv/bns/blobstore2/bitpusher/50.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=U8ysW5q4MpHLswb4lL2QAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/50.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/50:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoXG9bPCZjg8Y-JYI_mKdqxDfcvxy1T1PEOnEOwqO3hTQsieNFGouIFTCWTs_WPwVLYtb44oe_VICNWurm3S0GPUXvizw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTIiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NTYuMzg0WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjU2LjM4NFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMjdUMTI6MjU6NTYuMzg0WiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" + } + }, + { + "ID": "f1c21ab6b25294f4", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0012?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "47" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4048de951dc5ccf83e71e2ffdece3a3e/14474712459457803254;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0012?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiMzYwMCJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2441" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:58 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051454000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnlf2:4485,/bns/yx/borg/yx/bns/blobstore2/bitpusher/94.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=VMysW6uqJcngzgL4h4rADw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/94.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/94:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoMFwI7mcS4cWtpbLK42cpnqw0kSanMUXAFgllAzXYjMAP7pqhOjWKPzKeGP889Mcw9U3Y-M7fNZ0e7QNmm7i_4IaLWvQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTIiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NTYuMzg0WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjU4LjI1N1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMi9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTIvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTIvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEyL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTIiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiIzNjAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMjdUMTI6MjU6NTYuMzg0WiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" + } + }, + { + "ID": "6f5d255f0d88f21b", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0012?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1c795c1024bc55ef42d27faffed977f3/16065124363508242836;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0012?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2441" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:58 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:25:58 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051458000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbq123:4158,/bns/yv/borg/yv/bns/blobstore2/bitpusher/295.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=VsysW6TRHIjeggTPoo6QAg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/295.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/295:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoPL5yIP9ZEqMYOFdRS_FrN6uAVgJDcH82ZdNWFTiRzrpzphlRzFY7M7_qfGxNAhJodJCRNpjkt0TmohT1V5v8okMD72A" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTIiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NTYuMzg0WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjU4LjI1N1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMi9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTIvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTIvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEyL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTIiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiIzNjAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMjdUMTI6MjU6NTYuMzg0WiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" + } + }, + { + "ID": "4b64fc29d8731a8f", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "103" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "64bbece284f2952cd259b93aee5a9e73/17583198298072448563;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEzIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "512" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:25:59 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051453000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vryy20:4108,/bns/yv/borg/yv/bns/blobstore2/bitpusher/37.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=VsysW_SiNsz5gASdporABw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/37.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/37:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpqMbhbjEYwtx_QsZjoA3HbE40bhjEQzZU2TbptRTES7Bq3MHuojyXP0eKhY3Y9VCIhn8spjA4y4fSsdshX9umGMl1fe2uK8yNasoLTBPqcv6DyUuE" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTMiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NTkuNTA4WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjU5LjUwOFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMjdUMTI6MjU6NTkuNTA4WiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" + } + }, + { + "ID": "496195d1abcde418", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0013?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "25" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "697aa538323c65d1011f2f6844cd5763/727147603389981906;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0013?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJyZXRlbnRpb25Qb2xpY3kiOm51bGx9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2353" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:01 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051454000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnew15:4140,/bns/yx/borg/yx/bns/blobstore2/bitpusher/83.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=V8ysW8rRLsW1zALZhJywDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/83.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/83:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrbY7boJBe2XoPiqZsTc01Uxq6nqiB2OXZBh1o6oSng7jBQL9mpCi5qkBcck0oI_DAJTDbBjDuflfdVXyA2hLXAl70_FA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTMiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NTkuNTA4WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjAwLjgyM1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTMvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEzL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTMiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "0b8bf573cd2107c4", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0013?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d9d2b7dcaa66aaabfa2864d56c5d3a72/2317558407962347888;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0013?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2353" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:01 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:01 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051453000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnhu9:4289,/bns/yx/borg/yx/bns/blobstore2/bitpusher/102.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=WcysW4T4AszpzgLY0KnIDg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/102.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/102:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrbRCrtu0mTZRDhZrFXk7VrictqM0zKI1U8DoFpKO28cynd5QzxKB5J7XCMWYbXrJca3OalA-IIX45CGsetEVGp4qZISg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTMiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjU6NTkuNTA4WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjAwLjgyM1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxMyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTMvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDEzL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTMiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "a7c95422a2471394", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "103" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0e89c35a6de9f58ec66d48975c54b4f9/3907970307717820175;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE0IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "512" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:02 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051453000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdh9:4228,/bns/yv/borg/yv/bns/blobstore2/bitpusher/304.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=WcysW63cGcSqgQSHvaiACQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/304.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/304:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpP8VkKvEDcF-JqT0gT3fvzqoizXGbFNONJWx8R5oaqlSM0Q0uc5ken0aSOiix0NPrauvWu1QRiwbreckiadEfVgtHnVg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTQiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MDEuODgxWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjAxLjg4MVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMjdUMTI6MjY6MDEuODgxWiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" + } + }, + { + "ID": "325d0ff065c04d4e", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0014?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "25" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "51fd4d8c082df8e4d506278eb1ca823b/5498100741103228078;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0014?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJyZXRlbnRpb25Qb2xpY3kiOm51bGx9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2353" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:03 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051462000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrba123:4470,/bns/yv/borg/yv/bns/blobstore2/bitpusher/259.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=WsysW7KWC8mngASFkp7wAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/259.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/259:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqJUrTAXY29C_wmpxbjt01tQ4m9VTBeUypKlJzX15UwDuSJe5hsBBynDQsl5a16PpiVFdBz0u-Vf-X5ZRRt209TtmIHKw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTQiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MDEuODgxWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjAzLjUyMFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTQvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTQvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE0L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTQiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "cca326efdc436d37", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0014?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4ab7fb4514357f83b302152b924fb136/7088512645153667660;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0014?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2353" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:03 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:03 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051458000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrnn4:4418,/bns/yv/borg/yv/bns/blobstore2/bitpusher/270.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=W8ysW5i6LIykNvW7uMAB" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/270.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/270:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpbKUoJzMFO7uO-VveC3KwrCtOcCOHRDrLKCkq-DsuFXnTJrCWiiMgqfkbFYrmOP-ubGDpLSrMWmRKLmSXBxP8Gry44mA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTQiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MDEuODgxWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjAzLjUyMFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTQiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTQvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTQvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE0L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTQiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "63c01600827f77b3", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "103" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "c9bb61a9fd1b4ae9f5981ca5df957f93/8678924544925917163;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE1IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "512" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:04 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051453000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrud24:4012,/bns/yv/borg/yv/bns/blobstore2/bitpusher/387.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=XMysW89vy6KCBKOFl_AD" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/387.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/387:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrUsJUBq_XX9ztZulVTMu3salJ5JDRcpfmZ0mmdN70LnnzyOiN2Y8ICZBiw2LZ5ahaPBX2P3IaVz8keKoWCNgAX7TenNA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTUiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MDQuNDU0WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjA0LjQ1NFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjYwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMjdUMTI6MjY6MDQuNDU0WiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" + } + }, + { + "ID": "768bc98442297830", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0015?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "71269e6dd6eb30c6c2d4b40e6b4d950f/10269053878799697290;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0015?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2439" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:06 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051462000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrni16:4226,/bns/yv/borg/yv/bns/blobstore2/bitpusher/221.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=XMysW-W9LM_kgwSjmoe4DQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/221.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/221:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uox4G0BhHPrZfc-b4hSe5pLsjUItbWWUixSn0GyQ5oUgO_Pp74soedZ0zi0uAJ23USfmwKxzzrdNmWS5mGPrSA7xMDoWg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTUiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MDQuNDU0WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjA2LjAzM1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTUvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTUvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE1L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI2MCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE4LTA5LTI3VDEyOjI2OjA0LjQ1NFoifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FJPSJ9" + } + }, + { + "ID": "cdd3f2848c873bb4", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0015?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "c16176bddcc21b2c6d2882ce5fd06ae1/11859465782866913832;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0015?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2439" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:06 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:06 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051458000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrqs12:4337,/bns/yw/borg/yw/bns/blobstore2/bitpusher/196.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=XsysW8nRDtayN7DNhPAN" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/196.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/196:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uov7rSAsXMYIGR6Ss96xbFjQgp0NIncfsGrPyYJrNeooyiPImTTAN4_Bc7mxhhFQAajgNguI2PRkTggi9Gg2ILtEGzpXg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTUiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MDQuNDU0WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjA2LjAzM1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTUvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTUvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE1L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI2MCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE4LTA5LTI3VDEyOjI2OjA0LjQ1NFoifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FJPSJ9" + } + }, + { + "ID": "186f1f73a6d920af", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0015?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "455235aa4f1ed37b4bb469c1d623fc80/13449877686917288135;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0015?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:07 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051466000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnf65:4298,/bns/yx/borg/yx/bns/blobstore2/bitpusher/73.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=XsysW8DKJce6zwLWnrjACQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/73.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/73:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrUvGh7bHpgmVxRKfm-xKQepbBeSGbWt50TgXOFRbNlv_XSDoVmBBQYQXpkmZw0TUnXHNvfkDQnr9mVvq1aWtZ4ug8lsA" + ] + }, + "Body": "" + } + }, + { + "ID": "dfd8fbe545d7bee6", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0014?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "07a05ef320720f3b509ec54f162283bb/15040289586689602917;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0014?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:07 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051453000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrqi15:4037,/bns/yr/borg/yr/bns/blobstore2/bitpusher/28.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=X8ysW9iWBKiWkATJhbDgBQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/28.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/28:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UobaiYoUYiX5ZJvU-OYpl1FY5F9nfQiJXeWBYxdo-WvOnvz5aVbrblbXtwUnAzgH0UyM3mc2drAZddD0clThFqqJP61Gw" + ] + }, + "Body": "" + } + }, + { + "ID": "012e95579c6845fb", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0013?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "dbcd5340924fe39a15e8e32ab27745fe/16630420020058233604;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0013?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:07 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051453000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrfw24:4041,/bns/yr/borg/yr/bns/blobstore2/bitpusher/53.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=X8ysW4fcHcX4kAOu3LKIDg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/53.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/53:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoSbsEMlGkIsvaXr6x6MfACr66APL8lwZSivf3_cryiFk4Vt_8ap4MIFxSDS0CMex25ggALxCfJNIKispqIj9qd5FgM-A" + ] + }, + "Body": "" + } + }, + { + "ID": "62966b136cf0b529", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0012?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "07fa936444fbf30801717d2d264883c6/18220830824630534307;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0012?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:08 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051453000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrt3:4124,/bns/yr/borg/yr/bns/blobstore2/bitpusher/96.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=X8ysW__bOsihkATs_LGgCw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/96.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/96:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uqy0RkP5XEsHo3lOvqW35li0Pw0z3juzlb9FvypLY_302_58O6U-mg6Vjn-cJpHJSjkmbIjP8-g5V1n-2CZ9S3yvkbq_g" + ] + }, + "Body": "" + } + }, + { + "ID": "308931080dfea4b9", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0011?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "81a10a84360b6edf4533bd4f550bb0d0/1364780125653231169;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0011?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:08 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051453000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrjl65:4261,/bns/yv/borg/yv/bns/blobstore2/bitpusher/211.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=YMysW_22G8fWgwSThbvoBw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/211.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/211:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWkdVeUFHMkhLRHc5UlRMb3BORW9Rb2xrMjQ2NGItSkRZcnRkVjRCV21pUlNvVVY2Q2w3WTlJTk1FZWFKY2FnRlFZc0ZHcVpmbU84dUgxMG5aYl9IWnIzTkhKMFJOQjJEUWhEVnlMQ0JaaVNlQlJHZUhtWDlpRGN2OE9iaEppdVBmbG93Y3NEbWtObF9lSzRaVUNrVmd4Nm5QRmhJak1JSUtKYkpLbnBqN2pCMEkwcnE2TmxKRlAtWmswBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqIieaMhbydFRqWbKPS5MmBE4LNbvLVhM6e9eGRbbgl0_hso2ahTxY4gWLqyahE89LsT91qfndHkp9Fzq-5NPhltIEdrA" + ] + }, + "Body": "" + } + }, + { + "ID": "d1beb37dcd83aa6a", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "106" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "64af50f9fd3c73200370a81b5f0883c8/2883135535194082272;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "515" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:09 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051468000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlq86:4154,/bns/yv/borg/yv/bns/blobstore2/bitpusher/301.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=YMysW5HAOMaPgQTXw4nIBw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/301.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/301:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYTVGNmlfNzNkdVJhUVRFQXNzZUdCeEdGWld0bm9pVHl0TGhyNW1FY0hyQTF4eDJEXzNxS2cwUGxYVTJhZC1kOHl3dE9jMUVrNzZmVXdFU2J1TlpoVE9NWThoaEhzNlRjUTl1dHRwNHZZRmJBODdBX05uZ1BwNWIxRHdNR1NQUXV2XzdySWxFZjFtQTVRRUMyZThES1VqcHotcmFtNFJMc01MR2x0aVdrTFQzNlNXLVNZMFhjVlpFVG8wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Urvb0freP0GJIhCc7eyV_aUlJDKx3W0kq2q99OI4-jWaBAzkU-aGnP6QsWrmOiP-EMxe0DtGBtgqrud-qgZepmxpx3PNw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTYiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MDkuNDg3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjA5LjQ4N1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMjdUMTI6MjY6MDkuNDg3WiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" + } + }, + { + "ID": "5a146f91846e2f4b", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0016/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=4a385c57e7c68fe2d07ad9d19a8e1f50a9b104c1e57d1387629dc32ad0d9" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9c6200e4526c02cb8c8b5c77883e179c/3714228999141580335;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0016/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS00YTM4NWM1N2U3YzY4ZmUyZDA3YWQ5ZDE5YThlMWY1MGE5YjEwNGMxZTU3ZDEzODc2MjlkYzMyYWQwZDkNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNiIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJzb21lLW9iamVjdCJ9Cg0KLS00YTM4NWM1N2U3YzY4ZmUyZDA3YWQ5ZDE5YThlMWY1MGE5YjEwNGMxZTU3ZDEzODc2MjlkYzMyYWQwZDkNCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbg0KDQpoZWxsbyB3b3JsZA0KLS00YTM4NWM1N2U3YzY4ZmUyZDA3YWQ5ZDE5YThlMWY1MGE5YjEwNGMxZTU3ZDEzODc2MjlkYzMyYWQwZDktLQ0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3408" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:10 GMT" + ], + "Etag": [ + "CLajk42X290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051468000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrt186:4143,/bns/yr/borg/yr/bns/blobstore2/bitpusher/63.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=YcysW47OMJKQkATCvaHwDg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/63.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/63:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYTVGNmlfNzNkdVJhUVRFQXNzZUdCeEdGWld0bm9pVHl0TGhyNW1FY0hyQTF4eDJEXzNxS2cwUGxYVTJhZC1kOHl3dE9jMUVrNzZmVXdFU2J1TlpoVE9NWThoaEhzNlRjUTl1dHRwNHZZRmJBODdBX05uZ1BwNWIxRHdNR1NQUXV2XzdySWxFZjFtQTVRRUMyZThES1VqcHotcmFtNFJMc01MR2x0aVdrTFQzNlNXLVNZMFhjVlpFVG8wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq0lNITSEEX9MB17Og399j1oxQXjkF757LQ9dGaEIJ--anuY0cz52Whpi7vpIyV9kVIH-zuGiEZgxw-UCK-JEjurFLsOQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNi9zb21lLW9iamVjdC8xNTM4MDUxMTcwMTYxMDc4Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2L28vc29tZS1vYmplY3QiLCJuYW1lIjoic29tZS1vYmplY3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTYiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE3MDE2MTA3OCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjoxMC4xNjBaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MTAuMTYwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjEwLjE2MFoiLCJzaXplIjoiMTEiLCJtZDVIYXNoIjoiWHJZN3UrQWU3dENUeXlLN2oxck53dz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNi9vL3NvbWUtb2JqZWN0P2dlbmVyYXRpb249MTUzODA1MTE3MDE2MTA3OCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNi9zb21lLW9iamVjdC8xNTM4MDUxMTcwMTYxMDc4L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2L28vc29tZS1vYmplY3QvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2Iiwib2JqZWN0Ijoic29tZS1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE3MDE2MTA3OCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0xhams0MlgyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2L3NvbWUtb2JqZWN0LzE1MzgwNTExNzAxNjEwNzgvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2L28vc29tZS1vYmplY3QvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNiIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExNzAxNjEwNzgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0xhams0MlgyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2L3NvbWUtb2JqZWN0LzE1MzgwNTExNzAxNjEwNzgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2L28vc29tZS1vYmplY3QvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNiIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExNzAxNjEwNzgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNMYWprNDJYMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNi9zb21lLW9iamVjdC8xNTM4MDUxMTcwMTYxMDc4L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTYvby9zb21lLW9iamVjdC9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNiIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExNzAxNjEwNzgiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTGFqazQyWDI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6InlaUmxxZz09IiwiZXRhZyI6IkNMYWprNDJYMjkwQ0VBRT0iLCJyZXRlbnRpb25FeHBpcmF0aW9uVGltZSI6IjIwMTgtMDktMjhUMTM6MjY6MTAuMTYwWiJ9" + } + }, + { + "ID": "fc16f5c7b8a77052", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0016/o/some-object?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "6b5663749bf8ab9ea1692229808a7b22/4473265968562712959;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0016/o/some-object?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13776" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:10 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:10 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051468000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrjd27:4293,/bns/yw/borg/yw/bns/blobstore2/bitpusher/115.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=YsysW6CPGI-jhQTSyrfwDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/115.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/115:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYTVGNmlfNzNkdVJhUVRFQXNzZUdCeEdGWld0bm9pVHl0TGhyNW1FY0hyQTF4eDJEXzNxS2cwUGxYVTJhZC1kOHl3dE9jMUVrNzZmVXdFU2J1TlpoVE9NWThoaEhzNlRjUTl1dHRwNHZZRmJBODdBX05uZ1BwNWIxRHdNR1NQUXV2XzdySWxFZjFtQTVRRUMyZThES1VqcHotcmFtNFJMc01MR2x0aVdrTFQzNlNXLVNZMFhjVlpFVG8wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo_qg4-mUkzGfnA4DihWnTigVKTnnU-Rezw6vz2A3xHWZpDnrOUkw3-hDkcOOGydPq1y_TLcMAeYRtwAOGjU3FmE4YFig" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJPYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNi9zb21lLW9iamVjdCcgaXMgc3ViamVjdCB0byBidWNrZXQncyByZXRlbnRpb24gcG9saWN5IGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgMjAxOC0wOS0yOFQwNjoyNjoxMC4xNjA5Mjg0NDYtMDc6MDAiLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6UkVURU5USU9OX1BPTElDWV9OT1RfTUVUOiBPYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNi9zb21lLW9iamVjdCcgaXMgc3ViamVjdCB0byBidWNrZXQncyByZXRlbnRpb24gcG9saWN5IGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgMjAxOC0wOS0yOFQwNjoyNjoxMC4xNjA5Mjg0NDYtMDc6MDBcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo3Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogT2JqZWN0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTYvc29tZS1vYmplY3QnIGlzIHN1YmplY3QgdG8gYnVja2V0J3MgcmV0ZW50aW9uIHBvbGljeSBhbmQgY2Fubm90IGJlIGRlbGV0ZWQsIG92ZXJ3cml0dGVuIG9yIGFyY2hpdmVkIHVudGlsIDIwMTgtMDktMjhUMDY6MjY6MTAuMTYwOTI4NDQ2LTA3OjAwXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVRFTlRJT05fUE9MSUNZX05PVF9NRVQ6IE9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2L3NvbWUtb2JqZWN0JyBpcyBzdWJqZWN0IHRvIGJ1Y2tldCdzIHJldGVudGlvbiBwb2xpY3kgYW5kIGNhbm5vdCBiZSBkZWxldGVkLCBvdmVyd3JpdHRlbiBvciBhcmNoaXZlZCB1bnRpbCAyMDE4LTA5LTI4VDA2OjI2OjEwLjE2MDkyODQ0Ni0wNzowMFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjc3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBPYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNi9zb21lLW9iamVjdCcgaXMgc3ViamVjdCB0byBidWNrZXQncyByZXRlbnRpb24gcG9saWN5IGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgMjAxOC0wOS0yOFQwNjoyNjoxMC4xNjA5Mjg0NDYtMDc6MDBcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9Zm9yYmlkZGVuLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5GT1JCSURERU4sIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpSRVRFTlRJT05fUE9MSUNZX05PVF9NRVQ6IE9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2L3NvbWUtb2JqZWN0JyBpcyBzdWJqZWN0IHRvIGJ1Y2tldCdzIHJldGVudGlvbiBwb2xpY3kgYW5kIGNhbm5vdCBiZSBkZWxldGVkLCBvdmVyd3JpdHRlbiBvciBhcmNoaXZlZCB1bnRpbCAyMDE4LTA5LTI4VDA2OjI2OjEwLjE2MDkyODQ0Ni0wNzowMFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjc3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBPYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNi9zb21lLW9iamVjdCcgaXMgc3ViamVjdCB0byBidWNrZXQncyByZXRlbnRpb24gcG9saWN5IGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgMjAxOC0wOS0yOFQwNjoyNjoxMC4xNjA5Mjg0NDYtMDc6MDBcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1GT1JCSURERU4sIGVycm9yUHJvdG9Eb21haW49Z2RhdGEuQ29yZUVycm9yRG9tYWluLCBmaWx0ZXJlZE1lc3NhZ2U9bnVsbCwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1PYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNi9zb21lLW9iamVjdCcgaXMgc3ViamVjdCB0byBidWNrZXQncyByZXRlbnRpb24gcG9saWN5IGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgMjAxOC0wOS0yOFQwNjoyNjoxMC4xNjA5Mjg0NDYtMDc6MDAsIHVubmFtZWRBcmd1bWVudHM9W119LCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPU9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2L3NvbWUtb2JqZWN0JyBpcyBzdWJqZWN0IHRvIGJ1Y2tldCdzIHJldGVudGlvbiBwb2xpY3kgYW5kIGNhbm5vdCBiZSBkZWxldGVkLCBvdmVyd3JpdHRlbiBvciBhcmNoaXZlZCB1bnRpbCAyMDE4LTA5LTI4VDA2OjI2OjEwLjE2MDkyODQ0Ni0wNzowMCwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IE9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2L3NvbWUtb2JqZWN0JyBpcyBzdWJqZWN0IHRvIGJ1Y2tldCdzIHJldGVudGlvbiBwb2xpY3kgYW5kIGNhbm5vdCBiZSBkZWxldGVkLCBvdmVyd3JpdHRlbiBvciBhcmNoaXZlZCB1bnRpbCAyMDE4LTA5LTI4VDA2OjI2OjEwLjE2MDkyODQ0Ni0wNzowMDogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OlJFVEVOVElPTl9QT0xJQ1lfTk9UX01FVDogT2JqZWN0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTYvc29tZS1vYmplY3QnIGlzIHN1YmplY3QgdG8gYnVja2V0J3MgcmV0ZW50aW9uIHBvbGljeSBhbmQgY2Fubm90IGJlIGRlbGV0ZWQsIG92ZXJ3cml0dGVuIG9yIGFyY2hpdmVkIHVudGlsIDIwMTgtMDktMjhUMDY6MjY6MTAuMTYwOTI4NDQ2LTA3OjAwXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6NzcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjIzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5kZWxldGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjExMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2L3NvbWUtb2JqZWN0JyBpcyBzdWJqZWN0IHRvIGJ1Y2tldCdzIHJldGVudGlvbiBwb2xpY3kgYW5kIGNhbm5vdCBiZSBkZWxldGVkLCBvdmVyd3JpdHRlbiBvciBhcmNoaXZlZCB1bnRpbCAyMDE4LTA5LTI4VDA2OjI2OjEwLjE2MDkyODQ0Ni0wNzowMFxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAzLCJtZXNzYWdlIjoiT2JqZWN0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTYvc29tZS1vYmplY3QnIGlzIHN1YmplY3QgdG8gYnVja2V0J3MgcmV0ZW50aW9uIHBvbGljeSBhbmQgY2Fubm90IGJlIGRlbGV0ZWQsIG92ZXJ3cml0dGVuIG9yIGFyY2hpdmVkIHVudGlsIDIwMTgtMDktMjhUMDY6MjY6MTAuMTYwOTI4NDQ2LTA3OjAwIn19" + } + }, + { + "ID": "605f8d1dd95809c7", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0016?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "25" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "45a524594262aa1f959d45c5f0261799/6063677872629929501;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0016?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJyZXRlbnRpb25Qb2xpY3kiOm51bGx9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2353" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:12 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051471000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrjl65:4261,/bns/yw/borg/yw/bns/blobstore2/bitpusher/84.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=YsysW6jRKIXMhgTk56f4BQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/84.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/84:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYTVGNmlfNzNkdVJhUVRFQXNzZUdCeEdGWld0bm9pVHl0TGhyNW1FY0hyQTF4eDJEXzNxS2cwUGxYVTJhZC1kOHl3dE9jMUVrNzZmVXdFU2J1TlpoVE9NWThoaEhzNlRjUTl1dHRwNHZZRmJBODdBX05uZ1BwNWIxRHdNR1NQUXV2XzdySWxFZjFtQTVRRUMyZThES1VqcHotcmFtNFJMc01MR2x0aVdrTFQzNlNXLVNZMFhjVlpFVG8wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uoc4h8amQZalCX5R_TWKyE24jbt0D3VpYBvdcCaXM00UzRTu3Uk2OZ8JSITvj7Ihu8hWdeClLqSaL_ppYtUpu5tGHa0Dg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTYiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MDkuNDg3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjEyLjExOFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNi9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTYiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTYvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTYvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE2L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTYiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "47475e76832941e9", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0016/o/some-object?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ffa1323060cacbec2111b53f746f3400/6894771332282460525;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0016/o/some-object?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:12 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051468000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrhr16:4228,/bns/yv/borg/yv/bns/blobstore2/bitpusher/266.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=ZMysW5-wGpCcNsOPmzA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/266.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/266:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYTVGNmlfNzNkdVJhUVRFQXNzZUdCeEdGWld0bm9pVHl0TGhyNW1FY0hyQTF4eDJEXzNxS2cwUGxYVTJhZC1kOHl3dE9jMUVrNzZmVXdFU2J1TlpoVE9NWThoaEhzNlRjUTl1dHRwNHZZRmJBODdBX05uZ1BwNWIxRHdNR1NQUXV2XzdySWxFZjFtQTVRRUMyZThES1VqcHotcmFtNFJMc01MR2x0aVdrTFQzNlNXLVNZMFhjVlpFVG8wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpZOvNJJ_u3XkC7z73EahCGO3GCWFD-dAlxsw3J2U8j_6n3KGm4-dI8loxdemHGBCvsyaPf2VS5jesxH8IblmKbUB7dWQ" + ] + }, + "Body": "" + } + }, + { + "ID": "f15f5d67c9f184d5", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0016?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "800ead8e859d24c198485164290457c1/8485182136854826507;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0016?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:13 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051472000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnab126:4314,/bns/yx/borg/yx/bns/blobstore2/bitpusher/8.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=ZMysW8T8MsyAzQKYkrHgAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/8.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/8:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYTVGNmlfNzNkdVJhUVRFQXNzZUdCeEdGWld0bm9pVHl0TGhyNW1FY0hyQTF4eDJEXzNxS2cwUGxYVTJhZC1kOHl3dE9jMUVrNzZmVXdFU2J1TlpoVE9NWThoaEhzNlRjUTl1dHRwNHZZRmJBODdBX05uZ1BwNWIxRHdNR1NQUXV2XzdySWxFZjFtQTVRRUMyZThES1VqcHotcmFtNFJMc01MR2x0aVdrTFQzNlNXLVNZMFhjVlpFVG8wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrxN_lEa5gdh4ZryppZ3tgdyGfuXwgtkZUYTAJ28QIFZaJmgFdh7RTwJ2pzxdYDYVKrl1tX4Z8HjuMsKBnwyB7UDIUD8A" + ] + }, + "Body": "" + } + }, + { + "ID": "d1099de2d74ac1d9", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "106" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d073a04f3dfd6da876848e5ad6f763ca/10075594040905200810;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE3IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "515" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:14 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051473000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnao18:4369,/bns/yx/borg/yx/bns/blobstore2/bitpusher/108.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=ZcysW4jUEYHGzALUubuoBg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/108.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/108:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYkNVTHJoYzlVZGhJQ1l3YzNNQjVKQU8wRzBJZjBPb3FOYk5IMEpoZlphYzBaTkNzR2RCR1hCYV9LcDFYeEZ1aWlOSVo3WFhZM2I0azlnS1lSZWZscEtNNlpDclNKTGhad0RuLWxKR3pUNEFULVU0RV9xa01MQ1dRallrTDFUeTBSOTFJV2M3MzQtYWs5ZlhjdF9BbmtLMVlMbEFHRFFhMGgtRXdCM0VsOW1La29ibG1UZHZCZ0VKaXcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpPbyGbVtM7oj8m_VpH2LDSEgA3a9Y1xJv-Uyzm9pbwLkO2oGHAtjaP132v8oabe0lkhVZhbYCUYJwzfb2M46NBOJQU_Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTciLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MTMuODg3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjEzLjg4N1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMjdUMTI6MjY6MTMuODg3WiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" + } + }, + { + "ID": "a939f9cc6dba5113", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0017?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9733eddf476bb62db1d4cd2544bb7770/11666005940677450057;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0017?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2442" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:14 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:14 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051474000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlb12:4251,/bns/yv/borg/yv/bns/blobstore2/bitpusher/43.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=ZsysW9jpBoOegwTq3L2ADw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/43.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/43:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYkNVTHJoYzlVZGhJQ1l3YzNNQjVKQU8wRzBJZjBPb3FOYk5IMEpoZlphYzBaTkNzR2RCR1hCYV9LcDFYeEZ1aWlOSVo3WFhZM2I0azlnS1lSZWZscEtNNlpDclNKTGhad0RuLWxKR3pUNEFULVU0RV9xa01MQ1dRallrTDFUeTBSOTFJV2M3MzQtYWs5ZlhjdF9BbmtLMVlMbEFHRFFhMGgtRXdCM0VsOW1La29ibG1UZHZCZ0VKaXcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrZ01-y1806-liZzg1Zc4EJgkrGX9gYB6aX_TDs2Zm-j1iUC6AD7poaLO05U5iAiWwcAUDxfQNuWV9Vcq6MDGim36ClVA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTciLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MTMuODg3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjEzLjg4N1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTcvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTcvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE3L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE4LTA5LTI3VDEyOjI2OjEzLjg4N1oifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "7e76ac1d23c04912", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0017/lockRetentionPolicy?alt=json\u0026ifMetagenerationMatch=1\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "0" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "8fe2407fd7131d02df69a56f109f8645/12425042910098648216;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0017/lockRetentionPolicy?alt=json\u0026ifMetagenerationMatch=1\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "579" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:16 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051473000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnnk15:4485,/bns/yx/borg/yx/bns/blobstore2/bitpusher/113.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=ZsysW_6JGcP9zALA9KDoCQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/113.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/113:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYkNVTHJoYzlVZGhJQ1l3YzNNQjVKQU8wRzBJZjBPb3FOYk5IMEpoZlphYzBaTkNzR2RCR1hCYV9LcDFYeEZ1aWlOSVo3WFhZM2I0azlnS1lSZWZscEtNNlpDclNKTGhad0RuLWxKR3pUNEFULVU0RV9xa01MQ1dRallrTDFUeTBSOTFJV2M3MzQtYWs5ZlhjdF9BbmtLMVlMbEFHRFFhMGgtRXdCM0VsOW1La29ibG1UZHZCZ0VKaXcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoMQSqHqmJkvz8xDacwxPwyaIVrIlIsEdjNKzPZAvOHXU4sJVbyiBesmbpc5gIpL9KBQYa4AMYhYCo5u-LFPQ0y_vAVZg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTciLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MTMuODg3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjE1LjkzNloiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSJ9LCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMjdUMTI6MjY6MTMuODg3WiIsImlzTG9ja2VkIjp0cnVlfSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FJPSJ9" + } + }, + { + "ID": "8e8e90b1f311e0c0", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0017?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "fe36332fb369320ee3dd205b0abd8788/14015454814165799223;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0017?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2458" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:16 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:16 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051474000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrtg25:4215,/bns/yr/borg/yr/bns/blobstore2/bitpusher/19.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=aMysW-GeCcXtkAPp7qJg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/19.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/19:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYkNVTHJoYzlVZGhJQ1l3YzNNQjVKQU8wRzBJZjBPb3FOYk5IMEpoZlphYzBaTkNzR2RCR1hCYV9LcDFYeEZ1aWlOSVo3WFhZM2I0azlnS1lSZWZscEtNNlpDclNKTGhad0RuLWxKR3pUNEFULVU0RV9xa01MQ1dRallrTDFUeTBSOTFJV2M3MzQtYWs5ZlhjdF9BbmtLMVlMbEFHRFFhMGgtRXdCM0VsOW1La29ibG1UZHZCZ0VKaXcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq8KJ3zwGSpR8HjTO4SFtb08TdIZrIEj9oG7XdimkQAiSDBWdUHlWYI1_2NgFVVXV67OFPEutBQarF5JHYd86SUCglkPA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTciLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MTMuODg3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjE1LjkzNloiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTcvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTcvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE3L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE4LTA5LTI3VDEyOjI2OjEzLjg4N1oiLCJpc0xvY2tlZCI6dHJ1ZX0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "e070e3b1fc8b6e0b", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0017?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "47" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "83e4b5789f8577482f1a8df237d6382c/15605584148039645141;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0017?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiMzYwMCJ9fQo=" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "13262" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:17 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051476000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrqe25:4313,/bns/yv/borg/yv/bns/blobstore2/bitpusher/358.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=aMysW7WpG8SCgQTU6r3QDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/358.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/358:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRYkNVTHJoYzlVZGhJQ1l3YzNNQjVKQU8wRzBJZjBPb3FOYk5IMEpoZlphYzBaTkNzR2RCR1hCYV9LcDFYeEZ1aWlOSVo3WFhZM2I0azlnS1lSZWZscEtNNlpDclNKTGhad0RuLWxKR3pUNEFULVU0RV9xa01MQ1dRallrTDFUeTBSOTFJV2M3MzQtYWs5ZlhjdF9BbmtLMVlMbEFHRFFhMGgtRXdCM0VsOW1La29ibG1UZHZCZ0VKaXcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqBd-ZobK3AR5YXeKm28RfOfm_Lp9v4Baz5VA9TTyBtqKBlN-MkFvHcwI9Cwjn9yLgZjc1YCEa1iXmaVLszE1_inCuh8w" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJDYW5ub3QgcmVkdWNlIHJldGVudGlvbiBkdXJhdGlvbiBvZiBhIGxvY2tlZCBSZXRlbnRpb24gUG9saWN5IGZvciBidWNrZXQgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNycuIiwiZGVidWdJbmZvIjoiY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkFDQ0VTU19ERU5JRUQ6IENhbm5vdCByZWR1Y2UgcmV0ZW50aW9uIGR1cmF0aW9uIG9mIGEgbG9ja2VkIFJldGVudGlvbiBQb2xpY3kgZm9yIGJ1Y2tldCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE3Jy5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuVXBkYXRlQW5kUGF0Y2hCdWNrZXQudXBkYXRlQnVja2V0KFVwZGF0ZUFuZFBhdGNoQnVja2V0LmphdmE6MTIxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuVXBkYXRlQnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVCdWNrZXQuamF2YTo3OClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLlVwZGF0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQnVja2V0LmphdmE6MTgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLnVwZGF0ZShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogQ2Fubm90IHJlZHVjZSByZXRlbnRpb24gZHVyYXRpb24gb2YgYSBsb2NrZWQgUmV0ZW50aW9uIFBvbGljeSBmb3IgYnVja2V0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTcnLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxOCBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1GT1JCSURERU4sIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQ2Fubm90IHJlZHVjZSByZXRlbnRpb24gZHVyYXRpb24gb2YgYSBsb2NrZWQgUmV0ZW50aW9uIFBvbGljeSBmb3IgYnVja2V0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTcnLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5VcGRhdGVBbmRQYXRjaEJ1Y2tldC51cGRhdGVCdWNrZXQoVXBkYXRlQW5kUGF0Y2hCdWNrZXQuamF2YToxMjEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5VcGRhdGVCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUJ1Y2tldC5qYXZhOjc4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuVXBkYXRlQnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVCdWNrZXQuamF2YToxOClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IudXBkYXRlKEJ1Y2tldHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDYW5ub3QgcmVkdWNlIHJldGVudGlvbiBkdXJhdGlvbiBvZiBhIGxvY2tlZCBSZXRlbnRpb24gUG9saWN5IGZvciBidWNrZXQgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNycuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE4IG1vcmVcbiwgZG9tYWluPWdsb2JhbCwgZXh0ZW5kZWRIZWxwPW51bGwsIGh0dHBIZWFkZXJzPXt9LCBodHRwU3RhdHVzPWZvcmJpZGRlbiwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uRk9SQklEREVOLCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QUNDRVNTX0RFTklFRDogQ2Fubm90IHJlZHVjZSByZXRlbnRpb24gZHVyYXRpb24gb2YgYSBsb2NrZWQgUmV0ZW50aW9uIFBvbGljeSBmb3IgYnVja2V0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTcnLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5VcGRhdGVBbmRQYXRjaEJ1Y2tldC51cGRhdGVCdWNrZXQoVXBkYXRlQW5kUGF0Y2hCdWNrZXQuamF2YToxMjEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5VcGRhdGVCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUJ1Y2tldC5qYXZhOjc4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuVXBkYXRlQnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChVcGRhdGVCdWNrZXQuamF2YToxOClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IudXBkYXRlKEJ1Y2tldHNEZWxlZ2F0b3IuamF2YToxMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBDYW5ub3QgcmVkdWNlIHJldGVudGlvbiBkdXJhdGlvbiBvZiBhIGxvY2tlZCBSZXRlbnRpb24gUG9saWN5IGZvciBidWNrZXQgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNycuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE4IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Rk9SQklEREVOLCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9Q2Fubm90IHJlZHVjZSByZXRlbnRpb24gZHVyYXRpb24gb2YgYSBsb2NrZWQgUmV0ZW50aW9uIFBvbGljeSBmb3IgYnVja2V0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTcnLiwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9Q2Fubm90IHJlZHVjZSByZXRlbnRpb24gZHVyYXRpb24gb2YgYSBsb2NrZWQgUmV0ZW50aW9uIFBvbGljeSBmb3IgYnVja2V0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTcnLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IENhbm5vdCByZWR1Y2UgcmV0ZW50aW9uIGR1cmF0aW9uIG9mIGEgbG9ja2VkIFJldGVudGlvbiBQb2xpY3kgZm9yIGJ1Y2tldCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE3Jy46IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpBQ0NFU1NfREVOSUVEOiBDYW5ub3QgcmVkdWNlIHJldGVudGlvbiBkdXJhdGlvbiBvZiBhIGxvY2tlZCBSZXRlbnRpb24gUG9saWN5IGZvciBidWNrZXQgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNycuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLlVwZGF0ZUFuZFBhdGNoQnVja2V0LnVwZGF0ZUJ1Y2tldChVcGRhdGVBbmRQYXRjaEJ1Y2tldC5qYXZhOjEyMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLlVwZGF0ZUJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoVXBkYXRlQnVja2V0LmphdmE6NzgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5VcGRhdGVCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKFVwZGF0ZUJ1Y2tldC5qYXZhOjE4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci51cGRhdGUoQnVja2V0c0RlbGVnYXRvci5qYXZhOjEwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IENhbm5vdCByZWR1Y2UgcmV0ZW50aW9uIGR1cmF0aW9uIG9mIGEgbG9ja2VkIFJldGVudGlvbiBQb2xpY3kgZm9yIGJ1Y2tldCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE3Jy5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTggbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwMywibWVzc2FnZSI6IkNhbm5vdCByZWR1Y2UgcmV0ZW50aW9uIGR1cmF0aW9uIG9mIGEgbG9ja2VkIFJldGVudGlvbiBQb2xpY3kgZm9yIGJ1Y2tldCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE3Jy4ifX0=" + } + }, + { + "ID": "e047cc4d51eb7a0b", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "106" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "659c9077010b672bd0c19fc8b2a97534/17195996047811894388;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE4IiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIn19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "515" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:18 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051477000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnel1:4152,/bns/yx/borg/yx/bns/blobstore2/bitpusher/100.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=acysW_7mMMrpzgLno6zgCQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/100.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/100:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWkdjdEt2SlhWQm5yQUtJOTBLMVdES19JU2FRSFdleUZlcEpXeVdXLWpxZzQ0cHVUbEtVdzlsX1gwUHg4UzZEM3dsck9SNFZ1OW5GRkR3TlItd0xIdWRWSGU2b2VEVDZNdnhZdm5xV0VWQVN6djl1YW5lYVlacFZuSm9jZkV2TDV4R0NycEt5UGZLX2VQNTNvMlEyUlgwRGMxal8xRDQtSDlEMWNqTV8wTlRoZlFOYzRseEFKYnhRb0EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UowgkIx9NAooO2nrcRcCMxbenJDY1cuQTBJ9cG6ivuhp_2AhgfZRoIGVOcXBlkej0lSskPz8aTvaEQk_l1S4S8SYVZ1bA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MTguMjU5WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjE4LjI1OVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMjdUMTI6MjY6MTguMjU5WiJ9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0=" + } + }, + { + "ID": "e1e8b0731cfcad02", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0018/lockRetentionPolicy?alt=json\u0026ifMetagenerationMatch=0\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "0" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "23661918021938212e5b727fa88cefdb/17955033017233092547;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0018/lockRetentionPolicy?alt=json\u0026ifMetagenerationMatch=0\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 412, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Content-Length": [ + "12047" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:19 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051478000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrqn25:4154,/bns/yv/borg/yv/bns/blobstore2/bitpusher/374.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=asysW93pIY3yggSq27_4CQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/374.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/374:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWkdjdEt2SlhWQm5yQUtJOTBLMVdES19JU2FRSFdleUZlcEpXeVdXLWpxZzQ0cHVUbEtVdzlsX1gwUHg4UzZEM3dsck9SNFZ1OW5GRkR3TlItd0xIdWRWSGU2b2VEVDZNdnhZdm5xV0VWQVN6djl1YW5lYVlacFZuSm9jZkV2TDV4R0NycEt5UGZLX2VQNTNvMlEyUlgwRGMxal8xRDQtSDlEMWNqTV8wTlRoZlFOYzRseEFKYnhRb0EwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqER26joR5Zr10uFvGr04GcG4fwKz3reu5PWUfJhto9NHp7X0WIF6R6tqywEUrgQtORtgykSYov_L6b3N_o4QRDOAFBqA" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImNvbmRpdGlvbk5vdE1ldCIsIm1lc3NhZ2UiOiJQcmVjb25kaXRpb24gRmFpbGVkIiwibG9jYXRpb25UeXBlIjoiaGVhZGVyIiwibG9jYXRpb24iOiJJZi1NYXRjaCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpJTkNPUlJFQ1RfTUVUQV9HRU5FUkFUSU9OX1NQRUNJRklFRDogZXhwZWN0ZWQgQnVja2V0TWV0YWRhdGEubWV0YWRhdGFfZ2VuZXJhdGlvbjogMCBhY3R1YWw6IDFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuTG9ja1JldGVudGlvblBvbGljeS5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTG9ja1JldGVudGlvblBvbGljeS5qYXZhOjIxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkxvY2tSZXRlbnRpb25Qb2xpY3kuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExvY2tSZXRlbnRpb25Qb2xpY3kuamF2YTo1OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IubG9ja1JldGVudGlvblBvbGljeShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogZXhwZWN0ZWQgQnVja2V0TWV0YWRhdGEubWV0YWRhdGFfZ2VuZXJhdGlvbjogMCBhY3R1YWw6IDFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9UFJFQ09ORElUSU9OX0ZBSUxFRCwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpJTkNPUlJFQ1RfTUVUQV9HRU5FUkFUSU9OX1NQRUNJRklFRDogZXhwZWN0ZWQgQnVja2V0TWV0YWRhdGEubWV0YWRhdGFfZ2VuZXJhdGlvbjogMCBhY3R1YWw6IDFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuTG9ja1JldGVudGlvblBvbGljeS5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTG9ja1JldGVudGlvblBvbGljeS5qYXZhOjIxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkxvY2tSZXRlbnRpb25Qb2xpY3kuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExvY2tSZXRlbnRpb25Qb2xpY3kuamF2YTo1OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IubG9ja1JldGVudGlvblBvbGljeShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogZXhwZWN0ZWQgQnVja2V0TWV0YWRhdGEubWV0YWRhdGFfZ2VuZXJhdGlvbjogMCBhY3R1YWw6IDFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9cHJlY29uZGl0aW9uRmFpbGVkLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5DT05ESVRJT05fTk9UX01FVCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OklOQ09SUkVDVF9NRVRBX0dFTkVSQVRJT05fU1BFQ0lGSUVEOiBleHBlY3RlZCBCdWNrZXRNZXRhZGF0YS5tZXRhZGF0YV9nZW5lcmF0aW9uOiAwIGFjdHVhbDogMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5Mb2NrUmV0ZW50aW9uUG9saWN5LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMb2NrUmV0ZW50aW9uUG9saWN5LmphdmE6MjEyKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuTG9ja1JldGVudGlvblBvbGljeS5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTG9ja1JldGVudGlvblBvbGljeS5qYXZhOjU5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5sb2NrUmV0ZW50aW9uUG9saWN5KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YToxMDkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBleHBlY3RlZCBCdWNrZXRNZXRhZGF0YS5tZXRhZGF0YV9nZW5lcmF0aW9uOiAwIGFjdHVhbDogMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGVycm9yUHJvdG9Db2RlPUNPTkRJVElPTl9OT1RfTUVULCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPW51bGwsIG1lc3NhZ2U9bnVsbCwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWhlYWRlcnMuSWYtTWF0Y2gsIG1lc3NhZ2U9UHJlY29uZGl0aW9uIEZhaWxlZCwgcmVhc29uPWNvbmRpdGlvbk5vdE1ldCwgcnBjQ29kZT00MTJ9IFByZWNvbmRpdGlvbiBGYWlsZWQ6IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpJTkNPUlJFQ1RfTUVUQV9HRU5FUkFUSU9OX1NQRUNJRklFRDogZXhwZWN0ZWQgQnVja2V0TWV0YWRhdGEubWV0YWRhdGFfZ2VuZXJhdGlvbjogMCBhY3R1YWw6IDFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuTG9ja1JldGVudGlvblBvbGljeS5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTG9ja1JldGVudGlvblBvbGljeS5qYXZhOjIxMilcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkxvY2tSZXRlbnRpb25Qb2xpY3kuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExvY2tSZXRlbnRpb25Qb2xpY3kuamF2YTo1OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IubG9ja1JldGVudGlvblBvbGljeShCdWNrZXRzRGVsZWdhdG9yLmphdmE6MTA5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogZXhwZWN0ZWQgQnVja2V0TWV0YWRhdGEubWV0YWRhdGFfZ2VuZXJhdGlvbjogMCBhY3R1YWw6IDFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQxMiwibWVzc2FnZSI6IlByZWNvbmRpdGlvbiBGYWlsZWQifX0=" + } + }, + { + "ID": "26ad03b13cb9a440", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026kmsKeyName=projects%2Fdulcet-port-762%2Flocations%2Fus%2FkeyRings%2Fgo-integration-test%2FcryptoKeys%2Fkey1\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=0c3a1ebded0d74462865e396c868acafbb701f15d2e7922cd62ec5885fe3" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "2183dfe9a0824db0099ffe40c5204242/339945353129427475;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026kmsKeyName=projects%2Fdulcet-port-762%2Flocations%2Fus%2FkeyRings%2Fgo-integration-test%2FcryptoKeys%2Fkey1\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0wYzNhMWViZGVkMGQ3NDQ2Mjg2NWUzOTZjODY4YWNhZmJiNzAxZjE1ZDJlNzkyMmNkNjJlYzU4ODVmZTMNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm5hbWUiOiJrbXMifQoNCi0tMGMzYTFlYmRlZDBkNzQ0NjI4NjVlMzk2Yzg2OGFjYWZiYjcwMWYxNWQyZTc5MjJjZDYyZWM1ODg1ZmUzDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgNCg0KbXkgc2VjcmV0DQotLTBjM2ExZWJkZWQwZDc0NDYyODY1ZTM5NmM4NjhhY2FmYmI3MDFmMTVkMmU3OTIyY2Q2MmVjNTg4NWZlMy0tDQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3323" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:21 GMT" + ], + "Etag": [ + "CIHswZKX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051480000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnbu6:4207,/bns/yx/borg/yx/bns/blobstore2/bitpusher/115.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=bMysW-i0A4igzALuzLGYBQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/115.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/115:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqwEUvAdhjjtCpa7cDpQOh4WraTFmvAU6477TEva-lYmRo41fu1ekaVjDSKM95VeLFE5gmOhJ-9s9IlFQMUgNT59m5Amw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9rbXMvMTUzODA1MTE4MTQwOTc5MyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2ttcyIsIm5hbWUiOiJrbXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE4MTQwOTc5MyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjoyMS40MDlaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MjEuNDA5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjIxLjQwOVoiLCJzaXplIjoiOSIsIm1kNUhhc2giOiJBQVBRUzQ2VHJuTVlucWlLQWJhZ3RRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28va21zP2dlbmVyYXRpb249MTUzODA1MTE4MTQwOTc5MyZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9rbXMvMTUzODA1MTE4MTQwOTc5My9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2ttcy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJrbXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE4MTQwOTc5MyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0lIc3daS1gyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2ttcy8xNTM4MDUxMTgxNDA5NzkzL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2ttcy9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODE0MDk3OTMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0lIc3daS1gyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2ttcy8xNTM4MDUxMTgxNDA5NzkzL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2ttcy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODE0MDk3OTMiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJSHN3WktYMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9rbXMvMTUzODA1MTE4MTQwOTc5My91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28va21zL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODE0MDk3OTMiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSUhzd1pLWDI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlVJNzg1QT09IiwiZXRhZyI6IkNJSHN3WktYMjkwQ0VBRT0iLCJrbXNLZXlOYW1lIjoicHJvamVjdHMvZHVsY2V0LXBvcnQtNzYyL2xvY2F0aW9ucy91cy9rZXlSaW5ncy9nby1pbnRlZ3JhdGlvbi10ZXN0L2NyeXB0b0tleXMva2V5MS9jcnlwdG9LZXlWZXJzaW9ucy8xIn0=" + } + }, + { + "ID": "83ecf58d8ae08666", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/kms", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "fb8cda3f34c8118f6c49a1fee026ffb5/1930075786514900913;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/kms" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "9" + ], + "Content-Type": [ + "text/plain; charset=utf-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:21 GMT" + ], + "Etag": [ + "\"-CIHswZKX290CEAE=\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:26:21 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Encryption-Kms-Key-Name": [ + "projects/dulcet-port-762/locations/us/keyRings/go-integration-test/cryptoKeys/key1/cryptoKeyVersions/1" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:26:21 GMT" + ], + "X-Goog-Generation": [ + "1538051181409793" + ], + "X-Goog-Hash": [ + "crc32c=UI785A==", + "md5=AAPQS46TrnMYnqiKAbagtQ==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "9" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/35,/bns/xh/borg/xh/bns/blobstore2/bitpusher/2.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=bcysW7fsII6kswbkhYKoAQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/2.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/2:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoP-scCUQfp-FabC2kCJED0zZhTBx6qp7seKgu7IvwEPJru7voz-I4aRKXb5ZENMkXDurafjLwyzJdkcT6YgXmAtL3Eiw" + ] + }, + "Body": "bXkgc2VjcmV0" + } + }, + { + "ID": "107c5ecc1982bc8a", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/kms?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "9ecd0d79a117a2848bed84654246265a/3520487690565274960;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/kms?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3323" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:22 GMT" + ], + "Etag": [ + "CIHswZKX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051481000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrp62:4379,/bns/yw/borg/yw/bns/blobstore2/bitpusher/191.scotty,yxfg3-v6:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=bcysW-GxNtW_hATnsKm4BA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/191.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/191:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpVIJ58Vc6OdRzCeCdWcfDPryC9SxGM8vlaBeyGyfjN8QT009BeR4KdR8ZxmXI_VCiiob9ZCk7DrgkQl5muzJ9PTDit8Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9rbXMvMTUzODA1MTE4MTQwOTc5MyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2ttcyIsIm5hbWUiOiJrbXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE4MTQwOTc5MyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjoyMS40MDlaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MjEuNDA5WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjIxLjQwOVoiLCJzaXplIjoiOSIsIm1kNUhhc2giOiJBQVBRUzQ2VHJuTVlucWlLQWJhZ3RRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28va21zP2dlbmVyYXRpb249MTUzODA1MTE4MTQwOTc5MyZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9rbXMvMTUzODA1MTE4MTQwOTc5My9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2ttcy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJrbXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE4MTQwOTc5MyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0lIc3daS1gyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2ttcy8xNTM4MDUxMTgxNDA5NzkzL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2ttcy9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODE0MDk3OTMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0lIc3daS1gyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2ttcy8xNTM4MDUxMTgxNDA5NzkzL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2ttcy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODE0MDk3OTMiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJSHN3WktYMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9rbXMvMTUzODA1MTE4MTQwOTc5My91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28va21zL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODE0MDk3OTMiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSUhzd1pLWDI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlVJNzg1QT09IiwiZXRhZyI6IkNJSHN3WktYMjkwQ0VBRT0iLCJrbXNLZXlOYW1lIjoicHJvamVjdHMvZHVsY2V0LXBvcnQtNzYyL2xvY2F0aW9ucy91cy9rZXlSaW5ncy9nby1pbnRlZ3JhdGlvbi10ZXN0L2NyeXB0b0tleXMva2V5MS9jcnlwdG9LZXlWZXJzaW9ucy8xIn0=" + } + }, + { + "ID": "13fbc80fb1aa6b47", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/kms?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "97f99806cd482d3aed9f661961a2e0f0/4279806126373314719;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/kms?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:22 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051482000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrvj9:4122,/bns/yv/borg/yv/bns/blobstore2/bitpusher/296.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=bsysW-vuAcu0gASSk5bYAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/296.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/296:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpDftfZWHfmZJAilgwtUbtPOsOPMq-dwRcjfSZJEri1v0W1v-HfuBBevxJ6rYv06LgT2JjjUsb5K7ntra9HTFiz6ya_kQ" + ] + }, + "Body": "" + } + }, + { + "ID": "b8cb55f73f268a09", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=cd07c217ad1b4040d04177ecdd1c792ad8cf91b4aa87c7fa4f72f9042bb1" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "856c112fe406a0bd419f15f0ec95f1ca/5110898490842739438;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ], + "X-Goog-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Encryption-Key-Sha256": [ + "Io4lnOPU+EThO0X0nq7mNEXB1rWxZsBI4L37pBmyfDc=" + ] + }, + "Body": "LS1jZDA3YzIxN2FkMWI0MDQwZDA0MTc3ZWNkZDFjNzkyYWQ4Y2Y5MWI0YWE4N2M3ZmE0ZjcyZjkwNDJiYjENCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJjc2VrIn0KDQotLWNkMDdjMjE3YWQxYjQwNDBkMDQxNzdlY2RkMWM3OTJhZDhjZjkxYjRhYTg3YzdmYTRmNzJmOTA0MmJiMQ0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluDQoNCm15IHNlY3JldA0KLS1jZDA3YzIxN2FkMWI0MDQwZDA0MTc3ZWNkZDFjNzkyYWQ4Y2Y5MWI0YWE4N2M3ZmE0ZjcyZjkwNDJiYjEtLQ0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3355" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:22 GMT" + ], + "Etag": [ + "CJD7+ZKX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051480000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnap189:4365,/bns/yx/borg/yx/bns/blobstore2/bitpusher/28.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=bsysW--PDpLlzAKvsrHYBA" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/28.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/28:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur4Us7KxtRF9-lVKK2FUYH_EXFpHY-EaaO0VIwmldcOC2ISoEAfhjWxLUcaaaKqVyW2WeyswAJ3b1so1p7VHGutspR5jA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jc2VrLzE1MzgwNTExODIzMjkyMzIiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jc2VrIiwibmFtZSI6ImNzZWsiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE4MjMyOTIzMiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjoyMi4zMjhaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MjIuMzI4WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjIyLjMyOFoiLCJzaXplIjoiOSIsIm1kNUhhc2giOiJBQVBRUzQ2VHJuTVlucWlLQWJhZ3RRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3Nlaz9nZW5lcmF0aW9uPTE1MzgwNTExODIzMjkyMzImYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3Nlay8xNTM4MDUxMTgyMzI5MjMyL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3Nlay9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjc2VrIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODIzMjkyMzIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNKRDcrWktYMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jc2VrLzE1MzgwNTExODIzMjkyMzIvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3Nlay9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3NlayIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTgyMzI5MjMyIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNKRDcrWktYMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jc2VrLzE1MzgwNTExODIzMjkyMzIvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3Nlay9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3NlayIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTgyMzI5MjMyIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSkQ3K1pLWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3Nlay8xNTM4MDUxMTgyMzI5MjMyL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jc2VrL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3NlayIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTgyMzI5MjMyIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0pENytaS1gyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJVSTc4NUE9PSIsImV0YWciOiJDSkQ3K1pLWDI5MENFQUU9IiwiY3VzdG9tZXJFbmNyeXB0aW9uIjp7ImVuY3J5cHRpb25BbGdvcml0aG0iOiJBRVMyNTYiLCJrZXlTaGEyNTYiOiJJbzRsbk9QVStFVGhPMFgwbnE3bU5FWEIxcld4WnNCSTRMMzdwQm15ZkRjPSJ9fQ==" + } + }, + { + "ID": "d3abeec5c28d5532", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/csek/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/cmek?alt=json\u0026destinationKmsKeyName=projects%2Fdulcet-port-762%2Flocations%2Fus%2FkeyRings%2Fgo-integration-test%2FcryptoKeys%2Fkey1\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "33a94b645ecf5e03ba14b10348949d2e/6701310394893113485;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/csek/rewriteTo/b/go-integration-test-20180927-44630911863640-0001/o/cmek?alt=json\u0026destinationKmsKeyName=projects%2Fdulcet-port-762%2Flocations%2Fus%2FkeyRings%2Fgo-integration-test%2FcryptoKeys%2Fkey1\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ], + "X-Goog-Copy-Source-Encryption-Algorithm": [ + "AES256" + ], + "X-Goog-Copy-Source-Encryption-Key": [ + "REDACTED" + ], + "X-Goog-Copy-Source-Encryption-Key-Sha256": [ + "Io4lnOPU+EThO0X0nq7mNEXB1rWxZsBI4L37pBmyfDc=" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3461" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:22 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051482000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdz77:4028,/bns/yv/borg/yv/bns/blobstore2/bitpusher/82.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=bsysW4aoIoOlgASf-Jco" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/82.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/82:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up-GIJ-hr4O1BXwGcOo0ufD5O5Cck3nZrSYqNqSDYS3I25lPDsq81Qdf83Kt3O7zYafFwVdpGLlHrPgdWFPsYxU-dQMWw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiOSIsIm9iamVjdFNpemUiOiI5IiwiZG9uZSI6dHJ1ZSwicmVzb3VyY2UiOnsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY21lay8xNTM4MDUxMTgyODgwMjY2Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY21layIsIm5hbWUiOiJjbWVrIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODI4ODAyNjYiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW4iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MjIuODgwWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjIyLjg4MFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjoyMi44ODBaIiwic2l6ZSI6IjkiLCJtZDVIYXNoIjoiQUFQUVM0NlRybk1ZbnFpS0FiYWd0UT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NtZWs/Z2VuZXJhdGlvbj0xNTM4MDUxMTgyODgwMjY2JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NtZWsvMTUzODA1MTE4Mjg4MDI2Ni9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NtZWsvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY21layIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTgyODgwMjY2IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSXJNbTVPWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY21lay8xNTM4MDUxMTgyODgwMjY2L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NtZWsvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNtZWsiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE4Mjg4MDI2NiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSXJNbTVPWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY21lay8xNTM4MDUxMTgyODgwMjY2L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NtZWsvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNtZWsiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE4Mjg4MDI2NiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0lyTW01T1gyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NtZWsvMTUzODA1MTE4Mjg4MDI2Ni91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY21lay9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNtZWsiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE4Mjg4MDI2NiIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJck1tNU9YMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiVUk3ODVBPT0iLCJldGFnIjoiQ0lyTW01T1gyOTBDRUFFPSIsImttc0tleU5hbWUiOiJwcm9qZWN0cy9kdWxjZXQtcG9ydC03NjIvbG9jYXRpb25zL3VzL2tleVJpbmdzL2dvLWludGVncmF0aW9uLXRlc3QvY3J5cHRvS2V5cy9rZXkxL2NyeXB0b0tleVZlcnNpb25zLzEifX0=" + } + }, + { + "ID": "b97ea7cb09758872", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/cmek", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "dd30b0cbb65a6fc65281b1c38c359d6f/8219384333752220972;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/cmek" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "9" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:23 GMT" + ], + "Etag": [ + "\"-CIrMm5OX290CEAE=\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:26:22 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Encryption-Kms-Key-Name": [ + "projects/dulcet-port-762/locations/us/keyRings/go-integration-test/cryptoKeys/key1/cryptoKeyVersions/1" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:26:22 GMT" + ], + "X-Goog-Generation": [ + "1538051182880266" + ], + "X-Goog-Hash": [ + "crc32c=UI785A==", + "md5=AAPQS46TrnMYnqiKAbagtQ==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "9" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/37,/bns/xh/borg/xh/bns/blobstore2/bitpusher/64.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=b8ysW-0KwqazBrKogYgO" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/64.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/64:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpEYPjNylJw_x0HSlaYlHnG5ObFsMfVkmtpR5B5UuLAgVHHvkN1Mlj7d84jSdO5r9VR20TYFanxN-HpkmO08bEr5XYNbQ" + ] + }, + "Body": "bXkgc2VjcmV0" + } + }, + { + "ID": "7470c09fdaf73fca", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/cmek?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4412449cb3de7d4e1ea446fc09b69389/9809796233507759050;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/cmek?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3360" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:23 GMT" + ], + "Etag": [ + "CIrMm5OX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051481000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrjl65:4261,/bns/yw/borg/yw/bns/blobstore2/bitpusher/195.scotty,yxfg3-v6:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=b8ysW9C1DtTDhgTjyLO4CA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/195.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/195:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrqAbn5AuAiZxxcaDtDRpw3gqzV-tqipVeKhMqY5BHMNNGkTvc_PIactpOG0D99x0BfLS383RIBwfCxQMc_39vIffe6oA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jbWVrLzE1MzgwNTExODI4ODAyNjYiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jbWVrIiwibmFtZSI6ImNtZWsiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE4Mjg4MDI2NiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjoyMi44ODBaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MjIuODgwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjIyLjg4MFoiLCJzaXplIjoiOSIsIm1kNUhhc2giOiJBQVBRUzQ2VHJuTVlucWlLQWJhZ3RRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY21laz9nZW5lcmF0aW9uPTE1MzgwNTExODI4ODAyNjYmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY21lay8xNTM4MDUxMTgyODgwMjY2L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY21lay9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjbWVrIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODI4ODAyNjYiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNJck1tNU9YMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jbWVrLzE1MzgwNTExODI4ODAyNjYvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY21lay9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY21layIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTgyODgwMjY2IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNJck1tNU9YMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jbWVrLzE1MzgwNTExODI4ODAyNjYvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY21lay9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY21layIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTgyODgwMjY2IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDSXJNbTVPWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY21lay8xNTM4MDUxMTgyODgwMjY2L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jbWVrL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY21layIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTgyODgwMjY2IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0lyTW01T1gyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJVSTc4NUE9PSIsImV0YWciOiJDSXJNbTVPWDI5MENFQUU9Iiwia21zS2V5TmFtZSI6InByb2plY3RzL2R1bGNldC1wb3J0LTc2Mi9sb2NhdGlvbnMvdXMva2V5UmluZ3MvZ28taW50ZWdyYXRpb24tdGVzdC9jcnlwdG9LZXlzL2tleTEvY3J5cHRvS2V5VmVyc2lvbnMvMSJ9" + } + }, + { + "ID": "79abcb8c4c7c4a93", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/csek?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0551ce04083a90c2f936914acf102ade/10640889697471968538;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/csek?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:23 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051482000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrpa10:4240,/bns/yw/borg/yw/bns/blobstore2/bitpusher/26.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=b8ysW-XJFYrahQTRl7aoCQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/26.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/26:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqxmCHZ6nG_fv9txvIgPWT-btTH3CklFSONa4gIntCV80jUBLdhvwLvPbL4S2_Wxe7VeI81G89Dv2wOLxd6nd6nfS9_vA" + ] + }, + "Body": "" + } + }, + { + "ID": "bfc9cf8ca6d60100", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/cmek?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "20625a94d307387d3dd25631634e914f/11400208137574910057;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/cmek?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:23 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051482000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrch186:4050,/bns/yv/borg/yv/bns/blobstore2/bitpusher/289.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=b8ysW7H-IIb-gQTynLpY" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/289.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/289:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpID_zLKj3Thx28dlgiIatppY3nHmPVtxZsDwGTNfapqMcGaQdejUos_3Y7IqGs0bgkSdqKF1By7cJITT6l3yIeFeTocQ" + ] + }, + "Body": "" + } + }, + { + "ID": "e95d94c243928a86", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "196" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "26eda56d11fa90f3369f3d16e097cb4a/12990618942130433544;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJlbmNyeXB0aW9uIjp7ImRlZmF1bHRLbXNLZXlOYW1lIjoicHJvamVjdHMvZHVsY2V0LXBvcnQtNzYyL2xvY2F0aW9ucy91cy9rZXlSaW5ncy9nby1pbnRlZ3JhdGlvbi10ZXN0L2NyeXB0b0tleXMva2V5MSJ9LCJsb2NhdGlvbiI6IlVTIiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSJ9Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "546" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:24 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051482000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrvs3:4021,/bns/yw/borg/yw/bns/blobstore2/bitpusher/192.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=b8ysW63yK4eqhQTHrbmIBw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/192.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/192:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UotNfKtVqKNn8cMC1eOIsB9ICtRV_iouKvDLT910PuKBmI8ITvotlxU93Y2PkHDOt8Q_U6jOmAWK-YWwvrmdto7Q7Bn1w" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MjQuMTU2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjI0LjE1NloiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJlbmNyeXB0aW9uIjp7ImRlZmF1bHRLbXNLZXlOYW1lIjoicHJvamVjdHMvZHVsY2V0LXBvcnQtNzYyL2xvY2F0aW9ucy91cy9rZXlSaW5ncy9nby1pbnRlZ3JhdGlvbi10ZXN0L2NyeXB0b0tleXMva2V5MSJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "20ba6d16efe589ea", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "5788138dee7e452edf25cc2804838019/14580749371221005222;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2473" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:24 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:24 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051484000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vndt66:4404,/bns/yx/borg/yx/bns/blobstore2/bitpusher/131.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=cMysW--wF8a5zALhwpn4Ag" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/131.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/131:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoFlZwaiTWES3oc5jmTNwSMGBjBKeRObUKKMPiM0vcvToX1cVnGImNDiXBmo4xbYBE-yRM4_mBGxRl16aJv7ji_xVVoJg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MjQuMTU2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjI0LjE1NloiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwiZW5jcnlwdGlvbiI6eyJkZWZhdWx0S21zS2V5TmFtZSI6InByb2plY3RzL2R1bGNldC1wb3J0LTc2Mi9sb2NhdGlvbnMvdXMva2V5UmluZ3MvZ28taW50ZWdyYXRpb24tdGVzdC9jcnlwdG9LZXlzL2tleTEifSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifQ==" + } + }, + { + "ID": "98d4d0396aa532db", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0019/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=0183510b9204e3050d5dc85bb81ef02775f84a265d260d4e05220590dcd1" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "f1ca850acbb001abd943c3dc4b11d15c/15412124305850181366;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0019/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0wMTgzNTEwYjkyMDRlMzA1MGQ1ZGM4NWJiODFlZjAyNzc1Zjg0YTI2NWQyNjBkNGUwNTIyMDU5MGRjZDENCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsIm5hbWUiOiJrbXMifQoNCi0tMDE4MzUxMGI5MjA0ZTMwNTBkNWRjODViYjgxZWYwMjc3NWY4NGEyNjVkMjYwZDRlMDUyMjA1OTBkY2QxDQpDb250ZW50LVR5cGU6IHRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgNCg0KbXkgc2VjcmV0DQotLTAxODM1MTBiOTIwNGUzMDUwZDVkYzg1YmI4MWVmMDI3NzVmODRhMjY1ZDI2MGQ0ZTA1MjIwNTkwZGNkMS0tDQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3323" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:26 GMT" + ], + "Etag": [ + "CJyE6ZSX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051482000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrl7:4233,/bns/yr/borg/yr/bns/blobstore2/bitpusher/41.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=cMysW8CILMy9kASo-IzwBQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/41.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/41:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo6QGRGmaNNuOiWVDAgdtuLslGQeZy-98D7XTNvT-KZreR-QMUmyGGG3KX-ZiREC1U4y2-ieiHWGgOaBkdl4bOc6g9lxw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9rbXMvMTUzODA1MTE4NjI0NjE3MiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9vL2ttcyIsIm5hbWUiOiJrbXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE4NjI0NjE3MiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjoyNi4yNDVaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MjYuMjQ1WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjI2LjI0NVoiLCJzaXplIjoiOSIsIm1kNUhhc2giOiJBQVBRUzQ2VHJuTVlucWlLQWJhZ3RRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5L28va21zP2dlbmVyYXRpb249MTUzODA1MTE4NjI0NjE3MiZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9rbXMvMTUzODA1MTE4NjI0NjE3Mi9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9vL2ttcy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJvYmplY3QiOiJrbXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE4NjI0NjE3MiIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0p5RTZaU1gyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5L2ttcy8xNTM4MDUxMTg2MjQ2MTcyL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9vL2ttcy9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5Iiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODYyNDYxNzIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0p5RTZaU1gyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5L2ttcy8xNTM4MDUxMTg2MjQ2MTcyL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9vL2ttcy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5Iiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODYyNDYxNzIiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKeUU2WlNYMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9rbXMvMTUzODA1MTE4NjI0NjE3Mi91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5L28va21zL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5Iiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODYyNDYxNzIiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSnlFNlpTWDI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlVJNzg1QT09IiwiZXRhZyI6IkNKeUU2WlNYMjkwQ0VBRT0iLCJrbXNLZXlOYW1lIjoicHJvamVjdHMvZHVsY2V0LXBvcnQtNzYyL2xvY2F0aW9ucy91cy9rZXlSaW5ncy9nby1pbnRlZ3JhdGlvbi10ZXN0L2NyeXB0b0tleXMva2V5MS9jcnlwdG9LZXlWZXJzaW9ucy8xIn0=" + } + }, + { + "ID": "9f8cf00a4303c7e8", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0019/kms", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "84569a2d9db1db62fa4d579148c78171/17002254739235654548;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0019/kms" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "9" + ], + "Content-Type": [ + "text/plain; charset=utf-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:26 GMT" + ], + "Etag": [ + "\"-CJyE6ZSX290CEAE=\"" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:26:26 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Encryption-Kms-Key-Name": [ + "projects/dulcet-port-762/locations/us/keyRings/go-integration-test/cryptoKeys/key1/cryptoKeyVersions/1" + ], + "X-Goog-Generation": [ + "1538051186246172" + ], + "X-Goog-Hash": [ + "crc32c=UI785A==", + "md5=AAPQS46TrnMYnqiKAbagtQ==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "9" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/28,/bns/xh/borg/xh/bns/blobstore2/bitpusher/50.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=csysW9mnFoKiswbHo7-QAQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/50.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/50:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq1-XQ2yh2yq4HD7w8uf-OE1shhofPPQuAKmp-qC5da9s0m1AN7uTNKx0tIrF9-MyTIt7td30r9K5tTyLuqRzWNHMxFwQ" + ] + }, + "Body": "bXkgc2VjcmV0" + } + }, + { + "ID": "a485ba435ca28523", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019/o/kms?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "7830534cfb711b081d08eba0b65cf2a9/74147550026887475;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019/o/kms?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3323" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:27 GMT" + ], + "Etag": [ + "CJyE6ZSX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051481000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrsw12:4100,/bns/yr/borg/yr/bns/blobstore2/bitpusher/77.scotty,yxfg3-v6:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=csysW_vKIo-ZkAT23pHoBg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/77.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/77:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpT4qsGMeiKmm3SkoiWZwAbBHcGKtofVYo_STTBdjDahuf4BQEGdwFN6zz_j2-uhr3VZgULq_8JuBgsgZAQQPSwIK19OA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9rbXMvMTUzODA1MTE4NjI0NjE3MiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9vL2ttcyIsIm5hbWUiOiJrbXMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE4NjI0NjE3MiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjoyNi4yNDVaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MjYuMjQ1WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjI2LjI0NVoiLCJzaXplIjoiOSIsIm1kNUhhc2giOiJBQVBRUzQ2VHJuTVlucWlLQWJhZ3RRPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5L28va21zP2dlbmVyYXRpb249MTUzODA1MTE4NjI0NjE3MiZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9rbXMvMTUzODA1MTE4NjI0NjE3Mi9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9vL2ttcy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJvYmplY3QiOiJrbXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE4NjI0NjE3MiIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0p5RTZaU1gyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5L2ttcy8xNTM4MDUxMTg2MjQ2MTcyL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9vL2ttcy9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5Iiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODYyNDYxNzIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0p5RTZaU1gyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5L2ttcy8xNTM4MDUxMTg2MjQ2MTcyL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9vL2ttcy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5Iiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODYyNDYxNzIiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNKeUU2WlNYMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9rbXMvMTUzODA1MTE4NjI0NjE3Mi91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5L28va21zL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5Iiwib2JqZWN0Ijoia21zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExODYyNDYxNzIiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSnlFNlpTWDI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlVJNzg1QT09IiwiZXRhZyI6IkNKeUU2WlNYMjkwQ0VBRT0iLCJrbXNLZXlOYW1lIjoicHJvamVjdHMvZHVsY2V0LXBvcnQtNzYyL2xvY2F0aW9ucy91cy9rZXlSaW5ncy9nby1pbnRlZ3JhdGlvbi10ZXN0L2NyeXB0b0tleXMva2V5MS9jcnlwdG9LZXlWZXJzaW9ucy8xIn0=" + } + }, + { + "ID": "7d9bd0c6e55e46e5", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019/o/kms?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d215618fb2f9dcd133d16a7384b7d353/905241013974385794;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019/o/kms?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:28 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051480000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnbd134:4063,/bns/yx/borg/yx/bns/blobstore2/bitpusher/105.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=c8ysW8HfNIbjzAKq95zACQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/105.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/105:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpAexQip8Gz7qHe9IjghL0m9p9kYsvUUOwykqCu4RqDkKXhu6scrgPhzVL1QmWWMZD5L8-ZEXNcUylqtd4on6SutBZ4RA" + ] + }, + "Body": "" + } + }, + { + "ID": "c47642fa5db3bd5e", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "122" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "fbfc712b5c1899fd4ca63ee52e6ab532/2495651814251784481;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJlbmNyeXB0aW9uIjp7ImRlZmF1bHRLbXNLZXlOYW1lIjoicHJvamVjdHMvZHVsY2V0LXBvcnQtNzYyL2xvY2F0aW9ucy91cy9rZXlSaW5ncy9nby1pbnRlZ3JhdGlvbi10ZXN0L2NyeXB0b0tleXMva2V5MiJ9fQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2473" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:29 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051488000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vncd127:4456,/bns/yx/borg/yx/bns/blobstore2/bitpusher/98.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=dMysW5vaC5C5zwK1qK7ABg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/98.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/98:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo4X9EhCcRBlaJH_pVouWM2j23zb0mheEAPSKeXBBJwCJRwCNMRaw6tJxmnLuktTi66gi6vWF93hfao8LTicVMfjoUWgA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MjQuMTU2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjI5LjQyM1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwiZW5jcnlwdGlvbiI6eyJkZWZhdWx0S21zS2V5TmFtZSI6InByb2plY3RzL2R1bGNldC1wb3J0LTc2Mi9sb2NhdGlvbnMvdXMva2V5UmluZ3MvZ28taW50ZWdyYXRpb24tdGVzdC9jcnlwdG9LZXlzL2tleTIifSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "7f62069aba528822", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "c002ca593e602630ded6a19c2b134689/4086063718302158784;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2473" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:29 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:29 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051481000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrlm79:4339,/bns/yv/borg/yv/bns/blobstore2/bitpusher/192.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=dcysW8jIJsHMggTy3YG4Bw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/192.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/192:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqkNX11AQYP3N2kiMuxoq73fzNO7Bi0pJMhX1c_mLQ42QXGDO_A43-c1RBddVMXKxeMwfQhiRGF86B-ooIMrZpXs1MmVw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MjQuMTU2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjI5LjQyM1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwiZW5jcnlwdGlvbiI6eyJkZWZhdWx0S21zS2V5TmFtZSI6InByb2plY3RzL2R1bGNldC1wb3J0LTc2Mi9sb2NhdGlvbnMvdXMva2V5UmluZ3MvZ28taW50ZWdyYXRpb24tdGVzdC9jcnlwdG9LZXlzL2tleTIifSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBST0ifQ==" + } + }, + { + "ID": "fa6f06c5ad8064e4", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "20" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "130a425fc5abcea3f3c5283a84daaac0/5676475622369375326;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJlbmNyeXB0aW9uIjpudWxsfQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2353" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:31 GMT" + ], + "Etag": [ + "CAM=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051490000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrv189:4445,/bns/yr/borg/yr/bns/blobstore2/bitpusher/106.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=dcysW-mJONHokAPIiaDwDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/106.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/106:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UojIFggaWZN6hEXoEkYo4ICef8Y8G2QPP99gaRwO_31pyKn2XSpn1KMBY5Ha9TGzntD2rjuSpxTPCpF9icPZ4U5RDR_2Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MjQuMTU2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjMxLjE1OFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjMiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQU09In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE5L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTkiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBTT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FNPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBTT0ifQ==" + } + }, + { + "ID": "4cb5a8bb09514dcd", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "49bf774f40da9c6ccd6aaac6b1f8fb6d/7266606051459881469;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0019?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:31 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051482000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrhj86:4129,/bns/yv/borg/yv/bns/blobstore2/bitpusher/227.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=d8ysW_DxFsTDswat-Z-oBg" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/227.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/227:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWm1PRlpHcGk5RmhEek1fZDZaWW5nT2k1RTVURThhLXdxeDhkTnNrcVMyNVJkeURqQnQ0MVRlWnZtbjJLRHBEVm5yZUlsNTN0clJYXzFGNkpfMU5OS1ZRZlEzY0M5WTkwSHhZb1hGc09JbTgtUkRPYThhcUVFWnFrdkpjOGw2WmQyMzFhRmliVmwyQVVoeHFzQkdvOFJKTXZ2QTc1M29vT1BCanZJQTR0VEZ6bXVzbTEyU2lVU0xveWMwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up1rQ-BgoD09ndH8GWMMzS2Zhmn0QjIDIJukp6NieOesT9EvuTS0RwbBIPpMlVgQEhFAKxVMNUp4VJAYaWQ7swQezWs0A" + ] + }, + "Body": "" + } + }, + { + "ID": "891d7683ffefdda3", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026predefinedAcl=authenticatedRead\u0026predefinedDefaultObjectAcl=publicRead\u0026prettyPrint=false\u0026project=dulcet-port-762", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "60" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "cb6b62d23ca6eb2db0c7e01be1b9bb97/8857017955510321051;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026predefinedAcl=authenticatedRead\u0026predefinedDefaultObjectAcl=publicRead\u0026prettyPrint=false\u0026project=dulcet-port-762" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIwIn0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "1404" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:32 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051491000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnam67:4028,/bns/yx/borg/yx/bns/blobstore2/bitpusher/78.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=d8ysW8yrPKSGzQLC47eoAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/78.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/78:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWnhJX2MxZzUwRGhIUUYyaHZ3SXljdlJ1SEdtaEZZb3ZldVcwLVZDMUdOcjdRck83TTFuWXp0MklvWnJfaXBRTFlpNUplM1RyZ29mSUJJLXRFcnpkVlR2dzJsTGVlQWdJS1lmQ01WejJrT1pTWFo4Vk9FT3pzMHhVVExreDdiU2NtaWg3Ung5NXFVeEsxYjdwbkxQSGJ0RGhHOEhfTFZvUWhGT1pseWNwZ0E3NlZZODlSY3RiNHVLRGcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqMpuPJgLpZv1oExTs4Xg16mQfhfIKXonUO9BJXMHQsuGF4dTdsbigEov8h0t91zJU8pmxlW3jj0JTLD7rnnfatR3lPrg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MzIuNDU2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjMyLjQ1NloiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMC9hbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvYWNsL2FsbEF1dGhlbnRpY2F0ZWRVc2VycyIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMCIsImVudGl0eSI6ImFsbEF1dGhlbnRpY2F0ZWRVc2VycyIsInJvbGUiOiJSRUFERVIiLCJldGFnIjoiQ0FFPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6ImFsbFVzZXJzIiwicm9sZSI6IlJFQURFUiIsImV0YWciOiJDQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "b49c1e9a0f83e151", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0d60ab1455023a58da860c5a8382cd3f/10447428760082621498;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "1404" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:33 GMT" + ], + "Etag": [ + "CAE=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:33 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051492000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrp184:4188,/bns/yr/borg/yr/bns/blobstore2/bitpusher/105.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=eMysW7aDLZCMkATtpaSoDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/105.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/105:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWnhJX2MxZzUwRGhIUUYyaHZ3SXljdlJ1SEdtaEZZb3ZldVcwLVZDMUdOcjdRck83TTFuWXp0MklvWnJfaXBRTFlpNUplM1RyZ29mSUJJLXRFcnpkVlR2dzJsTGVlQWdJS1lmQ01WejJrT1pTWFo4Vk9FT3pzMHhVVExreDdiU2NtaWg3Ung5NXFVeEsxYjdwbkxQSGJ0RGhHOEhfTFZvUWhGT1pseWNwZ0E3NlZZODlSY3RiNHVLRGcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Urqu3mcHdMmoSo-FZwYHnjUt-4JoFJC40fJlB6GgRNe3MJSsnCfflBb4Fn7MRFozkTM0lJVdby67cEnsWc_pzlvRBjCew" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MzIuNDU2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjMyLjQ1NloiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMC9hbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvYWNsL2FsbEF1dGhlbnRpY2F0ZWRVc2VycyIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMCIsImVudGl0eSI6ImFsbEF1dGhlbnRpY2F0ZWRVc2VycyIsInJvbGUiOiJSRUFERVIiLCJldGFnIjoiQ0FFPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6ImFsbFVzZXJzIiwicm9sZSI6IlJFQURFUiIsImV0YWciOiJDQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9" + } + }, + { + "ID": "87a9188ffc1f950f", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020?alt=json\u0026predefinedAcl=private\u0026predefinedDefaultObjectAcl=authenticatedRead\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "33" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "949ae0c5485ef5fba888d9ee9e3ece82/11965502694630050521;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020?alt=json\u0026predefinedAcl=private\u0026predefinedDefaultObjectAcl=authenticatedRead\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJhY2wiOltdLCJkZWZhdWx0T2JqZWN0QWNsIjpbXX0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "1049" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:34 GMT" + ], + "Etag": [ + "CAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051493000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrna23:4440,/bns/yw/borg/yw/bns/blobstore2/bitpusher/181.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=ecysW7XYAdPkhATNoabIDw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/181.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/181:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWnhJX2MxZzUwRGhIUUYyaHZ3SXljdlJ1SEdtaEZZb3ZldVcwLVZDMUdOcjdRck83TTFuWXp0MklvWnJfaXBRTFlpNUplM1RyZ29mSUJJLXRFcnpkVlR2dzJsTGVlQWdJS1lmQ01WejJrT1pTWFo4Vk9FT3pzMHhVVExreDdiU2NtaWg3Ung5NXFVeEsxYjdwbkxQSGJ0RGhHOEhfTFZvUWhGT1pseWNwZ0E3NlZZODlSY3RiNHVLRGcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpZpSJIhVMhoHzAya137K-3ICxB3mv_44utwUUjjgeN6udkUR5RE-QVvopzq8Es4nhaQ3ZLEx2u6y7TcbaBjwRy5LAqqQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MzIuNDU2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjM0LjU0M1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjIiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBST0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJhbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJyb2xlIjoiUkVBREVSIiwiZXRhZyI6IkNBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0=" + } + }, + { + "ID": "e4a3dd503180735b", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o?alt=json\u0026predefinedAcl=authenticatedRead\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=beb0c8923f1906fc1d6a5d8d3bc17f536531b44ab40d3d9fc8efb9fb7f72" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "23efe85846102ea586924024a1100570/12796877629259291944;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o?alt=json\u0026predefinedAcl=authenticatedRead\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS1iZWIwYzg5MjNmMTkwNmZjMWQ2YTVkOGQzYmMxN2Y1MzY1MzFiNDRhYjQwZDNkOWZjOGVmYjlmYjdmNzINCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMCIsIm5hbWUiOiJwcml2YXRlIn0KDQotLWJlYjBjODkyM2YxOTA2ZmMxZDZhNWQ4ZDNiYzE3ZjUzNjUzMWI0NGFiNDBkM2Q5ZmM4ZWZiOWZiN2Y3Mg0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04DQoNCmhlbGxvDQotLWJlYjBjODkyM2YxOTA2ZmMxZDZhNWQ4ZDNiYzE3ZjUzNjUzMWI0NGFiNDBkM2Q5ZmM4ZWZiOWZiN2Y3Mi0tDQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2100" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:35 GMT" + ], + "Etag": [ + "COekh5mX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051494000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vryy5:4338,/bns/yw/borg/yw/bns/blobstore2/bitpusher/209.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=esysW57EMM2dhQTpyo-oDQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/209.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/209:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWnhJX2MxZzUwRGhIUUYyaHZ3SXljdlJ1SEdtaEZZb3ZldVcwLVZDMUdOcjdRck83TTFuWXp0MklvWnJfaXBRTFlpNUplM1RyZ29mSUJJLXRFcnpkVlR2dzJsTGVlQWdJS1lmQ01WejJrT1pTWFo4Vk9FT3pzMHhVVExreDdiU2NtaWg3Ung5NXFVeEsxYjdwbkxQSGJ0RGhHOEhfTFZvUWhGT1pseWNwZ0E3NlZZODlSY3RiNHVLRGcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpCtq9CUGSgrynMd2mh8SOMhrLN0tJva6vaDC8MLugZf43ohkNU0tMfnT9LrjH9cN9nhdnM3SZuopEE2PwjqP0eRagjRg" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMC9wcml2YXRlLzE1MzgwNTExOTUxMzA0NzEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvby9wcml2YXRlIiwibmFtZSI6InByaXZhdGUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE5NTEzMDQ3MSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjozNS4xMzBaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MzUuMTMwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjM1LjEzMFoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIwL28vcHJpdmF0ZT9nZW5lcmF0aW9uPTE1MzgwNTExOTUxMzA0NzEmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvcHJpdmF0ZS8xNTM4MDUxMTk1MTMwNDcxL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvby9wcml2YXRlL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIwIiwib2JqZWN0IjoicHJpdmF0ZSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTk1MTMwNDcxIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09la2g1bVgyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIwL3ByaXZhdGUvMTUzODA1MTE5NTEzMDQ3MS9hbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvby9wcml2YXRlL2FjbC9hbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAiLCJvYmplY3QiOiJwcml2YXRlIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExOTUxMzA0NzEiLCJlbnRpdHkiOiJhbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJyb2xlIjoiUkVBREVSIiwiZXRhZyI6IkNPZWtoNW1YMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibW5HN1RBPT0iLCJldGFnIjoiQ09la2g1bVgyOTBDRUFFPSJ9" + } + }, + { + "ID": "58df35897052bee4", + "Request": { + "Method": "PATCH", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o/private?alt=json\u0026predefinedAcl=private\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "62" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "24397f66feee409b62926787352017ec/14387289533326443207;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o/private?alt=json\u0026predefinedAcl=private\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAifQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "1634" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:35 GMT" + ], + "Etag": [ + "COekh5mX290CEAI=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051493000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrjo80:4463,/bns/yv/borg/yv/bns/blobstore2/bitpusher/13.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=e8ysW4LvDtCuggSokbuwAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/13.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/13:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATpxChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4CtK4wESxgF5YTI5LmMuRW93QkpRWnhJX2MxZzUwRGhIUUYyaHZ3SXljdlJ1SEdtaEZZb3ZldVcwLVZDMUdOcjdRck83TTFuWXp0MklvWnJfaXBRTFlpNUplM1RyZ29mSUJJLXRFcnpkVlR2dzJsTGVlQWdJS1lmQ01WejJrT1pTWFo4Vk9FT3pzMHhVVExreDdiU2NtaWg3Ung5NXFVeEsxYjdwbkxQSGJ0RGhHOEhfTFZvUWhGT1pseWNwZ0E3NlZZODlSY3RiNHVLRGcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up9VN6AT4MFmZg0IARYnDCGfAGvkNhL2qzxtqOu4JFgUXJ_Q9kA4PKAlsvszTSqw4rljl00PRjory0QRWzbLupw8M06nA" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMC9wcml2YXRlLzE1MzgwNTExOTUxMzA0NzEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvby9wcml2YXRlIiwibmFtZSI6InByaXZhdGUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE5NTEzMDQ3MSIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjozNS4xMzBaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MzUuMzM0WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjM1LjEzMFoiLCJzaXplIjoiNSIsIm1kNUhhc2giOiJYVUZBS3J4TEtuYTVjWjJSRUJmRmtnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIwL28vcHJpdmF0ZT9nZW5lcmF0aW9uPTE1MzgwNTExOTUxMzA0NzEmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvcHJpdmF0ZS8xNTM4MDUxMTk1MTMwNDcxL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvby9wcml2YXRlL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIwIiwib2JqZWN0IjoicHJpdmF0ZSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTk1MTMwNDcxIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09la2g1bVgyOTBDRUFJPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJtbkc3VEE9PSIsImV0YWciOiJDT2VraDVtWDI5MENFQUk9In0=" + } + }, + { + "ID": "6c8b9234e260aec0", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o/private/rewriteTo/b/go-integration-test-20180927-44630911863640-0020/o/dst?alt=json\u0026destinationPredefinedAcl=publicRead\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "3" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e84540708abd3927db61182f95c94954/15977419966695139429;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o/private/rewriteTo/b/go-integration-test-20180927-44630911863640-0020/o/dst?alt=json\u0026destinationPredefinedAcl=publicRead\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "e30K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2122" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:35 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051495000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrqv16:4123,/bns/yv/borg/yv/bns/blobstore2/bitpusher/135.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=e8ysW8aOG4iRNq7qqOgL" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/135.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/135:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWnhJX2MxZzUwRGhIUUYyaHZ3SXljdlJ1SEdtaEZZb3ZldVcwLVZDMUdOcjdRck83TTFuWXp0MklvWnJfaXBRTFlpNUplM1RyZ29mSUJJLXRFcnpkVlR2dzJsTGVlQWdJS1lmQ01WejJrT1pTWFo4Vk9FT3pzMHhVVExreDdiU2NtaWg3Ung5NXFVeEsxYjdwbkxQSGJ0RGhHOEhfTFZvUWhGT1pseWNwZ0E3NlZZODlSY3RiNHVLRGcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoGz2UN6X_ehowCDfc4UzRfzOOABUIOku0QYLlq2xV_D-ZSoyXFGiI0r2Ze0jbdiZtGxNtE0ZDopU4i4_VfctaYdcfLUw" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNyZXdyaXRlUmVzcG9uc2UiLCJ0b3RhbEJ5dGVzUmV3cml0dGVuIjoiNSIsIm9iamVjdFNpemUiOiI1IiwiZG9uZSI6dHJ1ZSwicmVzb3VyY2UiOnsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvZHN0LzE1MzgwNTExOTU4MjAwMDMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvby9kc3QiLCJuYW1lIjoiZHN0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIwIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExOTU4MjAwMDMiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MzUuODE4WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjM1LjgxOFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjozNS44MThaIiwic2l6ZSI6IjUiLCJtZDVIYXNoIjoiWFVGQUtyeExLbmE1Y1oyUkVCZkZrZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMC9vL2RzdD9nZW5lcmF0aW9uPTE1MzgwNTExOTU4MjAwMDMmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvZHN0LzE1MzgwNTExOTU4MjAwMDMvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMC9vL2RzdC9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMCIsIm9iamVjdCI6ImRzdCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTk1ODIwMDAzIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ09PdnNabVgyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIwL2RzdC8xNTM4MDUxMTk1ODIwMDAzL2FsbFVzZXJzIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIwL28vZHN0L2FjbC9hbGxVc2VycyIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMCIsIm9iamVjdCI6ImRzdCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTk1ODIwMDAzIiwiZW50aXR5IjoiYWxsVXNlcnMiLCJyb2xlIjoiUkVBREVSIiwiZXRhZyI6IkNPT3ZzWm1YMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoibW5HN1RBPT0iLCJldGFnIjoiQ09PdnNabVgyOTBDRUFFPSJ9fQ==" + } + }, + { + "ID": "bdf3d7c64ba82e03", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o/comp/compose?alt=json\u0026destinationPredefinedAcl=authenticatedRead\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Length": [ + "130" + ], + "Content-Type": [ + "application/json" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "55fba242302f069c8de08a55a63b312f/17567830766972538116;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o/comp/compose?alt=json\u0026destinationPredefinedAcl=authenticatedRead\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "eyJkZXN0aW5hdGlvbiI6eyJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAifSwic291cmNlT2JqZWN0cyI6W3sibmFtZSI6InByaXZhdGUifSx7Im5hbWUiOiJkc3QifV19Cg==" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "2011" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:36 GMT" + ], + "Etag": [ + "CKiF2JmX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051495000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrbe87:4071,/bns/yv/borg/yv/bns/blobstore2/bitpusher/178.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=e8ysW6n9O8TIggSEmZeoDA" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/178.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/178:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp0ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4StK4wESxgF5YTI5LmMuRW93QkpRWnhJX2MxZzUwRGhIUUYyaHZ3SXljdlJ1SEdtaEZZb3ZldVcwLVZDMUdOcjdRck83TTFuWXp0MklvWnJfaXBRTFlpNUplM1RyZ29mSUJJLXRFcnpkVlR2dzJsTGVlQWdJS1lmQ01WejJrT1pTWFo4Vk9FT3pzMHhVVExreDdiU2NtaWg3Ung5NXFVeEsxYjdwbkxQSGJ0RGhHOEhfTFZvUWhGT1pseWNwZ0E3NlZZODlSY3RiNHVLRGcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoVcr8Vwk5n96yY0XwCEwzrkQvuCRGOYIkL4sTNjvaL0NlweMw8cCjbLfz-73ZEPbE8s7m5oNJ6KhRMMLKJ8eR_29Msng" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMC9jb21wLzE1MzgwNTExOTY0NTM1NDQiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvby9jb21wIiwibmFtZSI6ImNvbXAiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE5NjQ1MzU0NCIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjozNi40NTJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MzYuNDUyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjM2LjQ1MloiLCJzaXplIjoiMTAiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIwL28vY29tcD9nZW5lcmF0aW9uPTE1MzgwNTExOTY0NTM1NDQmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvY29tcC8xNTM4MDUxMTk2NDUzNTQ0L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvby9jb21wL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIwIiwib2JqZWN0IjoiY29tcCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTk2NDUzNTQ0IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ0tpRjJKbVgyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIwL2NvbXAvMTUzODA1MTE5NjQ1MzU0NC9hbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAvby9jb21wL2FjbC9hbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjAiLCJvYmplY3QiOiJjb21wIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExOTY0NTM1NDQiLCJlbnRpdHkiOiJhbGxBdXRoZW50aWNhdGVkVXNlcnMiLCJyb2xlIjoiUkVBREVSIiwiZXRhZyI6IkNLaUYySm1YMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiL1JDT2dnPT0iLCJjb21wb25lbnRDb3VudCI6MiwiZXRhZyI6IkNLaUYySm1YMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "ee7bc5d7208c190c", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o/comp?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4a2194905ad1cf3d334d917f83e28255/18326867736393736275;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o/comp?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:37 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051496000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrvq22:4011,/bns/yr/borg/yr/bns/blobstore2/bitpusher/69.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=fMysW-3oJ8zx4QSiqbCQCw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/69.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/69:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWnhJX2MxZzUwRGhIUUYyaHZ3SXljdlJ1SEdtaEZZb3ZldVcwLVZDMUdOcjdRck83TTFuWXp0MklvWnJfaXBRTFlpNUplM1RyZ29mSUJJLXRFcnpkVlR2dzJsTGVlQWdJS1lmQ01WejJrT1pTWFo4Vk9FT3pzMHhVVExreDdiU2NtaWg3Ung5NXFVeEsxYjdwbkxQSGJ0RGhHOEhfTFZvUWhGT1pseWNwZ0E3NlZZODlSY3RiNHVLRGcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpG9-TyHzYXAb1ytjOQjqEQ98fTCU_yZe5G-HK1SELnmk4DQ2EcgdFJoM4mSUTB1yro5RqktWxmw0pNnLiUyBC25Ba60g" + ] + }, + "Body": "" + } + }, + { + "ID": "ac3f89ec4e04e3c1", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o/dst?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d86b6c05e8c204b9a0f81a62b0ff1215/711780072290071459;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o/dst?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:37 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051496000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrud20:4007,/bns/yv/borg/yv/bns/blobstore2/bitpusher/259.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=fcysW8_OBsmngASFkp7wAw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/259.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/259:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWnhJX2MxZzUwRGhIUUYyaHZ3SXljdlJ1SEdtaEZZb3ZldVcwLVZDMUdOcjdRck83TTFuWXp0MklvWnJfaXBRTFlpNUplM1RyZ29mSUJJLXRFcnpkVlR2dzJsTGVlQWdJS1lmQ01WejJrT1pTWFo4Vk9FT3pzMHhVVExreDdiU2NtaWg3Ung5NXFVeEsxYjdwbkxQSGJ0RGhHOEhfTFZvUWhGT1pseWNwZ0E3NlZZODlSY3RiNHVLRGcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqEiJiMnVBV_g1vn1HPeT4lJx2pAGupW_0ewE6RCPuEs6LX1kKVZPChhF6uNXfd6B-zq41gJBEXqWV3n_C2rVbwOdxQZA" + ] + }, + "Body": "" + } + }, + { + "ID": "624ebe45009cda5b", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o/private?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "93b0a271a6a576c37c4b73fa976c4598/1470817041728046578;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020/o/private?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:37 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051491000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnep66:4228,/bns/yx/borg/yx/bns/blobstore2/bitpusher/121.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=fcysW-m_H8uRzgLBuZuAAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/121.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/121:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWnhJX2MxZzUwRGhIUUYyaHZ3SXljdlJ1SEdtaEZZb3ZldVcwLVZDMUdOcjdRck83TTFuWXp0MklvWnJfaXBRTFlpNUplM1RyZ29mSUJJLXRFcnpkVlR2dzJsTGVlQWdJS1lmQ01WejJrT1pTWFo4Vk9FT3pzMHhVVExreDdiU2NtaWg3Ung5NXFVeEsxYjdwbkxQSGJ0RGhHOEhfTFZvUWhGT1pseWNwZ0E3NlZZODlSY3RiNHVLRGcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrMCxb5W9i5rriC3v0MUc9h8Xj4pD83_CNEbRKtAEPOBu0xByvZFQkU2cY3omAUSed_AUo69GRSfyfOfQWZvfpYx1dTYw" + ] + }, + "Body": "" + } + }, + { + "ID": "96fe3135b84e9748", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "7be9885fc654f5342511b3e446928915/3061228945778420625;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0020?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:38 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051496000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdp9:4227,/bns/yr/borg/yr/bns/blobstore2/bitpusher/0.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=fcysW9y4OMSxkATZ74bIAQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yr/borg/yr/bns/blobstore2/bitpusher/0.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yr/borg/yr/bns/blobstore2/bitpusher/0:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWnhJX2MxZzUwRGhIUUYyaHZ3SXljdlJ1SEdtaEZZb3ZldVcwLVZDMUdOcjdRck83TTFuWXp0MklvWnJfaXBRTFlpNUplM1RyZ29mSUJJLXRFcnpkVlR2dzJsTGVlQWdJS1lmQ01WejJrT1pTWFo4Vk9FT3pzMHhVVExreDdiU2NtaWg3Ung5NXFVeEsxYjdwbkxQSGJ0RGhHOEhfTFZvUWhGT1pseWNwZ0E3NlZZODlSY3RiNHVLRGcwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Upkthb5ilb0PmvZb8U4V94kTAXT3MGBM_IgyGfzK-IJ6cNMLC5-5iXDx9bVq8L2RsI3oWQofGLNRTSEyGisE1QS9Od1uA" + ] + }, + "Body": "" + } + }, + { + "ID": "ef843a316e292cac", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/projects/dulcet-port-762/serviceAccount?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d7dda37113a0d839d93dfd3c96e9240d/3820265915199618784;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/projects/dulcet-port-762/serviceAccount?alt=json\u0026prettyPrint=false" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "115" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:38 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:38 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051498000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vraf24:4012,/bns/yv/borg/yv/bns/blobstore2/bitpusher/164.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=fsysW_33GJCAgwTX26HYCw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/164.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/164:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYjRBUXFsa3NIcFl6R0t5SlVsbnU0blE5Y0RGNkp6TDRMRmNFaFpMbTNYekFTUmhVUXQtQzgtN3FQcjhsMERLd0NWM09Mck1iR1lhZG0xZnFESVlSaFR3MzloN1Y0U1JocVZDdmM2eGJ2ZjZhVzcwSlhQU0JjdVVQRzVpMEJIMVdQcGZOR0NiakY1X19QcXBpb3lsWEJVaTFGa0l6TVRZWEk5bVk2N01kSG8wOENVOGN2N3hQenRsa1UwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur0HKrUa4R5Mq8Ygoy8TSuogTipVuQD81bwHIZhbVtOKm3ynxpsPT0CFMujvH7hOyRMdQOUJnJU12fFAqF8yrNatJVHFg" + ] + }, + "Body": "eyJlbWFpbF9hZGRyZXNzIjoic2VydmljZS0zNjYzOTkzMzE0NUBncy1wcm9qZWN0LWFjY291bnRzLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwia2luZCI6InN0b3JhZ2Ujc2VydmljZUFjY291bnQifQ==" + } + }, + { + "ID": "87b1562f89ba920e", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=127503253f4275a1da1367a0477ce4d95e90d1d7751cb3524fb96f55940e" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "5c407b38ad9b734e406b6679785ea219/4651640845550735407;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS0xMjc1MDMyNTNmNDI3NWExZGExMzY3YTA0NzdjZTRkOTVlOTBkMWQ3NzUxY2IzNTI0ZmI5NmY1NTk0MGUNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsIm5hbWUiOiJzb21lLW9iamVjdCJ9Cg0KLS0xMjc1MDMyNTNmNDI3NWExZGExMzY3YTA0NzdjZTRkOTVlOTBkMWQ3NzUxY2IzNTI0ZmI5NmY1NTk0MGUNCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbg0KDQpJco8tJMbRB9F7evlHCJTVDQotLTEyNzUwMzI1M2Y0Mjc1YTFkYTEzNjdhMDQ3N2NlNGQ5NWU5MGQxZDc3NTFjYjM1MjRmYjk2ZjU1OTQwZS0tDQo=" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3355" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:39 GMT" + ], + "Etag": [ + "CMXE9pqX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051498000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrqm23:4413,/bns/yv/borg/yv/bns/blobstore2/bitpusher/243.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=fsysW9qAOoGngASMt5uwAw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yv/borg/yv/bns/blobstore2/bitpusher/243.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yv/borg/yv/bns/blobstore2/bitpusher/243:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRYjRBUXFsa3NIcFl6R0t5SlVsbnU0blE5Y0RGNkp6TDRMRmNFaFpMbTNYekFTUmhVUXQtQzgtN3FQcjhsMERLd0NWM09Mck1iR1lhZG0xZnFESVlSaFR3MzloN1Y0U1JocVZDdmM2eGJ2ZjZhVzcwSlhQU0JjdVVQRzVpMEJIMVdQcGZOR0NiakY1X19QcXBpb3lsWEJVaTFGa0l6TVRZWEk5bVk2N01kSG8wOENVOGN2N3hQenRsa1UwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoZH9z6DQLmLB3hszbJhku2WP75wvFdtWB0fK58doI-vthHIkizLLlhv9R7fh6RktiLx1xK60xmYuZySlA3JW_n9MbA8Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9zb21lLW9iamVjdC8xNTM4MDUxMTk5MDUwMzA5Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vc29tZS1vYmplY3QiLCJuYW1lIjoic29tZS1vYmplY3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE5OTA1MDMwOSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjozOS4wNTBaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MzkuMDUwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjM5LjA1MFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoicUUrc2Iva3BhNXRXaGVidWVmdkFOdz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3NvbWUtb2JqZWN0P2dlbmVyYXRpb249MTUzODA1MTE5OTA1MDMwOSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9zb21lLW9iamVjdC8xNTM4MDUxMTk5MDUwMzA5L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vc29tZS1vYmplY3QvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoic29tZS1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE5OTA1MDMwOSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ01YRTlwcVgyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3NvbWUtb2JqZWN0LzE1MzgwNTExOTkwNTAzMDkvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vc29tZS1vYmplY3QvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExOTkwNTAzMDkiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ01YRTlwcVgyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3NvbWUtb2JqZWN0LzE1MzgwNTExOTkwNTAzMDkvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vc29tZS1vYmplY3QvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExOTkwNTAzMDkiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNNWEU5cHFYMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9zb21lLW9iamVjdC8xNTM4MDUxMTk5MDUwMzA5L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9zb21lLW9iamVjdC9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExOTkwNTAzMDkiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTVhFOXBxWDI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlNqenVxUT09IiwiZXRhZyI6IkNNWEU5cHFYMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "9ecb01da3bca46d8", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/some-object", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0cf8cc62e6088f206796f89f84a766d2/6241771278919366350;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/some-object" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=60" + ], + "Content-Length": [ + "16" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:39 GMT" + ], + "Etag": [ + "\"a84fac6ff9296b9b5685e6ee79fbc037\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:27:39 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:26:39 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:26:39 GMT" + ], + "X-Goog-Generation": [ + "1538051199050309" + ], + "X-Goog-Hash": [ + "crc32c=SjzuqQ==", + "md5=qE+sb/kpa5tWhebuefvANw==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "16" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/12,/bns/xh/borg/xh/bns/blobstore2/bitpusher/66.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=f8ysW4nqEcqtswbr-bqwBw" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/66.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/66:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Urw8zsXd0aII9-Dy-sOtg9P7YKZhi_9stUTywmNGoP55deaXNxwKNlKoSuPRmN7ABkk_PN3mBo56AbtnHHgMznZSZtzMQ" + ] + }, + "Body": "SXKPLSTG0QfRe3r5RwiU1Q==" + } + }, + { + "ID": "72b17314bb7de6e2", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/some-object?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "e27bc4849f7b3e65585a7b7f7eb80649/7832182083491666797;o=0" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/some-object?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3355" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:39 GMT" + ], + "Etag": [ + "CMXE9pqX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051498000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrdz77:4028,/bns/yw/borg/yw/bns/blobstore2/bitpusher/20.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=f8ysW7_lGIfjhASigr7ACQ" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/20.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/20:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRYjRBUXFsa3NIcFl6R0t5SlVsbnU0blE5Y0RGNkp6TDRMRmNFaFpMbTNYekFTUmhVUXQtQzgtN3FQcjhsMERLd0NWM09Mck1iR1lhZG0xZnFESVlSaFR3MzloN1Y0U1JocVZDdmM2eGJ2ZjZhVzcwSlhQU0JjdVVQRzVpMEJIMVdQcGZOR0NiakY1X19QcXBpb3lsWEJVaTFGa0l6TVRZWEk5bVk2N01kSG8wOENVOGN2N3hQenRsa1UwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uoa6lNJOwaCeO8CbNnMDeuNJhaMQUSmgIPPeM5txvHbfy-amN-3jbSuXejgrSadZ3_EKFxfGfJNssxhrZahoqwOU3msTQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9zb21lLW9iamVjdC8xNTM4MDUxMTk5MDUwMzA5Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vc29tZS1vYmplY3QiLCJuYW1lIjoic29tZS1vYmplY3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE5OTA1MDMwOSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjozOS4wNTBaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MzkuMDUwWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjM5LjA1MFoiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoicUUrc2Iva3BhNXRXaGVidWVmdkFOdz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3NvbWUtb2JqZWN0P2dlbmVyYXRpb249MTUzODA1MTE5OTA1MDMwOSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9zb21lLW9iamVjdC8xNTM4MDUxMTk5MDUwMzA5L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vc29tZS1vYmplY3QvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoic29tZS1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE5OTA1MDMwOSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ01YRTlwcVgyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3NvbWUtb2JqZWN0LzE1MzgwNTExOTkwNTAzMDkvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vc29tZS1vYmplY3QvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExOTkwNTAzMDkiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ01YRTlwcVgyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3NvbWUtb2JqZWN0LzE1MzgwNTExOTkwNTAzMDkvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vc29tZS1vYmplY3QvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExOTkwNTAzMDkiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNNWEU5cHFYMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9zb21lLW9iamVjdC8xNTM4MDUxMTk5MDUwMzA5L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9zb21lLW9iamVjdC9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InNvbWUtb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTExOTkwNTAzMDkiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTVhFOXBxWDI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlNqenVxUT09IiwiZXRhZyI6IkNNWEU5cHFYMjkwQ0VBRT0ifQ==" + } + }, + { + "ID": "e6fb407ff0ea1619", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1986dc56b619cf38e2e1dff7ba63e222/11772042856735554041;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "2493" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:39 GMT" + ], + "Etag": [ + "CAw=" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:39 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051499000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnbq5:4467,/bns/yx/borg/yx/bns/blobstore2/bitpusher/109.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=f8ysW6G1IsOSzALqioPQCw" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yx/borg/yx/bns/blobstore2/bitpusher/109.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yx/borg/yx/bns/blobstore2/bitpusher/109:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWWM5QnpDbzAwZl9ZcWt3RGJLV21iQWhrMXlzd1pUM0N2aVZrcjlNV2FJWWFTcDhXenE5WlVKR2wzVzVQTHNLSFgtRVdicUtncHF4ZzdPbDhpbWVQYXRXRHloVXgxVHhycVZ5R2xtNDNiaTlEZ3BrSGRKWlEtLUVVbndMVXZDSDFsQTIwcDMxMDVwZ3FhcEZhZG5RUFhGYklKTUtsVmRjVE5xaENqRG9UZmdXdXBYcFAyWjNRdlFpbjgwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Ur8lmXsqw9klo3KfTUQKj8SjhLcx5JNfMtlnIfw2b27a3bJzG3Ax2xD9Iqe5ZefCvdfTGStaoPjJlW1JwF-bcyRTqhLEQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjM6NTIuMzU1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI1OjIxLjYyNFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0F3PSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0F3PSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQXc9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQXc9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBdz0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBdz0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJ2ZXJzaW9uaW5nIjp7ImVuYWJsZWQiOmZhbHNlfSwibGlmZWN5Y2xlIjp7InJ1bGUiOlt7ImFjdGlvbiI6eyJ0eXBlIjoiRGVsZXRlIn0sImNvbmRpdGlvbiI6eyJhZ2UiOjMwfX1dfSwibGFiZWxzIjp7Im5ldyI6Im5ldyIsImwxIjoidjIifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0F3PSJ9" + } + }, + { + "ID": "d9fdf9def0ae992e", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0021?alt=json\u0026prettyPrint=false\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4d4193baef0cea67da822685e135bc86/3998359321505832337;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0021?alt=json\u0026prettyPrint=false\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "11693" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:39 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:39 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051499000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrsp13:4212,/bns/yw/borg/yw/bns/blobstore2/bitpusher/30.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=f8ysW4GkMtWuN-TzuZgK" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/30.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/30:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWWM5QnpDbzAwZl9ZcWt3RGJLV21iQWhrMXlzd1pUM0N2aVZrcjlNV2FJWWFTcDhXenE5WlVKR2wzVzVQTHNLSFgtRVdicUtncHF4ZzdPbDhpbWVQYXRXRHloVXgxVHhycVZ5R2xtNDNiaTlEZ3BrSGRKWlEtLUVVbndMVXZDSDFsQTIwcDMxMDVwZ3FhcEZhZG5RUFhGYklKTUtsVmRjVE5xaENqRG9UZmdXdXBYcFAyWjNRdlFpbjgwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoYHqfe9AEz4PqkjcQ8M4PtgG-XYjPzfLqyI_Rwy4j7jrKbFuXHoq_Us0tLKDQaHkdo_OdAFahJfqPTmHZlLIyCWoTjJQ" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpCVUNLRVRfTk9UX0ZPVU5EOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6OTkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjMxKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uQnVja2V0c0RlbGVnYXRvci5nZXQoQnVja2V0c0RlbGVnYXRvci5qYXZhOjgzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogTm8gc3VjaCBidWNrZXQ6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cbmNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkZhdWx0OiBJbW11dGFibGVFcnJvckRlZmluaXRpb257YmFzZT1OT1RfRk9VTkQsIGNhdGVnb3J5PVVTRVJfRVJST1IsIGNhdXNlPW51bGwsIGRlYnVnSW5mbz1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QlVDS0VUX05PVF9GT1VORDogTm8gc3VjaCBidWNrZXQ6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMuYnVja2V0cy5HZXRCdWNrZXQuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKEdldEJ1Y2tldC5qYXZhOjk5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YTozMSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLkJ1Y2tldHNEZWxlZ2F0b3IuZ2V0KEJ1Y2tldHNEZWxlZ2F0b3IuamF2YTo4Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE5vIHN1Y2ggYnVja2V0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9bm90Rm91bmQsIGludGVybmFsUmVhc29uPVJlYXNvbnthcmd1bWVudHM9e30sIGNhdXNlPW51bGwsIGNvZGU9Z2RhdGEuQ29yZUVycm9yRG9tYWluLk5PVF9GT1VORCwgY3JlYXRlZEJ5QmFja2VuZD10cnVlLCBkZWJ1Z01lc3NhZ2U9Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkJVQ0tFVF9OT1RfRk9VTkQ6IE5vIHN1Y2ggYnVja2V0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YTo5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6MzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmdldChCdWNrZXRzRGVsZWdhdG9yLmphdmE6ODMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5yZXNvdXJjZV9pZC5uYW1lLCBtZXNzYWdlPW51bGwsIHVubmFtZWRBcmd1bWVudHM9W119LCBsb2NhdGlvbj1lbnRpdHkucmVzb3VyY2VfaWQubmFtZSwgbWVzc2FnZT1Ob3QgRm91bmQsIHJlYXNvbj1ub3RGb3VuZCwgcnBjQ29kZT00MDR9IE5vdCBGb3VuZDogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkJVQ0tFVF9OT1RfRk9VTkQ6IE5vIHN1Y2ggYnVja2V0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLmJ1Y2tldHMuR2V0QnVja2V0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChHZXRCdWNrZXQuamF2YTo5OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5idWNrZXRzLkdldEJ1Y2tldC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoR2V0QnVja2V0LmphdmE6MzEpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5CdWNrZXRzRGVsZWdhdG9yLmdldChCdWNrZXRzRGVsZWdhdG9yLmphdmE6ODMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5FcnJvckNvbGxlY3Rvci50b0ZhdWx0KEVycm9yQ29sbGVjdG9yLmphdmE6NTQpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5RXJyb3JDb252ZXJ0ZXIudG9GYXVsdChSb3N5RXJyb3JDb252ZXJ0ZXIuamF2YTo2Nylcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjI1OClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lIYW5kbGVyJDIuY2FsbChSb3N5SGFuZGxlci5qYXZhOjIzOClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkRpcmVjdEV4ZWN1dG9yLmV4ZWN1dGUoRGlyZWN0RXhlY3V0b3IuamF2YTozMClcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmV4ZWN1dGVMaXN0ZW5lcihBYnN0cmFjdEZ1dHVyZS5qYXZhOjExNDMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5jb21wbGV0ZShBYnN0cmFjdEZ1dHVyZS5qYXZhOjk2Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLnNldChBYnN0cmFjdEZ1dHVyZS5qYXZhOjczMSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUudXRpbC5DYWxsYWJsZUZ1dHVyZS5ydW4oQ2FsbGFibGVGdXR1cmUuamF2YTo2Milcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnRocmVhZC5UaHJlYWRUcmFja2VycyRUaHJlYWRUcmFja2luZ1J1bm5hYmxlLnJ1bihUaHJlYWRUcmFja2Vycy5qYXZhOjEyNilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6NDU1KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuc2VydmVyLkNvbW1vbk1vZHVsZSRDb250ZXh0Q2FycnlpbmdFeGVjdXRvclNlcnZpY2UkMS5ydW5JbkNvbnRleHQoQ29tbW9uTW9kdWxlLmphdmE6ODQ2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlJDEucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ2Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoVHJhY2VDb250ZXh0LmphdmE6MzIxKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjMxMylcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDU5KVxuXHRhdCBjb20uZ29vZ2xlLmdzZS5pbnRlcm5hbC5EaXNwYXRjaFF1ZXVlSW1wbCRXb3JrZXJUaHJlYWQucnVuKERpc3BhdGNoUXVldWVJbXBsLmphdmE6NDAzKVxuIn1dLCJjb2RlIjo0MDQsIm1lc3NhZ2UiOiJOb3QgRm91bmQifX0=" + } + }, + { + "ID": "f2edea2e972018e1", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/storage-library-test-bucket/Caf%C3%A9", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "933e44fa78b6b0ed72a1c7d4bd460266/4757677761608773856;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/storage-library-test-bucket/Caf%C3%A9" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=3600" + ], + "Content-Length": [ + "20" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:39 GMT" + ], + "Etag": [ + "\"ade43306cb39336d630e101af5fb51b4\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 13:26:39 GMT" + ], + "Last-Modified": [ + "Fri, 24 Mar 2017 20:04:38 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Generation": [ + "1490385878535828" + ], + "X-Goog-Hash": [ + "crc32c=fN3yZg==", + "md5=reQzBss5M21jDhAa9ftRtA==" + ], + "X-Goog-Metageneration": [ + "2" + ], + "X-Goog-Storage-Class": [ + "MULTI_REGIONAL" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "20" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/37,/bns/xh/borg/xh/bns/blobstore2/bitpusher/49.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=f8ysW_rAMoSiswb5o6qIAQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "149776848335" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/49.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/49:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpJdKvPm3TxMimdp11GJCNz-S3qlr68hTz4f2s27QxYCMrVkbVDSRKeUhg-Btf2ddXmVwaNQ0sXdnkh6Vgfww7XD6j0ww" + ] + }, + "Body": "Tm9ybWFsaXphdGlvbiBGb3JtIEM=" + } + }, + { + "ID": "a29c391e37458245", + "Request": { + "Method": "POST", + "URL": "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "Content-Type": [ + "multipart/related; boundary=ae8294b34cb6487dfa4fea0f258df1ec078489b2ede5ab6f6bac3a2ac7f7" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "109c8ce598490c80bd07e57ab2feb0f2/5588771225556271919;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/upload/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026prettyPrint=false\u0026projection=full\u0026uploadType=multipart" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "LS1hZTgyOTRiMzRjYjY0ODdkZmE0ZmVhMGYyNThkZjFlYzA3ODQ4OWIyZWRlNWFiNmY2YmFjM2EyYWM3ZjcNCkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbg0KDQp7ImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm5hbWUiOiJ6ZXJvIn0KDQotLWFlODI5NGIzNGNiNjQ4N2RmYTRmZWEwZjI1OGRmMWVjMDc4NDg5YjJlZGU1YWI2ZjZiYWMzYTJhYzdmNw0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04DQoNCg0KLS1hZTgyOTRiMzRjYjY0ODdkZmE0ZmVhMGYyNThkZjFlYzA3ODQ4OWIyZWRlNWFiNmY2YmFjM2EyYWM3ZjctLQ0K" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "3221" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:40 GMT" + ], + "Etag": [ + "CPzzsJuX290CEAE=" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051499000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vrks2:4058,/bns/yw/borg/yw/bns/blobstore2/bitpusher/85.scotty,yxfg3-v6:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=f8ysW7vPN8j0hQSdnoHgBg" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "yxfg3-v6:443,/bns/yw/borg/yw/bns/blobstore2/bitpusher/85.scotty,yxfg3-v6:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yw/borg/yw/bns/blobstore2/bitpusher/85:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWWM5QnpDbzAwZl9ZcWt3RGJLV21iQWhrMXlzd1pUM0N2aVZrcjlNV2FJWWFTcDhXenE5WlVKR2wzVzVQTHNLSFgtRVdicUtncHF4ZzdPbDhpbWVQYXRXRHloVXgxVHhycVZ5R2xtNDNiaTlEZ3BrSGRKWlEtLUVVbndMVXZDSDFsQTIwcDMxMDVwZ3FhcEZhZG5RUFhGYklKTUtsVmRjVE5xaENqRG9UZmdXdXBYcFAyWjNRdlFpbjgwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_single_post_uploads" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UprL6_ZKFBbAa3bmTkv0s56mho6CPzO6zIAoHGZ_upPgJFAGrHfSXKPmjgB17shyHdAD2SvQz7t6nCfVMo65tybQC7OiQ" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS96ZXJvLzE1MzgwNTEyMDAwMDY2NTIiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby96ZXJvIiwibmFtZSI6Inplcm8iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTIwMDAwNjY1MiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjo0MC4wMDVaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6NDAuMDA1WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjQwLjAwNVoiLCJzaXplIjoiMCIsIm1kNUhhc2giOiIxQjJNMlk4QXNnVHBnQW1ZN1BoQ2ZnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vemVybz9nZW5lcmF0aW9uPTE1MzgwNTEyMDAwMDY2NTImYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvemVyby8xNTM4MDUxMjAwMDA2NjUyL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vemVyby9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJ6ZXJvIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEyMDAwMDY2NTIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNQenpzSnVYMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS96ZXJvLzE1MzgwNTEyMDAwMDY2NTIvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vemVyby9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiemVybyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMjAwMDA2NjUyIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNQenpzSnVYMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS96ZXJvLzE1MzgwNTEyMDAwMDY2NTIvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vemVyby9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiemVybyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMjAwMDA2NjUyIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDUHp6c0p1WDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvemVyby8xNTM4MDUxMjAwMDA2NjUyL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby96ZXJvL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiemVybyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMjAwMDA2NjUyIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1B6enNKdVgyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJBQUFBQUE9PSIsImV0YWciOiJDUHp6c0p1WDI5MENFQUU9In0=" + } + }, + { + "ID": "ad8e1b5fa8d4abd6", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0021/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "72f5cb05d9cd5cf0128b6566bbb6b02f/6348089665675924863;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0021/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 404, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "11713" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:39 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:39 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051499000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vlhm196:4223,/bns/yk/borg/yk/bns/blobstore2/bitpusher/511.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=f8ysW5aMONXuqQXr74ywDA" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/511.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/511:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWWM5QnpDbzAwZl9ZcWt3RGJLV21iQWhrMXlzd1pUM0N2aVZrcjlNV2FJWWFTcDhXenE5WlVKR2wzVzVQTHNLSFgtRVdicUtncHF4ZzdPbDhpbWVQYXRXRHloVXgxVHhycVZ5R2xtNDNiaTlEZ3BrSGRKWlEtLUVVbndMVXZDSDFsQTIwcDMxMDVwZ3FhcEZhZG5RUFhGYklKTUtsVmRjVE5xaENqRG9UZmdXdXBYcFAyWjNRdlFpbjgwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpkzYrUdFlxkZrW8EdgXtWWUKQvTAJuGymLHVTn4cPRfEREWNaVKuXwyYW4mF2y6_d3a1GoYDsx3b3TTuknUqSSfQEl_g" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6Im5vdEZvdW5kIiwibWVzc2FnZSI6Ik5vdCBGb3VuZCIsImRlYnVnSW5mbyI6ImNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpCVUNLRVRfTk9UX0ZPVU5EOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkxpc3RPYmplY3RzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0T2JqZWN0cy5qYXZhOjE2MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkxpc3RPYmplY3RzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0T2JqZWN0cy5qYXZhOjM4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5saXN0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE5vIHN1Y2ggYnVja2V0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5jb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS5GYXVsdDogSW1tdXRhYmxlRXJyb3JEZWZpbml0aW9ue2Jhc2U9Tk9UX0ZPVU5ELCBjYXRlZ29yeT1VU0VSX0VSUk9SLCBjYXVzZT1udWxsLCBkZWJ1Z0luZm89Y29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6OkJVQ0tFVF9OT1RfRk9VTkQ6IE5vIHN1Y2ggYnVja2V0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuTGlzdE9iamVjdHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RPYmplY3RzLmphdmE6MTYwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuTGlzdE9iamVjdHMuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKExpc3RPYmplY3RzLmphdmE6MzgpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmxpc3QoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjg5KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogTm8gc3VjaCBidWNrZXQ6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG4sIGRvbWFpbj1nbG9iYWwsIGV4dGVuZGVkSGVscD1udWxsLCBodHRwSGVhZGVycz17fSwgaHR0cFN0YXR1cz1ub3RGb3VuZCwgaW50ZXJuYWxSZWFzb249UmVhc29ue2FyZ3VtZW50cz17fSwgY2F1c2U9bnVsbCwgY29kZT1nZGF0YS5Db3JlRXJyb3JEb21haW4uTk9UX0ZPVU5ELCBjcmVhdGVkQnlCYWNrZW5kPXRydWUsIGRlYnVnTWVzc2FnZT1jb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6QlVDS0VUX05PVF9GT1VORDogTm8gc3VjaCBidWNrZXQ6IGdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAyMVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5MaXN0T2JqZWN0cy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdE9iamVjdHMuamF2YToxNjApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5MaXN0T2JqZWN0cy5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoTGlzdE9iamVjdHMuamF2YTozOClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IubGlzdChPYmplY3RzRGVsZWdhdG9yLmphdmE6ODkpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5Mylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcbiwgZXJyb3JQcm90b0NvZGU9Tk9UX0ZPVU5ELCBlcnJvclByb3RvRG9tYWluPWdkYXRhLkNvcmVFcnJvckRvbWFpbiwgZmlsdGVyZWRNZXNzYWdlPW51bGwsIGxvY2F0aW9uPWVudGl0eS5idWNrZXQsIG1lc3NhZ2U9bnVsbCwgdW5uYW1lZEFyZ3VtZW50cz1bXX0sIGxvY2F0aW9uPWVudGl0eS5idWNrZXQsIG1lc3NhZ2U9Tm90IEZvdW5kLCByZWFzb249bm90Rm91bmQsIHJwY0NvZGU9NDA0fSBOb3QgRm91bmQ6IGNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpCVUNLRVRfTk9UX0ZPVU5EOiBObyBzdWNoIGJ1Y2tldDogZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDIxXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkxpc3RPYmplY3RzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0T2JqZWN0cy5qYXZhOjE2MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkxpc3RPYmplY3RzLmhhbmRsZVJlcXVlc3RSZWNlaXZlZChMaXN0T2JqZWN0cy5qYXZhOjM4KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5saXN0KE9iamVjdHNEZWxlZ2F0b3IuamF2YTo4OSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE5vIHN1Y2ggYnVja2V0OiBnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMjFcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLkVycm9yQ29sbGVjdG9yLnRvRmF1bHQoRXJyb3JDb2xsZWN0b3IuamF2YTo1NClcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnJlc3QuYWRhcHRlci5yb3N5LlJvc3lFcnJvckNvbnZlcnRlci50b0ZhdWx0KFJvc3lFcnJvckNvbnZlcnRlci5qYXZhOjY3KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjU4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUhhbmRsZXIkMi5jYWxsKFJvc3lIYW5kbGVyLmphdmE6MjM4KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuRGlyZWN0RXhlY3V0b3IuZXhlY3V0ZShEaXJlY3RFeGVjdXRvci5qYXZhOjMwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuZXhlY3V0ZUxpc3RlbmVyKEFic3RyYWN0RnV0dXJlLmphdmE6MTE0Mylcblx0YXQgY29tLmdvb2dsZS5jb21tb24udXRpbC5jb25jdXJyZW50LkFic3RyYWN0RnV0dXJlLmNvbXBsZXRlKEFic3RyYWN0RnV0dXJlLmphdmE6OTYzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuc2V0KEFic3RyYWN0RnV0dXJlLmphdmE6NzMxKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIuY29yZS51dGlsLkNhbGxhYmxlRnV0dXJlLnJ1bihDYWxsYWJsZUZ1dHVyZS5qYXZhOjYyKVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIudGhyZWFkLlRocmVhZFRyYWNrZXJzJFRocmVhZFRyYWNraW5nUnVubmFibGUucnVuKFRocmVhZFRyYWNrZXJzLmphdmE6MTI2KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTo0NTUpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5zZXJ2ZXIuQ29tbW9uTW9kdWxlJENvbnRleHRDYXJyeWluZ0V4ZWN1dG9yU2VydmljZSQxLnJ1bkluQ29udGV4dChDb21tb25Nb2R1bGUuamF2YTo4NDYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUkMS5ydW4oVHJhY2VDb250ZXh0LmphdmE6NDYyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JEFic3RyYWN0VHJhY2VDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihUcmFjZUNvbnRleHQuamF2YTozMjEpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoVHJhY2VDb250ZXh0LmphdmE6MzEzKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuVHJhY2VDb250ZXh0JFRyYWNlQ29udGV4dFJ1bm5hYmxlLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NTkpXG5cdGF0IGNvbS5nb29nbGUuZ3NlLmludGVybmFsLkRpc3BhdGNoUXVldWVJbXBsJFdvcmtlclRocmVhZC5ydW4oRGlzcGF0Y2hRdWV1ZUltcGwuamF2YTo0MDMpXG4ifV0sImNvZGUiOjQwNCwibWVzc2FnZSI6Ik5vdCBGb3VuZCJ9fQ==" + } + }, + { + "ID": "66fe2a28fb424b1b", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/storage-library-test-bucket/Cafe%CC%81", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "c37f321207ea898411bcb64ce8a123d9/7938218995254868765;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/storage-library-test-bucket/Cafe%CC%81" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "public, max-age=3600" + ], + "Content-Length": [ + "20" + ], + "Content-Type": [ + "text/plain" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:40 GMT" + ], + "Etag": [ + "\"df597679bac7c6150429ad80a1a05680\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 13:26:40 GMT" + ], + "Last-Modified": [ + "Fri, 24 Mar 2017 20:04:37 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Generation": [ + "1490385877705600" + ], + "X-Goog-Hash": [ + "crc32c=qBeWjQ==", + "md5=31l2ebrHxhUEKa2AoaBWgA==" + ], + "X-Goog-Metageneration": [ + "2" + ], + "X-Goog-Storage-Class": [ + "MULTI_REGIONAL" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "20" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/41,/bns/xh/borg/xh/bns/blobstore2/bitpusher/31.scotty,aclgag19:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=gMysW-n0Au2iswb0w5eIAQ" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "149776848335" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/31.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/31:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoNn1YQ-BDeQ-KRYAa-HiVMAgNHohnsb2swJwhk8j-DIFUfIxwS-uSy-ewFIj6cekOhnlt8vVrHhxZkrgZ3kftYtB2g_A" + ] + }, + "Body": "Tm9ybWFsaXphdGlvbiBGb3JtIEQ=" + } + }, + { + "ID": "f235a22996dff1e9", + "Request": { + "Method": "GET", + "URL": "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/zero", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "Go-http-client/1.1" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "5235692a62da640b886a2be6092c3a8f/9528630899322020028;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "storage.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://storage.googleapis.com/go-integration-test-20180927-44630911863640-0001/zero" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Accept-Ranges": [ + "bytes" + ], + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "text/plain; charset=utf-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:40 GMT" + ], + "Etag": [ + "\"d41d8cd98f00b204e9800998ecf8427e\"" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:40 GMT" + ], + "Last-Modified": [ + "Thu, 27 Sep 2018 12:26:40 GMT" + ], + "Server": [ + "UploadServer" + ], + "X-Goog-Expiration": [ + "Sat, 27 Oct 2018 12:26:40 GMT" + ], + "X-Goog-Generation": [ + "1538051200006652" + ], + "X-Goog-Hash": [ + "crc32c=AAAAAA==", + "md5=1B2M2Y8AsgTpgAmY7PhCfg==" + ], + "X-Goog-Metageneration": [ + "1" + ], + "X-Goog-Storage-Class": [ + "STANDARD" + ], + "X-Goog-Stored-Content-Encoding": [ + "identity" + ], + "X-Goog-Stored-Content-Length": [ + "0" + ], + "X-Google-Backends": [ + "/bns/xh/borg/xh/bns/cloud-storage/prod-cloud-storage-frontend.frontend/31,/bns/xh/borg/xh/bns/blobstore2/bitpusher/54.scotty,aclgag19:443" + ], + "X-Google-Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=gMysW43ZCaagswbX74WoBA" + ], + "X-Google-Gfe-Cloud-Project-Number": [ + "36639933145" + ], + "X-Google-Gfe-Request-Trace": [ + "aclgag19:443,/bns/xh/borg/xh/bns/blobstore2/bitpusher/54.scotty,aclgag19:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-cloud-storage" + ], + "X-Google-Netmon-Label": [ + "/bns/xh/borg/xh/bns/blobstore2/bitpusher/54:caf3" + ], + "X-Google-Service": [ + "bitpusher-cloud-storage" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBJ" + ], + "X-Google-Storage-Location": [ + "US" + ], + "X-Guploader-Customer": [ + "cloud-storage" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpRIGEDgm48N7EzftkVrfZeWQdtHI4QTti5zdCFBt7gLd3XZDI6Ehi5VVtXA0DAnoDRx1CGBgC0W9CGOHt-JOsIkALP1g" + ] + }, + "Body": "" + } + }, + { + "ID": "7889cb6a06d14c21", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/zero?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "f59da26d669545720dc31e2a55614433/10359724363269518091;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/zero?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:40 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051500000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnpp189:4374,/bns/yk/borg/yk/bns/blobstore2/bitpusher/765.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=gMysW5rFDtW4qQXQnLHQBQ" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/765.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/765:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWWM5QnpDbzAwZl9ZcWt3RGJLV21iQWhrMXlzd1pUM0N2aVZrcjlNV2FJWWFTcDhXenE5WlVKR2wzVzVQTHNLSFgtRVdicUtncHF4ZzdPbDhpbWVQYXRXRHloVXgxVHhycVZ5R2xtNDNiaTlEZ3BrSGRKWlEtLUVVbndMVXZDSDFsQTIwcDMxMDVwZ3FhcEZhZG5RUFhGYklKTUtsVmRjVE5xaENqRG9UZmdXdXBYcFAyWjNRdlFpbjgwBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqRhqqFiBwv6ALAvWPdy7FoMtfiJtc7AdZC3JrI92TgGvrnvK6IouIO2tkfGGKVxqq0SdCy6c-3RlAZqCL2DVyogJawrA" + ] + }, + "Body": "" + } + }, + { + "ID": "df180f9e03860f11", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "725cdf27d3143785c971c87035f61f1a/11119042803372394075;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "66618" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:44 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:44 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051503000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vlep62:4200,/bns/yk/borg/yk/bns/blobstore2/bitpusher/689.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=g8ysW__dOdXZqAXus6PwCg" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/689.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/689:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoqUqo_U2y3joYDko_2gxf4WCSpFiddYyWfcbCD8QiyOD-5tvBtzIAB0JiYF9KQSIvI6DqW2XH7pa1qz4qgsuEplKIO-g" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbDEvMTUzODA1MTA2MzIzMTMxNyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2FjbDEiLCJuYW1lIjoiYWNsMSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDYzMjMxMzE3IiwibWV0YWdlbmVyYXRpb24iOiIyIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MjMuMjMwWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjI0LjQ4N1oiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoyMy4yMzBaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6InpwQ0ozb3JROTV5eHZmeitRcTd2UUE9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hY2wxP2dlbmVyYXRpb249MTUzODA1MTA2MzIzMTMxNyZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wxLzE1MzgwNTEwNjMyMzEzMTcvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hY2wxL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImFjbDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA2MzIzMTMxNyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ05YbWxOcVcyOTBDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbDEvMTUzODA1MTA2MzIzMTMxNy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hY2wxL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjMyMzEzMTciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ05YbWxOcVcyOTBDRUFJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbDEvMTUzODA1MTA2MzIzMTMxNy9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hY2wxL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjMyMzEzMTciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOWG1sTnFXMjkwQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wxLzE1MzgwNTEwNjMyMzEzMTcvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2FjbDEvYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjMyMzEzMTciLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTlhtbE5xVzI5MENFQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IjViL2ltZz09IiwiZXRhZyI6IkNOWG1sTnFXMjkwQ0VBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbDIvMTUzODA1MTA2Mzk1MTQ5OSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2FjbDIiLCJuYW1lIjoiYWNsMiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDYzOTUxNDk5IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJhcHBsaWNhdGlvbi9vY3RldC1zdHJlYW0iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MjMuOTUxWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjIzLjk1MVoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoyMy45NTFaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6ImFtdGMwalVmWjJDRUYwR1ZmNVR6ZXc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hY2wyP2dlbmVyYXRpb249MTUzODA1MTA2Mzk1MTQ5OSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wyLzE1MzgwNTEwNjM5NTE0OTkvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hY2wyL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImFjbDIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA2Mzk1MTQ5OSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0l2aHdOcVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbDIvMTUzODA1MTA2Mzk1MTQ5OS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hY2wyL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjM5NTE0OTkiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0l2aHdOcVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbDIvMTUzODA1MTA2Mzk1MTQ5OS9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hY2wyL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJhY2wyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjM5NTE0OTkiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJdmh3TnFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9hY2wyLzE1MzgwNTEwNjM5NTE0OTkvZG9tYWluLWdvb2dsZS5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9hY2wyL2FjbC9kb21haW4tZ29vZ2xlLmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImFjbDIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA2Mzk1MTQ5OSIsImVudGl0eSI6ImRvbWFpbi1nb29nbGUuY29tIiwicm9sZSI6IlJFQURFUiIsImRvbWFpbiI6Imdvb2dsZS5jb20iLCJldGFnIjoiQ0l2aHdOcVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2FjbDIvMTUzODA1MTA2Mzk1MTQ5OS91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYWNsMi9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImFjbDIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA2Mzk1MTQ5OSIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNJdmh3TnFXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiWWRyanhnPT0iLCJldGFnIjoiQ0l2aHdOcVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvYnVja2V0SW5Db3B5QXR0cnMvMTUzODA1MTA4NDIyNDYwMCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2J1Y2tldEluQ29weUF0dHJzIiwibmFtZSI6ImJ1Y2tldEluQ29weUF0dHJzIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODQyMjQ2MDAiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDQuMjI0WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQ0LjIyNFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0NC4yMjRaIiwic2l6ZSI6IjMiLCJtZDVIYXNoIjoickwwWTIwekMrRnp0NzJWUHpNU2syQT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2J1Y2tldEluQ29weUF0dHJzP2dlbmVyYXRpb249MTUzODA1MTA4NDIyNDYwMCZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9idWNrZXRJbkNvcHlBdHRycy8xNTM4MDUxMDg0MjI0NjAwL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYnVja2V0SW5Db3B5QXR0cnMvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiYnVja2V0SW5Db3B5QXR0cnMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NDIyNDYwMCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ05pUWx1U1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2J1Y2tldEluQ29weUF0dHJzLzE1MzgwNTEwODQyMjQ2MDAvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYnVja2V0SW5Db3B5QXR0cnMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImJ1Y2tldEluQ29weUF0dHJzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODQyMjQ2MDAiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ05pUWx1U1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2J1Y2tldEluQ29weUF0dHJzLzE1MzgwNTEwODQyMjQ2MDAvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vYnVja2V0SW5Db3B5QXR0cnMvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImJ1Y2tldEluQ29weUF0dHJzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODQyMjQ2MDAiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNOaVFsdVNXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9idWNrZXRJbkNvcHlBdHRycy8xNTM4MDUxMDg0MjI0NjAwL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9idWNrZXRJbkNvcHlBdHRycy9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImJ1Y2tldEluQ29weUF0dHJzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODQyMjQ2MDAiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTmlRbHVTVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6Ino4U3VIUT09IiwiZXRhZyI6IkNOaVFsdVNXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NoZWNrc3VtLW9iamVjdC8xNTM4MDUxMDU1MzM3NTE5Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY2hlY2tzdW0tb2JqZWN0IiwibmFtZSI6ImNoZWNrc3VtLW9iamVjdCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU1MzM3NTE5IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjE1LjMzN1oiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxNS4zMzdaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MTUuMzM3WiIsInNpemUiOiIxMCIsIm1kNUhhc2giOiIvRjREalRpbGNESUlWRUhuL25BUXNBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY2hlY2tzdW0tb2JqZWN0P2dlbmVyYXRpb249MTUzODA1MTA1NTMzNzUxOSZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jaGVja3N1bS1vYmplY3QvMTUzODA1MTA1NTMzNzUxOS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NoZWNrc3VtLW9iamVjdC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjaGVja3N1bS1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1NTMzNzUxOSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0srQXM5YVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NoZWNrc3VtLW9iamVjdC8xNTM4MDUxMDU1MzM3NTE5L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NoZWNrc3VtLW9iamVjdC9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY2hlY2tzdW0tb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTUzMzc1MTkiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0srQXM5YVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NoZWNrc3VtLW9iamVjdC8xNTM4MDUxMDU1MzM3NTE5L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NoZWNrc3VtLW9iamVjdC9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY2hlY2tzdW0tb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTUzMzc1MTkiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNLK0FzOWFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jaGVja3N1bS1vYmplY3QvMTUzODA1MTA1NTMzNzUxOS91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY2hlY2tzdW0tb2JqZWN0L2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY2hlY2tzdW0tb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTUzMzc1MTkiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSytBczlhVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlZzdTBnQT09IiwiZXRhZyI6IkNLK0FzOWFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbXBvc2VkMS8xNTM4MDUxMDU3Njg4MTc4Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29tcG9zZWQxIiwibmFtZSI6ImNvbXBvc2VkMSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU3Njg4MTc4IiwibWV0YWdlbmVyYXRpb24iOiIxIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjE3LjY4OFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxNy42ODhaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MTcuNjg4WiIsInNpemUiOiI0OCIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb21wb3NlZDE/Z2VuZXJhdGlvbj0xNTM4MDUxMDU3Njg4MTc4JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbXBvc2VkMS8xNTM4MDUxMDU3Njg4MTc4L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29tcG9zZWQxL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbXBvc2VkMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU3Njg4MTc4IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUEs4d3RlVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29tcG9zZWQxLzE1MzgwNTEwNTc2ODgxNzgvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29tcG9zZWQxL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjb21wb3NlZDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1NzY4ODE3OCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUEs4d3RlVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29tcG9zZWQxLzE1MzgwNTEwNTc2ODgxNzgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29tcG9zZWQxL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjb21wb3NlZDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1NzY4ODE3OCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1BLOHd0ZVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbXBvc2VkMS8xNTM4MDUxMDU3Njg4MTc4L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb21wb3NlZDEvYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjb21wb3NlZDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1NzY4ODE3OCIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQSzh3dGVXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiYm9COG13PT0iLCJjb21wb25lbnRDb3VudCI6MywiZXRhZyI6IkNQSzh3dGVXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbXBvc2VkMi8xNTM4MDUxMDU4MzgxNzg1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29tcG9zZWQyIiwibmFtZSI6ImNvbXBvc2VkMiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU4MzgxNzg1IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L2pzb24iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MTguMzc5WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjE4LjM3OVoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxOC4zNzlaIiwic2l6ZSI6IjQ4IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbXBvc2VkMj9nZW5lcmF0aW9uPTE1MzgwNTEwNTgzODE3ODUmYWx0PW1lZGlhIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29tcG9zZWQyLzE1MzgwNTEwNTgzODE3ODUvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb21wb3NlZDIvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY29tcG9zZWQyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTgzODE3ODUiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNObm43TmVXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb21wb3NlZDIvMTUzODA1MTA1ODM4MTc4NS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb21wb3NlZDIvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbXBvc2VkMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU4MzgxNzg1IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNObm43TmVXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb21wb3NlZDIvMTUzODA1MTA1ODM4MTc4NS9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb21wb3NlZDIvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbXBvc2VkMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU4MzgxNzg1IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTm5uN05lVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29tcG9zZWQyLzE1MzgwNTEwNTgzODE3ODUvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbXBvc2VkMi9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbXBvc2VkMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU4MzgxNzg1IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ05ubjdOZVcyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJib0I4bXc9PSIsImNvbXBvbmVudENvdW50IjozLCJldGFnIjoiQ05ubjdOZVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY29udGVudC8xNTM4MDUxMDc1MzMwMDQ5Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY29udGVudCIsIm5hbWUiOiJjb250ZW50IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzUzMzAwNDkiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6ImltYWdlL2pwZWciLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzUuMzI5WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM1LjMyOVoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNS4zMjlaIiwic2l6ZSI6IjU0IiwibWQ1SGFzaCI6Ik44cDgvczlGd2RBQW5sdnIvbEVBalE9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50P2dlbmVyYXRpb249MTUzODA1MTA3NTMzMDA0OSZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzUzMzAwNDkvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50L2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImNvbnRlbnQiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTMzMDA0OSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0lHZzk5K1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbnRlbnQvMTUzODA1MTA3NTMzMDA0OS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50L2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzUzMzAwNDkiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0lHZzk5K1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2NvbnRlbnQvMTUzODA1MTA3NTMzMDA0OS9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jb250ZW50L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzUzMzAwNDkiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJR2c5OStXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jb250ZW50LzE1MzgwNTEwNzUzMzAwNDkvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2NvbnRlbnQvYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjb250ZW50IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNzUzMzAwNDkiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSUdnOTkrVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IkdvVWJzUT09IiwiZXRhZyI6IkNJR2c5OStXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTUzODA1MTA3NTk1NjQ3OSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24iLCJuYW1lIjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc1OTU2NDc5IiwibWV0YWdlbmVyYXRpb24iOiIzIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluOyBjaGFyc2V0PXV0Zi04IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjM1Ljk1NloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDozNi43NDdaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MzUuOTU2WiIsInNpemUiOiIxMSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uP2dlbmVyYXRpb249MTUzODA1MTA3NTk1NjQ3OSZhbHQ9bWVkaWEiLCJjb250ZW50TGFuZ3VhZ2UiOiJlbiIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTUzODA1MTA3NTk1NjQ3OS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDc1OTU2NDc5IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUCs5bmVDVzI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTM4MDUxMDc1OTU2NDc5L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUCs5bmVDVzI5MENFQU09In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi8xNTM4MDUxMDc1OTU2NDc5L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24vYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1ArOW5lQ1cyOTBDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24vMTUzODA1MTA3NTk1NjQ3OS91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24iLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA3NTk1NjQ3OSIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQKzluZUNXMjkwQ0VBTT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiZXRhZyI6IkNQKzluZUNXMjkwQ0VBTT0iLCJjdXN0b21lckVuY3J5cHRpb24iOnsiZW5jcnlwdGlvbkFsZ29yaXRobSI6IkFFUzI1NiIsImtleVNoYTI1NiI6IkgrTG1uWGhSb2VJNlRNVzVic1Y2SHlVazZweUdjMklNYnFZYkFYQmNwczA9In19LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yLzE1MzgwNTEwODEyMTU2MDciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uLTIiLCJuYW1lIjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODEyMTU2MDciLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDEuMjE0WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQxLjIxNFoiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0MS4yMTRaIiwic2l6ZSI6IjExIiwibWQ1SGFzaCI6Inh3V05GYTBWZFhQbWxBd3JsY0FKY2c9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uLTI/Z2VuZXJhdGlvbj0xNTM4MDUxMDgxMjE1NjA3JmFsdD1tZWRpYSIsImNvbnRlbnRMYW5ndWFnZSI6ImVuIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yLzE1MzgwNTEwODEyMTU2MDcvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uLTIvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0yIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODEyMTU2MDciLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNQZTgzdUtXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA4MTIxNTYwNy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uLTIvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDgxMjE1NjA3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNQZTgzdUtXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTIvMTUzODA1MTA4MTIxNTYwNy9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9jdXN0b21lci1lbmNyeXB0aW9uLTIvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDgxMjE1NjA3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDUGU4M3VLVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvY3VzdG9tZXItZW5jcnlwdGlvbi0yLzE1MzgwNTEwODEyMTU2MDcvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMi9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6ImN1c3RvbWVyLWVuY3J5cHRpb24tMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDgxMjE1NjA3IiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ1BlODN1S1cyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiJyME5Hcmc9PSIsImV0YWciOiJDUGU4M3VLVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTMvMTUzODA1MTA4MDQzNDU0NyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMyIsIm5hbWUiOiJjdXN0b21lci1lbmNyeXB0aW9uLTMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MDQzNDU0NyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0MC40MzRaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDAuNDM0WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQwLjQzNFoiLCJzaXplIjoiMjIiLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0zP2dlbmVyYXRpb249MTUzODA1MTA4MDQzNDU0NyZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTMvMTUzODA1MTA4MDQzNDU0Ny9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJjdXN0b21lci1lbmNyeXB0aW9uLTMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MDQzNDU0NyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1BQbXJ1S1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMy8xNTM4MDUxMDgwNDM0NTQ3L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMy9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODA0MzQ1NDciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1BQbXJ1S1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2N1c3RvbWVyLWVuY3J5cHRpb24tMy8xNTM4MDUxMDgwNDM0NTQ3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2N1c3RvbWVyLWVuY3J5cHRpb24tMy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODA0MzQ1NDciLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQUG1ydUtXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9jdXN0b21lci1lbmNyeXB0aW9uLTMvMTUzODA1MTA4MDQzNDU0Ny91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vY3VzdG9tZXItZW5jcnlwdGlvbi0zL2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiY3VzdG9tZXItZW5jcnlwdGlvbi0zIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODA0MzQ1NDciLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUFBtcnVLVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNvbXBvbmVudENvdW50IjoyLCJldGFnIjoiQ1BQbXJ1S1cyOTBDRUFFPSIsImN1c3RvbWVyRW5jcnlwdGlvbiI6eyJlbmNyeXB0aW9uQWxnb3JpdGhtIjoiQUVTMjU2Iiwia2V5U2hhMjU2IjoiSCtMbW5YaFJvZUk2VE1XNWJzVjZIeVVrNnB5R2MySU1icVliQVhCY3BzMD0ifX0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9nemlwLXRlc3QvMTUzODA1MTA1OTEzODUxMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2d6aXAtdGVzdCIsIm5hbWUiOiJnemlwLXRlc3QiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1OTEzODUxMiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoiYXBwbGljYXRpb24veC1nemlwIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjE5LjEzOFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxOS4xMzhaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MTkuMTM4WiIsInNpemUiOiIyNyIsIm1kNUhhc2giOiJPdEN3K2FSUklScUtHRkFFT2F4K3F3PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vZ3ppcC10ZXN0P2dlbmVyYXRpb249MTUzODA1MTA1OTEzODUxMiZhbHQ9bWVkaWEiLCJjb250ZW50RW5jb2RpbmciOiJnemlwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvZ3ppcC10ZXN0LzE1MzgwNTEwNTkxMzg1MTIvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9nemlwLXRlc3QvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiZ3ppcC10ZXN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTkxMzg1MTIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNORC9tdGlXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9nemlwLXRlc3QvMTUzODA1MTA1OTEzODUxMi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9nemlwLXRlc3QvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imd6aXAtdGVzdCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU5MTM4NTEyIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNORC9tdGlXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9nemlwLXRlc3QvMTUzODA1MTA1OTEzODUxMi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9nemlwLXRlc3QvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imd6aXAtdGVzdCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU5MTM4NTEyIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDTkQvbXRpVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvZ3ppcC10ZXN0LzE1MzgwNTEwNTkxMzg1MTIvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2d6aXAtdGVzdC9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imd6aXAtdGVzdCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDU5MTM4NTEyIiwiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInJvbGUiOiJPV05FUiIsImVtYWlsIjoiMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJldGFnIjoiQ05EL210aVcyOTBDRUFFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiI5RGh3QkE9PSIsImV0YWciOiJDTkQvbXRpVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9oYXNoZXNPblVwbG9hZC0xLzE1MzgwNTEwODYxMjc0ODciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9oYXNoZXNPblVwbG9hZC0xIiwibmFtZSI6Imhhc2hlc09uVXBsb2FkLTEiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NjEyNzQ4NyIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbjsgY2hhcnNldD11dGYtOCIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0Ni4xMjdaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDYuMTI3WiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQ2LjEyN1oiLCJzaXplIjoiMjciLCJtZDVIYXNoIjoib2ZaakdsY1hQSmlHT0FmS0ZiSmwxUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTE/Z2VuZXJhdGlvbj0xNTM4MDUxMDg2MTI3NDg3JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTUzODA1MTA4NjEyNzQ4Ny9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiaGFzaGVzT25VcGxvYWQtMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDg2MTI3NDg3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDUCtpaXVXVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvaGFzaGVzT25VcGxvYWQtMS8xNTM4MDUxMDg2MTI3NDg3L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NjEyNzQ4NyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDUCtpaXVXVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvaGFzaGVzT25VcGxvYWQtMS8xNTM4MDUxMDg2MTI3NDg3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL2hhc2hlc09uVXBsb2FkLTEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NjEyNzQ4NyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ1AraWl1V1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL2hhc2hlc09uVXBsb2FkLTEvMTUzODA1MTA4NjEyNzQ4Ny91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vaGFzaGVzT25VcGxvYWQtMS9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Imhhc2hlc09uVXBsb2FkLTEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4NjEyNzQ4NyIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNQK2lpdVdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiY0grQSt3PT0iLCJldGFnIjoiQ1AraWl1V1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqL3dpdGgvc2xhc2hlcy8xNTM4MDUxMDQ1NjI3MTk4Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMiLCJuYW1lIjoib2JqL3dpdGgvc2xhc2hlcyIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjYyN1oiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS42MjdaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuNjI3WiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiIrN21WbjZMVHdEblYzdGcvcENyaW93PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXM/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ1NjI3MTk4JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iaiUyRndpdGglMkZzbGFzaGVzL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmolMkZ3aXRoJTJGc2xhc2hlcy9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqL3dpdGgvc2xhc2hlcyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1NjI3MTk4IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmovd2l0aC9zbGFzaGVzLzE1MzgwNTEwNDU2MjcxOTgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iai93aXRoL3NsYXNoZXMiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTYyNzE5OCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0w2cTR0R1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iai93aXRoL3NsYXNoZXMvMTUzODA1MTA0NTYyNzE5OC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqJTJGd2l0aCUyRnNsYXNoZXMvYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmovd2l0aC9zbGFzaGVzIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDU2MjcxOTgiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTDZxNHRHVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6ImtTc1dRZz09IiwiZXRhZyI6IkNMNnE0dEdXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajEvMTUzODA1MTA0NDUzMjM2NiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEiLCJuYW1lIjoib2JqMSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ0NTMyMzY2IiwibWV0YWdlbmVyYXRpb24iOiI0IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA0LjUzMloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxNi4yMTBaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDQuNTMyWiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiI3d1VGSDhtRER3SEZZcW83b2x4ZFBnPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMT9nZW5lcmF0aW9uPTE1MzgwNTEwNDQ1MzIzNjYmYWx0PW1lZGlhIiwiY2FjaGVDb250cm9sIjoicHVibGljLCBtYXgtYWdlPTYwIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L2RvbWFpbi1nb29nbGUuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvZG9tYWluLWdvb2dsZS5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDQ1MzIzNjYiLCJlbnRpdHkiOiJkb21haW4tZ29vZ2xlLmNvbSIsInJvbGUiOiJSRUFERVIiLCJkb21haW4iOiJnb29nbGUuY29tIiwiZXRhZyI6IkNJN0JuOUdXMjkwQ0VBUT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoxLzE1MzgwNTEwNDQ1MzIzNjYvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajEvYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDQ1MzIzNjYiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSTdCbjlHVzI5MENFQVE9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMS8xNTM4MDUxMDQ0NTMyMzY2L2FsbFVzZXJzIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMS9hY2wvYWxsVXNlcnMiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJvYmoxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNDQ1MzIzNjYiLCJlbnRpdHkiOiJhbGxVc2VycyIsInJvbGUiOiJSRUFERVIiLCJldGFnIjoiQ0k3Qm45R1cyOTBDRUFRPSJ9XSwib3duZXIiOnsiZW50aXR5IjoidXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSJ9LCJjcmMzMmMiOiIrN1IxMWc9PSIsImV0YWciOiJDSTdCbjlHVzI5MENFQVE9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3QiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vYmoyLzE1MzgwNTEwNDUxMzI2MzEiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9vYmoyIiwibmFtZSI6Im9iajIiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImNvbnRlbnRUeXBlIjoidGV4dC9wbGFpbiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDowNS4xMzJaIiwidXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MDUuMTMyWiIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwidGltZVN0b3JhZ2VDbGFzc1VwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjA1LjEzMloiLCJzaXplIjoiMTYiLCJtZDVIYXNoIjoiaDY0bVlxSjJPNTRqcnhHT0pOeUd4UT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajI/Z2VuZXJhdGlvbj0xNTM4MDUxMDQ1MTMyNjMxJmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoib2JqMiIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDQ1MTMyNjMxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTmVTeE5HVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvb2JqMi8xNTM4MDUxMDQ1MTMyNjMxL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL29iajIvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL29iajIvMTUzODA1MTA0NTEzMjYzMS91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vb2JqMi9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Im9iajIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA0NTEzMjYzMSIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNOZVN4TkdXMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiM0RLRHFnPT0iLCJldGFnIjoiQ05lU3hOR1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcG9zYy8xNTM4MDUxMDgzMjI3NTQ3Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYyIsIm5hbWUiOiJwb3NjIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODMyMjc1NDciLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDMuMjI1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQzLjIyNVoiLCJzdG9yYWdlQ2xhc3MiOiJNVUxUSV9SRUdJT05BTCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0My4yMjVaIiwic2l6ZSI6IjMiLCJtZDVIYXNoIjoickwwWTIwekMrRnp0NzJWUHpNU2syQT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3Bvc2M/Z2VuZXJhdGlvbj0xNTM4MDUxMDgzMjI3NTQ3JmFsdD1tZWRpYSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3Bvc2MvMTUzODA1MTA4MzIyNzU0Ny9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3Bvc2MvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoicG9zYyIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDgzMjI3NTQ3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDSnVqMmVPVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcG9zYy8xNTM4MDUxMDgzMjI3NTQ3L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3Bvc2MvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MzIyNzU0NyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDSnVqMmVPVzI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcG9zYy8xNTM4MDUxMDgzMjI3NTQ3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3Bvc2MvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MzIyNzU0NyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0p1ajJlT1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3Bvc2MvMTUzODA1MTA4MzIyNzU0Ny91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYy9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InBvc2MiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MzIyNzU0NyIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNKdWoyZU9XMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiejhTdUhRPT0iLCJldGFnIjoiQ0p1ajJlT1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvcG9zYzIvMTUzODA1MTA4MzcyNzU2MyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3Bvc2MyIiwibmFtZSI6InBvc2MyIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODM3Mjc1NjMiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6NDMuNzI3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjQzLjcyN1oiLCJzdG9yYWdlQ2xhc3MiOiJNVUxUSV9SRUdJT05BTCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDo0My43MjdaIiwic2l6ZSI6IjMiLCJtZDVIYXNoIjoiOVdHcTl1OEw4VTFDQ0x0R3BNeXpyUT09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3Bvc2MyP2dlbmVyYXRpb249MTUzODA1MTA4MzcyNzU2MyZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wb3NjMi8xNTM4MDUxMDgzNzI3NTYzL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYzIvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoicG9zYzIiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA4MzcyNzU2MyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ012bDkrT1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3Bvc2MyLzE1MzgwNTEwODM3Mjc1NjMvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYzIvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InBvc2MyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODM3Mjc1NjMiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ012bDkrT1cyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3Bvc2MyLzE1MzgwNTEwODM3Mjc1NjMvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vcG9zYzIvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InBvc2MyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODM3Mjc1NjMiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNNdmw5K09XMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9wb3NjMi8xNTM4MDUxMDgzNzI3NTYzL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9wb3NjMi9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6InBvc2MyIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwODM3Mjc1NjMiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTXZsOStPVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IjE3cUFCUT09IiwiZXRhZyI6IkNNdmw5K09XMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3NpZ25lZFVSTC8xNTM4MDUxMDYwMTI4MzI0Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vc2lnbmVkVVJMIiwibmFtZSI6InNpZ25lZFVSTCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMDYwMTI4MzI0IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjIwLjEyOFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoyMC4xMjhaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MjAuMTI4WiIsInNpemUiOiIyOSIsIm1kNUhhc2giOiJKeXh2Z3dtOW4yTXNyR1RNUGJNZVlBPT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vc2lnbmVkVVJMP2dlbmVyYXRpb249MTUzODA1MTA2MDEyODMyNCZhbHQ9bWVkaWEiLCJjYWNoZUNvbnRyb2wiOiJwdWJsaWMsIG1heC1hZ2U9NjAiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9zaWduZWRVUkwvMTUzODA1MTA2MDEyODMyNC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3NpZ25lZFVSTC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJzaWduZWRVUkwiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA2MDEyODMyNCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ01TMDE5aVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3NpZ25lZFVSTC8xNTM4MDUxMDYwMTI4MzI0L3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3NpZ25lZFVSTC9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoic2lnbmVkVVJMIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjAxMjgzMjQiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ01TMDE5aVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3NpZ25lZFVSTC8xNTM4MDUxMDYwMTI4MzI0L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3NpZ25lZFVSTC9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoic2lnbmVkVVJMIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjAxMjgzMjQiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNNUzAxOWlXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9zaWduZWRVUkwvMTUzODA1MTA2MDEyODMyNC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vc2lnbmVkVVJML2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoic2lnbmVkVVJMIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNjAxMjgzMjQiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDTVMwMTlpVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IlpUcUFMdz09IiwiZXRhZyI6IkNNUzAxOWlXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3NvbWUtb2JqZWN0LzE1MzgwNTExOTkwNTAzMDkiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9zb21lLW9iamVjdCIsIm5hbWUiOiJzb21lLW9iamVjdCIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTk5MDUwMzA5IiwibWV0YWdlbmVyYXRpb24iOiIxIiwiY29udGVudFR5cGUiOiJ0ZXh0L3BsYWluIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjM5LjA1MFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjozOS4wNTBaIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJ0aW1lU3RvcmFnZUNsYXNzVXBkYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MzkuMDUwWiIsInNpemUiOiIxNiIsIm1kNUhhc2giOiJxRStzYi9rcGE1dFdoZWJ1ZWZ2QU53PT0iLCJtZWRpYUxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9kb3dubG9hZC9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vc29tZS1vYmplY3Q/Z2VuZXJhdGlvbj0xNTM4MDUxMTk5MDUwMzA5JmFsdD1tZWRpYSIsImNhY2hlQ29udHJvbCI6InB1YmxpYywgbWF4LWFnZT02MCIsImFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3NvbWUtb2JqZWN0LzE1MzgwNTExOTkwNTAzMDkvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9zb21lLW9iamVjdC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEiLCJvYmplY3QiOiJzb21lLW9iamVjdCIsImdlbmVyYXRpb24iOiIxNTM4MDUxMTk5MDUwMzA5IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDTVhFOXBxWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvc29tZS1vYmplY3QvMTUzODA1MTE5OTA1MDMwOS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9zb21lLW9iamVjdC9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoic29tZS1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE5OTA1MDMwOSIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDTVhFOXBxWDI5MENFQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvc29tZS1vYmplY3QvMTUzODA1MTE5OTA1MDMwOS9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby9zb21lLW9iamVjdC9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoic29tZS1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE5OTA1MDMwOSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ01YRTlwcVgyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3NvbWUtb2JqZWN0LzE1MzgwNTExOTkwNTAzMDkvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3NvbWUtb2JqZWN0L2FjbC91c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0Ijoic29tZS1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTE5OTA1MDMwOSIsImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJyb2xlIjoiT1dORVIiLCJlbWFpbCI6IjM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwiZXRhZyI6IkNNWEU5cHFYMjkwQ0VBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InVzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20ifSwiY3JjMzJjIjoiU2p6dXFRPT0iLCJldGFnIjoiQ01YRTlwcVgyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvemVyby1vYmplY3QvMTUzODA1MTA1NTkzNjc1OCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3plcm8tb2JqZWN0IiwibmFtZSI6Inplcm8tb2JqZWN0IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTU5MzY3NTgiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJjb250ZW50VHlwZSI6InRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjQ6MTUuOTM2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI0OjE1LjkzNloiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNDoxNS45MzZaIiwic2l6ZSI6IjAiLCJtZDVIYXNoIjoiMUIyTTJZOEFzZ1RwZ0FtWTdQaENmZz09IiwibWVkaWFMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vZG93bmxvYWQvc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS9vL3plcm8tb2JqZWN0P2dlbmVyYXRpb249MTUzODA1MTA1NTkzNjc1OCZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS96ZXJvLW9iamVjdC8xNTM4MDUxMDU1OTM2NzU4L3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vemVyby1vYmplY3QvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxIiwib2JqZWN0IjoiemVyby1vYmplY3QiLCJnZW5lcmF0aW9uIjoiMTUzODA1MTA1NTkzNjc1OCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ1BiSjE5YVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3plcm8tb2JqZWN0LzE1MzgwNTEwNTU5MzY3NTgvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vemVyby1vYmplY3QvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Inplcm8tb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTU5MzY3NTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ1BiSjE5YVcyOTBDRUFFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL3plcm8tb2JqZWN0LzE1MzgwNTEwNTU5MzY3NTgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDAxL28vemVyby1vYmplY3QvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Inplcm8tb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTU5MzY3NTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNQYkoxOWFXMjkwQ0VBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMS96ZXJvLW9iamVjdC8xNTM4MDUxMDU1OTM2NzU4L3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMDEvby96ZXJvLW9iamVjdC9hY2wvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAwMSIsIm9iamVjdCI6Inplcm8tb2JqZWN0IiwiZ2VuZXJhdGlvbiI6IjE1MzgwNTEwNTU5MzY3NTgiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDUGJKMTlhVzI5MENFQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6IkFBQUFBQT09IiwiZXRhZyI6IkNQYkoxOWFXMjkwQ0VBRT0ifV19" + } + }, + { + "ID": "08c4d10dd8332635", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/acl1?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ef2d1528b634a8d513b51fceb3755dea/11950136267319892394;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/acl1?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:44 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vlfr201:4123,/bns/yk/borg/yk/bns/blobstore2/bitpusher/609.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=hMysW_jTEYe3qwWuxrnABQ" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/609.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/609:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpnXVUzckGzeWmCJAkfLe_4VfTkxJKwgFhdiaJ84f8BaD2BDM47uUHfASQw4_Gwd8tn3PSepx1i50ZVi-d9RDB_WFs8CQ" + ] + }, + "Body": "" + } + }, + { + "ID": "012e6a47fa7c11ad", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/acl2?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "aeab4ffc00ee146e9159e2cbc6697ce1/12709173232462965753;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/acl2?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:44 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vng123:4144,/bns/yk/borg/yk/bns/blobstore2/bitpusher/207.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=hMysW67MHsKSqQXUr52wAg" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/207.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/207:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqOT6HMXjKjXaR-65FBDE3UzG9tfq6NN2JjBBJuMvPQraW28CciOFm0f43SI6e59nQIaHqVrWusyu7mAQiVQQ9WMlc8sw" + ] + }, + "Body": "" + } + }, + { + "ID": "9d37776ab422369f", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/bucketInCopyAttrs?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b2f4772b497824d6fa08ec90d4b4ab2e/13540548167092207176;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/bucketInCopyAttrs?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:44 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vlkj7:4437,/bns/yk/borg/yk/bns/blobstore2/bitpusher/265.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=hMysW5nFL46LqgWQiJGICA" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/265.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/265:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqOqguDZoaoQuyhQZEqdT9gRvXfCOukU_s4IADMOeCthLyOz0ci8DeVKHiqdniCR2p0rFHU8lxtz2gq4GPJZakjC4cqig" + ] + }, + "Body": "" + } + }, + { + "ID": "f058e292b3ecbcdc", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/checksum-object?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1d4b9606de321abb0c58127db449aa56/14299585136513339800;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/checksum-object?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:45 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vlgh81:4169,/bns/yk/borg/yk/bns/blobstore2/bitpusher/302.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=hMysW5OOPIrCqgWgjKzoBg" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/302.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/302:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UptxT1bViawpoJzHTVTvKP4Xx1ZcSifkPhGPbzjvhW7hG9ugAgdOyI9uKaB4KOIMXAClmE6pHIqBaPUpEgvsppsHpWhzA" + ] + }, + "Body": "" + } + }, + { + "ID": "28115bbb2e191827", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/composed1?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "325c4987a34e0f0960b4194b3230753a/15130958971647730919;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/composed1?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:45 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vlaw129:4170,/bns/yk/borg/yk/bns/blobstore2/bitpusher/77.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=hcysW6GBIYTIqwWCqZ-YCg" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/77.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/77:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uq0IVEL0SX1tuKSBfKN5LKIj2zQZOeGRwK-vpSIa3Vz-jS_eaEWoR4kkvEpSHSwhkeASKZvvNxYij4YxB7TTQ7M0wU9Sg" + ] + }, + "Body": "" + } + }, + { + "ID": "b9135729814675aa", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/composed2?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "478ff7b82b02acc614fbd7491cc26138/15889995941085705782;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/composed2?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:45 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnfg189:4335,/bns/yk/borg/yk/bns/blobstore2/bitpusher/210.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=hcysW9WbLImgqQW5iZ2IAw" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/210.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/210:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up-GoXthTSv9bQ8EW2L_8OW8tcawoqd1dzbe5qE803XVsaMvhysX7AEki0vYm_b_PUp4UQo6nAJty3tzw3sJKs-CkVqZg" + ] + }, + "Body": "" + } + }, + { + "ID": "a70f6efc7b66aebd", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/content?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "f2138a3bfdb3ca1270a29175c89434a9/16649032910506838406;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/content?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:46 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vlfx126:4091,/bns/yk/borg/yk/bns/blobstore2/bitpusher/143.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=hcysW5HGN9aaqQXtlL7gBw" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/143.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/143:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqLRuDWRCZeM1EVDaQWKPgK7oGyYAhiawyTnUmvHL8adw-5x6bDRd4BAtsgEdd6dwTjGcM31JC_PVuxFXk2Gbmi-LgZPg" + ] + }, + "Body": "" + } + }, + { + "ID": "8e3c63694062e50d", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0563889f56ec7e8a3d4ba57f5eff7ec8/17480407845136080085;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:46 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnfl3:4248,/bns/yk/borg/yk/bns/blobstore2/bitpusher/112.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=hsysW6a5IMHIqgXnhp64Cg" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/112.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/112:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpQNMs15b2ZK6X_5MihXwZgEjLo6T05WbTr2n0z8XAU1_M6PFj_TGFOvcH2xA8v51X5rXwMMgOa8Zlnciiw5XoNA0wLzw" + ] + }, + "Body": "" + } + }, + { + "ID": "e77e746365ee07f6", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ce94342b388282a0f8a232cd262deb24/18239444810262376228;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-2?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:46 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnme21:4136,/bns/yk/borg/yk/bns/blobstore2/bitpusher/346.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=hsysW6OaMYbdqQWr3LygCA" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/346.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/346:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up7RfFw6uxIJDsqLp2OQTL_fS4D5Cc7UeUw4mfGwhtlWhLKTB-dm5O4V4A2TwN9GDbHkUTbBK973X78OUzH-R3oGR63mw" + ] + }, + "Body": "" + } + }, + { + "ID": "031605bbb573c6df", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-3?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1f633c49c4dc1cf5e4c915a12098d132/624075675493745012;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/customer-encryption-3?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:47 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vngr8:4458,/bns/yk/borg/yk/bns/blobstore2/bitpusher/776.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=hsysW6vkPMWPqwWHh7rQCw" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/776.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/776:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoK6XiFtLYFGaYtU7nXDjnLYgspLnsp33G7h02rm5oxCRPiKztJAxnaptk1DdxcsgtRWFDpspDibInpfJSmyNate7NAdA" + ] + }, + "Body": "" + } + }, + { + "ID": "a439009eb3aa1c46", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/gzip-test?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "873200505d2f90a7a10b789742172930/1383394115596686531;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/gzip-test?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:47 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnfl3:4248,/bns/yk/borg/yk/bns/blobstore2/bitpusher/415.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=h8ysW-3XC4aaqgWynrWACA" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/415.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/415:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrAL3qpc0XLK8xxxACBMn1fQsJ6CVsY_8Nz09Yy-uCdBU96K6ItuF_EzyJaBR9VqVAxYzetcGXWdykqY22ex6Rd7t-WnA" + ] + }, + "Body": "" + } + }, + { + "ID": "442cd738948405a8", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/hashesOnUpload-1?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b37363c18ed7c1f3a242d8100c37474d/2214487579544184594;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/hashesOnUpload-1?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:47 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnbf187:4310,/bns/yk/borg/yk/bns/blobstore2/bitpusher/120.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=h8ysW7KrF8a9qQX1-5gQ" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/120.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/120:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UrnZGU805pyZDr-jWUChiJ7PauljYSRc1qu3luwzs4sK1YhEeNuc4z23xWBHQUdf9xnFLxlcYF8y9Mp1J-ZjbXLlE7Edg" + ] + }, + "Body": "" + } + }, + { + "ID": "0ab5c557adf4d210", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj%2Fwith%2Fslashes?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "bfa8c9bbc4fe4bcd2dd20e47d1292d25/2973524548982094178;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj%2Fwith%2Fslashes?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:47 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnaq187:4351,/bns/yk/borg/yk/bns/blobstore2/bitpusher/324.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=h8ysW7reIsHxqwXNrrqQBA" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/324.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/324:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uro06y0j7cAboYlh45nook9CsziqhW4GSDgzR0O41cP9mfrL9LCu-VXFQJN4j_ifc0VzCxPCC_pS8Xi1JsLbiGTQZ4kZw" + ] + }, + "Body": "" + } + }, + { + "ID": "5d15c1564955b248", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1dd3e26a809feaa655da53979de2232c/3804899483611335857;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj1?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:47 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnlw7:4165,/bns/yk/borg/yk/bns/blobstore2/bitpusher/613.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=h8ysW4WLLoOrqwXN27_QBg" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/613.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/613:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uog3n9HLH7oOSIA-N3pS-kf6I_aeZYEinxjeDg9glVhvv8Hn9ZUJk6oKyu1vLO3bDnjVJjdaVeyT_w5C9zqouTqbvFDQA" + ] + }, + "Body": "" + } + }, + { + "ID": "773d0d0e7c8de8d7", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj2?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "ae355ff20ff9094a11603f3171b80758/4563935353537683200;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/obj2?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:48 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnbr125:4157,/bns/yk/borg/yk/bns/blobstore2/bitpusher/767.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=h8ysW8CeOY7HqwX96J_QBQ" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/767.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/767:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoEeadrUiIgvDLmHfsXIxGMbZwpdL5mrSCwSpoLJsFgNtv3HwESa9z6p58RBQEkI0ybLZtmCC4m5J7pliw5PcoJY-I9_w" + ] + }, + "Body": "" + } + }, + { + "ID": "7fbeaf8b3cf1b91c", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/posc?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "1d8302757f1cbbac298d60752aae572f/5395310283871957584;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/posc?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:48 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vngg82:4082,/bns/yk/borg/yk/bns/blobstore2/bitpusher/454.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=iMysW5mlB4n_qAXV4q7QBg" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/454.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/454:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UoY53cxU4F-dLTTWSvF_miS_w7rFCL6M3gLqmlhu57v_ZofFq1LhJsb7oj9A0OzWgKqL7LnByKllH5uDb02LVJYHZlTqQ" + ] + }, + "Body": "" + } + }, + { + "ID": "7a869ae16e04acab", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/posc2?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "0f17da0653514183f41837352b13cac1/6154347253309932703;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/posc2?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:48 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vlfu144:4148,/bns/yk/borg/yk/bns/blobstore2/bitpusher/345.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=iMysW5rwEoLHqQXhy6ugCQ" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/345.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/345:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo6NddOzIil9_TPreOmibWWAp0uuzawHLKoTgLsR5TFz4BdvjhLEPqJWnyQlbvuGu64LRM69DdFAU46Kv4G3wPMi1cDFg" + ] + }, + "Body": "" + } + }, + { + "ID": "90d1290d9e8338e4", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/signedURL?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "56769fe6f7799f8cce8d412e696c8d0d/6985440717257431022;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/signedURL?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:48 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vly135:4474,/bns/yk/borg/yk/bns/blobstore2/bitpusher/735.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=iMysW-uFHsGsqQWeuYfgCA" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/735.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/735:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UqvbeFGjeDdPJCJQCgDngxkPzKNvOQ8FdU1SY7YNAwACJ1YgjQxl6ogh-FGD6uYGinljM1qCH4diAOJC3qSsqKj1ZtNrw" + ] + }, + "Body": "" + } + }, + { + "ID": "9c1feb92dadcfc24", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/some-object?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "da9b41949711014098fef2c91d0f75d3/7744759157360306750;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/some-object?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:48 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vlba65:4352,/bns/yk/borg/yk/bns/blobstore2/bitpusher/169.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=iMysW_-jKYOPqQWX5o6wBA" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/169.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/169:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpXqAP9xLjQWdcgz7d8Q_Cbf4AnteqAh9Y73lfxN3Sf3RY2c88hpqs6As4zmkoi7IsdRwxSFQpbwjdWxFHktKceAVTcgg" + ] + }, + "Body": "" + } + }, + { + "ID": "32dbe6fe59803fdd", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/zero-object?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "b038092da7535a6b1a016b5969d43816/8503796126781504909;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001/o/zero-object?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:49 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vnll189:4029,/bns/yk/borg/yk/bns/blobstore2/bitpusher/96.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=iMysW56MNYWyqgWbr4X4Bw" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/96.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/96:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Uo3Gb0e8jwES-jB53Gxhy2Tmlp0VZUOMS4ml-qTNRDKPhFArOCBgKBoQ7ncCW6FqolC3nizW4el-fG3AzpD-xocDeXw4g" + ] + }, + "Body": "" + } + }, + { + "ID": "57411c02a06c30c2", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "7e48b2dfc255815f0f8966e31ae6a811/10094208030848655916;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180927-44630911863640-0001?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 204, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "no-cache, no-store, max-age=0, must-revalidate" + ], + "Content-Length": [ + "0" + ], + "Content-Type": [ + "application/json" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:49 GMT" + ], + "Expires": [ + "Mon, 01 Jan 1990 00:00:00 GMT" + ], + "Pragma": [ + "no-cache" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vngg200:4073,/bns/yk/borg/yk/bns/blobstore2/bitpusher/608.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=icysW43NBNPuqgXrl4aACg" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/608.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/608:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UolMTGCP9CHjJUePEKE4nRrZ1BxgPKXRv5wjE2rGWQ3hVauimcqefSaoRlr42ly3N6m8U8W3eKK42b_zjLI6lQmBK_ptA" + ] + }, + "Body": "" + } + }, + { + "ID": "94f77b6c25ff6aee", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b?alt=json\u0026pageToken=\u0026prefix=go-integration-test\u0026prettyPrint=false\u0026project=dulcet-port-762\u0026projection=full", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "4a5bbb92754558627e8dd36fe23e7902/10925301490501252475;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b?alt=json\u0026pageToken=\u0026prefix=go-integration-test\u0026prettyPrint=false\u0026project=dulcet-port-762\u0026projection=full" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "77624" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:49 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:49 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051503000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vldj144:4070,/bns/yk/borg/yk/bns/blobstore2/bitpusher/595.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=icysW7nUGNe2qwXao6yQDw" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/595.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/595:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2Up6TaL9Fk0PBYIR55LIqT8d93Peu8cpyc6QcENB7DInI2b12XEHdBbjY03_Ue-SY_V4i-E2t4QOnymAaoC9kwgvkpiB9w" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNidWNrZXRzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00MTMxNzY3MzE4MDAwLTAwMDIiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0xOFQwMTowODo1My4yOTVaIiwidXBkYXRlZCI6IjIwMTgtMDktMThUMDE6MDg6NTMuMjk1WiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00MTMxNzY3MzE4MDAwLTAwMDIvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMiIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00MTMxNzY3MzE4MDAwLTAwMDIvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00MTMxNzY3MzE4MDAwLTAwMDIvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDEzMTc2NzMxODAwMC0wMDAyIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDEzMTc2NzMxODAwMC0wMDAyL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDEzMTc2NzMxODAwMC0wMDAyL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQ3MzQyMDk0ODMwMDAtMDAwMSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDczNDIwOTQ4MzAwMC0wMDAxIiwicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDczNDIwOTQ4MzAwMC0wMDAxIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTE4VDAxOjE4OjU1LjA5NloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0xOFQwMToxODo1NS4wOTZaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQ3MzQyMDk0ODMwMDAtMDAwMS9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDczNDIwOTQ4MzAwMC0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDczNDIwOTQ4MzAwMC0wMDAxIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQ3MzQyMDk0ODMwMDAtMDAwMS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQ3MzQyMDk0ODMwMDAtMDAwMS9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00NzM0MjA5NDgzMDAwLTAwMDEiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00NzM0MjA5NDgzMDAwLTAwMDEvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00NzM0MjA5NDgzMDAwLTAwMDEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDczNDIwOTQ4MzAwMC0wMDAxIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDczNDIwOTQ4MzAwMC0wMDAyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00NzM0MjA5NDgzMDAwLTAwMDIiLCJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00NzM0MjA5NDgzMDAwLTAwMDIiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMThUMDE6MTg6NTUuOTkwWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTE4VDAxOjE4OjU1Ljk5MFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDczNDIwOTQ4MzAwMC0wMDAyL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00NzM0MjA5NDgzMDAwLTAwMDIvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00NzM0MjA5NDgzMDAwLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDczNDIwOTQ4MzAwMC0wMDAyL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDczNDIwOTQ4MzAwMC0wMDAyL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQ3MzQyMDk0ODMwMDAtMDAwMiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQ3MzQyMDk0ODMwMDAtMDAwMi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQ3MzQyMDk0ODMwMDAtMDAwMi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00NzM0MjA5NDgzMDAwLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00OTUzNTYyODAzMDAwLTAwMDIiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQ5NTM1NjI4MDMwMDAtMDAwMiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQ5NTM1NjI4MDMwMDAtMDAwMiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0xOFQwMToyMjozNC44NjBaIiwidXBkYXRlZCI6IjIwMTgtMDktMThUMDE6MjI6MzQuODYwWiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00OTUzNTYyODAzMDAwLTAwMDIvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQ5NTM1NjI4MDMwMDAtMDAwMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQ5NTM1NjI4MDMwMDAtMDAwMiIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00OTUzNTYyODAzMDAwLTAwMDIvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00OTUzNTYyODAzMDAwLTAwMDIvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDk1MzU2MjgwMzAwMC0wMDAyIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDk1MzU2MjgwMzAwMC0wMDAyL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDk1MzU2MjgwMzAwMC0wMDAyL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQ5NTM1NjI4MDMwMDAtMDAwMiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTU0NjE3OTA0MDcwMDAtMDAwMiIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNTQ2MTc5MDQwNzAwMC0wMDAyIiwicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNTQ2MTc5MDQwNzAwMC0wMDAyIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTE4VDAxOjMxOjA1LjQ5MloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0xOFQwMTozMTowNS40OTJaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTU0NjE3OTA0MDcwMDAtMDAwMi9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNTQ2MTc5MDQwNzAwMC0wMDAyL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNTQ2MTc5MDQwNzAwMC0wMDAyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTU0NjE3OTA0MDcwMDAtMDAwMi9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTU0NjE3OTA0MDcwMDAtMDAwMi9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC01NDYxNzkwNDA3MDAwLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC01NDYxNzkwNDA3MDAwLTAwMDIvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC01NDYxNzkwNDA3MDAwLTAwMDIvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNTQ2MTc5MDQwNzAwMC0wMDAyIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNTU2MTc3OTI0NjAwMC0wMDAyIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC01NTYxNzc5MjQ2MDAwLTAwMDIiLCJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC01NTYxNzc5MjQ2MDAwLTAwMDIiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMThUMDE6MzI6NDMuMjk3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTE4VDAxOjMyOjQzLjI5N1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNTU2MTc3OTI0NjAwMC0wMDAyL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC01NTYxNzc5MjQ2MDAwLTAwMDIvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC01NTYxNzc5MjQ2MDAwLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNTU2MTc3OTI0NjAwMC0wMDAyL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNTU2MTc3OTI0NjAwMC0wMDAyL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTU1NjE3NzkyNDYwMDAtMDAwMiIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTU1NjE3NzkyNDYwMDAtMDAwMi9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTU1NjE3NzkyNDYwMDAtMDAwMi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC01NTYxNzc5MjQ2MDAwLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC02Njg0MjM5MDAzMDAwLTAwMDIiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY2ODQyMzkwMDMwMDAtMDAwMiIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY2ODQyMzkwMDMwMDAtMDAwMiIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0xOFQwMTo1MToyNS43OTVaIiwidXBkYXRlZCI6IjIwMTgtMDktMThUMDE6NTE6MjUuNzk1WiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC02Njg0MjM5MDAzMDAwLTAwMDIvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY2ODQyMzkwMDMwMDAtMDAwMi9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY2ODQyMzkwMDMwMDAtMDAwMiIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC02Njg0MjM5MDAzMDAwLTAwMDIvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC02Njg0MjM5MDAzMDAwLTAwMDIvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNjY4NDIzOTAwMzAwMC0wMDAyIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNjY4NDIzOTAwMzAwMC0wMDAyL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNjY4NDIzOTAwMzAwMC0wMDAyL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY2ODQyMzkwMDMwMDAtMDAwMiIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSJ9LCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjM2MDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0xOFQwMTo1MToyNS43OTVaIn0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC02ODM3NzA3MzQxMDAwLTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY4Mzc3MDczNDEwMDAtMDAxNyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY4Mzc3MDczNDEwMDAtMDAxNyIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0xOFQwMTo1NjoyNC44OTZaIiwidXBkYXRlZCI6IjIwMTgtMDktMThUMDE6NTY6MjYuODY1WiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC02ODM3NzA3MzQxMDAwLTAwMTcvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY4Mzc3MDczNDEwMDAtMDAxNy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY4Mzc3MDczNDEwMDAtMDAxNyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC02ODM3NzA3MzQxMDAwLTAwMTcvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC02ODM3NzA3MzQxMDAwLTAwMTcvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNjgzNzcwNzM0MTAwMC0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNjgzNzcwNzM0MTAwMC0wMDE3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNjgzNzcwNzM0MTAwMC0wMDE3L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY4Mzc3MDczNDEwMDAtMDAxNyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSJ9LCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMThUMDE6NTY6MjQuODk2WiIsImlzTG9ja2VkIjp0cnVlfSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY4Mzc3MDczNDEwMDAtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNjgzNzcwNzM0MTAwMC0wMDE4IiwicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNjgzNzcwNzM0MTAwMC0wMDE4IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTE4VDAxOjU2OjI5LjA5MVoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0xOFQwMTo1NjoyOS4wOTFaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY4Mzc3MDczNDEwMDAtMDAxOC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNjgzNzcwNzM0MTAwMC0wMDE4L2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNjgzNzcwNzM0MTAwMC0wMDE4IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY4Mzc3MDczNDEwMDAtMDAxOC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTY4Mzc3MDczNDEwMDAtMDAxOC9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC02ODM3NzA3MzQxMDAwLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC02ODM3NzA3MzQxMDAwLTAwMTgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC02ODM3NzA3MzQxMDAwLTAwMTgvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNjgzNzcwNzM0MTAwMC0wMDE4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0xOFQwMTo1NjoyOS4wOTFaIn0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC03NTg3NzI5ODMwMDAwLTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTc1ODc3Mjk4MzAwMDAtMDAxNyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTc1ODc3Mjk4MzAwMDAtMDAxNyIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0xOFQwMjowODo0Ny42MDFaIiwidXBkYXRlZCI6IjIwMTgtMDktMThUMDI6MDg6NDkuMzQ2WiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC03NTg3NzI5ODMwMDAwLTAwMTcvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTc1ODc3Mjk4MzAwMDAtMDAxNy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTc1ODc3Mjk4MzAwMDAtMDAxNyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC03NTg3NzI5ODMwMDAwLTAwMTcvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC03NTg3NzI5ODMwMDAwLTAwMTcvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNzU4NzcyOTgzMDAwMC0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNzU4NzcyOTgzMDAwMC0wMDE3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNzU4NzcyOTgzMDAwMC0wMDE3L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTc1ODc3Mjk4MzAwMDAtMDAxNyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSJ9LCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMThUMDI6MDg6NDcuNjAxWiIsImlzTG9ja2VkIjp0cnVlfSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTc1ODc3Mjk4MzAwMDAtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNzU4NzcyOTgzMDAwMC0wMDE4IiwicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNzU4NzcyOTgzMDAwMC0wMDE4IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTE4VDAyOjA4OjU0LjA5NFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0xOFQwMjowODo1NC4wOTRaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTc1ODc3Mjk4MzAwMDAtMDAxOC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNzU4NzcyOTgzMDAwMC0wMDE4L2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNzU4NzcyOTgzMDAwMC0wMDE4IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTc1ODc3Mjk4MzAwMDAtMDAxOC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTc1ODc3Mjk4MzAwMDAtMDAxOC9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC03NTg3NzI5ODMwMDAwLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC03NTg3NzI5ODMwMDAwLTAwMTgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC03NTg3NzI5ODMwMDAwLTAwMTgvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNzU4NzcyOTgzMDAwMC0wMDE4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0xOFQwMjowODo1NC4wOTRaIn0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS01MTgzMzUwOTM2MDAwLTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTUxODMzNTA5MzYwMDAtMDAxNyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTUxODMzNTA5MzYwMDAtMDAxNyIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0xOVQwMToyOToxMC45OTJaIiwidXBkYXRlZCI6IjIwMTgtMDktMTlUMDE6Mjk6MTMuMDUzWiIsIm1ldGFnZW5lcmF0aW9uIjoiMiIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS01MTgzMzUwOTM2MDAwLTAwMTcvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTUxODMzNTA5MzYwMDAtMDAxNy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTUxODMzNTA5MzYwMDAtMDAxNyIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS01MTgzMzUwOTM2MDAwLTAwMTcvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS01MTgzMzUwOTM2MDAwLTAwMTcvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNTE4MzM1MDkzNjAwMC0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNTE4MzM1MDkzNjAwMC0wMDE3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNTE4MzM1MDkzNjAwMC0wMDE3L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTUxODMzNTA5MzYwMDAtMDAxNyIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FJPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSJ9LCJsb2NhdGlvbiI6IlVTIiwicmV0ZW50aW9uUG9saWN5Ijp7InJldGVudGlvblBlcmlvZCI6IjkwMDAwIiwiZWZmZWN0aXZlVGltZSI6IjIwMTgtMDktMTlUMDE6Mjk6MTAuOTkyWiIsImlzTG9ja2VkIjp0cnVlfSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTUxODMzNTA5MzYwMDAtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNTE4MzM1MDkzNjAwMC0wMDE4IiwicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNTE4MzM1MDkzNjAwMC0wMDE4IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTE5VDAxOjI5OjE1LjUwMloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0xOVQwMToyOToxNS41MDJaIiwibWV0YWdlbmVyYXRpb24iOiIxIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTUxODMzNTA5MzYwMDAtMDAxOC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNTE4MzM1MDkzNjAwMC0wMDE4L2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNTE4MzM1MDkzNjAwMC0wMDE4IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTUxODMzNTA5MzYwMDAtMDAxOC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTUxODMzNTA5MzYwMDAtMDAxOC9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS01MTgzMzUwOTM2MDAwLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS01MTgzMzUwOTM2MDAwLTAwMTgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS01MTgzMzUwOTM2MDAwLTAwMTgvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNTE4MzM1MDkzNjAwMC0wMDE4IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0xOVQwMToyOToxNS41MDJaIn0sInN0b3JhZ2VDbGFzcyI6IlNUQU5EQVJEIiwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS03NDI0NjMxNjM4ODAwMC0wMDAxIiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS03NDI0NjMxNjM4ODAwMC0wMDAxIiwicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwibmFtZSI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNzQyNDYzMTYzODgwMDAtMDAwMSIsInRpbWVDcmVhdGVkIjoiMjAxOC0wOS0xOVQyMDozNzoyOC4wODVaIiwidXBkYXRlZCI6IjIwMTgtMDktMTlUMjA6Mzc6MjguMDg1WiIsIm1ldGFnZW5lcmF0aW9uIjoiMSIsImFjbCI6W3sia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS03NDI0NjMxNjM4ODAwMC0wMDAxL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS03NDI0NjMxNjM4ODAwMC0wMDAxL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNzQyNDYzMTYzODgwMDAtMDAwMSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS03NDI0NjMxNjM4ODAwMC0wMDAxL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNzQyNDYzMTYzODgwMDAtMDAwMS9hY2wvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS03NDI0NjMxNjM4ODAwMC0wMDAxIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNzQyNDYzMTYzODgwMDAtMDAwMS9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTc0MjQ2MzE2Mzg4MDAwLTAwMDEvYWNsL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNzQyNDYzMTYzODgwMDAtMDAwMSIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwiZGVmYXVsdE9iamVjdEFjbCI6W3sia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUU9In1dLCJvd25lciI6eyJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSJ9LCJsb2NhdGlvbiI6IlVTIiwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTc0MjQ2MzE2Mzg4MDAwLTAwMDIiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTc0MjQ2MzE2Mzg4MDAwLTAwMDIiLCJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS03NDI0NjMxNjM4ODAwMC0wMDAyIiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTE5VDIwOjM3OjI5LjM4NFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0xOVQyMDozNzozMi41NzdaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTc0MjQ2MzE2Mzg4MDAwLTAwMDIvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTc0MjQ2MzE2Mzg4MDAwLTAwMDIvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS03NDI0NjMxNjM4ODAwMC0wMDAyIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTc0MjQ2MzE2Mzg4MDAwLTAwMDIvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS03NDI0NjMxNjM4ODAwMC0wMDAyL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTc0MjQ2MzE2Mzg4MDAwLTAwMDIiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS03NDI0NjMxNjM4ODAwMC0wMDAyL3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNzQyNDYzMTYzODgwMDAtMDAwMi9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS03NDI0NjMxNjM4ODAwMC0wMDAyIiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0xOVQyMDozNzoyOS4zODRaIiwiaXNMb2NrZWQiOnRydWV9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNzQyNDYzMTYzODgwMDAtMDAwMyIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNzQyNDYzMTYzODgwMDAtMDAwMyIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTc0MjQ2MzE2Mzg4MDAwLTAwMDMiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMTlUMjA6Mzc6MzYuMzg1WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTE5VDIwOjM3OjM2LjM4NVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNzQyNDYzMTYzODgwMDAtMDAwMy9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNzQyNDYzMTYzODgwMDAtMDAwMy9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTc0MjQ2MzE2Mzg4MDAwLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNzQyNDYzMTYzODgwMDAtMDAwMy9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTc0MjQ2MzE2Mzg4MDAwLTAwMDMvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktNzQyNDYzMTYzODgwMDAtMDAwMyIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTc0MjQ2MzE2Mzg4MDAwLTAwMDMvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS03NDI0NjMxNjM4ODAwMC0wMDAzL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTc0MjQ2MzE2Mzg4MDAwLTAwMDMiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE4LTA5LTE5VDIwOjM3OjM2LjM4NVoifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTgwMDg2MTI0OTA4MDAwLTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTgwMDg2MTI0OTA4MDAwLTAwMTciLCJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS04MDA4NjEyNDkwODAwMC0wMDE3IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTE5VDIyOjE3OjExLjc5MFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0xOVQyMjoxNzoxMy40NDZaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTgwMDg2MTI0OTA4MDAwLTAwMTcvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTgwMDg2MTI0OTA4MDAwLTAwMTcvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS04MDA4NjEyNDkwODAwMC0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTgwMDg2MTI0OTA4MDAwLTAwMTcvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS04MDA4NjEyNDkwODAwMC0wMDE3L2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTgwMDg2MTI0OTA4MDAwLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS04MDA4NjEyNDkwODAwMC0wMDE3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktODAwODYxMjQ5MDgwMDAtMDAxNy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS04MDA4NjEyNDkwODAwMC0wMDE3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0xOVQyMjoxNzoxMS43OTBaIiwiaXNMb2NrZWQiOnRydWV9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktODAwODYxMjQ5MDgwMDAtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktODAwODYxMjQ5MDgwMDAtMDAxOCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTgwMDg2MTI0OTA4MDAwLTAwMTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMTlUMjI6MTc6MTUuNDkzWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTE5VDIyOjE3OjE1LjQ5M1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktODAwODYxMjQ5MDgwMDAtMDAxOC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktODAwODYxMjQ5MDgwMDAtMDAxOC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTgwMDg2MTI0OTA4MDAwLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktODAwODYxMjQ5MDgwMDAtMDAxOC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTgwMDg2MTI0OTA4MDAwLTAwMTgvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTktODAwODYxMjQ5MDgwMDAtMDAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTgwMDg2MTI0OTA4MDAwLTAwMTgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOS04MDA4NjEyNDkwODAwMC0wMDE4L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE5LTgwMDg2MTI0OTA4MDAwLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE4LTA5LTE5VDIyOjE3OjE1LjQ5M1oifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTUzMzQ2MjQyMDU2NTQxLTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTUzMzQ2MjQyMDU2NTQxLTAwMTciLCJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01MzM0NjI0MjA1NjU0MS0wMDE3IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTIwVDE0OjUyOjQ1LjU4NloiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yMFQxNDo1Mjo0OC4xMjJaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTUzMzQ2MjQyMDU2NTQxLTAwMTcvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTUzMzQ2MjQyMDU2NTQxLTAwMTcvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01MzM0NjI0MjA1NjU0MS0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTUzMzQ2MjQyMDU2NTQxLTAwMTcvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01MzM0NjI0MjA1NjU0MS0wMDE3L2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTUzMzQ2MjQyMDU2NTQxLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01MzM0NjI0MjA1NjU0MS0wMDE3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTMzNDYyNDIwNTY1NDEtMDAxNy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01MzM0NjI0MjA1NjU0MS0wMDE3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0yMFQxNDo1Mjo0NS41ODZaIiwiaXNMb2NrZWQiOnRydWV9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTMzNDYyNDIwNTY1NDEtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTMzNDYyNDIwNTY1NDEtMDAxOCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTUzMzQ2MjQyMDU2NTQxLTAwMTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjBUMTQ6NTI6NTEuNjQ5WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTIwVDE0OjUyOjUxLjY0OVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTMzNDYyNDIwNTY1NDEtMDAxOC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTMzNDYyNDIwNTY1NDEtMDAxOC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTUzMzQ2MjQyMDU2NTQxLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTMzNDYyNDIwNTY1NDEtMDAxOC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTUzMzQ2MjQyMDU2NTQxLTAwMTgvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTMzNDYyNDIwNTY1NDEtMDAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTUzMzQ2MjQyMDU2NTQxLTAwMTgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01MzM0NjI0MjA1NjU0MS0wMDE4L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTUzMzQ2MjQyMDU2NTQxLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE4LTA5LTIwVDE0OjUyOjUxLjY0OVoifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0MDE5NjI4NDM5MDIyLTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0MDE5NjI4NDM5MDIyLTAwMTciLCJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NDAxOTYyODQzOTAyMi0wMDE3IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTIwVDE1OjAyOjQ2LjE3MFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yMFQxNTowMjo0OC40NDFaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0MDE5NjI4NDM5MDIyLTAwMTcvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0MDE5NjI4NDM5MDIyLTAwMTcvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NDAxOTYyODQzOTAyMi0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0MDE5NjI4NDM5MDIyLTAwMTcvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NDAxOTYyODQzOTAyMi0wMDE3L2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0MDE5NjI4NDM5MDIyLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NDAxOTYyODQzOTAyMi0wMDE3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQwMTk2Mjg0MzkwMjItMDAxNy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NDAxOTYyODQzOTAyMi0wMDE3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0yMFQxNTowMjo0Ni4xNzBaIiwiaXNMb2NrZWQiOnRydWV9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQwMTk2Mjg0MzkwMjItMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQwMTk2Mjg0MzkwMjItMDAxOCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0MDE5NjI4NDM5MDIyLTAwMTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjBUMTU6MDI6NTEuMDg3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTIwVDE1OjAyOjUxLjA4N1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQwMTk2Mjg0MzkwMjItMDAxOC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQwMTk2Mjg0MzkwMjItMDAxOC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0MDE5NjI4NDM5MDIyLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQwMTk2Mjg0MzkwMjItMDAxOC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0MDE5NjI4NDM5MDIyLTAwMTgvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQwMTk2Mjg0MzkwMjItMDAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0MDE5NjI4NDM5MDIyLTAwMTgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NDAxOTYyODQzOTAyMi0wMDE4L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0MDE5NjI4NDM5MDIyLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE4LTA5LTIwVDE1OjAyOjUxLjA4N1oifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0NzE1NjE3NzI2NzAyLTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0NzE1NjE3NzI2NzAyLTAwMTciLCJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NDcxNTYxNzcyNjcwMi0wMDE3IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTIwVDE1OjE0OjI2Ljk1NVoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yMFQxNToxNDoyOS4xMjZaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0NzE1NjE3NzI2NzAyLTAwMTcvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0NzE1NjE3NzI2NzAyLTAwMTcvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NDcxNTYxNzcyNjcwMi0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0NzE1NjE3NzI2NzAyLTAwMTcvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NDcxNTYxNzcyNjcwMi0wMDE3L2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0NzE1NjE3NzI2NzAyLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NDcxNTYxNzcyNjcwMi0wMDE3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQ3MTU2MTc3MjY3MDItMDAxNy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NDcxNTYxNzcyNjcwMi0wMDE3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0yMFQxNToxNDoyNi45NTVaIiwiaXNMb2NrZWQiOnRydWV9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQ3MTU2MTc3MjY3MDItMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQ3MTU2MTc3MjY3MDItMDAxOCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0NzE1NjE3NzI2NzAyLTAwMTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjBUMTU6MTQ6MzEuNjAxWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTIwVDE1OjE0OjMxLjYwMVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQ3MTU2MTc3MjY3MDItMDAxOC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQ3MTU2MTc3MjY3MDItMDAxOC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0NzE1NjE3NzI2NzAyLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQ3MTU2MTc3MjY3MDItMDAxOC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0NzE1NjE3NzI2NzAyLTAwMTgvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTQ3MTU2MTc3MjY3MDItMDAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0NzE1NjE3NzI2NzAyLTAwMTgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NDcxNTYxNzcyNjcwMi0wMDE4L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU0NzE1NjE3NzI2NzAyLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE4LTA5LTIwVDE1OjE0OjMxLjYwMVoifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1MzkxMTkyMjU2ODk2LTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1MzkxMTkyMjU2ODk2LTAwMTciLCJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NTM5MTE5MjI1Njg5Ni0wMDE3IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTIwVDE1OjI1OjMyLjk4N1oiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yMFQxNToyNTozNC44MzRaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1MzkxMTkyMjU2ODk2LTAwMTcvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1MzkxMTkyMjU2ODk2LTAwMTcvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NTM5MTE5MjI1Njg5Ni0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1MzkxMTkyMjU2ODk2LTAwMTcvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NTM5MTE5MjI1Njg5Ni0wMDE3L2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1MzkxMTkyMjU2ODk2LTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NTM5MTE5MjI1Njg5Ni0wMDE3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTUzOTExOTIyNTY4OTYtMDAxNy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NTM5MTE5MjI1Njg5Ni0wMDE3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0yMFQxNToyNTozMi45ODdaIiwiaXNMb2NrZWQiOnRydWV9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTUzOTExOTIyNTY4OTYtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTUzOTExOTIyNTY4OTYtMDAxOCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1MzkxMTkyMjU2ODk2LTAwMTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjBUMTU6MjU6MzcuMzU3WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTIwVDE1OjI1OjM3LjM1N1oiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTUzOTExOTIyNTY4OTYtMDAxOC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTUzOTExOTIyNTY4OTYtMDAxOC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1MzkxMTkyMjU2ODk2LTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTUzOTExOTIyNTY4OTYtMDAxOC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1MzkxMTkyMjU2ODk2LTAwMTgvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTUzOTExOTIyNTY4OTYtMDAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1MzkxMTkyMjU2ODk2LTAwMTgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NTM5MTE5MjI1Njg5Ni0wMDE4L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1MzkxMTkyMjU2ODk2LTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE4LTA5LTIwVDE1OjI1OjM3LjM1N1oifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1OTkzMDU4NzAzNTE2LTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1OTkzMDU4NzAzNTE2LTAwMTciLCJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NTk5MzA1ODcwMzUxNi0wMDE3IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTIwVDE1OjM1OjM4LjYwN1oiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yMFQxNTozNTo0MC43MzVaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1OTkzMDU4NzAzNTE2LTAwMTcvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1OTkzMDU4NzAzNTE2LTAwMTcvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NTk5MzA1ODcwMzUxNi0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1OTkzMDU4NzAzNTE2LTAwMTcvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NTk5MzA1ODcwMzUxNi0wMDE3L2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1OTkzMDU4NzAzNTE2LTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NTk5MzA1ODcwMzUxNi0wMDE3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTU5OTMwNTg3MDM1MTYtMDAxNy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NTk5MzA1ODcwMzUxNi0wMDE3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0yMFQxNTozNTozOC42MDdaIiwiaXNMb2NrZWQiOnRydWV9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTU5OTMwNTg3MDM1MTYtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTU5OTMwNTg3MDM1MTYtMDAxOCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1OTkzMDU4NzAzNTE2LTAwMTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjBUMTU6MzU6NDMuNDY2WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTIwVDE1OjM1OjQzLjQ2NloiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTU5OTMwNTg3MDM1MTYtMDAxOC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTU5OTMwNTg3MDM1MTYtMDAxOC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1OTkzMDU4NzAzNTE2LTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTU5OTMwNTg3MDM1MTYtMDAxOC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1OTkzMDU4NzAzNTE2LTAwMTgvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTU5OTMwNTg3MDM1MTYtMDAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1OTkzMDU4NzAzNTE2LTAwMTgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01NTk5MzA1ODcwMzUxNi0wMDE4L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU1OTkzMDU4NzAzNTE2LTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE4LTA5LTIwVDE1OjM1OjQzLjQ2NloifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU2OTY2NzE5NzUxMjQzLTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU2OTY2NzE5NzUxMjQzLTAwMTciLCJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01Njk2NjcxOTc1MTI0My0wMDE3IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTIwVDE1OjUxOjUzLjQwMFoiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yMFQxNTo1MTo1NS4zMjRaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU2OTY2NzE5NzUxMjQzLTAwMTcvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU2OTY2NzE5NzUxMjQzLTAwMTcvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01Njk2NjcxOTc1MTI0My0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU2OTY2NzE5NzUxMjQzLTAwMTcvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01Njk2NjcxOTc1MTI0My0wMDE3L2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU2OTY2NzE5NzUxMjQzLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01Njk2NjcxOTc1MTI0My0wMDE3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTY5NjY3MTk3NTEyNDMtMDAxNy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01Njk2NjcxOTc1MTI0My0wMDE3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0yMFQxNTo1MTo1My40MDBaIiwiaXNMb2NrZWQiOnRydWV9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTY5NjY3MTk3NTEyNDMtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTY5NjY3MTk3NTEyNDMtMDAxOCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU2OTY2NzE5NzUxMjQzLTAwMTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjBUMTU6NTE6NTcuODAwWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTIwVDE1OjUxOjU3LjgwMFoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTY5NjY3MTk3NTEyNDMtMDAxOC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTY5NjY3MTk3NTEyNDMtMDAxOC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU2OTY2NzE5NzUxMjQzLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTY5NjY3MTk3NTEyNDMtMDAxOC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU2OTY2NzE5NzUxMjQzLTAwMTgvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjAtNTY5NjY3MTk3NTEyNDMtMDAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU2OTY2NzE5NzUxMjQzLTAwMTgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyMC01Njk2NjcxOTc1MTI0My0wMDE4L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTIwLTU2OTY2NzE5NzUxMjQzLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE4LTA5LTIwVDE1OjUxOjU3LjgwMFoifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0IiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTciLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTciLCJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJuYW1lIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE3IiwidGltZUNyZWF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjEzLjg4N1oiLCJ1cGRhdGVkIjoiMjAxOC0wOS0yN1QxMjoyNjoxNS45MzZaIiwibWV0YWdlbmVyYXRpb24iOiIyIiwiYWNsIjpbeyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTcvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTcvYWNsL3Byb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE3IiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTcvcHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE3L2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTciLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FJPSJ9LHsia2luZCI6InN0b3JhZ2UjYnVja2V0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE3L3Byb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxNy9hY2wvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1IiwiYnVja2V0IjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE3IiwiZW50aXR5IjoicHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6IlJFQURFUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJ2aWV3ZXJzIn0sImV0YWciOiJDQUk9In1dLCJkZWZhdWx0T2JqZWN0QWNsIjpbeyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoib3duZXJzIn0sImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNvYmplY3RBY2Nlc3NDb250cm9sIiwiZW50aXR5IjoicHJvamVjdC1lZGl0b3JzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6ImVkaXRvcnMifSwiZXRhZyI6IkNBST0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBST0ifV0sIm93bmVyIjp7ImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1In0sImxvY2F0aW9uIjoiVVMiLCJyZXRlbnRpb25Qb2xpY3kiOnsicmV0ZW50aW9uUGVyaW9kIjoiOTAwMDAiLCJlZmZlY3RpdmVUaW1lIjoiMjAxOC0wOS0yN1QxMjoyNjoxMy44ODdaIiwiaXNMb2NrZWQiOnRydWV9LCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsImV0YWciOiJDQUk9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXQiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOCIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOCIsInByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsIm5hbWUiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTgiLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMjdUMTI6MjY6MTguMjU5WiIsInVwZGF0ZWQiOiIyMDE4LTA5LTI3VDEyOjI2OjE4LjI1OVoiLCJtZXRhZ2VuZXJhdGlvbiI6IjEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOC9hY2wvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI2J1Y2tldEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTgvYWNsL3Byb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MjctNDQ2MzA5MTE4NjM2NDAtMDAxOCIsImVudGl0eSI6InByb2plY3QtZWRpdG9ycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJlZGl0b3JzIn0sImV0YWciOiJDQUU9In0seyJraW5kIjoic3RvcmFnZSNidWNrZXRBY2Nlc3NDb250cm9sIiwiaWQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTgvcHJvamVjdC12aWV3ZXJzLTM2NjM5OTMzMTQ1Iiwic2VsZkxpbmsiOiJodHRwczovL3d3dy5nb29nbGVhcGlzLmNvbS9zdG9yYWdlL3YxL2IvZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkyNy00NDYzMDkxMTg2MzY0MC0wMDE4L2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTI3LTQ0NjMwOTExODYzNjQwLTAwMTgiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNBRT0ifV0sImRlZmF1bHRPYmplY3RBY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJPV05FUiIsInByb2plY3RUZWFtIjp7InByb2plY3ROdW1iZXIiOiIzNjYzOTkzMzE0NSIsInRlYW0iOiJvd25lcnMifSwiZXRhZyI6IkNBRT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0FFPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImVudGl0eSI6InByb2plY3Qtdmlld2Vycy0zNjYzOTkzMzE0NSIsInJvbGUiOiJSRUFERVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoidmlld2VycyJ9LCJldGFnIjoiQ0FFPSJ9XSwib3duZXIiOnsiZW50aXR5IjoicHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUifSwibG9jYXRpb24iOiJVUyIsInJldGVudGlvblBvbGljeSI6eyJyZXRlbnRpb25QZXJpb2QiOiI5MDAwMCIsImVmZmVjdGl2ZVRpbWUiOiIyMDE4LTA5LTI3VDEyOjI2OjE4LjI1OVoifSwic3RvcmFnZUNsYXNzIjoiU1RBTkRBUkQiLCJldGFnIjoiQ0FFPSJ9XX0=" + } + }, + { + "ID": "a4e69be0e239962d", + "Request": { + "Method": "GET", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180918-4131767318000-0002/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=\u0026prettyPrint=false\u0026projection=full\u0026versions=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "882c02022466c15c2d708f6ccc043bea/11684338459922450634;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180918-4131767318000-0002/o?alt=json\u0026delimiter=\u0026pageToken=\u0026prefix=\u0026prettyPrint=false\u0026projection=full\u0026versions=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 200, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0, must-revalidate, no-transform" + ], + "Content-Length": [ + "3307" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:50 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:50 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051503000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.read_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vlfx126:4091,/bns/yk/borg/yk/bns/blobstore2/bitpusher/559.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=icysW_ORN8GDqQW4zYjQAw" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/559.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/559:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4itK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "success" + ], + "X-Guploader-Upload-Result": [ + "success" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpwEgzCXs8iMGXWCPB6Hq6LFaljM5D8sntRbfhs9lY4TSkWGfDHHRzPddyJVjVzaDcLNy8fYOr07OgVIElY_eNXzVUR9Q" + ] + }, + "Body": "eyJraW5kIjoic3RvcmFnZSNvYmplY3RzIiwiaXRlbXMiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00MTMxNzY3MzE4MDAwLTAwMDIvc29tZS1vYmovMTUzNzIzMjkzMzc2Mjk1NSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDEzMTc2NzMxODAwMC0wMDAyL28vc29tZS1vYmoiLCJuYW1lIjoic29tZS1vYmoiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMiIsImdlbmVyYXRpb24iOiIxNTM3MjMyOTMzNzYyOTU1IiwibWV0YWdlbmVyYXRpb24iOiIzIiwiY29udGVudFR5cGUiOiJmb28iLCJ0aW1lQ3JlYXRlZCI6IjIwMTgtMDktMThUMDE6MDg6NTMuNzYyWiIsInVwZGF0ZWQiOiIyMDE4LTA5LTE4VDAxOjA4OjU0LjU5MloiLCJzdG9yYWdlQ2xhc3MiOiJTVEFOREFSRCIsInRpbWVTdG9yYWdlQ2xhc3NVcGRhdGVkIjoiMjAxOC0wOS0xOFQwMTowODo1My43NjJaIiwic2l6ZSI6IjE2IiwibWQ1SGFzaCI6InJWZ0NOcVVrd1JpV3pDOUtvNUlIanc9PSIsIm1lZGlhTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2Rvd25sb2FkL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMi9vL3NvbWUtb2JqP2dlbmVyYXRpb249MTUzNzIzMjkzMzc2Mjk1NSZhbHQ9bWVkaWEiLCJhY2wiOlt7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDEzMTc2NzMxODAwMC0wMDAyL3NvbWUtb2JqLzE1MzcyMzI5MzM3NjI5NTUvcHJvamVjdC1vd25lcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMi9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LW93bmVycy0zNjYzOTkzMzE0NSIsImJ1Y2tldCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDEzMTc2NzMxODAwMC0wMDAyIiwib2JqZWN0Ijoic29tZS1vYmoiLCJnZW5lcmF0aW9uIjoiMTUzNzIzMjkzMzc2Mjk1NSIsImVudGl0eSI6InByb2plY3Qtb3duZXJzLTM2NjM5OTMzMTQ1Iiwicm9sZSI6Ik9XTkVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6Im93bmVycyJ9LCJldGFnIjoiQ0l2djBQZXV3OTBDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00MTMxNzY3MzE4MDAwLTAwMDIvc29tZS1vYmovMTUzNzIzMjkzMzc2Mjk1NS9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMi9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMiIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1MzcyMzI5MzM3NjI5NTUiLCJlbnRpdHkiOiJwcm9qZWN0LWVkaXRvcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiT1dORVIiLCJwcm9qZWN0VGVhbSI6eyJwcm9qZWN0TnVtYmVyIjoiMzY2Mzk5MzMxNDUiLCJ0ZWFtIjoiZWRpdG9ycyJ9LCJldGFnIjoiQ0l2djBQZXV3OTBDRUFNPSJ9LHsia2luZCI6InN0b3JhZ2Ujb2JqZWN0QWNjZXNzQ29udHJvbCIsImlkIjoiZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00MTMxNzY3MzE4MDAwLTAwMDIvc29tZS1vYmovMTUzNzIzMjkzMzc2Mjk1NS9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJzZWxmTGluayI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3N0b3JhZ2UvdjEvYi9nby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMi9vL3NvbWUtb2JqL2FjbC9wcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMiIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1MzcyMzI5MzM3NjI5NTUiLCJlbnRpdHkiOiJwcm9qZWN0LXZpZXdlcnMtMzY2Mzk5MzMxNDUiLCJyb2xlIjoiUkVBREVSIiwicHJvamVjdFRlYW0iOnsicHJvamVjdE51bWJlciI6IjM2NjM5OTMzMTQ1IiwidGVhbSI6InZpZXdlcnMifSwiZXRhZyI6IkNJdnYwUGV1dzkwQ0VBTT0ifSx7ImtpbmQiOiJzdG9yYWdlI29iamVjdEFjY2Vzc0NvbnRyb2wiLCJpZCI6ImdvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDEzMTc2NzMxODAwMC0wMDAyL3NvbWUtb2JqLzE1MzcyMzI5MzM3NjI5NTUvdXNlci0zNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNlbGZMaW5rIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vc3RvcmFnZS92MS9iL2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDEzMTc2NzMxODAwMC0wMDAyL28vc29tZS1vYmovYWNsL3VzZXItMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJidWNrZXQiOiJnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMiIsIm9iamVjdCI6InNvbWUtb2JqIiwiZ2VuZXJhdGlvbiI6IjE1MzcyMzI5MzM3NjI5NTUiLCJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwicm9sZSI6Ik9XTkVSIiwiZW1haWwiOiIzNjYzOTkzMzE0NS1iMTh0MDFvbXQ5YTI3OWtjM2djZ2lxaHFrbDhib2JodUBkZXZlbG9wZXIuZ3NlcnZpY2VhY2NvdW50LmNvbSIsImV0YWciOiJDSXZ2MFBldXc5MENFQU09In1dLCJvd25lciI6eyJlbnRpdHkiOiJ1c2VyLTM2NjM5OTMzMTQ1LWIxOHQwMW9tdDlhMjc5a2MzZ2NnaXFocWtsOGJvYmh1QGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIn0sImNyYzMyYyI6ImdTSjJJUT09IiwiZXRhZyI6IkNJdnYwUGV1dzkwQ0VBTT0iLCJldmVudEJhc2VkSG9sZCI6dHJ1ZX1dfQ==" + } + }, + { + "ID": "cf09ae4a1ba8491f", + "Request": { + "Method": "DELETE", + "URL": "https://www.googleapis.com/storage/v1/b/go-integration-test-20180918-4131767318000-0002/o/some-obj?alt=json\u0026prettyPrint=false", + "Proto": "HTTP/1.1", + "Header": { + "Accept-Encoding": [ + "gzip" + ], + "Authorization": [ + "REDACTED" + ], + "User-Agent": [ + "google-api-go-client/0.5" + ], + "Via": [ + "1.1 httpr-f4507be84cc405ed397a" + ], + "X-Cloud-Trace-Context": [ + "d45c92e9f8b203c29533eacb69213e0a/12515712295073552922;o=1" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Forwarded-Host": [ + "www.googleapis.com" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Forwarded-Url": [ + "https://www.googleapis.com/storage/v1/b/go-integration-test-20180918-4131767318000-0002/o/some-obj?alt=json\u0026prettyPrint=false" + ], + "X-Goog-Api-Client": [ + "gl-go/1.11.0-rc2 gccl/20180226" + ] + }, + "Body": "" + }, + "Response": { + "StatusCode": 403, + "Proto": "HTTP/1.1", + "ProtoMajor": 1, + "ProtoMinor": 1, + "Header": { + "Alt-Svc": [ + "quic=\":443\"; ma=2592000; v=\"44,43,39,35\"" + ], + "Cache-Control": [ + "private, max-age=0" + ], + "Content-Length": [ + "13398" + ], + "Content-Type": [ + "application/json; charset=UTF-8" + ], + "Date": [ + "Thu, 27 Sep 2018 12:26:50 GMT" + ], + "Expires": [ + "Thu, 27 Sep 2018 12:26:50 GMT" + ], + "Server": [ + "UploadServer" + ], + "Vary": [ + "Origin", + "X-Origin" + ], + "X-Google-Apiary-Auth-Expires": [ + "1538051504000" + ], + "X-Google-Apiary-Auth-Scopes": [ + "https://www.googleapis.com/auth/devstorage.full_control https://www.googleapis.com/auth/devstorage.read_write https://www.googleapis.com/auth/devstorage.write_only" + ], + "X-Google-Apiary-Auth-User": [ + "998958384336" + ], + "X-Google-Backends": [ + "vlhl7:4477,/bns/yk/borg/yk/bns/blobstore2/bitpusher/202.scotty,acatlm7:443" + ], + "X-Google-Dos-Service-Trace": [ + "main:apps-upload-cloud-storage-unified" + ], + "X-Google-Gfe-Backend-Request-Info": [ + "eid=isysW_KtDZPlqAXbqbOADw" + ], + "X-Google-Gfe-Request-Trace": [ + "acatlm7:443,/bns/yk/borg/yk/bns/blobstore2/bitpusher/202.scotty,acatlm7:443" + ], + "X-Google-Gfe-Response-Code-Details-Trace": [ + "response_code_set_by_backend" + ], + "X-Google-Gfe-Service-Trace": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Netmon-Label": [ + "/bns/yk/borg/yk/bns/blobstore2/bitpusher/202:caf3" + ], + "X-Google-Service": [ + "bitpusher-gcs-apiary" + ], + "X-Google-Session-Info": [ + "CNCJvbSJHRoCGAYoATp3ChJjbG91ZC1zdG9yYWdlLXJvc3kSCGJpZ3N0b3JlGNmFpL-IASJHMzY2Mzk5MzMxNDUtYjE4dDAxb210OWEyNzlrYzNnY2dpcWhxa2w4Ym9iaHUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20w4Csw4Ssw4ytK4wESxgF5YTI5LmMuRW93QkpRWU94SDhBWjdSeWVHSm16OFFSZV80RWc4RjdJOUFYemxhX1lqdU1TYkM3YkFFZ2hZY3JuVmR3ckppdUNMWlQyUXNhUWFlV01xeW1EbmRlY3EySHQ5b0ZjQmtGZDA5bk9yZTl4T3Q1Q081RXpHVkNNMGxQQjdneUR4Nm9iMWJFUlZqVTJ0QTJMX0tzMnhZZkRTaEU2cFhlTlpEMzR3Z3lJbUZXQjBUTVU0eDNvLTVFVG5Wa2VpSW9rR00wBDoWTk9UX0FfUEVSU0lTVEVOVF9UT0tFTg" + ], + "X-Google-Shellfish-Status": [ + "CA0gBEBG" + ], + "X-Guploader-Customer": [ + "apiary_cloudstorage_metadata" + ], + "X-Guploader-Request-Result": [ + "agent_rejected" + ], + "X-Guploader-Upload-Result": [ + "agent_rejected" + ], + "X-Guploader-Uploadid": [ + "AEnB2UpxwthGRvjv9oE6KLGMR2nM0RaOpyc3u06tE-6RseFdQnMw_wlaHX9a2iR7Z8UF6e5pAUkE-2-kKutOohrLN7o6-JFZgw" + ] + }, + "Body": "eyJlcnJvciI6eyJlcnJvcnMiOlt7ImRvbWFpbiI6Imdsb2JhbCIsInJlYXNvbiI6ImZvcmJpZGRlbiIsIm1lc3NhZ2UiOiJPYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDEzMTc2NzMxODAwMC0wMDAyL3NvbWUtb2JqJyBpcyB1bmRlciBhY3RpdmUgRXZlbnQtQmFzZWQgaG9sZCBhbmQgY2Fubm90IGJlIGRlbGV0ZWQsIG92ZXJ3cml0dGVuIG9yIGFyY2hpdmVkIHVudGlsIGhvbGQgaXMgcmVtb3ZlZC4iLCJkZWJ1Z0luZm8iOiJjb20uZ29vZ2xlLm5ldC5ycGMzLlJwY0V4Y2VwdGlvbjogY2xvdWQuYmlnc3RvcmUuUmVzcG9uc2VDb2RlLkVycm9yQ29kZTo6T0JKRUNUX0lTX1VOREVSX0FDVElWRV9IT0xEOiBPYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDEzMTc2NzMxODAwMC0wMDAyL3NvbWUtb2JqJyBpcyB1bmRlciBhY3RpdmUgRXZlbnQtQmFzZWQgaG9sZCBhbmQgY2Fubm90IGJlIGRlbGV0ZWQsIG92ZXJ3cml0dGVuIG9yIGFyY2hpdmVkIHVudGlsIGhvbGQgaXMgcmVtb3ZlZC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udG9ScGMzRXhjZXB0aW9uKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MTM1KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YTo3Nylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6MjMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uZnJhbWV3b3JrLlJlcXVlc3RIYW5kbGVyLmhhbmRsZShSZXF1ZXN0SGFuZGxlci5qYXZhOjI5NClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5PYmplY3RzRGVsZWdhdG9yLmRlbGV0ZShPYmplY3RzRGVsZWdhdG9yLmphdmE6MTEzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5ScGNSZWNlaXZlci5sYW1iZGEkcHJvY2Vzc1JlcXVlc3RBc3luYyQ0KFJwY1JlY2VpdmVyLmphdmE6MjAzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmlzb2xhdGlvbi5Bc3luY0V4ZWN1dG9yLmxhbWJkYSRzdWJtaXQkMChBc3luY0V4ZWN1dG9yLmphdmE6MjcyKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW5JbkNvbnRleHQoQ29udGV4dFJ1bm5hYmxlLmphdmE6NTApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlJDEucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM5KVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuQ3VycmVudENvbnRleHQucnVuSW5Db250ZXh0KEN1cnJlbnRDb250ZXh0LmphdmE6MzIwKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo3Milcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0KEdlbmVyaWNDb250ZXh0Q2FsbGJhY2suamF2YTo2NClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuKENvbnRleHRSdW5uYWJsZS5qYXZhOjM2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5FeGVjdXRvcnMkUnVubmFibGVBZGFwdGVyLmNhbGwoRXhlY3V0b3JzLmphdmE6NTExKVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5GdXR1cmVUYXNrLnJ1bihGdXR1cmVUYXNrLmphdmE6MjY2KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IucnVuV29ya2VyKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjExNDkpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvciRXb3JrZXIucnVuKFRocmVhZFBvb2xFeGVjdXRvci5qYXZhOjYyNClcblx0YXQgamF2YS5sYW5nLlRocmVhZC5ydW4oVGhyZWFkLmphdmE6NzQ4KVxuQ2F1c2VkIGJ5OiBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbjogT2JqZWN0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMi9zb21lLW9iaicgaXMgdW5kZXIgYWN0aXZlIEV2ZW50LUJhc2VkIGhvbGQgYW5kIGNhbm5vdCBiZSBkZWxldGVkLCBvdmVyd3JpdHRlbiBvciBhcmNoaXZlZCB1bnRpbCBob2xkIGlzIHJlbW92ZWQuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93T25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjI5MClcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMSlcblx0Li4uIDE3IG1vcmVcblxuY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRmF1bHQ6IEltbXV0YWJsZUVycm9yRGVmaW5pdGlvbntiYXNlPUZPUkJJRERFTiwgY2F0ZWdvcnk9VVNFUl9FUlJPUiwgY2F1c2U9bnVsbCwgZGVidWdJbmZvPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfSVNfVU5ERVJfQUNUSVZFX0hPTEQ6IE9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00MTMxNzY3MzE4MDAwLTAwMDIvc29tZS1vYmonIGlzIHVuZGVyIGFjdGl2ZSBFdmVudC1CYXNlZCBob2xkIGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgaG9sZCBpcyByZW1vdmVkLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjc3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBPYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDEzMTc2NzMxODAwMC0wMDAyL3NvbWUtb2JqJyBpcyB1bmRlciBhY3RpdmUgRXZlbnQtQmFzZWQgaG9sZCBhbmQgY2Fubm90IGJlIGRlbGV0ZWQsIG92ZXJ3cml0dGVuIG9yIGFyY2hpdmVkIHVudGlsIGhvbGQgaXMgcmVtb3ZlZC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBkb21haW49Z2xvYmFsLCBleHRlbmRlZEhlbHA9bnVsbCwgaHR0cEhlYWRlcnM9e30sIGh0dHBTdGF0dXM9Zm9yYmlkZGVuLCBpbnRlcm5hbFJlYXNvbj1SZWFzb257YXJndW1lbnRzPXt9LCBjYXVzZT1udWxsLCBjb2RlPWdkYXRhLkNvcmVFcnJvckRvbWFpbi5GT1JCSURERU4sIGNyZWF0ZWRCeUJhY2tlbmQ9dHJ1ZSwgZGVidWdNZXNzYWdlPWNvbS5nb29nbGUubmV0LnJwYzMuUnBjRXhjZXB0aW9uOiBjbG91ZC5iaWdzdG9yZS5SZXNwb25zZUNvZGUuRXJyb3JDb2RlOjpPQkpFQ1RfSVNfVU5ERVJfQUNUSVZFX0hPTEQ6IE9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00MTMxNzY3MzE4MDAwLTAwMDIvc29tZS1vYmonIGlzIHVuZGVyIGFjdGl2ZSBFdmVudC1CYXNlZCBob2xkIGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgaG9sZCBpcyByZW1vdmVkLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50b1JwYzNFeGNlcHRpb24oQmlnc3RvcmVFeGNlcHRpb24uamF2YToxMzUpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjc3KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmhhbmRsZXJzLm9iamVjdHMuRGVsZXRlT2JqZWN0LmhhbmRsZVJlcXVlc3RSZWNlaXZlZChEZWxldGVPYmplY3QuamF2YToyMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5mcmFtZXdvcmsuUmVxdWVzdEhhbmRsZXIuaGFuZGxlKFJlcXVlc3RIYW5kbGVyLmphdmE6Mjk0KVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLk9iamVjdHNEZWxlZ2F0b3IuZGVsZXRlKE9iamVjdHNEZWxlZ2F0b3IuamF2YToxMTMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLlJwY1JlY2VpdmVyLmxhbWJkYSRwcm9jZXNzUmVxdWVzdEFzeW5jJDQoUnBjUmVjZWl2ZXIuamF2YToyMDMpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuaXNvbGF0aW9uLkFzeW5jRXhlY3V0b3IubGFtYmRhJHN1Ym1pdCQwKEFzeW5jRXhlY3V0b3IuamF2YToyNzIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bkluQ29udGV4dChDb250ZXh0UnVubmFibGUuamF2YTo1MClcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUkMS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzkpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dE5vVW5yZWYoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjcyKVxuXHRhdCBjb20uZ29vZ2xlLnRyYWNpbmcuR2VuZXJpY0NvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHQoR2VuZXJpY0NvbnRleHRDYWxsYmFjay5qYXZhOjY0KVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZS5ydW4oQ29udGV4dFJ1bm5hYmxlLmphdmE6MzYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkV4ZWN1dG9ycyRSdW5uYWJsZUFkYXB0ZXIuY2FsbChFeGVjdXRvcnMuamF2YTo1MTEpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LkZ1dHVyZVRhc2sucnVuKEZ1dHVyZVRhc2suamF2YToyNjYpXG5cdGF0IGphdmEudXRpbC5jb25jdXJyZW50LlRocmVhZFBvb2xFeGVjdXRvci5ydW5Xb3JrZXIoVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6MTE0OSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yJFdvcmtlci5ydW4oVGhyZWFkUG9vbEV4ZWN1dG9yLmphdmE6NjI0KVxuXHRhdCBqYXZhLmxhbmcuVGhyZWFkLnJ1bihUaHJlYWQuamF2YTo3NDgpXG5DYXVzZWQgYnk6IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uOiBPYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDEzMTc2NzMxODAwMC0wMDAyL3NvbWUtb2JqJyBpcyB1bmRlciBhY3RpdmUgRXZlbnQtQmFzZWQgaG9sZCBhbmQgY2Fubm90IGJlIGRlbGV0ZWQsIG92ZXJ3cml0dGVuIG9yIGFyY2hpdmVkIHVudGlsIGhvbGQgaXMgcmVtb3ZlZC5cblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MjkwKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd1JwYzNPbkVycm9yKEJpZ3N0b3JlRXhjZXB0aW9uLmphdmE6MzAxKVxuXHQuLi4gMTcgbW9yZVxuLCBlcnJvclByb3RvQ29kZT1GT1JCSURERU4sIGVycm9yUHJvdG9Eb21haW49Z2RhdGEuQ29yZUVycm9yRG9tYWluLCBmaWx0ZXJlZE1lc3NhZ2U9bnVsbCwgbG9jYXRpb249bnVsbCwgbWVzc2FnZT1PYmplY3QgJ2dvLWludGVncmF0aW9uLXRlc3QtMjAxODA5MTgtNDEzMTc2NzMxODAwMC0wMDAyL3NvbWUtb2JqJyBpcyB1bmRlciBhY3RpdmUgRXZlbnQtQmFzZWQgaG9sZCBhbmQgY2Fubm90IGJlIGRlbGV0ZWQsIG92ZXJ3cml0dGVuIG9yIGFyY2hpdmVkIHVudGlsIGhvbGQgaXMgcmVtb3ZlZC4sIHVubmFtZWRBcmd1bWVudHM9W119LCBsb2NhdGlvbj1udWxsLCBtZXNzYWdlPU9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00MTMxNzY3MzE4MDAwLTAwMDIvc29tZS1vYmonIGlzIHVuZGVyIGFjdGl2ZSBFdmVudC1CYXNlZCBob2xkIGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgaG9sZCBpcyByZW1vdmVkLiwgcmVhc29uPWZvcmJpZGRlbiwgcnBjQ29kZT00MDN9IE9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00MTMxNzY3MzE4MDAwLTAwMDIvc29tZS1vYmonIGlzIHVuZGVyIGFjdGl2ZSBFdmVudC1CYXNlZCBob2xkIGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgaG9sZCBpcyByZW1vdmVkLjogY29tLmdvb2dsZS5uZXQucnBjMy5ScGNFeGNlcHRpb246IGNsb3VkLmJpZ3N0b3JlLlJlc3BvbnNlQ29kZS5FcnJvckNvZGU6Ok9CSkVDVF9JU19VTkRFUl9BQ1RJVkVfSE9MRDogT2JqZWN0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMi9zb21lLW9iaicgaXMgdW5kZXIgYWN0aXZlIEV2ZW50LUJhc2VkIGhvbGQgYW5kIGNhbm5vdCBiZSBkZWxldGVkLCBvdmVyd3JpdHRlbiBvciBhcmNoaXZlZCB1bnRpbCBob2xkIGlzIHJlbW92ZWQuXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRvUnBjM0V4Y2VwdGlvbihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjEzNSlcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb24udGhyb3dScGMzT25FcnJvcihCaWdzdG9yZUV4Y2VwdGlvbi5qYXZhOjMwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5hcGkuanNvbi5oYW5kbGVycy5vYmplY3RzLkRlbGV0ZU9iamVjdC5oYW5kbGVSZXF1ZXN0UmVjZWl2ZWQoRGVsZXRlT2JqZWN0LmphdmE6NzcpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uaGFuZGxlcnMub2JqZWN0cy5EZWxldGVPYmplY3QuaGFuZGxlUmVxdWVzdFJlY2VpdmVkKERlbGV0ZU9iamVjdC5qYXZhOjIzKVxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmFwaS5qc29uLmZyYW1ld29yay5SZXF1ZXN0SGFuZGxlci5oYW5kbGUoUmVxdWVzdEhhbmRsZXIuamF2YToyOTQpXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuYXBpLmpzb24uT2JqZWN0c0RlbGVnYXRvci5kZWxldGUoT2JqZWN0c0RlbGVnYXRvci5qYXZhOjExMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uUnBjUmVjZWl2ZXIubGFtYmRhJHByb2Nlc3NSZXF1ZXN0QXN5bmMkNChScGNSZWNlaXZlci5qYXZhOjIwMylcblx0YXQgY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5pc29sYXRpb24uQXN5bmNFeGVjdXRvci5sYW1iZGEkc3VibWl0JDAoQXN5bmNFeGVjdXRvci5qYXZhOjI3Milcblx0YXQgY29tLmdvb2dsZS5jb21tb24uY29udGV4dC5Db250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KENvbnRleHRSdW5uYWJsZS5qYXZhOjUwKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi5jb250ZXh0LkNvbnRleHRSdW5uYWJsZSQxLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozOSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkN1cnJlbnRDb250ZXh0LnJ1bkluQ29udGV4dChDdXJyZW50Q29udGV4dC5qYXZhOjMyMClcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLkdlbmVyaWNDb250ZXh0Q2FsbGJhY2sucnVuSW5Jbmhlcml0ZWRDb250ZXh0Tm9VbnJlZihHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NzIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5HZW5lcmljQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChHZW5lcmljQ29udGV4dENhbGxiYWNrLmphdmE6NjQpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLmNvbnRleHQuQ29udGV4dFJ1bm5hYmxlLnJ1bihDb250ZXh0UnVubmFibGUuamF2YTozNilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRXhlY3V0b3JzJFJ1bm5hYmxlQWRhcHRlci5jYWxsKEV4ZWN1dG9ycy5qYXZhOjUxMSlcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuRnV0dXJlVGFzay5ydW4oRnV0dXJlVGFzay5qYXZhOjI2Nilcblx0YXQgamF2YS51dGlsLmNvbmN1cnJlbnQuVGhyZWFkUG9vbEV4ZWN1dG9yLnJ1bldvcmtlcihUaHJlYWRQb29sRXhlY3V0b3IuamF2YToxMTQ5KVxuXHRhdCBqYXZhLnV0aWwuY29uY3VycmVudC5UaHJlYWRQb29sRXhlY3V0b3IkV29ya2VyLnJ1bihUaHJlYWRQb29sRXhlY3V0b3IuamF2YTo2MjQpXG5cdGF0IGphdmEubGFuZy5UaHJlYWQucnVuKFRocmVhZC5qYXZhOjc0OClcbkNhdXNlZCBieTogY29tLmdvb2dsZS5jbG91ZC5iaWdzdG9yZS5jb21tb24uQmlnc3RvcmVFeGNlcHRpb246IE9iamVjdCAnZ28taW50ZWdyYXRpb24tdGVzdC0yMDE4MDkxOC00MTMxNzY3MzE4MDAwLTAwMDIvc29tZS1vYmonIGlzIHVuZGVyIGFjdGl2ZSBFdmVudC1CYXNlZCBob2xkIGFuZCBjYW5ub3QgYmUgZGVsZXRlZCwgb3ZlcndyaXR0ZW4gb3IgYXJjaGl2ZWQgdW50aWwgaG9sZCBpcyByZW1vdmVkLlxuXHRhdCBjb20uZ29vZ2xlLmNsb3VkLmJpZ3N0b3JlLmNvbW1vbi5CaWdzdG9yZUV4Y2VwdGlvbi50aHJvd09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YToyOTApXG5cdGF0IGNvbS5nb29nbGUuY2xvdWQuYmlnc3RvcmUuY29tbW9uLkJpZ3N0b3JlRXhjZXB0aW9uLnRocm93UnBjM09uRXJyb3IoQmlnc3RvcmVFeGNlcHRpb24uamF2YTozMDEpXG5cdC4uLiAxNyBtb3JlXG5cblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLmNvcmUuRXJyb3JDb2xsZWN0b3IudG9GYXVsdChFcnJvckNvbGxlY3Rvci5qYXZhOjU0KVxuXHRhdCBjb20uZ29vZ2xlLmFwaS5zZXJ2ZXIucmVzdC5hZGFwdGVyLnJvc3kuUm9zeUVycm9yQ29udmVydGVyLnRvRmF1bHQoUm9zeUVycm9yQ29udmVydGVyLmphdmE6NjcpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyNTgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5yZXN0LmFkYXB0ZXIucm9zeS5Sb3N5SGFuZGxlciQyLmNhbGwoUm9zeUhhbmRsZXIuamF2YToyMzgpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5EaXJlY3RFeGVjdXRvci5leGVjdXRlKERpcmVjdEV4ZWN1dG9yLmphdmE6MzApXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5leGVjdXRlTGlzdGVuZXIoQWJzdHJhY3RGdXR1cmUuamF2YToxMTQzKVxuXHRhdCBjb20uZ29vZ2xlLmNvbW1vbi51dGlsLmNvbmN1cnJlbnQuQWJzdHJhY3RGdXR1cmUuY29tcGxldGUoQWJzdHJhY3RGdXR1cmUuamF2YTo5NjMpXG5cdGF0IGNvbS5nb29nbGUuY29tbW9uLnV0aWwuY29uY3VycmVudC5BYnN0cmFjdEZ1dHVyZS5zZXQoQWJzdHJhY3RGdXR1cmUuamF2YTo3MzEpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci5jb3JlLnV0aWwuQ2FsbGFibGVGdXR1cmUucnVuKENhbGxhYmxlRnV0dXJlLmphdmE6NjIpXG5cdGF0IGNvbS5nb29nbGUuYXBpLnNlcnZlci50aHJlYWQuVGhyZWFkVHJhY2tlcnMkVGhyZWFkVHJhY2tpbmdSdW5uYWJsZS5ydW4oVGhyZWFkVHJhY2tlcnMuamF2YToxMjYpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuSW5Db250ZXh0KFRyYWNlQ29udGV4dC5qYXZhOjQ1NSlcblx0YXQgY29tLmdvb2dsZS5hcGkuc2VydmVyLnNlcnZlci5Db21tb25Nb2R1bGUkQ29udGV4dENhcnJ5aW5nRXhlY3V0b3JTZXJ2aWNlJDEucnVuSW5Db250ZXh0KENvbW1vbk1vZHVsZS5qYXZhOjg0Nilcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRUcmFjZUNvbnRleHRSdW5uYWJsZSQxLnJ1bihUcmFjZUNvbnRleHQuamF2YTo0NjIpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5DdXJyZW50Q29udGV4dC5ydW5JbkNvbnRleHQoQ3VycmVudENvbnRleHQuamF2YTozMjApXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkQWJzdHJhY3RUcmFjZUNvbnRleHRDYWxsYmFjay5ydW5JbkluaGVyaXRlZENvbnRleHROb1VucmVmKFRyYWNlQ29udGV4dC5qYXZhOjMyMSlcblx0YXQgY29tLmdvb2dsZS50cmFjaW5nLlRyYWNlQ29udGV4dCRBYnN0cmFjdFRyYWNlQ29udGV4dENhbGxiYWNrLnJ1bkluSW5oZXJpdGVkQ29udGV4dChUcmFjZUNvbnRleHQuamF2YTozMTMpXG5cdGF0IGNvbS5nb29nbGUudHJhY2luZy5UcmFjZUNvbnRleHQkVHJhY2VDb250ZXh0UnVubmFibGUucnVuKFRyYWNlQ29udGV4dC5qYXZhOjQ1OSlcblx0YXQgY29tLmdvb2dsZS5nc2UuaW50ZXJuYWwuRGlzcGF0Y2hRdWV1ZUltcGwkV29ya2VyVGhyZWFkLnJ1bihEaXNwYXRjaFF1ZXVlSW1wbC5qYXZhOjQwMylcbiJ9XSwiY29kZSI6NDAzLCJtZXNzYWdlIjoiT2JqZWN0ICdnby1pbnRlZ3JhdGlvbi10ZXN0LTIwMTgwOTE4LTQxMzE3NjczMTgwMDAtMDAwMi9zb21lLW9iaicgaXMgdW5kZXIgYWN0aXZlIEV2ZW50LUJhc2VkIGhvbGQgYW5kIGNhbm5vdCBiZSBkZWxldGVkLCBvdmVyd3JpdHRlbiBvciBhcmNoaXZlZCB1bnRpbCBob2xkIGlzIHJlbW92ZWQuIn19" + } + } + ] +} \ No newline at end of file diff --git a/vendor/cloud.google.com/go/storage/storage_test.go b/vendor/cloud.google.com/go/storage/storage_test.go new file mode 100644 index 00000000..6806472e --- /dev/null +++ b/vendor/cloud.google.com/go/storage/storage_test.go @@ -0,0 +1,790 @@ +// Copyright 2014 Google LLC +// +// 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 storage + +import ( + "context" + "crypto/tls" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "log" + "net" + "net/http" + "net/http/httptest" + "net/url" + "regexp" + "strings" + "testing" + "time" + + "cloud.google.com/go/iam" + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + raw "google.golang.org/api/storage/v1" +) + +func TestHeaderSanitization(t *testing.T) { + t.Parallel() + var tests = []struct { + desc string + in []string + want []string + }{ + { + desc: "already sanitized headers should not be modified", + in: []string{"x-goog-header1:true", "x-goog-header2:0"}, + want: []string{"x-goog-header1:true", "x-goog-header2:0"}, + }, + { + desc: "sanitized headers should be sorted", + in: []string{"x-goog-header2:0", "x-goog-header1:true"}, + want: []string{"x-goog-header1:true", "x-goog-header2:0"}, + }, + { + desc: "non-canonical headers should be removed", + in: []string{"x-goog-header1:true", "x-goog-no-value", "non-canonical-header:not-of-use"}, + want: []string{"x-goog-header1:true"}, + }, + { + desc: "excluded canonical headers should be removed", + in: []string{"x-goog-header1:true", "x-goog-encryption-key:my_key", "x-goog-encryption-key-sha256:my_sha256"}, + want: []string{"x-goog-header1:true"}, + }, + { + desc: "dirty headers should be formatted correctly", + in: []string{" x-goog-header1 : \textra-spaces ", "X-Goog-Header2:CamelCaseValue"}, + want: []string{"x-goog-header1:extra-spaces", "x-goog-header2:CamelCaseValue"}, + }, + { + desc: "duplicate headers should be merged", + in: []string{"x-goog-header1:value1", "X-Goog-Header1:value2"}, + want: []string{"x-goog-header1:value1,value2"}, + }, + } + for _, test := range tests { + got := sanitizeHeaders(test.in) + if !testutil.Equal(got, test.want) { + t.Errorf("%s: got %v, want %v", test.desc, got, test.want) + } + } +} + +func TestSignedURL(t *testing.T) { + t.Parallel() + expires, _ := time.Parse(time.RFC3339, "2002-10-02T10:00:00-05:00") + url, err := SignedURL("bucket-name", "object-name", &SignedURLOptions{ + GoogleAccessID: "xxx@clientid", + PrivateKey: dummyKey("rsa"), + Method: "GET", + MD5: "ICy5YqxZB1uWSwcVLSNLcA==", + Expires: expires, + ContentType: "application/json", + Headers: []string{"x-goog-header1:true", "x-goog-header2:false"}, + }) + if err != nil { + t.Error(err) + } + want := "https://storage.googleapis.com/bucket-name/object-name?" + + "Expires=1033570800&GoogleAccessId=xxx%40clientid&Signature=" + + "RfsHlPtbB2JUYjzCgNr2Mi%2BjggdEuL1V7E6N9o6aaqwVLBDuTv3I0%2B9" + + "x94E6rmmr%2FVgnmZigkIUxX%2Blfl7LgKf30uPGLt0mjKGH2p7r9ey1ONJ" + + "%2BhVec23FnTRcSgopglvHPuCMWU2oNJE%2F1y8EwWE27baHrG1RhRHbLVF" + + "bPpLZ9xTRFK20pluIkfHV00JGljB1imqQHXM%2B2XPWqBngLr%2FwqxLN7i" + + "FcUiqR8xQEOHF%2F2e7fbkTHPNq4TazaLZ8X0eZ3eFdJ55A5QmNi8atlN4W" + + "5q7Hvs0jcxElG3yqIbx439A995BkspLiAcA%2Fo4%2BxAwEMkGLICdbvakq" + + "3eEprNCojw%3D%3D" + if url != want { + t.Fatalf("Unexpected signed URL; found %v", url) + } +} + +func TestSignedURL_PEMPrivateKey(t *testing.T) { + t.Parallel() + expires, _ := time.Parse(time.RFC3339, "2002-10-02T10:00:00-05:00") + url, err := SignedURL("bucket-name", "object-name", &SignedURLOptions{ + GoogleAccessID: "xxx@clientid", + PrivateKey: dummyKey("pem"), + Method: "GET", + MD5: "ICy5YqxZB1uWSwcVLSNLcA==", + Expires: expires, + ContentType: "application/json", + Headers: []string{"x-goog-header1:true", "x-goog-header2:false"}, + }) + if err != nil { + t.Error(err) + } + want := "https://storage.googleapis.com/bucket-name/object-name?" + + "Expires=1033570800&GoogleAccessId=xxx%40clientid&Signature=" + + "TiyKD%2FgGb6Kh0kkb2iF%2FfF%2BnTx7L0J4YiZua8AcTmnidutePEGIU5" + + "NULYlrGl6l52gz4zqFb3VFfIRTcPXMdXnnFdMCDhz2QuJBUpsU1Ai9zlyTQ" + + "dkb6ShG03xz9%2BEXWAUQO4GBybJw%2FULASuv37xA00SwLdkqj8YdyS5II" + + "1lro%3D" + if url != want { + t.Fatalf("Unexpected signed URL; found %v", url) + } +} + +func TestSignedURL_SignBytes(t *testing.T) { + t.Parallel() + expires, _ := time.Parse(time.RFC3339, "2002-10-02T10:00:00-05:00") + url, err := SignedURL("bucket-name", "object-name", &SignedURLOptions{ + GoogleAccessID: "xxx@clientid", + SignBytes: func(b []byte) ([]byte, error) { + return []byte("signed"), nil + }, + Method: "GET", + MD5: "ICy5YqxZB1uWSwcVLSNLcA==", + Expires: expires, + ContentType: "application/json", + Headers: []string{"x-goog-header1:true", "x-goog-header2:false"}, + }) + if err != nil { + t.Error(err) + } + want := "https://storage.googleapis.com/bucket-name/object-name?" + + "Expires=1033570800&GoogleAccessId=xxx%40clientid&Signature=" + + "c2lnbmVk" // base64('signed') == 'c2lnbmVk' + if url != want { + t.Fatalf("Unexpected signed URL\ngot: %q\nwant: %q", url, want) + } +} + +func TestSignedURL_URLUnsafeObjectName(t *testing.T) { + t.Parallel() + expires, _ := time.Parse(time.RFC3339, "2002-10-02T10:00:00-05:00") + url, err := SignedURL("bucket-name", "object name界", &SignedURLOptions{ + GoogleAccessID: "xxx@clientid", + PrivateKey: dummyKey("pem"), + Method: "GET", + MD5: "ICy5YqxZB1uWSwcVLSNLcA==", + Expires: expires, + ContentType: "application/json", + Headers: []string{"x-goog-header1:true", "x-goog-header2:false"}, + }) + if err != nil { + t.Error(err) + } + want := "https://storage.googleapis.com/bucket-name/object%20name%E7%95%8C?" + + "Expires=1033570800&GoogleAccessId=xxx%40clientid&Signature=bxVH1%2Bl%2" + + "BSxpnj3XuqKz6mOFk6M94Y%2B4w85J6FCmJan%2FNhGSpndP6fAw1uLHlOn%2F8xUaY%2F" + + "SfZ5GzcQ%2BbxOL1WA37yIwZ7xgLYlO%2ByAi3GuqMUmHZiNCai28emODXQ8RtWHvgv6dE" + + "SQ%2F0KpDMIWW7rYCaUa63UkUyeSQsKhrVqkIA%3D" + if url != want { + t.Fatalf("Unexpected signed URL; found %v", url) + } +} + +func TestSignedURL_MissingOptions(t *testing.T) { + t.Parallel() + pk := dummyKey("rsa") + expires, _ := time.Parse(time.RFC3339, "2002-10-02T10:00:00-05:00") + var tests = []struct { + opts *SignedURLOptions + errMsg string + }{ + { + &SignedURLOptions{}, + "missing required GoogleAccessID", + }, + { + &SignedURLOptions{GoogleAccessID: "access_id"}, + "exactly one of PrivateKey or SignedBytes must be set", + }, + { + &SignedURLOptions{ + GoogleAccessID: "access_id", + SignBytes: func(b []byte) ([]byte, error) { return b, nil }, + PrivateKey: pk, + }, + "exactly one of PrivateKey or SignedBytes must be set", + }, + { + &SignedURLOptions{ + GoogleAccessID: "access_id", + PrivateKey: pk, + }, + "missing required method", + }, + { + &SignedURLOptions{ + GoogleAccessID: "access_id", + SignBytes: func(b []byte) ([]byte, error) { return b, nil }, + }, + "missing required method", + }, + { + &SignedURLOptions{ + GoogleAccessID: "access_id", + PrivateKey: pk, + Method: "PUT", + }, + "missing required expires", + }, + { + &SignedURLOptions{ + GoogleAccessID: "access_id", + PrivateKey: pk, + Method: "PUT", + Expires: expires, + MD5: "invalid", + }, + "invalid MD5 checksum", + }, + } + for _, test := range tests { + _, err := SignedURL("bucket", "name", test.opts) + if !strings.Contains(err.Error(), test.errMsg) { + t.Errorf("expected err: %v, found: %v", test.errMsg, err) + } + } +} + +func dummyKey(kind string) []byte { + slurp, err := ioutil.ReadFile(fmt.Sprintf("./testdata/dummy_%s", kind)) + if err != nil { + log.Fatal(err) + } + return slurp +} + +func TestObjectNames(t *testing.T) { + t.Parallel() + // Naming requirements: https://cloud.google.com/storage/docs/bucket-naming + const maxLegalLength = 1024 + + type testT struct { + name, want string + } + tests := []testT{ + // Embedded characters important in URLs. + {"foo % bar", "foo%20%25%20bar"}, + {"foo ? bar", "foo%20%3F%20bar"}, + {"foo / bar", "foo%20/%20bar"}, + {"foo %?/ bar", "foo%20%25%3F/%20bar"}, + + // Non-Roman scripts + {"타코", "%ED%83%80%EC%BD%94"}, + {"世界", "%E4%B8%96%E7%95%8C"}, + + // Longest legal name + {strings.Repeat("a", maxLegalLength), strings.Repeat("a", maxLegalLength)}, + + // Line terminators besides CR and LF: https://en.wikipedia.org/wiki/Newline#Unicode + {"foo \u000b bar", "foo%20%0B%20bar"}, + {"foo \u000c bar", "foo%20%0C%20bar"}, + {"foo \u0085 bar", "foo%20%C2%85%20bar"}, + {"foo \u2028 bar", "foo%20%E2%80%A8%20bar"}, + {"foo \u2029 bar", "foo%20%E2%80%A9%20bar"}, + + // Null byte. + {"foo \u0000 bar", "foo%20%00%20bar"}, + + // Non-control characters that are discouraged, but not forbidden, according to the documentation. + {"foo # bar", "foo%20%23%20bar"}, + {"foo []*? bar", "foo%20%5B%5D%2A%3F%20bar"}, + + // Angstrom symbol singleton and normalized forms: http://unicode.org/reports/tr15/ + {"foo \u212b bar", "foo%20%E2%84%AB%20bar"}, + {"foo \u0041\u030a bar", "foo%20A%CC%8A%20bar"}, + {"foo \u00c5 bar", "foo%20%C3%85%20bar"}, + + // Hangul separating jamo: http://www.unicode.org/versions/Unicode7.0.0/ch18.pdf (Table 18-10) + {"foo \u3131\u314f bar", "foo%20%E3%84%B1%E3%85%8F%20bar"}, + {"foo \u1100\u1161 bar", "foo%20%E1%84%80%E1%85%A1%20bar"}, + {"foo \uac00 bar", "foo%20%EA%B0%80%20bar"}, + } + + // C0 control characters not forbidden by the docs. + var runes []rune + for r := rune(0x01); r <= rune(0x1f); r++ { + if r != '\u000a' && r != '\u000d' { + runes = append(runes, r) + } + } + tests = append(tests, testT{fmt.Sprintf("foo %s bar", string(runes)), "foo%20%01%02%03%04%05%06%07%08%09%0B%0C%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20bar"}) + + // C1 control characters, plus DEL. + runes = nil + for r := rune(0x7f); r <= rune(0x9f); r++ { + runes = append(runes, r) + } + tests = append(tests, testT{fmt.Sprintf("foo %s bar", string(runes)), "foo%20%7F%C2%80%C2%81%C2%82%C2%83%C2%84%C2%85%C2%86%C2%87%C2%88%C2%89%C2%8A%C2%8B%C2%8C%C2%8D%C2%8E%C2%8F%C2%90%C2%91%C2%92%C2%93%C2%94%C2%95%C2%96%C2%97%C2%98%C2%99%C2%9A%C2%9B%C2%9C%C2%9D%C2%9E%C2%9F%20bar"}) + + opts := &SignedURLOptions{ + GoogleAccessID: "xxx@clientid", + PrivateKey: dummyKey("rsa"), + Method: "GET", + MD5: "ICy5YqxZB1uWSwcVLSNLcA==", + Expires: time.Date(2002, time.October, 2, 10, 0, 0, 0, time.UTC), + ContentType: "application/json", + Headers: []string{"x-goog-header1", "x-goog-header2"}, + } + + for _, test := range tests { + g, err := SignedURL("bucket-name", test.name, opts) + if err != nil { + t.Errorf("SignedURL(%q) err=%v, want nil", test.name, err) + } + if w := "/bucket-name/" + test.want; !strings.Contains(g, w) { + t.Errorf("SignedURL(%q)=%q, want substring %q", test.name, g, w) + } + } +} + +func TestCondition(t *testing.T) { + t.Parallel() + gotReq := make(chan *http.Request, 1) + hc, close := newTestServer(func(w http.ResponseWriter, r *http.Request) { + io.Copy(ioutil.Discard, r.Body) + gotReq <- r + w.WriteHeader(200) + }) + defer close() + ctx := context.Background() + c, err := NewClient(ctx, option.WithHTTPClient(hc)) + if err != nil { + t.Fatal(err) + } + + obj := c.Bucket("buck").Object("obj") + dst := c.Bucket("dstbuck").Object("dst") + tests := []struct { + fn func() + want string + }{ + { + func() { obj.Generation(1234).NewReader(ctx) }, + "GET /buck/obj?generation=1234", + }, + { + func() { obj.If(Conditions{GenerationMatch: 1234}).NewReader(ctx) }, + "GET /buck/obj?ifGenerationMatch=1234", + }, + { + func() { obj.If(Conditions{GenerationNotMatch: 1234}).NewReader(ctx) }, + "GET /buck/obj?ifGenerationNotMatch=1234", + }, + { + func() { obj.If(Conditions{MetagenerationMatch: 1234}).NewReader(ctx) }, + "GET /buck/obj?ifMetagenerationMatch=1234", + }, + { + func() { obj.If(Conditions{MetagenerationNotMatch: 1234}).NewReader(ctx) }, + "GET /buck/obj?ifMetagenerationNotMatch=1234", + }, + { + func() { obj.If(Conditions{MetagenerationNotMatch: 1234}).Attrs(ctx) }, + "GET /storage/v1/b/buck/o/obj?alt=json&ifMetagenerationNotMatch=1234&prettyPrint=false&projection=full", + }, + + { + func() { obj.If(Conditions{MetagenerationMatch: 1234}).Update(ctx, ObjectAttrsToUpdate{}) }, + "PATCH /storage/v1/b/buck/o/obj?alt=json&ifMetagenerationMatch=1234&prettyPrint=false&projection=full", + }, + { + func() { obj.Generation(1234).Delete(ctx) }, + "DELETE /storage/v1/b/buck/o/obj?alt=json&generation=1234&prettyPrint=false", + }, + { + func() { + w := obj.If(Conditions{GenerationMatch: 1234}).NewWriter(ctx) + w.ContentType = "text/plain" + w.Close() + }, + "POST /upload/storage/v1/b/buck/o?alt=json&ifGenerationMatch=1234&prettyPrint=false&projection=full&uploadType=multipart", + }, + { + func() { + w := obj.If(Conditions{DoesNotExist: true}).NewWriter(ctx) + w.ContentType = "text/plain" + w.Close() + }, + "POST /upload/storage/v1/b/buck/o?alt=json&ifGenerationMatch=0&prettyPrint=false&projection=full&uploadType=multipart", + }, + { + func() { + dst.If(Conditions{MetagenerationMatch: 5678}).CopierFrom(obj.If(Conditions{GenerationMatch: 1234})).Run(ctx) + }, + "POST /storage/v1/b/buck/o/obj/rewriteTo/b/dstbuck/o/dst?alt=json&ifMetagenerationMatch=5678&ifSourceGenerationMatch=1234&prettyPrint=false&projection=full", + }, + } + + for i, tt := range tests { + tt.fn() + select { + case r := <-gotReq: + got := r.Method + " " + r.RequestURI + if got != tt.want { + t.Errorf("%d. RequestURI = %q; want %q", i, got, tt.want) + } + case <-time.After(5 * time.Second): + t.Fatalf("%d. timeout", i) + } + if err != nil { + t.Fatal(err) + } + } + + // Test an error, too: + err = obj.Generation(1234).NewWriter(ctx).Close() + if err == nil || !strings.Contains(err.Error(), "NewWriter: generation not supported") { + t.Errorf("want error about unsupported generation; got %v", err) + } +} + +func TestConditionErrors(t *testing.T) { + t.Parallel() + for _, conds := range []Conditions{ + {GenerationMatch: 0}, + {DoesNotExist: false}, // same as above, actually + {GenerationMatch: 1, GenerationNotMatch: 2}, + {GenerationNotMatch: 2, DoesNotExist: true}, + {MetagenerationMatch: 1, MetagenerationNotMatch: 2}, + } { + if err := conds.validate(""); err == nil { + t.Errorf("%+v: got nil, want error", conds) + } + } +} + +// Test object compose. +func TestObjectCompose(t *testing.T) { + t.Parallel() + gotURL := make(chan string, 1) + gotBody := make(chan []byte, 1) + hc, close := newTestServer(func(w http.ResponseWriter, r *http.Request) { + body, _ := ioutil.ReadAll(r.Body) + gotURL <- r.URL.String() + gotBody <- body + w.Write([]byte("{}")) + }) + defer close() + ctx := context.Background() + c, err := NewClient(ctx, option.WithHTTPClient(hc)) + if err != nil { + t.Fatal(err) + } + + testCases := []struct { + desc string + dst *ObjectHandle + srcs []*ObjectHandle + attrs *ObjectAttrs + wantReq raw.ComposeRequest + wantURL string + wantErr bool + }{ + { + desc: "basic case", + dst: c.Bucket("foo").Object("bar"), + srcs: []*ObjectHandle{ + c.Bucket("foo").Object("baz"), + c.Bucket("foo").Object("quux"), + }, + wantURL: "/storage/v1/b/foo/o/bar/compose?alt=json&prettyPrint=false", + wantReq: raw.ComposeRequest{ + Destination: &raw.Object{Bucket: "foo"}, + SourceObjects: []*raw.ComposeRequestSourceObjects{ + {Name: "baz"}, + {Name: "quux"}, + }, + }, + }, + { + desc: "with object attrs", + dst: c.Bucket("foo").Object("bar"), + srcs: []*ObjectHandle{ + c.Bucket("foo").Object("baz"), + c.Bucket("foo").Object("quux"), + }, + attrs: &ObjectAttrs{ + Name: "not-bar", + ContentType: "application/json", + }, + wantURL: "/storage/v1/b/foo/o/bar/compose?alt=json&prettyPrint=false", + wantReq: raw.ComposeRequest{ + Destination: &raw.Object{ + Bucket: "foo", + Name: "not-bar", + ContentType: "application/json", + }, + SourceObjects: []*raw.ComposeRequestSourceObjects{ + {Name: "baz"}, + {Name: "quux"}, + }, + }, + }, + { + desc: "with conditions", + dst: c.Bucket("foo").Object("bar").If(Conditions{ + GenerationMatch: 12, + MetagenerationMatch: 34, + }), + srcs: []*ObjectHandle{ + c.Bucket("foo").Object("baz").Generation(56), + c.Bucket("foo").Object("quux").If(Conditions{GenerationMatch: 78}), + }, + wantURL: "/storage/v1/b/foo/o/bar/compose?alt=json&ifGenerationMatch=12&ifMetagenerationMatch=34&prettyPrint=false", + wantReq: raw.ComposeRequest{ + Destination: &raw.Object{Bucket: "foo"}, + SourceObjects: []*raw.ComposeRequestSourceObjects{ + { + Name: "baz", + Generation: 56, + }, + { + Name: "quux", + ObjectPreconditions: &raw.ComposeRequestSourceObjectsObjectPreconditions{ + IfGenerationMatch: 78, + }, + }, + }, + }, + }, + { + desc: "no sources", + dst: c.Bucket("foo").Object("bar"), + wantErr: true, + }, + { + desc: "destination, no bucket", + dst: c.Bucket("").Object("bar"), + srcs: []*ObjectHandle{ + c.Bucket("foo").Object("baz"), + }, + wantErr: true, + }, + { + desc: "destination, no object", + dst: c.Bucket("foo").Object(""), + srcs: []*ObjectHandle{ + c.Bucket("foo").Object("baz"), + }, + wantErr: true, + }, + { + desc: "source, different bucket", + dst: c.Bucket("foo").Object("bar"), + srcs: []*ObjectHandle{ + c.Bucket("otherbucket").Object("baz"), + }, + wantErr: true, + }, + { + desc: "source, no object", + dst: c.Bucket("foo").Object("bar"), + srcs: []*ObjectHandle{ + c.Bucket("foo").Object(""), + }, + wantErr: true, + }, + { + desc: "destination, bad condition", + dst: c.Bucket("foo").Object("bar").Generation(12), + srcs: []*ObjectHandle{ + c.Bucket("foo").Object("baz"), + }, + wantErr: true, + }, + { + desc: "source, bad condition", + dst: c.Bucket("foo").Object("bar"), + srcs: []*ObjectHandle{ + c.Bucket("foo").Object("baz").If(Conditions{MetagenerationMatch: 12}), + }, + wantErr: true, + }, + } + + for _, tt := range testCases { + composer := tt.dst.ComposerFrom(tt.srcs...) + if tt.attrs != nil { + composer.ObjectAttrs = *tt.attrs + } + _, err := composer.Run(ctx) + if gotErr := err != nil; gotErr != tt.wantErr { + t.Errorf("%s: got error %v; want err %t", tt.desc, err, tt.wantErr) + continue + } + if tt.wantErr { + continue + } + url, body := <-gotURL, <-gotBody + if url != tt.wantURL { + t.Errorf("%s: request URL\ngot %q\nwant %q", tt.desc, url, tt.wantURL) + } + var req raw.ComposeRequest + if err := json.Unmarshal(body, &req); err != nil { + t.Errorf("%s: json.Unmarshal %v (body %s)", tt.desc, err, body) + } + if !testutil.Equal(req, tt.wantReq) { + // Print to JSON. + wantReq, _ := json.Marshal(tt.wantReq) + t.Errorf("%s: request body\ngot %s\nwant %s", tt.desc, body, wantReq) + } + } +} + +// Test that ObjectIterator's Next and NextPage methods correctly terminate +// if there is nothing to iterate over. +func TestEmptyObjectIterator(t *testing.T) { + t.Parallel() + hClient, close := newTestServer(func(w http.ResponseWriter, r *http.Request) { + io.Copy(ioutil.Discard, r.Body) + fmt.Fprintf(w, "{}") + }) + defer close() + ctx := context.Background() + client, err := NewClient(ctx, option.WithHTTPClient(hClient)) + if err != nil { + t.Fatal(err) + } + it := client.Bucket("b").Objects(ctx, nil) + _, err = it.Next() + if err != iterator.Done { + t.Errorf("got %v, want Done", err) + } +} + +// Test that BucketIterator's Next method correctly terminates if there is +// nothing to iterate over. +func TestEmptyBucketIterator(t *testing.T) { + t.Parallel() + hClient, close := newTestServer(func(w http.ResponseWriter, r *http.Request) { + io.Copy(ioutil.Discard, r.Body) + fmt.Fprintf(w, "{}") + }) + defer close() + ctx := context.Background() + client, err := NewClient(ctx, option.WithHTTPClient(hClient)) + if err != nil { + t.Fatal(err) + } + it := client.Buckets(ctx, "project") + _, err = it.Next() + if err != iterator.Done { + t.Errorf("got %v, want Done", err) + } + +} + +func TestCodecUint32(t *testing.T) { + t.Parallel() + for _, u := range []uint32{0, 1, 256, 0xFFFFFFFF} { + s := encodeUint32(u) + d, err := decodeUint32(s) + if err != nil { + t.Fatal(err) + } + if d != u { + t.Errorf("got %d, want input %d", d, u) + } + } +} + +func TestUserProject(t *testing.T) { + // Verify that the userProject query param is sent. + t.Parallel() + ctx := context.Background() + gotURL := make(chan *url.URL, 1) + hClient, close := newTestServer(func(w http.ResponseWriter, r *http.Request) { + io.Copy(ioutil.Discard, r.Body) + gotURL <- r.URL + if strings.Contains(r.URL.String(), "/rewriteTo/") { + res := &raw.RewriteResponse{Done: true} + bytes, err := res.MarshalJSON() + if err != nil { + t.Fatal(err) + } + w.Write(bytes) + } else { + fmt.Fprintf(w, "{}") + } + }) + defer close() + client, err := NewClient(ctx, option.WithHTTPClient(hClient)) + if err != nil { + t.Fatal(err) + } + + re := regexp.MustCompile(`\buserProject=p\b`) + b := client.Bucket("b").UserProject("p") + o := b.Object("o") + + check := func(msg string, f func()) { + f() + select { + case u := <-gotURL: + if !re.MatchString(u.RawQuery) { + t.Errorf("%s: query string %q does not contain userProject", msg, u.RawQuery) + } + case <-time.After(2 * time.Second): + t.Errorf("%s: timed out", msg) + } + } + + check("buckets.delete", func() { b.Delete(ctx) }) + check("buckets.get", func() { b.Attrs(ctx) }) + check("buckets.patch", func() { b.Update(ctx, BucketAttrsToUpdate{}) }) + check("storage.objects.compose", func() { o.ComposerFrom(b.Object("x")).Run(ctx) }) + check("storage.objects.delete", func() { o.Delete(ctx) }) + check("storage.objects.get", func() { o.Attrs(ctx) }) + check("storage.objects.insert", func() { o.NewWriter(ctx).Close() }) + check("storage.objects.list", func() { b.Objects(ctx, nil).Next() }) + check("storage.objects.patch", func() { o.Update(ctx, ObjectAttrsToUpdate{}) }) + check("storage.objects.rewrite", func() { o.CopierFrom(b.Object("x")).Run(ctx) }) + check("storage.objectAccessControls.list", func() { o.ACL().List(ctx) }) + check("storage.objectAccessControls.update", func() { o.ACL().Set(ctx, "", "") }) + check("storage.objectAccessControls.delete", func() { o.ACL().Delete(ctx, "") }) + check("storage.bucketAccessControls.list", func() { b.ACL().List(ctx) }) + check("storage.bucketAccessControls.update", func() { b.ACL().Set(ctx, "", "") }) + check("storage.bucketAccessControls.delete", func() { b.ACL().Delete(ctx, "") }) + check("storage.defaultObjectAccessControls.list", + func() { b.DefaultObjectACL().List(ctx) }) + check("storage.defaultObjectAccessControls.update", + func() { b.DefaultObjectACL().Set(ctx, "", "") }) + check("storage.defaultObjectAccessControls.delete", + func() { b.DefaultObjectACL().Delete(ctx, "") }) + check("buckets.getIamPolicy", func() { b.IAM().Policy(ctx) }) + check("buckets.setIamPolicy", func() { + p := &iam.Policy{} + p.Add("m", iam.Owner) + b.IAM().SetPolicy(ctx, p) + }) + check("buckets.testIamPermissions", func() { b.IAM().TestPermissions(ctx, nil) }) + check("storage.notifications.insert", func() { + b.AddNotification(ctx, &Notification{TopicProjectID: "p", TopicID: "t"}) + }) + check("storage.notifications.delete", func() { b.DeleteNotification(ctx, "n") }) + check("storage.notifications.list", func() { b.Notifications(ctx) }) +} + +func newTestServer(handler func(w http.ResponseWriter, r *http.Request)) (*http.Client, func()) { + ts := httptest.NewTLSServer(http.HandlerFunc(handler)) + tlsConf := &tls.Config{InsecureSkipVerify: true} + tr := &http.Transport{ + TLSClientConfig: tlsConf, + DialTLS: func(netw, addr string) (net.Conn, error) { + return tls.Dial("tcp", ts.Listener.Addr().String(), tlsConf) + }, + } + return &http.Client{Transport: tr}, func() { + tr.CloseIdleConnections() + ts.Close() + } +} diff --git a/vendor/cloud.google.com/go/storage/testdata/dummy_pem b/vendor/cloud.google.com/go/storage/testdata/dummy_pem new file mode 100644 index 00000000..3428d449 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/testdata/dummy_pem @@ -0,0 +1,39 @@ +Bag Attributes + friendlyName: privatekey + localKeyID: 54 69 6D 65 20 31 34 31 36 38 35 32 30 30 34 37 37 32 +Key Attributes: +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQCtCWMoJ2Bok2QoGFyU7A6IlGprO9QfUTT0jNrLkIbM5OWNIuDx +64+PEaTS5g5m+2Hz/lmd5jJKanAH4dY9LZzsaYAPq1K17Gcmg1hEisYeKsgOcjYY +kwRkV+natCTsC+tfWmS0voRh0jA1rI1J4MikceoHtgWdEuoHrrptRVpWKwIDAQAB +AoGAKp3uQvx3vSnX+BwP6Um+RpsvHpwMoW3xue1bEdnVqW8SrlERz+NxZw40ZxDs +KSbuuBZD4iTI7BUM5JQVnNm4FQY1YrPlWZLyI73Bj8RKTXrPdJheM/0r7xjiIXbQ +7w4cUSM9rVugnI/rxF2kPIQTGYI+EG/6+P+k6VvgPmC0T/ECQQDUPskiS18WaY+i +Koalbrb3GakaBoHrC1b4ln4CAv7fq7H4WvFvqi/2rxLhHYq31iwxYy8s7J7Sba1+ +5vwJ2TxZAkEA0LVfs3Q2VWZ+cM3bv0aYTalMXg6wT+LoNvk9HnOb0zQYajF3qm4G +ZFdfEqvOkje0zQ4fcihARKyda/VY84UGIwJBAIZa0FvjNmgrnn7bSKzEbxHwrnkJ +EYjGfuGR8mY3mzvfpiM+/oLfSslvfhX+62cALq18yco4ZzlxsFgaxAU//NECQDcS +NN94YcHlGqYPW9W7/gI4EwOaoqFhwV6II71+SfbP/0U+KlJZV+xwNZEKrqZcdqPI +/zkzL8ovNha/laokRrsCQQCyoPHGcBWj+VFbNoyQnX4tghc6rOY7n4pmpgQvU825 +TAM9vnYtSkKK/V56kEDNBO5LwiRsir95IUNclqqMKR1C +-----END RSA PRIVATE KEY----- +Bag Attributes + friendlyName: privatekey + localKeyID: 54 69 6D 65 20 31 34 31 36 38 35 32 30 30 34 37 37 32 +subject=/CN=1079432350659-nvog0vmn9s6pqr3kr4v2avbc7nkhoa11.apps.googleusercontent.com +issuer=/CN=1079432350659-nvog0vmn9s6pqr3kr4v2avbc7nkhoa11.apps.googleusercontent.com +-----BEGIN CERTIFICATE----- +MIICXTCCAcagAwIBAgIIHxTMQUVJRZ0wDQYJKoZIhvcNAQEFBQAwVDFSMFAGA1UE +AxNJMTA3OTQzMjM1MDY1OS1udm9nMHZtbjlzNnBxcjNrcjR2MmF2YmM3bmtob2Ex +MS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbTAeFw0xNDExMjQxODAwMDRaFw0y +NDExMjExODAwMDRaMFQxUjBQBgNVBAMTSTEwNzk0MzIzNTA2NTktbnZvZzB2bW45 +czZwcXIza3I0djJhdmJjN25raG9hMTEuYXBwcy5nb29nbGV1c2VyY29udGVudC5j +b20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAK0JYygnYGiTZCgYXJTsDoiU +ams71B9RNPSM2suQhszk5Y0i4PHrj48RpNLmDmb7YfP+WZ3mMkpqcAfh1j0tnOxp +gA+rUrXsZyaDWESKxh4qyA5yNhiTBGRX6dq0JOwL619aZLS+hGHSMDWsjUngyKRx +6ge2BZ0S6geuum1FWlYrAgMBAAGjODA2MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/ +BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4GB +ACVvKkZkomHq3uffOQwdZ4VJYuxrvDGnZu/ExW9WngO2teEsjxABL41TNnRYHN5T +lMC19poFA2tR/DySDLJ2XNs/hSvyQUL6HHCncVdR4Srpie88j48peY1MZSMP51Jv +qagbbP5K5DSEu02/zZaV0kaCvLEN0KAtj/noDuOOnQU2 +-----END CERTIFICATE----- diff --git a/vendor/cloud.google.com/go/storage/testdata/dummy_rsa b/vendor/cloud.google.com/go/storage/testdata/dummy_rsa new file mode 100644 index 00000000..4ce6678d --- /dev/null +++ b/vendor/cloud.google.com/go/storage/testdata/dummy_rsa @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAx4fm7dngEmOULNmAs1IGZ9Apfzh+BkaQ1dzkmbUgpcoghucE +DZRnAGd2aPyB6skGMXUytWQvNYav0WTR00wFtX1ohWTfv68HGXJ8QXCpyoSKSSFY +fuP9X36wBSkSX9J5DVgiuzD5VBdzUISSmapjKm+DcbRALjz6OUIPEWi1Tjl6p5RK +1w41qdbmt7E5/kGhKLDuT7+M83g4VWhgIvaAXtnhklDAggilPPa8ZJ1IFe31lNlr +k4DRk38nc6sEutdf3RL7QoH7FBusI7uXV03DC6dwN1kP4GE7bjJhcRb/7jYt7CQ9 +/E9Exz3c0yAp0yrTg0Fwh+qxfH9dKwN52S7SBwIDAQABAoIBAQCaCs26K07WY5Jt +3a2Cw3y2gPrIgTCqX6hJs7O5ByEhXZ8nBwsWANBUe4vrGaajQHdLj5OKfsIDrOvn +2NI1MqflqeAbu/kR32q3tq8/Rl+PPiwUsW3E6Pcf1orGMSNCXxeducF2iySySzh3 +nSIhCG5uwJDWI7a4+9KiieFgK1pt/Iv30q1SQS8IEntTfXYwANQrfKUVMmVF9aIK +6/WZE2yd5+q3wVVIJ6jsmTzoDCX6QQkkJICIYwCkglmVy5AeTckOVwcXL0jqw5Kf +5/soZJQwLEyBoQq7Kbpa26QHq+CJONetPP8Ssy8MJJXBT+u/bSseMb3Zsr5cr43e +DJOhwsThAoGBAPY6rPKl2NT/K7XfRCGm1sbWjUQyDShscwuWJ5+kD0yudnT/ZEJ1 +M3+KS/iOOAoHDdEDi9crRvMl0UfNa8MAcDKHflzxg2jg/QI+fTBjPP5GOX0lkZ9g +z6VePoVoQw2gpPFVNPPTxKfk27tEzbaffvOLGBEih0Kb7HTINkW8rIlzAoGBAM9y +1yr+jvfS1cGFtNU+Gotoihw2eMKtIqR03Yn3n0PK1nVCDKqwdUqCypz4+ml6cxRK +J8+Pfdh7D+ZJd4LEG6Y4QRDLuv5OA700tUoSHxMSNn3q9As4+T3MUyYxWKvTeu3U +f2NWP9ePU0lV8ttk7YlpVRaPQmc1qwooBA/z/8AdAoGAW9x0HWqmRICWTBnpjyxx +QGlW9rQ9mHEtUotIaRSJ6K/F3cxSGUEkX1a3FRnp6kPLcckC6NlqdNgNBd6rb2rA +cPl/uSkZP42Als+9YMoFPU/xrrDPbUhu72EDrj3Bllnyb168jKLa4VBOccUvggxr +Dm08I1hgYgdN5huzs7y6GeUCgYEAj+AZJSOJ6o1aXS6rfV3mMRve9bQ9yt8jcKXw +5HhOCEmMtaSKfnOF1Ziih34Sxsb7O2428DiX0mV/YHtBnPsAJidL0SdLWIapBzeg +KHArByIRkwE6IvJvwpGMdaex1PIGhx5i/3VZL9qiq/ElT05PhIb+UXgoWMabCp84 +OgxDK20CgYAeaFo8BdQ7FmVX2+EEejF+8xSge6WVLtkaon8bqcn6P0O8lLypoOhd +mJAYH8WU+UAy9pecUnDZj14LAGNVmYcse8HFX71MoshnvCTFEPVo4rZxIAGwMpeJ +5jgQ3slYLpqrGlcbLgUXBUgzEO684Wk/UV9DFPlHALVqCfXQ9dpJPg== +-----END RSA PRIVATE KEY----- diff --git a/vendor/cloud.google.com/go/storage/writer.go b/vendor/cloud.google.com/go/storage/writer.go new file mode 100644 index 00000000..3a58c404 --- /dev/null +++ b/vendor/cloud.google.com/go/storage/writer.go @@ -0,0 +1,261 @@ +// Copyright 2014 Google LLC +// +// 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 storage + +import ( + "context" + "encoding/base64" + "errors" + "fmt" + "io" + "sync" + "unicode/utf8" + + "google.golang.org/api/googleapi" + raw "google.golang.org/api/storage/v1" +) + +// A Writer writes a Cloud Storage object. +type Writer struct { + // ObjectAttrs are optional attributes to set on the object. Any attributes + // must be initialized before the first Write call. Nil or zero-valued + // attributes are ignored. + ObjectAttrs + + // SendCRC specifies whether to transmit a CRC32C field. It should be set + // to true in addition to setting the Writer's CRC32C field, because zero + // is a valid CRC and normally a zero would not be transmitted. + // If a CRC32C is sent, and the data written does not match the checksum, + // the write will be rejected. + SendCRC32C bool + + // ChunkSize controls the maximum number of bytes of the object that the + // Writer will attempt to send to the server in a single request. Objects + // smaller than the size will be sent in a single request, while larger + // objects will be split over multiple requests. The size will be rounded up + // to the nearest multiple of 256K. If zero, chunking will be disabled and + // the object will be uploaded in a single request. + // + // ChunkSize will default to a reasonable value. If you perform many concurrent + // writes of small objects, you may wish set ChunkSize to a value that matches + // your objects' sizes to avoid consuming large amounts of memory. + // + // ChunkSize must be set before the first Write call. + ChunkSize int + + // ProgressFunc can be used to monitor the progress of a large write. + // operation. If ProgressFunc is not nil and writing requires multiple + // calls to the underlying service (see + // https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload), + // then ProgressFunc will be invoked after each call with the number of bytes of + // content copied so far. + // + // ProgressFunc should return quickly without blocking. + ProgressFunc func(int64) + + ctx context.Context + o *ObjectHandle + + opened bool + pw *io.PipeWriter + + donec chan struct{} // closed after err and obj are set. + obj *ObjectAttrs + + mu sync.Mutex + err error +} + +func (w *Writer) open() error { + attrs := w.ObjectAttrs + // Check the developer didn't change the object Name (this is unfortunate, but + // we don't want to store an object under the wrong name). + if attrs.Name != w.o.object { + return fmt.Errorf("storage: Writer.Name %q does not match object name %q", attrs.Name, w.o.object) + } + if !utf8.ValidString(attrs.Name) { + return fmt.Errorf("storage: object name %q is not valid UTF-8", attrs.Name) + } + if attrs.KMSKeyName != "" && w.o.encryptionKey != nil { + return errors.New("storage: cannot use KMSKeyName with a customer-supplied encryption key") + } + pr, pw := io.Pipe() + w.pw = pw + w.opened = true + + go w.monitorCancel() + + if w.ChunkSize < 0 { + return errors.New("storage: Writer.ChunkSize must be non-negative") + } + mediaOpts := []googleapi.MediaOption{ + googleapi.ChunkSize(w.ChunkSize), + } + if c := attrs.ContentType; c != "" { + mediaOpts = append(mediaOpts, googleapi.ContentType(c)) + } + + go func() { + defer close(w.donec) + + rawObj := attrs.toRawObject(w.o.bucket) + if w.SendCRC32C { + rawObj.Crc32c = encodeUint32(attrs.CRC32C) + } + if w.MD5 != nil { + rawObj.Md5Hash = base64.StdEncoding.EncodeToString(w.MD5) + } + call := w.o.c.raw.Objects.Insert(w.o.bucket, rawObj). + Media(pr, mediaOpts...). + Projection("full"). + Context(w.ctx) + if w.ProgressFunc != nil { + call.ProgressUpdater(func(n, _ int64) { w.ProgressFunc(n) }) + } + if attrs.KMSKeyName != "" { + call.KmsKeyName(attrs.KMSKeyName) + } + if attrs.PredefinedACL != "" { + call.PredefinedAcl(attrs.PredefinedACL) + } + if err := setEncryptionHeaders(call.Header(), w.o.encryptionKey, false); err != nil { + w.mu.Lock() + w.err = err + w.mu.Unlock() + pr.CloseWithError(err) + return + } + var resp *raw.Object + err := applyConds("NewWriter", w.o.gen, w.o.conds, call) + if err == nil { + if w.o.userProject != "" { + call.UserProject(w.o.userProject) + } + setClientHeader(call.Header()) + // If the chunk size is zero, then no chunking is done on the Reader, + // which means we cannot retry: the first call will read the data, and if + // it fails, there is no way to re-read. + if w.ChunkSize == 0 { + resp, err = call.Do() + } else { + // We will only retry here if the initial POST, which obtains a URI for + // the resumable upload, fails with a retryable error. The upload itself + // has its own retry logic. + err = runWithRetry(w.ctx, func() error { + var err2 error + resp, err2 = call.Do() + return err2 + }) + } + } + if err != nil { + w.mu.Lock() + w.err = err + w.mu.Unlock() + pr.CloseWithError(err) + return + } + w.obj = newObject(resp) + }() + return nil +} + +// Write appends to w. It implements the io.Writer interface. +// +// Since writes happen asynchronously, Write may return a nil +// error even though the write failed (or will fail). Always +// use the error returned from Writer.Close to determine if +// the upload was successful. +func (w *Writer) Write(p []byte) (n int, err error) { + w.mu.Lock() + werr := w.err + w.mu.Unlock() + if werr != nil { + return 0, werr + } + if !w.opened { + if err := w.open(); err != nil { + return 0, err + } + } + n, err = w.pw.Write(p) + if err != nil { + w.mu.Lock() + werr := w.err + w.mu.Unlock() + // Preserve existing functionality that when context is canceled, Write will return + // context.Canceled instead of "io: read/write on closed pipe". This hides the + // pipe implementation detail from users and makes Write seem as though it's an RPC. + if werr == context.Canceled || werr == context.DeadlineExceeded { + return n, werr + } + } + return n, err +} + +// Close completes the write operation and flushes any buffered data. +// If Close doesn't return an error, metadata about the written object +// can be retrieved by calling Attrs. +func (w *Writer) Close() error { + if !w.opened { + if err := w.open(); err != nil { + return err + } + } + + // Closing either the read or write causes the entire pipe to close. + if err := w.pw.Close(); err != nil { + return err + } + + <-w.donec + w.mu.Lock() + defer w.mu.Unlock() + return w.err +} + +// monitorCancel is intended to be used as a background goroutine. It monitors the +// the context, and when it observes that the context has been canceled, it manually +// closes things that do not take a context. +func (w *Writer) monitorCancel() { + select { + case <-w.ctx.Done(): + w.mu.Lock() + werr := w.ctx.Err() + w.err = werr + w.mu.Unlock() + + // Closing either the read or write causes the entire pipe to close. + w.CloseWithError(werr) + case <-w.donec: + } +} + +// CloseWithError aborts the write operation with the provided error. +// CloseWithError always returns nil. +// +// Deprecated: cancel the context passed to NewWriter instead. +func (w *Writer) CloseWithError(err error) error { + if !w.opened { + return nil + } + return w.pw.CloseWithError(err) +} + +// Attrs returns metadata about a successfully-written object. +// It's only valid to call it after Close returns nil. +func (w *Writer) Attrs() *ObjectAttrs { + return w.obj +} diff --git a/vendor/cloud.google.com/go/storage/writer_test.go b/vendor/cloud.google.com/go/storage/writer_test.go new file mode 100644 index 00000000..7ac9b7ef --- /dev/null +++ b/vendor/cloud.google.com/go/storage/writer_test.go @@ -0,0 +1,177 @@ +// Copyright 2014 Google LLC +// +// 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 storage + +import ( + "context" + "crypto/sha256" + "encoding/base64" + "net/http" + "strings" + "testing" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/googleapi" + "google.golang.org/api/option" +) + +var testEncryptionKey = []byte("secret-key-that-is-32-bytes-long") + +func TestErrorOnObjectsInsertCall(t *testing.T) { + t.Parallel() + ctx := context.Background() + const contents = "hello world" + + doWrite := func(mt *mockTransport) *Writer { + client := mockClient(t, mt) + wc := client.Bucket("bucketname").Object("filename1").NewWriter(ctx) + wc.ContentType = "text/plain" + + // We can't check that the Write fails, since it depends on the write to the + // underling mockTransport failing which is racy. + wc.Write([]byte(contents)) + return wc + } + + wc := doWrite(&mockTransport{}) + // Close must always return an error though since it waits for the transport to + // have closed. + if err := wc.Close(); err == nil { + t.Errorf("expected error on close, got nil") + } + + // Retry on 5xx + mt := &mockTransport{} + mt.addResult(&http.Response{StatusCode: 503, Body: bodyReader("")}, nil) + mt.addResult(&http.Response{StatusCode: 200, Body: bodyReader("{}")}, nil) + + wc = doWrite(mt) + if err := wc.Close(); err != nil { + t.Errorf("got %v, want nil", err) + } + got := string(mt.gotBody) + if !strings.Contains(got, contents) { + t.Errorf("got body %q, which does not contain %q", got, contents) + } +} + +func TestEncryption(t *testing.T) { + t.Parallel() + ctx := context.Background() + mt := &mockTransport{} + mt.addResult(&http.Response{StatusCode: 200, Body: bodyReader("{}")}, nil) + client := mockClient(t, mt) + obj := client.Bucket("bucketname").Object("filename1") + wc := obj.Key(testEncryptionKey).NewWriter(ctx) + if _, err := wc.Write([]byte("hello world")); err != nil { + t.Fatal(err) + } + if err := wc.Close(); err != nil { + t.Fatal(err) + } + if got, want := mt.gotReq.Header.Get("x-goog-encryption-algorithm"), "AES256"; got != want { + t.Errorf("algorithm: got %q, want %q", got, want) + } + gotKey, err := base64.StdEncoding.DecodeString(mt.gotReq.Header.Get("x-goog-encryption-key")) + if err != nil { + t.Fatalf("decoding key: %v", err) + } + if !testutil.Equal(gotKey, testEncryptionKey) { + t.Errorf("key: got %v, want %v", gotKey, testEncryptionKey) + } + wantHash := sha256.Sum256(testEncryptionKey) + gotHash, err := base64.StdEncoding.DecodeString(mt.gotReq.Header.Get("x-goog-encryption-key-sha256")) + if err != nil { + t.Fatalf("decoding hash: %v", err) + } + if !testutil.Equal(gotHash, wantHash[:]) { // wantHash is an array + t.Errorf("hash: got\n%v, want\n%v", gotHash, wantHash) + } + + // Using a customer-supplied encryption key and a KMS key together is an error. + checkKMSError := func(msg string, err error) { + if err == nil { + t.Errorf("%s: got nil, want error", msg) + } else if !strings.Contains(err.Error(), "KMS") { + t.Errorf(`%s: got %q, want it to contain "KMS"`, msg, err) + } + } + + wc = obj.Key(testEncryptionKey).NewWriter(ctx) + wc.KMSKeyName = "key" + _, err = wc.Write([]byte{}) + checkKMSError("Write", err) + checkKMSError("Close", wc.Close()) +} + +// This test demonstrates the data race on Writer.err that can happen when the +// Writer's context is cancelled. To see the race, comment out the w.mu.Lock/Unlock +// lines in writer.go and run this test with -race. +func TestRaceOnCancel(t *testing.T) { + client := mockClient(t, &mockTransport{}) + cctx, cancel := context.WithCancel(context.Background()) + w := client.Bucket("b").Object("o").NewWriter(cctx) + w.ChunkSize = googleapi.MinUploadChunkSize + buf := make([]byte, w.ChunkSize) + // This Write starts the goroutine in Writer.open. That reads the first chunk in its entirety + // before sending the request (see google.golang.org/api/gensupport.PrepareUpload), + // so to exhibit the race we must provide ChunkSize bytes. The goroutine then makes the RPC (L137). + w.Write(buf) + // Canceling the context causes the call to return context.Canceled, which makes the open goroutine + // write to w.err (L151). + cancel() + // This call to Write concurrently reads w.err (L169). + w.Write([]byte(nil)) +} + +func TestCancelDoesNotLeak(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + const contents = "hello world" + mt := mockTransport{} + + client, err := NewClient(ctx, option.WithHTTPClient(&http.Client{Transport: &mt})) + if err != nil { + t.Fatal(err) + } + + wc := client.Bucket("bucketname").Object("filename1").NewWriter(ctx) + wc.ContentType = "text/plain" + + // We can't check that the Write fails, since it depends on the write to the + // underling mockTransport failing which is racy. + wc.Write([]byte(contents)) + + cancel() +} + +func TestCloseDoesNotLeak(t *testing.T) { + ctx := context.Background() + const contents = "hello world" + mt := mockTransport{} + + client, err := NewClient(ctx, option.WithHTTPClient(&http.Client{Transport: &mt})) + if err != nil { + t.Fatal(err) + } + + wc := client.Bucket("bucketname").Object("filename1").NewWriter(ctx) + wc.ContentType = "text/plain" + + // We can't check that the Write fails, since it depends on the write to the + // underling mockTransport failing which is racy. + wc.Write([]byte(contents)) + + wc.Close() +} diff --git a/vendor/cloud.google.com/go/texttospeech/apiv1/doc.go b/vendor/cloud.google.com/go/texttospeech/apiv1/doc.go new file mode 100644 index 00000000..6eb53757 --- /dev/null +++ b/vendor/cloud.google.com/go/texttospeech/apiv1/doc.go @@ -0,0 +1,90 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package texttospeech is an auto-generated package for the +// Cloud Text-to-Speech API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Synthesizes natural-sounding speech by applying powerful neural network +// models. +package texttospeech // import "cloud.google.com/go/texttospeech/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/texttospeech/apiv1/mock_test.go b/vendor/cloud.google.com/go/texttospeech/apiv1/mock_test.go new file mode 100644 index 00000000..b844387d --- /dev/null +++ b/vendor/cloud.google.com/go/texttospeech/apiv1/mock_test.go @@ -0,0 +1,232 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package texttospeech + +import ( + texttospeechpb "google.golang.org/genproto/googleapis/cloud/texttospeech/v1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockTextToSpeechServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + texttospeechpb.TextToSpeechServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockTextToSpeechServer) ListVoices(ctx context.Context, req *texttospeechpb.ListVoicesRequest) (*texttospeechpb.ListVoicesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*texttospeechpb.ListVoicesResponse), nil +} + +func (s *mockTextToSpeechServer) SynthesizeSpeech(ctx context.Context, req *texttospeechpb.SynthesizeSpeechRequest) (*texttospeechpb.SynthesizeSpeechResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*texttospeechpb.SynthesizeSpeechResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockTextToSpeech mockTextToSpeechServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + texttospeechpb.RegisterTextToSpeechServer(serv, &mockTextToSpeech) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestTextToSpeechListVoices(t *testing.T) { + var expectedResponse *texttospeechpb.ListVoicesResponse = &texttospeechpb.ListVoicesResponse{} + + mockTextToSpeech.err = nil + mockTextToSpeech.reqs = nil + + mockTextToSpeech.resps = append(mockTextToSpeech.resps[:0], expectedResponse) + + var request *texttospeechpb.ListVoicesRequest = &texttospeechpb.ListVoicesRequest{} + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListVoices(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockTextToSpeech.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestTextToSpeechListVoicesError(t *testing.T) { + errCode := codes.PermissionDenied + mockTextToSpeech.err = gstatus.Error(errCode, "test error") + + var request *texttospeechpb.ListVoicesRequest = &texttospeechpb.ListVoicesRequest{} + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListVoices(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestTextToSpeechSynthesizeSpeech(t *testing.T) { + var audioContent []byte = []byte("16") + var expectedResponse = &texttospeechpb.SynthesizeSpeechResponse{ + AudioContent: audioContent, + } + + mockTextToSpeech.err = nil + mockTextToSpeech.reqs = nil + + mockTextToSpeech.resps = append(mockTextToSpeech.resps[:0], expectedResponse) + + var input *texttospeechpb.SynthesisInput = &texttospeechpb.SynthesisInput{} + var voice *texttospeechpb.VoiceSelectionParams = &texttospeechpb.VoiceSelectionParams{} + var audioConfig *texttospeechpb.AudioConfig = &texttospeechpb.AudioConfig{} + var request = &texttospeechpb.SynthesizeSpeechRequest{ + Input: input, + Voice: voice, + AudioConfig: audioConfig, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SynthesizeSpeech(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockTextToSpeech.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestTextToSpeechSynthesizeSpeechError(t *testing.T) { + errCode := codes.PermissionDenied + mockTextToSpeech.err = gstatus.Error(errCode, "test error") + + var input *texttospeechpb.SynthesisInput = &texttospeechpb.SynthesisInput{} + var voice *texttospeechpb.VoiceSelectionParams = &texttospeechpb.VoiceSelectionParams{} + var audioConfig *texttospeechpb.AudioConfig = &texttospeechpb.AudioConfig{} + var request = &texttospeechpb.SynthesizeSpeechRequest{ + Input: input, + Voice: voice, + AudioConfig: audioConfig, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.SynthesizeSpeech(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/texttospeech/apiv1/text_to_speech_client.go b/vendor/cloud.google.com/go/texttospeech/apiv1/text_to_speech_client.go new file mode 100644 index 00000000..00a9dd61 --- /dev/null +++ b/vendor/cloud.google.com/go/texttospeech/apiv1/text_to_speech_client.go @@ -0,0 +1,153 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package texttospeech + +import ( + "context" + "time" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + texttospeechpb "google.golang.org/genproto/googleapis/cloud/texttospeech/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + ListVoices []gax.CallOption + SynthesizeSpeech []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("texttospeech.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &CallOptions{ + ListVoices: retry[[2]string{"default", "idempotent"}], + SynthesizeSpeech: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Cloud Text-to-Speech API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client texttospeechpb.TextToSpeechClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new text to speech client. +// +// Service that implements Google Cloud Text-to-Speech API. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: texttospeechpb.NewTextToSpeechClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// ListVoices returns a list of [Voice][google.cloud.texttospeech.v1.Voice] +// supported for synthesis. +func (c *Client) ListVoices(ctx context.Context, req *texttospeechpb.ListVoicesRequest, opts ...gax.CallOption) (*texttospeechpb.ListVoicesResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListVoices[0:len(c.CallOptions.ListVoices):len(c.CallOptions.ListVoices)], opts...) + var resp *texttospeechpb.ListVoicesResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListVoices(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// SynthesizeSpeech synthesizes speech synchronously: receive results after all text input +// has been processed. +func (c *Client) SynthesizeSpeech(ctx context.Context, req *texttospeechpb.SynthesizeSpeechRequest, opts ...gax.CallOption) (*texttospeechpb.SynthesizeSpeechResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.SynthesizeSpeech[0:len(c.CallOptions.SynthesizeSpeech):len(c.CallOptions.SynthesizeSpeech)], opts...) + var resp *texttospeechpb.SynthesizeSpeechResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.SynthesizeSpeech(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/texttospeech/apiv1/text_to_speech_client_example_test.go b/vendor/cloud.google.com/go/texttospeech/apiv1/text_to_speech_client_example_test.go new file mode 100644 index 00000000..cf07511d --- /dev/null +++ b/vendor/cloud.google.com/go/texttospeech/apiv1/text_to_speech_client_example_test.go @@ -0,0 +1,70 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package texttospeech_test + +import ( + "context" + + texttospeech "cloud.google.com/go/texttospeech/apiv1" + texttospeechpb "google.golang.org/genproto/googleapis/cloud/texttospeech/v1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := texttospeech.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_ListVoices() { + ctx := context.Background() + c, err := texttospeech.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &texttospeechpb.ListVoicesRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.ListVoices(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_SynthesizeSpeech() { + ctx := context.Background() + c, err := texttospeech.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &texttospeechpb.SynthesizeSpeechRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.SynthesizeSpeech(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/trace/apiv1/ListTraces_smoke_test.go b/vendor/cloud.google.com/go/trace/apiv1/ListTraces_smoke_test.go new file mode 100644 index 00000000..76ed3580 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/apiv1/ListTraces_smoke_test.go @@ -0,0 +1,67 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package trace + +import ( + cloudtracepb "google.golang.org/genproto/googleapis/devtools/cloudtrace/v1" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestTraceServiceSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var projectId2 string = projectId + var request = &cloudtracepb.ListTracesRequest{ + ProjectId: projectId2, + } + + iter := c.ListTraces(ctx, request) + if _, err := iter.Next(); err != nil && err != iterator.Done { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/trace/apiv1/doc.go b/vendor/cloud.google.com/go/trace/apiv1/doc.go new file mode 100644 index 00000000..005df208 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/apiv1/doc.go @@ -0,0 +1,97 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package trace is an auto-generated package for the +// Stackdriver Trace API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Sends application trace data to Stackdriver Trace for viewing. Trace data +// is +// collected for all App Engine applications by default. Trace data from +// other +// applications can be provided using this API. +// +// Use the client at cloud.google.com/go/trace in preference to this. +package trace // import "cloud.google.com/go/trace/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/trace.append", + "https://www.googleapis.com/auth/trace.readonly", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/trace/apiv1/mock_test.go b/vendor/cloud.google.com/go/trace/apiv1/mock_test.go new file mode 100644 index 00000000..d42f75b5 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/apiv1/mock_test.go @@ -0,0 +1,321 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package trace + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + cloudtracepb "google.golang.org/genproto/googleapis/devtools/cloudtrace/v1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockTraceServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + cloudtracepb.TraceServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockTraceServer) ListTraces(ctx context.Context, req *cloudtracepb.ListTracesRequest) (*cloudtracepb.ListTracesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*cloudtracepb.ListTracesResponse), nil +} + +func (s *mockTraceServer) GetTrace(ctx context.Context, req *cloudtracepb.GetTraceRequest) (*cloudtracepb.Trace, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*cloudtracepb.Trace), nil +} + +func (s *mockTraceServer) PatchTraces(ctx context.Context, req *cloudtracepb.PatchTracesRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockTrace mockTraceServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + cloudtracepb.RegisterTraceServiceServer(serv, &mockTrace) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestTraceServicePatchTraces(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockTrace.err = nil + mockTrace.reqs = nil + + mockTrace.resps = append(mockTrace.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var traces *cloudtracepb.Traces = &cloudtracepb.Traces{} + var request = &cloudtracepb.PatchTracesRequest{ + ProjectId: projectId, + Traces: traces, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.PatchTraces(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockTrace.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestTraceServicePatchTracesError(t *testing.T) { + errCode := codes.PermissionDenied + mockTrace.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var traces *cloudtracepb.Traces = &cloudtracepb.Traces{} + var request = &cloudtracepb.PatchTracesRequest{ + ProjectId: projectId, + Traces: traces, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.PatchTraces(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestTraceServiceGetTrace(t *testing.T) { + var projectId2 string = "projectId2939242356" + var traceId2 string = "traceId2987826376" + var expectedResponse = &cloudtracepb.Trace{ + ProjectId: projectId2, + TraceId: traceId2, + } + + mockTrace.err = nil + mockTrace.reqs = nil + + mockTrace.resps = append(mockTrace.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var traceId string = "traceId1270300245" + var request = &cloudtracepb.GetTraceRequest{ + ProjectId: projectId, + TraceId: traceId, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetTrace(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockTrace.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestTraceServiceGetTraceError(t *testing.T) { + errCode := codes.PermissionDenied + mockTrace.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var traceId string = "traceId1270300245" + var request = &cloudtracepb.GetTraceRequest{ + ProjectId: projectId, + TraceId: traceId, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetTrace(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestTraceServiceListTraces(t *testing.T) { + var nextPageToken string = "" + var tracesElement *cloudtracepb.Trace = &cloudtracepb.Trace{} + var traces = []*cloudtracepb.Trace{tracesElement} + var expectedResponse = &cloudtracepb.ListTracesResponse{ + NextPageToken: nextPageToken, + Traces: traces, + } + + mockTrace.err = nil + mockTrace.reqs = nil + + mockTrace.resps = append(mockTrace.resps[:0], expectedResponse) + + var projectId string = "projectId-1969970175" + var request = &cloudtracepb.ListTracesRequest{ + ProjectId: projectId, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTraces(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockTrace.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Traces[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestTraceServiceListTracesError(t *testing.T) { + errCode := codes.PermissionDenied + mockTrace.err = gstatus.Error(errCode, "test error") + + var projectId string = "projectId-1969970175" + var request = &cloudtracepb.ListTracesRequest{ + ProjectId: projectId, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListTraces(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/trace/apiv1/trace_client.go b/vendor/cloud.google.com/go/trace/apiv1/trace_client.go new file mode 100644 index 00000000..73d654eb --- /dev/null +++ b/vendor/cloud.google.com/go/trace/apiv1/trace_client.go @@ -0,0 +1,239 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package trace + +import ( + "context" + "math" + "time" + + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + cloudtracepb "google.golang.org/genproto/googleapis/devtools/cloudtrace/v1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + PatchTraces []gax.CallOption + GetTrace []gax.CallOption + ListTraces []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("cloudtrace.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 1000 * time.Millisecond, + Multiplier: 1.2, + }) + }), + }, + } + return &CallOptions{ + PatchTraces: retry[[2]string{"default", "idempotent"}], + GetTrace: retry[[2]string{"default", "idempotent"}], + ListTraces: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Stackdriver Trace API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client cloudtracepb.TraceServiceClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new trace service client. +// +// This file describes an API for collecting and viewing traces and spans +// within a trace. A Trace is a collection of spans corresponding to a single +// operation or set of operations for an application. A span is an individual +// timed event which forms a node of the trace tree. Spans for a single trace +// may span multiple services. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: cloudtracepb.NewTraceServiceClient(conn), + } + c.SetGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// SetGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) SetGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// PatchTraces sends new traces to Stackdriver Trace or updates existing traces. If the ID +// of a trace that you send matches that of an existing trace, any fields +// in the existing trace and its spans are overwritten by the provided values, +// and any new fields provided are merged with the existing trace data. If the +// ID does not match, a new trace is created. +func (c *Client) PatchTraces(ctx context.Context, req *cloudtracepb.PatchTracesRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.PatchTraces[0:len(c.CallOptions.PatchTraces):len(c.CallOptions.PatchTraces)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.PatchTraces(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// GetTrace gets a single trace by its ID. +func (c *Client) GetTrace(ctx context.Context, req *cloudtracepb.GetTraceRequest, opts ...gax.CallOption) (*cloudtracepb.Trace, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetTrace[0:len(c.CallOptions.GetTrace):len(c.CallOptions.GetTrace)], opts...) + var resp *cloudtracepb.Trace + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.GetTrace(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListTraces returns of a list of traces that match the specified filter conditions. +func (c *Client) ListTraces(ctx context.Context, req *cloudtracepb.ListTracesRequest, opts ...gax.CallOption) *TraceIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListTraces[0:len(c.CallOptions.ListTraces):len(c.CallOptions.ListTraces)], opts...) + it := &TraceIterator{} + req = proto.Clone(req).(*cloudtracepb.ListTracesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*cloudtracepb.Trace, string, error) { + var resp *cloudtracepb.ListTracesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.ListTraces(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Traces, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// TraceIterator manages a stream of *cloudtracepb.Trace. +type TraceIterator struct { + items []*cloudtracepb.Trace + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*cloudtracepb.Trace, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TraceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TraceIterator) Next() (*cloudtracepb.Trace, error) { + var item *cloudtracepb.Trace + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TraceIterator) bufLen() int { + return len(it.items) +} + +func (it *TraceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/vendor/cloud.google.com/go/trace/apiv1/trace_client_example_test.go b/vendor/cloud.google.com/go/trace/apiv1/trace_client_example_test.go new file mode 100644 index 00000000..98b134c1 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/apiv1/trace_client_example_test.go @@ -0,0 +1,93 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package trace_test + +import ( + "context" + + trace "cloud.google.com/go/trace/apiv1" + "google.golang.org/api/iterator" + cloudtracepb "google.golang.org/genproto/googleapis/devtools/cloudtrace/v1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := trace.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_PatchTraces() { + ctx := context.Background() + c, err := trace.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &cloudtracepb.PatchTracesRequest{ + // TODO: Fill request struct fields. + } + err = c.PatchTraces(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_GetTrace() { + ctx := context.Background() + c, err := trace.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &cloudtracepb.GetTraceRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetTrace(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleClient_ListTraces() { + ctx := context.Background() + c, err := trace.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &cloudtracepb.ListTracesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListTraces(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} diff --git a/vendor/cloud.google.com/go/trace/apiv2/BatchWriteSpans_smoke_test.go b/vendor/cloud.google.com/go/trace/apiv2/BatchWriteSpans_smoke_test.go new file mode 100644 index 00000000..9c143858 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/apiv2/BatchWriteSpans_smoke_test.go @@ -0,0 +1,66 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package trace + +import ( + cloudtracepb "google.golang.org/genproto/googleapis/devtools/cloudtrace/v2" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestTraceServiceSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var formattedName string = fmt.Sprintf("projects/%s", projectId) + var request = &cloudtracepb.BatchWriteSpansRequest{ + Name: formattedName, + } + + if err := c.BatchWriteSpans(ctx, request); err != nil { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/trace/apiv2/doc.go b/vendor/cloud.google.com/go/trace/apiv2/doc.go new file mode 100644 index 00000000..553d9de7 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/apiv2/doc.go @@ -0,0 +1,94 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package trace is an auto-generated package for the +// Stackdriver Trace API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Sends application trace data to Stackdriver Trace for viewing. Trace data +// is +// collected for all App Engine applications by default. Trace data from +// other +// applications can be provided using this API. +package trace // import "cloud.google.com/go/trace/apiv2" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/trace.append", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/trace/apiv2/mock_test.go b/vendor/cloud.google.com/go/trace/apiv2/mock_test.go new file mode 100644 index 00000000..b1e430dc --- /dev/null +++ b/vendor/cloud.google.com/go/trace/apiv2/mock_test.go @@ -0,0 +1,252 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package trace + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + timestamppb "github.com/golang/protobuf/ptypes/timestamp" + cloudtracepb "google.golang.org/genproto/googleapis/devtools/cloudtrace/v2" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockTraceServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + cloudtracepb.TraceServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockTraceServer) BatchWriteSpans(ctx context.Context, req *cloudtracepb.BatchWriteSpansRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockTraceServer) CreateSpan(ctx context.Context, req *cloudtracepb.Span) (*cloudtracepb.Span, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*cloudtracepb.Span), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockTrace mockTraceServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + cloudtracepb.RegisterTraceServiceServer(serv, &mockTrace) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestTraceServiceBatchWriteSpans(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockTrace.err = nil + mockTrace.reqs = nil + + mockTrace.resps = append(mockTrace.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var spans []*cloudtracepb.Span = nil + var request = &cloudtracepb.BatchWriteSpansRequest{ + Name: formattedName, + Spans: spans, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.BatchWriteSpans(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockTrace.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestTraceServiceBatchWriteSpansError(t *testing.T) { + errCode := codes.PermissionDenied + mockTrace.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s", "[PROJECT]") + var spans []*cloudtracepb.Span = nil + var request = &cloudtracepb.BatchWriteSpansRequest{ + Name: formattedName, + Spans: spans, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.BatchWriteSpans(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestTraceServiceCreateSpan(t *testing.T) { + var name2 string = "name2-1052831874" + var spanId2 string = "spanId2-643891741" + var parentSpanId string = "parentSpanId-1757797477" + var expectedResponse = &cloudtracepb.Span{ + Name: name2, + SpanId: spanId2, + ParentSpanId: parentSpanId, + } + + mockTrace.err = nil + mockTrace.reqs = nil + + mockTrace.resps = append(mockTrace.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/traces/%s/spans/%s", "[PROJECT]", "[TRACE]", "[SPAN]") + var spanId string = "spanId-2011840976" + var displayName *cloudtracepb.TruncatableString = &cloudtracepb.TruncatableString{} + var startTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var endTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var request = &cloudtracepb.Span{ + Name: formattedName, + SpanId: spanId, + DisplayName: displayName, + StartTime: startTime, + EndTime: endTime, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSpan(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockTrace.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestTraceServiceCreateSpanError(t *testing.T) { + errCode := codes.PermissionDenied + mockTrace.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/traces/%s/spans/%s", "[PROJECT]", "[TRACE]", "[SPAN]") + var spanId string = "spanId-2011840976" + var displayName *cloudtracepb.TruncatableString = &cloudtracepb.TruncatableString{} + var startTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var endTime *timestamppb.Timestamp = ×tamppb.Timestamp{} + var request = &cloudtracepb.Span{ + Name: formattedName, + SpanId: spanId, + DisplayName: displayName, + StartTime: startTime, + EndTime: endTime, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateSpan(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/trace/apiv2/path_funcs.go b/vendor/cloud.google.com/go/trace/apiv2/path_funcs.go new file mode 100644 index 00000000..80b8d40b --- /dev/null +++ b/vendor/cloud.google.com/go/trace/apiv2/path_funcs.go @@ -0,0 +1,43 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace + +// ProjectPath returns the path for the project resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s", project) +// instead. +func ProjectPath(project string) string { + return "" + + "projects/" + + project + + "" +} + +// SpanPath returns the path for the span resource. +// +// Deprecated: Use +// fmt.Sprintf("projects/%s/traces/%s/spans/%s", project, trace, span) +// instead. +func SpanPath(project, trace, span string) string { + return "" + + "projects/" + + project + + "/traces/" + + trace + + "/spans/" + + span + + "" +} diff --git a/vendor/cloud.google.com/go/trace/apiv2/trace_client.go b/vendor/cloud.google.com/go/trace/apiv2/trace_client.go new file mode 100644 index 00000000..1581d672 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/apiv2/trace_client.go @@ -0,0 +1,152 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package trace + +import ( + "context" + "time" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + cloudtracepb "google.golang.org/genproto/googleapis/devtools/cloudtrace/v2" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + BatchWriteSpans []gax.CallOption + CreateSpan []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("cloudtrace.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 1000 * time.Millisecond, + Multiplier: 1.2, + }) + }), + }, + } + return &CallOptions{ + BatchWriteSpans: retry[[2]string{"default", "non_idempotent"}], + CreateSpan: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Stackdriver Trace API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client cloudtracepb.TraceServiceClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new trace service client. +// +// This file describes an API for collecting and viewing traces and spans +// within a trace. A Trace is a collection of spans corresponding to a single +// operation or set of operations for an application. A span is an individual +// timed event which forms a node of the trace tree. A single trace may +// contain span(s) from multiple services. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: cloudtracepb.NewTraceServiceClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// BatchWriteSpans sends new spans to new or existing traces. You cannot update +// existing spans. +func (c *Client) BatchWriteSpans(ctx context.Context, req *cloudtracepb.BatchWriteSpansRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchWriteSpans[0:len(c.CallOptions.BatchWriteSpans):len(c.CallOptions.BatchWriteSpans)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.client.BatchWriteSpans(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// CreateSpan creates a new span. +func (c *Client) CreateSpan(ctx context.Context, req *cloudtracepb.Span, opts ...gax.CallOption) (*cloudtracepb.Span, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateSpan[0:len(c.CallOptions.CreateSpan):len(c.CallOptions.CreateSpan)], opts...) + var resp *cloudtracepb.Span + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.CreateSpan(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/trace/apiv2/trace_client_example_test.go b/vendor/cloud.google.com/go/trace/apiv2/trace_client_example_test.go new file mode 100644 index 00000000..ae2413ec --- /dev/null +++ b/vendor/cloud.google.com/go/trace/apiv2/trace_client_example_test.go @@ -0,0 +1,68 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package trace_test + +import ( + "context" + + trace "cloud.google.com/go/trace/apiv2" + cloudtracepb "google.golang.org/genproto/googleapis/devtools/cloudtrace/v2" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := trace.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_BatchWriteSpans() { + ctx := context.Background() + c, err := trace.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &cloudtracepb.BatchWriteSpansRequest{ + // TODO: Fill request struct fields. + } + err = c.BatchWriteSpans(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleClient_CreateSpan() { + ctx := context.Background() + c, err := trace.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &cloudtracepb.Span{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateSpan(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/trace/grpc.go b/vendor/cloud.google.com/go/trace/grpc.go new file mode 100644 index 00000000..e7c00310 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/grpc.go @@ -0,0 +1,111 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace + +import ( + "context" + "encoding/hex" + "fmt" + + "cloud.google.com/go/internal/tracecontext" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +const grpcMetadataKey = "grpc-trace-bin" + +// GRPCClientInterceptor returns a grpc.UnaryClientInterceptor that traces all outgoing requests from a gRPC client. +// The calling context should already have a *trace.Span; a child span will be +// created for the outgoing gRPC call. If the calling context doesn't have a span, +// the call will not be traced. If the client is nil, then the interceptor just +// passes through the request. +// +// The functionality in gRPC that this feature relies on is currently experimental. +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (c *Client) GRPCClientInterceptor() grpc.UnaryClientInterceptor { + if c == nil { + return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + return invoker(ctx, method, req, reply, cc, opts...) + } + } + return grpc.UnaryClientInterceptor(c.grpcUnaryInterceptor) +} + +func (c *Client) grpcUnaryInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + // TODO: also intercept streams. + span := FromContext(ctx).NewChild(method) + if span == nil { + span = c.NewSpan(method) + } + defer span.Finish() + + traceContext := make([]byte, tracecontext.Len) + // traceID is a hex-encoded 128-bit value. + // TODO(jbd): Decode trace IDs upon arrival and + // represent trace IDs with 16 bytes internally. + tid, err := hex.DecodeString(span.trace.traceID) + if err != nil { + return invoker(ctx, method, req, reply, cc, opts...) + } + tracecontext.Encode(traceContext, tid, span.span.SpanId, byte(span.trace.globalOptions)) + md, ok := metadata.FromOutgoingContext(ctx) + if !ok { + md = metadata.Pairs(grpcMetadataKey, string(traceContext)) + } else { + md = md.Copy() // metadata is immutable, copy. + md[grpcMetadataKey] = []string{string(traceContext)} + } + ctx = metadata.NewOutgoingContext(ctx, md) + + err = invoker(ctx, method, req, reply, cc, opts...) + if err != nil { + // TODO: standardize gRPC label names? + span.SetLabel("error", err.Error()) + } + return err +} + +// GRPCServerInterceptor returns a grpc.UnaryServerInterceptor that enables the tracing of the incoming +// gRPC calls. Incoming call's context can be used to extract the span on servers that enabled this option: +// +// span := trace.FromContext(ctx) +// +// If the client is nil, then the interceptor just invokes the handler. +// +// The functionality in gRPC that this feature relies on is currently experimental. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (c *Client) GRPCServerInterceptor() grpc.UnaryServerInterceptor { + if c == nil { + return func(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + return handler(ctx, req) + } + } + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + md, _ := metadata.FromIncomingContext(ctx) + var traceHeader string + if header, ok := md[grpcMetadataKey]; ok { + traceID, spanID, opts, ok := tracecontext.Decode([]byte(header[0])) + if ok { + // TODO(jbd): Generate a span directly from string(traceID), spanID and opts. + traceHeader = fmt.Sprintf("%x/%d;o=%d", traceID, spanID, opts) + } + } + span := c.SpanFromHeader(info.FullMethod, traceHeader) + defer span.Finish() + ctx = NewContext(ctx, span) + return handler(ctx, req) + } +} diff --git a/vendor/cloud.google.com/go/trace/grpc_test.go b/vendor/cloud.google.com/go/trace/grpc_test.go new file mode 100644 index 00000000..51ba2ed5 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/grpc_test.go @@ -0,0 +1,180 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace + +import ( + "context" + "io/ioutil" + "log" + "net" + "net/http" + "strings" + "testing" + + pb "cloud.google.com/go/trace/testdata/helloworld" + "google.golang.org/grpc" +) + +func TestGRPCInterceptors(t *testing.T) { + t.Skip("hangs forever for go < 1.9") + + tc := newTestClient(&noopTransport{}) + + // default sampling with global=1. + parent := tc.SpanFromHeader("parent", "7f27601f17b7a2873739efd18ff83872/123;o=1") + testGRPCInterceptor(t, tc, parent, func(t *testing.T, out, in *Span) { + if in == nil { + t.Fatalf("missing span in the incoming context") + } + if got, want := in.TraceID(), out.TraceID(); got != want { + t.Errorf("incoming call is not tracing the outgoing trace; TraceID = %q; want %q", got, want) + } + if !in.Traced() { + t.Errorf("incoming span is not traced; want traced") + } + }) + + // default sampling with global=0. + parent = tc.SpanFromHeader("parent", "7f27601f17b7a2873739efd18ff83872/123;o=0") + testGRPCInterceptor(t, tc, parent, func(t *testing.T, out, in *Span) { + if in == nil { + t.Fatalf("missing span in the incoming context") + } + if got, want := in.TraceID(), out.TraceID(); got != want { + t.Errorf("incoming call is not tracing the outgoing trace; TraceID = %q; want %q", got, want) + } + if in.Traced() { + t.Errorf("incoming span is traced; want not traced") + } + }) + + // sampling all with global=1. + all, _ := NewLimitedSampler(1.0, 1<<32) + tc.SetSamplingPolicy(all) + parent = tc.SpanFromHeader("parent", "7f27601f17b7a2873739efd18ff83872/123;o=1") + testGRPCInterceptor(t, tc, parent, func(t *testing.T, out, in *Span) { + if in == nil { + t.Fatalf("missing span in the incoming context") + } + if got, want := in.TraceID(), out.TraceID(); got != want { + t.Errorf("incoming call is not tracing the outgoing trace; TraceID = %q; want %q", got, want) + } + if !in.Traced() { + t.Errorf("incoming span is not traced; want traced") + } + }) + + // sampling none with global=1. + none, _ := NewLimitedSampler(0, 0) + tc.SetSamplingPolicy(none) + parent = tc.SpanFromHeader("parent", "7f27601f17b7a2873739efd18ff83872/123;o=1") + testGRPCInterceptor(t, tc, parent, func(t *testing.T, out, in *Span) { + if in == nil { + t.Fatalf("missing span in the incoming context") + } + if got, want := in.TraceID(), out.TraceID(); got != want { + t.Errorf("incoming call is not tracing the outgoing trace; TraceID = %q; want %q", got, want) + } + if in.Traced() { + t.Errorf("incoming span is traced; want not traced") + } + }) + + // sampling all with no parent span. + tc.SetSamplingPolicy(all) + testGRPCInterceptor(t, tc, nil, func(t *testing.T, out, in *Span) { + if in == nil { + t.Fatalf("missing span in the incoming context") + } + if in.TraceID() == "" { + t.Errorf("incoming call TraceID is empty") + } + if !in.Traced() { + t.Errorf("incoming span is not traced; want traced") + } + }) + + // sampling none with no parent span. + tc.SetSamplingPolicy(none) + testGRPCInterceptor(t, tc, nil, func(t *testing.T, out, in *Span) { + if in == nil { + t.Fatalf("missing span in the incoming context") + } + if in.TraceID() == "" { + t.Errorf("incoming call TraceID is empty") + } + if in.Traced() { + t.Errorf("incoming span is traced; want not traced") + } + }) +} + +func testGRPCInterceptor(t *testing.T, tc *Client, parent *Span, assert func(t *testing.T, out, in *Span)) { + incomingCh := make(chan *Span, 1) + addrCh := make(chan net.Addr, 1) + go func() { + lis, err := net.Listen("tcp", "") + if err != nil { + t.Errorf("Failed to listen: %v", err) + } + addrCh <- lis.Addr() + + s := grpc.NewServer(grpc.UnaryInterceptor(tc.GRPCServerInterceptor())) + pb.RegisterGreeterServer(s, &grpcServer{ + fn: func(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { + incomingCh <- FromContext(ctx) + return &pb.HelloReply{}, nil + }, + }) + if err := s.Serve(lis); err != nil { + t.Errorf("Failed to serve: %v", err) + } + }() + + addr := <-addrCh + conn, err := grpc.Dial(addr.String(), grpc.WithInsecure(), grpc.WithBlock(), grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor())) + if err != nil { + t.Fatalf("Did not connect: %v", err) + } + defer conn.Close() + c := pb.NewGreeterClient(conn) + + outgoingCtx := NewContext(context.Background(), parent) + _, err = c.SayHello(outgoingCtx, &pb.HelloRequest{}) + if err != nil { + log.Fatalf("Could not SayHello: %v", err) + } + + assert(t, parent, <-incomingCh) +} + +type noopTransport struct{} + +func (rt *noopTransport) RoundTrip(req *http.Request) (*http.Response, error) { + resp := &http.Response{ + Status: "200 OK", + StatusCode: 200, + Body: ioutil.NopCloser(strings.NewReader("{}")), + } + return resp, nil +} + +type grpcServer struct { + fn func(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) +} + +func (s *grpcServer) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { + return s.fn(ctx, in) +} diff --git a/vendor/cloud.google.com/go/trace/http.go b/vendor/cloud.google.com/go/trace/http.go new file mode 100644 index 00000000..6a64465a --- /dev/null +++ b/vendor/cloud.google.com/go/trace/http.go @@ -0,0 +1,114 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace + +import ( + "net/http" +) + +// Transport is an http.RoundTripper that traces the outgoing requests. +// +// Transport is safe for concurrent usage. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +type Transport struct { + // Base is the base http.RoundTripper to be used to do the actual request. + // + // Optional. If nil, http.DefaultTransport is used. + Base http.RoundTripper +} + +// RoundTrip creates a trace.Span and inserts it into the outgoing request's headers. +// The created span can follow a parent span, if a parent is presented in +// the request's context. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (t Transport) RoundTrip(req *http.Request) (*http.Response, error) { + span := FromContext(req.Context()).NewRemoteChild(req) + resp, err := t.base().RoundTrip(req) + + // TODO(jbd): Is it possible to defer the span.Finish? + // In cases where RoundTrip panics, we still can finish the span. + span.Finish(WithResponse(resp)) + return resp, err +} + +// CancelRequest cancels an in-flight request by closing its connection. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (t Transport) CancelRequest(req *http.Request) { + type canceler interface { + CancelRequest(*http.Request) + } + if cr, ok := t.base().(canceler); ok { + cr.CancelRequest(req) + } +} + +func (t Transport) base() http.RoundTripper { + if t.Base != nil { + return t.Base + } + return http.DefaultTransport +} + +// HTTPHandler returns a http.Handler from the given handler +// that is aware of the incoming request's span. +// The span can be extracted from the incoming request in handler +// functions from incoming request's context: +// +// span := trace.FromContext(r.Context()) +// +// The span will be auto finished by the handler. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (c *Client) HTTPHandler(h http.Handler) http.Handler { + if c == nil { + return h + } + return &handler{traceClient: c, handler: h} +} + +type handler struct { + traceClient *Client + handler http.Handler +} + +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + traceID, parentSpanID, options, optionsOk, ok := traceInfoFromHeader(r.Header.Get(httpHeader)) + if !ok { + traceID = nextTraceID() + } + t := &trace{ + traceID: traceID, + client: h.traceClient, + globalOptions: options, + localOptions: options, + } + span := startNewChildWithRequest(r, t, parentSpanID) + span.span.Kind = spanKindServer + span.rootSpan = true + configureSpanFromPolicy(span, h.traceClient.policy, ok) + defer span.Finish() + + r = r.WithContext(NewContext(r.Context(), span)) + if ok && !optionsOk { + // Inject the trace context back to the response with the sampling options. + // TODO(jbd): Remove when there is a better way to report the client's sampling. + w.Header().Set(httpHeader, spanHeader(traceID, parentSpanID, span.trace.localOptions)) + } + h.handler.ServeHTTP(w, r) +} diff --git a/vendor/cloud.google.com/go/trace/http_test.go b/vendor/cloud.google.com/go/trace/http_test.go new file mode 100644 index 00000000..93cc1b09 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/http_test.go @@ -0,0 +1,149 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace + +import ( + "io/ioutil" + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +type recorderTransport struct { + ch chan *http.Request +} + +func (rt *recorderTransport) RoundTrip(req *http.Request) (*http.Response, error) { + rt.ch <- req + resp := &http.Response{ + Status: "200 OK", + StatusCode: 200, + Body: ioutil.NopCloser(strings.NewReader("{}")), + } + return resp, nil +} + +func TestNewHTTPClient(t *testing.T) { + rt := &recorderTransport{ + ch: make(chan *http.Request, 1), + } + + tc := newTestClient(&noopTransport{}) + client := &http.Client{ + Transport: &Transport{ + Base: rt, + }, + } + req, _ := http.NewRequest("GET", "http://example.com", nil) + + t.Run("NoTrace", func(t *testing.T) { + _, err := client.Do(req) + if err != nil { + t.Error(err) + } + outgoing := <-rt.ch + if got, want := outgoing.Header.Get(httpHeader), ""; want != got { + t.Errorf("got trace header = %q; want none", got) + } + }) + + t.Run("Trace", func(t *testing.T) { + span := tc.NewSpan("/foo") + + req = req.WithContext(NewContext(req.Context(), span)) + _, err := client.Do(req) + if err != nil { + t.Error(err) + } + outgoing := <-rt.ch + + s := tc.SpanFromHeader("/foo", outgoing.Header.Get(httpHeader)) + if got, want := s.TraceID(), span.TraceID(); got != want { + t.Errorf("trace ID = %q; want %q", got, want) + } + }) +} + +func TestHTTPHandlerNoTrace(t *testing.T) { + tc := newTestClient(&noopTransport{}) + client := &http.Client{ + Transport: &Transport{}, + } + handler := tc.HTTPHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + span := FromContext(r.Context()) + if span == nil { + t.Errorf("span is nil; want non-nil span") + } + })) + + ts := httptest.NewServer(handler) + defer ts.Close() + + req, _ := http.NewRequest("GET", ts.URL, nil) + _, err := client.Do(req) + if err != nil { + t.Fatal(err) + } +} + +func TestHTTPHandler_response(t *testing.T) { + tc := newTestClient(&noopTransport{}) + p, _ := NewLimitedSampler(1, 1<<32) // all + tc.SetSamplingPolicy(p) + handler := tc.HTTPHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) + ts := httptest.NewServer(handler) + defer ts.Close() + + tests := []struct { + name string + traceHeader string + wantTraceHeader string + }{ + { + name: "no global", + traceHeader: "0123456789ABCDEF0123456789ABCDEF/123", + wantTraceHeader: "0123456789ABCDEF0123456789ABCDEF/123;o=1", + }, + { + name: "global=1", + traceHeader: "0123456789ABCDEF0123456789ABCDEF/123;o=1", + wantTraceHeader: "", + }, + { + name: "global=0", + traceHeader: "0123456789ABCDEF0123456789ABCDEF/123;o=0", + wantTraceHeader: "", + }, + { + name: "no trace context", + traceHeader: "", + wantTraceHeader: "", + }, + } + + for _, tt := range tests { + req, _ := http.NewRequest("GET", ts.URL, nil) + req.Header.Set(httpHeader, tt.traceHeader) + + res, err := http.DefaultClient.Do(req) + if err != nil { + t.Errorf("failed to request: %v", err) + } + if got, want := res.Header.Get(httpHeader), tt.wantTraceHeader; got != want { + t.Errorf("%v: response context header = %q; want %q", tt.name, got, want) + } + } +} diff --git a/vendor/cloud.google.com/go/trace/httpexample_test.go b/vendor/cloud.google.com/go/trace/httpexample_test.go new file mode 100644 index 00000000..2af4ead6 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/httpexample_test.go @@ -0,0 +1,55 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace_test + +import ( + "log" + "net/http" + + "cloud.google.com/go/trace" +) + +var traceClient *trace.Client + +func ExampleHTTPClient_Do() { + client := http.Client{ + Transport: &trace.Transport{}, + } + span := traceClient.NewSpan("/foo") // traceClient is a *trace.Client + + req, _ := http.NewRequest("GET", "https://metadata/users", nil) + req = req.WithContext(trace.NewContext(req.Context(), span)) + + if _, err := client.Do(req); err != nil { + log.Fatal(err) + } +} + +func ExampleClient_HTTPHandler() { + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + client := http.Client{ + Transport: &trace.Transport{}, + } + + req, _ := http.NewRequest("GET", "https://metadata/users", nil) + req = req.WithContext(r.Context()) + + // The outgoing request will be traced with r's trace ID. + if _, err := client.Do(req); err != nil { + log.Fatal(err) + } + }) + http.Handle("/foo", traceClient.HTTPHandler(handler)) // traceClient is a *trace.Client +} diff --git a/vendor/cloud.google.com/go/trace/sampling.go b/vendor/cloud.google.com/go/trace/sampling.go new file mode 100644 index 00000000..802144b2 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/sampling.go @@ -0,0 +1,127 @@ +// Copyright 2016 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace + +import ( + crand "crypto/rand" + "encoding/binary" + "fmt" + "math/rand" + "sync" + "time" + + "golang.org/x/time/rate" +) + +// SamplingPolicy provides an interface for sampling. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +type SamplingPolicy interface { + // Sample returns a Decision. + // If Trace is false in the returned Decision, then the Decision should be + // the zero value. + Sample(p Parameters) Decision +} + +// Parameters contains the values passed to a SamplingPolicy's Sample method. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +type Parameters struct { + HasTraceHeader bool // whether the incoming request has a valid X-Cloud-Trace-Context header. +} + +// Decision is the value returned by a call to a SamplingPolicy's Sample method. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +type Decision struct { + Trace bool // Whether to trace the request. + Sample bool // Whether the trace is included in the random sample. + Policy string // Name of the sampling policy. + Weight float64 // Sample weight to be used in statistical calculations. +} + +type sampler struct { + fraction float64 + skipped float64 + *rate.Limiter + *rand.Rand + sync.Mutex +} + +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (s *sampler) Sample(p Parameters) Decision { + s.Lock() + x := s.Float64() + d := s.sample(p, time.Now(), x) + s.Unlock() + return d +} + +// sample contains the a deterministic, time-independent logic of Sample. +func (s *sampler) sample(p Parameters, now time.Time, x float64) (d Decision) { + d.Sample = x < s.fraction + d.Trace = p.HasTraceHeader || d.Sample + if !d.Trace { + // We have no reason to trace this request. + return Decision{} + } + // We test separately that the rate limit is not tiny before calling AllowN, + // because of overflow problems in x/time/rate. + if s.Limit() < 1e-9 || !s.AllowN(now, 1) { + // Rejected by the rate limit. + if d.Sample { + s.skipped++ + } + return Decision{} + } + if d.Sample { + d.Policy, d.Weight = "default", (1.0+s.skipped)/s.fraction + s.skipped = 0.0 + } + return +} + +// NewLimitedSampler returns a sampling policy that randomly samples a given +// fraction of requests. It also enforces a limit on the number of traces per +// second. It tries to trace every request with a trace header, but will not +// exceed the qps limit to do it. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func NewLimitedSampler(fraction, maxqps float64) (SamplingPolicy, error) { + if !(fraction >= 0) { + return nil, fmt.Errorf("invalid fraction %f", fraction) + } + if !(maxqps >= 0) { + return nil, fmt.Errorf("invalid maxqps %f", maxqps) + } + // Set a limit on the number of accumulated "tokens", to limit bursts of + // traced requests. Use one more than a second's worth of tokens, or 100, + // whichever is smaller. + // See https://godoc.org/golang.org/x/time/rate#NewLimiter. + maxTokens := 100 + if maxqps < 99.0 { + maxTokens = 1 + int(maxqps) + } + var seed int64 + if err := binary.Read(crand.Reader, binary.LittleEndian, &seed); err != nil { + seed = time.Now().UnixNano() + } + s := sampler{ + fraction: fraction, + Limiter: rate.NewLimiter(rate.Limit(maxqps), maxTokens), + Rand: rand.New(rand.NewSource(seed)), + } + return &s, nil +} diff --git a/vendor/cloud.google.com/go/trace/testdata/helloworld/helloworld.pb.go b/vendor/cloud.google.com/go/trace/testdata/helloworld/helloworld.pb.go new file mode 100644 index 00000000..2ece7a51 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/testdata/helloworld/helloworld.pb.go @@ -0,0 +1,162 @@ +// Copyright 2017 Google LLC +// +// 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 helloworld is a generated protocol buffer package. + +It is generated from these files: + helloworld.proto + +It has these top-level messages: + HelloRequest + HelloReply +*/ +package helloworld + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + "context" + + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// The request message containing the user's name. +type HelloRequest struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` +} + +func (m *HelloRequest) Reset() { *m = HelloRequest{} } +func (m *HelloRequest) String() string { return proto.CompactTextString(m) } +func (*HelloRequest) ProtoMessage() {} +func (*HelloRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +// The response message containing the greetings +type HelloReply struct { + Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` +} + +func (m *HelloReply) Reset() { *m = HelloReply{} } +func (m *HelloReply) String() string { return proto.CompactTextString(m) } +func (*HelloReply) ProtoMessage() {} +func (*HelloReply) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func init() { + proto.RegisterType((*HelloRequest)(nil), "helloworld.HelloRequest") + proto.RegisterType((*HelloReply)(nil), "helloworld.HelloReply") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for Greeter service + +type GreeterClient interface { + // Sends a greeting + SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) +} + +type greeterClient struct { + cc *grpc.ClientConn +} + +func NewGreeterClient(cc *grpc.ClientConn) GreeterClient { + return &greeterClient{cc} +} + +func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) { + out := new(HelloReply) + err := grpc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Greeter service + +type GreeterServer interface { + // Sends a greeting + SayHello(context.Context, *HelloRequest) (*HelloReply, error) +} + +func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) { + s.RegisterService(&_Greeter_serviceDesc, srv) +} + +func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HelloRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GreeterServer).SayHello(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/helloworld.Greeter/SayHello", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Greeter_serviceDesc = grpc.ServiceDesc{ + ServiceName: "helloworld.Greeter", + HandlerType: (*GreeterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SayHello", + Handler: _Greeter_SayHello_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "helloworld.proto", +} + +func init() { proto.RegisterFile("helloworld.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 174 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x12, 0xc8, 0x48, 0xcd, 0xc9, + 0xc9, 0x2f, 0xcf, 0x2f, 0xca, 0x49, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x42, 0x88, + 0x28, 0x29, 0x71, 0xf1, 0x78, 0x80, 0x78, 0x41, 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x42, + 0x5c, 0x2c, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x60, 0xb6, 0x92, + 0x1a, 0x17, 0x17, 0x54, 0x4d, 0x41, 0x4e, 0xa5, 0x90, 0x04, 0x17, 0x7b, 0x6e, 0x6a, 0x71, 0x71, + 0x62, 0x3a, 0x4c, 0x11, 0x8c, 0x6b, 0xe4, 0xc9, 0xc5, 0xee, 0x5e, 0x94, 0x9a, 0x5a, 0x92, 0x5a, + 0x24, 0x64, 0xc7, 0xc5, 0x11, 0x9c, 0x58, 0x09, 0xd6, 0x25, 0x24, 0xa1, 0x87, 0xe4, 0x02, 0x64, + 0xcb, 0xa4, 0xc4, 0xb0, 0xc8, 0x00, 0xad, 0x50, 0x62, 0x70, 0x32, 0xe0, 0x92, 0xce, 0xcc, 0xd7, + 0x4b, 0x2f, 0x2a, 0x48, 0xd6, 0x4b, 0xad, 0x48, 0xcc, 0x2d, 0xc8, 0x49, 0x2d, 0x46, 0x52, 0xeb, + 0xc4, 0x0f, 0x56, 0x1c, 0x0e, 0x62, 0x07, 0x80, 0xbc, 0x14, 0xc0, 0x98, 0xc4, 0x06, 0xf6, 0x9b, + 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x0f, 0xb7, 0xcd, 0xf2, 0xef, 0x00, 0x00, 0x00, +} diff --git a/vendor/cloud.google.com/go/trace/testdata/helloworld/helloworld.proto b/vendor/cloud.google.com/go/trace/testdata/helloworld/helloworld.proto new file mode 100644 index 00000000..bffe980e --- /dev/null +++ b/vendor/cloud.google.com/go/trace/testdata/helloworld/helloworld.proto @@ -0,0 +1,37 @@ +// Copyright 2017 Google LLC +// +// 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. + +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.grpc.examples.helloworld"; +option java_outer_classname = "HelloWorldProto"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/vendor/cloud.google.com/go/trace/trace.go b/vendor/cloud.google.com/go/trace/trace.go new file mode 100644 index 00000000..7a11de95 --- /dev/null +++ b/vendor/cloud.google.com/go/trace/trace.go @@ -0,0 +1,758 @@ +// Copyright 2016 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package trace is OBSOLETE. See https://cloud.google.com/trace/docs/setup/go. +package trace // import "cloud.google.com/go/trace" + +import ( + "context" + "crypto/rand" + "encoding/binary" + "encoding/json" + "fmt" + "log" + "net/http" + "runtime" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + api "google.golang.org/api/cloudtrace/v1" + "google.golang.org/api/gensupport" + "google.golang.org/api/option" + "google.golang.org/api/support/bundler" + htransport "google.golang.org/api/transport/http" +) + +const ( + httpHeader = `X-Cloud-Trace-Context` + userAgent = `gcloud-golang-trace/20160501` + cloudPlatformScope = `https://www.googleapis.com/auth/cloud-platform` + spanKindClient = `RPC_CLIENT` + spanKindServer = `RPC_SERVER` + spanKindUnspecified = `SPAN_KIND_UNSPECIFIED` + maxStackFrames = 20 + labelAgent = `trace.cloud.google.com/agent` +) + +// Stackdriver Trace API predefined labels. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +const ( + LabelComponent = `trace.cloud.google.com/component` + LabelErrorMessage = `trace.cloud.google.com/error/message` + LabelErrorName = `trace.cloud.google.com/error/name` + LabelHTTPClientCity = `trace.cloud.google.com/http/client_city` + LabelHTTPClientCountry = `trace.cloud.google.com/http/client_country` + LabelHTTPClientProtocol = `trace.cloud.google.com/http/client_protocol` + LabelHTTPClientRegion = `trace.cloud.google.com/http/client_region` + LabelHTTPHost = `trace.cloud.google.com/http/host` + LabelHTTPMethod = `trace.cloud.google.com/http/method` + LabelHTTPRedirectedURL = `trace.cloud.google.com/http/redirected_url` + LabelHTTPRequestSize = `trace.cloud.google.com/http/request/size` + LabelHTTPResponseSize = `trace.cloud.google.com/http/response/size` + LabelHTTPStatusCode = `trace.cloud.google.com/http/status_code` + LabelHTTPURL = `trace.cloud.google.com/http/url` + LabelHTTPUserAgent = `trace.cloud.google.com/http/user_agent` + LabelPID = `trace.cloud.google.com/pid` + LabelSamplingPolicy = `trace.cloud.google.com/sampling_policy` + LabelSamplingWeight = `trace.cloud.google.com/sampling_weight` + LabelStackTrace = `trace.cloud.google.com/stacktrace` + LabelTID = `trace.cloud.google.com/tid` +) + +const ( + // ScopeTraceAppend grants permissions to write trace data for a project. + // + // Deprecated: see https://cloud.google.com/trace/docs/setup/go. + ScopeTraceAppend = "https://www.googleapis.com/auth/trace.append" + + // ScopeCloudPlatform grants permissions to view and manage your data + // across Google Cloud Platform services. + // + // Deprecated: see https://cloud.google.com/trace/docs/setup/go. + ScopeCloudPlatform = "https://www.googleapis.com/auth/cloud-platform" +) + +type contextKey struct{} + +type stackLabelValue struct { + Frames []stackFrame `json:"stack_frame"` +} + +type stackFrame struct { + Class string `json:"class_name,omitempty"` + Method string `json:"method_name"` + Filename string `json:"file_name"` + Line int64 `json:"line_number"` +} + +var ( + spanIDCounter uint64 + spanIDIncrement uint64 +) + +func init() { + // Set spanIDCounter and spanIDIncrement to random values. nextSpanID will + // return an arithmetic progression using these values, skipping zero. We set + // the LSB of spanIDIncrement to 1, so that the cycle length is 2^64. + binary.Read(rand.Reader, binary.LittleEndian, &spanIDCounter) + binary.Read(rand.Reader, binary.LittleEndian, &spanIDIncrement) + spanIDIncrement |= 1 + // Attach hook for autogenerated Google API calls. This will automatically + // create trace spans for API calls if there is a trace in the context. + gensupport.RegisterHook(requestHook) +} + +func requestHook(ctx context.Context, req *http.Request) func(resp *http.Response) { + span := FromContext(ctx) + if span == nil || req == nil { + return nil + } + span = span.NewRemoteChild(req) + return func(resp *http.Response) { + if resp != nil { + span.Finish(WithResponse(resp)) + } else { + span.Finish() + } + } +} + +// nextSpanID returns a new span ID. It will never return zero. +func nextSpanID() uint64 { + var id uint64 + for id == 0 { + id = atomic.AddUint64(&spanIDCounter, spanIDIncrement) + } + return id +} + +// nextTraceID returns a new trace ID. +func nextTraceID() string { + id1 := nextSpanID() + id2 := nextSpanID() + return fmt.Sprintf("%016x%016x", id1, id2) +} + +// Client is a client for uploading traces to the Google Stackdriver Trace service. +// A nil Client will no-op for all of its methods. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +type Client struct { + service *api.Service + projectID string + policy SamplingPolicy + bundler *bundler.Bundler +} + +// NewClient creates a new Google Stackdriver Trace client. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) { + o := []option.ClientOption{ + option.WithScopes(cloudPlatformScope), + option.WithUserAgent(userAgent), + } + o = append(o, opts...) + hc, basePath, err := htransport.NewClient(ctx, o...) + if err != nil { + return nil, fmt.Errorf("creating HTTP client for Google Stackdriver Trace API: %v", err) + } + apiService, err := api.New(hc) + if err != nil { + return nil, fmt.Errorf("creating Google Stackdriver Trace API client: %v", err) + } + if basePath != "" { + // An option set a basepath, so override api.New's default. + apiService.BasePath = basePath + } + c := &Client{ + service: apiService, + projectID: projectID, + } + bundler := bundler.NewBundler((*api.Trace)(nil), func(bundle interface{}) { + traces := bundle.([]*api.Trace) + err := c.upload(traces) + if err != nil { + log.Printf("failed to upload %d traces to the Cloud Trace server: %v", len(traces), err) + } + }) + bundler.DelayThreshold = 2 * time.Second + bundler.BundleCountThreshold = 100 + // We're not measuring bytes here, we're counting traces and spans as one "byte" each. + bundler.BundleByteThreshold = 1000 + bundler.BundleByteLimit = 1000 + bundler.BufferedByteLimit = 10000 + c.bundler = bundler + return c, nil +} + +// SetSamplingPolicy sets the SamplingPolicy that determines how often traces +// are initiated by this client. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (c *Client) SetSamplingPolicy(p SamplingPolicy) { + if c != nil { + c.policy = p + } +} + +// SpanFromHeader returns a new trace span based on a provided request header +// value or nil iff the client is nil. +// +// The trace information and identifiers will be read from the header value. +// Otherwise, a new trace ID is made and the parent span ID is zero. +// For the exact format of the header value, see +// https://cloud.google.com/trace/docs/troubleshooting#force-trace +// +// The name of the new span is provided as an argument. +// +// If a non-nil sampling policy has been set in the client, it can override +// the options set in the header and choose whether to trace the request. +// +// If the header doesn't have existing tracing information, then a *Span is +// returned anyway, but it will not be uploaded to the server, just as when +// calling SpanFromRequest on an untraced request. +// +// Most users using HTTP should use SpanFromRequest, rather than +// SpanFromHeader, since it provides additional functionality for HTTP +// requests. In particular, it will set various pieces of request information +// as labels on the *Span, which is not available from the header alone. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (c *Client) SpanFromHeader(name string, header string) *Span { + if c == nil { + return nil + } + traceID, parentSpanID, options, _, ok := traceInfoFromHeader(header) + if !ok { + traceID = nextTraceID() + } + t := &trace{ + traceID: traceID, + client: c, + globalOptions: options, + localOptions: options, + } + span := startNewChild(name, t, parentSpanID) + span.span.Kind = spanKindServer + span.rootSpan = true + configureSpanFromPolicy(span, c.policy, ok) + return span +} + +// SpanFromRequest returns a new trace span for an HTTP request or nil +// iff the client is nil. +// +// If the incoming HTTP request contains a trace context header, the trace ID, +// parent span ID, and tracing options will be read from that header. +// Otherwise, a new trace ID is made and the parent span ID is zero. +// +// If a non-nil sampling policy has been set in the client, it can override the +// options set in the header and choose whether to trace the request. +// +// If the request is not being traced, then a *Span is returned anyway, but it +// will not be uploaded to the server -- it is only useful for propagating +// trace context to child requests and for getting the TraceID. All its +// methods can still be called -- the Finish, FinishWait, and SetLabel methods +// do nothing. NewChild does nothing, and returns the same *Span. TraceID +// works as usual. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (c *Client) SpanFromRequest(r *http.Request) *Span { + if c == nil { + return nil + } + traceID, parentSpanID, options, _, ok := traceInfoFromHeader(r.Header.Get(httpHeader)) + if !ok { + traceID = nextTraceID() + } + t := &trace{ + traceID: traceID, + client: c, + globalOptions: options, + localOptions: options, + } + span := startNewChildWithRequest(r, t, parentSpanID) + span.span.Kind = spanKindServer + span.rootSpan = true + configureSpanFromPolicy(span, c.policy, ok) + return span +} + +// NewSpan returns a new trace span with the given name or nil iff the +// client is nil. +// +// A new trace and span ID is generated to trace the span. +// Returned span need to be finished by calling Finish or FinishWait. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (c *Client) NewSpan(name string) *Span { + if c == nil { + return nil + } + t := &trace{ + traceID: nextTraceID(), + client: c, + localOptions: optionTrace, + globalOptions: optionTrace, + } + span := startNewChild(name, t, 0) + span.span.Kind = spanKindUnspecified + span.rootSpan = true + configureSpanFromPolicy(span, c.policy, false) + return span +} + +func configureSpanFromPolicy(s *Span, p SamplingPolicy, ok bool) { + if p == nil { + return + } + d := p.Sample(Parameters{HasTraceHeader: ok}) + if d.Trace { + // Turn on tracing locally, and in child requests. + s.trace.localOptions |= optionTrace + s.trace.globalOptions |= optionTrace + } else { + // Turn off tracing locally. + s.trace.localOptions = 0 + return + } + if d.Sample { + // This trace is in the random sample, so set the labels. + s.SetLabel(LabelSamplingPolicy, d.Policy) + s.SetLabel(LabelSamplingWeight, fmt.Sprint(d.Weight)) + } +} + +// NewContext returns a derived context containing the span. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func NewContext(ctx context.Context, s *Span) context.Context { + if s == nil { + return ctx + } + return context.WithValue(ctx, contextKey{}, s) +} + +// FromContext returns the span contained in the context, or nil. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func FromContext(ctx context.Context) *Span { + s, _ := ctx.Value(contextKey{}).(*Span) + return s +} + +func traceInfoFromHeader(h string) (traceID string, spanID uint64, options optionFlags, optionsOk bool, ok bool) { + // See https://cloud.google.com/trace/docs/faq for the header format. + // Return if the header is empty or missing, or if the header is unreasonably + // large, to avoid making unnecessary copies of a large string. + if h == "" || len(h) > 200 { + return "", 0, 0, false, false + + } + + // Parse the trace id field. + slash := strings.Index(h, `/`) + if slash == -1 { + return "", 0, 0, false, false + + } + traceID, h = h[:slash], h[slash+1:] + + // Parse the span id field. + spanstr := h + semicolon := strings.Index(h, `;`) + if semicolon != -1 { + spanstr, h = h[:semicolon], h[semicolon+1:] + } + spanID, err := strconv.ParseUint(spanstr, 10, 64) + if err != nil { + return "", 0, 0, false, false + + } + + // Parse the options field, options field is optional. + if !strings.HasPrefix(h, "o=") { + return traceID, spanID, 0, false, true + + } + o, err := strconv.ParseUint(h[2:], 10, 64) + if err != nil { + return "", 0, 0, false, false + + } + options = optionFlags(o) + return traceID, spanID, options, true, true +} + +type optionFlags uint32 + +const ( + optionTrace optionFlags = 1 << iota + optionStack +) + +type trace struct { + mu sync.Mutex + client *Client + traceID string + globalOptions optionFlags // options that will be passed to any child requests + localOptions optionFlags // options applied in this server + spans []*Span // finished spans for this trace. +} + +// finish appends s to t.spans. If s is the root span, uploads the trace to the +// server. +func (t *trace) finish(s *Span, wait bool, opts ...FinishOption) error { + for _, o := range opts { + o.modifySpan(s) + } + s.end = time.Now() + t.mu.Lock() + t.spans = append(t.spans, s) + spans := t.spans + t.mu.Unlock() + if s.rootSpan { + if wait { + return t.client.upload([]*api.Trace{t.constructTrace(spans)}) + } + go func() { + tr := t.constructTrace(spans) + err := t.client.bundler.Add(tr, 1+len(spans)) + if err == bundler.ErrOversizedItem { + err = t.client.upload([]*api.Trace{tr}) + } + if err != nil { + log.Println("error uploading trace:", err) + } + }() + } + return nil +} + +func (t *trace) constructTrace(spans []*Span) *api.Trace { + apiSpans := make([]*api.TraceSpan, len(spans)) + for i, sp := range spans { + sp.span.StartTime = sp.start.In(time.UTC).Format(time.RFC3339Nano) + sp.span.EndTime = sp.end.In(time.UTC).Format(time.RFC3339Nano) + if t.localOptions&optionStack != 0 { + sp.setStackLabel() + } + if sp.host != "" { + sp.SetLabel(LabelHTTPHost, sp.host) + } + if sp.url != "" { + sp.SetLabel(LabelHTTPURL, sp.url) + } + if sp.method != "" { + sp.SetLabel(LabelHTTPMethod, sp.method) + } + if sp.statusCode != 0 { + sp.SetLabel(LabelHTTPStatusCode, strconv.Itoa(sp.statusCode)) + } + sp.SetLabel(labelAgent, userAgent) + apiSpans[i] = &sp.span + } + + return &api.Trace{ + ProjectId: t.client.projectID, + TraceId: t.traceID, + Spans: apiSpans, + } +} + +func (c *Client) upload(traces []*api.Trace) error { + _, err := c.service.Projects.PatchTraces(c.projectID, &api.Traces{Traces: traces}).Do() + return err +} + +// Span contains information about one span of a trace. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +type Span struct { + trace *trace + + spanMu sync.Mutex // guards span.Labels + span api.TraceSpan + + start time.Time + end time.Time + rootSpan bool + stack [maxStackFrames]uintptr + host string + method string + url string + statusCode int +} + +// Traced reports whether the current span is sampled to be traced. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (s *Span) Traced() bool { + if s == nil { + return false + } + return s.trace.localOptions&optionTrace != 0 +} + +// NewChild creates a new span with the given name as a child of s. +// If s is nil, does nothing and returns nil. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (s *Span) NewChild(name string) *Span { + if s == nil { + return nil + } + if !s.Traced() { + // TODO(jbd): Document this behavior in godoc here and elsewhere. + return s + } + return startNewChild(name, s.trace, s.span.SpanId) +} + +// NewRemoteChild creates a new span as a child of s. +// +// Some labels in the span are set from the outgoing *http.Request r. +// +// A header is set in r so that the trace context is propagated to the +// destination. The parent span ID in that header is set as follows: +// - If the request is being traced, then the ID of s is used. +// - If the request is not being traced, but there was a trace context header +// in the incoming request for this trace (the request passed to +// SpanFromRequest), the parent span ID in that header is used. +// - Otherwise, the parent span ID is zero. +// The tracing bit in the options is set if tracing is enabled, or if it was +// set in the incoming request. +// +// If s is nil, does nothing and returns nil. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (s *Span) NewRemoteChild(r *http.Request) *Span { + if s == nil { + return nil + } + if !s.Traced() { + r.Header[httpHeader] = []string{spanHeader(s.trace.traceID, s.span.ParentSpanId, s.trace.globalOptions)} + return s + } + newSpan := startNewChildWithRequest(r, s.trace, s.span.SpanId) + r.Header[httpHeader] = []string{spanHeader(s.trace.traceID, newSpan.span.SpanId, s.trace.globalOptions)} + return newSpan +} + +// Header returns the value of the X-Cloud-Trace-Context header that +// should be used to propagate the span. This is the inverse of +// SpanFromHeader. +// +// Most users should use NewRemoteChild unless they have specific +// propagation needs or want to control the naming of their span. +// Header() does not create a new span. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (s *Span) Header() string { + if s == nil { + return "" + } + return spanHeader(s.trace.traceID, s.span.SpanId, s.trace.globalOptions) +} + +func startNewChildWithRequest(r *http.Request, trace *trace, parentSpanID uint64) *Span { + name := r.URL.Host + r.URL.Path // drop scheme and query params + newSpan := startNewChild(name, trace, parentSpanID) + if r.Host == "" { + newSpan.host = r.URL.Host + } else { + newSpan.host = r.Host + } + newSpan.method = r.Method + newSpan.url = r.URL.String() + return newSpan +} + +func startNewChild(name string, trace *trace, parentSpanID uint64) *Span { + spanID := nextSpanID() + for spanID == parentSpanID { + spanID = nextSpanID() + } + newSpan := &Span{ + trace: trace, + span: api.TraceSpan{ + Kind: spanKindClient, + Name: name, + ParentSpanId: parentSpanID, + SpanId: spanID, + }, + start: time.Now(), + } + if trace.localOptions&optionStack != 0 { + _ = runtime.Callers(1, newSpan.stack[:]) + } + return newSpan +} + +// TraceID returns the ID of the trace to which s belongs. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (s *Span) TraceID() string { + if s == nil { + return "" + } + return s.trace.traceID +} + +// SetLabel sets the label for the given key to the given value. +// If the value is empty, the label for that key is deleted. +// If a label is given a value automatically and by SetLabel, the +// automatically-set value is used. +// If s is nil, does nothing. +// +// SetLabel shouldn't be called after Finish or FinishWait. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (s *Span) SetLabel(key, value string) { + if s == nil { + return + } + if !s.Traced() { + return + } + s.spanMu.Lock() + defer s.spanMu.Unlock() + + if value == "" { + if s.span.Labels != nil { + delete(s.span.Labels, key) + } + return + } + if s.span.Labels == nil { + s.span.Labels = make(map[string]string) + } + s.span.Labels[key] = value +} + +// FinishOption allows users to specify span finalizers. +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +type FinishOption interface { + modifySpan(s *Span) +} + +type withResponse struct { + *http.Response +} + +// WithResponse returns an option that can be passed to Finish that indicates +// that some labels for the span should be set using the given *http.Response. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func WithResponse(resp *http.Response) FinishOption { + return withResponse{resp} +} + +func (u withResponse) modifySpan(s *Span) { + if u.Response != nil { + s.statusCode = u.StatusCode + } +} + +// Finish declares that the span has finished. +// +// If s is nil, Finish does nothing and returns nil. +// +// If the option trace.WithResponse(resp) is passed, then some labels are set +// for s using information in the given *http.Response. This is useful when the +// span is for an outgoing http request; s will typically have been created by +// NewRemoteChild in this case. +// +// If s is a root span (one created by SpanFromRequest) then s, and all its +// descendant spans that have finished, are uploaded to the Google Stackdriver +// Trace server asynchronously. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (s *Span) Finish(opts ...FinishOption) { + if s == nil { + return + } + if !s.Traced() { + return + } + s.trace.finish(s, false, opts...) +} + +// FinishWait is like Finish, but if s is a root span, it waits until uploading +// is finished, then returns an error if one occurred. +// +// Deprecated: see https://cloud.google.com/trace/docs/setup/go. +func (s *Span) FinishWait(opts ...FinishOption) error { + if s == nil { + return nil + } + if !s.Traced() { + return nil + } + return s.trace.finish(s, true, opts...) +} + +func spanHeader(traceID string, spanID uint64, options optionFlags) string { + // See https://cloud.google.com/trace/docs/faq for the header format. + return fmt.Sprintf("%s/%d;o=%d", traceID, spanID, options) +} + +func (s *Span) setStackLabel() { + var stack stackLabelValue + lastSigPanic, inTraceLibrary := false, true + for _, pc := range s.stack { + if pc == 0 { + break + } + if !lastSigPanic { + pc-- + } + fn := runtime.FuncForPC(pc) + file, line := fn.FileLine(pc) + // Name has one of the following forms: + // path/to/package.Foo + // path/to/package.(Type).Foo + // For the first form, we store the whole name in the Method field of the + // stack frame. For the second form, we set the Method field to "Foo" and + // the Class field to "path/to/package.(Type)". + name := fn.Name() + if inTraceLibrary && !strings.HasPrefix(name, "cloud.google.com/go/trace.") { + inTraceLibrary = false + } + var class string + if i := strings.Index(name, ")."); i != -1 { + class, name = name[:i+1], name[i+2:] + } + frame := stackFrame{ + Class: class, + Method: name, + Filename: file, + Line: int64(line), + } + if inTraceLibrary && len(stack.Frames) == 1 { + stack.Frames[0] = frame + } else { + stack.Frames = append(stack.Frames, frame) + } + lastSigPanic = fn.Name() == "runtime.sigpanic" + } + if label, err := json.Marshal(stack); err == nil { + s.SetLabel(LabelStackTrace, string(label)) + } +} diff --git a/vendor/cloud.google.com/go/trace/trace_test.go b/vendor/cloud.google.com/go/trace/trace_test.go new file mode 100644 index 00000000..4992533c --- /dev/null +++ b/vendor/cloud.google.com/go/trace/trace_test.go @@ -0,0 +1,967 @@ +// Copyright 2016 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "math/rand" + "net/http" + "regexp" + "strings" + "sync" + "testing" + "time" + + "cloud.google.com/go/datastore" + "cloud.google.com/go/internal/testutil" + "cloud.google.com/go/storage" + api "google.golang.org/api/cloudtrace/v1" + compute "google.golang.org/api/compute/v1" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + dspb "google.golang.org/genproto/googleapis/datastore/v1" + "google.golang.org/grpc" +) + +const testProjectID = "testproject" + +type fakeRoundTripper struct { + reqc chan *http.Request +} + +func newFakeRoundTripper() *fakeRoundTripper { + return &fakeRoundTripper{reqc: make(chan *http.Request)} +} + +func (rt *fakeRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { + rt.reqc <- r + resp := &http.Response{ + Status: "200 OK", + StatusCode: 200, + Body: ioutil.NopCloser(strings.NewReader("{}")), + } + return resp, nil +} + +func newTestClient(rt http.RoundTripper) *Client { + t, err := NewClient(context.Background(), testProjectID, option.WithHTTPClient(&http.Client{Transport: rt})) + if err != nil { + panic(err) + } + return t +} + +type fakeDatastoreServer struct { + dspb.DatastoreServer + fail bool +} + +func (f *fakeDatastoreServer) Lookup(ctx context.Context, req *dspb.LookupRequest) (*dspb.LookupResponse, error) { + if f.fail { + return nil, errors.New("lookup failed") + } + return &dspb.LookupResponse{}, nil +} + +// makeRequests makes some requests. +// span is the root span. rt is the trace client's http client's transport. +// This is used to retrieve the trace uploaded by the client, if any. If +// expectTrace is true, we expect a trace will be uploaded. If synchronous is +// true, the call to Finish is expected not to return before the client has +// uploaded any traces. +func makeRequests(t *testing.T, span *Span, rt *fakeRoundTripper, synchronous bool, expectTrace bool) *http.Request { + ctx := NewContext(context.Background(), span) + tc := newTestClient(&noopTransport{}) + + // An HTTP request. + { + req2, err := http.NewRequest("GET", "http://example.com/bar", nil) + if err != nil { + t.Fatal(err) + } + resp := &http.Response{StatusCode: 200} + s := span.NewRemoteChild(req2) + s.Finish(WithResponse(resp)) + } + + // An autogenerated API call. + { + rt := &fakeRoundTripper{reqc: make(chan *http.Request, 1)} + hc := &http.Client{Transport: rt} + computeClient, err := compute.New(hc) + if err != nil { + t.Fatal(err) + } + _, err = computeClient.Zones.List(testProjectID).Context(ctx).Do() + if err != nil { + t.Fatal(err) + } + } + + // A cloud library call that uses the autogenerated API. + { + rt := &fakeRoundTripper{reqc: make(chan *http.Request, 1)} + hc := &http.Client{Transport: rt} + storageClient, err := storage.NewClient(context.Background(), option.WithHTTPClient(hc)) + if err != nil { + t.Fatal(err) + } + it := storageClient.Bucket("testbucket").Objects(ctx, nil) + for { + _, err := it.Next() + if err != nil && err != iterator.Done { + t.Fatal(err) + } + if err == iterator.Done { + break + } + } + } + + // A cloud library call that uses grpc internally. + for _, fail := range []bool{false, true} { + srv, err := testutil.NewServer() + if err != nil { + t.Fatalf("creating test datastore server: %v", err) + } + dspb.RegisterDatastoreServer(srv.Gsrv, &fakeDatastoreServer{fail: fail}) + srv.Start() + conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure(), grpc.WithUnaryInterceptor(tc.GRPCClientInterceptor())) + if err != nil { + t.Fatalf("connecting to test datastore server: %v", err) + } + datastoreClient, err := datastore.NewClient(ctx, testProjectID, option.WithGRPCConn(conn)) + if err != nil { + t.Fatalf("creating datastore client: %v", err) + } + k := datastore.NameKey("Entity", "stringID", nil) + e := new(datastore.Entity) + datastoreClient.Get(ctx, k, e) + } + + done := make(chan struct{}) + go func() { + if synchronous { + err := span.FinishWait() + if err != nil { + t.Errorf("Unexpected error from span.FinishWait: %v", err) + } + } else { + span.Finish() + } + done <- struct{}{} + }() + if !expectTrace { + <-done + select { + case <-rt.reqc: + t.Errorf("Got a trace, expected none.") + case <-time.After(5 * time.Millisecond): + } + return nil + } else if !synchronous { + <-done + return <-rt.reqc + } else { + select { + case <-done: + t.Errorf("Synchronous Finish didn't wait for trace upload.") + return <-rt.reqc + case <-time.After(5 * time.Millisecond): + r := <-rt.reqc + <-done + return r + } + } +} + +func TestHeader(t *testing.T) { + tests := []struct { + header string + wantTraceID string + wantSpanID uint64 + wantOpts optionFlags + wantOK bool + }{ + { + header: "0123456789ABCDEF0123456789ABCDEF/1;o=1", + wantTraceID: "0123456789ABCDEF0123456789ABCDEF", + wantSpanID: 1, + wantOpts: 1, + wantOK: true, + }, + { + header: "0123456789ABCDEF0123456789ABCDEF/1;o=0", + wantTraceID: "0123456789ABCDEF0123456789ABCDEF", + wantSpanID: 1, + wantOpts: 0, + wantOK: true, + }, + { + header: "0123456789ABCDEF0123456789ABCDEF/1", + wantTraceID: "0123456789ABCDEF0123456789ABCDEF", + wantSpanID: 1, + wantOpts: 0, + wantOK: true, + }, + { + header: "", + wantTraceID: "", + wantSpanID: 0, + wantOpts: 0, + wantOK: false, + }, + } + for _, tt := range tests { + traceID, parentSpanID, opts, _, ok := traceInfoFromHeader(tt.header) + if got, want := traceID, tt.wantTraceID; got != want { + t.Errorf("TraceID(%v) = %q; want %q", tt.header, got, want) + } + if got, want := parentSpanID, tt.wantSpanID; got != want { + t.Errorf("SpanID(%v) = %v; want %v", tt.header, got, want) + } + if got, want := opts, tt.wantOpts; got != want { + t.Errorf("Options(%v) = %v; want %v", tt.header, got, want) + } + if got, want := ok, tt.wantOK; got != want { + t.Errorf("Header exists (%v) = %v; want %v", tt.header, got, want) + } + } +} + +func TestOutgoingReqHeader(t *testing.T) { + all, _ := NewLimitedSampler(1, 1<<16) // trace every request + + tests := []struct { + desc string + traceHeader string + samplingPolicy SamplingPolicy + + wantHeaderRe *regexp.Regexp + }{ + { + desc: "Parent span without sampling options, client samples all", + traceHeader: "0123456789ABCDEF0123456789ABCDEF/1", + samplingPolicy: all, + wantHeaderRe: regexp.MustCompile("0123456789ABCDEF0123456789ABCDEF/\\d+;o=1"), + }, + { + desc: "Parent span without sampling options, without client sampling", + traceHeader: "0123456789ABCDEF0123456789ABCDEF/1", + samplingPolicy: nil, + wantHeaderRe: regexp.MustCompile("0123456789ABCDEF0123456789ABCDEF/\\d+;o=0"), + }, + { + desc: "Parent span with o=1, client samples none", + traceHeader: "0123456789ABCDEF0123456789ABCDEF/1;o=1", + samplingPolicy: nil, + wantHeaderRe: regexp.MustCompile("0123456789ABCDEF0123456789ABCDEF/\\d+;o=1"), + }, + { + desc: "Parent span with o=0, without client sampling", + traceHeader: "0123456789ABCDEF0123456789ABCDEF/1;o=0", + samplingPolicy: nil, + wantHeaderRe: regexp.MustCompile("0123456789ABCDEF0123456789ABCDEF/\\d+;o=0"), + }, + } + + tc := newTestClient(nil) + for _, tt := range tests { + tc.SetSamplingPolicy(tt.samplingPolicy) + span := tc.SpanFromHeader("/foo", tt.traceHeader) + + req, _ := http.NewRequest("GET", "http://localhost", nil) + span.NewRemoteChild(req) + + if got, re := req.Header.Get(httpHeader), tt.wantHeaderRe; !re.MatchString(got) { + t.Errorf("%v (parent=%q): got header %q; want in format %q", tt.desc, tt.traceHeader, got, re) + } + } +} + +func TestTrace(t *testing.T) { + t.Parallel() + testTrace(t, false, true) +} + +func TestTraceWithWait(t *testing.T) { + testTrace(t, true, true) +} + +func TestTraceFromHeader(t *testing.T) { + t.Parallel() + testTrace(t, false, false) +} + +func TestTraceFromHeaderWithWait(t *testing.T) { + testTrace(t, false, true) +} + +func TestNewSpan(t *testing.T) { + t.Skip("flaky") + const traceID = "0123456789ABCDEF0123456789ABCDEF" + + rt := newFakeRoundTripper() + traceClient := newTestClient(rt) + span := traceClient.NewSpan("/foo") + span.trace.traceID = traceID + + uploaded := makeRequests(t, span, rt, true, true) + + if uploaded == nil { + t.Fatalf("No trace uploaded, expected one.") + } + + expected := api.Traces{ + Traces: []*api.Trace{ + { + ProjectId: testProjectID, + Spans: []*api.TraceSpan{ + { + Kind: "RPC_CLIENT", + Labels: map[string]string{ + "trace.cloud.google.com/http/host": "example.com", + "trace.cloud.google.com/http/method": "GET", + "trace.cloud.google.com/http/status_code": "200", + "trace.cloud.google.com/http/url": "http://example.com/bar", + }, + Name: "example.com/bar", + }, + { + Kind: "RPC_CLIENT", + Labels: map[string]string{ + "trace.cloud.google.com/http/host": "www.googleapis.com", + "trace.cloud.google.com/http/method": "GET", + "trace.cloud.google.com/http/status_code": "200", + "trace.cloud.google.com/http/url": "https://www.googleapis.com/compute/v1/projects/testproject/zones", + }, + Name: "www.googleapis.com/compute/v1/projects/testproject/zones", + }, + { + Kind: "RPC_CLIENT", + Labels: map[string]string{ + "trace.cloud.google.com/http/host": "www.googleapis.com", + "trace.cloud.google.com/http/method": "GET", + "trace.cloud.google.com/http/status_code": "200", + "trace.cloud.google.com/http/url": "https://www.googleapis.com/storage/v1/b/testbucket/o", + }, + Name: "www.googleapis.com/storage/v1/b/testbucket/o", + }, + { + Kind: "RPC_CLIENT", + Labels: nil, + Name: "/google.datastore.v1.Datastore/Lookup", + }, + { + Kind: "RPC_CLIENT", + Labels: map[string]string{"error": "rpc error: code = Unknown desc = lookup failed"}, + Name: "/google.datastore.v1.Datastore/Lookup", + }, + { + Kind: "SPAN_KIND_UNSPECIFIED", + Labels: map[string]string{}, + Name: "/foo", + }, + }, + TraceId: traceID, + }, + }, + } + + body, err := ioutil.ReadAll(uploaded.Body) + if err != nil { + t.Fatal(err) + } + var patch api.Traces + err = json.Unmarshal(body, &patch) + if err != nil { + t.Fatal(err) + } + + checkTraces(t, patch, expected) + + n := len(patch.Traces[0].Spans) + rootSpan := patch.Traces[0].Spans[n-1] + for i, s := range patch.Traces[0].Spans { + if a, b := s.StartTime, s.EndTime; a > b { + t.Errorf("span %d start time is later than its end time (%q, %q)", i, a, b) + } + if a, b := rootSpan.StartTime, s.StartTime; a > b { + t.Errorf("trace start time is later than span %d start time (%q, %q)", i, a, b) + } + if a, b := s.EndTime, rootSpan.EndTime; a > b { + t.Errorf("span %d end time is later than trace end time (%q, %q)", i, a, b) + } + if i > 1 && i < n-1 { + if a, b := patch.Traces[0].Spans[i-1].EndTime, s.StartTime; a > b { + t.Errorf("span %d end time is later than span %d start time (%q, %q)", i-1, i, a, b) + } + } + } + + if x := rootSpan.ParentSpanId; x != 0 { + t.Errorf("Incorrect ParentSpanId: got %d want %d", x, 0) + } + for i, s := range patch.Traces[0].Spans { + if x, y := rootSpan.SpanId, s.ParentSpanId; i < n-1 && x != y { + t.Errorf("Incorrect ParentSpanId in span %d: got %d want %d", i, y, x) + } + } + for i, s := range patch.Traces[0].Spans { + s.EndTime = "" + labels := &expected.Traces[0].Spans[i].Labels + for key, value := range *labels { + if v, ok := s.Labels[key]; !ok { + t.Errorf("Span %d is missing Label %q:%q", i, key, value) + } else if key == "trace.cloud.google.com/http/url" { + if !strings.HasPrefix(v, value) { + t.Errorf("Span %d Label %q: got value %q want prefix %q", i, key, v, value) + } + } else if v != value { + t.Errorf("Span %d Label %q: got value %q want %q", i, key, v, value) + } + } + for key := range s.Labels { + if _, ok := (*labels)[key]; key != "trace.cloud.google.com/stacktrace" && !ok { + t.Errorf("Span %d: unexpected label %q", i, key) + } + } + *labels = nil + s.Labels = nil + s.ParentSpanId = 0 + if s.SpanId == 0 { + t.Errorf("Incorrect SpanId: got 0 want nonzero") + } + s.SpanId = 0 + s.StartTime = "" + } + if !testutil.Equal(patch, expected) { + got, _ := json.Marshal(patch) + want, _ := json.Marshal(expected) + t.Errorf("PatchTraces request: got %s want %s", got, want) + } +} + +func testTrace(t *testing.T, synchronous bool, fromRequest bool) { + t.Skip("flaky") + const header = `0123456789ABCDEF0123456789ABCDEF/42;o=3` + rt := newFakeRoundTripper() + traceClient := newTestClient(rt) + + span := traceClient.SpanFromHeader("/foo", header) + headerOrReqLabels := map[string]string{} + headerOrReqName := "/foo" + + if fromRequest { + req, err := http.NewRequest("GET", "http://example.com/foo", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Set("X-Cloud-Trace-Context", header) + span = traceClient.SpanFromRequest(req) + headerOrReqLabels = map[string]string{ + "trace.cloud.google.com/http/host": "example.com", + "trace.cloud.google.com/http/method": "GET", + "trace.cloud.google.com/http/url": "http://example.com/foo", + } + headerOrReqName = "example.com/foo" + } + + uploaded := makeRequests(t, span, rt, synchronous, true) + if uploaded == nil { + t.Fatalf("No trace uploaded, expected one.") + } + + expected := api.Traces{ + Traces: []*api.Trace{ + { + ProjectId: testProjectID, + Spans: []*api.TraceSpan{ + { + Kind: "RPC_CLIENT", + Labels: map[string]string{ + "trace.cloud.google.com/http/host": "example.com", + "trace.cloud.google.com/http/method": "GET", + "trace.cloud.google.com/http/status_code": "200", + "trace.cloud.google.com/http/url": "http://example.com/bar", + }, + Name: "example.com/bar", + }, + { + Kind: "RPC_CLIENT", + Labels: map[string]string{ + "trace.cloud.google.com/http/host": "www.googleapis.com", + "trace.cloud.google.com/http/method": "GET", + "trace.cloud.google.com/http/status_code": "200", + "trace.cloud.google.com/http/url": "https://www.googleapis.com/compute/v1/projects/testproject/zones", + }, + Name: "www.googleapis.com/compute/v1/projects/testproject/zones", + }, + { + Kind: "RPC_CLIENT", + Labels: map[string]string{ + "trace.cloud.google.com/http/host": "www.googleapis.com", + "trace.cloud.google.com/http/method": "GET", + "trace.cloud.google.com/http/status_code": "200", + "trace.cloud.google.com/http/url": "https://www.googleapis.com/storage/v1/b/testbucket/o", + }, + Name: "www.googleapis.com/storage/v1/b/testbucket/o", + }, + { + Kind: "RPC_CLIENT", + Labels: nil, + Name: "/google.datastore.v1.Datastore/Lookup", + }, + { + Kind: "RPC_CLIENT", + Labels: map[string]string{"error": "rpc error: code = Unknown desc = lookup failed"}, + Name: "/google.datastore.v1.Datastore/Lookup", + }, + { + Kind: "RPC_SERVER", + Labels: headerOrReqLabels, + Name: headerOrReqName, + }, + }, + TraceId: "0123456789ABCDEF0123456789ABCDEF", + }, + }, + } + + body, err := ioutil.ReadAll(uploaded.Body) + if err != nil { + t.Fatal(err) + } + var patch api.Traces + err = json.Unmarshal(body, &patch) + if err != nil { + t.Fatal(err) + } + + checkTraces(t, patch, expected) + + n := len(patch.Traces[0].Spans) + rootSpan := patch.Traces[0].Spans[n-1] + for i, s := range patch.Traces[0].Spans { + if a, b := s.StartTime, s.EndTime; a > b { + t.Errorf("span %d start time is later than its end time (%q, %q)", i, a, b) + } + if a, b := rootSpan.StartTime, s.StartTime; a > b { + t.Errorf("trace start time is later than span %d start time (%q, %q)", i, a, b) + } + if a, b := s.EndTime, rootSpan.EndTime; a > b { + t.Errorf("span %d end time is later than trace end time (%q, %q)", i, a, b) + } + if i > 1 && i < n-1 { + if a, b := patch.Traces[0].Spans[i-1].EndTime, s.StartTime; a > b { + t.Errorf("span %d end time is later than span %d start time (%q, %q)", i-1, i, a, b) + } + } + } + + if x := rootSpan.ParentSpanId; x != 42 { + t.Errorf("Incorrect ParentSpanId: got %d want %d", x, 42) + } + for i, s := range patch.Traces[0].Spans { + if x, y := rootSpan.SpanId, s.ParentSpanId; i < n-1 && x != y { + t.Errorf("Incorrect ParentSpanId in span %d: got %d want %d", i, y, x) + } + } + for i, s := range patch.Traces[0].Spans { + s.EndTime = "" + labels := &expected.Traces[0].Spans[i].Labels + for key, value := range *labels { + if v, ok := s.Labels[key]; !ok { + t.Errorf("Span %d is missing Label %q:%q", i, key, value) + } else if key == "trace.cloud.google.com/http/url" { + if !strings.HasPrefix(v, value) { + t.Errorf("Span %d Label %q: got value %q want prefix %q", i, key, v, value) + } + } else if v != value { + t.Errorf("Span %d Label %q: got value %q want %q", i, key, v, value) + } + } + for key := range s.Labels { + if _, ok := (*labels)[key]; key != "trace.cloud.google.com/stacktrace" && !ok { + t.Errorf("Span %d: unexpected label %q", i, key) + } + } + *labels = nil + s.Labels = nil + s.ParentSpanId = 0 + if s.SpanId == 0 { + t.Errorf("Incorrect SpanId: got 0 want nonzero") + } + s.SpanId = 0 + s.StartTime = "" + } + if !testutil.Equal(patch, expected) { + got, _ := json.Marshal(patch) + want, _ := json.Marshal(expected) + t.Errorf("PatchTraces request: got %s \n\n want %s", got, want) + } +} + +func TestNoTrace(t *testing.T) { + testNoTrace(t, false, true) +} + +func TestNoTraceWithWait(t *testing.T) { + testNoTrace(t, true, true) +} + +func TestNoTraceFromHeader(t *testing.T) { + testNoTrace(t, false, false) +} + +func TestNoTraceFromHeaderWithWait(t *testing.T) { + testNoTrace(t, true, false) +} + +func testNoTrace(t *testing.T, synchronous bool, fromRequest bool) { + for _, header := range []string{ + `0123456789ABCDEF0123456789ABCDEF/42;o=2`, + `0123456789ABCDEF0123456789ABCDEF/42;o=0`, + `0123456789ABCDEF0123456789ABCDEF/42`, + `0123456789ABCDEF0123456789ABCDEF`, + ``, + } { + rt := newFakeRoundTripper() + traceClient := newTestClient(rt) + var span *Span + if fromRequest { + req, err := http.NewRequest("GET", "http://example.com/foo", nil) + if header != "" { + req.Header.Set("X-Cloud-Trace-Context", header) + } + if err != nil { + t.Fatal(err) + } + span = traceClient.SpanFromRequest(req) + } else { + span = traceClient.SpanFromHeader("/foo", header) + } + uploaded := makeRequests(t, span, rt, synchronous, false) + if uploaded != nil { + t.Errorf("Got a trace, expected none.") + } + } +} + +func TestSample(t *testing.T) { + // A deterministic test of the sampler logic. + type testCase struct { + rate float64 + maxqps float64 + want int + } + const delta = 25 * time.Millisecond + for _, test := range []testCase{ + // qps won't matter, so we will sample half of the 79 calls + {0.50, 100, 40}, + // with 1 qps and a burst of 2, we will sample twice in second #1, once in the partial second #2 + {0.50, 1, 3}, + } { + sp, err := NewLimitedSampler(test.rate, test.maxqps) + if err != nil { + t.Fatal(err) + } + s := sp.(*sampler) + sampled := 0 + tm := time.Now() + for i := 0; i < 80; i++ { + if s.sample(Parameters{}, tm, float64(i%2)).Sample { + sampled++ + } + tm = tm.Add(delta) + } + if sampled != test.want { + t.Errorf("rate=%f, maxqps=%f: got %d samples, want %d", test.rate, test.maxqps, sampled, test.want) + } + } +} + +func TestSampling(t *testing.T) { + t.Parallel() + // This scope tests sampling in a larger context, with real time and randomness. + wg := sync.WaitGroup{} + type testCase struct { + rate float64 + maxqps float64 + expectedRange [2]int + } + for _, test := range []testCase{ + {0, 5, [2]int{0, 0}}, + {5, 0, [2]int{0, 0}}, + {0.50, 100, [2]int{20, 60}}, + {0.50, 1, [2]int{3, 4}}, // Windows, with its less precise clock, sometimes gives 4. + } { + wg.Add(1) + go func(test testCase) { + rt := newFakeRoundTripper() + traceClient := newTestClient(rt) + traceClient.bundler.BundleByteLimit = 1 + p, err := NewLimitedSampler(test.rate, test.maxqps) + if err != nil { + t.Errorf("NewLimitedSampler: %v", err) + } + traceClient.SetSamplingPolicy(p) + ticker := time.NewTicker(25 * time.Millisecond) + sampled := 0 + for i := 0; i < 79; i++ { + req, err := http.NewRequest("GET", "http://example.com/foo", nil) + if err != nil { + t.Error(err) + } + span := traceClient.SpanFromRequest(req) + span.Finish() + select { + case <-rt.reqc: + <-ticker.C + sampled++ + case <-ticker.C: + } + } + ticker.Stop() + if test.expectedRange[0] > sampled || sampled > test.expectedRange[1] { + t.Errorf("rate=%f, maxqps=%f: got %d samples want ∈ %v", test.rate, test.maxqps, sampled, test.expectedRange) + } + wg.Done() + }(test) + } + wg.Wait() +} + +func TestBundling(t *testing.T) { + t.Parallel() + rt := newFakeRoundTripper() + traceClient := newTestClient(rt) + traceClient.bundler.DelayThreshold = time.Second / 2 + traceClient.bundler.BundleCountThreshold = 10 + p, err := NewLimitedSampler(1, 99) // sample every request. + if err != nil { + t.Fatalf("NewLimitedSampler: %v", err) + } + traceClient.SetSamplingPolicy(p) + + for i := 0; i < 35; i++ { + go func() { + req, err := http.NewRequest("GET", "http://example.com/foo", nil) + if err != nil { + t.Error(err) + } + span := traceClient.SpanFromRequest(req) + span.Finish() + }() + } + + // Read the first three bundles. + <-rt.reqc + <-rt.reqc + <-rt.reqc + + // Test that the fourth bundle isn't sent early. + select { + case <-rt.reqc: + t.Errorf("bundle sent too early") + case <-time.After(time.Second / 4): + <-rt.reqc + } + + // Test that there aren't extra bundles. + select { + case <-rt.reqc: + t.Errorf("too many bundles sent") + case <-time.After(time.Second): + } +} + +func TestWeights(t *testing.T) { + const ( + expectedNumTraced = 10100 + numTracedEpsilon = 100 + expectedTotalWeight = 50000 + totalWeightEpsilon = 5000 + ) + rng := rand.New(rand.NewSource(1)) + const delta = 2 * time.Millisecond + for _, headerRate := range []float64{0.0, 0.5, 1.0} { + // Simulate 10 seconds of requests arriving at 500qps. + // + // The sampling policy tries to sample 25% of them, but has a qps limit of + // 100, so it will not be able to. The returned weight should be higher + // for some sampled requests to compensate. + // + // headerRate is the fraction of incoming requests that have a trace header + // set. The qps limit should not be exceeded, even if headerRate is high. + sp, err := NewLimitedSampler(0.25, 100) + if err != nil { + t.Fatal(err) + } + s := sp.(*sampler) + tm := time.Now() + totalWeight := 0.0 + numTraced := 0 + seenLargeWeight := false + for i := 0; i < 50000; i++ { + d := s.sample(Parameters{HasTraceHeader: rng.Float64() < headerRate}, tm, rng.Float64()) + if d.Trace { + numTraced++ + } + if d.Sample { + totalWeight += d.Weight + if x := int(d.Weight) / 4; x <= 0 || x >= 100 || d.Weight != float64(x)*4.0 { + t.Errorf("weight: got %f, want a small positive multiple of 4", d.Weight) + } + if d.Weight > 4 { + seenLargeWeight = true + } + } + tm = tm.Add(delta) + } + if !seenLargeWeight { + t.Errorf("headerRate %f: never saw sample weight higher than 4.", headerRate) + } + if numTraced < expectedNumTraced-numTracedEpsilon || expectedNumTraced+numTracedEpsilon < numTraced { + t.Errorf("headerRate %f: got %d traced requests, want ∈ [%d, %d]", headerRate, numTraced, expectedNumTraced-numTracedEpsilon, expectedNumTraced+numTracedEpsilon) + } + if totalWeight < expectedTotalWeight-totalWeightEpsilon || expectedTotalWeight+totalWeightEpsilon < totalWeight { + t.Errorf("headerRate %f: got total weight %f want ∈ [%d, %d]", headerRate, totalWeight, expectedTotalWeight-totalWeightEpsilon, expectedTotalWeight+totalWeightEpsilon) + } + } +} + +type alwaysTrace struct{} + +func (a alwaysTrace) Sample(p Parameters) Decision { + return Decision{Trace: true} +} + +type neverTrace struct{} + +func (a neverTrace) Sample(p Parameters) Decision { + return Decision{Trace: false} +} + +func TestPropagation(t *testing.T) { + rt := newFakeRoundTripper() + traceClient := newTestClient(rt) + for _, header := range []string{ + `0123456789ABCDEF0123456789ABCDEF/42;o=0`, + `0123456789ABCDEF0123456789ABCDEF/42;o=1`, + `0123456789ABCDEF0123456789ABCDEF/42;o=2`, + `0123456789ABCDEF0123456789ABCDEF/42;o=3`, + `0123456789ABCDEF0123456789ABCDEF/0;o=0`, + `0123456789ABCDEF0123456789ABCDEF/0;o=1`, + `0123456789ABCDEF0123456789ABCDEF/0;o=2`, + `0123456789ABCDEF0123456789ABCDEF/0;o=3`, + ``, + } { + for _, policy := range []SamplingPolicy{ + nil, + alwaysTrace{}, + neverTrace{}, + } { + traceClient.SetSamplingPolicy(policy) + req, err := http.NewRequest("GET", "http://example.com/foo", nil) + if err != nil { + t.Fatal(err) + } + if header != "" { + req.Header.Set("X-Cloud-Trace-Context", header) + } + + span := traceClient.SpanFromRequest(req) + + req2, err := http.NewRequest("GET", "http://example.com/bar", nil) + if err != nil { + t.Fatal(err) + } + req3, err := http.NewRequest("GET", "http://example.com/baz", nil) + if err != nil { + t.Fatal(err) + } + span.NewRemoteChild(req2) + span.NewRemoteChild(req3) + + var ( + t1, t2, t3 string + s1, s2, s3 uint64 + o1, o2, o3 uint64 + ) + fmt.Sscanf(header, "%32s/%d;o=%d", &t1, &s1, &o1) + fmt.Sscanf(req2.Header.Get("X-Cloud-Trace-Context"), "%32s/%d;o=%d", &t2, &s2, &o2) + fmt.Sscanf(req3.Header.Get("X-Cloud-Trace-Context"), "%32s/%d;o=%d", &t3, &s3, &o3) + + if header == "" { + if t2 != t3 { + t.Errorf("expected the same trace ID in child requests, got %q %q", t2, t3) + } + } else { + if t2 != t1 || t3 != t1 { + t.Errorf("trace IDs should be passed to child requests") + } + } + trace := policy == alwaysTrace{} || policy == nil && (o1&1) != 0 + if header == "" { + if trace && (s2 == 0 || s3 == 0) { + t.Errorf("got span IDs %d %d in child requests, want nonzero", s2, s3) + } + if trace && s2 == s3 { + t.Errorf("got span IDs %d %d in child requests, should be different", s2, s3) + } + if !trace && (s2 != 0 || s3 != 0) { + t.Errorf("got span IDs %d %d in child requests, want zero", s2, s3) + } + } else { + if trace && (s2 == s1 || s3 == s1 || s2 == s3) { + t.Errorf("parent span IDs in input and outputs should be all different, got %d %d %d", s1, s2, s3) + } + if !trace && (s2 != s1 || s3 != s1) { + t.Errorf("parent span ID in input, %d, should have been equal to parent span IDs in output: %d %d", s1, s2, s3) + } + } + expectTraceOption := policy == alwaysTrace{} || (o1&1) != 0 + if expectTraceOption != ((o2&1) != 0) || expectTraceOption != ((o3&1) != 0) { + t.Errorf("tracing flag in child requests should be %t, got options %d %d", expectTraceOption, o2, o3) + } + } + } +} + +func BenchmarkSpanFromHeader(b *testing.B) { + const header = `0123456789ABCDEF0123456789ABCDEF/42;o=0` + const name = "/foo" + + rt := newFakeRoundTripper() + traceClient := newTestClient(rt) + for n := 0; n < b.N; n++ { + traceClient.SpanFromHeader(name, header) + } +} + +func checkTraces(t *testing.T, patch, expected api.Traces) { + if len(patch.Traces) != len(expected.Traces) || len(patch.Traces[0].Spans) != len(expected.Traces[0].Spans) { + diff := testutil.Diff(patch.Traces, expected.Traces) + t.Logf("diff:\n%s", diff) + got, _ := json.Marshal(patch) + want, _ := json.Marshal(expected) + t.Fatalf("PatchTraces request: got %s want %s", got, want) + } +} diff --git a/vendor/cloud.google.com/go/translate/examples_test.go b/vendor/cloud.google.com/go/translate/examples_test.go new file mode 100644 index 00000000..2e96b068 --- /dev/null +++ b/vendor/cloud.google.com/go/translate/examples_test.go @@ -0,0 +1,81 @@ +// Copyright 2016 Google LLC +// +// 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 translate_test + +import ( + "context" + "fmt" + + "cloud.google.com/go/translate" + "golang.org/x/text/language" +) + +func Example_NewClient() { + ctx := context.Background() + client, err := translate.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + // Use the client. + + // Close the client when finished. + if err := client.Close(); err != nil { + // TODO: handle error. + } +} + +func Example_Translate() { + ctx := context.Background() + client, err := translate.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + translations, err := client.Translate(ctx, + []string{"Le singe est sur la branche"}, language.English, + &translate.Options{ + Source: language.French, + Format: translate.Text, + }) + if err != nil { + // TODO: handle error. + } + fmt.Println(translations[0].Text) +} + +func Example_DetectLanguage() { + ctx := context.Background() + client, err := translate.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + ds, err := client.DetectLanguage(ctx, []string{"Today is Monday"}) + if err != nil { + // TODO: handle error. + } + fmt.Println(ds) +} + +func Example_SupportedLanguages() { + ctx := context.Background() + client, err := translate.NewClient(ctx) + if err != nil { + // TODO: handle error. + } + langs, err := client.SupportedLanguages(ctx, language.English) + if err != nil { + // TODO: handle error. + } + fmt.Println(langs) +} diff --git a/vendor/cloud.google.com/go/translate/internal/translate/v2/README b/vendor/cloud.google.com/go/translate/internal/translate/v2/README new file mode 100644 index 00000000..a4f22c6f --- /dev/null +++ b/vendor/cloud.google.com/go/translate/internal/translate/v2/README @@ -0,0 +1,12 @@ +translate-nov2016-api.json is a hand-modified version of translate-api.json. +It correctly reflects the API as of 2016-11-15. + +Differences: + +- Change to base URL +- Addition of OAuth scopes + +To generate: + + + diff --git a/vendor/cloud.google.com/go/translate/internal/translate/v2/regen.sh b/vendor/cloud.google.com/go/translate/internal/translate/v2/regen.sh new file mode 100755 index 00000000..dc8fd9e1 --- /dev/null +++ b/vendor/cloud.google.com/go/translate/internal/translate/v2/regen.sh @@ -0,0 +1,29 @@ +#!/bin/bash -e + + +(cd $GOPATH/src/google.golang.org/api; make generator) + +$GOPATH/bin/google-api-go-generator \ + -api_json_file translate-nov2016-api.json \ + -api_pkg_base cloud.google.com/go/translate/internal \ + -output translate-nov2016-gen.nolicense + +cat - translate-nov2016-gen.nolicense > translate-nov2016-gen.go <" + s + "" + } + tr = translate(htmlify(test.input), test.target, nil) + if got, want := tr.Text, htmlify(test.output); got != want { + t.Errorf("html: got %q, want %q", got, want) + } + // Using the HTML format behaves the same. + tr = translate(htmlify(test.input), test.target, &Options{Format: HTML}) + if got, want := tr.Text, htmlify(test.output); got != want { + t.Errorf("html: got %q, want %q", got, want) + } + } +} + +// This tests the beta "nmt" model. +func TestTranslateModel(t *testing.T) { + ctx := context.Background() + c := initTest(ctx, t) + defer c.Close() + + trs, err := c.Translate(ctx, []string{"Hello"}, language.French, &Options{Model: "nmt"}) + if err != nil { + t.Fatal(err) + } + if len(trs) != 1 { + t.Fatalf("wanted one Translation, got %d", len(trs)) + } + tr := trs[0] + if got, want := tr.Text, "Bonjour"; got != want { + t.Errorf("text: got %q, want %q", got, want) + } + if got, want := tr.Model, "nmt"; got != want { + t.Errorf("model: got %q, want %q", got, want) + } +} + +func TestTranslateMultipleInputs(t *testing.T) { + ctx := context.Background() + c := initTest(ctx, t) + defer c.Close() + + inputs := []string{ + "When you're a Jet, you're a Jet all the way", + "From your first cigarette to your last dying day", + "When you're a Jet if the spit hits the fan", + "You got brothers around, you're a family man", + } + ts, err := c.Translate(ctx, inputs, language.French, nil) + if err != nil { + t.Fatal(err) + } + if got, want := len(ts), len(inputs); got != want { + t.Fatalf("got %d Translations, wanted %d", got, want) + } +} + +func TestTranslateErrors(t *testing.T) { + ctx := context.Background() + c := initTest(ctx, t) + defer c.Close() + + for _, test := range []struct { + ctx context.Context + target language.Tag + inputs []string + opts *Options + }{ + {ctx, language.English, nil, nil}, + {ctx, language.Und, []string{"input"}, nil}, + {ctx, language.English, []string{}, nil}, + {ctx, language.English, []string{"input"}, &Options{Format: "random"}}, + } { + _, err := c.Translate(test.ctx, test.inputs, test.target, test.opts) + if err == nil { + t.Errorf("%+v: got nil, want error", test) + } + } +} + +func TestDetectLanguage(t *testing.T) { + ctx := context.Background() + c := initTest(ctx, t) + defer c.Close() + ds, err := c.DetectLanguage(ctx, []string{ + "Today is Monday", + "Aujourd'hui est lundi", + }) + if err != nil { + t.Fatal(err) + } + if len(ds) != 2 { + t.Fatalf("got %d detection lists, want 2", len(ds)) + } + checkDetections(t, ds[0], language.English) + checkDetections(t, ds[1], language.French) +} + +func checkDetections(t *testing.T, ds []Detection, want language.Tag) { + for _, d := range ds { + if d.Language == want { + return + } + } + t.Errorf("%v: missing %s", ds, want) +} + +// A small subset of the supported languages. +var supportedLangs = []Language{ + {Name: "Danish", Tag: language.Danish}, + {Name: "English", Tag: language.English}, + {Name: "French", Tag: language.French}, + {Name: "German", Tag: language.German}, + {Name: "Greek", Tag: language.Greek}, + {Name: "Hindi", Tag: language.Hindi}, + {Name: "Hungarian", Tag: language.Hungarian}, + {Name: "Italian", Tag: language.Italian}, + {Name: "Russian", Tag: language.Russian}, + {Name: "Turkish", Tag: language.Turkish}, +} + +func TestSupportedLanguages(t *testing.T) { + ctx := context.Background() + c := initTest(ctx, t) + defer c.Close() + got, err := c.SupportedLanguages(ctx, language.English) + if err != nil { + t.Fatal(err) + } + want := map[language.Tag]Language{} + for _, sl := range supportedLangs { + want[sl.Tag] = sl + } + for _, g := range got { + w, ok := want[g.Tag] + if !ok { + continue + } + if g != w { + t.Errorf("got %+v, want %+v", g, w) + } + delete(want, g.Tag) + } + if len(want) > 0 { + t.Errorf("missing: %+v", want) + } +} diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1/AnnotateVideo_smoke_test.go b/vendor/cloud.google.com/go/videointelligence/apiv1/AnnotateVideo_smoke_test.go new file mode 100644 index 00000000..9f28854c --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1/AnnotateVideo_smoke_test.go @@ -0,0 +1,69 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package videointelligence + +import ( + videointelligencepb "google.golang.org/genproto/googleapis/cloud/videointelligence/v1" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestVideoIntelligenceServiceSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var inputUri string = "gs://demomaker/cat.mp4" + var featuresElement videointelligencepb.Feature = videointelligencepb.Feature_LABEL_DETECTION + var features = []videointelligencepb.Feature{featuresElement} + var request = &videointelligencepb.AnnotateVideoRequest{ + InputUri: inputUri, + Features: features, + } + + if _, err := c.AnnotateVideo(ctx, request); err != nil { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1/doc.go b/vendor/cloud.google.com/go/videointelligence/apiv1/doc.go new file mode 100644 index 00000000..9c79b9a1 --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package videointelligence is an auto-generated package for the +// Cloud Video Intelligence API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Cloud Video Intelligence API. +package videointelligence // import "cloud.google.com/go/videointelligence/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1/mock_test.go b/vendor/cloud.google.com/go/videointelligence/apiv1/mock_test.go new file mode 100644 index 00000000..59919e0a --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1/mock_test.go @@ -0,0 +1,192 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package videointelligence + +import ( + videointelligencepb "google.golang.org/genproto/googleapis/cloud/videointelligence/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockVideoIntelligenceServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + videointelligencepb.VideoIntelligenceServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockVideoIntelligenceServer) AnnotateVideo(ctx context.Context, req *videointelligencepb.AnnotateVideoRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockVideoIntelligence mockVideoIntelligenceServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + videointelligencepb.RegisterVideoIntelligenceServiceServer(serv, &mockVideoIntelligence) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestVideoIntelligenceServiceAnnotateVideo(t *testing.T) { + var expectedResponse *videointelligencepb.AnnotateVideoResponse = &videointelligencepb.AnnotateVideoResponse{} + + mockVideoIntelligence.err = nil + mockVideoIntelligence.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockVideoIntelligence.resps = append(mockVideoIntelligence.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var inputUri string = "gs://demomaker/cat.mp4" + var featuresElement videointelligencepb.Feature = videointelligencepb.Feature_LABEL_DETECTION + var features = []videointelligencepb.Feature{featuresElement} + var request = &videointelligencepb.AnnotateVideoRequest{ + InputUri: inputUri, + Features: features, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.AnnotateVideo(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockVideoIntelligence.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestVideoIntelligenceServiceAnnotateVideoError(t *testing.T) { + errCode := codes.PermissionDenied + mockVideoIntelligence.err = nil + mockVideoIntelligence.resps = append(mockVideoIntelligence.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var inputUri string = "gs://demomaker/cat.mp4" + var featuresElement videointelligencepb.Feature = videointelligencepb.Feature_LABEL_DETECTION + var features = []videointelligencepb.Feature{featuresElement} + var request = &videointelligencepb.AnnotateVideoRequest{ + InputUri: inputUri, + Features: features, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.AnnotateVideo(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1/video_intelligence_client.go b/vendor/cloud.google.com/go/videointelligence/apiv1/video_intelligence_client.go new file mode 100644 index 00000000..e16d1dd1 --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1/video_intelligence_client.go @@ -0,0 +1,226 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package videointelligence + +import ( + "context" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + videointelligencepb "google.golang.org/genproto/googleapis/cloud/videointelligence/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + AnnotateVideo []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("videointelligence.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 120000 * time.Millisecond, + Multiplier: 2.5, + }) + }), + }, + } + return &CallOptions{ + AnnotateVideo: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Cloud Video Intelligence API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client videointelligencepb.VideoIntelligenceServiceClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new video intelligence service client. +// +// Service that implements Google Cloud Video Intelligence API. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: videointelligencepb.NewVideoIntelligenceServiceClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// AnnotateVideo performs asynchronous video annotation. Progress and results can be +// retrieved through the google.longrunning.Operations interface. +// Operation.metadata contains AnnotateVideoProgress (progress). +// Operation.response contains AnnotateVideoResponse (results). +func (c *Client) AnnotateVideo(ctx context.Context, req *videointelligencepb.AnnotateVideoRequest, opts ...gax.CallOption) (*AnnotateVideoOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AnnotateVideo[0:len(c.CallOptions.AnnotateVideo):len(c.CallOptions.AnnotateVideo)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.AnnotateVideo(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &AnnotateVideoOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// AnnotateVideoOperation manages a long-running operation from AnnotateVideo. +type AnnotateVideoOperation struct { + lro *longrunning.Operation +} + +// AnnotateVideoOperation returns a new AnnotateVideoOperation from a given name. +// The name must be that of a previously created AnnotateVideoOperation, possibly from a different process. +func (c *Client) AnnotateVideoOperation(name string) *AnnotateVideoOperation { + return &AnnotateVideoOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *AnnotateVideoOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*videointelligencepb.AnnotateVideoResponse, error) { + var resp videointelligencepb.AnnotateVideoResponse + if err := op.lro.WaitWithInterval(ctx, &resp, 45000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *AnnotateVideoOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*videointelligencepb.AnnotateVideoResponse, error) { + var resp videointelligencepb.AnnotateVideoResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *AnnotateVideoOperation) Metadata() (*videointelligencepb.AnnotateVideoProgress, error) { + var meta videointelligencepb.AnnotateVideoProgress + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *AnnotateVideoOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *AnnotateVideoOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1/video_intelligence_client_example_test.go b/vendor/cloud.google.com/go/videointelligence/apiv1/video_intelligence_client_example_test.go new file mode 100644 index 00000000..9586594a --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1/video_intelligence_client_example_test.go @@ -0,0 +1,57 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package videointelligence_test + +import ( + "context" + + videointelligence "cloud.google.com/go/videointelligence/apiv1" + videointelligencepb "google.golang.org/genproto/googleapis/cloud/videointelligence/v1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := videointelligence.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_AnnotateVideo() { + ctx := context.Background() + c, err := videointelligence.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &videointelligencepb.AnnotateVideoRequest{ + // TODO: Fill request struct fields. + } + op, err := c.AnnotateVideo(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1beta1/doc.go b/vendor/cloud.google.com/go/videointelligence/apiv1beta1/doc.go new file mode 100644 index 00000000..00b740e3 --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1beta1/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package videointelligence is an auto-generated package for the +// Google Cloud Video Intelligence API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Google Cloud Video Intelligence API. +package videointelligence // import "cloud.google.com/go/videointelligence/apiv1beta1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1beta1/mock_test.go b/vendor/cloud.google.com/go/videointelligence/apiv1beta1/mock_test.go new file mode 100644 index 00000000..bcf22f7e --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1beta1/mock_test.go @@ -0,0 +1,192 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package videointelligence + +import ( + videointelligencepb "google.golang.org/genproto/googleapis/cloud/videointelligence/v1beta1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockVideoIntelligenceServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + videointelligencepb.VideoIntelligenceServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockVideoIntelligenceServer) AnnotateVideo(ctx context.Context, req *videointelligencepb.AnnotateVideoRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockVideoIntelligence mockVideoIntelligenceServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + videointelligencepb.RegisterVideoIntelligenceServiceServer(serv, &mockVideoIntelligence) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestVideoIntelligenceServiceAnnotateVideo(t *testing.T) { + var expectedResponse *videointelligencepb.AnnotateVideoResponse = &videointelligencepb.AnnotateVideoResponse{} + + mockVideoIntelligence.err = nil + mockVideoIntelligence.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockVideoIntelligence.resps = append(mockVideoIntelligence.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var inputUri string = "gs://demomaker/cat.mp4" + var featuresElement videointelligencepb.Feature = videointelligencepb.Feature_LABEL_DETECTION + var features = []videointelligencepb.Feature{featuresElement} + var request = &videointelligencepb.AnnotateVideoRequest{ + InputUri: inputUri, + Features: features, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.AnnotateVideo(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockVideoIntelligence.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestVideoIntelligenceServiceAnnotateVideoError(t *testing.T) { + errCode := codes.PermissionDenied + mockVideoIntelligence.err = nil + mockVideoIntelligence.resps = append(mockVideoIntelligence.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var inputUri string = "gs://demomaker/cat.mp4" + var featuresElement videointelligencepb.Feature = videointelligencepb.Feature_LABEL_DETECTION + var features = []videointelligencepb.Feature{featuresElement} + var request = &videointelligencepb.AnnotateVideoRequest{ + InputUri: inputUri, + Features: features, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.AnnotateVideo(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1beta1/video_intelligence_client.go b/vendor/cloud.google.com/go/videointelligence/apiv1beta1/video_intelligence_client.go new file mode 100644 index 00000000..f3003935 --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1beta1/video_intelligence_client.go @@ -0,0 +1,226 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package videointelligence + +import ( + "context" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + videointelligencepb "google.golang.org/genproto/googleapis/cloud/videointelligence/v1beta1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + AnnotateVideo []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("videointelligence.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 120000 * time.Millisecond, + Multiplier: 2.5, + }) + }), + }, + } + return &CallOptions{ + AnnotateVideo: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Google Cloud Video Intelligence API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client videointelligencepb.VideoIntelligenceServiceClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new video intelligence service client. +// +// Service that implements Google Cloud Video Intelligence API. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: videointelligencepb.NewVideoIntelligenceServiceClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// AnnotateVideo performs asynchronous video annotation. Progress and results can be +// retrieved through the google.longrunning.Operations interface. +// Operation.metadata contains AnnotateVideoProgress (progress). +// Operation.response contains AnnotateVideoResponse (results). +func (c *Client) AnnotateVideo(ctx context.Context, req *videointelligencepb.AnnotateVideoRequest, opts ...gax.CallOption) (*AnnotateVideoOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AnnotateVideo[0:len(c.CallOptions.AnnotateVideo):len(c.CallOptions.AnnotateVideo)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.AnnotateVideo(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &AnnotateVideoOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// AnnotateVideoOperation manages a long-running operation from AnnotateVideo. +type AnnotateVideoOperation struct { + lro *longrunning.Operation +} + +// AnnotateVideoOperation returns a new AnnotateVideoOperation from a given name. +// The name must be that of a previously created AnnotateVideoOperation, possibly from a different process. +func (c *Client) AnnotateVideoOperation(name string) *AnnotateVideoOperation { + return &AnnotateVideoOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *AnnotateVideoOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*videointelligencepb.AnnotateVideoResponse, error) { + var resp videointelligencepb.AnnotateVideoResponse + if err := op.lro.WaitWithInterval(ctx, &resp, 45000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *AnnotateVideoOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*videointelligencepb.AnnotateVideoResponse, error) { + var resp videointelligencepb.AnnotateVideoResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *AnnotateVideoOperation) Metadata() (*videointelligencepb.AnnotateVideoProgress, error) { + var meta videointelligencepb.AnnotateVideoProgress + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *AnnotateVideoOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *AnnotateVideoOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1beta1/video_intelligence_client_example_test.go b/vendor/cloud.google.com/go/videointelligence/apiv1beta1/video_intelligence_client_example_test.go new file mode 100644 index 00000000..6e4cd811 --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1beta1/video_intelligence_client_example_test.go @@ -0,0 +1,57 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package videointelligence_test + +import ( + "context" + + videointelligence "cloud.google.com/go/videointelligence/apiv1beta1" + videointelligencepb "google.golang.org/genproto/googleapis/cloud/videointelligence/v1beta1" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := videointelligence.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_AnnotateVideo() { + ctx := context.Background() + c, err := videointelligence.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &videointelligencepb.AnnotateVideoRequest{ + // TODO: Fill request struct fields. + } + op, err := c.AnnotateVideo(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1beta2/doc.go b/vendor/cloud.google.com/go/videointelligence/apiv1beta2/doc.go new file mode 100644 index 00000000..3f72b902 --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1beta2/doc.go @@ -0,0 +1,89 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package videointelligence is an auto-generated package for the +// Google Cloud Video Intelligence API. +// +// NOTE: This package is in alpha. It is not stable, and is likely to change. +// +// Google Cloud Video Intelligence API. +package videointelligence // import "cloud.google.com/go/videointelligence/apiv1beta2" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1beta2/mock_test.go b/vendor/cloud.google.com/go/videointelligence/apiv1beta2/mock_test.go new file mode 100644 index 00000000..4214c26d --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1beta2/mock_test.go @@ -0,0 +1,192 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package videointelligence + +import ( + videointelligencepb "google.golang.org/genproto/googleapis/cloud/videointelligence/v1beta2" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockVideoIntelligenceServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + videointelligencepb.VideoIntelligenceServiceServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockVideoIntelligenceServer) AnnotateVideo(ctx context.Context, req *videointelligencepb.AnnotateVideoRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockVideoIntelligence mockVideoIntelligenceServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + videointelligencepb.RegisterVideoIntelligenceServiceServer(serv, &mockVideoIntelligence) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestVideoIntelligenceServiceAnnotateVideo(t *testing.T) { + var expectedResponse *videointelligencepb.AnnotateVideoResponse = &videointelligencepb.AnnotateVideoResponse{} + + mockVideoIntelligence.err = nil + mockVideoIntelligence.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockVideoIntelligence.resps = append(mockVideoIntelligence.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var inputUri string = "gs://demomaker/cat.mp4" + var featuresElement videointelligencepb.Feature = videointelligencepb.Feature_LABEL_DETECTION + var features = []videointelligencepb.Feature{featuresElement} + var request = &videointelligencepb.AnnotateVideoRequest{ + InputUri: inputUri, + Features: features, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.AnnotateVideo(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockVideoIntelligence.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestVideoIntelligenceServiceAnnotateVideoError(t *testing.T) { + errCode := codes.PermissionDenied + mockVideoIntelligence.err = nil + mockVideoIntelligence.resps = append(mockVideoIntelligence.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var inputUri string = "gs://demomaker/cat.mp4" + var featuresElement videointelligencepb.Feature = videointelligencepb.Feature_LABEL_DETECTION + var features = []videointelligencepb.Feature{featuresElement} + var request = &videointelligencepb.AnnotateVideoRequest{ + InputUri: inputUri, + Features: features, + } + + c, err := NewClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.AnnotateVideo(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1beta2/video_intelligence_client.go b/vendor/cloud.google.com/go/videointelligence/apiv1beta2/video_intelligence_client.go new file mode 100644 index 00000000..d662165e --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1beta2/video_intelligence_client.go @@ -0,0 +1,226 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package videointelligence + +import ( + "context" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + videointelligencepb "google.golang.org/genproto/googleapis/cloud/videointelligence/v1beta2" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// CallOptions contains the retry settings for each method of Client. +type CallOptions struct { + AnnotateVideo []gax.CallOption +} + +func defaultClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("videointelligence.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultCallOptions() *CallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 1000 * time.Millisecond, + Max: 120000 * time.Millisecond, + Multiplier: 2.5, + }) + }), + }, + } + return &CallOptions{ + AnnotateVideo: retry[[2]string{"default", "idempotent"}], + } +} + +// Client is a client for interacting with Google Cloud Video Intelligence API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type Client struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + client videointelligencepb.VideoIntelligenceServiceClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *CallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewClient creates a new video intelligence service client. +// +// Service that implements Google Cloud Video Intelligence API. +func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error) { + conn, err := transport.DialGRPC(ctx, append(defaultClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &Client{ + conn: conn, + CallOptions: defaultCallOptions(), + + client: videointelligencepb.NewVideoIntelligenceServiceClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *Client) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *Client) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *Client) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// AnnotateVideo performs asynchronous video annotation. Progress and results can be +// retrieved through the google.longrunning.Operations interface. +// Operation.metadata contains AnnotateVideoProgress (progress). +// Operation.response contains AnnotateVideoResponse (results). +func (c *Client) AnnotateVideo(ctx context.Context, req *videointelligencepb.AnnotateVideoRequest, opts ...gax.CallOption) (*AnnotateVideoOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AnnotateVideo[0:len(c.CallOptions.AnnotateVideo):len(c.CallOptions.AnnotateVideo)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.client.AnnotateVideo(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &AnnotateVideoOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// AnnotateVideoOperation manages a long-running operation from AnnotateVideo. +type AnnotateVideoOperation struct { + lro *longrunning.Operation +} + +// AnnotateVideoOperation returns a new AnnotateVideoOperation from a given name. +// The name must be that of a previously created AnnotateVideoOperation, possibly from a different process. +func (c *Client) AnnotateVideoOperation(name string) *AnnotateVideoOperation { + return &AnnotateVideoOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *AnnotateVideoOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*videointelligencepb.AnnotateVideoResponse, error) { + var resp videointelligencepb.AnnotateVideoResponse + if err := op.lro.WaitWithInterval(ctx, &resp, 45000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *AnnotateVideoOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*videointelligencepb.AnnotateVideoResponse, error) { + var resp videointelligencepb.AnnotateVideoResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *AnnotateVideoOperation) Metadata() (*videointelligencepb.AnnotateVideoProgress, error) { + var meta videointelligencepb.AnnotateVideoProgress + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *AnnotateVideoOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *AnnotateVideoOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1beta2/video_intelligence_client_example_test.go b/vendor/cloud.google.com/go/videointelligence/apiv1beta2/video_intelligence_client_example_test.go new file mode 100644 index 00000000..e4a18f0c --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1beta2/video_intelligence_client_example_test.go @@ -0,0 +1,57 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package videointelligence_test + +import ( + "context" + + videointelligence "cloud.google.com/go/videointelligence/apiv1beta2" + videointelligencepb "google.golang.org/genproto/googleapis/cloud/videointelligence/v1beta2" +) + +func ExampleNewClient() { + ctx := context.Background() + c, err := videointelligence.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleClient_AnnotateVideo() { + ctx := context.Background() + c, err := videointelligence.NewClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &videointelligencepb.AnnotateVideoRequest{ + // TODO: Fill request struct fields. + } + op, err := c.AnnotateVideo(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/videointelligence/apiv1beta2/whitelist.go b/vendor/cloud.google.com/go/videointelligence/apiv1beta2/whitelist.go new file mode 100644 index 00000000..d0e057e7 --- /dev/null +++ b/vendor/cloud.google.com/go/videointelligence/apiv1beta2/whitelist.go @@ -0,0 +1,16 @@ +// Copyright 2017, Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// THIS API IS CURRENTLY UNDER WHITELIST. +package videointelligence diff --git a/vendor/cloud.google.com/go/vision/apiv1/BatchAnnotateImages_smoke_test.go b/vendor/cloud.google.com/go/vision/apiv1/BatchAnnotateImages_smoke_test.go new file mode 100644 index 00000000..a4d99388 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/BatchAnnotateImages_smoke_test.go @@ -0,0 +1,82 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package vision + +import ( + visionpb "google.golang.org/genproto/googleapis/cloud/vision/v1" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestImageAnnotatorSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewImageAnnotatorClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var gcsImageUri string = "gs://gapic-toolkit/President_Barack_Obama.jpg" + var source = &visionpb.ImageSource{ + GcsImageUri: gcsImageUri, + } + var image = &visionpb.Image{ + Source: source, + } + var type_ visionpb.Feature_Type = visionpb.Feature_FACE_DETECTION + var featuresElement = &visionpb.Feature{ + Type: type_, + } + var features = []*visionpb.Feature{featuresElement} + var requestsElement = &visionpb.AnnotateImageRequest{ + Image: image, + Features: features, + } + var requests = []*visionpb.AnnotateImageRequest{requestsElement} + var request = &visionpb.BatchAnnotateImagesRequest{ + Requests: requests, + } + + if _, err := c.BatchAnnotateImages(ctx, request); err != nil { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/vision/apiv1/README.md b/vendor/cloud.google.com/go/vision/apiv1/README.md new file mode 100644 index 00000000..bcfa08dd --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/README.md @@ -0,0 +1,9 @@ +Auto-generated vision v1 clients +================================= + +This package includes auto-generated clients for the vision v1 API. + +Use the handwritten client (in the parent directory, +cloud.google.com/go/vision) in preference to this. + +This code is EXPERIMENTAL and subject to CHANGE AT ANY TIME. diff --git a/vendor/cloud.google.com/go/vision/apiv1/client.go b/vendor/cloud.google.com/go/vision/apiv1/client.go new file mode 100644 index 00000000..77ae33e0 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/client.go @@ -0,0 +1,170 @@ +// Copyright 2017, Google LLC +// +// 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 vision + +import ( + "context" + + gax "github.com/googleapis/gax-go" + pb "google.golang.org/genproto/googleapis/cloud/vision/v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// AnnotateImage runs image detection and annotation for a single image. +func (c *ImageAnnotatorClient) AnnotateImage(ctx context.Context, req *pb.AnnotateImageRequest, opts ...gax.CallOption) (*pb.AnnotateImageResponse, error) { + res, err := c.BatchAnnotateImages(ctx, &pb.BatchAnnotateImagesRequest{ + Requests: []*pb.AnnotateImageRequest{req}, + }, opts...) + if err != nil { + return nil, err + } + return res.Responses[0], nil +} + +// Called for a single image and a single feature. +func (c *ImageAnnotatorClient) annotateOne(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, ftype pb.Feature_Type, maxResults int, opts []gax.CallOption) (*pb.AnnotateImageResponse, error) { + res, err := c.AnnotateImage(ctx, &pb.AnnotateImageRequest{ + Image: img, + ImageContext: ictx, + Features: []*pb.Feature{{Type: ftype, MaxResults: int32(maxResults)}}, + }, opts...) + if err != nil { + return nil, err + } + // When there is only one image and one feature, the response's Error field is + // unambiguously about that one detection, so we "promote" it to the error return + // value. + // res.Error is a google.rpc.Status. Convert to a Go error. Use a gRPC + // error because it preserves the code as a separate field. + // TODO(jba): preserve the details field. + if res.Error != nil { + return nil, status.Errorf(codes.Code(res.Error.Code), "%s", res.Error.Message) + } + return res, nil +} + +// DetectFaces performs face detection on the image. +// At most maxResults results are returned. +func (c *ImageAnnotatorClient) DetectFaces(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, maxResults int, opts ...gax.CallOption) ([]*pb.FaceAnnotation, error) { + res, err := c.annotateOne(ctx, img, ictx, pb.Feature_FACE_DETECTION, maxResults, opts) + if err != nil { + return nil, err + } + return res.FaceAnnotations, nil +} + +// DetectLandmarks performs landmark detection on the image. +// At most maxResults results are returned. +func (c *ImageAnnotatorClient) DetectLandmarks(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, maxResults int, opts ...gax.CallOption) ([]*pb.EntityAnnotation, error) { + res, err := c.annotateOne(ctx, img, ictx, pb.Feature_LANDMARK_DETECTION, maxResults, opts) + if err != nil { + return nil, err + } + return res.LandmarkAnnotations, nil +} + +// DetectLogos performs logo detection on the image. +// At most maxResults results are returned. +func (c *ImageAnnotatorClient) DetectLogos(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, maxResults int, opts ...gax.CallOption) ([]*pb.EntityAnnotation, error) { + res, err := c.annotateOne(ctx, img, ictx, pb.Feature_LOGO_DETECTION, maxResults, opts) + if err != nil { + return nil, err + } + return res.LogoAnnotations, nil +} + +// DetectLabels performs label detection on the image. +// At most maxResults results are returned. +func (c *ImageAnnotatorClient) DetectLabels(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, maxResults int, opts ...gax.CallOption) ([]*pb.EntityAnnotation, error) { + res, err := c.annotateOne(ctx, img, ictx, pb.Feature_LABEL_DETECTION, maxResults, opts) + if err != nil { + return nil, err + } + return res.LabelAnnotations, nil +} + +// DetectTexts performs text detection on the image. +// At most maxResults results are returned. +func (c *ImageAnnotatorClient) DetectTexts(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, maxResults int, opts ...gax.CallOption) ([]*pb.EntityAnnotation, error) { + res, err := c.annotateOne(ctx, img, ictx, pb.Feature_TEXT_DETECTION, maxResults, opts) + if err != nil { + return nil, err + } + return res.TextAnnotations, nil +} + +// DetectDocumentText performs full text (OCR) detection on the image. +func (c *ImageAnnotatorClient) DetectDocumentText(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) (*pb.TextAnnotation, error) { + res, err := c.annotateOne(ctx, img, ictx, pb.Feature_DOCUMENT_TEXT_DETECTION, 0, opts) + if err != nil { + return nil, err + } + return res.FullTextAnnotation, nil +} + +// DetectSafeSearch performs safe-search detection on the image. +func (c *ImageAnnotatorClient) DetectSafeSearch(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) (*pb.SafeSearchAnnotation, error) { + res, err := c.annotateOne(ctx, img, ictx, pb.Feature_SAFE_SEARCH_DETECTION, 0, opts) + if err != nil { + return nil, err + } + return res.SafeSearchAnnotation, nil +} + +// DetectImageProperties computes properties of the image. +func (c *ImageAnnotatorClient) DetectImageProperties(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) (*pb.ImageProperties, error) { + res, err := c.annotateOne(ctx, img, ictx, pb.Feature_IMAGE_PROPERTIES, 0, opts) + if err != nil { + return nil, err + } + return res.ImagePropertiesAnnotation, nil +} + +// DetectWeb computes a web annotation on the image. +func (c *ImageAnnotatorClient) DetectWeb(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) (*pb.WebDetection, error) { + res, err := c.annotateOne(ctx, img, ictx, pb.Feature_WEB_DETECTION, 0, opts) + if err != nil { + return nil, err + } + return res.WebDetection, nil +} + +// CropHints computes crop hints for the image. +func (c *ImageAnnotatorClient) CropHints(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) (*pb.CropHintsAnnotation, error) { + res, err := c.annotateOne(ctx, img, ictx, pb.Feature_CROP_HINTS, 0, opts) + if err != nil { + return nil, err + } + return res.CropHintsAnnotation, nil +} + +// LocalizeObject runs the localizer for object detection. +func (c *ImageAnnotatorClient) LocalizeObjects(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) ([]*pb.LocalizedObjectAnnotation, error) { + res, err := c.annotateOne(ctx, img, ictx, pb.Feature_OBJECT_LOCALIZATION, 0, opts) + if err != nil { + return nil, err + } + return res.LocalizedObjectAnnotations, nil +} + +// ProductSearch searches the image for products. +func (c *ImageAnnotatorClient) ProductSearch(ctx context.Context, img *pb.Image, ictx *pb.ImageContext, opts ...gax.CallOption) (*pb.ProductSearchResults, error) { + res, err := c.annotateOne(ctx, img, ictx, pb.Feature_PRODUCT_SEARCH, 0, opts) + if err != nil { + return nil, err + } + return res.ProductSearchResults, nil +} diff --git a/vendor/cloud.google.com/go/vision/apiv1/client_test.go b/vendor/cloud.google.com/go/vision/apiv1/client_test.go new file mode 100644 index 00000000..c997eaae --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/client_test.go @@ -0,0 +1,210 @@ +// Copyright 2017, Google LLC +// +// 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 vision + +import ( + "context" + "fmt" + "reflect" + "testing" + + "github.com/golang/protobuf/proto" + pb "google.golang.org/genproto/googleapis/cloud/vision/v1" + "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" +) + +var batchResponse = &pb.BatchAnnotateImagesResponse{ + Responses: []*pb.AnnotateImageResponse{{ + FaceAnnotations: []*pb.FaceAnnotation{ + {RollAngle: 1}, {RollAngle: 2}}, + LandmarkAnnotations: []*pb.EntityAnnotation{{Mid: "landmark"}}, + LogoAnnotations: []*pb.EntityAnnotation{{Mid: "logo"}}, + LabelAnnotations: []*pb.EntityAnnotation{{Mid: "label"}}, + TextAnnotations: []*pb.EntityAnnotation{{Mid: "text"}}, + FullTextAnnotation: &pb.TextAnnotation{Text: "full"}, + SafeSearchAnnotation: &pb.SafeSearchAnnotation{Spoof: pb.Likelihood_POSSIBLE}, + ImagePropertiesAnnotation: &pb.ImageProperties{DominantColors: &pb.DominantColorsAnnotation{}}, + CropHintsAnnotation: &pb.CropHintsAnnotation{CropHints: []*pb.CropHint{{Confidence: 0.5}}}, + WebDetection: &pb.WebDetection{WebEntities: []*pb.WebDetection_WebEntity{{EntityId: "web"}}}, + }}, +} + +// Verify that all the "shortcut" methods use the underlying +// BatchAnnotateImages RPC correctly. +func TestClientMethods(t *testing.T) { + ctx := context.Background() + c, err := NewImageAnnotatorClient(ctx, clientOpt) + if err != nil { + t.Fatal(err) + } + + mockImageAnnotator.resps = []proto.Message{batchResponse} + img := &pb.Image{Source: &pb.ImageSource{ImageUri: "http://foo.jpg"}} + ictx := &pb.ImageContext{LanguageHints: []string{"en", "fr"}} + req := &pb.AnnotateImageRequest{ + Image: img, + ImageContext: ictx, + Features: []*pb.Feature{ + {Type: pb.Feature_LABEL_DETECTION, MaxResults: 3}, + {Type: pb.Feature_FACE_DETECTION, MaxResults: 4}, + }, + } + + for i, test := range []struct { + call func() (interface{}, error) + wantFeatures []*pb.Feature + wantRes interface{} + }{ + { + func() (interface{}, error) { return c.AnnotateImage(ctx, req) }, + req.Features, batchResponse.Responses[0], + }, + { + func() (interface{}, error) { return c.DetectFaces(ctx, img, ictx, 2) }, + []*pb.Feature{{Type: pb.Feature_FACE_DETECTION, MaxResults: 2}}, + batchResponse.Responses[0].FaceAnnotations, + }, + { + func() (interface{}, error) { return c.DetectLandmarks(ctx, img, ictx, 2) }, + []*pb.Feature{{Type: pb.Feature_LANDMARK_DETECTION, MaxResults: 2}}, + batchResponse.Responses[0].LandmarkAnnotations, + }, + { + func() (interface{}, error) { return c.DetectLogos(ctx, img, ictx, 2) }, + []*pb.Feature{{Type: pb.Feature_LOGO_DETECTION, MaxResults: 2}}, + batchResponse.Responses[0].LogoAnnotations, + }, + { + func() (interface{}, error) { return c.DetectLabels(ctx, img, ictx, 2) }, + []*pb.Feature{{Type: pb.Feature_LABEL_DETECTION, MaxResults: 2}}, + batchResponse.Responses[0].LabelAnnotations, + }, + { + func() (interface{}, error) { return c.DetectTexts(ctx, img, ictx, 2) }, + []*pb.Feature{{Type: pb.Feature_TEXT_DETECTION, MaxResults: 2}}, + batchResponse.Responses[0].TextAnnotations, + }, + { + func() (interface{}, error) { return c.DetectDocumentText(ctx, img, ictx) }, + []*pb.Feature{{Type: pb.Feature_DOCUMENT_TEXT_DETECTION, MaxResults: 0}}, + batchResponse.Responses[0].FullTextAnnotation, + }, + { + func() (interface{}, error) { return c.DetectSafeSearch(ctx, img, ictx) }, + []*pb.Feature{{Type: pb.Feature_SAFE_SEARCH_DETECTION, MaxResults: 0}}, + batchResponse.Responses[0].SafeSearchAnnotation, + }, + { + func() (interface{}, error) { return c.DetectImageProperties(ctx, img, ictx) }, + []*pb.Feature{{Type: pb.Feature_IMAGE_PROPERTIES, MaxResults: 0}}, + batchResponse.Responses[0].ImagePropertiesAnnotation, + }, + { + func() (interface{}, error) { return c.DetectWeb(ctx, img, ictx) }, + []*pb.Feature{{Type: pb.Feature_WEB_DETECTION, MaxResults: 0}}, + batchResponse.Responses[0].WebDetection, + }, + { + func() (interface{}, error) { return c.CropHints(ctx, img, ictx) }, + []*pb.Feature{{Type: pb.Feature_CROP_HINTS, MaxResults: 0}}, + batchResponse.Responses[0].CropHintsAnnotation, + }, + { + func() (interface{}, error) { return c.LocalizeObjects(ctx, img, ictx) }, + []*pb.Feature{{Type: pb.Feature_OBJECT_LOCALIZATION, MaxResults: 0}}, + batchResponse.Responses[0].LocalizedObjectAnnotations, + }, + { + func() (interface{}, error) { return c.ProductSearch(ctx, img, ictx) }, + []*pb.Feature{{Type: pb.Feature_PRODUCT_SEARCH, MaxResults: 0}}, + batchResponse.Responses[0].ProductSearchResults, + }, + } { + mockImageAnnotator.reqs = nil + res, err := test.call() + if err != nil { + t.Fatal(err) + } + got := mockImageAnnotator.reqs[0] + want := &pb.BatchAnnotateImagesRequest{ + Requests: []*pb.AnnotateImageRequest{{ + Image: img, + ImageContext: ictx, + Features: test.wantFeatures, + }}, + } + if !testEqual(got, want) { + t.Errorf("#%d:\ngot %v\nwant %v", i, got, want) + } + if got, want := res, test.wantRes; !testEqual(got, want) { + t.Errorf("#%d:\ngot %v\nwant %v", i, got, want) + } + } + +} + +func testEqual(a, b interface{}) bool { + if a == nil && b == nil { + return true + } + if a == nil || b == nil { + return false + } + t := reflect.TypeOf(a) + if t != reflect.TypeOf(b) { + return false + } + if am, ok := a.(proto.Message); ok { + return proto.Equal(am, b.(proto.Message)) + } + if t.Kind() != reflect.Slice { + panic(fmt.Sprintf("testEqual can only handle proto.Message and slices, got %s", t)) + } + va := reflect.ValueOf(a) + vb := reflect.ValueOf(b) + if va.Len() != vb.Len() { + return false + } + for i := 0; i < va.Len(); i++ { + if !testEqual(va.Index(i).Interface(), vb.Index(i).Interface()) { + return false + } + } + return true +} + +func TestAnnotateOneError(t *testing.T) { + ctx := context.Background() + c, err := NewImageAnnotatorClient(ctx, clientOpt) + if err != nil { + t.Fatal(err) + } + mockImageAnnotator.resps = []proto.Message{ + &pb.BatchAnnotateImagesResponse{ + Responses: []*pb.AnnotateImageResponse{{ + Error: &status.Status{Code: int32(codes.NotFound), Message: "not found"}, + }}, + }, + } + + _, err = c.annotateOne(ctx, + &pb.Image{Source: &pb.ImageSource{ImageUri: "http://foo.jpg"}}, + nil, pb.Feature_LOGO_DETECTION, 1, nil) + if c := grpc.Code(err); c != codes.NotFound { + t.Errorf("got %v, want NotFound", c) + } +} diff --git a/vendor/cloud.google.com/go/vision/apiv1/doc.go b/vendor/cloud.google.com/go/vision/apiv1/doc.go new file mode 100644 index 00000000..43445248 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/doc.go @@ -0,0 +1,92 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package vision is an auto-generated package for the +// Cloud Vision API. + +// +// Integrates Google Vision features, including image labeling, face, logo, +// and +// landmark detection, optical character recognition (OCR), and detection of +// explicit content, into applications. +package vision // import "cloud.google.com/go/vision/apiv1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/cloud-vision", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/vision/apiv1/examples_test.go b/vendor/cloud.google.com/go/vision/apiv1/examples_test.go new file mode 100644 index 00000000..94650c99 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/examples_test.go @@ -0,0 +1,92 @@ +// Copyright 2016 Google LLC +// +// 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 vision_test + +import ( + "context" + "fmt" + "os" + + vision "cloud.google.com/go/vision/apiv1" + pb "google.golang.org/genproto/googleapis/cloud/vision/v1" +) + +func Example_NewImageFromReader() { + f, err := os.Open("path/to/image.jpg") + if err != nil { + // TODO: handle error. + } + img, err := vision.NewImageFromReader(f) + if err != nil { + // TODO: handle error. + } + fmt.Println(img) +} + +func Example_NewImageFromURI() { + img := vision.NewImageFromURI("gs://my-bucket/my-image.png") + fmt.Println(img) +} + +func ExampleImageAnnotatorClient_AnnotateImage() { + ctx := context.Background() + c, err := vision.NewImageAnnotatorClient(ctx) + if err != nil { + // TODO: Handle error. + } + res, err := c.AnnotateImage(ctx, &pb.AnnotateImageRequest{ + Image: vision.NewImageFromURI("gs://my-bucket/my-image.png"), + Features: []*pb.Feature{ + {Type: pb.Feature_LANDMARK_DETECTION, MaxResults: 5}, + {Type: pb.Feature_LABEL_DETECTION, MaxResults: 3}, + }, + }) + if err != nil { + // TODO: Handle error. + } + // TODO: Use res. + _ = res +} + +func Example_FaceFromLandmarks() { + ctx := context.Background() + c, err := vision.NewImageAnnotatorClient(ctx) + if err != nil { + // TODO: Handle error. + } + resp, err := c.BatchAnnotateImages(ctx, &pb.BatchAnnotateImagesRequest{ + Requests: []*pb.AnnotateImageRequest{ + { + Image: vision.NewImageFromURI("gs://bucket/image.jpg"), + Features: []*pb.Feature{{ + Type: pb.Feature_FACE_DETECTION, + MaxResults: 5, + }}, + }, + }, + }) + if err != nil { + // TODO: Handle error. + } + res := resp.Responses[0] + if res.Error != nil { + // TODO: Handle error. + } + for _, a := range res.FaceAnnotations { + face := vision.FaceFromLandmarks(a.Landmarks) + fmt.Println(face.Nose.Tip) + fmt.Println(face.Eyes.Left.Pupil) + } +} diff --git a/vendor/cloud.google.com/go/vision/apiv1/face.go b/vendor/cloud.google.com/go/vision/apiv1/face.go new file mode 100644 index 00000000..6758121b --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/face.go @@ -0,0 +1,153 @@ +// Copyright 2016 Google LLC +// +// 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 vision + +import ( + "log" + + pb "google.golang.org/genproto/googleapis/cloud/vision/v1" +) + +// FaceLandmarks contains the positions of facial features detected by the service. +type FaceLandmarks struct { + Eyebrows Eyebrows + Eyes Eyes + Ears Ears + Nose Nose + Mouth Mouth + Chin Chin + Forehead *pb.Position +} + +// Eyebrows represents a face's eyebrows. +type Eyebrows struct { + Left, Right Eyebrow +} + +// Eyebrow represents a face's eyebrow. +type Eyebrow struct { + Top, Left, Right *pb.Position +} + +// Eyes represents a face's eyes. +type Eyes struct { + Left, Right Eye +} + +// Eye represents a face's eye. +type Eye struct { + Left, Right, Top, Bottom, Center, Pupil *pb.Position +} + +// Ears represents a face's ears. +type Ears struct { + Left, Right *pb.Position +} + +// Nose represents a face's nose. +type Nose struct { + Left, Right, Top, Bottom, Tip *pb.Position +} + +// Mouth represents a face's mouth. +type Mouth struct { + Left, Center, Right, UpperLip, LowerLip *pb.Position +} + +// Chin represents a face's chin. +type Chin struct { + Left, Center, Right *pb.Position +} + +// FaceFromLandmarks converts the list of face landmarks returned by the service +// to a FaceLandmarks struct. +func FaceFromLandmarks(landmarks []*pb.FaceAnnotation_Landmark) *FaceLandmarks { + face := &FaceLandmarks{} + for _, lm := range landmarks { + switch lm.Type { + case pb.FaceAnnotation_Landmark_LEFT_OF_LEFT_EYEBROW: + face.Eyebrows.Left.Left = lm.Position + case pb.FaceAnnotation_Landmark_RIGHT_OF_LEFT_EYEBROW: + face.Eyebrows.Left.Right = lm.Position + case pb.FaceAnnotation_Landmark_LEFT_OF_RIGHT_EYEBROW: + face.Eyebrows.Right.Left = lm.Position + case pb.FaceAnnotation_Landmark_RIGHT_OF_RIGHT_EYEBROW: + face.Eyebrows.Right.Right = lm.Position + case pb.FaceAnnotation_Landmark_LEFT_EYEBROW_UPPER_MIDPOINT: + face.Eyebrows.Left.Top = lm.Position + case pb.FaceAnnotation_Landmark_RIGHT_EYEBROW_UPPER_MIDPOINT: + face.Eyebrows.Right.Top = lm.Position + case pb.FaceAnnotation_Landmark_MIDPOINT_BETWEEN_EYES: + face.Nose.Top = lm.Position + case pb.FaceAnnotation_Landmark_NOSE_TIP: + face.Nose.Tip = lm.Position + case pb.FaceAnnotation_Landmark_UPPER_LIP: + face.Mouth.UpperLip = lm.Position + case pb.FaceAnnotation_Landmark_LOWER_LIP: + face.Mouth.LowerLip = lm.Position + case pb.FaceAnnotation_Landmark_MOUTH_LEFT: + face.Mouth.Left = lm.Position + case pb.FaceAnnotation_Landmark_MOUTH_RIGHT: + face.Mouth.Right = lm.Position + case pb.FaceAnnotation_Landmark_MOUTH_CENTER: + face.Mouth.Center = lm.Position + case pb.FaceAnnotation_Landmark_NOSE_BOTTOM_RIGHT: + face.Nose.Right = lm.Position + case pb.FaceAnnotation_Landmark_NOSE_BOTTOM_LEFT: + face.Nose.Left = lm.Position + case pb.FaceAnnotation_Landmark_NOSE_BOTTOM_CENTER: + face.Nose.Bottom = lm.Position + case pb.FaceAnnotation_Landmark_LEFT_EYE: + face.Eyes.Left.Center = lm.Position + case pb.FaceAnnotation_Landmark_RIGHT_EYE: + face.Eyes.Right.Center = lm.Position + case pb.FaceAnnotation_Landmark_LEFT_EYE_TOP_BOUNDARY: + face.Eyes.Left.Top = lm.Position + case pb.FaceAnnotation_Landmark_LEFT_EYE_RIGHT_CORNER: + face.Eyes.Left.Right = lm.Position + case pb.FaceAnnotation_Landmark_LEFT_EYE_BOTTOM_BOUNDARY: + face.Eyes.Left.Bottom = lm.Position + case pb.FaceAnnotation_Landmark_LEFT_EYE_LEFT_CORNER: + face.Eyes.Left.Left = lm.Position + case pb.FaceAnnotation_Landmark_RIGHT_EYE_TOP_BOUNDARY: + face.Eyes.Right.Top = lm.Position + case pb.FaceAnnotation_Landmark_RIGHT_EYE_RIGHT_CORNER: + face.Eyes.Right.Right = lm.Position + case pb.FaceAnnotation_Landmark_RIGHT_EYE_BOTTOM_BOUNDARY: + face.Eyes.Right.Bottom = lm.Position + case pb.FaceAnnotation_Landmark_RIGHT_EYE_LEFT_CORNER: + face.Eyes.Right.Left = lm.Position + case pb.FaceAnnotation_Landmark_LEFT_EYE_PUPIL: + face.Eyes.Left.Pupil = lm.Position + case pb.FaceAnnotation_Landmark_RIGHT_EYE_PUPIL: + face.Eyes.Right.Pupil = lm.Position + case pb.FaceAnnotation_Landmark_LEFT_EAR_TRAGION: + face.Ears.Left = lm.Position + case pb.FaceAnnotation_Landmark_RIGHT_EAR_TRAGION: + face.Ears.Right = lm.Position + case pb.FaceAnnotation_Landmark_FOREHEAD_GLABELLA: + face.Forehead = lm.Position + case pb.FaceAnnotation_Landmark_CHIN_GNATHION: + face.Chin.Center = lm.Position + case pb.FaceAnnotation_Landmark_CHIN_LEFT_GONION: + face.Chin.Left = lm.Position + case pb.FaceAnnotation_Landmark_CHIN_RIGHT_GONION: + face.Chin.Right = lm.Position + default: + log.Printf("vision: ignoring unknown face annotation landmark %s", lm.Type) + } + } + return face +} diff --git a/vendor/cloud.google.com/go/vision/apiv1/face_test.go b/vendor/cloud.google.com/go/vision/apiv1/face_test.go new file mode 100644 index 00000000..e5eef4c8 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/face_test.go @@ -0,0 +1,224 @@ +// Copyright 2016 Google LLC +// +// 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 vision + +import ( + "testing" + + "cloud.google.com/go/internal/testutil" + pb "google.golang.org/genproto/googleapis/cloud/vision/v1" +) + +func TestFaceFromLandmarks(t *testing.T) { + landmarks := []*pb.FaceAnnotation_Landmark{ + { + Type: pb.FaceAnnotation_Landmark_LEFT_EYE, + Position: &pb.Position{X: 1192, Y: 575, Z: 0}, + }, + { + Type: pb.FaceAnnotation_Landmark_RIGHT_EYE, + Position: &pb.Position{X: 1479, Y: 571, Z: -9}, + }, + { + Type: pb.FaceAnnotation_Landmark_LEFT_OF_LEFT_EYEBROW, + Position: &pb.Position{X: 1097, Y: 522, Z: 27}, + }, + { + Type: pb.FaceAnnotation_Landmark_RIGHT_OF_LEFT_EYEBROW, + Position: &pb.Position{X: 1266, Y: 521, Z: -61}, + }, + { + Type: pb.FaceAnnotation_Landmark_LEFT_OF_RIGHT_EYEBROW, + Position: &pb.Position{X: 1402, Y: 520, Z: -66}, + }, + { + Type: pb.FaceAnnotation_Landmark_RIGHT_OF_RIGHT_EYEBROW, + Position: &pb.Position{X: 1571, Y: 519, Z: 10}, + }, + { + Type: pb.FaceAnnotation_Landmark_MIDPOINT_BETWEEN_EYES, + Position: &pb.Position{X: 1331, Y: 566, Z: -66}, + }, + { + Type: pb.FaceAnnotation_Landmark_NOSE_TIP, + Position: &pb.Position{X: 1329, Y: 743, Z: -137}, + }, + { + Type: pb.FaceAnnotation_Landmark_UPPER_LIP, + Position: &pb.Position{X: 1330, Y: 836, Z: -66}, + }, + { + Type: pb.FaceAnnotation_Landmark_LOWER_LIP, + Position: &pb.Position{X: 1334, Y: 954, Z: -36}, + }, + { + Type: pb.FaceAnnotation_Landmark_MOUTH_LEFT, + Position: &pb.Position{X: 1186, Y: 867, Z: 27}, + }, + { + Type: pb.FaceAnnotation_Landmark_MOUTH_RIGHT, + Position: &pb.Position{X: 1484, Y: 857, Z: 19}, + }, + { + Type: pb.FaceAnnotation_Landmark_MOUTH_CENTER, + Position: &pb.Position{X: 1332, Y: 894, Z: -41}, + }, + { + Type: pb.FaceAnnotation_Landmark_NOSE_BOTTOM_RIGHT, + Position: &pb.Position{X: 1432, Y: 750, Z: -26}, + }, + { + Type: pb.FaceAnnotation_Landmark_NOSE_BOTTOM_LEFT, + Position: &pb.Position{X: 1236, Y: 755, Z: -20}, + }, + { + Type: pb.FaceAnnotation_Landmark_NOSE_BOTTOM_CENTER, + Position: &pb.Position{X: 1332, Y: 783, Z: -70}, + }, + { + Type: pb.FaceAnnotation_Landmark_LEFT_EYE_TOP_BOUNDARY, + Position: &pb.Position{X: 1193, Y: 561, Z: -20}, + }, + { + Type: pb.FaceAnnotation_Landmark_LEFT_EYE_RIGHT_CORNER, + Position: &pb.Position{X: 1252, Y: 581, Z: -1}, + }, + { + Type: pb.FaceAnnotation_Landmark_LEFT_EYE_BOTTOM_BOUNDARY, + Position: &pb.Position{X: 1190, Y: 593, Z: -1}, + }, + { + Type: pb.FaceAnnotation_Landmark_LEFT_EYE_LEFT_CORNER, + Position: &pb.Position{X: 1133, Y: 584, Z: 28}, + }, + { + Type: pb.FaceAnnotation_Landmark_LEFT_EYE_PUPIL, + Position: &pb.Position{X: 1189, Y: 580, Z: -8}, + }, + { + Type: pb.FaceAnnotation_Landmark_RIGHT_EYE_TOP_BOUNDARY, + Position: &pb.Position{X: 1474, Y: 561, Z: -30}, + }, + { + Type: pb.FaceAnnotation_Landmark_RIGHT_EYE_RIGHT_CORNER, + Position: &pb.Position{X: 1536, Y: 581, Z: 15}, + }, + { + Type: pb.FaceAnnotation_Landmark_RIGHT_EYE_BOTTOM_BOUNDARY, + Position: &pb.Position{X: 1481, Y: 590, Z: -11}, + }, + { + Type: pb.FaceAnnotation_Landmark_RIGHT_EYE_LEFT_CORNER, + Position: &pb.Position{X: 1424, Y: 579, Z: -6}, + }, + { + Type: pb.FaceAnnotation_Landmark_RIGHT_EYE_PUPIL, + Position: &pb.Position{X: 1478, Y: 580, Z: -18}, + }, + { + Type: pb.FaceAnnotation_Landmark_LEFT_EYEBROW_UPPER_MIDPOINT, + Position: &pb.Position{X: 1181, Y: 482, Z: -40}, + }, + { + Type: pb.FaceAnnotation_Landmark_RIGHT_EYEBROW_UPPER_MIDPOINT, + Position: &pb.Position{X: 1485, Y: 482, Z: -50}, + }, + { + Type: pb.FaceAnnotation_Landmark_LEFT_EAR_TRAGION, + Position: &pb.Position{X: 1027, Y: 696, Z: 361}, + }, + { + Type: pb.FaceAnnotation_Landmark_RIGHT_EAR_TRAGION, + Position: &pb.Position{X: 1666, Y: 695, Z: 339}, + }, + { + Type: pb.FaceAnnotation_Landmark_FOREHEAD_GLABELLA, + Position: &pb.Position{X: 1332, Y: 514, Z: -75}, + }, + { + Type: pb.FaceAnnotation_Landmark_CHIN_GNATHION, + Position: &pb.Position{X: 1335, Y: 1058, Z: 6}, + }, + { + Type: pb.FaceAnnotation_Landmark_CHIN_LEFT_GONION, + Position: &pb.Position{X: 1055, Y: 882, Z: 257}, + }, + { + Type: pb.FaceAnnotation_Landmark_CHIN_RIGHT_GONION, + Position: &pb.Position{X: 1631, Y: 881, Z: 238}, + }, + } + want := &FaceLandmarks{ + Eyebrows: Eyebrows{ + Left: Eyebrow{ + Top: &pb.Position{X: 1181, Y: 482, Z: -40}, + Left: &pb.Position{X: 1097, Y: 522, Z: 27}, + Right: &pb.Position{X: 1266, Y: 521, Z: -61}, + }, + Right: Eyebrow{ + Top: &pb.Position{X: 1485, Y: 482, Z: -50}, + Left: &pb.Position{X: 1402, Y: 520, Z: -66}, + Right: &pb.Position{X: 1571, Y: 519, Z: 10}, + }, + }, + Eyes: Eyes{ + Left: Eye{ + Left: &pb.Position{X: 1133, Y: 584, Z: 28}, + Right: &pb.Position{X: 1252, Y: 581, Z: -1}, + Top: &pb.Position{X: 1193, Y: 561, Z: -20}, + Bottom: &pb.Position{X: 1190, Y: 593, Z: -1}, + Center: &pb.Position{X: 1192, Y: 575, Z: 0}, + Pupil: &pb.Position{X: 1189, Y: 580, Z: -8}, + }, + Right: Eye{ + Left: &pb.Position{X: 1424, Y: 579, Z: -6}, + Right: &pb.Position{X: 1536, Y: 581, Z: 15}, + Top: &pb.Position{X: 1474, Y: 561, Z: -30}, + Bottom: &pb.Position{X: 1481, Y: 590, Z: -11}, + Center: &pb.Position{X: 1479, Y: 571, Z: -9}, + Pupil: &pb.Position{X: 1478, Y: 580, Z: -18}, + }, + }, + Ears: Ears{ + Left: &pb.Position{X: 1027, Y: 696, Z: 361}, + Right: &pb.Position{X: 1666, Y: 695, Z: 339}, + }, + Nose: Nose{ + Left: &pb.Position{X: 1236, Y: 755, Z: -20}, + Right: &pb.Position{X: 1432, Y: 750, Z: -26}, + Top: &pb.Position{X: 1331, Y: 566, Z: -66}, + Bottom: &pb.Position{X: 1332, Y: 783, Z: -70}, + Tip: &pb.Position{X: 1329, Y: 743, Z: -137}, + }, + Mouth: Mouth{ + Left: &pb.Position{X: 1186, Y: 867, Z: 27}, + Center: &pb.Position{X: 1332, Y: 894, Z: -41}, + Right: &pb.Position{X: 1484, Y: 857, Z: 19}, + UpperLip: &pb.Position{X: 1330, Y: 836, Z: -66}, + LowerLip: &pb.Position{X: 1334, Y: 954, Z: -36}, + }, + Chin: Chin{ + Left: &pb.Position{X: 1055, Y: 882, Z: 257}, + Center: &pb.Position{X: 1335, Y: 1058, Z: 6}, + Right: &pb.Position{X: 1631, Y: 881, Z: 238}, + }, + Forehead: &pb.Position{X: 1332, Y: 514, Z: -75}, + } + + got := FaceFromLandmarks(landmarks) + if diff := testutil.Diff(got, want); diff != "" { + t.Error(diff) + } +} diff --git a/vendor/cloud.google.com/go/vision/apiv1/image.go b/vendor/cloud.google.com/go/vision/apiv1/image.go new file mode 100644 index 00000000..fd6d9a77 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/image.go @@ -0,0 +1,37 @@ +// Copyright 2017, Google LLC +// +// 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 vision + +import ( + "io" + "io/ioutil" + + pb "google.golang.org/genproto/googleapis/cloud/vision/v1" +) + +// NewImageFromReader reads the bytes of an image from r. +func NewImageFromReader(r io.Reader) (*pb.Image, error) { + bytes, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + return &pb.Image{Content: bytes}, nil +} + +// NewImageFromURI returns an image that refers to an object in Google Cloud Storage +// (when the uri is of the form "gs://BUCKET/OBJECT") or at a public URL. +func NewImageFromURI(uri string) *pb.Image { + return &pb.Image{Source: &pb.ImageSource{ImageUri: uri}} +} diff --git a/vendor/cloud.google.com/go/vision/apiv1/image_annotator_client.go b/vendor/cloud.google.com/go/vision/apiv1/image_annotator_client.go new file mode 100644 index 00000000..d82eedd5 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/image_annotator_client.go @@ -0,0 +1,248 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package vision + +import ( + "context" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + visionpb "google.golang.org/genproto/googleapis/cloud/vision/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// ImageAnnotatorCallOptions contains the retry settings for each method of ImageAnnotatorClient. +type ImageAnnotatorCallOptions struct { + BatchAnnotateImages []gax.CallOption + AsyncBatchAnnotateFiles []gax.CallOption +} + +func defaultImageAnnotatorClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("vision.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultImageAnnotatorCallOptions() *ImageAnnotatorCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &ImageAnnotatorCallOptions{ + BatchAnnotateImages: retry[[2]string{"default", "idempotent"}], + AsyncBatchAnnotateFiles: retry[[2]string{"default", "idempotent"}], + } +} + +// ImageAnnotatorClient is a client for interacting with Cloud Vision API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type ImageAnnotatorClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + imageAnnotatorClient visionpb.ImageAnnotatorClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *ImageAnnotatorCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewImageAnnotatorClient creates a new image annotator client. +// +// Service that performs Google Cloud Vision API detection tasks over client +// images, such as face, landmark, logo, label, and text detection. The +// ImageAnnotator service returns detected entities from the images. +func NewImageAnnotatorClient(ctx context.Context, opts ...option.ClientOption) (*ImageAnnotatorClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultImageAnnotatorClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &ImageAnnotatorClient{ + conn: conn, + CallOptions: defaultImageAnnotatorCallOptions(), + + imageAnnotatorClient: visionpb.NewImageAnnotatorClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *ImageAnnotatorClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *ImageAnnotatorClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *ImageAnnotatorClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// BatchAnnotateImages run image detection and annotation for a batch of images. +func (c *ImageAnnotatorClient) BatchAnnotateImages(ctx context.Context, req *visionpb.BatchAnnotateImagesRequest, opts ...gax.CallOption) (*visionpb.BatchAnnotateImagesResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchAnnotateImages[0:len(c.CallOptions.BatchAnnotateImages):len(c.CallOptions.BatchAnnotateImages)], opts...) + var resp *visionpb.BatchAnnotateImagesResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.imageAnnotatorClient.BatchAnnotateImages(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// AsyncBatchAnnotateFiles run asynchronous image detection and annotation for a list of generic +// files, such as PDF files, which may contain multiple pages and multiple +// images per page. Progress and results can be retrieved through the +// google.longrunning.Operations interface. +// Operation.metadata contains OperationMetadata (metadata). +// Operation.response contains AsyncBatchAnnotateFilesResponse (results). +func (c *ImageAnnotatorClient) AsyncBatchAnnotateFiles(ctx context.Context, req *visionpb.AsyncBatchAnnotateFilesRequest, opts ...gax.CallOption) (*AsyncBatchAnnotateFilesOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AsyncBatchAnnotateFiles[0:len(c.CallOptions.AsyncBatchAnnotateFiles):len(c.CallOptions.AsyncBatchAnnotateFiles)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.imageAnnotatorClient.AsyncBatchAnnotateFiles(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &AsyncBatchAnnotateFilesOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// AsyncBatchAnnotateFilesOperation manages a long-running operation from AsyncBatchAnnotateFiles. +type AsyncBatchAnnotateFilesOperation struct { + lro *longrunning.Operation +} + +// AsyncBatchAnnotateFilesOperation returns a new AsyncBatchAnnotateFilesOperation from a given name. +// The name must be that of a previously created AsyncBatchAnnotateFilesOperation, possibly from a different process. +func (c *ImageAnnotatorClient) AsyncBatchAnnotateFilesOperation(name string) *AsyncBatchAnnotateFilesOperation { + return &AsyncBatchAnnotateFilesOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *AsyncBatchAnnotateFilesOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*visionpb.AsyncBatchAnnotateFilesResponse, error) { + var resp visionpb.AsyncBatchAnnotateFilesResponse + if err := op.lro.WaitWithInterval(ctx, &resp, 45000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *AsyncBatchAnnotateFilesOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*visionpb.AsyncBatchAnnotateFilesResponse, error) { + var resp visionpb.AsyncBatchAnnotateFilesResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *AsyncBatchAnnotateFilesOperation) Metadata() (*visionpb.OperationMetadata, error) { + var meta visionpb.OperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *AsyncBatchAnnotateFilesOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *AsyncBatchAnnotateFilesOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/vision/apiv1/image_annotator_client_example_test.go b/vendor/cloud.google.com/go/vision/apiv1/image_annotator_client_example_test.go new file mode 100644 index 00000000..0f4ca101 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/image_annotator_client_example_test.go @@ -0,0 +1,75 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package vision_test + +import ( + "context" + + vision "cloud.google.com/go/vision/apiv1" + visionpb "google.golang.org/genproto/googleapis/cloud/vision/v1" +) + +func ExampleNewImageAnnotatorClient() { + ctx := context.Background() + c, err := vision.NewImageAnnotatorClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleImageAnnotatorClient_BatchAnnotateImages() { + ctx := context.Background() + c, err := vision.NewImageAnnotatorClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.BatchAnnotateImagesRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.BatchAnnotateImages(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleImageAnnotatorClient_AsyncBatchAnnotateFiles() { + ctx := context.Background() + c, err := vision.NewImageAnnotatorClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.AsyncBatchAnnotateFilesRequest{ + // TODO: Fill request struct fields. + } + op, err := c.AsyncBatchAnnotateFiles(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/vision/apiv1/mock_test.go b/vendor/cloud.google.com/go/vision/apiv1/mock_test.go new file mode 100644 index 00000000..5a7cf2e7 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/mock_test.go @@ -0,0 +1,1644 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package vision + +import ( + emptypb "github.com/golang/protobuf/ptypes/empty" + visionpb "google.golang.org/genproto/googleapis/cloud/vision/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockProductSearchServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + visionpb.ProductSearchServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockProductSearchServer) CreateProductSet(ctx context.Context, req *visionpb.CreateProductSetRequest) (*visionpb.ProductSet, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.ProductSet), nil +} + +func (s *mockProductSearchServer) ListProductSets(ctx context.Context, req *visionpb.ListProductSetsRequest) (*visionpb.ListProductSetsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.ListProductSetsResponse), nil +} + +func (s *mockProductSearchServer) GetProductSet(ctx context.Context, req *visionpb.GetProductSetRequest) (*visionpb.ProductSet, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.ProductSet), nil +} + +func (s *mockProductSearchServer) UpdateProductSet(ctx context.Context, req *visionpb.UpdateProductSetRequest) (*visionpb.ProductSet, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.ProductSet), nil +} + +func (s *mockProductSearchServer) DeleteProductSet(ctx context.Context, req *visionpb.DeleteProductSetRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockProductSearchServer) CreateProduct(ctx context.Context, req *visionpb.CreateProductRequest) (*visionpb.Product, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.Product), nil +} + +func (s *mockProductSearchServer) ListProducts(ctx context.Context, req *visionpb.ListProductsRequest) (*visionpb.ListProductsResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.ListProductsResponse), nil +} + +func (s *mockProductSearchServer) GetProduct(ctx context.Context, req *visionpb.GetProductRequest) (*visionpb.Product, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.Product), nil +} + +func (s *mockProductSearchServer) UpdateProduct(ctx context.Context, req *visionpb.UpdateProductRequest) (*visionpb.Product, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.Product), nil +} + +func (s *mockProductSearchServer) DeleteProduct(ctx context.Context, req *visionpb.DeleteProductRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockProductSearchServer) CreateReferenceImage(ctx context.Context, req *visionpb.CreateReferenceImageRequest) (*visionpb.ReferenceImage, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.ReferenceImage), nil +} + +func (s *mockProductSearchServer) DeleteReferenceImage(ctx context.Context, req *visionpb.DeleteReferenceImageRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockProductSearchServer) ListReferenceImages(ctx context.Context, req *visionpb.ListReferenceImagesRequest) (*visionpb.ListReferenceImagesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.ListReferenceImagesResponse), nil +} + +func (s *mockProductSearchServer) GetReferenceImage(ctx context.Context, req *visionpb.GetReferenceImageRequest) (*visionpb.ReferenceImage, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.ReferenceImage), nil +} + +func (s *mockProductSearchServer) AddProductToProductSet(ctx context.Context, req *visionpb.AddProductToProductSetRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockProductSearchServer) RemoveProductFromProductSet(ctx context.Context, req *visionpb.RemoveProductFromProductSetRequest) (*emptypb.Empty, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*emptypb.Empty), nil +} + +func (s *mockProductSearchServer) ListProductsInProductSet(ctx context.Context, req *visionpb.ListProductsInProductSetRequest) (*visionpb.ListProductsInProductSetResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.ListProductsInProductSetResponse), nil +} + +func (s *mockProductSearchServer) ImportProductSets(ctx context.Context, req *visionpb.ImportProductSetsRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +type mockImageAnnotatorServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + visionpb.ImageAnnotatorServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockImageAnnotatorServer) BatchAnnotateImages(ctx context.Context, req *visionpb.BatchAnnotateImagesRequest) (*visionpb.BatchAnnotateImagesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.BatchAnnotateImagesResponse), nil +} + +func (s *mockImageAnnotatorServer) AsyncBatchAnnotateFiles(ctx context.Context, req *visionpb.AsyncBatchAnnotateFilesRequest) (*longrunningpb.Operation, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*longrunningpb.Operation), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockProductSearch mockProductSearchServer + mockImageAnnotator mockImageAnnotatorServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + visionpb.RegisterProductSearchServer(serv, &mockProductSearch) + visionpb.RegisterImageAnnotatorServer(serv, &mockImageAnnotator) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestProductSearchCreateProduct(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var productCategory string = "productCategory-1607451058" + var expectedResponse = &visionpb.Product{ + Name: name, + DisplayName: displayName, + Description: description, + ProductCategory: productCategory, + } + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var product *visionpb.Product = &visionpb.Product{} + var request = &visionpb.CreateProductRequest{ + Parent: formattedParent, + Product: product, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateProduct(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestProductSearchCreateProductError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var product *visionpb.Product = &visionpb.Product{} + var request = &visionpb.CreateProductRequest{ + Parent: formattedParent, + Product: product, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateProduct(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestProductSearchListProducts(t *testing.T) { + var nextPageToken string = "" + var productsElement *visionpb.Product = &visionpb.Product{} + var products = []*visionpb.Product{productsElement} + var expectedResponse = &visionpb.ListProductsResponse{ + NextPageToken: nextPageToken, + Products: products, + } + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &visionpb.ListProductsRequest{ + Parent: formattedParent, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListProducts(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Products[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestProductSearchListProductsError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &visionpb.ListProductsRequest{ + Parent: formattedParent, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListProducts(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestProductSearchGetProduct(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var productCategory string = "productCategory-1607451058" + var expectedResponse = &visionpb.Product{ + Name: name2, + DisplayName: displayName, + Description: description, + ProductCategory: productCategory, + } + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/products/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT]") + var request = &visionpb.GetProductRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetProduct(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestProductSearchGetProductError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/products/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT]") + var request = &visionpb.GetProductRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetProduct(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestProductSearchUpdateProduct(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var description string = "description-1724546052" + var productCategory string = "productCategory-1607451058" + var expectedResponse = &visionpb.Product{ + Name: name, + DisplayName: displayName, + Description: description, + ProductCategory: productCategory, + } + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var product *visionpb.Product = &visionpb.Product{} + var request = &visionpb.UpdateProductRequest{ + Product: product, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateProduct(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestProductSearchUpdateProductError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var product *visionpb.Product = &visionpb.Product{} + var request = &visionpb.UpdateProductRequest{ + Product: product, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateProduct(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestProductSearchDeleteProduct(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/products/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT]") + var request = &visionpb.DeleteProductRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteProduct(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestProductSearchDeleteProductError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/products/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT]") + var request = &visionpb.DeleteProductRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteProduct(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestProductSearchListReferenceImages(t *testing.T) { + var pageSize int32 = 883849137 + var nextPageToken string = "" + var referenceImagesElement *visionpb.ReferenceImage = &visionpb.ReferenceImage{} + var referenceImages = []*visionpb.ReferenceImage{referenceImagesElement} + var expectedResponse = &visionpb.ListReferenceImagesResponse{ + PageSize: pageSize, + NextPageToken: nextPageToken, + ReferenceImages: referenceImages, + } + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/products/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT]") + var request = &visionpb.ListReferenceImagesRequest{ + Parent: formattedParent, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListReferenceImages(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.ReferenceImages[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestProductSearchListReferenceImagesError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/products/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT]") + var request = &visionpb.ListReferenceImagesRequest{ + Parent: formattedParent, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListReferenceImages(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestProductSearchGetReferenceImage(t *testing.T) { + var name2 string = "name2-1052831874" + var uri string = "uri116076" + var expectedResponse = &visionpb.ReferenceImage{ + Name: name2, + Uri: uri, + } + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/products/%s/referenceImages/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT]", "[REFERENCE_IMAGE]") + var request = &visionpb.GetReferenceImageRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetReferenceImage(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestProductSearchGetReferenceImageError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/products/%s/referenceImages/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT]", "[REFERENCE_IMAGE]") + var request = &visionpb.GetReferenceImageRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetReferenceImage(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestProductSearchDeleteReferenceImage(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/products/%s/referenceImages/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT]", "[REFERENCE_IMAGE]") + var request = &visionpb.DeleteReferenceImageRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteReferenceImage(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestProductSearchDeleteReferenceImageError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/products/%s/referenceImages/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT]", "[REFERENCE_IMAGE]") + var request = &visionpb.DeleteReferenceImageRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteReferenceImage(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestProductSearchCreateReferenceImage(t *testing.T) { + var name string = "name3373707" + var uri string = "uri116076" + var expectedResponse = &visionpb.ReferenceImage{ + Name: name, + Uri: uri, + } + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/products/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT]") + var referenceImage *visionpb.ReferenceImage = &visionpb.ReferenceImage{} + var request = &visionpb.CreateReferenceImageRequest{ + Parent: formattedParent, + ReferenceImage: referenceImage, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateReferenceImage(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestProductSearchCreateReferenceImageError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s/products/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT]") + var referenceImage *visionpb.ReferenceImage = &visionpb.ReferenceImage{} + var request = &visionpb.CreateReferenceImageRequest{ + Parent: formattedParent, + ReferenceImage: referenceImage, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateReferenceImage(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestProductSearchCreateProductSet(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var expectedResponse = &visionpb.ProductSet{ + Name: name, + DisplayName: displayName, + } + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var productSet *visionpb.ProductSet = &visionpb.ProductSet{} + var request = &visionpb.CreateProductSetRequest{ + Parent: formattedParent, + ProductSet: productSet, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateProductSet(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestProductSearchCreateProductSetError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var productSet *visionpb.ProductSet = &visionpb.ProductSet{} + var request = &visionpb.CreateProductSetRequest{ + Parent: formattedParent, + ProductSet: productSet, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.CreateProductSet(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestProductSearchListProductSets(t *testing.T) { + var nextPageToken string = "" + var productSetsElement *visionpb.ProductSet = &visionpb.ProductSet{} + var productSets = []*visionpb.ProductSet{productSetsElement} + var expectedResponse = &visionpb.ListProductSetsResponse{ + NextPageToken: nextPageToken, + ProductSets: productSets, + } + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &visionpb.ListProductSetsRequest{ + Parent: formattedParent, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListProductSets(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.ProductSets[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestProductSearchListProductSetsError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var request = &visionpb.ListProductSetsRequest{ + Parent: formattedParent, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListProductSets(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestProductSearchGetProductSet(t *testing.T) { + var name2 string = "name2-1052831874" + var displayName string = "displayName1615086568" + var expectedResponse = &visionpb.ProductSet{ + Name: name2, + DisplayName: displayName, + } + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/productSets/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT_SET]") + var request = &visionpb.GetProductSetRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetProductSet(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestProductSearchGetProductSetError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/productSets/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT_SET]") + var request = &visionpb.GetProductSetRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.GetProductSet(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestProductSearchUpdateProductSet(t *testing.T) { + var name string = "name3373707" + var displayName string = "displayName1615086568" + var expectedResponse = &visionpb.ProductSet{ + Name: name, + DisplayName: displayName, + } + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var productSet *visionpb.ProductSet = &visionpb.ProductSet{} + var request = &visionpb.UpdateProductSetRequest{ + ProductSet: productSet, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateProductSet(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestProductSearchUpdateProductSetError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var productSet *visionpb.ProductSet = &visionpb.ProductSet{} + var request = &visionpb.UpdateProductSetRequest{ + ProductSet: productSet, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.UpdateProductSet(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestProductSearchDeleteProductSet(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/productSets/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT_SET]") + var request = &visionpb.DeleteProductSetRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteProductSet(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestProductSearchDeleteProductSetError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/productSets/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT_SET]") + var request = &visionpb.DeleteProductSetRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.DeleteProductSet(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestProductSearchAddProductToProductSet(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/productSets/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT_SET]") + var product string = "product-309474065" + var request = &visionpb.AddProductToProductSetRequest{ + Name: formattedName, + Product: product, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.AddProductToProductSet(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestProductSearchAddProductToProductSetError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/productSets/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT_SET]") + var product string = "product-309474065" + var request = &visionpb.AddProductToProductSetRequest{ + Name: formattedName, + Product: product, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.AddProductToProductSet(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestProductSearchRemoveProductFromProductSet(t *testing.T) { + var expectedResponse *emptypb.Empty = &emptypb.Empty{} + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/productSets/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT_SET]") + var product string = "product-309474065" + var request = &visionpb.RemoveProductFromProductSetRequest{ + Name: formattedName, + Product: product, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.RemoveProductFromProductSet(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + +} + +func TestProductSearchRemoveProductFromProductSetError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/productSets/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT_SET]") + var product string = "product-309474065" + var request = &visionpb.RemoveProductFromProductSetRequest{ + Name: formattedName, + Product: product, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + err = c.RemoveProductFromProductSet(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } +} +func TestProductSearchListProductsInProductSet(t *testing.T) { + var nextPageToken string = "" + var productsElement *visionpb.Product = &visionpb.Product{} + var products = []*visionpb.Product{productsElement} + var expectedResponse = &visionpb.ListProductsInProductSetResponse{ + NextPageToken: nextPageToken, + Products: products, + } + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + mockProductSearch.resps = append(mockProductSearch.resps[:0], expectedResponse) + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/productSets/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT_SET]") + var request = &visionpb.ListProductsInProductSetRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListProductsInProductSet(context.Background(), request).Next() + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + want := (interface{})(expectedResponse.Products[0]) + got := (interface{})(resp) + var ok bool + + switch want := (want).(type) { + case proto.Message: + ok = proto.Equal(want, got.(proto.Message)) + default: + ok = want == got + } + if !ok { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestProductSearchListProductsInProductSetError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = gstatus.Error(errCode, "test error") + + var formattedName string = fmt.Sprintf("projects/%s/locations/%s/productSets/%s", "[PROJECT]", "[LOCATION]", "[PRODUCT_SET]") + var request = &visionpb.ListProductsInProductSetRequest{ + Name: formattedName, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.ListProductsInProductSet(context.Background(), request).Next() + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestProductSearchImportProductSets(t *testing.T) { + var expectedResponse *visionpb.ImportProductSetsResponse = &visionpb.ImportProductSetsResponse{} + + mockProductSearch.err = nil + mockProductSearch.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockProductSearch.resps = append(mockProductSearch.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var inputConfig *visionpb.ImportProductSetsInputConfig = &visionpb.ImportProductSetsInputConfig{} + var request = &visionpb.ImportProductSetsRequest{ + Parent: formattedParent, + InputConfig: inputConfig, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.ImportProductSets(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockProductSearch.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestProductSearchImportProductSetsError(t *testing.T) { + errCode := codes.PermissionDenied + mockProductSearch.err = nil + mockProductSearch.resps = append(mockProductSearch.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var formattedParent string = fmt.Sprintf("projects/%s/locations/%s", "[PROJECT]", "[LOCATION]") + var inputConfig *visionpb.ImportProductSetsInputConfig = &visionpb.ImportProductSetsInputConfig{} + var request = &visionpb.ImportProductSetsRequest{ + Parent: formattedParent, + InputConfig: inputConfig, + } + + c, err := NewProductSearchClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.ImportProductSets(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestImageAnnotatorBatchAnnotateImages(t *testing.T) { + var expectedResponse *visionpb.BatchAnnotateImagesResponse = &visionpb.BatchAnnotateImagesResponse{} + + mockImageAnnotator.err = nil + mockImageAnnotator.reqs = nil + + mockImageAnnotator.resps = append(mockImageAnnotator.resps[:0], expectedResponse) + + var requests []*visionpb.AnnotateImageRequest = nil + var request = &visionpb.BatchAnnotateImagesRequest{ + Requests: requests, + } + + c, err := NewImageAnnotatorClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BatchAnnotateImages(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockImageAnnotator.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestImageAnnotatorBatchAnnotateImagesError(t *testing.T) { + errCode := codes.PermissionDenied + mockImageAnnotator.err = gstatus.Error(errCode, "test error") + + var requests []*visionpb.AnnotateImageRequest = nil + var request = &visionpb.BatchAnnotateImagesRequest{ + Requests: requests, + } + + c, err := NewImageAnnotatorClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BatchAnnotateImages(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} +func TestImageAnnotatorAsyncBatchAnnotateFiles(t *testing.T) { + var expectedResponse *visionpb.AsyncBatchAnnotateFilesResponse = &visionpb.AsyncBatchAnnotateFilesResponse{} + + mockImageAnnotator.err = nil + mockImageAnnotator.reqs = nil + + any, err := ptypes.MarshalAny(expectedResponse) + if err != nil { + t.Fatal(err) + } + mockImageAnnotator.resps = append(mockImageAnnotator.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Response{Response: any}, + }) + + var requests []*visionpb.AsyncAnnotateFileRequest = nil + var request = &visionpb.AsyncBatchAnnotateFilesRequest{ + Requests: requests, + } + + c, err := NewImageAnnotatorClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.AsyncBatchAnnotateFiles(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockImageAnnotator.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestImageAnnotatorAsyncBatchAnnotateFilesError(t *testing.T) { + errCode := codes.PermissionDenied + mockImageAnnotator.err = nil + mockImageAnnotator.resps = append(mockImageAnnotator.resps[:0], &longrunningpb.Operation{ + Name: "longrunning-test", + Done: true, + Result: &longrunningpb.Operation_Error{ + Error: &status.Status{ + Code: int32(errCode), + Message: "test error", + }, + }, + }) + + var requests []*visionpb.AsyncAnnotateFileRequest = nil + var request = &visionpb.AsyncBatchAnnotateFilesRequest{ + Requests: requests, + } + + c, err := NewImageAnnotatorClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + respLRO, err := c.AsyncBatchAnnotateFiles(context.Background(), request) + if err != nil { + t.Fatal(err) + } + resp, err := respLRO.Wait(context.Background()) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/cloud.google.com/go/vision/apiv1/product_search_client.go b/vendor/cloud.google.com/go/vision/apiv1/product_search_client.go new file mode 100644 index 00000000..2a835abb --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/product_search_client.go @@ -0,0 +1,875 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package vision + +import ( + "context" + "math" + "time" + + "cloud.google.com/go/longrunning" + lroauto "cloud.google.com/go/longrunning/autogen" + "github.com/golang/protobuf/proto" + gax "github.com/googleapis/gax-go" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + "google.golang.org/api/transport" + visionpb "google.golang.org/genproto/googleapis/cloud/vision/v1" + longrunningpb "google.golang.org/genproto/googleapis/longrunning" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// ProductSearchCallOptions contains the retry settings for each method of ProductSearchClient. +type ProductSearchCallOptions struct { + CreateProduct []gax.CallOption + ListProducts []gax.CallOption + GetProduct []gax.CallOption + UpdateProduct []gax.CallOption + DeleteProduct []gax.CallOption + ListReferenceImages []gax.CallOption + GetReferenceImage []gax.CallOption + DeleteReferenceImage []gax.CallOption + CreateReferenceImage []gax.CallOption + CreateProductSet []gax.CallOption + ListProductSets []gax.CallOption + GetProductSet []gax.CallOption + UpdateProductSet []gax.CallOption + DeleteProductSet []gax.CallOption + AddProductToProductSet []gax.CallOption + RemoveProductFromProductSet []gax.CallOption + ListProductsInProductSet []gax.CallOption + ImportProductSets []gax.CallOption +} + +func defaultProductSearchClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("vision.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultProductSearchCallOptions() *ProductSearchCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &ProductSearchCallOptions{ + CreateProduct: retry[[2]string{"default", "non_idempotent"}], + ListProducts: retry[[2]string{"default", "idempotent"}], + GetProduct: retry[[2]string{"default", "idempotent"}], + UpdateProduct: retry[[2]string{"default", "idempotent"}], + DeleteProduct: retry[[2]string{"default", "idempotent"}], + ListReferenceImages: retry[[2]string{"default", "idempotent"}], + GetReferenceImage: retry[[2]string{"default", "idempotent"}], + DeleteReferenceImage: retry[[2]string{"default", "idempotent"}], + CreateReferenceImage: retry[[2]string{"default", "non_idempotent"}], + CreateProductSet: retry[[2]string{"default", "non_idempotent"}], + ListProductSets: retry[[2]string{"default", "idempotent"}], + GetProductSet: retry[[2]string{"default", "idempotent"}], + UpdateProductSet: retry[[2]string{"default", "idempotent"}], + DeleteProductSet: retry[[2]string{"default", "idempotent"}], + AddProductToProductSet: retry[[2]string{"default", "idempotent"}], + RemoveProductFromProductSet: retry[[2]string{"default", "idempotent"}], + ListProductsInProductSet: retry[[2]string{"default", "idempotent"}], + ImportProductSets: retry[[2]string{"default", "non_idempotent"}], + } +} + +// ProductSearchClient is a client for interacting with Cloud Vision API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type ProductSearchClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + productSearchClient visionpb.ProductSearchClient + + // LROClient is used internally to handle longrunning operations. + // It is exposed so that its CallOptions can be modified if required. + // Users should not Close this client. + LROClient *lroauto.OperationsClient + + // The call options for this service. + CallOptions *ProductSearchCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewProductSearchClient creates a new product search client. +// +// Manages Products and ProductSets of reference images for use in product +// search. It uses the following resource model: +// +// The API has a collection of [ProductSet][google.cloud.vision.v1.ProductSet] resources, named +// projects/*/locations/*/productSets/*, which acts as a way to put different +// products into groups to limit identification. +// +// In parallel, +// +// The API has a collection of [Product][google.cloud.vision.v1.Product] resources, named +// projects/*/locations/*/products/* +// +// Each [Product][google.cloud.vision.v1.Product] has a collection of [ReferenceImage][google.cloud.vision.v1.ReferenceImage] resources, named +// projects/*/locations/*/products/*/referenceImages/* +func NewProductSearchClient(ctx context.Context, opts ...option.ClientOption) (*ProductSearchClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultProductSearchClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &ProductSearchClient{ + conn: conn, + CallOptions: defaultProductSearchCallOptions(), + + productSearchClient: visionpb.NewProductSearchClient(conn), + } + c.setGoogleClientInfo() + + c.LROClient, err = lroauto.NewOperationsClient(ctx, option.WithGRPCConn(conn)) + if err != nil { + // This error "should not happen", since we are just reusing old connection + // and never actually need to dial. + // If this does happen, we could leak conn. However, we cannot close conn: + // If the user invoked the function with option.WithGRPCConn, + // we would close a connection that's still in use. + // TODO(pongad): investigate error conditions. + return nil, err + } + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *ProductSearchClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *ProductSearchClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *ProductSearchClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// CreateProduct creates and returns a new product resource. +// +// Possible errors: +// +// Returns INVALID_ARGUMENT if display_name is missing or longer than 4096 +// characters. +// +// Returns INVALID_ARGUMENT if description is longer than 4096 characters. +// +// Returns INVALID_ARGUMENT if product_category is missing or invalid. +func (c *ProductSearchClient) CreateProduct(ctx context.Context, req *visionpb.CreateProductRequest, opts ...gax.CallOption) (*visionpb.Product, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateProduct[0:len(c.CallOptions.CreateProduct):len(c.CallOptions.CreateProduct)], opts...) + var resp *visionpb.Product + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.productSearchClient.CreateProduct(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListProducts lists products in an unspecified order. +// +// Possible errors: +// +// Returns INVALID_ARGUMENT if page_size is greater than 100 or less than 1. +func (c *ProductSearchClient) ListProducts(ctx context.Context, req *visionpb.ListProductsRequest, opts ...gax.CallOption) *ProductIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListProducts[0:len(c.CallOptions.ListProducts):len(c.CallOptions.ListProducts)], opts...) + it := &ProductIterator{} + req = proto.Clone(req).(*visionpb.ListProductsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*visionpb.Product, string, error) { + var resp *visionpb.ListProductsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.productSearchClient.ListProducts(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Products, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetProduct gets information associated with a Product. +// +// Possible errors: +// +// Returns NOT_FOUND if the Product does not exist. +func (c *ProductSearchClient) GetProduct(ctx context.Context, req *visionpb.GetProductRequest, opts ...gax.CallOption) (*visionpb.Product, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetProduct[0:len(c.CallOptions.GetProduct):len(c.CallOptions.GetProduct)], opts...) + var resp *visionpb.Product + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.productSearchClient.GetProduct(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateProduct makes changes to a Product resource. +// Only the display_name, description, and labels fields can be updated +// right now. +// +// If labels are updated, the change will not be reflected in queries until +// the next index time. +// +// Possible errors: +// +// Returns NOT_FOUND if the Product does not exist. +// +// Returns INVALID_ARGUMENT if display_name is present in update_mask but is +// missing from the request or longer than 4096 characters. +// +// Returns INVALID_ARGUMENT if description is present in update_mask but is +// longer than 4096 characters. +// +// Returns INVALID_ARGUMENT if product_category is present in update_mask. +func (c *ProductSearchClient) UpdateProduct(ctx context.Context, req *visionpb.UpdateProductRequest, opts ...gax.CallOption) (*visionpb.Product, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateProduct[0:len(c.CallOptions.UpdateProduct):len(c.CallOptions.UpdateProduct)], opts...) + var resp *visionpb.Product + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.productSearchClient.UpdateProduct(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteProduct permanently deletes a product and its reference images. +// +// Metadata of the product and all its images will be deleted right away, but +// search queries against ProductSets containing the product may still work +// until all related caches are refreshed. +// +// Possible errors: +// +// Returns NOT_FOUND if the product does not exist. +func (c *ProductSearchClient) DeleteProduct(ctx context.Context, req *visionpb.DeleteProductRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteProduct[0:len(c.CallOptions.DeleteProduct):len(c.CallOptions.DeleteProduct)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.productSearchClient.DeleteProduct(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ListReferenceImages lists reference images. +// +// Possible errors: +// +// Returns NOT_FOUND if the parent product does not exist. +// +// Returns INVALID_ARGUMENT if the page_size is greater than 100, or less +// than 1. +func (c *ProductSearchClient) ListReferenceImages(ctx context.Context, req *visionpb.ListReferenceImagesRequest, opts ...gax.CallOption) *ReferenceImageIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListReferenceImages[0:len(c.CallOptions.ListReferenceImages):len(c.CallOptions.ListReferenceImages)], opts...) + it := &ReferenceImageIterator{} + req = proto.Clone(req).(*visionpb.ListReferenceImagesRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*visionpb.ReferenceImage, string, error) { + var resp *visionpb.ListReferenceImagesResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.productSearchClient.ListReferenceImages(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.ReferenceImages, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetReferenceImage gets information associated with a ReferenceImage. +// +// Possible errors: +// +// Returns NOT_FOUND if the specified image does not exist. +func (c *ProductSearchClient) GetReferenceImage(ctx context.Context, req *visionpb.GetReferenceImageRequest, opts ...gax.CallOption) (*visionpb.ReferenceImage, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetReferenceImage[0:len(c.CallOptions.GetReferenceImage):len(c.CallOptions.GetReferenceImage)], opts...) + var resp *visionpb.ReferenceImage + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.productSearchClient.GetReferenceImage(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteReferenceImage permanently deletes a reference image. +// +// The image metadata will be deleted right away, but search queries +// against ProductSets containing the image may still work until all related +// caches are refreshed. +// +// The actual image files are not deleted from Google Cloud Storage. +// +// Possible errors: +// +// Returns NOT_FOUND if the reference image does not exist. +func (c *ProductSearchClient) DeleteReferenceImage(ctx context.Context, req *visionpb.DeleteReferenceImageRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteReferenceImage[0:len(c.CallOptions.DeleteReferenceImage):len(c.CallOptions.DeleteReferenceImage)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.productSearchClient.DeleteReferenceImage(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// CreateReferenceImage creates and returns a new ReferenceImage resource. +// +// The bounding_poly field is optional. If bounding_poly is not specified, +// the system will try to detect regions of interest in the image that are +// compatible with the product_category on the parent product. If it is +// specified, detection is ALWAYS skipped. The system converts polygons into +// non-rotated rectangles. +// +// Note that the pipeline will resize the image if the image resolution is too +// large to process (above 50MP). +// +// Possible errors: +// +// Returns INVALID_ARGUMENT if the image_uri is missing or longer than 4096 +// characters. +// +// Returns INVALID_ARGUMENT if the product does not exist. +// +// Returns INVALID_ARGUMENT if bounding_poly is not provided, and nothing +// compatible with the parent product's product_category is detected. +// +// Returns INVALID_ARGUMENT if bounding_poly contains more than 10 polygons. +func (c *ProductSearchClient) CreateReferenceImage(ctx context.Context, req *visionpb.CreateReferenceImageRequest, opts ...gax.CallOption) (*visionpb.ReferenceImage, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateReferenceImage[0:len(c.CallOptions.CreateReferenceImage):len(c.CallOptions.CreateReferenceImage)], opts...) + var resp *visionpb.ReferenceImage + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.productSearchClient.CreateReferenceImage(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// CreateProductSet creates and returns a new ProductSet resource. +// +// Possible errors: +// +// Returns INVALID_ARGUMENT if display_name is missing, or is longer than +// 4096 characters. +func (c *ProductSearchClient) CreateProductSet(ctx context.Context, req *visionpb.CreateProductSetRequest, opts ...gax.CallOption) (*visionpb.ProductSet, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.CreateProductSet[0:len(c.CallOptions.CreateProductSet):len(c.CallOptions.CreateProductSet)], opts...) + var resp *visionpb.ProductSet + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.productSearchClient.CreateProductSet(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// ListProductSets lists ProductSets in an unspecified order. +// +// Possible errors: +// +// Returns INVALID_ARGUMENT if page_size is greater than 100, or less +// than 1. +func (c *ProductSearchClient) ListProductSets(ctx context.Context, req *visionpb.ListProductSetsRequest, opts ...gax.CallOption) *ProductSetIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListProductSets[0:len(c.CallOptions.ListProductSets):len(c.CallOptions.ListProductSets)], opts...) + it := &ProductSetIterator{} + req = proto.Clone(req).(*visionpb.ListProductSetsRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*visionpb.ProductSet, string, error) { + var resp *visionpb.ListProductSetsResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.productSearchClient.ListProductSets(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.ProductSets, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// GetProductSet gets information associated with a ProductSet. +// +// Possible errors: +// +// Returns NOT_FOUND if the ProductSet does not exist. +func (c *ProductSearchClient) GetProductSet(ctx context.Context, req *visionpb.GetProductSetRequest, opts ...gax.CallOption) (*visionpb.ProductSet, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.GetProductSet[0:len(c.CallOptions.GetProductSet):len(c.CallOptions.GetProductSet)], opts...) + var resp *visionpb.ProductSet + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.productSearchClient.GetProductSet(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// UpdateProductSet makes changes to a ProductSet resource. +// Only display_name can be updated currently. +// +// Possible errors: +// +// Returns NOT_FOUND if the ProductSet does not exist. +// +// Returns INVALID_ARGUMENT if display_name is present in update_mask but +// missing from the request or longer than 4096 characters. +func (c *ProductSearchClient) UpdateProductSet(ctx context.Context, req *visionpb.UpdateProductSetRequest, opts ...gax.CallOption) (*visionpb.ProductSet, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.UpdateProductSet[0:len(c.CallOptions.UpdateProductSet):len(c.CallOptions.UpdateProductSet)], opts...) + var resp *visionpb.ProductSet + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.productSearchClient.UpdateProductSet(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} + +// DeleteProductSet permanently deletes a ProductSet. Products and ReferenceImages in the +// ProductSet are not deleted. +// +// The actual image files are not deleted from Google Cloud Storage. +// +// Possible errors: +// +// Returns NOT_FOUND if the ProductSet does not exist. +func (c *ProductSearchClient) DeleteProductSet(ctx context.Context, req *visionpb.DeleteProductSetRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.DeleteProductSet[0:len(c.CallOptions.DeleteProductSet):len(c.CallOptions.DeleteProductSet)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.productSearchClient.DeleteProductSet(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// AddProductToProductSet adds a Product to the specified ProductSet. If the Product is already +// present, no change is made. +// +// One Product can be added to at most 100 ProductSets. +// +// Possible errors: +// +// Returns NOT_FOUND if the Product or the ProductSet doesn't exist. +func (c *ProductSearchClient) AddProductToProductSet(ctx context.Context, req *visionpb.AddProductToProductSetRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.AddProductToProductSet[0:len(c.CallOptions.AddProductToProductSet):len(c.CallOptions.AddProductToProductSet)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.productSearchClient.AddProductToProductSet(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// RemoveProductFromProductSet removes a Product from the specified ProductSet. +// +// Possible errors: +// +// Returns NOT_FOUND If the Product is not found under the ProductSet. +func (c *ProductSearchClient) RemoveProductFromProductSet(ctx context.Context, req *visionpb.RemoveProductFromProductSetRequest, opts ...gax.CallOption) error { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.RemoveProductFromProductSet[0:len(c.CallOptions.RemoveProductFromProductSet):len(c.CallOptions.RemoveProductFromProductSet)], opts...) + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + _, err = c.productSearchClient.RemoveProductFromProductSet(ctx, req, settings.GRPC...) + return err + }, opts...) + return err +} + +// ListProductsInProductSet lists the Products in a ProductSet, in an unspecified order. If the +// ProductSet does not exist, the products field of the response will be +// empty. +// +// Possible errors: +// +// Returns INVALID_ARGUMENT if page_size is greater than 100 or less than 1. +func (c *ProductSearchClient) ListProductsInProductSet(ctx context.Context, req *visionpb.ListProductsInProductSetRequest, opts ...gax.CallOption) *ProductIterator { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ListProductsInProductSet[0:len(c.CallOptions.ListProductsInProductSet):len(c.CallOptions.ListProductsInProductSet)], opts...) + it := &ProductIterator{} + req = proto.Clone(req).(*visionpb.ListProductsInProductSetRequest) + it.InternalFetch = func(pageSize int, pageToken string) ([]*visionpb.Product, string, error) { + var resp *visionpb.ListProductsInProductSetResponse + req.PageToken = pageToken + if pageSize > math.MaxInt32 { + req.PageSize = math.MaxInt32 + } else { + req.PageSize = int32(pageSize) + } + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.productSearchClient.ListProductsInProductSet(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, "", err + } + return resp.Products, resp.NextPageToken, nil + } + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.PageSize) + return it +} + +// ImportProductSets asynchronous API that imports a list of reference images to specified +// product sets based on a list of image information. +// +// The [google.longrunning.Operation][google.longrunning.Operation] API can be used to keep track of the +// progress and results of the request. +// Operation.metadata contains BatchOperationMetadata. (progress) +// Operation.response contains ImportProductSetsResponse. (results) +// +// The input source of this method is a csv file on Google Cloud Storage. +// For the format of the csv file please see +// [ImportProductSetsGcsSource.csv_file_uri][google.cloud.vision.v1.ImportProductSetsGcsSource.csv_file_uri]. +func (c *ProductSearchClient) ImportProductSets(ctx context.Context, req *visionpb.ImportProductSetsRequest, opts ...gax.CallOption) (*ImportProductSetsOperation, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.ImportProductSets[0:len(c.CallOptions.ImportProductSets):len(c.CallOptions.ImportProductSets)], opts...) + var resp *longrunningpb.Operation + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.productSearchClient.ImportProductSets(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return &ImportProductSetsOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, resp), + }, nil +} + +// ProductIterator manages a stream of *visionpb.Product. +type ProductIterator struct { + items []*visionpb.Product + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*visionpb.Product, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ProductIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ProductIterator) Next() (*visionpb.Product, error) { + var item *visionpb.Product + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ProductIterator) bufLen() int { + return len(it.items) +} + +func (it *ProductIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// ProductSetIterator manages a stream of *visionpb.ProductSet. +type ProductSetIterator struct { + items []*visionpb.ProductSet + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*visionpb.ProductSet, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ProductSetIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ProductSetIterator) Next() (*visionpb.ProductSet, error) { + var item *visionpb.ProductSet + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ProductSetIterator) bufLen() int { + return len(it.items) +} + +func (it *ProductSetIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// ReferenceImageIterator manages a stream of *visionpb.ReferenceImage. +type ReferenceImageIterator struct { + items []*visionpb.ReferenceImage + pageInfo *iterator.PageInfo + nextFunc func() error + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*visionpb.ReferenceImage, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ReferenceImageIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ReferenceImageIterator) Next() (*visionpb.ReferenceImage, error) { + var item *visionpb.ReferenceImage + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ReferenceImageIterator) bufLen() int { + return len(it.items) +} + +func (it *ReferenceImageIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// ImportProductSetsOperation manages a long-running operation from ImportProductSets. +type ImportProductSetsOperation struct { + lro *longrunning.Operation +} + +// ImportProductSetsOperation returns a new ImportProductSetsOperation from a given name. +// The name must be that of a previously created ImportProductSetsOperation, possibly from a different process. +func (c *ProductSearchClient) ImportProductSetsOperation(name string) *ImportProductSetsOperation { + return &ImportProductSetsOperation{ + lro: longrunning.InternalNewOperation(c.LROClient, &longrunningpb.Operation{Name: name}), + } +} + +// Wait blocks until the long-running operation is completed, returning the response and any errors encountered. +// +// See documentation of Poll for error-handling information. +func (op *ImportProductSetsOperation) Wait(ctx context.Context, opts ...gax.CallOption) (*visionpb.ImportProductSetsResponse, error) { + var resp visionpb.ImportProductSetsResponse + if err := op.lro.WaitWithInterval(ctx, &resp, 45000*time.Millisecond, opts...); err != nil { + return nil, err + } + return &resp, nil +} + +// Poll fetches the latest state of the long-running operation. +// +// Poll also fetches the latest metadata, which can be retrieved by Metadata. +// +// If Poll fails, the error is returned and op is unmodified. If Poll succeeds and +// the operation has completed with failure, the error is returned and op.Done will return true. +// If Poll succeeds and the operation has completed successfully, +// op.Done will return true, and the response of the operation is returned. +// If Poll succeeds and the operation has not completed, the returned response and error are both nil. +func (op *ImportProductSetsOperation) Poll(ctx context.Context, opts ...gax.CallOption) (*visionpb.ImportProductSetsResponse, error) { + var resp visionpb.ImportProductSetsResponse + if err := op.lro.Poll(ctx, &resp, opts...); err != nil { + return nil, err + } + if !op.Done() { + return nil, nil + } + return &resp, nil +} + +// Metadata returns metadata associated with the long-running operation. +// Metadata itself does not contact the server, but Poll does. +// To get the latest metadata, call this method after a successful call to Poll. +// If the metadata is not available, the returned metadata and error are both nil. +func (op *ImportProductSetsOperation) Metadata() (*visionpb.BatchOperationMetadata, error) { + var meta visionpb.BatchOperationMetadata + if err := op.lro.Metadata(&meta); err == longrunning.ErrNoMetadata { + return nil, nil + } else if err != nil { + return nil, err + } + return &meta, nil +} + +// Done reports whether the long-running operation has completed. +func (op *ImportProductSetsOperation) Done() bool { + return op.lro.Done() +} + +// Name returns the name of the long-running operation. +// The name is assigned by the server and is unique within the service from which the operation is created. +func (op *ImportProductSetsOperation) Name() string { + return op.lro.Name() +} diff --git a/vendor/cloud.google.com/go/vision/apiv1/product_search_client_example_test.go b/vendor/cloud.google.com/go/vision/apiv1/product_search_client_example_test.go new file mode 100644 index 00000000..116fd964 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1/product_search_client_example_test.go @@ -0,0 +1,378 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package vision_test + +import ( + "context" + + vision "cloud.google.com/go/vision/apiv1" + "google.golang.org/api/iterator" + visionpb "google.golang.org/genproto/googleapis/cloud/vision/v1" +) + +func ExampleNewProductSearchClient() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleProductSearchClient_CreateProduct() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.CreateProductRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateProduct(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleProductSearchClient_ListProducts() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.ListProductsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListProducts(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleProductSearchClient_GetProduct() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.GetProductRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetProduct(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleProductSearchClient_UpdateProduct() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.UpdateProductRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateProduct(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleProductSearchClient_DeleteProduct() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.DeleteProductRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteProduct(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleProductSearchClient_ListReferenceImages() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.ListReferenceImagesRequest{ + // TODO: Fill request struct fields. + } + it := c.ListReferenceImages(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleProductSearchClient_GetReferenceImage() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.GetReferenceImageRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetReferenceImage(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleProductSearchClient_DeleteReferenceImage() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.DeleteReferenceImageRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteReferenceImage(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleProductSearchClient_CreateReferenceImage() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.CreateReferenceImageRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateReferenceImage(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleProductSearchClient_CreateProductSet() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.CreateProductSetRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.CreateProductSet(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleProductSearchClient_ListProductSets() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.ListProductSetsRequest{ + // TODO: Fill request struct fields. + } + it := c.ListProductSets(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleProductSearchClient_GetProductSet() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.GetProductSetRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.GetProductSet(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleProductSearchClient_UpdateProductSet() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.UpdateProductSetRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.UpdateProductSet(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} + +func ExampleProductSearchClient_DeleteProductSet() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.DeleteProductSetRequest{ + // TODO: Fill request struct fields. + } + err = c.DeleteProductSet(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleProductSearchClient_AddProductToProductSet() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.AddProductToProductSetRequest{ + // TODO: Fill request struct fields. + } + err = c.AddProductToProductSet(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleProductSearchClient_RemoveProductFromProductSet() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.RemoveProductFromProductSetRequest{ + // TODO: Fill request struct fields. + } + err = c.RemoveProductFromProductSet(ctx, req) + if err != nil { + // TODO: Handle error. + } +} + +func ExampleProductSearchClient_ListProductsInProductSet() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.ListProductsInProductSetRequest{ + // TODO: Fill request struct fields. + } + it := c.ListProductsInProductSet(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp + } +} + +func ExampleProductSearchClient_ImportProductSets() { + ctx := context.Background() + c, err := vision.NewProductSearchClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.ImportProductSetsRequest{ + // TODO: Fill request struct fields. + } + op, err := c.ImportProductSets(ctx, req) + if err != nil { + // TODO: Handle error. + } + + resp, err := op.Wait(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/vision/apiv1p1beta1/BatchAnnotateImages_smoke_test.go b/vendor/cloud.google.com/go/vision/apiv1p1beta1/BatchAnnotateImages_smoke_test.go new file mode 100644 index 00000000..cea107b6 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1p1beta1/BatchAnnotateImages_smoke_test.go @@ -0,0 +1,82 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package vision + +import ( + visionpb "google.golang.org/genproto/googleapis/cloud/vision/v1p1beta1" +) + +import ( + "context" + "fmt" + "strconv" + "testing" + "time" + + "cloud.google.com/go/internal/testutil" + "google.golang.org/api/iterator" + "google.golang.org/api/option" +) + +var _ = fmt.Sprintf +var _ = iterator.Done +var _ = strconv.FormatUint +var _ = time.Now + +func TestImageAnnotatorSmoke(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + ts := testutil.TokenSource(ctx, DefaultAuthScopes()...) + if ts == nil { + t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") + } + + projectId := testutil.ProjID() + _ = projectId + + c, err := NewImageAnnotatorClient(ctx, option.WithTokenSource(ts)) + if err != nil { + t.Fatal(err) + } + + var gcsImageUri string = "gs://gapic-toolkit/President_Barack_Obama.jpg" + var source = &visionpb.ImageSource{ + GcsImageUri: gcsImageUri, + } + var image = &visionpb.Image{ + Source: source, + } + var type_ visionpb.Feature_Type = visionpb.Feature_FACE_DETECTION + var featuresElement = &visionpb.Feature{ + Type: type_, + } + var features = []*visionpb.Feature{featuresElement} + var requestsElement = &visionpb.AnnotateImageRequest{ + Image: image, + Features: features, + } + var requests = []*visionpb.AnnotateImageRequest{requestsElement} + var request = &visionpb.BatchAnnotateImagesRequest{ + Requests: requests, + } + + if _, err := c.BatchAnnotateImages(ctx, request); err != nil { + t.Error(err) + } +} diff --git a/vendor/cloud.google.com/go/vision/apiv1p1beta1/doc.go b/vendor/cloud.google.com/go/vision/apiv1p1beta1/doc.go new file mode 100644 index 00000000..317f2f61 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1p1beta1/doc.go @@ -0,0 +1,93 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +// Package vision is an auto-generated package for the +// Google Cloud Vision API. +// +// NOTE: This package is in beta. It is not stable, and may be subject to changes. +// +// Integrates Google Vision features, including image labeling, face, logo, +// and +// landmark detection, optical character recognition (OCR), and detection of +// explicit content, into applications. +package vision // import "cloud.google.com/go/vision/apiv1p1beta1" + +import ( + "context" + "runtime" + "strings" + "unicode" + + "google.golang.org/grpc/metadata" +) + +func insertMetadata(ctx context.Context, mds ...metadata.MD) context.Context { + out, _ := metadata.FromOutgoingContext(ctx) + out = out.Copy() + for _, md := range mds { + for k, v := range md { + out[k] = append(out[k], v...) + } + } + return metadata.NewOutgoingContext(ctx, out) +} + +// DefaultAuthScopes reports the default set of authentication scopes to use with this package. +func DefaultAuthScopes() []string { + return []string{ + "https://www.googleapis.com/auth/cloud-platform", + "https://www.googleapis.com/auth/cloud-vision", + } +} + +// versionGo returns the Go runtime version. The returned string +// has no whitespace, suitable for reporting in header. +func versionGo() string { + const develPrefix = "devel +" + + s := runtime.Version() + if strings.HasPrefix(s, develPrefix) { + s = s[len(develPrefix):] + if p := strings.IndexFunc(s, unicode.IsSpace); p >= 0 { + s = s[:p] + } + return s + } + + notSemverRune := func(r rune) bool { + return strings.IndexRune("0123456789.", r) < 0 + } + + if strings.HasPrefix(s, "go1") { + s = s[2:] + var prerelease string + if p := strings.IndexFunc(s, notSemverRune); p >= 0 { + s, prerelease = s[:p], s[p:] + } + if strings.HasSuffix(s, ".") { + s += "0" + } else if strings.Count(s, ".") < 2 { + s += ".0" + } + if prerelease != "" { + s += "-" + prerelease + } + return s + } + return "UNKNOWN" +} + +const versionClient = "20181129" diff --git a/vendor/cloud.google.com/go/vision/apiv1p1beta1/image_annotator_client.go b/vendor/cloud.google.com/go/vision/apiv1p1beta1/image_annotator_client.go new file mode 100644 index 00000000..d0a75375 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1p1beta1/image_annotator_client.go @@ -0,0 +1,135 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package vision + +import ( + "context" + "time" + + gax "github.com/googleapis/gax-go" + "google.golang.org/api/option" + "google.golang.org/api/transport" + visionpb "google.golang.org/genproto/googleapis/cloud/vision/v1p1beta1" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +// ImageAnnotatorCallOptions contains the retry settings for each method of ImageAnnotatorClient. +type ImageAnnotatorCallOptions struct { + BatchAnnotateImages []gax.CallOption +} + +func defaultImageAnnotatorClientOptions() []option.ClientOption { + return []option.ClientOption{ + option.WithEndpoint("vision.googleapis.com:443"), + option.WithScopes(DefaultAuthScopes()...), + } +} + +func defaultImageAnnotatorCallOptions() *ImageAnnotatorCallOptions { + retry := map[[2]string][]gax.CallOption{ + {"default", "idempotent"}: { + gax.WithRetry(func() gax.Retryer { + return gax.OnCodes([]codes.Code{ + codes.DeadlineExceeded, + codes.Unavailable, + }, gax.Backoff{ + Initial: 100 * time.Millisecond, + Max: 60000 * time.Millisecond, + Multiplier: 1.3, + }) + }), + }, + } + return &ImageAnnotatorCallOptions{ + BatchAnnotateImages: retry[[2]string{"default", "idempotent"}], + } +} + +// ImageAnnotatorClient is a client for interacting with Google Cloud Vision API. +// +// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. +type ImageAnnotatorClient struct { + // The connection to the service. + conn *grpc.ClientConn + + // The gRPC API client. + imageAnnotatorClient visionpb.ImageAnnotatorClient + + // The call options for this service. + CallOptions *ImageAnnotatorCallOptions + + // The x-goog-* metadata to be sent with each request. + xGoogMetadata metadata.MD +} + +// NewImageAnnotatorClient creates a new image annotator client. +// +// Service that performs Google Cloud Vision API detection tasks over client +// images, such as face, landmark, logo, label, and text detection. The +// ImageAnnotator service returns detected entities from the images. +func NewImageAnnotatorClient(ctx context.Context, opts ...option.ClientOption) (*ImageAnnotatorClient, error) { + conn, err := transport.DialGRPC(ctx, append(defaultImageAnnotatorClientOptions(), opts...)...) + if err != nil { + return nil, err + } + c := &ImageAnnotatorClient{ + conn: conn, + CallOptions: defaultImageAnnotatorCallOptions(), + + imageAnnotatorClient: visionpb.NewImageAnnotatorClient(conn), + } + c.setGoogleClientInfo() + return c, nil +} + +// Connection returns the client's connection to the API service. +func (c *ImageAnnotatorClient) Connection() *grpc.ClientConn { + return c.conn +} + +// Close closes the connection to the API service. The user should invoke this when +// the client is no longer required. +func (c *ImageAnnotatorClient) Close() error { + return c.conn.Close() +} + +// setGoogleClientInfo sets the name and version of the application in +// the `x-goog-api-client` header passed on each request. Intended for +// use by Google-written clients. +func (c *ImageAnnotatorClient) setGoogleClientInfo(keyval ...string) { + kv := append([]string{"gl-go", versionGo()}, keyval...) + kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) + c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) +} + +// BatchAnnotateImages run image detection and annotation for a batch of images. +func (c *ImageAnnotatorClient) BatchAnnotateImages(ctx context.Context, req *visionpb.BatchAnnotateImagesRequest, opts ...gax.CallOption) (*visionpb.BatchAnnotateImagesResponse, error) { + ctx = insertMetadata(ctx, c.xGoogMetadata) + opts = append(c.CallOptions.BatchAnnotateImages[0:len(c.CallOptions.BatchAnnotateImages):len(c.CallOptions.BatchAnnotateImages)], opts...) + var resp *visionpb.BatchAnnotateImagesResponse + err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { + var err error + resp, err = c.imageAnnotatorClient.BatchAnnotateImages(ctx, req, settings.GRPC...) + return err + }, opts...) + if err != nil { + return nil, err + } + return resp, nil +} diff --git a/vendor/cloud.google.com/go/vision/apiv1p1beta1/image_annotator_client_example_test.go b/vendor/cloud.google.com/go/vision/apiv1p1beta1/image_annotator_client_example_test.go new file mode 100644 index 00000000..cc99d230 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1p1beta1/image_annotator_client_example_test.go @@ -0,0 +1,52 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package vision_test + +import ( + "context" + + vision "cloud.google.com/go/vision/apiv1p1beta1" + visionpb "google.golang.org/genproto/googleapis/cloud/vision/v1p1beta1" +) + +func ExampleNewImageAnnotatorClient() { + ctx := context.Background() + c, err := vision.NewImageAnnotatorClient(ctx) + if err != nil { + // TODO: Handle error. + } + // TODO: Use client. + _ = c +} + +func ExampleImageAnnotatorClient_BatchAnnotateImages() { + ctx := context.Background() + c, err := vision.NewImageAnnotatorClient(ctx) + if err != nil { + // TODO: Handle error. + } + + req := &visionpb.BatchAnnotateImagesRequest{ + // TODO: Fill request struct fields. + } + resp, err := c.BatchAnnotateImages(ctx, req) + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp +} diff --git a/vendor/cloud.google.com/go/vision/apiv1p1beta1/mock_test.go b/vendor/cloud.google.com/go/vision/apiv1p1beta1/mock_test.go new file mode 100644 index 00000000..999a4537 --- /dev/null +++ b/vendor/cloud.google.com/go/vision/apiv1p1beta1/mock_test.go @@ -0,0 +1,159 @@ +// Copyright 2018 Google LLC +// +// 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 +// +// https://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. + +// AUTO-GENERATED CODE. DO NOT EDIT. + +package vision + +import ( + visionpb "google.golang.org/genproto/googleapis/cloud/vision/v1p1beta1" +) + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "net" + "os" + "strings" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes" + "google.golang.org/api/option" + status "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + gstatus "google.golang.org/grpc/status" +) + +var _ = io.EOF +var _ = ptypes.MarshalAny +var _ status.Status + +type mockImageAnnotatorServer struct { + // Embed for forward compatibility. + // Tests will keep working if more methods are added + // in the future. + visionpb.ImageAnnotatorServer + + reqs []proto.Message + + // If set, all calls return this error. + err error + + // responses to return if err == nil + resps []proto.Message +} + +func (s *mockImageAnnotatorServer) BatchAnnotateImages(ctx context.Context, req *visionpb.BatchAnnotateImagesRequest) (*visionpb.BatchAnnotateImagesResponse, error) { + md, _ := metadata.FromIncomingContext(ctx) + if xg := md["x-goog-api-client"]; len(xg) == 0 || !strings.Contains(xg[0], "gl-go/") { + return nil, fmt.Errorf("x-goog-api-client = %v, expected gl-go key", xg) + } + s.reqs = append(s.reqs, req) + if s.err != nil { + return nil, s.err + } + return s.resps[0].(*visionpb.BatchAnnotateImagesResponse), nil +} + +// clientOpt is the option tests should use to connect to the test server. +// It is initialized by TestMain. +var clientOpt option.ClientOption + +var ( + mockImageAnnotator mockImageAnnotatorServer +) + +func TestMain(m *testing.M) { + flag.Parse() + + serv := grpc.NewServer() + visionpb.RegisterImageAnnotatorServer(serv, &mockImageAnnotator) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + log.Fatal(err) + } + go serv.Serve(lis) + + conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure()) + if err != nil { + log.Fatal(err) + } + clientOpt = option.WithGRPCConn(conn) + + os.Exit(m.Run()) +} + +func TestImageAnnotatorBatchAnnotateImages(t *testing.T) { + var expectedResponse *visionpb.BatchAnnotateImagesResponse = &visionpb.BatchAnnotateImagesResponse{} + + mockImageAnnotator.err = nil + mockImageAnnotator.reqs = nil + + mockImageAnnotator.resps = append(mockImageAnnotator.resps[:0], expectedResponse) + + var requests []*visionpb.AnnotateImageRequest = nil + var request = &visionpb.BatchAnnotateImagesRequest{ + Requests: requests, + } + + c, err := NewImageAnnotatorClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BatchAnnotateImages(context.Background(), request) + + if err != nil { + t.Fatal(err) + } + + if want, got := request, mockImageAnnotator.reqs[0]; !proto.Equal(want, got) { + t.Errorf("wrong request %q, want %q", got, want) + } + + if want, got := expectedResponse, resp; !proto.Equal(want, got) { + t.Errorf("wrong response %q, want %q)", got, want) + } +} + +func TestImageAnnotatorBatchAnnotateImagesError(t *testing.T) { + errCode := codes.PermissionDenied + mockImageAnnotator.err = gstatus.Error(errCode, "test error") + + var requests []*visionpb.AnnotateImageRequest = nil + var request = &visionpb.BatchAnnotateImagesRequest{ + Requests: requests, + } + + c, err := NewImageAnnotatorClient(context.Background(), clientOpt) + if err != nil { + t.Fatal(err) + } + + resp, err := c.BatchAnnotateImages(context.Background(), request) + + if st, ok := gstatus.FromError(err); !ok { + t.Errorf("got error %v, expected grpc error", err) + } else if c := st.Code(); c != errCode { + t.Errorf("got error code %q, want %q", c, errCode) + } + _ = resp +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/LICENSE.txt b/vendor/github.com/denisenkom/go-mssqldb/LICENSE.txt new file mode 100644 index 00000000..74487567 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/LICENSE.txt @@ -0,0 +1,27 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/denisenkom/go-mssqldb/README.md b/vendor/github.com/denisenkom/go-mssqldb/README.md new file mode 100644 index 00000000..ea06b900 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/README.md @@ -0,0 +1,215 @@ +# A pure Go MSSQL driver for Go's database/sql package + +[![GoDoc](https://godoc.org/github.com/denisenkom/go-mssqldb?status.svg)](http://godoc.org/github.com/denisenkom/go-mssqldb) +[![Build status](https://ci.appveyor.com/api/projects/status/jrln8cs62wj9i0a2?svg=true)](https://ci.appveyor.com/project/denisenkom/go-mssqldb) +[![codecov](https://codecov.io/gh/denisenkom/go-mssqldb/branch/master/graph/badge.svg)](https://codecov.io/gh/denisenkom/go-mssqldb) + +## Install + +Requires Go 1.8 or above. + +Install with `go get github.com/denisenkom/go-mssqldb` . + +## Connection Parameters and DSN + +The recommended connection string uses a URL format: +`sqlserver://username:password@host/instance?param1=value¶m2=value` +Other supported formats are listed below. + +### Common parameters: + +* `user id` - enter the SQL Server Authentication user id or the Windows Authentication user id in the DOMAIN\User format. On Windows, if user id is empty or missing Single-Sign-On is used. +* `password` +* `database` +* `connection timeout` - in seconds (default is 0 for no timeout), set to 0 for no timeout. Recommended to set to 0 and use context to manage query and connection timeouts. +* `dial timeout` - in seconds (default is 15), set to 0 for no timeout +* `encrypt` + * `disable` - Data send between client and server is not encrypted. + * `false` - Data sent between client and server is not encrypted beyond the login packet. (Default) + * `true` - Data sent between client and server is encrypted. +* `app name` - The application name (default is go-mssqldb) + +### Connection parameters for ODBC and ADO style connection strings: + +* `server` - host or host\instance (default localhost) +* `port` - used only when there is no instance in server (default 1433) + +### Less common parameters: + +* `keepAlive` - in seconds; 0 to disable (default is 30) +* `failoverpartner` - host or host\instance (default is no partner). +* `failoverport` - used only when there is no instance in failoverpartner (default 1433) +* `packet size` - in bytes; 512 to 32767 (default is 4096) + * Encrypted connections have a maximum packet size of 16383 bytes + * Further information on usage: https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-network-packet-size-server-configuration-option +* `log` - logging flags (default 0/no logging, 63 for full logging) + * 1 log errors + * 2 log messages + * 4 log rows affected + * 8 trace sql statements + * 16 log statement parameters + * 32 log transaction begin/end +* `TrustServerCertificate` + * false - Server certificate is checked. Default is false if encypt is specified. + * true - Server certificate is not checked. Default is true if encrypt is not specified. If trust server certificate is true, driver accepts any certificate presented by the server and any host name in that certificate. In this mode, TLS is susceptible to man-in-the-middle attacks. This should be used only for testing. +* `certificate` - The file that contains the public key certificate of the CA that signed the SQL Server certificate. The specified certificate overrides the go platform specific CA certificates. +* `hostNameInCertificate` - Specifies the Common Name (CN) in the server certificate. Default value is the server host. +* `ServerSPN` - The kerberos SPN (Service Principal Name) for the server. Default is MSSQLSvc/host:port. +* `Workstation ID` - The workstation name (default is the host name) +* `ApplicationIntent` - Can be given the value `ReadOnly` to initiate a read-only connection to an Availability Group listener. + +### The connection string can be specified in one of three formats: + + +1. URL: with `sqlserver` scheme. username and password appears before the host. Any instance appears as + the first segment in the path. All other options are query parameters. Examples: + + * `sqlserver://username:password@host/instance?param1=value¶m2=value` + * `sqlserver://username:password@host:port?param1=value¶m2=value` + * `sqlserver://sa@localhost/SQLExpress?database=master&connection+timeout=30` // `SQLExpress instance. + * `sqlserver://sa:mypass@localhost?database=master&connection+timeout=30` // username=sa, password=mypass. + * `sqlserver://sa:mypass@localhost:1234?database=master&connection+timeout=30` // port 1234 on localhost. + * `sqlserver://sa:my%7Bpass@somehost?connection+timeout=30` // password is "my{pass" + + A string of this format can be constructed using the `URL` type in the `net/url` package. + +```go + query := url.Values{} + query.Add("app name", "MyAppName") + + u := &url.URL{ + Scheme: "sqlserver", + User: url.UserPassword(username, password), + Host: fmt.Sprintf("%s:%d", hostname, port), + // Path: instance, // if connecting to an instance instead of a port + RawQuery: query.Encode(), + } + db, err := sql.Open("sqlserver", u.String()) +``` + +2. ADO: `key=value` pairs separated by `;`. Values may not contain `;`, leading and trailing whitespace is ignored. + Examples: + + * `server=localhost\\SQLExpress;user id=sa;database=master;app name=MyAppName` + * `server=localhost;user id=sa;database=master;app name=MyAppName` + +3. ODBC: Prefix with `odbc`, `key=value` pairs separated by `;`. Allow `;` by wrapping + values in `{}`. Examples: + + * `odbc:server=localhost\\SQLExpress;user id=sa;database=master;app name=MyAppName` + * `odbc:server=localhost;user id=sa;database=master;app name=MyAppName` + * `odbc:server=localhost;user id=sa;password={foo;bar}` // Value marked with `{}`, password is "foo;bar" + * `odbc:server=localhost;user id=sa;password={foo{bar}` // Value marked with `{}`, password is "foo{bar" + * `odbc:server=localhost;user id=sa;password={foobar }` // Value marked with `{}`, password is "foobar " + * `odbc:server=localhost;user id=sa;password=foo{bar` // Literal `{`, password is "foo{bar" + * `odbc:server=localhost;user id=sa;password=foo}bar` // Literal `}`, password is "foo}bar" + * `odbc:server=localhost;user id=sa;password={foo{bar}` // Literal `{`, password is "foo{bar" + * `odbc:server=localhost;user id=sa;password={foo}}bar}` // Escaped `} with `}}`, password is "foo}bar" + +## Executing Stored Procedures + +To run a stored procedure, set the query text to the procedure name: +```go +var account = "abc" +_, err := db.ExecContext(ctx, "sp_RunMe", + sql.Named("ID", 123), + sql.Named("Account", sql.Out{Dest: &account}), +) +``` + +## Return Status + +To get the procedure return status, pass into the parameters a +`*mssql.ReturnStatus`. For example: +``` +var rs mssql.ReturnStatus +_, err := db.ExecContext(ctx, "theproc", &rs) +log.Printf("status=%d", rs) +``` + +## Parameters + +The `sqlserver` driver uses normal MS SQL Server syntax and expects parameters in +the sql query to be in the form of either `@Name` or `@p1` to `@pN` (ordinal position). + +```go +db.QueryContext(ctx, `select * from t where ID = @ID and Name = @p2;`, sql.Named("ID", 6), "Bob") +``` + +### Parameter Types + +To pass specific types to the query parameters, say `varchar` or `date` types, +you must convert the types to the type before passing in. The following types +are supported: + + * string -> nvarchar + * mssql.VarChar -> varchar + * time.Time -> datetimeoffset or datetime (TDS version dependent) + * mssql.DateTime1 -> datetime + * mssql.DateTimeOffset -> datetimeoffset + * "cloud.google.com/go/civil".Date -> date + * "cloud.google.com/go/civil".DateTime -> datetime2 + * "cloud.google.com/go/civil".Time -> time + +## Important Notes + + * [LastInsertId](https://golang.org/pkg/database/sql/#Result.LastInsertId) should + not be used with this driver (or SQL Server) due to how the TDS protocol + works. Please use the [OUTPUT Clause](https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql) + or add a `select ID = convert(bigint, SCOPE_IDENTITY());` to the end of your + query (ref [SCOPE_IDENTITY](https://docs.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql)). + This will ensure you are getting the correct ID and will prevent a network round trip. + * [NewConnector](https://godoc.org/github.com/denisenkom/go-mssqldb#NewConnector) + may be used with [OpenDB](https://golang.org/pkg/database/sql/#OpenDB). + * [Connector.SessionInitSQL](https://godoc.org/github.com/denisenkom/go-mssqldb#Connector.SessionInitSQL) + may be set to set any driver specific session settings after the session + has been reset. If empty the session will still be reset but use the database + defaults in Go1.10+. + +## Features + +* Can be used with SQL Server 2005 or newer +* Can be used with Microsoft Azure SQL Database +* Can be used on all go supported platforms (e.g. Linux, Mac OS X and Windows) +* Supports new date/time types: date, time, datetime2, datetimeoffset +* Supports string parameters longer than 8000 characters +* Supports encryption using SSL/TLS +* Supports SQL Server and Windows Authentication +* Supports Single-Sign-On on Windows +* Supports connections to AlwaysOn Availability Group listeners, including re-direction to read-only replicas. +* Supports query notifications + +## Tests + +`go test` is used for testing. A running instance of MSSQL server is required. +Environment variables are used to pass login information. + +Example: + + env SQLSERVER_DSN=sqlserver://user:pass@hostname/instance?database=test1 go test + +## Deprecated + +These features still exist in the driver, but they are are deprecated. + +### Query Parameter Token Replace (driver "mssql") + +If you use the driver name "mssql" (rather then "sqlserver") the SQL text +will be loosly parsed and an attempt to extract identifiers using one of + +* ? +* ?nnn +* :nnn +* $nnn + +will be used. This is not recommended with SQL Server. +There is at least one existing `won't fix` issue with the query parsing. + +Use the native "@Name" parameters instead with the "sqlserver" driver name. + +## Known Issues + +* SQL Server 2008 and 2008 R2 engine cannot handle login records when SSL encryption is not disabled. +To fix SQL Server 2008 R2 issue, install SQL Server 2008 R2 Service Pack 2. +To fix SQL Server 2008 issue, install Microsoft SQL Server 2008 Service Pack 3 and Cumulative update package 3 for SQL Server 2008 SP3. +More information: http://support.microsoft.com/kb/2653857 diff --git a/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml b/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml new file mode 100644 index 00000000..2ae5456d --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml @@ -0,0 +1,48 @@ +version: 1.0.{build} + +os: Windows Server 2012 R2 + +clone_folder: c:\gopath\src\github.com\denisenkom\go-mssqldb + +environment: + GOPATH: c:\gopath + HOST: localhost + SQLUSER: sa + SQLPASSWORD: Password12! + DATABASE: test + GOVERSION: 110 + matrix: + - GOVERSION: 18 + SQLINSTANCE: SQL2016 + - GOVERSION: 19 + SQLINSTANCE: SQL2016 + - GOVERSION: 110 + SQLINSTANCE: SQL2016 + - SQLINSTANCE: SQL2014 + - SQLINSTANCE: SQL2012SP1 + - SQLINSTANCE: SQL2008R2SP2 + +install: + - set GOROOT=c:\go%GOVERSION% + - set PATH=%GOPATH%\bin;%GOROOT%\bin;%PATH% + - go version + - go env + - go get -u cloud.google.com/go/civil + +build_script: + - go build + +before_test: + # setup SQL Server + - ps: | + $instanceName = $env:SQLINSTANCE + Start-Service "MSSQL`$$instanceName" + Start-Service "SQLBrowser" + - sqlcmd -S "(local)\%SQLINSTANCE%" -Q "Use [master]; CREATE DATABASE test;" + - sqlcmd -S "(local)\%SQLINSTANCE%" -h -1 -Q "set nocount on; Select @@version" + - pip install codecov + + +test_script: + - go test -race -cpu 4 -coverprofile=coverage.txt -covermode=atomic + - codecov -f coverage.txt diff --git a/vendor/github.com/denisenkom/go-mssqldb/batch/batch.go b/vendor/github.com/denisenkom/go-mssqldb/batch/batch.go new file mode 100644 index 00000000..5b793dcb --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/batch/batch.go @@ -0,0 +1,287 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// bach splits a single script containing multiple batches separated by +// a keyword into multiple scripts. +package batch + +import ( + "bytes" + "fmt" + "strconv" + "strings" + "unicode" +) + +// Split the provided SQL into multiple sql scripts based on a given +// separator, often "GO". It also allows escaping newlines with a +// backslash. +func Split(sql, separator string) []string { + if len(separator) == 0 || len(sql) < len(separator) { + return []string{sql} + } + l := &lexer{ + Sql: sql, + Sep: separator, + At: 0, + } + state := stateWhitespace + for state != nil { + state = state(l) + } + l.AddCurrent(1) + return l.Batch +} + +const debugPrintStateName = false + +func printStateName(name string, l *lexer) { + if debugPrintStateName { + fmt.Printf("state %s At=%d\n", name, l.At) + } +} + +func hasPrefixFold(s, sep string) bool { + if len(s) < len(sep) { + return false + } + return strings.EqualFold(s[:len(sep)], sep) +} + +type lexer struct { + Sql string + Sep string + At int + Start int + + Skip []int + + Batch []string +} + +func (l *lexer) Add(b string) { + if len(b) == 0 { + return + } + l.Batch = append(l.Batch, b) +} + +func (l *lexer) Next() bool { + l.At++ + return l.At < len(l.Sql) +} + +func (l *lexer) AddCurrent(count int64) bool { + if count < 0 { + count = 0 + } + if l.At >= len(l.Sql) { + l.At = len(l.Sql) + } + text := l.Sql[l.Start:l.At] + if len(l.Skip) > 0 { + buf := &bytes.Buffer{} + nextSkipIndex := 0 + nextSkip := l.Skip[nextSkipIndex] + for i, r := range text { + if i == nextSkip { + nextSkipIndex++ + if nextSkipIndex < len(l.Skip) { + nextSkip = l.Skip[nextSkipIndex] + } + continue + } + buf.WriteRune(r) + } + text = buf.String() + l.Skip = nil + } + // Limit the number of counts for sanity. + if count > 1000 { + count = 1000 + } + for i := int64(0); i < count; i++ { + l.Add(text) + } + l.At += len(l.Sep) + l.Start = l.At + return (l.At < len(l.Sql)) +} + +type stateFn func(*lexer) stateFn + +const ( + lineComment = "--" + leftComment = "/*" + rightComment = "*/" +) + +func stateSep(l *lexer) stateFn { + printStateName("sep", l) + if l.At+len(l.Sep) >= len(l.Sql) { + return nil + } + s := l.Sql[l.At+len(l.Sep):] + + parseNumberStart := -1 +loop: + for i, r := range s { + switch { + case r == '\n', r == '\r': + l.AddCurrent(1) + return stateWhitespace + case unicode.IsSpace(r): + case unicode.IsNumber(r): + parseNumberStart = i + break loop + } + } + if parseNumberStart < 0 { + return nil + } + + parseNumberCount := 0 +numLoop: + for i, r := range s[parseNumberStart:] { + switch { + case unicode.IsNumber(r): + parseNumberCount = i + default: + break numLoop + } + } + parseNumberEnd := parseNumberStart + parseNumberCount + 1 + + count, err := strconv.ParseInt(s[parseNumberStart:parseNumberEnd], 10, 64) + if err != nil { + return stateText + } + for _, r := range s[parseNumberEnd:] { + switch { + case r == '\n', r == '\r': + l.AddCurrent(count) + l.At += parseNumberEnd + l.Start = l.At + return stateWhitespace + case unicode.IsSpace(r): + default: + return stateText + } + } + + return nil +} + +func stateText(l *lexer) stateFn { + printStateName("text", l) + for { + ch := l.Sql[l.At] + + switch { + case strings.HasPrefix(l.Sql[l.At:], lineComment): + l.At += len(lineComment) + return stateLineComment + case strings.HasPrefix(l.Sql[l.At:], leftComment): + l.At += len(leftComment) + return stateMultiComment + case ch == '\'': + l.At += 1 + return stateString + case ch == '\r', ch == '\n': + l.At += 1 + return stateWhitespace + default: + if l.Next() == false { + return nil + } + } + } +} + +func stateWhitespace(l *lexer) stateFn { + printStateName("whitespace", l) + if l.At >= len(l.Sql) { + return nil + } + ch := l.Sql[l.At] + + switch { + case unicode.IsSpace(rune(ch)): + l.At += 1 + return stateWhitespace + case hasPrefixFold(l.Sql[l.At:], l.Sep): + return stateSep + default: + return stateText + } +} + +func stateLineComment(l *lexer) stateFn { + printStateName("line-comment", l) + for { + if l.At >= len(l.Sql) { + return nil + } + ch := l.Sql[l.At] + + switch { + case ch == '\r', ch == '\n': + l.At += 1 + return stateWhitespace + default: + if l.Next() == false { + return nil + } + } + } +} + +func stateMultiComment(l *lexer) stateFn { + printStateName("multi-line-comment", l) + for { + switch { + case strings.HasPrefix(l.Sql[l.At:], rightComment): + l.At += len(leftComment) + return stateWhitespace + default: + if l.Next() == false { + return nil + } + } + } +} + +func stateString(l *lexer) stateFn { + printStateName("string", l) + for { + if l.At >= len(l.Sql) { + return nil + } + ch := l.Sql[l.At] + chNext := rune(-1) + if l.At+1 < len(l.Sql) { + chNext = rune(l.Sql[l.At+1]) + } + + switch { + case ch == '\\' && (chNext == '\r' || chNext == '\n'): + next := 2 + l.Skip = append(l.Skip, l.At, l.At+1) + if chNext == '\r' && l.At+2 < len(l.Sql) && l.Sql[l.At+2] == '\n' { + l.Skip = append(l.Skip, l.At+2) + next = 3 + } + l.At += next + case ch == '\'' && chNext == '\'': + l.At += 2 + case ch == '\'' && chNext != '\'': + l.At += 1 + return stateWhitespace + default: + if l.Next() == false { + return nil + } + } + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/batch/batch_fuzz.go b/vendor/github.com/denisenkom/go-mssqldb/batch/batch_fuzz.go new file mode 100644 index 00000000..150818db --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/batch/batch_fuzz.go @@ -0,0 +1,12 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build gofuzz + +package batch + +func Fuzz(data []byte) int { + Split(string(data), "GO") + return 0 +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/batch/batch_test.go b/vendor/github.com/denisenkom/go-mssqldb/batch/batch_test.go new file mode 100644 index 00000000..51978283 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/batch/batch_test.go @@ -0,0 +1,120 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package batch + +import ( + "fmt" + "testing" +) + +func TestBatchSplit(t *testing.T) { + type testItem struct { + Sql string + Expect []string + } + + list := []testItem{ + testItem{ + Sql: `use DB +go +select 1 +go +select 2 +`, + Expect: []string{`use DB +`, ` +select 1 +`, ` +select 2 +`, + }, + }, + testItem{ + Sql: `go +use DB go +`, + Expect: []string{` +use DB go +`, + }, + }, + testItem{ + Sql: `select 'It''s go time' +go +select top 1 1`, + Expect: []string{`select 'It''s go time' +`, ` +select top 1 1`, + }, + }, + testItem{ + Sql: `select 1 /* go */ +go +select top 1 1`, + Expect: []string{`select 1 /* go */ +`, ` +select top 1 1`, + }, + }, + testItem{ + Sql: `select 1 -- go +go +select top 1 1`, + Expect: []string{`select 1 -- go +`, ` +select top 1 1`, + }, + }, + testItem{Sql: `"0'"`, Expect: []string{`"0'"`}}, + testItem{Sql: "0'", Expect: []string{"0'"}}, + testItem{Sql: "--", Expect: []string{"--"}}, + testItem{Sql: "GO", Expect: nil}, + testItem{Sql: "/*", Expect: []string{"/*"}}, + testItem{Sql: "gO\x01\x00O550655490663051008\n", Expect: []string{"\n"}}, + testItem{Sql: "select 1;\nGO 2\nselect 2;", Expect: []string{"select 1;\n", "select 1;\n", "\nselect 2;"}}, + testItem{Sql: "select 'hi\\\n-hello';", Expect: []string{"select 'hi-hello';"}}, + testItem{Sql: "select 'hi\\\r\n-hello';", Expect: []string{"select 'hi-hello';"}}, + testItem{Sql: "select 'hi\\\r-hello';", Expect: []string{"select 'hi-hello';"}}, + testItem{Sql: "select 'hi\\\n\nhello';", Expect: []string{"select 'hi\nhello';"}}, + } + + index := -1 + + for i := range list { + if index >= 0 && index != i { + continue + } + sqltext := list[i].Sql + t.Run(fmt.Sprintf("index-%d", i), func(t *testing.T) { + ss := Split(sqltext, "go") + if len(ss) != len(list[i].Expect) { + t.Errorf("Test Item index %d; expect %d items, got %d %q", i, len(list[i].Expect), len(ss), ss) + return + } + for j := 0; j < len(ss); j++ { + if ss[j] != list[i].Expect[j] { + t.Errorf("Test Item index %d, batch index %d; expect <%s>, got <%s>", i, j, list[i].Expect[j], ss[j]) + } + } + }) + } +} + +func TestHasPrefixFold(t *testing.T) { + list := []struct { + s, pre string + is bool + }{ + {"h", "H", true}, + {"h", "K", false}, + {"go 5\n", "go", true}, + } + for _, item := range list { + is := hasPrefixFold(item.s, item.pre) + if is != item.is { + t.Errorf("want (%q, %q)=%t got %t", item.s, item.pre, item.is, is) + } + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/buf.go b/vendor/github.com/denisenkom/go-mssqldb/buf.go new file mode 100644 index 00000000..927d75d1 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/buf.go @@ -0,0 +1,258 @@ +package mssql + +import ( + "encoding/binary" + "errors" + "io" +) + +type packetType uint8 + +type header struct { + PacketType packetType + Status uint8 + Size uint16 + Spid uint16 + PacketNo uint8 + Pad uint8 +} + +// tdsBuffer reads and writes TDS packets of data to the transport. +// The write and read buffers are separate to make sending attn signals +// possible without locks. Currently attn signals are only sent during +// reads, not writes. +type tdsBuffer struct { + transport io.ReadWriteCloser + + packetSize int + + // Write fields. + wbuf []byte + wpos int + wPacketSeq byte + wPacketType packetType + + // Read fields. + rbuf []byte + rpos int + rsize int + final bool + rPacketType packetType + + // afterFirst is assigned to right after tdsBuffer is created and + // before the first use. It is executed after the first packet is + // written and then removed. + afterFirst func() +} + +func newTdsBuffer(bufsize uint16, transport io.ReadWriteCloser) *tdsBuffer { + return &tdsBuffer{ + packetSize: int(bufsize), + wbuf: make([]byte, 1<<16), + rbuf: make([]byte, 1<<16), + rpos: 8, + transport: transport, + } +} + +func (rw *tdsBuffer) ResizeBuffer(packetSize int) { + rw.packetSize = packetSize +} + +func (w *tdsBuffer) PackageSize() int { + return w.packetSize +} + +func (w *tdsBuffer) flush() (err error) { + // Write packet size. + w.wbuf[0] = byte(w.wPacketType) + binary.BigEndian.PutUint16(w.wbuf[2:], uint16(w.wpos)) + w.wbuf[6] = w.wPacketSeq + + // Write packet into underlying transport. + if _, err = w.transport.Write(w.wbuf[:w.wpos]); err != nil { + return err + } + // It is possible to create a whole new buffer after a flush. + // Useful for debugging. Normally reuse the buffer. + // w.wbuf = make([]byte, 1<<16) + + // Execute afterFirst hook if it is set. + if w.afterFirst != nil { + w.afterFirst() + w.afterFirst = nil + } + + w.wpos = 8 + w.wPacketSeq++ + return nil +} + +func (w *tdsBuffer) Write(p []byte) (total int, err error) { + for { + copied := copy(w.wbuf[w.wpos:w.packetSize], p) + w.wpos += copied + total += copied + if copied == len(p) { + return + } + if err = w.flush(); err != nil { + return + } + p = p[copied:] + } +} + +func (w *tdsBuffer) WriteByte(b byte) error { + if int(w.wpos) == len(w.wbuf) || w.wpos == w.packetSize { + if err := w.flush(); err != nil { + return err + } + } + w.wbuf[w.wpos] = b + w.wpos += 1 + return nil +} + +func (w *tdsBuffer) BeginPacket(packetType packetType, resetSession bool) { + status := byte(0) + if resetSession { + switch packetType { + // Reset session can only be set on the following packet types. + case packSQLBatch, packRPCRequest, packTransMgrReq: + status = 0x8 + } + } + w.wbuf[1] = status // Packet is incomplete. This byte is set again in FinishPacket. + w.wpos = 8 + w.wPacketSeq = 1 + w.wPacketType = packetType +} + +func (w *tdsBuffer) FinishPacket() error { + w.wbuf[1] |= 1 // Mark this as the last packet in the message. + return w.flush() +} + +var headerSize = binary.Size(header{}) + +func (r *tdsBuffer) readNextPacket() error { + h := header{} + var err error + err = binary.Read(r.transport, binary.BigEndian, &h) + if err != nil { + return err + } + if int(h.Size) > r.packetSize { + return errors.New("Invalid packet size, it is longer than buffer size") + } + if headerSize > int(h.Size) { + return errors.New("Invalid packet size, it is shorter than header size") + } + _, err = io.ReadFull(r.transport, r.rbuf[headerSize:h.Size]) + if err != nil { + return err + } + r.rpos = headerSize + r.rsize = int(h.Size) + r.final = h.Status != 0 + r.rPacketType = h.PacketType + return nil +} + +func (r *tdsBuffer) BeginRead() (packetType, error) { + err := r.readNextPacket() + if err != nil { + return 0, err + } + return r.rPacketType, nil +} + +func (r *tdsBuffer) ReadByte() (res byte, err error) { + if r.rpos == r.rsize { + if r.final { + return 0, io.EOF + } + err = r.readNextPacket() + if err != nil { + return 0, err + } + } + res = r.rbuf[r.rpos] + r.rpos++ + return res, nil +} + +func (r *tdsBuffer) byte() byte { + b, err := r.ReadByte() + if err != nil { + badStreamPanic(err) + } + return b +} + +func (r *tdsBuffer) ReadFull(buf []byte) { + _, err := io.ReadFull(r, buf[:]) + if err != nil { + badStreamPanic(err) + } +} + +func (r *tdsBuffer) uint64() uint64 { + var buf [8]byte + r.ReadFull(buf[:]) + return binary.LittleEndian.Uint64(buf[:]) +} + +func (r *tdsBuffer) int32() int32 { + return int32(r.uint32()) +} + +func (r *tdsBuffer) uint32() uint32 { + var buf [4]byte + r.ReadFull(buf[:]) + return binary.LittleEndian.Uint32(buf[:]) +} + +func (r *tdsBuffer) uint16() uint16 { + var buf [2]byte + r.ReadFull(buf[:]) + return binary.LittleEndian.Uint16(buf[:]) +} + +func (r *tdsBuffer) BVarChar() string { + l := int(r.byte()) + return r.readUcs2(l) +} + +func (r *tdsBuffer) UsVarChar() string { + l := int(r.uint16()) + return r.readUcs2(l) +} + +func (r *tdsBuffer) readUcs2(numchars int) string { + b := make([]byte, numchars*2) + r.ReadFull(b) + res, err := ucs22str(b) + if err != nil { + badStreamPanic(err) + } + return res +} + +func (r *tdsBuffer) Read(buf []byte) (copied int, err error) { + copied = 0 + err = nil + if r.rpos == r.rsize { + if r.final { + return 0, io.EOF + } + err = r.readNextPacket() + if err != nil { + return + } + } + copied = copy(buf, r.rbuf[r.rpos:r.rsize]) + r.rpos += copied + return +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/buf_test.go b/vendor/github.com/denisenkom/go-mssqldb/buf_test.go new file mode 100644 index 00000000..9d681665 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/buf_test.go @@ -0,0 +1,284 @@ +package mssql + +import ( + "bytes" + "errors" + "testing" +) + +type closableBuffer struct { + *bytes.Buffer +} + +func (closableBuffer) Close() error { + return nil +} + +type failBuffer struct { +} + +func (failBuffer) Read([]byte) (int, error) { + return 0, errors.New("read failed") +} + +func (failBuffer) Write([]byte) (int, error) { + return 0, errors.New("write failed") +} + +func (failBuffer) Close() error { + return nil +} + +func makeBuf(bufSize uint16, testData []byte) *tdsBuffer { + buffer := closableBuffer{bytes.NewBuffer(testData)} + return newTdsBuffer(bufSize, &buffer) +} + +func TestStreamShorterThanHeader(t *testing.T) { + //buffer := closableBuffer{*bytes.NewBuffer([]byte{0xFF, 0xFF})} + //buffer := closableBuffer{*bytes.NewBuffer([]byte{0x6F, 0x96, 0x19, 0xFF, 0x8B, 0x86, 0xD0, 0x11, 0xB4, 0x2D, 0x00, 0xC0, 0x4F, 0xC9, 0x64, 0xFF})} + //tdsBuffer := newTdsBuffer(100, &buffer) + buffer := makeBuf(100, []byte{0xFF, 0xFF}) + _, err := buffer.BeginRead() + if err == nil { + t.Fatal("BeginRead was expected to return error but it didn't") + } else { + t.Log("BeginRead failed as expected with error:", err.Error()) + } +} + +func TestInvalidLengthInHeaderTooLong(t *testing.T) { + buffer := makeBuf(8, []byte{0xFF, 0xFF, 0x0, 0x9, 0xff, 0xff, 0xff, 0xff}) + _, err := buffer.BeginRead() + if err == nil { + t.Fatal("BeginRead was expected to return error but it didn't") + } else { + if err.Error() != "Invalid packet size, it is longer than buffer size" { + t.Fatal("BeginRead failed with incorrect error", err) + } else { + t.Log("BeginRead failed as expected with error:", err.Error()) + } + } +} + +func TestInvalidLengthInHeaderTooShort(t *testing.T) { + buffer := makeBuf(100, []byte{0xFF, 0xFF, 0x0, 0x1, 0xff, 0xff, 0xff, 0xff}) + _, err := buffer.BeginRead() + if err == nil { + t.Fatal("BeginRead was expected to return error but it didn't") + } else { + t.Log("BeginRead failed as expected with error:", err.Error()) + } +} + +func TestInvalidLengthInHeaderLongerThanIncomingBuffer(t *testing.T) { + buffer := makeBuf(9, []byte{0xFF, 0xFF, 0x0, 0x9, 0xff, 0xff, 0xff, 0xff}) + _, err := buffer.BeginRead() + if err == nil { + t.Fatal("BeginRead was expected to return error but it didn't") + } else { + t.Log("BeginRead failed as expected with error:", err.Error()) + } +} + +func TestBeginReadSucceeds(t *testing.T) { + buffer := makeBuf(9, []byte{0x01 /*id*/, 0xFF /*status*/, 0x0, 0x9 /*size*/, 0xff, 0xff, 0xff, 0xff, 0x02 /*test byte*/}) + + id, err := buffer.BeginRead() + if err != nil { + t.Fatal("BeginRead failed:", err.Error()) + } + if id != 1 { + t.Fatalf("Expected id to be 1 but it is %d", id) + } + + b, err := buffer.ReadByte() + if err != nil { + t.Fatal("ReadByte failed:", err.Error()) + } + if b != 2 { + t.Fatalf("Expected read byte to be 2 but it is %d", b) + } + + // should fail because no more bytes left + _, err = buffer.ReadByte() + if err == nil { + t.Fatal("ReadByte was expected to return error but it didn't") + } else { + t.Log("ReadByte failed as expected with error:", err.Error()) + } + + testBuf := []byte{0, 1, 2} + // should fail because no more bytes left + _, err = buffer.Read(testBuf) + if err == nil { + t.Fatal("Read was expected to return error but it didn't") + } else { + t.Log("Read failed as expected with error:", err.Error()) + } +} + +func TestReadByteFailsOnSecondPacket(t *testing.T) { + buffer := makeBuf(9, []byte{ + 0x01 /*id*/, 0x0 /*not final*/, 0x0, 0x9 /*size*/, 0xff, 0xff, 0xff, 0xff, 0x02, /*test byte*/ + 0x01 /*next id, this packet is invalid, it is too short*/}) + + _, err := buffer.BeginRead() + if err != nil { + t.Fatal("BeginRead failed:", err.Error()) + } + + _, err = buffer.ReadByte() + if err != nil { + t.Fatal("ReadByte failed:", err.Error()) + } + + _, err = buffer.ReadByte() + if err == nil { + t.Fatal("ReadByte was expected to return error but it didn't") + } else { + t.Log("ReadByte failed as expected with error:", err.Error()) + } + + t.Run("test byte() panic", func(t *testing.T) { + defer func() { + recover() + }() + buffer.byte() + t.Fatal("byte() should panic, but it didn't") + }) + + t.Run("test ReadFull() panic", func(t *testing.T) { + defer func() { + recover() + }() + buf := make([]byte, 10) + buffer.ReadFull(buf) + t.Fatal("ReadFull() should panic, but it didn't") + }) +} + +func TestReadFailsOnSecondPacket(t *testing.T) { + buffer := makeBuf(9, []byte{ + 0x01 /*id*/, 0x0 /*not final*/, 0x0, 0x9 /*size*/, 0xff, 0xff, 0xff, 0xff, 0x02, /*test byte*/ + 0x01 /*next id, this packet is invalid, it is too short*/}) + + _, err := buffer.BeginRead() + if err != nil { + t.Fatal("BeginRead failed:", err.Error()) + } + + testBuf := []byte{0} + _, err = buffer.Read(testBuf) + if err != nil { + t.Fatal("Read failed:", err.Error()) + } + if testBuf[0] != 2 { + t.Fatal("Read returned invalid value") + } + + _, err = buffer.Read(testBuf) + if err == nil { + t.Fatal("ReadByte was expected to return error but it didn't") + } else { + t.Log("ReadByte failed as expected with error:", err.Error()) + } +} + +func TestWrite(t *testing.T) { + memBuf := bytes.NewBuffer([]byte{}) + buf := newTdsBuffer(11, closableBuffer{memBuf}) + buf.BeginPacket(1, false) + err := buf.WriteByte(2) + if err != nil { + t.Fatal("WriteByte failed:", err.Error()) + } + wrote, err := buf.Write([]byte{3, 4}) + if err != nil { + t.Fatal("Write failed:", err.Error()) + } + if wrote != 2 { + t.Fatalf("Write returned invalid value of written bytes %d", wrote) + } + + err = buf.FinishPacket() + if err != nil { + t.Fatal("FinishPacket failed:", err.Error()) + } + if bytes.Compare(memBuf.Bytes(), []byte{1, 1, 0, 11, 0, 0, 1, 0, 2, 3, 4}) != 0 { + t.Fatalf("Written buffer has invalid content: %v", memBuf.Bytes()) + } + + buf.BeginPacket(2, false) + wrote, err = buf.Write([]byte{3, 4, 5, 6}) + if err != nil { + t.Fatal("Write failed:", err.Error()) + } + if wrote != 4 { + t.Fatalf("Write returned invalid value of written bytes %d", wrote) + } + err = buf.FinishPacket() + if err != nil { + t.Fatal("FinishPacket failed:", err.Error()) + } + expectedBuf := []byte{ + 1, 1, 0, 11, 0, 0, 1, 0, 2, 3, 4, // packet 1 + 2, 0, 0, 11, 0, 0, 1, 0, 3, 4, 5, // packet 2 + 2, 1, 0, 9, 0, 0, 2, 0, 6, // packet 3 + } + if bytes.Compare(memBuf.Bytes(), expectedBuf) != 0 { + t.Fatalf("Written buffer has invalid content:\n got: %v\nwant: %v", memBuf.Bytes(), expectedBuf) + } +} + +func TestWriteErrors(t *testing.T) { + // write should fail if underlying transport fails + buf := newTdsBuffer(uint16(headerSize)+1, failBuffer{}) + buf.BeginPacket(1, false) + wrote, err := buf.Write([]byte{0, 0}) + // may change from error to panic in future + if err == nil { + t.Fatal("Write should fail but it didn't") + } + if wrote != 1 { + t.Fatal("Should write 1 byte but it wrote ", wrote) + } + + // writebyte should fail if underlying transport fails + buf = newTdsBuffer(uint16(headerSize)+1, failBuffer{}) + buf.BeginPacket(1, false) + // first write should not fail because if fits in the buffer + err = buf.WriteByte(0) + if err != nil { + t.Fatal("First WriteByte should not fail because it should fit in the buffer, but it failed", err) + } + err = buf.WriteByte(0) + // may change from error to panic in future + if err == nil { + t.Fatal("Second WriteByte should fail but it didn't") + } +} + +func TestWrite_BufferBounds(t *testing.T) { + memBuf := bytes.NewBuffer([]byte{}) + buf := newTdsBuffer(11, closableBuffer{memBuf}) + + buf.BeginPacket(1, false) + // write bytes enough to complete a package + _, err := buf.Write([]byte{1, 1, 1}) + if err != nil { + t.Fatal("Write failed:", err.Error()) + } + err = buf.WriteByte(1) + if err != nil { + t.Fatal("WriteByte failed:", err.Error()) + } + _, err = buf.Write([]byte{1, 1, 1}) + if err != nil { + t.Fatal("Write failed:", err.Error()) + } + err = buf.FinishPacket() + if err != nil { + t.Fatal("FinishPacket failed:", err.Error()) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go new file mode 100644 index 00000000..3b319af8 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go @@ -0,0 +1,554 @@ +package mssql + +import ( + "bytes" + "context" + "encoding/binary" + "fmt" + "math" + "reflect" + "strconv" + "strings" + "time" +) + +type Bulk struct { + // ctx is used only for AddRow and Done methods. + // This could be removed if AddRow and Done accepted + // a ctx field as well, which is available with the + // database/sql call. + ctx context.Context + + cn *Conn + metadata []columnStruct + bulkColumns []columnStruct + columnsName []string + tablename string + numRows int + + headerSent bool + Options BulkOptions + Debug bool +} +type BulkOptions struct { + CheckConstraints bool + FireTriggers bool + KeepNulls bool + KilobytesPerBatch int + RowsPerBatch int + Order []string + Tablock bool +} + +type DataValue interface{} + +func (cn *Conn) CreateBulk(table string, columns []string) (_ *Bulk) { + b := Bulk{ctx: context.Background(), cn: cn, tablename: table, headerSent: false, columnsName: columns} + b.Debug = false + return &b +} + +func (cn *Conn) CreateBulkContext(ctx context.Context, table string, columns []string) (_ *Bulk) { + b := Bulk{ctx: ctx, cn: cn, tablename: table, headerSent: false, columnsName: columns} + b.Debug = false + return &b +} + +func (b *Bulk) sendBulkCommand(ctx context.Context) (err error) { + //get table columns info + err = b.getMetadata(ctx) + if err != nil { + return err + } + + //match the columns + for _, colname := range b.columnsName { + var bulkCol *columnStruct + + for _, m := range b.metadata { + if m.ColName == colname { + bulkCol = &m + break + } + } + if bulkCol != nil { + + if bulkCol.ti.TypeId == typeUdt { + //send udt as binary + bulkCol.ti.TypeId = typeBigVarBin + } + b.bulkColumns = append(b.bulkColumns, *bulkCol) + b.dlogf("Adding column %s %s %#x", colname, bulkCol.ColName, bulkCol.ti.TypeId) + } else { + return fmt.Errorf("Column %s does not exist in destination table %s", colname, b.tablename) + } + } + + //create the bulk command + + //columns definitions + var col_defs bytes.Buffer + for i, col := range b.bulkColumns { + if i != 0 { + col_defs.WriteString(", ") + } + col_defs.WriteString("[" + col.ColName + "] " + makeDecl(col.ti)) + } + + //options + var with_opts []string + + if b.Options.CheckConstraints { + with_opts = append(with_opts, "CHECK_CONSTRAINTS") + } + if b.Options.FireTriggers { + with_opts = append(with_opts, "FIRE_TRIGGERS") + } + if b.Options.KeepNulls { + with_opts = append(with_opts, "KEEP_NULLS") + } + if b.Options.KilobytesPerBatch > 0 { + with_opts = append(with_opts, fmt.Sprintf("KILOBYTES_PER_BATCH = %d", b.Options.KilobytesPerBatch)) + } + if b.Options.RowsPerBatch > 0 { + with_opts = append(with_opts, fmt.Sprintf("ROWS_PER_BATCH = %d", b.Options.RowsPerBatch)) + } + if len(b.Options.Order) > 0 { + with_opts = append(with_opts, fmt.Sprintf("ORDER(%s)", strings.Join(b.Options.Order, ","))) + } + if b.Options.Tablock { + with_opts = append(with_opts, "TABLOCK") + } + var with_part string + if len(with_opts) > 0 { + with_part = fmt.Sprintf("WITH (%s)", strings.Join(with_opts, ",")) + } + + query := fmt.Sprintf("INSERT BULK %s (%s) %s", b.tablename, col_defs.String(), with_part) + + stmt, err := b.cn.PrepareContext(ctx, query) + if err != nil { + return fmt.Errorf("Prepare failed: %s", err.Error()) + } + b.dlogf(query) + + _, err = stmt.(*Stmt).ExecContext(ctx, nil) + if err != nil { + return err + } + + b.headerSent = true + + var buf = b.cn.sess.buf + buf.BeginPacket(packBulkLoadBCP, false) + + // Send the columns metadata. + columnMetadata := b.createColMetadata() + _, err = buf.Write(columnMetadata) + + return +} + +// AddRow immediately writes the row to the destination table. +// The arguments are the row values in the order they were specified. +func (b *Bulk) AddRow(row []interface{}) (err error) { + if !b.headerSent { + err = b.sendBulkCommand(b.ctx) + if err != nil { + return + } + } + + if len(row) != len(b.bulkColumns) { + return fmt.Errorf("Row does not have the same number of columns than the destination table %d %d", + len(row), len(b.bulkColumns)) + } + + bytes, err := b.makeRowData(row) + if err != nil { + return + } + + _, err = b.cn.sess.buf.Write(bytes) + if err != nil { + return + } + + b.numRows = b.numRows + 1 + return +} + +func (b *Bulk) makeRowData(row []interface{}) ([]byte, error) { + buf := new(bytes.Buffer) + buf.WriteByte(byte(tokenRow)) + + var logcol bytes.Buffer + for i, col := range b.bulkColumns { + + if b.Debug { + logcol.WriteString(fmt.Sprintf(" col[%d]='%v' ", i, row[i])) + } + param, err := b.makeParam(row[i], col) + if err != nil { + return nil, fmt.Errorf("bulkcopy: %s", err.Error()) + } + + if col.ti.Writer == nil { + return nil, fmt.Errorf("no writer for column: %s, TypeId: %#x", + col.ColName, col.ti.TypeId) + } + err = col.ti.Writer(buf, param.ti, param.buffer) + if err != nil { + return nil, fmt.Errorf("bulkcopy: %s", err.Error()) + } + } + + b.dlogf("row[%d] %s\n", b.numRows, logcol.String()) + + return buf.Bytes(), nil +} + +func (b *Bulk) Done() (rowcount int64, err error) { + if b.headerSent == false { + //no rows had been sent + return 0, nil + } + var buf = b.cn.sess.buf + buf.WriteByte(byte(tokenDone)) + + binary.Write(buf, binary.LittleEndian, uint16(doneFinal)) + binary.Write(buf, binary.LittleEndian, uint16(0)) // curcmd + + if b.cn.sess.loginAck.TDSVersion >= verTDS72 { + binary.Write(buf, binary.LittleEndian, uint64(0)) //rowcount 0 + } else { + binary.Write(buf, binary.LittleEndian, uint32(0)) //rowcount 0 + } + + buf.FinishPacket() + + tokchan := make(chan tokenStruct, 5) + go processResponse(b.ctx, b.cn.sess, tokchan, nil) + + var rowCount int64 + for token := range tokchan { + switch token := token.(type) { + case doneStruct: + if token.Status&doneCount != 0 { + rowCount = int64(token.RowCount) + } + if token.isError() { + return 0, token.getError() + } + case error: + return 0, b.cn.checkBadConn(token) + } + } + return rowCount, nil +} + +func (b *Bulk) createColMetadata() []byte { + buf := new(bytes.Buffer) + buf.WriteByte(byte(tokenColMetadata)) // token + binary.Write(buf, binary.LittleEndian, uint16(len(b.bulkColumns))) // column count + + for i, col := range b.bulkColumns { + + if b.cn.sess.loginAck.TDSVersion >= verTDS72 { + binary.Write(buf, binary.LittleEndian, uint32(col.UserType)) // usertype, always 0? + } else { + binary.Write(buf, binary.LittleEndian, uint16(col.UserType)) + } + binary.Write(buf, binary.LittleEndian, uint16(col.Flags)) + + writeTypeInfo(buf, &b.bulkColumns[i].ti) + + if col.ti.TypeId == typeNText || + col.ti.TypeId == typeText || + col.ti.TypeId == typeImage { + + tablename_ucs2 := str2ucs2(b.tablename) + binary.Write(buf, binary.LittleEndian, uint16(len(tablename_ucs2)/2)) + buf.Write(tablename_ucs2) + } + colname_ucs2 := str2ucs2(col.ColName) + buf.WriteByte(uint8(len(colname_ucs2) / 2)) + buf.Write(colname_ucs2) + } + + return buf.Bytes() +} + +func (b *Bulk) getMetadata(ctx context.Context) (err error) { + stmt, err := b.cn.prepareContext(ctx, "SET FMTONLY ON") + if err != nil { + return + } + + _, err = stmt.ExecContext(ctx, nil) + if err != nil { + return + } + + // Get columns info. + stmt, err = b.cn.prepareContext(ctx, fmt.Sprintf("select * from %s SET FMTONLY OFF", b.tablename)) + if err != nil { + return + } + rows, err := stmt.QueryContext(ctx, nil) + if err != nil { + return fmt.Errorf("get columns info failed: %v", err) + } + b.metadata = rows.(*Rows).cols + + if b.Debug { + for _, col := range b.metadata { + b.dlogf("col: %s typeId: %#x size: %d scale: %d prec: %d flags: %d lcid: %#x\n", + col.ColName, col.ti.TypeId, col.ti.Size, col.ti.Scale, col.ti.Prec, + col.Flags, col.ti.Collation.LcidAndFlags) + } + } + + return rows.Close() +} + +func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) { + res.ti.Size = col.ti.Size + res.ti.TypeId = col.ti.TypeId + + if val == nil { + res.ti.Size = 0 + return + } + + switch col.ti.TypeId { + + case typeInt1, typeInt2, typeInt4, typeInt8, typeIntN: + var intvalue int64 + + switch val := val.(type) { + case int: + intvalue = int64(val) + case int32: + intvalue = int64(val) + case int64: + intvalue = val + default: + err = fmt.Errorf("mssql: invalid type for int column") + return + } + + res.buffer = make([]byte, res.ti.Size) + if col.ti.Size == 1 { + res.buffer[0] = byte(intvalue) + } else if col.ti.Size == 2 { + binary.LittleEndian.PutUint16(res.buffer, uint16(intvalue)) + } else if col.ti.Size == 4 { + binary.LittleEndian.PutUint32(res.buffer, uint32(intvalue)) + } else if col.ti.Size == 8 { + binary.LittleEndian.PutUint64(res.buffer, uint64(intvalue)) + } + case typeFlt4, typeFlt8, typeFltN: + var floatvalue float64 + + switch val := val.(type) { + case float32: + floatvalue = float64(val) + case float64: + floatvalue = val + case int: + floatvalue = float64(val) + case int64: + floatvalue = float64(val) + default: + err = fmt.Errorf("mssql: invalid type for float column: %s", val) + return + } + + if col.ti.Size == 4 { + res.buffer = make([]byte, 4) + binary.LittleEndian.PutUint32(res.buffer, math.Float32bits(float32(floatvalue))) + } else if col.ti.Size == 8 { + res.buffer = make([]byte, 8) + binary.LittleEndian.PutUint64(res.buffer, math.Float64bits(floatvalue)) + } + case typeNVarChar, typeNText, typeNChar: + + switch val := val.(type) { + case string: + res.buffer = str2ucs2(val) + case []byte: + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for nvarchar column: %s", val) + return + } + res.ti.Size = len(res.buffer) + + case typeVarChar, typeBigVarChar, typeText, typeChar, typeBigChar: + switch val := val.(type) { + case string: + res.buffer = []byte(val) + case []byte: + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for varchar column: %s", val) + return + } + res.ti.Size = len(res.buffer) + + case typeBit, typeBitN: + if reflect.TypeOf(val).Kind() != reflect.Bool { + err = fmt.Errorf("mssql: invalid type for bit column: %s", val) + return + } + res.ti.TypeId = typeBitN + res.ti.Size = 1 + res.buffer = make([]byte, 1) + if val.(bool) { + res.buffer[0] = 1 + } + case typeDateTime2N: + switch val := val.(type) { + case time.Time: + res.buffer = encodeDateTime2(val, int(col.ti.Scale)) + res.ti.Size = len(res.buffer) + default: + err = fmt.Errorf("mssql: invalid type for datetime2 column: %s", val) + return + } + case typeDateTimeOffsetN: + switch val := val.(type) { + case time.Time: + res.buffer = encodeDateTimeOffset(val, int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + + default: + err = fmt.Errorf("mssql: invalid type for datetimeoffset column: %s", val) + return + } + case typeDateN: + switch val := val.(type) { + case time.Time: + res.buffer = encodeDate(val) + res.ti.Size = len(res.buffer) + default: + err = fmt.Errorf("mssql: invalid type for date column: %s", val) + return + } + case typeDateTime, typeDateTimeN, typeDateTim4: + switch val := val.(type) { + case time.Time: + if col.ti.Size == 4 { + res.buffer = encodeDateTim4(val) + res.ti.Size = len(res.buffer) + } else if col.ti.Size == 8 { + res.buffer = encodeDateTime(val) + res.ti.Size = len(res.buffer) + } else { + err = fmt.Errorf("mssql: invalid size of column") + } + + default: + err = fmt.Errorf("mssql: invalid type for datetime column: %s", val) + } + + // case typeMoney, typeMoney4, typeMoneyN: + case typeDecimal, typeDecimalN, typeNumeric, typeNumericN: + var value float64 + switch v := val.(type) { + case int: + value = float64(v) + case int8: + value = float64(v) + case int16: + value = float64(v) + case int32: + value = float64(v) + case int64: + value = float64(v) + case float32: + value = float64(v) + case float64: + value = v + case string: + if value, err = strconv.ParseFloat(v, 64); err != nil { + return res, fmt.Errorf("bulk: unable to convert string to float: %v", err) + } + default: + return res, fmt.Errorf("unknown value for decimal: %#v", v) + } + + perc := col.ti.Prec + scale := col.ti.Scale + var dec Decimal + dec, err = Float64ToDecimalScale(value, scale) + if err != nil { + return res, err + } + dec.prec = perc + + var length byte + switch { + case perc <= 9: + length = 4 + case perc <= 19: + length = 8 + case perc <= 28: + length = 12 + default: + length = 16 + } + + buf := make([]byte, length+1) + // first byte length written by typeInfo.writer + res.ti.Size = int(length) + 1 + // second byte sign + if value < 0 { + buf[0] = 0 + } else { + buf[0] = 1 + } + + ub := dec.UnscaledBytes() + l := len(ub) + if l > int(length) { + err = fmt.Errorf("decimal out of range: %s", dec) + return res, err + } + // reverse the bytes + for i, j := 1, l-1; j >= 0; i, j = i+1, j-1 { + buf[i] = ub[j] + } + res.buffer = buf + case typeBigVarBin, typeBigBinary: + switch val := val.(type) { + case []byte: + res.ti.Size = len(val) + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for Binary column: %s", val) + return + } + case typeGuid: + switch val := val.(type) { + case []byte: + res.ti.Size = len(val) + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for Guid column: %s", val) + return + } + + default: + err = fmt.Errorf("mssql: type %x not implemented", col.ti.TypeId) + } + return + +} + +func (b *Bulk) dlogf(format string, v ...interface{}) { + if b.Debug { + b.cn.sess.log.Printf(format, v...) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go new file mode 100644 index 00000000..709505b2 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go @@ -0,0 +1,93 @@ +package mssql + +import ( + "context" + "database/sql/driver" + "encoding/json" + "errors" +) + +type copyin struct { + cn *Conn + bulkcopy *Bulk + closed bool +} + +type serializableBulkConfig struct { + TableName string + ColumnsName []string + Options BulkOptions +} + +func (d *Driver) OpenConnection(dsn string) (*Conn, error) { + return d.open(context.Background(), dsn) +} + +func (c *Conn) prepareCopyIn(ctx context.Context, query string) (_ driver.Stmt, err error) { + config_json := query[11:] + + bulkconfig := serializableBulkConfig{} + err = json.Unmarshal([]byte(config_json), &bulkconfig) + if err != nil { + return + } + + bulkcopy := c.CreateBulkContext(ctx, bulkconfig.TableName, bulkconfig.ColumnsName) + bulkcopy.Options = bulkconfig.Options + + ci := ©in{ + cn: c, + bulkcopy: bulkcopy, + } + + return ci, nil +} + +func CopyIn(table string, options BulkOptions, columns ...string) string { + bulkconfig := &serializableBulkConfig{TableName: table, Options: options, ColumnsName: columns} + + config_json, err := json.Marshal(bulkconfig) + if err != nil { + panic(err) + } + + stmt := "INSERTBULK " + string(config_json) + + return stmt +} + +func (ci *copyin) NumInput() int { + return -1 +} + +func (ci *copyin) Query(v []driver.Value) (r driver.Rows, err error) { + panic("should never be called") +} + +func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) { + if ci.closed { + return nil, errors.New("copyin query is closed") + } + + if len(v) == 0 { + rowCount, err := ci.bulkcopy.Done() + ci.closed = true + return driver.RowsAffected(rowCount), err + } + + t := make([]interface{}, len(v)) + for i, val := range v { + t[i] = val + } + + err = ci.bulkcopy.AddRow(t) + if err != nil { + return + } + + return driver.RowsAffected(0), nil +} + +func (ci *copyin) Close() (err error) { + return nil +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_test.go b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_test.go new file mode 100644 index 00000000..c0c89885 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_test.go @@ -0,0 +1,237 @@ +// +build go1.9 + +package mssql + +import ( + "context" + "database/sql" + "encoding/hex" + "math" + "reflect" + "strings" + "testing" + "time" +) + +func TestBulkcopy(t *testing.T) { + // TDS level Bulk Insert is not supported on Azure SQL Server. + if dsn := makeConnStr(t); strings.HasSuffix(strings.Split(dsn.Host, ":")[0], ".database.windows.net") { + t.Skip("TDS level bulk copy is not supported on Azure SQL Server") + } + type testValue struct { + colname string + val interface{} + } + + tableName := "#table_test" + geom, _ := hex.DecodeString("E6100000010C00000000000034400000000000004440") + bin, _ := hex.DecodeString("ba8b7782168d4033a299333aec17bd33") + testValues := []testValue{ + + {"test_nvarchar", "ab©ĎéⒻghïjklmnopqЯ☀tuvwxyz"}, + {"test_varchar", "abcdefg"}, + {"test_char", "abcdefg "}, + {"test_nchar", "abcdefg "}, + {"test_text", "abcdefg"}, + {"test_ntext", "abcdefg"}, + {"test_float", 1234.56}, + {"test_floatn", 1234.56}, + {"test_real", 1234.56}, + {"test_realn", 1234.56}, + {"test_bit", true}, + {"test_bitn", nil}, + {"test_smalldatetime", time.Date(2010, 11, 12, 13, 14, 0, 0, time.UTC)}, + {"test_smalldatetimen", time.Date(2010, 11, 12, 13, 14, 0, 0, time.UTC)}, + {"test_datetime", time.Date(2010, 11, 12, 13, 14, 15, 120000000, time.UTC)}, + {"test_datetimen", time.Date(2010, 11, 12, 13, 14, 15, 120000000, time.UTC)}, + {"test_datetimen_1", time.Date(4010, 11, 12, 13, 14, 15, 120000000, time.UTC)}, + {"test_datetime2_1", time.Date(2010, 11, 12, 13, 14, 15, 0, time.UTC)}, + {"test_datetime2_3", time.Date(2010, 11, 12, 13, 14, 15, 123000000, time.UTC)}, + {"test_datetime2_7", time.Date(2010, 11, 12, 13, 14, 15, 123000000, time.UTC)}, + {"test_date", time.Date(2010, 11, 12, 00, 00, 00, 0, time.UTC)}, + {"test_tinyint", 255}, + {"test_smallint", 32767}, + {"test_smallintn", nil}, + {"test_int", 2147483647}, + {"test_bigint", 9223372036854775807}, + {"test_bigintn", nil}, + {"test_geom", geom}, + {"test_uniqueidentifier", []byte{0x6F, 0x96, 0x19, 0xFF, 0x8B, 0x86, 0xD0, 0x11, 0xB4, 0x2D, 0x00, 0xC0, 0x4F, 0xC9, 0x64, 0xFF}}, + // {"test_smallmoney", 1234.56}, + // {"test_money", 1234.56}, + {"test_decimal_18_0", 1234.0001}, + {"test_decimal_9_2", 1234.560001}, + {"test_decimal_20_0", 1234.0001}, + {"test_numeric_30_10", 1234567.1234567}, + {"test_varbinary", []byte("1")}, + {"test_varbinary_16", bin}, + {"test_varbinary_max", bin}, + {"test_binary", []byte("1")}, + {"test_binary_16", bin}, + } + + columns := make([]string, len(testValues)) + for i, val := range testValues { + columns[i] = val.colname + } + + values := make([]interface{}, len(testValues)) + for i, val := range testValues { + values[i] = val.val + } + + pool := open(t) + defer pool.Close() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // Now that session resetting is supported, the use of the per session + // temp table requires the use of a dedicated connection from the connection + // pool. + conn, err := pool.Conn(ctx) + if err != nil { + t.Fatal("failed to pull connection from pool", err) + } + defer conn.Close() + + err = setupTable(ctx, t, conn, tableName) + if err != nil { + t.Error("Setup table failed: ", err) + return + } + + t.Log("Preparing copy in statement") + + stmt, err := conn.PrepareContext(ctx, CopyIn(tableName, BulkOptions{}, columns...)) + + for i := 0; i < 10; i++ { + t.Logf("Executing copy in statement %d time with %d values", i+1, len(values)) + _, err = stmt.Exec(values...) + if err != nil { + t.Error("AddRow failed: ", err.Error()) + return + } + } + + result, err := stmt.Exec() + if err != nil { + t.Fatal("bulkcopy failed: ", err.Error()) + } + + insertedRowCount, _ := result.RowsAffected() + if insertedRowCount == 0 { + t.Fatal("0 row inserted!") + } + + //check that all rows are present + var rowCount int + err = conn.QueryRowContext(ctx, "select count(*) c from "+tableName).Scan(&rowCount) + + if rowCount != 10 { + t.Errorf("unexpected row count %d", rowCount) + } + + //data verification + rows, err := conn.QueryContext(ctx, "select "+strings.Join(columns, ",")+" from "+tableName) + if err != nil { + t.Fatal(err) + } + defer rows.Close() + for rows.Next() { + + ptrs := make([]interface{}, len(columns)) + container := make([]interface{}, len(columns)) + for i, _ := range ptrs { + ptrs[i] = &container[i] + } + if err := rows.Scan(ptrs...); err != nil { + t.Fatal(err) + } + for i, c := range testValues { + if !compareValue(container[i], c.val) { + t.Errorf("columns %s : expected: %v, got: %v\n", c.colname, c.val, container[i]) + } + } + } + if err := rows.Err(); err != nil { + t.Error(err) + } +} + +func compareValue(a interface{}, expected interface{}) bool { + switch expected := expected.(type) { + case int: + return int64(expected) == a + case int32: + return int64(expected) == a + case int64: + return int64(expected) == a + case float64: + if got, ok := a.([]uint8); ok { + var nf sql.NullFloat64 + nf.Scan(got) + a = nf.Float64 + } + return math.Abs(expected-a.(float64)) < 0.0001 + default: + return reflect.DeepEqual(expected, a) + } +} + +func setupTable(ctx context.Context, t *testing.T, conn *sql.Conn, tableName string) (err error) { + tablesql := `CREATE TABLE ` + tableName + ` ( + [id] [int] IDENTITY(1,1) NOT NULL, + [test_nvarchar] [nvarchar](50) NULL, + [test_varchar] [varchar](50) NULL, + [test_char] [char](10) NULL, + [test_nchar] [nchar](10) NULL, + [test_text] [text] NULL, + [test_ntext] [ntext] NULL, + [test_float] [float] NOT NULL, + [test_floatn] [float] NULL, + [test_real] [real] NULL, + [test_realn] [real] NULL, + [test_bit] [bit] NOT NULL, + [test_bitn] [bit] NULL, + [test_smalldatetime] [smalldatetime] NOT NULL, + [test_smalldatetimen] [smalldatetime] NULL, + [test_datetime] [datetime] NOT NULL, + [test_datetimen] [datetime] NULL, + [test_datetimen_1] [datetime] NULL, + [test_datetime2_1] [datetime2](1) NULL, + [test_datetime2_3] [datetime2](3) NULL, + [test_datetime2_7] [datetime2](7) NULL, + [test_date] [date] NULL, + [test_smallmoney] [smallmoney] NULL, + [test_money] [money] NULL, + [test_tinyint] [tinyint] NULL, + [test_smallint] [smallint] NOT NULL, + [test_smallintn] [smallint] NULL, + [test_int] [int] NULL, + [test_bigint] [bigint] NOT NULL, + [test_bigintn] [bigint] NULL, + [test_geom] [geometry] NULL, + [test_geog] [geography] NULL, + [text_xml] [xml] NULL, + [test_uniqueidentifier] [uniqueidentifier] NULL, + [test_decimal_18_0] [decimal](18, 0) NULL, + [test_decimal_9_2] [decimal](9, 2) NULL, + [test_decimal_20_0] [decimal](20, 0) NULL, + [test_numeric_30_10] [decimal](30, 10) NULL, + [test_varbinary] VARBINARY NOT NULL, + [test_varbinary_16] VARBINARY(16) NOT NULL, + [test_varbinary_max] VARBINARY(max) NOT NULL, + [test_binary] BINARY NOT NULL, + [test_binary_16] BINARY(16) NOT NULL, + CONSTRAINT [PK_` + tableName + `_id] PRIMARY KEY CLUSTERED +( + [id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY];` + _, err = conn.ExecContext(ctx, tablesql) + if err != nil { + t.Fatal("tablesql failed:", err) + } + return +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/convert.go b/vendor/github.com/denisenkom/go-mssqldb/convert.go new file mode 100644 index 00000000..51bd4ee3 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/convert.go @@ -0,0 +1,306 @@ +package mssql + +import "errors" + +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Type conversions for Scan. + +// This file was imported from database.sql.convert for go 1.10.3 with minor modifications to get +// convertAssign function +// This function is used internally by sql to convert values during call to Scan, we need same +// logic to return values for OUTPUT parameters. +// TODO: sql library should instead expose function defaultCheckNamedValue to be callable by drivers + +import ( + "database/sql" + "database/sql/driver" + "fmt" + "reflect" + "strconv" + "time" +) + +var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error + +// convertAssign copies to dest the value in src, converting it if possible. +// An error is returned if the copy would result in loss of information. +// dest should be a pointer type. +func convertAssign(dest, src interface{}) error { + // Common cases, without reflect. + switch s := src.(type) { + case string: + switch d := dest.(type) { + case *string: + if d == nil { + return errNilPtr + } + *d = s + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = []byte(s) + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = append((*d)[:0], s...) + return nil + } + case []byte: + switch d := dest.(type) { + case *string: + if d == nil { + return errNilPtr + } + *d = string(s) + return nil + case *interface{}: + if d == nil { + return errNilPtr + } + *d = cloneBytes(s) + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = cloneBytes(s) + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = s + return nil + } + case time.Time: + switch d := dest.(type) { + case *time.Time: + *d = s + return nil + case *string: + *d = s.Format(time.RFC3339Nano) + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = []byte(s.Format(time.RFC3339Nano)) + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = s.AppendFormat((*d)[:0], time.RFC3339Nano) + return nil + } + case nil: + switch d := dest.(type) { + case *interface{}: + if d == nil { + return errNilPtr + } + *d = nil + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = nil + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = nil + return nil + } + } + + var sv reflect.Value + + switch d := dest.(type) { + case *string: + sv = reflect.ValueOf(src) + switch sv.Kind() { + case reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: + *d = asString(src) + return nil + } + case *[]byte: + sv = reflect.ValueOf(src) + if b, ok := asBytes(nil, sv); ok { + *d = b + return nil + } + case *sql.RawBytes: + sv = reflect.ValueOf(src) + if b, ok := asBytes([]byte(*d)[:0], sv); ok { + *d = sql.RawBytes(b) + return nil + } + case *bool: + bv, err := driver.Bool.ConvertValue(src) + if err == nil { + *d = bv.(bool) + } + return err + case *interface{}: + *d = src + return nil + } + + if scanner, ok := dest.(sql.Scanner); ok { + return scanner.Scan(src) + } + + dpv := reflect.ValueOf(dest) + if dpv.Kind() != reflect.Ptr { + return errors.New("destination not a pointer") + } + if dpv.IsNil() { + return errNilPtr + } + + if !sv.IsValid() { + sv = reflect.ValueOf(src) + } + + dv := reflect.Indirect(dpv) + if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { + switch b := src.(type) { + case []byte: + dv.Set(reflect.ValueOf(cloneBytes(b))) + default: + dv.Set(sv) + } + return nil + } + + if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { + dv.Set(sv.Convert(dv.Type())) + return nil + } + + // The following conversions use a string value as an intermediate representation + // to convert between various numeric types. + // + // This also allows scanning into user defined types such as "type Int int64". + // For symmetry, also check for string destination types. + switch dv.Kind() { + case reflect.Ptr: + if src == nil { + dv.Set(reflect.Zero(dv.Type())) + return nil + } else { + dv.Set(reflect.New(dv.Type().Elem())) + return convertAssign(dv.Interface(), src) + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := asString(src) + i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetInt(i64) + return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + s := asString(src) + u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetUint(u64) + return nil + case reflect.Float32, reflect.Float64: + s := asString(src) + f64, err := strconv.ParseFloat(s, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetFloat(f64) + return nil + case reflect.String: + switch v := src.(type) { + case string: + dv.SetString(v) + return nil + case []byte: + dv.SetString(string(v)) + return nil + } + } + + return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) +} + +func strconvErr(err error) error { + if ne, ok := err.(*strconv.NumError); ok { + return ne.Err + } + return err +} + +func cloneBytes(b []byte) []byte { + if b == nil { + return nil + } else { + c := make([]byte, len(b)) + copy(c, b) + return c + } +} + +func asString(src interface{}) string { + switch v := src.(type) { + case string: + return v + case []byte: + return string(v) + } + rv := reflect.ValueOf(src) + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.FormatInt(rv.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.FormatUint(rv.Uint(), 10) + case reflect.Float64: + return strconv.FormatFloat(rv.Float(), 'g', -1, 64) + case reflect.Float32: + return strconv.FormatFloat(rv.Float(), 'g', -1, 32) + case reflect.Bool: + return strconv.FormatBool(rv.Bool()) + } + return fmt.Sprintf("%v", src) +} + +func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) { + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.AppendInt(buf, rv.Int(), 10), true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.AppendUint(buf, rv.Uint(), 10), true + case reflect.Float32: + return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true + case reflect.Float64: + return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true + case reflect.Bool: + return strconv.AppendBool(buf, rv.Bool()), true + case reflect.String: + s := rv.String() + return append(buf, s...), true + } + return +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/decimal.go b/vendor/github.com/denisenkom/go-mssqldb/decimal.go new file mode 100644 index 00000000..372f64b4 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/decimal.go @@ -0,0 +1,131 @@ +package mssql + +import ( + "encoding/binary" + "errors" + "math" + "math/big" +) + +// http://msdn.microsoft.com/en-us/library/ee780893.aspx +type Decimal struct { + integer [4]uint32 + positive bool + prec uint8 + scale uint8 +} + +var scaletblflt64 [39]float64 + +func (d Decimal) ToFloat64() float64 { + val := float64(0) + for i := 3; i >= 0; i-- { + val *= 0x100000000 + val += float64(d.integer[i]) + } + if !d.positive { + val = -val + } + if d.scale != 0 { + val /= scaletblflt64[d.scale] + } + return val +} + +const autoScale = 100 + +func Float64ToDecimal(f float64) (Decimal, error) { + return Float64ToDecimalScale(f, autoScale) +} + +func Float64ToDecimalScale(f float64, scale uint8) (Decimal, error) { + var dec Decimal + if math.IsNaN(f) { + return dec, errors.New("NaN") + } + if math.IsInf(f, 0) { + return dec, errors.New("Infinity can't be converted to decimal") + } + dec.positive = f >= 0 + if !dec.positive { + f = math.Abs(f) + } + if f > 3.402823669209385e+38 { + return dec, errors.New("Float value is out of range") + } + dec.prec = 20 + var integer float64 + for dec.scale = 0; dec.scale <= scale; dec.scale++ { + integer = f * scaletblflt64[dec.scale] + _, frac := math.Modf(integer) + if frac == 0 && scale == autoScale { + break + } + } + for i := 0; i < 4; i++ { + mod := math.Mod(integer, 0x100000000) + integer -= mod + integer /= 0x100000000 + dec.integer[i] = uint32(mod) + } + return dec, nil +} + +func init() { + var acc float64 = 1 + for i := 0; i <= 38; i++ { + scaletblflt64[i] = acc + acc *= 10 + } +} + +func (d Decimal) BigInt() big.Int { + bytes := make([]byte, 16) + binary.BigEndian.PutUint32(bytes[0:4], d.integer[3]) + binary.BigEndian.PutUint32(bytes[4:8], d.integer[2]) + binary.BigEndian.PutUint32(bytes[8:12], d.integer[1]) + binary.BigEndian.PutUint32(bytes[12:16], d.integer[0]) + var x big.Int + x.SetBytes(bytes) + if !d.positive { + x.Neg(&x) + } + return x +} + +func (d Decimal) Bytes() []byte { + x := d.BigInt() + return scaleBytes(x.String(), d.scale) +} + +func (d Decimal) UnscaledBytes() []byte { + x := d.BigInt() + return x.Bytes() +} + +func scaleBytes(s string, scale uint8) []byte { + z := make([]byte, 0, len(s)+1) + if s[0] == '-' || s[0] == '+' { + z = append(z, byte(s[0])) + s = s[1:] + } + pos := len(s) - int(scale) + if pos <= 0 { + z = append(z, byte('0')) + } else if pos > 0 { + z = append(z, []byte(s[:pos])...) + } + if scale > 0 { + z = append(z, byte('.')) + for pos < 0 { + z = append(z, byte('0')) + pos++ + } + z = append(z, []byte(s[pos:])...) + } + return z +} + +func (d Decimal) String() string { + return string(d.Bytes()) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/decimal_test.go b/vendor/github.com/denisenkom/go-mssqldb/decimal_test.go new file mode 100644 index 00000000..bf38d20d --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/decimal_test.go @@ -0,0 +1,107 @@ +package mssql + +import ( + "math" + "testing" +) + +func TestToString(t *testing.T) { + values := []struct { + dec Decimal + s string + }{ + {Decimal{positive: true, prec: 10, scale: 0, integer: [4]uint32{1, 0, 0, 0}}, "1"}, + {Decimal{positive: false, prec: 10, scale: 0, integer: [4]uint32{1, 0, 0, 0}}, "-1"}, + {Decimal{positive: true, prec: 10, scale: 1, integer: [4]uint32{1, 0, 0, 0}}, "0.1"}, + {Decimal{positive: true, prec: 10, scale: 2, integer: [4]uint32{1, 0, 0, 0}}, "0.01"}, + {Decimal{positive: false, prec: 10, scale: 1, integer: [4]uint32{1, 0, 0, 0}}, "-0.1"}, + {Decimal{positive: true, prec: 10, scale: 2, integer: [4]uint32{100, 0, 0, 0}}, "1.00"}, + {Decimal{positive: false, prec: 10, scale: 2, integer: [4]uint32{100, 0, 0, 0}}, "-1.00"}, + {Decimal{positive: true, prec: 30, scale: 0, integer: [4]uint32{0, 1, 0, 0}}, "4294967296"}, // 2^32 + {Decimal{positive: true, prec: 30, scale: 0, integer: [4]uint32{0, 0, 1, 0}}, "18446744073709551616"}, // 2^64 + {Decimal{positive: true, prec: 30, scale: 0, integer: [4]uint32{0, 1, 1, 0}}, "18446744078004518912"}, // 2^64+2^32 + } + for _, v := range values { + if v.dec.String() != v.s { + t.Error("String values don't match ", v.dec.String(), v.s) + } + } +} + +func TestToFloat64(t *testing.T) { + values := []struct { + dec Decimal + flt float64 + }{ + {Decimal{positive: true, prec: 1}, + 0.0}, + {Decimal{positive: true, prec: 1, integer: [4]uint32{1}}, + 1.0}, + {Decimal{positive: false, prec: 1, integer: [4]uint32{1}}, + -1.0}, + {Decimal{positive: true, prec: 1, scale: 1, integer: [4]uint32{5}}, + 0.5}, + {Decimal{positive: true, prec: 38, integer: [4]uint32{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}}, + 3.402823669209385e+38}, + {Decimal{positive: true, prec: 38, scale: 3, integer: [4]uint32{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}}, + 3.402823669209385e+35}, + } + for _, v := range values { + if v.dec.ToFloat64() != v.flt { + t.Error("ToFloat values don't match ", v.dec.ToFloat64(), v.flt) + } + } +} + +func TestFromFloat64(t *testing.T) { + values := []struct { + dec Decimal + flt float64 + }{ + {Decimal{positive: true, prec: 20}, + 0.0}, + {Decimal{positive: true, prec: 20, integer: [4]uint32{1}}, + 1.0}, + {Decimal{positive: false, prec: 20, integer: [4]uint32{1}}, + -1.0}, + {Decimal{positive: true, prec: 20, scale: 1, integer: [4]uint32{5}}, + 0.5}, + {Decimal{positive: true, prec: 20, integer: [4]uint32{0, 0, 0xfffff000, 0xffffffff}}, + 3.402823669209384e+38}, + //{Decimal{positive: true, prec: 20, scale: 3, integer: [4]uint32{0, 0, 0xfffff000, 0xffffffff}}, + // 3.402823669209385e+35}, + } + for _, v := range values { + decfromflt, err := Float64ToDecimal(v.flt) + if err == nil { + if decfromflt != v.dec { + t.Error("FromFloat values don't match ", decfromflt, v.dec) + } + } else { + t.Error("Float64ToDecimal failed with error:", err.Error()) + } + } + + _, err := Float64ToDecimal(math.NaN()) + if err == nil { + t.Error("Expected to get error for conversion from NaN, but didn't") + } + + _, err = Float64ToDecimal(math.Inf(1)) + if err == nil { + t.Error("Expected to get error for conversion from positive infinity, but didn't") + } + + _, err = Float64ToDecimal(math.Inf(-1)) + if err == nil { + t.Error("Expected to get error for conversion from negative infinity, but didn't") + } + _, err = Float64ToDecimal(3.402823669209386e+38) + if err == nil { + t.Error("Expected to get error for conversion from too big number, but didn't") + } + _, err = Float64ToDecimal(-3.402823669209386e+38) + if err == nil { + t.Error("Expected to get error for conversion from too big number, but didn't") + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/doc.go b/vendor/github.com/denisenkom/go-mssqldb/doc.go new file mode 100644 index 00000000..2e54929c --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/doc.go @@ -0,0 +1,14 @@ +// package mssql implements the TDS protocol used to connect to MS SQL Server (sqlserver) +// database servers. +// +// This package registers the driver: +// sqlserver: uses native "@" parameter placeholder names and does no pre-processing. +// +// If the ordinal position is used for query parameters, identifiers will be named +// "@p1", "@p2", ... "@pN". +// +// Please refer to the README for the format of the DSN. There are multiple DSN +// formats accepted: ADO style, ODBC style, and URL style. The following is an +// example of a URL style DSN: +// sqlserver://sa:mypass@localhost:1234?database=master&connection+timeout=30 +package mssql diff --git a/vendor/github.com/denisenkom/go-mssqldb/error.go b/vendor/github.com/denisenkom/go-mssqldb/error.go new file mode 100644 index 00000000..2e5bacee --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/error.go @@ -0,0 +1,73 @@ +package mssql + +import ( + "fmt" +) + +// Error represents an SQL Server error. This +// type includes methods for reading the contents +// of the struct, which allows calling programs +// to check for specific error conditions without +// having to import this package directly. +type Error struct { + Number int32 + State uint8 + Class uint8 + Message string + ServerName string + ProcName string + LineNo int32 +} + +func (e Error) Error() string { + return "mssql: " + e.Message +} + +// SQLErrorNumber returns the SQL Server error number. +func (e Error) SQLErrorNumber() int32 { + return e.Number +} + +func (e Error) SQLErrorState() uint8 { + return e.State +} + +func (e Error) SQLErrorClass() uint8 { + return e.Class +} + +func (e Error) SQLErrorMessage() string { + return e.Message +} + +func (e Error) SQLErrorServerName() string { + return e.ServerName +} + +func (e Error) SQLErrorProcName() string { + return e.ProcName +} + +func (e Error) SQLErrorLineNo() int32 { + return e.LineNo +} + +type StreamError struct { + Message string +} + +func (e StreamError) Error() string { + return e.Message +} + +func streamErrorf(format string, v ...interface{}) StreamError { + return StreamError{"Invalid TDS stream: " + fmt.Sprintf(format, v...)} +} + +func badStreamPanic(err error) { + panic(err) +} + +func badStreamPanicf(format string, v ...interface{}) { + panic(streamErrorf(format, v...)) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/error_example_test.go b/vendor/github.com/denisenkom/go-mssqldb/error_example_test.go new file mode 100644 index 00000000..05549755 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/error_example_test.go @@ -0,0 +1,38 @@ +package mssql + +import "fmt" + +func ExampleError_1() { + // call a function that might return a mssql error + err := callUsingMSSQL() + + type ErrorWithNumber interface { + SQLErrorNumber() int32 + } + + if errorWithNumber, ok := err.(ErrorWithNumber); ok { + if errorWithNumber.SQLErrorNumber() == 1205 { + fmt.Println("deadlock error") + } + } +} + +func ExampleError_2() { + // call a function that might return a mssql error + err := callUsingMSSQL() + + type SQLError interface { + SQLErrorNumber() int32 + SQLErrorMessage() string + } + + if sqlError, ok := err.(SQLError); ok { + if sqlError.SQLErrorNumber() == 1205 { + fmt.Println("deadlock error", sqlError.SQLErrorMessage()) + } + } +} + +func callUsingMSSQL() error { + return nil +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/examples/bulk/bulk.go b/vendor/github.com/denisenkom/go-mssqldb/examples/bulk/bulk.go new file mode 100644 index 00000000..8ce12388 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/examples/bulk/bulk.go @@ -0,0 +1,111 @@ +package main + +import ( + "database/sql" + "flag" + "fmt" + "log" + + "github.com/denisenkom/go-mssqldb" +) + +var ( + debug = flag.Bool("debug", true, "enable debugging") + password = flag.String("password", "osmtest", "the database password") + port *int = flag.Int("port", 1433, "the database port") + server = flag.String("server", "localhost", "the database server") + user = flag.String("user", "osmtest", "the database user") + database = flag.String("database", "bulktest", "the database name") +) + +/* + CREATE TABLE test_table( + [id] [int] IDENTITY(1,1) NOT NULL, + [test_nvarchar] [nvarchar](50) NULL, + [test_varchar] [varchar](50) NULL, + [test_float] [float] NULL, + [test_datetime2_3] [datetime2](3) NULL, + [test_bitn] [bit] NULL, + [test_bigint] [bigint] NOT NULL, + [test_geom] [geometry] NULL, + CONSTRAINT [PK_table_test_id] PRIMARY KEY CLUSTERED + ( + [id] ASC + ) ON [PRIMARY]); +*/ + +func main() { + flag.Parse() + + if *debug { + fmt.Printf(" password:%s\n", *password) + fmt.Printf(" port:%d\n", *port) + fmt.Printf(" server:%s\n", *server) + fmt.Printf(" user:%s\n", *user) + fmt.Printf(" database:%s\n", *database) + } + + connString := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;database=%s", *server, *user, *password, *port, *database) + if *debug { + fmt.Printf("connString:%s\n", connString) + } + conn, err := sql.Open("mssql", connString) + if err != nil { + log.Fatal("Open connection failed:", err.Error()) + } + defer conn.Close() + + txn, err := conn.Begin() + if err != nil { + log.Fatal(err) + } + + stmt, err := txn.Prepare(mssql.CopyIn("test_table", mssql.BulkOptions{}, "test_varchar", "test_nvarchar", "test_float", "test_bigint")) + if err != nil { + log.Fatal(err.Error()) + } + + for i := 0; i < 10; i++ { + _, err = stmt.Exec(generateString(0, 30), generateStringUnicode(0, 30), i, i) + if err != nil { + log.Fatal(err.Error()) + } + } + + result, err := stmt.Exec() + if err != nil { + log.Fatal(err) + } + + err = stmt.Close() + if err != nil { + log.Fatal(err) + } + + err = txn.Commit() + if err != nil { + log.Fatal(err) + } + rowCount, _ := result.RowsAffected() + log.Printf("%d row copied\n", rowCount) + log.Printf("bye\n") + +} + +func generateString(x int, n int) string { + letters := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + b := make([]byte, n) + for i := range b { + b[i] = letters[i%len(letters)] + } + return string(b) +} +func generateStringUnicode(x int, n int) string { + letters := "ab©💾é?ghïjklmnopqЯ☀tuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + + b := make([]byte, n) + for i := range b { + b[i] = letters[i%len(letters)] + } + return string(b) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/examples/simple/simple.go b/vendor/github.com/denisenkom/go-mssqldb/examples/simple/simple.go new file mode 100644 index 00000000..67f88aa4 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/examples/simple/simple.go @@ -0,0 +1,57 @@ +package main + +import ( + "database/sql" + "flag" + "fmt" + "log" + + _ "github.com/denisenkom/go-mssqldb" +) + +var ( + debug = flag.Bool("debug", false, "enable debugging") + password = flag.String("password", "", "the database password") + port *int = flag.Int("port", 1433, "the database port") + server = flag.String("server", "", "the database server") + user = flag.String("user", "", "the database user") +) + +func main() { + flag.Parse() + + if *debug { + fmt.Printf(" password:%s\n", *password) + fmt.Printf(" port:%d\n", *port) + fmt.Printf(" server:%s\n", *server) + fmt.Printf(" user:%s\n", *user) + } + + connString := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d", *server, *user, *password, *port) + if *debug { + fmt.Printf(" connString:%s\n", connString) + } + conn, err := sql.Open("mssql", connString) + if err != nil { + log.Fatal("Open connection failed:", err.Error()) + } + defer conn.Close() + + stmt, err := conn.Prepare("select 1, 'abc'") + if err != nil { + log.Fatal("Prepare failed:", err.Error()) + } + defer stmt.Close() + + row := stmt.QueryRow() + var somenumber int64 + var somechars string + err = row.Scan(&somenumber, &somechars) + if err != nil { + log.Fatal("Scan failed:", err.Error()) + } + fmt.Printf("somenumber:%d\n", somenumber) + fmt.Printf("somechars:%s\n", somechars) + + fmt.Printf("bye\n") +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/examples/tsql/tsql.go b/vendor/github.com/denisenkom/go-mssqldb/examples/tsql/tsql.go new file mode 100644 index 00000000..409404a0 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/examples/tsql/tsql.go @@ -0,0 +1,119 @@ +package main + +import ( + "bufio" + "database/sql" + "flag" + "fmt" + "io" + "os" + "time" + + _ "github.com/denisenkom/go-mssqldb" +) + +func main() { + var ( + userid = flag.String("U", "", "login_id") + password = flag.String("P", "", "password") + server = flag.String("S", "localhost", "server_name[\\instance_name]") + database = flag.String("d", "", "db_name") + ) + flag.Parse() + + dsn := "server=" + *server + ";user id=" + *userid + ";password=" + *password + ";database=" + *database + db, err := sql.Open("mssql", dsn) + if err != nil { + fmt.Println("Cannot connect: ", err.Error()) + return + } + err = db.Ping() + if err != nil { + fmt.Println("Cannot connect: ", err.Error()) + return + } + defer db.Close() + r := bufio.NewReader(os.Stdin) + for { + _, err = os.Stdout.Write([]byte("> ")) + if err != nil { + fmt.Println(err) + return + } + cmd, err := r.ReadString('\n') + if err != nil { + if err == io.EOF { + fmt.Println() + return + } + fmt.Println(err) + return + } + err = exec(db, cmd) + if err != nil { + fmt.Println(err) + } + } +} + +func exec(db *sql.DB, cmd string) error { + rows, err := db.Query(cmd) + if err != nil { + return err + } + defer rows.Close() + cols, err := rows.Columns() + if err != nil { + return err + } + if cols == nil { + return nil + } + vals := make([]interface{}, len(cols)) + for i := 0; i < len(cols); i++ { + vals[i] = new(interface{}) + if i != 0 { + fmt.Print("\t") + } + fmt.Print(cols[i]) + } + fmt.Println() + for rows.Next() { + err = rows.Scan(vals...) + if err != nil { + fmt.Println(err) + continue + } + for i := 0; i < len(vals); i++ { + if i != 0 { + fmt.Print("\t") + } + printValue(vals[i].(*interface{})) + } + fmt.Println() + + } + if rows.Err() != nil { + return rows.Err() + } + return nil +} + +func printValue(pval *interface{}) { + switch v := (*pval).(type) { + case nil: + fmt.Print("NULL") + case bool: + if v { + fmt.Print("1") + } else { + fmt.Print("0") + } + case []byte: + fmt.Print(string(v)) + case time.Time: + fmt.Print(v.Format("2006-01-02 15:04:05.999")) + default: + fmt.Print(v) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/charset.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/charset.go new file mode 100644 index 00000000..8dc2279e --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/charset.go @@ -0,0 +1,113 @@ +package cp + +type charsetMap struct { + sb [256]rune // single byte runes, -1 for a double byte character lead byte + db map[int]rune // double byte runes +} + +func collation2charset(col Collation) *charsetMap { + // http://msdn.microsoft.com/en-us/library/ms144250.aspx + // http://msdn.microsoft.com/en-us/library/ms144250(v=sql.105).aspx + switch col.SortId { + case 30, 31, 32, 33, 34: + return cp437 + case 40, 41, 42, 44, 49, 55, 56, 57, 58, 59, 60, 61: + return cp850 + case 50, 51, 52, 53, 54, 71, 72, 73, 74, 75: + return cp1252 + case 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96: + return cp1250 + case 104, 105, 106, 107, 108: + return cp1251 + case 112, 113, 114, 121, 124: + return cp1253 + case 128, 129, 130: + return cp1254 + case 136, 137, 138: + return cp1255 + case 144, 145, 146: + return cp1256 + case 152, 153, 154, 155, 156, 157, 158, 159, 160: + return cp1257 + case 183, 184, 185, 186: + return cp1252 + case 192, 193: + return cp932 + case 194, 195: + return cp949 + case 196, 197: + return cp950 + case 198, 199: + return cp936 + case 200: + return cp932 + case 201: + return cp949 + case 202: + return cp950 + case 203: + return cp936 + case 204, 205, 206: + return cp874 + case 210, 211, 212, 213, 214, 215, 216, 217: + return cp1252 + } + // http://technet.microsoft.com/en-us/library/aa176553(v=sql.80).aspx + switch col.getLcid() { + case 0x001e, 0x041e: + return cp874 + case 0x0411, 0x10411: + return cp932 + case 0x0804, 0x1004, 0x20804: + return cp936 + case 0x0012, 0x0412: + return cp949 + case 0x0404, 0x1404, 0x0c04, 0x7c04, 0x30404: + return cp950 + case 0x041c, 0x041a, 0x0405, 0x040e, 0x104e, 0x0415, 0x0418, 0x041b, 0x0424, 0x1040e: + return cp1250 + case 0x0423, 0x0402, 0x042f, 0x0419, 0x081a, 0x0c1a, 0x0422, 0x043f, 0x0444, 0x082c: + return cp1251 + case 0x0408: + return cp1253 + case 0x041f, 0x042c, 0x0443: + return cp1254 + case 0x040d: + return cp1255 + case 0x0401, 0x0801, 0xc01, 0x1001, 0x1401, 0x1801, 0x1c01, 0x2001, 0x2401, 0x2801, 0x2c01, 0x3001, 0x3401, 0x3801, 0x3c01, 0x4001, 0x0429, 0x0420: + return cp1256 + case 0x0425, 0x0426, 0x0427, 0x0827: + return cp1257 + case 0x042a: + return cp1258 + case 0x0439, 0x045a, 0x0465: + return nil + } + return cp1252 +} + +func CharsetToUTF8(col Collation, s []byte) string { + cm := collation2charset(col) + if cm == nil { + return string(s) + } + buf := make([]rune, 0, len(s)) + for i := 0; i < len(s); i++ { + ch := cm.sb[s[i]] + if ch == -1 { + if i+1 == len(s) { + ch = 0xfffd + } else { + n := int(s[i+1]) + (int(s[i]) << 8) + i++ + var ok bool + ch, ok = cm.db[n] + if !ok { + ch = 0xfffd + } + } + } + buf = append(buf, ch) + } + return string(buf) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go new file mode 100644 index 00000000..ae7b03bf --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go @@ -0,0 +1,20 @@ +package cp + +// http://msdn.microsoft.com/en-us/library/dd340437.aspx + +type Collation struct { + LcidAndFlags uint32 + SortId uint8 +} + +func (c Collation) getLcid() uint32 { + return c.LcidAndFlags & 0x000fffff +} + +func (c Collation) getFlags() uint32 { + return (c.LcidAndFlags & 0x0ff00000) >> 20 +} + +func (c Collation) getVersion() uint32 { + return (c.LcidAndFlags & 0xf0000000) >> 28 +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1250.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1250.go new file mode 100644 index 00000000..5c8094ec --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1250.go @@ -0,0 +1,262 @@ +package cp + +var cp1250 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0xFFFD, //UNDEFINED + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0xFFFD, //UNDEFINED + 0x2030, //PER MILLE SIGN + 0x0160, //LATIN CAPITAL LETTER S WITH CARON + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x015A, //LATIN CAPITAL LETTER S WITH ACUTE + 0x0164, //LATIN CAPITAL LETTER T WITH CARON + 0x017D, //LATIN CAPITAL LETTER Z WITH CARON + 0x0179, //LATIN CAPITAL LETTER Z WITH ACUTE + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0xFFFD, //UNDEFINED + 0x2122, //TRADE MARK SIGN + 0x0161, //LATIN SMALL LETTER S WITH CARON + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x015B, //LATIN SMALL LETTER S WITH ACUTE + 0x0165, //LATIN SMALL LETTER T WITH CARON + 0x017E, //LATIN SMALL LETTER Z WITH CARON + 0x017A, //LATIN SMALL LETTER Z WITH ACUTE + 0x00A0, //NO-BREAK SPACE + 0x02C7, //CARON + 0x02D8, //BREVE + 0x0141, //LATIN CAPITAL LETTER L WITH STROKE + 0x00A4, //CURRENCY SIGN + 0x0104, //LATIN CAPITAL LETTER A WITH OGONEK + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0x015E, //LATIN CAPITAL LETTER S WITH CEDILLA + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x017B, //LATIN CAPITAL LETTER Z WITH DOT ABOVE + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x02DB, //OGONEK + 0x0142, //LATIN SMALL LETTER L WITH STROKE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00B8, //CEDILLA + 0x0105, //LATIN SMALL LETTER A WITH OGONEK + 0x015F, //LATIN SMALL LETTER S WITH CEDILLA + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x013D, //LATIN CAPITAL LETTER L WITH CARON + 0x02DD, //DOUBLE ACUTE ACCENT + 0x013E, //LATIN SMALL LETTER L WITH CARON + 0x017C, //LATIN SMALL LETTER Z WITH DOT ABOVE + 0x0154, //LATIN CAPITAL LETTER R WITH ACUTE + 0x00C1, //LATIN CAPITAL LETTER A WITH ACUTE + 0x00C2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX + 0x0102, //LATIN CAPITAL LETTER A WITH BREVE + 0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x0139, //LATIN CAPITAL LETTER L WITH ACUTE + 0x0106, //LATIN CAPITAL LETTER C WITH ACUTE + 0x00C7, //LATIN CAPITAL LETTER C WITH CEDILLA + 0x010C, //LATIN CAPITAL LETTER C WITH CARON + 0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x0118, //LATIN CAPITAL LETTER E WITH OGONEK + 0x00CB, //LATIN CAPITAL LETTER E WITH DIAERESIS + 0x011A, //LATIN CAPITAL LETTER E WITH CARON + 0x00CD, //LATIN CAPITAL LETTER I WITH ACUTE + 0x00CE, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX + 0x010E, //LATIN CAPITAL LETTER D WITH CARON + 0x0110, //LATIN CAPITAL LETTER D WITH STROKE + 0x0143, //LATIN CAPITAL LETTER N WITH ACUTE + 0x0147, //LATIN CAPITAL LETTER N WITH CARON + 0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE + 0x00D4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX + 0x0150, //LATIN CAPITAL LETTER O WITH DOUBLE ACUTE + 0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00D7, //MULTIPLICATION SIGN + 0x0158, //LATIN CAPITAL LETTER R WITH CARON + 0x016E, //LATIN CAPITAL LETTER U WITH RING ABOVE + 0x00DA, //LATIN CAPITAL LETTER U WITH ACUTE + 0x0170, //LATIN CAPITAL LETTER U WITH DOUBLE ACUTE + 0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x00DD, //LATIN CAPITAL LETTER Y WITH ACUTE + 0x0162, //LATIN CAPITAL LETTER T WITH CEDILLA + 0x00DF, //LATIN SMALL LETTER SHARP S + 0x0155, //LATIN SMALL LETTER R WITH ACUTE + 0x00E1, //LATIN SMALL LETTER A WITH ACUTE + 0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x0103, //LATIN SMALL LETTER A WITH BREVE + 0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x013A, //LATIN SMALL LETTER L WITH ACUTE + 0x0107, //LATIN SMALL LETTER C WITH ACUTE + 0x00E7, //LATIN SMALL LETTER C WITH CEDILLA + 0x010D, //LATIN SMALL LETTER C WITH CARON + 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0x0119, //LATIN SMALL LETTER E WITH OGONEK + 0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS + 0x011B, //LATIN SMALL LETTER E WITH CARON + 0x00ED, //LATIN SMALL LETTER I WITH ACUTE + 0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x010F, //LATIN SMALL LETTER D WITH CARON + 0x0111, //LATIN SMALL LETTER D WITH STROKE + 0x0144, //LATIN SMALL LETTER N WITH ACUTE + 0x0148, //LATIN SMALL LETTER N WITH CARON + 0x00F3, //LATIN SMALL LETTER O WITH ACUTE + 0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x0151, //LATIN SMALL LETTER O WITH DOUBLE ACUTE + 0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00F7, //DIVISION SIGN + 0x0159, //LATIN SMALL LETTER R WITH CARON + 0x016F, //LATIN SMALL LETTER U WITH RING ABOVE + 0x00FA, //LATIN SMALL LETTER U WITH ACUTE + 0x0171, //LATIN SMALL LETTER U WITH DOUBLE ACUTE + 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0x00FD, //LATIN SMALL LETTER Y WITH ACUTE + 0x0163, //LATIN SMALL LETTER T WITH CEDILLA + 0x02D9, //DOT ABOVE + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1251.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1251.go new file mode 100644 index 00000000..dc589677 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1251.go @@ -0,0 +1,262 @@ +package cp + +var cp1251 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x0402, //CYRILLIC CAPITAL LETTER DJE + 0x0403, //CYRILLIC CAPITAL LETTER GJE + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0453, //CYRILLIC SMALL LETTER GJE + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0x20AC, //EURO SIGN + 0x2030, //PER MILLE SIGN + 0x0409, //CYRILLIC CAPITAL LETTER LJE + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x040A, //CYRILLIC CAPITAL LETTER NJE + 0x040C, //CYRILLIC CAPITAL LETTER KJE + 0x040B, //CYRILLIC CAPITAL LETTER TSHE + 0x040F, //CYRILLIC CAPITAL LETTER DZHE + 0x0452, //CYRILLIC SMALL LETTER DJE + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0xFFFD, //UNDEFINED + 0x2122, //TRADE MARK SIGN + 0x0459, //CYRILLIC SMALL LETTER LJE + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x045A, //CYRILLIC SMALL LETTER NJE + 0x045C, //CYRILLIC SMALL LETTER KJE + 0x045B, //CYRILLIC SMALL LETTER TSHE + 0x045F, //CYRILLIC SMALL LETTER DZHE + 0x00A0, //NO-BREAK SPACE + 0x040E, //CYRILLIC CAPITAL LETTER SHORT U + 0x045E, //CYRILLIC SMALL LETTER SHORT U + 0x0408, //CYRILLIC CAPITAL LETTER JE + 0x00A4, //CURRENCY SIGN + 0x0490, //CYRILLIC CAPITAL LETTER GHE WITH UPTURN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x0401, //CYRILLIC CAPITAL LETTER IO + 0x00A9, //COPYRIGHT SIGN + 0x0404, //CYRILLIC CAPITAL LETTER UKRAINIAN IE + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x0407, //CYRILLIC CAPITAL LETTER YI + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x0406, //CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I + 0x0456, //CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I + 0x0491, //CYRILLIC SMALL LETTER GHE WITH UPTURN + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x0451, //CYRILLIC SMALL LETTER IO + 0x2116, //NUMERO SIGN + 0x0454, //CYRILLIC SMALL LETTER UKRAINIAN IE + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x0458, //CYRILLIC SMALL LETTER JE + 0x0405, //CYRILLIC CAPITAL LETTER DZE + 0x0455, //CYRILLIC SMALL LETTER DZE + 0x0457, //CYRILLIC SMALL LETTER YI + 0x0410, //CYRILLIC CAPITAL LETTER A + 0x0411, //CYRILLIC CAPITAL LETTER BE + 0x0412, //CYRILLIC CAPITAL LETTER VE + 0x0413, //CYRILLIC CAPITAL LETTER GHE + 0x0414, //CYRILLIC CAPITAL LETTER DE + 0x0415, //CYRILLIC CAPITAL LETTER IE + 0x0416, //CYRILLIC CAPITAL LETTER ZHE + 0x0417, //CYRILLIC CAPITAL LETTER ZE + 0x0418, //CYRILLIC CAPITAL LETTER I + 0x0419, //CYRILLIC CAPITAL LETTER SHORT I + 0x041A, //CYRILLIC CAPITAL LETTER KA + 0x041B, //CYRILLIC CAPITAL LETTER EL + 0x041C, //CYRILLIC CAPITAL LETTER EM + 0x041D, //CYRILLIC CAPITAL LETTER EN + 0x041E, //CYRILLIC CAPITAL LETTER O + 0x041F, //CYRILLIC CAPITAL LETTER PE + 0x0420, //CYRILLIC CAPITAL LETTER ER + 0x0421, //CYRILLIC CAPITAL LETTER ES + 0x0422, //CYRILLIC CAPITAL LETTER TE + 0x0423, //CYRILLIC CAPITAL LETTER U + 0x0424, //CYRILLIC CAPITAL LETTER EF + 0x0425, //CYRILLIC CAPITAL LETTER HA + 0x0426, //CYRILLIC CAPITAL LETTER TSE + 0x0427, //CYRILLIC CAPITAL LETTER CHE + 0x0428, //CYRILLIC CAPITAL LETTER SHA + 0x0429, //CYRILLIC CAPITAL LETTER SHCHA + 0x042A, //CYRILLIC CAPITAL LETTER HARD SIGN + 0x042B, //CYRILLIC CAPITAL LETTER YERU + 0x042C, //CYRILLIC CAPITAL LETTER SOFT SIGN + 0x042D, //CYRILLIC CAPITAL LETTER E + 0x042E, //CYRILLIC CAPITAL LETTER YU + 0x042F, //CYRILLIC CAPITAL LETTER YA + 0x0430, //CYRILLIC SMALL LETTER A + 0x0431, //CYRILLIC SMALL LETTER BE + 0x0432, //CYRILLIC SMALL LETTER VE + 0x0433, //CYRILLIC SMALL LETTER GHE + 0x0434, //CYRILLIC SMALL LETTER DE + 0x0435, //CYRILLIC SMALL LETTER IE + 0x0436, //CYRILLIC SMALL LETTER ZHE + 0x0437, //CYRILLIC SMALL LETTER ZE + 0x0438, //CYRILLIC SMALL LETTER I + 0x0439, //CYRILLIC SMALL LETTER SHORT I + 0x043A, //CYRILLIC SMALL LETTER KA + 0x043B, //CYRILLIC SMALL LETTER EL + 0x043C, //CYRILLIC SMALL LETTER EM + 0x043D, //CYRILLIC SMALL LETTER EN + 0x043E, //CYRILLIC SMALL LETTER O + 0x043F, //CYRILLIC SMALL LETTER PE + 0x0440, //CYRILLIC SMALL LETTER ER + 0x0441, //CYRILLIC SMALL LETTER ES + 0x0442, //CYRILLIC SMALL LETTER TE + 0x0443, //CYRILLIC SMALL LETTER U + 0x0444, //CYRILLIC SMALL LETTER EF + 0x0445, //CYRILLIC SMALL LETTER HA + 0x0446, //CYRILLIC SMALL LETTER TSE + 0x0447, //CYRILLIC SMALL LETTER CHE + 0x0448, //CYRILLIC SMALL LETTER SHA + 0x0449, //CYRILLIC SMALL LETTER SHCHA + 0x044A, //CYRILLIC SMALL LETTER HARD SIGN + 0x044B, //CYRILLIC SMALL LETTER YERU + 0x044C, //CYRILLIC SMALL LETTER SOFT SIGN + 0x044D, //CYRILLIC SMALL LETTER E + 0x044E, //CYRILLIC SMALL LETTER YU + 0x044F, //CYRILLIC SMALL LETTER YA + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1252.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1252.go new file mode 100644 index 00000000..5ae87035 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1252.go @@ -0,0 +1,262 @@ +package cp + +var cp1252 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT + 0x2030, //PER MILLE SIGN + 0x0160, //LATIN CAPITAL LETTER S WITH CARON + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x0152, //LATIN CAPITAL LIGATURE OE + 0xFFFD, //UNDEFINED + 0x017D, //LATIN CAPITAL LETTER Z WITH CARON + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0x02DC, //SMALL TILDE + 0x2122, //TRADE MARK SIGN + 0x0161, //LATIN SMALL LETTER S WITH CARON + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x0153, //LATIN SMALL LIGATURE OE + 0xFFFD, //UNDEFINED + 0x017E, //LATIN SMALL LETTER Z WITH CARON + 0x0178, //LATIN CAPITAL LETTER Y WITH DIAERESIS + 0x00A0, //NO-BREAK SPACE + 0x00A1, //INVERTED EXCLAMATION MARK + 0x00A2, //CENT SIGN + 0x00A3, //POUND SIGN + 0x00A4, //CURRENCY SIGN + 0x00A5, //YEN SIGN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0x00AA, //FEMININE ORDINAL INDICATOR + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x00AF, //MACRON + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00B8, //CEDILLA + 0x00B9, //SUPERSCRIPT ONE + 0x00BA, //MASCULINE ORDINAL INDICATOR + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00BC, //VULGAR FRACTION ONE QUARTER + 0x00BD, //VULGAR FRACTION ONE HALF + 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0x00BF, //INVERTED QUESTION MARK + 0x00C0, //LATIN CAPITAL LETTER A WITH GRAVE + 0x00C1, //LATIN CAPITAL LETTER A WITH ACUTE + 0x00C2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX + 0x00C3, //LATIN CAPITAL LETTER A WITH TILDE + 0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00C5, //LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00C6, //LATIN CAPITAL LETTER AE + 0x00C7, //LATIN CAPITAL LETTER C WITH CEDILLA + 0x00C8, //LATIN CAPITAL LETTER E WITH GRAVE + 0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x00CA, //LATIN CAPITAL LETTER E WITH CIRCUMFLEX + 0x00CB, //LATIN CAPITAL LETTER E WITH DIAERESIS + 0x00CC, //LATIN CAPITAL LETTER I WITH GRAVE + 0x00CD, //LATIN CAPITAL LETTER I WITH ACUTE + 0x00CE, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX + 0x00CF, //LATIN CAPITAL LETTER I WITH DIAERESIS + 0x00D0, //LATIN CAPITAL LETTER ETH + 0x00D1, //LATIN CAPITAL LETTER N WITH TILDE + 0x00D2, //LATIN CAPITAL LETTER O WITH GRAVE + 0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE + 0x00D4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX + 0x00D5, //LATIN CAPITAL LETTER O WITH TILDE + 0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00D7, //MULTIPLICATION SIGN + 0x00D8, //LATIN CAPITAL LETTER O WITH STROKE + 0x00D9, //LATIN CAPITAL LETTER U WITH GRAVE + 0x00DA, //LATIN CAPITAL LETTER U WITH ACUTE + 0x00DB, //LATIN CAPITAL LETTER U WITH CIRCUMFLEX + 0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x00DD, //LATIN CAPITAL LETTER Y WITH ACUTE + 0x00DE, //LATIN CAPITAL LETTER THORN + 0x00DF, //LATIN SMALL LETTER SHARP S + 0x00E0, //LATIN SMALL LETTER A WITH GRAVE + 0x00E1, //LATIN SMALL LETTER A WITH ACUTE + 0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x00E3, //LATIN SMALL LETTER A WITH TILDE + 0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x00E5, //LATIN SMALL LETTER A WITH RING ABOVE + 0x00E6, //LATIN SMALL LETTER AE + 0x00E7, //LATIN SMALL LETTER C WITH CEDILLA + 0x00E8, //LATIN SMALL LETTER E WITH GRAVE + 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS + 0x00EC, //LATIN SMALL LETTER I WITH GRAVE + 0x00ED, //LATIN SMALL LETTER I WITH ACUTE + 0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00EF, //LATIN SMALL LETTER I WITH DIAERESIS + 0x00F0, //LATIN SMALL LETTER ETH + 0x00F1, //LATIN SMALL LETTER N WITH TILDE + 0x00F2, //LATIN SMALL LETTER O WITH GRAVE + 0x00F3, //LATIN SMALL LETTER O WITH ACUTE + 0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x00F5, //LATIN SMALL LETTER O WITH TILDE + 0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00F7, //DIVISION SIGN + 0x00F8, //LATIN SMALL LETTER O WITH STROKE + 0x00F9, //LATIN SMALL LETTER U WITH GRAVE + 0x00FA, //LATIN SMALL LETTER U WITH ACUTE + 0x00FB, //LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0x00FD, //LATIN SMALL LETTER Y WITH ACUTE + 0x00FE, //LATIN SMALL LETTER THORN + 0x00FF, //LATIN SMALL LETTER Y WITH DIAERESIS + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1253.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1253.go new file mode 100644 index 00000000..52c8e07a --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1253.go @@ -0,0 +1,262 @@ +package cp + +var cp1253 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0xFFFD, //UNDEFINED + 0x2030, //PER MILLE SIGN + 0xFFFD, //UNDEFINED + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0xFFFD, //UNDEFINED + 0x2122, //TRADE MARK SIGN + 0xFFFD, //UNDEFINED + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x00A0, //NO-BREAK SPACE + 0x0385, //GREEK DIALYTIKA TONOS + 0x0386, //GREEK CAPITAL LETTER ALPHA WITH TONOS + 0x00A3, //POUND SIGN + 0x00A4, //CURRENCY SIGN + 0x00A5, //YEN SIGN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0xFFFD, //UNDEFINED + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x2015, //HORIZONTAL BAR + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x0384, //GREEK TONOS + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x0388, //GREEK CAPITAL LETTER EPSILON WITH TONOS + 0x0389, //GREEK CAPITAL LETTER ETA WITH TONOS + 0x038A, //GREEK CAPITAL LETTER IOTA WITH TONOS + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x038C, //GREEK CAPITAL LETTER OMICRON WITH TONOS + 0x00BD, //VULGAR FRACTION ONE HALF + 0x038E, //GREEK CAPITAL LETTER UPSILON WITH TONOS + 0x038F, //GREEK CAPITAL LETTER OMEGA WITH TONOS + 0x0390, //GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS + 0x0391, //GREEK CAPITAL LETTER ALPHA + 0x0392, //GREEK CAPITAL LETTER BETA + 0x0393, //GREEK CAPITAL LETTER GAMMA + 0x0394, //GREEK CAPITAL LETTER DELTA + 0x0395, //GREEK CAPITAL LETTER EPSILON + 0x0396, //GREEK CAPITAL LETTER ZETA + 0x0397, //GREEK CAPITAL LETTER ETA + 0x0398, //GREEK CAPITAL LETTER THETA + 0x0399, //GREEK CAPITAL LETTER IOTA + 0x039A, //GREEK CAPITAL LETTER KAPPA + 0x039B, //GREEK CAPITAL LETTER LAMDA + 0x039C, //GREEK CAPITAL LETTER MU + 0x039D, //GREEK CAPITAL LETTER NU + 0x039E, //GREEK CAPITAL LETTER XI + 0x039F, //GREEK CAPITAL LETTER OMICRON + 0x03A0, //GREEK CAPITAL LETTER PI + 0x03A1, //GREEK CAPITAL LETTER RHO + 0xFFFD, //UNDEFINED + 0x03A3, //GREEK CAPITAL LETTER SIGMA + 0x03A4, //GREEK CAPITAL LETTER TAU + 0x03A5, //GREEK CAPITAL LETTER UPSILON + 0x03A6, //GREEK CAPITAL LETTER PHI + 0x03A7, //GREEK CAPITAL LETTER CHI + 0x03A8, //GREEK CAPITAL LETTER PSI + 0x03A9, //GREEK CAPITAL LETTER OMEGA + 0x03AA, //GREEK CAPITAL LETTER IOTA WITH DIALYTIKA + 0x03AB, //GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA + 0x03AC, //GREEK SMALL LETTER ALPHA WITH TONOS + 0x03AD, //GREEK SMALL LETTER EPSILON WITH TONOS + 0x03AE, //GREEK SMALL LETTER ETA WITH TONOS + 0x03AF, //GREEK SMALL LETTER IOTA WITH TONOS + 0x03B0, //GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS + 0x03B1, //GREEK SMALL LETTER ALPHA + 0x03B2, //GREEK SMALL LETTER BETA + 0x03B3, //GREEK SMALL LETTER GAMMA + 0x03B4, //GREEK SMALL LETTER DELTA + 0x03B5, //GREEK SMALL LETTER EPSILON + 0x03B6, //GREEK SMALL LETTER ZETA + 0x03B7, //GREEK SMALL LETTER ETA + 0x03B8, //GREEK SMALL LETTER THETA + 0x03B9, //GREEK SMALL LETTER IOTA + 0x03BA, //GREEK SMALL LETTER KAPPA + 0x03BB, //GREEK SMALL LETTER LAMDA + 0x03BC, //GREEK SMALL LETTER MU + 0x03BD, //GREEK SMALL LETTER NU + 0x03BE, //GREEK SMALL LETTER XI + 0x03BF, //GREEK SMALL LETTER OMICRON + 0x03C0, //GREEK SMALL LETTER PI + 0x03C1, //GREEK SMALL LETTER RHO + 0x03C2, //GREEK SMALL LETTER FINAL SIGMA + 0x03C3, //GREEK SMALL LETTER SIGMA + 0x03C4, //GREEK SMALL LETTER TAU + 0x03C5, //GREEK SMALL LETTER UPSILON + 0x03C6, //GREEK SMALL LETTER PHI + 0x03C7, //GREEK SMALL LETTER CHI + 0x03C8, //GREEK SMALL LETTER PSI + 0x03C9, //GREEK SMALL LETTER OMEGA + 0x03CA, //GREEK SMALL LETTER IOTA WITH DIALYTIKA + 0x03CB, //GREEK SMALL LETTER UPSILON WITH DIALYTIKA + 0x03CC, //GREEK SMALL LETTER OMICRON WITH TONOS + 0x03CD, //GREEK SMALL LETTER UPSILON WITH TONOS + 0x03CE, //GREEK SMALL LETTER OMEGA WITH TONOS + 0xFFFD, //UNDEFINED + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1254.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1254.go new file mode 100644 index 00000000..5d8864a5 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1254.go @@ -0,0 +1,262 @@ +package cp + +var cp1254 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT + 0x2030, //PER MILLE SIGN + 0x0160, //LATIN CAPITAL LETTER S WITH CARON + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x0152, //LATIN CAPITAL LIGATURE OE + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0x02DC, //SMALL TILDE + 0x2122, //TRADE MARK SIGN + 0x0161, //LATIN SMALL LETTER S WITH CARON + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x0153, //LATIN SMALL LIGATURE OE + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x0178, //LATIN CAPITAL LETTER Y WITH DIAERESIS + 0x00A0, //NO-BREAK SPACE + 0x00A1, //INVERTED EXCLAMATION MARK + 0x00A2, //CENT SIGN + 0x00A3, //POUND SIGN + 0x00A4, //CURRENCY SIGN + 0x00A5, //YEN SIGN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0x00AA, //FEMININE ORDINAL INDICATOR + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x00AF, //MACRON + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00B8, //CEDILLA + 0x00B9, //SUPERSCRIPT ONE + 0x00BA, //MASCULINE ORDINAL INDICATOR + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00BC, //VULGAR FRACTION ONE QUARTER + 0x00BD, //VULGAR FRACTION ONE HALF + 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0x00BF, //INVERTED QUESTION MARK + 0x00C0, //LATIN CAPITAL LETTER A WITH GRAVE + 0x00C1, //LATIN CAPITAL LETTER A WITH ACUTE + 0x00C2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX + 0x00C3, //LATIN CAPITAL LETTER A WITH TILDE + 0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00C5, //LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00C6, //LATIN CAPITAL LETTER AE + 0x00C7, //LATIN CAPITAL LETTER C WITH CEDILLA + 0x00C8, //LATIN CAPITAL LETTER E WITH GRAVE + 0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x00CA, //LATIN CAPITAL LETTER E WITH CIRCUMFLEX + 0x00CB, //LATIN CAPITAL LETTER E WITH DIAERESIS + 0x00CC, //LATIN CAPITAL LETTER I WITH GRAVE + 0x00CD, //LATIN CAPITAL LETTER I WITH ACUTE + 0x00CE, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX + 0x00CF, //LATIN CAPITAL LETTER I WITH DIAERESIS + 0x011E, //LATIN CAPITAL LETTER G WITH BREVE + 0x00D1, //LATIN CAPITAL LETTER N WITH TILDE + 0x00D2, //LATIN CAPITAL LETTER O WITH GRAVE + 0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE + 0x00D4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX + 0x00D5, //LATIN CAPITAL LETTER O WITH TILDE + 0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00D7, //MULTIPLICATION SIGN + 0x00D8, //LATIN CAPITAL LETTER O WITH STROKE + 0x00D9, //LATIN CAPITAL LETTER U WITH GRAVE + 0x00DA, //LATIN CAPITAL LETTER U WITH ACUTE + 0x00DB, //LATIN CAPITAL LETTER U WITH CIRCUMFLEX + 0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x0130, //LATIN CAPITAL LETTER I WITH DOT ABOVE + 0x015E, //LATIN CAPITAL LETTER S WITH CEDILLA + 0x00DF, //LATIN SMALL LETTER SHARP S + 0x00E0, //LATIN SMALL LETTER A WITH GRAVE + 0x00E1, //LATIN SMALL LETTER A WITH ACUTE + 0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x00E3, //LATIN SMALL LETTER A WITH TILDE + 0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x00E5, //LATIN SMALL LETTER A WITH RING ABOVE + 0x00E6, //LATIN SMALL LETTER AE + 0x00E7, //LATIN SMALL LETTER C WITH CEDILLA + 0x00E8, //LATIN SMALL LETTER E WITH GRAVE + 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS + 0x00EC, //LATIN SMALL LETTER I WITH GRAVE + 0x00ED, //LATIN SMALL LETTER I WITH ACUTE + 0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00EF, //LATIN SMALL LETTER I WITH DIAERESIS + 0x011F, //LATIN SMALL LETTER G WITH BREVE + 0x00F1, //LATIN SMALL LETTER N WITH TILDE + 0x00F2, //LATIN SMALL LETTER O WITH GRAVE + 0x00F3, //LATIN SMALL LETTER O WITH ACUTE + 0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x00F5, //LATIN SMALL LETTER O WITH TILDE + 0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00F7, //DIVISION SIGN + 0x00F8, //LATIN SMALL LETTER O WITH STROKE + 0x00F9, //LATIN SMALL LETTER U WITH GRAVE + 0x00FA, //LATIN SMALL LETTER U WITH ACUTE + 0x00FB, //LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0x0131, //LATIN SMALL LETTER DOTLESS I + 0x015F, //LATIN SMALL LETTER S WITH CEDILLA + 0x00FF, //LATIN SMALL LETTER Y WITH DIAERESIS + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1255.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1255.go new file mode 100644 index 00000000..60619895 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1255.go @@ -0,0 +1,262 @@ +package cp + +var cp1255 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT + 0x2030, //PER MILLE SIGN + 0xFFFD, //UNDEFINED + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0x02DC, //SMALL TILDE + 0x2122, //TRADE MARK SIGN + 0xFFFD, //UNDEFINED + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x00A0, //NO-BREAK SPACE + 0x00A1, //INVERTED EXCLAMATION MARK + 0x00A2, //CENT SIGN + 0x00A3, //POUND SIGN + 0x20AA, //NEW SHEQEL SIGN + 0x00A5, //YEN SIGN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0x00D7, //MULTIPLICATION SIGN + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x00AF, //MACRON + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00B8, //CEDILLA + 0x00B9, //SUPERSCRIPT ONE + 0x00F7, //DIVISION SIGN + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00BC, //VULGAR FRACTION ONE QUARTER + 0x00BD, //VULGAR FRACTION ONE HALF + 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0x00BF, //INVERTED QUESTION MARK + 0x05B0, //HEBREW POINT SHEVA + 0x05B1, //HEBREW POINT HATAF SEGOL + 0x05B2, //HEBREW POINT HATAF PATAH + 0x05B3, //HEBREW POINT HATAF QAMATS + 0x05B4, //HEBREW POINT HIRIQ + 0x05B5, //HEBREW POINT TSERE + 0x05B6, //HEBREW POINT SEGOL + 0x05B7, //HEBREW POINT PATAH + 0x05B8, //HEBREW POINT QAMATS + 0x05B9, //HEBREW POINT HOLAM + 0xFFFD, //UNDEFINED + 0x05BB, //HEBREW POINT QUBUTS + 0x05BC, //HEBREW POINT DAGESH OR MAPIQ + 0x05BD, //HEBREW POINT METEG + 0x05BE, //HEBREW PUNCTUATION MAQAF + 0x05BF, //HEBREW POINT RAFE + 0x05C0, //HEBREW PUNCTUATION PASEQ + 0x05C1, //HEBREW POINT SHIN DOT + 0x05C2, //HEBREW POINT SIN DOT + 0x05C3, //HEBREW PUNCTUATION SOF PASUQ + 0x05F0, //HEBREW LIGATURE YIDDISH DOUBLE VAV + 0x05F1, //HEBREW LIGATURE YIDDISH VAV YOD + 0x05F2, //HEBREW LIGATURE YIDDISH DOUBLE YOD + 0x05F3, //HEBREW PUNCTUATION GERESH + 0x05F4, //HEBREW PUNCTUATION GERSHAYIM + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x05D0, //HEBREW LETTER ALEF + 0x05D1, //HEBREW LETTER BET + 0x05D2, //HEBREW LETTER GIMEL + 0x05D3, //HEBREW LETTER DALET + 0x05D4, //HEBREW LETTER HE + 0x05D5, //HEBREW LETTER VAV + 0x05D6, //HEBREW LETTER ZAYIN + 0x05D7, //HEBREW LETTER HET + 0x05D8, //HEBREW LETTER TET + 0x05D9, //HEBREW LETTER YOD + 0x05DA, //HEBREW LETTER FINAL KAF + 0x05DB, //HEBREW LETTER KAF + 0x05DC, //HEBREW LETTER LAMED + 0x05DD, //HEBREW LETTER FINAL MEM + 0x05DE, //HEBREW LETTER MEM + 0x05DF, //HEBREW LETTER FINAL NUN + 0x05E0, //HEBREW LETTER NUN + 0x05E1, //HEBREW LETTER SAMEKH + 0x05E2, //HEBREW LETTER AYIN + 0x05E3, //HEBREW LETTER FINAL PE + 0x05E4, //HEBREW LETTER PE + 0x05E5, //HEBREW LETTER FINAL TSADI + 0x05E6, //HEBREW LETTER TSADI + 0x05E7, //HEBREW LETTER QOF + 0x05E8, //HEBREW LETTER RESH + 0x05E9, //HEBREW LETTER SHIN + 0x05EA, //HEBREW LETTER TAV + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x200E, //LEFT-TO-RIGHT MARK + 0x200F, //RIGHT-TO-LEFT MARK + 0xFFFD, //UNDEFINED + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1256.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1256.go new file mode 100644 index 00000000..ffd04b3e --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1256.go @@ -0,0 +1,262 @@ +package cp + +var cp1256 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0x067E, //ARABIC LETTER PEH + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT + 0x2030, //PER MILLE SIGN + 0x0679, //ARABIC LETTER TTEH + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x0152, //LATIN CAPITAL LIGATURE OE + 0x0686, //ARABIC LETTER TCHEH + 0x0698, //ARABIC LETTER JEH + 0x0688, //ARABIC LETTER DDAL + 0x06AF, //ARABIC LETTER GAF + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0x06A9, //ARABIC LETTER KEHEH + 0x2122, //TRADE MARK SIGN + 0x0691, //ARABIC LETTER RREH + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x0153, //LATIN SMALL LIGATURE OE + 0x200C, //ZERO WIDTH NON-JOINER + 0x200D, //ZERO WIDTH JOINER + 0x06BA, //ARABIC LETTER NOON GHUNNA + 0x00A0, //NO-BREAK SPACE + 0x060C, //ARABIC COMMA + 0x00A2, //CENT SIGN + 0x00A3, //POUND SIGN + 0x00A4, //CURRENCY SIGN + 0x00A5, //YEN SIGN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0x06BE, //ARABIC LETTER HEH DOACHASHMEE + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x00AF, //MACRON + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00B8, //CEDILLA + 0x00B9, //SUPERSCRIPT ONE + 0x061B, //ARABIC SEMICOLON + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00BC, //VULGAR FRACTION ONE QUARTER + 0x00BD, //VULGAR FRACTION ONE HALF + 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0x061F, //ARABIC QUESTION MARK + 0x06C1, //ARABIC LETTER HEH GOAL + 0x0621, //ARABIC LETTER HAMZA + 0x0622, //ARABIC LETTER ALEF WITH MADDA ABOVE + 0x0623, //ARABIC LETTER ALEF WITH HAMZA ABOVE + 0x0624, //ARABIC LETTER WAW WITH HAMZA ABOVE + 0x0625, //ARABIC LETTER ALEF WITH HAMZA BELOW + 0x0626, //ARABIC LETTER YEH WITH HAMZA ABOVE + 0x0627, //ARABIC LETTER ALEF + 0x0628, //ARABIC LETTER BEH + 0x0629, //ARABIC LETTER TEH MARBUTA + 0x062A, //ARABIC LETTER TEH + 0x062B, //ARABIC LETTER THEH + 0x062C, //ARABIC LETTER JEEM + 0x062D, //ARABIC LETTER HAH + 0x062E, //ARABIC LETTER KHAH + 0x062F, //ARABIC LETTER DAL + 0x0630, //ARABIC LETTER THAL + 0x0631, //ARABIC LETTER REH + 0x0632, //ARABIC LETTER ZAIN + 0x0633, //ARABIC LETTER SEEN + 0x0634, //ARABIC LETTER SHEEN + 0x0635, //ARABIC LETTER SAD + 0x0636, //ARABIC LETTER DAD + 0x00D7, //MULTIPLICATION SIGN + 0x0637, //ARABIC LETTER TAH + 0x0638, //ARABIC LETTER ZAH + 0x0639, //ARABIC LETTER AIN + 0x063A, //ARABIC LETTER GHAIN + 0x0640, //ARABIC TATWEEL + 0x0641, //ARABIC LETTER FEH + 0x0642, //ARABIC LETTER QAF + 0x0643, //ARABIC LETTER KAF + 0x00E0, //LATIN SMALL LETTER A WITH GRAVE + 0x0644, //ARABIC LETTER LAM + 0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x0645, //ARABIC LETTER MEEM + 0x0646, //ARABIC LETTER NOON + 0x0647, //ARABIC LETTER HEH + 0x0648, //ARABIC LETTER WAW + 0x00E7, //LATIN SMALL LETTER C WITH CEDILLA + 0x00E8, //LATIN SMALL LETTER E WITH GRAVE + 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS + 0x0649, //ARABIC LETTER ALEF MAKSURA + 0x064A, //ARABIC LETTER YEH + 0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00EF, //LATIN SMALL LETTER I WITH DIAERESIS + 0x064B, //ARABIC FATHATAN + 0x064C, //ARABIC DAMMATAN + 0x064D, //ARABIC KASRATAN + 0x064E, //ARABIC FATHA + 0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x064F, //ARABIC DAMMA + 0x0650, //ARABIC KASRA + 0x00F7, //DIVISION SIGN + 0x0651, //ARABIC SHADDA + 0x00F9, //LATIN SMALL LETTER U WITH GRAVE + 0x0652, //ARABIC SUKUN + 0x00FB, //LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0x200E, //LEFT-TO-RIGHT MARK + 0x200F, //RIGHT-TO-LEFT MARK + 0x06D2, //ARABIC LETTER YEH BARREE + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1257.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1257.go new file mode 100644 index 00000000..492da72e --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1257.go @@ -0,0 +1,262 @@ +package cp + +var cp1257 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0xFFFD, //UNDEFINED + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0xFFFD, //UNDEFINED + 0x2030, //PER MILLE SIGN + 0xFFFD, //UNDEFINED + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0xFFFD, //UNDEFINED + 0x00A8, //DIAERESIS + 0x02C7, //CARON + 0x00B8, //CEDILLA + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0xFFFD, //UNDEFINED + 0x2122, //TRADE MARK SIGN + 0xFFFD, //UNDEFINED + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0xFFFD, //UNDEFINED + 0x00AF, //MACRON + 0x02DB, //OGONEK + 0xFFFD, //UNDEFINED + 0x00A0, //NO-BREAK SPACE + 0xFFFD, //UNDEFINED + 0x00A2, //CENT SIGN + 0x00A3, //POUND SIGN + 0x00A4, //CURRENCY SIGN + 0xFFFD, //UNDEFINED + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00D8, //LATIN CAPITAL LETTER O WITH STROKE + 0x00A9, //COPYRIGHT SIGN + 0x0156, //LATIN CAPITAL LETTER R WITH CEDILLA + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x00C6, //LATIN CAPITAL LETTER AE + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00F8, //LATIN SMALL LETTER O WITH STROKE + 0x00B9, //SUPERSCRIPT ONE + 0x0157, //LATIN SMALL LETTER R WITH CEDILLA + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00BC, //VULGAR FRACTION ONE QUARTER + 0x00BD, //VULGAR FRACTION ONE HALF + 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0x00E6, //LATIN SMALL LETTER AE + 0x0104, //LATIN CAPITAL LETTER A WITH OGONEK + 0x012E, //LATIN CAPITAL LETTER I WITH OGONEK + 0x0100, //LATIN CAPITAL LETTER A WITH MACRON + 0x0106, //LATIN CAPITAL LETTER C WITH ACUTE + 0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00C5, //LATIN CAPITAL LETTER A WITH RING ABOVE + 0x0118, //LATIN CAPITAL LETTER E WITH OGONEK + 0x0112, //LATIN CAPITAL LETTER E WITH MACRON + 0x010C, //LATIN CAPITAL LETTER C WITH CARON + 0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x0179, //LATIN CAPITAL LETTER Z WITH ACUTE + 0x0116, //LATIN CAPITAL LETTER E WITH DOT ABOVE + 0x0122, //LATIN CAPITAL LETTER G WITH CEDILLA + 0x0136, //LATIN CAPITAL LETTER K WITH CEDILLA + 0x012A, //LATIN CAPITAL LETTER I WITH MACRON + 0x013B, //LATIN CAPITAL LETTER L WITH CEDILLA + 0x0160, //LATIN CAPITAL LETTER S WITH CARON + 0x0143, //LATIN CAPITAL LETTER N WITH ACUTE + 0x0145, //LATIN CAPITAL LETTER N WITH CEDILLA + 0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE + 0x014C, //LATIN CAPITAL LETTER O WITH MACRON + 0x00D5, //LATIN CAPITAL LETTER O WITH TILDE + 0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00D7, //MULTIPLICATION SIGN + 0x0172, //LATIN CAPITAL LETTER U WITH OGONEK + 0x0141, //LATIN CAPITAL LETTER L WITH STROKE + 0x015A, //LATIN CAPITAL LETTER S WITH ACUTE + 0x016A, //LATIN CAPITAL LETTER U WITH MACRON + 0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x017B, //LATIN CAPITAL LETTER Z WITH DOT ABOVE + 0x017D, //LATIN CAPITAL LETTER Z WITH CARON + 0x00DF, //LATIN SMALL LETTER SHARP S + 0x0105, //LATIN SMALL LETTER A WITH OGONEK + 0x012F, //LATIN SMALL LETTER I WITH OGONEK + 0x0101, //LATIN SMALL LETTER A WITH MACRON + 0x0107, //LATIN SMALL LETTER C WITH ACUTE + 0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x00E5, //LATIN SMALL LETTER A WITH RING ABOVE + 0x0119, //LATIN SMALL LETTER E WITH OGONEK + 0x0113, //LATIN SMALL LETTER E WITH MACRON + 0x010D, //LATIN SMALL LETTER C WITH CARON + 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0x017A, //LATIN SMALL LETTER Z WITH ACUTE + 0x0117, //LATIN SMALL LETTER E WITH DOT ABOVE + 0x0123, //LATIN SMALL LETTER G WITH CEDILLA + 0x0137, //LATIN SMALL LETTER K WITH CEDILLA + 0x012B, //LATIN SMALL LETTER I WITH MACRON + 0x013C, //LATIN SMALL LETTER L WITH CEDILLA + 0x0161, //LATIN SMALL LETTER S WITH CARON + 0x0144, //LATIN SMALL LETTER N WITH ACUTE + 0x0146, //LATIN SMALL LETTER N WITH CEDILLA + 0x00F3, //LATIN SMALL LETTER O WITH ACUTE + 0x014D, //LATIN SMALL LETTER O WITH MACRON + 0x00F5, //LATIN SMALL LETTER O WITH TILDE + 0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00F7, //DIVISION SIGN + 0x0173, //LATIN SMALL LETTER U WITH OGONEK + 0x0142, //LATIN SMALL LETTER L WITH STROKE + 0x015B, //LATIN SMALL LETTER S WITH ACUTE + 0x016B, //LATIN SMALL LETTER U WITH MACRON + 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0x017C, //LATIN SMALL LETTER Z WITH DOT ABOVE + 0x017E, //LATIN SMALL LETTER Z WITH CARON + 0x02D9, //DOT ABOVE + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1258.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1258.go new file mode 100644 index 00000000..80be52c5 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1258.go @@ -0,0 +1,262 @@ +package cp + +var cp1258 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0x201A, //SINGLE LOW-9 QUOTATION MARK + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x201E, //DOUBLE LOW-9 QUOTATION MARK + 0x2026, //HORIZONTAL ELLIPSIS + 0x2020, //DAGGER + 0x2021, //DOUBLE DAGGER + 0x02C6, //MODIFIER LETTER CIRCUMFLEX ACCENT + 0x2030, //PER MILLE SIGN + 0xFFFD, //UNDEFINED + 0x2039, //SINGLE LEFT-POINTING ANGLE QUOTATION MARK + 0x0152, //LATIN CAPITAL LIGATURE OE + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0x02DC, //SMALL TILDE + 0x2122, //TRADE MARK SIGN + 0xFFFD, //UNDEFINED + 0x203A, //SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + 0x0153, //LATIN SMALL LIGATURE OE + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x0178, //LATIN CAPITAL LETTER Y WITH DIAERESIS + 0x00A0, //NO-BREAK SPACE + 0x00A1, //INVERTED EXCLAMATION MARK + 0x00A2, //CENT SIGN + 0x00A3, //POUND SIGN + 0x00A4, //CURRENCY SIGN + 0x00A5, //YEN SIGN + 0x00A6, //BROKEN BAR + 0x00A7, //SECTION SIGN + 0x00A8, //DIAERESIS + 0x00A9, //COPYRIGHT SIGN + 0x00AA, //FEMININE ORDINAL INDICATOR + 0x00AB, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00AC, //NOT SIGN + 0x00AD, //SOFT HYPHEN + 0x00AE, //REGISTERED SIGN + 0x00AF, //MACRON + 0x00B0, //DEGREE SIGN + 0x00B1, //PLUS-MINUS SIGN + 0x00B2, //SUPERSCRIPT TWO + 0x00B3, //SUPERSCRIPT THREE + 0x00B4, //ACUTE ACCENT + 0x00B5, //MICRO SIGN + 0x00B6, //PILCROW SIGN + 0x00B7, //MIDDLE DOT + 0x00B8, //CEDILLA + 0x00B9, //SUPERSCRIPT ONE + 0x00BA, //MASCULINE ORDINAL INDICATOR + 0x00BB, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00BC, //VULGAR FRACTION ONE QUARTER + 0x00BD, //VULGAR FRACTION ONE HALF + 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0x00BF, //INVERTED QUESTION MARK + 0x00C0, //LATIN CAPITAL LETTER A WITH GRAVE + 0x00C1, //LATIN CAPITAL LETTER A WITH ACUTE + 0x00C2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX + 0x0102, //LATIN CAPITAL LETTER A WITH BREVE + 0x00C4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00C5, //LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00C6, //LATIN CAPITAL LETTER AE + 0x00C7, //LATIN CAPITAL LETTER C WITH CEDILLA + 0x00C8, //LATIN CAPITAL LETTER E WITH GRAVE + 0x00C9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x00CA, //LATIN CAPITAL LETTER E WITH CIRCUMFLEX + 0x00CB, //LATIN CAPITAL LETTER E WITH DIAERESIS + 0x0300, //COMBINING GRAVE ACCENT + 0x00CD, //LATIN CAPITAL LETTER I WITH ACUTE + 0x00CE, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX + 0x00CF, //LATIN CAPITAL LETTER I WITH DIAERESIS + 0x0110, //LATIN CAPITAL LETTER D WITH STROKE + 0x00D1, //LATIN CAPITAL LETTER N WITH TILDE + 0x0309, //COMBINING HOOK ABOVE + 0x00D3, //LATIN CAPITAL LETTER O WITH ACUTE + 0x00D4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX + 0x01A0, //LATIN CAPITAL LETTER O WITH HORN + 0x00D6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00D7, //MULTIPLICATION SIGN + 0x00D8, //LATIN CAPITAL LETTER O WITH STROKE + 0x00D9, //LATIN CAPITAL LETTER U WITH GRAVE + 0x00DA, //LATIN CAPITAL LETTER U WITH ACUTE + 0x00DB, //LATIN CAPITAL LETTER U WITH CIRCUMFLEX + 0x00DC, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x01AF, //LATIN CAPITAL LETTER U WITH HORN + 0x0303, //COMBINING TILDE + 0x00DF, //LATIN SMALL LETTER SHARP S + 0x00E0, //LATIN SMALL LETTER A WITH GRAVE + 0x00E1, //LATIN SMALL LETTER A WITH ACUTE + 0x00E2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x0103, //LATIN SMALL LETTER A WITH BREVE + 0x00E4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x00E5, //LATIN SMALL LETTER A WITH RING ABOVE + 0x00E6, //LATIN SMALL LETTER AE + 0x00E7, //LATIN SMALL LETTER C WITH CEDILLA + 0x00E8, //LATIN SMALL LETTER E WITH GRAVE + 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00EB, //LATIN SMALL LETTER E WITH DIAERESIS + 0x0301, //COMBINING ACUTE ACCENT + 0x00ED, //LATIN SMALL LETTER I WITH ACUTE + 0x00EE, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00EF, //LATIN SMALL LETTER I WITH DIAERESIS + 0x0111, //LATIN SMALL LETTER D WITH STROKE + 0x00F1, //LATIN SMALL LETTER N WITH TILDE + 0x0323, //COMBINING DOT BELOW + 0x00F3, //LATIN SMALL LETTER O WITH ACUTE + 0x00F4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x01A1, //LATIN SMALL LETTER O WITH HORN + 0x00F6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00F7, //DIVISION SIGN + 0x00F8, //LATIN SMALL LETTER O WITH STROKE + 0x00F9, //LATIN SMALL LETTER U WITH GRAVE + 0x00FA, //LATIN SMALL LETTER U WITH ACUTE + 0x00FB, //LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0x01B0, //LATIN SMALL LETTER U WITH HORN + 0x20AB, //DONG SIGN + 0x00FF, //LATIN SMALL LETTER Y WITH DIAERESIS + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp437.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp437.go new file mode 100644 index 00000000..76dedfb8 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp437.go @@ -0,0 +1,262 @@ +package cp + +var cp437 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000a, //LINE FEED + 0x000b, //VERTICAL TABULATION + 0x000c, //FORM FEED + 0x000d, //CARRIAGE RETURN + 0x000e, //SHIFT OUT + 0x000f, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001a, //SUBSTITUTE + 0x001b, //ESCAPE + 0x001c, //FILE SEPARATOR + 0x001d, //GROUP SEPARATOR + 0x001e, //RECORD SEPARATOR + 0x001f, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002a, //ASTERISK + 0x002b, //PLUS SIGN + 0x002c, //COMMA + 0x002d, //HYPHEN-MINUS + 0x002e, //FULL STOP + 0x002f, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003a, //COLON + 0x003b, //SEMICOLON + 0x003c, //LESS-THAN SIGN + 0x003d, //EQUALS SIGN + 0x003e, //GREATER-THAN SIGN + 0x003f, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004a, //LATIN CAPITAL LETTER J + 0x004b, //LATIN CAPITAL LETTER K + 0x004c, //LATIN CAPITAL LETTER L + 0x004d, //LATIN CAPITAL LETTER M + 0x004e, //LATIN CAPITAL LETTER N + 0x004f, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005a, //LATIN CAPITAL LETTER Z + 0x005b, //LEFT SQUARE BRACKET + 0x005c, //REVERSE SOLIDUS + 0x005d, //RIGHT SQUARE BRACKET + 0x005e, //CIRCUMFLEX ACCENT + 0x005f, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006a, //LATIN SMALL LETTER J + 0x006b, //LATIN SMALL LETTER K + 0x006c, //LATIN SMALL LETTER L + 0x006d, //LATIN SMALL LETTER M + 0x006e, //LATIN SMALL LETTER N + 0x006f, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007a, //LATIN SMALL LETTER Z + 0x007b, //LEFT CURLY BRACKET + 0x007c, //VERTICAL LINE + 0x007d, //RIGHT CURLY BRACKET + 0x007e, //TILDE + 0x007f, //DELETE + 0x00c7, //LATIN CAPITAL LETTER C WITH CEDILLA + 0x00fc, //LATIN SMALL LETTER U WITH DIAERESIS + 0x00e9, //LATIN SMALL LETTER E WITH ACUTE + 0x00e2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x00e4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x00e0, //LATIN SMALL LETTER A WITH GRAVE + 0x00e5, //LATIN SMALL LETTER A WITH RING ABOVE + 0x00e7, //LATIN SMALL LETTER C WITH CEDILLA + 0x00ea, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00eb, //LATIN SMALL LETTER E WITH DIAERESIS + 0x00e8, //LATIN SMALL LETTER E WITH GRAVE + 0x00ef, //LATIN SMALL LETTER I WITH DIAERESIS + 0x00ee, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00ec, //LATIN SMALL LETTER I WITH GRAVE + 0x00c4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00c5, //LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00c9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x00e6, //LATIN SMALL LIGATURE AE + 0x00c6, //LATIN CAPITAL LIGATURE AE + 0x00f4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x00f6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00f2, //LATIN SMALL LETTER O WITH GRAVE + 0x00fb, //LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00f9, //LATIN SMALL LETTER U WITH GRAVE + 0x00ff, //LATIN SMALL LETTER Y WITH DIAERESIS + 0x00d6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00dc, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x00a2, //CENT SIGN + 0x00a3, //POUND SIGN + 0x00a5, //YEN SIGN + 0x20a7, //PESETA SIGN + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x00e1, //LATIN SMALL LETTER A WITH ACUTE + 0x00ed, //LATIN SMALL LETTER I WITH ACUTE + 0x00f3, //LATIN SMALL LETTER O WITH ACUTE + 0x00fa, //LATIN SMALL LETTER U WITH ACUTE + 0x00f1, //LATIN SMALL LETTER N WITH TILDE + 0x00d1, //LATIN CAPITAL LETTER N WITH TILDE + 0x00aa, //FEMININE ORDINAL INDICATOR + 0x00ba, //MASCULINE ORDINAL INDICATOR + 0x00bf, //INVERTED QUESTION MARK + 0x2310, //REVERSED NOT SIGN + 0x00ac, //NOT SIGN + 0x00bd, //VULGAR FRACTION ONE HALF + 0x00bc, //VULGAR FRACTION ONE QUARTER + 0x00a1, //INVERTED EXCLAMATION MARK + 0x00ab, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00bb, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x2591, //LIGHT SHADE + 0x2592, //MEDIUM SHADE + 0x2593, //DARK SHADE + 0x2502, //BOX DRAWINGS LIGHT VERTICAL + 0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0x2561, //BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + 0x2562, //BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE + 0x2556, //BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE + 0x2555, //BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE + 0x2563, //BOX DRAWINGS DOUBLE VERTICAL AND LEFT + 0x2551, //BOX DRAWINGS DOUBLE VERTICAL + 0x2557, //BOX DRAWINGS DOUBLE DOWN AND LEFT + 0x255d, //BOX DRAWINGS DOUBLE UP AND LEFT + 0x255c, //BOX DRAWINGS UP DOUBLE AND LEFT SINGLE + 0x255b, //BOX DRAWINGS UP SINGLE AND LEFT DOUBLE + 0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT + 0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT + 0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0x252c, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0x251c, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0x2500, //BOX DRAWINGS LIGHT HORIZONTAL + 0x253c, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0x255e, //BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + 0x255f, //BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE + 0x255a, //BOX DRAWINGS DOUBLE UP AND RIGHT + 0x2554, //BOX DRAWINGS DOUBLE DOWN AND RIGHT + 0x2569, //BOX DRAWINGS DOUBLE UP AND HORIZONTAL + 0x2566, //BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + 0x2560, //BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + 0x2550, //BOX DRAWINGS DOUBLE HORIZONTAL + 0x256c, //BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + 0x2567, //BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE + 0x2568, //BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE + 0x2564, //BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE + 0x2565, //BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE + 0x2559, //BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE + 0x2558, //BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE + 0x2552, //BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE + 0x2553, //BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE + 0x256b, //BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE + 0x256a, //BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + 0x2518, //BOX DRAWINGS LIGHT UP AND LEFT + 0x250c, //BOX DRAWINGS LIGHT DOWN AND RIGHT + 0x2588, //FULL BLOCK + 0x2584, //LOWER HALF BLOCK + 0x258c, //LEFT HALF BLOCK + 0x2590, //RIGHT HALF BLOCK + 0x2580, //UPPER HALF BLOCK + 0x03b1, //GREEK SMALL LETTER ALPHA + 0x00df, //LATIN SMALL LETTER SHARP S + 0x0393, //GREEK CAPITAL LETTER GAMMA + 0x03c0, //GREEK SMALL LETTER PI + 0x03a3, //GREEK CAPITAL LETTER SIGMA + 0x03c3, //GREEK SMALL LETTER SIGMA + 0x00b5, //MICRO SIGN + 0x03c4, //GREEK SMALL LETTER TAU + 0x03a6, //GREEK CAPITAL LETTER PHI + 0x0398, //GREEK CAPITAL LETTER THETA + 0x03a9, //GREEK CAPITAL LETTER OMEGA + 0x03b4, //GREEK SMALL LETTER DELTA + 0x221e, //INFINITY + 0x03c6, //GREEK SMALL LETTER PHI + 0x03b5, //GREEK SMALL LETTER EPSILON + 0x2229, //INTERSECTION + 0x2261, //IDENTICAL TO + 0x00b1, //PLUS-MINUS SIGN + 0x2265, //GREATER-THAN OR EQUAL TO + 0x2264, //LESS-THAN OR EQUAL TO + 0x2320, //TOP HALF INTEGRAL + 0x2321, //BOTTOM HALF INTEGRAL + 0x00f7, //DIVISION SIGN + 0x2248, //ALMOST EQUAL TO + 0x00b0, //DEGREE SIGN + 0x2219, //BULLET OPERATOR + 0x00b7, //MIDDLE DOT + 0x221a, //SQUARE ROOT + 0x207f, //SUPERSCRIPT LATIN SMALL LETTER N + 0x00b2, //SUPERSCRIPT TWO + 0x25a0, //BLACK SQUARE + 0x00a0, //NO-BREAK SPACE + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp850.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp850.go new file mode 100644 index 00000000..927ab249 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp850.go @@ -0,0 +1,262 @@ +package cp + +var cp850 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000a, //LINE FEED + 0x000b, //VERTICAL TABULATION + 0x000c, //FORM FEED + 0x000d, //CARRIAGE RETURN + 0x000e, //SHIFT OUT + 0x000f, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001a, //SUBSTITUTE + 0x001b, //ESCAPE + 0x001c, //FILE SEPARATOR + 0x001d, //GROUP SEPARATOR + 0x001e, //RECORD SEPARATOR + 0x001f, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002a, //ASTERISK + 0x002b, //PLUS SIGN + 0x002c, //COMMA + 0x002d, //HYPHEN-MINUS + 0x002e, //FULL STOP + 0x002f, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003a, //COLON + 0x003b, //SEMICOLON + 0x003c, //LESS-THAN SIGN + 0x003d, //EQUALS SIGN + 0x003e, //GREATER-THAN SIGN + 0x003f, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004a, //LATIN CAPITAL LETTER J + 0x004b, //LATIN CAPITAL LETTER K + 0x004c, //LATIN CAPITAL LETTER L + 0x004d, //LATIN CAPITAL LETTER M + 0x004e, //LATIN CAPITAL LETTER N + 0x004f, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005a, //LATIN CAPITAL LETTER Z + 0x005b, //LEFT SQUARE BRACKET + 0x005c, //REVERSE SOLIDUS + 0x005d, //RIGHT SQUARE BRACKET + 0x005e, //CIRCUMFLEX ACCENT + 0x005f, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006a, //LATIN SMALL LETTER J + 0x006b, //LATIN SMALL LETTER K + 0x006c, //LATIN SMALL LETTER L + 0x006d, //LATIN SMALL LETTER M + 0x006e, //LATIN SMALL LETTER N + 0x006f, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007a, //LATIN SMALL LETTER Z + 0x007b, //LEFT CURLY BRACKET + 0x007c, //VERTICAL LINE + 0x007d, //RIGHT CURLY BRACKET + 0x007e, //TILDE + 0x007f, //DELETE + 0x00c7, //LATIN CAPITAL LETTER C WITH CEDILLA + 0x00fc, //LATIN SMALL LETTER U WITH DIAERESIS + 0x00e9, //LATIN SMALL LETTER E WITH ACUTE + 0x00e2, //LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x00e4, //LATIN SMALL LETTER A WITH DIAERESIS + 0x00e0, //LATIN SMALL LETTER A WITH GRAVE + 0x00e5, //LATIN SMALL LETTER A WITH RING ABOVE + 0x00e7, //LATIN SMALL LETTER C WITH CEDILLA + 0x00ea, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00eb, //LATIN SMALL LETTER E WITH DIAERESIS + 0x00e8, //LATIN SMALL LETTER E WITH GRAVE + 0x00ef, //LATIN SMALL LETTER I WITH DIAERESIS + 0x00ee, //LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00ec, //LATIN SMALL LETTER I WITH GRAVE + 0x00c4, //LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00c5, //LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00c9, //LATIN CAPITAL LETTER E WITH ACUTE + 0x00e6, //LATIN SMALL LIGATURE AE + 0x00c6, //LATIN CAPITAL LIGATURE AE + 0x00f4, //LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x00f6, //LATIN SMALL LETTER O WITH DIAERESIS + 0x00f2, //LATIN SMALL LETTER O WITH GRAVE + 0x00fb, //LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00f9, //LATIN SMALL LETTER U WITH GRAVE + 0x00ff, //LATIN SMALL LETTER Y WITH DIAERESIS + 0x00d6, //LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00dc, //LATIN CAPITAL LETTER U WITH DIAERESIS + 0x00f8, //LATIN SMALL LETTER O WITH STROKE + 0x00a3, //POUND SIGN + 0x00d8, //LATIN CAPITAL LETTER O WITH STROKE + 0x00d7, //MULTIPLICATION SIGN + 0x0192, //LATIN SMALL LETTER F WITH HOOK + 0x00e1, //LATIN SMALL LETTER A WITH ACUTE + 0x00ed, //LATIN SMALL LETTER I WITH ACUTE + 0x00f3, //LATIN SMALL LETTER O WITH ACUTE + 0x00fa, //LATIN SMALL LETTER U WITH ACUTE + 0x00f1, //LATIN SMALL LETTER N WITH TILDE + 0x00d1, //LATIN CAPITAL LETTER N WITH TILDE + 0x00aa, //FEMININE ORDINAL INDICATOR + 0x00ba, //MASCULINE ORDINAL INDICATOR + 0x00bf, //INVERTED QUESTION MARK + 0x00ae, //REGISTERED SIGN + 0x00ac, //NOT SIGN + 0x00bd, //VULGAR FRACTION ONE HALF + 0x00bc, //VULGAR FRACTION ONE QUARTER + 0x00a1, //INVERTED EXCLAMATION MARK + 0x00ab, //LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00bb, //RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x2591, //LIGHT SHADE + 0x2592, //MEDIUM SHADE + 0x2593, //DARK SHADE + 0x2502, //BOX DRAWINGS LIGHT VERTICAL + 0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0x00c1, //LATIN CAPITAL LETTER A WITH ACUTE + 0x00c2, //LATIN CAPITAL LETTER A WITH CIRCUMFLEX + 0x00c0, //LATIN CAPITAL LETTER A WITH GRAVE + 0x00a9, //COPYRIGHT SIGN + 0x2563, //BOX DRAWINGS DOUBLE VERTICAL AND LEFT + 0x2551, //BOX DRAWINGS DOUBLE VERTICAL + 0x2557, //BOX DRAWINGS DOUBLE DOWN AND LEFT + 0x255d, //BOX DRAWINGS DOUBLE UP AND LEFT + 0x00a2, //CENT SIGN + 0x00a5, //YEN SIGN + 0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT + 0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT + 0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0x252c, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0x251c, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0x2500, //BOX DRAWINGS LIGHT HORIZONTAL + 0x253c, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0x00e3, //LATIN SMALL LETTER A WITH TILDE + 0x00c3, //LATIN CAPITAL LETTER A WITH TILDE + 0x255a, //BOX DRAWINGS DOUBLE UP AND RIGHT + 0x2554, //BOX DRAWINGS DOUBLE DOWN AND RIGHT + 0x2569, //BOX DRAWINGS DOUBLE UP AND HORIZONTAL + 0x2566, //BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + 0x2560, //BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + 0x2550, //BOX DRAWINGS DOUBLE HORIZONTAL + 0x256c, //BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + 0x00a4, //CURRENCY SIGN + 0x00f0, //LATIN SMALL LETTER ETH + 0x00d0, //LATIN CAPITAL LETTER ETH + 0x00ca, //LATIN CAPITAL LETTER E WITH CIRCUMFLEX + 0x00cb, //LATIN CAPITAL LETTER E WITH DIAERESIS + 0x00c8, //LATIN CAPITAL LETTER E WITH GRAVE + 0x0131, //LATIN SMALL LETTER DOTLESS I + 0x00cd, //LATIN CAPITAL LETTER I WITH ACUTE + 0x00ce, //LATIN CAPITAL LETTER I WITH CIRCUMFLEX + 0x00cf, //LATIN CAPITAL LETTER I WITH DIAERESIS + 0x2518, //BOX DRAWINGS LIGHT UP AND LEFT + 0x250c, //BOX DRAWINGS LIGHT DOWN AND RIGHT + 0x2588, //FULL BLOCK + 0x2584, //LOWER HALF BLOCK + 0x00a6, //BROKEN BAR + 0x00cc, //LATIN CAPITAL LETTER I WITH GRAVE + 0x2580, //UPPER HALF BLOCK + 0x00d3, //LATIN CAPITAL LETTER O WITH ACUTE + 0x00df, //LATIN SMALL LETTER SHARP S + 0x00d4, //LATIN CAPITAL LETTER O WITH CIRCUMFLEX + 0x00d2, //LATIN CAPITAL LETTER O WITH GRAVE + 0x00f5, //LATIN SMALL LETTER O WITH TILDE + 0x00d5, //LATIN CAPITAL LETTER O WITH TILDE + 0x00b5, //MICRO SIGN + 0x00fe, //LATIN SMALL LETTER THORN + 0x00de, //LATIN CAPITAL LETTER THORN + 0x00da, //LATIN CAPITAL LETTER U WITH ACUTE + 0x00db, //LATIN CAPITAL LETTER U WITH CIRCUMFLEX + 0x00d9, //LATIN CAPITAL LETTER U WITH GRAVE + 0x00fd, //LATIN SMALL LETTER Y WITH ACUTE + 0x00dd, //LATIN CAPITAL LETTER Y WITH ACUTE + 0x00af, //MACRON + 0x00b4, //ACUTE ACCENT + 0x00ad, //SOFT HYPHEN + 0x00b1, //PLUS-MINUS SIGN + 0x2017, //DOUBLE LOW LINE + 0x00be, //VULGAR FRACTION THREE QUARTERS + 0x00b6, //PILCROW SIGN + 0x00a7, //SECTION SIGN + 0x00f7, //DIVISION SIGN + 0x00b8, //CEDILLA + 0x00b0, //DEGREE SIGN + 0x00a8, //DIAERESIS + 0x00b7, //MIDDLE DOT + 0x00b9, //SUPERSCRIPT ONE + 0x00b3, //SUPERSCRIPT THREE + 0x00b2, //SUPERSCRIPT TWO + 0x25a0, //BLACK SQUARE + 0x00a0, //NO-BREAK SPACE + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp874.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp874.go new file mode 100644 index 00000000..723bf6c3 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp874.go @@ -0,0 +1,262 @@ +package cp + +var cp874 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2026, //HORIZONTAL ELLIPSIS + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x2018, //LEFT SINGLE QUOTATION MARK + 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x2022, //BULLET + 0x2013, //EN DASH + 0x2014, //EM DASH + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x00A0, //NO-BREAK SPACE + 0x0E01, //THAI CHARACTER KO KAI + 0x0E02, //THAI CHARACTER KHO KHAI + 0x0E03, //THAI CHARACTER KHO KHUAT + 0x0E04, //THAI CHARACTER KHO KHWAI + 0x0E05, //THAI CHARACTER KHO KHON + 0x0E06, //THAI CHARACTER KHO RAKHANG + 0x0E07, //THAI CHARACTER NGO NGU + 0x0E08, //THAI CHARACTER CHO CHAN + 0x0E09, //THAI CHARACTER CHO CHING + 0x0E0A, //THAI CHARACTER CHO CHANG + 0x0E0B, //THAI CHARACTER SO SO + 0x0E0C, //THAI CHARACTER CHO CHOE + 0x0E0D, //THAI CHARACTER YO YING + 0x0E0E, //THAI CHARACTER DO CHADA + 0x0E0F, //THAI CHARACTER TO PATAK + 0x0E10, //THAI CHARACTER THO THAN + 0x0E11, //THAI CHARACTER THO NANGMONTHO + 0x0E12, //THAI CHARACTER THO PHUTHAO + 0x0E13, //THAI CHARACTER NO NEN + 0x0E14, //THAI CHARACTER DO DEK + 0x0E15, //THAI CHARACTER TO TAO + 0x0E16, //THAI CHARACTER THO THUNG + 0x0E17, //THAI CHARACTER THO THAHAN + 0x0E18, //THAI CHARACTER THO THONG + 0x0E19, //THAI CHARACTER NO NU + 0x0E1A, //THAI CHARACTER BO BAIMAI + 0x0E1B, //THAI CHARACTER PO PLA + 0x0E1C, //THAI CHARACTER PHO PHUNG + 0x0E1D, //THAI CHARACTER FO FA + 0x0E1E, //THAI CHARACTER PHO PHAN + 0x0E1F, //THAI CHARACTER FO FAN + 0x0E20, //THAI CHARACTER PHO SAMPHAO + 0x0E21, //THAI CHARACTER MO MA + 0x0E22, //THAI CHARACTER YO YAK + 0x0E23, //THAI CHARACTER RO RUA + 0x0E24, //THAI CHARACTER RU + 0x0E25, //THAI CHARACTER LO LING + 0x0E26, //THAI CHARACTER LU + 0x0E27, //THAI CHARACTER WO WAEN + 0x0E28, //THAI CHARACTER SO SALA + 0x0E29, //THAI CHARACTER SO RUSI + 0x0E2A, //THAI CHARACTER SO SUA + 0x0E2B, //THAI CHARACTER HO HIP + 0x0E2C, //THAI CHARACTER LO CHULA + 0x0E2D, //THAI CHARACTER O ANG + 0x0E2E, //THAI CHARACTER HO NOKHUK + 0x0E2F, //THAI CHARACTER PAIYANNOI + 0x0E30, //THAI CHARACTER SARA A + 0x0E31, //THAI CHARACTER MAI HAN-AKAT + 0x0E32, //THAI CHARACTER SARA AA + 0x0E33, //THAI CHARACTER SARA AM + 0x0E34, //THAI CHARACTER SARA I + 0x0E35, //THAI CHARACTER SARA II + 0x0E36, //THAI CHARACTER SARA UE + 0x0E37, //THAI CHARACTER SARA UEE + 0x0E38, //THAI CHARACTER SARA U + 0x0E39, //THAI CHARACTER SARA UU + 0x0E3A, //THAI CHARACTER PHINTHU + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0x0E3F, //THAI CURRENCY SYMBOL BAHT + 0x0E40, //THAI CHARACTER SARA E + 0x0E41, //THAI CHARACTER SARA AE + 0x0E42, //THAI CHARACTER SARA O + 0x0E43, //THAI CHARACTER SARA AI MAIMUAN + 0x0E44, //THAI CHARACTER SARA AI MAIMALAI + 0x0E45, //THAI CHARACTER LAKKHANGYAO + 0x0E46, //THAI CHARACTER MAIYAMOK + 0x0E47, //THAI CHARACTER MAITAIKHU + 0x0E48, //THAI CHARACTER MAI EK + 0x0E49, //THAI CHARACTER MAI THO + 0x0E4A, //THAI CHARACTER MAI TRI + 0x0E4B, //THAI CHARACTER MAI CHATTAWA + 0x0E4C, //THAI CHARACTER THANTHAKHAT + 0x0E4D, //THAI CHARACTER NIKHAHIT + 0x0E4E, //THAI CHARACTER YAMAKKAN + 0x0E4F, //THAI CHARACTER FONGMAN + 0x0E50, //THAI DIGIT ZERO + 0x0E51, //THAI DIGIT ONE + 0x0E52, //THAI DIGIT TWO + 0x0E53, //THAI DIGIT THREE + 0x0E54, //THAI DIGIT FOUR + 0x0E55, //THAI DIGIT FIVE + 0x0E56, //THAI DIGIT SIX + 0x0E57, //THAI DIGIT SEVEN + 0x0E58, //THAI DIGIT EIGHT + 0x0E59, //THAI DIGIT NINE + 0x0E5A, //THAI CHARACTER ANGKHANKHU + 0x0E5B, //THAI CHARACTER KHOMUT + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp932.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp932.go new file mode 100644 index 00000000..5fc13774 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp932.go @@ -0,0 +1,7988 @@ +package cp + +var cp932 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0xFFFD, //UNDEFINED + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + 0xFFFD, //UNDEFINED + 0xFF61, //HALFWIDTH IDEOGRAPHIC FULL STOP + 0xFF62, //HALFWIDTH LEFT CORNER BRACKET + 0xFF63, //HALFWIDTH RIGHT CORNER BRACKET + 0xFF64, //HALFWIDTH IDEOGRAPHIC COMMA + 0xFF65, //HALFWIDTH KATAKANA MIDDLE DOT + 0xFF66, //HALFWIDTH KATAKANA LETTER WO + 0xFF67, //HALFWIDTH KATAKANA LETTER SMALL A + 0xFF68, //HALFWIDTH KATAKANA LETTER SMALL I + 0xFF69, //HALFWIDTH KATAKANA LETTER SMALL U + 0xFF6A, //HALFWIDTH KATAKANA LETTER SMALL E + 0xFF6B, //HALFWIDTH KATAKANA LETTER SMALL O + 0xFF6C, //HALFWIDTH KATAKANA LETTER SMALL YA + 0xFF6D, //HALFWIDTH KATAKANA LETTER SMALL YU + 0xFF6E, //HALFWIDTH KATAKANA LETTER SMALL YO + 0xFF6F, //HALFWIDTH KATAKANA LETTER SMALL TU + 0xFF70, //HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK + 0xFF71, //HALFWIDTH KATAKANA LETTER A + 0xFF72, //HALFWIDTH KATAKANA LETTER I + 0xFF73, //HALFWIDTH KATAKANA LETTER U + 0xFF74, //HALFWIDTH KATAKANA LETTER E + 0xFF75, //HALFWIDTH KATAKANA LETTER O + 0xFF76, //HALFWIDTH KATAKANA LETTER KA + 0xFF77, //HALFWIDTH KATAKANA LETTER KI + 0xFF78, //HALFWIDTH KATAKANA LETTER KU + 0xFF79, //HALFWIDTH KATAKANA LETTER KE + 0xFF7A, //HALFWIDTH KATAKANA LETTER KO + 0xFF7B, //HALFWIDTH KATAKANA LETTER SA + 0xFF7C, //HALFWIDTH KATAKANA LETTER SI + 0xFF7D, //HALFWIDTH KATAKANA LETTER SU + 0xFF7E, //HALFWIDTH KATAKANA LETTER SE + 0xFF7F, //HALFWIDTH KATAKANA LETTER SO + 0xFF80, //HALFWIDTH KATAKANA LETTER TA + 0xFF81, //HALFWIDTH KATAKANA LETTER TI + 0xFF82, //HALFWIDTH KATAKANA LETTER TU + 0xFF83, //HALFWIDTH KATAKANA LETTER TE + 0xFF84, //HALFWIDTH KATAKANA LETTER TO + 0xFF85, //HALFWIDTH KATAKANA LETTER NA + 0xFF86, //HALFWIDTH KATAKANA LETTER NI + 0xFF87, //HALFWIDTH KATAKANA LETTER NU + 0xFF88, //HALFWIDTH KATAKANA LETTER NE + 0xFF89, //HALFWIDTH KATAKANA LETTER NO + 0xFF8A, //HALFWIDTH KATAKANA LETTER HA + 0xFF8B, //HALFWIDTH KATAKANA LETTER HI + 0xFF8C, //HALFWIDTH KATAKANA LETTER HU + 0xFF8D, //HALFWIDTH KATAKANA LETTER HE + 0xFF8E, //HALFWIDTH KATAKANA LETTER HO + 0xFF8F, //HALFWIDTH KATAKANA LETTER MA + 0xFF90, //HALFWIDTH KATAKANA LETTER MI + 0xFF91, //HALFWIDTH KATAKANA LETTER MU + 0xFF92, //HALFWIDTH KATAKANA LETTER ME + 0xFF93, //HALFWIDTH KATAKANA LETTER MO + 0xFF94, //HALFWIDTH KATAKANA LETTER YA + 0xFF95, //HALFWIDTH KATAKANA LETTER YU + 0xFF96, //HALFWIDTH KATAKANA LETTER YO + 0xFF97, //HALFWIDTH KATAKANA LETTER RA + 0xFF98, //HALFWIDTH KATAKANA LETTER RI + 0xFF99, //HALFWIDTH KATAKANA LETTER RU + 0xFF9A, //HALFWIDTH KATAKANA LETTER RE + 0xFF9B, //HALFWIDTH KATAKANA LETTER RO + 0xFF9C, //HALFWIDTH KATAKANA LETTER WA + 0xFF9D, //HALFWIDTH KATAKANA LETTER N + 0xFF9E, //HALFWIDTH KATAKANA VOICED SOUND MARK + 0xFF9F, //HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + 0xFFFD, //UNDEFINED + }, + db: map[int]rune{ + 0x8140: 0x3000, //IDEOGRAPHIC SPACE + 0x8141: 0x3001, //IDEOGRAPHIC COMMA + 0x8142: 0x3002, //IDEOGRAPHIC FULL STOP + 0x8143: 0xFF0C, //FULLWIDTH COMMA + 0x8144: 0xFF0E, //FULLWIDTH FULL STOP + 0x8145: 0x30FB, //KATAKANA MIDDLE DOT + 0x8146: 0xFF1A, //FULLWIDTH COLON + 0x8147: 0xFF1B, //FULLWIDTH SEMICOLON + 0x8148: 0xFF1F, //FULLWIDTH QUESTION MARK + 0x8149: 0xFF01, //FULLWIDTH EXCLAMATION MARK + 0x814A: 0x309B, //KATAKANA-HIRAGANA VOICED SOUND MARK + 0x814B: 0x309C, //KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK + 0x814C: 0x00B4, //ACUTE ACCENT + 0x814D: 0xFF40, //FULLWIDTH GRAVE ACCENT + 0x814E: 0x00A8, //DIAERESIS + 0x814F: 0xFF3E, //FULLWIDTH CIRCUMFLEX ACCENT + 0x8150: 0xFFE3, //FULLWIDTH MACRON + 0x8151: 0xFF3F, //FULLWIDTH LOW LINE + 0x8152: 0x30FD, //KATAKANA ITERATION MARK + 0x8153: 0x30FE, //KATAKANA VOICED ITERATION MARK + 0x8154: 0x309D, //HIRAGANA ITERATION MARK + 0x8155: 0x309E, //HIRAGANA VOICED ITERATION MARK + 0x8156: 0x3003, //DITTO MARK + 0x8157: 0x4EDD, //CJK UNIFIED IDEOGRAPH + 0x8158: 0x3005, //IDEOGRAPHIC ITERATION MARK + 0x8159: 0x3006, //IDEOGRAPHIC CLOSING MARK + 0x815A: 0x3007, //IDEOGRAPHIC NUMBER ZERO + 0x815B: 0x30FC, //KATAKANA-HIRAGANA PROLONGED SOUND MARK + 0x815C: 0x2015, //HORIZONTAL BAR + 0x815D: 0x2010, //HYPHEN + 0x815E: 0xFF0F, //FULLWIDTH SOLIDUS + 0x815F: 0xFF3C, //FULLWIDTH REVERSE SOLIDUS + 0x8160: 0xFF5E, //FULLWIDTH TILDE + 0x8161: 0x2225, //PARALLEL TO + 0x8162: 0xFF5C, //FULLWIDTH VERTICAL LINE + 0x8163: 0x2026, //HORIZONTAL ELLIPSIS + 0x8164: 0x2025, //TWO DOT LEADER + 0x8165: 0x2018, //LEFT SINGLE QUOTATION MARK + 0x8166: 0x2019, //RIGHT SINGLE QUOTATION MARK + 0x8167: 0x201C, //LEFT DOUBLE QUOTATION MARK + 0x8168: 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0x8169: 0xFF08, //FULLWIDTH LEFT PARENTHESIS + 0x816A: 0xFF09, //FULLWIDTH RIGHT PARENTHESIS + 0x816B: 0x3014, //LEFT TORTOISE SHELL BRACKET + 0x816C: 0x3015, //RIGHT TORTOISE SHELL BRACKET + 0x816D: 0xFF3B, //FULLWIDTH LEFT SQUARE BRACKET + 0x816E: 0xFF3D, //FULLWIDTH RIGHT SQUARE BRACKET + 0x816F: 0xFF5B, //FULLWIDTH LEFT CURLY BRACKET + 0x8170: 0xFF5D, //FULLWIDTH RIGHT CURLY BRACKET + 0x8171: 0x3008, //LEFT ANGLE BRACKET + 0x8172: 0x3009, //RIGHT ANGLE BRACKET + 0x8173: 0x300A, //LEFT DOUBLE ANGLE BRACKET + 0x8174: 0x300B, //RIGHT DOUBLE ANGLE BRACKET + 0x8175: 0x300C, //LEFT CORNER BRACKET + 0x8176: 0x300D, //RIGHT CORNER BRACKET + 0x8177: 0x300E, //LEFT WHITE CORNER BRACKET + 0x8178: 0x300F, //RIGHT WHITE CORNER BRACKET + 0x8179: 0x3010, //LEFT BLACK LENTICULAR BRACKET + 0x817A: 0x3011, //RIGHT BLACK LENTICULAR BRACKET + 0x817B: 0xFF0B, //FULLWIDTH PLUS SIGN + 0x817C: 0xFF0D, //FULLWIDTH HYPHEN-MINUS + 0x817D: 0x00B1, //PLUS-MINUS SIGN + 0x817E: 0x00D7, //MULTIPLICATION SIGN + 0x8180: 0x00F7, //DIVISION SIGN + 0x8181: 0xFF1D, //FULLWIDTH EQUALS SIGN + 0x8182: 0x2260, //NOT EQUAL TO + 0x8183: 0xFF1C, //FULLWIDTH LESS-THAN SIGN + 0x8184: 0xFF1E, //FULLWIDTH GREATER-THAN SIGN + 0x8185: 0x2266, //LESS-THAN OVER EQUAL TO + 0x8186: 0x2267, //GREATER-THAN OVER EQUAL TO + 0x8187: 0x221E, //INFINITY + 0x8188: 0x2234, //THEREFORE + 0x8189: 0x2642, //MALE SIGN + 0x818A: 0x2640, //FEMALE SIGN + 0x818B: 0x00B0, //DEGREE SIGN + 0x818C: 0x2032, //PRIME + 0x818D: 0x2033, //DOUBLE PRIME + 0x818E: 0x2103, //DEGREE CELSIUS + 0x818F: 0xFFE5, //FULLWIDTH YEN SIGN + 0x8190: 0xFF04, //FULLWIDTH DOLLAR SIGN + 0x8191: 0xFFE0, //FULLWIDTH CENT SIGN + 0x8192: 0xFFE1, //FULLWIDTH POUND SIGN + 0x8193: 0xFF05, //FULLWIDTH PERCENT SIGN + 0x8194: 0xFF03, //FULLWIDTH NUMBER SIGN + 0x8195: 0xFF06, //FULLWIDTH AMPERSAND + 0x8196: 0xFF0A, //FULLWIDTH ASTERISK + 0x8197: 0xFF20, //FULLWIDTH COMMERCIAL AT + 0x8198: 0x00A7, //SECTION SIGN + 0x8199: 0x2606, //WHITE STAR + 0x819A: 0x2605, //BLACK STAR + 0x819B: 0x25CB, //WHITE CIRCLE + 0x819C: 0x25CF, //BLACK CIRCLE + 0x819D: 0x25CE, //BULLSEYE + 0x819E: 0x25C7, //WHITE DIAMOND + 0x819F: 0x25C6, //BLACK DIAMOND + 0x81A0: 0x25A1, //WHITE SQUARE + 0x81A1: 0x25A0, //BLACK SQUARE + 0x81A2: 0x25B3, //WHITE UP-POINTING TRIANGLE + 0x81A3: 0x25B2, //BLACK UP-POINTING TRIANGLE + 0x81A4: 0x25BD, //WHITE DOWN-POINTING TRIANGLE + 0x81A5: 0x25BC, //BLACK DOWN-POINTING TRIANGLE + 0x81A6: 0x203B, //REFERENCE MARK + 0x81A7: 0x3012, //POSTAL MARK + 0x81A8: 0x2192, //RIGHTWARDS ARROW + 0x81A9: 0x2190, //LEFTWARDS ARROW + 0x81AA: 0x2191, //UPWARDS ARROW + 0x81AB: 0x2193, //DOWNWARDS ARROW + 0x81AC: 0x3013, //GETA MARK + 0x81B8: 0x2208, //ELEMENT OF + 0x81B9: 0x220B, //CONTAINS AS MEMBER + 0x81BA: 0x2286, //SUBSET OF OR EQUAL TO + 0x81BB: 0x2287, //SUPERSET OF OR EQUAL TO + 0x81BC: 0x2282, //SUBSET OF + 0x81BD: 0x2283, //SUPERSET OF + 0x81BE: 0x222A, //UNION + 0x81BF: 0x2229, //INTERSECTION + 0x81C8: 0x2227, //LOGICAL AND + 0x81C9: 0x2228, //LOGICAL OR + 0x81CA: 0xFFE2, //FULLWIDTH NOT SIGN + 0x81CB: 0x21D2, //RIGHTWARDS DOUBLE ARROW + 0x81CC: 0x21D4, //LEFT RIGHT DOUBLE ARROW + 0x81CD: 0x2200, //FOR ALL + 0x81CE: 0x2203, //THERE EXISTS + 0x81DA: 0x2220, //ANGLE + 0x81DB: 0x22A5, //UP TACK + 0x81DC: 0x2312, //ARC + 0x81DD: 0x2202, //PARTIAL DIFFERENTIAL + 0x81DE: 0x2207, //NABLA + 0x81DF: 0x2261, //IDENTICAL TO + 0x81E0: 0x2252, //APPROXIMATELY EQUAL TO OR THE IMAGE OF + 0x81E1: 0x226A, //MUCH LESS-THAN + 0x81E2: 0x226B, //MUCH GREATER-THAN + 0x81E3: 0x221A, //SQUARE ROOT + 0x81E4: 0x223D, //REVERSED TILDE + 0x81E5: 0x221D, //PROPORTIONAL TO + 0x81E6: 0x2235, //BECAUSE + 0x81E7: 0x222B, //INTEGRAL + 0x81E8: 0x222C, //DOUBLE INTEGRAL + 0x81F0: 0x212B, //ANGSTROM SIGN + 0x81F1: 0x2030, //PER MILLE SIGN + 0x81F2: 0x266F, //MUSIC SHARP SIGN + 0x81F3: 0x266D, //MUSIC FLAT SIGN + 0x81F4: 0x266A, //EIGHTH NOTE + 0x81F5: 0x2020, //DAGGER + 0x81F6: 0x2021, //DOUBLE DAGGER + 0x81F7: 0x00B6, //PILCROW SIGN + 0x81FC: 0x25EF, //LARGE CIRCLE + 0x824F: 0xFF10, //FULLWIDTH DIGIT ZERO + 0x8250: 0xFF11, //FULLWIDTH DIGIT ONE + 0x8251: 0xFF12, //FULLWIDTH DIGIT TWO + 0x8252: 0xFF13, //FULLWIDTH DIGIT THREE + 0x8253: 0xFF14, //FULLWIDTH DIGIT FOUR + 0x8254: 0xFF15, //FULLWIDTH DIGIT FIVE + 0x8255: 0xFF16, //FULLWIDTH DIGIT SIX + 0x8256: 0xFF17, //FULLWIDTH DIGIT SEVEN + 0x8257: 0xFF18, //FULLWIDTH DIGIT EIGHT + 0x8258: 0xFF19, //FULLWIDTH DIGIT NINE + 0x8260: 0xFF21, //FULLWIDTH LATIN CAPITAL LETTER A + 0x8261: 0xFF22, //FULLWIDTH LATIN CAPITAL LETTER B + 0x8262: 0xFF23, //FULLWIDTH LATIN CAPITAL LETTER C + 0x8263: 0xFF24, //FULLWIDTH LATIN CAPITAL LETTER D + 0x8264: 0xFF25, //FULLWIDTH LATIN CAPITAL LETTER E + 0x8265: 0xFF26, //FULLWIDTH LATIN CAPITAL LETTER F + 0x8266: 0xFF27, //FULLWIDTH LATIN CAPITAL LETTER G + 0x8267: 0xFF28, //FULLWIDTH LATIN CAPITAL LETTER H + 0x8268: 0xFF29, //FULLWIDTH LATIN CAPITAL LETTER I + 0x8269: 0xFF2A, //FULLWIDTH LATIN CAPITAL LETTER J + 0x826A: 0xFF2B, //FULLWIDTH LATIN CAPITAL LETTER K + 0x826B: 0xFF2C, //FULLWIDTH LATIN CAPITAL LETTER L + 0x826C: 0xFF2D, //FULLWIDTH LATIN CAPITAL LETTER M + 0x826D: 0xFF2E, //FULLWIDTH LATIN CAPITAL LETTER N + 0x826E: 0xFF2F, //FULLWIDTH LATIN CAPITAL LETTER O + 0x826F: 0xFF30, //FULLWIDTH LATIN CAPITAL LETTER P + 0x8270: 0xFF31, //FULLWIDTH LATIN CAPITAL LETTER Q + 0x8271: 0xFF32, //FULLWIDTH LATIN CAPITAL LETTER R + 0x8272: 0xFF33, //FULLWIDTH LATIN CAPITAL LETTER S + 0x8273: 0xFF34, //FULLWIDTH LATIN CAPITAL LETTER T + 0x8274: 0xFF35, //FULLWIDTH LATIN CAPITAL LETTER U + 0x8275: 0xFF36, //FULLWIDTH LATIN CAPITAL LETTER V + 0x8276: 0xFF37, //FULLWIDTH LATIN CAPITAL LETTER W + 0x8277: 0xFF38, //FULLWIDTH LATIN CAPITAL LETTER X + 0x8278: 0xFF39, //FULLWIDTH LATIN CAPITAL LETTER Y + 0x8279: 0xFF3A, //FULLWIDTH LATIN CAPITAL LETTER Z + 0x8281: 0xFF41, //FULLWIDTH LATIN SMALL LETTER A + 0x8282: 0xFF42, //FULLWIDTH LATIN SMALL LETTER B + 0x8283: 0xFF43, //FULLWIDTH LATIN SMALL LETTER C + 0x8284: 0xFF44, //FULLWIDTH LATIN SMALL LETTER D + 0x8285: 0xFF45, //FULLWIDTH LATIN SMALL LETTER E + 0x8286: 0xFF46, //FULLWIDTH LATIN SMALL LETTER F + 0x8287: 0xFF47, //FULLWIDTH LATIN SMALL LETTER G + 0x8288: 0xFF48, //FULLWIDTH LATIN SMALL LETTER H + 0x8289: 0xFF49, //FULLWIDTH LATIN SMALL LETTER I + 0x828A: 0xFF4A, //FULLWIDTH LATIN SMALL LETTER J + 0x828B: 0xFF4B, //FULLWIDTH LATIN SMALL LETTER K + 0x828C: 0xFF4C, //FULLWIDTH LATIN SMALL LETTER L + 0x828D: 0xFF4D, //FULLWIDTH LATIN SMALL LETTER M + 0x828E: 0xFF4E, //FULLWIDTH LATIN SMALL LETTER N + 0x828F: 0xFF4F, //FULLWIDTH LATIN SMALL LETTER O + 0x8290: 0xFF50, //FULLWIDTH LATIN SMALL LETTER P + 0x8291: 0xFF51, //FULLWIDTH LATIN SMALL LETTER Q + 0x8292: 0xFF52, //FULLWIDTH LATIN SMALL LETTER R + 0x8293: 0xFF53, //FULLWIDTH LATIN SMALL LETTER S + 0x8294: 0xFF54, //FULLWIDTH LATIN SMALL LETTER T + 0x8295: 0xFF55, //FULLWIDTH LATIN SMALL LETTER U + 0x8296: 0xFF56, //FULLWIDTH LATIN SMALL LETTER V + 0x8297: 0xFF57, //FULLWIDTH LATIN SMALL LETTER W + 0x8298: 0xFF58, //FULLWIDTH LATIN SMALL LETTER X + 0x8299: 0xFF59, //FULLWIDTH LATIN SMALL LETTER Y + 0x829A: 0xFF5A, //FULLWIDTH LATIN SMALL LETTER Z + 0x829F: 0x3041, //HIRAGANA LETTER SMALL A + 0x82A0: 0x3042, //HIRAGANA LETTER A + 0x82A1: 0x3043, //HIRAGANA LETTER SMALL I + 0x82A2: 0x3044, //HIRAGANA LETTER I + 0x82A3: 0x3045, //HIRAGANA LETTER SMALL U + 0x82A4: 0x3046, //HIRAGANA LETTER U + 0x82A5: 0x3047, //HIRAGANA LETTER SMALL E + 0x82A6: 0x3048, //HIRAGANA LETTER E + 0x82A7: 0x3049, //HIRAGANA LETTER SMALL O + 0x82A8: 0x304A, //HIRAGANA LETTER O + 0x82A9: 0x304B, //HIRAGANA LETTER KA + 0x82AA: 0x304C, //HIRAGANA LETTER GA + 0x82AB: 0x304D, //HIRAGANA LETTER KI + 0x82AC: 0x304E, //HIRAGANA LETTER GI + 0x82AD: 0x304F, //HIRAGANA LETTER KU + 0x82AE: 0x3050, //HIRAGANA LETTER GU + 0x82AF: 0x3051, //HIRAGANA LETTER KE + 0x82B0: 0x3052, //HIRAGANA LETTER GE + 0x82B1: 0x3053, //HIRAGANA LETTER KO + 0x82B2: 0x3054, //HIRAGANA LETTER GO + 0x82B3: 0x3055, //HIRAGANA LETTER SA + 0x82B4: 0x3056, //HIRAGANA LETTER ZA + 0x82B5: 0x3057, //HIRAGANA LETTER SI + 0x82B6: 0x3058, //HIRAGANA LETTER ZI + 0x82B7: 0x3059, //HIRAGANA LETTER SU + 0x82B8: 0x305A, //HIRAGANA LETTER ZU + 0x82B9: 0x305B, //HIRAGANA LETTER SE + 0x82BA: 0x305C, //HIRAGANA LETTER ZE + 0x82BB: 0x305D, //HIRAGANA LETTER SO + 0x82BC: 0x305E, //HIRAGANA LETTER ZO + 0x82BD: 0x305F, //HIRAGANA LETTER TA + 0x82BE: 0x3060, //HIRAGANA LETTER DA + 0x82BF: 0x3061, //HIRAGANA LETTER TI + 0x82C0: 0x3062, //HIRAGANA LETTER DI + 0x82C1: 0x3063, //HIRAGANA LETTER SMALL TU + 0x82C2: 0x3064, //HIRAGANA LETTER TU + 0x82C3: 0x3065, //HIRAGANA LETTER DU + 0x82C4: 0x3066, //HIRAGANA LETTER TE + 0x82C5: 0x3067, //HIRAGANA LETTER DE + 0x82C6: 0x3068, //HIRAGANA LETTER TO + 0x82C7: 0x3069, //HIRAGANA LETTER DO + 0x82C8: 0x306A, //HIRAGANA LETTER NA + 0x82C9: 0x306B, //HIRAGANA LETTER NI + 0x82CA: 0x306C, //HIRAGANA LETTER NU + 0x82CB: 0x306D, //HIRAGANA LETTER NE + 0x82CC: 0x306E, //HIRAGANA LETTER NO + 0x82CD: 0x306F, //HIRAGANA LETTER HA + 0x82CE: 0x3070, //HIRAGANA LETTER BA + 0x82CF: 0x3071, //HIRAGANA LETTER PA + 0x82D0: 0x3072, //HIRAGANA LETTER HI + 0x82D1: 0x3073, //HIRAGANA LETTER BI + 0x82D2: 0x3074, //HIRAGANA LETTER PI + 0x82D3: 0x3075, //HIRAGANA LETTER HU + 0x82D4: 0x3076, //HIRAGANA LETTER BU + 0x82D5: 0x3077, //HIRAGANA LETTER PU + 0x82D6: 0x3078, //HIRAGANA LETTER HE + 0x82D7: 0x3079, //HIRAGANA LETTER BE + 0x82D8: 0x307A, //HIRAGANA LETTER PE + 0x82D9: 0x307B, //HIRAGANA LETTER HO + 0x82DA: 0x307C, //HIRAGANA LETTER BO + 0x82DB: 0x307D, //HIRAGANA LETTER PO + 0x82DC: 0x307E, //HIRAGANA LETTER MA + 0x82DD: 0x307F, //HIRAGANA LETTER MI + 0x82DE: 0x3080, //HIRAGANA LETTER MU + 0x82DF: 0x3081, //HIRAGANA LETTER ME + 0x82E0: 0x3082, //HIRAGANA LETTER MO + 0x82E1: 0x3083, //HIRAGANA LETTER SMALL YA + 0x82E2: 0x3084, //HIRAGANA LETTER YA + 0x82E3: 0x3085, //HIRAGANA LETTER SMALL YU + 0x82E4: 0x3086, //HIRAGANA LETTER YU + 0x82E5: 0x3087, //HIRAGANA LETTER SMALL YO + 0x82E6: 0x3088, //HIRAGANA LETTER YO + 0x82E7: 0x3089, //HIRAGANA LETTER RA + 0x82E8: 0x308A, //HIRAGANA LETTER RI + 0x82E9: 0x308B, //HIRAGANA LETTER RU + 0x82EA: 0x308C, //HIRAGANA LETTER RE + 0x82EB: 0x308D, //HIRAGANA LETTER RO + 0x82EC: 0x308E, //HIRAGANA LETTER SMALL WA + 0x82ED: 0x308F, //HIRAGANA LETTER WA + 0x82EE: 0x3090, //HIRAGANA LETTER WI + 0x82EF: 0x3091, //HIRAGANA LETTER WE + 0x82F0: 0x3092, //HIRAGANA LETTER WO + 0x82F1: 0x3093, //HIRAGANA LETTER N + 0x8340: 0x30A1, //KATAKANA LETTER SMALL A + 0x8341: 0x30A2, //KATAKANA LETTER A + 0x8342: 0x30A3, //KATAKANA LETTER SMALL I + 0x8343: 0x30A4, //KATAKANA LETTER I + 0x8344: 0x30A5, //KATAKANA LETTER SMALL U + 0x8345: 0x30A6, //KATAKANA LETTER U + 0x8346: 0x30A7, //KATAKANA LETTER SMALL E + 0x8347: 0x30A8, //KATAKANA LETTER E + 0x8348: 0x30A9, //KATAKANA LETTER SMALL O + 0x8349: 0x30AA, //KATAKANA LETTER O + 0x834A: 0x30AB, //KATAKANA LETTER KA + 0x834B: 0x30AC, //KATAKANA LETTER GA + 0x834C: 0x30AD, //KATAKANA LETTER KI + 0x834D: 0x30AE, //KATAKANA LETTER GI + 0x834E: 0x30AF, //KATAKANA LETTER KU + 0x834F: 0x30B0, //KATAKANA LETTER GU + 0x8350: 0x30B1, //KATAKANA LETTER KE + 0x8351: 0x30B2, //KATAKANA LETTER GE + 0x8352: 0x30B3, //KATAKANA LETTER KO + 0x8353: 0x30B4, //KATAKANA LETTER GO + 0x8354: 0x30B5, //KATAKANA LETTER SA + 0x8355: 0x30B6, //KATAKANA LETTER ZA + 0x8356: 0x30B7, //KATAKANA LETTER SI + 0x8357: 0x30B8, //KATAKANA LETTER ZI + 0x8358: 0x30B9, //KATAKANA LETTER SU + 0x8359: 0x30BA, //KATAKANA LETTER ZU + 0x835A: 0x30BB, //KATAKANA LETTER SE + 0x835B: 0x30BC, //KATAKANA LETTER ZE + 0x835C: 0x30BD, //KATAKANA LETTER SO + 0x835D: 0x30BE, //KATAKANA LETTER ZO + 0x835E: 0x30BF, //KATAKANA LETTER TA + 0x835F: 0x30C0, //KATAKANA LETTER DA + 0x8360: 0x30C1, //KATAKANA LETTER TI + 0x8361: 0x30C2, //KATAKANA LETTER DI + 0x8362: 0x30C3, //KATAKANA LETTER SMALL TU + 0x8363: 0x30C4, //KATAKANA LETTER TU + 0x8364: 0x30C5, //KATAKANA LETTER DU + 0x8365: 0x30C6, //KATAKANA LETTER TE + 0x8366: 0x30C7, //KATAKANA LETTER DE + 0x8367: 0x30C8, //KATAKANA LETTER TO + 0x8368: 0x30C9, //KATAKANA LETTER DO + 0x8369: 0x30CA, //KATAKANA LETTER NA + 0x836A: 0x30CB, //KATAKANA LETTER NI + 0x836B: 0x30CC, //KATAKANA LETTER NU + 0x836C: 0x30CD, //KATAKANA LETTER NE + 0x836D: 0x30CE, //KATAKANA LETTER NO + 0x836E: 0x30CF, //KATAKANA LETTER HA + 0x836F: 0x30D0, //KATAKANA LETTER BA + 0x8370: 0x30D1, //KATAKANA LETTER PA + 0x8371: 0x30D2, //KATAKANA LETTER HI + 0x8372: 0x30D3, //KATAKANA LETTER BI + 0x8373: 0x30D4, //KATAKANA LETTER PI + 0x8374: 0x30D5, //KATAKANA LETTER HU + 0x8375: 0x30D6, //KATAKANA LETTER BU + 0x8376: 0x30D7, //KATAKANA LETTER PU + 0x8377: 0x30D8, //KATAKANA LETTER HE + 0x8378: 0x30D9, //KATAKANA LETTER BE + 0x8379: 0x30DA, //KATAKANA LETTER PE + 0x837A: 0x30DB, //KATAKANA LETTER HO + 0x837B: 0x30DC, //KATAKANA LETTER BO + 0x837C: 0x30DD, //KATAKANA LETTER PO + 0x837D: 0x30DE, //KATAKANA LETTER MA + 0x837E: 0x30DF, //KATAKANA LETTER MI + 0x8380: 0x30E0, //KATAKANA LETTER MU + 0x8381: 0x30E1, //KATAKANA LETTER ME + 0x8382: 0x30E2, //KATAKANA LETTER MO + 0x8383: 0x30E3, //KATAKANA LETTER SMALL YA + 0x8384: 0x30E4, //KATAKANA LETTER YA + 0x8385: 0x30E5, //KATAKANA LETTER SMALL YU + 0x8386: 0x30E6, //KATAKANA LETTER YU + 0x8387: 0x30E7, //KATAKANA LETTER SMALL YO + 0x8388: 0x30E8, //KATAKANA LETTER YO + 0x8389: 0x30E9, //KATAKANA LETTER RA + 0x838A: 0x30EA, //KATAKANA LETTER RI + 0x838B: 0x30EB, //KATAKANA LETTER RU + 0x838C: 0x30EC, //KATAKANA LETTER RE + 0x838D: 0x30ED, //KATAKANA LETTER RO + 0x838E: 0x30EE, //KATAKANA LETTER SMALL WA + 0x838F: 0x30EF, //KATAKANA LETTER WA + 0x8390: 0x30F0, //KATAKANA LETTER WI + 0x8391: 0x30F1, //KATAKANA LETTER WE + 0x8392: 0x30F2, //KATAKANA LETTER WO + 0x8393: 0x30F3, //KATAKANA LETTER N + 0x8394: 0x30F4, //KATAKANA LETTER VU + 0x8395: 0x30F5, //KATAKANA LETTER SMALL KA + 0x8396: 0x30F6, //KATAKANA LETTER SMALL KE + 0x839F: 0x0391, //GREEK CAPITAL LETTER ALPHA + 0x83A0: 0x0392, //GREEK CAPITAL LETTER BETA + 0x83A1: 0x0393, //GREEK CAPITAL LETTER GAMMA + 0x83A2: 0x0394, //GREEK CAPITAL LETTER DELTA + 0x83A3: 0x0395, //GREEK CAPITAL LETTER EPSILON + 0x83A4: 0x0396, //GREEK CAPITAL LETTER ZETA + 0x83A5: 0x0397, //GREEK CAPITAL LETTER ETA + 0x83A6: 0x0398, //GREEK CAPITAL LETTER THETA + 0x83A7: 0x0399, //GREEK CAPITAL LETTER IOTA + 0x83A8: 0x039A, //GREEK CAPITAL LETTER KAPPA + 0x83A9: 0x039B, //GREEK CAPITAL LETTER LAMDA + 0x83AA: 0x039C, //GREEK CAPITAL LETTER MU + 0x83AB: 0x039D, //GREEK CAPITAL LETTER NU + 0x83AC: 0x039E, //GREEK CAPITAL LETTER XI + 0x83AD: 0x039F, //GREEK CAPITAL LETTER OMICRON + 0x83AE: 0x03A0, //GREEK CAPITAL LETTER PI + 0x83AF: 0x03A1, //GREEK CAPITAL LETTER RHO + 0x83B0: 0x03A3, //GREEK CAPITAL LETTER SIGMA + 0x83B1: 0x03A4, //GREEK CAPITAL LETTER TAU + 0x83B2: 0x03A5, //GREEK CAPITAL LETTER UPSILON + 0x83B3: 0x03A6, //GREEK CAPITAL LETTER PHI + 0x83B4: 0x03A7, //GREEK CAPITAL LETTER CHI + 0x83B5: 0x03A8, //GREEK CAPITAL LETTER PSI + 0x83B6: 0x03A9, //GREEK CAPITAL LETTER OMEGA + 0x83BF: 0x03B1, //GREEK SMALL LETTER ALPHA + 0x83C0: 0x03B2, //GREEK SMALL LETTER BETA + 0x83C1: 0x03B3, //GREEK SMALL LETTER GAMMA + 0x83C2: 0x03B4, //GREEK SMALL LETTER DELTA + 0x83C3: 0x03B5, //GREEK SMALL LETTER EPSILON + 0x83C4: 0x03B6, //GREEK SMALL LETTER ZETA + 0x83C5: 0x03B7, //GREEK SMALL LETTER ETA + 0x83C6: 0x03B8, //GREEK SMALL LETTER THETA + 0x83C7: 0x03B9, //GREEK SMALL LETTER IOTA + 0x83C8: 0x03BA, //GREEK SMALL LETTER KAPPA + 0x83C9: 0x03BB, //GREEK SMALL LETTER LAMDA + 0x83CA: 0x03BC, //GREEK SMALL LETTER MU + 0x83CB: 0x03BD, //GREEK SMALL LETTER NU + 0x83CC: 0x03BE, //GREEK SMALL LETTER XI + 0x83CD: 0x03BF, //GREEK SMALL LETTER OMICRON + 0x83CE: 0x03C0, //GREEK SMALL LETTER PI + 0x83CF: 0x03C1, //GREEK SMALL LETTER RHO + 0x83D0: 0x03C3, //GREEK SMALL LETTER SIGMA + 0x83D1: 0x03C4, //GREEK SMALL LETTER TAU + 0x83D2: 0x03C5, //GREEK SMALL LETTER UPSILON + 0x83D3: 0x03C6, //GREEK SMALL LETTER PHI + 0x83D4: 0x03C7, //GREEK SMALL LETTER CHI + 0x83D5: 0x03C8, //GREEK SMALL LETTER PSI + 0x83D6: 0x03C9, //GREEK SMALL LETTER OMEGA + 0x8440: 0x0410, //CYRILLIC CAPITAL LETTER A + 0x8441: 0x0411, //CYRILLIC CAPITAL LETTER BE + 0x8442: 0x0412, //CYRILLIC CAPITAL LETTER VE + 0x8443: 0x0413, //CYRILLIC CAPITAL LETTER GHE + 0x8444: 0x0414, //CYRILLIC CAPITAL LETTER DE + 0x8445: 0x0415, //CYRILLIC CAPITAL LETTER IE + 0x8446: 0x0401, //CYRILLIC CAPITAL LETTER IO + 0x8447: 0x0416, //CYRILLIC CAPITAL LETTER ZHE + 0x8448: 0x0417, //CYRILLIC CAPITAL LETTER ZE + 0x8449: 0x0418, //CYRILLIC CAPITAL LETTER I + 0x844A: 0x0419, //CYRILLIC CAPITAL LETTER SHORT I + 0x844B: 0x041A, //CYRILLIC CAPITAL LETTER KA + 0x844C: 0x041B, //CYRILLIC CAPITAL LETTER EL + 0x844D: 0x041C, //CYRILLIC CAPITAL LETTER EM + 0x844E: 0x041D, //CYRILLIC CAPITAL LETTER EN + 0x844F: 0x041E, //CYRILLIC CAPITAL LETTER O + 0x8450: 0x041F, //CYRILLIC CAPITAL LETTER PE + 0x8451: 0x0420, //CYRILLIC CAPITAL LETTER ER + 0x8452: 0x0421, //CYRILLIC CAPITAL LETTER ES + 0x8453: 0x0422, //CYRILLIC CAPITAL LETTER TE + 0x8454: 0x0423, //CYRILLIC CAPITAL LETTER U + 0x8455: 0x0424, //CYRILLIC CAPITAL LETTER EF + 0x8456: 0x0425, //CYRILLIC CAPITAL LETTER HA + 0x8457: 0x0426, //CYRILLIC CAPITAL LETTER TSE + 0x8458: 0x0427, //CYRILLIC CAPITAL LETTER CHE + 0x8459: 0x0428, //CYRILLIC CAPITAL LETTER SHA + 0x845A: 0x0429, //CYRILLIC CAPITAL LETTER SHCHA + 0x845B: 0x042A, //CYRILLIC CAPITAL LETTER HARD SIGN + 0x845C: 0x042B, //CYRILLIC CAPITAL LETTER YERU + 0x845D: 0x042C, //CYRILLIC CAPITAL LETTER SOFT SIGN + 0x845E: 0x042D, //CYRILLIC CAPITAL LETTER E + 0x845F: 0x042E, //CYRILLIC CAPITAL LETTER YU + 0x8460: 0x042F, //CYRILLIC CAPITAL LETTER YA + 0x8470: 0x0430, //CYRILLIC SMALL LETTER A + 0x8471: 0x0431, //CYRILLIC SMALL LETTER BE + 0x8472: 0x0432, //CYRILLIC SMALL LETTER VE + 0x8473: 0x0433, //CYRILLIC SMALL LETTER GHE + 0x8474: 0x0434, //CYRILLIC SMALL LETTER DE + 0x8475: 0x0435, //CYRILLIC SMALL LETTER IE + 0x8476: 0x0451, //CYRILLIC SMALL LETTER IO + 0x8477: 0x0436, //CYRILLIC SMALL LETTER ZHE + 0x8478: 0x0437, //CYRILLIC SMALL LETTER ZE + 0x8479: 0x0438, //CYRILLIC SMALL LETTER I + 0x847A: 0x0439, //CYRILLIC SMALL LETTER SHORT I + 0x847B: 0x043A, //CYRILLIC SMALL LETTER KA + 0x847C: 0x043B, //CYRILLIC SMALL LETTER EL + 0x847D: 0x043C, //CYRILLIC SMALL LETTER EM + 0x847E: 0x043D, //CYRILLIC SMALL LETTER EN + 0x8480: 0x043E, //CYRILLIC SMALL LETTER O + 0x8481: 0x043F, //CYRILLIC SMALL LETTER PE + 0x8482: 0x0440, //CYRILLIC SMALL LETTER ER + 0x8483: 0x0441, //CYRILLIC SMALL LETTER ES + 0x8484: 0x0442, //CYRILLIC SMALL LETTER TE + 0x8485: 0x0443, //CYRILLIC SMALL LETTER U + 0x8486: 0x0444, //CYRILLIC SMALL LETTER EF + 0x8487: 0x0445, //CYRILLIC SMALL LETTER HA + 0x8488: 0x0446, //CYRILLIC SMALL LETTER TSE + 0x8489: 0x0447, //CYRILLIC SMALL LETTER CHE + 0x848A: 0x0448, //CYRILLIC SMALL LETTER SHA + 0x848B: 0x0449, //CYRILLIC SMALL LETTER SHCHA + 0x848C: 0x044A, //CYRILLIC SMALL LETTER HARD SIGN + 0x848D: 0x044B, //CYRILLIC SMALL LETTER YERU + 0x848E: 0x044C, //CYRILLIC SMALL LETTER SOFT SIGN + 0x848F: 0x044D, //CYRILLIC SMALL LETTER E + 0x8490: 0x044E, //CYRILLIC SMALL LETTER YU + 0x8491: 0x044F, //CYRILLIC SMALL LETTER YA + 0x849F: 0x2500, //BOX DRAWINGS LIGHT HORIZONTAL + 0x84A0: 0x2502, //BOX DRAWINGS LIGHT VERTICAL + 0x84A1: 0x250C, //BOX DRAWINGS LIGHT DOWN AND RIGHT + 0x84A2: 0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT + 0x84A3: 0x2518, //BOX DRAWINGS LIGHT UP AND LEFT + 0x84A4: 0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT + 0x84A5: 0x251C, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0x84A6: 0x252C, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0x84A7: 0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0x84A8: 0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0x84A9: 0x253C, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0x84AA: 0x2501, //BOX DRAWINGS HEAVY HORIZONTAL + 0x84AB: 0x2503, //BOX DRAWINGS HEAVY VERTICAL + 0x84AC: 0x250F, //BOX DRAWINGS HEAVY DOWN AND RIGHT + 0x84AD: 0x2513, //BOX DRAWINGS HEAVY DOWN AND LEFT + 0x84AE: 0x251B, //BOX DRAWINGS HEAVY UP AND LEFT + 0x84AF: 0x2517, //BOX DRAWINGS HEAVY UP AND RIGHT + 0x84B0: 0x2523, //BOX DRAWINGS HEAVY VERTICAL AND RIGHT + 0x84B1: 0x2533, //BOX DRAWINGS HEAVY DOWN AND HORIZONTAL + 0x84B2: 0x252B, //BOX DRAWINGS HEAVY VERTICAL AND LEFT + 0x84B3: 0x253B, //BOX DRAWINGS HEAVY UP AND HORIZONTAL + 0x84B4: 0x254B, //BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL + 0x84B5: 0x2520, //BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT + 0x84B6: 0x252F, //BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY + 0x84B7: 0x2528, //BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT + 0x84B8: 0x2537, //BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY + 0x84B9: 0x253F, //BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY + 0x84BA: 0x251D, //BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY + 0x84BB: 0x2530, //BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT + 0x84BC: 0x2525, //BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY + 0x84BD: 0x2538, //BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT + 0x84BE: 0x2542, //BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT + 0x8740: 0x2460, //CIRCLED DIGIT ONE + 0x8741: 0x2461, //CIRCLED DIGIT TWO + 0x8742: 0x2462, //CIRCLED DIGIT THREE + 0x8743: 0x2463, //CIRCLED DIGIT FOUR + 0x8744: 0x2464, //CIRCLED DIGIT FIVE + 0x8745: 0x2465, //CIRCLED DIGIT SIX + 0x8746: 0x2466, //CIRCLED DIGIT SEVEN + 0x8747: 0x2467, //CIRCLED DIGIT EIGHT + 0x8748: 0x2468, //CIRCLED DIGIT NINE + 0x8749: 0x2469, //CIRCLED NUMBER TEN + 0x874A: 0x246A, //CIRCLED NUMBER ELEVEN + 0x874B: 0x246B, //CIRCLED NUMBER TWELVE + 0x874C: 0x246C, //CIRCLED NUMBER THIRTEEN + 0x874D: 0x246D, //CIRCLED NUMBER FOURTEEN + 0x874E: 0x246E, //CIRCLED NUMBER FIFTEEN + 0x874F: 0x246F, //CIRCLED NUMBER SIXTEEN + 0x8750: 0x2470, //CIRCLED NUMBER SEVENTEEN + 0x8751: 0x2471, //CIRCLED NUMBER EIGHTEEN + 0x8752: 0x2472, //CIRCLED NUMBER NINETEEN + 0x8753: 0x2473, //CIRCLED NUMBER TWENTY + 0x8754: 0x2160, //ROMAN NUMERAL ONE + 0x8755: 0x2161, //ROMAN NUMERAL TWO + 0x8756: 0x2162, //ROMAN NUMERAL THREE + 0x8757: 0x2163, //ROMAN NUMERAL FOUR + 0x8758: 0x2164, //ROMAN NUMERAL FIVE + 0x8759: 0x2165, //ROMAN NUMERAL SIX + 0x875A: 0x2166, //ROMAN NUMERAL SEVEN + 0x875B: 0x2167, //ROMAN NUMERAL EIGHT + 0x875C: 0x2168, //ROMAN NUMERAL NINE + 0x875D: 0x2169, //ROMAN NUMERAL TEN + 0x875F: 0x3349, //SQUARE MIRI + 0x8760: 0x3314, //SQUARE KIRO + 0x8761: 0x3322, //SQUARE SENTI + 0x8762: 0x334D, //SQUARE MEETORU + 0x8763: 0x3318, //SQUARE GURAMU + 0x8764: 0x3327, //SQUARE TON + 0x8765: 0x3303, //SQUARE AARU + 0x8766: 0x3336, //SQUARE HEKUTAARU + 0x8767: 0x3351, //SQUARE RITTORU + 0x8768: 0x3357, //SQUARE WATTO + 0x8769: 0x330D, //SQUARE KARORII + 0x876A: 0x3326, //SQUARE DORU + 0x876B: 0x3323, //SQUARE SENTO + 0x876C: 0x332B, //SQUARE PAASENTO + 0x876D: 0x334A, //SQUARE MIRIBAARU + 0x876E: 0x333B, //SQUARE PEEZI + 0x876F: 0x339C, //SQUARE MM + 0x8770: 0x339D, //SQUARE CM + 0x8771: 0x339E, //SQUARE KM + 0x8772: 0x338E, //SQUARE MG + 0x8773: 0x338F, //SQUARE KG + 0x8774: 0x33C4, //SQUARE CC + 0x8775: 0x33A1, //SQUARE M SQUARED + 0x877E: 0x337B, //SQUARE ERA NAME HEISEI + 0x8780: 0x301D, //REVERSED DOUBLE PRIME QUOTATION MARK + 0x8781: 0x301F, //LOW DOUBLE PRIME QUOTATION MARK + 0x8782: 0x2116, //NUMERO SIGN + 0x8783: 0x33CD, //SQUARE KK + 0x8784: 0x2121, //TELEPHONE SIGN + 0x8785: 0x32A4, //CIRCLED IDEOGRAPH HIGH + 0x8786: 0x32A5, //CIRCLED IDEOGRAPH CENTRE + 0x8787: 0x32A6, //CIRCLED IDEOGRAPH LOW + 0x8788: 0x32A7, //CIRCLED IDEOGRAPH LEFT + 0x8789: 0x32A8, //CIRCLED IDEOGRAPH RIGHT + 0x878A: 0x3231, //PARENTHESIZED IDEOGRAPH STOCK + 0x878B: 0x3232, //PARENTHESIZED IDEOGRAPH HAVE + 0x878C: 0x3239, //PARENTHESIZED IDEOGRAPH REPRESENT + 0x878D: 0x337E, //SQUARE ERA NAME MEIZI + 0x878E: 0x337D, //SQUARE ERA NAME TAISYOU + 0x878F: 0x337C, //SQUARE ERA NAME SYOUWA + 0x8790: 0x2252, //APPROXIMATELY EQUAL TO OR THE IMAGE OF + 0x8791: 0x2261, //IDENTICAL TO + 0x8792: 0x222B, //INTEGRAL + 0x8793: 0x222E, //CONTOUR INTEGRAL + 0x8794: 0x2211, //N-ARY SUMMATION + 0x8795: 0x221A, //SQUARE ROOT + 0x8796: 0x22A5, //UP TACK + 0x8797: 0x2220, //ANGLE + 0x8798: 0x221F, //RIGHT ANGLE + 0x8799: 0x22BF, //RIGHT TRIANGLE + 0x879A: 0x2235, //BECAUSE + 0x879B: 0x2229, //INTERSECTION + 0x879C: 0x222A, //UNION + 0x889F: 0x4E9C, //CJK UNIFIED IDEOGRAPH + 0x88A0: 0x5516, //CJK UNIFIED IDEOGRAPH + 0x88A1: 0x5A03, //CJK UNIFIED IDEOGRAPH + 0x88A2: 0x963F, //CJK UNIFIED IDEOGRAPH + 0x88A3: 0x54C0, //CJK UNIFIED IDEOGRAPH + 0x88A4: 0x611B, //CJK UNIFIED IDEOGRAPH + 0x88A5: 0x6328, //CJK UNIFIED IDEOGRAPH + 0x88A6: 0x59F6, //CJK UNIFIED IDEOGRAPH + 0x88A7: 0x9022, //CJK UNIFIED IDEOGRAPH + 0x88A8: 0x8475, //CJK UNIFIED IDEOGRAPH + 0x88A9: 0x831C, //CJK UNIFIED IDEOGRAPH + 0x88AA: 0x7A50, //CJK UNIFIED IDEOGRAPH + 0x88AB: 0x60AA, //CJK UNIFIED IDEOGRAPH + 0x88AC: 0x63E1, //CJK UNIFIED IDEOGRAPH + 0x88AD: 0x6E25, //CJK UNIFIED IDEOGRAPH + 0x88AE: 0x65ED, //CJK UNIFIED IDEOGRAPH + 0x88AF: 0x8466, //CJK UNIFIED IDEOGRAPH + 0x88B0: 0x82A6, //CJK UNIFIED IDEOGRAPH + 0x88B1: 0x9BF5, //CJK UNIFIED IDEOGRAPH + 0x88B2: 0x6893, //CJK UNIFIED IDEOGRAPH + 0x88B3: 0x5727, //CJK UNIFIED IDEOGRAPH + 0x88B4: 0x65A1, //CJK UNIFIED IDEOGRAPH + 0x88B5: 0x6271, //CJK UNIFIED IDEOGRAPH + 0x88B6: 0x5B9B, //CJK UNIFIED IDEOGRAPH + 0x88B7: 0x59D0, //CJK UNIFIED IDEOGRAPH + 0x88B8: 0x867B, //CJK UNIFIED IDEOGRAPH + 0x88B9: 0x98F4, //CJK UNIFIED IDEOGRAPH + 0x88BA: 0x7D62, //CJK UNIFIED IDEOGRAPH + 0x88BB: 0x7DBE, //CJK UNIFIED IDEOGRAPH + 0x88BC: 0x9B8E, //CJK UNIFIED IDEOGRAPH + 0x88BD: 0x6216, //CJK UNIFIED IDEOGRAPH + 0x88BE: 0x7C9F, //CJK UNIFIED IDEOGRAPH + 0x88BF: 0x88B7, //CJK UNIFIED IDEOGRAPH + 0x88C0: 0x5B89, //CJK UNIFIED IDEOGRAPH + 0x88C1: 0x5EB5, //CJK UNIFIED IDEOGRAPH + 0x88C2: 0x6309, //CJK UNIFIED IDEOGRAPH + 0x88C3: 0x6697, //CJK UNIFIED IDEOGRAPH + 0x88C4: 0x6848, //CJK UNIFIED IDEOGRAPH + 0x88C5: 0x95C7, //CJK UNIFIED IDEOGRAPH + 0x88C6: 0x978D, //CJK UNIFIED IDEOGRAPH + 0x88C7: 0x674F, //CJK UNIFIED IDEOGRAPH + 0x88C8: 0x4EE5, //CJK UNIFIED IDEOGRAPH + 0x88C9: 0x4F0A, //CJK UNIFIED IDEOGRAPH + 0x88CA: 0x4F4D, //CJK UNIFIED IDEOGRAPH + 0x88CB: 0x4F9D, //CJK UNIFIED IDEOGRAPH + 0x88CC: 0x5049, //CJK UNIFIED IDEOGRAPH + 0x88CD: 0x56F2, //CJK UNIFIED IDEOGRAPH + 0x88CE: 0x5937, //CJK UNIFIED IDEOGRAPH + 0x88CF: 0x59D4, //CJK UNIFIED IDEOGRAPH + 0x88D0: 0x5A01, //CJK UNIFIED IDEOGRAPH + 0x88D1: 0x5C09, //CJK UNIFIED IDEOGRAPH + 0x88D2: 0x60DF, //CJK UNIFIED IDEOGRAPH + 0x88D3: 0x610F, //CJK UNIFIED IDEOGRAPH + 0x88D4: 0x6170, //CJK UNIFIED IDEOGRAPH + 0x88D5: 0x6613, //CJK UNIFIED IDEOGRAPH + 0x88D6: 0x6905, //CJK UNIFIED IDEOGRAPH + 0x88D7: 0x70BA, //CJK UNIFIED IDEOGRAPH + 0x88D8: 0x754F, //CJK UNIFIED IDEOGRAPH + 0x88D9: 0x7570, //CJK UNIFIED IDEOGRAPH + 0x88DA: 0x79FB, //CJK UNIFIED IDEOGRAPH + 0x88DB: 0x7DAD, //CJK UNIFIED IDEOGRAPH + 0x88DC: 0x7DEF, //CJK UNIFIED IDEOGRAPH + 0x88DD: 0x80C3, //CJK UNIFIED IDEOGRAPH + 0x88DE: 0x840E, //CJK UNIFIED IDEOGRAPH + 0x88DF: 0x8863, //CJK UNIFIED IDEOGRAPH + 0x88E0: 0x8B02, //CJK UNIFIED IDEOGRAPH + 0x88E1: 0x9055, //CJK UNIFIED IDEOGRAPH + 0x88E2: 0x907A, //CJK UNIFIED IDEOGRAPH + 0x88E3: 0x533B, //CJK UNIFIED IDEOGRAPH + 0x88E4: 0x4E95, //CJK UNIFIED IDEOGRAPH + 0x88E5: 0x4EA5, //CJK UNIFIED IDEOGRAPH + 0x88E6: 0x57DF, //CJK UNIFIED IDEOGRAPH + 0x88E7: 0x80B2, //CJK UNIFIED IDEOGRAPH + 0x88E8: 0x90C1, //CJK UNIFIED IDEOGRAPH + 0x88E9: 0x78EF, //CJK UNIFIED IDEOGRAPH + 0x88EA: 0x4E00, //CJK UNIFIED IDEOGRAPH + 0x88EB: 0x58F1, //CJK UNIFIED IDEOGRAPH + 0x88EC: 0x6EA2, //CJK UNIFIED IDEOGRAPH + 0x88ED: 0x9038, //CJK UNIFIED IDEOGRAPH + 0x88EE: 0x7A32, //CJK UNIFIED IDEOGRAPH + 0x88EF: 0x8328, //CJK UNIFIED IDEOGRAPH + 0x88F0: 0x828B, //CJK UNIFIED IDEOGRAPH + 0x88F1: 0x9C2F, //CJK UNIFIED IDEOGRAPH + 0x88F2: 0x5141, //CJK UNIFIED IDEOGRAPH + 0x88F3: 0x5370, //CJK UNIFIED IDEOGRAPH + 0x88F4: 0x54BD, //CJK UNIFIED IDEOGRAPH + 0x88F5: 0x54E1, //CJK UNIFIED IDEOGRAPH + 0x88F6: 0x56E0, //CJK UNIFIED IDEOGRAPH + 0x88F7: 0x59FB, //CJK UNIFIED IDEOGRAPH + 0x88F8: 0x5F15, //CJK UNIFIED IDEOGRAPH + 0x88F9: 0x98F2, //CJK UNIFIED IDEOGRAPH + 0x88FA: 0x6DEB, //CJK UNIFIED IDEOGRAPH + 0x88FB: 0x80E4, //CJK UNIFIED IDEOGRAPH + 0x88FC: 0x852D, //CJK UNIFIED IDEOGRAPH + 0x8940: 0x9662, //CJK UNIFIED IDEOGRAPH + 0x8941: 0x9670, //CJK UNIFIED IDEOGRAPH + 0x8942: 0x96A0, //CJK UNIFIED IDEOGRAPH + 0x8943: 0x97FB, //CJK UNIFIED IDEOGRAPH + 0x8944: 0x540B, //CJK UNIFIED IDEOGRAPH + 0x8945: 0x53F3, //CJK UNIFIED IDEOGRAPH + 0x8946: 0x5B87, //CJK UNIFIED IDEOGRAPH + 0x8947: 0x70CF, //CJK UNIFIED IDEOGRAPH + 0x8948: 0x7FBD, //CJK UNIFIED IDEOGRAPH + 0x8949: 0x8FC2, //CJK UNIFIED IDEOGRAPH + 0x894A: 0x96E8, //CJK UNIFIED IDEOGRAPH + 0x894B: 0x536F, //CJK UNIFIED IDEOGRAPH + 0x894C: 0x9D5C, //CJK UNIFIED IDEOGRAPH + 0x894D: 0x7ABA, //CJK UNIFIED IDEOGRAPH + 0x894E: 0x4E11, //CJK UNIFIED IDEOGRAPH + 0x894F: 0x7893, //CJK UNIFIED IDEOGRAPH + 0x8950: 0x81FC, //CJK UNIFIED IDEOGRAPH + 0x8951: 0x6E26, //CJK UNIFIED IDEOGRAPH + 0x8952: 0x5618, //CJK UNIFIED IDEOGRAPH + 0x8953: 0x5504, //CJK UNIFIED IDEOGRAPH + 0x8954: 0x6B1D, //CJK UNIFIED IDEOGRAPH + 0x8955: 0x851A, //CJK UNIFIED IDEOGRAPH + 0x8956: 0x9C3B, //CJK UNIFIED IDEOGRAPH + 0x8957: 0x59E5, //CJK UNIFIED IDEOGRAPH + 0x8958: 0x53A9, //CJK UNIFIED IDEOGRAPH + 0x8959: 0x6D66, //CJK UNIFIED IDEOGRAPH + 0x895A: 0x74DC, //CJK UNIFIED IDEOGRAPH + 0x895B: 0x958F, //CJK UNIFIED IDEOGRAPH + 0x895C: 0x5642, //CJK UNIFIED IDEOGRAPH + 0x895D: 0x4E91, //CJK UNIFIED IDEOGRAPH + 0x895E: 0x904B, //CJK UNIFIED IDEOGRAPH + 0x895F: 0x96F2, //CJK UNIFIED IDEOGRAPH + 0x8960: 0x834F, //CJK UNIFIED IDEOGRAPH + 0x8961: 0x990C, //CJK UNIFIED IDEOGRAPH + 0x8962: 0x53E1, //CJK UNIFIED IDEOGRAPH + 0x8963: 0x55B6, //CJK UNIFIED IDEOGRAPH + 0x8964: 0x5B30, //CJK UNIFIED IDEOGRAPH + 0x8965: 0x5F71, //CJK UNIFIED IDEOGRAPH + 0x8966: 0x6620, //CJK UNIFIED IDEOGRAPH + 0x8967: 0x66F3, //CJK UNIFIED IDEOGRAPH + 0x8968: 0x6804, //CJK UNIFIED IDEOGRAPH + 0x8969: 0x6C38, //CJK UNIFIED IDEOGRAPH + 0x896A: 0x6CF3, //CJK UNIFIED IDEOGRAPH + 0x896B: 0x6D29, //CJK UNIFIED IDEOGRAPH + 0x896C: 0x745B, //CJK UNIFIED IDEOGRAPH + 0x896D: 0x76C8, //CJK UNIFIED IDEOGRAPH + 0x896E: 0x7A4E, //CJK UNIFIED IDEOGRAPH + 0x896F: 0x9834, //CJK UNIFIED IDEOGRAPH + 0x8970: 0x82F1, //CJK UNIFIED IDEOGRAPH + 0x8971: 0x885B, //CJK UNIFIED IDEOGRAPH + 0x8972: 0x8A60, //CJK UNIFIED IDEOGRAPH + 0x8973: 0x92ED, //CJK UNIFIED IDEOGRAPH + 0x8974: 0x6DB2, //CJK UNIFIED IDEOGRAPH + 0x8975: 0x75AB, //CJK UNIFIED IDEOGRAPH + 0x8976: 0x76CA, //CJK UNIFIED IDEOGRAPH + 0x8977: 0x99C5, //CJK UNIFIED IDEOGRAPH + 0x8978: 0x60A6, //CJK UNIFIED IDEOGRAPH + 0x8979: 0x8B01, //CJK UNIFIED IDEOGRAPH + 0x897A: 0x8D8A, //CJK UNIFIED IDEOGRAPH + 0x897B: 0x95B2, //CJK UNIFIED IDEOGRAPH + 0x897C: 0x698E, //CJK UNIFIED IDEOGRAPH + 0x897D: 0x53AD, //CJK UNIFIED IDEOGRAPH + 0x897E: 0x5186, //CJK UNIFIED IDEOGRAPH + 0x8980: 0x5712, //CJK UNIFIED IDEOGRAPH + 0x8981: 0x5830, //CJK UNIFIED IDEOGRAPH + 0x8982: 0x5944, //CJK UNIFIED IDEOGRAPH + 0x8983: 0x5BB4, //CJK UNIFIED IDEOGRAPH + 0x8984: 0x5EF6, //CJK UNIFIED IDEOGRAPH + 0x8985: 0x6028, //CJK UNIFIED IDEOGRAPH + 0x8986: 0x63A9, //CJK UNIFIED IDEOGRAPH + 0x8987: 0x63F4, //CJK UNIFIED IDEOGRAPH + 0x8988: 0x6CBF, //CJK UNIFIED IDEOGRAPH + 0x8989: 0x6F14, //CJK UNIFIED IDEOGRAPH + 0x898A: 0x708E, //CJK UNIFIED IDEOGRAPH + 0x898B: 0x7114, //CJK UNIFIED IDEOGRAPH + 0x898C: 0x7159, //CJK UNIFIED IDEOGRAPH + 0x898D: 0x71D5, //CJK UNIFIED IDEOGRAPH + 0x898E: 0x733F, //CJK UNIFIED IDEOGRAPH + 0x898F: 0x7E01, //CJK UNIFIED IDEOGRAPH + 0x8990: 0x8276, //CJK UNIFIED IDEOGRAPH + 0x8991: 0x82D1, //CJK UNIFIED IDEOGRAPH + 0x8992: 0x8597, //CJK UNIFIED IDEOGRAPH + 0x8993: 0x9060, //CJK UNIFIED IDEOGRAPH + 0x8994: 0x925B, //CJK UNIFIED IDEOGRAPH + 0x8995: 0x9D1B, //CJK UNIFIED IDEOGRAPH + 0x8996: 0x5869, //CJK UNIFIED IDEOGRAPH + 0x8997: 0x65BC, //CJK UNIFIED IDEOGRAPH + 0x8998: 0x6C5A, //CJK UNIFIED IDEOGRAPH + 0x8999: 0x7525, //CJK UNIFIED IDEOGRAPH + 0x899A: 0x51F9, //CJK UNIFIED IDEOGRAPH + 0x899B: 0x592E, //CJK UNIFIED IDEOGRAPH + 0x899C: 0x5965, //CJK UNIFIED IDEOGRAPH + 0x899D: 0x5F80, //CJK UNIFIED IDEOGRAPH + 0x899E: 0x5FDC, //CJK UNIFIED IDEOGRAPH + 0x899F: 0x62BC, //CJK UNIFIED IDEOGRAPH + 0x89A0: 0x65FA, //CJK UNIFIED IDEOGRAPH + 0x89A1: 0x6A2A, //CJK UNIFIED IDEOGRAPH + 0x89A2: 0x6B27, //CJK UNIFIED IDEOGRAPH + 0x89A3: 0x6BB4, //CJK UNIFIED IDEOGRAPH + 0x89A4: 0x738B, //CJK UNIFIED IDEOGRAPH + 0x89A5: 0x7FC1, //CJK UNIFIED IDEOGRAPH + 0x89A6: 0x8956, //CJK UNIFIED IDEOGRAPH + 0x89A7: 0x9D2C, //CJK UNIFIED IDEOGRAPH + 0x89A8: 0x9D0E, //CJK UNIFIED IDEOGRAPH + 0x89A9: 0x9EC4, //CJK UNIFIED IDEOGRAPH + 0x89AA: 0x5CA1, //CJK UNIFIED IDEOGRAPH + 0x89AB: 0x6C96, //CJK UNIFIED IDEOGRAPH + 0x89AC: 0x837B, //CJK UNIFIED IDEOGRAPH + 0x89AD: 0x5104, //CJK UNIFIED IDEOGRAPH + 0x89AE: 0x5C4B, //CJK UNIFIED IDEOGRAPH + 0x89AF: 0x61B6, //CJK UNIFIED IDEOGRAPH + 0x89B0: 0x81C6, //CJK UNIFIED IDEOGRAPH + 0x89B1: 0x6876, //CJK UNIFIED IDEOGRAPH + 0x89B2: 0x7261, //CJK UNIFIED IDEOGRAPH + 0x89B3: 0x4E59, //CJK UNIFIED IDEOGRAPH + 0x89B4: 0x4FFA, //CJK UNIFIED IDEOGRAPH + 0x89B5: 0x5378, //CJK UNIFIED IDEOGRAPH + 0x89B6: 0x6069, //CJK UNIFIED IDEOGRAPH + 0x89B7: 0x6E29, //CJK UNIFIED IDEOGRAPH + 0x89B8: 0x7A4F, //CJK UNIFIED IDEOGRAPH + 0x89B9: 0x97F3, //CJK UNIFIED IDEOGRAPH + 0x89BA: 0x4E0B, //CJK UNIFIED IDEOGRAPH + 0x89BB: 0x5316, //CJK UNIFIED IDEOGRAPH + 0x89BC: 0x4EEE, //CJK UNIFIED IDEOGRAPH + 0x89BD: 0x4F55, //CJK UNIFIED IDEOGRAPH + 0x89BE: 0x4F3D, //CJK UNIFIED IDEOGRAPH + 0x89BF: 0x4FA1, //CJK UNIFIED IDEOGRAPH + 0x89C0: 0x4F73, //CJK UNIFIED IDEOGRAPH + 0x89C1: 0x52A0, //CJK UNIFIED IDEOGRAPH + 0x89C2: 0x53EF, //CJK UNIFIED IDEOGRAPH + 0x89C3: 0x5609, //CJK UNIFIED IDEOGRAPH + 0x89C4: 0x590F, //CJK UNIFIED IDEOGRAPH + 0x89C5: 0x5AC1, //CJK UNIFIED IDEOGRAPH + 0x89C6: 0x5BB6, //CJK UNIFIED IDEOGRAPH + 0x89C7: 0x5BE1, //CJK UNIFIED IDEOGRAPH + 0x89C8: 0x79D1, //CJK UNIFIED IDEOGRAPH + 0x89C9: 0x6687, //CJK UNIFIED IDEOGRAPH + 0x89CA: 0x679C, //CJK UNIFIED IDEOGRAPH + 0x89CB: 0x67B6, //CJK UNIFIED IDEOGRAPH + 0x89CC: 0x6B4C, //CJK UNIFIED IDEOGRAPH + 0x89CD: 0x6CB3, //CJK UNIFIED IDEOGRAPH + 0x89CE: 0x706B, //CJK UNIFIED IDEOGRAPH + 0x89CF: 0x73C2, //CJK UNIFIED IDEOGRAPH + 0x89D0: 0x798D, //CJK UNIFIED IDEOGRAPH + 0x89D1: 0x79BE, //CJK UNIFIED IDEOGRAPH + 0x89D2: 0x7A3C, //CJK UNIFIED IDEOGRAPH + 0x89D3: 0x7B87, //CJK UNIFIED IDEOGRAPH + 0x89D4: 0x82B1, //CJK UNIFIED IDEOGRAPH + 0x89D5: 0x82DB, //CJK UNIFIED IDEOGRAPH + 0x89D6: 0x8304, //CJK UNIFIED IDEOGRAPH + 0x89D7: 0x8377, //CJK UNIFIED IDEOGRAPH + 0x89D8: 0x83EF, //CJK UNIFIED IDEOGRAPH + 0x89D9: 0x83D3, //CJK UNIFIED IDEOGRAPH + 0x89DA: 0x8766, //CJK UNIFIED IDEOGRAPH + 0x89DB: 0x8AB2, //CJK UNIFIED IDEOGRAPH + 0x89DC: 0x5629, //CJK UNIFIED IDEOGRAPH + 0x89DD: 0x8CA8, //CJK UNIFIED IDEOGRAPH + 0x89DE: 0x8FE6, //CJK UNIFIED IDEOGRAPH + 0x89DF: 0x904E, //CJK UNIFIED IDEOGRAPH + 0x89E0: 0x971E, //CJK UNIFIED IDEOGRAPH + 0x89E1: 0x868A, //CJK UNIFIED IDEOGRAPH + 0x89E2: 0x4FC4, //CJK UNIFIED IDEOGRAPH + 0x89E3: 0x5CE8, //CJK UNIFIED IDEOGRAPH + 0x89E4: 0x6211, //CJK UNIFIED IDEOGRAPH + 0x89E5: 0x7259, //CJK UNIFIED IDEOGRAPH + 0x89E6: 0x753B, //CJK UNIFIED IDEOGRAPH + 0x89E7: 0x81E5, //CJK UNIFIED IDEOGRAPH + 0x89E8: 0x82BD, //CJK UNIFIED IDEOGRAPH + 0x89E9: 0x86FE, //CJK UNIFIED IDEOGRAPH + 0x89EA: 0x8CC0, //CJK UNIFIED IDEOGRAPH + 0x89EB: 0x96C5, //CJK UNIFIED IDEOGRAPH + 0x89EC: 0x9913, //CJK UNIFIED IDEOGRAPH + 0x89ED: 0x99D5, //CJK UNIFIED IDEOGRAPH + 0x89EE: 0x4ECB, //CJK UNIFIED IDEOGRAPH + 0x89EF: 0x4F1A, //CJK UNIFIED IDEOGRAPH + 0x89F0: 0x89E3, //CJK UNIFIED IDEOGRAPH + 0x89F1: 0x56DE, //CJK UNIFIED IDEOGRAPH + 0x89F2: 0x584A, //CJK UNIFIED IDEOGRAPH + 0x89F3: 0x58CA, //CJK UNIFIED IDEOGRAPH + 0x89F4: 0x5EFB, //CJK UNIFIED IDEOGRAPH + 0x89F5: 0x5FEB, //CJK UNIFIED IDEOGRAPH + 0x89F6: 0x602A, //CJK UNIFIED IDEOGRAPH + 0x89F7: 0x6094, //CJK UNIFIED IDEOGRAPH + 0x89F8: 0x6062, //CJK UNIFIED IDEOGRAPH + 0x89F9: 0x61D0, //CJK UNIFIED IDEOGRAPH + 0x89FA: 0x6212, //CJK UNIFIED IDEOGRAPH + 0x89FB: 0x62D0, //CJK UNIFIED IDEOGRAPH + 0x89FC: 0x6539, //CJK UNIFIED IDEOGRAPH + 0x8A40: 0x9B41, //CJK UNIFIED IDEOGRAPH + 0x8A41: 0x6666, //CJK UNIFIED IDEOGRAPH + 0x8A42: 0x68B0, //CJK UNIFIED IDEOGRAPH + 0x8A43: 0x6D77, //CJK UNIFIED IDEOGRAPH + 0x8A44: 0x7070, //CJK UNIFIED IDEOGRAPH + 0x8A45: 0x754C, //CJK UNIFIED IDEOGRAPH + 0x8A46: 0x7686, //CJK UNIFIED IDEOGRAPH + 0x8A47: 0x7D75, //CJK UNIFIED IDEOGRAPH + 0x8A48: 0x82A5, //CJK UNIFIED IDEOGRAPH + 0x8A49: 0x87F9, //CJK UNIFIED IDEOGRAPH + 0x8A4A: 0x958B, //CJK UNIFIED IDEOGRAPH + 0x8A4B: 0x968E, //CJK UNIFIED IDEOGRAPH + 0x8A4C: 0x8C9D, //CJK UNIFIED IDEOGRAPH + 0x8A4D: 0x51F1, //CJK UNIFIED IDEOGRAPH + 0x8A4E: 0x52BE, //CJK UNIFIED IDEOGRAPH + 0x8A4F: 0x5916, //CJK UNIFIED IDEOGRAPH + 0x8A50: 0x54B3, //CJK UNIFIED IDEOGRAPH + 0x8A51: 0x5BB3, //CJK UNIFIED IDEOGRAPH + 0x8A52: 0x5D16, //CJK UNIFIED IDEOGRAPH + 0x8A53: 0x6168, //CJK UNIFIED IDEOGRAPH + 0x8A54: 0x6982, //CJK UNIFIED IDEOGRAPH + 0x8A55: 0x6DAF, //CJK UNIFIED IDEOGRAPH + 0x8A56: 0x788D, //CJK UNIFIED IDEOGRAPH + 0x8A57: 0x84CB, //CJK UNIFIED IDEOGRAPH + 0x8A58: 0x8857, //CJK UNIFIED IDEOGRAPH + 0x8A59: 0x8A72, //CJK UNIFIED IDEOGRAPH + 0x8A5A: 0x93A7, //CJK UNIFIED IDEOGRAPH + 0x8A5B: 0x9AB8, //CJK UNIFIED IDEOGRAPH + 0x8A5C: 0x6D6C, //CJK UNIFIED IDEOGRAPH + 0x8A5D: 0x99A8, //CJK UNIFIED IDEOGRAPH + 0x8A5E: 0x86D9, //CJK UNIFIED IDEOGRAPH + 0x8A5F: 0x57A3, //CJK UNIFIED IDEOGRAPH + 0x8A60: 0x67FF, //CJK UNIFIED IDEOGRAPH + 0x8A61: 0x86CE, //CJK UNIFIED IDEOGRAPH + 0x8A62: 0x920E, //CJK UNIFIED IDEOGRAPH + 0x8A63: 0x5283, //CJK UNIFIED IDEOGRAPH + 0x8A64: 0x5687, //CJK UNIFIED IDEOGRAPH + 0x8A65: 0x5404, //CJK UNIFIED IDEOGRAPH + 0x8A66: 0x5ED3, //CJK UNIFIED IDEOGRAPH + 0x8A67: 0x62E1, //CJK UNIFIED IDEOGRAPH + 0x8A68: 0x64B9, //CJK UNIFIED IDEOGRAPH + 0x8A69: 0x683C, //CJK UNIFIED IDEOGRAPH + 0x8A6A: 0x6838, //CJK UNIFIED IDEOGRAPH + 0x8A6B: 0x6BBB, //CJK UNIFIED IDEOGRAPH + 0x8A6C: 0x7372, //CJK UNIFIED IDEOGRAPH + 0x8A6D: 0x78BA, //CJK UNIFIED IDEOGRAPH + 0x8A6E: 0x7A6B, //CJK UNIFIED IDEOGRAPH + 0x8A6F: 0x899A, //CJK UNIFIED IDEOGRAPH + 0x8A70: 0x89D2, //CJK UNIFIED IDEOGRAPH + 0x8A71: 0x8D6B, //CJK UNIFIED IDEOGRAPH + 0x8A72: 0x8F03, //CJK UNIFIED IDEOGRAPH + 0x8A73: 0x90ED, //CJK UNIFIED IDEOGRAPH + 0x8A74: 0x95A3, //CJK UNIFIED IDEOGRAPH + 0x8A75: 0x9694, //CJK UNIFIED IDEOGRAPH + 0x8A76: 0x9769, //CJK UNIFIED IDEOGRAPH + 0x8A77: 0x5B66, //CJK UNIFIED IDEOGRAPH + 0x8A78: 0x5CB3, //CJK UNIFIED IDEOGRAPH + 0x8A79: 0x697D, //CJK UNIFIED IDEOGRAPH + 0x8A7A: 0x984D, //CJK UNIFIED IDEOGRAPH + 0x8A7B: 0x984E, //CJK UNIFIED IDEOGRAPH + 0x8A7C: 0x639B, //CJK UNIFIED IDEOGRAPH + 0x8A7D: 0x7B20, //CJK UNIFIED IDEOGRAPH + 0x8A7E: 0x6A2B, //CJK UNIFIED IDEOGRAPH + 0x8A80: 0x6A7F, //CJK UNIFIED IDEOGRAPH + 0x8A81: 0x68B6, //CJK UNIFIED IDEOGRAPH + 0x8A82: 0x9C0D, //CJK UNIFIED IDEOGRAPH + 0x8A83: 0x6F5F, //CJK UNIFIED IDEOGRAPH + 0x8A84: 0x5272, //CJK UNIFIED IDEOGRAPH + 0x8A85: 0x559D, //CJK UNIFIED IDEOGRAPH + 0x8A86: 0x6070, //CJK UNIFIED IDEOGRAPH + 0x8A87: 0x62EC, //CJK UNIFIED IDEOGRAPH + 0x8A88: 0x6D3B, //CJK UNIFIED IDEOGRAPH + 0x8A89: 0x6E07, //CJK UNIFIED IDEOGRAPH + 0x8A8A: 0x6ED1, //CJK UNIFIED IDEOGRAPH + 0x8A8B: 0x845B, //CJK UNIFIED IDEOGRAPH + 0x8A8C: 0x8910, //CJK UNIFIED IDEOGRAPH + 0x8A8D: 0x8F44, //CJK UNIFIED IDEOGRAPH + 0x8A8E: 0x4E14, //CJK UNIFIED IDEOGRAPH + 0x8A8F: 0x9C39, //CJK UNIFIED IDEOGRAPH + 0x8A90: 0x53F6, //CJK UNIFIED IDEOGRAPH + 0x8A91: 0x691B, //CJK UNIFIED IDEOGRAPH + 0x8A92: 0x6A3A, //CJK UNIFIED IDEOGRAPH + 0x8A93: 0x9784, //CJK UNIFIED IDEOGRAPH + 0x8A94: 0x682A, //CJK UNIFIED IDEOGRAPH + 0x8A95: 0x515C, //CJK UNIFIED IDEOGRAPH + 0x8A96: 0x7AC3, //CJK UNIFIED IDEOGRAPH + 0x8A97: 0x84B2, //CJK UNIFIED IDEOGRAPH + 0x8A98: 0x91DC, //CJK UNIFIED IDEOGRAPH + 0x8A99: 0x938C, //CJK UNIFIED IDEOGRAPH + 0x8A9A: 0x565B, //CJK UNIFIED IDEOGRAPH + 0x8A9B: 0x9D28, //CJK UNIFIED IDEOGRAPH + 0x8A9C: 0x6822, //CJK UNIFIED IDEOGRAPH + 0x8A9D: 0x8305, //CJK UNIFIED IDEOGRAPH + 0x8A9E: 0x8431, //CJK UNIFIED IDEOGRAPH + 0x8A9F: 0x7CA5, //CJK UNIFIED IDEOGRAPH + 0x8AA0: 0x5208, //CJK UNIFIED IDEOGRAPH + 0x8AA1: 0x82C5, //CJK UNIFIED IDEOGRAPH + 0x8AA2: 0x74E6, //CJK UNIFIED IDEOGRAPH + 0x8AA3: 0x4E7E, //CJK UNIFIED IDEOGRAPH + 0x8AA4: 0x4F83, //CJK UNIFIED IDEOGRAPH + 0x8AA5: 0x51A0, //CJK UNIFIED IDEOGRAPH + 0x8AA6: 0x5BD2, //CJK UNIFIED IDEOGRAPH + 0x8AA7: 0x520A, //CJK UNIFIED IDEOGRAPH + 0x8AA8: 0x52D8, //CJK UNIFIED IDEOGRAPH + 0x8AA9: 0x52E7, //CJK UNIFIED IDEOGRAPH + 0x8AAA: 0x5DFB, //CJK UNIFIED IDEOGRAPH + 0x8AAB: 0x559A, //CJK UNIFIED IDEOGRAPH + 0x8AAC: 0x582A, //CJK UNIFIED IDEOGRAPH + 0x8AAD: 0x59E6, //CJK UNIFIED IDEOGRAPH + 0x8AAE: 0x5B8C, //CJK UNIFIED IDEOGRAPH + 0x8AAF: 0x5B98, //CJK UNIFIED IDEOGRAPH + 0x8AB0: 0x5BDB, //CJK UNIFIED IDEOGRAPH + 0x8AB1: 0x5E72, //CJK UNIFIED IDEOGRAPH + 0x8AB2: 0x5E79, //CJK UNIFIED IDEOGRAPH + 0x8AB3: 0x60A3, //CJK UNIFIED IDEOGRAPH + 0x8AB4: 0x611F, //CJK UNIFIED IDEOGRAPH + 0x8AB5: 0x6163, //CJK UNIFIED IDEOGRAPH + 0x8AB6: 0x61BE, //CJK UNIFIED IDEOGRAPH + 0x8AB7: 0x63DB, //CJK UNIFIED IDEOGRAPH + 0x8AB8: 0x6562, //CJK UNIFIED IDEOGRAPH + 0x8AB9: 0x67D1, //CJK UNIFIED IDEOGRAPH + 0x8ABA: 0x6853, //CJK UNIFIED IDEOGRAPH + 0x8ABB: 0x68FA, //CJK UNIFIED IDEOGRAPH + 0x8ABC: 0x6B3E, //CJK UNIFIED IDEOGRAPH + 0x8ABD: 0x6B53, //CJK UNIFIED IDEOGRAPH + 0x8ABE: 0x6C57, //CJK UNIFIED IDEOGRAPH + 0x8ABF: 0x6F22, //CJK UNIFIED IDEOGRAPH + 0x8AC0: 0x6F97, //CJK UNIFIED IDEOGRAPH + 0x8AC1: 0x6F45, //CJK UNIFIED IDEOGRAPH + 0x8AC2: 0x74B0, //CJK UNIFIED IDEOGRAPH + 0x8AC3: 0x7518, //CJK UNIFIED IDEOGRAPH + 0x8AC4: 0x76E3, //CJK UNIFIED IDEOGRAPH + 0x8AC5: 0x770B, //CJK UNIFIED IDEOGRAPH + 0x8AC6: 0x7AFF, //CJK UNIFIED IDEOGRAPH + 0x8AC7: 0x7BA1, //CJK UNIFIED IDEOGRAPH + 0x8AC8: 0x7C21, //CJK UNIFIED IDEOGRAPH + 0x8AC9: 0x7DE9, //CJK UNIFIED IDEOGRAPH + 0x8ACA: 0x7F36, //CJK UNIFIED IDEOGRAPH + 0x8ACB: 0x7FF0, //CJK UNIFIED IDEOGRAPH + 0x8ACC: 0x809D, //CJK UNIFIED IDEOGRAPH + 0x8ACD: 0x8266, //CJK UNIFIED IDEOGRAPH + 0x8ACE: 0x839E, //CJK UNIFIED IDEOGRAPH + 0x8ACF: 0x89B3, //CJK UNIFIED IDEOGRAPH + 0x8AD0: 0x8ACC, //CJK UNIFIED IDEOGRAPH + 0x8AD1: 0x8CAB, //CJK UNIFIED IDEOGRAPH + 0x8AD2: 0x9084, //CJK UNIFIED IDEOGRAPH + 0x8AD3: 0x9451, //CJK UNIFIED IDEOGRAPH + 0x8AD4: 0x9593, //CJK UNIFIED IDEOGRAPH + 0x8AD5: 0x9591, //CJK UNIFIED IDEOGRAPH + 0x8AD6: 0x95A2, //CJK UNIFIED IDEOGRAPH + 0x8AD7: 0x9665, //CJK UNIFIED IDEOGRAPH + 0x8AD8: 0x97D3, //CJK UNIFIED IDEOGRAPH + 0x8AD9: 0x9928, //CJK UNIFIED IDEOGRAPH + 0x8ADA: 0x8218, //CJK UNIFIED IDEOGRAPH + 0x8ADB: 0x4E38, //CJK UNIFIED IDEOGRAPH + 0x8ADC: 0x542B, //CJK UNIFIED IDEOGRAPH + 0x8ADD: 0x5CB8, //CJK UNIFIED IDEOGRAPH + 0x8ADE: 0x5DCC, //CJK UNIFIED IDEOGRAPH + 0x8ADF: 0x73A9, //CJK UNIFIED IDEOGRAPH + 0x8AE0: 0x764C, //CJK UNIFIED IDEOGRAPH + 0x8AE1: 0x773C, //CJK UNIFIED IDEOGRAPH + 0x8AE2: 0x5CA9, //CJK UNIFIED IDEOGRAPH + 0x8AE3: 0x7FEB, //CJK UNIFIED IDEOGRAPH + 0x8AE4: 0x8D0B, //CJK UNIFIED IDEOGRAPH + 0x8AE5: 0x96C1, //CJK UNIFIED IDEOGRAPH + 0x8AE6: 0x9811, //CJK UNIFIED IDEOGRAPH + 0x8AE7: 0x9854, //CJK UNIFIED IDEOGRAPH + 0x8AE8: 0x9858, //CJK UNIFIED IDEOGRAPH + 0x8AE9: 0x4F01, //CJK UNIFIED IDEOGRAPH + 0x8AEA: 0x4F0E, //CJK UNIFIED IDEOGRAPH + 0x8AEB: 0x5371, //CJK UNIFIED IDEOGRAPH + 0x8AEC: 0x559C, //CJK UNIFIED IDEOGRAPH + 0x8AED: 0x5668, //CJK UNIFIED IDEOGRAPH + 0x8AEE: 0x57FA, //CJK UNIFIED IDEOGRAPH + 0x8AEF: 0x5947, //CJK UNIFIED IDEOGRAPH + 0x8AF0: 0x5B09, //CJK UNIFIED IDEOGRAPH + 0x8AF1: 0x5BC4, //CJK UNIFIED IDEOGRAPH + 0x8AF2: 0x5C90, //CJK UNIFIED IDEOGRAPH + 0x8AF3: 0x5E0C, //CJK UNIFIED IDEOGRAPH + 0x8AF4: 0x5E7E, //CJK UNIFIED IDEOGRAPH + 0x8AF5: 0x5FCC, //CJK UNIFIED IDEOGRAPH + 0x8AF6: 0x63EE, //CJK UNIFIED IDEOGRAPH + 0x8AF7: 0x673A, //CJK UNIFIED IDEOGRAPH + 0x8AF8: 0x65D7, //CJK UNIFIED IDEOGRAPH + 0x8AF9: 0x65E2, //CJK UNIFIED IDEOGRAPH + 0x8AFA: 0x671F, //CJK UNIFIED IDEOGRAPH + 0x8AFB: 0x68CB, //CJK UNIFIED IDEOGRAPH + 0x8AFC: 0x68C4, //CJK UNIFIED IDEOGRAPH + 0x8B40: 0x6A5F, //CJK UNIFIED IDEOGRAPH + 0x8B41: 0x5E30, //CJK UNIFIED IDEOGRAPH + 0x8B42: 0x6BC5, //CJK UNIFIED IDEOGRAPH + 0x8B43: 0x6C17, //CJK UNIFIED IDEOGRAPH + 0x8B44: 0x6C7D, //CJK UNIFIED IDEOGRAPH + 0x8B45: 0x757F, //CJK UNIFIED IDEOGRAPH + 0x8B46: 0x7948, //CJK UNIFIED IDEOGRAPH + 0x8B47: 0x5B63, //CJK UNIFIED IDEOGRAPH + 0x8B48: 0x7A00, //CJK UNIFIED IDEOGRAPH + 0x8B49: 0x7D00, //CJK UNIFIED IDEOGRAPH + 0x8B4A: 0x5FBD, //CJK UNIFIED IDEOGRAPH + 0x8B4B: 0x898F, //CJK UNIFIED IDEOGRAPH + 0x8B4C: 0x8A18, //CJK UNIFIED IDEOGRAPH + 0x8B4D: 0x8CB4, //CJK UNIFIED IDEOGRAPH + 0x8B4E: 0x8D77, //CJK UNIFIED IDEOGRAPH + 0x8B4F: 0x8ECC, //CJK UNIFIED IDEOGRAPH + 0x8B50: 0x8F1D, //CJK UNIFIED IDEOGRAPH + 0x8B51: 0x98E2, //CJK UNIFIED IDEOGRAPH + 0x8B52: 0x9A0E, //CJK UNIFIED IDEOGRAPH + 0x8B53: 0x9B3C, //CJK UNIFIED IDEOGRAPH + 0x8B54: 0x4E80, //CJK UNIFIED IDEOGRAPH + 0x8B55: 0x507D, //CJK UNIFIED IDEOGRAPH + 0x8B56: 0x5100, //CJK UNIFIED IDEOGRAPH + 0x8B57: 0x5993, //CJK UNIFIED IDEOGRAPH + 0x8B58: 0x5B9C, //CJK UNIFIED IDEOGRAPH + 0x8B59: 0x622F, //CJK UNIFIED IDEOGRAPH + 0x8B5A: 0x6280, //CJK UNIFIED IDEOGRAPH + 0x8B5B: 0x64EC, //CJK UNIFIED IDEOGRAPH + 0x8B5C: 0x6B3A, //CJK UNIFIED IDEOGRAPH + 0x8B5D: 0x72A0, //CJK UNIFIED IDEOGRAPH + 0x8B5E: 0x7591, //CJK UNIFIED IDEOGRAPH + 0x8B5F: 0x7947, //CJK UNIFIED IDEOGRAPH + 0x8B60: 0x7FA9, //CJK UNIFIED IDEOGRAPH + 0x8B61: 0x87FB, //CJK UNIFIED IDEOGRAPH + 0x8B62: 0x8ABC, //CJK UNIFIED IDEOGRAPH + 0x8B63: 0x8B70, //CJK UNIFIED IDEOGRAPH + 0x8B64: 0x63AC, //CJK UNIFIED IDEOGRAPH + 0x8B65: 0x83CA, //CJK UNIFIED IDEOGRAPH + 0x8B66: 0x97A0, //CJK UNIFIED IDEOGRAPH + 0x8B67: 0x5409, //CJK UNIFIED IDEOGRAPH + 0x8B68: 0x5403, //CJK UNIFIED IDEOGRAPH + 0x8B69: 0x55AB, //CJK UNIFIED IDEOGRAPH + 0x8B6A: 0x6854, //CJK UNIFIED IDEOGRAPH + 0x8B6B: 0x6A58, //CJK UNIFIED IDEOGRAPH + 0x8B6C: 0x8A70, //CJK UNIFIED IDEOGRAPH + 0x8B6D: 0x7827, //CJK UNIFIED IDEOGRAPH + 0x8B6E: 0x6775, //CJK UNIFIED IDEOGRAPH + 0x8B6F: 0x9ECD, //CJK UNIFIED IDEOGRAPH + 0x8B70: 0x5374, //CJK UNIFIED IDEOGRAPH + 0x8B71: 0x5BA2, //CJK UNIFIED IDEOGRAPH + 0x8B72: 0x811A, //CJK UNIFIED IDEOGRAPH + 0x8B73: 0x8650, //CJK UNIFIED IDEOGRAPH + 0x8B74: 0x9006, //CJK UNIFIED IDEOGRAPH + 0x8B75: 0x4E18, //CJK UNIFIED IDEOGRAPH + 0x8B76: 0x4E45, //CJK UNIFIED IDEOGRAPH + 0x8B77: 0x4EC7, //CJK UNIFIED IDEOGRAPH + 0x8B78: 0x4F11, //CJK UNIFIED IDEOGRAPH + 0x8B79: 0x53CA, //CJK UNIFIED IDEOGRAPH + 0x8B7A: 0x5438, //CJK UNIFIED IDEOGRAPH + 0x8B7B: 0x5BAE, //CJK UNIFIED IDEOGRAPH + 0x8B7C: 0x5F13, //CJK UNIFIED IDEOGRAPH + 0x8B7D: 0x6025, //CJK UNIFIED IDEOGRAPH + 0x8B7E: 0x6551, //CJK UNIFIED IDEOGRAPH + 0x8B80: 0x673D, //CJK UNIFIED IDEOGRAPH + 0x8B81: 0x6C42, //CJK UNIFIED IDEOGRAPH + 0x8B82: 0x6C72, //CJK UNIFIED IDEOGRAPH + 0x8B83: 0x6CE3, //CJK UNIFIED IDEOGRAPH + 0x8B84: 0x7078, //CJK UNIFIED IDEOGRAPH + 0x8B85: 0x7403, //CJK UNIFIED IDEOGRAPH + 0x8B86: 0x7A76, //CJK UNIFIED IDEOGRAPH + 0x8B87: 0x7AAE, //CJK UNIFIED IDEOGRAPH + 0x8B88: 0x7B08, //CJK UNIFIED IDEOGRAPH + 0x8B89: 0x7D1A, //CJK UNIFIED IDEOGRAPH + 0x8B8A: 0x7CFE, //CJK UNIFIED IDEOGRAPH + 0x8B8B: 0x7D66, //CJK UNIFIED IDEOGRAPH + 0x8B8C: 0x65E7, //CJK UNIFIED IDEOGRAPH + 0x8B8D: 0x725B, //CJK UNIFIED IDEOGRAPH + 0x8B8E: 0x53BB, //CJK UNIFIED IDEOGRAPH + 0x8B8F: 0x5C45, //CJK UNIFIED IDEOGRAPH + 0x8B90: 0x5DE8, //CJK UNIFIED IDEOGRAPH + 0x8B91: 0x62D2, //CJK UNIFIED IDEOGRAPH + 0x8B92: 0x62E0, //CJK UNIFIED IDEOGRAPH + 0x8B93: 0x6319, //CJK UNIFIED IDEOGRAPH + 0x8B94: 0x6E20, //CJK UNIFIED IDEOGRAPH + 0x8B95: 0x865A, //CJK UNIFIED IDEOGRAPH + 0x8B96: 0x8A31, //CJK UNIFIED IDEOGRAPH + 0x8B97: 0x8DDD, //CJK UNIFIED IDEOGRAPH + 0x8B98: 0x92F8, //CJK UNIFIED IDEOGRAPH + 0x8B99: 0x6F01, //CJK UNIFIED IDEOGRAPH + 0x8B9A: 0x79A6, //CJK UNIFIED IDEOGRAPH + 0x8B9B: 0x9B5A, //CJK UNIFIED IDEOGRAPH + 0x8B9C: 0x4EA8, //CJK UNIFIED IDEOGRAPH + 0x8B9D: 0x4EAB, //CJK UNIFIED IDEOGRAPH + 0x8B9E: 0x4EAC, //CJK UNIFIED IDEOGRAPH + 0x8B9F: 0x4F9B, //CJK UNIFIED IDEOGRAPH + 0x8BA0: 0x4FA0, //CJK UNIFIED IDEOGRAPH + 0x8BA1: 0x50D1, //CJK UNIFIED IDEOGRAPH + 0x8BA2: 0x5147, //CJK UNIFIED IDEOGRAPH + 0x8BA3: 0x7AF6, //CJK UNIFIED IDEOGRAPH + 0x8BA4: 0x5171, //CJK UNIFIED IDEOGRAPH + 0x8BA5: 0x51F6, //CJK UNIFIED IDEOGRAPH + 0x8BA6: 0x5354, //CJK UNIFIED IDEOGRAPH + 0x8BA7: 0x5321, //CJK UNIFIED IDEOGRAPH + 0x8BA8: 0x537F, //CJK UNIFIED IDEOGRAPH + 0x8BA9: 0x53EB, //CJK UNIFIED IDEOGRAPH + 0x8BAA: 0x55AC, //CJK UNIFIED IDEOGRAPH + 0x8BAB: 0x5883, //CJK UNIFIED IDEOGRAPH + 0x8BAC: 0x5CE1, //CJK UNIFIED IDEOGRAPH + 0x8BAD: 0x5F37, //CJK UNIFIED IDEOGRAPH + 0x8BAE: 0x5F4A, //CJK UNIFIED IDEOGRAPH + 0x8BAF: 0x602F, //CJK UNIFIED IDEOGRAPH + 0x8BB0: 0x6050, //CJK UNIFIED IDEOGRAPH + 0x8BB1: 0x606D, //CJK UNIFIED IDEOGRAPH + 0x8BB2: 0x631F, //CJK UNIFIED IDEOGRAPH + 0x8BB3: 0x6559, //CJK UNIFIED IDEOGRAPH + 0x8BB4: 0x6A4B, //CJK UNIFIED IDEOGRAPH + 0x8BB5: 0x6CC1, //CJK UNIFIED IDEOGRAPH + 0x8BB6: 0x72C2, //CJK UNIFIED IDEOGRAPH + 0x8BB7: 0x72ED, //CJK UNIFIED IDEOGRAPH + 0x8BB8: 0x77EF, //CJK UNIFIED IDEOGRAPH + 0x8BB9: 0x80F8, //CJK UNIFIED IDEOGRAPH + 0x8BBA: 0x8105, //CJK UNIFIED IDEOGRAPH + 0x8BBB: 0x8208, //CJK UNIFIED IDEOGRAPH + 0x8BBC: 0x854E, //CJK UNIFIED IDEOGRAPH + 0x8BBD: 0x90F7, //CJK UNIFIED IDEOGRAPH + 0x8BBE: 0x93E1, //CJK UNIFIED IDEOGRAPH + 0x8BBF: 0x97FF, //CJK UNIFIED IDEOGRAPH + 0x8BC0: 0x9957, //CJK UNIFIED IDEOGRAPH + 0x8BC1: 0x9A5A, //CJK UNIFIED IDEOGRAPH + 0x8BC2: 0x4EF0, //CJK UNIFIED IDEOGRAPH + 0x8BC3: 0x51DD, //CJK UNIFIED IDEOGRAPH + 0x8BC4: 0x5C2D, //CJK UNIFIED IDEOGRAPH + 0x8BC5: 0x6681, //CJK UNIFIED IDEOGRAPH + 0x8BC6: 0x696D, //CJK UNIFIED IDEOGRAPH + 0x8BC7: 0x5C40, //CJK UNIFIED IDEOGRAPH + 0x8BC8: 0x66F2, //CJK UNIFIED IDEOGRAPH + 0x8BC9: 0x6975, //CJK UNIFIED IDEOGRAPH + 0x8BCA: 0x7389, //CJK UNIFIED IDEOGRAPH + 0x8BCB: 0x6850, //CJK UNIFIED IDEOGRAPH + 0x8BCC: 0x7C81, //CJK UNIFIED IDEOGRAPH + 0x8BCD: 0x50C5, //CJK UNIFIED IDEOGRAPH + 0x8BCE: 0x52E4, //CJK UNIFIED IDEOGRAPH + 0x8BCF: 0x5747, //CJK UNIFIED IDEOGRAPH + 0x8BD0: 0x5DFE, //CJK UNIFIED IDEOGRAPH + 0x8BD1: 0x9326, //CJK UNIFIED IDEOGRAPH + 0x8BD2: 0x65A4, //CJK UNIFIED IDEOGRAPH + 0x8BD3: 0x6B23, //CJK UNIFIED IDEOGRAPH + 0x8BD4: 0x6B3D, //CJK UNIFIED IDEOGRAPH + 0x8BD5: 0x7434, //CJK UNIFIED IDEOGRAPH + 0x8BD6: 0x7981, //CJK UNIFIED IDEOGRAPH + 0x8BD7: 0x79BD, //CJK UNIFIED IDEOGRAPH + 0x8BD8: 0x7B4B, //CJK UNIFIED IDEOGRAPH + 0x8BD9: 0x7DCA, //CJK UNIFIED IDEOGRAPH + 0x8BDA: 0x82B9, //CJK UNIFIED IDEOGRAPH + 0x8BDB: 0x83CC, //CJK UNIFIED IDEOGRAPH + 0x8BDC: 0x887F, //CJK UNIFIED IDEOGRAPH + 0x8BDD: 0x895F, //CJK UNIFIED IDEOGRAPH + 0x8BDE: 0x8B39, //CJK UNIFIED IDEOGRAPH + 0x8BDF: 0x8FD1, //CJK UNIFIED IDEOGRAPH + 0x8BE0: 0x91D1, //CJK UNIFIED IDEOGRAPH + 0x8BE1: 0x541F, //CJK UNIFIED IDEOGRAPH + 0x8BE2: 0x9280, //CJK UNIFIED IDEOGRAPH + 0x8BE3: 0x4E5D, //CJK UNIFIED IDEOGRAPH + 0x8BE4: 0x5036, //CJK UNIFIED IDEOGRAPH + 0x8BE5: 0x53E5, //CJK UNIFIED IDEOGRAPH + 0x8BE6: 0x533A, //CJK UNIFIED IDEOGRAPH + 0x8BE7: 0x72D7, //CJK UNIFIED IDEOGRAPH + 0x8BE8: 0x7396, //CJK UNIFIED IDEOGRAPH + 0x8BE9: 0x77E9, //CJK UNIFIED IDEOGRAPH + 0x8BEA: 0x82E6, //CJK UNIFIED IDEOGRAPH + 0x8BEB: 0x8EAF, //CJK UNIFIED IDEOGRAPH + 0x8BEC: 0x99C6, //CJK UNIFIED IDEOGRAPH + 0x8BED: 0x99C8, //CJK UNIFIED IDEOGRAPH + 0x8BEE: 0x99D2, //CJK UNIFIED IDEOGRAPH + 0x8BEF: 0x5177, //CJK UNIFIED IDEOGRAPH + 0x8BF0: 0x611A, //CJK UNIFIED IDEOGRAPH + 0x8BF1: 0x865E, //CJK UNIFIED IDEOGRAPH + 0x8BF2: 0x55B0, //CJK UNIFIED IDEOGRAPH + 0x8BF3: 0x7A7A, //CJK UNIFIED IDEOGRAPH + 0x8BF4: 0x5076, //CJK UNIFIED IDEOGRAPH + 0x8BF5: 0x5BD3, //CJK UNIFIED IDEOGRAPH + 0x8BF6: 0x9047, //CJK UNIFIED IDEOGRAPH + 0x8BF7: 0x9685, //CJK UNIFIED IDEOGRAPH + 0x8BF8: 0x4E32, //CJK UNIFIED IDEOGRAPH + 0x8BF9: 0x6ADB, //CJK UNIFIED IDEOGRAPH + 0x8BFA: 0x91E7, //CJK UNIFIED IDEOGRAPH + 0x8BFB: 0x5C51, //CJK UNIFIED IDEOGRAPH + 0x8BFC: 0x5C48, //CJK UNIFIED IDEOGRAPH + 0x8C40: 0x6398, //CJK UNIFIED IDEOGRAPH + 0x8C41: 0x7A9F, //CJK UNIFIED IDEOGRAPH + 0x8C42: 0x6C93, //CJK UNIFIED IDEOGRAPH + 0x8C43: 0x9774, //CJK UNIFIED IDEOGRAPH + 0x8C44: 0x8F61, //CJK UNIFIED IDEOGRAPH + 0x8C45: 0x7AAA, //CJK UNIFIED IDEOGRAPH + 0x8C46: 0x718A, //CJK UNIFIED IDEOGRAPH + 0x8C47: 0x9688, //CJK UNIFIED IDEOGRAPH + 0x8C48: 0x7C82, //CJK UNIFIED IDEOGRAPH + 0x8C49: 0x6817, //CJK UNIFIED IDEOGRAPH + 0x8C4A: 0x7E70, //CJK UNIFIED IDEOGRAPH + 0x8C4B: 0x6851, //CJK UNIFIED IDEOGRAPH + 0x8C4C: 0x936C, //CJK UNIFIED IDEOGRAPH + 0x8C4D: 0x52F2, //CJK UNIFIED IDEOGRAPH + 0x8C4E: 0x541B, //CJK UNIFIED IDEOGRAPH + 0x8C4F: 0x85AB, //CJK UNIFIED IDEOGRAPH + 0x8C50: 0x8A13, //CJK UNIFIED IDEOGRAPH + 0x8C51: 0x7FA4, //CJK UNIFIED IDEOGRAPH + 0x8C52: 0x8ECD, //CJK UNIFIED IDEOGRAPH + 0x8C53: 0x90E1, //CJK UNIFIED IDEOGRAPH + 0x8C54: 0x5366, //CJK UNIFIED IDEOGRAPH + 0x8C55: 0x8888, //CJK UNIFIED IDEOGRAPH + 0x8C56: 0x7941, //CJK UNIFIED IDEOGRAPH + 0x8C57: 0x4FC2, //CJK UNIFIED IDEOGRAPH + 0x8C58: 0x50BE, //CJK UNIFIED IDEOGRAPH + 0x8C59: 0x5211, //CJK UNIFIED IDEOGRAPH + 0x8C5A: 0x5144, //CJK UNIFIED IDEOGRAPH + 0x8C5B: 0x5553, //CJK UNIFIED IDEOGRAPH + 0x8C5C: 0x572D, //CJK UNIFIED IDEOGRAPH + 0x8C5D: 0x73EA, //CJK UNIFIED IDEOGRAPH + 0x8C5E: 0x578B, //CJK UNIFIED IDEOGRAPH + 0x8C5F: 0x5951, //CJK UNIFIED IDEOGRAPH + 0x8C60: 0x5F62, //CJK UNIFIED IDEOGRAPH + 0x8C61: 0x5F84, //CJK UNIFIED IDEOGRAPH + 0x8C62: 0x6075, //CJK UNIFIED IDEOGRAPH + 0x8C63: 0x6176, //CJK UNIFIED IDEOGRAPH + 0x8C64: 0x6167, //CJK UNIFIED IDEOGRAPH + 0x8C65: 0x61A9, //CJK UNIFIED IDEOGRAPH + 0x8C66: 0x63B2, //CJK UNIFIED IDEOGRAPH + 0x8C67: 0x643A, //CJK UNIFIED IDEOGRAPH + 0x8C68: 0x656C, //CJK UNIFIED IDEOGRAPH + 0x8C69: 0x666F, //CJK UNIFIED IDEOGRAPH + 0x8C6A: 0x6842, //CJK UNIFIED IDEOGRAPH + 0x8C6B: 0x6E13, //CJK UNIFIED IDEOGRAPH + 0x8C6C: 0x7566, //CJK UNIFIED IDEOGRAPH + 0x8C6D: 0x7A3D, //CJK UNIFIED IDEOGRAPH + 0x8C6E: 0x7CFB, //CJK UNIFIED IDEOGRAPH + 0x8C6F: 0x7D4C, //CJK UNIFIED IDEOGRAPH + 0x8C70: 0x7D99, //CJK UNIFIED IDEOGRAPH + 0x8C71: 0x7E4B, //CJK UNIFIED IDEOGRAPH + 0x8C72: 0x7F6B, //CJK UNIFIED IDEOGRAPH + 0x8C73: 0x830E, //CJK UNIFIED IDEOGRAPH + 0x8C74: 0x834A, //CJK UNIFIED IDEOGRAPH + 0x8C75: 0x86CD, //CJK UNIFIED IDEOGRAPH + 0x8C76: 0x8A08, //CJK UNIFIED IDEOGRAPH + 0x8C77: 0x8A63, //CJK UNIFIED IDEOGRAPH + 0x8C78: 0x8B66, //CJK UNIFIED IDEOGRAPH + 0x8C79: 0x8EFD, //CJK UNIFIED IDEOGRAPH + 0x8C7A: 0x981A, //CJK UNIFIED IDEOGRAPH + 0x8C7B: 0x9D8F, //CJK UNIFIED IDEOGRAPH + 0x8C7C: 0x82B8, //CJK UNIFIED IDEOGRAPH + 0x8C7D: 0x8FCE, //CJK UNIFIED IDEOGRAPH + 0x8C7E: 0x9BE8, //CJK UNIFIED IDEOGRAPH + 0x8C80: 0x5287, //CJK UNIFIED IDEOGRAPH + 0x8C81: 0x621F, //CJK UNIFIED IDEOGRAPH + 0x8C82: 0x6483, //CJK UNIFIED IDEOGRAPH + 0x8C83: 0x6FC0, //CJK UNIFIED IDEOGRAPH + 0x8C84: 0x9699, //CJK UNIFIED IDEOGRAPH + 0x8C85: 0x6841, //CJK UNIFIED IDEOGRAPH + 0x8C86: 0x5091, //CJK UNIFIED IDEOGRAPH + 0x8C87: 0x6B20, //CJK UNIFIED IDEOGRAPH + 0x8C88: 0x6C7A, //CJK UNIFIED IDEOGRAPH + 0x8C89: 0x6F54, //CJK UNIFIED IDEOGRAPH + 0x8C8A: 0x7A74, //CJK UNIFIED IDEOGRAPH + 0x8C8B: 0x7D50, //CJK UNIFIED IDEOGRAPH + 0x8C8C: 0x8840, //CJK UNIFIED IDEOGRAPH + 0x8C8D: 0x8A23, //CJK UNIFIED IDEOGRAPH + 0x8C8E: 0x6708, //CJK UNIFIED IDEOGRAPH + 0x8C8F: 0x4EF6, //CJK UNIFIED IDEOGRAPH + 0x8C90: 0x5039, //CJK UNIFIED IDEOGRAPH + 0x8C91: 0x5026, //CJK UNIFIED IDEOGRAPH + 0x8C92: 0x5065, //CJK UNIFIED IDEOGRAPH + 0x8C93: 0x517C, //CJK UNIFIED IDEOGRAPH + 0x8C94: 0x5238, //CJK UNIFIED IDEOGRAPH + 0x8C95: 0x5263, //CJK UNIFIED IDEOGRAPH + 0x8C96: 0x55A7, //CJK UNIFIED IDEOGRAPH + 0x8C97: 0x570F, //CJK UNIFIED IDEOGRAPH + 0x8C98: 0x5805, //CJK UNIFIED IDEOGRAPH + 0x8C99: 0x5ACC, //CJK UNIFIED IDEOGRAPH + 0x8C9A: 0x5EFA, //CJK UNIFIED IDEOGRAPH + 0x8C9B: 0x61B2, //CJK UNIFIED IDEOGRAPH + 0x8C9C: 0x61F8, //CJK UNIFIED IDEOGRAPH + 0x8C9D: 0x62F3, //CJK UNIFIED IDEOGRAPH + 0x8C9E: 0x6372, //CJK UNIFIED IDEOGRAPH + 0x8C9F: 0x691C, //CJK UNIFIED IDEOGRAPH + 0x8CA0: 0x6A29, //CJK UNIFIED IDEOGRAPH + 0x8CA1: 0x727D, //CJK UNIFIED IDEOGRAPH + 0x8CA2: 0x72AC, //CJK UNIFIED IDEOGRAPH + 0x8CA3: 0x732E, //CJK UNIFIED IDEOGRAPH + 0x8CA4: 0x7814, //CJK UNIFIED IDEOGRAPH + 0x8CA5: 0x786F, //CJK UNIFIED IDEOGRAPH + 0x8CA6: 0x7D79, //CJK UNIFIED IDEOGRAPH + 0x8CA7: 0x770C, //CJK UNIFIED IDEOGRAPH + 0x8CA8: 0x80A9, //CJK UNIFIED IDEOGRAPH + 0x8CA9: 0x898B, //CJK UNIFIED IDEOGRAPH + 0x8CAA: 0x8B19, //CJK UNIFIED IDEOGRAPH + 0x8CAB: 0x8CE2, //CJK UNIFIED IDEOGRAPH + 0x8CAC: 0x8ED2, //CJK UNIFIED IDEOGRAPH + 0x8CAD: 0x9063, //CJK UNIFIED IDEOGRAPH + 0x8CAE: 0x9375, //CJK UNIFIED IDEOGRAPH + 0x8CAF: 0x967A, //CJK UNIFIED IDEOGRAPH + 0x8CB0: 0x9855, //CJK UNIFIED IDEOGRAPH + 0x8CB1: 0x9A13, //CJK UNIFIED IDEOGRAPH + 0x8CB2: 0x9E78, //CJK UNIFIED IDEOGRAPH + 0x8CB3: 0x5143, //CJK UNIFIED IDEOGRAPH + 0x8CB4: 0x539F, //CJK UNIFIED IDEOGRAPH + 0x8CB5: 0x53B3, //CJK UNIFIED IDEOGRAPH + 0x8CB6: 0x5E7B, //CJK UNIFIED IDEOGRAPH + 0x8CB7: 0x5F26, //CJK UNIFIED IDEOGRAPH + 0x8CB8: 0x6E1B, //CJK UNIFIED IDEOGRAPH + 0x8CB9: 0x6E90, //CJK UNIFIED IDEOGRAPH + 0x8CBA: 0x7384, //CJK UNIFIED IDEOGRAPH + 0x8CBB: 0x73FE, //CJK UNIFIED IDEOGRAPH + 0x8CBC: 0x7D43, //CJK UNIFIED IDEOGRAPH + 0x8CBD: 0x8237, //CJK UNIFIED IDEOGRAPH + 0x8CBE: 0x8A00, //CJK UNIFIED IDEOGRAPH + 0x8CBF: 0x8AFA, //CJK UNIFIED IDEOGRAPH + 0x8CC0: 0x9650, //CJK UNIFIED IDEOGRAPH + 0x8CC1: 0x4E4E, //CJK UNIFIED IDEOGRAPH + 0x8CC2: 0x500B, //CJK UNIFIED IDEOGRAPH + 0x8CC3: 0x53E4, //CJK UNIFIED IDEOGRAPH + 0x8CC4: 0x547C, //CJK UNIFIED IDEOGRAPH + 0x8CC5: 0x56FA, //CJK UNIFIED IDEOGRAPH + 0x8CC6: 0x59D1, //CJK UNIFIED IDEOGRAPH + 0x8CC7: 0x5B64, //CJK UNIFIED IDEOGRAPH + 0x8CC8: 0x5DF1, //CJK UNIFIED IDEOGRAPH + 0x8CC9: 0x5EAB, //CJK UNIFIED IDEOGRAPH + 0x8CCA: 0x5F27, //CJK UNIFIED IDEOGRAPH + 0x8CCB: 0x6238, //CJK UNIFIED IDEOGRAPH + 0x8CCC: 0x6545, //CJK UNIFIED IDEOGRAPH + 0x8CCD: 0x67AF, //CJK UNIFIED IDEOGRAPH + 0x8CCE: 0x6E56, //CJK UNIFIED IDEOGRAPH + 0x8CCF: 0x72D0, //CJK UNIFIED IDEOGRAPH + 0x8CD0: 0x7CCA, //CJK UNIFIED IDEOGRAPH + 0x8CD1: 0x88B4, //CJK UNIFIED IDEOGRAPH + 0x8CD2: 0x80A1, //CJK UNIFIED IDEOGRAPH + 0x8CD3: 0x80E1, //CJK UNIFIED IDEOGRAPH + 0x8CD4: 0x83F0, //CJK UNIFIED IDEOGRAPH + 0x8CD5: 0x864E, //CJK UNIFIED IDEOGRAPH + 0x8CD6: 0x8A87, //CJK UNIFIED IDEOGRAPH + 0x8CD7: 0x8DE8, //CJK UNIFIED IDEOGRAPH + 0x8CD8: 0x9237, //CJK UNIFIED IDEOGRAPH + 0x8CD9: 0x96C7, //CJK UNIFIED IDEOGRAPH + 0x8CDA: 0x9867, //CJK UNIFIED IDEOGRAPH + 0x8CDB: 0x9F13, //CJK UNIFIED IDEOGRAPH + 0x8CDC: 0x4E94, //CJK UNIFIED IDEOGRAPH + 0x8CDD: 0x4E92, //CJK UNIFIED IDEOGRAPH + 0x8CDE: 0x4F0D, //CJK UNIFIED IDEOGRAPH + 0x8CDF: 0x5348, //CJK UNIFIED IDEOGRAPH + 0x8CE0: 0x5449, //CJK UNIFIED IDEOGRAPH + 0x8CE1: 0x543E, //CJK UNIFIED IDEOGRAPH + 0x8CE2: 0x5A2F, //CJK UNIFIED IDEOGRAPH + 0x8CE3: 0x5F8C, //CJK UNIFIED IDEOGRAPH + 0x8CE4: 0x5FA1, //CJK UNIFIED IDEOGRAPH + 0x8CE5: 0x609F, //CJK UNIFIED IDEOGRAPH + 0x8CE6: 0x68A7, //CJK UNIFIED IDEOGRAPH + 0x8CE7: 0x6A8E, //CJK UNIFIED IDEOGRAPH + 0x8CE8: 0x745A, //CJK UNIFIED IDEOGRAPH + 0x8CE9: 0x7881, //CJK UNIFIED IDEOGRAPH + 0x8CEA: 0x8A9E, //CJK UNIFIED IDEOGRAPH + 0x8CEB: 0x8AA4, //CJK UNIFIED IDEOGRAPH + 0x8CEC: 0x8B77, //CJK UNIFIED IDEOGRAPH + 0x8CED: 0x9190, //CJK UNIFIED IDEOGRAPH + 0x8CEE: 0x4E5E, //CJK UNIFIED IDEOGRAPH + 0x8CEF: 0x9BC9, //CJK UNIFIED IDEOGRAPH + 0x8CF0: 0x4EA4, //CJK UNIFIED IDEOGRAPH + 0x8CF1: 0x4F7C, //CJK UNIFIED IDEOGRAPH + 0x8CF2: 0x4FAF, //CJK UNIFIED IDEOGRAPH + 0x8CF3: 0x5019, //CJK UNIFIED IDEOGRAPH + 0x8CF4: 0x5016, //CJK UNIFIED IDEOGRAPH + 0x8CF5: 0x5149, //CJK UNIFIED IDEOGRAPH + 0x8CF6: 0x516C, //CJK UNIFIED IDEOGRAPH + 0x8CF7: 0x529F, //CJK UNIFIED IDEOGRAPH + 0x8CF8: 0x52B9, //CJK UNIFIED IDEOGRAPH + 0x8CF9: 0x52FE, //CJK UNIFIED IDEOGRAPH + 0x8CFA: 0x539A, //CJK UNIFIED IDEOGRAPH + 0x8CFB: 0x53E3, //CJK UNIFIED IDEOGRAPH + 0x8CFC: 0x5411, //CJK UNIFIED IDEOGRAPH + 0x8D40: 0x540E, //CJK UNIFIED IDEOGRAPH + 0x8D41: 0x5589, //CJK UNIFIED IDEOGRAPH + 0x8D42: 0x5751, //CJK UNIFIED IDEOGRAPH + 0x8D43: 0x57A2, //CJK UNIFIED IDEOGRAPH + 0x8D44: 0x597D, //CJK UNIFIED IDEOGRAPH + 0x8D45: 0x5B54, //CJK UNIFIED IDEOGRAPH + 0x8D46: 0x5B5D, //CJK UNIFIED IDEOGRAPH + 0x8D47: 0x5B8F, //CJK UNIFIED IDEOGRAPH + 0x8D48: 0x5DE5, //CJK UNIFIED IDEOGRAPH + 0x8D49: 0x5DE7, //CJK UNIFIED IDEOGRAPH + 0x8D4A: 0x5DF7, //CJK UNIFIED IDEOGRAPH + 0x8D4B: 0x5E78, //CJK UNIFIED IDEOGRAPH + 0x8D4C: 0x5E83, //CJK UNIFIED IDEOGRAPH + 0x8D4D: 0x5E9A, //CJK UNIFIED IDEOGRAPH + 0x8D4E: 0x5EB7, //CJK UNIFIED IDEOGRAPH + 0x8D4F: 0x5F18, //CJK UNIFIED IDEOGRAPH + 0x8D50: 0x6052, //CJK UNIFIED IDEOGRAPH + 0x8D51: 0x614C, //CJK UNIFIED IDEOGRAPH + 0x8D52: 0x6297, //CJK UNIFIED IDEOGRAPH + 0x8D53: 0x62D8, //CJK UNIFIED IDEOGRAPH + 0x8D54: 0x63A7, //CJK UNIFIED IDEOGRAPH + 0x8D55: 0x653B, //CJK UNIFIED IDEOGRAPH + 0x8D56: 0x6602, //CJK UNIFIED IDEOGRAPH + 0x8D57: 0x6643, //CJK UNIFIED IDEOGRAPH + 0x8D58: 0x66F4, //CJK UNIFIED IDEOGRAPH + 0x8D59: 0x676D, //CJK UNIFIED IDEOGRAPH + 0x8D5A: 0x6821, //CJK UNIFIED IDEOGRAPH + 0x8D5B: 0x6897, //CJK UNIFIED IDEOGRAPH + 0x8D5C: 0x69CB, //CJK UNIFIED IDEOGRAPH + 0x8D5D: 0x6C5F, //CJK UNIFIED IDEOGRAPH + 0x8D5E: 0x6D2A, //CJK UNIFIED IDEOGRAPH + 0x8D5F: 0x6D69, //CJK UNIFIED IDEOGRAPH + 0x8D60: 0x6E2F, //CJK UNIFIED IDEOGRAPH + 0x8D61: 0x6E9D, //CJK UNIFIED IDEOGRAPH + 0x8D62: 0x7532, //CJK UNIFIED IDEOGRAPH + 0x8D63: 0x7687, //CJK UNIFIED IDEOGRAPH + 0x8D64: 0x786C, //CJK UNIFIED IDEOGRAPH + 0x8D65: 0x7A3F, //CJK UNIFIED IDEOGRAPH + 0x8D66: 0x7CE0, //CJK UNIFIED IDEOGRAPH + 0x8D67: 0x7D05, //CJK UNIFIED IDEOGRAPH + 0x8D68: 0x7D18, //CJK UNIFIED IDEOGRAPH + 0x8D69: 0x7D5E, //CJK UNIFIED IDEOGRAPH + 0x8D6A: 0x7DB1, //CJK UNIFIED IDEOGRAPH + 0x8D6B: 0x8015, //CJK UNIFIED IDEOGRAPH + 0x8D6C: 0x8003, //CJK UNIFIED IDEOGRAPH + 0x8D6D: 0x80AF, //CJK UNIFIED IDEOGRAPH + 0x8D6E: 0x80B1, //CJK UNIFIED IDEOGRAPH + 0x8D6F: 0x8154, //CJK UNIFIED IDEOGRAPH + 0x8D70: 0x818F, //CJK UNIFIED IDEOGRAPH + 0x8D71: 0x822A, //CJK UNIFIED IDEOGRAPH + 0x8D72: 0x8352, //CJK UNIFIED IDEOGRAPH + 0x8D73: 0x884C, //CJK UNIFIED IDEOGRAPH + 0x8D74: 0x8861, //CJK UNIFIED IDEOGRAPH + 0x8D75: 0x8B1B, //CJK UNIFIED IDEOGRAPH + 0x8D76: 0x8CA2, //CJK UNIFIED IDEOGRAPH + 0x8D77: 0x8CFC, //CJK UNIFIED IDEOGRAPH + 0x8D78: 0x90CA, //CJK UNIFIED IDEOGRAPH + 0x8D79: 0x9175, //CJK UNIFIED IDEOGRAPH + 0x8D7A: 0x9271, //CJK UNIFIED IDEOGRAPH + 0x8D7B: 0x783F, //CJK UNIFIED IDEOGRAPH + 0x8D7C: 0x92FC, //CJK UNIFIED IDEOGRAPH + 0x8D7D: 0x95A4, //CJK UNIFIED IDEOGRAPH + 0x8D7E: 0x964D, //CJK UNIFIED IDEOGRAPH + 0x8D80: 0x9805, //CJK UNIFIED IDEOGRAPH + 0x8D81: 0x9999, //CJK UNIFIED IDEOGRAPH + 0x8D82: 0x9AD8, //CJK UNIFIED IDEOGRAPH + 0x8D83: 0x9D3B, //CJK UNIFIED IDEOGRAPH + 0x8D84: 0x525B, //CJK UNIFIED IDEOGRAPH + 0x8D85: 0x52AB, //CJK UNIFIED IDEOGRAPH + 0x8D86: 0x53F7, //CJK UNIFIED IDEOGRAPH + 0x8D87: 0x5408, //CJK UNIFIED IDEOGRAPH + 0x8D88: 0x58D5, //CJK UNIFIED IDEOGRAPH + 0x8D89: 0x62F7, //CJK UNIFIED IDEOGRAPH + 0x8D8A: 0x6FE0, //CJK UNIFIED IDEOGRAPH + 0x8D8B: 0x8C6A, //CJK UNIFIED IDEOGRAPH + 0x8D8C: 0x8F5F, //CJK UNIFIED IDEOGRAPH + 0x8D8D: 0x9EB9, //CJK UNIFIED IDEOGRAPH + 0x8D8E: 0x514B, //CJK UNIFIED IDEOGRAPH + 0x8D8F: 0x523B, //CJK UNIFIED IDEOGRAPH + 0x8D90: 0x544A, //CJK UNIFIED IDEOGRAPH + 0x8D91: 0x56FD, //CJK UNIFIED IDEOGRAPH + 0x8D92: 0x7A40, //CJK UNIFIED IDEOGRAPH + 0x8D93: 0x9177, //CJK UNIFIED IDEOGRAPH + 0x8D94: 0x9D60, //CJK UNIFIED IDEOGRAPH + 0x8D95: 0x9ED2, //CJK UNIFIED IDEOGRAPH + 0x8D96: 0x7344, //CJK UNIFIED IDEOGRAPH + 0x8D97: 0x6F09, //CJK UNIFIED IDEOGRAPH + 0x8D98: 0x8170, //CJK UNIFIED IDEOGRAPH + 0x8D99: 0x7511, //CJK UNIFIED IDEOGRAPH + 0x8D9A: 0x5FFD, //CJK UNIFIED IDEOGRAPH + 0x8D9B: 0x60DA, //CJK UNIFIED IDEOGRAPH + 0x8D9C: 0x9AA8, //CJK UNIFIED IDEOGRAPH + 0x8D9D: 0x72DB, //CJK UNIFIED IDEOGRAPH + 0x8D9E: 0x8FBC, //CJK UNIFIED IDEOGRAPH + 0x8D9F: 0x6B64, //CJK UNIFIED IDEOGRAPH + 0x8DA0: 0x9803, //CJK UNIFIED IDEOGRAPH + 0x8DA1: 0x4ECA, //CJK UNIFIED IDEOGRAPH + 0x8DA2: 0x56F0, //CJK UNIFIED IDEOGRAPH + 0x8DA3: 0x5764, //CJK UNIFIED IDEOGRAPH + 0x8DA4: 0x58BE, //CJK UNIFIED IDEOGRAPH + 0x8DA5: 0x5A5A, //CJK UNIFIED IDEOGRAPH + 0x8DA6: 0x6068, //CJK UNIFIED IDEOGRAPH + 0x8DA7: 0x61C7, //CJK UNIFIED IDEOGRAPH + 0x8DA8: 0x660F, //CJK UNIFIED IDEOGRAPH + 0x8DA9: 0x6606, //CJK UNIFIED IDEOGRAPH + 0x8DAA: 0x6839, //CJK UNIFIED IDEOGRAPH + 0x8DAB: 0x68B1, //CJK UNIFIED IDEOGRAPH + 0x8DAC: 0x6DF7, //CJK UNIFIED IDEOGRAPH + 0x8DAD: 0x75D5, //CJK UNIFIED IDEOGRAPH + 0x8DAE: 0x7D3A, //CJK UNIFIED IDEOGRAPH + 0x8DAF: 0x826E, //CJK UNIFIED IDEOGRAPH + 0x8DB0: 0x9B42, //CJK UNIFIED IDEOGRAPH + 0x8DB1: 0x4E9B, //CJK UNIFIED IDEOGRAPH + 0x8DB2: 0x4F50, //CJK UNIFIED IDEOGRAPH + 0x8DB3: 0x53C9, //CJK UNIFIED IDEOGRAPH + 0x8DB4: 0x5506, //CJK UNIFIED IDEOGRAPH + 0x8DB5: 0x5D6F, //CJK UNIFIED IDEOGRAPH + 0x8DB6: 0x5DE6, //CJK UNIFIED IDEOGRAPH + 0x8DB7: 0x5DEE, //CJK UNIFIED IDEOGRAPH + 0x8DB8: 0x67FB, //CJK UNIFIED IDEOGRAPH + 0x8DB9: 0x6C99, //CJK UNIFIED IDEOGRAPH + 0x8DBA: 0x7473, //CJK UNIFIED IDEOGRAPH + 0x8DBB: 0x7802, //CJK UNIFIED IDEOGRAPH + 0x8DBC: 0x8A50, //CJK UNIFIED IDEOGRAPH + 0x8DBD: 0x9396, //CJK UNIFIED IDEOGRAPH + 0x8DBE: 0x88DF, //CJK UNIFIED IDEOGRAPH + 0x8DBF: 0x5750, //CJK UNIFIED IDEOGRAPH + 0x8DC0: 0x5EA7, //CJK UNIFIED IDEOGRAPH + 0x8DC1: 0x632B, //CJK UNIFIED IDEOGRAPH + 0x8DC2: 0x50B5, //CJK UNIFIED IDEOGRAPH + 0x8DC3: 0x50AC, //CJK UNIFIED IDEOGRAPH + 0x8DC4: 0x518D, //CJK UNIFIED IDEOGRAPH + 0x8DC5: 0x6700, //CJK UNIFIED IDEOGRAPH + 0x8DC6: 0x54C9, //CJK UNIFIED IDEOGRAPH + 0x8DC7: 0x585E, //CJK UNIFIED IDEOGRAPH + 0x8DC8: 0x59BB, //CJK UNIFIED IDEOGRAPH + 0x8DC9: 0x5BB0, //CJK UNIFIED IDEOGRAPH + 0x8DCA: 0x5F69, //CJK UNIFIED IDEOGRAPH + 0x8DCB: 0x624D, //CJK UNIFIED IDEOGRAPH + 0x8DCC: 0x63A1, //CJK UNIFIED IDEOGRAPH + 0x8DCD: 0x683D, //CJK UNIFIED IDEOGRAPH + 0x8DCE: 0x6B73, //CJK UNIFIED IDEOGRAPH + 0x8DCF: 0x6E08, //CJK UNIFIED IDEOGRAPH + 0x8DD0: 0x707D, //CJK UNIFIED IDEOGRAPH + 0x8DD1: 0x91C7, //CJK UNIFIED IDEOGRAPH + 0x8DD2: 0x7280, //CJK UNIFIED IDEOGRAPH + 0x8DD3: 0x7815, //CJK UNIFIED IDEOGRAPH + 0x8DD4: 0x7826, //CJK UNIFIED IDEOGRAPH + 0x8DD5: 0x796D, //CJK UNIFIED IDEOGRAPH + 0x8DD6: 0x658E, //CJK UNIFIED IDEOGRAPH + 0x8DD7: 0x7D30, //CJK UNIFIED IDEOGRAPH + 0x8DD8: 0x83DC, //CJK UNIFIED IDEOGRAPH + 0x8DD9: 0x88C1, //CJK UNIFIED IDEOGRAPH + 0x8DDA: 0x8F09, //CJK UNIFIED IDEOGRAPH + 0x8DDB: 0x969B, //CJK UNIFIED IDEOGRAPH + 0x8DDC: 0x5264, //CJK UNIFIED IDEOGRAPH + 0x8DDD: 0x5728, //CJK UNIFIED IDEOGRAPH + 0x8DDE: 0x6750, //CJK UNIFIED IDEOGRAPH + 0x8DDF: 0x7F6A, //CJK UNIFIED IDEOGRAPH + 0x8DE0: 0x8CA1, //CJK UNIFIED IDEOGRAPH + 0x8DE1: 0x51B4, //CJK UNIFIED IDEOGRAPH + 0x8DE2: 0x5742, //CJK UNIFIED IDEOGRAPH + 0x8DE3: 0x962A, //CJK UNIFIED IDEOGRAPH + 0x8DE4: 0x583A, //CJK UNIFIED IDEOGRAPH + 0x8DE5: 0x698A, //CJK UNIFIED IDEOGRAPH + 0x8DE6: 0x80B4, //CJK UNIFIED IDEOGRAPH + 0x8DE7: 0x54B2, //CJK UNIFIED IDEOGRAPH + 0x8DE8: 0x5D0E, //CJK UNIFIED IDEOGRAPH + 0x8DE9: 0x57FC, //CJK UNIFIED IDEOGRAPH + 0x8DEA: 0x7895, //CJK UNIFIED IDEOGRAPH + 0x8DEB: 0x9DFA, //CJK UNIFIED IDEOGRAPH + 0x8DEC: 0x4F5C, //CJK UNIFIED IDEOGRAPH + 0x8DED: 0x524A, //CJK UNIFIED IDEOGRAPH + 0x8DEE: 0x548B, //CJK UNIFIED IDEOGRAPH + 0x8DEF: 0x643E, //CJK UNIFIED IDEOGRAPH + 0x8DF0: 0x6628, //CJK UNIFIED IDEOGRAPH + 0x8DF1: 0x6714, //CJK UNIFIED IDEOGRAPH + 0x8DF2: 0x67F5, //CJK UNIFIED IDEOGRAPH + 0x8DF3: 0x7A84, //CJK UNIFIED IDEOGRAPH + 0x8DF4: 0x7B56, //CJK UNIFIED IDEOGRAPH + 0x8DF5: 0x7D22, //CJK UNIFIED IDEOGRAPH + 0x8DF6: 0x932F, //CJK UNIFIED IDEOGRAPH + 0x8DF7: 0x685C, //CJK UNIFIED IDEOGRAPH + 0x8DF8: 0x9BAD, //CJK UNIFIED IDEOGRAPH + 0x8DF9: 0x7B39, //CJK UNIFIED IDEOGRAPH + 0x8DFA: 0x5319, //CJK UNIFIED IDEOGRAPH + 0x8DFB: 0x518A, //CJK UNIFIED IDEOGRAPH + 0x8DFC: 0x5237, //CJK UNIFIED IDEOGRAPH + 0x8E40: 0x5BDF, //CJK UNIFIED IDEOGRAPH + 0x8E41: 0x62F6, //CJK UNIFIED IDEOGRAPH + 0x8E42: 0x64AE, //CJK UNIFIED IDEOGRAPH + 0x8E43: 0x64E6, //CJK UNIFIED IDEOGRAPH + 0x8E44: 0x672D, //CJK UNIFIED IDEOGRAPH + 0x8E45: 0x6BBA, //CJK UNIFIED IDEOGRAPH + 0x8E46: 0x85A9, //CJK UNIFIED IDEOGRAPH + 0x8E47: 0x96D1, //CJK UNIFIED IDEOGRAPH + 0x8E48: 0x7690, //CJK UNIFIED IDEOGRAPH + 0x8E49: 0x9BD6, //CJK UNIFIED IDEOGRAPH + 0x8E4A: 0x634C, //CJK UNIFIED IDEOGRAPH + 0x8E4B: 0x9306, //CJK UNIFIED IDEOGRAPH + 0x8E4C: 0x9BAB, //CJK UNIFIED IDEOGRAPH + 0x8E4D: 0x76BF, //CJK UNIFIED IDEOGRAPH + 0x8E4E: 0x6652, //CJK UNIFIED IDEOGRAPH + 0x8E4F: 0x4E09, //CJK UNIFIED IDEOGRAPH + 0x8E50: 0x5098, //CJK UNIFIED IDEOGRAPH + 0x8E51: 0x53C2, //CJK UNIFIED IDEOGRAPH + 0x8E52: 0x5C71, //CJK UNIFIED IDEOGRAPH + 0x8E53: 0x60E8, //CJK UNIFIED IDEOGRAPH + 0x8E54: 0x6492, //CJK UNIFIED IDEOGRAPH + 0x8E55: 0x6563, //CJK UNIFIED IDEOGRAPH + 0x8E56: 0x685F, //CJK UNIFIED IDEOGRAPH + 0x8E57: 0x71E6, //CJK UNIFIED IDEOGRAPH + 0x8E58: 0x73CA, //CJK UNIFIED IDEOGRAPH + 0x8E59: 0x7523, //CJK UNIFIED IDEOGRAPH + 0x8E5A: 0x7B97, //CJK UNIFIED IDEOGRAPH + 0x8E5B: 0x7E82, //CJK UNIFIED IDEOGRAPH + 0x8E5C: 0x8695, //CJK UNIFIED IDEOGRAPH + 0x8E5D: 0x8B83, //CJK UNIFIED IDEOGRAPH + 0x8E5E: 0x8CDB, //CJK UNIFIED IDEOGRAPH + 0x8E5F: 0x9178, //CJK UNIFIED IDEOGRAPH + 0x8E60: 0x9910, //CJK UNIFIED IDEOGRAPH + 0x8E61: 0x65AC, //CJK UNIFIED IDEOGRAPH + 0x8E62: 0x66AB, //CJK UNIFIED IDEOGRAPH + 0x8E63: 0x6B8B, //CJK UNIFIED IDEOGRAPH + 0x8E64: 0x4ED5, //CJK UNIFIED IDEOGRAPH + 0x8E65: 0x4ED4, //CJK UNIFIED IDEOGRAPH + 0x8E66: 0x4F3A, //CJK UNIFIED IDEOGRAPH + 0x8E67: 0x4F7F, //CJK UNIFIED IDEOGRAPH + 0x8E68: 0x523A, //CJK UNIFIED IDEOGRAPH + 0x8E69: 0x53F8, //CJK UNIFIED IDEOGRAPH + 0x8E6A: 0x53F2, //CJK UNIFIED IDEOGRAPH + 0x8E6B: 0x55E3, //CJK UNIFIED IDEOGRAPH + 0x8E6C: 0x56DB, //CJK UNIFIED IDEOGRAPH + 0x8E6D: 0x58EB, //CJK UNIFIED IDEOGRAPH + 0x8E6E: 0x59CB, //CJK UNIFIED IDEOGRAPH + 0x8E6F: 0x59C9, //CJK UNIFIED IDEOGRAPH + 0x8E70: 0x59FF, //CJK UNIFIED IDEOGRAPH + 0x8E71: 0x5B50, //CJK UNIFIED IDEOGRAPH + 0x8E72: 0x5C4D, //CJK UNIFIED IDEOGRAPH + 0x8E73: 0x5E02, //CJK UNIFIED IDEOGRAPH + 0x8E74: 0x5E2B, //CJK UNIFIED IDEOGRAPH + 0x8E75: 0x5FD7, //CJK UNIFIED IDEOGRAPH + 0x8E76: 0x601D, //CJK UNIFIED IDEOGRAPH + 0x8E77: 0x6307, //CJK UNIFIED IDEOGRAPH + 0x8E78: 0x652F, //CJK UNIFIED IDEOGRAPH + 0x8E79: 0x5B5C, //CJK UNIFIED IDEOGRAPH + 0x8E7A: 0x65AF, //CJK UNIFIED IDEOGRAPH + 0x8E7B: 0x65BD, //CJK UNIFIED IDEOGRAPH + 0x8E7C: 0x65E8, //CJK UNIFIED IDEOGRAPH + 0x8E7D: 0x679D, //CJK UNIFIED IDEOGRAPH + 0x8E7E: 0x6B62, //CJK UNIFIED IDEOGRAPH + 0x8E80: 0x6B7B, //CJK UNIFIED IDEOGRAPH + 0x8E81: 0x6C0F, //CJK UNIFIED IDEOGRAPH + 0x8E82: 0x7345, //CJK UNIFIED IDEOGRAPH + 0x8E83: 0x7949, //CJK UNIFIED IDEOGRAPH + 0x8E84: 0x79C1, //CJK UNIFIED IDEOGRAPH + 0x8E85: 0x7CF8, //CJK UNIFIED IDEOGRAPH + 0x8E86: 0x7D19, //CJK UNIFIED IDEOGRAPH + 0x8E87: 0x7D2B, //CJK UNIFIED IDEOGRAPH + 0x8E88: 0x80A2, //CJK UNIFIED IDEOGRAPH + 0x8E89: 0x8102, //CJK UNIFIED IDEOGRAPH + 0x8E8A: 0x81F3, //CJK UNIFIED IDEOGRAPH + 0x8E8B: 0x8996, //CJK UNIFIED IDEOGRAPH + 0x8E8C: 0x8A5E, //CJK UNIFIED IDEOGRAPH + 0x8E8D: 0x8A69, //CJK UNIFIED IDEOGRAPH + 0x8E8E: 0x8A66, //CJK UNIFIED IDEOGRAPH + 0x8E8F: 0x8A8C, //CJK UNIFIED IDEOGRAPH + 0x8E90: 0x8AEE, //CJK UNIFIED IDEOGRAPH + 0x8E91: 0x8CC7, //CJK UNIFIED IDEOGRAPH + 0x8E92: 0x8CDC, //CJK UNIFIED IDEOGRAPH + 0x8E93: 0x96CC, //CJK UNIFIED IDEOGRAPH + 0x8E94: 0x98FC, //CJK UNIFIED IDEOGRAPH + 0x8E95: 0x6B6F, //CJK UNIFIED IDEOGRAPH + 0x8E96: 0x4E8B, //CJK UNIFIED IDEOGRAPH + 0x8E97: 0x4F3C, //CJK UNIFIED IDEOGRAPH + 0x8E98: 0x4F8D, //CJK UNIFIED IDEOGRAPH + 0x8E99: 0x5150, //CJK UNIFIED IDEOGRAPH + 0x8E9A: 0x5B57, //CJK UNIFIED IDEOGRAPH + 0x8E9B: 0x5BFA, //CJK UNIFIED IDEOGRAPH + 0x8E9C: 0x6148, //CJK UNIFIED IDEOGRAPH + 0x8E9D: 0x6301, //CJK UNIFIED IDEOGRAPH + 0x8E9E: 0x6642, //CJK UNIFIED IDEOGRAPH + 0x8E9F: 0x6B21, //CJK UNIFIED IDEOGRAPH + 0x8EA0: 0x6ECB, //CJK UNIFIED IDEOGRAPH + 0x8EA1: 0x6CBB, //CJK UNIFIED IDEOGRAPH + 0x8EA2: 0x723E, //CJK UNIFIED IDEOGRAPH + 0x8EA3: 0x74BD, //CJK UNIFIED IDEOGRAPH + 0x8EA4: 0x75D4, //CJK UNIFIED IDEOGRAPH + 0x8EA5: 0x78C1, //CJK UNIFIED IDEOGRAPH + 0x8EA6: 0x793A, //CJK UNIFIED IDEOGRAPH + 0x8EA7: 0x800C, //CJK UNIFIED IDEOGRAPH + 0x8EA8: 0x8033, //CJK UNIFIED IDEOGRAPH + 0x8EA9: 0x81EA, //CJK UNIFIED IDEOGRAPH + 0x8EAA: 0x8494, //CJK UNIFIED IDEOGRAPH + 0x8EAB: 0x8F9E, //CJK UNIFIED IDEOGRAPH + 0x8EAC: 0x6C50, //CJK UNIFIED IDEOGRAPH + 0x8EAD: 0x9E7F, //CJK UNIFIED IDEOGRAPH + 0x8EAE: 0x5F0F, //CJK UNIFIED IDEOGRAPH + 0x8EAF: 0x8B58, //CJK UNIFIED IDEOGRAPH + 0x8EB0: 0x9D2B, //CJK UNIFIED IDEOGRAPH + 0x8EB1: 0x7AFA, //CJK UNIFIED IDEOGRAPH + 0x8EB2: 0x8EF8, //CJK UNIFIED IDEOGRAPH + 0x8EB3: 0x5B8D, //CJK UNIFIED IDEOGRAPH + 0x8EB4: 0x96EB, //CJK UNIFIED IDEOGRAPH + 0x8EB5: 0x4E03, //CJK UNIFIED IDEOGRAPH + 0x8EB6: 0x53F1, //CJK UNIFIED IDEOGRAPH + 0x8EB7: 0x57F7, //CJK UNIFIED IDEOGRAPH + 0x8EB8: 0x5931, //CJK UNIFIED IDEOGRAPH + 0x8EB9: 0x5AC9, //CJK UNIFIED IDEOGRAPH + 0x8EBA: 0x5BA4, //CJK UNIFIED IDEOGRAPH + 0x8EBB: 0x6089, //CJK UNIFIED IDEOGRAPH + 0x8EBC: 0x6E7F, //CJK UNIFIED IDEOGRAPH + 0x8EBD: 0x6F06, //CJK UNIFIED IDEOGRAPH + 0x8EBE: 0x75BE, //CJK UNIFIED IDEOGRAPH + 0x8EBF: 0x8CEA, //CJK UNIFIED IDEOGRAPH + 0x8EC0: 0x5B9F, //CJK UNIFIED IDEOGRAPH + 0x8EC1: 0x8500, //CJK UNIFIED IDEOGRAPH + 0x8EC2: 0x7BE0, //CJK UNIFIED IDEOGRAPH + 0x8EC3: 0x5072, //CJK UNIFIED IDEOGRAPH + 0x8EC4: 0x67F4, //CJK UNIFIED IDEOGRAPH + 0x8EC5: 0x829D, //CJK UNIFIED IDEOGRAPH + 0x8EC6: 0x5C61, //CJK UNIFIED IDEOGRAPH + 0x8EC7: 0x854A, //CJK UNIFIED IDEOGRAPH + 0x8EC8: 0x7E1E, //CJK UNIFIED IDEOGRAPH + 0x8EC9: 0x820E, //CJK UNIFIED IDEOGRAPH + 0x8ECA: 0x5199, //CJK UNIFIED IDEOGRAPH + 0x8ECB: 0x5C04, //CJK UNIFIED IDEOGRAPH + 0x8ECC: 0x6368, //CJK UNIFIED IDEOGRAPH + 0x8ECD: 0x8D66, //CJK UNIFIED IDEOGRAPH + 0x8ECE: 0x659C, //CJK UNIFIED IDEOGRAPH + 0x8ECF: 0x716E, //CJK UNIFIED IDEOGRAPH + 0x8ED0: 0x793E, //CJK UNIFIED IDEOGRAPH + 0x8ED1: 0x7D17, //CJK UNIFIED IDEOGRAPH + 0x8ED2: 0x8005, //CJK UNIFIED IDEOGRAPH + 0x8ED3: 0x8B1D, //CJK UNIFIED IDEOGRAPH + 0x8ED4: 0x8ECA, //CJK UNIFIED IDEOGRAPH + 0x8ED5: 0x906E, //CJK UNIFIED IDEOGRAPH + 0x8ED6: 0x86C7, //CJK UNIFIED IDEOGRAPH + 0x8ED7: 0x90AA, //CJK UNIFIED IDEOGRAPH + 0x8ED8: 0x501F, //CJK UNIFIED IDEOGRAPH + 0x8ED9: 0x52FA, //CJK UNIFIED IDEOGRAPH + 0x8EDA: 0x5C3A, //CJK UNIFIED IDEOGRAPH + 0x8EDB: 0x6753, //CJK UNIFIED IDEOGRAPH + 0x8EDC: 0x707C, //CJK UNIFIED IDEOGRAPH + 0x8EDD: 0x7235, //CJK UNIFIED IDEOGRAPH + 0x8EDE: 0x914C, //CJK UNIFIED IDEOGRAPH + 0x8EDF: 0x91C8, //CJK UNIFIED IDEOGRAPH + 0x8EE0: 0x932B, //CJK UNIFIED IDEOGRAPH + 0x8EE1: 0x82E5, //CJK UNIFIED IDEOGRAPH + 0x8EE2: 0x5BC2, //CJK UNIFIED IDEOGRAPH + 0x8EE3: 0x5F31, //CJK UNIFIED IDEOGRAPH + 0x8EE4: 0x60F9, //CJK UNIFIED IDEOGRAPH + 0x8EE5: 0x4E3B, //CJK UNIFIED IDEOGRAPH + 0x8EE6: 0x53D6, //CJK UNIFIED IDEOGRAPH + 0x8EE7: 0x5B88, //CJK UNIFIED IDEOGRAPH + 0x8EE8: 0x624B, //CJK UNIFIED IDEOGRAPH + 0x8EE9: 0x6731, //CJK UNIFIED IDEOGRAPH + 0x8EEA: 0x6B8A, //CJK UNIFIED IDEOGRAPH + 0x8EEB: 0x72E9, //CJK UNIFIED IDEOGRAPH + 0x8EEC: 0x73E0, //CJK UNIFIED IDEOGRAPH + 0x8EED: 0x7A2E, //CJK UNIFIED IDEOGRAPH + 0x8EEE: 0x816B, //CJK UNIFIED IDEOGRAPH + 0x8EEF: 0x8DA3, //CJK UNIFIED IDEOGRAPH + 0x8EF0: 0x9152, //CJK UNIFIED IDEOGRAPH + 0x8EF1: 0x9996, //CJK UNIFIED IDEOGRAPH + 0x8EF2: 0x5112, //CJK UNIFIED IDEOGRAPH + 0x8EF3: 0x53D7, //CJK UNIFIED IDEOGRAPH + 0x8EF4: 0x546A, //CJK UNIFIED IDEOGRAPH + 0x8EF5: 0x5BFF, //CJK UNIFIED IDEOGRAPH + 0x8EF6: 0x6388, //CJK UNIFIED IDEOGRAPH + 0x8EF7: 0x6A39, //CJK UNIFIED IDEOGRAPH + 0x8EF8: 0x7DAC, //CJK UNIFIED IDEOGRAPH + 0x8EF9: 0x9700, //CJK UNIFIED IDEOGRAPH + 0x8EFA: 0x56DA, //CJK UNIFIED IDEOGRAPH + 0x8EFB: 0x53CE, //CJK UNIFIED IDEOGRAPH + 0x8EFC: 0x5468, //CJK UNIFIED IDEOGRAPH + 0x8F40: 0x5B97, //CJK UNIFIED IDEOGRAPH + 0x8F41: 0x5C31, //CJK UNIFIED IDEOGRAPH + 0x8F42: 0x5DDE, //CJK UNIFIED IDEOGRAPH + 0x8F43: 0x4FEE, //CJK UNIFIED IDEOGRAPH + 0x8F44: 0x6101, //CJK UNIFIED IDEOGRAPH + 0x8F45: 0x62FE, //CJK UNIFIED IDEOGRAPH + 0x8F46: 0x6D32, //CJK UNIFIED IDEOGRAPH + 0x8F47: 0x79C0, //CJK UNIFIED IDEOGRAPH + 0x8F48: 0x79CB, //CJK UNIFIED IDEOGRAPH + 0x8F49: 0x7D42, //CJK UNIFIED IDEOGRAPH + 0x8F4A: 0x7E4D, //CJK UNIFIED IDEOGRAPH + 0x8F4B: 0x7FD2, //CJK UNIFIED IDEOGRAPH + 0x8F4C: 0x81ED, //CJK UNIFIED IDEOGRAPH + 0x8F4D: 0x821F, //CJK UNIFIED IDEOGRAPH + 0x8F4E: 0x8490, //CJK UNIFIED IDEOGRAPH + 0x8F4F: 0x8846, //CJK UNIFIED IDEOGRAPH + 0x8F50: 0x8972, //CJK UNIFIED IDEOGRAPH + 0x8F51: 0x8B90, //CJK UNIFIED IDEOGRAPH + 0x8F52: 0x8E74, //CJK UNIFIED IDEOGRAPH + 0x8F53: 0x8F2F, //CJK UNIFIED IDEOGRAPH + 0x8F54: 0x9031, //CJK UNIFIED IDEOGRAPH + 0x8F55: 0x914B, //CJK UNIFIED IDEOGRAPH + 0x8F56: 0x916C, //CJK UNIFIED IDEOGRAPH + 0x8F57: 0x96C6, //CJK UNIFIED IDEOGRAPH + 0x8F58: 0x919C, //CJK UNIFIED IDEOGRAPH + 0x8F59: 0x4EC0, //CJK UNIFIED IDEOGRAPH + 0x8F5A: 0x4F4F, //CJK UNIFIED IDEOGRAPH + 0x8F5B: 0x5145, //CJK UNIFIED IDEOGRAPH + 0x8F5C: 0x5341, //CJK UNIFIED IDEOGRAPH + 0x8F5D: 0x5F93, //CJK UNIFIED IDEOGRAPH + 0x8F5E: 0x620E, //CJK UNIFIED IDEOGRAPH + 0x8F5F: 0x67D4, //CJK UNIFIED IDEOGRAPH + 0x8F60: 0x6C41, //CJK UNIFIED IDEOGRAPH + 0x8F61: 0x6E0B, //CJK UNIFIED IDEOGRAPH + 0x8F62: 0x7363, //CJK UNIFIED IDEOGRAPH + 0x8F63: 0x7E26, //CJK UNIFIED IDEOGRAPH + 0x8F64: 0x91CD, //CJK UNIFIED IDEOGRAPH + 0x8F65: 0x9283, //CJK UNIFIED IDEOGRAPH + 0x8F66: 0x53D4, //CJK UNIFIED IDEOGRAPH + 0x8F67: 0x5919, //CJK UNIFIED IDEOGRAPH + 0x8F68: 0x5BBF, //CJK UNIFIED IDEOGRAPH + 0x8F69: 0x6DD1, //CJK UNIFIED IDEOGRAPH + 0x8F6A: 0x795D, //CJK UNIFIED IDEOGRAPH + 0x8F6B: 0x7E2E, //CJK UNIFIED IDEOGRAPH + 0x8F6C: 0x7C9B, //CJK UNIFIED IDEOGRAPH + 0x8F6D: 0x587E, //CJK UNIFIED IDEOGRAPH + 0x8F6E: 0x719F, //CJK UNIFIED IDEOGRAPH + 0x8F6F: 0x51FA, //CJK UNIFIED IDEOGRAPH + 0x8F70: 0x8853, //CJK UNIFIED IDEOGRAPH + 0x8F71: 0x8FF0, //CJK UNIFIED IDEOGRAPH + 0x8F72: 0x4FCA, //CJK UNIFIED IDEOGRAPH + 0x8F73: 0x5CFB, //CJK UNIFIED IDEOGRAPH + 0x8F74: 0x6625, //CJK UNIFIED IDEOGRAPH + 0x8F75: 0x77AC, //CJK UNIFIED IDEOGRAPH + 0x8F76: 0x7AE3, //CJK UNIFIED IDEOGRAPH + 0x8F77: 0x821C, //CJK UNIFIED IDEOGRAPH + 0x8F78: 0x99FF, //CJK UNIFIED IDEOGRAPH + 0x8F79: 0x51C6, //CJK UNIFIED IDEOGRAPH + 0x8F7A: 0x5FAA, //CJK UNIFIED IDEOGRAPH + 0x8F7B: 0x65EC, //CJK UNIFIED IDEOGRAPH + 0x8F7C: 0x696F, //CJK UNIFIED IDEOGRAPH + 0x8F7D: 0x6B89, //CJK UNIFIED IDEOGRAPH + 0x8F7E: 0x6DF3, //CJK UNIFIED IDEOGRAPH + 0x8F80: 0x6E96, //CJK UNIFIED IDEOGRAPH + 0x8F81: 0x6F64, //CJK UNIFIED IDEOGRAPH + 0x8F82: 0x76FE, //CJK UNIFIED IDEOGRAPH + 0x8F83: 0x7D14, //CJK UNIFIED IDEOGRAPH + 0x8F84: 0x5DE1, //CJK UNIFIED IDEOGRAPH + 0x8F85: 0x9075, //CJK UNIFIED IDEOGRAPH + 0x8F86: 0x9187, //CJK UNIFIED IDEOGRAPH + 0x8F87: 0x9806, //CJK UNIFIED IDEOGRAPH + 0x8F88: 0x51E6, //CJK UNIFIED IDEOGRAPH + 0x8F89: 0x521D, //CJK UNIFIED IDEOGRAPH + 0x8F8A: 0x6240, //CJK UNIFIED IDEOGRAPH + 0x8F8B: 0x6691, //CJK UNIFIED IDEOGRAPH + 0x8F8C: 0x66D9, //CJK UNIFIED IDEOGRAPH + 0x8F8D: 0x6E1A, //CJK UNIFIED IDEOGRAPH + 0x8F8E: 0x5EB6, //CJK UNIFIED IDEOGRAPH + 0x8F8F: 0x7DD2, //CJK UNIFIED IDEOGRAPH + 0x8F90: 0x7F72, //CJK UNIFIED IDEOGRAPH + 0x8F91: 0x66F8, //CJK UNIFIED IDEOGRAPH + 0x8F92: 0x85AF, //CJK UNIFIED IDEOGRAPH + 0x8F93: 0x85F7, //CJK UNIFIED IDEOGRAPH + 0x8F94: 0x8AF8, //CJK UNIFIED IDEOGRAPH + 0x8F95: 0x52A9, //CJK UNIFIED IDEOGRAPH + 0x8F96: 0x53D9, //CJK UNIFIED IDEOGRAPH + 0x8F97: 0x5973, //CJK UNIFIED IDEOGRAPH + 0x8F98: 0x5E8F, //CJK UNIFIED IDEOGRAPH + 0x8F99: 0x5F90, //CJK UNIFIED IDEOGRAPH + 0x8F9A: 0x6055, //CJK UNIFIED IDEOGRAPH + 0x8F9B: 0x92E4, //CJK UNIFIED IDEOGRAPH + 0x8F9C: 0x9664, //CJK UNIFIED IDEOGRAPH + 0x8F9D: 0x50B7, //CJK UNIFIED IDEOGRAPH + 0x8F9E: 0x511F, //CJK UNIFIED IDEOGRAPH + 0x8F9F: 0x52DD, //CJK UNIFIED IDEOGRAPH + 0x8FA0: 0x5320, //CJK UNIFIED IDEOGRAPH + 0x8FA1: 0x5347, //CJK UNIFIED IDEOGRAPH + 0x8FA2: 0x53EC, //CJK UNIFIED IDEOGRAPH + 0x8FA3: 0x54E8, //CJK UNIFIED IDEOGRAPH + 0x8FA4: 0x5546, //CJK UNIFIED IDEOGRAPH + 0x8FA5: 0x5531, //CJK UNIFIED IDEOGRAPH + 0x8FA6: 0x5617, //CJK UNIFIED IDEOGRAPH + 0x8FA7: 0x5968, //CJK UNIFIED IDEOGRAPH + 0x8FA8: 0x59BE, //CJK UNIFIED IDEOGRAPH + 0x8FA9: 0x5A3C, //CJK UNIFIED IDEOGRAPH + 0x8FAA: 0x5BB5, //CJK UNIFIED IDEOGRAPH + 0x8FAB: 0x5C06, //CJK UNIFIED IDEOGRAPH + 0x8FAC: 0x5C0F, //CJK UNIFIED IDEOGRAPH + 0x8FAD: 0x5C11, //CJK UNIFIED IDEOGRAPH + 0x8FAE: 0x5C1A, //CJK UNIFIED IDEOGRAPH + 0x8FAF: 0x5E84, //CJK UNIFIED IDEOGRAPH + 0x8FB0: 0x5E8A, //CJK UNIFIED IDEOGRAPH + 0x8FB1: 0x5EE0, //CJK UNIFIED IDEOGRAPH + 0x8FB2: 0x5F70, //CJK UNIFIED IDEOGRAPH + 0x8FB3: 0x627F, //CJK UNIFIED IDEOGRAPH + 0x8FB4: 0x6284, //CJK UNIFIED IDEOGRAPH + 0x8FB5: 0x62DB, //CJK UNIFIED IDEOGRAPH + 0x8FB6: 0x638C, //CJK UNIFIED IDEOGRAPH + 0x8FB7: 0x6377, //CJK UNIFIED IDEOGRAPH + 0x8FB8: 0x6607, //CJK UNIFIED IDEOGRAPH + 0x8FB9: 0x660C, //CJK UNIFIED IDEOGRAPH + 0x8FBA: 0x662D, //CJK UNIFIED IDEOGRAPH + 0x8FBB: 0x6676, //CJK UNIFIED IDEOGRAPH + 0x8FBC: 0x677E, //CJK UNIFIED IDEOGRAPH + 0x8FBD: 0x68A2, //CJK UNIFIED IDEOGRAPH + 0x8FBE: 0x6A1F, //CJK UNIFIED IDEOGRAPH + 0x8FBF: 0x6A35, //CJK UNIFIED IDEOGRAPH + 0x8FC0: 0x6CBC, //CJK UNIFIED IDEOGRAPH + 0x8FC1: 0x6D88, //CJK UNIFIED IDEOGRAPH + 0x8FC2: 0x6E09, //CJK UNIFIED IDEOGRAPH + 0x8FC3: 0x6E58, //CJK UNIFIED IDEOGRAPH + 0x8FC4: 0x713C, //CJK UNIFIED IDEOGRAPH + 0x8FC5: 0x7126, //CJK UNIFIED IDEOGRAPH + 0x8FC6: 0x7167, //CJK UNIFIED IDEOGRAPH + 0x8FC7: 0x75C7, //CJK UNIFIED IDEOGRAPH + 0x8FC8: 0x7701, //CJK UNIFIED IDEOGRAPH + 0x8FC9: 0x785D, //CJK UNIFIED IDEOGRAPH + 0x8FCA: 0x7901, //CJK UNIFIED IDEOGRAPH + 0x8FCB: 0x7965, //CJK UNIFIED IDEOGRAPH + 0x8FCC: 0x79F0, //CJK UNIFIED IDEOGRAPH + 0x8FCD: 0x7AE0, //CJK UNIFIED IDEOGRAPH + 0x8FCE: 0x7B11, //CJK UNIFIED IDEOGRAPH + 0x8FCF: 0x7CA7, //CJK UNIFIED IDEOGRAPH + 0x8FD0: 0x7D39, //CJK UNIFIED IDEOGRAPH + 0x8FD1: 0x8096, //CJK UNIFIED IDEOGRAPH + 0x8FD2: 0x83D6, //CJK UNIFIED IDEOGRAPH + 0x8FD3: 0x848B, //CJK UNIFIED IDEOGRAPH + 0x8FD4: 0x8549, //CJK UNIFIED IDEOGRAPH + 0x8FD5: 0x885D, //CJK UNIFIED IDEOGRAPH + 0x8FD6: 0x88F3, //CJK UNIFIED IDEOGRAPH + 0x8FD7: 0x8A1F, //CJK UNIFIED IDEOGRAPH + 0x8FD8: 0x8A3C, //CJK UNIFIED IDEOGRAPH + 0x8FD9: 0x8A54, //CJK UNIFIED IDEOGRAPH + 0x8FDA: 0x8A73, //CJK UNIFIED IDEOGRAPH + 0x8FDB: 0x8C61, //CJK UNIFIED IDEOGRAPH + 0x8FDC: 0x8CDE, //CJK UNIFIED IDEOGRAPH + 0x8FDD: 0x91A4, //CJK UNIFIED IDEOGRAPH + 0x8FDE: 0x9266, //CJK UNIFIED IDEOGRAPH + 0x8FDF: 0x937E, //CJK UNIFIED IDEOGRAPH + 0x8FE0: 0x9418, //CJK UNIFIED IDEOGRAPH + 0x8FE1: 0x969C, //CJK UNIFIED IDEOGRAPH + 0x8FE2: 0x9798, //CJK UNIFIED IDEOGRAPH + 0x8FE3: 0x4E0A, //CJK UNIFIED IDEOGRAPH + 0x8FE4: 0x4E08, //CJK UNIFIED IDEOGRAPH + 0x8FE5: 0x4E1E, //CJK UNIFIED IDEOGRAPH + 0x8FE6: 0x4E57, //CJK UNIFIED IDEOGRAPH + 0x8FE7: 0x5197, //CJK UNIFIED IDEOGRAPH + 0x8FE8: 0x5270, //CJK UNIFIED IDEOGRAPH + 0x8FE9: 0x57CE, //CJK UNIFIED IDEOGRAPH + 0x8FEA: 0x5834, //CJK UNIFIED IDEOGRAPH + 0x8FEB: 0x58CC, //CJK UNIFIED IDEOGRAPH + 0x8FEC: 0x5B22, //CJK UNIFIED IDEOGRAPH + 0x8FED: 0x5E38, //CJK UNIFIED IDEOGRAPH + 0x8FEE: 0x60C5, //CJK UNIFIED IDEOGRAPH + 0x8FEF: 0x64FE, //CJK UNIFIED IDEOGRAPH + 0x8FF0: 0x6761, //CJK UNIFIED IDEOGRAPH + 0x8FF1: 0x6756, //CJK UNIFIED IDEOGRAPH + 0x8FF2: 0x6D44, //CJK UNIFIED IDEOGRAPH + 0x8FF3: 0x72B6, //CJK UNIFIED IDEOGRAPH + 0x8FF4: 0x7573, //CJK UNIFIED IDEOGRAPH + 0x8FF5: 0x7A63, //CJK UNIFIED IDEOGRAPH + 0x8FF6: 0x84B8, //CJK UNIFIED IDEOGRAPH + 0x8FF7: 0x8B72, //CJK UNIFIED IDEOGRAPH + 0x8FF8: 0x91B8, //CJK UNIFIED IDEOGRAPH + 0x8FF9: 0x9320, //CJK UNIFIED IDEOGRAPH + 0x8FFA: 0x5631, //CJK UNIFIED IDEOGRAPH + 0x8FFB: 0x57F4, //CJK UNIFIED IDEOGRAPH + 0x8FFC: 0x98FE, //CJK UNIFIED IDEOGRAPH + 0x9040: 0x62ED, //CJK UNIFIED IDEOGRAPH + 0x9041: 0x690D, //CJK UNIFIED IDEOGRAPH + 0x9042: 0x6B96, //CJK UNIFIED IDEOGRAPH + 0x9043: 0x71ED, //CJK UNIFIED IDEOGRAPH + 0x9044: 0x7E54, //CJK UNIFIED IDEOGRAPH + 0x9045: 0x8077, //CJK UNIFIED IDEOGRAPH + 0x9046: 0x8272, //CJK UNIFIED IDEOGRAPH + 0x9047: 0x89E6, //CJK UNIFIED IDEOGRAPH + 0x9048: 0x98DF, //CJK UNIFIED IDEOGRAPH + 0x9049: 0x8755, //CJK UNIFIED IDEOGRAPH + 0x904A: 0x8FB1, //CJK UNIFIED IDEOGRAPH + 0x904B: 0x5C3B, //CJK UNIFIED IDEOGRAPH + 0x904C: 0x4F38, //CJK UNIFIED IDEOGRAPH + 0x904D: 0x4FE1, //CJK UNIFIED IDEOGRAPH + 0x904E: 0x4FB5, //CJK UNIFIED IDEOGRAPH + 0x904F: 0x5507, //CJK UNIFIED IDEOGRAPH + 0x9050: 0x5A20, //CJK UNIFIED IDEOGRAPH + 0x9051: 0x5BDD, //CJK UNIFIED IDEOGRAPH + 0x9052: 0x5BE9, //CJK UNIFIED IDEOGRAPH + 0x9053: 0x5FC3, //CJK UNIFIED IDEOGRAPH + 0x9054: 0x614E, //CJK UNIFIED IDEOGRAPH + 0x9055: 0x632F, //CJK UNIFIED IDEOGRAPH + 0x9056: 0x65B0, //CJK UNIFIED IDEOGRAPH + 0x9057: 0x664B, //CJK UNIFIED IDEOGRAPH + 0x9058: 0x68EE, //CJK UNIFIED IDEOGRAPH + 0x9059: 0x699B, //CJK UNIFIED IDEOGRAPH + 0x905A: 0x6D78, //CJK UNIFIED IDEOGRAPH + 0x905B: 0x6DF1, //CJK UNIFIED IDEOGRAPH + 0x905C: 0x7533, //CJK UNIFIED IDEOGRAPH + 0x905D: 0x75B9, //CJK UNIFIED IDEOGRAPH + 0x905E: 0x771F, //CJK UNIFIED IDEOGRAPH + 0x905F: 0x795E, //CJK UNIFIED IDEOGRAPH + 0x9060: 0x79E6, //CJK UNIFIED IDEOGRAPH + 0x9061: 0x7D33, //CJK UNIFIED IDEOGRAPH + 0x9062: 0x81E3, //CJK UNIFIED IDEOGRAPH + 0x9063: 0x82AF, //CJK UNIFIED IDEOGRAPH + 0x9064: 0x85AA, //CJK UNIFIED IDEOGRAPH + 0x9065: 0x89AA, //CJK UNIFIED IDEOGRAPH + 0x9066: 0x8A3A, //CJK UNIFIED IDEOGRAPH + 0x9067: 0x8EAB, //CJK UNIFIED IDEOGRAPH + 0x9068: 0x8F9B, //CJK UNIFIED IDEOGRAPH + 0x9069: 0x9032, //CJK UNIFIED IDEOGRAPH + 0x906A: 0x91DD, //CJK UNIFIED IDEOGRAPH + 0x906B: 0x9707, //CJK UNIFIED IDEOGRAPH + 0x906C: 0x4EBA, //CJK UNIFIED IDEOGRAPH + 0x906D: 0x4EC1, //CJK UNIFIED IDEOGRAPH + 0x906E: 0x5203, //CJK UNIFIED IDEOGRAPH + 0x906F: 0x5875, //CJK UNIFIED IDEOGRAPH + 0x9070: 0x58EC, //CJK UNIFIED IDEOGRAPH + 0x9071: 0x5C0B, //CJK UNIFIED IDEOGRAPH + 0x9072: 0x751A, //CJK UNIFIED IDEOGRAPH + 0x9073: 0x5C3D, //CJK UNIFIED IDEOGRAPH + 0x9074: 0x814E, //CJK UNIFIED IDEOGRAPH + 0x9075: 0x8A0A, //CJK UNIFIED IDEOGRAPH + 0x9076: 0x8FC5, //CJK UNIFIED IDEOGRAPH + 0x9077: 0x9663, //CJK UNIFIED IDEOGRAPH + 0x9078: 0x976D, //CJK UNIFIED IDEOGRAPH + 0x9079: 0x7B25, //CJK UNIFIED IDEOGRAPH + 0x907A: 0x8ACF, //CJK UNIFIED IDEOGRAPH + 0x907B: 0x9808, //CJK UNIFIED IDEOGRAPH + 0x907C: 0x9162, //CJK UNIFIED IDEOGRAPH + 0x907D: 0x56F3, //CJK UNIFIED IDEOGRAPH + 0x907E: 0x53A8, //CJK UNIFIED IDEOGRAPH + 0x9080: 0x9017, //CJK UNIFIED IDEOGRAPH + 0x9081: 0x5439, //CJK UNIFIED IDEOGRAPH + 0x9082: 0x5782, //CJK UNIFIED IDEOGRAPH + 0x9083: 0x5E25, //CJK UNIFIED IDEOGRAPH + 0x9084: 0x63A8, //CJK UNIFIED IDEOGRAPH + 0x9085: 0x6C34, //CJK UNIFIED IDEOGRAPH + 0x9086: 0x708A, //CJK UNIFIED IDEOGRAPH + 0x9087: 0x7761, //CJK UNIFIED IDEOGRAPH + 0x9088: 0x7C8B, //CJK UNIFIED IDEOGRAPH + 0x9089: 0x7FE0, //CJK UNIFIED IDEOGRAPH + 0x908A: 0x8870, //CJK UNIFIED IDEOGRAPH + 0x908B: 0x9042, //CJK UNIFIED IDEOGRAPH + 0x908C: 0x9154, //CJK UNIFIED IDEOGRAPH + 0x908D: 0x9310, //CJK UNIFIED IDEOGRAPH + 0x908E: 0x9318, //CJK UNIFIED IDEOGRAPH + 0x908F: 0x968F, //CJK UNIFIED IDEOGRAPH + 0x9090: 0x745E, //CJK UNIFIED IDEOGRAPH + 0x9091: 0x9AC4, //CJK UNIFIED IDEOGRAPH + 0x9092: 0x5D07, //CJK UNIFIED IDEOGRAPH + 0x9093: 0x5D69, //CJK UNIFIED IDEOGRAPH + 0x9094: 0x6570, //CJK UNIFIED IDEOGRAPH + 0x9095: 0x67A2, //CJK UNIFIED IDEOGRAPH + 0x9096: 0x8DA8, //CJK UNIFIED IDEOGRAPH + 0x9097: 0x96DB, //CJK UNIFIED IDEOGRAPH + 0x9098: 0x636E, //CJK UNIFIED IDEOGRAPH + 0x9099: 0x6749, //CJK UNIFIED IDEOGRAPH + 0x909A: 0x6919, //CJK UNIFIED IDEOGRAPH + 0x909B: 0x83C5, //CJK UNIFIED IDEOGRAPH + 0x909C: 0x9817, //CJK UNIFIED IDEOGRAPH + 0x909D: 0x96C0, //CJK UNIFIED IDEOGRAPH + 0x909E: 0x88FE, //CJK UNIFIED IDEOGRAPH + 0x909F: 0x6F84, //CJK UNIFIED IDEOGRAPH + 0x90A0: 0x647A, //CJK UNIFIED IDEOGRAPH + 0x90A1: 0x5BF8, //CJK UNIFIED IDEOGRAPH + 0x90A2: 0x4E16, //CJK UNIFIED IDEOGRAPH + 0x90A3: 0x702C, //CJK UNIFIED IDEOGRAPH + 0x90A4: 0x755D, //CJK UNIFIED IDEOGRAPH + 0x90A5: 0x662F, //CJK UNIFIED IDEOGRAPH + 0x90A6: 0x51C4, //CJK UNIFIED IDEOGRAPH + 0x90A7: 0x5236, //CJK UNIFIED IDEOGRAPH + 0x90A8: 0x52E2, //CJK UNIFIED IDEOGRAPH + 0x90A9: 0x59D3, //CJK UNIFIED IDEOGRAPH + 0x90AA: 0x5F81, //CJK UNIFIED IDEOGRAPH + 0x90AB: 0x6027, //CJK UNIFIED IDEOGRAPH + 0x90AC: 0x6210, //CJK UNIFIED IDEOGRAPH + 0x90AD: 0x653F, //CJK UNIFIED IDEOGRAPH + 0x90AE: 0x6574, //CJK UNIFIED IDEOGRAPH + 0x90AF: 0x661F, //CJK UNIFIED IDEOGRAPH + 0x90B0: 0x6674, //CJK UNIFIED IDEOGRAPH + 0x90B1: 0x68F2, //CJK UNIFIED IDEOGRAPH + 0x90B2: 0x6816, //CJK UNIFIED IDEOGRAPH + 0x90B3: 0x6B63, //CJK UNIFIED IDEOGRAPH + 0x90B4: 0x6E05, //CJK UNIFIED IDEOGRAPH + 0x90B5: 0x7272, //CJK UNIFIED IDEOGRAPH + 0x90B6: 0x751F, //CJK UNIFIED IDEOGRAPH + 0x90B7: 0x76DB, //CJK UNIFIED IDEOGRAPH + 0x90B8: 0x7CBE, //CJK UNIFIED IDEOGRAPH + 0x90B9: 0x8056, //CJK UNIFIED IDEOGRAPH + 0x90BA: 0x58F0, //CJK UNIFIED IDEOGRAPH + 0x90BB: 0x88FD, //CJK UNIFIED IDEOGRAPH + 0x90BC: 0x897F, //CJK UNIFIED IDEOGRAPH + 0x90BD: 0x8AA0, //CJK UNIFIED IDEOGRAPH + 0x90BE: 0x8A93, //CJK UNIFIED IDEOGRAPH + 0x90BF: 0x8ACB, //CJK UNIFIED IDEOGRAPH + 0x90C0: 0x901D, //CJK UNIFIED IDEOGRAPH + 0x90C1: 0x9192, //CJK UNIFIED IDEOGRAPH + 0x90C2: 0x9752, //CJK UNIFIED IDEOGRAPH + 0x90C3: 0x9759, //CJK UNIFIED IDEOGRAPH + 0x90C4: 0x6589, //CJK UNIFIED IDEOGRAPH + 0x90C5: 0x7A0E, //CJK UNIFIED IDEOGRAPH + 0x90C6: 0x8106, //CJK UNIFIED IDEOGRAPH + 0x90C7: 0x96BB, //CJK UNIFIED IDEOGRAPH + 0x90C8: 0x5E2D, //CJK UNIFIED IDEOGRAPH + 0x90C9: 0x60DC, //CJK UNIFIED IDEOGRAPH + 0x90CA: 0x621A, //CJK UNIFIED IDEOGRAPH + 0x90CB: 0x65A5, //CJK UNIFIED IDEOGRAPH + 0x90CC: 0x6614, //CJK UNIFIED IDEOGRAPH + 0x90CD: 0x6790, //CJK UNIFIED IDEOGRAPH + 0x90CE: 0x77F3, //CJK UNIFIED IDEOGRAPH + 0x90CF: 0x7A4D, //CJK UNIFIED IDEOGRAPH + 0x90D0: 0x7C4D, //CJK UNIFIED IDEOGRAPH + 0x90D1: 0x7E3E, //CJK UNIFIED IDEOGRAPH + 0x90D2: 0x810A, //CJK UNIFIED IDEOGRAPH + 0x90D3: 0x8CAC, //CJK UNIFIED IDEOGRAPH + 0x90D4: 0x8D64, //CJK UNIFIED IDEOGRAPH + 0x90D5: 0x8DE1, //CJK UNIFIED IDEOGRAPH + 0x90D6: 0x8E5F, //CJK UNIFIED IDEOGRAPH + 0x90D7: 0x78A9, //CJK UNIFIED IDEOGRAPH + 0x90D8: 0x5207, //CJK UNIFIED IDEOGRAPH + 0x90D9: 0x62D9, //CJK UNIFIED IDEOGRAPH + 0x90DA: 0x63A5, //CJK UNIFIED IDEOGRAPH + 0x90DB: 0x6442, //CJK UNIFIED IDEOGRAPH + 0x90DC: 0x6298, //CJK UNIFIED IDEOGRAPH + 0x90DD: 0x8A2D, //CJK UNIFIED IDEOGRAPH + 0x90DE: 0x7A83, //CJK UNIFIED IDEOGRAPH + 0x90DF: 0x7BC0, //CJK UNIFIED IDEOGRAPH + 0x90E0: 0x8AAC, //CJK UNIFIED IDEOGRAPH + 0x90E1: 0x96EA, //CJK UNIFIED IDEOGRAPH + 0x90E2: 0x7D76, //CJK UNIFIED IDEOGRAPH + 0x90E3: 0x820C, //CJK UNIFIED IDEOGRAPH + 0x90E4: 0x8749, //CJK UNIFIED IDEOGRAPH + 0x90E5: 0x4ED9, //CJK UNIFIED IDEOGRAPH + 0x90E6: 0x5148, //CJK UNIFIED IDEOGRAPH + 0x90E7: 0x5343, //CJK UNIFIED IDEOGRAPH + 0x90E8: 0x5360, //CJK UNIFIED IDEOGRAPH + 0x90E9: 0x5BA3, //CJK UNIFIED IDEOGRAPH + 0x90EA: 0x5C02, //CJK UNIFIED IDEOGRAPH + 0x90EB: 0x5C16, //CJK UNIFIED IDEOGRAPH + 0x90EC: 0x5DDD, //CJK UNIFIED IDEOGRAPH + 0x90ED: 0x6226, //CJK UNIFIED IDEOGRAPH + 0x90EE: 0x6247, //CJK UNIFIED IDEOGRAPH + 0x90EF: 0x64B0, //CJK UNIFIED IDEOGRAPH + 0x90F0: 0x6813, //CJK UNIFIED IDEOGRAPH + 0x90F1: 0x6834, //CJK UNIFIED IDEOGRAPH + 0x90F2: 0x6CC9, //CJK UNIFIED IDEOGRAPH + 0x90F3: 0x6D45, //CJK UNIFIED IDEOGRAPH + 0x90F4: 0x6D17, //CJK UNIFIED IDEOGRAPH + 0x90F5: 0x67D3, //CJK UNIFIED IDEOGRAPH + 0x90F6: 0x6F5C, //CJK UNIFIED IDEOGRAPH + 0x90F7: 0x714E, //CJK UNIFIED IDEOGRAPH + 0x90F8: 0x717D, //CJK UNIFIED IDEOGRAPH + 0x90F9: 0x65CB, //CJK UNIFIED IDEOGRAPH + 0x90FA: 0x7A7F, //CJK UNIFIED IDEOGRAPH + 0x90FB: 0x7BAD, //CJK UNIFIED IDEOGRAPH + 0x90FC: 0x7DDA, //CJK UNIFIED IDEOGRAPH + 0x9140: 0x7E4A, //CJK UNIFIED IDEOGRAPH + 0x9141: 0x7FA8, //CJK UNIFIED IDEOGRAPH + 0x9142: 0x817A, //CJK UNIFIED IDEOGRAPH + 0x9143: 0x821B, //CJK UNIFIED IDEOGRAPH + 0x9144: 0x8239, //CJK UNIFIED IDEOGRAPH + 0x9145: 0x85A6, //CJK UNIFIED IDEOGRAPH + 0x9146: 0x8A6E, //CJK UNIFIED IDEOGRAPH + 0x9147: 0x8CCE, //CJK UNIFIED IDEOGRAPH + 0x9148: 0x8DF5, //CJK UNIFIED IDEOGRAPH + 0x9149: 0x9078, //CJK UNIFIED IDEOGRAPH + 0x914A: 0x9077, //CJK UNIFIED IDEOGRAPH + 0x914B: 0x92AD, //CJK UNIFIED IDEOGRAPH + 0x914C: 0x9291, //CJK UNIFIED IDEOGRAPH + 0x914D: 0x9583, //CJK UNIFIED IDEOGRAPH + 0x914E: 0x9BAE, //CJK UNIFIED IDEOGRAPH + 0x914F: 0x524D, //CJK UNIFIED IDEOGRAPH + 0x9150: 0x5584, //CJK UNIFIED IDEOGRAPH + 0x9151: 0x6F38, //CJK UNIFIED IDEOGRAPH + 0x9152: 0x7136, //CJK UNIFIED IDEOGRAPH + 0x9153: 0x5168, //CJK UNIFIED IDEOGRAPH + 0x9154: 0x7985, //CJK UNIFIED IDEOGRAPH + 0x9155: 0x7E55, //CJK UNIFIED IDEOGRAPH + 0x9156: 0x81B3, //CJK UNIFIED IDEOGRAPH + 0x9157: 0x7CCE, //CJK UNIFIED IDEOGRAPH + 0x9158: 0x564C, //CJK UNIFIED IDEOGRAPH + 0x9159: 0x5851, //CJK UNIFIED IDEOGRAPH + 0x915A: 0x5CA8, //CJK UNIFIED IDEOGRAPH + 0x915B: 0x63AA, //CJK UNIFIED IDEOGRAPH + 0x915C: 0x66FE, //CJK UNIFIED IDEOGRAPH + 0x915D: 0x66FD, //CJK UNIFIED IDEOGRAPH + 0x915E: 0x695A, //CJK UNIFIED IDEOGRAPH + 0x915F: 0x72D9, //CJK UNIFIED IDEOGRAPH + 0x9160: 0x758F, //CJK UNIFIED IDEOGRAPH + 0x9161: 0x758E, //CJK UNIFIED IDEOGRAPH + 0x9162: 0x790E, //CJK UNIFIED IDEOGRAPH + 0x9163: 0x7956, //CJK UNIFIED IDEOGRAPH + 0x9164: 0x79DF, //CJK UNIFIED IDEOGRAPH + 0x9165: 0x7C97, //CJK UNIFIED IDEOGRAPH + 0x9166: 0x7D20, //CJK UNIFIED IDEOGRAPH + 0x9167: 0x7D44, //CJK UNIFIED IDEOGRAPH + 0x9168: 0x8607, //CJK UNIFIED IDEOGRAPH + 0x9169: 0x8A34, //CJK UNIFIED IDEOGRAPH + 0x916A: 0x963B, //CJK UNIFIED IDEOGRAPH + 0x916B: 0x9061, //CJK UNIFIED IDEOGRAPH + 0x916C: 0x9F20, //CJK UNIFIED IDEOGRAPH + 0x916D: 0x50E7, //CJK UNIFIED IDEOGRAPH + 0x916E: 0x5275, //CJK UNIFIED IDEOGRAPH + 0x916F: 0x53CC, //CJK UNIFIED IDEOGRAPH + 0x9170: 0x53E2, //CJK UNIFIED IDEOGRAPH + 0x9171: 0x5009, //CJK UNIFIED IDEOGRAPH + 0x9172: 0x55AA, //CJK UNIFIED IDEOGRAPH + 0x9173: 0x58EE, //CJK UNIFIED IDEOGRAPH + 0x9174: 0x594F, //CJK UNIFIED IDEOGRAPH + 0x9175: 0x723D, //CJK UNIFIED IDEOGRAPH + 0x9176: 0x5B8B, //CJK UNIFIED IDEOGRAPH + 0x9177: 0x5C64, //CJK UNIFIED IDEOGRAPH + 0x9178: 0x531D, //CJK UNIFIED IDEOGRAPH + 0x9179: 0x60E3, //CJK UNIFIED IDEOGRAPH + 0x917A: 0x60F3, //CJK UNIFIED IDEOGRAPH + 0x917B: 0x635C, //CJK UNIFIED IDEOGRAPH + 0x917C: 0x6383, //CJK UNIFIED IDEOGRAPH + 0x917D: 0x633F, //CJK UNIFIED IDEOGRAPH + 0x917E: 0x63BB, //CJK UNIFIED IDEOGRAPH + 0x9180: 0x64CD, //CJK UNIFIED IDEOGRAPH + 0x9181: 0x65E9, //CJK UNIFIED IDEOGRAPH + 0x9182: 0x66F9, //CJK UNIFIED IDEOGRAPH + 0x9183: 0x5DE3, //CJK UNIFIED IDEOGRAPH + 0x9184: 0x69CD, //CJK UNIFIED IDEOGRAPH + 0x9185: 0x69FD, //CJK UNIFIED IDEOGRAPH + 0x9186: 0x6F15, //CJK UNIFIED IDEOGRAPH + 0x9187: 0x71E5, //CJK UNIFIED IDEOGRAPH + 0x9188: 0x4E89, //CJK UNIFIED IDEOGRAPH + 0x9189: 0x75E9, //CJK UNIFIED IDEOGRAPH + 0x918A: 0x76F8, //CJK UNIFIED IDEOGRAPH + 0x918B: 0x7A93, //CJK UNIFIED IDEOGRAPH + 0x918C: 0x7CDF, //CJK UNIFIED IDEOGRAPH + 0x918D: 0x7DCF, //CJK UNIFIED IDEOGRAPH + 0x918E: 0x7D9C, //CJK UNIFIED IDEOGRAPH + 0x918F: 0x8061, //CJK UNIFIED IDEOGRAPH + 0x9190: 0x8349, //CJK UNIFIED IDEOGRAPH + 0x9191: 0x8358, //CJK UNIFIED IDEOGRAPH + 0x9192: 0x846C, //CJK UNIFIED IDEOGRAPH + 0x9193: 0x84BC, //CJK UNIFIED IDEOGRAPH + 0x9194: 0x85FB, //CJK UNIFIED IDEOGRAPH + 0x9195: 0x88C5, //CJK UNIFIED IDEOGRAPH + 0x9196: 0x8D70, //CJK UNIFIED IDEOGRAPH + 0x9197: 0x9001, //CJK UNIFIED IDEOGRAPH + 0x9198: 0x906D, //CJK UNIFIED IDEOGRAPH + 0x9199: 0x9397, //CJK UNIFIED IDEOGRAPH + 0x919A: 0x971C, //CJK UNIFIED IDEOGRAPH + 0x919B: 0x9A12, //CJK UNIFIED IDEOGRAPH + 0x919C: 0x50CF, //CJK UNIFIED IDEOGRAPH + 0x919D: 0x5897, //CJK UNIFIED IDEOGRAPH + 0x919E: 0x618E, //CJK UNIFIED IDEOGRAPH + 0x919F: 0x81D3, //CJK UNIFIED IDEOGRAPH + 0x91A0: 0x8535, //CJK UNIFIED IDEOGRAPH + 0x91A1: 0x8D08, //CJK UNIFIED IDEOGRAPH + 0x91A2: 0x9020, //CJK UNIFIED IDEOGRAPH + 0x91A3: 0x4FC3, //CJK UNIFIED IDEOGRAPH + 0x91A4: 0x5074, //CJK UNIFIED IDEOGRAPH + 0x91A5: 0x5247, //CJK UNIFIED IDEOGRAPH + 0x91A6: 0x5373, //CJK UNIFIED IDEOGRAPH + 0x91A7: 0x606F, //CJK UNIFIED IDEOGRAPH + 0x91A8: 0x6349, //CJK UNIFIED IDEOGRAPH + 0x91A9: 0x675F, //CJK UNIFIED IDEOGRAPH + 0x91AA: 0x6E2C, //CJK UNIFIED IDEOGRAPH + 0x91AB: 0x8DB3, //CJK UNIFIED IDEOGRAPH + 0x91AC: 0x901F, //CJK UNIFIED IDEOGRAPH + 0x91AD: 0x4FD7, //CJK UNIFIED IDEOGRAPH + 0x91AE: 0x5C5E, //CJK UNIFIED IDEOGRAPH + 0x91AF: 0x8CCA, //CJK UNIFIED IDEOGRAPH + 0x91B0: 0x65CF, //CJK UNIFIED IDEOGRAPH + 0x91B1: 0x7D9A, //CJK UNIFIED IDEOGRAPH + 0x91B2: 0x5352, //CJK UNIFIED IDEOGRAPH + 0x91B3: 0x8896, //CJK UNIFIED IDEOGRAPH + 0x91B4: 0x5176, //CJK UNIFIED IDEOGRAPH + 0x91B5: 0x63C3, //CJK UNIFIED IDEOGRAPH + 0x91B6: 0x5B58, //CJK UNIFIED IDEOGRAPH + 0x91B7: 0x5B6B, //CJK UNIFIED IDEOGRAPH + 0x91B8: 0x5C0A, //CJK UNIFIED IDEOGRAPH + 0x91B9: 0x640D, //CJK UNIFIED IDEOGRAPH + 0x91BA: 0x6751, //CJK UNIFIED IDEOGRAPH + 0x91BB: 0x905C, //CJK UNIFIED IDEOGRAPH + 0x91BC: 0x4ED6, //CJK UNIFIED IDEOGRAPH + 0x91BD: 0x591A, //CJK UNIFIED IDEOGRAPH + 0x91BE: 0x592A, //CJK UNIFIED IDEOGRAPH + 0x91BF: 0x6C70, //CJK UNIFIED IDEOGRAPH + 0x91C0: 0x8A51, //CJK UNIFIED IDEOGRAPH + 0x91C1: 0x553E, //CJK UNIFIED IDEOGRAPH + 0x91C2: 0x5815, //CJK UNIFIED IDEOGRAPH + 0x91C3: 0x59A5, //CJK UNIFIED IDEOGRAPH + 0x91C4: 0x60F0, //CJK UNIFIED IDEOGRAPH + 0x91C5: 0x6253, //CJK UNIFIED IDEOGRAPH + 0x91C6: 0x67C1, //CJK UNIFIED IDEOGRAPH + 0x91C7: 0x8235, //CJK UNIFIED IDEOGRAPH + 0x91C8: 0x6955, //CJK UNIFIED IDEOGRAPH + 0x91C9: 0x9640, //CJK UNIFIED IDEOGRAPH + 0x91CA: 0x99C4, //CJK UNIFIED IDEOGRAPH + 0x91CB: 0x9A28, //CJK UNIFIED IDEOGRAPH + 0x91CC: 0x4F53, //CJK UNIFIED IDEOGRAPH + 0x91CD: 0x5806, //CJK UNIFIED IDEOGRAPH + 0x91CE: 0x5BFE, //CJK UNIFIED IDEOGRAPH + 0x91CF: 0x8010, //CJK UNIFIED IDEOGRAPH + 0x91D0: 0x5CB1, //CJK UNIFIED IDEOGRAPH + 0x91D1: 0x5E2F, //CJK UNIFIED IDEOGRAPH + 0x91D2: 0x5F85, //CJK UNIFIED IDEOGRAPH + 0x91D3: 0x6020, //CJK UNIFIED IDEOGRAPH + 0x91D4: 0x614B, //CJK UNIFIED IDEOGRAPH + 0x91D5: 0x6234, //CJK UNIFIED IDEOGRAPH + 0x91D6: 0x66FF, //CJK UNIFIED IDEOGRAPH + 0x91D7: 0x6CF0, //CJK UNIFIED IDEOGRAPH + 0x91D8: 0x6EDE, //CJK UNIFIED IDEOGRAPH + 0x91D9: 0x80CE, //CJK UNIFIED IDEOGRAPH + 0x91DA: 0x817F, //CJK UNIFIED IDEOGRAPH + 0x91DB: 0x82D4, //CJK UNIFIED IDEOGRAPH + 0x91DC: 0x888B, //CJK UNIFIED IDEOGRAPH + 0x91DD: 0x8CB8, //CJK UNIFIED IDEOGRAPH + 0x91DE: 0x9000, //CJK UNIFIED IDEOGRAPH + 0x91DF: 0x902E, //CJK UNIFIED IDEOGRAPH + 0x91E0: 0x968A, //CJK UNIFIED IDEOGRAPH + 0x91E1: 0x9EDB, //CJK UNIFIED IDEOGRAPH + 0x91E2: 0x9BDB, //CJK UNIFIED IDEOGRAPH + 0x91E3: 0x4EE3, //CJK UNIFIED IDEOGRAPH + 0x91E4: 0x53F0, //CJK UNIFIED IDEOGRAPH + 0x91E5: 0x5927, //CJK UNIFIED IDEOGRAPH + 0x91E6: 0x7B2C, //CJK UNIFIED IDEOGRAPH + 0x91E7: 0x918D, //CJK UNIFIED IDEOGRAPH + 0x91E8: 0x984C, //CJK UNIFIED IDEOGRAPH + 0x91E9: 0x9DF9, //CJK UNIFIED IDEOGRAPH + 0x91EA: 0x6EDD, //CJK UNIFIED IDEOGRAPH + 0x91EB: 0x7027, //CJK UNIFIED IDEOGRAPH + 0x91EC: 0x5353, //CJK UNIFIED IDEOGRAPH + 0x91ED: 0x5544, //CJK UNIFIED IDEOGRAPH + 0x91EE: 0x5B85, //CJK UNIFIED IDEOGRAPH + 0x91EF: 0x6258, //CJK UNIFIED IDEOGRAPH + 0x91F0: 0x629E, //CJK UNIFIED IDEOGRAPH + 0x91F1: 0x62D3, //CJK UNIFIED IDEOGRAPH + 0x91F2: 0x6CA2, //CJK UNIFIED IDEOGRAPH + 0x91F3: 0x6FEF, //CJK UNIFIED IDEOGRAPH + 0x91F4: 0x7422, //CJK UNIFIED IDEOGRAPH + 0x91F5: 0x8A17, //CJK UNIFIED IDEOGRAPH + 0x91F6: 0x9438, //CJK UNIFIED IDEOGRAPH + 0x91F7: 0x6FC1, //CJK UNIFIED IDEOGRAPH + 0x91F8: 0x8AFE, //CJK UNIFIED IDEOGRAPH + 0x91F9: 0x8338, //CJK UNIFIED IDEOGRAPH + 0x91FA: 0x51E7, //CJK UNIFIED IDEOGRAPH + 0x91FB: 0x86F8, //CJK UNIFIED IDEOGRAPH + 0x91FC: 0x53EA, //CJK UNIFIED IDEOGRAPH + 0x9240: 0x53E9, //CJK UNIFIED IDEOGRAPH + 0x9241: 0x4F46, //CJK UNIFIED IDEOGRAPH + 0x9242: 0x9054, //CJK UNIFIED IDEOGRAPH + 0x9243: 0x8FB0, //CJK UNIFIED IDEOGRAPH + 0x9244: 0x596A, //CJK UNIFIED IDEOGRAPH + 0x9245: 0x8131, //CJK UNIFIED IDEOGRAPH + 0x9246: 0x5DFD, //CJK UNIFIED IDEOGRAPH + 0x9247: 0x7AEA, //CJK UNIFIED IDEOGRAPH + 0x9248: 0x8FBF, //CJK UNIFIED IDEOGRAPH + 0x9249: 0x68DA, //CJK UNIFIED IDEOGRAPH + 0x924A: 0x8C37, //CJK UNIFIED IDEOGRAPH + 0x924B: 0x72F8, //CJK UNIFIED IDEOGRAPH + 0x924C: 0x9C48, //CJK UNIFIED IDEOGRAPH + 0x924D: 0x6A3D, //CJK UNIFIED IDEOGRAPH + 0x924E: 0x8AB0, //CJK UNIFIED IDEOGRAPH + 0x924F: 0x4E39, //CJK UNIFIED IDEOGRAPH + 0x9250: 0x5358, //CJK UNIFIED IDEOGRAPH + 0x9251: 0x5606, //CJK UNIFIED IDEOGRAPH + 0x9252: 0x5766, //CJK UNIFIED IDEOGRAPH + 0x9253: 0x62C5, //CJK UNIFIED IDEOGRAPH + 0x9254: 0x63A2, //CJK UNIFIED IDEOGRAPH + 0x9255: 0x65E6, //CJK UNIFIED IDEOGRAPH + 0x9256: 0x6B4E, //CJK UNIFIED IDEOGRAPH + 0x9257: 0x6DE1, //CJK UNIFIED IDEOGRAPH + 0x9258: 0x6E5B, //CJK UNIFIED IDEOGRAPH + 0x9259: 0x70AD, //CJK UNIFIED IDEOGRAPH + 0x925A: 0x77ED, //CJK UNIFIED IDEOGRAPH + 0x925B: 0x7AEF, //CJK UNIFIED IDEOGRAPH + 0x925C: 0x7BAA, //CJK UNIFIED IDEOGRAPH + 0x925D: 0x7DBB, //CJK UNIFIED IDEOGRAPH + 0x925E: 0x803D, //CJK UNIFIED IDEOGRAPH + 0x925F: 0x80C6, //CJK UNIFIED IDEOGRAPH + 0x9260: 0x86CB, //CJK UNIFIED IDEOGRAPH + 0x9261: 0x8A95, //CJK UNIFIED IDEOGRAPH + 0x9262: 0x935B, //CJK UNIFIED IDEOGRAPH + 0x9263: 0x56E3, //CJK UNIFIED IDEOGRAPH + 0x9264: 0x58C7, //CJK UNIFIED IDEOGRAPH + 0x9265: 0x5F3E, //CJK UNIFIED IDEOGRAPH + 0x9266: 0x65AD, //CJK UNIFIED IDEOGRAPH + 0x9267: 0x6696, //CJK UNIFIED IDEOGRAPH + 0x9268: 0x6A80, //CJK UNIFIED IDEOGRAPH + 0x9269: 0x6BB5, //CJK UNIFIED IDEOGRAPH + 0x926A: 0x7537, //CJK UNIFIED IDEOGRAPH + 0x926B: 0x8AC7, //CJK UNIFIED IDEOGRAPH + 0x926C: 0x5024, //CJK UNIFIED IDEOGRAPH + 0x926D: 0x77E5, //CJK UNIFIED IDEOGRAPH + 0x926E: 0x5730, //CJK UNIFIED IDEOGRAPH + 0x926F: 0x5F1B, //CJK UNIFIED IDEOGRAPH + 0x9270: 0x6065, //CJK UNIFIED IDEOGRAPH + 0x9271: 0x667A, //CJK UNIFIED IDEOGRAPH + 0x9272: 0x6C60, //CJK UNIFIED IDEOGRAPH + 0x9273: 0x75F4, //CJK UNIFIED IDEOGRAPH + 0x9274: 0x7A1A, //CJK UNIFIED IDEOGRAPH + 0x9275: 0x7F6E, //CJK UNIFIED IDEOGRAPH + 0x9276: 0x81F4, //CJK UNIFIED IDEOGRAPH + 0x9277: 0x8718, //CJK UNIFIED IDEOGRAPH + 0x9278: 0x9045, //CJK UNIFIED IDEOGRAPH + 0x9279: 0x99B3, //CJK UNIFIED IDEOGRAPH + 0x927A: 0x7BC9, //CJK UNIFIED IDEOGRAPH + 0x927B: 0x755C, //CJK UNIFIED IDEOGRAPH + 0x927C: 0x7AF9, //CJK UNIFIED IDEOGRAPH + 0x927D: 0x7B51, //CJK UNIFIED IDEOGRAPH + 0x927E: 0x84C4, //CJK UNIFIED IDEOGRAPH + 0x9280: 0x9010, //CJK UNIFIED IDEOGRAPH + 0x9281: 0x79E9, //CJK UNIFIED IDEOGRAPH + 0x9282: 0x7A92, //CJK UNIFIED IDEOGRAPH + 0x9283: 0x8336, //CJK UNIFIED IDEOGRAPH + 0x9284: 0x5AE1, //CJK UNIFIED IDEOGRAPH + 0x9285: 0x7740, //CJK UNIFIED IDEOGRAPH + 0x9286: 0x4E2D, //CJK UNIFIED IDEOGRAPH + 0x9287: 0x4EF2, //CJK UNIFIED IDEOGRAPH + 0x9288: 0x5B99, //CJK UNIFIED IDEOGRAPH + 0x9289: 0x5FE0, //CJK UNIFIED IDEOGRAPH + 0x928A: 0x62BD, //CJK UNIFIED IDEOGRAPH + 0x928B: 0x663C, //CJK UNIFIED IDEOGRAPH + 0x928C: 0x67F1, //CJK UNIFIED IDEOGRAPH + 0x928D: 0x6CE8, //CJK UNIFIED IDEOGRAPH + 0x928E: 0x866B, //CJK UNIFIED IDEOGRAPH + 0x928F: 0x8877, //CJK UNIFIED IDEOGRAPH + 0x9290: 0x8A3B, //CJK UNIFIED IDEOGRAPH + 0x9291: 0x914E, //CJK UNIFIED IDEOGRAPH + 0x9292: 0x92F3, //CJK UNIFIED IDEOGRAPH + 0x9293: 0x99D0, //CJK UNIFIED IDEOGRAPH + 0x9294: 0x6A17, //CJK UNIFIED IDEOGRAPH + 0x9295: 0x7026, //CJK UNIFIED IDEOGRAPH + 0x9296: 0x732A, //CJK UNIFIED IDEOGRAPH + 0x9297: 0x82E7, //CJK UNIFIED IDEOGRAPH + 0x9298: 0x8457, //CJK UNIFIED IDEOGRAPH + 0x9299: 0x8CAF, //CJK UNIFIED IDEOGRAPH + 0x929A: 0x4E01, //CJK UNIFIED IDEOGRAPH + 0x929B: 0x5146, //CJK UNIFIED IDEOGRAPH + 0x929C: 0x51CB, //CJK UNIFIED IDEOGRAPH + 0x929D: 0x558B, //CJK UNIFIED IDEOGRAPH + 0x929E: 0x5BF5, //CJK UNIFIED IDEOGRAPH + 0x929F: 0x5E16, //CJK UNIFIED IDEOGRAPH + 0x92A0: 0x5E33, //CJK UNIFIED IDEOGRAPH + 0x92A1: 0x5E81, //CJK UNIFIED IDEOGRAPH + 0x92A2: 0x5F14, //CJK UNIFIED IDEOGRAPH + 0x92A3: 0x5F35, //CJK UNIFIED IDEOGRAPH + 0x92A4: 0x5F6B, //CJK UNIFIED IDEOGRAPH + 0x92A5: 0x5FB4, //CJK UNIFIED IDEOGRAPH + 0x92A6: 0x61F2, //CJK UNIFIED IDEOGRAPH + 0x92A7: 0x6311, //CJK UNIFIED IDEOGRAPH + 0x92A8: 0x66A2, //CJK UNIFIED IDEOGRAPH + 0x92A9: 0x671D, //CJK UNIFIED IDEOGRAPH + 0x92AA: 0x6F6E, //CJK UNIFIED IDEOGRAPH + 0x92AB: 0x7252, //CJK UNIFIED IDEOGRAPH + 0x92AC: 0x753A, //CJK UNIFIED IDEOGRAPH + 0x92AD: 0x773A, //CJK UNIFIED IDEOGRAPH + 0x92AE: 0x8074, //CJK UNIFIED IDEOGRAPH + 0x92AF: 0x8139, //CJK UNIFIED IDEOGRAPH + 0x92B0: 0x8178, //CJK UNIFIED IDEOGRAPH + 0x92B1: 0x8776, //CJK UNIFIED IDEOGRAPH + 0x92B2: 0x8ABF, //CJK UNIFIED IDEOGRAPH + 0x92B3: 0x8ADC, //CJK UNIFIED IDEOGRAPH + 0x92B4: 0x8D85, //CJK UNIFIED IDEOGRAPH + 0x92B5: 0x8DF3, //CJK UNIFIED IDEOGRAPH + 0x92B6: 0x929A, //CJK UNIFIED IDEOGRAPH + 0x92B7: 0x9577, //CJK UNIFIED IDEOGRAPH + 0x92B8: 0x9802, //CJK UNIFIED IDEOGRAPH + 0x92B9: 0x9CE5, //CJK UNIFIED IDEOGRAPH + 0x92BA: 0x52C5, //CJK UNIFIED IDEOGRAPH + 0x92BB: 0x6357, //CJK UNIFIED IDEOGRAPH + 0x92BC: 0x76F4, //CJK UNIFIED IDEOGRAPH + 0x92BD: 0x6715, //CJK UNIFIED IDEOGRAPH + 0x92BE: 0x6C88, //CJK UNIFIED IDEOGRAPH + 0x92BF: 0x73CD, //CJK UNIFIED IDEOGRAPH + 0x92C0: 0x8CC3, //CJK UNIFIED IDEOGRAPH + 0x92C1: 0x93AE, //CJK UNIFIED IDEOGRAPH + 0x92C2: 0x9673, //CJK UNIFIED IDEOGRAPH + 0x92C3: 0x6D25, //CJK UNIFIED IDEOGRAPH + 0x92C4: 0x589C, //CJK UNIFIED IDEOGRAPH + 0x92C5: 0x690E, //CJK UNIFIED IDEOGRAPH + 0x92C6: 0x69CC, //CJK UNIFIED IDEOGRAPH + 0x92C7: 0x8FFD, //CJK UNIFIED IDEOGRAPH + 0x92C8: 0x939A, //CJK UNIFIED IDEOGRAPH + 0x92C9: 0x75DB, //CJK UNIFIED IDEOGRAPH + 0x92CA: 0x901A, //CJK UNIFIED IDEOGRAPH + 0x92CB: 0x585A, //CJK UNIFIED IDEOGRAPH + 0x92CC: 0x6802, //CJK UNIFIED IDEOGRAPH + 0x92CD: 0x63B4, //CJK UNIFIED IDEOGRAPH + 0x92CE: 0x69FB, //CJK UNIFIED IDEOGRAPH + 0x92CF: 0x4F43, //CJK UNIFIED IDEOGRAPH + 0x92D0: 0x6F2C, //CJK UNIFIED IDEOGRAPH + 0x92D1: 0x67D8, //CJK UNIFIED IDEOGRAPH + 0x92D2: 0x8FBB, //CJK UNIFIED IDEOGRAPH + 0x92D3: 0x8526, //CJK UNIFIED IDEOGRAPH + 0x92D4: 0x7DB4, //CJK UNIFIED IDEOGRAPH + 0x92D5: 0x9354, //CJK UNIFIED IDEOGRAPH + 0x92D6: 0x693F, //CJK UNIFIED IDEOGRAPH + 0x92D7: 0x6F70, //CJK UNIFIED IDEOGRAPH + 0x92D8: 0x576A, //CJK UNIFIED IDEOGRAPH + 0x92D9: 0x58F7, //CJK UNIFIED IDEOGRAPH + 0x92DA: 0x5B2C, //CJK UNIFIED IDEOGRAPH + 0x92DB: 0x7D2C, //CJK UNIFIED IDEOGRAPH + 0x92DC: 0x722A, //CJK UNIFIED IDEOGRAPH + 0x92DD: 0x540A, //CJK UNIFIED IDEOGRAPH + 0x92DE: 0x91E3, //CJK UNIFIED IDEOGRAPH + 0x92DF: 0x9DB4, //CJK UNIFIED IDEOGRAPH + 0x92E0: 0x4EAD, //CJK UNIFIED IDEOGRAPH + 0x92E1: 0x4F4E, //CJK UNIFIED IDEOGRAPH + 0x92E2: 0x505C, //CJK UNIFIED IDEOGRAPH + 0x92E3: 0x5075, //CJK UNIFIED IDEOGRAPH + 0x92E4: 0x5243, //CJK UNIFIED IDEOGRAPH + 0x92E5: 0x8C9E, //CJK UNIFIED IDEOGRAPH + 0x92E6: 0x5448, //CJK UNIFIED IDEOGRAPH + 0x92E7: 0x5824, //CJK UNIFIED IDEOGRAPH + 0x92E8: 0x5B9A, //CJK UNIFIED IDEOGRAPH + 0x92E9: 0x5E1D, //CJK UNIFIED IDEOGRAPH + 0x92EA: 0x5E95, //CJK UNIFIED IDEOGRAPH + 0x92EB: 0x5EAD, //CJK UNIFIED IDEOGRAPH + 0x92EC: 0x5EF7, //CJK UNIFIED IDEOGRAPH + 0x92ED: 0x5F1F, //CJK UNIFIED IDEOGRAPH + 0x92EE: 0x608C, //CJK UNIFIED IDEOGRAPH + 0x92EF: 0x62B5, //CJK UNIFIED IDEOGRAPH + 0x92F0: 0x633A, //CJK UNIFIED IDEOGRAPH + 0x92F1: 0x63D0, //CJK UNIFIED IDEOGRAPH + 0x92F2: 0x68AF, //CJK UNIFIED IDEOGRAPH + 0x92F3: 0x6C40, //CJK UNIFIED IDEOGRAPH + 0x92F4: 0x7887, //CJK UNIFIED IDEOGRAPH + 0x92F5: 0x798E, //CJK UNIFIED IDEOGRAPH + 0x92F6: 0x7A0B, //CJK UNIFIED IDEOGRAPH + 0x92F7: 0x7DE0, //CJK UNIFIED IDEOGRAPH + 0x92F8: 0x8247, //CJK UNIFIED IDEOGRAPH + 0x92F9: 0x8A02, //CJK UNIFIED IDEOGRAPH + 0x92FA: 0x8AE6, //CJK UNIFIED IDEOGRAPH + 0x92FB: 0x8E44, //CJK UNIFIED IDEOGRAPH + 0x92FC: 0x9013, //CJK UNIFIED IDEOGRAPH + 0x9340: 0x90B8, //CJK UNIFIED IDEOGRAPH + 0x9341: 0x912D, //CJK UNIFIED IDEOGRAPH + 0x9342: 0x91D8, //CJK UNIFIED IDEOGRAPH + 0x9343: 0x9F0E, //CJK UNIFIED IDEOGRAPH + 0x9344: 0x6CE5, //CJK UNIFIED IDEOGRAPH + 0x9345: 0x6458, //CJK UNIFIED IDEOGRAPH + 0x9346: 0x64E2, //CJK UNIFIED IDEOGRAPH + 0x9347: 0x6575, //CJK UNIFIED IDEOGRAPH + 0x9348: 0x6EF4, //CJK UNIFIED IDEOGRAPH + 0x9349: 0x7684, //CJK UNIFIED IDEOGRAPH + 0x934A: 0x7B1B, //CJK UNIFIED IDEOGRAPH + 0x934B: 0x9069, //CJK UNIFIED IDEOGRAPH + 0x934C: 0x93D1, //CJK UNIFIED IDEOGRAPH + 0x934D: 0x6EBA, //CJK UNIFIED IDEOGRAPH + 0x934E: 0x54F2, //CJK UNIFIED IDEOGRAPH + 0x934F: 0x5FB9, //CJK UNIFIED IDEOGRAPH + 0x9350: 0x64A4, //CJK UNIFIED IDEOGRAPH + 0x9351: 0x8F4D, //CJK UNIFIED IDEOGRAPH + 0x9352: 0x8FED, //CJK UNIFIED IDEOGRAPH + 0x9353: 0x9244, //CJK UNIFIED IDEOGRAPH + 0x9354: 0x5178, //CJK UNIFIED IDEOGRAPH + 0x9355: 0x586B, //CJK UNIFIED IDEOGRAPH + 0x9356: 0x5929, //CJK UNIFIED IDEOGRAPH + 0x9357: 0x5C55, //CJK UNIFIED IDEOGRAPH + 0x9358: 0x5E97, //CJK UNIFIED IDEOGRAPH + 0x9359: 0x6DFB, //CJK UNIFIED IDEOGRAPH + 0x935A: 0x7E8F, //CJK UNIFIED IDEOGRAPH + 0x935B: 0x751C, //CJK UNIFIED IDEOGRAPH + 0x935C: 0x8CBC, //CJK UNIFIED IDEOGRAPH + 0x935D: 0x8EE2, //CJK UNIFIED IDEOGRAPH + 0x935E: 0x985B, //CJK UNIFIED IDEOGRAPH + 0x935F: 0x70B9, //CJK UNIFIED IDEOGRAPH + 0x9360: 0x4F1D, //CJK UNIFIED IDEOGRAPH + 0x9361: 0x6BBF, //CJK UNIFIED IDEOGRAPH + 0x9362: 0x6FB1, //CJK UNIFIED IDEOGRAPH + 0x9363: 0x7530, //CJK UNIFIED IDEOGRAPH + 0x9364: 0x96FB, //CJK UNIFIED IDEOGRAPH + 0x9365: 0x514E, //CJK UNIFIED IDEOGRAPH + 0x9366: 0x5410, //CJK UNIFIED IDEOGRAPH + 0x9367: 0x5835, //CJK UNIFIED IDEOGRAPH + 0x9368: 0x5857, //CJK UNIFIED IDEOGRAPH + 0x9369: 0x59AC, //CJK UNIFIED IDEOGRAPH + 0x936A: 0x5C60, //CJK UNIFIED IDEOGRAPH + 0x936B: 0x5F92, //CJK UNIFIED IDEOGRAPH + 0x936C: 0x6597, //CJK UNIFIED IDEOGRAPH + 0x936D: 0x675C, //CJK UNIFIED IDEOGRAPH + 0x936E: 0x6E21, //CJK UNIFIED IDEOGRAPH + 0x936F: 0x767B, //CJK UNIFIED IDEOGRAPH + 0x9370: 0x83DF, //CJK UNIFIED IDEOGRAPH + 0x9371: 0x8CED, //CJK UNIFIED IDEOGRAPH + 0x9372: 0x9014, //CJK UNIFIED IDEOGRAPH + 0x9373: 0x90FD, //CJK UNIFIED IDEOGRAPH + 0x9374: 0x934D, //CJK UNIFIED IDEOGRAPH + 0x9375: 0x7825, //CJK UNIFIED IDEOGRAPH + 0x9376: 0x783A, //CJK UNIFIED IDEOGRAPH + 0x9377: 0x52AA, //CJK UNIFIED IDEOGRAPH + 0x9378: 0x5EA6, //CJK UNIFIED IDEOGRAPH + 0x9379: 0x571F, //CJK UNIFIED IDEOGRAPH + 0x937A: 0x5974, //CJK UNIFIED IDEOGRAPH + 0x937B: 0x6012, //CJK UNIFIED IDEOGRAPH + 0x937C: 0x5012, //CJK UNIFIED IDEOGRAPH + 0x937D: 0x515A, //CJK UNIFIED IDEOGRAPH + 0x937E: 0x51AC, //CJK UNIFIED IDEOGRAPH + 0x9380: 0x51CD, //CJK UNIFIED IDEOGRAPH + 0x9381: 0x5200, //CJK UNIFIED IDEOGRAPH + 0x9382: 0x5510, //CJK UNIFIED IDEOGRAPH + 0x9383: 0x5854, //CJK UNIFIED IDEOGRAPH + 0x9384: 0x5858, //CJK UNIFIED IDEOGRAPH + 0x9385: 0x5957, //CJK UNIFIED IDEOGRAPH + 0x9386: 0x5B95, //CJK UNIFIED IDEOGRAPH + 0x9387: 0x5CF6, //CJK UNIFIED IDEOGRAPH + 0x9388: 0x5D8B, //CJK UNIFIED IDEOGRAPH + 0x9389: 0x60BC, //CJK UNIFIED IDEOGRAPH + 0x938A: 0x6295, //CJK UNIFIED IDEOGRAPH + 0x938B: 0x642D, //CJK UNIFIED IDEOGRAPH + 0x938C: 0x6771, //CJK UNIFIED IDEOGRAPH + 0x938D: 0x6843, //CJK UNIFIED IDEOGRAPH + 0x938E: 0x68BC, //CJK UNIFIED IDEOGRAPH + 0x938F: 0x68DF, //CJK UNIFIED IDEOGRAPH + 0x9390: 0x76D7, //CJK UNIFIED IDEOGRAPH + 0x9391: 0x6DD8, //CJK UNIFIED IDEOGRAPH + 0x9392: 0x6E6F, //CJK UNIFIED IDEOGRAPH + 0x9393: 0x6D9B, //CJK UNIFIED IDEOGRAPH + 0x9394: 0x706F, //CJK UNIFIED IDEOGRAPH + 0x9395: 0x71C8, //CJK UNIFIED IDEOGRAPH + 0x9396: 0x5F53, //CJK UNIFIED IDEOGRAPH + 0x9397: 0x75D8, //CJK UNIFIED IDEOGRAPH + 0x9398: 0x7977, //CJK UNIFIED IDEOGRAPH + 0x9399: 0x7B49, //CJK UNIFIED IDEOGRAPH + 0x939A: 0x7B54, //CJK UNIFIED IDEOGRAPH + 0x939B: 0x7B52, //CJK UNIFIED IDEOGRAPH + 0x939C: 0x7CD6, //CJK UNIFIED IDEOGRAPH + 0x939D: 0x7D71, //CJK UNIFIED IDEOGRAPH + 0x939E: 0x5230, //CJK UNIFIED IDEOGRAPH + 0x939F: 0x8463, //CJK UNIFIED IDEOGRAPH + 0x93A0: 0x8569, //CJK UNIFIED IDEOGRAPH + 0x93A1: 0x85E4, //CJK UNIFIED IDEOGRAPH + 0x93A2: 0x8A0E, //CJK UNIFIED IDEOGRAPH + 0x93A3: 0x8B04, //CJK UNIFIED IDEOGRAPH + 0x93A4: 0x8C46, //CJK UNIFIED IDEOGRAPH + 0x93A5: 0x8E0F, //CJK UNIFIED IDEOGRAPH + 0x93A6: 0x9003, //CJK UNIFIED IDEOGRAPH + 0x93A7: 0x900F, //CJK UNIFIED IDEOGRAPH + 0x93A8: 0x9419, //CJK UNIFIED IDEOGRAPH + 0x93A9: 0x9676, //CJK UNIFIED IDEOGRAPH + 0x93AA: 0x982D, //CJK UNIFIED IDEOGRAPH + 0x93AB: 0x9A30, //CJK UNIFIED IDEOGRAPH + 0x93AC: 0x95D8, //CJK UNIFIED IDEOGRAPH + 0x93AD: 0x50CD, //CJK UNIFIED IDEOGRAPH + 0x93AE: 0x52D5, //CJK UNIFIED IDEOGRAPH + 0x93AF: 0x540C, //CJK UNIFIED IDEOGRAPH + 0x93B0: 0x5802, //CJK UNIFIED IDEOGRAPH + 0x93B1: 0x5C0E, //CJK UNIFIED IDEOGRAPH + 0x93B2: 0x61A7, //CJK UNIFIED IDEOGRAPH + 0x93B3: 0x649E, //CJK UNIFIED IDEOGRAPH + 0x93B4: 0x6D1E, //CJK UNIFIED IDEOGRAPH + 0x93B5: 0x77B3, //CJK UNIFIED IDEOGRAPH + 0x93B6: 0x7AE5, //CJK UNIFIED IDEOGRAPH + 0x93B7: 0x80F4, //CJK UNIFIED IDEOGRAPH + 0x93B8: 0x8404, //CJK UNIFIED IDEOGRAPH + 0x93B9: 0x9053, //CJK UNIFIED IDEOGRAPH + 0x93BA: 0x9285, //CJK UNIFIED IDEOGRAPH + 0x93BB: 0x5CE0, //CJK UNIFIED IDEOGRAPH + 0x93BC: 0x9D07, //CJK UNIFIED IDEOGRAPH + 0x93BD: 0x533F, //CJK UNIFIED IDEOGRAPH + 0x93BE: 0x5F97, //CJK UNIFIED IDEOGRAPH + 0x93BF: 0x5FB3, //CJK UNIFIED IDEOGRAPH + 0x93C0: 0x6D9C, //CJK UNIFIED IDEOGRAPH + 0x93C1: 0x7279, //CJK UNIFIED IDEOGRAPH + 0x93C2: 0x7763, //CJK UNIFIED IDEOGRAPH + 0x93C3: 0x79BF, //CJK UNIFIED IDEOGRAPH + 0x93C4: 0x7BE4, //CJK UNIFIED IDEOGRAPH + 0x93C5: 0x6BD2, //CJK UNIFIED IDEOGRAPH + 0x93C6: 0x72EC, //CJK UNIFIED IDEOGRAPH + 0x93C7: 0x8AAD, //CJK UNIFIED IDEOGRAPH + 0x93C8: 0x6803, //CJK UNIFIED IDEOGRAPH + 0x93C9: 0x6A61, //CJK UNIFIED IDEOGRAPH + 0x93CA: 0x51F8, //CJK UNIFIED IDEOGRAPH + 0x93CB: 0x7A81, //CJK UNIFIED IDEOGRAPH + 0x93CC: 0x6934, //CJK UNIFIED IDEOGRAPH + 0x93CD: 0x5C4A, //CJK UNIFIED IDEOGRAPH + 0x93CE: 0x9CF6, //CJK UNIFIED IDEOGRAPH + 0x93CF: 0x82EB, //CJK UNIFIED IDEOGRAPH + 0x93D0: 0x5BC5, //CJK UNIFIED IDEOGRAPH + 0x93D1: 0x9149, //CJK UNIFIED IDEOGRAPH + 0x93D2: 0x701E, //CJK UNIFIED IDEOGRAPH + 0x93D3: 0x5678, //CJK UNIFIED IDEOGRAPH + 0x93D4: 0x5C6F, //CJK UNIFIED IDEOGRAPH + 0x93D5: 0x60C7, //CJK UNIFIED IDEOGRAPH + 0x93D6: 0x6566, //CJK UNIFIED IDEOGRAPH + 0x93D7: 0x6C8C, //CJK UNIFIED IDEOGRAPH + 0x93D8: 0x8C5A, //CJK UNIFIED IDEOGRAPH + 0x93D9: 0x9041, //CJK UNIFIED IDEOGRAPH + 0x93DA: 0x9813, //CJK UNIFIED IDEOGRAPH + 0x93DB: 0x5451, //CJK UNIFIED IDEOGRAPH + 0x93DC: 0x66C7, //CJK UNIFIED IDEOGRAPH + 0x93DD: 0x920D, //CJK UNIFIED IDEOGRAPH + 0x93DE: 0x5948, //CJK UNIFIED IDEOGRAPH + 0x93DF: 0x90A3, //CJK UNIFIED IDEOGRAPH + 0x93E0: 0x5185, //CJK UNIFIED IDEOGRAPH + 0x93E1: 0x4E4D, //CJK UNIFIED IDEOGRAPH + 0x93E2: 0x51EA, //CJK UNIFIED IDEOGRAPH + 0x93E3: 0x8599, //CJK UNIFIED IDEOGRAPH + 0x93E4: 0x8B0E, //CJK UNIFIED IDEOGRAPH + 0x93E5: 0x7058, //CJK UNIFIED IDEOGRAPH + 0x93E6: 0x637A, //CJK UNIFIED IDEOGRAPH + 0x93E7: 0x934B, //CJK UNIFIED IDEOGRAPH + 0x93E8: 0x6962, //CJK UNIFIED IDEOGRAPH + 0x93E9: 0x99B4, //CJK UNIFIED IDEOGRAPH + 0x93EA: 0x7E04, //CJK UNIFIED IDEOGRAPH + 0x93EB: 0x7577, //CJK UNIFIED IDEOGRAPH + 0x93EC: 0x5357, //CJK UNIFIED IDEOGRAPH + 0x93ED: 0x6960, //CJK UNIFIED IDEOGRAPH + 0x93EE: 0x8EDF, //CJK UNIFIED IDEOGRAPH + 0x93EF: 0x96E3, //CJK UNIFIED IDEOGRAPH + 0x93F0: 0x6C5D, //CJK UNIFIED IDEOGRAPH + 0x93F1: 0x4E8C, //CJK UNIFIED IDEOGRAPH + 0x93F2: 0x5C3C, //CJK UNIFIED IDEOGRAPH + 0x93F3: 0x5F10, //CJK UNIFIED IDEOGRAPH + 0x93F4: 0x8FE9, //CJK UNIFIED IDEOGRAPH + 0x93F5: 0x5302, //CJK UNIFIED IDEOGRAPH + 0x93F6: 0x8CD1, //CJK UNIFIED IDEOGRAPH + 0x93F7: 0x8089, //CJK UNIFIED IDEOGRAPH + 0x93F8: 0x8679, //CJK UNIFIED IDEOGRAPH + 0x93F9: 0x5EFF, //CJK UNIFIED IDEOGRAPH + 0x93FA: 0x65E5, //CJK UNIFIED IDEOGRAPH + 0x93FB: 0x4E73, //CJK UNIFIED IDEOGRAPH + 0x93FC: 0x5165, //CJK UNIFIED IDEOGRAPH + 0x9440: 0x5982, //CJK UNIFIED IDEOGRAPH + 0x9441: 0x5C3F, //CJK UNIFIED IDEOGRAPH + 0x9442: 0x97EE, //CJK UNIFIED IDEOGRAPH + 0x9443: 0x4EFB, //CJK UNIFIED IDEOGRAPH + 0x9444: 0x598A, //CJK UNIFIED IDEOGRAPH + 0x9445: 0x5FCD, //CJK UNIFIED IDEOGRAPH + 0x9446: 0x8A8D, //CJK UNIFIED IDEOGRAPH + 0x9447: 0x6FE1, //CJK UNIFIED IDEOGRAPH + 0x9448: 0x79B0, //CJK UNIFIED IDEOGRAPH + 0x9449: 0x7962, //CJK UNIFIED IDEOGRAPH + 0x944A: 0x5BE7, //CJK UNIFIED IDEOGRAPH + 0x944B: 0x8471, //CJK UNIFIED IDEOGRAPH + 0x944C: 0x732B, //CJK UNIFIED IDEOGRAPH + 0x944D: 0x71B1, //CJK UNIFIED IDEOGRAPH + 0x944E: 0x5E74, //CJK UNIFIED IDEOGRAPH + 0x944F: 0x5FF5, //CJK UNIFIED IDEOGRAPH + 0x9450: 0x637B, //CJK UNIFIED IDEOGRAPH + 0x9451: 0x649A, //CJK UNIFIED IDEOGRAPH + 0x9452: 0x71C3, //CJK UNIFIED IDEOGRAPH + 0x9453: 0x7C98, //CJK UNIFIED IDEOGRAPH + 0x9454: 0x4E43, //CJK UNIFIED IDEOGRAPH + 0x9455: 0x5EFC, //CJK UNIFIED IDEOGRAPH + 0x9456: 0x4E4B, //CJK UNIFIED IDEOGRAPH + 0x9457: 0x57DC, //CJK UNIFIED IDEOGRAPH + 0x9458: 0x56A2, //CJK UNIFIED IDEOGRAPH + 0x9459: 0x60A9, //CJK UNIFIED IDEOGRAPH + 0x945A: 0x6FC3, //CJK UNIFIED IDEOGRAPH + 0x945B: 0x7D0D, //CJK UNIFIED IDEOGRAPH + 0x945C: 0x80FD, //CJK UNIFIED IDEOGRAPH + 0x945D: 0x8133, //CJK UNIFIED IDEOGRAPH + 0x945E: 0x81BF, //CJK UNIFIED IDEOGRAPH + 0x945F: 0x8FB2, //CJK UNIFIED IDEOGRAPH + 0x9460: 0x8997, //CJK UNIFIED IDEOGRAPH + 0x9461: 0x86A4, //CJK UNIFIED IDEOGRAPH + 0x9462: 0x5DF4, //CJK UNIFIED IDEOGRAPH + 0x9463: 0x628A, //CJK UNIFIED IDEOGRAPH + 0x9464: 0x64AD, //CJK UNIFIED IDEOGRAPH + 0x9465: 0x8987, //CJK UNIFIED IDEOGRAPH + 0x9466: 0x6777, //CJK UNIFIED IDEOGRAPH + 0x9467: 0x6CE2, //CJK UNIFIED IDEOGRAPH + 0x9468: 0x6D3E, //CJK UNIFIED IDEOGRAPH + 0x9469: 0x7436, //CJK UNIFIED IDEOGRAPH + 0x946A: 0x7834, //CJK UNIFIED IDEOGRAPH + 0x946B: 0x5A46, //CJK UNIFIED IDEOGRAPH + 0x946C: 0x7F75, //CJK UNIFIED IDEOGRAPH + 0x946D: 0x82AD, //CJK UNIFIED IDEOGRAPH + 0x946E: 0x99AC, //CJK UNIFIED IDEOGRAPH + 0x946F: 0x4FF3, //CJK UNIFIED IDEOGRAPH + 0x9470: 0x5EC3, //CJK UNIFIED IDEOGRAPH + 0x9471: 0x62DD, //CJK UNIFIED IDEOGRAPH + 0x9472: 0x6392, //CJK UNIFIED IDEOGRAPH + 0x9473: 0x6557, //CJK UNIFIED IDEOGRAPH + 0x9474: 0x676F, //CJK UNIFIED IDEOGRAPH + 0x9475: 0x76C3, //CJK UNIFIED IDEOGRAPH + 0x9476: 0x724C, //CJK UNIFIED IDEOGRAPH + 0x9477: 0x80CC, //CJK UNIFIED IDEOGRAPH + 0x9478: 0x80BA, //CJK UNIFIED IDEOGRAPH + 0x9479: 0x8F29, //CJK UNIFIED IDEOGRAPH + 0x947A: 0x914D, //CJK UNIFIED IDEOGRAPH + 0x947B: 0x500D, //CJK UNIFIED IDEOGRAPH + 0x947C: 0x57F9, //CJK UNIFIED IDEOGRAPH + 0x947D: 0x5A92, //CJK UNIFIED IDEOGRAPH + 0x947E: 0x6885, //CJK UNIFIED IDEOGRAPH + 0x9480: 0x6973, //CJK UNIFIED IDEOGRAPH + 0x9481: 0x7164, //CJK UNIFIED IDEOGRAPH + 0x9482: 0x72FD, //CJK UNIFIED IDEOGRAPH + 0x9483: 0x8CB7, //CJK UNIFIED IDEOGRAPH + 0x9484: 0x58F2, //CJK UNIFIED IDEOGRAPH + 0x9485: 0x8CE0, //CJK UNIFIED IDEOGRAPH + 0x9486: 0x966A, //CJK UNIFIED IDEOGRAPH + 0x9487: 0x9019, //CJK UNIFIED IDEOGRAPH + 0x9488: 0x877F, //CJK UNIFIED IDEOGRAPH + 0x9489: 0x79E4, //CJK UNIFIED IDEOGRAPH + 0x948A: 0x77E7, //CJK UNIFIED IDEOGRAPH + 0x948B: 0x8429, //CJK UNIFIED IDEOGRAPH + 0x948C: 0x4F2F, //CJK UNIFIED IDEOGRAPH + 0x948D: 0x5265, //CJK UNIFIED IDEOGRAPH + 0x948E: 0x535A, //CJK UNIFIED IDEOGRAPH + 0x948F: 0x62CD, //CJK UNIFIED IDEOGRAPH + 0x9490: 0x67CF, //CJK UNIFIED IDEOGRAPH + 0x9491: 0x6CCA, //CJK UNIFIED IDEOGRAPH + 0x9492: 0x767D, //CJK UNIFIED IDEOGRAPH + 0x9493: 0x7B94, //CJK UNIFIED IDEOGRAPH + 0x9494: 0x7C95, //CJK UNIFIED IDEOGRAPH + 0x9495: 0x8236, //CJK UNIFIED IDEOGRAPH + 0x9496: 0x8584, //CJK UNIFIED IDEOGRAPH + 0x9497: 0x8FEB, //CJK UNIFIED IDEOGRAPH + 0x9498: 0x66DD, //CJK UNIFIED IDEOGRAPH + 0x9499: 0x6F20, //CJK UNIFIED IDEOGRAPH + 0x949A: 0x7206, //CJK UNIFIED IDEOGRAPH + 0x949B: 0x7E1B, //CJK UNIFIED IDEOGRAPH + 0x949C: 0x83AB, //CJK UNIFIED IDEOGRAPH + 0x949D: 0x99C1, //CJK UNIFIED IDEOGRAPH + 0x949E: 0x9EA6, //CJK UNIFIED IDEOGRAPH + 0x949F: 0x51FD, //CJK UNIFIED IDEOGRAPH + 0x94A0: 0x7BB1, //CJK UNIFIED IDEOGRAPH + 0x94A1: 0x7872, //CJK UNIFIED IDEOGRAPH + 0x94A2: 0x7BB8, //CJK UNIFIED IDEOGRAPH + 0x94A3: 0x8087, //CJK UNIFIED IDEOGRAPH + 0x94A4: 0x7B48, //CJK UNIFIED IDEOGRAPH + 0x94A5: 0x6AE8, //CJK UNIFIED IDEOGRAPH + 0x94A6: 0x5E61, //CJK UNIFIED IDEOGRAPH + 0x94A7: 0x808C, //CJK UNIFIED IDEOGRAPH + 0x94A8: 0x7551, //CJK UNIFIED IDEOGRAPH + 0x94A9: 0x7560, //CJK UNIFIED IDEOGRAPH + 0x94AA: 0x516B, //CJK UNIFIED IDEOGRAPH + 0x94AB: 0x9262, //CJK UNIFIED IDEOGRAPH + 0x94AC: 0x6E8C, //CJK UNIFIED IDEOGRAPH + 0x94AD: 0x767A, //CJK UNIFIED IDEOGRAPH + 0x94AE: 0x9197, //CJK UNIFIED IDEOGRAPH + 0x94AF: 0x9AEA, //CJK UNIFIED IDEOGRAPH + 0x94B0: 0x4F10, //CJK UNIFIED IDEOGRAPH + 0x94B1: 0x7F70, //CJK UNIFIED IDEOGRAPH + 0x94B2: 0x629C, //CJK UNIFIED IDEOGRAPH + 0x94B3: 0x7B4F, //CJK UNIFIED IDEOGRAPH + 0x94B4: 0x95A5, //CJK UNIFIED IDEOGRAPH + 0x94B5: 0x9CE9, //CJK UNIFIED IDEOGRAPH + 0x94B6: 0x567A, //CJK UNIFIED IDEOGRAPH + 0x94B7: 0x5859, //CJK UNIFIED IDEOGRAPH + 0x94B8: 0x86E4, //CJK UNIFIED IDEOGRAPH + 0x94B9: 0x96BC, //CJK UNIFIED IDEOGRAPH + 0x94BA: 0x4F34, //CJK UNIFIED IDEOGRAPH + 0x94BB: 0x5224, //CJK UNIFIED IDEOGRAPH + 0x94BC: 0x534A, //CJK UNIFIED IDEOGRAPH + 0x94BD: 0x53CD, //CJK UNIFIED IDEOGRAPH + 0x94BE: 0x53DB, //CJK UNIFIED IDEOGRAPH + 0x94BF: 0x5E06, //CJK UNIFIED IDEOGRAPH + 0x94C0: 0x642C, //CJK UNIFIED IDEOGRAPH + 0x94C1: 0x6591, //CJK UNIFIED IDEOGRAPH + 0x94C2: 0x677F, //CJK UNIFIED IDEOGRAPH + 0x94C3: 0x6C3E, //CJK UNIFIED IDEOGRAPH + 0x94C4: 0x6C4E, //CJK UNIFIED IDEOGRAPH + 0x94C5: 0x7248, //CJK UNIFIED IDEOGRAPH + 0x94C6: 0x72AF, //CJK UNIFIED IDEOGRAPH + 0x94C7: 0x73ED, //CJK UNIFIED IDEOGRAPH + 0x94C8: 0x7554, //CJK UNIFIED IDEOGRAPH + 0x94C9: 0x7E41, //CJK UNIFIED IDEOGRAPH + 0x94CA: 0x822C, //CJK UNIFIED IDEOGRAPH + 0x94CB: 0x85E9, //CJK UNIFIED IDEOGRAPH + 0x94CC: 0x8CA9, //CJK UNIFIED IDEOGRAPH + 0x94CD: 0x7BC4, //CJK UNIFIED IDEOGRAPH + 0x94CE: 0x91C6, //CJK UNIFIED IDEOGRAPH + 0x94CF: 0x7169, //CJK UNIFIED IDEOGRAPH + 0x94D0: 0x9812, //CJK UNIFIED IDEOGRAPH + 0x94D1: 0x98EF, //CJK UNIFIED IDEOGRAPH + 0x94D2: 0x633D, //CJK UNIFIED IDEOGRAPH + 0x94D3: 0x6669, //CJK UNIFIED IDEOGRAPH + 0x94D4: 0x756A, //CJK UNIFIED IDEOGRAPH + 0x94D5: 0x76E4, //CJK UNIFIED IDEOGRAPH + 0x94D6: 0x78D0, //CJK UNIFIED IDEOGRAPH + 0x94D7: 0x8543, //CJK UNIFIED IDEOGRAPH + 0x94D8: 0x86EE, //CJK UNIFIED IDEOGRAPH + 0x94D9: 0x532A, //CJK UNIFIED IDEOGRAPH + 0x94DA: 0x5351, //CJK UNIFIED IDEOGRAPH + 0x94DB: 0x5426, //CJK UNIFIED IDEOGRAPH + 0x94DC: 0x5983, //CJK UNIFIED IDEOGRAPH + 0x94DD: 0x5E87, //CJK UNIFIED IDEOGRAPH + 0x94DE: 0x5F7C, //CJK UNIFIED IDEOGRAPH + 0x94DF: 0x60B2, //CJK UNIFIED IDEOGRAPH + 0x94E0: 0x6249, //CJK UNIFIED IDEOGRAPH + 0x94E1: 0x6279, //CJK UNIFIED IDEOGRAPH + 0x94E2: 0x62AB, //CJK UNIFIED IDEOGRAPH + 0x94E3: 0x6590, //CJK UNIFIED IDEOGRAPH + 0x94E4: 0x6BD4, //CJK UNIFIED IDEOGRAPH + 0x94E5: 0x6CCC, //CJK UNIFIED IDEOGRAPH + 0x94E6: 0x75B2, //CJK UNIFIED IDEOGRAPH + 0x94E7: 0x76AE, //CJK UNIFIED IDEOGRAPH + 0x94E8: 0x7891, //CJK UNIFIED IDEOGRAPH + 0x94E9: 0x79D8, //CJK UNIFIED IDEOGRAPH + 0x94EA: 0x7DCB, //CJK UNIFIED IDEOGRAPH + 0x94EB: 0x7F77, //CJK UNIFIED IDEOGRAPH + 0x94EC: 0x80A5, //CJK UNIFIED IDEOGRAPH + 0x94ED: 0x88AB, //CJK UNIFIED IDEOGRAPH + 0x94EE: 0x8AB9, //CJK UNIFIED IDEOGRAPH + 0x94EF: 0x8CBB, //CJK UNIFIED IDEOGRAPH + 0x94F0: 0x907F, //CJK UNIFIED IDEOGRAPH + 0x94F1: 0x975E, //CJK UNIFIED IDEOGRAPH + 0x94F2: 0x98DB, //CJK UNIFIED IDEOGRAPH + 0x94F3: 0x6A0B, //CJK UNIFIED IDEOGRAPH + 0x94F4: 0x7C38, //CJK UNIFIED IDEOGRAPH + 0x94F5: 0x5099, //CJK UNIFIED IDEOGRAPH + 0x94F6: 0x5C3E, //CJK UNIFIED IDEOGRAPH + 0x94F7: 0x5FAE, //CJK UNIFIED IDEOGRAPH + 0x94F8: 0x6787, //CJK UNIFIED IDEOGRAPH + 0x94F9: 0x6BD8, //CJK UNIFIED IDEOGRAPH + 0x94FA: 0x7435, //CJK UNIFIED IDEOGRAPH + 0x94FB: 0x7709, //CJK UNIFIED IDEOGRAPH + 0x94FC: 0x7F8E, //CJK UNIFIED IDEOGRAPH + 0x9540: 0x9F3B, //CJK UNIFIED IDEOGRAPH + 0x9541: 0x67CA, //CJK UNIFIED IDEOGRAPH + 0x9542: 0x7A17, //CJK UNIFIED IDEOGRAPH + 0x9543: 0x5339, //CJK UNIFIED IDEOGRAPH + 0x9544: 0x758B, //CJK UNIFIED IDEOGRAPH + 0x9545: 0x9AED, //CJK UNIFIED IDEOGRAPH + 0x9546: 0x5F66, //CJK UNIFIED IDEOGRAPH + 0x9547: 0x819D, //CJK UNIFIED IDEOGRAPH + 0x9548: 0x83F1, //CJK UNIFIED IDEOGRAPH + 0x9549: 0x8098, //CJK UNIFIED IDEOGRAPH + 0x954A: 0x5F3C, //CJK UNIFIED IDEOGRAPH + 0x954B: 0x5FC5, //CJK UNIFIED IDEOGRAPH + 0x954C: 0x7562, //CJK UNIFIED IDEOGRAPH + 0x954D: 0x7B46, //CJK UNIFIED IDEOGRAPH + 0x954E: 0x903C, //CJK UNIFIED IDEOGRAPH + 0x954F: 0x6867, //CJK UNIFIED IDEOGRAPH + 0x9550: 0x59EB, //CJK UNIFIED IDEOGRAPH + 0x9551: 0x5A9B, //CJK UNIFIED IDEOGRAPH + 0x9552: 0x7D10, //CJK UNIFIED IDEOGRAPH + 0x9553: 0x767E, //CJK UNIFIED IDEOGRAPH + 0x9554: 0x8B2C, //CJK UNIFIED IDEOGRAPH + 0x9555: 0x4FF5, //CJK UNIFIED IDEOGRAPH + 0x9556: 0x5F6A, //CJK UNIFIED IDEOGRAPH + 0x9557: 0x6A19, //CJK UNIFIED IDEOGRAPH + 0x9558: 0x6C37, //CJK UNIFIED IDEOGRAPH + 0x9559: 0x6F02, //CJK UNIFIED IDEOGRAPH + 0x955A: 0x74E2, //CJK UNIFIED IDEOGRAPH + 0x955B: 0x7968, //CJK UNIFIED IDEOGRAPH + 0x955C: 0x8868, //CJK UNIFIED IDEOGRAPH + 0x955D: 0x8A55, //CJK UNIFIED IDEOGRAPH + 0x955E: 0x8C79, //CJK UNIFIED IDEOGRAPH + 0x955F: 0x5EDF, //CJK UNIFIED IDEOGRAPH + 0x9560: 0x63CF, //CJK UNIFIED IDEOGRAPH + 0x9561: 0x75C5, //CJK UNIFIED IDEOGRAPH + 0x9562: 0x79D2, //CJK UNIFIED IDEOGRAPH + 0x9563: 0x82D7, //CJK UNIFIED IDEOGRAPH + 0x9564: 0x9328, //CJK UNIFIED IDEOGRAPH + 0x9565: 0x92F2, //CJK UNIFIED IDEOGRAPH + 0x9566: 0x849C, //CJK UNIFIED IDEOGRAPH + 0x9567: 0x86ED, //CJK UNIFIED IDEOGRAPH + 0x9568: 0x9C2D, //CJK UNIFIED IDEOGRAPH + 0x9569: 0x54C1, //CJK UNIFIED IDEOGRAPH + 0x956A: 0x5F6C, //CJK UNIFIED IDEOGRAPH + 0x956B: 0x658C, //CJK UNIFIED IDEOGRAPH + 0x956C: 0x6D5C, //CJK UNIFIED IDEOGRAPH + 0x956D: 0x7015, //CJK UNIFIED IDEOGRAPH + 0x956E: 0x8CA7, //CJK UNIFIED IDEOGRAPH + 0x956F: 0x8CD3, //CJK UNIFIED IDEOGRAPH + 0x9570: 0x983B, //CJK UNIFIED IDEOGRAPH + 0x9571: 0x654F, //CJK UNIFIED IDEOGRAPH + 0x9572: 0x74F6, //CJK UNIFIED IDEOGRAPH + 0x9573: 0x4E0D, //CJK UNIFIED IDEOGRAPH + 0x9574: 0x4ED8, //CJK UNIFIED IDEOGRAPH + 0x9575: 0x57E0, //CJK UNIFIED IDEOGRAPH + 0x9576: 0x592B, //CJK UNIFIED IDEOGRAPH + 0x9577: 0x5A66, //CJK UNIFIED IDEOGRAPH + 0x9578: 0x5BCC, //CJK UNIFIED IDEOGRAPH + 0x9579: 0x51A8, //CJK UNIFIED IDEOGRAPH + 0x957A: 0x5E03, //CJK UNIFIED IDEOGRAPH + 0x957B: 0x5E9C, //CJK UNIFIED IDEOGRAPH + 0x957C: 0x6016, //CJK UNIFIED IDEOGRAPH + 0x957D: 0x6276, //CJK UNIFIED IDEOGRAPH + 0x957E: 0x6577, //CJK UNIFIED IDEOGRAPH + 0x9580: 0x65A7, //CJK UNIFIED IDEOGRAPH + 0x9581: 0x666E, //CJK UNIFIED IDEOGRAPH + 0x9582: 0x6D6E, //CJK UNIFIED IDEOGRAPH + 0x9583: 0x7236, //CJK UNIFIED IDEOGRAPH + 0x9584: 0x7B26, //CJK UNIFIED IDEOGRAPH + 0x9585: 0x8150, //CJK UNIFIED IDEOGRAPH + 0x9586: 0x819A, //CJK UNIFIED IDEOGRAPH + 0x9587: 0x8299, //CJK UNIFIED IDEOGRAPH + 0x9588: 0x8B5C, //CJK UNIFIED IDEOGRAPH + 0x9589: 0x8CA0, //CJK UNIFIED IDEOGRAPH + 0x958A: 0x8CE6, //CJK UNIFIED IDEOGRAPH + 0x958B: 0x8D74, //CJK UNIFIED IDEOGRAPH + 0x958C: 0x961C, //CJK UNIFIED IDEOGRAPH + 0x958D: 0x9644, //CJK UNIFIED IDEOGRAPH + 0x958E: 0x4FAE, //CJK UNIFIED IDEOGRAPH + 0x958F: 0x64AB, //CJK UNIFIED IDEOGRAPH + 0x9590: 0x6B66, //CJK UNIFIED IDEOGRAPH + 0x9591: 0x821E, //CJK UNIFIED IDEOGRAPH + 0x9592: 0x8461, //CJK UNIFIED IDEOGRAPH + 0x9593: 0x856A, //CJK UNIFIED IDEOGRAPH + 0x9594: 0x90E8, //CJK UNIFIED IDEOGRAPH + 0x9595: 0x5C01, //CJK UNIFIED IDEOGRAPH + 0x9596: 0x6953, //CJK UNIFIED IDEOGRAPH + 0x9597: 0x98A8, //CJK UNIFIED IDEOGRAPH + 0x9598: 0x847A, //CJK UNIFIED IDEOGRAPH + 0x9599: 0x8557, //CJK UNIFIED IDEOGRAPH + 0x959A: 0x4F0F, //CJK UNIFIED IDEOGRAPH + 0x959B: 0x526F, //CJK UNIFIED IDEOGRAPH + 0x959C: 0x5FA9, //CJK UNIFIED IDEOGRAPH + 0x959D: 0x5E45, //CJK UNIFIED IDEOGRAPH + 0x959E: 0x670D, //CJK UNIFIED IDEOGRAPH + 0x959F: 0x798F, //CJK UNIFIED IDEOGRAPH + 0x95A0: 0x8179, //CJK UNIFIED IDEOGRAPH + 0x95A1: 0x8907, //CJK UNIFIED IDEOGRAPH + 0x95A2: 0x8986, //CJK UNIFIED IDEOGRAPH + 0x95A3: 0x6DF5, //CJK UNIFIED IDEOGRAPH + 0x95A4: 0x5F17, //CJK UNIFIED IDEOGRAPH + 0x95A5: 0x6255, //CJK UNIFIED IDEOGRAPH + 0x95A6: 0x6CB8, //CJK UNIFIED IDEOGRAPH + 0x95A7: 0x4ECF, //CJK UNIFIED IDEOGRAPH + 0x95A8: 0x7269, //CJK UNIFIED IDEOGRAPH + 0x95A9: 0x9B92, //CJK UNIFIED IDEOGRAPH + 0x95AA: 0x5206, //CJK UNIFIED IDEOGRAPH + 0x95AB: 0x543B, //CJK UNIFIED IDEOGRAPH + 0x95AC: 0x5674, //CJK UNIFIED IDEOGRAPH + 0x95AD: 0x58B3, //CJK UNIFIED IDEOGRAPH + 0x95AE: 0x61A4, //CJK UNIFIED IDEOGRAPH + 0x95AF: 0x626E, //CJK UNIFIED IDEOGRAPH + 0x95B0: 0x711A, //CJK UNIFIED IDEOGRAPH + 0x95B1: 0x596E, //CJK UNIFIED IDEOGRAPH + 0x95B2: 0x7C89, //CJK UNIFIED IDEOGRAPH + 0x95B3: 0x7CDE, //CJK UNIFIED IDEOGRAPH + 0x95B4: 0x7D1B, //CJK UNIFIED IDEOGRAPH + 0x95B5: 0x96F0, //CJK UNIFIED IDEOGRAPH + 0x95B6: 0x6587, //CJK UNIFIED IDEOGRAPH + 0x95B7: 0x805E, //CJK UNIFIED IDEOGRAPH + 0x95B8: 0x4E19, //CJK UNIFIED IDEOGRAPH + 0x95B9: 0x4F75, //CJK UNIFIED IDEOGRAPH + 0x95BA: 0x5175, //CJK UNIFIED IDEOGRAPH + 0x95BB: 0x5840, //CJK UNIFIED IDEOGRAPH + 0x95BC: 0x5E63, //CJK UNIFIED IDEOGRAPH + 0x95BD: 0x5E73, //CJK UNIFIED IDEOGRAPH + 0x95BE: 0x5F0A, //CJK UNIFIED IDEOGRAPH + 0x95BF: 0x67C4, //CJK UNIFIED IDEOGRAPH + 0x95C0: 0x4E26, //CJK UNIFIED IDEOGRAPH + 0x95C1: 0x853D, //CJK UNIFIED IDEOGRAPH + 0x95C2: 0x9589, //CJK UNIFIED IDEOGRAPH + 0x95C3: 0x965B, //CJK UNIFIED IDEOGRAPH + 0x95C4: 0x7C73, //CJK UNIFIED IDEOGRAPH + 0x95C5: 0x9801, //CJK UNIFIED IDEOGRAPH + 0x95C6: 0x50FB, //CJK UNIFIED IDEOGRAPH + 0x95C7: 0x58C1, //CJK UNIFIED IDEOGRAPH + 0x95C8: 0x7656, //CJK UNIFIED IDEOGRAPH + 0x95C9: 0x78A7, //CJK UNIFIED IDEOGRAPH + 0x95CA: 0x5225, //CJK UNIFIED IDEOGRAPH + 0x95CB: 0x77A5, //CJK UNIFIED IDEOGRAPH + 0x95CC: 0x8511, //CJK UNIFIED IDEOGRAPH + 0x95CD: 0x7B86, //CJK UNIFIED IDEOGRAPH + 0x95CE: 0x504F, //CJK UNIFIED IDEOGRAPH + 0x95CF: 0x5909, //CJK UNIFIED IDEOGRAPH + 0x95D0: 0x7247, //CJK UNIFIED IDEOGRAPH + 0x95D1: 0x7BC7, //CJK UNIFIED IDEOGRAPH + 0x95D2: 0x7DE8, //CJK UNIFIED IDEOGRAPH + 0x95D3: 0x8FBA, //CJK UNIFIED IDEOGRAPH + 0x95D4: 0x8FD4, //CJK UNIFIED IDEOGRAPH + 0x95D5: 0x904D, //CJK UNIFIED IDEOGRAPH + 0x95D6: 0x4FBF, //CJK UNIFIED IDEOGRAPH + 0x95D7: 0x52C9, //CJK UNIFIED IDEOGRAPH + 0x95D8: 0x5A29, //CJK UNIFIED IDEOGRAPH + 0x95D9: 0x5F01, //CJK UNIFIED IDEOGRAPH + 0x95DA: 0x97AD, //CJK UNIFIED IDEOGRAPH + 0x95DB: 0x4FDD, //CJK UNIFIED IDEOGRAPH + 0x95DC: 0x8217, //CJK UNIFIED IDEOGRAPH + 0x95DD: 0x92EA, //CJK UNIFIED IDEOGRAPH + 0x95DE: 0x5703, //CJK UNIFIED IDEOGRAPH + 0x95DF: 0x6355, //CJK UNIFIED IDEOGRAPH + 0x95E0: 0x6B69, //CJK UNIFIED IDEOGRAPH + 0x95E1: 0x752B, //CJK UNIFIED IDEOGRAPH + 0x95E2: 0x88DC, //CJK UNIFIED IDEOGRAPH + 0x95E3: 0x8F14, //CJK UNIFIED IDEOGRAPH + 0x95E4: 0x7A42, //CJK UNIFIED IDEOGRAPH + 0x95E5: 0x52DF, //CJK UNIFIED IDEOGRAPH + 0x95E6: 0x5893, //CJK UNIFIED IDEOGRAPH + 0x95E7: 0x6155, //CJK UNIFIED IDEOGRAPH + 0x95E8: 0x620A, //CJK UNIFIED IDEOGRAPH + 0x95E9: 0x66AE, //CJK UNIFIED IDEOGRAPH + 0x95EA: 0x6BCD, //CJK UNIFIED IDEOGRAPH + 0x95EB: 0x7C3F, //CJK UNIFIED IDEOGRAPH + 0x95EC: 0x83E9, //CJK UNIFIED IDEOGRAPH + 0x95ED: 0x5023, //CJK UNIFIED IDEOGRAPH + 0x95EE: 0x4FF8, //CJK UNIFIED IDEOGRAPH + 0x95EF: 0x5305, //CJK UNIFIED IDEOGRAPH + 0x95F0: 0x5446, //CJK UNIFIED IDEOGRAPH + 0x95F1: 0x5831, //CJK UNIFIED IDEOGRAPH + 0x95F2: 0x5949, //CJK UNIFIED IDEOGRAPH + 0x95F3: 0x5B9D, //CJK UNIFIED IDEOGRAPH + 0x95F4: 0x5CF0, //CJK UNIFIED IDEOGRAPH + 0x95F5: 0x5CEF, //CJK UNIFIED IDEOGRAPH + 0x95F6: 0x5D29, //CJK UNIFIED IDEOGRAPH + 0x95F7: 0x5E96, //CJK UNIFIED IDEOGRAPH + 0x95F8: 0x62B1, //CJK UNIFIED IDEOGRAPH + 0x95F9: 0x6367, //CJK UNIFIED IDEOGRAPH + 0x95FA: 0x653E, //CJK UNIFIED IDEOGRAPH + 0x95FB: 0x65B9, //CJK UNIFIED IDEOGRAPH + 0x95FC: 0x670B, //CJK UNIFIED IDEOGRAPH + 0x9640: 0x6CD5, //CJK UNIFIED IDEOGRAPH + 0x9641: 0x6CE1, //CJK UNIFIED IDEOGRAPH + 0x9642: 0x70F9, //CJK UNIFIED IDEOGRAPH + 0x9643: 0x7832, //CJK UNIFIED IDEOGRAPH + 0x9644: 0x7E2B, //CJK UNIFIED IDEOGRAPH + 0x9645: 0x80DE, //CJK UNIFIED IDEOGRAPH + 0x9646: 0x82B3, //CJK UNIFIED IDEOGRAPH + 0x9647: 0x840C, //CJK UNIFIED IDEOGRAPH + 0x9648: 0x84EC, //CJK UNIFIED IDEOGRAPH + 0x9649: 0x8702, //CJK UNIFIED IDEOGRAPH + 0x964A: 0x8912, //CJK UNIFIED IDEOGRAPH + 0x964B: 0x8A2A, //CJK UNIFIED IDEOGRAPH + 0x964C: 0x8C4A, //CJK UNIFIED IDEOGRAPH + 0x964D: 0x90A6, //CJK UNIFIED IDEOGRAPH + 0x964E: 0x92D2, //CJK UNIFIED IDEOGRAPH + 0x964F: 0x98FD, //CJK UNIFIED IDEOGRAPH + 0x9650: 0x9CF3, //CJK UNIFIED IDEOGRAPH + 0x9651: 0x9D6C, //CJK UNIFIED IDEOGRAPH + 0x9652: 0x4E4F, //CJK UNIFIED IDEOGRAPH + 0x9653: 0x4EA1, //CJK UNIFIED IDEOGRAPH + 0x9654: 0x508D, //CJK UNIFIED IDEOGRAPH + 0x9655: 0x5256, //CJK UNIFIED IDEOGRAPH + 0x9656: 0x574A, //CJK UNIFIED IDEOGRAPH + 0x9657: 0x59A8, //CJK UNIFIED IDEOGRAPH + 0x9658: 0x5E3D, //CJK UNIFIED IDEOGRAPH + 0x9659: 0x5FD8, //CJK UNIFIED IDEOGRAPH + 0x965A: 0x5FD9, //CJK UNIFIED IDEOGRAPH + 0x965B: 0x623F, //CJK UNIFIED IDEOGRAPH + 0x965C: 0x66B4, //CJK UNIFIED IDEOGRAPH + 0x965D: 0x671B, //CJK UNIFIED IDEOGRAPH + 0x965E: 0x67D0, //CJK UNIFIED IDEOGRAPH + 0x965F: 0x68D2, //CJK UNIFIED IDEOGRAPH + 0x9660: 0x5192, //CJK UNIFIED IDEOGRAPH + 0x9661: 0x7D21, //CJK UNIFIED IDEOGRAPH + 0x9662: 0x80AA, //CJK UNIFIED IDEOGRAPH + 0x9663: 0x81A8, //CJK UNIFIED IDEOGRAPH + 0x9664: 0x8B00, //CJK UNIFIED IDEOGRAPH + 0x9665: 0x8C8C, //CJK UNIFIED IDEOGRAPH + 0x9666: 0x8CBF, //CJK UNIFIED IDEOGRAPH + 0x9667: 0x927E, //CJK UNIFIED IDEOGRAPH + 0x9668: 0x9632, //CJK UNIFIED IDEOGRAPH + 0x9669: 0x5420, //CJK UNIFIED IDEOGRAPH + 0x966A: 0x982C, //CJK UNIFIED IDEOGRAPH + 0x966B: 0x5317, //CJK UNIFIED IDEOGRAPH + 0x966C: 0x50D5, //CJK UNIFIED IDEOGRAPH + 0x966D: 0x535C, //CJK UNIFIED IDEOGRAPH + 0x966E: 0x58A8, //CJK UNIFIED IDEOGRAPH + 0x966F: 0x64B2, //CJK UNIFIED IDEOGRAPH + 0x9670: 0x6734, //CJK UNIFIED IDEOGRAPH + 0x9671: 0x7267, //CJK UNIFIED IDEOGRAPH + 0x9672: 0x7766, //CJK UNIFIED IDEOGRAPH + 0x9673: 0x7A46, //CJK UNIFIED IDEOGRAPH + 0x9674: 0x91E6, //CJK UNIFIED IDEOGRAPH + 0x9675: 0x52C3, //CJK UNIFIED IDEOGRAPH + 0x9676: 0x6CA1, //CJK UNIFIED IDEOGRAPH + 0x9677: 0x6B86, //CJK UNIFIED IDEOGRAPH + 0x9678: 0x5800, //CJK UNIFIED IDEOGRAPH + 0x9679: 0x5E4C, //CJK UNIFIED IDEOGRAPH + 0x967A: 0x5954, //CJK UNIFIED IDEOGRAPH + 0x967B: 0x672C, //CJK UNIFIED IDEOGRAPH + 0x967C: 0x7FFB, //CJK UNIFIED IDEOGRAPH + 0x967D: 0x51E1, //CJK UNIFIED IDEOGRAPH + 0x967E: 0x76C6, //CJK UNIFIED IDEOGRAPH + 0x9680: 0x6469, //CJK UNIFIED IDEOGRAPH + 0x9681: 0x78E8, //CJK UNIFIED IDEOGRAPH + 0x9682: 0x9B54, //CJK UNIFIED IDEOGRAPH + 0x9683: 0x9EBB, //CJK UNIFIED IDEOGRAPH + 0x9684: 0x57CB, //CJK UNIFIED IDEOGRAPH + 0x9685: 0x59B9, //CJK UNIFIED IDEOGRAPH + 0x9686: 0x6627, //CJK UNIFIED IDEOGRAPH + 0x9687: 0x679A, //CJK UNIFIED IDEOGRAPH + 0x9688: 0x6BCE, //CJK UNIFIED IDEOGRAPH + 0x9689: 0x54E9, //CJK UNIFIED IDEOGRAPH + 0x968A: 0x69D9, //CJK UNIFIED IDEOGRAPH + 0x968B: 0x5E55, //CJK UNIFIED IDEOGRAPH + 0x968C: 0x819C, //CJK UNIFIED IDEOGRAPH + 0x968D: 0x6795, //CJK UNIFIED IDEOGRAPH + 0x968E: 0x9BAA, //CJK UNIFIED IDEOGRAPH + 0x968F: 0x67FE, //CJK UNIFIED IDEOGRAPH + 0x9690: 0x9C52, //CJK UNIFIED IDEOGRAPH + 0x9691: 0x685D, //CJK UNIFIED IDEOGRAPH + 0x9692: 0x4EA6, //CJK UNIFIED IDEOGRAPH + 0x9693: 0x4FE3, //CJK UNIFIED IDEOGRAPH + 0x9694: 0x53C8, //CJK UNIFIED IDEOGRAPH + 0x9695: 0x62B9, //CJK UNIFIED IDEOGRAPH + 0x9696: 0x672B, //CJK UNIFIED IDEOGRAPH + 0x9697: 0x6CAB, //CJK UNIFIED IDEOGRAPH + 0x9698: 0x8FC4, //CJK UNIFIED IDEOGRAPH + 0x9699: 0x4FAD, //CJK UNIFIED IDEOGRAPH + 0x969A: 0x7E6D, //CJK UNIFIED IDEOGRAPH + 0x969B: 0x9EBF, //CJK UNIFIED IDEOGRAPH + 0x969C: 0x4E07, //CJK UNIFIED IDEOGRAPH + 0x969D: 0x6162, //CJK UNIFIED IDEOGRAPH + 0x969E: 0x6E80, //CJK UNIFIED IDEOGRAPH + 0x969F: 0x6F2B, //CJK UNIFIED IDEOGRAPH + 0x96A0: 0x8513, //CJK UNIFIED IDEOGRAPH + 0x96A1: 0x5473, //CJK UNIFIED IDEOGRAPH + 0x96A2: 0x672A, //CJK UNIFIED IDEOGRAPH + 0x96A3: 0x9B45, //CJK UNIFIED IDEOGRAPH + 0x96A4: 0x5DF3, //CJK UNIFIED IDEOGRAPH + 0x96A5: 0x7B95, //CJK UNIFIED IDEOGRAPH + 0x96A6: 0x5CAC, //CJK UNIFIED IDEOGRAPH + 0x96A7: 0x5BC6, //CJK UNIFIED IDEOGRAPH + 0x96A8: 0x871C, //CJK UNIFIED IDEOGRAPH + 0x96A9: 0x6E4A, //CJK UNIFIED IDEOGRAPH + 0x96AA: 0x84D1, //CJK UNIFIED IDEOGRAPH + 0x96AB: 0x7A14, //CJK UNIFIED IDEOGRAPH + 0x96AC: 0x8108, //CJK UNIFIED IDEOGRAPH + 0x96AD: 0x5999, //CJK UNIFIED IDEOGRAPH + 0x96AE: 0x7C8D, //CJK UNIFIED IDEOGRAPH + 0x96AF: 0x6C11, //CJK UNIFIED IDEOGRAPH + 0x96B0: 0x7720, //CJK UNIFIED IDEOGRAPH + 0x96B1: 0x52D9, //CJK UNIFIED IDEOGRAPH + 0x96B2: 0x5922, //CJK UNIFIED IDEOGRAPH + 0x96B3: 0x7121, //CJK UNIFIED IDEOGRAPH + 0x96B4: 0x725F, //CJK UNIFIED IDEOGRAPH + 0x96B5: 0x77DB, //CJK UNIFIED IDEOGRAPH + 0x96B6: 0x9727, //CJK UNIFIED IDEOGRAPH + 0x96B7: 0x9D61, //CJK UNIFIED IDEOGRAPH + 0x96B8: 0x690B, //CJK UNIFIED IDEOGRAPH + 0x96B9: 0x5A7F, //CJK UNIFIED IDEOGRAPH + 0x96BA: 0x5A18, //CJK UNIFIED IDEOGRAPH + 0x96BB: 0x51A5, //CJK UNIFIED IDEOGRAPH + 0x96BC: 0x540D, //CJK UNIFIED IDEOGRAPH + 0x96BD: 0x547D, //CJK UNIFIED IDEOGRAPH + 0x96BE: 0x660E, //CJK UNIFIED IDEOGRAPH + 0x96BF: 0x76DF, //CJK UNIFIED IDEOGRAPH + 0x96C0: 0x8FF7, //CJK UNIFIED IDEOGRAPH + 0x96C1: 0x9298, //CJK UNIFIED IDEOGRAPH + 0x96C2: 0x9CF4, //CJK UNIFIED IDEOGRAPH + 0x96C3: 0x59EA, //CJK UNIFIED IDEOGRAPH + 0x96C4: 0x725D, //CJK UNIFIED IDEOGRAPH + 0x96C5: 0x6EC5, //CJK UNIFIED IDEOGRAPH + 0x96C6: 0x514D, //CJK UNIFIED IDEOGRAPH + 0x96C7: 0x68C9, //CJK UNIFIED IDEOGRAPH + 0x96C8: 0x7DBF, //CJK UNIFIED IDEOGRAPH + 0x96C9: 0x7DEC, //CJK UNIFIED IDEOGRAPH + 0x96CA: 0x9762, //CJK UNIFIED IDEOGRAPH + 0x96CB: 0x9EBA, //CJK UNIFIED IDEOGRAPH + 0x96CC: 0x6478, //CJK UNIFIED IDEOGRAPH + 0x96CD: 0x6A21, //CJK UNIFIED IDEOGRAPH + 0x96CE: 0x8302, //CJK UNIFIED IDEOGRAPH + 0x96CF: 0x5984, //CJK UNIFIED IDEOGRAPH + 0x96D0: 0x5B5F, //CJK UNIFIED IDEOGRAPH + 0x96D1: 0x6BDB, //CJK UNIFIED IDEOGRAPH + 0x96D2: 0x731B, //CJK UNIFIED IDEOGRAPH + 0x96D3: 0x76F2, //CJK UNIFIED IDEOGRAPH + 0x96D4: 0x7DB2, //CJK UNIFIED IDEOGRAPH + 0x96D5: 0x8017, //CJK UNIFIED IDEOGRAPH + 0x96D6: 0x8499, //CJK UNIFIED IDEOGRAPH + 0x96D7: 0x5132, //CJK UNIFIED IDEOGRAPH + 0x96D8: 0x6728, //CJK UNIFIED IDEOGRAPH + 0x96D9: 0x9ED9, //CJK UNIFIED IDEOGRAPH + 0x96DA: 0x76EE, //CJK UNIFIED IDEOGRAPH + 0x96DB: 0x6762, //CJK UNIFIED IDEOGRAPH + 0x96DC: 0x52FF, //CJK UNIFIED IDEOGRAPH + 0x96DD: 0x9905, //CJK UNIFIED IDEOGRAPH + 0x96DE: 0x5C24, //CJK UNIFIED IDEOGRAPH + 0x96DF: 0x623B, //CJK UNIFIED IDEOGRAPH + 0x96E0: 0x7C7E, //CJK UNIFIED IDEOGRAPH + 0x96E1: 0x8CB0, //CJK UNIFIED IDEOGRAPH + 0x96E2: 0x554F, //CJK UNIFIED IDEOGRAPH + 0x96E3: 0x60B6, //CJK UNIFIED IDEOGRAPH + 0x96E4: 0x7D0B, //CJK UNIFIED IDEOGRAPH + 0x96E5: 0x9580, //CJK UNIFIED IDEOGRAPH + 0x96E6: 0x5301, //CJK UNIFIED IDEOGRAPH + 0x96E7: 0x4E5F, //CJK UNIFIED IDEOGRAPH + 0x96E8: 0x51B6, //CJK UNIFIED IDEOGRAPH + 0x96E9: 0x591C, //CJK UNIFIED IDEOGRAPH + 0x96EA: 0x723A, //CJK UNIFIED IDEOGRAPH + 0x96EB: 0x8036, //CJK UNIFIED IDEOGRAPH + 0x96EC: 0x91CE, //CJK UNIFIED IDEOGRAPH + 0x96ED: 0x5F25, //CJK UNIFIED IDEOGRAPH + 0x96EE: 0x77E2, //CJK UNIFIED IDEOGRAPH + 0x96EF: 0x5384, //CJK UNIFIED IDEOGRAPH + 0x96F0: 0x5F79, //CJK UNIFIED IDEOGRAPH + 0x96F1: 0x7D04, //CJK UNIFIED IDEOGRAPH + 0x96F2: 0x85AC, //CJK UNIFIED IDEOGRAPH + 0x96F3: 0x8A33, //CJK UNIFIED IDEOGRAPH + 0x96F4: 0x8E8D, //CJK UNIFIED IDEOGRAPH + 0x96F5: 0x9756, //CJK UNIFIED IDEOGRAPH + 0x96F6: 0x67F3, //CJK UNIFIED IDEOGRAPH + 0x96F7: 0x85AE, //CJK UNIFIED IDEOGRAPH + 0x96F8: 0x9453, //CJK UNIFIED IDEOGRAPH + 0x96F9: 0x6109, //CJK UNIFIED IDEOGRAPH + 0x96FA: 0x6108, //CJK UNIFIED IDEOGRAPH + 0x96FB: 0x6CB9, //CJK UNIFIED IDEOGRAPH + 0x96FC: 0x7652, //CJK UNIFIED IDEOGRAPH + 0x9740: 0x8AED, //CJK UNIFIED IDEOGRAPH + 0x9741: 0x8F38, //CJK UNIFIED IDEOGRAPH + 0x9742: 0x552F, //CJK UNIFIED IDEOGRAPH + 0x9743: 0x4F51, //CJK UNIFIED IDEOGRAPH + 0x9744: 0x512A, //CJK UNIFIED IDEOGRAPH + 0x9745: 0x52C7, //CJK UNIFIED IDEOGRAPH + 0x9746: 0x53CB, //CJK UNIFIED IDEOGRAPH + 0x9747: 0x5BA5, //CJK UNIFIED IDEOGRAPH + 0x9748: 0x5E7D, //CJK UNIFIED IDEOGRAPH + 0x9749: 0x60A0, //CJK UNIFIED IDEOGRAPH + 0x974A: 0x6182, //CJK UNIFIED IDEOGRAPH + 0x974B: 0x63D6, //CJK UNIFIED IDEOGRAPH + 0x974C: 0x6709, //CJK UNIFIED IDEOGRAPH + 0x974D: 0x67DA, //CJK UNIFIED IDEOGRAPH + 0x974E: 0x6E67, //CJK UNIFIED IDEOGRAPH + 0x974F: 0x6D8C, //CJK UNIFIED IDEOGRAPH + 0x9750: 0x7336, //CJK UNIFIED IDEOGRAPH + 0x9751: 0x7337, //CJK UNIFIED IDEOGRAPH + 0x9752: 0x7531, //CJK UNIFIED IDEOGRAPH + 0x9753: 0x7950, //CJK UNIFIED IDEOGRAPH + 0x9754: 0x88D5, //CJK UNIFIED IDEOGRAPH + 0x9755: 0x8A98, //CJK UNIFIED IDEOGRAPH + 0x9756: 0x904A, //CJK UNIFIED IDEOGRAPH + 0x9757: 0x9091, //CJK UNIFIED IDEOGRAPH + 0x9758: 0x90F5, //CJK UNIFIED IDEOGRAPH + 0x9759: 0x96C4, //CJK UNIFIED IDEOGRAPH + 0x975A: 0x878D, //CJK UNIFIED IDEOGRAPH + 0x975B: 0x5915, //CJK UNIFIED IDEOGRAPH + 0x975C: 0x4E88, //CJK UNIFIED IDEOGRAPH + 0x975D: 0x4F59, //CJK UNIFIED IDEOGRAPH + 0x975E: 0x4E0E, //CJK UNIFIED IDEOGRAPH + 0x975F: 0x8A89, //CJK UNIFIED IDEOGRAPH + 0x9760: 0x8F3F, //CJK UNIFIED IDEOGRAPH + 0x9761: 0x9810, //CJK UNIFIED IDEOGRAPH + 0x9762: 0x50AD, //CJK UNIFIED IDEOGRAPH + 0x9763: 0x5E7C, //CJK UNIFIED IDEOGRAPH + 0x9764: 0x5996, //CJK UNIFIED IDEOGRAPH + 0x9765: 0x5BB9, //CJK UNIFIED IDEOGRAPH + 0x9766: 0x5EB8, //CJK UNIFIED IDEOGRAPH + 0x9767: 0x63DA, //CJK UNIFIED IDEOGRAPH + 0x9768: 0x63FA, //CJK UNIFIED IDEOGRAPH + 0x9769: 0x64C1, //CJK UNIFIED IDEOGRAPH + 0x976A: 0x66DC, //CJK UNIFIED IDEOGRAPH + 0x976B: 0x694A, //CJK UNIFIED IDEOGRAPH + 0x976C: 0x69D8, //CJK UNIFIED IDEOGRAPH + 0x976D: 0x6D0B, //CJK UNIFIED IDEOGRAPH + 0x976E: 0x6EB6, //CJK UNIFIED IDEOGRAPH + 0x976F: 0x7194, //CJK UNIFIED IDEOGRAPH + 0x9770: 0x7528, //CJK UNIFIED IDEOGRAPH + 0x9771: 0x7AAF, //CJK UNIFIED IDEOGRAPH + 0x9772: 0x7F8A, //CJK UNIFIED IDEOGRAPH + 0x9773: 0x8000, //CJK UNIFIED IDEOGRAPH + 0x9774: 0x8449, //CJK UNIFIED IDEOGRAPH + 0x9775: 0x84C9, //CJK UNIFIED IDEOGRAPH + 0x9776: 0x8981, //CJK UNIFIED IDEOGRAPH + 0x9777: 0x8B21, //CJK UNIFIED IDEOGRAPH + 0x9778: 0x8E0A, //CJK UNIFIED IDEOGRAPH + 0x9779: 0x9065, //CJK UNIFIED IDEOGRAPH + 0x977A: 0x967D, //CJK UNIFIED IDEOGRAPH + 0x977B: 0x990A, //CJK UNIFIED IDEOGRAPH + 0x977C: 0x617E, //CJK UNIFIED IDEOGRAPH + 0x977D: 0x6291, //CJK UNIFIED IDEOGRAPH + 0x977E: 0x6B32, //CJK UNIFIED IDEOGRAPH + 0x9780: 0x6C83, //CJK UNIFIED IDEOGRAPH + 0x9781: 0x6D74, //CJK UNIFIED IDEOGRAPH + 0x9782: 0x7FCC, //CJK UNIFIED IDEOGRAPH + 0x9783: 0x7FFC, //CJK UNIFIED IDEOGRAPH + 0x9784: 0x6DC0, //CJK UNIFIED IDEOGRAPH + 0x9785: 0x7F85, //CJK UNIFIED IDEOGRAPH + 0x9786: 0x87BA, //CJK UNIFIED IDEOGRAPH + 0x9787: 0x88F8, //CJK UNIFIED IDEOGRAPH + 0x9788: 0x6765, //CJK UNIFIED IDEOGRAPH + 0x9789: 0x83B1, //CJK UNIFIED IDEOGRAPH + 0x978A: 0x983C, //CJK UNIFIED IDEOGRAPH + 0x978B: 0x96F7, //CJK UNIFIED IDEOGRAPH + 0x978C: 0x6D1B, //CJK UNIFIED IDEOGRAPH + 0x978D: 0x7D61, //CJK UNIFIED IDEOGRAPH + 0x978E: 0x843D, //CJK UNIFIED IDEOGRAPH + 0x978F: 0x916A, //CJK UNIFIED IDEOGRAPH + 0x9790: 0x4E71, //CJK UNIFIED IDEOGRAPH + 0x9791: 0x5375, //CJK UNIFIED IDEOGRAPH + 0x9792: 0x5D50, //CJK UNIFIED IDEOGRAPH + 0x9793: 0x6B04, //CJK UNIFIED IDEOGRAPH + 0x9794: 0x6FEB, //CJK UNIFIED IDEOGRAPH + 0x9795: 0x85CD, //CJK UNIFIED IDEOGRAPH + 0x9796: 0x862D, //CJK UNIFIED IDEOGRAPH + 0x9797: 0x89A7, //CJK UNIFIED IDEOGRAPH + 0x9798: 0x5229, //CJK UNIFIED IDEOGRAPH + 0x9799: 0x540F, //CJK UNIFIED IDEOGRAPH + 0x979A: 0x5C65, //CJK UNIFIED IDEOGRAPH + 0x979B: 0x674E, //CJK UNIFIED IDEOGRAPH + 0x979C: 0x68A8, //CJK UNIFIED IDEOGRAPH + 0x979D: 0x7406, //CJK UNIFIED IDEOGRAPH + 0x979E: 0x7483, //CJK UNIFIED IDEOGRAPH + 0x979F: 0x75E2, //CJK UNIFIED IDEOGRAPH + 0x97A0: 0x88CF, //CJK UNIFIED IDEOGRAPH + 0x97A1: 0x88E1, //CJK UNIFIED IDEOGRAPH + 0x97A2: 0x91CC, //CJK UNIFIED IDEOGRAPH + 0x97A3: 0x96E2, //CJK UNIFIED IDEOGRAPH + 0x97A4: 0x9678, //CJK UNIFIED IDEOGRAPH + 0x97A5: 0x5F8B, //CJK UNIFIED IDEOGRAPH + 0x97A6: 0x7387, //CJK UNIFIED IDEOGRAPH + 0x97A7: 0x7ACB, //CJK UNIFIED IDEOGRAPH + 0x97A8: 0x844E, //CJK UNIFIED IDEOGRAPH + 0x97A9: 0x63A0, //CJK UNIFIED IDEOGRAPH + 0x97AA: 0x7565, //CJK UNIFIED IDEOGRAPH + 0x97AB: 0x5289, //CJK UNIFIED IDEOGRAPH + 0x97AC: 0x6D41, //CJK UNIFIED IDEOGRAPH + 0x97AD: 0x6E9C, //CJK UNIFIED IDEOGRAPH + 0x97AE: 0x7409, //CJK UNIFIED IDEOGRAPH + 0x97AF: 0x7559, //CJK UNIFIED IDEOGRAPH + 0x97B0: 0x786B, //CJK UNIFIED IDEOGRAPH + 0x97B1: 0x7C92, //CJK UNIFIED IDEOGRAPH + 0x97B2: 0x9686, //CJK UNIFIED IDEOGRAPH + 0x97B3: 0x7ADC, //CJK UNIFIED IDEOGRAPH + 0x97B4: 0x9F8D, //CJK UNIFIED IDEOGRAPH + 0x97B5: 0x4FB6, //CJK UNIFIED IDEOGRAPH + 0x97B6: 0x616E, //CJK UNIFIED IDEOGRAPH + 0x97B7: 0x65C5, //CJK UNIFIED IDEOGRAPH + 0x97B8: 0x865C, //CJK UNIFIED IDEOGRAPH + 0x97B9: 0x4E86, //CJK UNIFIED IDEOGRAPH + 0x97BA: 0x4EAE, //CJK UNIFIED IDEOGRAPH + 0x97BB: 0x50DA, //CJK UNIFIED IDEOGRAPH + 0x97BC: 0x4E21, //CJK UNIFIED IDEOGRAPH + 0x97BD: 0x51CC, //CJK UNIFIED IDEOGRAPH + 0x97BE: 0x5BEE, //CJK UNIFIED IDEOGRAPH + 0x97BF: 0x6599, //CJK UNIFIED IDEOGRAPH + 0x97C0: 0x6881, //CJK UNIFIED IDEOGRAPH + 0x97C1: 0x6DBC, //CJK UNIFIED IDEOGRAPH + 0x97C2: 0x731F, //CJK UNIFIED IDEOGRAPH + 0x97C3: 0x7642, //CJK UNIFIED IDEOGRAPH + 0x97C4: 0x77AD, //CJK UNIFIED IDEOGRAPH + 0x97C5: 0x7A1C, //CJK UNIFIED IDEOGRAPH + 0x97C6: 0x7CE7, //CJK UNIFIED IDEOGRAPH + 0x97C7: 0x826F, //CJK UNIFIED IDEOGRAPH + 0x97C8: 0x8AD2, //CJK UNIFIED IDEOGRAPH + 0x97C9: 0x907C, //CJK UNIFIED IDEOGRAPH + 0x97CA: 0x91CF, //CJK UNIFIED IDEOGRAPH + 0x97CB: 0x9675, //CJK UNIFIED IDEOGRAPH + 0x97CC: 0x9818, //CJK UNIFIED IDEOGRAPH + 0x97CD: 0x529B, //CJK UNIFIED IDEOGRAPH + 0x97CE: 0x7DD1, //CJK UNIFIED IDEOGRAPH + 0x97CF: 0x502B, //CJK UNIFIED IDEOGRAPH + 0x97D0: 0x5398, //CJK UNIFIED IDEOGRAPH + 0x97D1: 0x6797, //CJK UNIFIED IDEOGRAPH + 0x97D2: 0x6DCB, //CJK UNIFIED IDEOGRAPH + 0x97D3: 0x71D0, //CJK UNIFIED IDEOGRAPH + 0x97D4: 0x7433, //CJK UNIFIED IDEOGRAPH + 0x97D5: 0x81E8, //CJK UNIFIED IDEOGRAPH + 0x97D6: 0x8F2A, //CJK UNIFIED IDEOGRAPH + 0x97D7: 0x96A3, //CJK UNIFIED IDEOGRAPH + 0x97D8: 0x9C57, //CJK UNIFIED IDEOGRAPH + 0x97D9: 0x9E9F, //CJK UNIFIED IDEOGRAPH + 0x97DA: 0x7460, //CJK UNIFIED IDEOGRAPH + 0x97DB: 0x5841, //CJK UNIFIED IDEOGRAPH + 0x97DC: 0x6D99, //CJK UNIFIED IDEOGRAPH + 0x97DD: 0x7D2F, //CJK UNIFIED IDEOGRAPH + 0x97DE: 0x985E, //CJK UNIFIED IDEOGRAPH + 0x97DF: 0x4EE4, //CJK UNIFIED IDEOGRAPH + 0x97E0: 0x4F36, //CJK UNIFIED IDEOGRAPH + 0x97E1: 0x4F8B, //CJK UNIFIED IDEOGRAPH + 0x97E2: 0x51B7, //CJK UNIFIED IDEOGRAPH + 0x97E3: 0x52B1, //CJK UNIFIED IDEOGRAPH + 0x97E4: 0x5DBA, //CJK UNIFIED IDEOGRAPH + 0x97E5: 0x601C, //CJK UNIFIED IDEOGRAPH + 0x97E6: 0x73B2, //CJK UNIFIED IDEOGRAPH + 0x97E7: 0x793C, //CJK UNIFIED IDEOGRAPH + 0x97E8: 0x82D3, //CJK UNIFIED IDEOGRAPH + 0x97E9: 0x9234, //CJK UNIFIED IDEOGRAPH + 0x97EA: 0x96B7, //CJK UNIFIED IDEOGRAPH + 0x97EB: 0x96F6, //CJK UNIFIED IDEOGRAPH + 0x97EC: 0x970A, //CJK UNIFIED IDEOGRAPH + 0x97ED: 0x9E97, //CJK UNIFIED IDEOGRAPH + 0x97EE: 0x9F62, //CJK UNIFIED IDEOGRAPH + 0x97EF: 0x66A6, //CJK UNIFIED IDEOGRAPH + 0x97F0: 0x6B74, //CJK UNIFIED IDEOGRAPH + 0x97F1: 0x5217, //CJK UNIFIED IDEOGRAPH + 0x97F2: 0x52A3, //CJK UNIFIED IDEOGRAPH + 0x97F3: 0x70C8, //CJK UNIFIED IDEOGRAPH + 0x97F4: 0x88C2, //CJK UNIFIED IDEOGRAPH + 0x97F5: 0x5EC9, //CJK UNIFIED IDEOGRAPH + 0x97F6: 0x604B, //CJK UNIFIED IDEOGRAPH + 0x97F7: 0x6190, //CJK UNIFIED IDEOGRAPH + 0x97F8: 0x6F23, //CJK UNIFIED IDEOGRAPH + 0x97F9: 0x7149, //CJK UNIFIED IDEOGRAPH + 0x97FA: 0x7C3E, //CJK UNIFIED IDEOGRAPH + 0x97FB: 0x7DF4, //CJK UNIFIED IDEOGRAPH + 0x97FC: 0x806F, //CJK UNIFIED IDEOGRAPH + 0x9840: 0x84EE, //CJK UNIFIED IDEOGRAPH + 0x9841: 0x9023, //CJK UNIFIED IDEOGRAPH + 0x9842: 0x932C, //CJK UNIFIED IDEOGRAPH + 0x9843: 0x5442, //CJK UNIFIED IDEOGRAPH + 0x9844: 0x9B6F, //CJK UNIFIED IDEOGRAPH + 0x9845: 0x6AD3, //CJK UNIFIED IDEOGRAPH + 0x9846: 0x7089, //CJK UNIFIED IDEOGRAPH + 0x9847: 0x8CC2, //CJK UNIFIED IDEOGRAPH + 0x9848: 0x8DEF, //CJK UNIFIED IDEOGRAPH + 0x9849: 0x9732, //CJK UNIFIED IDEOGRAPH + 0x984A: 0x52B4, //CJK UNIFIED IDEOGRAPH + 0x984B: 0x5A41, //CJK UNIFIED IDEOGRAPH + 0x984C: 0x5ECA, //CJK UNIFIED IDEOGRAPH + 0x984D: 0x5F04, //CJK UNIFIED IDEOGRAPH + 0x984E: 0x6717, //CJK UNIFIED IDEOGRAPH + 0x984F: 0x697C, //CJK UNIFIED IDEOGRAPH + 0x9850: 0x6994, //CJK UNIFIED IDEOGRAPH + 0x9851: 0x6D6A, //CJK UNIFIED IDEOGRAPH + 0x9852: 0x6F0F, //CJK UNIFIED IDEOGRAPH + 0x9853: 0x7262, //CJK UNIFIED IDEOGRAPH + 0x9854: 0x72FC, //CJK UNIFIED IDEOGRAPH + 0x9855: 0x7BED, //CJK UNIFIED IDEOGRAPH + 0x9856: 0x8001, //CJK UNIFIED IDEOGRAPH + 0x9857: 0x807E, //CJK UNIFIED IDEOGRAPH + 0x9858: 0x874B, //CJK UNIFIED IDEOGRAPH + 0x9859: 0x90CE, //CJK UNIFIED IDEOGRAPH + 0x985A: 0x516D, //CJK UNIFIED IDEOGRAPH + 0x985B: 0x9E93, //CJK UNIFIED IDEOGRAPH + 0x985C: 0x7984, //CJK UNIFIED IDEOGRAPH + 0x985D: 0x808B, //CJK UNIFIED IDEOGRAPH + 0x985E: 0x9332, //CJK UNIFIED IDEOGRAPH + 0x985F: 0x8AD6, //CJK UNIFIED IDEOGRAPH + 0x9860: 0x502D, //CJK UNIFIED IDEOGRAPH + 0x9861: 0x548C, //CJK UNIFIED IDEOGRAPH + 0x9862: 0x8A71, //CJK UNIFIED IDEOGRAPH + 0x9863: 0x6B6A, //CJK UNIFIED IDEOGRAPH + 0x9864: 0x8CC4, //CJK UNIFIED IDEOGRAPH + 0x9865: 0x8107, //CJK UNIFIED IDEOGRAPH + 0x9866: 0x60D1, //CJK UNIFIED IDEOGRAPH + 0x9867: 0x67A0, //CJK UNIFIED IDEOGRAPH + 0x9868: 0x9DF2, //CJK UNIFIED IDEOGRAPH + 0x9869: 0x4E99, //CJK UNIFIED IDEOGRAPH + 0x986A: 0x4E98, //CJK UNIFIED IDEOGRAPH + 0x986B: 0x9C10, //CJK UNIFIED IDEOGRAPH + 0x986C: 0x8A6B, //CJK UNIFIED IDEOGRAPH + 0x986D: 0x85C1, //CJK UNIFIED IDEOGRAPH + 0x986E: 0x8568, //CJK UNIFIED IDEOGRAPH + 0x986F: 0x6900, //CJK UNIFIED IDEOGRAPH + 0x9870: 0x6E7E, //CJK UNIFIED IDEOGRAPH + 0x9871: 0x7897, //CJK UNIFIED IDEOGRAPH + 0x9872: 0x8155, //CJK UNIFIED IDEOGRAPH + 0x989F: 0x5F0C, //CJK UNIFIED IDEOGRAPH + 0x98A0: 0x4E10, //CJK UNIFIED IDEOGRAPH + 0x98A1: 0x4E15, //CJK UNIFIED IDEOGRAPH + 0x98A2: 0x4E2A, //CJK UNIFIED IDEOGRAPH + 0x98A3: 0x4E31, //CJK UNIFIED IDEOGRAPH + 0x98A4: 0x4E36, //CJK UNIFIED IDEOGRAPH + 0x98A5: 0x4E3C, //CJK UNIFIED IDEOGRAPH + 0x98A6: 0x4E3F, //CJK UNIFIED IDEOGRAPH + 0x98A7: 0x4E42, //CJK UNIFIED IDEOGRAPH + 0x98A8: 0x4E56, //CJK UNIFIED IDEOGRAPH + 0x98A9: 0x4E58, //CJK UNIFIED IDEOGRAPH + 0x98AA: 0x4E82, //CJK UNIFIED IDEOGRAPH + 0x98AB: 0x4E85, //CJK UNIFIED IDEOGRAPH + 0x98AC: 0x8C6B, //CJK UNIFIED IDEOGRAPH + 0x98AD: 0x4E8A, //CJK UNIFIED IDEOGRAPH + 0x98AE: 0x8212, //CJK UNIFIED IDEOGRAPH + 0x98AF: 0x5F0D, //CJK UNIFIED IDEOGRAPH + 0x98B0: 0x4E8E, //CJK UNIFIED IDEOGRAPH + 0x98B1: 0x4E9E, //CJK UNIFIED IDEOGRAPH + 0x98B2: 0x4E9F, //CJK UNIFIED IDEOGRAPH + 0x98B3: 0x4EA0, //CJK UNIFIED IDEOGRAPH + 0x98B4: 0x4EA2, //CJK UNIFIED IDEOGRAPH + 0x98B5: 0x4EB0, //CJK UNIFIED IDEOGRAPH + 0x98B6: 0x4EB3, //CJK UNIFIED IDEOGRAPH + 0x98B7: 0x4EB6, //CJK UNIFIED IDEOGRAPH + 0x98B8: 0x4ECE, //CJK UNIFIED IDEOGRAPH + 0x98B9: 0x4ECD, //CJK UNIFIED IDEOGRAPH + 0x98BA: 0x4EC4, //CJK UNIFIED IDEOGRAPH + 0x98BB: 0x4EC6, //CJK UNIFIED IDEOGRAPH + 0x98BC: 0x4EC2, //CJK UNIFIED IDEOGRAPH + 0x98BD: 0x4ED7, //CJK UNIFIED IDEOGRAPH + 0x98BE: 0x4EDE, //CJK UNIFIED IDEOGRAPH + 0x98BF: 0x4EED, //CJK UNIFIED IDEOGRAPH + 0x98C0: 0x4EDF, //CJK UNIFIED IDEOGRAPH + 0x98C1: 0x4EF7, //CJK UNIFIED IDEOGRAPH + 0x98C2: 0x4F09, //CJK UNIFIED IDEOGRAPH + 0x98C3: 0x4F5A, //CJK UNIFIED IDEOGRAPH + 0x98C4: 0x4F30, //CJK UNIFIED IDEOGRAPH + 0x98C5: 0x4F5B, //CJK UNIFIED IDEOGRAPH + 0x98C6: 0x4F5D, //CJK UNIFIED IDEOGRAPH + 0x98C7: 0x4F57, //CJK UNIFIED IDEOGRAPH + 0x98C8: 0x4F47, //CJK UNIFIED IDEOGRAPH + 0x98C9: 0x4F76, //CJK UNIFIED IDEOGRAPH + 0x98CA: 0x4F88, //CJK UNIFIED IDEOGRAPH + 0x98CB: 0x4F8F, //CJK UNIFIED IDEOGRAPH + 0x98CC: 0x4F98, //CJK UNIFIED IDEOGRAPH + 0x98CD: 0x4F7B, //CJK UNIFIED IDEOGRAPH + 0x98CE: 0x4F69, //CJK UNIFIED IDEOGRAPH + 0x98CF: 0x4F70, //CJK UNIFIED IDEOGRAPH + 0x98D0: 0x4F91, //CJK UNIFIED IDEOGRAPH + 0x98D1: 0x4F6F, //CJK UNIFIED IDEOGRAPH + 0x98D2: 0x4F86, //CJK UNIFIED IDEOGRAPH + 0x98D3: 0x4F96, //CJK UNIFIED IDEOGRAPH + 0x98D4: 0x5118, //CJK UNIFIED IDEOGRAPH + 0x98D5: 0x4FD4, //CJK UNIFIED IDEOGRAPH + 0x98D6: 0x4FDF, //CJK UNIFIED IDEOGRAPH + 0x98D7: 0x4FCE, //CJK UNIFIED IDEOGRAPH + 0x98D8: 0x4FD8, //CJK UNIFIED IDEOGRAPH + 0x98D9: 0x4FDB, //CJK UNIFIED IDEOGRAPH + 0x98DA: 0x4FD1, //CJK UNIFIED IDEOGRAPH + 0x98DB: 0x4FDA, //CJK UNIFIED IDEOGRAPH + 0x98DC: 0x4FD0, //CJK UNIFIED IDEOGRAPH + 0x98DD: 0x4FE4, //CJK UNIFIED IDEOGRAPH + 0x98DE: 0x4FE5, //CJK UNIFIED IDEOGRAPH + 0x98DF: 0x501A, //CJK UNIFIED IDEOGRAPH + 0x98E0: 0x5028, //CJK UNIFIED IDEOGRAPH + 0x98E1: 0x5014, //CJK UNIFIED IDEOGRAPH + 0x98E2: 0x502A, //CJK UNIFIED IDEOGRAPH + 0x98E3: 0x5025, //CJK UNIFIED IDEOGRAPH + 0x98E4: 0x5005, //CJK UNIFIED IDEOGRAPH + 0x98E5: 0x4F1C, //CJK UNIFIED IDEOGRAPH + 0x98E6: 0x4FF6, //CJK UNIFIED IDEOGRAPH + 0x98E7: 0x5021, //CJK UNIFIED IDEOGRAPH + 0x98E8: 0x5029, //CJK UNIFIED IDEOGRAPH + 0x98E9: 0x502C, //CJK UNIFIED IDEOGRAPH + 0x98EA: 0x4FFE, //CJK UNIFIED IDEOGRAPH + 0x98EB: 0x4FEF, //CJK UNIFIED IDEOGRAPH + 0x98EC: 0x5011, //CJK UNIFIED IDEOGRAPH + 0x98ED: 0x5006, //CJK UNIFIED IDEOGRAPH + 0x98EE: 0x5043, //CJK UNIFIED IDEOGRAPH + 0x98EF: 0x5047, //CJK UNIFIED IDEOGRAPH + 0x98F0: 0x6703, //CJK UNIFIED IDEOGRAPH + 0x98F1: 0x5055, //CJK UNIFIED IDEOGRAPH + 0x98F2: 0x5050, //CJK UNIFIED IDEOGRAPH + 0x98F3: 0x5048, //CJK UNIFIED IDEOGRAPH + 0x98F4: 0x505A, //CJK UNIFIED IDEOGRAPH + 0x98F5: 0x5056, //CJK UNIFIED IDEOGRAPH + 0x98F6: 0x506C, //CJK UNIFIED IDEOGRAPH + 0x98F7: 0x5078, //CJK UNIFIED IDEOGRAPH + 0x98F8: 0x5080, //CJK UNIFIED IDEOGRAPH + 0x98F9: 0x509A, //CJK UNIFIED IDEOGRAPH + 0x98FA: 0x5085, //CJK UNIFIED IDEOGRAPH + 0x98FB: 0x50B4, //CJK UNIFIED IDEOGRAPH + 0x98FC: 0x50B2, //CJK UNIFIED IDEOGRAPH + 0x9940: 0x50C9, //CJK UNIFIED IDEOGRAPH + 0x9941: 0x50CA, //CJK UNIFIED IDEOGRAPH + 0x9942: 0x50B3, //CJK UNIFIED IDEOGRAPH + 0x9943: 0x50C2, //CJK UNIFIED IDEOGRAPH + 0x9944: 0x50D6, //CJK UNIFIED IDEOGRAPH + 0x9945: 0x50DE, //CJK UNIFIED IDEOGRAPH + 0x9946: 0x50E5, //CJK UNIFIED IDEOGRAPH + 0x9947: 0x50ED, //CJK UNIFIED IDEOGRAPH + 0x9948: 0x50E3, //CJK UNIFIED IDEOGRAPH + 0x9949: 0x50EE, //CJK UNIFIED IDEOGRAPH + 0x994A: 0x50F9, //CJK UNIFIED IDEOGRAPH + 0x994B: 0x50F5, //CJK UNIFIED IDEOGRAPH + 0x994C: 0x5109, //CJK UNIFIED IDEOGRAPH + 0x994D: 0x5101, //CJK UNIFIED IDEOGRAPH + 0x994E: 0x5102, //CJK UNIFIED IDEOGRAPH + 0x994F: 0x5116, //CJK UNIFIED IDEOGRAPH + 0x9950: 0x5115, //CJK UNIFIED IDEOGRAPH + 0x9951: 0x5114, //CJK UNIFIED IDEOGRAPH + 0x9952: 0x511A, //CJK UNIFIED IDEOGRAPH + 0x9953: 0x5121, //CJK UNIFIED IDEOGRAPH + 0x9954: 0x513A, //CJK UNIFIED IDEOGRAPH + 0x9955: 0x5137, //CJK UNIFIED IDEOGRAPH + 0x9956: 0x513C, //CJK UNIFIED IDEOGRAPH + 0x9957: 0x513B, //CJK UNIFIED IDEOGRAPH + 0x9958: 0x513F, //CJK UNIFIED IDEOGRAPH + 0x9959: 0x5140, //CJK UNIFIED IDEOGRAPH + 0x995A: 0x5152, //CJK UNIFIED IDEOGRAPH + 0x995B: 0x514C, //CJK UNIFIED IDEOGRAPH + 0x995C: 0x5154, //CJK UNIFIED IDEOGRAPH + 0x995D: 0x5162, //CJK UNIFIED IDEOGRAPH + 0x995E: 0x7AF8, //CJK UNIFIED IDEOGRAPH + 0x995F: 0x5169, //CJK UNIFIED IDEOGRAPH + 0x9960: 0x516A, //CJK UNIFIED IDEOGRAPH + 0x9961: 0x516E, //CJK UNIFIED IDEOGRAPH + 0x9962: 0x5180, //CJK UNIFIED IDEOGRAPH + 0x9963: 0x5182, //CJK UNIFIED IDEOGRAPH + 0x9964: 0x56D8, //CJK UNIFIED IDEOGRAPH + 0x9965: 0x518C, //CJK UNIFIED IDEOGRAPH + 0x9966: 0x5189, //CJK UNIFIED IDEOGRAPH + 0x9967: 0x518F, //CJK UNIFIED IDEOGRAPH + 0x9968: 0x5191, //CJK UNIFIED IDEOGRAPH + 0x9969: 0x5193, //CJK UNIFIED IDEOGRAPH + 0x996A: 0x5195, //CJK UNIFIED IDEOGRAPH + 0x996B: 0x5196, //CJK UNIFIED IDEOGRAPH + 0x996C: 0x51A4, //CJK UNIFIED IDEOGRAPH + 0x996D: 0x51A6, //CJK UNIFIED IDEOGRAPH + 0x996E: 0x51A2, //CJK UNIFIED IDEOGRAPH + 0x996F: 0x51A9, //CJK UNIFIED IDEOGRAPH + 0x9970: 0x51AA, //CJK UNIFIED IDEOGRAPH + 0x9971: 0x51AB, //CJK UNIFIED IDEOGRAPH + 0x9972: 0x51B3, //CJK UNIFIED IDEOGRAPH + 0x9973: 0x51B1, //CJK UNIFIED IDEOGRAPH + 0x9974: 0x51B2, //CJK UNIFIED IDEOGRAPH + 0x9975: 0x51B0, //CJK UNIFIED IDEOGRAPH + 0x9976: 0x51B5, //CJK UNIFIED IDEOGRAPH + 0x9977: 0x51BD, //CJK UNIFIED IDEOGRAPH + 0x9978: 0x51C5, //CJK UNIFIED IDEOGRAPH + 0x9979: 0x51C9, //CJK UNIFIED IDEOGRAPH + 0x997A: 0x51DB, //CJK UNIFIED IDEOGRAPH + 0x997B: 0x51E0, //CJK UNIFIED IDEOGRAPH + 0x997C: 0x8655, //CJK UNIFIED IDEOGRAPH + 0x997D: 0x51E9, //CJK UNIFIED IDEOGRAPH + 0x997E: 0x51ED, //CJK UNIFIED IDEOGRAPH + 0x9980: 0x51F0, //CJK UNIFIED IDEOGRAPH + 0x9981: 0x51F5, //CJK UNIFIED IDEOGRAPH + 0x9982: 0x51FE, //CJK UNIFIED IDEOGRAPH + 0x9983: 0x5204, //CJK UNIFIED IDEOGRAPH + 0x9984: 0x520B, //CJK UNIFIED IDEOGRAPH + 0x9985: 0x5214, //CJK UNIFIED IDEOGRAPH + 0x9986: 0x520E, //CJK UNIFIED IDEOGRAPH + 0x9987: 0x5227, //CJK UNIFIED IDEOGRAPH + 0x9988: 0x522A, //CJK UNIFIED IDEOGRAPH + 0x9989: 0x522E, //CJK UNIFIED IDEOGRAPH + 0x998A: 0x5233, //CJK UNIFIED IDEOGRAPH + 0x998B: 0x5239, //CJK UNIFIED IDEOGRAPH + 0x998C: 0x524F, //CJK UNIFIED IDEOGRAPH + 0x998D: 0x5244, //CJK UNIFIED IDEOGRAPH + 0x998E: 0x524B, //CJK UNIFIED IDEOGRAPH + 0x998F: 0x524C, //CJK UNIFIED IDEOGRAPH + 0x9990: 0x525E, //CJK UNIFIED IDEOGRAPH + 0x9991: 0x5254, //CJK UNIFIED IDEOGRAPH + 0x9992: 0x526A, //CJK UNIFIED IDEOGRAPH + 0x9993: 0x5274, //CJK UNIFIED IDEOGRAPH + 0x9994: 0x5269, //CJK UNIFIED IDEOGRAPH + 0x9995: 0x5273, //CJK UNIFIED IDEOGRAPH + 0x9996: 0x527F, //CJK UNIFIED IDEOGRAPH + 0x9997: 0x527D, //CJK UNIFIED IDEOGRAPH + 0x9998: 0x528D, //CJK UNIFIED IDEOGRAPH + 0x9999: 0x5294, //CJK UNIFIED IDEOGRAPH + 0x999A: 0x5292, //CJK UNIFIED IDEOGRAPH + 0x999B: 0x5271, //CJK UNIFIED IDEOGRAPH + 0x999C: 0x5288, //CJK UNIFIED IDEOGRAPH + 0x999D: 0x5291, //CJK UNIFIED IDEOGRAPH + 0x999E: 0x8FA8, //CJK UNIFIED IDEOGRAPH + 0x999F: 0x8FA7, //CJK UNIFIED IDEOGRAPH + 0x99A0: 0x52AC, //CJK UNIFIED IDEOGRAPH + 0x99A1: 0x52AD, //CJK UNIFIED IDEOGRAPH + 0x99A2: 0x52BC, //CJK UNIFIED IDEOGRAPH + 0x99A3: 0x52B5, //CJK UNIFIED IDEOGRAPH + 0x99A4: 0x52C1, //CJK UNIFIED IDEOGRAPH + 0x99A5: 0x52CD, //CJK UNIFIED IDEOGRAPH + 0x99A6: 0x52D7, //CJK UNIFIED IDEOGRAPH + 0x99A7: 0x52DE, //CJK UNIFIED IDEOGRAPH + 0x99A8: 0x52E3, //CJK UNIFIED IDEOGRAPH + 0x99A9: 0x52E6, //CJK UNIFIED IDEOGRAPH + 0x99AA: 0x98ED, //CJK UNIFIED IDEOGRAPH + 0x99AB: 0x52E0, //CJK UNIFIED IDEOGRAPH + 0x99AC: 0x52F3, //CJK UNIFIED IDEOGRAPH + 0x99AD: 0x52F5, //CJK UNIFIED IDEOGRAPH + 0x99AE: 0x52F8, //CJK UNIFIED IDEOGRAPH + 0x99AF: 0x52F9, //CJK UNIFIED IDEOGRAPH + 0x99B0: 0x5306, //CJK UNIFIED IDEOGRAPH + 0x99B1: 0x5308, //CJK UNIFIED IDEOGRAPH + 0x99B2: 0x7538, //CJK UNIFIED IDEOGRAPH + 0x99B3: 0x530D, //CJK UNIFIED IDEOGRAPH + 0x99B4: 0x5310, //CJK UNIFIED IDEOGRAPH + 0x99B5: 0x530F, //CJK UNIFIED IDEOGRAPH + 0x99B6: 0x5315, //CJK UNIFIED IDEOGRAPH + 0x99B7: 0x531A, //CJK UNIFIED IDEOGRAPH + 0x99B8: 0x5323, //CJK UNIFIED IDEOGRAPH + 0x99B9: 0x532F, //CJK UNIFIED IDEOGRAPH + 0x99BA: 0x5331, //CJK UNIFIED IDEOGRAPH + 0x99BB: 0x5333, //CJK UNIFIED IDEOGRAPH + 0x99BC: 0x5338, //CJK UNIFIED IDEOGRAPH + 0x99BD: 0x5340, //CJK UNIFIED IDEOGRAPH + 0x99BE: 0x5346, //CJK UNIFIED IDEOGRAPH + 0x99BF: 0x5345, //CJK UNIFIED IDEOGRAPH + 0x99C0: 0x4E17, //CJK UNIFIED IDEOGRAPH + 0x99C1: 0x5349, //CJK UNIFIED IDEOGRAPH + 0x99C2: 0x534D, //CJK UNIFIED IDEOGRAPH + 0x99C3: 0x51D6, //CJK UNIFIED IDEOGRAPH + 0x99C4: 0x535E, //CJK UNIFIED IDEOGRAPH + 0x99C5: 0x5369, //CJK UNIFIED IDEOGRAPH + 0x99C6: 0x536E, //CJK UNIFIED IDEOGRAPH + 0x99C7: 0x5918, //CJK UNIFIED IDEOGRAPH + 0x99C8: 0x537B, //CJK UNIFIED IDEOGRAPH + 0x99C9: 0x5377, //CJK UNIFIED IDEOGRAPH + 0x99CA: 0x5382, //CJK UNIFIED IDEOGRAPH + 0x99CB: 0x5396, //CJK UNIFIED IDEOGRAPH + 0x99CC: 0x53A0, //CJK UNIFIED IDEOGRAPH + 0x99CD: 0x53A6, //CJK UNIFIED IDEOGRAPH + 0x99CE: 0x53A5, //CJK UNIFIED IDEOGRAPH + 0x99CF: 0x53AE, //CJK UNIFIED IDEOGRAPH + 0x99D0: 0x53B0, //CJK UNIFIED IDEOGRAPH + 0x99D1: 0x53B6, //CJK UNIFIED IDEOGRAPH + 0x99D2: 0x53C3, //CJK UNIFIED IDEOGRAPH + 0x99D3: 0x7C12, //CJK UNIFIED IDEOGRAPH + 0x99D4: 0x96D9, //CJK UNIFIED IDEOGRAPH + 0x99D5: 0x53DF, //CJK UNIFIED IDEOGRAPH + 0x99D6: 0x66FC, //CJK UNIFIED IDEOGRAPH + 0x99D7: 0x71EE, //CJK UNIFIED IDEOGRAPH + 0x99D8: 0x53EE, //CJK UNIFIED IDEOGRAPH + 0x99D9: 0x53E8, //CJK UNIFIED IDEOGRAPH + 0x99DA: 0x53ED, //CJK UNIFIED IDEOGRAPH + 0x99DB: 0x53FA, //CJK UNIFIED IDEOGRAPH + 0x99DC: 0x5401, //CJK UNIFIED IDEOGRAPH + 0x99DD: 0x543D, //CJK UNIFIED IDEOGRAPH + 0x99DE: 0x5440, //CJK UNIFIED IDEOGRAPH + 0x99DF: 0x542C, //CJK UNIFIED IDEOGRAPH + 0x99E0: 0x542D, //CJK UNIFIED IDEOGRAPH + 0x99E1: 0x543C, //CJK UNIFIED IDEOGRAPH + 0x99E2: 0x542E, //CJK UNIFIED IDEOGRAPH + 0x99E3: 0x5436, //CJK UNIFIED IDEOGRAPH + 0x99E4: 0x5429, //CJK UNIFIED IDEOGRAPH + 0x99E5: 0x541D, //CJK UNIFIED IDEOGRAPH + 0x99E6: 0x544E, //CJK UNIFIED IDEOGRAPH + 0x99E7: 0x548F, //CJK UNIFIED IDEOGRAPH + 0x99E8: 0x5475, //CJK UNIFIED IDEOGRAPH + 0x99E9: 0x548E, //CJK UNIFIED IDEOGRAPH + 0x99EA: 0x545F, //CJK UNIFIED IDEOGRAPH + 0x99EB: 0x5471, //CJK UNIFIED IDEOGRAPH + 0x99EC: 0x5477, //CJK UNIFIED IDEOGRAPH + 0x99ED: 0x5470, //CJK UNIFIED IDEOGRAPH + 0x99EE: 0x5492, //CJK UNIFIED IDEOGRAPH + 0x99EF: 0x547B, //CJK UNIFIED IDEOGRAPH + 0x99F0: 0x5480, //CJK UNIFIED IDEOGRAPH + 0x99F1: 0x5476, //CJK UNIFIED IDEOGRAPH + 0x99F2: 0x5484, //CJK UNIFIED IDEOGRAPH + 0x99F3: 0x5490, //CJK UNIFIED IDEOGRAPH + 0x99F4: 0x5486, //CJK UNIFIED IDEOGRAPH + 0x99F5: 0x54C7, //CJK UNIFIED IDEOGRAPH + 0x99F6: 0x54A2, //CJK UNIFIED IDEOGRAPH + 0x99F7: 0x54B8, //CJK UNIFIED IDEOGRAPH + 0x99F8: 0x54A5, //CJK UNIFIED IDEOGRAPH + 0x99F9: 0x54AC, //CJK UNIFIED IDEOGRAPH + 0x99FA: 0x54C4, //CJK UNIFIED IDEOGRAPH + 0x99FB: 0x54C8, //CJK UNIFIED IDEOGRAPH + 0x99FC: 0x54A8, //CJK UNIFIED IDEOGRAPH + 0x9A40: 0x54AB, //CJK UNIFIED IDEOGRAPH + 0x9A41: 0x54C2, //CJK UNIFIED IDEOGRAPH + 0x9A42: 0x54A4, //CJK UNIFIED IDEOGRAPH + 0x9A43: 0x54BE, //CJK UNIFIED IDEOGRAPH + 0x9A44: 0x54BC, //CJK UNIFIED IDEOGRAPH + 0x9A45: 0x54D8, //CJK UNIFIED IDEOGRAPH + 0x9A46: 0x54E5, //CJK UNIFIED IDEOGRAPH + 0x9A47: 0x54E6, //CJK UNIFIED IDEOGRAPH + 0x9A48: 0x550F, //CJK UNIFIED IDEOGRAPH + 0x9A49: 0x5514, //CJK UNIFIED IDEOGRAPH + 0x9A4A: 0x54FD, //CJK UNIFIED IDEOGRAPH + 0x9A4B: 0x54EE, //CJK UNIFIED IDEOGRAPH + 0x9A4C: 0x54ED, //CJK UNIFIED IDEOGRAPH + 0x9A4D: 0x54FA, //CJK UNIFIED IDEOGRAPH + 0x9A4E: 0x54E2, //CJK UNIFIED IDEOGRAPH + 0x9A4F: 0x5539, //CJK UNIFIED IDEOGRAPH + 0x9A50: 0x5540, //CJK UNIFIED IDEOGRAPH + 0x9A51: 0x5563, //CJK UNIFIED IDEOGRAPH + 0x9A52: 0x554C, //CJK UNIFIED IDEOGRAPH + 0x9A53: 0x552E, //CJK UNIFIED IDEOGRAPH + 0x9A54: 0x555C, //CJK UNIFIED IDEOGRAPH + 0x9A55: 0x5545, //CJK UNIFIED IDEOGRAPH + 0x9A56: 0x5556, //CJK UNIFIED IDEOGRAPH + 0x9A57: 0x5557, //CJK UNIFIED IDEOGRAPH + 0x9A58: 0x5538, //CJK UNIFIED IDEOGRAPH + 0x9A59: 0x5533, //CJK UNIFIED IDEOGRAPH + 0x9A5A: 0x555D, //CJK UNIFIED IDEOGRAPH + 0x9A5B: 0x5599, //CJK UNIFIED IDEOGRAPH + 0x9A5C: 0x5580, //CJK UNIFIED IDEOGRAPH + 0x9A5D: 0x54AF, //CJK UNIFIED IDEOGRAPH + 0x9A5E: 0x558A, //CJK UNIFIED IDEOGRAPH + 0x9A5F: 0x559F, //CJK UNIFIED IDEOGRAPH + 0x9A60: 0x557B, //CJK UNIFIED IDEOGRAPH + 0x9A61: 0x557E, //CJK UNIFIED IDEOGRAPH + 0x9A62: 0x5598, //CJK UNIFIED IDEOGRAPH + 0x9A63: 0x559E, //CJK UNIFIED IDEOGRAPH + 0x9A64: 0x55AE, //CJK UNIFIED IDEOGRAPH + 0x9A65: 0x557C, //CJK UNIFIED IDEOGRAPH + 0x9A66: 0x5583, //CJK UNIFIED IDEOGRAPH + 0x9A67: 0x55A9, //CJK UNIFIED IDEOGRAPH + 0x9A68: 0x5587, //CJK UNIFIED IDEOGRAPH + 0x9A69: 0x55A8, //CJK UNIFIED IDEOGRAPH + 0x9A6A: 0x55DA, //CJK UNIFIED IDEOGRAPH + 0x9A6B: 0x55C5, //CJK UNIFIED IDEOGRAPH + 0x9A6C: 0x55DF, //CJK UNIFIED IDEOGRAPH + 0x9A6D: 0x55C4, //CJK UNIFIED IDEOGRAPH + 0x9A6E: 0x55DC, //CJK UNIFIED IDEOGRAPH + 0x9A6F: 0x55E4, //CJK UNIFIED IDEOGRAPH + 0x9A70: 0x55D4, //CJK UNIFIED IDEOGRAPH + 0x9A71: 0x5614, //CJK UNIFIED IDEOGRAPH + 0x9A72: 0x55F7, //CJK UNIFIED IDEOGRAPH + 0x9A73: 0x5616, //CJK UNIFIED IDEOGRAPH + 0x9A74: 0x55FE, //CJK UNIFIED IDEOGRAPH + 0x9A75: 0x55FD, //CJK UNIFIED IDEOGRAPH + 0x9A76: 0x561B, //CJK UNIFIED IDEOGRAPH + 0x9A77: 0x55F9, //CJK UNIFIED IDEOGRAPH + 0x9A78: 0x564E, //CJK UNIFIED IDEOGRAPH + 0x9A79: 0x5650, //CJK UNIFIED IDEOGRAPH + 0x9A7A: 0x71DF, //CJK UNIFIED IDEOGRAPH + 0x9A7B: 0x5634, //CJK UNIFIED IDEOGRAPH + 0x9A7C: 0x5636, //CJK UNIFIED IDEOGRAPH + 0x9A7D: 0x5632, //CJK UNIFIED IDEOGRAPH + 0x9A7E: 0x5638, //CJK UNIFIED IDEOGRAPH + 0x9A80: 0x566B, //CJK UNIFIED IDEOGRAPH + 0x9A81: 0x5664, //CJK UNIFIED IDEOGRAPH + 0x9A82: 0x562F, //CJK UNIFIED IDEOGRAPH + 0x9A83: 0x566C, //CJK UNIFIED IDEOGRAPH + 0x9A84: 0x566A, //CJK UNIFIED IDEOGRAPH + 0x9A85: 0x5686, //CJK UNIFIED IDEOGRAPH + 0x9A86: 0x5680, //CJK UNIFIED IDEOGRAPH + 0x9A87: 0x568A, //CJK UNIFIED IDEOGRAPH + 0x9A88: 0x56A0, //CJK UNIFIED IDEOGRAPH + 0x9A89: 0x5694, //CJK UNIFIED IDEOGRAPH + 0x9A8A: 0x568F, //CJK UNIFIED IDEOGRAPH + 0x9A8B: 0x56A5, //CJK UNIFIED IDEOGRAPH + 0x9A8C: 0x56AE, //CJK UNIFIED IDEOGRAPH + 0x9A8D: 0x56B6, //CJK UNIFIED IDEOGRAPH + 0x9A8E: 0x56B4, //CJK UNIFIED IDEOGRAPH + 0x9A8F: 0x56C2, //CJK UNIFIED IDEOGRAPH + 0x9A90: 0x56BC, //CJK UNIFIED IDEOGRAPH + 0x9A91: 0x56C1, //CJK UNIFIED IDEOGRAPH + 0x9A92: 0x56C3, //CJK UNIFIED IDEOGRAPH + 0x9A93: 0x56C0, //CJK UNIFIED IDEOGRAPH + 0x9A94: 0x56C8, //CJK UNIFIED IDEOGRAPH + 0x9A95: 0x56CE, //CJK UNIFIED IDEOGRAPH + 0x9A96: 0x56D1, //CJK UNIFIED IDEOGRAPH + 0x9A97: 0x56D3, //CJK UNIFIED IDEOGRAPH + 0x9A98: 0x56D7, //CJK UNIFIED IDEOGRAPH + 0x9A99: 0x56EE, //CJK UNIFIED IDEOGRAPH + 0x9A9A: 0x56F9, //CJK UNIFIED IDEOGRAPH + 0x9A9B: 0x5700, //CJK UNIFIED IDEOGRAPH + 0x9A9C: 0x56FF, //CJK UNIFIED IDEOGRAPH + 0x9A9D: 0x5704, //CJK UNIFIED IDEOGRAPH + 0x9A9E: 0x5709, //CJK UNIFIED IDEOGRAPH + 0x9A9F: 0x5708, //CJK UNIFIED IDEOGRAPH + 0x9AA0: 0x570B, //CJK UNIFIED IDEOGRAPH + 0x9AA1: 0x570D, //CJK UNIFIED IDEOGRAPH + 0x9AA2: 0x5713, //CJK UNIFIED IDEOGRAPH + 0x9AA3: 0x5718, //CJK UNIFIED IDEOGRAPH + 0x9AA4: 0x5716, //CJK UNIFIED IDEOGRAPH + 0x9AA5: 0x55C7, //CJK UNIFIED IDEOGRAPH + 0x9AA6: 0x571C, //CJK UNIFIED IDEOGRAPH + 0x9AA7: 0x5726, //CJK UNIFIED IDEOGRAPH + 0x9AA8: 0x5737, //CJK UNIFIED IDEOGRAPH + 0x9AA9: 0x5738, //CJK UNIFIED IDEOGRAPH + 0x9AAA: 0x574E, //CJK UNIFIED IDEOGRAPH + 0x9AAB: 0x573B, //CJK UNIFIED IDEOGRAPH + 0x9AAC: 0x5740, //CJK UNIFIED IDEOGRAPH + 0x9AAD: 0x574F, //CJK UNIFIED IDEOGRAPH + 0x9AAE: 0x5769, //CJK UNIFIED IDEOGRAPH + 0x9AAF: 0x57C0, //CJK UNIFIED IDEOGRAPH + 0x9AB0: 0x5788, //CJK UNIFIED IDEOGRAPH + 0x9AB1: 0x5761, //CJK UNIFIED IDEOGRAPH + 0x9AB2: 0x577F, //CJK UNIFIED IDEOGRAPH + 0x9AB3: 0x5789, //CJK UNIFIED IDEOGRAPH + 0x9AB4: 0x5793, //CJK UNIFIED IDEOGRAPH + 0x9AB5: 0x57A0, //CJK UNIFIED IDEOGRAPH + 0x9AB6: 0x57B3, //CJK UNIFIED IDEOGRAPH + 0x9AB7: 0x57A4, //CJK UNIFIED IDEOGRAPH + 0x9AB8: 0x57AA, //CJK UNIFIED IDEOGRAPH + 0x9AB9: 0x57B0, //CJK UNIFIED IDEOGRAPH + 0x9ABA: 0x57C3, //CJK UNIFIED IDEOGRAPH + 0x9ABB: 0x57C6, //CJK UNIFIED IDEOGRAPH + 0x9ABC: 0x57D4, //CJK UNIFIED IDEOGRAPH + 0x9ABD: 0x57D2, //CJK UNIFIED IDEOGRAPH + 0x9ABE: 0x57D3, //CJK UNIFIED IDEOGRAPH + 0x9ABF: 0x580A, //CJK UNIFIED IDEOGRAPH + 0x9AC0: 0x57D6, //CJK UNIFIED IDEOGRAPH + 0x9AC1: 0x57E3, //CJK UNIFIED IDEOGRAPH + 0x9AC2: 0x580B, //CJK UNIFIED IDEOGRAPH + 0x9AC3: 0x5819, //CJK UNIFIED IDEOGRAPH + 0x9AC4: 0x581D, //CJK UNIFIED IDEOGRAPH + 0x9AC5: 0x5872, //CJK UNIFIED IDEOGRAPH + 0x9AC6: 0x5821, //CJK UNIFIED IDEOGRAPH + 0x9AC7: 0x5862, //CJK UNIFIED IDEOGRAPH + 0x9AC8: 0x584B, //CJK UNIFIED IDEOGRAPH + 0x9AC9: 0x5870, //CJK UNIFIED IDEOGRAPH + 0x9ACA: 0x6BC0, //CJK UNIFIED IDEOGRAPH + 0x9ACB: 0x5852, //CJK UNIFIED IDEOGRAPH + 0x9ACC: 0x583D, //CJK UNIFIED IDEOGRAPH + 0x9ACD: 0x5879, //CJK UNIFIED IDEOGRAPH + 0x9ACE: 0x5885, //CJK UNIFIED IDEOGRAPH + 0x9ACF: 0x58B9, //CJK UNIFIED IDEOGRAPH + 0x9AD0: 0x589F, //CJK UNIFIED IDEOGRAPH + 0x9AD1: 0x58AB, //CJK UNIFIED IDEOGRAPH + 0x9AD2: 0x58BA, //CJK UNIFIED IDEOGRAPH + 0x9AD3: 0x58DE, //CJK UNIFIED IDEOGRAPH + 0x9AD4: 0x58BB, //CJK UNIFIED IDEOGRAPH + 0x9AD5: 0x58B8, //CJK UNIFIED IDEOGRAPH + 0x9AD6: 0x58AE, //CJK UNIFIED IDEOGRAPH + 0x9AD7: 0x58C5, //CJK UNIFIED IDEOGRAPH + 0x9AD8: 0x58D3, //CJK UNIFIED IDEOGRAPH + 0x9AD9: 0x58D1, //CJK UNIFIED IDEOGRAPH + 0x9ADA: 0x58D7, //CJK UNIFIED IDEOGRAPH + 0x9ADB: 0x58D9, //CJK UNIFIED IDEOGRAPH + 0x9ADC: 0x58D8, //CJK UNIFIED IDEOGRAPH + 0x9ADD: 0x58E5, //CJK UNIFIED IDEOGRAPH + 0x9ADE: 0x58DC, //CJK UNIFIED IDEOGRAPH + 0x9ADF: 0x58E4, //CJK UNIFIED IDEOGRAPH + 0x9AE0: 0x58DF, //CJK UNIFIED IDEOGRAPH + 0x9AE1: 0x58EF, //CJK UNIFIED IDEOGRAPH + 0x9AE2: 0x58FA, //CJK UNIFIED IDEOGRAPH + 0x9AE3: 0x58F9, //CJK UNIFIED IDEOGRAPH + 0x9AE4: 0x58FB, //CJK UNIFIED IDEOGRAPH + 0x9AE5: 0x58FC, //CJK UNIFIED IDEOGRAPH + 0x9AE6: 0x58FD, //CJK UNIFIED IDEOGRAPH + 0x9AE7: 0x5902, //CJK UNIFIED IDEOGRAPH + 0x9AE8: 0x590A, //CJK UNIFIED IDEOGRAPH + 0x9AE9: 0x5910, //CJK UNIFIED IDEOGRAPH + 0x9AEA: 0x591B, //CJK UNIFIED IDEOGRAPH + 0x9AEB: 0x68A6, //CJK UNIFIED IDEOGRAPH + 0x9AEC: 0x5925, //CJK UNIFIED IDEOGRAPH + 0x9AED: 0x592C, //CJK UNIFIED IDEOGRAPH + 0x9AEE: 0x592D, //CJK UNIFIED IDEOGRAPH + 0x9AEF: 0x5932, //CJK UNIFIED IDEOGRAPH + 0x9AF0: 0x5938, //CJK UNIFIED IDEOGRAPH + 0x9AF1: 0x593E, //CJK UNIFIED IDEOGRAPH + 0x9AF2: 0x7AD2, //CJK UNIFIED IDEOGRAPH + 0x9AF3: 0x5955, //CJK UNIFIED IDEOGRAPH + 0x9AF4: 0x5950, //CJK UNIFIED IDEOGRAPH + 0x9AF5: 0x594E, //CJK UNIFIED IDEOGRAPH + 0x9AF6: 0x595A, //CJK UNIFIED IDEOGRAPH + 0x9AF7: 0x5958, //CJK UNIFIED IDEOGRAPH + 0x9AF8: 0x5962, //CJK UNIFIED IDEOGRAPH + 0x9AF9: 0x5960, //CJK UNIFIED IDEOGRAPH + 0x9AFA: 0x5967, //CJK UNIFIED IDEOGRAPH + 0x9AFB: 0x596C, //CJK UNIFIED IDEOGRAPH + 0x9AFC: 0x5969, //CJK UNIFIED IDEOGRAPH + 0x9B40: 0x5978, //CJK UNIFIED IDEOGRAPH + 0x9B41: 0x5981, //CJK UNIFIED IDEOGRAPH + 0x9B42: 0x599D, //CJK UNIFIED IDEOGRAPH + 0x9B43: 0x4F5E, //CJK UNIFIED IDEOGRAPH + 0x9B44: 0x4FAB, //CJK UNIFIED IDEOGRAPH + 0x9B45: 0x59A3, //CJK UNIFIED IDEOGRAPH + 0x9B46: 0x59B2, //CJK UNIFIED IDEOGRAPH + 0x9B47: 0x59C6, //CJK UNIFIED IDEOGRAPH + 0x9B48: 0x59E8, //CJK UNIFIED IDEOGRAPH + 0x9B49: 0x59DC, //CJK UNIFIED IDEOGRAPH + 0x9B4A: 0x598D, //CJK UNIFIED IDEOGRAPH + 0x9B4B: 0x59D9, //CJK UNIFIED IDEOGRAPH + 0x9B4C: 0x59DA, //CJK UNIFIED IDEOGRAPH + 0x9B4D: 0x5A25, //CJK UNIFIED IDEOGRAPH + 0x9B4E: 0x5A1F, //CJK UNIFIED IDEOGRAPH + 0x9B4F: 0x5A11, //CJK UNIFIED IDEOGRAPH + 0x9B50: 0x5A1C, //CJK UNIFIED IDEOGRAPH + 0x9B51: 0x5A09, //CJK UNIFIED IDEOGRAPH + 0x9B52: 0x5A1A, //CJK UNIFIED IDEOGRAPH + 0x9B53: 0x5A40, //CJK UNIFIED IDEOGRAPH + 0x9B54: 0x5A6C, //CJK UNIFIED IDEOGRAPH + 0x9B55: 0x5A49, //CJK UNIFIED IDEOGRAPH + 0x9B56: 0x5A35, //CJK UNIFIED IDEOGRAPH + 0x9B57: 0x5A36, //CJK UNIFIED IDEOGRAPH + 0x9B58: 0x5A62, //CJK UNIFIED IDEOGRAPH + 0x9B59: 0x5A6A, //CJK UNIFIED IDEOGRAPH + 0x9B5A: 0x5A9A, //CJK UNIFIED IDEOGRAPH + 0x9B5B: 0x5ABC, //CJK UNIFIED IDEOGRAPH + 0x9B5C: 0x5ABE, //CJK UNIFIED IDEOGRAPH + 0x9B5D: 0x5ACB, //CJK UNIFIED IDEOGRAPH + 0x9B5E: 0x5AC2, //CJK UNIFIED IDEOGRAPH + 0x9B5F: 0x5ABD, //CJK UNIFIED IDEOGRAPH + 0x9B60: 0x5AE3, //CJK UNIFIED IDEOGRAPH + 0x9B61: 0x5AD7, //CJK UNIFIED IDEOGRAPH + 0x9B62: 0x5AE6, //CJK UNIFIED IDEOGRAPH + 0x9B63: 0x5AE9, //CJK UNIFIED IDEOGRAPH + 0x9B64: 0x5AD6, //CJK UNIFIED IDEOGRAPH + 0x9B65: 0x5AFA, //CJK UNIFIED IDEOGRAPH + 0x9B66: 0x5AFB, //CJK UNIFIED IDEOGRAPH + 0x9B67: 0x5B0C, //CJK UNIFIED IDEOGRAPH + 0x9B68: 0x5B0B, //CJK UNIFIED IDEOGRAPH + 0x9B69: 0x5B16, //CJK UNIFIED IDEOGRAPH + 0x9B6A: 0x5B32, //CJK UNIFIED IDEOGRAPH + 0x9B6B: 0x5AD0, //CJK UNIFIED IDEOGRAPH + 0x9B6C: 0x5B2A, //CJK UNIFIED IDEOGRAPH + 0x9B6D: 0x5B36, //CJK UNIFIED IDEOGRAPH + 0x9B6E: 0x5B3E, //CJK UNIFIED IDEOGRAPH + 0x9B6F: 0x5B43, //CJK UNIFIED IDEOGRAPH + 0x9B70: 0x5B45, //CJK UNIFIED IDEOGRAPH + 0x9B71: 0x5B40, //CJK UNIFIED IDEOGRAPH + 0x9B72: 0x5B51, //CJK UNIFIED IDEOGRAPH + 0x9B73: 0x5B55, //CJK UNIFIED IDEOGRAPH + 0x9B74: 0x5B5A, //CJK UNIFIED IDEOGRAPH + 0x9B75: 0x5B5B, //CJK UNIFIED IDEOGRAPH + 0x9B76: 0x5B65, //CJK UNIFIED IDEOGRAPH + 0x9B77: 0x5B69, //CJK UNIFIED IDEOGRAPH + 0x9B78: 0x5B70, //CJK UNIFIED IDEOGRAPH + 0x9B79: 0x5B73, //CJK UNIFIED IDEOGRAPH + 0x9B7A: 0x5B75, //CJK UNIFIED IDEOGRAPH + 0x9B7B: 0x5B78, //CJK UNIFIED IDEOGRAPH + 0x9B7C: 0x6588, //CJK UNIFIED IDEOGRAPH + 0x9B7D: 0x5B7A, //CJK UNIFIED IDEOGRAPH + 0x9B7E: 0x5B80, //CJK UNIFIED IDEOGRAPH + 0x9B80: 0x5B83, //CJK UNIFIED IDEOGRAPH + 0x9B81: 0x5BA6, //CJK UNIFIED IDEOGRAPH + 0x9B82: 0x5BB8, //CJK UNIFIED IDEOGRAPH + 0x9B83: 0x5BC3, //CJK UNIFIED IDEOGRAPH + 0x9B84: 0x5BC7, //CJK UNIFIED IDEOGRAPH + 0x9B85: 0x5BC9, //CJK UNIFIED IDEOGRAPH + 0x9B86: 0x5BD4, //CJK UNIFIED IDEOGRAPH + 0x9B87: 0x5BD0, //CJK UNIFIED IDEOGRAPH + 0x9B88: 0x5BE4, //CJK UNIFIED IDEOGRAPH + 0x9B89: 0x5BE6, //CJK UNIFIED IDEOGRAPH + 0x9B8A: 0x5BE2, //CJK UNIFIED IDEOGRAPH + 0x9B8B: 0x5BDE, //CJK UNIFIED IDEOGRAPH + 0x9B8C: 0x5BE5, //CJK UNIFIED IDEOGRAPH + 0x9B8D: 0x5BEB, //CJK UNIFIED IDEOGRAPH + 0x9B8E: 0x5BF0, //CJK UNIFIED IDEOGRAPH + 0x9B8F: 0x5BF6, //CJK UNIFIED IDEOGRAPH + 0x9B90: 0x5BF3, //CJK UNIFIED IDEOGRAPH + 0x9B91: 0x5C05, //CJK UNIFIED IDEOGRAPH + 0x9B92: 0x5C07, //CJK UNIFIED IDEOGRAPH + 0x9B93: 0x5C08, //CJK UNIFIED IDEOGRAPH + 0x9B94: 0x5C0D, //CJK UNIFIED IDEOGRAPH + 0x9B95: 0x5C13, //CJK UNIFIED IDEOGRAPH + 0x9B96: 0x5C20, //CJK UNIFIED IDEOGRAPH + 0x9B97: 0x5C22, //CJK UNIFIED IDEOGRAPH + 0x9B98: 0x5C28, //CJK UNIFIED IDEOGRAPH + 0x9B99: 0x5C38, //CJK UNIFIED IDEOGRAPH + 0x9B9A: 0x5C39, //CJK UNIFIED IDEOGRAPH + 0x9B9B: 0x5C41, //CJK UNIFIED IDEOGRAPH + 0x9B9C: 0x5C46, //CJK UNIFIED IDEOGRAPH + 0x9B9D: 0x5C4E, //CJK UNIFIED IDEOGRAPH + 0x9B9E: 0x5C53, //CJK UNIFIED IDEOGRAPH + 0x9B9F: 0x5C50, //CJK UNIFIED IDEOGRAPH + 0x9BA0: 0x5C4F, //CJK UNIFIED IDEOGRAPH + 0x9BA1: 0x5B71, //CJK UNIFIED IDEOGRAPH + 0x9BA2: 0x5C6C, //CJK UNIFIED IDEOGRAPH + 0x9BA3: 0x5C6E, //CJK UNIFIED IDEOGRAPH + 0x9BA4: 0x4E62, //CJK UNIFIED IDEOGRAPH + 0x9BA5: 0x5C76, //CJK UNIFIED IDEOGRAPH + 0x9BA6: 0x5C79, //CJK UNIFIED IDEOGRAPH + 0x9BA7: 0x5C8C, //CJK UNIFIED IDEOGRAPH + 0x9BA8: 0x5C91, //CJK UNIFIED IDEOGRAPH + 0x9BA9: 0x5C94, //CJK UNIFIED IDEOGRAPH + 0x9BAA: 0x599B, //CJK UNIFIED IDEOGRAPH + 0x9BAB: 0x5CAB, //CJK UNIFIED IDEOGRAPH + 0x9BAC: 0x5CBB, //CJK UNIFIED IDEOGRAPH + 0x9BAD: 0x5CB6, //CJK UNIFIED IDEOGRAPH + 0x9BAE: 0x5CBC, //CJK UNIFIED IDEOGRAPH + 0x9BAF: 0x5CB7, //CJK UNIFIED IDEOGRAPH + 0x9BB0: 0x5CC5, //CJK UNIFIED IDEOGRAPH + 0x9BB1: 0x5CBE, //CJK UNIFIED IDEOGRAPH + 0x9BB2: 0x5CC7, //CJK UNIFIED IDEOGRAPH + 0x9BB3: 0x5CD9, //CJK UNIFIED IDEOGRAPH + 0x9BB4: 0x5CE9, //CJK UNIFIED IDEOGRAPH + 0x9BB5: 0x5CFD, //CJK UNIFIED IDEOGRAPH + 0x9BB6: 0x5CFA, //CJK UNIFIED IDEOGRAPH + 0x9BB7: 0x5CED, //CJK UNIFIED IDEOGRAPH + 0x9BB8: 0x5D8C, //CJK UNIFIED IDEOGRAPH + 0x9BB9: 0x5CEA, //CJK UNIFIED IDEOGRAPH + 0x9BBA: 0x5D0B, //CJK UNIFIED IDEOGRAPH + 0x9BBB: 0x5D15, //CJK UNIFIED IDEOGRAPH + 0x9BBC: 0x5D17, //CJK UNIFIED IDEOGRAPH + 0x9BBD: 0x5D5C, //CJK UNIFIED IDEOGRAPH + 0x9BBE: 0x5D1F, //CJK UNIFIED IDEOGRAPH + 0x9BBF: 0x5D1B, //CJK UNIFIED IDEOGRAPH + 0x9BC0: 0x5D11, //CJK UNIFIED IDEOGRAPH + 0x9BC1: 0x5D14, //CJK UNIFIED IDEOGRAPH + 0x9BC2: 0x5D22, //CJK UNIFIED IDEOGRAPH + 0x9BC3: 0x5D1A, //CJK UNIFIED IDEOGRAPH + 0x9BC4: 0x5D19, //CJK UNIFIED IDEOGRAPH + 0x9BC5: 0x5D18, //CJK UNIFIED IDEOGRAPH + 0x9BC6: 0x5D4C, //CJK UNIFIED IDEOGRAPH + 0x9BC7: 0x5D52, //CJK UNIFIED IDEOGRAPH + 0x9BC8: 0x5D4E, //CJK UNIFIED IDEOGRAPH + 0x9BC9: 0x5D4B, //CJK UNIFIED IDEOGRAPH + 0x9BCA: 0x5D6C, //CJK UNIFIED IDEOGRAPH + 0x9BCB: 0x5D73, //CJK UNIFIED IDEOGRAPH + 0x9BCC: 0x5D76, //CJK UNIFIED IDEOGRAPH + 0x9BCD: 0x5D87, //CJK UNIFIED IDEOGRAPH + 0x9BCE: 0x5D84, //CJK UNIFIED IDEOGRAPH + 0x9BCF: 0x5D82, //CJK UNIFIED IDEOGRAPH + 0x9BD0: 0x5DA2, //CJK UNIFIED IDEOGRAPH + 0x9BD1: 0x5D9D, //CJK UNIFIED IDEOGRAPH + 0x9BD2: 0x5DAC, //CJK UNIFIED IDEOGRAPH + 0x9BD3: 0x5DAE, //CJK UNIFIED IDEOGRAPH + 0x9BD4: 0x5DBD, //CJK UNIFIED IDEOGRAPH + 0x9BD5: 0x5D90, //CJK UNIFIED IDEOGRAPH + 0x9BD6: 0x5DB7, //CJK UNIFIED IDEOGRAPH + 0x9BD7: 0x5DBC, //CJK UNIFIED IDEOGRAPH + 0x9BD8: 0x5DC9, //CJK UNIFIED IDEOGRAPH + 0x9BD9: 0x5DCD, //CJK UNIFIED IDEOGRAPH + 0x9BDA: 0x5DD3, //CJK UNIFIED IDEOGRAPH + 0x9BDB: 0x5DD2, //CJK UNIFIED IDEOGRAPH + 0x9BDC: 0x5DD6, //CJK UNIFIED IDEOGRAPH + 0x9BDD: 0x5DDB, //CJK UNIFIED IDEOGRAPH + 0x9BDE: 0x5DEB, //CJK UNIFIED IDEOGRAPH + 0x9BDF: 0x5DF2, //CJK UNIFIED IDEOGRAPH + 0x9BE0: 0x5DF5, //CJK UNIFIED IDEOGRAPH + 0x9BE1: 0x5E0B, //CJK UNIFIED IDEOGRAPH + 0x9BE2: 0x5E1A, //CJK UNIFIED IDEOGRAPH + 0x9BE3: 0x5E19, //CJK UNIFIED IDEOGRAPH + 0x9BE4: 0x5E11, //CJK UNIFIED IDEOGRAPH + 0x9BE5: 0x5E1B, //CJK UNIFIED IDEOGRAPH + 0x9BE6: 0x5E36, //CJK UNIFIED IDEOGRAPH + 0x9BE7: 0x5E37, //CJK UNIFIED IDEOGRAPH + 0x9BE8: 0x5E44, //CJK UNIFIED IDEOGRAPH + 0x9BE9: 0x5E43, //CJK UNIFIED IDEOGRAPH + 0x9BEA: 0x5E40, //CJK UNIFIED IDEOGRAPH + 0x9BEB: 0x5E4E, //CJK UNIFIED IDEOGRAPH + 0x9BEC: 0x5E57, //CJK UNIFIED IDEOGRAPH + 0x9BED: 0x5E54, //CJK UNIFIED IDEOGRAPH + 0x9BEE: 0x5E5F, //CJK UNIFIED IDEOGRAPH + 0x9BEF: 0x5E62, //CJK UNIFIED IDEOGRAPH + 0x9BF0: 0x5E64, //CJK UNIFIED IDEOGRAPH + 0x9BF1: 0x5E47, //CJK UNIFIED IDEOGRAPH + 0x9BF2: 0x5E75, //CJK UNIFIED IDEOGRAPH + 0x9BF3: 0x5E76, //CJK UNIFIED IDEOGRAPH + 0x9BF4: 0x5E7A, //CJK UNIFIED IDEOGRAPH + 0x9BF5: 0x9EBC, //CJK UNIFIED IDEOGRAPH + 0x9BF6: 0x5E7F, //CJK UNIFIED IDEOGRAPH + 0x9BF7: 0x5EA0, //CJK UNIFIED IDEOGRAPH + 0x9BF8: 0x5EC1, //CJK UNIFIED IDEOGRAPH + 0x9BF9: 0x5EC2, //CJK UNIFIED IDEOGRAPH + 0x9BFA: 0x5EC8, //CJK UNIFIED IDEOGRAPH + 0x9BFB: 0x5ED0, //CJK UNIFIED IDEOGRAPH + 0x9BFC: 0x5ECF, //CJK UNIFIED IDEOGRAPH + 0x9C40: 0x5ED6, //CJK UNIFIED IDEOGRAPH + 0x9C41: 0x5EE3, //CJK UNIFIED IDEOGRAPH + 0x9C42: 0x5EDD, //CJK UNIFIED IDEOGRAPH + 0x9C43: 0x5EDA, //CJK UNIFIED IDEOGRAPH + 0x9C44: 0x5EDB, //CJK UNIFIED IDEOGRAPH + 0x9C45: 0x5EE2, //CJK UNIFIED IDEOGRAPH + 0x9C46: 0x5EE1, //CJK UNIFIED IDEOGRAPH + 0x9C47: 0x5EE8, //CJK UNIFIED IDEOGRAPH + 0x9C48: 0x5EE9, //CJK UNIFIED IDEOGRAPH + 0x9C49: 0x5EEC, //CJK UNIFIED IDEOGRAPH + 0x9C4A: 0x5EF1, //CJK UNIFIED IDEOGRAPH + 0x9C4B: 0x5EF3, //CJK UNIFIED IDEOGRAPH + 0x9C4C: 0x5EF0, //CJK UNIFIED IDEOGRAPH + 0x9C4D: 0x5EF4, //CJK UNIFIED IDEOGRAPH + 0x9C4E: 0x5EF8, //CJK UNIFIED IDEOGRAPH + 0x9C4F: 0x5EFE, //CJK UNIFIED IDEOGRAPH + 0x9C50: 0x5F03, //CJK UNIFIED IDEOGRAPH + 0x9C51: 0x5F09, //CJK UNIFIED IDEOGRAPH + 0x9C52: 0x5F5D, //CJK UNIFIED IDEOGRAPH + 0x9C53: 0x5F5C, //CJK UNIFIED IDEOGRAPH + 0x9C54: 0x5F0B, //CJK UNIFIED IDEOGRAPH + 0x9C55: 0x5F11, //CJK UNIFIED IDEOGRAPH + 0x9C56: 0x5F16, //CJK UNIFIED IDEOGRAPH + 0x9C57: 0x5F29, //CJK UNIFIED IDEOGRAPH + 0x9C58: 0x5F2D, //CJK UNIFIED IDEOGRAPH + 0x9C59: 0x5F38, //CJK UNIFIED IDEOGRAPH + 0x9C5A: 0x5F41, //CJK UNIFIED IDEOGRAPH + 0x9C5B: 0x5F48, //CJK UNIFIED IDEOGRAPH + 0x9C5C: 0x5F4C, //CJK UNIFIED IDEOGRAPH + 0x9C5D: 0x5F4E, //CJK UNIFIED IDEOGRAPH + 0x9C5E: 0x5F2F, //CJK UNIFIED IDEOGRAPH + 0x9C5F: 0x5F51, //CJK UNIFIED IDEOGRAPH + 0x9C60: 0x5F56, //CJK UNIFIED IDEOGRAPH + 0x9C61: 0x5F57, //CJK UNIFIED IDEOGRAPH + 0x9C62: 0x5F59, //CJK UNIFIED IDEOGRAPH + 0x9C63: 0x5F61, //CJK UNIFIED IDEOGRAPH + 0x9C64: 0x5F6D, //CJK UNIFIED IDEOGRAPH + 0x9C65: 0x5F73, //CJK UNIFIED IDEOGRAPH + 0x9C66: 0x5F77, //CJK UNIFIED IDEOGRAPH + 0x9C67: 0x5F83, //CJK UNIFIED IDEOGRAPH + 0x9C68: 0x5F82, //CJK UNIFIED IDEOGRAPH + 0x9C69: 0x5F7F, //CJK UNIFIED IDEOGRAPH + 0x9C6A: 0x5F8A, //CJK UNIFIED IDEOGRAPH + 0x9C6B: 0x5F88, //CJK UNIFIED IDEOGRAPH + 0x9C6C: 0x5F91, //CJK UNIFIED IDEOGRAPH + 0x9C6D: 0x5F87, //CJK UNIFIED IDEOGRAPH + 0x9C6E: 0x5F9E, //CJK UNIFIED IDEOGRAPH + 0x9C6F: 0x5F99, //CJK UNIFIED IDEOGRAPH + 0x9C70: 0x5F98, //CJK UNIFIED IDEOGRAPH + 0x9C71: 0x5FA0, //CJK UNIFIED IDEOGRAPH + 0x9C72: 0x5FA8, //CJK UNIFIED IDEOGRAPH + 0x9C73: 0x5FAD, //CJK UNIFIED IDEOGRAPH + 0x9C74: 0x5FBC, //CJK UNIFIED IDEOGRAPH + 0x9C75: 0x5FD6, //CJK UNIFIED IDEOGRAPH + 0x9C76: 0x5FFB, //CJK UNIFIED IDEOGRAPH + 0x9C77: 0x5FE4, //CJK UNIFIED IDEOGRAPH + 0x9C78: 0x5FF8, //CJK UNIFIED IDEOGRAPH + 0x9C79: 0x5FF1, //CJK UNIFIED IDEOGRAPH + 0x9C7A: 0x5FDD, //CJK UNIFIED IDEOGRAPH + 0x9C7B: 0x60B3, //CJK UNIFIED IDEOGRAPH + 0x9C7C: 0x5FFF, //CJK UNIFIED IDEOGRAPH + 0x9C7D: 0x6021, //CJK UNIFIED IDEOGRAPH + 0x9C7E: 0x6060, //CJK UNIFIED IDEOGRAPH + 0x9C80: 0x6019, //CJK UNIFIED IDEOGRAPH + 0x9C81: 0x6010, //CJK UNIFIED IDEOGRAPH + 0x9C82: 0x6029, //CJK UNIFIED IDEOGRAPH + 0x9C83: 0x600E, //CJK UNIFIED IDEOGRAPH + 0x9C84: 0x6031, //CJK UNIFIED IDEOGRAPH + 0x9C85: 0x601B, //CJK UNIFIED IDEOGRAPH + 0x9C86: 0x6015, //CJK UNIFIED IDEOGRAPH + 0x9C87: 0x602B, //CJK UNIFIED IDEOGRAPH + 0x9C88: 0x6026, //CJK UNIFIED IDEOGRAPH + 0x9C89: 0x600F, //CJK UNIFIED IDEOGRAPH + 0x9C8A: 0x603A, //CJK UNIFIED IDEOGRAPH + 0x9C8B: 0x605A, //CJK UNIFIED IDEOGRAPH + 0x9C8C: 0x6041, //CJK UNIFIED IDEOGRAPH + 0x9C8D: 0x606A, //CJK UNIFIED IDEOGRAPH + 0x9C8E: 0x6077, //CJK UNIFIED IDEOGRAPH + 0x9C8F: 0x605F, //CJK UNIFIED IDEOGRAPH + 0x9C90: 0x604A, //CJK UNIFIED IDEOGRAPH + 0x9C91: 0x6046, //CJK UNIFIED IDEOGRAPH + 0x9C92: 0x604D, //CJK UNIFIED IDEOGRAPH + 0x9C93: 0x6063, //CJK UNIFIED IDEOGRAPH + 0x9C94: 0x6043, //CJK UNIFIED IDEOGRAPH + 0x9C95: 0x6064, //CJK UNIFIED IDEOGRAPH + 0x9C96: 0x6042, //CJK UNIFIED IDEOGRAPH + 0x9C97: 0x606C, //CJK UNIFIED IDEOGRAPH + 0x9C98: 0x606B, //CJK UNIFIED IDEOGRAPH + 0x9C99: 0x6059, //CJK UNIFIED IDEOGRAPH + 0x9C9A: 0x6081, //CJK UNIFIED IDEOGRAPH + 0x9C9B: 0x608D, //CJK UNIFIED IDEOGRAPH + 0x9C9C: 0x60E7, //CJK UNIFIED IDEOGRAPH + 0x9C9D: 0x6083, //CJK UNIFIED IDEOGRAPH + 0x9C9E: 0x609A, //CJK UNIFIED IDEOGRAPH + 0x9C9F: 0x6084, //CJK UNIFIED IDEOGRAPH + 0x9CA0: 0x609B, //CJK UNIFIED IDEOGRAPH + 0x9CA1: 0x6096, //CJK UNIFIED IDEOGRAPH + 0x9CA2: 0x6097, //CJK UNIFIED IDEOGRAPH + 0x9CA3: 0x6092, //CJK UNIFIED IDEOGRAPH + 0x9CA4: 0x60A7, //CJK UNIFIED IDEOGRAPH + 0x9CA5: 0x608B, //CJK UNIFIED IDEOGRAPH + 0x9CA6: 0x60E1, //CJK UNIFIED IDEOGRAPH + 0x9CA7: 0x60B8, //CJK UNIFIED IDEOGRAPH + 0x9CA8: 0x60E0, //CJK UNIFIED IDEOGRAPH + 0x9CA9: 0x60D3, //CJK UNIFIED IDEOGRAPH + 0x9CAA: 0x60B4, //CJK UNIFIED IDEOGRAPH + 0x9CAB: 0x5FF0, //CJK UNIFIED IDEOGRAPH + 0x9CAC: 0x60BD, //CJK UNIFIED IDEOGRAPH + 0x9CAD: 0x60C6, //CJK UNIFIED IDEOGRAPH + 0x9CAE: 0x60B5, //CJK UNIFIED IDEOGRAPH + 0x9CAF: 0x60D8, //CJK UNIFIED IDEOGRAPH + 0x9CB0: 0x614D, //CJK UNIFIED IDEOGRAPH + 0x9CB1: 0x6115, //CJK UNIFIED IDEOGRAPH + 0x9CB2: 0x6106, //CJK UNIFIED IDEOGRAPH + 0x9CB3: 0x60F6, //CJK UNIFIED IDEOGRAPH + 0x9CB4: 0x60F7, //CJK UNIFIED IDEOGRAPH + 0x9CB5: 0x6100, //CJK UNIFIED IDEOGRAPH + 0x9CB6: 0x60F4, //CJK UNIFIED IDEOGRAPH + 0x9CB7: 0x60FA, //CJK UNIFIED IDEOGRAPH + 0x9CB8: 0x6103, //CJK UNIFIED IDEOGRAPH + 0x9CB9: 0x6121, //CJK UNIFIED IDEOGRAPH + 0x9CBA: 0x60FB, //CJK UNIFIED IDEOGRAPH + 0x9CBB: 0x60F1, //CJK UNIFIED IDEOGRAPH + 0x9CBC: 0x610D, //CJK UNIFIED IDEOGRAPH + 0x9CBD: 0x610E, //CJK UNIFIED IDEOGRAPH + 0x9CBE: 0x6147, //CJK UNIFIED IDEOGRAPH + 0x9CBF: 0x613E, //CJK UNIFIED IDEOGRAPH + 0x9CC0: 0x6128, //CJK UNIFIED IDEOGRAPH + 0x9CC1: 0x6127, //CJK UNIFIED IDEOGRAPH + 0x9CC2: 0x614A, //CJK UNIFIED IDEOGRAPH + 0x9CC3: 0x613F, //CJK UNIFIED IDEOGRAPH + 0x9CC4: 0x613C, //CJK UNIFIED IDEOGRAPH + 0x9CC5: 0x612C, //CJK UNIFIED IDEOGRAPH + 0x9CC6: 0x6134, //CJK UNIFIED IDEOGRAPH + 0x9CC7: 0x613D, //CJK UNIFIED IDEOGRAPH + 0x9CC8: 0x6142, //CJK UNIFIED IDEOGRAPH + 0x9CC9: 0x6144, //CJK UNIFIED IDEOGRAPH + 0x9CCA: 0x6173, //CJK UNIFIED IDEOGRAPH + 0x9CCB: 0x6177, //CJK UNIFIED IDEOGRAPH + 0x9CCC: 0x6158, //CJK UNIFIED IDEOGRAPH + 0x9CCD: 0x6159, //CJK UNIFIED IDEOGRAPH + 0x9CCE: 0x615A, //CJK UNIFIED IDEOGRAPH + 0x9CCF: 0x616B, //CJK UNIFIED IDEOGRAPH + 0x9CD0: 0x6174, //CJK UNIFIED IDEOGRAPH + 0x9CD1: 0x616F, //CJK UNIFIED IDEOGRAPH + 0x9CD2: 0x6165, //CJK UNIFIED IDEOGRAPH + 0x9CD3: 0x6171, //CJK UNIFIED IDEOGRAPH + 0x9CD4: 0x615F, //CJK UNIFIED IDEOGRAPH + 0x9CD5: 0x615D, //CJK UNIFIED IDEOGRAPH + 0x9CD6: 0x6153, //CJK UNIFIED IDEOGRAPH + 0x9CD7: 0x6175, //CJK UNIFIED IDEOGRAPH + 0x9CD8: 0x6199, //CJK UNIFIED IDEOGRAPH + 0x9CD9: 0x6196, //CJK UNIFIED IDEOGRAPH + 0x9CDA: 0x6187, //CJK UNIFIED IDEOGRAPH + 0x9CDB: 0x61AC, //CJK UNIFIED IDEOGRAPH + 0x9CDC: 0x6194, //CJK UNIFIED IDEOGRAPH + 0x9CDD: 0x619A, //CJK UNIFIED IDEOGRAPH + 0x9CDE: 0x618A, //CJK UNIFIED IDEOGRAPH + 0x9CDF: 0x6191, //CJK UNIFIED IDEOGRAPH + 0x9CE0: 0x61AB, //CJK UNIFIED IDEOGRAPH + 0x9CE1: 0x61AE, //CJK UNIFIED IDEOGRAPH + 0x9CE2: 0x61CC, //CJK UNIFIED IDEOGRAPH + 0x9CE3: 0x61CA, //CJK UNIFIED IDEOGRAPH + 0x9CE4: 0x61C9, //CJK UNIFIED IDEOGRAPH + 0x9CE5: 0x61F7, //CJK UNIFIED IDEOGRAPH + 0x9CE6: 0x61C8, //CJK UNIFIED IDEOGRAPH + 0x9CE7: 0x61C3, //CJK UNIFIED IDEOGRAPH + 0x9CE8: 0x61C6, //CJK UNIFIED IDEOGRAPH + 0x9CE9: 0x61BA, //CJK UNIFIED IDEOGRAPH + 0x9CEA: 0x61CB, //CJK UNIFIED IDEOGRAPH + 0x9CEB: 0x7F79, //CJK UNIFIED IDEOGRAPH + 0x9CEC: 0x61CD, //CJK UNIFIED IDEOGRAPH + 0x9CED: 0x61E6, //CJK UNIFIED IDEOGRAPH + 0x9CEE: 0x61E3, //CJK UNIFIED IDEOGRAPH + 0x9CEF: 0x61F6, //CJK UNIFIED IDEOGRAPH + 0x9CF0: 0x61FA, //CJK UNIFIED IDEOGRAPH + 0x9CF1: 0x61F4, //CJK UNIFIED IDEOGRAPH + 0x9CF2: 0x61FF, //CJK UNIFIED IDEOGRAPH + 0x9CF3: 0x61FD, //CJK UNIFIED IDEOGRAPH + 0x9CF4: 0x61FC, //CJK UNIFIED IDEOGRAPH + 0x9CF5: 0x61FE, //CJK UNIFIED IDEOGRAPH + 0x9CF6: 0x6200, //CJK UNIFIED IDEOGRAPH + 0x9CF7: 0x6208, //CJK UNIFIED IDEOGRAPH + 0x9CF8: 0x6209, //CJK UNIFIED IDEOGRAPH + 0x9CF9: 0x620D, //CJK UNIFIED IDEOGRAPH + 0x9CFA: 0x620C, //CJK UNIFIED IDEOGRAPH + 0x9CFB: 0x6214, //CJK UNIFIED IDEOGRAPH + 0x9CFC: 0x621B, //CJK UNIFIED IDEOGRAPH + 0x9D40: 0x621E, //CJK UNIFIED IDEOGRAPH + 0x9D41: 0x6221, //CJK UNIFIED IDEOGRAPH + 0x9D42: 0x622A, //CJK UNIFIED IDEOGRAPH + 0x9D43: 0x622E, //CJK UNIFIED IDEOGRAPH + 0x9D44: 0x6230, //CJK UNIFIED IDEOGRAPH + 0x9D45: 0x6232, //CJK UNIFIED IDEOGRAPH + 0x9D46: 0x6233, //CJK UNIFIED IDEOGRAPH + 0x9D47: 0x6241, //CJK UNIFIED IDEOGRAPH + 0x9D48: 0x624E, //CJK UNIFIED IDEOGRAPH + 0x9D49: 0x625E, //CJK UNIFIED IDEOGRAPH + 0x9D4A: 0x6263, //CJK UNIFIED IDEOGRAPH + 0x9D4B: 0x625B, //CJK UNIFIED IDEOGRAPH + 0x9D4C: 0x6260, //CJK UNIFIED IDEOGRAPH + 0x9D4D: 0x6268, //CJK UNIFIED IDEOGRAPH + 0x9D4E: 0x627C, //CJK UNIFIED IDEOGRAPH + 0x9D4F: 0x6282, //CJK UNIFIED IDEOGRAPH + 0x9D50: 0x6289, //CJK UNIFIED IDEOGRAPH + 0x9D51: 0x627E, //CJK UNIFIED IDEOGRAPH + 0x9D52: 0x6292, //CJK UNIFIED IDEOGRAPH + 0x9D53: 0x6293, //CJK UNIFIED IDEOGRAPH + 0x9D54: 0x6296, //CJK UNIFIED IDEOGRAPH + 0x9D55: 0x62D4, //CJK UNIFIED IDEOGRAPH + 0x9D56: 0x6283, //CJK UNIFIED IDEOGRAPH + 0x9D57: 0x6294, //CJK UNIFIED IDEOGRAPH + 0x9D58: 0x62D7, //CJK UNIFIED IDEOGRAPH + 0x9D59: 0x62D1, //CJK UNIFIED IDEOGRAPH + 0x9D5A: 0x62BB, //CJK UNIFIED IDEOGRAPH + 0x9D5B: 0x62CF, //CJK UNIFIED IDEOGRAPH + 0x9D5C: 0x62FF, //CJK UNIFIED IDEOGRAPH + 0x9D5D: 0x62C6, //CJK UNIFIED IDEOGRAPH + 0x9D5E: 0x64D4, //CJK UNIFIED IDEOGRAPH + 0x9D5F: 0x62C8, //CJK UNIFIED IDEOGRAPH + 0x9D60: 0x62DC, //CJK UNIFIED IDEOGRAPH + 0x9D61: 0x62CC, //CJK UNIFIED IDEOGRAPH + 0x9D62: 0x62CA, //CJK UNIFIED IDEOGRAPH + 0x9D63: 0x62C2, //CJK UNIFIED IDEOGRAPH + 0x9D64: 0x62C7, //CJK UNIFIED IDEOGRAPH + 0x9D65: 0x629B, //CJK UNIFIED IDEOGRAPH + 0x9D66: 0x62C9, //CJK UNIFIED IDEOGRAPH + 0x9D67: 0x630C, //CJK UNIFIED IDEOGRAPH + 0x9D68: 0x62EE, //CJK UNIFIED IDEOGRAPH + 0x9D69: 0x62F1, //CJK UNIFIED IDEOGRAPH + 0x9D6A: 0x6327, //CJK UNIFIED IDEOGRAPH + 0x9D6B: 0x6302, //CJK UNIFIED IDEOGRAPH + 0x9D6C: 0x6308, //CJK UNIFIED IDEOGRAPH + 0x9D6D: 0x62EF, //CJK UNIFIED IDEOGRAPH + 0x9D6E: 0x62F5, //CJK UNIFIED IDEOGRAPH + 0x9D6F: 0x6350, //CJK UNIFIED IDEOGRAPH + 0x9D70: 0x633E, //CJK UNIFIED IDEOGRAPH + 0x9D71: 0x634D, //CJK UNIFIED IDEOGRAPH + 0x9D72: 0x641C, //CJK UNIFIED IDEOGRAPH + 0x9D73: 0x634F, //CJK UNIFIED IDEOGRAPH + 0x9D74: 0x6396, //CJK UNIFIED IDEOGRAPH + 0x9D75: 0x638E, //CJK UNIFIED IDEOGRAPH + 0x9D76: 0x6380, //CJK UNIFIED IDEOGRAPH + 0x9D77: 0x63AB, //CJK UNIFIED IDEOGRAPH + 0x9D78: 0x6376, //CJK UNIFIED IDEOGRAPH + 0x9D79: 0x63A3, //CJK UNIFIED IDEOGRAPH + 0x9D7A: 0x638F, //CJK UNIFIED IDEOGRAPH + 0x9D7B: 0x6389, //CJK UNIFIED IDEOGRAPH + 0x9D7C: 0x639F, //CJK UNIFIED IDEOGRAPH + 0x9D7D: 0x63B5, //CJK UNIFIED IDEOGRAPH + 0x9D7E: 0x636B, //CJK UNIFIED IDEOGRAPH + 0x9D80: 0x6369, //CJK UNIFIED IDEOGRAPH + 0x9D81: 0x63BE, //CJK UNIFIED IDEOGRAPH + 0x9D82: 0x63E9, //CJK UNIFIED IDEOGRAPH + 0x9D83: 0x63C0, //CJK UNIFIED IDEOGRAPH + 0x9D84: 0x63C6, //CJK UNIFIED IDEOGRAPH + 0x9D85: 0x63E3, //CJK UNIFIED IDEOGRAPH + 0x9D86: 0x63C9, //CJK UNIFIED IDEOGRAPH + 0x9D87: 0x63D2, //CJK UNIFIED IDEOGRAPH + 0x9D88: 0x63F6, //CJK UNIFIED IDEOGRAPH + 0x9D89: 0x63C4, //CJK UNIFIED IDEOGRAPH + 0x9D8A: 0x6416, //CJK UNIFIED IDEOGRAPH + 0x9D8B: 0x6434, //CJK UNIFIED IDEOGRAPH + 0x9D8C: 0x6406, //CJK UNIFIED IDEOGRAPH + 0x9D8D: 0x6413, //CJK UNIFIED IDEOGRAPH + 0x9D8E: 0x6426, //CJK UNIFIED IDEOGRAPH + 0x9D8F: 0x6436, //CJK UNIFIED IDEOGRAPH + 0x9D90: 0x651D, //CJK UNIFIED IDEOGRAPH + 0x9D91: 0x6417, //CJK UNIFIED IDEOGRAPH + 0x9D92: 0x6428, //CJK UNIFIED IDEOGRAPH + 0x9D93: 0x640F, //CJK UNIFIED IDEOGRAPH + 0x9D94: 0x6467, //CJK UNIFIED IDEOGRAPH + 0x9D95: 0x646F, //CJK UNIFIED IDEOGRAPH + 0x9D96: 0x6476, //CJK UNIFIED IDEOGRAPH + 0x9D97: 0x644E, //CJK UNIFIED IDEOGRAPH + 0x9D98: 0x652A, //CJK UNIFIED IDEOGRAPH + 0x9D99: 0x6495, //CJK UNIFIED IDEOGRAPH + 0x9D9A: 0x6493, //CJK UNIFIED IDEOGRAPH + 0x9D9B: 0x64A5, //CJK UNIFIED IDEOGRAPH + 0x9D9C: 0x64A9, //CJK UNIFIED IDEOGRAPH + 0x9D9D: 0x6488, //CJK UNIFIED IDEOGRAPH + 0x9D9E: 0x64BC, //CJK UNIFIED IDEOGRAPH + 0x9D9F: 0x64DA, //CJK UNIFIED IDEOGRAPH + 0x9DA0: 0x64D2, //CJK UNIFIED IDEOGRAPH + 0x9DA1: 0x64C5, //CJK UNIFIED IDEOGRAPH + 0x9DA2: 0x64C7, //CJK UNIFIED IDEOGRAPH + 0x9DA3: 0x64BB, //CJK UNIFIED IDEOGRAPH + 0x9DA4: 0x64D8, //CJK UNIFIED IDEOGRAPH + 0x9DA5: 0x64C2, //CJK UNIFIED IDEOGRAPH + 0x9DA6: 0x64F1, //CJK UNIFIED IDEOGRAPH + 0x9DA7: 0x64E7, //CJK UNIFIED IDEOGRAPH + 0x9DA8: 0x8209, //CJK UNIFIED IDEOGRAPH + 0x9DA9: 0x64E0, //CJK UNIFIED IDEOGRAPH + 0x9DAA: 0x64E1, //CJK UNIFIED IDEOGRAPH + 0x9DAB: 0x62AC, //CJK UNIFIED IDEOGRAPH + 0x9DAC: 0x64E3, //CJK UNIFIED IDEOGRAPH + 0x9DAD: 0x64EF, //CJK UNIFIED IDEOGRAPH + 0x9DAE: 0x652C, //CJK UNIFIED IDEOGRAPH + 0x9DAF: 0x64F6, //CJK UNIFIED IDEOGRAPH + 0x9DB0: 0x64F4, //CJK UNIFIED IDEOGRAPH + 0x9DB1: 0x64F2, //CJK UNIFIED IDEOGRAPH + 0x9DB2: 0x64FA, //CJK UNIFIED IDEOGRAPH + 0x9DB3: 0x6500, //CJK UNIFIED IDEOGRAPH + 0x9DB4: 0x64FD, //CJK UNIFIED IDEOGRAPH + 0x9DB5: 0x6518, //CJK UNIFIED IDEOGRAPH + 0x9DB6: 0x651C, //CJK UNIFIED IDEOGRAPH + 0x9DB7: 0x6505, //CJK UNIFIED IDEOGRAPH + 0x9DB8: 0x6524, //CJK UNIFIED IDEOGRAPH + 0x9DB9: 0x6523, //CJK UNIFIED IDEOGRAPH + 0x9DBA: 0x652B, //CJK UNIFIED IDEOGRAPH + 0x9DBB: 0x6534, //CJK UNIFIED IDEOGRAPH + 0x9DBC: 0x6535, //CJK UNIFIED IDEOGRAPH + 0x9DBD: 0x6537, //CJK UNIFIED IDEOGRAPH + 0x9DBE: 0x6536, //CJK UNIFIED IDEOGRAPH + 0x9DBF: 0x6538, //CJK UNIFIED IDEOGRAPH + 0x9DC0: 0x754B, //CJK UNIFIED IDEOGRAPH + 0x9DC1: 0x6548, //CJK UNIFIED IDEOGRAPH + 0x9DC2: 0x6556, //CJK UNIFIED IDEOGRAPH + 0x9DC3: 0x6555, //CJK UNIFIED IDEOGRAPH + 0x9DC4: 0x654D, //CJK UNIFIED IDEOGRAPH + 0x9DC5: 0x6558, //CJK UNIFIED IDEOGRAPH + 0x9DC6: 0x655E, //CJK UNIFIED IDEOGRAPH + 0x9DC7: 0x655D, //CJK UNIFIED IDEOGRAPH + 0x9DC8: 0x6572, //CJK UNIFIED IDEOGRAPH + 0x9DC9: 0x6578, //CJK UNIFIED IDEOGRAPH + 0x9DCA: 0x6582, //CJK UNIFIED IDEOGRAPH + 0x9DCB: 0x6583, //CJK UNIFIED IDEOGRAPH + 0x9DCC: 0x8B8A, //CJK UNIFIED IDEOGRAPH + 0x9DCD: 0x659B, //CJK UNIFIED IDEOGRAPH + 0x9DCE: 0x659F, //CJK UNIFIED IDEOGRAPH + 0x9DCF: 0x65AB, //CJK UNIFIED IDEOGRAPH + 0x9DD0: 0x65B7, //CJK UNIFIED IDEOGRAPH + 0x9DD1: 0x65C3, //CJK UNIFIED IDEOGRAPH + 0x9DD2: 0x65C6, //CJK UNIFIED IDEOGRAPH + 0x9DD3: 0x65C1, //CJK UNIFIED IDEOGRAPH + 0x9DD4: 0x65C4, //CJK UNIFIED IDEOGRAPH + 0x9DD5: 0x65CC, //CJK UNIFIED IDEOGRAPH + 0x9DD6: 0x65D2, //CJK UNIFIED IDEOGRAPH + 0x9DD7: 0x65DB, //CJK UNIFIED IDEOGRAPH + 0x9DD8: 0x65D9, //CJK UNIFIED IDEOGRAPH + 0x9DD9: 0x65E0, //CJK UNIFIED IDEOGRAPH + 0x9DDA: 0x65E1, //CJK UNIFIED IDEOGRAPH + 0x9DDB: 0x65F1, //CJK UNIFIED IDEOGRAPH + 0x9DDC: 0x6772, //CJK UNIFIED IDEOGRAPH + 0x9DDD: 0x660A, //CJK UNIFIED IDEOGRAPH + 0x9DDE: 0x6603, //CJK UNIFIED IDEOGRAPH + 0x9DDF: 0x65FB, //CJK UNIFIED IDEOGRAPH + 0x9DE0: 0x6773, //CJK UNIFIED IDEOGRAPH + 0x9DE1: 0x6635, //CJK UNIFIED IDEOGRAPH + 0x9DE2: 0x6636, //CJK UNIFIED IDEOGRAPH + 0x9DE3: 0x6634, //CJK UNIFIED IDEOGRAPH + 0x9DE4: 0x661C, //CJK UNIFIED IDEOGRAPH + 0x9DE5: 0x664F, //CJK UNIFIED IDEOGRAPH + 0x9DE6: 0x6644, //CJK UNIFIED IDEOGRAPH + 0x9DE7: 0x6649, //CJK UNIFIED IDEOGRAPH + 0x9DE8: 0x6641, //CJK UNIFIED IDEOGRAPH + 0x9DE9: 0x665E, //CJK UNIFIED IDEOGRAPH + 0x9DEA: 0x665D, //CJK UNIFIED IDEOGRAPH + 0x9DEB: 0x6664, //CJK UNIFIED IDEOGRAPH + 0x9DEC: 0x6667, //CJK UNIFIED IDEOGRAPH + 0x9DED: 0x6668, //CJK UNIFIED IDEOGRAPH + 0x9DEE: 0x665F, //CJK UNIFIED IDEOGRAPH + 0x9DEF: 0x6662, //CJK UNIFIED IDEOGRAPH + 0x9DF0: 0x6670, //CJK UNIFIED IDEOGRAPH + 0x9DF1: 0x6683, //CJK UNIFIED IDEOGRAPH + 0x9DF2: 0x6688, //CJK UNIFIED IDEOGRAPH + 0x9DF3: 0x668E, //CJK UNIFIED IDEOGRAPH + 0x9DF4: 0x6689, //CJK UNIFIED IDEOGRAPH + 0x9DF5: 0x6684, //CJK UNIFIED IDEOGRAPH + 0x9DF6: 0x6698, //CJK UNIFIED IDEOGRAPH + 0x9DF7: 0x669D, //CJK UNIFIED IDEOGRAPH + 0x9DF8: 0x66C1, //CJK UNIFIED IDEOGRAPH + 0x9DF9: 0x66B9, //CJK UNIFIED IDEOGRAPH + 0x9DFA: 0x66C9, //CJK UNIFIED IDEOGRAPH + 0x9DFB: 0x66BE, //CJK UNIFIED IDEOGRAPH + 0x9DFC: 0x66BC, //CJK UNIFIED IDEOGRAPH + 0x9E40: 0x66C4, //CJK UNIFIED IDEOGRAPH + 0x9E41: 0x66B8, //CJK UNIFIED IDEOGRAPH + 0x9E42: 0x66D6, //CJK UNIFIED IDEOGRAPH + 0x9E43: 0x66DA, //CJK UNIFIED IDEOGRAPH + 0x9E44: 0x66E0, //CJK UNIFIED IDEOGRAPH + 0x9E45: 0x663F, //CJK UNIFIED IDEOGRAPH + 0x9E46: 0x66E6, //CJK UNIFIED IDEOGRAPH + 0x9E47: 0x66E9, //CJK UNIFIED IDEOGRAPH + 0x9E48: 0x66F0, //CJK UNIFIED IDEOGRAPH + 0x9E49: 0x66F5, //CJK UNIFIED IDEOGRAPH + 0x9E4A: 0x66F7, //CJK UNIFIED IDEOGRAPH + 0x9E4B: 0x670F, //CJK UNIFIED IDEOGRAPH + 0x9E4C: 0x6716, //CJK UNIFIED IDEOGRAPH + 0x9E4D: 0x671E, //CJK UNIFIED IDEOGRAPH + 0x9E4E: 0x6726, //CJK UNIFIED IDEOGRAPH + 0x9E4F: 0x6727, //CJK UNIFIED IDEOGRAPH + 0x9E50: 0x9738, //CJK UNIFIED IDEOGRAPH + 0x9E51: 0x672E, //CJK UNIFIED IDEOGRAPH + 0x9E52: 0x673F, //CJK UNIFIED IDEOGRAPH + 0x9E53: 0x6736, //CJK UNIFIED IDEOGRAPH + 0x9E54: 0x6741, //CJK UNIFIED IDEOGRAPH + 0x9E55: 0x6738, //CJK UNIFIED IDEOGRAPH + 0x9E56: 0x6737, //CJK UNIFIED IDEOGRAPH + 0x9E57: 0x6746, //CJK UNIFIED IDEOGRAPH + 0x9E58: 0x675E, //CJK UNIFIED IDEOGRAPH + 0x9E59: 0x6760, //CJK UNIFIED IDEOGRAPH + 0x9E5A: 0x6759, //CJK UNIFIED IDEOGRAPH + 0x9E5B: 0x6763, //CJK UNIFIED IDEOGRAPH + 0x9E5C: 0x6764, //CJK UNIFIED IDEOGRAPH + 0x9E5D: 0x6789, //CJK UNIFIED IDEOGRAPH + 0x9E5E: 0x6770, //CJK UNIFIED IDEOGRAPH + 0x9E5F: 0x67A9, //CJK UNIFIED IDEOGRAPH + 0x9E60: 0x677C, //CJK UNIFIED IDEOGRAPH + 0x9E61: 0x676A, //CJK UNIFIED IDEOGRAPH + 0x9E62: 0x678C, //CJK UNIFIED IDEOGRAPH + 0x9E63: 0x678B, //CJK UNIFIED IDEOGRAPH + 0x9E64: 0x67A6, //CJK UNIFIED IDEOGRAPH + 0x9E65: 0x67A1, //CJK UNIFIED IDEOGRAPH + 0x9E66: 0x6785, //CJK UNIFIED IDEOGRAPH + 0x9E67: 0x67B7, //CJK UNIFIED IDEOGRAPH + 0x9E68: 0x67EF, //CJK UNIFIED IDEOGRAPH + 0x9E69: 0x67B4, //CJK UNIFIED IDEOGRAPH + 0x9E6A: 0x67EC, //CJK UNIFIED IDEOGRAPH + 0x9E6B: 0x67B3, //CJK UNIFIED IDEOGRAPH + 0x9E6C: 0x67E9, //CJK UNIFIED IDEOGRAPH + 0x9E6D: 0x67B8, //CJK UNIFIED IDEOGRAPH + 0x9E6E: 0x67E4, //CJK UNIFIED IDEOGRAPH + 0x9E6F: 0x67DE, //CJK UNIFIED IDEOGRAPH + 0x9E70: 0x67DD, //CJK UNIFIED IDEOGRAPH + 0x9E71: 0x67E2, //CJK UNIFIED IDEOGRAPH + 0x9E72: 0x67EE, //CJK UNIFIED IDEOGRAPH + 0x9E73: 0x67B9, //CJK UNIFIED IDEOGRAPH + 0x9E74: 0x67CE, //CJK UNIFIED IDEOGRAPH + 0x9E75: 0x67C6, //CJK UNIFIED IDEOGRAPH + 0x9E76: 0x67E7, //CJK UNIFIED IDEOGRAPH + 0x9E77: 0x6A9C, //CJK UNIFIED IDEOGRAPH + 0x9E78: 0x681E, //CJK UNIFIED IDEOGRAPH + 0x9E79: 0x6846, //CJK UNIFIED IDEOGRAPH + 0x9E7A: 0x6829, //CJK UNIFIED IDEOGRAPH + 0x9E7B: 0x6840, //CJK UNIFIED IDEOGRAPH + 0x9E7C: 0x684D, //CJK UNIFIED IDEOGRAPH + 0x9E7D: 0x6832, //CJK UNIFIED IDEOGRAPH + 0x9E7E: 0x684E, //CJK UNIFIED IDEOGRAPH + 0x9E80: 0x68B3, //CJK UNIFIED IDEOGRAPH + 0x9E81: 0x682B, //CJK UNIFIED IDEOGRAPH + 0x9E82: 0x6859, //CJK UNIFIED IDEOGRAPH + 0x9E83: 0x6863, //CJK UNIFIED IDEOGRAPH + 0x9E84: 0x6877, //CJK UNIFIED IDEOGRAPH + 0x9E85: 0x687F, //CJK UNIFIED IDEOGRAPH + 0x9E86: 0x689F, //CJK UNIFIED IDEOGRAPH + 0x9E87: 0x688F, //CJK UNIFIED IDEOGRAPH + 0x9E88: 0x68AD, //CJK UNIFIED IDEOGRAPH + 0x9E89: 0x6894, //CJK UNIFIED IDEOGRAPH + 0x9E8A: 0x689D, //CJK UNIFIED IDEOGRAPH + 0x9E8B: 0x689B, //CJK UNIFIED IDEOGRAPH + 0x9E8C: 0x6883, //CJK UNIFIED IDEOGRAPH + 0x9E8D: 0x6AAE, //CJK UNIFIED IDEOGRAPH + 0x9E8E: 0x68B9, //CJK UNIFIED IDEOGRAPH + 0x9E8F: 0x6874, //CJK UNIFIED IDEOGRAPH + 0x9E90: 0x68B5, //CJK UNIFIED IDEOGRAPH + 0x9E91: 0x68A0, //CJK UNIFIED IDEOGRAPH + 0x9E92: 0x68BA, //CJK UNIFIED IDEOGRAPH + 0x9E93: 0x690F, //CJK UNIFIED IDEOGRAPH + 0x9E94: 0x688D, //CJK UNIFIED IDEOGRAPH + 0x9E95: 0x687E, //CJK UNIFIED IDEOGRAPH + 0x9E96: 0x6901, //CJK UNIFIED IDEOGRAPH + 0x9E97: 0x68CA, //CJK UNIFIED IDEOGRAPH + 0x9E98: 0x6908, //CJK UNIFIED IDEOGRAPH + 0x9E99: 0x68D8, //CJK UNIFIED IDEOGRAPH + 0x9E9A: 0x6922, //CJK UNIFIED IDEOGRAPH + 0x9E9B: 0x6926, //CJK UNIFIED IDEOGRAPH + 0x9E9C: 0x68E1, //CJK UNIFIED IDEOGRAPH + 0x9E9D: 0x690C, //CJK UNIFIED IDEOGRAPH + 0x9E9E: 0x68CD, //CJK UNIFIED IDEOGRAPH + 0x9E9F: 0x68D4, //CJK UNIFIED IDEOGRAPH + 0x9EA0: 0x68E7, //CJK UNIFIED IDEOGRAPH + 0x9EA1: 0x68D5, //CJK UNIFIED IDEOGRAPH + 0x9EA2: 0x6936, //CJK UNIFIED IDEOGRAPH + 0x9EA3: 0x6912, //CJK UNIFIED IDEOGRAPH + 0x9EA4: 0x6904, //CJK UNIFIED IDEOGRAPH + 0x9EA5: 0x68D7, //CJK UNIFIED IDEOGRAPH + 0x9EA6: 0x68E3, //CJK UNIFIED IDEOGRAPH + 0x9EA7: 0x6925, //CJK UNIFIED IDEOGRAPH + 0x9EA8: 0x68F9, //CJK UNIFIED IDEOGRAPH + 0x9EA9: 0x68E0, //CJK UNIFIED IDEOGRAPH + 0x9EAA: 0x68EF, //CJK UNIFIED IDEOGRAPH + 0x9EAB: 0x6928, //CJK UNIFIED IDEOGRAPH + 0x9EAC: 0x692A, //CJK UNIFIED IDEOGRAPH + 0x9EAD: 0x691A, //CJK UNIFIED IDEOGRAPH + 0x9EAE: 0x6923, //CJK UNIFIED IDEOGRAPH + 0x9EAF: 0x6921, //CJK UNIFIED IDEOGRAPH + 0x9EB0: 0x68C6, //CJK UNIFIED IDEOGRAPH + 0x9EB1: 0x6979, //CJK UNIFIED IDEOGRAPH + 0x9EB2: 0x6977, //CJK UNIFIED IDEOGRAPH + 0x9EB3: 0x695C, //CJK UNIFIED IDEOGRAPH + 0x9EB4: 0x6978, //CJK UNIFIED IDEOGRAPH + 0x9EB5: 0x696B, //CJK UNIFIED IDEOGRAPH + 0x9EB6: 0x6954, //CJK UNIFIED IDEOGRAPH + 0x9EB7: 0x697E, //CJK UNIFIED IDEOGRAPH + 0x9EB8: 0x696E, //CJK UNIFIED IDEOGRAPH + 0x9EB9: 0x6939, //CJK UNIFIED IDEOGRAPH + 0x9EBA: 0x6974, //CJK UNIFIED IDEOGRAPH + 0x9EBB: 0x693D, //CJK UNIFIED IDEOGRAPH + 0x9EBC: 0x6959, //CJK UNIFIED IDEOGRAPH + 0x9EBD: 0x6930, //CJK UNIFIED IDEOGRAPH + 0x9EBE: 0x6961, //CJK UNIFIED IDEOGRAPH + 0x9EBF: 0x695E, //CJK UNIFIED IDEOGRAPH + 0x9EC0: 0x695D, //CJK UNIFIED IDEOGRAPH + 0x9EC1: 0x6981, //CJK UNIFIED IDEOGRAPH + 0x9EC2: 0x696A, //CJK UNIFIED IDEOGRAPH + 0x9EC3: 0x69B2, //CJK UNIFIED IDEOGRAPH + 0x9EC4: 0x69AE, //CJK UNIFIED IDEOGRAPH + 0x9EC5: 0x69D0, //CJK UNIFIED IDEOGRAPH + 0x9EC6: 0x69BF, //CJK UNIFIED IDEOGRAPH + 0x9EC7: 0x69C1, //CJK UNIFIED IDEOGRAPH + 0x9EC8: 0x69D3, //CJK UNIFIED IDEOGRAPH + 0x9EC9: 0x69BE, //CJK UNIFIED IDEOGRAPH + 0x9ECA: 0x69CE, //CJK UNIFIED IDEOGRAPH + 0x9ECB: 0x5BE8, //CJK UNIFIED IDEOGRAPH + 0x9ECC: 0x69CA, //CJK UNIFIED IDEOGRAPH + 0x9ECD: 0x69DD, //CJK UNIFIED IDEOGRAPH + 0x9ECE: 0x69BB, //CJK UNIFIED IDEOGRAPH + 0x9ECF: 0x69C3, //CJK UNIFIED IDEOGRAPH + 0x9ED0: 0x69A7, //CJK UNIFIED IDEOGRAPH + 0x9ED1: 0x6A2E, //CJK UNIFIED IDEOGRAPH + 0x9ED2: 0x6991, //CJK UNIFIED IDEOGRAPH + 0x9ED3: 0x69A0, //CJK UNIFIED IDEOGRAPH + 0x9ED4: 0x699C, //CJK UNIFIED IDEOGRAPH + 0x9ED5: 0x6995, //CJK UNIFIED IDEOGRAPH + 0x9ED6: 0x69B4, //CJK UNIFIED IDEOGRAPH + 0x9ED7: 0x69DE, //CJK UNIFIED IDEOGRAPH + 0x9ED8: 0x69E8, //CJK UNIFIED IDEOGRAPH + 0x9ED9: 0x6A02, //CJK UNIFIED IDEOGRAPH + 0x9EDA: 0x6A1B, //CJK UNIFIED IDEOGRAPH + 0x9EDB: 0x69FF, //CJK UNIFIED IDEOGRAPH + 0x9EDC: 0x6B0A, //CJK UNIFIED IDEOGRAPH + 0x9EDD: 0x69F9, //CJK UNIFIED IDEOGRAPH + 0x9EDE: 0x69F2, //CJK UNIFIED IDEOGRAPH + 0x9EDF: 0x69E7, //CJK UNIFIED IDEOGRAPH + 0x9EE0: 0x6A05, //CJK UNIFIED IDEOGRAPH + 0x9EE1: 0x69B1, //CJK UNIFIED IDEOGRAPH + 0x9EE2: 0x6A1E, //CJK UNIFIED IDEOGRAPH + 0x9EE3: 0x69ED, //CJK UNIFIED IDEOGRAPH + 0x9EE4: 0x6A14, //CJK UNIFIED IDEOGRAPH + 0x9EE5: 0x69EB, //CJK UNIFIED IDEOGRAPH + 0x9EE6: 0x6A0A, //CJK UNIFIED IDEOGRAPH + 0x9EE7: 0x6A12, //CJK UNIFIED IDEOGRAPH + 0x9EE8: 0x6AC1, //CJK UNIFIED IDEOGRAPH + 0x9EE9: 0x6A23, //CJK UNIFIED IDEOGRAPH + 0x9EEA: 0x6A13, //CJK UNIFIED IDEOGRAPH + 0x9EEB: 0x6A44, //CJK UNIFIED IDEOGRAPH + 0x9EEC: 0x6A0C, //CJK UNIFIED IDEOGRAPH + 0x9EED: 0x6A72, //CJK UNIFIED IDEOGRAPH + 0x9EEE: 0x6A36, //CJK UNIFIED IDEOGRAPH + 0x9EEF: 0x6A78, //CJK UNIFIED IDEOGRAPH + 0x9EF0: 0x6A47, //CJK UNIFIED IDEOGRAPH + 0x9EF1: 0x6A62, //CJK UNIFIED IDEOGRAPH + 0x9EF2: 0x6A59, //CJK UNIFIED IDEOGRAPH + 0x9EF3: 0x6A66, //CJK UNIFIED IDEOGRAPH + 0x9EF4: 0x6A48, //CJK UNIFIED IDEOGRAPH + 0x9EF5: 0x6A38, //CJK UNIFIED IDEOGRAPH + 0x9EF6: 0x6A22, //CJK UNIFIED IDEOGRAPH + 0x9EF7: 0x6A90, //CJK UNIFIED IDEOGRAPH + 0x9EF8: 0x6A8D, //CJK UNIFIED IDEOGRAPH + 0x9EF9: 0x6AA0, //CJK UNIFIED IDEOGRAPH + 0x9EFA: 0x6A84, //CJK UNIFIED IDEOGRAPH + 0x9EFB: 0x6AA2, //CJK UNIFIED IDEOGRAPH + 0x9EFC: 0x6AA3, //CJK UNIFIED IDEOGRAPH + 0x9F40: 0x6A97, //CJK UNIFIED IDEOGRAPH + 0x9F41: 0x8617, //CJK UNIFIED IDEOGRAPH + 0x9F42: 0x6ABB, //CJK UNIFIED IDEOGRAPH + 0x9F43: 0x6AC3, //CJK UNIFIED IDEOGRAPH + 0x9F44: 0x6AC2, //CJK UNIFIED IDEOGRAPH + 0x9F45: 0x6AB8, //CJK UNIFIED IDEOGRAPH + 0x9F46: 0x6AB3, //CJK UNIFIED IDEOGRAPH + 0x9F47: 0x6AAC, //CJK UNIFIED IDEOGRAPH + 0x9F48: 0x6ADE, //CJK UNIFIED IDEOGRAPH + 0x9F49: 0x6AD1, //CJK UNIFIED IDEOGRAPH + 0x9F4A: 0x6ADF, //CJK UNIFIED IDEOGRAPH + 0x9F4B: 0x6AAA, //CJK UNIFIED IDEOGRAPH + 0x9F4C: 0x6ADA, //CJK UNIFIED IDEOGRAPH + 0x9F4D: 0x6AEA, //CJK UNIFIED IDEOGRAPH + 0x9F4E: 0x6AFB, //CJK UNIFIED IDEOGRAPH + 0x9F4F: 0x6B05, //CJK UNIFIED IDEOGRAPH + 0x9F50: 0x8616, //CJK UNIFIED IDEOGRAPH + 0x9F51: 0x6AFA, //CJK UNIFIED IDEOGRAPH + 0x9F52: 0x6B12, //CJK UNIFIED IDEOGRAPH + 0x9F53: 0x6B16, //CJK UNIFIED IDEOGRAPH + 0x9F54: 0x9B31, //CJK UNIFIED IDEOGRAPH + 0x9F55: 0x6B1F, //CJK UNIFIED IDEOGRAPH + 0x9F56: 0x6B38, //CJK UNIFIED IDEOGRAPH + 0x9F57: 0x6B37, //CJK UNIFIED IDEOGRAPH + 0x9F58: 0x76DC, //CJK UNIFIED IDEOGRAPH + 0x9F59: 0x6B39, //CJK UNIFIED IDEOGRAPH + 0x9F5A: 0x98EE, //CJK UNIFIED IDEOGRAPH + 0x9F5B: 0x6B47, //CJK UNIFIED IDEOGRAPH + 0x9F5C: 0x6B43, //CJK UNIFIED IDEOGRAPH + 0x9F5D: 0x6B49, //CJK UNIFIED IDEOGRAPH + 0x9F5E: 0x6B50, //CJK UNIFIED IDEOGRAPH + 0x9F5F: 0x6B59, //CJK UNIFIED IDEOGRAPH + 0x9F60: 0x6B54, //CJK UNIFIED IDEOGRAPH + 0x9F61: 0x6B5B, //CJK UNIFIED IDEOGRAPH + 0x9F62: 0x6B5F, //CJK UNIFIED IDEOGRAPH + 0x9F63: 0x6B61, //CJK UNIFIED IDEOGRAPH + 0x9F64: 0x6B78, //CJK UNIFIED IDEOGRAPH + 0x9F65: 0x6B79, //CJK UNIFIED IDEOGRAPH + 0x9F66: 0x6B7F, //CJK UNIFIED IDEOGRAPH + 0x9F67: 0x6B80, //CJK UNIFIED IDEOGRAPH + 0x9F68: 0x6B84, //CJK UNIFIED IDEOGRAPH + 0x9F69: 0x6B83, //CJK UNIFIED IDEOGRAPH + 0x9F6A: 0x6B8D, //CJK UNIFIED IDEOGRAPH + 0x9F6B: 0x6B98, //CJK UNIFIED IDEOGRAPH + 0x9F6C: 0x6B95, //CJK UNIFIED IDEOGRAPH + 0x9F6D: 0x6B9E, //CJK UNIFIED IDEOGRAPH + 0x9F6E: 0x6BA4, //CJK UNIFIED IDEOGRAPH + 0x9F6F: 0x6BAA, //CJK UNIFIED IDEOGRAPH + 0x9F70: 0x6BAB, //CJK UNIFIED IDEOGRAPH + 0x9F71: 0x6BAF, //CJK UNIFIED IDEOGRAPH + 0x9F72: 0x6BB2, //CJK UNIFIED IDEOGRAPH + 0x9F73: 0x6BB1, //CJK UNIFIED IDEOGRAPH + 0x9F74: 0x6BB3, //CJK UNIFIED IDEOGRAPH + 0x9F75: 0x6BB7, //CJK UNIFIED IDEOGRAPH + 0x9F76: 0x6BBC, //CJK UNIFIED IDEOGRAPH + 0x9F77: 0x6BC6, //CJK UNIFIED IDEOGRAPH + 0x9F78: 0x6BCB, //CJK UNIFIED IDEOGRAPH + 0x9F79: 0x6BD3, //CJK UNIFIED IDEOGRAPH + 0x9F7A: 0x6BDF, //CJK UNIFIED IDEOGRAPH + 0x9F7B: 0x6BEC, //CJK UNIFIED IDEOGRAPH + 0x9F7C: 0x6BEB, //CJK UNIFIED IDEOGRAPH + 0x9F7D: 0x6BF3, //CJK UNIFIED IDEOGRAPH + 0x9F7E: 0x6BEF, //CJK UNIFIED IDEOGRAPH + 0x9F80: 0x9EBE, //CJK UNIFIED IDEOGRAPH + 0x9F81: 0x6C08, //CJK UNIFIED IDEOGRAPH + 0x9F82: 0x6C13, //CJK UNIFIED IDEOGRAPH + 0x9F83: 0x6C14, //CJK UNIFIED IDEOGRAPH + 0x9F84: 0x6C1B, //CJK UNIFIED IDEOGRAPH + 0x9F85: 0x6C24, //CJK UNIFIED IDEOGRAPH + 0x9F86: 0x6C23, //CJK UNIFIED IDEOGRAPH + 0x9F87: 0x6C5E, //CJK UNIFIED IDEOGRAPH + 0x9F88: 0x6C55, //CJK UNIFIED IDEOGRAPH + 0x9F89: 0x6C62, //CJK UNIFIED IDEOGRAPH + 0x9F8A: 0x6C6A, //CJK UNIFIED IDEOGRAPH + 0x9F8B: 0x6C82, //CJK UNIFIED IDEOGRAPH + 0x9F8C: 0x6C8D, //CJK UNIFIED IDEOGRAPH + 0x9F8D: 0x6C9A, //CJK UNIFIED IDEOGRAPH + 0x9F8E: 0x6C81, //CJK UNIFIED IDEOGRAPH + 0x9F8F: 0x6C9B, //CJK UNIFIED IDEOGRAPH + 0x9F90: 0x6C7E, //CJK UNIFIED IDEOGRAPH + 0x9F91: 0x6C68, //CJK UNIFIED IDEOGRAPH + 0x9F92: 0x6C73, //CJK UNIFIED IDEOGRAPH + 0x9F93: 0x6C92, //CJK UNIFIED IDEOGRAPH + 0x9F94: 0x6C90, //CJK UNIFIED IDEOGRAPH + 0x9F95: 0x6CC4, //CJK UNIFIED IDEOGRAPH + 0x9F96: 0x6CF1, //CJK UNIFIED IDEOGRAPH + 0x9F97: 0x6CD3, //CJK UNIFIED IDEOGRAPH + 0x9F98: 0x6CBD, //CJK UNIFIED IDEOGRAPH + 0x9F99: 0x6CD7, //CJK UNIFIED IDEOGRAPH + 0x9F9A: 0x6CC5, //CJK UNIFIED IDEOGRAPH + 0x9F9B: 0x6CDD, //CJK UNIFIED IDEOGRAPH + 0x9F9C: 0x6CAE, //CJK UNIFIED IDEOGRAPH + 0x9F9D: 0x6CB1, //CJK UNIFIED IDEOGRAPH + 0x9F9E: 0x6CBE, //CJK UNIFIED IDEOGRAPH + 0x9F9F: 0x6CBA, //CJK UNIFIED IDEOGRAPH + 0x9FA0: 0x6CDB, //CJK UNIFIED IDEOGRAPH + 0x9FA1: 0x6CEF, //CJK UNIFIED IDEOGRAPH + 0x9FA2: 0x6CD9, //CJK UNIFIED IDEOGRAPH + 0x9FA3: 0x6CEA, //CJK UNIFIED IDEOGRAPH + 0x9FA4: 0x6D1F, //CJK UNIFIED IDEOGRAPH + 0x9FA5: 0x884D, //CJK UNIFIED IDEOGRAPH + 0x9FA6: 0x6D36, //CJK UNIFIED IDEOGRAPH + 0x9FA7: 0x6D2B, //CJK UNIFIED IDEOGRAPH + 0x9FA8: 0x6D3D, //CJK UNIFIED IDEOGRAPH + 0x9FA9: 0x6D38, //CJK UNIFIED IDEOGRAPH + 0x9FAA: 0x6D19, //CJK UNIFIED IDEOGRAPH + 0x9FAB: 0x6D35, //CJK UNIFIED IDEOGRAPH + 0x9FAC: 0x6D33, //CJK UNIFIED IDEOGRAPH + 0x9FAD: 0x6D12, //CJK UNIFIED IDEOGRAPH + 0x9FAE: 0x6D0C, //CJK UNIFIED IDEOGRAPH + 0x9FAF: 0x6D63, //CJK UNIFIED IDEOGRAPH + 0x9FB0: 0x6D93, //CJK UNIFIED IDEOGRAPH + 0x9FB1: 0x6D64, //CJK UNIFIED IDEOGRAPH + 0x9FB2: 0x6D5A, //CJK UNIFIED IDEOGRAPH + 0x9FB3: 0x6D79, //CJK UNIFIED IDEOGRAPH + 0x9FB4: 0x6D59, //CJK UNIFIED IDEOGRAPH + 0x9FB5: 0x6D8E, //CJK UNIFIED IDEOGRAPH + 0x9FB6: 0x6D95, //CJK UNIFIED IDEOGRAPH + 0x9FB7: 0x6FE4, //CJK UNIFIED IDEOGRAPH + 0x9FB8: 0x6D85, //CJK UNIFIED IDEOGRAPH + 0x9FB9: 0x6DF9, //CJK UNIFIED IDEOGRAPH + 0x9FBA: 0x6E15, //CJK UNIFIED IDEOGRAPH + 0x9FBB: 0x6E0A, //CJK UNIFIED IDEOGRAPH + 0x9FBC: 0x6DB5, //CJK UNIFIED IDEOGRAPH + 0x9FBD: 0x6DC7, //CJK UNIFIED IDEOGRAPH + 0x9FBE: 0x6DE6, //CJK UNIFIED IDEOGRAPH + 0x9FBF: 0x6DB8, //CJK UNIFIED IDEOGRAPH + 0x9FC0: 0x6DC6, //CJK UNIFIED IDEOGRAPH + 0x9FC1: 0x6DEC, //CJK UNIFIED IDEOGRAPH + 0x9FC2: 0x6DDE, //CJK UNIFIED IDEOGRAPH + 0x9FC3: 0x6DCC, //CJK UNIFIED IDEOGRAPH + 0x9FC4: 0x6DE8, //CJK UNIFIED IDEOGRAPH + 0x9FC5: 0x6DD2, //CJK UNIFIED IDEOGRAPH + 0x9FC6: 0x6DC5, //CJK UNIFIED IDEOGRAPH + 0x9FC7: 0x6DFA, //CJK UNIFIED IDEOGRAPH + 0x9FC8: 0x6DD9, //CJK UNIFIED IDEOGRAPH + 0x9FC9: 0x6DE4, //CJK UNIFIED IDEOGRAPH + 0x9FCA: 0x6DD5, //CJK UNIFIED IDEOGRAPH + 0x9FCB: 0x6DEA, //CJK UNIFIED IDEOGRAPH + 0x9FCC: 0x6DEE, //CJK UNIFIED IDEOGRAPH + 0x9FCD: 0x6E2D, //CJK UNIFIED IDEOGRAPH + 0x9FCE: 0x6E6E, //CJK UNIFIED IDEOGRAPH + 0x9FCF: 0x6E2E, //CJK UNIFIED IDEOGRAPH + 0x9FD0: 0x6E19, //CJK UNIFIED IDEOGRAPH + 0x9FD1: 0x6E72, //CJK UNIFIED IDEOGRAPH + 0x9FD2: 0x6E5F, //CJK UNIFIED IDEOGRAPH + 0x9FD3: 0x6E3E, //CJK UNIFIED IDEOGRAPH + 0x9FD4: 0x6E23, //CJK UNIFIED IDEOGRAPH + 0x9FD5: 0x6E6B, //CJK UNIFIED IDEOGRAPH + 0x9FD6: 0x6E2B, //CJK UNIFIED IDEOGRAPH + 0x9FD7: 0x6E76, //CJK UNIFIED IDEOGRAPH + 0x9FD8: 0x6E4D, //CJK UNIFIED IDEOGRAPH + 0x9FD9: 0x6E1F, //CJK UNIFIED IDEOGRAPH + 0x9FDA: 0x6E43, //CJK UNIFIED IDEOGRAPH + 0x9FDB: 0x6E3A, //CJK UNIFIED IDEOGRAPH + 0x9FDC: 0x6E4E, //CJK UNIFIED IDEOGRAPH + 0x9FDD: 0x6E24, //CJK UNIFIED IDEOGRAPH + 0x9FDE: 0x6EFF, //CJK UNIFIED IDEOGRAPH + 0x9FDF: 0x6E1D, //CJK UNIFIED IDEOGRAPH + 0x9FE0: 0x6E38, //CJK UNIFIED IDEOGRAPH + 0x9FE1: 0x6E82, //CJK UNIFIED IDEOGRAPH + 0x9FE2: 0x6EAA, //CJK UNIFIED IDEOGRAPH + 0x9FE3: 0x6E98, //CJK UNIFIED IDEOGRAPH + 0x9FE4: 0x6EC9, //CJK UNIFIED IDEOGRAPH + 0x9FE5: 0x6EB7, //CJK UNIFIED IDEOGRAPH + 0x9FE6: 0x6ED3, //CJK UNIFIED IDEOGRAPH + 0x9FE7: 0x6EBD, //CJK UNIFIED IDEOGRAPH + 0x9FE8: 0x6EAF, //CJK UNIFIED IDEOGRAPH + 0x9FE9: 0x6EC4, //CJK UNIFIED IDEOGRAPH + 0x9FEA: 0x6EB2, //CJK UNIFIED IDEOGRAPH + 0x9FEB: 0x6ED4, //CJK UNIFIED IDEOGRAPH + 0x9FEC: 0x6ED5, //CJK UNIFIED IDEOGRAPH + 0x9FED: 0x6E8F, //CJK UNIFIED IDEOGRAPH + 0x9FEE: 0x6EA5, //CJK UNIFIED IDEOGRAPH + 0x9FEF: 0x6EC2, //CJK UNIFIED IDEOGRAPH + 0x9FF0: 0x6E9F, //CJK UNIFIED IDEOGRAPH + 0x9FF1: 0x6F41, //CJK UNIFIED IDEOGRAPH + 0x9FF2: 0x6F11, //CJK UNIFIED IDEOGRAPH + 0x9FF3: 0x704C, //CJK UNIFIED IDEOGRAPH + 0x9FF4: 0x6EEC, //CJK UNIFIED IDEOGRAPH + 0x9FF5: 0x6EF8, //CJK UNIFIED IDEOGRAPH + 0x9FF6: 0x6EFE, //CJK UNIFIED IDEOGRAPH + 0x9FF7: 0x6F3F, //CJK UNIFIED IDEOGRAPH + 0x9FF8: 0x6EF2, //CJK UNIFIED IDEOGRAPH + 0x9FF9: 0x6F31, //CJK UNIFIED IDEOGRAPH + 0x9FFA: 0x6EEF, //CJK UNIFIED IDEOGRAPH + 0x9FFB: 0x6F32, //CJK UNIFIED IDEOGRAPH + 0x9FFC: 0x6ECC, //CJK UNIFIED IDEOGRAPH + 0xE040: 0x6F3E, //CJK UNIFIED IDEOGRAPH + 0xE041: 0x6F13, //CJK UNIFIED IDEOGRAPH + 0xE042: 0x6EF7, //CJK UNIFIED IDEOGRAPH + 0xE043: 0x6F86, //CJK UNIFIED IDEOGRAPH + 0xE044: 0x6F7A, //CJK UNIFIED IDEOGRAPH + 0xE045: 0x6F78, //CJK UNIFIED IDEOGRAPH + 0xE046: 0x6F81, //CJK UNIFIED IDEOGRAPH + 0xE047: 0x6F80, //CJK UNIFIED IDEOGRAPH + 0xE048: 0x6F6F, //CJK UNIFIED IDEOGRAPH + 0xE049: 0x6F5B, //CJK UNIFIED IDEOGRAPH + 0xE04A: 0x6FF3, //CJK UNIFIED IDEOGRAPH + 0xE04B: 0x6F6D, //CJK UNIFIED IDEOGRAPH + 0xE04C: 0x6F82, //CJK UNIFIED IDEOGRAPH + 0xE04D: 0x6F7C, //CJK UNIFIED IDEOGRAPH + 0xE04E: 0x6F58, //CJK UNIFIED IDEOGRAPH + 0xE04F: 0x6F8E, //CJK UNIFIED IDEOGRAPH + 0xE050: 0x6F91, //CJK UNIFIED IDEOGRAPH + 0xE051: 0x6FC2, //CJK UNIFIED IDEOGRAPH + 0xE052: 0x6F66, //CJK UNIFIED IDEOGRAPH + 0xE053: 0x6FB3, //CJK UNIFIED IDEOGRAPH + 0xE054: 0x6FA3, //CJK UNIFIED IDEOGRAPH + 0xE055: 0x6FA1, //CJK UNIFIED IDEOGRAPH + 0xE056: 0x6FA4, //CJK UNIFIED IDEOGRAPH + 0xE057: 0x6FB9, //CJK UNIFIED IDEOGRAPH + 0xE058: 0x6FC6, //CJK UNIFIED IDEOGRAPH + 0xE059: 0x6FAA, //CJK UNIFIED IDEOGRAPH + 0xE05A: 0x6FDF, //CJK UNIFIED IDEOGRAPH + 0xE05B: 0x6FD5, //CJK UNIFIED IDEOGRAPH + 0xE05C: 0x6FEC, //CJK UNIFIED IDEOGRAPH + 0xE05D: 0x6FD4, //CJK UNIFIED IDEOGRAPH + 0xE05E: 0x6FD8, //CJK UNIFIED IDEOGRAPH + 0xE05F: 0x6FF1, //CJK UNIFIED IDEOGRAPH + 0xE060: 0x6FEE, //CJK UNIFIED IDEOGRAPH + 0xE061: 0x6FDB, //CJK UNIFIED IDEOGRAPH + 0xE062: 0x7009, //CJK UNIFIED IDEOGRAPH + 0xE063: 0x700B, //CJK UNIFIED IDEOGRAPH + 0xE064: 0x6FFA, //CJK UNIFIED IDEOGRAPH + 0xE065: 0x7011, //CJK UNIFIED IDEOGRAPH + 0xE066: 0x7001, //CJK UNIFIED IDEOGRAPH + 0xE067: 0x700F, //CJK UNIFIED IDEOGRAPH + 0xE068: 0x6FFE, //CJK UNIFIED IDEOGRAPH + 0xE069: 0x701B, //CJK UNIFIED IDEOGRAPH + 0xE06A: 0x701A, //CJK UNIFIED IDEOGRAPH + 0xE06B: 0x6F74, //CJK UNIFIED IDEOGRAPH + 0xE06C: 0x701D, //CJK UNIFIED IDEOGRAPH + 0xE06D: 0x7018, //CJK UNIFIED IDEOGRAPH + 0xE06E: 0x701F, //CJK UNIFIED IDEOGRAPH + 0xE06F: 0x7030, //CJK UNIFIED IDEOGRAPH + 0xE070: 0x703E, //CJK UNIFIED IDEOGRAPH + 0xE071: 0x7032, //CJK UNIFIED IDEOGRAPH + 0xE072: 0x7051, //CJK UNIFIED IDEOGRAPH + 0xE073: 0x7063, //CJK UNIFIED IDEOGRAPH + 0xE074: 0x7099, //CJK UNIFIED IDEOGRAPH + 0xE075: 0x7092, //CJK UNIFIED IDEOGRAPH + 0xE076: 0x70AF, //CJK UNIFIED IDEOGRAPH + 0xE077: 0x70F1, //CJK UNIFIED IDEOGRAPH + 0xE078: 0x70AC, //CJK UNIFIED IDEOGRAPH + 0xE079: 0x70B8, //CJK UNIFIED IDEOGRAPH + 0xE07A: 0x70B3, //CJK UNIFIED IDEOGRAPH + 0xE07B: 0x70AE, //CJK UNIFIED IDEOGRAPH + 0xE07C: 0x70DF, //CJK UNIFIED IDEOGRAPH + 0xE07D: 0x70CB, //CJK UNIFIED IDEOGRAPH + 0xE07E: 0x70DD, //CJK UNIFIED IDEOGRAPH + 0xE080: 0x70D9, //CJK UNIFIED IDEOGRAPH + 0xE081: 0x7109, //CJK UNIFIED IDEOGRAPH + 0xE082: 0x70FD, //CJK UNIFIED IDEOGRAPH + 0xE083: 0x711C, //CJK UNIFIED IDEOGRAPH + 0xE084: 0x7119, //CJK UNIFIED IDEOGRAPH + 0xE085: 0x7165, //CJK UNIFIED IDEOGRAPH + 0xE086: 0x7155, //CJK UNIFIED IDEOGRAPH + 0xE087: 0x7188, //CJK UNIFIED IDEOGRAPH + 0xE088: 0x7166, //CJK UNIFIED IDEOGRAPH + 0xE089: 0x7162, //CJK UNIFIED IDEOGRAPH + 0xE08A: 0x714C, //CJK UNIFIED IDEOGRAPH + 0xE08B: 0x7156, //CJK UNIFIED IDEOGRAPH + 0xE08C: 0x716C, //CJK UNIFIED IDEOGRAPH + 0xE08D: 0x718F, //CJK UNIFIED IDEOGRAPH + 0xE08E: 0x71FB, //CJK UNIFIED IDEOGRAPH + 0xE08F: 0x7184, //CJK UNIFIED IDEOGRAPH + 0xE090: 0x7195, //CJK UNIFIED IDEOGRAPH + 0xE091: 0x71A8, //CJK UNIFIED IDEOGRAPH + 0xE092: 0x71AC, //CJK UNIFIED IDEOGRAPH + 0xE093: 0x71D7, //CJK UNIFIED IDEOGRAPH + 0xE094: 0x71B9, //CJK UNIFIED IDEOGRAPH + 0xE095: 0x71BE, //CJK UNIFIED IDEOGRAPH + 0xE096: 0x71D2, //CJK UNIFIED IDEOGRAPH + 0xE097: 0x71C9, //CJK UNIFIED IDEOGRAPH + 0xE098: 0x71D4, //CJK UNIFIED IDEOGRAPH + 0xE099: 0x71CE, //CJK UNIFIED IDEOGRAPH + 0xE09A: 0x71E0, //CJK UNIFIED IDEOGRAPH + 0xE09B: 0x71EC, //CJK UNIFIED IDEOGRAPH + 0xE09C: 0x71E7, //CJK UNIFIED IDEOGRAPH + 0xE09D: 0x71F5, //CJK UNIFIED IDEOGRAPH + 0xE09E: 0x71FC, //CJK UNIFIED IDEOGRAPH + 0xE09F: 0x71F9, //CJK UNIFIED IDEOGRAPH + 0xE0A0: 0x71FF, //CJK UNIFIED IDEOGRAPH + 0xE0A1: 0x720D, //CJK UNIFIED IDEOGRAPH + 0xE0A2: 0x7210, //CJK UNIFIED IDEOGRAPH + 0xE0A3: 0x721B, //CJK UNIFIED IDEOGRAPH + 0xE0A4: 0x7228, //CJK UNIFIED IDEOGRAPH + 0xE0A5: 0x722D, //CJK UNIFIED IDEOGRAPH + 0xE0A6: 0x722C, //CJK UNIFIED IDEOGRAPH + 0xE0A7: 0x7230, //CJK UNIFIED IDEOGRAPH + 0xE0A8: 0x7232, //CJK UNIFIED IDEOGRAPH + 0xE0A9: 0x723B, //CJK UNIFIED IDEOGRAPH + 0xE0AA: 0x723C, //CJK UNIFIED IDEOGRAPH + 0xE0AB: 0x723F, //CJK UNIFIED IDEOGRAPH + 0xE0AC: 0x7240, //CJK UNIFIED IDEOGRAPH + 0xE0AD: 0x7246, //CJK UNIFIED IDEOGRAPH + 0xE0AE: 0x724B, //CJK UNIFIED IDEOGRAPH + 0xE0AF: 0x7258, //CJK UNIFIED IDEOGRAPH + 0xE0B0: 0x7274, //CJK UNIFIED IDEOGRAPH + 0xE0B1: 0x727E, //CJK UNIFIED IDEOGRAPH + 0xE0B2: 0x7282, //CJK UNIFIED IDEOGRAPH + 0xE0B3: 0x7281, //CJK UNIFIED IDEOGRAPH + 0xE0B4: 0x7287, //CJK UNIFIED IDEOGRAPH + 0xE0B5: 0x7292, //CJK UNIFIED IDEOGRAPH + 0xE0B6: 0x7296, //CJK UNIFIED IDEOGRAPH + 0xE0B7: 0x72A2, //CJK UNIFIED IDEOGRAPH + 0xE0B8: 0x72A7, //CJK UNIFIED IDEOGRAPH + 0xE0B9: 0x72B9, //CJK UNIFIED IDEOGRAPH + 0xE0BA: 0x72B2, //CJK UNIFIED IDEOGRAPH + 0xE0BB: 0x72C3, //CJK UNIFIED IDEOGRAPH + 0xE0BC: 0x72C6, //CJK UNIFIED IDEOGRAPH + 0xE0BD: 0x72C4, //CJK UNIFIED IDEOGRAPH + 0xE0BE: 0x72CE, //CJK UNIFIED IDEOGRAPH + 0xE0BF: 0x72D2, //CJK UNIFIED IDEOGRAPH + 0xE0C0: 0x72E2, //CJK UNIFIED IDEOGRAPH + 0xE0C1: 0x72E0, //CJK UNIFIED IDEOGRAPH + 0xE0C2: 0x72E1, //CJK UNIFIED IDEOGRAPH + 0xE0C3: 0x72F9, //CJK UNIFIED IDEOGRAPH + 0xE0C4: 0x72F7, //CJK UNIFIED IDEOGRAPH + 0xE0C5: 0x500F, //CJK UNIFIED IDEOGRAPH + 0xE0C6: 0x7317, //CJK UNIFIED IDEOGRAPH + 0xE0C7: 0x730A, //CJK UNIFIED IDEOGRAPH + 0xE0C8: 0x731C, //CJK UNIFIED IDEOGRAPH + 0xE0C9: 0x7316, //CJK UNIFIED IDEOGRAPH + 0xE0CA: 0x731D, //CJK UNIFIED IDEOGRAPH + 0xE0CB: 0x7334, //CJK UNIFIED IDEOGRAPH + 0xE0CC: 0x732F, //CJK UNIFIED IDEOGRAPH + 0xE0CD: 0x7329, //CJK UNIFIED IDEOGRAPH + 0xE0CE: 0x7325, //CJK UNIFIED IDEOGRAPH + 0xE0CF: 0x733E, //CJK UNIFIED IDEOGRAPH + 0xE0D0: 0x734E, //CJK UNIFIED IDEOGRAPH + 0xE0D1: 0x734F, //CJK UNIFIED IDEOGRAPH + 0xE0D2: 0x9ED8, //CJK UNIFIED IDEOGRAPH + 0xE0D3: 0x7357, //CJK UNIFIED IDEOGRAPH + 0xE0D4: 0x736A, //CJK UNIFIED IDEOGRAPH + 0xE0D5: 0x7368, //CJK UNIFIED IDEOGRAPH + 0xE0D6: 0x7370, //CJK UNIFIED IDEOGRAPH + 0xE0D7: 0x7378, //CJK UNIFIED IDEOGRAPH + 0xE0D8: 0x7375, //CJK UNIFIED IDEOGRAPH + 0xE0D9: 0x737B, //CJK UNIFIED IDEOGRAPH + 0xE0DA: 0x737A, //CJK UNIFIED IDEOGRAPH + 0xE0DB: 0x73C8, //CJK UNIFIED IDEOGRAPH + 0xE0DC: 0x73B3, //CJK UNIFIED IDEOGRAPH + 0xE0DD: 0x73CE, //CJK UNIFIED IDEOGRAPH + 0xE0DE: 0x73BB, //CJK UNIFIED IDEOGRAPH + 0xE0DF: 0x73C0, //CJK UNIFIED IDEOGRAPH + 0xE0E0: 0x73E5, //CJK UNIFIED IDEOGRAPH + 0xE0E1: 0x73EE, //CJK UNIFIED IDEOGRAPH + 0xE0E2: 0x73DE, //CJK UNIFIED IDEOGRAPH + 0xE0E3: 0x74A2, //CJK UNIFIED IDEOGRAPH + 0xE0E4: 0x7405, //CJK UNIFIED IDEOGRAPH + 0xE0E5: 0x746F, //CJK UNIFIED IDEOGRAPH + 0xE0E6: 0x7425, //CJK UNIFIED IDEOGRAPH + 0xE0E7: 0x73F8, //CJK UNIFIED IDEOGRAPH + 0xE0E8: 0x7432, //CJK UNIFIED IDEOGRAPH + 0xE0E9: 0x743A, //CJK UNIFIED IDEOGRAPH + 0xE0EA: 0x7455, //CJK UNIFIED IDEOGRAPH + 0xE0EB: 0x743F, //CJK UNIFIED IDEOGRAPH + 0xE0EC: 0x745F, //CJK UNIFIED IDEOGRAPH + 0xE0ED: 0x7459, //CJK UNIFIED IDEOGRAPH + 0xE0EE: 0x7441, //CJK UNIFIED IDEOGRAPH + 0xE0EF: 0x745C, //CJK UNIFIED IDEOGRAPH + 0xE0F0: 0x7469, //CJK UNIFIED IDEOGRAPH + 0xE0F1: 0x7470, //CJK UNIFIED IDEOGRAPH + 0xE0F2: 0x7463, //CJK UNIFIED IDEOGRAPH + 0xE0F3: 0x746A, //CJK UNIFIED IDEOGRAPH + 0xE0F4: 0x7476, //CJK UNIFIED IDEOGRAPH + 0xE0F5: 0x747E, //CJK UNIFIED IDEOGRAPH + 0xE0F6: 0x748B, //CJK UNIFIED IDEOGRAPH + 0xE0F7: 0x749E, //CJK UNIFIED IDEOGRAPH + 0xE0F8: 0x74A7, //CJK UNIFIED IDEOGRAPH + 0xE0F9: 0x74CA, //CJK UNIFIED IDEOGRAPH + 0xE0FA: 0x74CF, //CJK UNIFIED IDEOGRAPH + 0xE0FB: 0x74D4, //CJK UNIFIED IDEOGRAPH + 0xE0FC: 0x73F1, //CJK UNIFIED IDEOGRAPH + 0xE140: 0x74E0, //CJK UNIFIED IDEOGRAPH + 0xE141: 0x74E3, //CJK UNIFIED IDEOGRAPH + 0xE142: 0x74E7, //CJK UNIFIED IDEOGRAPH + 0xE143: 0x74E9, //CJK UNIFIED IDEOGRAPH + 0xE144: 0x74EE, //CJK UNIFIED IDEOGRAPH + 0xE145: 0x74F2, //CJK UNIFIED IDEOGRAPH + 0xE146: 0x74F0, //CJK UNIFIED IDEOGRAPH + 0xE147: 0x74F1, //CJK UNIFIED IDEOGRAPH + 0xE148: 0x74F8, //CJK UNIFIED IDEOGRAPH + 0xE149: 0x74F7, //CJK UNIFIED IDEOGRAPH + 0xE14A: 0x7504, //CJK UNIFIED IDEOGRAPH + 0xE14B: 0x7503, //CJK UNIFIED IDEOGRAPH + 0xE14C: 0x7505, //CJK UNIFIED IDEOGRAPH + 0xE14D: 0x750C, //CJK UNIFIED IDEOGRAPH + 0xE14E: 0x750E, //CJK UNIFIED IDEOGRAPH + 0xE14F: 0x750D, //CJK UNIFIED IDEOGRAPH + 0xE150: 0x7515, //CJK UNIFIED IDEOGRAPH + 0xE151: 0x7513, //CJK UNIFIED IDEOGRAPH + 0xE152: 0x751E, //CJK UNIFIED IDEOGRAPH + 0xE153: 0x7526, //CJK UNIFIED IDEOGRAPH + 0xE154: 0x752C, //CJK UNIFIED IDEOGRAPH + 0xE155: 0x753C, //CJK UNIFIED IDEOGRAPH + 0xE156: 0x7544, //CJK UNIFIED IDEOGRAPH + 0xE157: 0x754D, //CJK UNIFIED IDEOGRAPH + 0xE158: 0x754A, //CJK UNIFIED IDEOGRAPH + 0xE159: 0x7549, //CJK UNIFIED IDEOGRAPH + 0xE15A: 0x755B, //CJK UNIFIED IDEOGRAPH + 0xE15B: 0x7546, //CJK UNIFIED IDEOGRAPH + 0xE15C: 0x755A, //CJK UNIFIED IDEOGRAPH + 0xE15D: 0x7569, //CJK UNIFIED IDEOGRAPH + 0xE15E: 0x7564, //CJK UNIFIED IDEOGRAPH + 0xE15F: 0x7567, //CJK UNIFIED IDEOGRAPH + 0xE160: 0x756B, //CJK UNIFIED IDEOGRAPH + 0xE161: 0x756D, //CJK UNIFIED IDEOGRAPH + 0xE162: 0x7578, //CJK UNIFIED IDEOGRAPH + 0xE163: 0x7576, //CJK UNIFIED IDEOGRAPH + 0xE164: 0x7586, //CJK UNIFIED IDEOGRAPH + 0xE165: 0x7587, //CJK UNIFIED IDEOGRAPH + 0xE166: 0x7574, //CJK UNIFIED IDEOGRAPH + 0xE167: 0x758A, //CJK UNIFIED IDEOGRAPH + 0xE168: 0x7589, //CJK UNIFIED IDEOGRAPH + 0xE169: 0x7582, //CJK UNIFIED IDEOGRAPH + 0xE16A: 0x7594, //CJK UNIFIED IDEOGRAPH + 0xE16B: 0x759A, //CJK UNIFIED IDEOGRAPH + 0xE16C: 0x759D, //CJK UNIFIED IDEOGRAPH + 0xE16D: 0x75A5, //CJK UNIFIED IDEOGRAPH + 0xE16E: 0x75A3, //CJK UNIFIED IDEOGRAPH + 0xE16F: 0x75C2, //CJK UNIFIED IDEOGRAPH + 0xE170: 0x75B3, //CJK UNIFIED IDEOGRAPH + 0xE171: 0x75C3, //CJK UNIFIED IDEOGRAPH + 0xE172: 0x75B5, //CJK UNIFIED IDEOGRAPH + 0xE173: 0x75BD, //CJK UNIFIED IDEOGRAPH + 0xE174: 0x75B8, //CJK UNIFIED IDEOGRAPH + 0xE175: 0x75BC, //CJK UNIFIED IDEOGRAPH + 0xE176: 0x75B1, //CJK UNIFIED IDEOGRAPH + 0xE177: 0x75CD, //CJK UNIFIED IDEOGRAPH + 0xE178: 0x75CA, //CJK UNIFIED IDEOGRAPH + 0xE179: 0x75D2, //CJK UNIFIED IDEOGRAPH + 0xE17A: 0x75D9, //CJK UNIFIED IDEOGRAPH + 0xE17B: 0x75E3, //CJK UNIFIED IDEOGRAPH + 0xE17C: 0x75DE, //CJK UNIFIED IDEOGRAPH + 0xE17D: 0x75FE, //CJK UNIFIED IDEOGRAPH + 0xE17E: 0x75FF, //CJK UNIFIED IDEOGRAPH + 0xE180: 0x75FC, //CJK UNIFIED IDEOGRAPH + 0xE181: 0x7601, //CJK UNIFIED IDEOGRAPH + 0xE182: 0x75F0, //CJK UNIFIED IDEOGRAPH + 0xE183: 0x75FA, //CJK UNIFIED IDEOGRAPH + 0xE184: 0x75F2, //CJK UNIFIED IDEOGRAPH + 0xE185: 0x75F3, //CJK UNIFIED IDEOGRAPH + 0xE186: 0x760B, //CJK UNIFIED IDEOGRAPH + 0xE187: 0x760D, //CJK UNIFIED IDEOGRAPH + 0xE188: 0x7609, //CJK UNIFIED IDEOGRAPH + 0xE189: 0x761F, //CJK UNIFIED IDEOGRAPH + 0xE18A: 0x7627, //CJK UNIFIED IDEOGRAPH + 0xE18B: 0x7620, //CJK UNIFIED IDEOGRAPH + 0xE18C: 0x7621, //CJK UNIFIED IDEOGRAPH + 0xE18D: 0x7622, //CJK UNIFIED IDEOGRAPH + 0xE18E: 0x7624, //CJK UNIFIED IDEOGRAPH + 0xE18F: 0x7634, //CJK UNIFIED IDEOGRAPH + 0xE190: 0x7630, //CJK UNIFIED IDEOGRAPH + 0xE191: 0x763B, //CJK UNIFIED IDEOGRAPH + 0xE192: 0x7647, //CJK UNIFIED IDEOGRAPH + 0xE193: 0x7648, //CJK UNIFIED IDEOGRAPH + 0xE194: 0x7646, //CJK UNIFIED IDEOGRAPH + 0xE195: 0x765C, //CJK UNIFIED IDEOGRAPH + 0xE196: 0x7658, //CJK UNIFIED IDEOGRAPH + 0xE197: 0x7661, //CJK UNIFIED IDEOGRAPH + 0xE198: 0x7662, //CJK UNIFIED IDEOGRAPH + 0xE199: 0x7668, //CJK UNIFIED IDEOGRAPH + 0xE19A: 0x7669, //CJK UNIFIED IDEOGRAPH + 0xE19B: 0x766A, //CJK UNIFIED IDEOGRAPH + 0xE19C: 0x7667, //CJK UNIFIED IDEOGRAPH + 0xE19D: 0x766C, //CJK UNIFIED IDEOGRAPH + 0xE19E: 0x7670, //CJK UNIFIED IDEOGRAPH + 0xE19F: 0x7672, //CJK UNIFIED IDEOGRAPH + 0xE1A0: 0x7676, //CJK UNIFIED IDEOGRAPH + 0xE1A1: 0x7678, //CJK UNIFIED IDEOGRAPH + 0xE1A2: 0x767C, //CJK UNIFIED IDEOGRAPH + 0xE1A3: 0x7680, //CJK UNIFIED IDEOGRAPH + 0xE1A4: 0x7683, //CJK UNIFIED IDEOGRAPH + 0xE1A5: 0x7688, //CJK UNIFIED IDEOGRAPH + 0xE1A6: 0x768B, //CJK UNIFIED IDEOGRAPH + 0xE1A7: 0x768E, //CJK UNIFIED IDEOGRAPH + 0xE1A8: 0x7696, //CJK UNIFIED IDEOGRAPH + 0xE1A9: 0x7693, //CJK UNIFIED IDEOGRAPH + 0xE1AA: 0x7699, //CJK UNIFIED IDEOGRAPH + 0xE1AB: 0x769A, //CJK UNIFIED IDEOGRAPH + 0xE1AC: 0x76B0, //CJK UNIFIED IDEOGRAPH + 0xE1AD: 0x76B4, //CJK UNIFIED IDEOGRAPH + 0xE1AE: 0x76B8, //CJK UNIFIED IDEOGRAPH + 0xE1AF: 0x76B9, //CJK UNIFIED IDEOGRAPH + 0xE1B0: 0x76BA, //CJK UNIFIED IDEOGRAPH + 0xE1B1: 0x76C2, //CJK UNIFIED IDEOGRAPH + 0xE1B2: 0x76CD, //CJK UNIFIED IDEOGRAPH + 0xE1B3: 0x76D6, //CJK UNIFIED IDEOGRAPH + 0xE1B4: 0x76D2, //CJK UNIFIED IDEOGRAPH + 0xE1B5: 0x76DE, //CJK UNIFIED IDEOGRAPH + 0xE1B6: 0x76E1, //CJK UNIFIED IDEOGRAPH + 0xE1B7: 0x76E5, //CJK UNIFIED IDEOGRAPH + 0xE1B8: 0x76E7, //CJK UNIFIED IDEOGRAPH + 0xE1B9: 0x76EA, //CJK UNIFIED IDEOGRAPH + 0xE1BA: 0x862F, //CJK UNIFIED IDEOGRAPH + 0xE1BB: 0x76FB, //CJK UNIFIED IDEOGRAPH + 0xE1BC: 0x7708, //CJK UNIFIED IDEOGRAPH + 0xE1BD: 0x7707, //CJK UNIFIED IDEOGRAPH + 0xE1BE: 0x7704, //CJK UNIFIED IDEOGRAPH + 0xE1BF: 0x7729, //CJK UNIFIED IDEOGRAPH + 0xE1C0: 0x7724, //CJK UNIFIED IDEOGRAPH + 0xE1C1: 0x771E, //CJK UNIFIED IDEOGRAPH + 0xE1C2: 0x7725, //CJK UNIFIED IDEOGRAPH + 0xE1C3: 0x7726, //CJK UNIFIED IDEOGRAPH + 0xE1C4: 0x771B, //CJK UNIFIED IDEOGRAPH + 0xE1C5: 0x7737, //CJK UNIFIED IDEOGRAPH + 0xE1C6: 0x7738, //CJK UNIFIED IDEOGRAPH + 0xE1C7: 0x7747, //CJK UNIFIED IDEOGRAPH + 0xE1C8: 0x775A, //CJK UNIFIED IDEOGRAPH + 0xE1C9: 0x7768, //CJK UNIFIED IDEOGRAPH + 0xE1CA: 0x776B, //CJK UNIFIED IDEOGRAPH + 0xE1CB: 0x775B, //CJK UNIFIED IDEOGRAPH + 0xE1CC: 0x7765, //CJK UNIFIED IDEOGRAPH + 0xE1CD: 0x777F, //CJK UNIFIED IDEOGRAPH + 0xE1CE: 0x777E, //CJK UNIFIED IDEOGRAPH + 0xE1CF: 0x7779, //CJK UNIFIED IDEOGRAPH + 0xE1D0: 0x778E, //CJK UNIFIED IDEOGRAPH + 0xE1D1: 0x778B, //CJK UNIFIED IDEOGRAPH + 0xE1D2: 0x7791, //CJK UNIFIED IDEOGRAPH + 0xE1D3: 0x77A0, //CJK UNIFIED IDEOGRAPH + 0xE1D4: 0x779E, //CJK UNIFIED IDEOGRAPH + 0xE1D5: 0x77B0, //CJK UNIFIED IDEOGRAPH + 0xE1D6: 0x77B6, //CJK UNIFIED IDEOGRAPH + 0xE1D7: 0x77B9, //CJK UNIFIED IDEOGRAPH + 0xE1D8: 0x77BF, //CJK UNIFIED IDEOGRAPH + 0xE1D9: 0x77BC, //CJK UNIFIED IDEOGRAPH + 0xE1DA: 0x77BD, //CJK UNIFIED IDEOGRAPH + 0xE1DB: 0x77BB, //CJK UNIFIED IDEOGRAPH + 0xE1DC: 0x77C7, //CJK UNIFIED IDEOGRAPH + 0xE1DD: 0x77CD, //CJK UNIFIED IDEOGRAPH + 0xE1DE: 0x77D7, //CJK UNIFIED IDEOGRAPH + 0xE1DF: 0x77DA, //CJK UNIFIED IDEOGRAPH + 0xE1E0: 0x77DC, //CJK UNIFIED IDEOGRAPH + 0xE1E1: 0x77E3, //CJK UNIFIED IDEOGRAPH + 0xE1E2: 0x77EE, //CJK UNIFIED IDEOGRAPH + 0xE1E3: 0x77FC, //CJK UNIFIED IDEOGRAPH + 0xE1E4: 0x780C, //CJK UNIFIED IDEOGRAPH + 0xE1E5: 0x7812, //CJK UNIFIED IDEOGRAPH + 0xE1E6: 0x7926, //CJK UNIFIED IDEOGRAPH + 0xE1E7: 0x7820, //CJK UNIFIED IDEOGRAPH + 0xE1E8: 0x792A, //CJK UNIFIED IDEOGRAPH + 0xE1E9: 0x7845, //CJK UNIFIED IDEOGRAPH + 0xE1EA: 0x788E, //CJK UNIFIED IDEOGRAPH + 0xE1EB: 0x7874, //CJK UNIFIED IDEOGRAPH + 0xE1EC: 0x7886, //CJK UNIFIED IDEOGRAPH + 0xE1ED: 0x787C, //CJK UNIFIED IDEOGRAPH + 0xE1EE: 0x789A, //CJK UNIFIED IDEOGRAPH + 0xE1EF: 0x788C, //CJK UNIFIED IDEOGRAPH + 0xE1F0: 0x78A3, //CJK UNIFIED IDEOGRAPH + 0xE1F1: 0x78B5, //CJK UNIFIED IDEOGRAPH + 0xE1F2: 0x78AA, //CJK UNIFIED IDEOGRAPH + 0xE1F3: 0x78AF, //CJK UNIFIED IDEOGRAPH + 0xE1F4: 0x78D1, //CJK UNIFIED IDEOGRAPH + 0xE1F5: 0x78C6, //CJK UNIFIED IDEOGRAPH + 0xE1F6: 0x78CB, //CJK UNIFIED IDEOGRAPH + 0xE1F7: 0x78D4, //CJK UNIFIED IDEOGRAPH + 0xE1F8: 0x78BE, //CJK UNIFIED IDEOGRAPH + 0xE1F9: 0x78BC, //CJK UNIFIED IDEOGRAPH + 0xE1FA: 0x78C5, //CJK UNIFIED IDEOGRAPH + 0xE1FB: 0x78CA, //CJK UNIFIED IDEOGRAPH + 0xE1FC: 0x78EC, //CJK UNIFIED IDEOGRAPH + 0xE240: 0x78E7, //CJK UNIFIED IDEOGRAPH + 0xE241: 0x78DA, //CJK UNIFIED IDEOGRAPH + 0xE242: 0x78FD, //CJK UNIFIED IDEOGRAPH + 0xE243: 0x78F4, //CJK UNIFIED IDEOGRAPH + 0xE244: 0x7907, //CJK UNIFIED IDEOGRAPH + 0xE245: 0x7912, //CJK UNIFIED IDEOGRAPH + 0xE246: 0x7911, //CJK UNIFIED IDEOGRAPH + 0xE247: 0x7919, //CJK UNIFIED IDEOGRAPH + 0xE248: 0x792C, //CJK UNIFIED IDEOGRAPH + 0xE249: 0x792B, //CJK UNIFIED IDEOGRAPH + 0xE24A: 0x7940, //CJK UNIFIED IDEOGRAPH + 0xE24B: 0x7960, //CJK UNIFIED IDEOGRAPH + 0xE24C: 0x7957, //CJK UNIFIED IDEOGRAPH + 0xE24D: 0x795F, //CJK UNIFIED IDEOGRAPH + 0xE24E: 0x795A, //CJK UNIFIED IDEOGRAPH + 0xE24F: 0x7955, //CJK UNIFIED IDEOGRAPH + 0xE250: 0x7953, //CJK UNIFIED IDEOGRAPH + 0xE251: 0x797A, //CJK UNIFIED IDEOGRAPH + 0xE252: 0x797F, //CJK UNIFIED IDEOGRAPH + 0xE253: 0x798A, //CJK UNIFIED IDEOGRAPH + 0xE254: 0x799D, //CJK UNIFIED IDEOGRAPH + 0xE255: 0x79A7, //CJK UNIFIED IDEOGRAPH + 0xE256: 0x9F4B, //CJK UNIFIED IDEOGRAPH + 0xE257: 0x79AA, //CJK UNIFIED IDEOGRAPH + 0xE258: 0x79AE, //CJK UNIFIED IDEOGRAPH + 0xE259: 0x79B3, //CJK UNIFIED IDEOGRAPH + 0xE25A: 0x79B9, //CJK UNIFIED IDEOGRAPH + 0xE25B: 0x79BA, //CJK UNIFIED IDEOGRAPH + 0xE25C: 0x79C9, //CJK UNIFIED IDEOGRAPH + 0xE25D: 0x79D5, //CJK UNIFIED IDEOGRAPH + 0xE25E: 0x79E7, //CJK UNIFIED IDEOGRAPH + 0xE25F: 0x79EC, //CJK UNIFIED IDEOGRAPH + 0xE260: 0x79E1, //CJK UNIFIED IDEOGRAPH + 0xE261: 0x79E3, //CJK UNIFIED IDEOGRAPH + 0xE262: 0x7A08, //CJK UNIFIED IDEOGRAPH + 0xE263: 0x7A0D, //CJK UNIFIED IDEOGRAPH + 0xE264: 0x7A18, //CJK UNIFIED IDEOGRAPH + 0xE265: 0x7A19, //CJK UNIFIED IDEOGRAPH + 0xE266: 0x7A20, //CJK UNIFIED IDEOGRAPH + 0xE267: 0x7A1F, //CJK UNIFIED IDEOGRAPH + 0xE268: 0x7980, //CJK UNIFIED IDEOGRAPH + 0xE269: 0x7A31, //CJK UNIFIED IDEOGRAPH + 0xE26A: 0x7A3B, //CJK UNIFIED IDEOGRAPH + 0xE26B: 0x7A3E, //CJK UNIFIED IDEOGRAPH + 0xE26C: 0x7A37, //CJK UNIFIED IDEOGRAPH + 0xE26D: 0x7A43, //CJK UNIFIED IDEOGRAPH + 0xE26E: 0x7A57, //CJK UNIFIED IDEOGRAPH + 0xE26F: 0x7A49, //CJK UNIFIED IDEOGRAPH + 0xE270: 0x7A61, //CJK UNIFIED IDEOGRAPH + 0xE271: 0x7A62, //CJK UNIFIED IDEOGRAPH + 0xE272: 0x7A69, //CJK UNIFIED IDEOGRAPH + 0xE273: 0x9F9D, //CJK UNIFIED IDEOGRAPH + 0xE274: 0x7A70, //CJK UNIFIED IDEOGRAPH + 0xE275: 0x7A79, //CJK UNIFIED IDEOGRAPH + 0xE276: 0x7A7D, //CJK UNIFIED IDEOGRAPH + 0xE277: 0x7A88, //CJK UNIFIED IDEOGRAPH + 0xE278: 0x7A97, //CJK UNIFIED IDEOGRAPH + 0xE279: 0x7A95, //CJK UNIFIED IDEOGRAPH + 0xE27A: 0x7A98, //CJK UNIFIED IDEOGRAPH + 0xE27B: 0x7A96, //CJK UNIFIED IDEOGRAPH + 0xE27C: 0x7AA9, //CJK UNIFIED IDEOGRAPH + 0xE27D: 0x7AC8, //CJK UNIFIED IDEOGRAPH + 0xE27E: 0x7AB0, //CJK UNIFIED IDEOGRAPH + 0xE280: 0x7AB6, //CJK UNIFIED IDEOGRAPH + 0xE281: 0x7AC5, //CJK UNIFIED IDEOGRAPH + 0xE282: 0x7AC4, //CJK UNIFIED IDEOGRAPH + 0xE283: 0x7ABF, //CJK UNIFIED IDEOGRAPH + 0xE284: 0x9083, //CJK UNIFIED IDEOGRAPH + 0xE285: 0x7AC7, //CJK UNIFIED IDEOGRAPH + 0xE286: 0x7ACA, //CJK UNIFIED IDEOGRAPH + 0xE287: 0x7ACD, //CJK UNIFIED IDEOGRAPH + 0xE288: 0x7ACF, //CJK UNIFIED IDEOGRAPH + 0xE289: 0x7AD5, //CJK UNIFIED IDEOGRAPH + 0xE28A: 0x7AD3, //CJK UNIFIED IDEOGRAPH + 0xE28B: 0x7AD9, //CJK UNIFIED IDEOGRAPH + 0xE28C: 0x7ADA, //CJK UNIFIED IDEOGRAPH + 0xE28D: 0x7ADD, //CJK UNIFIED IDEOGRAPH + 0xE28E: 0x7AE1, //CJK UNIFIED IDEOGRAPH + 0xE28F: 0x7AE2, //CJK UNIFIED IDEOGRAPH + 0xE290: 0x7AE6, //CJK UNIFIED IDEOGRAPH + 0xE291: 0x7AED, //CJK UNIFIED IDEOGRAPH + 0xE292: 0x7AF0, //CJK UNIFIED IDEOGRAPH + 0xE293: 0x7B02, //CJK UNIFIED IDEOGRAPH + 0xE294: 0x7B0F, //CJK UNIFIED IDEOGRAPH + 0xE295: 0x7B0A, //CJK UNIFIED IDEOGRAPH + 0xE296: 0x7B06, //CJK UNIFIED IDEOGRAPH + 0xE297: 0x7B33, //CJK UNIFIED IDEOGRAPH + 0xE298: 0x7B18, //CJK UNIFIED IDEOGRAPH + 0xE299: 0x7B19, //CJK UNIFIED IDEOGRAPH + 0xE29A: 0x7B1E, //CJK UNIFIED IDEOGRAPH + 0xE29B: 0x7B35, //CJK UNIFIED IDEOGRAPH + 0xE29C: 0x7B28, //CJK UNIFIED IDEOGRAPH + 0xE29D: 0x7B36, //CJK UNIFIED IDEOGRAPH + 0xE29E: 0x7B50, //CJK UNIFIED IDEOGRAPH + 0xE29F: 0x7B7A, //CJK UNIFIED IDEOGRAPH + 0xE2A0: 0x7B04, //CJK UNIFIED IDEOGRAPH + 0xE2A1: 0x7B4D, //CJK UNIFIED IDEOGRAPH + 0xE2A2: 0x7B0B, //CJK UNIFIED IDEOGRAPH + 0xE2A3: 0x7B4C, //CJK UNIFIED IDEOGRAPH + 0xE2A4: 0x7B45, //CJK UNIFIED IDEOGRAPH + 0xE2A5: 0x7B75, //CJK UNIFIED IDEOGRAPH + 0xE2A6: 0x7B65, //CJK UNIFIED IDEOGRAPH + 0xE2A7: 0x7B74, //CJK UNIFIED IDEOGRAPH + 0xE2A8: 0x7B67, //CJK UNIFIED IDEOGRAPH + 0xE2A9: 0x7B70, //CJK UNIFIED IDEOGRAPH + 0xE2AA: 0x7B71, //CJK UNIFIED IDEOGRAPH + 0xE2AB: 0x7B6C, //CJK UNIFIED IDEOGRAPH + 0xE2AC: 0x7B6E, //CJK UNIFIED IDEOGRAPH + 0xE2AD: 0x7B9D, //CJK UNIFIED IDEOGRAPH + 0xE2AE: 0x7B98, //CJK UNIFIED IDEOGRAPH + 0xE2AF: 0x7B9F, //CJK UNIFIED IDEOGRAPH + 0xE2B0: 0x7B8D, //CJK UNIFIED IDEOGRAPH + 0xE2B1: 0x7B9C, //CJK UNIFIED IDEOGRAPH + 0xE2B2: 0x7B9A, //CJK UNIFIED IDEOGRAPH + 0xE2B3: 0x7B8B, //CJK UNIFIED IDEOGRAPH + 0xE2B4: 0x7B92, //CJK UNIFIED IDEOGRAPH + 0xE2B5: 0x7B8F, //CJK UNIFIED IDEOGRAPH + 0xE2B6: 0x7B5D, //CJK UNIFIED IDEOGRAPH + 0xE2B7: 0x7B99, //CJK UNIFIED IDEOGRAPH + 0xE2B8: 0x7BCB, //CJK UNIFIED IDEOGRAPH + 0xE2B9: 0x7BC1, //CJK UNIFIED IDEOGRAPH + 0xE2BA: 0x7BCC, //CJK UNIFIED IDEOGRAPH + 0xE2BB: 0x7BCF, //CJK UNIFIED IDEOGRAPH + 0xE2BC: 0x7BB4, //CJK UNIFIED IDEOGRAPH + 0xE2BD: 0x7BC6, //CJK UNIFIED IDEOGRAPH + 0xE2BE: 0x7BDD, //CJK UNIFIED IDEOGRAPH + 0xE2BF: 0x7BE9, //CJK UNIFIED IDEOGRAPH + 0xE2C0: 0x7C11, //CJK UNIFIED IDEOGRAPH + 0xE2C1: 0x7C14, //CJK UNIFIED IDEOGRAPH + 0xE2C2: 0x7BE6, //CJK UNIFIED IDEOGRAPH + 0xE2C3: 0x7BE5, //CJK UNIFIED IDEOGRAPH + 0xE2C4: 0x7C60, //CJK UNIFIED IDEOGRAPH + 0xE2C5: 0x7C00, //CJK UNIFIED IDEOGRAPH + 0xE2C6: 0x7C07, //CJK UNIFIED IDEOGRAPH + 0xE2C7: 0x7C13, //CJK UNIFIED IDEOGRAPH + 0xE2C8: 0x7BF3, //CJK UNIFIED IDEOGRAPH + 0xE2C9: 0x7BF7, //CJK UNIFIED IDEOGRAPH + 0xE2CA: 0x7C17, //CJK UNIFIED IDEOGRAPH + 0xE2CB: 0x7C0D, //CJK UNIFIED IDEOGRAPH + 0xE2CC: 0x7BF6, //CJK UNIFIED IDEOGRAPH + 0xE2CD: 0x7C23, //CJK UNIFIED IDEOGRAPH + 0xE2CE: 0x7C27, //CJK UNIFIED IDEOGRAPH + 0xE2CF: 0x7C2A, //CJK UNIFIED IDEOGRAPH + 0xE2D0: 0x7C1F, //CJK UNIFIED IDEOGRAPH + 0xE2D1: 0x7C37, //CJK UNIFIED IDEOGRAPH + 0xE2D2: 0x7C2B, //CJK UNIFIED IDEOGRAPH + 0xE2D3: 0x7C3D, //CJK UNIFIED IDEOGRAPH + 0xE2D4: 0x7C4C, //CJK UNIFIED IDEOGRAPH + 0xE2D5: 0x7C43, //CJK UNIFIED IDEOGRAPH + 0xE2D6: 0x7C54, //CJK UNIFIED IDEOGRAPH + 0xE2D7: 0x7C4F, //CJK UNIFIED IDEOGRAPH + 0xE2D8: 0x7C40, //CJK UNIFIED IDEOGRAPH + 0xE2D9: 0x7C50, //CJK UNIFIED IDEOGRAPH + 0xE2DA: 0x7C58, //CJK UNIFIED IDEOGRAPH + 0xE2DB: 0x7C5F, //CJK UNIFIED IDEOGRAPH + 0xE2DC: 0x7C64, //CJK UNIFIED IDEOGRAPH + 0xE2DD: 0x7C56, //CJK UNIFIED IDEOGRAPH + 0xE2DE: 0x7C65, //CJK UNIFIED IDEOGRAPH + 0xE2DF: 0x7C6C, //CJK UNIFIED IDEOGRAPH + 0xE2E0: 0x7C75, //CJK UNIFIED IDEOGRAPH + 0xE2E1: 0x7C83, //CJK UNIFIED IDEOGRAPH + 0xE2E2: 0x7C90, //CJK UNIFIED IDEOGRAPH + 0xE2E3: 0x7CA4, //CJK UNIFIED IDEOGRAPH + 0xE2E4: 0x7CAD, //CJK UNIFIED IDEOGRAPH + 0xE2E5: 0x7CA2, //CJK UNIFIED IDEOGRAPH + 0xE2E6: 0x7CAB, //CJK UNIFIED IDEOGRAPH + 0xE2E7: 0x7CA1, //CJK UNIFIED IDEOGRAPH + 0xE2E8: 0x7CA8, //CJK UNIFIED IDEOGRAPH + 0xE2E9: 0x7CB3, //CJK UNIFIED IDEOGRAPH + 0xE2EA: 0x7CB2, //CJK UNIFIED IDEOGRAPH + 0xE2EB: 0x7CB1, //CJK UNIFIED IDEOGRAPH + 0xE2EC: 0x7CAE, //CJK UNIFIED IDEOGRAPH + 0xE2ED: 0x7CB9, //CJK UNIFIED IDEOGRAPH + 0xE2EE: 0x7CBD, //CJK UNIFIED IDEOGRAPH + 0xE2EF: 0x7CC0, //CJK UNIFIED IDEOGRAPH + 0xE2F0: 0x7CC5, //CJK UNIFIED IDEOGRAPH + 0xE2F1: 0x7CC2, //CJK UNIFIED IDEOGRAPH + 0xE2F2: 0x7CD8, //CJK UNIFIED IDEOGRAPH + 0xE2F3: 0x7CD2, //CJK UNIFIED IDEOGRAPH + 0xE2F4: 0x7CDC, //CJK UNIFIED IDEOGRAPH + 0xE2F5: 0x7CE2, //CJK UNIFIED IDEOGRAPH + 0xE2F6: 0x9B3B, //CJK UNIFIED IDEOGRAPH + 0xE2F7: 0x7CEF, //CJK UNIFIED IDEOGRAPH + 0xE2F8: 0x7CF2, //CJK UNIFIED IDEOGRAPH + 0xE2F9: 0x7CF4, //CJK UNIFIED IDEOGRAPH + 0xE2FA: 0x7CF6, //CJK UNIFIED IDEOGRAPH + 0xE2FB: 0x7CFA, //CJK UNIFIED IDEOGRAPH + 0xE2FC: 0x7D06, //CJK UNIFIED IDEOGRAPH + 0xE340: 0x7D02, //CJK UNIFIED IDEOGRAPH + 0xE341: 0x7D1C, //CJK UNIFIED IDEOGRAPH + 0xE342: 0x7D15, //CJK UNIFIED IDEOGRAPH + 0xE343: 0x7D0A, //CJK UNIFIED IDEOGRAPH + 0xE344: 0x7D45, //CJK UNIFIED IDEOGRAPH + 0xE345: 0x7D4B, //CJK UNIFIED IDEOGRAPH + 0xE346: 0x7D2E, //CJK UNIFIED IDEOGRAPH + 0xE347: 0x7D32, //CJK UNIFIED IDEOGRAPH + 0xE348: 0x7D3F, //CJK UNIFIED IDEOGRAPH + 0xE349: 0x7D35, //CJK UNIFIED IDEOGRAPH + 0xE34A: 0x7D46, //CJK UNIFIED IDEOGRAPH + 0xE34B: 0x7D73, //CJK UNIFIED IDEOGRAPH + 0xE34C: 0x7D56, //CJK UNIFIED IDEOGRAPH + 0xE34D: 0x7D4E, //CJK UNIFIED IDEOGRAPH + 0xE34E: 0x7D72, //CJK UNIFIED IDEOGRAPH + 0xE34F: 0x7D68, //CJK UNIFIED IDEOGRAPH + 0xE350: 0x7D6E, //CJK UNIFIED IDEOGRAPH + 0xE351: 0x7D4F, //CJK UNIFIED IDEOGRAPH + 0xE352: 0x7D63, //CJK UNIFIED IDEOGRAPH + 0xE353: 0x7D93, //CJK UNIFIED IDEOGRAPH + 0xE354: 0x7D89, //CJK UNIFIED IDEOGRAPH + 0xE355: 0x7D5B, //CJK UNIFIED IDEOGRAPH + 0xE356: 0x7D8F, //CJK UNIFIED IDEOGRAPH + 0xE357: 0x7D7D, //CJK UNIFIED IDEOGRAPH + 0xE358: 0x7D9B, //CJK UNIFIED IDEOGRAPH + 0xE359: 0x7DBA, //CJK UNIFIED IDEOGRAPH + 0xE35A: 0x7DAE, //CJK UNIFIED IDEOGRAPH + 0xE35B: 0x7DA3, //CJK UNIFIED IDEOGRAPH + 0xE35C: 0x7DB5, //CJK UNIFIED IDEOGRAPH + 0xE35D: 0x7DC7, //CJK UNIFIED IDEOGRAPH + 0xE35E: 0x7DBD, //CJK UNIFIED IDEOGRAPH + 0xE35F: 0x7DAB, //CJK UNIFIED IDEOGRAPH + 0xE360: 0x7E3D, //CJK UNIFIED IDEOGRAPH + 0xE361: 0x7DA2, //CJK UNIFIED IDEOGRAPH + 0xE362: 0x7DAF, //CJK UNIFIED IDEOGRAPH + 0xE363: 0x7DDC, //CJK UNIFIED IDEOGRAPH + 0xE364: 0x7DB8, //CJK UNIFIED IDEOGRAPH + 0xE365: 0x7D9F, //CJK UNIFIED IDEOGRAPH + 0xE366: 0x7DB0, //CJK UNIFIED IDEOGRAPH + 0xE367: 0x7DD8, //CJK UNIFIED IDEOGRAPH + 0xE368: 0x7DDD, //CJK UNIFIED IDEOGRAPH + 0xE369: 0x7DE4, //CJK UNIFIED IDEOGRAPH + 0xE36A: 0x7DDE, //CJK UNIFIED IDEOGRAPH + 0xE36B: 0x7DFB, //CJK UNIFIED IDEOGRAPH + 0xE36C: 0x7DF2, //CJK UNIFIED IDEOGRAPH + 0xE36D: 0x7DE1, //CJK UNIFIED IDEOGRAPH + 0xE36E: 0x7E05, //CJK UNIFIED IDEOGRAPH + 0xE36F: 0x7E0A, //CJK UNIFIED IDEOGRAPH + 0xE370: 0x7E23, //CJK UNIFIED IDEOGRAPH + 0xE371: 0x7E21, //CJK UNIFIED IDEOGRAPH + 0xE372: 0x7E12, //CJK UNIFIED IDEOGRAPH + 0xE373: 0x7E31, //CJK UNIFIED IDEOGRAPH + 0xE374: 0x7E1F, //CJK UNIFIED IDEOGRAPH + 0xE375: 0x7E09, //CJK UNIFIED IDEOGRAPH + 0xE376: 0x7E0B, //CJK UNIFIED IDEOGRAPH + 0xE377: 0x7E22, //CJK UNIFIED IDEOGRAPH + 0xE378: 0x7E46, //CJK UNIFIED IDEOGRAPH + 0xE379: 0x7E66, //CJK UNIFIED IDEOGRAPH + 0xE37A: 0x7E3B, //CJK UNIFIED IDEOGRAPH + 0xE37B: 0x7E35, //CJK UNIFIED IDEOGRAPH + 0xE37C: 0x7E39, //CJK UNIFIED IDEOGRAPH + 0xE37D: 0x7E43, //CJK UNIFIED IDEOGRAPH + 0xE37E: 0x7E37, //CJK UNIFIED IDEOGRAPH + 0xE380: 0x7E32, //CJK UNIFIED IDEOGRAPH + 0xE381: 0x7E3A, //CJK UNIFIED IDEOGRAPH + 0xE382: 0x7E67, //CJK UNIFIED IDEOGRAPH + 0xE383: 0x7E5D, //CJK UNIFIED IDEOGRAPH + 0xE384: 0x7E56, //CJK UNIFIED IDEOGRAPH + 0xE385: 0x7E5E, //CJK UNIFIED IDEOGRAPH + 0xE386: 0x7E59, //CJK UNIFIED IDEOGRAPH + 0xE387: 0x7E5A, //CJK UNIFIED IDEOGRAPH + 0xE388: 0x7E79, //CJK UNIFIED IDEOGRAPH + 0xE389: 0x7E6A, //CJK UNIFIED IDEOGRAPH + 0xE38A: 0x7E69, //CJK UNIFIED IDEOGRAPH + 0xE38B: 0x7E7C, //CJK UNIFIED IDEOGRAPH + 0xE38C: 0x7E7B, //CJK UNIFIED IDEOGRAPH + 0xE38D: 0x7E83, //CJK UNIFIED IDEOGRAPH + 0xE38E: 0x7DD5, //CJK UNIFIED IDEOGRAPH + 0xE38F: 0x7E7D, //CJK UNIFIED IDEOGRAPH + 0xE390: 0x8FAE, //CJK UNIFIED IDEOGRAPH + 0xE391: 0x7E7F, //CJK UNIFIED IDEOGRAPH + 0xE392: 0x7E88, //CJK UNIFIED IDEOGRAPH + 0xE393: 0x7E89, //CJK UNIFIED IDEOGRAPH + 0xE394: 0x7E8C, //CJK UNIFIED IDEOGRAPH + 0xE395: 0x7E92, //CJK UNIFIED IDEOGRAPH + 0xE396: 0x7E90, //CJK UNIFIED IDEOGRAPH + 0xE397: 0x7E93, //CJK UNIFIED IDEOGRAPH + 0xE398: 0x7E94, //CJK UNIFIED IDEOGRAPH + 0xE399: 0x7E96, //CJK UNIFIED IDEOGRAPH + 0xE39A: 0x7E8E, //CJK UNIFIED IDEOGRAPH + 0xE39B: 0x7E9B, //CJK UNIFIED IDEOGRAPH + 0xE39C: 0x7E9C, //CJK UNIFIED IDEOGRAPH + 0xE39D: 0x7F38, //CJK UNIFIED IDEOGRAPH + 0xE39E: 0x7F3A, //CJK UNIFIED IDEOGRAPH + 0xE39F: 0x7F45, //CJK UNIFIED IDEOGRAPH + 0xE3A0: 0x7F4C, //CJK UNIFIED IDEOGRAPH + 0xE3A1: 0x7F4D, //CJK UNIFIED IDEOGRAPH + 0xE3A2: 0x7F4E, //CJK UNIFIED IDEOGRAPH + 0xE3A3: 0x7F50, //CJK UNIFIED IDEOGRAPH + 0xE3A4: 0x7F51, //CJK UNIFIED IDEOGRAPH + 0xE3A5: 0x7F55, //CJK UNIFIED IDEOGRAPH + 0xE3A6: 0x7F54, //CJK UNIFIED IDEOGRAPH + 0xE3A7: 0x7F58, //CJK UNIFIED IDEOGRAPH + 0xE3A8: 0x7F5F, //CJK UNIFIED IDEOGRAPH + 0xE3A9: 0x7F60, //CJK UNIFIED IDEOGRAPH + 0xE3AA: 0x7F68, //CJK UNIFIED IDEOGRAPH + 0xE3AB: 0x7F69, //CJK UNIFIED IDEOGRAPH + 0xE3AC: 0x7F67, //CJK UNIFIED IDEOGRAPH + 0xE3AD: 0x7F78, //CJK UNIFIED IDEOGRAPH + 0xE3AE: 0x7F82, //CJK UNIFIED IDEOGRAPH + 0xE3AF: 0x7F86, //CJK UNIFIED IDEOGRAPH + 0xE3B0: 0x7F83, //CJK UNIFIED IDEOGRAPH + 0xE3B1: 0x7F88, //CJK UNIFIED IDEOGRAPH + 0xE3B2: 0x7F87, //CJK UNIFIED IDEOGRAPH + 0xE3B3: 0x7F8C, //CJK UNIFIED IDEOGRAPH + 0xE3B4: 0x7F94, //CJK UNIFIED IDEOGRAPH + 0xE3B5: 0x7F9E, //CJK UNIFIED IDEOGRAPH + 0xE3B6: 0x7F9D, //CJK UNIFIED IDEOGRAPH + 0xE3B7: 0x7F9A, //CJK UNIFIED IDEOGRAPH + 0xE3B8: 0x7FA3, //CJK UNIFIED IDEOGRAPH + 0xE3B9: 0x7FAF, //CJK UNIFIED IDEOGRAPH + 0xE3BA: 0x7FB2, //CJK UNIFIED IDEOGRAPH + 0xE3BB: 0x7FB9, //CJK UNIFIED IDEOGRAPH + 0xE3BC: 0x7FAE, //CJK UNIFIED IDEOGRAPH + 0xE3BD: 0x7FB6, //CJK UNIFIED IDEOGRAPH + 0xE3BE: 0x7FB8, //CJK UNIFIED IDEOGRAPH + 0xE3BF: 0x8B71, //CJK UNIFIED IDEOGRAPH + 0xE3C0: 0x7FC5, //CJK UNIFIED IDEOGRAPH + 0xE3C1: 0x7FC6, //CJK UNIFIED IDEOGRAPH + 0xE3C2: 0x7FCA, //CJK UNIFIED IDEOGRAPH + 0xE3C3: 0x7FD5, //CJK UNIFIED IDEOGRAPH + 0xE3C4: 0x7FD4, //CJK UNIFIED IDEOGRAPH + 0xE3C5: 0x7FE1, //CJK UNIFIED IDEOGRAPH + 0xE3C6: 0x7FE6, //CJK UNIFIED IDEOGRAPH + 0xE3C7: 0x7FE9, //CJK UNIFIED IDEOGRAPH + 0xE3C8: 0x7FF3, //CJK UNIFIED IDEOGRAPH + 0xE3C9: 0x7FF9, //CJK UNIFIED IDEOGRAPH + 0xE3CA: 0x98DC, //CJK UNIFIED IDEOGRAPH + 0xE3CB: 0x8006, //CJK UNIFIED IDEOGRAPH + 0xE3CC: 0x8004, //CJK UNIFIED IDEOGRAPH + 0xE3CD: 0x800B, //CJK UNIFIED IDEOGRAPH + 0xE3CE: 0x8012, //CJK UNIFIED IDEOGRAPH + 0xE3CF: 0x8018, //CJK UNIFIED IDEOGRAPH + 0xE3D0: 0x8019, //CJK UNIFIED IDEOGRAPH + 0xE3D1: 0x801C, //CJK UNIFIED IDEOGRAPH + 0xE3D2: 0x8021, //CJK UNIFIED IDEOGRAPH + 0xE3D3: 0x8028, //CJK UNIFIED IDEOGRAPH + 0xE3D4: 0x803F, //CJK UNIFIED IDEOGRAPH + 0xE3D5: 0x803B, //CJK UNIFIED IDEOGRAPH + 0xE3D6: 0x804A, //CJK UNIFIED IDEOGRAPH + 0xE3D7: 0x8046, //CJK UNIFIED IDEOGRAPH + 0xE3D8: 0x8052, //CJK UNIFIED IDEOGRAPH + 0xE3D9: 0x8058, //CJK UNIFIED IDEOGRAPH + 0xE3DA: 0x805A, //CJK UNIFIED IDEOGRAPH + 0xE3DB: 0x805F, //CJK UNIFIED IDEOGRAPH + 0xE3DC: 0x8062, //CJK UNIFIED IDEOGRAPH + 0xE3DD: 0x8068, //CJK UNIFIED IDEOGRAPH + 0xE3DE: 0x8073, //CJK UNIFIED IDEOGRAPH + 0xE3DF: 0x8072, //CJK UNIFIED IDEOGRAPH + 0xE3E0: 0x8070, //CJK UNIFIED IDEOGRAPH + 0xE3E1: 0x8076, //CJK UNIFIED IDEOGRAPH + 0xE3E2: 0x8079, //CJK UNIFIED IDEOGRAPH + 0xE3E3: 0x807D, //CJK UNIFIED IDEOGRAPH + 0xE3E4: 0x807F, //CJK UNIFIED IDEOGRAPH + 0xE3E5: 0x8084, //CJK UNIFIED IDEOGRAPH + 0xE3E6: 0x8086, //CJK UNIFIED IDEOGRAPH + 0xE3E7: 0x8085, //CJK UNIFIED IDEOGRAPH + 0xE3E8: 0x809B, //CJK UNIFIED IDEOGRAPH + 0xE3E9: 0x8093, //CJK UNIFIED IDEOGRAPH + 0xE3EA: 0x809A, //CJK UNIFIED IDEOGRAPH + 0xE3EB: 0x80AD, //CJK UNIFIED IDEOGRAPH + 0xE3EC: 0x5190, //CJK UNIFIED IDEOGRAPH + 0xE3ED: 0x80AC, //CJK UNIFIED IDEOGRAPH + 0xE3EE: 0x80DB, //CJK UNIFIED IDEOGRAPH + 0xE3EF: 0x80E5, //CJK UNIFIED IDEOGRAPH + 0xE3F0: 0x80D9, //CJK UNIFIED IDEOGRAPH + 0xE3F1: 0x80DD, //CJK UNIFIED IDEOGRAPH + 0xE3F2: 0x80C4, //CJK UNIFIED IDEOGRAPH + 0xE3F3: 0x80DA, //CJK UNIFIED IDEOGRAPH + 0xE3F4: 0x80D6, //CJK UNIFIED IDEOGRAPH + 0xE3F5: 0x8109, //CJK UNIFIED IDEOGRAPH + 0xE3F6: 0x80EF, //CJK UNIFIED IDEOGRAPH + 0xE3F7: 0x80F1, //CJK UNIFIED IDEOGRAPH + 0xE3F8: 0x811B, //CJK UNIFIED IDEOGRAPH + 0xE3F9: 0x8129, //CJK UNIFIED IDEOGRAPH + 0xE3FA: 0x8123, //CJK UNIFIED IDEOGRAPH + 0xE3FB: 0x812F, //CJK UNIFIED IDEOGRAPH + 0xE3FC: 0x814B, //CJK UNIFIED IDEOGRAPH + 0xE440: 0x968B, //CJK UNIFIED IDEOGRAPH + 0xE441: 0x8146, //CJK UNIFIED IDEOGRAPH + 0xE442: 0x813E, //CJK UNIFIED IDEOGRAPH + 0xE443: 0x8153, //CJK UNIFIED IDEOGRAPH + 0xE444: 0x8151, //CJK UNIFIED IDEOGRAPH + 0xE445: 0x80FC, //CJK UNIFIED IDEOGRAPH + 0xE446: 0x8171, //CJK UNIFIED IDEOGRAPH + 0xE447: 0x816E, //CJK UNIFIED IDEOGRAPH + 0xE448: 0x8165, //CJK UNIFIED IDEOGRAPH + 0xE449: 0x8166, //CJK UNIFIED IDEOGRAPH + 0xE44A: 0x8174, //CJK UNIFIED IDEOGRAPH + 0xE44B: 0x8183, //CJK UNIFIED IDEOGRAPH + 0xE44C: 0x8188, //CJK UNIFIED IDEOGRAPH + 0xE44D: 0x818A, //CJK UNIFIED IDEOGRAPH + 0xE44E: 0x8180, //CJK UNIFIED IDEOGRAPH + 0xE44F: 0x8182, //CJK UNIFIED IDEOGRAPH + 0xE450: 0x81A0, //CJK UNIFIED IDEOGRAPH + 0xE451: 0x8195, //CJK UNIFIED IDEOGRAPH + 0xE452: 0x81A4, //CJK UNIFIED IDEOGRAPH + 0xE453: 0x81A3, //CJK UNIFIED IDEOGRAPH + 0xE454: 0x815F, //CJK UNIFIED IDEOGRAPH + 0xE455: 0x8193, //CJK UNIFIED IDEOGRAPH + 0xE456: 0x81A9, //CJK UNIFIED IDEOGRAPH + 0xE457: 0x81B0, //CJK UNIFIED IDEOGRAPH + 0xE458: 0x81B5, //CJK UNIFIED IDEOGRAPH + 0xE459: 0x81BE, //CJK UNIFIED IDEOGRAPH + 0xE45A: 0x81B8, //CJK UNIFIED IDEOGRAPH + 0xE45B: 0x81BD, //CJK UNIFIED IDEOGRAPH + 0xE45C: 0x81C0, //CJK UNIFIED IDEOGRAPH + 0xE45D: 0x81C2, //CJK UNIFIED IDEOGRAPH + 0xE45E: 0x81BA, //CJK UNIFIED IDEOGRAPH + 0xE45F: 0x81C9, //CJK UNIFIED IDEOGRAPH + 0xE460: 0x81CD, //CJK UNIFIED IDEOGRAPH + 0xE461: 0x81D1, //CJK UNIFIED IDEOGRAPH + 0xE462: 0x81D9, //CJK UNIFIED IDEOGRAPH + 0xE463: 0x81D8, //CJK UNIFIED IDEOGRAPH + 0xE464: 0x81C8, //CJK UNIFIED IDEOGRAPH + 0xE465: 0x81DA, //CJK UNIFIED IDEOGRAPH + 0xE466: 0x81DF, //CJK UNIFIED IDEOGRAPH + 0xE467: 0x81E0, //CJK UNIFIED IDEOGRAPH + 0xE468: 0x81E7, //CJK UNIFIED IDEOGRAPH + 0xE469: 0x81FA, //CJK UNIFIED IDEOGRAPH + 0xE46A: 0x81FB, //CJK UNIFIED IDEOGRAPH + 0xE46B: 0x81FE, //CJK UNIFIED IDEOGRAPH + 0xE46C: 0x8201, //CJK UNIFIED IDEOGRAPH + 0xE46D: 0x8202, //CJK UNIFIED IDEOGRAPH + 0xE46E: 0x8205, //CJK UNIFIED IDEOGRAPH + 0xE46F: 0x8207, //CJK UNIFIED IDEOGRAPH + 0xE470: 0x820A, //CJK UNIFIED IDEOGRAPH + 0xE471: 0x820D, //CJK UNIFIED IDEOGRAPH + 0xE472: 0x8210, //CJK UNIFIED IDEOGRAPH + 0xE473: 0x8216, //CJK UNIFIED IDEOGRAPH + 0xE474: 0x8229, //CJK UNIFIED IDEOGRAPH + 0xE475: 0x822B, //CJK UNIFIED IDEOGRAPH + 0xE476: 0x8238, //CJK UNIFIED IDEOGRAPH + 0xE477: 0x8233, //CJK UNIFIED IDEOGRAPH + 0xE478: 0x8240, //CJK UNIFIED IDEOGRAPH + 0xE479: 0x8259, //CJK UNIFIED IDEOGRAPH + 0xE47A: 0x8258, //CJK UNIFIED IDEOGRAPH + 0xE47B: 0x825D, //CJK UNIFIED IDEOGRAPH + 0xE47C: 0x825A, //CJK UNIFIED IDEOGRAPH + 0xE47D: 0x825F, //CJK UNIFIED IDEOGRAPH + 0xE47E: 0x8264, //CJK UNIFIED IDEOGRAPH + 0xE480: 0x8262, //CJK UNIFIED IDEOGRAPH + 0xE481: 0x8268, //CJK UNIFIED IDEOGRAPH + 0xE482: 0x826A, //CJK UNIFIED IDEOGRAPH + 0xE483: 0x826B, //CJK UNIFIED IDEOGRAPH + 0xE484: 0x822E, //CJK UNIFIED IDEOGRAPH + 0xE485: 0x8271, //CJK UNIFIED IDEOGRAPH + 0xE486: 0x8277, //CJK UNIFIED IDEOGRAPH + 0xE487: 0x8278, //CJK UNIFIED IDEOGRAPH + 0xE488: 0x827E, //CJK UNIFIED IDEOGRAPH + 0xE489: 0x828D, //CJK UNIFIED IDEOGRAPH + 0xE48A: 0x8292, //CJK UNIFIED IDEOGRAPH + 0xE48B: 0x82AB, //CJK UNIFIED IDEOGRAPH + 0xE48C: 0x829F, //CJK UNIFIED IDEOGRAPH + 0xE48D: 0x82BB, //CJK UNIFIED IDEOGRAPH + 0xE48E: 0x82AC, //CJK UNIFIED IDEOGRAPH + 0xE48F: 0x82E1, //CJK UNIFIED IDEOGRAPH + 0xE490: 0x82E3, //CJK UNIFIED IDEOGRAPH + 0xE491: 0x82DF, //CJK UNIFIED IDEOGRAPH + 0xE492: 0x82D2, //CJK UNIFIED IDEOGRAPH + 0xE493: 0x82F4, //CJK UNIFIED IDEOGRAPH + 0xE494: 0x82F3, //CJK UNIFIED IDEOGRAPH + 0xE495: 0x82FA, //CJK UNIFIED IDEOGRAPH + 0xE496: 0x8393, //CJK UNIFIED IDEOGRAPH + 0xE497: 0x8303, //CJK UNIFIED IDEOGRAPH + 0xE498: 0x82FB, //CJK UNIFIED IDEOGRAPH + 0xE499: 0x82F9, //CJK UNIFIED IDEOGRAPH + 0xE49A: 0x82DE, //CJK UNIFIED IDEOGRAPH + 0xE49B: 0x8306, //CJK UNIFIED IDEOGRAPH + 0xE49C: 0x82DC, //CJK UNIFIED IDEOGRAPH + 0xE49D: 0x8309, //CJK UNIFIED IDEOGRAPH + 0xE49E: 0x82D9, //CJK UNIFIED IDEOGRAPH + 0xE49F: 0x8335, //CJK UNIFIED IDEOGRAPH + 0xE4A0: 0x8334, //CJK UNIFIED IDEOGRAPH + 0xE4A1: 0x8316, //CJK UNIFIED IDEOGRAPH + 0xE4A2: 0x8332, //CJK UNIFIED IDEOGRAPH + 0xE4A3: 0x8331, //CJK UNIFIED IDEOGRAPH + 0xE4A4: 0x8340, //CJK UNIFIED IDEOGRAPH + 0xE4A5: 0x8339, //CJK UNIFIED IDEOGRAPH + 0xE4A6: 0x8350, //CJK UNIFIED IDEOGRAPH + 0xE4A7: 0x8345, //CJK UNIFIED IDEOGRAPH + 0xE4A8: 0x832F, //CJK UNIFIED IDEOGRAPH + 0xE4A9: 0x832B, //CJK UNIFIED IDEOGRAPH + 0xE4AA: 0x8317, //CJK UNIFIED IDEOGRAPH + 0xE4AB: 0x8318, //CJK UNIFIED IDEOGRAPH + 0xE4AC: 0x8385, //CJK UNIFIED IDEOGRAPH + 0xE4AD: 0x839A, //CJK UNIFIED IDEOGRAPH + 0xE4AE: 0x83AA, //CJK UNIFIED IDEOGRAPH + 0xE4AF: 0x839F, //CJK UNIFIED IDEOGRAPH + 0xE4B0: 0x83A2, //CJK UNIFIED IDEOGRAPH + 0xE4B1: 0x8396, //CJK UNIFIED IDEOGRAPH + 0xE4B2: 0x8323, //CJK UNIFIED IDEOGRAPH + 0xE4B3: 0x838E, //CJK UNIFIED IDEOGRAPH + 0xE4B4: 0x8387, //CJK UNIFIED IDEOGRAPH + 0xE4B5: 0x838A, //CJK UNIFIED IDEOGRAPH + 0xE4B6: 0x837C, //CJK UNIFIED IDEOGRAPH + 0xE4B7: 0x83B5, //CJK UNIFIED IDEOGRAPH + 0xE4B8: 0x8373, //CJK UNIFIED IDEOGRAPH + 0xE4B9: 0x8375, //CJK UNIFIED IDEOGRAPH + 0xE4BA: 0x83A0, //CJK UNIFIED IDEOGRAPH + 0xE4BB: 0x8389, //CJK UNIFIED IDEOGRAPH + 0xE4BC: 0x83A8, //CJK UNIFIED IDEOGRAPH + 0xE4BD: 0x83F4, //CJK UNIFIED IDEOGRAPH + 0xE4BE: 0x8413, //CJK UNIFIED IDEOGRAPH + 0xE4BF: 0x83EB, //CJK UNIFIED IDEOGRAPH + 0xE4C0: 0x83CE, //CJK UNIFIED IDEOGRAPH + 0xE4C1: 0x83FD, //CJK UNIFIED IDEOGRAPH + 0xE4C2: 0x8403, //CJK UNIFIED IDEOGRAPH + 0xE4C3: 0x83D8, //CJK UNIFIED IDEOGRAPH + 0xE4C4: 0x840B, //CJK UNIFIED IDEOGRAPH + 0xE4C5: 0x83C1, //CJK UNIFIED IDEOGRAPH + 0xE4C6: 0x83F7, //CJK UNIFIED IDEOGRAPH + 0xE4C7: 0x8407, //CJK UNIFIED IDEOGRAPH + 0xE4C8: 0x83E0, //CJK UNIFIED IDEOGRAPH + 0xE4C9: 0x83F2, //CJK UNIFIED IDEOGRAPH + 0xE4CA: 0x840D, //CJK UNIFIED IDEOGRAPH + 0xE4CB: 0x8422, //CJK UNIFIED IDEOGRAPH + 0xE4CC: 0x8420, //CJK UNIFIED IDEOGRAPH + 0xE4CD: 0x83BD, //CJK UNIFIED IDEOGRAPH + 0xE4CE: 0x8438, //CJK UNIFIED IDEOGRAPH + 0xE4CF: 0x8506, //CJK UNIFIED IDEOGRAPH + 0xE4D0: 0x83FB, //CJK UNIFIED IDEOGRAPH + 0xE4D1: 0x846D, //CJK UNIFIED IDEOGRAPH + 0xE4D2: 0x842A, //CJK UNIFIED IDEOGRAPH + 0xE4D3: 0x843C, //CJK UNIFIED IDEOGRAPH + 0xE4D4: 0x855A, //CJK UNIFIED IDEOGRAPH + 0xE4D5: 0x8484, //CJK UNIFIED IDEOGRAPH + 0xE4D6: 0x8477, //CJK UNIFIED IDEOGRAPH + 0xE4D7: 0x846B, //CJK UNIFIED IDEOGRAPH + 0xE4D8: 0x84AD, //CJK UNIFIED IDEOGRAPH + 0xE4D9: 0x846E, //CJK UNIFIED IDEOGRAPH + 0xE4DA: 0x8482, //CJK UNIFIED IDEOGRAPH + 0xE4DB: 0x8469, //CJK UNIFIED IDEOGRAPH + 0xE4DC: 0x8446, //CJK UNIFIED IDEOGRAPH + 0xE4DD: 0x842C, //CJK UNIFIED IDEOGRAPH + 0xE4DE: 0x846F, //CJK UNIFIED IDEOGRAPH + 0xE4DF: 0x8479, //CJK UNIFIED IDEOGRAPH + 0xE4E0: 0x8435, //CJK UNIFIED IDEOGRAPH + 0xE4E1: 0x84CA, //CJK UNIFIED IDEOGRAPH + 0xE4E2: 0x8462, //CJK UNIFIED IDEOGRAPH + 0xE4E3: 0x84B9, //CJK UNIFIED IDEOGRAPH + 0xE4E4: 0x84BF, //CJK UNIFIED IDEOGRAPH + 0xE4E5: 0x849F, //CJK UNIFIED IDEOGRAPH + 0xE4E6: 0x84D9, //CJK UNIFIED IDEOGRAPH + 0xE4E7: 0x84CD, //CJK UNIFIED IDEOGRAPH + 0xE4E8: 0x84BB, //CJK UNIFIED IDEOGRAPH + 0xE4E9: 0x84DA, //CJK UNIFIED IDEOGRAPH + 0xE4EA: 0x84D0, //CJK UNIFIED IDEOGRAPH + 0xE4EB: 0x84C1, //CJK UNIFIED IDEOGRAPH + 0xE4EC: 0x84C6, //CJK UNIFIED IDEOGRAPH + 0xE4ED: 0x84D6, //CJK UNIFIED IDEOGRAPH + 0xE4EE: 0x84A1, //CJK UNIFIED IDEOGRAPH + 0xE4EF: 0x8521, //CJK UNIFIED IDEOGRAPH + 0xE4F0: 0x84FF, //CJK UNIFIED IDEOGRAPH + 0xE4F1: 0x84F4, //CJK UNIFIED IDEOGRAPH + 0xE4F2: 0x8517, //CJK UNIFIED IDEOGRAPH + 0xE4F3: 0x8518, //CJK UNIFIED IDEOGRAPH + 0xE4F4: 0x852C, //CJK UNIFIED IDEOGRAPH + 0xE4F5: 0x851F, //CJK UNIFIED IDEOGRAPH + 0xE4F6: 0x8515, //CJK UNIFIED IDEOGRAPH + 0xE4F7: 0x8514, //CJK UNIFIED IDEOGRAPH + 0xE4F8: 0x84FC, //CJK UNIFIED IDEOGRAPH + 0xE4F9: 0x8540, //CJK UNIFIED IDEOGRAPH + 0xE4FA: 0x8563, //CJK UNIFIED IDEOGRAPH + 0xE4FB: 0x8558, //CJK UNIFIED IDEOGRAPH + 0xE4FC: 0x8548, //CJK UNIFIED IDEOGRAPH + 0xE540: 0x8541, //CJK UNIFIED IDEOGRAPH + 0xE541: 0x8602, //CJK UNIFIED IDEOGRAPH + 0xE542: 0x854B, //CJK UNIFIED IDEOGRAPH + 0xE543: 0x8555, //CJK UNIFIED IDEOGRAPH + 0xE544: 0x8580, //CJK UNIFIED IDEOGRAPH + 0xE545: 0x85A4, //CJK UNIFIED IDEOGRAPH + 0xE546: 0x8588, //CJK UNIFIED IDEOGRAPH + 0xE547: 0x8591, //CJK UNIFIED IDEOGRAPH + 0xE548: 0x858A, //CJK UNIFIED IDEOGRAPH + 0xE549: 0x85A8, //CJK UNIFIED IDEOGRAPH + 0xE54A: 0x856D, //CJK UNIFIED IDEOGRAPH + 0xE54B: 0x8594, //CJK UNIFIED IDEOGRAPH + 0xE54C: 0x859B, //CJK UNIFIED IDEOGRAPH + 0xE54D: 0x85EA, //CJK UNIFIED IDEOGRAPH + 0xE54E: 0x8587, //CJK UNIFIED IDEOGRAPH + 0xE54F: 0x859C, //CJK UNIFIED IDEOGRAPH + 0xE550: 0x8577, //CJK UNIFIED IDEOGRAPH + 0xE551: 0x857E, //CJK UNIFIED IDEOGRAPH + 0xE552: 0x8590, //CJK UNIFIED IDEOGRAPH + 0xE553: 0x85C9, //CJK UNIFIED IDEOGRAPH + 0xE554: 0x85BA, //CJK UNIFIED IDEOGRAPH + 0xE555: 0x85CF, //CJK UNIFIED IDEOGRAPH + 0xE556: 0x85B9, //CJK UNIFIED IDEOGRAPH + 0xE557: 0x85D0, //CJK UNIFIED IDEOGRAPH + 0xE558: 0x85D5, //CJK UNIFIED IDEOGRAPH + 0xE559: 0x85DD, //CJK UNIFIED IDEOGRAPH + 0xE55A: 0x85E5, //CJK UNIFIED IDEOGRAPH + 0xE55B: 0x85DC, //CJK UNIFIED IDEOGRAPH + 0xE55C: 0x85F9, //CJK UNIFIED IDEOGRAPH + 0xE55D: 0x860A, //CJK UNIFIED IDEOGRAPH + 0xE55E: 0x8613, //CJK UNIFIED IDEOGRAPH + 0xE55F: 0x860B, //CJK UNIFIED IDEOGRAPH + 0xE560: 0x85FE, //CJK UNIFIED IDEOGRAPH + 0xE561: 0x85FA, //CJK UNIFIED IDEOGRAPH + 0xE562: 0x8606, //CJK UNIFIED IDEOGRAPH + 0xE563: 0x8622, //CJK UNIFIED IDEOGRAPH + 0xE564: 0x861A, //CJK UNIFIED IDEOGRAPH + 0xE565: 0x8630, //CJK UNIFIED IDEOGRAPH + 0xE566: 0x863F, //CJK UNIFIED IDEOGRAPH + 0xE567: 0x864D, //CJK UNIFIED IDEOGRAPH + 0xE568: 0x4E55, //CJK UNIFIED IDEOGRAPH + 0xE569: 0x8654, //CJK UNIFIED IDEOGRAPH + 0xE56A: 0x865F, //CJK UNIFIED IDEOGRAPH + 0xE56B: 0x8667, //CJK UNIFIED IDEOGRAPH + 0xE56C: 0x8671, //CJK UNIFIED IDEOGRAPH + 0xE56D: 0x8693, //CJK UNIFIED IDEOGRAPH + 0xE56E: 0x86A3, //CJK UNIFIED IDEOGRAPH + 0xE56F: 0x86A9, //CJK UNIFIED IDEOGRAPH + 0xE570: 0x86AA, //CJK UNIFIED IDEOGRAPH + 0xE571: 0x868B, //CJK UNIFIED IDEOGRAPH + 0xE572: 0x868C, //CJK UNIFIED IDEOGRAPH + 0xE573: 0x86B6, //CJK UNIFIED IDEOGRAPH + 0xE574: 0x86AF, //CJK UNIFIED IDEOGRAPH + 0xE575: 0x86C4, //CJK UNIFIED IDEOGRAPH + 0xE576: 0x86C6, //CJK UNIFIED IDEOGRAPH + 0xE577: 0x86B0, //CJK UNIFIED IDEOGRAPH + 0xE578: 0x86C9, //CJK UNIFIED IDEOGRAPH + 0xE579: 0x8823, //CJK UNIFIED IDEOGRAPH + 0xE57A: 0x86AB, //CJK UNIFIED IDEOGRAPH + 0xE57B: 0x86D4, //CJK UNIFIED IDEOGRAPH + 0xE57C: 0x86DE, //CJK UNIFIED IDEOGRAPH + 0xE57D: 0x86E9, //CJK UNIFIED IDEOGRAPH + 0xE57E: 0x86EC, //CJK UNIFIED IDEOGRAPH + 0xE580: 0x86DF, //CJK UNIFIED IDEOGRAPH + 0xE581: 0x86DB, //CJK UNIFIED IDEOGRAPH + 0xE582: 0x86EF, //CJK UNIFIED IDEOGRAPH + 0xE583: 0x8712, //CJK UNIFIED IDEOGRAPH + 0xE584: 0x8706, //CJK UNIFIED IDEOGRAPH + 0xE585: 0x8708, //CJK UNIFIED IDEOGRAPH + 0xE586: 0x8700, //CJK UNIFIED IDEOGRAPH + 0xE587: 0x8703, //CJK UNIFIED IDEOGRAPH + 0xE588: 0x86FB, //CJK UNIFIED IDEOGRAPH + 0xE589: 0x8711, //CJK UNIFIED IDEOGRAPH + 0xE58A: 0x8709, //CJK UNIFIED IDEOGRAPH + 0xE58B: 0x870D, //CJK UNIFIED IDEOGRAPH + 0xE58C: 0x86F9, //CJK UNIFIED IDEOGRAPH + 0xE58D: 0x870A, //CJK UNIFIED IDEOGRAPH + 0xE58E: 0x8734, //CJK UNIFIED IDEOGRAPH + 0xE58F: 0x873F, //CJK UNIFIED IDEOGRAPH + 0xE590: 0x8737, //CJK UNIFIED IDEOGRAPH + 0xE591: 0x873B, //CJK UNIFIED IDEOGRAPH + 0xE592: 0x8725, //CJK UNIFIED IDEOGRAPH + 0xE593: 0x8729, //CJK UNIFIED IDEOGRAPH + 0xE594: 0x871A, //CJK UNIFIED IDEOGRAPH + 0xE595: 0x8760, //CJK UNIFIED IDEOGRAPH + 0xE596: 0x875F, //CJK UNIFIED IDEOGRAPH + 0xE597: 0x8778, //CJK UNIFIED IDEOGRAPH + 0xE598: 0x874C, //CJK UNIFIED IDEOGRAPH + 0xE599: 0x874E, //CJK UNIFIED IDEOGRAPH + 0xE59A: 0x8774, //CJK UNIFIED IDEOGRAPH + 0xE59B: 0x8757, //CJK UNIFIED IDEOGRAPH + 0xE59C: 0x8768, //CJK UNIFIED IDEOGRAPH + 0xE59D: 0x876E, //CJK UNIFIED IDEOGRAPH + 0xE59E: 0x8759, //CJK UNIFIED IDEOGRAPH + 0xE59F: 0x8753, //CJK UNIFIED IDEOGRAPH + 0xE5A0: 0x8763, //CJK UNIFIED IDEOGRAPH + 0xE5A1: 0x876A, //CJK UNIFIED IDEOGRAPH + 0xE5A2: 0x8805, //CJK UNIFIED IDEOGRAPH + 0xE5A3: 0x87A2, //CJK UNIFIED IDEOGRAPH + 0xE5A4: 0x879F, //CJK UNIFIED IDEOGRAPH + 0xE5A5: 0x8782, //CJK UNIFIED IDEOGRAPH + 0xE5A6: 0x87AF, //CJK UNIFIED IDEOGRAPH + 0xE5A7: 0x87CB, //CJK UNIFIED IDEOGRAPH + 0xE5A8: 0x87BD, //CJK UNIFIED IDEOGRAPH + 0xE5A9: 0x87C0, //CJK UNIFIED IDEOGRAPH + 0xE5AA: 0x87D0, //CJK UNIFIED IDEOGRAPH + 0xE5AB: 0x96D6, //CJK UNIFIED IDEOGRAPH + 0xE5AC: 0x87AB, //CJK UNIFIED IDEOGRAPH + 0xE5AD: 0x87C4, //CJK UNIFIED IDEOGRAPH + 0xE5AE: 0x87B3, //CJK UNIFIED IDEOGRAPH + 0xE5AF: 0x87C7, //CJK UNIFIED IDEOGRAPH + 0xE5B0: 0x87C6, //CJK UNIFIED IDEOGRAPH + 0xE5B1: 0x87BB, //CJK UNIFIED IDEOGRAPH + 0xE5B2: 0x87EF, //CJK UNIFIED IDEOGRAPH + 0xE5B3: 0x87F2, //CJK UNIFIED IDEOGRAPH + 0xE5B4: 0x87E0, //CJK UNIFIED IDEOGRAPH + 0xE5B5: 0x880F, //CJK UNIFIED IDEOGRAPH + 0xE5B6: 0x880D, //CJK UNIFIED IDEOGRAPH + 0xE5B7: 0x87FE, //CJK UNIFIED IDEOGRAPH + 0xE5B8: 0x87F6, //CJK UNIFIED IDEOGRAPH + 0xE5B9: 0x87F7, //CJK UNIFIED IDEOGRAPH + 0xE5BA: 0x880E, //CJK UNIFIED IDEOGRAPH + 0xE5BB: 0x87D2, //CJK UNIFIED IDEOGRAPH + 0xE5BC: 0x8811, //CJK UNIFIED IDEOGRAPH + 0xE5BD: 0x8816, //CJK UNIFIED IDEOGRAPH + 0xE5BE: 0x8815, //CJK UNIFIED IDEOGRAPH + 0xE5BF: 0x8822, //CJK UNIFIED IDEOGRAPH + 0xE5C0: 0x8821, //CJK UNIFIED IDEOGRAPH + 0xE5C1: 0x8831, //CJK UNIFIED IDEOGRAPH + 0xE5C2: 0x8836, //CJK UNIFIED IDEOGRAPH + 0xE5C3: 0x8839, //CJK UNIFIED IDEOGRAPH + 0xE5C4: 0x8827, //CJK UNIFIED IDEOGRAPH + 0xE5C5: 0x883B, //CJK UNIFIED IDEOGRAPH + 0xE5C6: 0x8844, //CJK UNIFIED IDEOGRAPH + 0xE5C7: 0x8842, //CJK UNIFIED IDEOGRAPH + 0xE5C8: 0x8852, //CJK UNIFIED IDEOGRAPH + 0xE5C9: 0x8859, //CJK UNIFIED IDEOGRAPH + 0xE5CA: 0x885E, //CJK UNIFIED IDEOGRAPH + 0xE5CB: 0x8862, //CJK UNIFIED IDEOGRAPH + 0xE5CC: 0x886B, //CJK UNIFIED IDEOGRAPH + 0xE5CD: 0x8881, //CJK UNIFIED IDEOGRAPH + 0xE5CE: 0x887E, //CJK UNIFIED IDEOGRAPH + 0xE5CF: 0x889E, //CJK UNIFIED IDEOGRAPH + 0xE5D0: 0x8875, //CJK UNIFIED IDEOGRAPH + 0xE5D1: 0x887D, //CJK UNIFIED IDEOGRAPH + 0xE5D2: 0x88B5, //CJK UNIFIED IDEOGRAPH + 0xE5D3: 0x8872, //CJK UNIFIED IDEOGRAPH + 0xE5D4: 0x8882, //CJK UNIFIED IDEOGRAPH + 0xE5D5: 0x8897, //CJK UNIFIED IDEOGRAPH + 0xE5D6: 0x8892, //CJK UNIFIED IDEOGRAPH + 0xE5D7: 0x88AE, //CJK UNIFIED IDEOGRAPH + 0xE5D8: 0x8899, //CJK UNIFIED IDEOGRAPH + 0xE5D9: 0x88A2, //CJK UNIFIED IDEOGRAPH + 0xE5DA: 0x888D, //CJK UNIFIED IDEOGRAPH + 0xE5DB: 0x88A4, //CJK UNIFIED IDEOGRAPH + 0xE5DC: 0x88B0, //CJK UNIFIED IDEOGRAPH + 0xE5DD: 0x88BF, //CJK UNIFIED IDEOGRAPH + 0xE5DE: 0x88B1, //CJK UNIFIED IDEOGRAPH + 0xE5DF: 0x88C3, //CJK UNIFIED IDEOGRAPH + 0xE5E0: 0x88C4, //CJK UNIFIED IDEOGRAPH + 0xE5E1: 0x88D4, //CJK UNIFIED IDEOGRAPH + 0xE5E2: 0x88D8, //CJK UNIFIED IDEOGRAPH + 0xE5E3: 0x88D9, //CJK UNIFIED IDEOGRAPH + 0xE5E4: 0x88DD, //CJK UNIFIED IDEOGRAPH + 0xE5E5: 0x88F9, //CJK UNIFIED IDEOGRAPH + 0xE5E6: 0x8902, //CJK UNIFIED IDEOGRAPH + 0xE5E7: 0x88FC, //CJK UNIFIED IDEOGRAPH + 0xE5E8: 0x88F4, //CJK UNIFIED IDEOGRAPH + 0xE5E9: 0x88E8, //CJK UNIFIED IDEOGRAPH + 0xE5EA: 0x88F2, //CJK UNIFIED IDEOGRAPH + 0xE5EB: 0x8904, //CJK UNIFIED IDEOGRAPH + 0xE5EC: 0x890C, //CJK UNIFIED IDEOGRAPH + 0xE5ED: 0x890A, //CJK UNIFIED IDEOGRAPH + 0xE5EE: 0x8913, //CJK UNIFIED IDEOGRAPH + 0xE5EF: 0x8943, //CJK UNIFIED IDEOGRAPH + 0xE5F0: 0x891E, //CJK UNIFIED IDEOGRAPH + 0xE5F1: 0x8925, //CJK UNIFIED IDEOGRAPH + 0xE5F2: 0x892A, //CJK UNIFIED IDEOGRAPH + 0xE5F3: 0x892B, //CJK UNIFIED IDEOGRAPH + 0xE5F4: 0x8941, //CJK UNIFIED IDEOGRAPH + 0xE5F5: 0x8944, //CJK UNIFIED IDEOGRAPH + 0xE5F6: 0x893B, //CJK UNIFIED IDEOGRAPH + 0xE5F7: 0x8936, //CJK UNIFIED IDEOGRAPH + 0xE5F8: 0x8938, //CJK UNIFIED IDEOGRAPH + 0xE5F9: 0x894C, //CJK UNIFIED IDEOGRAPH + 0xE5FA: 0x891D, //CJK UNIFIED IDEOGRAPH + 0xE5FB: 0x8960, //CJK UNIFIED IDEOGRAPH + 0xE5FC: 0x895E, //CJK UNIFIED IDEOGRAPH + 0xE640: 0x8966, //CJK UNIFIED IDEOGRAPH + 0xE641: 0x8964, //CJK UNIFIED IDEOGRAPH + 0xE642: 0x896D, //CJK UNIFIED IDEOGRAPH + 0xE643: 0x896A, //CJK UNIFIED IDEOGRAPH + 0xE644: 0x896F, //CJK UNIFIED IDEOGRAPH + 0xE645: 0x8974, //CJK UNIFIED IDEOGRAPH + 0xE646: 0x8977, //CJK UNIFIED IDEOGRAPH + 0xE647: 0x897E, //CJK UNIFIED IDEOGRAPH + 0xE648: 0x8983, //CJK UNIFIED IDEOGRAPH + 0xE649: 0x8988, //CJK UNIFIED IDEOGRAPH + 0xE64A: 0x898A, //CJK UNIFIED IDEOGRAPH + 0xE64B: 0x8993, //CJK UNIFIED IDEOGRAPH + 0xE64C: 0x8998, //CJK UNIFIED IDEOGRAPH + 0xE64D: 0x89A1, //CJK UNIFIED IDEOGRAPH + 0xE64E: 0x89A9, //CJK UNIFIED IDEOGRAPH + 0xE64F: 0x89A6, //CJK UNIFIED IDEOGRAPH + 0xE650: 0x89AC, //CJK UNIFIED IDEOGRAPH + 0xE651: 0x89AF, //CJK UNIFIED IDEOGRAPH + 0xE652: 0x89B2, //CJK UNIFIED IDEOGRAPH + 0xE653: 0x89BA, //CJK UNIFIED IDEOGRAPH + 0xE654: 0x89BD, //CJK UNIFIED IDEOGRAPH + 0xE655: 0x89BF, //CJK UNIFIED IDEOGRAPH + 0xE656: 0x89C0, //CJK UNIFIED IDEOGRAPH + 0xE657: 0x89DA, //CJK UNIFIED IDEOGRAPH + 0xE658: 0x89DC, //CJK UNIFIED IDEOGRAPH + 0xE659: 0x89DD, //CJK UNIFIED IDEOGRAPH + 0xE65A: 0x89E7, //CJK UNIFIED IDEOGRAPH + 0xE65B: 0x89F4, //CJK UNIFIED IDEOGRAPH + 0xE65C: 0x89F8, //CJK UNIFIED IDEOGRAPH + 0xE65D: 0x8A03, //CJK UNIFIED IDEOGRAPH + 0xE65E: 0x8A16, //CJK UNIFIED IDEOGRAPH + 0xE65F: 0x8A10, //CJK UNIFIED IDEOGRAPH + 0xE660: 0x8A0C, //CJK UNIFIED IDEOGRAPH + 0xE661: 0x8A1B, //CJK UNIFIED IDEOGRAPH + 0xE662: 0x8A1D, //CJK UNIFIED IDEOGRAPH + 0xE663: 0x8A25, //CJK UNIFIED IDEOGRAPH + 0xE664: 0x8A36, //CJK UNIFIED IDEOGRAPH + 0xE665: 0x8A41, //CJK UNIFIED IDEOGRAPH + 0xE666: 0x8A5B, //CJK UNIFIED IDEOGRAPH + 0xE667: 0x8A52, //CJK UNIFIED IDEOGRAPH + 0xE668: 0x8A46, //CJK UNIFIED IDEOGRAPH + 0xE669: 0x8A48, //CJK UNIFIED IDEOGRAPH + 0xE66A: 0x8A7C, //CJK UNIFIED IDEOGRAPH + 0xE66B: 0x8A6D, //CJK UNIFIED IDEOGRAPH + 0xE66C: 0x8A6C, //CJK UNIFIED IDEOGRAPH + 0xE66D: 0x8A62, //CJK UNIFIED IDEOGRAPH + 0xE66E: 0x8A85, //CJK UNIFIED IDEOGRAPH + 0xE66F: 0x8A82, //CJK UNIFIED IDEOGRAPH + 0xE670: 0x8A84, //CJK UNIFIED IDEOGRAPH + 0xE671: 0x8AA8, //CJK UNIFIED IDEOGRAPH + 0xE672: 0x8AA1, //CJK UNIFIED IDEOGRAPH + 0xE673: 0x8A91, //CJK UNIFIED IDEOGRAPH + 0xE674: 0x8AA5, //CJK UNIFIED IDEOGRAPH + 0xE675: 0x8AA6, //CJK UNIFIED IDEOGRAPH + 0xE676: 0x8A9A, //CJK UNIFIED IDEOGRAPH + 0xE677: 0x8AA3, //CJK UNIFIED IDEOGRAPH + 0xE678: 0x8AC4, //CJK UNIFIED IDEOGRAPH + 0xE679: 0x8ACD, //CJK UNIFIED IDEOGRAPH + 0xE67A: 0x8AC2, //CJK UNIFIED IDEOGRAPH + 0xE67B: 0x8ADA, //CJK UNIFIED IDEOGRAPH + 0xE67C: 0x8AEB, //CJK UNIFIED IDEOGRAPH + 0xE67D: 0x8AF3, //CJK UNIFIED IDEOGRAPH + 0xE67E: 0x8AE7, //CJK UNIFIED IDEOGRAPH + 0xE680: 0x8AE4, //CJK UNIFIED IDEOGRAPH + 0xE681: 0x8AF1, //CJK UNIFIED IDEOGRAPH + 0xE682: 0x8B14, //CJK UNIFIED IDEOGRAPH + 0xE683: 0x8AE0, //CJK UNIFIED IDEOGRAPH + 0xE684: 0x8AE2, //CJK UNIFIED IDEOGRAPH + 0xE685: 0x8AF7, //CJK UNIFIED IDEOGRAPH + 0xE686: 0x8ADE, //CJK UNIFIED IDEOGRAPH + 0xE687: 0x8ADB, //CJK UNIFIED IDEOGRAPH + 0xE688: 0x8B0C, //CJK UNIFIED IDEOGRAPH + 0xE689: 0x8B07, //CJK UNIFIED IDEOGRAPH + 0xE68A: 0x8B1A, //CJK UNIFIED IDEOGRAPH + 0xE68B: 0x8AE1, //CJK UNIFIED IDEOGRAPH + 0xE68C: 0x8B16, //CJK UNIFIED IDEOGRAPH + 0xE68D: 0x8B10, //CJK UNIFIED IDEOGRAPH + 0xE68E: 0x8B17, //CJK UNIFIED IDEOGRAPH + 0xE68F: 0x8B20, //CJK UNIFIED IDEOGRAPH + 0xE690: 0x8B33, //CJK UNIFIED IDEOGRAPH + 0xE691: 0x97AB, //CJK UNIFIED IDEOGRAPH + 0xE692: 0x8B26, //CJK UNIFIED IDEOGRAPH + 0xE693: 0x8B2B, //CJK UNIFIED IDEOGRAPH + 0xE694: 0x8B3E, //CJK UNIFIED IDEOGRAPH + 0xE695: 0x8B28, //CJK UNIFIED IDEOGRAPH + 0xE696: 0x8B41, //CJK UNIFIED IDEOGRAPH + 0xE697: 0x8B4C, //CJK UNIFIED IDEOGRAPH + 0xE698: 0x8B4F, //CJK UNIFIED IDEOGRAPH + 0xE699: 0x8B4E, //CJK UNIFIED IDEOGRAPH + 0xE69A: 0x8B49, //CJK UNIFIED IDEOGRAPH + 0xE69B: 0x8B56, //CJK UNIFIED IDEOGRAPH + 0xE69C: 0x8B5B, //CJK UNIFIED IDEOGRAPH + 0xE69D: 0x8B5A, //CJK UNIFIED IDEOGRAPH + 0xE69E: 0x8B6B, //CJK UNIFIED IDEOGRAPH + 0xE69F: 0x8B5F, //CJK UNIFIED IDEOGRAPH + 0xE6A0: 0x8B6C, //CJK UNIFIED IDEOGRAPH + 0xE6A1: 0x8B6F, //CJK UNIFIED IDEOGRAPH + 0xE6A2: 0x8B74, //CJK UNIFIED IDEOGRAPH + 0xE6A3: 0x8B7D, //CJK UNIFIED IDEOGRAPH + 0xE6A4: 0x8B80, //CJK UNIFIED IDEOGRAPH + 0xE6A5: 0x8B8C, //CJK UNIFIED IDEOGRAPH + 0xE6A6: 0x8B8E, //CJK UNIFIED IDEOGRAPH + 0xE6A7: 0x8B92, //CJK UNIFIED IDEOGRAPH + 0xE6A8: 0x8B93, //CJK UNIFIED IDEOGRAPH + 0xE6A9: 0x8B96, //CJK UNIFIED IDEOGRAPH + 0xE6AA: 0x8B99, //CJK UNIFIED IDEOGRAPH + 0xE6AB: 0x8B9A, //CJK UNIFIED IDEOGRAPH + 0xE6AC: 0x8C3A, //CJK UNIFIED IDEOGRAPH + 0xE6AD: 0x8C41, //CJK UNIFIED IDEOGRAPH + 0xE6AE: 0x8C3F, //CJK UNIFIED IDEOGRAPH + 0xE6AF: 0x8C48, //CJK UNIFIED IDEOGRAPH + 0xE6B0: 0x8C4C, //CJK UNIFIED IDEOGRAPH + 0xE6B1: 0x8C4E, //CJK UNIFIED IDEOGRAPH + 0xE6B2: 0x8C50, //CJK UNIFIED IDEOGRAPH + 0xE6B3: 0x8C55, //CJK UNIFIED IDEOGRAPH + 0xE6B4: 0x8C62, //CJK UNIFIED IDEOGRAPH + 0xE6B5: 0x8C6C, //CJK UNIFIED IDEOGRAPH + 0xE6B6: 0x8C78, //CJK UNIFIED IDEOGRAPH + 0xE6B7: 0x8C7A, //CJK UNIFIED IDEOGRAPH + 0xE6B8: 0x8C82, //CJK UNIFIED IDEOGRAPH + 0xE6B9: 0x8C89, //CJK UNIFIED IDEOGRAPH + 0xE6BA: 0x8C85, //CJK UNIFIED IDEOGRAPH + 0xE6BB: 0x8C8A, //CJK UNIFIED IDEOGRAPH + 0xE6BC: 0x8C8D, //CJK UNIFIED IDEOGRAPH + 0xE6BD: 0x8C8E, //CJK UNIFIED IDEOGRAPH + 0xE6BE: 0x8C94, //CJK UNIFIED IDEOGRAPH + 0xE6BF: 0x8C7C, //CJK UNIFIED IDEOGRAPH + 0xE6C0: 0x8C98, //CJK UNIFIED IDEOGRAPH + 0xE6C1: 0x621D, //CJK UNIFIED IDEOGRAPH + 0xE6C2: 0x8CAD, //CJK UNIFIED IDEOGRAPH + 0xE6C3: 0x8CAA, //CJK UNIFIED IDEOGRAPH + 0xE6C4: 0x8CBD, //CJK UNIFIED IDEOGRAPH + 0xE6C5: 0x8CB2, //CJK UNIFIED IDEOGRAPH + 0xE6C6: 0x8CB3, //CJK UNIFIED IDEOGRAPH + 0xE6C7: 0x8CAE, //CJK UNIFIED IDEOGRAPH + 0xE6C8: 0x8CB6, //CJK UNIFIED IDEOGRAPH + 0xE6C9: 0x8CC8, //CJK UNIFIED IDEOGRAPH + 0xE6CA: 0x8CC1, //CJK UNIFIED IDEOGRAPH + 0xE6CB: 0x8CE4, //CJK UNIFIED IDEOGRAPH + 0xE6CC: 0x8CE3, //CJK UNIFIED IDEOGRAPH + 0xE6CD: 0x8CDA, //CJK UNIFIED IDEOGRAPH + 0xE6CE: 0x8CFD, //CJK UNIFIED IDEOGRAPH + 0xE6CF: 0x8CFA, //CJK UNIFIED IDEOGRAPH + 0xE6D0: 0x8CFB, //CJK UNIFIED IDEOGRAPH + 0xE6D1: 0x8D04, //CJK UNIFIED IDEOGRAPH + 0xE6D2: 0x8D05, //CJK UNIFIED IDEOGRAPH + 0xE6D3: 0x8D0A, //CJK UNIFIED IDEOGRAPH + 0xE6D4: 0x8D07, //CJK UNIFIED IDEOGRAPH + 0xE6D5: 0x8D0F, //CJK UNIFIED IDEOGRAPH + 0xE6D6: 0x8D0D, //CJK UNIFIED IDEOGRAPH + 0xE6D7: 0x8D10, //CJK UNIFIED IDEOGRAPH + 0xE6D8: 0x9F4E, //CJK UNIFIED IDEOGRAPH + 0xE6D9: 0x8D13, //CJK UNIFIED IDEOGRAPH + 0xE6DA: 0x8CCD, //CJK UNIFIED IDEOGRAPH + 0xE6DB: 0x8D14, //CJK UNIFIED IDEOGRAPH + 0xE6DC: 0x8D16, //CJK UNIFIED IDEOGRAPH + 0xE6DD: 0x8D67, //CJK UNIFIED IDEOGRAPH + 0xE6DE: 0x8D6D, //CJK UNIFIED IDEOGRAPH + 0xE6DF: 0x8D71, //CJK UNIFIED IDEOGRAPH + 0xE6E0: 0x8D73, //CJK UNIFIED IDEOGRAPH + 0xE6E1: 0x8D81, //CJK UNIFIED IDEOGRAPH + 0xE6E2: 0x8D99, //CJK UNIFIED IDEOGRAPH + 0xE6E3: 0x8DC2, //CJK UNIFIED IDEOGRAPH + 0xE6E4: 0x8DBE, //CJK UNIFIED IDEOGRAPH + 0xE6E5: 0x8DBA, //CJK UNIFIED IDEOGRAPH + 0xE6E6: 0x8DCF, //CJK UNIFIED IDEOGRAPH + 0xE6E7: 0x8DDA, //CJK UNIFIED IDEOGRAPH + 0xE6E8: 0x8DD6, //CJK UNIFIED IDEOGRAPH + 0xE6E9: 0x8DCC, //CJK UNIFIED IDEOGRAPH + 0xE6EA: 0x8DDB, //CJK UNIFIED IDEOGRAPH + 0xE6EB: 0x8DCB, //CJK UNIFIED IDEOGRAPH + 0xE6EC: 0x8DEA, //CJK UNIFIED IDEOGRAPH + 0xE6ED: 0x8DEB, //CJK UNIFIED IDEOGRAPH + 0xE6EE: 0x8DDF, //CJK UNIFIED IDEOGRAPH + 0xE6EF: 0x8DE3, //CJK UNIFIED IDEOGRAPH + 0xE6F0: 0x8DFC, //CJK UNIFIED IDEOGRAPH + 0xE6F1: 0x8E08, //CJK UNIFIED IDEOGRAPH + 0xE6F2: 0x8E09, //CJK UNIFIED IDEOGRAPH + 0xE6F3: 0x8DFF, //CJK UNIFIED IDEOGRAPH + 0xE6F4: 0x8E1D, //CJK UNIFIED IDEOGRAPH + 0xE6F5: 0x8E1E, //CJK UNIFIED IDEOGRAPH + 0xE6F6: 0x8E10, //CJK UNIFIED IDEOGRAPH + 0xE6F7: 0x8E1F, //CJK UNIFIED IDEOGRAPH + 0xE6F8: 0x8E42, //CJK UNIFIED IDEOGRAPH + 0xE6F9: 0x8E35, //CJK UNIFIED IDEOGRAPH + 0xE6FA: 0x8E30, //CJK UNIFIED IDEOGRAPH + 0xE6FB: 0x8E34, //CJK UNIFIED IDEOGRAPH + 0xE6FC: 0x8E4A, //CJK UNIFIED IDEOGRAPH + 0xE740: 0x8E47, //CJK UNIFIED IDEOGRAPH + 0xE741: 0x8E49, //CJK UNIFIED IDEOGRAPH + 0xE742: 0x8E4C, //CJK UNIFIED IDEOGRAPH + 0xE743: 0x8E50, //CJK UNIFIED IDEOGRAPH + 0xE744: 0x8E48, //CJK UNIFIED IDEOGRAPH + 0xE745: 0x8E59, //CJK UNIFIED IDEOGRAPH + 0xE746: 0x8E64, //CJK UNIFIED IDEOGRAPH + 0xE747: 0x8E60, //CJK UNIFIED IDEOGRAPH + 0xE748: 0x8E2A, //CJK UNIFIED IDEOGRAPH + 0xE749: 0x8E63, //CJK UNIFIED IDEOGRAPH + 0xE74A: 0x8E55, //CJK UNIFIED IDEOGRAPH + 0xE74B: 0x8E76, //CJK UNIFIED IDEOGRAPH + 0xE74C: 0x8E72, //CJK UNIFIED IDEOGRAPH + 0xE74D: 0x8E7C, //CJK UNIFIED IDEOGRAPH + 0xE74E: 0x8E81, //CJK UNIFIED IDEOGRAPH + 0xE74F: 0x8E87, //CJK UNIFIED IDEOGRAPH + 0xE750: 0x8E85, //CJK UNIFIED IDEOGRAPH + 0xE751: 0x8E84, //CJK UNIFIED IDEOGRAPH + 0xE752: 0x8E8B, //CJK UNIFIED IDEOGRAPH + 0xE753: 0x8E8A, //CJK UNIFIED IDEOGRAPH + 0xE754: 0x8E93, //CJK UNIFIED IDEOGRAPH + 0xE755: 0x8E91, //CJK UNIFIED IDEOGRAPH + 0xE756: 0x8E94, //CJK UNIFIED IDEOGRAPH + 0xE757: 0x8E99, //CJK UNIFIED IDEOGRAPH + 0xE758: 0x8EAA, //CJK UNIFIED IDEOGRAPH + 0xE759: 0x8EA1, //CJK UNIFIED IDEOGRAPH + 0xE75A: 0x8EAC, //CJK UNIFIED IDEOGRAPH + 0xE75B: 0x8EB0, //CJK UNIFIED IDEOGRAPH + 0xE75C: 0x8EC6, //CJK UNIFIED IDEOGRAPH + 0xE75D: 0x8EB1, //CJK UNIFIED IDEOGRAPH + 0xE75E: 0x8EBE, //CJK UNIFIED IDEOGRAPH + 0xE75F: 0x8EC5, //CJK UNIFIED IDEOGRAPH + 0xE760: 0x8EC8, //CJK UNIFIED IDEOGRAPH + 0xE761: 0x8ECB, //CJK UNIFIED IDEOGRAPH + 0xE762: 0x8EDB, //CJK UNIFIED IDEOGRAPH + 0xE763: 0x8EE3, //CJK UNIFIED IDEOGRAPH + 0xE764: 0x8EFC, //CJK UNIFIED IDEOGRAPH + 0xE765: 0x8EFB, //CJK UNIFIED IDEOGRAPH + 0xE766: 0x8EEB, //CJK UNIFIED IDEOGRAPH + 0xE767: 0x8EFE, //CJK UNIFIED IDEOGRAPH + 0xE768: 0x8F0A, //CJK UNIFIED IDEOGRAPH + 0xE769: 0x8F05, //CJK UNIFIED IDEOGRAPH + 0xE76A: 0x8F15, //CJK UNIFIED IDEOGRAPH + 0xE76B: 0x8F12, //CJK UNIFIED IDEOGRAPH + 0xE76C: 0x8F19, //CJK UNIFIED IDEOGRAPH + 0xE76D: 0x8F13, //CJK UNIFIED IDEOGRAPH + 0xE76E: 0x8F1C, //CJK UNIFIED IDEOGRAPH + 0xE76F: 0x8F1F, //CJK UNIFIED IDEOGRAPH + 0xE770: 0x8F1B, //CJK UNIFIED IDEOGRAPH + 0xE771: 0x8F0C, //CJK UNIFIED IDEOGRAPH + 0xE772: 0x8F26, //CJK UNIFIED IDEOGRAPH + 0xE773: 0x8F33, //CJK UNIFIED IDEOGRAPH + 0xE774: 0x8F3B, //CJK UNIFIED IDEOGRAPH + 0xE775: 0x8F39, //CJK UNIFIED IDEOGRAPH + 0xE776: 0x8F45, //CJK UNIFIED IDEOGRAPH + 0xE777: 0x8F42, //CJK UNIFIED IDEOGRAPH + 0xE778: 0x8F3E, //CJK UNIFIED IDEOGRAPH + 0xE779: 0x8F4C, //CJK UNIFIED IDEOGRAPH + 0xE77A: 0x8F49, //CJK UNIFIED IDEOGRAPH + 0xE77B: 0x8F46, //CJK UNIFIED IDEOGRAPH + 0xE77C: 0x8F4E, //CJK UNIFIED IDEOGRAPH + 0xE77D: 0x8F57, //CJK UNIFIED IDEOGRAPH + 0xE77E: 0x8F5C, //CJK UNIFIED IDEOGRAPH + 0xE780: 0x8F62, //CJK UNIFIED IDEOGRAPH + 0xE781: 0x8F63, //CJK UNIFIED IDEOGRAPH + 0xE782: 0x8F64, //CJK UNIFIED IDEOGRAPH + 0xE783: 0x8F9C, //CJK UNIFIED IDEOGRAPH + 0xE784: 0x8F9F, //CJK UNIFIED IDEOGRAPH + 0xE785: 0x8FA3, //CJK UNIFIED IDEOGRAPH + 0xE786: 0x8FAD, //CJK UNIFIED IDEOGRAPH + 0xE787: 0x8FAF, //CJK UNIFIED IDEOGRAPH + 0xE788: 0x8FB7, //CJK UNIFIED IDEOGRAPH + 0xE789: 0x8FDA, //CJK UNIFIED IDEOGRAPH + 0xE78A: 0x8FE5, //CJK UNIFIED IDEOGRAPH + 0xE78B: 0x8FE2, //CJK UNIFIED IDEOGRAPH + 0xE78C: 0x8FEA, //CJK UNIFIED IDEOGRAPH + 0xE78D: 0x8FEF, //CJK UNIFIED IDEOGRAPH + 0xE78E: 0x9087, //CJK UNIFIED IDEOGRAPH + 0xE78F: 0x8FF4, //CJK UNIFIED IDEOGRAPH + 0xE790: 0x9005, //CJK UNIFIED IDEOGRAPH + 0xE791: 0x8FF9, //CJK UNIFIED IDEOGRAPH + 0xE792: 0x8FFA, //CJK UNIFIED IDEOGRAPH + 0xE793: 0x9011, //CJK UNIFIED IDEOGRAPH + 0xE794: 0x9015, //CJK UNIFIED IDEOGRAPH + 0xE795: 0x9021, //CJK UNIFIED IDEOGRAPH + 0xE796: 0x900D, //CJK UNIFIED IDEOGRAPH + 0xE797: 0x901E, //CJK UNIFIED IDEOGRAPH + 0xE798: 0x9016, //CJK UNIFIED IDEOGRAPH + 0xE799: 0x900B, //CJK UNIFIED IDEOGRAPH + 0xE79A: 0x9027, //CJK UNIFIED IDEOGRAPH + 0xE79B: 0x9036, //CJK UNIFIED IDEOGRAPH + 0xE79C: 0x9035, //CJK UNIFIED IDEOGRAPH + 0xE79D: 0x9039, //CJK UNIFIED IDEOGRAPH + 0xE79E: 0x8FF8, //CJK UNIFIED IDEOGRAPH + 0xE79F: 0x904F, //CJK UNIFIED IDEOGRAPH + 0xE7A0: 0x9050, //CJK UNIFIED IDEOGRAPH + 0xE7A1: 0x9051, //CJK UNIFIED IDEOGRAPH + 0xE7A2: 0x9052, //CJK UNIFIED IDEOGRAPH + 0xE7A3: 0x900E, //CJK UNIFIED IDEOGRAPH + 0xE7A4: 0x9049, //CJK UNIFIED IDEOGRAPH + 0xE7A5: 0x903E, //CJK UNIFIED IDEOGRAPH + 0xE7A6: 0x9056, //CJK UNIFIED IDEOGRAPH + 0xE7A7: 0x9058, //CJK UNIFIED IDEOGRAPH + 0xE7A8: 0x905E, //CJK UNIFIED IDEOGRAPH + 0xE7A9: 0x9068, //CJK UNIFIED IDEOGRAPH + 0xE7AA: 0x906F, //CJK UNIFIED IDEOGRAPH + 0xE7AB: 0x9076, //CJK UNIFIED IDEOGRAPH + 0xE7AC: 0x96A8, //CJK UNIFIED IDEOGRAPH + 0xE7AD: 0x9072, //CJK UNIFIED IDEOGRAPH + 0xE7AE: 0x9082, //CJK UNIFIED IDEOGRAPH + 0xE7AF: 0x907D, //CJK UNIFIED IDEOGRAPH + 0xE7B0: 0x9081, //CJK UNIFIED IDEOGRAPH + 0xE7B1: 0x9080, //CJK UNIFIED IDEOGRAPH + 0xE7B2: 0x908A, //CJK UNIFIED IDEOGRAPH + 0xE7B3: 0x9089, //CJK UNIFIED IDEOGRAPH + 0xE7B4: 0x908F, //CJK UNIFIED IDEOGRAPH + 0xE7B5: 0x90A8, //CJK UNIFIED IDEOGRAPH + 0xE7B6: 0x90AF, //CJK UNIFIED IDEOGRAPH + 0xE7B7: 0x90B1, //CJK UNIFIED IDEOGRAPH + 0xE7B8: 0x90B5, //CJK UNIFIED IDEOGRAPH + 0xE7B9: 0x90E2, //CJK UNIFIED IDEOGRAPH + 0xE7BA: 0x90E4, //CJK UNIFIED IDEOGRAPH + 0xE7BB: 0x6248, //CJK UNIFIED IDEOGRAPH + 0xE7BC: 0x90DB, //CJK UNIFIED IDEOGRAPH + 0xE7BD: 0x9102, //CJK UNIFIED IDEOGRAPH + 0xE7BE: 0x9112, //CJK UNIFIED IDEOGRAPH + 0xE7BF: 0x9119, //CJK UNIFIED IDEOGRAPH + 0xE7C0: 0x9132, //CJK UNIFIED IDEOGRAPH + 0xE7C1: 0x9130, //CJK UNIFIED IDEOGRAPH + 0xE7C2: 0x914A, //CJK UNIFIED IDEOGRAPH + 0xE7C3: 0x9156, //CJK UNIFIED IDEOGRAPH + 0xE7C4: 0x9158, //CJK UNIFIED IDEOGRAPH + 0xE7C5: 0x9163, //CJK UNIFIED IDEOGRAPH + 0xE7C6: 0x9165, //CJK UNIFIED IDEOGRAPH + 0xE7C7: 0x9169, //CJK UNIFIED IDEOGRAPH + 0xE7C8: 0x9173, //CJK UNIFIED IDEOGRAPH + 0xE7C9: 0x9172, //CJK UNIFIED IDEOGRAPH + 0xE7CA: 0x918B, //CJK UNIFIED IDEOGRAPH + 0xE7CB: 0x9189, //CJK UNIFIED IDEOGRAPH + 0xE7CC: 0x9182, //CJK UNIFIED IDEOGRAPH + 0xE7CD: 0x91A2, //CJK UNIFIED IDEOGRAPH + 0xE7CE: 0x91AB, //CJK UNIFIED IDEOGRAPH + 0xE7CF: 0x91AF, //CJK UNIFIED IDEOGRAPH + 0xE7D0: 0x91AA, //CJK UNIFIED IDEOGRAPH + 0xE7D1: 0x91B5, //CJK UNIFIED IDEOGRAPH + 0xE7D2: 0x91B4, //CJK UNIFIED IDEOGRAPH + 0xE7D3: 0x91BA, //CJK UNIFIED IDEOGRAPH + 0xE7D4: 0x91C0, //CJK UNIFIED IDEOGRAPH + 0xE7D5: 0x91C1, //CJK UNIFIED IDEOGRAPH + 0xE7D6: 0x91C9, //CJK UNIFIED IDEOGRAPH + 0xE7D7: 0x91CB, //CJK UNIFIED IDEOGRAPH + 0xE7D8: 0x91D0, //CJK UNIFIED IDEOGRAPH + 0xE7D9: 0x91D6, //CJK UNIFIED IDEOGRAPH + 0xE7DA: 0x91DF, //CJK UNIFIED IDEOGRAPH + 0xE7DB: 0x91E1, //CJK UNIFIED IDEOGRAPH + 0xE7DC: 0x91DB, //CJK UNIFIED IDEOGRAPH + 0xE7DD: 0x91FC, //CJK UNIFIED IDEOGRAPH + 0xE7DE: 0x91F5, //CJK UNIFIED IDEOGRAPH + 0xE7DF: 0x91F6, //CJK UNIFIED IDEOGRAPH + 0xE7E0: 0x921E, //CJK UNIFIED IDEOGRAPH + 0xE7E1: 0x91FF, //CJK UNIFIED IDEOGRAPH + 0xE7E2: 0x9214, //CJK UNIFIED IDEOGRAPH + 0xE7E3: 0x922C, //CJK UNIFIED IDEOGRAPH + 0xE7E4: 0x9215, //CJK UNIFIED IDEOGRAPH + 0xE7E5: 0x9211, //CJK UNIFIED IDEOGRAPH + 0xE7E6: 0x925E, //CJK UNIFIED IDEOGRAPH + 0xE7E7: 0x9257, //CJK UNIFIED IDEOGRAPH + 0xE7E8: 0x9245, //CJK UNIFIED IDEOGRAPH + 0xE7E9: 0x9249, //CJK UNIFIED IDEOGRAPH + 0xE7EA: 0x9264, //CJK UNIFIED IDEOGRAPH + 0xE7EB: 0x9248, //CJK UNIFIED IDEOGRAPH + 0xE7EC: 0x9295, //CJK UNIFIED IDEOGRAPH + 0xE7ED: 0x923F, //CJK UNIFIED IDEOGRAPH + 0xE7EE: 0x924B, //CJK UNIFIED IDEOGRAPH + 0xE7EF: 0x9250, //CJK UNIFIED IDEOGRAPH + 0xE7F0: 0x929C, //CJK UNIFIED IDEOGRAPH + 0xE7F1: 0x9296, //CJK UNIFIED IDEOGRAPH + 0xE7F2: 0x9293, //CJK UNIFIED IDEOGRAPH + 0xE7F3: 0x929B, //CJK UNIFIED IDEOGRAPH + 0xE7F4: 0x925A, //CJK UNIFIED IDEOGRAPH + 0xE7F5: 0x92CF, //CJK UNIFIED IDEOGRAPH + 0xE7F6: 0x92B9, //CJK UNIFIED IDEOGRAPH + 0xE7F7: 0x92B7, //CJK UNIFIED IDEOGRAPH + 0xE7F8: 0x92E9, //CJK UNIFIED IDEOGRAPH + 0xE7F9: 0x930F, //CJK UNIFIED IDEOGRAPH + 0xE7FA: 0x92FA, //CJK UNIFIED IDEOGRAPH + 0xE7FB: 0x9344, //CJK UNIFIED IDEOGRAPH + 0xE7FC: 0x932E, //CJK UNIFIED IDEOGRAPH + 0xE840: 0x9319, //CJK UNIFIED IDEOGRAPH + 0xE841: 0x9322, //CJK UNIFIED IDEOGRAPH + 0xE842: 0x931A, //CJK UNIFIED IDEOGRAPH + 0xE843: 0x9323, //CJK UNIFIED IDEOGRAPH + 0xE844: 0x933A, //CJK UNIFIED IDEOGRAPH + 0xE845: 0x9335, //CJK UNIFIED IDEOGRAPH + 0xE846: 0x933B, //CJK UNIFIED IDEOGRAPH + 0xE847: 0x935C, //CJK UNIFIED IDEOGRAPH + 0xE848: 0x9360, //CJK UNIFIED IDEOGRAPH + 0xE849: 0x937C, //CJK UNIFIED IDEOGRAPH + 0xE84A: 0x936E, //CJK UNIFIED IDEOGRAPH + 0xE84B: 0x9356, //CJK UNIFIED IDEOGRAPH + 0xE84C: 0x93B0, //CJK UNIFIED IDEOGRAPH + 0xE84D: 0x93AC, //CJK UNIFIED IDEOGRAPH + 0xE84E: 0x93AD, //CJK UNIFIED IDEOGRAPH + 0xE84F: 0x9394, //CJK UNIFIED IDEOGRAPH + 0xE850: 0x93B9, //CJK UNIFIED IDEOGRAPH + 0xE851: 0x93D6, //CJK UNIFIED IDEOGRAPH + 0xE852: 0x93D7, //CJK UNIFIED IDEOGRAPH + 0xE853: 0x93E8, //CJK UNIFIED IDEOGRAPH + 0xE854: 0x93E5, //CJK UNIFIED IDEOGRAPH + 0xE855: 0x93D8, //CJK UNIFIED IDEOGRAPH + 0xE856: 0x93C3, //CJK UNIFIED IDEOGRAPH + 0xE857: 0x93DD, //CJK UNIFIED IDEOGRAPH + 0xE858: 0x93D0, //CJK UNIFIED IDEOGRAPH + 0xE859: 0x93C8, //CJK UNIFIED IDEOGRAPH + 0xE85A: 0x93E4, //CJK UNIFIED IDEOGRAPH + 0xE85B: 0x941A, //CJK UNIFIED IDEOGRAPH + 0xE85C: 0x9414, //CJK UNIFIED IDEOGRAPH + 0xE85D: 0x9413, //CJK UNIFIED IDEOGRAPH + 0xE85E: 0x9403, //CJK UNIFIED IDEOGRAPH + 0xE85F: 0x9407, //CJK UNIFIED IDEOGRAPH + 0xE860: 0x9410, //CJK UNIFIED IDEOGRAPH + 0xE861: 0x9436, //CJK UNIFIED IDEOGRAPH + 0xE862: 0x942B, //CJK UNIFIED IDEOGRAPH + 0xE863: 0x9435, //CJK UNIFIED IDEOGRAPH + 0xE864: 0x9421, //CJK UNIFIED IDEOGRAPH + 0xE865: 0x943A, //CJK UNIFIED IDEOGRAPH + 0xE866: 0x9441, //CJK UNIFIED IDEOGRAPH + 0xE867: 0x9452, //CJK UNIFIED IDEOGRAPH + 0xE868: 0x9444, //CJK UNIFIED IDEOGRAPH + 0xE869: 0x945B, //CJK UNIFIED IDEOGRAPH + 0xE86A: 0x9460, //CJK UNIFIED IDEOGRAPH + 0xE86B: 0x9462, //CJK UNIFIED IDEOGRAPH + 0xE86C: 0x945E, //CJK UNIFIED IDEOGRAPH + 0xE86D: 0x946A, //CJK UNIFIED IDEOGRAPH + 0xE86E: 0x9229, //CJK UNIFIED IDEOGRAPH + 0xE86F: 0x9470, //CJK UNIFIED IDEOGRAPH + 0xE870: 0x9475, //CJK UNIFIED IDEOGRAPH + 0xE871: 0x9477, //CJK UNIFIED IDEOGRAPH + 0xE872: 0x947D, //CJK UNIFIED IDEOGRAPH + 0xE873: 0x945A, //CJK UNIFIED IDEOGRAPH + 0xE874: 0x947C, //CJK UNIFIED IDEOGRAPH + 0xE875: 0x947E, //CJK UNIFIED IDEOGRAPH + 0xE876: 0x9481, //CJK UNIFIED IDEOGRAPH + 0xE877: 0x947F, //CJK UNIFIED IDEOGRAPH + 0xE878: 0x9582, //CJK UNIFIED IDEOGRAPH + 0xE879: 0x9587, //CJK UNIFIED IDEOGRAPH + 0xE87A: 0x958A, //CJK UNIFIED IDEOGRAPH + 0xE87B: 0x9594, //CJK UNIFIED IDEOGRAPH + 0xE87C: 0x9596, //CJK UNIFIED IDEOGRAPH + 0xE87D: 0x9598, //CJK UNIFIED IDEOGRAPH + 0xE87E: 0x9599, //CJK UNIFIED IDEOGRAPH + 0xE880: 0x95A0, //CJK UNIFIED IDEOGRAPH + 0xE881: 0x95A8, //CJK UNIFIED IDEOGRAPH + 0xE882: 0x95A7, //CJK UNIFIED IDEOGRAPH + 0xE883: 0x95AD, //CJK UNIFIED IDEOGRAPH + 0xE884: 0x95BC, //CJK UNIFIED IDEOGRAPH + 0xE885: 0x95BB, //CJK UNIFIED IDEOGRAPH + 0xE886: 0x95B9, //CJK UNIFIED IDEOGRAPH + 0xE887: 0x95BE, //CJK UNIFIED IDEOGRAPH + 0xE888: 0x95CA, //CJK UNIFIED IDEOGRAPH + 0xE889: 0x6FF6, //CJK UNIFIED IDEOGRAPH + 0xE88A: 0x95C3, //CJK UNIFIED IDEOGRAPH + 0xE88B: 0x95CD, //CJK UNIFIED IDEOGRAPH + 0xE88C: 0x95CC, //CJK UNIFIED IDEOGRAPH + 0xE88D: 0x95D5, //CJK UNIFIED IDEOGRAPH + 0xE88E: 0x95D4, //CJK UNIFIED IDEOGRAPH + 0xE88F: 0x95D6, //CJK UNIFIED IDEOGRAPH + 0xE890: 0x95DC, //CJK UNIFIED IDEOGRAPH + 0xE891: 0x95E1, //CJK UNIFIED IDEOGRAPH + 0xE892: 0x95E5, //CJK UNIFIED IDEOGRAPH + 0xE893: 0x95E2, //CJK UNIFIED IDEOGRAPH + 0xE894: 0x9621, //CJK UNIFIED IDEOGRAPH + 0xE895: 0x9628, //CJK UNIFIED IDEOGRAPH + 0xE896: 0x962E, //CJK UNIFIED IDEOGRAPH + 0xE897: 0x962F, //CJK UNIFIED IDEOGRAPH + 0xE898: 0x9642, //CJK UNIFIED IDEOGRAPH + 0xE899: 0x964C, //CJK UNIFIED IDEOGRAPH + 0xE89A: 0x964F, //CJK UNIFIED IDEOGRAPH + 0xE89B: 0x964B, //CJK UNIFIED IDEOGRAPH + 0xE89C: 0x9677, //CJK UNIFIED IDEOGRAPH + 0xE89D: 0x965C, //CJK UNIFIED IDEOGRAPH + 0xE89E: 0x965E, //CJK UNIFIED IDEOGRAPH + 0xE89F: 0x965D, //CJK UNIFIED IDEOGRAPH + 0xE8A0: 0x965F, //CJK UNIFIED IDEOGRAPH + 0xE8A1: 0x9666, //CJK UNIFIED IDEOGRAPH + 0xE8A2: 0x9672, //CJK UNIFIED IDEOGRAPH + 0xE8A3: 0x966C, //CJK UNIFIED IDEOGRAPH + 0xE8A4: 0x968D, //CJK UNIFIED IDEOGRAPH + 0xE8A5: 0x9698, //CJK UNIFIED IDEOGRAPH + 0xE8A6: 0x9695, //CJK UNIFIED IDEOGRAPH + 0xE8A7: 0x9697, //CJK UNIFIED IDEOGRAPH + 0xE8A8: 0x96AA, //CJK UNIFIED IDEOGRAPH + 0xE8A9: 0x96A7, //CJK UNIFIED IDEOGRAPH + 0xE8AA: 0x96B1, //CJK UNIFIED IDEOGRAPH + 0xE8AB: 0x96B2, //CJK UNIFIED IDEOGRAPH + 0xE8AC: 0x96B0, //CJK UNIFIED IDEOGRAPH + 0xE8AD: 0x96B4, //CJK UNIFIED IDEOGRAPH + 0xE8AE: 0x96B6, //CJK UNIFIED IDEOGRAPH + 0xE8AF: 0x96B8, //CJK UNIFIED IDEOGRAPH + 0xE8B0: 0x96B9, //CJK UNIFIED IDEOGRAPH + 0xE8B1: 0x96CE, //CJK UNIFIED IDEOGRAPH + 0xE8B2: 0x96CB, //CJK UNIFIED IDEOGRAPH + 0xE8B3: 0x96C9, //CJK UNIFIED IDEOGRAPH + 0xE8B4: 0x96CD, //CJK UNIFIED IDEOGRAPH + 0xE8B5: 0x894D, //CJK UNIFIED IDEOGRAPH + 0xE8B6: 0x96DC, //CJK UNIFIED IDEOGRAPH + 0xE8B7: 0x970D, //CJK UNIFIED IDEOGRAPH + 0xE8B8: 0x96D5, //CJK UNIFIED IDEOGRAPH + 0xE8B9: 0x96F9, //CJK UNIFIED IDEOGRAPH + 0xE8BA: 0x9704, //CJK UNIFIED IDEOGRAPH + 0xE8BB: 0x9706, //CJK UNIFIED IDEOGRAPH + 0xE8BC: 0x9708, //CJK UNIFIED IDEOGRAPH + 0xE8BD: 0x9713, //CJK UNIFIED IDEOGRAPH + 0xE8BE: 0x970E, //CJK UNIFIED IDEOGRAPH + 0xE8BF: 0x9711, //CJK UNIFIED IDEOGRAPH + 0xE8C0: 0x970F, //CJK UNIFIED IDEOGRAPH + 0xE8C1: 0x9716, //CJK UNIFIED IDEOGRAPH + 0xE8C2: 0x9719, //CJK UNIFIED IDEOGRAPH + 0xE8C3: 0x9724, //CJK UNIFIED IDEOGRAPH + 0xE8C4: 0x972A, //CJK UNIFIED IDEOGRAPH + 0xE8C5: 0x9730, //CJK UNIFIED IDEOGRAPH + 0xE8C6: 0x9739, //CJK UNIFIED IDEOGRAPH + 0xE8C7: 0x973D, //CJK UNIFIED IDEOGRAPH + 0xE8C8: 0x973E, //CJK UNIFIED IDEOGRAPH + 0xE8C9: 0x9744, //CJK UNIFIED IDEOGRAPH + 0xE8CA: 0x9746, //CJK UNIFIED IDEOGRAPH + 0xE8CB: 0x9748, //CJK UNIFIED IDEOGRAPH + 0xE8CC: 0x9742, //CJK UNIFIED IDEOGRAPH + 0xE8CD: 0x9749, //CJK UNIFIED IDEOGRAPH + 0xE8CE: 0x975C, //CJK UNIFIED IDEOGRAPH + 0xE8CF: 0x9760, //CJK UNIFIED IDEOGRAPH + 0xE8D0: 0x9764, //CJK UNIFIED IDEOGRAPH + 0xE8D1: 0x9766, //CJK UNIFIED IDEOGRAPH + 0xE8D2: 0x9768, //CJK UNIFIED IDEOGRAPH + 0xE8D3: 0x52D2, //CJK UNIFIED IDEOGRAPH + 0xE8D4: 0x976B, //CJK UNIFIED IDEOGRAPH + 0xE8D5: 0x9771, //CJK UNIFIED IDEOGRAPH + 0xE8D6: 0x9779, //CJK UNIFIED IDEOGRAPH + 0xE8D7: 0x9785, //CJK UNIFIED IDEOGRAPH + 0xE8D8: 0x977C, //CJK UNIFIED IDEOGRAPH + 0xE8D9: 0x9781, //CJK UNIFIED IDEOGRAPH + 0xE8DA: 0x977A, //CJK UNIFIED IDEOGRAPH + 0xE8DB: 0x9786, //CJK UNIFIED IDEOGRAPH + 0xE8DC: 0x978B, //CJK UNIFIED IDEOGRAPH + 0xE8DD: 0x978F, //CJK UNIFIED IDEOGRAPH + 0xE8DE: 0x9790, //CJK UNIFIED IDEOGRAPH + 0xE8DF: 0x979C, //CJK UNIFIED IDEOGRAPH + 0xE8E0: 0x97A8, //CJK UNIFIED IDEOGRAPH + 0xE8E1: 0x97A6, //CJK UNIFIED IDEOGRAPH + 0xE8E2: 0x97A3, //CJK UNIFIED IDEOGRAPH + 0xE8E3: 0x97B3, //CJK UNIFIED IDEOGRAPH + 0xE8E4: 0x97B4, //CJK UNIFIED IDEOGRAPH + 0xE8E5: 0x97C3, //CJK UNIFIED IDEOGRAPH + 0xE8E6: 0x97C6, //CJK UNIFIED IDEOGRAPH + 0xE8E7: 0x97C8, //CJK UNIFIED IDEOGRAPH + 0xE8E8: 0x97CB, //CJK UNIFIED IDEOGRAPH + 0xE8E9: 0x97DC, //CJK UNIFIED IDEOGRAPH + 0xE8EA: 0x97ED, //CJK UNIFIED IDEOGRAPH + 0xE8EB: 0x9F4F, //CJK UNIFIED IDEOGRAPH + 0xE8EC: 0x97F2, //CJK UNIFIED IDEOGRAPH + 0xE8ED: 0x7ADF, //CJK UNIFIED IDEOGRAPH + 0xE8EE: 0x97F6, //CJK UNIFIED IDEOGRAPH + 0xE8EF: 0x97F5, //CJK UNIFIED IDEOGRAPH + 0xE8F0: 0x980F, //CJK UNIFIED IDEOGRAPH + 0xE8F1: 0x980C, //CJK UNIFIED IDEOGRAPH + 0xE8F2: 0x9838, //CJK UNIFIED IDEOGRAPH + 0xE8F3: 0x9824, //CJK UNIFIED IDEOGRAPH + 0xE8F4: 0x9821, //CJK UNIFIED IDEOGRAPH + 0xE8F5: 0x9837, //CJK UNIFIED IDEOGRAPH + 0xE8F6: 0x983D, //CJK UNIFIED IDEOGRAPH + 0xE8F7: 0x9846, //CJK UNIFIED IDEOGRAPH + 0xE8F8: 0x984F, //CJK UNIFIED IDEOGRAPH + 0xE8F9: 0x984B, //CJK UNIFIED IDEOGRAPH + 0xE8FA: 0x986B, //CJK UNIFIED IDEOGRAPH + 0xE8FB: 0x986F, //CJK UNIFIED IDEOGRAPH + 0xE8FC: 0x9870, //CJK UNIFIED IDEOGRAPH + 0xE940: 0x9871, //CJK UNIFIED IDEOGRAPH + 0xE941: 0x9874, //CJK UNIFIED IDEOGRAPH + 0xE942: 0x9873, //CJK UNIFIED IDEOGRAPH + 0xE943: 0x98AA, //CJK UNIFIED IDEOGRAPH + 0xE944: 0x98AF, //CJK UNIFIED IDEOGRAPH + 0xE945: 0x98B1, //CJK UNIFIED IDEOGRAPH + 0xE946: 0x98B6, //CJK UNIFIED IDEOGRAPH + 0xE947: 0x98C4, //CJK UNIFIED IDEOGRAPH + 0xE948: 0x98C3, //CJK UNIFIED IDEOGRAPH + 0xE949: 0x98C6, //CJK UNIFIED IDEOGRAPH + 0xE94A: 0x98E9, //CJK UNIFIED IDEOGRAPH + 0xE94B: 0x98EB, //CJK UNIFIED IDEOGRAPH + 0xE94C: 0x9903, //CJK UNIFIED IDEOGRAPH + 0xE94D: 0x9909, //CJK UNIFIED IDEOGRAPH + 0xE94E: 0x9912, //CJK UNIFIED IDEOGRAPH + 0xE94F: 0x9914, //CJK UNIFIED IDEOGRAPH + 0xE950: 0x9918, //CJK UNIFIED IDEOGRAPH + 0xE951: 0x9921, //CJK UNIFIED IDEOGRAPH + 0xE952: 0x991D, //CJK UNIFIED IDEOGRAPH + 0xE953: 0x991E, //CJK UNIFIED IDEOGRAPH + 0xE954: 0x9924, //CJK UNIFIED IDEOGRAPH + 0xE955: 0x9920, //CJK UNIFIED IDEOGRAPH + 0xE956: 0x992C, //CJK UNIFIED IDEOGRAPH + 0xE957: 0x992E, //CJK UNIFIED IDEOGRAPH + 0xE958: 0x993D, //CJK UNIFIED IDEOGRAPH + 0xE959: 0x993E, //CJK UNIFIED IDEOGRAPH + 0xE95A: 0x9942, //CJK UNIFIED IDEOGRAPH + 0xE95B: 0x9949, //CJK UNIFIED IDEOGRAPH + 0xE95C: 0x9945, //CJK UNIFIED IDEOGRAPH + 0xE95D: 0x9950, //CJK UNIFIED IDEOGRAPH + 0xE95E: 0x994B, //CJK UNIFIED IDEOGRAPH + 0xE95F: 0x9951, //CJK UNIFIED IDEOGRAPH + 0xE960: 0x9952, //CJK UNIFIED IDEOGRAPH + 0xE961: 0x994C, //CJK UNIFIED IDEOGRAPH + 0xE962: 0x9955, //CJK UNIFIED IDEOGRAPH + 0xE963: 0x9997, //CJK UNIFIED IDEOGRAPH + 0xE964: 0x9998, //CJK UNIFIED IDEOGRAPH + 0xE965: 0x99A5, //CJK UNIFIED IDEOGRAPH + 0xE966: 0x99AD, //CJK UNIFIED IDEOGRAPH + 0xE967: 0x99AE, //CJK UNIFIED IDEOGRAPH + 0xE968: 0x99BC, //CJK UNIFIED IDEOGRAPH + 0xE969: 0x99DF, //CJK UNIFIED IDEOGRAPH + 0xE96A: 0x99DB, //CJK UNIFIED IDEOGRAPH + 0xE96B: 0x99DD, //CJK UNIFIED IDEOGRAPH + 0xE96C: 0x99D8, //CJK UNIFIED IDEOGRAPH + 0xE96D: 0x99D1, //CJK UNIFIED IDEOGRAPH + 0xE96E: 0x99ED, //CJK UNIFIED IDEOGRAPH + 0xE96F: 0x99EE, //CJK UNIFIED IDEOGRAPH + 0xE970: 0x99F1, //CJK UNIFIED IDEOGRAPH + 0xE971: 0x99F2, //CJK UNIFIED IDEOGRAPH + 0xE972: 0x99FB, //CJK UNIFIED IDEOGRAPH + 0xE973: 0x99F8, //CJK UNIFIED IDEOGRAPH + 0xE974: 0x9A01, //CJK UNIFIED IDEOGRAPH + 0xE975: 0x9A0F, //CJK UNIFIED IDEOGRAPH + 0xE976: 0x9A05, //CJK UNIFIED IDEOGRAPH + 0xE977: 0x99E2, //CJK UNIFIED IDEOGRAPH + 0xE978: 0x9A19, //CJK UNIFIED IDEOGRAPH + 0xE979: 0x9A2B, //CJK UNIFIED IDEOGRAPH + 0xE97A: 0x9A37, //CJK UNIFIED IDEOGRAPH + 0xE97B: 0x9A45, //CJK UNIFIED IDEOGRAPH + 0xE97C: 0x9A42, //CJK UNIFIED IDEOGRAPH + 0xE97D: 0x9A40, //CJK UNIFIED IDEOGRAPH + 0xE97E: 0x9A43, //CJK UNIFIED IDEOGRAPH + 0xE980: 0x9A3E, //CJK UNIFIED IDEOGRAPH + 0xE981: 0x9A55, //CJK UNIFIED IDEOGRAPH + 0xE982: 0x9A4D, //CJK UNIFIED IDEOGRAPH + 0xE983: 0x9A5B, //CJK UNIFIED IDEOGRAPH + 0xE984: 0x9A57, //CJK UNIFIED IDEOGRAPH + 0xE985: 0x9A5F, //CJK UNIFIED IDEOGRAPH + 0xE986: 0x9A62, //CJK UNIFIED IDEOGRAPH + 0xE987: 0x9A65, //CJK UNIFIED IDEOGRAPH + 0xE988: 0x9A64, //CJK UNIFIED IDEOGRAPH + 0xE989: 0x9A69, //CJK UNIFIED IDEOGRAPH + 0xE98A: 0x9A6B, //CJK UNIFIED IDEOGRAPH + 0xE98B: 0x9A6A, //CJK UNIFIED IDEOGRAPH + 0xE98C: 0x9AAD, //CJK UNIFIED IDEOGRAPH + 0xE98D: 0x9AB0, //CJK UNIFIED IDEOGRAPH + 0xE98E: 0x9ABC, //CJK UNIFIED IDEOGRAPH + 0xE98F: 0x9AC0, //CJK UNIFIED IDEOGRAPH + 0xE990: 0x9ACF, //CJK UNIFIED IDEOGRAPH + 0xE991: 0x9AD1, //CJK UNIFIED IDEOGRAPH + 0xE992: 0x9AD3, //CJK UNIFIED IDEOGRAPH + 0xE993: 0x9AD4, //CJK UNIFIED IDEOGRAPH + 0xE994: 0x9ADE, //CJK UNIFIED IDEOGRAPH + 0xE995: 0x9ADF, //CJK UNIFIED IDEOGRAPH + 0xE996: 0x9AE2, //CJK UNIFIED IDEOGRAPH + 0xE997: 0x9AE3, //CJK UNIFIED IDEOGRAPH + 0xE998: 0x9AE6, //CJK UNIFIED IDEOGRAPH + 0xE999: 0x9AEF, //CJK UNIFIED IDEOGRAPH + 0xE99A: 0x9AEB, //CJK UNIFIED IDEOGRAPH + 0xE99B: 0x9AEE, //CJK UNIFIED IDEOGRAPH + 0xE99C: 0x9AF4, //CJK UNIFIED IDEOGRAPH + 0xE99D: 0x9AF1, //CJK UNIFIED IDEOGRAPH + 0xE99E: 0x9AF7, //CJK UNIFIED IDEOGRAPH + 0xE99F: 0x9AFB, //CJK UNIFIED IDEOGRAPH + 0xE9A0: 0x9B06, //CJK UNIFIED IDEOGRAPH + 0xE9A1: 0x9B18, //CJK UNIFIED IDEOGRAPH + 0xE9A2: 0x9B1A, //CJK UNIFIED IDEOGRAPH + 0xE9A3: 0x9B1F, //CJK UNIFIED IDEOGRAPH + 0xE9A4: 0x9B22, //CJK UNIFIED IDEOGRAPH + 0xE9A5: 0x9B23, //CJK UNIFIED IDEOGRAPH + 0xE9A6: 0x9B25, //CJK UNIFIED IDEOGRAPH + 0xE9A7: 0x9B27, //CJK UNIFIED IDEOGRAPH + 0xE9A8: 0x9B28, //CJK UNIFIED IDEOGRAPH + 0xE9A9: 0x9B29, //CJK UNIFIED IDEOGRAPH + 0xE9AA: 0x9B2A, //CJK UNIFIED IDEOGRAPH + 0xE9AB: 0x9B2E, //CJK UNIFIED IDEOGRAPH + 0xE9AC: 0x9B2F, //CJK UNIFIED IDEOGRAPH + 0xE9AD: 0x9B32, //CJK UNIFIED IDEOGRAPH + 0xE9AE: 0x9B44, //CJK UNIFIED IDEOGRAPH + 0xE9AF: 0x9B43, //CJK UNIFIED IDEOGRAPH + 0xE9B0: 0x9B4F, //CJK UNIFIED IDEOGRAPH + 0xE9B1: 0x9B4D, //CJK UNIFIED IDEOGRAPH + 0xE9B2: 0x9B4E, //CJK UNIFIED IDEOGRAPH + 0xE9B3: 0x9B51, //CJK UNIFIED IDEOGRAPH + 0xE9B4: 0x9B58, //CJK UNIFIED IDEOGRAPH + 0xE9B5: 0x9B74, //CJK UNIFIED IDEOGRAPH + 0xE9B6: 0x9B93, //CJK UNIFIED IDEOGRAPH + 0xE9B7: 0x9B83, //CJK UNIFIED IDEOGRAPH + 0xE9B8: 0x9B91, //CJK UNIFIED IDEOGRAPH + 0xE9B9: 0x9B96, //CJK UNIFIED IDEOGRAPH + 0xE9BA: 0x9B97, //CJK UNIFIED IDEOGRAPH + 0xE9BB: 0x9B9F, //CJK UNIFIED IDEOGRAPH + 0xE9BC: 0x9BA0, //CJK UNIFIED IDEOGRAPH + 0xE9BD: 0x9BA8, //CJK UNIFIED IDEOGRAPH + 0xE9BE: 0x9BB4, //CJK UNIFIED IDEOGRAPH + 0xE9BF: 0x9BC0, //CJK UNIFIED IDEOGRAPH + 0xE9C0: 0x9BCA, //CJK UNIFIED IDEOGRAPH + 0xE9C1: 0x9BB9, //CJK UNIFIED IDEOGRAPH + 0xE9C2: 0x9BC6, //CJK UNIFIED IDEOGRAPH + 0xE9C3: 0x9BCF, //CJK UNIFIED IDEOGRAPH + 0xE9C4: 0x9BD1, //CJK UNIFIED IDEOGRAPH + 0xE9C5: 0x9BD2, //CJK UNIFIED IDEOGRAPH + 0xE9C6: 0x9BE3, //CJK UNIFIED IDEOGRAPH + 0xE9C7: 0x9BE2, //CJK UNIFIED IDEOGRAPH + 0xE9C8: 0x9BE4, //CJK UNIFIED IDEOGRAPH + 0xE9C9: 0x9BD4, //CJK UNIFIED IDEOGRAPH + 0xE9CA: 0x9BE1, //CJK UNIFIED IDEOGRAPH + 0xE9CB: 0x9C3A, //CJK UNIFIED IDEOGRAPH + 0xE9CC: 0x9BF2, //CJK UNIFIED IDEOGRAPH + 0xE9CD: 0x9BF1, //CJK UNIFIED IDEOGRAPH + 0xE9CE: 0x9BF0, //CJK UNIFIED IDEOGRAPH + 0xE9CF: 0x9C15, //CJK UNIFIED IDEOGRAPH + 0xE9D0: 0x9C14, //CJK UNIFIED IDEOGRAPH + 0xE9D1: 0x9C09, //CJK UNIFIED IDEOGRAPH + 0xE9D2: 0x9C13, //CJK UNIFIED IDEOGRAPH + 0xE9D3: 0x9C0C, //CJK UNIFIED IDEOGRAPH + 0xE9D4: 0x9C06, //CJK UNIFIED IDEOGRAPH + 0xE9D5: 0x9C08, //CJK UNIFIED IDEOGRAPH + 0xE9D6: 0x9C12, //CJK UNIFIED IDEOGRAPH + 0xE9D7: 0x9C0A, //CJK UNIFIED IDEOGRAPH + 0xE9D8: 0x9C04, //CJK UNIFIED IDEOGRAPH + 0xE9D9: 0x9C2E, //CJK UNIFIED IDEOGRAPH + 0xE9DA: 0x9C1B, //CJK UNIFIED IDEOGRAPH + 0xE9DB: 0x9C25, //CJK UNIFIED IDEOGRAPH + 0xE9DC: 0x9C24, //CJK UNIFIED IDEOGRAPH + 0xE9DD: 0x9C21, //CJK UNIFIED IDEOGRAPH + 0xE9DE: 0x9C30, //CJK UNIFIED IDEOGRAPH + 0xE9DF: 0x9C47, //CJK UNIFIED IDEOGRAPH + 0xE9E0: 0x9C32, //CJK UNIFIED IDEOGRAPH + 0xE9E1: 0x9C46, //CJK UNIFIED IDEOGRAPH + 0xE9E2: 0x9C3E, //CJK UNIFIED IDEOGRAPH + 0xE9E3: 0x9C5A, //CJK UNIFIED IDEOGRAPH + 0xE9E4: 0x9C60, //CJK UNIFIED IDEOGRAPH + 0xE9E5: 0x9C67, //CJK UNIFIED IDEOGRAPH + 0xE9E6: 0x9C76, //CJK UNIFIED IDEOGRAPH + 0xE9E7: 0x9C78, //CJK UNIFIED IDEOGRAPH + 0xE9E8: 0x9CE7, //CJK UNIFIED IDEOGRAPH + 0xE9E9: 0x9CEC, //CJK UNIFIED IDEOGRAPH + 0xE9EA: 0x9CF0, //CJK UNIFIED IDEOGRAPH + 0xE9EB: 0x9D09, //CJK UNIFIED IDEOGRAPH + 0xE9EC: 0x9D08, //CJK UNIFIED IDEOGRAPH + 0xE9ED: 0x9CEB, //CJK UNIFIED IDEOGRAPH + 0xE9EE: 0x9D03, //CJK UNIFIED IDEOGRAPH + 0xE9EF: 0x9D06, //CJK UNIFIED IDEOGRAPH + 0xE9F0: 0x9D2A, //CJK UNIFIED IDEOGRAPH + 0xE9F1: 0x9D26, //CJK UNIFIED IDEOGRAPH + 0xE9F2: 0x9DAF, //CJK UNIFIED IDEOGRAPH + 0xE9F3: 0x9D23, //CJK UNIFIED IDEOGRAPH + 0xE9F4: 0x9D1F, //CJK UNIFIED IDEOGRAPH + 0xE9F5: 0x9D44, //CJK UNIFIED IDEOGRAPH + 0xE9F6: 0x9D15, //CJK UNIFIED IDEOGRAPH + 0xE9F7: 0x9D12, //CJK UNIFIED IDEOGRAPH + 0xE9F8: 0x9D41, //CJK UNIFIED IDEOGRAPH + 0xE9F9: 0x9D3F, //CJK UNIFIED IDEOGRAPH + 0xE9FA: 0x9D3E, //CJK UNIFIED IDEOGRAPH + 0xE9FB: 0x9D46, //CJK UNIFIED IDEOGRAPH + 0xE9FC: 0x9D48, //CJK UNIFIED IDEOGRAPH + 0xEA40: 0x9D5D, //CJK UNIFIED IDEOGRAPH + 0xEA41: 0x9D5E, //CJK UNIFIED IDEOGRAPH + 0xEA42: 0x9D64, //CJK UNIFIED IDEOGRAPH + 0xEA43: 0x9D51, //CJK UNIFIED IDEOGRAPH + 0xEA44: 0x9D50, //CJK UNIFIED IDEOGRAPH + 0xEA45: 0x9D59, //CJK UNIFIED IDEOGRAPH + 0xEA46: 0x9D72, //CJK UNIFIED IDEOGRAPH + 0xEA47: 0x9D89, //CJK UNIFIED IDEOGRAPH + 0xEA48: 0x9D87, //CJK UNIFIED IDEOGRAPH + 0xEA49: 0x9DAB, //CJK UNIFIED IDEOGRAPH + 0xEA4A: 0x9D6F, //CJK UNIFIED IDEOGRAPH + 0xEA4B: 0x9D7A, //CJK UNIFIED IDEOGRAPH + 0xEA4C: 0x9D9A, //CJK UNIFIED IDEOGRAPH + 0xEA4D: 0x9DA4, //CJK UNIFIED IDEOGRAPH + 0xEA4E: 0x9DA9, //CJK UNIFIED IDEOGRAPH + 0xEA4F: 0x9DB2, //CJK UNIFIED IDEOGRAPH + 0xEA50: 0x9DC4, //CJK UNIFIED IDEOGRAPH + 0xEA51: 0x9DC1, //CJK UNIFIED IDEOGRAPH + 0xEA52: 0x9DBB, //CJK UNIFIED IDEOGRAPH + 0xEA53: 0x9DB8, //CJK UNIFIED IDEOGRAPH + 0xEA54: 0x9DBA, //CJK UNIFIED IDEOGRAPH + 0xEA55: 0x9DC6, //CJK UNIFIED IDEOGRAPH + 0xEA56: 0x9DCF, //CJK UNIFIED IDEOGRAPH + 0xEA57: 0x9DC2, //CJK UNIFIED IDEOGRAPH + 0xEA58: 0x9DD9, //CJK UNIFIED IDEOGRAPH + 0xEA59: 0x9DD3, //CJK UNIFIED IDEOGRAPH + 0xEA5A: 0x9DF8, //CJK UNIFIED IDEOGRAPH + 0xEA5B: 0x9DE6, //CJK UNIFIED IDEOGRAPH + 0xEA5C: 0x9DED, //CJK UNIFIED IDEOGRAPH + 0xEA5D: 0x9DEF, //CJK UNIFIED IDEOGRAPH + 0xEA5E: 0x9DFD, //CJK UNIFIED IDEOGRAPH + 0xEA5F: 0x9E1A, //CJK UNIFIED IDEOGRAPH + 0xEA60: 0x9E1B, //CJK UNIFIED IDEOGRAPH + 0xEA61: 0x9E1E, //CJK UNIFIED IDEOGRAPH + 0xEA62: 0x9E75, //CJK UNIFIED IDEOGRAPH + 0xEA63: 0x9E79, //CJK UNIFIED IDEOGRAPH + 0xEA64: 0x9E7D, //CJK UNIFIED IDEOGRAPH + 0xEA65: 0x9E81, //CJK UNIFIED IDEOGRAPH + 0xEA66: 0x9E88, //CJK UNIFIED IDEOGRAPH + 0xEA67: 0x9E8B, //CJK UNIFIED IDEOGRAPH + 0xEA68: 0x9E8C, //CJK UNIFIED IDEOGRAPH + 0xEA69: 0x9E92, //CJK UNIFIED IDEOGRAPH + 0xEA6A: 0x9E95, //CJK UNIFIED IDEOGRAPH + 0xEA6B: 0x9E91, //CJK UNIFIED IDEOGRAPH + 0xEA6C: 0x9E9D, //CJK UNIFIED IDEOGRAPH + 0xEA6D: 0x9EA5, //CJK UNIFIED IDEOGRAPH + 0xEA6E: 0x9EA9, //CJK UNIFIED IDEOGRAPH + 0xEA6F: 0x9EB8, //CJK UNIFIED IDEOGRAPH + 0xEA70: 0x9EAA, //CJK UNIFIED IDEOGRAPH + 0xEA71: 0x9EAD, //CJK UNIFIED IDEOGRAPH + 0xEA72: 0x9761, //CJK UNIFIED IDEOGRAPH + 0xEA73: 0x9ECC, //CJK UNIFIED IDEOGRAPH + 0xEA74: 0x9ECE, //CJK UNIFIED IDEOGRAPH + 0xEA75: 0x9ECF, //CJK UNIFIED IDEOGRAPH + 0xEA76: 0x9ED0, //CJK UNIFIED IDEOGRAPH + 0xEA77: 0x9ED4, //CJK UNIFIED IDEOGRAPH + 0xEA78: 0x9EDC, //CJK UNIFIED IDEOGRAPH + 0xEA79: 0x9EDE, //CJK UNIFIED IDEOGRAPH + 0xEA7A: 0x9EDD, //CJK UNIFIED IDEOGRAPH + 0xEA7B: 0x9EE0, //CJK UNIFIED IDEOGRAPH + 0xEA7C: 0x9EE5, //CJK UNIFIED IDEOGRAPH + 0xEA7D: 0x9EE8, //CJK UNIFIED IDEOGRAPH + 0xEA7E: 0x9EEF, //CJK UNIFIED IDEOGRAPH + 0xEA80: 0x9EF4, //CJK UNIFIED IDEOGRAPH + 0xEA81: 0x9EF6, //CJK UNIFIED IDEOGRAPH + 0xEA82: 0x9EF7, //CJK UNIFIED IDEOGRAPH + 0xEA83: 0x9EF9, //CJK UNIFIED IDEOGRAPH + 0xEA84: 0x9EFB, //CJK UNIFIED IDEOGRAPH + 0xEA85: 0x9EFC, //CJK UNIFIED IDEOGRAPH + 0xEA86: 0x9EFD, //CJK UNIFIED IDEOGRAPH + 0xEA87: 0x9F07, //CJK UNIFIED IDEOGRAPH + 0xEA88: 0x9F08, //CJK UNIFIED IDEOGRAPH + 0xEA89: 0x76B7, //CJK UNIFIED IDEOGRAPH + 0xEA8A: 0x9F15, //CJK UNIFIED IDEOGRAPH + 0xEA8B: 0x9F21, //CJK UNIFIED IDEOGRAPH + 0xEA8C: 0x9F2C, //CJK UNIFIED IDEOGRAPH + 0xEA8D: 0x9F3E, //CJK UNIFIED IDEOGRAPH + 0xEA8E: 0x9F4A, //CJK UNIFIED IDEOGRAPH + 0xEA8F: 0x9F52, //CJK UNIFIED IDEOGRAPH + 0xEA90: 0x9F54, //CJK UNIFIED IDEOGRAPH + 0xEA91: 0x9F63, //CJK UNIFIED IDEOGRAPH + 0xEA92: 0x9F5F, //CJK UNIFIED IDEOGRAPH + 0xEA93: 0x9F60, //CJK UNIFIED IDEOGRAPH + 0xEA94: 0x9F61, //CJK UNIFIED IDEOGRAPH + 0xEA95: 0x9F66, //CJK UNIFIED IDEOGRAPH + 0xEA96: 0x9F67, //CJK UNIFIED IDEOGRAPH + 0xEA97: 0x9F6C, //CJK UNIFIED IDEOGRAPH + 0xEA98: 0x9F6A, //CJK UNIFIED IDEOGRAPH + 0xEA99: 0x9F77, //CJK UNIFIED IDEOGRAPH + 0xEA9A: 0x9F72, //CJK UNIFIED IDEOGRAPH + 0xEA9B: 0x9F76, //CJK UNIFIED IDEOGRAPH + 0xEA9C: 0x9F95, //CJK UNIFIED IDEOGRAPH + 0xEA9D: 0x9F9C, //CJK UNIFIED IDEOGRAPH + 0xEA9E: 0x9FA0, //CJK UNIFIED IDEOGRAPH + 0xEA9F: 0x582F, //CJK UNIFIED IDEOGRAPH + 0xEAA0: 0x69C7, //CJK UNIFIED IDEOGRAPH + 0xEAA1: 0x9059, //CJK UNIFIED IDEOGRAPH + 0xEAA2: 0x7464, //CJK UNIFIED IDEOGRAPH + 0xEAA3: 0x51DC, //CJK UNIFIED IDEOGRAPH + 0xEAA4: 0x7199, //CJK UNIFIED IDEOGRAPH + 0xED40: 0x7E8A, //CJK UNIFIED IDEOGRAPH + 0xED41: 0x891C, //CJK UNIFIED IDEOGRAPH + 0xED42: 0x9348, //CJK UNIFIED IDEOGRAPH + 0xED43: 0x9288, //CJK UNIFIED IDEOGRAPH + 0xED44: 0x84DC, //CJK UNIFIED IDEOGRAPH + 0xED45: 0x4FC9, //CJK UNIFIED IDEOGRAPH + 0xED46: 0x70BB, //CJK UNIFIED IDEOGRAPH + 0xED47: 0x6631, //CJK UNIFIED IDEOGRAPH + 0xED48: 0x68C8, //CJK UNIFIED IDEOGRAPH + 0xED49: 0x92F9, //CJK UNIFIED IDEOGRAPH + 0xED4A: 0x66FB, //CJK UNIFIED IDEOGRAPH + 0xED4B: 0x5F45, //CJK UNIFIED IDEOGRAPH + 0xED4C: 0x4E28, //CJK UNIFIED IDEOGRAPH + 0xED4D: 0x4EE1, //CJK UNIFIED IDEOGRAPH + 0xED4E: 0x4EFC, //CJK UNIFIED IDEOGRAPH + 0xED4F: 0x4F00, //CJK UNIFIED IDEOGRAPH + 0xED50: 0x4F03, //CJK UNIFIED IDEOGRAPH + 0xED51: 0x4F39, //CJK UNIFIED IDEOGRAPH + 0xED52: 0x4F56, //CJK UNIFIED IDEOGRAPH + 0xED53: 0x4F92, //CJK UNIFIED IDEOGRAPH + 0xED54: 0x4F8A, //CJK UNIFIED IDEOGRAPH + 0xED55: 0x4F9A, //CJK UNIFIED IDEOGRAPH + 0xED56: 0x4F94, //CJK UNIFIED IDEOGRAPH + 0xED57: 0x4FCD, //CJK UNIFIED IDEOGRAPH + 0xED58: 0x5040, //CJK UNIFIED IDEOGRAPH + 0xED59: 0x5022, //CJK UNIFIED IDEOGRAPH + 0xED5A: 0x4FFF, //CJK UNIFIED IDEOGRAPH + 0xED5B: 0x501E, //CJK UNIFIED IDEOGRAPH + 0xED5C: 0x5046, //CJK UNIFIED IDEOGRAPH + 0xED5D: 0x5070, //CJK UNIFIED IDEOGRAPH + 0xED5E: 0x5042, //CJK UNIFIED IDEOGRAPH + 0xED5F: 0x5094, //CJK UNIFIED IDEOGRAPH + 0xED60: 0x50F4, //CJK UNIFIED IDEOGRAPH + 0xED61: 0x50D8, //CJK UNIFIED IDEOGRAPH + 0xED62: 0x514A, //CJK UNIFIED IDEOGRAPH + 0xED63: 0x5164, //CJK UNIFIED IDEOGRAPH + 0xED64: 0x519D, //CJK UNIFIED IDEOGRAPH + 0xED65: 0x51BE, //CJK UNIFIED IDEOGRAPH + 0xED66: 0x51EC, //CJK UNIFIED IDEOGRAPH + 0xED67: 0x5215, //CJK UNIFIED IDEOGRAPH + 0xED68: 0x529C, //CJK UNIFIED IDEOGRAPH + 0xED69: 0x52A6, //CJK UNIFIED IDEOGRAPH + 0xED6A: 0x52C0, //CJK UNIFIED IDEOGRAPH + 0xED6B: 0x52DB, //CJK UNIFIED IDEOGRAPH + 0xED6C: 0x5300, //CJK UNIFIED IDEOGRAPH + 0xED6D: 0x5307, //CJK UNIFIED IDEOGRAPH + 0xED6E: 0x5324, //CJK UNIFIED IDEOGRAPH + 0xED6F: 0x5372, //CJK UNIFIED IDEOGRAPH + 0xED70: 0x5393, //CJK UNIFIED IDEOGRAPH + 0xED71: 0x53B2, //CJK UNIFIED IDEOGRAPH + 0xED72: 0x53DD, //CJK UNIFIED IDEOGRAPH + 0xED73: 0xFA0E, //CJK COMPATIBILITY IDEOGRAPH + 0xED74: 0x549C, //CJK UNIFIED IDEOGRAPH + 0xED75: 0x548A, //CJK UNIFIED IDEOGRAPH + 0xED76: 0x54A9, //CJK UNIFIED IDEOGRAPH + 0xED77: 0x54FF, //CJK UNIFIED IDEOGRAPH + 0xED78: 0x5586, //CJK UNIFIED IDEOGRAPH + 0xED79: 0x5759, //CJK UNIFIED IDEOGRAPH + 0xED7A: 0x5765, //CJK UNIFIED IDEOGRAPH + 0xED7B: 0x57AC, //CJK UNIFIED IDEOGRAPH + 0xED7C: 0x57C8, //CJK UNIFIED IDEOGRAPH + 0xED7D: 0x57C7, //CJK UNIFIED IDEOGRAPH + 0xED7E: 0xFA0F, //CJK COMPATIBILITY IDEOGRAPH + 0xED80: 0xFA10, //CJK COMPATIBILITY IDEOGRAPH + 0xED81: 0x589E, //CJK UNIFIED IDEOGRAPH + 0xED82: 0x58B2, //CJK UNIFIED IDEOGRAPH + 0xED83: 0x590B, //CJK UNIFIED IDEOGRAPH + 0xED84: 0x5953, //CJK UNIFIED IDEOGRAPH + 0xED85: 0x595B, //CJK UNIFIED IDEOGRAPH + 0xED86: 0x595D, //CJK UNIFIED IDEOGRAPH + 0xED87: 0x5963, //CJK UNIFIED IDEOGRAPH + 0xED88: 0x59A4, //CJK UNIFIED IDEOGRAPH + 0xED89: 0x59BA, //CJK UNIFIED IDEOGRAPH + 0xED8A: 0x5B56, //CJK UNIFIED IDEOGRAPH + 0xED8B: 0x5BC0, //CJK UNIFIED IDEOGRAPH + 0xED8C: 0x752F, //CJK UNIFIED IDEOGRAPH + 0xED8D: 0x5BD8, //CJK UNIFIED IDEOGRAPH + 0xED8E: 0x5BEC, //CJK UNIFIED IDEOGRAPH + 0xED8F: 0x5C1E, //CJK UNIFIED IDEOGRAPH + 0xED90: 0x5CA6, //CJK UNIFIED IDEOGRAPH + 0xED91: 0x5CBA, //CJK UNIFIED IDEOGRAPH + 0xED92: 0x5CF5, //CJK UNIFIED IDEOGRAPH + 0xED93: 0x5D27, //CJK UNIFIED IDEOGRAPH + 0xED94: 0x5D53, //CJK UNIFIED IDEOGRAPH + 0xED95: 0xFA11, //CJK COMPATIBILITY IDEOGRAPH + 0xED96: 0x5D42, //CJK UNIFIED IDEOGRAPH + 0xED97: 0x5D6D, //CJK UNIFIED IDEOGRAPH + 0xED98: 0x5DB8, //CJK UNIFIED IDEOGRAPH + 0xED99: 0x5DB9, //CJK UNIFIED IDEOGRAPH + 0xED9A: 0x5DD0, //CJK UNIFIED IDEOGRAPH + 0xED9B: 0x5F21, //CJK UNIFIED IDEOGRAPH + 0xED9C: 0x5F34, //CJK UNIFIED IDEOGRAPH + 0xED9D: 0x5F67, //CJK UNIFIED IDEOGRAPH + 0xED9E: 0x5FB7, //CJK UNIFIED IDEOGRAPH + 0xED9F: 0x5FDE, //CJK UNIFIED IDEOGRAPH + 0xEDA0: 0x605D, //CJK UNIFIED IDEOGRAPH + 0xEDA1: 0x6085, //CJK UNIFIED IDEOGRAPH + 0xEDA2: 0x608A, //CJK UNIFIED IDEOGRAPH + 0xEDA3: 0x60DE, //CJK UNIFIED IDEOGRAPH + 0xEDA4: 0x60D5, //CJK UNIFIED IDEOGRAPH + 0xEDA5: 0x6120, //CJK UNIFIED IDEOGRAPH + 0xEDA6: 0x60F2, //CJK UNIFIED IDEOGRAPH + 0xEDA7: 0x6111, //CJK UNIFIED IDEOGRAPH + 0xEDA8: 0x6137, //CJK UNIFIED IDEOGRAPH + 0xEDA9: 0x6130, //CJK UNIFIED IDEOGRAPH + 0xEDAA: 0x6198, //CJK UNIFIED IDEOGRAPH + 0xEDAB: 0x6213, //CJK UNIFIED IDEOGRAPH + 0xEDAC: 0x62A6, //CJK UNIFIED IDEOGRAPH + 0xEDAD: 0x63F5, //CJK UNIFIED IDEOGRAPH + 0xEDAE: 0x6460, //CJK UNIFIED IDEOGRAPH + 0xEDAF: 0x649D, //CJK UNIFIED IDEOGRAPH + 0xEDB0: 0x64CE, //CJK UNIFIED IDEOGRAPH + 0xEDB1: 0x654E, //CJK UNIFIED IDEOGRAPH + 0xEDB2: 0x6600, //CJK UNIFIED IDEOGRAPH + 0xEDB3: 0x6615, //CJK UNIFIED IDEOGRAPH + 0xEDB4: 0x663B, //CJK UNIFIED IDEOGRAPH + 0xEDB5: 0x6609, //CJK UNIFIED IDEOGRAPH + 0xEDB6: 0x662E, //CJK UNIFIED IDEOGRAPH + 0xEDB7: 0x661E, //CJK UNIFIED IDEOGRAPH + 0xEDB8: 0x6624, //CJK UNIFIED IDEOGRAPH + 0xEDB9: 0x6665, //CJK UNIFIED IDEOGRAPH + 0xEDBA: 0x6657, //CJK UNIFIED IDEOGRAPH + 0xEDBB: 0x6659, //CJK UNIFIED IDEOGRAPH + 0xEDBC: 0xFA12, //CJK COMPATIBILITY IDEOGRAPH + 0xEDBD: 0x6673, //CJK UNIFIED IDEOGRAPH + 0xEDBE: 0x6699, //CJK UNIFIED IDEOGRAPH + 0xEDBF: 0x66A0, //CJK UNIFIED IDEOGRAPH + 0xEDC0: 0x66B2, //CJK UNIFIED IDEOGRAPH + 0xEDC1: 0x66BF, //CJK UNIFIED IDEOGRAPH + 0xEDC2: 0x66FA, //CJK UNIFIED IDEOGRAPH + 0xEDC3: 0x670E, //CJK UNIFIED IDEOGRAPH + 0xEDC4: 0xF929, //CJK COMPATIBILITY IDEOGRAPH + 0xEDC5: 0x6766, //CJK UNIFIED IDEOGRAPH + 0xEDC6: 0x67BB, //CJK UNIFIED IDEOGRAPH + 0xEDC7: 0x6852, //CJK UNIFIED IDEOGRAPH + 0xEDC8: 0x67C0, //CJK UNIFIED IDEOGRAPH + 0xEDC9: 0x6801, //CJK UNIFIED IDEOGRAPH + 0xEDCA: 0x6844, //CJK UNIFIED IDEOGRAPH + 0xEDCB: 0x68CF, //CJK UNIFIED IDEOGRAPH + 0xEDCC: 0xFA13, //CJK COMPATIBILITY IDEOGRAPH + 0xEDCD: 0x6968, //CJK UNIFIED IDEOGRAPH + 0xEDCE: 0xFA14, //CJK COMPATIBILITY IDEOGRAPH + 0xEDCF: 0x6998, //CJK UNIFIED IDEOGRAPH + 0xEDD0: 0x69E2, //CJK UNIFIED IDEOGRAPH + 0xEDD1: 0x6A30, //CJK UNIFIED IDEOGRAPH + 0xEDD2: 0x6A6B, //CJK UNIFIED IDEOGRAPH + 0xEDD3: 0x6A46, //CJK UNIFIED IDEOGRAPH + 0xEDD4: 0x6A73, //CJK UNIFIED IDEOGRAPH + 0xEDD5: 0x6A7E, //CJK UNIFIED IDEOGRAPH + 0xEDD6: 0x6AE2, //CJK UNIFIED IDEOGRAPH + 0xEDD7: 0x6AE4, //CJK UNIFIED IDEOGRAPH + 0xEDD8: 0x6BD6, //CJK UNIFIED IDEOGRAPH + 0xEDD9: 0x6C3F, //CJK UNIFIED IDEOGRAPH + 0xEDDA: 0x6C5C, //CJK UNIFIED IDEOGRAPH + 0xEDDB: 0x6C86, //CJK UNIFIED IDEOGRAPH + 0xEDDC: 0x6C6F, //CJK UNIFIED IDEOGRAPH + 0xEDDD: 0x6CDA, //CJK UNIFIED IDEOGRAPH + 0xEDDE: 0x6D04, //CJK UNIFIED IDEOGRAPH + 0xEDDF: 0x6D87, //CJK UNIFIED IDEOGRAPH + 0xEDE0: 0x6D6F, //CJK UNIFIED IDEOGRAPH + 0xEDE1: 0x6D96, //CJK UNIFIED IDEOGRAPH + 0xEDE2: 0x6DAC, //CJK UNIFIED IDEOGRAPH + 0xEDE3: 0x6DCF, //CJK UNIFIED IDEOGRAPH + 0xEDE4: 0x6DF8, //CJK UNIFIED IDEOGRAPH + 0xEDE5: 0x6DF2, //CJK UNIFIED IDEOGRAPH + 0xEDE6: 0x6DFC, //CJK UNIFIED IDEOGRAPH + 0xEDE7: 0x6E39, //CJK UNIFIED IDEOGRAPH + 0xEDE8: 0x6E5C, //CJK UNIFIED IDEOGRAPH + 0xEDE9: 0x6E27, //CJK UNIFIED IDEOGRAPH + 0xEDEA: 0x6E3C, //CJK UNIFIED IDEOGRAPH + 0xEDEB: 0x6EBF, //CJK UNIFIED IDEOGRAPH + 0xEDEC: 0x6F88, //CJK UNIFIED IDEOGRAPH + 0xEDED: 0x6FB5, //CJK UNIFIED IDEOGRAPH + 0xEDEE: 0x6FF5, //CJK UNIFIED IDEOGRAPH + 0xEDEF: 0x7005, //CJK UNIFIED IDEOGRAPH + 0xEDF0: 0x7007, //CJK UNIFIED IDEOGRAPH + 0xEDF1: 0x7028, //CJK UNIFIED IDEOGRAPH + 0xEDF2: 0x7085, //CJK UNIFIED IDEOGRAPH + 0xEDF3: 0x70AB, //CJK UNIFIED IDEOGRAPH + 0xEDF4: 0x710F, //CJK UNIFIED IDEOGRAPH + 0xEDF5: 0x7104, //CJK UNIFIED IDEOGRAPH + 0xEDF6: 0x715C, //CJK UNIFIED IDEOGRAPH + 0xEDF7: 0x7146, //CJK UNIFIED IDEOGRAPH + 0xEDF8: 0x7147, //CJK UNIFIED IDEOGRAPH + 0xEDF9: 0xFA15, //CJK COMPATIBILITY IDEOGRAPH + 0xEDFA: 0x71C1, //CJK UNIFIED IDEOGRAPH + 0xEDFB: 0x71FE, //CJK UNIFIED IDEOGRAPH + 0xEDFC: 0x72B1, //CJK UNIFIED IDEOGRAPH + 0xEE40: 0x72BE, //CJK UNIFIED IDEOGRAPH + 0xEE41: 0x7324, //CJK UNIFIED IDEOGRAPH + 0xEE42: 0xFA16, //CJK COMPATIBILITY IDEOGRAPH + 0xEE43: 0x7377, //CJK UNIFIED IDEOGRAPH + 0xEE44: 0x73BD, //CJK UNIFIED IDEOGRAPH + 0xEE45: 0x73C9, //CJK UNIFIED IDEOGRAPH + 0xEE46: 0x73D6, //CJK UNIFIED IDEOGRAPH + 0xEE47: 0x73E3, //CJK UNIFIED IDEOGRAPH + 0xEE48: 0x73D2, //CJK UNIFIED IDEOGRAPH + 0xEE49: 0x7407, //CJK UNIFIED IDEOGRAPH + 0xEE4A: 0x73F5, //CJK UNIFIED IDEOGRAPH + 0xEE4B: 0x7426, //CJK UNIFIED IDEOGRAPH + 0xEE4C: 0x742A, //CJK UNIFIED IDEOGRAPH + 0xEE4D: 0x7429, //CJK UNIFIED IDEOGRAPH + 0xEE4E: 0x742E, //CJK UNIFIED IDEOGRAPH + 0xEE4F: 0x7462, //CJK UNIFIED IDEOGRAPH + 0xEE50: 0x7489, //CJK UNIFIED IDEOGRAPH + 0xEE51: 0x749F, //CJK UNIFIED IDEOGRAPH + 0xEE52: 0x7501, //CJK UNIFIED IDEOGRAPH + 0xEE53: 0x756F, //CJK UNIFIED IDEOGRAPH + 0xEE54: 0x7682, //CJK UNIFIED IDEOGRAPH + 0xEE55: 0x769C, //CJK UNIFIED IDEOGRAPH + 0xEE56: 0x769E, //CJK UNIFIED IDEOGRAPH + 0xEE57: 0x769B, //CJK UNIFIED IDEOGRAPH + 0xEE58: 0x76A6, //CJK UNIFIED IDEOGRAPH + 0xEE59: 0xFA17, //CJK COMPATIBILITY IDEOGRAPH + 0xEE5A: 0x7746, //CJK UNIFIED IDEOGRAPH + 0xEE5B: 0x52AF, //CJK UNIFIED IDEOGRAPH + 0xEE5C: 0x7821, //CJK UNIFIED IDEOGRAPH + 0xEE5D: 0x784E, //CJK UNIFIED IDEOGRAPH + 0xEE5E: 0x7864, //CJK UNIFIED IDEOGRAPH + 0xEE5F: 0x787A, //CJK UNIFIED IDEOGRAPH + 0xEE60: 0x7930, //CJK UNIFIED IDEOGRAPH + 0xEE61: 0xFA18, //CJK COMPATIBILITY IDEOGRAPH + 0xEE62: 0xFA19, //CJK COMPATIBILITY IDEOGRAPH + 0xEE63: 0xFA1A, //CJK COMPATIBILITY IDEOGRAPH + 0xEE64: 0x7994, //CJK UNIFIED IDEOGRAPH + 0xEE65: 0xFA1B, //CJK COMPATIBILITY IDEOGRAPH + 0xEE66: 0x799B, //CJK UNIFIED IDEOGRAPH + 0xEE67: 0x7AD1, //CJK UNIFIED IDEOGRAPH + 0xEE68: 0x7AE7, //CJK UNIFIED IDEOGRAPH + 0xEE69: 0xFA1C, //CJK COMPATIBILITY IDEOGRAPH + 0xEE6A: 0x7AEB, //CJK UNIFIED IDEOGRAPH + 0xEE6B: 0x7B9E, //CJK UNIFIED IDEOGRAPH + 0xEE6C: 0xFA1D, //CJK COMPATIBILITY IDEOGRAPH + 0xEE6D: 0x7D48, //CJK UNIFIED IDEOGRAPH + 0xEE6E: 0x7D5C, //CJK UNIFIED IDEOGRAPH + 0xEE6F: 0x7DB7, //CJK UNIFIED IDEOGRAPH + 0xEE70: 0x7DA0, //CJK UNIFIED IDEOGRAPH + 0xEE71: 0x7DD6, //CJK UNIFIED IDEOGRAPH + 0xEE72: 0x7E52, //CJK UNIFIED IDEOGRAPH + 0xEE73: 0x7F47, //CJK UNIFIED IDEOGRAPH + 0xEE74: 0x7FA1, //CJK UNIFIED IDEOGRAPH + 0xEE75: 0xFA1E, //CJK COMPATIBILITY IDEOGRAPH + 0xEE76: 0x8301, //CJK UNIFIED IDEOGRAPH + 0xEE77: 0x8362, //CJK UNIFIED IDEOGRAPH + 0xEE78: 0x837F, //CJK UNIFIED IDEOGRAPH + 0xEE79: 0x83C7, //CJK UNIFIED IDEOGRAPH + 0xEE7A: 0x83F6, //CJK UNIFIED IDEOGRAPH + 0xEE7B: 0x8448, //CJK UNIFIED IDEOGRAPH + 0xEE7C: 0x84B4, //CJK UNIFIED IDEOGRAPH + 0xEE7D: 0x8553, //CJK UNIFIED IDEOGRAPH + 0xEE7E: 0x8559, //CJK UNIFIED IDEOGRAPH + 0xEE80: 0x856B, //CJK UNIFIED IDEOGRAPH + 0xEE81: 0xFA1F, //CJK COMPATIBILITY IDEOGRAPH + 0xEE82: 0x85B0, //CJK UNIFIED IDEOGRAPH + 0xEE83: 0xFA20, //CJK COMPATIBILITY IDEOGRAPH + 0xEE84: 0xFA21, //CJK COMPATIBILITY IDEOGRAPH + 0xEE85: 0x8807, //CJK UNIFIED IDEOGRAPH + 0xEE86: 0x88F5, //CJK UNIFIED IDEOGRAPH + 0xEE87: 0x8A12, //CJK UNIFIED IDEOGRAPH + 0xEE88: 0x8A37, //CJK UNIFIED IDEOGRAPH + 0xEE89: 0x8A79, //CJK UNIFIED IDEOGRAPH + 0xEE8A: 0x8AA7, //CJK UNIFIED IDEOGRAPH + 0xEE8B: 0x8ABE, //CJK UNIFIED IDEOGRAPH + 0xEE8C: 0x8ADF, //CJK UNIFIED IDEOGRAPH + 0xEE8D: 0xFA22, //CJK COMPATIBILITY IDEOGRAPH + 0xEE8E: 0x8AF6, //CJK UNIFIED IDEOGRAPH + 0xEE8F: 0x8B53, //CJK UNIFIED IDEOGRAPH + 0xEE90: 0x8B7F, //CJK UNIFIED IDEOGRAPH + 0xEE91: 0x8CF0, //CJK UNIFIED IDEOGRAPH + 0xEE92: 0x8CF4, //CJK UNIFIED IDEOGRAPH + 0xEE93: 0x8D12, //CJK UNIFIED IDEOGRAPH + 0xEE94: 0x8D76, //CJK UNIFIED IDEOGRAPH + 0xEE95: 0xFA23, //CJK COMPATIBILITY IDEOGRAPH + 0xEE96: 0x8ECF, //CJK UNIFIED IDEOGRAPH + 0xEE97: 0xFA24, //CJK COMPATIBILITY IDEOGRAPH + 0xEE98: 0xFA25, //CJK COMPATIBILITY IDEOGRAPH + 0xEE99: 0x9067, //CJK UNIFIED IDEOGRAPH + 0xEE9A: 0x90DE, //CJK UNIFIED IDEOGRAPH + 0xEE9B: 0xFA26, //CJK COMPATIBILITY IDEOGRAPH + 0xEE9C: 0x9115, //CJK UNIFIED IDEOGRAPH + 0xEE9D: 0x9127, //CJK UNIFIED IDEOGRAPH + 0xEE9E: 0x91DA, //CJK UNIFIED IDEOGRAPH + 0xEE9F: 0x91D7, //CJK UNIFIED IDEOGRAPH + 0xEEA0: 0x91DE, //CJK UNIFIED IDEOGRAPH + 0xEEA1: 0x91ED, //CJK UNIFIED IDEOGRAPH + 0xEEA2: 0x91EE, //CJK UNIFIED IDEOGRAPH + 0xEEA3: 0x91E4, //CJK UNIFIED IDEOGRAPH + 0xEEA4: 0x91E5, //CJK UNIFIED IDEOGRAPH + 0xEEA5: 0x9206, //CJK UNIFIED IDEOGRAPH + 0xEEA6: 0x9210, //CJK UNIFIED IDEOGRAPH + 0xEEA7: 0x920A, //CJK UNIFIED IDEOGRAPH + 0xEEA8: 0x923A, //CJK UNIFIED IDEOGRAPH + 0xEEA9: 0x9240, //CJK UNIFIED IDEOGRAPH + 0xEEAA: 0x923C, //CJK UNIFIED IDEOGRAPH + 0xEEAB: 0x924E, //CJK UNIFIED IDEOGRAPH + 0xEEAC: 0x9259, //CJK UNIFIED IDEOGRAPH + 0xEEAD: 0x9251, //CJK UNIFIED IDEOGRAPH + 0xEEAE: 0x9239, //CJK UNIFIED IDEOGRAPH + 0xEEAF: 0x9267, //CJK UNIFIED IDEOGRAPH + 0xEEB0: 0x92A7, //CJK UNIFIED IDEOGRAPH + 0xEEB1: 0x9277, //CJK UNIFIED IDEOGRAPH + 0xEEB2: 0x9278, //CJK UNIFIED IDEOGRAPH + 0xEEB3: 0x92E7, //CJK UNIFIED IDEOGRAPH + 0xEEB4: 0x92D7, //CJK UNIFIED IDEOGRAPH + 0xEEB5: 0x92D9, //CJK UNIFIED IDEOGRAPH + 0xEEB6: 0x92D0, //CJK UNIFIED IDEOGRAPH + 0xEEB7: 0xFA27, //CJK COMPATIBILITY IDEOGRAPH + 0xEEB8: 0x92D5, //CJK UNIFIED IDEOGRAPH + 0xEEB9: 0x92E0, //CJK UNIFIED IDEOGRAPH + 0xEEBA: 0x92D3, //CJK UNIFIED IDEOGRAPH + 0xEEBB: 0x9325, //CJK UNIFIED IDEOGRAPH + 0xEEBC: 0x9321, //CJK UNIFIED IDEOGRAPH + 0xEEBD: 0x92FB, //CJK UNIFIED IDEOGRAPH + 0xEEBE: 0xFA28, //CJK COMPATIBILITY IDEOGRAPH + 0xEEBF: 0x931E, //CJK UNIFIED IDEOGRAPH + 0xEEC0: 0x92FF, //CJK UNIFIED IDEOGRAPH + 0xEEC1: 0x931D, //CJK UNIFIED IDEOGRAPH + 0xEEC2: 0x9302, //CJK UNIFIED IDEOGRAPH + 0xEEC3: 0x9370, //CJK UNIFIED IDEOGRAPH + 0xEEC4: 0x9357, //CJK UNIFIED IDEOGRAPH + 0xEEC5: 0x93A4, //CJK UNIFIED IDEOGRAPH + 0xEEC6: 0x93C6, //CJK UNIFIED IDEOGRAPH + 0xEEC7: 0x93DE, //CJK UNIFIED IDEOGRAPH + 0xEEC8: 0x93F8, //CJK UNIFIED IDEOGRAPH + 0xEEC9: 0x9431, //CJK UNIFIED IDEOGRAPH + 0xEECA: 0x9445, //CJK UNIFIED IDEOGRAPH + 0xEECB: 0x9448, //CJK UNIFIED IDEOGRAPH + 0xEECC: 0x9592, //CJK UNIFIED IDEOGRAPH + 0xEECD: 0xF9DC, //CJK COMPATIBILITY IDEOGRAPH + 0xEECE: 0xFA29, //CJK COMPATIBILITY IDEOGRAPH + 0xEECF: 0x969D, //CJK UNIFIED IDEOGRAPH + 0xEED0: 0x96AF, //CJK UNIFIED IDEOGRAPH + 0xEED1: 0x9733, //CJK UNIFIED IDEOGRAPH + 0xEED2: 0x973B, //CJK UNIFIED IDEOGRAPH + 0xEED3: 0x9743, //CJK UNIFIED IDEOGRAPH + 0xEED4: 0x974D, //CJK UNIFIED IDEOGRAPH + 0xEED5: 0x974F, //CJK UNIFIED IDEOGRAPH + 0xEED6: 0x9751, //CJK UNIFIED IDEOGRAPH + 0xEED7: 0x9755, //CJK UNIFIED IDEOGRAPH + 0xEED8: 0x9857, //CJK UNIFIED IDEOGRAPH + 0xEED9: 0x9865, //CJK UNIFIED IDEOGRAPH + 0xEEDA: 0xFA2A, //CJK COMPATIBILITY IDEOGRAPH + 0xEEDB: 0xFA2B, //CJK COMPATIBILITY IDEOGRAPH + 0xEEDC: 0x9927, //CJK UNIFIED IDEOGRAPH + 0xEEDD: 0xFA2C, //CJK COMPATIBILITY IDEOGRAPH + 0xEEDE: 0x999E, //CJK UNIFIED IDEOGRAPH + 0xEEDF: 0x9A4E, //CJK UNIFIED IDEOGRAPH + 0xEEE0: 0x9AD9, //CJK UNIFIED IDEOGRAPH + 0xEEE1: 0x9ADC, //CJK UNIFIED IDEOGRAPH + 0xEEE2: 0x9B75, //CJK UNIFIED IDEOGRAPH + 0xEEE3: 0x9B72, //CJK UNIFIED IDEOGRAPH + 0xEEE4: 0x9B8F, //CJK UNIFIED IDEOGRAPH + 0xEEE5: 0x9BB1, //CJK UNIFIED IDEOGRAPH + 0xEEE6: 0x9BBB, //CJK UNIFIED IDEOGRAPH + 0xEEE7: 0x9C00, //CJK UNIFIED IDEOGRAPH + 0xEEE8: 0x9D70, //CJK UNIFIED IDEOGRAPH + 0xEEE9: 0x9D6B, //CJK UNIFIED IDEOGRAPH + 0xEEEA: 0xFA2D, //CJK COMPATIBILITY IDEOGRAPH + 0xEEEB: 0x9E19, //CJK UNIFIED IDEOGRAPH + 0xEEEC: 0x9ED1, //CJK UNIFIED IDEOGRAPH + 0xEEEF: 0x2170, //SMALL ROMAN NUMERAL ONE + 0xEEF0: 0x2171, //SMALL ROMAN NUMERAL TWO + 0xEEF1: 0x2172, //SMALL ROMAN NUMERAL THREE + 0xEEF2: 0x2173, //SMALL ROMAN NUMERAL FOUR + 0xEEF3: 0x2174, //SMALL ROMAN NUMERAL FIVE + 0xEEF4: 0x2175, //SMALL ROMAN NUMERAL SIX + 0xEEF5: 0x2176, //SMALL ROMAN NUMERAL SEVEN + 0xEEF6: 0x2177, //SMALL ROMAN NUMERAL EIGHT + 0xEEF7: 0x2178, //SMALL ROMAN NUMERAL NINE + 0xEEF8: 0x2179, //SMALL ROMAN NUMERAL TEN + 0xEEF9: 0xFFE2, //FULLWIDTH NOT SIGN + 0xEEFA: 0xFFE4, //FULLWIDTH BROKEN BAR + 0xEEFB: 0xFF07, //FULLWIDTH APOSTROPHE + 0xEEFC: 0xFF02, //FULLWIDTH QUOTATION MARK + 0xFA40: 0x2170, //SMALL ROMAN NUMERAL ONE + 0xFA41: 0x2171, //SMALL ROMAN NUMERAL TWO + 0xFA42: 0x2172, //SMALL ROMAN NUMERAL THREE + 0xFA43: 0x2173, //SMALL ROMAN NUMERAL FOUR + 0xFA44: 0x2174, //SMALL ROMAN NUMERAL FIVE + 0xFA45: 0x2175, //SMALL ROMAN NUMERAL SIX + 0xFA46: 0x2176, //SMALL ROMAN NUMERAL SEVEN + 0xFA47: 0x2177, //SMALL ROMAN NUMERAL EIGHT + 0xFA48: 0x2178, //SMALL ROMAN NUMERAL NINE + 0xFA49: 0x2179, //SMALL ROMAN NUMERAL TEN + 0xFA4A: 0x2160, //ROMAN NUMERAL ONE + 0xFA4B: 0x2161, //ROMAN NUMERAL TWO + 0xFA4C: 0x2162, //ROMAN NUMERAL THREE + 0xFA4D: 0x2163, //ROMAN NUMERAL FOUR + 0xFA4E: 0x2164, //ROMAN NUMERAL FIVE + 0xFA4F: 0x2165, //ROMAN NUMERAL SIX + 0xFA50: 0x2166, //ROMAN NUMERAL SEVEN + 0xFA51: 0x2167, //ROMAN NUMERAL EIGHT + 0xFA52: 0x2168, //ROMAN NUMERAL NINE + 0xFA53: 0x2169, //ROMAN NUMERAL TEN + 0xFA54: 0xFFE2, //FULLWIDTH NOT SIGN + 0xFA55: 0xFFE4, //FULLWIDTH BROKEN BAR + 0xFA56: 0xFF07, //FULLWIDTH APOSTROPHE + 0xFA57: 0xFF02, //FULLWIDTH QUOTATION MARK + 0xFA58: 0x3231, //PARENTHESIZED IDEOGRAPH STOCK + 0xFA59: 0x2116, //NUMERO SIGN + 0xFA5A: 0x2121, //TELEPHONE SIGN + 0xFA5B: 0x2235, //BECAUSE + 0xFA5C: 0x7E8A, //CJK UNIFIED IDEOGRAPH + 0xFA5D: 0x891C, //CJK UNIFIED IDEOGRAPH + 0xFA5E: 0x9348, //CJK UNIFIED IDEOGRAPH + 0xFA5F: 0x9288, //CJK UNIFIED IDEOGRAPH + 0xFA60: 0x84DC, //CJK UNIFIED IDEOGRAPH + 0xFA61: 0x4FC9, //CJK UNIFIED IDEOGRAPH + 0xFA62: 0x70BB, //CJK UNIFIED IDEOGRAPH + 0xFA63: 0x6631, //CJK UNIFIED IDEOGRAPH + 0xFA64: 0x68C8, //CJK UNIFIED IDEOGRAPH + 0xFA65: 0x92F9, //CJK UNIFIED IDEOGRAPH + 0xFA66: 0x66FB, //CJK UNIFIED IDEOGRAPH + 0xFA67: 0x5F45, //CJK UNIFIED IDEOGRAPH + 0xFA68: 0x4E28, //CJK UNIFIED IDEOGRAPH + 0xFA69: 0x4EE1, //CJK UNIFIED IDEOGRAPH + 0xFA6A: 0x4EFC, //CJK UNIFIED IDEOGRAPH + 0xFA6B: 0x4F00, //CJK UNIFIED IDEOGRAPH + 0xFA6C: 0x4F03, //CJK UNIFIED IDEOGRAPH + 0xFA6D: 0x4F39, //CJK UNIFIED IDEOGRAPH + 0xFA6E: 0x4F56, //CJK UNIFIED IDEOGRAPH + 0xFA6F: 0x4F92, //CJK UNIFIED IDEOGRAPH + 0xFA70: 0x4F8A, //CJK UNIFIED IDEOGRAPH + 0xFA71: 0x4F9A, //CJK UNIFIED IDEOGRAPH + 0xFA72: 0x4F94, //CJK UNIFIED IDEOGRAPH + 0xFA73: 0x4FCD, //CJK UNIFIED IDEOGRAPH + 0xFA74: 0x5040, //CJK UNIFIED IDEOGRAPH + 0xFA75: 0x5022, //CJK UNIFIED IDEOGRAPH + 0xFA76: 0x4FFF, //CJK UNIFIED IDEOGRAPH + 0xFA77: 0x501E, //CJK UNIFIED IDEOGRAPH + 0xFA78: 0x5046, //CJK UNIFIED IDEOGRAPH + 0xFA79: 0x5070, //CJK UNIFIED IDEOGRAPH + 0xFA7A: 0x5042, //CJK UNIFIED IDEOGRAPH + 0xFA7B: 0x5094, //CJK UNIFIED IDEOGRAPH + 0xFA7C: 0x50F4, //CJK UNIFIED IDEOGRAPH + 0xFA7D: 0x50D8, //CJK UNIFIED IDEOGRAPH + 0xFA7E: 0x514A, //CJK UNIFIED IDEOGRAPH + 0xFA80: 0x5164, //CJK UNIFIED IDEOGRAPH + 0xFA81: 0x519D, //CJK UNIFIED IDEOGRAPH + 0xFA82: 0x51BE, //CJK UNIFIED IDEOGRAPH + 0xFA83: 0x51EC, //CJK UNIFIED IDEOGRAPH + 0xFA84: 0x5215, //CJK UNIFIED IDEOGRAPH + 0xFA85: 0x529C, //CJK UNIFIED IDEOGRAPH + 0xFA86: 0x52A6, //CJK UNIFIED IDEOGRAPH + 0xFA87: 0x52C0, //CJK UNIFIED IDEOGRAPH + 0xFA88: 0x52DB, //CJK UNIFIED IDEOGRAPH + 0xFA89: 0x5300, //CJK UNIFIED IDEOGRAPH + 0xFA8A: 0x5307, //CJK UNIFIED IDEOGRAPH + 0xFA8B: 0x5324, //CJK UNIFIED IDEOGRAPH + 0xFA8C: 0x5372, //CJK UNIFIED IDEOGRAPH + 0xFA8D: 0x5393, //CJK UNIFIED IDEOGRAPH + 0xFA8E: 0x53B2, //CJK UNIFIED IDEOGRAPH + 0xFA8F: 0x53DD, //CJK UNIFIED IDEOGRAPH + 0xFA90: 0xFA0E, //CJK COMPATIBILITY IDEOGRAPH + 0xFA91: 0x549C, //CJK UNIFIED IDEOGRAPH + 0xFA92: 0x548A, //CJK UNIFIED IDEOGRAPH + 0xFA93: 0x54A9, //CJK UNIFIED IDEOGRAPH + 0xFA94: 0x54FF, //CJK UNIFIED IDEOGRAPH + 0xFA95: 0x5586, //CJK UNIFIED IDEOGRAPH + 0xFA96: 0x5759, //CJK UNIFIED IDEOGRAPH + 0xFA97: 0x5765, //CJK UNIFIED IDEOGRAPH + 0xFA98: 0x57AC, //CJK UNIFIED IDEOGRAPH + 0xFA99: 0x57C8, //CJK UNIFIED IDEOGRAPH + 0xFA9A: 0x57C7, //CJK UNIFIED IDEOGRAPH + 0xFA9B: 0xFA0F, //CJK COMPATIBILITY IDEOGRAPH + 0xFA9C: 0xFA10, //CJK COMPATIBILITY IDEOGRAPH + 0xFA9D: 0x589E, //CJK UNIFIED IDEOGRAPH + 0xFA9E: 0x58B2, //CJK UNIFIED IDEOGRAPH + 0xFA9F: 0x590B, //CJK UNIFIED IDEOGRAPH + 0xFAA0: 0x5953, //CJK UNIFIED IDEOGRAPH + 0xFAA1: 0x595B, //CJK UNIFIED IDEOGRAPH + 0xFAA2: 0x595D, //CJK UNIFIED IDEOGRAPH + 0xFAA3: 0x5963, //CJK UNIFIED IDEOGRAPH + 0xFAA4: 0x59A4, //CJK UNIFIED IDEOGRAPH + 0xFAA5: 0x59BA, //CJK UNIFIED IDEOGRAPH + 0xFAA6: 0x5B56, //CJK UNIFIED IDEOGRAPH + 0xFAA7: 0x5BC0, //CJK UNIFIED IDEOGRAPH + 0xFAA8: 0x752F, //CJK UNIFIED IDEOGRAPH + 0xFAA9: 0x5BD8, //CJK UNIFIED IDEOGRAPH + 0xFAAA: 0x5BEC, //CJK UNIFIED IDEOGRAPH + 0xFAAB: 0x5C1E, //CJK UNIFIED IDEOGRAPH + 0xFAAC: 0x5CA6, //CJK UNIFIED IDEOGRAPH + 0xFAAD: 0x5CBA, //CJK UNIFIED IDEOGRAPH + 0xFAAE: 0x5CF5, //CJK UNIFIED IDEOGRAPH + 0xFAAF: 0x5D27, //CJK UNIFIED IDEOGRAPH + 0xFAB0: 0x5D53, //CJK UNIFIED IDEOGRAPH + 0xFAB1: 0xFA11, //CJK COMPATIBILITY IDEOGRAPH + 0xFAB2: 0x5D42, //CJK UNIFIED IDEOGRAPH + 0xFAB3: 0x5D6D, //CJK UNIFIED IDEOGRAPH + 0xFAB4: 0x5DB8, //CJK UNIFIED IDEOGRAPH + 0xFAB5: 0x5DB9, //CJK UNIFIED IDEOGRAPH + 0xFAB6: 0x5DD0, //CJK UNIFIED IDEOGRAPH + 0xFAB7: 0x5F21, //CJK UNIFIED IDEOGRAPH + 0xFAB8: 0x5F34, //CJK UNIFIED IDEOGRAPH + 0xFAB9: 0x5F67, //CJK UNIFIED IDEOGRAPH + 0xFABA: 0x5FB7, //CJK UNIFIED IDEOGRAPH + 0xFABB: 0x5FDE, //CJK UNIFIED IDEOGRAPH + 0xFABC: 0x605D, //CJK UNIFIED IDEOGRAPH + 0xFABD: 0x6085, //CJK UNIFIED IDEOGRAPH + 0xFABE: 0x608A, //CJK UNIFIED IDEOGRAPH + 0xFABF: 0x60DE, //CJK UNIFIED IDEOGRAPH + 0xFAC0: 0x60D5, //CJK UNIFIED IDEOGRAPH + 0xFAC1: 0x6120, //CJK UNIFIED IDEOGRAPH + 0xFAC2: 0x60F2, //CJK UNIFIED IDEOGRAPH + 0xFAC3: 0x6111, //CJK UNIFIED IDEOGRAPH + 0xFAC4: 0x6137, //CJK UNIFIED IDEOGRAPH + 0xFAC5: 0x6130, //CJK UNIFIED IDEOGRAPH + 0xFAC6: 0x6198, //CJK UNIFIED IDEOGRAPH + 0xFAC7: 0x6213, //CJK UNIFIED IDEOGRAPH + 0xFAC8: 0x62A6, //CJK UNIFIED IDEOGRAPH + 0xFAC9: 0x63F5, //CJK UNIFIED IDEOGRAPH + 0xFACA: 0x6460, //CJK UNIFIED IDEOGRAPH + 0xFACB: 0x649D, //CJK UNIFIED IDEOGRAPH + 0xFACC: 0x64CE, //CJK UNIFIED IDEOGRAPH + 0xFACD: 0x654E, //CJK UNIFIED IDEOGRAPH + 0xFACE: 0x6600, //CJK UNIFIED IDEOGRAPH + 0xFACF: 0x6615, //CJK UNIFIED IDEOGRAPH + 0xFAD0: 0x663B, //CJK UNIFIED IDEOGRAPH + 0xFAD1: 0x6609, //CJK UNIFIED IDEOGRAPH + 0xFAD2: 0x662E, //CJK UNIFIED IDEOGRAPH + 0xFAD3: 0x661E, //CJK UNIFIED IDEOGRAPH + 0xFAD4: 0x6624, //CJK UNIFIED IDEOGRAPH + 0xFAD5: 0x6665, //CJK UNIFIED IDEOGRAPH + 0xFAD6: 0x6657, //CJK UNIFIED IDEOGRAPH + 0xFAD7: 0x6659, //CJK UNIFIED IDEOGRAPH + 0xFAD8: 0xFA12, //CJK COMPATIBILITY IDEOGRAPH + 0xFAD9: 0x6673, //CJK UNIFIED IDEOGRAPH + 0xFADA: 0x6699, //CJK UNIFIED IDEOGRAPH + 0xFADB: 0x66A0, //CJK UNIFIED IDEOGRAPH + 0xFADC: 0x66B2, //CJK UNIFIED IDEOGRAPH + 0xFADD: 0x66BF, //CJK UNIFIED IDEOGRAPH + 0xFADE: 0x66FA, //CJK UNIFIED IDEOGRAPH + 0xFADF: 0x670E, //CJK UNIFIED IDEOGRAPH + 0xFAE0: 0xF929, //CJK COMPATIBILITY IDEOGRAPH + 0xFAE1: 0x6766, //CJK UNIFIED IDEOGRAPH + 0xFAE2: 0x67BB, //CJK UNIFIED IDEOGRAPH + 0xFAE3: 0x6852, //CJK UNIFIED IDEOGRAPH + 0xFAE4: 0x67C0, //CJK UNIFIED IDEOGRAPH + 0xFAE5: 0x6801, //CJK UNIFIED IDEOGRAPH + 0xFAE6: 0x6844, //CJK UNIFIED IDEOGRAPH + 0xFAE7: 0x68CF, //CJK UNIFIED IDEOGRAPH + 0xFAE8: 0xFA13, //CJK COMPATIBILITY IDEOGRAPH + 0xFAE9: 0x6968, //CJK UNIFIED IDEOGRAPH + 0xFAEA: 0xFA14, //CJK COMPATIBILITY IDEOGRAPH + 0xFAEB: 0x6998, //CJK UNIFIED IDEOGRAPH + 0xFAEC: 0x69E2, //CJK UNIFIED IDEOGRAPH + 0xFAED: 0x6A30, //CJK UNIFIED IDEOGRAPH + 0xFAEE: 0x6A6B, //CJK UNIFIED IDEOGRAPH + 0xFAEF: 0x6A46, //CJK UNIFIED IDEOGRAPH + 0xFAF0: 0x6A73, //CJK UNIFIED IDEOGRAPH + 0xFAF1: 0x6A7E, //CJK UNIFIED IDEOGRAPH + 0xFAF2: 0x6AE2, //CJK UNIFIED IDEOGRAPH + 0xFAF3: 0x6AE4, //CJK UNIFIED IDEOGRAPH + 0xFAF4: 0x6BD6, //CJK UNIFIED IDEOGRAPH + 0xFAF5: 0x6C3F, //CJK UNIFIED IDEOGRAPH + 0xFAF6: 0x6C5C, //CJK UNIFIED IDEOGRAPH + 0xFAF7: 0x6C86, //CJK UNIFIED IDEOGRAPH + 0xFAF8: 0x6C6F, //CJK UNIFIED IDEOGRAPH + 0xFAF9: 0x6CDA, //CJK UNIFIED IDEOGRAPH + 0xFAFA: 0x6D04, //CJK UNIFIED IDEOGRAPH + 0xFAFB: 0x6D87, //CJK UNIFIED IDEOGRAPH + 0xFAFC: 0x6D6F, //CJK UNIFIED IDEOGRAPH + 0xFB40: 0x6D96, //CJK UNIFIED IDEOGRAPH + 0xFB41: 0x6DAC, //CJK UNIFIED IDEOGRAPH + 0xFB42: 0x6DCF, //CJK UNIFIED IDEOGRAPH + 0xFB43: 0x6DF8, //CJK UNIFIED IDEOGRAPH + 0xFB44: 0x6DF2, //CJK UNIFIED IDEOGRAPH + 0xFB45: 0x6DFC, //CJK UNIFIED IDEOGRAPH + 0xFB46: 0x6E39, //CJK UNIFIED IDEOGRAPH + 0xFB47: 0x6E5C, //CJK UNIFIED IDEOGRAPH + 0xFB48: 0x6E27, //CJK UNIFIED IDEOGRAPH + 0xFB49: 0x6E3C, //CJK UNIFIED IDEOGRAPH + 0xFB4A: 0x6EBF, //CJK UNIFIED IDEOGRAPH + 0xFB4B: 0x6F88, //CJK UNIFIED IDEOGRAPH + 0xFB4C: 0x6FB5, //CJK UNIFIED IDEOGRAPH + 0xFB4D: 0x6FF5, //CJK UNIFIED IDEOGRAPH + 0xFB4E: 0x7005, //CJK UNIFIED IDEOGRAPH + 0xFB4F: 0x7007, //CJK UNIFIED IDEOGRAPH + 0xFB50: 0x7028, //CJK UNIFIED IDEOGRAPH + 0xFB51: 0x7085, //CJK UNIFIED IDEOGRAPH + 0xFB52: 0x70AB, //CJK UNIFIED IDEOGRAPH + 0xFB53: 0x710F, //CJK UNIFIED IDEOGRAPH + 0xFB54: 0x7104, //CJK UNIFIED IDEOGRAPH + 0xFB55: 0x715C, //CJK UNIFIED IDEOGRAPH + 0xFB56: 0x7146, //CJK UNIFIED IDEOGRAPH + 0xFB57: 0x7147, //CJK UNIFIED IDEOGRAPH + 0xFB58: 0xFA15, //CJK COMPATIBILITY IDEOGRAPH + 0xFB59: 0x71C1, //CJK UNIFIED IDEOGRAPH + 0xFB5A: 0x71FE, //CJK UNIFIED IDEOGRAPH + 0xFB5B: 0x72B1, //CJK UNIFIED IDEOGRAPH + 0xFB5C: 0x72BE, //CJK UNIFIED IDEOGRAPH + 0xFB5D: 0x7324, //CJK UNIFIED IDEOGRAPH + 0xFB5E: 0xFA16, //CJK COMPATIBILITY IDEOGRAPH + 0xFB5F: 0x7377, //CJK UNIFIED IDEOGRAPH + 0xFB60: 0x73BD, //CJK UNIFIED IDEOGRAPH + 0xFB61: 0x73C9, //CJK UNIFIED IDEOGRAPH + 0xFB62: 0x73D6, //CJK UNIFIED IDEOGRAPH + 0xFB63: 0x73E3, //CJK UNIFIED IDEOGRAPH + 0xFB64: 0x73D2, //CJK UNIFIED IDEOGRAPH + 0xFB65: 0x7407, //CJK UNIFIED IDEOGRAPH + 0xFB66: 0x73F5, //CJK UNIFIED IDEOGRAPH + 0xFB67: 0x7426, //CJK UNIFIED IDEOGRAPH + 0xFB68: 0x742A, //CJK UNIFIED IDEOGRAPH + 0xFB69: 0x7429, //CJK UNIFIED IDEOGRAPH + 0xFB6A: 0x742E, //CJK UNIFIED IDEOGRAPH + 0xFB6B: 0x7462, //CJK UNIFIED IDEOGRAPH + 0xFB6C: 0x7489, //CJK UNIFIED IDEOGRAPH + 0xFB6D: 0x749F, //CJK UNIFIED IDEOGRAPH + 0xFB6E: 0x7501, //CJK UNIFIED IDEOGRAPH + 0xFB6F: 0x756F, //CJK UNIFIED IDEOGRAPH + 0xFB70: 0x7682, //CJK UNIFIED IDEOGRAPH + 0xFB71: 0x769C, //CJK UNIFIED IDEOGRAPH + 0xFB72: 0x769E, //CJK UNIFIED IDEOGRAPH + 0xFB73: 0x769B, //CJK UNIFIED IDEOGRAPH + 0xFB74: 0x76A6, //CJK UNIFIED IDEOGRAPH + 0xFB75: 0xFA17, //CJK COMPATIBILITY IDEOGRAPH + 0xFB76: 0x7746, //CJK UNIFIED IDEOGRAPH + 0xFB77: 0x52AF, //CJK UNIFIED IDEOGRAPH + 0xFB78: 0x7821, //CJK UNIFIED IDEOGRAPH + 0xFB79: 0x784E, //CJK UNIFIED IDEOGRAPH + 0xFB7A: 0x7864, //CJK UNIFIED IDEOGRAPH + 0xFB7B: 0x787A, //CJK UNIFIED IDEOGRAPH + 0xFB7C: 0x7930, //CJK UNIFIED IDEOGRAPH + 0xFB7D: 0xFA18, //CJK COMPATIBILITY IDEOGRAPH + 0xFB7E: 0xFA19, //CJK COMPATIBILITY IDEOGRAPH + 0xFB80: 0xFA1A, //CJK COMPATIBILITY IDEOGRAPH + 0xFB81: 0x7994, //CJK UNIFIED IDEOGRAPH + 0xFB82: 0xFA1B, //CJK COMPATIBILITY IDEOGRAPH + 0xFB83: 0x799B, //CJK UNIFIED IDEOGRAPH + 0xFB84: 0x7AD1, //CJK UNIFIED IDEOGRAPH + 0xFB85: 0x7AE7, //CJK UNIFIED IDEOGRAPH + 0xFB86: 0xFA1C, //CJK COMPATIBILITY IDEOGRAPH + 0xFB87: 0x7AEB, //CJK UNIFIED IDEOGRAPH + 0xFB88: 0x7B9E, //CJK UNIFIED IDEOGRAPH + 0xFB89: 0xFA1D, //CJK COMPATIBILITY IDEOGRAPH + 0xFB8A: 0x7D48, //CJK UNIFIED IDEOGRAPH + 0xFB8B: 0x7D5C, //CJK UNIFIED IDEOGRAPH + 0xFB8C: 0x7DB7, //CJK UNIFIED IDEOGRAPH + 0xFB8D: 0x7DA0, //CJK UNIFIED IDEOGRAPH + 0xFB8E: 0x7DD6, //CJK UNIFIED IDEOGRAPH + 0xFB8F: 0x7E52, //CJK UNIFIED IDEOGRAPH + 0xFB90: 0x7F47, //CJK UNIFIED IDEOGRAPH + 0xFB91: 0x7FA1, //CJK UNIFIED IDEOGRAPH + 0xFB92: 0xFA1E, //CJK COMPATIBILITY IDEOGRAPH + 0xFB93: 0x8301, //CJK UNIFIED IDEOGRAPH + 0xFB94: 0x8362, //CJK UNIFIED IDEOGRAPH + 0xFB95: 0x837F, //CJK UNIFIED IDEOGRAPH + 0xFB96: 0x83C7, //CJK UNIFIED IDEOGRAPH + 0xFB97: 0x83F6, //CJK UNIFIED IDEOGRAPH + 0xFB98: 0x8448, //CJK UNIFIED IDEOGRAPH + 0xFB99: 0x84B4, //CJK UNIFIED IDEOGRAPH + 0xFB9A: 0x8553, //CJK UNIFIED IDEOGRAPH + 0xFB9B: 0x8559, //CJK UNIFIED IDEOGRAPH + 0xFB9C: 0x856B, //CJK UNIFIED IDEOGRAPH + 0xFB9D: 0xFA1F, //CJK COMPATIBILITY IDEOGRAPH + 0xFB9E: 0x85B0, //CJK UNIFIED IDEOGRAPH + 0xFB9F: 0xFA20, //CJK COMPATIBILITY IDEOGRAPH + 0xFBA0: 0xFA21, //CJK COMPATIBILITY IDEOGRAPH + 0xFBA1: 0x8807, //CJK UNIFIED IDEOGRAPH + 0xFBA2: 0x88F5, //CJK UNIFIED IDEOGRAPH + 0xFBA3: 0x8A12, //CJK UNIFIED IDEOGRAPH + 0xFBA4: 0x8A37, //CJK UNIFIED IDEOGRAPH + 0xFBA5: 0x8A79, //CJK UNIFIED IDEOGRAPH + 0xFBA6: 0x8AA7, //CJK UNIFIED IDEOGRAPH + 0xFBA7: 0x8ABE, //CJK UNIFIED IDEOGRAPH + 0xFBA8: 0x8ADF, //CJK UNIFIED IDEOGRAPH + 0xFBA9: 0xFA22, //CJK COMPATIBILITY IDEOGRAPH + 0xFBAA: 0x8AF6, //CJK UNIFIED IDEOGRAPH + 0xFBAB: 0x8B53, //CJK UNIFIED IDEOGRAPH + 0xFBAC: 0x8B7F, //CJK UNIFIED IDEOGRAPH + 0xFBAD: 0x8CF0, //CJK UNIFIED IDEOGRAPH + 0xFBAE: 0x8CF4, //CJK UNIFIED IDEOGRAPH + 0xFBAF: 0x8D12, //CJK UNIFIED IDEOGRAPH + 0xFBB0: 0x8D76, //CJK UNIFIED IDEOGRAPH + 0xFBB1: 0xFA23, //CJK COMPATIBILITY IDEOGRAPH + 0xFBB2: 0x8ECF, //CJK UNIFIED IDEOGRAPH + 0xFBB3: 0xFA24, //CJK COMPATIBILITY IDEOGRAPH + 0xFBB4: 0xFA25, //CJK COMPATIBILITY IDEOGRAPH + 0xFBB5: 0x9067, //CJK UNIFIED IDEOGRAPH + 0xFBB6: 0x90DE, //CJK UNIFIED IDEOGRAPH + 0xFBB7: 0xFA26, //CJK COMPATIBILITY IDEOGRAPH + 0xFBB8: 0x9115, //CJK UNIFIED IDEOGRAPH + 0xFBB9: 0x9127, //CJK UNIFIED IDEOGRAPH + 0xFBBA: 0x91DA, //CJK UNIFIED IDEOGRAPH + 0xFBBB: 0x91D7, //CJK UNIFIED IDEOGRAPH + 0xFBBC: 0x91DE, //CJK UNIFIED IDEOGRAPH + 0xFBBD: 0x91ED, //CJK UNIFIED IDEOGRAPH + 0xFBBE: 0x91EE, //CJK UNIFIED IDEOGRAPH + 0xFBBF: 0x91E4, //CJK UNIFIED IDEOGRAPH + 0xFBC0: 0x91E5, //CJK UNIFIED IDEOGRAPH + 0xFBC1: 0x9206, //CJK UNIFIED IDEOGRAPH + 0xFBC2: 0x9210, //CJK UNIFIED IDEOGRAPH + 0xFBC3: 0x920A, //CJK UNIFIED IDEOGRAPH + 0xFBC4: 0x923A, //CJK UNIFIED IDEOGRAPH + 0xFBC5: 0x9240, //CJK UNIFIED IDEOGRAPH + 0xFBC6: 0x923C, //CJK UNIFIED IDEOGRAPH + 0xFBC7: 0x924E, //CJK UNIFIED IDEOGRAPH + 0xFBC8: 0x9259, //CJK UNIFIED IDEOGRAPH + 0xFBC9: 0x9251, //CJK UNIFIED IDEOGRAPH + 0xFBCA: 0x9239, //CJK UNIFIED IDEOGRAPH + 0xFBCB: 0x9267, //CJK UNIFIED IDEOGRAPH + 0xFBCC: 0x92A7, //CJK UNIFIED IDEOGRAPH + 0xFBCD: 0x9277, //CJK UNIFIED IDEOGRAPH + 0xFBCE: 0x9278, //CJK UNIFIED IDEOGRAPH + 0xFBCF: 0x92E7, //CJK UNIFIED IDEOGRAPH + 0xFBD0: 0x92D7, //CJK UNIFIED IDEOGRAPH + 0xFBD1: 0x92D9, //CJK UNIFIED IDEOGRAPH + 0xFBD2: 0x92D0, //CJK UNIFIED IDEOGRAPH + 0xFBD3: 0xFA27, //CJK COMPATIBILITY IDEOGRAPH + 0xFBD4: 0x92D5, //CJK UNIFIED IDEOGRAPH + 0xFBD5: 0x92E0, //CJK UNIFIED IDEOGRAPH + 0xFBD6: 0x92D3, //CJK UNIFIED IDEOGRAPH + 0xFBD7: 0x9325, //CJK UNIFIED IDEOGRAPH + 0xFBD8: 0x9321, //CJK UNIFIED IDEOGRAPH + 0xFBD9: 0x92FB, //CJK UNIFIED IDEOGRAPH + 0xFBDA: 0xFA28, //CJK COMPATIBILITY IDEOGRAPH + 0xFBDB: 0x931E, //CJK UNIFIED IDEOGRAPH + 0xFBDC: 0x92FF, //CJK UNIFIED IDEOGRAPH + 0xFBDD: 0x931D, //CJK UNIFIED IDEOGRAPH + 0xFBDE: 0x9302, //CJK UNIFIED IDEOGRAPH + 0xFBDF: 0x9370, //CJK UNIFIED IDEOGRAPH + 0xFBE0: 0x9357, //CJK UNIFIED IDEOGRAPH + 0xFBE1: 0x93A4, //CJK UNIFIED IDEOGRAPH + 0xFBE2: 0x93C6, //CJK UNIFIED IDEOGRAPH + 0xFBE3: 0x93DE, //CJK UNIFIED IDEOGRAPH + 0xFBE4: 0x93F8, //CJK UNIFIED IDEOGRAPH + 0xFBE5: 0x9431, //CJK UNIFIED IDEOGRAPH + 0xFBE6: 0x9445, //CJK UNIFIED IDEOGRAPH + 0xFBE7: 0x9448, //CJK UNIFIED IDEOGRAPH + 0xFBE8: 0x9592, //CJK UNIFIED IDEOGRAPH + 0xFBE9: 0xF9DC, //CJK COMPATIBILITY IDEOGRAPH + 0xFBEA: 0xFA29, //CJK COMPATIBILITY IDEOGRAPH + 0xFBEB: 0x969D, //CJK UNIFIED IDEOGRAPH + 0xFBEC: 0x96AF, //CJK UNIFIED IDEOGRAPH + 0xFBED: 0x9733, //CJK UNIFIED IDEOGRAPH + 0xFBEE: 0x973B, //CJK UNIFIED IDEOGRAPH + 0xFBEF: 0x9743, //CJK UNIFIED IDEOGRAPH + 0xFBF0: 0x974D, //CJK UNIFIED IDEOGRAPH + 0xFBF1: 0x974F, //CJK UNIFIED IDEOGRAPH + 0xFBF2: 0x9751, //CJK UNIFIED IDEOGRAPH + 0xFBF3: 0x9755, //CJK UNIFIED IDEOGRAPH + 0xFBF4: 0x9857, //CJK UNIFIED IDEOGRAPH + 0xFBF5: 0x9865, //CJK UNIFIED IDEOGRAPH + 0xFBF6: 0xFA2A, //CJK COMPATIBILITY IDEOGRAPH + 0xFBF7: 0xFA2B, //CJK COMPATIBILITY IDEOGRAPH + 0xFBF8: 0x9927, //CJK UNIFIED IDEOGRAPH + 0xFBF9: 0xFA2C, //CJK COMPATIBILITY IDEOGRAPH + 0xFBFA: 0x999E, //CJK UNIFIED IDEOGRAPH + 0xFBFB: 0x9A4E, //CJK UNIFIED IDEOGRAPH + 0xFBFC: 0x9AD9, //CJK UNIFIED IDEOGRAPH + 0xFC40: 0x9ADC, //CJK UNIFIED IDEOGRAPH + 0xFC41: 0x9B75, //CJK UNIFIED IDEOGRAPH + 0xFC42: 0x9B72, //CJK UNIFIED IDEOGRAPH + 0xFC43: 0x9B8F, //CJK UNIFIED IDEOGRAPH + 0xFC44: 0x9BB1, //CJK UNIFIED IDEOGRAPH + 0xFC45: 0x9BBB, //CJK UNIFIED IDEOGRAPH + 0xFC46: 0x9C00, //CJK UNIFIED IDEOGRAPH + 0xFC47: 0x9D70, //CJK UNIFIED IDEOGRAPH + 0xFC48: 0x9D6B, //CJK UNIFIED IDEOGRAPH + 0xFC49: 0xFA2D, //CJK COMPATIBILITY IDEOGRAPH + 0xFC4A: 0x9E19, //CJK UNIFIED IDEOGRAPH + 0xFC4B: 0x9ED1, //CJK UNIFIED IDEOGRAPH + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp936.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp936.go new file mode 100644 index 00000000..d1fac12e --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp936.go @@ -0,0 +1,22055 @@ +package cp + +var cp936 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0x20AC, //EURO SIGN + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + 0xFFFD, //UNDEFINED + }, + db: map[int]rune{ + 0x8140: 0x4E02, //CJK UNIFIED IDEOGRAPH + 0x8141: 0x4E04, //CJK UNIFIED IDEOGRAPH + 0x8142: 0x4E05, //CJK UNIFIED IDEOGRAPH + 0x8143: 0x4E06, //CJK UNIFIED IDEOGRAPH + 0x8144: 0x4E0F, //CJK UNIFIED IDEOGRAPH + 0x8145: 0x4E12, //CJK UNIFIED IDEOGRAPH + 0x8146: 0x4E17, //CJK UNIFIED IDEOGRAPH + 0x8147: 0x4E1F, //CJK UNIFIED IDEOGRAPH + 0x8148: 0x4E20, //CJK UNIFIED IDEOGRAPH + 0x8149: 0x4E21, //CJK UNIFIED IDEOGRAPH + 0x814A: 0x4E23, //CJK UNIFIED IDEOGRAPH + 0x814B: 0x4E26, //CJK UNIFIED IDEOGRAPH + 0x814C: 0x4E29, //CJK UNIFIED IDEOGRAPH + 0x814D: 0x4E2E, //CJK UNIFIED IDEOGRAPH + 0x814E: 0x4E2F, //CJK UNIFIED IDEOGRAPH + 0x814F: 0x4E31, //CJK UNIFIED IDEOGRAPH + 0x8150: 0x4E33, //CJK UNIFIED IDEOGRAPH + 0x8151: 0x4E35, //CJK UNIFIED IDEOGRAPH + 0x8152: 0x4E37, //CJK UNIFIED IDEOGRAPH + 0x8153: 0x4E3C, //CJK UNIFIED IDEOGRAPH + 0x8154: 0x4E40, //CJK UNIFIED IDEOGRAPH + 0x8155: 0x4E41, //CJK UNIFIED IDEOGRAPH + 0x8156: 0x4E42, //CJK UNIFIED IDEOGRAPH + 0x8157: 0x4E44, //CJK UNIFIED IDEOGRAPH + 0x8158: 0x4E46, //CJK UNIFIED IDEOGRAPH + 0x8159: 0x4E4A, //CJK UNIFIED IDEOGRAPH + 0x815A: 0x4E51, //CJK UNIFIED IDEOGRAPH + 0x815B: 0x4E55, //CJK UNIFIED IDEOGRAPH + 0x815C: 0x4E57, //CJK UNIFIED IDEOGRAPH + 0x815D: 0x4E5A, //CJK UNIFIED IDEOGRAPH + 0x815E: 0x4E5B, //CJK UNIFIED IDEOGRAPH + 0x815F: 0x4E62, //CJK UNIFIED IDEOGRAPH + 0x8160: 0x4E63, //CJK UNIFIED IDEOGRAPH + 0x8161: 0x4E64, //CJK UNIFIED IDEOGRAPH + 0x8162: 0x4E65, //CJK UNIFIED IDEOGRAPH + 0x8163: 0x4E67, //CJK UNIFIED IDEOGRAPH + 0x8164: 0x4E68, //CJK UNIFIED IDEOGRAPH + 0x8165: 0x4E6A, //CJK UNIFIED IDEOGRAPH + 0x8166: 0x4E6B, //CJK UNIFIED IDEOGRAPH + 0x8167: 0x4E6C, //CJK UNIFIED IDEOGRAPH + 0x8168: 0x4E6D, //CJK UNIFIED IDEOGRAPH + 0x8169: 0x4E6E, //CJK UNIFIED IDEOGRAPH + 0x816A: 0x4E6F, //CJK UNIFIED IDEOGRAPH + 0x816B: 0x4E72, //CJK UNIFIED IDEOGRAPH + 0x816C: 0x4E74, //CJK UNIFIED IDEOGRAPH + 0x816D: 0x4E75, //CJK UNIFIED IDEOGRAPH + 0x816E: 0x4E76, //CJK UNIFIED IDEOGRAPH + 0x816F: 0x4E77, //CJK UNIFIED IDEOGRAPH + 0x8170: 0x4E78, //CJK UNIFIED IDEOGRAPH + 0x8171: 0x4E79, //CJK UNIFIED IDEOGRAPH + 0x8172: 0x4E7A, //CJK UNIFIED IDEOGRAPH + 0x8173: 0x4E7B, //CJK UNIFIED IDEOGRAPH + 0x8174: 0x4E7C, //CJK UNIFIED IDEOGRAPH + 0x8175: 0x4E7D, //CJK UNIFIED IDEOGRAPH + 0x8176: 0x4E7F, //CJK UNIFIED IDEOGRAPH + 0x8177: 0x4E80, //CJK UNIFIED IDEOGRAPH + 0x8178: 0x4E81, //CJK UNIFIED IDEOGRAPH + 0x8179: 0x4E82, //CJK UNIFIED IDEOGRAPH + 0x817A: 0x4E83, //CJK UNIFIED IDEOGRAPH + 0x817B: 0x4E84, //CJK UNIFIED IDEOGRAPH + 0x817C: 0x4E85, //CJK UNIFIED IDEOGRAPH + 0x817D: 0x4E87, //CJK UNIFIED IDEOGRAPH + 0x817E: 0x4E8A, //CJK UNIFIED IDEOGRAPH + 0x8180: 0x4E90, //CJK UNIFIED IDEOGRAPH + 0x8181: 0x4E96, //CJK UNIFIED IDEOGRAPH + 0x8182: 0x4E97, //CJK UNIFIED IDEOGRAPH + 0x8183: 0x4E99, //CJK UNIFIED IDEOGRAPH + 0x8184: 0x4E9C, //CJK UNIFIED IDEOGRAPH + 0x8185: 0x4E9D, //CJK UNIFIED IDEOGRAPH + 0x8186: 0x4E9E, //CJK UNIFIED IDEOGRAPH + 0x8187: 0x4EA3, //CJK UNIFIED IDEOGRAPH + 0x8188: 0x4EAA, //CJK UNIFIED IDEOGRAPH + 0x8189: 0x4EAF, //CJK UNIFIED IDEOGRAPH + 0x818A: 0x4EB0, //CJK UNIFIED IDEOGRAPH + 0x818B: 0x4EB1, //CJK UNIFIED IDEOGRAPH + 0x818C: 0x4EB4, //CJK UNIFIED IDEOGRAPH + 0x818D: 0x4EB6, //CJK UNIFIED IDEOGRAPH + 0x818E: 0x4EB7, //CJK UNIFIED IDEOGRAPH + 0x818F: 0x4EB8, //CJK UNIFIED IDEOGRAPH + 0x8190: 0x4EB9, //CJK UNIFIED IDEOGRAPH + 0x8191: 0x4EBC, //CJK UNIFIED IDEOGRAPH + 0x8192: 0x4EBD, //CJK UNIFIED IDEOGRAPH + 0x8193: 0x4EBE, //CJK UNIFIED IDEOGRAPH + 0x8194: 0x4EC8, //CJK UNIFIED IDEOGRAPH + 0x8195: 0x4ECC, //CJK UNIFIED IDEOGRAPH + 0x8196: 0x4ECF, //CJK UNIFIED IDEOGRAPH + 0x8197: 0x4ED0, //CJK UNIFIED IDEOGRAPH + 0x8198: 0x4ED2, //CJK UNIFIED IDEOGRAPH + 0x8199: 0x4EDA, //CJK UNIFIED IDEOGRAPH + 0x819A: 0x4EDB, //CJK UNIFIED IDEOGRAPH + 0x819B: 0x4EDC, //CJK UNIFIED IDEOGRAPH + 0x819C: 0x4EE0, //CJK UNIFIED IDEOGRAPH + 0x819D: 0x4EE2, //CJK UNIFIED IDEOGRAPH + 0x819E: 0x4EE6, //CJK UNIFIED IDEOGRAPH + 0x819F: 0x4EE7, //CJK UNIFIED IDEOGRAPH + 0x81A0: 0x4EE9, //CJK UNIFIED IDEOGRAPH + 0x81A1: 0x4EED, //CJK UNIFIED IDEOGRAPH + 0x81A2: 0x4EEE, //CJK UNIFIED IDEOGRAPH + 0x81A3: 0x4EEF, //CJK UNIFIED IDEOGRAPH + 0x81A4: 0x4EF1, //CJK UNIFIED IDEOGRAPH + 0x81A5: 0x4EF4, //CJK UNIFIED IDEOGRAPH + 0x81A6: 0x4EF8, //CJK UNIFIED IDEOGRAPH + 0x81A7: 0x4EF9, //CJK UNIFIED IDEOGRAPH + 0x81A8: 0x4EFA, //CJK UNIFIED IDEOGRAPH + 0x81A9: 0x4EFC, //CJK UNIFIED IDEOGRAPH + 0x81AA: 0x4EFE, //CJK UNIFIED IDEOGRAPH + 0x81AB: 0x4F00, //CJK UNIFIED IDEOGRAPH + 0x81AC: 0x4F02, //CJK UNIFIED IDEOGRAPH + 0x81AD: 0x4F03, //CJK UNIFIED IDEOGRAPH + 0x81AE: 0x4F04, //CJK UNIFIED IDEOGRAPH + 0x81AF: 0x4F05, //CJK UNIFIED IDEOGRAPH + 0x81B0: 0x4F06, //CJK UNIFIED IDEOGRAPH + 0x81B1: 0x4F07, //CJK UNIFIED IDEOGRAPH + 0x81B2: 0x4F08, //CJK UNIFIED IDEOGRAPH + 0x81B3: 0x4F0B, //CJK UNIFIED IDEOGRAPH + 0x81B4: 0x4F0C, //CJK UNIFIED IDEOGRAPH + 0x81B5: 0x4F12, //CJK UNIFIED IDEOGRAPH + 0x81B6: 0x4F13, //CJK UNIFIED IDEOGRAPH + 0x81B7: 0x4F14, //CJK UNIFIED IDEOGRAPH + 0x81B8: 0x4F15, //CJK UNIFIED IDEOGRAPH + 0x81B9: 0x4F16, //CJK UNIFIED IDEOGRAPH + 0x81BA: 0x4F1C, //CJK UNIFIED IDEOGRAPH + 0x81BB: 0x4F1D, //CJK UNIFIED IDEOGRAPH + 0x81BC: 0x4F21, //CJK UNIFIED IDEOGRAPH + 0x81BD: 0x4F23, //CJK UNIFIED IDEOGRAPH + 0x81BE: 0x4F28, //CJK UNIFIED IDEOGRAPH + 0x81BF: 0x4F29, //CJK UNIFIED IDEOGRAPH + 0x81C0: 0x4F2C, //CJK UNIFIED IDEOGRAPH + 0x81C1: 0x4F2D, //CJK UNIFIED IDEOGRAPH + 0x81C2: 0x4F2E, //CJK UNIFIED IDEOGRAPH + 0x81C3: 0x4F31, //CJK UNIFIED IDEOGRAPH + 0x81C4: 0x4F33, //CJK UNIFIED IDEOGRAPH + 0x81C5: 0x4F35, //CJK UNIFIED IDEOGRAPH + 0x81C6: 0x4F37, //CJK UNIFIED IDEOGRAPH + 0x81C7: 0x4F39, //CJK UNIFIED IDEOGRAPH + 0x81C8: 0x4F3B, //CJK UNIFIED IDEOGRAPH + 0x81C9: 0x4F3E, //CJK UNIFIED IDEOGRAPH + 0x81CA: 0x4F3F, //CJK UNIFIED IDEOGRAPH + 0x81CB: 0x4F40, //CJK UNIFIED IDEOGRAPH + 0x81CC: 0x4F41, //CJK UNIFIED IDEOGRAPH + 0x81CD: 0x4F42, //CJK UNIFIED IDEOGRAPH + 0x81CE: 0x4F44, //CJK UNIFIED IDEOGRAPH + 0x81CF: 0x4F45, //CJK UNIFIED IDEOGRAPH + 0x81D0: 0x4F47, //CJK UNIFIED IDEOGRAPH + 0x81D1: 0x4F48, //CJK UNIFIED IDEOGRAPH + 0x81D2: 0x4F49, //CJK UNIFIED IDEOGRAPH + 0x81D3: 0x4F4A, //CJK UNIFIED IDEOGRAPH + 0x81D4: 0x4F4B, //CJK UNIFIED IDEOGRAPH + 0x81D5: 0x4F4C, //CJK UNIFIED IDEOGRAPH + 0x81D6: 0x4F52, //CJK UNIFIED IDEOGRAPH + 0x81D7: 0x4F54, //CJK UNIFIED IDEOGRAPH + 0x81D8: 0x4F56, //CJK UNIFIED IDEOGRAPH + 0x81D9: 0x4F61, //CJK UNIFIED IDEOGRAPH + 0x81DA: 0x4F62, //CJK UNIFIED IDEOGRAPH + 0x81DB: 0x4F66, //CJK UNIFIED IDEOGRAPH + 0x81DC: 0x4F68, //CJK UNIFIED IDEOGRAPH + 0x81DD: 0x4F6A, //CJK UNIFIED IDEOGRAPH + 0x81DE: 0x4F6B, //CJK UNIFIED IDEOGRAPH + 0x81DF: 0x4F6D, //CJK UNIFIED IDEOGRAPH + 0x81E0: 0x4F6E, //CJK UNIFIED IDEOGRAPH + 0x81E1: 0x4F71, //CJK UNIFIED IDEOGRAPH + 0x81E2: 0x4F72, //CJK UNIFIED IDEOGRAPH + 0x81E3: 0x4F75, //CJK UNIFIED IDEOGRAPH + 0x81E4: 0x4F77, //CJK UNIFIED IDEOGRAPH + 0x81E5: 0x4F78, //CJK UNIFIED IDEOGRAPH + 0x81E6: 0x4F79, //CJK UNIFIED IDEOGRAPH + 0x81E7: 0x4F7A, //CJK UNIFIED IDEOGRAPH + 0x81E8: 0x4F7D, //CJK UNIFIED IDEOGRAPH + 0x81E9: 0x4F80, //CJK UNIFIED IDEOGRAPH + 0x81EA: 0x4F81, //CJK UNIFIED IDEOGRAPH + 0x81EB: 0x4F82, //CJK UNIFIED IDEOGRAPH + 0x81EC: 0x4F85, //CJK UNIFIED IDEOGRAPH + 0x81ED: 0x4F86, //CJK UNIFIED IDEOGRAPH + 0x81EE: 0x4F87, //CJK UNIFIED IDEOGRAPH + 0x81EF: 0x4F8A, //CJK UNIFIED IDEOGRAPH + 0x81F0: 0x4F8C, //CJK UNIFIED IDEOGRAPH + 0x81F1: 0x4F8E, //CJK UNIFIED IDEOGRAPH + 0x81F2: 0x4F90, //CJK UNIFIED IDEOGRAPH + 0x81F3: 0x4F92, //CJK UNIFIED IDEOGRAPH + 0x81F4: 0x4F93, //CJK UNIFIED IDEOGRAPH + 0x81F5: 0x4F95, //CJK UNIFIED IDEOGRAPH + 0x81F6: 0x4F96, //CJK UNIFIED IDEOGRAPH + 0x81F7: 0x4F98, //CJK UNIFIED IDEOGRAPH + 0x81F8: 0x4F99, //CJK UNIFIED IDEOGRAPH + 0x81F9: 0x4F9A, //CJK UNIFIED IDEOGRAPH + 0x81FA: 0x4F9C, //CJK UNIFIED IDEOGRAPH + 0x81FB: 0x4F9E, //CJK UNIFIED IDEOGRAPH + 0x81FC: 0x4F9F, //CJK UNIFIED IDEOGRAPH + 0x81FD: 0x4FA1, //CJK UNIFIED IDEOGRAPH + 0x81FE: 0x4FA2, //CJK UNIFIED IDEOGRAPH + 0x8240: 0x4FA4, //CJK UNIFIED IDEOGRAPH + 0x8241: 0x4FAB, //CJK UNIFIED IDEOGRAPH + 0x8242: 0x4FAD, //CJK UNIFIED IDEOGRAPH + 0x8243: 0x4FB0, //CJK UNIFIED IDEOGRAPH + 0x8244: 0x4FB1, //CJK UNIFIED IDEOGRAPH + 0x8245: 0x4FB2, //CJK UNIFIED IDEOGRAPH + 0x8246: 0x4FB3, //CJK UNIFIED IDEOGRAPH + 0x8247: 0x4FB4, //CJK UNIFIED IDEOGRAPH + 0x8248: 0x4FB6, //CJK UNIFIED IDEOGRAPH + 0x8249: 0x4FB7, //CJK UNIFIED IDEOGRAPH + 0x824A: 0x4FB8, //CJK UNIFIED IDEOGRAPH + 0x824B: 0x4FB9, //CJK UNIFIED IDEOGRAPH + 0x824C: 0x4FBA, //CJK UNIFIED IDEOGRAPH + 0x824D: 0x4FBB, //CJK UNIFIED IDEOGRAPH + 0x824E: 0x4FBC, //CJK UNIFIED IDEOGRAPH + 0x824F: 0x4FBD, //CJK UNIFIED IDEOGRAPH + 0x8250: 0x4FBE, //CJK UNIFIED IDEOGRAPH + 0x8251: 0x4FC0, //CJK UNIFIED IDEOGRAPH + 0x8252: 0x4FC1, //CJK UNIFIED IDEOGRAPH + 0x8253: 0x4FC2, //CJK UNIFIED IDEOGRAPH + 0x8254: 0x4FC6, //CJK UNIFIED IDEOGRAPH + 0x8255: 0x4FC7, //CJK UNIFIED IDEOGRAPH + 0x8256: 0x4FC8, //CJK UNIFIED IDEOGRAPH + 0x8257: 0x4FC9, //CJK UNIFIED IDEOGRAPH + 0x8258: 0x4FCB, //CJK UNIFIED IDEOGRAPH + 0x8259: 0x4FCC, //CJK UNIFIED IDEOGRAPH + 0x825A: 0x4FCD, //CJK UNIFIED IDEOGRAPH + 0x825B: 0x4FD2, //CJK UNIFIED IDEOGRAPH + 0x825C: 0x4FD3, //CJK UNIFIED IDEOGRAPH + 0x825D: 0x4FD4, //CJK UNIFIED IDEOGRAPH + 0x825E: 0x4FD5, //CJK UNIFIED IDEOGRAPH + 0x825F: 0x4FD6, //CJK UNIFIED IDEOGRAPH + 0x8260: 0x4FD9, //CJK UNIFIED IDEOGRAPH + 0x8261: 0x4FDB, //CJK UNIFIED IDEOGRAPH + 0x8262: 0x4FE0, //CJK UNIFIED IDEOGRAPH + 0x8263: 0x4FE2, //CJK UNIFIED IDEOGRAPH + 0x8264: 0x4FE4, //CJK UNIFIED IDEOGRAPH + 0x8265: 0x4FE5, //CJK UNIFIED IDEOGRAPH + 0x8266: 0x4FE7, //CJK UNIFIED IDEOGRAPH + 0x8267: 0x4FEB, //CJK UNIFIED IDEOGRAPH + 0x8268: 0x4FEC, //CJK UNIFIED IDEOGRAPH + 0x8269: 0x4FF0, //CJK UNIFIED IDEOGRAPH + 0x826A: 0x4FF2, //CJK UNIFIED IDEOGRAPH + 0x826B: 0x4FF4, //CJK UNIFIED IDEOGRAPH + 0x826C: 0x4FF5, //CJK UNIFIED IDEOGRAPH + 0x826D: 0x4FF6, //CJK UNIFIED IDEOGRAPH + 0x826E: 0x4FF7, //CJK UNIFIED IDEOGRAPH + 0x826F: 0x4FF9, //CJK UNIFIED IDEOGRAPH + 0x8270: 0x4FFB, //CJK UNIFIED IDEOGRAPH + 0x8271: 0x4FFC, //CJK UNIFIED IDEOGRAPH + 0x8272: 0x4FFD, //CJK UNIFIED IDEOGRAPH + 0x8273: 0x4FFF, //CJK UNIFIED IDEOGRAPH + 0x8274: 0x5000, //CJK UNIFIED IDEOGRAPH + 0x8275: 0x5001, //CJK UNIFIED IDEOGRAPH + 0x8276: 0x5002, //CJK UNIFIED IDEOGRAPH + 0x8277: 0x5003, //CJK UNIFIED IDEOGRAPH + 0x8278: 0x5004, //CJK UNIFIED IDEOGRAPH + 0x8279: 0x5005, //CJK UNIFIED IDEOGRAPH + 0x827A: 0x5006, //CJK UNIFIED IDEOGRAPH + 0x827B: 0x5007, //CJK UNIFIED IDEOGRAPH + 0x827C: 0x5008, //CJK UNIFIED IDEOGRAPH + 0x827D: 0x5009, //CJK UNIFIED IDEOGRAPH + 0x827E: 0x500A, //CJK UNIFIED IDEOGRAPH + 0x8280: 0x500B, //CJK UNIFIED IDEOGRAPH + 0x8281: 0x500E, //CJK UNIFIED IDEOGRAPH + 0x8282: 0x5010, //CJK UNIFIED IDEOGRAPH + 0x8283: 0x5011, //CJK UNIFIED IDEOGRAPH + 0x8284: 0x5013, //CJK UNIFIED IDEOGRAPH + 0x8285: 0x5015, //CJK UNIFIED IDEOGRAPH + 0x8286: 0x5016, //CJK UNIFIED IDEOGRAPH + 0x8287: 0x5017, //CJK UNIFIED IDEOGRAPH + 0x8288: 0x501B, //CJK UNIFIED IDEOGRAPH + 0x8289: 0x501D, //CJK UNIFIED IDEOGRAPH + 0x828A: 0x501E, //CJK UNIFIED IDEOGRAPH + 0x828B: 0x5020, //CJK UNIFIED IDEOGRAPH + 0x828C: 0x5022, //CJK UNIFIED IDEOGRAPH + 0x828D: 0x5023, //CJK UNIFIED IDEOGRAPH + 0x828E: 0x5024, //CJK UNIFIED IDEOGRAPH + 0x828F: 0x5027, //CJK UNIFIED IDEOGRAPH + 0x8290: 0x502B, //CJK UNIFIED IDEOGRAPH + 0x8291: 0x502F, //CJK UNIFIED IDEOGRAPH + 0x8292: 0x5030, //CJK UNIFIED IDEOGRAPH + 0x8293: 0x5031, //CJK UNIFIED IDEOGRAPH + 0x8294: 0x5032, //CJK UNIFIED IDEOGRAPH + 0x8295: 0x5033, //CJK UNIFIED IDEOGRAPH + 0x8296: 0x5034, //CJK UNIFIED IDEOGRAPH + 0x8297: 0x5035, //CJK UNIFIED IDEOGRAPH + 0x8298: 0x5036, //CJK UNIFIED IDEOGRAPH + 0x8299: 0x5037, //CJK UNIFIED IDEOGRAPH + 0x829A: 0x5038, //CJK UNIFIED IDEOGRAPH + 0x829B: 0x5039, //CJK UNIFIED IDEOGRAPH + 0x829C: 0x503B, //CJK UNIFIED IDEOGRAPH + 0x829D: 0x503D, //CJK UNIFIED IDEOGRAPH + 0x829E: 0x503F, //CJK UNIFIED IDEOGRAPH + 0x829F: 0x5040, //CJK UNIFIED IDEOGRAPH + 0x82A0: 0x5041, //CJK UNIFIED IDEOGRAPH + 0x82A1: 0x5042, //CJK UNIFIED IDEOGRAPH + 0x82A2: 0x5044, //CJK UNIFIED IDEOGRAPH + 0x82A3: 0x5045, //CJK UNIFIED IDEOGRAPH + 0x82A4: 0x5046, //CJK UNIFIED IDEOGRAPH + 0x82A5: 0x5049, //CJK UNIFIED IDEOGRAPH + 0x82A6: 0x504A, //CJK UNIFIED IDEOGRAPH + 0x82A7: 0x504B, //CJK UNIFIED IDEOGRAPH + 0x82A8: 0x504D, //CJK UNIFIED IDEOGRAPH + 0x82A9: 0x5050, //CJK UNIFIED IDEOGRAPH + 0x82AA: 0x5051, //CJK UNIFIED IDEOGRAPH + 0x82AB: 0x5052, //CJK UNIFIED IDEOGRAPH + 0x82AC: 0x5053, //CJK UNIFIED IDEOGRAPH + 0x82AD: 0x5054, //CJK UNIFIED IDEOGRAPH + 0x82AE: 0x5056, //CJK UNIFIED IDEOGRAPH + 0x82AF: 0x5057, //CJK UNIFIED IDEOGRAPH + 0x82B0: 0x5058, //CJK UNIFIED IDEOGRAPH + 0x82B1: 0x5059, //CJK UNIFIED IDEOGRAPH + 0x82B2: 0x505B, //CJK UNIFIED IDEOGRAPH + 0x82B3: 0x505D, //CJK UNIFIED IDEOGRAPH + 0x82B4: 0x505E, //CJK UNIFIED IDEOGRAPH + 0x82B5: 0x505F, //CJK UNIFIED IDEOGRAPH + 0x82B6: 0x5060, //CJK UNIFIED IDEOGRAPH + 0x82B7: 0x5061, //CJK UNIFIED IDEOGRAPH + 0x82B8: 0x5062, //CJK UNIFIED IDEOGRAPH + 0x82B9: 0x5063, //CJK UNIFIED IDEOGRAPH + 0x82BA: 0x5064, //CJK UNIFIED IDEOGRAPH + 0x82BB: 0x5066, //CJK UNIFIED IDEOGRAPH + 0x82BC: 0x5067, //CJK UNIFIED IDEOGRAPH + 0x82BD: 0x5068, //CJK UNIFIED IDEOGRAPH + 0x82BE: 0x5069, //CJK UNIFIED IDEOGRAPH + 0x82BF: 0x506A, //CJK UNIFIED IDEOGRAPH + 0x82C0: 0x506B, //CJK UNIFIED IDEOGRAPH + 0x82C1: 0x506D, //CJK UNIFIED IDEOGRAPH + 0x82C2: 0x506E, //CJK UNIFIED IDEOGRAPH + 0x82C3: 0x506F, //CJK UNIFIED IDEOGRAPH + 0x82C4: 0x5070, //CJK UNIFIED IDEOGRAPH + 0x82C5: 0x5071, //CJK UNIFIED IDEOGRAPH + 0x82C6: 0x5072, //CJK UNIFIED IDEOGRAPH + 0x82C7: 0x5073, //CJK UNIFIED IDEOGRAPH + 0x82C8: 0x5074, //CJK UNIFIED IDEOGRAPH + 0x82C9: 0x5075, //CJK UNIFIED IDEOGRAPH + 0x82CA: 0x5078, //CJK UNIFIED IDEOGRAPH + 0x82CB: 0x5079, //CJK UNIFIED IDEOGRAPH + 0x82CC: 0x507A, //CJK UNIFIED IDEOGRAPH + 0x82CD: 0x507C, //CJK UNIFIED IDEOGRAPH + 0x82CE: 0x507D, //CJK UNIFIED IDEOGRAPH + 0x82CF: 0x5081, //CJK UNIFIED IDEOGRAPH + 0x82D0: 0x5082, //CJK UNIFIED IDEOGRAPH + 0x82D1: 0x5083, //CJK UNIFIED IDEOGRAPH + 0x82D2: 0x5084, //CJK UNIFIED IDEOGRAPH + 0x82D3: 0x5086, //CJK UNIFIED IDEOGRAPH + 0x82D4: 0x5087, //CJK UNIFIED IDEOGRAPH + 0x82D5: 0x5089, //CJK UNIFIED IDEOGRAPH + 0x82D6: 0x508A, //CJK UNIFIED IDEOGRAPH + 0x82D7: 0x508B, //CJK UNIFIED IDEOGRAPH + 0x82D8: 0x508C, //CJK UNIFIED IDEOGRAPH + 0x82D9: 0x508E, //CJK UNIFIED IDEOGRAPH + 0x82DA: 0x508F, //CJK UNIFIED IDEOGRAPH + 0x82DB: 0x5090, //CJK UNIFIED IDEOGRAPH + 0x82DC: 0x5091, //CJK UNIFIED IDEOGRAPH + 0x82DD: 0x5092, //CJK UNIFIED IDEOGRAPH + 0x82DE: 0x5093, //CJK UNIFIED IDEOGRAPH + 0x82DF: 0x5094, //CJK UNIFIED IDEOGRAPH + 0x82E0: 0x5095, //CJK UNIFIED IDEOGRAPH + 0x82E1: 0x5096, //CJK UNIFIED IDEOGRAPH + 0x82E2: 0x5097, //CJK UNIFIED IDEOGRAPH + 0x82E3: 0x5098, //CJK UNIFIED IDEOGRAPH + 0x82E4: 0x5099, //CJK UNIFIED IDEOGRAPH + 0x82E5: 0x509A, //CJK UNIFIED IDEOGRAPH + 0x82E6: 0x509B, //CJK UNIFIED IDEOGRAPH + 0x82E7: 0x509C, //CJK UNIFIED IDEOGRAPH + 0x82E8: 0x509D, //CJK UNIFIED IDEOGRAPH + 0x82E9: 0x509E, //CJK UNIFIED IDEOGRAPH + 0x82EA: 0x509F, //CJK UNIFIED IDEOGRAPH + 0x82EB: 0x50A0, //CJK UNIFIED IDEOGRAPH + 0x82EC: 0x50A1, //CJK UNIFIED IDEOGRAPH + 0x82ED: 0x50A2, //CJK UNIFIED IDEOGRAPH + 0x82EE: 0x50A4, //CJK UNIFIED IDEOGRAPH + 0x82EF: 0x50A6, //CJK UNIFIED IDEOGRAPH + 0x82F0: 0x50AA, //CJK UNIFIED IDEOGRAPH + 0x82F1: 0x50AB, //CJK UNIFIED IDEOGRAPH + 0x82F2: 0x50AD, //CJK UNIFIED IDEOGRAPH + 0x82F3: 0x50AE, //CJK UNIFIED IDEOGRAPH + 0x82F4: 0x50AF, //CJK UNIFIED IDEOGRAPH + 0x82F5: 0x50B0, //CJK UNIFIED IDEOGRAPH + 0x82F6: 0x50B1, //CJK UNIFIED IDEOGRAPH + 0x82F7: 0x50B3, //CJK UNIFIED IDEOGRAPH + 0x82F8: 0x50B4, //CJK UNIFIED IDEOGRAPH + 0x82F9: 0x50B5, //CJK UNIFIED IDEOGRAPH + 0x82FA: 0x50B6, //CJK UNIFIED IDEOGRAPH + 0x82FB: 0x50B7, //CJK UNIFIED IDEOGRAPH + 0x82FC: 0x50B8, //CJK UNIFIED IDEOGRAPH + 0x82FD: 0x50B9, //CJK UNIFIED IDEOGRAPH + 0x82FE: 0x50BC, //CJK UNIFIED IDEOGRAPH + 0x8340: 0x50BD, //CJK UNIFIED IDEOGRAPH + 0x8341: 0x50BE, //CJK UNIFIED IDEOGRAPH + 0x8342: 0x50BF, //CJK UNIFIED IDEOGRAPH + 0x8343: 0x50C0, //CJK UNIFIED IDEOGRAPH + 0x8344: 0x50C1, //CJK UNIFIED IDEOGRAPH + 0x8345: 0x50C2, //CJK UNIFIED IDEOGRAPH + 0x8346: 0x50C3, //CJK UNIFIED IDEOGRAPH + 0x8347: 0x50C4, //CJK UNIFIED IDEOGRAPH + 0x8348: 0x50C5, //CJK UNIFIED IDEOGRAPH + 0x8349: 0x50C6, //CJK UNIFIED IDEOGRAPH + 0x834A: 0x50C7, //CJK UNIFIED IDEOGRAPH + 0x834B: 0x50C8, //CJK UNIFIED IDEOGRAPH + 0x834C: 0x50C9, //CJK UNIFIED IDEOGRAPH + 0x834D: 0x50CA, //CJK UNIFIED IDEOGRAPH + 0x834E: 0x50CB, //CJK UNIFIED IDEOGRAPH + 0x834F: 0x50CC, //CJK UNIFIED IDEOGRAPH + 0x8350: 0x50CD, //CJK UNIFIED IDEOGRAPH + 0x8351: 0x50CE, //CJK UNIFIED IDEOGRAPH + 0x8352: 0x50D0, //CJK UNIFIED IDEOGRAPH + 0x8353: 0x50D1, //CJK UNIFIED IDEOGRAPH + 0x8354: 0x50D2, //CJK UNIFIED IDEOGRAPH + 0x8355: 0x50D3, //CJK UNIFIED IDEOGRAPH + 0x8356: 0x50D4, //CJK UNIFIED IDEOGRAPH + 0x8357: 0x50D5, //CJK UNIFIED IDEOGRAPH + 0x8358: 0x50D7, //CJK UNIFIED IDEOGRAPH + 0x8359: 0x50D8, //CJK UNIFIED IDEOGRAPH + 0x835A: 0x50D9, //CJK UNIFIED IDEOGRAPH + 0x835B: 0x50DB, //CJK UNIFIED IDEOGRAPH + 0x835C: 0x50DC, //CJK UNIFIED IDEOGRAPH + 0x835D: 0x50DD, //CJK UNIFIED IDEOGRAPH + 0x835E: 0x50DE, //CJK UNIFIED IDEOGRAPH + 0x835F: 0x50DF, //CJK UNIFIED IDEOGRAPH + 0x8360: 0x50E0, //CJK UNIFIED IDEOGRAPH + 0x8361: 0x50E1, //CJK UNIFIED IDEOGRAPH + 0x8362: 0x50E2, //CJK UNIFIED IDEOGRAPH + 0x8363: 0x50E3, //CJK UNIFIED IDEOGRAPH + 0x8364: 0x50E4, //CJK UNIFIED IDEOGRAPH + 0x8365: 0x50E5, //CJK UNIFIED IDEOGRAPH + 0x8366: 0x50E8, //CJK UNIFIED IDEOGRAPH + 0x8367: 0x50E9, //CJK UNIFIED IDEOGRAPH + 0x8368: 0x50EA, //CJK UNIFIED IDEOGRAPH + 0x8369: 0x50EB, //CJK UNIFIED IDEOGRAPH + 0x836A: 0x50EF, //CJK UNIFIED IDEOGRAPH + 0x836B: 0x50F0, //CJK UNIFIED IDEOGRAPH + 0x836C: 0x50F1, //CJK UNIFIED IDEOGRAPH + 0x836D: 0x50F2, //CJK UNIFIED IDEOGRAPH + 0x836E: 0x50F4, //CJK UNIFIED IDEOGRAPH + 0x836F: 0x50F6, //CJK UNIFIED IDEOGRAPH + 0x8370: 0x50F7, //CJK UNIFIED IDEOGRAPH + 0x8371: 0x50F8, //CJK UNIFIED IDEOGRAPH + 0x8372: 0x50F9, //CJK UNIFIED IDEOGRAPH + 0x8373: 0x50FA, //CJK UNIFIED IDEOGRAPH + 0x8374: 0x50FC, //CJK UNIFIED IDEOGRAPH + 0x8375: 0x50FD, //CJK UNIFIED IDEOGRAPH + 0x8376: 0x50FE, //CJK UNIFIED IDEOGRAPH + 0x8377: 0x50FF, //CJK UNIFIED IDEOGRAPH + 0x8378: 0x5100, //CJK UNIFIED IDEOGRAPH + 0x8379: 0x5101, //CJK UNIFIED IDEOGRAPH + 0x837A: 0x5102, //CJK UNIFIED IDEOGRAPH + 0x837B: 0x5103, //CJK UNIFIED IDEOGRAPH + 0x837C: 0x5104, //CJK UNIFIED IDEOGRAPH + 0x837D: 0x5105, //CJK UNIFIED IDEOGRAPH + 0x837E: 0x5108, //CJK UNIFIED IDEOGRAPH + 0x8380: 0x5109, //CJK UNIFIED IDEOGRAPH + 0x8381: 0x510A, //CJK UNIFIED IDEOGRAPH + 0x8382: 0x510C, //CJK UNIFIED IDEOGRAPH + 0x8383: 0x510D, //CJK UNIFIED IDEOGRAPH + 0x8384: 0x510E, //CJK UNIFIED IDEOGRAPH + 0x8385: 0x510F, //CJK UNIFIED IDEOGRAPH + 0x8386: 0x5110, //CJK UNIFIED IDEOGRAPH + 0x8387: 0x5111, //CJK UNIFIED IDEOGRAPH + 0x8388: 0x5113, //CJK UNIFIED IDEOGRAPH + 0x8389: 0x5114, //CJK UNIFIED IDEOGRAPH + 0x838A: 0x5115, //CJK UNIFIED IDEOGRAPH + 0x838B: 0x5116, //CJK UNIFIED IDEOGRAPH + 0x838C: 0x5117, //CJK UNIFIED IDEOGRAPH + 0x838D: 0x5118, //CJK UNIFIED IDEOGRAPH + 0x838E: 0x5119, //CJK UNIFIED IDEOGRAPH + 0x838F: 0x511A, //CJK UNIFIED IDEOGRAPH + 0x8390: 0x511B, //CJK UNIFIED IDEOGRAPH + 0x8391: 0x511C, //CJK UNIFIED IDEOGRAPH + 0x8392: 0x511D, //CJK UNIFIED IDEOGRAPH + 0x8393: 0x511E, //CJK UNIFIED IDEOGRAPH + 0x8394: 0x511F, //CJK UNIFIED IDEOGRAPH + 0x8395: 0x5120, //CJK UNIFIED IDEOGRAPH + 0x8396: 0x5122, //CJK UNIFIED IDEOGRAPH + 0x8397: 0x5123, //CJK UNIFIED IDEOGRAPH + 0x8398: 0x5124, //CJK UNIFIED IDEOGRAPH + 0x8399: 0x5125, //CJK UNIFIED IDEOGRAPH + 0x839A: 0x5126, //CJK UNIFIED IDEOGRAPH + 0x839B: 0x5127, //CJK UNIFIED IDEOGRAPH + 0x839C: 0x5128, //CJK UNIFIED IDEOGRAPH + 0x839D: 0x5129, //CJK UNIFIED IDEOGRAPH + 0x839E: 0x512A, //CJK UNIFIED IDEOGRAPH + 0x839F: 0x512B, //CJK UNIFIED IDEOGRAPH + 0x83A0: 0x512C, //CJK UNIFIED IDEOGRAPH + 0x83A1: 0x512D, //CJK UNIFIED IDEOGRAPH + 0x83A2: 0x512E, //CJK UNIFIED IDEOGRAPH + 0x83A3: 0x512F, //CJK UNIFIED IDEOGRAPH + 0x83A4: 0x5130, //CJK UNIFIED IDEOGRAPH + 0x83A5: 0x5131, //CJK UNIFIED IDEOGRAPH + 0x83A6: 0x5132, //CJK UNIFIED IDEOGRAPH + 0x83A7: 0x5133, //CJK UNIFIED IDEOGRAPH + 0x83A8: 0x5134, //CJK UNIFIED IDEOGRAPH + 0x83A9: 0x5135, //CJK UNIFIED IDEOGRAPH + 0x83AA: 0x5136, //CJK UNIFIED IDEOGRAPH + 0x83AB: 0x5137, //CJK UNIFIED IDEOGRAPH + 0x83AC: 0x5138, //CJK UNIFIED IDEOGRAPH + 0x83AD: 0x5139, //CJK UNIFIED IDEOGRAPH + 0x83AE: 0x513A, //CJK UNIFIED IDEOGRAPH + 0x83AF: 0x513B, //CJK UNIFIED IDEOGRAPH + 0x83B0: 0x513C, //CJK UNIFIED IDEOGRAPH + 0x83B1: 0x513D, //CJK UNIFIED IDEOGRAPH + 0x83B2: 0x513E, //CJK UNIFIED IDEOGRAPH + 0x83B3: 0x5142, //CJK UNIFIED IDEOGRAPH + 0x83B4: 0x5147, //CJK UNIFIED IDEOGRAPH + 0x83B5: 0x514A, //CJK UNIFIED IDEOGRAPH + 0x83B6: 0x514C, //CJK UNIFIED IDEOGRAPH + 0x83B7: 0x514E, //CJK UNIFIED IDEOGRAPH + 0x83B8: 0x514F, //CJK UNIFIED IDEOGRAPH + 0x83B9: 0x5150, //CJK UNIFIED IDEOGRAPH + 0x83BA: 0x5152, //CJK UNIFIED IDEOGRAPH + 0x83BB: 0x5153, //CJK UNIFIED IDEOGRAPH + 0x83BC: 0x5157, //CJK UNIFIED IDEOGRAPH + 0x83BD: 0x5158, //CJK UNIFIED IDEOGRAPH + 0x83BE: 0x5159, //CJK UNIFIED IDEOGRAPH + 0x83BF: 0x515B, //CJK UNIFIED IDEOGRAPH + 0x83C0: 0x515D, //CJK UNIFIED IDEOGRAPH + 0x83C1: 0x515E, //CJK UNIFIED IDEOGRAPH + 0x83C2: 0x515F, //CJK UNIFIED IDEOGRAPH + 0x83C3: 0x5160, //CJK UNIFIED IDEOGRAPH + 0x83C4: 0x5161, //CJK UNIFIED IDEOGRAPH + 0x83C5: 0x5163, //CJK UNIFIED IDEOGRAPH + 0x83C6: 0x5164, //CJK UNIFIED IDEOGRAPH + 0x83C7: 0x5166, //CJK UNIFIED IDEOGRAPH + 0x83C8: 0x5167, //CJK UNIFIED IDEOGRAPH + 0x83C9: 0x5169, //CJK UNIFIED IDEOGRAPH + 0x83CA: 0x516A, //CJK UNIFIED IDEOGRAPH + 0x83CB: 0x516F, //CJK UNIFIED IDEOGRAPH + 0x83CC: 0x5172, //CJK UNIFIED IDEOGRAPH + 0x83CD: 0x517A, //CJK UNIFIED IDEOGRAPH + 0x83CE: 0x517E, //CJK UNIFIED IDEOGRAPH + 0x83CF: 0x517F, //CJK UNIFIED IDEOGRAPH + 0x83D0: 0x5183, //CJK UNIFIED IDEOGRAPH + 0x83D1: 0x5184, //CJK UNIFIED IDEOGRAPH + 0x83D2: 0x5186, //CJK UNIFIED IDEOGRAPH + 0x83D3: 0x5187, //CJK UNIFIED IDEOGRAPH + 0x83D4: 0x518A, //CJK UNIFIED IDEOGRAPH + 0x83D5: 0x518B, //CJK UNIFIED IDEOGRAPH + 0x83D6: 0x518E, //CJK UNIFIED IDEOGRAPH + 0x83D7: 0x518F, //CJK UNIFIED IDEOGRAPH + 0x83D8: 0x5190, //CJK UNIFIED IDEOGRAPH + 0x83D9: 0x5191, //CJK UNIFIED IDEOGRAPH + 0x83DA: 0x5193, //CJK UNIFIED IDEOGRAPH + 0x83DB: 0x5194, //CJK UNIFIED IDEOGRAPH + 0x83DC: 0x5198, //CJK UNIFIED IDEOGRAPH + 0x83DD: 0x519A, //CJK UNIFIED IDEOGRAPH + 0x83DE: 0x519D, //CJK UNIFIED IDEOGRAPH + 0x83DF: 0x519E, //CJK UNIFIED IDEOGRAPH + 0x83E0: 0x519F, //CJK UNIFIED IDEOGRAPH + 0x83E1: 0x51A1, //CJK UNIFIED IDEOGRAPH + 0x83E2: 0x51A3, //CJK UNIFIED IDEOGRAPH + 0x83E3: 0x51A6, //CJK UNIFIED IDEOGRAPH + 0x83E4: 0x51A7, //CJK UNIFIED IDEOGRAPH + 0x83E5: 0x51A8, //CJK UNIFIED IDEOGRAPH + 0x83E6: 0x51A9, //CJK UNIFIED IDEOGRAPH + 0x83E7: 0x51AA, //CJK UNIFIED IDEOGRAPH + 0x83E8: 0x51AD, //CJK UNIFIED IDEOGRAPH + 0x83E9: 0x51AE, //CJK UNIFIED IDEOGRAPH + 0x83EA: 0x51B4, //CJK UNIFIED IDEOGRAPH + 0x83EB: 0x51B8, //CJK UNIFIED IDEOGRAPH + 0x83EC: 0x51B9, //CJK UNIFIED IDEOGRAPH + 0x83ED: 0x51BA, //CJK UNIFIED IDEOGRAPH + 0x83EE: 0x51BE, //CJK UNIFIED IDEOGRAPH + 0x83EF: 0x51BF, //CJK UNIFIED IDEOGRAPH + 0x83F0: 0x51C1, //CJK UNIFIED IDEOGRAPH + 0x83F1: 0x51C2, //CJK UNIFIED IDEOGRAPH + 0x83F2: 0x51C3, //CJK UNIFIED IDEOGRAPH + 0x83F3: 0x51C5, //CJK UNIFIED IDEOGRAPH + 0x83F4: 0x51C8, //CJK UNIFIED IDEOGRAPH + 0x83F5: 0x51CA, //CJK UNIFIED IDEOGRAPH + 0x83F6: 0x51CD, //CJK UNIFIED IDEOGRAPH + 0x83F7: 0x51CE, //CJK UNIFIED IDEOGRAPH + 0x83F8: 0x51D0, //CJK UNIFIED IDEOGRAPH + 0x83F9: 0x51D2, //CJK UNIFIED IDEOGRAPH + 0x83FA: 0x51D3, //CJK UNIFIED IDEOGRAPH + 0x83FB: 0x51D4, //CJK UNIFIED IDEOGRAPH + 0x83FC: 0x51D5, //CJK UNIFIED IDEOGRAPH + 0x83FD: 0x51D6, //CJK UNIFIED IDEOGRAPH + 0x83FE: 0x51D7, //CJK UNIFIED IDEOGRAPH + 0x8440: 0x51D8, //CJK UNIFIED IDEOGRAPH + 0x8441: 0x51D9, //CJK UNIFIED IDEOGRAPH + 0x8442: 0x51DA, //CJK UNIFIED IDEOGRAPH + 0x8443: 0x51DC, //CJK UNIFIED IDEOGRAPH + 0x8444: 0x51DE, //CJK UNIFIED IDEOGRAPH + 0x8445: 0x51DF, //CJK UNIFIED IDEOGRAPH + 0x8446: 0x51E2, //CJK UNIFIED IDEOGRAPH + 0x8447: 0x51E3, //CJK UNIFIED IDEOGRAPH + 0x8448: 0x51E5, //CJK UNIFIED IDEOGRAPH + 0x8449: 0x51E6, //CJK UNIFIED IDEOGRAPH + 0x844A: 0x51E7, //CJK UNIFIED IDEOGRAPH + 0x844B: 0x51E8, //CJK UNIFIED IDEOGRAPH + 0x844C: 0x51E9, //CJK UNIFIED IDEOGRAPH + 0x844D: 0x51EA, //CJK UNIFIED IDEOGRAPH + 0x844E: 0x51EC, //CJK UNIFIED IDEOGRAPH + 0x844F: 0x51EE, //CJK UNIFIED IDEOGRAPH + 0x8450: 0x51F1, //CJK UNIFIED IDEOGRAPH + 0x8451: 0x51F2, //CJK UNIFIED IDEOGRAPH + 0x8452: 0x51F4, //CJK UNIFIED IDEOGRAPH + 0x8453: 0x51F7, //CJK UNIFIED IDEOGRAPH + 0x8454: 0x51FE, //CJK UNIFIED IDEOGRAPH + 0x8455: 0x5204, //CJK UNIFIED IDEOGRAPH + 0x8456: 0x5205, //CJK UNIFIED IDEOGRAPH + 0x8457: 0x5209, //CJK UNIFIED IDEOGRAPH + 0x8458: 0x520B, //CJK UNIFIED IDEOGRAPH + 0x8459: 0x520C, //CJK UNIFIED IDEOGRAPH + 0x845A: 0x520F, //CJK UNIFIED IDEOGRAPH + 0x845B: 0x5210, //CJK UNIFIED IDEOGRAPH + 0x845C: 0x5213, //CJK UNIFIED IDEOGRAPH + 0x845D: 0x5214, //CJK UNIFIED IDEOGRAPH + 0x845E: 0x5215, //CJK UNIFIED IDEOGRAPH + 0x845F: 0x521C, //CJK UNIFIED IDEOGRAPH + 0x8460: 0x521E, //CJK UNIFIED IDEOGRAPH + 0x8461: 0x521F, //CJK UNIFIED IDEOGRAPH + 0x8462: 0x5221, //CJK UNIFIED IDEOGRAPH + 0x8463: 0x5222, //CJK UNIFIED IDEOGRAPH + 0x8464: 0x5223, //CJK UNIFIED IDEOGRAPH + 0x8465: 0x5225, //CJK UNIFIED IDEOGRAPH + 0x8466: 0x5226, //CJK UNIFIED IDEOGRAPH + 0x8467: 0x5227, //CJK UNIFIED IDEOGRAPH + 0x8468: 0x522A, //CJK UNIFIED IDEOGRAPH + 0x8469: 0x522C, //CJK UNIFIED IDEOGRAPH + 0x846A: 0x522F, //CJK UNIFIED IDEOGRAPH + 0x846B: 0x5231, //CJK UNIFIED IDEOGRAPH + 0x846C: 0x5232, //CJK UNIFIED IDEOGRAPH + 0x846D: 0x5234, //CJK UNIFIED IDEOGRAPH + 0x846E: 0x5235, //CJK UNIFIED IDEOGRAPH + 0x846F: 0x523C, //CJK UNIFIED IDEOGRAPH + 0x8470: 0x523E, //CJK UNIFIED IDEOGRAPH + 0x8471: 0x5244, //CJK UNIFIED IDEOGRAPH + 0x8472: 0x5245, //CJK UNIFIED IDEOGRAPH + 0x8473: 0x5246, //CJK UNIFIED IDEOGRAPH + 0x8474: 0x5247, //CJK UNIFIED IDEOGRAPH + 0x8475: 0x5248, //CJK UNIFIED IDEOGRAPH + 0x8476: 0x5249, //CJK UNIFIED IDEOGRAPH + 0x8477: 0x524B, //CJK UNIFIED IDEOGRAPH + 0x8478: 0x524E, //CJK UNIFIED IDEOGRAPH + 0x8479: 0x524F, //CJK UNIFIED IDEOGRAPH + 0x847A: 0x5252, //CJK UNIFIED IDEOGRAPH + 0x847B: 0x5253, //CJK UNIFIED IDEOGRAPH + 0x847C: 0x5255, //CJK UNIFIED IDEOGRAPH + 0x847D: 0x5257, //CJK UNIFIED IDEOGRAPH + 0x847E: 0x5258, //CJK UNIFIED IDEOGRAPH + 0x8480: 0x5259, //CJK UNIFIED IDEOGRAPH + 0x8481: 0x525A, //CJK UNIFIED IDEOGRAPH + 0x8482: 0x525B, //CJK UNIFIED IDEOGRAPH + 0x8483: 0x525D, //CJK UNIFIED IDEOGRAPH + 0x8484: 0x525F, //CJK UNIFIED IDEOGRAPH + 0x8485: 0x5260, //CJK UNIFIED IDEOGRAPH + 0x8486: 0x5262, //CJK UNIFIED IDEOGRAPH + 0x8487: 0x5263, //CJK UNIFIED IDEOGRAPH + 0x8488: 0x5264, //CJK UNIFIED IDEOGRAPH + 0x8489: 0x5266, //CJK UNIFIED IDEOGRAPH + 0x848A: 0x5268, //CJK UNIFIED IDEOGRAPH + 0x848B: 0x526B, //CJK UNIFIED IDEOGRAPH + 0x848C: 0x526C, //CJK UNIFIED IDEOGRAPH + 0x848D: 0x526D, //CJK UNIFIED IDEOGRAPH + 0x848E: 0x526E, //CJK UNIFIED IDEOGRAPH + 0x848F: 0x5270, //CJK UNIFIED IDEOGRAPH + 0x8490: 0x5271, //CJK UNIFIED IDEOGRAPH + 0x8491: 0x5273, //CJK UNIFIED IDEOGRAPH + 0x8492: 0x5274, //CJK UNIFIED IDEOGRAPH + 0x8493: 0x5275, //CJK UNIFIED IDEOGRAPH + 0x8494: 0x5276, //CJK UNIFIED IDEOGRAPH + 0x8495: 0x5277, //CJK UNIFIED IDEOGRAPH + 0x8496: 0x5278, //CJK UNIFIED IDEOGRAPH + 0x8497: 0x5279, //CJK UNIFIED IDEOGRAPH + 0x8498: 0x527A, //CJK UNIFIED IDEOGRAPH + 0x8499: 0x527B, //CJK UNIFIED IDEOGRAPH + 0x849A: 0x527C, //CJK UNIFIED IDEOGRAPH + 0x849B: 0x527E, //CJK UNIFIED IDEOGRAPH + 0x849C: 0x5280, //CJK UNIFIED IDEOGRAPH + 0x849D: 0x5283, //CJK UNIFIED IDEOGRAPH + 0x849E: 0x5284, //CJK UNIFIED IDEOGRAPH + 0x849F: 0x5285, //CJK UNIFIED IDEOGRAPH + 0x84A0: 0x5286, //CJK UNIFIED IDEOGRAPH + 0x84A1: 0x5287, //CJK UNIFIED IDEOGRAPH + 0x84A2: 0x5289, //CJK UNIFIED IDEOGRAPH + 0x84A3: 0x528A, //CJK UNIFIED IDEOGRAPH + 0x84A4: 0x528B, //CJK UNIFIED IDEOGRAPH + 0x84A5: 0x528C, //CJK UNIFIED IDEOGRAPH + 0x84A6: 0x528D, //CJK UNIFIED IDEOGRAPH + 0x84A7: 0x528E, //CJK UNIFIED IDEOGRAPH + 0x84A8: 0x528F, //CJK UNIFIED IDEOGRAPH + 0x84A9: 0x5291, //CJK UNIFIED IDEOGRAPH + 0x84AA: 0x5292, //CJK UNIFIED IDEOGRAPH + 0x84AB: 0x5294, //CJK UNIFIED IDEOGRAPH + 0x84AC: 0x5295, //CJK UNIFIED IDEOGRAPH + 0x84AD: 0x5296, //CJK UNIFIED IDEOGRAPH + 0x84AE: 0x5297, //CJK UNIFIED IDEOGRAPH + 0x84AF: 0x5298, //CJK UNIFIED IDEOGRAPH + 0x84B0: 0x5299, //CJK UNIFIED IDEOGRAPH + 0x84B1: 0x529A, //CJK UNIFIED IDEOGRAPH + 0x84B2: 0x529C, //CJK UNIFIED IDEOGRAPH + 0x84B3: 0x52A4, //CJK UNIFIED IDEOGRAPH + 0x84B4: 0x52A5, //CJK UNIFIED IDEOGRAPH + 0x84B5: 0x52A6, //CJK UNIFIED IDEOGRAPH + 0x84B6: 0x52A7, //CJK UNIFIED IDEOGRAPH + 0x84B7: 0x52AE, //CJK UNIFIED IDEOGRAPH + 0x84B8: 0x52AF, //CJK UNIFIED IDEOGRAPH + 0x84B9: 0x52B0, //CJK UNIFIED IDEOGRAPH + 0x84BA: 0x52B4, //CJK UNIFIED IDEOGRAPH + 0x84BB: 0x52B5, //CJK UNIFIED IDEOGRAPH + 0x84BC: 0x52B6, //CJK UNIFIED IDEOGRAPH + 0x84BD: 0x52B7, //CJK UNIFIED IDEOGRAPH + 0x84BE: 0x52B8, //CJK UNIFIED IDEOGRAPH + 0x84BF: 0x52B9, //CJK UNIFIED IDEOGRAPH + 0x84C0: 0x52BA, //CJK UNIFIED IDEOGRAPH + 0x84C1: 0x52BB, //CJK UNIFIED IDEOGRAPH + 0x84C2: 0x52BC, //CJK UNIFIED IDEOGRAPH + 0x84C3: 0x52BD, //CJK UNIFIED IDEOGRAPH + 0x84C4: 0x52C0, //CJK UNIFIED IDEOGRAPH + 0x84C5: 0x52C1, //CJK UNIFIED IDEOGRAPH + 0x84C6: 0x52C2, //CJK UNIFIED IDEOGRAPH + 0x84C7: 0x52C4, //CJK UNIFIED IDEOGRAPH + 0x84C8: 0x52C5, //CJK UNIFIED IDEOGRAPH + 0x84C9: 0x52C6, //CJK UNIFIED IDEOGRAPH + 0x84CA: 0x52C8, //CJK UNIFIED IDEOGRAPH + 0x84CB: 0x52CA, //CJK UNIFIED IDEOGRAPH + 0x84CC: 0x52CC, //CJK UNIFIED IDEOGRAPH + 0x84CD: 0x52CD, //CJK UNIFIED IDEOGRAPH + 0x84CE: 0x52CE, //CJK UNIFIED IDEOGRAPH + 0x84CF: 0x52CF, //CJK UNIFIED IDEOGRAPH + 0x84D0: 0x52D1, //CJK UNIFIED IDEOGRAPH + 0x84D1: 0x52D3, //CJK UNIFIED IDEOGRAPH + 0x84D2: 0x52D4, //CJK UNIFIED IDEOGRAPH + 0x84D3: 0x52D5, //CJK UNIFIED IDEOGRAPH + 0x84D4: 0x52D7, //CJK UNIFIED IDEOGRAPH + 0x84D5: 0x52D9, //CJK UNIFIED IDEOGRAPH + 0x84D6: 0x52DA, //CJK UNIFIED IDEOGRAPH + 0x84D7: 0x52DB, //CJK UNIFIED IDEOGRAPH + 0x84D8: 0x52DC, //CJK UNIFIED IDEOGRAPH + 0x84D9: 0x52DD, //CJK UNIFIED IDEOGRAPH + 0x84DA: 0x52DE, //CJK UNIFIED IDEOGRAPH + 0x84DB: 0x52E0, //CJK UNIFIED IDEOGRAPH + 0x84DC: 0x52E1, //CJK UNIFIED IDEOGRAPH + 0x84DD: 0x52E2, //CJK UNIFIED IDEOGRAPH + 0x84DE: 0x52E3, //CJK UNIFIED IDEOGRAPH + 0x84DF: 0x52E5, //CJK UNIFIED IDEOGRAPH + 0x84E0: 0x52E6, //CJK UNIFIED IDEOGRAPH + 0x84E1: 0x52E7, //CJK UNIFIED IDEOGRAPH + 0x84E2: 0x52E8, //CJK UNIFIED IDEOGRAPH + 0x84E3: 0x52E9, //CJK UNIFIED IDEOGRAPH + 0x84E4: 0x52EA, //CJK UNIFIED IDEOGRAPH + 0x84E5: 0x52EB, //CJK UNIFIED IDEOGRAPH + 0x84E6: 0x52EC, //CJK UNIFIED IDEOGRAPH + 0x84E7: 0x52ED, //CJK UNIFIED IDEOGRAPH + 0x84E8: 0x52EE, //CJK UNIFIED IDEOGRAPH + 0x84E9: 0x52EF, //CJK UNIFIED IDEOGRAPH + 0x84EA: 0x52F1, //CJK UNIFIED IDEOGRAPH + 0x84EB: 0x52F2, //CJK UNIFIED IDEOGRAPH + 0x84EC: 0x52F3, //CJK UNIFIED IDEOGRAPH + 0x84ED: 0x52F4, //CJK UNIFIED IDEOGRAPH + 0x84EE: 0x52F5, //CJK UNIFIED IDEOGRAPH + 0x84EF: 0x52F6, //CJK UNIFIED IDEOGRAPH + 0x84F0: 0x52F7, //CJK UNIFIED IDEOGRAPH + 0x84F1: 0x52F8, //CJK UNIFIED IDEOGRAPH + 0x84F2: 0x52FB, //CJK UNIFIED IDEOGRAPH + 0x84F3: 0x52FC, //CJK UNIFIED IDEOGRAPH + 0x84F4: 0x52FD, //CJK UNIFIED IDEOGRAPH + 0x84F5: 0x5301, //CJK UNIFIED IDEOGRAPH + 0x84F6: 0x5302, //CJK UNIFIED IDEOGRAPH + 0x84F7: 0x5303, //CJK UNIFIED IDEOGRAPH + 0x84F8: 0x5304, //CJK UNIFIED IDEOGRAPH + 0x84F9: 0x5307, //CJK UNIFIED IDEOGRAPH + 0x84FA: 0x5309, //CJK UNIFIED IDEOGRAPH + 0x84FB: 0x530A, //CJK UNIFIED IDEOGRAPH + 0x84FC: 0x530B, //CJK UNIFIED IDEOGRAPH + 0x84FD: 0x530C, //CJK UNIFIED IDEOGRAPH + 0x84FE: 0x530E, //CJK UNIFIED IDEOGRAPH + 0x8540: 0x5311, //CJK UNIFIED IDEOGRAPH + 0x8541: 0x5312, //CJK UNIFIED IDEOGRAPH + 0x8542: 0x5313, //CJK UNIFIED IDEOGRAPH + 0x8543: 0x5314, //CJK UNIFIED IDEOGRAPH + 0x8544: 0x5318, //CJK UNIFIED IDEOGRAPH + 0x8545: 0x531B, //CJK UNIFIED IDEOGRAPH + 0x8546: 0x531C, //CJK UNIFIED IDEOGRAPH + 0x8547: 0x531E, //CJK UNIFIED IDEOGRAPH + 0x8548: 0x531F, //CJK UNIFIED IDEOGRAPH + 0x8549: 0x5322, //CJK UNIFIED IDEOGRAPH + 0x854A: 0x5324, //CJK UNIFIED IDEOGRAPH + 0x854B: 0x5325, //CJK UNIFIED IDEOGRAPH + 0x854C: 0x5327, //CJK UNIFIED IDEOGRAPH + 0x854D: 0x5328, //CJK UNIFIED IDEOGRAPH + 0x854E: 0x5329, //CJK UNIFIED IDEOGRAPH + 0x854F: 0x532B, //CJK UNIFIED IDEOGRAPH + 0x8550: 0x532C, //CJK UNIFIED IDEOGRAPH + 0x8551: 0x532D, //CJK UNIFIED IDEOGRAPH + 0x8552: 0x532F, //CJK UNIFIED IDEOGRAPH + 0x8553: 0x5330, //CJK UNIFIED IDEOGRAPH + 0x8554: 0x5331, //CJK UNIFIED IDEOGRAPH + 0x8555: 0x5332, //CJK UNIFIED IDEOGRAPH + 0x8556: 0x5333, //CJK UNIFIED IDEOGRAPH + 0x8557: 0x5334, //CJK UNIFIED IDEOGRAPH + 0x8558: 0x5335, //CJK UNIFIED IDEOGRAPH + 0x8559: 0x5336, //CJK UNIFIED IDEOGRAPH + 0x855A: 0x5337, //CJK UNIFIED IDEOGRAPH + 0x855B: 0x5338, //CJK UNIFIED IDEOGRAPH + 0x855C: 0x533C, //CJK UNIFIED IDEOGRAPH + 0x855D: 0x533D, //CJK UNIFIED IDEOGRAPH + 0x855E: 0x5340, //CJK UNIFIED IDEOGRAPH + 0x855F: 0x5342, //CJK UNIFIED IDEOGRAPH + 0x8560: 0x5344, //CJK UNIFIED IDEOGRAPH + 0x8561: 0x5346, //CJK UNIFIED IDEOGRAPH + 0x8562: 0x534B, //CJK UNIFIED IDEOGRAPH + 0x8563: 0x534C, //CJK UNIFIED IDEOGRAPH + 0x8564: 0x534D, //CJK UNIFIED IDEOGRAPH + 0x8565: 0x5350, //CJK UNIFIED IDEOGRAPH + 0x8566: 0x5354, //CJK UNIFIED IDEOGRAPH + 0x8567: 0x5358, //CJK UNIFIED IDEOGRAPH + 0x8568: 0x5359, //CJK UNIFIED IDEOGRAPH + 0x8569: 0x535B, //CJK UNIFIED IDEOGRAPH + 0x856A: 0x535D, //CJK UNIFIED IDEOGRAPH + 0x856B: 0x5365, //CJK UNIFIED IDEOGRAPH + 0x856C: 0x5368, //CJK UNIFIED IDEOGRAPH + 0x856D: 0x536A, //CJK UNIFIED IDEOGRAPH + 0x856E: 0x536C, //CJK UNIFIED IDEOGRAPH + 0x856F: 0x536D, //CJK UNIFIED IDEOGRAPH + 0x8570: 0x5372, //CJK UNIFIED IDEOGRAPH + 0x8571: 0x5376, //CJK UNIFIED IDEOGRAPH + 0x8572: 0x5379, //CJK UNIFIED IDEOGRAPH + 0x8573: 0x537B, //CJK UNIFIED IDEOGRAPH + 0x8574: 0x537C, //CJK UNIFIED IDEOGRAPH + 0x8575: 0x537D, //CJK UNIFIED IDEOGRAPH + 0x8576: 0x537E, //CJK UNIFIED IDEOGRAPH + 0x8577: 0x5380, //CJK UNIFIED IDEOGRAPH + 0x8578: 0x5381, //CJK UNIFIED IDEOGRAPH + 0x8579: 0x5383, //CJK UNIFIED IDEOGRAPH + 0x857A: 0x5387, //CJK UNIFIED IDEOGRAPH + 0x857B: 0x5388, //CJK UNIFIED IDEOGRAPH + 0x857C: 0x538A, //CJK UNIFIED IDEOGRAPH + 0x857D: 0x538E, //CJK UNIFIED IDEOGRAPH + 0x857E: 0x538F, //CJK UNIFIED IDEOGRAPH + 0x8580: 0x5390, //CJK UNIFIED IDEOGRAPH + 0x8581: 0x5391, //CJK UNIFIED IDEOGRAPH + 0x8582: 0x5392, //CJK UNIFIED IDEOGRAPH + 0x8583: 0x5393, //CJK UNIFIED IDEOGRAPH + 0x8584: 0x5394, //CJK UNIFIED IDEOGRAPH + 0x8585: 0x5396, //CJK UNIFIED IDEOGRAPH + 0x8586: 0x5397, //CJK UNIFIED IDEOGRAPH + 0x8587: 0x5399, //CJK UNIFIED IDEOGRAPH + 0x8588: 0x539B, //CJK UNIFIED IDEOGRAPH + 0x8589: 0x539C, //CJK UNIFIED IDEOGRAPH + 0x858A: 0x539E, //CJK UNIFIED IDEOGRAPH + 0x858B: 0x53A0, //CJK UNIFIED IDEOGRAPH + 0x858C: 0x53A1, //CJK UNIFIED IDEOGRAPH + 0x858D: 0x53A4, //CJK UNIFIED IDEOGRAPH + 0x858E: 0x53A7, //CJK UNIFIED IDEOGRAPH + 0x858F: 0x53AA, //CJK UNIFIED IDEOGRAPH + 0x8590: 0x53AB, //CJK UNIFIED IDEOGRAPH + 0x8591: 0x53AC, //CJK UNIFIED IDEOGRAPH + 0x8592: 0x53AD, //CJK UNIFIED IDEOGRAPH + 0x8593: 0x53AF, //CJK UNIFIED IDEOGRAPH + 0x8594: 0x53B0, //CJK UNIFIED IDEOGRAPH + 0x8595: 0x53B1, //CJK UNIFIED IDEOGRAPH + 0x8596: 0x53B2, //CJK UNIFIED IDEOGRAPH + 0x8597: 0x53B3, //CJK UNIFIED IDEOGRAPH + 0x8598: 0x53B4, //CJK UNIFIED IDEOGRAPH + 0x8599: 0x53B5, //CJK UNIFIED IDEOGRAPH + 0x859A: 0x53B7, //CJK UNIFIED IDEOGRAPH + 0x859B: 0x53B8, //CJK UNIFIED IDEOGRAPH + 0x859C: 0x53B9, //CJK UNIFIED IDEOGRAPH + 0x859D: 0x53BA, //CJK UNIFIED IDEOGRAPH + 0x859E: 0x53BC, //CJK UNIFIED IDEOGRAPH + 0x859F: 0x53BD, //CJK UNIFIED IDEOGRAPH + 0x85A0: 0x53BE, //CJK UNIFIED IDEOGRAPH + 0x85A1: 0x53C0, //CJK UNIFIED IDEOGRAPH + 0x85A2: 0x53C3, //CJK UNIFIED IDEOGRAPH + 0x85A3: 0x53C4, //CJK UNIFIED IDEOGRAPH + 0x85A4: 0x53C5, //CJK UNIFIED IDEOGRAPH + 0x85A5: 0x53C6, //CJK UNIFIED IDEOGRAPH + 0x85A6: 0x53C7, //CJK UNIFIED IDEOGRAPH + 0x85A7: 0x53CE, //CJK UNIFIED IDEOGRAPH + 0x85A8: 0x53CF, //CJK UNIFIED IDEOGRAPH + 0x85A9: 0x53D0, //CJK UNIFIED IDEOGRAPH + 0x85AA: 0x53D2, //CJK UNIFIED IDEOGRAPH + 0x85AB: 0x53D3, //CJK UNIFIED IDEOGRAPH + 0x85AC: 0x53D5, //CJK UNIFIED IDEOGRAPH + 0x85AD: 0x53DA, //CJK UNIFIED IDEOGRAPH + 0x85AE: 0x53DC, //CJK UNIFIED IDEOGRAPH + 0x85AF: 0x53DD, //CJK UNIFIED IDEOGRAPH + 0x85B0: 0x53DE, //CJK UNIFIED IDEOGRAPH + 0x85B1: 0x53E1, //CJK UNIFIED IDEOGRAPH + 0x85B2: 0x53E2, //CJK UNIFIED IDEOGRAPH + 0x85B3: 0x53E7, //CJK UNIFIED IDEOGRAPH + 0x85B4: 0x53F4, //CJK UNIFIED IDEOGRAPH + 0x85B5: 0x53FA, //CJK UNIFIED IDEOGRAPH + 0x85B6: 0x53FE, //CJK UNIFIED IDEOGRAPH + 0x85B7: 0x53FF, //CJK UNIFIED IDEOGRAPH + 0x85B8: 0x5400, //CJK UNIFIED IDEOGRAPH + 0x85B9: 0x5402, //CJK UNIFIED IDEOGRAPH + 0x85BA: 0x5405, //CJK UNIFIED IDEOGRAPH + 0x85BB: 0x5407, //CJK UNIFIED IDEOGRAPH + 0x85BC: 0x540B, //CJK UNIFIED IDEOGRAPH + 0x85BD: 0x5414, //CJK UNIFIED IDEOGRAPH + 0x85BE: 0x5418, //CJK UNIFIED IDEOGRAPH + 0x85BF: 0x5419, //CJK UNIFIED IDEOGRAPH + 0x85C0: 0x541A, //CJK UNIFIED IDEOGRAPH + 0x85C1: 0x541C, //CJK UNIFIED IDEOGRAPH + 0x85C2: 0x5422, //CJK UNIFIED IDEOGRAPH + 0x85C3: 0x5424, //CJK UNIFIED IDEOGRAPH + 0x85C4: 0x5425, //CJK UNIFIED IDEOGRAPH + 0x85C5: 0x542A, //CJK UNIFIED IDEOGRAPH + 0x85C6: 0x5430, //CJK UNIFIED IDEOGRAPH + 0x85C7: 0x5433, //CJK UNIFIED IDEOGRAPH + 0x85C8: 0x5436, //CJK UNIFIED IDEOGRAPH + 0x85C9: 0x5437, //CJK UNIFIED IDEOGRAPH + 0x85CA: 0x543A, //CJK UNIFIED IDEOGRAPH + 0x85CB: 0x543D, //CJK UNIFIED IDEOGRAPH + 0x85CC: 0x543F, //CJK UNIFIED IDEOGRAPH + 0x85CD: 0x5441, //CJK UNIFIED IDEOGRAPH + 0x85CE: 0x5442, //CJK UNIFIED IDEOGRAPH + 0x85CF: 0x5444, //CJK UNIFIED IDEOGRAPH + 0x85D0: 0x5445, //CJK UNIFIED IDEOGRAPH + 0x85D1: 0x5447, //CJK UNIFIED IDEOGRAPH + 0x85D2: 0x5449, //CJK UNIFIED IDEOGRAPH + 0x85D3: 0x544C, //CJK UNIFIED IDEOGRAPH + 0x85D4: 0x544D, //CJK UNIFIED IDEOGRAPH + 0x85D5: 0x544E, //CJK UNIFIED IDEOGRAPH + 0x85D6: 0x544F, //CJK UNIFIED IDEOGRAPH + 0x85D7: 0x5451, //CJK UNIFIED IDEOGRAPH + 0x85D8: 0x545A, //CJK UNIFIED IDEOGRAPH + 0x85D9: 0x545D, //CJK UNIFIED IDEOGRAPH + 0x85DA: 0x545E, //CJK UNIFIED IDEOGRAPH + 0x85DB: 0x545F, //CJK UNIFIED IDEOGRAPH + 0x85DC: 0x5460, //CJK UNIFIED IDEOGRAPH + 0x85DD: 0x5461, //CJK UNIFIED IDEOGRAPH + 0x85DE: 0x5463, //CJK UNIFIED IDEOGRAPH + 0x85DF: 0x5465, //CJK UNIFIED IDEOGRAPH + 0x85E0: 0x5467, //CJK UNIFIED IDEOGRAPH + 0x85E1: 0x5469, //CJK UNIFIED IDEOGRAPH + 0x85E2: 0x546A, //CJK UNIFIED IDEOGRAPH + 0x85E3: 0x546B, //CJK UNIFIED IDEOGRAPH + 0x85E4: 0x546C, //CJK UNIFIED IDEOGRAPH + 0x85E5: 0x546D, //CJK UNIFIED IDEOGRAPH + 0x85E6: 0x546E, //CJK UNIFIED IDEOGRAPH + 0x85E7: 0x546F, //CJK UNIFIED IDEOGRAPH + 0x85E8: 0x5470, //CJK UNIFIED IDEOGRAPH + 0x85E9: 0x5474, //CJK UNIFIED IDEOGRAPH + 0x85EA: 0x5479, //CJK UNIFIED IDEOGRAPH + 0x85EB: 0x547A, //CJK UNIFIED IDEOGRAPH + 0x85EC: 0x547E, //CJK UNIFIED IDEOGRAPH + 0x85ED: 0x547F, //CJK UNIFIED IDEOGRAPH + 0x85EE: 0x5481, //CJK UNIFIED IDEOGRAPH + 0x85EF: 0x5483, //CJK UNIFIED IDEOGRAPH + 0x85F0: 0x5485, //CJK UNIFIED IDEOGRAPH + 0x85F1: 0x5487, //CJK UNIFIED IDEOGRAPH + 0x85F2: 0x5488, //CJK UNIFIED IDEOGRAPH + 0x85F3: 0x5489, //CJK UNIFIED IDEOGRAPH + 0x85F4: 0x548A, //CJK UNIFIED IDEOGRAPH + 0x85F5: 0x548D, //CJK UNIFIED IDEOGRAPH + 0x85F6: 0x5491, //CJK UNIFIED IDEOGRAPH + 0x85F7: 0x5493, //CJK UNIFIED IDEOGRAPH + 0x85F8: 0x5497, //CJK UNIFIED IDEOGRAPH + 0x85F9: 0x5498, //CJK UNIFIED IDEOGRAPH + 0x85FA: 0x549C, //CJK UNIFIED IDEOGRAPH + 0x85FB: 0x549E, //CJK UNIFIED IDEOGRAPH + 0x85FC: 0x549F, //CJK UNIFIED IDEOGRAPH + 0x85FD: 0x54A0, //CJK UNIFIED IDEOGRAPH + 0x85FE: 0x54A1, //CJK UNIFIED IDEOGRAPH + 0x8640: 0x54A2, //CJK UNIFIED IDEOGRAPH + 0x8641: 0x54A5, //CJK UNIFIED IDEOGRAPH + 0x8642: 0x54AE, //CJK UNIFIED IDEOGRAPH + 0x8643: 0x54B0, //CJK UNIFIED IDEOGRAPH + 0x8644: 0x54B2, //CJK UNIFIED IDEOGRAPH + 0x8645: 0x54B5, //CJK UNIFIED IDEOGRAPH + 0x8646: 0x54B6, //CJK UNIFIED IDEOGRAPH + 0x8647: 0x54B7, //CJK UNIFIED IDEOGRAPH + 0x8648: 0x54B9, //CJK UNIFIED IDEOGRAPH + 0x8649: 0x54BA, //CJK UNIFIED IDEOGRAPH + 0x864A: 0x54BC, //CJK UNIFIED IDEOGRAPH + 0x864B: 0x54BE, //CJK UNIFIED IDEOGRAPH + 0x864C: 0x54C3, //CJK UNIFIED IDEOGRAPH + 0x864D: 0x54C5, //CJK UNIFIED IDEOGRAPH + 0x864E: 0x54CA, //CJK UNIFIED IDEOGRAPH + 0x864F: 0x54CB, //CJK UNIFIED IDEOGRAPH + 0x8650: 0x54D6, //CJK UNIFIED IDEOGRAPH + 0x8651: 0x54D8, //CJK UNIFIED IDEOGRAPH + 0x8652: 0x54DB, //CJK UNIFIED IDEOGRAPH + 0x8653: 0x54E0, //CJK UNIFIED IDEOGRAPH + 0x8654: 0x54E1, //CJK UNIFIED IDEOGRAPH + 0x8655: 0x54E2, //CJK UNIFIED IDEOGRAPH + 0x8656: 0x54E3, //CJK UNIFIED IDEOGRAPH + 0x8657: 0x54E4, //CJK UNIFIED IDEOGRAPH + 0x8658: 0x54EB, //CJK UNIFIED IDEOGRAPH + 0x8659: 0x54EC, //CJK UNIFIED IDEOGRAPH + 0x865A: 0x54EF, //CJK UNIFIED IDEOGRAPH + 0x865B: 0x54F0, //CJK UNIFIED IDEOGRAPH + 0x865C: 0x54F1, //CJK UNIFIED IDEOGRAPH + 0x865D: 0x54F4, //CJK UNIFIED IDEOGRAPH + 0x865E: 0x54F5, //CJK UNIFIED IDEOGRAPH + 0x865F: 0x54F6, //CJK UNIFIED IDEOGRAPH + 0x8660: 0x54F7, //CJK UNIFIED IDEOGRAPH + 0x8661: 0x54F8, //CJK UNIFIED IDEOGRAPH + 0x8662: 0x54F9, //CJK UNIFIED IDEOGRAPH + 0x8663: 0x54FB, //CJK UNIFIED IDEOGRAPH + 0x8664: 0x54FE, //CJK UNIFIED IDEOGRAPH + 0x8665: 0x5500, //CJK UNIFIED IDEOGRAPH + 0x8666: 0x5502, //CJK UNIFIED IDEOGRAPH + 0x8667: 0x5503, //CJK UNIFIED IDEOGRAPH + 0x8668: 0x5504, //CJK UNIFIED IDEOGRAPH + 0x8669: 0x5505, //CJK UNIFIED IDEOGRAPH + 0x866A: 0x5508, //CJK UNIFIED IDEOGRAPH + 0x866B: 0x550A, //CJK UNIFIED IDEOGRAPH + 0x866C: 0x550B, //CJK UNIFIED IDEOGRAPH + 0x866D: 0x550C, //CJK UNIFIED IDEOGRAPH + 0x866E: 0x550D, //CJK UNIFIED IDEOGRAPH + 0x866F: 0x550E, //CJK UNIFIED IDEOGRAPH + 0x8670: 0x5512, //CJK UNIFIED IDEOGRAPH + 0x8671: 0x5513, //CJK UNIFIED IDEOGRAPH + 0x8672: 0x5515, //CJK UNIFIED IDEOGRAPH + 0x8673: 0x5516, //CJK UNIFIED IDEOGRAPH + 0x8674: 0x5517, //CJK UNIFIED IDEOGRAPH + 0x8675: 0x5518, //CJK UNIFIED IDEOGRAPH + 0x8676: 0x5519, //CJK UNIFIED IDEOGRAPH + 0x8677: 0x551A, //CJK UNIFIED IDEOGRAPH + 0x8678: 0x551C, //CJK UNIFIED IDEOGRAPH + 0x8679: 0x551D, //CJK UNIFIED IDEOGRAPH + 0x867A: 0x551E, //CJK UNIFIED IDEOGRAPH + 0x867B: 0x551F, //CJK UNIFIED IDEOGRAPH + 0x867C: 0x5521, //CJK UNIFIED IDEOGRAPH + 0x867D: 0x5525, //CJK UNIFIED IDEOGRAPH + 0x867E: 0x5526, //CJK UNIFIED IDEOGRAPH + 0x8680: 0x5528, //CJK UNIFIED IDEOGRAPH + 0x8681: 0x5529, //CJK UNIFIED IDEOGRAPH + 0x8682: 0x552B, //CJK UNIFIED IDEOGRAPH + 0x8683: 0x552D, //CJK UNIFIED IDEOGRAPH + 0x8684: 0x5532, //CJK UNIFIED IDEOGRAPH + 0x8685: 0x5534, //CJK UNIFIED IDEOGRAPH + 0x8686: 0x5535, //CJK UNIFIED IDEOGRAPH + 0x8687: 0x5536, //CJK UNIFIED IDEOGRAPH + 0x8688: 0x5538, //CJK UNIFIED IDEOGRAPH + 0x8689: 0x5539, //CJK UNIFIED IDEOGRAPH + 0x868A: 0x553A, //CJK UNIFIED IDEOGRAPH + 0x868B: 0x553B, //CJK UNIFIED IDEOGRAPH + 0x868C: 0x553D, //CJK UNIFIED IDEOGRAPH + 0x868D: 0x5540, //CJK UNIFIED IDEOGRAPH + 0x868E: 0x5542, //CJK UNIFIED IDEOGRAPH + 0x868F: 0x5545, //CJK UNIFIED IDEOGRAPH + 0x8690: 0x5547, //CJK UNIFIED IDEOGRAPH + 0x8691: 0x5548, //CJK UNIFIED IDEOGRAPH + 0x8692: 0x554B, //CJK UNIFIED IDEOGRAPH + 0x8693: 0x554C, //CJK UNIFIED IDEOGRAPH + 0x8694: 0x554D, //CJK UNIFIED IDEOGRAPH + 0x8695: 0x554E, //CJK UNIFIED IDEOGRAPH + 0x8696: 0x554F, //CJK UNIFIED IDEOGRAPH + 0x8697: 0x5551, //CJK UNIFIED IDEOGRAPH + 0x8698: 0x5552, //CJK UNIFIED IDEOGRAPH + 0x8699: 0x5553, //CJK UNIFIED IDEOGRAPH + 0x869A: 0x5554, //CJK UNIFIED IDEOGRAPH + 0x869B: 0x5557, //CJK UNIFIED IDEOGRAPH + 0x869C: 0x5558, //CJK UNIFIED IDEOGRAPH + 0x869D: 0x5559, //CJK UNIFIED IDEOGRAPH + 0x869E: 0x555A, //CJK UNIFIED IDEOGRAPH + 0x869F: 0x555B, //CJK UNIFIED IDEOGRAPH + 0x86A0: 0x555D, //CJK UNIFIED IDEOGRAPH + 0x86A1: 0x555E, //CJK UNIFIED IDEOGRAPH + 0x86A2: 0x555F, //CJK UNIFIED IDEOGRAPH + 0x86A3: 0x5560, //CJK UNIFIED IDEOGRAPH + 0x86A4: 0x5562, //CJK UNIFIED IDEOGRAPH + 0x86A5: 0x5563, //CJK UNIFIED IDEOGRAPH + 0x86A6: 0x5568, //CJK UNIFIED IDEOGRAPH + 0x86A7: 0x5569, //CJK UNIFIED IDEOGRAPH + 0x86A8: 0x556B, //CJK UNIFIED IDEOGRAPH + 0x86A9: 0x556F, //CJK UNIFIED IDEOGRAPH + 0x86AA: 0x5570, //CJK UNIFIED IDEOGRAPH + 0x86AB: 0x5571, //CJK UNIFIED IDEOGRAPH + 0x86AC: 0x5572, //CJK UNIFIED IDEOGRAPH + 0x86AD: 0x5573, //CJK UNIFIED IDEOGRAPH + 0x86AE: 0x5574, //CJK UNIFIED IDEOGRAPH + 0x86AF: 0x5579, //CJK UNIFIED IDEOGRAPH + 0x86B0: 0x557A, //CJK UNIFIED IDEOGRAPH + 0x86B1: 0x557D, //CJK UNIFIED IDEOGRAPH + 0x86B2: 0x557F, //CJK UNIFIED IDEOGRAPH + 0x86B3: 0x5585, //CJK UNIFIED IDEOGRAPH + 0x86B4: 0x5586, //CJK UNIFIED IDEOGRAPH + 0x86B5: 0x558C, //CJK UNIFIED IDEOGRAPH + 0x86B6: 0x558D, //CJK UNIFIED IDEOGRAPH + 0x86B7: 0x558E, //CJK UNIFIED IDEOGRAPH + 0x86B8: 0x5590, //CJK UNIFIED IDEOGRAPH + 0x86B9: 0x5592, //CJK UNIFIED IDEOGRAPH + 0x86BA: 0x5593, //CJK UNIFIED IDEOGRAPH + 0x86BB: 0x5595, //CJK UNIFIED IDEOGRAPH + 0x86BC: 0x5596, //CJK UNIFIED IDEOGRAPH + 0x86BD: 0x5597, //CJK UNIFIED IDEOGRAPH + 0x86BE: 0x559A, //CJK UNIFIED IDEOGRAPH + 0x86BF: 0x559B, //CJK UNIFIED IDEOGRAPH + 0x86C0: 0x559E, //CJK UNIFIED IDEOGRAPH + 0x86C1: 0x55A0, //CJK UNIFIED IDEOGRAPH + 0x86C2: 0x55A1, //CJK UNIFIED IDEOGRAPH + 0x86C3: 0x55A2, //CJK UNIFIED IDEOGRAPH + 0x86C4: 0x55A3, //CJK UNIFIED IDEOGRAPH + 0x86C5: 0x55A4, //CJK UNIFIED IDEOGRAPH + 0x86C6: 0x55A5, //CJK UNIFIED IDEOGRAPH + 0x86C7: 0x55A6, //CJK UNIFIED IDEOGRAPH + 0x86C8: 0x55A8, //CJK UNIFIED IDEOGRAPH + 0x86C9: 0x55A9, //CJK UNIFIED IDEOGRAPH + 0x86CA: 0x55AA, //CJK UNIFIED IDEOGRAPH + 0x86CB: 0x55AB, //CJK UNIFIED IDEOGRAPH + 0x86CC: 0x55AC, //CJK UNIFIED IDEOGRAPH + 0x86CD: 0x55AD, //CJK UNIFIED IDEOGRAPH + 0x86CE: 0x55AE, //CJK UNIFIED IDEOGRAPH + 0x86CF: 0x55AF, //CJK UNIFIED IDEOGRAPH + 0x86D0: 0x55B0, //CJK UNIFIED IDEOGRAPH + 0x86D1: 0x55B2, //CJK UNIFIED IDEOGRAPH + 0x86D2: 0x55B4, //CJK UNIFIED IDEOGRAPH + 0x86D3: 0x55B6, //CJK UNIFIED IDEOGRAPH + 0x86D4: 0x55B8, //CJK UNIFIED IDEOGRAPH + 0x86D5: 0x55BA, //CJK UNIFIED IDEOGRAPH + 0x86D6: 0x55BC, //CJK UNIFIED IDEOGRAPH + 0x86D7: 0x55BF, //CJK UNIFIED IDEOGRAPH + 0x86D8: 0x55C0, //CJK UNIFIED IDEOGRAPH + 0x86D9: 0x55C1, //CJK UNIFIED IDEOGRAPH + 0x86DA: 0x55C2, //CJK UNIFIED IDEOGRAPH + 0x86DB: 0x55C3, //CJK UNIFIED IDEOGRAPH + 0x86DC: 0x55C6, //CJK UNIFIED IDEOGRAPH + 0x86DD: 0x55C7, //CJK UNIFIED IDEOGRAPH + 0x86DE: 0x55C8, //CJK UNIFIED IDEOGRAPH + 0x86DF: 0x55CA, //CJK UNIFIED IDEOGRAPH + 0x86E0: 0x55CB, //CJK UNIFIED IDEOGRAPH + 0x86E1: 0x55CE, //CJK UNIFIED IDEOGRAPH + 0x86E2: 0x55CF, //CJK UNIFIED IDEOGRAPH + 0x86E3: 0x55D0, //CJK UNIFIED IDEOGRAPH + 0x86E4: 0x55D5, //CJK UNIFIED IDEOGRAPH + 0x86E5: 0x55D7, //CJK UNIFIED IDEOGRAPH + 0x86E6: 0x55D8, //CJK UNIFIED IDEOGRAPH + 0x86E7: 0x55D9, //CJK UNIFIED IDEOGRAPH + 0x86E8: 0x55DA, //CJK UNIFIED IDEOGRAPH + 0x86E9: 0x55DB, //CJK UNIFIED IDEOGRAPH + 0x86EA: 0x55DE, //CJK UNIFIED IDEOGRAPH + 0x86EB: 0x55E0, //CJK UNIFIED IDEOGRAPH + 0x86EC: 0x55E2, //CJK UNIFIED IDEOGRAPH + 0x86ED: 0x55E7, //CJK UNIFIED IDEOGRAPH + 0x86EE: 0x55E9, //CJK UNIFIED IDEOGRAPH + 0x86EF: 0x55ED, //CJK UNIFIED IDEOGRAPH + 0x86F0: 0x55EE, //CJK UNIFIED IDEOGRAPH + 0x86F1: 0x55F0, //CJK UNIFIED IDEOGRAPH + 0x86F2: 0x55F1, //CJK UNIFIED IDEOGRAPH + 0x86F3: 0x55F4, //CJK UNIFIED IDEOGRAPH + 0x86F4: 0x55F6, //CJK UNIFIED IDEOGRAPH + 0x86F5: 0x55F8, //CJK UNIFIED IDEOGRAPH + 0x86F6: 0x55F9, //CJK UNIFIED IDEOGRAPH + 0x86F7: 0x55FA, //CJK UNIFIED IDEOGRAPH + 0x86F8: 0x55FB, //CJK UNIFIED IDEOGRAPH + 0x86F9: 0x55FC, //CJK UNIFIED IDEOGRAPH + 0x86FA: 0x55FF, //CJK UNIFIED IDEOGRAPH + 0x86FB: 0x5602, //CJK UNIFIED IDEOGRAPH + 0x86FC: 0x5603, //CJK UNIFIED IDEOGRAPH + 0x86FD: 0x5604, //CJK UNIFIED IDEOGRAPH + 0x86FE: 0x5605, //CJK UNIFIED IDEOGRAPH + 0x8740: 0x5606, //CJK UNIFIED IDEOGRAPH + 0x8741: 0x5607, //CJK UNIFIED IDEOGRAPH + 0x8742: 0x560A, //CJK UNIFIED IDEOGRAPH + 0x8743: 0x560B, //CJK UNIFIED IDEOGRAPH + 0x8744: 0x560D, //CJK UNIFIED IDEOGRAPH + 0x8745: 0x5610, //CJK UNIFIED IDEOGRAPH + 0x8746: 0x5611, //CJK UNIFIED IDEOGRAPH + 0x8747: 0x5612, //CJK UNIFIED IDEOGRAPH + 0x8748: 0x5613, //CJK UNIFIED IDEOGRAPH + 0x8749: 0x5614, //CJK UNIFIED IDEOGRAPH + 0x874A: 0x5615, //CJK UNIFIED IDEOGRAPH + 0x874B: 0x5616, //CJK UNIFIED IDEOGRAPH + 0x874C: 0x5617, //CJK UNIFIED IDEOGRAPH + 0x874D: 0x5619, //CJK UNIFIED IDEOGRAPH + 0x874E: 0x561A, //CJK UNIFIED IDEOGRAPH + 0x874F: 0x561C, //CJK UNIFIED IDEOGRAPH + 0x8750: 0x561D, //CJK UNIFIED IDEOGRAPH + 0x8751: 0x5620, //CJK UNIFIED IDEOGRAPH + 0x8752: 0x5621, //CJK UNIFIED IDEOGRAPH + 0x8753: 0x5622, //CJK UNIFIED IDEOGRAPH + 0x8754: 0x5625, //CJK UNIFIED IDEOGRAPH + 0x8755: 0x5626, //CJK UNIFIED IDEOGRAPH + 0x8756: 0x5628, //CJK UNIFIED IDEOGRAPH + 0x8757: 0x5629, //CJK UNIFIED IDEOGRAPH + 0x8758: 0x562A, //CJK UNIFIED IDEOGRAPH + 0x8759: 0x562B, //CJK UNIFIED IDEOGRAPH + 0x875A: 0x562E, //CJK UNIFIED IDEOGRAPH + 0x875B: 0x562F, //CJK UNIFIED IDEOGRAPH + 0x875C: 0x5630, //CJK UNIFIED IDEOGRAPH + 0x875D: 0x5633, //CJK UNIFIED IDEOGRAPH + 0x875E: 0x5635, //CJK UNIFIED IDEOGRAPH + 0x875F: 0x5637, //CJK UNIFIED IDEOGRAPH + 0x8760: 0x5638, //CJK UNIFIED IDEOGRAPH + 0x8761: 0x563A, //CJK UNIFIED IDEOGRAPH + 0x8762: 0x563C, //CJK UNIFIED IDEOGRAPH + 0x8763: 0x563D, //CJK UNIFIED IDEOGRAPH + 0x8764: 0x563E, //CJK UNIFIED IDEOGRAPH + 0x8765: 0x5640, //CJK UNIFIED IDEOGRAPH + 0x8766: 0x5641, //CJK UNIFIED IDEOGRAPH + 0x8767: 0x5642, //CJK UNIFIED IDEOGRAPH + 0x8768: 0x5643, //CJK UNIFIED IDEOGRAPH + 0x8769: 0x5644, //CJK UNIFIED IDEOGRAPH + 0x876A: 0x5645, //CJK UNIFIED IDEOGRAPH + 0x876B: 0x5646, //CJK UNIFIED IDEOGRAPH + 0x876C: 0x5647, //CJK UNIFIED IDEOGRAPH + 0x876D: 0x5648, //CJK UNIFIED IDEOGRAPH + 0x876E: 0x5649, //CJK UNIFIED IDEOGRAPH + 0x876F: 0x564A, //CJK UNIFIED IDEOGRAPH + 0x8770: 0x564B, //CJK UNIFIED IDEOGRAPH + 0x8771: 0x564F, //CJK UNIFIED IDEOGRAPH + 0x8772: 0x5650, //CJK UNIFIED IDEOGRAPH + 0x8773: 0x5651, //CJK UNIFIED IDEOGRAPH + 0x8774: 0x5652, //CJK UNIFIED IDEOGRAPH + 0x8775: 0x5653, //CJK UNIFIED IDEOGRAPH + 0x8776: 0x5655, //CJK UNIFIED IDEOGRAPH + 0x8777: 0x5656, //CJK UNIFIED IDEOGRAPH + 0x8778: 0x565A, //CJK UNIFIED IDEOGRAPH + 0x8779: 0x565B, //CJK UNIFIED IDEOGRAPH + 0x877A: 0x565D, //CJK UNIFIED IDEOGRAPH + 0x877B: 0x565E, //CJK UNIFIED IDEOGRAPH + 0x877C: 0x565F, //CJK UNIFIED IDEOGRAPH + 0x877D: 0x5660, //CJK UNIFIED IDEOGRAPH + 0x877E: 0x5661, //CJK UNIFIED IDEOGRAPH + 0x8780: 0x5663, //CJK UNIFIED IDEOGRAPH + 0x8781: 0x5665, //CJK UNIFIED IDEOGRAPH + 0x8782: 0x5666, //CJK UNIFIED IDEOGRAPH + 0x8783: 0x5667, //CJK UNIFIED IDEOGRAPH + 0x8784: 0x566D, //CJK UNIFIED IDEOGRAPH + 0x8785: 0x566E, //CJK UNIFIED IDEOGRAPH + 0x8786: 0x566F, //CJK UNIFIED IDEOGRAPH + 0x8787: 0x5670, //CJK UNIFIED IDEOGRAPH + 0x8788: 0x5672, //CJK UNIFIED IDEOGRAPH + 0x8789: 0x5673, //CJK UNIFIED IDEOGRAPH + 0x878A: 0x5674, //CJK UNIFIED IDEOGRAPH + 0x878B: 0x5675, //CJK UNIFIED IDEOGRAPH + 0x878C: 0x5677, //CJK UNIFIED IDEOGRAPH + 0x878D: 0x5678, //CJK UNIFIED IDEOGRAPH + 0x878E: 0x5679, //CJK UNIFIED IDEOGRAPH + 0x878F: 0x567A, //CJK UNIFIED IDEOGRAPH + 0x8790: 0x567D, //CJK UNIFIED IDEOGRAPH + 0x8791: 0x567E, //CJK UNIFIED IDEOGRAPH + 0x8792: 0x567F, //CJK UNIFIED IDEOGRAPH + 0x8793: 0x5680, //CJK UNIFIED IDEOGRAPH + 0x8794: 0x5681, //CJK UNIFIED IDEOGRAPH + 0x8795: 0x5682, //CJK UNIFIED IDEOGRAPH + 0x8796: 0x5683, //CJK UNIFIED IDEOGRAPH + 0x8797: 0x5684, //CJK UNIFIED IDEOGRAPH + 0x8798: 0x5687, //CJK UNIFIED IDEOGRAPH + 0x8799: 0x5688, //CJK UNIFIED IDEOGRAPH + 0x879A: 0x5689, //CJK UNIFIED IDEOGRAPH + 0x879B: 0x568A, //CJK UNIFIED IDEOGRAPH + 0x879C: 0x568B, //CJK UNIFIED IDEOGRAPH + 0x879D: 0x568C, //CJK UNIFIED IDEOGRAPH + 0x879E: 0x568D, //CJK UNIFIED IDEOGRAPH + 0x879F: 0x5690, //CJK UNIFIED IDEOGRAPH + 0x87A0: 0x5691, //CJK UNIFIED IDEOGRAPH + 0x87A1: 0x5692, //CJK UNIFIED IDEOGRAPH + 0x87A2: 0x5694, //CJK UNIFIED IDEOGRAPH + 0x87A3: 0x5695, //CJK UNIFIED IDEOGRAPH + 0x87A4: 0x5696, //CJK UNIFIED IDEOGRAPH + 0x87A5: 0x5697, //CJK UNIFIED IDEOGRAPH + 0x87A6: 0x5698, //CJK UNIFIED IDEOGRAPH + 0x87A7: 0x5699, //CJK UNIFIED IDEOGRAPH + 0x87A8: 0x569A, //CJK UNIFIED IDEOGRAPH + 0x87A9: 0x569B, //CJK UNIFIED IDEOGRAPH + 0x87AA: 0x569C, //CJK UNIFIED IDEOGRAPH + 0x87AB: 0x569D, //CJK UNIFIED IDEOGRAPH + 0x87AC: 0x569E, //CJK UNIFIED IDEOGRAPH + 0x87AD: 0x569F, //CJK UNIFIED IDEOGRAPH + 0x87AE: 0x56A0, //CJK UNIFIED IDEOGRAPH + 0x87AF: 0x56A1, //CJK UNIFIED IDEOGRAPH + 0x87B0: 0x56A2, //CJK UNIFIED IDEOGRAPH + 0x87B1: 0x56A4, //CJK UNIFIED IDEOGRAPH + 0x87B2: 0x56A5, //CJK UNIFIED IDEOGRAPH + 0x87B3: 0x56A6, //CJK UNIFIED IDEOGRAPH + 0x87B4: 0x56A7, //CJK UNIFIED IDEOGRAPH + 0x87B5: 0x56A8, //CJK UNIFIED IDEOGRAPH + 0x87B6: 0x56A9, //CJK UNIFIED IDEOGRAPH + 0x87B7: 0x56AA, //CJK UNIFIED IDEOGRAPH + 0x87B8: 0x56AB, //CJK UNIFIED IDEOGRAPH + 0x87B9: 0x56AC, //CJK UNIFIED IDEOGRAPH + 0x87BA: 0x56AD, //CJK UNIFIED IDEOGRAPH + 0x87BB: 0x56AE, //CJK UNIFIED IDEOGRAPH + 0x87BC: 0x56B0, //CJK UNIFIED IDEOGRAPH + 0x87BD: 0x56B1, //CJK UNIFIED IDEOGRAPH + 0x87BE: 0x56B2, //CJK UNIFIED IDEOGRAPH + 0x87BF: 0x56B3, //CJK UNIFIED IDEOGRAPH + 0x87C0: 0x56B4, //CJK UNIFIED IDEOGRAPH + 0x87C1: 0x56B5, //CJK UNIFIED IDEOGRAPH + 0x87C2: 0x56B6, //CJK UNIFIED IDEOGRAPH + 0x87C3: 0x56B8, //CJK UNIFIED IDEOGRAPH + 0x87C4: 0x56B9, //CJK UNIFIED IDEOGRAPH + 0x87C5: 0x56BA, //CJK UNIFIED IDEOGRAPH + 0x87C6: 0x56BB, //CJK UNIFIED IDEOGRAPH + 0x87C7: 0x56BD, //CJK UNIFIED IDEOGRAPH + 0x87C8: 0x56BE, //CJK UNIFIED IDEOGRAPH + 0x87C9: 0x56BF, //CJK UNIFIED IDEOGRAPH + 0x87CA: 0x56C0, //CJK UNIFIED IDEOGRAPH + 0x87CB: 0x56C1, //CJK UNIFIED IDEOGRAPH + 0x87CC: 0x56C2, //CJK UNIFIED IDEOGRAPH + 0x87CD: 0x56C3, //CJK UNIFIED IDEOGRAPH + 0x87CE: 0x56C4, //CJK UNIFIED IDEOGRAPH + 0x87CF: 0x56C5, //CJK UNIFIED IDEOGRAPH + 0x87D0: 0x56C6, //CJK UNIFIED IDEOGRAPH + 0x87D1: 0x56C7, //CJK UNIFIED IDEOGRAPH + 0x87D2: 0x56C8, //CJK UNIFIED IDEOGRAPH + 0x87D3: 0x56C9, //CJK UNIFIED IDEOGRAPH + 0x87D4: 0x56CB, //CJK UNIFIED IDEOGRAPH + 0x87D5: 0x56CC, //CJK UNIFIED IDEOGRAPH + 0x87D6: 0x56CD, //CJK UNIFIED IDEOGRAPH + 0x87D7: 0x56CE, //CJK UNIFIED IDEOGRAPH + 0x87D8: 0x56CF, //CJK UNIFIED IDEOGRAPH + 0x87D9: 0x56D0, //CJK UNIFIED IDEOGRAPH + 0x87DA: 0x56D1, //CJK UNIFIED IDEOGRAPH + 0x87DB: 0x56D2, //CJK UNIFIED IDEOGRAPH + 0x87DC: 0x56D3, //CJK UNIFIED IDEOGRAPH + 0x87DD: 0x56D5, //CJK UNIFIED IDEOGRAPH + 0x87DE: 0x56D6, //CJK UNIFIED IDEOGRAPH + 0x87DF: 0x56D8, //CJK UNIFIED IDEOGRAPH + 0x87E0: 0x56D9, //CJK UNIFIED IDEOGRAPH + 0x87E1: 0x56DC, //CJK UNIFIED IDEOGRAPH + 0x87E2: 0x56E3, //CJK UNIFIED IDEOGRAPH + 0x87E3: 0x56E5, //CJK UNIFIED IDEOGRAPH + 0x87E4: 0x56E6, //CJK UNIFIED IDEOGRAPH + 0x87E5: 0x56E7, //CJK UNIFIED IDEOGRAPH + 0x87E6: 0x56E8, //CJK UNIFIED IDEOGRAPH + 0x87E7: 0x56E9, //CJK UNIFIED IDEOGRAPH + 0x87E8: 0x56EA, //CJK UNIFIED IDEOGRAPH + 0x87E9: 0x56EC, //CJK UNIFIED IDEOGRAPH + 0x87EA: 0x56EE, //CJK UNIFIED IDEOGRAPH + 0x87EB: 0x56EF, //CJK UNIFIED IDEOGRAPH + 0x87EC: 0x56F2, //CJK UNIFIED IDEOGRAPH + 0x87ED: 0x56F3, //CJK UNIFIED IDEOGRAPH + 0x87EE: 0x56F6, //CJK UNIFIED IDEOGRAPH + 0x87EF: 0x56F7, //CJK UNIFIED IDEOGRAPH + 0x87F0: 0x56F8, //CJK UNIFIED IDEOGRAPH + 0x87F1: 0x56FB, //CJK UNIFIED IDEOGRAPH + 0x87F2: 0x56FC, //CJK UNIFIED IDEOGRAPH + 0x87F3: 0x5700, //CJK UNIFIED IDEOGRAPH + 0x87F4: 0x5701, //CJK UNIFIED IDEOGRAPH + 0x87F5: 0x5702, //CJK UNIFIED IDEOGRAPH + 0x87F6: 0x5705, //CJK UNIFIED IDEOGRAPH + 0x87F7: 0x5707, //CJK UNIFIED IDEOGRAPH + 0x87F8: 0x570B, //CJK UNIFIED IDEOGRAPH + 0x87F9: 0x570C, //CJK UNIFIED IDEOGRAPH + 0x87FA: 0x570D, //CJK UNIFIED IDEOGRAPH + 0x87FB: 0x570E, //CJK UNIFIED IDEOGRAPH + 0x87FC: 0x570F, //CJK UNIFIED IDEOGRAPH + 0x87FD: 0x5710, //CJK UNIFIED IDEOGRAPH + 0x87FE: 0x5711, //CJK UNIFIED IDEOGRAPH + 0x8840: 0x5712, //CJK UNIFIED IDEOGRAPH + 0x8841: 0x5713, //CJK UNIFIED IDEOGRAPH + 0x8842: 0x5714, //CJK UNIFIED IDEOGRAPH + 0x8843: 0x5715, //CJK UNIFIED IDEOGRAPH + 0x8844: 0x5716, //CJK UNIFIED IDEOGRAPH + 0x8845: 0x5717, //CJK UNIFIED IDEOGRAPH + 0x8846: 0x5718, //CJK UNIFIED IDEOGRAPH + 0x8847: 0x5719, //CJK UNIFIED IDEOGRAPH + 0x8848: 0x571A, //CJK UNIFIED IDEOGRAPH + 0x8849: 0x571B, //CJK UNIFIED IDEOGRAPH + 0x884A: 0x571D, //CJK UNIFIED IDEOGRAPH + 0x884B: 0x571E, //CJK UNIFIED IDEOGRAPH + 0x884C: 0x5720, //CJK UNIFIED IDEOGRAPH + 0x884D: 0x5721, //CJK UNIFIED IDEOGRAPH + 0x884E: 0x5722, //CJK UNIFIED IDEOGRAPH + 0x884F: 0x5724, //CJK UNIFIED IDEOGRAPH + 0x8850: 0x5725, //CJK UNIFIED IDEOGRAPH + 0x8851: 0x5726, //CJK UNIFIED IDEOGRAPH + 0x8852: 0x5727, //CJK UNIFIED IDEOGRAPH + 0x8853: 0x572B, //CJK UNIFIED IDEOGRAPH + 0x8854: 0x5731, //CJK UNIFIED IDEOGRAPH + 0x8855: 0x5732, //CJK UNIFIED IDEOGRAPH + 0x8856: 0x5734, //CJK UNIFIED IDEOGRAPH + 0x8857: 0x5735, //CJK UNIFIED IDEOGRAPH + 0x8858: 0x5736, //CJK UNIFIED IDEOGRAPH + 0x8859: 0x5737, //CJK UNIFIED IDEOGRAPH + 0x885A: 0x5738, //CJK UNIFIED IDEOGRAPH + 0x885B: 0x573C, //CJK UNIFIED IDEOGRAPH + 0x885C: 0x573D, //CJK UNIFIED IDEOGRAPH + 0x885D: 0x573F, //CJK UNIFIED IDEOGRAPH + 0x885E: 0x5741, //CJK UNIFIED IDEOGRAPH + 0x885F: 0x5743, //CJK UNIFIED IDEOGRAPH + 0x8860: 0x5744, //CJK UNIFIED IDEOGRAPH + 0x8861: 0x5745, //CJK UNIFIED IDEOGRAPH + 0x8862: 0x5746, //CJK UNIFIED IDEOGRAPH + 0x8863: 0x5748, //CJK UNIFIED IDEOGRAPH + 0x8864: 0x5749, //CJK UNIFIED IDEOGRAPH + 0x8865: 0x574B, //CJK UNIFIED IDEOGRAPH + 0x8866: 0x5752, //CJK UNIFIED IDEOGRAPH + 0x8867: 0x5753, //CJK UNIFIED IDEOGRAPH + 0x8868: 0x5754, //CJK UNIFIED IDEOGRAPH + 0x8869: 0x5755, //CJK UNIFIED IDEOGRAPH + 0x886A: 0x5756, //CJK UNIFIED IDEOGRAPH + 0x886B: 0x5758, //CJK UNIFIED IDEOGRAPH + 0x886C: 0x5759, //CJK UNIFIED IDEOGRAPH + 0x886D: 0x5762, //CJK UNIFIED IDEOGRAPH + 0x886E: 0x5763, //CJK UNIFIED IDEOGRAPH + 0x886F: 0x5765, //CJK UNIFIED IDEOGRAPH + 0x8870: 0x5767, //CJK UNIFIED IDEOGRAPH + 0x8871: 0x576C, //CJK UNIFIED IDEOGRAPH + 0x8872: 0x576E, //CJK UNIFIED IDEOGRAPH + 0x8873: 0x5770, //CJK UNIFIED IDEOGRAPH + 0x8874: 0x5771, //CJK UNIFIED IDEOGRAPH + 0x8875: 0x5772, //CJK UNIFIED IDEOGRAPH + 0x8876: 0x5774, //CJK UNIFIED IDEOGRAPH + 0x8877: 0x5775, //CJK UNIFIED IDEOGRAPH + 0x8878: 0x5778, //CJK UNIFIED IDEOGRAPH + 0x8879: 0x5779, //CJK UNIFIED IDEOGRAPH + 0x887A: 0x577A, //CJK UNIFIED IDEOGRAPH + 0x887B: 0x577D, //CJK UNIFIED IDEOGRAPH + 0x887C: 0x577E, //CJK UNIFIED IDEOGRAPH + 0x887D: 0x577F, //CJK UNIFIED IDEOGRAPH + 0x887E: 0x5780, //CJK UNIFIED IDEOGRAPH + 0x8880: 0x5781, //CJK UNIFIED IDEOGRAPH + 0x8881: 0x5787, //CJK UNIFIED IDEOGRAPH + 0x8882: 0x5788, //CJK UNIFIED IDEOGRAPH + 0x8883: 0x5789, //CJK UNIFIED IDEOGRAPH + 0x8884: 0x578A, //CJK UNIFIED IDEOGRAPH + 0x8885: 0x578D, //CJK UNIFIED IDEOGRAPH + 0x8886: 0x578E, //CJK UNIFIED IDEOGRAPH + 0x8887: 0x578F, //CJK UNIFIED IDEOGRAPH + 0x8888: 0x5790, //CJK UNIFIED IDEOGRAPH + 0x8889: 0x5791, //CJK UNIFIED IDEOGRAPH + 0x888A: 0x5794, //CJK UNIFIED IDEOGRAPH + 0x888B: 0x5795, //CJK UNIFIED IDEOGRAPH + 0x888C: 0x5796, //CJK UNIFIED IDEOGRAPH + 0x888D: 0x5797, //CJK UNIFIED IDEOGRAPH + 0x888E: 0x5798, //CJK UNIFIED IDEOGRAPH + 0x888F: 0x5799, //CJK UNIFIED IDEOGRAPH + 0x8890: 0x579A, //CJK UNIFIED IDEOGRAPH + 0x8891: 0x579C, //CJK UNIFIED IDEOGRAPH + 0x8892: 0x579D, //CJK UNIFIED IDEOGRAPH + 0x8893: 0x579E, //CJK UNIFIED IDEOGRAPH + 0x8894: 0x579F, //CJK UNIFIED IDEOGRAPH + 0x8895: 0x57A5, //CJK UNIFIED IDEOGRAPH + 0x8896: 0x57A8, //CJK UNIFIED IDEOGRAPH + 0x8897: 0x57AA, //CJK UNIFIED IDEOGRAPH + 0x8898: 0x57AC, //CJK UNIFIED IDEOGRAPH + 0x8899: 0x57AF, //CJK UNIFIED IDEOGRAPH + 0x889A: 0x57B0, //CJK UNIFIED IDEOGRAPH + 0x889B: 0x57B1, //CJK UNIFIED IDEOGRAPH + 0x889C: 0x57B3, //CJK UNIFIED IDEOGRAPH + 0x889D: 0x57B5, //CJK UNIFIED IDEOGRAPH + 0x889E: 0x57B6, //CJK UNIFIED IDEOGRAPH + 0x889F: 0x57B7, //CJK UNIFIED IDEOGRAPH + 0x88A0: 0x57B9, //CJK UNIFIED IDEOGRAPH + 0x88A1: 0x57BA, //CJK UNIFIED IDEOGRAPH + 0x88A2: 0x57BB, //CJK UNIFIED IDEOGRAPH + 0x88A3: 0x57BC, //CJK UNIFIED IDEOGRAPH + 0x88A4: 0x57BD, //CJK UNIFIED IDEOGRAPH + 0x88A5: 0x57BE, //CJK UNIFIED IDEOGRAPH + 0x88A6: 0x57BF, //CJK UNIFIED IDEOGRAPH + 0x88A7: 0x57C0, //CJK UNIFIED IDEOGRAPH + 0x88A8: 0x57C1, //CJK UNIFIED IDEOGRAPH + 0x88A9: 0x57C4, //CJK UNIFIED IDEOGRAPH + 0x88AA: 0x57C5, //CJK UNIFIED IDEOGRAPH + 0x88AB: 0x57C6, //CJK UNIFIED IDEOGRAPH + 0x88AC: 0x57C7, //CJK UNIFIED IDEOGRAPH + 0x88AD: 0x57C8, //CJK UNIFIED IDEOGRAPH + 0x88AE: 0x57C9, //CJK UNIFIED IDEOGRAPH + 0x88AF: 0x57CA, //CJK UNIFIED IDEOGRAPH + 0x88B0: 0x57CC, //CJK UNIFIED IDEOGRAPH + 0x88B1: 0x57CD, //CJK UNIFIED IDEOGRAPH + 0x88B2: 0x57D0, //CJK UNIFIED IDEOGRAPH + 0x88B3: 0x57D1, //CJK UNIFIED IDEOGRAPH + 0x88B4: 0x57D3, //CJK UNIFIED IDEOGRAPH + 0x88B5: 0x57D6, //CJK UNIFIED IDEOGRAPH + 0x88B6: 0x57D7, //CJK UNIFIED IDEOGRAPH + 0x88B7: 0x57DB, //CJK UNIFIED IDEOGRAPH + 0x88B8: 0x57DC, //CJK UNIFIED IDEOGRAPH + 0x88B9: 0x57DE, //CJK UNIFIED IDEOGRAPH + 0x88BA: 0x57E1, //CJK UNIFIED IDEOGRAPH + 0x88BB: 0x57E2, //CJK UNIFIED IDEOGRAPH + 0x88BC: 0x57E3, //CJK UNIFIED IDEOGRAPH + 0x88BD: 0x57E5, //CJK UNIFIED IDEOGRAPH + 0x88BE: 0x57E6, //CJK UNIFIED IDEOGRAPH + 0x88BF: 0x57E7, //CJK UNIFIED IDEOGRAPH + 0x88C0: 0x57E8, //CJK UNIFIED IDEOGRAPH + 0x88C1: 0x57E9, //CJK UNIFIED IDEOGRAPH + 0x88C2: 0x57EA, //CJK UNIFIED IDEOGRAPH + 0x88C3: 0x57EB, //CJK UNIFIED IDEOGRAPH + 0x88C4: 0x57EC, //CJK UNIFIED IDEOGRAPH + 0x88C5: 0x57EE, //CJK UNIFIED IDEOGRAPH + 0x88C6: 0x57F0, //CJK UNIFIED IDEOGRAPH + 0x88C7: 0x57F1, //CJK UNIFIED IDEOGRAPH + 0x88C8: 0x57F2, //CJK UNIFIED IDEOGRAPH + 0x88C9: 0x57F3, //CJK UNIFIED IDEOGRAPH + 0x88CA: 0x57F5, //CJK UNIFIED IDEOGRAPH + 0x88CB: 0x57F6, //CJK UNIFIED IDEOGRAPH + 0x88CC: 0x57F7, //CJK UNIFIED IDEOGRAPH + 0x88CD: 0x57FB, //CJK UNIFIED IDEOGRAPH + 0x88CE: 0x57FC, //CJK UNIFIED IDEOGRAPH + 0x88CF: 0x57FE, //CJK UNIFIED IDEOGRAPH + 0x88D0: 0x57FF, //CJK UNIFIED IDEOGRAPH + 0x88D1: 0x5801, //CJK UNIFIED IDEOGRAPH + 0x88D2: 0x5803, //CJK UNIFIED IDEOGRAPH + 0x88D3: 0x5804, //CJK UNIFIED IDEOGRAPH + 0x88D4: 0x5805, //CJK UNIFIED IDEOGRAPH + 0x88D5: 0x5808, //CJK UNIFIED IDEOGRAPH + 0x88D6: 0x5809, //CJK UNIFIED IDEOGRAPH + 0x88D7: 0x580A, //CJK UNIFIED IDEOGRAPH + 0x88D8: 0x580C, //CJK UNIFIED IDEOGRAPH + 0x88D9: 0x580E, //CJK UNIFIED IDEOGRAPH + 0x88DA: 0x580F, //CJK UNIFIED IDEOGRAPH + 0x88DB: 0x5810, //CJK UNIFIED IDEOGRAPH + 0x88DC: 0x5812, //CJK UNIFIED IDEOGRAPH + 0x88DD: 0x5813, //CJK UNIFIED IDEOGRAPH + 0x88DE: 0x5814, //CJK UNIFIED IDEOGRAPH + 0x88DF: 0x5816, //CJK UNIFIED IDEOGRAPH + 0x88E0: 0x5817, //CJK UNIFIED IDEOGRAPH + 0x88E1: 0x5818, //CJK UNIFIED IDEOGRAPH + 0x88E2: 0x581A, //CJK UNIFIED IDEOGRAPH + 0x88E3: 0x581B, //CJK UNIFIED IDEOGRAPH + 0x88E4: 0x581C, //CJK UNIFIED IDEOGRAPH + 0x88E5: 0x581D, //CJK UNIFIED IDEOGRAPH + 0x88E6: 0x581F, //CJK UNIFIED IDEOGRAPH + 0x88E7: 0x5822, //CJK UNIFIED IDEOGRAPH + 0x88E8: 0x5823, //CJK UNIFIED IDEOGRAPH + 0x88E9: 0x5825, //CJK UNIFIED IDEOGRAPH + 0x88EA: 0x5826, //CJK UNIFIED IDEOGRAPH + 0x88EB: 0x5827, //CJK UNIFIED IDEOGRAPH + 0x88EC: 0x5828, //CJK UNIFIED IDEOGRAPH + 0x88ED: 0x5829, //CJK UNIFIED IDEOGRAPH + 0x88EE: 0x582B, //CJK UNIFIED IDEOGRAPH + 0x88EF: 0x582C, //CJK UNIFIED IDEOGRAPH + 0x88F0: 0x582D, //CJK UNIFIED IDEOGRAPH + 0x88F1: 0x582E, //CJK UNIFIED IDEOGRAPH + 0x88F2: 0x582F, //CJK UNIFIED IDEOGRAPH + 0x88F3: 0x5831, //CJK UNIFIED IDEOGRAPH + 0x88F4: 0x5832, //CJK UNIFIED IDEOGRAPH + 0x88F5: 0x5833, //CJK UNIFIED IDEOGRAPH + 0x88F6: 0x5834, //CJK UNIFIED IDEOGRAPH + 0x88F7: 0x5836, //CJK UNIFIED IDEOGRAPH + 0x88F8: 0x5837, //CJK UNIFIED IDEOGRAPH + 0x88F9: 0x5838, //CJK UNIFIED IDEOGRAPH + 0x88FA: 0x5839, //CJK UNIFIED IDEOGRAPH + 0x88FB: 0x583A, //CJK UNIFIED IDEOGRAPH + 0x88FC: 0x583B, //CJK UNIFIED IDEOGRAPH + 0x88FD: 0x583C, //CJK UNIFIED IDEOGRAPH + 0x88FE: 0x583D, //CJK UNIFIED IDEOGRAPH + 0x8940: 0x583E, //CJK UNIFIED IDEOGRAPH + 0x8941: 0x583F, //CJK UNIFIED IDEOGRAPH + 0x8942: 0x5840, //CJK UNIFIED IDEOGRAPH + 0x8943: 0x5841, //CJK UNIFIED IDEOGRAPH + 0x8944: 0x5842, //CJK UNIFIED IDEOGRAPH + 0x8945: 0x5843, //CJK UNIFIED IDEOGRAPH + 0x8946: 0x5845, //CJK UNIFIED IDEOGRAPH + 0x8947: 0x5846, //CJK UNIFIED IDEOGRAPH + 0x8948: 0x5847, //CJK UNIFIED IDEOGRAPH + 0x8949: 0x5848, //CJK UNIFIED IDEOGRAPH + 0x894A: 0x5849, //CJK UNIFIED IDEOGRAPH + 0x894B: 0x584A, //CJK UNIFIED IDEOGRAPH + 0x894C: 0x584B, //CJK UNIFIED IDEOGRAPH + 0x894D: 0x584E, //CJK UNIFIED IDEOGRAPH + 0x894E: 0x584F, //CJK UNIFIED IDEOGRAPH + 0x894F: 0x5850, //CJK UNIFIED IDEOGRAPH + 0x8950: 0x5852, //CJK UNIFIED IDEOGRAPH + 0x8951: 0x5853, //CJK UNIFIED IDEOGRAPH + 0x8952: 0x5855, //CJK UNIFIED IDEOGRAPH + 0x8953: 0x5856, //CJK UNIFIED IDEOGRAPH + 0x8954: 0x5857, //CJK UNIFIED IDEOGRAPH + 0x8955: 0x5859, //CJK UNIFIED IDEOGRAPH + 0x8956: 0x585A, //CJK UNIFIED IDEOGRAPH + 0x8957: 0x585B, //CJK UNIFIED IDEOGRAPH + 0x8958: 0x585C, //CJK UNIFIED IDEOGRAPH + 0x8959: 0x585D, //CJK UNIFIED IDEOGRAPH + 0x895A: 0x585F, //CJK UNIFIED IDEOGRAPH + 0x895B: 0x5860, //CJK UNIFIED IDEOGRAPH + 0x895C: 0x5861, //CJK UNIFIED IDEOGRAPH + 0x895D: 0x5862, //CJK UNIFIED IDEOGRAPH + 0x895E: 0x5863, //CJK UNIFIED IDEOGRAPH + 0x895F: 0x5864, //CJK UNIFIED IDEOGRAPH + 0x8960: 0x5866, //CJK UNIFIED IDEOGRAPH + 0x8961: 0x5867, //CJK UNIFIED IDEOGRAPH + 0x8962: 0x5868, //CJK UNIFIED IDEOGRAPH + 0x8963: 0x5869, //CJK UNIFIED IDEOGRAPH + 0x8964: 0x586A, //CJK UNIFIED IDEOGRAPH + 0x8965: 0x586D, //CJK UNIFIED IDEOGRAPH + 0x8966: 0x586E, //CJK UNIFIED IDEOGRAPH + 0x8967: 0x586F, //CJK UNIFIED IDEOGRAPH + 0x8968: 0x5870, //CJK UNIFIED IDEOGRAPH + 0x8969: 0x5871, //CJK UNIFIED IDEOGRAPH + 0x896A: 0x5872, //CJK UNIFIED IDEOGRAPH + 0x896B: 0x5873, //CJK UNIFIED IDEOGRAPH + 0x896C: 0x5874, //CJK UNIFIED IDEOGRAPH + 0x896D: 0x5875, //CJK UNIFIED IDEOGRAPH + 0x896E: 0x5876, //CJK UNIFIED IDEOGRAPH + 0x896F: 0x5877, //CJK UNIFIED IDEOGRAPH + 0x8970: 0x5878, //CJK UNIFIED IDEOGRAPH + 0x8971: 0x5879, //CJK UNIFIED IDEOGRAPH + 0x8972: 0x587A, //CJK UNIFIED IDEOGRAPH + 0x8973: 0x587B, //CJK UNIFIED IDEOGRAPH + 0x8974: 0x587C, //CJK UNIFIED IDEOGRAPH + 0x8975: 0x587D, //CJK UNIFIED IDEOGRAPH + 0x8976: 0x587F, //CJK UNIFIED IDEOGRAPH + 0x8977: 0x5882, //CJK UNIFIED IDEOGRAPH + 0x8978: 0x5884, //CJK UNIFIED IDEOGRAPH + 0x8979: 0x5886, //CJK UNIFIED IDEOGRAPH + 0x897A: 0x5887, //CJK UNIFIED IDEOGRAPH + 0x897B: 0x5888, //CJK UNIFIED IDEOGRAPH + 0x897C: 0x588A, //CJK UNIFIED IDEOGRAPH + 0x897D: 0x588B, //CJK UNIFIED IDEOGRAPH + 0x897E: 0x588C, //CJK UNIFIED IDEOGRAPH + 0x8980: 0x588D, //CJK UNIFIED IDEOGRAPH + 0x8981: 0x588E, //CJK UNIFIED IDEOGRAPH + 0x8982: 0x588F, //CJK UNIFIED IDEOGRAPH + 0x8983: 0x5890, //CJK UNIFIED IDEOGRAPH + 0x8984: 0x5891, //CJK UNIFIED IDEOGRAPH + 0x8985: 0x5894, //CJK UNIFIED IDEOGRAPH + 0x8986: 0x5895, //CJK UNIFIED IDEOGRAPH + 0x8987: 0x5896, //CJK UNIFIED IDEOGRAPH + 0x8988: 0x5897, //CJK UNIFIED IDEOGRAPH + 0x8989: 0x5898, //CJK UNIFIED IDEOGRAPH + 0x898A: 0x589B, //CJK UNIFIED IDEOGRAPH + 0x898B: 0x589C, //CJK UNIFIED IDEOGRAPH + 0x898C: 0x589D, //CJK UNIFIED IDEOGRAPH + 0x898D: 0x58A0, //CJK UNIFIED IDEOGRAPH + 0x898E: 0x58A1, //CJK UNIFIED IDEOGRAPH + 0x898F: 0x58A2, //CJK UNIFIED IDEOGRAPH + 0x8990: 0x58A3, //CJK UNIFIED IDEOGRAPH + 0x8991: 0x58A4, //CJK UNIFIED IDEOGRAPH + 0x8992: 0x58A5, //CJK UNIFIED IDEOGRAPH + 0x8993: 0x58A6, //CJK UNIFIED IDEOGRAPH + 0x8994: 0x58A7, //CJK UNIFIED IDEOGRAPH + 0x8995: 0x58AA, //CJK UNIFIED IDEOGRAPH + 0x8996: 0x58AB, //CJK UNIFIED IDEOGRAPH + 0x8997: 0x58AC, //CJK UNIFIED IDEOGRAPH + 0x8998: 0x58AD, //CJK UNIFIED IDEOGRAPH + 0x8999: 0x58AE, //CJK UNIFIED IDEOGRAPH + 0x899A: 0x58AF, //CJK UNIFIED IDEOGRAPH + 0x899B: 0x58B0, //CJK UNIFIED IDEOGRAPH + 0x899C: 0x58B1, //CJK UNIFIED IDEOGRAPH + 0x899D: 0x58B2, //CJK UNIFIED IDEOGRAPH + 0x899E: 0x58B3, //CJK UNIFIED IDEOGRAPH + 0x899F: 0x58B4, //CJK UNIFIED IDEOGRAPH + 0x89A0: 0x58B5, //CJK UNIFIED IDEOGRAPH + 0x89A1: 0x58B6, //CJK UNIFIED IDEOGRAPH + 0x89A2: 0x58B7, //CJK UNIFIED IDEOGRAPH + 0x89A3: 0x58B8, //CJK UNIFIED IDEOGRAPH + 0x89A4: 0x58B9, //CJK UNIFIED IDEOGRAPH + 0x89A5: 0x58BA, //CJK UNIFIED IDEOGRAPH + 0x89A6: 0x58BB, //CJK UNIFIED IDEOGRAPH + 0x89A7: 0x58BD, //CJK UNIFIED IDEOGRAPH + 0x89A8: 0x58BE, //CJK UNIFIED IDEOGRAPH + 0x89A9: 0x58BF, //CJK UNIFIED IDEOGRAPH + 0x89AA: 0x58C0, //CJK UNIFIED IDEOGRAPH + 0x89AB: 0x58C2, //CJK UNIFIED IDEOGRAPH + 0x89AC: 0x58C3, //CJK UNIFIED IDEOGRAPH + 0x89AD: 0x58C4, //CJK UNIFIED IDEOGRAPH + 0x89AE: 0x58C6, //CJK UNIFIED IDEOGRAPH + 0x89AF: 0x58C7, //CJK UNIFIED IDEOGRAPH + 0x89B0: 0x58C8, //CJK UNIFIED IDEOGRAPH + 0x89B1: 0x58C9, //CJK UNIFIED IDEOGRAPH + 0x89B2: 0x58CA, //CJK UNIFIED IDEOGRAPH + 0x89B3: 0x58CB, //CJK UNIFIED IDEOGRAPH + 0x89B4: 0x58CC, //CJK UNIFIED IDEOGRAPH + 0x89B5: 0x58CD, //CJK UNIFIED IDEOGRAPH + 0x89B6: 0x58CE, //CJK UNIFIED IDEOGRAPH + 0x89B7: 0x58CF, //CJK UNIFIED IDEOGRAPH + 0x89B8: 0x58D0, //CJK UNIFIED IDEOGRAPH + 0x89B9: 0x58D2, //CJK UNIFIED IDEOGRAPH + 0x89BA: 0x58D3, //CJK UNIFIED IDEOGRAPH + 0x89BB: 0x58D4, //CJK UNIFIED IDEOGRAPH + 0x89BC: 0x58D6, //CJK UNIFIED IDEOGRAPH + 0x89BD: 0x58D7, //CJK UNIFIED IDEOGRAPH + 0x89BE: 0x58D8, //CJK UNIFIED IDEOGRAPH + 0x89BF: 0x58D9, //CJK UNIFIED IDEOGRAPH + 0x89C0: 0x58DA, //CJK UNIFIED IDEOGRAPH + 0x89C1: 0x58DB, //CJK UNIFIED IDEOGRAPH + 0x89C2: 0x58DC, //CJK UNIFIED IDEOGRAPH + 0x89C3: 0x58DD, //CJK UNIFIED IDEOGRAPH + 0x89C4: 0x58DE, //CJK UNIFIED IDEOGRAPH + 0x89C5: 0x58DF, //CJK UNIFIED IDEOGRAPH + 0x89C6: 0x58E0, //CJK UNIFIED IDEOGRAPH + 0x89C7: 0x58E1, //CJK UNIFIED IDEOGRAPH + 0x89C8: 0x58E2, //CJK UNIFIED IDEOGRAPH + 0x89C9: 0x58E3, //CJK UNIFIED IDEOGRAPH + 0x89CA: 0x58E5, //CJK UNIFIED IDEOGRAPH + 0x89CB: 0x58E6, //CJK UNIFIED IDEOGRAPH + 0x89CC: 0x58E7, //CJK UNIFIED IDEOGRAPH + 0x89CD: 0x58E8, //CJK UNIFIED IDEOGRAPH + 0x89CE: 0x58E9, //CJK UNIFIED IDEOGRAPH + 0x89CF: 0x58EA, //CJK UNIFIED IDEOGRAPH + 0x89D0: 0x58ED, //CJK UNIFIED IDEOGRAPH + 0x89D1: 0x58EF, //CJK UNIFIED IDEOGRAPH + 0x89D2: 0x58F1, //CJK UNIFIED IDEOGRAPH + 0x89D3: 0x58F2, //CJK UNIFIED IDEOGRAPH + 0x89D4: 0x58F4, //CJK UNIFIED IDEOGRAPH + 0x89D5: 0x58F5, //CJK UNIFIED IDEOGRAPH + 0x89D6: 0x58F7, //CJK UNIFIED IDEOGRAPH + 0x89D7: 0x58F8, //CJK UNIFIED IDEOGRAPH + 0x89D8: 0x58FA, //CJK UNIFIED IDEOGRAPH + 0x89D9: 0x58FB, //CJK UNIFIED IDEOGRAPH + 0x89DA: 0x58FC, //CJK UNIFIED IDEOGRAPH + 0x89DB: 0x58FD, //CJK UNIFIED IDEOGRAPH + 0x89DC: 0x58FE, //CJK UNIFIED IDEOGRAPH + 0x89DD: 0x58FF, //CJK UNIFIED IDEOGRAPH + 0x89DE: 0x5900, //CJK UNIFIED IDEOGRAPH + 0x89DF: 0x5901, //CJK UNIFIED IDEOGRAPH + 0x89E0: 0x5903, //CJK UNIFIED IDEOGRAPH + 0x89E1: 0x5905, //CJK UNIFIED IDEOGRAPH + 0x89E2: 0x5906, //CJK UNIFIED IDEOGRAPH + 0x89E3: 0x5908, //CJK UNIFIED IDEOGRAPH + 0x89E4: 0x5909, //CJK UNIFIED IDEOGRAPH + 0x89E5: 0x590A, //CJK UNIFIED IDEOGRAPH + 0x89E6: 0x590B, //CJK UNIFIED IDEOGRAPH + 0x89E7: 0x590C, //CJK UNIFIED IDEOGRAPH + 0x89E8: 0x590E, //CJK UNIFIED IDEOGRAPH + 0x89E9: 0x5910, //CJK UNIFIED IDEOGRAPH + 0x89EA: 0x5911, //CJK UNIFIED IDEOGRAPH + 0x89EB: 0x5912, //CJK UNIFIED IDEOGRAPH + 0x89EC: 0x5913, //CJK UNIFIED IDEOGRAPH + 0x89ED: 0x5917, //CJK UNIFIED IDEOGRAPH + 0x89EE: 0x5918, //CJK UNIFIED IDEOGRAPH + 0x89EF: 0x591B, //CJK UNIFIED IDEOGRAPH + 0x89F0: 0x591D, //CJK UNIFIED IDEOGRAPH + 0x89F1: 0x591E, //CJK UNIFIED IDEOGRAPH + 0x89F2: 0x5920, //CJK UNIFIED IDEOGRAPH + 0x89F3: 0x5921, //CJK UNIFIED IDEOGRAPH + 0x89F4: 0x5922, //CJK UNIFIED IDEOGRAPH + 0x89F5: 0x5923, //CJK UNIFIED IDEOGRAPH + 0x89F6: 0x5926, //CJK UNIFIED IDEOGRAPH + 0x89F7: 0x5928, //CJK UNIFIED IDEOGRAPH + 0x89F8: 0x592C, //CJK UNIFIED IDEOGRAPH + 0x89F9: 0x5930, //CJK UNIFIED IDEOGRAPH + 0x89FA: 0x5932, //CJK UNIFIED IDEOGRAPH + 0x89FB: 0x5933, //CJK UNIFIED IDEOGRAPH + 0x89FC: 0x5935, //CJK UNIFIED IDEOGRAPH + 0x89FD: 0x5936, //CJK UNIFIED IDEOGRAPH + 0x89FE: 0x593B, //CJK UNIFIED IDEOGRAPH + 0x8A40: 0x593D, //CJK UNIFIED IDEOGRAPH + 0x8A41: 0x593E, //CJK UNIFIED IDEOGRAPH + 0x8A42: 0x593F, //CJK UNIFIED IDEOGRAPH + 0x8A43: 0x5940, //CJK UNIFIED IDEOGRAPH + 0x8A44: 0x5943, //CJK UNIFIED IDEOGRAPH + 0x8A45: 0x5945, //CJK UNIFIED IDEOGRAPH + 0x8A46: 0x5946, //CJK UNIFIED IDEOGRAPH + 0x8A47: 0x594A, //CJK UNIFIED IDEOGRAPH + 0x8A48: 0x594C, //CJK UNIFIED IDEOGRAPH + 0x8A49: 0x594D, //CJK UNIFIED IDEOGRAPH + 0x8A4A: 0x5950, //CJK UNIFIED IDEOGRAPH + 0x8A4B: 0x5952, //CJK UNIFIED IDEOGRAPH + 0x8A4C: 0x5953, //CJK UNIFIED IDEOGRAPH + 0x8A4D: 0x5959, //CJK UNIFIED IDEOGRAPH + 0x8A4E: 0x595B, //CJK UNIFIED IDEOGRAPH + 0x8A4F: 0x595C, //CJK UNIFIED IDEOGRAPH + 0x8A50: 0x595D, //CJK UNIFIED IDEOGRAPH + 0x8A51: 0x595E, //CJK UNIFIED IDEOGRAPH + 0x8A52: 0x595F, //CJK UNIFIED IDEOGRAPH + 0x8A53: 0x5961, //CJK UNIFIED IDEOGRAPH + 0x8A54: 0x5963, //CJK UNIFIED IDEOGRAPH + 0x8A55: 0x5964, //CJK UNIFIED IDEOGRAPH + 0x8A56: 0x5966, //CJK UNIFIED IDEOGRAPH + 0x8A57: 0x5967, //CJK UNIFIED IDEOGRAPH + 0x8A58: 0x5968, //CJK UNIFIED IDEOGRAPH + 0x8A59: 0x5969, //CJK UNIFIED IDEOGRAPH + 0x8A5A: 0x596A, //CJK UNIFIED IDEOGRAPH + 0x8A5B: 0x596B, //CJK UNIFIED IDEOGRAPH + 0x8A5C: 0x596C, //CJK UNIFIED IDEOGRAPH + 0x8A5D: 0x596D, //CJK UNIFIED IDEOGRAPH + 0x8A5E: 0x596E, //CJK UNIFIED IDEOGRAPH + 0x8A5F: 0x596F, //CJK UNIFIED IDEOGRAPH + 0x8A60: 0x5970, //CJK UNIFIED IDEOGRAPH + 0x8A61: 0x5971, //CJK UNIFIED IDEOGRAPH + 0x8A62: 0x5972, //CJK UNIFIED IDEOGRAPH + 0x8A63: 0x5975, //CJK UNIFIED IDEOGRAPH + 0x8A64: 0x5977, //CJK UNIFIED IDEOGRAPH + 0x8A65: 0x597A, //CJK UNIFIED IDEOGRAPH + 0x8A66: 0x597B, //CJK UNIFIED IDEOGRAPH + 0x8A67: 0x597C, //CJK UNIFIED IDEOGRAPH + 0x8A68: 0x597E, //CJK UNIFIED IDEOGRAPH + 0x8A69: 0x597F, //CJK UNIFIED IDEOGRAPH + 0x8A6A: 0x5980, //CJK UNIFIED IDEOGRAPH + 0x8A6B: 0x5985, //CJK UNIFIED IDEOGRAPH + 0x8A6C: 0x5989, //CJK UNIFIED IDEOGRAPH + 0x8A6D: 0x598B, //CJK UNIFIED IDEOGRAPH + 0x8A6E: 0x598C, //CJK UNIFIED IDEOGRAPH + 0x8A6F: 0x598E, //CJK UNIFIED IDEOGRAPH + 0x8A70: 0x598F, //CJK UNIFIED IDEOGRAPH + 0x8A71: 0x5990, //CJK UNIFIED IDEOGRAPH + 0x8A72: 0x5991, //CJK UNIFIED IDEOGRAPH + 0x8A73: 0x5994, //CJK UNIFIED IDEOGRAPH + 0x8A74: 0x5995, //CJK UNIFIED IDEOGRAPH + 0x8A75: 0x5998, //CJK UNIFIED IDEOGRAPH + 0x8A76: 0x599A, //CJK UNIFIED IDEOGRAPH + 0x8A77: 0x599B, //CJK UNIFIED IDEOGRAPH + 0x8A78: 0x599C, //CJK UNIFIED IDEOGRAPH + 0x8A79: 0x599D, //CJK UNIFIED IDEOGRAPH + 0x8A7A: 0x599F, //CJK UNIFIED IDEOGRAPH + 0x8A7B: 0x59A0, //CJK UNIFIED IDEOGRAPH + 0x8A7C: 0x59A1, //CJK UNIFIED IDEOGRAPH + 0x8A7D: 0x59A2, //CJK UNIFIED IDEOGRAPH + 0x8A7E: 0x59A6, //CJK UNIFIED IDEOGRAPH + 0x8A80: 0x59A7, //CJK UNIFIED IDEOGRAPH + 0x8A81: 0x59AC, //CJK UNIFIED IDEOGRAPH + 0x8A82: 0x59AD, //CJK UNIFIED IDEOGRAPH + 0x8A83: 0x59B0, //CJK UNIFIED IDEOGRAPH + 0x8A84: 0x59B1, //CJK UNIFIED IDEOGRAPH + 0x8A85: 0x59B3, //CJK UNIFIED IDEOGRAPH + 0x8A86: 0x59B4, //CJK UNIFIED IDEOGRAPH + 0x8A87: 0x59B5, //CJK UNIFIED IDEOGRAPH + 0x8A88: 0x59B6, //CJK UNIFIED IDEOGRAPH + 0x8A89: 0x59B7, //CJK UNIFIED IDEOGRAPH + 0x8A8A: 0x59B8, //CJK UNIFIED IDEOGRAPH + 0x8A8B: 0x59BA, //CJK UNIFIED IDEOGRAPH + 0x8A8C: 0x59BC, //CJK UNIFIED IDEOGRAPH + 0x8A8D: 0x59BD, //CJK UNIFIED IDEOGRAPH + 0x8A8E: 0x59BF, //CJK UNIFIED IDEOGRAPH + 0x8A8F: 0x59C0, //CJK UNIFIED IDEOGRAPH + 0x8A90: 0x59C1, //CJK UNIFIED IDEOGRAPH + 0x8A91: 0x59C2, //CJK UNIFIED IDEOGRAPH + 0x8A92: 0x59C3, //CJK UNIFIED IDEOGRAPH + 0x8A93: 0x59C4, //CJK UNIFIED IDEOGRAPH + 0x8A94: 0x59C5, //CJK UNIFIED IDEOGRAPH + 0x8A95: 0x59C7, //CJK UNIFIED IDEOGRAPH + 0x8A96: 0x59C8, //CJK UNIFIED IDEOGRAPH + 0x8A97: 0x59C9, //CJK UNIFIED IDEOGRAPH + 0x8A98: 0x59CC, //CJK UNIFIED IDEOGRAPH + 0x8A99: 0x59CD, //CJK UNIFIED IDEOGRAPH + 0x8A9A: 0x59CE, //CJK UNIFIED IDEOGRAPH + 0x8A9B: 0x59CF, //CJK UNIFIED IDEOGRAPH + 0x8A9C: 0x59D5, //CJK UNIFIED IDEOGRAPH + 0x8A9D: 0x59D6, //CJK UNIFIED IDEOGRAPH + 0x8A9E: 0x59D9, //CJK UNIFIED IDEOGRAPH + 0x8A9F: 0x59DB, //CJK UNIFIED IDEOGRAPH + 0x8AA0: 0x59DE, //CJK UNIFIED IDEOGRAPH + 0x8AA1: 0x59DF, //CJK UNIFIED IDEOGRAPH + 0x8AA2: 0x59E0, //CJK UNIFIED IDEOGRAPH + 0x8AA3: 0x59E1, //CJK UNIFIED IDEOGRAPH + 0x8AA4: 0x59E2, //CJK UNIFIED IDEOGRAPH + 0x8AA5: 0x59E4, //CJK UNIFIED IDEOGRAPH + 0x8AA6: 0x59E6, //CJK UNIFIED IDEOGRAPH + 0x8AA7: 0x59E7, //CJK UNIFIED IDEOGRAPH + 0x8AA8: 0x59E9, //CJK UNIFIED IDEOGRAPH + 0x8AA9: 0x59EA, //CJK UNIFIED IDEOGRAPH + 0x8AAA: 0x59EB, //CJK UNIFIED IDEOGRAPH + 0x8AAB: 0x59ED, //CJK UNIFIED IDEOGRAPH + 0x8AAC: 0x59EE, //CJK UNIFIED IDEOGRAPH + 0x8AAD: 0x59EF, //CJK UNIFIED IDEOGRAPH + 0x8AAE: 0x59F0, //CJK UNIFIED IDEOGRAPH + 0x8AAF: 0x59F1, //CJK UNIFIED IDEOGRAPH + 0x8AB0: 0x59F2, //CJK UNIFIED IDEOGRAPH + 0x8AB1: 0x59F3, //CJK UNIFIED IDEOGRAPH + 0x8AB2: 0x59F4, //CJK UNIFIED IDEOGRAPH + 0x8AB3: 0x59F5, //CJK UNIFIED IDEOGRAPH + 0x8AB4: 0x59F6, //CJK UNIFIED IDEOGRAPH + 0x8AB5: 0x59F7, //CJK UNIFIED IDEOGRAPH + 0x8AB6: 0x59F8, //CJK UNIFIED IDEOGRAPH + 0x8AB7: 0x59FA, //CJK UNIFIED IDEOGRAPH + 0x8AB8: 0x59FC, //CJK UNIFIED IDEOGRAPH + 0x8AB9: 0x59FD, //CJK UNIFIED IDEOGRAPH + 0x8ABA: 0x59FE, //CJK UNIFIED IDEOGRAPH + 0x8ABB: 0x5A00, //CJK UNIFIED IDEOGRAPH + 0x8ABC: 0x5A02, //CJK UNIFIED IDEOGRAPH + 0x8ABD: 0x5A0A, //CJK UNIFIED IDEOGRAPH + 0x8ABE: 0x5A0B, //CJK UNIFIED IDEOGRAPH + 0x8ABF: 0x5A0D, //CJK UNIFIED IDEOGRAPH + 0x8AC0: 0x5A0E, //CJK UNIFIED IDEOGRAPH + 0x8AC1: 0x5A0F, //CJK UNIFIED IDEOGRAPH + 0x8AC2: 0x5A10, //CJK UNIFIED IDEOGRAPH + 0x8AC3: 0x5A12, //CJK UNIFIED IDEOGRAPH + 0x8AC4: 0x5A14, //CJK UNIFIED IDEOGRAPH + 0x8AC5: 0x5A15, //CJK UNIFIED IDEOGRAPH + 0x8AC6: 0x5A16, //CJK UNIFIED IDEOGRAPH + 0x8AC7: 0x5A17, //CJK UNIFIED IDEOGRAPH + 0x8AC8: 0x5A19, //CJK UNIFIED IDEOGRAPH + 0x8AC9: 0x5A1A, //CJK UNIFIED IDEOGRAPH + 0x8ACA: 0x5A1B, //CJK UNIFIED IDEOGRAPH + 0x8ACB: 0x5A1D, //CJK UNIFIED IDEOGRAPH + 0x8ACC: 0x5A1E, //CJK UNIFIED IDEOGRAPH + 0x8ACD: 0x5A21, //CJK UNIFIED IDEOGRAPH + 0x8ACE: 0x5A22, //CJK UNIFIED IDEOGRAPH + 0x8ACF: 0x5A24, //CJK UNIFIED IDEOGRAPH + 0x8AD0: 0x5A26, //CJK UNIFIED IDEOGRAPH + 0x8AD1: 0x5A27, //CJK UNIFIED IDEOGRAPH + 0x8AD2: 0x5A28, //CJK UNIFIED IDEOGRAPH + 0x8AD3: 0x5A2A, //CJK UNIFIED IDEOGRAPH + 0x8AD4: 0x5A2B, //CJK UNIFIED IDEOGRAPH + 0x8AD5: 0x5A2C, //CJK UNIFIED IDEOGRAPH + 0x8AD6: 0x5A2D, //CJK UNIFIED IDEOGRAPH + 0x8AD7: 0x5A2E, //CJK UNIFIED IDEOGRAPH + 0x8AD8: 0x5A2F, //CJK UNIFIED IDEOGRAPH + 0x8AD9: 0x5A30, //CJK UNIFIED IDEOGRAPH + 0x8ADA: 0x5A33, //CJK UNIFIED IDEOGRAPH + 0x8ADB: 0x5A35, //CJK UNIFIED IDEOGRAPH + 0x8ADC: 0x5A37, //CJK UNIFIED IDEOGRAPH + 0x8ADD: 0x5A38, //CJK UNIFIED IDEOGRAPH + 0x8ADE: 0x5A39, //CJK UNIFIED IDEOGRAPH + 0x8ADF: 0x5A3A, //CJK UNIFIED IDEOGRAPH + 0x8AE0: 0x5A3B, //CJK UNIFIED IDEOGRAPH + 0x8AE1: 0x5A3D, //CJK UNIFIED IDEOGRAPH + 0x8AE2: 0x5A3E, //CJK UNIFIED IDEOGRAPH + 0x8AE3: 0x5A3F, //CJK UNIFIED IDEOGRAPH + 0x8AE4: 0x5A41, //CJK UNIFIED IDEOGRAPH + 0x8AE5: 0x5A42, //CJK UNIFIED IDEOGRAPH + 0x8AE6: 0x5A43, //CJK UNIFIED IDEOGRAPH + 0x8AE7: 0x5A44, //CJK UNIFIED IDEOGRAPH + 0x8AE8: 0x5A45, //CJK UNIFIED IDEOGRAPH + 0x8AE9: 0x5A47, //CJK UNIFIED IDEOGRAPH + 0x8AEA: 0x5A48, //CJK UNIFIED IDEOGRAPH + 0x8AEB: 0x5A4B, //CJK UNIFIED IDEOGRAPH + 0x8AEC: 0x5A4C, //CJK UNIFIED IDEOGRAPH + 0x8AED: 0x5A4D, //CJK UNIFIED IDEOGRAPH + 0x8AEE: 0x5A4E, //CJK UNIFIED IDEOGRAPH + 0x8AEF: 0x5A4F, //CJK UNIFIED IDEOGRAPH + 0x8AF0: 0x5A50, //CJK UNIFIED IDEOGRAPH + 0x8AF1: 0x5A51, //CJK UNIFIED IDEOGRAPH + 0x8AF2: 0x5A52, //CJK UNIFIED IDEOGRAPH + 0x8AF3: 0x5A53, //CJK UNIFIED IDEOGRAPH + 0x8AF4: 0x5A54, //CJK UNIFIED IDEOGRAPH + 0x8AF5: 0x5A56, //CJK UNIFIED IDEOGRAPH + 0x8AF6: 0x5A57, //CJK UNIFIED IDEOGRAPH + 0x8AF7: 0x5A58, //CJK UNIFIED IDEOGRAPH + 0x8AF8: 0x5A59, //CJK UNIFIED IDEOGRAPH + 0x8AF9: 0x5A5B, //CJK UNIFIED IDEOGRAPH + 0x8AFA: 0x5A5C, //CJK UNIFIED IDEOGRAPH + 0x8AFB: 0x5A5D, //CJK UNIFIED IDEOGRAPH + 0x8AFC: 0x5A5E, //CJK UNIFIED IDEOGRAPH + 0x8AFD: 0x5A5F, //CJK UNIFIED IDEOGRAPH + 0x8AFE: 0x5A60, //CJK UNIFIED IDEOGRAPH + 0x8B40: 0x5A61, //CJK UNIFIED IDEOGRAPH + 0x8B41: 0x5A63, //CJK UNIFIED IDEOGRAPH + 0x8B42: 0x5A64, //CJK UNIFIED IDEOGRAPH + 0x8B43: 0x5A65, //CJK UNIFIED IDEOGRAPH + 0x8B44: 0x5A66, //CJK UNIFIED IDEOGRAPH + 0x8B45: 0x5A68, //CJK UNIFIED IDEOGRAPH + 0x8B46: 0x5A69, //CJK UNIFIED IDEOGRAPH + 0x8B47: 0x5A6B, //CJK UNIFIED IDEOGRAPH + 0x8B48: 0x5A6C, //CJK UNIFIED IDEOGRAPH + 0x8B49: 0x5A6D, //CJK UNIFIED IDEOGRAPH + 0x8B4A: 0x5A6E, //CJK UNIFIED IDEOGRAPH + 0x8B4B: 0x5A6F, //CJK UNIFIED IDEOGRAPH + 0x8B4C: 0x5A70, //CJK UNIFIED IDEOGRAPH + 0x8B4D: 0x5A71, //CJK UNIFIED IDEOGRAPH + 0x8B4E: 0x5A72, //CJK UNIFIED IDEOGRAPH + 0x8B4F: 0x5A73, //CJK UNIFIED IDEOGRAPH + 0x8B50: 0x5A78, //CJK UNIFIED IDEOGRAPH + 0x8B51: 0x5A79, //CJK UNIFIED IDEOGRAPH + 0x8B52: 0x5A7B, //CJK UNIFIED IDEOGRAPH + 0x8B53: 0x5A7C, //CJK UNIFIED IDEOGRAPH + 0x8B54: 0x5A7D, //CJK UNIFIED IDEOGRAPH + 0x8B55: 0x5A7E, //CJK UNIFIED IDEOGRAPH + 0x8B56: 0x5A80, //CJK UNIFIED IDEOGRAPH + 0x8B57: 0x5A81, //CJK UNIFIED IDEOGRAPH + 0x8B58: 0x5A82, //CJK UNIFIED IDEOGRAPH + 0x8B59: 0x5A83, //CJK UNIFIED IDEOGRAPH + 0x8B5A: 0x5A84, //CJK UNIFIED IDEOGRAPH + 0x8B5B: 0x5A85, //CJK UNIFIED IDEOGRAPH + 0x8B5C: 0x5A86, //CJK UNIFIED IDEOGRAPH + 0x8B5D: 0x5A87, //CJK UNIFIED IDEOGRAPH + 0x8B5E: 0x5A88, //CJK UNIFIED IDEOGRAPH + 0x8B5F: 0x5A89, //CJK UNIFIED IDEOGRAPH + 0x8B60: 0x5A8A, //CJK UNIFIED IDEOGRAPH + 0x8B61: 0x5A8B, //CJK UNIFIED IDEOGRAPH + 0x8B62: 0x5A8C, //CJK UNIFIED IDEOGRAPH + 0x8B63: 0x5A8D, //CJK UNIFIED IDEOGRAPH + 0x8B64: 0x5A8E, //CJK UNIFIED IDEOGRAPH + 0x8B65: 0x5A8F, //CJK UNIFIED IDEOGRAPH + 0x8B66: 0x5A90, //CJK UNIFIED IDEOGRAPH + 0x8B67: 0x5A91, //CJK UNIFIED IDEOGRAPH + 0x8B68: 0x5A93, //CJK UNIFIED IDEOGRAPH + 0x8B69: 0x5A94, //CJK UNIFIED IDEOGRAPH + 0x8B6A: 0x5A95, //CJK UNIFIED IDEOGRAPH + 0x8B6B: 0x5A96, //CJK UNIFIED IDEOGRAPH + 0x8B6C: 0x5A97, //CJK UNIFIED IDEOGRAPH + 0x8B6D: 0x5A98, //CJK UNIFIED IDEOGRAPH + 0x8B6E: 0x5A99, //CJK UNIFIED IDEOGRAPH + 0x8B6F: 0x5A9C, //CJK UNIFIED IDEOGRAPH + 0x8B70: 0x5A9D, //CJK UNIFIED IDEOGRAPH + 0x8B71: 0x5A9E, //CJK UNIFIED IDEOGRAPH + 0x8B72: 0x5A9F, //CJK UNIFIED IDEOGRAPH + 0x8B73: 0x5AA0, //CJK UNIFIED IDEOGRAPH + 0x8B74: 0x5AA1, //CJK UNIFIED IDEOGRAPH + 0x8B75: 0x5AA2, //CJK UNIFIED IDEOGRAPH + 0x8B76: 0x5AA3, //CJK UNIFIED IDEOGRAPH + 0x8B77: 0x5AA4, //CJK UNIFIED IDEOGRAPH + 0x8B78: 0x5AA5, //CJK UNIFIED IDEOGRAPH + 0x8B79: 0x5AA6, //CJK UNIFIED IDEOGRAPH + 0x8B7A: 0x5AA7, //CJK UNIFIED IDEOGRAPH + 0x8B7B: 0x5AA8, //CJK UNIFIED IDEOGRAPH + 0x8B7C: 0x5AA9, //CJK UNIFIED IDEOGRAPH + 0x8B7D: 0x5AAB, //CJK UNIFIED IDEOGRAPH + 0x8B7E: 0x5AAC, //CJK UNIFIED IDEOGRAPH + 0x8B80: 0x5AAD, //CJK UNIFIED IDEOGRAPH + 0x8B81: 0x5AAE, //CJK UNIFIED IDEOGRAPH + 0x8B82: 0x5AAF, //CJK UNIFIED IDEOGRAPH + 0x8B83: 0x5AB0, //CJK UNIFIED IDEOGRAPH + 0x8B84: 0x5AB1, //CJK UNIFIED IDEOGRAPH + 0x8B85: 0x5AB4, //CJK UNIFIED IDEOGRAPH + 0x8B86: 0x5AB6, //CJK UNIFIED IDEOGRAPH + 0x8B87: 0x5AB7, //CJK UNIFIED IDEOGRAPH + 0x8B88: 0x5AB9, //CJK UNIFIED IDEOGRAPH + 0x8B89: 0x5ABA, //CJK UNIFIED IDEOGRAPH + 0x8B8A: 0x5ABB, //CJK UNIFIED IDEOGRAPH + 0x8B8B: 0x5ABC, //CJK UNIFIED IDEOGRAPH + 0x8B8C: 0x5ABD, //CJK UNIFIED IDEOGRAPH + 0x8B8D: 0x5ABF, //CJK UNIFIED IDEOGRAPH + 0x8B8E: 0x5AC0, //CJK UNIFIED IDEOGRAPH + 0x8B8F: 0x5AC3, //CJK UNIFIED IDEOGRAPH + 0x8B90: 0x5AC4, //CJK UNIFIED IDEOGRAPH + 0x8B91: 0x5AC5, //CJK UNIFIED IDEOGRAPH + 0x8B92: 0x5AC6, //CJK UNIFIED IDEOGRAPH + 0x8B93: 0x5AC7, //CJK UNIFIED IDEOGRAPH + 0x8B94: 0x5AC8, //CJK UNIFIED IDEOGRAPH + 0x8B95: 0x5ACA, //CJK UNIFIED IDEOGRAPH + 0x8B96: 0x5ACB, //CJK UNIFIED IDEOGRAPH + 0x8B97: 0x5ACD, //CJK UNIFIED IDEOGRAPH + 0x8B98: 0x5ACE, //CJK UNIFIED IDEOGRAPH + 0x8B99: 0x5ACF, //CJK UNIFIED IDEOGRAPH + 0x8B9A: 0x5AD0, //CJK UNIFIED IDEOGRAPH + 0x8B9B: 0x5AD1, //CJK UNIFIED IDEOGRAPH + 0x8B9C: 0x5AD3, //CJK UNIFIED IDEOGRAPH + 0x8B9D: 0x5AD5, //CJK UNIFIED IDEOGRAPH + 0x8B9E: 0x5AD7, //CJK UNIFIED IDEOGRAPH + 0x8B9F: 0x5AD9, //CJK UNIFIED IDEOGRAPH + 0x8BA0: 0x5ADA, //CJK UNIFIED IDEOGRAPH + 0x8BA1: 0x5ADB, //CJK UNIFIED IDEOGRAPH + 0x8BA2: 0x5ADD, //CJK UNIFIED IDEOGRAPH + 0x8BA3: 0x5ADE, //CJK UNIFIED IDEOGRAPH + 0x8BA4: 0x5ADF, //CJK UNIFIED IDEOGRAPH + 0x8BA5: 0x5AE2, //CJK UNIFIED IDEOGRAPH + 0x8BA6: 0x5AE4, //CJK UNIFIED IDEOGRAPH + 0x8BA7: 0x5AE5, //CJK UNIFIED IDEOGRAPH + 0x8BA8: 0x5AE7, //CJK UNIFIED IDEOGRAPH + 0x8BA9: 0x5AE8, //CJK UNIFIED IDEOGRAPH + 0x8BAA: 0x5AEA, //CJK UNIFIED IDEOGRAPH + 0x8BAB: 0x5AEC, //CJK UNIFIED IDEOGRAPH + 0x8BAC: 0x5AED, //CJK UNIFIED IDEOGRAPH + 0x8BAD: 0x5AEE, //CJK UNIFIED IDEOGRAPH + 0x8BAE: 0x5AEF, //CJK UNIFIED IDEOGRAPH + 0x8BAF: 0x5AF0, //CJK UNIFIED IDEOGRAPH + 0x8BB0: 0x5AF2, //CJK UNIFIED IDEOGRAPH + 0x8BB1: 0x5AF3, //CJK UNIFIED IDEOGRAPH + 0x8BB2: 0x5AF4, //CJK UNIFIED IDEOGRAPH + 0x8BB3: 0x5AF5, //CJK UNIFIED IDEOGRAPH + 0x8BB4: 0x5AF6, //CJK UNIFIED IDEOGRAPH + 0x8BB5: 0x5AF7, //CJK UNIFIED IDEOGRAPH + 0x8BB6: 0x5AF8, //CJK UNIFIED IDEOGRAPH + 0x8BB7: 0x5AF9, //CJK UNIFIED IDEOGRAPH + 0x8BB8: 0x5AFA, //CJK UNIFIED IDEOGRAPH + 0x8BB9: 0x5AFB, //CJK UNIFIED IDEOGRAPH + 0x8BBA: 0x5AFC, //CJK UNIFIED IDEOGRAPH + 0x8BBB: 0x5AFD, //CJK UNIFIED IDEOGRAPH + 0x8BBC: 0x5AFE, //CJK UNIFIED IDEOGRAPH + 0x8BBD: 0x5AFF, //CJK UNIFIED IDEOGRAPH + 0x8BBE: 0x5B00, //CJK UNIFIED IDEOGRAPH + 0x8BBF: 0x5B01, //CJK UNIFIED IDEOGRAPH + 0x8BC0: 0x5B02, //CJK UNIFIED IDEOGRAPH + 0x8BC1: 0x5B03, //CJK UNIFIED IDEOGRAPH + 0x8BC2: 0x5B04, //CJK UNIFIED IDEOGRAPH + 0x8BC3: 0x5B05, //CJK UNIFIED IDEOGRAPH + 0x8BC4: 0x5B06, //CJK UNIFIED IDEOGRAPH + 0x8BC5: 0x5B07, //CJK UNIFIED IDEOGRAPH + 0x8BC6: 0x5B08, //CJK UNIFIED IDEOGRAPH + 0x8BC7: 0x5B0A, //CJK UNIFIED IDEOGRAPH + 0x8BC8: 0x5B0B, //CJK UNIFIED IDEOGRAPH + 0x8BC9: 0x5B0C, //CJK UNIFIED IDEOGRAPH + 0x8BCA: 0x5B0D, //CJK UNIFIED IDEOGRAPH + 0x8BCB: 0x5B0E, //CJK UNIFIED IDEOGRAPH + 0x8BCC: 0x5B0F, //CJK UNIFIED IDEOGRAPH + 0x8BCD: 0x5B10, //CJK UNIFIED IDEOGRAPH + 0x8BCE: 0x5B11, //CJK UNIFIED IDEOGRAPH + 0x8BCF: 0x5B12, //CJK UNIFIED IDEOGRAPH + 0x8BD0: 0x5B13, //CJK UNIFIED IDEOGRAPH + 0x8BD1: 0x5B14, //CJK UNIFIED IDEOGRAPH + 0x8BD2: 0x5B15, //CJK UNIFIED IDEOGRAPH + 0x8BD3: 0x5B18, //CJK UNIFIED IDEOGRAPH + 0x8BD4: 0x5B19, //CJK UNIFIED IDEOGRAPH + 0x8BD5: 0x5B1A, //CJK UNIFIED IDEOGRAPH + 0x8BD6: 0x5B1B, //CJK UNIFIED IDEOGRAPH + 0x8BD7: 0x5B1C, //CJK UNIFIED IDEOGRAPH + 0x8BD8: 0x5B1D, //CJK UNIFIED IDEOGRAPH + 0x8BD9: 0x5B1E, //CJK UNIFIED IDEOGRAPH + 0x8BDA: 0x5B1F, //CJK UNIFIED IDEOGRAPH + 0x8BDB: 0x5B20, //CJK UNIFIED IDEOGRAPH + 0x8BDC: 0x5B21, //CJK UNIFIED IDEOGRAPH + 0x8BDD: 0x5B22, //CJK UNIFIED IDEOGRAPH + 0x8BDE: 0x5B23, //CJK UNIFIED IDEOGRAPH + 0x8BDF: 0x5B24, //CJK UNIFIED IDEOGRAPH + 0x8BE0: 0x5B25, //CJK UNIFIED IDEOGRAPH + 0x8BE1: 0x5B26, //CJK UNIFIED IDEOGRAPH + 0x8BE2: 0x5B27, //CJK UNIFIED IDEOGRAPH + 0x8BE3: 0x5B28, //CJK UNIFIED IDEOGRAPH + 0x8BE4: 0x5B29, //CJK UNIFIED IDEOGRAPH + 0x8BE5: 0x5B2A, //CJK UNIFIED IDEOGRAPH + 0x8BE6: 0x5B2B, //CJK UNIFIED IDEOGRAPH + 0x8BE7: 0x5B2C, //CJK UNIFIED IDEOGRAPH + 0x8BE8: 0x5B2D, //CJK UNIFIED IDEOGRAPH + 0x8BE9: 0x5B2E, //CJK UNIFIED IDEOGRAPH + 0x8BEA: 0x5B2F, //CJK UNIFIED IDEOGRAPH + 0x8BEB: 0x5B30, //CJK UNIFIED IDEOGRAPH + 0x8BEC: 0x5B31, //CJK UNIFIED IDEOGRAPH + 0x8BED: 0x5B33, //CJK UNIFIED IDEOGRAPH + 0x8BEE: 0x5B35, //CJK UNIFIED IDEOGRAPH + 0x8BEF: 0x5B36, //CJK UNIFIED IDEOGRAPH + 0x8BF0: 0x5B38, //CJK UNIFIED IDEOGRAPH + 0x8BF1: 0x5B39, //CJK UNIFIED IDEOGRAPH + 0x8BF2: 0x5B3A, //CJK UNIFIED IDEOGRAPH + 0x8BF3: 0x5B3B, //CJK UNIFIED IDEOGRAPH + 0x8BF4: 0x5B3C, //CJK UNIFIED IDEOGRAPH + 0x8BF5: 0x5B3D, //CJK UNIFIED IDEOGRAPH + 0x8BF6: 0x5B3E, //CJK UNIFIED IDEOGRAPH + 0x8BF7: 0x5B3F, //CJK UNIFIED IDEOGRAPH + 0x8BF8: 0x5B41, //CJK UNIFIED IDEOGRAPH + 0x8BF9: 0x5B42, //CJK UNIFIED IDEOGRAPH + 0x8BFA: 0x5B43, //CJK UNIFIED IDEOGRAPH + 0x8BFB: 0x5B44, //CJK UNIFIED IDEOGRAPH + 0x8BFC: 0x5B45, //CJK UNIFIED IDEOGRAPH + 0x8BFD: 0x5B46, //CJK UNIFIED IDEOGRAPH + 0x8BFE: 0x5B47, //CJK UNIFIED IDEOGRAPH + 0x8C40: 0x5B48, //CJK UNIFIED IDEOGRAPH + 0x8C41: 0x5B49, //CJK UNIFIED IDEOGRAPH + 0x8C42: 0x5B4A, //CJK UNIFIED IDEOGRAPH + 0x8C43: 0x5B4B, //CJK UNIFIED IDEOGRAPH + 0x8C44: 0x5B4C, //CJK UNIFIED IDEOGRAPH + 0x8C45: 0x5B4D, //CJK UNIFIED IDEOGRAPH + 0x8C46: 0x5B4E, //CJK UNIFIED IDEOGRAPH + 0x8C47: 0x5B4F, //CJK UNIFIED IDEOGRAPH + 0x8C48: 0x5B52, //CJK UNIFIED IDEOGRAPH + 0x8C49: 0x5B56, //CJK UNIFIED IDEOGRAPH + 0x8C4A: 0x5B5E, //CJK UNIFIED IDEOGRAPH + 0x8C4B: 0x5B60, //CJK UNIFIED IDEOGRAPH + 0x8C4C: 0x5B61, //CJK UNIFIED IDEOGRAPH + 0x8C4D: 0x5B67, //CJK UNIFIED IDEOGRAPH + 0x8C4E: 0x5B68, //CJK UNIFIED IDEOGRAPH + 0x8C4F: 0x5B6B, //CJK UNIFIED IDEOGRAPH + 0x8C50: 0x5B6D, //CJK UNIFIED IDEOGRAPH + 0x8C51: 0x5B6E, //CJK UNIFIED IDEOGRAPH + 0x8C52: 0x5B6F, //CJK UNIFIED IDEOGRAPH + 0x8C53: 0x5B72, //CJK UNIFIED IDEOGRAPH + 0x8C54: 0x5B74, //CJK UNIFIED IDEOGRAPH + 0x8C55: 0x5B76, //CJK UNIFIED IDEOGRAPH + 0x8C56: 0x5B77, //CJK UNIFIED IDEOGRAPH + 0x8C57: 0x5B78, //CJK UNIFIED IDEOGRAPH + 0x8C58: 0x5B79, //CJK UNIFIED IDEOGRAPH + 0x8C59: 0x5B7B, //CJK UNIFIED IDEOGRAPH + 0x8C5A: 0x5B7C, //CJK UNIFIED IDEOGRAPH + 0x8C5B: 0x5B7E, //CJK UNIFIED IDEOGRAPH + 0x8C5C: 0x5B7F, //CJK UNIFIED IDEOGRAPH + 0x8C5D: 0x5B82, //CJK UNIFIED IDEOGRAPH + 0x8C5E: 0x5B86, //CJK UNIFIED IDEOGRAPH + 0x8C5F: 0x5B8A, //CJK UNIFIED IDEOGRAPH + 0x8C60: 0x5B8D, //CJK UNIFIED IDEOGRAPH + 0x8C61: 0x5B8E, //CJK UNIFIED IDEOGRAPH + 0x8C62: 0x5B90, //CJK UNIFIED IDEOGRAPH + 0x8C63: 0x5B91, //CJK UNIFIED IDEOGRAPH + 0x8C64: 0x5B92, //CJK UNIFIED IDEOGRAPH + 0x8C65: 0x5B94, //CJK UNIFIED IDEOGRAPH + 0x8C66: 0x5B96, //CJK UNIFIED IDEOGRAPH + 0x8C67: 0x5B9F, //CJK UNIFIED IDEOGRAPH + 0x8C68: 0x5BA7, //CJK UNIFIED IDEOGRAPH + 0x8C69: 0x5BA8, //CJK UNIFIED IDEOGRAPH + 0x8C6A: 0x5BA9, //CJK UNIFIED IDEOGRAPH + 0x8C6B: 0x5BAC, //CJK UNIFIED IDEOGRAPH + 0x8C6C: 0x5BAD, //CJK UNIFIED IDEOGRAPH + 0x8C6D: 0x5BAE, //CJK UNIFIED IDEOGRAPH + 0x8C6E: 0x5BAF, //CJK UNIFIED IDEOGRAPH + 0x8C6F: 0x5BB1, //CJK UNIFIED IDEOGRAPH + 0x8C70: 0x5BB2, //CJK UNIFIED IDEOGRAPH + 0x8C71: 0x5BB7, //CJK UNIFIED IDEOGRAPH + 0x8C72: 0x5BBA, //CJK UNIFIED IDEOGRAPH + 0x8C73: 0x5BBB, //CJK UNIFIED IDEOGRAPH + 0x8C74: 0x5BBC, //CJK UNIFIED IDEOGRAPH + 0x8C75: 0x5BC0, //CJK UNIFIED IDEOGRAPH + 0x8C76: 0x5BC1, //CJK UNIFIED IDEOGRAPH + 0x8C77: 0x5BC3, //CJK UNIFIED IDEOGRAPH + 0x8C78: 0x5BC8, //CJK UNIFIED IDEOGRAPH + 0x8C79: 0x5BC9, //CJK UNIFIED IDEOGRAPH + 0x8C7A: 0x5BCA, //CJK UNIFIED IDEOGRAPH + 0x8C7B: 0x5BCB, //CJK UNIFIED IDEOGRAPH + 0x8C7C: 0x5BCD, //CJK UNIFIED IDEOGRAPH + 0x8C7D: 0x5BCE, //CJK UNIFIED IDEOGRAPH + 0x8C7E: 0x5BCF, //CJK UNIFIED IDEOGRAPH + 0x8C80: 0x5BD1, //CJK UNIFIED IDEOGRAPH + 0x8C81: 0x5BD4, //CJK UNIFIED IDEOGRAPH + 0x8C82: 0x5BD5, //CJK UNIFIED IDEOGRAPH + 0x8C83: 0x5BD6, //CJK UNIFIED IDEOGRAPH + 0x8C84: 0x5BD7, //CJK UNIFIED IDEOGRAPH + 0x8C85: 0x5BD8, //CJK UNIFIED IDEOGRAPH + 0x8C86: 0x5BD9, //CJK UNIFIED IDEOGRAPH + 0x8C87: 0x5BDA, //CJK UNIFIED IDEOGRAPH + 0x8C88: 0x5BDB, //CJK UNIFIED IDEOGRAPH + 0x8C89: 0x5BDC, //CJK UNIFIED IDEOGRAPH + 0x8C8A: 0x5BE0, //CJK UNIFIED IDEOGRAPH + 0x8C8B: 0x5BE2, //CJK UNIFIED IDEOGRAPH + 0x8C8C: 0x5BE3, //CJK UNIFIED IDEOGRAPH + 0x8C8D: 0x5BE6, //CJK UNIFIED IDEOGRAPH + 0x8C8E: 0x5BE7, //CJK UNIFIED IDEOGRAPH + 0x8C8F: 0x5BE9, //CJK UNIFIED IDEOGRAPH + 0x8C90: 0x5BEA, //CJK UNIFIED IDEOGRAPH + 0x8C91: 0x5BEB, //CJK UNIFIED IDEOGRAPH + 0x8C92: 0x5BEC, //CJK UNIFIED IDEOGRAPH + 0x8C93: 0x5BED, //CJK UNIFIED IDEOGRAPH + 0x8C94: 0x5BEF, //CJK UNIFIED IDEOGRAPH + 0x8C95: 0x5BF1, //CJK UNIFIED IDEOGRAPH + 0x8C96: 0x5BF2, //CJK UNIFIED IDEOGRAPH + 0x8C97: 0x5BF3, //CJK UNIFIED IDEOGRAPH + 0x8C98: 0x5BF4, //CJK UNIFIED IDEOGRAPH + 0x8C99: 0x5BF5, //CJK UNIFIED IDEOGRAPH + 0x8C9A: 0x5BF6, //CJK UNIFIED IDEOGRAPH + 0x8C9B: 0x5BF7, //CJK UNIFIED IDEOGRAPH + 0x8C9C: 0x5BFD, //CJK UNIFIED IDEOGRAPH + 0x8C9D: 0x5BFE, //CJK UNIFIED IDEOGRAPH + 0x8C9E: 0x5C00, //CJK UNIFIED IDEOGRAPH + 0x8C9F: 0x5C02, //CJK UNIFIED IDEOGRAPH + 0x8CA0: 0x5C03, //CJK UNIFIED IDEOGRAPH + 0x8CA1: 0x5C05, //CJK UNIFIED IDEOGRAPH + 0x8CA2: 0x5C07, //CJK UNIFIED IDEOGRAPH + 0x8CA3: 0x5C08, //CJK UNIFIED IDEOGRAPH + 0x8CA4: 0x5C0B, //CJK UNIFIED IDEOGRAPH + 0x8CA5: 0x5C0C, //CJK UNIFIED IDEOGRAPH + 0x8CA6: 0x5C0D, //CJK UNIFIED IDEOGRAPH + 0x8CA7: 0x5C0E, //CJK UNIFIED IDEOGRAPH + 0x8CA8: 0x5C10, //CJK UNIFIED IDEOGRAPH + 0x8CA9: 0x5C12, //CJK UNIFIED IDEOGRAPH + 0x8CAA: 0x5C13, //CJK UNIFIED IDEOGRAPH + 0x8CAB: 0x5C17, //CJK UNIFIED IDEOGRAPH + 0x8CAC: 0x5C19, //CJK UNIFIED IDEOGRAPH + 0x8CAD: 0x5C1B, //CJK UNIFIED IDEOGRAPH + 0x8CAE: 0x5C1E, //CJK UNIFIED IDEOGRAPH + 0x8CAF: 0x5C1F, //CJK UNIFIED IDEOGRAPH + 0x8CB0: 0x5C20, //CJK UNIFIED IDEOGRAPH + 0x8CB1: 0x5C21, //CJK UNIFIED IDEOGRAPH + 0x8CB2: 0x5C23, //CJK UNIFIED IDEOGRAPH + 0x8CB3: 0x5C26, //CJK UNIFIED IDEOGRAPH + 0x8CB4: 0x5C28, //CJK UNIFIED IDEOGRAPH + 0x8CB5: 0x5C29, //CJK UNIFIED IDEOGRAPH + 0x8CB6: 0x5C2A, //CJK UNIFIED IDEOGRAPH + 0x8CB7: 0x5C2B, //CJK UNIFIED IDEOGRAPH + 0x8CB8: 0x5C2D, //CJK UNIFIED IDEOGRAPH + 0x8CB9: 0x5C2E, //CJK UNIFIED IDEOGRAPH + 0x8CBA: 0x5C2F, //CJK UNIFIED IDEOGRAPH + 0x8CBB: 0x5C30, //CJK UNIFIED IDEOGRAPH + 0x8CBC: 0x5C32, //CJK UNIFIED IDEOGRAPH + 0x8CBD: 0x5C33, //CJK UNIFIED IDEOGRAPH + 0x8CBE: 0x5C35, //CJK UNIFIED IDEOGRAPH + 0x8CBF: 0x5C36, //CJK UNIFIED IDEOGRAPH + 0x8CC0: 0x5C37, //CJK UNIFIED IDEOGRAPH + 0x8CC1: 0x5C43, //CJK UNIFIED IDEOGRAPH + 0x8CC2: 0x5C44, //CJK UNIFIED IDEOGRAPH + 0x8CC3: 0x5C46, //CJK UNIFIED IDEOGRAPH + 0x8CC4: 0x5C47, //CJK UNIFIED IDEOGRAPH + 0x8CC5: 0x5C4C, //CJK UNIFIED IDEOGRAPH + 0x8CC6: 0x5C4D, //CJK UNIFIED IDEOGRAPH + 0x8CC7: 0x5C52, //CJK UNIFIED IDEOGRAPH + 0x8CC8: 0x5C53, //CJK UNIFIED IDEOGRAPH + 0x8CC9: 0x5C54, //CJK UNIFIED IDEOGRAPH + 0x8CCA: 0x5C56, //CJK UNIFIED IDEOGRAPH + 0x8CCB: 0x5C57, //CJK UNIFIED IDEOGRAPH + 0x8CCC: 0x5C58, //CJK UNIFIED IDEOGRAPH + 0x8CCD: 0x5C5A, //CJK UNIFIED IDEOGRAPH + 0x8CCE: 0x5C5B, //CJK UNIFIED IDEOGRAPH + 0x8CCF: 0x5C5C, //CJK UNIFIED IDEOGRAPH + 0x8CD0: 0x5C5D, //CJK UNIFIED IDEOGRAPH + 0x8CD1: 0x5C5F, //CJK UNIFIED IDEOGRAPH + 0x8CD2: 0x5C62, //CJK UNIFIED IDEOGRAPH + 0x8CD3: 0x5C64, //CJK UNIFIED IDEOGRAPH + 0x8CD4: 0x5C67, //CJK UNIFIED IDEOGRAPH + 0x8CD5: 0x5C68, //CJK UNIFIED IDEOGRAPH + 0x8CD6: 0x5C69, //CJK UNIFIED IDEOGRAPH + 0x8CD7: 0x5C6A, //CJK UNIFIED IDEOGRAPH + 0x8CD8: 0x5C6B, //CJK UNIFIED IDEOGRAPH + 0x8CD9: 0x5C6C, //CJK UNIFIED IDEOGRAPH + 0x8CDA: 0x5C6D, //CJK UNIFIED IDEOGRAPH + 0x8CDB: 0x5C70, //CJK UNIFIED IDEOGRAPH + 0x8CDC: 0x5C72, //CJK UNIFIED IDEOGRAPH + 0x8CDD: 0x5C73, //CJK UNIFIED IDEOGRAPH + 0x8CDE: 0x5C74, //CJK UNIFIED IDEOGRAPH + 0x8CDF: 0x5C75, //CJK UNIFIED IDEOGRAPH + 0x8CE0: 0x5C76, //CJK UNIFIED IDEOGRAPH + 0x8CE1: 0x5C77, //CJK UNIFIED IDEOGRAPH + 0x8CE2: 0x5C78, //CJK UNIFIED IDEOGRAPH + 0x8CE3: 0x5C7B, //CJK UNIFIED IDEOGRAPH + 0x8CE4: 0x5C7C, //CJK UNIFIED IDEOGRAPH + 0x8CE5: 0x5C7D, //CJK UNIFIED IDEOGRAPH + 0x8CE6: 0x5C7E, //CJK UNIFIED IDEOGRAPH + 0x8CE7: 0x5C80, //CJK UNIFIED IDEOGRAPH + 0x8CE8: 0x5C83, //CJK UNIFIED IDEOGRAPH + 0x8CE9: 0x5C84, //CJK UNIFIED IDEOGRAPH + 0x8CEA: 0x5C85, //CJK UNIFIED IDEOGRAPH + 0x8CEB: 0x5C86, //CJK UNIFIED IDEOGRAPH + 0x8CEC: 0x5C87, //CJK UNIFIED IDEOGRAPH + 0x8CED: 0x5C89, //CJK UNIFIED IDEOGRAPH + 0x8CEE: 0x5C8A, //CJK UNIFIED IDEOGRAPH + 0x8CEF: 0x5C8B, //CJK UNIFIED IDEOGRAPH + 0x8CF0: 0x5C8E, //CJK UNIFIED IDEOGRAPH + 0x8CF1: 0x5C8F, //CJK UNIFIED IDEOGRAPH + 0x8CF2: 0x5C92, //CJK UNIFIED IDEOGRAPH + 0x8CF3: 0x5C93, //CJK UNIFIED IDEOGRAPH + 0x8CF4: 0x5C95, //CJK UNIFIED IDEOGRAPH + 0x8CF5: 0x5C9D, //CJK UNIFIED IDEOGRAPH + 0x8CF6: 0x5C9E, //CJK UNIFIED IDEOGRAPH + 0x8CF7: 0x5C9F, //CJK UNIFIED IDEOGRAPH + 0x8CF8: 0x5CA0, //CJK UNIFIED IDEOGRAPH + 0x8CF9: 0x5CA1, //CJK UNIFIED IDEOGRAPH + 0x8CFA: 0x5CA4, //CJK UNIFIED IDEOGRAPH + 0x8CFB: 0x5CA5, //CJK UNIFIED IDEOGRAPH + 0x8CFC: 0x5CA6, //CJK UNIFIED IDEOGRAPH + 0x8CFD: 0x5CA7, //CJK UNIFIED IDEOGRAPH + 0x8CFE: 0x5CA8, //CJK UNIFIED IDEOGRAPH + 0x8D40: 0x5CAA, //CJK UNIFIED IDEOGRAPH + 0x8D41: 0x5CAE, //CJK UNIFIED IDEOGRAPH + 0x8D42: 0x5CAF, //CJK UNIFIED IDEOGRAPH + 0x8D43: 0x5CB0, //CJK UNIFIED IDEOGRAPH + 0x8D44: 0x5CB2, //CJK UNIFIED IDEOGRAPH + 0x8D45: 0x5CB4, //CJK UNIFIED IDEOGRAPH + 0x8D46: 0x5CB6, //CJK UNIFIED IDEOGRAPH + 0x8D47: 0x5CB9, //CJK UNIFIED IDEOGRAPH + 0x8D48: 0x5CBA, //CJK UNIFIED IDEOGRAPH + 0x8D49: 0x5CBB, //CJK UNIFIED IDEOGRAPH + 0x8D4A: 0x5CBC, //CJK UNIFIED IDEOGRAPH + 0x8D4B: 0x5CBE, //CJK UNIFIED IDEOGRAPH + 0x8D4C: 0x5CC0, //CJK UNIFIED IDEOGRAPH + 0x8D4D: 0x5CC2, //CJK UNIFIED IDEOGRAPH + 0x8D4E: 0x5CC3, //CJK UNIFIED IDEOGRAPH + 0x8D4F: 0x5CC5, //CJK UNIFIED IDEOGRAPH + 0x8D50: 0x5CC6, //CJK UNIFIED IDEOGRAPH + 0x8D51: 0x5CC7, //CJK UNIFIED IDEOGRAPH + 0x8D52: 0x5CC8, //CJK UNIFIED IDEOGRAPH + 0x8D53: 0x5CC9, //CJK UNIFIED IDEOGRAPH + 0x8D54: 0x5CCA, //CJK UNIFIED IDEOGRAPH + 0x8D55: 0x5CCC, //CJK UNIFIED IDEOGRAPH + 0x8D56: 0x5CCD, //CJK UNIFIED IDEOGRAPH + 0x8D57: 0x5CCE, //CJK UNIFIED IDEOGRAPH + 0x8D58: 0x5CCF, //CJK UNIFIED IDEOGRAPH + 0x8D59: 0x5CD0, //CJK UNIFIED IDEOGRAPH + 0x8D5A: 0x5CD1, //CJK UNIFIED IDEOGRAPH + 0x8D5B: 0x5CD3, //CJK UNIFIED IDEOGRAPH + 0x8D5C: 0x5CD4, //CJK UNIFIED IDEOGRAPH + 0x8D5D: 0x5CD5, //CJK UNIFIED IDEOGRAPH + 0x8D5E: 0x5CD6, //CJK UNIFIED IDEOGRAPH + 0x8D5F: 0x5CD7, //CJK UNIFIED IDEOGRAPH + 0x8D60: 0x5CD8, //CJK UNIFIED IDEOGRAPH + 0x8D61: 0x5CDA, //CJK UNIFIED IDEOGRAPH + 0x8D62: 0x5CDB, //CJK UNIFIED IDEOGRAPH + 0x8D63: 0x5CDC, //CJK UNIFIED IDEOGRAPH + 0x8D64: 0x5CDD, //CJK UNIFIED IDEOGRAPH + 0x8D65: 0x5CDE, //CJK UNIFIED IDEOGRAPH + 0x8D66: 0x5CDF, //CJK UNIFIED IDEOGRAPH + 0x8D67: 0x5CE0, //CJK UNIFIED IDEOGRAPH + 0x8D68: 0x5CE2, //CJK UNIFIED IDEOGRAPH + 0x8D69: 0x5CE3, //CJK UNIFIED IDEOGRAPH + 0x8D6A: 0x5CE7, //CJK UNIFIED IDEOGRAPH + 0x8D6B: 0x5CE9, //CJK UNIFIED IDEOGRAPH + 0x8D6C: 0x5CEB, //CJK UNIFIED IDEOGRAPH + 0x8D6D: 0x5CEC, //CJK UNIFIED IDEOGRAPH + 0x8D6E: 0x5CEE, //CJK UNIFIED IDEOGRAPH + 0x8D6F: 0x5CEF, //CJK UNIFIED IDEOGRAPH + 0x8D70: 0x5CF1, //CJK UNIFIED IDEOGRAPH + 0x8D71: 0x5CF2, //CJK UNIFIED IDEOGRAPH + 0x8D72: 0x5CF3, //CJK UNIFIED IDEOGRAPH + 0x8D73: 0x5CF4, //CJK UNIFIED IDEOGRAPH + 0x8D74: 0x5CF5, //CJK UNIFIED IDEOGRAPH + 0x8D75: 0x5CF6, //CJK UNIFIED IDEOGRAPH + 0x8D76: 0x5CF7, //CJK UNIFIED IDEOGRAPH + 0x8D77: 0x5CF8, //CJK UNIFIED IDEOGRAPH + 0x8D78: 0x5CF9, //CJK UNIFIED IDEOGRAPH + 0x8D79: 0x5CFA, //CJK UNIFIED IDEOGRAPH + 0x8D7A: 0x5CFC, //CJK UNIFIED IDEOGRAPH + 0x8D7B: 0x5CFD, //CJK UNIFIED IDEOGRAPH + 0x8D7C: 0x5CFE, //CJK UNIFIED IDEOGRAPH + 0x8D7D: 0x5CFF, //CJK UNIFIED IDEOGRAPH + 0x8D7E: 0x5D00, //CJK UNIFIED IDEOGRAPH + 0x8D80: 0x5D01, //CJK UNIFIED IDEOGRAPH + 0x8D81: 0x5D04, //CJK UNIFIED IDEOGRAPH + 0x8D82: 0x5D05, //CJK UNIFIED IDEOGRAPH + 0x8D83: 0x5D08, //CJK UNIFIED IDEOGRAPH + 0x8D84: 0x5D09, //CJK UNIFIED IDEOGRAPH + 0x8D85: 0x5D0A, //CJK UNIFIED IDEOGRAPH + 0x8D86: 0x5D0B, //CJK UNIFIED IDEOGRAPH + 0x8D87: 0x5D0C, //CJK UNIFIED IDEOGRAPH + 0x8D88: 0x5D0D, //CJK UNIFIED IDEOGRAPH + 0x8D89: 0x5D0F, //CJK UNIFIED IDEOGRAPH + 0x8D8A: 0x5D10, //CJK UNIFIED IDEOGRAPH + 0x8D8B: 0x5D11, //CJK UNIFIED IDEOGRAPH + 0x8D8C: 0x5D12, //CJK UNIFIED IDEOGRAPH + 0x8D8D: 0x5D13, //CJK UNIFIED IDEOGRAPH + 0x8D8E: 0x5D15, //CJK UNIFIED IDEOGRAPH + 0x8D8F: 0x5D17, //CJK UNIFIED IDEOGRAPH + 0x8D90: 0x5D18, //CJK UNIFIED IDEOGRAPH + 0x8D91: 0x5D19, //CJK UNIFIED IDEOGRAPH + 0x8D92: 0x5D1A, //CJK UNIFIED IDEOGRAPH + 0x8D93: 0x5D1C, //CJK UNIFIED IDEOGRAPH + 0x8D94: 0x5D1D, //CJK UNIFIED IDEOGRAPH + 0x8D95: 0x5D1F, //CJK UNIFIED IDEOGRAPH + 0x8D96: 0x5D20, //CJK UNIFIED IDEOGRAPH + 0x8D97: 0x5D21, //CJK UNIFIED IDEOGRAPH + 0x8D98: 0x5D22, //CJK UNIFIED IDEOGRAPH + 0x8D99: 0x5D23, //CJK UNIFIED IDEOGRAPH + 0x8D9A: 0x5D25, //CJK UNIFIED IDEOGRAPH + 0x8D9B: 0x5D28, //CJK UNIFIED IDEOGRAPH + 0x8D9C: 0x5D2A, //CJK UNIFIED IDEOGRAPH + 0x8D9D: 0x5D2B, //CJK UNIFIED IDEOGRAPH + 0x8D9E: 0x5D2C, //CJK UNIFIED IDEOGRAPH + 0x8D9F: 0x5D2F, //CJK UNIFIED IDEOGRAPH + 0x8DA0: 0x5D30, //CJK UNIFIED IDEOGRAPH + 0x8DA1: 0x5D31, //CJK UNIFIED IDEOGRAPH + 0x8DA2: 0x5D32, //CJK UNIFIED IDEOGRAPH + 0x8DA3: 0x5D33, //CJK UNIFIED IDEOGRAPH + 0x8DA4: 0x5D35, //CJK UNIFIED IDEOGRAPH + 0x8DA5: 0x5D36, //CJK UNIFIED IDEOGRAPH + 0x8DA6: 0x5D37, //CJK UNIFIED IDEOGRAPH + 0x8DA7: 0x5D38, //CJK UNIFIED IDEOGRAPH + 0x8DA8: 0x5D39, //CJK UNIFIED IDEOGRAPH + 0x8DA9: 0x5D3A, //CJK UNIFIED IDEOGRAPH + 0x8DAA: 0x5D3B, //CJK UNIFIED IDEOGRAPH + 0x8DAB: 0x5D3C, //CJK UNIFIED IDEOGRAPH + 0x8DAC: 0x5D3F, //CJK UNIFIED IDEOGRAPH + 0x8DAD: 0x5D40, //CJK UNIFIED IDEOGRAPH + 0x8DAE: 0x5D41, //CJK UNIFIED IDEOGRAPH + 0x8DAF: 0x5D42, //CJK UNIFIED IDEOGRAPH + 0x8DB0: 0x5D43, //CJK UNIFIED IDEOGRAPH + 0x8DB1: 0x5D44, //CJK UNIFIED IDEOGRAPH + 0x8DB2: 0x5D45, //CJK UNIFIED IDEOGRAPH + 0x8DB3: 0x5D46, //CJK UNIFIED IDEOGRAPH + 0x8DB4: 0x5D48, //CJK UNIFIED IDEOGRAPH + 0x8DB5: 0x5D49, //CJK UNIFIED IDEOGRAPH + 0x8DB6: 0x5D4D, //CJK UNIFIED IDEOGRAPH + 0x8DB7: 0x5D4E, //CJK UNIFIED IDEOGRAPH + 0x8DB8: 0x5D4F, //CJK UNIFIED IDEOGRAPH + 0x8DB9: 0x5D50, //CJK UNIFIED IDEOGRAPH + 0x8DBA: 0x5D51, //CJK UNIFIED IDEOGRAPH + 0x8DBB: 0x5D52, //CJK UNIFIED IDEOGRAPH + 0x8DBC: 0x5D53, //CJK UNIFIED IDEOGRAPH + 0x8DBD: 0x5D54, //CJK UNIFIED IDEOGRAPH + 0x8DBE: 0x5D55, //CJK UNIFIED IDEOGRAPH + 0x8DBF: 0x5D56, //CJK UNIFIED IDEOGRAPH + 0x8DC0: 0x5D57, //CJK UNIFIED IDEOGRAPH + 0x8DC1: 0x5D59, //CJK UNIFIED IDEOGRAPH + 0x8DC2: 0x5D5A, //CJK UNIFIED IDEOGRAPH + 0x8DC3: 0x5D5C, //CJK UNIFIED IDEOGRAPH + 0x8DC4: 0x5D5E, //CJK UNIFIED IDEOGRAPH + 0x8DC5: 0x5D5F, //CJK UNIFIED IDEOGRAPH + 0x8DC6: 0x5D60, //CJK UNIFIED IDEOGRAPH + 0x8DC7: 0x5D61, //CJK UNIFIED IDEOGRAPH + 0x8DC8: 0x5D62, //CJK UNIFIED IDEOGRAPH + 0x8DC9: 0x5D63, //CJK UNIFIED IDEOGRAPH + 0x8DCA: 0x5D64, //CJK UNIFIED IDEOGRAPH + 0x8DCB: 0x5D65, //CJK UNIFIED IDEOGRAPH + 0x8DCC: 0x5D66, //CJK UNIFIED IDEOGRAPH + 0x8DCD: 0x5D67, //CJK UNIFIED IDEOGRAPH + 0x8DCE: 0x5D68, //CJK UNIFIED IDEOGRAPH + 0x8DCF: 0x5D6A, //CJK UNIFIED IDEOGRAPH + 0x8DD0: 0x5D6D, //CJK UNIFIED IDEOGRAPH + 0x8DD1: 0x5D6E, //CJK UNIFIED IDEOGRAPH + 0x8DD2: 0x5D70, //CJK UNIFIED IDEOGRAPH + 0x8DD3: 0x5D71, //CJK UNIFIED IDEOGRAPH + 0x8DD4: 0x5D72, //CJK UNIFIED IDEOGRAPH + 0x8DD5: 0x5D73, //CJK UNIFIED IDEOGRAPH + 0x8DD6: 0x5D75, //CJK UNIFIED IDEOGRAPH + 0x8DD7: 0x5D76, //CJK UNIFIED IDEOGRAPH + 0x8DD8: 0x5D77, //CJK UNIFIED IDEOGRAPH + 0x8DD9: 0x5D78, //CJK UNIFIED IDEOGRAPH + 0x8DDA: 0x5D79, //CJK UNIFIED IDEOGRAPH + 0x8DDB: 0x5D7A, //CJK UNIFIED IDEOGRAPH + 0x8DDC: 0x5D7B, //CJK UNIFIED IDEOGRAPH + 0x8DDD: 0x5D7C, //CJK UNIFIED IDEOGRAPH + 0x8DDE: 0x5D7D, //CJK UNIFIED IDEOGRAPH + 0x8DDF: 0x5D7E, //CJK UNIFIED IDEOGRAPH + 0x8DE0: 0x5D7F, //CJK UNIFIED IDEOGRAPH + 0x8DE1: 0x5D80, //CJK UNIFIED IDEOGRAPH + 0x8DE2: 0x5D81, //CJK UNIFIED IDEOGRAPH + 0x8DE3: 0x5D83, //CJK UNIFIED IDEOGRAPH + 0x8DE4: 0x5D84, //CJK UNIFIED IDEOGRAPH + 0x8DE5: 0x5D85, //CJK UNIFIED IDEOGRAPH + 0x8DE6: 0x5D86, //CJK UNIFIED IDEOGRAPH + 0x8DE7: 0x5D87, //CJK UNIFIED IDEOGRAPH + 0x8DE8: 0x5D88, //CJK UNIFIED IDEOGRAPH + 0x8DE9: 0x5D89, //CJK UNIFIED IDEOGRAPH + 0x8DEA: 0x5D8A, //CJK UNIFIED IDEOGRAPH + 0x8DEB: 0x5D8B, //CJK UNIFIED IDEOGRAPH + 0x8DEC: 0x5D8C, //CJK UNIFIED IDEOGRAPH + 0x8DED: 0x5D8D, //CJK UNIFIED IDEOGRAPH + 0x8DEE: 0x5D8E, //CJK UNIFIED IDEOGRAPH + 0x8DEF: 0x5D8F, //CJK UNIFIED IDEOGRAPH + 0x8DF0: 0x5D90, //CJK UNIFIED IDEOGRAPH + 0x8DF1: 0x5D91, //CJK UNIFIED IDEOGRAPH + 0x8DF2: 0x5D92, //CJK UNIFIED IDEOGRAPH + 0x8DF3: 0x5D93, //CJK UNIFIED IDEOGRAPH + 0x8DF4: 0x5D94, //CJK UNIFIED IDEOGRAPH + 0x8DF5: 0x5D95, //CJK UNIFIED IDEOGRAPH + 0x8DF6: 0x5D96, //CJK UNIFIED IDEOGRAPH + 0x8DF7: 0x5D97, //CJK UNIFIED IDEOGRAPH + 0x8DF8: 0x5D98, //CJK UNIFIED IDEOGRAPH + 0x8DF9: 0x5D9A, //CJK UNIFIED IDEOGRAPH + 0x8DFA: 0x5D9B, //CJK UNIFIED IDEOGRAPH + 0x8DFB: 0x5D9C, //CJK UNIFIED IDEOGRAPH + 0x8DFC: 0x5D9E, //CJK UNIFIED IDEOGRAPH + 0x8DFD: 0x5D9F, //CJK UNIFIED IDEOGRAPH + 0x8DFE: 0x5DA0, //CJK UNIFIED IDEOGRAPH + 0x8E40: 0x5DA1, //CJK UNIFIED IDEOGRAPH + 0x8E41: 0x5DA2, //CJK UNIFIED IDEOGRAPH + 0x8E42: 0x5DA3, //CJK UNIFIED IDEOGRAPH + 0x8E43: 0x5DA4, //CJK UNIFIED IDEOGRAPH + 0x8E44: 0x5DA5, //CJK UNIFIED IDEOGRAPH + 0x8E45: 0x5DA6, //CJK UNIFIED IDEOGRAPH + 0x8E46: 0x5DA7, //CJK UNIFIED IDEOGRAPH + 0x8E47: 0x5DA8, //CJK UNIFIED IDEOGRAPH + 0x8E48: 0x5DA9, //CJK UNIFIED IDEOGRAPH + 0x8E49: 0x5DAA, //CJK UNIFIED IDEOGRAPH + 0x8E4A: 0x5DAB, //CJK UNIFIED IDEOGRAPH + 0x8E4B: 0x5DAC, //CJK UNIFIED IDEOGRAPH + 0x8E4C: 0x5DAD, //CJK UNIFIED IDEOGRAPH + 0x8E4D: 0x5DAE, //CJK UNIFIED IDEOGRAPH + 0x8E4E: 0x5DAF, //CJK UNIFIED IDEOGRAPH + 0x8E4F: 0x5DB0, //CJK UNIFIED IDEOGRAPH + 0x8E50: 0x5DB1, //CJK UNIFIED IDEOGRAPH + 0x8E51: 0x5DB2, //CJK UNIFIED IDEOGRAPH + 0x8E52: 0x5DB3, //CJK UNIFIED IDEOGRAPH + 0x8E53: 0x5DB4, //CJK UNIFIED IDEOGRAPH + 0x8E54: 0x5DB5, //CJK UNIFIED IDEOGRAPH + 0x8E55: 0x5DB6, //CJK UNIFIED IDEOGRAPH + 0x8E56: 0x5DB8, //CJK UNIFIED IDEOGRAPH + 0x8E57: 0x5DB9, //CJK UNIFIED IDEOGRAPH + 0x8E58: 0x5DBA, //CJK UNIFIED IDEOGRAPH + 0x8E59: 0x5DBB, //CJK UNIFIED IDEOGRAPH + 0x8E5A: 0x5DBC, //CJK UNIFIED IDEOGRAPH + 0x8E5B: 0x5DBD, //CJK UNIFIED IDEOGRAPH + 0x8E5C: 0x5DBE, //CJK UNIFIED IDEOGRAPH + 0x8E5D: 0x5DBF, //CJK UNIFIED IDEOGRAPH + 0x8E5E: 0x5DC0, //CJK UNIFIED IDEOGRAPH + 0x8E5F: 0x5DC1, //CJK UNIFIED IDEOGRAPH + 0x8E60: 0x5DC2, //CJK UNIFIED IDEOGRAPH + 0x8E61: 0x5DC3, //CJK UNIFIED IDEOGRAPH + 0x8E62: 0x5DC4, //CJK UNIFIED IDEOGRAPH + 0x8E63: 0x5DC6, //CJK UNIFIED IDEOGRAPH + 0x8E64: 0x5DC7, //CJK UNIFIED IDEOGRAPH + 0x8E65: 0x5DC8, //CJK UNIFIED IDEOGRAPH + 0x8E66: 0x5DC9, //CJK UNIFIED IDEOGRAPH + 0x8E67: 0x5DCA, //CJK UNIFIED IDEOGRAPH + 0x8E68: 0x5DCB, //CJK UNIFIED IDEOGRAPH + 0x8E69: 0x5DCC, //CJK UNIFIED IDEOGRAPH + 0x8E6A: 0x5DCE, //CJK UNIFIED IDEOGRAPH + 0x8E6B: 0x5DCF, //CJK UNIFIED IDEOGRAPH + 0x8E6C: 0x5DD0, //CJK UNIFIED IDEOGRAPH + 0x8E6D: 0x5DD1, //CJK UNIFIED IDEOGRAPH + 0x8E6E: 0x5DD2, //CJK UNIFIED IDEOGRAPH + 0x8E6F: 0x5DD3, //CJK UNIFIED IDEOGRAPH + 0x8E70: 0x5DD4, //CJK UNIFIED IDEOGRAPH + 0x8E71: 0x5DD5, //CJK UNIFIED IDEOGRAPH + 0x8E72: 0x5DD6, //CJK UNIFIED IDEOGRAPH + 0x8E73: 0x5DD7, //CJK UNIFIED IDEOGRAPH + 0x8E74: 0x5DD8, //CJK UNIFIED IDEOGRAPH + 0x8E75: 0x5DD9, //CJK UNIFIED IDEOGRAPH + 0x8E76: 0x5DDA, //CJK UNIFIED IDEOGRAPH + 0x8E77: 0x5DDC, //CJK UNIFIED IDEOGRAPH + 0x8E78: 0x5DDF, //CJK UNIFIED IDEOGRAPH + 0x8E79: 0x5DE0, //CJK UNIFIED IDEOGRAPH + 0x8E7A: 0x5DE3, //CJK UNIFIED IDEOGRAPH + 0x8E7B: 0x5DE4, //CJK UNIFIED IDEOGRAPH + 0x8E7C: 0x5DEA, //CJK UNIFIED IDEOGRAPH + 0x8E7D: 0x5DEC, //CJK UNIFIED IDEOGRAPH + 0x8E7E: 0x5DED, //CJK UNIFIED IDEOGRAPH + 0x8E80: 0x5DF0, //CJK UNIFIED IDEOGRAPH + 0x8E81: 0x5DF5, //CJK UNIFIED IDEOGRAPH + 0x8E82: 0x5DF6, //CJK UNIFIED IDEOGRAPH + 0x8E83: 0x5DF8, //CJK UNIFIED IDEOGRAPH + 0x8E84: 0x5DF9, //CJK UNIFIED IDEOGRAPH + 0x8E85: 0x5DFA, //CJK UNIFIED IDEOGRAPH + 0x8E86: 0x5DFB, //CJK UNIFIED IDEOGRAPH + 0x8E87: 0x5DFC, //CJK UNIFIED IDEOGRAPH + 0x8E88: 0x5DFF, //CJK UNIFIED IDEOGRAPH + 0x8E89: 0x5E00, //CJK UNIFIED IDEOGRAPH + 0x8E8A: 0x5E04, //CJK UNIFIED IDEOGRAPH + 0x8E8B: 0x5E07, //CJK UNIFIED IDEOGRAPH + 0x8E8C: 0x5E09, //CJK UNIFIED IDEOGRAPH + 0x8E8D: 0x5E0A, //CJK UNIFIED IDEOGRAPH + 0x8E8E: 0x5E0B, //CJK UNIFIED IDEOGRAPH + 0x8E8F: 0x5E0D, //CJK UNIFIED IDEOGRAPH + 0x8E90: 0x5E0E, //CJK UNIFIED IDEOGRAPH + 0x8E91: 0x5E12, //CJK UNIFIED IDEOGRAPH + 0x8E92: 0x5E13, //CJK UNIFIED IDEOGRAPH + 0x8E93: 0x5E17, //CJK UNIFIED IDEOGRAPH + 0x8E94: 0x5E1E, //CJK UNIFIED IDEOGRAPH + 0x8E95: 0x5E1F, //CJK UNIFIED IDEOGRAPH + 0x8E96: 0x5E20, //CJK UNIFIED IDEOGRAPH + 0x8E97: 0x5E21, //CJK UNIFIED IDEOGRAPH + 0x8E98: 0x5E22, //CJK UNIFIED IDEOGRAPH + 0x8E99: 0x5E23, //CJK UNIFIED IDEOGRAPH + 0x8E9A: 0x5E24, //CJK UNIFIED IDEOGRAPH + 0x8E9B: 0x5E25, //CJK UNIFIED IDEOGRAPH + 0x8E9C: 0x5E28, //CJK UNIFIED IDEOGRAPH + 0x8E9D: 0x5E29, //CJK UNIFIED IDEOGRAPH + 0x8E9E: 0x5E2A, //CJK UNIFIED IDEOGRAPH + 0x8E9F: 0x5E2B, //CJK UNIFIED IDEOGRAPH + 0x8EA0: 0x5E2C, //CJK UNIFIED IDEOGRAPH + 0x8EA1: 0x5E2F, //CJK UNIFIED IDEOGRAPH + 0x8EA2: 0x5E30, //CJK UNIFIED IDEOGRAPH + 0x8EA3: 0x5E32, //CJK UNIFIED IDEOGRAPH + 0x8EA4: 0x5E33, //CJK UNIFIED IDEOGRAPH + 0x8EA5: 0x5E34, //CJK UNIFIED IDEOGRAPH + 0x8EA6: 0x5E35, //CJK UNIFIED IDEOGRAPH + 0x8EA7: 0x5E36, //CJK UNIFIED IDEOGRAPH + 0x8EA8: 0x5E39, //CJK UNIFIED IDEOGRAPH + 0x8EA9: 0x5E3A, //CJK UNIFIED IDEOGRAPH + 0x8EAA: 0x5E3E, //CJK UNIFIED IDEOGRAPH + 0x8EAB: 0x5E3F, //CJK UNIFIED IDEOGRAPH + 0x8EAC: 0x5E40, //CJK UNIFIED IDEOGRAPH + 0x8EAD: 0x5E41, //CJK UNIFIED IDEOGRAPH + 0x8EAE: 0x5E43, //CJK UNIFIED IDEOGRAPH + 0x8EAF: 0x5E46, //CJK UNIFIED IDEOGRAPH + 0x8EB0: 0x5E47, //CJK UNIFIED IDEOGRAPH + 0x8EB1: 0x5E48, //CJK UNIFIED IDEOGRAPH + 0x8EB2: 0x5E49, //CJK UNIFIED IDEOGRAPH + 0x8EB3: 0x5E4A, //CJK UNIFIED IDEOGRAPH + 0x8EB4: 0x5E4B, //CJK UNIFIED IDEOGRAPH + 0x8EB5: 0x5E4D, //CJK UNIFIED IDEOGRAPH + 0x8EB6: 0x5E4E, //CJK UNIFIED IDEOGRAPH + 0x8EB7: 0x5E4F, //CJK UNIFIED IDEOGRAPH + 0x8EB8: 0x5E50, //CJK UNIFIED IDEOGRAPH + 0x8EB9: 0x5E51, //CJK UNIFIED IDEOGRAPH + 0x8EBA: 0x5E52, //CJK UNIFIED IDEOGRAPH + 0x8EBB: 0x5E53, //CJK UNIFIED IDEOGRAPH + 0x8EBC: 0x5E56, //CJK UNIFIED IDEOGRAPH + 0x8EBD: 0x5E57, //CJK UNIFIED IDEOGRAPH + 0x8EBE: 0x5E58, //CJK UNIFIED IDEOGRAPH + 0x8EBF: 0x5E59, //CJK UNIFIED IDEOGRAPH + 0x8EC0: 0x5E5A, //CJK UNIFIED IDEOGRAPH + 0x8EC1: 0x5E5C, //CJK UNIFIED IDEOGRAPH + 0x8EC2: 0x5E5D, //CJK UNIFIED IDEOGRAPH + 0x8EC3: 0x5E5F, //CJK UNIFIED IDEOGRAPH + 0x8EC4: 0x5E60, //CJK UNIFIED IDEOGRAPH + 0x8EC5: 0x5E63, //CJK UNIFIED IDEOGRAPH + 0x8EC6: 0x5E64, //CJK UNIFIED IDEOGRAPH + 0x8EC7: 0x5E65, //CJK UNIFIED IDEOGRAPH + 0x8EC8: 0x5E66, //CJK UNIFIED IDEOGRAPH + 0x8EC9: 0x5E67, //CJK UNIFIED IDEOGRAPH + 0x8ECA: 0x5E68, //CJK UNIFIED IDEOGRAPH + 0x8ECB: 0x5E69, //CJK UNIFIED IDEOGRAPH + 0x8ECC: 0x5E6A, //CJK UNIFIED IDEOGRAPH + 0x8ECD: 0x5E6B, //CJK UNIFIED IDEOGRAPH + 0x8ECE: 0x5E6C, //CJK UNIFIED IDEOGRAPH + 0x8ECF: 0x5E6D, //CJK UNIFIED IDEOGRAPH + 0x8ED0: 0x5E6E, //CJK UNIFIED IDEOGRAPH + 0x8ED1: 0x5E6F, //CJK UNIFIED IDEOGRAPH + 0x8ED2: 0x5E70, //CJK UNIFIED IDEOGRAPH + 0x8ED3: 0x5E71, //CJK UNIFIED IDEOGRAPH + 0x8ED4: 0x5E75, //CJK UNIFIED IDEOGRAPH + 0x8ED5: 0x5E77, //CJK UNIFIED IDEOGRAPH + 0x8ED6: 0x5E79, //CJK UNIFIED IDEOGRAPH + 0x8ED7: 0x5E7E, //CJK UNIFIED IDEOGRAPH + 0x8ED8: 0x5E81, //CJK UNIFIED IDEOGRAPH + 0x8ED9: 0x5E82, //CJK UNIFIED IDEOGRAPH + 0x8EDA: 0x5E83, //CJK UNIFIED IDEOGRAPH + 0x8EDB: 0x5E85, //CJK UNIFIED IDEOGRAPH + 0x8EDC: 0x5E88, //CJK UNIFIED IDEOGRAPH + 0x8EDD: 0x5E89, //CJK UNIFIED IDEOGRAPH + 0x8EDE: 0x5E8C, //CJK UNIFIED IDEOGRAPH + 0x8EDF: 0x5E8D, //CJK UNIFIED IDEOGRAPH + 0x8EE0: 0x5E8E, //CJK UNIFIED IDEOGRAPH + 0x8EE1: 0x5E92, //CJK UNIFIED IDEOGRAPH + 0x8EE2: 0x5E98, //CJK UNIFIED IDEOGRAPH + 0x8EE3: 0x5E9B, //CJK UNIFIED IDEOGRAPH + 0x8EE4: 0x5E9D, //CJK UNIFIED IDEOGRAPH + 0x8EE5: 0x5EA1, //CJK UNIFIED IDEOGRAPH + 0x8EE6: 0x5EA2, //CJK UNIFIED IDEOGRAPH + 0x8EE7: 0x5EA3, //CJK UNIFIED IDEOGRAPH + 0x8EE8: 0x5EA4, //CJK UNIFIED IDEOGRAPH + 0x8EE9: 0x5EA8, //CJK UNIFIED IDEOGRAPH + 0x8EEA: 0x5EA9, //CJK UNIFIED IDEOGRAPH + 0x8EEB: 0x5EAA, //CJK UNIFIED IDEOGRAPH + 0x8EEC: 0x5EAB, //CJK UNIFIED IDEOGRAPH + 0x8EED: 0x5EAC, //CJK UNIFIED IDEOGRAPH + 0x8EEE: 0x5EAE, //CJK UNIFIED IDEOGRAPH + 0x8EEF: 0x5EAF, //CJK UNIFIED IDEOGRAPH + 0x8EF0: 0x5EB0, //CJK UNIFIED IDEOGRAPH + 0x8EF1: 0x5EB1, //CJK UNIFIED IDEOGRAPH + 0x8EF2: 0x5EB2, //CJK UNIFIED IDEOGRAPH + 0x8EF3: 0x5EB4, //CJK UNIFIED IDEOGRAPH + 0x8EF4: 0x5EBA, //CJK UNIFIED IDEOGRAPH + 0x8EF5: 0x5EBB, //CJK UNIFIED IDEOGRAPH + 0x8EF6: 0x5EBC, //CJK UNIFIED IDEOGRAPH + 0x8EF7: 0x5EBD, //CJK UNIFIED IDEOGRAPH + 0x8EF8: 0x5EBF, //CJK UNIFIED IDEOGRAPH + 0x8EF9: 0x5EC0, //CJK UNIFIED IDEOGRAPH + 0x8EFA: 0x5EC1, //CJK UNIFIED IDEOGRAPH + 0x8EFB: 0x5EC2, //CJK UNIFIED IDEOGRAPH + 0x8EFC: 0x5EC3, //CJK UNIFIED IDEOGRAPH + 0x8EFD: 0x5EC4, //CJK UNIFIED IDEOGRAPH + 0x8EFE: 0x5EC5, //CJK UNIFIED IDEOGRAPH + 0x8F40: 0x5EC6, //CJK UNIFIED IDEOGRAPH + 0x8F41: 0x5EC7, //CJK UNIFIED IDEOGRAPH + 0x8F42: 0x5EC8, //CJK UNIFIED IDEOGRAPH + 0x8F43: 0x5ECB, //CJK UNIFIED IDEOGRAPH + 0x8F44: 0x5ECC, //CJK UNIFIED IDEOGRAPH + 0x8F45: 0x5ECD, //CJK UNIFIED IDEOGRAPH + 0x8F46: 0x5ECE, //CJK UNIFIED IDEOGRAPH + 0x8F47: 0x5ECF, //CJK UNIFIED IDEOGRAPH + 0x8F48: 0x5ED0, //CJK UNIFIED IDEOGRAPH + 0x8F49: 0x5ED4, //CJK UNIFIED IDEOGRAPH + 0x8F4A: 0x5ED5, //CJK UNIFIED IDEOGRAPH + 0x8F4B: 0x5ED7, //CJK UNIFIED IDEOGRAPH + 0x8F4C: 0x5ED8, //CJK UNIFIED IDEOGRAPH + 0x8F4D: 0x5ED9, //CJK UNIFIED IDEOGRAPH + 0x8F4E: 0x5EDA, //CJK UNIFIED IDEOGRAPH + 0x8F4F: 0x5EDC, //CJK UNIFIED IDEOGRAPH + 0x8F50: 0x5EDD, //CJK UNIFIED IDEOGRAPH + 0x8F51: 0x5EDE, //CJK UNIFIED IDEOGRAPH + 0x8F52: 0x5EDF, //CJK UNIFIED IDEOGRAPH + 0x8F53: 0x5EE0, //CJK UNIFIED IDEOGRAPH + 0x8F54: 0x5EE1, //CJK UNIFIED IDEOGRAPH + 0x8F55: 0x5EE2, //CJK UNIFIED IDEOGRAPH + 0x8F56: 0x5EE3, //CJK UNIFIED IDEOGRAPH + 0x8F57: 0x5EE4, //CJK UNIFIED IDEOGRAPH + 0x8F58: 0x5EE5, //CJK UNIFIED IDEOGRAPH + 0x8F59: 0x5EE6, //CJK UNIFIED IDEOGRAPH + 0x8F5A: 0x5EE7, //CJK UNIFIED IDEOGRAPH + 0x8F5B: 0x5EE9, //CJK UNIFIED IDEOGRAPH + 0x8F5C: 0x5EEB, //CJK UNIFIED IDEOGRAPH + 0x8F5D: 0x5EEC, //CJK UNIFIED IDEOGRAPH + 0x8F5E: 0x5EED, //CJK UNIFIED IDEOGRAPH + 0x8F5F: 0x5EEE, //CJK UNIFIED IDEOGRAPH + 0x8F60: 0x5EEF, //CJK UNIFIED IDEOGRAPH + 0x8F61: 0x5EF0, //CJK UNIFIED IDEOGRAPH + 0x8F62: 0x5EF1, //CJK UNIFIED IDEOGRAPH + 0x8F63: 0x5EF2, //CJK UNIFIED IDEOGRAPH + 0x8F64: 0x5EF3, //CJK UNIFIED IDEOGRAPH + 0x8F65: 0x5EF5, //CJK UNIFIED IDEOGRAPH + 0x8F66: 0x5EF8, //CJK UNIFIED IDEOGRAPH + 0x8F67: 0x5EF9, //CJK UNIFIED IDEOGRAPH + 0x8F68: 0x5EFB, //CJK UNIFIED IDEOGRAPH + 0x8F69: 0x5EFC, //CJK UNIFIED IDEOGRAPH + 0x8F6A: 0x5EFD, //CJK UNIFIED IDEOGRAPH + 0x8F6B: 0x5F05, //CJK UNIFIED IDEOGRAPH + 0x8F6C: 0x5F06, //CJK UNIFIED IDEOGRAPH + 0x8F6D: 0x5F07, //CJK UNIFIED IDEOGRAPH + 0x8F6E: 0x5F09, //CJK UNIFIED IDEOGRAPH + 0x8F6F: 0x5F0C, //CJK UNIFIED IDEOGRAPH + 0x8F70: 0x5F0D, //CJK UNIFIED IDEOGRAPH + 0x8F71: 0x5F0E, //CJK UNIFIED IDEOGRAPH + 0x8F72: 0x5F10, //CJK UNIFIED IDEOGRAPH + 0x8F73: 0x5F12, //CJK UNIFIED IDEOGRAPH + 0x8F74: 0x5F14, //CJK UNIFIED IDEOGRAPH + 0x8F75: 0x5F16, //CJK UNIFIED IDEOGRAPH + 0x8F76: 0x5F19, //CJK UNIFIED IDEOGRAPH + 0x8F77: 0x5F1A, //CJK UNIFIED IDEOGRAPH + 0x8F78: 0x5F1C, //CJK UNIFIED IDEOGRAPH + 0x8F79: 0x5F1D, //CJK UNIFIED IDEOGRAPH + 0x8F7A: 0x5F1E, //CJK UNIFIED IDEOGRAPH + 0x8F7B: 0x5F21, //CJK UNIFIED IDEOGRAPH + 0x8F7C: 0x5F22, //CJK UNIFIED IDEOGRAPH + 0x8F7D: 0x5F23, //CJK UNIFIED IDEOGRAPH + 0x8F7E: 0x5F24, //CJK UNIFIED IDEOGRAPH + 0x8F80: 0x5F28, //CJK UNIFIED IDEOGRAPH + 0x8F81: 0x5F2B, //CJK UNIFIED IDEOGRAPH + 0x8F82: 0x5F2C, //CJK UNIFIED IDEOGRAPH + 0x8F83: 0x5F2E, //CJK UNIFIED IDEOGRAPH + 0x8F84: 0x5F30, //CJK UNIFIED IDEOGRAPH + 0x8F85: 0x5F32, //CJK UNIFIED IDEOGRAPH + 0x8F86: 0x5F33, //CJK UNIFIED IDEOGRAPH + 0x8F87: 0x5F34, //CJK UNIFIED IDEOGRAPH + 0x8F88: 0x5F35, //CJK UNIFIED IDEOGRAPH + 0x8F89: 0x5F36, //CJK UNIFIED IDEOGRAPH + 0x8F8A: 0x5F37, //CJK UNIFIED IDEOGRAPH + 0x8F8B: 0x5F38, //CJK UNIFIED IDEOGRAPH + 0x8F8C: 0x5F3B, //CJK UNIFIED IDEOGRAPH + 0x8F8D: 0x5F3D, //CJK UNIFIED IDEOGRAPH + 0x8F8E: 0x5F3E, //CJK UNIFIED IDEOGRAPH + 0x8F8F: 0x5F3F, //CJK UNIFIED IDEOGRAPH + 0x8F90: 0x5F41, //CJK UNIFIED IDEOGRAPH + 0x8F91: 0x5F42, //CJK UNIFIED IDEOGRAPH + 0x8F92: 0x5F43, //CJK UNIFIED IDEOGRAPH + 0x8F93: 0x5F44, //CJK UNIFIED IDEOGRAPH + 0x8F94: 0x5F45, //CJK UNIFIED IDEOGRAPH + 0x8F95: 0x5F46, //CJK UNIFIED IDEOGRAPH + 0x8F96: 0x5F47, //CJK UNIFIED IDEOGRAPH + 0x8F97: 0x5F48, //CJK UNIFIED IDEOGRAPH + 0x8F98: 0x5F49, //CJK UNIFIED IDEOGRAPH + 0x8F99: 0x5F4A, //CJK UNIFIED IDEOGRAPH + 0x8F9A: 0x5F4B, //CJK UNIFIED IDEOGRAPH + 0x8F9B: 0x5F4C, //CJK UNIFIED IDEOGRAPH + 0x8F9C: 0x5F4D, //CJK UNIFIED IDEOGRAPH + 0x8F9D: 0x5F4E, //CJK UNIFIED IDEOGRAPH + 0x8F9E: 0x5F4F, //CJK UNIFIED IDEOGRAPH + 0x8F9F: 0x5F51, //CJK UNIFIED IDEOGRAPH + 0x8FA0: 0x5F54, //CJK UNIFIED IDEOGRAPH + 0x8FA1: 0x5F59, //CJK UNIFIED IDEOGRAPH + 0x8FA2: 0x5F5A, //CJK UNIFIED IDEOGRAPH + 0x8FA3: 0x5F5B, //CJK UNIFIED IDEOGRAPH + 0x8FA4: 0x5F5C, //CJK UNIFIED IDEOGRAPH + 0x8FA5: 0x5F5E, //CJK UNIFIED IDEOGRAPH + 0x8FA6: 0x5F5F, //CJK UNIFIED IDEOGRAPH + 0x8FA7: 0x5F60, //CJK UNIFIED IDEOGRAPH + 0x8FA8: 0x5F63, //CJK UNIFIED IDEOGRAPH + 0x8FA9: 0x5F65, //CJK UNIFIED IDEOGRAPH + 0x8FAA: 0x5F67, //CJK UNIFIED IDEOGRAPH + 0x8FAB: 0x5F68, //CJK UNIFIED IDEOGRAPH + 0x8FAC: 0x5F6B, //CJK UNIFIED IDEOGRAPH + 0x8FAD: 0x5F6E, //CJK UNIFIED IDEOGRAPH + 0x8FAE: 0x5F6F, //CJK UNIFIED IDEOGRAPH + 0x8FAF: 0x5F72, //CJK UNIFIED IDEOGRAPH + 0x8FB0: 0x5F74, //CJK UNIFIED IDEOGRAPH + 0x8FB1: 0x5F75, //CJK UNIFIED IDEOGRAPH + 0x8FB2: 0x5F76, //CJK UNIFIED IDEOGRAPH + 0x8FB3: 0x5F78, //CJK UNIFIED IDEOGRAPH + 0x8FB4: 0x5F7A, //CJK UNIFIED IDEOGRAPH + 0x8FB5: 0x5F7D, //CJK UNIFIED IDEOGRAPH + 0x8FB6: 0x5F7E, //CJK UNIFIED IDEOGRAPH + 0x8FB7: 0x5F7F, //CJK UNIFIED IDEOGRAPH + 0x8FB8: 0x5F83, //CJK UNIFIED IDEOGRAPH + 0x8FB9: 0x5F86, //CJK UNIFIED IDEOGRAPH + 0x8FBA: 0x5F8D, //CJK UNIFIED IDEOGRAPH + 0x8FBB: 0x5F8E, //CJK UNIFIED IDEOGRAPH + 0x8FBC: 0x5F8F, //CJK UNIFIED IDEOGRAPH + 0x8FBD: 0x5F91, //CJK UNIFIED IDEOGRAPH + 0x8FBE: 0x5F93, //CJK UNIFIED IDEOGRAPH + 0x8FBF: 0x5F94, //CJK UNIFIED IDEOGRAPH + 0x8FC0: 0x5F96, //CJK UNIFIED IDEOGRAPH + 0x8FC1: 0x5F9A, //CJK UNIFIED IDEOGRAPH + 0x8FC2: 0x5F9B, //CJK UNIFIED IDEOGRAPH + 0x8FC3: 0x5F9D, //CJK UNIFIED IDEOGRAPH + 0x8FC4: 0x5F9E, //CJK UNIFIED IDEOGRAPH + 0x8FC5: 0x5F9F, //CJK UNIFIED IDEOGRAPH + 0x8FC6: 0x5FA0, //CJK UNIFIED IDEOGRAPH + 0x8FC7: 0x5FA2, //CJK UNIFIED IDEOGRAPH + 0x8FC8: 0x5FA3, //CJK UNIFIED IDEOGRAPH + 0x8FC9: 0x5FA4, //CJK UNIFIED IDEOGRAPH + 0x8FCA: 0x5FA5, //CJK UNIFIED IDEOGRAPH + 0x8FCB: 0x5FA6, //CJK UNIFIED IDEOGRAPH + 0x8FCC: 0x5FA7, //CJK UNIFIED IDEOGRAPH + 0x8FCD: 0x5FA9, //CJK UNIFIED IDEOGRAPH + 0x8FCE: 0x5FAB, //CJK UNIFIED IDEOGRAPH + 0x8FCF: 0x5FAC, //CJK UNIFIED IDEOGRAPH + 0x8FD0: 0x5FAF, //CJK UNIFIED IDEOGRAPH + 0x8FD1: 0x5FB0, //CJK UNIFIED IDEOGRAPH + 0x8FD2: 0x5FB1, //CJK UNIFIED IDEOGRAPH + 0x8FD3: 0x5FB2, //CJK UNIFIED IDEOGRAPH + 0x8FD4: 0x5FB3, //CJK UNIFIED IDEOGRAPH + 0x8FD5: 0x5FB4, //CJK UNIFIED IDEOGRAPH + 0x8FD6: 0x5FB6, //CJK UNIFIED IDEOGRAPH + 0x8FD7: 0x5FB8, //CJK UNIFIED IDEOGRAPH + 0x8FD8: 0x5FB9, //CJK UNIFIED IDEOGRAPH + 0x8FD9: 0x5FBA, //CJK UNIFIED IDEOGRAPH + 0x8FDA: 0x5FBB, //CJK UNIFIED IDEOGRAPH + 0x8FDB: 0x5FBE, //CJK UNIFIED IDEOGRAPH + 0x8FDC: 0x5FBF, //CJK UNIFIED IDEOGRAPH + 0x8FDD: 0x5FC0, //CJK UNIFIED IDEOGRAPH + 0x8FDE: 0x5FC1, //CJK UNIFIED IDEOGRAPH + 0x8FDF: 0x5FC2, //CJK UNIFIED IDEOGRAPH + 0x8FE0: 0x5FC7, //CJK UNIFIED IDEOGRAPH + 0x8FE1: 0x5FC8, //CJK UNIFIED IDEOGRAPH + 0x8FE2: 0x5FCA, //CJK UNIFIED IDEOGRAPH + 0x8FE3: 0x5FCB, //CJK UNIFIED IDEOGRAPH + 0x8FE4: 0x5FCE, //CJK UNIFIED IDEOGRAPH + 0x8FE5: 0x5FD3, //CJK UNIFIED IDEOGRAPH + 0x8FE6: 0x5FD4, //CJK UNIFIED IDEOGRAPH + 0x8FE7: 0x5FD5, //CJK UNIFIED IDEOGRAPH + 0x8FE8: 0x5FDA, //CJK UNIFIED IDEOGRAPH + 0x8FE9: 0x5FDB, //CJK UNIFIED IDEOGRAPH + 0x8FEA: 0x5FDC, //CJK UNIFIED IDEOGRAPH + 0x8FEB: 0x5FDE, //CJK UNIFIED IDEOGRAPH + 0x8FEC: 0x5FDF, //CJK UNIFIED IDEOGRAPH + 0x8FED: 0x5FE2, //CJK UNIFIED IDEOGRAPH + 0x8FEE: 0x5FE3, //CJK UNIFIED IDEOGRAPH + 0x8FEF: 0x5FE5, //CJK UNIFIED IDEOGRAPH + 0x8FF0: 0x5FE6, //CJK UNIFIED IDEOGRAPH + 0x8FF1: 0x5FE8, //CJK UNIFIED IDEOGRAPH + 0x8FF2: 0x5FE9, //CJK UNIFIED IDEOGRAPH + 0x8FF3: 0x5FEC, //CJK UNIFIED IDEOGRAPH + 0x8FF4: 0x5FEF, //CJK UNIFIED IDEOGRAPH + 0x8FF5: 0x5FF0, //CJK UNIFIED IDEOGRAPH + 0x8FF6: 0x5FF2, //CJK UNIFIED IDEOGRAPH + 0x8FF7: 0x5FF3, //CJK UNIFIED IDEOGRAPH + 0x8FF8: 0x5FF4, //CJK UNIFIED IDEOGRAPH + 0x8FF9: 0x5FF6, //CJK UNIFIED IDEOGRAPH + 0x8FFA: 0x5FF7, //CJK UNIFIED IDEOGRAPH + 0x8FFB: 0x5FF9, //CJK UNIFIED IDEOGRAPH + 0x8FFC: 0x5FFA, //CJK UNIFIED IDEOGRAPH + 0x8FFD: 0x5FFC, //CJK UNIFIED IDEOGRAPH + 0x8FFE: 0x6007, //CJK UNIFIED IDEOGRAPH + 0x9040: 0x6008, //CJK UNIFIED IDEOGRAPH + 0x9041: 0x6009, //CJK UNIFIED IDEOGRAPH + 0x9042: 0x600B, //CJK UNIFIED IDEOGRAPH + 0x9043: 0x600C, //CJK UNIFIED IDEOGRAPH + 0x9044: 0x6010, //CJK UNIFIED IDEOGRAPH + 0x9045: 0x6011, //CJK UNIFIED IDEOGRAPH + 0x9046: 0x6013, //CJK UNIFIED IDEOGRAPH + 0x9047: 0x6017, //CJK UNIFIED IDEOGRAPH + 0x9048: 0x6018, //CJK UNIFIED IDEOGRAPH + 0x9049: 0x601A, //CJK UNIFIED IDEOGRAPH + 0x904A: 0x601E, //CJK UNIFIED IDEOGRAPH + 0x904B: 0x601F, //CJK UNIFIED IDEOGRAPH + 0x904C: 0x6022, //CJK UNIFIED IDEOGRAPH + 0x904D: 0x6023, //CJK UNIFIED IDEOGRAPH + 0x904E: 0x6024, //CJK UNIFIED IDEOGRAPH + 0x904F: 0x602C, //CJK UNIFIED IDEOGRAPH + 0x9050: 0x602D, //CJK UNIFIED IDEOGRAPH + 0x9051: 0x602E, //CJK UNIFIED IDEOGRAPH + 0x9052: 0x6030, //CJK UNIFIED IDEOGRAPH + 0x9053: 0x6031, //CJK UNIFIED IDEOGRAPH + 0x9054: 0x6032, //CJK UNIFIED IDEOGRAPH + 0x9055: 0x6033, //CJK UNIFIED IDEOGRAPH + 0x9056: 0x6034, //CJK UNIFIED IDEOGRAPH + 0x9057: 0x6036, //CJK UNIFIED IDEOGRAPH + 0x9058: 0x6037, //CJK UNIFIED IDEOGRAPH + 0x9059: 0x6038, //CJK UNIFIED IDEOGRAPH + 0x905A: 0x6039, //CJK UNIFIED IDEOGRAPH + 0x905B: 0x603A, //CJK UNIFIED IDEOGRAPH + 0x905C: 0x603D, //CJK UNIFIED IDEOGRAPH + 0x905D: 0x603E, //CJK UNIFIED IDEOGRAPH + 0x905E: 0x6040, //CJK UNIFIED IDEOGRAPH + 0x905F: 0x6044, //CJK UNIFIED IDEOGRAPH + 0x9060: 0x6045, //CJK UNIFIED IDEOGRAPH + 0x9061: 0x6046, //CJK UNIFIED IDEOGRAPH + 0x9062: 0x6047, //CJK UNIFIED IDEOGRAPH + 0x9063: 0x6048, //CJK UNIFIED IDEOGRAPH + 0x9064: 0x6049, //CJK UNIFIED IDEOGRAPH + 0x9065: 0x604A, //CJK UNIFIED IDEOGRAPH + 0x9066: 0x604C, //CJK UNIFIED IDEOGRAPH + 0x9067: 0x604E, //CJK UNIFIED IDEOGRAPH + 0x9068: 0x604F, //CJK UNIFIED IDEOGRAPH + 0x9069: 0x6051, //CJK UNIFIED IDEOGRAPH + 0x906A: 0x6053, //CJK UNIFIED IDEOGRAPH + 0x906B: 0x6054, //CJK UNIFIED IDEOGRAPH + 0x906C: 0x6056, //CJK UNIFIED IDEOGRAPH + 0x906D: 0x6057, //CJK UNIFIED IDEOGRAPH + 0x906E: 0x6058, //CJK UNIFIED IDEOGRAPH + 0x906F: 0x605B, //CJK UNIFIED IDEOGRAPH + 0x9070: 0x605C, //CJK UNIFIED IDEOGRAPH + 0x9071: 0x605E, //CJK UNIFIED IDEOGRAPH + 0x9072: 0x605F, //CJK UNIFIED IDEOGRAPH + 0x9073: 0x6060, //CJK UNIFIED IDEOGRAPH + 0x9074: 0x6061, //CJK UNIFIED IDEOGRAPH + 0x9075: 0x6065, //CJK UNIFIED IDEOGRAPH + 0x9076: 0x6066, //CJK UNIFIED IDEOGRAPH + 0x9077: 0x606E, //CJK UNIFIED IDEOGRAPH + 0x9078: 0x6071, //CJK UNIFIED IDEOGRAPH + 0x9079: 0x6072, //CJK UNIFIED IDEOGRAPH + 0x907A: 0x6074, //CJK UNIFIED IDEOGRAPH + 0x907B: 0x6075, //CJK UNIFIED IDEOGRAPH + 0x907C: 0x6077, //CJK UNIFIED IDEOGRAPH + 0x907D: 0x607E, //CJK UNIFIED IDEOGRAPH + 0x907E: 0x6080, //CJK UNIFIED IDEOGRAPH + 0x9080: 0x6081, //CJK UNIFIED IDEOGRAPH + 0x9081: 0x6082, //CJK UNIFIED IDEOGRAPH + 0x9082: 0x6085, //CJK UNIFIED IDEOGRAPH + 0x9083: 0x6086, //CJK UNIFIED IDEOGRAPH + 0x9084: 0x6087, //CJK UNIFIED IDEOGRAPH + 0x9085: 0x6088, //CJK UNIFIED IDEOGRAPH + 0x9086: 0x608A, //CJK UNIFIED IDEOGRAPH + 0x9087: 0x608B, //CJK UNIFIED IDEOGRAPH + 0x9088: 0x608E, //CJK UNIFIED IDEOGRAPH + 0x9089: 0x608F, //CJK UNIFIED IDEOGRAPH + 0x908A: 0x6090, //CJK UNIFIED IDEOGRAPH + 0x908B: 0x6091, //CJK UNIFIED IDEOGRAPH + 0x908C: 0x6093, //CJK UNIFIED IDEOGRAPH + 0x908D: 0x6095, //CJK UNIFIED IDEOGRAPH + 0x908E: 0x6097, //CJK UNIFIED IDEOGRAPH + 0x908F: 0x6098, //CJK UNIFIED IDEOGRAPH + 0x9090: 0x6099, //CJK UNIFIED IDEOGRAPH + 0x9091: 0x609C, //CJK UNIFIED IDEOGRAPH + 0x9092: 0x609E, //CJK UNIFIED IDEOGRAPH + 0x9093: 0x60A1, //CJK UNIFIED IDEOGRAPH + 0x9094: 0x60A2, //CJK UNIFIED IDEOGRAPH + 0x9095: 0x60A4, //CJK UNIFIED IDEOGRAPH + 0x9096: 0x60A5, //CJK UNIFIED IDEOGRAPH + 0x9097: 0x60A7, //CJK UNIFIED IDEOGRAPH + 0x9098: 0x60A9, //CJK UNIFIED IDEOGRAPH + 0x9099: 0x60AA, //CJK UNIFIED IDEOGRAPH + 0x909A: 0x60AE, //CJK UNIFIED IDEOGRAPH + 0x909B: 0x60B0, //CJK UNIFIED IDEOGRAPH + 0x909C: 0x60B3, //CJK UNIFIED IDEOGRAPH + 0x909D: 0x60B5, //CJK UNIFIED IDEOGRAPH + 0x909E: 0x60B6, //CJK UNIFIED IDEOGRAPH + 0x909F: 0x60B7, //CJK UNIFIED IDEOGRAPH + 0x90A0: 0x60B9, //CJK UNIFIED IDEOGRAPH + 0x90A1: 0x60BA, //CJK UNIFIED IDEOGRAPH + 0x90A2: 0x60BD, //CJK UNIFIED IDEOGRAPH + 0x90A3: 0x60BE, //CJK UNIFIED IDEOGRAPH + 0x90A4: 0x60BF, //CJK UNIFIED IDEOGRAPH + 0x90A5: 0x60C0, //CJK UNIFIED IDEOGRAPH + 0x90A6: 0x60C1, //CJK UNIFIED IDEOGRAPH + 0x90A7: 0x60C2, //CJK UNIFIED IDEOGRAPH + 0x90A8: 0x60C3, //CJK UNIFIED IDEOGRAPH + 0x90A9: 0x60C4, //CJK UNIFIED IDEOGRAPH + 0x90AA: 0x60C7, //CJK UNIFIED IDEOGRAPH + 0x90AB: 0x60C8, //CJK UNIFIED IDEOGRAPH + 0x90AC: 0x60C9, //CJK UNIFIED IDEOGRAPH + 0x90AD: 0x60CC, //CJK UNIFIED IDEOGRAPH + 0x90AE: 0x60CD, //CJK UNIFIED IDEOGRAPH + 0x90AF: 0x60CE, //CJK UNIFIED IDEOGRAPH + 0x90B0: 0x60CF, //CJK UNIFIED IDEOGRAPH + 0x90B1: 0x60D0, //CJK UNIFIED IDEOGRAPH + 0x90B2: 0x60D2, //CJK UNIFIED IDEOGRAPH + 0x90B3: 0x60D3, //CJK UNIFIED IDEOGRAPH + 0x90B4: 0x60D4, //CJK UNIFIED IDEOGRAPH + 0x90B5: 0x60D6, //CJK UNIFIED IDEOGRAPH + 0x90B6: 0x60D7, //CJK UNIFIED IDEOGRAPH + 0x90B7: 0x60D9, //CJK UNIFIED IDEOGRAPH + 0x90B8: 0x60DB, //CJK UNIFIED IDEOGRAPH + 0x90B9: 0x60DE, //CJK UNIFIED IDEOGRAPH + 0x90BA: 0x60E1, //CJK UNIFIED IDEOGRAPH + 0x90BB: 0x60E2, //CJK UNIFIED IDEOGRAPH + 0x90BC: 0x60E3, //CJK UNIFIED IDEOGRAPH + 0x90BD: 0x60E4, //CJK UNIFIED IDEOGRAPH + 0x90BE: 0x60E5, //CJK UNIFIED IDEOGRAPH + 0x90BF: 0x60EA, //CJK UNIFIED IDEOGRAPH + 0x90C0: 0x60F1, //CJK UNIFIED IDEOGRAPH + 0x90C1: 0x60F2, //CJK UNIFIED IDEOGRAPH + 0x90C2: 0x60F5, //CJK UNIFIED IDEOGRAPH + 0x90C3: 0x60F7, //CJK UNIFIED IDEOGRAPH + 0x90C4: 0x60F8, //CJK UNIFIED IDEOGRAPH + 0x90C5: 0x60FB, //CJK UNIFIED IDEOGRAPH + 0x90C6: 0x60FC, //CJK UNIFIED IDEOGRAPH + 0x90C7: 0x60FD, //CJK UNIFIED IDEOGRAPH + 0x90C8: 0x60FE, //CJK UNIFIED IDEOGRAPH + 0x90C9: 0x60FF, //CJK UNIFIED IDEOGRAPH + 0x90CA: 0x6102, //CJK UNIFIED IDEOGRAPH + 0x90CB: 0x6103, //CJK UNIFIED IDEOGRAPH + 0x90CC: 0x6104, //CJK UNIFIED IDEOGRAPH + 0x90CD: 0x6105, //CJK UNIFIED IDEOGRAPH + 0x90CE: 0x6107, //CJK UNIFIED IDEOGRAPH + 0x90CF: 0x610A, //CJK UNIFIED IDEOGRAPH + 0x90D0: 0x610B, //CJK UNIFIED IDEOGRAPH + 0x90D1: 0x610C, //CJK UNIFIED IDEOGRAPH + 0x90D2: 0x6110, //CJK UNIFIED IDEOGRAPH + 0x90D3: 0x6111, //CJK UNIFIED IDEOGRAPH + 0x90D4: 0x6112, //CJK UNIFIED IDEOGRAPH + 0x90D5: 0x6113, //CJK UNIFIED IDEOGRAPH + 0x90D6: 0x6114, //CJK UNIFIED IDEOGRAPH + 0x90D7: 0x6116, //CJK UNIFIED IDEOGRAPH + 0x90D8: 0x6117, //CJK UNIFIED IDEOGRAPH + 0x90D9: 0x6118, //CJK UNIFIED IDEOGRAPH + 0x90DA: 0x6119, //CJK UNIFIED IDEOGRAPH + 0x90DB: 0x611B, //CJK UNIFIED IDEOGRAPH + 0x90DC: 0x611C, //CJK UNIFIED IDEOGRAPH + 0x90DD: 0x611D, //CJK UNIFIED IDEOGRAPH + 0x90DE: 0x611E, //CJK UNIFIED IDEOGRAPH + 0x90DF: 0x6121, //CJK UNIFIED IDEOGRAPH + 0x90E0: 0x6122, //CJK UNIFIED IDEOGRAPH + 0x90E1: 0x6125, //CJK UNIFIED IDEOGRAPH + 0x90E2: 0x6128, //CJK UNIFIED IDEOGRAPH + 0x90E3: 0x6129, //CJK UNIFIED IDEOGRAPH + 0x90E4: 0x612A, //CJK UNIFIED IDEOGRAPH + 0x90E5: 0x612C, //CJK UNIFIED IDEOGRAPH + 0x90E6: 0x612D, //CJK UNIFIED IDEOGRAPH + 0x90E7: 0x612E, //CJK UNIFIED IDEOGRAPH + 0x90E8: 0x612F, //CJK UNIFIED IDEOGRAPH + 0x90E9: 0x6130, //CJK UNIFIED IDEOGRAPH + 0x90EA: 0x6131, //CJK UNIFIED IDEOGRAPH + 0x90EB: 0x6132, //CJK UNIFIED IDEOGRAPH + 0x90EC: 0x6133, //CJK UNIFIED IDEOGRAPH + 0x90ED: 0x6134, //CJK UNIFIED IDEOGRAPH + 0x90EE: 0x6135, //CJK UNIFIED IDEOGRAPH + 0x90EF: 0x6136, //CJK UNIFIED IDEOGRAPH + 0x90F0: 0x6137, //CJK UNIFIED IDEOGRAPH + 0x90F1: 0x6138, //CJK UNIFIED IDEOGRAPH + 0x90F2: 0x6139, //CJK UNIFIED IDEOGRAPH + 0x90F3: 0x613A, //CJK UNIFIED IDEOGRAPH + 0x90F4: 0x613B, //CJK UNIFIED IDEOGRAPH + 0x90F5: 0x613C, //CJK UNIFIED IDEOGRAPH + 0x90F6: 0x613D, //CJK UNIFIED IDEOGRAPH + 0x90F7: 0x613E, //CJK UNIFIED IDEOGRAPH + 0x90F8: 0x6140, //CJK UNIFIED IDEOGRAPH + 0x90F9: 0x6141, //CJK UNIFIED IDEOGRAPH + 0x90FA: 0x6142, //CJK UNIFIED IDEOGRAPH + 0x90FB: 0x6143, //CJK UNIFIED IDEOGRAPH + 0x90FC: 0x6144, //CJK UNIFIED IDEOGRAPH + 0x90FD: 0x6145, //CJK UNIFIED IDEOGRAPH + 0x90FE: 0x6146, //CJK UNIFIED IDEOGRAPH + 0x9140: 0x6147, //CJK UNIFIED IDEOGRAPH + 0x9141: 0x6149, //CJK UNIFIED IDEOGRAPH + 0x9142: 0x614B, //CJK UNIFIED IDEOGRAPH + 0x9143: 0x614D, //CJK UNIFIED IDEOGRAPH + 0x9144: 0x614F, //CJK UNIFIED IDEOGRAPH + 0x9145: 0x6150, //CJK UNIFIED IDEOGRAPH + 0x9146: 0x6152, //CJK UNIFIED IDEOGRAPH + 0x9147: 0x6153, //CJK UNIFIED IDEOGRAPH + 0x9148: 0x6154, //CJK UNIFIED IDEOGRAPH + 0x9149: 0x6156, //CJK UNIFIED IDEOGRAPH + 0x914A: 0x6157, //CJK UNIFIED IDEOGRAPH + 0x914B: 0x6158, //CJK UNIFIED IDEOGRAPH + 0x914C: 0x6159, //CJK UNIFIED IDEOGRAPH + 0x914D: 0x615A, //CJK UNIFIED IDEOGRAPH + 0x914E: 0x615B, //CJK UNIFIED IDEOGRAPH + 0x914F: 0x615C, //CJK UNIFIED IDEOGRAPH + 0x9150: 0x615E, //CJK UNIFIED IDEOGRAPH + 0x9151: 0x615F, //CJK UNIFIED IDEOGRAPH + 0x9152: 0x6160, //CJK UNIFIED IDEOGRAPH + 0x9153: 0x6161, //CJK UNIFIED IDEOGRAPH + 0x9154: 0x6163, //CJK UNIFIED IDEOGRAPH + 0x9155: 0x6164, //CJK UNIFIED IDEOGRAPH + 0x9156: 0x6165, //CJK UNIFIED IDEOGRAPH + 0x9157: 0x6166, //CJK UNIFIED IDEOGRAPH + 0x9158: 0x6169, //CJK UNIFIED IDEOGRAPH + 0x9159: 0x616A, //CJK UNIFIED IDEOGRAPH + 0x915A: 0x616B, //CJK UNIFIED IDEOGRAPH + 0x915B: 0x616C, //CJK UNIFIED IDEOGRAPH + 0x915C: 0x616D, //CJK UNIFIED IDEOGRAPH + 0x915D: 0x616E, //CJK UNIFIED IDEOGRAPH + 0x915E: 0x616F, //CJK UNIFIED IDEOGRAPH + 0x915F: 0x6171, //CJK UNIFIED IDEOGRAPH + 0x9160: 0x6172, //CJK UNIFIED IDEOGRAPH + 0x9161: 0x6173, //CJK UNIFIED IDEOGRAPH + 0x9162: 0x6174, //CJK UNIFIED IDEOGRAPH + 0x9163: 0x6176, //CJK UNIFIED IDEOGRAPH + 0x9164: 0x6178, //CJK UNIFIED IDEOGRAPH + 0x9165: 0x6179, //CJK UNIFIED IDEOGRAPH + 0x9166: 0x617A, //CJK UNIFIED IDEOGRAPH + 0x9167: 0x617B, //CJK UNIFIED IDEOGRAPH + 0x9168: 0x617C, //CJK UNIFIED IDEOGRAPH + 0x9169: 0x617D, //CJK UNIFIED IDEOGRAPH + 0x916A: 0x617E, //CJK UNIFIED IDEOGRAPH + 0x916B: 0x617F, //CJK UNIFIED IDEOGRAPH + 0x916C: 0x6180, //CJK UNIFIED IDEOGRAPH + 0x916D: 0x6181, //CJK UNIFIED IDEOGRAPH + 0x916E: 0x6182, //CJK UNIFIED IDEOGRAPH + 0x916F: 0x6183, //CJK UNIFIED IDEOGRAPH + 0x9170: 0x6184, //CJK UNIFIED IDEOGRAPH + 0x9171: 0x6185, //CJK UNIFIED IDEOGRAPH + 0x9172: 0x6186, //CJK UNIFIED IDEOGRAPH + 0x9173: 0x6187, //CJK UNIFIED IDEOGRAPH + 0x9174: 0x6188, //CJK UNIFIED IDEOGRAPH + 0x9175: 0x6189, //CJK UNIFIED IDEOGRAPH + 0x9176: 0x618A, //CJK UNIFIED IDEOGRAPH + 0x9177: 0x618C, //CJK UNIFIED IDEOGRAPH + 0x9178: 0x618D, //CJK UNIFIED IDEOGRAPH + 0x9179: 0x618F, //CJK UNIFIED IDEOGRAPH + 0x917A: 0x6190, //CJK UNIFIED IDEOGRAPH + 0x917B: 0x6191, //CJK UNIFIED IDEOGRAPH + 0x917C: 0x6192, //CJK UNIFIED IDEOGRAPH + 0x917D: 0x6193, //CJK UNIFIED IDEOGRAPH + 0x917E: 0x6195, //CJK UNIFIED IDEOGRAPH + 0x9180: 0x6196, //CJK UNIFIED IDEOGRAPH + 0x9181: 0x6197, //CJK UNIFIED IDEOGRAPH + 0x9182: 0x6198, //CJK UNIFIED IDEOGRAPH + 0x9183: 0x6199, //CJK UNIFIED IDEOGRAPH + 0x9184: 0x619A, //CJK UNIFIED IDEOGRAPH + 0x9185: 0x619B, //CJK UNIFIED IDEOGRAPH + 0x9186: 0x619C, //CJK UNIFIED IDEOGRAPH + 0x9187: 0x619E, //CJK UNIFIED IDEOGRAPH + 0x9188: 0x619F, //CJK UNIFIED IDEOGRAPH + 0x9189: 0x61A0, //CJK UNIFIED IDEOGRAPH + 0x918A: 0x61A1, //CJK UNIFIED IDEOGRAPH + 0x918B: 0x61A2, //CJK UNIFIED IDEOGRAPH + 0x918C: 0x61A3, //CJK UNIFIED IDEOGRAPH + 0x918D: 0x61A4, //CJK UNIFIED IDEOGRAPH + 0x918E: 0x61A5, //CJK UNIFIED IDEOGRAPH + 0x918F: 0x61A6, //CJK UNIFIED IDEOGRAPH + 0x9190: 0x61AA, //CJK UNIFIED IDEOGRAPH + 0x9191: 0x61AB, //CJK UNIFIED IDEOGRAPH + 0x9192: 0x61AD, //CJK UNIFIED IDEOGRAPH + 0x9193: 0x61AE, //CJK UNIFIED IDEOGRAPH + 0x9194: 0x61AF, //CJK UNIFIED IDEOGRAPH + 0x9195: 0x61B0, //CJK UNIFIED IDEOGRAPH + 0x9196: 0x61B1, //CJK UNIFIED IDEOGRAPH + 0x9197: 0x61B2, //CJK UNIFIED IDEOGRAPH + 0x9198: 0x61B3, //CJK UNIFIED IDEOGRAPH + 0x9199: 0x61B4, //CJK UNIFIED IDEOGRAPH + 0x919A: 0x61B5, //CJK UNIFIED IDEOGRAPH + 0x919B: 0x61B6, //CJK UNIFIED IDEOGRAPH + 0x919C: 0x61B8, //CJK UNIFIED IDEOGRAPH + 0x919D: 0x61B9, //CJK UNIFIED IDEOGRAPH + 0x919E: 0x61BA, //CJK UNIFIED IDEOGRAPH + 0x919F: 0x61BB, //CJK UNIFIED IDEOGRAPH + 0x91A0: 0x61BC, //CJK UNIFIED IDEOGRAPH + 0x91A1: 0x61BD, //CJK UNIFIED IDEOGRAPH + 0x91A2: 0x61BF, //CJK UNIFIED IDEOGRAPH + 0x91A3: 0x61C0, //CJK UNIFIED IDEOGRAPH + 0x91A4: 0x61C1, //CJK UNIFIED IDEOGRAPH + 0x91A5: 0x61C3, //CJK UNIFIED IDEOGRAPH + 0x91A6: 0x61C4, //CJK UNIFIED IDEOGRAPH + 0x91A7: 0x61C5, //CJK UNIFIED IDEOGRAPH + 0x91A8: 0x61C6, //CJK UNIFIED IDEOGRAPH + 0x91A9: 0x61C7, //CJK UNIFIED IDEOGRAPH + 0x91AA: 0x61C9, //CJK UNIFIED IDEOGRAPH + 0x91AB: 0x61CC, //CJK UNIFIED IDEOGRAPH + 0x91AC: 0x61CD, //CJK UNIFIED IDEOGRAPH + 0x91AD: 0x61CE, //CJK UNIFIED IDEOGRAPH + 0x91AE: 0x61CF, //CJK UNIFIED IDEOGRAPH + 0x91AF: 0x61D0, //CJK UNIFIED IDEOGRAPH + 0x91B0: 0x61D3, //CJK UNIFIED IDEOGRAPH + 0x91B1: 0x61D5, //CJK UNIFIED IDEOGRAPH + 0x91B2: 0x61D6, //CJK UNIFIED IDEOGRAPH + 0x91B3: 0x61D7, //CJK UNIFIED IDEOGRAPH + 0x91B4: 0x61D8, //CJK UNIFIED IDEOGRAPH + 0x91B5: 0x61D9, //CJK UNIFIED IDEOGRAPH + 0x91B6: 0x61DA, //CJK UNIFIED IDEOGRAPH + 0x91B7: 0x61DB, //CJK UNIFIED IDEOGRAPH + 0x91B8: 0x61DC, //CJK UNIFIED IDEOGRAPH + 0x91B9: 0x61DD, //CJK UNIFIED IDEOGRAPH + 0x91BA: 0x61DE, //CJK UNIFIED IDEOGRAPH + 0x91BB: 0x61DF, //CJK UNIFIED IDEOGRAPH + 0x91BC: 0x61E0, //CJK UNIFIED IDEOGRAPH + 0x91BD: 0x61E1, //CJK UNIFIED IDEOGRAPH + 0x91BE: 0x61E2, //CJK UNIFIED IDEOGRAPH + 0x91BF: 0x61E3, //CJK UNIFIED IDEOGRAPH + 0x91C0: 0x61E4, //CJK UNIFIED IDEOGRAPH + 0x91C1: 0x61E5, //CJK UNIFIED IDEOGRAPH + 0x91C2: 0x61E7, //CJK UNIFIED IDEOGRAPH + 0x91C3: 0x61E8, //CJK UNIFIED IDEOGRAPH + 0x91C4: 0x61E9, //CJK UNIFIED IDEOGRAPH + 0x91C5: 0x61EA, //CJK UNIFIED IDEOGRAPH + 0x91C6: 0x61EB, //CJK UNIFIED IDEOGRAPH + 0x91C7: 0x61EC, //CJK UNIFIED IDEOGRAPH + 0x91C8: 0x61ED, //CJK UNIFIED IDEOGRAPH + 0x91C9: 0x61EE, //CJK UNIFIED IDEOGRAPH + 0x91CA: 0x61EF, //CJK UNIFIED IDEOGRAPH + 0x91CB: 0x61F0, //CJK UNIFIED IDEOGRAPH + 0x91CC: 0x61F1, //CJK UNIFIED IDEOGRAPH + 0x91CD: 0x61F2, //CJK UNIFIED IDEOGRAPH + 0x91CE: 0x61F3, //CJK UNIFIED IDEOGRAPH + 0x91CF: 0x61F4, //CJK UNIFIED IDEOGRAPH + 0x91D0: 0x61F6, //CJK UNIFIED IDEOGRAPH + 0x91D1: 0x61F7, //CJK UNIFIED IDEOGRAPH + 0x91D2: 0x61F8, //CJK UNIFIED IDEOGRAPH + 0x91D3: 0x61F9, //CJK UNIFIED IDEOGRAPH + 0x91D4: 0x61FA, //CJK UNIFIED IDEOGRAPH + 0x91D5: 0x61FB, //CJK UNIFIED IDEOGRAPH + 0x91D6: 0x61FC, //CJK UNIFIED IDEOGRAPH + 0x91D7: 0x61FD, //CJK UNIFIED IDEOGRAPH + 0x91D8: 0x61FE, //CJK UNIFIED IDEOGRAPH + 0x91D9: 0x6200, //CJK UNIFIED IDEOGRAPH + 0x91DA: 0x6201, //CJK UNIFIED IDEOGRAPH + 0x91DB: 0x6202, //CJK UNIFIED IDEOGRAPH + 0x91DC: 0x6203, //CJK UNIFIED IDEOGRAPH + 0x91DD: 0x6204, //CJK UNIFIED IDEOGRAPH + 0x91DE: 0x6205, //CJK UNIFIED IDEOGRAPH + 0x91DF: 0x6207, //CJK UNIFIED IDEOGRAPH + 0x91E0: 0x6209, //CJK UNIFIED IDEOGRAPH + 0x91E1: 0x6213, //CJK UNIFIED IDEOGRAPH + 0x91E2: 0x6214, //CJK UNIFIED IDEOGRAPH + 0x91E3: 0x6219, //CJK UNIFIED IDEOGRAPH + 0x91E4: 0x621C, //CJK UNIFIED IDEOGRAPH + 0x91E5: 0x621D, //CJK UNIFIED IDEOGRAPH + 0x91E6: 0x621E, //CJK UNIFIED IDEOGRAPH + 0x91E7: 0x6220, //CJK UNIFIED IDEOGRAPH + 0x91E8: 0x6223, //CJK UNIFIED IDEOGRAPH + 0x91E9: 0x6226, //CJK UNIFIED IDEOGRAPH + 0x91EA: 0x6227, //CJK UNIFIED IDEOGRAPH + 0x91EB: 0x6228, //CJK UNIFIED IDEOGRAPH + 0x91EC: 0x6229, //CJK UNIFIED IDEOGRAPH + 0x91ED: 0x622B, //CJK UNIFIED IDEOGRAPH + 0x91EE: 0x622D, //CJK UNIFIED IDEOGRAPH + 0x91EF: 0x622F, //CJK UNIFIED IDEOGRAPH + 0x91F0: 0x6230, //CJK UNIFIED IDEOGRAPH + 0x91F1: 0x6231, //CJK UNIFIED IDEOGRAPH + 0x91F2: 0x6232, //CJK UNIFIED IDEOGRAPH + 0x91F3: 0x6235, //CJK UNIFIED IDEOGRAPH + 0x91F4: 0x6236, //CJK UNIFIED IDEOGRAPH + 0x91F5: 0x6238, //CJK UNIFIED IDEOGRAPH + 0x91F6: 0x6239, //CJK UNIFIED IDEOGRAPH + 0x91F7: 0x623A, //CJK UNIFIED IDEOGRAPH + 0x91F8: 0x623B, //CJK UNIFIED IDEOGRAPH + 0x91F9: 0x623C, //CJK UNIFIED IDEOGRAPH + 0x91FA: 0x6242, //CJK UNIFIED IDEOGRAPH + 0x91FB: 0x6244, //CJK UNIFIED IDEOGRAPH + 0x91FC: 0x6245, //CJK UNIFIED IDEOGRAPH + 0x91FD: 0x6246, //CJK UNIFIED IDEOGRAPH + 0x91FE: 0x624A, //CJK UNIFIED IDEOGRAPH + 0x9240: 0x624F, //CJK UNIFIED IDEOGRAPH + 0x9241: 0x6250, //CJK UNIFIED IDEOGRAPH + 0x9242: 0x6255, //CJK UNIFIED IDEOGRAPH + 0x9243: 0x6256, //CJK UNIFIED IDEOGRAPH + 0x9244: 0x6257, //CJK UNIFIED IDEOGRAPH + 0x9245: 0x6259, //CJK UNIFIED IDEOGRAPH + 0x9246: 0x625A, //CJK UNIFIED IDEOGRAPH + 0x9247: 0x625C, //CJK UNIFIED IDEOGRAPH + 0x9248: 0x625D, //CJK UNIFIED IDEOGRAPH + 0x9249: 0x625E, //CJK UNIFIED IDEOGRAPH + 0x924A: 0x625F, //CJK UNIFIED IDEOGRAPH + 0x924B: 0x6260, //CJK UNIFIED IDEOGRAPH + 0x924C: 0x6261, //CJK UNIFIED IDEOGRAPH + 0x924D: 0x6262, //CJK UNIFIED IDEOGRAPH + 0x924E: 0x6264, //CJK UNIFIED IDEOGRAPH + 0x924F: 0x6265, //CJK UNIFIED IDEOGRAPH + 0x9250: 0x6268, //CJK UNIFIED IDEOGRAPH + 0x9251: 0x6271, //CJK UNIFIED IDEOGRAPH + 0x9252: 0x6272, //CJK UNIFIED IDEOGRAPH + 0x9253: 0x6274, //CJK UNIFIED IDEOGRAPH + 0x9254: 0x6275, //CJK UNIFIED IDEOGRAPH + 0x9255: 0x6277, //CJK UNIFIED IDEOGRAPH + 0x9256: 0x6278, //CJK UNIFIED IDEOGRAPH + 0x9257: 0x627A, //CJK UNIFIED IDEOGRAPH + 0x9258: 0x627B, //CJK UNIFIED IDEOGRAPH + 0x9259: 0x627D, //CJK UNIFIED IDEOGRAPH + 0x925A: 0x6281, //CJK UNIFIED IDEOGRAPH + 0x925B: 0x6282, //CJK UNIFIED IDEOGRAPH + 0x925C: 0x6283, //CJK UNIFIED IDEOGRAPH + 0x925D: 0x6285, //CJK UNIFIED IDEOGRAPH + 0x925E: 0x6286, //CJK UNIFIED IDEOGRAPH + 0x925F: 0x6287, //CJK UNIFIED IDEOGRAPH + 0x9260: 0x6288, //CJK UNIFIED IDEOGRAPH + 0x9261: 0x628B, //CJK UNIFIED IDEOGRAPH + 0x9262: 0x628C, //CJK UNIFIED IDEOGRAPH + 0x9263: 0x628D, //CJK UNIFIED IDEOGRAPH + 0x9264: 0x628E, //CJK UNIFIED IDEOGRAPH + 0x9265: 0x628F, //CJK UNIFIED IDEOGRAPH + 0x9266: 0x6290, //CJK UNIFIED IDEOGRAPH + 0x9267: 0x6294, //CJK UNIFIED IDEOGRAPH + 0x9268: 0x6299, //CJK UNIFIED IDEOGRAPH + 0x9269: 0x629C, //CJK UNIFIED IDEOGRAPH + 0x926A: 0x629D, //CJK UNIFIED IDEOGRAPH + 0x926B: 0x629E, //CJK UNIFIED IDEOGRAPH + 0x926C: 0x62A3, //CJK UNIFIED IDEOGRAPH + 0x926D: 0x62A6, //CJK UNIFIED IDEOGRAPH + 0x926E: 0x62A7, //CJK UNIFIED IDEOGRAPH + 0x926F: 0x62A9, //CJK UNIFIED IDEOGRAPH + 0x9270: 0x62AA, //CJK UNIFIED IDEOGRAPH + 0x9271: 0x62AD, //CJK UNIFIED IDEOGRAPH + 0x9272: 0x62AE, //CJK UNIFIED IDEOGRAPH + 0x9273: 0x62AF, //CJK UNIFIED IDEOGRAPH + 0x9274: 0x62B0, //CJK UNIFIED IDEOGRAPH + 0x9275: 0x62B2, //CJK UNIFIED IDEOGRAPH + 0x9276: 0x62B3, //CJK UNIFIED IDEOGRAPH + 0x9277: 0x62B4, //CJK UNIFIED IDEOGRAPH + 0x9278: 0x62B6, //CJK UNIFIED IDEOGRAPH + 0x9279: 0x62B7, //CJK UNIFIED IDEOGRAPH + 0x927A: 0x62B8, //CJK UNIFIED IDEOGRAPH + 0x927B: 0x62BA, //CJK UNIFIED IDEOGRAPH + 0x927C: 0x62BE, //CJK UNIFIED IDEOGRAPH + 0x927D: 0x62C0, //CJK UNIFIED IDEOGRAPH + 0x927E: 0x62C1, //CJK UNIFIED IDEOGRAPH + 0x9280: 0x62C3, //CJK UNIFIED IDEOGRAPH + 0x9281: 0x62CB, //CJK UNIFIED IDEOGRAPH + 0x9282: 0x62CF, //CJK UNIFIED IDEOGRAPH + 0x9283: 0x62D1, //CJK UNIFIED IDEOGRAPH + 0x9284: 0x62D5, //CJK UNIFIED IDEOGRAPH + 0x9285: 0x62DD, //CJK UNIFIED IDEOGRAPH + 0x9286: 0x62DE, //CJK UNIFIED IDEOGRAPH + 0x9287: 0x62E0, //CJK UNIFIED IDEOGRAPH + 0x9288: 0x62E1, //CJK UNIFIED IDEOGRAPH + 0x9289: 0x62E4, //CJK UNIFIED IDEOGRAPH + 0x928A: 0x62EA, //CJK UNIFIED IDEOGRAPH + 0x928B: 0x62EB, //CJK UNIFIED IDEOGRAPH + 0x928C: 0x62F0, //CJK UNIFIED IDEOGRAPH + 0x928D: 0x62F2, //CJK UNIFIED IDEOGRAPH + 0x928E: 0x62F5, //CJK UNIFIED IDEOGRAPH + 0x928F: 0x62F8, //CJK UNIFIED IDEOGRAPH + 0x9290: 0x62F9, //CJK UNIFIED IDEOGRAPH + 0x9291: 0x62FA, //CJK UNIFIED IDEOGRAPH + 0x9292: 0x62FB, //CJK UNIFIED IDEOGRAPH + 0x9293: 0x6300, //CJK UNIFIED IDEOGRAPH + 0x9294: 0x6303, //CJK UNIFIED IDEOGRAPH + 0x9295: 0x6304, //CJK UNIFIED IDEOGRAPH + 0x9296: 0x6305, //CJK UNIFIED IDEOGRAPH + 0x9297: 0x6306, //CJK UNIFIED IDEOGRAPH + 0x9298: 0x630A, //CJK UNIFIED IDEOGRAPH + 0x9299: 0x630B, //CJK UNIFIED IDEOGRAPH + 0x929A: 0x630C, //CJK UNIFIED IDEOGRAPH + 0x929B: 0x630D, //CJK UNIFIED IDEOGRAPH + 0x929C: 0x630F, //CJK UNIFIED IDEOGRAPH + 0x929D: 0x6310, //CJK UNIFIED IDEOGRAPH + 0x929E: 0x6312, //CJK UNIFIED IDEOGRAPH + 0x929F: 0x6313, //CJK UNIFIED IDEOGRAPH + 0x92A0: 0x6314, //CJK UNIFIED IDEOGRAPH + 0x92A1: 0x6315, //CJK UNIFIED IDEOGRAPH + 0x92A2: 0x6317, //CJK UNIFIED IDEOGRAPH + 0x92A3: 0x6318, //CJK UNIFIED IDEOGRAPH + 0x92A4: 0x6319, //CJK UNIFIED IDEOGRAPH + 0x92A5: 0x631C, //CJK UNIFIED IDEOGRAPH + 0x92A6: 0x6326, //CJK UNIFIED IDEOGRAPH + 0x92A7: 0x6327, //CJK UNIFIED IDEOGRAPH + 0x92A8: 0x6329, //CJK UNIFIED IDEOGRAPH + 0x92A9: 0x632C, //CJK UNIFIED IDEOGRAPH + 0x92AA: 0x632D, //CJK UNIFIED IDEOGRAPH + 0x92AB: 0x632E, //CJK UNIFIED IDEOGRAPH + 0x92AC: 0x6330, //CJK UNIFIED IDEOGRAPH + 0x92AD: 0x6331, //CJK UNIFIED IDEOGRAPH + 0x92AE: 0x6333, //CJK UNIFIED IDEOGRAPH + 0x92AF: 0x6334, //CJK UNIFIED IDEOGRAPH + 0x92B0: 0x6335, //CJK UNIFIED IDEOGRAPH + 0x92B1: 0x6336, //CJK UNIFIED IDEOGRAPH + 0x92B2: 0x6337, //CJK UNIFIED IDEOGRAPH + 0x92B3: 0x6338, //CJK UNIFIED IDEOGRAPH + 0x92B4: 0x633B, //CJK UNIFIED IDEOGRAPH + 0x92B5: 0x633C, //CJK UNIFIED IDEOGRAPH + 0x92B6: 0x633E, //CJK UNIFIED IDEOGRAPH + 0x92B7: 0x633F, //CJK UNIFIED IDEOGRAPH + 0x92B8: 0x6340, //CJK UNIFIED IDEOGRAPH + 0x92B9: 0x6341, //CJK UNIFIED IDEOGRAPH + 0x92BA: 0x6344, //CJK UNIFIED IDEOGRAPH + 0x92BB: 0x6347, //CJK UNIFIED IDEOGRAPH + 0x92BC: 0x6348, //CJK UNIFIED IDEOGRAPH + 0x92BD: 0x634A, //CJK UNIFIED IDEOGRAPH + 0x92BE: 0x6351, //CJK UNIFIED IDEOGRAPH + 0x92BF: 0x6352, //CJK UNIFIED IDEOGRAPH + 0x92C0: 0x6353, //CJK UNIFIED IDEOGRAPH + 0x92C1: 0x6354, //CJK UNIFIED IDEOGRAPH + 0x92C2: 0x6356, //CJK UNIFIED IDEOGRAPH + 0x92C3: 0x6357, //CJK UNIFIED IDEOGRAPH + 0x92C4: 0x6358, //CJK UNIFIED IDEOGRAPH + 0x92C5: 0x6359, //CJK UNIFIED IDEOGRAPH + 0x92C6: 0x635A, //CJK UNIFIED IDEOGRAPH + 0x92C7: 0x635B, //CJK UNIFIED IDEOGRAPH + 0x92C8: 0x635C, //CJK UNIFIED IDEOGRAPH + 0x92C9: 0x635D, //CJK UNIFIED IDEOGRAPH + 0x92CA: 0x6360, //CJK UNIFIED IDEOGRAPH + 0x92CB: 0x6364, //CJK UNIFIED IDEOGRAPH + 0x92CC: 0x6365, //CJK UNIFIED IDEOGRAPH + 0x92CD: 0x6366, //CJK UNIFIED IDEOGRAPH + 0x92CE: 0x6368, //CJK UNIFIED IDEOGRAPH + 0x92CF: 0x636A, //CJK UNIFIED IDEOGRAPH + 0x92D0: 0x636B, //CJK UNIFIED IDEOGRAPH + 0x92D1: 0x636C, //CJK UNIFIED IDEOGRAPH + 0x92D2: 0x636F, //CJK UNIFIED IDEOGRAPH + 0x92D3: 0x6370, //CJK UNIFIED IDEOGRAPH + 0x92D4: 0x6372, //CJK UNIFIED IDEOGRAPH + 0x92D5: 0x6373, //CJK UNIFIED IDEOGRAPH + 0x92D6: 0x6374, //CJK UNIFIED IDEOGRAPH + 0x92D7: 0x6375, //CJK UNIFIED IDEOGRAPH + 0x92D8: 0x6378, //CJK UNIFIED IDEOGRAPH + 0x92D9: 0x6379, //CJK UNIFIED IDEOGRAPH + 0x92DA: 0x637C, //CJK UNIFIED IDEOGRAPH + 0x92DB: 0x637D, //CJK UNIFIED IDEOGRAPH + 0x92DC: 0x637E, //CJK UNIFIED IDEOGRAPH + 0x92DD: 0x637F, //CJK UNIFIED IDEOGRAPH + 0x92DE: 0x6381, //CJK UNIFIED IDEOGRAPH + 0x92DF: 0x6383, //CJK UNIFIED IDEOGRAPH + 0x92E0: 0x6384, //CJK UNIFIED IDEOGRAPH + 0x92E1: 0x6385, //CJK UNIFIED IDEOGRAPH + 0x92E2: 0x6386, //CJK UNIFIED IDEOGRAPH + 0x92E3: 0x638B, //CJK UNIFIED IDEOGRAPH + 0x92E4: 0x638D, //CJK UNIFIED IDEOGRAPH + 0x92E5: 0x6391, //CJK UNIFIED IDEOGRAPH + 0x92E6: 0x6393, //CJK UNIFIED IDEOGRAPH + 0x92E7: 0x6394, //CJK UNIFIED IDEOGRAPH + 0x92E8: 0x6395, //CJK UNIFIED IDEOGRAPH + 0x92E9: 0x6397, //CJK UNIFIED IDEOGRAPH + 0x92EA: 0x6399, //CJK UNIFIED IDEOGRAPH + 0x92EB: 0x639A, //CJK UNIFIED IDEOGRAPH + 0x92EC: 0x639B, //CJK UNIFIED IDEOGRAPH + 0x92ED: 0x639C, //CJK UNIFIED IDEOGRAPH + 0x92EE: 0x639D, //CJK UNIFIED IDEOGRAPH + 0x92EF: 0x639E, //CJK UNIFIED IDEOGRAPH + 0x92F0: 0x639F, //CJK UNIFIED IDEOGRAPH + 0x92F1: 0x63A1, //CJK UNIFIED IDEOGRAPH + 0x92F2: 0x63A4, //CJK UNIFIED IDEOGRAPH + 0x92F3: 0x63A6, //CJK UNIFIED IDEOGRAPH + 0x92F4: 0x63AB, //CJK UNIFIED IDEOGRAPH + 0x92F5: 0x63AF, //CJK UNIFIED IDEOGRAPH + 0x92F6: 0x63B1, //CJK UNIFIED IDEOGRAPH + 0x92F7: 0x63B2, //CJK UNIFIED IDEOGRAPH + 0x92F8: 0x63B5, //CJK UNIFIED IDEOGRAPH + 0x92F9: 0x63B6, //CJK UNIFIED IDEOGRAPH + 0x92FA: 0x63B9, //CJK UNIFIED IDEOGRAPH + 0x92FB: 0x63BB, //CJK UNIFIED IDEOGRAPH + 0x92FC: 0x63BD, //CJK UNIFIED IDEOGRAPH + 0x92FD: 0x63BF, //CJK UNIFIED IDEOGRAPH + 0x92FE: 0x63C0, //CJK UNIFIED IDEOGRAPH + 0x9340: 0x63C1, //CJK UNIFIED IDEOGRAPH + 0x9341: 0x63C2, //CJK UNIFIED IDEOGRAPH + 0x9342: 0x63C3, //CJK UNIFIED IDEOGRAPH + 0x9343: 0x63C5, //CJK UNIFIED IDEOGRAPH + 0x9344: 0x63C7, //CJK UNIFIED IDEOGRAPH + 0x9345: 0x63C8, //CJK UNIFIED IDEOGRAPH + 0x9346: 0x63CA, //CJK UNIFIED IDEOGRAPH + 0x9347: 0x63CB, //CJK UNIFIED IDEOGRAPH + 0x9348: 0x63CC, //CJK UNIFIED IDEOGRAPH + 0x9349: 0x63D1, //CJK UNIFIED IDEOGRAPH + 0x934A: 0x63D3, //CJK UNIFIED IDEOGRAPH + 0x934B: 0x63D4, //CJK UNIFIED IDEOGRAPH + 0x934C: 0x63D5, //CJK UNIFIED IDEOGRAPH + 0x934D: 0x63D7, //CJK UNIFIED IDEOGRAPH + 0x934E: 0x63D8, //CJK UNIFIED IDEOGRAPH + 0x934F: 0x63D9, //CJK UNIFIED IDEOGRAPH + 0x9350: 0x63DA, //CJK UNIFIED IDEOGRAPH + 0x9351: 0x63DB, //CJK UNIFIED IDEOGRAPH + 0x9352: 0x63DC, //CJK UNIFIED IDEOGRAPH + 0x9353: 0x63DD, //CJK UNIFIED IDEOGRAPH + 0x9354: 0x63DF, //CJK UNIFIED IDEOGRAPH + 0x9355: 0x63E2, //CJK UNIFIED IDEOGRAPH + 0x9356: 0x63E4, //CJK UNIFIED IDEOGRAPH + 0x9357: 0x63E5, //CJK UNIFIED IDEOGRAPH + 0x9358: 0x63E6, //CJK UNIFIED IDEOGRAPH + 0x9359: 0x63E7, //CJK UNIFIED IDEOGRAPH + 0x935A: 0x63E8, //CJK UNIFIED IDEOGRAPH + 0x935B: 0x63EB, //CJK UNIFIED IDEOGRAPH + 0x935C: 0x63EC, //CJK UNIFIED IDEOGRAPH + 0x935D: 0x63EE, //CJK UNIFIED IDEOGRAPH + 0x935E: 0x63EF, //CJK UNIFIED IDEOGRAPH + 0x935F: 0x63F0, //CJK UNIFIED IDEOGRAPH + 0x9360: 0x63F1, //CJK UNIFIED IDEOGRAPH + 0x9361: 0x63F3, //CJK UNIFIED IDEOGRAPH + 0x9362: 0x63F5, //CJK UNIFIED IDEOGRAPH + 0x9363: 0x63F7, //CJK UNIFIED IDEOGRAPH + 0x9364: 0x63F9, //CJK UNIFIED IDEOGRAPH + 0x9365: 0x63FA, //CJK UNIFIED IDEOGRAPH + 0x9366: 0x63FB, //CJK UNIFIED IDEOGRAPH + 0x9367: 0x63FC, //CJK UNIFIED IDEOGRAPH + 0x9368: 0x63FE, //CJK UNIFIED IDEOGRAPH + 0x9369: 0x6403, //CJK UNIFIED IDEOGRAPH + 0x936A: 0x6404, //CJK UNIFIED IDEOGRAPH + 0x936B: 0x6406, //CJK UNIFIED IDEOGRAPH + 0x936C: 0x6407, //CJK UNIFIED IDEOGRAPH + 0x936D: 0x6408, //CJK UNIFIED IDEOGRAPH + 0x936E: 0x6409, //CJK UNIFIED IDEOGRAPH + 0x936F: 0x640A, //CJK UNIFIED IDEOGRAPH + 0x9370: 0x640D, //CJK UNIFIED IDEOGRAPH + 0x9371: 0x640E, //CJK UNIFIED IDEOGRAPH + 0x9372: 0x6411, //CJK UNIFIED IDEOGRAPH + 0x9373: 0x6412, //CJK UNIFIED IDEOGRAPH + 0x9374: 0x6415, //CJK UNIFIED IDEOGRAPH + 0x9375: 0x6416, //CJK UNIFIED IDEOGRAPH + 0x9376: 0x6417, //CJK UNIFIED IDEOGRAPH + 0x9377: 0x6418, //CJK UNIFIED IDEOGRAPH + 0x9378: 0x6419, //CJK UNIFIED IDEOGRAPH + 0x9379: 0x641A, //CJK UNIFIED IDEOGRAPH + 0x937A: 0x641D, //CJK UNIFIED IDEOGRAPH + 0x937B: 0x641F, //CJK UNIFIED IDEOGRAPH + 0x937C: 0x6422, //CJK UNIFIED IDEOGRAPH + 0x937D: 0x6423, //CJK UNIFIED IDEOGRAPH + 0x937E: 0x6424, //CJK UNIFIED IDEOGRAPH + 0x9380: 0x6425, //CJK UNIFIED IDEOGRAPH + 0x9381: 0x6427, //CJK UNIFIED IDEOGRAPH + 0x9382: 0x6428, //CJK UNIFIED IDEOGRAPH + 0x9383: 0x6429, //CJK UNIFIED IDEOGRAPH + 0x9384: 0x642B, //CJK UNIFIED IDEOGRAPH + 0x9385: 0x642E, //CJK UNIFIED IDEOGRAPH + 0x9386: 0x642F, //CJK UNIFIED IDEOGRAPH + 0x9387: 0x6430, //CJK UNIFIED IDEOGRAPH + 0x9388: 0x6431, //CJK UNIFIED IDEOGRAPH + 0x9389: 0x6432, //CJK UNIFIED IDEOGRAPH + 0x938A: 0x6433, //CJK UNIFIED IDEOGRAPH + 0x938B: 0x6435, //CJK UNIFIED IDEOGRAPH + 0x938C: 0x6436, //CJK UNIFIED IDEOGRAPH + 0x938D: 0x6437, //CJK UNIFIED IDEOGRAPH + 0x938E: 0x6438, //CJK UNIFIED IDEOGRAPH + 0x938F: 0x6439, //CJK UNIFIED IDEOGRAPH + 0x9390: 0x643B, //CJK UNIFIED IDEOGRAPH + 0x9391: 0x643C, //CJK UNIFIED IDEOGRAPH + 0x9392: 0x643E, //CJK UNIFIED IDEOGRAPH + 0x9393: 0x6440, //CJK UNIFIED IDEOGRAPH + 0x9394: 0x6442, //CJK UNIFIED IDEOGRAPH + 0x9395: 0x6443, //CJK UNIFIED IDEOGRAPH + 0x9396: 0x6449, //CJK UNIFIED IDEOGRAPH + 0x9397: 0x644B, //CJK UNIFIED IDEOGRAPH + 0x9398: 0x644C, //CJK UNIFIED IDEOGRAPH + 0x9399: 0x644D, //CJK UNIFIED IDEOGRAPH + 0x939A: 0x644E, //CJK UNIFIED IDEOGRAPH + 0x939B: 0x644F, //CJK UNIFIED IDEOGRAPH + 0x939C: 0x6450, //CJK UNIFIED IDEOGRAPH + 0x939D: 0x6451, //CJK UNIFIED IDEOGRAPH + 0x939E: 0x6453, //CJK UNIFIED IDEOGRAPH + 0x939F: 0x6455, //CJK UNIFIED IDEOGRAPH + 0x93A0: 0x6456, //CJK UNIFIED IDEOGRAPH + 0x93A1: 0x6457, //CJK UNIFIED IDEOGRAPH + 0x93A2: 0x6459, //CJK UNIFIED IDEOGRAPH + 0x93A3: 0x645A, //CJK UNIFIED IDEOGRAPH + 0x93A4: 0x645B, //CJK UNIFIED IDEOGRAPH + 0x93A5: 0x645C, //CJK UNIFIED IDEOGRAPH + 0x93A6: 0x645D, //CJK UNIFIED IDEOGRAPH + 0x93A7: 0x645F, //CJK UNIFIED IDEOGRAPH + 0x93A8: 0x6460, //CJK UNIFIED IDEOGRAPH + 0x93A9: 0x6461, //CJK UNIFIED IDEOGRAPH + 0x93AA: 0x6462, //CJK UNIFIED IDEOGRAPH + 0x93AB: 0x6463, //CJK UNIFIED IDEOGRAPH + 0x93AC: 0x6464, //CJK UNIFIED IDEOGRAPH + 0x93AD: 0x6465, //CJK UNIFIED IDEOGRAPH + 0x93AE: 0x6466, //CJK UNIFIED IDEOGRAPH + 0x93AF: 0x6468, //CJK UNIFIED IDEOGRAPH + 0x93B0: 0x646A, //CJK UNIFIED IDEOGRAPH + 0x93B1: 0x646B, //CJK UNIFIED IDEOGRAPH + 0x93B2: 0x646C, //CJK UNIFIED IDEOGRAPH + 0x93B3: 0x646E, //CJK UNIFIED IDEOGRAPH + 0x93B4: 0x646F, //CJK UNIFIED IDEOGRAPH + 0x93B5: 0x6470, //CJK UNIFIED IDEOGRAPH + 0x93B6: 0x6471, //CJK UNIFIED IDEOGRAPH + 0x93B7: 0x6472, //CJK UNIFIED IDEOGRAPH + 0x93B8: 0x6473, //CJK UNIFIED IDEOGRAPH + 0x93B9: 0x6474, //CJK UNIFIED IDEOGRAPH + 0x93BA: 0x6475, //CJK UNIFIED IDEOGRAPH + 0x93BB: 0x6476, //CJK UNIFIED IDEOGRAPH + 0x93BC: 0x6477, //CJK UNIFIED IDEOGRAPH + 0x93BD: 0x647B, //CJK UNIFIED IDEOGRAPH + 0x93BE: 0x647C, //CJK UNIFIED IDEOGRAPH + 0x93BF: 0x647D, //CJK UNIFIED IDEOGRAPH + 0x93C0: 0x647E, //CJK UNIFIED IDEOGRAPH + 0x93C1: 0x647F, //CJK UNIFIED IDEOGRAPH + 0x93C2: 0x6480, //CJK UNIFIED IDEOGRAPH + 0x93C3: 0x6481, //CJK UNIFIED IDEOGRAPH + 0x93C4: 0x6483, //CJK UNIFIED IDEOGRAPH + 0x93C5: 0x6486, //CJK UNIFIED IDEOGRAPH + 0x93C6: 0x6488, //CJK UNIFIED IDEOGRAPH + 0x93C7: 0x6489, //CJK UNIFIED IDEOGRAPH + 0x93C8: 0x648A, //CJK UNIFIED IDEOGRAPH + 0x93C9: 0x648B, //CJK UNIFIED IDEOGRAPH + 0x93CA: 0x648C, //CJK UNIFIED IDEOGRAPH + 0x93CB: 0x648D, //CJK UNIFIED IDEOGRAPH + 0x93CC: 0x648E, //CJK UNIFIED IDEOGRAPH + 0x93CD: 0x648F, //CJK UNIFIED IDEOGRAPH + 0x93CE: 0x6490, //CJK UNIFIED IDEOGRAPH + 0x93CF: 0x6493, //CJK UNIFIED IDEOGRAPH + 0x93D0: 0x6494, //CJK UNIFIED IDEOGRAPH + 0x93D1: 0x6497, //CJK UNIFIED IDEOGRAPH + 0x93D2: 0x6498, //CJK UNIFIED IDEOGRAPH + 0x93D3: 0x649A, //CJK UNIFIED IDEOGRAPH + 0x93D4: 0x649B, //CJK UNIFIED IDEOGRAPH + 0x93D5: 0x649C, //CJK UNIFIED IDEOGRAPH + 0x93D6: 0x649D, //CJK UNIFIED IDEOGRAPH + 0x93D7: 0x649F, //CJK UNIFIED IDEOGRAPH + 0x93D8: 0x64A0, //CJK UNIFIED IDEOGRAPH + 0x93D9: 0x64A1, //CJK UNIFIED IDEOGRAPH + 0x93DA: 0x64A2, //CJK UNIFIED IDEOGRAPH + 0x93DB: 0x64A3, //CJK UNIFIED IDEOGRAPH + 0x93DC: 0x64A5, //CJK UNIFIED IDEOGRAPH + 0x93DD: 0x64A6, //CJK UNIFIED IDEOGRAPH + 0x93DE: 0x64A7, //CJK UNIFIED IDEOGRAPH + 0x93DF: 0x64A8, //CJK UNIFIED IDEOGRAPH + 0x93E0: 0x64AA, //CJK UNIFIED IDEOGRAPH + 0x93E1: 0x64AB, //CJK UNIFIED IDEOGRAPH + 0x93E2: 0x64AF, //CJK UNIFIED IDEOGRAPH + 0x93E3: 0x64B1, //CJK UNIFIED IDEOGRAPH + 0x93E4: 0x64B2, //CJK UNIFIED IDEOGRAPH + 0x93E5: 0x64B3, //CJK UNIFIED IDEOGRAPH + 0x93E6: 0x64B4, //CJK UNIFIED IDEOGRAPH + 0x93E7: 0x64B6, //CJK UNIFIED IDEOGRAPH + 0x93E8: 0x64B9, //CJK UNIFIED IDEOGRAPH + 0x93E9: 0x64BB, //CJK UNIFIED IDEOGRAPH + 0x93EA: 0x64BD, //CJK UNIFIED IDEOGRAPH + 0x93EB: 0x64BE, //CJK UNIFIED IDEOGRAPH + 0x93EC: 0x64BF, //CJK UNIFIED IDEOGRAPH + 0x93ED: 0x64C1, //CJK UNIFIED IDEOGRAPH + 0x93EE: 0x64C3, //CJK UNIFIED IDEOGRAPH + 0x93EF: 0x64C4, //CJK UNIFIED IDEOGRAPH + 0x93F0: 0x64C6, //CJK UNIFIED IDEOGRAPH + 0x93F1: 0x64C7, //CJK UNIFIED IDEOGRAPH + 0x93F2: 0x64C8, //CJK UNIFIED IDEOGRAPH + 0x93F3: 0x64C9, //CJK UNIFIED IDEOGRAPH + 0x93F4: 0x64CA, //CJK UNIFIED IDEOGRAPH + 0x93F5: 0x64CB, //CJK UNIFIED IDEOGRAPH + 0x93F6: 0x64CC, //CJK UNIFIED IDEOGRAPH + 0x93F7: 0x64CF, //CJK UNIFIED IDEOGRAPH + 0x93F8: 0x64D1, //CJK UNIFIED IDEOGRAPH + 0x93F9: 0x64D3, //CJK UNIFIED IDEOGRAPH + 0x93FA: 0x64D4, //CJK UNIFIED IDEOGRAPH + 0x93FB: 0x64D5, //CJK UNIFIED IDEOGRAPH + 0x93FC: 0x64D6, //CJK UNIFIED IDEOGRAPH + 0x93FD: 0x64D9, //CJK UNIFIED IDEOGRAPH + 0x93FE: 0x64DA, //CJK UNIFIED IDEOGRAPH + 0x9440: 0x64DB, //CJK UNIFIED IDEOGRAPH + 0x9441: 0x64DC, //CJK UNIFIED IDEOGRAPH + 0x9442: 0x64DD, //CJK UNIFIED IDEOGRAPH + 0x9443: 0x64DF, //CJK UNIFIED IDEOGRAPH + 0x9444: 0x64E0, //CJK UNIFIED IDEOGRAPH + 0x9445: 0x64E1, //CJK UNIFIED IDEOGRAPH + 0x9446: 0x64E3, //CJK UNIFIED IDEOGRAPH + 0x9447: 0x64E5, //CJK UNIFIED IDEOGRAPH + 0x9448: 0x64E7, //CJK UNIFIED IDEOGRAPH + 0x9449: 0x64E8, //CJK UNIFIED IDEOGRAPH + 0x944A: 0x64E9, //CJK UNIFIED IDEOGRAPH + 0x944B: 0x64EA, //CJK UNIFIED IDEOGRAPH + 0x944C: 0x64EB, //CJK UNIFIED IDEOGRAPH + 0x944D: 0x64EC, //CJK UNIFIED IDEOGRAPH + 0x944E: 0x64ED, //CJK UNIFIED IDEOGRAPH + 0x944F: 0x64EE, //CJK UNIFIED IDEOGRAPH + 0x9450: 0x64EF, //CJK UNIFIED IDEOGRAPH + 0x9451: 0x64F0, //CJK UNIFIED IDEOGRAPH + 0x9452: 0x64F1, //CJK UNIFIED IDEOGRAPH + 0x9453: 0x64F2, //CJK UNIFIED IDEOGRAPH + 0x9454: 0x64F3, //CJK UNIFIED IDEOGRAPH + 0x9455: 0x64F4, //CJK UNIFIED IDEOGRAPH + 0x9456: 0x64F5, //CJK UNIFIED IDEOGRAPH + 0x9457: 0x64F6, //CJK UNIFIED IDEOGRAPH + 0x9458: 0x64F7, //CJK UNIFIED IDEOGRAPH + 0x9459: 0x64F8, //CJK UNIFIED IDEOGRAPH + 0x945A: 0x64F9, //CJK UNIFIED IDEOGRAPH + 0x945B: 0x64FA, //CJK UNIFIED IDEOGRAPH + 0x945C: 0x64FB, //CJK UNIFIED IDEOGRAPH + 0x945D: 0x64FC, //CJK UNIFIED IDEOGRAPH + 0x945E: 0x64FD, //CJK UNIFIED IDEOGRAPH + 0x945F: 0x64FE, //CJK UNIFIED IDEOGRAPH + 0x9460: 0x64FF, //CJK UNIFIED IDEOGRAPH + 0x9461: 0x6501, //CJK UNIFIED IDEOGRAPH + 0x9462: 0x6502, //CJK UNIFIED IDEOGRAPH + 0x9463: 0x6503, //CJK UNIFIED IDEOGRAPH + 0x9464: 0x6504, //CJK UNIFIED IDEOGRAPH + 0x9465: 0x6505, //CJK UNIFIED IDEOGRAPH + 0x9466: 0x6506, //CJK UNIFIED IDEOGRAPH + 0x9467: 0x6507, //CJK UNIFIED IDEOGRAPH + 0x9468: 0x6508, //CJK UNIFIED IDEOGRAPH + 0x9469: 0x650A, //CJK UNIFIED IDEOGRAPH + 0x946A: 0x650B, //CJK UNIFIED IDEOGRAPH + 0x946B: 0x650C, //CJK UNIFIED IDEOGRAPH + 0x946C: 0x650D, //CJK UNIFIED IDEOGRAPH + 0x946D: 0x650E, //CJK UNIFIED IDEOGRAPH + 0x946E: 0x650F, //CJK UNIFIED IDEOGRAPH + 0x946F: 0x6510, //CJK UNIFIED IDEOGRAPH + 0x9470: 0x6511, //CJK UNIFIED IDEOGRAPH + 0x9471: 0x6513, //CJK UNIFIED IDEOGRAPH + 0x9472: 0x6514, //CJK UNIFIED IDEOGRAPH + 0x9473: 0x6515, //CJK UNIFIED IDEOGRAPH + 0x9474: 0x6516, //CJK UNIFIED IDEOGRAPH + 0x9475: 0x6517, //CJK UNIFIED IDEOGRAPH + 0x9476: 0x6519, //CJK UNIFIED IDEOGRAPH + 0x9477: 0x651A, //CJK UNIFIED IDEOGRAPH + 0x9478: 0x651B, //CJK UNIFIED IDEOGRAPH + 0x9479: 0x651C, //CJK UNIFIED IDEOGRAPH + 0x947A: 0x651D, //CJK UNIFIED IDEOGRAPH + 0x947B: 0x651E, //CJK UNIFIED IDEOGRAPH + 0x947C: 0x651F, //CJK UNIFIED IDEOGRAPH + 0x947D: 0x6520, //CJK UNIFIED IDEOGRAPH + 0x947E: 0x6521, //CJK UNIFIED IDEOGRAPH + 0x9480: 0x6522, //CJK UNIFIED IDEOGRAPH + 0x9481: 0x6523, //CJK UNIFIED IDEOGRAPH + 0x9482: 0x6524, //CJK UNIFIED IDEOGRAPH + 0x9483: 0x6526, //CJK UNIFIED IDEOGRAPH + 0x9484: 0x6527, //CJK UNIFIED IDEOGRAPH + 0x9485: 0x6528, //CJK UNIFIED IDEOGRAPH + 0x9486: 0x6529, //CJK UNIFIED IDEOGRAPH + 0x9487: 0x652A, //CJK UNIFIED IDEOGRAPH + 0x9488: 0x652C, //CJK UNIFIED IDEOGRAPH + 0x9489: 0x652D, //CJK UNIFIED IDEOGRAPH + 0x948A: 0x6530, //CJK UNIFIED IDEOGRAPH + 0x948B: 0x6531, //CJK UNIFIED IDEOGRAPH + 0x948C: 0x6532, //CJK UNIFIED IDEOGRAPH + 0x948D: 0x6533, //CJK UNIFIED IDEOGRAPH + 0x948E: 0x6537, //CJK UNIFIED IDEOGRAPH + 0x948F: 0x653A, //CJK UNIFIED IDEOGRAPH + 0x9490: 0x653C, //CJK UNIFIED IDEOGRAPH + 0x9491: 0x653D, //CJK UNIFIED IDEOGRAPH + 0x9492: 0x6540, //CJK UNIFIED IDEOGRAPH + 0x9493: 0x6541, //CJK UNIFIED IDEOGRAPH + 0x9494: 0x6542, //CJK UNIFIED IDEOGRAPH + 0x9495: 0x6543, //CJK UNIFIED IDEOGRAPH + 0x9496: 0x6544, //CJK UNIFIED IDEOGRAPH + 0x9497: 0x6546, //CJK UNIFIED IDEOGRAPH + 0x9498: 0x6547, //CJK UNIFIED IDEOGRAPH + 0x9499: 0x654A, //CJK UNIFIED IDEOGRAPH + 0x949A: 0x654B, //CJK UNIFIED IDEOGRAPH + 0x949B: 0x654D, //CJK UNIFIED IDEOGRAPH + 0x949C: 0x654E, //CJK UNIFIED IDEOGRAPH + 0x949D: 0x6550, //CJK UNIFIED IDEOGRAPH + 0x949E: 0x6552, //CJK UNIFIED IDEOGRAPH + 0x949F: 0x6553, //CJK UNIFIED IDEOGRAPH + 0x94A0: 0x6554, //CJK UNIFIED IDEOGRAPH + 0x94A1: 0x6557, //CJK UNIFIED IDEOGRAPH + 0x94A2: 0x6558, //CJK UNIFIED IDEOGRAPH + 0x94A3: 0x655A, //CJK UNIFIED IDEOGRAPH + 0x94A4: 0x655C, //CJK UNIFIED IDEOGRAPH + 0x94A5: 0x655F, //CJK UNIFIED IDEOGRAPH + 0x94A6: 0x6560, //CJK UNIFIED IDEOGRAPH + 0x94A7: 0x6561, //CJK UNIFIED IDEOGRAPH + 0x94A8: 0x6564, //CJK UNIFIED IDEOGRAPH + 0x94A9: 0x6565, //CJK UNIFIED IDEOGRAPH + 0x94AA: 0x6567, //CJK UNIFIED IDEOGRAPH + 0x94AB: 0x6568, //CJK UNIFIED IDEOGRAPH + 0x94AC: 0x6569, //CJK UNIFIED IDEOGRAPH + 0x94AD: 0x656A, //CJK UNIFIED IDEOGRAPH + 0x94AE: 0x656D, //CJK UNIFIED IDEOGRAPH + 0x94AF: 0x656E, //CJK UNIFIED IDEOGRAPH + 0x94B0: 0x656F, //CJK UNIFIED IDEOGRAPH + 0x94B1: 0x6571, //CJK UNIFIED IDEOGRAPH + 0x94B2: 0x6573, //CJK UNIFIED IDEOGRAPH + 0x94B3: 0x6575, //CJK UNIFIED IDEOGRAPH + 0x94B4: 0x6576, //CJK UNIFIED IDEOGRAPH + 0x94B5: 0x6578, //CJK UNIFIED IDEOGRAPH + 0x94B6: 0x6579, //CJK UNIFIED IDEOGRAPH + 0x94B7: 0x657A, //CJK UNIFIED IDEOGRAPH + 0x94B8: 0x657B, //CJK UNIFIED IDEOGRAPH + 0x94B9: 0x657C, //CJK UNIFIED IDEOGRAPH + 0x94BA: 0x657D, //CJK UNIFIED IDEOGRAPH + 0x94BB: 0x657E, //CJK UNIFIED IDEOGRAPH + 0x94BC: 0x657F, //CJK UNIFIED IDEOGRAPH + 0x94BD: 0x6580, //CJK UNIFIED IDEOGRAPH + 0x94BE: 0x6581, //CJK UNIFIED IDEOGRAPH + 0x94BF: 0x6582, //CJK UNIFIED IDEOGRAPH + 0x94C0: 0x6583, //CJK UNIFIED IDEOGRAPH + 0x94C1: 0x6584, //CJK UNIFIED IDEOGRAPH + 0x94C2: 0x6585, //CJK UNIFIED IDEOGRAPH + 0x94C3: 0x6586, //CJK UNIFIED IDEOGRAPH + 0x94C4: 0x6588, //CJK UNIFIED IDEOGRAPH + 0x94C5: 0x6589, //CJK UNIFIED IDEOGRAPH + 0x94C6: 0x658A, //CJK UNIFIED IDEOGRAPH + 0x94C7: 0x658D, //CJK UNIFIED IDEOGRAPH + 0x94C8: 0x658E, //CJK UNIFIED IDEOGRAPH + 0x94C9: 0x658F, //CJK UNIFIED IDEOGRAPH + 0x94CA: 0x6592, //CJK UNIFIED IDEOGRAPH + 0x94CB: 0x6594, //CJK UNIFIED IDEOGRAPH + 0x94CC: 0x6595, //CJK UNIFIED IDEOGRAPH + 0x94CD: 0x6596, //CJK UNIFIED IDEOGRAPH + 0x94CE: 0x6598, //CJK UNIFIED IDEOGRAPH + 0x94CF: 0x659A, //CJK UNIFIED IDEOGRAPH + 0x94D0: 0x659D, //CJK UNIFIED IDEOGRAPH + 0x94D1: 0x659E, //CJK UNIFIED IDEOGRAPH + 0x94D2: 0x65A0, //CJK UNIFIED IDEOGRAPH + 0x94D3: 0x65A2, //CJK UNIFIED IDEOGRAPH + 0x94D4: 0x65A3, //CJK UNIFIED IDEOGRAPH + 0x94D5: 0x65A6, //CJK UNIFIED IDEOGRAPH + 0x94D6: 0x65A8, //CJK UNIFIED IDEOGRAPH + 0x94D7: 0x65AA, //CJK UNIFIED IDEOGRAPH + 0x94D8: 0x65AC, //CJK UNIFIED IDEOGRAPH + 0x94D9: 0x65AE, //CJK UNIFIED IDEOGRAPH + 0x94DA: 0x65B1, //CJK UNIFIED IDEOGRAPH + 0x94DB: 0x65B2, //CJK UNIFIED IDEOGRAPH + 0x94DC: 0x65B3, //CJK UNIFIED IDEOGRAPH + 0x94DD: 0x65B4, //CJK UNIFIED IDEOGRAPH + 0x94DE: 0x65B5, //CJK UNIFIED IDEOGRAPH + 0x94DF: 0x65B6, //CJK UNIFIED IDEOGRAPH + 0x94E0: 0x65B7, //CJK UNIFIED IDEOGRAPH + 0x94E1: 0x65B8, //CJK UNIFIED IDEOGRAPH + 0x94E2: 0x65BA, //CJK UNIFIED IDEOGRAPH + 0x94E3: 0x65BB, //CJK UNIFIED IDEOGRAPH + 0x94E4: 0x65BE, //CJK UNIFIED IDEOGRAPH + 0x94E5: 0x65BF, //CJK UNIFIED IDEOGRAPH + 0x94E6: 0x65C0, //CJK UNIFIED IDEOGRAPH + 0x94E7: 0x65C2, //CJK UNIFIED IDEOGRAPH + 0x94E8: 0x65C7, //CJK UNIFIED IDEOGRAPH + 0x94E9: 0x65C8, //CJK UNIFIED IDEOGRAPH + 0x94EA: 0x65C9, //CJK UNIFIED IDEOGRAPH + 0x94EB: 0x65CA, //CJK UNIFIED IDEOGRAPH + 0x94EC: 0x65CD, //CJK UNIFIED IDEOGRAPH + 0x94ED: 0x65D0, //CJK UNIFIED IDEOGRAPH + 0x94EE: 0x65D1, //CJK UNIFIED IDEOGRAPH + 0x94EF: 0x65D3, //CJK UNIFIED IDEOGRAPH + 0x94F0: 0x65D4, //CJK UNIFIED IDEOGRAPH + 0x94F1: 0x65D5, //CJK UNIFIED IDEOGRAPH + 0x94F2: 0x65D8, //CJK UNIFIED IDEOGRAPH + 0x94F3: 0x65D9, //CJK UNIFIED IDEOGRAPH + 0x94F4: 0x65DA, //CJK UNIFIED IDEOGRAPH + 0x94F5: 0x65DB, //CJK UNIFIED IDEOGRAPH + 0x94F6: 0x65DC, //CJK UNIFIED IDEOGRAPH + 0x94F7: 0x65DD, //CJK UNIFIED IDEOGRAPH + 0x94F8: 0x65DE, //CJK UNIFIED IDEOGRAPH + 0x94F9: 0x65DF, //CJK UNIFIED IDEOGRAPH + 0x94FA: 0x65E1, //CJK UNIFIED IDEOGRAPH + 0x94FB: 0x65E3, //CJK UNIFIED IDEOGRAPH + 0x94FC: 0x65E4, //CJK UNIFIED IDEOGRAPH + 0x94FD: 0x65EA, //CJK UNIFIED IDEOGRAPH + 0x94FE: 0x65EB, //CJK UNIFIED IDEOGRAPH + 0x9540: 0x65F2, //CJK UNIFIED IDEOGRAPH + 0x9541: 0x65F3, //CJK UNIFIED IDEOGRAPH + 0x9542: 0x65F4, //CJK UNIFIED IDEOGRAPH + 0x9543: 0x65F5, //CJK UNIFIED IDEOGRAPH + 0x9544: 0x65F8, //CJK UNIFIED IDEOGRAPH + 0x9545: 0x65F9, //CJK UNIFIED IDEOGRAPH + 0x9546: 0x65FB, //CJK UNIFIED IDEOGRAPH + 0x9547: 0x65FC, //CJK UNIFIED IDEOGRAPH + 0x9548: 0x65FD, //CJK UNIFIED IDEOGRAPH + 0x9549: 0x65FE, //CJK UNIFIED IDEOGRAPH + 0x954A: 0x65FF, //CJK UNIFIED IDEOGRAPH + 0x954B: 0x6601, //CJK UNIFIED IDEOGRAPH + 0x954C: 0x6604, //CJK UNIFIED IDEOGRAPH + 0x954D: 0x6605, //CJK UNIFIED IDEOGRAPH + 0x954E: 0x6607, //CJK UNIFIED IDEOGRAPH + 0x954F: 0x6608, //CJK UNIFIED IDEOGRAPH + 0x9550: 0x6609, //CJK UNIFIED IDEOGRAPH + 0x9551: 0x660B, //CJK UNIFIED IDEOGRAPH + 0x9552: 0x660D, //CJK UNIFIED IDEOGRAPH + 0x9553: 0x6610, //CJK UNIFIED IDEOGRAPH + 0x9554: 0x6611, //CJK UNIFIED IDEOGRAPH + 0x9555: 0x6612, //CJK UNIFIED IDEOGRAPH + 0x9556: 0x6616, //CJK UNIFIED IDEOGRAPH + 0x9557: 0x6617, //CJK UNIFIED IDEOGRAPH + 0x9558: 0x6618, //CJK UNIFIED IDEOGRAPH + 0x9559: 0x661A, //CJK UNIFIED IDEOGRAPH + 0x955A: 0x661B, //CJK UNIFIED IDEOGRAPH + 0x955B: 0x661C, //CJK UNIFIED IDEOGRAPH + 0x955C: 0x661E, //CJK UNIFIED IDEOGRAPH + 0x955D: 0x6621, //CJK UNIFIED IDEOGRAPH + 0x955E: 0x6622, //CJK UNIFIED IDEOGRAPH + 0x955F: 0x6623, //CJK UNIFIED IDEOGRAPH + 0x9560: 0x6624, //CJK UNIFIED IDEOGRAPH + 0x9561: 0x6626, //CJK UNIFIED IDEOGRAPH + 0x9562: 0x6629, //CJK UNIFIED IDEOGRAPH + 0x9563: 0x662A, //CJK UNIFIED IDEOGRAPH + 0x9564: 0x662B, //CJK UNIFIED IDEOGRAPH + 0x9565: 0x662C, //CJK UNIFIED IDEOGRAPH + 0x9566: 0x662E, //CJK UNIFIED IDEOGRAPH + 0x9567: 0x6630, //CJK UNIFIED IDEOGRAPH + 0x9568: 0x6632, //CJK UNIFIED IDEOGRAPH + 0x9569: 0x6633, //CJK UNIFIED IDEOGRAPH + 0x956A: 0x6637, //CJK UNIFIED IDEOGRAPH + 0x956B: 0x6638, //CJK UNIFIED IDEOGRAPH + 0x956C: 0x6639, //CJK UNIFIED IDEOGRAPH + 0x956D: 0x663A, //CJK UNIFIED IDEOGRAPH + 0x956E: 0x663B, //CJK UNIFIED IDEOGRAPH + 0x956F: 0x663D, //CJK UNIFIED IDEOGRAPH + 0x9570: 0x663F, //CJK UNIFIED IDEOGRAPH + 0x9571: 0x6640, //CJK UNIFIED IDEOGRAPH + 0x9572: 0x6642, //CJK UNIFIED IDEOGRAPH + 0x9573: 0x6644, //CJK UNIFIED IDEOGRAPH + 0x9574: 0x6645, //CJK UNIFIED IDEOGRAPH + 0x9575: 0x6646, //CJK UNIFIED IDEOGRAPH + 0x9576: 0x6647, //CJK UNIFIED IDEOGRAPH + 0x9577: 0x6648, //CJK UNIFIED IDEOGRAPH + 0x9578: 0x6649, //CJK UNIFIED IDEOGRAPH + 0x9579: 0x664A, //CJK UNIFIED IDEOGRAPH + 0x957A: 0x664D, //CJK UNIFIED IDEOGRAPH + 0x957B: 0x664E, //CJK UNIFIED IDEOGRAPH + 0x957C: 0x6650, //CJK UNIFIED IDEOGRAPH + 0x957D: 0x6651, //CJK UNIFIED IDEOGRAPH + 0x957E: 0x6658, //CJK UNIFIED IDEOGRAPH + 0x9580: 0x6659, //CJK UNIFIED IDEOGRAPH + 0x9581: 0x665B, //CJK UNIFIED IDEOGRAPH + 0x9582: 0x665C, //CJK UNIFIED IDEOGRAPH + 0x9583: 0x665D, //CJK UNIFIED IDEOGRAPH + 0x9584: 0x665E, //CJK UNIFIED IDEOGRAPH + 0x9585: 0x6660, //CJK UNIFIED IDEOGRAPH + 0x9586: 0x6662, //CJK UNIFIED IDEOGRAPH + 0x9587: 0x6663, //CJK UNIFIED IDEOGRAPH + 0x9588: 0x6665, //CJK UNIFIED IDEOGRAPH + 0x9589: 0x6667, //CJK UNIFIED IDEOGRAPH + 0x958A: 0x6669, //CJK UNIFIED IDEOGRAPH + 0x958B: 0x666A, //CJK UNIFIED IDEOGRAPH + 0x958C: 0x666B, //CJK UNIFIED IDEOGRAPH + 0x958D: 0x666C, //CJK UNIFIED IDEOGRAPH + 0x958E: 0x666D, //CJK UNIFIED IDEOGRAPH + 0x958F: 0x6671, //CJK UNIFIED IDEOGRAPH + 0x9590: 0x6672, //CJK UNIFIED IDEOGRAPH + 0x9591: 0x6673, //CJK UNIFIED IDEOGRAPH + 0x9592: 0x6675, //CJK UNIFIED IDEOGRAPH + 0x9593: 0x6678, //CJK UNIFIED IDEOGRAPH + 0x9594: 0x6679, //CJK UNIFIED IDEOGRAPH + 0x9595: 0x667B, //CJK UNIFIED IDEOGRAPH + 0x9596: 0x667C, //CJK UNIFIED IDEOGRAPH + 0x9597: 0x667D, //CJK UNIFIED IDEOGRAPH + 0x9598: 0x667F, //CJK UNIFIED IDEOGRAPH + 0x9599: 0x6680, //CJK UNIFIED IDEOGRAPH + 0x959A: 0x6681, //CJK UNIFIED IDEOGRAPH + 0x959B: 0x6683, //CJK UNIFIED IDEOGRAPH + 0x959C: 0x6685, //CJK UNIFIED IDEOGRAPH + 0x959D: 0x6686, //CJK UNIFIED IDEOGRAPH + 0x959E: 0x6688, //CJK UNIFIED IDEOGRAPH + 0x959F: 0x6689, //CJK UNIFIED IDEOGRAPH + 0x95A0: 0x668A, //CJK UNIFIED IDEOGRAPH + 0x95A1: 0x668B, //CJK UNIFIED IDEOGRAPH + 0x95A2: 0x668D, //CJK UNIFIED IDEOGRAPH + 0x95A3: 0x668E, //CJK UNIFIED IDEOGRAPH + 0x95A4: 0x668F, //CJK UNIFIED IDEOGRAPH + 0x95A5: 0x6690, //CJK UNIFIED IDEOGRAPH + 0x95A6: 0x6692, //CJK UNIFIED IDEOGRAPH + 0x95A7: 0x6693, //CJK UNIFIED IDEOGRAPH + 0x95A8: 0x6694, //CJK UNIFIED IDEOGRAPH + 0x95A9: 0x6695, //CJK UNIFIED IDEOGRAPH + 0x95AA: 0x6698, //CJK UNIFIED IDEOGRAPH + 0x95AB: 0x6699, //CJK UNIFIED IDEOGRAPH + 0x95AC: 0x669A, //CJK UNIFIED IDEOGRAPH + 0x95AD: 0x669B, //CJK UNIFIED IDEOGRAPH + 0x95AE: 0x669C, //CJK UNIFIED IDEOGRAPH + 0x95AF: 0x669E, //CJK UNIFIED IDEOGRAPH + 0x95B0: 0x669F, //CJK UNIFIED IDEOGRAPH + 0x95B1: 0x66A0, //CJK UNIFIED IDEOGRAPH + 0x95B2: 0x66A1, //CJK UNIFIED IDEOGRAPH + 0x95B3: 0x66A2, //CJK UNIFIED IDEOGRAPH + 0x95B4: 0x66A3, //CJK UNIFIED IDEOGRAPH + 0x95B5: 0x66A4, //CJK UNIFIED IDEOGRAPH + 0x95B6: 0x66A5, //CJK UNIFIED IDEOGRAPH + 0x95B7: 0x66A6, //CJK UNIFIED IDEOGRAPH + 0x95B8: 0x66A9, //CJK UNIFIED IDEOGRAPH + 0x95B9: 0x66AA, //CJK UNIFIED IDEOGRAPH + 0x95BA: 0x66AB, //CJK UNIFIED IDEOGRAPH + 0x95BB: 0x66AC, //CJK UNIFIED IDEOGRAPH + 0x95BC: 0x66AD, //CJK UNIFIED IDEOGRAPH + 0x95BD: 0x66AF, //CJK UNIFIED IDEOGRAPH + 0x95BE: 0x66B0, //CJK UNIFIED IDEOGRAPH + 0x95BF: 0x66B1, //CJK UNIFIED IDEOGRAPH + 0x95C0: 0x66B2, //CJK UNIFIED IDEOGRAPH + 0x95C1: 0x66B3, //CJK UNIFIED IDEOGRAPH + 0x95C2: 0x66B5, //CJK UNIFIED IDEOGRAPH + 0x95C3: 0x66B6, //CJK UNIFIED IDEOGRAPH + 0x95C4: 0x66B7, //CJK UNIFIED IDEOGRAPH + 0x95C5: 0x66B8, //CJK UNIFIED IDEOGRAPH + 0x95C6: 0x66BA, //CJK UNIFIED IDEOGRAPH + 0x95C7: 0x66BB, //CJK UNIFIED IDEOGRAPH + 0x95C8: 0x66BC, //CJK UNIFIED IDEOGRAPH + 0x95C9: 0x66BD, //CJK UNIFIED IDEOGRAPH + 0x95CA: 0x66BF, //CJK UNIFIED IDEOGRAPH + 0x95CB: 0x66C0, //CJK UNIFIED IDEOGRAPH + 0x95CC: 0x66C1, //CJK UNIFIED IDEOGRAPH + 0x95CD: 0x66C2, //CJK UNIFIED IDEOGRAPH + 0x95CE: 0x66C3, //CJK UNIFIED IDEOGRAPH + 0x95CF: 0x66C4, //CJK UNIFIED IDEOGRAPH + 0x95D0: 0x66C5, //CJK UNIFIED IDEOGRAPH + 0x95D1: 0x66C6, //CJK UNIFIED IDEOGRAPH + 0x95D2: 0x66C7, //CJK UNIFIED IDEOGRAPH + 0x95D3: 0x66C8, //CJK UNIFIED IDEOGRAPH + 0x95D4: 0x66C9, //CJK UNIFIED IDEOGRAPH + 0x95D5: 0x66CA, //CJK UNIFIED IDEOGRAPH + 0x95D6: 0x66CB, //CJK UNIFIED IDEOGRAPH + 0x95D7: 0x66CC, //CJK UNIFIED IDEOGRAPH + 0x95D8: 0x66CD, //CJK UNIFIED IDEOGRAPH + 0x95D9: 0x66CE, //CJK UNIFIED IDEOGRAPH + 0x95DA: 0x66CF, //CJK UNIFIED IDEOGRAPH + 0x95DB: 0x66D0, //CJK UNIFIED IDEOGRAPH + 0x95DC: 0x66D1, //CJK UNIFIED IDEOGRAPH + 0x95DD: 0x66D2, //CJK UNIFIED IDEOGRAPH + 0x95DE: 0x66D3, //CJK UNIFIED IDEOGRAPH + 0x95DF: 0x66D4, //CJK UNIFIED IDEOGRAPH + 0x95E0: 0x66D5, //CJK UNIFIED IDEOGRAPH + 0x95E1: 0x66D6, //CJK UNIFIED IDEOGRAPH + 0x95E2: 0x66D7, //CJK UNIFIED IDEOGRAPH + 0x95E3: 0x66D8, //CJK UNIFIED IDEOGRAPH + 0x95E4: 0x66DA, //CJK UNIFIED IDEOGRAPH + 0x95E5: 0x66DE, //CJK UNIFIED IDEOGRAPH + 0x95E6: 0x66DF, //CJK UNIFIED IDEOGRAPH + 0x95E7: 0x66E0, //CJK UNIFIED IDEOGRAPH + 0x95E8: 0x66E1, //CJK UNIFIED IDEOGRAPH + 0x95E9: 0x66E2, //CJK UNIFIED IDEOGRAPH + 0x95EA: 0x66E3, //CJK UNIFIED IDEOGRAPH + 0x95EB: 0x66E4, //CJK UNIFIED IDEOGRAPH + 0x95EC: 0x66E5, //CJK UNIFIED IDEOGRAPH + 0x95ED: 0x66E7, //CJK UNIFIED IDEOGRAPH + 0x95EE: 0x66E8, //CJK UNIFIED IDEOGRAPH + 0x95EF: 0x66EA, //CJK UNIFIED IDEOGRAPH + 0x95F0: 0x66EB, //CJK UNIFIED IDEOGRAPH + 0x95F1: 0x66EC, //CJK UNIFIED IDEOGRAPH + 0x95F2: 0x66ED, //CJK UNIFIED IDEOGRAPH + 0x95F3: 0x66EE, //CJK UNIFIED IDEOGRAPH + 0x95F4: 0x66EF, //CJK UNIFIED IDEOGRAPH + 0x95F5: 0x66F1, //CJK UNIFIED IDEOGRAPH + 0x95F6: 0x66F5, //CJK UNIFIED IDEOGRAPH + 0x95F7: 0x66F6, //CJK UNIFIED IDEOGRAPH + 0x95F8: 0x66F8, //CJK UNIFIED IDEOGRAPH + 0x95F9: 0x66FA, //CJK UNIFIED IDEOGRAPH + 0x95FA: 0x66FB, //CJK UNIFIED IDEOGRAPH + 0x95FB: 0x66FD, //CJK UNIFIED IDEOGRAPH + 0x95FC: 0x6701, //CJK UNIFIED IDEOGRAPH + 0x95FD: 0x6702, //CJK UNIFIED IDEOGRAPH + 0x95FE: 0x6703, //CJK UNIFIED IDEOGRAPH + 0x9640: 0x6704, //CJK UNIFIED IDEOGRAPH + 0x9641: 0x6705, //CJK UNIFIED IDEOGRAPH + 0x9642: 0x6706, //CJK UNIFIED IDEOGRAPH + 0x9643: 0x6707, //CJK UNIFIED IDEOGRAPH + 0x9644: 0x670C, //CJK UNIFIED IDEOGRAPH + 0x9645: 0x670E, //CJK UNIFIED IDEOGRAPH + 0x9646: 0x670F, //CJK UNIFIED IDEOGRAPH + 0x9647: 0x6711, //CJK UNIFIED IDEOGRAPH + 0x9648: 0x6712, //CJK UNIFIED IDEOGRAPH + 0x9649: 0x6713, //CJK UNIFIED IDEOGRAPH + 0x964A: 0x6716, //CJK UNIFIED IDEOGRAPH + 0x964B: 0x6718, //CJK UNIFIED IDEOGRAPH + 0x964C: 0x6719, //CJK UNIFIED IDEOGRAPH + 0x964D: 0x671A, //CJK UNIFIED IDEOGRAPH + 0x964E: 0x671C, //CJK UNIFIED IDEOGRAPH + 0x964F: 0x671E, //CJK UNIFIED IDEOGRAPH + 0x9650: 0x6720, //CJK UNIFIED IDEOGRAPH + 0x9651: 0x6721, //CJK UNIFIED IDEOGRAPH + 0x9652: 0x6722, //CJK UNIFIED IDEOGRAPH + 0x9653: 0x6723, //CJK UNIFIED IDEOGRAPH + 0x9654: 0x6724, //CJK UNIFIED IDEOGRAPH + 0x9655: 0x6725, //CJK UNIFIED IDEOGRAPH + 0x9656: 0x6727, //CJK UNIFIED IDEOGRAPH + 0x9657: 0x6729, //CJK UNIFIED IDEOGRAPH + 0x9658: 0x672E, //CJK UNIFIED IDEOGRAPH + 0x9659: 0x6730, //CJK UNIFIED IDEOGRAPH + 0x965A: 0x6732, //CJK UNIFIED IDEOGRAPH + 0x965B: 0x6733, //CJK UNIFIED IDEOGRAPH + 0x965C: 0x6736, //CJK UNIFIED IDEOGRAPH + 0x965D: 0x6737, //CJK UNIFIED IDEOGRAPH + 0x965E: 0x6738, //CJK UNIFIED IDEOGRAPH + 0x965F: 0x6739, //CJK UNIFIED IDEOGRAPH + 0x9660: 0x673B, //CJK UNIFIED IDEOGRAPH + 0x9661: 0x673C, //CJK UNIFIED IDEOGRAPH + 0x9662: 0x673E, //CJK UNIFIED IDEOGRAPH + 0x9663: 0x673F, //CJK UNIFIED IDEOGRAPH + 0x9664: 0x6741, //CJK UNIFIED IDEOGRAPH + 0x9665: 0x6744, //CJK UNIFIED IDEOGRAPH + 0x9666: 0x6745, //CJK UNIFIED IDEOGRAPH + 0x9667: 0x6747, //CJK UNIFIED IDEOGRAPH + 0x9668: 0x674A, //CJK UNIFIED IDEOGRAPH + 0x9669: 0x674B, //CJK UNIFIED IDEOGRAPH + 0x966A: 0x674D, //CJK UNIFIED IDEOGRAPH + 0x966B: 0x6752, //CJK UNIFIED IDEOGRAPH + 0x966C: 0x6754, //CJK UNIFIED IDEOGRAPH + 0x966D: 0x6755, //CJK UNIFIED IDEOGRAPH + 0x966E: 0x6757, //CJK UNIFIED IDEOGRAPH + 0x966F: 0x6758, //CJK UNIFIED IDEOGRAPH + 0x9670: 0x6759, //CJK UNIFIED IDEOGRAPH + 0x9671: 0x675A, //CJK UNIFIED IDEOGRAPH + 0x9672: 0x675B, //CJK UNIFIED IDEOGRAPH + 0x9673: 0x675D, //CJK UNIFIED IDEOGRAPH + 0x9674: 0x6762, //CJK UNIFIED IDEOGRAPH + 0x9675: 0x6763, //CJK UNIFIED IDEOGRAPH + 0x9676: 0x6764, //CJK UNIFIED IDEOGRAPH + 0x9677: 0x6766, //CJK UNIFIED IDEOGRAPH + 0x9678: 0x6767, //CJK UNIFIED IDEOGRAPH + 0x9679: 0x676B, //CJK UNIFIED IDEOGRAPH + 0x967A: 0x676C, //CJK UNIFIED IDEOGRAPH + 0x967B: 0x676E, //CJK UNIFIED IDEOGRAPH + 0x967C: 0x6771, //CJK UNIFIED IDEOGRAPH + 0x967D: 0x6774, //CJK UNIFIED IDEOGRAPH + 0x967E: 0x6776, //CJK UNIFIED IDEOGRAPH + 0x9680: 0x6778, //CJK UNIFIED IDEOGRAPH + 0x9681: 0x6779, //CJK UNIFIED IDEOGRAPH + 0x9682: 0x677A, //CJK UNIFIED IDEOGRAPH + 0x9683: 0x677B, //CJK UNIFIED IDEOGRAPH + 0x9684: 0x677D, //CJK UNIFIED IDEOGRAPH + 0x9685: 0x6780, //CJK UNIFIED IDEOGRAPH + 0x9686: 0x6782, //CJK UNIFIED IDEOGRAPH + 0x9687: 0x6783, //CJK UNIFIED IDEOGRAPH + 0x9688: 0x6785, //CJK UNIFIED IDEOGRAPH + 0x9689: 0x6786, //CJK UNIFIED IDEOGRAPH + 0x968A: 0x6788, //CJK UNIFIED IDEOGRAPH + 0x968B: 0x678A, //CJK UNIFIED IDEOGRAPH + 0x968C: 0x678C, //CJK UNIFIED IDEOGRAPH + 0x968D: 0x678D, //CJK UNIFIED IDEOGRAPH + 0x968E: 0x678E, //CJK UNIFIED IDEOGRAPH + 0x968F: 0x678F, //CJK UNIFIED IDEOGRAPH + 0x9690: 0x6791, //CJK UNIFIED IDEOGRAPH + 0x9691: 0x6792, //CJK UNIFIED IDEOGRAPH + 0x9692: 0x6793, //CJK UNIFIED IDEOGRAPH + 0x9693: 0x6794, //CJK UNIFIED IDEOGRAPH + 0x9694: 0x6796, //CJK UNIFIED IDEOGRAPH + 0x9695: 0x6799, //CJK UNIFIED IDEOGRAPH + 0x9696: 0x679B, //CJK UNIFIED IDEOGRAPH + 0x9697: 0x679F, //CJK UNIFIED IDEOGRAPH + 0x9698: 0x67A0, //CJK UNIFIED IDEOGRAPH + 0x9699: 0x67A1, //CJK UNIFIED IDEOGRAPH + 0x969A: 0x67A4, //CJK UNIFIED IDEOGRAPH + 0x969B: 0x67A6, //CJK UNIFIED IDEOGRAPH + 0x969C: 0x67A9, //CJK UNIFIED IDEOGRAPH + 0x969D: 0x67AC, //CJK UNIFIED IDEOGRAPH + 0x969E: 0x67AE, //CJK UNIFIED IDEOGRAPH + 0x969F: 0x67B1, //CJK UNIFIED IDEOGRAPH + 0x96A0: 0x67B2, //CJK UNIFIED IDEOGRAPH + 0x96A1: 0x67B4, //CJK UNIFIED IDEOGRAPH + 0x96A2: 0x67B9, //CJK UNIFIED IDEOGRAPH + 0x96A3: 0x67BA, //CJK UNIFIED IDEOGRAPH + 0x96A4: 0x67BB, //CJK UNIFIED IDEOGRAPH + 0x96A5: 0x67BC, //CJK UNIFIED IDEOGRAPH + 0x96A6: 0x67BD, //CJK UNIFIED IDEOGRAPH + 0x96A7: 0x67BE, //CJK UNIFIED IDEOGRAPH + 0x96A8: 0x67BF, //CJK UNIFIED IDEOGRAPH + 0x96A9: 0x67C0, //CJK UNIFIED IDEOGRAPH + 0x96AA: 0x67C2, //CJK UNIFIED IDEOGRAPH + 0x96AB: 0x67C5, //CJK UNIFIED IDEOGRAPH + 0x96AC: 0x67C6, //CJK UNIFIED IDEOGRAPH + 0x96AD: 0x67C7, //CJK UNIFIED IDEOGRAPH + 0x96AE: 0x67C8, //CJK UNIFIED IDEOGRAPH + 0x96AF: 0x67C9, //CJK UNIFIED IDEOGRAPH + 0x96B0: 0x67CA, //CJK UNIFIED IDEOGRAPH + 0x96B1: 0x67CB, //CJK UNIFIED IDEOGRAPH + 0x96B2: 0x67CC, //CJK UNIFIED IDEOGRAPH + 0x96B3: 0x67CD, //CJK UNIFIED IDEOGRAPH + 0x96B4: 0x67CE, //CJK UNIFIED IDEOGRAPH + 0x96B5: 0x67D5, //CJK UNIFIED IDEOGRAPH + 0x96B6: 0x67D6, //CJK UNIFIED IDEOGRAPH + 0x96B7: 0x67D7, //CJK UNIFIED IDEOGRAPH + 0x96B8: 0x67DB, //CJK UNIFIED IDEOGRAPH + 0x96B9: 0x67DF, //CJK UNIFIED IDEOGRAPH + 0x96BA: 0x67E1, //CJK UNIFIED IDEOGRAPH + 0x96BB: 0x67E3, //CJK UNIFIED IDEOGRAPH + 0x96BC: 0x67E4, //CJK UNIFIED IDEOGRAPH + 0x96BD: 0x67E6, //CJK UNIFIED IDEOGRAPH + 0x96BE: 0x67E7, //CJK UNIFIED IDEOGRAPH + 0x96BF: 0x67E8, //CJK UNIFIED IDEOGRAPH + 0x96C0: 0x67EA, //CJK UNIFIED IDEOGRAPH + 0x96C1: 0x67EB, //CJK UNIFIED IDEOGRAPH + 0x96C2: 0x67ED, //CJK UNIFIED IDEOGRAPH + 0x96C3: 0x67EE, //CJK UNIFIED IDEOGRAPH + 0x96C4: 0x67F2, //CJK UNIFIED IDEOGRAPH + 0x96C5: 0x67F5, //CJK UNIFIED IDEOGRAPH + 0x96C6: 0x67F6, //CJK UNIFIED IDEOGRAPH + 0x96C7: 0x67F7, //CJK UNIFIED IDEOGRAPH + 0x96C8: 0x67F8, //CJK UNIFIED IDEOGRAPH + 0x96C9: 0x67F9, //CJK UNIFIED IDEOGRAPH + 0x96CA: 0x67FA, //CJK UNIFIED IDEOGRAPH + 0x96CB: 0x67FB, //CJK UNIFIED IDEOGRAPH + 0x96CC: 0x67FC, //CJK UNIFIED IDEOGRAPH + 0x96CD: 0x67FE, //CJK UNIFIED IDEOGRAPH + 0x96CE: 0x6801, //CJK UNIFIED IDEOGRAPH + 0x96CF: 0x6802, //CJK UNIFIED IDEOGRAPH + 0x96D0: 0x6803, //CJK UNIFIED IDEOGRAPH + 0x96D1: 0x6804, //CJK UNIFIED IDEOGRAPH + 0x96D2: 0x6806, //CJK UNIFIED IDEOGRAPH + 0x96D3: 0x680D, //CJK UNIFIED IDEOGRAPH + 0x96D4: 0x6810, //CJK UNIFIED IDEOGRAPH + 0x96D5: 0x6812, //CJK UNIFIED IDEOGRAPH + 0x96D6: 0x6814, //CJK UNIFIED IDEOGRAPH + 0x96D7: 0x6815, //CJK UNIFIED IDEOGRAPH + 0x96D8: 0x6818, //CJK UNIFIED IDEOGRAPH + 0x96D9: 0x6819, //CJK UNIFIED IDEOGRAPH + 0x96DA: 0x681A, //CJK UNIFIED IDEOGRAPH + 0x96DB: 0x681B, //CJK UNIFIED IDEOGRAPH + 0x96DC: 0x681C, //CJK UNIFIED IDEOGRAPH + 0x96DD: 0x681E, //CJK UNIFIED IDEOGRAPH + 0x96DE: 0x681F, //CJK UNIFIED IDEOGRAPH + 0x96DF: 0x6820, //CJK UNIFIED IDEOGRAPH + 0x96E0: 0x6822, //CJK UNIFIED IDEOGRAPH + 0x96E1: 0x6823, //CJK UNIFIED IDEOGRAPH + 0x96E2: 0x6824, //CJK UNIFIED IDEOGRAPH + 0x96E3: 0x6825, //CJK UNIFIED IDEOGRAPH + 0x96E4: 0x6826, //CJK UNIFIED IDEOGRAPH + 0x96E5: 0x6827, //CJK UNIFIED IDEOGRAPH + 0x96E6: 0x6828, //CJK UNIFIED IDEOGRAPH + 0x96E7: 0x682B, //CJK UNIFIED IDEOGRAPH + 0x96E8: 0x682C, //CJK UNIFIED IDEOGRAPH + 0x96E9: 0x682D, //CJK UNIFIED IDEOGRAPH + 0x96EA: 0x682E, //CJK UNIFIED IDEOGRAPH + 0x96EB: 0x682F, //CJK UNIFIED IDEOGRAPH + 0x96EC: 0x6830, //CJK UNIFIED IDEOGRAPH + 0x96ED: 0x6831, //CJK UNIFIED IDEOGRAPH + 0x96EE: 0x6834, //CJK UNIFIED IDEOGRAPH + 0x96EF: 0x6835, //CJK UNIFIED IDEOGRAPH + 0x96F0: 0x6836, //CJK UNIFIED IDEOGRAPH + 0x96F1: 0x683A, //CJK UNIFIED IDEOGRAPH + 0x96F2: 0x683B, //CJK UNIFIED IDEOGRAPH + 0x96F3: 0x683F, //CJK UNIFIED IDEOGRAPH + 0x96F4: 0x6847, //CJK UNIFIED IDEOGRAPH + 0x96F5: 0x684B, //CJK UNIFIED IDEOGRAPH + 0x96F6: 0x684D, //CJK UNIFIED IDEOGRAPH + 0x96F7: 0x684F, //CJK UNIFIED IDEOGRAPH + 0x96F8: 0x6852, //CJK UNIFIED IDEOGRAPH + 0x96F9: 0x6856, //CJK UNIFIED IDEOGRAPH + 0x96FA: 0x6857, //CJK UNIFIED IDEOGRAPH + 0x96FB: 0x6858, //CJK UNIFIED IDEOGRAPH + 0x96FC: 0x6859, //CJK UNIFIED IDEOGRAPH + 0x96FD: 0x685A, //CJK UNIFIED IDEOGRAPH + 0x96FE: 0x685B, //CJK UNIFIED IDEOGRAPH + 0x9740: 0x685C, //CJK UNIFIED IDEOGRAPH + 0x9741: 0x685D, //CJK UNIFIED IDEOGRAPH + 0x9742: 0x685E, //CJK UNIFIED IDEOGRAPH + 0x9743: 0x685F, //CJK UNIFIED IDEOGRAPH + 0x9744: 0x686A, //CJK UNIFIED IDEOGRAPH + 0x9745: 0x686C, //CJK UNIFIED IDEOGRAPH + 0x9746: 0x686D, //CJK UNIFIED IDEOGRAPH + 0x9747: 0x686E, //CJK UNIFIED IDEOGRAPH + 0x9748: 0x686F, //CJK UNIFIED IDEOGRAPH + 0x9749: 0x6870, //CJK UNIFIED IDEOGRAPH + 0x974A: 0x6871, //CJK UNIFIED IDEOGRAPH + 0x974B: 0x6872, //CJK UNIFIED IDEOGRAPH + 0x974C: 0x6873, //CJK UNIFIED IDEOGRAPH + 0x974D: 0x6875, //CJK UNIFIED IDEOGRAPH + 0x974E: 0x6878, //CJK UNIFIED IDEOGRAPH + 0x974F: 0x6879, //CJK UNIFIED IDEOGRAPH + 0x9750: 0x687A, //CJK UNIFIED IDEOGRAPH + 0x9751: 0x687B, //CJK UNIFIED IDEOGRAPH + 0x9752: 0x687C, //CJK UNIFIED IDEOGRAPH + 0x9753: 0x687D, //CJK UNIFIED IDEOGRAPH + 0x9754: 0x687E, //CJK UNIFIED IDEOGRAPH + 0x9755: 0x687F, //CJK UNIFIED IDEOGRAPH + 0x9756: 0x6880, //CJK UNIFIED IDEOGRAPH + 0x9757: 0x6882, //CJK UNIFIED IDEOGRAPH + 0x9758: 0x6884, //CJK UNIFIED IDEOGRAPH + 0x9759: 0x6887, //CJK UNIFIED IDEOGRAPH + 0x975A: 0x6888, //CJK UNIFIED IDEOGRAPH + 0x975B: 0x6889, //CJK UNIFIED IDEOGRAPH + 0x975C: 0x688A, //CJK UNIFIED IDEOGRAPH + 0x975D: 0x688B, //CJK UNIFIED IDEOGRAPH + 0x975E: 0x688C, //CJK UNIFIED IDEOGRAPH + 0x975F: 0x688D, //CJK UNIFIED IDEOGRAPH + 0x9760: 0x688E, //CJK UNIFIED IDEOGRAPH + 0x9761: 0x6890, //CJK UNIFIED IDEOGRAPH + 0x9762: 0x6891, //CJK UNIFIED IDEOGRAPH + 0x9763: 0x6892, //CJK UNIFIED IDEOGRAPH + 0x9764: 0x6894, //CJK UNIFIED IDEOGRAPH + 0x9765: 0x6895, //CJK UNIFIED IDEOGRAPH + 0x9766: 0x6896, //CJK UNIFIED IDEOGRAPH + 0x9767: 0x6898, //CJK UNIFIED IDEOGRAPH + 0x9768: 0x6899, //CJK UNIFIED IDEOGRAPH + 0x9769: 0x689A, //CJK UNIFIED IDEOGRAPH + 0x976A: 0x689B, //CJK UNIFIED IDEOGRAPH + 0x976B: 0x689C, //CJK UNIFIED IDEOGRAPH + 0x976C: 0x689D, //CJK UNIFIED IDEOGRAPH + 0x976D: 0x689E, //CJK UNIFIED IDEOGRAPH + 0x976E: 0x689F, //CJK UNIFIED IDEOGRAPH + 0x976F: 0x68A0, //CJK UNIFIED IDEOGRAPH + 0x9770: 0x68A1, //CJK UNIFIED IDEOGRAPH + 0x9771: 0x68A3, //CJK UNIFIED IDEOGRAPH + 0x9772: 0x68A4, //CJK UNIFIED IDEOGRAPH + 0x9773: 0x68A5, //CJK UNIFIED IDEOGRAPH + 0x9774: 0x68A9, //CJK UNIFIED IDEOGRAPH + 0x9775: 0x68AA, //CJK UNIFIED IDEOGRAPH + 0x9776: 0x68AB, //CJK UNIFIED IDEOGRAPH + 0x9777: 0x68AC, //CJK UNIFIED IDEOGRAPH + 0x9778: 0x68AE, //CJK UNIFIED IDEOGRAPH + 0x9779: 0x68B1, //CJK UNIFIED IDEOGRAPH + 0x977A: 0x68B2, //CJK UNIFIED IDEOGRAPH + 0x977B: 0x68B4, //CJK UNIFIED IDEOGRAPH + 0x977C: 0x68B6, //CJK UNIFIED IDEOGRAPH + 0x977D: 0x68B7, //CJK UNIFIED IDEOGRAPH + 0x977E: 0x68B8, //CJK UNIFIED IDEOGRAPH + 0x9780: 0x68B9, //CJK UNIFIED IDEOGRAPH + 0x9781: 0x68BA, //CJK UNIFIED IDEOGRAPH + 0x9782: 0x68BB, //CJK UNIFIED IDEOGRAPH + 0x9783: 0x68BC, //CJK UNIFIED IDEOGRAPH + 0x9784: 0x68BD, //CJK UNIFIED IDEOGRAPH + 0x9785: 0x68BE, //CJK UNIFIED IDEOGRAPH + 0x9786: 0x68BF, //CJK UNIFIED IDEOGRAPH + 0x9787: 0x68C1, //CJK UNIFIED IDEOGRAPH + 0x9788: 0x68C3, //CJK UNIFIED IDEOGRAPH + 0x9789: 0x68C4, //CJK UNIFIED IDEOGRAPH + 0x978A: 0x68C5, //CJK UNIFIED IDEOGRAPH + 0x978B: 0x68C6, //CJK UNIFIED IDEOGRAPH + 0x978C: 0x68C7, //CJK UNIFIED IDEOGRAPH + 0x978D: 0x68C8, //CJK UNIFIED IDEOGRAPH + 0x978E: 0x68CA, //CJK UNIFIED IDEOGRAPH + 0x978F: 0x68CC, //CJK UNIFIED IDEOGRAPH + 0x9790: 0x68CE, //CJK UNIFIED IDEOGRAPH + 0x9791: 0x68CF, //CJK UNIFIED IDEOGRAPH + 0x9792: 0x68D0, //CJK UNIFIED IDEOGRAPH + 0x9793: 0x68D1, //CJK UNIFIED IDEOGRAPH + 0x9794: 0x68D3, //CJK UNIFIED IDEOGRAPH + 0x9795: 0x68D4, //CJK UNIFIED IDEOGRAPH + 0x9796: 0x68D6, //CJK UNIFIED IDEOGRAPH + 0x9797: 0x68D7, //CJK UNIFIED IDEOGRAPH + 0x9798: 0x68D9, //CJK UNIFIED IDEOGRAPH + 0x9799: 0x68DB, //CJK UNIFIED IDEOGRAPH + 0x979A: 0x68DC, //CJK UNIFIED IDEOGRAPH + 0x979B: 0x68DD, //CJK UNIFIED IDEOGRAPH + 0x979C: 0x68DE, //CJK UNIFIED IDEOGRAPH + 0x979D: 0x68DF, //CJK UNIFIED IDEOGRAPH + 0x979E: 0x68E1, //CJK UNIFIED IDEOGRAPH + 0x979F: 0x68E2, //CJK UNIFIED IDEOGRAPH + 0x97A0: 0x68E4, //CJK UNIFIED IDEOGRAPH + 0x97A1: 0x68E5, //CJK UNIFIED IDEOGRAPH + 0x97A2: 0x68E6, //CJK UNIFIED IDEOGRAPH + 0x97A3: 0x68E7, //CJK UNIFIED IDEOGRAPH + 0x97A4: 0x68E8, //CJK UNIFIED IDEOGRAPH + 0x97A5: 0x68E9, //CJK UNIFIED IDEOGRAPH + 0x97A6: 0x68EA, //CJK UNIFIED IDEOGRAPH + 0x97A7: 0x68EB, //CJK UNIFIED IDEOGRAPH + 0x97A8: 0x68EC, //CJK UNIFIED IDEOGRAPH + 0x97A9: 0x68ED, //CJK UNIFIED IDEOGRAPH + 0x97AA: 0x68EF, //CJK UNIFIED IDEOGRAPH + 0x97AB: 0x68F2, //CJK UNIFIED IDEOGRAPH + 0x97AC: 0x68F3, //CJK UNIFIED IDEOGRAPH + 0x97AD: 0x68F4, //CJK UNIFIED IDEOGRAPH + 0x97AE: 0x68F6, //CJK UNIFIED IDEOGRAPH + 0x97AF: 0x68F7, //CJK UNIFIED IDEOGRAPH + 0x97B0: 0x68F8, //CJK UNIFIED IDEOGRAPH + 0x97B1: 0x68FB, //CJK UNIFIED IDEOGRAPH + 0x97B2: 0x68FD, //CJK UNIFIED IDEOGRAPH + 0x97B3: 0x68FE, //CJK UNIFIED IDEOGRAPH + 0x97B4: 0x68FF, //CJK UNIFIED IDEOGRAPH + 0x97B5: 0x6900, //CJK UNIFIED IDEOGRAPH + 0x97B6: 0x6902, //CJK UNIFIED IDEOGRAPH + 0x97B7: 0x6903, //CJK UNIFIED IDEOGRAPH + 0x97B8: 0x6904, //CJK UNIFIED IDEOGRAPH + 0x97B9: 0x6906, //CJK UNIFIED IDEOGRAPH + 0x97BA: 0x6907, //CJK UNIFIED IDEOGRAPH + 0x97BB: 0x6908, //CJK UNIFIED IDEOGRAPH + 0x97BC: 0x6909, //CJK UNIFIED IDEOGRAPH + 0x97BD: 0x690A, //CJK UNIFIED IDEOGRAPH + 0x97BE: 0x690C, //CJK UNIFIED IDEOGRAPH + 0x97BF: 0x690F, //CJK UNIFIED IDEOGRAPH + 0x97C0: 0x6911, //CJK UNIFIED IDEOGRAPH + 0x97C1: 0x6913, //CJK UNIFIED IDEOGRAPH + 0x97C2: 0x6914, //CJK UNIFIED IDEOGRAPH + 0x97C3: 0x6915, //CJK UNIFIED IDEOGRAPH + 0x97C4: 0x6916, //CJK UNIFIED IDEOGRAPH + 0x97C5: 0x6917, //CJK UNIFIED IDEOGRAPH + 0x97C6: 0x6918, //CJK UNIFIED IDEOGRAPH + 0x97C7: 0x6919, //CJK UNIFIED IDEOGRAPH + 0x97C8: 0x691A, //CJK UNIFIED IDEOGRAPH + 0x97C9: 0x691B, //CJK UNIFIED IDEOGRAPH + 0x97CA: 0x691C, //CJK UNIFIED IDEOGRAPH + 0x97CB: 0x691D, //CJK UNIFIED IDEOGRAPH + 0x97CC: 0x691E, //CJK UNIFIED IDEOGRAPH + 0x97CD: 0x6921, //CJK UNIFIED IDEOGRAPH + 0x97CE: 0x6922, //CJK UNIFIED IDEOGRAPH + 0x97CF: 0x6923, //CJK UNIFIED IDEOGRAPH + 0x97D0: 0x6925, //CJK UNIFIED IDEOGRAPH + 0x97D1: 0x6926, //CJK UNIFIED IDEOGRAPH + 0x97D2: 0x6927, //CJK UNIFIED IDEOGRAPH + 0x97D3: 0x6928, //CJK UNIFIED IDEOGRAPH + 0x97D4: 0x6929, //CJK UNIFIED IDEOGRAPH + 0x97D5: 0x692A, //CJK UNIFIED IDEOGRAPH + 0x97D6: 0x692B, //CJK UNIFIED IDEOGRAPH + 0x97D7: 0x692C, //CJK UNIFIED IDEOGRAPH + 0x97D8: 0x692E, //CJK UNIFIED IDEOGRAPH + 0x97D9: 0x692F, //CJK UNIFIED IDEOGRAPH + 0x97DA: 0x6931, //CJK UNIFIED IDEOGRAPH + 0x97DB: 0x6932, //CJK UNIFIED IDEOGRAPH + 0x97DC: 0x6933, //CJK UNIFIED IDEOGRAPH + 0x97DD: 0x6935, //CJK UNIFIED IDEOGRAPH + 0x97DE: 0x6936, //CJK UNIFIED IDEOGRAPH + 0x97DF: 0x6937, //CJK UNIFIED IDEOGRAPH + 0x97E0: 0x6938, //CJK UNIFIED IDEOGRAPH + 0x97E1: 0x693A, //CJK UNIFIED IDEOGRAPH + 0x97E2: 0x693B, //CJK UNIFIED IDEOGRAPH + 0x97E3: 0x693C, //CJK UNIFIED IDEOGRAPH + 0x97E4: 0x693E, //CJK UNIFIED IDEOGRAPH + 0x97E5: 0x6940, //CJK UNIFIED IDEOGRAPH + 0x97E6: 0x6941, //CJK UNIFIED IDEOGRAPH + 0x97E7: 0x6943, //CJK UNIFIED IDEOGRAPH + 0x97E8: 0x6944, //CJK UNIFIED IDEOGRAPH + 0x97E9: 0x6945, //CJK UNIFIED IDEOGRAPH + 0x97EA: 0x6946, //CJK UNIFIED IDEOGRAPH + 0x97EB: 0x6947, //CJK UNIFIED IDEOGRAPH + 0x97EC: 0x6948, //CJK UNIFIED IDEOGRAPH + 0x97ED: 0x6949, //CJK UNIFIED IDEOGRAPH + 0x97EE: 0x694A, //CJK UNIFIED IDEOGRAPH + 0x97EF: 0x694B, //CJK UNIFIED IDEOGRAPH + 0x97F0: 0x694C, //CJK UNIFIED IDEOGRAPH + 0x97F1: 0x694D, //CJK UNIFIED IDEOGRAPH + 0x97F2: 0x694E, //CJK UNIFIED IDEOGRAPH + 0x97F3: 0x694F, //CJK UNIFIED IDEOGRAPH + 0x97F4: 0x6950, //CJK UNIFIED IDEOGRAPH + 0x97F5: 0x6951, //CJK UNIFIED IDEOGRAPH + 0x97F6: 0x6952, //CJK UNIFIED IDEOGRAPH + 0x97F7: 0x6953, //CJK UNIFIED IDEOGRAPH + 0x97F8: 0x6955, //CJK UNIFIED IDEOGRAPH + 0x97F9: 0x6956, //CJK UNIFIED IDEOGRAPH + 0x97FA: 0x6958, //CJK UNIFIED IDEOGRAPH + 0x97FB: 0x6959, //CJK UNIFIED IDEOGRAPH + 0x97FC: 0x695B, //CJK UNIFIED IDEOGRAPH + 0x97FD: 0x695C, //CJK UNIFIED IDEOGRAPH + 0x97FE: 0x695F, //CJK UNIFIED IDEOGRAPH + 0x9840: 0x6961, //CJK UNIFIED IDEOGRAPH + 0x9841: 0x6962, //CJK UNIFIED IDEOGRAPH + 0x9842: 0x6964, //CJK UNIFIED IDEOGRAPH + 0x9843: 0x6965, //CJK UNIFIED IDEOGRAPH + 0x9844: 0x6967, //CJK UNIFIED IDEOGRAPH + 0x9845: 0x6968, //CJK UNIFIED IDEOGRAPH + 0x9846: 0x6969, //CJK UNIFIED IDEOGRAPH + 0x9847: 0x696A, //CJK UNIFIED IDEOGRAPH + 0x9848: 0x696C, //CJK UNIFIED IDEOGRAPH + 0x9849: 0x696D, //CJK UNIFIED IDEOGRAPH + 0x984A: 0x696F, //CJK UNIFIED IDEOGRAPH + 0x984B: 0x6970, //CJK UNIFIED IDEOGRAPH + 0x984C: 0x6972, //CJK UNIFIED IDEOGRAPH + 0x984D: 0x6973, //CJK UNIFIED IDEOGRAPH + 0x984E: 0x6974, //CJK UNIFIED IDEOGRAPH + 0x984F: 0x6975, //CJK UNIFIED IDEOGRAPH + 0x9850: 0x6976, //CJK UNIFIED IDEOGRAPH + 0x9851: 0x697A, //CJK UNIFIED IDEOGRAPH + 0x9852: 0x697B, //CJK UNIFIED IDEOGRAPH + 0x9853: 0x697D, //CJK UNIFIED IDEOGRAPH + 0x9854: 0x697E, //CJK UNIFIED IDEOGRAPH + 0x9855: 0x697F, //CJK UNIFIED IDEOGRAPH + 0x9856: 0x6981, //CJK UNIFIED IDEOGRAPH + 0x9857: 0x6983, //CJK UNIFIED IDEOGRAPH + 0x9858: 0x6985, //CJK UNIFIED IDEOGRAPH + 0x9859: 0x698A, //CJK UNIFIED IDEOGRAPH + 0x985A: 0x698B, //CJK UNIFIED IDEOGRAPH + 0x985B: 0x698C, //CJK UNIFIED IDEOGRAPH + 0x985C: 0x698E, //CJK UNIFIED IDEOGRAPH + 0x985D: 0x698F, //CJK UNIFIED IDEOGRAPH + 0x985E: 0x6990, //CJK UNIFIED IDEOGRAPH + 0x985F: 0x6991, //CJK UNIFIED IDEOGRAPH + 0x9860: 0x6992, //CJK UNIFIED IDEOGRAPH + 0x9861: 0x6993, //CJK UNIFIED IDEOGRAPH + 0x9862: 0x6996, //CJK UNIFIED IDEOGRAPH + 0x9863: 0x6997, //CJK UNIFIED IDEOGRAPH + 0x9864: 0x6999, //CJK UNIFIED IDEOGRAPH + 0x9865: 0x699A, //CJK UNIFIED IDEOGRAPH + 0x9866: 0x699D, //CJK UNIFIED IDEOGRAPH + 0x9867: 0x699E, //CJK UNIFIED IDEOGRAPH + 0x9868: 0x699F, //CJK UNIFIED IDEOGRAPH + 0x9869: 0x69A0, //CJK UNIFIED IDEOGRAPH + 0x986A: 0x69A1, //CJK UNIFIED IDEOGRAPH + 0x986B: 0x69A2, //CJK UNIFIED IDEOGRAPH + 0x986C: 0x69A3, //CJK UNIFIED IDEOGRAPH + 0x986D: 0x69A4, //CJK UNIFIED IDEOGRAPH + 0x986E: 0x69A5, //CJK UNIFIED IDEOGRAPH + 0x986F: 0x69A6, //CJK UNIFIED IDEOGRAPH + 0x9870: 0x69A9, //CJK UNIFIED IDEOGRAPH + 0x9871: 0x69AA, //CJK UNIFIED IDEOGRAPH + 0x9872: 0x69AC, //CJK UNIFIED IDEOGRAPH + 0x9873: 0x69AE, //CJK UNIFIED IDEOGRAPH + 0x9874: 0x69AF, //CJK UNIFIED IDEOGRAPH + 0x9875: 0x69B0, //CJK UNIFIED IDEOGRAPH + 0x9876: 0x69B2, //CJK UNIFIED IDEOGRAPH + 0x9877: 0x69B3, //CJK UNIFIED IDEOGRAPH + 0x9878: 0x69B5, //CJK UNIFIED IDEOGRAPH + 0x9879: 0x69B6, //CJK UNIFIED IDEOGRAPH + 0x987A: 0x69B8, //CJK UNIFIED IDEOGRAPH + 0x987B: 0x69B9, //CJK UNIFIED IDEOGRAPH + 0x987C: 0x69BA, //CJK UNIFIED IDEOGRAPH + 0x987D: 0x69BC, //CJK UNIFIED IDEOGRAPH + 0x987E: 0x69BD, //CJK UNIFIED IDEOGRAPH + 0x9880: 0x69BE, //CJK UNIFIED IDEOGRAPH + 0x9881: 0x69BF, //CJK UNIFIED IDEOGRAPH + 0x9882: 0x69C0, //CJK UNIFIED IDEOGRAPH + 0x9883: 0x69C2, //CJK UNIFIED IDEOGRAPH + 0x9884: 0x69C3, //CJK UNIFIED IDEOGRAPH + 0x9885: 0x69C4, //CJK UNIFIED IDEOGRAPH + 0x9886: 0x69C5, //CJK UNIFIED IDEOGRAPH + 0x9887: 0x69C6, //CJK UNIFIED IDEOGRAPH + 0x9888: 0x69C7, //CJK UNIFIED IDEOGRAPH + 0x9889: 0x69C8, //CJK UNIFIED IDEOGRAPH + 0x988A: 0x69C9, //CJK UNIFIED IDEOGRAPH + 0x988B: 0x69CB, //CJK UNIFIED IDEOGRAPH + 0x988C: 0x69CD, //CJK UNIFIED IDEOGRAPH + 0x988D: 0x69CF, //CJK UNIFIED IDEOGRAPH + 0x988E: 0x69D1, //CJK UNIFIED IDEOGRAPH + 0x988F: 0x69D2, //CJK UNIFIED IDEOGRAPH + 0x9890: 0x69D3, //CJK UNIFIED IDEOGRAPH + 0x9891: 0x69D5, //CJK UNIFIED IDEOGRAPH + 0x9892: 0x69D6, //CJK UNIFIED IDEOGRAPH + 0x9893: 0x69D7, //CJK UNIFIED IDEOGRAPH + 0x9894: 0x69D8, //CJK UNIFIED IDEOGRAPH + 0x9895: 0x69D9, //CJK UNIFIED IDEOGRAPH + 0x9896: 0x69DA, //CJK UNIFIED IDEOGRAPH + 0x9897: 0x69DC, //CJK UNIFIED IDEOGRAPH + 0x9898: 0x69DD, //CJK UNIFIED IDEOGRAPH + 0x9899: 0x69DE, //CJK UNIFIED IDEOGRAPH + 0x989A: 0x69E1, //CJK UNIFIED IDEOGRAPH + 0x989B: 0x69E2, //CJK UNIFIED IDEOGRAPH + 0x989C: 0x69E3, //CJK UNIFIED IDEOGRAPH + 0x989D: 0x69E4, //CJK UNIFIED IDEOGRAPH + 0x989E: 0x69E5, //CJK UNIFIED IDEOGRAPH + 0x989F: 0x69E6, //CJK UNIFIED IDEOGRAPH + 0x98A0: 0x69E7, //CJK UNIFIED IDEOGRAPH + 0x98A1: 0x69E8, //CJK UNIFIED IDEOGRAPH + 0x98A2: 0x69E9, //CJK UNIFIED IDEOGRAPH + 0x98A3: 0x69EA, //CJK UNIFIED IDEOGRAPH + 0x98A4: 0x69EB, //CJK UNIFIED IDEOGRAPH + 0x98A5: 0x69EC, //CJK UNIFIED IDEOGRAPH + 0x98A6: 0x69EE, //CJK UNIFIED IDEOGRAPH + 0x98A7: 0x69EF, //CJK UNIFIED IDEOGRAPH + 0x98A8: 0x69F0, //CJK UNIFIED IDEOGRAPH + 0x98A9: 0x69F1, //CJK UNIFIED IDEOGRAPH + 0x98AA: 0x69F3, //CJK UNIFIED IDEOGRAPH + 0x98AB: 0x69F4, //CJK UNIFIED IDEOGRAPH + 0x98AC: 0x69F5, //CJK UNIFIED IDEOGRAPH + 0x98AD: 0x69F6, //CJK UNIFIED IDEOGRAPH + 0x98AE: 0x69F7, //CJK UNIFIED IDEOGRAPH + 0x98AF: 0x69F8, //CJK UNIFIED IDEOGRAPH + 0x98B0: 0x69F9, //CJK UNIFIED IDEOGRAPH + 0x98B1: 0x69FA, //CJK UNIFIED IDEOGRAPH + 0x98B2: 0x69FB, //CJK UNIFIED IDEOGRAPH + 0x98B3: 0x69FC, //CJK UNIFIED IDEOGRAPH + 0x98B4: 0x69FE, //CJK UNIFIED IDEOGRAPH + 0x98B5: 0x6A00, //CJK UNIFIED IDEOGRAPH + 0x98B6: 0x6A01, //CJK UNIFIED IDEOGRAPH + 0x98B7: 0x6A02, //CJK UNIFIED IDEOGRAPH + 0x98B8: 0x6A03, //CJK UNIFIED IDEOGRAPH + 0x98B9: 0x6A04, //CJK UNIFIED IDEOGRAPH + 0x98BA: 0x6A05, //CJK UNIFIED IDEOGRAPH + 0x98BB: 0x6A06, //CJK UNIFIED IDEOGRAPH + 0x98BC: 0x6A07, //CJK UNIFIED IDEOGRAPH + 0x98BD: 0x6A08, //CJK UNIFIED IDEOGRAPH + 0x98BE: 0x6A09, //CJK UNIFIED IDEOGRAPH + 0x98BF: 0x6A0B, //CJK UNIFIED IDEOGRAPH + 0x98C0: 0x6A0C, //CJK UNIFIED IDEOGRAPH + 0x98C1: 0x6A0D, //CJK UNIFIED IDEOGRAPH + 0x98C2: 0x6A0E, //CJK UNIFIED IDEOGRAPH + 0x98C3: 0x6A0F, //CJK UNIFIED IDEOGRAPH + 0x98C4: 0x6A10, //CJK UNIFIED IDEOGRAPH + 0x98C5: 0x6A11, //CJK UNIFIED IDEOGRAPH + 0x98C6: 0x6A12, //CJK UNIFIED IDEOGRAPH + 0x98C7: 0x6A13, //CJK UNIFIED IDEOGRAPH + 0x98C8: 0x6A14, //CJK UNIFIED IDEOGRAPH + 0x98C9: 0x6A15, //CJK UNIFIED IDEOGRAPH + 0x98CA: 0x6A16, //CJK UNIFIED IDEOGRAPH + 0x98CB: 0x6A19, //CJK UNIFIED IDEOGRAPH + 0x98CC: 0x6A1A, //CJK UNIFIED IDEOGRAPH + 0x98CD: 0x6A1B, //CJK UNIFIED IDEOGRAPH + 0x98CE: 0x6A1C, //CJK UNIFIED IDEOGRAPH + 0x98CF: 0x6A1D, //CJK UNIFIED IDEOGRAPH + 0x98D0: 0x6A1E, //CJK UNIFIED IDEOGRAPH + 0x98D1: 0x6A20, //CJK UNIFIED IDEOGRAPH + 0x98D2: 0x6A22, //CJK UNIFIED IDEOGRAPH + 0x98D3: 0x6A23, //CJK UNIFIED IDEOGRAPH + 0x98D4: 0x6A24, //CJK UNIFIED IDEOGRAPH + 0x98D5: 0x6A25, //CJK UNIFIED IDEOGRAPH + 0x98D6: 0x6A26, //CJK UNIFIED IDEOGRAPH + 0x98D7: 0x6A27, //CJK UNIFIED IDEOGRAPH + 0x98D8: 0x6A29, //CJK UNIFIED IDEOGRAPH + 0x98D9: 0x6A2B, //CJK UNIFIED IDEOGRAPH + 0x98DA: 0x6A2C, //CJK UNIFIED IDEOGRAPH + 0x98DB: 0x6A2D, //CJK UNIFIED IDEOGRAPH + 0x98DC: 0x6A2E, //CJK UNIFIED IDEOGRAPH + 0x98DD: 0x6A30, //CJK UNIFIED IDEOGRAPH + 0x98DE: 0x6A32, //CJK UNIFIED IDEOGRAPH + 0x98DF: 0x6A33, //CJK UNIFIED IDEOGRAPH + 0x98E0: 0x6A34, //CJK UNIFIED IDEOGRAPH + 0x98E1: 0x6A36, //CJK UNIFIED IDEOGRAPH + 0x98E2: 0x6A37, //CJK UNIFIED IDEOGRAPH + 0x98E3: 0x6A38, //CJK UNIFIED IDEOGRAPH + 0x98E4: 0x6A39, //CJK UNIFIED IDEOGRAPH + 0x98E5: 0x6A3A, //CJK UNIFIED IDEOGRAPH + 0x98E6: 0x6A3B, //CJK UNIFIED IDEOGRAPH + 0x98E7: 0x6A3C, //CJK UNIFIED IDEOGRAPH + 0x98E8: 0x6A3F, //CJK UNIFIED IDEOGRAPH + 0x98E9: 0x6A40, //CJK UNIFIED IDEOGRAPH + 0x98EA: 0x6A41, //CJK UNIFIED IDEOGRAPH + 0x98EB: 0x6A42, //CJK UNIFIED IDEOGRAPH + 0x98EC: 0x6A43, //CJK UNIFIED IDEOGRAPH + 0x98ED: 0x6A45, //CJK UNIFIED IDEOGRAPH + 0x98EE: 0x6A46, //CJK UNIFIED IDEOGRAPH + 0x98EF: 0x6A48, //CJK UNIFIED IDEOGRAPH + 0x98F0: 0x6A49, //CJK UNIFIED IDEOGRAPH + 0x98F1: 0x6A4A, //CJK UNIFIED IDEOGRAPH + 0x98F2: 0x6A4B, //CJK UNIFIED IDEOGRAPH + 0x98F3: 0x6A4C, //CJK UNIFIED IDEOGRAPH + 0x98F4: 0x6A4D, //CJK UNIFIED IDEOGRAPH + 0x98F5: 0x6A4E, //CJK UNIFIED IDEOGRAPH + 0x98F6: 0x6A4F, //CJK UNIFIED IDEOGRAPH + 0x98F7: 0x6A51, //CJK UNIFIED IDEOGRAPH + 0x98F8: 0x6A52, //CJK UNIFIED IDEOGRAPH + 0x98F9: 0x6A53, //CJK UNIFIED IDEOGRAPH + 0x98FA: 0x6A54, //CJK UNIFIED IDEOGRAPH + 0x98FB: 0x6A55, //CJK UNIFIED IDEOGRAPH + 0x98FC: 0x6A56, //CJK UNIFIED IDEOGRAPH + 0x98FD: 0x6A57, //CJK UNIFIED IDEOGRAPH + 0x98FE: 0x6A5A, //CJK UNIFIED IDEOGRAPH + 0x9940: 0x6A5C, //CJK UNIFIED IDEOGRAPH + 0x9941: 0x6A5D, //CJK UNIFIED IDEOGRAPH + 0x9942: 0x6A5E, //CJK UNIFIED IDEOGRAPH + 0x9943: 0x6A5F, //CJK UNIFIED IDEOGRAPH + 0x9944: 0x6A60, //CJK UNIFIED IDEOGRAPH + 0x9945: 0x6A62, //CJK UNIFIED IDEOGRAPH + 0x9946: 0x6A63, //CJK UNIFIED IDEOGRAPH + 0x9947: 0x6A64, //CJK UNIFIED IDEOGRAPH + 0x9948: 0x6A66, //CJK UNIFIED IDEOGRAPH + 0x9949: 0x6A67, //CJK UNIFIED IDEOGRAPH + 0x994A: 0x6A68, //CJK UNIFIED IDEOGRAPH + 0x994B: 0x6A69, //CJK UNIFIED IDEOGRAPH + 0x994C: 0x6A6A, //CJK UNIFIED IDEOGRAPH + 0x994D: 0x6A6B, //CJK UNIFIED IDEOGRAPH + 0x994E: 0x6A6C, //CJK UNIFIED IDEOGRAPH + 0x994F: 0x6A6D, //CJK UNIFIED IDEOGRAPH + 0x9950: 0x6A6E, //CJK UNIFIED IDEOGRAPH + 0x9951: 0x6A6F, //CJK UNIFIED IDEOGRAPH + 0x9952: 0x6A70, //CJK UNIFIED IDEOGRAPH + 0x9953: 0x6A72, //CJK UNIFIED IDEOGRAPH + 0x9954: 0x6A73, //CJK UNIFIED IDEOGRAPH + 0x9955: 0x6A74, //CJK UNIFIED IDEOGRAPH + 0x9956: 0x6A75, //CJK UNIFIED IDEOGRAPH + 0x9957: 0x6A76, //CJK UNIFIED IDEOGRAPH + 0x9958: 0x6A77, //CJK UNIFIED IDEOGRAPH + 0x9959: 0x6A78, //CJK UNIFIED IDEOGRAPH + 0x995A: 0x6A7A, //CJK UNIFIED IDEOGRAPH + 0x995B: 0x6A7B, //CJK UNIFIED IDEOGRAPH + 0x995C: 0x6A7D, //CJK UNIFIED IDEOGRAPH + 0x995D: 0x6A7E, //CJK UNIFIED IDEOGRAPH + 0x995E: 0x6A7F, //CJK UNIFIED IDEOGRAPH + 0x995F: 0x6A81, //CJK UNIFIED IDEOGRAPH + 0x9960: 0x6A82, //CJK UNIFIED IDEOGRAPH + 0x9961: 0x6A83, //CJK UNIFIED IDEOGRAPH + 0x9962: 0x6A85, //CJK UNIFIED IDEOGRAPH + 0x9963: 0x6A86, //CJK UNIFIED IDEOGRAPH + 0x9964: 0x6A87, //CJK UNIFIED IDEOGRAPH + 0x9965: 0x6A88, //CJK UNIFIED IDEOGRAPH + 0x9966: 0x6A89, //CJK UNIFIED IDEOGRAPH + 0x9967: 0x6A8A, //CJK UNIFIED IDEOGRAPH + 0x9968: 0x6A8B, //CJK UNIFIED IDEOGRAPH + 0x9969: 0x6A8C, //CJK UNIFIED IDEOGRAPH + 0x996A: 0x6A8D, //CJK UNIFIED IDEOGRAPH + 0x996B: 0x6A8F, //CJK UNIFIED IDEOGRAPH + 0x996C: 0x6A92, //CJK UNIFIED IDEOGRAPH + 0x996D: 0x6A93, //CJK UNIFIED IDEOGRAPH + 0x996E: 0x6A94, //CJK UNIFIED IDEOGRAPH + 0x996F: 0x6A95, //CJK UNIFIED IDEOGRAPH + 0x9970: 0x6A96, //CJK UNIFIED IDEOGRAPH + 0x9971: 0x6A98, //CJK UNIFIED IDEOGRAPH + 0x9972: 0x6A99, //CJK UNIFIED IDEOGRAPH + 0x9973: 0x6A9A, //CJK UNIFIED IDEOGRAPH + 0x9974: 0x6A9B, //CJK UNIFIED IDEOGRAPH + 0x9975: 0x6A9C, //CJK UNIFIED IDEOGRAPH + 0x9976: 0x6A9D, //CJK UNIFIED IDEOGRAPH + 0x9977: 0x6A9E, //CJK UNIFIED IDEOGRAPH + 0x9978: 0x6A9F, //CJK UNIFIED IDEOGRAPH + 0x9979: 0x6AA1, //CJK UNIFIED IDEOGRAPH + 0x997A: 0x6AA2, //CJK UNIFIED IDEOGRAPH + 0x997B: 0x6AA3, //CJK UNIFIED IDEOGRAPH + 0x997C: 0x6AA4, //CJK UNIFIED IDEOGRAPH + 0x997D: 0x6AA5, //CJK UNIFIED IDEOGRAPH + 0x997E: 0x6AA6, //CJK UNIFIED IDEOGRAPH + 0x9980: 0x6AA7, //CJK UNIFIED IDEOGRAPH + 0x9981: 0x6AA8, //CJK UNIFIED IDEOGRAPH + 0x9982: 0x6AAA, //CJK UNIFIED IDEOGRAPH + 0x9983: 0x6AAD, //CJK UNIFIED IDEOGRAPH + 0x9984: 0x6AAE, //CJK UNIFIED IDEOGRAPH + 0x9985: 0x6AAF, //CJK UNIFIED IDEOGRAPH + 0x9986: 0x6AB0, //CJK UNIFIED IDEOGRAPH + 0x9987: 0x6AB1, //CJK UNIFIED IDEOGRAPH + 0x9988: 0x6AB2, //CJK UNIFIED IDEOGRAPH + 0x9989: 0x6AB3, //CJK UNIFIED IDEOGRAPH + 0x998A: 0x6AB4, //CJK UNIFIED IDEOGRAPH + 0x998B: 0x6AB5, //CJK UNIFIED IDEOGRAPH + 0x998C: 0x6AB6, //CJK UNIFIED IDEOGRAPH + 0x998D: 0x6AB7, //CJK UNIFIED IDEOGRAPH + 0x998E: 0x6AB8, //CJK UNIFIED IDEOGRAPH + 0x998F: 0x6AB9, //CJK UNIFIED IDEOGRAPH + 0x9990: 0x6ABA, //CJK UNIFIED IDEOGRAPH + 0x9991: 0x6ABB, //CJK UNIFIED IDEOGRAPH + 0x9992: 0x6ABC, //CJK UNIFIED IDEOGRAPH + 0x9993: 0x6ABD, //CJK UNIFIED IDEOGRAPH + 0x9994: 0x6ABE, //CJK UNIFIED IDEOGRAPH + 0x9995: 0x6ABF, //CJK UNIFIED IDEOGRAPH + 0x9996: 0x6AC0, //CJK UNIFIED IDEOGRAPH + 0x9997: 0x6AC1, //CJK UNIFIED IDEOGRAPH + 0x9998: 0x6AC2, //CJK UNIFIED IDEOGRAPH + 0x9999: 0x6AC3, //CJK UNIFIED IDEOGRAPH + 0x999A: 0x6AC4, //CJK UNIFIED IDEOGRAPH + 0x999B: 0x6AC5, //CJK UNIFIED IDEOGRAPH + 0x999C: 0x6AC6, //CJK UNIFIED IDEOGRAPH + 0x999D: 0x6AC7, //CJK UNIFIED IDEOGRAPH + 0x999E: 0x6AC8, //CJK UNIFIED IDEOGRAPH + 0x999F: 0x6AC9, //CJK UNIFIED IDEOGRAPH + 0x99A0: 0x6ACA, //CJK UNIFIED IDEOGRAPH + 0x99A1: 0x6ACB, //CJK UNIFIED IDEOGRAPH + 0x99A2: 0x6ACC, //CJK UNIFIED IDEOGRAPH + 0x99A3: 0x6ACD, //CJK UNIFIED IDEOGRAPH + 0x99A4: 0x6ACE, //CJK UNIFIED IDEOGRAPH + 0x99A5: 0x6ACF, //CJK UNIFIED IDEOGRAPH + 0x99A6: 0x6AD0, //CJK UNIFIED IDEOGRAPH + 0x99A7: 0x6AD1, //CJK UNIFIED IDEOGRAPH + 0x99A8: 0x6AD2, //CJK UNIFIED IDEOGRAPH + 0x99A9: 0x6AD3, //CJK UNIFIED IDEOGRAPH + 0x99AA: 0x6AD4, //CJK UNIFIED IDEOGRAPH + 0x99AB: 0x6AD5, //CJK UNIFIED IDEOGRAPH + 0x99AC: 0x6AD6, //CJK UNIFIED IDEOGRAPH + 0x99AD: 0x6AD7, //CJK UNIFIED IDEOGRAPH + 0x99AE: 0x6AD8, //CJK UNIFIED IDEOGRAPH + 0x99AF: 0x6AD9, //CJK UNIFIED IDEOGRAPH + 0x99B0: 0x6ADA, //CJK UNIFIED IDEOGRAPH + 0x99B1: 0x6ADB, //CJK UNIFIED IDEOGRAPH + 0x99B2: 0x6ADC, //CJK UNIFIED IDEOGRAPH + 0x99B3: 0x6ADD, //CJK UNIFIED IDEOGRAPH + 0x99B4: 0x6ADE, //CJK UNIFIED IDEOGRAPH + 0x99B5: 0x6ADF, //CJK UNIFIED IDEOGRAPH + 0x99B6: 0x6AE0, //CJK UNIFIED IDEOGRAPH + 0x99B7: 0x6AE1, //CJK UNIFIED IDEOGRAPH + 0x99B8: 0x6AE2, //CJK UNIFIED IDEOGRAPH + 0x99B9: 0x6AE3, //CJK UNIFIED IDEOGRAPH + 0x99BA: 0x6AE4, //CJK UNIFIED IDEOGRAPH + 0x99BB: 0x6AE5, //CJK UNIFIED IDEOGRAPH + 0x99BC: 0x6AE6, //CJK UNIFIED IDEOGRAPH + 0x99BD: 0x6AE7, //CJK UNIFIED IDEOGRAPH + 0x99BE: 0x6AE8, //CJK UNIFIED IDEOGRAPH + 0x99BF: 0x6AE9, //CJK UNIFIED IDEOGRAPH + 0x99C0: 0x6AEA, //CJK UNIFIED IDEOGRAPH + 0x99C1: 0x6AEB, //CJK UNIFIED IDEOGRAPH + 0x99C2: 0x6AEC, //CJK UNIFIED IDEOGRAPH + 0x99C3: 0x6AED, //CJK UNIFIED IDEOGRAPH + 0x99C4: 0x6AEE, //CJK UNIFIED IDEOGRAPH + 0x99C5: 0x6AEF, //CJK UNIFIED IDEOGRAPH + 0x99C6: 0x6AF0, //CJK UNIFIED IDEOGRAPH + 0x99C7: 0x6AF1, //CJK UNIFIED IDEOGRAPH + 0x99C8: 0x6AF2, //CJK UNIFIED IDEOGRAPH + 0x99C9: 0x6AF3, //CJK UNIFIED IDEOGRAPH + 0x99CA: 0x6AF4, //CJK UNIFIED IDEOGRAPH + 0x99CB: 0x6AF5, //CJK UNIFIED IDEOGRAPH + 0x99CC: 0x6AF6, //CJK UNIFIED IDEOGRAPH + 0x99CD: 0x6AF7, //CJK UNIFIED IDEOGRAPH + 0x99CE: 0x6AF8, //CJK UNIFIED IDEOGRAPH + 0x99CF: 0x6AF9, //CJK UNIFIED IDEOGRAPH + 0x99D0: 0x6AFA, //CJK UNIFIED IDEOGRAPH + 0x99D1: 0x6AFB, //CJK UNIFIED IDEOGRAPH + 0x99D2: 0x6AFC, //CJK UNIFIED IDEOGRAPH + 0x99D3: 0x6AFD, //CJK UNIFIED IDEOGRAPH + 0x99D4: 0x6AFE, //CJK UNIFIED IDEOGRAPH + 0x99D5: 0x6AFF, //CJK UNIFIED IDEOGRAPH + 0x99D6: 0x6B00, //CJK UNIFIED IDEOGRAPH + 0x99D7: 0x6B01, //CJK UNIFIED IDEOGRAPH + 0x99D8: 0x6B02, //CJK UNIFIED IDEOGRAPH + 0x99D9: 0x6B03, //CJK UNIFIED IDEOGRAPH + 0x99DA: 0x6B04, //CJK UNIFIED IDEOGRAPH + 0x99DB: 0x6B05, //CJK UNIFIED IDEOGRAPH + 0x99DC: 0x6B06, //CJK UNIFIED IDEOGRAPH + 0x99DD: 0x6B07, //CJK UNIFIED IDEOGRAPH + 0x99DE: 0x6B08, //CJK UNIFIED IDEOGRAPH + 0x99DF: 0x6B09, //CJK UNIFIED IDEOGRAPH + 0x99E0: 0x6B0A, //CJK UNIFIED IDEOGRAPH + 0x99E1: 0x6B0B, //CJK UNIFIED IDEOGRAPH + 0x99E2: 0x6B0C, //CJK UNIFIED IDEOGRAPH + 0x99E3: 0x6B0D, //CJK UNIFIED IDEOGRAPH + 0x99E4: 0x6B0E, //CJK UNIFIED IDEOGRAPH + 0x99E5: 0x6B0F, //CJK UNIFIED IDEOGRAPH + 0x99E6: 0x6B10, //CJK UNIFIED IDEOGRAPH + 0x99E7: 0x6B11, //CJK UNIFIED IDEOGRAPH + 0x99E8: 0x6B12, //CJK UNIFIED IDEOGRAPH + 0x99E9: 0x6B13, //CJK UNIFIED IDEOGRAPH + 0x99EA: 0x6B14, //CJK UNIFIED IDEOGRAPH + 0x99EB: 0x6B15, //CJK UNIFIED IDEOGRAPH + 0x99EC: 0x6B16, //CJK UNIFIED IDEOGRAPH + 0x99ED: 0x6B17, //CJK UNIFIED IDEOGRAPH + 0x99EE: 0x6B18, //CJK UNIFIED IDEOGRAPH + 0x99EF: 0x6B19, //CJK UNIFIED IDEOGRAPH + 0x99F0: 0x6B1A, //CJK UNIFIED IDEOGRAPH + 0x99F1: 0x6B1B, //CJK UNIFIED IDEOGRAPH + 0x99F2: 0x6B1C, //CJK UNIFIED IDEOGRAPH + 0x99F3: 0x6B1D, //CJK UNIFIED IDEOGRAPH + 0x99F4: 0x6B1E, //CJK UNIFIED IDEOGRAPH + 0x99F5: 0x6B1F, //CJK UNIFIED IDEOGRAPH + 0x99F6: 0x6B25, //CJK UNIFIED IDEOGRAPH + 0x99F7: 0x6B26, //CJK UNIFIED IDEOGRAPH + 0x99F8: 0x6B28, //CJK UNIFIED IDEOGRAPH + 0x99F9: 0x6B29, //CJK UNIFIED IDEOGRAPH + 0x99FA: 0x6B2A, //CJK UNIFIED IDEOGRAPH + 0x99FB: 0x6B2B, //CJK UNIFIED IDEOGRAPH + 0x99FC: 0x6B2C, //CJK UNIFIED IDEOGRAPH + 0x99FD: 0x6B2D, //CJK UNIFIED IDEOGRAPH + 0x99FE: 0x6B2E, //CJK UNIFIED IDEOGRAPH + 0x9A40: 0x6B2F, //CJK UNIFIED IDEOGRAPH + 0x9A41: 0x6B30, //CJK UNIFIED IDEOGRAPH + 0x9A42: 0x6B31, //CJK UNIFIED IDEOGRAPH + 0x9A43: 0x6B33, //CJK UNIFIED IDEOGRAPH + 0x9A44: 0x6B34, //CJK UNIFIED IDEOGRAPH + 0x9A45: 0x6B35, //CJK UNIFIED IDEOGRAPH + 0x9A46: 0x6B36, //CJK UNIFIED IDEOGRAPH + 0x9A47: 0x6B38, //CJK UNIFIED IDEOGRAPH + 0x9A48: 0x6B3B, //CJK UNIFIED IDEOGRAPH + 0x9A49: 0x6B3C, //CJK UNIFIED IDEOGRAPH + 0x9A4A: 0x6B3D, //CJK UNIFIED IDEOGRAPH + 0x9A4B: 0x6B3F, //CJK UNIFIED IDEOGRAPH + 0x9A4C: 0x6B40, //CJK UNIFIED IDEOGRAPH + 0x9A4D: 0x6B41, //CJK UNIFIED IDEOGRAPH + 0x9A4E: 0x6B42, //CJK UNIFIED IDEOGRAPH + 0x9A4F: 0x6B44, //CJK UNIFIED IDEOGRAPH + 0x9A50: 0x6B45, //CJK UNIFIED IDEOGRAPH + 0x9A51: 0x6B48, //CJK UNIFIED IDEOGRAPH + 0x9A52: 0x6B4A, //CJK UNIFIED IDEOGRAPH + 0x9A53: 0x6B4B, //CJK UNIFIED IDEOGRAPH + 0x9A54: 0x6B4D, //CJK UNIFIED IDEOGRAPH + 0x9A55: 0x6B4E, //CJK UNIFIED IDEOGRAPH + 0x9A56: 0x6B4F, //CJK UNIFIED IDEOGRAPH + 0x9A57: 0x6B50, //CJK UNIFIED IDEOGRAPH + 0x9A58: 0x6B51, //CJK UNIFIED IDEOGRAPH + 0x9A59: 0x6B52, //CJK UNIFIED IDEOGRAPH + 0x9A5A: 0x6B53, //CJK UNIFIED IDEOGRAPH + 0x9A5B: 0x6B54, //CJK UNIFIED IDEOGRAPH + 0x9A5C: 0x6B55, //CJK UNIFIED IDEOGRAPH + 0x9A5D: 0x6B56, //CJK UNIFIED IDEOGRAPH + 0x9A5E: 0x6B57, //CJK UNIFIED IDEOGRAPH + 0x9A5F: 0x6B58, //CJK UNIFIED IDEOGRAPH + 0x9A60: 0x6B5A, //CJK UNIFIED IDEOGRAPH + 0x9A61: 0x6B5B, //CJK UNIFIED IDEOGRAPH + 0x9A62: 0x6B5C, //CJK UNIFIED IDEOGRAPH + 0x9A63: 0x6B5D, //CJK UNIFIED IDEOGRAPH + 0x9A64: 0x6B5E, //CJK UNIFIED IDEOGRAPH + 0x9A65: 0x6B5F, //CJK UNIFIED IDEOGRAPH + 0x9A66: 0x6B60, //CJK UNIFIED IDEOGRAPH + 0x9A67: 0x6B61, //CJK UNIFIED IDEOGRAPH + 0x9A68: 0x6B68, //CJK UNIFIED IDEOGRAPH + 0x9A69: 0x6B69, //CJK UNIFIED IDEOGRAPH + 0x9A6A: 0x6B6B, //CJK UNIFIED IDEOGRAPH + 0x9A6B: 0x6B6C, //CJK UNIFIED IDEOGRAPH + 0x9A6C: 0x6B6D, //CJK UNIFIED IDEOGRAPH + 0x9A6D: 0x6B6E, //CJK UNIFIED IDEOGRAPH + 0x9A6E: 0x6B6F, //CJK UNIFIED IDEOGRAPH + 0x9A6F: 0x6B70, //CJK UNIFIED IDEOGRAPH + 0x9A70: 0x6B71, //CJK UNIFIED IDEOGRAPH + 0x9A71: 0x6B72, //CJK UNIFIED IDEOGRAPH + 0x9A72: 0x6B73, //CJK UNIFIED IDEOGRAPH + 0x9A73: 0x6B74, //CJK UNIFIED IDEOGRAPH + 0x9A74: 0x6B75, //CJK UNIFIED IDEOGRAPH + 0x9A75: 0x6B76, //CJK UNIFIED IDEOGRAPH + 0x9A76: 0x6B77, //CJK UNIFIED IDEOGRAPH + 0x9A77: 0x6B78, //CJK UNIFIED IDEOGRAPH + 0x9A78: 0x6B7A, //CJK UNIFIED IDEOGRAPH + 0x9A79: 0x6B7D, //CJK UNIFIED IDEOGRAPH + 0x9A7A: 0x6B7E, //CJK UNIFIED IDEOGRAPH + 0x9A7B: 0x6B7F, //CJK UNIFIED IDEOGRAPH + 0x9A7C: 0x6B80, //CJK UNIFIED IDEOGRAPH + 0x9A7D: 0x6B85, //CJK UNIFIED IDEOGRAPH + 0x9A7E: 0x6B88, //CJK UNIFIED IDEOGRAPH + 0x9A80: 0x6B8C, //CJK UNIFIED IDEOGRAPH + 0x9A81: 0x6B8E, //CJK UNIFIED IDEOGRAPH + 0x9A82: 0x6B8F, //CJK UNIFIED IDEOGRAPH + 0x9A83: 0x6B90, //CJK UNIFIED IDEOGRAPH + 0x9A84: 0x6B91, //CJK UNIFIED IDEOGRAPH + 0x9A85: 0x6B94, //CJK UNIFIED IDEOGRAPH + 0x9A86: 0x6B95, //CJK UNIFIED IDEOGRAPH + 0x9A87: 0x6B97, //CJK UNIFIED IDEOGRAPH + 0x9A88: 0x6B98, //CJK UNIFIED IDEOGRAPH + 0x9A89: 0x6B99, //CJK UNIFIED IDEOGRAPH + 0x9A8A: 0x6B9C, //CJK UNIFIED IDEOGRAPH + 0x9A8B: 0x6B9D, //CJK UNIFIED IDEOGRAPH + 0x9A8C: 0x6B9E, //CJK UNIFIED IDEOGRAPH + 0x9A8D: 0x6B9F, //CJK UNIFIED IDEOGRAPH + 0x9A8E: 0x6BA0, //CJK UNIFIED IDEOGRAPH + 0x9A8F: 0x6BA2, //CJK UNIFIED IDEOGRAPH + 0x9A90: 0x6BA3, //CJK UNIFIED IDEOGRAPH + 0x9A91: 0x6BA4, //CJK UNIFIED IDEOGRAPH + 0x9A92: 0x6BA5, //CJK UNIFIED IDEOGRAPH + 0x9A93: 0x6BA6, //CJK UNIFIED IDEOGRAPH + 0x9A94: 0x6BA7, //CJK UNIFIED IDEOGRAPH + 0x9A95: 0x6BA8, //CJK UNIFIED IDEOGRAPH + 0x9A96: 0x6BA9, //CJK UNIFIED IDEOGRAPH + 0x9A97: 0x6BAB, //CJK UNIFIED IDEOGRAPH + 0x9A98: 0x6BAC, //CJK UNIFIED IDEOGRAPH + 0x9A99: 0x6BAD, //CJK UNIFIED IDEOGRAPH + 0x9A9A: 0x6BAE, //CJK UNIFIED IDEOGRAPH + 0x9A9B: 0x6BAF, //CJK UNIFIED IDEOGRAPH + 0x9A9C: 0x6BB0, //CJK UNIFIED IDEOGRAPH + 0x9A9D: 0x6BB1, //CJK UNIFIED IDEOGRAPH + 0x9A9E: 0x6BB2, //CJK UNIFIED IDEOGRAPH + 0x9A9F: 0x6BB6, //CJK UNIFIED IDEOGRAPH + 0x9AA0: 0x6BB8, //CJK UNIFIED IDEOGRAPH + 0x9AA1: 0x6BB9, //CJK UNIFIED IDEOGRAPH + 0x9AA2: 0x6BBA, //CJK UNIFIED IDEOGRAPH + 0x9AA3: 0x6BBB, //CJK UNIFIED IDEOGRAPH + 0x9AA4: 0x6BBC, //CJK UNIFIED IDEOGRAPH + 0x9AA5: 0x6BBD, //CJK UNIFIED IDEOGRAPH + 0x9AA6: 0x6BBE, //CJK UNIFIED IDEOGRAPH + 0x9AA7: 0x6BC0, //CJK UNIFIED IDEOGRAPH + 0x9AA8: 0x6BC3, //CJK UNIFIED IDEOGRAPH + 0x9AA9: 0x6BC4, //CJK UNIFIED IDEOGRAPH + 0x9AAA: 0x6BC6, //CJK UNIFIED IDEOGRAPH + 0x9AAB: 0x6BC7, //CJK UNIFIED IDEOGRAPH + 0x9AAC: 0x6BC8, //CJK UNIFIED IDEOGRAPH + 0x9AAD: 0x6BC9, //CJK UNIFIED IDEOGRAPH + 0x9AAE: 0x6BCA, //CJK UNIFIED IDEOGRAPH + 0x9AAF: 0x6BCC, //CJK UNIFIED IDEOGRAPH + 0x9AB0: 0x6BCE, //CJK UNIFIED IDEOGRAPH + 0x9AB1: 0x6BD0, //CJK UNIFIED IDEOGRAPH + 0x9AB2: 0x6BD1, //CJK UNIFIED IDEOGRAPH + 0x9AB3: 0x6BD8, //CJK UNIFIED IDEOGRAPH + 0x9AB4: 0x6BDA, //CJK UNIFIED IDEOGRAPH + 0x9AB5: 0x6BDC, //CJK UNIFIED IDEOGRAPH + 0x9AB6: 0x6BDD, //CJK UNIFIED IDEOGRAPH + 0x9AB7: 0x6BDE, //CJK UNIFIED IDEOGRAPH + 0x9AB8: 0x6BDF, //CJK UNIFIED IDEOGRAPH + 0x9AB9: 0x6BE0, //CJK UNIFIED IDEOGRAPH + 0x9ABA: 0x6BE2, //CJK UNIFIED IDEOGRAPH + 0x9ABB: 0x6BE3, //CJK UNIFIED IDEOGRAPH + 0x9ABC: 0x6BE4, //CJK UNIFIED IDEOGRAPH + 0x9ABD: 0x6BE5, //CJK UNIFIED IDEOGRAPH + 0x9ABE: 0x6BE6, //CJK UNIFIED IDEOGRAPH + 0x9ABF: 0x6BE7, //CJK UNIFIED IDEOGRAPH + 0x9AC0: 0x6BE8, //CJK UNIFIED IDEOGRAPH + 0x9AC1: 0x6BE9, //CJK UNIFIED IDEOGRAPH + 0x9AC2: 0x6BEC, //CJK UNIFIED IDEOGRAPH + 0x9AC3: 0x6BED, //CJK UNIFIED IDEOGRAPH + 0x9AC4: 0x6BEE, //CJK UNIFIED IDEOGRAPH + 0x9AC5: 0x6BF0, //CJK UNIFIED IDEOGRAPH + 0x9AC6: 0x6BF1, //CJK UNIFIED IDEOGRAPH + 0x9AC7: 0x6BF2, //CJK UNIFIED IDEOGRAPH + 0x9AC8: 0x6BF4, //CJK UNIFIED IDEOGRAPH + 0x9AC9: 0x6BF6, //CJK UNIFIED IDEOGRAPH + 0x9ACA: 0x6BF7, //CJK UNIFIED IDEOGRAPH + 0x9ACB: 0x6BF8, //CJK UNIFIED IDEOGRAPH + 0x9ACC: 0x6BFA, //CJK UNIFIED IDEOGRAPH + 0x9ACD: 0x6BFB, //CJK UNIFIED IDEOGRAPH + 0x9ACE: 0x6BFC, //CJK UNIFIED IDEOGRAPH + 0x9ACF: 0x6BFE, //CJK UNIFIED IDEOGRAPH + 0x9AD0: 0x6BFF, //CJK UNIFIED IDEOGRAPH + 0x9AD1: 0x6C00, //CJK UNIFIED IDEOGRAPH + 0x9AD2: 0x6C01, //CJK UNIFIED IDEOGRAPH + 0x9AD3: 0x6C02, //CJK UNIFIED IDEOGRAPH + 0x9AD4: 0x6C03, //CJK UNIFIED IDEOGRAPH + 0x9AD5: 0x6C04, //CJK UNIFIED IDEOGRAPH + 0x9AD6: 0x6C08, //CJK UNIFIED IDEOGRAPH + 0x9AD7: 0x6C09, //CJK UNIFIED IDEOGRAPH + 0x9AD8: 0x6C0A, //CJK UNIFIED IDEOGRAPH + 0x9AD9: 0x6C0B, //CJK UNIFIED IDEOGRAPH + 0x9ADA: 0x6C0C, //CJK UNIFIED IDEOGRAPH + 0x9ADB: 0x6C0E, //CJK UNIFIED IDEOGRAPH + 0x9ADC: 0x6C12, //CJK UNIFIED IDEOGRAPH + 0x9ADD: 0x6C17, //CJK UNIFIED IDEOGRAPH + 0x9ADE: 0x6C1C, //CJK UNIFIED IDEOGRAPH + 0x9ADF: 0x6C1D, //CJK UNIFIED IDEOGRAPH + 0x9AE0: 0x6C1E, //CJK UNIFIED IDEOGRAPH + 0x9AE1: 0x6C20, //CJK UNIFIED IDEOGRAPH + 0x9AE2: 0x6C23, //CJK UNIFIED IDEOGRAPH + 0x9AE3: 0x6C25, //CJK UNIFIED IDEOGRAPH + 0x9AE4: 0x6C2B, //CJK UNIFIED IDEOGRAPH + 0x9AE5: 0x6C2C, //CJK UNIFIED IDEOGRAPH + 0x9AE6: 0x6C2D, //CJK UNIFIED IDEOGRAPH + 0x9AE7: 0x6C31, //CJK UNIFIED IDEOGRAPH + 0x9AE8: 0x6C33, //CJK UNIFIED IDEOGRAPH + 0x9AE9: 0x6C36, //CJK UNIFIED IDEOGRAPH + 0x9AEA: 0x6C37, //CJK UNIFIED IDEOGRAPH + 0x9AEB: 0x6C39, //CJK UNIFIED IDEOGRAPH + 0x9AEC: 0x6C3A, //CJK UNIFIED IDEOGRAPH + 0x9AED: 0x6C3B, //CJK UNIFIED IDEOGRAPH + 0x9AEE: 0x6C3C, //CJK UNIFIED IDEOGRAPH + 0x9AEF: 0x6C3E, //CJK UNIFIED IDEOGRAPH + 0x9AF0: 0x6C3F, //CJK UNIFIED IDEOGRAPH + 0x9AF1: 0x6C43, //CJK UNIFIED IDEOGRAPH + 0x9AF2: 0x6C44, //CJK UNIFIED IDEOGRAPH + 0x9AF3: 0x6C45, //CJK UNIFIED IDEOGRAPH + 0x9AF4: 0x6C48, //CJK UNIFIED IDEOGRAPH + 0x9AF5: 0x6C4B, //CJK UNIFIED IDEOGRAPH + 0x9AF6: 0x6C4C, //CJK UNIFIED IDEOGRAPH + 0x9AF7: 0x6C4D, //CJK UNIFIED IDEOGRAPH + 0x9AF8: 0x6C4E, //CJK UNIFIED IDEOGRAPH + 0x9AF9: 0x6C4F, //CJK UNIFIED IDEOGRAPH + 0x9AFA: 0x6C51, //CJK UNIFIED IDEOGRAPH + 0x9AFB: 0x6C52, //CJK UNIFIED IDEOGRAPH + 0x9AFC: 0x6C53, //CJK UNIFIED IDEOGRAPH + 0x9AFD: 0x6C56, //CJK UNIFIED IDEOGRAPH + 0x9AFE: 0x6C58, //CJK UNIFIED IDEOGRAPH + 0x9B40: 0x6C59, //CJK UNIFIED IDEOGRAPH + 0x9B41: 0x6C5A, //CJK UNIFIED IDEOGRAPH + 0x9B42: 0x6C62, //CJK UNIFIED IDEOGRAPH + 0x9B43: 0x6C63, //CJK UNIFIED IDEOGRAPH + 0x9B44: 0x6C65, //CJK UNIFIED IDEOGRAPH + 0x9B45: 0x6C66, //CJK UNIFIED IDEOGRAPH + 0x9B46: 0x6C67, //CJK UNIFIED IDEOGRAPH + 0x9B47: 0x6C6B, //CJK UNIFIED IDEOGRAPH + 0x9B48: 0x6C6C, //CJK UNIFIED IDEOGRAPH + 0x9B49: 0x6C6D, //CJK UNIFIED IDEOGRAPH + 0x9B4A: 0x6C6E, //CJK UNIFIED IDEOGRAPH + 0x9B4B: 0x6C6F, //CJK UNIFIED IDEOGRAPH + 0x9B4C: 0x6C71, //CJK UNIFIED IDEOGRAPH + 0x9B4D: 0x6C73, //CJK UNIFIED IDEOGRAPH + 0x9B4E: 0x6C75, //CJK UNIFIED IDEOGRAPH + 0x9B4F: 0x6C77, //CJK UNIFIED IDEOGRAPH + 0x9B50: 0x6C78, //CJK UNIFIED IDEOGRAPH + 0x9B51: 0x6C7A, //CJK UNIFIED IDEOGRAPH + 0x9B52: 0x6C7B, //CJK UNIFIED IDEOGRAPH + 0x9B53: 0x6C7C, //CJK UNIFIED IDEOGRAPH + 0x9B54: 0x6C7F, //CJK UNIFIED IDEOGRAPH + 0x9B55: 0x6C80, //CJK UNIFIED IDEOGRAPH + 0x9B56: 0x6C84, //CJK UNIFIED IDEOGRAPH + 0x9B57: 0x6C87, //CJK UNIFIED IDEOGRAPH + 0x9B58: 0x6C8A, //CJK UNIFIED IDEOGRAPH + 0x9B59: 0x6C8B, //CJK UNIFIED IDEOGRAPH + 0x9B5A: 0x6C8D, //CJK UNIFIED IDEOGRAPH + 0x9B5B: 0x6C8E, //CJK UNIFIED IDEOGRAPH + 0x9B5C: 0x6C91, //CJK UNIFIED IDEOGRAPH + 0x9B5D: 0x6C92, //CJK UNIFIED IDEOGRAPH + 0x9B5E: 0x6C95, //CJK UNIFIED IDEOGRAPH + 0x9B5F: 0x6C96, //CJK UNIFIED IDEOGRAPH + 0x9B60: 0x6C97, //CJK UNIFIED IDEOGRAPH + 0x9B61: 0x6C98, //CJK UNIFIED IDEOGRAPH + 0x9B62: 0x6C9A, //CJK UNIFIED IDEOGRAPH + 0x9B63: 0x6C9C, //CJK UNIFIED IDEOGRAPH + 0x9B64: 0x6C9D, //CJK UNIFIED IDEOGRAPH + 0x9B65: 0x6C9E, //CJK UNIFIED IDEOGRAPH + 0x9B66: 0x6CA0, //CJK UNIFIED IDEOGRAPH + 0x9B67: 0x6CA2, //CJK UNIFIED IDEOGRAPH + 0x9B68: 0x6CA8, //CJK UNIFIED IDEOGRAPH + 0x9B69: 0x6CAC, //CJK UNIFIED IDEOGRAPH + 0x9B6A: 0x6CAF, //CJK UNIFIED IDEOGRAPH + 0x9B6B: 0x6CB0, //CJK UNIFIED IDEOGRAPH + 0x9B6C: 0x6CB4, //CJK UNIFIED IDEOGRAPH + 0x9B6D: 0x6CB5, //CJK UNIFIED IDEOGRAPH + 0x9B6E: 0x6CB6, //CJK UNIFIED IDEOGRAPH + 0x9B6F: 0x6CB7, //CJK UNIFIED IDEOGRAPH + 0x9B70: 0x6CBA, //CJK UNIFIED IDEOGRAPH + 0x9B71: 0x6CC0, //CJK UNIFIED IDEOGRAPH + 0x9B72: 0x6CC1, //CJK UNIFIED IDEOGRAPH + 0x9B73: 0x6CC2, //CJK UNIFIED IDEOGRAPH + 0x9B74: 0x6CC3, //CJK UNIFIED IDEOGRAPH + 0x9B75: 0x6CC6, //CJK UNIFIED IDEOGRAPH + 0x9B76: 0x6CC7, //CJK UNIFIED IDEOGRAPH + 0x9B77: 0x6CC8, //CJK UNIFIED IDEOGRAPH + 0x9B78: 0x6CCB, //CJK UNIFIED IDEOGRAPH + 0x9B79: 0x6CCD, //CJK UNIFIED IDEOGRAPH + 0x9B7A: 0x6CCE, //CJK UNIFIED IDEOGRAPH + 0x9B7B: 0x6CCF, //CJK UNIFIED IDEOGRAPH + 0x9B7C: 0x6CD1, //CJK UNIFIED IDEOGRAPH + 0x9B7D: 0x6CD2, //CJK UNIFIED IDEOGRAPH + 0x9B7E: 0x6CD8, //CJK UNIFIED IDEOGRAPH + 0x9B80: 0x6CD9, //CJK UNIFIED IDEOGRAPH + 0x9B81: 0x6CDA, //CJK UNIFIED IDEOGRAPH + 0x9B82: 0x6CDC, //CJK UNIFIED IDEOGRAPH + 0x9B83: 0x6CDD, //CJK UNIFIED IDEOGRAPH + 0x9B84: 0x6CDF, //CJK UNIFIED IDEOGRAPH + 0x9B85: 0x6CE4, //CJK UNIFIED IDEOGRAPH + 0x9B86: 0x6CE6, //CJK UNIFIED IDEOGRAPH + 0x9B87: 0x6CE7, //CJK UNIFIED IDEOGRAPH + 0x9B88: 0x6CE9, //CJK UNIFIED IDEOGRAPH + 0x9B89: 0x6CEC, //CJK UNIFIED IDEOGRAPH + 0x9B8A: 0x6CED, //CJK UNIFIED IDEOGRAPH + 0x9B8B: 0x6CF2, //CJK UNIFIED IDEOGRAPH + 0x9B8C: 0x6CF4, //CJK UNIFIED IDEOGRAPH + 0x9B8D: 0x6CF9, //CJK UNIFIED IDEOGRAPH + 0x9B8E: 0x6CFF, //CJK UNIFIED IDEOGRAPH + 0x9B8F: 0x6D00, //CJK UNIFIED IDEOGRAPH + 0x9B90: 0x6D02, //CJK UNIFIED IDEOGRAPH + 0x9B91: 0x6D03, //CJK UNIFIED IDEOGRAPH + 0x9B92: 0x6D05, //CJK UNIFIED IDEOGRAPH + 0x9B93: 0x6D06, //CJK UNIFIED IDEOGRAPH + 0x9B94: 0x6D08, //CJK UNIFIED IDEOGRAPH + 0x9B95: 0x6D09, //CJK UNIFIED IDEOGRAPH + 0x9B96: 0x6D0A, //CJK UNIFIED IDEOGRAPH + 0x9B97: 0x6D0D, //CJK UNIFIED IDEOGRAPH + 0x9B98: 0x6D0F, //CJK UNIFIED IDEOGRAPH + 0x9B99: 0x6D10, //CJK UNIFIED IDEOGRAPH + 0x9B9A: 0x6D11, //CJK UNIFIED IDEOGRAPH + 0x9B9B: 0x6D13, //CJK UNIFIED IDEOGRAPH + 0x9B9C: 0x6D14, //CJK UNIFIED IDEOGRAPH + 0x9B9D: 0x6D15, //CJK UNIFIED IDEOGRAPH + 0x9B9E: 0x6D16, //CJK UNIFIED IDEOGRAPH + 0x9B9F: 0x6D18, //CJK UNIFIED IDEOGRAPH + 0x9BA0: 0x6D1C, //CJK UNIFIED IDEOGRAPH + 0x9BA1: 0x6D1D, //CJK UNIFIED IDEOGRAPH + 0x9BA2: 0x6D1F, //CJK UNIFIED IDEOGRAPH + 0x9BA3: 0x6D20, //CJK UNIFIED IDEOGRAPH + 0x9BA4: 0x6D21, //CJK UNIFIED IDEOGRAPH + 0x9BA5: 0x6D22, //CJK UNIFIED IDEOGRAPH + 0x9BA6: 0x6D23, //CJK UNIFIED IDEOGRAPH + 0x9BA7: 0x6D24, //CJK UNIFIED IDEOGRAPH + 0x9BA8: 0x6D26, //CJK UNIFIED IDEOGRAPH + 0x9BA9: 0x6D28, //CJK UNIFIED IDEOGRAPH + 0x9BAA: 0x6D29, //CJK UNIFIED IDEOGRAPH + 0x9BAB: 0x6D2C, //CJK UNIFIED IDEOGRAPH + 0x9BAC: 0x6D2D, //CJK UNIFIED IDEOGRAPH + 0x9BAD: 0x6D2F, //CJK UNIFIED IDEOGRAPH + 0x9BAE: 0x6D30, //CJK UNIFIED IDEOGRAPH + 0x9BAF: 0x6D34, //CJK UNIFIED IDEOGRAPH + 0x9BB0: 0x6D36, //CJK UNIFIED IDEOGRAPH + 0x9BB1: 0x6D37, //CJK UNIFIED IDEOGRAPH + 0x9BB2: 0x6D38, //CJK UNIFIED IDEOGRAPH + 0x9BB3: 0x6D3A, //CJK UNIFIED IDEOGRAPH + 0x9BB4: 0x6D3F, //CJK UNIFIED IDEOGRAPH + 0x9BB5: 0x6D40, //CJK UNIFIED IDEOGRAPH + 0x9BB6: 0x6D42, //CJK UNIFIED IDEOGRAPH + 0x9BB7: 0x6D44, //CJK UNIFIED IDEOGRAPH + 0x9BB8: 0x6D49, //CJK UNIFIED IDEOGRAPH + 0x9BB9: 0x6D4C, //CJK UNIFIED IDEOGRAPH + 0x9BBA: 0x6D50, //CJK UNIFIED IDEOGRAPH + 0x9BBB: 0x6D55, //CJK UNIFIED IDEOGRAPH + 0x9BBC: 0x6D56, //CJK UNIFIED IDEOGRAPH + 0x9BBD: 0x6D57, //CJK UNIFIED IDEOGRAPH + 0x9BBE: 0x6D58, //CJK UNIFIED IDEOGRAPH + 0x9BBF: 0x6D5B, //CJK UNIFIED IDEOGRAPH + 0x9BC0: 0x6D5D, //CJK UNIFIED IDEOGRAPH + 0x9BC1: 0x6D5F, //CJK UNIFIED IDEOGRAPH + 0x9BC2: 0x6D61, //CJK UNIFIED IDEOGRAPH + 0x9BC3: 0x6D62, //CJK UNIFIED IDEOGRAPH + 0x9BC4: 0x6D64, //CJK UNIFIED IDEOGRAPH + 0x9BC5: 0x6D65, //CJK UNIFIED IDEOGRAPH + 0x9BC6: 0x6D67, //CJK UNIFIED IDEOGRAPH + 0x9BC7: 0x6D68, //CJK UNIFIED IDEOGRAPH + 0x9BC8: 0x6D6B, //CJK UNIFIED IDEOGRAPH + 0x9BC9: 0x6D6C, //CJK UNIFIED IDEOGRAPH + 0x9BCA: 0x6D6D, //CJK UNIFIED IDEOGRAPH + 0x9BCB: 0x6D70, //CJK UNIFIED IDEOGRAPH + 0x9BCC: 0x6D71, //CJK UNIFIED IDEOGRAPH + 0x9BCD: 0x6D72, //CJK UNIFIED IDEOGRAPH + 0x9BCE: 0x6D73, //CJK UNIFIED IDEOGRAPH + 0x9BCF: 0x6D75, //CJK UNIFIED IDEOGRAPH + 0x9BD0: 0x6D76, //CJK UNIFIED IDEOGRAPH + 0x9BD1: 0x6D79, //CJK UNIFIED IDEOGRAPH + 0x9BD2: 0x6D7A, //CJK UNIFIED IDEOGRAPH + 0x9BD3: 0x6D7B, //CJK UNIFIED IDEOGRAPH + 0x9BD4: 0x6D7D, //CJK UNIFIED IDEOGRAPH + 0x9BD5: 0x6D7E, //CJK UNIFIED IDEOGRAPH + 0x9BD6: 0x6D7F, //CJK UNIFIED IDEOGRAPH + 0x9BD7: 0x6D80, //CJK UNIFIED IDEOGRAPH + 0x9BD8: 0x6D81, //CJK UNIFIED IDEOGRAPH + 0x9BD9: 0x6D83, //CJK UNIFIED IDEOGRAPH + 0x9BDA: 0x6D84, //CJK UNIFIED IDEOGRAPH + 0x9BDB: 0x6D86, //CJK UNIFIED IDEOGRAPH + 0x9BDC: 0x6D87, //CJK UNIFIED IDEOGRAPH + 0x9BDD: 0x6D8A, //CJK UNIFIED IDEOGRAPH + 0x9BDE: 0x6D8B, //CJK UNIFIED IDEOGRAPH + 0x9BDF: 0x6D8D, //CJK UNIFIED IDEOGRAPH + 0x9BE0: 0x6D8F, //CJK UNIFIED IDEOGRAPH + 0x9BE1: 0x6D90, //CJK UNIFIED IDEOGRAPH + 0x9BE2: 0x6D92, //CJK UNIFIED IDEOGRAPH + 0x9BE3: 0x6D96, //CJK UNIFIED IDEOGRAPH + 0x9BE4: 0x6D97, //CJK UNIFIED IDEOGRAPH + 0x9BE5: 0x6D98, //CJK UNIFIED IDEOGRAPH + 0x9BE6: 0x6D99, //CJK UNIFIED IDEOGRAPH + 0x9BE7: 0x6D9A, //CJK UNIFIED IDEOGRAPH + 0x9BE8: 0x6D9C, //CJK UNIFIED IDEOGRAPH + 0x9BE9: 0x6DA2, //CJK UNIFIED IDEOGRAPH + 0x9BEA: 0x6DA5, //CJK UNIFIED IDEOGRAPH + 0x9BEB: 0x6DAC, //CJK UNIFIED IDEOGRAPH + 0x9BEC: 0x6DAD, //CJK UNIFIED IDEOGRAPH + 0x9BED: 0x6DB0, //CJK UNIFIED IDEOGRAPH + 0x9BEE: 0x6DB1, //CJK UNIFIED IDEOGRAPH + 0x9BEF: 0x6DB3, //CJK UNIFIED IDEOGRAPH + 0x9BF0: 0x6DB4, //CJK UNIFIED IDEOGRAPH + 0x9BF1: 0x6DB6, //CJK UNIFIED IDEOGRAPH + 0x9BF2: 0x6DB7, //CJK UNIFIED IDEOGRAPH + 0x9BF3: 0x6DB9, //CJK UNIFIED IDEOGRAPH + 0x9BF4: 0x6DBA, //CJK UNIFIED IDEOGRAPH + 0x9BF5: 0x6DBB, //CJK UNIFIED IDEOGRAPH + 0x9BF6: 0x6DBC, //CJK UNIFIED IDEOGRAPH + 0x9BF7: 0x6DBD, //CJK UNIFIED IDEOGRAPH + 0x9BF8: 0x6DBE, //CJK UNIFIED IDEOGRAPH + 0x9BF9: 0x6DC1, //CJK UNIFIED IDEOGRAPH + 0x9BFA: 0x6DC2, //CJK UNIFIED IDEOGRAPH + 0x9BFB: 0x6DC3, //CJK UNIFIED IDEOGRAPH + 0x9BFC: 0x6DC8, //CJK UNIFIED IDEOGRAPH + 0x9BFD: 0x6DC9, //CJK UNIFIED IDEOGRAPH + 0x9BFE: 0x6DCA, //CJK UNIFIED IDEOGRAPH + 0x9C40: 0x6DCD, //CJK UNIFIED IDEOGRAPH + 0x9C41: 0x6DCE, //CJK UNIFIED IDEOGRAPH + 0x9C42: 0x6DCF, //CJK UNIFIED IDEOGRAPH + 0x9C43: 0x6DD0, //CJK UNIFIED IDEOGRAPH + 0x9C44: 0x6DD2, //CJK UNIFIED IDEOGRAPH + 0x9C45: 0x6DD3, //CJK UNIFIED IDEOGRAPH + 0x9C46: 0x6DD4, //CJK UNIFIED IDEOGRAPH + 0x9C47: 0x6DD5, //CJK UNIFIED IDEOGRAPH + 0x9C48: 0x6DD7, //CJK UNIFIED IDEOGRAPH + 0x9C49: 0x6DDA, //CJK UNIFIED IDEOGRAPH + 0x9C4A: 0x6DDB, //CJK UNIFIED IDEOGRAPH + 0x9C4B: 0x6DDC, //CJK UNIFIED IDEOGRAPH + 0x9C4C: 0x6DDF, //CJK UNIFIED IDEOGRAPH + 0x9C4D: 0x6DE2, //CJK UNIFIED IDEOGRAPH + 0x9C4E: 0x6DE3, //CJK UNIFIED IDEOGRAPH + 0x9C4F: 0x6DE5, //CJK UNIFIED IDEOGRAPH + 0x9C50: 0x6DE7, //CJK UNIFIED IDEOGRAPH + 0x9C51: 0x6DE8, //CJK UNIFIED IDEOGRAPH + 0x9C52: 0x6DE9, //CJK UNIFIED IDEOGRAPH + 0x9C53: 0x6DEA, //CJK UNIFIED IDEOGRAPH + 0x9C54: 0x6DED, //CJK UNIFIED IDEOGRAPH + 0x9C55: 0x6DEF, //CJK UNIFIED IDEOGRAPH + 0x9C56: 0x6DF0, //CJK UNIFIED IDEOGRAPH + 0x9C57: 0x6DF2, //CJK UNIFIED IDEOGRAPH + 0x9C58: 0x6DF4, //CJK UNIFIED IDEOGRAPH + 0x9C59: 0x6DF5, //CJK UNIFIED IDEOGRAPH + 0x9C5A: 0x6DF6, //CJK UNIFIED IDEOGRAPH + 0x9C5B: 0x6DF8, //CJK UNIFIED IDEOGRAPH + 0x9C5C: 0x6DFA, //CJK UNIFIED IDEOGRAPH + 0x9C5D: 0x6DFD, //CJK UNIFIED IDEOGRAPH + 0x9C5E: 0x6DFE, //CJK UNIFIED IDEOGRAPH + 0x9C5F: 0x6DFF, //CJK UNIFIED IDEOGRAPH + 0x9C60: 0x6E00, //CJK UNIFIED IDEOGRAPH + 0x9C61: 0x6E01, //CJK UNIFIED IDEOGRAPH + 0x9C62: 0x6E02, //CJK UNIFIED IDEOGRAPH + 0x9C63: 0x6E03, //CJK UNIFIED IDEOGRAPH + 0x9C64: 0x6E04, //CJK UNIFIED IDEOGRAPH + 0x9C65: 0x6E06, //CJK UNIFIED IDEOGRAPH + 0x9C66: 0x6E07, //CJK UNIFIED IDEOGRAPH + 0x9C67: 0x6E08, //CJK UNIFIED IDEOGRAPH + 0x9C68: 0x6E09, //CJK UNIFIED IDEOGRAPH + 0x9C69: 0x6E0B, //CJK UNIFIED IDEOGRAPH + 0x9C6A: 0x6E0F, //CJK UNIFIED IDEOGRAPH + 0x9C6B: 0x6E12, //CJK UNIFIED IDEOGRAPH + 0x9C6C: 0x6E13, //CJK UNIFIED IDEOGRAPH + 0x9C6D: 0x6E15, //CJK UNIFIED IDEOGRAPH + 0x9C6E: 0x6E18, //CJK UNIFIED IDEOGRAPH + 0x9C6F: 0x6E19, //CJK UNIFIED IDEOGRAPH + 0x9C70: 0x6E1B, //CJK UNIFIED IDEOGRAPH + 0x9C71: 0x6E1C, //CJK UNIFIED IDEOGRAPH + 0x9C72: 0x6E1E, //CJK UNIFIED IDEOGRAPH + 0x9C73: 0x6E1F, //CJK UNIFIED IDEOGRAPH + 0x9C74: 0x6E22, //CJK UNIFIED IDEOGRAPH + 0x9C75: 0x6E26, //CJK UNIFIED IDEOGRAPH + 0x9C76: 0x6E27, //CJK UNIFIED IDEOGRAPH + 0x9C77: 0x6E28, //CJK UNIFIED IDEOGRAPH + 0x9C78: 0x6E2A, //CJK UNIFIED IDEOGRAPH + 0x9C79: 0x6E2C, //CJK UNIFIED IDEOGRAPH + 0x9C7A: 0x6E2E, //CJK UNIFIED IDEOGRAPH + 0x9C7B: 0x6E30, //CJK UNIFIED IDEOGRAPH + 0x9C7C: 0x6E31, //CJK UNIFIED IDEOGRAPH + 0x9C7D: 0x6E33, //CJK UNIFIED IDEOGRAPH + 0x9C7E: 0x6E35, //CJK UNIFIED IDEOGRAPH + 0x9C80: 0x6E36, //CJK UNIFIED IDEOGRAPH + 0x9C81: 0x6E37, //CJK UNIFIED IDEOGRAPH + 0x9C82: 0x6E39, //CJK UNIFIED IDEOGRAPH + 0x9C83: 0x6E3B, //CJK UNIFIED IDEOGRAPH + 0x9C84: 0x6E3C, //CJK UNIFIED IDEOGRAPH + 0x9C85: 0x6E3D, //CJK UNIFIED IDEOGRAPH + 0x9C86: 0x6E3E, //CJK UNIFIED IDEOGRAPH + 0x9C87: 0x6E3F, //CJK UNIFIED IDEOGRAPH + 0x9C88: 0x6E40, //CJK UNIFIED IDEOGRAPH + 0x9C89: 0x6E41, //CJK UNIFIED IDEOGRAPH + 0x9C8A: 0x6E42, //CJK UNIFIED IDEOGRAPH + 0x9C8B: 0x6E45, //CJK UNIFIED IDEOGRAPH + 0x9C8C: 0x6E46, //CJK UNIFIED IDEOGRAPH + 0x9C8D: 0x6E47, //CJK UNIFIED IDEOGRAPH + 0x9C8E: 0x6E48, //CJK UNIFIED IDEOGRAPH + 0x9C8F: 0x6E49, //CJK UNIFIED IDEOGRAPH + 0x9C90: 0x6E4A, //CJK UNIFIED IDEOGRAPH + 0x9C91: 0x6E4B, //CJK UNIFIED IDEOGRAPH + 0x9C92: 0x6E4C, //CJK UNIFIED IDEOGRAPH + 0x9C93: 0x6E4F, //CJK UNIFIED IDEOGRAPH + 0x9C94: 0x6E50, //CJK UNIFIED IDEOGRAPH + 0x9C95: 0x6E51, //CJK UNIFIED IDEOGRAPH + 0x9C96: 0x6E52, //CJK UNIFIED IDEOGRAPH + 0x9C97: 0x6E55, //CJK UNIFIED IDEOGRAPH + 0x9C98: 0x6E57, //CJK UNIFIED IDEOGRAPH + 0x9C99: 0x6E59, //CJK UNIFIED IDEOGRAPH + 0x9C9A: 0x6E5A, //CJK UNIFIED IDEOGRAPH + 0x9C9B: 0x6E5C, //CJK UNIFIED IDEOGRAPH + 0x9C9C: 0x6E5D, //CJK UNIFIED IDEOGRAPH + 0x9C9D: 0x6E5E, //CJK UNIFIED IDEOGRAPH + 0x9C9E: 0x6E60, //CJK UNIFIED IDEOGRAPH + 0x9C9F: 0x6E61, //CJK UNIFIED IDEOGRAPH + 0x9CA0: 0x6E62, //CJK UNIFIED IDEOGRAPH + 0x9CA1: 0x6E63, //CJK UNIFIED IDEOGRAPH + 0x9CA2: 0x6E64, //CJK UNIFIED IDEOGRAPH + 0x9CA3: 0x6E65, //CJK UNIFIED IDEOGRAPH + 0x9CA4: 0x6E66, //CJK UNIFIED IDEOGRAPH + 0x9CA5: 0x6E67, //CJK UNIFIED IDEOGRAPH + 0x9CA6: 0x6E68, //CJK UNIFIED IDEOGRAPH + 0x9CA7: 0x6E69, //CJK UNIFIED IDEOGRAPH + 0x9CA8: 0x6E6A, //CJK UNIFIED IDEOGRAPH + 0x9CA9: 0x6E6C, //CJK UNIFIED IDEOGRAPH + 0x9CAA: 0x6E6D, //CJK UNIFIED IDEOGRAPH + 0x9CAB: 0x6E6F, //CJK UNIFIED IDEOGRAPH + 0x9CAC: 0x6E70, //CJK UNIFIED IDEOGRAPH + 0x9CAD: 0x6E71, //CJK UNIFIED IDEOGRAPH + 0x9CAE: 0x6E72, //CJK UNIFIED IDEOGRAPH + 0x9CAF: 0x6E73, //CJK UNIFIED IDEOGRAPH + 0x9CB0: 0x6E74, //CJK UNIFIED IDEOGRAPH + 0x9CB1: 0x6E75, //CJK UNIFIED IDEOGRAPH + 0x9CB2: 0x6E76, //CJK UNIFIED IDEOGRAPH + 0x9CB3: 0x6E77, //CJK UNIFIED IDEOGRAPH + 0x9CB4: 0x6E78, //CJK UNIFIED IDEOGRAPH + 0x9CB5: 0x6E79, //CJK UNIFIED IDEOGRAPH + 0x9CB6: 0x6E7A, //CJK UNIFIED IDEOGRAPH + 0x9CB7: 0x6E7B, //CJK UNIFIED IDEOGRAPH + 0x9CB8: 0x6E7C, //CJK UNIFIED IDEOGRAPH + 0x9CB9: 0x6E7D, //CJK UNIFIED IDEOGRAPH + 0x9CBA: 0x6E80, //CJK UNIFIED IDEOGRAPH + 0x9CBB: 0x6E81, //CJK UNIFIED IDEOGRAPH + 0x9CBC: 0x6E82, //CJK UNIFIED IDEOGRAPH + 0x9CBD: 0x6E84, //CJK UNIFIED IDEOGRAPH + 0x9CBE: 0x6E87, //CJK UNIFIED IDEOGRAPH + 0x9CBF: 0x6E88, //CJK UNIFIED IDEOGRAPH + 0x9CC0: 0x6E8A, //CJK UNIFIED IDEOGRAPH + 0x9CC1: 0x6E8B, //CJK UNIFIED IDEOGRAPH + 0x9CC2: 0x6E8C, //CJK UNIFIED IDEOGRAPH + 0x9CC3: 0x6E8D, //CJK UNIFIED IDEOGRAPH + 0x9CC4: 0x6E8E, //CJK UNIFIED IDEOGRAPH + 0x9CC5: 0x6E91, //CJK UNIFIED IDEOGRAPH + 0x9CC6: 0x6E92, //CJK UNIFIED IDEOGRAPH + 0x9CC7: 0x6E93, //CJK UNIFIED IDEOGRAPH + 0x9CC8: 0x6E94, //CJK UNIFIED IDEOGRAPH + 0x9CC9: 0x6E95, //CJK UNIFIED IDEOGRAPH + 0x9CCA: 0x6E96, //CJK UNIFIED IDEOGRAPH + 0x9CCB: 0x6E97, //CJK UNIFIED IDEOGRAPH + 0x9CCC: 0x6E99, //CJK UNIFIED IDEOGRAPH + 0x9CCD: 0x6E9A, //CJK UNIFIED IDEOGRAPH + 0x9CCE: 0x6E9B, //CJK UNIFIED IDEOGRAPH + 0x9CCF: 0x6E9D, //CJK UNIFIED IDEOGRAPH + 0x9CD0: 0x6E9E, //CJK UNIFIED IDEOGRAPH + 0x9CD1: 0x6EA0, //CJK UNIFIED IDEOGRAPH + 0x9CD2: 0x6EA1, //CJK UNIFIED IDEOGRAPH + 0x9CD3: 0x6EA3, //CJK UNIFIED IDEOGRAPH + 0x9CD4: 0x6EA4, //CJK UNIFIED IDEOGRAPH + 0x9CD5: 0x6EA6, //CJK UNIFIED IDEOGRAPH + 0x9CD6: 0x6EA8, //CJK UNIFIED IDEOGRAPH + 0x9CD7: 0x6EA9, //CJK UNIFIED IDEOGRAPH + 0x9CD8: 0x6EAB, //CJK UNIFIED IDEOGRAPH + 0x9CD9: 0x6EAC, //CJK UNIFIED IDEOGRAPH + 0x9CDA: 0x6EAD, //CJK UNIFIED IDEOGRAPH + 0x9CDB: 0x6EAE, //CJK UNIFIED IDEOGRAPH + 0x9CDC: 0x6EB0, //CJK UNIFIED IDEOGRAPH + 0x9CDD: 0x6EB3, //CJK UNIFIED IDEOGRAPH + 0x9CDE: 0x6EB5, //CJK UNIFIED IDEOGRAPH + 0x9CDF: 0x6EB8, //CJK UNIFIED IDEOGRAPH + 0x9CE0: 0x6EB9, //CJK UNIFIED IDEOGRAPH + 0x9CE1: 0x6EBC, //CJK UNIFIED IDEOGRAPH + 0x9CE2: 0x6EBE, //CJK UNIFIED IDEOGRAPH + 0x9CE3: 0x6EBF, //CJK UNIFIED IDEOGRAPH + 0x9CE4: 0x6EC0, //CJK UNIFIED IDEOGRAPH + 0x9CE5: 0x6EC3, //CJK UNIFIED IDEOGRAPH + 0x9CE6: 0x6EC4, //CJK UNIFIED IDEOGRAPH + 0x9CE7: 0x6EC5, //CJK UNIFIED IDEOGRAPH + 0x9CE8: 0x6EC6, //CJK UNIFIED IDEOGRAPH + 0x9CE9: 0x6EC8, //CJK UNIFIED IDEOGRAPH + 0x9CEA: 0x6EC9, //CJK UNIFIED IDEOGRAPH + 0x9CEB: 0x6ECA, //CJK UNIFIED IDEOGRAPH + 0x9CEC: 0x6ECC, //CJK UNIFIED IDEOGRAPH + 0x9CED: 0x6ECD, //CJK UNIFIED IDEOGRAPH + 0x9CEE: 0x6ECE, //CJK UNIFIED IDEOGRAPH + 0x9CEF: 0x6ED0, //CJK UNIFIED IDEOGRAPH + 0x9CF0: 0x6ED2, //CJK UNIFIED IDEOGRAPH + 0x9CF1: 0x6ED6, //CJK UNIFIED IDEOGRAPH + 0x9CF2: 0x6ED8, //CJK UNIFIED IDEOGRAPH + 0x9CF3: 0x6ED9, //CJK UNIFIED IDEOGRAPH + 0x9CF4: 0x6EDB, //CJK UNIFIED IDEOGRAPH + 0x9CF5: 0x6EDC, //CJK UNIFIED IDEOGRAPH + 0x9CF6: 0x6EDD, //CJK UNIFIED IDEOGRAPH + 0x9CF7: 0x6EE3, //CJK UNIFIED IDEOGRAPH + 0x9CF8: 0x6EE7, //CJK UNIFIED IDEOGRAPH + 0x9CF9: 0x6EEA, //CJK UNIFIED IDEOGRAPH + 0x9CFA: 0x6EEB, //CJK UNIFIED IDEOGRAPH + 0x9CFB: 0x6EEC, //CJK UNIFIED IDEOGRAPH + 0x9CFC: 0x6EED, //CJK UNIFIED IDEOGRAPH + 0x9CFD: 0x6EEE, //CJK UNIFIED IDEOGRAPH + 0x9CFE: 0x6EEF, //CJK UNIFIED IDEOGRAPH + 0x9D40: 0x6EF0, //CJK UNIFIED IDEOGRAPH + 0x9D41: 0x6EF1, //CJK UNIFIED IDEOGRAPH + 0x9D42: 0x6EF2, //CJK UNIFIED IDEOGRAPH + 0x9D43: 0x6EF3, //CJK UNIFIED IDEOGRAPH + 0x9D44: 0x6EF5, //CJK UNIFIED IDEOGRAPH + 0x9D45: 0x6EF6, //CJK UNIFIED IDEOGRAPH + 0x9D46: 0x6EF7, //CJK UNIFIED IDEOGRAPH + 0x9D47: 0x6EF8, //CJK UNIFIED IDEOGRAPH + 0x9D48: 0x6EFA, //CJK UNIFIED IDEOGRAPH + 0x9D49: 0x6EFB, //CJK UNIFIED IDEOGRAPH + 0x9D4A: 0x6EFC, //CJK UNIFIED IDEOGRAPH + 0x9D4B: 0x6EFD, //CJK UNIFIED IDEOGRAPH + 0x9D4C: 0x6EFE, //CJK UNIFIED IDEOGRAPH + 0x9D4D: 0x6EFF, //CJK UNIFIED IDEOGRAPH + 0x9D4E: 0x6F00, //CJK UNIFIED IDEOGRAPH + 0x9D4F: 0x6F01, //CJK UNIFIED IDEOGRAPH + 0x9D50: 0x6F03, //CJK UNIFIED IDEOGRAPH + 0x9D51: 0x6F04, //CJK UNIFIED IDEOGRAPH + 0x9D52: 0x6F05, //CJK UNIFIED IDEOGRAPH + 0x9D53: 0x6F07, //CJK UNIFIED IDEOGRAPH + 0x9D54: 0x6F08, //CJK UNIFIED IDEOGRAPH + 0x9D55: 0x6F0A, //CJK UNIFIED IDEOGRAPH + 0x9D56: 0x6F0B, //CJK UNIFIED IDEOGRAPH + 0x9D57: 0x6F0C, //CJK UNIFIED IDEOGRAPH + 0x9D58: 0x6F0D, //CJK UNIFIED IDEOGRAPH + 0x9D59: 0x6F0E, //CJK UNIFIED IDEOGRAPH + 0x9D5A: 0x6F10, //CJK UNIFIED IDEOGRAPH + 0x9D5B: 0x6F11, //CJK UNIFIED IDEOGRAPH + 0x9D5C: 0x6F12, //CJK UNIFIED IDEOGRAPH + 0x9D5D: 0x6F16, //CJK UNIFIED IDEOGRAPH + 0x9D5E: 0x6F17, //CJK UNIFIED IDEOGRAPH + 0x9D5F: 0x6F18, //CJK UNIFIED IDEOGRAPH + 0x9D60: 0x6F19, //CJK UNIFIED IDEOGRAPH + 0x9D61: 0x6F1A, //CJK UNIFIED IDEOGRAPH + 0x9D62: 0x6F1B, //CJK UNIFIED IDEOGRAPH + 0x9D63: 0x6F1C, //CJK UNIFIED IDEOGRAPH + 0x9D64: 0x6F1D, //CJK UNIFIED IDEOGRAPH + 0x9D65: 0x6F1E, //CJK UNIFIED IDEOGRAPH + 0x9D66: 0x6F1F, //CJK UNIFIED IDEOGRAPH + 0x9D67: 0x6F21, //CJK UNIFIED IDEOGRAPH + 0x9D68: 0x6F22, //CJK UNIFIED IDEOGRAPH + 0x9D69: 0x6F23, //CJK UNIFIED IDEOGRAPH + 0x9D6A: 0x6F25, //CJK UNIFIED IDEOGRAPH + 0x9D6B: 0x6F26, //CJK UNIFIED IDEOGRAPH + 0x9D6C: 0x6F27, //CJK UNIFIED IDEOGRAPH + 0x9D6D: 0x6F28, //CJK UNIFIED IDEOGRAPH + 0x9D6E: 0x6F2C, //CJK UNIFIED IDEOGRAPH + 0x9D6F: 0x6F2E, //CJK UNIFIED IDEOGRAPH + 0x9D70: 0x6F30, //CJK UNIFIED IDEOGRAPH + 0x9D71: 0x6F32, //CJK UNIFIED IDEOGRAPH + 0x9D72: 0x6F34, //CJK UNIFIED IDEOGRAPH + 0x9D73: 0x6F35, //CJK UNIFIED IDEOGRAPH + 0x9D74: 0x6F37, //CJK UNIFIED IDEOGRAPH + 0x9D75: 0x6F38, //CJK UNIFIED IDEOGRAPH + 0x9D76: 0x6F39, //CJK UNIFIED IDEOGRAPH + 0x9D77: 0x6F3A, //CJK UNIFIED IDEOGRAPH + 0x9D78: 0x6F3B, //CJK UNIFIED IDEOGRAPH + 0x9D79: 0x6F3C, //CJK UNIFIED IDEOGRAPH + 0x9D7A: 0x6F3D, //CJK UNIFIED IDEOGRAPH + 0x9D7B: 0x6F3F, //CJK UNIFIED IDEOGRAPH + 0x9D7C: 0x6F40, //CJK UNIFIED IDEOGRAPH + 0x9D7D: 0x6F41, //CJK UNIFIED IDEOGRAPH + 0x9D7E: 0x6F42, //CJK UNIFIED IDEOGRAPH + 0x9D80: 0x6F43, //CJK UNIFIED IDEOGRAPH + 0x9D81: 0x6F44, //CJK UNIFIED IDEOGRAPH + 0x9D82: 0x6F45, //CJK UNIFIED IDEOGRAPH + 0x9D83: 0x6F48, //CJK UNIFIED IDEOGRAPH + 0x9D84: 0x6F49, //CJK UNIFIED IDEOGRAPH + 0x9D85: 0x6F4A, //CJK UNIFIED IDEOGRAPH + 0x9D86: 0x6F4C, //CJK UNIFIED IDEOGRAPH + 0x9D87: 0x6F4E, //CJK UNIFIED IDEOGRAPH + 0x9D88: 0x6F4F, //CJK UNIFIED IDEOGRAPH + 0x9D89: 0x6F50, //CJK UNIFIED IDEOGRAPH + 0x9D8A: 0x6F51, //CJK UNIFIED IDEOGRAPH + 0x9D8B: 0x6F52, //CJK UNIFIED IDEOGRAPH + 0x9D8C: 0x6F53, //CJK UNIFIED IDEOGRAPH + 0x9D8D: 0x6F54, //CJK UNIFIED IDEOGRAPH + 0x9D8E: 0x6F55, //CJK UNIFIED IDEOGRAPH + 0x9D8F: 0x6F56, //CJK UNIFIED IDEOGRAPH + 0x9D90: 0x6F57, //CJK UNIFIED IDEOGRAPH + 0x9D91: 0x6F59, //CJK UNIFIED IDEOGRAPH + 0x9D92: 0x6F5A, //CJK UNIFIED IDEOGRAPH + 0x9D93: 0x6F5B, //CJK UNIFIED IDEOGRAPH + 0x9D94: 0x6F5D, //CJK UNIFIED IDEOGRAPH + 0x9D95: 0x6F5F, //CJK UNIFIED IDEOGRAPH + 0x9D96: 0x6F60, //CJK UNIFIED IDEOGRAPH + 0x9D97: 0x6F61, //CJK UNIFIED IDEOGRAPH + 0x9D98: 0x6F63, //CJK UNIFIED IDEOGRAPH + 0x9D99: 0x6F64, //CJK UNIFIED IDEOGRAPH + 0x9D9A: 0x6F65, //CJK UNIFIED IDEOGRAPH + 0x9D9B: 0x6F67, //CJK UNIFIED IDEOGRAPH + 0x9D9C: 0x6F68, //CJK UNIFIED IDEOGRAPH + 0x9D9D: 0x6F69, //CJK UNIFIED IDEOGRAPH + 0x9D9E: 0x6F6A, //CJK UNIFIED IDEOGRAPH + 0x9D9F: 0x6F6B, //CJK UNIFIED IDEOGRAPH + 0x9DA0: 0x6F6C, //CJK UNIFIED IDEOGRAPH + 0x9DA1: 0x6F6F, //CJK UNIFIED IDEOGRAPH + 0x9DA2: 0x6F70, //CJK UNIFIED IDEOGRAPH + 0x9DA3: 0x6F71, //CJK UNIFIED IDEOGRAPH + 0x9DA4: 0x6F73, //CJK UNIFIED IDEOGRAPH + 0x9DA5: 0x6F75, //CJK UNIFIED IDEOGRAPH + 0x9DA6: 0x6F76, //CJK UNIFIED IDEOGRAPH + 0x9DA7: 0x6F77, //CJK UNIFIED IDEOGRAPH + 0x9DA8: 0x6F79, //CJK UNIFIED IDEOGRAPH + 0x9DA9: 0x6F7B, //CJK UNIFIED IDEOGRAPH + 0x9DAA: 0x6F7D, //CJK UNIFIED IDEOGRAPH + 0x9DAB: 0x6F7E, //CJK UNIFIED IDEOGRAPH + 0x9DAC: 0x6F7F, //CJK UNIFIED IDEOGRAPH + 0x9DAD: 0x6F80, //CJK UNIFIED IDEOGRAPH + 0x9DAE: 0x6F81, //CJK UNIFIED IDEOGRAPH + 0x9DAF: 0x6F82, //CJK UNIFIED IDEOGRAPH + 0x9DB0: 0x6F83, //CJK UNIFIED IDEOGRAPH + 0x9DB1: 0x6F85, //CJK UNIFIED IDEOGRAPH + 0x9DB2: 0x6F86, //CJK UNIFIED IDEOGRAPH + 0x9DB3: 0x6F87, //CJK UNIFIED IDEOGRAPH + 0x9DB4: 0x6F8A, //CJK UNIFIED IDEOGRAPH + 0x9DB5: 0x6F8B, //CJK UNIFIED IDEOGRAPH + 0x9DB6: 0x6F8F, //CJK UNIFIED IDEOGRAPH + 0x9DB7: 0x6F90, //CJK UNIFIED IDEOGRAPH + 0x9DB8: 0x6F91, //CJK UNIFIED IDEOGRAPH + 0x9DB9: 0x6F92, //CJK UNIFIED IDEOGRAPH + 0x9DBA: 0x6F93, //CJK UNIFIED IDEOGRAPH + 0x9DBB: 0x6F94, //CJK UNIFIED IDEOGRAPH + 0x9DBC: 0x6F95, //CJK UNIFIED IDEOGRAPH + 0x9DBD: 0x6F96, //CJK UNIFIED IDEOGRAPH + 0x9DBE: 0x6F97, //CJK UNIFIED IDEOGRAPH + 0x9DBF: 0x6F98, //CJK UNIFIED IDEOGRAPH + 0x9DC0: 0x6F99, //CJK UNIFIED IDEOGRAPH + 0x9DC1: 0x6F9A, //CJK UNIFIED IDEOGRAPH + 0x9DC2: 0x6F9B, //CJK UNIFIED IDEOGRAPH + 0x9DC3: 0x6F9D, //CJK UNIFIED IDEOGRAPH + 0x9DC4: 0x6F9E, //CJK UNIFIED IDEOGRAPH + 0x9DC5: 0x6F9F, //CJK UNIFIED IDEOGRAPH + 0x9DC6: 0x6FA0, //CJK UNIFIED IDEOGRAPH + 0x9DC7: 0x6FA2, //CJK UNIFIED IDEOGRAPH + 0x9DC8: 0x6FA3, //CJK UNIFIED IDEOGRAPH + 0x9DC9: 0x6FA4, //CJK UNIFIED IDEOGRAPH + 0x9DCA: 0x6FA5, //CJK UNIFIED IDEOGRAPH + 0x9DCB: 0x6FA6, //CJK UNIFIED IDEOGRAPH + 0x9DCC: 0x6FA8, //CJK UNIFIED IDEOGRAPH + 0x9DCD: 0x6FA9, //CJK UNIFIED IDEOGRAPH + 0x9DCE: 0x6FAA, //CJK UNIFIED IDEOGRAPH + 0x9DCF: 0x6FAB, //CJK UNIFIED IDEOGRAPH + 0x9DD0: 0x6FAC, //CJK UNIFIED IDEOGRAPH + 0x9DD1: 0x6FAD, //CJK UNIFIED IDEOGRAPH + 0x9DD2: 0x6FAE, //CJK UNIFIED IDEOGRAPH + 0x9DD3: 0x6FAF, //CJK UNIFIED IDEOGRAPH + 0x9DD4: 0x6FB0, //CJK UNIFIED IDEOGRAPH + 0x9DD5: 0x6FB1, //CJK UNIFIED IDEOGRAPH + 0x9DD6: 0x6FB2, //CJK UNIFIED IDEOGRAPH + 0x9DD7: 0x6FB4, //CJK UNIFIED IDEOGRAPH + 0x9DD8: 0x6FB5, //CJK UNIFIED IDEOGRAPH + 0x9DD9: 0x6FB7, //CJK UNIFIED IDEOGRAPH + 0x9DDA: 0x6FB8, //CJK UNIFIED IDEOGRAPH + 0x9DDB: 0x6FBA, //CJK UNIFIED IDEOGRAPH + 0x9DDC: 0x6FBB, //CJK UNIFIED IDEOGRAPH + 0x9DDD: 0x6FBC, //CJK UNIFIED IDEOGRAPH + 0x9DDE: 0x6FBD, //CJK UNIFIED IDEOGRAPH + 0x9DDF: 0x6FBE, //CJK UNIFIED IDEOGRAPH + 0x9DE0: 0x6FBF, //CJK UNIFIED IDEOGRAPH + 0x9DE1: 0x6FC1, //CJK UNIFIED IDEOGRAPH + 0x9DE2: 0x6FC3, //CJK UNIFIED IDEOGRAPH + 0x9DE3: 0x6FC4, //CJK UNIFIED IDEOGRAPH + 0x9DE4: 0x6FC5, //CJK UNIFIED IDEOGRAPH + 0x9DE5: 0x6FC6, //CJK UNIFIED IDEOGRAPH + 0x9DE6: 0x6FC7, //CJK UNIFIED IDEOGRAPH + 0x9DE7: 0x6FC8, //CJK UNIFIED IDEOGRAPH + 0x9DE8: 0x6FCA, //CJK UNIFIED IDEOGRAPH + 0x9DE9: 0x6FCB, //CJK UNIFIED IDEOGRAPH + 0x9DEA: 0x6FCC, //CJK UNIFIED IDEOGRAPH + 0x9DEB: 0x6FCD, //CJK UNIFIED IDEOGRAPH + 0x9DEC: 0x6FCE, //CJK UNIFIED IDEOGRAPH + 0x9DED: 0x6FCF, //CJK UNIFIED IDEOGRAPH + 0x9DEE: 0x6FD0, //CJK UNIFIED IDEOGRAPH + 0x9DEF: 0x6FD3, //CJK UNIFIED IDEOGRAPH + 0x9DF0: 0x6FD4, //CJK UNIFIED IDEOGRAPH + 0x9DF1: 0x6FD5, //CJK UNIFIED IDEOGRAPH + 0x9DF2: 0x6FD6, //CJK UNIFIED IDEOGRAPH + 0x9DF3: 0x6FD7, //CJK UNIFIED IDEOGRAPH + 0x9DF4: 0x6FD8, //CJK UNIFIED IDEOGRAPH + 0x9DF5: 0x6FD9, //CJK UNIFIED IDEOGRAPH + 0x9DF6: 0x6FDA, //CJK UNIFIED IDEOGRAPH + 0x9DF7: 0x6FDB, //CJK UNIFIED IDEOGRAPH + 0x9DF8: 0x6FDC, //CJK UNIFIED IDEOGRAPH + 0x9DF9: 0x6FDD, //CJK UNIFIED IDEOGRAPH + 0x9DFA: 0x6FDF, //CJK UNIFIED IDEOGRAPH + 0x9DFB: 0x6FE2, //CJK UNIFIED IDEOGRAPH + 0x9DFC: 0x6FE3, //CJK UNIFIED IDEOGRAPH + 0x9DFD: 0x6FE4, //CJK UNIFIED IDEOGRAPH + 0x9DFE: 0x6FE5, //CJK UNIFIED IDEOGRAPH + 0x9E40: 0x6FE6, //CJK UNIFIED IDEOGRAPH + 0x9E41: 0x6FE7, //CJK UNIFIED IDEOGRAPH + 0x9E42: 0x6FE8, //CJK UNIFIED IDEOGRAPH + 0x9E43: 0x6FE9, //CJK UNIFIED IDEOGRAPH + 0x9E44: 0x6FEA, //CJK UNIFIED IDEOGRAPH + 0x9E45: 0x6FEB, //CJK UNIFIED IDEOGRAPH + 0x9E46: 0x6FEC, //CJK UNIFIED IDEOGRAPH + 0x9E47: 0x6FED, //CJK UNIFIED IDEOGRAPH + 0x9E48: 0x6FF0, //CJK UNIFIED IDEOGRAPH + 0x9E49: 0x6FF1, //CJK UNIFIED IDEOGRAPH + 0x9E4A: 0x6FF2, //CJK UNIFIED IDEOGRAPH + 0x9E4B: 0x6FF3, //CJK UNIFIED IDEOGRAPH + 0x9E4C: 0x6FF4, //CJK UNIFIED IDEOGRAPH + 0x9E4D: 0x6FF5, //CJK UNIFIED IDEOGRAPH + 0x9E4E: 0x6FF6, //CJK UNIFIED IDEOGRAPH + 0x9E4F: 0x6FF7, //CJK UNIFIED IDEOGRAPH + 0x9E50: 0x6FF8, //CJK UNIFIED IDEOGRAPH + 0x9E51: 0x6FF9, //CJK UNIFIED IDEOGRAPH + 0x9E52: 0x6FFA, //CJK UNIFIED IDEOGRAPH + 0x9E53: 0x6FFB, //CJK UNIFIED IDEOGRAPH + 0x9E54: 0x6FFC, //CJK UNIFIED IDEOGRAPH + 0x9E55: 0x6FFD, //CJK UNIFIED IDEOGRAPH + 0x9E56: 0x6FFE, //CJK UNIFIED IDEOGRAPH + 0x9E57: 0x6FFF, //CJK UNIFIED IDEOGRAPH + 0x9E58: 0x7000, //CJK UNIFIED IDEOGRAPH + 0x9E59: 0x7001, //CJK UNIFIED IDEOGRAPH + 0x9E5A: 0x7002, //CJK UNIFIED IDEOGRAPH + 0x9E5B: 0x7003, //CJK UNIFIED IDEOGRAPH + 0x9E5C: 0x7004, //CJK UNIFIED IDEOGRAPH + 0x9E5D: 0x7005, //CJK UNIFIED IDEOGRAPH + 0x9E5E: 0x7006, //CJK UNIFIED IDEOGRAPH + 0x9E5F: 0x7007, //CJK UNIFIED IDEOGRAPH + 0x9E60: 0x7008, //CJK UNIFIED IDEOGRAPH + 0x9E61: 0x7009, //CJK UNIFIED IDEOGRAPH + 0x9E62: 0x700A, //CJK UNIFIED IDEOGRAPH + 0x9E63: 0x700B, //CJK UNIFIED IDEOGRAPH + 0x9E64: 0x700C, //CJK UNIFIED IDEOGRAPH + 0x9E65: 0x700D, //CJK UNIFIED IDEOGRAPH + 0x9E66: 0x700E, //CJK UNIFIED IDEOGRAPH + 0x9E67: 0x700F, //CJK UNIFIED IDEOGRAPH + 0x9E68: 0x7010, //CJK UNIFIED IDEOGRAPH + 0x9E69: 0x7012, //CJK UNIFIED IDEOGRAPH + 0x9E6A: 0x7013, //CJK UNIFIED IDEOGRAPH + 0x9E6B: 0x7014, //CJK UNIFIED IDEOGRAPH + 0x9E6C: 0x7015, //CJK UNIFIED IDEOGRAPH + 0x9E6D: 0x7016, //CJK UNIFIED IDEOGRAPH + 0x9E6E: 0x7017, //CJK UNIFIED IDEOGRAPH + 0x9E6F: 0x7018, //CJK UNIFIED IDEOGRAPH + 0x9E70: 0x7019, //CJK UNIFIED IDEOGRAPH + 0x9E71: 0x701C, //CJK UNIFIED IDEOGRAPH + 0x9E72: 0x701D, //CJK UNIFIED IDEOGRAPH + 0x9E73: 0x701E, //CJK UNIFIED IDEOGRAPH + 0x9E74: 0x701F, //CJK UNIFIED IDEOGRAPH + 0x9E75: 0x7020, //CJK UNIFIED IDEOGRAPH + 0x9E76: 0x7021, //CJK UNIFIED IDEOGRAPH + 0x9E77: 0x7022, //CJK UNIFIED IDEOGRAPH + 0x9E78: 0x7024, //CJK UNIFIED IDEOGRAPH + 0x9E79: 0x7025, //CJK UNIFIED IDEOGRAPH + 0x9E7A: 0x7026, //CJK UNIFIED IDEOGRAPH + 0x9E7B: 0x7027, //CJK UNIFIED IDEOGRAPH + 0x9E7C: 0x7028, //CJK UNIFIED IDEOGRAPH + 0x9E7D: 0x7029, //CJK UNIFIED IDEOGRAPH + 0x9E7E: 0x702A, //CJK UNIFIED IDEOGRAPH + 0x9E80: 0x702B, //CJK UNIFIED IDEOGRAPH + 0x9E81: 0x702C, //CJK UNIFIED IDEOGRAPH + 0x9E82: 0x702D, //CJK UNIFIED IDEOGRAPH + 0x9E83: 0x702E, //CJK UNIFIED IDEOGRAPH + 0x9E84: 0x702F, //CJK UNIFIED IDEOGRAPH + 0x9E85: 0x7030, //CJK UNIFIED IDEOGRAPH + 0x9E86: 0x7031, //CJK UNIFIED IDEOGRAPH + 0x9E87: 0x7032, //CJK UNIFIED IDEOGRAPH + 0x9E88: 0x7033, //CJK UNIFIED IDEOGRAPH + 0x9E89: 0x7034, //CJK UNIFIED IDEOGRAPH + 0x9E8A: 0x7036, //CJK UNIFIED IDEOGRAPH + 0x9E8B: 0x7037, //CJK UNIFIED IDEOGRAPH + 0x9E8C: 0x7038, //CJK UNIFIED IDEOGRAPH + 0x9E8D: 0x703A, //CJK UNIFIED IDEOGRAPH + 0x9E8E: 0x703B, //CJK UNIFIED IDEOGRAPH + 0x9E8F: 0x703C, //CJK UNIFIED IDEOGRAPH + 0x9E90: 0x703D, //CJK UNIFIED IDEOGRAPH + 0x9E91: 0x703E, //CJK UNIFIED IDEOGRAPH + 0x9E92: 0x703F, //CJK UNIFIED IDEOGRAPH + 0x9E93: 0x7040, //CJK UNIFIED IDEOGRAPH + 0x9E94: 0x7041, //CJK UNIFIED IDEOGRAPH + 0x9E95: 0x7042, //CJK UNIFIED IDEOGRAPH + 0x9E96: 0x7043, //CJK UNIFIED IDEOGRAPH + 0x9E97: 0x7044, //CJK UNIFIED IDEOGRAPH + 0x9E98: 0x7045, //CJK UNIFIED IDEOGRAPH + 0x9E99: 0x7046, //CJK UNIFIED IDEOGRAPH + 0x9E9A: 0x7047, //CJK UNIFIED IDEOGRAPH + 0x9E9B: 0x7048, //CJK UNIFIED IDEOGRAPH + 0x9E9C: 0x7049, //CJK UNIFIED IDEOGRAPH + 0x9E9D: 0x704A, //CJK UNIFIED IDEOGRAPH + 0x9E9E: 0x704B, //CJK UNIFIED IDEOGRAPH + 0x9E9F: 0x704D, //CJK UNIFIED IDEOGRAPH + 0x9EA0: 0x704E, //CJK UNIFIED IDEOGRAPH + 0x9EA1: 0x7050, //CJK UNIFIED IDEOGRAPH + 0x9EA2: 0x7051, //CJK UNIFIED IDEOGRAPH + 0x9EA3: 0x7052, //CJK UNIFIED IDEOGRAPH + 0x9EA4: 0x7053, //CJK UNIFIED IDEOGRAPH + 0x9EA5: 0x7054, //CJK UNIFIED IDEOGRAPH + 0x9EA6: 0x7055, //CJK UNIFIED IDEOGRAPH + 0x9EA7: 0x7056, //CJK UNIFIED IDEOGRAPH + 0x9EA8: 0x7057, //CJK UNIFIED IDEOGRAPH + 0x9EA9: 0x7058, //CJK UNIFIED IDEOGRAPH + 0x9EAA: 0x7059, //CJK UNIFIED IDEOGRAPH + 0x9EAB: 0x705A, //CJK UNIFIED IDEOGRAPH + 0x9EAC: 0x705B, //CJK UNIFIED IDEOGRAPH + 0x9EAD: 0x705C, //CJK UNIFIED IDEOGRAPH + 0x9EAE: 0x705D, //CJK UNIFIED IDEOGRAPH + 0x9EAF: 0x705F, //CJK UNIFIED IDEOGRAPH + 0x9EB0: 0x7060, //CJK UNIFIED IDEOGRAPH + 0x9EB1: 0x7061, //CJK UNIFIED IDEOGRAPH + 0x9EB2: 0x7062, //CJK UNIFIED IDEOGRAPH + 0x9EB3: 0x7063, //CJK UNIFIED IDEOGRAPH + 0x9EB4: 0x7064, //CJK UNIFIED IDEOGRAPH + 0x9EB5: 0x7065, //CJK UNIFIED IDEOGRAPH + 0x9EB6: 0x7066, //CJK UNIFIED IDEOGRAPH + 0x9EB7: 0x7067, //CJK UNIFIED IDEOGRAPH + 0x9EB8: 0x7068, //CJK UNIFIED IDEOGRAPH + 0x9EB9: 0x7069, //CJK UNIFIED IDEOGRAPH + 0x9EBA: 0x706A, //CJK UNIFIED IDEOGRAPH + 0x9EBB: 0x706E, //CJK UNIFIED IDEOGRAPH + 0x9EBC: 0x7071, //CJK UNIFIED IDEOGRAPH + 0x9EBD: 0x7072, //CJK UNIFIED IDEOGRAPH + 0x9EBE: 0x7073, //CJK UNIFIED IDEOGRAPH + 0x9EBF: 0x7074, //CJK UNIFIED IDEOGRAPH + 0x9EC0: 0x7077, //CJK UNIFIED IDEOGRAPH + 0x9EC1: 0x7079, //CJK UNIFIED IDEOGRAPH + 0x9EC2: 0x707A, //CJK UNIFIED IDEOGRAPH + 0x9EC3: 0x707B, //CJK UNIFIED IDEOGRAPH + 0x9EC4: 0x707D, //CJK UNIFIED IDEOGRAPH + 0x9EC5: 0x7081, //CJK UNIFIED IDEOGRAPH + 0x9EC6: 0x7082, //CJK UNIFIED IDEOGRAPH + 0x9EC7: 0x7083, //CJK UNIFIED IDEOGRAPH + 0x9EC8: 0x7084, //CJK UNIFIED IDEOGRAPH + 0x9EC9: 0x7086, //CJK UNIFIED IDEOGRAPH + 0x9ECA: 0x7087, //CJK UNIFIED IDEOGRAPH + 0x9ECB: 0x7088, //CJK UNIFIED IDEOGRAPH + 0x9ECC: 0x708B, //CJK UNIFIED IDEOGRAPH + 0x9ECD: 0x708C, //CJK UNIFIED IDEOGRAPH + 0x9ECE: 0x708D, //CJK UNIFIED IDEOGRAPH + 0x9ECF: 0x708F, //CJK UNIFIED IDEOGRAPH + 0x9ED0: 0x7090, //CJK UNIFIED IDEOGRAPH + 0x9ED1: 0x7091, //CJK UNIFIED IDEOGRAPH + 0x9ED2: 0x7093, //CJK UNIFIED IDEOGRAPH + 0x9ED3: 0x7097, //CJK UNIFIED IDEOGRAPH + 0x9ED4: 0x7098, //CJK UNIFIED IDEOGRAPH + 0x9ED5: 0x709A, //CJK UNIFIED IDEOGRAPH + 0x9ED6: 0x709B, //CJK UNIFIED IDEOGRAPH + 0x9ED7: 0x709E, //CJK UNIFIED IDEOGRAPH + 0x9ED8: 0x709F, //CJK UNIFIED IDEOGRAPH + 0x9ED9: 0x70A0, //CJK UNIFIED IDEOGRAPH + 0x9EDA: 0x70A1, //CJK UNIFIED IDEOGRAPH + 0x9EDB: 0x70A2, //CJK UNIFIED IDEOGRAPH + 0x9EDC: 0x70A3, //CJK UNIFIED IDEOGRAPH + 0x9EDD: 0x70A4, //CJK UNIFIED IDEOGRAPH + 0x9EDE: 0x70A5, //CJK UNIFIED IDEOGRAPH + 0x9EDF: 0x70A6, //CJK UNIFIED IDEOGRAPH + 0x9EE0: 0x70A7, //CJK UNIFIED IDEOGRAPH + 0x9EE1: 0x70A8, //CJK UNIFIED IDEOGRAPH + 0x9EE2: 0x70A9, //CJK UNIFIED IDEOGRAPH + 0x9EE3: 0x70AA, //CJK UNIFIED IDEOGRAPH + 0x9EE4: 0x70B0, //CJK UNIFIED IDEOGRAPH + 0x9EE5: 0x70B2, //CJK UNIFIED IDEOGRAPH + 0x9EE6: 0x70B4, //CJK UNIFIED IDEOGRAPH + 0x9EE7: 0x70B5, //CJK UNIFIED IDEOGRAPH + 0x9EE8: 0x70B6, //CJK UNIFIED IDEOGRAPH + 0x9EE9: 0x70BA, //CJK UNIFIED IDEOGRAPH + 0x9EEA: 0x70BE, //CJK UNIFIED IDEOGRAPH + 0x9EEB: 0x70BF, //CJK UNIFIED IDEOGRAPH + 0x9EEC: 0x70C4, //CJK UNIFIED IDEOGRAPH + 0x9EED: 0x70C5, //CJK UNIFIED IDEOGRAPH + 0x9EEE: 0x70C6, //CJK UNIFIED IDEOGRAPH + 0x9EEF: 0x70C7, //CJK UNIFIED IDEOGRAPH + 0x9EF0: 0x70C9, //CJK UNIFIED IDEOGRAPH + 0x9EF1: 0x70CB, //CJK UNIFIED IDEOGRAPH + 0x9EF2: 0x70CC, //CJK UNIFIED IDEOGRAPH + 0x9EF3: 0x70CD, //CJK UNIFIED IDEOGRAPH + 0x9EF4: 0x70CE, //CJK UNIFIED IDEOGRAPH + 0x9EF5: 0x70CF, //CJK UNIFIED IDEOGRAPH + 0x9EF6: 0x70D0, //CJK UNIFIED IDEOGRAPH + 0x9EF7: 0x70D1, //CJK UNIFIED IDEOGRAPH + 0x9EF8: 0x70D2, //CJK UNIFIED IDEOGRAPH + 0x9EF9: 0x70D3, //CJK UNIFIED IDEOGRAPH + 0x9EFA: 0x70D4, //CJK UNIFIED IDEOGRAPH + 0x9EFB: 0x70D5, //CJK UNIFIED IDEOGRAPH + 0x9EFC: 0x70D6, //CJK UNIFIED IDEOGRAPH + 0x9EFD: 0x70D7, //CJK UNIFIED IDEOGRAPH + 0x9EFE: 0x70DA, //CJK UNIFIED IDEOGRAPH + 0x9F40: 0x70DC, //CJK UNIFIED IDEOGRAPH + 0x9F41: 0x70DD, //CJK UNIFIED IDEOGRAPH + 0x9F42: 0x70DE, //CJK UNIFIED IDEOGRAPH + 0x9F43: 0x70E0, //CJK UNIFIED IDEOGRAPH + 0x9F44: 0x70E1, //CJK UNIFIED IDEOGRAPH + 0x9F45: 0x70E2, //CJK UNIFIED IDEOGRAPH + 0x9F46: 0x70E3, //CJK UNIFIED IDEOGRAPH + 0x9F47: 0x70E5, //CJK UNIFIED IDEOGRAPH + 0x9F48: 0x70EA, //CJK UNIFIED IDEOGRAPH + 0x9F49: 0x70EE, //CJK UNIFIED IDEOGRAPH + 0x9F4A: 0x70F0, //CJK UNIFIED IDEOGRAPH + 0x9F4B: 0x70F1, //CJK UNIFIED IDEOGRAPH + 0x9F4C: 0x70F2, //CJK UNIFIED IDEOGRAPH + 0x9F4D: 0x70F3, //CJK UNIFIED IDEOGRAPH + 0x9F4E: 0x70F4, //CJK UNIFIED IDEOGRAPH + 0x9F4F: 0x70F5, //CJK UNIFIED IDEOGRAPH + 0x9F50: 0x70F6, //CJK UNIFIED IDEOGRAPH + 0x9F51: 0x70F8, //CJK UNIFIED IDEOGRAPH + 0x9F52: 0x70FA, //CJK UNIFIED IDEOGRAPH + 0x9F53: 0x70FB, //CJK UNIFIED IDEOGRAPH + 0x9F54: 0x70FC, //CJK UNIFIED IDEOGRAPH + 0x9F55: 0x70FE, //CJK UNIFIED IDEOGRAPH + 0x9F56: 0x70FF, //CJK UNIFIED IDEOGRAPH + 0x9F57: 0x7100, //CJK UNIFIED IDEOGRAPH + 0x9F58: 0x7101, //CJK UNIFIED IDEOGRAPH + 0x9F59: 0x7102, //CJK UNIFIED IDEOGRAPH + 0x9F5A: 0x7103, //CJK UNIFIED IDEOGRAPH + 0x9F5B: 0x7104, //CJK UNIFIED IDEOGRAPH + 0x9F5C: 0x7105, //CJK UNIFIED IDEOGRAPH + 0x9F5D: 0x7106, //CJK UNIFIED IDEOGRAPH + 0x9F5E: 0x7107, //CJK UNIFIED IDEOGRAPH + 0x9F5F: 0x7108, //CJK UNIFIED IDEOGRAPH + 0x9F60: 0x710B, //CJK UNIFIED IDEOGRAPH + 0x9F61: 0x710C, //CJK UNIFIED IDEOGRAPH + 0x9F62: 0x710D, //CJK UNIFIED IDEOGRAPH + 0x9F63: 0x710E, //CJK UNIFIED IDEOGRAPH + 0x9F64: 0x710F, //CJK UNIFIED IDEOGRAPH + 0x9F65: 0x7111, //CJK UNIFIED IDEOGRAPH + 0x9F66: 0x7112, //CJK UNIFIED IDEOGRAPH + 0x9F67: 0x7114, //CJK UNIFIED IDEOGRAPH + 0x9F68: 0x7117, //CJK UNIFIED IDEOGRAPH + 0x9F69: 0x711B, //CJK UNIFIED IDEOGRAPH + 0x9F6A: 0x711C, //CJK UNIFIED IDEOGRAPH + 0x9F6B: 0x711D, //CJK UNIFIED IDEOGRAPH + 0x9F6C: 0x711E, //CJK UNIFIED IDEOGRAPH + 0x9F6D: 0x711F, //CJK UNIFIED IDEOGRAPH + 0x9F6E: 0x7120, //CJK UNIFIED IDEOGRAPH + 0x9F6F: 0x7121, //CJK UNIFIED IDEOGRAPH + 0x9F70: 0x7122, //CJK UNIFIED IDEOGRAPH + 0x9F71: 0x7123, //CJK UNIFIED IDEOGRAPH + 0x9F72: 0x7124, //CJK UNIFIED IDEOGRAPH + 0x9F73: 0x7125, //CJK UNIFIED IDEOGRAPH + 0x9F74: 0x7127, //CJK UNIFIED IDEOGRAPH + 0x9F75: 0x7128, //CJK UNIFIED IDEOGRAPH + 0x9F76: 0x7129, //CJK UNIFIED IDEOGRAPH + 0x9F77: 0x712A, //CJK UNIFIED IDEOGRAPH + 0x9F78: 0x712B, //CJK UNIFIED IDEOGRAPH + 0x9F79: 0x712C, //CJK UNIFIED IDEOGRAPH + 0x9F7A: 0x712D, //CJK UNIFIED IDEOGRAPH + 0x9F7B: 0x712E, //CJK UNIFIED IDEOGRAPH + 0x9F7C: 0x7132, //CJK UNIFIED IDEOGRAPH + 0x9F7D: 0x7133, //CJK UNIFIED IDEOGRAPH + 0x9F7E: 0x7134, //CJK UNIFIED IDEOGRAPH + 0x9F80: 0x7135, //CJK UNIFIED IDEOGRAPH + 0x9F81: 0x7137, //CJK UNIFIED IDEOGRAPH + 0x9F82: 0x7138, //CJK UNIFIED IDEOGRAPH + 0x9F83: 0x7139, //CJK UNIFIED IDEOGRAPH + 0x9F84: 0x713A, //CJK UNIFIED IDEOGRAPH + 0x9F85: 0x713B, //CJK UNIFIED IDEOGRAPH + 0x9F86: 0x713C, //CJK UNIFIED IDEOGRAPH + 0x9F87: 0x713D, //CJK UNIFIED IDEOGRAPH + 0x9F88: 0x713E, //CJK UNIFIED IDEOGRAPH + 0x9F89: 0x713F, //CJK UNIFIED IDEOGRAPH + 0x9F8A: 0x7140, //CJK UNIFIED IDEOGRAPH + 0x9F8B: 0x7141, //CJK UNIFIED IDEOGRAPH + 0x9F8C: 0x7142, //CJK UNIFIED IDEOGRAPH + 0x9F8D: 0x7143, //CJK UNIFIED IDEOGRAPH + 0x9F8E: 0x7144, //CJK UNIFIED IDEOGRAPH + 0x9F8F: 0x7146, //CJK UNIFIED IDEOGRAPH + 0x9F90: 0x7147, //CJK UNIFIED IDEOGRAPH + 0x9F91: 0x7148, //CJK UNIFIED IDEOGRAPH + 0x9F92: 0x7149, //CJK UNIFIED IDEOGRAPH + 0x9F93: 0x714B, //CJK UNIFIED IDEOGRAPH + 0x9F94: 0x714D, //CJK UNIFIED IDEOGRAPH + 0x9F95: 0x714F, //CJK UNIFIED IDEOGRAPH + 0x9F96: 0x7150, //CJK UNIFIED IDEOGRAPH + 0x9F97: 0x7151, //CJK UNIFIED IDEOGRAPH + 0x9F98: 0x7152, //CJK UNIFIED IDEOGRAPH + 0x9F99: 0x7153, //CJK UNIFIED IDEOGRAPH + 0x9F9A: 0x7154, //CJK UNIFIED IDEOGRAPH + 0x9F9B: 0x7155, //CJK UNIFIED IDEOGRAPH + 0x9F9C: 0x7156, //CJK UNIFIED IDEOGRAPH + 0x9F9D: 0x7157, //CJK UNIFIED IDEOGRAPH + 0x9F9E: 0x7158, //CJK UNIFIED IDEOGRAPH + 0x9F9F: 0x7159, //CJK UNIFIED IDEOGRAPH + 0x9FA0: 0x715A, //CJK UNIFIED IDEOGRAPH + 0x9FA1: 0x715B, //CJK UNIFIED IDEOGRAPH + 0x9FA2: 0x715D, //CJK UNIFIED IDEOGRAPH + 0x9FA3: 0x715F, //CJK UNIFIED IDEOGRAPH + 0x9FA4: 0x7160, //CJK UNIFIED IDEOGRAPH + 0x9FA5: 0x7161, //CJK UNIFIED IDEOGRAPH + 0x9FA6: 0x7162, //CJK UNIFIED IDEOGRAPH + 0x9FA7: 0x7163, //CJK UNIFIED IDEOGRAPH + 0x9FA8: 0x7165, //CJK UNIFIED IDEOGRAPH + 0x9FA9: 0x7169, //CJK UNIFIED IDEOGRAPH + 0x9FAA: 0x716A, //CJK UNIFIED IDEOGRAPH + 0x9FAB: 0x716B, //CJK UNIFIED IDEOGRAPH + 0x9FAC: 0x716C, //CJK UNIFIED IDEOGRAPH + 0x9FAD: 0x716D, //CJK UNIFIED IDEOGRAPH + 0x9FAE: 0x716F, //CJK UNIFIED IDEOGRAPH + 0x9FAF: 0x7170, //CJK UNIFIED IDEOGRAPH + 0x9FB0: 0x7171, //CJK UNIFIED IDEOGRAPH + 0x9FB1: 0x7174, //CJK UNIFIED IDEOGRAPH + 0x9FB2: 0x7175, //CJK UNIFIED IDEOGRAPH + 0x9FB3: 0x7176, //CJK UNIFIED IDEOGRAPH + 0x9FB4: 0x7177, //CJK UNIFIED IDEOGRAPH + 0x9FB5: 0x7179, //CJK UNIFIED IDEOGRAPH + 0x9FB6: 0x717B, //CJK UNIFIED IDEOGRAPH + 0x9FB7: 0x717C, //CJK UNIFIED IDEOGRAPH + 0x9FB8: 0x717E, //CJK UNIFIED IDEOGRAPH + 0x9FB9: 0x717F, //CJK UNIFIED IDEOGRAPH + 0x9FBA: 0x7180, //CJK UNIFIED IDEOGRAPH + 0x9FBB: 0x7181, //CJK UNIFIED IDEOGRAPH + 0x9FBC: 0x7182, //CJK UNIFIED IDEOGRAPH + 0x9FBD: 0x7183, //CJK UNIFIED IDEOGRAPH + 0x9FBE: 0x7185, //CJK UNIFIED IDEOGRAPH + 0x9FBF: 0x7186, //CJK UNIFIED IDEOGRAPH + 0x9FC0: 0x7187, //CJK UNIFIED IDEOGRAPH + 0x9FC1: 0x7188, //CJK UNIFIED IDEOGRAPH + 0x9FC2: 0x7189, //CJK UNIFIED IDEOGRAPH + 0x9FC3: 0x718B, //CJK UNIFIED IDEOGRAPH + 0x9FC4: 0x718C, //CJK UNIFIED IDEOGRAPH + 0x9FC5: 0x718D, //CJK UNIFIED IDEOGRAPH + 0x9FC6: 0x718E, //CJK UNIFIED IDEOGRAPH + 0x9FC7: 0x7190, //CJK UNIFIED IDEOGRAPH + 0x9FC8: 0x7191, //CJK UNIFIED IDEOGRAPH + 0x9FC9: 0x7192, //CJK UNIFIED IDEOGRAPH + 0x9FCA: 0x7193, //CJK UNIFIED IDEOGRAPH + 0x9FCB: 0x7195, //CJK UNIFIED IDEOGRAPH + 0x9FCC: 0x7196, //CJK UNIFIED IDEOGRAPH + 0x9FCD: 0x7197, //CJK UNIFIED IDEOGRAPH + 0x9FCE: 0x719A, //CJK UNIFIED IDEOGRAPH + 0x9FCF: 0x719B, //CJK UNIFIED IDEOGRAPH + 0x9FD0: 0x719C, //CJK UNIFIED IDEOGRAPH + 0x9FD1: 0x719D, //CJK UNIFIED IDEOGRAPH + 0x9FD2: 0x719E, //CJK UNIFIED IDEOGRAPH + 0x9FD3: 0x71A1, //CJK UNIFIED IDEOGRAPH + 0x9FD4: 0x71A2, //CJK UNIFIED IDEOGRAPH + 0x9FD5: 0x71A3, //CJK UNIFIED IDEOGRAPH + 0x9FD6: 0x71A4, //CJK UNIFIED IDEOGRAPH + 0x9FD7: 0x71A5, //CJK UNIFIED IDEOGRAPH + 0x9FD8: 0x71A6, //CJK UNIFIED IDEOGRAPH + 0x9FD9: 0x71A7, //CJK UNIFIED IDEOGRAPH + 0x9FDA: 0x71A9, //CJK UNIFIED IDEOGRAPH + 0x9FDB: 0x71AA, //CJK UNIFIED IDEOGRAPH + 0x9FDC: 0x71AB, //CJK UNIFIED IDEOGRAPH + 0x9FDD: 0x71AD, //CJK UNIFIED IDEOGRAPH + 0x9FDE: 0x71AE, //CJK UNIFIED IDEOGRAPH + 0x9FDF: 0x71AF, //CJK UNIFIED IDEOGRAPH + 0x9FE0: 0x71B0, //CJK UNIFIED IDEOGRAPH + 0x9FE1: 0x71B1, //CJK UNIFIED IDEOGRAPH + 0x9FE2: 0x71B2, //CJK UNIFIED IDEOGRAPH + 0x9FE3: 0x71B4, //CJK UNIFIED IDEOGRAPH + 0x9FE4: 0x71B6, //CJK UNIFIED IDEOGRAPH + 0x9FE5: 0x71B7, //CJK UNIFIED IDEOGRAPH + 0x9FE6: 0x71B8, //CJK UNIFIED IDEOGRAPH + 0x9FE7: 0x71BA, //CJK UNIFIED IDEOGRAPH + 0x9FE8: 0x71BB, //CJK UNIFIED IDEOGRAPH + 0x9FE9: 0x71BC, //CJK UNIFIED IDEOGRAPH + 0x9FEA: 0x71BD, //CJK UNIFIED IDEOGRAPH + 0x9FEB: 0x71BE, //CJK UNIFIED IDEOGRAPH + 0x9FEC: 0x71BF, //CJK UNIFIED IDEOGRAPH + 0x9FED: 0x71C0, //CJK UNIFIED IDEOGRAPH + 0x9FEE: 0x71C1, //CJK UNIFIED IDEOGRAPH + 0x9FEF: 0x71C2, //CJK UNIFIED IDEOGRAPH + 0x9FF0: 0x71C4, //CJK UNIFIED IDEOGRAPH + 0x9FF1: 0x71C5, //CJK UNIFIED IDEOGRAPH + 0x9FF2: 0x71C6, //CJK UNIFIED IDEOGRAPH + 0x9FF3: 0x71C7, //CJK UNIFIED IDEOGRAPH + 0x9FF4: 0x71C8, //CJK UNIFIED IDEOGRAPH + 0x9FF5: 0x71C9, //CJK UNIFIED IDEOGRAPH + 0x9FF6: 0x71CA, //CJK UNIFIED IDEOGRAPH + 0x9FF7: 0x71CB, //CJK UNIFIED IDEOGRAPH + 0x9FF8: 0x71CC, //CJK UNIFIED IDEOGRAPH + 0x9FF9: 0x71CD, //CJK UNIFIED IDEOGRAPH + 0x9FFA: 0x71CF, //CJK UNIFIED IDEOGRAPH + 0x9FFB: 0x71D0, //CJK UNIFIED IDEOGRAPH + 0x9FFC: 0x71D1, //CJK UNIFIED IDEOGRAPH + 0x9FFD: 0x71D2, //CJK UNIFIED IDEOGRAPH + 0x9FFE: 0x71D3, //CJK UNIFIED IDEOGRAPH + 0xA040: 0x71D6, //CJK UNIFIED IDEOGRAPH + 0xA041: 0x71D7, //CJK UNIFIED IDEOGRAPH + 0xA042: 0x71D8, //CJK UNIFIED IDEOGRAPH + 0xA043: 0x71D9, //CJK UNIFIED IDEOGRAPH + 0xA044: 0x71DA, //CJK UNIFIED IDEOGRAPH + 0xA045: 0x71DB, //CJK UNIFIED IDEOGRAPH + 0xA046: 0x71DC, //CJK UNIFIED IDEOGRAPH + 0xA047: 0x71DD, //CJK UNIFIED IDEOGRAPH + 0xA048: 0x71DE, //CJK UNIFIED IDEOGRAPH + 0xA049: 0x71DF, //CJK UNIFIED IDEOGRAPH + 0xA04A: 0x71E1, //CJK UNIFIED IDEOGRAPH + 0xA04B: 0x71E2, //CJK UNIFIED IDEOGRAPH + 0xA04C: 0x71E3, //CJK UNIFIED IDEOGRAPH + 0xA04D: 0x71E4, //CJK UNIFIED IDEOGRAPH + 0xA04E: 0x71E6, //CJK UNIFIED IDEOGRAPH + 0xA04F: 0x71E8, //CJK UNIFIED IDEOGRAPH + 0xA050: 0x71E9, //CJK UNIFIED IDEOGRAPH + 0xA051: 0x71EA, //CJK UNIFIED IDEOGRAPH + 0xA052: 0x71EB, //CJK UNIFIED IDEOGRAPH + 0xA053: 0x71EC, //CJK UNIFIED IDEOGRAPH + 0xA054: 0x71ED, //CJK UNIFIED IDEOGRAPH + 0xA055: 0x71EF, //CJK UNIFIED IDEOGRAPH + 0xA056: 0x71F0, //CJK UNIFIED IDEOGRAPH + 0xA057: 0x71F1, //CJK UNIFIED IDEOGRAPH + 0xA058: 0x71F2, //CJK UNIFIED IDEOGRAPH + 0xA059: 0x71F3, //CJK UNIFIED IDEOGRAPH + 0xA05A: 0x71F4, //CJK UNIFIED IDEOGRAPH + 0xA05B: 0x71F5, //CJK UNIFIED IDEOGRAPH + 0xA05C: 0x71F6, //CJK UNIFIED IDEOGRAPH + 0xA05D: 0x71F7, //CJK UNIFIED IDEOGRAPH + 0xA05E: 0x71F8, //CJK UNIFIED IDEOGRAPH + 0xA05F: 0x71FA, //CJK UNIFIED IDEOGRAPH + 0xA060: 0x71FB, //CJK UNIFIED IDEOGRAPH + 0xA061: 0x71FC, //CJK UNIFIED IDEOGRAPH + 0xA062: 0x71FD, //CJK UNIFIED IDEOGRAPH + 0xA063: 0x71FE, //CJK UNIFIED IDEOGRAPH + 0xA064: 0x71FF, //CJK UNIFIED IDEOGRAPH + 0xA065: 0x7200, //CJK UNIFIED IDEOGRAPH + 0xA066: 0x7201, //CJK UNIFIED IDEOGRAPH + 0xA067: 0x7202, //CJK UNIFIED IDEOGRAPH + 0xA068: 0x7203, //CJK UNIFIED IDEOGRAPH + 0xA069: 0x7204, //CJK UNIFIED IDEOGRAPH + 0xA06A: 0x7205, //CJK UNIFIED IDEOGRAPH + 0xA06B: 0x7207, //CJK UNIFIED IDEOGRAPH + 0xA06C: 0x7208, //CJK UNIFIED IDEOGRAPH + 0xA06D: 0x7209, //CJK UNIFIED IDEOGRAPH + 0xA06E: 0x720A, //CJK UNIFIED IDEOGRAPH + 0xA06F: 0x720B, //CJK UNIFIED IDEOGRAPH + 0xA070: 0x720C, //CJK UNIFIED IDEOGRAPH + 0xA071: 0x720D, //CJK UNIFIED IDEOGRAPH + 0xA072: 0x720E, //CJK UNIFIED IDEOGRAPH + 0xA073: 0x720F, //CJK UNIFIED IDEOGRAPH + 0xA074: 0x7210, //CJK UNIFIED IDEOGRAPH + 0xA075: 0x7211, //CJK UNIFIED IDEOGRAPH + 0xA076: 0x7212, //CJK UNIFIED IDEOGRAPH + 0xA077: 0x7213, //CJK UNIFIED IDEOGRAPH + 0xA078: 0x7214, //CJK UNIFIED IDEOGRAPH + 0xA079: 0x7215, //CJK UNIFIED IDEOGRAPH + 0xA07A: 0x7216, //CJK UNIFIED IDEOGRAPH + 0xA07B: 0x7217, //CJK UNIFIED IDEOGRAPH + 0xA07C: 0x7218, //CJK UNIFIED IDEOGRAPH + 0xA07D: 0x7219, //CJK UNIFIED IDEOGRAPH + 0xA07E: 0x721A, //CJK UNIFIED IDEOGRAPH + 0xA080: 0x721B, //CJK UNIFIED IDEOGRAPH + 0xA081: 0x721C, //CJK UNIFIED IDEOGRAPH + 0xA082: 0x721E, //CJK UNIFIED IDEOGRAPH + 0xA083: 0x721F, //CJK UNIFIED IDEOGRAPH + 0xA084: 0x7220, //CJK UNIFIED IDEOGRAPH + 0xA085: 0x7221, //CJK UNIFIED IDEOGRAPH + 0xA086: 0x7222, //CJK UNIFIED IDEOGRAPH + 0xA087: 0x7223, //CJK UNIFIED IDEOGRAPH + 0xA088: 0x7224, //CJK UNIFIED IDEOGRAPH + 0xA089: 0x7225, //CJK UNIFIED IDEOGRAPH + 0xA08A: 0x7226, //CJK UNIFIED IDEOGRAPH + 0xA08B: 0x7227, //CJK UNIFIED IDEOGRAPH + 0xA08C: 0x7229, //CJK UNIFIED IDEOGRAPH + 0xA08D: 0x722B, //CJK UNIFIED IDEOGRAPH + 0xA08E: 0x722D, //CJK UNIFIED IDEOGRAPH + 0xA08F: 0x722E, //CJK UNIFIED IDEOGRAPH + 0xA090: 0x722F, //CJK UNIFIED IDEOGRAPH + 0xA091: 0x7232, //CJK UNIFIED IDEOGRAPH + 0xA092: 0x7233, //CJK UNIFIED IDEOGRAPH + 0xA093: 0x7234, //CJK UNIFIED IDEOGRAPH + 0xA094: 0x723A, //CJK UNIFIED IDEOGRAPH + 0xA095: 0x723C, //CJK UNIFIED IDEOGRAPH + 0xA096: 0x723E, //CJK UNIFIED IDEOGRAPH + 0xA097: 0x7240, //CJK UNIFIED IDEOGRAPH + 0xA098: 0x7241, //CJK UNIFIED IDEOGRAPH + 0xA099: 0x7242, //CJK UNIFIED IDEOGRAPH + 0xA09A: 0x7243, //CJK UNIFIED IDEOGRAPH + 0xA09B: 0x7244, //CJK UNIFIED IDEOGRAPH + 0xA09C: 0x7245, //CJK UNIFIED IDEOGRAPH + 0xA09D: 0x7246, //CJK UNIFIED IDEOGRAPH + 0xA09E: 0x7249, //CJK UNIFIED IDEOGRAPH + 0xA09F: 0x724A, //CJK UNIFIED IDEOGRAPH + 0xA0A0: 0x724B, //CJK UNIFIED IDEOGRAPH + 0xA0A1: 0x724E, //CJK UNIFIED IDEOGRAPH + 0xA0A2: 0x724F, //CJK UNIFIED IDEOGRAPH + 0xA0A3: 0x7250, //CJK UNIFIED IDEOGRAPH + 0xA0A4: 0x7251, //CJK UNIFIED IDEOGRAPH + 0xA0A5: 0x7253, //CJK UNIFIED IDEOGRAPH + 0xA0A6: 0x7254, //CJK UNIFIED IDEOGRAPH + 0xA0A7: 0x7255, //CJK UNIFIED IDEOGRAPH + 0xA0A8: 0x7257, //CJK UNIFIED IDEOGRAPH + 0xA0A9: 0x7258, //CJK UNIFIED IDEOGRAPH + 0xA0AA: 0x725A, //CJK UNIFIED IDEOGRAPH + 0xA0AB: 0x725C, //CJK UNIFIED IDEOGRAPH + 0xA0AC: 0x725E, //CJK UNIFIED IDEOGRAPH + 0xA0AD: 0x7260, //CJK UNIFIED IDEOGRAPH + 0xA0AE: 0x7263, //CJK UNIFIED IDEOGRAPH + 0xA0AF: 0x7264, //CJK UNIFIED IDEOGRAPH + 0xA0B0: 0x7265, //CJK UNIFIED IDEOGRAPH + 0xA0B1: 0x7268, //CJK UNIFIED IDEOGRAPH + 0xA0B2: 0x726A, //CJK UNIFIED IDEOGRAPH + 0xA0B3: 0x726B, //CJK UNIFIED IDEOGRAPH + 0xA0B4: 0x726C, //CJK UNIFIED IDEOGRAPH + 0xA0B5: 0x726D, //CJK UNIFIED IDEOGRAPH + 0xA0B6: 0x7270, //CJK UNIFIED IDEOGRAPH + 0xA0B7: 0x7271, //CJK UNIFIED IDEOGRAPH + 0xA0B8: 0x7273, //CJK UNIFIED IDEOGRAPH + 0xA0B9: 0x7274, //CJK UNIFIED IDEOGRAPH + 0xA0BA: 0x7276, //CJK UNIFIED IDEOGRAPH + 0xA0BB: 0x7277, //CJK UNIFIED IDEOGRAPH + 0xA0BC: 0x7278, //CJK UNIFIED IDEOGRAPH + 0xA0BD: 0x727B, //CJK UNIFIED IDEOGRAPH + 0xA0BE: 0x727C, //CJK UNIFIED IDEOGRAPH + 0xA0BF: 0x727D, //CJK UNIFIED IDEOGRAPH + 0xA0C0: 0x7282, //CJK UNIFIED IDEOGRAPH + 0xA0C1: 0x7283, //CJK UNIFIED IDEOGRAPH + 0xA0C2: 0x7285, //CJK UNIFIED IDEOGRAPH + 0xA0C3: 0x7286, //CJK UNIFIED IDEOGRAPH + 0xA0C4: 0x7287, //CJK UNIFIED IDEOGRAPH + 0xA0C5: 0x7288, //CJK UNIFIED IDEOGRAPH + 0xA0C6: 0x7289, //CJK UNIFIED IDEOGRAPH + 0xA0C7: 0x728C, //CJK UNIFIED IDEOGRAPH + 0xA0C8: 0x728E, //CJK UNIFIED IDEOGRAPH + 0xA0C9: 0x7290, //CJK UNIFIED IDEOGRAPH + 0xA0CA: 0x7291, //CJK UNIFIED IDEOGRAPH + 0xA0CB: 0x7293, //CJK UNIFIED IDEOGRAPH + 0xA0CC: 0x7294, //CJK UNIFIED IDEOGRAPH + 0xA0CD: 0x7295, //CJK UNIFIED IDEOGRAPH + 0xA0CE: 0x7296, //CJK UNIFIED IDEOGRAPH + 0xA0CF: 0x7297, //CJK UNIFIED IDEOGRAPH + 0xA0D0: 0x7298, //CJK UNIFIED IDEOGRAPH + 0xA0D1: 0x7299, //CJK UNIFIED IDEOGRAPH + 0xA0D2: 0x729A, //CJK UNIFIED IDEOGRAPH + 0xA0D3: 0x729B, //CJK UNIFIED IDEOGRAPH + 0xA0D4: 0x729C, //CJK UNIFIED IDEOGRAPH + 0xA0D5: 0x729D, //CJK UNIFIED IDEOGRAPH + 0xA0D6: 0x729E, //CJK UNIFIED IDEOGRAPH + 0xA0D7: 0x72A0, //CJK UNIFIED IDEOGRAPH + 0xA0D8: 0x72A1, //CJK UNIFIED IDEOGRAPH + 0xA0D9: 0x72A2, //CJK UNIFIED IDEOGRAPH + 0xA0DA: 0x72A3, //CJK UNIFIED IDEOGRAPH + 0xA0DB: 0x72A4, //CJK UNIFIED IDEOGRAPH + 0xA0DC: 0x72A5, //CJK UNIFIED IDEOGRAPH + 0xA0DD: 0x72A6, //CJK UNIFIED IDEOGRAPH + 0xA0DE: 0x72A7, //CJK UNIFIED IDEOGRAPH + 0xA0DF: 0x72A8, //CJK UNIFIED IDEOGRAPH + 0xA0E0: 0x72A9, //CJK UNIFIED IDEOGRAPH + 0xA0E1: 0x72AA, //CJK UNIFIED IDEOGRAPH + 0xA0E2: 0x72AB, //CJK UNIFIED IDEOGRAPH + 0xA0E3: 0x72AE, //CJK UNIFIED IDEOGRAPH + 0xA0E4: 0x72B1, //CJK UNIFIED IDEOGRAPH + 0xA0E5: 0x72B2, //CJK UNIFIED IDEOGRAPH + 0xA0E6: 0x72B3, //CJK UNIFIED IDEOGRAPH + 0xA0E7: 0x72B5, //CJK UNIFIED IDEOGRAPH + 0xA0E8: 0x72BA, //CJK UNIFIED IDEOGRAPH + 0xA0E9: 0x72BB, //CJK UNIFIED IDEOGRAPH + 0xA0EA: 0x72BC, //CJK UNIFIED IDEOGRAPH + 0xA0EB: 0x72BD, //CJK UNIFIED IDEOGRAPH + 0xA0EC: 0x72BE, //CJK UNIFIED IDEOGRAPH + 0xA0ED: 0x72BF, //CJK UNIFIED IDEOGRAPH + 0xA0EE: 0x72C0, //CJK UNIFIED IDEOGRAPH + 0xA0EF: 0x72C5, //CJK UNIFIED IDEOGRAPH + 0xA0F0: 0x72C6, //CJK UNIFIED IDEOGRAPH + 0xA0F1: 0x72C7, //CJK UNIFIED IDEOGRAPH + 0xA0F2: 0x72C9, //CJK UNIFIED IDEOGRAPH + 0xA0F3: 0x72CA, //CJK UNIFIED IDEOGRAPH + 0xA0F4: 0x72CB, //CJK UNIFIED IDEOGRAPH + 0xA0F5: 0x72CC, //CJK UNIFIED IDEOGRAPH + 0xA0F6: 0x72CF, //CJK UNIFIED IDEOGRAPH + 0xA0F7: 0x72D1, //CJK UNIFIED IDEOGRAPH + 0xA0F8: 0x72D3, //CJK UNIFIED IDEOGRAPH + 0xA0F9: 0x72D4, //CJK UNIFIED IDEOGRAPH + 0xA0FA: 0x72D5, //CJK UNIFIED IDEOGRAPH + 0xA0FB: 0x72D6, //CJK UNIFIED IDEOGRAPH + 0xA0FC: 0x72D8, //CJK UNIFIED IDEOGRAPH + 0xA0FD: 0x72DA, //CJK UNIFIED IDEOGRAPH + 0xA0FE: 0x72DB, //CJK UNIFIED IDEOGRAPH + 0xA1A1: 0x3000, //IDEOGRAPHIC SPACE + 0xA1A2: 0x3001, //IDEOGRAPHIC COMMA + 0xA1A3: 0x3002, //IDEOGRAPHIC FULL STOP + 0xA1A4: 0x00B7, //MIDDLE DOT + 0xA1A5: 0x02C9, //MODIFIER LETTER MACRON + 0xA1A6: 0x02C7, //CARON + 0xA1A7: 0x00A8, //DIAERESIS + 0xA1A8: 0x3003, //DITTO MARK + 0xA1A9: 0x3005, //IDEOGRAPHIC ITERATION MARK + 0xA1AA: 0x2014, //EM DASH + 0xA1AB: 0xFF5E, //FULLWIDTH TILDE + 0xA1AC: 0x2016, //DOUBLE VERTICAL LINE + 0xA1AD: 0x2026, //HORIZONTAL ELLIPSIS + 0xA1AE: 0x2018, //LEFT SINGLE QUOTATION MARK + 0xA1AF: 0x2019, //RIGHT SINGLE QUOTATION MARK + 0xA1B0: 0x201C, //LEFT DOUBLE QUOTATION MARK + 0xA1B1: 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0xA1B2: 0x3014, //LEFT TORTOISE SHELL BRACKET + 0xA1B3: 0x3015, //RIGHT TORTOISE SHELL BRACKET + 0xA1B4: 0x3008, //LEFT ANGLE BRACKET + 0xA1B5: 0x3009, //RIGHT ANGLE BRACKET + 0xA1B6: 0x300A, //LEFT DOUBLE ANGLE BRACKET + 0xA1B7: 0x300B, //RIGHT DOUBLE ANGLE BRACKET + 0xA1B8: 0x300C, //LEFT CORNER BRACKET + 0xA1B9: 0x300D, //RIGHT CORNER BRACKET + 0xA1BA: 0x300E, //LEFT WHITE CORNER BRACKET + 0xA1BB: 0x300F, //RIGHT WHITE CORNER BRACKET + 0xA1BC: 0x3016, //LEFT WHITE LENTICULAR BRACKET + 0xA1BD: 0x3017, //RIGHT WHITE LENTICULAR BRACKET + 0xA1BE: 0x3010, //LEFT BLACK LENTICULAR BRACKET + 0xA1BF: 0x3011, //RIGHT BLACK LENTICULAR BRACKET + 0xA1C0: 0x00B1, //PLUS-MINUS SIGN + 0xA1C1: 0x00D7, //MULTIPLICATION SIGN + 0xA1C2: 0x00F7, //DIVISION SIGN + 0xA1C3: 0x2236, //RATIO + 0xA1C4: 0x2227, //LOGICAL AND + 0xA1C5: 0x2228, //LOGICAL OR + 0xA1C6: 0x2211, //N-ARY SUMMATION + 0xA1C7: 0x220F, //N-ARY PRODUCT + 0xA1C8: 0x222A, //UNION + 0xA1C9: 0x2229, //INTERSECTION + 0xA1CA: 0x2208, //ELEMENT OF + 0xA1CB: 0x2237, //PROPORTION + 0xA1CC: 0x221A, //SQUARE ROOT + 0xA1CD: 0x22A5, //UP TACK + 0xA1CE: 0x2225, //PARALLEL TO + 0xA1CF: 0x2220, //ANGLE + 0xA1D0: 0x2312, //ARC + 0xA1D1: 0x2299, //CIRCLED DOT OPERATOR + 0xA1D2: 0x222B, //INTEGRAL + 0xA1D3: 0x222E, //CONTOUR INTEGRAL + 0xA1D4: 0x2261, //IDENTICAL TO + 0xA1D5: 0x224C, //ALL EQUAL TO + 0xA1D6: 0x2248, //ALMOST EQUAL TO + 0xA1D7: 0x223D, //REVERSED TILDE + 0xA1D8: 0x221D, //PROPORTIONAL TO + 0xA1D9: 0x2260, //NOT EQUAL TO + 0xA1DA: 0x226E, //NOT LESS-THAN + 0xA1DB: 0x226F, //NOT GREATER-THAN + 0xA1DC: 0x2264, //LESS-THAN OR EQUAL TO + 0xA1DD: 0x2265, //GREATER-THAN OR EQUAL TO + 0xA1DE: 0x221E, //INFINITY + 0xA1DF: 0x2235, //BECAUSE + 0xA1E0: 0x2234, //THEREFORE + 0xA1E1: 0x2642, //MALE SIGN + 0xA1E2: 0x2640, //FEMALE SIGN + 0xA1E3: 0x00B0, //DEGREE SIGN + 0xA1E4: 0x2032, //PRIME + 0xA1E5: 0x2033, //DOUBLE PRIME + 0xA1E6: 0x2103, //DEGREE CELSIUS + 0xA1E7: 0xFF04, //FULLWIDTH DOLLAR SIGN + 0xA1E8: 0x00A4, //CURRENCY SIGN + 0xA1E9: 0xFFE0, //FULLWIDTH CENT SIGN + 0xA1EA: 0xFFE1, //FULLWIDTH POUND SIGN + 0xA1EB: 0x2030, //PER MILLE SIGN + 0xA1EC: 0x00A7, //SECTION SIGN + 0xA1ED: 0x2116, //NUMERO SIGN + 0xA1EE: 0x2606, //WHITE STAR + 0xA1EF: 0x2605, //BLACK STAR + 0xA1F0: 0x25CB, //WHITE CIRCLE + 0xA1F1: 0x25CF, //BLACK CIRCLE + 0xA1F2: 0x25CE, //BULLSEYE + 0xA1F3: 0x25C7, //WHITE DIAMOND + 0xA1F4: 0x25C6, //BLACK DIAMOND + 0xA1F5: 0x25A1, //WHITE SQUARE + 0xA1F6: 0x25A0, //BLACK SQUARE + 0xA1F7: 0x25B3, //WHITE UP-POINTING TRIANGLE + 0xA1F8: 0x25B2, //BLACK UP-POINTING TRIANGLE + 0xA1F9: 0x203B, //REFERENCE MARK + 0xA1FA: 0x2192, //RIGHTWARDS ARROW + 0xA1FB: 0x2190, //LEFTWARDS ARROW + 0xA1FC: 0x2191, //UPWARDS ARROW + 0xA1FD: 0x2193, //DOWNWARDS ARROW + 0xA1FE: 0x3013, //GETA MARK + 0xA2A1: 0x2170, //SMALL ROMAN NUMERAL ONE + 0xA2A2: 0x2171, //SMALL ROMAN NUMERAL TWO + 0xA2A3: 0x2172, //SMALL ROMAN NUMERAL THREE + 0xA2A4: 0x2173, //SMALL ROMAN NUMERAL FOUR + 0xA2A5: 0x2174, //SMALL ROMAN NUMERAL FIVE + 0xA2A6: 0x2175, //SMALL ROMAN NUMERAL SIX + 0xA2A7: 0x2176, //SMALL ROMAN NUMERAL SEVEN + 0xA2A8: 0x2177, //SMALL ROMAN NUMERAL EIGHT + 0xA2A9: 0x2178, //SMALL ROMAN NUMERAL NINE + 0xA2AA: 0x2179, //SMALL ROMAN NUMERAL TEN + 0xA2B1: 0x2488, //DIGIT ONE FULL STOP + 0xA2B2: 0x2489, //DIGIT TWO FULL STOP + 0xA2B3: 0x248A, //DIGIT THREE FULL STOP + 0xA2B4: 0x248B, //DIGIT FOUR FULL STOP + 0xA2B5: 0x248C, //DIGIT FIVE FULL STOP + 0xA2B6: 0x248D, //DIGIT SIX FULL STOP + 0xA2B7: 0x248E, //DIGIT SEVEN FULL STOP + 0xA2B8: 0x248F, //DIGIT EIGHT FULL STOP + 0xA2B9: 0x2490, //DIGIT NINE FULL STOP + 0xA2BA: 0x2491, //NUMBER TEN FULL STOP + 0xA2BB: 0x2492, //NUMBER ELEVEN FULL STOP + 0xA2BC: 0x2493, //NUMBER TWELVE FULL STOP + 0xA2BD: 0x2494, //NUMBER THIRTEEN FULL STOP + 0xA2BE: 0x2495, //NUMBER FOURTEEN FULL STOP + 0xA2BF: 0x2496, //NUMBER FIFTEEN FULL STOP + 0xA2C0: 0x2497, //NUMBER SIXTEEN FULL STOP + 0xA2C1: 0x2498, //NUMBER SEVENTEEN FULL STOP + 0xA2C2: 0x2499, //NUMBER EIGHTEEN FULL STOP + 0xA2C3: 0x249A, //NUMBER NINETEEN FULL STOP + 0xA2C4: 0x249B, //NUMBER TWENTY FULL STOP + 0xA2C5: 0x2474, //PARENTHESIZED DIGIT ONE + 0xA2C6: 0x2475, //PARENTHESIZED DIGIT TWO + 0xA2C7: 0x2476, //PARENTHESIZED DIGIT THREE + 0xA2C8: 0x2477, //PARENTHESIZED DIGIT FOUR + 0xA2C9: 0x2478, //PARENTHESIZED DIGIT FIVE + 0xA2CA: 0x2479, //PARENTHESIZED DIGIT SIX + 0xA2CB: 0x247A, //PARENTHESIZED DIGIT SEVEN + 0xA2CC: 0x247B, //PARENTHESIZED DIGIT EIGHT + 0xA2CD: 0x247C, //PARENTHESIZED DIGIT NINE + 0xA2CE: 0x247D, //PARENTHESIZED NUMBER TEN + 0xA2CF: 0x247E, //PARENTHESIZED NUMBER ELEVEN + 0xA2D0: 0x247F, //PARENTHESIZED NUMBER TWELVE + 0xA2D1: 0x2480, //PARENTHESIZED NUMBER THIRTEEN + 0xA2D2: 0x2481, //PARENTHESIZED NUMBER FOURTEEN + 0xA2D3: 0x2482, //PARENTHESIZED NUMBER FIFTEEN + 0xA2D4: 0x2483, //PARENTHESIZED NUMBER SIXTEEN + 0xA2D5: 0x2484, //PARENTHESIZED NUMBER SEVENTEEN + 0xA2D6: 0x2485, //PARENTHESIZED NUMBER EIGHTEEN + 0xA2D7: 0x2486, //PARENTHESIZED NUMBER NINETEEN + 0xA2D8: 0x2487, //PARENTHESIZED NUMBER TWENTY + 0xA2D9: 0x2460, //CIRCLED DIGIT ONE + 0xA2DA: 0x2461, //CIRCLED DIGIT TWO + 0xA2DB: 0x2462, //CIRCLED DIGIT THREE + 0xA2DC: 0x2463, //CIRCLED DIGIT FOUR + 0xA2DD: 0x2464, //CIRCLED DIGIT FIVE + 0xA2DE: 0x2465, //CIRCLED DIGIT SIX + 0xA2DF: 0x2466, //CIRCLED DIGIT SEVEN + 0xA2E0: 0x2467, //CIRCLED DIGIT EIGHT + 0xA2E1: 0x2468, //CIRCLED DIGIT NINE + 0xA2E2: 0x2469, //CIRCLED NUMBER TEN + 0xA2E5: 0x3220, //PARENTHESIZED IDEOGRAPH ONE + 0xA2E6: 0x3221, //PARENTHESIZED IDEOGRAPH TWO + 0xA2E7: 0x3222, //PARENTHESIZED IDEOGRAPH THREE + 0xA2E8: 0x3223, //PARENTHESIZED IDEOGRAPH FOUR + 0xA2E9: 0x3224, //PARENTHESIZED IDEOGRAPH FIVE + 0xA2EA: 0x3225, //PARENTHESIZED IDEOGRAPH SIX + 0xA2EB: 0x3226, //PARENTHESIZED IDEOGRAPH SEVEN + 0xA2EC: 0x3227, //PARENTHESIZED IDEOGRAPH EIGHT + 0xA2ED: 0x3228, //PARENTHESIZED IDEOGRAPH NINE + 0xA2EE: 0x3229, //PARENTHESIZED IDEOGRAPH TEN + 0xA2F1: 0x2160, //ROMAN NUMERAL ONE + 0xA2F2: 0x2161, //ROMAN NUMERAL TWO + 0xA2F3: 0x2162, //ROMAN NUMERAL THREE + 0xA2F4: 0x2163, //ROMAN NUMERAL FOUR + 0xA2F5: 0x2164, //ROMAN NUMERAL FIVE + 0xA2F6: 0x2165, //ROMAN NUMERAL SIX + 0xA2F7: 0x2166, //ROMAN NUMERAL SEVEN + 0xA2F8: 0x2167, //ROMAN NUMERAL EIGHT + 0xA2F9: 0x2168, //ROMAN NUMERAL NINE + 0xA2FA: 0x2169, //ROMAN NUMERAL TEN + 0xA2FB: 0x216A, //ROMAN NUMERAL ELEVEN + 0xA2FC: 0x216B, //ROMAN NUMERAL TWELVE + 0xA3A1: 0xFF01, //FULLWIDTH EXCLAMATION MARK + 0xA3A2: 0xFF02, //FULLWIDTH QUOTATION MARK + 0xA3A3: 0xFF03, //FULLWIDTH NUMBER SIGN + 0xA3A4: 0xFFE5, //FULLWIDTH YEN SIGN + 0xA3A5: 0xFF05, //FULLWIDTH PERCENT SIGN + 0xA3A6: 0xFF06, //FULLWIDTH AMPERSAND + 0xA3A7: 0xFF07, //FULLWIDTH APOSTROPHE + 0xA3A8: 0xFF08, //FULLWIDTH LEFT PARENTHESIS + 0xA3A9: 0xFF09, //FULLWIDTH RIGHT PARENTHESIS + 0xA3AA: 0xFF0A, //FULLWIDTH ASTERISK + 0xA3AB: 0xFF0B, //FULLWIDTH PLUS SIGN + 0xA3AC: 0xFF0C, //FULLWIDTH COMMA + 0xA3AD: 0xFF0D, //FULLWIDTH HYPHEN-MINUS + 0xA3AE: 0xFF0E, //FULLWIDTH FULL STOP + 0xA3AF: 0xFF0F, //FULLWIDTH SOLIDUS + 0xA3B0: 0xFF10, //FULLWIDTH DIGIT ZERO + 0xA3B1: 0xFF11, //FULLWIDTH DIGIT ONE + 0xA3B2: 0xFF12, //FULLWIDTH DIGIT TWO + 0xA3B3: 0xFF13, //FULLWIDTH DIGIT THREE + 0xA3B4: 0xFF14, //FULLWIDTH DIGIT FOUR + 0xA3B5: 0xFF15, //FULLWIDTH DIGIT FIVE + 0xA3B6: 0xFF16, //FULLWIDTH DIGIT SIX + 0xA3B7: 0xFF17, //FULLWIDTH DIGIT SEVEN + 0xA3B8: 0xFF18, //FULLWIDTH DIGIT EIGHT + 0xA3B9: 0xFF19, //FULLWIDTH DIGIT NINE + 0xA3BA: 0xFF1A, //FULLWIDTH COLON + 0xA3BB: 0xFF1B, //FULLWIDTH SEMICOLON + 0xA3BC: 0xFF1C, //FULLWIDTH LESS-THAN SIGN + 0xA3BD: 0xFF1D, //FULLWIDTH EQUALS SIGN + 0xA3BE: 0xFF1E, //FULLWIDTH GREATER-THAN SIGN + 0xA3BF: 0xFF1F, //FULLWIDTH QUESTION MARK + 0xA3C0: 0xFF20, //FULLWIDTH COMMERCIAL AT + 0xA3C1: 0xFF21, //FULLWIDTH LATIN CAPITAL LETTER A + 0xA3C2: 0xFF22, //FULLWIDTH LATIN CAPITAL LETTER B + 0xA3C3: 0xFF23, //FULLWIDTH LATIN CAPITAL LETTER C + 0xA3C4: 0xFF24, //FULLWIDTH LATIN CAPITAL LETTER D + 0xA3C5: 0xFF25, //FULLWIDTH LATIN CAPITAL LETTER E + 0xA3C6: 0xFF26, //FULLWIDTH LATIN CAPITAL LETTER F + 0xA3C7: 0xFF27, //FULLWIDTH LATIN CAPITAL LETTER G + 0xA3C8: 0xFF28, //FULLWIDTH LATIN CAPITAL LETTER H + 0xA3C9: 0xFF29, //FULLWIDTH LATIN CAPITAL LETTER I + 0xA3CA: 0xFF2A, //FULLWIDTH LATIN CAPITAL LETTER J + 0xA3CB: 0xFF2B, //FULLWIDTH LATIN CAPITAL LETTER K + 0xA3CC: 0xFF2C, //FULLWIDTH LATIN CAPITAL LETTER L + 0xA3CD: 0xFF2D, //FULLWIDTH LATIN CAPITAL LETTER M + 0xA3CE: 0xFF2E, //FULLWIDTH LATIN CAPITAL LETTER N + 0xA3CF: 0xFF2F, //FULLWIDTH LATIN CAPITAL LETTER O + 0xA3D0: 0xFF30, //FULLWIDTH LATIN CAPITAL LETTER P + 0xA3D1: 0xFF31, //FULLWIDTH LATIN CAPITAL LETTER Q + 0xA3D2: 0xFF32, //FULLWIDTH LATIN CAPITAL LETTER R + 0xA3D3: 0xFF33, //FULLWIDTH LATIN CAPITAL LETTER S + 0xA3D4: 0xFF34, //FULLWIDTH LATIN CAPITAL LETTER T + 0xA3D5: 0xFF35, //FULLWIDTH LATIN CAPITAL LETTER U + 0xA3D6: 0xFF36, //FULLWIDTH LATIN CAPITAL LETTER V + 0xA3D7: 0xFF37, //FULLWIDTH LATIN CAPITAL LETTER W + 0xA3D8: 0xFF38, //FULLWIDTH LATIN CAPITAL LETTER X + 0xA3D9: 0xFF39, //FULLWIDTH LATIN CAPITAL LETTER Y + 0xA3DA: 0xFF3A, //FULLWIDTH LATIN CAPITAL LETTER Z + 0xA3DB: 0xFF3B, //FULLWIDTH LEFT SQUARE BRACKET + 0xA3DC: 0xFF3C, //FULLWIDTH REVERSE SOLIDUS + 0xA3DD: 0xFF3D, //FULLWIDTH RIGHT SQUARE BRACKET + 0xA3DE: 0xFF3E, //FULLWIDTH CIRCUMFLEX ACCENT + 0xA3DF: 0xFF3F, //FULLWIDTH LOW LINE + 0xA3E0: 0xFF40, //FULLWIDTH GRAVE ACCENT + 0xA3E1: 0xFF41, //FULLWIDTH LATIN SMALL LETTER A + 0xA3E2: 0xFF42, //FULLWIDTH LATIN SMALL LETTER B + 0xA3E3: 0xFF43, //FULLWIDTH LATIN SMALL LETTER C + 0xA3E4: 0xFF44, //FULLWIDTH LATIN SMALL LETTER D + 0xA3E5: 0xFF45, //FULLWIDTH LATIN SMALL LETTER E + 0xA3E6: 0xFF46, //FULLWIDTH LATIN SMALL LETTER F + 0xA3E7: 0xFF47, //FULLWIDTH LATIN SMALL LETTER G + 0xA3E8: 0xFF48, //FULLWIDTH LATIN SMALL LETTER H + 0xA3E9: 0xFF49, //FULLWIDTH LATIN SMALL LETTER I + 0xA3EA: 0xFF4A, //FULLWIDTH LATIN SMALL LETTER J + 0xA3EB: 0xFF4B, //FULLWIDTH LATIN SMALL LETTER K + 0xA3EC: 0xFF4C, //FULLWIDTH LATIN SMALL LETTER L + 0xA3ED: 0xFF4D, //FULLWIDTH LATIN SMALL LETTER M + 0xA3EE: 0xFF4E, //FULLWIDTH LATIN SMALL LETTER N + 0xA3EF: 0xFF4F, //FULLWIDTH LATIN SMALL LETTER O + 0xA3F0: 0xFF50, //FULLWIDTH LATIN SMALL LETTER P + 0xA3F1: 0xFF51, //FULLWIDTH LATIN SMALL LETTER Q + 0xA3F2: 0xFF52, //FULLWIDTH LATIN SMALL LETTER R + 0xA3F3: 0xFF53, //FULLWIDTH LATIN SMALL LETTER S + 0xA3F4: 0xFF54, //FULLWIDTH LATIN SMALL LETTER T + 0xA3F5: 0xFF55, //FULLWIDTH LATIN SMALL LETTER U + 0xA3F6: 0xFF56, //FULLWIDTH LATIN SMALL LETTER V + 0xA3F7: 0xFF57, //FULLWIDTH LATIN SMALL LETTER W + 0xA3F8: 0xFF58, //FULLWIDTH LATIN SMALL LETTER X + 0xA3F9: 0xFF59, //FULLWIDTH LATIN SMALL LETTER Y + 0xA3FA: 0xFF5A, //FULLWIDTH LATIN SMALL LETTER Z + 0xA3FB: 0xFF5B, //FULLWIDTH LEFT CURLY BRACKET + 0xA3FC: 0xFF5C, //FULLWIDTH VERTICAL LINE + 0xA3FD: 0xFF5D, //FULLWIDTH RIGHT CURLY BRACKET + 0xA3FE: 0xFFE3, //FULLWIDTH MACRON + 0xA4A1: 0x3041, //HIRAGANA LETTER SMALL A + 0xA4A2: 0x3042, //HIRAGANA LETTER A + 0xA4A3: 0x3043, //HIRAGANA LETTER SMALL I + 0xA4A4: 0x3044, //HIRAGANA LETTER I + 0xA4A5: 0x3045, //HIRAGANA LETTER SMALL U + 0xA4A6: 0x3046, //HIRAGANA LETTER U + 0xA4A7: 0x3047, //HIRAGANA LETTER SMALL E + 0xA4A8: 0x3048, //HIRAGANA LETTER E + 0xA4A9: 0x3049, //HIRAGANA LETTER SMALL O + 0xA4AA: 0x304A, //HIRAGANA LETTER O + 0xA4AB: 0x304B, //HIRAGANA LETTER KA + 0xA4AC: 0x304C, //HIRAGANA LETTER GA + 0xA4AD: 0x304D, //HIRAGANA LETTER KI + 0xA4AE: 0x304E, //HIRAGANA LETTER GI + 0xA4AF: 0x304F, //HIRAGANA LETTER KU + 0xA4B0: 0x3050, //HIRAGANA LETTER GU + 0xA4B1: 0x3051, //HIRAGANA LETTER KE + 0xA4B2: 0x3052, //HIRAGANA LETTER GE + 0xA4B3: 0x3053, //HIRAGANA LETTER KO + 0xA4B4: 0x3054, //HIRAGANA LETTER GO + 0xA4B5: 0x3055, //HIRAGANA LETTER SA + 0xA4B6: 0x3056, //HIRAGANA LETTER ZA + 0xA4B7: 0x3057, //HIRAGANA LETTER SI + 0xA4B8: 0x3058, //HIRAGANA LETTER ZI + 0xA4B9: 0x3059, //HIRAGANA LETTER SU + 0xA4BA: 0x305A, //HIRAGANA LETTER ZU + 0xA4BB: 0x305B, //HIRAGANA LETTER SE + 0xA4BC: 0x305C, //HIRAGANA LETTER ZE + 0xA4BD: 0x305D, //HIRAGANA LETTER SO + 0xA4BE: 0x305E, //HIRAGANA LETTER ZO + 0xA4BF: 0x305F, //HIRAGANA LETTER TA + 0xA4C0: 0x3060, //HIRAGANA LETTER DA + 0xA4C1: 0x3061, //HIRAGANA LETTER TI + 0xA4C2: 0x3062, //HIRAGANA LETTER DI + 0xA4C3: 0x3063, //HIRAGANA LETTER SMALL TU + 0xA4C4: 0x3064, //HIRAGANA LETTER TU + 0xA4C5: 0x3065, //HIRAGANA LETTER DU + 0xA4C6: 0x3066, //HIRAGANA LETTER TE + 0xA4C7: 0x3067, //HIRAGANA LETTER DE + 0xA4C8: 0x3068, //HIRAGANA LETTER TO + 0xA4C9: 0x3069, //HIRAGANA LETTER DO + 0xA4CA: 0x306A, //HIRAGANA LETTER NA + 0xA4CB: 0x306B, //HIRAGANA LETTER NI + 0xA4CC: 0x306C, //HIRAGANA LETTER NU + 0xA4CD: 0x306D, //HIRAGANA LETTER NE + 0xA4CE: 0x306E, //HIRAGANA LETTER NO + 0xA4CF: 0x306F, //HIRAGANA LETTER HA + 0xA4D0: 0x3070, //HIRAGANA LETTER BA + 0xA4D1: 0x3071, //HIRAGANA LETTER PA + 0xA4D2: 0x3072, //HIRAGANA LETTER HI + 0xA4D3: 0x3073, //HIRAGANA LETTER BI + 0xA4D4: 0x3074, //HIRAGANA LETTER PI + 0xA4D5: 0x3075, //HIRAGANA LETTER HU + 0xA4D6: 0x3076, //HIRAGANA LETTER BU + 0xA4D7: 0x3077, //HIRAGANA LETTER PU + 0xA4D8: 0x3078, //HIRAGANA LETTER HE + 0xA4D9: 0x3079, //HIRAGANA LETTER BE + 0xA4DA: 0x307A, //HIRAGANA LETTER PE + 0xA4DB: 0x307B, //HIRAGANA LETTER HO + 0xA4DC: 0x307C, //HIRAGANA LETTER BO + 0xA4DD: 0x307D, //HIRAGANA LETTER PO + 0xA4DE: 0x307E, //HIRAGANA LETTER MA + 0xA4DF: 0x307F, //HIRAGANA LETTER MI + 0xA4E0: 0x3080, //HIRAGANA LETTER MU + 0xA4E1: 0x3081, //HIRAGANA LETTER ME + 0xA4E2: 0x3082, //HIRAGANA LETTER MO + 0xA4E3: 0x3083, //HIRAGANA LETTER SMALL YA + 0xA4E4: 0x3084, //HIRAGANA LETTER YA + 0xA4E5: 0x3085, //HIRAGANA LETTER SMALL YU + 0xA4E6: 0x3086, //HIRAGANA LETTER YU + 0xA4E7: 0x3087, //HIRAGANA LETTER SMALL YO + 0xA4E8: 0x3088, //HIRAGANA LETTER YO + 0xA4E9: 0x3089, //HIRAGANA LETTER RA + 0xA4EA: 0x308A, //HIRAGANA LETTER RI + 0xA4EB: 0x308B, //HIRAGANA LETTER RU + 0xA4EC: 0x308C, //HIRAGANA LETTER RE + 0xA4ED: 0x308D, //HIRAGANA LETTER RO + 0xA4EE: 0x308E, //HIRAGANA LETTER SMALL WA + 0xA4EF: 0x308F, //HIRAGANA LETTER WA + 0xA4F0: 0x3090, //HIRAGANA LETTER WI + 0xA4F1: 0x3091, //HIRAGANA LETTER WE + 0xA4F2: 0x3092, //HIRAGANA LETTER WO + 0xA4F3: 0x3093, //HIRAGANA LETTER N + 0xA5A1: 0x30A1, //KATAKANA LETTER SMALL A + 0xA5A2: 0x30A2, //KATAKANA LETTER A + 0xA5A3: 0x30A3, //KATAKANA LETTER SMALL I + 0xA5A4: 0x30A4, //KATAKANA LETTER I + 0xA5A5: 0x30A5, //KATAKANA LETTER SMALL U + 0xA5A6: 0x30A6, //KATAKANA LETTER U + 0xA5A7: 0x30A7, //KATAKANA LETTER SMALL E + 0xA5A8: 0x30A8, //KATAKANA LETTER E + 0xA5A9: 0x30A9, //KATAKANA LETTER SMALL O + 0xA5AA: 0x30AA, //KATAKANA LETTER O + 0xA5AB: 0x30AB, //KATAKANA LETTER KA + 0xA5AC: 0x30AC, //KATAKANA LETTER GA + 0xA5AD: 0x30AD, //KATAKANA LETTER KI + 0xA5AE: 0x30AE, //KATAKANA LETTER GI + 0xA5AF: 0x30AF, //KATAKANA LETTER KU + 0xA5B0: 0x30B0, //KATAKANA LETTER GU + 0xA5B1: 0x30B1, //KATAKANA LETTER KE + 0xA5B2: 0x30B2, //KATAKANA LETTER GE + 0xA5B3: 0x30B3, //KATAKANA LETTER KO + 0xA5B4: 0x30B4, //KATAKANA LETTER GO + 0xA5B5: 0x30B5, //KATAKANA LETTER SA + 0xA5B6: 0x30B6, //KATAKANA LETTER ZA + 0xA5B7: 0x30B7, //KATAKANA LETTER SI + 0xA5B8: 0x30B8, //KATAKANA LETTER ZI + 0xA5B9: 0x30B9, //KATAKANA LETTER SU + 0xA5BA: 0x30BA, //KATAKANA LETTER ZU + 0xA5BB: 0x30BB, //KATAKANA LETTER SE + 0xA5BC: 0x30BC, //KATAKANA LETTER ZE + 0xA5BD: 0x30BD, //KATAKANA LETTER SO + 0xA5BE: 0x30BE, //KATAKANA LETTER ZO + 0xA5BF: 0x30BF, //KATAKANA LETTER TA + 0xA5C0: 0x30C0, //KATAKANA LETTER DA + 0xA5C1: 0x30C1, //KATAKANA LETTER TI + 0xA5C2: 0x30C2, //KATAKANA LETTER DI + 0xA5C3: 0x30C3, //KATAKANA LETTER SMALL TU + 0xA5C4: 0x30C4, //KATAKANA LETTER TU + 0xA5C5: 0x30C5, //KATAKANA LETTER DU + 0xA5C6: 0x30C6, //KATAKANA LETTER TE + 0xA5C7: 0x30C7, //KATAKANA LETTER DE + 0xA5C8: 0x30C8, //KATAKANA LETTER TO + 0xA5C9: 0x30C9, //KATAKANA LETTER DO + 0xA5CA: 0x30CA, //KATAKANA LETTER NA + 0xA5CB: 0x30CB, //KATAKANA LETTER NI + 0xA5CC: 0x30CC, //KATAKANA LETTER NU + 0xA5CD: 0x30CD, //KATAKANA LETTER NE + 0xA5CE: 0x30CE, //KATAKANA LETTER NO + 0xA5CF: 0x30CF, //KATAKANA LETTER HA + 0xA5D0: 0x30D0, //KATAKANA LETTER BA + 0xA5D1: 0x30D1, //KATAKANA LETTER PA + 0xA5D2: 0x30D2, //KATAKANA LETTER HI + 0xA5D3: 0x30D3, //KATAKANA LETTER BI + 0xA5D4: 0x30D4, //KATAKANA LETTER PI + 0xA5D5: 0x30D5, //KATAKANA LETTER HU + 0xA5D6: 0x30D6, //KATAKANA LETTER BU + 0xA5D7: 0x30D7, //KATAKANA LETTER PU + 0xA5D8: 0x30D8, //KATAKANA LETTER HE + 0xA5D9: 0x30D9, //KATAKANA LETTER BE + 0xA5DA: 0x30DA, //KATAKANA LETTER PE + 0xA5DB: 0x30DB, //KATAKANA LETTER HO + 0xA5DC: 0x30DC, //KATAKANA LETTER BO + 0xA5DD: 0x30DD, //KATAKANA LETTER PO + 0xA5DE: 0x30DE, //KATAKANA LETTER MA + 0xA5DF: 0x30DF, //KATAKANA LETTER MI + 0xA5E0: 0x30E0, //KATAKANA LETTER MU + 0xA5E1: 0x30E1, //KATAKANA LETTER ME + 0xA5E2: 0x30E2, //KATAKANA LETTER MO + 0xA5E3: 0x30E3, //KATAKANA LETTER SMALL YA + 0xA5E4: 0x30E4, //KATAKANA LETTER YA + 0xA5E5: 0x30E5, //KATAKANA LETTER SMALL YU + 0xA5E6: 0x30E6, //KATAKANA LETTER YU + 0xA5E7: 0x30E7, //KATAKANA LETTER SMALL YO + 0xA5E8: 0x30E8, //KATAKANA LETTER YO + 0xA5E9: 0x30E9, //KATAKANA LETTER RA + 0xA5EA: 0x30EA, //KATAKANA LETTER RI + 0xA5EB: 0x30EB, //KATAKANA LETTER RU + 0xA5EC: 0x30EC, //KATAKANA LETTER RE + 0xA5ED: 0x30ED, //KATAKANA LETTER RO + 0xA5EE: 0x30EE, //KATAKANA LETTER SMALL WA + 0xA5EF: 0x30EF, //KATAKANA LETTER WA + 0xA5F0: 0x30F0, //KATAKANA LETTER WI + 0xA5F1: 0x30F1, //KATAKANA LETTER WE + 0xA5F2: 0x30F2, //KATAKANA LETTER WO + 0xA5F3: 0x30F3, //KATAKANA LETTER N + 0xA5F4: 0x30F4, //KATAKANA LETTER VU + 0xA5F5: 0x30F5, //KATAKANA LETTER SMALL KA + 0xA5F6: 0x30F6, //KATAKANA LETTER SMALL KE + 0xA6A1: 0x0391, //GREEK CAPITAL LETTER ALPHA + 0xA6A2: 0x0392, //GREEK CAPITAL LETTER BETA + 0xA6A3: 0x0393, //GREEK CAPITAL LETTER GAMMA + 0xA6A4: 0x0394, //GREEK CAPITAL LETTER DELTA + 0xA6A5: 0x0395, //GREEK CAPITAL LETTER EPSILON + 0xA6A6: 0x0396, //GREEK CAPITAL LETTER ZETA + 0xA6A7: 0x0397, //GREEK CAPITAL LETTER ETA + 0xA6A8: 0x0398, //GREEK CAPITAL LETTER THETA + 0xA6A9: 0x0399, //GREEK CAPITAL LETTER IOTA + 0xA6AA: 0x039A, //GREEK CAPITAL LETTER KAPPA + 0xA6AB: 0x039B, //GREEK CAPITAL LETTER LAMDA + 0xA6AC: 0x039C, //GREEK CAPITAL LETTER MU + 0xA6AD: 0x039D, //GREEK CAPITAL LETTER NU + 0xA6AE: 0x039E, //GREEK CAPITAL LETTER XI + 0xA6AF: 0x039F, //GREEK CAPITAL LETTER OMICRON + 0xA6B0: 0x03A0, //GREEK CAPITAL LETTER PI + 0xA6B1: 0x03A1, //GREEK CAPITAL LETTER RHO + 0xA6B2: 0x03A3, //GREEK CAPITAL LETTER SIGMA + 0xA6B3: 0x03A4, //GREEK CAPITAL LETTER TAU + 0xA6B4: 0x03A5, //GREEK CAPITAL LETTER UPSILON + 0xA6B5: 0x03A6, //GREEK CAPITAL LETTER PHI + 0xA6B6: 0x03A7, //GREEK CAPITAL LETTER CHI + 0xA6B7: 0x03A8, //GREEK CAPITAL LETTER PSI + 0xA6B8: 0x03A9, //GREEK CAPITAL LETTER OMEGA + 0xA6C1: 0x03B1, //GREEK SMALL LETTER ALPHA + 0xA6C2: 0x03B2, //GREEK SMALL LETTER BETA + 0xA6C3: 0x03B3, //GREEK SMALL LETTER GAMMA + 0xA6C4: 0x03B4, //GREEK SMALL LETTER DELTA + 0xA6C5: 0x03B5, //GREEK SMALL LETTER EPSILON + 0xA6C6: 0x03B6, //GREEK SMALL LETTER ZETA + 0xA6C7: 0x03B7, //GREEK SMALL LETTER ETA + 0xA6C8: 0x03B8, //GREEK SMALL LETTER THETA + 0xA6C9: 0x03B9, //GREEK SMALL LETTER IOTA + 0xA6CA: 0x03BA, //GREEK SMALL LETTER KAPPA + 0xA6CB: 0x03BB, //GREEK SMALL LETTER LAMDA + 0xA6CC: 0x03BC, //GREEK SMALL LETTER MU + 0xA6CD: 0x03BD, //GREEK SMALL LETTER NU + 0xA6CE: 0x03BE, //GREEK SMALL LETTER XI + 0xA6CF: 0x03BF, //GREEK SMALL LETTER OMICRON + 0xA6D0: 0x03C0, //GREEK SMALL LETTER PI + 0xA6D1: 0x03C1, //GREEK SMALL LETTER RHO + 0xA6D2: 0x03C3, //GREEK SMALL LETTER SIGMA + 0xA6D3: 0x03C4, //GREEK SMALL LETTER TAU + 0xA6D4: 0x03C5, //GREEK SMALL LETTER UPSILON + 0xA6D5: 0x03C6, //GREEK SMALL LETTER PHI + 0xA6D6: 0x03C7, //GREEK SMALL LETTER CHI + 0xA6D7: 0x03C8, //GREEK SMALL LETTER PSI + 0xA6D8: 0x03C9, //GREEK SMALL LETTER OMEGA + 0xA6E0: 0xFE35, //PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS + 0xA6E1: 0xFE36, //PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS + 0xA6E2: 0xFE39, //PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET + 0xA6E3: 0xFE3A, //PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET + 0xA6E4: 0xFE3F, //PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET + 0xA6E5: 0xFE40, //PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET + 0xA6E6: 0xFE3D, //PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET + 0xA6E7: 0xFE3E, //PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET + 0xA6E8: 0xFE41, //PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET + 0xA6E9: 0xFE42, //PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET + 0xA6EA: 0xFE43, //PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET + 0xA6EB: 0xFE44, //PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET + 0xA6EE: 0xFE3B, //PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET + 0xA6EF: 0xFE3C, //PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET + 0xA6F0: 0xFE37, //PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET + 0xA6F1: 0xFE38, //PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET + 0xA6F2: 0xFE31, //PRESENTATION FORM FOR VERTICAL EM DASH + 0xA6F4: 0xFE33, //PRESENTATION FORM FOR VERTICAL LOW LINE + 0xA6F5: 0xFE34, //PRESENTATION FORM FOR VERTICAL WAVY LOW LINE + 0xA7A1: 0x0410, //CYRILLIC CAPITAL LETTER A + 0xA7A2: 0x0411, //CYRILLIC CAPITAL LETTER BE + 0xA7A3: 0x0412, //CYRILLIC CAPITAL LETTER VE + 0xA7A4: 0x0413, //CYRILLIC CAPITAL LETTER GHE + 0xA7A5: 0x0414, //CYRILLIC CAPITAL LETTER DE + 0xA7A6: 0x0415, //CYRILLIC CAPITAL LETTER IE + 0xA7A7: 0x0401, //CYRILLIC CAPITAL LETTER IO + 0xA7A8: 0x0416, //CYRILLIC CAPITAL LETTER ZHE + 0xA7A9: 0x0417, //CYRILLIC CAPITAL LETTER ZE + 0xA7AA: 0x0418, //CYRILLIC CAPITAL LETTER I + 0xA7AB: 0x0419, //CYRILLIC CAPITAL LETTER SHORT I + 0xA7AC: 0x041A, //CYRILLIC CAPITAL LETTER KA + 0xA7AD: 0x041B, //CYRILLIC CAPITAL LETTER EL + 0xA7AE: 0x041C, //CYRILLIC CAPITAL LETTER EM + 0xA7AF: 0x041D, //CYRILLIC CAPITAL LETTER EN + 0xA7B0: 0x041E, //CYRILLIC CAPITAL LETTER O + 0xA7B1: 0x041F, //CYRILLIC CAPITAL LETTER PE + 0xA7B2: 0x0420, //CYRILLIC CAPITAL LETTER ER + 0xA7B3: 0x0421, //CYRILLIC CAPITAL LETTER ES + 0xA7B4: 0x0422, //CYRILLIC CAPITAL LETTER TE + 0xA7B5: 0x0423, //CYRILLIC CAPITAL LETTER U + 0xA7B6: 0x0424, //CYRILLIC CAPITAL LETTER EF + 0xA7B7: 0x0425, //CYRILLIC CAPITAL LETTER HA + 0xA7B8: 0x0426, //CYRILLIC CAPITAL LETTER TSE + 0xA7B9: 0x0427, //CYRILLIC CAPITAL LETTER CHE + 0xA7BA: 0x0428, //CYRILLIC CAPITAL LETTER SHA + 0xA7BB: 0x0429, //CYRILLIC CAPITAL LETTER SHCHA + 0xA7BC: 0x042A, //CYRILLIC CAPITAL LETTER HARD SIGN + 0xA7BD: 0x042B, //CYRILLIC CAPITAL LETTER YERU + 0xA7BE: 0x042C, //CYRILLIC CAPITAL LETTER SOFT SIGN + 0xA7BF: 0x042D, //CYRILLIC CAPITAL LETTER E + 0xA7C0: 0x042E, //CYRILLIC CAPITAL LETTER YU + 0xA7C1: 0x042F, //CYRILLIC CAPITAL LETTER YA + 0xA7D1: 0x0430, //CYRILLIC SMALL LETTER A + 0xA7D2: 0x0431, //CYRILLIC SMALL LETTER BE + 0xA7D3: 0x0432, //CYRILLIC SMALL LETTER VE + 0xA7D4: 0x0433, //CYRILLIC SMALL LETTER GHE + 0xA7D5: 0x0434, //CYRILLIC SMALL LETTER DE + 0xA7D6: 0x0435, //CYRILLIC SMALL LETTER IE + 0xA7D7: 0x0451, //CYRILLIC SMALL LETTER IO + 0xA7D8: 0x0436, //CYRILLIC SMALL LETTER ZHE + 0xA7D9: 0x0437, //CYRILLIC SMALL LETTER ZE + 0xA7DA: 0x0438, //CYRILLIC SMALL LETTER I + 0xA7DB: 0x0439, //CYRILLIC SMALL LETTER SHORT I + 0xA7DC: 0x043A, //CYRILLIC SMALL LETTER KA + 0xA7DD: 0x043B, //CYRILLIC SMALL LETTER EL + 0xA7DE: 0x043C, //CYRILLIC SMALL LETTER EM + 0xA7DF: 0x043D, //CYRILLIC SMALL LETTER EN + 0xA7E0: 0x043E, //CYRILLIC SMALL LETTER O + 0xA7E1: 0x043F, //CYRILLIC SMALL LETTER PE + 0xA7E2: 0x0440, //CYRILLIC SMALL LETTER ER + 0xA7E3: 0x0441, //CYRILLIC SMALL LETTER ES + 0xA7E4: 0x0442, //CYRILLIC SMALL LETTER TE + 0xA7E5: 0x0443, //CYRILLIC SMALL LETTER U + 0xA7E6: 0x0444, //CYRILLIC SMALL LETTER EF + 0xA7E7: 0x0445, //CYRILLIC SMALL LETTER HA + 0xA7E8: 0x0446, //CYRILLIC SMALL LETTER TSE + 0xA7E9: 0x0447, //CYRILLIC SMALL LETTER CHE + 0xA7EA: 0x0448, //CYRILLIC SMALL LETTER SHA + 0xA7EB: 0x0449, //CYRILLIC SMALL LETTER SHCHA + 0xA7EC: 0x044A, //CYRILLIC SMALL LETTER HARD SIGN + 0xA7ED: 0x044B, //CYRILLIC SMALL LETTER YERU + 0xA7EE: 0x044C, //CYRILLIC SMALL LETTER SOFT SIGN + 0xA7EF: 0x044D, //CYRILLIC SMALL LETTER E + 0xA7F0: 0x044E, //CYRILLIC SMALL LETTER YU + 0xA7F1: 0x044F, //CYRILLIC SMALL LETTER YA + 0xA840: 0x02CA, //MODIFIER LETTER ACUTE ACCENT + 0xA841: 0x02CB, //MODIFIER LETTER GRAVE ACCENT + 0xA842: 0x02D9, //DOT ABOVE + 0xA843: 0x2013, //EN DASH + 0xA844: 0x2015, //HORIZONTAL BAR + 0xA845: 0x2025, //TWO DOT LEADER + 0xA846: 0x2035, //REVERSED PRIME + 0xA847: 0x2105, //CARE OF + 0xA848: 0x2109, //DEGREE FAHRENHEIT + 0xA849: 0x2196, //NORTH WEST ARROW + 0xA84A: 0x2197, //NORTH EAST ARROW + 0xA84B: 0x2198, //SOUTH EAST ARROW + 0xA84C: 0x2199, //SOUTH WEST ARROW + 0xA84D: 0x2215, //DIVISION SLASH + 0xA84E: 0x221F, //RIGHT ANGLE + 0xA84F: 0x2223, //DIVIDES + 0xA850: 0x2252, //APPROXIMATELY EQUAL TO OR THE IMAGE OF + 0xA851: 0x2266, //LESS-THAN OVER EQUAL TO + 0xA852: 0x2267, //GREATER-THAN OVER EQUAL TO + 0xA853: 0x22BF, //RIGHT TRIANGLE + 0xA854: 0x2550, //BOX DRAWINGS DOUBLE HORIZONTAL + 0xA855: 0x2551, //BOX DRAWINGS DOUBLE VERTICAL + 0xA856: 0x2552, //BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE + 0xA857: 0x2553, //BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE + 0xA858: 0x2554, //BOX DRAWINGS DOUBLE DOWN AND RIGHT + 0xA859: 0x2555, //BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE + 0xA85A: 0x2556, //BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE + 0xA85B: 0x2557, //BOX DRAWINGS DOUBLE DOWN AND LEFT + 0xA85C: 0x2558, //BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE + 0xA85D: 0x2559, //BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE + 0xA85E: 0x255A, //BOX DRAWINGS DOUBLE UP AND RIGHT + 0xA85F: 0x255B, //BOX DRAWINGS UP SINGLE AND LEFT DOUBLE + 0xA860: 0x255C, //BOX DRAWINGS UP DOUBLE AND LEFT SINGLE + 0xA861: 0x255D, //BOX DRAWINGS DOUBLE UP AND LEFT + 0xA862: 0x255E, //BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + 0xA863: 0x255F, //BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE + 0xA864: 0x2560, //BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + 0xA865: 0x2561, //BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + 0xA866: 0x2562, //BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE + 0xA867: 0x2563, //BOX DRAWINGS DOUBLE VERTICAL AND LEFT + 0xA868: 0x2564, //BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE + 0xA869: 0x2565, //BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE + 0xA86A: 0x2566, //BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + 0xA86B: 0x2567, //BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE + 0xA86C: 0x2568, //BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE + 0xA86D: 0x2569, //BOX DRAWINGS DOUBLE UP AND HORIZONTAL + 0xA86E: 0x256A, //BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + 0xA86F: 0x256B, //BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE + 0xA870: 0x256C, //BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + 0xA871: 0x256D, //BOX DRAWINGS LIGHT ARC DOWN AND RIGHT + 0xA872: 0x256E, //BOX DRAWINGS LIGHT ARC DOWN AND LEFT + 0xA873: 0x256F, //BOX DRAWINGS LIGHT ARC UP AND LEFT + 0xA874: 0x2570, //BOX DRAWINGS LIGHT ARC UP AND RIGHT + 0xA875: 0x2571, //BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + 0xA876: 0x2572, //BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + 0xA877: 0x2573, //BOX DRAWINGS LIGHT DIAGONAL CROSS + 0xA878: 0x2581, //LOWER ONE EIGHTH BLOCK + 0xA879: 0x2582, //LOWER ONE QUARTER BLOCK + 0xA87A: 0x2583, //LOWER THREE EIGHTHS BLOCK + 0xA87B: 0x2584, //LOWER HALF BLOCK + 0xA87C: 0x2585, //LOWER FIVE EIGHTHS BLOCK + 0xA87D: 0x2586, //LOWER THREE QUARTERS BLOCK + 0xA87E: 0x2587, //LOWER SEVEN EIGHTHS BLOCK + 0xA880: 0x2588, //FULL BLOCK + 0xA881: 0x2589, //LEFT SEVEN EIGHTHS BLOCK + 0xA882: 0x258A, //LEFT THREE QUARTERS BLOCK + 0xA883: 0x258B, //LEFT FIVE EIGHTHS BLOCK + 0xA884: 0x258C, //LEFT HALF BLOCK + 0xA885: 0x258D, //LEFT THREE EIGHTHS BLOCK + 0xA886: 0x258E, //LEFT ONE QUARTER BLOCK + 0xA887: 0x258F, //LEFT ONE EIGHTH BLOCK + 0xA888: 0x2593, //DARK SHADE + 0xA889: 0x2594, //UPPER ONE EIGHTH BLOCK + 0xA88A: 0x2595, //RIGHT ONE EIGHTH BLOCK + 0xA88B: 0x25BC, //BLACK DOWN-POINTING TRIANGLE + 0xA88C: 0x25BD, //WHITE DOWN-POINTING TRIANGLE + 0xA88D: 0x25E2, //BLACK LOWER RIGHT TRIANGLE + 0xA88E: 0x25E3, //BLACK LOWER LEFT TRIANGLE + 0xA88F: 0x25E4, //BLACK UPPER LEFT TRIANGLE + 0xA890: 0x25E5, //BLACK UPPER RIGHT TRIANGLE + 0xA891: 0x2609, //SUN + 0xA892: 0x2295, //CIRCLED PLUS + 0xA893: 0x3012, //POSTAL MARK + 0xA894: 0x301D, //REVERSED DOUBLE PRIME QUOTATION MARK + 0xA895: 0x301E, //DOUBLE PRIME QUOTATION MARK + 0xA8A1: 0x0101, //LATIN SMALL LETTER A WITH MACRON + 0xA8A2: 0x00E1, //LATIN SMALL LETTER A WITH ACUTE + 0xA8A3: 0x01CE, //LATIN SMALL LETTER A WITH CARON + 0xA8A4: 0x00E0, //LATIN SMALL LETTER A WITH GRAVE + 0xA8A5: 0x0113, //LATIN SMALL LETTER E WITH MACRON + 0xA8A6: 0x00E9, //LATIN SMALL LETTER E WITH ACUTE + 0xA8A7: 0x011B, //LATIN SMALL LETTER E WITH CARON + 0xA8A8: 0x00E8, //LATIN SMALL LETTER E WITH GRAVE + 0xA8A9: 0x012B, //LATIN SMALL LETTER I WITH MACRON + 0xA8AA: 0x00ED, //LATIN SMALL LETTER I WITH ACUTE + 0xA8AB: 0x01D0, //LATIN SMALL LETTER I WITH CARON + 0xA8AC: 0x00EC, //LATIN SMALL LETTER I WITH GRAVE + 0xA8AD: 0x014D, //LATIN SMALL LETTER O WITH MACRON + 0xA8AE: 0x00F3, //LATIN SMALL LETTER O WITH ACUTE + 0xA8AF: 0x01D2, //LATIN SMALL LETTER O WITH CARON + 0xA8B0: 0x00F2, //LATIN SMALL LETTER O WITH GRAVE + 0xA8B1: 0x016B, //LATIN SMALL LETTER U WITH MACRON + 0xA8B2: 0x00FA, //LATIN SMALL LETTER U WITH ACUTE + 0xA8B3: 0x01D4, //LATIN SMALL LETTER U WITH CARON + 0xA8B4: 0x00F9, //LATIN SMALL LETTER U WITH GRAVE + 0xA8B5: 0x01D6, //LATIN SMALL LETTER U WITH DIAERESIS AND MACRON + 0xA8B6: 0x01D8, //LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE + 0xA8B7: 0x01DA, //LATIN SMALL LETTER U WITH DIAERESIS AND CARON + 0xA8B8: 0x01DC, //LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE + 0xA8B9: 0x00FC, //LATIN SMALL LETTER U WITH DIAERESIS + 0xA8BA: 0x00EA, //LATIN SMALL LETTER E WITH CIRCUMFLEX + 0xA8BB: 0x0251, //LATIN SMALL LETTER ALPHA + 0xA8BD: 0x0144, //LATIN SMALL LETTER N WITH ACUTE + 0xA8BE: 0x0148, //LATIN SMALL LETTER N WITH CARON + 0xA8C0: 0x0261, //LATIN SMALL LETTER SCRIPT G + 0xA8C5: 0x3105, //BOPOMOFO LETTER B + 0xA8C6: 0x3106, //BOPOMOFO LETTER P + 0xA8C7: 0x3107, //BOPOMOFO LETTER M + 0xA8C8: 0x3108, //BOPOMOFO LETTER F + 0xA8C9: 0x3109, //BOPOMOFO LETTER D + 0xA8CA: 0x310A, //BOPOMOFO LETTER T + 0xA8CB: 0x310B, //BOPOMOFO LETTER N + 0xA8CC: 0x310C, //BOPOMOFO LETTER L + 0xA8CD: 0x310D, //BOPOMOFO LETTER G + 0xA8CE: 0x310E, //BOPOMOFO LETTER K + 0xA8CF: 0x310F, //BOPOMOFO LETTER H + 0xA8D0: 0x3110, //BOPOMOFO LETTER J + 0xA8D1: 0x3111, //BOPOMOFO LETTER Q + 0xA8D2: 0x3112, //BOPOMOFO LETTER X + 0xA8D3: 0x3113, //BOPOMOFO LETTER ZH + 0xA8D4: 0x3114, //BOPOMOFO LETTER CH + 0xA8D5: 0x3115, //BOPOMOFO LETTER SH + 0xA8D6: 0x3116, //BOPOMOFO LETTER R + 0xA8D7: 0x3117, //BOPOMOFO LETTER Z + 0xA8D8: 0x3118, //BOPOMOFO LETTER C + 0xA8D9: 0x3119, //BOPOMOFO LETTER S + 0xA8DA: 0x311A, //BOPOMOFO LETTER A + 0xA8DB: 0x311B, //BOPOMOFO LETTER O + 0xA8DC: 0x311C, //BOPOMOFO LETTER E + 0xA8DD: 0x311D, //BOPOMOFO LETTER EH + 0xA8DE: 0x311E, //BOPOMOFO LETTER AI + 0xA8DF: 0x311F, //BOPOMOFO LETTER EI + 0xA8E0: 0x3120, //BOPOMOFO LETTER AU + 0xA8E1: 0x3121, //BOPOMOFO LETTER OU + 0xA8E2: 0x3122, //BOPOMOFO LETTER AN + 0xA8E3: 0x3123, //BOPOMOFO LETTER EN + 0xA8E4: 0x3124, //BOPOMOFO LETTER ANG + 0xA8E5: 0x3125, //BOPOMOFO LETTER ENG + 0xA8E6: 0x3126, //BOPOMOFO LETTER ER + 0xA8E7: 0x3127, //BOPOMOFO LETTER I + 0xA8E8: 0x3128, //BOPOMOFO LETTER U + 0xA8E9: 0x3129, //BOPOMOFO LETTER IU + 0xA940: 0x3021, //HANGZHOU NUMERAL ONE + 0xA941: 0x3022, //HANGZHOU NUMERAL TWO + 0xA942: 0x3023, //HANGZHOU NUMERAL THREE + 0xA943: 0x3024, //HANGZHOU NUMERAL FOUR + 0xA944: 0x3025, //HANGZHOU NUMERAL FIVE + 0xA945: 0x3026, //HANGZHOU NUMERAL SIX + 0xA946: 0x3027, //HANGZHOU NUMERAL SEVEN + 0xA947: 0x3028, //HANGZHOU NUMERAL EIGHT + 0xA948: 0x3029, //HANGZHOU NUMERAL NINE + 0xA949: 0x32A3, //CIRCLED IDEOGRAPH CORRECT + 0xA94A: 0x338E, //SQUARE MG + 0xA94B: 0x338F, //SQUARE KG + 0xA94C: 0x339C, //SQUARE MM + 0xA94D: 0x339D, //SQUARE CM + 0xA94E: 0x339E, //SQUARE KM + 0xA94F: 0x33A1, //SQUARE M SQUARED + 0xA950: 0x33C4, //SQUARE CC + 0xA951: 0x33CE, //SQUARE KM CAPITAL + 0xA952: 0x33D1, //SQUARE LN + 0xA953: 0x33D2, //SQUARE LOG + 0xA954: 0x33D5, //SQUARE MIL + 0xA955: 0xFE30, //PRESENTATION FORM FOR VERTICAL TWO DOT LEADER + 0xA956: 0xFFE2, //FULLWIDTH NOT SIGN + 0xA957: 0xFFE4, //FULLWIDTH BROKEN BAR + 0xA959: 0x2121, //TELEPHONE SIGN + 0xA95A: 0x3231, //PARENTHESIZED IDEOGRAPH STOCK + 0xA95C: 0x2010, //HYPHEN + 0xA960: 0x30FC, //KATAKANA-HIRAGANA PROLONGED SOUND MARK + 0xA961: 0x309B, //KATAKANA-HIRAGANA VOICED SOUND MARK + 0xA962: 0x309C, //KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK + 0xA963: 0x30FD, //KATAKANA ITERATION MARK + 0xA964: 0x30FE, //KATAKANA VOICED ITERATION MARK + 0xA965: 0x3006, //IDEOGRAPHIC CLOSING MARK + 0xA966: 0x309D, //HIRAGANA ITERATION MARK + 0xA967: 0x309E, //HIRAGANA VOICED ITERATION MARK + 0xA968: 0xFE49, //DASHED OVERLINE + 0xA969: 0xFE4A, //CENTRELINE OVERLINE + 0xA96A: 0xFE4B, //WAVY OVERLINE + 0xA96B: 0xFE4C, //DOUBLE WAVY OVERLINE + 0xA96C: 0xFE4D, //DASHED LOW LINE + 0xA96D: 0xFE4E, //CENTRELINE LOW LINE + 0xA96E: 0xFE4F, //WAVY LOW LINE + 0xA96F: 0xFE50, //SMALL COMMA + 0xA970: 0xFE51, //SMALL IDEOGRAPHIC COMMA + 0xA971: 0xFE52, //SMALL FULL STOP + 0xA972: 0xFE54, //SMALL SEMICOLON + 0xA973: 0xFE55, //SMALL COLON + 0xA974: 0xFE56, //SMALL QUESTION MARK + 0xA975: 0xFE57, //SMALL EXCLAMATION MARK + 0xA976: 0xFE59, //SMALL LEFT PARENTHESIS + 0xA977: 0xFE5A, //SMALL RIGHT PARENTHESIS + 0xA978: 0xFE5B, //SMALL LEFT CURLY BRACKET + 0xA979: 0xFE5C, //SMALL RIGHT CURLY BRACKET + 0xA97A: 0xFE5D, //SMALL LEFT TORTOISE SHELL BRACKET + 0xA97B: 0xFE5E, //SMALL RIGHT TORTOISE SHELL BRACKET + 0xA97C: 0xFE5F, //SMALL NUMBER SIGN + 0xA97D: 0xFE60, //SMALL AMPERSAND + 0xA97E: 0xFE61, //SMALL ASTERISK + 0xA980: 0xFE62, //SMALL PLUS SIGN + 0xA981: 0xFE63, //SMALL HYPHEN-MINUS + 0xA982: 0xFE64, //SMALL LESS-THAN SIGN + 0xA983: 0xFE65, //SMALL GREATER-THAN SIGN + 0xA984: 0xFE66, //SMALL EQUALS SIGN + 0xA985: 0xFE68, //SMALL REVERSE SOLIDUS + 0xA986: 0xFE69, //SMALL DOLLAR SIGN + 0xA987: 0xFE6A, //SMALL PERCENT SIGN + 0xA988: 0xFE6B, //SMALL COMMERCIAL AT + 0xA996: 0x3007, //IDEOGRAPHIC NUMBER ZERO + 0xA9A4: 0x2500, //BOX DRAWINGS LIGHT HORIZONTAL + 0xA9A5: 0x2501, //BOX DRAWINGS HEAVY HORIZONTAL + 0xA9A6: 0x2502, //BOX DRAWINGS LIGHT VERTICAL + 0xA9A7: 0x2503, //BOX DRAWINGS HEAVY VERTICAL + 0xA9A8: 0x2504, //BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL + 0xA9A9: 0x2505, //BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL + 0xA9AA: 0x2506, //BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL + 0xA9AB: 0x2507, //BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL + 0xA9AC: 0x2508, //BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL + 0xA9AD: 0x2509, //BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL + 0xA9AE: 0x250A, //BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL + 0xA9AF: 0x250B, //BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL + 0xA9B0: 0x250C, //BOX DRAWINGS LIGHT DOWN AND RIGHT + 0xA9B1: 0x250D, //BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY + 0xA9B2: 0x250E, //BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT + 0xA9B3: 0x250F, //BOX DRAWINGS HEAVY DOWN AND RIGHT + 0xA9B4: 0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT + 0xA9B5: 0x2511, //BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY + 0xA9B6: 0x2512, //BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT + 0xA9B7: 0x2513, //BOX DRAWINGS HEAVY DOWN AND LEFT + 0xA9B8: 0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT + 0xA9B9: 0x2515, //BOX DRAWINGS UP LIGHT AND RIGHT HEAVY + 0xA9BA: 0x2516, //BOX DRAWINGS UP HEAVY AND RIGHT LIGHT + 0xA9BB: 0x2517, //BOX DRAWINGS HEAVY UP AND RIGHT + 0xA9BC: 0x2518, //BOX DRAWINGS LIGHT UP AND LEFT + 0xA9BD: 0x2519, //BOX DRAWINGS UP LIGHT AND LEFT HEAVY + 0xA9BE: 0x251A, //BOX DRAWINGS UP HEAVY AND LEFT LIGHT + 0xA9BF: 0x251B, //BOX DRAWINGS HEAVY UP AND LEFT + 0xA9C0: 0x251C, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0xA9C1: 0x251D, //BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY + 0xA9C2: 0x251E, //BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT + 0xA9C3: 0x251F, //BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT + 0xA9C4: 0x2520, //BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT + 0xA9C5: 0x2521, //BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY + 0xA9C6: 0x2522, //BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY + 0xA9C7: 0x2523, //BOX DRAWINGS HEAVY VERTICAL AND RIGHT + 0xA9C8: 0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0xA9C9: 0x2525, //BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY + 0xA9CA: 0x2526, //BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT + 0xA9CB: 0x2527, //BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT + 0xA9CC: 0x2528, //BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT + 0xA9CD: 0x2529, //BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY + 0xA9CE: 0x252A, //BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY + 0xA9CF: 0x252B, //BOX DRAWINGS HEAVY VERTICAL AND LEFT + 0xA9D0: 0x252C, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0xA9D1: 0x252D, //BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT + 0xA9D2: 0x252E, //BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT + 0xA9D3: 0x252F, //BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY + 0xA9D4: 0x2530, //BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT + 0xA9D5: 0x2531, //BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY + 0xA9D6: 0x2532, //BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY + 0xA9D7: 0x2533, //BOX DRAWINGS HEAVY DOWN AND HORIZONTAL + 0xA9D8: 0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0xA9D9: 0x2535, //BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT + 0xA9DA: 0x2536, //BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT + 0xA9DB: 0x2537, //BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY + 0xA9DC: 0x2538, //BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT + 0xA9DD: 0x2539, //BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY + 0xA9DE: 0x253A, //BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY + 0xA9DF: 0x253B, //BOX DRAWINGS HEAVY UP AND HORIZONTAL + 0xA9E0: 0x253C, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0xA9E1: 0x253D, //BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT + 0xA9E2: 0x253E, //BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT + 0xA9E3: 0x253F, //BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY + 0xA9E4: 0x2540, //BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT + 0xA9E5: 0x2541, //BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT + 0xA9E6: 0x2542, //BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT + 0xA9E7: 0x2543, //BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT + 0xA9E8: 0x2544, //BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT + 0xA9E9: 0x2545, //BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT + 0xA9EA: 0x2546, //BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT + 0xA9EB: 0x2547, //BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY + 0xA9EC: 0x2548, //BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY + 0xA9ED: 0x2549, //BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY + 0xA9EE: 0x254A, //BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY + 0xA9EF: 0x254B, //BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL + 0xAA40: 0x72DC, //CJK UNIFIED IDEOGRAPH + 0xAA41: 0x72DD, //CJK UNIFIED IDEOGRAPH + 0xAA42: 0x72DF, //CJK UNIFIED IDEOGRAPH + 0xAA43: 0x72E2, //CJK UNIFIED IDEOGRAPH + 0xAA44: 0x72E3, //CJK UNIFIED IDEOGRAPH + 0xAA45: 0x72E4, //CJK UNIFIED IDEOGRAPH + 0xAA46: 0x72E5, //CJK UNIFIED IDEOGRAPH + 0xAA47: 0x72E6, //CJK UNIFIED IDEOGRAPH + 0xAA48: 0x72E7, //CJK UNIFIED IDEOGRAPH + 0xAA49: 0x72EA, //CJK UNIFIED IDEOGRAPH + 0xAA4A: 0x72EB, //CJK UNIFIED IDEOGRAPH + 0xAA4B: 0x72F5, //CJK UNIFIED IDEOGRAPH + 0xAA4C: 0x72F6, //CJK UNIFIED IDEOGRAPH + 0xAA4D: 0x72F9, //CJK UNIFIED IDEOGRAPH + 0xAA4E: 0x72FD, //CJK UNIFIED IDEOGRAPH + 0xAA4F: 0x72FE, //CJK UNIFIED IDEOGRAPH + 0xAA50: 0x72FF, //CJK UNIFIED IDEOGRAPH + 0xAA51: 0x7300, //CJK UNIFIED IDEOGRAPH + 0xAA52: 0x7302, //CJK UNIFIED IDEOGRAPH + 0xAA53: 0x7304, //CJK UNIFIED IDEOGRAPH + 0xAA54: 0x7305, //CJK UNIFIED IDEOGRAPH + 0xAA55: 0x7306, //CJK UNIFIED IDEOGRAPH + 0xAA56: 0x7307, //CJK UNIFIED IDEOGRAPH + 0xAA57: 0x7308, //CJK UNIFIED IDEOGRAPH + 0xAA58: 0x7309, //CJK UNIFIED IDEOGRAPH + 0xAA59: 0x730B, //CJK UNIFIED IDEOGRAPH + 0xAA5A: 0x730C, //CJK UNIFIED IDEOGRAPH + 0xAA5B: 0x730D, //CJK UNIFIED IDEOGRAPH + 0xAA5C: 0x730F, //CJK UNIFIED IDEOGRAPH + 0xAA5D: 0x7310, //CJK UNIFIED IDEOGRAPH + 0xAA5E: 0x7311, //CJK UNIFIED IDEOGRAPH + 0xAA5F: 0x7312, //CJK UNIFIED IDEOGRAPH + 0xAA60: 0x7314, //CJK UNIFIED IDEOGRAPH + 0xAA61: 0x7318, //CJK UNIFIED IDEOGRAPH + 0xAA62: 0x7319, //CJK UNIFIED IDEOGRAPH + 0xAA63: 0x731A, //CJK UNIFIED IDEOGRAPH + 0xAA64: 0x731F, //CJK UNIFIED IDEOGRAPH + 0xAA65: 0x7320, //CJK UNIFIED IDEOGRAPH + 0xAA66: 0x7323, //CJK UNIFIED IDEOGRAPH + 0xAA67: 0x7324, //CJK UNIFIED IDEOGRAPH + 0xAA68: 0x7326, //CJK UNIFIED IDEOGRAPH + 0xAA69: 0x7327, //CJK UNIFIED IDEOGRAPH + 0xAA6A: 0x7328, //CJK UNIFIED IDEOGRAPH + 0xAA6B: 0x732D, //CJK UNIFIED IDEOGRAPH + 0xAA6C: 0x732F, //CJK UNIFIED IDEOGRAPH + 0xAA6D: 0x7330, //CJK UNIFIED IDEOGRAPH + 0xAA6E: 0x7332, //CJK UNIFIED IDEOGRAPH + 0xAA6F: 0x7333, //CJK UNIFIED IDEOGRAPH + 0xAA70: 0x7335, //CJK UNIFIED IDEOGRAPH + 0xAA71: 0x7336, //CJK UNIFIED IDEOGRAPH + 0xAA72: 0x733A, //CJK UNIFIED IDEOGRAPH + 0xAA73: 0x733B, //CJK UNIFIED IDEOGRAPH + 0xAA74: 0x733C, //CJK UNIFIED IDEOGRAPH + 0xAA75: 0x733D, //CJK UNIFIED IDEOGRAPH + 0xAA76: 0x7340, //CJK UNIFIED IDEOGRAPH + 0xAA77: 0x7341, //CJK UNIFIED IDEOGRAPH + 0xAA78: 0x7342, //CJK UNIFIED IDEOGRAPH + 0xAA79: 0x7343, //CJK UNIFIED IDEOGRAPH + 0xAA7A: 0x7344, //CJK UNIFIED IDEOGRAPH + 0xAA7B: 0x7345, //CJK UNIFIED IDEOGRAPH + 0xAA7C: 0x7346, //CJK UNIFIED IDEOGRAPH + 0xAA7D: 0x7347, //CJK UNIFIED IDEOGRAPH + 0xAA7E: 0x7348, //CJK UNIFIED IDEOGRAPH + 0xAA80: 0x7349, //CJK UNIFIED IDEOGRAPH + 0xAA81: 0x734A, //CJK UNIFIED IDEOGRAPH + 0xAA82: 0x734B, //CJK UNIFIED IDEOGRAPH + 0xAA83: 0x734C, //CJK UNIFIED IDEOGRAPH + 0xAA84: 0x734E, //CJK UNIFIED IDEOGRAPH + 0xAA85: 0x734F, //CJK UNIFIED IDEOGRAPH + 0xAA86: 0x7351, //CJK UNIFIED IDEOGRAPH + 0xAA87: 0x7353, //CJK UNIFIED IDEOGRAPH + 0xAA88: 0x7354, //CJK UNIFIED IDEOGRAPH + 0xAA89: 0x7355, //CJK UNIFIED IDEOGRAPH + 0xAA8A: 0x7356, //CJK UNIFIED IDEOGRAPH + 0xAA8B: 0x7358, //CJK UNIFIED IDEOGRAPH + 0xAA8C: 0x7359, //CJK UNIFIED IDEOGRAPH + 0xAA8D: 0x735A, //CJK UNIFIED IDEOGRAPH + 0xAA8E: 0x735B, //CJK UNIFIED IDEOGRAPH + 0xAA8F: 0x735C, //CJK UNIFIED IDEOGRAPH + 0xAA90: 0x735D, //CJK UNIFIED IDEOGRAPH + 0xAA91: 0x735E, //CJK UNIFIED IDEOGRAPH + 0xAA92: 0x735F, //CJK UNIFIED IDEOGRAPH + 0xAA93: 0x7361, //CJK UNIFIED IDEOGRAPH + 0xAA94: 0x7362, //CJK UNIFIED IDEOGRAPH + 0xAA95: 0x7363, //CJK UNIFIED IDEOGRAPH + 0xAA96: 0x7364, //CJK UNIFIED IDEOGRAPH + 0xAA97: 0x7365, //CJK UNIFIED IDEOGRAPH + 0xAA98: 0x7366, //CJK UNIFIED IDEOGRAPH + 0xAA99: 0x7367, //CJK UNIFIED IDEOGRAPH + 0xAA9A: 0x7368, //CJK UNIFIED IDEOGRAPH + 0xAA9B: 0x7369, //CJK UNIFIED IDEOGRAPH + 0xAA9C: 0x736A, //CJK UNIFIED IDEOGRAPH + 0xAA9D: 0x736B, //CJK UNIFIED IDEOGRAPH + 0xAA9E: 0x736E, //CJK UNIFIED IDEOGRAPH + 0xAA9F: 0x7370, //CJK UNIFIED IDEOGRAPH + 0xAAA0: 0x7371, //CJK UNIFIED IDEOGRAPH + 0xAB40: 0x7372, //CJK UNIFIED IDEOGRAPH + 0xAB41: 0x7373, //CJK UNIFIED IDEOGRAPH + 0xAB42: 0x7374, //CJK UNIFIED IDEOGRAPH + 0xAB43: 0x7375, //CJK UNIFIED IDEOGRAPH + 0xAB44: 0x7376, //CJK UNIFIED IDEOGRAPH + 0xAB45: 0x7377, //CJK UNIFIED IDEOGRAPH + 0xAB46: 0x7378, //CJK UNIFIED IDEOGRAPH + 0xAB47: 0x7379, //CJK UNIFIED IDEOGRAPH + 0xAB48: 0x737A, //CJK UNIFIED IDEOGRAPH + 0xAB49: 0x737B, //CJK UNIFIED IDEOGRAPH + 0xAB4A: 0x737C, //CJK UNIFIED IDEOGRAPH + 0xAB4B: 0x737D, //CJK UNIFIED IDEOGRAPH + 0xAB4C: 0x737F, //CJK UNIFIED IDEOGRAPH + 0xAB4D: 0x7380, //CJK UNIFIED IDEOGRAPH + 0xAB4E: 0x7381, //CJK UNIFIED IDEOGRAPH + 0xAB4F: 0x7382, //CJK UNIFIED IDEOGRAPH + 0xAB50: 0x7383, //CJK UNIFIED IDEOGRAPH + 0xAB51: 0x7385, //CJK UNIFIED IDEOGRAPH + 0xAB52: 0x7386, //CJK UNIFIED IDEOGRAPH + 0xAB53: 0x7388, //CJK UNIFIED IDEOGRAPH + 0xAB54: 0x738A, //CJK UNIFIED IDEOGRAPH + 0xAB55: 0x738C, //CJK UNIFIED IDEOGRAPH + 0xAB56: 0x738D, //CJK UNIFIED IDEOGRAPH + 0xAB57: 0x738F, //CJK UNIFIED IDEOGRAPH + 0xAB58: 0x7390, //CJK UNIFIED IDEOGRAPH + 0xAB59: 0x7392, //CJK UNIFIED IDEOGRAPH + 0xAB5A: 0x7393, //CJK UNIFIED IDEOGRAPH + 0xAB5B: 0x7394, //CJK UNIFIED IDEOGRAPH + 0xAB5C: 0x7395, //CJK UNIFIED IDEOGRAPH + 0xAB5D: 0x7397, //CJK UNIFIED IDEOGRAPH + 0xAB5E: 0x7398, //CJK UNIFIED IDEOGRAPH + 0xAB5F: 0x7399, //CJK UNIFIED IDEOGRAPH + 0xAB60: 0x739A, //CJK UNIFIED IDEOGRAPH + 0xAB61: 0x739C, //CJK UNIFIED IDEOGRAPH + 0xAB62: 0x739D, //CJK UNIFIED IDEOGRAPH + 0xAB63: 0x739E, //CJK UNIFIED IDEOGRAPH + 0xAB64: 0x73A0, //CJK UNIFIED IDEOGRAPH + 0xAB65: 0x73A1, //CJK UNIFIED IDEOGRAPH + 0xAB66: 0x73A3, //CJK UNIFIED IDEOGRAPH + 0xAB67: 0x73A4, //CJK UNIFIED IDEOGRAPH + 0xAB68: 0x73A5, //CJK UNIFIED IDEOGRAPH + 0xAB69: 0x73A6, //CJK UNIFIED IDEOGRAPH + 0xAB6A: 0x73A7, //CJK UNIFIED IDEOGRAPH + 0xAB6B: 0x73A8, //CJK UNIFIED IDEOGRAPH + 0xAB6C: 0x73AA, //CJK UNIFIED IDEOGRAPH + 0xAB6D: 0x73AC, //CJK UNIFIED IDEOGRAPH + 0xAB6E: 0x73AD, //CJK UNIFIED IDEOGRAPH + 0xAB6F: 0x73B1, //CJK UNIFIED IDEOGRAPH + 0xAB70: 0x73B4, //CJK UNIFIED IDEOGRAPH + 0xAB71: 0x73B5, //CJK UNIFIED IDEOGRAPH + 0xAB72: 0x73B6, //CJK UNIFIED IDEOGRAPH + 0xAB73: 0x73B8, //CJK UNIFIED IDEOGRAPH + 0xAB74: 0x73B9, //CJK UNIFIED IDEOGRAPH + 0xAB75: 0x73BC, //CJK UNIFIED IDEOGRAPH + 0xAB76: 0x73BD, //CJK UNIFIED IDEOGRAPH + 0xAB77: 0x73BE, //CJK UNIFIED IDEOGRAPH + 0xAB78: 0x73BF, //CJK UNIFIED IDEOGRAPH + 0xAB79: 0x73C1, //CJK UNIFIED IDEOGRAPH + 0xAB7A: 0x73C3, //CJK UNIFIED IDEOGRAPH + 0xAB7B: 0x73C4, //CJK UNIFIED IDEOGRAPH + 0xAB7C: 0x73C5, //CJK UNIFIED IDEOGRAPH + 0xAB7D: 0x73C6, //CJK UNIFIED IDEOGRAPH + 0xAB7E: 0x73C7, //CJK UNIFIED IDEOGRAPH + 0xAB80: 0x73CB, //CJK UNIFIED IDEOGRAPH + 0xAB81: 0x73CC, //CJK UNIFIED IDEOGRAPH + 0xAB82: 0x73CE, //CJK UNIFIED IDEOGRAPH + 0xAB83: 0x73D2, //CJK UNIFIED IDEOGRAPH + 0xAB84: 0x73D3, //CJK UNIFIED IDEOGRAPH + 0xAB85: 0x73D4, //CJK UNIFIED IDEOGRAPH + 0xAB86: 0x73D5, //CJK UNIFIED IDEOGRAPH + 0xAB87: 0x73D6, //CJK UNIFIED IDEOGRAPH + 0xAB88: 0x73D7, //CJK UNIFIED IDEOGRAPH + 0xAB89: 0x73D8, //CJK UNIFIED IDEOGRAPH + 0xAB8A: 0x73DA, //CJK UNIFIED IDEOGRAPH + 0xAB8B: 0x73DB, //CJK UNIFIED IDEOGRAPH + 0xAB8C: 0x73DC, //CJK UNIFIED IDEOGRAPH + 0xAB8D: 0x73DD, //CJK UNIFIED IDEOGRAPH + 0xAB8E: 0x73DF, //CJK UNIFIED IDEOGRAPH + 0xAB8F: 0x73E1, //CJK UNIFIED IDEOGRAPH + 0xAB90: 0x73E2, //CJK UNIFIED IDEOGRAPH + 0xAB91: 0x73E3, //CJK UNIFIED IDEOGRAPH + 0xAB92: 0x73E4, //CJK UNIFIED IDEOGRAPH + 0xAB93: 0x73E6, //CJK UNIFIED IDEOGRAPH + 0xAB94: 0x73E8, //CJK UNIFIED IDEOGRAPH + 0xAB95: 0x73EA, //CJK UNIFIED IDEOGRAPH + 0xAB96: 0x73EB, //CJK UNIFIED IDEOGRAPH + 0xAB97: 0x73EC, //CJK UNIFIED IDEOGRAPH + 0xAB98: 0x73EE, //CJK UNIFIED IDEOGRAPH + 0xAB99: 0x73EF, //CJK UNIFIED IDEOGRAPH + 0xAB9A: 0x73F0, //CJK UNIFIED IDEOGRAPH + 0xAB9B: 0x73F1, //CJK UNIFIED IDEOGRAPH + 0xAB9C: 0x73F3, //CJK UNIFIED IDEOGRAPH + 0xAB9D: 0x73F4, //CJK UNIFIED IDEOGRAPH + 0xAB9E: 0x73F5, //CJK UNIFIED IDEOGRAPH + 0xAB9F: 0x73F6, //CJK UNIFIED IDEOGRAPH + 0xABA0: 0x73F7, //CJK UNIFIED IDEOGRAPH + 0xAC40: 0x73F8, //CJK UNIFIED IDEOGRAPH + 0xAC41: 0x73F9, //CJK UNIFIED IDEOGRAPH + 0xAC42: 0x73FA, //CJK UNIFIED IDEOGRAPH + 0xAC43: 0x73FB, //CJK UNIFIED IDEOGRAPH + 0xAC44: 0x73FC, //CJK UNIFIED IDEOGRAPH + 0xAC45: 0x73FD, //CJK UNIFIED IDEOGRAPH + 0xAC46: 0x73FE, //CJK UNIFIED IDEOGRAPH + 0xAC47: 0x73FF, //CJK UNIFIED IDEOGRAPH + 0xAC48: 0x7400, //CJK UNIFIED IDEOGRAPH + 0xAC49: 0x7401, //CJK UNIFIED IDEOGRAPH + 0xAC4A: 0x7402, //CJK UNIFIED IDEOGRAPH + 0xAC4B: 0x7404, //CJK UNIFIED IDEOGRAPH + 0xAC4C: 0x7407, //CJK UNIFIED IDEOGRAPH + 0xAC4D: 0x7408, //CJK UNIFIED IDEOGRAPH + 0xAC4E: 0x740B, //CJK UNIFIED IDEOGRAPH + 0xAC4F: 0x740C, //CJK UNIFIED IDEOGRAPH + 0xAC50: 0x740D, //CJK UNIFIED IDEOGRAPH + 0xAC51: 0x740E, //CJK UNIFIED IDEOGRAPH + 0xAC52: 0x7411, //CJK UNIFIED IDEOGRAPH + 0xAC53: 0x7412, //CJK UNIFIED IDEOGRAPH + 0xAC54: 0x7413, //CJK UNIFIED IDEOGRAPH + 0xAC55: 0x7414, //CJK UNIFIED IDEOGRAPH + 0xAC56: 0x7415, //CJK UNIFIED IDEOGRAPH + 0xAC57: 0x7416, //CJK UNIFIED IDEOGRAPH + 0xAC58: 0x7417, //CJK UNIFIED IDEOGRAPH + 0xAC59: 0x7418, //CJK UNIFIED IDEOGRAPH + 0xAC5A: 0x7419, //CJK UNIFIED IDEOGRAPH + 0xAC5B: 0x741C, //CJK UNIFIED IDEOGRAPH + 0xAC5C: 0x741D, //CJK UNIFIED IDEOGRAPH + 0xAC5D: 0x741E, //CJK UNIFIED IDEOGRAPH + 0xAC5E: 0x741F, //CJK UNIFIED IDEOGRAPH + 0xAC5F: 0x7420, //CJK UNIFIED IDEOGRAPH + 0xAC60: 0x7421, //CJK UNIFIED IDEOGRAPH + 0xAC61: 0x7423, //CJK UNIFIED IDEOGRAPH + 0xAC62: 0x7424, //CJK UNIFIED IDEOGRAPH + 0xAC63: 0x7427, //CJK UNIFIED IDEOGRAPH + 0xAC64: 0x7429, //CJK UNIFIED IDEOGRAPH + 0xAC65: 0x742B, //CJK UNIFIED IDEOGRAPH + 0xAC66: 0x742D, //CJK UNIFIED IDEOGRAPH + 0xAC67: 0x742F, //CJK UNIFIED IDEOGRAPH + 0xAC68: 0x7431, //CJK UNIFIED IDEOGRAPH + 0xAC69: 0x7432, //CJK UNIFIED IDEOGRAPH + 0xAC6A: 0x7437, //CJK UNIFIED IDEOGRAPH + 0xAC6B: 0x7438, //CJK UNIFIED IDEOGRAPH + 0xAC6C: 0x7439, //CJK UNIFIED IDEOGRAPH + 0xAC6D: 0x743A, //CJK UNIFIED IDEOGRAPH + 0xAC6E: 0x743B, //CJK UNIFIED IDEOGRAPH + 0xAC6F: 0x743D, //CJK UNIFIED IDEOGRAPH + 0xAC70: 0x743E, //CJK UNIFIED IDEOGRAPH + 0xAC71: 0x743F, //CJK UNIFIED IDEOGRAPH + 0xAC72: 0x7440, //CJK UNIFIED IDEOGRAPH + 0xAC73: 0x7442, //CJK UNIFIED IDEOGRAPH + 0xAC74: 0x7443, //CJK UNIFIED IDEOGRAPH + 0xAC75: 0x7444, //CJK UNIFIED IDEOGRAPH + 0xAC76: 0x7445, //CJK UNIFIED IDEOGRAPH + 0xAC77: 0x7446, //CJK UNIFIED IDEOGRAPH + 0xAC78: 0x7447, //CJK UNIFIED IDEOGRAPH + 0xAC79: 0x7448, //CJK UNIFIED IDEOGRAPH + 0xAC7A: 0x7449, //CJK UNIFIED IDEOGRAPH + 0xAC7B: 0x744A, //CJK UNIFIED IDEOGRAPH + 0xAC7C: 0x744B, //CJK UNIFIED IDEOGRAPH + 0xAC7D: 0x744C, //CJK UNIFIED IDEOGRAPH + 0xAC7E: 0x744D, //CJK UNIFIED IDEOGRAPH + 0xAC80: 0x744E, //CJK UNIFIED IDEOGRAPH + 0xAC81: 0x744F, //CJK UNIFIED IDEOGRAPH + 0xAC82: 0x7450, //CJK UNIFIED IDEOGRAPH + 0xAC83: 0x7451, //CJK UNIFIED IDEOGRAPH + 0xAC84: 0x7452, //CJK UNIFIED IDEOGRAPH + 0xAC85: 0x7453, //CJK UNIFIED IDEOGRAPH + 0xAC86: 0x7454, //CJK UNIFIED IDEOGRAPH + 0xAC87: 0x7456, //CJK UNIFIED IDEOGRAPH + 0xAC88: 0x7458, //CJK UNIFIED IDEOGRAPH + 0xAC89: 0x745D, //CJK UNIFIED IDEOGRAPH + 0xAC8A: 0x7460, //CJK UNIFIED IDEOGRAPH + 0xAC8B: 0x7461, //CJK UNIFIED IDEOGRAPH + 0xAC8C: 0x7462, //CJK UNIFIED IDEOGRAPH + 0xAC8D: 0x7463, //CJK UNIFIED IDEOGRAPH + 0xAC8E: 0x7464, //CJK UNIFIED IDEOGRAPH + 0xAC8F: 0x7465, //CJK UNIFIED IDEOGRAPH + 0xAC90: 0x7466, //CJK UNIFIED IDEOGRAPH + 0xAC91: 0x7467, //CJK UNIFIED IDEOGRAPH + 0xAC92: 0x7468, //CJK UNIFIED IDEOGRAPH + 0xAC93: 0x7469, //CJK UNIFIED IDEOGRAPH + 0xAC94: 0x746A, //CJK UNIFIED IDEOGRAPH + 0xAC95: 0x746B, //CJK UNIFIED IDEOGRAPH + 0xAC96: 0x746C, //CJK UNIFIED IDEOGRAPH + 0xAC97: 0x746E, //CJK UNIFIED IDEOGRAPH + 0xAC98: 0x746F, //CJK UNIFIED IDEOGRAPH + 0xAC99: 0x7471, //CJK UNIFIED IDEOGRAPH + 0xAC9A: 0x7472, //CJK UNIFIED IDEOGRAPH + 0xAC9B: 0x7473, //CJK UNIFIED IDEOGRAPH + 0xAC9C: 0x7474, //CJK UNIFIED IDEOGRAPH + 0xAC9D: 0x7475, //CJK UNIFIED IDEOGRAPH + 0xAC9E: 0x7478, //CJK UNIFIED IDEOGRAPH + 0xAC9F: 0x7479, //CJK UNIFIED IDEOGRAPH + 0xACA0: 0x747A, //CJK UNIFIED IDEOGRAPH + 0xAD40: 0x747B, //CJK UNIFIED IDEOGRAPH + 0xAD41: 0x747C, //CJK UNIFIED IDEOGRAPH + 0xAD42: 0x747D, //CJK UNIFIED IDEOGRAPH + 0xAD43: 0x747F, //CJK UNIFIED IDEOGRAPH + 0xAD44: 0x7482, //CJK UNIFIED IDEOGRAPH + 0xAD45: 0x7484, //CJK UNIFIED IDEOGRAPH + 0xAD46: 0x7485, //CJK UNIFIED IDEOGRAPH + 0xAD47: 0x7486, //CJK UNIFIED IDEOGRAPH + 0xAD48: 0x7488, //CJK UNIFIED IDEOGRAPH + 0xAD49: 0x7489, //CJK UNIFIED IDEOGRAPH + 0xAD4A: 0x748A, //CJK UNIFIED IDEOGRAPH + 0xAD4B: 0x748C, //CJK UNIFIED IDEOGRAPH + 0xAD4C: 0x748D, //CJK UNIFIED IDEOGRAPH + 0xAD4D: 0x748F, //CJK UNIFIED IDEOGRAPH + 0xAD4E: 0x7491, //CJK UNIFIED IDEOGRAPH + 0xAD4F: 0x7492, //CJK UNIFIED IDEOGRAPH + 0xAD50: 0x7493, //CJK UNIFIED IDEOGRAPH + 0xAD51: 0x7494, //CJK UNIFIED IDEOGRAPH + 0xAD52: 0x7495, //CJK UNIFIED IDEOGRAPH + 0xAD53: 0x7496, //CJK UNIFIED IDEOGRAPH + 0xAD54: 0x7497, //CJK UNIFIED IDEOGRAPH + 0xAD55: 0x7498, //CJK UNIFIED IDEOGRAPH + 0xAD56: 0x7499, //CJK UNIFIED IDEOGRAPH + 0xAD57: 0x749A, //CJK UNIFIED IDEOGRAPH + 0xAD58: 0x749B, //CJK UNIFIED IDEOGRAPH + 0xAD59: 0x749D, //CJK UNIFIED IDEOGRAPH + 0xAD5A: 0x749F, //CJK UNIFIED IDEOGRAPH + 0xAD5B: 0x74A0, //CJK UNIFIED IDEOGRAPH + 0xAD5C: 0x74A1, //CJK UNIFIED IDEOGRAPH + 0xAD5D: 0x74A2, //CJK UNIFIED IDEOGRAPH + 0xAD5E: 0x74A3, //CJK UNIFIED IDEOGRAPH + 0xAD5F: 0x74A4, //CJK UNIFIED IDEOGRAPH + 0xAD60: 0x74A5, //CJK UNIFIED IDEOGRAPH + 0xAD61: 0x74A6, //CJK UNIFIED IDEOGRAPH + 0xAD62: 0x74AA, //CJK UNIFIED IDEOGRAPH + 0xAD63: 0x74AB, //CJK UNIFIED IDEOGRAPH + 0xAD64: 0x74AC, //CJK UNIFIED IDEOGRAPH + 0xAD65: 0x74AD, //CJK UNIFIED IDEOGRAPH + 0xAD66: 0x74AE, //CJK UNIFIED IDEOGRAPH + 0xAD67: 0x74AF, //CJK UNIFIED IDEOGRAPH + 0xAD68: 0x74B0, //CJK UNIFIED IDEOGRAPH + 0xAD69: 0x74B1, //CJK UNIFIED IDEOGRAPH + 0xAD6A: 0x74B2, //CJK UNIFIED IDEOGRAPH + 0xAD6B: 0x74B3, //CJK UNIFIED IDEOGRAPH + 0xAD6C: 0x74B4, //CJK UNIFIED IDEOGRAPH + 0xAD6D: 0x74B5, //CJK UNIFIED IDEOGRAPH + 0xAD6E: 0x74B6, //CJK UNIFIED IDEOGRAPH + 0xAD6F: 0x74B7, //CJK UNIFIED IDEOGRAPH + 0xAD70: 0x74B8, //CJK UNIFIED IDEOGRAPH + 0xAD71: 0x74B9, //CJK UNIFIED IDEOGRAPH + 0xAD72: 0x74BB, //CJK UNIFIED IDEOGRAPH + 0xAD73: 0x74BC, //CJK UNIFIED IDEOGRAPH + 0xAD74: 0x74BD, //CJK UNIFIED IDEOGRAPH + 0xAD75: 0x74BE, //CJK UNIFIED IDEOGRAPH + 0xAD76: 0x74BF, //CJK UNIFIED IDEOGRAPH + 0xAD77: 0x74C0, //CJK UNIFIED IDEOGRAPH + 0xAD78: 0x74C1, //CJK UNIFIED IDEOGRAPH + 0xAD79: 0x74C2, //CJK UNIFIED IDEOGRAPH + 0xAD7A: 0x74C3, //CJK UNIFIED IDEOGRAPH + 0xAD7B: 0x74C4, //CJK UNIFIED IDEOGRAPH + 0xAD7C: 0x74C5, //CJK UNIFIED IDEOGRAPH + 0xAD7D: 0x74C6, //CJK UNIFIED IDEOGRAPH + 0xAD7E: 0x74C7, //CJK UNIFIED IDEOGRAPH + 0xAD80: 0x74C8, //CJK UNIFIED IDEOGRAPH + 0xAD81: 0x74C9, //CJK UNIFIED IDEOGRAPH + 0xAD82: 0x74CA, //CJK UNIFIED IDEOGRAPH + 0xAD83: 0x74CB, //CJK UNIFIED IDEOGRAPH + 0xAD84: 0x74CC, //CJK UNIFIED IDEOGRAPH + 0xAD85: 0x74CD, //CJK UNIFIED IDEOGRAPH + 0xAD86: 0x74CE, //CJK UNIFIED IDEOGRAPH + 0xAD87: 0x74CF, //CJK UNIFIED IDEOGRAPH + 0xAD88: 0x74D0, //CJK UNIFIED IDEOGRAPH + 0xAD89: 0x74D1, //CJK UNIFIED IDEOGRAPH + 0xAD8A: 0x74D3, //CJK UNIFIED IDEOGRAPH + 0xAD8B: 0x74D4, //CJK UNIFIED IDEOGRAPH + 0xAD8C: 0x74D5, //CJK UNIFIED IDEOGRAPH + 0xAD8D: 0x74D6, //CJK UNIFIED IDEOGRAPH + 0xAD8E: 0x74D7, //CJK UNIFIED IDEOGRAPH + 0xAD8F: 0x74D8, //CJK UNIFIED IDEOGRAPH + 0xAD90: 0x74D9, //CJK UNIFIED IDEOGRAPH + 0xAD91: 0x74DA, //CJK UNIFIED IDEOGRAPH + 0xAD92: 0x74DB, //CJK UNIFIED IDEOGRAPH + 0xAD93: 0x74DD, //CJK UNIFIED IDEOGRAPH + 0xAD94: 0x74DF, //CJK UNIFIED IDEOGRAPH + 0xAD95: 0x74E1, //CJK UNIFIED IDEOGRAPH + 0xAD96: 0x74E5, //CJK UNIFIED IDEOGRAPH + 0xAD97: 0x74E7, //CJK UNIFIED IDEOGRAPH + 0xAD98: 0x74E8, //CJK UNIFIED IDEOGRAPH + 0xAD99: 0x74E9, //CJK UNIFIED IDEOGRAPH + 0xAD9A: 0x74EA, //CJK UNIFIED IDEOGRAPH + 0xAD9B: 0x74EB, //CJK UNIFIED IDEOGRAPH + 0xAD9C: 0x74EC, //CJK UNIFIED IDEOGRAPH + 0xAD9D: 0x74ED, //CJK UNIFIED IDEOGRAPH + 0xAD9E: 0x74F0, //CJK UNIFIED IDEOGRAPH + 0xAD9F: 0x74F1, //CJK UNIFIED IDEOGRAPH + 0xADA0: 0x74F2, //CJK UNIFIED IDEOGRAPH + 0xAE40: 0x74F3, //CJK UNIFIED IDEOGRAPH + 0xAE41: 0x74F5, //CJK UNIFIED IDEOGRAPH + 0xAE42: 0x74F8, //CJK UNIFIED IDEOGRAPH + 0xAE43: 0x74F9, //CJK UNIFIED IDEOGRAPH + 0xAE44: 0x74FA, //CJK UNIFIED IDEOGRAPH + 0xAE45: 0x74FB, //CJK UNIFIED IDEOGRAPH + 0xAE46: 0x74FC, //CJK UNIFIED IDEOGRAPH + 0xAE47: 0x74FD, //CJK UNIFIED IDEOGRAPH + 0xAE48: 0x74FE, //CJK UNIFIED IDEOGRAPH + 0xAE49: 0x7500, //CJK UNIFIED IDEOGRAPH + 0xAE4A: 0x7501, //CJK UNIFIED IDEOGRAPH + 0xAE4B: 0x7502, //CJK UNIFIED IDEOGRAPH + 0xAE4C: 0x7503, //CJK UNIFIED IDEOGRAPH + 0xAE4D: 0x7505, //CJK UNIFIED IDEOGRAPH + 0xAE4E: 0x7506, //CJK UNIFIED IDEOGRAPH + 0xAE4F: 0x7507, //CJK UNIFIED IDEOGRAPH + 0xAE50: 0x7508, //CJK UNIFIED IDEOGRAPH + 0xAE51: 0x7509, //CJK UNIFIED IDEOGRAPH + 0xAE52: 0x750A, //CJK UNIFIED IDEOGRAPH + 0xAE53: 0x750B, //CJK UNIFIED IDEOGRAPH + 0xAE54: 0x750C, //CJK UNIFIED IDEOGRAPH + 0xAE55: 0x750E, //CJK UNIFIED IDEOGRAPH + 0xAE56: 0x7510, //CJK UNIFIED IDEOGRAPH + 0xAE57: 0x7512, //CJK UNIFIED IDEOGRAPH + 0xAE58: 0x7514, //CJK UNIFIED IDEOGRAPH + 0xAE59: 0x7515, //CJK UNIFIED IDEOGRAPH + 0xAE5A: 0x7516, //CJK UNIFIED IDEOGRAPH + 0xAE5B: 0x7517, //CJK UNIFIED IDEOGRAPH + 0xAE5C: 0x751B, //CJK UNIFIED IDEOGRAPH + 0xAE5D: 0x751D, //CJK UNIFIED IDEOGRAPH + 0xAE5E: 0x751E, //CJK UNIFIED IDEOGRAPH + 0xAE5F: 0x7520, //CJK UNIFIED IDEOGRAPH + 0xAE60: 0x7521, //CJK UNIFIED IDEOGRAPH + 0xAE61: 0x7522, //CJK UNIFIED IDEOGRAPH + 0xAE62: 0x7523, //CJK UNIFIED IDEOGRAPH + 0xAE63: 0x7524, //CJK UNIFIED IDEOGRAPH + 0xAE64: 0x7526, //CJK UNIFIED IDEOGRAPH + 0xAE65: 0x7527, //CJK UNIFIED IDEOGRAPH + 0xAE66: 0x752A, //CJK UNIFIED IDEOGRAPH + 0xAE67: 0x752E, //CJK UNIFIED IDEOGRAPH + 0xAE68: 0x7534, //CJK UNIFIED IDEOGRAPH + 0xAE69: 0x7536, //CJK UNIFIED IDEOGRAPH + 0xAE6A: 0x7539, //CJK UNIFIED IDEOGRAPH + 0xAE6B: 0x753C, //CJK UNIFIED IDEOGRAPH + 0xAE6C: 0x753D, //CJK UNIFIED IDEOGRAPH + 0xAE6D: 0x753F, //CJK UNIFIED IDEOGRAPH + 0xAE6E: 0x7541, //CJK UNIFIED IDEOGRAPH + 0xAE6F: 0x7542, //CJK UNIFIED IDEOGRAPH + 0xAE70: 0x7543, //CJK UNIFIED IDEOGRAPH + 0xAE71: 0x7544, //CJK UNIFIED IDEOGRAPH + 0xAE72: 0x7546, //CJK UNIFIED IDEOGRAPH + 0xAE73: 0x7547, //CJK UNIFIED IDEOGRAPH + 0xAE74: 0x7549, //CJK UNIFIED IDEOGRAPH + 0xAE75: 0x754A, //CJK UNIFIED IDEOGRAPH + 0xAE76: 0x754D, //CJK UNIFIED IDEOGRAPH + 0xAE77: 0x7550, //CJK UNIFIED IDEOGRAPH + 0xAE78: 0x7551, //CJK UNIFIED IDEOGRAPH + 0xAE79: 0x7552, //CJK UNIFIED IDEOGRAPH + 0xAE7A: 0x7553, //CJK UNIFIED IDEOGRAPH + 0xAE7B: 0x7555, //CJK UNIFIED IDEOGRAPH + 0xAE7C: 0x7556, //CJK UNIFIED IDEOGRAPH + 0xAE7D: 0x7557, //CJK UNIFIED IDEOGRAPH + 0xAE7E: 0x7558, //CJK UNIFIED IDEOGRAPH + 0xAE80: 0x755D, //CJK UNIFIED IDEOGRAPH + 0xAE81: 0x755E, //CJK UNIFIED IDEOGRAPH + 0xAE82: 0x755F, //CJK UNIFIED IDEOGRAPH + 0xAE83: 0x7560, //CJK UNIFIED IDEOGRAPH + 0xAE84: 0x7561, //CJK UNIFIED IDEOGRAPH + 0xAE85: 0x7562, //CJK UNIFIED IDEOGRAPH + 0xAE86: 0x7563, //CJK UNIFIED IDEOGRAPH + 0xAE87: 0x7564, //CJK UNIFIED IDEOGRAPH + 0xAE88: 0x7567, //CJK UNIFIED IDEOGRAPH + 0xAE89: 0x7568, //CJK UNIFIED IDEOGRAPH + 0xAE8A: 0x7569, //CJK UNIFIED IDEOGRAPH + 0xAE8B: 0x756B, //CJK UNIFIED IDEOGRAPH + 0xAE8C: 0x756C, //CJK UNIFIED IDEOGRAPH + 0xAE8D: 0x756D, //CJK UNIFIED IDEOGRAPH + 0xAE8E: 0x756E, //CJK UNIFIED IDEOGRAPH + 0xAE8F: 0x756F, //CJK UNIFIED IDEOGRAPH + 0xAE90: 0x7570, //CJK UNIFIED IDEOGRAPH + 0xAE91: 0x7571, //CJK UNIFIED IDEOGRAPH + 0xAE92: 0x7573, //CJK UNIFIED IDEOGRAPH + 0xAE93: 0x7575, //CJK UNIFIED IDEOGRAPH + 0xAE94: 0x7576, //CJK UNIFIED IDEOGRAPH + 0xAE95: 0x7577, //CJK UNIFIED IDEOGRAPH + 0xAE96: 0x757A, //CJK UNIFIED IDEOGRAPH + 0xAE97: 0x757B, //CJK UNIFIED IDEOGRAPH + 0xAE98: 0x757C, //CJK UNIFIED IDEOGRAPH + 0xAE99: 0x757D, //CJK UNIFIED IDEOGRAPH + 0xAE9A: 0x757E, //CJK UNIFIED IDEOGRAPH + 0xAE9B: 0x7580, //CJK UNIFIED IDEOGRAPH + 0xAE9C: 0x7581, //CJK UNIFIED IDEOGRAPH + 0xAE9D: 0x7582, //CJK UNIFIED IDEOGRAPH + 0xAE9E: 0x7584, //CJK UNIFIED IDEOGRAPH + 0xAE9F: 0x7585, //CJK UNIFIED IDEOGRAPH + 0xAEA0: 0x7587, //CJK UNIFIED IDEOGRAPH + 0xAF40: 0x7588, //CJK UNIFIED IDEOGRAPH + 0xAF41: 0x7589, //CJK UNIFIED IDEOGRAPH + 0xAF42: 0x758A, //CJK UNIFIED IDEOGRAPH + 0xAF43: 0x758C, //CJK UNIFIED IDEOGRAPH + 0xAF44: 0x758D, //CJK UNIFIED IDEOGRAPH + 0xAF45: 0x758E, //CJK UNIFIED IDEOGRAPH + 0xAF46: 0x7590, //CJK UNIFIED IDEOGRAPH + 0xAF47: 0x7593, //CJK UNIFIED IDEOGRAPH + 0xAF48: 0x7595, //CJK UNIFIED IDEOGRAPH + 0xAF49: 0x7598, //CJK UNIFIED IDEOGRAPH + 0xAF4A: 0x759B, //CJK UNIFIED IDEOGRAPH + 0xAF4B: 0x759C, //CJK UNIFIED IDEOGRAPH + 0xAF4C: 0x759E, //CJK UNIFIED IDEOGRAPH + 0xAF4D: 0x75A2, //CJK UNIFIED IDEOGRAPH + 0xAF4E: 0x75A6, //CJK UNIFIED IDEOGRAPH + 0xAF4F: 0x75A7, //CJK UNIFIED IDEOGRAPH + 0xAF50: 0x75A8, //CJK UNIFIED IDEOGRAPH + 0xAF51: 0x75A9, //CJK UNIFIED IDEOGRAPH + 0xAF52: 0x75AA, //CJK UNIFIED IDEOGRAPH + 0xAF53: 0x75AD, //CJK UNIFIED IDEOGRAPH + 0xAF54: 0x75B6, //CJK UNIFIED IDEOGRAPH + 0xAF55: 0x75B7, //CJK UNIFIED IDEOGRAPH + 0xAF56: 0x75BA, //CJK UNIFIED IDEOGRAPH + 0xAF57: 0x75BB, //CJK UNIFIED IDEOGRAPH + 0xAF58: 0x75BF, //CJK UNIFIED IDEOGRAPH + 0xAF59: 0x75C0, //CJK UNIFIED IDEOGRAPH + 0xAF5A: 0x75C1, //CJK UNIFIED IDEOGRAPH + 0xAF5B: 0x75C6, //CJK UNIFIED IDEOGRAPH + 0xAF5C: 0x75CB, //CJK UNIFIED IDEOGRAPH + 0xAF5D: 0x75CC, //CJK UNIFIED IDEOGRAPH + 0xAF5E: 0x75CE, //CJK UNIFIED IDEOGRAPH + 0xAF5F: 0x75CF, //CJK UNIFIED IDEOGRAPH + 0xAF60: 0x75D0, //CJK UNIFIED IDEOGRAPH + 0xAF61: 0x75D1, //CJK UNIFIED IDEOGRAPH + 0xAF62: 0x75D3, //CJK UNIFIED IDEOGRAPH + 0xAF63: 0x75D7, //CJK UNIFIED IDEOGRAPH + 0xAF64: 0x75D9, //CJK UNIFIED IDEOGRAPH + 0xAF65: 0x75DA, //CJK UNIFIED IDEOGRAPH + 0xAF66: 0x75DC, //CJK UNIFIED IDEOGRAPH + 0xAF67: 0x75DD, //CJK UNIFIED IDEOGRAPH + 0xAF68: 0x75DF, //CJK UNIFIED IDEOGRAPH + 0xAF69: 0x75E0, //CJK UNIFIED IDEOGRAPH + 0xAF6A: 0x75E1, //CJK UNIFIED IDEOGRAPH + 0xAF6B: 0x75E5, //CJK UNIFIED IDEOGRAPH + 0xAF6C: 0x75E9, //CJK UNIFIED IDEOGRAPH + 0xAF6D: 0x75EC, //CJK UNIFIED IDEOGRAPH + 0xAF6E: 0x75ED, //CJK UNIFIED IDEOGRAPH + 0xAF6F: 0x75EE, //CJK UNIFIED IDEOGRAPH + 0xAF70: 0x75EF, //CJK UNIFIED IDEOGRAPH + 0xAF71: 0x75F2, //CJK UNIFIED IDEOGRAPH + 0xAF72: 0x75F3, //CJK UNIFIED IDEOGRAPH + 0xAF73: 0x75F5, //CJK UNIFIED IDEOGRAPH + 0xAF74: 0x75F6, //CJK UNIFIED IDEOGRAPH + 0xAF75: 0x75F7, //CJK UNIFIED IDEOGRAPH + 0xAF76: 0x75F8, //CJK UNIFIED IDEOGRAPH + 0xAF77: 0x75FA, //CJK UNIFIED IDEOGRAPH + 0xAF78: 0x75FB, //CJK UNIFIED IDEOGRAPH + 0xAF79: 0x75FD, //CJK UNIFIED IDEOGRAPH + 0xAF7A: 0x75FE, //CJK UNIFIED IDEOGRAPH + 0xAF7B: 0x7602, //CJK UNIFIED IDEOGRAPH + 0xAF7C: 0x7604, //CJK UNIFIED IDEOGRAPH + 0xAF7D: 0x7606, //CJK UNIFIED IDEOGRAPH + 0xAF7E: 0x7607, //CJK UNIFIED IDEOGRAPH + 0xAF80: 0x7608, //CJK UNIFIED IDEOGRAPH + 0xAF81: 0x7609, //CJK UNIFIED IDEOGRAPH + 0xAF82: 0x760B, //CJK UNIFIED IDEOGRAPH + 0xAF83: 0x760D, //CJK UNIFIED IDEOGRAPH + 0xAF84: 0x760E, //CJK UNIFIED IDEOGRAPH + 0xAF85: 0x760F, //CJK UNIFIED IDEOGRAPH + 0xAF86: 0x7611, //CJK UNIFIED IDEOGRAPH + 0xAF87: 0x7612, //CJK UNIFIED IDEOGRAPH + 0xAF88: 0x7613, //CJK UNIFIED IDEOGRAPH + 0xAF89: 0x7614, //CJK UNIFIED IDEOGRAPH + 0xAF8A: 0x7616, //CJK UNIFIED IDEOGRAPH + 0xAF8B: 0x761A, //CJK UNIFIED IDEOGRAPH + 0xAF8C: 0x761C, //CJK UNIFIED IDEOGRAPH + 0xAF8D: 0x761D, //CJK UNIFIED IDEOGRAPH + 0xAF8E: 0x761E, //CJK UNIFIED IDEOGRAPH + 0xAF8F: 0x7621, //CJK UNIFIED IDEOGRAPH + 0xAF90: 0x7623, //CJK UNIFIED IDEOGRAPH + 0xAF91: 0x7627, //CJK UNIFIED IDEOGRAPH + 0xAF92: 0x7628, //CJK UNIFIED IDEOGRAPH + 0xAF93: 0x762C, //CJK UNIFIED IDEOGRAPH + 0xAF94: 0x762E, //CJK UNIFIED IDEOGRAPH + 0xAF95: 0x762F, //CJK UNIFIED IDEOGRAPH + 0xAF96: 0x7631, //CJK UNIFIED IDEOGRAPH + 0xAF97: 0x7632, //CJK UNIFIED IDEOGRAPH + 0xAF98: 0x7636, //CJK UNIFIED IDEOGRAPH + 0xAF99: 0x7637, //CJK UNIFIED IDEOGRAPH + 0xAF9A: 0x7639, //CJK UNIFIED IDEOGRAPH + 0xAF9B: 0x763A, //CJK UNIFIED IDEOGRAPH + 0xAF9C: 0x763B, //CJK UNIFIED IDEOGRAPH + 0xAF9D: 0x763D, //CJK UNIFIED IDEOGRAPH + 0xAF9E: 0x7641, //CJK UNIFIED IDEOGRAPH + 0xAF9F: 0x7642, //CJK UNIFIED IDEOGRAPH + 0xAFA0: 0x7644, //CJK UNIFIED IDEOGRAPH + 0xB040: 0x7645, //CJK UNIFIED IDEOGRAPH + 0xB041: 0x7646, //CJK UNIFIED IDEOGRAPH + 0xB042: 0x7647, //CJK UNIFIED IDEOGRAPH + 0xB043: 0x7648, //CJK UNIFIED IDEOGRAPH + 0xB044: 0x7649, //CJK UNIFIED IDEOGRAPH + 0xB045: 0x764A, //CJK UNIFIED IDEOGRAPH + 0xB046: 0x764B, //CJK UNIFIED IDEOGRAPH + 0xB047: 0x764E, //CJK UNIFIED IDEOGRAPH + 0xB048: 0x764F, //CJK UNIFIED IDEOGRAPH + 0xB049: 0x7650, //CJK UNIFIED IDEOGRAPH + 0xB04A: 0x7651, //CJK UNIFIED IDEOGRAPH + 0xB04B: 0x7652, //CJK UNIFIED IDEOGRAPH + 0xB04C: 0x7653, //CJK UNIFIED IDEOGRAPH + 0xB04D: 0x7655, //CJK UNIFIED IDEOGRAPH + 0xB04E: 0x7657, //CJK UNIFIED IDEOGRAPH + 0xB04F: 0x7658, //CJK UNIFIED IDEOGRAPH + 0xB050: 0x7659, //CJK UNIFIED IDEOGRAPH + 0xB051: 0x765A, //CJK UNIFIED IDEOGRAPH + 0xB052: 0x765B, //CJK UNIFIED IDEOGRAPH + 0xB053: 0x765D, //CJK UNIFIED IDEOGRAPH + 0xB054: 0x765F, //CJK UNIFIED IDEOGRAPH + 0xB055: 0x7660, //CJK UNIFIED IDEOGRAPH + 0xB056: 0x7661, //CJK UNIFIED IDEOGRAPH + 0xB057: 0x7662, //CJK UNIFIED IDEOGRAPH + 0xB058: 0x7664, //CJK UNIFIED IDEOGRAPH + 0xB059: 0x7665, //CJK UNIFIED IDEOGRAPH + 0xB05A: 0x7666, //CJK UNIFIED IDEOGRAPH + 0xB05B: 0x7667, //CJK UNIFIED IDEOGRAPH + 0xB05C: 0x7668, //CJK UNIFIED IDEOGRAPH + 0xB05D: 0x7669, //CJK UNIFIED IDEOGRAPH + 0xB05E: 0x766A, //CJK UNIFIED IDEOGRAPH + 0xB05F: 0x766C, //CJK UNIFIED IDEOGRAPH + 0xB060: 0x766D, //CJK UNIFIED IDEOGRAPH + 0xB061: 0x766E, //CJK UNIFIED IDEOGRAPH + 0xB062: 0x7670, //CJK UNIFIED IDEOGRAPH + 0xB063: 0x7671, //CJK UNIFIED IDEOGRAPH + 0xB064: 0x7672, //CJK UNIFIED IDEOGRAPH + 0xB065: 0x7673, //CJK UNIFIED IDEOGRAPH + 0xB066: 0x7674, //CJK UNIFIED IDEOGRAPH + 0xB067: 0x7675, //CJK UNIFIED IDEOGRAPH + 0xB068: 0x7676, //CJK UNIFIED IDEOGRAPH + 0xB069: 0x7677, //CJK UNIFIED IDEOGRAPH + 0xB06A: 0x7679, //CJK UNIFIED IDEOGRAPH + 0xB06B: 0x767A, //CJK UNIFIED IDEOGRAPH + 0xB06C: 0x767C, //CJK UNIFIED IDEOGRAPH + 0xB06D: 0x767F, //CJK UNIFIED IDEOGRAPH + 0xB06E: 0x7680, //CJK UNIFIED IDEOGRAPH + 0xB06F: 0x7681, //CJK UNIFIED IDEOGRAPH + 0xB070: 0x7683, //CJK UNIFIED IDEOGRAPH + 0xB071: 0x7685, //CJK UNIFIED IDEOGRAPH + 0xB072: 0x7689, //CJK UNIFIED IDEOGRAPH + 0xB073: 0x768A, //CJK UNIFIED IDEOGRAPH + 0xB074: 0x768C, //CJK UNIFIED IDEOGRAPH + 0xB075: 0x768D, //CJK UNIFIED IDEOGRAPH + 0xB076: 0x768F, //CJK UNIFIED IDEOGRAPH + 0xB077: 0x7690, //CJK UNIFIED IDEOGRAPH + 0xB078: 0x7692, //CJK UNIFIED IDEOGRAPH + 0xB079: 0x7694, //CJK UNIFIED IDEOGRAPH + 0xB07A: 0x7695, //CJK UNIFIED IDEOGRAPH + 0xB07B: 0x7697, //CJK UNIFIED IDEOGRAPH + 0xB07C: 0x7698, //CJK UNIFIED IDEOGRAPH + 0xB07D: 0x769A, //CJK UNIFIED IDEOGRAPH + 0xB07E: 0x769B, //CJK UNIFIED IDEOGRAPH + 0xB080: 0x769C, //CJK UNIFIED IDEOGRAPH + 0xB081: 0x769D, //CJK UNIFIED IDEOGRAPH + 0xB082: 0x769E, //CJK UNIFIED IDEOGRAPH + 0xB083: 0x769F, //CJK UNIFIED IDEOGRAPH + 0xB084: 0x76A0, //CJK UNIFIED IDEOGRAPH + 0xB085: 0x76A1, //CJK UNIFIED IDEOGRAPH + 0xB086: 0x76A2, //CJK UNIFIED IDEOGRAPH + 0xB087: 0x76A3, //CJK UNIFIED IDEOGRAPH + 0xB088: 0x76A5, //CJK UNIFIED IDEOGRAPH + 0xB089: 0x76A6, //CJK UNIFIED IDEOGRAPH + 0xB08A: 0x76A7, //CJK UNIFIED IDEOGRAPH + 0xB08B: 0x76A8, //CJK UNIFIED IDEOGRAPH + 0xB08C: 0x76A9, //CJK UNIFIED IDEOGRAPH + 0xB08D: 0x76AA, //CJK UNIFIED IDEOGRAPH + 0xB08E: 0x76AB, //CJK UNIFIED IDEOGRAPH + 0xB08F: 0x76AC, //CJK UNIFIED IDEOGRAPH + 0xB090: 0x76AD, //CJK UNIFIED IDEOGRAPH + 0xB091: 0x76AF, //CJK UNIFIED IDEOGRAPH + 0xB092: 0x76B0, //CJK UNIFIED IDEOGRAPH + 0xB093: 0x76B3, //CJK UNIFIED IDEOGRAPH + 0xB094: 0x76B5, //CJK UNIFIED IDEOGRAPH + 0xB095: 0x76B6, //CJK UNIFIED IDEOGRAPH + 0xB096: 0x76B7, //CJK UNIFIED IDEOGRAPH + 0xB097: 0x76B8, //CJK UNIFIED IDEOGRAPH + 0xB098: 0x76B9, //CJK UNIFIED IDEOGRAPH + 0xB099: 0x76BA, //CJK UNIFIED IDEOGRAPH + 0xB09A: 0x76BB, //CJK UNIFIED IDEOGRAPH + 0xB09B: 0x76BC, //CJK UNIFIED IDEOGRAPH + 0xB09C: 0x76BD, //CJK UNIFIED IDEOGRAPH + 0xB09D: 0x76BE, //CJK UNIFIED IDEOGRAPH + 0xB09E: 0x76C0, //CJK UNIFIED IDEOGRAPH + 0xB09F: 0x76C1, //CJK UNIFIED IDEOGRAPH + 0xB0A0: 0x76C3, //CJK UNIFIED IDEOGRAPH + 0xB0A1: 0x554A, //CJK UNIFIED IDEOGRAPH + 0xB0A2: 0x963F, //CJK UNIFIED IDEOGRAPH + 0xB0A3: 0x57C3, //CJK UNIFIED IDEOGRAPH + 0xB0A4: 0x6328, //CJK UNIFIED IDEOGRAPH + 0xB0A5: 0x54CE, //CJK UNIFIED IDEOGRAPH + 0xB0A6: 0x5509, //CJK UNIFIED IDEOGRAPH + 0xB0A7: 0x54C0, //CJK UNIFIED IDEOGRAPH + 0xB0A8: 0x7691, //CJK UNIFIED IDEOGRAPH + 0xB0A9: 0x764C, //CJK UNIFIED IDEOGRAPH + 0xB0AA: 0x853C, //CJK UNIFIED IDEOGRAPH + 0xB0AB: 0x77EE, //CJK UNIFIED IDEOGRAPH + 0xB0AC: 0x827E, //CJK UNIFIED IDEOGRAPH + 0xB0AD: 0x788D, //CJK UNIFIED IDEOGRAPH + 0xB0AE: 0x7231, //CJK UNIFIED IDEOGRAPH + 0xB0AF: 0x9698, //CJK UNIFIED IDEOGRAPH + 0xB0B0: 0x978D, //CJK UNIFIED IDEOGRAPH + 0xB0B1: 0x6C28, //CJK UNIFIED IDEOGRAPH + 0xB0B2: 0x5B89, //CJK UNIFIED IDEOGRAPH + 0xB0B3: 0x4FFA, //CJK UNIFIED IDEOGRAPH + 0xB0B4: 0x6309, //CJK UNIFIED IDEOGRAPH + 0xB0B5: 0x6697, //CJK UNIFIED IDEOGRAPH + 0xB0B6: 0x5CB8, //CJK UNIFIED IDEOGRAPH + 0xB0B7: 0x80FA, //CJK UNIFIED IDEOGRAPH + 0xB0B8: 0x6848, //CJK UNIFIED IDEOGRAPH + 0xB0B9: 0x80AE, //CJK UNIFIED IDEOGRAPH + 0xB0BA: 0x6602, //CJK UNIFIED IDEOGRAPH + 0xB0BB: 0x76CE, //CJK UNIFIED IDEOGRAPH + 0xB0BC: 0x51F9, //CJK UNIFIED IDEOGRAPH + 0xB0BD: 0x6556, //CJK UNIFIED IDEOGRAPH + 0xB0BE: 0x71AC, //CJK UNIFIED IDEOGRAPH + 0xB0BF: 0x7FF1, //CJK UNIFIED IDEOGRAPH + 0xB0C0: 0x8884, //CJK UNIFIED IDEOGRAPH + 0xB0C1: 0x50B2, //CJK UNIFIED IDEOGRAPH + 0xB0C2: 0x5965, //CJK UNIFIED IDEOGRAPH + 0xB0C3: 0x61CA, //CJK UNIFIED IDEOGRAPH + 0xB0C4: 0x6FB3, //CJK UNIFIED IDEOGRAPH + 0xB0C5: 0x82AD, //CJK UNIFIED IDEOGRAPH + 0xB0C6: 0x634C, //CJK UNIFIED IDEOGRAPH + 0xB0C7: 0x6252, //CJK UNIFIED IDEOGRAPH + 0xB0C8: 0x53ED, //CJK UNIFIED IDEOGRAPH + 0xB0C9: 0x5427, //CJK UNIFIED IDEOGRAPH + 0xB0CA: 0x7B06, //CJK UNIFIED IDEOGRAPH + 0xB0CB: 0x516B, //CJK UNIFIED IDEOGRAPH + 0xB0CC: 0x75A4, //CJK UNIFIED IDEOGRAPH + 0xB0CD: 0x5DF4, //CJK UNIFIED IDEOGRAPH + 0xB0CE: 0x62D4, //CJK UNIFIED IDEOGRAPH + 0xB0CF: 0x8DCB, //CJK UNIFIED IDEOGRAPH + 0xB0D0: 0x9776, //CJK UNIFIED IDEOGRAPH + 0xB0D1: 0x628A, //CJK UNIFIED IDEOGRAPH + 0xB0D2: 0x8019, //CJK UNIFIED IDEOGRAPH + 0xB0D3: 0x575D, //CJK UNIFIED IDEOGRAPH + 0xB0D4: 0x9738, //CJK UNIFIED IDEOGRAPH + 0xB0D5: 0x7F62, //CJK UNIFIED IDEOGRAPH + 0xB0D6: 0x7238, //CJK UNIFIED IDEOGRAPH + 0xB0D7: 0x767D, //CJK UNIFIED IDEOGRAPH + 0xB0D8: 0x67CF, //CJK UNIFIED IDEOGRAPH + 0xB0D9: 0x767E, //CJK UNIFIED IDEOGRAPH + 0xB0DA: 0x6446, //CJK UNIFIED IDEOGRAPH + 0xB0DB: 0x4F70, //CJK UNIFIED IDEOGRAPH + 0xB0DC: 0x8D25, //CJK UNIFIED IDEOGRAPH + 0xB0DD: 0x62DC, //CJK UNIFIED IDEOGRAPH + 0xB0DE: 0x7A17, //CJK UNIFIED IDEOGRAPH + 0xB0DF: 0x6591, //CJK UNIFIED IDEOGRAPH + 0xB0E0: 0x73ED, //CJK UNIFIED IDEOGRAPH + 0xB0E1: 0x642C, //CJK UNIFIED IDEOGRAPH + 0xB0E2: 0x6273, //CJK UNIFIED IDEOGRAPH + 0xB0E3: 0x822C, //CJK UNIFIED IDEOGRAPH + 0xB0E4: 0x9881, //CJK UNIFIED IDEOGRAPH + 0xB0E5: 0x677F, //CJK UNIFIED IDEOGRAPH + 0xB0E6: 0x7248, //CJK UNIFIED IDEOGRAPH + 0xB0E7: 0x626E, //CJK UNIFIED IDEOGRAPH + 0xB0E8: 0x62CC, //CJK UNIFIED IDEOGRAPH + 0xB0E9: 0x4F34, //CJK UNIFIED IDEOGRAPH + 0xB0EA: 0x74E3, //CJK UNIFIED IDEOGRAPH + 0xB0EB: 0x534A, //CJK UNIFIED IDEOGRAPH + 0xB0EC: 0x529E, //CJK UNIFIED IDEOGRAPH + 0xB0ED: 0x7ECA, //CJK UNIFIED IDEOGRAPH + 0xB0EE: 0x90A6, //CJK UNIFIED IDEOGRAPH + 0xB0EF: 0x5E2E, //CJK UNIFIED IDEOGRAPH + 0xB0F0: 0x6886, //CJK UNIFIED IDEOGRAPH + 0xB0F1: 0x699C, //CJK UNIFIED IDEOGRAPH + 0xB0F2: 0x8180, //CJK UNIFIED IDEOGRAPH + 0xB0F3: 0x7ED1, //CJK UNIFIED IDEOGRAPH + 0xB0F4: 0x68D2, //CJK UNIFIED IDEOGRAPH + 0xB0F5: 0x78C5, //CJK UNIFIED IDEOGRAPH + 0xB0F6: 0x868C, //CJK UNIFIED IDEOGRAPH + 0xB0F7: 0x9551, //CJK UNIFIED IDEOGRAPH + 0xB0F8: 0x508D, //CJK UNIFIED IDEOGRAPH + 0xB0F9: 0x8C24, //CJK UNIFIED IDEOGRAPH + 0xB0FA: 0x82DE, //CJK UNIFIED IDEOGRAPH + 0xB0FB: 0x80DE, //CJK UNIFIED IDEOGRAPH + 0xB0FC: 0x5305, //CJK UNIFIED IDEOGRAPH + 0xB0FD: 0x8912, //CJK UNIFIED IDEOGRAPH + 0xB0FE: 0x5265, //CJK UNIFIED IDEOGRAPH + 0xB140: 0x76C4, //CJK UNIFIED IDEOGRAPH + 0xB141: 0x76C7, //CJK UNIFIED IDEOGRAPH + 0xB142: 0x76C9, //CJK UNIFIED IDEOGRAPH + 0xB143: 0x76CB, //CJK UNIFIED IDEOGRAPH + 0xB144: 0x76CC, //CJK UNIFIED IDEOGRAPH + 0xB145: 0x76D3, //CJK UNIFIED IDEOGRAPH + 0xB146: 0x76D5, //CJK UNIFIED IDEOGRAPH + 0xB147: 0x76D9, //CJK UNIFIED IDEOGRAPH + 0xB148: 0x76DA, //CJK UNIFIED IDEOGRAPH + 0xB149: 0x76DC, //CJK UNIFIED IDEOGRAPH + 0xB14A: 0x76DD, //CJK UNIFIED IDEOGRAPH + 0xB14B: 0x76DE, //CJK UNIFIED IDEOGRAPH + 0xB14C: 0x76E0, //CJK UNIFIED IDEOGRAPH + 0xB14D: 0x76E1, //CJK UNIFIED IDEOGRAPH + 0xB14E: 0x76E2, //CJK UNIFIED IDEOGRAPH + 0xB14F: 0x76E3, //CJK UNIFIED IDEOGRAPH + 0xB150: 0x76E4, //CJK UNIFIED IDEOGRAPH + 0xB151: 0x76E6, //CJK UNIFIED IDEOGRAPH + 0xB152: 0x76E7, //CJK UNIFIED IDEOGRAPH + 0xB153: 0x76E8, //CJK UNIFIED IDEOGRAPH + 0xB154: 0x76E9, //CJK UNIFIED IDEOGRAPH + 0xB155: 0x76EA, //CJK UNIFIED IDEOGRAPH + 0xB156: 0x76EB, //CJK UNIFIED IDEOGRAPH + 0xB157: 0x76EC, //CJK UNIFIED IDEOGRAPH + 0xB158: 0x76ED, //CJK UNIFIED IDEOGRAPH + 0xB159: 0x76F0, //CJK UNIFIED IDEOGRAPH + 0xB15A: 0x76F3, //CJK UNIFIED IDEOGRAPH + 0xB15B: 0x76F5, //CJK UNIFIED IDEOGRAPH + 0xB15C: 0x76F6, //CJK UNIFIED IDEOGRAPH + 0xB15D: 0x76F7, //CJK UNIFIED IDEOGRAPH + 0xB15E: 0x76FA, //CJK UNIFIED IDEOGRAPH + 0xB15F: 0x76FB, //CJK UNIFIED IDEOGRAPH + 0xB160: 0x76FD, //CJK UNIFIED IDEOGRAPH + 0xB161: 0x76FF, //CJK UNIFIED IDEOGRAPH + 0xB162: 0x7700, //CJK UNIFIED IDEOGRAPH + 0xB163: 0x7702, //CJK UNIFIED IDEOGRAPH + 0xB164: 0x7703, //CJK UNIFIED IDEOGRAPH + 0xB165: 0x7705, //CJK UNIFIED IDEOGRAPH + 0xB166: 0x7706, //CJK UNIFIED IDEOGRAPH + 0xB167: 0x770A, //CJK UNIFIED IDEOGRAPH + 0xB168: 0x770C, //CJK UNIFIED IDEOGRAPH + 0xB169: 0x770E, //CJK UNIFIED IDEOGRAPH + 0xB16A: 0x770F, //CJK UNIFIED IDEOGRAPH + 0xB16B: 0x7710, //CJK UNIFIED IDEOGRAPH + 0xB16C: 0x7711, //CJK UNIFIED IDEOGRAPH + 0xB16D: 0x7712, //CJK UNIFIED IDEOGRAPH + 0xB16E: 0x7713, //CJK UNIFIED IDEOGRAPH + 0xB16F: 0x7714, //CJK UNIFIED IDEOGRAPH + 0xB170: 0x7715, //CJK UNIFIED IDEOGRAPH + 0xB171: 0x7716, //CJK UNIFIED IDEOGRAPH + 0xB172: 0x7717, //CJK UNIFIED IDEOGRAPH + 0xB173: 0x7718, //CJK UNIFIED IDEOGRAPH + 0xB174: 0x771B, //CJK UNIFIED IDEOGRAPH + 0xB175: 0x771C, //CJK UNIFIED IDEOGRAPH + 0xB176: 0x771D, //CJK UNIFIED IDEOGRAPH + 0xB177: 0x771E, //CJK UNIFIED IDEOGRAPH + 0xB178: 0x7721, //CJK UNIFIED IDEOGRAPH + 0xB179: 0x7723, //CJK UNIFIED IDEOGRAPH + 0xB17A: 0x7724, //CJK UNIFIED IDEOGRAPH + 0xB17B: 0x7725, //CJK UNIFIED IDEOGRAPH + 0xB17C: 0x7727, //CJK UNIFIED IDEOGRAPH + 0xB17D: 0x772A, //CJK UNIFIED IDEOGRAPH + 0xB17E: 0x772B, //CJK UNIFIED IDEOGRAPH + 0xB180: 0x772C, //CJK UNIFIED IDEOGRAPH + 0xB181: 0x772E, //CJK UNIFIED IDEOGRAPH + 0xB182: 0x7730, //CJK UNIFIED IDEOGRAPH + 0xB183: 0x7731, //CJK UNIFIED IDEOGRAPH + 0xB184: 0x7732, //CJK UNIFIED IDEOGRAPH + 0xB185: 0x7733, //CJK UNIFIED IDEOGRAPH + 0xB186: 0x7734, //CJK UNIFIED IDEOGRAPH + 0xB187: 0x7739, //CJK UNIFIED IDEOGRAPH + 0xB188: 0x773B, //CJK UNIFIED IDEOGRAPH + 0xB189: 0x773D, //CJK UNIFIED IDEOGRAPH + 0xB18A: 0x773E, //CJK UNIFIED IDEOGRAPH + 0xB18B: 0x773F, //CJK UNIFIED IDEOGRAPH + 0xB18C: 0x7742, //CJK UNIFIED IDEOGRAPH + 0xB18D: 0x7744, //CJK UNIFIED IDEOGRAPH + 0xB18E: 0x7745, //CJK UNIFIED IDEOGRAPH + 0xB18F: 0x7746, //CJK UNIFIED IDEOGRAPH + 0xB190: 0x7748, //CJK UNIFIED IDEOGRAPH + 0xB191: 0x7749, //CJK UNIFIED IDEOGRAPH + 0xB192: 0x774A, //CJK UNIFIED IDEOGRAPH + 0xB193: 0x774B, //CJK UNIFIED IDEOGRAPH + 0xB194: 0x774C, //CJK UNIFIED IDEOGRAPH + 0xB195: 0x774D, //CJK UNIFIED IDEOGRAPH + 0xB196: 0x774E, //CJK UNIFIED IDEOGRAPH + 0xB197: 0x774F, //CJK UNIFIED IDEOGRAPH + 0xB198: 0x7752, //CJK UNIFIED IDEOGRAPH + 0xB199: 0x7753, //CJK UNIFIED IDEOGRAPH + 0xB19A: 0x7754, //CJK UNIFIED IDEOGRAPH + 0xB19B: 0x7755, //CJK UNIFIED IDEOGRAPH + 0xB19C: 0x7756, //CJK UNIFIED IDEOGRAPH + 0xB19D: 0x7757, //CJK UNIFIED IDEOGRAPH + 0xB19E: 0x7758, //CJK UNIFIED IDEOGRAPH + 0xB19F: 0x7759, //CJK UNIFIED IDEOGRAPH + 0xB1A0: 0x775C, //CJK UNIFIED IDEOGRAPH + 0xB1A1: 0x8584, //CJK UNIFIED IDEOGRAPH + 0xB1A2: 0x96F9, //CJK UNIFIED IDEOGRAPH + 0xB1A3: 0x4FDD, //CJK UNIFIED IDEOGRAPH + 0xB1A4: 0x5821, //CJK UNIFIED IDEOGRAPH + 0xB1A5: 0x9971, //CJK UNIFIED IDEOGRAPH + 0xB1A6: 0x5B9D, //CJK UNIFIED IDEOGRAPH + 0xB1A7: 0x62B1, //CJK UNIFIED IDEOGRAPH + 0xB1A8: 0x62A5, //CJK UNIFIED IDEOGRAPH + 0xB1A9: 0x66B4, //CJK UNIFIED IDEOGRAPH + 0xB1AA: 0x8C79, //CJK UNIFIED IDEOGRAPH + 0xB1AB: 0x9C8D, //CJK UNIFIED IDEOGRAPH + 0xB1AC: 0x7206, //CJK UNIFIED IDEOGRAPH + 0xB1AD: 0x676F, //CJK UNIFIED IDEOGRAPH + 0xB1AE: 0x7891, //CJK UNIFIED IDEOGRAPH + 0xB1AF: 0x60B2, //CJK UNIFIED IDEOGRAPH + 0xB1B0: 0x5351, //CJK UNIFIED IDEOGRAPH + 0xB1B1: 0x5317, //CJK UNIFIED IDEOGRAPH + 0xB1B2: 0x8F88, //CJK UNIFIED IDEOGRAPH + 0xB1B3: 0x80CC, //CJK UNIFIED IDEOGRAPH + 0xB1B4: 0x8D1D, //CJK UNIFIED IDEOGRAPH + 0xB1B5: 0x94A1, //CJK UNIFIED IDEOGRAPH + 0xB1B6: 0x500D, //CJK UNIFIED IDEOGRAPH + 0xB1B7: 0x72C8, //CJK UNIFIED IDEOGRAPH + 0xB1B8: 0x5907, //CJK UNIFIED IDEOGRAPH + 0xB1B9: 0x60EB, //CJK UNIFIED IDEOGRAPH + 0xB1BA: 0x7119, //CJK UNIFIED IDEOGRAPH + 0xB1BB: 0x88AB, //CJK UNIFIED IDEOGRAPH + 0xB1BC: 0x5954, //CJK UNIFIED IDEOGRAPH + 0xB1BD: 0x82EF, //CJK UNIFIED IDEOGRAPH + 0xB1BE: 0x672C, //CJK UNIFIED IDEOGRAPH + 0xB1BF: 0x7B28, //CJK UNIFIED IDEOGRAPH + 0xB1C0: 0x5D29, //CJK UNIFIED IDEOGRAPH + 0xB1C1: 0x7EF7, //CJK UNIFIED IDEOGRAPH + 0xB1C2: 0x752D, //CJK UNIFIED IDEOGRAPH + 0xB1C3: 0x6CF5, //CJK UNIFIED IDEOGRAPH + 0xB1C4: 0x8E66, //CJK UNIFIED IDEOGRAPH + 0xB1C5: 0x8FF8, //CJK UNIFIED IDEOGRAPH + 0xB1C6: 0x903C, //CJK UNIFIED IDEOGRAPH + 0xB1C7: 0x9F3B, //CJK UNIFIED IDEOGRAPH + 0xB1C8: 0x6BD4, //CJK UNIFIED IDEOGRAPH + 0xB1C9: 0x9119, //CJK UNIFIED IDEOGRAPH + 0xB1CA: 0x7B14, //CJK UNIFIED IDEOGRAPH + 0xB1CB: 0x5F7C, //CJK UNIFIED IDEOGRAPH + 0xB1CC: 0x78A7, //CJK UNIFIED IDEOGRAPH + 0xB1CD: 0x84D6, //CJK UNIFIED IDEOGRAPH + 0xB1CE: 0x853D, //CJK UNIFIED IDEOGRAPH + 0xB1CF: 0x6BD5, //CJK UNIFIED IDEOGRAPH + 0xB1D0: 0x6BD9, //CJK UNIFIED IDEOGRAPH + 0xB1D1: 0x6BD6, //CJK UNIFIED IDEOGRAPH + 0xB1D2: 0x5E01, //CJK UNIFIED IDEOGRAPH + 0xB1D3: 0x5E87, //CJK UNIFIED IDEOGRAPH + 0xB1D4: 0x75F9, //CJK UNIFIED IDEOGRAPH + 0xB1D5: 0x95ED, //CJK UNIFIED IDEOGRAPH + 0xB1D6: 0x655D, //CJK UNIFIED IDEOGRAPH + 0xB1D7: 0x5F0A, //CJK UNIFIED IDEOGRAPH + 0xB1D8: 0x5FC5, //CJK UNIFIED IDEOGRAPH + 0xB1D9: 0x8F9F, //CJK UNIFIED IDEOGRAPH + 0xB1DA: 0x58C1, //CJK UNIFIED IDEOGRAPH + 0xB1DB: 0x81C2, //CJK UNIFIED IDEOGRAPH + 0xB1DC: 0x907F, //CJK UNIFIED IDEOGRAPH + 0xB1DD: 0x965B, //CJK UNIFIED IDEOGRAPH + 0xB1DE: 0x97AD, //CJK UNIFIED IDEOGRAPH + 0xB1DF: 0x8FB9, //CJK UNIFIED IDEOGRAPH + 0xB1E0: 0x7F16, //CJK UNIFIED IDEOGRAPH + 0xB1E1: 0x8D2C, //CJK UNIFIED IDEOGRAPH + 0xB1E2: 0x6241, //CJK UNIFIED IDEOGRAPH + 0xB1E3: 0x4FBF, //CJK UNIFIED IDEOGRAPH + 0xB1E4: 0x53D8, //CJK UNIFIED IDEOGRAPH + 0xB1E5: 0x535E, //CJK UNIFIED IDEOGRAPH + 0xB1E6: 0x8FA8, //CJK UNIFIED IDEOGRAPH + 0xB1E7: 0x8FA9, //CJK UNIFIED IDEOGRAPH + 0xB1E8: 0x8FAB, //CJK UNIFIED IDEOGRAPH + 0xB1E9: 0x904D, //CJK UNIFIED IDEOGRAPH + 0xB1EA: 0x6807, //CJK UNIFIED IDEOGRAPH + 0xB1EB: 0x5F6A, //CJK UNIFIED IDEOGRAPH + 0xB1EC: 0x8198, //CJK UNIFIED IDEOGRAPH + 0xB1ED: 0x8868, //CJK UNIFIED IDEOGRAPH + 0xB1EE: 0x9CD6, //CJK UNIFIED IDEOGRAPH + 0xB1EF: 0x618B, //CJK UNIFIED IDEOGRAPH + 0xB1F0: 0x522B, //CJK UNIFIED IDEOGRAPH + 0xB1F1: 0x762A, //CJK UNIFIED IDEOGRAPH + 0xB1F2: 0x5F6C, //CJK UNIFIED IDEOGRAPH + 0xB1F3: 0x658C, //CJK UNIFIED IDEOGRAPH + 0xB1F4: 0x6FD2, //CJK UNIFIED IDEOGRAPH + 0xB1F5: 0x6EE8, //CJK UNIFIED IDEOGRAPH + 0xB1F6: 0x5BBE, //CJK UNIFIED IDEOGRAPH + 0xB1F7: 0x6448, //CJK UNIFIED IDEOGRAPH + 0xB1F8: 0x5175, //CJK UNIFIED IDEOGRAPH + 0xB1F9: 0x51B0, //CJK UNIFIED IDEOGRAPH + 0xB1FA: 0x67C4, //CJK UNIFIED IDEOGRAPH + 0xB1FB: 0x4E19, //CJK UNIFIED IDEOGRAPH + 0xB1FC: 0x79C9, //CJK UNIFIED IDEOGRAPH + 0xB1FD: 0x997C, //CJK UNIFIED IDEOGRAPH + 0xB1FE: 0x70B3, //CJK UNIFIED IDEOGRAPH + 0xB240: 0x775D, //CJK UNIFIED IDEOGRAPH + 0xB241: 0x775E, //CJK UNIFIED IDEOGRAPH + 0xB242: 0x775F, //CJK UNIFIED IDEOGRAPH + 0xB243: 0x7760, //CJK UNIFIED IDEOGRAPH + 0xB244: 0x7764, //CJK UNIFIED IDEOGRAPH + 0xB245: 0x7767, //CJK UNIFIED IDEOGRAPH + 0xB246: 0x7769, //CJK UNIFIED IDEOGRAPH + 0xB247: 0x776A, //CJK UNIFIED IDEOGRAPH + 0xB248: 0x776D, //CJK UNIFIED IDEOGRAPH + 0xB249: 0x776E, //CJK UNIFIED IDEOGRAPH + 0xB24A: 0x776F, //CJK UNIFIED IDEOGRAPH + 0xB24B: 0x7770, //CJK UNIFIED IDEOGRAPH + 0xB24C: 0x7771, //CJK UNIFIED IDEOGRAPH + 0xB24D: 0x7772, //CJK UNIFIED IDEOGRAPH + 0xB24E: 0x7773, //CJK UNIFIED IDEOGRAPH + 0xB24F: 0x7774, //CJK UNIFIED IDEOGRAPH + 0xB250: 0x7775, //CJK UNIFIED IDEOGRAPH + 0xB251: 0x7776, //CJK UNIFIED IDEOGRAPH + 0xB252: 0x7777, //CJK UNIFIED IDEOGRAPH + 0xB253: 0x7778, //CJK UNIFIED IDEOGRAPH + 0xB254: 0x777A, //CJK UNIFIED IDEOGRAPH + 0xB255: 0x777B, //CJK UNIFIED IDEOGRAPH + 0xB256: 0x777C, //CJK UNIFIED IDEOGRAPH + 0xB257: 0x7781, //CJK UNIFIED IDEOGRAPH + 0xB258: 0x7782, //CJK UNIFIED IDEOGRAPH + 0xB259: 0x7783, //CJK UNIFIED IDEOGRAPH + 0xB25A: 0x7786, //CJK UNIFIED IDEOGRAPH + 0xB25B: 0x7787, //CJK UNIFIED IDEOGRAPH + 0xB25C: 0x7788, //CJK UNIFIED IDEOGRAPH + 0xB25D: 0x7789, //CJK UNIFIED IDEOGRAPH + 0xB25E: 0x778A, //CJK UNIFIED IDEOGRAPH + 0xB25F: 0x778B, //CJK UNIFIED IDEOGRAPH + 0xB260: 0x778F, //CJK UNIFIED IDEOGRAPH + 0xB261: 0x7790, //CJK UNIFIED IDEOGRAPH + 0xB262: 0x7793, //CJK UNIFIED IDEOGRAPH + 0xB263: 0x7794, //CJK UNIFIED IDEOGRAPH + 0xB264: 0x7795, //CJK UNIFIED IDEOGRAPH + 0xB265: 0x7796, //CJK UNIFIED IDEOGRAPH + 0xB266: 0x7797, //CJK UNIFIED IDEOGRAPH + 0xB267: 0x7798, //CJK UNIFIED IDEOGRAPH + 0xB268: 0x7799, //CJK UNIFIED IDEOGRAPH + 0xB269: 0x779A, //CJK UNIFIED IDEOGRAPH + 0xB26A: 0x779B, //CJK UNIFIED IDEOGRAPH + 0xB26B: 0x779C, //CJK UNIFIED IDEOGRAPH + 0xB26C: 0x779D, //CJK UNIFIED IDEOGRAPH + 0xB26D: 0x779E, //CJK UNIFIED IDEOGRAPH + 0xB26E: 0x77A1, //CJK UNIFIED IDEOGRAPH + 0xB26F: 0x77A3, //CJK UNIFIED IDEOGRAPH + 0xB270: 0x77A4, //CJK UNIFIED IDEOGRAPH + 0xB271: 0x77A6, //CJK UNIFIED IDEOGRAPH + 0xB272: 0x77A8, //CJK UNIFIED IDEOGRAPH + 0xB273: 0x77AB, //CJK UNIFIED IDEOGRAPH + 0xB274: 0x77AD, //CJK UNIFIED IDEOGRAPH + 0xB275: 0x77AE, //CJK UNIFIED IDEOGRAPH + 0xB276: 0x77AF, //CJK UNIFIED IDEOGRAPH + 0xB277: 0x77B1, //CJK UNIFIED IDEOGRAPH + 0xB278: 0x77B2, //CJK UNIFIED IDEOGRAPH + 0xB279: 0x77B4, //CJK UNIFIED IDEOGRAPH + 0xB27A: 0x77B6, //CJK UNIFIED IDEOGRAPH + 0xB27B: 0x77B7, //CJK UNIFIED IDEOGRAPH + 0xB27C: 0x77B8, //CJK UNIFIED IDEOGRAPH + 0xB27D: 0x77B9, //CJK UNIFIED IDEOGRAPH + 0xB27E: 0x77BA, //CJK UNIFIED IDEOGRAPH + 0xB280: 0x77BC, //CJK UNIFIED IDEOGRAPH + 0xB281: 0x77BE, //CJK UNIFIED IDEOGRAPH + 0xB282: 0x77C0, //CJK UNIFIED IDEOGRAPH + 0xB283: 0x77C1, //CJK UNIFIED IDEOGRAPH + 0xB284: 0x77C2, //CJK UNIFIED IDEOGRAPH + 0xB285: 0x77C3, //CJK UNIFIED IDEOGRAPH + 0xB286: 0x77C4, //CJK UNIFIED IDEOGRAPH + 0xB287: 0x77C5, //CJK UNIFIED IDEOGRAPH + 0xB288: 0x77C6, //CJK UNIFIED IDEOGRAPH + 0xB289: 0x77C7, //CJK UNIFIED IDEOGRAPH + 0xB28A: 0x77C8, //CJK UNIFIED IDEOGRAPH + 0xB28B: 0x77C9, //CJK UNIFIED IDEOGRAPH + 0xB28C: 0x77CA, //CJK UNIFIED IDEOGRAPH + 0xB28D: 0x77CB, //CJK UNIFIED IDEOGRAPH + 0xB28E: 0x77CC, //CJK UNIFIED IDEOGRAPH + 0xB28F: 0x77CE, //CJK UNIFIED IDEOGRAPH + 0xB290: 0x77CF, //CJK UNIFIED IDEOGRAPH + 0xB291: 0x77D0, //CJK UNIFIED IDEOGRAPH + 0xB292: 0x77D1, //CJK UNIFIED IDEOGRAPH + 0xB293: 0x77D2, //CJK UNIFIED IDEOGRAPH + 0xB294: 0x77D3, //CJK UNIFIED IDEOGRAPH + 0xB295: 0x77D4, //CJK UNIFIED IDEOGRAPH + 0xB296: 0x77D5, //CJK UNIFIED IDEOGRAPH + 0xB297: 0x77D6, //CJK UNIFIED IDEOGRAPH + 0xB298: 0x77D8, //CJK UNIFIED IDEOGRAPH + 0xB299: 0x77D9, //CJK UNIFIED IDEOGRAPH + 0xB29A: 0x77DA, //CJK UNIFIED IDEOGRAPH + 0xB29B: 0x77DD, //CJK UNIFIED IDEOGRAPH + 0xB29C: 0x77DE, //CJK UNIFIED IDEOGRAPH + 0xB29D: 0x77DF, //CJK UNIFIED IDEOGRAPH + 0xB29E: 0x77E0, //CJK UNIFIED IDEOGRAPH + 0xB29F: 0x77E1, //CJK UNIFIED IDEOGRAPH + 0xB2A0: 0x77E4, //CJK UNIFIED IDEOGRAPH + 0xB2A1: 0x75C5, //CJK UNIFIED IDEOGRAPH + 0xB2A2: 0x5E76, //CJK UNIFIED IDEOGRAPH + 0xB2A3: 0x73BB, //CJK UNIFIED IDEOGRAPH + 0xB2A4: 0x83E0, //CJK UNIFIED IDEOGRAPH + 0xB2A5: 0x64AD, //CJK UNIFIED IDEOGRAPH + 0xB2A6: 0x62E8, //CJK UNIFIED IDEOGRAPH + 0xB2A7: 0x94B5, //CJK UNIFIED IDEOGRAPH + 0xB2A8: 0x6CE2, //CJK UNIFIED IDEOGRAPH + 0xB2A9: 0x535A, //CJK UNIFIED IDEOGRAPH + 0xB2AA: 0x52C3, //CJK UNIFIED IDEOGRAPH + 0xB2AB: 0x640F, //CJK UNIFIED IDEOGRAPH + 0xB2AC: 0x94C2, //CJK UNIFIED IDEOGRAPH + 0xB2AD: 0x7B94, //CJK UNIFIED IDEOGRAPH + 0xB2AE: 0x4F2F, //CJK UNIFIED IDEOGRAPH + 0xB2AF: 0x5E1B, //CJK UNIFIED IDEOGRAPH + 0xB2B0: 0x8236, //CJK UNIFIED IDEOGRAPH + 0xB2B1: 0x8116, //CJK UNIFIED IDEOGRAPH + 0xB2B2: 0x818A, //CJK UNIFIED IDEOGRAPH + 0xB2B3: 0x6E24, //CJK UNIFIED IDEOGRAPH + 0xB2B4: 0x6CCA, //CJK UNIFIED IDEOGRAPH + 0xB2B5: 0x9A73, //CJK UNIFIED IDEOGRAPH + 0xB2B6: 0x6355, //CJK UNIFIED IDEOGRAPH + 0xB2B7: 0x535C, //CJK UNIFIED IDEOGRAPH + 0xB2B8: 0x54FA, //CJK UNIFIED IDEOGRAPH + 0xB2B9: 0x8865, //CJK UNIFIED IDEOGRAPH + 0xB2BA: 0x57E0, //CJK UNIFIED IDEOGRAPH + 0xB2BB: 0x4E0D, //CJK UNIFIED IDEOGRAPH + 0xB2BC: 0x5E03, //CJK UNIFIED IDEOGRAPH + 0xB2BD: 0x6B65, //CJK UNIFIED IDEOGRAPH + 0xB2BE: 0x7C3F, //CJK UNIFIED IDEOGRAPH + 0xB2BF: 0x90E8, //CJK UNIFIED IDEOGRAPH + 0xB2C0: 0x6016, //CJK UNIFIED IDEOGRAPH + 0xB2C1: 0x64E6, //CJK UNIFIED IDEOGRAPH + 0xB2C2: 0x731C, //CJK UNIFIED IDEOGRAPH + 0xB2C3: 0x88C1, //CJK UNIFIED IDEOGRAPH + 0xB2C4: 0x6750, //CJK UNIFIED IDEOGRAPH + 0xB2C5: 0x624D, //CJK UNIFIED IDEOGRAPH + 0xB2C6: 0x8D22, //CJK UNIFIED IDEOGRAPH + 0xB2C7: 0x776C, //CJK UNIFIED IDEOGRAPH + 0xB2C8: 0x8E29, //CJK UNIFIED IDEOGRAPH + 0xB2C9: 0x91C7, //CJK UNIFIED IDEOGRAPH + 0xB2CA: 0x5F69, //CJK UNIFIED IDEOGRAPH + 0xB2CB: 0x83DC, //CJK UNIFIED IDEOGRAPH + 0xB2CC: 0x8521, //CJK UNIFIED IDEOGRAPH + 0xB2CD: 0x9910, //CJK UNIFIED IDEOGRAPH + 0xB2CE: 0x53C2, //CJK UNIFIED IDEOGRAPH + 0xB2CF: 0x8695, //CJK UNIFIED IDEOGRAPH + 0xB2D0: 0x6B8B, //CJK UNIFIED IDEOGRAPH + 0xB2D1: 0x60ED, //CJK UNIFIED IDEOGRAPH + 0xB2D2: 0x60E8, //CJK UNIFIED IDEOGRAPH + 0xB2D3: 0x707F, //CJK UNIFIED IDEOGRAPH + 0xB2D4: 0x82CD, //CJK UNIFIED IDEOGRAPH + 0xB2D5: 0x8231, //CJK UNIFIED IDEOGRAPH + 0xB2D6: 0x4ED3, //CJK UNIFIED IDEOGRAPH + 0xB2D7: 0x6CA7, //CJK UNIFIED IDEOGRAPH + 0xB2D8: 0x85CF, //CJK UNIFIED IDEOGRAPH + 0xB2D9: 0x64CD, //CJK UNIFIED IDEOGRAPH + 0xB2DA: 0x7CD9, //CJK UNIFIED IDEOGRAPH + 0xB2DB: 0x69FD, //CJK UNIFIED IDEOGRAPH + 0xB2DC: 0x66F9, //CJK UNIFIED IDEOGRAPH + 0xB2DD: 0x8349, //CJK UNIFIED IDEOGRAPH + 0xB2DE: 0x5395, //CJK UNIFIED IDEOGRAPH + 0xB2DF: 0x7B56, //CJK UNIFIED IDEOGRAPH + 0xB2E0: 0x4FA7, //CJK UNIFIED IDEOGRAPH + 0xB2E1: 0x518C, //CJK UNIFIED IDEOGRAPH + 0xB2E2: 0x6D4B, //CJK UNIFIED IDEOGRAPH + 0xB2E3: 0x5C42, //CJK UNIFIED IDEOGRAPH + 0xB2E4: 0x8E6D, //CJK UNIFIED IDEOGRAPH + 0xB2E5: 0x63D2, //CJK UNIFIED IDEOGRAPH + 0xB2E6: 0x53C9, //CJK UNIFIED IDEOGRAPH + 0xB2E7: 0x832C, //CJK UNIFIED IDEOGRAPH + 0xB2E8: 0x8336, //CJK UNIFIED IDEOGRAPH + 0xB2E9: 0x67E5, //CJK UNIFIED IDEOGRAPH + 0xB2EA: 0x78B4, //CJK UNIFIED IDEOGRAPH + 0xB2EB: 0x643D, //CJK UNIFIED IDEOGRAPH + 0xB2EC: 0x5BDF, //CJK UNIFIED IDEOGRAPH + 0xB2ED: 0x5C94, //CJK UNIFIED IDEOGRAPH + 0xB2EE: 0x5DEE, //CJK UNIFIED IDEOGRAPH + 0xB2EF: 0x8BE7, //CJK UNIFIED IDEOGRAPH + 0xB2F0: 0x62C6, //CJK UNIFIED IDEOGRAPH + 0xB2F1: 0x67F4, //CJK UNIFIED IDEOGRAPH + 0xB2F2: 0x8C7A, //CJK UNIFIED IDEOGRAPH + 0xB2F3: 0x6400, //CJK UNIFIED IDEOGRAPH + 0xB2F4: 0x63BA, //CJK UNIFIED IDEOGRAPH + 0xB2F5: 0x8749, //CJK UNIFIED IDEOGRAPH + 0xB2F6: 0x998B, //CJK UNIFIED IDEOGRAPH + 0xB2F7: 0x8C17, //CJK UNIFIED IDEOGRAPH + 0xB2F8: 0x7F20, //CJK UNIFIED IDEOGRAPH + 0xB2F9: 0x94F2, //CJK UNIFIED IDEOGRAPH + 0xB2FA: 0x4EA7, //CJK UNIFIED IDEOGRAPH + 0xB2FB: 0x9610, //CJK UNIFIED IDEOGRAPH + 0xB2FC: 0x98A4, //CJK UNIFIED IDEOGRAPH + 0xB2FD: 0x660C, //CJK UNIFIED IDEOGRAPH + 0xB2FE: 0x7316, //CJK UNIFIED IDEOGRAPH + 0xB340: 0x77E6, //CJK UNIFIED IDEOGRAPH + 0xB341: 0x77E8, //CJK UNIFIED IDEOGRAPH + 0xB342: 0x77EA, //CJK UNIFIED IDEOGRAPH + 0xB343: 0x77EF, //CJK UNIFIED IDEOGRAPH + 0xB344: 0x77F0, //CJK UNIFIED IDEOGRAPH + 0xB345: 0x77F1, //CJK UNIFIED IDEOGRAPH + 0xB346: 0x77F2, //CJK UNIFIED IDEOGRAPH + 0xB347: 0x77F4, //CJK UNIFIED IDEOGRAPH + 0xB348: 0x77F5, //CJK UNIFIED IDEOGRAPH + 0xB349: 0x77F7, //CJK UNIFIED IDEOGRAPH + 0xB34A: 0x77F9, //CJK UNIFIED IDEOGRAPH + 0xB34B: 0x77FA, //CJK UNIFIED IDEOGRAPH + 0xB34C: 0x77FB, //CJK UNIFIED IDEOGRAPH + 0xB34D: 0x77FC, //CJK UNIFIED IDEOGRAPH + 0xB34E: 0x7803, //CJK UNIFIED IDEOGRAPH + 0xB34F: 0x7804, //CJK UNIFIED IDEOGRAPH + 0xB350: 0x7805, //CJK UNIFIED IDEOGRAPH + 0xB351: 0x7806, //CJK UNIFIED IDEOGRAPH + 0xB352: 0x7807, //CJK UNIFIED IDEOGRAPH + 0xB353: 0x7808, //CJK UNIFIED IDEOGRAPH + 0xB354: 0x780A, //CJK UNIFIED IDEOGRAPH + 0xB355: 0x780B, //CJK UNIFIED IDEOGRAPH + 0xB356: 0x780E, //CJK UNIFIED IDEOGRAPH + 0xB357: 0x780F, //CJK UNIFIED IDEOGRAPH + 0xB358: 0x7810, //CJK UNIFIED IDEOGRAPH + 0xB359: 0x7813, //CJK UNIFIED IDEOGRAPH + 0xB35A: 0x7815, //CJK UNIFIED IDEOGRAPH + 0xB35B: 0x7819, //CJK UNIFIED IDEOGRAPH + 0xB35C: 0x781B, //CJK UNIFIED IDEOGRAPH + 0xB35D: 0x781E, //CJK UNIFIED IDEOGRAPH + 0xB35E: 0x7820, //CJK UNIFIED IDEOGRAPH + 0xB35F: 0x7821, //CJK UNIFIED IDEOGRAPH + 0xB360: 0x7822, //CJK UNIFIED IDEOGRAPH + 0xB361: 0x7824, //CJK UNIFIED IDEOGRAPH + 0xB362: 0x7828, //CJK UNIFIED IDEOGRAPH + 0xB363: 0x782A, //CJK UNIFIED IDEOGRAPH + 0xB364: 0x782B, //CJK UNIFIED IDEOGRAPH + 0xB365: 0x782E, //CJK UNIFIED IDEOGRAPH + 0xB366: 0x782F, //CJK UNIFIED IDEOGRAPH + 0xB367: 0x7831, //CJK UNIFIED IDEOGRAPH + 0xB368: 0x7832, //CJK UNIFIED IDEOGRAPH + 0xB369: 0x7833, //CJK UNIFIED IDEOGRAPH + 0xB36A: 0x7835, //CJK UNIFIED IDEOGRAPH + 0xB36B: 0x7836, //CJK UNIFIED IDEOGRAPH + 0xB36C: 0x783D, //CJK UNIFIED IDEOGRAPH + 0xB36D: 0x783F, //CJK UNIFIED IDEOGRAPH + 0xB36E: 0x7841, //CJK UNIFIED IDEOGRAPH + 0xB36F: 0x7842, //CJK UNIFIED IDEOGRAPH + 0xB370: 0x7843, //CJK UNIFIED IDEOGRAPH + 0xB371: 0x7844, //CJK UNIFIED IDEOGRAPH + 0xB372: 0x7846, //CJK UNIFIED IDEOGRAPH + 0xB373: 0x7848, //CJK UNIFIED IDEOGRAPH + 0xB374: 0x7849, //CJK UNIFIED IDEOGRAPH + 0xB375: 0x784A, //CJK UNIFIED IDEOGRAPH + 0xB376: 0x784B, //CJK UNIFIED IDEOGRAPH + 0xB377: 0x784D, //CJK UNIFIED IDEOGRAPH + 0xB378: 0x784F, //CJK UNIFIED IDEOGRAPH + 0xB379: 0x7851, //CJK UNIFIED IDEOGRAPH + 0xB37A: 0x7853, //CJK UNIFIED IDEOGRAPH + 0xB37B: 0x7854, //CJK UNIFIED IDEOGRAPH + 0xB37C: 0x7858, //CJK UNIFIED IDEOGRAPH + 0xB37D: 0x7859, //CJK UNIFIED IDEOGRAPH + 0xB37E: 0x785A, //CJK UNIFIED IDEOGRAPH + 0xB380: 0x785B, //CJK UNIFIED IDEOGRAPH + 0xB381: 0x785C, //CJK UNIFIED IDEOGRAPH + 0xB382: 0x785E, //CJK UNIFIED IDEOGRAPH + 0xB383: 0x785F, //CJK UNIFIED IDEOGRAPH + 0xB384: 0x7860, //CJK UNIFIED IDEOGRAPH + 0xB385: 0x7861, //CJK UNIFIED IDEOGRAPH + 0xB386: 0x7862, //CJK UNIFIED IDEOGRAPH + 0xB387: 0x7863, //CJK UNIFIED IDEOGRAPH + 0xB388: 0x7864, //CJK UNIFIED IDEOGRAPH + 0xB389: 0x7865, //CJK UNIFIED IDEOGRAPH + 0xB38A: 0x7866, //CJK UNIFIED IDEOGRAPH + 0xB38B: 0x7867, //CJK UNIFIED IDEOGRAPH + 0xB38C: 0x7868, //CJK UNIFIED IDEOGRAPH + 0xB38D: 0x7869, //CJK UNIFIED IDEOGRAPH + 0xB38E: 0x786F, //CJK UNIFIED IDEOGRAPH + 0xB38F: 0x7870, //CJK UNIFIED IDEOGRAPH + 0xB390: 0x7871, //CJK UNIFIED IDEOGRAPH + 0xB391: 0x7872, //CJK UNIFIED IDEOGRAPH + 0xB392: 0x7873, //CJK UNIFIED IDEOGRAPH + 0xB393: 0x7874, //CJK UNIFIED IDEOGRAPH + 0xB394: 0x7875, //CJK UNIFIED IDEOGRAPH + 0xB395: 0x7876, //CJK UNIFIED IDEOGRAPH + 0xB396: 0x7878, //CJK UNIFIED IDEOGRAPH + 0xB397: 0x7879, //CJK UNIFIED IDEOGRAPH + 0xB398: 0x787A, //CJK UNIFIED IDEOGRAPH + 0xB399: 0x787B, //CJK UNIFIED IDEOGRAPH + 0xB39A: 0x787D, //CJK UNIFIED IDEOGRAPH + 0xB39B: 0x787E, //CJK UNIFIED IDEOGRAPH + 0xB39C: 0x787F, //CJK UNIFIED IDEOGRAPH + 0xB39D: 0x7880, //CJK UNIFIED IDEOGRAPH + 0xB39E: 0x7881, //CJK UNIFIED IDEOGRAPH + 0xB39F: 0x7882, //CJK UNIFIED IDEOGRAPH + 0xB3A0: 0x7883, //CJK UNIFIED IDEOGRAPH + 0xB3A1: 0x573A, //CJK UNIFIED IDEOGRAPH + 0xB3A2: 0x5C1D, //CJK UNIFIED IDEOGRAPH + 0xB3A3: 0x5E38, //CJK UNIFIED IDEOGRAPH + 0xB3A4: 0x957F, //CJK UNIFIED IDEOGRAPH + 0xB3A5: 0x507F, //CJK UNIFIED IDEOGRAPH + 0xB3A6: 0x80A0, //CJK UNIFIED IDEOGRAPH + 0xB3A7: 0x5382, //CJK UNIFIED IDEOGRAPH + 0xB3A8: 0x655E, //CJK UNIFIED IDEOGRAPH + 0xB3A9: 0x7545, //CJK UNIFIED IDEOGRAPH + 0xB3AA: 0x5531, //CJK UNIFIED IDEOGRAPH + 0xB3AB: 0x5021, //CJK UNIFIED IDEOGRAPH + 0xB3AC: 0x8D85, //CJK UNIFIED IDEOGRAPH + 0xB3AD: 0x6284, //CJK UNIFIED IDEOGRAPH + 0xB3AE: 0x949E, //CJK UNIFIED IDEOGRAPH + 0xB3AF: 0x671D, //CJK UNIFIED IDEOGRAPH + 0xB3B0: 0x5632, //CJK UNIFIED IDEOGRAPH + 0xB3B1: 0x6F6E, //CJK UNIFIED IDEOGRAPH + 0xB3B2: 0x5DE2, //CJK UNIFIED IDEOGRAPH + 0xB3B3: 0x5435, //CJK UNIFIED IDEOGRAPH + 0xB3B4: 0x7092, //CJK UNIFIED IDEOGRAPH + 0xB3B5: 0x8F66, //CJK UNIFIED IDEOGRAPH + 0xB3B6: 0x626F, //CJK UNIFIED IDEOGRAPH + 0xB3B7: 0x64A4, //CJK UNIFIED IDEOGRAPH + 0xB3B8: 0x63A3, //CJK UNIFIED IDEOGRAPH + 0xB3B9: 0x5F7B, //CJK UNIFIED IDEOGRAPH + 0xB3BA: 0x6F88, //CJK UNIFIED IDEOGRAPH + 0xB3BB: 0x90F4, //CJK UNIFIED IDEOGRAPH + 0xB3BC: 0x81E3, //CJK UNIFIED IDEOGRAPH + 0xB3BD: 0x8FB0, //CJK UNIFIED IDEOGRAPH + 0xB3BE: 0x5C18, //CJK UNIFIED IDEOGRAPH + 0xB3BF: 0x6668, //CJK UNIFIED IDEOGRAPH + 0xB3C0: 0x5FF1, //CJK UNIFIED IDEOGRAPH + 0xB3C1: 0x6C89, //CJK UNIFIED IDEOGRAPH + 0xB3C2: 0x9648, //CJK UNIFIED IDEOGRAPH + 0xB3C3: 0x8D81, //CJK UNIFIED IDEOGRAPH + 0xB3C4: 0x886C, //CJK UNIFIED IDEOGRAPH + 0xB3C5: 0x6491, //CJK UNIFIED IDEOGRAPH + 0xB3C6: 0x79F0, //CJK UNIFIED IDEOGRAPH + 0xB3C7: 0x57CE, //CJK UNIFIED IDEOGRAPH + 0xB3C8: 0x6A59, //CJK UNIFIED IDEOGRAPH + 0xB3C9: 0x6210, //CJK UNIFIED IDEOGRAPH + 0xB3CA: 0x5448, //CJK UNIFIED IDEOGRAPH + 0xB3CB: 0x4E58, //CJK UNIFIED IDEOGRAPH + 0xB3CC: 0x7A0B, //CJK UNIFIED IDEOGRAPH + 0xB3CD: 0x60E9, //CJK UNIFIED IDEOGRAPH + 0xB3CE: 0x6F84, //CJK UNIFIED IDEOGRAPH + 0xB3CF: 0x8BDA, //CJK UNIFIED IDEOGRAPH + 0xB3D0: 0x627F, //CJK UNIFIED IDEOGRAPH + 0xB3D1: 0x901E, //CJK UNIFIED IDEOGRAPH + 0xB3D2: 0x9A8B, //CJK UNIFIED IDEOGRAPH + 0xB3D3: 0x79E4, //CJK UNIFIED IDEOGRAPH + 0xB3D4: 0x5403, //CJK UNIFIED IDEOGRAPH + 0xB3D5: 0x75F4, //CJK UNIFIED IDEOGRAPH + 0xB3D6: 0x6301, //CJK UNIFIED IDEOGRAPH + 0xB3D7: 0x5319, //CJK UNIFIED IDEOGRAPH + 0xB3D8: 0x6C60, //CJK UNIFIED IDEOGRAPH + 0xB3D9: 0x8FDF, //CJK UNIFIED IDEOGRAPH + 0xB3DA: 0x5F1B, //CJK UNIFIED IDEOGRAPH + 0xB3DB: 0x9A70, //CJK UNIFIED IDEOGRAPH + 0xB3DC: 0x803B, //CJK UNIFIED IDEOGRAPH + 0xB3DD: 0x9F7F, //CJK UNIFIED IDEOGRAPH + 0xB3DE: 0x4F88, //CJK UNIFIED IDEOGRAPH + 0xB3DF: 0x5C3A, //CJK UNIFIED IDEOGRAPH + 0xB3E0: 0x8D64, //CJK UNIFIED IDEOGRAPH + 0xB3E1: 0x7FC5, //CJK UNIFIED IDEOGRAPH + 0xB3E2: 0x65A5, //CJK UNIFIED IDEOGRAPH + 0xB3E3: 0x70BD, //CJK UNIFIED IDEOGRAPH + 0xB3E4: 0x5145, //CJK UNIFIED IDEOGRAPH + 0xB3E5: 0x51B2, //CJK UNIFIED IDEOGRAPH + 0xB3E6: 0x866B, //CJK UNIFIED IDEOGRAPH + 0xB3E7: 0x5D07, //CJK UNIFIED IDEOGRAPH + 0xB3E8: 0x5BA0, //CJK UNIFIED IDEOGRAPH + 0xB3E9: 0x62BD, //CJK UNIFIED IDEOGRAPH + 0xB3EA: 0x916C, //CJK UNIFIED IDEOGRAPH + 0xB3EB: 0x7574, //CJK UNIFIED IDEOGRAPH + 0xB3EC: 0x8E0C, //CJK UNIFIED IDEOGRAPH + 0xB3ED: 0x7A20, //CJK UNIFIED IDEOGRAPH + 0xB3EE: 0x6101, //CJK UNIFIED IDEOGRAPH + 0xB3EF: 0x7B79, //CJK UNIFIED IDEOGRAPH + 0xB3F0: 0x4EC7, //CJK UNIFIED IDEOGRAPH + 0xB3F1: 0x7EF8, //CJK UNIFIED IDEOGRAPH + 0xB3F2: 0x7785, //CJK UNIFIED IDEOGRAPH + 0xB3F3: 0x4E11, //CJK UNIFIED IDEOGRAPH + 0xB3F4: 0x81ED, //CJK UNIFIED IDEOGRAPH + 0xB3F5: 0x521D, //CJK UNIFIED IDEOGRAPH + 0xB3F6: 0x51FA, //CJK UNIFIED IDEOGRAPH + 0xB3F7: 0x6A71, //CJK UNIFIED IDEOGRAPH + 0xB3F8: 0x53A8, //CJK UNIFIED IDEOGRAPH + 0xB3F9: 0x8E87, //CJK UNIFIED IDEOGRAPH + 0xB3FA: 0x9504, //CJK UNIFIED IDEOGRAPH + 0xB3FB: 0x96CF, //CJK UNIFIED IDEOGRAPH + 0xB3FC: 0x6EC1, //CJK UNIFIED IDEOGRAPH + 0xB3FD: 0x9664, //CJK UNIFIED IDEOGRAPH + 0xB3FE: 0x695A, //CJK UNIFIED IDEOGRAPH + 0xB440: 0x7884, //CJK UNIFIED IDEOGRAPH + 0xB441: 0x7885, //CJK UNIFIED IDEOGRAPH + 0xB442: 0x7886, //CJK UNIFIED IDEOGRAPH + 0xB443: 0x7888, //CJK UNIFIED IDEOGRAPH + 0xB444: 0x788A, //CJK UNIFIED IDEOGRAPH + 0xB445: 0x788B, //CJK UNIFIED IDEOGRAPH + 0xB446: 0x788F, //CJK UNIFIED IDEOGRAPH + 0xB447: 0x7890, //CJK UNIFIED IDEOGRAPH + 0xB448: 0x7892, //CJK UNIFIED IDEOGRAPH + 0xB449: 0x7894, //CJK UNIFIED IDEOGRAPH + 0xB44A: 0x7895, //CJK UNIFIED IDEOGRAPH + 0xB44B: 0x7896, //CJK UNIFIED IDEOGRAPH + 0xB44C: 0x7899, //CJK UNIFIED IDEOGRAPH + 0xB44D: 0x789D, //CJK UNIFIED IDEOGRAPH + 0xB44E: 0x789E, //CJK UNIFIED IDEOGRAPH + 0xB44F: 0x78A0, //CJK UNIFIED IDEOGRAPH + 0xB450: 0x78A2, //CJK UNIFIED IDEOGRAPH + 0xB451: 0x78A4, //CJK UNIFIED IDEOGRAPH + 0xB452: 0x78A6, //CJK UNIFIED IDEOGRAPH + 0xB453: 0x78A8, //CJK UNIFIED IDEOGRAPH + 0xB454: 0x78A9, //CJK UNIFIED IDEOGRAPH + 0xB455: 0x78AA, //CJK UNIFIED IDEOGRAPH + 0xB456: 0x78AB, //CJK UNIFIED IDEOGRAPH + 0xB457: 0x78AC, //CJK UNIFIED IDEOGRAPH + 0xB458: 0x78AD, //CJK UNIFIED IDEOGRAPH + 0xB459: 0x78AE, //CJK UNIFIED IDEOGRAPH + 0xB45A: 0x78AF, //CJK UNIFIED IDEOGRAPH + 0xB45B: 0x78B5, //CJK UNIFIED IDEOGRAPH + 0xB45C: 0x78B6, //CJK UNIFIED IDEOGRAPH + 0xB45D: 0x78B7, //CJK UNIFIED IDEOGRAPH + 0xB45E: 0x78B8, //CJK UNIFIED IDEOGRAPH + 0xB45F: 0x78BA, //CJK UNIFIED IDEOGRAPH + 0xB460: 0x78BB, //CJK UNIFIED IDEOGRAPH + 0xB461: 0x78BC, //CJK UNIFIED IDEOGRAPH + 0xB462: 0x78BD, //CJK UNIFIED IDEOGRAPH + 0xB463: 0x78BF, //CJK UNIFIED IDEOGRAPH + 0xB464: 0x78C0, //CJK UNIFIED IDEOGRAPH + 0xB465: 0x78C2, //CJK UNIFIED IDEOGRAPH + 0xB466: 0x78C3, //CJK UNIFIED IDEOGRAPH + 0xB467: 0x78C4, //CJK UNIFIED IDEOGRAPH + 0xB468: 0x78C6, //CJK UNIFIED IDEOGRAPH + 0xB469: 0x78C7, //CJK UNIFIED IDEOGRAPH + 0xB46A: 0x78C8, //CJK UNIFIED IDEOGRAPH + 0xB46B: 0x78CC, //CJK UNIFIED IDEOGRAPH + 0xB46C: 0x78CD, //CJK UNIFIED IDEOGRAPH + 0xB46D: 0x78CE, //CJK UNIFIED IDEOGRAPH + 0xB46E: 0x78CF, //CJK UNIFIED IDEOGRAPH + 0xB46F: 0x78D1, //CJK UNIFIED IDEOGRAPH + 0xB470: 0x78D2, //CJK UNIFIED IDEOGRAPH + 0xB471: 0x78D3, //CJK UNIFIED IDEOGRAPH + 0xB472: 0x78D6, //CJK UNIFIED IDEOGRAPH + 0xB473: 0x78D7, //CJK UNIFIED IDEOGRAPH + 0xB474: 0x78D8, //CJK UNIFIED IDEOGRAPH + 0xB475: 0x78DA, //CJK UNIFIED IDEOGRAPH + 0xB476: 0x78DB, //CJK UNIFIED IDEOGRAPH + 0xB477: 0x78DC, //CJK UNIFIED IDEOGRAPH + 0xB478: 0x78DD, //CJK UNIFIED IDEOGRAPH + 0xB479: 0x78DE, //CJK UNIFIED IDEOGRAPH + 0xB47A: 0x78DF, //CJK UNIFIED IDEOGRAPH + 0xB47B: 0x78E0, //CJK UNIFIED IDEOGRAPH + 0xB47C: 0x78E1, //CJK UNIFIED IDEOGRAPH + 0xB47D: 0x78E2, //CJK UNIFIED IDEOGRAPH + 0xB47E: 0x78E3, //CJK UNIFIED IDEOGRAPH + 0xB480: 0x78E4, //CJK UNIFIED IDEOGRAPH + 0xB481: 0x78E5, //CJK UNIFIED IDEOGRAPH + 0xB482: 0x78E6, //CJK UNIFIED IDEOGRAPH + 0xB483: 0x78E7, //CJK UNIFIED IDEOGRAPH + 0xB484: 0x78E9, //CJK UNIFIED IDEOGRAPH + 0xB485: 0x78EA, //CJK UNIFIED IDEOGRAPH + 0xB486: 0x78EB, //CJK UNIFIED IDEOGRAPH + 0xB487: 0x78ED, //CJK UNIFIED IDEOGRAPH + 0xB488: 0x78EE, //CJK UNIFIED IDEOGRAPH + 0xB489: 0x78EF, //CJK UNIFIED IDEOGRAPH + 0xB48A: 0x78F0, //CJK UNIFIED IDEOGRAPH + 0xB48B: 0x78F1, //CJK UNIFIED IDEOGRAPH + 0xB48C: 0x78F3, //CJK UNIFIED IDEOGRAPH + 0xB48D: 0x78F5, //CJK UNIFIED IDEOGRAPH + 0xB48E: 0x78F6, //CJK UNIFIED IDEOGRAPH + 0xB48F: 0x78F8, //CJK UNIFIED IDEOGRAPH + 0xB490: 0x78F9, //CJK UNIFIED IDEOGRAPH + 0xB491: 0x78FB, //CJK UNIFIED IDEOGRAPH + 0xB492: 0x78FC, //CJK UNIFIED IDEOGRAPH + 0xB493: 0x78FD, //CJK UNIFIED IDEOGRAPH + 0xB494: 0x78FE, //CJK UNIFIED IDEOGRAPH + 0xB495: 0x78FF, //CJK UNIFIED IDEOGRAPH + 0xB496: 0x7900, //CJK UNIFIED IDEOGRAPH + 0xB497: 0x7902, //CJK UNIFIED IDEOGRAPH + 0xB498: 0x7903, //CJK UNIFIED IDEOGRAPH + 0xB499: 0x7904, //CJK UNIFIED IDEOGRAPH + 0xB49A: 0x7906, //CJK UNIFIED IDEOGRAPH + 0xB49B: 0x7907, //CJK UNIFIED IDEOGRAPH + 0xB49C: 0x7908, //CJK UNIFIED IDEOGRAPH + 0xB49D: 0x7909, //CJK UNIFIED IDEOGRAPH + 0xB49E: 0x790A, //CJK UNIFIED IDEOGRAPH + 0xB49F: 0x790B, //CJK UNIFIED IDEOGRAPH + 0xB4A0: 0x790C, //CJK UNIFIED IDEOGRAPH + 0xB4A1: 0x7840, //CJK UNIFIED IDEOGRAPH + 0xB4A2: 0x50A8, //CJK UNIFIED IDEOGRAPH + 0xB4A3: 0x77D7, //CJK UNIFIED IDEOGRAPH + 0xB4A4: 0x6410, //CJK UNIFIED IDEOGRAPH + 0xB4A5: 0x89E6, //CJK UNIFIED IDEOGRAPH + 0xB4A6: 0x5904, //CJK UNIFIED IDEOGRAPH + 0xB4A7: 0x63E3, //CJK UNIFIED IDEOGRAPH + 0xB4A8: 0x5DDD, //CJK UNIFIED IDEOGRAPH + 0xB4A9: 0x7A7F, //CJK UNIFIED IDEOGRAPH + 0xB4AA: 0x693D, //CJK UNIFIED IDEOGRAPH + 0xB4AB: 0x4F20, //CJK UNIFIED IDEOGRAPH + 0xB4AC: 0x8239, //CJK UNIFIED IDEOGRAPH + 0xB4AD: 0x5598, //CJK UNIFIED IDEOGRAPH + 0xB4AE: 0x4E32, //CJK UNIFIED IDEOGRAPH + 0xB4AF: 0x75AE, //CJK UNIFIED IDEOGRAPH + 0xB4B0: 0x7A97, //CJK UNIFIED IDEOGRAPH + 0xB4B1: 0x5E62, //CJK UNIFIED IDEOGRAPH + 0xB4B2: 0x5E8A, //CJK UNIFIED IDEOGRAPH + 0xB4B3: 0x95EF, //CJK UNIFIED IDEOGRAPH + 0xB4B4: 0x521B, //CJK UNIFIED IDEOGRAPH + 0xB4B5: 0x5439, //CJK UNIFIED IDEOGRAPH + 0xB4B6: 0x708A, //CJK UNIFIED IDEOGRAPH + 0xB4B7: 0x6376, //CJK UNIFIED IDEOGRAPH + 0xB4B8: 0x9524, //CJK UNIFIED IDEOGRAPH + 0xB4B9: 0x5782, //CJK UNIFIED IDEOGRAPH + 0xB4BA: 0x6625, //CJK UNIFIED IDEOGRAPH + 0xB4BB: 0x693F, //CJK UNIFIED IDEOGRAPH + 0xB4BC: 0x9187, //CJK UNIFIED IDEOGRAPH + 0xB4BD: 0x5507, //CJK UNIFIED IDEOGRAPH + 0xB4BE: 0x6DF3, //CJK UNIFIED IDEOGRAPH + 0xB4BF: 0x7EAF, //CJK UNIFIED IDEOGRAPH + 0xB4C0: 0x8822, //CJK UNIFIED IDEOGRAPH + 0xB4C1: 0x6233, //CJK UNIFIED IDEOGRAPH + 0xB4C2: 0x7EF0, //CJK UNIFIED IDEOGRAPH + 0xB4C3: 0x75B5, //CJK UNIFIED IDEOGRAPH + 0xB4C4: 0x8328, //CJK UNIFIED IDEOGRAPH + 0xB4C5: 0x78C1, //CJK UNIFIED IDEOGRAPH + 0xB4C6: 0x96CC, //CJK UNIFIED IDEOGRAPH + 0xB4C7: 0x8F9E, //CJK UNIFIED IDEOGRAPH + 0xB4C8: 0x6148, //CJK UNIFIED IDEOGRAPH + 0xB4C9: 0x74F7, //CJK UNIFIED IDEOGRAPH + 0xB4CA: 0x8BCD, //CJK UNIFIED IDEOGRAPH + 0xB4CB: 0x6B64, //CJK UNIFIED IDEOGRAPH + 0xB4CC: 0x523A, //CJK UNIFIED IDEOGRAPH + 0xB4CD: 0x8D50, //CJK UNIFIED IDEOGRAPH + 0xB4CE: 0x6B21, //CJK UNIFIED IDEOGRAPH + 0xB4CF: 0x806A, //CJK UNIFIED IDEOGRAPH + 0xB4D0: 0x8471, //CJK UNIFIED IDEOGRAPH + 0xB4D1: 0x56F1, //CJK UNIFIED IDEOGRAPH + 0xB4D2: 0x5306, //CJK UNIFIED IDEOGRAPH + 0xB4D3: 0x4ECE, //CJK UNIFIED IDEOGRAPH + 0xB4D4: 0x4E1B, //CJK UNIFIED IDEOGRAPH + 0xB4D5: 0x51D1, //CJK UNIFIED IDEOGRAPH + 0xB4D6: 0x7C97, //CJK UNIFIED IDEOGRAPH + 0xB4D7: 0x918B, //CJK UNIFIED IDEOGRAPH + 0xB4D8: 0x7C07, //CJK UNIFIED IDEOGRAPH + 0xB4D9: 0x4FC3, //CJK UNIFIED IDEOGRAPH + 0xB4DA: 0x8E7F, //CJK UNIFIED IDEOGRAPH + 0xB4DB: 0x7BE1, //CJK UNIFIED IDEOGRAPH + 0xB4DC: 0x7A9C, //CJK UNIFIED IDEOGRAPH + 0xB4DD: 0x6467, //CJK UNIFIED IDEOGRAPH + 0xB4DE: 0x5D14, //CJK UNIFIED IDEOGRAPH + 0xB4DF: 0x50AC, //CJK UNIFIED IDEOGRAPH + 0xB4E0: 0x8106, //CJK UNIFIED IDEOGRAPH + 0xB4E1: 0x7601, //CJK UNIFIED IDEOGRAPH + 0xB4E2: 0x7CB9, //CJK UNIFIED IDEOGRAPH + 0xB4E3: 0x6DEC, //CJK UNIFIED IDEOGRAPH + 0xB4E4: 0x7FE0, //CJK UNIFIED IDEOGRAPH + 0xB4E5: 0x6751, //CJK UNIFIED IDEOGRAPH + 0xB4E6: 0x5B58, //CJK UNIFIED IDEOGRAPH + 0xB4E7: 0x5BF8, //CJK UNIFIED IDEOGRAPH + 0xB4E8: 0x78CB, //CJK UNIFIED IDEOGRAPH + 0xB4E9: 0x64AE, //CJK UNIFIED IDEOGRAPH + 0xB4EA: 0x6413, //CJK UNIFIED IDEOGRAPH + 0xB4EB: 0x63AA, //CJK UNIFIED IDEOGRAPH + 0xB4EC: 0x632B, //CJK UNIFIED IDEOGRAPH + 0xB4ED: 0x9519, //CJK UNIFIED IDEOGRAPH + 0xB4EE: 0x642D, //CJK UNIFIED IDEOGRAPH + 0xB4EF: 0x8FBE, //CJK UNIFIED IDEOGRAPH + 0xB4F0: 0x7B54, //CJK UNIFIED IDEOGRAPH + 0xB4F1: 0x7629, //CJK UNIFIED IDEOGRAPH + 0xB4F2: 0x6253, //CJK UNIFIED IDEOGRAPH + 0xB4F3: 0x5927, //CJK UNIFIED IDEOGRAPH + 0xB4F4: 0x5446, //CJK UNIFIED IDEOGRAPH + 0xB4F5: 0x6B79, //CJK UNIFIED IDEOGRAPH + 0xB4F6: 0x50A3, //CJK UNIFIED IDEOGRAPH + 0xB4F7: 0x6234, //CJK UNIFIED IDEOGRAPH + 0xB4F8: 0x5E26, //CJK UNIFIED IDEOGRAPH + 0xB4F9: 0x6B86, //CJK UNIFIED IDEOGRAPH + 0xB4FA: 0x4EE3, //CJK UNIFIED IDEOGRAPH + 0xB4FB: 0x8D37, //CJK UNIFIED IDEOGRAPH + 0xB4FC: 0x888B, //CJK UNIFIED IDEOGRAPH + 0xB4FD: 0x5F85, //CJK UNIFIED IDEOGRAPH + 0xB4FE: 0x902E, //CJK UNIFIED IDEOGRAPH + 0xB540: 0x790D, //CJK UNIFIED IDEOGRAPH + 0xB541: 0x790E, //CJK UNIFIED IDEOGRAPH + 0xB542: 0x790F, //CJK UNIFIED IDEOGRAPH + 0xB543: 0x7910, //CJK UNIFIED IDEOGRAPH + 0xB544: 0x7911, //CJK UNIFIED IDEOGRAPH + 0xB545: 0x7912, //CJK UNIFIED IDEOGRAPH + 0xB546: 0x7914, //CJK UNIFIED IDEOGRAPH + 0xB547: 0x7915, //CJK UNIFIED IDEOGRAPH + 0xB548: 0x7916, //CJK UNIFIED IDEOGRAPH + 0xB549: 0x7917, //CJK UNIFIED IDEOGRAPH + 0xB54A: 0x7918, //CJK UNIFIED IDEOGRAPH + 0xB54B: 0x7919, //CJK UNIFIED IDEOGRAPH + 0xB54C: 0x791A, //CJK UNIFIED IDEOGRAPH + 0xB54D: 0x791B, //CJK UNIFIED IDEOGRAPH + 0xB54E: 0x791C, //CJK UNIFIED IDEOGRAPH + 0xB54F: 0x791D, //CJK UNIFIED IDEOGRAPH + 0xB550: 0x791F, //CJK UNIFIED IDEOGRAPH + 0xB551: 0x7920, //CJK UNIFIED IDEOGRAPH + 0xB552: 0x7921, //CJK UNIFIED IDEOGRAPH + 0xB553: 0x7922, //CJK UNIFIED IDEOGRAPH + 0xB554: 0x7923, //CJK UNIFIED IDEOGRAPH + 0xB555: 0x7925, //CJK UNIFIED IDEOGRAPH + 0xB556: 0x7926, //CJK UNIFIED IDEOGRAPH + 0xB557: 0x7927, //CJK UNIFIED IDEOGRAPH + 0xB558: 0x7928, //CJK UNIFIED IDEOGRAPH + 0xB559: 0x7929, //CJK UNIFIED IDEOGRAPH + 0xB55A: 0x792A, //CJK UNIFIED IDEOGRAPH + 0xB55B: 0x792B, //CJK UNIFIED IDEOGRAPH + 0xB55C: 0x792C, //CJK UNIFIED IDEOGRAPH + 0xB55D: 0x792D, //CJK UNIFIED IDEOGRAPH + 0xB55E: 0x792E, //CJK UNIFIED IDEOGRAPH + 0xB55F: 0x792F, //CJK UNIFIED IDEOGRAPH + 0xB560: 0x7930, //CJK UNIFIED IDEOGRAPH + 0xB561: 0x7931, //CJK UNIFIED IDEOGRAPH + 0xB562: 0x7932, //CJK UNIFIED IDEOGRAPH + 0xB563: 0x7933, //CJK UNIFIED IDEOGRAPH + 0xB564: 0x7935, //CJK UNIFIED IDEOGRAPH + 0xB565: 0x7936, //CJK UNIFIED IDEOGRAPH + 0xB566: 0x7937, //CJK UNIFIED IDEOGRAPH + 0xB567: 0x7938, //CJK UNIFIED IDEOGRAPH + 0xB568: 0x7939, //CJK UNIFIED IDEOGRAPH + 0xB569: 0x793D, //CJK UNIFIED IDEOGRAPH + 0xB56A: 0x793F, //CJK UNIFIED IDEOGRAPH + 0xB56B: 0x7942, //CJK UNIFIED IDEOGRAPH + 0xB56C: 0x7943, //CJK UNIFIED IDEOGRAPH + 0xB56D: 0x7944, //CJK UNIFIED IDEOGRAPH + 0xB56E: 0x7945, //CJK UNIFIED IDEOGRAPH + 0xB56F: 0x7947, //CJK UNIFIED IDEOGRAPH + 0xB570: 0x794A, //CJK UNIFIED IDEOGRAPH + 0xB571: 0x794B, //CJK UNIFIED IDEOGRAPH + 0xB572: 0x794C, //CJK UNIFIED IDEOGRAPH + 0xB573: 0x794D, //CJK UNIFIED IDEOGRAPH + 0xB574: 0x794E, //CJK UNIFIED IDEOGRAPH + 0xB575: 0x794F, //CJK UNIFIED IDEOGRAPH + 0xB576: 0x7950, //CJK UNIFIED IDEOGRAPH + 0xB577: 0x7951, //CJK UNIFIED IDEOGRAPH + 0xB578: 0x7952, //CJK UNIFIED IDEOGRAPH + 0xB579: 0x7954, //CJK UNIFIED IDEOGRAPH + 0xB57A: 0x7955, //CJK UNIFIED IDEOGRAPH + 0xB57B: 0x7958, //CJK UNIFIED IDEOGRAPH + 0xB57C: 0x7959, //CJK UNIFIED IDEOGRAPH + 0xB57D: 0x7961, //CJK UNIFIED IDEOGRAPH + 0xB57E: 0x7963, //CJK UNIFIED IDEOGRAPH + 0xB580: 0x7964, //CJK UNIFIED IDEOGRAPH + 0xB581: 0x7966, //CJK UNIFIED IDEOGRAPH + 0xB582: 0x7969, //CJK UNIFIED IDEOGRAPH + 0xB583: 0x796A, //CJK UNIFIED IDEOGRAPH + 0xB584: 0x796B, //CJK UNIFIED IDEOGRAPH + 0xB585: 0x796C, //CJK UNIFIED IDEOGRAPH + 0xB586: 0x796E, //CJK UNIFIED IDEOGRAPH + 0xB587: 0x7970, //CJK UNIFIED IDEOGRAPH + 0xB588: 0x7971, //CJK UNIFIED IDEOGRAPH + 0xB589: 0x7972, //CJK UNIFIED IDEOGRAPH + 0xB58A: 0x7973, //CJK UNIFIED IDEOGRAPH + 0xB58B: 0x7974, //CJK UNIFIED IDEOGRAPH + 0xB58C: 0x7975, //CJK UNIFIED IDEOGRAPH + 0xB58D: 0x7976, //CJK UNIFIED IDEOGRAPH + 0xB58E: 0x7979, //CJK UNIFIED IDEOGRAPH + 0xB58F: 0x797B, //CJK UNIFIED IDEOGRAPH + 0xB590: 0x797C, //CJK UNIFIED IDEOGRAPH + 0xB591: 0x797D, //CJK UNIFIED IDEOGRAPH + 0xB592: 0x797E, //CJK UNIFIED IDEOGRAPH + 0xB593: 0x797F, //CJK UNIFIED IDEOGRAPH + 0xB594: 0x7982, //CJK UNIFIED IDEOGRAPH + 0xB595: 0x7983, //CJK UNIFIED IDEOGRAPH + 0xB596: 0x7986, //CJK UNIFIED IDEOGRAPH + 0xB597: 0x7987, //CJK UNIFIED IDEOGRAPH + 0xB598: 0x7988, //CJK UNIFIED IDEOGRAPH + 0xB599: 0x7989, //CJK UNIFIED IDEOGRAPH + 0xB59A: 0x798B, //CJK UNIFIED IDEOGRAPH + 0xB59B: 0x798C, //CJK UNIFIED IDEOGRAPH + 0xB59C: 0x798D, //CJK UNIFIED IDEOGRAPH + 0xB59D: 0x798E, //CJK UNIFIED IDEOGRAPH + 0xB59E: 0x7990, //CJK UNIFIED IDEOGRAPH + 0xB59F: 0x7991, //CJK UNIFIED IDEOGRAPH + 0xB5A0: 0x7992, //CJK UNIFIED IDEOGRAPH + 0xB5A1: 0x6020, //CJK UNIFIED IDEOGRAPH + 0xB5A2: 0x803D, //CJK UNIFIED IDEOGRAPH + 0xB5A3: 0x62C5, //CJK UNIFIED IDEOGRAPH + 0xB5A4: 0x4E39, //CJK UNIFIED IDEOGRAPH + 0xB5A5: 0x5355, //CJK UNIFIED IDEOGRAPH + 0xB5A6: 0x90F8, //CJK UNIFIED IDEOGRAPH + 0xB5A7: 0x63B8, //CJK UNIFIED IDEOGRAPH + 0xB5A8: 0x80C6, //CJK UNIFIED IDEOGRAPH + 0xB5A9: 0x65E6, //CJK UNIFIED IDEOGRAPH + 0xB5AA: 0x6C2E, //CJK UNIFIED IDEOGRAPH + 0xB5AB: 0x4F46, //CJK UNIFIED IDEOGRAPH + 0xB5AC: 0x60EE, //CJK UNIFIED IDEOGRAPH + 0xB5AD: 0x6DE1, //CJK UNIFIED IDEOGRAPH + 0xB5AE: 0x8BDE, //CJK UNIFIED IDEOGRAPH + 0xB5AF: 0x5F39, //CJK UNIFIED IDEOGRAPH + 0xB5B0: 0x86CB, //CJK UNIFIED IDEOGRAPH + 0xB5B1: 0x5F53, //CJK UNIFIED IDEOGRAPH + 0xB5B2: 0x6321, //CJK UNIFIED IDEOGRAPH + 0xB5B3: 0x515A, //CJK UNIFIED IDEOGRAPH + 0xB5B4: 0x8361, //CJK UNIFIED IDEOGRAPH + 0xB5B5: 0x6863, //CJK UNIFIED IDEOGRAPH + 0xB5B6: 0x5200, //CJK UNIFIED IDEOGRAPH + 0xB5B7: 0x6363, //CJK UNIFIED IDEOGRAPH + 0xB5B8: 0x8E48, //CJK UNIFIED IDEOGRAPH + 0xB5B9: 0x5012, //CJK UNIFIED IDEOGRAPH + 0xB5BA: 0x5C9B, //CJK UNIFIED IDEOGRAPH + 0xB5BB: 0x7977, //CJK UNIFIED IDEOGRAPH + 0xB5BC: 0x5BFC, //CJK UNIFIED IDEOGRAPH + 0xB5BD: 0x5230, //CJK UNIFIED IDEOGRAPH + 0xB5BE: 0x7A3B, //CJK UNIFIED IDEOGRAPH + 0xB5BF: 0x60BC, //CJK UNIFIED IDEOGRAPH + 0xB5C0: 0x9053, //CJK UNIFIED IDEOGRAPH + 0xB5C1: 0x76D7, //CJK UNIFIED IDEOGRAPH + 0xB5C2: 0x5FB7, //CJK UNIFIED IDEOGRAPH + 0xB5C3: 0x5F97, //CJK UNIFIED IDEOGRAPH + 0xB5C4: 0x7684, //CJK UNIFIED IDEOGRAPH + 0xB5C5: 0x8E6C, //CJK UNIFIED IDEOGRAPH + 0xB5C6: 0x706F, //CJK UNIFIED IDEOGRAPH + 0xB5C7: 0x767B, //CJK UNIFIED IDEOGRAPH + 0xB5C8: 0x7B49, //CJK UNIFIED IDEOGRAPH + 0xB5C9: 0x77AA, //CJK UNIFIED IDEOGRAPH + 0xB5CA: 0x51F3, //CJK UNIFIED IDEOGRAPH + 0xB5CB: 0x9093, //CJK UNIFIED IDEOGRAPH + 0xB5CC: 0x5824, //CJK UNIFIED IDEOGRAPH + 0xB5CD: 0x4F4E, //CJK UNIFIED IDEOGRAPH + 0xB5CE: 0x6EF4, //CJK UNIFIED IDEOGRAPH + 0xB5CF: 0x8FEA, //CJK UNIFIED IDEOGRAPH + 0xB5D0: 0x654C, //CJK UNIFIED IDEOGRAPH + 0xB5D1: 0x7B1B, //CJK UNIFIED IDEOGRAPH + 0xB5D2: 0x72C4, //CJK UNIFIED IDEOGRAPH + 0xB5D3: 0x6DA4, //CJK UNIFIED IDEOGRAPH + 0xB5D4: 0x7FDF, //CJK UNIFIED IDEOGRAPH + 0xB5D5: 0x5AE1, //CJK UNIFIED IDEOGRAPH + 0xB5D6: 0x62B5, //CJK UNIFIED IDEOGRAPH + 0xB5D7: 0x5E95, //CJK UNIFIED IDEOGRAPH + 0xB5D8: 0x5730, //CJK UNIFIED IDEOGRAPH + 0xB5D9: 0x8482, //CJK UNIFIED IDEOGRAPH + 0xB5DA: 0x7B2C, //CJK UNIFIED IDEOGRAPH + 0xB5DB: 0x5E1D, //CJK UNIFIED IDEOGRAPH + 0xB5DC: 0x5F1F, //CJK UNIFIED IDEOGRAPH + 0xB5DD: 0x9012, //CJK UNIFIED IDEOGRAPH + 0xB5DE: 0x7F14, //CJK UNIFIED IDEOGRAPH + 0xB5DF: 0x98A0, //CJK UNIFIED IDEOGRAPH + 0xB5E0: 0x6382, //CJK UNIFIED IDEOGRAPH + 0xB5E1: 0x6EC7, //CJK UNIFIED IDEOGRAPH + 0xB5E2: 0x7898, //CJK UNIFIED IDEOGRAPH + 0xB5E3: 0x70B9, //CJK UNIFIED IDEOGRAPH + 0xB5E4: 0x5178, //CJK UNIFIED IDEOGRAPH + 0xB5E5: 0x975B, //CJK UNIFIED IDEOGRAPH + 0xB5E6: 0x57AB, //CJK UNIFIED IDEOGRAPH + 0xB5E7: 0x7535, //CJK UNIFIED IDEOGRAPH + 0xB5E8: 0x4F43, //CJK UNIFIED IDEOGRAPH + 0xB5E9: 0x7538, //CJK UNIFIED IDEOGRAPH + 0xB5EA: 0x5E97, //CJK UNIFIED IDEOGRAPH + 0xB5EB: 0x60E6, //CJK UNIFIED IDEOGRAPH + 0xB5EC: 0x5960, //CJK UNIFIED IDEOGRAPH + 0xB5ED: 0x6DC0, //CJK UNIFIED IDEOGRAPH + 0xB5EE: 0x6BBF, //CJK UNIFIED IDEOGRAPH + 0xB5EF: 0x7889, //CJK UNIFIED IDEOGRAPH + 0xB5F0: 0x53FC, //CJK UNIFIED IDEOGRAPH + 0xB5F1: 0x96D5, //CJK UNIFIED IDEOGRAPH + 0xB5F2: 0x51CB, //CJK UNIFIED IDEOGRAPH + 0xB5F3: 0x5201, //CJK UNIFIED IDEOGRAPH + 0xB5F4: 0x6389, //CJK UNIFIED IDEOGRAPH + 0xB5F5: 0x540A, //CJK UNIFIED IDEOGRAPH + 0xB5F6: 0x9493, //CJK UNIFIED IDEOGRAPH + 0xB5F7: 0x8C03, //CJK UNIFIED IDEOGRAPH + 0xB5F8: 0x8DCC, //CJK UNIFIED IDEOGRAPH + 0xB5F9: 0x7239, //CJK UNIFIED IDEOGRAPH + 0xB5FA: 0x789F, //CJK UNIFIED IDEOGRAPH + 0xB5FB: 0x8776, //CJK UNIFIED IDEOGRAPH + 0xB5FC: 0x8FED, //CJK UNIFIED IDEOGRAPH + 0xB5FD: 0x8C0D, //CJK UNIFIED IDEOGRAPH + 0xB5FE: 0x53E0, //CJK UNIFIED IDEOGRAPH + 0xB640: 0x7993, //CJK UNIFIED IDEOGRAPH + 0xB641: 0x7994, //CJK UNIFIED IDEOGRAPH + 0xB642: 0x7995, //CJK UNIFIED IDEOGRAPH + 0xB643: 0x7996, //CJK UNIFIED IDEOGRAPH + 0xB644: 0x7997, //CJK UNIFIED IDEOGRAPH + 0xB645: 0x7998, //CJK UNIFIED IDEOGRAPH + 0xB646: 0x7999, //CJK UNIFIED IDEOGRAPH + 0xB647: 0x799B, //CJK UNIFIED IDEOGRAPH + 0xB648: 0x799C, //CJK UNIFIED IDEOGRAPH + 0xB649: 0x799D, //CJK UNIFIED IDEOGRAPH + 0xB64A: 0x799E, //CJK UNIFIED IDEOGRAPH + 0xB64B: 0x799F, //CJK UNIFIED IDEOGRAPH + 0xB64C: 0x79A0, //CJK UNIFIED IDEOGRAPH + 0xB64D: 0x79A1, //CJK UNIFIED IDEOGRAPH + 0xB64E: 0x79A2, //CJK UNIFIED IDEOGRAPH + 0xB64F: 0x79A3, //CJK UNIFIED IDEOGRAPH + 0xB650: 0x79A4, //CJK UNIFIED IDEOGRAPH + 0xB651: 0x79A5, //CJK UNIFIED IDEOGRAPH + 0xB652: 0x79A6, //CJK UNIFIED IDEOGRAPH + 0xB653: 0x79A8, //CJK UNIFIED IDEOGRAPH + 0xB654: 0x79A9, //CJK UNIFIED IDEOGRAPH + 0xB655: 0x79AA, //CJK UNIFIED IDEOGRAPH + 0xB656: 0x79AB, //CJK UNIFIED IDEOGRAPH + 0xB657: 0x79AC, //CJK UNIFIED IDEOGRAPH + 0xB658: 0x79AD, //CJK UNIFIED IDEOGRAPH + 0xB659: 0x79AE, //CJK UNIFIED IDEOGRAPH + 0xB65A: 0x79AF, //CJK UNIFIED IDEOGRAPH + 0xB65B: 0x79B0, //CJK UNIFIED IDEOGRAPH + 0xB65C: 0x79B1, //CJK UNIFIED IDEOGRAPH + 0xB65D: 0x79B2, //CJK UNIFIED IDEOGRAPH + 0xB65E: 0x79B4, //CJK UNIFIED IDEOGRAPH + 0xB65F: 0x79B5, //CJK UNIFIED IDEOGRAPH + 0xB660: 0x79B6, //CJK UNIFIED IDEOGRAPH + 0xB661: 0x79B7, //CJK UNIFIED IDEOGRAPH + 0xB662: 0x79B8, //CJK UNIFIED IDEOGRAPH + 0xB663: 0x79BC, //CJK UNIFIED IDEOGRAPH + 0xB664: 0x79BF, //CJK UNIFIED IDEOGRAPH + 0xB665: 0x79C2, //CJK UNIFIED IDEOGRAPH + 0xB666: 0x79C4, //CJK UNIFIED IDEOGRAPH + 0xB667: 0x79C5, //CJK UNIFIED IDEOGRAPH + 0xB668: 0x79C7, //CJK UNIFIED IDEOGRAPH + 0xB669: 0x79C8, //CJK UNIFIED IDEOGRAPH + 0xB66A: 0x79CA, //CJK UNIFIED IDEOGRAPH + 0xB66B: 0x79CC, //CJK UNIFIED IDEOGRAPH + 0xB66C: 0x79CE, //CJK UNIFIED IDEOGRAPH + 0xB66D: 0x79CF, //CJK UNIFIED IDEOGRAPH + 0xB66E: 0x79D0, //CJK UNIFIED IDEOGRAPH + 0xB66F: 0x79D3, //CJK UNIFIED IDEOGRAPH + 0xB670: 0x79D4, //CJK UNIFIED IDEOGRAPH + 0xB671: 0x79D6, //CJK UNIFIED IDEOGRAPH + 0xB672: 0x79D7, //CJK UNIFIED IDEOGRAPH + 0xB673: 0x79D9, //CJK UNIFIED IDEOGRAPH + 0xB674: 0x79DA, //CJK UNIFIED IDEOGRAPH + 0xB675: 0x79DB, //CJK UNIFIED IDEOGRAPH + 0xB676: 0x79DC, //CJK UNIFIED IDEOGRAPH + 0xB677: 0x79DD, //CJK UNIFIED IDEOGRAPH + 0xB678: 0x79DE, //CJK UNIFIED IDEOGRAPH + 0xB679: 0x79E0, //CJK UNIFIED IDEOGRAPH + 0xB67A: 0x79E1, //CJK UNIFIED IDEOGRAPH + 0xB67B: 0x79E2, //CJK UNIFIED IDEOGRAPH + 0xB67C: 0x79E5, //CJK UNIFIED IDEOGRAPH + 0xB67D: 0x79E8, //CJK UNIFIED IDEOGRAPH + 0xB67E: 0x79EA, //CJK UNIFIED IDEOGRAPH + 0xB680: 0x79EC, //CJK UNIFIED IDEOGRAPH + 0xB681: 0x79EE, //CJK UNIFIED IDEOGRAPH + 0xB682: 0x79F1, //CJK UNIFIED IDEOGRAPH + 0xB683: 0x79F2, //CJK UNIFIED IDEOGRAPH + 0xB684: 0x79F3, //CJK UNIFIED IDEOGRAPH + 0xB685: 0x79F4, //CJK UNIFIED IDEOGRAPH + 0xB686: 0x79F5, //CJK UNIFIED IDEOGRAPH + 0xB687: 0x79F6, //CJK UNIFIED IDEOGRAPH + 0xB688: 0x79F7, //CJK UNIFIED IDEOGRAPH + 0xB689: 0x79F9, //CJK UNIFIED IDEOGRAPH + 0xB68A: 0x79FA, //CJK UNIFIED IDEOGRAPH + 0xB68B: 0x79FC, //CJK UNIFIED IDEOGRAPH + 0xB68C: 0x79FE, //CJK UNIFIED IDEOGRAPH + 0xB68D: 0x79FF, //CJK UNIFIED IDEOGRAPH + 0xB68E: 0x7A01, //CJK UNIFIED IDEOGRAPH + 0xB68F: 0x7A04, //CJK UNIFIED IDEOGRAPH + 0xB690: 0x7A05, //CJK UNIFIED IDEOGRAPH + 0xB691: 0x7A07, //CJK UNIFIED IDEOGRAPH + 0xB692: 0x7A08, //CJK UNIFIED IDEOGRAPH + 0xB693: 0x7A09, //CJK UNIFIED IDEOGRAPH + 0xB694: 0x7A0A, //CJK UNIFIED IDEOGRAPH + 0xB695: 0x7A0C, //CJK UNIFIED IDEOGRAPH + 0xB696: 0x7A0F, //CJK UNIFIED IDEOGRAPH + 0xB697: 0x7A10, //CJK UNIFIED IDEOGRAPH + 0xB698: 0x7A11, //CJK UNIFIED IDEOGRAPH + 0xB699: 0x7A12, //CJK UNIFIED IDEOGRAPH + 0xB69A: 0x7A13, //CJK UNIFIED IDEOGRAPH + 0xB69B: 0x7A15, //CJK UNIFIED IDEOGRAPH + 0xB69C: 0x7A16, //CJK UNIFIED IDEOGRAPH + 0xB69D: 0x7A18, //CJK UNIFIED IDEOGRAPH + 0xB69E: 0x7A19, //CJK UNIFIED IDEOGRAPH + 0xB69F: 0x7A1B, //CJK UNIFIED IDEOGRAPH + 0xB6A0: 0x7A1C, //CJK UNIFIED IDEOGRAPH + 0xB6A1: 0x4E01, //CJK UNIFIED IDEOGRAPH + 0xB6A2: 0x76EF, //CJK UNIFIED IDEOGRAPH + 0xB6A3: 0x53EE, //CJK UNIFIED IDEOGRAPH + 0xB6A4: 0x9489, //CJK UNIFIED IDEOGRAPH + 0xB6A5: 0x9876, //CJK UNIFIED IDEOGRAPH + 0xB6A6: 0x9F0E, //CJK UNIFIED IDEOGRAPH + 0xB6A7: 0x952D, //CJK UNIFIED IDEOGRAPH + 0xB6A8: 0x5B9A, //CJK UNIFIED IDEOGRAPH + 0xB6A9: 0x8BA2, //CJK UNIFIED IDEOGRAPH + 0xB6AA: 0x4E22, //CJK UNIFIED IDEOGRAPH + 0xB6AB: 0x4E1C, //CJK UNIFIED IDEOGRAPH + 0xB6AC: 0x51AC, //CJK UNIFIED IDEOGRAPH + 0xB6AD: 0x8463, //CJK UNIFIED IDEOGRAPH + 0xB6AE: 0x61C2, //CJK UNIFIED IDEOGRAPH + 0xB6AF: 0x52A8, //CJK UNIFIED IDEOGRAPH + 0xB6B0: 0x680B, //CJK UNIFIED IDEOGRAPH + 0xB6B1: 0x4F97, //CJK UNIFIED IDEOGRAPH + 0xB6B2: 0x606B, //CJK UNIFIED IDEOGRAPH + 0xB6B3: 0x51BB, //CJK UNIFIED IDEOGRAPH + 0xB6B4: 0x6D1E, //CJK UNIFIED IDEOGRAPH + 0xB6B5: 0x515C, //CJK UNIFIED IDEOGRAPH + 0xB6B6: 0x6296, //CJK UNIFIED IDEOGRAPH + 0xB6B7: 0x6597, //CJK UNIFIED IDEOGRAPH + 0xB6B8: 0x9661, //CJK UNIFIED IDEOGRAPH + 0xB6B9: 0x8C46, //CJK UNIFIED IDEOGRAPH + 0xB6BA: 0x9017, //CJK UNIFIED IDEOGRAPH + 0xB6BB: 0x75D8, //CJK UNIFIED IDEOGRAPH + 0xB6BC: 0x90FD, //CJK UNIFIED IDEOGRAPH + 0xB6BD: 0x7763, //CJK UNIFIED IDEOGRAPH + 0xB6BE: 0x6BD2, //CJK UNIFIED IDEOGRAPH + 0xB6BF: 0x728A, //CJK UNIFIED IDEOGRAPH + 0xB6C0: 0x72EC, //CJK UNIFIED IDEOGRAPH + 0xB6C1: 0x8BFB, //CJK UNIFIED IDEOGRAPH + 0xB6C2: 0x5835, //CJK UNIFIED IDEOGRAPH + 0xB6C3: 0x7779, //CJK UNIFIED IDEOGRAPH + 0xB6C4: 0x8D4C, //CJK UNIFIED IDEOGRAPH + 0xB6C5: 0x675C, //CJK UNIFIED IDEOGRAPH + 0xB6C6: 0x9540, //CJK UNIFIED IDEOGRAPH + 0xB6C7: 0x809A, //CJK UNIFIED IDEOGRAPH + 0xB6C8: 0x5EA6, //CJK UNIFIED IDEOGRAPH + 0xB6C9: 0x6E21, //CJK UNIFIED IDEOGRAPH + 0xB6CA: 0x5992, //CJK UNIFIED IDEOGRAPH + 0xB6CB: 0x7AEF, //CJK UNIFIED IDEOGRAPH + 0xB6CC: 0x77ED, //CJK UNIFIED IDEOGRAPH + 0xB6CD: 0x953B, //CJK UNIFIED IDEOGRAPH + 0xB6CE: 0x6BB5, //CJK UNIFIED IDEOGRAPH + 0xB6CF: 0x65AD, //CJK UNIFIED IDEOGRAPH + 0xB6D0: 0x7F0E, //CJK UNIFIED IDEOGRAPH + 0xB6D1: 0x5806, //CJK UNIFIED IDEOGRAPH + 0xB6D2: 0x5151, //CJK UNIFIED IDEOGRAPH + 0xB6D3: 0x961F, //CJK UNIFIED IDEOGRAPH + 0xB6D4: 0x5BF9, //CJK UNIFIED IDEOGRAPH + 0xB6D5: 0x58A9, //CJK UNIFIED IDEOGRAPH + 0xB6D6: 0x5428, //CJK UNIFIED IDEOGRAPH + 0xB6D7: 0x8E72, //CJK UNIFIED IDEOGRAPH + 0xB6D8: 0x6566, //CJK UNIFIED IDEOGRAPH + 0xB6D9: 0x987F, //CJK UNIFIED IDEOGRAPH + 0xB6DA: 0x56E4, //CJK UNIFIED IDEOGRAPH + 0xB6DB: 0x949D, //CJK UNIFIED IDEOGRAPH + 0xB6DC: 0x76FE, //CJK UNIFIED IDEOGRAPH + 0xB6DD: 0x9041, //CJK UNIFIED IDEOGRAPH + 0xB6DE: 0x6387, //CJK UNIFIED IDEOGRAPH + 0xB6DF: 0x54C6, //CJK UNIFIED IDEOGRAPH + 0xB6E0: 0x591A, //CJK UNIFIED IDEOGRAPH + 0xB6E1: 0x593A, //CJK UNIFIED IDEOGRAPH + 0xB6E2: 0x579B, //CJK UNIFIED IDEOGRAPH + 0xB6E3: 0x8EB2, //CJK UNIFIED IDEOGRAPH + 0xB6E4: 0x6735, //CJK UNIFIED IDEOGRAPH + 0xB6E5: 0x8DFA, //CJK UNIFIED IDEOGRAPH + 0xB6E6: 0x8235, //CJK UNIFIED IDEOGRAPH + 0xB6E7: 0x5241, //CJK UNIFIED IDEOGRAPH + 0xB6E8: 0x60F0, //CJK UNIFIED IDEOGRAPH + 0xB6E9: 0x5815, //CJK UNIFIED IDEOGRAPH + 0xB6EA: 0x86FE, //CJK UNIFIED IDEOGRAPH + 0xB6EB: 0x5CE8, //CJK UNIFIED IDEOGRAPH + 0xB6EC: 0x9E45, //CJK UNIFIED IDEOGRAPH + 0xB6ED: 0x4FC4, //CJK UNIFIED IDEOGRAPH + 0xB6EE: 0x989D, //CJK UNIFIED IDEOGRAPH + 0xB6EF: 0x8BB9, //CJK UNIFIED IDEOGRAPH + 0xB6F0: 0x5A25, //CJK UNIFIED IDEOGRAPH + 0xB6F1: 0x6076, //CJK UNIFIED IDEOGRAPH + 0xB6F2: 0x5384, //CJK UNIFIED IDEOGRAPH + 0xB6F3: 0x627C, //CJK UNIFIED IDEOGRAPH + 0xB6F4: 0x904F, //CJK UNIFIED IDEOGRAPH + 0xB6F5: 0x9102, //CJK UNIFIED IDEOGRAPH + 0xB6F6: 0x997F, //CJK UNIFIED IDEOGRAPH + 0xB6F7: 0x6069, //CJK UNIFIED IDEOGRAPH + 0xB6F8: 0x800C, //CJK UNIFIED IDEOGRAPH + 0xB6F9: 0x513F, //CJK UNIFIED IDEOGRAPH + 0xB6FA: 0x8033, //CJK UNIFIED IDEOGRAPH + 0xB6FB: 0x5C14, //CJK UNIFIED IDEOGRAPH + 0xB6FC: 0x9975, //CJK UNIFIED IDEOGRAPH + 0xB6FD: 0x6D31, //CJK UNIFIED IDEOGRAPH + 0xB6FE: 0x4E8C, //CJK UNIFIED IDEOGRAPH + 0xB740: 0x7A1D, //CJK UNIFIED IDEOGRAPH + 0xB741: 0x7A1F, //CJK UNIFIED IDEOGRAPH + 0xB742: 0x7A21, //CJK UNIFIED IDEOGRAPH + 0xB743: 0x7A22, //CJK UNIFIED IDEOGRAPH + 0xB744: 0x7A24, //CJK UNIFIED IDEOGRAPH + 0xB745: 0x7A25, //CJK UNIFIED IDEOGRAPH + 0xB746: 0x7A26, //CJK UNIFIED IDEOGRAPH + 0xB747: 0x7A27, //CJK UNIFIED IDEOGRAPH + 0xB748: 0x7A28, //CJK UNIFIED IDEOGRAPH + 0xB749: 0x7A29, //CJK UNIFIED IDEOGRAPH + 0xB74A: 0x7A2A, //CJK UNIFIED IDEOGRAPH + 0xB74B: 0x7A2B, //CJK UNIFIED IDEOGRAPH + 0xB74C: 0x7A2C, //CJK UNIFIED IDEOGRAPH + 0xB74D: 0x7A2D, //CJK UNIFIED IDEOGRAPH + 0xB74E: 0x7A2E, //CJK UNIFIED IDEOGRAPH + 0xB74F: 0x7A2F, //CJK UNIFIED IDEOGRAPH + 0xB750: 0x7A30, //CJK UNIFIED IDEOGRAPH + 0xB751: 0x7A31, //CJK UNIFIED IDEOGRAPH + 0xB752: 0x7A32, //CJK UNIFIED IDEOGRAPH + 0xB753: 0x7A34, //CJK UNIFIED IDEOGRAPH + 0xB754: 0x7A35, //CJK UNIFIED IDEOGRAPH + 0xB755: 0x7A36, //CJK UNIFIED IDEOGRAPH + 0xB756: 0x7A38, //CJK UNIFIED IDEOGRAPH + 0xB757: 0x7A3A, //CJK UNIFIED IDEOGRAPH + 0xB758: 0x7A3E, //CJK UNIFIED IDEOGRAPH + 0xB759: 0x7A40, //CJK UNIFIED IDEOGRAPH + 0xB75A: 0x7A41, //CJK UNIFIED IDEOGRAPH + 0xB75B: 0x7A42, //CJK UNIFIED IDEOGRAPH + 0xB75C: 0x7A43, //CJK UNIFIED IDEOGRAPH + 0xB75D: 0x7A44, //CJK UNIFIED IDEOGRAPH + 0xB75E: 0x7A45, //CJK UNIFIED IDEOGRAPH + 0xB75F: 0x7A47, //CJK UNIFIED IDEOGRAPH + 0xB760: 0x7A48, //CJK UNIFIED IDEOGRAPH + 0xB761: 0x7A49, //CJK UNIFIED IDEOGRAPH + 0xB762: 0x7A4A, //CJK UNIFIED IDEOGRAPH + 0xB763: 0x7A4B, //CJK UNIFIED IDEOGRAPH + 0xB764: 0x7A4C, //CJK UNIFIED IDEOGRAPH + 0xB765: 0x7A4D, //CJK UNIFIED IDEOGRAPH + 0xB766: 0x7A4E, //CJK UNIFIED IDEOGRAPH + 0xB767: 0x7A4F, //CJK UNIFIED IDEOGRAPH + 0xB768: 0x7A50, //CJK UNIFIED IDEOGRAPH + 0xB769: 0x7A52, //CJK UNIFIED IDEOGRAPH + 0xB76A: 0x7A53, //CJK UNIFIED IDEOGRAPH + 0xB76B: 0x7A54, //CJK UNIFIED IDEOGRAPH + 0xB76C: 0x7A55, //CJK UNIFIED IDEOGRAPH + 0xB76D: 0x7A56, //CJK UNIFIED IDEOGRAPH + 0xB76E: 0x7A58, //CJK UNIFIED IDEOGRAPH + 0xB76F: 0x7A59, //CJK UNIFIED IDEOGRAPH + 0xB770: 0x7A5A, //CJK UNIFIED IDEOGRAPH + 0xB771: 0x7A5B, //CJK UNIFIED IDEOGRAPH + 0xB772: 0x7A5C, //CJK UNIFIED IDEOGRAPH + 0xB773: 0x7A5D, //CJK UNIFIED IDEOGRAPH + 0xB774: 0x7A5E, //CJK UNIFIED IDEOGRAPH + 0xB775: 0x7A5F, //CJK UNIFIED IDEOGRAPH + 0xB776: 0x7A60, //CJK UNIFIED IDEOGRAPH + 0xB777: 0x7A61, //CJK UNIFIED IDEOGRAPH + 0xB778: 0x7A62, //CJK UNIFIED IDEOGRAPH + 0xB779: 0x7A63, //CJK UNIFIED IDEOGRAPH + 0xB77A: 0x7A64, //CJK UNIFIED IDEOGRAPH + 0xB77B: 0x7A65, //CJK UNIFIED IDEOGRAPH + 0xB77C: 0x7A66, //CJK UNIFIED IDEOGRAPH + 0xB77D: 0x7A67, //CJK UNIFIED IDEOGRAPH + 0xB77E: 0x7A68, //CJK UNIFIED IDEOGRAPH + 0xB780: 0x7A69, //CJK UNIFIED IDEOGRAPH + 0xB781: 0x7A6A, //CJK UNIFIED IDEOGRAPH + 0xB782: 0x7A6B, //CJK UNIFIED IDEOGRAPH + 0xB783: 0x7A6C, //CJK UNIFIED IDEOGRAPH + 0xB784: 0x7A6D, //CJK UNIFIED IDEOGRAPH + 0xB785: 0x7A6E, //CJK UNIFIED IDEOGRAPH + 0xB786: 0x7A6F, //CJK UNIFIED IDEOGRAPH + 0xB787: 0x7A71, //CJK UNIFIED IDEOGRAPH + 0xB788: 0x7A72, //CJK UNIFIED IDEOGRAPH + 0xB789: 0x7A73, //CJK UNIFIED IDEOGRAPH + 0xB78A: 0x7A75, //CJK UNIFIED IDEOGRAPH + 0xB78B: 0x7A7B, //CJK UNIFIED IDEOGRAPH + 0xB78C: 0x7A7C, //CJK UNIFIED IDEOGRAPH + 0xB78D: 0x7A7D, //CJK UNIFIED IDEOGRAPH + 0xB78E: 0x7A7E, //CJK UNIFIED IDEOGRAPH + 0xB78F: 0x7A82, //CJK UNIFIED IDEOGRAPH + 0xB790: 0x7A85, //CJK UNIFIED IDEOGRAPH + 0xB791: 0x7A87, //CJK UNIFIED IDEOGRAPH + 0xB792: 0x7A89, //CJK UNIFIED IDEOGRAPH + 0xB793: 0x7A8A, //CJK UNIFIED IDEOGRAPH + 0xB794: 0x7A8B, //CJK UNIFIED IDEOGRAPH + 0xB795: 0x7A8C, //CJK UNIFIED IDEOGRAPH + 0xB796: 0x7A8E, //CJK UNIFIED IDEOGRAPH + 0xB797: 0x7A8F, //CJK UNIFIED IDEOGRAPH + 0xB798: 0x7A90, //CJK UNIFIED IDEOGRAPH + 0xB799: 0x7A93, //CJK UNIFIED IDEOGRAPH + 0xB79A: 0x7A94, //CJK UNIFIED IDEOGRAPH + 0xB79B: 0x7A99, //CJK UNIFIED IDEOGRAPH + 0xB79C: 0x7A9A, //CJK UNIFIED IDEOGRAPH + 0xB79D: 0x7A9B, //CJK UNIFIED IDEOGRAPH + 0xB79E: 0x7A9E, //CJK UNIFIED IDEOGRAPH + 0xB79F: 0x7AA1, //CJK UNIFIED IDEOGRAPH + 0xB7A0: 0x7AA2, //CJK UNIFIED IDEOGRAPH + 0xB7A1: 0x8D30, //CJK UNIFIED IDEOGRAPH + 0xB7A2: 0x53D1, //CJK UNIFIED IDEOGRAPH + 0xB7A3: 0x7F5A, //CJK UNIFIED IDEOGRAPH + 0xB7A4: 0x7B4F, //CJK UNIFIED IDEOGRAPH + 0xB7A5: 0x4F10, //CJK UNIFIED IDEOGRAPH + 0xB7A6: 0x4E4F, //CJK UNIFIED IDEOGRAPH + 0xB7A7: 0x9600, //CJK UNIFIED IDEOGRAPH + 0xB7A8: 0x6CD5, //CJK UNIFIED IDEOGRAPH + 0xB7A9: 0x73D0, //CJK UNIFIED IDEOGRAPH + 0xB7AA: 0x85E9, //CJK UNIFIED IDEOGRAPH + 0xB7AB: 0x5E06, //CJK UNIFIED IDEOGRAPH + 0xB7AC: 0x756A, //CJK UNIFIED IDEOGRAPH + 0xB7AD: 0x7FFB, //CJK UNIFIED IDEOGRAPH + 0xB7AE: 0x6A0A, //CJK UNIFIED IDEOGRAPH + 0xB7AF: 0x77FE, //CJK UNIFIED IDEOGRAPH + 0xB7B0: 0x9492, //CJK UNIFIED IDEOGRAPH + 0xB7B1: 0x7E41, //CJK UNIFIED IDEOGRAPH + 0xB7B2: 0x51E1, //CJK UNIFIED IDEOGRAPH + 0xB7B3: 0x70E6, //CJK UNIFIED IDEOGRAPH + 0xB7B4: 0x53CD, //CJK UNIFIED IDEOGRAPH + 0xB7B5: 0x8FD4, //CJK UNIFIED IDEOGRAPH + 0xB7B6: 0x8303, //CJK UNIFIED IDEOGRAPH + 0xB7B7: 0x8D29, //CJK UNIFIED IDEOGRAPH + 0xB7B8: 0x72AF, //CJK UNIFIED IDEOGRAPH + 0xB7B9: 0x996D, //CJK UNIFIED IDEOGRAPH + 0xB7BA: 0x6CDB, //CJK UNIFIED IDEOGRAPH + 0xB7BB: 0x574A, //CJK UNIFIED IDEOGRAPH + 0xB7BC: 0x82B3, //CJK UNIFIED IDEOGRAPH + 0xB7BD: 0x65B9, //CJK UNIFIED IDEOGRAPH + 0xB7BE: 0x80AA, //CJK UNIFIED IDEOGRAPH + 0xB7BF: 0x623F, //CJK UNIFIED IDEOGRAPH + 0xB7C0: 0x9632, //CJK UNIFIED IDEOGRAPH + 0xB7C1: 0x59A8, //CJK UNIFIED IDEOGRAPH + 0xB7C2: 0x4EFF, //CJK UNIFIED IDEOGRAPH + 0xB7C3: 0x8BBF, //CJK UNIFIED IDEOGRAPH + 0xB7C4: 0x7EBA, //CJK UNIFIED IDEOGRAPH + 0xB7C5: 0x653E, //CJK UNIFIED IDEOGRAPH + 0xB7C6: 0x83F2, //CJK UNIFIED IDEOGRAPH + 0xB7C7: 0x975E, //CJK UNIFIED IDEOGRAPH + 0xB7C8: 0x5561, //CJK UNIFIED IDEOGRAPH + 0xB7C9: 0x98DE, //CJK UNIFIED IDEOGRAPH + 0xB7CA: 0x80A5, //CJK UNIFIED IDEOGRAPH + 0xB7CB: 0x532A, //CJK UNIFIED IDEOGRAPH + 0xB7CC: 0x8BFD, //CJK UNIFIED IDEOGRAPH + 0xB7CD: 0x5420, //CJK UNIFIED IDEOGRAPH + 0xB7CE: 0x80BA, //CJK UNIFIED IDEOGRAPH + 0xB7CF: 0x5E9F, //CJK UNIFIED IDEOGRAPH + 0xB7D0: 0x6CB8, //CJK UNIFIED IDEOGRAPH + 0xB7D1: 0x8D39, //CJK UNIFIED IDEOGRAPH + 0xB7D2: 0x82AC, //CJK UNIFIED IDEOGRAPH + 0xB7D3: 0x915A, //CJK UNIFIED IDEOGRAPH + 0xB7D4: 0x5429, //CJK UNIFIED IDEOGRAPH + 0xB7D5: 0x6C1B, //CJK UNIFIED IDEOGRAPH + 0xB7D6: 0x5206, //CJK UNIFIED IDEOGRAPH + 0xB7D7: 0x7EB7, //CJK UNIFIED IDEOGRAPH + 0xB7D8: 0x575F, //CJK UNIFIED IDEOGRAPH + 0xB7D9: 0x711A, //CJK UNIFIED IDEOGRAPH + 0xB7DA: 0x6C7E, //CJK UNIFIED IDEOGRAPH + 0xB7DB: 0x7C89, //CJK UNIFIED IDEOGRAPH + 0xB7DC: 0x594B, //CJK UNIFIED IDEOGRAPH + 0xB7DD: 0x4EFD, //CJK UNIFIED IDEOGRAPH + 0xB7DE: 0x5FFF, //CJK UNIFIED IDEOGRAPH + 0xB7DF: 0x6124, //CJK UNIFIED IDEOGRAPH + 0xB7E0: 0x7CAA, //CJK UNIFIED IDEOGRAPH + 0xB7E1: 0x4E30, //CJK UNIFIED IDEOGRAPH + 0xB7E2: 0x5C01, //CJK UNIFIED IDEOGRAPH + 0xB7E3: 0x67AB, //CJK UNIFIED IDEOGRAPH + 0xB7E4: 0x8702, //CJK UNIFIED IDEOGRAPH + 0xB7E5: 0x5CF0, //CJK UNIFIED IDEOGRAPH + 0xB7E6: 0x950B, //CJK UNIFIED IDEOGRAPH + 0xB7E7: 0x98CE, //CJK UNIFIED IDEOGRAPH + 0xB7E8: 0x75AF, //CJK UNIFIED IDEOGRAPH + 0xB7E9: 0x70FD, //CJK UNIFIED IDEOGRAPH + 0xB7EA: 0x9022, //CJK UNIFIED IDEOGRAPH + 0xB7EB: 0x51AF, //CJK UNIFIED IDEOGRAPH + 0xB7EC: 0x7F1D, //CJK UNIFIED IDEOGRAPH + 0xB7ED: 0x8BBD, //CJK UNIFIED IDEOGRAPH + 0xB7EE: 0x5949, //CJK UNIFIED IDEOGRAPH + 0xB7EF: 0x51E4, //CJK UNIFIED IDEOGRAPH + 0xB7F0: 0x4F5B, //CJK UNIFIED IDEOGRAPH + 0xB7F1: 0x5426, //CJK UNIFIED IDEOGRAPH + 0xB7F2: 0x592B, //CJK UNIFIED IDEOGRAPH + 0xB7F3: 0x6577, //CJK UNIFIED IDEOGRAPH + 0xB7F4: 0x80A4, //CJK UNIFIED IDEOGRAPH + 0xB7F5: 0x5B75, //CJK UNIFIED IDEOGRAPH + 0xB7F6: 0x6276, //CJK UNIFIED IDEOGRAPH + 0xB7F7: 0x62C2, //CJK UNIFIED IDEOGRAPH + 0xB7F8: 0x8F90, //CJK UNIFIED IDEOGRAPH + 0xB7F9: 0x5E45, //CJK UNIFIED IDEOGRAPH + 0xB7FA: 0x6C1F, //CJK UNIFIED IDEOGRAPH + 0xB7FB: 0x7B26, //CJK UNIFIED IDEOGRAPH + 0xB7FC: 0x4F0F, //CJK UNIFIED IDEOGRAPH + 0xB7FD: 0x4FD8, //CJK UNIFIED IDEOGRAPH + 0xB7FE: 0x670D, //CJK UNIFIED IDEOGRAPH + 0xB840: 0x7AA3, //CJK UNIFIED IDEOGRAPH + 0xB841: 0x7AA4, //CJK UNIFIED IDEOGRAPH + 0xB842: 0x7AA7, //CJK UNIFIED IDEOGRAPH + 0xB843: 0x7AA9, //CJK UNIFIED IDEOGRAPH + 0xB844: 0x7AAA, //CJK UNIFIED IDEOGRAPH + 0xB845: 0x7AAB, //CJK UNIFIED IDEOGRAPH + 0xB846: 0x7AAE, //CJK UNIFIED IDEOGRAPH + 0xB847: 0x7AAF, //CJK UNIFIED IDEOGRAPH + 0xB848: 0x7AB0, //CJK UNIFIED IDEOGRAPH + 0xB849: 0x7AB1, //CJK UNIFIED IDEOGRAPH + 0xB84A: 0x7AB2, //CJK UNIFIED IDEOGRAPH + 0xB84B: 0x7AB4, //CJK UNIFIED IDEOGRAPH + 0xB84C: 0x7AB5, //CJK UNIFIED IDEOGRAPH + 0xB84D: 0x7AB6, //CJK UNIFIED IDEOGRAPH + 0xB84E: 0x7AB7, //CJK UNIFIED IDEOGRAPH + 0xB84F: 0x7AB8, //CJK UNIFIED IDEOGRAPH + 0xB850: 0x7AB9, //CJK UNIFIED IDEOGRAPH + 0xB851: 0x7ABA, //CJK UNIFIED IDEOGRAPH + 0xB852: 0x7ABB, //CJK UNIFIED IDEOGRAPH + 0xB853: 0x7ABC, //CJK UNIFIED IDEOGRAPH + 0xB854: 0x7ABD, //CJK UNIFIED IDEOGRAPH + 0xB855: 0x7ABE, //CJK UNIFIED IDEOGRAPH + 0xB856: 0x7AC0, //CJK UNIFIED IDEOGRAPH + 0xB857: 0x7AC1, //CJK UNIFIED IDEOGRAPH + 0xB858: 0x7AC2, //CJK UNIFIED IDEOGRAPH + 0xB859: 0x7AC3, //CJK UNIFIED IDEOGRAPH + 0xB85A: 0x7AC4, //CJK UNIFIED IDEOGRAPH + 0xB85B: 0x7AC5, //CJK UNIFIED IDEOGRAPH + 0xB85C: 0x7AC6, //CJK UNIFIED IDEOGRAPH + 0xB85D: 0x7AC7, //CJK UNIFIED IDEOGRAPH + 0xB85E: 0x7AC8, //CJK UNIFIED IDEOGRAPH + 0xB85F: 0x7AC9, //CJK UNIFIED IDEOGRAPH + 0xB860: 0x7ACA, //CJK UNIFIED IDEOGRAPH + 0xB861: 0x7ACC, //CJK UNIFIED IDEOGRAPH + 0xB862: 0x7ACD, //CJK UNIFIED IDEOGRAPH + 0xB863: 0x7ACE, //CJK UNIFIED IDEOGRAPH + 0xB864: 0x7ACF, //CJK UNIFIED IDEOGRAPH + 0xB865: 0x7AD0, //CJK UNIFIED IDEOGRAPH + 0xB866: 0x7AD1, //CJK UNIFIED IDEOGRAPH + 0xB867: 0x7AD2, //CJK UNIFIED IDEOGRAPH + 0xB868: 0x7AD3, //CJK UNIFIED IDEOGRAPH + 0xB869: 0x7AD4, //CJK UNIFIED IDEOGRAPH + 0xB86A: 0x7AD5, //CJK UNIFIED IDEOGRAPH + 0xB86B: 0x7AD7, //CJK UNIFIED IDEOGRAPH + 0xB86C: 0x7AD8, //CJK UNIFIED IDEOGRAPH + 0xB86D: 0x7ADA, //CJK UNIFIED IDEOGRAPH + 0xB86E: 0x7ADB, //CJK UNIFIED IDEOGRAPH + 0xB86F: 0x7ADC, //CJK UNIFIED IDEOGRAPH + 0xB870: 0x7ADD, //CJK UNIFIED IDEOGRAPH + 0xB871: 0x7AE1, //CJK UNIFIED IDEOGRAPH + 0xB872: 0x7AE2, //CJK UNIFIED IDEOGRAPH + 0xB873: 0x7AE4, //CJK UNIFIED IDEOGRAPH + 0xB874: 0x7AE7, //CJK UNIFIED IDEOGRAPH + 0xB875: 0x7AE8, //CJK UNIFIED IDEOGRAPH + 0xB876: 0x7AE9, //CJK UNIFIED IDEOGRAPH + 0xB877: 0x7AEA, //CJK UNIFIED IDEOGRAPH + 0xB878: 0x7AEB, //CJK UNIFIED IDEOGRAPH + 0xB879: 0x7AEC, //CJK UNIFIED IDEOGRAPH + 0xB87A: 0x7AEE, //CJK UNIFIED IDEOGRAPH + 0xB87B: 0x7AF0, //CJK UNIFIED IDEOGRAPH + 0xB87C: 0x7AF1, //CJK UNIFIED IDEOGRAPH + 0xB87D: 0x7AF2, //CJK UNIFIED IDEOGRAPH + 0xB87E: 0x7AF3, //CJK UNIFIED IDEOGRAPH + 0xB880: 0x7AF4, //CJK UNIFIED IDEOGRAPH + 0xB881: 0x7AF5, //CJK UNIFIED IDEOGRAPH + 0xB882: 0x7AF6, //CJK UNIFIED IDEOGRAPH + 0xB883: 0x7AF7, //CJK UNIFIED IDEOGRAPH + 0xB884: 0x7AF8, //CJK UNIFIED IDEOGRAPH + 0xB885: 0x7AFB, //CJK UNIFIED IDEOGRAPH + 0xB886: 0x7AFC, //CJK UNIFIED IDEOGRAPH + 0xB887: 0x7AFE, //CJK UNIFIED IDEOGRAPH + 0xB888: 0x7B00, //CJK UNIFIED IDEOGRAPH + 0xB889: 0x7B01, //CJK UNIFIED IDEOGRAPH + 0xB88A: 0x7B02, //CJK UNIFIED IDEOGRAPH + 0xB88B: 0x7B05, //CJK UNIFIED IDEOGRAPH + 0xB88C: 0x7B07, //CJK UNIFIED IDEOGRAPH + 0xB88D: 0x7B09, //CJK UNIFIED IDEOGRAPH + 0xB88E: 0x7B0C, //CJK UNIFIED IDEOGRAPH + 0xB88F: 0x7B0D, //CJK UNIFIED IDEOGRAPH + 0xB890: 0x7B0E, //CJK UNIFIED IDEOGRAPH + 0xB891: 0x7B10, //CJK UNIFIED IDEOGRAPH + 0xB892: 0x7B12, //CJK UNIFIED IDEOGRAPH + 0xB893: 0x7B13, //CJK UNIFIED IDEOGRAPH + 0xB894: 0x7B16, //CJK UNIFIED IDEOGRAPH + 0xB895: 0x7B17, //CJK UNIFIED IDEOGRAPH + 0xB896: 0x7B18, //CJK UNIFIED IDEOGRAPH + 0xB897: 0x7B1A, //CJK UNIFIED IDEOGRAPH + 0xB898: 0x7B1C, //CJK UNIFIED IDEOGRAPH + 0xB899: 0x7B1D, //CJK UNIFIED IDEOGRAPH + 0xB89A: 0x7B1F, //CJK UNIFIED IDEOGRAPH + 0xB89B: 0x7B21, //CJK UNIFIED IDEOGRAPH + 0xB89C: 0x7B22, //CJK UNIFIED IDEOGRAPH + 0xB89D: 0x7B23, //CJK UNIFIED IDEOGRAPH + 0xB89E: 0x7B27, //CJK UNIFIED IDEOGRAPH + 0xB89F: 0x7B29, //CJK UNIFIED IDEOGRAPH + 0xB8A0: 0x7B2D, //CJK UNIFIED IDEOGRAPH + 0xB8A1: 0x6D6E, //CJK UNIFIED IDEOGRAPH + 0xB8A2: 0x6DAA, //CJK UNIFIED IDEOGRAPH + 0xB8A3: 0x798F, //CJK UNIFIED IDEOGRAPH + 0xB8A4: 0x88B1, //CJK UNIFIED IDEOGRAPH + 0xB8A5: 0x5F17, //CJK UNIFIED IDEOGRAPH + 0xB8A6: 0x752B, //CJK UNIFIED IDEOGRAPH + 0xB8A7: 0x629A, //CJK UNIFIED IDEOGRAPH + 0xB8A8: 0x8F85, //CJK UNIFIED IDEOGRAPH + 0xB8A9: 0x4FEF, //CJK UNIFIED IDEOGRAPH + 0xB8AA: 0x91DC, //CJK UNIFIED IDEOGRAPH + 0xB8AB: 0x65A7, //CJK UNIFIED IDEOGRAPH + 0xB8AC: 0x812F, //CJK UNIFIED IDEOGRAPH + 0xB8AD: 0x8151, //CJK UNIFIED IDEOGRAPH + 0xB8AE: 0x5E9C, //CJK UNIFIED IDEOGRAPH + 0xB8AF: 0x8150, //CJK UNIFIED IDEOGRAPH + 0xB8B0: 0x8D74, //CJK UNIFIED IDEOGRAPH + 0xB8B1: 0x526F, //CJK UNIFIED IDEOGRAPH + 0xB8B2: 0x8986, //CJK UNIFIED IDEOGRAPH + 0xB8B3: 0x8D4B, //CJK UNIFIED IDEOGRAPH + 0xB8B4: 0x590D, //CJK UNIFIED IDEOGRAPH + 0xB8B5: 0x5085, //CJK UNIFIED IDEOGRAPH + 0xB8B6: 0x4ED8, //CJK UNIFIED IDEOGRAPH + 0xB8B7: 0x961C, //CJK UNIFIED IDEOGRAPH + 0xB8B8: 0x7236, //CJK UNIFIED IDEOGRAPH + 0xB8B9: 0x8179, //CJK UNIFIED IDEOGRAPH + 0xB8BA: 0x8D1F, //CJK UNIFIED IDEOGRAPH + 0xB8BB: 0x5BCC, //CJK UNIFIED IDEOGRAPH + 0xB8BC: 0x8BA3, //CJK UNIFIED IDEOGRAPH + 0xB8BD: 0x9644, //CJK UNIFIED IDEOGRAPH + 0xB8BE: 0x5987, //CJK UNIFIED IDEOGRAPH + 0xB8BF: 0x7F1A, //CJK UNIFIED IDEOGRAPH + 0xB8C0: 0x5490, //CJK UNIFIED IDEOGRAPH + 0xB8C1: 0x5676, //CJK UNIFIED IDEOGRAPH + 0xB8C2: 0x560E, //CJK UNIFIED IDEOGRAPH + 0xB8C3: 0x8BE5, //CJK UNIFIED IDEOGRAPH + 0xB8C4: 0x6539, //CJK UNIFIED IDEOGRAPH + 0xB8C5: 0x6982, //CJK UNIFIED IDEOGRAPH + 0xB8C6: 0x9499, //CJK UNIFIED IDEOGRAPH + 0xB8C7: 0x76D6, //CJK UNIFIED IDEOGRAPH + 0xB8C8: 0x6E89, //CJK UNIFIED IDEOGRAPH + 0xB8C9: 0x5E72, //CJK UNIFIED IDEOGRAPH + 0xB8CA: 0x7518, //CJK UNIFIED IDEOGRAPH + 0xB8CB: 0x6746, //CJK UNIFIED IDEOGRAPH + 0xB8CC: 0x67D1, //CJK UNIFIED IDEOGRAPH + 0xB8CD: 0x7AFF, //CJK UNIFIED IDEOGRAPH + 0xB8CE: 0x809D, //CJK UNIFIED IDEOGRAPH + 0xB8CF: 0x8D76, //CJK UNIFIED IDEOGRAPH + 0xB8D0: 0x611F, //CJK UNIFIED IDEOGRAPH + 0xB8D1: 0x79C6, //CJK UNIFIED IDEOGRAPH + 0xB8D2: 0x6562, //CJK UNIFIED IDEOGRAPH + 0xB8D3: 0x8D63, //CJK UNIFIED IDEOGRAPH + 0xB8D4: 0x5188, //CJK UNIFIED IDEOGRAPH + 0xB8D5: 0x521A, //CJK UNIFIED IDEOGRAPH + 0xB8D6: 0x94A2, //CJK UNIFIED IDEOGRAPH + 0xB8D7: 0x7F38, //CJK UNIFIED IDEOGRAPH + 0xB8D8: 0x809B, //CJK UNIFIED IDEOGRAPH + 0xB8D9: 0x7EB2, //CJK UNIFIED IDEOGRAPH + 0xB8DA: 0x5C97, //CJK UNIFIED IDEOGRAPH + 0xB8DB: 0x6E2F, //CJK UNIFIED IDEOGRAPH + 0xB8DC: 0x6760, //CJK UNIFIED IDEOGRAPH + 0xB8DD: 0x7BD9, //CJK UNIFIED IDEOGRAPH + 0xB8DE: 0x768B, //CJK UNIFIED IDEOGRAPH + 0xB8DF: 0x9AD8, //CJK UNIFIED IDEOGRAPH + 0xB8E0: 0x818F, //CJK UNIFIED IDEOGRAPH + 0xB8E1: 0x7F94, //CJK UNIFIED IDEOGRAPH + 0xB8E2: 0x7CD5, //CJK UNIFIED IDEOGRAPH + 0xB8E3: 0x641E, //CJK UNIFIED IDEOGRAPH + 0xB8E4: 0x9550, //CJK UNIFIED IDEOGRAPH + 0xB8E5: 0x7A3F, //CJK UNIFIED IDEOGRAPH + 0xB8E6: 0x544A, //CJK UNIFIED IDEOGRAPH + 0xB8E7: 0x54E5, //CJK UNIFIED IDEOGRAPH + 0xB8E8: 0x6B4C, //CJK UNIFIED IDEOGRAPH + 0xB8E9: 0x6401, //CJK UNIFIED IDEOGRAPH + 0xB8EA: 0x6208, //CJK UNIFIED IDEOGRAPH + 0xB8EB: 0x9E3D, //CJK UNIFIED IDEOGRAPH + 0xB8EC: 0x80F3, //CJK UNIFIED IDEOGRAPH + 0xB8ED: 0x7599, //CJK UNIFIED IDEOGRAPH + 0xB8EE: 0x5272, //CJK UNIFIED IDEOGRAPH + 0xB8EF: 0x9769, //CJK UNIFIED IDEOGRAPH + 0xB8F0: 0x845B, //CJK UNIFIED IDEOGRAPH + 0xB8F1: 0x683C, //CJK UNIFIED IDEOGRAPH + 0xB8F2: 0x86E4, //CJK UNIFIED IDEOGRAPH + 0xB8F3: 0x9601, //CJK UNIFIED IDEOGRAPH + 0xB8F4: 0x9694, //CJK UNIFIED IDEOGRAPH + 0xB8F5: 0x94EC, //CJK UNIFIED IDEOGRAPH + 0xB8F6: 0x4E2A, //CJK UNIFIED IDEOGRAPH + 0xB8F7: 0x5404, //CJK UNIFIED IDEOGRAPH + 0xB8F8: 0x7ED9, //CJK UNIFIED IDEOGRAPH + 0xB8F9: 0x6839, //CJK UNIFIED IDEOGRAPH + 0xB8FA: 0x8DDF, //CJK UNIFIED IDEOGRAPH + 0xB8FB: 0x8015, //CJK UNIFIED IDEOGRAPH + 0xB8FC: 0x66F4, //CJK UNIFIED IDEOGRAPH + 0xB8FD: 0x5E9A, //CJK UNIFIED IDEOGRAPH + 0xB8FE: 0x7FB9, //CJK UNIFIED IDEOGRAPH + 0xB940: 0x7B2F, //CJK UNIFIED IDEOGRAPH + 0xB941: 0x7B30, //CJK UNIFIED IDEOGRAPH + 0xB942: 0x7B32, //CJK UNIFIED IDEOGRAPH + 0xB943: 0x7B34, //CJK UNIFIED IDEOGRAPH + 0xB944: 0x7B35, //CJK UNIFIED IDEOGRAPH + 0xB945: 0x7B36, //CJK UNIFIED IDEOGRAPH + 0xB946: 0x7B37, //CJK UNIFIED IDEOGRAPH + 0xB947: 0x7B39, //CJK UNIFIED IDEOGRAPH + 0xB948: 0x7B3B, //CJK UNIFIED IDEOGRAPH + 0xB949: 0x7B3D, //CJK UNIFIED IDEOGRAPH + 0xB94A: 0x7B3F, //CJK UNIFIED IDEOGRAPH + 0xB94B: 0x7B40, //CJK UNIFIED IDEOGRAPH + 0xB94C: 0x7B41, //CJK UNIFIED IDEOGRAPH + 0xB94D: 0x7B42, //CJK UNIFIED IDEOGRAPH + 0xB94E: 0x7B43, //CJK UNIFIED IDEOGRAPH + 0xB94F: 0x7B44, //CJK UNIFIED IDEOGRAPH + 0xB950: 0x7B46, //CJK UNIFIED IDEOGRAPH + 0xB951: 0x7B48, //CJK UNIFIED IDEOGRAPH + 0xB952: 0x7B4A, //CJK UNIFIED IDEOGRAPH + 0xB953: 0x7B4D, //CJK UNIFIED IDEOGRAPH + 0xB954: 0x7B4E, //CJK UNIFIED IDEOGRAPH + 0xB955: 0x7B53, //CJK UNIFIED IDEOGRAPH + 0xB956: 0x7B55, //CJK UNIFIED IDEOGRAPH + 0xB957: 0x7B57, //CJK UNIFIED IDEOGRAPH + 0xB958: 0x7B59, //CJK UNIFIED IDEOGRAPH + 0xB959: 0x7B5C, //CJK UNIFIED IDEOGRAPH + 0xB95A: 0x7B5E, //CJK UNIFIED IDEOGRAPH + 0xB95B: 0x7B5F, //CJK UNIFIED IDEOGRAPH + 0xB95C: 0x7B61, //CJK UNIFIED IDEOGRAPH + 0xB95D: 0x7B63, //CJK UNIFIED IDEOGRAPH + 0xB95E: 0x7B64, //CJK UNIFIED IDEOGRAPH + 0xB95F: 0x7B65, //CJK UNIFIED IDEOGRAPH + 0xB960: 0x7B66, //CJK UNIFIED IDEOGRAPH + 0xB961: 0x7B67, //CJK UNIFIED IDEOGRAPH + 0xB962: 0x7B68, //CJK UNIFIED IDEOGRAPH + 0xB963: 0x7B69, //CJK UNIFIED IDEOGRAPH + 0xB964: 0x7B6A, //CJK UNIFIED IDEOGRAPH + 0xB965: 0x7B6B, //CJK UNIFIED IDEOGRAPH + 0xB966: 0x7B6C, //CJK UNIFIED IDEOGRAPH + 0xB967: 0x7B6D, //CJK UNIFIED IDEOGRAPH + 0xB968: 0x7B6F, //CJK UNIFIED IDEOGRAPH + 0xB969: 0x7B70, //CJK UNIFIED IDEOGRAPH + 0xB96A: 0x7B73, //CJK UNIFIED IDEOGRAPH + 0xB96B: 0x7B74, //CJK UNIFIED IDEOGRAPH + 0xB96C: 0x7B76, //CJK UNIFIED IDEOGRAPH + 0xB96D: 0x7B78, //CJK UNIFIED IDEOGRAPH + 0xB96E: 0x7B7A, //CJK UNIFIED IDEOGRAPH + 0xB96F: 0x7B7C, //CJK UNIFIED IDEOGRAPH + 0xB970: 0x7B7D, //CJK UNIFIED IDEOGRAPH + 0xB971: 0x7B7F, //CJK UNIFIED IDEOGRAPH + 0xB972: 0x7B81, //CJK UNIFIED IDEOGRAPH + 0xB973: 0x7B82, //CJK UNIFIED IDEOGRAPH + 0xB974: 0x7B83, //CJK UNIFIED IDEOGRAPH + 0xB975: 0x7B84, //CJK UNIFIED IDEOGRAPH + 0xB976: 0x7B86, //CJK UNIFIED IDEOGRAPH + 0xB977: 0x7B87, //CJK UNIFIED IDEOGRAPH + 0xB978: 0x7B88, //CJK UNIFIED IDEOGRAPH + 0xB979: 0x7B89, //CJK UNIFIED IDEOGRAPH + 0xB97A: 0x7B8A, //CJK UNIFIED IDEOGRAPH + 0xB97B: 0x7B8B, //CJK UNIFIED IDEOGRAPH + 0xB97C: 0x7B8C, //CJK UNIFIED IDEOGRAPH + 0xB97D: 0x7B8E, //CJK UNIFIED IDEOGRAPH + 0xB97E: 0x7B8F, //CJK UNIFIED IDEOGRAPH + 0xB980: 0x7B91, //CJK UNIFIED IDEOGRAPH + 0xB981: 0x7B92, //CJK UNIFIED IDEOGRAPH + 0xB982: 0x7B93, //CJK UNIFIED IDEOGRAPH + 0xB983: 0x7B96, //CJK UNIFIED IDEOGRAPH + 0xB984: 0x7B98, //CJK UNIFIED IDEOGRAPH + 0xB985: 0x7B99, //CJK UNIFIED IDEOGRAPH + 0xB986: 0x7B9A, //CJK UNIFIED IDEOGRAPH + 0xB987: 0x7B9B, //CJK UNIFIED IDEOGRAPH + 0xB988: 0x7B9E, //CJK UNIFIED IDEOGRAPH + 0xB989: 0x7B9F, //CJK UNIFIED IDEOGRAPH + 0xB98A: 0x7BA0, //CJK UNIFIED IDEOGRAPH + 0xB98B: 0x7BA3, //CJK UNIFIED IDEOGRAPH + 0xB98C: 0x7BA4, //CJK UNIFIED IDEOGRAPH + 0xB98D: 0x7BA5, //CJK UNIFIED IDEOGRAPH + 0xB98E: 0x7BAE, //CJK UNIFIED IDEOGRAPH + 0xB98F: 0x7BAF, //CJK UNIFIED IDEOGRAPH + 0xB990: 0x7BB0, //CJK UNIFIED IDEOGRAPH + 0xB991: 0x7BB2, //CJK UNIFIED IDEOGRAPH + 0xB992: 0x7BB3, //CJK UNIFIED IDEOGRAPH + 0xB993: 0x7BB5, //CJK UNIFIED IDEOGRAPH + 0xB994: 0x7BB6, //CJK UNIFIED IDEOGRAPH + 0xB995: 0x7BB7, //CJK UNIFIED IDEOGRAPH + 0xB996: 0x7BB9, //CJK UNIFIED IDEOGRAPH + 0xB997: 0x7BBA, //CJK UNIFIED IDEOGRAPH + 0xB998: 0x7BBB, //CJK UNIFIED IDEOGRAPH + 0xB999: 0x7BBC, //CJK UNIFIED IDEOGRAPH + 0xB99A: 0x7BBD, //CJK UNIFIED IDEOGRAPH + 0xB99B: 0x7BBE, //CJK UNIFIED IDEOGRAPH + 0xB99C: 0x7BBF, //CJK UNIFIED IDEOGRAPH + 0xB99D: 0x7BC0, //CJK UNIFIED IDEOGRAPH + 0xB99E: 0x7BC2, //CJK UNIFIED IDEOGRAPH + 0xB99F: 0x7BC3, //CJK UNIFIED IDEOGRAPH + 0xB9A0: 0x7BC4, //CJK UNIFIED IDEOGRAPH + 0xB9A1: 0x57C2, //CJK UNIFIED IDEOGRAPH + 0xB9A2: 0x803F, //CJK UNIFIED IDEOGRAPH + 0xB9A3: 0x6897, //CJK UNIFIED IDEOGRAPH + 0xB9A4: 0x5DE5, //CJK UNIFIED IDEOGRAPH + 0xB9A5: 0x653B, //CJK UNIFIED IDEOGRAPH + 0xB9A6: 0x529F, //CJK UNIFIED IDEOGRAPH + 0xB9A7: 0x606D, //CJK UNIFIED IDEOGRAPH + 0xB9A8: 0x9F9A, //CJK UNIFIED IDEOGRAPH + 0xB9A9: 0x4F9B, //CJK UNIFIED IDEOGRAPH + 0xB9AA: 0x8EAC, //CJK UNIFIED IDEOGRAPH + 0xB9AB: 0x516C, //CJK UNIFIED IDEOGRAPH + 0xB9AC: 0x5BAB, //CJK UNIFIED IDEOGRAPH + 0xB9AD: 0x5F13, //CJK UNIFIED IDEOGRAPH + 0xB9AE: 0x5DE9, //CJK UNIFIED IDEOGRAPH + 0xB9AF: 0x6C5E, //CJK UNIFIED IDEOGRAPH + 0xB9B0: 0x62F1, //CJK UNIFIED IDEOGRAPH + 0xB9B1: 0x8D21, //CJK UNIFIED IDEOGRAPH + 0xB9B2: 0x5171, //CJK UNIFIED IDEOGRAPH + 0xB9B3: 0x94A9, //CJK UNIFIED IDEOGRAPH + 0xB9B4: 0x52FE, //CJK UNIFIED IDEOGRAPH + 0xB9B5: 0x6C9F, //CJK UNIFIED IDEOGRAPH + 0xB9B6: 0x82DF, //CJK UNIFIED IDEOGRAPH + 0xB9B7: 0x72D7, //CJK UNIFIED IDEOGRAPH + 0xB9B8: 0x57A2, //CJK UNIFIED IDEOGRAPH + 0xB9B9: 0x6784, //CJK UNIFIED IDEOGRAPH + 0xB9BA: 0x8D2D, //CJK UNIFIED IDEOGRAPH + 0xB9BB: 0x591F, //CJK UNIFIED IDEOGRAPH + 0xB9BC: 0x8F9C, //CJK UNIFIED IDEOGRAPH + 0xB9BD: 0x83C7, //CJK UNIFIED IDEOGRAPH + 0xB9BE: 0x5495, //CJK UNIFIED IDEOGRAPH + 0xB9BF: 0x7B8D, //CJK UNIFIED IDEOGRAPH + 0xB9C0: 0x4F30, //CJK UNIFIED IDEOGRAPH + 0xB9C1: 0x6CBD, //CJK UNIFIED IDEOGRAPH + 0xB9C2: 0x5B64, //CJK UNIFIED IDEOGRAPH + 0xB9C3: 0x59D1, //CJK UNIFIED IDEOGRAPH + 0xB9C4: 0x9F13, //CJK UNIFIED IDEOGRAPH + 0xB9C5: 0x53E4, //CJK UNIFIED IDEOGRAPH + 0xB9C6: 0x86CA, //CJK UNIFIED IDEOGRAPH + 0xB9C7: 0x9AA8, //CJK UNIFIED IDEOGRAPH + 0xB9C8: 0x8C37, //CJK UNIFIED IDEOGRAPH + 0xB9C9: 0x80A1, //CJK UNIFIED IDEOGRAPH + 0xB9CA: 0x6545, //CJK UNIFIED IDEOGRAPH + 0xB9CB: 0x987E, //CJK UNIFIED IDEOGRAPH + 0xB9CC: 0x56FA, //CJK UNIFIED IDEOGRAPH + 0xB9CD: 0x96C7, //CJK UNIFIED IDEOGRAPH + 0xB9CE: 0x522E, //CJK UNIFIED IDEOGRAPH + 0xB9CF: 0x74DC, //CJK UNIFIED IDEOGRAPH + 0xB9D0: 0x5250, //CJK UNIFIED IDEOGRAPH + 0xB9D1: 0x5BE1, //CJK UNIFIED IDEOGRAPH + 0xB9D2: 0x6302, //CJK UNIFIED IDEOGRAPH + 0xB9D3: 0x8902, //CJK UNIFIED IDEOGRAPH + 0xB9D4: 0x4E56, //CJK UNIFIED IDEOGRAPH + 0xB9D5: 0x62D0, //CJK UNIFIED IDEOGRAPH + 0xB9D6: 0x602A, //CJK UNIFIED IDEOGRAPH + 0xB9D7: 0x68FA, //CJK UNIFIED IDEOGRAPH + 0xB9D8: 0x5173, //CJK UNIFIED IDEOGRAPH + 0xB9D9: 0x5B98, //CJK UNIFIED IDEOGRAPH + 0xB9DA: 0x51A0, //CJK UNIFIED IDEOGRAPH + 0xB9DB: 0x89C2, //CJK UNIFIED IDEOGRAPH + 0xB9DC: 0x7BA1, //CJK UNIFIED IDEOGRAPH + 0xB9DD: 0x9986, //CJK UNIFIED IDEOGRAPH + 0xB9DE: 0x7F50, //CJK UNIFIED IDEOGRAPH + 0xB9DF: 0x60EF, //CJK UNIFIED IDEOGRAPH + 0xB9E0: 0x704C, //CJK UNIFIED IDEOGRAPH + 0xB9E1: 0x8D2F, //CJK UNIFIED IDEOGRAPH + 0xB9E2: 0x5149, //CJK UNIFIED IDEOGRAPH + 0xB9E3: 0x5E7F, //CJK UNIFIED IDEOGRAPH + 0xB9E4: 0x901B, //CJK UNIFIED IDEOGRAPH + 0xB9E5: 0x7470, //CJK UNIFIED IDEOGRAPH + 0xB9E6: 0x89C4, //CJK UNIFIED IDEOGRAPH + 0xB9E7: 0x572D, //CJK UNIFIED IDEOGRAPH + 0xB9E8: 0x7845, //CJK UNIFIED IDEOGRAPH + 0xB9E9: 0x5F52, //CJK UNIFIED IDEOGRAPH + 0xB9EA: 0x9F9F, //CJK UNIFIED IDEOGRAPH + 0xB9EB: 0x95FA, //CJK UNIFIED IDEOGRAPH + 0xB9EC: 0x8F68, //CJK UNIFIED IDEOGRAPH + 0xB9ED: 0x9B3C, //CJK UNIFIED IDEOGRAPH + 0xB9EE: 0x8BE1, //CJK UNIFIED IDEOGRAPH + 0xB9EF: 0x7678, //CJK UNIFIED IDEOGRAPH + 0xB9F0: 0x6842, //CJK UNIFIED IDEOGRAPH + 0xB9F1: 0x67DC, //CJK UNIFIED IDEOGRAPH + 0xB9F2: 0x8DEA, //CJK UNIFIED IDEOGRAPH + 0xB9F3: 0x8D35, //CJK UNIFIED IDEOGRAPH + 0xB9F4: 0x523D, //CJK UNIFIED IDEOGRAPH + 0xB9F5: 0x8F8A, //CJK UNIFIED IDEOGRAPH + 0xB9F6: 0x6EDA, //CJK UNIFIED IDEOGRAPH + 0xB9F7: 0x68CD, //CJK UNIFIED IDEOGRAPH + 0xB9F8: 0x9505, //CJK UNIFIED IDEOGRAPH + 0xB9F9: 0x90ED, //CJK UNIFIED IDEOGRAPH + 0xB9FA: 0x56FD, //CJK UNIFIED IDEOGRAPH + 0xB9FB: 0x679C, //CJK UNIFIED IDEOGRAPH + 0xB9FC: 0x88F9, //CJK UNIFIED IDEOGRAPH + 0xB9FD: 0x8FC7, //CJK UNIFIED IDEOGRAPH + 0xB9FE: 0x54C8, //CJK UNIFIED IDEOGRAPH + 0xBA40: 0x7BC5, //CJK UNIFIED IDEOGRAPH + 0xBA41: 0x7BC8, //CJK UNIFIED IDEOGRAPH + 0xBA42: 0x7BC9, //CJK UNIFIED IDEOGRAPH + 0xBA43: 0x7BCA, //CJK UNIFIED IDEOGRAPH + 0xBA44: 0x7BCB, //CJK UNIFIED IDEOGRAPH + 0xBA45: 0x7BCD, //CJK UNIFIED IDEOGRAPH + 0xBA46: 0x7BCE, //CJK UNIFIED IDEOGRAPH + 0xBA47: 0x7BCF, //CJK UNIFIED IDEOGRAPH + 0xBA48: 0x7BD0, //CJK UNIFIED IDEOGRAPH + 0xBA49: 0x7BD2, //CJK UNIFIED IDEOGRAPH + 0xBA4A: 0x7BD4, //CJK UNIFIED IDEOGRAPH + 0xBA4B: 0x7BD5, //CJK UNIFIED IDEOGRAPH + 0xBA4C: 0x7BD6, //CJK UNIFIED IDEOGRAPH + 0xBA4D: 0x7BD7, //CJK UNIFIED IDEOGRAPH + 0xBA4E: 0x7BD8, //CJK UNIFIED IDEOGRAPH + 0xBA4F: 0x7BDB, //CJK UNIFIED IDEOGRAPH + 0xBA50: 0x7BDC, //CJK UNIFIED IDEOGRAPH + 0xBA51: 0x7BDE, //CJK UNIFIED IDEOGRAPH + 0xBA52: 0x7BDF, //CJK UNIFIED IDEOGRAPH + 0xBA53: 0x7BE0, //CJK UNIFIED IDEOGRAPH + 0xBA54: 0x7BE2, //CJK UNIFIED IDEOGRAPH + 0xBA55: 0x7BE3, //CJK UNIFIED IDEOGRAPH + 0xBA56: 0x7BE4, //CJK UNIFIED IDEOGRAPH + 0xBA57: 0x7BE7, //CJK UNIFIED IDEOGRAPH + 0xBA58: 0x7BE8, //CJK UNIFIED IDEOGRAPH + 0xBA59: 0x7BE9, //CJK UNIFIED IDEOGRAPH + 0xBA5A: 0x7BEB, //CJK UNIFIED IDEOGRAPH + 0xBA5B: 0x7BEC, //CJK UNIFIED IDEOGRAPH + 0xBA5C: 0x7BED, //CJK UNIFIED IDEOGRAPH + 0xBA5D: 0x7BEF, //CJK UNIFIED IDEOGRAPH + 0xBA5E: 0x7BF0, //CJK UNIFIED IDEOGRAPH + 0xBA5F: 0x7BF2, //CJK UNIFIED IDEOGRAPH + 0xBA60: 0x7BF3, //CJK UNIFIED IDEOGRAPH + 0xBA61: 0x7BF4, //CJK UNIFIED IDEOGRAPH + 0xBA62: 0x7BF5, //CJK UNIFIED IDEOGRAPH + 0xBA63: 0x7BF6, //CJK UNIFIED IDEOGRAPH + 0xBA64: 0x7BF8, //CJK UNIFIED IDEOGRAPH + 0xBA65: 0x7BF9, //CJK UNIFIED IDEOGRAPH + 0xBA66: 0x7BFA, //CJK UNIFIED IDEOGRAPH + 0xBA67: 0x7BFB, //CJK UNIFIED IDEOGRAPH + 0xBA68: 0x7BFD, //CJK UNIFIED IDEOGRAPH + 0xBA69: 0x7BFF, //CJK UNIFIED IDEOGRAPH + 0xBA6A: 0x7C00, //CJK UNIFIED IDEOGRAPH + 0xBA6B: 0x7C01, //CJK UNIFIED IDEOGRAPH + 0xBA6C: 0x7C02, //CJK UNIFIED IDEOGRAPH + 0xBA6D: 0x7C03, //CJK UNIFIED IDEOGRAPH + 0xBA6E: 0x7C04, //CJK UNIFIED IDEOGRAPH + 0xBA6F: 0x7C05, //CJK UNIFIED IDEOGRAPH + 0xBA70: 0x7C06, //CJK UNIFIED IDEOGRAPH + 0xBA71: 0x7C08, //CJK UNIFIED IDEOGRAPH + 0xBA72: 0x7C09, //CJK UNIFIED IDEOGRAPH + 0xBA73: 0x7C0A, //CJK UNIFIED IDEOGRAPH + 0xBA74: 0x7C0D, //CJK UNIFIED IDEOGRAPH + 0xBA75: 0x7C0E, //CJK UNIFIED IDEOGRAPH + 0xBA76: 0x7C10, //CJK UNIFIED IDEOGRAPH + 0xBA77: 0x7C11, //CJK UNIFIED IDEOGRAPH + 0xBA78: 0x7C12, //CJK UNIFIED IDEOGRAPH + 0xBA79: 0x7C13, //CJK UNIFIED IDEOGRAPH + 0xBA7A: 0x7C14, //CJK UNIFIED IDEOGRAPH + 0xBA7B: 0x7C15, //CJK UNIFIED IDEOGRAPH + 0xBA7C: 0x7C17, //CJK UNIFIED IDEOGRAPH + 0xBA7D: 0x7C18, //CJK UNIFIED IDEOGRAPH + 0xBA7E: 0x7C19, //CJK UNIFIED IDEOGRAPH + 0xBA80: 0x7C1A, //CJK UNIFIED IDEOGRAPH + 0xBA81: 0x7C1B, //CJK UNIFIED IDEOGRAPH + 0xBA82: 0x7C1C, //CJK UNIFIED IDEOGRAPH + 0xBA83: 0x7C1D, //CJK UNIFIED IDEOGRAPH + 0xBA84: 0x7C1E, //CJK UNIFIED IDEOGRAPH + 0xBA85: 0x7C20, //CJK UNIFIED IDEOGRAPH + 0xBA86: 0x7C21, //CJK UNIFIED IDEOGRAPH + 0xBA87: 0x7C22, //CJK UNIFIED IDEOGRAPH + 0xBA88: 0x7C23, //CJK UNIFIED IDEOGRAPH + 0xBA89: 0x7C24, //CJK UNIFIED IDEOGRAPH + 0xBA8A: 0x7C25, //CJK UNIFIED IDEOGRAPH + 0xBA8B: 0x7C28, //CJK UNIFIED IDEOGRAPH + 0xBA8C: 0x7C29, //CJK UNIFIED IDEOGRAPH + 0xBA8D: 0x7C2B, //CJK UNIFIED IDEOGRAPH + 0xBA8E: 0x7C2C, //CJK UNIFIED IDEOGRAPH + 0xBA8F: 0x7C2D, //CJK UNIFIED IDEOGRAPH + 0xBA90: 0x7C2E, //CJK UNIFIED IDEOGRAPH + 0xBA91: 0x7C2F, //CJK UNIFIED IDEOGRAPH + 0xBA92: 0x7C30, //CJK UNIFIED IDEOGRAPH + 0xBA93: 0x7C31, //CJK UNIFIED IDEOGRAPH + 0xBA94: 0x7C32, //CJK UNIFIED IDEOGRAPH + 0xBA95: 0x7C33, //CJK UNIFIED IDEOGRAPH + 0xBA96: 0x7C34, //CJK UNIFIED IDEOGRAPH + 0xBA97: 0x7C35, //CJK UNIFIED IDEOGRAPH + 0xBA98: 0x7C36, //CJK UNIFIED IDEOGRAPH + 0xBA99: 0x7C37, //CJK UNIFIED IDEOGRAPH + 0xBA9A: 0x7C39, //CJK UNIFIED IDEOGRAPH + 0xBA9B: 0x7C3A, //CJK UNIFIED IDEOGRAPH + 0xBA9C: 0x7C3B, //CJK UNIFIED IDEOGRAPH + 0xBA9D: 0x7C3C, //CJK UNIFIED IDEOGRAPH + 0xBA9E: 0x7C3D, //CJK UNIFIED IDEOGRAPH + 0xBA9F: 0x7C3E, //CJK UNIFIED IDEOGRAPH + 0xBAA0: 0x7C42, //CJK UNIFIED IDEOGRAPH + 0xBAA1: 0x9AB8, //CJK UNIFIED IDEOGRAPH + 0xBAA2: 0x5B69, //CJK UNIFIED IDEOGRAPH + 0xBAA3: 0x6D77, //CJK UNIFIED IDEOGRAPH + 0xBAA4: 0x6C26, //CJK UNIFIED IDEOGRAPH + 0xBAA5: 0x4EA5, //CJK UNIFIED IDEOGRAPH + 0xBAA6: 0x5BB3, //CJK UNIFIED IDEOGRAPH + 0xBAA7: 0x9A87, //CJK UNIFIED IDEOGRAPH + 0xBAA8: 0x9163, //CJK UNIFIED IDEOGRAPH + 0xBAA9: 0x61A8, //CJK UNIFIED IDEOGRAPH + 0xBAAA: 0x90AF, //CJK UNIFIED IDEOGRAPH + 0xBAAB: 0x97E9, //CJK UNIFIED IDEOGRAPH + 0xBAAC: 0x542B, //CJK UNIFIED IDEOGRAPH + 0xBAAD: 0x6DB5, //CJK UNIFIED IDEOGRAPH + 0xBAAE: 0x5BD2, //CJK UNIFIED IDEOGRAPH + 0xBAAF: 0x51FD, //CJK UNIFIED IDEOGRAPH + 0xBAB0: 0x558A, //CJK UNIFIED IDEOGRAPH + 0xBAB1: 0x7F55, //CJK UNIFIED IDEOGRAPH + 0xBAB2: 0x7FF0, //CJK UNIFIED IDEOGRAPH + 0xBAB3: 0x64BC, //CJK UNIFIED IDEOGRAPH + 0xBAB4: 0x634D, //CJK UNIFIED IDEOGRAPH + 0xBAB5: 0x65F1, //CJK UNIFIED IDEOGRAPH + 0xBAB6: 0x61BE, //CJK UNIFIED IDEOGRAPH + 0xBAB7: 0x608D, //CJK UNIFIED IDEOGRAPH + 0xBAB8: 0x710A, //CJK UNIFIED IDEOGRAPH + 0xBAB9: 0x6C57, //CJK UNIFIED IDEOGRAPH + 0xBABA: 0x6C49, //CJK UNIFIED IDEOGRAPH + 0xBABB: 0x592F, //CJK UNIFIED IDEOGRAPH + 0xBABC: 0x676D, //CJK UNIFIED IDEOGRAPH + 0xBABD: 0x822A, //CJK UNIFIED IDEOGRAPH + 0xBABE: 0x58D5, //CJK UNIFIED IDEOGRAPH + 0xBABF: 0x568E, //CJK UNIFIED IDEOGRAPH + 0xBAC0: 0x8C6A, //CJK UNIFIED IDEOGRAPH + 0xBAC1: 0x6BEB, //CJK UNIFIED IDEOGRAPH + 0xBAC2: 0x90DD, //CJK UNIFIED IDEOGRAPH + 0xBAC3: 0x597D, //CJK UNIFIED IDEOGRAPH + 0xBAC4: 0x8017, //CJK UNIFIED IDEOGRAPH + 0xBAC5: 0x53F7, //CJK UNIFIED IDEOGRAPH + 0xBAC6: 0x6D69, //CJK UNIFIED IDEOGRAPH + 0xBAC7: 0x5475, //CJK UNIFIED IDEOGRAPH + 0xBAC8: 0x559D, //CJK UNIFIED IDEOGRAPH + 0xBAC9: 0x8377, //CJK UNIFIED IDEOGRAPH + 0xBACA: 0x83CF, //CJK UNIFIED IDEOGRAPH + 0xBACB: 0x6838, //CJK UNIFIED IDEOGRAPH + 0xBACC: 0x79BE, //CJK UNIFIED IDEOGRAPH + 0xBACD: 0x548C, //CJK UNIFIED IDEOGRAPH + 0xBACE: 0x4F55, //CJK UNIFIED IDEOGRAPH + 0xBACF: 0x5408, //CJK UNIFIED IDEOGRAPH + 0xBAD0: 0x76D2, //CJK UNIFIED IDEOGRAPH + 0xBAD1: 0x8C89, //CJK UNIFIED IDEOGRAPH + 0xBAD2: 0x9602, //CJK UNIFIED IDEOGRAPH + 0xBAD3: 0x6CB3, //CJK UNIFIED IDEOGRAPH + 0xBAD4: 0x6DB8, //CJK UNIFIED IDEOGRAPH + 0xBAD5: 0x8D6B, //CJK UNIFIED IDEOGRAPH + 0xBAD6: 0x8910, //CJK UNIFIED IDEOGRAPH + 0xBAD7: 0x9E64, //CJK UNIFIED IDEOGRAPH + 0xBAD8: 0x8D3A, //CJK UNIFIED IDEOGRAPH + 0xBAD9: 0x563F, //CJK UNIFIED IDEOGRAPH + 0xBADA: 0x9ED1, //CJK UNIFIED IDEOGRAPH + 0xBADB: 0x75D5, //CJK UNIFIED IDEOGRAPH + 0xBADC: 0x5F88, //CJK UNIFIED IDEOGRAPH + 0xBADD: 0x72E0, //CJK UNIFIED IDEOGRAPH + 0xBADE: 0x6068, //CJK UNIFIED IDEOGRAPH + 0xBADF: 0x54FC, //CJK UNIFIED IDEOGRAPH + 0xBAE0: 0x4EA8, //CJK UNIFIED IDEOGRAPH + 0xBAE1: 0x6A2A, //CJK UNIFIED IDEOGRAPH + 0xBAE2: 0x8861, //CJK UNIFIED IDEOGRAPH + 0xBAE3: 0x6052, //CJK UNIFIED IDEOGRAPH + 0xBAE4: 0x8F70, //CJK UNIFIED IDEOGRAPH + 0xBAE5: 0x54C4, //CJK UNIFIED IDEOGRAPH + 0xBAE6: 0x70D8, //CJK UNIFIED IDEOGRAPH + 0xBAE7: 0x8679, //CJK UNIFIED IDEOGRAPH + 0xBAE8: 0x9E3F, //CJK UNIFIED IDEOGRAPH + 0xBAE9: 0x6D2A, //CJK UNIFIED IDEOGRAPH + 0xBAEA: 0x5B8F, //CJK UNIFIED IDEOGRAPH + 0xBAEB: 0x5F18, //CJK UNIFIED IDEOGRAPH + 0xBAEC: 0x7EA2, //CJK UNIFIED IDEOGRAPH + 0xBAED: 0x5589, //CJK UNIFIED IDEOGRAPH + 0xBAEE: 0x4FAF, //CJK UNIFIED IDEOGRAPH + 0xBAEF: 0x7334, //CJK UNIFIED IDEOGRAPH + 0xBAF0: 0x543C, //CJK UNIFIED IDEOGRAPH + 0xBAF1: 0x539A, //CJK UNIFIED IDEOGRAPH + 0xBAF2: 0x5019, //CJK UNIFIED IDEOGRAPH + 0xBAF3: 0x540E, //CJK UNIFIED IDEOGRAPH + 0xBAF4: 0x547C, //CJK UNIFIED IDEOGRAPH + 0xBAF5: 0x4E4E, //CJK UNIFIED IDEOGRAPH + 0xBAF6: 0x5FFD, //CJK UNIFIED IDEOGRAPH + 0xBAF7: 0x745A, //CJK UNIFIED IDEOGRAPH + 0xBAF8: 0x58F6, //CJK UNIFIED IDEOGRAPH + 0xBAF9: 0x846B, //CJK UNIFIED IDEOGRAPH + 0xBAFA: 0x80E1, //CJK UNIFIED IDEOGRAPH + 0xBAFB: 0x8774, //CJK UNIFIED IDEOGRAPH + 0xBAFC: 0x72D0, //CJK UNIFIED IDEOGRAPH + 0xBAFD: 0x7CCA, //CJK UNIFIED IDEOGRAPH + 0xBAFE: 0x6E56, //CJK UNIFIED IDEOGRAPH + 0xBB40: 0x7C43, //CJK UNIFIED IDEOGRAPH + 0xBB41: 0x7C44, //CJK UNIFIED IDEOGRAPH + 0xBB42: 0x7C45, //CJK UNIFIED IDEOGRAPH + 0xBB43: 0x7C46, //CJK UNIFIED IDEOGRAPH + 0xBB44: 0x7C47, //CJK UNIFIED IDEOGRAPH + 0xBB45: 0x7C48, //CJK UNIFIED IDEOGRAPH + 0xBB46: 0x7C49, //CJK UNIFIED IDEOGRAPH + 0xBB47: 0x7C4A, //CJK UNIFIED IDEOGRAPH + 0xBB48: 0x7C4B, //CJK UNIFIED IDEOGRAPH + 0xBB49: 0x7C4C, //CJK UNIFIED IDEOGRAPH + 0xBB4A: 0x7C4E, //CJK UNIFIED IDEOGRAPH + 0xBB4B: 0x7C4F, //CJK UNIFIED IDEOGRAPH + 0xBB4C: 0x7C50, //CJK UNIFIED IDEOGRAPH + 0xBB4D: 0x7C51, //CJK UNIFIED IDEOGRAPH + 0xBB4E: 0x7C52, //CJK UNIFIED IDEOGRAPH + 0xBB4F: 0x7C53, //CJK UNIFIED IDEOGRAPH + 0xBB50: 0x7C54, //CJK UNIFIED IDEOGRAPH + 0xBB51: 0x7C55, //CJK UNIFIED IDEOGRAPH + 0xBB52: 0x7C56, //CJK UNIFIED IDEOGRAPH + 0xBB53: 0x7C57, //CJK UNIFIED IDEOGRAPH + 0xBB54: 0x7C58, //CJK UNIFIED IDEOGRAPH + 0xBB55: 0x7C59, //CJK UNIFIED IDEOGRAPH + 0xBB56: 0x7C5A, //CJK UNIFIED IDEOGRAPH + 0xBB57: 0x7C5B, //CJK UNIFIED IDEOGRAPH + 0xBB58: 0x7C5C, //CJK UNIFIED IDEOGRAPH + 0xBB59: 0x7C5D, //CJK UNIFIED IDEOGRAPH + 0xBB5A: 0x7C5E, //CJK UNIFIED IDEOGRAPH + 0xBB5B: 0x7C5F, //CJK UNIFIED IDEOGRAPH + 0xBB5C: 0x7C60, //CJK UNIFIED IDEOGRAPH + 0xBB5D: 0x7C61, //CJK UNIFIED IDEOGRAPH + 0xBB5E: 0x7C62, //CJK UNIFIED IDEOGRAPH + 0xBB5F: 0x7C63, //CJK UNIFIED IDEOGRAPH + 0xBB60: 0x7C64, //CJK UNIFIED IDEOGRAPH + 0xBB61: 0x7C65, //CJK UNIFIED IDEOGRAPH + 0xBB62: 0x7C66, //CJK UNIFIED IDEOGRAPH + 0xBB63: 0x7C67, //CJK UNIFIED IDEOGRAPH + 0xBB64: 0x7C68, //CJK UNIFIED IDEOGRAPH + 0xBB65: 0x7C69, //CJK UNIFIED IDEOGRAPH + 0xBB66: 0x7C6A, //CJK UNIFIED IDEOGRAPH + 0xBB67: 0x7C6B, //CJK UNIFIED IDEOGRAPH + 0xBB68: 0x7C6C, //CJK UNIFIED IDEOGRAPH + 0xBB69: 0x7C6D, //CJK UNIFIED IDEOGRAPH + 0xBB6A: 0x7C6E, //CJK UNIFIED IDEOGRAPH + 0xBB6B: 0x7C6F, //CJK UNIFIED IDEOGRAPH + 0xBB6C: 0x7C70, //CJK UNIFIED IDEOGRAPH + 0xBB6D: 0x7C71, //CJK UNIFIED IDEOGRAPH + 0xBB6E: 0x7C72, //CJK UNIFIED IDEOGRAPH + 0xBB6F: 0x7C75, //CJK UNIFIED IDEOGRAPH + 0xBB70: 0x7C76, //CJK UNIFIED IDEOGRAPH + 0xBB71: 0x7C77, //CJK UNIFIED IDEOGRAPH + 0xBB72: 0x7C78, //CJK UNIFIED IDEOGRAPH + 0xBB73: 0x7C79, //CJK UNIFIED IDEOGRAPH + 0xBB74: 0x7C7A, //CJK UNIFIED IDEOGRAPH + 0xBB75: 0x7C7E, //CJK UNIFIED IDEOGRAPH + 0xBB76: 0x7C7F, //CJK UNIFIED IDEOGRAPH + 0xBB77: 0x7C80, //CJK UNIFIED IDEOGRAPH + 0xBB78: 0x7C81, //CJK UNIFIED IDEOGRAPH + 0xBB79: 0x7C82, //CJK UNIFIED IDEOGRAPH + 0xBB7A: 0x7C83, //CJK UNIFIED IDEOGRAPH + 0xBB7B: 0x7C84, //CJK UNIFIED IDEOGRAPH + 0xBB7C: 0x7C85, //CJK UNIFIED IDEOGRAPH + 0xBB7D: 0x7C86, //CJK UNIFIED IDEOGRAPH + 0xBB7E: 0x7C87, //CJK UNIFIED IDEOGRAPH + 0xBB80: 0x7C88, //CJK UNIFIED IDEOGRAPH + 0xBB81: 0x7C8A, //CJK UNIFIED IDEOGRAPH + 0xBB82: 0x7C8B, //CJK UNIFIED IDEOGRAPH + 0xBB83: 0x7C8C, //CJK UNIFIED IDEOGRAPH + 0xBB84: 0x7C8D, //CJK UNIFIED IDEOGRAPH + 0xBB85: 0x7C8E, //CJK UNIFIED IDEOGRAPH + 0xBB86: 0x7C8F, //CJK UNIFIED IDEOGRAPH + 0xBB87: 0x7C90, //CJK UNIFIED IDEOGRAPH + 0xBB88: 0x7C93, //CJK UNIFIED IDEOGRAPH + 0xBB89: 0x7C94, //CJK UNIFIED IDEOGRAPH + 0xBB8A: 0x7C96, //CJK UNIFIED IDEOGRAPH + 0xBB8B: 0x7C99, //CJK UNIFIED IDEOGRAPH + 0xBB8C: 0x7C9A, //CJK UNIFIED IDEOGRAPH + 0xBB8D: 0x7C9B, //CJK UNIFIED IDEOGRAPH + 0xBB8E: 0x7CA0, //CJK UNIFIED IDEOGRAPH + 0xBB8F: 0x7CA1, //CJK UNIFIED IDEOGRAPH + 0xBB90: 0x7CA3, //CJK UNIFIED IDEOGRAPH + 0xBB91: 0x7CA6, //CJK UNIFIED IDEOGRAPH + 0xBB92: 0x7CA7, //CJK UNIFIED IDEOGRAPH + 0xBB93: 0x7CA8, //CJK UNIFIED IDEOGRAPH + 0xBB94: 0x7CA9, //CJK UNIFIED IDEOGRAPH + 0xBB95: 0x7CAB, //CJK UNIFIED IDEOGRAPH + 0xBB96: 0x7CAC, //CJK UNIFIED IDEOGRAPH + 0xBB97: 0x7CAD, //CJK UNIFIED IDEOGRAPH + 0xBB98: 0x7CAF, //CJK UNIFIED IDEOGRAPH + 0xBB99: 0x7CB0, //CJK UNIFIED IDEOGRAPH + 0xBB9A: 0x7CB4, //CJK UNIFIED IDEOGRAPH + 0xBB9B: 0x7CB5, //CJK UNIFIED IDEOGRAPH + 0xBB9C: 0x7CB6, //CJK UNIFIED IDEOGRAPH + 0xBB9D: 0x7CB7, //CJK UNIFIED IDEOGRAPH + 0xBB9E: 0x7CB8, //CJK UNIFIED IDEOGRAPH + 0xBB9F: 0x7CBA, //CJK UNIFIED IDEOGRAPH + 0xBBA0: 0x7CBB, //CJK UNIFIED IDEOGRAPH + 0xBBA1: 0x5F27, //CJK UNIFIED IDEOGRAPH + 0xBBA2: 0x864E, //CJK UNIFIED IDEOGRAPH + 0xBBA3: 0x552C, //CJK UNIFIED IDEOGRAPH + 0xBBA4: 0x62A4, //CJK UNIFIED IDEOGRAPH + 0xBBA5: 0x4E92, //CJK UNIFIED IDEOGRAPH + 0xBBA6: 0x6CAA, //CJK UNIFIED IDEOGRAPH + 0xBBA7: 0x6237, //CJK UNIFIED IDEOGRAPH + 0xBBA8: 0x82B1, //CJK UNIFIED IDEOGRAPH + 0xBBA9: 0x54D7, //CJK UNIFIED IDEOGRAPH + 0xBBAA: 0x534E, //CJK UNIFIED IDEOGRAPH + 0xBBAB: 0x733E, //CJK UNIFIED IDEOGRAPH + 0xBBAC: 0x6ED1, //CJK UNIFIED IDEOGRAPH + 0xBBAD: 0x753B, //CJK UNIFIED IDEOGRAPH + 0xBBAE: 0x5212, //CJK UNIFIED IDEOGRAPH + 0xBBAF: 0x5316, //CJK UNIFIED IDEOGRAPH + 0xBBB0: 0x8BDD, //CJK UNIFIED IDEOGRAPH + 0xBBB1: 0x69D0, //CJK UNIFIED IDEOGRAPH + 0xBBB2: 0x5F8A, //CJK UNIFIED IDEOGRAPH + 0xBBB3: 0x6000, //CJK UNIFIED IDEOGRAPH + 0xBBB4: 0x6DEE, //CJK UNIFIED IDEOGRAPH + 0xBBB5: 0x574F, //CJK UNIFIED IDEOGRAPH + 0xBBB6: 0x6B22, //CJK UNIFIED IDEOGRAPH + 0xBBB7: 0x73AF, //CJK UNIFIED IDEOGRAPH + 0xBBB8: 0x6853, //CJK UNIFIED IDEOGRAPH + 0xBBB9: 0x8FD8, //CJK UNIFIED IDEOGRAPH + 0xBBBA: 0x7F13, //CJK UNIFIED IDEOGRAPH + 0xBBBB: 0x6362, //CJK UNIFIED IDEOGRAPH + 0xBBBC: 0x60A3, //CJK UNIFIED IDEOGRAPH + 0xBBBD: 0x5524, //CJK UNIFIED IDEOGRAPH + 0xBBBE: 0x75EA, //CJK UNIFIED IDEOGRAPH + 0xBBBF: 0x8C62, //CJK UNIFIED IDEOGRAPH + 0xBBC0: 0x7115, //CJK UNIFIED IDEOGRAPH + 0xBBC1: 0x6DA3, //CJK UNIFIED IDEOGRAPH + 0xBBC2: 0x5BA6, //CJK UNIFIED IDEOGRAPH + 0xBBC3: 0x5E7B, //CJK UNIFIED IDEOGRAPH + 0xBBC4: 0x8352, //CJK UNIFIED IDEOGRAPH + 0xBBC5: 0x614C, //CJK UNIFIED IDEOGRAPH + 0xBBC6: 0x9EC4, //CJK UNIFIED IDEOGRAPH + 0xBBC7: 0x78FA, //CJK UNIFIED IDEOGRAPH + 0xBBC8: 0x8757, //CJK UNIFIED IDEOGRAPH + 0xBBC9: 0x7C27, //CJK UNIFIED IDEOGRAPH + 0xBBCA: 0x7687, //CJK UNIFIED IDEOGRAPH + 0xBBCB: 0x51F0, //CJK UNIFIED IDEOGRAPH + 0xBBCC: 0x60F6, //CJK UNIFIED IDEOGRAPH + 0xBBCD: 0x714C, //CJK UNIFIED IDEOGRAPH + 0xBBCE: 0x6643, //CJK UNIFIED IDEOGRAPH + 0xBBCF: 0x5E4C, //CJK UNIFIED IDEOGRAPH + 0xBBD0: 0x604D, //CJK UNIFIED IDEOGRAPH + 0xBBD1: 0x8C0E, //CJK UNIFIED IDEOGRAPH + 0xBBD2: 0x7070, //CJK UNIFIED IDEOGRAPH + 0xBBD3: 0x6325, //CJK UNIFIED IDEOGRAPH + 0xBBD4: 0x8F89, //CJK UNIFIED IDEOGRAPH + 0xBBD5: 0x5FBD, //CJK UNIFIED IDEOGRAPH + 0xBBD6: 0x6062, //CJK UNIFIED IDEOGRAPH + 0xBBD7: 0x86D4, //CJK UNIFIED IDEOGRAPH + 0xBBD8: 0x56DE, //CJK UNIFIED IDEOGRAPH + 0xBBD9: 0x6BC1, //CJK UNIFIED IDEOGRAPH + 0xBBDA: 0x6094, //CJK UNIFIED IDEOGRAPH + 0xBBDB: 0x6167, //CJK UNIFIED IDEOGRAPH + 0xBBDC: 0x5349, //CJK UNIFIED IDEOGRAPH + 0xBBDD: 0x60E0, //CJK UNIFIED IDEOGRAPH + 0xBBDE: 0x6666, //CJK UNIFIED IDEOGRAPH + 0xBBDF: 0x8D3F, //CJK UNIFIED IDEOGRAPH + 0xBBE0: 0x79FD, //CJK UNIFIED IDEOGRAPH + 0xBBE1: 0x4F1A, //CJK UNIFIED IDEOGRAPH + 0xBBE2: 0x70E9, //CJK UNIFIED IDEOGRAPH + 0xBBE3: 0x6C47, //CJK UNIFIED IDEOGRAPH + 0xBBE4: 0x8BB3, //CJK UNIFIED IDEOGRAPH + 0xBBE5: 0x8BF2, //CJK UNIFIED IDEOGRAPH + 0xBBE6: 0x7ED8, //CJK UNIFIED IDEOGRAPH + 0xBBE7: 0x8364, //CJK UNIFIED IDEOGRAPH + 0xBBE8: 0x660F, //CJK UNIFIED IDEOGRAPH + 0xBBE9: 0x5A5A, //CJK UNIFIED IDEOGRAPH + 0xBBEA: 0x9B42, //CJK UNIFIED IDEOGRAPH + 0xBBEB: 0x6D51, //CJK UNIFIED IDEOGRAPH + 0xBBEC: 0x6DF7, //CJK UNIFIED IDEOGRAPH + 0xBBED: 0x8C41, //CJK UNIFIED IDEOGRAPH + 0xBBEE: 0x6D3B, //CJK UNIFIED IDEOGRAPH + 0xBBEF: 0x4F19, //CJK UNIFIED IDEOGRAPH + 0xBBF0: 0x706B, //CJK UNIFIED IDEOGRAPH + 0xBBF1: 0x83B7, //CJK UNIFIED IDEOGRAPH + 0xBBF2: 0x6216, //CJK UNIFIED IDEOGRAPH + 0xBBF3: 0x60D1, //CJK UNIFIED IDEOGRAPH + 0xBBF4: 0x970D, //CJK UNIFIED IDEOGRAPH + 0xBBF5: 0x8D27, //CJK UNIFIED IDEOGRAPH + 0xBBF6: 0x7978, //CJK UNIFIED IDEOGRAPH + 0xBBF7: 0x51FB, //CJK UNIFIED IDEOGRAPH + 0xBBF8: 0x573E, //CJK UNIFIED IDEOGRAPH + 0xBBF9: 0x57FA, //CJK UNIFIED IDEOGRAPH + 0xBBFA: 0x673A, //CJK UNIFIED IDEOGRAPH + 0xBBFB: 0x7578, //CJK UNIFIED IDEOGRAPH + 0xBBFC: 0x7A3D, //CJK UNIFIED IDEOGRAPH + 0xBBFD: 0x79EF, //CJK UNIFIED IDEOGRAPH + 0xBBFE: 0x7B95, //CJK UNIFIED IDEOGRAPH + 0xBC40: 0x7CBF, //CJK UNIFIED IDEOGRAPH + 0xBC41: 0x7CC0, //CJK UNIFIED IDEOGRAPH + 0xBC42: 0x7CC2, //CJK UNIFIED IDEOGRAPH + 0xBC43: 0x7CC3, //CJK UNIFIED IDEOGRAPH + 0xBC44: 0x7CC4, //CJK UNIFIED IDEOGRAPH + 0xBC45: 0x7CC6, //CJK UNIFIED IDEOGRAPH + 0xBC46: 0x7CC9, //CJK UNIFIED IDEOGRAPH + 0xBC47: 0x7CCB, //CJK UNIFIED IDEOGRAPH + 0xBC48: 0x7CCE, //CJK UNIFIED IDEOGRAPH + 0xBC49: 0x7CCF, //CJK UNIFIED IDEOGRAPH + 0xBC4A: 0x7CD0, //CJK UNIFIED IDEOGRAPH + 0xBC4B: 0x7CD1, //CJK UNIFIED IDEOGRAPH + 0xBC4C: 0x7CD2, //CJK UNIFIED IDEOGRAPH + 0xBC4D: 0x7CD3, //CJK UNIFIED IDEOGRAPH + 0xBC4E: 0x7CD4, //CJK UNIFIED IDEOGRAPH + 0xBC4F: 0x7CD8, //CJK UNIFIED IDEOGRAPH + 0xBC50: 0x7CDA, //CJK UNIFIED IDEOGRAPH + 0xBC51: 0x7CDB, //CJK UNIFIED IDEOGRAPH + 0xBC52: 0x7CDD, //CJK UNIFIED IDEOGRAPH + 0xBC53: 0x7CDE, //CJK UNIFIED IDEOGRAPH + 0xBC54: 0x7CE1, //CJK UNIFIED IDEOGRAPH + 0xBC55: 0x7CE2, //CJK UNIFIED IDEOGRAPH + 0xBC56: 0x7CE3, //CJK UNIFIED IDEOGRAPH + 0xBC57: 0x7CE4, //CJK UNIFIED IDEOGRAPH + 0xBC58: 0x7CE5, //CJK UNIFIED IDEOGRAPH + 0xBC59: 0x7CE6, //CJK UNIFIED IDEOGRAPH + 0xBC5A: 0x7CE7, //CJK UNIFIED IDEOGRAPH + 0xBC5B: 0x7CE9, //CJK UNIFIED IDEOGRAPH + 0xBC5C: 0x7CEA, //CJK UNIFIED IDEOGRAPH + 0xBC5D: 0x7CEB, //CJK UNIFIED IDEOGRAPH + 0xBC5E: 0x7CEC, //CJK UNIFIED IDEOGRAPH + 0xBC5F: 0x7CED, //CJK UNIFIED IDEOGRAPH + 0xBC60: 0x7CEE, //CJK UNIFIED IDEOGRAPH + 0xBC61: 0x7CF0, //CJK UNIFIED IDEOGRAPH + 0xBC62: 0x7CF1, //CJK UNIFIED IDEOGRAPH + 0xBC63: 0x7CF2, //CJK UNIFIED IDEOGRAPH + 0xBC64: 0x7CF3, //CJK UNIFIED IDEOGRAPH + 0xBC65: 0x7CF4, //CJK UNIFIED IDEOGRAPH + 0xBC66: 0x7CF5, //CJK UNIFIED IDEOGRAPH + 0xBC67: 0x7CF6, //CJK UNIFIED IDEOGRAPH + 0xBC68: 0x7CF7, //CJK UNIFIED IDEOGRAPH + 0xBC69: 0x7CF9, //CJK UNIFIED IDEOGRAPH + 0xBC6A: 0x7CFA, //CJK UNIFIED IDEOGRAPH + 0xBC6B: 0x7CFC, //CJK UNIFIED IDEOGRAPH + 0xBC6C: 0x7CFD, //CJK UNIFIED IDEOGRAPH + 0xBC6D: 0x7CFE, //CJK UNIFIED IDEOGRAPH + 0xBC6E: 0x7CFF, //CJK UNIFIED IDEOGRAPH + 0xBC6F: 0x7D00, //CJK UNIFIED IDEOGRAPH + 0xBC70: 0x7D01, //CJK UNIFIED IDEOGRAPH + 0xBC71: 0x7D02, //CJK UNIFIED IDEOGRAPH + 0xBC72: 0x7D03, //CJK UNIFIED IDEOGRAPH + 0xBC73: 0x7D04, //CJK UNIFIED IDEOGRAPH + 0xBC74: 0x7D05, //CJK UNIFIED IDEOGRAPH + 0xBC75: 0x7D06, //CJK UNIFIED IDEOGRAPH + 0xBC76: 0x7D07, //CJK UNIFIED IDEOGRAPH + 0xBC77: 0x7D08, //CJK UNIFIED IDEOGRAPH + 0xBC78: 0x7D09, //CJK UNIFIED IDEOGRAPH + 0xBC79: 0x7D0B, //CJK UNIFIED IDEOGRAPH + 0xBC7A: 0x7D0C, //CJK UNIFIED IDEOGRAPH + 0xBC7B: 0x7D0D, //CJK UNIFIED IDEOGRAPH + 0xBC7C: 0x7D0E, //CJK UNIFIED IDEOGRAPH + 0xBC7D: 0x7D0F, //CJK UNIFIED IDEOGRAPH + 0xBC7E: 0x7D10, //CJK UNIFIED IDEOGRAPH + 0xBC80: 0x7D11, //CJK UNIFIED IDEOGRAPH + 0xBC81: 0x7D12, //CJK UNIFIED IDEOGRAPH + 0xBC82: 0x7D13, //CJK UNIFIED IDEOGRAPH + 0xBC83: 0x7D14, //CJK UNIFIED IDEOGRAPH + 0xBC84: 0x7D15, //CJK UNIFIED IDEOGRAPH + 0xBC85: 0x7D16, //CJK UNIFIED IDEOGRAPH + 0xBC86: 0x7D17, //CJK UNIFIED IDEOGRAPH + 0xBC87: 0x7D18, //CJK UNIFIED IDEOGRAPH + 0xBC88: 0x7D19, //CJK UNIFIED IDEOGRAPH + 0xBC89: 0x7D1A, //CJK UNIFIED IDEOGRAPH + 0xBC8A: 0x7D1B, //CJK UNIFIED IDEOGRAPH + 0xBC8B: 0x7D1C, //CJK UNIFIED IDEOGRAPH + 0xBC8C: 0x7D1D, //CJK UNIFIED IDEOGRAPH + 0xBC8D: 0x7D1E, //CJK UNIFIED IDEOGRAPH + 0xBC8E: 0x7D1F, //CJK UNIFIED IDEOGRAPH + 0xBC8F: 0x7D21, //CJK UNIFIED IDEOGRAPH + 0xBC90: 0x7D23, //CJK UNIFIED IDEOGRAPH + 0xBC91: 0x7D24, //CJK UNIFIED IDEOGRAPH + 0xBC92: 0x7D25, //CJK UNIFIED IDEOGRAPH + 0xBC93: 0x7D26, //CJK UNIFIED IDEOGRAPH + 0xBC94: 0x7D28, //CJK UNIFIED IDEOGRAPH + 0xBC95: 0x7D29, //CJK UNIFIED IDEOGRAPH + 0xBC96: 0x7D2A, //CJK UNIFIED IDEOGRAPH + 0xBC97: 0x7D2C, //CJK UNIFIED IDEOGRAPH + 0xBC98: 0x7D2D, //CJK UNIFIED IDEOGRAPH + 0xBC99: 0x7D2E, //CJK UNIFIED IDEOGRAPH + 0xBC9A: 0x7D30, //CJK UNIFIED IDEOGRAPH + 0xBC9B: 0x7D31, //CJK UNIFIED IDEOGRAPH + 0xBC9C: 0x7D32, //CJK UNIFIED IDEOGRAPH + 0xBC9D: 0x7D33, //CJK UNIFIED IDEOGRAPH + 0xBC9E: 0x7D34, //CJK UNIFIED IDEOGRAPH + 0xBC9F: 0x7D35, //CJK UNIFIED IDEOGRAPH + 0xBCA0: 0x7D36, //CJK UNIFIED IDEOGRAPH + 0xBCA1: 0x808C, //CJK UNIFIED IDEOGRAPH + 0xBCA2: 0x9965, //CJK UNIFIED IDEOGRAPH + 0xBCA3: 0x8FF9, //CJK UNIFIED IDEOGRAPH + 0xBCA4: 0x6FC0, //CJK UNIFIED IDEOGRAPH + 0xBCA5: 0x8BA5, //CJK UNIFIED IDEOGRAPH + 0xBCA6: 0x9E21, //CJK UNIFIED IDEOGRAPH + 0xBCA7: 0x59EC, //CJK UNIFIED IDEOGRAPH + 0xBCA8: 0x7EE9, //CJK UNIFIED IDEOGRAPH + 0xBCA9: 0x7F09, //CJK UNIFIED IDEOGRAPH + 0xBCAA: 0x5409, //CJK UNIFIED IDEOGRAPH + 0xBCAB: 0x6781, //CJK UNIFIED IDEOGRAPH + 0xBCAC: 0x68D8, //CJK UNIFIED IDEOGRAPH + 0xBCAD: 0x8F91, //CJK UNIFIED IDEOGRAPH + 0xBCAE: 0x7C4D, //CJK UNIFIED IDEOGRAPH + 0xBCAF: 0x96C6, //CJK UNIFIED IDEOGRAPH + 0xBCB0: 0x53CA, //CJK UNIFIED IDEOGRAPH + 0xBCB1: 0x6025, //CJK UNIFIED IDEOGRAPH + 0xBCB2: 0x75BE, //CJK UNIFIED IDEOGRAPH + 0xBCB3: 0x6C72, //CJK UNIFIED IDEOGRAPH + 0xBCB4: 0x5373, //CJK UNIFIED IDEOGRAPH + 0xBCB5: 0x5AC9, //CJK UNIFIED IDEOGRAPH + 0xBCB6: 0x7EA7, //CJK UNIFIED IDEOGRAPH + 0xBCB7: 0x6324, //CJK UNIFIED IDEOGRAPH + 0xBCB8: 0x51E0, //CJK UNIFIED IDEOGRAPH + 0xBCB9: 0x810A, //CJK UNIFIED IDEOGRAPH + 0xBCBA: 0x5DF1, //CJK UNIFIED IDEOGRAPH + 0xBCBB: 0x84DF, //CJK UNIFIED IDEOGRAPH + 0xBCBC: 0x6280, //CJK UNIFIED IDEOGRAPH + 0xBCBD: 0x5180, //CJK UNIFIED IDEOGRAPH + 0xBCBE: 0x5B63, //CJK UNIFIED IDEOGRAPH + 0xBCBF: 0x4F0E, //CJK UNIFIED IDEOGRAPH + 0xBCC0: 0x796D, //CJK UNIFIED IDEOGRAPH + 0xBCC1: 0x5242, //CJK UNIFIED IDEOGRAPH + 0xBCC2: 0x60B8, //CJK UNIFIED IDEOGRAPH + 0xBCC3: 0x6D4E, //CJK UNIFIED IDEOGRAPH + 0xBCC4: 0x5BC4, //CJK UNIFIED IDEOGRAPH + 0xBCC5: 0x5BC2, //CJK UNIFIED IDEOGRAPH + 0xBCC6: 0x8BA1, //CJK UNIFIED IDEOGRAPH + 0xBCC7: 0x8BB0, //CJK UNIFIED IDEOGRAPH + 0xBCC8: 0x65E2, //CJK UNIFIED IDEOGRAPH + 0xBCC9: 0x5FCC, //CJK UNIFIED IDEOGRAPH + 0xBCCA: 0x9645, //CJK UNIFIED IDEOGRAPH + 0xBCCB: 0x5993, //CJK UNIFIED IDEOGRAPH + 0xBCCC: 0x7EE7, //CJK UNIFIED IDEOGRAPH + 0xBCCD: 0x7EAA, //CJK UNIFIED IDEOGRAPH + 0xBCCE: 0x5609, //CJK UNIFIED IDEOGRAPH + 0xBCCF: 0x67B7, //CJK UNIFIED IDEOGRAPH + 0xBCD0: 0x5939, //CJK UNIFIED IDEOGRAPH + 0xBCD1: 0x4F73, //CJK UNIFIED IDEOGRAPH + 0xBCD2: 0x5BB6, //CJK UNIFIED IDEOGRAPH + 0xBCD3: 0x52A0, //CJK UNIFIED IDEOGRAPH + 0xBCD4: 0x835A, //CJK UNIFIED IDEOGRAPH + 0xBCD5: 0x988A, //CJK UNIFIED IDEOGRAPH + 0xBCD6: 0x8D3E, //CJK UNIFIED IDEOGRAPH + 0xBCD7: 0x7532, //CJK UNIFIED IDEOGRAPH + 0xBCD8: 0x94BE, //CJK UNIFIED IDEOGRAPH + 0xBCD9: 0x5047, //CJK UNIFIED IDEOGRAPH + 0xBCDA: 0x7A3C, //CJK UNIFIED IDEOGRAPH + 0xBCDB: 0x4EF7, //CJK UNIFIED IDEOGRAPH + 0xBCDC: 0x67B6, //CJK UNIFIED IDEOGRAPH + 0xBCDD: 0x9A7E, //CJK UNIFIED IDEOGRAPH + 0xBCDE: 0x5AC1, //CJK UNIFIED IDEOGRAPH + 0xBCDF: 0x6B7C, //CJK UNIFIED IDEOGRAPH + 0xBCE0: 0x76D1, //CJK UNIFIED IDEOGRAPH + 0xBCE1: 0x575A, //CJK UNIFIED IDEOGRAPH + 0xBCE2: 0x5C16, //CJK UNIFIED IDEOGRAPH + 0xBCE3: 0x7B3A, //CJK UNIFIED IDEOGRAPH + 0xBCE4: 0x95F4, //CJK UNIFIED IDEOGRAPH + 0xBCE5: 0x714E, //CJK UNIFIED IDEOGRAPH + 0xBCE6: 0x517C, //CJK UNIFIED IDEOGRAPH + 0xBCE7: 0x80A9, //CJK UNIFIED IDEOGRAPH + 0xBCE8: 0x8270, //CJK UNIFIED IDEOGRAPH + 0xBCE9: 0x5978, //CJK UNIFIED IDEOGRAPH + 0xBCEA: 0x7F04, //CJK UNIFIED IDEOGRAPH + 0xBCEB: 0x8327, //CJK UNIFIED IDEOGRAPH + 0xBCEC: 0x68C0, //CJK UNIFIED IDEOGRAPH + 0xBCED: 0x67EC, //CJK UNIFIED IDEOGRAPH + 0xBCEE: 0x78B1, //CJK UNIFIED IDEOGRAPH + 0xBCEF: 0x7877, //CJK UNIFIED IDEOGRAPH + 0xBCF0: 0x62E3, //CJK UNIFIED IDEOGRAPH + 0xBCF1: 0x6361, //CJK UNIFIED IDEOGRAPH + 0xBCF2: 0x7B80, //CJK UNIFIED IDEOGRAPH + 0xBCF3: 0x4FED, //CJK UNIFIED IDEOGRAPH + 0xBCF4: 0x526A, //CJK UNIFIED IDEOGRAPH + 0xBCF5: 0x51CF, //CJK UNIFIED IDEOGRAPH + 0xBCF6: 0x8350, //CJK UNIFIED IDEOGRAPH + 0xBCF7: 0x69DB, //CJK UNIFIED IDEOGRAPH + 0xBCF8: 0x9274, //CJK UNIFIED IDEOGRAPH + 0xBCF9: 0x8DF5, //CJK UNIFIED IDEOGRAPH + 0xBCFA: 0x8D31, //CJK UNIFIED IDEOGRAPH + 0xBCFB: 0x89C1, //CJK UNIFIED IDEOGRAPH + 0xBCFC: 0x952E, //CJK UNIFIED IDEOGRAPH + 0xBCFD: 0x7BAD, //CJK UNIFIED IDEOGRAPH + 0xBCFE: 0x4EF6, //CJK UNIFIED IDEOGRAPH + 0xBD40: 0x7D37, //CJK UNIFIED IDEOGRAPH + 0xBD41: 0x7D38, //CJK UNIFIED IDEOGRAPH + 0xBD42: 0x7D39, //CJK UNIFIED IDEOGRAPH + 0xBD43: 0x7D3A, //CJK UNIFIED IDEOGRAPH + 0xBD44: 0x7D3B, //CJK UNIFIED IDEOGRAPH + 0xBD45: 0x7D3C, //CJK UNIFIED IDEOGRAPH + 0xBD46: 0x7D3D, //CJK UNIFIED IDEOGRAPH + 0xBD47: 0x7D3E, //CJK UNIFIED IDEOGRAPH + 0xBD48: 0x7D3F, //CJK UNIFIED IDEOGRAPH + 0xBD49: 0x7D40, //CJK UNIFIED IDEOGRAPH + 0xBD4A: 0x7D41, //CJK UNIFIED IDEOGRAPH + 0xBD4B: 0x7D42, //CJK UNIFIED IDEOGRAPH + 0xBD4C: 0x7D43, //CJK UNIFIED IDEOGRAPH + 0xBD4D: 0x7D44, //CJK UNIFIED IDEOGRAPH + 0xBD4E: 0x7D45, //CJK UNIFIED IDEOGRAPH + 0xBD4F: 0x7D46, //CJK UNIFIED IDEOGRAPH + 0xBD50: 0x7D47, //CJK UNIFIED IDEOGRAPH + 0xBD51: 0x7D48, //CJK UNIFIED IDEOGRAPH + 0xBD52: 0x7D49, //CJK UNIFIED IDEOGRAPH + 0xBD53: 0x7D4A, //CJK UNIFIED IDEOGRAPH + 0xBD54: 0x7D4B, //CJK UNIFIED IDEOGRAPH + 0xBD55: 0x7D4C, //CJK UNIFIED IDEOGRAPH + 0xBD56: 0x7D4D, //CJK UNIFIED IDEOGRAPH + 0xBD57: 0x7D4E, //CJK UNIFIED IDEOGRAPH + 0xBD58: 0x7D4F, //CJK UNIFIED IDEOGRAPH + 0xBD59: 0x7D50, //CJK UNIFIED IDEOGRAPH + 0xBD5A: 0x7D51, //CJK UNIFIED IDEOGRAPH + 0xBD5B: 0x7D52, //CJK UNIFIED IDEOGRAPH + 0xBD5C: 0x7D53, //CJK UNIFIED IDEOGRAPH + 0xBD5D: 0x7D54, //CJK UNIFIED IDEOGRAPH + 0xBD5E: 0x7D55, //CJK UNIFIED IDEOGRAPH + 0xBD5F: 0x7D56, //CJK UNIFIED IDEOGRAPH + 0xBD60: 0x7D57, //CJK UNIFIED IDEOGRAPH + 0xBD61: 0x7D58, //CJK UNIFIED IDEOGRAPH + 0xBD62: 0x7D59, //CJK UNIFIED IDEOGRAPH + 0xBD63: 0x7D5A, //CJK UNIFIED IDEOGRAPH + 0xBD64: 0x7D5B, //CJK UNIFIED IDEOGRAPH + 0xBD65: 0x7D5C, //CJK UNIFIED IDEOGRAPH + 0xBD66: 0x7D5D, //CJK UNIFIED IDEOGRAPH + 0xBD67: 0x7D5E, //CJK UNIFIED IDEOGRAPH + 0xBD68: 0x7D5F, //CJK UNIFIED IDEOGRAPH + 0xBD69: 0x7D60, //CJK UNIFIED IDEOGRAPH + 0xBD6A: 0x7D61, //CJK UNIFIED IDEOGRAPH + 0xBD6B: 0x7D62, //CJK UNIFIED IDEOGRAPH + 0xBD6C: 0x7D63, //CJK UNIFIED IDEOGRAPH + 0xBD6D: 0x7D64, //CJK UNIFIED IDEOGRAPH + 0xBD6E: 0x7D65, //CJK UNIFIED IDEOGRAPH + 0xBD6F: 0x7D66, //CJK UNIFIED IDEOGRAPH + 0xBD70: 0x7D67, //CJK UNIFIED IDEOGRAPH + 0xBD71: 0x7D68, //CJK UNIFIED IDEOGRAPH + 0xBD72: 0x7D69, //CJK UNIFIED IDEOGRAPH + 0xBD73: 0x7D6A, //CJK UNIFIED IDEOGRAPH + 0xBD74: 0x7D6B, //CJK UNIFIED IDEOGRAPH + 0xBD75: 0x7D6C, //CJK UNIFIED IDEOGRAPH + 0xBD76: 0x7D6D, //CJK UNIFIED IDEOGRAPH + 0xBD77: 0x7D6F, //CJK UNIFIED IDEOGRAPH + 0xBD78: 0x7D70, //CJK UNIFIED IDEOGRAPH + 0xBD79: 0x7D71, //CJK UNIFIED IDEOGRAPH + 0xBD7A: 0x7D72, //CJK UNIFIED IDEOGRAPH + 0xBD7B: 0x7D73, //CJK UNIFIED IDEOGRAPH + 0xBD7C: 0x7D74, //CJK UNIFIED IDEOGRAPH + 0xBD7D: 0x7D75, //CJK UNIFIED IDEOGRAPH + 0xBD7E: 0x7D76, //CJK UNIFIED IDEOGRAPH + 0xBD80: 0x7D78, //CJK UNIFIED IDEOGRAPH + 0xBD81: 0x7D79, //CJK UNIFIED IDEOGRAPH + 0xBD82: 0x7D7A, //CJK UNIFIED IDEOGRAPH + 0xBD83: 0x7D7B, //CJK UNIFIED IDEOGRAPH + 0xBD84: 0x7D7C, //CJK UNIFIED IDEOGRAPH + 0xBD85: 0x7D7D, //CJK UNIFIED IDEOGRAPH + 0xBD86: 0x7D7E, //CJK UNIFIED IDEOGRAPH + 0xBD87: 0x7D7F, //CJK UNIFIED IDEOGRAPH + 0xBD88: 0x7D80, //CJK UNIFIED IDEOGRAPH + 0xBD89: 0x7D81, //CJK UNIFIED IDEOGRAPH + 0xBD8A: 0x7D82, //CJK UNIFIED IDEOGRAPH + 0xBD8B: 0x7D83, //CJK UNIFIED IDEOGRAPH + 0xBD8C: 0x7D84, //CJK UNIFIED IDEOGRAPH + 0xBD8D: 0x7D85, //CJK UNIFIED IDEOGRAPH + 0xBD8E: 0x7D86, //CJK UNIFIED IDEOGRAPH + 0xBD8F: 0x7D87, //CJK UNIFIED IDEOGRAPH + 0xBD90: 0x7D88, //CJK UNIFIED IDEOGRAPH + 0xBD91: 0x7D89, //CJK UNIFIED IDEOGRAPH + 0xBD92: 0x7D8A, //CJK UNIFIED IDEOGRAPH + 0xBD93: 0x7D8B, //CJK UNIFIED IDEOGRAPH + 0xBD94: 0x7D8C, //CJK UNIFIED IDEOGRAPH + 0xBD95: 0x7D8D, //CJK UNIFIED IDEOGRAPH + 0xBD96: 0x7D8E, //CJK UNIFIED IDEOGRAPH + 0xBD97: 0x7D8F, //CJK UNIFIED IDEOGRAPH + 0xBD98: 0x7D90, //CJK UNIFIED IDEOGRAPH + 0xBD99: 0x7D91, //CJK UNIFIED IDEOGRAPH + 0xBD9A: 0x7D92, //CJK UNIFIED IDEOGRAPH + 0xBD9B: 0x7D93, //CJK UNIFIED IDEOGRAPH + 0xBD9C: 0x7D94, //CJK UNIFIED IDEOGRAPH + 0xBD9D: 0x7D95, //CJK UNIFIED IDEOGRAPH + 0xBD9E: 0x7D96, //CJK UNIFIED IDEOGRAPH + 0xBD9F: 0x7D97, //CJK UNIFIED IDEOGRAPH + 0xBDA0: 0x7D98, //CJK UNIFIED IDEOGRAPH + 0xBDA1: 0x5065, //CJK UNIFIED IDEOGRAPH + 0xBDA2: 0x8230, //CJK UNIFIED IDEOGRAPH + 0xBDA3: 0x5251, //CJK UNIFIED IDEOGRAPH + 0xBDA4: 0x996F, //CJK UNIFIED IDEOGRAPH + 0xBDA5: 0x6E10, //CJK UNIFIED IDEOGRAPH + 0xBDA6: 0x6E85, //CJK UNIFIED IDEOGRAPH + 0xBDA7: 0x6DA7, //CJK UNIFIED IDEOGRAPH + 0xBDA8: 0x5EFA, //CJK UNIFIED IDEOGRAPH + 0xBDA9: 0x50F5, //CJK UNIFIED IDEOGRAPH + 0xBDAA: 0x59DC, //CJK UNIFIED IDEOGRAPH + 0xBDAB: 0x5C06, //CJK UNIFIED IDEOGRAPH + 0xBDAC: 0x6D46, //CJK UNIFIED IDEOGRAPH + 0xBDAD: 0x6C5F, //CJK UNIFIED IDEOGRAPH + 0xBDAE: 0x7586, //CJK UNIFIED IDEOGRAPH + 0xBDAF: 0x848B, //CJK UNIFIED IDEOGRAPH + 0xBDB0: 0x6868, //CJK UNIFIED IDEOGRAPH + 0xBDB1: 0x5956, //CJK UNIFIED IDEOGRAPH + 0xBDB2: 0x8BB2, //CJK UNIFIED IDEOGRAPH + 0xBDB3: 0x5320, //CJK UNIFIED IDEOGRAPH + 0xBDB4: 0x9171, //CJK UNIFIED IDEOGRAPH + 0xBDB5: 0x964D, //CJK UNIFIED IDEOGRAPH + 0xBDB6: 0x8549, //CJK UNIFIED IDEOGRAPH + 0xBDB7: 0x6912, //CJK UNIFIED IDEOGRAPH + 0xBDB8: 0x7901, //CJK UNIFIED IDEOGRAPH + 0xBDB9: 0x7126, //CJK UNIFIED IDEOGRAPH + 0xBDBA: 0x80F6, //CJK UNIFIED IDEOGRAPH + 0xBDBB: 0x4EA4, //CJK UNIFIED IDEOGRAPH + 0xBDBC: 0x90CA, //CJK UNIFIED IDEOGRAPH + 0xBDBD: 0x6D47, //CJK UNIFIED IDEOGRAPH + 0xBDBE: 0x9A84, //CJK UNIFIED IDEOGRAPH + 0xBDBF: 0x5A07, //CJK UNIFIED IDEOGRAPH + 0xBDC0: 0x56BC, //CJK UNIFIED IDEOGRAPH + 0xBDC1: 0x6405, //CJK UNIFIED IDEOGRAPH + 0xBDC2: 0x94F0, //CJK UNIFIED IDEOGRAPH + 0xBDC3: 0x77EB, //CJK UNIFIED IDEOGRAPH + 0xBDC4: 0x4FA5, //CJK UNIFIED IDEOGRAPH + 0xBDC5: 0x811A, //CJK UNIFIED IDEOGRAPH + 0xBDC6: 0x72E1, //CJK UNIFIED IDEOGRAPH + 0xBDC7: 0x89D2, //CJK UNIFIED IDEOGRAPH + 0xBDC8: 0x997A, //CJK UNIFIED IDEOGRAPH + 0xBDC9: 0x7F34, //CJK UNIFIED IDEOGRAPH + 0xBDCA: 0x7EDE, //CJK UNIFIED IDEOGRAPH + 0xBDCB: 0x527F, //CJK UNIFIED IDEOGRAPH + 0xBDCC: 0x6559, //CJK UNIFIED IDEOGRAPH + 0xBDCD: 0x9175, //CJK UNIFIED IDEOGRAPH + 0xBDCE: 0x8F7F, //CJK UNIFIED IDEOGRAPH + 0xBDCF: 0x8F83, //CJK UNIFIED IDEOGRAPH + 0xBDD0: 0x53EB, //CJK UNIFIED IDEOGRAPH + 0xBDD1: 0x7A96, //CJK UNIFIED IDEOGRAPH + 0xBDD2: 0x63ED, //CJK UNIFIED IDEOGRAPH + 0xBDD3: 0x63A5, //CJK UNIFIED IDEOGRAPH + 0xBDD4: 0x7686, //CJK UNIFIED IDEOGRAPH + 0xBDD5: 0x79F8, //CJK UNIFIED IDEOGRAPH + 0xBDD6: 0x8857, //CJK UNIFIED IDEOGRAPH + 0xBDD7: 0x9636, //CJK UNIFIED IDEOGRAPH + 0xBDD8: 0x622A, //CJK UNIFIED IDEOGRAPH + 0xBDD9: 0x52AB, //CJK UNIFIED IDEOGRAPH + 0xBDDA: 0x8282, //CJK UNIFIED IDEOGRAPH + 0xBDDB: 0x6854, //CJK UNIFIED IDEOGRAPH + 0xBDDC: 0x6770, //CJK UNIFIED IDEOGRAPH + 0xBDDD: 0x6377, //CJK UNIFIED IDEOGRAPH + 0xBDDE: 0x776B, //CJK UNIFIED IDEOGRAPH + 0xBDDF: 0x7AED, //CJK UNIFIED IDEOGRAPH + 0xBDE0: 0x6D01, //CJK UNIFIED IDEOGRAPH + 0xBDE1: 0x7ED3, //CJK UNIFIED IDEOGRAPH + 0xBDE2: 0x89E3, //CJK UNIFIED IDEOGRAPH + 0xBDE3: 0x59D0, //CJK UNIFIED IDEOGRAPH + 0xBDE4: 0x6212, //CJK UNIFIED IDEOGRAPH + 0xBDE5: 0x85C9, //CJK UNIFIED IDEOGRAPH + 0xBDE6: 0x82A5, //CJK UNIFIED IDEOGRAPH + 0xBDE7: 0x754C, //CJK UNIFIED IDEOGRAPH + 0xBDE8: 0x501F, //CJK UNIFIED IDEOGRAPH + 0xBDE9: 0x4ECB, //CJK UNIFIED IDEOGRAPH + 0xBDEA: 0x75A5, //CJK UNIFIED IDEOGRAPH + 0xBDEB: 0x8BEB, //CJK UNIFIED IDEOGRAPH + 0xBDEC: 0x5C4A, //CJK UNIFIED IDEOGRAPH + 0xBDED: 0x5DFE, //CJK UNIFIED IDEOGRAPH + 0xBDEE: 0x7B4B, //CJK UNIFIED IDEOGRAPH + 0xBDEF: 0x65A4, //CJK UNIFIED IDEOGRAPH + 0xBDF0: 0x91D1, //CJK UNIFIED IDEOGRAPH + 0xBDF1: 0x4ECA, //CJK UNIFIED IDEOGRAPH + 0xBDF2: 0x6D25, //CJK UNIFIED IDEOGRAPH + 0xBDF3: 0x895F, //CJK UNIFIED IDEOGRAPH + 0xBDF4: 0x7D27, //CJK UNIFIED IDEOGRAPH + 0xBDF5: 0x9526, //CJK UNIFIED IDEOGRAPH + 0xBDF6: 0x4EC5, //CJK UNIFIED IDEOGRAPH + 0xBDF7: 0x8C28, //CJK UNIFIED IDEOGRAPH + 0xBDF8: 0x8FDB, //CJK UNIFIED IDEOGRAPH + 0xBDF9: 0x9773, //CJK UNIFIED IDEOGRAPH + 0xBDFA: 0x664B, //CJK UNIFIED IDEOGRAPH + 0xBDFB: 0x7981, //CJK UNIFIED IDEOGRAPH + 0xBDFC: 0x8FD1, //CJK UNIFIED IDEOGRAPH + 0xBDFD: 0x70EC, //CJK UNIFIED IDEOGRAPH + 0xBDFE: 0x6D78, //CJK UNIFIED IDEOGRAPH + 0xBE40: 0x7D99, //CJK UNIFIED IDEOGRAPH + 0xBE41: 0x7D9A, //CJK UNIFIED IDEOGRAPH + 0xBE42: 0x7D9B, //CJK UNIFIED IDEOGRAPH + 0xBE43: 0x7D9C, //CJK UNIFIED IDEOGRAPH + 0xBE44: 0x7D9D, //CJK UNIFIED IDEOGRAPH + 0xBE45: 0x7D9E, //CJK UNIFIED IDEOGRAPH + 0xBE46: 0x7D9F, //CJK UNIFIED IDEOGRAPH + 0xBE47: 0x7DA0, //CJK UNIFIED IDEOGRAPH + 0xBE48: 0x7DA1, //CJK UNIFIED IDEOGRAPH + 0xBE49: 0x7DA2, //CJK UNIFIED IDEOGRAPH + 0xBE4A: 0x7DA3, //CJK UNIFIED IDEOGRAPH + 0xBE4B: 0x7DA4, //CJK UNIFIED IDEOGRAPH + 0xBE4C: 0x7DA5, //CJK UNIFIED IDEOGRAPH + 0xBE4D: 0x7DA7, //CJK UNIFIED IDEOGRAPH + 0xBE4E: 0x7DA8, //CJK UNIFIED IDEOGRAPH + 0xBE4F: 0x7DA9, //CJK UNIFIED IDEOGRAPH + 0xBE50: 0x7DAA, //CJK UNIFIED IDEOGRAPH + 0xBE51: 0x7DAB, //CJK UNIFIED IDEOGRAPH + 0xBE52: 0x7DAC, //CJK UNIFIED IDEOGRAPH + 0xBE53: 0x7DAD, //CJK UNIFIED IDEOGRAPH + 0xBE54: 0x7DAF, //CJK UNIFIED IDEOGRAPH + 0xBE55: 0x7DB0, //CJK UNIFIED IDEOGRAPH + 0xBE56: 0x7DB1, //CJK UNIFIED IDEOGRAPH + 0xBE57: 0x7DB2, //CJK UNIFIED IDEOGRAPH + 0xBE58: 0x7DB3, //CJK UNIFIED IDEOGRAPH + 0xBE59: 0x7DB4, //CJK UNIFIED IDEOGRAPH + 0xBE5A: 0x7DB5, //CJK UNIFIED IDEOGRAPH + 0xBE5B: 0x7DB6, //CJK UNIFIED IDEOGRAPH + 0xBE5C: 0x7DB7, //CJK UNIFIED IDEOGRAPH + 0xBE5D: 0x7DB8, //CJK UNIFIED IDEOGRAPH + 0xBE5E: 0x7DB9, //CJK UNIFIED IDEOGRAPH + 0xBE5F: 0x7DBA, //CJK UNIFIED IDEOGRAPH + 0xBE60: 0x7DBB, //CJK UNIFIED IDEOGRAPH + 0xBE61: 0x7DBC, //CJK UNIFIED IDEOGRAPH + 0xBE62: 0x7DBD, //CJK UNIFIED IDEOGRAPH + 0xBE63: 0x7DBE, //CJK UNIFIED IDEOGRAPH + 0xBE64: 0x7DBF, //CJK UNIFIED IDEOGRAPH + 0xBE65: 0x7DC0, //CJK UNIFIED IDEOGRAPH + 0xBE66: 0x7DC1, //CJK UNIFIED IDEOGRAPH + 0xBE67: 0x7DC2, //CJK UNIFIED IDEOGRAPH + 0xBE68: 0x7DC3, //CJK UNIFIED IDEOGRAPH + 0xBE69: 0x7DC4, //CJK UNIFIED IDEOGRAPH + 0xBE6A: 0x7DC5, //CJK UNIFIED IDEOGRAPH + 0xBE6B: 0x7DC6, //CJK UNIFIED IDEOGRAPH + 0xBE6C: 0x7DC7, //CJK UNIFIED IDEOGRAPH + 0xBE6D: 0x7DC8, //CJK UNIFIED IDEOGRAPH + 0xBE6E: 0x7DC9, //CJK UNIFIED IDEOGRAPH + 0xBE6F: 0x7DCA, //CJK UNIFIED IDEOGRAPH + 0xBE70: 0x7DCB, //CJK UNIFIED IDEOGRAPH + 0xBE71: 0x7DCC, //CJK UNIFIED IDEOGRAPH + 0xBE72: 0x7DCD, //CJK UNIFIED IDEOGRAPH + 0xBE73: 0x7DCE, //CJK UNIFIED IDEOGRAPH + 0xBE74: 0x7DCF, //CJK UNIFIED IDEOGRAPH + 0xBE75: 0x7DD0, //CJK UNIFIED IDEOGRAPH + 0xBE76: 0x7DD1, //CJK UNIFIED IDEOGRAPH + 0xBE77: 0x7DD2, //CJK UNIFIED IDEOGRAPH + 0xBE78: 0x7DD3, //CJK UNIFIED IDEOGRAPH + 0xBE79: 0x7DD4, //CJK UNIFIED IDEOGRAPH + 0xBE7A: 0x7DD5, //CJK UNIFIED IDEOGRAPH + 0xBE7B: 0x7DD6, //CJK UNIFIED IDEOGRAPH + 0xBE7C: 0x7DD7, //CJK UNIFIED IDEOGRAPH + 0xBE7D: 0x7DD8, //CJK UNIFIED IDEOGRAPH + 0xBE7E: 0x7DD9, //CJK UNIFIED IDEOGRAPH + 0xBE80: 0x7DDA, //CJK UNIFIED IDEOGRAPH + 0xBE81: 0x7DDB, //CJK UNIFIED IDEOGRAPH + 0xBE82: 0x7DDC, //CJK UNIFIED IDEOGRAPH + 0xBE83: 0x7DDD, //CJK UNIFIED IDEOGRAPH + 0xBE84: 0x7DDE, //CJK UNIFIED IDEOGRAPH + 0xBE85: 0x7DDF, //CJK UNIFIED IDEOGRAPH + 0xBE86: 0x7DE0, //CJK UNIFIED IDEOGRAPH + 0xBE87: 0x7DE1, //CJK UNIFIED IDEOGRAPH + 0xBE88: 0x7DE2, //CJK UNIFIED IDEOGRAPH + 0xBE89: 0x7DE3, //CJK UNIFIED IDEOGRAPH + 0xBE8A: 0x7DE4, //CJK UNIFIED IDEOGRAPH + 0xBE8B: 0x7DE5, //CJK UNIFIED IDEOGRAPH + 0xBE8C: 0x7DE6, //CJK UNIFIED IDEOGRAPH + 0xBE8D: 0x7DE7, //CJK UNIFIED IDEOGRAPH + 0xBE8E: 0x7DE8, //CJK UNIFIED IDEOGRAPH + 0xBE8F: 0x7DE9, //CJK UNIFIED IDEOGRAPH + 0xBE90: 0x7DEA, //CJK UNIFIED IDEOGRAPH + 0xBE91: 0x7DEB, //CJK UNIFIED IDEOGRAPH + 0xBE92: 0x7DEC, //CJK UNIFIED IDEOGRAPH + 0xBE93: 0x7DED, //CJK UNIFIED IDEOGRAPH + 0xBE94: 0x7DEE, //CJK UNIFIED IDEOGRAPH + 0xBE95: 0x7DEF, //CJK UNIFIED IDEOGRAPH + 0xBE96: 0x7DF0, //CJK UNIFIED IDEOGRAPH + 0xBE97: 0x7DF1, //CJK UNIFIED IDEOGRAPH + 0xBE98: 0x7DF2, //CJK UNIFIED IDEOGRAPH + 0xBE99: 0x7DF3, //CJK UNIFIED IDEOGRAPH + 0xBE9A: 0x7DF4, //CJK UNIFIED IDEOGRAPH + 0xBE9B: 0x7DF5, //CJK UNIFIED IDEOGRAPH + 0xBE9C: 0x7DF6, //CJK UNIFIED IDEOGRAPH + 0xBE9D: 0x7DF7, //CJK UNIFIED IDEOGRAPH + 0xBE9E: 0x7DF8, //CJK UNIFIED IDEOGRAPH + 0xBE9F: 0x7DF9, //CJK UNIFIED IDEOGRAPH + 0xBEA0: 0x7DFA, //CJK UNIFIED IDEOGRAPH + 0xBEA1: 0x5C3D, //CJK UNIFIED IDEOGRAPH + 0xBEA2: 0x52B2, //CJK UNIFIED IDEOGRAPH + 0xBEA3: 0x8346, //CJK UNIFIED IDEOGRAPH + 0xBEA4: 0x5162, //CJK UNIFIED IDEOGRAPH + 0xBEA5: 0x830E, //CJK UNIFIED IDEOGRAPH + 0xBEA6: 0x775B, //CJK UNIFIED IDEOGRAPH + 0xBEA7: 0x6676, //CJK UNIFIED IDEOGRAPH + 0xBEA8: 0x9CB8, //CJK UNIFIED IDEOGRAPH + 0xBEA9: 0x4EAC, //CJK UNIFIED IDEOGRAPH + 0xBEAA: 0x60CA, //CJK UNIFIED IDEOGRAPH + 0xBEAB: 0x7CBE, //CJK UNIFIED IDEOGRAPH + 0xBEAC: 0x7CB3, //CJK UNIFIED IDEOGRAPH + 0xBEAD: 0x7ECF, //CJK UNIFIED IDEOGRAPH + 0xBEAE: 0x4E95, //CJK UNIFIED IDEOGRAPH + 0xBEAF: 0x8B66, //CJK UNIFIED IDEOGRAPH + 0xBEB0: 0x666F, //CJK UNIFIED IDEOGRAPH + 0xBEB1: 0x9888, //CJK UNIFIED IDEOGRAPH + 0xBEB2: 0x9759, //CJK UNIFIED IDEOGRAPH + 0xBEB3: 0x5883, //CJK UNIFIED IDEOGRAPH + 0xBEB4: 0x656C, //CJK UNIFIED IDEOGRAPH + 0xBEB5: 0x955C, //CJK UNIFIED IDEOGRAPH + 0xBEB6: 0x5F84, //CJK UNIFIED IDEOGRAPH + 0xBEB7: 0x75C9, //CJK UNIFIED IDEOGRAPH + 0xBEB8: 0x9756, //CJK UNIFIED IDEOGRAPH + 0xBEB9: 0x7ADF, //CJK UNIFIED IDEOGRAPH + 0xBEBA: 0x7ADE, //CJK UNIFIED IDEOGRAPH + 0xBEBB: 0x51C0, //CJK UNIFIED IDEOGRAPH + 0xBEBC: 0x70AF, //CJK UNIFIED IDEOGRAPH + 0xBEBD: 0x7A98, //CJK UNIFIED IDEOGRAPH + 0xBEBE: 0x63EA, //CJK UNIFIED IDEOGRAPH + 0xBEBF: 0x7A76, //CJK UNIFIED IDEOGRAPH + 0xBEC0: 0x7EA0, //CJK UNIFIED IDEOGRAPH + 0xBEC1: 0x7396, //CJK UNIFIED IDEOGRAPH + 0xBEC2: 0x97ED, //CJK UNIFIED IDEOGRAPH + 0xBEC3: 0x4E45, //CJK UNIFIED IDEOGRAPH + 0xBEC4: 0x7078, //CJK UNIFIED IDEOGRAPH + 0xBEC5: 0x4E5D, //CJK UNIFIED IDEOGRAPH + 0xBEC6: 0x9152, //CJK UNIFIED IDEOGRAPH + 0xBEC7: 0x53A9, //CJK UNIFIED IDEOGRAPH + 0xBEC8: 0x6551, //CJK UNIFIED IDEOGRAPH + 0xBEC9: 0x65E7, //CJK UNIFIED IDEOGRAPH + 0xBECA: 0x81FC, //CJK UNIFIED IDEOGRAPH + 0xBECB: 0x8205, //CJK UNIFIED IDEOGRAPH + 0xBECC: 0x548E, //CJK UNIFIED IDEOGRAPH + 0xBECD: 0x5C31, //CJK UNIFIED IDEOGRAPH + 0xBECE: 0x759A, //CJK UNIFIED IDEOGRAPH + 0xBECF: 0x97A0, //CJK UNIFIED IDEOGRAPH + 0xBED0: 0x62D8, //CJK UNIFIED IDEOGRAPH + 0xBED1: 0x72D9, //CJK UNIFIED IDEOGRAPH + 0xBED2: 0x75BD, //CJK UNIFIED IDEOGRAPH + 0xBED3: 0x5C45, //CJK UNIFIED IDEOGRAPH + 0xBED4: 0x9A79, //CJK UNIFIED IDEOGRAPH + 0xBED5: 0x83CA, //CJK UNIFIED IDEOGRAPH + 0xBED6: 0x5C40, //CJK UNIFIED IDEOGRAPH + 0xBED7: 0x5480, //CJK UNIFIED IDEOGRAPH + 0xBED8: 0x77E9, //CJK UNIFIED IDEOGRAPH + 0xBED9: 0x4E3E, //CJK UNIFIED IDEOGRAPH + 0xBEDA: 0x6CAE, //CJK UNIFIED IDEOGRAPH + 0xBEDB: 0x805A, //CJK UNIFIED IDEOGRAPH + 0xBEDC: 0x62D2, //CJK UNIFIED IDEOGRAPH + 0xBEDD: 0x636E, //CJK UNIFIED IDEOGRAPH + 0xBEDE: 0x5DE8, //CJK UNIFIED IDEOGRAPH + 0xBEDF: 0x5177, //CJK UNIFIED IDEOGRAPH + 0xBEE0: 0x8DDD, //CJK UNIFIED IDEOGRAPH + 0xBEE1: 0x8E1E, //CJK UNIFIED IDEOGRAPH + 0xBEE2: 0x952F, //CJK UNIFIED IDEOGRAPH + 0xBEE3: 0x4FF1, //CJK UNIFIED IDEOGRAPH + 0xBEE4: 0x53E5, //CJK UNIFIED IDEOGRAPH + 0xBEE5: 0x60E7, //CJK UNIFIED IDEOGRAPH + 0xBEE6: 0x70AC, //CJK UNIFIED IDEOGRAPH + 0xBEE7: 0x5267, //CJK UNIFIED IDEOGRAPH + 0xBEE8: 0x6350, //CJK UNIFIED IDEOGRAPH + 0xBEE9: 0x9E43, //CJK UNIFIED IDEOGRAPH + 0xBEEA: 0x5A1F, //CJK UNIFIED IDEOGRAPH + 0xBEEB: 0x5026, //CJK UNIFIED IDEOGRAPH + 0xBEEC: 0x7737, //CJK UNIFIED IDEOGRAPH + 0xBEED: 0x5377, //CJK UNIFIED IDEOGRAPH + 0xBEEE: 0x7EE2, //CJK UNIFIED IDEOGRAPH + 0xBEEF: 0x6485, //CJK UNIFIED IDEOGRAPH + 0xBEF0: 0x652B, //CJK UNIFIED IDEOGRAPH + 0xBEF1: 0x6289, //CJK UNIFIED IDEOGRAPH + 0xBEF2: 0x6398, //CJK UNIFIED IDEOGRAPH + 0xBEF3: 0x5014, //CJK UNIFIED IDEOGRAPH + 0xBEF4: 0x7235, //CJK UNIFIED IDEOGRAPH + 0xBEF5: 0x89C9, //CJK UNIFIED IDEOGRAPH + 0xBEF6: 0x51B3, //CJK UNIFIED IDEOGRAPH + 0xBEF7: 0x8BC0, //CJK UNIFIED IDEOGRAPH + 0xBEF8: 0x7EDD, //CJK UNIFIED IDEOGRAPH + 0xBEF9: 0x5747, //CJK UNIFIED IDEOGRAPH + 0xBEFA: 0x83CC, //CJK UNIFIED IDEOGRAPH + 0xBEFB: 0x94A7, //CJK UNIFIED IDEOGRAPH + 0xBEFC: 0x519B, //CJK UNIFIED IDEOGRAPH + 0xBEFD: 0x541B, //CJK UNIFIED IDEOGRAPH + 0xBEFE: 0x5CFB, //CJK UNIFIED IDEOGRAPH + 0xBF40: 0x7DFB, //CJK UNIFIED IDEOGRAPH + 0xBF41: 0x7DFC, //CJK UNIFIED IDEOGRAPH + 0xBF42: 0x7DFD, //CJK UNIFIED IDEOGRAPH + 0xBF43: 0x7DFE, //CJK UNIFIED IDEOGRAPH + 0xBF44: 0x7DFF, //CJK UNIFIED IDEOGRAPH + 0xBF45: 0x7E00, //CJK UNIFIED IDEOGRAPH + 0xBF46: 0x7E01, //CJK UNIFIED IDEOGRAPH + 0xBF47: 0x7E02, //CJK UNIFIED IDEOGRAPH + 0xBF48: 0x7E03, //CJK UNIFIED IDEOGRAPH + 0xBF49: 0x7E04, //CJK UNIFIED IDEOGRAPH + 0xBF4A: 0x7E05, //CJK UNIFIED IDEOGRAPH + 0xBF4B: 0x7E06, //CJK UNIFIED IDEOGRAPH + 0xBF4C: 0x7E07, //CJK UNIFIED IDEOGRAPH + 0xBF4D: 0x7E08, //CJK UNIFIED IDEOGRAPH + 0xBF4E: 0x7E09, //CJK UNIFIED IDEOGRAPH + 0xBF4F: 0x7E0A, //CJK UNIFIED IDEOGRAPH + 0xBF50: 0x7E0B, //CJK UNIFIED IDEOGRAPH + 0xBF51: 0x7E0C, //CJK UNIFIED IDEOGRAPH + 0xBF52: 0x7E0D, //CJK UNIFIED IDEOGRAPH + 0xBF53: 0x7E0E, //CJK UNIFIED IDEOGRAPH + 0xBF54: 0x7E0F, //CJK UNIFIED IDEOGRAPH + 0xBF55: 0x7E10, //CJK UNIFIED IDEOGRAPH + 0xBF56: 0x7E11, //CJK UNIFIED IDEOGRAPH + 0xBF57: 0x7E12, //CJK UNIFIED IDEOGRAPH + 0xBF58: 0x7E13, //CJK UNIFIED IDEOGRAPH + 0xBF59: 0x7E14, //CJK UNIFIED IDEOGRAPH + 0xBF5A: 0x7E15, //CJK UNIFIED IDEOGRAPH + 0xBF5B: 0x7E16, //CJK UNIFIED IDEOGRAPH + 0xBF5C: 0x7E17, //CJK UNIFIED IDEOGRAPH + 0xBF5D: 0x7E18, //CJK UNIFIED IDEOGRAPH + 0xBF5E: 0x7E19, //CJK UNIFIED IDEOGRAPH + 0xBF5F: 0x7E1A, //CJK UNIFIED IDEOGRAPH + 0xBF60: 0x7E1B, //CJK UNIFIED IDEOGRAPH + 0xBF61: 0x7E1C, //CJK UNIFIED IDEOGRAPH + 0xBF62: 0x7E1D, //CJK UNIFIED IDEOGRAPH + 0xBF63: 0x7E1E, //CJK UNIFIED IDEOGRAPH + 0xBF64: 0x7E1F, //CJK UNIFIED IDEOGRAPH + 0xBF65: 0x7E20, //CJK UNIFIED IDEOGRAPH + 0xBF66: 0x7E21, //CJK UNIFIED IDEOGRAPH + 0xBF67: 0x7E22, //CJK UNIFIED IDEOGRAPH + 0xBF68: 0x7E23, //CJK UNIFIED IDEOGRAPH + 0xBF69: 0x7E24, //CJK UNIFIED IDEOGRAPH + 0xBF6A: 0x7E25, //CJK UNIFIED IDEOGRAPH + 0xBF6B: 0x7E26, //CJK UNIFIED IDEOGRAPH + 0xBF6C: 0x7E27, //CJK UNIFIED IDEOGRAPH + 0xBF6D: 0x7E28, //CJK UNIFIED IDEOGRAPH + 0xBF6E: 0x7E29, //CJK UNIFIED IDEOGRAPH + 0xBF6F: 0x7E2A, //CJK UNIFIED IDEOGRAPH + 0xBF70: 0x7E2B, //CJK UNIFIED IDEOGRAPH + 0xBF71: 0x7E2C, //CJK UNIFIED IDEOGRAPH + 0xBF72: 0x7E2D, //CJK UNIFIED IDEOGRAPH + 0xBF73: 0x7E2E, //CJK UNIFIED IDEOGRAPH + 0xBF74: 0x7E2F, //CJK UNIFIED IDEOGRAPH + 0xBF75: 0x7E30, //CJK UNIFIED IDEOGRAPH + 0xBF76: 0x7E31, //CJK UNIFIED IDEOGRAPH + 0xBF77: 0x7E32, //CJK UNIFIED IDEOGRAPH + 0xBF78: 0x7E33, //CJK UNIFIED IDEOGRAPH + 0xBF79: 0x7E34, //CJK UNIFIED IDEOGRAPH + 0xBF7A: 0x7E35, //CJK UNIFIED IDEOGRAPH + 0xBF7B: 0x7E36, //CJK UNIFIED IDEOGRAPH + 0xBF7C: 0x7E37, //CJK UNIFIED IDEOGRAPH + 0xBF7D: 0x7E38, //CJK UNIFIED IDEOGRAPH + 0xBF7E: 0x7E39, //CJK UNIFIED IDEOGRAPH + 0xBF80: 0x7E3A, //CJK UNIFIED IDEOGRAPH + 0xBF81: 0x7E3C, //CJK UNIFIED IDEOGRAPH + 0xBF82: 0x7E3D, //CJK UNIFIED IDEOGRAPH + 0xBF83: 0x7E3E, //CJK UNIFIED IDEOGRAPH + 0xBF84: 0x7E3F, //CJK UNIFIED IDEOGRAPH + 0xBF85: 0x7E40, //CJK UNIFIED IDEOGRAPH + 0xBF86: 0x7E42, //CJK UNIFIED IDEOGRAPH + 0xBF87: 0x7E43, //CJK UNIFIED IDEOGRAPH + 0xBF88: 0x7E44, //CJK UNIFIED IDEOGRAPH + 0xBF89: 0x7E45, //CJK UNIFIED IDEOGRAPH + 0xBF8A: 0x7E46, //CJK UNIFIED IDEOGRAPH + 0xBF8B: 0x7E48, //CJK UNIFIED IDEOGRAPH + 0xBF8C: 0x7E49, //CJK UNIFIED IDEOGRAPH + 0xBF8D: 0x7E4A, //CJK UNIFIED IDEOGRAPH + 0xBF8E: 0x7E4B, //CJK UNIFIED IDEOGRAPH + 0xBF8F: 0x7E4C, //CJK UNIFIED IDEOGRAPH + 0xBF90: 0x7E4D, //CJK UNIFIED IDEOGRAPH + 0xBF91: 0x7E4E, //CJK UNIFIED IDEOGRAPH + 0xBF92: 0x7E4F, //CJK UNIFIED IDEOGRAPH + 0xBF93: 0x7E50, //CJK UNIFIED IDEOGRAPH + 0xBF94: 0x7E51, //CJK UNIFIED IDEOGRAPH + 0xBF95: 0x7E52, //CJK UNIFIED IDEOGRAPH + 0xBF96: 0x7E53, //CJK UNIFIED IDEOGRAPH + 0xBF97: 0x7E54, //CJK UNIFIED IDEOGRAPH + 0xBF98: 0x7E55, //CJK UNIFIED IDEOGRAPH + 0xBF99: 0x7E56, //CJK UNIFIED IDEOGRAPH + 0xBF9A: 0x7E57, //CJK UNIFIED IDEOGRAPH + 0xBF9B: 0x7E58, //CJK UNIFIED IDEOGRAPH + 0xBF9C: 0x7E59, //CJK UNIFIED IDEOGRAPH + 0xBF9D: 0x7E5A, //CJK UNIFIED IDEOGRAPH + 0xBF9E: 0x7E5B, //CJK UNIFIED IDEOGRAPH + 0xBF9F: 0x7E5C, //CJK UNIFIED IDEOGRAPH + 0xBFA0: 0x7E5D, //CJK UNIFIED IDEOGRAPH + 0xBFA1: 0x4FCA, //CJK UNIFIED IDEOGRAPH + 0xBFA2: 0x7AE3, //CJK UNIFIED IDEOGRAPH + 0xBFA3: 0x6D5A, //CJK UNIFIED IDEOGRAPH + 0xBFA4: 0x90E1, //CJK UNIFIED IDEOGRAPH + 0xBFA5: 0x9A8F, //CJK UNIFIED IDEOGRAPH + 0xBFA6: 0x5580, //CJK UNIFIED IDEOGRAPH + 0xBFA7: 0x5496, //CJK UNIFIED IDEOGRAPH + 0xBFA8: 0x5361, //CJK UNIFIED IDEOGRAPH + 0xBFA9: 0x54AF, //CJK UNIFIED IDEOGRAPH + 0xBFAA: 0x5F00, //CJK UNIFIED IDEOGRAPH + 0xBFAB: 0x63E9, //CJK UNIFIED IDEOGRAPH + 0xBFAC: 0x6977, //CJK UNIFIED IDEOGRAPH + 0xBFAD: 0x51EF, //CJK UNIFIED IDEOGRAPH + 0xBFAE: 0x6168, //CJK UNIFIED IDEOGRAPH + 0xBFAF: 0x520A, //CJK UNIFIED IDEOGRAPH + 0xBFB0: 0x582A, //CJK UNIFIED IDEOGRAPH + 0xBFB1: 0x52D8, //CJK UNIFIED IDEOGRAPH + 0xBFB2: 0x574E, //CJK UNIFIED IDEOGRAPH + 0xBFB3: 0x780D, //CJK UNIFIED IDEOGRAPH + 0xBFB4: 0x770B, //CJK UNIFIED IDEOGRAPH + 0xBFB5: 0x5EB7, //CJK UNIFIED IDEOGRAPH + 0xBFB6: 0x6177, //CJK UNIFIED IDEOGRAPH + 0xBFB7: 0x7CE0, //CJK UNIFIED IDEOGRAPH + 0xBFB8: 0x625B, //CJK UNIFIED IDEOGRAPH + 0xBFB9: 0x6297, //CJK UNIFIED IDEOGRAPH + 0xBFBA: 0x4EA2, //CJK UNIFIED IDEOGRAPH + 0xBFBB: 0x7095, //CJK UNIFIED IDEOGRAPH + 0xBFBC: 0x8003, //CJK UNIFIED IDEOGRAPH + 0xBFBD: 0x62F7, //CJK UNIFIED IDEOGRAPH + 0xBFBE: 0x70E4, //CJK UNIFIED IDEOGRAPH + 0xBFBF: 0x9760, //CJK UNIFIED IDEOGRAPH + 0xBFC0: 0x5777, //CJK UNIFIED IDEOGRAPH + 0xBFC1: 0x82DB, //CJK UNIFIED IDEOGRAPH + 0xBFC2: 0x67EF, //CJK UNIFIED IDEOGRAPH + 0xBFC3: 0x68F5, //CJK UNIFIED IDEOGRAPH + 0xBFC4: 0x78D5, //CJK UNIFIED IDEOGRAPH + 0xBFC5: 0x9897, //CJK UNIFIED IDEOGRAPH + 0xBFC6: 0x79D1, //CJK UNIFIED IDEOGRAPH + 0xBFC7: 0x58F3, //CJK UNIFIED IDEOGRAPH + 0xBFC8: 0x54B3, //CJK UNIFIED IDEOGRAPH + 0xBFC9: 0x53EF, //CJK UNIFIED IDEOGRAPH + 0xBFCA: 0x6E34, //CJK UNIFIED IDEOGRAPH + 0xBFCB: 0x514B, //CJK UNIFIED IDEOGRAPH + 0xBFCC: 0x523B, //CJK UNIFIED IDEOGRAPH + 0xBFCD: 0x5BA2, //CJK UNIFIED IDEOGRAPH + 0xBFCE: 0x8BFE, //CJK UNIFIED IDEOGRAPH + 0xBFCF: 0x80AF, //CJK UNIFIED IDEOGRAPH + 0xBFD0: 0x5543, //CJK UNIFIED IDEOGRAPH + 0xBFD1: 0x57A6, //CJK UNIFIED IDEOGRAPH + 0xBFD2: 0x6073, //CJK UNIFIED IDEOGRAPH + 0xBFD3: 0x5751, //CJK UNIFIED IDEOGRAPH + 0xBFD4: 0x542D, //CJK UNIFIED IDEOGRAPH + 0xBFD5: 0x7A7A, //CJK UNIFIED IDEOGRAPH + 0xBFD6: 0x6050, //CJK UNIFIED IDEOGRAPH + 0xBFD7: 0x5B54, //CJK UNIFIED IDEOGRAPH + 0xBFD8: 0x63A7, //CJK UNIFIED IDEOGRAPH + 0xBFD9: 0x62A0, //CJK UNIFIED IDEOGRAPH + 0xBFDA: 0x53E3, //CJK UNIFIED IDEOGRAPH + 0xBFDB: 0x6263, //CJK UNIFIED IDEOGRAPH + 0xBFDC: 0x5BC7, //CJK UNIFIED IDEOGRAPH + 0xBFDD: 0x67AF, //CJK UNIFIED IDEOGRAPH + 0xBFDE: 0x54ED, //CJK UNIFIED IDEOGRAPH + 0xBFDF: 0x7A9F, //CJK UNIFIED IDEOGRAPH + 0xBFE0: 0x82E6, //CJK UNIFIED IDEOGRAPH + 0xBFE1: 0x9177, //CJK UNIFIED IDEOGRAPH + 0xBFE2: 0x5E93, //CJK UNIFIED IDEOGRAPH + 0xBFE3: 0x88E4, //CJK UNIFIED IDEOGRAPH + 0xBFE4: 0x5938, //CJK UNIFIED IDEOGRAPH + 0xBFE5: 0x57AE, //CJK UNIFIED IDEOGRAPH + 0xBFE6: 0x630E, //CJK UNIFIED IDEOGRAPH + 0xBFE7: 0x8DE8, //CJK UNIFIED IDEOGRAPH + 0xBFE8: 0x80EF, //CJK UNIFIED IDEOGRAPH + 0xBFE9: 0x5757, //CJK UNIFIED IDEOGRAPH + 0xBFEA: 0x7B77, //CJK UNIFIED IDEOGRAPH + 0xBFEB: 0x4FA9, //CJK UNIFIED IDEOGRAPH + 0xBFEC: 0x5FEB, //CJK UNIFIED IDEOGRAPH + 0xBFED: 0x5BBD, //CJK UNIFIED IDEOGRAPH + 0xBFEE: 0x6B3E, //CJK UNIFIED IDEOGRAPH + 0xBFEF: 0x5321, //CJK UNIFIED IDEOGRAPH + 0xBFF0: 0x7B50, //CJK UNIFIED IDEOGRAPH + 0xBFF1: 0x72C2, //CJK UNIFIED IDEOGRAPH + 0xBFF2: 0x6846, //CJK UNIFIED IDEOGRAPH + 0xBFF3: 0x77FF, //CJK UNIFIED IDEOGRAPH + 0xBFF4: 0x7736, //CJK UNIFIED IDEOGRAPH + 0xBFF5: 0x65F7, //CJK UNIFIED IDEOGRAPH + 0xBFF6: 0x51B5, //CJK UNIFIED IDEOGRAPH + 0xBFF7: 0x4E8F, //CJK UNIFIED IDEOGRAPH + 0xBFF8: 0x76D4, //CJK UNIFIED IDEOGRAPH + 0xBFF9: 0x5CBF, //CJK UNIFIED IDEOGRAPH + 0xBFFA: 0x7AA5, //CJK UNIFIED IDEOGRAPH + 0xBFFB: 0x8475, //CJK UNIFIED IDEOGRAPH + 0xBFFC: 0x594E, //CJK UNIFIED IDEOGRAPH + 0xBFFD: 0x9B41, //CJK UNIFIED IDEOGRAPH + 0xBFFE: 0x5080, //CJK UNIFIED IDEOGRAPH + 0xC040: 0x7E5E, //CJK UNIFIED IDEOGRAPH + 0xC041: 0x7E5F, //CJK UNIFIED IDEOGRAPH + 0xC042: 0x7E60, //CJK UNIFIED IDEOGRAPH + 0xC043: 0x7E61, //CJK UNIFIED IDEOGRAPH + 0xC044: 0x7E62, //CJK UNIFIED IDEOGRAPH + 0xC045: 0x7E63, //CJK UNIFIED IDEOGRAPH + 0xC046: 0x7E64, //CJK UNIFIED IDEOGRAPH + 0xC047: 0x7E65, //CJK UNIFIED IDEOGRAPH + 0xC048: 0x7E66, //CJK UNIFIED IDEOGRAPH + 0xC049: 0x7E67, //CJK UNIFIED IDEOGRAPH + 0xC04A: 0x7E68, //CJK UNIFIED IDEOGRAPH + 0xC04B: 0x7E69, //CJK UNIFIED IDEOGRAPH + 0xC04C: 0x7E6A, //CJK UNIFIED IDEOGRAPH + 0xC04D: 0x7E6B, //CJK UNIFIED IDEOGRAPH + 0xC04E: 0x7E6C, //CJK UNIFIED IDEOGRAPH + 0xC04F: 0x7E6D, //CJK UNIFIED IDEOGRAPH + 0xC050: 0x7E6E, //CJK UNIFIED IDEOGRAPH + 0xC051: 0x7E6F, //CJK UNIFIED IDEOGRAPH + 0xC052: 0x7E70, //CJK UNIFIED IDEOGRAPH + 0xC053: 0x7E71, //CJK UNIFIED IDEOGRAPH + 0xC054: 0x7E72, //CJK UNIFIED IDEOGRAPH + 0xC055: 0x7E73, //CJK UNIFIED IDEOGRAPH + 0xC056: 0x7E74, //CJK UNIFIED IDEOGRAPH + 0xC057: 0x7E75, //CJK UNIFIED IDEOGRAPH + 0xC058: 0x7E76, //CJK UNIFIED IDEOGRAPH + 0xC059: 0x7E77, //CJK UNIFIED IDEOGRAPH + 0xC05A: 0x7E78, //CJK UNIFIED IDEOGRAPH + 0xC05B: 0x7E79, //CJK UNIFIED IDEOGRAPH + 0xC05C: 0x7E7A, //CJK UNIFIED IDEOGRAPH + 0xC05D: 0x7E7B, //CJK UNIFIED IDEOGRAPH + 0xC05E: 0x7E7C, //CJK UNIFIED IDEOGRAPH + 0xC05F: 0x7E7D, //CJK UNIFIED IDEOGRAPH + 0xC060: 0x7E7E, //CJK UNIFIED IDEOGRAPH + 0xC061: 0x7E7F, //CJK UNIFIED IDEOGRAPH + 0xC062: 0x7E80, //CJK UNIFIED IDEOGRAPH + 0xC063: 0x7E81, //CJK UNIFIED IDEOGRAPH + 0xC064: 0x7E83, //CJK UNIFIED IDEOGRAPH + 0xC065: 0x7E84, //CJK UNIFIED IDEOGRAPH + 0xC066: 0x7E85, //CJK UNIFIED IDEOGRAPH + 0xC067: 0x7E86, //CJK UNIFIED IDEOGRAPH + 0xC068: 0x7E87, //CJK UNIFIED IDEOGRAPH + 0xC069: 0x7E88, //CJK UNIFIED IDEOGRAPH + 0xC06A: 0x7E89, //CJK UNIFIED IDEOGRAPH + 0xC06B: 0x7E8A, //CJK UNIFIED IDEOGRAPH + 0xC06C: 0x7E8B, //CJK UNIFIED IDEOGRAPH + 0xC06D: 0x7E8C, //CJK UNIFIED IDEOGRAPH + 0xC06E: 0x7E8D, //CJK UNIFIED IDEOGRAPH + 0xC06F: 0x7E8E, //CJK UNIFIED IDEOGRAPH + 0xC070: 0x7E8F, //CJK UNIFIED IDEOGRAPH + 0xC071: 0x7E90, //CJK UNIFIED IDEOGRAPH + 0xC072: 0x7E91, //CJK UNIFIED IDEOGRAPH + 0xC073: 0x7E92, //CJK UNIFIED IDEOGRAPH + 0xC074: 0x7E93, //CJK UNIFIED IDEOGRAPH + 0xC075: 0x7E94, //CJK UNIFIED IDEOGRAPH + 0xC076: 0x7E95, //CJK UNIFIED IDEOGRAPH + 0xC077: 0x7E96, //CJK UNIFIED IDEOGRAPH + 0xC078: 0x7E97, //CJK UNIFIED IDEOGRAPH + 0xC079: 0x7E98, //CJK UNIFIED IDEOGRAPH + 0xC07A: 0x7E99, //CJK UNIFIED IDEOGRAPH + 0xC07B: 0x7E9A, //CJK UNIFIED IDEOGRAPH + 0xC07C: 0x7E9C, //CJK UNIFIED IDEOGRAPH + 0xC07D: 0x7E9D, //CJK UNIFIED IDEOGRAPH + 0xC07E: 0x7E9E, //CJK UNIFIED IDEOGRAPH + 0xC080: 0x7EAE, //CJK UNIFIED IDEOGRAPH + 0xC081: 0x7EB4, //CJK UNIFIED IDEOGRAPH + 0xC082: 0x7EBB, //CJK UNIFIED IDEOGRAPH + 0xC083: 0x7EBC, //CJK UNIFIED IDEOGRAPH + 0xC084: 0x7ED6, //CJK UNIFIED IDEOGRAPH + 0xC085: 0x7EE4, //CJK UNIFIED IDEOGRAPH + 0xC086: 0x7EEC, //CJK UNIFIED IDEOGRAPH + 0xC087: 0x7EF9, //CJK UNIFIED IDEOGRAPH + 0xC088: 0x7F0A, //CJK UNIFIED IDEOGRAPH + 0xC089: 0x7F10, //CJK UNIFIED IDEOGRAPH + 0xC08A: 0x7F1E, //CJK UNIFIED IDEOGRAPH + 0xC08B: 0x7F37, //CJK UNIFIED IDEOGRAPH + 0xC08C: 0x7F39, //CJK UNIFIED IDEOGRAPH + 0xC08D: 0x7F3B, //CJK UNIFIED IDEOGRAPH + 0xC08E: 0x7F3C, //CJK UNIFIED IDEOGRAPH + 0xC08F: 0x7F3D, //CJK UNIFIED IDEOGRAPH + 0xC090: 0x7F3E, //CJK UNIFIED IDEOGRAPH + 0xC091: 0x7F3F, //CJK UNIFIED IDEOGRAPH + 0xC092: 0x7F40, //CJK UNIFIED IDEOGRAPH + 0xC093: 0x7F41, //CJK UNIFIED IDEOGRAPH + 0xC094: 0x7F43, //CJK UNIFIED IDEOGRAPH + 0xC095: 0x7F46, //CJK UNIFIED IDEOGRAPH + 0xC096: 0x7F47, //CJK UNIFIED IDEOGRAPH + 0xC097: 0x7F48, //CJK UNIFIED IDEOGRAPH + 0xC098: 0x7F49, //CJK UNIFIED IDEOGRAPH + 0xC099: 0x7F4A, //CJK UNIFIED IDEOGRAPH + 0xC09A: 0x7F4B, //CJK UNIFIED IDEOGRAPH + 0xC09B: 0x7F4C, //CJK UNIFIED IDEOGRAPH + 0xC09C: 0x7F4D, //CJK UNIFIED IDEOGRAPH + 0xC09D: 0x7F4E, //CJK UNIFIED IDEOGRAPH + 0xC09E: 0x7F4F, //CJK UNIFIED IDEOGRAPH + 0xC09F: 0x7F52, //CJK UNIFIED IDEOGRAPH + 0xC0A0: 0x7F53, //CJK UNIFIED IDEOGRAPH + 0xC0A1: 0x9988, //CJK UNIFIED IDEOGRAPH + 0xC0A2: 0x6127, //CJK UNIFIED IDEOGRAPH + 0xC0A3: 0x6E83, //CJK UNIFIED IDEOGRAPH + 0xC0A4: 0x5764, //CJK UNIFIED IDEOGRAPH + 0xC0A5: 0x6606, //CJK UNIFIED IDEOGRAPH + 0xC0A6: 0x6346, //CJK UNIFIED IDEOGRAPH + 0xC0A7: 0x56F0, //CJK UNIFIED IDEOGRAPH + 0xC0A8: 0x62EC, //CJK UNIFIED IDEOGRAPH + 0xC0A9: 0x6269, //CJK UNIFIED IDEOGRAPH + 0xC0AA: 0x5ED3, //CJK UNIFIED IDEOGRAPH + 0xC0AB: 0x9614, //CJK UNIFIED IDEOGRAPH + 0xC0AC: 0x5783, //CJK UNIFIED IDEOGRAPH + 0xC0AD: 0x62C9, //CJK UNIFIED IDEOGRAPH + 0xC0AE: 0x5587, //CJK UNIFIED IDEOGRAPH + 0xC0AF: 0x8721, //CJK UNIFIED IDEOGRAPH + 0xC0B0: 0x814A, //CJK UNIFIED IDEOGRAPH + 0xC0B1: 0x8FA3, //CJK UNIFIED IDEOGRAPH + 0xC0B2: 0x5566, //CJK UNIFIED IDEOGRAPH + 0xC0B3: 0x83B1, //CJK UNIFIED IDEOGRAPH + 0xC0B4: 0x6765, //CJK UNIFIED IDEOGRAPH + 0xC0B5: 0x8D56, //CJK UNIFIED IDEOGRAPH + 0xC0B6: 0x84DD, //CJK UNIFIED IDEOGRAPH + 0xC0B7: 0x5A6A, //CJK UNIFIED IDEOGRAPH + 0xC0B8: 0x680F, //CJK UNIFIED IDEOGRAPH + 0xC0B9: 0x62E6, //CJK UNIFIED IDEOGRAPH + 0xC0BA: 0x7BEE, //CJK UNIFIED IDEOGRAPH + 0xC0BB: 0x9611, //CJK UNIFIED IDEOGRAPH + 0xC0BC: 0x5170, //CJK UNIFIED IDEOGRAPH + 0xC0BD: 0x6F9C, //CJK UNIFIED IDEOGRAPH + 0xC0BE: 0x8C30, //CJK UNIFIED IDEOGRAPH + 0xC0BF: 0x63FD, //CJK UNIFIED IDEOGRAPH + 0xC0C0: 0x89C8, //CJK UNIFIED IDEOGRAPH + 0xC0C1: 0x61D2, //CJK UNIFIED IDEOGRAPH + 0xC0C2: 0x7F06, //CJK UNIFIED IDEOGRAPH + 0xC0C3: 0x70C2, //CJK UNIFIED IDEOGRAPH + 0xC0C4: 0x6EE5, //CJK UNIFIED IDEOGRAPH + 0xC0C5: 0x7405, //CJK UNIFIED IDEOGRAPH + 0xC0C6: 0x6994, //CJK UNIFIED IDEOGRAPH + 0xC0C7: 0x72FC, //CJK UNIFIED IDEOGRAPH + 0xC0C8: 0x5ECA, //CJK UNIFIED IDEOGRAPH + 0xC0C9: 0x90CE, //CJK UNIFIED IDEOGRAPH + 0xC0CA: 0x6717, //CJK UNIFIED IDEOGRAPH + 0xC0CB: 0x6D6A, //CJK UNIFIED IDEOGRAPH + 0xC0CC: 0x635E, //CJK UNIFIED IDEOGRAPH + 0xC0CD: 0x52B3, //CJK UNIFIED IDEOGRAPH + 0xC0CE: 0x7262, //CJK UNIFIED IDEOGRAPH + 0xC0CF: 0x8001, //CJK UNIFIED IDEOGRAPH + 0xC0D0: 0x4F6C, //CJK UNIFIED IDEOGRAPH + 0xC0D1: 0x59E5, //CJK UNIFIED IDEOGRAPH + 0xC0D2: 0x916A, //CJK UNIFIED IDEOGRAPH + 0xC0D3: 0x70D9, //CJK UNIFIED IDEOGRAPH + 0xC0D4: 0x6D9D, //CJK UNIFIED IDEOGRAPH + 0xC0D5: 0x52D2, //CJK UNIFIED IDEOGRAPH + 0xC0D6: 0x4E50, //CJK UNIFIED IDEOGRAPH + 0xC0D7: 0x96F7, //CJK UNIFIED IDEOGRAPH + 0xC0D8: 0x956D, //CJK UNIFIED IDEOGRAPH + 0xC0D9: 0x857E, //CJK UNIFIED IDEOGRAPH + 0xC0DA: 0x78CA, //CJK UNIFIED IDEOGRAPH + 0xC0DB: 0x7D2F, //CJK UNIFIED IDEOGRAPH + 0xC0DC: 0x5121, //CJK UNIFIED IDEOGRAPH + 0xC0DD: 0x5792, //CJK UNIFIED IDEOGRAPH + 0xC0DE: 0x64C2, //CJK UNIFIED IDEOGRAPH + 0xC0DF: 0x808B, //CJK UNIFIED IDEOGRAPH + 0xC0E0: 0x7C7B, //CJK UNIFIED IDEOGRAPH + 0xC0E1: 0x6CEA, //CJK UNIFIED IDEOGRAPH + 0xC0E2: 0x68F1, //CJK UNIFIED IDEOGRAPH + 0xC0E3: 0x695E, //CJK UNIFIED IDEOGRAPH + 0xC0E4: 0x51B7, //CJK UNIFIED IDEOGRAPH + 0xC0E5: 0x5398, //CJK UNIFIED IDEOGRAPH + 0xC0E6: 0x68A8, //CJK UNIFIED IDEOGRAPH + 0xC0E7: 0x7281, //CJK UNIFIED IDEOGRAPH + 0xC0E8: 0x9ECE, //CJK UNIFIED IDEOGRAPH + 0xC0E9: 0x7BF1, //CJK UNIFIED IDEOGRAPH + 0xC0EA: 0x72F8, //CJK UNIFIED IDEOGRAPH + 0xC0EB: 0x79BB, //CJK UNIFIED IDEOGRAPH + 0xC0EC: 0x6F13, //CJK UNIFIED IDEOGRAPH + 0xC0ED: 0x7406, //CJK UNIFIED IDEOGRAPH + 0xC0EE: 0x674E, //CJK UNIFIED IDEOGRAPH + 0xC0EF: 0x91CC, //CJK UNIFIED IDEOGRAPH + 0xC0F0: 0x9CA4, //CJK UNIFIED IDEOGRAPH + 0xC0F1: 0x793C, //CJK UNIFIED IDEOGRAPH + 0xC0F2: 0x8389, //CJK UNIFIED IDEOGRAPH + 0xC0F3: 0x8354, //CJK UNIFIED IDEOGRAPH + 0xC0F4: 0x540F, //CJK UNIFIED IDEOGRAPH + 0xC0F5: 0x6817, //CJK UNIFIED IDEOGRAPH + 0xC0F6: 0x4E3D, //CJK UNIFIED IDEOGRAPH + 0xC0F7: 0x5389, //CJK UNIFIED IDEOGRAPH + 0xC0F8: 0x52B1, //CJK UNIFIED IDEOGRAPH + 0xC0F9: 0x783E, //CJK UNIFIED IDEOGRAPH + 0xC0FA: 0x5386, //CJK UNIFIED IDEOGRAPH + 0xC0FB: 0x5229, //CJK UNIFIED IDEOGRAPH + 0xC0FC: 0x5088, //CJK UNIFIED IDEOGRAPH + 0xC0FD: 0x4F8B, //CJK UNIFIED IDEOGRAPH + 0xC0FE: 0x4FD0, //CJK UNIFIED IDEOGRAPH + 0xC140: 0x7F56, //CJK UNIFIED IDEOGRAPH + 0xC141: 0x7F59, //CJK UNIFIED IDEOGRAPH + 0xC142: 0x7F5B, //CJK UNIFIED IDEOGRAPH + 0xC143: 0x7F5C, //CJK UNIFIED IDEOGRAPH + 0xC144: 0x7F5D, //CJK UNIFIED IDEOGRAPH + 0xC145: 0x7F5E, //CJK UNIFIED IDEOGRAPH + 0xC146: 0x7F60, //CJK UNIFIED IDEOGRAPH + 0xC147: 0x7F63, //CJK UNIFIED IDEOGRAPH + 0xC148: 0x7F64, //CJK UNIFIED IDEOGRAPH + 0xC149: 0x7F65, //CJK UNIFIED IDEOGRAPH + 0xC14A: 0x7F66, //CJK UNIFIED IDEOGRAPH + 0xC14B: 0x7F67, //CJK UNIFIED IDEOGRAPH + 0xC14C: 0x7F6B, //CJK UNIFIED IDEOGRAPH + 0xC14D: 0x7F6C, //CJK UNIFIED IDEOGRAPH + 0xC14E: 0x7F6D, //CJK UNIFIED IDEOGRAPH + 0xC14F: 0x7F6F, //CJK UNIFIED IDEOGRAPH + 0xC150: 0x7F70, //CJK UNIFIED IDEOGRAPH + 0xC151: 0x7F73, //CJK UNIFIED IDEOGRAPH + 0xC152: 0x7F75, //CJK UNIFIED IDEOGRAPH + 0xC153: 0x7F76, //CJK UNIFIED IDEOGRAPH + 0xC154: 0x7F77, //CJK UNIFIED IDEOGRAPH + 0xC155: 0x7F78, //CJK UNIFIED IDEOGRAPH + 0xC156: 0x7F7A, //CJK UNIFIED IDEOGRAPH + 0xC157: 0x7F7B, //CJK UNIFIED IDEOGRAPH + 0xC158: 0x7F7C, //CJK UNIFIED IDEOGRAPH + 0xC159: 0x7F7D, //CJK UNIFIED IDEOGRAPH + 0xC15A: 0x7F7F, //CJK UNIFIED IDEOGRAPH + 0xC15B: 0x7F80, //CJK UNIFIED IDEOGRAPH + 0xC15C: 0x7F82, //CJK UNIFIED IDEOGRAPH + 0xC15D: 0x7F83, //CJK UNIFIED IDEOGRAPH + 0xC15E: 0x7F84, //CJK UNIFIED IDEOGRAPH + 0xC15F: 0x7F85, //CJK UNIFIED IDEOGRAPH + 0xC160: 0x7F86, //CJK UNIFIED IDEOGRAPH + 0xC161: 0x7F87, //CJK UNIFIED IDEOGRAPH + 0xC162: 0x7F88, //CJK UNIFIED IDEOGRAPH + 0xC163: 0x7F89, //CJK UNIFIED IDEOGRAPH + 0xC164: 0x7F8B, //CJK UNIFIED IDEOGRAPH + 0xC165: 0x7F8D, //CJK UNIFIED IDEOGRAPH + 0xC166: 0x7F8F, //CJK UNIFIED IDEOGRAPH + 0xC167: 0x7F90, //CJK UNIFIED IDEOGRAPH + 0xC168: 0x7F91, //CJK UNIFIED IDEOGRAPH + 0xC169: 0x7F92, //CJK UNIFIED IDEOGRAPH + 0xC16A: 0x7F93, //CJK UNIFIED IDEOGRAPH + 0xC16B: 0x7F95, //CJK UNIFIED IDEOGRAPH + 0xC16C: 0x7F96, //CJK UNIFIED IDEOGRAPH + 0xC16D: 0x7F97, //CJK UNIFIED IDEOGRAPH + 0xC16E: 0x7F98, //CJK UNIFIED IDEOGRAPH + 0xC16F: 0x7F99, //CJK UNIFIED IDEOGRAPH + 0xC170: 0x7F9B, //CJK UNIFIED IDEOGRAPH + 0xC171: 0x7F9C, //CJK UNIFIED IDEOGRAPH + 0xC172: 0x7FA0, //CJK UNIFIED IDEOGRAPH + 0xC173: 0x7FA2, //CJK UNIFIED IDEOGRAPH + 0xC174: 0x7FA3, //CJK UNIFIED IDEOGRAPH + 0xC175: 0x7FA5, //CJK UNIFIED IDEOGRAPH + 0xC176: 0x7FA6, //CJK UNIFIED IDEOGRAPH + 0xC177: 0x7FA8, //CJK UNIFIED IDEOGRAPH + 0xC178: 0x7FA9, //CJK UNIFIED IDEOGRAPH + 0xC179: 0x7FAA, //CJK UNIFIED IDEOGRAPH + 0xC17A: 0x7FAB, //CJK UNIFIED IDEOGRAPH + 0xC17B: 0x7FAC, //CJK UNIFIED IDEOGRAPH + 0xC17C: 0x7FAD, //CJK UNIFIED IDEOGRAPH + 0xC17D: 0x7FAE, //CJK UNIFIED IDEOGRAPH + 0xC17E: 0x7FB1, //CJK UNIFIED IDEOGRAPH + 0xC180: 0x7FB3, //CJK UNIFIED IDEOGRAPH + 0xC181: 0x7FB4, //CJK UNIFIED IDEOGRAPH + 0xC182: 0x7FB5, //CJK UNIFIED IDEOGRAPH + 0xC183: 0x7FB6, //CJK UNIFIED IDEOGRAPH + 0xC184: 0x7FB7, //CJK UNIFIED IDEOGRAPH + 0xC185: 0x7FBA, //CJK UNIFIED IDEOGRAPH + 0xC186: 0x7FBB, //CJK UNIFIED IDEOGRAPH + 0xC187: 0x7FBE, //CJK UNIFIED IDEOGRAPH + 0xC188: 0x7FC0, //CJK UNIFIED IDEOGRAPH + 0xC189: 0x7FC2, //CJK UNIFIED IDEOGRAPH + 0xC18A: 0x7FC3, //CJK UNIFIED IDEOGRAPH + 0xC18B: 0x7FC4, //CJK UNIFIED IDEOGRAPH + 0xC18C: 0x7FC6, //CJK UNIFIED IDEOGRAPH + 0xC18D: 0x7FC7, //CJK UNIFIED IDEOGRAPH + 0xC18E: 0x7FC8, //CJK UNIFIED IDEOGRAPH + 0xC18F: 0x7FC9, //CJK UNIFIED IDEOGRAPH + 0xC190: 0x7FCB, //CJK UNIFIED IDEOGRAPH + 0xC191: 0x7FCD, //CJK UNIFIED IDEOGRAPH + 0xC192: 0x7FCF, //CJK UNIFIED IDEOGRAPH + 0xC193: 0x7FD0, //CJK UNIFIED IDEOGRAPH + 0xC194: 0x7FD1, //CJK UNIFIED IDEOGRAPH + 0xC195: 0x7FD2, //CJK UNIFIED IDEOGRAPH + 0xC196: 0x7FD3, //CJK UNIFIED IDEOGRAPH + 0xC197: 0x7FD6, //CJK UNIFIED IDEOGRAPH + 0xC198: 0x7FD7, //CJK UNIFIED IDEOGRAPH + 0xC199: 0x7FD9, //CJK UNIFIED IDEOGRAPH + 0xC19A: 0x7FDA, //CJK UNIFIED IDEOGRAPH + 0xC19B: 0x7FDB, //CJK UNIFIED IDEOGRAPH + 0xC19C: 0x7FDC, //CJK UNIFIED IDEOGRAPH + 0xC19D: 0x7FDD, //CJK UNIFIED IDEOGRAPH + 0xC19E: 0x7FDE, //CJK UNIFIED IDEOGRAPH + 0xC19F: 0x7FE2, //CJK UNIFIED IDEOGRAPH + 0xC1A0: 0x7FE3, //CJK UNIFIED IDEOGRAPH + 0xC1A1: 0x75E2, //CJK UNIFIED IDEOGRAPH + 0xC1A2: 0x7ACB, //CJK UNIFIED IDEOGRAPH + 0xC1A3: 0x7C92, //CJK UNIFIED IDEOGRAPH + 0xC1A4: 0x6CA5, //CJK UNIFIED IDEOGRAPH + 0xC1A5: 0x96B6, //CJK UNIFIED IDEOGRAPH + 0xC1A6: 0x529B, //CJK UNIFIED IDEOGRAPH + 0xC1A7: 0x7483, //CJK UNIFIED IDEOGRAPH + 0xC1A8: 0x54E9, //CJK UNIFIED IDEOGRAPH + 0xC1A9: 0x4FE9, //CJK UNIFIED IDEOGRAPH + 0xC1AA: 0x8054, //CJK UNIFIED IDEOGRAPH + 0xC1AB: 0x83B2, //CJK UNIFIED IDEOGRAPH + 0xC1AC: 0x8FDE, //CJK UNIFIED IDEOGRAPH + 0xC1AD: 0x9570, //CJK UNIFIED IDEOGRAPH + 0xC1AE: 0x5EC9, //CJK UNIFIED IDEOGRAPH + 0xC1AF: 0x601C, //CJK UNIFIED IDEOGRAPH + 0xC1B0: 0x6D9F, //CJK UNIFIED IDEOGRAPH + 0xC1B1: 0x5E18, //CJK UNIFIED IDEOGRAPH + 0xC1B2: 0x655B, //CJK UNIFIED IDEOGRAPH + 0xC1B3: 0x8138, //CJK UNIFIED IDEOGRAPH + 0xC1B4: 0x94FE, //CJK UNIFIED IDEOGRAPH + 0xC1B5: 0x604B, //CJK UNIFIED IDEOGRAPH + 0xC1B6: 0x70BC, //CJK UNIFIED IDEOGRAPH + 0xC1B7: 0x7EC3, //CJK UNIFIED IDEOGRAPH + 0xC1B8: 0x7CAE, //CJK UNIFIED IDEOGRAPH + 0xC1B9: 0x51C9, //CJK UNIFIED IDEOGRAPH + 0xC1BA: 0x6881, //CJK UNIFIED IDEOGRAPH + 0xC1BB: 0x7CB1, //CJK UNIFIED IDEOGRAPH + 0xC1BC: 0x826F, //CJK UNIFIED IDEOGRAPH + 0xC1BD: 0x4E24, //CJK UNIFIED IDEOGRAPH + 0xC1BE: 0x8F86, //CJK UNIFIED IDEOGRAPH + 0xC1BF: 0x91CF, //CJK UNIFIED IDEOGRAPH + 0xC1C0: 0x667E, //CJK UNIFIED IDEOGRAPH + 0xC1C1: 0x4EAE, //CJK UNIFIED IDEOGRAPH + 0xC1C2: 0x8C05, //CJK UNIFIED IDEOGRAPH + 0xC1C3: 0x64A9, //CJK UNIFIED IDEOGRAPH + 0xC1C4: 0x804A, //CJK UNIFIED IDEOGRAPH + 0xC1C5: 0x50DA, //CJK UNIFIED IDEOGRAPH + 0xC1C6: 0x7597, //CJK UNIFIED IDEOGRAPH + 0xC1C7: 0x71CE, //CJK UNIFIED IDEOGRAPH + 0xC1C8: 0x5BE5, //CJK UNIFIED IDEOGRAPH + 0xC1C9: 0x8FBD, //CJK UNIFIED IDEOGRAPH + 0xC1CA: 0x6F66, //CJK UNIFIED IDEOGRAPH + 0xC1CB: 0x4E86, //CJK UNIFIED IDEOGRAPH + 0xC1CC: 0x6482, //CJK UNIFIED IDEOGRAPH + 0xC1CD: 0x9563, //CJK UNIFIED IDEOGRAPH + 0xC1CE: 0x5ED6, //CJK UNIFIED IDEOGRAPH + 0xC1CF: 0x6599, //CJK UNIFIED IDEOGRAPH + 0xC1D0: 0x5217, //CJK UNIFIED IDEOGRAPH + 0xC1D1: 0x88C2, //CJK UNIFIED IDEOGRAPH + 0xC1D2: 0x70C8, //CJK UNIFIED IDEOGRAPH + 0xC1D3: 0x52A3, //CJK UNIFIED IDEOGRAPH + 0xC1D4: 0x730E, //CJK UNIFIED IDEOGRAPH + 0xC1D5: 0x7433, //CJK UNIFIED IDEOGRAPH + 0xC1D6: 0x6797, //CJK UNIFIED IDEOGRAPH + 0xC1D7: 0x78F7, //CJK UNIFIED IDEOGRAPH + 0xC1D8: 0x9716, //CJK UNIFIED IDEOGRAPH + 0xC1D9: 0x4E34, //CJK UNIFIED IDEOGRAPH + 0xC1DA: 0x90BB, //CJK UNIFIED IDEOGRAPH + 0xC1DB: 0x9CDE, //CJK UNIFIED IDEOGRAPH + 0xC1DC: 0x6DCB, //CJK UNIFIED IDEOGRAPH + 0xC1DD: 0x51DB, //CJK UNIFIED IDEOGRAPH + 0xC1DE: 0x8D41, //CJK UNIFIED IDEOGRAPH + 0xC1DF: 0x541D, //CJK UNIFIED IDEOGRAPH + 0xC1E0: 0x62CE, //CJK UNIFIED IDEOGRAPH + 0xC1E1: 0x73B2, //CJK UNIFIED IDEOGRAPH + 0xC1E2: 0x83F1, //CJK UNIFIED IDEOGRAPH + 0xC1E3: 0x96F6, //CJK UNIFIED IDEOGRAPH + 0xC1E4: 0x9F84, //CJK UNIFIED IDEOGRAPH + 0xC1E5: 0x94C3, //CJK UNIFIED IDEOGRAPH + 0xC1E6: 0x4F36, //CJK UNIFIED IDEOGRAPH + 0xC1E7: 0x7F9A, //CJK UNIFIED IDEOGRAPH + 0xC1E8: 0x51CC, //CJK UNIFIED IDEOGRAPH + 0xC1E9: 0x7075, //CJK UNIFIED IDEOGRAPH + 0xC1EA: 0x9675, //CJK UNIFIED IDEOGRAPH + 0xC1EB: 0x5CAD, //CJK UNIFIED IDEOGRAPH + 0xC1EC: 0x9886, //CJK UNIFIED IDEOGRAPH + 0xC1ED: 0x53E6, //CJK UNIFIED IDEOGRAPH + 0xC1EE: 0x4EE4, //CJK UNIFIED IDEOGRAPH + 0xC1EF: 0x6E9C, //CJK UNIFIED IDEOGRAPH + 0xC1F0: 0x7409, //CJK UNIFIED IDEOGRAPH + 0xC1F1: 0x69B4, //CJK UNIFIED IDEOGRAPH + 0xC1F2: 0x786B, //CJK UNIFIED IDEOGRAPH + 0xC1F3: 0x998F, //CJK UNIFIED IDEOGRAPH + 0xC1F4: 0x7559, //CJK UNIFIED IDEOGRAPH + 0xC1F5: 0x5218, //CJK UNIFIED IDEOGRAPH + 0xC1F6: 0x7624, //CJK UNIFIED IDEOGRAPH + 0xC1F7: 0x6D41, //CJK UNIFIED IDEOGRAPH + 0xC1F8: 0x67F3, //CJK UNIFIED IDEOGRAPH + 0xC1F9: 0x516D, //CJK UNIFIED IDEOGRAPH + 0xC1FA: 0x9F99, //CJK UNIFIED IDEOGRAPH + 0xC1FB: 0x804B, //CJK UNIFIED IDEOGRAPH + 0xC1FC: 0x5499, //CJK UNIFIED IDEOGRAPH + 0xC1FD: 0x7B3C, //CJK UNIFIED IDEOGRAPH + 0xC1FE: 0x7ABF, //CJK UNIFIED IDEOGRAPH + 0xC240: 0x7FE4, //CJK UNIFIED IDEOGRAPH + 0xC241: 0x7FE7, //CJK UNIFIED IDEOGRAPH + 0xC242: 0x7FE8, //CJK UNIFIED IDEOGRAPH + 0xC243: 0x7FEA, //CJK UNIFIED IDEOGRAPH + 0xC244: 0x7FEB, //CJK UNIFIED IDEOGRAPH + 0xC245: 0x7FEC, //CJK UNIFIED IDEOGRAPH + 0xC246: 0x7FED, //CJK UNIFIED IDEOGRAPH + 0xC247: 0x7FEF, //CJK UNIFIED IDEOGRAPH + 0xC248: 0x7FF2, //CJK UNIFIED IDEOGRAPH + 0xC249: 0x7FF4, //CJK UNIFIED IDEOGRAPH + 0xC24A: 0x7FF5, //CJK UNIFIED IDEOGRAPH + 0xC24B: 0x7FF6, //CJK UNIFIED IDEOGRAPH + 0xC24C: 0x7FF7, //CJK UNIFIED IDEOGRAPH + 0xC24D: 0x7FF8, //CJK UNIFIED IDEOGRAPH + 0xC24E: 0x7FF9, //CJK UNIFIED IDEOGRAPH + 0xC24F: 0x7FFA, //CJK UNIFIED IDEOGRAPH + 0xC250: 0x7FFD, //CJK UNIFIED IDEOGRAPH + 0xC251: 0x7FFE, //CJK UNIFIED IDEOGRAPH + 0xC252: 0x7FFF, //CJK UNIFIED IDEOGRAPH + 0xC253: 0x8002, //CJK UNIFIED IDEOGRAPH + 0xC254: 0x8007, //CJK UNIFIED IDEOGRAPH + 0xC255: 0x8008, //CJK UNIFIED IDEOGRAPH + 0xC256: 0x8009, //CJK UNIFIED IDEOGRAPH + 0xC257: 0x800A, //CJK UNIFIED IDEOGRAPH + 0xC258: 0x800E, //CJK UNIFIED IDEOGRAPH + 0xC259: 0x800F, //CJK UNIFIED IDEOGRAPH + 0xC25A: 0x8011, //CJK UNIFIED IDEOGRAPH + 0xC25B: 0x8013, //CJK UNIFIED IDEOGRAPH + 0xC25C: 0x801A, //CJK UNIFIED IDEOGRAPH + 0xC25D: 0x801B, //CJK UNIFIED IDEOGRAPH + 0xC25E: 0x801D, //CJK UNIFIED IDEOGRAPH + 0xC25F: 0x801E, //CJK UNIFIED IDEOGRAPH + 0xC260: 0x801F, //CJK UNIFIED IDEOGRAPH + 0xC261: 0x8021, //CJK UNIFIED IDEOGRAPH + 0xC262: 0x8023, //CJK UNIFIED IDEOGRAPH + 0xC263: 0x8024, //CJK UNIFIED IDEOGRAPH + 0xC264: 0x802B, //CJK UNIFIED IDEOGRAPH + 0xC265: 0x802C, //CJK UNIFIED IDEOGRAPH + 0xC266: 0x802D, //CJK UNIFIED IDEOGRAPH + 0xC267: 0x802E, //CJK UNIFIED IDEOGRAPH + 0xC268: 0x802F, //CJK UNIFIED IDEOGRAPH + 0xC269: 0x8030, //CJK UNIFIED IDEOGRAPH + 0xC26A: 0x8032, //CJK UNIFIED IDEOGRAPH + 0xC26B: 0x8034, //CJK UNIFIED IDEOGRAPH + 0xC26C: 0x8039, //CJK UNIFIED IDEOGRAPH + 0xC26D: 0x803A, //CJK UNIFIED IDEOGRAPH + 0xC26E: 0x803C, //CJK UNIFIED IDEOGRAPH + 0xC26F: 0x803E, //CJK UNIFIED IDEOGRAPH + 0xC270: 0x8040, //CJK UNIFIED IDEOGRAPH + 0xC271: 0x8041, //CJK UNIFIED IDEOGRAPH + 0xC272: 0x8044, //CJK UNIFIED IDEOGRAPH + 0xC273: 0x8045, //CJK UNIFIED IDEOGRAPH + 0xC274: 0x8047, //CJK UNIFIED IDEOGRAPH + 0xC275: 0x8048, //CJK UNIFIED IDEOGRAPH + 0xC276: 0x8049, //CJK UNIFIED IDEOGRAPH + 0xC277: 0x804E, //CJK UNIFIED IDEOGRAPH + 0xC278: 0x804F, //CJK UNIFIED IDEOGRAPH + 0xC279: 0x8050, //CJK UNIFIED IDEOGRAPH + 0xC27A: 0x8051, //CJK UNIFIED IDEOGRAPH + 0xC27B: 0x8053, //CJK UNIFIED IDEOGRAPH + 0xC27C: 0x8055, //CJK UNIFIED IDEOGRAPH + 0xC27D: 0x8056, //CJK UNIFIED IDEOGRAPH + 0xC27E: 0x8057, //CJK UNIFIED IDEOGRAPH + 0xC280: 0x8059, //CJK UNIFIED IDEOGRAPH + 0xC281: 0x805B, //CJK UNIFIED IDEOGRAPH + 0xC282: 0x805C, //CJK UNIFIED IDEOGRAPH + 0xC283: 0x805D, //CJK UNIFIED IDEOGRAPH + 0xC284: 0x805E, //CJK UNIFIED IDEOGRAPH + 0xC285: 0x805F, //CJK UNIFIED IDEOGRAPH + 0xC286: 0x8060, //CJK UNIFIED IDEOGRAPH + 0xC287: 0x8061, //CJK UNIFIED IDEOGRAPH + 0xC288: 0x8062, //CJK UNIFIED IDEOGRAPH + 0xC289: 0x8063, //CJK UNIFIED IDEOGRAPH + 0xC28A: 0x8064, //CJK UNIFIED IDEOGRAPH + 0xC28B: 0x8065, //CJK UNIFIED IDEOGRAPH + 0xC28C: 0x8066, //CJK UNIFIED IDEOGRAPH + 0xC28D: 0x8067, //CJK UNIFIED IDEOGRAPH + 0xC28E: 0x8068, //CJK UNIFIED IDEOGRAPH + 0xC28F: 0x806B, //CJK UNIFIED IDEOGRAPH + 0xC290: 0x806C, //CJK UNIFIED IDEOGRAPH + 0xC291: 0x806D, //CJK UNIFIED IDEOGRAPH + 0xC292: 0x806E, //CJK UNIFIED IDEOGRAPH + 0xC293: 0x806F, //CJK UNIFIED IDEOGRAPH + 0xC294: 0x8070, //CJK UNIFIED IDEOGRAPH + 0xC295: 0x8072, //CJK UNIFIED IDEOGRAPH + 0xC296: 0x8073, //CJK UNIFIED IDEOGRAPH + 0xC297: 0x8074, //CJK UNIFIED IDEOGRAPH + 0xC298: 0x8075, //CJK UNIFIED IDEOGRAPH + 0xC299: 0x8076, //CJK UNIFIED IDEOGRAPH + 0xC29A: 0x8077, //CJK UNIFIED IDEOGRAPH + 0xC29B: 0x8078, //CJK UNIFIED IDEOGRAPH + 0xC29C: 0x8079, //CJK UNIFIED IDEOGRAPH + 0xC29D: 0x807A, //CJK UNIFIED IDEOGRAPH + 0xC29E: 0x807B, //CJK UNIFIED IDEOGRAPH + 0xC29F: 0x807C, //CJK UNIFIED IDEOGRAPH + 0xC2A0: 0x807D, //CJK UNIFIED IDEOGRAPH + 0xC2A1: 0x9686, //CJK UNIFIED IDEOGRAPH + 0xC2A2: 0x5784, //CJK UNIFIED IDEOGRAPH + 0xC2A3: 0x62E2, //CJK UNIFIED IDEOGRAPH + 0xC2A4: 0x9647, //CJK UNIFIED IDEOGRAPH + 0xC2A5: 0x697C, //CJK UNIFIED IDEOGRAPH + 0xC2A6: 0x5A04, //CJK UNIFIED IDEOGRAPH + 0xC2A7: 0x6402, //CJK UNIFIED IDEOGRAPH + 0xC2A8: 0x7BD3, //CJK UNIFIED IDEOGRAPH + 0xC2A9: 0x6F0F, //CJK UNIFIED IDEOGRAPH + 0xC2AA: 0x964B, //CJK UNIFIED IDEOGRAPH + 0xC2AB: 0x82A6, //CJK UNIFIED IDEOGRAPH + 0xC2AC: 0x5362, //CJK UNIFIED IDEOGRAPH + 0xC2AD: 0x9885, //CJK UNIFIED IDEOGRAPH + 0xC2AE: 0x5E90, //CJK UNIFIED IDEOGRAPH + 0xC2AF: 0x7089, //CJK UNIFIED IDEOGRAPH + 0xC2B0: 0x63B3, //CJK UNIFIED IDEOGRAPH + 0xC2B1: 0x5364, //CJK UNIFIED IDEOGRAPH + 0xC2B2: 0x864F, //CJK UNIFIED IDEOGRAPH + 0xC2B3: 0x9C81, //CJK UNIFIED IDEOGRAPH + 0xC2B4: 0x9E93, //CJK UNIFIED IDEOGRAPH + 0xC2B5: 0x788C, //CJK UNIFIED IDEOGRAPH + 0xC2B6: 0x9732, //CJK UNIFIED IDEOGRAPH + 0xC2B7: 0x8DEF, //CJK UNIFIED IDEOGRAPH + 0xC2B8: 0x8D42, //CJK UNIFIED IDEOGRAPH + 0xC2B9: 0x9E7F, //CJK UNIFIED IDEOGRAPH + 0xC2BA: 0x6F5E, //CJK UNIFIED IDEOGRAPH + 0xC2BB: 0x7984, //CJK UNIFIED IDEOGRAPH + 0xC2BC: 0x5F55, //CJK UNIFIED IDEOGRAPH + 0xC2BD: 0x9646, //CJK UNIFIED IDEOGRAPH + 0xC2BE: 0x622E, //CJK UNIFIED IDEOGRAPH + 0xC2BF: 0x9A74, //CJK UNIFIED IDEOGRAPH + 0xC2C0: 0x5415, //CJK UNIFIED IDEOGRAPH + 0xC2C1: 0x94DD, //CJK UNIFIED IDEOGRAPH + 0xC2C2: 0x4FA3, //CJK UNIFIED IDEOGRAPH + 0xC2C3: 0x65C5, //CJK UNIFIED IDEOGRAPH + 0xC2C4: 0x5C65, //CJK UNIFIED IDEOGRAPH + 0xC2C5: 0x5C61, //CJK UNIFIED IDEOGRAPH + 0xC2C6: 0x7F15, //CJK UNIFIED IDEOGRAPH + 0xC2C7: 0x8651, //CJK UNIFIED IDEOGRAPH + 0xC2C8: 0x6C2F, //CJK UNIFIED IDEOGRAPH + 0xC2C9: 0x5F8B, //CJK UNIFIED IDEOGRAPH + 0xC2CA: 0x7387, //CJK UNIFIED IDEOGRAPH + 0xC2CB: 0x6EE4, //CJK UNIFIED IDEOGRAPH + 0xC2CC: 0x7EFF, //CJK UNIFIED IDEOGRAPH + 0xC2CD: 0x5CE6, //CJK UNIFIED IDEOGRAPH + 0xC2CE: 0x631B, //CJK UNIFIED IDEOGRAPH + 0xC2CF: 0x5B6A, //CJK UNIFIED IDEOGRAPH + 0xC2D0: 0x6EE6, //CJK UNIFIED IDEOGRAPH + 0xC2D1: 0x5375, //CJK UNIFIED IDEOGRAPH + 0xC2D2: 0x4E71, //CJK UNIFIED IDEOGRAPH + 0xC2D3: 0x63A0, //CJK UNIFIED IDEOGRAPH + 0xC2D4: 0x7565, //CJK UNIFIED IDEOGRAPH + 0xC2D5: 0x62A1, //CJK UNIFIED IDEOGRAPH + 0xC2D6: 0x8F6E, //CJK UNIFIED IDEOGRAPH + 0xC2D7: 0x4F26, //CJK UNIFIED IDEOGRAPH + 0xC2D8: 0x4ED1, //CJK UNIFIED IDEOGRAPH + 0xC2D9: 0x6CA6, //CJK UNIFIED IDEOGRAPH + 0xC2DA: 0x7EB6, //CJK UNIFIED IDEOGRAPH + 0xC2DB: 0x8BBA, //CJK UNIFIED IDEOGRAPH + 0xC2DC: 0x841D, //CJK UNIFIED IDEOGRAPH + 0xC2DD: 0x87BA, //CJK UNIFIED IDEOGRAPH + 0xC2DE: 0x7F57, //CJK UNIFIED IDEOGRAPH + 0xC2DF: 0x903B, //CJK UNIFIED IDEOGRAPH + 0xC2E0: 0x9523, //CJK UNIFIED IDEOGRAPH + 0xC2E1: 0x7BA9, //CJK UNIFIED IDEOGRAPH + 0xC2E2: 0x9AA1, //CJK UNIFIED IDEOGRAPH + 0xC2E3: 0x88F8, //CJK UNIFIED IDEOGRAPH + 0xC2E4: 0x843D, //CJK UNIFIED IDEOGRAPH + 0xC2E5: 0x6D1B, //CJK UNIFIED IDEOGRAPH + 0xC2E6: 0x9A86, //CJK UNIFIED IDEOGRAPH + 0xC2E7: 0x7EDC, //CJK UNIFIED IDEOGRAPH + 0xC2E8: 0x5988, //CJK UNIFIED IDEOGRAPH + 0xC2E9: 0x9EBB, //CJK UNIFIED IDEOGRAPH + 0xC2EA: 0x739B, //CJK UNIFIED IDEOGRAPH + 0xC2EB: 0x7801, //CJK UNIFIED IDEOGRAPH + 0xC2EC: 0x8682, //CJK UNIFIED IDEOGRAPH + 0xC2ED: 0x9A6C, //CJK UNIFIED IDEOGRAPH + 0xC2EE: 0x9A82, //CJK UNIFIED IDEOGRAPH + 0xC2EF: 0x561B, //CJK UNIFIED IDEOGRAPH + 0xC2F0: 0x5417, //CJK UNIFIED IDEOGRAPH + 0xC2F1: 0x57CB, //CJK UNIFIED IDEOGRAPH + 0xC2F2: 0x4E70, //CJK UNIFIED IDEOGRAPH + 0xC2F3: 0x9EA6, //CJK UNIFIED IDEOGRAPH + 0xC2F4: 0x5356, //CJK UNIFIED IDEOGRAPH + 0xC2F5: 0x8FC8, //CJK UNIFIED IDEOGRAPH + 0xC2F6: 0x8109, //CJK UNIFIED IDEOGRAPH + 0xC2F7: 0x7792, //CJK UNIFIED IDEOGRAPH + 0xC2F8: 0x9992, //CJK UNIFIED IDEOGRAPH + 0xC2F9: 0x86EE, //CJK UNIFIED IDEOGRAPH + 0xC2FA: 0x6EE1, //CJK UNIFIED IDEOGRAPH + 0xC2FB: 0x8513, //CJK UNIFIED IDEOGRAPH + 0xC2FC: 0x66FC, //CJK UNIFIED IDEOGRAPH + 0xC2FD: 0x6162, //CJK UNIFIED IDEOGRAPH + 0xC2FE: 0x6F2B, //CJK UNIFIED IDEOGRAPH + 0xC340: 0x807E, //CJK UNIFIED IDEOGRAPH + 0xC341: 0x8081, //CJK UNIFIED IDEOGRAPH + 0xC342: 0x8082, //CJK UNIFIED IDEOGRAPH + 0xC343: 0x8085, //CJK UNIFIED IDEOGRAPH + 0xC344: 0x8088, //CJK UNIFIED IDEOGRAPH + 0xC345: 0x808A, //CJK UNIFIED IDEOGRAPH + 0xC346: 0x808D, //CJK UNIFIED IDEOGRAPH + 0xC347: 0x808E, //CJK UNIFIED IDEOGRAPH + 0xC348: 0x808F, //CJK UNIFIED IDEOGRAPH + 0xC349: 0x8090, //CJK UNIFIED IDEOGRAPH + 0xC34A: 0x8091, //CJK UNIFIED IDEOGRAPH + 0xC34B: 0x8092, //CJK UNIFIED IDEOGRAPH + 0xC34C: 0x8094, //CJK UNIFIED IDEOGRAPH + 0xC34D: 0x8095, //CJK UNIFIED IDEOGRAPH + 0xC34E: 0x8097, //CJK UNIFIED IDEOGRAPH + 0xC34F: 0x8099, //CJK UNIFIED IDEOGRAPH + 0xC350: 0x809E, //CJK UNIFIED IDEOGRAPH + 0xC351: 0x80A3, //CJK UNIFIED IDEOGRAPH + 0xC352: 0x80A6, //CJK UNIFIED IDEOGRAPH + 0xC353: 0x80A7, //CJK UNIFIED IDEOGRAPH + 0xC354: 0x80A8, //CJK UNIFIED IDEOGRAPH + 0xC355: 0x80AC, //CJK UNIFIED IDEOGRAPH + 0xC356: 0x80B0, //CJK UNIFIED IDEOGRAPH + 0xC357: 0x80B3, //CJK UNIFIED IDEOGRAPH + 0xC358: 0x80B5, //CJK UNIFIED IDEOGRAPH + 0xC359: 0x80B6, //CJK UNIFIED IDEOGRAPH + 0xC35A: 0x80B8, //CJK UNIFIED IDEOGRAPH + 0xC35B: 0x80B9, //CJK UNIFIED IDEOGRAPH + 0xC35C: 0x80BB, //CJK UNIFIED IDEOGRAPH + 0xC35D: 0x80C5, //CJK UNIFIED IDEOGRAPH + 0xC35E: 0x80C7, //CJK UNIFIED IDEOGRAPH + 0xC35F: 0x80C8, //CJK UNIFIED IDEOGRAPH + 0xC360: 0x80C9, //CJK UNIFIED IDEOGRAPH + 0xC361: 0x80CA, //CJK UNIFIED IDEOGRAPH + 0xC362: 0x80CB, //CJK UNIFIED IDEOGRAPH + 0xC363: 0x80CF, //CJK UNIFIED IDEOGRAPH + 0xC364: 0x80D0, //CJK UNIFIED IDEOGRAPH + 0xC365: 0x80D1, //CJK UNIFIED IDEOGRAPH + 0xC366: 0x80D2, //CJK UNIFIED IDEOGRAPH + 0xC367: 0x80D3, //CJK UNIFIED IDEOGRAPH + 0xC368: 0x80D4, //CJK UNIFIED IDEOGRAPH + 0xC369: 0x80D5, //CJK UNIFIED IDEOGRAPH + 0xC36A: 0x80D8, //CJK UNIFIED IDEOGRAPH + 0xC36B: 0x80DF, //CJK UNIFIED IDEOGRAPH + 0xC36C: 0x80E0, //CJK UNIFIED IDEOGRAPH + 0xC36D: 0x80E2, //CJK UNIFIED IDEOGRAPH + 0xC36E: 0x80E3, //CJK UNIFIED IDEOGRAPH + 0xC36F: 0x80E6, //CJK UNIFIED IDEOGRAPH + 0xC370: 0x80EE, //CJK UNIFIED IDEOGRAPH + 0xC371: 0x80F5, //CJK UNIFIED IDEOGRAPH + 0xC372: 0x80F7, //CJK UNIFIED IDEOGRAPH + 0xC373: 0x80F9, //CJK UNIFIED IDEOGRAPH + 0xC374: 0x80FB, //CJK UNIFIED IDEOGRAPH + 0xC375: 0x80FE, //CJK UNIFIED IDEOGRAPH + 0xC376: 0x80FF, //CJK UNIFIED IDEOGRAPH + 0xC377: 0x8100, //CJK UNIFIED IDEOGRAPH + 0xC378: 0x8101, //CJK UNIFIED IDEOGRAPH + 0xC379: 0x8103, //CJK UNIFIED IDEOGRAPH + 0xC37A: 0x8104, //CJK UNIFIED IDEOGRAPH + 0xC37B: 0x8105, //CJK UNIFIED IDEOGRAPH + 0xC37C: 0x8107, //CJK UNIFIED IDEOGRAPH + 0xC37D: 0x8108, //CJK UNIFIED IDEOGRAPH + 0xC37E: 0x810B, //CJK UNIFIED IDEOGRAPH + 0xC380: 0x810C, //CJK UNIFIED IDEOGRAPH + 0xC381: 0x8115, //CJK UNIFIED IDEOGRAPH + 0xC382: 0x8117, //CJK UNIFIED IDEOGRAPH + 0xC383: 0x8119, //CJK UNIFIED IDEOGRAPH + 0xC384: 0x811B, //CJK UNIFIED IDEOGRAPH + 0xC385: 0x811C, //CJK UNIFIED IDEOGRAPH + 0xC386: 0x811D, //CJK UNIFIED IDEOGRAPH + 0xC387: 0x811F, //CJK UNIFIED IDEOGRAPH + 0xC388: 0x8120, //CJK UNIFIED IDEOGRAPH + 0xC389: 0x8121, //CJK UNIFIED IDEOGRAPH + 0xC38A: 0x8122, //CJK UNIFIED IDEOGRAPH + 0xC38B: 0x8123, //CJK UNIFIED IDEOGRAPH + 0xC38C: 0x8124, //CJK UNIFIED IDEOGRAPH + 0xC38D: 0x8125, //CJK UNIFIED IDEOGRAPH + 0xC38E: 0x8126, //CJK UNIFIED IDEOGRAPH + 0xC38F: 0x8127, //CJK UNIFIED IDEOGRAPH + 0xC390: 0x8128, //CJK UNIFIED IDEOGRAPH + 0xC391: 0x8129, //CJK UNIFIED IDEOGRAPH + 0xC392: 0x812A, //CJK UNIFIED IDEOGRAPH + 0xC393: 0x812B, //CJK UNIFIED IDEOGRAPH + 0xC394: 0x812D, //CJK UNIFIED IDEOGRAPH + 0xC395: 0x812E, //CJK UNIFIED IDEOGRAPH + 0xC396: 0x8130, //CJK UNIFIED IDEOGRAPH + 0xC397: 0x8133, //CJK UNIFIED IDEOGRAPH + 0xC398: 0x8134, //CJK UNIFIED IDEOGRAPH + 0xC399: 0x8135, //CJK UNIFIED IDEOGRAPH + 0xC39A: 0x8137, //CJK UNIFIED IDEOGRAPH + 0xC39B: 0x8139, //CJK UNIFIED IDEOGRAPH + 0xC39C: 0x813A, //CJK UNIFIED IDEOGRAPH + 0xC39D: 0x813B, //CJK UNIFIED IDEOGRAPH + 0xC39E: 0x813C, //CJK UNIFIED IDEOGRAPH + 0xC39F: 0x813D, //CJK UNIFIED IDEOGRAPH + 0xC3A0: 0x813F, //CJK UNIFIED IDEOGRAPH + 0xC3A1: 0x8C29, //CJK UNIFIED IDEOGRAPH + 0xC3A2: 0x8292, //CJK UNIFIED IDEOGRAPH + 0xC3A3: 0x832B, //CJK UNIFIED IDEOGRAPH + 0xC3A4: 0x76F2, //CJK UNIFIED IDEOGRAPH + 0xC3A5: 0x6C13, //CJK UNIFIED IDEOGRAPH + 0xC3A6: 0x5FD9, //CJK UNIFIED IDEOGRAPH + 0xC3A7: 0x83BD, //CJK UNIFIED IDEOGRAPH + 0xC3A8: 0x732B, //CJK UNIFIED IDEOGRAPH + 0xC3A9: 0x8305, //CJK UNIFIED IDEOGRAPH + 0xC3AA: 0x951A, //CJK UNIFIED IDEOGRAPH + 0xC3AB: 0x6BDB, //CJK UNIFIED IDEOGRAPH + 0xC3AC: 0x77DB, //CJK UNIFIED IDEOGRAPH + 0xC3AD: 0x94C6, //CJK UNIFIED IDEOGRAPH + 0xC3AE: 0x536F, //CJK UNIFIED IDEOGRAPH + 0xC3AF: 0x8302, //CJK UNIFIED IDEOGRAPH + 0xC3B0: 0x5192, //CJK UNIFIED IDEOGRAPH + 0xC3B1: 0x5E3D, //CJK UNIFIED IDEOGRAPH + 0xC3B2: 0x8C8C, //CJK UNIFIED IDEOGRAPH + 0xC3B3: 0x8D38, //CJK UNIFIED IDEOGRAPH + 0xC3B4: 0x4E48, //CJK UNIFIED IDEOGRAPH + 0xC3B5: 0x73AB, //CJK UNIFIED IDEOGRAPH + 0xC3B6: 0x679A, //CJK UNIFIED IDEOGRAPH + 0xC3B7: 0x6885, //CJK UNIFIED IDEOGRAPH + 0xC3B8: 0x9176, //CJK UNIFIED IDEOGRAPH + 0xC3B9: 0x9709, //CJK UNIFIED IDEOGRAPH + 0xC3BA: 0x7164, //CJK UNIFIED IDEOGRAPH + 0xC3BB: 0x6CA1, //CJK UNIFIED IDEOGRAPH + 0xC3BC: 0x7709, //CJK UNIFIED IDEOGRAPH + 0xC3BD: 0x5A92, //CJK UNIFIED IDEOGRAPH + 0xC3BE: 0x9541, //CJK UNIFIED IDEOGRAPH + 0xC3BF: 0x6BCF, //CJK UNIFIED IDEOGRAPH + 0xC3C0: 0x7F8E, //CJK UNIFIED IDEOGRAPH + 0xC3C1: 0x6627, //CJK UNIFIED IDEOGRAPH + 0xC3C2: 0x5BD0, //CJK UNIFIED IDEOGRAPH + 0xC3C3: 0x59B9, //CJK UNIFIED IDEOGRAPH + 0xC3C4: 0x5A9A, //CJK UNIFIED IDEOGRAPH + 0xC3C5: 0x95E8, //CJK UNIFIED IDEOGRAPH + 0xC3C6: 0x95F7, //CJK UNIFIED IDEOGRAPH + 0xC3C7: 0x4EEC, //CJK UNIFIED IDEOGRAPH + 0xC3C8: 0x840C, //CJK UNIFIED IDEOGRAPH + 0xC3C9: 0x8499, //CJK UNIFIED IDEOGRAPH + 0xC3CA: 0x6AAC, //CJK UNIFIED IDEOGRAPH + 0xC3CB: 0x76DF, //CJK UNIFIED IDEOGRAPH + 0xC3CC: 0x9530, //CJK UNIFIED IDEOGRAPH + 0xC3CD: 0x731B, //CJK UNIFIED IDEOGRAPH + 0xC3CE: 0x68A6, //CJK UNIFIED IDEOGRAPH + 0xC3CF: 0x5B5F, //CJK UNIFIED IDEOGRAPH + 0xC3D0: 0x772F, //CJK UNIFIED IDEOGRAPH + 0xC3D1: 0x919A, //CJK UNIFIED IDEOGRAPH + 0xC3D2: 0x9761, //CJK UNIFIED IDEOGRAPH + 0xC3D3: 0x7CDC, //CJK UNIFIED IDEOGRAPH + 0xC3D4: 0x8FF7, //CJK UNIFIED IDEOGRAPH + 0xC3D5: 0x8C1C, //CJK UNIFIED IDEOGRAPH + 0xC3D6: 0x5F25, //CJK UNIFIED IDEOGRAPH + 0xC3D7: 0x7C73, //CJK UNIFIED IDEOGRAPH + 0xC3D8: 0x79D8, //CJK UNIFIED IDEOGRAPH + 0xC3D9: 0x89C5, //CJK UNIFIED IDEOGRAPH + 0xC3DA: 0x6CCC, //CJK UNIFIED IDEOGRAPH + 0xC3DB: 0x871C, //CJK UNIFIED IDEOGRAPH + 0xC3DC: 0x5BC6, //CJK UNIFIED IDEOGRAPH + 0xC3DD: 0x5E42, //CJK UNIFIED IDEOGRAPH + 0xC3DE: 0x68C9, //CJK UNIFIED IDEOGRAPH + 0xC3DF: 0x7720, //CJK UNIFIED IDEOGRAPH + 0xC3E0: 0x7EF5, //CJK UNIFIED IDEOGRAPH + 0xC3E1: 0x5195, //CJK UNIFIED IDEOGRAPH + 0xC3E2: 0x514D, //CJK UNIFIED IDEOGRAPH + 0xC3E3: 0x52C9, //CJK UNIFIED IDEOGRAPH + 0xC3E4: 0x5A29, //CJK UNIFIED IDEOGRAPH + 0xC3E5: 0x7F05, //CJK UNIFIED IDEOGRAPH + 0xC3E6: 0x9762, //CJK UNIFIED IDEOGRAPH + 0xC3E7: 0x82D7, //CJK UNIFIED IDEOGRAPH + 0xC3E8: 0x63CF, //CJK UNIFIED IDEOGRAPH + 0xC3E9: 0x7784, //CJK UNIFIED IDEOGRAPH + 0xC3EA: 0x85D0, //CJK UNIFIED IDEOGRAPH + 0xC3EB: 0x79D2, //CJK UNIFIED IDEOGRAPH + 0xC3EC: 0x6E3A, //CJK UNIFIED IDEOGRAPH + 0xC3ED: 0x5E99, //CJK UNIFIED IDEOGRAPH + 0xC3EE: 0x5999, //CJK UNIFIED IDEOGRAPH + 0xC3EF: 0x8511, //CJK UNIFIED IDEOGRAPH + 0xC3F0: 0x706D, //CJK UNIFIED IDEOGRAPH + 0xC3F1: 0x6C11, //CJK UNIFIED IDEOGRAPH + 0xC3F2: 0x62BF, //CJK UNIFIED IDEOGRAPH + 0xC3F3: 0x76BF, //CJK UNIFIED IDEOGRAPH + 0xC3F4: 0x654F, //CJK UNIFIED IDEOGRAPH + 0xC3F5: 0x60AF, //CJK UNIFIED IDEOGRAPH + 0xC3F6: 0x95FD, //CJK UNIFIED IDEOGRAPH + 0xC3F7: 0x660E, //CJK UNIFIED IDEOGRAPH + 0xC3F8: 0x879F, //CJK UNIFIED IDEOGRAPH + 0xC3F9: 0x9E23, //CJK UNIFIED IDEOGRAPH + 0xC3FA: 0x94ED, //CJK UNIFIED IDEOGRAPH + 0xC3FB: 0x540D, //CJK UNIFIED IDEOGRAPH + 0xC3FC: 0x547D, //CJK UNIFIED IDEOGRAPH + 0xC3FD: 0x8C2C, //CJK UNIFIED IDEOGRAPH + 0xC3FE: 0x6478, //CJK UNIFIED IDEOGRAPH + 0xC440: 0x8140, //CJK UNIFIED IDEOGRAPH + 0xC441: 0x8141, //CJK UNIFIED IDEOGRAPH + 0xC442: 0x8142, //CJK UNIFIED IDEOGRAPH + 0xC443: 0x8143, //CJK UNIFIED IDEOGRAPH + 0xC444: 0x8144, //CJK UNIFIED IDEOGRAPH + 0xC445: 0x8145, //CJK UNIFIED IDEOGRAPH + 0xC446: 0x8147, //CJK UNIFIED IDEOGRAPH + 0xC447: 0x8149, //CJK UNIFIED IDEOGRAPH + 0xC448: 0x814D, //CJK UNIFIED IDEOGRAPH + 0xC449: 0x814E, //CJK UNIFIED IDEOGRAPH + 0xC44A: 0x814F, //CJK UNIFIED IDEOGRAPH + 0xC44B: 0x8152, //CJK UNIFIED IDEOGRAPH + 0xC44C: 0x8156, //CJK UNIFIED IDEOGRAPH + 0xC44D: 0x8157, //CJK UNIFIED IDEOGRAPH + 0xC44E: 0x8158, //CJK UNIFIED IDEOGRAPH + 0xC44F: 0x815B, //CJK UNIFIED IDEOGRAPH + 0xC450: 0x815C, //CJK UNIFIED IDEOGRAPH + 0xC451: 0x815D, //CJK UNIFIED IDEOGRAPH + 0xC452: 0x815E, //CJK UNIFIED IDEOGRAPH + 0xC453: 0x815F, //CJK UNIFIED IDEOGRAPH + 0xC454: 0x8161, //CJK UNIFIED IDEOGRAPH + 0xC455: 0x8162, //CJK UNIFIED IDEOGRAPH + 0xC456: 0x8163, //CJK UNIFIED IDEOGRAPH + 0xC457: 0x8164, //CJK UNIFIED IDEOGRAPH + 0xC458: 0x8166, //CJK UNIFIED IDEOGRAPH + 0xC459: 0x8168, //CJK UNIFIED IDEOGRAPH + 0xC45A: 0x816A, //CJK UNIFIED IDEOGRAPH + 0xC45B: 0x816B, //CJK UNIFIED IDEOGRAPH + 0xC45C: 0x816C, //CJK UNIFIED IDEOGRAPH + 0xC45D: 0x816F, //CJK UNIFIED IDEOGRAPH + 0xC45E: 0x8172, //CJK UNIFIED IDEOGRAPH + 0xC45F: 0x8173, //CJK UNIFIED IDEOGRAPH + 0xC460: 0x8175, //CJK UNIFIED IDEOGRAPH + 0xC461: 0x8176, //CJK UNIFIED IDEOGRAPH + 0xC462: 0x8177, //CJK UNIFIED IDEOGRAPH + 0xC463: 0x8178, //CJK UNIFIED IDEOGRAPH + 0xC464: 0x8181, //CJK UNIFIED IDEOGRAPH + 0xC465: 0x8183, //CJK UNIFIED IDEOGRAPH + 0xC466: 0x8184, //CJK UNIFIED IDEOGRAPH + 0xC467: 0x8185, //CJK UNIFIED IDEOGRAPH + 0xC468: 0x8186, //CJK UNIFIED IDEOGRAPH + 0xC469: 0x8187, //CJK UNIFIED IDEOGRAPH + 0xC46A: 0x8189, //CJK UNIFIED IDEOGRAPH + 0xC46B: 0x818B, //CJK UNIFIED IDEOGRAPH + 0xC46C: 0x818C, //CJK UNIFIED IDEOGRAPH + 0xC46D: 0x818D, //CJK UNIFIED IDEOGRAPH + 0xC46E: 0x818E, //CJK UNIFIED IDEOGRAPH + 0xC46F: 0x8190, //CJK UNIFIED IDEOGRAPH + 0xC470: 0x8192, //CJK UNIFIED IDEOGRAPH + 0xC471: 0x8193, //CJK UNIFIED IDEOGRAPH + 0xC472: 0x8194, //CJK UNIFIED IDEOGRAPH + 0xC473: 0x8195, //CJK UNIFIED IDEOGRAPH + 0xC474: 0x8196, //CJK UNIFIED IDEOGRAPH + 0xC475: 0x8197, //CJK UNIFIED IDEOGRAPH + 0xC476: 0x8199, //CJK UNIFIED IDEOGRAPH + 0xC477: 0x819A, //CJK UNIFIED IDEOGRAPH + 0xC478: 0x819E, //CJK UNIFIED IDEOGRAPH + 0xC479: 0x819F, //CJK UNIFIED IDEOGRAPH + 0xC47A: 0x81A0, //CJK UNIFIED IDEOGRAPH + 0xC47B: 0x81A1, //CJK UNIFIED IDEOGRAPH + 0xC47C: 0x81A2, //CJK UNIFIED IDEOGRAPH + 0xC47D: 0x81A4, //CJK UNIFIED IDEOGRAPH + 0xC47E: 0x81A5, //CJK UNIFIED IDEOGRAPH + 0xC480: 0x81A7, //CJK UNIFIED IDEOGRAPH + 0xC481: 0x81A9, //CJK UNIFIED IDEOGRAPH + 0xC482: 0x81AB, //CJK UNIFIED IDEOGRAPH + 0xC483: 0x81AC, //CJK UNIFIED IDEOGRAPH + 0xC484: 0x81AD, //CJK UNIFIED IDEOGRAPH + 0xC485: 0x81AE, //CJK UNIFIED IDEOGRAPH + 0xC486: 0x81AF, //CJK UNIFIED IDEOGRAPH + 0xC487: 0x81B0, //CJK UNIFIED IDEOGRAPH + 0xC488: 0x81B1, //CJK UNIFIED IDEOGRAPH + 0xC489: 0x81B2, //CJK UNIFIED IDEOGRAPH + 0xC48A: 0x81B4, //CJK UNIFIED IDEOGRAPH + 0xC48B: 0x81B5, //CJK UNIFIED IDEOGRAPH + 0xC48C: 0x81B6, //CJK UNIFIED IDEOGRAPH + 0xC48D: 0x81B7, //CJK UNIFIED IDEOGRAPH + 0xC48E: 0x81B8, //CJK UNIFIED IDEOGRAPH + 0xC48F: 0x81B9, //CJK UNIFIED IDEOGRAPH + 0xC490: 0x81BC, //CJK UNIFIED IDEOGRAPH + 0xC491: 0x81BD, //CJK UNIFIED IDEOGRAPH + 0xC492: 0x81BE, //CJK UNIFIED IDEOGRAPH + 0xC493: 0x81BF, //CJK UNIFIED IDEOGRAPH + 0xC494: 0x81C4, //CJK UNIFIED IDEOGRAPH + 0xC495: 0x81C5, //CJK UNIFIED IDEOGRAPH + 0xC496: 0x81C7, //CJK UNIFIED IDEOGRAPH + 0xC497: 0x81C8, //CJK UNIFIED IDEOGRAPH + 0xC498: 0x81C9, //CJK UNIFIED IDEOGRAPH + 0xC499: 0x81CB, //CJK UNIFIED IDEOGRAPH + 0xC49A: 0x81CD, //CJK UNIFIED IDEOGRAPH + 0xC49B: 0x81CE, //CJK UNIFIED IDEOGRAPH + 0xC49C: 0x81CF, //CJK UNIFIED IDEOGRAPH + 0xC49D: 0x81D0, //CJK UNIFIED IDEOGRAPH + 0xC49E: 0x81D1, //CJK UNIFIED IDEOGRAPH + 0xC49F: 0x81D2, //CJK UNIFIED IDEOGRAPH + 0xC4A0: 0x81D3, //CJK UNIFIED IDEOGRAPH + 0xC4A1: 0x6479, //CJK UNIFIED IDEOGRAPH + 0xC4A2: 0x8611, //CJK UNIFIED IDEOGRAPH + 0xC4A3: 0x6A21, //CJK UNIFIED IDEOGRAPH + 0xC4A4: 0x819C, //CJK UNIFIED IDEOGRAPH + 0xC4A5: 0x78E8, //CJK UNIFIED IDEOGRAPH + 0xC4A6: 0x6469, //CJK UNIFIED IDEOGRAPH + 0xC4A7: 0x9B54, //CJK UNIFIED IDEOGRAPH + 0xC4A8: 0x62B9, //CJK UNIFIED IDEOGRAPH + 0xC4A9: 0x672B, //CJK UNIFIED IDEOGRAPH + 0xC4AA: 0x83AB, //CJK UNIFIED IDEOGRAPH + 0xC4AB: 0x58A8, //CJK UNIFIED IDEOGRAPH + 0xC4AC: 0x9ED8, //CJK UNIFIED IDEOGRAPH + 0xC4AD: 0x6CAB, //CJK UNIFIED IDEOGRAPH + 0xC4AE: 0x6F20, //CJK UNIFIED IDEOGRAPH + 0xC4AF: 0x5BDE, //CJK UNIFIED IDEOGRAPH + 0xC4B0: 0x964C, //CJK UNIFIED IDEOGRAPH + 0xC4B1: 0x8C0B, //CJK UNIFIED IDEOGRAPH + 0xC4B2: 0x725F, //CJK UNIFIED IDEOGRAPH + 0xC4B3: 0x67D0, //CJK UNIFIED IDEOGRAPH + 0xC4B4: 0x62C7, //CJK UNIFIED IDEOGRAPH + 0xC4B5: 0x7261, //CJK UNIFIED IDEOGRAPH + 0xC4B6: 0x4EA9, //CJK UNIFIED IDEOGRAPH + 0xC4B7: 0x59C6, //CJK UNIFIED IDEOGRAPH + 0xC4B8: 0x6BCD, //CJK UNIFIED IDEOGRAPH + 0xC4B9: 0x5893, //CJK UNIFIED IDEOGRAPH + 0xC4BA: 0x66AE, //CJK UNIFIED IDEOGRAPH + 0xC4BB: 0x5E55, //CJK UNIFIED IDEOGRAPH + 0xC4BC: 0x52DF, //CJK UNIFIED IDEOGRAPH + 0xC4BD: 0x6155, //CJK UNIFIED IDEOGRAPH + 0xC4BE: 0x6728, //CJK UNIFIED IDEOGRAPH + 0xC4BF: 0x76EE, //CJK UNIFIED IDEOGRAPH + 0xC4C0: 0x7766, //CJK UNIFIED IDEOGRAPH + 0xC4C1: 0x7267, //CJK UNIFIED IDEOGRAPH + 0xC4C2: 0x7A46, //CJK UNIFIED IDEOGRAPH + 0xC4C3: 0x62FF, //CJK UNIFIED IDEOGRAPH + 0xC4C4: 0x54EA, //CJK UNIFIED IDEOGRAPH + 0xC4C5: 0x5450, //CJK UNIFIED IDEOGRAPH + 0xC4C6: 0x94A0, //CJK UNIFIED IDEOGRAPH + 0xC4C7: 0x90A3, //CJK UNIFIED IDEOGRAPH + 0xC4C8: 0x5A1C, //CJK UNIFIED IDEOGRAPH + 0xC4C9: 0x7EB3, //CJK UNIFIED IDEOGRAPH + 0xC4CA: 0x6C16, //CJK UNIFIED IDEOGRAPH + 0xC4CB: 0x4E43, //CJK UNIFIED IDEOGRAPH + 0xC4CC: 0x5976, //CJK UNIFIED IDEOGRAPH + 0xC4CD: 0x8010, //CJK UNIFIED IDEOGRAPH + 0xC4CE: 0x5948, //CJK UNIFIED IDEOGRAPH + 0xC4CF: 0x5357, //CJK UNIFIED IDEOGRAPH + 0xC4D0: 0x7537, //CJK UNIFIED IDEOGRAPH + 0xC4D1: 0x96BE, //CJK UNIFIED IDEOGRAPH + 0xC4D2: 0x56CA, //CJK UNIFIED IDEOGRAPH + 0xC4D3: 0x6320, //CJK UNIFIED IDEOGRAPH + 0xC4D4: 0x8111, //CJK UNIFIED IDEOGRAPH + 0xC4D5: 0x607C, //CJK UNIFIED IDEOGRAPH + 0xC4D6: 0x95F9, //CJK UNIFIED IDEOGRAPH + 0xC4D7: 0x6DD6, //CJK UNIFIED IDEOGRAPH + 0xC4D8: 0x5462, //CJK UNIFIED IDEOGRAPH + 0xC4D9: 0x9981, //CJK UNIFIED IDEOGRAPH + 0xC4DA: 0x5185, //CJK UNIFIED IDEOGRAPH + 0xC4DB: 0x5AE9, //CJK UNIFIED IDEOGRAPH + 0xC4DC: 0x80FD, //CJK UNIFIED IDEOGRAPH + 0xC4DD: 0x59AE, //CJK UNIFIED IDEOGRAPH + 0xC4DE: 0x9713, //CJK UNIFIED IDEOGRAPH + 0xC4DF: 0x502A, //CJK UNIFIED IDEOGRAPH + 0xC4E0: 0x6CE5, //CJK UNIFIED IDEOGRAPH + 0xC4E1: 0x5C3C, //CJK UNIFIED IDEOGRAPH + 0xC4E2: 0x62DF, //CJK UNIFIED IDEOGRAPH + 0xC4E3: 0x4F60, //CJK UNIFIED IDEOGRAPH + 0xC4E4: 0x533F, //CJK UNIFIED IDEOGRAPH + 0xC4E5: 0x817B, //CJK UNIFIED IDEOGRAPH + 0xC4E6: 0x9006, //CJK UNIFIED IDEOGRAPH + 0xC4E7: 0x6EBA, //CJK UNIFIED IDEOGRAPH + 0xC4E8: 0x852B, //CJK UNIFIED IDEOGRAPH + 0xC4E9: 0x62C8, //CJK UNIFIED IDEOGRAPH + 0xC4EA: 0x5E74, //CJK UNIFIED IDEOGRAPH + 0xC4EB: 0x78BE, //CJK UNIFIED IDEOGRAPH + 0xC4EC: 0x64B5, //CJK UNIFIED IDEOGRAPH + 0xC4ED: 0x637B, //CJK UNIFIED IDEOGRAPH + 0xC4EE: 0x5FF5, //CJK UNIFIED IDEOGRAPH + 0xC4EF: 0x5A18, //CJK UNIFIED IDEOGRAPH + 0xC4F0: 0x917F, //CJK UNIFIED IDEOGRAPH + 0xC4F1: 0x9E1F, //CJK UNIFIED IDEOGRAPH + 0xC4F2: 0x5C3F, //CJK UNIFIED IDEOGRAPH + 0xC4F3: 0x634F, //CJK UNIFIED IDEOGRAPH + 0xC4F4: 0x8042, //CJK UNIFIED IDEOGRAPH + 0xC4F5: 0x5B7D, //CJK UNIFIED IDEOGRAPH + 0xC4F6: 0x556E, //CJK UNIFIED IDEOGRAPH + 0xC4F7: 0x954A, //CJK UNIFIED IDEOGRAPH + 0xC4F8: 0x954D, //CJK UNIFIED IDEOGRAPH + 0xC4F9: 0x6D85, //CJK UNIFIED IDEOGRAPH + 0xC4FA: 0x60A8, //CJK UNIFIED IDEOGRAPH + 0xC4FB: 0x67E0, //CJK UNIFIED IDEOGRAPH + 0xC4FC: 0x72DE, //CJK UNIFIED IDEOGRAPH + 0xC4FD: 0x51DD, //CJK UNIFIED IDEOGRAPH + 0xC4FE: 0x5B81, //CJK UNIFIED IDEOGRAPH + 0xC540: 0x81D4, //CJK UNIFIED IDEOGRAPH + 0xC541: 0x81D5, //CJK UNIFIED IDEOGRAPH + 0xC542: 0x81D6, //CJK UNIFIED IDEOGRAPH + 0xC543: 0x81D7, //CJK UNIFIED IDEOGRAPH + 0xC544: 0x81D8, //CJK UNIFIED IDEOGRAPH + 0xC545: 0x81D9, //CJK UNIFIED IDEOGRAPH + 0xC546: 0x81DA, //CJK UNIFIED IDEOGRAPH + 0xC547: 0x81DB, //CJK UNIFIED IDEOGRAPH + 0xC548: 0x81DC, //CJK UNIFIED IDEOGRAPH + 0xC549: 0x81DD, //CJK UNIFIED IDEOGRAPH + 0xC54A: 0x81DE, //CJK UNIFIED IDEOGRAPH + 0xC54B: 0x81DF, //CJK UNIFIED IDEOGRAPH + 0xC54C: 0x81E0, //CJK UNIFIED IDEOGRAPH + 0xC54D: 0x81E1, //CJK UNIFIED IDEOGRAPH + 0xC54E: 0x81E2, //CJK UNIFIED IDEOGRAPH + 0xC54F: 0x81E4, //CJK UNIFIED IDEOGRAPH + 0xC550: 0x81E5, //CJK UNIFIED IDEOGRAPH + 0xC551: 0x81E6, //CJK UNIFIED IDEOGRAPH + 0xC552: 0x81E8, //CJK UNIFIED IDEOGRAPH + 0xC553: 0x81E9, //CJK UNIFIED IDEOGRAPH + 0xC554: 0x81EB, //CJK UNIFIED IDEOGRAPH + 0xC555: 0x81EE, //CJK UNIFIED IDEOGRAPH + 0xC556: 0x81EF, //CJK UNIFIED IDEOGRAPH + 0xC557: 0x81F0, //CJK UNIFIED IDEOGRAPH + 0xC558: 0x81F1, //CJK UNIFIED IDEOGRAPH + 0xC559: 0x81F2, //CJK UNIFIED IDEOGRAPH + 0xC55A: 0x81F5, //CJK UNIFIED IDEOGRAPH + 0xC55B: 0x81F6, //CJK UNIFIED IDEOGRAPH + 0xC55C: 0x81F7, //CJK UNIFIED IDEOGRAPH + 0xC55D: 0x81F8, //CJK UNIFIED IDEOGRAPH + 0xC55E: 0x81F9, //CJK UNIFIED IDEOGRAPH + 0xC55F: 0x81FA, //CJK UNIFIED IDEOGRAPH + 0xC560: 0x81FD, //CJK UNIFIED IDEOGRAPH + 0xC561: 0x81FF, //CJK UNIFIED IDEOGRAPH + 0xC562: 0x8203, //CJK UNIFIED IDEOGRAPH + 0xC563: 0x8207, //CJK UNIFIED IDEOGRAPH + 0xC564: 0x8208, //CJK UNIFIED IDEOGRAPH + 0xC565: 0x8209, //CJK UNIFIED IDEOGRAPH + 0xC566: 0x820A, //CJK UNIFIED IDEOGRAPH + 0xC567: 0x820B, //CJK UNIFIED IDEOGRAPH + 0xC568: 0x820E, //CJK UNIFIED IDEOGRAPH + 0xC569: 0x820F, //CJK UNIFIED IDEOGRAPH + 0xC56A: 0x8211, //CJK UNIFIED IDEOGRAPH + 0xC56B: 0x8213, //CJK UNIFIED IDEOGRAPH + 0xC56C: 0x8215, //CJK UNIFIED IDEOGRAPH + 0xC56D: 0x8216, //CJK UNIFIED IDEOGRAPH + 0xC56E: 0x8217, //CJK UNIFIED IDEOGRAPH + 0xC56F: 0x8218, //CJK UNIFIED IDEOGRAPH + 0xC570: 0x8219, //CJK UNIFIED IDEOGRAPH + 0xC571: 0x821A, //CJK UNIFIED IDEOGRAPH + 0xC572: 0x821D, //CJK UNIFIED IDEOGRAPH + 0xC573: 0x8220, //CJK UNIFIED IDEOGRAPH + 0xC574: 0x8224, //CJK UNIFIED IDEOGRAPH + 0xC575: 0x8225, //CJK UNIFIED IDEOGRAPH + 0xC576: 0x8226, //CJK UNIFIED IDEOGRAPH + 0xC577: 0x8227, //CJK UNIFIED IDEOGRAPH + 0xC578: 0x8229, //CJK UNIFIED IDEOGRAPH + 0xC579: 0x822E, //CJK UNIFIED IDEOGRAPH + 0xC57A: 0x8232, //CJK UNIFIED IDEOGRAPH + 0xC57B: 0x823A, //CJK UNIFIED IDEOGRAPH + 0xC57C: 0x823C, //CJK UNIFIED IDEOGRAPH + 0xC57D: 0x823D, //CJK UNIFIED IDEOGRAPH + 0xC57E: 0x823F, //CJK UNIFIED IDEOGRAPH + 0xC580: 0x8240, //CJK UNIFIED IDEOGRAPH + 0xC581: 0x8241, //CJK UNIFIED IDEOGRAPH + 0xC582: 0x8242, //CJK UNIFIED IDEOGRAPH + 0xC583: 0x8243, //CJK UNIFIED IDEOGRAPH + 0xC584: 0x8245, //CJK UNIFIED IDEOGRAPH + 0xC585: 0x8246, //CJK UNIFIED IDEOGRAPH + 0xC586: 0x8248, //CJK UNIFIED IDEOGRAPH + 0xC587: 0x824A, //CJK UNIFIED IDEOGRAPH + 0xC588: 0x824C, //CJK UNIFIED IDEOGRAPH + 0xC589: 0x824D, //CJK UNIFIED IDEOGRAPH + 0xC58A: 0x824E, //CJK UNIFIED IDEOGRAPH + 0xC58B: 0x8250, //CJK UNIFIED IDEOGRAPH + 0xC58C: 0x8251, //CJK UNIFIED IDEOGRAPH + 0xC58D: 0x8252, //CJK UNIFIED IDEOGRAPH + 0xC58E: 0x8253, //CJK UNIFIED IDEOGRAPH + 0xC58F: 0x8254, //CJK UNIFIED IDEOGRAPH + 0xC590: 0x8255, //CJK UNIFIED IDEOGRAPH + 0xC591: 0x8256, //CJK UNIFIED IDEOGRAPH + 0xC592: 0x8257, //CJK UNIFIED IDEOGRAPH + 0xC593: 0x8259, //CJK UNIFIED IDEOGRAPH + 0xC594: 0x825B, //CJK UNIFIED IDEOGRAPH + 0xC595: 0x825C, //CJK UNIFIED IDEOGRAPH + 0xC596: 0x825D, //CJK UNIFIED IDEOGRAPH + 0xC597: 0x825E, //CJK UNIFIED IDEOGRAPH + 0xC598: 0x8260, //CJK UNIFIED IDEOGRAPH + 0xC599: 0x8261, //CJK UNIFIED IDEOGRAPH + 0xC59A: 0x8262, //CJK UNIFIED IDEOGRAPH + 0xC59B: 0x8263, //CJK UNIFIED IDEOGRAPH + 0xC59C: 0x8264, //CJK UNIFIED IDEOGRAPH + 0xC59D: 0x8265, //CJK UNIFIED IDEOGRAPH + 0xC59E: 0x8266, //CJK UNIFIED IDEOGRAPH + 0xC59F: 0x8267, //CJK UNIFIED IDEOGRAPH + 0xC5A0: 0x8269, //CJK UNIFIED IDEOGRAPH + 0xC5A1: 0x62E7, //CJK UNIFIED IDEOGRAPH + 0xC5A2: 0x6CDE, //CJK UNIFIED IDEOGRAPH + 0xC5A3: 0x725B, //CJK UNIFIED IDEOGRAPH + 0xC5A4: 0x626D, //CJK UNIFIED IDEOGRAPH + 0xC5A5: 0x94AE, //CJK UNIFIED IDEOGRAPH + 0xC5A6: 0x7EBD, //CJK UNIFIED IDEOGRAPH + 0xC5A7: 0x8113, //CJK UNIFIED IDEOGRAPH + 0xC5A8: 0x6D53, //CJK UNIFIED IDEOGRAPH + 0xC5A9: 0x519C, //CJK UNIFIED IDEOGRAPH + 0xC5AA: 0x5F04, //CJK UNIFIED IDEOGRAPH + 0xC5AB: 0x5974, //CJK UNIFIED IDEOGRAPH + 0xC5AC: 0x52AA, //CJK UNIFIED IDEOGRAPH + 0xC5AD: 0x6012, //CJK UNIFIED IDEOGRAPH + 0xC5AE: 0x5973, //CJK UNIFIED IDEOGRAPH + 0xC5AF: 0x6696, //CJK UNIFIED IDEOGRAPH + 0xC5B0: 0x8650, //CJK UNIFIED IDEOGRAPH + 0xC5B1: 0x759F, //CJK UNIFIED IDEOGRAPH + 0xC5B2: 0x632A, //CJK UNIFIED IDEOGRAPH + 0xC5B3: 0x61E6, //CJK UNIFIED IDEOGRAPH + 0xC5B4: 0x7CEF, //CJK UNIFIED IDEOGRAPH + 0xC5B5: 0x8BFA, //CJK UNIFIED IDEOGRAPH + 0xC5B6: 0x54E6, //CJK UNIFIED IDEOGRAPH + 0xC5B7: 0x6B27, //CJK UNIFIED IDEOGRAPH + 0xC5B8: 0x9E25, //CJK UNIFIED IDEOGRAPH + 0xC5B9: 0x6BB4, //CJK UNIFIED IDEOGRAPH + 0xC5BA: 0x85D5, //CJK UNIFIED IDEOGRAPH + 0xC5BB: 0x5455, //CJK UNIFIED IDEOGRAPH + 0xC5BC: 0x5076, //CJK UNIFIED IDEOGRAPH + 0xC5BD: 0x6CA4, //CJK UNIFIED IDEOGRAPH + 0xC5BE: 0x556A, //CJK UNIFIED IDEOGRAPH + 0xC5BF: 0x8DB4, //CJK UNIFIED IDEOGRAPH + 0xC5C0: 0x722C, //CJK UNIFIED IDEOGRAPH + 0xC5C1: 0x5E15, //CJK UNIFIED IDEOGRAPH + 0xC5C2: 0x6015, //CJK UNIFIED IDEOGRAPH + 0xC5C3: 0x7436, //CJK UNIFIED IDEOGRAPH + 0xC5C4: 0x62CD, //CJK UNIFIED IDEOGRAPH + 0xC5C5: 0x6392, //CJK UNIFIED IDEOGRAPH + 0xC5C6: 0x724C, //CJK UNIFIED IDEOGRAPH + 0xC5C7: 0x5F98, //CJK UNIFIED IDEOGRAPH + 0xC5C8: 0x6E43, //CJK UNIFIED IDEOGRAPH + 0xC5C9: 0x6D3E, //CJK UNIFIED IDEOGRAPH + 0xC5CA: 0x6500, //CJK UNIFIED IDEOGRAPH + 0xC5CB: 0x6F58, //CJK UNIFIED IDEOGRAPH + 0xC5CC: 0x76D8, //CJK UNIFIED IDEOGRAPH + 0xC5CD: 0x78D0, //CJK UNIFIED IDEOGRAPH + 0xC5CE: 0x76FC, //CJK UNIFIED IDEOGRAPH + 0xC5CF: 0x7554, //CJK UNIFIED IDEOGRAPH + 0xC5D0: 0x5224, //CJK UNIFIED IDEOGRAPH + 0xC5D1: 0x53DB, //CJK UNIFIED IDEOGRAPH + 0xC5D2: 0x4E53, //CJK UNIFIED IDEOGRAPH + 0xC5D3: 0x5E9E, //CJK UNIFIED IDEOGRAPH + 0xC5D4: 0x65C1, //CJK UNIFIED IDEOGRAPH + 0xC5D5: 0x802A, //CJK UNIFIED IDEOGRAPH + 0xC5D6: 0x80D6, //CJK UNIFIED IDEOGRAPH + 0xC5D7: 0x629B, //CJK UNIFIED IDEOGRAPH + 0xC5D8: 0x5486, //CJK UNIFIED IDEOGRAPH + 0xC5D9: 0x5228, //CJK UNIFIED IDEOGRAPH + 0xC5DA: 0x70AE, //CJK UNIFIED IDEOGRAPH + 0xC5DB: 0x888D, //CJK UNIFIED IDEOGRAPH + 0xC5DC: 0x8DD1, //CJK UNIFIED IDEOGRAPH + 0xC5DD: 0x6CE1, //CJK UNIFIED IDEOGRAPH + 0xC5DE: 0x5478, //CJK UNIFIED IDEOGRAPH + 0xC5DF: 0x80DA, //CJK UNIFIED IDEOGRAPH + 0xC5E0: 0x57F9, //CJK UNIFIED IDEOGRAPH + 0xC5E1: 0x88F4, //CJK UNIFIED IDEOGRAPH + 0xC5E2: 0x8D54, //CJK UNIFIED IDEOGRAPH + 0xC5E3: 0x966A, //CJK UNIFIED IDEOGRAPH + 0xC5E4: 0x914D, //CJK UNIFIED IDEOGRAPH + 0xC5E5: 0x4F69, //CJK UNIFIED IDEOGRAPH + 0xC5E6: 0x6C9B, //CJK UNIFIED IDEOGRAPH + 0xC5E7: 0x55B7, //CJK UNIFIED IDEOGRAPH + 0xC5E8: 0x76C6, //CJK UNIFIED IDEOGRAPH + 0xC5E9: 0x7830, //CJK UNIFIED IDEOGRAPH + 0xC5EA: 0x62A8, //CJK UNIFIED IDEOGRAPH + 0xC5EB: 0x70F9, //CJK UNIFIED IDEOGRAPH + 0xC5EC: 0x6F8E, //CJK UNIFIED IDEOGRAPH + 0xC5ED: 0x5F6D, //CJK UNIFIED IDEOGRAPH + 0xC5EE: 0x84EC, //CJK UNIFIED IDEOGRAPH + 0xC5EF: 0x68DA, //CJK UNIFIED IDEOGRAPH + 0xC5F0: 0x787C, //CJK UNIFIED IDEOGRAPH + 0xC5F1: 0x7BF7, //CJK UNIFIED IDEOGRAPH + 0xC5F2: 0x81A8, //CJK UNIFIED IDEOGRAPH + 0xC5F3: 0x670B, //CJK UNIFIED IDEOGRAPH + 0xC5F4: 0x9E4F, //CJK UNIFIED IDEOGRAPH + 0xC5F5: 0x6367, //CJK UNIFIED IDEOGRAPH + 0xC5F6: 0x78B0, //CJK UNIFIED IDEOGRAPH + 0xC5F7: 0x576F, //CJK UNIFIED IDEOGRAPH + 0xC5F8: 0x7812, //CJK UNIFIED IDEOGRAPH + 0xC5F9: 0x9739, //CJK UNIFIED IDEOGRAPH + 0xC5FA: 0x6279, //CJK UNIFIED IDEOGRAPH + 0xC5FB: 0x62AB, //CJK UNIFIED IDEOGRAPH + 0xC5FC: 0x5288, //CJK UNIFIED IDEOGRAPH + 0xC5FD: 0x7435, //CJK UNIFIED IDEOGRAPH + 0xC5FE: 0x6BD7, //CJK UNIFIED IDEOGRAPH + 0xC640: 0x826A, //CJK UNIFIED IDEOGRAPH + 0xC641: 0x826B, //CJK UNIFIED IDEOGRAPH + 0xC642: 0x826C, //CJK UNIFIED IDEOGRAPH + 0xC643: 0x826D, //CJK UNIFIED IDEOGRAPH + 0xC644: 0x8271, //CJK UNIFIED IDEOGRAPH + 0xC645: 0x8275, //CJK UNIFIED IDEOGRAPH + 0xC646: 0x8276, //CJK UNIFIED IDEOGRAPH + 0xC647: 0x8277, //CJK UNIFIED IDEOGRAPH + 0xC648: 0x8278, //CJK UNIFIED IDEOGRAPH + 0xC649: 0x827B, //CJK UNIFIED IDEOGRAPH + 0xC64A: 0x827C, //CJK UNIFIED IDEOGRAPH + 0xC64B: 0x8280, //CJK UNIFIED IDEOGRAPH + 0xC64C: 0x8281, //CJK UNIFIED IDEOGRAPH + 0xC64D: 0x8283, //CJK UNIFIED IDEOGRAPH + 0xC64E: 0x8285, //CJK UNIFIED IDEOGRAPH + 0xC64F: 0x8286, //CJK UNIFIED IDEOGRAPH + 0xC650: 0x8287, //CJK UNIFIED IDEOGRAPH + 0xC651: 0x8289, //CJK UNIFIED IDEOGRAPH + 0xC652: 0x828C, //CJK UNIFIED IDEOGRAPH + 0xC653: 0x8290, //CJK UNIFIED IDEOGRAPH + 0xC654: 0x8293, //CJK UNIFIED IDEOGRAPH + 0xC655: 0x8294, //CJK UNIFIED IDEOGRAPH + 0xC656: 0x8295, //CJK UNIFIED IDEOGRAPH + 0xC657: 0x8296, //CJK UNIFIED IDEOGRAPH + 0xC658: 0x829A, //CJK UNIFIED IDEOGRAPH + 0xC659: 0x829B, //CJK UNIFIED IDEOGRAPH + 0xC65A: 0x829E, //CJK UNIFIED IDEOGRAPH + 0xC65B: 0x82A0, //CJK UNIFIED IDEOGRAPH + 0xC65C: 0x82A2, //CJK UNIFIED IDEOGRAPH + 0xC65D: 0x82A3, //CJK UNIFIED IDEOGRAPH + 0xC65E: 0x82A7, //CJK UNIFIED IDEOGRAPH + 0xC65F: 0x82B2, //CJK UNIFIED IDEOGRAPH + 0xC660: 0x82B5, //CJK UNIFIED IDEOGRAPH + 0xC661: 0x82B6, //CJK UNIFIED IDEOGRAPH + 0xC662: 0x82BA, //CJK UNIFIED IDEOGRAPH + 0xC663: 0x82BB, //CJK UNIFIED IDEOGRAPH + 0xC664: 0x82BC, //CJK UNIFIED IDEOGRAPH + 0xC665: 0x82BF, //CJK UNIFIED IDEOGRAPH + 0xC666: 0x82C0, //CJK UNIFIED IDEOGRAPH + 0xC667: 0x82C2, //CJK UNIFIED IDEOGRAPH + 0xC668: 0x82C3, //CJK UNIFIED IDEOGRAPH + 0xC669: 0x82C5, //CJK UNIFIED IDEOGRAPH + 0xC66A: 0x82C6, //CJK UNIFIED IDEOGRAPH + 0xC66B: 0x82C9, //CJK UNIFIED IDEOGRAPH + 0xC66C: 0x82D0, //CJK UNIFIED IDEOGRAPH + 0xC66D: 0x82D6, //CJK UNIFIED IDEOGRAPH + 0xC66E: 0x82D9, //CJK UNIFIED IDEOGRAPH + 0xC66F: 0x82DA, //CJK UNIFIED IDEOGRAPH + 0xC670: 0x82DD, //CJK UNIFIED IDEOGRAPH + 0xC671: 0x82E2, //CJK UNIFIED IDEOGRAPH + 0xC672: 0x82E7, //CJK UNIFIED IDEOGRAPH + 0xC673: 0x82E8, //CJK UNIFIED IDEOGRAPH + 0xC674: 0x82E9, //CJK UNIFIED IDEOGRAPH + 0xC675: 0x82EA, //CJK UNIFIED IDEOGRAPH + 0xC676: 0x82EC, //CJK UNIFIED IDEOGRAPH + 0xC677: 0x82ED, //CJK UNIFIED IDEOGRAPH + 0xC678: 0x82EE, //CJK UNIFIED IDEOGRAPH + 0xC679: 0x82F0, //CJK UNIFIED IDEOGRAPH + 0xC67A: 0x82F2, //CJK UNIFIED IDEOGRAPH + 0xC67B: 0x82F3, //CJK UNIFIED IDEOGRAPH + 0xC67C: 0x82F5, //CJK UNIFIED IDEOGRAPH + 0xC67D: 0x82F6, //CJK UNIFIED IDEOGRAPH + 0xC67E: 0x82F8, //CJK UNIFIED IDEOGRAPH + 0xC680: 0x82FA, //CJK UNIFIED IDEOGRAPH + 0xC681: 0x82FC, //CJK UNIFIED IDEOGRAPH + 0xC682: 0x82FD, //CJK UNIFIED IDEOGRAPH + 0xC683: 0x82FE, //CJK UNIFIED IDEOGRAPH + 0xC684: 0x82FF, //CJK UNIFIED IDEOGRAPH + 0xC685: 0x8300, //CJK UNIFIED IDEOGRAPH + 0xC686: 0x830A, //CJK UNIFIED IDEOGRAPH + 0xC687: 0x830B, //CJK UNIFIED IDEOGRAPH + 0xC688: 0x830D, //CJK UNIFIED IDEOGRAPH + 0xC689: 0x8310, //CJK UNIFIED IDEOGRAPH + 0xC68A: 0x8312, //CJK UNIFIED IDEOGRAPH + 0xC68B: 0x8313, //CJK UNIFIED IDEOGRAPH + 0xC68C: 0x8316, //CJK UNIFIED IDEOGRAPH + 0xC68D: 0x8318, //CJK UNIFIED IDEOGRAPH + 0xC68E: 0x8319, //CJK UNIFIED IDEOGRAPH + 0xC68F: 0x831D, //CJK UNIFIED IDEOGRAPH + 0xC690: 0x831E, //CJK UNIFIED IDEOGRAPH + 0xC691: 0x831F, //CJK UNIFIED IDEOGRAPH + 0xC692: 0x8320, //CJK UNIFIED IDEOGRAPH + 0xC693: 0x8321, //CJK UNIFIED IDEOGRAPH + 0xC694: 0x8322, //CJK UNIFIED IDEOGRAPH + 0xC695: 0x8323, //CJK UNIFIED IDEOGRAPH + 0xC696: 0x8324, //CJK UNIFIED IDEOGRAPH + 0xC697: 0x8325, //CJK UNIFIED IDEOGRAPH + 0xC698: 0x8326, //CJK UNIFIED IDEOGRAPH + 0xC699: 0x8329, //CJK UNIFIED IDEOGRAPH + 0xC69A: 0x832A, //CJK UNIFIED IDEOGRAPH + 0xC69B: 0x832E, //CJK UNIFIED IDEOGRAPH + 0xC69C: 0x8330, //CJK UNIFIED IDEOGRAPH + 0xC69D: 0x8332, //CJK UNIFIED IDEOGRAPH + 0xC69E: 0x8337, //CJK UNIFIED IDEOGRAPH + 0xC69F: 0x833B, //CJK UNIFIED IDEOGRAPH + 0xC6A0: 0x833D, //CJK UNIFIED IDEOGRAPH + 0xC6A1: 0x5564, //CJK UNIFIED IDEOGRAPH + 0xC6A2: 0x813E, //CJK UNIFIED IDEOGRAPH + 0xC6A3: 0x75B2, //CJK UNIFIED IDEOGRAPH + 0xC6A4: 0x76AE, //CJK UNIFIED IDEOGRAPH + 0xC6A5: 0x5339, //CJK UNIFIED IDEOGRAPH + 0xC6A6: 0x75DE, //CJK UNIFIED IDEOGRAPH + 0xC6A7: 0x50FB, //CJK UNIFIED IDEOGRAPH + 0xC6A8: 0x5C41, //CJK UNIFIED IDEOGRAPH + 0xC6A9: 0x8B6C, //CJK UNIFIED IDEOGRAPH + 0xC6AA: 0x7BC7, //CJK UNIFIED IDEOGRAPH + 0xC6AB: 0x504F, //CJK UNIFIED IDEOGRAPH + 0xC6AC: 0x7247, //CJK UNIFIED IDEOGRAPH + 0xC6AD: 0x9A97, //CJK UNIFIED IDEOGRAPH + 0xC6AE: 0x98D8, //CJK UNIFIED IDEOGRAPH + 0xC6AF: 0x6F02, //CJK UNIFIED IDEOGRAPH + 0xC6B0: 0x74E2, //CJK UNIFIED IDEOGRAPH + 0xC6B1: 0x7968, //CJK UNIFIED IDEOGRAPH + 0xC6B2: 0x6487, //CJK UNIFIED IDEOGRAPH + 0xC6B3: 0x77A5, //CJK UNIFIED IDEOGRAPH + 0xC6B4: 0x62FC, //CJK UNIFIED IDEOGRAPH + 0xC6B5: 0x9891, //CJK UNIFIED IDEOGRAPH + 0xC6B6: 0x8D2B, //CJK UNIFIED IDEOGRAPH + 0xC6B7: 0x54C1, //CJK UNIFIED IDEOGRAPH + 0xC6B8: 0x8058, //CJK UNIFIED IDEOGRAPH + 0xC6B9: 0x4E52, //CJK UNIFIED IDEOGRAPH + 0xC6BA: 0x576A, //CJK UNIFIED IDEOGRAPH + 0xC6BB: 0x82F9, //CJK UNIFIED IDEOGRAPH + 0xC6BC: 0x840D, //CJK UNIFIED IDEOGRAPH + 0xC6BD: 0x5E73, //CJK UNIFIED IDEOGRAPH + 0xC6BE: 0x51ED, //CJK UNIFIED IDEOGRAPH + 0xC6BF: 0x74F6, //CJK UNIFIED IDEOGRAPH + 0xC6C0: 0x8BC4, //CJK UNIFIED IDEOGRAPH + 0xC6C1: 0x5C4F, //CJK UNIFIED IDEOGRAPH + 0xC6C2: 0x5761, //CJK UNIFIED IDEOGRAPH + 0xC6C3: 0x6CFC, //CJK UNIFIED IDEOGRAPH + 0xC6C4: 0x9887, //CJK UNIFIED IDEOGRAPH + 0xC6C5: 0x5A46, //CJK UNIFIED IDEOGRAPH + 0xC6C6: 0x7834, //CJK UNIFIED IDEOGRAPH + 0xC6C7: 0x9B44, //CJK UNIFIED IDEOGRAPH + 0xC6C8: 0x8FEB, //CJK UNIFIED IDEOGRAPH + 0xC6C9: 0x7C95, //CJK UNIFIED IDEOGRAPH + 0xC6CA: 0x5256, //CJK UNIFIED IDEOGRAPH + 0xC6CB: 0x6251, //CJK UNIFIED IDEOGRAPH + 0xC6CC: 0x94FA, //CJK UNIFIED IDEOGRAPH + 0xC6CD: 0x4EC6, //CJK UNIFIED IDEOGRAPH + 0xC6CE: 0x8386, //CJK UNIFIED IDEOGRAPH + 0xC6CF: 0x8461, //CJK UNIFIED IDEOGRAPH + 0xC6D0: 0x83E9, //CJK UNIFIED IDEOGRAPH + 0xC6D1: 0x84B2, //CJK UNIFIED IDEOGRAPH + 0xC6D2: 0x57D4, //CJK UNIFIED IDEOGRAPH + 0xC6D3: 0x6734, //CJK UNIFIED IDEOGRAPH + 0xC6D4: 0x5703, //CJK UNIFIED IDEOGRAPH + 0xC6D5: 0x666E, //CJK UNIFIED IDEOGRAPH + 0xC6D6: 0x6D66, //CJK UNIFIED IDEOGRAPH + 0xC6D7: 0x8C31, //CJK UNIFIED IDEOGRAPH + 0xC6D8: 0x66DD, //CJK UNIFIED IDEOGRAPH + 0xC6D9: 0x7011, //CJK UNIFIED IDEOGRAPH + 0xC6DA: 0x671F, //CJK UNIFIED IDEOGRAPH + 0xC6DB: 0x6B3A, //CJK UNIFIED IDEOGRAPH + 0xC6DC: 0x6816, //CJK UNIFIED IDEOGRAPH + 0xC6DD: 0x621A, //CJK UNIFIED IDEOGRAPH + 0xC6DE: 0x59BB, //CJK UNIFIED IDEOGRAPH + 0xC6DF: 0x4E03, //CJK UNIFIED IDEOGRAPH + 0xC6E0: 0x51C4, //CJK UNIFIED IDEOGRAPH + 0xC6E1: 0x6F06, //CJK UNIFIED IDEOGRAPH + 0xC6E2: 0x67D2, //CJK UNIFIED IDEOGRAPH + 0xC6E3: 0x6C8F, //CJK UNIFIED IDEOGRAPH + 0xC6E4: 0x5176, //CJK UNIFIED IDEOGRAPH + 0xC6E5: 0x68CB, //CJK UNIFIED IDEOGRAPH + 0xC6E6: 0x5947, //CJK UNIFIED IDEOGRAPH + 0xC6E7: 0x6B67, //CJK UNIFIED IDEOGRAPH + 0xC6E8: 0x7566, //CJK UNIFIED IDEOGRAPH + 0xC6E9: 0x5D0E, //CJK UNIFIED IDEOGRAPH + 0xC6EA: 0x8110, //CJK UNIFIED IDEOGRAPH + 0xC6EB: 0x9F50, //CJK UNIFIED IDEOGRAPH + 0xC6EC: 0x65D7, //CJK UNIFIED IDEOGRAPH + 0xC6ED: 0x7948, //CJK UNIFIED IDEOGRAPH + 0xC6EE: 0x7941, //CJK UNIFIED IDEOGRAPH + 0xC6EF: 0x9A91, //CJK UNIFIED IDEOGRAPH + 0xC6F0: 0x8D77, //CJK UNIFIED IDEOGRAPH + 0xC6F1: 0x5C82, //CJK UNIFIED IDEOGRAPH + 0xC6F2: 0x4E5E, //CJK UNIFIED IDEOGRAPH + 0xC6F3: 0x4F01, //CJK UNIFIED IDEOGRAPH + 0xC6F4: 0x542F, //CJK UNIFIED IDEOGRAPH + 0xC6F5: 0x5951, //CJK UNIFIED IDEOGRAPH + 0xC6F6: 0x780C, //CJK UNIFIED IDEOGRAPH + 0xC6F7: 0x5668, //CJK UNIFIED IDEOGRAPH + 0xC6F8: 0x6C14, //CJK UNIFIED IDEOGRAPH + 0xC6F9: 0x8FC4, //CJK UNIFIED IDEOGRAPH + 0xC6FA: 0x5F03, //CJK UNIFIED IDEOGRAPH + 0xC6FB: 0x6C7D, //CJK UNIFIED IDEOGRAPH + 0xC6FC: 0x6CE3, //CJK UNIFIED IDEOGRAPH + 0xC6FD: 0x8BAB, //CJK UNIFIED IDEOGRAPH + 0xC6FE: 0x6390, //CJK UNIFIED IDEOGRAPH + 0xC740: 0x833E, //CJK UNIFIED IDEOGRAPH + 0xC741: 0x833F, //CJK UNIFIED IDEOGRAPH + 0xC742: 0x8341, //CJK UNIFIED IDEOGRAPH + 0xC743: 0x8342, //CJK UNIFIED IDEOGRAPH + 0xC744: 0x8344, //CJK UNIFIED IDEOGRAPH + 0xC745: 0x8345, //CJK UNIFIED IDEOGRAPH + 0xC746: 0x8348, //CJK UNIFIED IDEOGRAPH + 0xC747: 0x834A, //CJK UNIFIED IDEOGRAPH + 0xC748: 0x834B, //CJK UNIFIED IDEOGRAPH + 0xC749: 0x834C, //CJK UNIFIED IDEOGRAPH + 0xC74A: 0x834D, //CJK UNIFIED IDEOGRAPH + 0xC74B: 0x834E, //CJK UNIFIED IDEOGRAPH + 0xC74C: 0x8353, //CJK UNIFIED IDEOGRAPH + 0xC74D: 0x8355, //CJK UNIFIED IDEOGRAPH + 0xC74E: 0x8356, //CJK UNIFIED IDEOGRAPH + 0xC74F: 0x8357, //CJK UNIFIED IDEOGRAPH + 0xC750: 0x8358, //CJK UNIFIED IDEOGRAPH + 0xC751: 0x8359, //CJK UNIFIED IDEOGRAPH + 0xC752: 0x835D, //CJK UNIFIED IDEOGRAPH + 0xC753: 0x8362, //CJK UNIFIED IDEOGRAPH + 0xC754: 0x8370, //CJK UNIFIED IDEOGRAPH + 0xC755: 0x8371, //CJK UNIFIED IDEOGRAPH + 0xC756: 0x8372, //CJK UNIFIED IDEOGRAPH + 0xC757: 0x8373, //CJK UNIFIED IDEOGRAPH + 0xC758: 0x8374, //CJK UNIFIED IDEOGRAPH + 0xC759: 0x8375, //CJK UNIFIED IDEOGRAPH + 0xC75A: 0x8376, //CJK UNIFIED IDEOGRAPH + 0xC75B: 0x8379, //CJK UNIFIED IDEOGRAPH + 0xC75C: 0x837A, //CJK UNIFIED IDEOGRAPH + 0xC75D: 0x837E, //CJK UNIFIED IDEOGRAPH + 0xC75E: 0x837F, //CJK UNIFIED IDEOGRAPH + 0xC75F: 0x8380, //CJK UNIFIED IDEOGRAPH + 0xC760: 0x8381, //CJK UNIFIED IDEOGRAPH + 0xC761: 0x8382, //CJK UNIFIED IDEOGRAPH + 0xC762: 0x8383, //CJK UNIFIED IDEOGRAPH + 0xC763: 0x8384, //CJK UNIFIED IDEOGRAPH + 0xC764: 0x8387, //CJK UNIFIED IDEOGRAPH + 0xC765: 0x8388, //CJK UNIFIED IDEOGRAPH + 0xC766: 0x838A, //CJK UNIFIED IDEOGRAPH + 0xC767: 0x838B, //CJK UNIFIED IDEOGRAPH + 0xC768: 0x838C, //CJK UNIFIED IDEOGRAPH + 0xC769: 0x838D, //CJK UNIFIED IDEOGRAPH + 0xC76A: 0x838F, //CJK UNIFIED IDEOGRAPH + 0xC76B: 0x8390, //CJK UNIFIED IDEOGRAPH + 0xC76C: 0x8391, //CJK UNIFIED IDEOGRAPH + 0xC76D: 0x8394, //CJK UNIFIED IDEOGRAPH + 0xC76E: 0x8395, //CJK UNIFIED IDEOGRAPH + 0xC76F: 0x8396, //CJK UNIFIED IDEOGRAPH + 0xC770: 0x8397, //CJK UNIFIED IDEOGRAPH + 0xC771: 0x8399, //CJK UNIFIED IDEOGRAPH + 0xC772: 0x839A, //CJK UNIFIED IDEOGRAPH + 0xC773: 0x839D, //CJK UNIFIED IDEOGRAPH + 0xC774: 0x839F, //CJK UNIFIED IDEOGRAPH + 0xC775: 0x83A1, //CJK UNIFIED IDEOGRAPH + 0xC776: 0x83A2, //CJK UNIFIED IDEOGRAPH + 0xC777: 0x83A3, //CJK UNIFIED IDEOGRAPH + 0xC778: 0x83A4, //CJK UNIFIED IDEOGRAPH + 0xC779: 0x83A5, //CJK UNIFIED IDEOGRAPH + 0xC77A: 0x83A6, //CJK UNIFIED IDEOGRAPH + 0xC77B: 0x83A7, //CJK UNIFIED IDEOGRAPH + 0xC77C: 0x83AC, //CJK UNIFIED IDEOGRAPH + 0xC77D: 0x83AD, //CJK UNIFIED IDEOGRAPH + 0xC77E: 0x83AE, //CJK UNIFIED IDEOGRAPH + 0xC780: 0x83AF, //CJK UNIFIED IDEOGRAPH + 0xC781: 0x83B5, //CJK UNIFIED IDEOGRAPH + 0xC782: 0x83BB, //CJK UNIFIED IDEOGRAPH + 0xC783: 0x83BE, //CJK UNIFIED IDEOGRAPH + 0xC784: 0x83BF, //CJK UNIFIED IDEOGRAPH + 0xC785: 0x83C2, //CJK UNIFIED IDEOGRAPH + 0xC786: 0x83C3, //CJK UNIFIED IDEOGRAPH + 0xC787: 0x83C4, //CJK UNIFIED IDEOGRAPH + 0xC788: 0x83C6, //CJK UNIFIED IDEOGRAPH + 0xC789: 0x83C8, //CJK UNIFIED IDEOGRAPH + 0xC78A: 0x83C9, //CJK UNIFIED IDEOGRAPH + 0xC78B: 0x83CB, //CJK UNIFIED IDEOGRAPH + 0xC78C: 0x83CD, //CJK UNIFIED IDEOGRAPH + 0xC78D: 0x83CE, //CJK UNIFIED IDEOGRAPH + 0xC78E: 0x83D0, //CJK UNIFIED IDEOGRAPH + 0xC78F: 0x83D1, //CJK UNIFIED IDEOGRAPH + 0xC790: 0x83D2, //CJK UNIFIED IDEOGRAPH + 0xC791: 0x83D3, //CJK UNIFIED IDEOGRAPH + 0xC792: 0x83D5, //CJK UNIFIED IDEOGRAPH + 0xC793: 0x83D7, //CJK UNIFIED IDEOGRAPH + 0xC794: 0x83D9, //CJK UNIFIED IDEOGRAPH + 0xC795: 0x83DA, //CJK UNIFIED IDEOGRAPH + 0xC796: 0x83DB, //CJK UNIFIED IDEOGRAPH + 0xC797: 0x83DE, //CJK UNIFIED IDEOGRAPH + 0xC798: 0x83E2, //CJK UNIFIED IDEOGRAPH + 0xC799: 0x83E3, //CJK UNIFIED IDEOGRAPH + 0xC79A: 0x83E4, //CJK UNIFIED IDEOGRAPH + 0xC79B: 0x83E6, //CJK UNIFIED IDEOGRAPH + 0xC79C: 0x83E7, //CJK UNIFIED IDEOGRAPH + 0xC79D: 0x83E8, //CJK UNIFIED IDEOGRAPH + 0xC79E: 0x83EB, //CJK UNIFIED IDEOGRAPH + 0xC79F: 0x83EC, //CJK UNIFIED IDEOGRAPH + 0xC7A0: 0x83ED, //CJK UNIFIED IDEOGRAPH + 0xC7A1: 0x6070, //CJK UNIFIED IDEOGRAPH + 0xC7A2: 0x6D3D, //CJK UNIFIED IDEOGRAPH + 0xC7A3: 0x7275, //CJK UNIFIED IDEOGRAPH + 0xC7A4: 0x6266, //CJK UNIFIED IDEOGRAPH + 0xC7A5: 0x948E, //CJK UNIFIED IDEOGRAPH + 0xC7A6: 0x94C5, //CJK UNIFIED IDEOGRAPH + 0xC7A7: 0x5343, //CJK UNIFIED IDEOGRAPH + 0xC7A8: 0x8FC1, //CJK UNIFIED IDEOGRAPH + 0xC7A9: 0x7B7E, //CJK UNIFIED IDEOGRAPH + 0xC7AA: 0x4EDF, //CJK UNIFIED IDEOGRAPH + 0xC7AB: 0x8C26, //CJK UNIFIED IDEOGRAPH + 0xC7AC: 0x4E7E, //CJK UNIFIED IDEOGRAPH + 0xC7AD: 0x9ED4, //CJK UNIFIED IDEOGRAPH + 0xC7AE: 0x94B1, //CJK UNIFIED IDEOGRAPH + 0xC7AF: 0x94B3, //CJK UNIFIED IDEOGRAPH + 0xC7B0: 0x524D, //CJK UNIFIED IDEOGRAPH + 0xC7B1: 0x6F5C, //CJK UNIFIED IDEOGRAPH + 0xC7B2: 0x9063, //CJK UNIFIED IDEOGRAPH + 0xC7B3: 0x6D45, //CJK UNIFIED IDEOGRAPH + 0xC7B4: 0x8C34, //CJK UNIFIED IDEOGRAPH + 0xC7B5: 0x5811, //CJK UNIFIED IDEOGRAPH + 0xC7B6: 0x5D4C, //CJK UNIFIED IDEOGRAPH + 0xC7B7: 0x6B20, //CJK UNIFIED IDEOGRAPH + 0xC7B8: 0x6B49, //CJK UNIFIED IDEOGRAPH + 0xC7B9: 0x67AA, //CJK UNIFIED IDEOGRAPH + 0xC7BA: 0x545B, //CJK UNIFIED IDEOGRAPH + 0xC7BB: 0x8154, //CJK UNIFIED IDEOGRAPH + 0xC7BC: 0x7F8C, //CJK UNIFIED IDEOGRAPH + 0xC7BD: 0x5899, //CJK UNIFIED IDEOGRAPH + 0xC7BE: 0x8537, //CJK UNIFIED IDEOGRAPH + 0xC7BF: 0x5F3A, //CJK UNIFIED IDEOGRAPH + 0xC7C0: 0x62A2, //CJK UNIFIED IDEOGRAPH + 0xC7C1: 0x6A47, //CJK UNIFIED IDEOGRAPH + 0xC7C2: 0x9539, //CJK UNIFIED IDEOGRAPH + 0xC7C3: 0x6572, //CJK UNIFIED IDEOGRAPH + 0xC7C4: 0x6084, //CJK UNIFIED IDEOGRAPH + 0xC7C5: 0x6865, //CJK UNIFIED IDEOGRAPH + 0xC7C6: 0x77A7, //CJK UNIFIED IDEOGRAPH + 0xC7C7: 0x4E54, //CJK UNIFIED IDEOGRAPH + 0xC7C8: 0x4FA8, //CJK UNIFIED IDEOGRAPH + 0xC7C9: 0x5DE7, //CJK UNIFIED IDEOGRAPH + 0xC7CA: 0x9798, //CJK UNIFIED IDEOGRAPH + 0xC7CB: 0x64AC, //CJK UNIFIED IDEOGRAPH + 0xC7CC: 0x7FD8, //CJK UNIFIED IDEOGRAPH + 0xC7CD: 0x5CED, //CJK UNIFIED IDEOGRAPH + 0xC7CE: 0x4FCF, //CJK UNIFIED IDEOGRAPH + 0xC7CF: 0x7A8D, //CJK UNIFIED IDEOGRAPH + 0xC7D0: 0x5207, //CJK UNIFIED IDEOGRAPH + 0xC7D1: 0x8304, //CJK UNIFIED IDEOGRAPH + 0xC7D2: 0x4E14, //CJK UNIFIED IDEOGRAPH + 0xC7D3: 0x602F, //CJK UNIFIED IDEOGRAPH + 0xC7D4: 0x7A83, //CJK UNIFIED IDEOGRAPH + 0xC7D5: 0x94A6, //CJK UNIFIED IDEOGRAPH + 0xC7D6: 0x4FB5, //CJK UNIFIED IDEOGRAPH + 0xC7D7: 0x4EB2, //CJK UNIFIED IDEOGRAPH + 0xC7D8: 0x79E6, //CJK UNIFIED IDEOGRAPH + 0xC7D9: 0x7434, //CJK UNIFIED IDEOGRAPH + 0xC7DA: 0x52E4, //CJK UNIFIED IDEOGRAPH + 0xC7DB: 0x82B9, //CJK UNIFIED IDEOGRAPH + 0xC7DC: 0x64D2, //CJK UNIFIED IDEOGRAPH + 0xC7DD: 0x79BD, //CJK UNIFIED IDEOGRAPH + 0xC7DE: 0x5BDD, //CJK UNIFIED IDEOGRAPH + 0xC7DF: 0x6C81, //CJK UNIFIED IDEOGRAPH + 0xC7E0: 0x9752, //CJK UNIFIED IDEOGRAPH + 0xC7E1: 0x8F7B, //CJK UNIFIED IDEOGRAPH + 0xC7E2: 0x6C22, //CJK UNIFIED IDEOGRAPH + 0xC7E3: 0x503E, //CJK UNIFIED IDEOGRAPH + 0xC7E4: 0x537F, //CJK UNIFIED IDEOGRAPH + 0xC7E5: 0x6E05, //CJK UNIFIED IDEOGRAPH + 0xC7E6: 0x64CE, //CJK UNIFIED IDEOGRAPH + 0xC7E7: 0x6674, //CJK UNIFIED IDEOGRAPH + 0xC7E8: 0x6C30, //CJK UNIFIED IDEOGRAPH + 0xC7E9: 0x60C5, //CJK UNIFIED IDEOGRAPH + 0xC7EA: 0x9877, //CJK UNIFIED IDEOGRAPH + 0xC7EB: 0x8BF7, //CJK UNIFIED IDEOGRAPH + 0xC7EC: 0x5E86, //CJK UNIFIED IDEOGRAPH + 0xC7ED: 0x743C, //CJK UNIFIED IDEOGRAPH + 0xC7EE: 0x7A77, //CJK UNIFIED IDEOGRAPH + 0xC7EF: 0x79CB, //CJK UNIFIED IDEOGRAPH + 0xC7F0: 0x4E18, //CJK UNIFIED IDEOGRAPH + 0xC7F1: 0x90B1, //CJK UNIFIED IDEOGRAPH + 0xC7F2: 0x7403, //CJK UNIFIED IDEOGRAPH + 0xC7F3: 0x6C42, //CJK UNIFIED IDEOGRAPH + 0xC7F4: 0x56DA, //CJK UNIFIED IDEOGRAPH + 0xC7F5: 0x914B, //CJK UNIFIED IDEOGRAPH + 0xC7F6: 0x6CC5, //CJK UNIFIED IDEOGRAPH + 0xC7F7: 0x8D8B, //CJK UNIFIED IDEOGRAPH + 0xC7F8: 0x533A, //CJK UNIFIED IDEOGRAPH + 0xC7F9: 0x86C6, //CJK UNIFIED IDEOGRAPH + 0xC7FA: 0x66F2, //CJK UNIFIED IDEOGRAPH + 0xC7FB: 0x8EAF, //CJK UNIFIED IDEOGRAPH + 0xC7FC: 0x5C48, //CJK UNIFIED IDEOGRAPH + 0xC7FD: 0x9A71, //CJK UNIFIED IDEOGRAPH + 0xC7FE: 0x6E20, //CJK UNIFIED IDEOGRAPH + 0xC840: 0x83EE, //CJK UNIFIED IDEOGRAPH + 0xC841: 0x83EF, //CJK UNIFIED IDEOGRAPH + 0xC842: 0x83F3, //CJK UNIFIED IDEOGRAPH + 0xC843: 0x83F4, //CJK UNIFIED IDEOGRAPH + 0xC844: 0x83F5, //CJK UNIFIED IDEOGRAPH + 0xC845: 0x83F6, //CJK UNIFIED IDEOGRAPH + 0xC846: 0x83F7, //CJK UNIFIED IDEOGRAPH + 0xC847: 0x83FA, //CJK UNIFIED IDEOGRAPH + 0xC848: 0x83FB, //CJK UNIFIED IDEOGRAPH + 0xC849: 0x83FC, //CJK UNIFIED IDEOGRAPH + 0xC84A: 0x83FE, //CJK UNIFIED IDEOGRAPH + 0xC84B: 0x83FF, //CJK UNIFIED IDEOGRAPH + 0xC84C: 0x8400, //CJK UNIFIED IDEOGRAPH + 0xC84D: 0x8402, //CJK UNIFIED IDEOGRAPH + 0xC84E: 0x8405, //CJK UNIFIED IDEOGRAPH + 0xC84F: 0x8407, //CJK UNIFIED IDEOGRAPH + 0xC850: 0x8408, //CJK UNIFIED IDEOGRAPH + 0xC851: 0x8409, //CJK UNIFIED IDEOGRAPH + 0xC852: 0x840A, //CJK UNIFIED IDEOGRAPH + 0xC853: 0x8410, //CJK UNIFIED IDEOGRAPH + 0xC854: 0x8412, //CJK UNIFIED IDEOGRAPH + 0xC855: 0x8413, //CJK UNIFIED IDEOGRAPH + 0xC856: 0x8414, //CJK UNIFIED IDEOGRAPH + 0xC857: 0x8415, //CJK UNIFIED IDEOGRAPH + 0xC858: 0x8416, //CJK UNIFIED IDEOGRAPH + 0xC859: 0x8417, //CJK UNIFIED IDEOGRAPH + 0xC85A: 0x8419, //CJK UNIFIED IDEOGRAPH + 0xC85B: 0x841A, //CJK UNIFIED IDEOGRAPH + 0xC85C: 0x841B, //CJK UNIFIED IDEOGRAPH + 0xC85D: 0x841E, //CJK UNIFIED IDEOGRAPH + 0xC85E: 0x841F, //CJK UNIFIED IDEOGRAPH + 0xC85F: 0x8420, //CJK UNIFIED IDEOGRAPH + 0xC860: 0x8421, //CJK UNIFIED IDEOGRAPH + 0xC861: 0x8422, //CJK UNIFIED IDEOGRAPH + 0xC862: 0x8423, //CJK UNIFIED IDEOGRAPH + 0xC863: 0x8429, //CJK UNIFIED IDEOGRAPH + 0xC864: 0x842A, //CJK UNIFIED IDEOGRAPH + 0xC865: 0x842B, //CJK UNIFIED IDEOGRAPH + 0xC866: 0x842C, //CJK UNIFIED IDEOGRAPH + 0xC867: 0x842D, //CJK UNIFIED IDEOGRAPH + 0xC868: 0x842E, //CJK UNIFIED IDEOGRAPH + 0xC869: 0x842F, //CJK UNIFIED IDEOGRAPH + 0xC86A: 0x8430, //CJK UNIFIED IDEOGRAPH + 0xC86B: 0x8432, //CJK UNIFIED IDEOGRAPH + 0xC86C: 0x8433, //CJK UNIFIED IDEOGRAPH + 0xC86D: 0x8434, //CJK UNIFIED IDEOGRAPH + 0xC86E: 0x8435, //CJK UNIFIED IDEOGRAPH + 0xC86F: 0x8436, //CJK UNIFIED IDEOGRAPH + 0xC870: 0x8437, //CJK UNIFIED IDEOGRAPH + 0xC871: 0x8439, //CJK UNIFIED IDEOGRAPH + 0xC872: 0x843A, //CJK UNIFIED IDEOGRAPH + 0xC873: 0x843B, //CJK UNIFIED IDEOGRAPH + 0xC874: 0x843E, //CJK UNIFIED IDEOGRAPH + 0xC875: 0x843F, //CJK UNIFIED IDEOGRAPH + 0xC876: 0x8440, //CJK UNIFIED IDEOGRAPH + 0xC877: 0x8441, //CJK UNIFIED IDEOGRAPH + 0xC878: 0x8442, //CJK UNIFIED IDEOGRAPH + 0xC879: 0x8443, //CJK UNIFIED IDEOGRAPH + 0xC87A: 0x8444, //CJK UNIFIED IDEOGRAPH + 0xC87B: 0x8445, //CJK UNIFIED IDEOGRAPH + 0xC87C: 0x8447, //CJK UNIFIED IDEOGRAPH + 0xC87D: 0x8448, //CJK UNIFIED IDEOGRAPH + 0xC87E: 0x8449, //CJK UNIFIED IDEOGRAPH + 0xC880: 0x844A, //CJK UNIFIED IDEOGRAPH + 0xC881: 0x844B, //CJK UNIFIED IDEOGRAPH + 0xC882: 0x844C, //CJK UNIFIED IDEOGRAPH + 0xC883: 0x844D, //CJK UNIFIED IDEOGRAPH + 0xC884: 0x844E, //CJK UNIFIED IDEOGRAPH + 0xC885: 0x844F, //CJK UNIFIED IDEOGRAPH + 0xC886: 0x8450, //CJK UNIFIED IDEOGRAPH + 0xC887: 0x8452, //CJK UNIFIED IDEOGRAPH + 0xC888: 0x8453, //CJK UNIFIED IDEOGRAPH + 0xC889: 0x8454, //CJK UNIFIED IDEOGRAPH + 0xC88A: 0x8455, //CJK UNIFIED IDEOGRAPH + 0xC88B: 0x8456, //CJK UNIFIED IDEOGRAPH + 0xC88C: 0x8458, //CJK UNIFIED IDEOGRAPH + 0xC88D: 0x845D, //CJK UNIFIED IDEOGRAPH + 0xC88E: 0x845E, //CJK UNIFIED IDEOGRAPH + 0xC88F: 0x845F, //CJK UNIFIED IDEOGRAPH + 0xC890: 0x8460, //CJK UNIFIED IDEOGRAPH + 0xC891: 0x8462, //CJK UNIFIED IDEOGRAPH + 0xC892: 0x8464, //CJK UNIFIED IDEOGRAPH + 0xC893: 0x8465, //CJK UNIFIED IDEOGRAPH + 0xC894: 0x8466, //CJK UNIFIED IDEOGRAPH + 0xC895: 0x8467, //CJK UNIFIED IDEOGRAPH + 0xC896: 0x8468, //CJK UNIFIED IDEOGRAPH + 0xC897: 0x846A, //CJK UNIFIED IDEOGRAPH + 0xC898: 0x846E, //CJK UNIFIED IDEOGRAPH + 0xC899: 0x846F, //CJK UNIFIED IDEOGRAPH + 0xC89A: 0x8470, //CJK UNIFIED IDEOGRAPH + 0xC89B: 0x8472, //CJK UNIFIED IDEOGRAPH + 0xC89C: 0x8474, //CJK UNIFIED IDEOGRAPH + 0xC89D: 0x8477, //CJK UNIFIED IDEOGRAPH + 0xC89E: 0x8479, //CJK UNIFIED IDEOGRAPH + 0xC89F: 0x847B, //CJK UNIFIED IDEOGRAPH + 0xC8A0: 0x847C, //CJK UNIFIED IDEOGRAPH + 0xC8A1: 0x53D6, //CJK UNIFIED IDEOGRAPH + 0xC8A2: 0x5A36, //CJK UNIFIED IDEOGRAPH + 0xC8A3: 0x9F8B, //CJK UNIFIED IDEOGRAPH + 0xC8A4: 0x8DA3, //CJK UNIFIED IDEOGRAPH + 0xC8A5: 0x53BB, //CJK UNIFIED IDEOGRAPH + 0xC8A6: 0x5708, //CJK UNIFIED IDEOGRAPH + 0xC8A7: 0x98A7, //CJK UNIFIED IDEOGRAPH + 0xC8A8: 0x6743, //CJK UNIFIED IDEOGRAPH + 0xC8A9: 0x919B, //CJK UNIFIED IDEOGRAPH + 0xC8AA: 0x6CC9, //CJK UNIFIED IDEOGRAPH + 0xC8AB: 0x5168, //CJK UNIFIED IDEOGRAPH + 0xC8AC: 0x75CA, //CJK UNIFIED IDEOGRAPH + 0xC8AD: 0x62F3, //CJK UNIFIED IDEOGRAPH + 0xC8AE: 0x72AC, //CJK UNIFIED IDEOGRAPH + 0xC8AF: 0x5238, //CJK UNIFIED IDEOGRAPH + 0xC8B0: 0x529D, //CJK UNIFIED IDEOGRAPH + 0xC8B1: 0x7F3A, //CJK UNIFIED IDEOGRAPH + 0xC8B2: 0x7094, //CJK UNIFIED IDEOGRAPH + 0xC8B3: 0x7638, //CJK UNIFIED IDEOGRAPH + 0xC8B4: 0x5374, //CJK UNIFIED IDEOGRAPH + 0xC8B5: 0x9E4A, //CJK UNIFIED IDEOGRAPH + 0xC8B6: 0x69B7, //CJK UNIFIED IDEOGRAPH + 0xC8B7: 0x786E, //CJK UNIFIED IDEOGRAPH + 0xC8B8: 0x96C0, //CJK UNIFIED IDEOGRAPH + 0xC8B9: 0x88D9, //CJK UNIFIED IDEOGRAPH + 0xC8BA: 0x7FA4, //CJK UNIFIED IDEOGRAPH + 0xC8BB: 0x7136, //CJK UNIFIED IDEOGRAPH + 0xC8BC: 0x71C3, //CJK UNIFIED IDEOGRAPH + 0xC8BD: 0x5189, //CJK UNIFIED IDEOGRAPH + 0xC8BE: 0x67D3, //CJK UNIFIED IDEOGRAPH + 0xC8BF: 0x74E4, //CJK UNIFIED IDEOGRAPH + 0xC8C0: 0x58E4, //CJK UNIFIED IDEOGRAPH + 0xC8C1: 0x6518, //CJK UNIFIED IDEOGRAPH + 0xC8C2: 0x56B7, //CJK UNIFIED IDEOGRAPH + 0xC8C3: 0x8BA9, //CJK UNIFIED IDEOGRAPH + 0xC8C4: 0x9976, //CJK UNIFIED IDEOGRAPH + 0xC8C5: 0x6270, //CJK UNIFIED IDEOGRAPH + 0xC8C6: 0x7ED5, //CJK UNIFIED IDEOGRAPH + 0xC8C7: 0x60F9, //CJK UNIFIED IDEOGRAPH + 0xC8C8: 0x70ED, //CJK UNIFIED IDEOGRAPH + 0xC8C9: 0x58EC, //CJK UNIFIED IDEOGRAPH + 0xC8CA: 0x4EC1, //CJK UNIFIED IDEOGRAPH + 0xC8CB: 0x4EBA, //CJK UNIFIED IDEOGRAPH + 0xC8CC: 0x5FCD, //CJK UNIFIED IDEOGRAPH + 0xC8CD: 0x97E7, //CJK UNIFIED IDEOGRAPH + 0xC8CE: 0x4EFB, //CJK UNIFIED IDEOGRAPH + 0xC8CF: 0x8BA4, //CJK UNIFIED IDEOGRAPH + 0xC8D0: 0x5203, //CJK UNIFIED IDEOGRAPH + 0xC8D1: 0x598A, //CJK UNIFIED IDEOGRAPH + 0xC8D2: 0x7EAB, //CJK UNIFIED IDEOGRAPH + 0xC8D3: 0x6254, //CJK UNIFIED IDEOGRAPH + 0xC8D4: 0x4ECD, //CJK UNIFIED IDEOGRAPH + 0xC8D5: 0x65E5, //CJK UNIFIED IDEOGRAPH + 0xC8D6: 0x620E, //CJK UNIFIED IDEOGRAPH + 0xC8D7: 0x8338, //CJK UNIFIED IDEOGRAPH + 0xC8D8: 0x84C9, //CJK UNIFIED IDEOGRAPH + 0xC8D9: 0x8363, //CJK UNIFIED IDEOGRAPH + 0xC8DA: 0x878D, //CJK UNIFIED IDEOGRAPH + 0xC8DB: 0x7194, //CJK UNIFIED IDEOGRAPH + 0xC8DC: 0x6EB6, //CJK UNIFIED IDEOGRAPH + 0xC8DD: 0x5BB9, //CJK UNIFIED IDEOGRAPH + 0xC8DE: 0x7ED2, //CJK UNIFIED IDEOGRAPH + 0xC8DF: 0x5197, //CJK UNIFIED IDEOGRAPH + 0xC8E0: 0x63C9, //CJK UNIFIED IDEOGRAPH + 0xC8E1: 0x67D4, //CJK UNIFIED IDEOGRAPH + 0xC8E2: 0x8089, //CJK UNIFIED IDEOGRAPH + 0xC8E3: 0x8339, //CJK UNIFIED IDEOGRAPH + 0xC8E4: 0x8815, //CJK UNIFIED IDEOGRAPH + 0xC8E5: 0x5112, //CJK UNIFIED IDEOGRAPH + 0xC8E6: 0x5B7A, //CJK UNIFIED IDEOGRAPH + 0xC8E7: 0x5982, //CJK UNIFIED IDEOGRAPH + 0xC8E8: 0x8FB1, //CJK UNIFIED IDEOGRAPH + 0xC8E9: 0x4E73, //CJK UNIFIED IDEOGRAPH + 0xC8EA: 0x6C5D, //CJK UNIFIED IDEOGRAPH + 0xC8EB: 0x5165, //CJK UNIFIED IDEOGRAPH + 0xC8EC: 0x8925, //CJK UNIFIED IDEOGRAPH + 0xC8ED: 0x8F6F, //CJK UNIFIED IDEOGRAPH + 0xC8EE: 0x962E, //CJK UNIFIED IDEOGRAPH + 0xC8EF: 0x854A, //CJK UNIFIED IDEOGRAPH + 0xC8F0: 0x745E, //CJK UNIFIED IDEOGRAPH + 0xC8F1: 0x9510, //CJK UNIFIED IDEOGRAPH + 0xC8F2: 0x95F0, //CJK UNIFIED IDEOGRAPH + 0xC8F3: 0x6DA6, //CJK UNIFIED IDEOGRAPH + 0xC8F4: 0x82E5, //CJK UNIFIED IDEOGRAPH + 0xC8F5: 0x5F31, //CJK UNIFIED IDEOGRAPH + 0xC8F6: 0x6492, //CJK UNIFIED IDEOGRAPH + 0xC8F7: 0x6D12, //CJK UNIFIED IDEOGRAPH + 0xC8F8: 0x8428, //CJK UNIFIED IDEOGRAPH + 0xC8F9: 0x816E, //CJK UNIFIED IDEOGRAPH + 0xC8FA: 0x9CC3, //CJK UNIFIED IDEOGRAPH + 0xC8FB: 0x585E, //CJK UNIFIED IDEOGRAPH + 0xC8FC: 0x8D5B, //CJK UNIFIED IDEOGRAPH + 0xC8FD: 0x4E09, //CJK UNIFIED IDEOGRAPH + 0xC8FE: 0x53C1, //CJK UNIFIED IDEOGRAPH + 0xC940: 0x847D, //CJK UNIFIED IDEOGRAPH + 0xC941: 0x847E, //CJK UNIFIED IDEOGRAPH + 0xC942: 0x847F, //CJK UNIFIED IDEOGRAPH + 0xC943: 0x8480, //CJK UNIFIED IDEOGRAPH + 0xC944: 0x8481, //CJK UNIFIED IDEOGRAPH + 0xC945: 0x8483, //CJK UNIFIED IDEOGRAPH + 0xC946: 0x8484, //CJK UNIFIED IDEOGRAPH + 0xC947: 0x8485, //CJK UNIFIED IDEOGRAPH + 0xC948: 0x8486, //CJK UNIFIED IDEOGRAPH + 0xC949: 0x848A, //CJK UNIFIED IDEOGRAPH + 0xC94A: 0x848D, //CJK UNIFIED IDEOGRAPH + 0xC94B: 0x848F, //CJK UNIFIED IDEOGRAPH + 0xC94C: 0x8490, //CJK UNIFIED IDEOGRAPH + 0xC94D: 0x8491, //CJK UNIFIED IDEOGRAPH + 0xC94E: 0x8492, //CJK UNIFIED IDEOGRAPH + 0xC94F: 0x8493, //CJK UNIFIED IDEOGRAPH + 0xC950: 0x8494, //CJK UNIFIED IDEOGRAPH + 0xC951: 0x8495, //CJK UNIFIED IDEOGRAPH + 0xC952: 0x8496, //CJK UNIFIED IDEOGRAPH + 0xC953: 0x8498, //CJK UNIFIED IDEOGRAPH + 0xC954: 0x849A, //CJK UNIFIED IDEOGRAPH + 0xC955: 0x849B, //CJK UNIFIED IDEOGRAPH + 0xC956: 0x849D, //CJK UNIFIED IDEOGRAPH + 0xC957: 0x849E, //CJK UNIFIED IDEOGRAPH + 0xC958: 0x849F, //CJK UNIFIED IDEOGRAPH + 0xC959: 0x84A0, //CJK UNIFIED IDEOGRAPH + 0xC95A: 0x84A2, //CJK UNIFIED IDEOGRAPH + 0xC95B: 0x84A3, //CJK UNIFIED IDEOGRAPH + 0xC95C: 0x84A4, //CJK UNIFIED IDEOGRAPH + 0xC95D: 0x84A5, //CJK UNIFIED IDEOGRAPH + 0xC95E: 0x84A6, //CJK UNIFIED IDEOGRAPH + 0xC95F: 0x84A7, //CJK UNIFIED IDEOGRAPH + 0xC960: 0x84A8, //CJK UNIFIED IDEOGRAPH + 0xC961: 0x84A9, //CJK UNIFIED IDEOGRAPH + 0xC962: 0x84AA, //CJK UNIFIED IDEOGRAPH + 0xC963: 0x84AB, //CJK UNIFIED IDEOGRAPH + 0xC964: 0x84AC, //CJK UNIFIED IDEOGRAPH + 0xC965: 0x84AD, //CJK UNIFIED IDEOGRAPH + 0xC966: 0x84AE, //CJK UNIFIED IDEOGRAPH + 0xC967: 0x84B0, //CJK UNIFIED IDEOGRAPH + 0xC968: 0x84B1, //CJK UNIFIED IDEOGRAPH + 0xC969: 0x84B3, //CJK UNIFIED IDEOGRAPH + 0xC96A: 0x84B5, //CJK UNIFIED IDEOGRAPH + 0xC96B: 0x84B6, //CJK UNIFIED IDEOGRAPH + 0xC96C: 0x84B7, //CJK UNIFIED IDEOGRAPH + 0xC96D: 0x84BB, //CJK UNIFIED IDEOGRAPH + 0xC96E: 0x84BC, //CJK UNIFIED IDEOGRAPH + 0xC96F: 0x84BE, //CJK UNIFIED IDEOGRAPH + 0xC970: 0x84C0, //CJK UNIFIED IDEOGRAPH + 0xC971: 0x84C2, //CJK UNIFIED IDEOGRAPH + 0xC972: 0x84C3, //CJK UNIFIED IDEOGRAPH + 0xC973: 0x84C5, //CJK UNIFIED IDEOGRAPH + 0xC974: 0x84C6, //CJK UNIFIED IDEOGRAPH + 0xC975: 0x84C7, //CJK UNIFIED IDEOGRAPH + 0xC976: 0x84C8, //CJK UNIFIED IDEOGRAPH + 0xC977: 0x84CB, //CJK UNIFIED IDEOGRAPH + 0xC978: 0x84CC, //CJK UNIFIED IDEOGRAPH + 0xC979: 0x84CE, //CJK UNIFIED IDEOGRAPH + 0xC97A: 0x84CF, //CJK UNIFIED IDEOGRAPH + 0xC97B: 0x84D2, //CJK UNIFIED IDEOGRAPH + 0xC97C: 0x84D4, //CJK UNIFIED IDEOGRAPH + 0xC97D: 0x84D5, //CJK UNIFIED IDEOGRAPH + 0xC97E: 0x84D7, //CJK UNIFIED IDEOGRAPH + 0xC980: 0x84D8, //CJK UNIFIED IDEOGRAPH + 0xC981: 0x84D9, //CJK UNIFIED IDEOGRAPH + 0xC982: 0x84DA, //CJK UNIFIED IDEOGRAPH + 0xC983: 0x84DB, //CJK UNIFIED IDEOGRAPH + 0xC984: 0x84DC, //CJK UNIFIED IDEOGRAPH + 0xC985: 0x84DE, //CJK UNIFIED IDEOGRAPH + 0xC986: 0x84E1, //CJK UNIFIED IDEOGRAPH + 0xC987: 0x84E2, //CJK UNIFIED IDEOGRAPH + 0xC988: 0x84E4, //CJK UNIFIED IDEOGRAPH + 0xC989: 0x84E7, //CJK UNIFIED IDEOGRAPH + 0xC98A: 0x84E8, //CJK UNIFIED IDEOGRAPH + 0xC98B: 0x84E9, //CJK UNIFIED IDEOGRAPH + 0xC98C: 0x84EA, //CJK UNIFIED IDEOGRAPH + 0xC98D: 0x84EB, //CJK UNIFIED IDEOGRAPH + 0xC98E: 0x84ED, //CJK UNIFIED IDEOGRAPH + 0xC98F: 0x84EE, //CJK UNIFIED IDEOGRAPH + 0xC990: 0x84EF, //CJK UNIFIED IDEOGRAPH + 0xC991: 0x84F1, //CJK UNIFIED IDEOGRAPH + 0xC992: 0x84F2, //CJK UNIFIED IDEOGRAPH + 0xC993: 0x84F3, //CJK UNIFIED IDEOGRAPH + 0xC994: 0x84F4, //CJK UNIFIED IDEOGRAPH + 0xC995: 0x84F5, //CJK UNIFIED IDEOGRAPH + 0xC996: 0x84F6, //CJK UNIFIED IDEOGRAPH + 0xC997: 0x84F7, //CJK UNIFIED IDEOGRAPH + 0xC998: 0x84F8, //CJK UNIFIED IDEOGRAPH + 0xC999: 0x84F9, //CJK UNIFIED IDEOGRAPH + 0xC99A: 0x84FA, //CJK UNIFIED IDEOGRAPH + 0xC99B: 0x84FB, //CJK UNIFIED IDEOGRAPH + 0xC99C: 0x84FD, //CJK UNIFIED IDEOGRAPH + 0xC99D: 0x84FE, //CJK UNIFIED IDEOGRAPH + 0xC99E: 0x8500, //CJK UNIFIED IDEOGRAPH + 0xC99F: 0x8501, //CJK UNIFIED IDEOGRAPH + 0xC9A0: 0x8502, //CJK UNIFIED IDEOGRAPH + 0xC9A1: 0x4F1E, //CJK UNIFIED IDEOGRAPH + 0xC9A2: 0x6563, //CJK UNIFIED IDEOGRAPH + 0xC9A3: 0x6851, //CJK UNIFIED IDEOGRAPH + 0xC9A4: 0x55D3, //CJK UNIFIED IDEOGRAPH + 0xC9A5: 0x4E27, //CJK UNIFIED IDEOGRAPH + 0xC9A6: 0x6414, //CJK UNIFIED IDEOGRAPH + 0xC9A7: 0x9A9A, //CJK UNIFIED IDEOGRAPH + 0xC9A8: 0x626B, //CJK UNIFIED IDEOGRAPH + 0xC9A9: 0x5AC2, //CJK UNIFIED IDEOGRAPH + 0xC9AA: 0x745F, //CJK UNIFIED IDEOGRAPH + 0xC9AB: 0x8272, //CJK UNIFIED IDEOGRAPH + 0xC9AC: 0x6DA9, //CJK UNIFIED IDEOGRAPH + 0xC9AD: 0x68EE, //CJK UNIFIED IDEOGRAPH + 0xC9AE: 0x50E7, //CJK UNIFIED IDEOGRAPH + 0xC9AF: 0x838E, //CJK UNIFIED IDEOGRAPH + 0xC9B0: 0x7802, //CJK UNIFIED IDEOGRAPH + 0xC9B1: 0x6740, //CJK UNIFIED IDEOGRAPH + 0xC9B2: 0x5239, //CJK UNIFIED IDEOGRAPH + 0xC9B3: 0x6C99, //CJK UNIFIED IDEOGRAPH + 0xC9B4: 0x7EB1, //CJK UNIFIED IDEOGRAPH + 0xC9B5: 0x50BB, //CJK UNIFIED IDEOGRAPH + 0xC9B6: 0x5565, //CJK UNIFIED IDEOGRAPH + 0xC9B7: 0x715E, //CJK UNIFIED IDEOGRAPH + 0xC9B8: 0x7B5B, //CJK UNIFIED IDEOGRAPH + 0xC9B9: 0x6652, //CJK UNIFIED IDEOGRAPH + 0xC9BA: 0x73CA, //CJK UNIFIED IDEOGRAPH + 0xC9BB: 0x82EB, //CJK UNIFIED IDEOGRAPH + 0xC9BC: 0x6749, //CJK UNIFIED IDEOGRAPH + 0xC9BD: 0x5C71, //CJK UNIFIED IDEOGRAPH + 0xC9BE: 0x5220, //CJK UNIFIED IDEOGRAPH + 0xC9BF: 0x717D, //CJK UNIFIED IDEOGRAPH + 0xC9C0: 0x886B, //CJK UNIFIED IDEOGRAPH + 0xC9C1: 0x95EA, //CJK UNIFIED IDEOGRAPH + 0xC9C2: 0x9655, //CJK UNIFIED IDEOGRAPH + 0xC9C3: 0x64C5, //CJK UNIFIED IDEOGRAPH + 0xC9C4: 0x8D61, //CJK UNIFIED IDEOGRAPH + 0xC9C5: 0x81B3, //CJK UNIFIED IDEOGRAPH + 0xC9C6: 0x5584, //CJK UNIFIED IDEOGRAPH + 0xC9C7: 0x6C55, //CJK UNIFIED IDEOGRAPH + 0xC9C8: 0x6247, //CJK UNIFIED IDEOGRAPH + 0xC9C9: 0x7F2E, //CJK UNIFIED IDEOGRAPH + 0xC9CA: 0x5892, //CJK UNIFIED IDEOGRAPH + 0xC9CB: 0x4F24, //CJK UNIFIED IDEOGRAPH + 0xC9CC: 0x5546, //CJK UNIFIED IDEOGRAPH + 0xC9CD: 0x8D4F, //CJK UNIFIED IDEOGRAPH + 0xC9CE: 0x664C, //CJK UNIFIED IDEOGRAPH + 0xC9CF: 0x4E0A, //CJK UNIFIED IDEOGRAPH + 0xC9D0: 0x5C1A, //CJK UNIFIED IDEOGRAPH + 0xC9D1: 0x88F3, //CJK UNIFIED IDEOGRAPH + 0xC9D2: 0x68A2, //CJK UNIFIED IDEOGRAPH + 0xC9D3: 0x634E, //CJK UNIFIED IDEOGRAPH + 0xC9D4: 0x7A0D, //CJK UNIFIED IDEOGRAPH + 0xC9D5: 0x70E7, //CJK UNIFIED IDEOGRAPH + 0xC9D6: 0x828D, //CJK UNIFIED IDEOGRAPH + 0xC9D7: 0x52FA, //CJK UNIFIED IDEOGRAPH + 0xC9D8: 0x97F6, //CJK UNIFIED IDEOGRAPH + 0xC9D9: 0x5C11, //CJK UNIFIED IDEOGRAPH + 0xC9DA: 0x54E8, //CJK UNIFIED IDEOGRAPH + 0xC9DB: 0x90B5, //CJK UNIFIED IDEOGRAPH + 0xC9DC: 0x7ECD, //CJK UNIFIED IDEOGRAPH + 0xC9DD: 0x5962, //CJK UNIFIED IDEOGRAPH + 0xC9DE: 0x8D4A, //CJK UNIFIED IDEOGRAPH + 0xC9DF: 0x86C7, //CJK UNIFIED IDEOGRAPH + 0xC9E0: 0x820C, //CJK UNIFIED IDEOGRAPH + 0xC9E1: 0x820D, //CJK UNIFIED IDEOGRAPH + 0xC9E2: 0x8D66, //CJK UNIFIED IDEOGRAPH + 0xC9E3: 0x6444, //CJK UNIFIED IDEOGRAPH + 0xC9E4: 0x5C04, //CJK UNIFIED IDEOGRAPH + 0xC9E5: 0x6151, //CJK UNIFIED IDEOGRAPH + 0xC9E6: 0x6D89, //CJK UNIFIED IDEOGRAPH + 0xC9E7: 0x793E, //CJK UNIFIED IDEOGRAPH + 0xC9E8: 0x8BBE, //CJK UNIFIED IDEOGRAPH + 0xC9E9: 0x7837, //CJK UNIFIED IDEOGRAPH + 0xC9EA: 0x7533, //CJK UNIFIED IDEOGRAPH + 0xC9EB: 0x547B, //CJK UNIFIED IDEOGRAPH + 0xC9EC: 0x4F38, //CJK UNIFIED IDEOGRAPH + 0xC9ED: 0x8EAB, //CJK UNIFIED IDEOGRAPH + 0xC9EE: 0x6DF1, //CJK UNIFIED IDEOGRAPH + 0xC9EF: 0x5A20, //CJK UNIFIED IDEOGRAPH + 0xC9F0: 0x7EC5, //CJK UNIFIED IDEOGRAPH + 0xC9F1: 0x795E, //CJK UNIFIED IDEOGRAPH + 0xC9F2: 0x6C88, //CJK UNIFIED IDEOGRAPH + 0xC9F3: 0x5BA1, //CJK UNIFIED IDEOGRAPH + 0xC9F4: 0x5A76, //CJK UNIFIED IDEOGRAPH + 0xC9F5: 0x751A, //CJK UNIFIED IDEOGRAPH + 0xC9F6: 0x80BE, //CJK UNIFIED IDEOGRAPH + 0xC9F7: 0x614E, //CJK UNIFIED IDEOGRAPH + 0xC9F8: 0x6E17, //CJK UNIFIED IDEOGRAPH + 0xC9F9: 0x58F0, //CJK UNIFIED IDEOGRAPH + 0xC9FA: 0x751F, //CJK UNIFIED IDEOGRAPH + 0xC9FB: 0x7525, //CJK UNIFIED IDEOGRAPH + 0xC9FC: 0x7272, //CJK UNIFIED IDEOGRAPH + 0xC9FD: 0x5347, //CJK UNIFIED IDEOGRAPH + 0xC9FE: 0x7EF3, //CJK UNIFIED IDEOGRAPH + 0xCA40: 0x8503, //CJK UNIFIED IDEOGRAPH + 0xCA41: 0x8504, //CJK UNIFIED IDEOGRAPH + 0xCA42: 0x8505, //CJK UNIFIED IDEOGRAPH + 0xCA43: 0x8506, //CJK UNIFIED IDEOGRAPH + 0xCA44: 0x8507, //CJK UNIFIED IDEOGRAPH + 0xCA45: 0x8508, //CJK UNIFIED IDEOGRAPH + 0xCA46: 0x8509, //CJK UNIFIED IDEOGRAPH + 0xCA47: 0x850A, //CJK UNIFIED IDEOGRAPH + 0xCA48: 0x850B, //CJK UNIFIED IDEOGRAPH + 0xCA49: 0x850D, //CJK UNIFIED IDEOGRAPH + 0xCA4A: 0x850E, //CJK UNIFIED IDEOGRAPH + 0xCA4B: 0x850F, //CJK UNIFIED IDEOGRAPH + 0xCA4C: 0x8510, //CJK UNIFIED IDEOGRAPH + 0xCA4D: 0x8512, //CJK UNIFIED IDEOGRAPH + 0xCA4E: 0x8514, //CJK UNIFIED IDEOGRAPH + 0xCA4F: 0x8515, //CJK UNIFIED IDEOGRAPH + 0xCA50: 0x8516, //CJK UNIFIED IDEOGRAPH + 0xCA51: 0x8518, //CJK UNIFIED IDEOGRAPH + 0xCA52: 0x8519, //CJK UNIFIED IDEOGRAPH + 0xCA53: 0x851B, //CJK UNIFIED IDEOGRAPH + 0xCA54: 0x851C, //CJK UNIFIED IDEOGRAPH + 0xCA55: 0x851D, //CJK UNIFIED IDEOGRAPH + 0xCA56: 0x851E, //CJK UNIFIED IDEOGRAPH + 0xCA57: 0x8520, //CJK UNIFIED IDEOGRAPH + 0xCA58: 0x8522, //CJK UNIFIED IDEOGRAPH + 0xCA59: 0x8523, //CJK UNIFIED IDEOGRAPH + 0xCA5A: 0x8524, //CJK UNIFIED IDEOGRAPH + 0xCA5B: 0x8525, //CJK UNIFIED IDEOGRAPH + 0xCA5C: 0x8526, //CJK UNIFIED IDEOGRAPH + 0xCA5D: 0x8527, //CJK UNIFIED IDEOGRAPH + 0xCA5E: 0x8528, //CJK UNIFIED IDEOGRAPH + 0xCA5F: 0x8529, //CJK UNIFIED IDEOGRAPH + 0xCA60: 0x852A, //CJK UNIFIED IDEOGRAPH + 0xCA61: 0x852D, //CJK UNIFIED IDEOGRAPH + 0xCA62: 0x852E, //CJK UNIFIED IDEOGRAPH + 0xCA63: 0x852F, //CJK UNIFIED IDEOGRAPH + 0xCA64: 0x8530, //CJK UNIFIED IDEOGRAPH + 0xCA65: 0x8531, //CJK UNIFIED IDEOGRAPH + 0xCA66: 0x8532, //CJK UNIFIED IDEOGRAPH + 0xCA67: 0x8533, //CJK UNIFIED IDEOGRAPH + 0xCA68: 0x8534, //CJK UNIFIED IDEOGRAPH + 0xCA69: 0x8535, //CJK UNIFIED IDEOGRAPH + 0xCA6A: 0x8536, //CJK UNIFIED IDEOGRAPH + 0xCA6B: 0x853E, //CJK UNIFIED IDEOGRAPH + 0xCA6C: 0x853F, //CJK UNIFIED IDEOGRAPH + 0xCA6D: 0x8540, //CJK UNIFIED IDEOGRAPH + 0xCA6E: 0x8541, //CJK UNIFIED IDEOGRAPH + 0xCA6F: 0x8542, //CJK UNIFIED IDEOGRAPH + 0xCA70: 0x8544, //CJK UNIFIED IDEOGRAPH + 0xCA71: 0x8545, //CJK UNIFIED IDEOGRAPH + 0xCA72: 0x8546, //CJK UNIFIED IDEOGRAPH + 0xCA73: 0x8547, //CJK UNIFIED IDEOGRAPH + 0xCA74: 0x854B, //CJK UNIFIED IDEOGRAPH + 0xCA75: 0x854C, //CJK UNIFIED IDEOGRAPH + 0xCA76: 0x854D, //CJK UNIFIED IDEOGRAPH + 0xCA77: 0x854E, //CJK UNIFIED IDEOGRAPH + 0xCA78: 0x854F, //CJK UNIFIED IDEOGRAPH + 0xCA79: 0x8550, //CJK UNIFIED IDEOGRAPH + 0xCA7A: 0x8551, //CJK UNIFIED IDEOGRAPH + 0xCA7B: 0x8552, //CJK UNIFIED IDEOGRAPH + 0xCA7C: 0x8553, //CJK UNIFIED IDEOGRAPH + 0xCA7D: 0x8554, //CJK UNIFIED IDEOGRAPH + 0xCA7E: 0x8555, //CJK UNIFIED IDEOGRAPH + 0xCA80: 0x8557, //CJK UNIFIED IDEOGRAPH + 0xCA81: 0x8558, //CJK UNIFIED IDEOGRAPH + 0xCA82: 0x855A, //CJK UNIFIED IDEOGRAPH + 0xCA83: 0x855B, //CJK UNIFIED IDEOGRAPH + 0xCA84: 0x855C, //CJK UNIFIED IDEOGRAPH + 0xCA85: 0x855D, //CJK UNIFIED IDEOGRAPH + 0xCA86: 0x855F, //CJK UNIFIED IDEOGRAPH + 0xCA87: 0x8560, //CJK UNIFIED IDEOGRAPH + 0xCA88: 0x8561, //CJK UNIFIED IDEOGRAPH + 0xCA89: 0x8562, //CJK UNIFIED IDEOGRAPH + 0xCA8A: 0x8563, //CJK UNIFIED IDEOGRAPH + 0xCA8B: 0x8565, //CJK UNIFIED IDEOGRAPH + 0xCA8C: 0x8566, //CJK UNIFIED IDEOGRAPH + 0xCA8D: 0x8567, //CJK UNIFIED IDEOGRAPH + 0xCA8E: 0x8569, //CJK UNIFIED IDEOGRAPH + 0xCA8F: 0x856A, //CJK UNIFIED IDEOGRAPH + 0xCA90: 0x856B, //CJK UNIFIED IDEOGRAPH + 0xCA91: 0x856C, //CJK UNIFIED IDEOGRAPH + 0xCA92: 0x856D, //CJK UNIFIED IDEOGRAPH + 0xCA93: 0x856E, //CJK UNIFIED IDEOGRAPH + 0xCA94: 0x856F, //CJK UNIFIED IDEOGRAPH + 0xCA95: 0x8570, //CJK UNIFIED IDEOGRAPH + 0xCA96: 0x8571, //CJK UNIFIED IDEOGRAPH + 0xCA97: 0x8573, //CJK UNIFIED IDEOGRAPH + 0xCA98: 0x8575, //CJK UNIFIED IDEOGRAPH + 0xCA99: 0x8576, //CJK UNIFIED IDEOGRAPH + 0xCA9A: 0x8577, //CJK UNIFIED IDEOGRAPH + 0xCA9B: 0x8578, //CJK UNIFIED IDEOGRAPH + 0xCA9C: 0x857C, //CJK UNIFIED IDEOGRAPH + 0xCA9D: 0x857D, //CJK UNIFIED IDEOGRAPH + 0xCA9E: 0x857F, //CJK UNIFIED IDEOGRAPH + 0xCA9F: 0x8580, //CJK UNIFIED IDEOGRAPH + 0xCAA0: 0x8581, //CJK UNIFIED IDEOGRAPH + 0xCAA1: 0x7701, //CJK UNIFIED IDEOGRAPH + 0xCAA2: 0x76DB, //CJK UNIFIED IDEOGRAPH + 0xCAA3: 0x5269, //CJK UNIFIED IDEOGRAPH + 0xCAA4: 0x80DC, //CJK UNIFIED IDEOGRAPH + 0xCAA5: 0x5723, //CJK UNIFIED IDEOGRAPH + 0xCAA6: 0x5E08, //CJK UNIFIED IDEOGRAPH + 0xCAA7: 0x5931, //CJK UNIFIED IDEOGRAPH + 0xCAA8: 0x72EE, //CJK UNIFIED IDEOGRAPH + 0xCAA9: 0x65BD, //CJK UNIFIED IDEOGRAPH + 0xCAAA: 0x6E7F, //CJK UNIFIED IDEOGRAPH + 0xCAAB: 0x8BD7, //CJK UNIFIED IDEOGRAPH + 0xCAAC: 0x5C38, //CJK UNIFIED IDEOGRAPH + 0xCAAD: 0x8671, //CJK UNIFIED IDEOGRAPH + 0xCAAE: 0x5341, //CJK UNIFIED IDEOGRAPH + 0xCAAF: 0x77F3, //CJK UNIFIED IDEOGRAPH + 0xCAB0: 0x62FE, //CJK UNIFIED IDEOGRAPH + 0xCAB1: 0x65F6, //CJK UNIFIED IDEOGRAPH + 0xCAB2: 0x4EC0, //CJK UNIFIED IDEOGRAPH + 0xCAB3: 0x98DF, //CJK UNIFIED IDEOGRAPH + 0xCAB4: 0x8680, //CJK UNIFIED IDEOGRAPH + 0xCAB5: 0x5B9E, //CJK UNIFIED IDEOGRAPH + 0xCAB6: 0x8BC6, //CJK UNIFIED IDEOGRAPH + 0xCAB7: 0x53F2, //CJK UNIFIED IDEOGRAPH + 0xCAB8: 0x77E2, //CJK UNIFIED IDEOGRAPH + 0xCAB9: 0x4F7F, //CJK UNIFIED IDEOGRAPH + 0xCABA: 0x5C4E, //CJK UNIFIED IDEOGRAPH + 0xCABB: 0x9A76, //CJK UNIFIED IDEOGRAPH + 0xCABC: 0x59CB, //CJK UNIFIED IDEOGRAPH + 0xCABD: 0x5F0F, //CJK UNIFIED IDEOGRAPH + 0xCABE: 0x793A, //CJK UNIFIED IDEOGRAPH + 0xCABF: 0x58EB, //CJK UNIFIED IDEOGRAPH + 0xCAC0: 0x4E16, //CJK UNIFIED IDEOGRAPH + 0xCAC1: 0x67FF, //CJK UNIFIED IDEOGRAPH + 0xCAC2: 0x4E8B, //CJK UNIFIED IDEOGRAPH + 0xCAC3: 0x62ED, //CJK UNIFIED IDEOGRAPH + 0xCAC4: 0x8A93, //CJK UNIFIED IDEOGRAPH + 0xCAC5: 0x901D, //CJK UNIFIED IDEOGRAPH + 0xCAC6: 0x52BF, //CJK UNIFIED IDEOGRAPH + 0xCAC7: 0x662F, //CJK UNIFIED IDEOGRAPH + 0xCAC8: 0x55DC, //CJK UNIFIED IDEOGRAPH + 0xCAC9: 0x566C, //CJK UNIFIED IDEOGRAPH + 0xCACA: 0x9002, //CJK UNIFIED IDEOGRAPH + 0xCACB: 0x4ED5, //CJK UNIFIED IDEOGRAPH + 0xCACC: 0x4F8D, //CJK UNIFIED IDEOGRAPH + 0xCACD: 0x91CA, //CJK UNIFIED IDEOGRAPH + 0xCACE: 0x9970, //CJK UNIFIED IDEOGRAPH + 0xCACF: 0x6C0F, //CJK UNIFIED IDEOGRAPH + 0xCAD0: 0x5E02, //CJK UNIFIED IDEOGRAPH + 0xCAD1: 0x6043, //CJK UNIFIED IDEOGRAPH + 0xCAD2: 0x5BA4, //CJK UNIFIED IDEOGRAPH + 0xCAD3: 0x89C6, //CJK UNIFIED IDEOGRAPH + 0xCAD4: 0x8BD5, //CJK UNIFIED IDEOGRAPH + 0xCAD5: 0x6536, //CJK UNIFIED IDEOGRAPH + 0xCAD6: 0x624B, //CJK UNIFIED IDEOGRAPH + 0xCAD7: 0x9996, //CJK UNIFIED IDEOGRAPH + 0xCAD8: 0x5B88, //CJK UNIFIED IDEOGRAPH + 0xCAD9: 0x5BFF, //CJK UNIFIED IDEOGRAPH + 0xCADA: 0x6388, //CJK UNIFIED IDEOGRAPH + 0xCADB: 0x552E, //CJK UNIFIED IDEOGRAPH + 0xCADC: 0x53D7, //CJK UNIFIED IDEOGRAPH + 0xCADD: 0x7626, //CJK UNIFIED IDEOGRAPH + 0xCADE: 0x517D, //CJK UNIFIED IDEOGRAPH + 0xCADF: 0x852C, //CJK UNIFIED IDEOGRAPH + 0xCAE0: 0x67A2, //CJK UNIFIED IDEOGRAPH + 0xCAE1: 0x68B3, //CJK UNIFIED IDEOGRAPH + 0xCAE2: 0x6B8A, //CJK UNIFIED IDEOGRAPH + 0xCAE3: 0x6292, //CJK UNIFIED IDEOGRAPH + 0xCAE4: 0x8F93, //CJK UNIFIED IDEOGRAPH + 0xCAE5: 0x53D4, //CJK UNIFIED IDEOGRAPH + 0xCAE6: 0x8212, //CJK UNIFIED IDEOGRAPH + 0xCAE7: 0x6DD1, //CJK UNIFIED IDEOGRAPH + 0xCAE8: 0x758F, //CJK UNIFIED IDEOGRAPH + 0xCAE9: 0x4E66, //CJK UNIFIED IDEOGRAPH + 0xCAEA: 0x8D4E, //CJK UNIFIED IDEOGRAPH + 0xCAEB: 0x5B70, //CJK UNIFIED IDEOGRAPH + 0xCAEC: 0x719F, //CJK UNIFIED IDEOGRAPH + 0xCAED: 0x85AF, //CJK UNIFIED IDEOGRAPH + 0xCAEE: 0x6691, //CJK UNIFIED IDEOGRAPH + 0xCAEF: 0x66D9, //CJK UNIFIED IDEOGRAPH + 0xCAF0: 0x7F72, //CJK UNIFIED IDEOGRAPH + 0xCAF1: 0x8700, //CJK UNIFIED IDEOGRAPH + 0xCAF2: 0x9ECD, //CJK UNIFIED IDEOGRAPH + 0xCAF3: 0x9F20, //CJK UNIFIED IDEOGRAPH + 0xCAF4: 0x5C5E, //CJK UNIFIED IDEOGRAPH + 0xCAF5: 0x672F, //CJK UNIFIED IDEOGRAPH + 0xCAF6: 0x8FF0, //CJK UNIFIED IDEOGRAPH + 0xCAF7: 0x6811, //CJK UNIFIED IDEOGRAPH + 0xCAF8: 0x675F, //CJK UNIFIED IDEOGRAPH + 0xCAF9: 0x620D, //CJK UNIFIED IDEOGRAPH + 0xCAFA: 0x7AD6, //CJK UNIFIED IDEOGRAPH + 0xCAFB: 0x5885, //CJK UNIFIED IDEOGRAPH + 0xCAFC: 0x5EB6, //CJK UNIFIED IDEOGRAPH + 0xCAFD: 0x6570, //CJK UNIFIED IDEOGRAPH + 0xCAFE: 0x6F31, //CJK UNIFIED IDEOGRAPH + 0xCB40: 0x8582, //CJK UNIFIED IDEOGRAPH + 0xCB41: 0x8583, //CJK UNIFIED IDEOGRAPH + 0xCB42: 0x8586, //CJK UNIFIED IDEOGRAPH + 0xCB43: 0x8588, //CJK UNIFIED IDEOGRAPH + 0xCB44: 0x8589, //CJK UNIFIED IDEOGRAPH + 0xCB45: 0x858A, //CJK UNIFIED IDEOGRAPH + 0xCB46: 0x858B, //CJK UNIFIED IDEOGRAPH + 0xCB47: 0x858C, //CJK UNIFIED IDEOGRAPH + 0xCB48: 0x858D, //CJK UNIFIED IDEOGRAPH + 0xCB49: 0x858E, //CJK UNIFIED IDEOGRAPH + 0xCB4A: 0x8590, //CJK UNIFIED IDEOGRAPH + 0xCB4B: 0x8591, //CJK UNIFIED IDEOGRAPH + 0xCB4C: 0x8592, //CJK UNIFIED IDEOGRAPH + 0xCB4D: 0x8593, //CJK UNIFIED IDEOGRAPH + 0xCB4E: 0x8594, //CJK UNIFIED IDEOGRAPH + 0xCB4F: 0x8595, //CJK UNIFIED IDEOGRAPH + 0xCB50: 0x8596, //CJK UNIFIED IDEOGRAPH + 0xCB51: 0x8597, //CJK UNIFIED IDEOGRAPH + 0xCB52: 0x8598, //CJK UNIFIED IDEOGRAPH + 0xCB53: 0x8599, //CJK UNIFIED IDEOGRAPH + 0xCB54: 0x859A, //CJK UNIFIED IDEOGRAPH + 0xCB55: 0x859D, //CJK UNIFIED IDEOGRAPH + 0xCB56: 0x859E, //CJK UNIFIED IDEOGRAPH + 0xCB57: 0x859F, //CJK UNIFIED IDEOGRAPH + 0xCB58: 0x85A0, //CJK UNIFIED IDEOGRAPH + 0xCB59: 0x85A1, //CJK UNIFIED IDEOGRAPH + 0xCB5A: 0x85A2, //CJK UNIFIED IDEOGRAPH + 0xCB5B: 0x85A3, //CJK UNIFIED IDEOGRAPH + 0xCB5C: 0x85A5, //CJK UNIFIED IDEOGRAPH + 0xCB5D: 0x85A6, //CJK UNIFIED IDEOGRAPH + 0xCB5E: 0x85A7, //CJK UNIFIED IDEOGRAPH + 0xCB5F: 0x85A9, //CJK UNIFIED IDEOGRAPH + 0xCB60: 0x85AB, //CJK UNIFIED IDEOGRAPH + 0xCB61: 0x85AC, //CJK UNIFIED IDEOGRAPH + 0xCB62: 0x85AD, //CJK UNIFIED IDEOGRAPH + 0xCB63: 0x85B1, //CJK UNIFIED IDEOGRAPH + 0xCB64: 0x85B2, //CJK UNIFIED IDEOGRAPH + 0xCB65: 0x85B3, //CJK UNIFIED IDEOGRAPH + 0xCB66: 0x85B4, //CJK UNIFIED IDEOGRAPH + 0xCB67: 0x85B5, //CJK UNIFIED IDEOGRAPH + 0xCB68: 0x85B6, //CJK UNIFIED IDEOGRAPH + 0xCB69: 0x85B8, //CJK UNIFIED IDEOGRAPH + 0xCB6A: 0x85BA, //CJK UNIFIED IDEOGRAPH + 0xCB6B: 0x85BB, //CJK UNIFIED IDEOGRAPH + 0xCB6C: 0x85BC, //CJK UNIFIED IDEOGRAPH + 0xCB6D: 0x85BD, //CJK UNIFIED IDEOGRAPH + 0xCB6E: 0x85BE, //CJK UNIFIED IDEOGRAPH + 0xCB6F: 0x85BF, //CJK UNIFIED IDEOGRAPH + 0xCB70: 0x85C0, //CJK UNIFIED IDEOGRAPH + 0xCB71: 0x85C2, //CJK UNIFIED IDEOGRAPH + 0xCB72: 0x85C3, //CJK UNIFIED IDEOGRAPH + 0xCB73: 0x85C4, //CJK UNIFIED IDEOGRAPH + 0xCB74: 0x85C5, //CJK UNIFIED IDEOGRAPH + 0xCB75: 0x85C6, //CJK UNIFIED IDEOGRAPH + 0xCB76: 0x85C7, //CJK UNIFIED IDEOGRAPH + 0xCB77: 0x85C8, //CJK UNIFIED IDEOGRAPH + 0xCB78: 0x85CA, //CJK UNIFIED IDEOGRAPH + 0xCB79: 0x85CB, //CJK UNIFIED IDEOGRAPH + 0xCB7A: 0x85CC, //CJK UNIFIED IDEOGRAPH + 0xCB7B: 0x85CD, //CJK UNIFIED IDEOGRAPH + 0xCB7C: 0x85CE, //CJK UNIFIED IDEOGRAPH + 0xCB7D: 0x85D1, //CJK UNIFIED IDEOGRAPH + 0xCB7E: 0x85D2, //CJK UNIFIED IDEOGRAPH + 0xCB80: 0x85D4, //CJK UNIFIED IDEOGRAPH + 0xCB81: 0x85D6, //CJK UNIFIED IDEOGRAPH + 0xCB82: 0x85D7, //CJK UNIFIED IDEOGRAPH + 0xCB83: 0x85D8, //CJK UNIFIED IDEOGRAPH + 0xCB84: 0x85D9, //CJK UNIFIED IDEOGRAPH + 0xCB85: 0x85DA, //CJK UNIFIED IDEOGRAPH + 0xCB86: 0x85DB, //CJK UNIFIED IDEOGRAPH + 0xCB87: 0x85DD, //CJK UNIFIED IDEOGRAPH + 0xCB88: 0x85DE, //CJK UNIFIED IDEOGRAPH + 0xCB89: 0x85DF, //CJK UNIFIED IDEOGRAPH + 0xCB8A: 0x85E0, //CJK UNIFIED IDEOGRAPH + 0xCB8B: 0x85E1, //CJK UNIFIED IDEOGRAPH + 0xCB8C: 0x85E2, //CJK UNIFIED IDEOGRAPH + 0xCB8D: 0x85E3, //CJK UNIFIED IDEOGRAPH + 0xCB8E: 0x85E5, //CJK UNIFIED IDEOGRAPH + 0xCB8F: 0x85E6, //CJK UNIFIED IDEOGRAPH + 0xCB90: 0x85E7, //CJK UNIFIED IDEOGRAPH + 0xCB91: 0x85E8, //CJK UNIFIED IDEOGRAPH + 0xCB92: 0x85EA, //CJK UNIFIED IDEOGRAPH + 0xCB93: 0x85EB, //CJK UNIFIED IDEOGRAPH + 0xCB94: 0x85EC, //CJK UNIFIED IDEOGRAPH + 0xCB95: 0x85ED, //CJK UNIFIED IDEOGRAPH + 0xCB96: 0x85EE, //CJK UNIFIED IDEOGRAPH + 0xCB97: 0x85EF, //CJK UNIFIED IDEOGRAPH + 0xCB98: 0x85F0, //CJK UNIFIED IDEOGRAPH + 0xCB99: 0x85F1, //CJK UNIFIED IDEOGRAPH + 0xCB9A: 0x85F2, //CJK UNIFIED IDEOGRAPH + 0xCB9B: 0x85F3, //CJK UNIFIED IDEOGRAPH + 0xCB9C: 0x85F4, //CJK UNIFIED IDEOGRAPH + 0xCB9D: 0x85F5, //CJK UNIFIED IDEOGRAPH + 0xCB9E: 0x85F6, //CJK UNIFIED IDEOGRAPH + 0xCB9F: 0x85F7, //CJK UNIFIED IDEOGRAPH + 0xCBA0: 0x85F8, //CJK UNIFIED IDEOGRAPH + 0xCBA1: 0x6055, //CJK UNIFIED IDEOGRAPH + 0xCBA2: 0x5237, //CJK UNIFIED IDEOGRAPH + 0xCBA3: 0x800D, //CJK UNIFIED IDEOGRAPH + 0xCBA4: 0x6454, //CJK UNIFIED IDEOGRAPH + 0xCBA5: 0x8870, //CJK UNIFIED IDEOGRAPH + 0xCBA6: 0x7529, //CJK UNIFIED IDEOGRAPH + 0xCBA7: 0x5E05, //CJK UNIFIED IDEOGRAPH + 0xCBA8: 0x6813, //CJK UNIFIED IDEOGRAPH + 0xCBA9: 0x62F4, //CJK UNIFIED IDEOGRAPH + 0xCBAA: 0x971C, //CJK UNIFIED IDEOGRAPH + 0xCBAB: 0x53CC, //CJK UNIFIED IDEOGRAPH + 0xCBAC: 0x723D, //CJK UNIFIED IDEOGRAPH + 0xCBAD: 0x8C01, //CJK UNIFIED IDEOGRAPH + 0xCBAE: 0x6C34, //CJK UNIFIED IDEOGRAPH + 0xCBAF: 0x7761, //CJK UNIFIED IDEOGRAPH + 0xCBB0: 0x7A0E, //CJK UNIFIED IDEOGRAPH + 0xCBB1: 0x542E, //CJK UNIFIED IDEOGRAPH + 0xCBB2: 0x77AC, //CJK UNIFIED IDEOGRAPH + 0xCBB3: 0x987A, //CJK UNIFIED IDEOGRAPH + 0xCBB4: 0x821C, //CJK UNIFIED IDEOGRAPH + 0xCBB5: 0x8BF4, //CJK UNIFIED IDEOGRAPH + 0xCBB6: 0x7855, //CJK UNIFIED IDEOGRAPH + 0xCBB7: 0x6714, //CJK UNIFIED IDEOGRAPH + 0xCBB8: 0x70C1, //CJK UNIFIED IDEOGRAPH + 0xCBB9: 0x65AF, //CJK UNIFIED IDEOGRAPH + 0xCBBA: 0x6495, //CJK UNIFIED IDEOGRAPH + 0xCBBB: 0x5636, //CJK UNIFIED IDEOGRAPH + 0xCBBC: 0x601D, //CJK UNIFIED IDEOGRAPH + 0xCBBD: 0x79C1, //CJK UNIFIED IDEOGRAPH + 0xCBBE: 0x53F8, //CJK UNIFIED IDEOGRAPH + 0xCBBF: 0x4E1D, //CJK UNIFIED IDEOGRAPH + 0xCBC0: 0x6B7B, //CJK UNIFIED IDEOGRAPH + 0xCBC1: 0x8086, //CJK UNIFIED IDEOGRAPH + 0xCBC2: 0x5BFA, //CJK UNIFIED IDEOGRAPH + 0xCBC3: 0x55E3, //CJK UNIFIED IDEOGRAPH + 0xCBC4: 0x56DB, //CJK UNIFIED IDEOGRAPH + 0xCBC5: 0x4F3A, //CJK UNIFIED IDEOGRAPH + 0xCBC6: 0x4F3C, //CJK UNIFIED IDEOGRAPH + 0xCBC7: 0x9972, //CJK UNIFIED IDEOGRAPH + 0xCBC8: 0x5DF3, //CJK UNIFIED IDEOGRAPH + 0xCBC9: 0x677E, //CJK UNIFIED IDEOGRAPH + 0xCBCA: 0x8038, //CJK UNIFIED IDEOGRAPH + 0xCBCB: 0x6002, //CJK UNIFIED IDEOGRAPH + 0xCBCC: 0x9882, //CJK UNIFIED IDEOGRAPH + 0xCBCD: 0x9001, //CJK UNIFIED IDEOGRAPH + 0xCBCE: 0x5B8B, //CJK UNIFIED IDEOGRAPH + 0xCBCF: 0x8BBC, //CJK UNIFIED IDEOGRAPH + 0xCBD0: 0x8BF5, //CJK UNIFIED IDEOGRAPH + 0xCBD1: 0x641C, //CJK UNIFIED IDEOGRAPH + 0xCBD2: 0x8258, //CJK UNIFIED IDEOGRAPH + 0xCBD3: 0x64DE, //CJK UNIFIED IDEOGRAPH + 0xCBD4: 0x55FD, //CJK UNIFIED IDEOGRAPH + 0xCBD5: 0x82CF, //CJK UNIFIED IDEOGRAPH + 0xCBD6: 0x9165, //CJK UNIFIED IDEOGRAPH + 0xCBD7: 0x4FD7, //CJK UNIFIED IDEOGRAPH + 0xCBD8: 0x7D20, //CJK UNIFIED IDEOGRAPH + 0xCBD9: 0x901F, //CJK UNIFIED IDEOGRAPH + 0xCBDA: 0x7C9F, //CJK UNIFIED IDEOGRAPH + 0xCBDB: 0x50F3, //CJK UNIFIED IDEOGRAPH + 0xCBDC: 0x5851, //CJK UNIFIED IDEOGRAPH + 0xCBDD: 0x6EAF, //CJK UNIFIED IDEOGRAPH + 0xCBDE: 0x5BBF, //CJK UNIFIED IDEOGRAPH + 0xCBDF: 0x8BC9, //CJK UNIFIED IDEOGRAPH + 0xCBE0: 0x8083, //CJK UNIFIED IDEOGRAPH + 0xCBE1: 0x9178, //CJK UNIFIED IDEOGRAPH + 0xCBE2: 0x849C, //CJK UNIFIED IDEOGRAPH + 0xCBE3: 0x7B97, //CJK UNIFIED IDEOGRAPH + 0xCBE4: 0x867D, //CJK UNIFIED IDEOGRAPH + 0xCBE5: 0x968B, //CJK UNIFIED IDEOGRAPH + 0xCBE6: 0x968F, //CJK UNIFIED IDEOGRAPH + 0xCBE7: 0x7EE5, //CJK UNIFIED IDEOGRAPH + 0xCBE8: 0x9AD3, //CJK UNIFIED IDEOGRAPH + 0xCBE9: 0x788E, //CJK UNIFIED IDEOGRAPH + 0xCBEA: 0x5C81, //CJK UNIFIED IDEOGRAPH + 0xCBEB: 0x7A57, //CJK UNIFIED IDEOGRAPH + 0xCBEC: 0x9042, //CJK UNIFIED IDEOGRAPH + 0xCBED: 0x96A7, //CJK UNIFIED IDEOGRAPH + 0xCBEE: 0x795F, //CJK UNIFIED IDEOGRAPH + 0xCBEF: 0x5B59, //CJK UNIFIED IDEOGRAPH + 0xCBF0: 0x635F, //CJK UNIFIED IDEOGRAPH + 0xCBF1: 0x7B0B, //CJK UNIFIED IDEOGRAPH + 0xCBF2: 0x84D1, //CJK UNIFIED IDEOGRAPH + 0xCBF3: 0x68AD, //CJK UNIFIED IDEOGRAPH + 0xCBF4: 0x5506, //CJK UNIFIED IDEOGRAPH + 0xCBF5: 0x7F29, //CJK UNIFIED IDEOGRAPH + 0xCBF6: 0x7410, //CJK UNIFIED IDEOGRAPH + 0xCBF7: 0x7D22, //CJK UNIFIED IDEOGRAPH + 0xCBF8: 0x9501, //CJK UNIFIED IDEOGRAPH + 0xCBF9: 0x6240, //CJK UNIFIED IDEOGRAPH + 0xCBFA: 0x584C, //CJK UNIFIED IDEOGRAPH + 0xCBFB: 0x4ED6, //CJK UNIFIED IDEOGRAPH + 0xCBFC: 0x5B83, //CJK UNIFIED IDEOGRAPH + 0xCBFD: 0x5979, //CJK UNIFIED IDEOGRAPH + 0xCBFE: 0x5854, //CJK UNIFIED IDEOGRAPH + 0xCC40: 0x85F9, //CJK UNIFIED IDEOGRAPH + 0xCC41: 0x85FA, //CJK UNIFIED IDEOGRAPH + 0xCC42: 0x85FC, //CJK UNIFIED IDEOGRAPH + 0xCC43: 0x85FD, //CJK UNIFIED IDEOGRAPH + 0xCC44: 0x85FE, //CJK UNIFIED IDEOGRAPH + 0xCC45: 0x8600, //CJK UNIFIED IDEOGRAPH + 0xCC46: 0x8601, //CJK UNIFIED IDEOGRAPH + 0xCC47: 0x8602, //CJK UNIFIED IDEOGRAPH + 0xCC48: 0x8603, //CJK UNIFIED IDEOGRAPH + 0xCC49: 0x8604, //CJK UNIFIED IDEOGRAPH + 0xCC4A: 0x8606, //CJK UNIFIED IDEOGRAPH + 0xCC4B: 0x8607, //CJK UNIFIED IDEOGRAPH + 0xCC4C: 0x8608, //CJK UNIFIED IDEOGRAPH + 0xCC4D: 0x8609, //CJK UNIFIED IDEOGRAPH + 0xCC4E: 0x860A, //CJK UNIFIED IDEOGRAPH + 0xCC4F: 0x860B, //CJK UNIFIED IDEOGRAPH + 0xCC50: 0x860C, //CJK UNIFIED IDEOGRAPH + 0xCC51: 0x860D, //CJK UNIFIED IDEOGRAPH + 0xCC52: 0x860E, //CJK UNIFIED IDEOGRAPH + 0xCC53: 0x860F, //CJK UNIFIED IDEOGRAPH + 0xCC54: 0x8610, //CJK UNIFIED IDEOGRAPH + 0xCC55: 0x8612, //CJK UNIFIED IDEOGRAPH + 0xCC56: 0x8613, //CJK UNIFIED IDEOGRAPH + 0xCC57: 0x8614, //CJK UNIFIED IDEOGRAPH + 0xCC58: 0x8615, //CJK UNIFIED IDEOGRAPH + 0xCC59: 0x8617, //CJK UNIFIED IDEOGRAPH + 0xCC5A: 0x8618, //CJK UNIFIED IDEOGRAPH + 0xCC5B: 0x8619, //CJK UNIFIED IDEOGRAPH + 0xCC5C: 0x861A, //CJK UNIFIED IDEOGRAPH + 0xCC5D: 0x861B, //CJK UNIFIED IDEOGRAPH + 0xCC5E: 0x861C, //CJK UNIFIED IDEOGRAPH + 0xCC5F: 0x861D, //CJK UNIFIED IDEOGRAPH + 0xCC60: 0x861E, //CJK UNIFIED IDEOGRAPH + 0xCC61: 0x861F, //CJK UNIFIED IDEOGRAPH + 0xCC62: 0x8620, //CJK UNIFIED IDEOGRAPH + 0xCC63: 0x8621, //CJK UNIFIED IDEOGRAPH + 0xCC64: 0x8622, //CJK UNIFIED IDEOGRAPH + 0xCC65: 0x8623, //CJK UNIFIED IDEOGRAPH + 0xCC66: 0x8624, //CJK UNIFIED IDEOGRAPH + 0xCC67: 0x8625, //CJK UNIFIED IDEOGRAPH + 0xCC68: 0x8626, //CJK UNIFIED IDEOGRAPH + 0xCC69: 0x8628, //CJK UNIFIED IDEOGRAPH + 0xCC6A: 0x862A, //CJK UNIFIED IDEOGRAPH + 0xCC6B: 0x862B, //CJK UNIFIED IDEOGRAPH + 0xCC6C: 0x862C, //CJK UNIFIED IDEOGRAPH + 0xCC6D: 0x862D, //CJK UNIFIED IDEOGRAPH + 0xCC6E: 0x862E, //CJK UNIFIED IDEOGRAPH + 0xCC6F: 0x862F, //CJK UNIFIED IDEOGRAPH + 0xCC70: 0x8630, //CJK UNIFIED IDEOGRAPH + 0xCC71: 0x8631, //CJK UNIFIED IDEOGRAPH + 0xCC72: 0x8632, //CJK UNIFIED IDEOGRAPH + 0xCC73: 0x8633, //CJK UNIFIED IDEOGRAPH + 0xCC74: 0x8634, //CJK UNIFIED IDEOGRAPH + 0xCC75: 0x8635, //CJK UNIFIED IDEOGRAPH + 0xCC76: 0x8636, //CJK UNIFIED IDEOGRAPH + 0xCC77: 0x8637, //CJK UNIFIED IDEOGRAPH + 0xCC78: 0x8639, //CJK UNIFIED IDEOGRAPH + 0xCC79: 0x863A, //CJK UNIFIED IDEOGRAPH + 0xCC7A: 0x863B, //CJK UNIFIED IDEOGRAPH + 0xCC7B: 0x863D, //CJK UNIFIED IDEOGRAPH + 0xCC7C: 0x863E, //CJK UNIFIED IDEOGRAPH + 0xCC7D: 0x863F, //CJK UNIFIED IDEOGRAPH + 0xCC7E: 0x8640, //CJK UNIFIED IDEOGRAPH + 0xCC80: 0x8641, //CJK UNIFIED IDEOGRAPH + 0xCC81: 0x8642, //CJK UNIFIED IDEOGRAPH + 0xCC82: 0x8643, //CJK UNIFIED IDEOGRAPH + 0xCC83: 0x8644, //CJK UNIFIED IDEOGRAPH + 0xCC84: 0x8645, //CJK UNIFIED IDEOGRAPH + 0xCC85: 0x8646, //CJK UNIFIED IDEOGRAPH + 0xCC86: 0x8647, //CJK UNIFIED IDEOGRAPH + 0xCC87: 0x8648, //CJK UNIFIED IDEOGRAPH + 0xCC88: 0x8649, //CJK UNIFIED IDEOGRAPH + 0xCC89: 0x864A, //CJK UNIFIED IDEOGRAPH + 0xCC8A: 0x864B, //CJK UNIFIED IDEOGRAPH + 0xCC8B: 0x864C, //CJK UNIFIED IDEOGRAPH + 0xCC8C: 0x8652, //CJK UNIFIED IDEOGRAPH + 0xCC8D: 0x8653, //CJK UNIFIED IDEOGRAPH + 0xCC8E: 0x8655, //CJK UNIFIED IDEOGRAPH + 0xCC8F: 0x8656, //CJK UNIFIED IDEOGRAPH + 0xCC90: 0x8657, //CJK UNIFIED IDEOGRAPH + 0xCC91: 0x8658, //CJK UNIFIED IDEOGRAPH + 0xCC92: 0x8659, //CJK UNIFIED IDEOGRAPH + 0xCC93: 0x865B, //CJK UNIFIED IDEOGRAPH + 0xCC94: 0x865C, //CJK UNIFIED IDEOGRAPH + 0xCC95: 0x865D, //CJK UNIFIED IDEOGRAPH + 0xCC96: 0x865F, //CJK UNIFIED IDEOGRAPH + 0xCC97: 0x8660, //CJK UNIFIED IDEOGRAPH + 0xCC98: 0x8661, //CJK UNIFIED IDEOGRAPH + 0xCC99: 0x8663, //CJK UNIFIED IDEOGRAPH + 0xCC9A: 0x8664, //CJK UNIFIED IDEOGRAPH + 0xCC9B: 0x8665, //CJK UNIFIED IDEOGRAPH + 0xCC9C: 0x8666, //CJK UNIFIED IDEOGRAPH + 0xCC9D: 0x8667, //CJK UNIFIED IDEOGRAPH + 0xCC9E: 0x8668, //CJK UNIFIED IDEOGRAPH + 0xCC9F: 0x8669, //CJK UNIFIED IDEOGRAPH + 0xCCA0: 0x866A, //CJK UNIFIED IDEOGRAPH + 0xCCA1: 0x736D, //CJK UNIFIED IDEOGRAPH + 0xCCA2: 0x631E, //CJK UNIFIED IDEOGRAPH + 0xCCA3: 0x8E4B, //CJK UNIFIED IDEOGRAPH + 0xCCA4: 0x8E0F, //CJK UNIFIED IDEOGRAPH + 0xCCA5: 0x80CE, //CJK UNIFIED IDEOGRAPH + 0xCCA6: 0x82D4, //CJK UNIFIED IDEOGRAPH + 0xCCA7: 0x62AC, //CJK UNIFIED IDEOGRAPH + 0xCCA8: 0x53F0, //CJK UNIFIED IDEOGRAPH + 0xCCA9: 0x6CF0, //CJK UNIFIED IDEOGRAPH + 0xCCAA: 0x915E, //CJK UNIFIED IDEOGRAPH + 0xCCAB: 0x592A, //CJK UNIFIED IDEOGRAPH + 0xCCAC: 0x6001, //CJK UNIFIED IDEOGRAPH + 0xCCAD: 0x6C70, //CJK UNIFIED IDEOGRAPH + 0xCCAE: 0x574D, //CJK UNIFIED IDEOGRAPH + 0xCCAF: 0x644A, //CJK UNIFIED IDEOGRAPH + 0xCCB0: 0x8D2A, //CJK UNIFIED IDEOGRAPH + 0xCCB1: 0x762B, //CJK UNIFIED IDEOGRAPH + 0xCCB2: 0x6EE9, //CJK UNIFIED IDEOGRAPH + 0xCCB3: 0x575B, //CJK UNIFIED IDEOGRAPH + 0xCCB4: 0x6A80, //CJK UNIFIED IDEOGRAPH + 0xCCB5: 0x75F0, //CJK UNIFIED IDEOGRAPH + 0xCCB6: 0x6F6D, //CJK UNIFIED IDEOGRAPH + 0xCCB7: 0x8C2D, //CJK UNIFIED IDEOGRAPH + 0xCCB8: 0x8C08, //CJK UNIFIED IDEOGRAPH + 0xCCB9: 0x5766, //CJK UNIFIED IDEOGRAPH + 0xCCBA: 0x6BEF, //CJK UNIFIED IDEOGRAPH + 0xCCBB: 0x8892, //CJK UNIFIED IDEOGRAPH + 0xCCBC: 0x78B3, //CJK UNIFIED IDEOGRAPH + 0xCCBD: 0x63A2, //CJK UNIFIED IDEOGRAPH + 0xCCBE: 0x53F9, //CJK UNIFIED IDEOGRAPH + 0xCCBF: 0x70AD, //CJK UNIFIED IDEOGRAPH + 0xCCC0: 0x6C64, //CJK UNIFIED IDEOGRAPH + 0xCCC1: 0x5858, //CJK UNIFIED IDEOGRAPH + 0xCCC2: 0x642A, //CJK UNIFIED IDEOGRAPH + 0xCCC3: 0x5802, //CJK UNIFIED IDEOGRAPH + 0xCCC4: 0x68E0, //CJK UNIFIED IDEOGRAPH + 0xCCC5: 0x819B, //CJK UNIFIED IDEOGRAPH + 0xCCC6: 0x5510, //CJK UNIFIED IDEOGRAPH + 0xCCC7: 0x7CD6, //CJK UNIFIED IDEOGRAPH + 0xCCC8: 0x5018, //CJK UNIFIED IDEOGRAPH + 0xCCC9: 0x8EBA, //CJK UNIFIED IDEOGRAPH + 0xCCCA: 0x6DCC, //CJK UNIFIED IDEOGRAPH + 0xCCCB: 0x8D9F, //CJK UNIFIED IDEOGRAPH + 0xCCCC: 0x70EB, //CJK UNIFIED IDEOGRAPH + 0xCCCD: 0x638F, //CJK UNIFIED IDEOGRAPH + 0xCCCE: 0x6D9B, //CJK UNIFIED IDEOGRAPH + 0xCCCF: 0x6ED4, //CJK UNIFIED IDEOGRAPH + 0xCCD0: 0x7EE6, //CJK UNIFIED IDEOGRAPH + 0xCCD1: 0x8404, //CJK UNIFIED IDEOGRAPH + 0xCCD2: 0x6843, //CJK UNIFIED IDEOGRAPH + 0xCCD3: 0x9003, //CJK UNIFIED IDEOGRAPH + 0xCCD4: 0x6DD8, //CJK UNIFIED IDEOGRAPH + 0xCCD5: 0x9676, //CJK UNIFIED IDEOGRAPH + 0xCCD6: 0x8BA8, //CJK UNIFIED IDEOGRAPH + 0xCCD7: 0x5957, //CJK UNIFIED IDEOGRAPH + 0xCCD8: 0x7279, //CJK UNIFIED IDEOGRAPH + 0xCCD9: 0x85E4, //CJK UNIFIED IDEOGRAPH + 0xCCDA: 0x817E, //CJK UNIFIED IDEOGRAPH + 0xCCDB: 0x75BC, //CJK UNIFIED IDEOGRAPH + 0xCCDC: 0x8A8A, //CJK UNIFIED IDEOGRAPH + 0xCCDD: 0x68AF, //CJK UNIFIED IDEOGRAPH + 0xCCDE: 0x5254, //CJK UNIFIED IDEOGRAPH + 0xCCDF: 0x8E22, //CJK UNIFIED IDEOGRAPH + 0xCCE0: 0x9511, //CJK UNIFIED IDEOGRAPH + 0xCCE1: 0x63D0, //CJK UNIFIED IDEOGRAPH + 0xCCE2: 0x9898, //CJK UNIFIED IDEOGRAPH + 0xCCE3: 0x8E44, //CJK UNIFIED IDEOGRAPH + 0xCCE4: 0x557C, //CJK UNIFIED IDEOGRAPH + 0xCCE5: 0x4F53, //CJK UNIFIED IDEOGRAPH + 0xCCE6: 0x66FF, //CJK UNIFIED IDEOGRAPH + 0xCCE7: 0x568F, //CJK UNIFIED IDEOGRAPH + 0xCCE8: 0x60D5, //CJK UNIFIED IDEOGRAPH + 0xCCE9: 0x6D95, //CJK UNIFIED IDEOGRAPH + 0xCCEA: 0x5243, //CJK UNIFIED IDEOGRAPH + 0xCCEB: 0x5C49, //CJK UNIFIED IDEOGRAPH + 0xCCEC: 0x5929, //CJK UNIFIED IDEOGRAPH + 0xCCED: 0x6DFB, //CJK UNIFIED IDEOGRAPH + 0xCCEE: 0x586B, //CJK UNIFIED IDEOGRAPH + 0xCCEF: 0x7530, //CJK UNIFIED IDEOGRAPH + 0xCCF0: 0x751C, //CJK UNIFIED IDEOGRAPH + 0xCCF1: 0x606C, //CJK UNIFIED IDEOGRAPH + 0xCCF2: 0x8214, //CJK UNIFIED IDEOGRAPH + 0xCCF3: 0x8146, //CJK UNIFIED IDEOGRAPH + 0xCCF4: 0x6311, //CJK UNIFIED IDEOGRAPH + 0xCCF5: 0x6761, //CJK UNIFIED IDEOGRAPH + 0xCCF6: 0x8FE2, //CJK UNIFIED IDEOGRAPH + 0xCCF7: 0x773A, //CJK UNIFIED IDEOGRAPH + 0xCCF8: 0x8DF3, //CJK UNIFIED IDEOGRAPH + 0xCCF9: 0x8D34, //CJK UNIFIED IDEOGRAPH + 0xCCFA: 0x94C1, //CJK UNIFIED IDEOGRAPH + 0xCCFB: 0x5E16, //CJK UNIFIED IDEOGRAPH + 0xCCFC: 0x5385, //CJK UNIFIED IDEOGRAPH + 0xCCFD: 0x542C, //CJK UNIFIED IDEOGRAPH + 0xCCFE: 0x70C3, //CJK UNIFIED IDEOGRAPH + 0xCD40: 0x866D, //CJK UNIFIED IDEOGRAPH + 0xCD41: 0x866F, //CJK UNIFIED IDEOGRAPH + 0xCD42: 0x8670, //CJK UNIFIED IDEOGRAPH + 0xCD43: 0x8672, //CJK UNIFIED IDEOGRAPH + 0xCD44: 0x8673, //CJK UNIFIED IDEOGRAPH + 0xCD45: 0x8674, //CJK UNIFIED IDEOGRAPH + 0xCD46: 0x8675, //CJK UNIFIED IDEOGRAPH + 0xCD47: 0x8676, //CJK UNIFIED IDEOGRAPH + 0xCD48: 0x8677, //CJK UNIFIED IDEOGRAPH + 0xCD49: 0x8678, //CJK UNIFIED IDEOGRAPH + 0xCD4A: 0x8683, //CJK UNIFIED IDEOGRAPH + 0xCD4B: 0x8684, //CJK UNIFIED IDEOGRAPH + 0xCD4C: 0x8685, //CJK UNIFIED IDEOGRAPH + 0xCD4D: 0x8686, //CJK UNIFIED IDEOGRAPH + 0xCD4E: 0x8687, //CJK UNIFIED IDEOGRAPH + 0xCD4F: 0x8688, //CJK UNIFIED IDEOGRAPH + 0xCD50: 0x8689, //CJK UNIFIED IDEOGRAPH + 0xCD51: 0x868E, //CJK UNIFIED IDEOGRAPH + 0xCD52: 0x868F, //CJK UNIFIED IDEOGRAPH + 0xCD53: 0x8690, //CJK UNIFIED IDEOGRAPH + 0xCD54: 0x8691, //CJK UNIFIED IDEOGRAPH + 0xCD55: 0x8692, //CJK UNIFIED IDEOGRAPH + 0xCD56: 0x8694, //CJK UNIFIED IDEOGRAPH + 0xCD57: 0x8696, //CJK UNIFIED IDEOGRAPH + 0xCD58: 0x8697, //CJK UNIFIED IDEOGRAPH + 0xCD59: 0x8698, //CJK UNIFIED IDEOGRAPH + 0xCD5A: 0x8699, //CJK UNIFIED IDEOGRAPH + 0xCD5B: 0x869A, //CJK UNIFIED IDEOGRAPH + 0xCD5C: 0x869B, //CJK UNIFIED IDEOGRAPH + 0xCD5D: 0x869E, //CJK UNIFIED IDEOGRAPH + 0xCD5E: 0x869F, //CJK UNIFIED IDEOGRAPH + 0xCD5F: 0x86A0, //CJK UNIFIED IDEOGRAPH + 0xCD60: 0x86A1, //CJK UNIFIED IDEOGRAPH + 0xCD61: 0x86A2, //CJK UNIFIED IDEOGRAPH + 0xCD62: 0x86A5, //CJK UNIFIED IDEOGRAPH + 0xCD63: 0x86A6, //CJK UNIFIED IDEOGRAPH + 0xCD64: 0x86AB, //CJK UNIFIED IDEOGRAPH + 0xCD65: 0x86AD, //CJK UNIFIED IDEOGRAPH + 0xCD66: 0x86AE, //CJK UNIFIED IDEOGRAPH + 0xCD67: 0x86B2, //CJK UNIFIED IDEOGRAPH + 0xCD68: 0x86B3, //CJK UNIFIED IDEOGRAPH + 0xCD69: 0x86B7, //CJK UNIFIED IDEOGRAPH + 0xCD6A: 0x86B8, //CJK UNIFIED IDEOGRAPH + 0xCD6B: 0x86B9, //CJK UNIFIED IDEOGRAPH + 0xCD6C: 0x86BB, //CJK UNIFIED IDEOGRAPH + 0xCD6D: 0x86BC, //CJK UNIFIED IDEOGRAPH + 0xCD6E: 0x86BD, //CJK UNIFIED IDEOGRAPH + 0xCD6F: 0x86BE, //CJK UNIFIED IDEOGRAPH + 0xCD70: 0x86BF, //CJK UNIFIED IDEOGRAPH + 0xCD71: 0x86C1, //CJK UNIFIED IDEOGRAPH + 0xCD72: 0x86C2, //CJK UNIFIED IDEOGRAPH + 0xCD73: 0x86C3, //CJK UNIFIED IDEOGRAPH + 0xCD74: 0x86C5, //CJK UNIFIED IDEOGRAPH + 0xCD75: 0x86C8, //CJK UNIFIED IDEOGRAPH + 0xCD76: 0x86CC, //CJK UNIFIED IDEOGRAPH + 0xCD77: 0x86CD, //CJK UNIFIED IDEOGRAPH + 0xCD78: 0x86D2, //CJK UNIFIED IDEOGRAPH + 0xCD79: 0x86D3, //CJK UNIFIED IDEOGRAPH + 0xCD7A: 0x86D5, //CJK UNIFIED IDEOGRAPH + 0xCD7B: 0x86D6, //CJK UNIFIED IDEOGRAPH + 0xCD7C: 0x86D7, //CJK UNIFIED IDEOGRAPH + 0xCD7D: 0x86DA, //CJK UNIFIED IDEOGRAPH + 0xCD7E: 0x86DC, //CJK UNIFIED IDEOGRAPH + 0xCD80: 0x86DD, //CJK UNIFIED IDEOGRAPH + 0xCD81: 0x86E0, //CJK UNIFIED IDEOGRAPH + 0xCD82: 0x86E1, //CJK UNIFIED IDEOGRAPH + 0xCD83: 0x86E2, //CJK UNIFIED IDEOGRAPH + 0xCD84: 0x86E3, //CJK UNIFIED IDEOGRAPH + 0xCD85: 0x86E5, //CJK UNIFIED IDEOGRAPH + 0xCD86: 0x86E6, //CJK UNIFIED IDEOGRAPH + 0xCD87: 0x86E7, //CJK UNIFIED IDEOGRAPH + 0xCD88: 0x86E8, //CJK UNIFIED IDEOGRAPH + 0xCD89: 0x86EA, //CJK UNIFIED IDEOGRAPH + 0xCD8A: 0x86EB, //CJK UNIFIED IDEOGRAPH + 0xCD8B: 0x86EC, //CJK UNIFIED IDEOGRAPH + 0xCD8C: 0x86EF, //CJK UNIFIED IDEOGRAPH + 0xCD8D: 0x86F5, //CJK UNIFIED IDEOGRAPH + 0xCD8E: 0x86F6, //CJK UNIFIED IDEOGRAPH + 0xCD8F: 0x86F7, //CJK UNIFIED IDEOGRAPH + 0xCD90: 0x86FA, //CJK UNIFIED IDEOGRAPH + 0xCD91: 0x86FB, //CJK UNIFIED IDEOGRAPH + 0xCD92: 0x86FC, //CJK UNIFIED IDEOGRAPH + 0xCD93: 0x86FD, //CJK UNIFIED IDEOGRAPH + 0xCD94: 0x86FF, //CJK UNIFIED IDEOGRAPH + 0xCD95: 0x8701, //CJK UNIFIED IDEOGRAPH + 0xCD96: 0x8704, //CJK UNIFIED IDEOGRAPH + 0xCD97: 0x8705, //CJK UNIFIED IDEOGRAPH + 0xCD98: 0x8706, //CJK UNIFIED IDEOGRAPH + 0xCD99: 0x870B, //CJK UNIFIED IDEOGRAPH + 0xCD9A: 0x870C, //CJK UNIFIED IDEOGRAPH + 0xCD9B: 0x870E, //CJK UNIFIED IDEOGRAPH + 0xCD9C: 0x870F, //CJK UNIFIED IDEOGRAPH + 0xCD9D: 0x8710, //CJK UNIFIED IDEOGRAPH + 0xCD9E: 0x8711, //CJK UNIFIED IDEOGRAPH + 0xCD9F: 0x8714, //CJK UNIFIED IDEOGRAPH + 0xCDA0: 0x8716, //CJK UNIFIED IDEOGRAPH + 0xCDA1: 0x6C40, //CJK UNIFIED IDEOGRAPH + 0xCDA2: 0x5EF7, //CJK UNIFIED IDEOGRAPH + 0xCDA3: 0x505C, //CJK UNIFIED IDEOGRAPH + 0xCDA4: 0x4EAD, //CJK UNIFIED IDEOGRAPH + 0xCDA5: 0x5EAD, //CJK UNIFIED IDEOGRAPH + 0xCDA6: 0x633A, //CJK UNIFIED IDEOGRAPH + 0xCDA7: 0x8247, //CJK UNIFIED IDEOGRAPH + 0xCDA8: 0x901A, //CJK UNIFIED IDEOGRAPH + 0xCDA9: 0x6850, //CJK UNIFIED IDEOGRAPH + 0xCDAA: 0x916E, //CJK UNIFIED IDEOGRAPH + 0xCDAB: 0x77B3, //CJK UNIFIED IDEOGRAPH + 0xCDAC: 0x540C, //CJK UNIFIED IDEOGRAPH + 0xCDAD: 0x94DC, //CJK UNIFIED IDEOGRAPH + 0xCDAE: 0x5F64, //CJK UNIFIED IDEOGRAPH + 0xCDAF: 0x7AE5, //CJK UNIFIED IDEOGRAPH + 0xCDB0: 0x6876, //CJK UNIFIED IDEOGRAPH + 0xCDB1: 0x6345, //CJK UNIFIED IDEOGRAPH + 0xCDB2: 0x7B52, //CJK UNIFIED IDEOGRAPH + 0xCDB3: 0x7EDF, //CJK UNIFIED IDEOGRAPH + 0xCDB4: 0x75DB, //CJK UNIFIED IDEOGRAPH + 0xCDB5: 0x5077, //CJK UNIFIED IDEOGRAPH + 0xCDB6: 0x6295, //CJK UNIFIED IDEOGRAPH + 0xCDB7: 0x5934, //CJK UNIFIED IDEOGRAPH + 0xCDB8: 0x900F, //CJK UNIFIED IDEOGRAPH + 0xCDB9: 0x51F8, //CJK UNIFIED IDEOGRAPH + 0xCDBA: 0x79C3, //CJK UNIFIED IDEOGRAPH + 0xCDBB: 0x7A81, //CJK UNIFIED IDEOGRAPH + 0xCDBC: 0x56FE, //CJK UNIFIED IDEOGRAPH + 0xCDBD: 0x5F92, //CJK UNIFIED IDEOGRAPH + 0xCDBE: 0x9014, //CJK UNIFIED IDEOGRAPH + 0xCDBF: 0x6D82, //CJK UNIFIED IDEOGRAPH + 0xCDC0: 0x5C60, //CJK UNIFIED IDEOGRAPH + 0xCDC1: 0x571F, //CJK UNIFIED IDEOGRAPH + 0xCDC2: 0x5410, //CJK UNIFIED IDEOGRAPH + 0xCDC3: 0x5154, //CJK UNIFIED IDEOGRAPH + 0xCDC4: 0x6E4D, //CJK UNIFIED IDEOGRAPH + 0xCDC5: 0x56E2, //CJK UNIFIED IDEOGRAPH + 0xCDC6: 0x63A8, //CJK UNIFIED IDEOGRAPH + 0xCDC7: 0x9893, //CJK UNIFIED IDEOGRAPH + 0xCDC8: 0x817F, //CJK UNIFIED IDEOGRAPH + 0xCDC9: 0x8715, //CJK UNIFIED IDEOGRAPH + 0xCDCA: 0x892A, //CJK UNIFIED IDEOGRAPH + 0xCDCB: 0x9000, //CJK UNIFIED IDEOGRAPH + 0xCDCC: 0x541E, //CJK UNIFIED IDEOGRAPH + 0xCDCD: 0x5C6F, //CJK UNIFIED IDEOGRAPH + 0xCDCE: 0x81C0, //CJK UNIFIED IDEOGRAPH + 0xCDCF: 0x62D6, //CJK UNIFIED IDEOGRAPH + 0xCDD0: 0x6258, //CJK UNIFIED IDEOGRAPH + 0xCDD1: 0x8131, //CJK UNIFIED IDEOGRAPH + 0xCDD2: 0x9E35, //CJK UNIFIED IDEOGRAPH + 0xCDD3: 0x9640, //CJK UNIFIED IDEOGRAPH + 0xCDD4: 0x9A6E, //CJK UNIFIED IDEOGRAPH + 0xCDD5: 0x9A7C, //CJK UNIFIED IDEOGRAPH + 0xCDD6: 0x692D, //CJK UNIFIED IDEOGRAPH + 0xCDD7: 0x59A5, //CJK UNIFIED IDEOGRAPH + 0xCDD8: 0x62D3, //CJK UNIFIED IDEOGRAPH + 0xCDD9: 0x553E, //CJK UNIFIED IDEOGRAPH + 0xCDDA: 0x6316, //CJK UNIFIED IDEOGRAPH + 0xCDDB: 0x54C7, //CJK UNIFIED IDEOGRAPH + 0xCDDC: 0x86D9, //CJK UNIFIED IDEOGRAPH + 0xCDDD: 0x6D3C, //CJK UNIFIED IDEOGRAPH + 0xCDDE: 0x5A03, //CJK UNIFIED IDEOGRAPH + 0xCDDF: 0x74E6, //CJK UNIFIED IDEOGRAPH + 0xCDE0: 0x889C, //CJK UNIFIED IDEOGRAPH + 0xCDE1: 0x6B6A, //CJK UNIFIED IDEOGRAPH + 0xCDE2: 0x5916, //CJK UNIFIED IDEOGRAPH + 0xCDE3: 0x8C4C, //CJK UNIFIED IDEOGRAPH + 0xCDE4: 0x5F2F, //CJK UNIFIED IDEOGRAPH + 0xCDE5: 0x6E7E, //CJK UNIFIED IDEOGRAPH + 0xCDE6: 0x73A9, //CJK UNIFIED IDEOGRAPH + 0xCDE7: 0x987D, //CJK UNIFIED IDEOGRAPH + 0xCDE8: 0x4E38, //CJK UNIFIED IDEOGRAPH + 0xCDE9: 0x70F7, //CJK UNIFIED IDEOGRAPH + 0xCDEA: 0x5B8C, //CJK UNIFIED IDEOGRAPH + 0xCDEB: 0x7897, //CJK UNIFIED IDEOGRAPH + 0xCDEC: 0x633D, //CJK UNIFIED IDEOGRAPH + 0xCDED: 0x665A, //CJK UNIFIED IDEOGRAPH + 0xCDEE: 0x7696, //CJK UNIFIED IDEOGRAPH + 0xCDEF: 0x60CB, //CJK UNIFIED IDEOGRAPH + 0xCDF0: 0x5B9B, //CJK UNIFIED IDEOGRAPH + 0xCDF1: 0x5A49, //CJK UNIFIED IDEOGRAPH + 0xCDF2: 0x4E07, //CJK UNIFIED IDEOGRAPH + 0xCDF3: 0x8155, //CJK UNIFIED IDEOGRAPH + 0xCDF4: 0x6C6A, //CJK UNIFIED IDEOGRAPH + 0xCDF5: 0x738B, //CJK UNIFIED IDEOGRAPH + 0xCDF6: 0x4EA1, //CJK UNIFIED IDEOGRAPH + 0xCDF7: 0x6789, //CJK UNIFIED IDEOGRAPH + 0xCDF8: 0x7F51, //CJK UNIFIED IDEOGRAPH + 0xCDF9: 0x5F80, //CJK UNIFIED IDEOGRAPH + 0xCDFA: 0x65FA, //CJK UNIFIED IDEOGRAPH + 0xCDFB: 0x671B, //CJK UNIFIED IDEOGRAPH + 0xCDFC: 0x5FD8, //CJK UNIFIED IDEOGRAPH + 0xCDFD: 0x5984, //CJK UNIFIED IDEOGRAPH + 0xCDFE: 0x5A01, //CJK UNIFIED IDEOGRAPH + 0xCE40: 0x8719, //CJK UNIFIED IDEOGRAPH + 0xCE41: 0x871B, //CJK UNIFIED IDEOGRAPH + 0xCE42: 0x871D, //CJK UNIFIED IDEOGRAPH + 0xCE43: 0x871F, //CJK UNIFIED IDEOGRAPH + 0xCE44: 0x8720, //CJK UNIFIED IDEOGRAPH + 0xCE45: 0x8724, //CJK UNIFIED IDEOGRAPH + 0xCE46: 0x8726, //CJK UNIFIED IDEOGRAPH + 0xCE47: 0x8727, //CJK UNIFIED IDEOGRAPH + 0xCE48: 0x8728, //CJK UNIFIED IDEOGRAPH + 0xCE49: 0x872A, //CJK UNIFIED IDEOGRAPH + 0xCE4A: 0x872B, //CJK UNIFIED IDEOGRAPH + 0xCE4B: 0x872C, //CJK UNIFIED IDEOGRAPH + 0xCE4C: 0x872D, //CJK UNIFIED IDEOGRAPH + 0xCE4D: 0x872F, //CJK UNIFIED IDEOGRAPH + 0xCE4E: 0x8730, //CJK UNIFIED IDEOGRAPH + 0xCE4F: 0x8732, //CJK UNIFIED IDEOGRAPH + 0xCE50: 0x8733, //CJK UNIFIED IDEOGRAPH + 0xCE51: 0x8735, //CJK UNIFIED IDEOGRAPH + 0xCE52: 0x8736, //CJK UNIFIED IDEOGRAPH + 0xCE53: 0x8738, //CJK UNIFIED IDEOGRAPH + 0xCE54: 0x8739, //CJK UNIFIED IDEOGRAPH + 0xCE55: 0x873A, //CJK UNIFIED IDEOGRAPH + 0xCE56: 0x873C, //CJK UNIFIED IDEOGRAPH + 0xCE57: 0x873D, //CJK UNIFIED IDEOGRAPH + 0xCE58: 0x8740, //CJK UNIFIED IDEOGRAPH + 0xCE59: 0x8741, //CJK UNIFIED IDEOGRAPH + 0xCE5A: 0x8742, //CJK UNIFIED IDEOGRAPH + 0xCE5B: 0x8743, //CJK UNIFIED IDEOGRAPH + 0xCE5C: 0x8744, //CJK UNIFIED IDEOGRAPH + 0xCE5D: 0x8745, //CJK UNIFIED IDEOGRAPH + 0xCE5E: 0x8746, //CJK UNIFIED IDEOGRAPH + 0xCE5F: 0x874A, //CJK UNIFIED IDEOGRAPH + 0xCE60: 0x874B, //CJK UNIFIED IDEOGRAPH + 0xCE61: 0x874D, //CJK UNIFIED IDEOGRAPH + 0xCE62: 0x874F, //CJK UNIFIED IDEOGRAPH + 0xCE63: 0x8750, //CJK UNIFIED IDEOGRAPH + 0xCE64: 0x8751, //CJK UNIFIED IDEOGRAPH + 0xCE65: 0x8752, //CJK UNIFIED IDEOGRAPH + 0xCE66: 0x8754, //CJK UNIFIED IDEOGRAPH + 0xCE67: 0x8755, //CJK UNIFIED IDEOGRAPH + 0xCE68: 0x8756, //CJK UNIFIED IDEOGRAPH + 0xCE69: 0x8758, //CJK UNIFIED IDEOGRAPH + 0xCE6A: 0x875A, //CJK UNIFIED IDEOGRAPH + 0xCE6B: 0x875B, //CJK UNIFIED IDEOGRAPH + 0xCE6C: 0x875C, //CJK UNIFIED IDEOGRAPH + 0xCE6D: 0x875D, //CJK UNIFIED IDEOGRAPH + 0xCE6E: 0x875E, //CJK UNIFIED IDEOGRAPH + 0xCE6F: 0x875F, //CJK UNIFIED IDEOGRAPH + 0xCE70: 0x8761, //CJK UNIFIED IDEOGRAPH + 0xCE71: 0x8762, //CJK UNIFIED IDEOGRAPH + 0xCE72: 0x8766, //CJK UNIFIED IDEOGRAPH + 0xCE73: 0x8767, //CJK UNIFIED IDEOGRAPH + 0xCE74: 0x8768, //CJK UNIFIED IDEOGRAPH + 0xCE75: 0x8769, //CJK UNIFIED IDEOGRAPH + 0xCE76: 0x876A, //CJK UNIFIED IDEOGRAPH + 0xCE77: 0x876B, //CJK UNIFIED IDEOGRAPH + 0xCE78: 0x876C, //CJK UNIFIED IDEOGRAPH + 0xCE79: 0x876D, //CJK UNIFIED IDEOGRAPH + 0xCE7A: 0x876F, //CJK UNIFIED IDEOGRAPH + 0xCE7B: 0x8771, //CJK UNIFIED IDEOGRAPH + 0xCE7C: 0x8772, //CJK UNIFIED IDEOGRAPH + 0xCE7D: 0x8773, //CJK UNIFIED IDEOGRAPH + 0xCE7E: 0x8775, //CJK UNIFIED IDEOGRAPH + 0xCE80: 0x8777, //CJK UNIFIED IDEOGRAPH + 0xCE81: 0x8778, //CJK UNIFIED IDEOGRAPH + 0xCE82: 0x8779, //CJK UNIFIED IDEOGRAPH + 0xCE83: 0x877A, //CJK UNIFIED IDEOGRAPH + 0xCE84: 0x877F, //CJK UNIFIED IDEOGRAPH + 0xCE85: 0x8780, //CJK UNIFIED IDEOGRAPH + 0xCE86: 0x8781, //CJK UNIFIED IDEOGRAPH + 0xCE87: 0x8784, //CJK UNIFIED IDEOGRAPH + 0xCE88: 0x8786, //CJK UNIFIED IDEOGRAPH + 0xCE89: 0x8787, //CJK UNIFIED IDEOGRAPH + 0xCE8A: 0x8789, //CJK UNIFIED IDEOGRAPH + 0xCE8B: 0x878A, //CJK UNIFIED IDEOGRAPH + 0xCE8C: 0x878C, //CJK UNIFIED IDEOGRAPH + 0xCE8D: 0x878E, //CJK UNIFIED IDEOGRAPH + 0xCE8E: 0x878F, //CJK UNIFIED IDEOGRAPH + 0xCE8F: 0x8790, //CJK UNIFIED IDEOGRAPH + 0xCE90: 0x8791, //CJK UNIFIED IDEOGRAPH + 0xCE91: 0x8792, //CJK UNIFIED IDEOGRAPH + 0xCE92: 0x8794, //CJK UNIFIED IDEOGRAPH + 0xCE93: 0x8795, //CJK UNIFIED IDEOGRAPH + 0xCE94: 0x8796, //CJK UNIFIED IDEOGRAPH + 0xCE95: 0x8798, //CJK UNIFIED IDEOGRAPH + 0xCE96: 0x8799, //CJK UNIFIED IDEOGRAPH + 0xCE97: 0x879A, //CJK UNIFIED IDEOGRAPH + 0xCE98: 0x879B, //CJK UNIFIED IDEOGRAPH + 0xCE99: 0x879C, //CJK UNIFIED IDEOGRAPH + 0xCE9A: 0x879D, //CJK UNIFIED IDEOGRAPH + 0xCE9B: 0x879E, //CJK UNIFIED IDEOGRAPH + 0xCE9C: 0x87A0, //CJK UNIFIED IDEOGRAPH + 0xCE9D: 0x87A1, //CJK UNIFIED IDEOGRAPH + 0xCE9E: 0x87A2, //CJK UNIFIED IDEOGRAPH + 0xCE9F: 0x87A3, //CJK UNIFIED IDEOGRAPH + 0xCEA0: 0x87A4, //CJK UNIFIED IDEOGRAPH + 0xCEA1: 0x5DCD, //CJK UNIFIED IDEOGRAPH + 0xCEA2: 0x5FAE, //CJK UNIFIED IDEOGRAPH + 0xCEA3: 0x5371, //CJK UNIFIED IDEOGRAPH + 0xCEA4: 0x97E6, //CJK UNIFIED IDEOGRAPH + 0xCEA5: 0x8FDD, //CJK UNIFIED IDEOGRAPH + 0xCEA6: 0x6845, //CJK UNIFIED IDEOGRAPH + 0xCEA7: 0x56F4, //CJK UNIFIED IDEOGRAPH + 0xCEA8: 0x552F, //CJK UNIFIED IDEOGRAPH + 0xCEA9: 0x60DF, //CJK UNIFIED IDEOGRAPH + 0xCEAA: 0x4E3A, //CJK UNIFIED IDEOGRAPH + 0xCEAB: 0x6F4D, //CJK UNIFIED IDEOGRAPH + 0xCEAC: 0x7EF4, //CJK UNIFIED IDEOGRAPH + 0xCEAD: 0x82C7, //CJK UNIFIED IDEOGRAPH + 0xCEAE: 0x840E, //CJK UNIFIED IDEOGRAPH + 0xCEAF: 0x59D4, //CJK UNIFIED IDEOGRAPH + 0xCEB0: 0x4F1F, //CJK UNIFIED IDEOGRAPH + 0xCEB1: 0x4F2A, //CJK UNIFIED IDEOGRAPH + 0xCEB2: 0x5C3E, //CJK UNIFIED IDEOGRAPH + 0xCEB3: 0x7EAC, //CJK UNIFIED IDEOGRAPH + 0xCEB4: 0x672A, //CJK UNIFIED IDEOGRAPH + 0xCEB5: 0x851A, //CJK UNIFIED IDEOGRAPH + 0xCEB6: 0x5473, //CJK UNIFIED IDEOGRAPH + 0xCEB7: 0x754F, //CJK UNIFIED IDEOGRAPH + 0xCEB8: 0x80C3, //CJK UNIFIED IDEOGRAPH + 0xCEB9: 0x5582, //CJK UNIFIED IDEOGRAPH + 0xCEBA: 0x9B4F, //CJK UNIFIED IDEOGRAPH + 0xCEBB: 0x4F4D, //CJK UNIFIED IDEOGRAPH + 0xCEBC: 0x6E2D, //CJK UNIFIED IDEOGRAPH + 0xCEBD: 0x8C13, //CJK UNIFIED IDEOGRAPH + 0xCEBE: 0x5C09, //CJK UNIFIED IDEOGRAPH + 0xCEBF: 0x6170, //CJK UNIFIED IDEOGRAPH + 0xCEC0: 0x536B, //CJK UNIFIED IDEOGRAPH + 0xCEC1: 0x761F, //CJK UNIFIED IDEOGRAPH + 0xCEC2: 0x6E29, //CJK UNIFIED IDEOGRAPH + 0xCEC3: 0x868A, //CJK UNIFIED IDEOGRAPH + 0xCEC4: 0x6587, //CJK UNIFIED IDEOGRAPH + 0xCEC5: 0x95FB, //CJK UNIFIED IDEOGRAPH + 0xCEC6: 0x7EB9, //CJK UNIFIED IDEOGRAPH + 0xCEC7: 0x543B, //CJK UNIFIED IDEOGRAPH + 0xCEC8: 0x7A33, //CJK UNIFIED IDEOGRAPH + 0xCEC9: 0x7D0A, //CJK UNIFIED IDEOGRAPH + 0xCECA: 0x95EE, //CJK UNIFIED IDEOGRAPH + 0xCECB: 0x55E1, //CJK UNIFIED IDEOGRAPH + 0xCECC: 0x7FC1, //CJK UNIFIED IDEOGRAPH + 0xCECD: 0x74EE, //CJK UNIFIED IDEOGRAPH + 0xCECE: 0x631D, //CJK UNIFIED IDEOGRAPH + 0xCECF: 0x8717, //CJK UNIFIED IDEOGRAPH + 0xCED0: 0x6DA1, //CJK UNIFIED IDEOGRAPH + 0xCED1: 0x7A9D, //CJK UNIFIED IDEOGRAPH + 0xCED2: 0x6211, //CJK UNIFIED IDEOGRAPH + 0xCED3: 0x65A1, //CJK UNIFIED IDEOGRAPH + 0xCED4: 0x5367, //CJK UNIFIED IDEOGRAPH + 0xCED5: 0x63E1, //CJK UNIFIED IDEOGRAPH + 0xCED6: 0x6C83, //CJK UNIFIED IDEOGRAPH + 0xCED7: 0x5DEB, //CJK UNIFIED IDEOGRAPH + 0xCED8: 0x545C, //CJK UNIFIED IDEOGRAPH + 0xCED9: 0x94A8, //CJK UNIFIED IDEOGRAPH + 0xCEDA: 0x4E4C, //CJK UNIFIED IDEOGRAPH + 0xCEDB: 0x6C61, //CJK UNIFIED IDEOGRAPH + 0xCEDC: 0x8BEC, //CJK UNIFIED IDEOGRAPH + 0xCEDD: 0x5C4B, //CJK UNIFIED IDEOGRAPH + 0xCEDE: 0x65E0, //CJK UNIFIED IDEOGRAPH + 0xCEDF: 0x829C, //CJK UNIFIED IDEOGRAPH + 0xCEE0: 0x68A7, //CJK UNIFIED IDEOGRAPH + 0xCEE1: 0x543E, //CJK UNIFIED IDEOGRAPH + 0xCEE2: 0x5434, //CJK UNIFIED IDEOGRAPH + 0xCEE3: 0x6BCB, //CJK UNIFIED IDEOGRAPH + 0xCEE4: 0x6B66, //CJK UNIFIED IDEOGRAPH + 0xCEE5: 0x4E94, //CJK UNIFIED IDEOGRAPH + 0xCEE6: 0x6342, //CJK UNIFIED IDEOGRAPH + 0xCEE7: 0x5348, //CJK UNIFIED IDEOGRAPH + 0xCEE8: 0x821E, //CJK UNIFIED IDEOGRAPH + 0xCEE9: 0x4F0D, //CJK UNIFIED IDEOGRAPH + 0xCEEA: 0x4FAE, //CJK UNIFIED IDEOGRAPH + 0xCEEB: 0x575E, //CJK UNIFIED IDEOGRAPH + 0xCEEC: 0x620A, //CJK UNIFIED IDEOGRAPH + 0xCEED: 0x96FE, //CJK UNIFIED IDEOGRAPH + 0xCEEE: 0x6664, //CJK UNIFIED IDEOGRAPH + 0xCEEF: 0x7269, //CJK UNIFIED IDEOGRAPH + 0xCEF0: 0x52FF, //CJK UNIFIED IDEOGRAPH + 0xCEF1: 0x52A1, //CJK UNIFIED IDEOGRAPH + 0xCEF2: 0x609F, //CJK UNIFIED IDEOGRAPH + 0xCEF3: 0x8BEF, //CJK UNIFIED IDEOGRAPH + 0xCEF4: 0x6614, //CJK UNIFIED IDEOGRAPH + 0xCEF5: 0x7199, //CJK UNIFIED IDEOGRAPH + 0xCEF6: 0x6790, //CJK UNIFIED IDEOGRAPH + 0xCEF7: 0x897F, //CJK UNIFIED IDEOGRAPH + 0xCEF8: 0x7852, //CJK UNIFIED IDEOGRAPH + 0xCEF9: 0x77FD, //CJK UNIFIED IDEOGRAPH + 0xCEFA: 0x6670, //CJK UNIFIED IDEOGRAPH + 0xCEFB: 0x563B, //CJK UNIFIED IDEOGRAPH + 0xCEFC: 0x5438, //CJK UNIFIED IDEOGRAPH + 0xCEFD: 0x9521, //CJK UNIFIED IDEOGRAPH + 0xCEFE: 0x727A, //CJK UNIFIED IDEOGRAPH + 0xCF40: 0x87A5, //CJK UNIFIED IDEOGRAPH + 0xCF41: 0x87A6, //CJK UNIFIED IDEOGRAPH + 0xCF42: 0x87A7, //CJK UNIFIED IDEOGRAPH + 0xCF43: 0x87A9, //CJK UNIFIED IDEOGRAPH + 0xCF44: 0x87AA, //CJK UNIFIED IDEOGRAPH + 0xCF45: 0x87AE, //CJK UNIFIED IDEOGRAPH + 0xCF46: 0x87B0, //CJK UNIFIED IDEOGRAPH + 0xCF47: 0x87B1, //CJK UNIFIED IDEOGRAPH + 0xCF48: 0x87B2, //CJK UNIFIED IDEOGRAPH + 0xCF49: 0x87B4, //CJK UNIFIED IDEOGRAPH + 0xCF4A: 0x87B6, //CJK UNIFIED IDEOGRAPH + 0xCF4B: 0x87B7, //CJK UNIFIED IDEOGRAPH + 0xCF4C: 0x87B8, //CJK UNIFIED IDEOGRAPH + 0xCF4D: 0x87B9, //CJK UNIFIED IDEOGRAPH + 0xCF4E: 0x87BB, //CJK UNIFIED IDEOGRAPH + 0xCF4F: 0x87BC, //CJK UNIFIED IDEOGRAPH + 0xCF50: 0x87BE, //CJK UNIFIED IDEOGRAPH + 0xCF51: 0x87BF, //CJK UNIFIED IDEOGRAPH + 0xCF52: 0x87C1, //CJK UNIFIED IDEOGRAPH + 0xCF53: 0x87C2, //CJK UNIFIED IDEOGRAPH + 0xCF54: 0x87C3, //CJK UNIFIED IDEOGRAPH + 0xCF55: 0x87C4, //CJK UNIFIED IDEOGRAPH + 0xCF56: 0x87C5, //CJK UNIFIED IDEOGRAPH + 0xCF57: 0x87C7, //CJK UNIFIED IDEOGRAPH + 0xCF58: 0x87C8, //CJK UNIFIED IDEOGRAPH + 0xCF59: 0x87C9, //CJK UNIFIED IDEOGRAPH + 0xCF5A: 0x87CC, //CJK UNIFIED IDEOGRAPH + 0xCF5B: 0x87CD, //CJK UNIFIED IDEOGRAPH + 0xCF5C: 0x87CE, //CJK UNIFIED IDEOGRAPH + 0xCF5D: 0x87CF, //CJK UNIFIED IDEOGRAPH + 0xCF5E: 0x87D0, //CJK UNIFIED IDEOGRAPH + 0xCF5F: 0x87D4, //CJK UNIFIED IDEOGRAPH + 0xCF60: 0x87D5, //CJK UNIFIED IDEOGRAPH + 0xCF61: 0x87D6, //CJK UNIFIED IDEOGRAPH + 0xCF62: 0x87D7, //CJK UNIFIED IDEOGRAPH + 0xCF63: 0x87D8, //CJK UNIFIED IDEOGRAPH + 0xCF64: 0x87D9, //CJK UNIFIED IDEOGRAPH + 0xCF65: 0x87DA, //CJK UNIFIED IDEOGRAPH + 0xCF66: 0x87DC, //CJK UNIFIED IDEOGRAPH + 0xCF67: 0x87DD, //CJK UNIFIED IDEOGRAPH + 0xCF68: 0x87DE, //CJK UNIFIED IDEOGRAPH + 0xCF69: 0x87DF, //CJK UNIFIED IDEOGRAPH + 0xCF6A: 0x87E1, //CJK UNIFIED IDEOGRAPH + 0xCF6B: 0x87E2, //CJK UNIFIED IDEOGRAPH + 0xCF6C: 0x87E3, //CJK UNIFIED IDEOGRAPH + 0xCF6D: 0x87E4, //CJK UNIFIED IDEOGRAPH + 0xCF6E: 0x87E6, //CJK UNIFIED IDEOGRAPH + 0xCF6F: 0x87E7, //CJK UNIFIED IDEOGRAPH + 0xCF70: 0x87E8, //CJK UNIFIED IDEOGRAPH + 0xCF71: 0x87E9, //CJK UNIFIED IDEOGRAPH + 0xCF72: 0x87EB, //CJK UNIFIED IDEOGRAPH + 0xCF73: 0x87EC, //CJK UNIFIED IDEOGRAPH + 0xCF74: 0x87ED, //CJK UNIFIED IDEOGRAPH + 0xCF75: 0x87EF, //CJK UNIFIED IDEOGRAPH + 0xCF76: 0x87F0, //CJK UNIFIED IDEOGRAPH + 0xCF77: 0x87F1, //CJK UNIFIED IDEOGRAPH + 0xCF78: 0x87F2, //CJK UNIFIED IDEOGRAPH + 0xCF79: 0x87F3, //CJK UNIFIED IDEOGRAPH + 0xCF7A: 0x87F4, //CJK UNIFIED IDEOGRAPH + 0xCF7B: 0x87F5, //CJK UNIFIED IDEOGRAPH + 0xCF7C: 0x87F6, //CJK UNIFIED IDEOGRAPH + 0xCF7D: 0x87F7, //CJK UNIFIED IDEOGRAPH + 0xCF7E: 0x87F8, //CJK UNIFIED IDEOGRAPH + 0xCF80: 0x87FA, //CJK UNIFIED IDEOGRAPH + 0xCF81: 0x87FB, //CJK UNIFIED IDEOGRAPH + 0xCF82: 0x87FC, //CJK UNIFIED IDEOGRAPH + 0xCF83: 0x87FD, //CJK UNIFIED IDEOGRAPH + 0xCF84: 0x87FF, //CJK UNIFIED IDEOGRAPH + 0xCF85: 0x8800, //CJK UNIFIED IDEOGRAPH + 0xCF86: 0x8801, //CJK UNIFIED IDEOGRAPH + 0xCF87: 0x8802, //CJK UNIFIED IDEOGRAPH + 0xCF88: 0x8804, //CJK UNIFIED IDEOGRAPH + 0xCF89: 0x8805, //CJK UNIFIED IDEOGRAPH + 0xCF8A: 0x8806, //CJK UNIFIED IDEOGRAPH + 0xCF8B: 0x8807, //CJK UNIFIED IDEOGRAPH + 0xCF8C: 0x8808, //CJK UNIFIED IDEOGRAPH + 0xCF8D: 0x8809, //CJK UNIFIED IDEOGRAPH + 0xCF8E: 0x880B, //CJK UNIFIED IDEOGRAPH + 0xCF8F: 0x880C, //CJK UNIFIED IDEOGRAPH + 0xCF90: 0x880D, //CJK UNIFIED IDEOGRAPH + 0xCF91: 0x880E, //CJK UNIFIED IDEOGRAPH + 0xCF92: 0x880F, //CJK UNIFIED IDEOGRAPH + 0xCF93: 0x8810, //CJK UNIFIED IDEOGRAPH + 0xCF94: 0x8811, //CJK UNIFIED IDEOGRAPH + 0xCF95: 0x8812, //CJK UNIFIED IDEOGRAPH + 0xCF96: 0x8814, //CJK UNIFIED IDEOGRAPH + 0xCF97: 0x8817, //CJK UNIFIED IDEOGRAPH + 0xCF98: 0x8818, //CJK UNIFIED IDEOGRAPH + 0xCF99: 0x8819, //CJK UNIFIED IDEOGRAPH + 0xCF9A: 0x881A, //CJK UNIFIED IDEOGRAPH + 0xCF9B: 0x881C, //CJK UNIFIED IDEOGRAPH + 0xCF9C: 0x881D, //CJK UNIFIED IDEOGRAPH + 0xCF9D: 0x881E, //CJK UNIFIED IDEOGRAPH + 0xCF9E: 0x881F, //CJK UNIFIED IDEOGRAPH + 0xCF9F: 0x8820, //CJK UNIFIED IDEOGRAPH + 0xCFA0: 0x8823, //CJK UNIFIED IDEOGRAPH + 0xCFA1: 0x7A00, //CJK UNIFIED IDEOGRAPH + 0xCFA2: 0x606F, //CJK UNIFIED IDEOGRAPH + 0xCFA3: 0x5E0C, //CJK UNIFIED IDEOGRAPH + 0xCFA4: 0x6089, //CJK UNIFIED IDEOGRAPH + 0xCFA5: 0x819D, //CJK UNIFIED IDEOGRAPH + 0xCFA6: 0x5915, //CJK UNIFIED IDEOGRAPH + 0xCFA7: 0x60DC, //CJK UNIFIED IDEOGRAPH + 0xCFA8: 0x7184, //CJK UNIFIED IDEOGRAPH + 0xCFA9: 0x70EF, //CJK UNIFIED IDEOGRAPH + 0xCFAA: 0x6EAA, //CJK UNIFIED IDEOGRAPH + 0xCFAB: 0x6C50, //CJK UNIFIED IDEOGRAPH + 0xCFAC: 0x7280, //CJK UNIFIED IDEOGRAPH + 0xCFAD: 0x6A84, //CJK UNIFIED IDEOGRAPH + 0xCFAE: 0x88AD, //CJK UNIFIED IDEOGRAPH + 0xCFAF: 0x5E2D, //CJK UNIFIED IDEOGRAPH + 0xCFB0: 0x4E60, //CJK UNIFIED IDEOGRAPH + 0xCFB1: 0x5AB3, //CJK UNIFIED IDEOGRAPH + 0xCFB2: 0x559C, //CJK UNIFIED IDEOGRAPH + 0xCFB3: 0x94E3, //CJK UNIFIED IDEOGRAPH + 0xCFB4: 0x6D17, //CJK UNIFIED IDEOGRAPH + 0xCFB5: 0x7CFB, //CJK UNIFIED IDEOGRAPH + 0xCFB6: 0x9699, //CJK UNIFIED IDEOGRAPH + 0xCFB7: 0x620F, //CJK UNIFIED IDEOGRAPH + 0xCFB8: 0x7EC6, //CJK UNIFIED IDEOGRAPH + 0xCFB9: 0x778E, //CJK UNIFIED IDEOGRAPH + 0xCFBA: 0x867E, //CJK UNIFIED IDEOGRAPH + 0xCFBB: 0x5323, //CJK UNIFIED IDEOGRAPH + 0xCFBC: 0x971E, //CJK UNIFIED IDEOGRAPH + 0xCFBD: 0x8F96, //CJK UNIFIED IDEOGRAPH + 0xCFBE: 0x6687, //CJK UNIFIED IDEOGRAPH + 0xCFBF: 0x5CE1, //CJK UNIFIED IDEOGRAPH + 0xCFC0: 0x4FA0, //CJK UNIFIED IDEOGRAPH + 0xCFC1: 0x72ED, //CJK UNIFIED IDEOGRAPH + 0xCFC2: 0x4E0B, //CJK UNIFIED IDEOGRAPH + 0xCFC3: 0x53A6, //CJK UNIFIED IDEOGRAPH + 0xCFC4: 0x590F, //CJK UNIFIED IDEOGRAPH + 0xCFC5: 0x5413, //CJK UNIFIED IDEOGRAPH + 0xCFC6: 0x6380, //CJK UNIFIED IDEOGRAPH + 0xCFC7: 0x9528, //CJK UNIFIED IDEOGRAPH + 0xCFC8: 0x5148, //CJK UNIFIED IDEOGRAPH + 0xCFC9: 0x4ED9, //CJK UNIFIED IDEOGRAPH + 0xCFCA: 0x9C9C, //CJK UNIFIED IDEOGRAPH + 0xCFCB: 0x7EA4, //CJK UNIFIED IDEOGRAPH + 0xCFCC: 0x54B8, //CJK UNIFIED IDEOGRAPH + 0xCFCD: 0x8D24, //CJK UNIFIED IDEOGRAPH + 0xCFCE: 0x8854, //CJK UNIFIED IDEOGRAPH + 0xCFCF: 0x8237, //CJK UNIFIED IDEOGRAPH + 0xCFD0: 0x95F2, //CJK UNIFIED IDEOGRAPH + 0xCFD1: 0x6D8E, //CJK UNIFIED IDEOGRAPH + 0xCFD2: 0x5F26, //CJK UNIFIED IDEOGRAPH + 0xCFD3: 0x5ACC, //CJK UNIFIED IDEOGRAPH + 0xCFD4: 0x663E, //CJK UNIFIED IDEOGRAPH + 0xCFD5: 0x9669, //CJK UNIFIED IDEOGRAPH + 0xCFD6: 0x73B0, //CJK UNIFIED IDEOGRAPH + 0xCFD7: 0x732E, //CJK UNIFIED IDEOGRAPH + 0xCFD8: 0x53BF, //CJK UNIFIED IDEOGRAPH + 0xCFD9: 0x817A, //CJK UNIFIED IDEOGRAPH + 0xCFDA: 0x9985, //CJK UNIFIED IDEOGRAPH + 0xCFDB: 0x7FA1, //CJK UNIFIED IDEOGRAPH + 0xCFDC: 0x5BAA, //CJK UNIFIED IDEOGRAPH + 0xCFDD: 0x9677, //CJK UNIFIED IDEOGRAPH + 0xCFDE: 0x9650, //CJK UNIFIED IDEOGRAPH + 0xCFDF: 0x7EBF, //CJK UNIFIED IDEOGRAPH + 0xCFE0: 0x76F8, //CJK UNIFIED IDEOGRAPH + 0xCFE1: 0x53A2, //CJK UNIFIED IDEOGRAPH + 0xCFE2: 0x9576, //CJK UNIFIED IDEOGRAPH + 0xCFE3: 0x9999, //CJK UNIFIED IDEOGRAPH + 0xCFE4: 0x7BB1, //CJK UNIFIED IDEOGRAPH + 0xCFE5: 0x8944, //CJK UNIFIED IDEOGRAPH + 0xCFE6: 0x6E58, //CJK UNIFIED IDEOGRAPH + 0xCFE7: 0x4E61, //CJK UNIFIED IDEOGRAPH + 0xCFE8: 0x7FD4, //CJK UNIFIED IDEOGRAPH + 0xCFE9: 0x7965, //CJK UNIFIED IDEOGRAPH + 0xCFEA: 0x8BE6, //CJK UNIFIED IDEOGRAPH + 0xCFEB: 0x60F3, //CJK UNIFIED IDEOGRAPH + 0xCFEC: 0x54CD, //CJK UNIFIED IDEOGRAPH + 0xCFED: 0x4EAB, //CJK UNIFIED IDEOGRAPH + 0xCFEE: 0x9879, //CJK UNIFIED IDEOGRAPH + 0xCFEF: 0x5DF7, //CJK UNIFIED IDEOGRAPH + 0xCFF0: 0x6A61, //CJK UNIFIED IDEOGRAPH + 0xCFF1: 0x50CF, //CJK UNIFIED IDEOGRAPH + 0xCFF2: 0x5411, //CJK UNIFIED IDEOGRAPH + 0xCFF3: 0x8C61, //CJK UNIFIED IDEOGRAPH + 0xCFF4: 0x8427, //CJK UNIFIED IDEOGRAPH + 0xCFF5: 0x785D, //CJK UNIFIED IDEOGRAPH + 0xCFF6: 0x9704, //CJK UNIFIED IDEOGRAPH + 0xCFF7: 0x524A, //CJK UNIFIED IDEOGRAPH + 0xCFF8: 0x54EE, //CJK UNIFIED IDEOGRAPH + 0xCFF9: 0x56A3, //CJK UNIFIED IDEOGRAPH + 0xCFFA: 0x9500, //CJK UNIFIED IDEOGRAPH + 0xCFFB: 0x6D88, //CJK UNIFIED IDEOGRAPH + 0xCFFC: 0x5BB5, //CJK UNIFIED IDEOGRAPH + 0xCFFD: 0x6DC6, //CJK UNIFIED IDEOGRAPH + 0xCFFE: 0x6653, //CJK UNIFIED IDEOGRAPH + 0xD040: 0x8824, //CJK UNIFIED IDEOGRAPH + 0xD041: 0x8825, //CJK UNIFIED IDEOGRAPH + 0xD042: 0x8826, //CJK UNIFIED IDEOGRAPH + 0xD043: 0x8827, //CJK UNIFIED IDEOGRAPH + 0xD044: 0x8828, //CJK UNIFIED IDEOGRAPH + 0xD045: 0x8829, //CJK UNIFIED IDEOGRAPH + 0xD046: 0x882A, //CJK UNIFIED IDEOGRAPH + 0xD047: 0x882B, //CJK UNIFIED IDEOGRAPH + 0xD048: 0x882C, //CJK UNIFIED IDEOGRAPH + 0xD049: 0x882D, //CJK UNIFIED IDEOGRAPH + 0xD04A: 0x882E, //CJK UNIFIED IDEOGRAPH + 0xD04B: 0x882F, //CJK UNIFIED IDEOGRAPH + 0xD04C: 0x8830, //CJK UNIFIED IDEOGRAPH + 0xD04D: 0x8831, //CJK UNIFIED IDEOGRAPH + 0xD04E: 0x8833, //CJK UNIFIED IDEOGRAPH + 0xD04F: 0x8834, //CJK UNIFIED IDEOGRAPH + 0xD050: 0x8835, //CJK UNIFIED IDEOGRAPH + 0xD051: 0x8836, //CJK UNIFIED IDEOGRAPH + 0xD052: 0x8837, //CJK UNIFIED IDEOGRAPH + 0xD053: 0x8838, //CJK UNIFIED IDEOGRAPH + 0xD054: 0x883A, //CJK UNIFIED IDEOGRAPH + 0xD055: 0x883B, //CJK UNIFIED IDEOGRAPH + 0xD056: 0x883D, //CJK UNIFIED IDEOGRAPH + 0xD057: 0x883E, //CJK UNIFIED IDEOGRAPH + 0xD058: 0x883F, //CJK UNIFIED IDEOGRAPH + 0xD059: 0x8841, //CJK UNIFIED IDEOGRAPH + 0xD05A: 0x8842, //CJK UNIFIED IDEOGRAPH + 0xD05B: 0x8843, //CJK UNIFIED IDEOGRAPH + 0xD05C: 0x8846, //CJK UNIFIED IDEOGRAPH + 0xD05D: 0x8847, //CJK UNIFIED IDEOGRAPH + 0xD05E: 0x8848, //CJK UNIFIED IDEOGRAPH + 0xD05F: 0x8849, //CJK UNIFIED IDEOGRAPH + 0xD060: 0x884A, //CJK UNIFIED IDEOGRAPH + 0xD061: 0x884B, //CJK UNIFIED IDEOGRAPH + 0xD062: 0x884E, //CJK UNIFIED IDEOGRAPH + 0xD063: 0x884F, //CJK UNIFIED IDEOGRAPH + 0xD064: 0x8850, //CJK UNIFIED IDEOGRAPH + 0xD065: 0x8851, //CJK UNIFIED IDEOGRAPH + 0xD066: 0x8852, //CJK UNIFIED IDEOGRAPH + 0xD067: 0x8853, //CJK UNIFIED IDEOGRAPH + 0xD068: 0x8855, //CJK UNIFIED IDEOGRAPH + 0xD069: 0x8856, //CJK UNIFIED IDEOGRAPH + 0xD06A: 0x8858, //CJK UNIFIED IDEOGRAPH + 0xD06B: 0x885A, //CJK UNIFIED IDEOGRAPH + 0xD06C: 0x885B, //CJK UNIFIED IDEOGRAPH + 0xD06D: 0x885C, //CJK UNIFIED IDEOGRAPH + 0xD06E: 0x885D, //CJK UNIFIED IDEOGRAPH + 0xD06F: 0x885E, //CJK UNIFIED IDEOGRAPH + 0xD070: 0x885F, //CJK UNIFIED IDEOGRAPH + 0xD071: 0x8860, //CJK UNIFIED IDEOGRAPH + 0xD072: 0x8866, //CJK UNIFIED IDEOGRAPH + 0xD073: 0x8867, //CJK UNIFIED IDEOGRAPH + 0xD074: 0x886A, //CJK UNIFIED IDEOGRAPH + 0xD075: 0x886D, //CJK UNIFIED IDEOGRAPH + 0xD076: 0x886F, //CJK UNIFIED IDEOGRAPH + 0xD077: 0x8871, //CJK UNIFIED IDEOGRAPH + 0xD078: 0x8873, //CJK UNIFIED IDEOGRAPH + 0xD079: 0x8874, //CJK UNIFIED IDEOGRAPH + 0xD07A: 0x8875, //CJK UNIFIED IDEOGRAPH + 0xD07B: 0x8876, //CJK UNIFIED IDEOGRAPH + 0xD07C: 0x8878, //CJK UNIFIED IDEOGRAPH + 0xD07D: 0x8879, //CJK UNIFIED IDEOGRAPH + 0xD07E: 0x887A, //CJK UNIFIED IDEOGRAPH + 0xD080: 0x887B, //CJK UNIFIED IDEOGRAPH + 0xD081: 0x887C, //CJK UNIFIED IDEOGRAPH + 0xD082: 0x8880, //CJK UNIFIED IDEOGRAPH + 0xD083: 0x8883, //CJK UNIFIED IDEOGRAPH + 0xD084: 0x8886, //CJK UNIFIED IDEOGRAPH + 0xD085: 0x8887, //CJK UNIFIED IDEOGRAPH + 0xD086: 0x8889, //CJK UNIFIED IDEOGRAPH + 0xD087: 0x888A, //CJK UNIFIED IDEOGRAPH + 0xD088: 0x888C, //CJK UNIFIED IDEOGRAPH + 0xD089: 0x888E, //CJK UNIFIED IDEOGRAPH + 0xD08A: 0x888F, //CJK UNIFIED IDEOGRAPH + 0xD08B: 0x8890, //CJK UNIFIED IDEOGRAPH + 0xD08C: 0x8891, //CJK UNIFIED IDEOGRAPH + 0xD08D: 0x8893, //CJK UNIFIED IDEOGRAPH + 0xD08E: 0x8894, //CJK UNIFIED IDEOGRAPH + 0xD08F: 0x8895, //CJK UNIFIED IDEOGRAPH + 0xD090: 0x8897, //CJK UNIFIED IDEOGRAPH + 0xD091: 0x8898, //CJK UNIFIED IDEOGRAPH + 0xD092: 0x8899, //CJK UNIFIED IDEOGRAPH + 0xD093: 0x889A, //CJK UNIFIED IDEOGRAPH + 0xD094: 0x889B, //CJK UNIFIED IDEOGRAPH + 0xD095: 0x889D, //CJK UNIFIED IDEOGRAPH + 0xD096: 0x889E, //CJK UNIFIED IDEOGRAPH + 0xD097: 0x889F, //CJK UNIFIED IDEOGRAPH + 0xD098: 0x88A0, //CJK UNIFIED IDEOGRAPH + 0xD099: 0x88A1, //CJK UNIFIED IDEOGRAPH + 0xD09A: 0x88A3, //CJK UNIFIED IDEOGRAPH + 0xD09B: 0x88A5, //CJK UNIFIED IDEOGRAPH + 0xD09C: 0x88A6, //CJK UNIFIED IDEOGRAPH + 0xD09D: 0x88A7, //CJK UNIFIED IDEOGRAPH + 0xD09E: 0x88A8, //CJK UNIFIED IDEOGRAPH + 0xD09F: 0x88A9, //CJK UNIFIED IDEOGRAPH + 0xD0A0: 0x88AA, //CJK UNIFIED IDEOGRAPH + 0xD0A1: 0x5C0F, //CJK UNIFIED IDEOGRAPH + 0xD0A2: 0x5B5D, //CJK UNIFIED IDEOGRAPH + 0xD0A3: 0x6821, //CJK UNIFIED IDEOGRAPH + 0xD0A4: 0x8096, //CJK UNIFIED IDEOGRAPH + 0xD0A5: 0x5578, //CJK UNIFIED IDEOGRAPH + 0xD0A6: 0x7B11, //CJK UNIFIED IDEOGRAPH + 0xD0A7: 0x6548, //CJK UNIFIED IDEOGRAPH + 0xD0A8: 0x6954, //CJK UNIFIED IDEOGRAPH + 0xD0A9: 0x4E9B, //CJK UNIFIED IDEOGRAPH + 0xD0AA: 0x6B47, //CJK UNIFIED IDEOGRAPH + 0xD0AB: 0x874E, //CJK UNIFIED IDEOGRAPH + 0xD0AC: 0x978B, //CJK UNIFIED IDEOGRAPH + 0xD0AD: 0x534F, //CJK UNIFIED IDEOGRAPH + 0xD0AE: 0x631F, //CJK UNIFIED IDEOGRAPH + 0xD0AF: 0x643A, //CJK UNIFIED IDEOGRAPH + 0xD0B0: 0x90AA, //CJK UNIFIED IDEOGRAPH + 0xD0B1: 0x659C, //CJK UNIFIED IDEOGRAPH + 0xD0B2: 0x80C1, //CJK UNIFIED IDEOGRAPH + 0xD0B3: 0x8C10, //CJK UNIFIED IDEOGRAPH + 0xD0B4: 0x5199, //CJK UNIFIED IDEOGRAPH + 0xD0B5: 0x68B0, //CJK UNIFIED IDEOGRAPH + 0xD0B6: 0x5378, //CJK UNIFIED IDEOGRAPH + 0xD0B7: 0x87F9, //CJK UNIFIED IDEOGRAPH + 0xD0B8: 0x61C8, //CJK UNIFIED IDEOGRAPH + 0xD0B9: 0x6CC4, //CJK UNIFIED IDEOGRAPH + 0xD0BA: 0x6CFB, //CJK UNIFIED IDEOGRAPH + 0xD0BB: 0x8C22, //CJK UNIFIED IDEOGRAPH + 0xD0BC: 0x5C51, //CJK UNIFIED IDEOGRAPH + 0xD0BD: 0x85AA, //CJK UNIFIED IDEOGRAPH + 0xD0BE: 0x82AF, //CJK UNIFIED IDEOGRAPH + 0xD0BF: 0x950C, //CJK UNIFIED IDEOGRAPH + 0xD0C0: 0x6B23, //CJK UNIFIED IDEOGRAPH + 0xD0C1: 0x8F9B, //CJK UNIFIED IDEOGRAPH + 0xD0C2: 0x65B0, //CJK UNIFIED IDEOGRAPH + 0xD0C3: 0x5FFB, //CJK UNIFIED IDEOGRAPH + 0xD0C4: 0x5FC3, //CJK UNIFIED IDEOGRAPH + 0xD0C5: 0x4FE1, //CJK UNIFIED IDEOGRAPH + 0xD0C6: 0x8845, //CJK UNIFIED IDEOGRAPH + 0xD0C7: 0x661F, //CJK UNIFIED IDEOGRAPH + 0xD0C8: 0x8165, //CJK UNIFIED IDEOGRAPH + 0xD0C9: 0x7329, //CJK UNIFIED IDEOGRAPH + 0xD0CA: 0x60FA, //CJK UNIFIED IDEOGRAPH + 0xD0CB: 0x5174, //CJK UNIFIED IDEOGRAPH + 0xD0CC: 0x5211, //CJK UNIFIED IDEOGRAPH + 0xD0CD: 0x578B, //CJK UNIFIED IDEOGRAPH + 0xD0CE: 0x5F62, //CJK UNIFIED IDEOGRAPH + 0xD0CF: 0x90A2, //CJK UNIFIED IDEOGRAPH + 0xD0D0: 0x884C, //CJK UNIFIED IDEOGRAPH + 0xD0D1: 0x9192, //CJK UNIFIED IDEOGRAPH + 0xD0D2: 0x5E78, //CJK UNIFIED IDEOGRAPH + 0xD0D3: 0x674F, //CJK UNIFIED IDEOGRAPH + 0xD0D4: 0x6027, //CJK UNIFIED IDEOGRAPH + 0xD0D5: 0x59D3, //CJK UNIFIED IDEOGRAPH + 0xD0D6: 0x5144, //CJK UNIFIED IDEOGRAPH + 0xD0D7: 0x51F6, //CJK UNIFIED IDEOGRAPH + 0xD0D8: 0x80F8, //CJK UNIFIED IDEOGRAPH + 0xD0D9: 0x5308, //CJK UNIFIED IDEOGRAPH + 0xD0DA: 0x6C79, //CJK UNIFIED IDEOGRAPH + 0xD0DB: 0x96C4, //CJK UNIFIED IDEOGRAPH + 0xD0DC: 0x718A, //CJK UNIFIED IDEOGRAPH + 0xD0DD: 0x4F11, //CJK UNIFIED IDEOGRAPH + 0xD0DE: 0x4FEE, //CJK UNIFIED IDEOGRAPH + 0xD0DF: 0x7F9E, //CJK UNIFIED IDEOGRAPH + 0xD0E0: 0x673D, //CJK UNIFIED IDEOGRAPH + 0xD0E1: 0x55C5, //CJK UNIFIED IDEOGRAPH + 0xD0E2: 0x9508, //CJK UNIFIED IDEOGRAPH + 0xD0E3: 0x79C0, //CJK UNIFIED IDEOGRAPH + 0xD0E4: 0x8896, //CJK UNIFIED IDEOGRAPH + 0xD0E5: 0x7EE3, //CJK UNIFIED IDEOGRAPH + 0xD0E6: 0x589F, //CJK UNIFIED IDEOGRAPH + 0xD0E7: 0x620C, //CJK UNIFIED IDEOGRAPH + 0xD0E8: 0x9700, //CJK UNIFIED IDEOGRAPH + 0xD0E9: 0x865A, //CJK UNIFIED IDEOGRAPH + 0xD0EA: 0x5618, //CJK UNIFIED IDEOGRAPH + 0xD0EB: 0x987B, //CJK UNIFIED IDEOGRAPH + 0xD0EC: 0x5F90, //CJK UNIFIED IDEOGRAPH + 0xD0ED: 0x8BB8, //CJK UNIFIED IDEOGRAPH + 0xD0EE: 0x84C4, //CJK UNIFIED IDEOGRAPH + 0xD0EF: 0x9157, //CJK UNIFIED IDEOGRAPH + 0xD0F0: 0x53D9, //CJK UNIFIED IDEOGRAPH + 0xD0F1: 0x65ED, //CJK UNIFIED IDEOGRAPH + 0xD0F2: 0x5E8F, //CJK UNIFIED IDEOGRAPH + 0xD0F3: 0x755C, //CJK UNIFIED IDEOGRAPH + 0xD0F4: 0x6064, //CJK UNIFIED IDEOGRAPH + 0xD0F5: 0x7D6E, //CJK UNIFIED IDEOGRAPH + 0xD0F6: 0x5A7F, //CJK UNIFIED IDEOGRAPH + 0xD0F7: 0x7EEA, //CJK UNIFIED IDEOGRAPH + 0xD0F8: 0x7EED, //CJK UNIFIED IDEOGRAPH + 0xD0F9: 0x8F69, //CJK UNIFIED IDEOGRAPH + 0xD0FA: 0x55A7, //CJK UNIFIED IDEOGRAPH + 0xD0FB: 0x5BA3, //CJK UNIFIED IDEOGRAPH + 0xD0FC: 0x60AC, //CJK UNIFIED IDEOGRAPH + 0xD0FD: 0x65CB, //CJK UNIFIED IDEOGRAPH + 0xD0FE: 0x7384, //CJK UNIFIED IDEOGRAPH + 0xD140: 0x88AC, //CJK UNIFIED IDEOGRAPH + 0xD141: 0x88AE, //CJK UNIFIED IDEOGRAPH + 0xD142: 0x88AF, //CJK UNIFIED IDEOGRAPH + 0xD143: 0x88B0, //CJK UNIFIED IDEOGRAPH + 0xD144: 0x88B2, //CJK UNIFIED IDEOGRAPH + 0xD145: 0x88B3, //CJK UNIFIED IDEOGRAPH + 0xD146: 0x88B4, //CJK UNIFIED IDEOGRAPH + 0xD147: 0x88B5, //CJK UNIFIED IDEOGRAPH + 0xD148: 0x88B6, //CJK UNIFIED IDEOGRAPH + 0xD149: 0x88B8, //CJK UNIFIED IDEOGRAPH + 0xD14A: 0x88B9, //CJK UNIFIED IDEOGRAPH + 0xD14B: 0x88BA, //CJK UNIFIED IDEOGRAPH + 0xD14C: 0x88BB, //CJK UNIFIED IDEOGRAPH + 0xD14D: 0x88BD, //CJK UNIFIED IDEOGRAPH + 0xD14E: 0x88BE, //CJK UNIFIED IDEOGRAPH + 0xD14F: 0x88BF, //CJK UNIFIED IDEOGRAPH + 0xD150: 0x88C0, //CJK UNIFIED IDEOGRAPH + 0xD151: 0x88C3, //CJK UNIFIED IDEOGRAPH + 0xD152: 0x88C4, //CJK UNIFIED IDEOGRAPH + 0xD153: 0x88C7, //CJK UNIFIED IDEOGRAPH + 0xD154: 0x88C8, //CJK UNIFIED IDEOGRAPH + 0xD155: 0x88CA, //CJK UNIFIED IDEOGRAPH + 0xD156: 0x88CB, //CJK UNIFIED IDEOGRAPH + 0xD157: 0x88CC, //CJK UNIFIED IDEOGRAPH + 0xD158: 0x88CD, //CJK UNIFIED IDEOGRAPH + 0xD159: 0x88CF, //CJK UNIFIED IDEOGRAPH + 0xD15A: 0x88D0, //CJK UNIFIED IDEOGRAPH + 0xD15B: 0x88D1, //CJK UNIFIED IDEOGRAPH + 0xD15C: 0x88D3, //CJK UNIFIED IDEOGRAPH + 0xD15D: 0x88D6, //CJK UNIFIED IDEOGRAPH + 0xD15E: 0x88D7, //CJK UNIFIED IDEOGRAPH + 0xD15F: 0x88DA, //CJK UNIFIED IDEOGRAPH + 0xD160: 0x88DB, //CJK UNIFIED IDEOGRAPH + 0xD161: 0x88DC, //CJK UNIFIED IDEOGRAPH + 0xD162: 0x88DD, //CJK UNIFIED IDEOGRAPH + 0xD163: 0x88DE, //CJK UNIFIED IDEOGRAPH + 0xD164: 0x88E0, //CJK UNIFIED IDEOGRAPH + 0xD165: 0x88E1, //CJK UNIFIED IDEOGRAPH + 0xD166: 0x88E6, //CJK UNIFIED IDEOGRAPH + 0xD167: 0x88E7, //CJK UNIFIED IDEOGRAPH + 0xD168: 0x88E9, //CJK UNIFIED IDEOGRAPH + 0xD169: 0x88EA, //CJK UNIFIED IDEOGRAPH + 0xD16A: 0x88EB, //CJK UNIFIED IDEOGRAPH + 0xD16B: 0x88EC, //CJK UNIFIED IDEOGRAPH + 0xD16C: 0x88ED, //CJK UNIFIED IDEOGRAPH + 0xD16D: 0x88EE, //CJK UNIFIED IDEOGRAPH + 0xD16E: 0x88EF, //CJK UNIFIED IDEOGRAPH + 0xD16F: 0x88F2, //CJK UNIFIED IDEOGRAPH + 0xD170: 0x88F5, //CJK UNIFIED IDEOGRAPH + 0xD171: 0x88F6, //CJK UNIFIED IDEOGRAPH + 0xD172: 0x88F7, //CJK UNIFIED IDEOGRAPH + 0xD173: 0x88FA, //CJK UNIFIED IDEOGRAPH + 0xD174: 0x88FB, //CJK UNIFIED IDEOGRAPH + 0xD175: 0x88FD, //CJK UNIFIED IDEOGRAPH + 0xD176: 0x88FF, //CJK UNIFIED IDEOGRAPH + 0xD177: 0x8900, //CJK UNIFIED IDEOGRAPH + 0xD178: 0x8901, //CJK UNIFIED IDEOGRAPH + 0xD179: 0x8903, //CJK UNIFIED IDEOGRAPH + 0xD17A: 0x8904, //CJK UNIFIED IDEOGRAPH + 0xD17B: 0x8905, //CJK UNIFIED IDEOGRAPH + 0xD17C: 0x8906, //CJK UNIFIED IDEOGRAPH + 0xD17D: 0x8907, //CJK UNIFIED IDEOGRAPH + 0xD17E: 0x8908, //CJK UNIFIED IDEOGRAPH + 0xD180: 0x8909, //CJK UNIFIED IDEOGRAPH + 0xD181: 0x890B, //CJK UNIFIED IDEOGRAPH + 0xD182: 0x890C, //CJK UNIFIED IDEOGRAPH + 0xD183: 0x890D, //CJK UNIFIED IDEOGRAPH + 0xD184: 0x890E, //CJK UNIFIED IDEOGRAPH + 0xD185: 0x890F, //CJK UNIFIED IDEOGRAPH + 0xD186: 0x8911, //CJK UNIFIED IDEOGRAPH + 0xD187: 0x8914, //CJK UNIFIED IDEOGRAPH + 0xD188: 0x8915, //CJK UNIFIED IDEOGRAPH + 0xD189: 0x8916, //CJK UNIFIED IDEOGRAPH + 0xD18A: 0x8917, //CJK UNIFIED IDEOGRAPH + 0xD18B: 0x8918, //CJK UNIFIED IDEOGRAPH + 0xD18C: 0x891C, //CJK UNIFIED IDEOGRAPH + 0xD18D: 0x891D, //CJK UNIFIED IDEOGRAPH + 0xD18E: 0x891E, //CJK UNIFIED IDEOGRAPH + 0xD18F: 0x891F, //CJK UNIFIED IDEOGRAPH + 0xD190: 0x8920, //CJK UNIFIED IDEOGRAPH + 0xD191: 0x8922, //CJK UNIFIED IDEOGRAPH + 0xD192: 0x8923, //CJK UNIFIED IDEOGRAPH + 0xD193: 0x8924, //CJK UNIFIED IDEOGRAPH + 0xD194: 0x8926, //CJK UNIFIED IDEOGRAPH + 0xD195: 0x8927, //CJK UNIFIED IDEOGRAPH + 0xD196: 0x8928, //CJK UNIFIED IDEOGRAPH + 0xD197: 0x8929, //CJK UNIFIED IDEOGRAPH + 0xD198: 0x892C, //CJK UNIFIED IDEOGRAPH + 0xD199: 0x892D, //CJK UNIFIED IDEOGRAPH + 0xD19A: 0x892E, //CJK UNIFIED IDEOGRAPH + 0xD19B: 0x892F, //CJK UNIFIED IDEOGRAPH + 0xD19C: 0x8931, //CJK UNIFIED IDEOGRAPH + 0xD19D: 0x8932, //CJK UNIFIED IDEOGRAPH + 0xD19E: 0x8933, //CJK UNIFIED IDEOGRAPH + 0xD19F: 0x8935, //CJK UNIFIED IDEOGRAPH + 0xD1A0: 0x8937, //CJK UNIFIED IDEOGRAPH + 0xD1A1: 0x9009, //CJK UNIFIED IDEOGRAPH + 0xD1A2: 0x7663, //CJK UNIFIED IDEOGRAPH + 0xD1A3: 0x7729, //CJK UNIFIED IDEOGRAPH + 0xD1A4: 0x7EDA, //CJK UNIFIED IDEOGRAPH + 0xD1A5: 0x9774, //CJK UNIFIED IDEOGRAPH + 0xD1A6: 0x859B, //CJK UNIFIED IDEOGRAPH + 0xD1A7: 0x5B66, //CJK UNIFIED IDEOGRAPH + 0xD1A8: 0x7A74, //CJK UNIFIED IDEOGRAPH + 0xD1A9: 0x96EA, //CJK UNIFIED IDEOGRAPH + 0xD1AA: 0x8840, //CJK UNIFIED IDEOGRAPH + 0xD1AB: 0x52CB, //CJK UNIFIED IDEOGRAPH + 0xD1AC: 0x718F, //CJK UNIFIED IDEOGRAPH + 0xD1AD: 0x5FAA, //CJK UNIFIED IDEOGRAPH + 0xD1AE: 0x65EC, //CJK UNIFIED IDEOGRAPH + 0xD1AF: 0x8BE2, //CJK UNIFIED IDEOGRAPH + 0xD1B0: 0x5BFB, //CJK UNIFIED IDEOGRAPH + 0xD1B1: 0x9A6F, //CJK UNIFIED IDEOGRAPH + 0xD1B2: 0x5DE1, //CJK UNIFIED IDEOGRAPH + 0xD1B3: 0x6B89, //CJK UNIFIED IDEOGRAPH + 0xD1B4: 0x6C5B, //CJK UNIFIED IDEOGRAPH + 0xD1B5: 0x8BAD, //CJK UNIFIED IDEOGRAPH + 0xD1B6: 0x8BAF, //CJK UNIFIED IDEOGRAPH + 0xD1B7: 0x900A, //CJK UNIFIED IDEOGRAPH + 0xD1B8: 0x8FC5, //CJK UNIFIED IDEOGRAPH + 0xD1B9: 0x538B, //CJK UNIFIED IDEOGRAPH + 0xD1BA: 0x62BC, //CJK UNIFIED IDEOGRAPH + 0xD1BB: 0x9E26, //CJK UNIFIED IDEOGRAPH + 0xD1BC: 0x9E2D, //CJK UNIFIED IDEOGRAPH + 0xD1BD: 0x5440, //CJK UNIFIED IDEOGRAPH + 0xD1BE: 0x4E2B, //CJK UNIFIED IDEOGRAPH + 0xD1BF: 0x82BD, //CJK UNIFIED IDEOGRAPH + 0xD1C0: 0x7259, //CJK UNIFIED IDEOGRAPH + 0xD1C1: 0x869C, //CJK UNIFIED IDEOGRAPH + 0xD1C2: 0x5D16, //CJK UNIFIED IDEOGRAPH + 0xD1C3: 0x8859, //CJK UNIFIED IDEOGRAPH + 0xD1C4: 0x6DAF, //CJK UNIFIED IDEOGRAPH + 0xD1C5: 0x96C5, //CJK UNIFIED IDEOGRAPH + 0xD1C6: 0x54D1, //CJK UNIFIED IDEOGRAPH + 0xD1C7: 0x4E9A, //CJK UNIFIED IDEOGRAPH + 0xD1C8: 0x8BB6, //CJK UNIFIED IDEOGRAPH + 0xD1C9: 0x7109, //CJK UNIFIED IDEOGRAPH + 0xD1CA: 0x54BD, //CJK UNIFIED IDEOGRAPH + 0xD1CB: 0x9609, //CJK UNIFIED IDEOGRAPH + 0xD1CC: 0x70DF, //CJK UNIFIED IDEOGRAPH + 0xD1CD: 0x6DF9, //CJK UNIFIED IDEOGRAPH + 0xD1CE: 0x76D0, //CJK UNIFIED IDEOGRAPH + 0xD1CF: 0x4E25, //CJK UNIFIED IDEOGRAPH + 0xD1D0: 0x7814, //CJK UNIFIED IDEOGRAPH + 0xD1D1: 0x8712, //CJK UNIFIED IDEOGRAPH + 0xD1D2: 0x5CA9, //CJK UNIFIED IDEOGRAPH + 0xD1D3: 0x5EF6, //CJK UNIFIED IDEOGRAPH + 0xD1D4: 0x8A00, //CJK UNIFIED IDEOGRAPH + 0xD1D5: 0x989C, //CJK UNIFIED IDEOGRAPH + 0xD1D6: 0x960E, //CJK UNIFIED IDEOGRAPH + 0xD1D7: 0x708E, //CJK UNIFIED IDEOGRAPH + 0xD1D8: 0x6CBF, //CJK UNIFIED IDEOGRAPH + 0xD1D9: 0x5944, //CJK UNIFIED IDEOGRAPH + 0xD1DA: 0x63A9, //CJK UNIFIED IDEOGRAPH + 0xD1DB: 0x773C, //CJK UNIFIED IDEOGRAPH + 0xD1DC: 0x884D, //CJK UNIFIED IDEOGRAPH + 0xD1DD: 0x6F14, //CJK UNIFIED IDEOGRAPH + 0xD1DE: 0x8273, //CJK UNIFIED IDEOGRAPH + 0xD1DF: 0x5830, //CJK UNIFIED IDEOGRAPH + 0xD1E0: 0x71D5, //CJK UNIFIED IDEOGRAPH + 0xD1E1: 0x538C, //CJK UNIFIED IDEOGRAPH + 0xD1E2: 0x781A, //CJK UNIFIED IDEOGRAPH + 0xD1E3: 0x96C1, //CJK UNIFIED IDEOGRAPH + 0xD1E4: 0x5501, //CJK UNIFIED IDEOGRAPH + 0xD1E5: 0x5F66, //CJK UNIFIED IDEOGRAPH + 0xD1E6: 0x7130, //CJK UNIFIED IDEOGRAPH + 0xD1E7: 0x5BB4, //CJK UNIFIED IDEOGRAPH + 0xD1E8: 0x8C1A, //CJK UNIFIED IDEOGRAPH + 0xD1E9: 0x9A8C, //CJK UNIFIED IDEOGRAPH + 0xD1EA: 0x6B83, //CJK UNIFIED IDEOGRAPH + 0xD1EB: 0x592E, //CJK UNIFIED IDEOGRAPH + 0xD1EC: 0x9E2F, //CJK UNIFIED IDEOGRAPH + 0xD1ED: 0x79E7, //CJK UNIFIED IDEOGRAPH + 0xD1EE: 0x6768, //CJK UNIFIED IDEOGRAPH + 0xD1EF: 0x626C, //CJK UNIFIED IDEOGRAPH + 0xD1F0: 0x4F6F, //CJK UNIFIED IDEOGRAPH + 0xD1F1: 0x75A1, //CJK UNIFIED IDEOGRAPH + 0xD1F2: 0x7F8A, //CJK UNIFIED IDEOGRAPH + 0xD1F3: 0x6D0B, //CJK UNIFIED IDEOGRAPH + 0xD1F4: 0x9633, //CJK UNIFIED IDEOGRAPH + 0xD1F5: 0x6C27, //CJK UNIFIED IDEOGRAPH + 0xD1F6: 0x4EF0, //CJK UNIFIED IDEOGRAPH + 0xD1F7: 0x75D2, //CJK UNIFIED IDEOGRAPH + 0xD1F8: 0x517B, //CJK UNIFIED IDEOGRAPH + 0xD1F9: 0x6837, //CJK UNIFIED IDEOGRAPH + 0xD1FA: 0x6F3E, //CJK UNIFIED IDEOGRAPH + 0xD1FB: 0x9080, //CJK UNIFIED IDEOGRAPH + 0xD1FC: 0x8170, //CJK UNIFIED IDEOGRAPH + 0xD1FD: 0x5996, //CJK UNIFIED IDEOGRAPH + 0xD1FE: 0x7476, //CJK UNIFIED IDEOGRAPH + 0xD240: 0x8938, //CJK UNIFIED IDEOGRAPH + 0xD241: 0x8939, //CJK UNIFIED IDEOGRAPH + 0xD242: 0x893A, //CJK UNIFIED IDEOGRAPH + 0xD243: 0x893B, //CJK UNIFIED IDEOGRAPH + 0xD244: 0x893C, //CJK UNIFIED IDEOGRAPH + 0xD245: 0x893D, //CJK UNIFIED IDEOGRAPH + 0xD246: 0x893E, //CJK UNIFIED IDEOGRAPH + 0xD247: 0x893F, //CJK UNIFIED IDEOGRAPH + 0xD248: 0x8940, //CJK UNIFIED IDEOGRAPH + 0xD249: 0x8942, //CJK UNIFIED IDEOGRAPH + 0xD24A: 0x8943, //CJK UNIFIED IDEOGRAPH + 0xD24B: 0x8945, //CJK UNIFIED IDEOGRAPH + 0xD24C: 0x8946, //CJK UNIFIED IDEOGRAPH + 0xD24D: 0x8947, //CJK UNIFIED IDEOGRAPH + 0xD24E: 0x8948, //CJK UNIFIED IDEOGRAPH + 0xD24F: 0x8949, //CJK UNIFIED IDEOGRAPH + 0xD250: 0x894A, //CJK UNIFIED IDEOGRAPH + 0xD251: 0x894B, //CJK UNIFIED IDEOGRAPH + 0xD252: 0x894C, //CJK UNIFIED IDEOGRAPH + 0xD253: 0x894D, //CJK UNIFIED IDEOGRAPH + 0xD254: 0x894E, //CJK UNIFIED IDEOGRAPH + 0xD255: 0x894F, //CJK UNIFIED IDEOGRAPH + 0xD256: 0x8950, //CJK UNIFIED IDEOGRAPH + 0xD257: 0x8951, //CJK UNIFIED IDEOGRAPH + 0xD258: 0x8952, //CJK UNIFIED IDEOGRAPH + 0xD259: 0x8953, //CJK UNIFIED IDEOGRAPH + 0xD25A: 0x8954, //CJK UNIFIED IDEOGRAPH + 0xD25B: 0x8955, //CJK UNIFIED IDEOGRAPH + 0xD25C: 0x8956, //CJK UNIFIED IDEOGRAPH + 0xD25D: 0x8957, //CJK UNIFIED IDEOGRAPH + 0xD25E: 0x8958, //CJK UNIFIED IDEOGRAPH + 0xD25F: 0x8959, //CJK UNIFIED IDEOGRAPH + 0xD260: 0x895A, //CJK UNIFIED IDEOGRAPH + 0xD261: 0x895B, //CJK UNIFIED IDEOGRAPH + 0xD262: 0x895C, //CJK UNIFIED IDEOGRAPH + 0xD263: 0x895D, //CJK UNIFIED IDEOGRAPH + 0xD264: 0x8960, //CJK UNIFIED IDEOGRAPH + 0xD265: 0x8961, //CJK UNIFIED IDEOGRAPH + 0xD266: 0x8962, //CJK UNIFIED IDEOGRAPH + 0xD267: 0x8963, //CJK UNIFIED IDEOGRAPH + 0xD268: 0x8964, //CJK UNIFIED IDEOGRAPH + 0xD269: 0x8965, //CJK UNIFIED IDEOGRAPH + 0xD26A: 0x8967, //CJK UNIFIED IDEOGRAPH + 0xD26B: 0x8968, //CJK UNIFIED IDEOGRAPH + 0xD26C: 0x8969, //CJK UNIFIED IDEOGRAPH + 0xD26D: 0x896A, //CJK UNIFIED IDEOGRAPH + 0xD26E: 0x896B, //CJK UNIFIED IDEOGRAPH + 0xD26F: 0x896C, //CJK UNIFIED IDEOGRAPH + 0xD270: 0x896D, //CJK UNIFIED IDEOGRAPH + 0xD271: 0x896E, //CJK UNIFIED IDEOGRAPH + 0xD272: 0x896F, //CJK UNIFIED IDEOGRAPH + 0xD273: 0x8970, //CJK UNIFIED IDEOGRAPH + 0xD274: 0x8971, //CJK UNIFIED IDEOGRAPH + 0xD275: 0x8972, //CJK UNIFIED IDEOGRAPH + 0xD276: 0x8973, //CJK UNIFIED IDEOGRAPH + 0xD277: 0x8974, //CJK UNIFIED IDEOGRAPH + 0xD278: 0x8975, //CJK UNIFIED IDEOGRAPH + 0xD279: 0x8976, //CJK UNIFIED IDEOGRAPH + 0xD27A: 0x8977, //CJK UNIFIED IDEOGRAPH + 0xD27B: 0x8978, //CJK UNIFIED IDEOGRAPH + 0xD27C: 0x8979, //CJK UNIFIED IDEOGRAPH + 0xD27D: 0x897A, //CJK UNIFIED IDEOGRAPH + 0xD27E: 0x897C, //CJK UNIFIED IDEOGRAPH + 0xD280: 0x897D, //CJK UNIFIED IDEOGRAPH + 0xD281: 0x897E, //CJK UNIFIED IDEOGRAPH + 0xD282: 0x8980, //CJK UNIFIED IDEOGRAPH + 0xD283: 0x8982, //CJK UNIFIED IDEOGRAPH + 0xD284: 0x8984, //CJK UNIFIED IDEOGRAPH + 0xD285: 0x8985, //CJK UNIFIED IDEOGRAPH + 0xD286: 0x8987, //CJK UNIFIED IDEOGRAPH + 0xD287: 0x8988, //CJK UNIFIED IDEOGRAPH + 0xD288: 0x8989, //CJK UNIFIED IDEOGRAPH + 0xD289: 0x898A, //CJK UNIFIED IDEOGRAPH + 0xD28A: 0x898B, //CJK UNIFIED IDEOGRAPH + 0xD28B: 0x898C, //CJK UNIFIED IDEOGRAPH + 0xD28C: 0x898D, //CJK UNIFIED IDEOGRAPH + 0xD28D: 0x898E, //CJK UNIFIED IDEOGRAPH + 0xD28E: 0x898F, //CJK UNIFIED IDEOGRAPH + 0xD28F: 0x8990, //CJK UNIFIED IDEOGRAPH + 0xD290: 0x8991, //CJK UNIFIED IDEOGRAPH + 0xD291: 0x8992, //CJK UNIFIED IDEOGRAPH + 0xD292: 0x8993, //CJK UNIFIED IDEOGRAPH + 0xD293: 0x8994, //CJK UNIFIED IDEOGRAPH + 0xD294: 0x8995, //CJK UNIFIED IDEOGRAPH + 0xD295: 0x8996, //CJK UNIFIED IDEOGRAPH + 0xD296: 0x8997, //CJK UNIFIED IDEOGRAPH + 0xD297: 0x8998, //CJK UNIFIED IDEOGRAPH + 0xD298: 0x8999, //CJK UNIFIED IDEOGRAPH + 0xD299: 0x899A, //CJK UNIFIED IDEOGRAPH + 0xD29A: 0x899B, //CJK UNIFIED IDEOGRAPH + 0xD29B: 0x899C, //CJK UNIFIED IDEOGRAPH + 0xD29C: 0x899D, //CJK UNIFIED IDEOGRAPH + 0xD29D: 0x899E, //CJK UNIFIED IDEOGRAPH + 0xD29E: 0x899F, //CJK UNIFIED IDEOGRAPH + 0xD29F: 0x89A0, //CJK UNIFIED IDEOGRAPH + 0xD2A0: 0x89A1, //CJK UNIFIED IDEOGRAPH + 0xD2A1: 0x6447, //CJK UNIFIED IDEOGRAPH + 0xD2A2: 0x5C27, //CJK UNIFIED IDEOGRAPH + 0xD2A3: 0x9065, //CJK UNIFIED IDEOGRAPH + 0xD2A4: 0x7A91, //CJK UNIFIED IDEOGRAPH + 0xD2A5: 0x8C23, //CJK UNIFIED IDEOGRAPH + 0xD2A6: 0x59DA, //CJK UNIFIED IDEOGRAPH + 0xD2A7: 0x54AC, //CJK UNIFIED IDEOGRAPH + 0xD2A8: 0x8200, //CJK UNIFIED IDEOGRAPH + 0xD2A9: 0x836F, //CJK UNIFIED IDEOGRAPH + 0xD2AA: 0x8981, //CJK UNIFIED IDEOGRAPH + 0xD2AB: 0x8000, //CJK UNIFIED IDEOGRAPH + 0xD2AC: 0x6930, //CJK UNIFIED IDEOGRAPH + 0xD2AD: 0x564E, //CJK UNIFIED IDEOGRAPH + 0xD2AE: 0x8036, //CJK UNIFIED IDEOGRAPH + 0xD2AF: 0x7237, //CJK UNIFIED IDEOGRAPH + 0xD2B0: 0x91CE, //CJK UNIFIED IDEOGRAPH + 0xD2B1: 0x51B6, //CJK UNIFIED IDEOGRAPH + 0xD2B2: 0x4E5F, //CJK UNIFIED IDEOGRAPH + 0xD2B3: 0x9875, //CJK UNIFIED IDEOGRAPH + 0xD2B4: 0x6396, //CJK UNIFIED IDEOGRAPH + 0xD2B5: 0x4E1A, //CJK UNIFIED IDEOGRAPH + 0xD2B6: 0x53F6, //CJK UNIFIED IDEOGRAPH + 0xD2B7: 0x66F3, //CJK UNIFIED IDEOGRAPH + 0xD2B8: 0x814B, //CJK UNIFIED IDEOGRAPH + 0xD2B9: 0x591C, //CJK UNIFIED IDEOGRAPH + 0xD2BA: 0x6DB2, //CJK UNIFIED IDEOGRAPH + 0xD2BB: 0x4E00, //CJK UNIFIED IDEOGRAPH + 0xD2BC: 0x58F9, //CJK UNIFIED IDEOGRAPH + 0xD2BD: 0x533B, //CJK UNIFIED IDEOGRAPH + 0xD2BE: 0x63D6, //CJK UNIFIED IDEOGRAPH + 0xD2BF: 0x94F1, //CJK UNIFIED IDEOGRAPH + 0xD2C0: 0x4F9D, //CJK UNIFIED IDEOGRAPH + 0xD2C1: 0x4F0A, //CJK UNIFIED IDEOGRAPH + 0xD2C2: 0x8863, //CJK UNIFIED IDEOGRAPH + 0xD2C3: 0x9890, //CJK UNIFIED IDEOGRAPH + 0xD2C4: 0x5937, //CJK UNIFIED IDEOGRAPH + 0xD2C5: 0x9057, //CJK UNIFIED IDEOGRAPH + 0xD2C6: 0x79FB, //CJK UNIFIED IDEOGRAPH + 0xD2C7: 0x4EEA, //CJK UNIFIED IDEOGRAPH + 0xD2C8: 0x80F0, //CJK UNIFIED IDEOGRAPH + 0xD2C9: 0x7591, //CJK UNIFIED IDEOGRAPH + 0xD2CA: 0x6C82, //CJK UNIFIED IDEOGRAPH + 0xD2CB: 0x5B9C, //CJK UNIFIED IDEOGRAPH + 0xD2CC: 0x59E8, //CJK UNIFIED IDEOGRAPH + 0xD2CD: 0x5F5D, //CJK UNIFIED IDEOGRAPH + 0xD2CE: 0x6905, //CJK UNIFIED IDEOGRAPH + 0xD2CF: 0x8681, //CJK UNIFIED IDEOGRAPH + 0xD2D0: 0x501A, //CJK UNIFIED IDEOGRAPH + 0xD2D1: 0x5DF2, //CJK UNIFIED IDEOGRAPH + 0xD2D2: 0x4E59, //CJK UNIFIED IDEOGRAPH + 0xD2D3: 0x77E3, //CJK UNIFIED IDEOGRAPH + 0xD2D4: 0x4EE5, //CJK UNIFIED IDEOGRAPH + 0xD2D5: 0x827A, //CJK UNIFIED IDEOGRAPH + 0xD2D6: 0x6291, //CJK UNIFIED IDEOGRAPH + 0xD2D7: 0x6613, //CJK UNIFIED IDEOGRAPH + 0xD2D8: 0x9091, //CJK UNIFIED IDEOGRAPH + 0xD2D9: 0x5C79, //CJK UNIFIED IDEOGRAPH + 0xD2DA: 0x4EBF, //CJK UNIFIED IDEOGRAPH + 0xD2DB: 0x5F79, //CJK UNIFIED IDEOGRAPH + 0xD2DC: 0x81C6, //CJK UNIFIED IDEOGRAPH + 0xD2DD: 0x9038, //CJK UNIFIED IDEOGRAPH + 0xD2DE: 0x8084, //CJK UNIFIED IDEOGRAPH + 0xD2DF: 0x75AB, //CJK UNIFIED IDEOGRAPH + 0xD2E0: 0x4EA6, //CJK UNIFIED IDEOGRAPH + 0xD2E1: 0x88D4, //CJK UNIFIED IDEOGRAPH + 0xD2E2: 0x610F, //CJK UNIFIED IDEOGRAPH + 0xD2E3: 0x6BC5, //CJK UNIFIED IDEOGRAPH + 0xD2E4: 0x5FC6, //CJK UNIFIED IDEOGRAPH + 0xD2E5: 0x4E49, //CJK UNIFIED IDEOGRAPH + 0xD2E6: 0x76CA, //CJK UNIFIED IDEOGRAPH + 0xD2E7: 0x6EA2, //CJK UNIFIED IDEOGRAPH + 0xD2E8: 0x8BE3, //CJK UNIFIED IDEOGRAPH + 0xD2E9: 0x8BAE, //CJK UNIFIED IDEOGRAPH + 0xD2EA: 0x8C0A, //CJK UNIFIED IDEOGRAPH + 0xD2EB: 0x8BD1, //CJK UNIFIED IDEOGRAPH + 0xD2EC: 0x5F02, //CJK UNIFIED IDEOGRAPH + 0xD2ED: 0x7FFC, //CJK UNIFIED IDEOGRAPH + 0xD2EE: 0x7FCC, //CJK UNIFIED IDEOGRAPH + 0xD2EF: 0x7ECE, //CJK UNIFIED IDEOGRAPH + 0xD2F0: 0x8335, //CJK UNIFIED IDEOGRAPH + 0xD2F1: 0x836B, //CJK UNIFIED IDEOGRAPH + 0xD2F2: 0x56E0, //CJK UNIFIED IDEOGRAPH + 0xD2F3: 0x6BB7, //CJK UNIFIED IDEOGRAPH + 0xD2F4: 0x97F3, //CJK UNIFIED IDEOGRAPH + 0xD2F5: 0x9634, //CJK UNIFIED IDEOGRAPH + 0xD2F6: 0x59FB, //CJK UNIFIED IDEOGRAPH + 0xD2F7: 0x541F, //CJK UNIFIED IDEOGRAPH + 0xD2F8: 0x94F6, //CJK UNIFIED IDEOGRAPH + 0xD2F9: 0x6DEB, //CJK UNIFIED IDEOGRAPH + 0xD2FA: 0x5BC5, //CJK UNIFIED IDEOGRAPH + 0xD2FB: 0x996E, //CJK UNIFIED IDEOGRAPH + 0xD2FC: 0x5C39, //CJK UNIFIED IDEOGRAPH + 0xD2FD: 0x5F15, //CJK UNIFIED IDEOGRAPH + 0xD2FE: 0x9690, //CJK UNIFIED IDEOGRAPH + 0xD340: 0x89A2, //CJK UNIFIED IDEOGRAPH + 0xD341: 0x89A3, //CJK UNIFIED IDEOGRAPH + 0xD342: 0x89A4, //CJK UNIFIED IDEOGRAPH + 0xD343: 0x89A5, //CJK UNIFIED IDEOGRAPH + 0xD344: 0x89A6, //CJK UNIFIED IDEOGRAPH + 0xD345: 0x89A7, //CJK UNIFIED IDEOGRAPH + 0xD346: 0x89A8, //CJK UNIFIED IDEOGRAPH + 0xD347: 0x89A9, //CJK UNIFIED IDEOGRAPH + 0xD348: 0x89AA, //CJK UNIFIED IDEOGRAPH + 0xD349: 0x89AB, //CJK UNIFIED IDEOGRAPH + 0xD34A: 0x89AC, //CJK UNIFIED IDEOGRAPH + 0xD34B: 0x89AD, //CJK UNIFIED IDEOGRAPH + 0xD34C: 0x89AE, //CJK UNIFIED IDEOGRAPH + 0xD34D: 0x89AF, //CJK UNIFIED IDEOGRAPH + 0xD34E: 0x89B0, //CJK UNIFIED IDEOGRAPH + 0xD34F: 0x89B1, //CJK UNIFIED IDEOGRAPH + 0xD350: 0x89B2, //CJK UNIFIED IDEOGRAPH + 0xD351: 0x89B3, //CJK UNIFIED IDEOGRAPH + 0xD352: 0x89B4, //CJK UNIFIED IDEOGRAPH + 0xD353: 0x89B5, //CJK UNIFIED IDEOGRAPH + 0xD354: 0x89B6, //CJK UNIFIED IDEOGRAPH + 0xD355: 0x89B7, //CJK UNIFIED IDEOGRAPH + 0xD356: 0x89B8, //CJK UNIFIED IDEOGRAPH + 0xD357: 0x89B9, //CJK UNIFIED IDEOGRAPH + 0xD358: 0x89BA, //CJK UNIFIED IDEOGRAPH + 0xD359: 0x89BB, //CJK UNIFIED IDEOGRAPH + 0xD35A: 0x89BC, //CJK UNIFIED IDEOGRAPH + 0xD35B: 0x89BD, //CJK UNIFIED IDEOGRAPH + 0xD35C: 0x89BE, //CJK UNIFIED IDEOGRAPH + 0xD35D: 0x89BF, //CJK UNIFIED IDEOGRAPH + 0xD35E: 0x89C0, //CJK UNIFIED IDEOGRAPH + 0xD35F: 0x89C3, //CJK UNIFIED IDEOGRAPH + 0xD360: 0x89CD, //CJK UNIFIED IDEOGRAPH + 0xD361: 0x89D3, //CJK UNIFIED IDEOGRAPH + 0xD362: 0x89D4, //CJK UNIFIED IDEOGRAPH + 0xD363: 0x89D5, //CJK UNIFIED IDEOGRAPH + 0xD364: 0x89D7, //CJK UNIFIED IDEOGRAPH + 0xD365: 0x89D8, //CJK UNIFIED IDEOGRAPH + 0xD366: 0x89D9, //CJK UNIFIED IDEOGRAPH + 0xD367: 0x89DB, //CJK UNIFIED IDEOGRAPH + 0xD368: 0x89DD, //CJK UNIFIED IDEOGRAPH + 0xD369: 0x89DF, //CJK UNIFIED IDEOGRAPH + 0xD36A: 0x89E0, //CJK UNIFIED IDEOGRAPH + 0xD36B: 0x89E1, //CJK UNIFIED IDEOGRAPH + 0xD36C: 0x89E2, //CJK UNIFIED IDEOGRAPH + 0xD36D: 0x89E4, //CJK UNIFIED IDEOGRAPH + 0xD36E: 0x89E7, //CJK UNIFIED IDEOGRAPH + 0xD36F: 0x89E8, //CJK UNIFIED IDEOGRAPH + 0xD370: 0x89E9, //CJK UNIFIED IDEOGRAPH + 0xD371: 0x89EA, //CJK UNIFIED IDEOGRAPH + 0xD372: 0x89EC, //CJK UNIFIED IDEOGRAPH + 0xD373: 0x89ED, //CJK UNIFIED IDEOGRAPH + 0xD374: 0x89EE, //CJK UNIFIED IDEOGRAPH + 0xD375: 0x89F0, //CJK UNIFIED IDEOGRAPH + 0xD376: 0x89F1, //CJK UNIFIED IDEOGRAPH + 0xD377: 0x89F2, //CJK UNIFIED IDEOGRAPH + 0xD378: 0x89F4, //CJK UNIFIED IDEOGRAPH + 0xD379: 0x89F5, //CJK UNIFIED IDEOGRAPH + 0xD37A: 0x89F6, //CJK UNIFIED IDEOGRAPH + 0xD37B: 0x89F7, //CJK UNIFIED IDEOGRAPH + 0xD37C: 0x89F8, //CJK UNIFIED IDEOGRAPH + 0xD37D: 0x89F9, //CJK UNIFIED IDEOGRAPH + 0xD37E: 0x89FA, //CJK UNIFIED IDEOGRAPH + 0xD380: 0x89FB, //CJK UNIFIED IDEOGRAPH + 0xD381: 0x89FC, //CJK UNIFIED IDEOGRAPH + 0xD382: 0x89FD, //CJK UNIFIED IDEOGRAPH + 0xD383: 0x89FE, //CJK UNIFIED IDEOGRAPH + 0xD384: 0x89FF, //CJK UNIFIED IDEOGRAPH + 0xD385: 0x8A01, //CJK UNIFIED IDEOGRAPH + 0xD386: 0x8A02, //CJK UNIFIED IDEOGRAPH + 0xD387: 0x8A03, //CJK UNIFIED IDEOGRAPH + 0xD388: 0x8A04, //CJK UNIFIED IDEOGRAPH + 0xD389: 0x8A05, //CJK UNIFIED IDEOGRAPH + 0xD38A: 0x8A06, //CJK UNIFIED IDEOGRAPH + 0xD38B: 0x8A08, //CJK UNIFIED IDEOGRAPH + 0xD38C: 0x8A09, //CJK UNIFIED IDEOGRAPH + 0xD38D: 0x8A0A, //CJK UNIFIED IDEOGRAPH + 0xD38E: 0x8A0B, //CJK UNIFIED IDEOGRAPH + 0xD38F: 0x8A0C, //CJK UNIFIED IDEOGRAPH + 0xD390: 0x8A0D, //CJK UNIFIED IDEOGRAPH + 0xD391: 0x8A0E, //CJK UNIFIED IDEOGRAPH + 0xD392: 0x8A0F, //CJK UNIFIED IDEOGRAPH + 0xD393: 0x8A10, //CJK UNIFIED IDEOGRAPH + 0xD394: 0x8A11, //CJK UNIFIED IDEOGRAPH + 0xD395: 0x8A12, //CJK UNIFIED IDEOGRAPH + 0xD396: 0x8A13, //CJK UNIFIED IDEOGRAPH + 0xD397: 0x8A14, //CJK UNIFIED IDEOGRAPH + 0xD398: 0x8A15, //CJK UNIFIED IDEOGRAPH + 0xD399: 0x8A16, //CJK UNIFIED IDEOGRAPH + 0xD39A: 0x8A17, //CJK UNIFIED IDEOGRAPH + 0xD39B: 0x8A18, //CJK UNIFIED IDEOGRAPH + 0xD39C: 0x8A19, //CJK UNIFIED IDEOGRAPH + 0xD39D: 0x8A1A, //CJK UNIFIED IDEOGRAPH + 0xD39E: 0x8A1B, //CJK UNIFIED IDEOGRAPH + 0xD39F: 0x8A1C, //CJK UNIFIED IDEOGRAPH + 0xD3A0: 0x8A1D, //CJK UNIFIED IDEOGRAPH + 0xD3A1: 0x5370, //CJK UNIFIED IDEOGRAPH + 0xD3A2: 0x82F1, //CJK UNIFIED IDEOGRAPH + 0xD3A3: 0x6A31, //CJK UNIFIED IDEOGRAPH + 0xD3A4: 0x5A74, //CJK UNIFIED IDEOGRAPH + 0xD3A5: 0x9E70, //CJK UNIFIED IDEOGRAPH + 0xD3A6: 0x5E94, //CJK UNIFIED IDEOGRAPH + 0xD3A7: 0x7F28, //CJK UNIFIED IDEOGRAPH + 0xD3A8: 0x83B9, //CJK UNIFIED IDEOGRAPH + 0xD3A9: 0x8424, //CJK UNIFIED IDEOGRAPH + 0xD3AA: 0x8425, //CJK UNIFIED IDEOGRAPH + 0xD3AB: 0x8367, //CJK UNIFIED IDEOGRAPH + 0xD3AC: 0x8747, //CJK UNIFIED IDEOGRAPH + 0xD3AD: 0x8FCE, //CJK UNIFIED IDEOGRAPH + 0xD3AE: 0x8D62, //CJK UNIFIED IDEOGRAPH + 0xD3AF: 0x76C8, //CJK UNIFIED IDEOGRAPH + 0xD3B0: 0x5F71, //CJK UNIFIED IDEOGRAPH + 0xD3B1: 0x9896, //CJK UNIFIED IDEOGRAPH + 0xD3B2: 0x786C, //CJK UNIFIED IDEOGRAPH + 0xD3B3: 0x6620, //CJK UNIFIED IDEOGRAPH + 0xD3B4: 0x54DF, //CJK UNIFIED IDEOGRAPH + 0xD3B5: 0x62E5, //CJK UNIFIED IDEOGRAPH + 0xD3B6: 0x4F63, //CJK UNIFIED IDEOGRAPH + 0xD3B7: 0x81C3, //CJK UNIFIED IDEOGRAPH + 0xD3B8: 0x75C8, //CJK UNIFIED IDEOGRAPH + 0xD3B9: 0x5EB8, //CJK UNIFIED IDEOGRAPH + 0xD3BA: 0x96CD, //CJK UNIFIED IDEOGRAPH + 0xD3BB: 0x8E0A, //CJK UNIFIED IDEOGRAPH + 0xD3BC: 0x86F9, //CJK UNIFIED IDEOGRAPH + 0xD3BD: 0x548F, //CJK UNIFIED IDEOGRAPH + 0xD3BE: 0x6CF3, //CJK UNIFIED IDEOGRAPH + 0xD3BF: 0x6D8C, //CJK UNIFIED IDEOGRAPH + 0xD3C0: 0x6C38, //CJK UNIFIED IDEOGRAPH + 0xD3C1: 0x607F, //CJK UNIFIED IDEOGRAPH + 0xD3C2: 0x52C7, //CJK UNIFIED IDEOGRAPH + 0xD3C3: 0x7528, //CJK UNIFIED IDEOGRAPH + 0xD3C4: 0x5E7D, //CJK UNIFIED IDEOGRAPH + 0xD3C5: 0x4F18, //CJK UNIFIED IDEOGRAPH + 0xD3C6: 0x60A0, //CJK UNIFIED IDEOGRAPH + 0xD3C7: 0x5FE7, //CJK UNIFIED IDEOGRAPH + 0xD3C8: 0x5C24, //CJK UNIFIED IDEOGRAPH + 0xD3C9: 0x7531, //CJK UNIFIED IDEOGRAPH + 0xD3CA: 0x90AE, //CJK UNIFIED IDEOGRAPH + 0xD3CB: 0x94C0, //CJK UNIFIED IDEOGRAPH + 0xD3CC: 0x72B9, //CJK UNIFIED IDEOGRAPH + 0xD3CD: 0x6CB9, //CJK UNIFIED IDEOGRAPH + 0xD3CE: 0x6E38, //CJK UNIFIED IDEOGRAPH + 0xD3CF: 0x9149, //CJK UNIFIED IDEOGRAPH + 0xD3D0: 0x6709, //CJK UNIFIED IDEOGRAPH + 0xD3D1: 0x53CB, //CJK UNIFIED IDEOGRAPH + 0xD3D2: 0x53F3, //CJK UNIFIED IDEOGRAPH + 0xD3D3: 0x4F51, //CJK UNIFIED IDEOGRAPH + 0xD3D4: 0x91C9, //CJK UNIFIED IDEOGRAPH + 0xD3D5: 0x8BF1, //CJK UNIFIED IDEOGRAPH + 0xD3D6: 0x53C8, //CJK UNIFIED IDEOGRAPH + 0xD3D7: 0x5E7C, //CJK UNIFIED IDEOGRAPH + 0xD3D8: 0x8FC2, //CJK UNIFIED IDEOGRAPH + 0xD3D9: 0x6DE4, //CJK UNIFIED IDEOGRAPH + 0xD3DA: 0x4E8E, //CJK UNIFIED IDEOGRAPH + 0xD3DB: 0x76C2, //CJK UNIFIED IDEOGRAPH + 0xD3DC: 0x6986, //CJK UNIFIED IDEOGRAPH + 0xD3DD: 0x865E, //CJK UNIFIED IDEOGRAPH + 0xD3DE: 0x611A, //CJK UNIFIED IDEOGRAPH + 0xD3DF: 0x8206, //CJK UNIFIED IDEOGRAPH + 0xD3E0: 0x4F59, //CJK UNIFIED IDEOGRAPH + 0xD3E1: 0x4FDE, //CJK UNIFIED IDEOGRAPH + 0xD3E2: 0x903E, //CJK UNIFIED IDEOGRAPH + 0xD3E3: 0x9C7C, //CJK UNIFIED IDEOGRAPH + 0xD3E4: 0x6109, //CJK UNIFIED IDEOGRAPH + 0xD3E5: 0x6E1D, //CJK UNIFIED IDEOGRAPH + 0xD3E6: 0x6E14, //CJK UNIFIED IDEOGRAPH + 0xD3E7: 0x9685, //CJK UNIFIED IDEOGRAPH + 0xD3E8: 0x4E88, //CJK UNIFIED IDEOGRAPH + 0xD3E9: 0x5A31, //CJK UNIFIED IDEOGRAPH + 0xD3EA: 0x96E8, //CJK UNIFIED IDEOGRAPH + 0xD3EB: 0x4E0E, //CJK UNIFIED IDEOGRAPH + 0xD3EC: 0x5C7F, //CJK UNIFIED IDEOGRAPH + 0xD3ED: 0x79B9, //CJK UNIFIED IDEOGRAPH + 0xD3EE: 0x5B87, //CJK UNIFIED IDEOGRAPH + 0xD3EF: 0x8BED, //CJK UNIFIED IDEOGRAPH + 0xD3F0: 0x7FBD, //CJK UNIFIED IDEOGRAPH + 0xD3F1: 0x7389, //CJK UNIFIED IDEOGRAPH + 0xD3F2: 0x57DF, //CJK UNIFIED IDEOGRAPH + 0xD3F3: 0x828B, //CJK UNIFIED IDEOGRAPH + 0xD3F4: 0x90C1, //CJK UNIFIED IDEOGRAPH + 0xD3F5: 0x5401, //CJK UNIFIED IDEOGRAPH + 0xD3F6: 0x9047, //CJK UNIFIED IDEOGRAPH + 0xD3F7: 0x55BB, //CJK UNIFIED IDEOGRAPH + 0xD3F8: 0x5CEA, //CJK UNIFIED IDEOGRAPH + 0xD3F9: 0x5FA1, //CJK UNIFIED IDEOGRAPH + 0xD3FA: 0x6108, //CJK UNIFIED IDEOGRAPH + 0xD3FB: 0x6B32, //CJK UNIFIED IDEOGRAPH + 0xD3FC: 0x72F1, //CJK UNIFIED IDEOGRAPH + 0xD3FD: 0x80B2, //CJK UNIFIED IDEOGRAPH + 0xD3FE: 0x8A89, //CJK UNIFIED IDEOGRAPH + 0xD440: 0x8A1E, //CJK UNIFIED IDEOGRAPH + 0xD441: 0x8A1F, //CJK UNIFIED IDEOGRAPH + 0xD442: 0x8A20, //CJK UNIFIED IDEOGRAPH + 0xD443: 0x8A21, //CJK UNIFIED IDEOGRAPH + 0xD444: 0x8A22, //CJK UNIFIED IDEOGRAPH + 0xD445: 0x8A23, //CJK UNIFIED IDEOGRAPH + 0xD446: 0x8A24, //CJK UNIFIED IDEOGRAPH + 0xD447: 0x8A25, //CJK UNIFIED IDEOGRAPH + 0xD448: 0x8A26, //CJK UNIFIED IDEOGRAPH + 0xD449: 0x8A27, //CJK UNIFIED IDEOGRAPH + 0xD44A: 0x8A28, //CJK UNIFIED IDEOGRAPH + 0xD44B: 0x8A29, //CJK UNIFIED IDEOGRAPH + 0xD44C: 0x8A2A, //CJK UNIFIED IDEOGRAPH + 0xD44D: 0x8A2B, //CJK UNIFIED IDEOGRAPH + 0xD44E: 0x8A2C, //CJK UNIFIED IDEOGRAPH + 0xD44F: 0x8A2D, //CJK UNIFIED IDEOGRAPH + 0xD450: 0x8A2E, //CJK UNIFIED IDEOGRAPH + 0xD451: 0x8A2F, //CJK UNIFIED IDEOGRAPH + 0xD452: 0x8A30, //CJK UNIFIED IDEOGRAPH + 0xD453: 0x8A31, //CJK UNIFIED IDEOGRAPH + 0xD454: 0x8A32, //CJK UNIFIED IDEOGRAPH + 0xD455: 0x8A33, //CJK UNIFIED IDEOGRAPH + 0xD456: 0x8A34, //CJK UNIFIED IDEOGRAPH + 0xD457: 0x8A35, //CJK UNIFIED IDEOGRAPH + 0xD458: 0x8A36, //CJK UNIFIED IDEOGRAPH + 0xD459: 0x8A37, //CJK UNIFIED IDEOGRAPH + 0xD45A: 0x8A38, //CJK UNIFIED IDEOGRAPH + 0xD45B: 0x8A39, //CJK UNIFIED IDEOGRAPH + 0xD45C: 0x8A3A, //CJK UNIFIED IDEOGRAPH + 0xD45D: 0x8A3B, //CJK UNIFIED IDEOGRAPH + 0xD45E: 0x8A3C, //CJK UNIFIED IDEOGRAPH + 0xD45F: 0x8A3D, //CJK UNIFIED IDEOGRAPH + 0xD460: 0x8A3F, //CJK UNIFIED IDEOGRAPH + 0xD461: 0x8A40, //CJK UNIFIED IDEOGRAPH + 0xD462: 0x8A41, //CJK UNIFIED IDEOGRAPH + 0xD463: 0x8A42, //CJK UNIFIED IDEOGRAPH + 0xD464: 0x8A43, //CJK UNIFIED IDEOGRAPH + 0xD465: 0x8A44, //CJK UNIFIED IDEOGRAPH + 0xD466: 0x8A45, //CJK UNIFIED IDEOGRAPH + 0xD467: 0x8A46, //CJK UNIFIED IDEOGRAPH + 0xD468: 0x8A47, //CJK UNIFIED IDEOGRAPH + 0xD469: 0x8A49, //CJK UNIFIED IDEOGRAPH + 0xD46A: 0x8A4A, //CJK UNIFIED IDEOGRAPH + 0xD46B: 0x8A4B, //CJK UNIFIED IDEOGRAPH + 0xD46C: 0x8A4C, //CJK UNIFIED IDEOGRAPH + 0xD46D: 0x8A4D, //CJK UNIFIED IDEOGRAPH + 0xD46E: 0x8A4E, //CJK UNIFIED IDEOGRAPH + 0xD46F: 0x8A4F, //CJK UNIFIED IDEOGRAPH + 0xD470: 0x8A50, //CJK UNIFIED IDEOGRAPH + 0xD471: 0x8A51, //CJK UNIFIED IDEOGRAPH + 0xD472: 0x8A52, //CJK UNIFIED IDEOGRAPH + 0xD473: 0x8A53, //CJK UNIFIED IDEOGRAPH + 0xD474: 0x8A54, //CJK UNIFIED IDEOGRAPH + 0xD475: 0x8A55, //CJK UNIFIED IDEOGRAPH + 0xD476: 0x8A56, //CJK UNIFIED IDEOGRAPH + 0xD477: 0x8A57, //CJK UNIFIED IDEOGRAPH + 0xD478: 0x8A58, //CJK UNIFIED IDEOGRAPH + 0xD479: 0x8A59, //CJK UNIFIED IDEOGRAPH + 0xD47A: 0x8A5A, //CJK UNIFIED IDEOGRAPH + 0xD47B: 0x8A5B, //CJK UNIFIED IDEOGRAPH + 0xD47C: 0x8A5C, //CJK UNIFIED IDEOGRAPH + 0xD47D: 0x8A5D, //CJK UNIFIED IDEOGRAPH + 0xD47E: 0x8A5E, //CJK UNIFIED IDEOGRAPH + 0xD480: 0x8A5F, //CJK UNIFIED IDEOGRAPH + 0xD481: 0x8A60, //CJK UNIFIED IDEOGRAPH + 0xD482: 0x8A61, //CJK UNIFIED IDEOGRAPH + 0xD483: 0x8A62, //CJK UNIFIED IDEOGRAPH + 0xD484: 0x8A63, //CJK UNIFIED IDEOGRAPH + 0xD485: 0x8A64, //CJK UNIFIED IDEOGRAPH + 0xD486: 0x8A65, //CJK UNIFIED IDEOGRAPH + 0xD487: 0x8A66, //CJK UNIFIED IDEOGRAPH + 0xD488: 0x8A67, //CJK UNIFIED IDEOGRAPH + 0xD489: 0x8A68, //CJK UNIFIED IDEOGRAPH + 0xD48A: 0x8A69, //CJK UNIFIED IDEOGRAPH + 0xD48B: 0x8A6A, //CJK UNIFIED IDEOGRAPH + 0xD48C: 0x8A6B, //CJK UNIFIED IDEOGRAPH + 0xD48D: 0x8A6C, //CJK UNIFIED IDEOGRAPH + 0xD48E: 0x8A6D, //CJK UNIFIED IDEOGRAPH + 0xD48F: 0x8A6E, //CJK UNIFIED IDEOGRAPH + 0xD490: 0x8A6F, //CJK UNIFIED IDEOGRAPH + 0xD491: 0x8A70, //CJK UNIFIED IDEOGRAPH + 0xD492: 0x8A71, //CJK UNIFIED IDEOGRAPH + 0xD493: 0x8A72, //CJK UNIFIED IDEOGRAPH + 0xD494: 0x8A73, //CJK UNIFIED IDEOGRAPH + 0xD495: 0x8A74, //CJK UNIFIED IDEOGRAPH + 0xD496: 0x8A75, //CJK UNIFIED IDEOGRAPH + 0xD497: 0x8A76, //CJK UNIFIED IDEOGRAPH + 0xD498: 0x8A77, //CJK UNIFIED IDEOGRAPH + 0xD499: 0x8A78, //CJK UNIFIED IDEOGRAPH + 0xD49A: 0x8A7A, //CJK UNIFIED IDEOGRAPH + 0xD49B: 0x8A7B, //CJK UNIFIED IDEOGRAPH + 0xD49C: 0x8A7C, //CJK UNIFIED IDEOGRAPH + 0xD49D: 0x8A7D, //CJK UNIFIED IDEOGRAPH + 0xD49E: 0x8A7E, //CJK UNIFIED IDEOGRAPH + 0xD49F: 0x8A7F, //CJK UNIFIED IDEOGRAPH + 0xD4A0: 0x8A80, //CJK UNIFIED IDEOGRAPH + 0xD4A1: 0x6D74, //CJK UNIFIED IDEOGRAPH + 0xD4A2: 0x5BD3, //CJK UNIFIED IDEOGRAPH + 0xD4A3: 0x88D5, //CJK UNIFIED IDEOGRAPH + 0xD4A4: 0x9884, //CJK UNIFIED IDEOGRAPH + 0xD4A5: 0x8C6B, //CJK UNIFIED IDEOGRAPH + 0xD4A6: 0x9A6D, //CJK UNIFIED IDEOGRAPH + 0xD4A7: 0x9E33, //CJK UNIFIED IDEOGRAPH + 0xD4A8: 0x6E0A, //CJK UNIFIED IDEOGRAPH + 0xD4A9: 0x51A4, //CJK UNIFIED IDEOGRAPH + 0xD4AA: 0x5143, //CJK UNIFIED IDEOGRAPH + 0xD4AB: 0x57A3, //CJK UNIFIED IDEOGRAPH + 0xD4AC: 0x8881, //CJK UNIFIED IDEOGRAPH + 0xD4AD: 0x539F, //CJK UNIFIED IDEOGRAPH + 0xD4AE: 0x63F4, //CJK UNIFIED IDEOGRAPH + 0xD4AF: 0x8F95, //CJK UNIFIED IDEOGRAPH + 0xD4B0: 0x56ED, //CJK UNIFIED IDEOGRAPH + 0xD4B1: 0x5458, //CJK UNIFIED IDEOGRAPH + 0xD4B2: 0x5706, //CJK UNIFIED IDEOGRAPH + 0xD4B3: 0x733F, //CJK UNIFIED IDEOGRAPH + 0xD4B4: 0x6E90, //CJK UNIFIED IDEOGRAPH + 0xD4B5: 0x7F18, //CJK UNIFIED IDEOGRAPH + 0xD4B6: 0x8FDC, //CJK UNIFIED IDEOGRAPH + 0xD4B7: 0x82D1, //CJK UNIFIED IDEOGRAPH + 0xD4B8: 0x613F, //CJK UNIFIED IDEOGRAPH + 0xD4B9: 0x6028, //CJK UNIFIED IDEOGRAPH + 0xD4BA: 0x9662, //CJK UNIFIED IDEOGRAPH + 0xD4BB: 0x66F0, //CJK UNIFIED IDEOGRAPH + 0xD4BC: 0x7EA6, //CJK UNIFIED IDEOGRAPH + 0xD4BD: 0x8D8A, //CJK UNIFIED IDEOGRAPH + 0xD4BE: 0x8DC3, //CJK UNIFIED IDEOGRAPH + 0xD4BF: 0x94A5, //CJK UNIFIED IDEOGRAPH + 0xD4C0: 0x5CB3, //CJK UNIFIED IDEOGRAPH + 0xD4C1: 0x7CA4, //CJK UNIFIED IDEOGRAPH + 0xD4C2: 0x6708, //CJK UNIFIED IDEOGRAPH + 0xD4C3: 0x60A6, //CJK UNIFIED IDEOGRAPH + 0xD4C4: 0x9605, //CJK UNIFIED IDEOGRAPH + 0xD4C5: 0x8018, //CJK UNIFIED IDEOGRAPH + 0xD4C6: 0x4E91, //CJK UNIFIED IDEOGRAPH + 0xD4C7: 0x90E7, //CJK UNIFIED IDEOGRAPH + 0xD4C8: 0x5300, //CJK UNIFIED IDEOGRAPH + 0xD4C9: 0x9668, //CJK UNIFIED IDEOGRAPH + 0xD4CA: 0x5141, //CJK UNIFIED IDEOGRAPH + 0xD4CB: 0x8FD0, //CJK UNIFIED IDEOGRAPH + 0xD4CC: 0x8574, //CJK UNIFIED IDEOGRAPH + 0xD4CD: 0x915D, //CJK UNIFIED IDEOGRAPH + 0xD4CE: 0x6655, //CJK UNIFIED IDEOGRAPH + 0xD4CF: 0x97F5, //CJK UNIFIED IDEOGRAPH + 0xD4D0: 0x5B55, //CJK UNIFIED IDEOGRAPH + 0xD4D1: 0x531D, //CJK UNIFIED IDEOGRAPH + 0xD4D2: 0x7838, //CJK UNIFIED IDEOGRAPH + 0xD4D3: 0x6742, //CJK UNIFIED IDEOGRAPH + 0xD4D4: 0x683D, //CJK UNIFIED IDEOGRAPH + 0xD4D5: 0x54C9, //CJK UNIFIED IDEOGRAPH + 0xD4D6: 0x707E, //CJK UNIFIED IDEOGRAPH + 0xD4D7: 0x5BB0, //CJK UNIFIED IDEOGRAPH + 0xD4D8: 0x8F7D, //CJK UNIFIED IDEOGRAPH + 0xD4D9: 0x518D, //CJK UNIFIED IDEOGRAPH + 0xD4DA: 0x5728, //CJK UNIFIED IDEOGRAPH + 0xD4DB: 0x54B1, //CJK UNIFIED IDEOGRAPH + 0xD4DC: 0x6512, //CJK UNIFIED IDEOGRAPH + 0xD4DD: 0x6682, //CJK UNIFIED IDEOGRAPH + 0xD4DE: 0x8D5E, //CJK UNIFIED IDEOGRAPH + 0xD4DF: 0x8D43, //CJK UNIFIED IDEOGRAPH + 0xD4E0: 0x810F, //CJK UNIFIED IDEOGRAPH + 0xD4E1: 0x846C, //CJK UNIFIED IDEOGRAPH + 0xD4E2: 0x906D, //CJK UNIFIED IDEOGRAPH + 0xD4E3: 0x7CDF, //CJK UNIFIED IDEOGRAPH + 0xD4E4: 0x51FF, //CJK UNIFIED IDEOGRAPH + 0xD4E5: 0x85FB, //CJK UNIFIED IDEOGRAPH + 0xD4E6: 0x67A3, //CJK UNIFIED IDEOGRAPH + 0xD4E7: 0x65E9, //CJK UNIFIED IDEOGRAPH + 0xD4E8: 0x6FA1, //CJK UNIFIED IDEOGRAPH + 0xD4E9: 0x86A4, //CJK UNIFIED IDEOGRAPH + 0xD4EA: 0x8E81, //CJK UNIFIED IDEOGRAPH + 0xD4EB: 0x566A, //CJK UNIFIED IDEOGRAPH + 0xD4EC: 0x9020, //CJK UNIFIED IDEOGRAPH + 0xD4ED: 0x7682, //CJK UNIFIED IDEOGRAPH + 0xD4EE: 0x7076, //CJK UNIFIED IDEOGRAPH + 0xD4EF: 0x71E5, //CJK UNIFIED IDEOGRAPH + 0xD4F0: 0x8D23, //CJK UNIFIED IDEOGRAPH + 0xD4F1: 0x62E9, //CJK UNIFIED IDEOGRAPH + 0xD4F2: 0x5219, //CJK UNIFIED IDEOGRAPH + 0xD4F3: 0x6CFD, //CJK UNIFIED IDEOGRAPH + 0xD4F4: 0x8D3C, //CJK UNIFIED IDEOGRAPH + 0xD4F5: 0x600E, //CJK UNIFIED IDEOGRAPH + 0xD4F6: 0x589E, //CJK UNIFIED IDEOGRAPH + 0xD4F7: 0x618E, //CJK UNIFIED IDEOGRAPH + 0xD4F8: 0x66FE, //CJK UNIFIED IDEOGRAPH + 0xD4F9: 0x8D60, //CJK UNIFIED IDEOGRAPH + 0xD4FA: 0x624E, //CJK UNIFIED IDEOGRAPH + 0xD4FB: 0x55B3, //CJK UNIFIED IDEOGRAPH + 0xD4FC: 0x6E23, //CJK UNIFIED IDEOGRAPH + 0xD4FD: 0x672D, //CJK UNIFIED IDEOGRAPH + 0xD4FE: 0x8F67, //CJK UNIFIED IDEOGRAPH + 0xD540: 0x8A81, //CJK UNIFIED IDEOGRAPH + 0xD541: 0x8A82, //CJK UNIFIED IDEOGRAPH + 0xD542: 0x8A83, //CJK UNIFIED IDEOGRAPH + 0xD543: 0x8A84, //CJK UNIFIED IDEOGRAPH + 0xD544: 0x8A85, //CJK UNIFIED IDEOGRAPH + 0xD545: 0x8A86, //CJK UNIFIED IDEOGRAPH + 0xD546: 0x8A87, //CJK UNIFIED IDEOGRAPH + 0xD547: 0x8A88, //CJK UNIFIED IDEOGRAPH + 0xD548: 0x8A8B, //CJK UNIFIED IDEOGRAPH + 0xD549: 0x8A8C, //CJK UNIFIED IDEOGRAPH + 0xD54A: 0x8A8D, //CJK UNIFIED IDEOGRAPH + 0xD54B: 0x8A8E, //CJK UNIFIED IDEOGRAPH + 0xD54C: 0x8A8F, //CJK UNIFIED IDEOGRAPH + 0xD54D: 0x8A90, //CJK UNIFIED IDEOGRAPH + 0xD54E: 0x8A91, //CJK UNIFIED IDEOGRAPH + 0xD54F: 0x8A92, //CJK UNIFIED IDEOGRAPH + 0xD550: 0x8A94, //CJK UNIFIED IDEOGRAPH + 0xD551: 0x8A95, //CJK UNIFIED IDEOGRAPH + 0xD552: 0x8A96, //CJK UNIFIED IDEOGRAPH + 0xD553: 0x8A97, //CJK UNIFIED IDEOGRAPH + 0xD554: 0x8A98, //CJK UNIFIED IDEOGRAPH + 0xD555: 0x8A99, //CJK UNIFIED IDEOGRAPH + 0xD556: 0x8A9A, //CJK UNIFIED IDEOGRAPH + 0xD557: 0x8A9B, //CJK UNIFIED IDEOGRAPH + 0xD558: 0x8A9C, //CJK UNIFIED IDEOGRAPH + 0xD559: 0x8A9D, //CJK UNIFIED IDEOGRAPH + 0xD55A: 0x8A9E, //CJK UNIFIED IDEOGRAPH + 0xD55B: 0x8A9F, //CJK UNIFIED IDEOGRAPH + 0xD55C: 0x8AA0, //CJK UNIFIED IDEOGRAPH + 0xD55D: 0x8AA1, //CJK UNIFIED IDEOGRAPH + 0xD55E: 0x8AA2, //CJK UNIFIED IDEOGRAPH + 0xD55F: 0x8AA3, //CJK UNIFIED IDEOGRAPH + 0xD560: 0x8AA4, //CJK UNIFIED IDEOGRAPH + 0xD561: 0x8AA5, //CJK UNIFIED IDEOGRAPH + 0xD562: 0x8AA6, //CJK UNIFIED IDEOGRAPH + 0xD563: 0x8AA7, //CJK UNIFIED IDEOGRAPH + 0xD564: 0x8AA8, //CJK UNIFIED IDEOGRAPH + 0xD565: 0x8AA9, //CJK UNIFIED IDEOGRAPH + 0xD566: 0x8AAA, //CJK UNIFIED IDEOGRAPH + 0xD567: 0x8AAB, //CJK UNIFIED IDEOGRAPH + 0xD568: 0x8AAC, //CJK UNIFIED IDEOGRAPH + 0xD569: 0x8AAD, //CJK UNIFIED IDEOGRAPH + 0xD56A: 0x8AAE, //CJK UNIFIED IDEOGRAPH + 0xD56B: 0x8AAF, //CJK UNIFIED IDEOGRAPH + 0xD56C: 0x8AB0, //CJK UNIFIED IDEOGRAPH + 0xD56D: 0x8AB1, //CJK UNIFIED IDEOGRAPH + 0xD56E: 0x8AB2, //CJK UNIFIED IDEOGRAPH + 0xD56F: 0x8AB3, //CJK UNIFIED IDEOGRAPH + 0xD570: 0x8AB4, //CJK UNIFIED IDEOGRAPH + 0xD571: 0x8AB5, //CJK UNIFIED IDEOGRAPH + 0xD572: 0x8AB6, //CJK UNIFIED IDEOGRAPH + 0xD573: 0x8AB7, //CJK UNIFIED IDEOGRAPH + 0xD574: 0x8AB8, //CJK UNIFIED IDEOGRAPH + 0xD575: 0x8AB9, //CJK UNIFIED IDEOGRAPH + 0xD576: 0x8ABA, //CJK UNIFIED IDEOGRAPH + 0xD577: 0x8ABB, //CJK UNIFIED IDEOGRAPH + 0xD578: 0x8ABC, //CJK UNIFIED IDEOGRAPH + 0xD579: 0x8ABD, //CJK UNIFIED IDEOGRAPH + 0xD57A: 0x8ABE, //CJK UNIFIED IDEOGRAPH + 0xD57B: 0x8ABF, //CJK UNIFIED IDEOGRAPH + 0xD57C: 0x8AC0, //CJK UNIFIED IDEOGRAPH + 0xD57D: 0x8AC1, //CJK UNIFIED IDEOGRAPH + 0xD57E: 0x8AC2, //CJK UNIFIED IDEOGRAPH + 0xD580: 0x8AC3, //CJK UNIFIED IDEOGRAPH + 0xD581: 0x8AC4, //CJK UNIFIED IDEOGRAPH + 0xD582: 0x8AC5, //CJK UNIFIED IDEOGRAPH + 0xD583: 0x8AC6, //CJK UNIFIED IDEOGRAPH + 0xD584: 0x8AC7, //CJK UNIFIED IDEOGRAPH + 0xD585: 0x8AC8, //CJK UNIFIED IDEOGRAPH + 0xD586: 0x8AC9, //CJK UNIFIED IDEOGRAPH + 0xD587: 0x8ACA, //CJK UNIFIED IDEOGRAPH + 0xD588: 0x8ACB, //CJK UNIFIED IDEOGRAPH + 0xD589: 0x8ACC, //CJK UNIFIED IDEOGRAPH + 0xD58A: 0x8ACD, //CJK UNIFIED IDEOGRAPH + 0xD58B: 0x8ACE, //CJK UNIFIED IDEOGRAPH + 0xD58C: 0x8ACF, //CJK UNIFIED IDEOGRAPH + 0xD58D: 0x8AD0, //CJK UNIFIED IDEOGRAPH + 0xD58E: 0x8AD1, //CJK UNIFIED IDEOGRAPH + 0xD58F: 0x8AD2, //CJK UNIFIED IDEOGRAPH + 0xD590: 0x8AD3, //CJK UNIFIED IDEOGRAPH + 0xD591: 0x8AD4, //CJK UNIFIED IDEOGRAPH + 0xD592: 0x8AD5, //CJK UNIFIED IDEOGRAPH + 0xD593: 0x8AD6, //CJK UNIFIED IDEOGRAPH + 0xD594: 0x8AD7, //CJK UNIFIED IDEOGRAPH + 0xD595: 0x8AD8, //CJK UNIFIED IDEOGRAPH + 0xD596: 0x8AD9, //CJK UNIFIED IDEOGRAPH + 0xD597: 0x8ADA, //CJK UNIFIED IDEOGRAPH + 0xD598: 0x8ADB, //CJK UNIFIED IDEOGRAPH + 0xD599: 0x8ADC, //CJK UNIFIED IDEOGRAPH + 0xD59A: 0x8ADD, //CJK UNIFIED IDEOGRAPH + 0xD59B: 0x8ADE, //CJK UNIFIED IDEOGRAPH + 0xD59C: 0x8ADF, //CJK UNIFIED IDEOGRAPH + 0xD59D: 0x8AE0, //CJK UNIFIED IDEOGRAPH + 0xD59E: 0x8AE1, //CJK UNIFIED IDEOGRAPH + 0xD59F: 0x8AE2, //CJK UNIFIED IDEOGRAPH + 0xD5A0: 0x8AE3, //CJK UNIFIED IDEOGRAPH + 0xD5A1: 0x94E1, //CJK UNIFIED IDEOGRAPH + 0xD5A2: 0x95F8, //CJK UNIFIED IDEOGRAPH + 0xD5A3: 0x7728, //CJK UNIFIED IDEOGRAPH + 0xD5A4: 0x6805, //CJK UNIFIED IDEOGRAPH + 0xD5A5: 0x69A8, //CJK UNIFIED IDEOGRAPH + 0xD5A6: 0x548B, //CJK UNIFIED IDEOGRAPH + 0xD5A7: 0x4E4D, //CJK UNIFIED IDEOGRAPH + 0xD5A8: 0x70B8, //CJK UNIFIED IDEOGRAPH + 0xD5A9: 0x8BC8, //CJK UNIFIED IDEOGRAPH + 0xD5AA: 0x6458, //CJK UNIFIED IDEOGRAPH + 0xD5AB: 0x658B, //CJK UNIFIED IDEOGRAPH + 0xD5AC: 0x5B85, //CJK UNIFIED IDEOGRAPH + 0xD5AD: 0x7A84, //CJK UNIFIED IDEOGRAPH + 0xD5AE: 0x503A, //CJK UNIFIED IDEOGRAPH + 0xD5AF: 0x5BE8, //CJK UNIFIED IDEOGRAPH + 0xD5B0: 0x77BB, //CJK UNIFIED IDEOGRAPH + 0xD5B1: 0x6BE1, //CJK UNIFIED IDEOGRAPH + 0xD5B2: 0x8A79, //CJK UNIFIED IDEOGRAPH + 0xD5B3: 0x7C98, //CJK UNIFIED IDEOGRAPH + 0xD5B4: 0x6CBE, //CJK UNIFIED IDEOGRAPH + 0xD5B5: 0x76CF, //CJK UNIFIED IDEOGRAPH + 0xD5B6: 0x65A9, //CJK UNIFIED IDEOGRAPH + 0xD5B7: 0x8F97, //CJK UNIFIED IDEOGRAPH + 0xD5B8: 0x5D2D, //CJK UNIFIED IDEOGRAPH + 0xD5B9: 0x5C55, //CJK UNIFIED IDEOGRAPH + 0xD5BA: 0x8638, //CJK UNIFIED IDEOGRAPH + 0xD5BB: 0x6808, //CJK UNIFIED IDEOGRAPH + 0xD5BC: 0x5360, //CJK UNIFIED IDEOGRAPH + 0xD5BD: 0x6218, //CJK UNIFIED IDEOGRAPH + 0xD5BE: 0x7AD9, //CJK UNIFIED IDEOGRAPH + 0xD5BF: 0x6E5B, //CJK UNIFIED IDEOGRAPH + 0xD5C0: 0x7EFD, //CJK UNIFIED IDEOGRAPH + 0xD5C1: 0x6A1F, //CJK UNIFIED IDEOGRAPH + 0xD5C2: 0x7AE0, //CJK UNIFIED IDEOGRAPH + 0xD5C3: 0x5F70, //CJK UNIFIED IDEOGRAPH + 0xD5C4: 0x6F33, //CJK UNIFIED IDEOGRAPH + 0xD5C5: 0x5F20, //CJK UNIFIED IDEOGRAPH + 0xD5C6: 0x638C, //CJK UNIFIED IDEOGRAPH + 0xD5C7: 0x6DA8, //CJK UNIFIED IDEOGRAPH + 0xD5C8: 0x6756, //CJK UNIFIED IDEOGRAPH + 0xD5C9: 0x4E08, //CJK UNIFIED IDEOGRAPH + 0xD5CA: 0x5E10, //CJK UNIFIED IDEOGRAPH + 0xD5CB: 0x8D26, //CJK UNIFIED IDEOGRAPH + 0xD5CC: 0x4ED7, //CJK UNIFIED IDEOGRAPH + 0xD5CD: 0x80C0, //CJK UNIFIED IDEOGRAPH + 0xD5CE: 0x7634, //CJK UNIFIED IDEOGRAPH + 0xD5CF: 0x969C, //CJK UNIFIED IDEOGRAPH + 0xD5D0: 0x62DB, //CJK UNIFIED IDEOGRAPH + 0xD5D1: 0x662D, //CJK UNIFIED IDEOGRAPH + 0xD5D2: 0x627E, //CJK UNIFIED IDEOGRAPH + 0xD5D3: 0x6CBC, //CJK UNIFIED IDEOGRAPH + 0xD5D4: 0x8D75, //CJK UNIFIED IDEOGRAPH + 0xD5D5: 0x7167, //CJK UNIFIED IDEOGRAPH + 0xD5D6: 0x7F69, //CJK UNIFIED IDEOGRAPH + 0xD5D7: 0x5146, //CJK UNIFIED IDEOGRAPH + 0xD5D8: 0x8087, //CJK UNIFIED IDEOGRAPH + 0xD5D9: 0x53EC, //CJK UNIFIED IDEOGRAPH + 0xD5DA: 0x906E, //CJK UNIFIED IDEOGRAPH + 0xD5DB: 0x6298, //CJK UNIFIED IDEOGRAPH + 0xD5DC: 0x54F2, //CJK UNIFIED IDEOGRAPH + 0xD5DD: 0x86F0, //CJK UNIFIED IDEOGRAPH + 0xD5DE: 0x8F99, //CJK UNIFIED IDEOGRAPH + 0xD5DF: 0x8005, //CJK UNIFIED IDEOGRAPH + 0xD5E0: 0x9517, //CJK UNIFIED IDEOGRAPH + 0xD5E1: 0x8517, //CJK UNIFIED IDEOGRAPH + 0xD5E2: 0x8FD9, //CJK UNIFIED IDEOGRAPH + 0xD5E3: 0x6D59, //CJK UNIFIED IDEOGRAPH + 0xD5E4: 0x73CD, //CJK UNIFIED IDEOGRAPH + 0xD5E5: 0x659F, //CJK UNIFIED IDEOGRAPH + 0xD5E6: 0x771F, //CJK UNIFIED IDEOGRAPH + 0xD5E7: 0x7504, //CJK UNIFIED IDEOGRAPH + 0xD5E8: 0x7827, //CJK UNIFIED IDEOGRAPH + 0xD5E9: 0x81FB, //CJK UNIFIED IDEOGRAPH + 0xD5EA: 0x8D1E, //CJK UNIFIED IDEOGRAPH + 0xD5EB: 0x9488, //CJK UNIFIED IDEOGRAPH + 0xD5EC: 0x4FA6, //CJK UNIFIED IDEOGRAPH + 0xD5ED: 0x6795, //CJK UNIFIED IDEOGRAPH + 0xD5EE: 0x75B9, //CJK UNIFIED IDEOGRAPH + 0xD5EF: 0x8BCA, //CJK UNIFIED IDEOGRAPH + 0xD5F0: 0x9707, //CJK UNIFIED IDEOGRAPH + 0xD5F1: 0x632F, //CJK UNIFIED IDEOGRAPH + 0xD5F2: 0x9547, //CJK UNIFIED IDEOGRAPH + 0xD5F3: 0x9635, //CJK UNIFIED IDEOGRAPH + 0xD5F4: 0x84B8, //CJK UNIFIED IDEOGRAPH + 0xD5F5: 0x6323, //CJK UNIFIED IDEOGRAPH + 0xD5F6: 0x7741, //CJK UNIFIED IDEOGRAPH + 0xD5F7: 0x5F81, //CJK UNIFIED IDEOGRAPH + 0xD5F8: 0x72F0, //CJK UNIFIED IDEOGRAPH + 0xD5F9: 0x4E89, //CJK UNIFIED IDEOGRAPH + 0xD5FA: 0x6014, //CJK UNIFIED IDEOGRAPH + 0xD5FB: 0x6574, //CJK UNIFIED IDEOGRAPH + 0xD5FC: 0x62EF, //CJK UNIFIED IDEOGRAPH + 0xD5FD: 0x6B63, //CJK UNIFIED IDEOGRAPH + 0xD5FE: 0x653F, //CJK UNIFIED IDEOGRAPH + 0xD640: 0x8AE4, //CJK UNIFIED IDEOGRAPH + 0xD641: 0x8AE5, //CJK UNIFIED IDEOGRAPH + 0xD642: 0x8AE6, //CJK UNIFIED IDEOGRAPH + 0xD643: 0x8AE7, //CJK UNIFIED IDEOGRAPH + 0xD644: 0x8AE8, //CJK UNIFIED IDEOGRAPH + 0xD645: 0x8AE9, //CJK UNIFIED IDEOGRAPH + 0xD646: 0x8AEA, //CJK UNIFIED IDEOGRAPH + 0xD647: 0x8AEB, //CJK UNIFIED IDEOGRAPH + 0xD648: 0x8AEC, //CJK UNIFIED IDEOGRAPH + 0xD649: 0x8AED, //CJK UNIFIED IDEOGRAPH + 0xD64A: 0x8AEE, //CJK UNIFIED IDEOGRAPH + 0xD64B: 0x8AEF, //CJK UNIFIED IDEOGRAPH + 0xD64C: 0x8AF0, //CJK UNIFIED IDEOGRAPH + 0xD64D: 0x8AF1, //CJK UNIFIED IDEOGRAPH + 0xD64E: 0x8AF2, //CJK UNIFIED IDEOGRAPH + 0xD64F: 0x8AF3, //CJK UNIFIED IDEOGRAPH + 0xD650: 0x8AF4, //CJK UNIFIED IDEOGRAPH + 0xD651: 0x8AF5, //CJK UNIFIED IDEOGRAPH + 0xD652: 0x8AF6, //CJK UNIFIED IDEOGRAPH + 0xD653: 0x8AF7, //CJK UNIFIED IDEOGRAPH + 0xD654: 0x8AF8, //CJK UNIFIED IDEOGRAPH + 0xD655: 0x8AF9, //CJK UNIFIED IDEOGRAPH + 0xD656: 0x8AFA, //CJK UNIFIED IDEOGRAPH + 0xD657: 0x8AFB, //CJK UNIFIED IDEOGRAPH + 0xD658: 0x8AFC, //CJK UNIFIED IDEOGRAPH + 0xD659: 0x8AFD, //CJK UNIFIED IDEOGRAPH + 0xD65A: 0x8AFE, //CJK UNIFIED IDEOGRAPH + 0xD65B: 0x8AFF, //CJK UNIFIED IDEOGRAPH + 0xD65C: 0x8B00, //CJK UNIFIED IDEOGRAPH + 0xD65D: 0x8B01, //CJK UNIFIED IDEOGRAPH + 0xD65E: 0x8B02, //CJK UNIFIED IDEOGRAPH + 0xD65F: 0x8B03, //CJK UNIFIED IDEOGRAPH + 0xD660: 0x8B04, //CJK UNIFIED IDEOGRAPH + 0xD661: 0x8B05, //CJK UNIFIED IDEOGRAPH + 0xD662: 0x8B06, //CJK UNIFIED IDEOGRAPH + 0xD663: 0x8B08, //CJK UNIFIED IDEOGRAPH + 0xD664: 0x8B09, //CJK UNIFIED IDEOGRAPH + 0xD665: 0x8B0A, //CJK UNIFIED IDEOGRAPH + 0xD666: 0x8B0B, //CJK UNIFIED IDEOGRAPH + 0xD667: 0x8B0C, //CJK UNIFIED IDEOGRAPH + 0xD668: 0x8B0D, //CJK UNIFIED IDEOGRAPH + 0xD669: 0x8B0E, //CJK UNIFIED IDEOGRAPH + 0xD66A: 0x8B0F, //CJK UNIFIED IDEOGRAPH + 0xD66B: 0x8B10, //CJK UNIFIED IDEOGRAPH + 0xD66C: 0x8B11, //CJK UNIFIED IDEOGRAPH + 0xD66D: 0x8B12, //CJK UNIFIED IDEOGRAPH + 0xD66E: 0x8B13, //CJK UNIFIED IDEOGRAPH + 0xD66F: 0x8B14, //CJK UNIFIED IDEOGRAPH + 0xD670: 0x8B15, //CJK UNIFIED IDEOGRAPH + 0xD671: 0x8B16, //CJK UNIFIED IDEOGRAPH + 0xD672: 0x8B17, //CJK UNIFIED IDEOGRAPH + 0xD673: 0x8B18, //CJK UNIFIED IDEOGRAPH + 0xD674: 0x8B19, //CJK UNIFIED IDEOGRAPH + 0xD675: 0x8B1A, //CJK UNIFIED IDEOGRAPH + 0xD676: 0x8B1B, //CJK UNIFIED IDEOGRAPH + 0xD677: 0x8B1C, //CJK UNIFIED IDEOGRAPH + 0xD678: 0x8B1D, //CJK UNIFIED IDEOGRAPH + 0xD679: 0x8B1E, //CJK UNIFIED IDEOGRAPH + 0xD67A: 0x8B1F, //CJK UNIFIED IDEOGRAPH + 0xD67B: 0x8B20, //CJK UNIFIED IDEOGRAPH + 0xD67C: 0x8B21, //CJK UNIFIED IDEOGRAPH + 0xD67D: 0x8B22, //CJK UNIFIED IDEOGRAPH + 0xD67E: 0x8B23, //CJK UNIFIED IDEOGRAPH + 0xD680: 0x8B24, //CJK UNIFIED IDEOGRAPH + 0xD681: 0x8B25, //CJK UNIFIED IDEOGRAPH + 0xD682: 0x8B27, //CJK UNIFIED IDEOGRAPH + 0xD683: 0x8B28, //CJK UNIFIED IDEOGRAPH + 0xD684: 0x8B29, //CJK UNIFIED IDEOGRAPH + 0xD685: 0x8B2A, //CJK UNIFIED IDEOGRAPH + 0xD686: 0x8B2B, //CJK UNIFIED IDEOGRAPH + 0xD687: 0x8B2C, //CJK UNIFIED IDEOGRAPH + 0xD688: 0x8B2D, //CJK UNIFIED IDEOGRAPH + 0xD689: 0x8B2E, //CJK UNIFIED IDEOGRAPH + 0xD68A: 0x8B2F, //CJK UNIFIED IDEOGRAPH + 0xD68B: 0x8B30, //CJK UNIFIED IDEOGRAPH + 0xD68C: 0x8B31, //CJK UNIFIED IDEOGRAPH + 0xD68D: 0x8B32, //CJK UNIFIED IDEOGRAPH + 0xD68E: 0x8B33, //CJK UNIFIED IDEOGRAPH + 0xD68F: 0x8B34, //CJK UNIFIED IDEOGRAPH + 0xD690: 0x8B35, //CJK UNIFIED IDEOGRAPH + 0xD691: 0x8B36, //CJK UNIFIED IDEOGRAPH + 0xD692: 0x8B37, //CJK UNIFIED IDEOGRAPH + 0xD693: 0x8B38, //CJK UNIFIED IDEOGRAPH + 0xD694: 0x8B39, //CJK UNIFIED IDEOGRAPH + 0xD695: 0x8B3A, //CJK UNIFIED IDEOGRAPH + 0xD696: 0x8B3B, //CJK UNIFIED IDEOGRAPH + 0xD697: 0x8B3C, //CJK UNIFIED IDEOGRAPH + 0xD698: 0x8B3D, //CJK UNIFIED IDEOGRAPH + 0xD699: 0x8B3E, //CJK UNIFIED IDEOGRAPH + 0xD69A: 0x8B3F, //CJK UNIFIED IDEOGRAPH + 0xD69B: 0x8B40, //CJK UNIFIED IDEOGRAPH + 0xD69C: 0x8B41, //CJK UNIFIED IDEOGRAPH + 0xD69D: 0x8B42, //CJK UNIFIED IDEOGRAPH + 0xD69E: 0x8B43, //CJK UNIFIED IDEOGRAPH + 0xD69F: 0x8B44, //CJK UNIFIED IDEOGRAPH + 0xD6A0: 0x8B45, //CJK UNIFIED IDEOGRAPH + 0xD6A1: 0x5E27, //CJK UNIFIED IDEOGRAPH + 0xD6A2: 0x75C7, //CJK UNIFIED IDEOGRAPH + 0xD6A3: 0x90D1, //CJK UNIFIED IDEOGRAPH + 0xD6A4: 0x8BC1, //CJK UNIFIED IDEOGRAPH + 0xD6A5: 0x829D, //CJK UNIFIED IDEOGRAPH + 0xD6A6: 0x679D, //CJK UNIFIED IDEOGRAPH + 0xD6A7: 0x652F, //CJK UNIFIED IDEOGRAPH + 0xD6A8: 0x5431, //CJK UNIFIED IDEOGRAPH + 0xD6A9: 0x8718, //CJK UNIFIED IDEOGRAPH + 0xD6AA: 0x77E5, //CJK UNIFIED IDEOGRAPH + 0xD6AB: 0x80A2, //CJK UNIFIED IDEOGRAPH + 0xD6AC: 0x8102, //CJK UNIFIED IDEOGRAPH + 0xD6AD: 0x6C41, //CJK UNIFIED IDEOGRAPH + 0xD6AE: 0x4E4B, //CJK UNIFIED IDEOGRAPH + 0xD6AF: 0x7EC7, //CJK UNIFIED IDEOGRAPH + 0xD6B0: 0x804C, //CJK UNIFIED IDEOGRAPH + 0xD6B1: 0x76F4, //CJK UNIFIED IDEOGRAPH + 0xD6B2: 0x690D, //CJK UNIFIED IDEOGRAPH + 0xD6B3: 0x6B96, //CJK UNIFIED IDEOGRAPH + 0xD6B4: 0x6267, //CJK UNIFIED IDEOGRAPH + 0xD6B5: 0x503C, //CJK UNIFIED IDEOGRAPH + 0xD6B6: 0x4F84, //CJK UNIFIED IDEOGRAPH + 0xD6B7: 0x5740, //CJK UNIFIED IDEOGRAPH + 0xD6B8: 0x6307, //CJK UNIFIED IDEOGRAPH + 0xD6B9: 0x6B62, //CJK UNIFIED IDEOGRAPH + 0xD6BA: 0x8DBE, //CJK UNIFIED IDEOGRAPH + 0xD6BB: 0x53EA, //CJK UNIFIED IDEOGRAPH + 0xD6BC: 0x65E8, //CJK UNIFIED IDEOGRAPH + 0xD6BD: 0x7EB8, //CJK UNIFIED IDEOGRAPH + 0xD6BE: 0x5FD7, //CJK UNIFIED IDEOGRAPH + 0xD6BF: 0x631A, //CJK UNIFIED IDEOGRAPH + 0xD6C0: 0x63B7, //CJK UNIFIED IDEOGRAPH + 0xD6C1: 0x81F3, //CJK UNIFIED IDEOGRAPH + 0xD6C2: 0x81F4, //CJK UNIFIED IDEOGRAPH + 0xD6C3: 0x7F6E, //CJK UNIFIED IDEOGRAPH + 0xD6C4: 0x5E1C, //CJK UNIFIED IDEOGRAPH + 0xD6C5: 0x5CD9, //CJK UNIFIED IDEOGRAPH + 0xD6C6: 0x5236, //CJK UNIFIED IDEOGRAPH + 0xD6C7: 0x667A, //CJK UNIFIED IDEOGRAPH + 0xD6C8: 0x79E9, //CJK UNIFIED IDEOGRAPH + 0xD6C9: 0x7A1A, //CJK UNIFIED IDEOGRAPH + 0xD6CA: 0x8D28, //CJK UNIFIED IDEOGRAPH + 0xD6CB: 0x7099, //CJK UNIFIED IDEOGRAPH + 0xD6CC: 0x75D4, //CJK UNIFIED IDEOGRAPH + 0xD6CD: 0x6EDE, //CJK UNIFIED IDEOGRAPH + 0xD6CE: 0x6CBB, //CJK UNIFIED IDEOGRAPH + 0xD6CF: 0x7A92, //CJK UNIFIED IDEOGRAPH + 0xD6D0: 0x4E2D, //CJK UNIFIED IDEOGRAPH + 0xD6D1: 0x76C5, //CJK UNIFIED IDEOGRAPH + 0xD6D2: 0x5FE0, //CJK UNIFIED IDEOGRAPH + 0xD6D3: 0x949F, //CJK UNIFIED IDEOGRAPH + 0xD6D4: 0x8877, //CJK UNIFIED IDEOGRAPH + 0xD6D5: 0x7EC8, //CJK UNIFIED IDEOGRAPH + 0xD6D6: 0x79CD, //CJK UNIFIED IDEOGRAPH + 0xD6D7: 0x80BF, //CJK UNIFIED IDEOGRAPH + 0xD6D8: 0x91CD, //CJK UNIFIED IDEOGRAPH + 0xD6D9: 0x4EF2, //CJK UNIFIED IDEOGRAPH + 0xD6DA: 0x4F17, //CJK UNIFIED IDEOGRAPH + 0xD6DB: 0x821F, //CJK UNIFIED IDEOGRAPH + 0xD6DC: 0x5468, //CJK UNIFIED IDEOGRAPH + 0xD6DD: 0x5DDE, //CJK UNIFIED IDEOGRAPH + 0xD6DE: 0x6D32, //CJK UNIFIED IDEOGRAPH + 0xD6DF: 0x8BCC, //CJK UNIFIED IDEOGRAPH + 0xD6E0: 0x7CA5, //CJK UNIFIED IDEOGRAPH + 0xD6E1: 0x8F74, //CJK UNIFIED IDEOGRAPH + 0xD6E2: 0x8098, //CJK UNIFIED IDEOGRAPH + 0xD6E3: 0x5E1A, //CJK UNIFIED IDEOGRAPH + 0xD6E4: 0x5492, //CJK UNIFIED IDEOGRAPH + 0xD6E5: 0x76B1, //CJK UNIFIED IDEOGRAPH + 0xD6E6: 0x5B99, //CJK UNIFIED IDEOGRAPH + 0xD6E7: 0x663C, //CJK UNIFIED IDEOGRAPH + 0xD6E8: 0x9AA4, //CJK UNIFIED IDEOGRAPH + 0xD6E9: 0x73E0, //CJK UNIFIED IDEOGRAPH + 0xD6EA: 0x682A, //CJK UNIFIED IDEOGRAPH + 0xD6EB: 0x86DB, //CJK UNIFIED IDEOGRAPH + 0xD6EC: 0x6731, //CJK UNIFIED IDEOGRAPH + 0xD6ED: 0x732A, //CJK UNIFIED IDEOGRAPH + 0xD6EE: 0x8BF8, //CJK UNIFIED IDEOGRAPH + 0xD6EF: 0x8BDB, //CJK UNIFIED IDEOGRAPH + 0xD6F0: 0x9010, //CJK UNIFIED IDEOGRAPH + 0xD6F1: 0x7AF9, //CJK UNIFIED IDEOGRAPH + 0xD6F2: 0x70DB, //CJK UNIFIED IDEOGRAPH + 0xD6F3: 0x716E, //CJK UNIFIED IDEOGRAPH + 0xD6F4: 0x62C4, //CJK UNIFIED IDEOGRAPH + 0xD6F5: 0x77A9, //CJK UNIFIED IDEOGRAPH + 0xD6F6: 0x5631, //CJK UNIFIED IDEOGRAPH + 0xD6F7: 0x4E3B, //CJK UNIFIED IDEOGRAPH + 0xD6F8: 0x8457, //CJK UNIFIED IDEOGRAPH + 0xD6F9: 0x67F1, //CJK UNIFIED IDEOGRAPH + 0xD6FA: 0x52A9, //CJK UNIFIED IDEOGRAPH + 0xD6FB: 0x86C0, //CJK UNIFIED IDEOGRAPH + 0xD6FC: 0x8D2E, //CJK UNIFIED IDEOGRAPH + 0xD6FD: 0x94F8, //CJK UNIFIED IDEOGRAPH + 0xD6FE: 0x7B51, //CJK UNIFIED IDEOGRAPH + 0xD740: 0x8B46, //CJK UNIFIED IDEOGRAPH + 0xD741: 0x8B47, //CJK UNIFIED IDEOGRAPH + 0xD742: 0x8B48, //CJK UNIFIED IDEOGRAPH + 0xD743: 0x8B49, //CJK UNIFIED IDEOGRAPH + 0xD744: 0x8B4A, //CJK UNIFIED IDEOGRAPH + 0xD745: 0x8B4B, //CJK UNIFIED IDEOGRAPH + 0xD746: 0x8B4C, //CJK UNIFIED IDEOGRAPH + 0xD747: 0x8B4D, //CJK UNIFIED IDEOGRAPH + 0xD748: 0x8B4E, //CJK UNIFIED IDEOGRAPH + 0xD749: 0x8B4F, //CJK UNIFIED IDEOGRAPH + 0xD74A: 0x8B50, //CJK UNIFIED IDEOGRAPH + 0xD74B: 0x8B51, //CJK UNIFIED IDEOGRAPH + 0xD74C: 0x8B52, //CJK UNIFIED IDEOGRAPH + 0xD74D: 0x8B53, //CJK UNIFIED IDEOGRAPH + 0xD74E: 0x8B54, //CJK UNIFIED IDEOGRAPH + 0xD74F: 0x8B55, //CJK UNIFIED IDEOGRAPH + 0xD750: 0x8B56, //CJK UNIFIED IDEOGRAPH + 0xD751: 0x8B57, //CJK UNIFIED IDEOGRAPH + 0xD752: 0x8B58, //CJK UNIFIED IDEOGRAPH + 0xD753: 0x8B59, //CJK UNIFIED IDEOGRAPH + 0xD754: 0x8B5A, //CJK UNIFIED IDEOGRAPH + 0xD755: 0x8B5B, //CJK UNIFIED IDEOGRAPH + 0xD756: 0x8B5C, //CJK UNIFIED IDEOGRAPH + 0xD757: 0x8B5D, //CJK UNIFIED IDEOGRAPH + 0xD758: 0x8B5E, //CJK UNIFIED IDEOGRAPH + 0xD759: 0x8B5F, //CJK UNIFIED IDEOGRAPH + 0xD75A: 0x8B60, //CJK UNIFIED IDEOGRAPH + 0xD75B: 0x8B61, //CJK UNIFIED IDEOGRAPH + 0xD75C: 0x8B62, //CJK UNIFIED IDEOGRAPH + 0xD75D: 0x8B63, //CJK UNIFIED IDEOGRAPH + 0xD75E: 0x8B64, //CJK UNIFIED IDEOGRAPH + 0xD75F: 0x8B65, //CJK UNIFIED IDEOGRAPH + 0xD760: 0x8B67, //CJK UNIFIED IDEOGRAPH + 0xD761: 0x8B68, //CJK UNIFIED IDEOGRAPH + 0xD762: 0x8B69, //CJK UNIFIED IDEOGRAPH + 0xD763: 0x8B6A, //CJK UNIFIED IDEOGRAPH + 0xD764: 0x8B6B, //CJK UNIFIED IDEOGRAPH + 0xD765: 0x8B6D, //CJK UNIFIED IDEOGRAPH + 0xD766: 0x8B6E, //CJK UNIFIED IDEOGRAPH + 0xD767: 0x8B6F, //CJK UNIFIED IDEOGRAPH + 0xD768: 0x8B70, //CJK UNIFIED IDEOGRAPH + 0xD769: 0x8B71, //CJK UNIFIED IDEOGRAPH + 0xD76A: 0x8B72, //CJK UNIFIED IDEOGRAPH + 0xD76B: 0x8B73, //CJK UNIFIED IDEOGRAPH + 0xD76C: 0x8B74, //CJK UNIFIED IDEOGRAPH + 0xD76D: 0x8B75, //CJK UNIFIED IDEOGRAPH + 0xD76E: 0x8B76, //CJK UNIFIED IDEOGRAPH + 0xD76F: 0x8B77, //CJK UNIFIED IDEOGRAPH + 0xD770: 0x8B78, //CJK UNIFIED IDEOGRAPH + 0xD771: 0x8B79, //CJK UNIFIED IDEOGRAPH + 0xD772: 0x8B7A, //CJK UNIFIED IDEOGRAPH + 0xD773: 0x8B7B, //CJK UNIFIED IDEOGRAPH + 0xD774: 0x8B7C, //CJK UNIFIED IDEOGRAPH + 0xD775: 0x8B7D, //CJK UNIFIED IDEOGRAPH + 0xD776: 0x8B7E, //CJK UNIFIED IDEOGRAPH + 0xD777: 0x8B7F, //CJK UNIFIED IDEOGRAPH + 0xD778: 0x8B80, //CJK UNIFIED IDEOGRAPH + 0xD779: 0x8B81, //CJK UNIFIED IDEOGRAPH + 0xD77A: 0x8B82, //CJK UNIFIED IDEOGRAPH + 0xD77B: 0x8B83, //CJK UNIFIED IDEOGRAPH + 0xD77C: 0x8B84, //CJK UNIFIED IDEOGRAPH + 0xD77D: 0x8B85, //CJK UNIFIED IDEOGRAPH + 0xD77E: 0x8B86, //CJK UNIFIED IDEOGRAPH + 0xD780: 0x8B87, //CJK UNIFIED IDEOGRAPH + 0xD781: 0x8B88, //CJK UNIFIED IDEOGRAPH + 0xD782: 0x8B89, //CJK UNIFIED IDEOGRAPH + 0xD783: 0x8B8A, //CJK UNIFIED IDEOGRAPH + 0xD784: 0x8B8B, //CJK UNIFIED IDEOGRAPH + 0xD785: 0x8B8C, //CJK UNIFIED IDEOGRAPH + 0xD786: 0x8B8D, //CJK UNIFIED IDEOGRAPH + 0xD787: 0x8B8E, //CJK UNIFIED IDEOGRAPH + 0xD788: 0x8B8F, //CJK UNIFIED IDEOGRAPH + 0xD789: 0x8B90, //CJK UNIFIED IDEOGRAPH + 0xD78A: 0x8B91, //CJK UNIFIED IDEOGRAPH + 0xD78B: 0x8B92, //CJK UNIFIED IDEOGRAPH + 0xD78C: 0x8B93, //CJK UNIFIED IDEOGRAPH + 0xD78D: 0x8B94, //CJK UNIFIED IDEOGRAPH + 0xD78E: 0x8B95, //CJK UNIFIED IDEOGRAPH + 0xD78F: 0x8B96, //CJK UNIFIED IDEOGRAPH + 0xD790: 0x8B97, //CJK UNIFIED IDEOGRAPH + 0xD791: 0x8B98, //CJK UNIFIED IDEOGRAPH + 0xD792: 0x8B99, //CJK UNIFIED IDEOGRAPH + 0xD793: 0x8B9A, //CJK UNIFIED IDEOGRAPH + 0xD794: 0x8B9B, //CJK UNIFIED IDEOGRAPH + 0xD795: 0x8B9C, //CJK UNIFIED IDEOGRAPH + 0xD796: 0x8B9D, //CJK UNIFIED IDEOGRAPH + 0xD797: 0x8B9E, //CJK UNIFIED IDEOGRAPH + 0xD798: 0x8B9F, //CJK UNIFIED IDEOGRAPH + 0xD799: 0x8BAC, //CJK UNIFIED IDEOGRAPH + 0xD79A: 0x8BB1, //CJK UNIFIED IDEOGRAPH + 0xD79B: 0x8BBB, //CJK UNIFIED IDEOGRAPH + 0xD79C: 0x8BC7, //CJK UNIFIED IDEOGRAPH + 0xD79D: 0x8BD0, //CJK UNIFIED IDEOGRAPH + 0xD79E: 0x8BEA, //CJK UNIFIED IDEOGRAPH + 0xD79F: 0x8C09, //CJK UNIFIED IDEOGRAPH + 0xD7A0: 0x8C1E, //CJK UNIFIED IDEOGRAPH + 0xD7A1: 0x4F4F, //CJK UNIFIED IDEOGRAPH + 0xD7A2: 0x6CE8, //CJK UNIFIED IDEOGRAPH + 0xD7A3: 0x795D, //CJK UNIFIED IDEOGRAPH + 0xD7A4: 0x9A7B, //CJK UNIFIED IDEOGRAPH + 0xD7A5: 0x6293, //CJK UNIFIED IDEOGRAPH + 0xD7A6: 0x722A, //CJK UNIFIED IDEOGRAPH + 0xD7A7: 0x62FD, //CJK UNIFIED IDEOGRAPH + 0xD7A8: 0x4E13, //CJK UNIFIED IDEOGRAPH + 0xD7A9: 0x7816, //CJK UNIFIED IDEOGRAPH + 0xD7AA: 0x8F6C, //CJK UNIFIED IDEOGRAPH + 0xD7AB: 0x64B0, //CJK UNIFIED IDEOGRAPH + 0xD7AC: 0x8D5A, //CJK UNIFIED IDEOGRAPH + 0xD7AD: 0x7BC6, //CJK UNIFIED IDEOGRAPH + 0xD7AE: 0x6869, //CJK UNIFIED IDEOGRAPH + 0xD7AF: 0x5E84, //CJK UNIFIED IDEOGRAPH + 0xD7B0: 0x88C5, //CJK UNIFIED IDEOGRAPH + 0xD7B1: 0x5986, //CJK UNIFIED IDEOGRAPH + 0xD7B2: 0x649E, //CJK UNIFIED IDEOGRAPH + 0xD7B3: 0x58EE, //CJK UNIFIED IDEOGRAPH + 0xD7B4: 0x72B6, //CJK UNIFIED IDEOGRAPH + 0xD7B5: 0x690E, //CJK UNIFIED IDEOGRAPH + 0xD7B6: 0x9525, //CJK UNIFIED IDEOGRAPH + 0xD7B7: 0x8FFD, //CJK UNIFIED IDEOGRAPH + 0xD7B8: 0x8D58, //CJK UNIFIED IDEOGRAPH + 0xD7B9: 0x5760, //CJK UNIFIED IDEOGRAPH + 0xD7BA: 0x7F00, //CJK UNIFIED IDEOGRAPH + 0xD7BB: 0x8C06, //CJK UNIFIED IDEOGRAPH + 0xD7BC: 0x51C6, //CJK UNIFIED IDEOGRAPH + 0xD7BD: 0x6349, //CJK UNIFIED IDEOGRAPH + 0xD7BE: 0x62D9, //CJK UNIFIED IDEOGRAPH + 0xD7BF: 0x5353, //CJK UNIFIED IDEOGRAPH + 0xD7C0: 0x684C, //CJK UNIFIED IDEOGRAPH + 0xD7C1: 0x7422, //CJK UNIFIED IDEOGRAPH + 0xD7C2: 0x8301, //CJK UNIFIED IDEOGRAPH + 0xD7C3: 0x914C, //CJK UNIFIED IDEOGRAPH + 0xD7C4: 0x5544, //CJK UNIFIED IDEOGRAPH + 0xD7C5: 0x7740, //CJK UNIFIED IDEOGRAPH + 0xD7C6: 0x707C, //CJK UNIFIED IDEOGRAPH + 0xD7C7: 0x6D4A, //CJK UNIFIED IDEOGRAPH + 0xD7C8: 0x5179, //CJK UNIFIED IDEOGRAPH + 0xD7C9: 0x54A8, //CJK UNIFIED IDEOGRAPH + 0xD7CA: 0x8D44, //CJK UNIFIED IDEOGRAPH + 0xD7CB: 0x59FF, //CJK UNIFIED IDEOGRAPH + 0xD7CC: 0x6ECB, //CJK UNIFIED IDEOGRAPH + 0xD7CD: 0x6DC4, //CJK UNIFIED IDEOGRAPH + 0xD7CE: 0x5B5C, //CJK UNIFIED IDEOGRAPH + 0xD7CF: 0x7D2B, //CJK UNIFIED IDEOGRAPH + 0xD7D0: 0x4ED4, //CJK UNIFIED IDEOGRAPH + 0xD7D1: 0x7C7D, //CJK UNIFIED IDEOGRAPH + 0xD7D2: 0x6ED3, //CJK UNIFIED IDEOGRAPH + 0xD7D3: 0x5B50, //CJK UNIFIED IDEOGRAPH + 0xD7D4: 0x81EA, //CJK UNIFIED IDEOGRAPH + 0xD7D5: 0x6E0D, //CJK UNIFIED IDEOGRAPH + 0xD7D6: 0x5B57, //CJK UNIFIED IDEOGRAPH + 0xD7D7: 0x9B03, //CJK UNIFIED IDEOGRAPH + 0xD7D8: 0x68D5, //CJK UNIFIED IDEOGRAPH + 0xD7D9: 0x8E2A, //CJK UNIFIED IDEOGRAPH + 0xD7DA: 0x5B97, //CJK UNIFIED IDEOGRAPH + 0xD7DB: 0x7EFC, //CJK UNIFIED IDEOGRAPH + 0xD7DC: 0x603B, //CJK UNIFIED IDEOGRAPH + 0xD7DD: 0x7EB5, //CJK UNIFIED IDEOGRAPH + 0xD7DE: 0x90B9, //CJK UNIFIED IDEOGRAPH + 0xD7DF: 0x8D70, //CJK UNIFIED IDEOGRAPH + 0xD7E0: 0x594F, //CJK UNIFIED IDEOGRAPH + 0xD7E1: 0x63CD, //CJK UNIFIED IDEOGRAPH + 0xD7E2: 0x79DF, //CJK UNIFIED IDEOGRAPH + 0xD7E3: 0x8DB3, //CJK UNIFIED IDEOGRAPH + 0xD7E4: 0x5352, //CJK UNIFIED IDEOGRAPH + 0xD7E5: 0x65CF, //CJK UNIFIED IDEOGRAPH + 0xD7E6: 0x7956, //CJK UNIFIED IDEOGRAPH + 0xD7E7: 0x8BC5, //CJK UNIFIED IDEOGRAPH + 0xD7E8: 0x963B, //CJK UNIFIED IDEOGRAPH + 0xD7E9: 0x7EC4, //CJK UNIFIED IDEOGRAPH + 0xD7EA: 0x94BB, //CJK UNIFIED IDEOGRAPH + 0xD7EB: 0x7E82, //CJK UNIFIED IDEOGRAPH + 0xD7EC: 0x5634, //CJK UNIFIED IDEOGRAPH + 0xD7ED: 0x9189, //CJK UNIFIED IDEOGRAPH + 0xD7EE: 0x6700, //CJK UNIFIED IDEOGRAPH + 0xD7EF: 0x7F6A, //CJK UNIFIED IDEOGRAPH + 0xD7F0: 0x5C0A, //CJK UNIFIED IDEOGRAPH + 0xD7F1: 0x9075, //CJK UNIFIED IDEOGRAPH + 0xD7F2: 0x6628, //CJK UNIFIED IDEOGRAPH + 0xD7F3: 0x5DE6, //CJK UNIFIED IDEOGRAPH + 0xD7F4: 0x4F50, //CJK UNIFIED IDEOGRAPH + 0xD7F5: 0x67DE, //CJK UNIFIED IDEOGRAPH + 0xD7F6: 0x505A, //CJK UNIFIED IDEOGRAPH + 0xD7F7: 0x4F5C, //CJK UNIFIED IDEOGRAPH + 0xD7F8: 0x5750, //CJK UNIFIED IDEOGRAPH + 0xD7F9: 0x5EA7, //CJK UNIFIED IDEOGRAPH + 0xD840: 0x8C38, //CJK UNIFIED IDEOGRAPH + 0xD841: 0x8C39, //CJK UNIFIED IDEOGRAPH + 0xD842: 0x8C3A, //CJK UNIFIED IDEOGRAPH + 0xD843: 0x8C3B, //CJK UNIFIED IDEOGRAPH + 0xD844: 0x8C3C, //CJK UNIFIED IDEOGRAPH + 0xD845: 0x8C3D, //CJK UNIFIED IDEOGRAPH + 0xD846: 0x8C3E, //CJK UNIFIED IDEOGRAPH + 0xD847: 0x8C3F, //CJK UNIFIED IDEOGRAPH + 0xD848: 0x8C40, //CJK UNIFIED IDEOGRAPH + 0xD849: 0x8C42, //CJK UNIFIED IDEOGRAPH + 0xD84A: 0x8C43, //CJK UNIFIED IDEOGRAPH + 0xD84B: 0x8C44, //CJK UNIFIED IDEOGRAPH + 0xD84C: 0x8C45, //CJK UNIFIED IDEOGRAPH + 0xD84D: 0x8C48, //CJK UNIFIED IDEOGRAPH + 0xD84E: 0x8C4A, //CJK UNIFIED IDEOGRAPH + 0xD84F: 0x8C4B, //CJK UNIFIED IDEOGRAPH + 0xD850: 0x8C4D, //CJK UNIFIED IDEOGRAPH + 0xD851: 0x8C4E, //CJK UNIFIED IDEOGRAPH + 0xD852: 0x8C4F, //CJK UNIFIED IDEOGRAPH + 0xD853: 0x8C50, //CJK UNIFIED IDEOGRAPH + 0xD854: 0x8C51, //CJK UNIFIED IDEOGRAPH + 0xD855: 0x8C52, //CJK UNIFIED IDEOGRAPH + 0xD856: 0x8C53, //CJK UNIFIED IDEOGRAPH + 0xD857: 0x8C54, //CJK UNIFIED IDEOGRAPH + 0xD858: 0x8C56, //CJK UNIFIED IDEOGRAPH + 0xD859: 0x8C57, //CJK UNIFIED IDEOGRAPH + 0xD85A: 0x8C58, //CJK UNIFIED IDEOGRAPH + 0xD85B: 0x8C59, //CJK UNIFIED IDEOGRAPH + 0xD85C: 0x8C5B, //CJK UNIFIED IDEOGRAPH + 0xD85D: 0x8C5C, //CJK UNIFIED IDEOGRAPH + 0xD85E: 0x8C5D, //CJK UNIFIED IDEOGRAPH + 0xD85F: 0x8C5E, //CJK UNIFIED IDEOGRAPH + 0xD860: 0x8C5F, //CJK UNIFIED IDEOGRAPH + 0xD861: 0x8C60, //CJK UNIFIED IDEOGRAPH + 0xD862: 0x8C63, //CJK UNIFIED IDEOGRAPH + 0xD863: 0x8C64, //CJK UNIFIED IDEOGRAPH + 0xD864: 0x8C65, //CJK UNIFIED IDEOGRAPH + 0xD865: 0x8C66, //CJK UNIFIED IDEOGRAPH + 0xD866: 0x8C67, //CJK UNIFIED IDEOGRAPH + 0xD867: 0x8C68, //CJK UNIFIED IDEOGRAPH + 0xD868: 0x8C69, //CJK UNIFIED IDEOGRAPH + 0xD869: 0x8C6C, //CJK UNIFIED IDEOGRAPH + 0xD86A: 0x8C6D, //CJK UNIFIED IDEOGRAPH + 0xD86B: 0x8C6E, //CJK UNIFIED IDEOGRAPH + 0xD86C: 0x8C6F, //CJK UNIFIED IDEOGRAPH + 0xD86D: 0x8C70, //CJK UNIFIED IDEOGRAPH + 0xD86E: 0x8C71, //CJK UNIFIED IDEOGRAPH + 0xD86F: 0x8C72, //CJK UNIFIED IDEOGRAPH + 0xD870: 0x8C74, //CJK UNIFIED IDEOGRAPH + 0xD871: 0x8C75, //CJK UNIFIED IDEOGRAPH + 0xD872: 0x8C76, //CJK UNIFIED IDEOGRAPH + 0xD873: 0x8C77, //CJK UNIFIED IDEOGRAPH + 0xD874: 0x8C7B, //CJK UNIFIED IDEOGRAPH + 0xD875: 0x8C7C, //CJK UNIFIED IDEOGRAPH + 0xD876: 0x8C7D, //CJK UNIFIED IDEOGRAPH + 0xD877: 0x8C7E, //CJK UNIFIED IDEOGRAPH + 0xD878: 0x8C7F, //CJK UNIFIED IDEOGRAPH + 0xD879: 0x8C80, //CJK UNIFIED IDEOGRAPH + 0xD87A: 0x8C81, //CJK UNIFIED IDEOGRAPH + 0xD87B: 0x8C83, //CJK UNIFIED IDEOGRAPH + 0xD87C: 0x8C84, //CJK UNIFIED IDEOGRAPH + 0xD87D: 0x8C86, //CJK UNIFIED IDEOGRAPH + 0xD87E: 0x8C87, //CJK UNIFIED IDEOGRAPH + 0xD880: 0x8C88, //CJK UNIFIED IDEOGRAPH + 0xD881: 0x8C8B, //CJK UNIFIED IDEOGRAPH + 0xD882: 0x8C8D, //CJK UNIFIED IDEOGRAPH + 0xD883: 0x8C8E, //CJK UNIFIED IDEOGRAPH + 0xD884: 0x8C8F, //CJK UNIFIED IDEOGRAPH + 0xD885: 0x8C90, //CJK UNIFIED IDEOGRAPH + 0xD886: 0x8C91, //CJK UNIFIED IDEOGRAPH + 0xD887: 0x8C92, //CJK UNIFIED IDEOGRAPH + 0xD888: 0x8C93, //CJK UNIFIED IDEOGRAPH + 0xD889: 0x8C95, //CJK UNIFIED IDEOGRAPH + 0xD88A: 0x8C96, //CJK UNIFIED IDEOGRAPH + 0xD88B: 0x8C97, //CJK UNIFIED IDEOGRAPH + 0xD88C: 0x8C99, //CJK UNIFIED IDEOGRAPH + 0xD88D: 0x8C9A, //CJK UNIFIED IDEOGRAPH + 0xD88E: 0x8C9B, //CJK UNIFIED IDEOGRAPH + 0xD88F: 0x8C9C, //CJK UNIFIED IDEOGRAPH + 0xD890: 0x8C9D, //CJK UNIFIED IDEOGRAPH + 0xD891: 0x8C9E, //CJK UNIFIED IDEOGRAPH + 0xD892: 0x8C9F, //CJK UNIFIED IDEOGRAPH + 0xD893: 0x8CA0, //CJK UNIFIED IDEOGRAPH + 0xD894: 0x8CA1, //CJK UNIFIED IDEOGRAPH + 0xD895: 0x8CA2, //CJK UNIFIED IDEOGRAPH + 0xD896: 0x8CA3, //CJK UNIFIED IDEOGRAPH + 0xD897: 0x8CA4, //CJK UNIFIED IDEOGRAPH + 0xD898: 0x8CA5, //CJK UNIFIED IDEOGRAPH + 0xD899: 0x8CA6, //CJK UNIFIED IDEOGRAPH + 0xD89A: 0x8CA7, //CJK UNIFIED IDEOGRAPH + 0xD89B: 0x8CA8, //CJK UNIFIED IDEOGRAPH + 0xD89C: 0x8CA9, //CJK UNIFIED IDEOGRAPH + 0xD89D: 0x8CAA, //CJK UNIFIED IDEOGRAPH + 0xD89E: 0x8CAB, //CJK UNIFIED IDEOGRAPH + 0xD89F: 0x8CAC, //CJK UNIFIED IDEOGRAPH + 0xD8A0: 0x8CAD, //CJK UNIFIED IDEOGRAPH + 0xD8A1: 0x4E8D, //CJK UNIFIED IDEOGRAPH + 0xD8A2: 0x4E0C, //CJK UNIFIED IDEOGRAPH + 0xD8A3: 0x5140, //CJK UNIFIED IDEOGRAPH + 0xD8A4: 0x4E10, //CJK UNIFIED IDEOGRAPH + 0xD8A5: 0x5EFF, //CJK UNIFIED IDEOGRAPH + 0xD8A6: 0x5345, //CJK UNIFIED IDEOGRAPH + 0xD8A7: 0x4E15, //CJK UNIFIED IDEOGRAPH + 0xD8A8: 0x4E98, //CJK UNIFIED IDEOGRAPH + 0xD8A9: 0x4E1E, //CJK UNIFIED IDEOGRAPH + 0xD8AA: 0x9B32, //CJK UNIFIED IDEOGRAPH + 0xD8AB: 0x5B6C, //CJK UNIFIED IDEOGRAPH + 0xD8AC: 0x5669, //CJK UNIFIED IDEOGRAPH + 0xD8AD: 0x4E28, //CJK UNIFIED IDEOGRAPH + 0xD8AE: 0x79BA, //CJK UNIFIED IDEOGRAPH + 0xD8AF: 0x4E3F, //CJK UNIFIED IDEOGRAPH + 0xD8B0: 0x5315, //CJK UNIFIED IDEOGRAPH + 0xD8B1: 0x4E47, //CJK UNIFIED IDEOGRAPH + 0xD8B2: 0x592D, //CJK UNIFIED IDEOGRAPH + 0xD8B3: 0x723B, //CJK UNIFIED IDEOGRAPH + 0xD8B4: 0x536E, //CJK UNIFIED IDEOGRAPH + 0xD8B5: 0x6C10, //CJK UNIFIED IDEOGRAPH + 0xD8B6: 0x56DF, //CJK UNIFIED IDEOGRAPH + 0xD8B7: 0x80E4, //CJK UNIFIED IDEOGRAPH + 0xD8B8: 0x9997, //CJK UNIFIED IDEOGRAPH + 0xD8B9: 0x6BD3, //CJK UNIFIED IDEOGRAPH + 0xD8BA: 0x777E, //CJK UNIFIED IDEOGRAPH + 0xD8BB: 0x9F17, //CJK UNIFIED IDEOGRAPH + 0xD8BC: 0x4E36, //CJK UNIFIED IDEOGRAPH + 0xD8BD: 0x4E9F, //CJK UNIFIED IDEOGRAPH + 0xD8BE: 0x9F10, //CJK UNIFIED IDEOGRAPH + 0xD8BF: 0x4E5C, //CJK UNIFIED IDEOGRAPH + 0xD8C0: 0x4E69, //CJK UNIFIED IDEOGRAPH + 0xD8C1: 0x4E93, //CJK UNIFIED IDEOGRAPH + 0xD8C2: 0x8288, //CJK UNIFIED IDEOGRAPH + 0xD8C3: 0x5B5B, //CJK UNIFIED IDEOGRAPH + 0xD8C4: 0x556C, //CJK UNIFIED IDEOGRAPH + 0xD8C5: 0x560F, //CJK UNIFIED IDEOGRAPH + 0xD8C6: 0x4EC4, //CJK UNIFIED IDEOGRAPH + 0xD8C7: 0x538D, //CJK UNIFIED IDEOGRAPH + 0xD8C8: 0x539D, //CJK UNIFIED IDEOGRAPH + 0xD8C9: 0x53A3, //CJK UNIFIED IDEOGRAPH + 0xD8CA: 0x53A5, //CJK UNIFIED IDEOGRAPH + 0xD8CB: 0x53AE, //CJK UNIFIED IDEOGRAPH + 0xD8CC: 0x9765, //CJK UNIFIED IDEOGRAPH + 0xD8CD: 0x8D5D, //CJK UNIFIED IDEOGRAPH + 0xD8CE: 0x531A, //CJK UNIFIED IDEOGRAPH + 0xD8CF: 0x53F5, //CJK UNIFIED IDEOGRAPH + 0xD8D0: 0x5326, //CJK UNIFIED IDEOGRAPH + 0xD8D1: 0x532E, //CJK UNIFIED IDEOGRAPH + 0xD8D2: 0x533E, //CJK UNIFIED IDEOGRAPH + 0xD8D3: 0x8D5C, //CJK UNIFIED IDEOGRAPH + 0xD8D4: 0x5366, //CJK UNIFIED IDEOGRAPH + 0xD8D5: 0x5363, //CJK UNIFIED IDEOGRAPH + 0xD8D6: 0x5202, //CJK UNIFIED IDEOGRAPH + 0xD8D7: 0x5208, //CJK UNIFIED IDEOGRAPH + 0xD8D8: 0x520E, //CJK UNIFIED IDEOGRAPH + 0xD8D9: 0x522D, //CJK UNIFIED IDEOGRAPH + 0xD8DA: 0x5233, //CJK UNIFIED IDEOGRAPH + 0xD8DB: 0x523F, //CJK UNIFIED IDEOGRAPH + 0xD8DC: 0x5240, //CJK UNIFIED IDEOGRAPH + 0xD8DD: 0x524C, //CJK UNIFIED IDEOGRAPH + 0xD8DE: 0x525E, //CJK UNIFIED IDEOGRAPH + 0xD8DF: 0x5261, //CJK UNIFIED IDEOGRAPH + 0xD8E0: 0x525C, //CJK UNIFIED IDEOGRAPH + 0xD8E1: 0x84AF, //CJK UNIFIED IDEOGRAPH + 0xD8E2: 0x527D, //CJK UNIFIED IDEOGRAPH + 0xD8E3: 0x5282, //CJK UNIFIED IDEOGRAPH + 0xD8E4: 0x5281, //CJK UNIFIED IDEOGRAPH + 0xD8E5: 0x5290, //CJK UNIFIED IDEOGRAPH + 0xD8E6: 0x5293, //CJK UNIFIED IDEOGRAPH + 0xD8E7: 0x5182, //CJK UNIFIED IDEOGRAPH + 0xD8E8: 0x7F54, //CJK UNIFIED IDEOGRAPH + 0xD8E9: 0x4EBB, //CJK UNIFIED IDEOGRAPH + 0xD8EA: 0x4EC3, //CJK UNIFIED IDEOGRAPH + 0xD8EB: 0x4EC9, //CJK UNIFIED IDEOGRAPH + 0xD8EC: 0x4EC2, //CJK UNIFIED IDEOGRAPH + 0xD8ED: 0x4EE8, //CJK UNIFIED IDEOGRAPH + 0xD8EE: 0x4EE1, //CJK UNIFIED IDEOGRAPH + 0xD8EF: 0x4EEB, //CJK UNIFIED IDEOGRAPH + 0xD8F0: 0x4EDE, //CJK UNIFIED IDEOGRAPH + 0xD8F1: 0x4F1B, //CJK UNIFIED IDEOGRAPH + 0xD8F2: 0x4EF3, //CJK UNIFIED IDEOGRAPH + 0xD8F3: 0x4F22, //CJK UNIFIED IDEOGRAPH + 0xD8F4: 0x4F64, //CJK UNIFIED IDEOGRAPH + 0xD8F5: 0x4EF5, //CJK UNIFIED IDEOGRAPH + 0xD8F6: 0x4F25, //CJK UNIFIED IDEOGRAPH + 0xD8F7: 0x4F27, //CJK UNIFIED IDEOGRAPH + 0xD8F8: 0x4F09, //CJK UNIFIED IDEOGRAPH + 0xD8F9: 0x4F2B, //CJK UNIFIED IDEOGRAPH + 0xD8FA: 0x4F5E, //CJK UNIFIED IDEOGRAPH + 0xD8FB: 0x4F67, //CJK UNIFIED IDEOGRAPH + 0xD8FC: 0x6538, //CJK UNIFIED IDEOGRAPH + 0xD8FD: 0x4F5A, //CJK UNIFIED IDEOGRAPH + 0xD8FE: 0x4F5D, //CJK UNIFIED IDEOGRAPH + 0xD940: 0x8CAE, //CJK UNIFIED IDEOGRAPH + 0xD941: 0x8CAF, //CJK UNIFIED IDEOGRAPH + 0xD942: 0x8CB0, //CJK UNIFIED IDEOGRAPH + 0xD943: 0x8CB1, //CJK UNIFIED IDEOGRAPH + 0xD944: 0x8CB2, //CJK UNIFIED IDEOGRAPH + 0xD945: 0x8CB3, //CJK UNIFIED IDEOGRAPH + 0xD946: 0x8CB4, //CJK UNIFIED IDEOGRAPH + 0xD947: 0x8CB5, //CJK UNIFIED IDEOGRAPH + 0xD948: 0x8CB6, //CJK UNIFIED IDEOGRAPH + 0xD949: 0x8CB7, //CJK UNIFIED IDEOGRAPH + 0xD94A: 0x8CB8, //CJK UNIFIED IDEOGRAPH + 0xD94B: 0x8CB9, //CJK UNIFIED IDEOGRAPH + 0xD94C: 0x8CBA, //CJK UNIFIED IDEOGRAPH + 0xD94D: 0x8CBB, //CJK UNIFIED IDEOGRAPH + 0xD94E: 0x8CBC, //CJK UNIFIED IDEOGRAPH + 0xD94F: 0x8CBD, //CJK UNIFIED IDEOGRAPH + 0xD950: 0x8CBE, //CJK UNIFIED IDEOGRAPH + 0xD951: 0x8CBF, //CJK UNIFIED IDEOGRAPH + 0xD952: 0x8CC0, //CJK UNIFIED IDEOGRAPH + 0xD953: 0x8CC1, //CJK UNIFIED IDEOGRAPH + 0xD954: 0x8CC2, //CJK UNIFIED IDEOGRAPH + 0xD955: 0x8CC3, //CJK UNIFIED IDEOGRAPH + 0xD956: 0x8CC4, //CJK UNIFIED IDEOGRAPH + 0xD957: 0x8CC5, //CJK UNIFIED IDEOGRAPH + 0xD958: 0x8CC6, //CJK UNIFIED IDEOGRAPH + 0xD959: 0x8CC7, //CJK UNIFIED IDEOGRAPH + 0xD95A: 0x8CC8, //CJK UNIFIED IDEOGRAPH + 0xD95B: 0x8CC9, //CJK UNIFIED IDEOGRAPH + 0xD95C: 0x8CCA, //CJK UNIFIED IDEOGRAPH + 0xD95D: 0x8CCB, //CJK UNIFIED IDEOGRAPH + 0xD95E: 0x8CCC, //CJK UNIFIED IDEOGRAPH + 0xD95F: 0x8CCD, //CJK UNIFIED IDEOGRAPH + 0xD960: 0x8CCE, //CJK UNIFIED IDEOGRAPH + 0xD961: 0x8CCF, //CJK UNIFIED IDEOGRAPH + 0xD962: 0x8CD0, //CJK UNIFIED IDEOGRAPH + 0xD963: 0x8CD1, //CJK UNIFIED IDEOGRAPH + 0xD964: 0x8CD2, //CJK UNIFIED IDEOGRAPH + 0xD965: 0x8CD3, //CJK UNIFIED IDEOGRAPH + 0xD966: 0x8CD4, //CJK UNIFIED IDEOGRAPH + 0xD967: 0x8CD5, //CJK UNIFIED IDEOGRAPH + 0xD968: 0x8CD6, //CJK UNIFIED IDEOGRAPH + 0xD969: 0x8CD7, //CJK UNIFIED IDEOGRAPH + 0xD96A: 0x8CD8, //CJK UNIFIED IDEOGRAPH + 0xD96B: 0x8CD9, //CJK UNIFIED IDEOGRAPH + 0xD96C: 0x8CDA, //CJK UNIFIED IDEOGRAPH + 0xD96D: 0x8CDB, //CJK UNIFIED IDEOGRAPH + 0xD96E: 0x8CDC, //CJK UNIFIED IDEOGRAPH + 0xD96F: 0x8CDD, //CJK UNIFIED IDEOGRAPH + 0xD970: 0x8CDE, //CJK UNIFIED IDEOGRAPH + 0xD971: 0x8CDF, //CJK UNIFIED IDEOGRAPH + 0xD972: 0x8CE0, //CJK UNIFIED IDEOGRAPH + 0xD973: 0x8CE1, //CJK UNIFIED IDEOGRAPH + 0xD974: 0x8CE2, //CJK UNIFIED IDEOGRAPH + 0xD975: 0x8CE3, //CJK UNIFIED IDEOGRAPH + 0xD976: 0x8CE4, //CJK UNIFIED IDEOGRAPH + 0xD977: 0x8CE5, //CJK UNIFIED IDEOGRAPH + 0xD978: 0x8CE6, //CJK UNIFIED IDEOGRAPH + 0xD979: 0x8CE7, //CJK UNIFIED IDEOGRAPH + 0xD97A: 0x8CE8, //CJK UNIFIED IDEOGRAPH + 0xD97B: 0x8CE9, //CJK UNIFIED IDEOGRAPH + 0xD97C: 0x8CEA, //CJK UNIFIED IDEOGRAPH + 0xD97D: 0x8CEB, //CJK UNIFIED IDEOGRAPH + 0xD97E: 0x8CEC, //CJK UNIFIED IDEOGRAPH + 0xD980: 0x8CED, //CJK UNIFIED IDEOGRAPH + 0xD981: 0x8CEE, //CJK UNIFIED IDEOGRAPH + 0xD982: 0x8CEF, //CJK UNIFIED IDEOGRAPH + 0xD983: 0x8CF0, //CJK UNIFIED IDEOGRAPH + 0xD984: 0x8CF1, //CJK UNIFIED IDEOGRAPH + 0xD985: 0x8CF2, //CJK UNIFIED IDEOGRAPH + 0xD986: 0x8CF3, //CJK UNIFIED IDEOGRAPH + 0xD987: 0x8CF4, //CJK UNIFIED IDEOGRAPH + 0xD988: 0x8CF5, //CJK UNIFIED IDEOGRAPH + 0xD989: 0x8CF6, //CJK UNIFIED IDEOGRAPH + 0xD98A: 0x8CF7, //CJK UNIFIED IDEOGRAPH + 0xD98B: 0x8CF8, //CJK UNIFIED IDEOGRAPH + 0xD98C: 0x8CF9, //CJK UNIFIED IDEOGRAPH + 0xD98D: 0x8CFA, //CJK UNIFIED IDEOGRAPH + 0xD98E: 0x8CFB, //CJK UNIFIED IDEOGRAPH + 0xD98F: 0x8CFC, //CJK UNIFIED IDEOGRAPH + 0xD990: 0x8CFD, //CJK UNIFIED IDEOGRAPH + 0xD991: 0x8CFE, //CJK UNIFIED IDEOGRAPH + 0xD992: 0x8CFF, //CJK UNIFIED IDEOGRAPH + 0xD993: 0x8D00, //CJK UNIFIED IDEOGRAPH + 0xD994: 0x8D01, //CJK UNIFIED IDEOGRAPH + 0xD995: 0x8D02, //CJK UNIFIED IDEOGRAPH + 0xD996: 0x8D03, //CJK UNIFIED IDEOGRAPH + 0xD997: 0x8D04, //CJK UNIFIED IDEOGRAPH + 0xD998: 0x8D05, //CJK UNIFIED IDEOGRAPH + 0xD999: 0x8D06, //CJK UNIFIED IDEOGRAPH + 0xD99A: 0x8D07, //CJK UNIFIED IDEOGRAPH + 0xD99B: 0x8D08, //CJK UNIFIED IDEOGRAPH + 0xD99C: 0x8D09, //CJK UNIFIED IDEOGRAPH + 0xD99D: 0x8D0A, //CJK UNIFIED IDEOGRAPH + 0xD99E: 0x8D0B, //CJK UNIFIED IDEOGRAPH + 0xD99F: 0x8D0C, //CJK UNIFIED IDEOGRAPH + 0xD9A0: 0x8D0D, //CJK UNIFIED IDEOGRAPH + 0xD9A1: 0x4F5F, //CJK UNIFIED IDEOGRAPH + 0xD9A2: 0x4F57, //CJK UNIFIED IDEOGRAPH + 0xD9A3: 0x4F32, //CJK UNIFIED IDEOGRAPH + 0xD9A4: 0x4F3D, //CJK UNIFIED IDEOGRAPH + 0xD9A5: 0x4F76, //CJK UNIFIED IDEOGRAPH + 0xD9A6: 0x4F74, //CJK UNIFIED IDEOGRAPH + 0xD9A7: 0x4F91, //CJK UNIFIED IDEOGRAPH + 0xD9A8: 0x4F89, //CJK UNIFIED IDEOGRAPH + 0xD9A9: 0x4F83, //CJK UNIFIED IDEOGRAPH + 0xD9AA: 0x4F8F, //CJK UNIFIED IDEOGRAPH + 0xD9AB: 0x4F7E, //CJK UNIFIED IDEOGRAPH + 0xD9AC: 0x4F7B, //CJK UNIFIED IDEOGRAPH + 0xD9AD: 0x4FAA, //CJK UNIFIED IDEOGRAPH + 0xD9AE: 0x4F7C, //CJK UNIFIED IDEOGRAPH + 0xD9AF: 0x4FAC, //CJK UNIFIED IDEOGRAPH + 0xD9B0: 0x4F94, //CJK UNIFIED IDEOGRAPH + 0xD9B1: 0x4FE6, //CJK UNIFIED IDEOGRAPH + 0xD9B2: 0x4FE8, //CJK UNIFIED IDEOGRAPH + 0xD9B3: 0x4FEA, //CJK UNIFIED IDEOGRAPH + 0xD9B4: 0x4FC5, //CJK UNIFIED IDEOGRAPH + 0xD9B5: 0x4FDA, //CJK UNIFIED IDEOGRAPH + 0xD9B6: 0x4FE3, //CJK UNIFIED IDEOGRAPH + 0xD9B7: 0x4FDC, //CJK UNIFIED IDEOGRAPH + 0xD9B8: 0x4FD1, //CJK UNIFIED IDEOGRAPH + 0xD9B9: 0x4FDF, //CJK UNIFIED IDEOGRAPH + 0xD9BA: 0x4FF8, //CJK UNIFIED IDEOGRAPH + 0xD9BB: 0x5029, //CJK UNIFIED IDEOGRAPH + 0xD9BC: 0x504C, //CJK UNIFIED IDEOGRAPH + 0xD9BD: 0x4FF3, //CJK UNIFIED IDEOGRAPH + 0xD9BE: 0x502C, //CJK UNIFIED IDEOGRAPH + 0xD9BF: 0x500F, //CJK UNIFIED IDEOGRAPH + 0xD9C0: 0x502E, //CJK UNIFIED IDEOGRAPH + 0xD9C1: 0x502D, //CJK UNIFIED IDEOGRAPH + 0xD9C2: 0x4FFE, //CJK UNIFIED IDEOGRAPH + 0xD9C3: 0x501C, //CJK UNIFIED IDEOGRAPH + 0xD9C4: 0x500C, //CJK UNIFIED IDEOGRAPH + 0xD9C5: 0x5025, //CJK UNIFIED IDEOGRAPH + 0xD9C6: 0x5028, //CJK UNIFIED IDEOGRAPH + 0xD9C7: 0x507E, //CJK UNIFIED IDEOGRAPH + 0xD9C8: 0x5043, //CJK UNIFIED IDEOGRAPH + 0xD9C9: 0x5055, //CJK UNIFIED IDEOGRAPH + 0xD9CA: 0x5048, //CJK UNIFIED IDEOGRAPH + 0xD9CB: 0x504E, //CJK UNIFIED IDEOGRAPH + 0xD9CC: 0x506C, //CJK UNIFIED IDEOGRAPH + 0xD9CD: 0x507B, //CJK UNIFIED IDEOGRAPH + 0xD9CE: 0x50A5, //CJK UNIFIED IDEOGRAPH + 0xD9CF: 0x50A7, //CJK UNIFIED IDEOGRAPH + 0xD9D0: 0x50A9, //CJK UNIFIED IDEOGRAPH + 0xD9D1: 0x50BA, //CJK UNIFIED IDEOGRAPH + 0xD9D2: 0x50D6, //CJK UNIFIED IDEOGRAPH + 0xD9D3: 0x5106, //CJK UNIFIED IDEOGRAPH + 0xD9D4: 0x50ED, //CJK UNIFIED IDEOGRAPH + 0xD9D5: 0x50EC, //CJK UNIFIED IDEOGRAPH + 0xD9D6: 0x50E6, //CJK UNIFIED IDEOGRAPH + 0xD9D7: 0x50EE, //CJK UNIFIED IDEOGRAPH + 0xD9D8: 0x5107, //CJK UNIFIED IDEOGRAPH + 0xD9D9: 0x510B, //CJK UNIFIED IDEOGRAPH + 0xD9DA: 0x4EDD, //CJK UNIFIED IDEOGRAPH + 0xD9DB: 0x6C3D, //CJK UNIFIED IDEOGRAPH + 0xD9DC: 0x4F58, //CJK UNIFIED IDEOGRAPH + 0xD9DD: 0x4F65, //CJK UNIFIED IDEOGRAPH + 0xD9DE: 0x4FCE, //CJK UNIFIED IDEOGRAPH + 0xD9DF: 0x9FA0, //CJK UNIFIED IDEOGRAPH + 0xD9E0: 0x6C46, //CJK UNIFIED IDEOGRAPH + 0xD9E1: 0x7C74, //CJK UNIFIED IDEOGRAPH + 0xD9E2: 0x516E, //CJK UNIFIED IDEOGRAPH + 0xD9E3: 0x5DFD, //CJK UNIFIED IDEOGRAPH + 0xD9E4: 0x9EC9, //CJK UNIFIED IDEOGRAPH + 0xD9E5: 0x9998, //CJK UNIFIED IDEOGRAPH + 0xD9E6: 0x5181, //CJK UNIFIED IDEOGRAPH + 0xD9E7: 0x5914, //CJK UNIFIED IDEOGRAPH + 0xD9E8: 0x52F9, //CJK UNIFIED IDEOGRAPH + 0xD9E9: 0x530D, //CJK UNIFIED IDEOGRAPH + 0xD9EA: 0x8A07, //CJK UNIFIED IDEOGRAPH + 0xD9EB: 0x5310, //CJK UNIFIED IDEOGRAPH + 0xD9EC: 0x51EB, //CJK UNIFIED IDEOGRAPH + 0xD9ED: 0x5919, //CJK UNIFIED IDEOGRAPH + 0xD9EE: 0x5155, //CJK UNIFIED IDEOGRAPH + 0xD9EF: 0x4EA0, //CJK UNIFIED IDEOGRAPH + 0xD9F0: 0x5156, //CJK UNIFIED IDEOGRAPH + 0xD9F1: 0x4EB3, //CJK UNIFIED IDEOGRAPH + 0xD9F2: 0x886E, //CJK UNIFIED IDEOGRAPH + 0xD9F3: 0x88A4, //CJK UNIFIED IDEOGRAPH + 0xD9F4: 0x4EB5, //CJK UNIFIED IDEOGRAPH + 0xD9F5: 0x8114, //CJK UNIFIED IDEOGRAPH + 0xD9F6: 0x88D2, //CJK UNIFIED IDEOGRAPH + 0xD9F7: 0x7980, //CJK UNIFIED IDEOGRAPH + 0xD9F8: 0x5B34, //CJK UNIFIED IDEOGRAPH + 0xD9F9: 0x8803, //CJK UNIFIED IDEOGRAPH + 0xD9FA: 0x7FB8, //CJK UNIFIED IDEOGRAPH + 0xD9FB: 0x51AB, //CJK UNIFIED IDEOGRAPH + 0xD9FC: 0x51B1, //CJK UNIFIED IDEOGRAPH + 0xD9FD: 0x51BD, //CJK UNIFIED IDEOGRAPH + 0xD9FE: 0x51BC, //CJK UNIFIED IDEOGRAPH + 0xDA40: 0x8D0E, //CJK UNIFIED IDEOGRAPH + 0xDA41: 0x8D0F, //CJK UNIFIED IDEOGRAPH + 0xDA42: 0x8D10, //CJK UNIFIED IDEOGRAPH + 0xDA43: 0x8D11, //CJK UNIFIED IDEOGRAPH + 0xDA44: 0x8D12, //CJK UNIFIED IDEOGRAPH + 0xDA45: 0x8D13, //CJK UNIFIED IDEOGRAPH + 0xDA46: 0x8D14, //CJK UNIFIED IDEOGRAPH + 0xDA47: 0x8D15, //CJK UNIFIED IDEOGRAPH + 0xDA48: 0x8D16, //CJK UNIFIED IDEOGRAPH + 0xDA49: 0x8D17, //CJK UNIFIED IDEOGRAPH + 0xDA4A: 0x8D18, //CJK UNIFIED IDEOGRAPH + 0xDA4B: 0x8D19, //CJK UNIFIED IDEOGRAPH + 0xDA4C: 0x8D1A, //CJK UNIFIED IDEOGRAPH + 0xDA4D: 0x8D1B, //CJK UNIFIED IDEOGRAPH + 0xDA4E: 0x8D1C, //CJK UNIFIED IDEOGRAPH + 0xDA4F: 0x8D20, //CJK UNIFIED IDEOGRAPH + 0xDA50: 0x8D51, //CJK UNIFIED IDEOGRAPH + 0xDA51: 0x8D52, //CJK UNIFIED IDEOGRAPH + 0xDA52: 0x8D57, //CJK UNIFIED IDEOGRAPH + 0xDA53: 0x8D5F, //CJK UNIFIED IDEOGRAPH + 0xDA54: 0x8D65, //CJK UNIFIED IDEOGRAPH + 0xDA55: 0x8D68, //CJK UNIFIED IDEOGRAPH + 0xDA56: 0x8D69, //CJK UNIFIED IDEOGRAPH + 0xDA57: 0x8D6A, //CJK UNIFIED IDEOGRAPH + 0xDA58: 0x8D6C, //CJK UNIFIED IDEOGRAPH + 0xDA59: 0x8D6E, //CJK UNIFIED IDEOGRAPH + 0xDA5A: 0x8D6F, //CJK UNIFIED IDEOGRAPH + 0xDA5B: 0x8D71, //CJK UNIFIED IDEOGRAPH + 0xDA5C: 0x8D72, //CJK UNIFIED IDEOGRAPH + 0xDA5D: 0x8D78, //CJK UNIFIED IDEOGRAPH + 0xDA5E: 0x8D79, //CJK UNIFIED IDEOGRAPH + 0xDA5F: 0x8D7A, //CJK UNIFIED IDEOGRAPH + 0xDA60: 0x8D7B, //CJK UNIFIED IDEOGRAPH + 0xDA61: 0x8D7C, //CJK UNIFIED IDEOGRAPH + 0xDA62: 0x8D7D, //CJK UNIFIED IDEOGRAPH + 0xDA63: 0x8D7E, //CJK UNIFIED IDEOGRAPH + 0xDA64: 0x8D7F, //CJK UNIFIED IDEOGRAPH + 0xDA65: 0x8D80, //CJK UNIFIED IDEOGRAPH + 0xDA66: 0x8D82, //CJK UNIFIED IDEOGRAPH + 0xDA67: 0x8D83, //CJK UNIFIED IDEOGRAPH + 0xDA68: 0x8D86, //CJK UNIFIED IDEOGRAPH + 0xDA69: 0x8D87, //CJK UNIFIED IDEOGRAPH + 0xDA6A: 0x8D88, //CJK UNIFIED IDEOGRAPH + 0xDA6B: 0x8D89, //CJK UNIFIED IDEOGRAPH + 0xDA6C: 0x8D8C, //CJK UNIFIED IDEOGRAPH + 0xDA6D: 0x8D8D, //CJK UNIFIED IDEOGRAPH + 0xDA6E: 0x8D8E, //CJK UNIFIED IDEOGRAPH + 0xDA6F: 0x8D8F, //CJK UNIFIED IDEOGRAPH + 0xDA70: 0x8D90, //CJK UNIFIED IDEOGRAPH + 0xDA71: 0x8D92, //CJK UNIFIED IDEOGRAPH + 0xDA72: 0x8D93, //CJK UNIFIED IDEOGRAPH + 0xDA73: 0x8D95, //CJK UNIFIED IDEOGRAPH + 0xDA74: 0x8D96, //CJK UNIFIED IDEOGRAPH + 0xDA75: 0x8D97, //CJK UNIFIED IDEOGRAPH + 0xDA76: 0x8D98, //CJK UNIFIED IDEOGRAPH + 0xDA77: 0x8D99, //CJK UNIFIED IDEOGRAPH + 0xDA78: 0x8D9A, //CJK UNIFIED IDEOGRAPH + 0xDA79: 0x8D9B, //CJK UNIFIED IDEOGRAPH + 0xDA7A: 0x8D9C, //CJK UNIFIED IDEOGRAPH + 0xDA7B: 0x8D9D, //CJK UNIFIED IDEOGRAPH + 0xDA7C: 0x8D9E, //CJK UNIFIED IDEOGRAPH + 0xDA7D: 0x8DA0, //CJK UNIFIED IDEOGRAPH + 0xDA7E: 0x8DA1, //CJK UNIFIED IDEOGRAPH + 0xDA80: 0x8DA2, //CJK UNIFIED IDEOGRAPH + 0xDA81: 0x8DA4, //CJK UNIFIED IDEOGRAPH + 0xDA82: 0x8DA5, //CJK UNIFIED IDEOGRAPH + 0xDA83: 0x8DA6, //CJK UNIFIED IDEOGRAPH + 0xDA84: 0x8DA7, //CJK UNIFIED IDEOGRAPH + 0xDA85: 0x8DA8, //CJK UNIFIED IDEOGRAPH + 0xDA86: 0x8DA9, //CJK UNIFIED IDEOGRAPH + 0xDA87: 0x8DAA, //CJK UNIFIED IDEOGRAPH + 0xDA88: 0x8DAB, //CJK UNIFIED IDEOGRAPH + 0xDA89: 0x8DAC, //CJK UNIFIED IDEOGRAPH + 0xDA8A: 0x8DAD, //CJK UNIFIED IDEOGRAPH + 0xDA8B: 0x8DAE, //CJK UNIFIED IDEOGRAPH + 0xDA8C: 0x8DAF, //CJK UNIFIED IDEOGRAPH + 0xDA8D: 0x8DB0, //CJK UNIFIED IDEOGRAPH + 0xDA8E: 0x8DB2, //CJK UNIFIED IDEOGRAPH + 0xDA8F: 0x8DB6, //CJK UNIFIED IDEOGRAPH + 0xDA90: 0x8DB7, //CJK UNIFIED IDEOGRAPH + 0xDA91: 0x8DB9, //CJK UNIFIED IDEOGRAPH + 0xDA92: 0x8DBB, //CJK UNIFIED IDEOGRAPH + 0xDA93: 0x8DBD, //CJK UNIFIED IDEOGRAPH + 0xDA94: 0x8DC0, //CJK UNIFIED IDEOGRAPH + 0xDA95: 0x8DC1, //CJK UNIFIED IDEOGRAPH + 0xDA96: 0x8DC2, //CJK UNIFIED IDEOGRAPH + 0xDA97: 0x8DC5, //CJK UNIFIED IDEOGRAPH + 0xDA98: 0x8DC7, //CJK UNIFIED IDEOGRAPH + 0xDA99: 0x8DC8, //CJK UNIFIED IDEOGRAPH + 0xDA9A: 0x8DC9, //CJK UNIFIED IDEOGRAPH + 0xDA9B: 0x8DCA, //CJK UNIFIED IDEOGRAPH + 0xDA9C: 0x8DCD, //CJK UNIFIED IDEOGRAPH + 0xDA9D: 0x8DD0, //CJK UNIFIED IDEOGRAPH + 0xDA9E: 0x8DD2, //CJK UNIFIED IDEOGRAPH + 0xDA9F: 0x8DD3, //CJK UNIFIED IDEOGRAPH + 0xDAA0: 0x8DD4, //CJK UNIFIED IDEOGRAPH + 0xDAA1: 0x51C7, //CJK UNIFIED IDEOGRAPH + 0xDAA2: 0x5196, //CJK UNIFIED IDEOGRAPH + 0xDAA3: 0x51A2, //CJK UNIFIED IDEOGRAPH + 0xDAA4: 0x51A5, //CJK UNIFIED IDEOGRAPH + 0xDAA5: 0x8BA0, //CJK UNIFIED IDEOGRAPH + 0xDAA6: 0x8BA6, //CJK UNIFIED IDEOGRAPH + 0xDAA7: 0x8BA7, //CJK UNIFIED IDEOGRAPH + 0xDAA8: 0x8BAA, //CJK UNIFIED IDEOGRAPH + 0xDAA9: 0x8BB4, //CJK UNIFIED IDEOGRAPH + 0xDAAA: 0x8BB5, //CJK UNIFIED IDEOGRAPH + 0xDAAB: 0x8BB7, //CJK UNIFIED IDEOGRAPH + 0xDAAC: 0x8BC2, //CJK UNIFIED IDEOGRAPH + 0xDAAD: 0x8BC3, //CJK UNIFIED IDEOGRAPH + 0xDAAE: 0x8BCB, //CJK UNIFIED IDEOGRAPH + 0xDAAF: 0x8BCF, //CJK UNIFIED IDEOGRAPH + 0xDAB0: 0x8BCE, //CJK UNIFIED IDEOGRAPH + 0xDAB1: 0x8BD2, //CJK UNIFIED IDEOGRAPH + 0xDAB2: 0x8BD3, //CJK UNIFIED IDEOGRAPH + 0xDAB3: 0x8BD4, //CJK UNIFIED IDEOGRAPH + 0xDAB4: 0x8BD6, //CJK UNIFIED IDEOGRAPH + 0xDAB5: 0x8BD8, //CJK UNIFIED IDEOGRAPH + 0xDAB6: 0x8BD9, //CJK UNIFIED IDEOGRAPH + 0xDAB7: 0x8BDC, //CJK UNIFIED IDEOGRAPH + 0xDAB8: 0x8BDF, //CJK UNIFIED IDEOGRAPH + 0xDAB9: 0x8BE0, //CJK UNIFIED IDEOGRAPH + 0xDABA: 0x8BE4, //CJK UNIFIED IDEOGRAPH + 0xDABB: 0x8BE8, //CJK UNIFIED IDEOGRAPH + 0xDABC: 0x8BE9, //CJK UNIFIED IDEOGRAPH + 0xDABD: 0x8BEE, //CJK UNIFIED IDEOGRAPH + 0xDABE: 0x8BF0, //CJK UNIFIED IDEOGRAPH + 0xDABF: 0x8BF3, //CJK UNIFIED IDEOGRAPH + 0xDAC0: 0x8BF6, //CJK UNIFIED IDEOGRAPH + 0xDAC1: 0x8BF9, //CJK UNIFIED IDEOGRAPH + 0xDAC2: 0x8BFC, //CJK UNIFIED IDEOGRAPH + 0xDAC3: 0x8BFF, //CJK UNIFIED IDEOGRAPH + 0xDAC4: 0x8C00, //CJK UNIFIED IDEOGRAPH + 0xDAC5: 0x8C02, //CJK UNIFIED IDEOGRAPH + 0xDAC6: 0x8C04, //CJK UNIFIED IDEOGRAPH + 0xDAC7: 0x8C07, //CJK UNIFIED IDEOGRAPH + 0xDAC8: 0x8C0C, //CJK UNIFIED IDEOGRAPH + 0xDAC9: 0x8C0F, //CJK UNIFIED IDEOGRAPH + 0xDACA: 0x8C11, //CJK UNIFIED IDEOGRAPH + 0xDACB: 0x8C12, //CJK UNIFIED IDEOGRAPH + 0xDACC: 0x8C14, //CJK UNIFIED IDEOGRAPH + 0xDACD: 0x8C15, //CJK UNIFIED IDEOGRAPH + 0xDACE: 0x8C16, //CJK UNIFIED IDEOGRAPH + 0xDACF: 0x8C19, //CJK UNIFIED IDEOGRAPH + 0xDAD0: 0x8C1B, //CJK UNIFIED IDEOGRAPH + 0xDAD1: 0x8C18, //CJK UNIFIED IDEOGRAPH + 0xDAD2: 0x8C1D, //CJK UNIFIED IDEOGRAPH + 0xDAD3: 0x8C1F, //CJK UNIFIED IDEOGRAPH + 0xDAD4: 0x8C20, //CJK UNIFIED IDEOGRAPH + 0xDAD5: 0x8C21, //CJK UNIFIED IDEOGRAPH + 0xDAD6: 0x8C25, //CJK UNIFIED IDEOGRAPH + 0xDAD7: 0x8C27, //CJK UNIFIED IDEOGRAPH + 0xDAD8: 0x8C2A, //CJK UNIFIED IDEOGRAPH + 0xDAD9: 0x8C2B, //CJK UNIFIED IDEOGRAPH + 0xDADA: 0x8C2E, //CJK UNIFIED IDEOGRAPH + 0xDADB: 0x8C2F, //CJK UNIFIED IDEOGRAPH + 0xDADC: 0x8C32, //CJK UNIFIED IDEOGRAPH + 0xDADD: 0x8C33, //CJK UNIFIED IDEOGRAPH + 0xDADE: 0x8C35, //CJK UNIFIED IDEOGRAPH + 0xDADF: 0x8C36, //CJK UNIFIED IDEOGRAPH + 0xDAE0: 0x5369, //CJK UNIFIED IDEOGRAPH + 0xDAE1: 0x537A, //CJK UNIFIED IDEOGRAPH + 0xDAE2: 0x961D, //CJK UNIFIED IDEOGRAPH + 0xDAE3: 0x9622, //CJK UNIFIED IDEOGRAPH + 0xDAE4: 0x9621, //CJK UNIFIED IDEOGRAPH + 0xDAE5: 0x9631, //CJK UNIFIED IDEOGRAPH + 0xDAE6: 0x962A, //CJK UNIFIED IDEOGRAPH + 0xDAE7: 0x963D, //CJK UNIFIED IDEOGRAPH + 0xDAE8: 0x963C, //CJK UNIFIED IDEOGRAPH + 0xDAE9: 0x9642, //CJK UNIFIED IDEOGRAPH + 0xDAEA: 0x9649, //CJK UNIFIED IDEOGRAPH + 0xDAEB: 0x9654, //CJK UNIFIED IDEOGRAPH + 0xDAEC: 0x965F, //CJK UNIFIED IDEOGRAPH + 0xDAED: 0x9667, //CJK UNIFIED IDEOGRAPH + 0xDAEE: 0x966C, //CJK UNIFIED IDEOGRAPH + 0xDAEF: 0x9672, //CJK UNIFIED IDEOGRAPH + 0xDAF0: 0x9674, //CJK UNIFIED IDEOGRAPH + 0xDAF1: 0x9688, //CJK UNIFIED IDEOGRAPH + 0xDAF2: 0x968D, //CJK UNIFIED IDEOGRAPH + 0xDAF3: 0x9697, //CJK UNIFIED IDEOGRAPH + 0xDAF4: 0x96B0, //CJK UNIFIED IDEOGRAPH + 0xDAF5: 0x9097, //CJK UNIFIED IDEOGRAPH + 0xDAF6: 0x909B, //CJK UNIFIED IDEOGRAPH + 0xDAF7: 0x909D, //CJK UNIFIED IDEOGRAPH + 0xDAF8: 0x9099, //CJK UNIFIED IDEOGRAPH + 0xDAF9: 0x90AC, //CJK UNIFIED IDEOGRAPH + 0xDAFA: 0x90A1, //CJK UNIFIED IDEOGRAPH + 0xDAFB: 0x90B4, //CJK UNIFIED IDEOGRAPH + 0xDAFC: 0x90B3, //CJK UNIFIED IDEOGRAPH + 0xDAFD: 0x90B6, //CJK UNIFIED IDEOGRAPH + 0xDAFE: 0x90BA, //CJK UNIFIED IDEOGRAPH + 0xDB40: 0x8DD5, //CJK UNIFIED IDEOGRAPH + 0xDB41: 0x8DD8, //CJK UNIFIED IDEOGRAPH + 0xDB42: 0x8DD9, //CJK UNIFIED IDEOGRAPH + 0xDB43: 0x8DDC, //CJK UNIFIED IDEOGRAPH + 0xDB44: 0x8DE0, //CJK UNIFIED IDEOGRAPH + 0xDB45: 0x8DE1, //CJK UNIFIED IDEOGRAPH + 0xDB46: 0x8DE2, //CJK UNIFIED IDEOGRAPH + 0xDB47: 0x8DE5, //CJK UNIFIED IDEOGRAPH + 0xDB48: 0x8DE6, //CJK UNIFIED IDEOGRAPH + 0xDB49: 0x8DE7, //CJK UNIFIED IDEOGRAPH + 0xDB4A: 0x8DE9, //CJK UNIFIED IDEOGRAPH + 0xDB4B: 0x8DED, //CJK UNIFIED IDEOGRAPH + 0xDB4C: 0x8DEE, //CJK UNIFIED IDEOGRAPH + 0xDB4D: 0x8DF0, //CJK UNIFIED IDEOGRAPH + 0xDB4E: 0x8DF1, //CJK UNIFIED IDEOGRAPH + 0xDB4F: 0x8DF2, //CJK UNIFIED IDEOGRAPH + 0xDB50: 0x8DF4, //CJK UNIFIED IDEOGRAPH + 0xDB51: 0x8DF6, //CJK UNIFIED IDEOGRAPH + 0xDB52: 0x8DFC, //CJK UNIFIED IDEOGRAPH + 0xDB53: 0x8DFE, //CJK UNIFIED IDEOGRAPH + 0xDB54: 0x8DFF, //CJK UNIFIED IDEOGRAPH + 0xDB55: 0x8E00, //CJK UNIFIED IDEOGRAPH + 0xDB56: 0x8E01, //CJK UNIFIED IDEOGRAPH + 0xDB57: 0x8E02, //CJK UNIFIED IDEOGRAPH + 0xDB58: 0x8E03, //CJK UNIFIED IDEOGRAPH + 0xDB59: 0x8E04, //CJK UNIFIED IDEOGRAPH + 0xDB5A: 0x8E06, //CJK UNIFIED IDEOGRAPH + 0xDB5B: 0x8E07, //CJK UNIFIED IDEOGRAPH + 0xDB5C: 0x8E08, //CJK UNIFIED IDEOGRAPH + 0xDB5D: 0x8E0B, //CJK UNIFIED IDEOGRAPH + 0xDB5E: 0x8E0D, //CJK UNIFIED IDEOGRAPH + 0xDB5F: 0x8E0E, //CJK UNIFIED IDEOGRAPH + 0xDB60: 0x8E10, //CJK UNIFIED IDEOGRAPH + 0xDB61: 0x8E11, //CJK UNIFIED IDEOGRAPH + 0xDB62: 0x8E12, //CJK UNIFIED IDEOGRAPH + 0xDB63: 0x8E13, //CJK UNIFIED IDEOGRAPH + 0xDB64: 0x8E15, //CJK UNIFIED IDEOGRAPH + 0xDB65: 0x8E16, //CJK UNIFIED IDEOGRAPH + 0xDB66: 0x8E17, //CJK UNIFIED IDEOGRAPH + 0xDB67: 0x8E18, //CJK UNIFIED IDEOGRAPH + 0xDB68: 0x8E19, //CJK UNIFIED IDEOGRAPH + 0xDB69: 0x8E1A, //CJK UNIFIED IDEOGRAPH + 0xDB6A: 0x8E1B, //CJK UNIFIED IDEOGRAPH + 0xDB6B: 0x8E1C, //CJK UNIFIED IDEOGRAPH + 0xDB6C: 0x8E20, //CJK UNIFIED IDEOGRAPH + 0xDB6D: 0x8E21, //CJK UNIFIED IDEOGRAPH + 0xDB6E: 0x8E24, //CJK UNIFIED IDEOGRAPH + 0xDB6F: 0x8E25, //CJK UNIFIED IDEOGRAPH + 0xDB70: 0x8E26, //CJK UNIFIED IDEOGRAPH + 0xDB71: 0x8E27, //CJK UNIFIED IDEOGRAPH + 0xDB72: 0x8E28, //CJK UNIFIED IDEOGRAPH + 0xDB73: 0x8E2B, //CJK UNIFIED IDEOGRAPH + 0xDB74: 0x8E2D, //CJK UNIFIED IDEOGRAPH + 0xDB75: 0x8E30, //CJK UNIFIED IDEOGRAPH + 0xDB76: 0x8E32, //CJK UNIFIED IDEOGRAPH + 0xDB77: 0x8E33, //CJK UNIFIED IDEOGRAPH + 0xDB78: 0x8E34, //CJK UNIFIED IDEOGRAPH + 0xDB79: 0x8E36, //CJK UNIFIED IDEOGRAPH + 0xDB7A: 0x8E37, //CJK UNIFIED IDEOGRAPH + 0xDB7B: 0x8E38, //CJK UNIFIED IDEOGRAPH + 0xDB7C: 0x8E3B, //CJK UNIFIED IDEOGRAPH + 0xDB7D: 0x8E3C, //CJK UNIFIED IDEOGRAPH + 0xDB7E: 0x8E3E, //CJK UNIFIED IDEOGRAPH + 0xDB80: 0x8E3F, //CJK UNIFIED IDEOGRAPH + 0xDB81: 0x8E43, //CJK UNIFIED IDEOGRAPH + 0xDB82: 0x8E45, //CJK UNIFIED IDEOGRAPH + 0xDB83: 0x8E46, //CJK UNIFIED IDEOGRAPH + 0xDB84: 0x8E4C, //CJK UNIFIED IDEOGRAPH + 0xDB85: 0x8E4D, //CJK UNIFIED IDEOGRAPH + 0xDB86: 0x8E4E, //CJK UNIFIED IDEOGRAPH + 0xDB87: 0x8E4F, //CJK UNIFIED IDEOGRAPH + 0xDB88: 0x8E50, //CJK UNIFIED IDEOGRAPH + 0xDB89: 0x8E53, //CJK UNIFIED IDEOGRAPH + 0xDB8A: 0x8E54, //CJK UNIFIED IDEOGRAPH + 0xDB8B: 0x8E55, //CJK UNIFIED IDEOGRAPH + 0xDB8C: 0x8E56, //CJK UNIFIED IDEOGRAPH + 0xDB8D: 0x8E57, //CJK UNIFIED IDEOGRAPH + 0xDB8E: 0x8E58, //CJK UNIFIED IDEOGRAPH + 0xDB8F: 0x8E5A, //CJK UNIFIED IDEOGRAPH + 0xDB90: 0x8E5B, //CJK UNIFIED IDEOGRAPH + 0xDB91: 0x8E5C, //CJK UNIFIED IDEOGRAPH + 0xDB92: 0x8E5D, //CJK UNIFIED IDEOGRAPH + 0xDB93: 0x8E5E, //CJK UNIFIED IDEOGRAPH + 0xDB94: 0x8E5F, //CJK UNIFIED IDEOGRAPH + 0xDB95: 0x8E60, //CJK UNIFIED IDEOGRAPH + 0xDB96: 0x8E61, //CJK UNIFIED IDEOGRAPH + 0xDB97: 0x8E62, //CJK UNIFIED IDEOGRAPH + 0xDB98: 0x8E63, //CJK UNIFIED IDEOGRAPH + 0xDB99: 0x8E64, //CJK UNIFIED IDEOGRAPH + 0xDB9A: 0x8E65, //CJK UNIFIED IDEOGRAPH + 0xDB9B: 0x8E67, //CJK UNIFIED IDEOGRAPH + 0xDB9C: 0x8E68, //CJK UNIFIED IDEOGRAPH + 0xDB9D: 0x8E6A, //CJK UNIFIED IDEOGRAPH + 0xDB9E: 0x8E6B, //CJK UNIFIED IDEOGRAPH + 0xDB9F: 0x8E6E, //CJK UNIFIED IDEOGRAPH + 0xDBA0: 0x8E71, //CJK UNIFIED IDEOGRAPH + 0xDBA1: 0x90B8, //CJK UNIFIED IDEOGRAPH + 0xDBA2: 0x90B0, //CJK UNIFIED IDEOGRAPH + 0xDBA3: 0x90CF, //CJK UNIFIED IDEOGRAPH + 0xDBA4: 0x90C5, //CJK UNIFIED IDEOGRAPH + 0xDBA5: 0x90BE, //CJK UNIFIED IDEOGRAPH + 0xDBA6: 0x90D0, //CJK UNIFIED IDEOGRAPH + 0xDBA7: 0x90C4, //CJK UNIFIED IDEOGRAPH + 0xDBA8: 0x90C7, //CJK UNIFIED IDEOGRAPH + 0xDBA9: 0x90D3, //CJK UNIFIED IDEOGRAPH + 0xDBAA: 0x90E6, //CJK UNIFIED IDEOGRAPH + 0xDBAB: 0x90E2, //CJK UNIFIED IDEOGRAPH + 0xDBAC: 0x90DC, //CJK UNIFIED IDEOGRAPH + 0xDBAD: 0x90D7, //CJK UNIFIED IDEOGRAPH + 0xDBAE: 0x90DB, //CJK UNIFIED IDEOGRAPH + 0xDBAF: 0x90EB, //CJK UNIFIED IDEOGRAPH + 0xDBB0: 0x90EF, //CJK UNIFIED IDEOGRAPH + 0xDBB1: 0x90FE, //CJK UNIFIED IDEOGRAPH + 0xDBB2: 0x9104, //CJK UNIFIED IDEOGRAPH + 0xDBB3: 0x9122, //CJK UNIFIED IDEOGRAPH + 0xDBB4: 0x911E, //CJK UNIFIED IDEOGRAPH + 0xDBB5: 0x9123, //CJK UNIFIED IDEOGRAPH + 0xDBB6: 0x9131, //CJK UNIFIED IDEOGRAPH + 0xDBB7: 0x912F, //CJK UNIFIED IDEOGRAPH + 0xDBB8: 0x9139, //CJK UNIFIED IDEOGRAPH + 0xDBB9: 0x9143, //CJK UNIFIED IDEOGRAPH + 0xDBBA: 0x9146, //CJK UNIFIED IDEOGRAPH + 0xDBBB: 0x520D, //CJK UNIFIED IDEOGRAPH + 0xDBBC: 0x5942, //CJK UNIFIED IDEOGRAPH + 0xDBBD: 0x52A2, //CJK UNIFIED IDEOGRAPH + 0xDBBE: 0x52AC, //CJK UNIFIED IDEOGRAPH + 0xDBBF: 0x52AD, //CJK UNIFIED IDEOGRAPH + 0xDBC0: 0x52BE, //CJK UNIFIED IDEOGRAPH + 0xDBC1: 0x54FF, //CJK UNIFIED IDEOGRAPH + 0xDBC2: 0x52D0, //CJK UNIFIED IDEOGRAPH + 0xDBC3: 0x52D6, //CJK UNIFIED IDEOGRAPH + 0xDBC4: 0x52F0, //CJK UNIFIED IDEOGRAPH + 0xDBC5: 0x53DF, //CJK UNIFIED IDEOGRAPH + 0xDBC6: 0x71EE, //CJK UNIFIED IDEOGRAPH + 0xDBC7: 0x77CD, //CJK UNIFIED IDEOGRAPH + 0xDBC8: 0x5EF4, //CJK UNIFIED IDEOGRAPH + 0xDBC9: 0x51F5, //CJK UNIFIED IDEOGRAPH + 0xDBCA: 0x51FC, //CJK UNIFIED IDEOGRAPH + 0xDBCB: 0x9B2F, //CJK UNIFIED IDEOGRAPH + 0xDBCC: 0x53B6, //CJK UNIFIED IDEOGRAPH + 0xDBCD: 0x5F01, //CJK UNIFIED IDEOGRAPH + 0xDBCE: 0x755A, //CJK UNIFIED IDEOGRAPH + 0xDBCF: 0x5DEF, //CJK UNIFIED IDEOGRAPH + 0xDBD0: 0x574C, //CJK UNIFIED IDEOGRAPH + 0xDBD1: 0x57A9, //CJK UNIFIED IDEOGRAPH + 0xDBD2: 0x57A1, //CJK UNIFIED IDEOGRAPH + 0xDBD3: 0x587E, //CJK UNIFIED IDEOGRAPH + 0xDBD4: 0x58BC, //CJK UNIFIED IDEOGRAPH + 0xDBD5: 0x58C5, //CJK UNIFIED IDEOGRAPH + 0xDBD6: 0x58D1, //CJK UNIFIED IDEOGRAPH + 0xDBD7: 0x5729, //CJK UNIFIED IDEOGRAPH + 0xDBD8: 0x572C, //CJK UNIFIED IDEOGRAPH + 0xDBD9: 0x572A, //CJK UNIFIED IDEOGRAPH + 0xDBDA: 0x5733, //CJK UNIFIED IDEOGRAPH + 0xDBDB: 0x5739, //CJK UNIFIED IDEOGRAPH + 0xDBDC: 0x572E, //CJK UNIFIED IDEOGRAPH + 0xDBDD: 0x572F, //CJK UNIFIED IDEOGRAPH + 0xDBDE: 0x575C, //CJK UNIFIED IDEOGRAPH + 0xDBDF: 0x573B, //CJK UNIFIED IDEOGRAPH + 0xDBE0: 0x5742, //CJK UNIFIED IDEOGRAPH + 0xDBE1: 0x5769, //CJK UNIFIED IDEOGRAPH + 0xDBE2: 0x5785, //CJK UNIFIED IDEOGRAPH + 0xDBE3: 0x576B, //CJK UNIFIED IDEOGRAPH + 0xDBE4: 0x5786, //CJK UNIFIED IDEOGRAPH + 0xDBE5: 0x577C, //CJK UNIFIED IDEOGRAPH + 0xDBE6: 0x577B, //CJK UNIFIED IDEOGRAPH + 0xDBE7: 0x5768, //CJK UNIFIED IDEOGRAPH + 0xDBE8: 0x576D, //CJK UNIFIED IDEOGRAPH + 0xDBE9: 0x5776, //CJK UNIFIED IDEOGRAPH + 0xDBEA: 0x5773, //CJK UNIFIED IDEOGRAPH + 0xDBEB: 0x57AD, //CJK UNIFIED IDEOGRAPH + 0xDBEC: 0x57A4, //CJK UNIFIED IDEOGRAPH + 0xDBED: 0x578C, //CJK UNIFIED IDEOGRAPH + 0xDBEE: 0x57B2, //CJK UNIFIED IDEOGRAPH + 0xDBEF: 0x57CF, //CJK UNIFIED IDEOGRAPH + 0xDBF0: 0x57A7, //CJK UNIFIED IDEOGRAPH + 0xDBF1: 0x57B4, //CJK UNIFIED IDEOGRAPH + 0xDBF2: 0x5793, //CJK UNIFIED IDEOGRAPH + 0xDBF3: 0x57A0, //CJK UNIFIED IDEOGRAPH + 0xDBF4: 0x57D5, //CJK UNIFIED IDEOGRAPH + 0xDBF5: 0x57D8, //CJK UNIFIED IDEOGRAPH + 0xDBF6: 0x57DA, //CJK UNIFIED IDEOGRAPH + 0xDBF7: 0x57D9, //CJK UNIFIED IDEOGRAPH + 0xDBF8: 0x57D2, //CJK UNIFIED IDEOGRAPH + 0xDBF9: 0x57B8, //CJK UNIFIED IDEOGRAPH + 0xDBFA: 0x57F4, //CJK UNIFIED IDEOGRAPH + 0xDBFB: 0x57EF, //CJK UNIFIED IDEOGRAPH + 0xDBFC: 0x57F8, //CJK UNIFIED IDEOGRAPH + 0xDBFD: 0x57E4, //CJK UNIFIED IDEOGRAPH + 0xDBFE: 0x57DD, //CJK UNIFIED IDEOGRAPH + 0xDC40: 0x8E73, //CJK UNIFIED IDEOGRAPH + 0xDC41: 0x8E75, //CJK UNIFIED IDEOGRAPH + 0xDC42: 0x8E77, //CJK UNIFIED IDEOGRAPH + 0xDC43: 0x8E78, //CJK UNIFIED IDEOGRAPH + 0xDC44: 0x8E79, //CJK UNIFIED IDEOGRAPH + 0xDC45: 0x8E7A, //CJK UNIFIED IDEOGRAPH + 0xDC46: 0x8E7B, //CJK UNIFIED IDEOGRAPH + 0xDC47: 0x8E7D, //CJK UNIFIED IDEOGRAPH + 0xDC48: 0x8E7E, //CJK UNIFIED IDEOGRAPH + 0xDC49: 0x8E80, //CJK UNIFIED IDEOGRAPH + 0xDC4A: 0x8E82, //CJK UNIFIED IDEOGRAPH + 0xDC4B: 0x8E83, //CJK UNIFIED IDEOGRAPH + 0xDC4C: 0x8E84, //CJK UNIFIED IDEOGRAPH + 0xDC4D: 0x8E86, //CJK UNIFIED IDEOGRAPH + 0xDC4E: 0x8E88, //CJK UNIFIED IDEOGRAPH + 0xDC4F: 0x8E89, //CJK UNIFIED IDEOGRAPH + 0xDC50: 0x8E8A, //CJK UNIFIED IDEOGRAPH + 0xDC51: 0x8E8B, //CJK UNIFIED IDEOGRAPH + 0xDC52: 0x8E8C, //CJK UNIFIED IDEOGRAPH + 0xDC53: 0x8E8D, //CJK UNIFIED IDEOGRAPH + 0xDC54: 0x8E8E, //CJK UNIFIED IDEOGRAPH + 0xDC55: 0x8E91, //CJK UNIFIED IDEOGRAPH + 0xDC56: 0x8E92, //CJK UNIFIED IDEOGRAPH + 0xDC57: 0x8E93, //CJK UNIFIED IDEOGRAPH + 0xDC58: 0x8E95, //CJK UNIFIED IDEOGRAPH + 0xDC59: 0x8E96, //CJK UNIFIED IDEOGRAPH + 0xDC5A: 0x8E97, //CJK UNIFIED IDEOGRAPH + 0xDC5B: 0x8E98, //CJK UNIFIED IDEOGRAPH + 0xDC5C: 0x8E99, //CJK UNIFIED IDEOGRAPH + 0xDC5D: 0x8E9A, //CJK UNIFIED IDEOGRAPH + 0xDC5E: 0x8E9B, //CJK UNIFIED IDEOGRAPH + 0xDC5F: 0x8E9D, //CJK UNIFIED IDEOGRAPH + 0xDC60: 0x8E9F, //CJK UNIFIED IDEOGRAPH + 0xDC61: 0x8EA0, //CJK UNIFIED IDEOGRAPH + 0xDC62: 0x8EA1, //CJK UNIFIED IDEOGRAPH + 0xDC63: 0x8EA2, //CJK UNIFIED IDEOGRAPH + 0xDC64: 0x8EA3, //CJK UNIFIED IDEOGRAPH + 0xDC65: 0x8EA4, //CJK UNIFIED IDEOGRAPH + 0xDC66: 0x8EA5, //CJK UNIFIED IDEOGRAPH + 0xDC67: 0x8EA6, //CJK UNIFIED IDEOGRAPH + 0xDC68: 0x8EA7, //CJK UNIFIED IDEOGRAPH + 0xDC69: 0x8EA8, //CJK UNIFIED IDEOGRAPH + 0xDC6A: 0x8EA9, //CJK UNIFIED IDEOGRAPH + 0xDC6B: 0x8EAA, //CJK UNIFIED IDEOGRAPH + 0xDC6C: 0x8EAD, //CJK UNIFIED IDEOGRAPH + 0xDC6D: 0x8EAE, //CJK UNIFIED IDEOGRAPH + 0xDC6E: 0x8EB0, //CJK UNIFIED IDEOGRAPH + 0xDC6F: 0x8EB1, //CJK UNIFIED IDEOGRAPH + 0xDC70: 0x8EB3, //CJK UNIFIED IDEOGRAPH + 0xDC71: 0x8EB4, //CJK UNIFIED IDEOGRAPH + 0xDC72: 0x8EB5, //CJK UNIFIED IDEOGRAPH + 0xDC73: 0x8EB6, //CJK UNIFIED IDEOGRAPH + 0xDC74: 0x8EB7, //CJK UNIFIED IDEOGRAPH + 0xDC75: 0x8EB8, //CJK UNIFIED IDEOGRAPH + 0xDC76: 0x8EB9, //CJK UNIFIED IDEOGRAPH + 0xDC77: 0x8EBB, //CJK UNIFIED IDEOGRAPH + 0xDC78: 0x8EBC, //CJK UNIFIED IDEOGRAPH + 0xDC79: 0x8EBD, //CJK UNIFIED IDEOGRAPH + 0xDC7A: 0x8EBE, //CJK UNIFIED IDEOGRAPH + 0xDC7B: 0x8EBF, //CJK UNIFIED IDEOGRAPH + 0xDC7C: 0x8EC0, //CJK UNIFIED IDEOGRAPH + 0xDC7D: 0x8EC1, //CJK UNIFIED IDEOGRAPH + 0xDC7E: 0x8EC2, //CJK UNIFIED IDEOGRAPH + 0xDC80: 0x8EC3, //CJK UNIFIED IDEOGRAPH + 0xDC81: 0x8EC4, //CJK UNIFIED IDEOGRAPH + 0xDC82: 0x8EC5, //CJK UNIFIED IDEOGRAPH + 0xDC83: 0x8EC6, //CJK UNIFIED IDEOGRAPH + 0xDC84: 0x8EC7, //CJK UNIFIED IDEOGRAPH + 0xDC85: 0x8EC8, //CJK UNIFIED IDEOGRAPH + 0xDC86: 0x8EC9, //CJK UNIFIED IDEOGRAPH + 0xDC87: 0x8ECA, //CJK UNIFIED IDEOGRAPH + 0xDC88: 0x8ECB, //CJK UNIFIED IDEOGRAPH + 0xDC89: 0x8ECC, //CJK UNIFIED IDEOGRAPH + 0xDC8A: 0x8ECD, //CJK UNIFIED IDEOGRAPH + 0xDC8B: 0x8ECF, //CJK UNIFIED IDEOGRAPH + 0xDC8C: 0x8ED0, //CJK UNIFIED IDEOGRAPH + 0xDC8D: 0x8ED1, //CJK UNIFIED IDEOGRAPH + 0xDC8E: 0x8ED2, //CJK UNIFIED IDEOGRAPH + 0xDC8F: 0x8ED3, //CJK UNIFIED IDEOGRAPH + 0xDC90: 0x8ED4, //CJK UNIFIED IDEOGRAPH + 0xDC91: 0x8ED5, //CJK UNIFIED IDEOGRAPH + 0xDC92: 0x8ED6, //CJK UNIFIED IDEOGRAPH + 0xDC93: 0x8ED7, //CJK UNIFIED IDEOGRAPH + 0xDC94: 0x8ED8, //CJK UNIFIED IDEOGRAPH + 0xDC95: 0x8ED9, //CJK UNIFIED IDEOGRAPH + 0xDC96: 0x8EDA, //CJK UNIFIED IDEOGRAPH + 0xDC97: 0x8EDB, //CJK UNIFIED IDEOGRAPH + 0xDC98: 0x8EDC, //CJK UNIFIED IDEOGRAPH + 0xDC99: 0x8EDD, //CJK UNIFIED IDEOGRAPH + 0xDC9A: 0x8EDE, //CJK UNIFIED IDEOGRAPH + 0xDC9B: 0x8EDF, //CJK UNIFIED IDEOGRAPH + 0xDC9C: 0x8EE0, //CJK UNIFIED IDEOGRAPH + 0xDC9D: 0x8EE1, //CJK UNIFIED IDEOGRAPH + 0xDC9E: 0x8EE2, //CJK UNIFIED IDEOGRAPH + 0xDC9F: 0x8EE3, //CJK UNIFIED IDEOGRAPH + 0xDCA0: 0x8EE4, //CJK UNIFIED IDEOGRAPH + 0xDCA1: 0x580B, //CJK UNIFIED IDEOGRAPH + 0xDCA2: 0x580D, //CJK UNIFIED IDEOGRAPH + 0xDCA3: 0x57FD, //CJK UNIFIED IDEOGRAPH + 0xDCA4: 0x57ED, //CJK UNIFIED IDEOGRAPH + 0xDCA5: 0x5800, //CJK UNIFIED IDEOGRAPH + 0xDCA6: 0x581E, //CJK UNIFIED IDEOGRAPH + 0xDCA7: 0x5819, //CJK UNIFIED IDEOGRAPH + 0xDCA8: 0x5844, //CJK UNIFIED IDEOGRAPH + 0xDCA9: 0x5820, //CJK UNIFIED IDEOGRAPH + 0xDCAA: 0x5865, //CJK UNIFIED IDEOGRAPH + 0xDCAB: 0x586C, //CJK UNIFIED IDEOGRAPH + 0xDCAC: 0x5881, //CJK UNIFIED IDEOGRAPH + 0xDCAD: 0x5889, //CJK UNIFIED IDEOGRAPH + 0xDCAE: 0x589A, //CJK UNIFIED IDEOGRAPH + 0xDCAF: 0x5880, //CJK UNIFIED IDEOGRAPH + 0xDCB0: 0x99A8, //CJK UNIFIED IDEOGRAPH + 0xDCB1: 0x9F19, //CJK UNIFIED IDEOGRAPH + 0xDCB2: 0x61FF, //CJK UNIFIED IDEOGRAPH + 0xDCB3: 0x8279, //CJK UNIFIED IDEOGRAPH + 0xDCB4: 0x827D, //CJK UNIFIED IDEOGRAPH + 0xDCB5: 0x827F, //CJK UNIFIED IDEOGRAPH + 0xDCB6: 0x828F, //CJK UNIFIED IDEOGRAPH + 0xDCB7: 0x828A, //CJK UNIFIED IDEOGRAPH + 0xDCB8: 0x82A8, //CJK UNIFIED IDEOGRAPH + 0xDCB9: 0x8284, //CJK UNIFIED IDEOGRAPH + 0xDCBA: 0x828E, //CJK UNIFIED IDEOGRAPH + 0xDCBB: 0x8291, //CJK UNIFIED IDEOGRAPH + 0xDCBC: 0x8297, //CJK UNIFIED IDEOGRAPH + 0xDCBD: 0x8299, //CJK UNIFIED IDEOGRAPH + 0xDCBE: 0x82AB, //CJK UNIFIED IDEOGRAPH + 0xDCBF: 0x82B8, //CJK UNIFIED IDEOGRAPH + 0xDCC0: 0x82BE, //CJK UNIFIED IDEOGRAPH + 0xDCC1: 0x82B0, //CJK UNIFIED IDEOGRAPH + 0xDCC2: 0x82C8, //CJK UNIFIED IDEOGRAPH + 0xDCC3: 0x82CA, //CJK UNIFIED IDEOGRAPH + 0xDCC4: 0x82E3, //CJK UNIFIED IDEOGRAPH + 0xDCC5: 0x8298, //CJK UNIFIED IDEOGRAPH + 0xDCC6: 0x82B7, //CJK UNIFIED IDEOGRAPH + 0xDCC7: 0x82AE, //CJK UNIFIED IDEOGRAPH + 0xDCC8: 0x82CB, //CJK UNIFIED IDEOGRAPH + 0xDCC9: 0x82CC, //CJK UNIFIED IDEOGRAPH + 0xDCCA: 0x82C1, //CJK UNIFIED IDEOGRAPH + 0xDCCB: 0x82A9, //CJK UNIFIED IDEOGRAPH + 0xDCCC: 0x82B4, //CJK UNIFIED IDEOGRAPH + 0xDCCD: 0x82A1, //CJK UNIFIED IDEOGRAPH + 0xDCCE: 0x82AA, //CJK UNIFIED IDEOGRAPH + 0xDCCF: 0x829F, //CJK UNIFIED IDEOGRAPH + 0xDCD0: 0x82C4, //CJK UNIFIED IDEOGRAPH + 0xDCD1: 0x82CE, //CJK UNIFIED IDEOGRAPH + 0xDCD2: 0x82A4, //CJK UNIFIED IDEOGRAPH + 0xDCD3: 0x82E1, //CJK UNIFIED IDEOGRAPH + 0xDCD4: 0x8309, //CJK UNIFIED IDEOGRAPH + 0xDCD5: 0x82F7, //CJK UNIFIED IDEOGRAPH + 0xDCD6: 0x82E4, //CJK UNIFIED IDEOGRAPH + 0xDCD7: 0x830F, //CJK UNIFIED IDEOGRAPH + 0xDCD8: 0x8307, //CJK UNIFIED IDEOGRAPH + 0xDCD9: 0x82DC, //CJK UNIFIED IDEOGRAPH + 0xDCDA: 0x82F4, //CJK UNIFIED IDEOGRAPH + 0xDCDB: 0x82D2, //CJK UNIFIED IDEOGRAPH + 0xDCDC: 0x82D8, //CJK UNIFIED IDEOGRAPH + 0xDCDD: 0x830C, //CJK UNIFIED IDEOGRAPH + 0xDCDE: 0x82FB, //CJK UNIFIED IDEOGRAPH + 0xDCDF: 0x82D3, //CJK UNIFIED IDEOGRAPH + 0xDCE0: 0x8311, //CJK UNIFIED IDEOGRAPH + 0xDCE1: 0x831A, //CJK UNIFIED IDEOGRAPH + 0xDCE2: 0x8306, //CJK UNIFIED IDEOGRAPH + 0xDCE3: 0x8314, //CJK UNIFIED IDEOGRAPH + 0xDCE4: 0x8315, //CJK UNIFIED IDEOGRAPH + 0xDCE5: 0x82E0, //CJK UNIFIED IDEOGRAPH + 0xDCE6: 0x82D5, //CJK UNIFIED IDEOGRAPH + 0xDCE7: 0x831C, //CJK UNIFIED IDEOGRAPH + 0xDCE8: 0x8351, //CJK UNIFIED IDEOGRAPH + 0xDCE9: 0x835B, //CJK UNIFIED IDEOGRAPH + 0xDCEA: 0x835C, //CJK UNIFIED IDEOGRAPH + 0xDCEB: 0x8308, //CJK UNIFIED IDEOGRAPH + 0xDCEC: 0x8392, //CJK UNIFIED IDEOGRAPH + 0xDCED: 0x833C, //CJK UNIFIED IDEOGRAPH + 0xDCEE: 0x8334, //CJK UNIFIED IDEOGRAPH + 0xDCEF: 0x8331, //CJK UNIFIED IDEOGRAPH + 0xDCF0: 0x839B, //CJK UNIFIED IDEOGRAPH + 0xDCF1: 0x835E, //CJK UNIFIED IDEOGRAPH + 0xDCF2: 0x832F, //CJK UNIFIED IDEOGRAPH + 0xDCF3: 0x834F, //CJK UNIFIED IDEOGRAPH + 0xDCF4: 0x8347, //CJK UNIFIED IDEOGRAPH + 0xDCF5: 0x8343, //CJK UNIFIED IDEOGRAPH + 0xDCF6: 0x835F, //CJK UNIFIED IDEOGRAPH + 0xDCF7: 0x8340, //CJK UNIFIED IDEOGRAPH + 0xDCF8: 0x8317, //CJK UNIFIED IDEOGRAPH + 0xDCF9: 0x8360, //CJK UNIFIED IDEOGRAPH + 0xDCFA: 0x832D, //CJK UNIFIED IDEOGRAPH + 0xDCFB: 0x833A, //CJK UNIFIED IDEOGRAPH + 0xDCFC: 0x8333, //CJK UNIFIED IDEOGRAPH + 0xDCFD: 0x8366, //CJK UNIFIED IDEOGRAPH + 0xDCFE: 0x8365, //CJK UNIFIED IDEOGRAPH + 0xDD40: 0x8EE5, //CJK UNIFIED IDEOGRAPH + 0xDD41: 0x8EE6, //CJK UNIFIED IDEOGRAPH + 0xDD42: 0x8EE7, //CJK UNIFIED IDEOGRAPH + 0xDD43: 0x8EE8, //CJK UNIFIED IDEOGRAPH + 0xDD44: 0x8EE9, //CJK UNIFIED IDEOGRAPH + 0xDD45: 0x8EEA, //CJK UNIFIED IDEOGRAPH + 0xDD46: 0x8EEB, //CJK UNIFIED IDEOGRAPH + 0xDD47: 0x8EEC, //CJK UNIFIED IDEOGRAPH + 0xDD48: 0x8EED, //CJK UNIFIED IDEOGRAPH + 0xDD49: 0x8EEE, //CJK UNIFIED IDEOGRAPH + 0xDD4A: 0x8EEF, //CJK UNIFIED IDEOGRAPH + 0xDD4B: 0x8EF0, //CJK UNIFIED IDEOGRAPH + 0xDD4C: 0x8EF1, //CJK UNIFIED IDEOGRAPH + 0xDD4D: 0x8EF2, //CJK UNIFIED IDEOGRAPH + 0xDD4E: 0x8EF3, //CJK UNIFIED IDEOGRAPH + 0xDD4F: 0x8EF4, //CJK UNIFIED IDEOGRAPH + 0xDD50: 0x8EF5, //CJK UNIFIED IDEOGRAPH + 0xDD51: 0x8EF6, //CJK UNIFIED IDEOGRAPH + 0xDD52: 0x8EF7, //CJK UNIFIED IDEOGRAPH + 0xDD53: 0x8EF8, //CJK UNIFIED IDEOGRAPH + 0xDD54: 0x8EF9, //CJK UNIFIED IDEOGRAPH + 0xDD55: 0x8EFA, //CJK UNIFIED IDEOGRAPH + 0xDD56: 0x8EFB, //CJK UNIFIED IDEOGRAPH + 0xDD57: 0x8EFC, //CJK UNIFIED IDEOGRAPH + 0xDD58: 0x8EFD, //CJK UNIFIED IDEOGRAPH + 0xDD59: 0x8EFE, //CJK UNIFIED IDEOGRAPH + 0xDD5A: 0x8EFF, //CJK UNIFIED IDEOGRAPH + 0xDD5B: 0x8F00, //CJK UNIFIED IDEOGRAPH + 0xDD5C: 0x8F01, //CJK UNIFIED IDEOGRAPH + 0xDD5D: 0x8F02, //CJK UNIFIED IDEOGRAPH + 0xDD5E: 0x8F03, //CJK UNIFIED IDEOGRAPH + 0xDD5F: 0x8F04, //CJK UNIFIED IDEOGRAPH + 0xDD60: 0x8F05, //CJK UNIFIED IDEOGRAPH + 0xDD61: 0x8F06, //CJK UNIFIED IDEOGRAPH + 0xDD62: 0x8F07, //CJK UNIFIED IDEOGRAPH + 0xDD63: 0x8F08, //CJK UNIFIED IDEOGRAPH + 0xDD64: 0x8F09, //CJK UNIFIED IDEOGRAPH + 0xDD65: 0x8F0A, //CJK UNIFIED IDEOGRAPH + 0xDD66: 0x8F0B, //CJK UNIFIED IDEOGRAPH + 0xDD67: 0x8F0C, //CJK UNIFIED IDEOGRAPH + 0xDD68: 0x8F0D, //CJK UNIFIED IDEOGRAPH + 0xDD69: 0x8F0E, //CJK UNIFIED IDEOGRAPH + 0xDD6A: 0x8F0F, //CJK UNIFIED IDEOGRAPH + 0xDD6B: 0x8F10, //CJK UNIFIED IDEOGRAPH + 0xDD6C: 0x8F11, //CJK UNIFIED IDEOGRAPH + 0xDD6D: 0x8F12, //CJK UNIFIED IDEOGRAPH + 0xDD6E: 0x8F13, //CJK UNIFIED IDEOGRAPH + 0xDD6F: 0x8F14, //CJK UNIFIED IDEOGRAPH + 0xDD70: 0x8F15, //CJK UNIFIED IDEOGRAPH + 0xDD71: 0x8F16, //CJK UNIFIED IDEOGRAPH + 0xDD72: 0x8F17, //CJK UNIFIED IDEOGRAPH + 0xDD73: 0x8F18, //CJK UNIFIED IDEOGRAPH + 0xDD74: 0x8F19, //CJK UNIFIED IDEOGRAPH + 0xDD75: 0x8F1A, //CJK UNIFIED IDEOGRAPH + 0xDD76: 0x8F1B, //CJK UNIFIED IDEOGRAPH + 0xDD77: 0x8F1C, //CJK UNIFIED IDEOGRAPH + 0xDD78: 0x8F1D, //CJK UNIFIED IDEOGRAPH + 0xDD79: 0x8F1E, //CJK UNIFIED IDEOGRAPH + 0xDD7A: 0x8F1F, //CJK UNIFIED IDEOGRAPH + 0xDD7B: 0x8F20, //CJK UNIFIED IDEOGRAPH + 0xDD7C: 0x8F21, //CJK UNIFIED IDEOGRAPH + 0xDD7D: 0x8F22, //CJK UNIFIED IDEOGRAPH + 0xDD7E: 0x8F23, //CJK UNIFIED IDEOGRAPH + 0xDD80: 0x8F24, //CJK UNIFIED IDEOGRAPH + 0xDD81: 0x8F25, //CJK UNIFIED IDEOGRAPH + 0xDD82: 0x8F26, //CJK UNIFIED IDEOGRAPH + 0xDD83: 0x8F27, //CJK UNIFIED IDEOGRAPH + 0xDD84: 0x8F28, //CJK UNIFIED IDEOGRAPH + 0xDD85: 0x8F29, //CJK UNIFIED IDEOGRAPH + 0xDD86: 0x8F2A, //CJK UNIFIED IDEOGRAPH + 0xDD87: 0x8F2B, //CJK UNIFIED IDEOGRAPH + 0xDD88: 0x8F2C, //CJK UNIFIED IDEOGRAPH + 0xDD89: 0x8F2D, //CJK UNIFIED IDEOGRAPH + 0xDD8A: 0x8F2E, //CJK UNIFIED IDEOGRAPH + 0xDD8B: 0x8F2F, //CJK UNIFIED IDEOGRAPH + 0xDD8C: 0x8F30, //CJK UNIFIED IDEOGRAPH + 0xDD8D: 0x8F31, //CJK UNIFIED IDEOGRAPH + 0xDD8E: 0x8F32, //CJK UNIFIED IDEOGRAPH + 0xDD8F: 0x8F33, //CJK UNIFIED IDEOGRAPH + 0xDD90: 0x8F34, //CJK UNIFIED IDEOGRAPH + 0xDD91: 0x8F35, //CJK UNIFIED IDEOGRAPH + 0xDD92: 0x8F36, //CJK UNIFIED IDEOGRAPH + 0xDD93: 0x8F37, //CJK UNIFIED IDEOGRAPH + 0xDD94: 0x8F38, //CJK UNIFIED IDEOGRAPH + 0xDD95: 0x8F39, //CJK UNIFIED IDEOGRAPH + 0xDD96: 0x8F3A, //CJK UNIFIED IDEOGRAPH + 0xDD97: 0x8F3B, //CJK UNIFIED IDEOGRAPH + 0xDD98: 0x8F3C, //CJK UNIFIED IDEOGRAPH + 0xDD99: 0x8F3D, //CJK UNIFIED IDEOGRAPH + 0xDD9A: 0x8F3E, //CJK UNIFIED IDEOGRAPH + 0xDD9B: 0x8F3F, //CJK UNIFIED IDEOGRAPH + 0xDD9C: 0x8F40, //CJK UNIFIED IDEOGRAPH + 0xDD9D: 0x8F41, //CJK UNIFIED IDEOGRAPH + 0xDD9E: 0x8F42, //CJK UNIFIED IDEOGRAPH + 0xDD9F: 0x8F43, //CJK UNIFIED IDEOGRAPH + 0xDDA0: 0x8F44, //CJK UNIFIED IDEOGRAPH + 0xDDA1: 0x8368, //CJK UNIFIED IDEOGRAPH + 0xDDA2: 0x831B, //CJK UNIFIED IDEOGRAPH + 0xDDA3: 0x8369, //CJK UNIFIED IDEOGRAPH + 0xDDA4: 0x836C, //CJK UNIFIED IDEOGRAPH + 0xDDA5: 0x836A, //CJK UNIFIED IDEOGRAPH + 0xDDA6: 0x836D, //CJK UNIFIED IDEOGRAPH + 0xDDA7: 0x836E, //CJK UNIFIED IDEOGRAPH + 0xDDA8: 0x83B0, //CJK UNIFIED IDEOGRAPH + 0xDDA9: 0x8378, //CJK UNIFIED IDEOGRAPH + 0xDDAA: 0x83B3, //CJK UNIFIED IDEOGRAPH + 0xDDAB: 0x83B4, //CJK UNIFIED IDEOGRAPH + 0xDDAC: 0x83A0, //CJK UNIFIED IDEOGRAPH + 0xDDAD: 0x83AA, //CJK UNIFIED IDEOGRAPH + 0xDDAE: 0x8393, //CJK UNIFIED IDEOGRAPH + 0xDDAF: 0x839C, //CJK UNIFIED IDEOGRAPH + 0xDDB0: 0x8385, //CJK UNIFIED IDEOGRAPH + 0xDDB1: 0x837C, //CJK UNIFIED IDEOGRAPH + 0xDDB2: 0x83B6, //CJK UNIFIED IDEOGRAPH + 0xDDB3: 0x83A9, //CJK UNIFIED IDEOGRAPH + 0xDDB4: 0x837D, //CJK UNIFIED IDEOGRAPH + 0xDDB5: 0x83B8, //CJK UNIFIED IDEOGRAPH + 0xDDB6: 0x837B, //CJK UNIFIED IDEOGRAPH + 0xDDB7: 0x8398, //CJK UNIFIED IDEOGRAPH + 0xDDB8: 0x839E, //CJK UNIFIED IDEOGRAPH + 0xDDB9: 0x83A8, //CJK UNIFIED IDEOGRAPH + 0xDDBA: 0x83BA, //CJK UNIFIED IDEOGRAPH + 0xDDBB: 0x83BC, //CJK UNIFIED IDEOGRAPH + 0xDDBC: 0x83C1, //CJK UNIFIED IDEOGRAPH + 0xDDBD: 0x8401, //CJK UNIFIED IDEOGRAPH + 0xDDBE: 0x83E5, //CJK UNIFIED IDEOGRAPH + 0xDDBF: 0x83D8, //CJK UNIFIED IDEOGRAPH + 0xDDC0: 0x5807, //CJK UNIFIED IDEOGRAPH + 0xDDC1: 0x8418, //CJK UNIFIED IDEOGRAPH + 0xDDC2: 0x840B, //CJK UNIFIED IDEOGRAPH + 0xDDC3: 0x83DD, //CJK UNIFIED IDEOGRAPH + 0xDDC4: 0x83FD, //CJK UNIFIED IDEOGRAPH + 0xDDC5: 0x83D6, //CJK UNIFIED IDEOGRAPH + 0xDDC6: 0x841C, //CJK UNIFIED IDEOGRAPH + 0xDDC7: 0x8438, //CJK UNIFIED IDEOGRAPH + 0xDDC8: 0x8411, //CJK UNIFIED IDEOGRAPH + 0xDDC9: 0x8406, //CJK UNIFIED IDEOGRAPH + 0xDDCA: 0x83D4, //CJK UNIFIED IDEOGRAPH + 0xDDCB: 0x83DF, //CJK UNIFIED IDEOGRAPH + 0xDDCC: 0x840F, //CJK UNIFIED IDEOGRAPH + 0xDDCD: 0x8403, //CJK UNIFIED IDEOGRAPH + 0xDDCE: 0x83F8, //CJK UNIFIED IDEOGRAPH + 0xDDCF: 0x83F9, //CJK UNIFIED IDEOGRAPH + 0xDDD0: 0x83EA, //CJK UNIFIED IDEOGRAPH + 0xDDD1: 0x83C5, //CJK UNIFIED IDEOGRAPH + 0xDDD2: 0x83C0, //CJK UNIFIED IDEOGRAPH + 0xDDD3: 0x8426, //CJK UNIFIED IDEOGRAPH + 0xDDD4: 0x83F0, //CJK UNIFIED IDEOGRAPH + 0xDDD5: 0x83E1, //CJK UNIFIED IDEOGRAPH + 0xDDD6: 0x845C, //CJK UNIFIED IDEOGRAPH + 0xDDD7: 0x8451, //CJK UNIFIED IDEOGRAPH + 0xDDD8: 0x845A, //CJK UNIFIED IDEOGRAPH + 0xDDD9: 0x8459, //CJK UNIFIED IDEOGRAPH + 0xDDDA: 0x8473, //CJK UNIFIED IDEOGRAPH + 0xDDDB: 0x8487, //CJK UNIFIED IDEOGRAPH + 0xDDDC: 0x8488, //CJK UNIFIED IDEOGRAPH + 0xDDDD: 0x847A, //CJK UNIFIED IDEOGRAPH + 0xDDDE: 0x8489, //CJK UNIFIED IDEOGRAPH + 0xDDDF: 0x8478, //CJK UNIFIED IDEOGRAPH + 0xDDE0: 0x843C, //CJK UNIFIED IDEOGRAPH + 0xDDE1: 0x8446, //CJK UNIFIED IDEOGRAPH + 0xDDE2: 0x8469, //CJK UNIFIED IDEOGRAPH + 0xDDE3: 0x8476, //CJK UNIFIED IDEOGRAPH + 0xDDE4: 0x848C, //CJK UNIFIED IDEOGRAPH + 0xDDE5: 0x848E, //CJK UNIFIED IDEOGRAPH + 0xDDE6: 0x8431, //CJK UNIFIED IDEOGRAPH + 0xDDE7: 0x846D, //CJK UNIFIED IDEOGRAPH + 0xDDE8: 0x84C1, //CJK UNIFIED IDEOGRAPH + 0xDDE9: 0x84CD, //CJK UNIFIED IDEOGRAPH + 0xDDEA: 0x84D0, //CJK UNIFIED IDEOGRAPH + 0xDDEB: 0x84E6, //CJK UNIFIED IDEOGRAPH + 0xDDEC: 0x84BD, //CJK UNIFIED IDEOGRAPH + 0xDDED: 0x84D3, //CJK UNIFIED IDEOGRAPH + 0xDDEE: 0x84CA, //CJK UNIFIED IDEOGRAPH + 0xDDEF: 0x84BF, //CJK UNIFIED IDEOGRAPH + 0xDDF0: 0x84BA, //CJK UNIFIED IDEOGRAPH + 0xDDF1: 0x84E0, //CJK UNIFIED IDEOGRAPH + 0xDDF2: 0x84A1, //CJK UNIFIED IDEOGRAPH + 0xDDF3: 0x84B9, //CJK UNIFIED IDEOGRAPH + 0xDDF4: 0x84B4, //CJK UNIFIED IDEOGRAPH + 0xDDF5: 0x8497, //CJK UNIFIED IDEOGRAPH + 0xDDF6: 0x84E5, //CJK UNIFIED IDEOGRAPH + 0xDDF7: 0x84E3, //CJK UNIFIED IDEOGRAPH + 0xDDF8: 0x850C, //CJK UNIFIED IDEOGRAPH + 0xDDF9: 0x750D, //CJK UNIFIED IDEOGRAPH + 0xDDFA: 0x8538, //CJK UNIFIED IDEOGRAPH + 0xDDFB: 0x84F0, //CJK UNIFIED IDEOGRAPH + 0xDDFC: 0x8539, //CJK UNIFIED IDEOGRAPH + 0xDDFD: 0x851F, //CJK UNIFIED IDEOGRAPH + 0xDDFE: 0x853A, //CJK UNIFIED IDEOGRAPH + 0xDE40: 0x8F45, //CJK UNIFIED IDEOGRAPH + 0xDE41: 0x8F46, //CJK UNIFIED IDEOGRAPH + 0xDE42: 0x8F47, //CJK UNIFIED IDEOGRAPH + 0xDE43: 0x8F48, //CJK UNIFIED IDEOGRAPH + 0xDE44: 0x8F49, //CJK UNIFIED IDEOGRAPH + 0xDE45: 0x8F4A, //CJK UNIFIED IDEOGRAPH + 0xDE46: 0x8F4B, //CJK UNIFIED IDEOGRAPH + 0xDE47: 0x8F4C, //CJK UNIFIED IDEOGRAPH + 0xDE48: 0x8F4D, //CJK UNIFIED IDEOGRAPH + 0xDE49: 0x8F4E, //CJK UNIFIED IDEOGRAPH + 0xDE4A: 0x8F4F, //CJK UNIFIED IDEOGRAPH + 0xDE4B: 0x8F50, //CJK UNIFIED IDEOGRAPH + 0xDE4C: 0x8F51, //CJK UNIFIED IDEOGRAPH + 0xDE4D: 0x8F52, //CJK UNIFIED IDEOGRAPH + 0xDE4E: 0x8F53, //CJK UNIFIED IDEOGRAPH + 0xDE4F: 0x8F54, //CJK UNIFIED IDEOGRAPH + 0xDE50: 0x8F55, //CJK UNIFIED IDEOGRAPH + 0xDE51: 0x8F56, //CJK UNIFIED IDEOGRAPH + 0xDE52: 0x8F57, //CJK UNIFIED IDEOGRAPH + 0xDE53: 0x8F58, //CJK UNIFIED IDEOGRAPH + 0xDE54: 0x8F59, //CJK UNIFIED IDEOGRAPH + 0xDE55: 0x8F5A, //CJK UNIFIED IDEOGRAPH + 0xDE56: 0x8F5B, //CJK UNIFIED IDEOGRAPH + 0xDE57: 0x8F5C, //CJK UNIFIED IDEOGRAPH + 0xDE58: 0x8F5D, //CJK UNIFIED IDEOGRAPH + 0xDE59: 0x8F5E, //CJK UNIFIED IDEOGRAPH + 0xDE5A: 0x8F5F, //CJK UNIFIED IDEOGRAPH + 0xDE5B: 0x8F60, //CJK UNIFIED IDEOGRAPH + 0xDE5C: 0x8F61, //CJK UNIFIED IDEOGRAPH + 0xDE5D: 0x8F62, //CJK UNIFIED IDEOGRAPH + 0xDE5E: 0x8F63, //CJK UNIFIED IDEOGRAPH + 0xDE5F: 0x8F64, //CJK UNIFIED IDEOGRAPH + 0xDE60: 0x8F65, //CJK UNIFIED IDEOGRAPH + 0xDE61: 0x8F6A, //CJK UNIFIED IDEOGRAPH + 0xDE62: 0x8F80, //CJK UNIFIED IDEOGRAPH + 0xDE63: 0x8F8C, //CJK UNIFIED IDEOGRAPH + 0xDE64: 0x8F92, //CJK UNIFIED IDEOGRAPH + 0xDE65: 0x8F9D, //CJK UNIFIED IDEOGRAPH + 0xDE66: 0x8FA0, //CJK UNIFIED IDEOGRAPH + 0xDE67: 0x8FA1, //CJK UNIFIED IDEOGRAPH + 0xDE68: 0x8FA2, //CJK UNIFIED IDEOGRAPH + 0xDE69: 0x8FA4, //CJK UNIFIED IDEOGRAPH + 0xDE6A: 0x8FA5, //CJK UNIFIED IDEOGRAPH + 0xDE6B: 0x8FA6, //CJK UNIFIED IDEOGRAPH + 0xDE6C: 0x8FA7, //CJK UNIFIED IDEOGRAPH + 0xDE6D: 0x8FAA, //CJK UNIFIED IDEOGRAPH + 0xDE6E: 0x8FAC, //CJK UNIFIED IDEOGRAPH + 0xDE6F: 0x8FAD, //CJK UNIFIED IDEOGRAPH + 0xDE70: 0x8FAE, //CJK UNIFIED IDEOGRAPH + 0xDE71: 0x8FAF, //CJK UNIFIED IDEOGRAPH + 0xDE72: 0x8FB2, //CJK UNIFIED IDEOGRAPH + 0xDE73: 0x8FB3, //CJK UNIFIED IDEOGRAPH + 0xDE74: 0x8FB4, //CJK UNIFIED IDEOGRAPH + 0xDE75: 0x8FB5, //CJK UNIFIED IDEOGRAPH + 0xDE76: 0x8FB7, //CJK UNIFIED IDEOGRAPH + 0xDE77: 0x8FB8, //CJK UNIFIED IDEOGRAPH + 0xDE78: 0x8FBA, //CJK UNIFIED IDEOGRAPH + 0xDE79: 0x8FBB, //CJK UNIFIED IDEOGRAPH + 0xDE7A: 0x8FBC, //CJK UNIFIED IDEOGRAPH + 0xDE7B: 0x8FBF, //CJK UNIFIED IDEOGRAPH + 0xDE7C: 0x8FC0, //CJK UNIFIED IDEOGRAPH + 0xDE7D: 0x8FC3, //CJK UNIFIED IDEOGRAPH + 0xDE7E: 0x8FC6, //CJK UNIFIED IDEOGRAPH + 0xDE80: 0x8FC9, //CJK UNIFIED IDEOGRAPH + 0xDE81: 0x8FCA, //CJK UNIFIED IDEOGRAPH + 0xDE82: 0x8FCB, //CJK UNIFIED IDEOGRAPH + 0xDE83: 0x8FCC, //CJK UNIFIED IDEOGRAPH + 0xDE84: 0x8FCD, //CJK UNIFIED IDEOGRAPH + 0xDE85: 0x8FCF, //CJK UNIFIED IDEOGRAPH + 0xDE86: 0x8FD2, //CJK UNIFIED IDEOGRAPH + 0xDE87: 0x8FD6, //CJK UNIFIED IDEOGRAPH + 0xDE88: 0x8FD7, //CJK UNIFIED IDEOGRAPH + 0xDE89: 0x8FDA, //CJK UNIFIED IDEOGRAPH + 0xDE8A: 0x8FE0, //CJK UNIFIED IDEOGRAPH + 0xDE8B: 0x8FE1, //CJK UNIFIED IDEOGRAPH + 0xDE8C: 0x8FE3, //CJK UNIFIED IDEOGRAPH + 0xDE8D: 0x8FE7, //CJK UNIFIED IDEOGRAPH + 0xDE8E: 0x8FEC, //CJK UNIFIED IDEOGRAPH + 0xDE8F: 0x8FEF, //CJK UNIFIED IDEOGRAPH + 0xDE90: 0x8FF1, //CJK UNIFIED IDEOGRAPH + 0xDE91: 0x8FF2, //CJK UNIFIED IDEOGRAPH + 0xDE92: 0x8FF4, //CJK UNIFIED IDEOGRAPH + 0xDE93: 0x8FF5, //CJK UNIFIED IDEOGRAPH + 0xDE94: 0x8FF6, //CJK UNIFIED IDEOGRAPH + 0xDE95: 0x8FFA, //CJK UNIFIED IDEOGRAPH + 0xDE96: 0x8FFB, //CJK UNIFIED IDEOGRAPH + 0xDE97: 0x8FFC, //CJK UNIFIED IDEOGRAPH + 0xDE98: 0x8FFE, //CJK UNIFIED IDEOGRAPH + 0xDE99: 0x8FFF, //CJK UNIFIED IDEOGRAPH + 0xDE9A: 0x9007, //CJK UNIFIED IDEOGRAPH + 0xDE9B: 0x9008, //CJK UNIFIED IDEOGRAPH + 0xDE9C: 0x900C, //CJK UNIFIED IDEOGRAPH + 0xDE9D: 0x900E, //CJK UNIFIED IDEOGRAPH + 0xDE9E: 0x9013, //CJK UNIFIED IDEOGRAPH + 0xDE9F: 0x9015, //CJK UNIFIED IDEOGRAPH + 0xDEA0: 0x9018, //CJK UNIFIED IDEOGRAPH + 0xDEA1: 0x8556, //CJK UNIFIED IDEOGRAPH + 0xDEA2: 0x853B, //CJK UNIFIED IDEOGRAPH + 0xDEA3: 0x84FF, //CJK UNIFIED IDEOGRAPH + 0xDEA4: 0x84FC, //CJK UNIFIED IDEOGRAPH + 0xDEA5: 0x8559, //CJK UNIFIED IDEOGRAPH + 0xDEA6: 0x8548, //CJK UNIFIED IDEOGRAPH + 0xDEA7: 0x8568, //CJK UNIFIED IDEOGRAPH + 0xDEA8: 0x8564, //CJK UNIFIED IDEOGRAPH + 0xDEA9: 0x855E, //CJK UNIFIED IDEOGRAPH + 0xDEAA: 0x857A, //CJK UNIFIED IDEOGRAPH + 0xDEAB: 0x77A2, //CJK UNIFIED IDEOGRAPH + 0xDEAC: 0x8543, //CJK UNIFIED IDEOGRAPH + 0xDEAD: 0x8572, //CJK UNIFIED IDEOGRAPH + 0xDEAE: 0x857B, //CJK UNIFIED IDEOGRAPH + 0xDEAF: 0x85A4, //CJK UNIFIED IDEOGRAPH + 0xDEB0: 0x85A8, //CJK UNIFIED IDEOGRAPH + 0xDEB1: 0x8587, //CJK UNIFIED IDEOGRAPH + 0xDEB2: 0x858F, //CJK UNIFIED IDEOGRAPH + 0xDEB3: 0x8579, //CJK UNIFIED IDEOGRAPH + 0xDEB4: 0x85AE, //CJK UNIFIED IDEOGRAPH + 0xDEB5: 0x859C, //CJK UNIFIED IDEOGRAPH + 0xDEB6: 0x8585, //CJK UNIFIED IDEOGRAPH + 0xDEB7: 0x85B9, //CJK UNIFIED IDEOGRAPH + 0xDEB8: 0x85B7, //CJK UNIFIED IDEOGRAPH + 0xDEB9: 0x85B0, //CJK UNIFIED IDEOGRAPH + 0xDEBA: 0x85D3, //CJK UNIFIED IDEOGRAPH + 0xDEBB: 0x85C1, //CJK UNIFIED IDEOGRAPH + 0xDEBC: 0x85DC, //CJK UNIFIED IDEOGRAPH + 0xDEBD: 0x85FF, //CJK UNIFIED IDEOGRAPH + 0xDEBE: 0x8627, //CJK UNIFIED IDEOGRAPH + 0xDEBF: 0x8605, //CJK UNIFIED IDEOGRAPH + 0xDEC0: 0x8629, //CJK UNIFIED IDEOGRAPH + 0xDEC1: 0x8616, //CJK UNIFIED IDEOGRAPH + 0xDEC2: 0x863C, //CJK UNIFIED IDEOGRAPH + 0xDEC3: 0x5EFE, //CJK UNIFIED IDEOGRAPH + 0xDEC4: 0x5F08, //CJK UNIFIED IDEOGRAPH + 0xDEC5: 0x593C, //CJK UNIFIED IDEOGRAPH + 0xDEC6: 0x5941, //CJK UNIFIED IDEOGRAPH + 0xDEC7: 0x8037, //CJK UNIFIED IDEOGRAPH + 0xDEC8: 0x5955, //CJK UNIFIED IDEOGRAPH + 0xDEC9: 0x595A, //CJK UNIFIED IDEOGRAPH + 0xDECA: 0x5958, //CJK UNIFIED IDEOGRAPH + 0xDECB: 0x530F, //CJK UNIFIED IDEOGRAPH + 0xDECC: 0x5C22, //CJK UNIFIED IDEOGRAPH + 0xDECD: 0x5C25, //CJK UNIFIED IDEOGRAPH + 0xDECE: 0x5C2C, //CJK UNIFIED IDEOGRAPH + 0xDECF: 0x5C34, //CJK UNIFIED IDEOGRAPH + 0xDED0: 0x624C, //CJK UNIFIED IDEOGRAPH + 0xDED1: 0x626A, //CJK UNIFIED IDEOGRAPH + 0xDED2: 0x629F, //CJK UNIFIED IDEOGRAPH + 0xDED3: 0x62BB, //CJK UNIFIED IDEOGRAPH + 0xDED4: 0x62CA, //CJK UNIFIED IDEOGRAPH + 0xDED5: 0x62DA, //CJK UNIFIED IDEOGRAPH + 0xDED6: 0x62D7, //CJK UNIFIED IDEOGRAPH + 0xDED7: 0x62EE, //CJK UNIFIED IDEOGRAPH + 0xDED8: 0x6322, //CJK UNIFIED IDEOGRAPH + 0xDED9: 0x62F6, //CJK UNIFIED IDEOGRAPH + 0xDEDA: 0x6339, //CJK UNIFIED IDEOGRAPH + 0xDEDB: 0x634B, //CJK UNIFIED IDEOGRAPH + 0xDEDC: 0x6343, //CJK UNIFIED IDEOGRAPH + 0xDEDD: 0x63AD, //CJK UNIFIED IDEOGRAPH + 0xDEDE: 0x63F6, //CJK UNIFIED IDEOGRAPH + 0xDEDF: 0x6371, //CJK UNIFIED IDEOGRAPH + 0xDEE0: 0x637A, //CJK UNIFIED IDEOGRAPH + 0xDEE1: 0x638E, //CJK UNIFIED IDEOGRAPH + 0xDEE2: 0x63B4, //CJK UNIFIED IDEOGRAPH + 0xDEE3: 0x636D, //CJK UNIFIED IDEOGRAPH + 0xDEE4: 0x63AC, //CJK UNIFIED IDEOGRAPH + 0xDEE5: 0x638A, //CJK UNIFIED IDEOGRAPH + 0xDEE6: 0x6369, //CJK UNIFIED IDEOGRAPH + 0xDEE7: 0x63AE, //CJK UNIFIED IDEOGRAPH + 0xDEE8: 0x63BC, //CJK UNIFIED IDEOGRAPH + 0xDEE9: 0x63F2, //CJK UNIFIED IDEOGRAPH + 0xDEEA: 0x63F8, //CJK UNIFIED IDEOGRAPH + 0xDEEB: 0x63E0, //CJK UNIFIED IDEOGRAPH + 0xDEEC: 0x63FF, //CJK UNIFIED IDEOGRAPH + 0xDEED: 0x63C4, //CJK UNIFIED IDEOGRAPH + 0xDEEE: 0x63DE, //CJK UNIFIED IDEOGRAPH + 0xDEEF: 0x63CE, //CJK UNIFIED IDEOGRAPH + 0xDEF0: 0x6452, //CJK UNIFIED IDEOGRAPH + 0xDEF1: 0x63C6, //CJK UNIFIED IDEOGRAPH + 0xDEF2: 0x63BE, //CJK UNIFIED IDEOGRAPH + 0xDEF3: 0x6445, //CJK UNIFIED IDEOGRAPH + 0xDEF4: 0x6441, //CJK UNIFIED IDEOGRAPH + 0xDEF5: 0x640B, //CJK UNIFIED IDEOGRAPH + 0xDEF6: 0x641B, //CJK UNIFIED IDEOGRAPH + 0xDEF7: 0x6420, //CJK UNIFIED IDEOGRAPH + 0xDEF8: 0x640C, //CJK UNIFIED IDEOGRAPH + 0xDEF9: 0x6426, //CJK UNIFIED IDEOGRAPH + 0xDEFA: 0x6421, //CJK UNIFIED IDEOGRAPH + 0xDEFB: 0x645E, //CJK UNIFIED IDEOGRAPH + 0xDEFC: 0x6484, //CJK UNIFIED IDEOGRAPH + 0xDEFD: 0x646D, //CJK UNIFIED IDEOGRAPH + 0xDEFE: 0x6496, //CJK UNIFIED IDEOGRAPH + 0xDF40: 0x9019, //CJK UNIFIED IDEOGRAPH + 0xDF41: 0x901C, //CJK UNIFIED IDEOGRAPH + 0xDF42: 0x9023, //CJK UNIFIED IDEOGRAPH + 0xDF43: 0x9024, //CJK UNIFIED IDEOGRAPH + 0xDF44: 0x9025, //CJK UNIFIED IDEOGRAPH + 0xDF45: 0x9027, //CJK UNIFIED IDEOGRAPH + 0xDF46: 0x9028, //CJK UNIFIED IDEOGRAPH + 0xDF47: 0x9029, //CJK UNIFIED IDEOGRAPH + 0xDF48: 0x902A, //CJK UNIFIED IDEOGRAPH + 0xDF49: 0x902B, //CJK UNIFIED IDEOGRAPH + 0xDF4A: 0x902C, //CJK UNIFIED IDEOGRAPH + 0xDF4B: 0x9030, //CJK UNIFIED IDEOGRAPH + 0xDF4C: 0x9031, //CJK UNIFIED IDEOGRAPH + 0xDF4D: 0x9032, //CJK UNIFIED IDEOGRAPH + 0xDF4E: 0x9033, //CJK UNIFIED IDEOGRAPH + 0xDF4F: 0x9034, //CJK UNIFIED IDEOGRAPH + 0xDF50: 0x9037, //CJK UNIFIED IDEOGRAPH + 0xDF51: 0x9039, //CJK UNIFIED IDEOGRAPH + 0xDF52: 0x903A, //CJK UNIFIED IDEOGRAPH + 0xDF53: 0x903D, //CJK UNIFIED IDEOGRAPH + 0xDF54: 0x903F, //CJK UNIFIED IDEOGRAPH + 0xDF55: 0x9040, //CJK UNIFIED IDEOGRAPH + 0xDF56: 0x9043, //CJK UNIFIED IDEOGRAPH + 0xDF57: 0x9045, //CJK UNIFIED IDEOGRAPH + 0xDF58: 0x9046, //CJK UNIFIED IDEOGRAPH + 0xDF59: 0x9048, //CJK UNIFIED IDEOGRAPH + 0xDF5A: 0x9049, //CJK UNIFIED IDEOGRAPH + 0xDF5B: 0x904A, //CJK UNIFIED IDEOGRAPH + 0xDF5C: 0x904B, //CJK UNIFIED IDEOGRAPH + 0xDF5D: 0x904C, //CJK UNIFIED IDEOGRAPH + 0xDF5E: 0x904E, //CJK UNIFIED IDEOGRAPH + 0xDF5F: 0x9054, //CJK UNIFIED IDEOGRAPH + 0xDF60: 0x9055, //CJK UNIFIED IDEOGRAPH + 0xDF61: 0x9056, //CJK UNIFIED IDEOGRAPH + 0xDF62: 0x9059, //CJK UNIFIED IDEOGRAPH + 0xDF63: 0x905A, //CJK UNIFIED IDEOGRAPH + 0xDF64: 0x905C, //CJK UNIFIED IDEOGRAPH + 0xDF65: 0x905D, //CJK UNIFIED IDEOGRAPH + 0xDF66: 0x905E, //CJK UNIFIED IDEOGRAPH + 0xDF67: 0x905F, //CJK UNIFIED IDEOGRAPH + 0xDF68: 0x9060, //CJK UNIFIED IDEOGRAPH + 0xDF69: 0x9061, //CJK UNIFIED IDEOGRAPH + 0xDF6A: 0x9064, //CJK UNIFIED IDEOGRAPH + 0xDF6B: 0x9066, //CJK UNIFIED IDEOGRAPH + 0xDF6C: 0x9067, //CJK UNIFIED IDEOGRAPH + 0xDF6D: 0x9069, //CJK UNIFIED IDEOGRAPH + 0xDF6E: 0x906A, //CJK UNIFIED IDEOGRAPH + 0xDF6F: 0x906B, //CJK UNIFIED IDEOGRAPH + 0xDF70: 0x906C, //CJK UNIFIED IDEOGRAPH + 0xDF71: 0x906F, //CJK UNIFIED IDEOGRAPH + 0xDF72: 0x9070, //CJK UNIFIED IDEOGRAPH + 0xDF73: 0x9071, //CJK UNIFIED IDEOGRAPH + 0xDF74: 0x9072, //CJK UNIFIED IDEOGRAPH + 0xDF75: 0x9073, //CJK UNIFIED IDEOGRAPH + 0xDF76: 0x9076, //CJK UNIFIED IDEOGRAPH + 0xDF77: 0x9077, //CJK UNIFIED IDEOGRAPH + 0xDF78: 0x9078, //CJK UNIFIED IDEOGRAPH + 0xDF79: 0x9079, //CJK UNIFIED IDEOGRAPH + 0xDF7A: 0x907A, //CJK UNIFIED IDEOGRAPH + 0xDF7B: 0x907B, //CJK UNIFIED IDEOGRAPH + 0xDF7C: 0x907C, //CJK UNIFIED IDEOGRAPH + 0xDF7D: 0x907E, //CJK UNIFIED IDEOGRAPH + 0xDF7E: 0x9081, //CJK UNIFIED IDEOGRAPH + 0xDF80: 0x9084, //CJK UNIFIED IDEOGRAPH + 0xDF81: 0x9085, //CJK UNIFIED IDEOGRAPH + 0xDF82: 0x9086, //CJK UNIFIED IDEOGRAPH + 0xDF83: 0x9087, //CJK UNIFIED IDEOGRAPH + 0xDF84: 0x9089, //CJK UNIFIED IDEOGRAPH + 0xDF85: 0x908A, //CJK UNIFIED IDEOGRAPH + 0xDF86: 0x908C, //CJK UNIFIED IDEOGRAPH + 0xDF87: 0x908D, //CJK UNIFIED IDEOGRAPH + 0xDF88: 0x908E, //CJK UNIFIED IDEOGRAPH + 0xDF89: 0x908F, //CJK UNIFIED IDEOGRAPH + 0xDF8A: 0x9090, //CJK UNIFIED IDEOGRAPH + 0xDF8B: 0x9092, //CJK UNIFIED IDEOGRAPH + 0xDF8C: 0x9094, //CJK UNIFIED IDEOGRAPH + 0xDF8D: 0x9096, //CJK UNIFIED IDEOGRAPH + 0xDF8E: 0x9098, //CJK UNIFIED IDEOGRAPH + 0xDF8F: 0x909A, //CJK UNIFIED IDEOGRAPH + 0xDF90: 0x909C, //CJK UNIFIED IDEOGRAPH + 0xDF91: 0x909E, //CJK UNIFIED IDEOGRAPH + 0xDF92: 0x909F, //CJK UNIFIED IDEOGRAPH + 0xDF93: 0x90A0, //CJK UNIFIED IDEOGRAPH + 0xDF94: 0x90A4, //CJK UNIFIED IDEOGRAPH + 0xDF95: 0x90A5, //CJK UNIFIED IDEOGRAPH + 0xDF96: 0x90A7, //CJK UNIFIED IDEOGRAPH + 0xDF97: 0x90A8, //CJK UNIFIED IDEOGRAPH + 0xDF98: 0x90A9, //CJK UNIFIED IDEOGRAPH + 0xDF99: 0x90AB, //CJK UNIFIED IDEOGRAPH + 0xDF9A: 0x90AD, //CJK UNIFIED IDEOGRAPH + 0xDF9B: 0x90B2, //CJK UNIFIED IDEOGRAPH + 0xDF9C: 0x90B7, //CJK UNIFIED IDEOGRAPH + 0xDF9D: 0x90BC, //CJK UNIFIED IDEOGRAPH + 0xDF9E: 0x90BD, //CJK UNIFIED IDEOGRAPH + 0xDF9F: 0x90BF, //CJK UNIFIED IDEOGRAPH + 0xDFA0: 0x90C0, //CJK UNIFIED IDEOGRAPH + 0xDFA1: 0x647A, //CJK UNIFIED IDEOGRAPH + 0xDFA2: 0x64B7, //CJK UNIFIED IDEOGRAPH + 0xDFA3: 0x64B8, //CJK UNIFIED IDEOGRAPH + 0xDFA4: 0x6499, //CJK UNIFIED IDEOGRAPH + 0xDFA5: 0x64BA, //CJK UNIFIED IDEOGRAPH + 0xDFA6: 0x64C0, //CJK UNIFIED IDEOGRAPH + 0xDFA7: 0x64D0, //CJK UNIFIED IDEOGRAPH + 0xDFA8: 0x64D7, //CJK UNIFIED IDEOGRAPH + 0xDFA9: 0x64E4, //CJK UNIFIED IDEOGRAPH + 0xDFAA: 0x64E2, //CJK UNIFIED IDEOGRAPH + 0xDFAB: 0x6509, //CJK UNIFIED IDEOGRAPH + 0xDFAC: 0x6525, //CJK UNIFIED IDEOGRAPH + 0xDFAD: 0x652E, //CJK UNIFIED IDEOGRAPH + 0xDFAE: 0x5F0B, //CJK UNIFIED IDEOGRAPH + 0xDFAF: 0x5FD2, //CJK UNIFIED IDEOGRAPH + 0xDFB0: 0x7519, //CJK UNIFIED IDEOGRAPH + 0xDFB1: 0x5F11, //CJK UNIFIED IDEOGRAPH + 0xDFB2: 0x535F, //CJK UNIFIED IDEOGRAPH + 0xDFB3: 0x53F1, //CJK UNIFIED IDEOGRAPH + 0xDFB4: 0x53FD, //CJK UNIFIED IDEOGRAPH + 0xDFB5: 0x53E9, //CJK UNIFIED IDEOGRAPH + 0xDFB6: 0x53E8, //CJK UNIFIED IDEOGRAPH + 0xDFB7: 0x53FB, //CJK UNIFIED IDEOGRAPH + 0xDFB8: 0x5412, //CJK UNIFIED IDEOGRAPH + 0xDFB9: 0x5416, //CJK UNIFIED IDEOGRAPH + 0xDFBA: 0x5406, //CJK UNIFIED IDEOGRAPH + 0xDFBB: 0x544B, //CJK UNIFIED IDEOGRAPH + 0xDFBC: 0x5452, //CJK UNIFIED IDEOGRAPH + 0xDFBD: 0x5453, //CJK UNIFIED IDEOGRAPH + 0xDFBE: 0x5454, //CJK UNIFIED IDEOGRAPH + 0xDFBF: 0x5456, //CJK UNIFIED IDEOGRAPH + 0xDFC0: 0x5443, //CJK UNIFIED IDEOGRAPH + 0xDFC1: 0x5421, //CJK UNIFIED IDEOGRAPH + 0xDFC2: 0x5457, //CJK UNIFIED IDEOGRAPH + 0xDFC3: 0x5459, //CJK UNIFIED IDEOGRAPH + 0xDFC4: 0x5423, //CJK UNIFIED IDEOGRAPH + 0xDFC5: 0x5432, //CJK UNIFIED IDEOGRAPH + 0xDFC6: 0x5482, //CJK UNIFIED IDEOGRAPH + 0xDFC7: 0x5494, //CJK UNIFIED IDEOGRAPH + 0xDFC8: 0x5477, //CJK UNIFIED IDEOGRAPH + 0xDFC9: 0x5471, //CJK UNIFIED IDEOGRAPH + 0xDFCA: 0x5464, //CJK UNIFIED IDEOGRAPH + 0xDFCB: 0x549A, //CJK UNIFIED IDEOGRAPH + 0xDFCC: 0x549B, //CJK UNIFIED IDEOGRAPH + 0xDFCD: 0x5484, //CJK UNIFIED IDEOGRAPH + 0xDFCE: 0x5476, //CJK UNIFIED IDEOGRAPH + 0xDFCF: 0x5466, //CJK UNIFIED IDEOGRAPH + 0xDFD0: 0x549D, //CJK UNIFIED IDEOGRAPH + 0xDFD1: 0x54D0, //CJK UNIFIED IDEOGRAPH + 0xDFD2: 0x54AD, //CJK UNIFIED IDEOGRAPH + 0xDFD3: 0x54C2, //CJK UNIFIED IDEOGRAPH + 0xDFD4: 0x54B4, //CJK UNIFIED IDEOGRAPH + 0xDFD5: 0x54D2, //CJK UNIFIED IDEOGRAPH + 0xDFD6: 0x54A7, //CJK UNIFIED IDEOGRAPH + 0xDFD7: 0x54A6, //CJK UNIFIED IDEOGRAPH + 0xDFD8: 0x54D3, //CJK UNIFIED IDEOGRAPH + 0xDFD9: 0x54D4, //CJK UNIFIED IDEOGRAPH + 0xDFDA: 0x5472, //CJK UNIFIED IDEOGRAPH + 0xDFDB: 0x54A3, //CJK UNIFIED IDEOGRAPH + 0xDFDC: 0x54D5, //CJK UNIFIED IDEOGRAPH + 0xDFDD: 0x54BB, //CJK UNIFIED IDEOGRAPH + 0xDFDE: 0x54BF, //CJK UNIFIED IDEOGRAPH + 0xDFDF: 0x54CC, //CJK UNIFIED IDEOGRAPH + 0xDFE0: 0x54D9, //CJK UNIFIED IDEOGRAPH + 0xDFE1: 0x54DA, //CJK UNIFIED IDEOGRAPH + 0xDFE2: 0x54DC, //CJK UNIFIED IDEOGRAPH + 0xDFE3: 0x54A9, //CJK UNIFIED IDEOGRAPH + 0xDFE4: 0x54AA, //CJK UNIFIED IDEOGRAPH + 0xDFE5: 0x54A4, //CJK UNIFIED IDEOGRAPH + 0xDFE6: 0x54DD, //CJK UNIFIED IDEOGRAPH + 0xDFE7: 0x54CF, //CJK UNIFIED IDEOGRAPH + 0xDFE8: 0x54DE, //CJK UNIFIED IDEOGRAPH + 0xDFE9: 0x551B, //CJK UNIFIED IDEOGRAPH + 0xDFEA: 0x54E7, //CJK UNIFIED IDEOGRAPH + 0xDFEB: 0x5520, //CJK UNIFIED IDEOGRAPH + 0xDFEC: 0x54FD, //CJK UNIFIED IDEOGRAPH + 0xDFED: 0x5514, //CJK UNIFIED IDEOGRAPH + 0xDFEE: 0x54F3, //CJK UNIFIED IDEOGRAPH + 0xDFEF: 0x5522, //CJK UNIFIED IDEOGRAPH + 0xDFF0: 0x5523, //CJK UNIFIED IDEOGRAPH + 0xDFF1: 0x550F, //CJK UNIFIED IDEOGRAPH + 0xDFF2: 0x5511, //CJK UNIFIED IDEOGRAPH + 0xDFF3: 0x5527, //CJK UNIFIED IDEOGRAPH + 0xDFF4: 0x552A, //CJK UNIFIED IDEOGRAPH + 0xDFF5: 0x5567, //CJK UNIFIED IDEOGRAPH + 0xDFF6: 0x558F, //CJK UNIFIED IDEOGRAPH + 0xDFF7: 0x55B5, //CJK UNIFIED IDEOGRAPH + 0xDFF8: 0x5549, //CJK UNIFIED IDEOGRAPH + 0xDFF9: 0x556D, //CJK UNIFIED IDEOGRAPH + 0xDFFA: 0x5541, //CJK UNIFIED IDEOGRAPH + 0xDFFB: 0x5555, //CJK UNIFIED IDEOGRAPH + 0xDFFC: 0x553F, //CJK UNIFIED IDEOGRAPH + 0xDFFD: 0x5550, //CJK UNIFIED IDEOGRAPH + 0xDFFE: 0x553C, //CJK UNIFIED IDEOGRAPH + 0xE040: 0x90C2, //CJK UNIFIED IDEOGRAPH + 0xE041: 0x90C3, //CJK UNIFIED IDEOGRAPH + 0xE042: 0x90C6, //CJK UNIFIED IDEOGRAPH + 0xE043: 0x90C8, //CJK UNIFIED IDEOGRAPH + 0xE044: 0x90C9, //CJK UNIFIED IDEOGRAPH + 0xE045: 0x90CB, //CJK UNIFIED IDEOGRAPH + 0xE046: 0x90CC, //CJK UNIFIED IDEOGRAPH + 0xE047: 0x90CD, //CJK UNIFIED IDEOGRAPH + 0xE048: 0x90D2, //CJK UNIFIED IDEOGRAPH + 0xE049: 0x90D4, //CJK UNIFIED IDEOGRAPH + 0xE04A: 0x90D5, //CJK UNIFIED IDEOGRAPH + 0xE04B: 0x90D6, //CJK UNIFIED IDEOGRAPH + 0xE04C: 0x90D8, //CJK UNIFIED IDEOGRAPH + 0xE04D: 0x90D9, //CJK UNIFIED IDEOGRAPH + 0xE04E: 0x90DA, //CJK UNIFIED IDEOGRAPH + 0xE04F: 0x90DE, //CJK UNIFIED IDEOGRAPH + 0xE050: 0x90DF, //CJK UNIFIED IDEOGRAPH + 0xE051: 0x90E0, //CJK UNIFIED IDEOGRAPH + 0xE052: 0x90E3, //CJK UNIFIED IDEOGRAPH + 0xE053: 0x90E4, //CJK UNIFIED IDEOGRAPH + 0xE054: 0x90E5, //CJK UNIFIED IDEOGRAPH + 0xE055: 0x90E9, //CJK UNIFIED IDEOGRAPH + 0xE056: 0x90EA, //CJK UNIFIED IDEOGRAPH + 0xE057: 0x90EC, //CJK UNIFIED IDEOGRAPH + 0xE058: 0x90EE, //CJK UNIFIED IDEOGRAPH + 0xE059: 0x90F0, //CJK UNIFIED IDEOGRAPH + 0xE05A: 0x90F1, //CJK UNIFIED IDEOGRAPH + 0xE05B: 0x90F2, //CJK UNIFIED IDEOGRAPH + 0xE05C: 0x90F3, //CJK UNIFIED IDEOGRAPH + 0xE05D: 0x90F5, //CJK UNIFIED IDEOGRAPH + 0xE05E: 0x90F6, //CJK UNIFIED IDEOGRAPH + 0xE05F: 0x90F7, //CJK UNIFIED IDEOGRAPH + 0xE060: 0x90F9, //CJK UNIFIED IDEOGRAPH + 0xE061: 0x90FA, //CJK UNIFIED IDEOGRAPH + 0xE062: 0x90FB, //CJK UNIFIED IDEOGRAPH + 0xE063: 0x90FC, //CJK UNIFIED IDEOGRAPH + 0xE064: 0x90FF, //CJK UNIFIED IDEOGRAPH + 0xE065: 0x9100, //CJK UNIFIED IDEOGRAPH + 0xE066: 0x9101, //CJK UNIFIED IDEOGRAPH + 0xE067: 0x9103, //CJK UNIFIED IDEOGRAPH + 0xE068: 0x9105, //CJK UNIFIED IDEOGRAPH + 0xE069: 0x9106, //CJK UNIFIED IDEOGRAPH + 0xE06A: 0x9107, //CJK UNIFIED IDEOGRAPH + 0xE06B: 0x9108, //CJK UNIFIED IDEOGRAPH + 0xE06C: 0x9109, //CJK UNIFIED IDEOGRAPH + 0xE06D: 0x910A, //CJK UNIFIED IDEOGRAPH + 0xE06E: 0x910B, //CJK UNIFIED IDEOGRAPH + 0xE06F: 0x910C, //CJK UNIFIED IDEOGRAPH + 0xE070: 0x910D, //CJK UNIFIED IDEOGRAPH + 0xE071: 0x910E, //CJK UNIFIED IDEOGRAPH + 0xE072: 0x910F, //CJK UNIFIED IDEOGRAPH + 0xE073: 0x9110, //CJK UNIFIED IDEOGRAPH + 0xE074: 0x9111, //CJK UNIFIED IDEOGRAPH + 0xE075: 0x9112, //CJK UNIFIED IDEOGRAPH + 0xE076: 0x9113, //CJK UNIFIED IDEOGRAPH + 0xE077: 0x9114, //CJK UNIFIED IDEOGRAPH + 0xE078: 0x9115, //CJK UNIFIED IDEOGRAPH + 0xE079: 0x9116, //CJK UNIFIED IDEOGRAPH + 0xE07A: 0x9117, //CJK UNIFIED IDEOGRAPH + 0xE07B: 0x9118, //CJK UNIFIED IDEOGRAPH + 0xE07C: 0x911A, //CJK UNIFIED IDEOGRAPH + 0xE07D: 0x911B, //CJK UNIFIED IDEOGRAPH + 0xE07E: 0x911C, //CJK UNIFIED IDEOGRAPH + 0xE080: 0x911D, //CJK UNIFIED IDEOGRAPH + 0xE081: 0x911F, //CJK UNIFIED IDEOGRAPH + 0xE082: 0x9120, //CJK UNIFIED IDEOGRAPH + 0xE083: 0x9121, //CJK UNIFIED IDEOGRAPH + 0xE084: 0x9124, //CJK UNIFIED IDEOGRAPH + 0xE085: 0x9125, //CJK UNIFIED IDEOGRAPH + 0xE086: 0x9126, //CJK UNIFIED IDEOGRAPH + 0xE087: 0x9127, //CJK UNIFIED IDEOGRAPH + 0xE088: 0x9128, //CJK UNIFIED IDEOGRAPH + 0xE089: 0x9129, //CJK UNIFIED IDEOGRAPH + 0xE08A: 0x912A, //CJK UNIFIED IDEOGRAPH + 0xE08B: 0x912B, //CJK UNIFIED IDEOGRAPH + 0xE08C: 0x912C, //CJK UNIFIED IDEOGRAPH + 0xE08D: 0x912D, //CJK UNIFIED IDEOGRAPH + 0xE08E: 0x912E, //CJK UNIFIED IDEOGRAPH + 0xE08F: 0x9130, //CJK UNIFIED IDEOGRAPH + 0xE090: 0x9132, //CJK UNIFIED IDEOGRAPH + 0xE091: 0x9133, //CJK UNIFIED IDEOGRAPH + 0xE092: 0x9134, //CJK UNIFIED IDEOGRAPH + 0xE093: 0x9135, //CJK UNIFIED IDEOGRAPH + 0xE094: 0x9136, //CJK UNIFIED IDEOGRAPH + 0xE095: 0x9137, //CJK UNIFIED IDEOGRAPH + 0xE096: 0x9138, //CJK UNIFIED IDEOGRAPH + 0xE097: 0x913A, //CJK UNIFIED IDEOGRAPH + 0xE098: 0x913B, //CJK UNIFIED IDEOGRAPH + 0xE099: 0x913C, //CJK UNIFIED IDEOGRAPH + 0xE09A: 0x913D, //CJK UNIFIED IDEOGRAPH + 0xE09B: 0x913E, //CJK UNIFIED IDEOGRAPH + 0xE09C: 0x913F, //CJK UNIFIED IDEOGRAPH + 0xE09D: 0x9140, //CJK UNIFIED IDEOGRAPH + 0xE09E: 0x9141, //CJK UNIFIED IDEOGRAPH + 0xE09F: 0x9142, //CJK UNIFIED IDEOGRAPH + 0xE0A0: 0x9144, //CJK UNIFIED IDEOGRAPH + 0xE0A1: 0x5537, //CJK UNIFIED IDEOGRAPH + 0xE0A2: 0x5556, //CJK UNIFIED IDEOGRAPH + 0xE0A3: 0x5575, //CJK UNIFIED IDEOGRAPH + 0xE0A4: 0x5576, //CJK UNIFIED IDEOGRAPH + 0xE0A5: 0x5577, //CJK UNIFIED IDEOGRAPH + 0xE0A6: 0x5533, //CJK UNIFIED IDEOGRAPH + 0xE0A7: 0x5530, //CJK UNIFIED IDEOGRAPH + 0xE0A8: 0x555C, //CJK UNIFIED IDEOGRAPH + 0xE0A9: 0x558B, //CJK UNIFIED IDEOGRAPH + 0xE0AA: 0x55D2, //CJK UNIFIED IDEOGRAPH + 0xE0AB: 0x5583, //CJK UNIFIED IDEOGRAPH + 0xE0AC: 0x55B1, //CJK UNIFIED IDEOGRAPH + 0xE0AD: 0x55B9, //CJK UNIFIED IDEOGRAPH + 0xE0AE: 0x5588, //CJK UNIFIED IDEOGRAPH + 0xE0AF: 0x5581, //CJK UNIFIED IDEOGRAPH + 0xE0B0: 0x559F, //CJK UNIFIED IDEOGRAPH + 0xE0B1: 0x557E, //CJK UNIFIED IDEOGRAPH + 0xE0B2: 0x55D6, //CJK UNIFIED IDEOGRAPH + 0xE0B3: 0x5591, //CJK UNIFIED IDEOGRAPH + 0xE0B4: 0x557B, //CJK UNIFIED IDEOGRAPH + 0xE0B5: 0x55DF, //CJK UNIFIED IDEOGRAPH + 0xE0B6: 0x55BD, //CJK UNIFIED IDEOGRAPH + 0xE0B7: 0x55BE, //CJK UNIFIED IDEOGRAPH + 0xE0B8: 0x5594, //CJK UNIFIED IDEOGRAPH + 0xE0B9: 0x5599, //CJK UNIFIED IDEOGRAPH + 0xE0BA: 0x55EA, //CJK UNIFIED IDEOGRAPH + 0xE0BB: 0x55F7, //CJK UNIFIED IDEOGRAPH + 0xE0BC: 0x55C9, //CJK UNIFIED IDEOGRAPH + 0xE0BD: 0x561F, //CJK UNIFIED IDEOGRAPH + 0xE0BE: 0x55D1, //CJK UNIFIED IDEOGRAPH + 0xE0BF: 0x55EB, //CJK UNIFIED IDEOGRAPH + 0xE0C0: 0x55EC, //CJK UNIFIED IDEOGRAPH + 0xE0C1: 0x55D4, //CJK UNIFIED IDEOGRAPH + 0xE0C2: 0x55E6, //CJK UNIFIED IDEOGRAPH + 0xE0C3: 0x55DD, //CJK UNIFIED IDEOGRAPH + 0xE0C4: 0x55C4, //CJK UNIFIED IDEOGRAPH + 0xE0C5: 0x55EF, //CJK UNIFIED IDEOGRAPH + 0xE0C6: 0x55E5, //CJK UNIFIED IDEOGRAPH + 0xE0C7: 0x55F2, //CJK UNIFIED IDEOGRAPH + 0xE0C8: 0x55F3, //CJK UNIFIED IDEOGRAPH + 0xE0C9: 0x55CC, //CJK UNIFIED IDEOGRAPH + 0xE0CA: 0x55CD, //CJK UNIFIED IDEOGRAPH + 0xE0CB: 0x55E8, //CJK UNIFIED IDEOGRAPH + 0xE0CC: 0x55F5, //CJK UNIFIED IDEOGRAPH + 0xE0CD: 0x55E4, //CJK UNIFIED IDEOGRAPH + 0xE0CE: 0x8F94, //CJK UNIFIED IDEOGRAPH + 0xE0CF: 0x561E, //CJK UNIFIED IDEOGRAPH + 0xE0D0: 0x5608, //CJK UNIFIED IDEOGRAPH + 0xE0D1: 0x560C, //CJK UNIFIED IDEOGRAPH + 0xE0D2: 0x5601, //CJK UNIFIED IDEOGRAPH + 0xE0D3: 0x5624, //CJK UNIFIED IDEOGRAPH + 0xE0D4: 0x5623, //CJK UNIFIED IDEOGRAPH + 0xE0D5: 0x55FE, //CJK UNIFIED IDEOGRAPH + 0xE0D6: 0x5600, //CJK UNIFIED IDEOGRAPH + 0xE0D7: 0x5627, //CJK UNIFIED IDEOGRAPH + 0xE0D8: 0x562D, //CJK UNIFIED IDEOGRAPH + 0xE0D9: 0x5658, //CJK UNIFIED IDEOGRAPH + 0xE0DA: 0x5639, //CJK UNIFIED IDEOGRAPH + 0xE0DB: 0x5657, //CJK UNIFIED IDEOGRAPH + 0xE0DC: 0x562C, //CJK UNIFIED IDEOGRAPH + 0xE0DD: 0x564D, //CJK UNIFIED IDEOGRAPH + 0xE0DE: 0x5662, //CJK UNIFIED IDEOGRAPH + 0xE0DF: 0x5659, //CJK UNIFIED IDEOGRAPH + 0xE0E0: 0x565C, //CJK UNIFIED IDEOGRAPH + 0xE0E1: 0x564C, //CJK UNIFIED IDEOGRAPH + 0xE0E2: 0x5654, //CJK UNIFIED IDEOGRAPH + 0xE0E3: 0x5686, //CJK UNIFIED IDEOGRAPH + 0xE0E4: 0x5664, //CJK UNIFIED IDEOGRAPH + 0xE0E5: 0x5671, //CJK UNIFIED IDEOGRAPH + 0xE0E6: 0x566B, //CJK UNIFIED IDEOGRAPH + 0xE0E7: 0x567B, //CJK UNIFIED IDEOGRAPH + 0xE0E8: 0x567C, //CJK UNIFIED IDEOGRAPH + 0xE0E9: 0x5685, //CJK UNIFIED IDEOGRAPH + 0xE0EA: 0x5693, //CJK UNIFIED IDEOGRAPH + 0xE0EB: 0x56AF, //CJK UNIFIED IDEOGRAPH + 0xE0EC: 0x56D4, //CJK UNIFIED IDEOGRAPH + 0xE0ED: 0x56D7, //CJK UNIFIED IDEOGRAPH + 0xE0EE: 0x56DD, //CJK UNIFIED IDEOGRAPH + 0xE0EF: 0x56E1, //CJK UNIFIED IDEOGRAPH + 0xE0F0: 0x56F5, //CJK UNIFIED IDEOGRAPH + 0xE0F1: 0x56EB, //CJK UNIFIED IDEOGRAPH + 0xE0F2: 0x56F9, //CJK UNIFIED IDEOGRAPH + 0xE0F3: 0x56FF, //CJK UNIFIED IDEOGRAPH + 0xE0F4: 0x5704, //CJK UNIFIED IDEOGRAPH + 0xE0F5: 0x570A, //CJK UNIFIED IDEOGRAPH + 0xE0F6: 0x5709, //CJK UNIFIED IDEOGRAPH + 0xE0F7: 0x571C, //CJK UNIFIED IDEOGRAPH + 0xE0F8: 0x5E0F, //CJK UNIFIED IDEOGRAPH + 0xE0F9: 0x5E19, //CJK UNIFIED IDEOGRAPH + 0xE0FA: 0x5E14, //CJK UNIFIED IDEOGRAPH + 0xE0FB: 0x5E11, //CJK UNIFIED IDEOGRAPH + 0xE0FC: 0x5E31, //CJK UNIFIED IDEOGRAPH + 0xE0FD: 0x5E3B, //CJK UNIFIED IDEOGRAPH + 0xE0FE: 0x5E3C, //CJK UNIFIED IDEOGRAPH + 0xE140: 0x9145, //CJK UNIFIED IDEOGRAPH + 0xE141: 0x9147, //CJK UNIFIED IDEOGRAPH + 0xE142: 0x9148, //CJK UNIFIED IDEOGRAPH + 0xE143: 0x9151, //CJK UNIFIED IDEOGRAPH + 0xE144: 0x9153, //CJK UNIFIED IDEOGRAPH + 0xE145: 0x9154, //CJK UNIFIED IDEOGRAPH + 0xE146: 0x9155, //CJK UNIFIED IDEOGRAPH + 0xE147: 0x9156, //CJK UNIFIED IDEOGRAPH + 0xE148: 0x9158, //CJK UNIFIED IDEOGRAPH + 0xE149: 0x9159, //CJK UNIFIED IDEOGRAPH + 0xE14A: 0x915B, //CJK UNIFIED IDEOGRAPH + 0xE14B: 0x915C, //CJK UNIFIED IDEOGRAPH + 0xE14C: 0x915F, //CJK UNIFIED IDEOGRAPH + 0xE14D: 0x9160, //CJK UNIFIED IDEOGRAPH + 0xE14E: 0x9166, //CJK UNIFIED IDEOGRAPH + 0xE14F: 0x9167, //CJK UNIFIED IDEOGRAPH + 0xE150: 0x9168, //CJK UNIFIED IDEOGRAPH + 0xE151: 0x916B, //CJK UNIFIED IDEOGRAPH + 0xE152: 0x916D, //CJK UNIFIED IDEOGRAPH + 0xE153: 0x9173, //CJK UNIFIED IDEOGRAPH + 0xE154: 0x917A, //CJK UNIFIED IDEOGRAPH + 0xE155: 0x917B, //CJK UNIFIED IDEOGRAPH + 0xE156: 0x917C, //CJK UNIFIED IDEOGRAPH + 0xE157: 0x9180, //CJK UNIFIED IDEOGRAPH + 0xE158: 0x9181, //CJK UNIFIED IDEOGRAPH + 0xE159: 0x9182, //CJK UNIFIED IDEOGRAPH + 0xE15A: 0x9183, //CJK UNIFIED IDEOGRAPH + 0xE15B: 0x9184, //CJK UNIFIED IDEOGRAPH + 0xE15C: 0x9186, //CJK UNIFIED IDEOGRAPH + 0xE15D: 0x9188, //CJK UNIFIED IDEOGRAPH + 0xE15E: 0x918A, //CJK UNIFIED IDEOGRAPH + 0xE15F: 0x918E, //CJK UNIFIED IDEOGRAPH + 0xE160: 0x918F, //CJK UNIFIED IDEOGRAPH + 0xE161: 0x9193, //CJK UNIFIED IDEOGRAPH + 0xE162: 0x9194, //CJK UNIFIED IDEOGRAPH + 0xE163: 0x9195, //CJK UNIFIED IDEOGRAPH + 0xE164: 0x9196, //CJK UNIFIED IDEOGRAPH + 0xE165: 0x9197, //CJK UNIFIED IDEOGRAPH + 0xE166: 0x9198, //CJK UNIFIED IDEOGRAPH + 0xE167: 0x9199, //CJK UNIFIED IDEOGRAPH + 0xE168: 0x919C, //CJK UNIFIED IDEOGRAPH + 0xE169: 0x919D, //CJK UNIFIED IDEOGRAPH + 0xE16A: 0x919E, //CJK UNIFIED IDEOGRAPH + 0xE16B: 0x919F, //CJK UNIFIED IDEOGRAPH + 0xE16C: 0x91A0, //CJK UNIFIED IDEOGRAPH + 0xE16D: 0x91A1, //CJK UNIFIED IDEOGRAPH + 0xE16E: 0x91A4, //CJK UNIFIED IDEOGRAPH + 0xE16F: 0x91A5, //CJK UNIFIED IDEOGRAPH + 0xE170: 0x91A6, //CJK UNIFIED IDEOGRAPH + 0xE171: 0x91A7, //CJK UNIFIED IDEOGRAPH + 0xE172: 0x91A8, //CJK UNIFIED IDEOGRAPH + 0xE173: 0x91A9, //CJK UNIFIED IDEOGRAPH + 0xE174: 0x91AB, //CJK UNIFIED IDEOGRAPH + 0xE175: 0x91AC, //CJK UNIFIED IDEOGRAPH + 0xE176: 0x91B0, //CJK UNIFIED IDEOGRAPH + 0xE177: 0x91B1, //CJK UNIFIED IDEOGRAPH + 0xE178: 0x91B2, //CJK UNIFIED IDEOGRAPH + 0xE179: 0x91B3, //CJK UNIFIED IDEOGRAPH + 0xE17A: 0x91B6, //CJK UNIFIED IDEOGRAPH + 0xE17B: 0x91B7, //CJK UNIFIED IDEOGRAPH + 0xE17C: 0x91B8, //CJK UNIFIED IDEOGRAPH + 0xE17D: 0x91B9, //CJK UNIFIED IDEOGRAPH + 0xE17E: 0x91BB, //CJK UNIFIED IDEOGRAPH + 0xE180: 0x91BC, //CJK UNIFIED IDEOGRAPH + 0xE181: 0x91BD, //CJK UNIFIED IDEOGRAPH + 0xE182: 0x91BE, //CJK UNIFIED IDEOGRAPH + 0xE183: 0x91BF, //CJK UNIFIED IDEOGRAPH + 0xE184: 0x91C0, //CJK UNIFIED IDEOGRAPH + 0xE185: 0x91C1, //CJK UNIFIED IDEOGRAPH + 0xE186: 0x91C2, //CJK UNIFIED IDEOGRAPH + 0xE187: 0x91C3, //CJK UNIFIED IDEOGRAPH + 0xE188: 0x91C4, //CJK UNIFIED IDEOGRAPH + 0xE189: 0x91C5, //CJK UNIFIED IDEOGRAPH + 0xE18A: 0x91C6, //CJK UNIFIED IDEOGRAPH + 0xE18B: 0x91C8, //CJK UNIFIED IDEOGRAPH + 0xE18C: 0x91CB, //CJK UNIFIED IDEOGRAPH + 0xE18D: 0x91D0, //CJK UNIFIED IDEOGRAPH + 0xE18E: 0x91D2, //CJK UNIFIED IDEOGRAPH + 0xE18F: 0x91D3, //CJK UNIFIED IDEOGRAPH + 0xE190: 0x91D4, //CJK UNIFIED IDEOGRAPH + 0xE191: 0x91D5, //CJK UNIFIED IDEOGRAPH + 0xE192: 0x91D6, //CJK UNIFIED IDEOGRAPH + 0xE193: 0x91D7, //CJK UNIFIED IDEOGRAPH + 0xE194: 0x91D8, //CJK UNIFIED IDEOGRAPH + 0xE195: 0x91D9, //CJK UNIFIED IDEOGRAPH + 0xE196: 0x91DA, //CJK UNIFIED IDEOGRAPH + 0xE197: 0x91DB, //CJK UNIFIED IDEOGRAPH + 0xE198: 0x91DD, //CJK UNIFIED IDEOGRAPH + 0xE199: 0x91DE, //CJK UNIFIED IDEOGRAPH + 0xE19A: 0x91DF, //CJK UNIFIED IDEOGRAPH + 0xE19B: 0x91E0, //CJK UNIFIED IDEOGRAPH + 0xE19C: 0x91E1, //CJK UNIFIED IDEOGRAPH + 0xE19D: 0x91E2, //CJK UNIFIED IDEOGRAPH + 0xE19E: 0x91E3, //CJK UNIFIED IDEOGRAPH + 0xE19F: 0x91E4, //CJK UNIFIED IDEOGRAPH + 0xE1A0: 0x91E5, //CJK UNIFIED IDEOGRAPH + 0xE1A1: 0x5E37, //CJK UNIFIED IDEOGRAPH + 0xE1A2: 0x5E44, //CJK UNIFIED IDEOGRAPH + 0xE1A3: 0x5E54, //CJK UNIFIED IDEOGRAPH + 0xE1A4: 0x5E5B, //CJK UNIFIED IDEOGRAPH + 0xE1A5: 0x5E5E, //CJK UNIFIED IDEOGRAPH + 0xE1A6: 0x5E61, //CJK UNIFIED IDEOGRAPH + 0xE1A7: 0x5C8C, //CJK UNIFIED IDEOGRAPH + 0xE1A8: 0x5C7A, //CJK UNIFIED IDEOGRAPH + 0xE1A9: 0x5C8D, //CJK UNIFIED IDEOGRAPH + 0xE1AA: 0x5C90, //CJK UNIFIED IDEOGRAPH + 0xE1AB: 0x5C96, //CJK UNIFIED IDEOGRAPH + 0xE1AC: 0x5C88, //CJK UNIFIED IDEOGRAPH + 0xE1AD: 0x5C98, //CJK UNIFIED IDEOGRAPH + 0xE1AE: 0x5C99, //CJK UNIFIED IDEOGRAPH + 0xE1AF: 0x5C91, //CJK UNIFIED IDEOGRAPH + 0xE1B0: 0x5C9A, //CJK UNIFIED IDEOGRAPH + 0xE1B1: 0x5C9C, //CJK UNIFIED IDEOGRAPH + 0xE1B2: 0x5CB5, //CJK UNIFIED IDEOGRAPH + 0xE1B3: 0x5CA2, //CJK UNIFIED IDEOGRAPH + 0xE1B4: 0x5CBD, //CJK UNIFIED IDEOGRAPH + 0xE1B5: 0x5CAC, //CJK UNIFIED IDEOGRAPH + 0xE1B6: 0x5CAB, //CJK UNIFIED IDEOGRAPH + 0xE1B7: 0x5CB1, //CJK UNIFIED IDEOGRAPH + 0xE1B8: 0x5CA3, //CJK UNIFIED IDEOGRAPH + 0xE1B9: 0x5CC1, //CJK UNIFIED IDEOGRAPH + 0xE1BA: 0x5CB7, //CJK UNIFIED IDEOGRAPH + 0xE1BB: 0x5CC4, //CJK UNIFIED IDEOGRAPH + 0xE1BC: 0x5CD2, //CJK UNIFIED IDEOGRAPH + 0xE1BD: 0x5CE4, //CJK UNIFIED IDEOGRAPH + 0xE1BE: 0x5CCB, //CJK UNIFIED IDEOGRAPH + 0xE1BF: 0x5CE5, //CJK UNIFIED IDEOGRAPH + 0xE1C0: 0x5D02, //CJK UNIFIED IDEOGRAPH + 0xE1C1: 0x5D03, //CJK UNIFIED IDEOGRAPH + 0xE1C2: 0x5D27, //CJK UNIFIED IDEOGRAPH + 0xE1C3: 0x5D26, //CJK UNIFIED IDEOGRAPH + 0xE1C4: 0x5D2E, //CJK UNIFIED IDEOGRAPH + 0xE1C5: 0x5D24, //CJK UNIFIED IDEOGRAPH + 0xE1C6: 0x5D1E, //CJK UNIFIED IDEOGRAPH + 0xE1C7: 0x5D06, //CJK UNIFIED IDEOGRAPH + 0xE1C8: 0x5D1B, //CJK UNIFIED IDEOGRAPH + 0xE1C9: 0x5D58, //CJK UNIFIED IDEOGRAPH + 0xE1CA: 0x5D3E, //CJK UNIFIED IDEOGRAPH + 0xE1CB: 0x5D34, //CJK UNIFIED IDEOGRAPH + 0xE1CC: 0x5D3D, //CJK UNIFIED IDEOGRAPH + 0xE1CD: 0x5D6C, //CJK UNIFIED IDEOGRAPH + 0xE1CE: 0x5D5B, //CJK UNIFIED IDEOGRAPH + 0xE1CF: 0x5D6F, //CJK UNIFIED IDEOGRAPH + 0xE1D0: 0x5D5D, //CJK UNIFIED IDEOGRAPH + 0xE1D1: 0x5D6B, //CJK UNIFIED IDEOGRAPH + 0xE1D2: 0x5D4B, //CJK UNIFIED IDEOGRAPH + 0xE1D3: 0x5D4A, //CJK UNIFIED IDEOGRAPH + 0xE1D4: 0x5D69, //CJK UNIFIED IDEOGRAPH + 0xE1D5: 0x5D74, //CJK UNIFIED IDEOGRAPH + 0xE1D6: 0x5D82, //CJK UNIFIED IDEOGRAPH + 0xE1D7: 0x5D99, //CJK UNIFIED IDEOGRAPH + 0xE1D8: 0x5D9D, //CJK UNIFIED IDEOGRAPH + 0xE1D9: 0x8C73, //CJK UNIFIED IDEOGRAPH + 0xE1DA: 0x5DB7, //CJK UNIFIED IDEOGRAPH + 0xE1DB: 0x5DC5, //CJK UNIFIED IDEOGRAPH + 0xE1DC: 0x5F73, //CJK UNIFIED IDEOGRAPH + 0xE1DD: 0x5F77, //CJK UNIFIED IDEOGRAPH + 0xE1DE: 0x5F82, //CJK UNIFIED IDEOGRAPH + 0xE1DF: 0x5F87, //CJK UNIFIED IDEOGRAPH + 0xE1E0: 0x5F89, //CJK UNIFIED IDEOGRAPH + 0xE1E1: 0x5F8C, //CJK UNIFIED IDEOGRAPH + 0xE1E2: 0x5F95, //CJK UNIFIED IDEOGRAPH + 0xE1E3: 0x5F99, //CJK UNIFIED IDEOGRAPH + 0xE1E4: 0x5F9C, //CJK UNIFIED IDEOGRAPH + 0xE1E5: 0x5FA8, //CJK UNIFIED IDEOGRAPH + 0xE1E6: 0x5FAD, //CJK UNIFIED IDEOGRAPH + 0xE1E7: 0x5FB5, //CJK UNIFIED IDEOGRAPH + 0xE1E8: 0x5FBC, //CJK UNIFIED IDEOGRAPH + 0xE1E9: 0x8862, //CJK UNIFIED IDEOGRAPH + 0xE1EA: 0x5F61, //CJK UNIFIED IDEOGRAPH + 0xE1EB: 0x72AD, //CJK UNIFIED IDEOGRAPH + 0xE1EC: 0x72B0, //CJK UNIFIED IDEOGRAPH + 0xE1ED: 0x72B4, //CJK UNIFIED IDEOGRAPH + 0xE1EE: 0x72B7, //CJK UNIFIED IDEOGRAPH + 0xE1EF: 0x72B8, //CJK UNIFIED IDEOGRAPH + 0xE1F0: 0x72C3, //CJK UNIFIED IDEOGRAPH + 0xE1F1: 0x72C1, //CJK UNIFIED IDEOGRAPH + 0xE1F2: 0x72CE, //CJK UNIFIED IDEOGRAPH + 0xE1F3: 0x72CD, //CJK UNIFIED IDEOGRAPH + 0xE1F4: 0x72D2, //CJK UNIFIED IDEOGRAPH + 0xE1F5: 0x72E8, //CJK UNIFIED IDEOGRAPH + 0xE1F6: 0x72EF, //CJK UNIFIED IDEOGRAPH + 0xE1F7: 0x72E9, //CJK UNIFIED IDEOGRAPH + 0xE1F8: 0x72F2, //CJK UNIFIED IDEOGRAPH + 0xE1F9: 0x72F4, //CJK UNIFIED IDEOGRAPH + 0xE1FA: 0x72F7, //CJK UNIFIED IDEOGRAPH + 0xE1FB: 0x7301, //CJK UNIFIED IDEOGRAPH + 0xE1FC: 0x72F3, //CJK UNIFIED IDEOGRAPH + 0xE1FD: 0x7303, //CJK UNIFIED IDEOGRAPH + 0xE1FE: 0x72FA, //CJK UNIFIED IDEOGRAPH + 0xE240: 0x91E6, //CJK UNIFIED IDEOGRAPH + 0xE241: 0x91E7, //CJK UNIFIED IDEOGRAPH + 0xE242: 0x91E8, //CJK UNIFIED IDEOGRAPH + 0xE243: 0x91E9, //CJK UNIFIED IDEOGRAPH + 0xE244: 0x91EA, //CJK UNIFIED IDEOGRAPH + 0xE245: 0x91EB, //CJK UNIFIED IDEOGRAPH + 0xE246: 0x91EC, //CJK UNIFIED IDEOGRAPH + 0xE247: 0x91ED, //CJK UNIFIED IDEOGRAPH + 0xE248: 0x91EE, //CJK UNIFIED IDEOGRAPH + 0xE249: 0x91EF, //CJK UNIFIED IDEOGRAPH + 0xE24A: 0x91F0, //CJK UNIFIED IDEOGRAPH + 0xE24B: 0x91F1, //CJK UNIFIED IDEOGRAPH + 0xE24C: 0x91F2, //CJK UNIFIED IDEOGRAPH + 0xE24D: 0x91F3, //CJK UNIFIED IDEOGRAPH + 0xE24E: 0x91F4, //CJK UNIFIED IDEOGRAPH + 0xE24F: 0x91F5, //CJK UNIFIED IDEOGRAPH + 0xE250: 0x91F6, //CJK UNIFIED IDEOGRAPH + 0xE251: 0x91F7, //CJK UNIFIED IDEOGRAPH + 0xE252: 0x91F8, //CJK UNIFIED IDEOGRAPH + 0xE253: 0x91F9, //CJK UNIFIED IDEOGRAPH + 0xE254: 0x91FA, //CJK UNIFIED IDEOGRAPH + 0xE255: 0x91FB, //CJK UNIFIED IDEOGRAPH + 0xE256: 0x91FC, //CJK UNIFIED IDEOGRAPH + 0xE257: 0x91FD, //CJK UNIFIED IDEOGRAPH + 0xE258: 0x91FE, //CJK UNIFIED IDEOGRAPH + 0xE259: 0x91FF, //CJK UNIFIED IDEOGRAPH + 0xE25A: 0x9200, //CJK UNIFIED IDEOGRAPH + 0xE25B: 0x9201, //CJK UNIFIED IDEOGRAPH + 0xE25C: 0x9202, //CJK UNIFIED IDEOGRAPH + 0xE25D: 0x9203, //CJK UNIFIED IDEOGRAPH + 0xE25E: 0x9204, //CJK UNIFIED IDEOGRAPH + 0xE25F: 0x9205, //CJK UNIFIED IDEOGRAPH + 0xE260: 0x9206, //CJK UNIFIED IDEOGRAPH + 0xE261: 0x9207, //CJK UNIFIED IDEOGRAPH + 0xE262: 0x9208, //CJK UNIFIED IDEOGRAPH + 0xE263: 0x9209, //CJK UNIFIED IDEOGRAPH + 0xE264: 0x920A, //CJK UNIFIED IDEOGRAPH + 0xE265: 0x920B, //CJK UNIFIED IDEOGRAPH + 0xE266: 0x920C, //CJK UNIFIED IDEOGRAPH + 0xE267: 0x920D, //CJK UNIFIED IDEOGRAPH + 0xE268: 0x920E, //CJK UNIFIED IDEOGRAPH + 0xE269: 0x920F, //CJK UNIFIED IDEOGRAPH + 0xE26A: 0x9210, //CJK UNIFIED IDEOGRAPH + 0xE26B: 0x9211, //CJK UNIFIED IDEOGRAPH + 0xE26C: 0x9212, //CJK UNIFIED IDEOGRAPH + 0xE26D: 0x9213, //CJK UNIFIED IDEOGRAPH + 0xE26E: 0x9214, //CJK UNIFIED IDEOGRAPH + 0xE26F: 0x9215, //CJK UNIFIED IDEOGRAPH + 0xE270: 0x9216, //CJK UNIFIED IDEOGRAPH + 0xE271: 0x9217, //CJK UNIFIED IDEOGRAPH + 0xE272: 0x9218, //CJK UNIFIED IDEOGRAPH + 0xE273: 0x9219, //CJK UNIFIED IDEOGRAPH + 0xE274: 0x921A, //CJK UNIFIED IDEOGRAPH + 0xE275: 0x921B, //CJK UNIFIED IDEOGRAPH + 0xE276: 0x921C, //CJK UNIFIED IDEOGRAPH + 0xE277: 0x921D, //CJK UNIFIED IDEOGRAPH + 0xE278: 0x921E, //CJK UNIFIED IDEOGRAPH + 0xE279: 0x921F, //CJK UNIFIED IDEOGRAPH + 0xE27A: 0x9220, //CJK UNIFIED IDEOGRAPH + 0xE27B: 0x9221, //CJK UNIFIED IDEOGRAPH + 0xE27C: 0x9222, //CJK UNIFIED IDEOGRAPH + 0xE27D: 0x9223, //CJK UNIFIED IDEOGRAPH + 0xE27E: 0x9224, //CJK UNIFIED IDEOGRAPH + 0xE280: 0x9225, //CJK UNIFIED IDEOGRAPH + 0xE281: 0x9226, //CJK UNIFIED IDEOGRAPH + 0xE282: 0x9227, //CJK UNIFIED IDEOGRAPH + 0xE283: 0x9228, //CJK UNIFIED IDEOGRAPH + 0xE284: 0x9229, //CJK UNIFIED IDEOGRAPH + 0xE285: 0x922A, //CJK UNIFIED IDEOGRAPH + 0xE286: 0x922B, //CJK UNIFIED IDEOGRAPH + 0xE287: 0x922C, //CJK UNIFIED IDEOGRAPH + 0xE288: 0x922D, //CJK UNIFIED IDEOGRAPH + 0xE289: 0x922E, //CJK UNIFIED IDEOGRAPH + 0xE28A: 0x922F, //CJK UNIFIED IDEOGRAPH + 0xE28B: 0x9230, //CJK UNIFIED IDEOGRAPH + 0xE28C: 0x9231, //CJK UNIFIED IDEOGRAPH + 0xE28D: 0x9232, //CJK UNIFIED IDEOGRAPH + 0xE28E: 0x9233, //CJK UNIFIED IDEOGRAPH + 0xE28F: 0x9234, //CJK UNIFIED IDEOGRAPH + 0xE290: 0x9235, //CJK UNIFIED IDEOGRAPH + 0xE291: 0x9236, //CJK UNIFIED IDEOGRAPH + 0xE292: 0x9237, //CJK UNIFIED IDEOGRAPH + 0xE293: 0x9238, //CJK UNIFIED IDEOGRAPH + 0xE294: 0x9239, //CJK UNIFIED IDEOGRAPH + 0xE295: 0x923A, //CJK UNIFIED IDEOGRAPH + 0xE296: 0x923B, //CJK UNIFIED IDEOGRAPH + 0xE297: 0x923C, //CJK UNIFIED IDEOGRAPH + 0xE298: 0x923D, //CJK UNIFIED IDEOGRAPH + 0xE299: 0x923E, //CJK UNIFIED IDEOGRAPH + 0xE29A: 0x923F, //CJK UNIFIED IDEOGRAPH + 0xE29B: 0x9240, //CJK UNIFIED IDEOGRAPH + 0xE29C: 0x9241, //CJK UNIFIED IDEOGRAPH + 0xE29D: 0x9242, //CJK UNIFIED IDEOGRAPH + 0xE29E: 0x9243, //CJK UNIFIED IDEOGRAPH + 0xE29F: 0x9244, //CJK UNIFIED IDEOGRAPH + 0xE2A0: 0x9245, //CJK UNIFIED IDEOGRAPH + 0xE2A1: 0x72FB, //CJK UNIFIED IDEOGRAPH + 0xE2A2: 0x7317, //CJK UNIFIED IDEOGRAPH + 0xE2A3: 0x7313, //CJK UNIFIED IDEOGRAPH + 0xE2A4: 0x7321, //CJK UNIFIED IDEOGRAPH + 0xE2A5: 0x730A, //CJK UNIFIED IDEOGRAPH + 0xE2A6: 0x731E, //CJK UNIFIED IDEOGRAPH + 0xE2A7: 0x731D, //CJK UNIFIED IDEOGRAPH + 0xE2A8: 0x7315, //CJK UNIFIED IDEOGRAPH + 0xE2A9: 0x7322, //CJK UNIFIED IDEOGRAPH + 0xE2AA: 0x7339, //CJK UNIFIED IDEOGRAPH + 0xE2AB: 0x7325, //CJK UNIFIED IDEOGRAPH + 0xE2AC: 0x732C, //CJK UNIFIED IDEOGRAPH + 0xE2AD: 0x7338, //CJK UNIFIED IDEOGRAPH + 0xE2AE: 0x7331, //CJK UNIFIED IDEOGRAPH + 0xE2AF: 0x7350, //CJK UNIFIED IDEOGRAPH + 0xE2B0: 0x734D, //CJK UNIFIED IDEOGRAPH + 0xE2B1: 0x7357, //CJK UNIFIED IDEOGRAPH + 0xE2B2: 0x7360, //CJK UNIFIED IDEOGRAPH + 0xE2B3: 0x736C, //CJK UNIFIED IDEOGRAPH + 0xE2B4: 0x736F, //CJK UNIFIED IDEOGRAPH + 0xE2B5: 0x737E, //CJK UNIFIED IDEOGRAPH + 0xE2B6: 0x821B, //CJK UNIFIED IDEOGRAPH + 0xE2B7: 0x5925, //CJK UNIFIED IDEOGRAPH + 0xE2B8: 0x98E7, //CJK UNIFIED IDEOGRAPH + 0xE2B9: 0x5924, //CJK UNIFIED IDEOGRAPH + 0xE2BA: 0x5902, //CJK UNIFIED IDEOGRAPH + 0xE2BB: 0x9963, //CJK UNIFIED IDEOGRAPH + 0xE2BC: 0x9967, //CJK UNIFIED IDEOGRAPH + 0xE2BD: 0x9968, //CJK UNIFIED IDEOGRAPH + 0xE2BE: 0x9969, //CJK UNIFIED IDEOGRAPH + 0xE2BF: 0x996A, //CJK UNIFIED IDEOGRAPH + 0xE2C0: 0x996B, //CJK UNIFIED IDEOGRAPH + 0xE2C1: 0x996C, //CJK UNIFIED IDEOGRAPH + 0xE2C2: 0x9974, //CJK UNIFIED IDEOGRAPH + 0xE2C3: 0x9977, //CJK UNIFIED IDEOGRAPH + 0xE2C4: 0x997D, //CJK UNIFIED IDEOGRAPH + 0xE2C5: 0x9980, //CJK UNIFIED IDEOGRAPH + 0xE2C6: 0x9984, //CJK UNIFIED IDEOGRAPH + 0xE2C7: 0x9987, //CJK UNIFIED IDEOGRAPH + 0xE2C8: 0x998A, //CJK UNIFIED IDEOGRAPH + 0xE2C9: 0x998D, //CJK UNIFIED IDEOGRAPH + 0xE2CA: 0x9990, //CJK UNIFIED IDEOGRAPH + 0xE2CB: 0x9991, //CJK UNIFIED IDEOGRAPH + 0xE2CC: 0x9993, //CJK UNIFIED IDEOGRAPH + 0xE2CD: 0x9994, //CJK UNIFIED IDEOGRAPH + 0xE2CE: 0x9995, //CJK UNIFIED IDEOGRAPH + 0xE2CF: 0x5E80, //CJK UNIFIED IDEOGRAPH + 0xE2D0: 0x5E91, //CJK UNIFIED IDEOGRAPH + 0xE2D1: 0x5E8B, //CJK UNIFIED IDEOGRAPH + 0xE2D2: 0x5E96, //CJK UNIFIED IDEOGRAPH + 0xE2D3: 0x5EA5, //CJK UNIFIED IDEOGRAPH + 0xE2D4: 0x5EA0, //CJK UNIFIED IDEOGRAPH + 0xE2D5: 0x5EB9, //CJK UNIFIED IDEOGRAPH + 0xE2D6: 0x5EB5, //CJK UNIFIED IDEOGRAPH + 0xE2D7: 0x5EBE, //CJK UNIFIED IDEOGRAPH + 0xE2D8: 0x5EB3, //CJK UNIFIED IDEOGRAPH + 0xE2D9: 0x8D53, //CJK UNIFIED IDEOGRAPH + 0xE2DA: 0x5ED2, //CJK UNIFIED IDEOGRAPH + 0xE2DB: 0x5ED1, //CJK UNIFIED IDEOGRAPH + 0xE2DC: 0x5EDB, //CJK UNIFIED IDEOGRAPH + 0xE2DD: 0x5EE8, //CJK UNIFIED IDEOGRAPH + 0xE2DE: 0x5EEA, //CJK UNIFIED IDEOGRAPH + 0xE2DF: 0x81BA, //CJK UNIFIED IDEOGRAPH + 0xE2E0: 0x5FC4, //CJK UNIFIED IDEOGRAPH + 0xE2E1: 0x5FC9, //CJK UNIFIED IDEOGRAPH + 0xE2E2: 0x5FD6, //CJK UNIFIED IDEOGRAPH + 0xE2E3: 0x5FCF, //CJK UNIFIED IDEOGRAPH + 0xE2E4: 0x6003, //CJK UNIFIED IDEOGRAPH + 0xE2E5: 0x5FEE, //CJK UNIFIED IDEOGRAPH + 0xE2E6: 0x6004, //CJK UNIFIED IDEOGRAPH + 0xE2E7: 0x5FE1, //CJK UNIFIED IDEOGRAPH + 0xE2E8: 0x5FE4, //CJK UNIFIED IDEOGRAPH + 0xE2E9: 0x5FFE, //CJK UNIFIED IDEOGRAPH + 0xE2EA: 0x6005, //CJK UNIFIED IDEOGRAPH + 0xE2EB: 0x6006, //CJK UNIFIED IDEOGRAPH + 0xE2EC: 0x5FEA, //CJK UNIFIED IDEOGRAPH + 0xE2ED: 0x5FED, //CJK UNIFIED IDEOGRAPH + 0xE2EE: 0x5FF8, //CJK UNIFIED IDEOGRAPH + 0xE2EF: 0x6019, //CJK UNIFIED IDEOGRAPH + 0xE2F0: 0x6035, //CJK UNIFIED IDEOGRAPH + 0xE2F1: 0x6026, //CJK UNIFIED IDEOGRAPH + 0xE2F2: 0x601B, //CJK UNIFIED IDEOGRAPH + 0xE2F3: 0x600F, //CJK UNIFIED IDEOGRAPH + 0xE2F4: 0x600D, //CJK UNIFIED IDEOGRAPH + 0xE2F5: 0x6029, //CJK UNIFIED IDEOGRAPH + 0xE2F6: 0x602B, //CJK UNIFIED IDEOGRAPH + 0xE2F7: 0x600A, //CJK UNIFIED IDEOGRAPH + 0xE2F8: 0x603F, //CJK UNIFIED IDEOGRAPH + 0xE2F9: 0x6021, //CJK UNIFIED IDEOGRAPH + 0xE2FA: 0x6078, //CJK UNIFIED IDEOGRAPH + 0xE2FB: 0x6079, //CJK UNIFIED IDEOGRAPH + 0xE2FC: 0x607B, //CJK UNIFIED IDEOGRAPH + 0xE2FD: 0x607A, //CJK UNIFIED IDEOGRAPH + 0xE2FE: 0x6042, //CJK UNIFIED IDEOGRAPH + 0xE340: 0x9246, //CJK UNIFIED IDEOGRAPH + 0xE341: 0x9247, //CJK UNIFIED IDEOGRAPH + 0xE342: 0x9248, //CJK UNIFIED IDEOGRAPH + 0xE343: 0x9249, //CJK UNIFIED IDEOGRAPH + 0xE344: 0x924A, //CJK UNIFIED IDEOGRAPH + 0xE345: 0x924B, //CJK UNIFIED IDEOGRAPH + 0xE346: 0x924C, //CJK UNIFIED IDEOGRAPH + 0xE347: 0x924D, //CJK UNIFIED IDEOGRAPH + 0xE348: 0x924E, //CJK UNIFIED IDEOGRAPH + 0xE349: 0x924F, //CJK UNIFIED IDEOGRAPH + 0xE34A: 0x9250, //CJK UNIFIED IDEOGRAPH + 0xE34B: 0x9251, //CJK UNIFIED IDEOGRAPH + 0xE34C: 0x9252, //CJK UNIFIED IDEOGRAPH + 0xE34D: 0x9253, //CJK UNIFIED IDEOGRAPH + 0xE34E: 0x9254, //CJK UNIFIED IDEOGRAPH + 0xE34F: 0x9255, //CJK UNIFIED IDEOGRAPH + 0xE350: 0x9256, //CJK UNIFIED IDEOGRAPH + 0xE351: 0x9257, //CJK UNIFIED IDEOGRAPH + 0xE352: 0x9258, //CJK UNIFIED IDEOGRAPH + 0xE353: 0x9259, //CJK UNIFIED IDEOGRAPH + 0xE354: 0x925A, //CJK UNIFIED IDEOGRAPH + 0xE355: 0x925B, //CJK UNIFIED IDEOGRAPH + 0xE356: 0x925C, //CJK UNIFIED IDEOGRAPH + 0xE357: 0x925D, //CJK UNIFIED IDEOGRAPH + 0xE358: 0x925E, //CJK UNIFIED IDEOGRAPH + 0xE359: 0x925F, //CJK UNIFIED IDEOGRAPH + 0xE35A: 0x9260, //CJK UNIFIED IDEOGRAPH + 0xE35B: 0x9261, //CJK UNIFIED IDEOGRAPH + 0xE35C: 0x9262, //CJK UNIFIED IDEOGRAPH + 0xE35D: 0x9263, //CJK UNIFIED IDEOGRAPH + 0xE35E: 0x9264, //CJK UNIFIED IDEOGRAPH + 0xE35F: 0x9265, //CJK UNIFIED IDEOGRAPH + 0xE360: 0x9266, //CJK UNIFIED IDEOGRAPH + 0xE361: 0x9267, //CJK UNIFIED IDEOGRAPH + 0xE362: 0x9268, //CJK UNIFIED IDEOGRAPH + 0xE363: 0x9269, //CJK UNIFIED IDEOGRAPH + 0xE364: 0x926A, //CJK UNIFIED IDEOGRAPH + 0xE365: 0x926B, //CJK UNIFIED IDEOGRAPH + 0xE366: 0x926C, //CJK UNIFIED IDEOGRAPH + 0xE367: 0x926D, //CJK UNIFIED IDEOGRAPH + 0xE368: 0x926E, //CJK UNIFIED IDEOGRAPH + 0xE369: 0x926F, //CJK UNIFIED IDEOGRAPH + 0xE36A: 0x9270, //CJK UNIFIED IDEOGRAPH + 0xE36B: 0x9271, //CJK UNIFIED IDEOGRAPH + 0xE36C: 0x9272, //CJK UNIFIED IDEOGRAPH + 0xE36D: 0x9273, //CJK UNIFIED IDEOGRAPH + 0xE36E: 0x9275, //CJK UNIFIED IDEOGRAPH + 0xE36F: 0x9276, //CJK UNIFIED IDEOGRAPH + 0xE370: 0x9277, //CJK UNIFIED IDEOGRAPH + 0xE371: 0x9278, //CJK UNIFIED IDEOGRAPH + 0xE372: 0x9279, //CJK UNIFIED IDEOGRAPH + 0xE373: 0x927A, //CJK UNIFIED IDEOGRAPH + 0xE374: 0x927B, //CJK UNIFIED IDEOGRAPH + 0xE375: 0x927C, //CJK UNIFIED IDEOGRAPH + 0xE376: 0x927D, //CJK UNIFIED IDEOGRAPH + 0xE377: 0x927E, //CJK UNIFIED IDEOGRAPH + 0xE378: 0x927F, //CJK UNIFIED IDEOGRAPH + 0xE379: 0x9280, //CJK UNIFIED IDEOGRAPH + 0xE37A: 0x9281, //CJK UNIFIED IDEOGRAPH + 0xE37B: 0x9282, //CJK UNIFIED IDEOGRAPH + 0xE37C: 0x9283, //CJK UNIFIED IDEOGRAPH + 0xE37D: 0x9284, //CJK UNIFIED IDEOGRAPH + 0xE37E: 0x9285, //CJK UNIFIED IDEOGRAPH + 0xE380: 0x9286, //CJK UNIFIED IDEOGRAPH + 0xE381: 0x9287, //CJK UNIFIED IDEOGRAPH + 0xE382: 0x9288, //CJK UNIFIED IDEOGRAPH + 0xE383: 0x9289, //CJK UNIFIED IDEOGRAPH + 0xE384: 0x928A, //CJK UNIFIED IDEOGRAPH + 0xE385: 0x928B, //CJK UNIFIED IDEOGRAPH + 0xE386: 0x928C, //CJK UNIFIED IDEOGRAPH + 0xE387: 0x928D, //CJK UNIFIED IDEOGRAPH + 0xE388: 0x928F, //CJK UNIFIED IDEOGRAPH + 0xE389: 0x9290, //CJK UNIFIED IDEOGRAPH + 0xE38A: 0x9291, //CJK UNIFIED IDEOGRAPH + 0xE38B: 0x9292, //CJK UNIFIED IDEOGRAPH + 0xE38C: 0x9293, //CJK UNIFIED IDEOGRAPH + 0xE38D: 0x9294, //CJK UNIFIED IDEOGRAPH + 0xE38E: 0x9295, //CJK UNIFIED IDEOGRAPH + 0xE38F: 0x9296, //CJK UNIFIED IDEOGRAPH + 0xE390: 0x9297, //CJK UNIFIED IDEOGRAPH + 0xE391: 0x9298, //CJK UNIFIED IDEOGRAPH + 0xE392: 0x9299, //CJK UNIFIED IDEOGRAPH + 0xE393: 0x929A, //CJK UNIFIED IDEOGRAPH + 0xE394: 0x929B, //CJK UNIFIED IDEOGRAPH + 0xE395: 0x929C, //CJK UNIFIED IDEOGRAPH + 0xE396: 0x929D, //CJK UNIFIED IDEOGRAPH + 0xE397: 0x929E, //CJK UNIFIED IDEOGRAPH + 0xE398: 0x929F, //CJK UNIFIED IDEOGRAPH + 0xE399: 0x92A0, //CJK UNIFIED IDEOGRAPH + 0xE39A: 0x92A1, //CJK UNIFIED IDEOGRAPH + 0xE39B: 0x92A2, //CJK UNIFIED IDEOGRAPH + 0xE39C: 0x92A3, //CJK UNIFIED IDEOGRAPH + 0xE39D: 0x92A4, //CJK UNIFIED IDEOGRAPH + 0xE39E: 0x92A5, //CJK UNIFIED IDEOGRAPH + 0xE39F: 0x92A6, //CJK UNIFIED IDEOGRAPH + 0xE3A0: 0x92A7, //CJK UNIFIED IDEOGRAPH + 0xE3A1: 0x606A, //CJK UNIFIED IDEOGRAPH + 0xE3A2: 0x607D, //CJK UNIFIED IDEOGRAPH + 0xE3A3: 0x6096, //CJK UNIFIED IDEOGRAPH + 0xE3A4: 0x609A, //CJK UNIFIED IDEOGRAPH + 0xE3A5: 0x60AD, //CJK UNIFIED IDEOGRAPH + 0xE3A6: 0x609D, //CJK UNIFIED IDEOGRAPH + 0xE3A7: 0x6083, //CJK UNIFIED IDEOGRAPH + 0xE3A8: 0x6092, //CJK UNIFIED IDEOGRAPH + 0xE3A9: 0x608C, //CJK UNIFIED IDEOGRAPH + 0xE3AA: 0x609B, //CJK UNIFIED IDEOGRAPH + 0xE3AB: 0x60EC, //CJK UNIFIED IDEOGRAPH + 0xE3AC: 0x60BB, //CJK UNIFIED IDEOGRAPH + 0xE3AD: 0x60B1, //CJK UNIFIED IDEOGRAPH + 0xE3AE: 0x60DD, //CJK UNIFIED IDEOGRAPH + 0xE3AF: 0x60D8, //CJK UNIFIED IDEOGRAPH + 0xE3B0: 0x60C6, //CJK UNIFIED IDEOGRAPH + 0xE3B1: 0x60DA, //CJK UNIFIED IDEOGRAPH + 0xE3B2: 0x60B4, //CJK UNIFIED IDEOGRAPH + 0xE3B3: 0x6120, //CJK UNIFIED IDEOGRAPH + 0xE3B4: 0x6126, //CJK UNIFIED IDEOGRAPH + 0xE3B5: 0x6115, //CJK UNIFIED IDEOGRAPH + 0xE3B6: 0x6123, //CJK UNIFIED IDEOGRAPH + 0xE3B7: 0x60F4, //CJK UNIFIED IDEOGRAPH + 0xE3B8: 0x6100, //CJK UNIFIED IDEOGRAPH + 0xE3B9: 0x610E, //CJK UNIFIED IDEOGRAPH + 0xE3BA: 0x612B, //CJK UNIFIED IDEOGRAPH + 0xE3BB: 0x614A, //CJK UNIFIED IDEOGRAPH + 0xE3BC: 0x6175, //CJK UNIFIED IDEOGRAPH + 0xE3BD: 0x61AC, //CJK UNIFIED IDEOGRAPH + 0xE3BE: 0x6194, //CJK UNIFIED IDEOGRAPH + 0xE3BF: 0x61A7, //CJK UNIFIED IDEOGRAPH + 0xE3C0: 0x61B7, //CJK UNIFIED IDEOGRAPH + 0xE3C1: 0x61D4, //CJK UNIFIED IDEOGRAPH + 0xE3C2: 0x61F5, //CJK UNIFIED IDEOGRAPH + 0xE3C3: 0x5FDD, //CJK UNIFIED IDEOGRAPH + 0xE3C4: 0x96B3, //CJK UNIFIED IDEOGRAPH + 0xE3C5: 0x95E9, //CJK UNIFIED IDEOGRAPH + 0xE3C6: 0x95EB, //CJK UNIFIED IDEOGRAPH + 0xE3C7: 0x95F1, //CJK UNIFIED IDEOGRAPH + 0xE3C8: 0x95F3, //CJK UNIFIED IDEOGRAPH + 0xE3C9: 0x95F5, //CJK UNIFIED IDEOGRAPH + 0xE3CA: 0x95F6, //CJK UNIFIED IDEOGRAPH + 0xE3CB: 0x95FC, //CJK UNIFIED IDEOGRAPH + 0xE3CC: 0x95FE, //CJK UNIFIED IDEOGRAPH + 0xE3CD: 0x9603, //CJK UNIFIED IDEOGRAPH + 0xE3CE: 0x9604, //CJK UNIFIED IDEOGRAPH + 0xE3CF: 0x9606, //CJK UNIFIED IDEOGRAPH + 0xE3D0: 0x9608, //CJK UNIFIED IDEOGRAPH + 0xE3D1: 0x960A, //CJK UNIFIED IDEOGRAPH + 0xE3D2: 0x960B, //CJK UNIFIED IDEOGRAPH + 0xE3D3: 0x960C, //CJK UNIFIED IDEOGRAPH + 0xE3D4: 0x960D, //CJK UNIFIED IDEOGRAPH + 0xE3D5: 0x960F, //CJK UNIFIED IDEOGRAPH + 0xE3D6: 0x9612, //CJK UNIFIED IDEOGRAPH + 0xE3D7: 0x9615, //CJK UNIFIED IDEOGRAPH + 0xE3D8: 0x9616, //CJK UNIFIED IDEOGRAPH + 0xE3D9: 0x9617, //CJK UNIFIED IDEOGRAPH + 0xE3DA: 0x9619, //CJK UNIFIED IDEOGRAPH + 0xE3DB: 0x961A, //CJK UNIFIED IDEOGRAPH + 0xE3DC: 0x4E2C, //CJK UNIFIED IDEOGRAPH + 0xE3DD: 0x723F, //CJK UNIFIED IDEOGRAPH + 0xE3DE: 0x6215, //CJK UNIFIED IDEOGRAPH + 0xE3DF: 0x6C35, //CJK UNIFIED IDEOGRAPH + 0xE3E0: 0x6C54, //CJK UNIFIED IDEOGRAPH + 0xE3E1: 0x6C5C, //CJK UNIFIED IDEOGRAPH + 0xE3E2: 0x6C4A, //CJK UNIFIED IDEOGRAPH + 0xE3E3: 0x6CA3, //CJK UNIFIED IDEOGRAPH + 0xE3E4: 0x6C85, //CJK UNIFIED IDEOGRAPH + 0xE3E5: 0x6C90, //CJK UNIFIED IDEOGRAPH + 0xE3E6: 0x6C94, //CJK UNIFIED IDEOGRAPH + 0xE3E7: 0x6C8C, //CJK UNIFIED IDEOGRAPH + 0xE3E8: 0x6C68, //CJK UNIFIED IDEOGRAPH + 0xE3E9: 0x6C69, //CJK UNIFIED IDEOGRAPH + 0xE3EA: 0x6C74, //CJK UNIFIED IDEOGRAPH + 0xE3EB: 0x6C76, //CJK UNIFIED IDEOGRAPH + 0xE3EC: 0x6C86, //CJK UNIFIED IDEOGRAPH + 0xE3ED: 0x6CA9, //CJK UNIFIED IDEOGRAPH + 0xE3EE: 0x6CD0, //CJK UNIFIED IDEOGRAPH + 0xE3EF: 0x6CD4, //CJK UNIFIED IDEOGRAPH + 0xE3F0: 0x6CAD, //CJK UNIFIED IDEOGRAPH + 0xE3F1: 0x6CF7, //CJK UNIFIED IDEOGRAPH + 0xE3F2: 0x6CF8, //CJK UNIFIED IDEOGRAPH + 0xE3F3: 0x6CF1, //CJK UNIFIED IDEOGRAPH + 0xE3F4: 0x6CD7, //CJK UNIFIED IDEOGRAPH + 0xE3F5: 0x6CB2, //CJK UNIFIED IDEOGRAPH + 0xE3F6: 0x6CE0, //CJK UNIFIED IDEOGRAPH + 0xE3F7: 0x6CD6, //CJK UNIFIED IDEOGRAPH + 0xE3F8: 0x6CFA, //CJK UNIFIED IDEOGRAPH + 0xE3F9: 0x6CEB, //CJK UNIFIED IDEOGRAPH + 0xE3FA: 0x6CEE, //CJK UNIFIED IDEOGRAPH + 0xE3FB: 0x6CB1, //CJK UNIFIED IDEOGRAPH + 0xE3FC: 0x6CD3, //CJK UNIFIED IDEOGRAPH + 0xE3FD: 0x6CEF, //CJK UNIFIED IDEOGRAPH + 0xE3FE: 0x6CFE, //CJK UNIFIED IDEOGRAPH + 0xE440: 0x92A8, //CJK UNIFIED IDEOGRAPH + 0xE441: 0x92A9, //CJK UNIFIED IDEOGRAPH + 0xE442: 0x92AA, //CJK UNIFIED IDEOGRAPH + 0xE443: 0x92AB, //CJK UNIFIED IDEOGRAPH + 0xE444: 0x92AC, //CJK UNIFIED IDEOGRAPH + 0xE445: 0x92AD, //CJK UNIFIED IDEOGRAPH + 0xE446: 0x92AF, //CJK UNIFIED IDEOGRAPH + 0xE447: 0x92B0, //CJK UNIFIED IDEOGRAPH + 0xE448: 0x92B1, //CJK UNIFIED IDEOGRAPH + 0xE449: 0x92B2, //CJK UNIFIED IDEOGRAPH + 0xE44A: 0x92B3, //CJK UNIFIED IDEOGRAPH + 0xE44B: 0x92B4, //CJK UNIFIED IDEOGRAPH + 0xE44C: 0x92B5, //CJK UNIFIED IDEOGRAPH + 0xE44D: 0x92B6, //CJK UNIFIED IDEOGRAPH + 0xE44E: 0x92B7, //CJK UNIFIED IDEOGRAPH + 0xE44F: 0x92B8, //CJK UNIFIED IDEOGRAPH + 0xE450: 0x92B9, //CJK UNIFIED IDEOGRAPH + 0xE451: 0x92BA, //CJK UNIFIED IDEOGRAPH + 0xE452: 0x92BB, //CJK UNIFIED IDEOGRAPH + 0xE453: 0x92BC, //CJK UNIFIED IDEOGRAPH + 0xE454: 0x92BD, //CJK UNIFIED IDEOGRAPH + 0xE455: 0x92BE, //CJK UNIFIED IDEOGRAPH + 0xE456: 0x92BF, //CJK UNIFIED IDEOGRAPH + 0xE457: 0x92C0, //CJK UNIFIED IDEOGRAPH + 0xE458: 0x92C1, //CJK UNIFIED IDEOGRAPH + 0xE459: 0x92C2, //CJK UNIFIED IDEOGRAPH + 0xE45A: 0x92C3, //CJK UNIFIED IDEOGRAPH + 0xE45B: 0x92C4, //CJK UNIFIED IDEOGRAPH + 0xE45C: 0x92C5, //CJK UNIFIED IDEOGRAPH + 0xE45D: 0x92C6, //CJK UNIFIED IDEOGRAPH + 0xE45E: 0x92C7, //CJK UNIFIED IDEOGRAPH + 0xE45F: 0x92C9, //CJK UNIFIED IDEOGRAPH + 0xE460: 0x92CA, //CJK UNIFIED IDEOGRAPH + 0xE461: 0x92CB, //CJK UNIFIED IDEOGRAPH + 0xE462: 0x92CC, //CJK UNIFIED IDEOGRAPH + 0xE463: 0x92CD, //CJK UNIFIED IDEOGRAPH + 0xE464: 0x92CE, //CJK UNIFIED IDEOGRAPH + 0xE465: 0x92CF, //CJK UNIFIED IDEOGRAPH + 0xE466: 0x92D0, //CJK UNIFIED IDEOGRAPH + 0xE467: 0x92D1, //CJK UNIFIED IDEOGRAPH + 0xE468: 0x92D2, //CJK UNIFIED IDEOGRAPH + 0xE469: 0x92D3, //CJK UNIFIED IDEOGRAPH + 0xE46A: 0x92D4, //CJK UNIFIED IDEOGRAPH + 0xE46B: 0x92D5, //CJK UNIFIED IDEOGRAPH + 0xE46C: 0x92D6, //CJK UNIFIED IDEOGRAPH + 0xE46D: 0x92D7, //CJK UNIFIED IDEOGRAPH + 0xE46E: 0x92D8, //CJK UNIFIED IDEOGRAPH + 0xE46F: 0x92D9, //CJK UNIFIED IDEOGRAPH + 0xE470: 0x92DA, //CJK UNIFIED IDEOGRAPH + 0xE471: 0x92DB, //CJK UNIFIED IDEOGRAPH + 0xE472: 0x92DC, //CJK UNIFIED IDEOGRAPH + 0xE473: 0x92DD, //CJK UNIFIED IDEOGRAPH + 0xE474: 0x92DE, //CJK UNIFIED IDEOGRAPH + 0xE475: 0x92DF, //CJK UNIFIED IDEOGRAPH + 0xE476: 0x92E0, //CJK UNIFIED IDEOGRAPH + 0xE477: 0x92E1, //CJK UNIFIED IDEOGRAPH + 0xE478: 0x92E2, //CJK UNIFIED IDEOGRAPH + 0xE479: 0x92E3, //CJK UNIFIED IDEOGRAPH + 0xE47A: 0x92E4, //CJK UNIFIED IDEOGRAPH + 0xE47B: 0x92E5, //CJK UNIFIED IDEOGRAPH + 0xE47C: 0x92E6, //CJK UNIFIED IDEOGRAPH + 0xE47D: 0x92E7, //CJK UNIFIED IDEOGRAPH + 0xE47E: 0x92E8, //CJK UNIFIED IDEOGRAPH + 0xE480: 0x92E9, //CJK UNIFIED IDEOGRAPH + 0xE481: 0x92EA, //CJK UNIFIED IDEOGRAPH + 0xE482: 0x92EB, //CJK UNIFIED IDEOGRAPH + 0xE483: 0x92EC, //CJK UNIFIED IDEOGRAPH + 0xE484: 0x92ED, //CJK UNIFIED IDEOGRAPH + 0xE485: 0x92EE, //CJK UNIFIED IDEOGRAPH + 0xE486: 0x92EF, //CJK UNIFIED IDEOGRAPH + 0xE487: 0x92F0, //CJK UNIFIED IDEOGRAPH + 0xE488: 0x92F1, //CJK UNIFIED IDEOGRAPH + 0xE489: 0x92F2, //CJK UNIFIED IDEOGRAPH + 0xE48A: 0x92F3, //CJK UNIFIED IDEOGRAPH + 0xE48B: 0x92F4, //CJK UNIFIED IDEOGRAPH + 0xE48C: 0x92F5, //CJK UNIFIED IDEOGRAPH + 0xE48D: 0x92F6, //CJK UNIFIED IDEOGRAPH + 0xE48E: 0x92F7, //CJK UNIFIED IDEOGRAPH + 0xE48F: 0x92F8, //CJK UNIFIED IDEOGRAPH + 0xE490: 0x92F9, //CJK UNIFIED IDEOGRAPH + 0xE491: 0x92FA, //CJK UNIFIED IDEOGRAPH + 0xE492: 0x92FB, //CJK UNIFIED IDEOGRAPH + 0xE493: 0x92FC, //CJK UNIFIED IDEOGRAPH + 0xE494: 0x92FD, //CJK UNIFIED IDEOGRAPH + 0xE495: 0x92FE, //CJK UNIFIED IDEOGRAPH + 0xE496: 0x92FF, //CJK UNIFIED IDEOGRAPH + 0xE497: 0x9300, //CJK UNIFIED IDEOGRAPH + 0xE498: 0x9301, //CJK UNIFIED IDEOGRAPH + 0xE499: 0x9302, //CJK UNIFIED IDEOGRAPH + 0xE49A: 0x9303, //CJK UNIFIED IDEOGRAPH + 0xE49B: 0x9304, //CJK UNIFIED IDEOGRAPH + 0xE49C: 0x9305, //CJK UNIFIED IDEOGRAPH + 0xE49D: 0x9306, //CJK UNIFIED IDEOGRAPH + 0xE49E: 0x9307, //CJK UNIFIED IDEOGRAPH + 0xE49F: 0x9308, //CJK UNIFIED IDEOGRAPH + 0xE4A0: 0x9309, //CJK UNIFIED IDEOGRAPH + 0xE4A1: 0x6D39, //CJK UNIFIED IDEOGRAPH + 0xE4A2: 0x6D27, //CJK UNIFIED IDEOGRAPH + 0xE4A3: 0x6D0C, //CJK UNIFIED IDEOGRAPH + 0xE4A4: 0x6D43, //CJK UNIFIED IDEOGRAPH + 0xE4A5: 0x6D48, //CJK UNIFIED IDEOGRAPH + 0xE4A6: 0x6D07, //CJK UNIFIED IDEOGRAPH + 0xE4A7: 0x6D04, //CJK UNIFIED IDEOGRAPH + 0xE4A8: 0x6D19, //CJK UNIFIED IDEOGRAPH + 0xE4A9: 0x6D0E, //CJK UNIFIED IDEOGRAPH + 0xE4AA: 0x6D2B, //CJK UNIFIED IDEOGRAPH + 0xE4AB: 0x6D4D, //CJK UNIFIED IDEOGRAPH + 0xE4AC: 0x6D2E, //CJK UNIFIED IDEOGRAPH + 0xE4AD: 0x6D35, //CJK UNIFIED IDEOGRAPH + 0xE4AE: 0x6D1A, //CJK UNIFIED IDEOGRAPH + 0xE4AF: 0x6D4F, //CJK UNIFIED IDEOGRAPH + 0xE4B0: 0x6D52, //CJK UNIFIED IDEOGRAPH + 0xE4B1: 0x6D54, //CJK UNIFIED IDEOGRAPH + 0xE4B2: 0x6D33, //CJK UNIFIED IDEOGRAPH + 0xE4B3: 0x6D91, //CJK UNIFIED IDEOGRAPH + 0xE4B4: 0x6D6F, //CJK UNIFIED IDEOGRAPH + 0xE4B5: 0x6D9E, //CJK UNIFIED IDEOGRAPH + 0xE4B6: 0x6DA0, //CJK UNIFIED IDEOGRAPH + 0xE4B7: 0x6D5E, //CJK UNIFIED IDEOGRAPH + 0xE4B8: 0x6D93, //CJK UNIFIED IDEOGRAPH + 0xE4B9: 0x6D94, //CJK UNIFIED IDEOGRAPH + 0xE4BA: 0x6D5C, //CJK UNIFIED IDEOGRAPH + 0xE4BB: 0x6D60, //CJK UNIFIED IDEOGRAPH + 0xE4BC: 0x6D7C, //CJK UNIFIED IDEOGRAPH + 0xE4BD: 0x6D63, //CJK UNIFIED IDEOGRAPH + 0xE4BE: 0x6E1A, //CJK UNIFIED IDEOGRAPH + 0xE4BF: 0x6DC7, //CJK UNIFIED IDEOGRAPH + 0xE4C0: 0x6DC5, //CJK UNIFIED IDEOGRAPH + 0xE4C1: 0x6DDE, //CJK UNIFIED IDEOGRAPH + 0xE4C2: 0x6E0E, //CJK UNIFIED IDEOGRAPH + 0xE4C3: 0x6DBF, //CJK UNIFIED IDEOGRAPH + 0xE4C4: 0x6DE0, //CJK UNIFIED IDEOGRAPH + 0xE4C5: 0x6E11, //CJK UNIFIED IDEOGRAPH + 0xE4C6: 0x6DE6, //CJK UNIFIED IDEOGRAPH + 0xE4C7: 0x6DDD, //CJK UNIFIED IDEOGRAPH + 0xE4C8: 0x6DD9, //CJK UNIFIED IDEOGRAPH + 0xE4C9: 0x6E16, //CJK UNIFIED IDEOGRAPH + 0xE4CA: 0x6DAB, //CJK UNIFIED IDEOGRAPH + 0xE4CB: 0x6E0C, //CJK UNIFIED IDEOGRAPH + 0xE4CC: 0x6DAE, //CJK UNIFIED IDEOGRAPH + 0xE4CD: 0x6E2B, //CJK UNIFIED IDEOGRAPH + 0xE4CE: 0x6E6E, //CJK UNIFIED IDEOGRAPH + 0xE4CF: 0x6E4E, //CJK UNIFIED IDEOGRAPH + 0xE4D0: 0x6E6B, //CJK UNIFIED IDEOGRAPH + 0xE4D1: 0x6EB2, //CJK UNIFIED IDEOGRAPH + 0xE4D2: 0x6E5F, //CJK UNIFIED IDEOGRAPH + 0xE4D3: 0x6E86, //CJK UNIFIED IDEOGRAPH + 0xE4D4: 0x6E53, //CJK UNIFIED IDEOGRAPH + 0xE4D5: 0x6E54, //CJK UNIFIED IDEOGRAPH + 0xE4D6: 0x6E32, //CJK UNIFIED IDEOGRAPH + 0xE4D7: 0x6E25, //CJK UNIFIED IDEOGRAPH + 0xE4D8: 0x6E44, //CJK UNIFIED IDEOGRAPH + 0xE4D9: 0x6EDF, //CJK UNIFIED IDEOGRAPH + 0xE4DA: 0x6EB1, //CJK UNIFIED IDEOGRAPH + 0xE4DB: 0x6E98, //CJK UNIFIED IDEOGRAPH + 0xE4DC: 0x6EE0, //CJK UNIFIED IDEOGRAPH + 0xE4DD: 0x6F2D, //CJK UNIFIED IDEOGRAPH + 0xE4DE: 0x6EE2, //CJK UNIFIED IDEOGRAPH + 0xE4DF: 0x6EA5, //CJK UNIFIED IDEOGRAPH + 0xE4E0: 0x6EA7, //CJK UNIFIED IDEOGRAPH + 0xE4E1: 0x6EBD, //CJK UNIFIED IDEOGRAPH + 0xE4E2: 0x6EBB, //CJK UNIFIED IDEOGRAPH + 0xE4E3: 0x6EB7, //CJK UNIFIED IDEOGRAPH + 0xE4E4: 0x6ED7, //CJK UNIFIED IDEOGRAPH + 0xE4E5: 0x6EB4, //CJK UNIFIED IDEOGRAPH + 0xE4E6: 0x6ECF, //CJK UNIFIED IDEOGRAPH + 0xE4E7: 0x6E8F, //CJK UNIFIED IDEOGRAPH + 0xE4E8: 0x6EC2, //CJK UNIFIED IDEOGRAPH + 0xE4E9: 0x6E9F, //CJK UNIFIED IDEOGRAPH + 0xE4EA: 0x6F62, //CJK UNIFIED IDEOGRAPH + 0xE4EB: 0x6F46, //CJK UNIFIED IDEOGRAPH + 0xE4EC: 0x6F47, //CJK UNIFIED IDEOGRAPH + 0xE4ED: 0x6F24, //CJK UNIFIED IDEOGRAPH + 0xE4EE: 0x6F15, //CJK UNIFIED IDEOGRAPH + 0xE4EF: 0x6EF9, //CJK UNIFIED IDEOGRAPH + 0xE4F0: 0x6F2F, //CJK UNIFIED IDEOGRAPH + 0xE4F1: 0x6F36, //CJK UNIFIED IDEOGRAPH + 0xE4F2: 0x6F4B, //CJK UNIFIED IDEOGRAPH + 0xE4F3: 0x6F74, //CJK UNIFIED IDEOGRAPH + 0xE4F4: 0x6F2A, //CJK UNIFIED IDEOGRAPH + 0xE4F5: 0x6F09, //CJK UNIFIED IDEOGRAPH + 0xE4F6: 0x6F29, //CJK UNIFIED IDEOGRAPH + 0xE4F7: 0x6F89, //CJK UNIFIED IDEOGRAPH + 0xE4F8: 0x6F8D, //CJK UNIFIED IDEOGRAPH + 0xE4F9: 0x6F8C, //CJK UNIFIED IDEOGRAPH + 0xE4FA: 0x6F78, //CJK UNIFIED IDEOGRAPH + 0xE4FB: 0x6F72, //CJK UNIFIED IDEOGRAPH + 0xE4FC: 0x6F7C, //CJK UNIFIED IDEOGRAPH + 0xE4FD: 0x6F7A, //CJK UNIFIED IDEOGRAPH + 0xE4FE: 0x6FD1, //CJK UNIFIED IDEOGRAPH + 0xE540: 0x930A, //CJK UNIFIED IDEOGRAPH + 0xE541: 0x930B, //CJK UNIFIED IDEOGRAPH + 0xE542: 0x930C, //CJK UNIFIED IDEOGRAPH + 0xE543: 0x930D, //CJK UNIFIED IDEOGRAPH + 0xE544: 0x930E, //CJK UNIFIED IDEOGRAPH + 0xE545: 0x930F, //CJK UNIFIED IDEOGRAPH + 0xE546: 0x9310, //CJK UNIFIED IDEOGRAPH + 0xE547: 0x9311, //CJK UNIFIED IDEOGRAPH + 0xE548: 0x9312, //CJK UNIFIED IDEOGRAPH + 0xE549: 0x9313, //CJK UNIFIED IDEOGRAPH + 0xE54A: 0x9314, //CJK UNIFIED IDEOGRAPH + 0xE54B: 0x9315, //CJK UNIFIED IDEOGRAPH + 0xE54C: 0x9316, //CJK UNIFIED IDEOGRAPH + 0xE54D: 0x9317, //CJK UNIFIED IDEOGRAPH + 0xE54E: 0x9318, //CJK UNIFIED IDEOGRAPH + 0xE54F: 0x9319, //CJK UNIFIED IDEOGRAPH + 0xE550: 0x931A, //CJK UNIFIED IDEOGRAPH + 0xE551: 0x931B, //CJK UNIFIED IDEOGRAPH + 0xE552: 0x931C, //CJK UNIFIED IDEOGRAPH + 0xE553: 0x931D, //CJK UNIFIED IDEOGRAPH + 0xE554: 0x931E, //CJK UNIFIED IDEOGRAPH + 0xE555: 0x931F, //CJK UNIFIED IDEOGRAPH + 0xE556: 0x9320, //CJK UNIFIED IDEOGRAPH + 0xE557: 0x9321, //CJK UNIFIED IDEOGRAPH + 0xE558: 0x9322, //CJK UNIFIED IDEOGRAPH + 0xE559: 0x9323, //CJK UNIFIED IDEOGRAPH + 0xE55A: 0x9324, //CJK UNIFIED IDEOGRAPH + 0xE55B: 0x9325, //CJK UNIFIED IDEOGRAPH + 0xE55C: 0x9326, //CJK UNIFIED IDEOGRAPH + 0xE55D: 0x9327, //CJK UNIFIED IDEOGRAPH + 0xE55E: 0x9328, //CJK UNIFIED IDEOGRAPH + 0xE55F: 0x9329, //CJK UNIFIED IDEOGRAPH + 0xE560: 0x932A, //CJK UNIFIED IDEOGRAPH + 0xE561: 0x932B, //CJK UNIFIED IDEOGRAPH + 0xE562: 0x932C, //CJK UNIFIED IDEOGRAPH + 0xE563: 0x932D, //CJK UNIFIED IDEOGRAPH + 0xE564: 0x932E, //CJK UNIFIED IDEOGRAPH + 0xE565: 0x932F, //CJK UNIFIED IDEOGRAPH + 0xE566: 0x9330, //CJK UNIFIED IDEOGRAPH + 0xE567: 0x9331, //CJK UNIFIED IDEOGRAPH + 0xE568: 0x9332, //CJK UNIFIED IDEOGRAPH + 0xE569: 0x9333, //CJK UNIFIED IDEOGRAPH + 0xE56A: 0x9334, //CJK UNIFIED IDEOGRAPH + 0xE56B: 0x9335, //CJK UNIFIED IDEOGRAPH + 0xE56C: 0x9336, //CJK UNIFIED IDEOGRAPH + 0xE56D: 0x9337, //CJK UNIFIED IDEOGRAPH + 0xE56E: 0x9338, //CJK UNIFIED IDEOGRAPH + 0xE56F: 0x9339, //CJK UNIFIED IDEOGRAPH + 0xE570: 0x933A, //CJK UNIFIED IDEOGRAPH + 0xE571: 0x933B, //CJK UNIFIED IDEOGRAPH + 0xE572: 0x933C, //CJK UNIFIED IDEOGRAPH + 0xE573: 0x933D, //CJK UNIFIED IDEOGRAPH + 0xE574: 0x933F, //CJK UNIFIED IDEOGRAPH + 0xE575: 0x9340, //CJK UNIFIED IDEOGRAPH + 0xE576: 0x9341, //CJK UNIFIED IDEOGRAPH + 0xE577: 0x9342, //CJK UNIFIED IDEOGRAPH + 0xE578: 0x9343, //CJK UNIFIED IDEOGRAPH + 0xE579: 0x9344, //CJK UNIFIED IDEOGRAPH + 0xE57A: 0x9345, //CJK UNIFIED IDEOGRAPH + 0xE57B: 0x9346, //CJK UNIFIED IDEOGRAPH + 0xE57C: 0x9347, //CJK UNIFIED IDEOGRAPH + 0xE57D: 0x9348, //CJK UNIFIED IDEOGRAPH + 0xE57E: 0x9349, //CJK UNIFIED IDEOGRAPH + 0xE580: 0x934A, //CJK UNIFIED IDEOGRAPH + 0xE581: 0x934B, //CJK UNIFIED IDEOGRAPH + 0xE582: 0x934C, //CJK UNIFIED IDEOGRAPH + 0xE583: 0x934D, //CJK UNIFIED IDEOGRAPH + 0xE584: 0x934E, //CJK UNIFIED IDEOGRAPH + 0xE585: 0x934F, //CJK UNIFIED IDEOGRAPH + 0xE586: 0x9350, //CJK UNIFIED IDEOGRAPH + 0xE587: 0x9351, //CJK UNIFIED IDEOGRAPH + 0xE588: 0x9352, //CJK UNIFIED IDEOGRAPH + 0xE589: 0x9353, //CJK UNIFIED IDEOGRAPH + 0xE58A: 0x9354, //CJK UNIFIED IDEOGRAPH + 0xE58B: 0x9355, //CJK UNIFIED IDEOGRAPH + 0xE58C: 0x9356, //CJK UNIFIED IDEOGRAPH + 0xE58D: 0x9357, //CJK UNIFIED IDEOGRAPH + 0xE58E: 0x9358, //CJK UNIFIED IDEOGRAPH + 0xE58F: 0x9359, //CJK UNIFIED IDEOGRAPH + 0xE590: 0x935A, //CJK UNIFIED IDEOGRAPH + 0xE591: 0x935B, //CJK UNIFIED IDEOGRAPH + 0xE592: 0x935C, //CJK UNIFIED IDEOGRAPH + 0xE593: 0x935D, //CJK UNIFIED IDEOGRAPH + 0xE594: 0x935E, //CJK UNIFIED IDEOGRAPH + 0xE595: 0x935F, //CJK UNIFIED IDEOGRAPH + 0xE596: 0x9360, //CJK UNIFIED IDEOGRAPH + 0xE597: 0x9361, //CJK UNIFIED IDEOGRAPH + 0xE598: 0x9362, //CJK UNIFIED IDEOGRAPH + 0xE599: 0x9363, //CJK UNIFIED IDEOGRAPH + 0xE59A: 0x9364, //CJK UNIFIED IDEOGRAPH + 0xE59B: 0x9365, //CJK UNIFIED IDEOGRAPH + 0xE59C: 0x9366, //CJK UNIFIED IDEOGRAPH + 0xE59D: 0x9367, //CJK UNIFIED IDEOGRAPH + 0xE59E: 0x9368, //CJK UNIFIED IDEOGRAPH + 0xE59F: 0x9369, //CJK UNIFIED IDEOGRAPH + 0xE5A0: 0x936B, //CJK UNIFIED IDEOGRAPH + 0xE5A1: 0x6FC9, //CJK UNIFIED IDEOGRAPH + 0xE5A2: 0x6FA7, //CJK UNIFIED IDEOGRAPH + 0xE5A3: 0x6FB9, //CJK UNIFIED IDEOGRAPH + 0xE5A4: 0x6FB6, //CJK UNIFIED IDEOGRAPH + 0xE5A5: 0x6FC2, //CJK UNIFIED IDEOGRAPH + 0xE5A6: 0x6FE1, //CJK UNIFIED IDEOGRAPH + 0xE5A7: 0x6FEE, //CJK UNIFIED IDEOGRAPH + 0xE5A8: 0x6FDE, //CJK UNIFIED IDEOGRAPH + 0xE5A9: 0x6FE0, //CJK UNIFIED IDEOGRAPH + 0xE5AA: 0x6FEF, //CJK UNIFIED IDEOGRAPH + 0xE5AB: 0x701A, //CJK UNIFIED IDEOGRAPH + 0xE5AC: 0x7023, //CJK UNIFIED IDEOGRAPH + 0xE5AD: 0x701B, //CJK UNIFIED IDEOGRAPH + 0xE5AE: 0x7039, //CJK UNIFIED IDEOGRAPH + 0xE5AF: 0x7035, //CJK UNIFIED IDEOGRAPH + 0xE5B0: 0x704F, //CJK UNIFIED IDEOGRAPH + 0xE5B1: 0x705E, //CJK UNIFIED IDEOGRAPH + 0xE5B2: 0x5B80, //CJK UNIFIED IDEOGRAPH + 0xE5B3: 0x5B84, //CJK UNIFIED IDEOGRAPH + 0xE5B4: 0x5B95, //CJK UNIFIED IDEOGRAPH + 0xE5B5: 0x5B93, //CJK UNIFIED IDEOGRAPH + 0xE5B6: 0x5BA5, //CJK UNIFIED IDEOGRAPH + 0xE5B7: 0x5BB8, //CJK UNIFIED IDEOGRAPH + 0xE5B8: 0x752F, //CJK UNIFIED IDEOGRAPH + 0xE5B9: 0x9A9E, //CJK UNIFIED IDEOGRAPH + 0xE5BA: 0x6434, //CJK UNIFIED IDEOGRAPH + 0xE5BB: 0x5BE4, //CJK UNIFIED IDEOGRAPH + 0xE5BC: 0x5BEE, //CJK UNIFIED IDEOGRAPH + 0xE5BD: 0x8930, //CJK UNIFIED IDEOGRAPH + 0xE5BE: 0x5BF0, //CJK UNIFIED IDEOGRAPH + 0xE5BF: 0x8E47, //CJK UNIFIED IDEOGRAPH + 0xE5C0: 0x8B07, //CJK UNIFIED IDEOGRAPH + 0xE5C1: 0x8FB6, //CJK UNIFIED IDEOGRAPH + 0xE5C2: 0x8FD3, //CJK UNIFIED IDEOGRAPH + 0xE5C3: 0x8FD5, //CJK UNIFIED IDEOGRAPH + 0xE5C4: 0x8FE5, //CJK UNIFIED IDEOGRAPH + 0xE5C5: 0x8FEE, //CJK UNIFIED IDEOGRAPH + 0xE5C6: 0x8FE4, //CJK UNIFIED IDEOGRAPH + 0xE5C7: 0x8FE9, //CJK UNIFIED IDEOGRAPH + 0xE5C8: 0x8FE6, //CJK UNIFIED IDEOGRAPH + 0xE5C9: 0x8FF3, //CJK UNIFIED IDEOGRAPH + 0xE5CA: 0x8FE8, //CJK UNIFIED IDEOGRAPH + 0xE5CB: 0x9005, //CJK UNIFIED IDEOGRAPH + 0xE5CC: 0x9004, //CJK UNIFIED IDEOGRAPH + 0xE5CD: 0x900B, //CJK UNIFIED IDEOGRAPH + 0xE5CE: 0x9026, //CJK UNIFIED IDEOGRAPH + 0xE5CF: 0x9011, //CJK UNIFIED IDEOGRAPH + 0xE5D0: 0x900D, //CJK UNIFIED IDEOGRAPH + 0xE5D1: 0x9016, //CJK UNIFIED IDEOGRAPH + 0xE5D2: 0x9021, //CJK UNIFIED IDEOGRAPH + 0xE5D3: 0x9035, //CJK UNIFIED IDEOGRAPH + 0xE5D4: 0x9036, //CJK UNIFIED IDEOGRAPH + 0xE5D5: 0x902D, //CJK UNIFIED IDEOGRAPH + 0xE5D6: 0x902F, //CJK UNIFIED IDEOGRAPH + 0xE5D7: 0x9044, //CJK UNIFIED IDEOGRAPH + 0xE5D8: 0x9051, //CJK UNIFIED IDEOGRAPH + 0xE5D9: 0x9052, //CJK UNIFIED IDEOGRAPH + 0xE5DA: 0x9050, //CJK UNIFIED IDEOGRAPH + 0xE5DB: 0x9068, //CJK UNIFIED IDEOGRAPH + 0xE5DC: 0x9058, //CJK UNIFIED IDEOGRAPH + 0xE5DD: 0x9062, //CJK UNIFIED IDEOGRAPH + 0xE5DE: 0x905B, //CJK UNIFIED IDEOGRAPH + 0xE5DF: 0x66B9, //CJK UNIFIED IDEOGRAPH + 0xE5E0: 0x9074, //CJK UNIFIED IDEOGRAPH + 0xE5E1: 0x907D, //CJK UNIFIED IDEOGRAPH + 0xE5E2: 0x9082, //CJK UNIFIED IDEOGRAPH + 0xE5E3: 0x9088, //CJK UNIFIED IDEOGRAPH + 0xE5E4: 0x9083, //CJK UNIFIED IDEOGRAPH + 0xE5E5: 0x908B, //CJK UNIFIED IDEOGRAPH + 0xE5E6: 0x5F50, //CJK UNIFIED IDEOGRAPH + 0xE5E7: 0x5F57, //CJK UNIFIED IDEOGRAPH + 0xE5E8: 0x5F56, //CJK UNIFIED IDEOGRAPH + 0xE5E9: 0x5F58, //CJK UNIFIED IDEOGRAPH + 0xE5EA: 0x5C3B, //CJK UNIFIED IDEOGRAPH + 0xE5EB: 0x54AB, //CJK UNIFIED IDEOGRAPH + 0xE5EC: 0x5C50, //CJK UNIFIED IDEOGRAPH + 0xE5ED: 0x5C59, //CJK UNIFIED IDEOGRAPH + 0xE5EE: 0x5B71, //CJK UNIFIED IDEOGRAPH + 0xE5EF: 0x5C63, //CJK UNIFIED IDEOGRAPH + 0xE5F0: 0x5C66, //CJK UNIFIED IDEOGRAPH + 0xE5F1: 0x7FBC, //CJK UNIFIED IDEOGRAPH + 0xE5F2: 0x5F2A, //CJK UNIFIED IDEOGRAPH + 0xE5F3: 0x5F29, //CJK UNIFIED IDEOGRAPH + 0xE5F4: 0x5F2D, //CJK UNIFIED IDEOGRAPH + 0xE5F5: 0x8274, //CJK UNIFIED IDEOGRAPH + 0xE5F6: 0x5F3C, //CJK UNIFIED IDEOGRAPH + 0xE5F7: 0x9B3B, //CJK UNIFIED IDEOGRAPH + 0xE5F8: 0x5C6E, //CJK UNIFIED IDEOGRAPH + 0xE5F9: 0x5981, //CJK UNIFIED IDEOGRAPH + 0xE5FA: 0x5983, //CJK UNIFIED IDEOGRAPH + 0xE5FB: 0x598D, //CJK UNIFIED IDEOGRAPH + 0xE5FC: 0x59A9, //CJK UNIFIED IDEOGRAPH + 0xE5FD: 0x59AA, //CJK UNIFIED IDEOGRAPH + 0xE5FE: 0x59A3, //CJK UNIFIED IDEOGRAPH + 0xE640: 0x936C, //CJK UNIFIED IDEOGRAPH + 0xE641: 0x936D, //CJK UNIFIED IDEOGRAPH + 0xE642: 0x936E, //CJK UNIFIED IDEOGRAPH + 0xE643: 0x936F, //CJK UNIFIED IDEOGRAPH + 0xE644: 0x9370, //CJK UNIFIED IDEOGRAPH + 0xE645: 0x9371, //CJK UNIFIED IDEOGRAPH + 0xE646: 0x9372, //CJK UNIFIED IDEOGRAPH + 0xE647: 0x9373, //CJK UNIFIED IDEOGRAPH + 0xE648: 0x9374, //CJK UNIFIED IDEOGRAPH + 0xE649: 0x9375, //CJK UNIFIED IDEOGRAPH + 0xE64A: 0x9376, //CJK UNIFIED IDEOGRAPH + 0xE64B: 0x9377, //CJK UNIFIED IDEOGRAPH + 0xE64C: 0x9378, //CJK UNIFIED IDEOGRAPH + 0xE64D: 0x9379, //CJK UNIFIED IDEOGRAPH + 0xE64E: 0x937A, //CJK UNIFIED IDEOGRAPH + 0xE64F: 0x937B, //CJK UNIFIED IDEOGRAPH + 0xE650: 0x937C, //CJK UNIFIED IDEOGRAPH + 0xE651: 0x937D, //CJK UNIFIED IDEOGRAPH + 0xE652: 0x937E, //CJK UNIFIED IDEOGRAPH + 0xE653: 0x937F, //CJK UNIFIED IDEOGRAPH + 0xE654: 0x9380, //CJK UNIFIED IDEOGRAPH + 0xE655: 0x9381, //CJK UNIFIED IDEOGRAPH + 0xE656: 0x9382, //CJK UNIFIED IDEOGRAPH + 0xE657: 0x9383, //CJK UNIFIED IDEOGRAPH + 0xE658: 0x9384, //CJK UNIFIED IDEOGRAPH + 0xE659: 0x9385, //CJK UNIFIED IDEOGRAPH + 0xE65A: 0x9386, //CJK UNIFIED IDEOGRAPH + 0xE65B: 0x9387, //CJK UNIFIED IDEOGRAPH + 0xE65C: 0x9388, //CJK UNIFIED IDEOGRAPH + 0xE65D: 0x9389, //CJK UNIFIED IDEOGRAPH + 0xE65E: 0x938A, //CJK UNIFIED IDEOGRAPH + 0xE65F: 0x938B, //CJK UNIFIED IDEOGRAPH + 0xE660: 0x938C, //CJK UNIFIED IDEOGRAPH + 0xE661: 0x938D, //CJK UNIFIED IDEOGRAPH + 0xE662: 0x938E, //CJK UNIFIED IDEOGRAPH + 0xE663: 0x9390, //CJK UNIFIED IDEOGRAPH + 0xE664: 0x9391, //CJK UNIFIED IDEOGRAPH + 0xE665: 0x9392, //CJK UNIFIED IDEOGRAPH + 0xE666: 0x9393, //CJK UNIFIED IDEOGRAPH + 0xE667: 0x9394, //CJK UNIFIED IDEOGRAPH + 0xE668: 0x9395, //CJK UNIFIED IDEOGRAPH + 0xE669: 0x9396, //CJK UNIFIED IDEOGRAPH + 0xE66A: 0x9397, //CJK UNIFIED IDEOGRAPH + 0xE66B: 0x9398, //CJK UNIFIED IDEOGRAPH + 0xE66C: 0x9399, //CJK UNIFIED IDEOGRAPH + 0xE66D: 0x939A, //CJK UNIFIED IDEOGRAPH + 0xE66E: 0x939B, //CJK UNIFIED IDEOGRAPH + 0xE66F: 0x939C, //CJK UNIFIED IDEOGRAPH + 0xE670: 0x939D, //CJK UNIFIED IDEOGRAPH + 0xE671: 0x939E, //CJK UNIFIED IDEOGRAPH + 0xE672: 0x939F, //CJK UNIFIED IDEOGRAPH + 0xE673: 0x93A0, //CJK UNIFIED IDEOGRAPH + 0xE674: 0x93A1, //CJK UNIFIED IDEOGRAPH + 0xE675: 0x93A2, //CJK UNIFIED IDEOGRAPH + 0xE676: 0x93A3, //CJK UNIFIED IDEOGRAPH + 0xE677: 0x93A4, //CJK UNIFIED IDEOGRAPH + 0xE678: 0x93A5, //CJK UNIFIED IDEOGRAPH + 0xE679: 0x93A6, //CJK UNIFIED IDEOGRAPH + 0xE67A: 0x93A7, //CJK UNIFIED IDEOGRAPH + 0xE67B: 0x93A8, //CJK UNIFIED IDEOGRAPH + 0xE67C: 0x93A9, //CJK UNIFIED IDEOGRAPH + 0xE67D: 0x93AA, //CJK UNIFIED IDEOGRAPH + 0xE67E: 0x93AB, //CJK UNIFIED IDEOGRAPH + 0xE680: 0x93AC, //CJK UNIFIED IDEOGRAPH + 0xE681: 0x93AD, //CJK UNIFIED IDEOGRAPH + 0xE682: 0x93AE, //CJK UNIFIED IDEOGRAPH + 0xE683: 0x93AF, //CJK UNIFIED IDEOGRAPH + 0xE684: 0x93B0, //CJK UNIFIED IDEOGRAPH + 0xE685: 0x93B1, //CJK UNIFIED IDEOGRAPH + 0xE686: 0x93B2, //CJK UNIFIED IDEOGRAPH + 0xE687: 0x93B3, //CJK UNIFIED IDEOGRAPH + 0xE688: 0x93B4, //CJK UNIFIED IDEOGRAPH + 0xE689: 0x93B5, //CJK UNIFIED IDEOGRAPH + 0xE68A: 0x93B6, //CJK UNIFIED IDEOGRAPH + 0xE68B: 0x93B7, //CJK UNIFIED IDEOGRAPH + 0xE68C: 0x93B8, //CJK UNIFIED IDEOGRAPH + 0xE68D: 0x93B9, //CJK UNIFIED IDEOGRAPH + 0xE68E: 0x93BA, //CJK UNIFIED IDEOGRAPH + 0xE68F: 0x93BB, //CJK UNIFIED IDEOGRAPH + 0xE690: 0x93BC, //CJK UNIFIED IDEOGRAPH + 0xE691: 0x93BD, //CJK UNIFIED IDEOGRAPH + 0xE692: 0x93BE, //CJK UNIFIED IDEOGRAPH + 0xE693: 0x93BF, //CJK UNIFIED IDEOGRAPH + 0xE694: 0x93C0, //CJK UNIFIED IDEOGRAPH + 0xE695: 0x93C1, //CJK UNIFIED IDEOGRAPH + 0xE696: 0x93C2, //CJK UNIFIED IDEOGRAPH + 0xE697: 0x93C3, //CJK UNIFIED IDEOGRAPH + 0xE698: 0x93C4, //CJK UNIFIED IDEOGRAPH + 0xE699: 0x93C5, //CJK UNIFIED IDEOGRAPH + 0xE69A: 0x93C6, //CJK UNIFIED IDEOGRAPH + 0xE69B: 0x93C7, //CJK UNIFIED IDEOGRAPH + 0xE69C: 0x93C8, //CJK UNIFIED IDEOGRAPH + 0xE69D: 0x93C9, //CJK UNIFIED IDEOGRAPH + 0xE69E: 0x93CB, //CJK UNIFIED IDEOGRAPH + 0xE69F: 0x93CC, //CJK UNIFIED IDEOGRAPH + 0xE6A0: 0x93CD, //CJK UNIFIED IDEOGRAPH + 0xE6A1: 0x5997, //CJK UNIFIED IDEOGRAPH + 0xE6A2: 0x59CA, //CJK UNIFIED IDEOGRAPH + 0xE6A3: 0x59AB, //CJK UNIFIED IDEOGRAPH + 0xE6A4: 0x599E, //CJK UNIFIED IDEOGRAPH + 0xE6A5: 0x59A4, //CJK UNIFIED IDEOGRAPH + 0xE6A6: 0x59D2, //CJK UNIFIED IDEOGRAPH + 0xE6A7: 0x59B2, //CJK UNIFIED IDEOGRAPH + 0xE6A8: 0x59AF, //CJK UNIFIED IDEOGRAPH + 0xE6A9: 0x59D7, //CJK UNIFIED IDEOGRAPH + 0xE6AA: 0x59BE, //CJK UNIFIED IDEOGRAPH + 0xE6AB: 0x5A05, //CJK UNIFIED IDEOGRAPH + 0xE6AC: 0x5A06, //CJK UNIFIED IDEOGRAPH + 0xE6AD: 0x59DD, //CJK UNIFIED IDEOGRAPH + 0xE6AE: 0x5A08, //CJK UNIFIED IDEOGRAPH + 0xE6AF: 0x59E3, //CJK UNIFIED IDEOGRAPH + 0xE6B0: 0x59D8, //CJK UNIFIED IDEOGRAPH + 0xE6B1: 0x59F9, //CJK UNIFIED IDEOGRAPH + 0xE6B2: 0x5A0C, //CJK UNIFIED IDEOGRAPH + 0xE6B3: 0x5A09, //CJK UNIFIED IDEOGRAPH + 0xE6B4: 0x5A32, //CJK UNIFIED IDEOGRAPH + 0xE6B5: 0x5A34, //CJK UNIFIED IDEOGRAPH + 0xE6B6: 0x5A11, //CJK UNIFIED IDEOGRAPH + 0xE6B7: 0x5A23, //CJK UNIFIED IDEOGRAPH + 0xE6B8: 0x5A13, //CJK UNIFIED IDEOGRAPH + 0xE6B9: 0x5A40, //CJK UNIFIED IDEOGRAPH + 0xE6BA: 0x5A67, //CJK UNIFIED IDEOGRAPH + 0xE6BB: 0x5A4A, //CJK UNIFIED IDEOGRAPH + 0xE6BC: 0x5A55, //CJK UNIFIED IDEOGRAPH + 0xE6BD: 0x5A3C, //CJK UNIFIED IDEOGRAPH + 0xE6BE: 0x5A62, //CJK UNIFIED IDEOGRAPH + 0xE6BF: 0x5A75, //CJK UNIFIED IDEOGRAPH + 0xE6C0: 0x80EC, //CJK UNIFIED IDEOGRAPH + 0xE6C1: 0x5AAA, //CJK UNIFIED IDEOGRAPH + 0xE6C2: 0x5A9B, //CJK UNIFIED IDEOGRAPH + 0xE6C3: 0x5A77, //CJK UNIFIED IDEOGRAPH + 0xE6C4: 0x5A7A, //CJK UNIFIED IDEOGRAPH + 0xE6C5: 0x5ABE, //CJK UNIFIED IDEOGRAPH + 0xE6C6: 0x5AEB, //CJK UNIFIED IDEOGRAPH + 0xE6C7: 0x5AB2, //CJK UNIFIED IDEOGRAPH + 0xE6C8: 0x5AD2, //CJK UNIFIED IDEOGRAPH + 0xE6C9: 0x5AD4, //CJK UNIFIED IDEOGRAPH + 0xE6CA: 0x5AB8, //CJK UNIFIED IDEOGRAPH + 0xE6CB: 0x5AE0, //CJK UNIFIED IDEOGRAPH + 0xE6CC: 0x5AE3, //CJK UNIFIED IDEOGRAPH + 0xE6CD: 0x5AF1, //CJK UNIFIED IDEOGRAPH + 0xE6CE: 0x5AD6, //CJK UNIFIED IDEOGRAPH + 0xE6CF: 0x5AE6, //CJK UNIFIED IDEOGRAPH + 0xE6D0: 0x5AD8, //CJK UNIFIED IDEOGRAPH + 0xE6D1: 0x5ADC, //CJK UNIFIED IDEOGRAPH + 0xE6D2: 0x5B09, //CJK UNIFIED IDEOGRAPH + 0xE6D3: 0x5B17, //CJK UNIFIED IDEOGRAPH + 0xE6D4: 0x5B16, //CJK UNIFIED IDEOGRAPH + 0xE6D5: 0x5B32, //CJK UNIFIED IDEOGRAPH + 0xE6D6: 0x5B37, //CJK UNIFIED IDEOGRAPH + 0xE6D7: 0x5B40, //CJK UNIFIED IDEOGRAPH + 0xE6D8: 0x5C15, //CJK UNIFIED IDEOGRAPH + 0xE6D9: 0x5C1C, //CJK UNIFIED IDEOGRAPH + 0xE6DA: 0x5B5A, //CJK UNIFIED IDEOGRAPH + 0xE6DB: 0x5B65, //CJK UNIFIED IDEOGRAPH + 0xE6DC: 0x5B73, //CJK UNIFIED IDEOGRAPH + 0xE6DD: 0x5B51, //CJK UNIFIED IDEOGRAPH + 0xE6DE: 0x5B53, //CJK UNIFIED IDEOGRAPH + 0xE6DF: 0x5B62, //CJK UNIFIED IDEOGRAPH + 0xE6E0: 0x9A75, //CJK UNIFIED IDEOGRAPH + 0xE6E1: 0x9A77, //CJK UNIFIED IDEOGRAPH + 0xE6E2: 0x9A78, //CJK UNIFIED IDEOGRAPH + 0xE6E3: 0x9A7A, //CJK UNIFIED IDEOGRAPH + 0xE6E4: 0x9A7F, //CJK UNIFIED IDEOGRAPH + 0xE6E5: 0x9A7D, //CJK UNIFIED IDEOGRAPH + 0xE6E6: 0x9A80, //CJK UNIFIED IDEOGRAPH + 0xE6E7: 0x9A81, //CJK UNIFIED IDEOGRAPH + 0xE6E8: 0x9A85, //CJK UNIFIED IDEOGRAPH + 0xE6E9: 0x9A88, //CJK UNIFIED IDEOGRAPH + 0xE6EA: 0x9A8A, //CJK UNIFIED IDEOGRAPH + 0xE6EB: 0x9A90, //CJK UNIFIED IDEOGRAPH + 0xE6EC: 0x9A92, //CJK UNIFIED IDEOGRAPH + 0xE6ED: 0x9A93, //CJK UNIFIED IDEOGRAPH + 0xE6EE: 0x9A96, //CJK UNIFIED IDEOGRAPH + 0xE6EF: 0x9A98, //CJK UNIFIED IDEOGRAPH + 0xE6F0: 0x9A9B, //CJK UNIFIED IDEOGRAPH + 0xE6F1: 0x9A9C, //CJK UNIFIED IDEOGRAPH + 0xE6F2: 0x9A9D, //CJK UNIFIED IDEOGRAPH + 0xE6F3: 0x9A9F, //CJK UNIFIED IDEOGRAPH + 0xE6F4: 0x9AA0, //CJK UNIFIED IDEOGRAPH + 0xE6F5: 0x9AA2, //CJK UNIFIED IDEOGRAPH + 0xE6F6: 0x9AA3, //CJK UNIFIED IDEOGRAPH + 0xE6F7: 0x9AA5, //CJK UNIFIED IDEOGRAPH + 0xE6F8: 0x9AA7, //CJK UNIFIED IDEOGRAPH + 0xE6F9: 0x7E9F, //CJK UNIFIED IDEOGRAPH + 0xE6FA: 0x7EA1, //CJK UNIFIED IDEOGRAPH + 0xE6FB: 0x7EA3, //CJK UNIFIED IDEOGRAPH + 0xE6FC: 0x7EA5, //CJK UNIFIED IDEOGRAPH + 0xE6FD: 0x7EA8, //CJK UNIFIED IDEOGRAPH + 0xE6FE: 0x7EA9, //CJK UNIFIED IDEOGRAPH + 0xE740: 0x93CE, //CJK UNIFIED IDEOGRAPH + 0xE741: 0x93CF, //CJK UNIFIED IDEOGRAPH + 0xE742: 0x93D0, //CJK UNIFIED IDEOGRAPH + 0xE743: 0x93D1, //CJK UNIFIED IDEOGRAPH + 0xE744: 0x93D2, //CJK UNIFIED IDEOGRAPH + 0xE745: 0x93D3, //CJK UNIFIED IDEOGRAPH + 0xE746: 0x93D4, //CJK UNIFIED IDEOGRAPH + 0xE747: 0x93D5, //CJK UNIFIED IDEOGRAPH + 0xE748: 0x93D7, //CJK UNIFIED IDEOGRAPH + 0xE749: 0x93D8, //CJK UNIFIED IDEOGRAPH + 0xE74A: 0x93D9, //CJK UNIFIED IDEOGRAPH + 0xE74B: 0x93DA, //CJK UNIFIED IDEOGRAPH + 0xE74C: 0x93DB, //CJK UNIFIED IDEOGRAPH + 0xE74D: 0x93DC, //CJK UNIFIED IDEOGRAPH + 0xE74E: 0x93DD, //CJK UNIFIED IDEOGRAPH + 0xE74F: 0x93DE, //CJK UNIFIED IDEOGRAPH + 0xE750: 0x93DF, //CJK UNIFIED IDEOGRAPH + 0xE751: 0x93E0, //CJK UNIFIED IDEOGRAPH + 0xE752: 0x93E1, //CJK UNIFIED IDEOGRAPH + 0xE753: 0x93E2, //CJK UNIFIED IDEOGRAPH + 0xE754: 0x93E3, //CJK UNIFIED IDEOGRAPH + 0xE755: 0x93E4, //CJK UNIFIED IDEOGRAPH + 0xE756: 0x93E5, //CJK UNIFIED IDEOGRAPH + 0xE757: 0x93E6, //CJK UNIFIED IDEOGRAPH + 0xE758: 0x93E7, //CJK UNIFIED IDEOGRAPH + 0xE759: 0x93E8, //CJK UNIFIED IDEOGRAPH + 0xE75A: 0x93E9, //CJK UNIFIED IDEOGRAPH + 0xE75B: 0x93EA, //CJK UNIFIED IDEOGRAPH + 0xE75C: 0x93EB, //CJK UNIFIED IDEOGRAPH + 0xE75D: 0x93EC, //CJK UNIFIED IDEOGRAPH + 0xE75E: 0x93ED, //CJK UNIFIED IDEOGRAPH + 0xE75F: 0x93EE, //CJK UNIFIED IDEOGRAPH + 0xE760: 0x93EF, //CJK UNIFIED IDEOGRAPH + 0xE761: 0x93F0, //CJK UNIFIED IDEOGRAPH + 0xE762: 0x93F1, //CJK UNIFIED IDEOGRAPH + 0xE763: 0x93F2, //CJK UNIFIED IDEOGRAPH + 0xE764: 0x93F3, //CJK UNIFIED IDEOGRAPH + 0xE765: 0x93F4, //CJK UNIFIED IDEOGRAPH + 0xE766: 0x93F5, //CJK UNIFIED IDEOGRAPH + 0xE767: 0x93F6, //CJK UNIFIED IDEOGRAPH + 0xE768: 0x93F7, //CJK UNIFIED IDEOGRAPH + 0xE769: 0x93F8, //CJK UNIFIED IDEOGRAPH + 0xE76A: 0x93F9, //CJK UNIFIED IDEOGRAPH + 0xE76B: 0x93FA, //CJK UNIFIED IDEOGRAPH + 0xE76C: 0x93FB, //CJK UNIFIED IDEOGRAPH + 0xE76D: 0x93FC, //CJK UNIFIED IDEOGRAPH + 0xE76E: 0x93FD, //CJK UNIFIED IDEOGRAPH + 0xE76F: 0x93FE, //CJK UNIFIED IDEOGRAPH + 0xE770: 0x93FF, //CJK UNIFIED IDEOGRAPH + 0xE771: 0x9400, //CJK UNIFIED IDEOGRAPH + 0xE772: 0x9401, //CJK UNIFIED IDEOGRAPH + 0xE773: 0x9402, //CJK UNIFIED IDEOGRAPH + 0xE774: 0x9403, //CJK UNIFIED IDEOGRAPH + 0xE775: 0x9404, //CJK UNIFIED IDEOGRAPH + 0xE776: 0x9405, //CJK UNIFIED IDEOGRAPH + 0xE777: 0x9406, //CJK UNIFIED IDEOGRAPH + 0xE778: 0x9407, //CJK UNIFIED IDEOGRAPH + 0xE779: 0x9408, //CJK UNIFIED IDEOGRAPH + 0xE77A: 0x9409, //CJK UNIFIED IDEOGRAPH + 0xE77B: 0x940A, //CJK UNIFIED IDEOGRAPH + 0xE77C: 0x940B, //CJK UNIFIED IDEOGRAPH + 0xE77D: 0x940C, //CJK UNIFIED IDEOGRAPH + 0xE77E: 0x940D, //CJK UNIFIED IDEOGRAPH + 0xE780: 0x940E, //CJK UNIFIED IDEOGRAPH + 0xE781: 0x940F, //CJK UNIFIED IDEOGRAPH + 0xE782: 0x9410, //CJK UNIFIED IDEOGRAPH + 0xE783: 0x9411, //CJK UNIFIED IDEOGRAPH + 0xE784: 0x9412, //CJK UNIFIED IDEOGRAPH + 0xE785: 0x9413, //CJK UNIFIED IDEOGRAPH + 0xE786: 0x9414, //CJK UNIFIED IDEOGRAPH + 0xE787: 0x9415, //CJK UNIFIED IDEOGRAPH + 0xE788: 0x9416, //CJK UNIFIED IDEOGRAPH + 0xE789: 0x9417, //CJK UNIFIED IDEOGRAPH + 0xE78A: 0x9418, //CJK UNIFIED IDEOGRAPH + 0xE78B: 0x9419, //CJK UNIFIED IDEOGRAPH + 0xE78C: 0x941A, //CJK UNIFIED IDEOGRAPH + 0xE78D: 0x941B, //CJK UNIFIED IDEOGRAPH + 0xE78E: 0x941C, //CJK UNIFIED IDEOGRAPH + 0xE78F: 0x941D, //CJK UNIFIED IDEOGRAPH + 0xE790: 0x941E, //CJK UNIFIED IDEOGRAPH + 0xE791: 0x941F, //CJK UNIFIED IDEOGRAPH + 0xE792: 0x9420, //CJK UNIFIED IDEOGRAPH + 0xE793: 0x9421, //CJK UNIFIED IDEOGRAPH + 0xE794: 0x9422, //CJK UNIFIED IDEOGRAPH + 0xE795: 0x9423, //CJK UNIFIED IDEOGRAPH + 0xE796: 0x9424, //CJK UNIFIED IDEOGRAPH + 0xE797: 0x9425, //CJK UNIFIED IDEOGRAPH + 0xE798: 0x9426, //CJK UNIFIED IDEOGRAPH + 0xE799: 0x9427, //CJK UNIFIED IDEOGRAPH + 0xE79A: 0x9428, //CJK UNIFIED IDEOGRAPH + 0xE79B: 0x9429, //CJK UNIFIED IDEOGRAPH + 0xE79C: 0x942A, //CJK UNIFIED IDEOGRAPH + 0xE79D: 0x942B, //CJK UNIFIED IDEOGRAPH + 0xE79E: 0x942C, //CJK UNIFIED IDEOGRAPH + 0xE79F: 0x942D, //CJK UNIFIED IDEOGRAPH + 0xE7A0: 0x942E, //CJK UNIFIED IDEOGRAPH + 0xE7A1: 0x7EAD, //CJK UNIFIED IDEOGRAPH + 0xE7A2: 0x7EB0, //CJK UNIFIED IDEOGRAPH + 0xE7A3: 0x7EBE, //CJK UNIFIED IDEOGRAPH + 0xE7A4: 0x7EC0, //CJK UNIFIED IDEOGRAPH + 0xE7A5: 0x7EC1, //CJK UNIFIED IDEOGRAPH + 0xE7A6: 0x7EC2, //CJK UNIFIED IDEOGRAPH + 0xE7A7: 0x7EC9, //CJK UNIFIED IDEOGRAPH + 0xE7A8: 0x7ECB, //CJK UNIFIED IDEOGRAPH + 0xE7A9: 0x7ECC, //CJK UNIFIED IDEOGRAPH + 0xE7AA: 0x7ED0, //CJK UNIFIED IDEOGRAPH + 0xE7AB: 0x7ED4, //CJK UNIFIED IDEOGRAPH + 0xE7AC: 0x7ED7, //CJK UNIFIED IDEOGRAPH + 0xE7AD: 0x7EDB, //CJK UNIFIED IDEOGRAPH + 0xE7AE: 0x7EE0, //CJK UNIFIED IDEOGRAPH + 0xE7AF: 0x7EE1, //CJK UNIFIED IDEOGRAPH + 0xE7B0: 0x7EE8, //CJK UNIFIED IDEOGRAPH + 0xE7B1: 0x7EEB, //CJK UNIFIED IDEOGRAPH + 0xE7B2: 0x7EEE, //CJK UNIFIED IDEOGRAPH + 0xE7B3: 0x7EEF, //CJK UNIFIED IDEOGRAPH + 0xE7B4: 0x7EF1, //CJK UNIFIED IDEOGRAPH + 0xE7B5: 0x7EF2, //CJK UNIFIED IDEOGRAPH + 0xE7B6: 0x7F0D, //CJK UNIFIED IDEOGRAPH + 0xE7B7: 0x7EF6, //CJK UNIFIED IDEOGRAPH + 0xE7B8: 0x7EFA, //CJK UNIFIED IDEOGRAPH + 0xE7B9: 0x7EFB, //CJK UNIFIED IDEOGRAPH + 0xE7BA: 0x7EFE, //CJK UNIFIED IDEOGRAPH + 0xE7BB: 0x7F01, //CJK UNIFIED IDEOGRAPH + 0xE7BC: 0x7F02, //CJK UNIFIED IDEOGRAPH + 0xE7BD: 0x7F03, //CJK UNIFIED IDEOGRAPH + 0xE7BE: 0x7F07, //CJK UNIFIED IDEOGRAPH + 0xE7BF: 0x7F08, //CJK UNIFIED IDEOGRAPH + 0xE7C0: 0x7F0B, //CJK UNIFIED IDEOGRAPH + 0xE7C1: 0x7F0C, //CJK UNIFIED IDEOGRAPH + 0xE7C2: 0x7F0F, //CJK UNIFIED IDEOGRAPH + 0xE7C3: 0x7F11, //CJK UNIFIED IDEOGRAPH + 0xE7C4: 0x7F12, //CJK UNIFIED IDEOGRAPH + 0xE7C5: 0x7F17, //CJK UNIFIED IDEOGRAPH + 0xE7C6: 0x7F19, //CJK UNIFIED IDEOGRAPH + 0xE7C7: 0x7F1C, //CJK UNIFIED IDEOGRAPH + 0xE7C8: 0x7F1B, //CJK UNIFIED IDEOGRAPH + 0xE7C9: 0x7F1F, //CJK UNIFIED IDEOGRAPH + 0xE7CA: 0x7F21, //CJK UNIFIED IDEOGRAPH + 0xE7CB: 0x7F22, //CJK UNIFIED IDEOGRAPH + 0xE7CC: 0x7F23, //CJK UNIFIED IDEOGRAPH + 0xE7CD: 0x7F24, //CJK UNIFIED IDEOGRAPH + 0xE7CE: 0x7F25, //CJK UNIFIED IDEOGRAPH + 0xE7CF: 0x7F26, //CJK UNIFIED IDEOGRAPH + 0xE7D0: 0x7F27, //CJK UNIFIED IDEOGRAPH + 0xE7D1: 0x7F2A, //CJK UNIFIED IDEOGRAPH + 0xE7D2: 0x7F2B, //CJK UNIFIED IDEOGRAPH + 0xE7D3: 0x7F2C, //CJK UNIFIED IDEOGRAPH + 0xE7D4: 0x7F2D, //CJK UNIFIED IDEOGRAPH + 0xE7D5: 0x7F2F, //CJK UNIFIED IDEOGRAPH + 0xE7D6: 0x7F30, //CJK UNIFIED IDEOGRAPH + 0xE7D7: 0x7F31, //CJK UNIFIED IDEOGRAPH + 0xE7D8: 0x7F32, //CJK UNIFIED IDEOGRAPH + 0xE7D9: 0x7F33, //CJK UNIFIED IDEOGRAPH + 0xE7DA: 0x7F35, //CJK UNIFIED IDEOGRAPH + 0xE7DB: 0x5E7A, //CJK UNIFIED IDEOGRAPH + 0xE7DC: 0x757F, //CJK UNIFIED IDEOGRAPH + 0xE7DD: 0x5DDB, //CJK UNIFIED IDEOGRAPH + 0xE7DE: 0x753E, //CJK UNIFIED IDEOGRAPH + 0xE7DF: 0x9095, //CJK UNIFIED IDEOGRAPH + 0xE7E0: 0x738E, //CJK UNIFIED IDEOGRAPH + 0xE7E1: 0x7391, //CJK UNIFIED IDEOGRAPH + 0xE7E2: 0x73AE, //CJK UNIFIED IDEOGRAPH + 0xE7E3: 0x73A2, //CJK UNIFIED IDEOGRAPH + 0xE7E4: 0x739F, //CJK UNIFIED IDEOGRAPH + 0xE7E5: 0x73CF, //CJK UNIFIED IDEOGRAPH + 0xE7E6: 0x73C2, //CJK UNIFIED IDEOGRAPH + 0xE7E7: 0x73D1, //CJK UNIFIED IDEOGRAPH + 0xE7E8: 0x73B7, //CJK UNIFIED IDEOGRAPH + 0xE7E9: 0x73B3, //CJK UNIFIED IDEOGRAPH + 0xE7EA: 0x73C0, //CJK UNIFIED IDEOGRAPH + 0xE7EB: 0x73C9, //CJK UNIFIED IDEOGRAPH + 0xE7EC: 0x73C8, //CJK UNIFIED IDEOGRAPH + 0xE7ED: 0x73E5, //CJK UNIFIED IDEOGRAPH + 0xE7EE: 0x73D9, //CJK UNIFIED IDEOGRAPH + 0xE7EF: 0x987C, //CJK UNIFIED IDEOGRAPH + 0xE7F0: 0x740A, //CJK UNIFIED IDEOGRAPH + 0xE7F1: 0x73E9, //CJK UNIFIED IDEOGRAPH + 0xE7F2: 0x73E7, //CJK UNIFIED IDEOGRAPH + 0xE7F3: 0x73DE, //CJK UNIFIED IDEOGRAPH + 0xE7F4: 0x73BA, //CJK UNIFIED IDEOGRAPH + 0xE7F5: 0x73F2, //CJK UNIFIED IDEOGRAPH + 0xE7F6: 0x740F, //CJK UNIFIED IDEOGRAPH + 0xE7F7: 0x742A, //CJK UNIFIED IDEOGRAPH + 0xE7F8: 0x745B, //CJK UNIFIED IDEOGRAPH + 0xE7F9: 0x7426, //CJK UNIFIED IDEOGRAPH + 0xE7FA: 0x7425, //CJK UNIFIED IDEOGRAPH + 0xE7FB: 0x7428, //CJK UNIFIED IDEOGRAPH + 0xE7FC: 0x7430, //CJK UNIFIED IDEOGRAPH + 0xE7FD: 0x742E, //CJK UNIFIED IDEOGRAPH + 0xE7FE: 0x742C, //CJK UNIFIED IDEOGRAPH + 0xE840: 0x942F, //CJK UNIFIED IDEOGRAPH + 0xE841: 0x9430, //CJK UNIFIED IDEOGRAPH + 0xE842: 0x9431, //CJK UNIFIED IDEOGRAPH + 0xE843: 0x9432, //CJK UNIFIED IDEOGRAPH + 0xE844: 0x9433, //CJK UNIFIED IDEOGRAPH + 0xE845: 0x9434, //CJK UNIFIED IDEOGRAPH + 0xE846: 0x9435, //CJK UNIFIED IDEOGRAPH + 0xE847: 0x9436, //CJK UNIFIED IDEOGRAPH + 0xE848: 0x9437, //CJK UNIFIED IDEOGRAPH + 0xE849: 0x9438, //CJK UNIFIED IDEOGRAPH + 0xE84A: 0x9439, //CJK UNIFIED IDEOGRAPH + 0xE84B: 0x943A, //CJK UNIFIED IDEOGRAPH + 0xE84C: 0x943B, //CJK UNIFIED IDEOGRAPH + 0xE84D: 0x943C, //CJK UNIFIED IDEOGRAPH + 0xE84E: 0x943D, //CJK UNIFIED IDEOGRAPH + 0xE84F: 0x943F, //CJK UNIFIED IDEOGRAPH + 0xE850: 0x9440, //CJK UNIFIED IDEOGRAPH + 0xE851: 0x9441, //CJK UNIFIED IDEOGRAPH + 0xE852: 0x9442, //CJK UNIFIED IDEOGRAPH + 0xE853: 0x9443, //CJK UNIFIED IDEOGRAPH + 0xE854: 0x9444, //CJK UNIFIED IDEOGRAPH + 0xE855: 0x9445, //CJK UNIFIED IDEOGRAPH + 0xE856: 0x9446, //CJK UNIFIED IDEOGRAPH + 0xE857: 0x9447, //CJK UNIFIED IDEOGRAPH + 0xE858: 0x9448, //CJK UNIFIED IDEOGRAPH + 0xE859: 0x9449, //CJK UNIFIED IDEOGRAPH + 0xE85A: 0x944A, //CJK UNIFIED IDEOGRAPH + 0xE85B: 0x944B, //CJK UNIFIED IDEOGRAPH + 0xE85C: 0x944C, //CJK UNIFIED IDEOGRAPH + 0xE85D: 0x944D, //CJK UNIFIED IDEOGRAPH + 0xE85E: 0x944E, //CJK UNIFIED IDEOGRAPH + 0xE85F: 0x944F, //CJK UNIFIED IDEOGRAPH + 0xE860: 0x9450, //CJK UNIFIED IDEOGRAPH + 0xE861: 0x9451, //CJK UNIFIED IDEOGRAPH + 0xE862: 0x9452, //CJK UNIFIED IDEOGRAPH + 0xE863: 0x9453, //CJK UNIFIED IDEOGRAPH + 0xE864: 0x9454, //CJK UNIFIED IDEOGRAPH + 0xE865: 0x9455, //CJK UNIFIED IDEOGRAPH + 0xE866: 0x9456, //CJK UNIFIED IDEOGRAPH + 0xE867: 0x9457, //CJK UNIFIED IDEOGRAPH + 0xE868: 0x9458, //CJK UNIFIED IDEOGRAPH + 0xE869: 0x9459, //CJK UNIFIED IDEOGRAPH + 0xE86A: 0x945A, //CJK UNIFIED IDEOGRAPH + 0xE86B: 0x945B, //CJK UNIFIED IDEOGRAPH + 0xE86C: 0x945C, //CJK UNIFIED IDEOGRAPH + 0xE86D: 0x945D, //CJK UNIFIED IDEOGRAPH + 0xE86E: 0x945E, //CJK UNIFIED IDEOGRAPH + 0xE86F: 0x945F, //CJK UNIFIED IDEOGRAPH + 0xE870: 0x9460, //CJK UNIFIED IDEOGRAPH + 0xE871: 0x9461, //CJK UNIFIED IDEOGRAPH + 0xE872: 0x9462, //CJK UNIFIED IDEOGRAPH + 0xE873: 0x9463, //CJK UNIFIED IDEOGRAPH + 0xE874: 0x9464, //CJK UNIFIED IDEOGRAPH + 0xE875: 0x9465, //CJK UNIFIED IDEOGRAPH + 0xE876: 0x9466, //CJK UNIFIED IDEOGRAPH + 0xE877: 0x9467, //CJK UNIFIED IDEOGRAPH + 0xE878: 0x9468, //CJK UNIFIED IDEOGRAPH + 0xE879: 0x9469, //CJK UNIFIED IDEOGRAPH + 0xE87A: 0x946A, //CJK UNIFIED IDEOGRAPH + 0xE87B: 0x946C, //CJK UNIFIED IDEOGRAPH + 0xE87C: 0x946D, //CJK UNIFIED IDEOGRAPH + 0xE87D: 0x946E, //CJK UNIFIED IDEOGRAPH + 0xE87E: 0x946F, //CJK UNIFIED IDEOGRAPH + 0xE880: 0x9470, //CJK UNIFIED IDEOGRAPH + 0xE881: 0x9471, //CJK UNIFIED IDEOGRAPH + 0xE882: 0x9472, //CJK UNIFIED IDEOGRAPH + 0xE883: 0x9473, //CJK UNIFIED IDEOGRAPH + 0xE884: 0x9474, //CJK UNIFIED IDEOGRAPH + 0xE885: 0x9475, //CJK UNIFIED IDEOGRAPH + 0xE886: 0x9476, //CJK UNIFIED IDEOGRAPH + 0xE887: 0x9477, //CJK UNIFIED IDEOGRAPH + 0xE888: 0x9478, //CJK UNIFIED IDEOGRAPH + 0xE889: 0x9479, //CJK UNIFIED IDEOGRAPH + 0xE88A: 0x947A, //CJK UNIFIED IDEOGRAPH + 0xE88B: 0x947B, //CJK UNIFIED IDEOGRAPH + 0xE88C: 0x947C, //CJK UNIFIED IDEOGRAPH + 0xE88D: 0x947D, //CJK UNIFIED IDEOGRAPH + 0xE88E: 0x947E, //CJK UNIFIED IDEOGRAPH + 0xE88F: 0x947F, //CJK UNIFIED IDEOGRAPH + 0xE890: 0x9480, //CJK UNIFIED IDEOGRAPH + 0xE891: 0x9481, //CJK UNIFIED IDEOGRAPH + 0xE892: 0x9482, //CJK UNIFIED IDEOGRAPH + 0xE893: 0x9483, //CJK UNIFIED IDEOGRAPH + 0xE894: 0x9484, //CJK UNIFIED IDEOGRAPH + 0xE895: 0x9491, //CJK UNIFIED IDEOGRAPH + 0xE896: 0x9496, //CJK UNIFIED IDEOGRAPH + 0xE897: 0x9498, //CJK UNIFIED IDEOGRAPH + 0xE898: 0x94C7, //CJK UNIFIED IDEOGRAPH + 0xE899: 0x94CF, //CJK UNIFIED IDEOGRAPH + 0xE89A: 0x94D3, //CJK UNIFIED IDEOGRAPH + 0xE89B: 0x94D4, //CJK UNIFIED IDEOGRAPH + 0xE89C: 0x94DA, //CJK UNIFIED IDEOGRAPH + 0xE89D: 0x94E6, //CJK UNIFIED IDEOGRAPH + 0xE89E: 0x94FB, //CJK UNIFIED IDEOGRAPH + 0xE89F: 0x951C, //CJK UNIFIED IDEOGRAPH + 0xE8A0: 0x9520, //CJK UNIFIED IDEOGRAPH + 0xE8A1: 0x741B, //CJK UNIFIED IDEOGRAPH + 0xE8A2: 0x741A, //CJK UNIFIED IDEOGRAPH + 0xE8A3: 0x7441, //CJK UNIFIED IDEOGRAPH + 0xE8A4: 0x745C, //CJK UNIFIED IDEOGRAPH + 0xE8A5: 0x7457, //CJK UNIFIED IDEOGRAPH + 0xE8A6: 0x7455, //CJK UNIFIED IDEOGRAPH + 0xE8A7: 0x7459, //CJK UNIFIED IDEOGRAPH + 0xE8A8: 0x7477, //CJK UNIFIED IDEOGRAPH + 0xE8A9: 0x746D, //CJK UNIFIED IDEOGRAPH + 0xE8AA: 0x747E, //CJK UNIFIED IDEOGRAPH + 0xE8AB: 0x749C, //CJK UNIFIED IDEOGRAPH + 0xE8AC: 0x748E, //CJK UNIFIED IDEOGRAPH + 0xE8AD: 0x7480, //CJK UNIFIED IDEOGRAPH + 0xE8AE: 0x7481, //CJK UNIFIED IDEOGRAPH + 0xE8AF: 0x7487, //CJK UNIFIED IDEOGRAPH + 0xE8B0: 0x748B, //CJK UNIFIED IDEOGRAPH + 0xE8B1: 0x749E, //CJK UNIFIED IDEOGRAPH + 0xE8B2: 0x74A8, //CJK UNIFIED IDEOGRAPH + 0xE8B3: 0x74A9, //CJK UNIFIED IDEOGRAPH + 0xE8B4: 0x7490, //CJK UNIFIED IDEOGRAPH + 0xE8B5: 0x74A7, //CJK UNIFIED IDEOGRAPH + 0xE8B6: 0x74D2, //CJK UNIFIED IDEOGRAPH + 0xE8B7: 0x74BA, //CJK UNIFIED IDEOGRAPH + 0xE8B8: 0x97EA, //CJK UNIFIED IDEOGRAPH + 0xE8B9: 0x97EB, //CJK UNIFIED IDEOGRAPH + 0xE8BA: 0x97EC, //CJK UNIFIED IDEOGRAPH + 0xE8BB: 0x674C, //CJK UNIFIED IDEOGRAPH + 0xE8BC: 0x6753, //CJK UNIFIED IDEOGRAPH + 0xE8BD: 0x675E, //CJK UNIFIED IDEOGRAPH + 0xE8BE: 0x6748, //CJK UNIFIED IDEOGRAPH + 0xE8BF: 0x6769, //CJK UNIFIED IDEOGRAPH + 0xE8C0: 0x67A5, //CJK UNIFIED IDEOGRAPH + 0xE8C1: 0x6787, //CJK UNIFIED IDEOGRAPH + 0xE8C2: 0x676A, //CJK UNIFIED IDEOGRAPH + 0xE8C3: 0x6773, //CJK UNIFIED IDEOGRAPH + 0xE8C4: 0x6798, //CJK UNIFIED IDEOGRAPH + 0xE8C5: 0x67A7, //CJK UNIFIED IDEOGRAPH + 0xE8C6: 0x6775, //CJK UNIFIED IDEOGRAPH + 0xE8C7: 0x67A8, //CJK UNIFIED IDEOGRAPH + 0xE8C8: 0x679E, //CJK UNIFIED IDEOGRAPH + 0xE8C9: 0x67AD, //CJK UNIFIED IDEOGRAPH + 0xE8CA: 0x678B, //CJK UNIFIED IDEOGRAPH + 0xE8CB: 0x6777, //CJK UNIFIED IDEOGRAPH + 0xE8CC: 0x677C, //CJK UNIFIED IDEOGRAPH + 0xE8CD: 0x67F0, //CJK UNIFIED IDEOGRAPH + 0xE8CE: 0x6809, //CJK UNIFIED IDEOGRAPH + 0xE8CF: 0x67D8, //CJK UNIFIED IDEOGRAPH + 0xE8D0: 0x680A, //CJK UNIFIED IDEOGRAPH + 0xE8D1: 0x67E9, //CJK UNIFIED IDEOGRAPH + 0xE8D2: 0x67B0, //CJK UNIFIED IDEOGRAPH + 0xE8D3: 0x680C, //CJK UNIFIED IDEOGRAPH + 0xE8D4: 0x67D9, //CJK UNIFIED IDEOGRAPH + 0xE8D5: 0x67B5, //CJK UNIFIED IDEOGRAPH + 0xE8D6: 0x67DA, //CJK UNIFIED IDEOGRAPH + 0xE8D7: 0x67B3, //CJK UNIFIED IDEOGRAPH + 0xE8D8: 0x67DD, //CJK UNIFIED IDEOGRAPH + 0xE8D9: 0x6800, //CJK UNIFIED IDEOGRAPH + 0xE8DA: 0x67C3, //CJK UNIFIED IDEOGRAPH + 0xE8DB: 0x67B8, //CJK UNIFIED IDEOGRAPH + 0xE8DC: 0x67E2, //CJK UNIFIED IDEOGRAPH + 0xE8DD: 0x680E, //CJK UNIFIED IDEOGRAPH + 0xE8DE: 0x67C1, //CJK UNIFIED IDEOGRAPH + 0xE8DF: 0x67FD, //CJK UNIFIED IDEOGRAPH + 0xE8E0: 0x6832, //CJK UNIFIED IDEOGRAPH + 0xE8E1: 0x6833, //CJK UNIFIED IDEOGRAPH + 0xE8E2: 0x6860, //CJK UNIFIED IDEOGRAPH + 0xE8E3: 0x6861, //CJK UNIFIED IDEOGRAPH + 0xE8E4: 0x684E, //CJK UNIFIED IDEOGRAPH + 0xE8E5: 0x6862, //CJK UNIFIED IDEOGRAPH + 0xE8E6: 0x6844, //CJK UNIFIED IDEOGRAPH + 0xE8E7: 0x6864, //CJK UNIFIED IDEOGRAPH + 0xE8E8: 0x6883, //CJK UNIFIED IDEOGRAPH + 0xE8E9: 0x681D, //CJK UNIFIED IDEOGRAPH + 0xE8EA: 0x6855, //CJK UNIFIED IDEOGRAPH + 0xE8EB: 0x6866, //CJK UNIFIED IDEOGRAPH + 0xE8EC: 0x6841, //CJK UNIFIED IDEOGRAPH + 0xE8ED: 0x6867, //CJK UNIFIED IDEOGRAPH + 0xE8EE: 0x6840, //CJK UNIFIED IDEOGRAPH + 0xE8EF: 0x683E, //CJK UNIFIED IDEOGRAPH + 0xE8F0: 0x684A, //CJK UNIFIED IDEOGRAPH + 0xE8F1: 0x6849, //CJK UNIFIED IDEOGRAPH + 0xE8F2: 0x6829, //CJK UNIFIED IDEOGRAPH + 0xE8F3: 0x68B5, //CJK UNIFIED IDEOGRAPH + 0xE8F4: 0x688F, //CJK UNIFIED IDEOGRAPH + 0xE8F5: 0x6874, //CJK UNIFIED IDEOGRAPH + 0xE8F6: 0x6877, //CJK UNIFIED IDEOGRAPH + 0xE8F7: 0x6893, //CJK UNIFIED IDEOGRAPH + 0xE8F8: 0x686B, //CJK UNIFIED IDEOGRAPH + 0xE8F9: 0x68C2, //CJK UNIFIED IDEOGRAPH + 0xE8FA: 0x696E, //CJK UNIFIED IDEOGRAPH + 0xE8FB: 0x68FC, //CJK UNIFIED IDEOGRAPH + 0xE8FC: 0x691F, //CJK UNIFIED IDEOGRAPH + 0xE8FD: 0x6920, //CJK UNIFIED IDEOGRAPH + 0xE8FE: 0x68F9, //CJK UNIFIED IDEOGRAPH + 0xE940: 0x9527, //CJK UNIFIED IDEOGRAPH + 0xE941: 0x9533, //CJK UNIFIED IDEOGRAPH + 0xE942: 0x953D, //CJK UNIFIED IDEOGRAPH + 0xE943: 0x9543, //CJK UNIFIED IDEOGRAPH + 0xE944: 0x9548, //CJK UNIFIED IDEOGRAPH + 0xE945: 0x954B, //CJK UNIFIED IDEOGRAPH + 0xE946: 0x9555, //CJK UNIFIED IDEOGRAPH + 0xE947: 0x955A, //CJK UNIFIED IDEOGRAPH + 0xE948: 0x9560, //CJK UNIFIED IDEOGRAPH + 0xE949: 0x956E, //CJK UNIFIED IDEOGRAPH + 0xE94A: 0x9574, //CJK UNIFIED IDEOGRAPH + 0xE94B: 0x9575, //CJK UNIFIED IDEOGRAPH + 0xE94C: 0x9577, //CJK UNIFIED IDEOGRAPH + 0xE94D: 0x9578, //CJK UNIFIED IDEOGRAPH + 0xE94E: 0x9579, //CJK UNIFIED IDEOGRAPH + 0xE94F: 0x957A, //CJK UNIFIED IDEOGRAPH + 0xE950: 0x957B, //CJK UNIFIED IDEOGRAPH + 0xE951: 0x957C, //CJK UNIFIED IDEOGRAPH + 0xE952: 0x957D, //CJK UNIFIED IDEOGRAPH + 0xE953: 0x957E, //CJK UNIFIED IDEOGRAPH + 0xE954: 0x9580, //CJK UNIFIED IDEOGRAPH + 0xE955: 0x9581, //CJK UNIFIED IDEOGRAPH + 0xE956: 0x9582, //CJK UNIFIED IDEOGRAPH + 0xE957: 0x9583, //CJK UNIFIED IDEOGRAPH + 0xE958: 0x9584, //CJK UNIFIED IDEOGRAPH + 0xE959: 0x9585, //CJK UNIFIED IDEOGRAPH + 0xE95A: 0x9586, //CJK UNIFIED IDEOGRAPH + 0xE95B: 0x9587, //CJK UNIFIED IDEOGRAPH + 0xE95C: 0x9588, //CJK UNIFIED IDEOGRAPH + 0xE95D: 0x9589, //CJK UNIFIED IDEOGRAPH + 0xE95E: 0x958A, //CJK UNIFIED IDEOGRAPH + 0xE95F: 0x958B, //CJK UNIFIED IDEOGRAPH + 0xE960: 0x958C, //CJK UNIFIED IDEOGRAPH + 0xE961: 0x958D, //CJK UNIFIED IDEOGRAPH + 0xE962: 0x958E, //CJK UNIFIED IDEOGRAPH + 0xE963: 0x958F, //CJK UNIFIED IDEOGRAPH + 0xE964: 0x9590, //CJK UNIFIED IDEOGRAPH + 0xE965: 0x9591, //CJK UNIFIED IDEOGRAPH + 0xE966: 0x9592, //CJK UNIFIED IDEOGRAPH + 0xE967: 0x9593, //CJK UNIFIED IDEOGRAPH + 0xE968: 0x9594, //CJK UNIFIED IDEOGRAPH + 0xE969: 0x9595, //CJK UNIFIED IDEOGRAPH + 0xE96A: 0x9596, //CJK UNIFIED IDEOGRAPH + 0xE96B: 0x9597, //CJK UNIFIED IDEOGRAPH + 0xE96C: 0x9598, //CJK UNIFIED IDEOGRAPH + 0xE96D: 0x9599, //CJK UNIFIED IDEOGRAPH + 0xE96E: 0x959A, //CJK UNIFIED IDEOGRAPH + 0xE96F: 0x959B, //CJK UNIFIED IDEOGRAPH + 0xE970: 0x959C, //CJK UNIFIED IDEOGRAPH + 0xE971: 0x959D, //CJK UNIFIED IDEOGRAPH + 0xE972: 0x959E, //CJK UNIFIED IDEOGRAPH + 0xE973: 0x959F, //CJK UNIFIED IDEOGRAPH + 0xE974: 0x95A0, //CJK UNIFIED IDEOGRAPH + 0xE975: 0x95A1, //CJK UNIFIED IDEOGRAPH + 0xE976: 0x95A2, //CJK UNIFIED IDEOGRAPH + 0xE977: 0x95A3, //CJK UNIFIED IDEOGRAPH + 0xE978: 0x95A4, //CJK UNIFIED IDEOGRAPH + 0xE979: 0x95A5, //CJK UNIFIED IDEOGRAPH + 0xE97A: 0x95A6, //CJK UNIFIED IDEOGRAPH + 0xE97B: 0x95A7, //CJK UNIFIED IDEOGRAPH + 0xE97C: 0x95A8, //CJK UNIFIED IDEOGRAPH + 0xE97D: 0x95A9, //CJK UNIFIED IDEOGRAPH + 0xE97E: 0x95AA, //CJK UNIFIED IDEOGRAPH + 0xE980: 0x95AB, //CJK UNIFIED IDEOGRAPH + 0xE981: 0x95AC, //CJK UNIFIED IDEOGRAPH + 0xE982: 0x95AD, //CJK UNIFIED IDEOGRAPH + 0xE983: 0x95AE, //CJK UNIFIED IDEOGRAPH + 0xE984: 0x95AF, //CJK UNIFIED IDEOGRAPH + 0xE985: 0x95B0, //CJK UNIFIED IDEOGRAPH + 0xE986: 0x95B1, //CJK UNIFIED IDEOGRAPH + 0xE987: 0x95B2, //CJK UNIFIED IDEOGRAPH + 0xE988: 0x95B3, //CJK UNIFIED IDEOGRAPH + 0xE989: 0x95B4, //CJK UNIFIED IDEOGRAPH + 0xE98A: 0x95B5, //CJK UNIFIED IDEOGRAPH + 0xE98B: 0x95B6, //CJK UNIFIED IDEOGRAPH + 0xE98C: 0x95B7, //CJK UNIFIED IDEOGRAPH + 0xE98D: 0x95B8, //CJK UNIFIED IDEOGRAPH + 0xE98E: 0x95B9, //CJK UNIFIED IDEOGRAPH + 0xE98F: 0x95BA, //CJK UNIFIED IDEOGRAPH + 0xE990: 0x95BB, //CJK UNIFIED IDEOGRAPH + 0xE991: 0x95BC, //CJK UNIFIED IDEOGRAPH + 0xE992: 0x95BD, //CJK UNIFIED IDEOGRAPH + 0xE993: 0x95BE, //CJK UNIFIED IDEOGRAPH + 0xE994: 0x95BF, //CJK UNIFIED IDEOGRAPH + 0xE995: 0x95C0, //CJK UNIFIED IDEOGRAPH + 0xE996: 0x95C1, //CJK UNIFIED IDEOGRAPH + 0xE997: 0x95C2, //CJK UNIFIED IDEOGRAPH + 0xE998: 0x95C3, //CJK UNIFIED IDEOGRAPH + 0xE999: 0x95C4, //CJK UNIFIED IDEOGRAPH + 0xE99A: 0x95C5, //CJK UNIFIED IDEOGRAPH + 0xE99B: 0x95C6, //CJK UNIFIED IDEOGRAPH + 0xE99C: 0x95C7, //CJK UNIFIED IDEOGRAPH + 0xE99D: 0x95C8, //CJK UNIFIED IDEOGRAPH + 0xE99E: 0x95C9, //CJK UNIFIED IDEOGRAPH + 0xE99F: 0x95CA, //CJK UNIFIED IDEOGRAPH + 0xE9A0: 0x95CB, //CJK UNIFIED IDEOGRAPH + 0xE9A1: 0x6924, //CJK UNIFIED IDEOGRAPH + 0xE9A2: 0x68F0, //CJK UNIFIED IDEOGRAPH + 0xE9A3: 0x690B, //CJK UNIFIED IDEOGRAPH + 0xE9A4: 0x6901, //CJK UNIFIED IDEOGRAPH + 0xE9A5: 0x6957, //CJK UNIFIED IDEOGRAPH + 0xE9A6: 0x68E3, //CJK UNIFIED IDEOGRAPH + 0xE9A7: 0x6910, //CJK UNIFIED IDEOGRAPH + 0xE9A8: 0x6971, //CJK UNIFIED IDEOGRAPH + 0xE9A9: 0x6939, //CJK UNIFIED IDEOGRAPH + 0xE9AA: 0x6960, //CJK UNIFIED IDEOGRAPH + 0xE9AB: 0x6942, //CJK UNIFIED IDEOGRAPH + 0xE9AC: 0x695D, //CJK UNIFIED IDEOGRAPH + 0xE9AD: 0x6984, //CJK UNIFIED IDEOGRAPH + 0xE9AE: 0x696B, //CJK UNIFIED IDEOGRAPH + 0xE9AF: 0x6980, //CJK UNIFIED IDEOGRAPH + 0xE9B0: 0x6998, //CJK UNIFIED IDEOGRAPH + 0xE9B1: 0x6978, //CJK UNIFIED IDEOGRAPH + 0xE9B2: 0x6934, //CJK UNIFIED IDEOGRAPH + 0xE9B3: 0x69CC, //CJK UNIFIED IDEOGRAPH + 0xE9B4: 0x6987, //CJK UNIFIED IDEOGRAPH + 0xE9B5: 0x6988, //CJK UNIFIED IDEOGRAPH + 0xE9B6: 0x69CE, //CJK UNIFIED IDEOGRAPH + 0xE9B7: 0x6989, //CJK UNIFIED IDEOGRAPH + 0xE9B8: 0x6966, //CJK UNIFIED IDEOGRAPH + 0xE9B9: 0x6963, //CJK UNIFIED IDEOGRAPH + 0xE9BA: 0x6979, //CJK UNIFIED IDEOGRAPH + 0xE9BB: 0x699B, //CJK UNIFIED IDEOGRAPH + 0xE9BC: 0x69A7, //CJK UNIFIED IDEOGRAPH + 0xE9BD: 0x69BB, //CJK UNIFIED IDEOGRAPH + 0xE9BE: 0x69AB, //CJK UNIFIED IDEOGRAPH + 0xE9BF: 0x69AD, //CJK UNIFIED IDEOGRAPH + 0xE9C0: 0x69D4, //CJK UNIFIED IDEOGRAPH + 0xE9C1: 0x69B1, //CJK UNIFIED IDEOGRAPH + 0xE9C2: 0x69C1, //CJK UNIFIED IDEOGRAPH + 0xE9C3: 0x69CA, //CJK UNIFIED IDEOGRAPH + 0xE9C4: 0x69DF, //CJK UNIFIED IDEOGRAPH + 0xE9C5: 0x6995, //CJK UNIFIED IDEOGRAPH + 0xE9C6: 0x69E0, //CJK UNIFIED IDEOGRAPH + 0xE9C7: 0x698D, //CJK UNIFIED IDEOGRAPH + 0xE9C8: 0x69FF, //CJK UNIFIED IDEOGRAPH + 0xE9C9: 0x6A2F, //CJK UNIFIED IDEOGRAPH + 0xE9CA: 0x69ED, //CJK UNIFIED IDEOGRAPH + 0xE9CB: 0x6A17, //CJK UNIFIED IDEOGRAPH + 0xE9CC: 0x6A18, //CJK UNIFIED IDEOGRAPH + 0xE9CD: 0x6A65, //CJK UNIFIED IDEOGRAPH + 0xE9CE: 0x69F2, //CJK UNIFIED IDEOGRAPH + 0xE9CF: 0x6A44, //CJK UNIFIED IDEOGRAPH + 0xE9D0: 0x6A3E, //CJK UNIFIED IDEOGRAPH + 0xE9D1: 0x6AA0, //CJK UNIFIED IDEOGRAPH + 0xE9D2: 0x6A50, //CJK UNIFIED IDEOGRAPH + 0xE9D3: 0x6A5B, //CJK UNIFIED IDEOGRAPH + 0xE9D4: 0x6A35, //CJK UNIFIED IDEOGRAPH + 0xE9D5: 0x6A8E, //CJK UNIFIED IDEOGRAPH + 0xE9D6: 0x6A79, //CJK UNIFIED IDEOGRAPH + 0xE9D7: 0x6A3D, //CJK UNIFIED IDEOGRAPH + 0xE9D8: 0x6A28, //CJK UNIFIED IDEOGRAPH + 0xE9D9: 0x6A58, //CJK UNIFIED IDEOGRAPH + 0xE9DA: 0x6A7C, //CJK UNIFIED IDEOGRAPH + 0xE9DB: 0x6A91, //CJK UNIFIED IDEOGRAPH + 0xE9DC: 0x6A90, //CJK UNIFIED IDEOGRAPH + 0xE9DD: 0x6AA9, //CJK UNIFIED IDEOGRAPH + 0xE9DE: 0x6A97, //CJK UNIFIED IDEOGRAPH + 0xE9DF: 0x6AAB, //CJK UNIFIED IDEOGRAPH + 0xE9E0: 0x7337, //CJK UNIFIED IDEOGRAPH + 0xE9E1: 0x7352, //CJK UNIFIED IDEOGRAPH + 0xE9E2: 0x6B81, //CJK UNIFIED IDEOGRAPH + 0xE9E3: 0x6B82, //CJK UNIFIED IDEOGRAPH + 0xE9E4: 0x6B87, //CJK UNIFIED IDEOGRAPH + 0xE9E5: 0x6B84, //CJK UNIFIED IDEOGRAPH + 0xE9E6: 0x6B92, //CJK UNIFIED IDEOGRAPH + 0xE9E7: 0x6B93, //CJK UNIFIED IDEOGRAPH + 0xE9E8: 0x6B8D, //CJK UNIFIED IDEOGRAPH + 0xE9E9: 0x6B9A, //CJK UNIFIED IDEOGRAPH + 0xE9EA: 0x6B9B, //CJK UNIFIED IDEOGRAPH + 0xE9EB: 0x6BA1, //CJK UNIFIED IDEOGRAPH + 0xE9EC: 0x6BAA, //CJK UNIFIED IDEOGRAPH + 0xE9ED: 0x8F6B, //CJK UNIFIED IDEOGRAPH + 0xE9EE: 0x8F6D, //CJK UNIFIED IDEOGRAPH + 0xE9EF: 0x8F71, //CJK UNIFIED IDEOGRAPH + 0xE9F0: 0x8F72, //CJK UNIFIED IDEOGRAPH + 0xE9F1: 0x8F73, //CJK UNIFIED IDEOGRAPH + 0xE9F2: 0x8F75, //CJK UNIFIED IDEOGRAPH + 0xE9F3: 0x8F76, //CJK UNIFIED IDEOGRAPH + 0xE9F4: 0x8F78, //CJK UNIFIED IDEOGRAPH + 0xE9F5: 0x8F77, //CJK UNIFIED IDEOGRAPH + 0xE9F6: 0x8F79, //CJK UNIFIED IDEOGRAPH + 0xE9F7: 0x8F7A, //CJK UNIFIED IDEOGRAPH + 0xE9F8: 0x8F7C, //CJK UNIFIED IDEOGRAPH + 0xE9F9: 0x8F7E, //CJK UNIFIED IDEOGRAPH + 0xE9FA: 0x8F81, //CJK UNIFIED IDEOGRAPH + 0xE9FB: 0x8F82, //CJK UNIFIED IDEOGRAPH + 0xE9FC: 0x8F84, //CJK UNIFIED IDEOGRAPH + 0xE9FD: 0x8F87, //CJK UNIFIED IDEOGRAPH + 0xE9FE: 0x8F8B, //CJK UNIFIED IDEOGRAPH + 0xEA40: 0x95CC, //CJK UNIFIED IDEOGRAPH + 0xEA41: 0x95CD, //CJK UNIFIED IDEOGRAPH + 0xEA42: 0x95CE, //CJK UNIFIED IDEOGRAPH + 0xEA43: 0x95CF, //CJK UNIFIED IDEOGRAPH + 0xEA44: 0x95D0, //CJK UNIFIED IDEOGRAPH + 0xEA45: 0x95D1, //CJK UNIFIED IDEOGRAPH + 0xEA46: 0x95D2, //CJK UNIFIED IDEOGRAPH + 0xEA47: 0x95D3, //CJK UNIFIED IDEOGRAPH + 0xEA48: 0x95D4, //CJK UNIFIED IDEOGRAPH + 0xEA49: 0x95D5, //CJK UNIFIED IDEOGRAPH + 0xEA4A: 0x95D6, //CJK UNIFIED IDEOGRAPH + 0xEA4B: 0x95D7, //CJK UNIFIED IDEOGRAPH + 0xEA4C: 0x95D8, //CJK UNIFIED IDEOGRAPH + 0xEA4D: 0x95D9, //CJK UNIFIED IDEOGRAPH + 0xEA4E: 0x95DA, //CJK UNIFIED IDEOGRAPH + 0xEA4F: 0x95DB, //CJK UNIFIED IDEOGRAPH + 0xEA50: 0x95DC, //CJK UNIFIED IDEOGRAPH + 0xEA51: 0x95DD, //CJK UNIFIED IDEOGRAPH + 0xEA52: 0x95DE, //CJK UNIFIED IDEOGRAPH + 0xEA53: 0x95DF, //CJK UNIFIED IDEOGRAPH + 0xEA54: 0x95E0, //CJK UNIFIED IDEOGRAPH + 0xEA55: 0x95E1, //CJK UNIFIED IDEOGRAPH + 0xEA56: 0x95E2, //CJK UNIFIED IDEOGRAPH + 0xEA57: 0x95E3, //CJK UNIFIED IDEOGRAPH + 0xEA58: 0x95E4, //CJK UNIFIED IDEOGRAPH + 0xEA59: 0x95E5, //CJK UNIFIED IDEOGRAPH + 0xEA5A: 0x95E6, //CJK UNIFIED IDEOGRAPH + 0xEA5B: 0x95E7, //CJK UNIFIED IDEOGRAPH + 0xEA5C: 0x95EC, //CJK UNIFIED IDEOGRAPH + 0xEA5D: 0x95FF, //CJK UNIFIED IDEOGRAPH + 0xEA5E: 0x9607, //CJK UNIFIED IDEOGRAPH + 0xEA5F: 0x9613, //CJK UNIFIED IDEOGRAPH + 0xEA60: 0x9618, //CJK UNIFIED IDEOGRAPH + 0xEA61: 0x961B, //CJK UNIFIED IDEOGRAPH + 0xEA62: 0x961E, //CJK UNIFIED IDEOGRAPH + 0xEA63: 0x9620, //CJK UNIFIED IDEOGRAPH + 0xEA64: 0x9623, //CJK UNIFIED IDEOGRAPH + 0xEA65: 0x9624, //CJK UNIFIED IDEOGRAPH + 0xEA66: 0x9625, //CJK UNIFIED IDEOGRAPH + 0xEA67: 0x9626, //CJK UNIFIED IDEOGRAPH + 0xEA68: 0x9627, //CJK UNIFIED IDEOGRAPH + 0xEA69: 0x9628, //CJK UNIFIED IDEOGRAPH + 0xEA6A: 0x9629, //CJK UNIFIED IDEOGRAPH + 0xEA6B: 0x962B, //CJK UNIFIED IDEOGRAPH + 0xEA6C: 0x962C, //CJK UNIFIED IDEOGRAPH + 0xEA6D: 0x962D, //CJK UNIFIED IDEOGRAPH + 0xEA6E: 0x962F, //CJK UNIFIED IDEOGRAPH + 0xEA6F: 0x9630, //CJK UNIFIED IDEOGRAPH + 0xEA70: 0x9637, //CJK UNIFIED IDEOGRAPH + 0xEA71: 0x9638, //CJK UNIFIED IDEOGRAPH + 0xEA72: 0x9639, //CJK UNIFIED IDEOGRAPH + 0xEA73: 0x963A, //CJK UNIFIED IDEOGRAPH + 0xEA74: 0x963E, //CJK UNIFIED IDEOGRAPH + 0xEA75: 0x9641, //CJK UNIFIED IDEOGRAPH + 0xEA76: 0x9643, //CJK UNIFIED IDEOGRAPH + 0xEA77: 0x964A, //CJK UNIFIED IDEOGRAPH + 0xEA78: 0x964E, //CJK UNIFIED IDEOGRAPH + 0xEA79: 0x964F, //CJK UNIFIED IDEOGRAPH + 0xEA7A: 0x9651, //CJK UNIFIED IDEOGRAPH + 0xEA7B: 0x9652, //CJK UNIFIED IDEOGRAPH + 0xEA7C: 0x9653, //CJK UNIFIED IDEOGRAPH + 0xEA7D: 0x9656, //CJK UNIFIED IDEOGRAPH + 0xEA7E: 0x9657, //CJK UNIFIED IDEOGRAPH + 0xEA80: 0x9658, //CJK UNIFIED IDEOGRAPH + 0xEA81: 0x9659, //CJK UNIFIED IDEOGRAPH + 0xEA82: 0x965A, //CJK UNIFIED IDEOGRAPH + 0xEA83: 0x965C, //CJK UNIFIED IDEOGRAPH + 0xEA84: 0x965D, //CJK UNIFIED IDEOGRAPH + 0xEA85: 0x965E, //CJK UNIFIED IDEOGRAPH + 0xEA86: 0x9660, //CJK UNIFIED IDEOGRAPH + 0xEA87: 0x9663, //CJK UNIFIED IDEOGRAPH + 0xEA88: 0x9665, //CJK UNIFIED IDEOGRAPH + 0xEA89: 0x9666, //CJK UNIFIED IDEOGRAPH + 0xEA8A: 0x966B, //CJK UNIFIED IDEOGRAPH + 0xEA8B: 0x966D, //CJK UNIFIED IDEOGRAPH + 0xEA8C: 0x966E, //CJK UNIFIED IDEOGRAPH + 0xEA8D: 0x966F, //CJK UNIFIED IDEOGRAPH + 0xEA8E: 0x9670, //CJK UNIFIED IDEOGRAPH + 0xEA8F: 0x9671, //CJK UNIFIED IDEOGRAPH + 0xEA90: 0x9673, //CJK UNIFIED IDEOGRAPH + 0xEA91: 0x9678, //CJK UNIFIED IDEOGRAPH + 0xEA92: 0x9679, //CJK UNIFIED IDEOGRAPH + 0xEA93: 0x967A, //CJK UNIFIED IDEOGRAPH + 0xEA94: 0x967B, //CJK UNIFIED IDEOGRAPH + 0xEA95: 0x967C, //CJK UNIFIED IDEOGRAPH + 0xEA96: 0x967D, //CJK UNIFIED IDEOGRAPH + 0xEA97: 0x967E, //CJK UNIFIED IDEOGRAPH + 0xEA98: 0x967F, //CJK UNIFIED IDEOGRAPH + 0xEA99: 0x9680, //CJK UNIFIED IDEOGRAPH + 0xEA9A: 0x9681, //CJK UNIFIED IDEOGRAPH + 0xEA9B: 0x9682, //CJK UNIFIED IDEOGRAPH + 0xEA9C: 0x9683, //CJK UNIFIED IDEOGRAPH + 0xEA9D: 0x9684, //CJK UNIFIED IDEOGRAPH + 0xEA9E: 0x9687, //CJK UNIFIED IDEOGRAPH + 0xEA9F: 0x9689, //CJK UNIFIED IDEOGRAPH + 0xEAA0: 0x968A, //CJK UNIFIED IDEOGRAPH + 0xEAA1: 0x8F8D, //CJK UNIFIED IDEOGRAPH + 0xEAA2: 0x8F8E, //CJK UNIFIED IDEOGRAPH + 0xEAA3: 0x8F8F, //CJK UNIFIED IDEOGRAPH + 0xEAA4: 0x8F98, //CJK UNIFIED IDEOGRAPH + 0xEAA5: 0x8F9A, //CJK UNIFIED IDEOGRAPH + 0xEAA6: 0x8ECE, //CJK UNIFIED IDEOGRAPH + 0xEAA7: 0x620B, //CJK UNIFIED IDEOGRAPH + 0xEAA8: 0x6217, //CJK UNIFIED IDEOGRAPH + 0xEAA9: 0x621B, //CJK UNIFIED IDEOGRAPH + 0xEAAA: 0x621F, //CJK UNIFIED IDEOGRAPH + 0xEAAB: 0x6222, //CJK UNIFIED IDEOGRAPH + 0xEAAC: 0x6221, //CJK UNIFIED IDEOGRAPH + 0xEAAD: 0x6225, //CJK UNIFIED IDEOGRAPH + 0xEAAE: 0x6224, //CJK UNIFIED IDEOGRAPH + 0xEAAF: 0x622C, //CJK UNIFIED IDEOGRAPH + 0xEAB0: 0x81E7, //CJK UNIFIED IDEOGRAPH + 0xEAB1: 0x74EF, //CJK UNIFIED IDEOGRAPH + 0xEAB2: 0x74F4, //CJK UNIFIED IDEOGRAPH + 0xEAB3: 0x74FF, //CJK UNIFIED IDEOGRAPH + 0xEAB4: 0x750F, //CJK UNIFIED IDEOGRAPH + 0xEAB5: 0x7511, //CJK UNIFIED IDEOGRAPH + 0xEAB6: 0x7513, //CJK UNIFIED IDEOGRAPH + 0xEAB7: 0x6534, //CJK UNIFIED IDEOGRAPH + 0xEAB8: 0x65EE, //CJK UNIFIED IDEOGRAPH + 0xEAB9: 0x65EF, //CJK UNIFIED IDEOGRAPH + 0xEABA: 0x65F0, //CJK UNIFIED IDEOGRAPH + 0xEABB: 0x660A, //CJK UNIFIED IDEOGRAPH + 0xEABC: 0x6619, //CJK UNIFIED IDEOGRAPH + 0xEABD: 0x6772, //CJK UNIFIED IDEOGRAPH + 0xEABE: 0x6603, //CJK UNIFIED IDEOGRAPH + 0xEABF: 0x6615, //CJK UNIFIED IDEOGRAPH + 0xEAC0: 0x6600, //CJK UNIFIED IDEOGRAPH + 0xEAC1: 0x7085, //CJK UNIFIED IDEOGRAPH + 0xEAC2: 0x66F7, //CJK UNIFIED IDEOGRAPH + 0xEAC3: 0x661D, //CJK UNIFIED IDEOGRAPH + 0xEAC4: 0x6634, //CJK UNIFIED IDEOGRAPH + 0xEAC5: 0x6631, //CJK UNIFIED IDEOGRAPH + 0xEAC6: 0x6636, //CJK UNIFIED IDEOGRAPH + 0xEAC7: 0x6635, //CJK UNIFIED IDEOGRAPH + 0xEAC8: 0x8006, //CJK UNIFIED IDEOGRAPH + 0xEAC9: 0x665F, //CJK UNIFIED IDEOGRAPH + 0xEACA: 0x6654, //CJK UNIFIED IDEOGRAPH + 0xEACB: 0x6641, //CJK UNIFIED IDEOGRAPH + 0xEACC: 0x664F, //CJK UNIFIED IDEOGRAPH + 0xEACD: 0x6656, //CJK UNIFIED IDEOGRAPH + 0xEACE: 0x6661, //CJK UNIFIED IDEOGRAPH + 0xEACF: 0x6657, //CJK UNIFIED IDEOGRAPH + 0xEAD0: 0x6677, //CJK UNIFIED IDEOGRAPH + 0xEAD1: 0x6684, //CJK UNIFIED IDEOGRAPH + 0xEAD2: 0x668C, //CJK UNIFIED IDEOGRAPH + 0xEAD3: 0x66A7, //CJK UNIFIED IDEOGRAPH + 0xEAD4: 0x669D, //CJK UNIFIED IDEOGRAPH + 0xEAD5: 0x66BE, //CJK UNIFIED IDEOGRAPH + 0xEAD6: 0x66DB, //CJK UNIFIED IDEOGRAPH + 0xEAD7: 0x66DC, //CJK UNIFIED IDEOGRAPH + 0xEAD8: 0x66E6, //CJK UNIFIED IDEOGRAPH + 0xEAD9: 0x66E9, //CJK UNIFIED IDEOGRAPH + 0xEADA: 0x8D32, //CJK UNIFIED IDEOGRAPH + 0xEADB: 0x8D33, //CJK UNIFIED IDEOGRAPH + 0xEADC: 0x8D36, //CJK UNIFIED IDEOGRAPH + 0xEADD: 0x8D3B, //CJK UNIFIED IDEOGRAPH + 0xEADE: 0x8D3D, //CJK UNIFIED IDEOGRAPH + 0xEADF: 0x8D40, //CJK UNIFIED IDEOGRAPH + 0xEAE0: 0x8D45, //CJK UNIFIED IDEOGRAPH + 0xEAE1: 0x8D46, //CJK UNIFIED IDEOGRAPH + 0xEAE2: 0x8D48, //CJK UNIFIED IDEOGRAPH + 0xEAE3: 0x8D49, //CJK UNIFIED IDEOGRAPH + 0xEAE4: 0x8D47, //CJK UNIFIED IDEOGRAPH + 0xEAE5: 0x8D4D, //CJK UNIFIED IDEOGRAPH + 0xEAE6: 0x8D55, //CJK UNIFIED IDEOGRAPH + 0xEAE7: 0x8D59, //CJK UNIFIED IDEOGRAPH + 0xEAE8: 0x89C7, //CJK UNIFIED IDEOGRAPH + 0xEAE9: 0x89CA, //CJK UNIFIED IDEOGRAPH + 0xEAEA: 0x89CB, //CJK UNIFIED IDEOGRAPH + 0xEAEB: 0x89CC, //CJK UNIFIED IDEOGRAPH + 0xEAEC: 0x89CE, //CJK UNIFIED IDEOGRAPH + 0xEAED: 0x89CF, //CJK UNIFIED IDEOGRAPH + 0xEAEE: 0x89D0, //CJK UNIFIED IDEOGRAPH + 0xEAEF: 0x89D1, //CJK UNIFIED IDEOGRAPH + 0xEAF0: 0x726E, //CJK UNIFIED IDEOGRAPH + 0xEAF1: 0x729F, //CJK UNIFIED IDEOGRAPH + 0xEAF2: 0x725D, //CJK UNIFIED IDEOGRAPH + 0xEAF3: 0x7266, //CJK UNIFIED IDEOGRAPH + 0xEAF4: 0x726F, //CJK UNIFIED IDEOGRAPH + 0xEAF5: 0x727E, //CJK UNIFIED IDEOGRAPH + 0xEAF6: 0x727F, //CJK UNIFIED IDEOGRAPH + 0xEAF7: 0x7284, //CJK UNIFIED IDEOGRAPH + 0xEAF8: 0x728B, //CJK UNIFIED IDEOGRAPH + 0xEAF9: 0x728D, //CJK UNIFIED IDEOGRAPH + 0xEAFA: 0x728F, //CJK UNIFIED IDEOGRAPH + 0xEAFB: 0x7292, //CJK UNIFIED IDEOGRAPH + 0xEAFC: 0x6308, //CJK UNIFIED IDEOGRAPH + 0xEAFD: 0x6332, //CJK UNIFIED IDEOGRAPH + 0xEAFE: 0x63B0, //CJK UNIFIED IDEOGRAPH + 0xEB40: 0x968C, //CJK UNIFIED IDEOGRAPH + 0xEB41: 0x968E, //CJK UNIFIED IDEOGRAPH + 0xEB42: 0x9691, //CJK UNIFIED IDEOGRAPH + 0xEB43: 0x9692, //CJK UNIFIED IDEOGRAPH + 0xEB44: 0x9693, //CJK UNIFIED IDEOGRAPH + 0xEB45: 0x9695, //CJK UNIFIED IDEOGRAPH + 0xEB46: 0x9696, //CJK UNIFIED IDEOGRAPH + 0xEB47: 0x969A, //CJK UNIFIED IDEOGRAPH + 0xEB48: 0x969B, //CJK UNIFIED IDEOGRAPH + 0xEB49: 0x969D, //CJK UNIFIED IDEOGRAPH + 0xEB4A: 0x969E, //CJK UNIFIED IDEOGRAPH + 0xEB4B: 0x969F, //CJK UNIFIED IDEOGRAPH + 0xEB4C: 0x96A0, //CJK UNIFIED IDEOGRAPH + 0xEB4D: 0x96A1, //CJK UNIFIED IDEOGRAPH + 0xEB4E: 0x96A2, //CJK UNIFIED IDEOGRAPH + 0xEB4F: 0x96A3, //CJK UNIFIED IDEOGRAPH + 0xEB50: 0x96A4, //CJK UNIFIED IDEOGRAPH + 0xEB51: 0x96A5, //CJK UNIFIED IDEOGRAPH + 0xEB52: 0x96A6, //CJK UNIFIED IDEOGRAPH + 0xEB53: 0x96A8, //CJK UNIFIED IDEOGRAPH + 0xEB54: 0x96A9, //CJK UNIFIED IDEOGRAPH + 0xEB55: 0x96AA, //CJK UNIFIED IDEOGRAPH + 0xEB56: 0x96AB, //CJK UNIFIED IDEOGRAPH + 0xEB57: 0x96AC, //CJK UNIFIED IDEOGRAPH + 0xEB58: 0x96AD, //CJK UNIFIED IDEOGRAPH + 0xEB59: 0x96AE, //CJK UNIFIED IDEOGRAPH + 0xEB5A: 0x96AF, //CJK UNIFIED IDEOGRAPH + 0xEB5B: 0x96B1, //CJK UNIFIED IDEOGRAPH + 0xEB5C: 0x96B2, //CJK UNIFIED IDEOGRAPH + 0xEB5D: 0x96B4, //CJK UNIFIED IDEOGRAPH + 0xEB5E: 0x96B5, //CJK UNIFIED IDEOGRAPH + 0xEB5F: 0x96B7, //CJK UNIFIED IDEOGRAPH + 0xEB60: 0x96B8, //CJK UNIFIED IDEOGRAPH + 0xEB61: 0x96BA, //CJK UNIFIED IDEOGRAPH + 0xEB62: 0x96BB, //CJK UNIFIED IDEOGRAPH + 0xEB63: 0x96BF, //CJK UNIFIED IDEOGRAPH + 0xEB64: 0x96C2, //CJK UNIFIED IDEOGRAPH + 0xEB65: 0x96C3, //CJK UNIFIED IDEOGRAPH + 0xEB66: 0x96C8, //CJK UNIFIED IDEOGRAPH + 0xEB67: 0x96CA, //CJK UNIFIED IDEOGRAPH + 0xEB68: 0x96CB, //CJK UNIFIED IDEOGRAPH + 0xEB69: 0x96D0, //CJK UNIFIED IDEOGRAPH + 0xEB6A: 0x96D1, //CJK UNIFIED IDEOGRAPH + 0xEB6B: 0x96D3, //CJK UNIFIED IDEOGRAPH + 0xEB6C: 0x96D4, //CJK UNIFIED IDEOGRAPH + 0xEB6D: 0x96D6, //CJK UNIFIED IDEOGRAPH + 0xEB6E: 0x96D7, //CJK UNIFIED IDEOGRAPH + 0xEB6F: 0x96D8, //CJK UNIFIED IDEOGRAPH + 0xEB70: 0x96D9, //CJK UNIFIED IDEOGRAPH + 0xEB71: 0x96DA, //CJK UNIFIED IDEOGRAPH + 0xEB72: 0x96DB, //CJK UNIFIED IDEOGRAPH + 0xEB73: 0x96DC, //CJK UNIFIED IDEOGRAPH + 0xEB74: 0x96DD, //CJK UNIFIED IDEOGRAPH + 0xEB75: 0x96DE, //CJK UNIFIED IDEOGRAPH + 0xEB76: 0x96DF, //CJK UNIFIED IDEOGRAPH + 0xEB77: 0x96E1, //CJK UNIFIED IDEOGRAPH + 0xEB78: 0x96E2, //CJK UNIFIED IDEOGRAPH + 0xEB79: 0x96E3, //CJK UNIFIED IDEOGRAPH + 0xEB7A: 0x96E4, //CJK UNIFIED IDEOGRAPH + 0xEB7B: 0x96E5, //CJK UNIFIED IDEOGRAPH + 0xEB7C: 0x96E6, //CJK UNIFIED IDEOGRAPH + 0xEB7D: 0x96E7, //CJK UNIFIED IDEOGRAPH + 0xEB7E: 0x96EB, //CJK UNIFIED IDEOGRAPH + 0xEB80: 0x96EC, //CJK UNIFIED IDEOGRAPH + 0xEB81: 0x96ED, //CJK UNIFIED IDEOGRAPH + 0xEB82: 0x96EE, //CJK UNIFIED IDEOGRAPH + 0xEB83: 0x96F0, //CJK UNIFIED IDEOGRAPH + 0xEB84: 0x96F1, //CJK UNIFIED IDEOGRAPH + 0xEB85: 0x96F2, //CJK UNIFIED IDEOGRAPH + 0xEB86: 0x96F4, //CJK UNIFIED IDEOGRAPH + 0xEB87: 0x96F5, //CJK UNIFIED IDEOGRAPH + 0xEB88: 0x96F8, //CJK UNIFIED IDEOGRAPH + 0xEB89: 0x96FA, //CJK UNIFIED IDEOGRAPH + 0xEB8A: 0x96FB, //CJK UNIFIED IDEOGRAPH + 0xEB8B: 0x96FC, //CJK UNIFIED IDEOGRAPH + 0xEB8C: 0x96FD, //CJK UNIFIED IDEOGRAPH + 0xEB8D: 0x96FF, //CJK UNIFIED IDEOGRAPH + 0xEB8E: 0x9702, //CJK UNIFIED IDEOGRAPH + 0xEB8F: 0x9703, //CJK UNIFIED IDEOGRAPH + 0xEB90: 0x9705, //CJK UNIFIED IDEOGRAPH + 0xEB91: 0x970A, //CJK UNIFIED IDEOGRAPH + 0xEB92: 0x970B, //CJK UNIFIED IDEOGRAPH + 0xEB93: 0x970C, //CJK UNIFIED IDEOGRAPH + 0xEB94: 0x9710, //CJK UNIFIED IDEOGRAPH + 0xEB95: 0x9711, //CJK UNIFIED IDEOGRAPH + 0xEB96: 0x9712, //CJK UNIFIED IDEOGRAPH + 0xEB97: 0x9714, //CJK UNIFIED IDEOGRAPH + 0xEB98: 0x9715, //CJK UNIFIED IDEOGRAPH + 0xEB99: 0x9717, //CJK UNIFIED IDEOGRAPH + 0xEB9A: 0x9718, //CJK UNIFIED IDEOGRAPH + 0xEB9B: 0x9719, //CJK UNIFIED IDEOGRAPH + 0xEB9C: 0x971A, //CJK UNIFIED IDEOGRAPH + 0xEB9D: 0x971B, //CJK UNIFIED IDEOGRAPH + 0xEB9E: 0x971D, //CJK UNIFIED IDEOGRAPH + 0xEB9F: 0x971F, //CJK UNIFIED IDEOGRAPH + 0xEBA0: 0x9720, //CJK UNIFIED IDEOGRAPH + 0xEBA1: 0x643F, //CJK UNIFIED IDEOGRAPH + 0xEBA2: 0x64D8, //CJK UNIFIED IDEOGRAPH + 0xEBA3: 0x8004, //CJK UNIFIED IDEOGRAPH + 0xEBA4: 0x6BEA, //CJK UNIFIED IDEOGRAPH + 0xEBA5: 0x6BF3, //CJK UNIFIED IDEOGRAPH + 0xEBA6: 0x6BFD, //CJK UNIFIED IDEOGRAPH + 0xEBA7: 0x6BF5, //CJK UNIFIED IDEOGRAPH + 0xEBA8: 0x6BF9, //CJK UNIFIED IDEOGRAPH + 0xEBA9: 0x6C05, //CJK UNIFIED IDEOGRAPH + 0xEBAA: 0x6C07, //CJK UNIFIED IDEOGRAPH + 0xEBAB: 0x6C06, //CJK UNIFIED IDEOGRAPH + 0xEBAC: 0x6C0D, //CJK UNIFIED IDEOGRAPH + 0xEBAD: 0x6C15, //CJK UNIFIED IDEOGRAPH + 0xEBAE: 0x6C18, //CJK UNIFIED IDEOGRAPH + 0xEBAF: 0x6C19, //CJK UNIFIED IDEOGRAPH + 0xEBB0: 0x6C1A, //CJK UNIFIED IDEOGRAPH + 0xEBB1: 0x6C21, //CJK UNIFIED IDEOGRAPH + 0xEBB2: 0x6C29, //CJK UNIFIED IDEOGRAPH + 0xEBB3: 0x6C24, //CJK UNIFIED IDEOGRAPH + 0xEBB4: 0x6C2A, //CJK UNIFIED IDEOGRAPH + 0xEBB5: 0x6C32, //CJK UNIFIED IDEOGRAPH + 0xEBB6: 0x6535, //CJK UNIFIED IDEOGRAPH + 0xEBB7: 0x6555, //CJK UNIFIED IDEOGRAPH + 0xEBB8: 0x656B, //CJK UNIFIED IDEOGRAPH + 0xEBB9: 0x724D, //CJK UNIFIED IDEOGRAPH + 0xEBBA: 0x7252, //CJK UNIFIED IDEOGRAPH + 0xEBBB: 0x7256, //CJK UNIFIED IDEOGRAPH + 0xEBBC: 0x7230, //CJK UNIFIED IDEOGRAPH + 0xEBBD: 0x8662, //CJK UNIFIED IDEOGRAPH + 0xEBBE: 0x5216, //CJK UNIFIED IDEOGRAPH + 0xEBBF: 0x809F, //CJK UNIFIED IDEOGRAPH + 0xEBC0: 0x809C, //CJK UNIFIED IDEOGRAPH + 0xEBC1: 0x8093, //CJK UNIFIED IDEOGRAPH + 0xEBC2: 0x80BC, //CJK UNIFIED IDEOGRAPH + 0xEBC3: 0x670A, //CJK UNIFIED IDEOGRAPH + 0xEBC4: 0x80BD, //CJK UNIFIED IDEOGRAPH + 0xEBC5: 0x80B1, //CJK UNIFIED IDEOGRAPH + 0xEBC6: 0x80AB, //CJK UNIFIED IDEOGRAPH + 0xEBC7: 0x80AD, //CJK UNIFIED IDEOGRAPH + 0xEBC8: 0x80B4, //CJK UNIFIED IDEOGRAPH + 0xEBC9: 0x80B7, //CJK UNIFIED IDEOGRAPH + 0xEBCA: 0x80E7, //CJK UNIFIED IDEOGRAPH + 0xEBCB: 0x80E8, //CJK UNIFIED IDEOGRAPH + 0xEBCC: 0x80E9, //CJK UNIFIED IDEOGRAPH + 0xEBCD: 0x80EA, //CJK UNIFIED IDEOGRAPH + 0xEBCE: 0x80DB, //CJK UNIFIED IDEOGRAPH + 0xEBCF: 0x80C2, //CJK UNIFIED IDEOGRAPH + 0xEBD0: 0x80C4, //CJK UNIFIED IDEOGRAPH + 0xEBD1: 0x80D9, //CJK UNIFIED IDEOGRAPH + 0xEBD2: 0x80CD, //CJK UNIFIED IDEOGRAPH + 0xEBD3: 0x80D7, //CJK UNIFIED IDEOGRAPH + 0xEBD4: 0x6710, //CJK UNIFIED IDEOGRAPH + 0xEBD5: 0x80DD, //CJK UNIFIED IDEOGRAPH + 0xEBD6: 0x80EB, //CJK UNIFIED IDEOGRAPH + 0xEBD7: 0x80F1, //CJK UNIFIED IDEOGRAPH + 0xEBD8: 0x80F4, //CJK UNIFIED IDEOGRAPH + 0xEBD9: 0x80ED, //CJK UNIFIED IDEOGRAPH + 0xEBDA: 0x810D, //CJK UNIFIED IDEOGRAPH + 0xEBDB: 0x810E, //CJK UNIFIED IDEOGRAPH + 0xEBDC: 0x80F2, //CJK UNIFIED IDEOGRAPH + 0xEBDD: 0x80FC, //CJK UNIFIED IDEOGRAPH + 0xEBDE: 0x6715, //CJK UNIFIED IDEOGRAPH + 0xEBDF: 0x8112, //CJK UNIFIED IDEOGRAPH + 0xEBE0: 0x8C5A, //CJK UNIFIED IDEOGRAPH + 0xEBE1: 0x8136, //CJK UNIFIED IDEOGRAPH + 0xEBE2: 0x811E, //CJK UNIFIED IDEOGRAPH + 0xEBE3: 0x812C, //CJK UNIFIED IDEOGRAPH + 0xEBE4: 0x8118, //CJK UNIFIED IDEOGRAPH + 0xEBE5: 0x8132, //CJK UNIFIED IDEOGRAPH + 0xEBE6: 0x8148, //CJK UNIFIED IDEOGRAPH + 0xEBE7: 0x814C, //CJK UNIFIED IDEOGRAPH + 0xEBE8: 0x8153, //CJK UNIFIED IDEOGRAPH + 0xEBE9: 0x8174, //CJK UNIFIED IDEOGRAPH + 0xEBEA: 0x8159, //CJK UNIFIED IDEOGRAPH + 0xEBEB: 0x815A, //CJK UNIFIED IDEOGRAPH + 0xEBEC: 0x8171, //CJK UNIFIED IDEOGRAPH + 0xEBED: 0x8160, //CJK UNIFIED IDEOGRAPH + 0xEBEE: 0x8169, //CJK UNIFIED IDEOGRAPH + 0xEBEF: 0x817C, //CJK UNIFIED IDEOGRAPH + 0xEBF0: 0x817D, //CJK UNIFIED IDEOGRAPH + 0xEBF1: 0x816D, //CJK UNIFIED IDEOGRAPH + 0xEBF2: 0x8167, //CJK UNIFIED IDEOGRAPH + 0xEBF3: 0x584D, //CJK UNIFIED IDEOGRAPH + 0xEBF4: 0x5AB5, //CJK UNIFIED IDEOGRAPH + 0xEBF5: 0x8188, //CJK UNIFIED IDEOGRAPH + 0xEBF6: 0x8182, //CJK UNIFIED IDEOGRAPH + 0xEBF7: 0x8191, //CJK UNIFIED IDEOGRAPH + 0xEBF8: 0x6ED5, //CJK UNIFIED IDEOGRAPH + 0xEBF9: 0x81A3, //CJK UNIFIED IDEOGRAPH + 0xEBFA: 0x81AA, //CJK UNIFIED IDEOGRAPH + 0xEBFB: 0x81CC, //CJK UNIFIED IDEOGRAPH + 0xEBFC: 0x6726, //CJK UNIFIED IDEOGRAPH + 0xEBFD: 0x81CA, //CJK UNIFIED IDEOGRAPH + 0xEBFE: 0x81BB, //CJK UNIFIED IDEOGRAPH + 0xEC40: 0x9721, //CJK UNIFIED IDEOGRAPH + 0xEC41: 0x9722, //CJK UNIFIED IDEOGRAPH + 0xEC42: 0x9723, //CJK UNIFIED IDEOGRAPH + 0xEC43: 0x9724, //CJK UNIFIED IDEOGRAPH + 0xEC44: 0x9725, //CJK UNIFIED IDEOGRAPH + 0xEC45: 0x9726, //CJK UNIFIED IDEOGRAPH + 0xEC46: 0x9727, //CJK UNIFIED IDEOGRAPH + 0xEC47: 0x9728, //CJK UNIFIED IDEOGRAPH + 0xEC48: 0x9729, //CJK UNIFIED IDEOGRAPH + 0xEC49: 0x972B, //CJK UNIFIED IDEOGRAPH + 0xEC4A: 0x972C, //CJK UNIFIED IDEOGRAPH + 0xEC4B: 0x972E, //CJK UNIFIED IDEOGRAPH + 0xEC4C: 0x972F, //CJK UNIFIED IDEOGRAPH + 0xEC4D: 0x9731, //CJK UNIFIED IDEOGRAPH + 0xEC4E: 0x9733, //CJK UNIFIED IDEOGRAPH + 0xEC4F: 0x9734, //CJK UNIFIED IDEOGRAPH + 0xEC50: 0x9735, //CJK UNIFIED IDEOGRAPH + 0xEC51: 0x9736, //CJK UNIFIED IDEOGRAPH + 0xEC52: 0x9737, //CJK UNIFIED IDEOGRAPH + 0xEC53: 0x973A, //CJK UNIFIED IDEOGRAPH + 0xEC54: 0x973B, //CJK UNIFIED IDEOGRAPH + 0xEC55: 0x973C, //CJK UNIFIED IDEOGRAPH + 0xEC56: 0x973D, //CJK UNIFIED IDEOGRAPH + 0xEC57: 0x973F, //CJK UNIFIED IDEOGRAPH + 0xEC58: 0x9740, //CJK UNIFIED IDEOGRAPH + 0xEC59: 0x9741, //CJK UNIFIED IDEOGRAPH + 0xEC5A: 0x9742, //CJK UNIFIED IDEOGRAPH + 0xEC5B: 0x9743, //CJK UNIFIED IDEOGRAPH + 0xEC5C: 0x9744, //CJK UNIFIED IDEOGRAPH + 0xEC5D: 0x9745, //CJK UNIFIED IDEOGRAPH + 0xEC5E: 0x9746, //CJK UNIFIED IDEOGRAPH + 0xEC5F: 0x9747, //CJK UNIFIED IDEOGRAPH + 0xEC60: 0x9748, //CJK UNIFIED IDEOGRAPH + 0xEC61: 0x9749, //CJK UNIFIED IDEOGRAPH + 0xEC62: 0x974A, //CJK UNIFIED IDEOGRAPH + 0xEC63: 0x974B, //CJK UNIFIED IDEOGRAPH + 0xEC64: 0x974C, //CJK UNIFIED IDEOGRAPH + 0xEC65: 0x974D, //CJK UNIFIED IDEOGRAPH + 0xEC66: 0x974E, //CJK UNIFIED IDEOGRAPH + 0xEC67: 0x974F, //CJK UNIFIED IDEOGRAPH + 0xEC68: 0x9750, //CJK UNIFIED IDEOGRAPH + 0xEC69: 0x9751, //CJK UNIFIED IDEOGRAPH + 0xEC6A: 0x9754, //CJK UNIFIED IDEOGRAPH + 0xEC6B: 0x9755, //CJK UNIFIED IDEOGRAPH + 0xEC6C: 0x9757, //CJK UNIFIED IDEOGRAPH + 0xEC6D: 0x9758, //CJK UNIFIED IDEOGRAPH + 0xEC6E: 0x975A, //CJK UNIFIED IDEOGRAPH + 0xEC6F: 0x975C, //CJK UNIFIED IDEOGRAPH + 0xEC70: 0x975D, //CJK UNIFIED IDEOGRAPH + 0xEC71: 0x975F, //CJK UNIFIED IDEOGRAPH + 0xEC72: 0x9763, //CJK UNIFIED IDEOGRAPH + 0xEC73: 0x9764, //CJK UNIFIED IDEOGRAPH + 0xEC74: 0x9766, //CJK UNIFIED IDEOGRAPH + 0xEC75: 0x9767, //CJK UNIFIED IDEOGRAPH + 0xEC76: 0x9768, //CJK UNIFIED IDEOGRAPH + 0xEC77: 0x976A, //CJK UNIFIED IDEOGRAPH + 0xEC78: 0x976B, //CJK UNIFIED IDEOGRAPH + 0xEC79: 0x976C, //CJK UNIFIED IDEOGRAPH + 0xEC7A: 0x976D, //CJK UNIFIED IDEOGRAPH + 0xEC7B: 0x976E, //CJK UNIFIED IDEOGRAPH + 0xEC7C: 0x976F, //CJK UNIFIED IDEOGRAPH + 0xEC7D: 0x9770, //CJK UNIFIED IDEOGRAPH + 0xEC7E: 0x9771, //CJK UNIFIED IDEOGRAPH + 0xEC80: 0x9772, //CJK UNIFIED IDEOGRAPH + 0xEC81: 0x9775, //CJK UNIFIED IDEOGRAPH + 0xEC82: 0x9777, //CJK UNIFIED IDEOGRAPH + 0xEC83: 0x9778, //CJK UNIFIED IDEOGRAPH + 0xEC84: 0x9779, //CJK UNIFIED IDEOGRAPH + 0xEC85: 0x977A, //CJK UNIFIED IDEOGRAPH + 0xEC86: 0x977B, //CJK UNIFIED IDEOGRAPH + 0xEC87: 0x977D, //CJK UNIFIED IDEOGRAPH + 0xEC88: 0x977E, //CJK UNIFIED IDEOGRAPH + 0xEC89: 0x977F, //CJK UNIFIED IDEOGRAPH + 0xEC8A: 0x9780, //CJK UNIFIED IDEOGRAPH + 0xEC8B: 0x9781, //CJK UNIFIED IDEOGRAPH + 0xEC8C: 0x9782, //CJK UNIFIED IDEOGRAPH + 0xEC8D: 0x9783, //CJK UNIFIED IDEOGRAPH + 0xEC8E: 0x9784, //CJK UNIFIED IDEOGRAPH + 0xEC8F: 0x9786, //CJK UNIFIED IDEOGRAPH + 0xEC90: 0x9787, //CJK UNIFIED IDEOGRAPH + 0xEC91: 0x9788, //CJK UNIFIED IDEOGRAPH + 0xEC92: 0x9789, //CJK UNIFIED IDEOGRAPH + 0xEC93: 0x978A, //CJK UNIFIED IDEOGRAPH + 0xEC94: 0x978C, //CJK UNIFIED IDEOGRAPH + 0xEC95: 0x978E, //CJK UNIFIED IDEOGRAPH + 0xEC96: 0x978F, //CJK UNIFIED IDEOGRAPH + 0xEC97: 0x9790, //CJK UNIFIED IDEOGRAPH + 0xEC98: 0x9793, //CJK UNIFIED IDEOGRAPH + 0xEC99: 0x9795, //CJK UNIFIED IDEOGRAPH + 0xEC9A: 0x9796, //CJK UNIFIED IDEOGRAPH + 0xEC9B: 0x9797, //CJK UNIFIED IDEOGRAPH + 0xEC9C: 0x9799, //CJK UNIFIED IDEOGRAPH + 0xEC9D: 0x979A, //CJK UNIFIED IDEOGRAPH + 0xEC9E: 0x979B, //CJK UNIFIED IDEOGRAPH + 0xEC9F: 0x979C, //CJK UNIFIED IDEOGRAPH + 0xECA0: 0x979D, //CJK UNIFIED IDEOGRAPH + 0xECA1: 0x81C1, //CJK UNIFIED IDEOGRAPH + 0xECA2: 0x81A6, //CJK UNIFIED IDEOGRAPH + 0xECA3: 0x6B24, //CJK UNIFIED IDEOGRAPH + 0xECA4: 0x6B37, //CJK UNIFIED IDEOGRAPH + 0xECA5: 0x6B39, //CJK UNIFIED IDEOGRAPH + 0xECA6: 0x6B43, //CJK UNIFIED IDEOGRAPH + 0xECA7: 0x6B46, //CJK UNIFIED IDEOGRAPH + 0xECA8: 0x6B59, //CJK UNIFIED IDEOGRAPH + 0xECA9: 0x98D1, //CJK UNIFIED IDEOGRAPH + 0xECAA: 0x98D2, //CJK UNIFIED IDEOGRAPH + 0xECAB: 0x98D3, //CJK UNIFIED IDEOGRAPH + 0xECAC: 0x98D5, //CJK UNIFIED IDEOGRAPH + 0xECAD: 0x98D9, //CJK UNIFIED IDEOGRAPH + 0xECAE: 0x98DA, //CJK UNIFIED IDEOGRAPH + 0xECAF: 0x6BB3, //CJK UNIFIED IDEOGRAPH + 0xECB0: 0x5F40, //CJK UNIFIED IDEOGRAPH + 0xECB1: 0x6BC2, //CJK UNIFIED IDEOGRAPH + 0xECB2: 0x89F3, //CJK UNIFIED IDEOGRAPH + 0xECB3: 0x6590, //CJK UNIFIED IDEOGRAPH + 0xECB4: 0x9F51, //CJK UNIFIED IDEOGRAPH + 0xECB5: 0x6593, //CJK UNIFIED IDEOGRAPH + 0xECB6: 0x65BC, //CJK UNIFIED IDEOGRAPH + 0xECB7: 0x65C6, //CJK UNIFIED IDEOGRAPH + 0xECB8: 0x65C4, //CJK UNIFIED IDEOGRAPH + 0xECB9: 0x65C3, //CJK UNIFIED IDEOGRAPH + 0xECBA: 0x65CC, //CJK UNIFIED IDEOGRAPH + 0xECBB: 0x65CE, //CJK UNIFIED IDEOGRAPH + 0xECBC: 0x65D2, //CJK UNIFIED IDEOGRAPH + 0xECBD: 0x65D6, //CJK UNIFIED IDEOGRAPH + 0xECBE: 0x7080, //CJK UNIFIED IDEOGRAPH + 0xECBF: 0x709C, //CJK UNIFIED IDEOGRAPH + 0xECC0: 0x7096, //CJK UNIFIED IDEOGRAPH + 0xECC1: 0x709D, //CJK UNIFIED IDEOGRAPH + 0xECC2: 0x70BB, //CJK UNIFIED IDEOGRAPH + 0xECC3: 0x70C0, //CJK UNIFIED IDEOGRAPH + 0xECC4: 0x70B7, //CJK UNIFIED IDEOGRAPH + 0xECC5: 0x70AB, //CJK UNIFIED IDEOGRAPH + 0xECC6: 0x70B1, //CJK UNIFIED IDEOGRAPH + 0xECC7: 0x70E8, //CJK UNIFIED IDEOGRAPH + 0xECC8: 0x70CA, //CJK UNIFIED IDEOGRAPH + 0xECC9: 0x7110, //CJK UNIFIED IDEOGRAPH + 0xECCA: 0x7113, //CJK UNIFIED IDEOGRAPH + 0xECCB: 0x7116, //CJK UNIFIED IDEOGRAPH + 0xECCC: 0x712F, //CJK UNIFIED IDEOGRAPH + 0xECCD: 0x7131, //CJK UNIFIED IDEOGRAPH + 0xECCE: 0x7173, //CJK UNIFIED IDEOGRAPH + 0xECCF: 0x715C, //CJK UNIFIED IDEOGRAPH + 0xECD0: 0x7168, //CJK UNIFIED IDEOGRAPH + 0xECD1: 0x7145, //CJK UNIFIED IDEOGRAPH + 0xECD2: 0x7172, //CJK UNIFIED IDEOGRAPH + 0xECD3: 0x714A, //CJK UNIFIED IDEOGRAPH + 0xECD4: 0x7178, //CJK UNIFIED IDEOGRAPH + 0xECD5: 0x717A, //CJK UNIFIED IDEOGRAPH + 0xECD6: 0x7198, //CJK UNIFIED IDEOGRAPH + 0xECD7: 0x71B3, //CJK UNIFIED IDEOGRAPH + 0xECD8: 0x71B5, //CJK UNIFIED IDEOGRAPH + 0xECD9: 0x71A8, //CJK UNIFIED IDEOGRAPH + 0xECDA: 0x71A0, //CJK UNIFIED IDEOGRAPH + 0xECDB: 0x71E0, //CJK UNIFIED IDEOGRAPH + 0xECDC: 0x71D4, //CJK UNIFIED IDEOGRAPH + 0xECDD: 0x71E7, //CJK UNIFIED IDEOGRAPH + 0xECDE: 0x71F9, //CJK UNIFIED IDEOGRAPH + 0xECDF: 0x721D, //CJK UNIFIED IDEOGRAPH + 0xECE0: 0x7228, //CJK UNIFIED IDEOGRAPH + 0xECE1: 0x706C, //CJK UNIFIED IDEOGRAPH + 0xECE2: 0x7118, //CJK UNIFIED IDEOGRAPH + 0xECE3: 0x7166, //CJK UNIFIED IDEOGRAPH + 0xECE4: 0x71B9, //CJK UNIFIED IDEOGRAPH + 0xECE5: 0x623E, //CJK UNIFIED IDEOGRAPH + 0xECE6: 0x623D, //CJK UNIFIED IDEOGRAPH + 0xECE7: 0x6243, //CJK UNIFIED IDEOGRAPH + 0xECE8: 0x6248, //CJK UNIFIED IDEOGRAPH + 0xECE9: 0x6249, //CJK UNIFIED IDEOGRAPH + 0xECEA: 0x793B, //CJK UNIFIED IDEOGRAPH + 0xECEB: 0x7940, //CJK UNIFIED IDEOGRAPH + 0xECEC: 0x7946, //CJK UNIFIED IDEOGRAPH + 0xECED: 0x7949, //CJK UNIFIED IDEOGRAPH + 0xECEE: 0x795B, //CJK UNIFIED IDEOGRAPH + 0xECEF: 0x795C, //CJK UNIFIED IDEOGRAPH + 0xECF0: 0x7953, //CJK UNIFIED IDEOGRAPH + 0xECF1: 0x795A, //CJK UNIFIED IDEOGRAPH + 0xECF2: 0x7962, //CJK UNIFIED IDEOGRAPH + 0xECF3: 0x7957, //CJK UNIFIED IDEOGRAPH + 0xECF4: 0x7960, //CJK UNIFIED IDEOGRAPH + 0xECF5: 0x796F, //CJK UNIFIED IDEOGRAPH + 0xECF6: 0x7967, //CJK UNIFIED IDEOGRAPH + 0xECF7: 0x797A, //CJK UNIFIED IDEOGRAPH + 0xECF8: 0x7985, //CJK UNIFIED IDEOGRAPH + 0xECF9: 0x798A, //CJK UNIFIED IDEOGRAPH + 0xECFA: 0x799A, //CJK UNIFIED IDEOGRAPH + 0xECFB: 0x79A7, //CJK UNIFIED IDEOGRAPH + 0xECFC: 0x79B3, //CJK UNIFIED IDEOGRAPH + 0xECFD: 0x5FD1, //CJK UNIFIED IDEOGRAPH + 0xECFE: 0x5FD0, //CJK UNIFIED IDEOGRAPH + 0xED40: 0x979E, //CJK UNIFIED IDEOGRAPH + 0xED41: 0x979F, //CJK UNIFIED IDEOGRAPH + 0xED42: 0x97A1, //CJK UNIFIED IDEOGRAPH + 0xED43: 0x97A2, //CJK UNIFIED IDEOGRAPH + 0xED44: 0x97A4, //CJK UNIFIED IDEOGRAPH + 0xED45: 0x97A5, //CJK UNIFIED IDEOGRAPH + 0xED46: 0x97A6, //CJK UNIFIED IDEOGRAPH + 0xED47: 0x97A7, //CJK UNIFIED IDEOGRAPH + 0xED48: 0x97A8, //CJK UNIFIED IDEOGRAPH + 0xED49: 0x97A9, //CJK UNIFIED IDEOGRAPH + 0xED4A: 0x97AA, //CJK UNIFIED IDEOGRAPH + 0xED4B: 0x97AC, //CJK UNIFIED IDEOGRAPH + 0xED4C: 0x97AE, //CJK UNIFIED IDEOGRAPH + 0xED4D: 0x97B0, //CJK UNIFIED IDEOGRAPH + 0xED4E: 0x97B1, //CJK UNIFIED IDEOGRAPH + 0xED4F: 0x97B3, //CJK UNIFIED IDEOGRAPH + 0xED50: 0x97B5, //CJK UNIFIED IDEOGRAPH + 0xED51: 0x97B6, //CJK UNIFIED IDEOGRAPH + 0xED52: 0x97B7, //CJK UNIFIED IDEOGRAPH + 0xED53: 0x97B8, //CJK UNIFIED IDEOGRAPH + 0xED54: 0x97B9, //CJK UNIFIED IDEOGRAPH + 0xED55: 0x97BA, //CJK UNIFIED IDEOGRAPH + 0xED56: 0x97BB, //CJK UNIFIED IDEOGRAPH + 0xED57: 0x97BC, //CJK UNIFIED IDEOGRAPH + 0xED58: 0x97BD, //CJK UNIFIED IDEOGRAPH + 0xED59: 0x97BE, //CJK UNIFIED IDEOGRAPH + 0xED5A: 0x97BF, //CJK UNIFIED IDEOGRAPH + 0xED5B: 0x97C0, //CJK UNIFIED IDEOGRAPH + 0xED5C: 0x97C1, //CJK UNIFIED IDEOGRAPH + 0xED5D: 0x97C2, //CJK UNIFIED IDEOGRAPH + 0xED5E: 0x97C3, //CJK UNIFIED IDEOGRAPH + 0xED5F: 0x97C4, //CJK UNIFIED IDEOGRAPH + 0xED60: 0x97C5, //CJK UNIFIED IDEOGRAPH + 0xED61: 0x97C6, //CJK UNIFIED IDEOGRAPH + 0xED62: 0x97C7, //CJK UNIFIED IDEOGRAPH + 0xED63: 0x97C8, //CJK UNIFIED IDEOGRAPH + 0xED64: 0x97C9, //CJK UNIFIED IDEOGRAPH + 0xED65: 0x97CA, //CJK UNIFIED IDEOGRAPH + 0xED66: 0x97CB, //CJK UNIFIED IDEOGRAPH + 0xED67: 0x97CC, //CJK UNIFIED IDEOGRAPH + 0xED68: 0x97CD, //CJK UNIFIED IDEOGRAPH + 0xED69: 0x97CE, //CJK UNIFIED IDEOGRAPH + 0xED6A: 0x97CF, //CJK UNIFIED IDEOGRAPH + 0xED6B: 0x97D0, //CJK UNIFIED IDEOGRAPH + 0xED6C: 0x97D1, //CJK UNIFIED IDEOGRAPH + 0xED6D: 0x97D2, //CJK UNIFIED IDEOGRAPH + 0xED6E: 0x97D3, //CJK UNIFIED IDEOGRAPH + 0xED6F: 0x97D4, //CJK UNIFIED IDEOGRAPH + 0xED70: 0x97D5, //CJK UNIFIED IDEOGRAPH + 0xED71: 0x97D6, //CJK UNIFIED IDEOGRAPH + 0xED72: 0x97D7, //CJK UNIFIED IDEOGRAPH + 0xED73: 0x97D8, //CJK UNIFIED IDEOGRAPH + 0xED74: 0x97D9, //CJK UNIFIED IDEOGRAPH + 0xED75: 0x97DA, //CJK UNIFIED IDEOGRAPH + 0xED76: 0x97DB, //CJK UNIFIED IDEOGRAPH + 0xED77: 0x97DC, //CJK UNIFIED IDEOGRAPH + 0xED78: 0x97DD, //CJK UNIFIED IDEOGRAPH + 0xED79: 0x97DE, //CJK UNIFIED IDEOGRAPH + 0xED7A: 0x97DF, //CJK UNIFIED IDEOGRAPH + 0xED7B: 0x97E0, //CJK UNIFIED IDEOGRAPH + 0xED7C: 0x97E1, //CJK UNIFIED IDEOGRAPH + 0xED7D: 0x97E2, //CJK UNIFIED IDEOGRAPH + 0xED7E: 0x97E3, //CJK UNIFIED IDEOGRAPH + 0xED80: 0x97E4, //CJK UNIFIED IDEOGRAPH + 0xED81: 0x97E5, //CJK UNIFIED IDEOGRAPH + 0xED82: 0x97E8, //CJK UNIFIED IDEOGRAPH + 0xED83: 0x97EE, //CJK UNIFIED IDEOGRAPH + 0xED84: 0x97EF, //CJK UNIFIED IDEOGRAPH + 0xED85: 0x97F0, //CJK UNIFIED IDEOGRAPH + 0xED86: 0x97F1, //CJK UNIFIED IDEOGRAPH + 0xED87: 0x97F2, //CJK UNIFIED IDEOGRAPH + 0xED88: 0x97F4, //CJK UNIFIED IDEOGRAPH + 0xED89: 0x97F7, //CJK UNIFIED IDEOGRAPH + 0xED8A: 0x97F8, //CJK UNIFIED IDEOGRAPH + 0xED8B: 0x97F9, //CJK UNIFIED IDEOGRAPH + 0xED8C: 0x97FA, //CJK UNIFIED IDEOGRAPH + 0xED8D: 0x97FB, //CJK UNIFIED IDEOGRAPH + 0xED8E: 0x97FC, //CJK UNIFIED IDEOGRAPH + 0xED8F: 0x97FD, //CJK UNIFIED IDEOGRAPH + 0xED90: 0x97FE, //CJK UNIFIED IDEOGRAPH + 0xED91: 0x97FF, //CJK UNIFIED IDEOGRAPH + 0xED92: 0x9800, //CJK UNIFIED IDEOGRAPH + 0xED93: 0x9801, //CJK UNIFIED IDEOGRAPH + 0xED94: 0x9802, //CJK UNIFIED IDEOGRAPH + 0xED95: 0x9803, //CJK UNIFIED IDEOGRAPH + 0xED96: 0x9804, //CJK UNIFIED IDEOGRAPH + 0xED97: 0x9805, //CJK UNIFIED IDEOGRAPH + 0xED98: 0x9806, //CJK UNIFIED IDEOGRAPH + 0xED99: 0x9807, //CJK UNIFIED IDEOGRAPH + 0xED9A: 0x9808, //CJK UNIFIED IDEOGRAPH + 0xED9B: 0x9809, //CJK UNIFIED IDEOGRAPH + 0xED9C: 0x980A, //CJK UNIFIED IDEOGRAPH + 0xED9D: 0x980B, //CJK UNIFIED IDEOGRAPH + 0xED9E: 0x980C, //CJK UNIFIED IDEOGRAPH + 0xED9F: 0x980D, //CJK UNIFIED IDEOGRAPH + 0xEDA0: 0x980E, //CJK UNIFIED IDEOGRAPH + 0xEDA1: 0x603C, //CJK UNIFIED IDEOGRAPH + 0xEDA2: 0x605D, //CJK UNIFIED IDEOGRAPH + 0xEDA3: 0x605A, //CJK UNIFIED IDEOGRAPH + 0xEDA4: 0x6067, //CJK UNIFIED IDEOGRAPH + 0xEDA5: 0x6041, //CJK UNIFIED IDEOGRAPH + 0xEDA6: 0x6059, //CJK UNIFIED IDEOGRAPH + 0xEDA7: 0x6063, //CJK UNIFIED IDEOGRAPH + 0xEDA8: 0x60AB, //CJK UNIFIED IDEOGRAPH + 0xEDA9: 0x6106, //CJK UNIFIED IDEOGRAPH + 0xEDAA: 0x610D, //CJK UNIFIED IDEOGRAPH + 0xEDAB: 0x615D, //CJK UNIFIED IDEOGRAPH + 0xEDAC: 0x61A9, //CJK UNIFIED IDEOGRAPH + 0xEDAD: 0x619D, //CJK UNIFIED IDEOGRAPH + 0xEDAE: 0x61CB, //CJK UNIFIED IDEOGRAPH + 0xEDAF: 0x61D1, //CJK UNIFIED IDEOGRAPH + 0xEDB0: 0x6206, //CJK UNIFIED IDEOGRAPH + 0xEDB1: 0x8080, //CJK UNIFIED IDEOGRAPH + 0xEDB2: 0x807F, //CJK UNIFIED IDEOGRAPH + 0xEDB3: 0x6C93, //CJK UNIFIED IDEOGRAPH + 0xEDB4: 0x6CF6, //CJK UNIFIED IDEOGRAPH + 0xEDB5: 0x6DFC, //CJK UNIFIED IDEOGRAPH + 0xEDB6: 0x77F6, //CJK UNIFIED IDEOGRAPH + 0xEDB7: 0x77F8, //CJK UNIFIED IDEOGRAPH + 0xEDB8: 0x7800, //CJK UNIFIED IDEOGRAPH + 0xEDB9: 0x7809, //CJK UNIFIED IDEOGRAPH + 0xEDBA: 0x7817, //CJK UNIFIED IDEOGRAPH + 0xEDBB: 0x7818, //CJK UNIFIED IDEOGRAPH + 0xEDBC: 0x7811, //CJK UNIFIED IDEOGRAPH + 0xEDBD: 0x65AB, //CJK UNIFIED IDEOGRAPH + 0xEDBE: 0x782D, //CJK UNIFIED IDEOGRAPH + 0xEDBF: 0x781C, //CJK UNIFIED IDEOGRAPH + 0xEDC0: 0x781D, //CJK UNIFIED IDEOGRAPH + 0xEDC1: 0x7839, //CJK UNIFIED IDEOGRAPH + 0xEDC2: 0x783A, //CJK UNIFIED IDEOGRAPH + 0xEDC3: 0x783B, //CJK UNIFIED IDEOGRAPH + 0xEDC4: 0x781F, //CJK UNIFIED IDEOGRAPH + 0xEDC5: 0x783C, //CJK UNIFIED IDEOGRAPH + 0xEDC6: 0x7825, //CJK UNIFIED IDEOGRAPH + 0xEDC7: 0x782C, //CJK UNIFIED IDEOGRAPH + 0xEDC8: 0x7823, //CJK UNIFIED IDEOGRAPH + 0xEDC9: 0x7829, //CJK UNIFIED IDEOGRAPH + 0xEDCA: 0x784E, //CJK UNIFIED IDEOGRAPH + 0xEDCB: 0x786D, //CJK UNIFIED IDEOGRAPH + 0xEDCC: 0x7856, //CJK UNIFIED IDEOGRAPH + 0xEDCD: 0x7857, //CJK UNIFIED IDEOGRAPH + 0xEDCE: 0x7826, //CJK UNIFIED IDEOGRAPH + 0xEDCF: 0x7850, //CJK UNIFIED IDEOGRAPH + 0xEDD0: 0x7847, //CJK UNIFIED IDEOGRAPH + 0xEDD1: 0x784C, //CJK UNIFIED IDEOGRAPH + 0xEDD2: 0x786A, //CJK UNIFIED IDEOGRAPH + 0xEDD3: 0x789B, //CJK UNIFIED IDEOGRAPH + 0xEDD4: 0x7893, //CJK UNIFIED IDEOGRAPH + 0xEDD5: 0x789A, //CJK UNIFIED IDEOGRAPH + 0xEDD6: 0x7887, //CJK UNIFIED IDEOGRAPH + 0xEDD7: 0x789C, //CJK UNIFIED IDEOGRAPH + 0xEDD8: 0x78A1, //CJK UNIFIED IDEOGRAPH + 0xEDD9: 0x78A3, //CJK UNIFIED IDEOGRAPH + 0xEDDA: 0x78B2, //CJK UNIFIED IDEOGRAPH + 0xEDDB: 0x78B9, //CJK UNIFIED IDEOGRAPH + 0xEDDC: 0x78A5, //CJK UNIFIED IDEOGRAPH + 0xEDDD: 0x78D4, //CJK UNIFIED IDEOGRAPH + 0xEDDE: 0x78D9, //CJK UNIFIED IDEOGRAPH + 0xEDDF: 0x78C9, //CJK UNIFIED IDEOGRAPH + 0xEDE0: 0x78EC, //CJK UNIFIED IDEOGRAPH + 0xEDE1: 0x78F2, //CJK UNIFIED IDEOGRAPH + 0xEDE2: 0x7905, //CJK UNIFIED IDEOGRAPH + 0xEDE3: 0x78F4, //CJK UNIFIED IDEOGRAPH + 0xEDE4: 0x7913, //CJK UNIFIED IDEOGRAPH + 0xEDE5: 0x7924, //CJK UNIFIED IDEOGRAPH + 0xEDE6: 0x791E, //CJK UNIFIED IDEOGRAPH + 0xEDE7: 0x7934, //CJK UNIFIED IDEOGRAPH + 0xEDE8: 0x9F9B, //CJK UNIFIED IDEOGRAPH + 0xEDE9: 0x9EF9, //CJK UNIFIED IDEOGRAPH + 0xEDEA: 0x9EFB, //CJK UNIFIED IDEOGRAPH + 0xEDEB: 0x9EFC, //CJK UNIFIED IDEOGRAPH + 0xEDEC: 0x76F1, //CJK UNIFIED IDEOGRAPH + 0xEDED: 0x7704, //CJK UNIFIED IDEOGRAPH + 0xEDEE: 0x770D, //CJK UNIFIED IDEOGRAPH + 0xEDEF: 0x76F9, //CJK UNIFIED IDEOGRAPH + 0xEDF0: 0x7707, //CJK UNIFIED IDEOGRAPH + 0xEDF1: 0x7708, //CJK UNIFIED IDEOGRAPH + 0xEDF2: 0x771A, //CJK UNIFIED IDEOGRAPH + 0xEDF3: 0x7722, //CJK UNIFIED IDEOGRAPH + 0xEDF4: 0x7719, //CJK UNIFIED IDEOGRAPH + 0xEDF5: 0x772D, //CJK UNIFIED IDEOGRAPH + 0xEDF6: 0x7726, //CJK UNIFIED IDEOGRAPH + 0xEDF7: 0x7735, //CJK UNIFIED IDEOGRAPH + 0xEDF8: 0x7738, //CJK UNIFIED IDEOGRAPH + 0xEDF9: 0x7750, //CJK UNIFIED IDEOGRAPH + 0xEDFA: 0x7751, //CJK UNIFIED IDEOGRAPH + 0xEDFB: 0x7747, //CJK UNIFIED IDEOGRAPH + 0xEDFC: 0x7743, //CJK UNIFIED IDEOGRAPH + 0xEDFD: 0x775A, //CJK UNIFIED IDEOGRAPH + 0xEDFE: 0x7768, //CJK UNIFIED IDEOGRAPH + 0xEE40: 0x980F, //CJK UNIFIED IDEOGRAPH + 0xEE41: 0x9810, //CJK UNIFIED IDEOGRAPH + 0xEE42: 0x9811, //CJK UNIFIED IDEOGRAPH + 0xEE43: 0x9812, //CJK UNIFIED IDEOGRAPH + 0xEE44: 0x9813, //CJK UNIFIED IDEOGRAPH + 0xEE45: 0x9814, //CJK UNIFIED IDEOGRAPH + 0xEE46: 0x9815, //CJK UNIFIED IDEOGRAPH + 0xEE47: 0x9816, //CJK UNIFIED IDEOGRAPH + 0xEE48: 0x9817, //CJK UNIFIED IDEOGRAPH + 0xEE49: 0x9818, //CJK UNIFIED IDEOGRAPH + 0xEE4A: 0x9819, //CJK UNIFIED IDEOGRAPH + 0xEE4B: 0x981A, //CJK UNIFIED IDEOGRAPH + 0xEE4C: 0x981B, //CJK UNIFIED IDEOGRAPH + 0xEE4D: 0x981C, //CJK UNIFIED IDEOGRAPH + 0xEE4E: 0x981D, //CJK UNIFIED IDEOGRAPH + 0xEE4F: 0x981E, //CJK UNIFIED IDEOGRAPH + 0xEE50: 0x981F, //CJK UNIFIED IDEOGRAPH + 0xEE51: 0x9820, //CJK UNIFIED IDEOGRAPH + 0xEE52: 0x9821, //CJK UNIFIED IDEOGRAPH + 0xEE53: 0x9822, //CJK UNIFIED IDEOGRAPH + 0xEE54: 0x9823, //CJK UNIFIED IDEOGRAPH + 0xEE55: 0x9824, //CJK UNIFIED IDEOGRAPH + 0xEE56: 0x9825, //CJK UNIFIED IDEOGRAPH + 0xEE57: 0x9826, //CJK UNIFIED IDEOGRAPH + 0xEE58: 0x9827, //CJK UNIFIED IDEOGRAPH + 0xEE59: 0x9828, //CJK UNIFIED IDEOGRAPH + 0xEE5A: 0x9829, //CJK UNIFIED IDEOGRAPH + 0xEE5B: 0x982A, //CJK UNIFIED IDEOGRAPH + 0xEE5C: 0x982B, //CJK UNIFIED IDEOGRAPH + 0xEE5D: 0x982C, //CJK UNIFIED IDEOGRAPH + 0xEE5E: 0x982D, //CJK UNIFIED IDEOGRAPH + 0xEE5F: 0x982E, //CJK UNIFIED IDEOGRAPH + 0xEE60: 0x982F, //CJK UNIFIED IDEOGRAPH + 0xEE61: 0x9830, //CJK UNIFIED IDEOGRAPH + 0xEE62: 0x9831, //CJK UNIFIED IDEOGRAPH + 0xEE63: 0x9832, //CJK UNIFIED IDEOGRAPH + 0xEE64: 0x9833, //CJK UNIFIED IDEOGRAPH + 0xEE65: 0x9834, //CJK UNIFIED IDEOGRAPH + 0xEE66: 0x9835, //CJK UNIFIED IDEOGRAPH + 0xEE67: 0x9836, //CJK UNIFIED IDEOGRAPH + 0xEE68: 0x9837, //CJK UNIFIED IDEOGRAPH + 0xEE69: 0x9838, //CJK UNIFIED IDEOGRAPH + 0xEE6A: 0x9839, //CJK UNIFIED IDEOGRAPH + 0xEE6B: 0x983A, //CJK UNIFIED IDEOGRAPH + 0xEE6C: 0x983B, //CJK UNIFIED IDEOGRAPH + 0xEE6D: 0x983C, //CJK UNIFIED IDEOGRAPH + 0xEE6E: 0x983D, //CJK UNIFIED IDEOGRAPH + 0xEE6F: 0x983E, //CJK UNIFIED IDEOGRAPH + 0xEE70: 0x983F, //CJK UNIFIED IDEOGRAPH + 0xEE71: 0x9840, //CJK UNIFIED IDEOGRAPH + 0xEE72: 0x9841, //CJK UNIFIED IDEOGRAPH + 0xEE73: 0x9842, //CJK UNIFIED IDEOGRAPH + 0xEE74: 0x9843, //CJK UNIFIED IDEOGRAPH + 0xEE75: 0x9844, //CJK UNIFIED IDEOGRAPH + 0xEE76: 0x9845, //CJK UNIFIED IDEOGRAPH + 0xEE77: 0x9846, //CJK UNIFIED IDEOGRAPH + 0xEE78: 0x9847, //CJK UNIFIED IDEOGRAPH + 0xEE79: 0x9848, //CJK UNIFIED IDEOGRAPH + 0xEE7A: 0x9849, //CJK UNIFIED IDEOGRAPH + 0xEE7B: 0x984A, //CJK UNIFIED IDEOGRAPH + 0xEE7C: 0x984B, //CJK UNIFIED IDEOGRAPH + 0xEE7D: 0x984C, //CJK UNIFIED IDEOGRAPH + 0xEE7E: 0x984D, //CJK UNIFIED IDEOGRAPH + 0xEE80: 0x984E, //CJK UNIFIED IDEOGRAPH + 0xEE81: 0x984F, //CJK UNIFIED IDEOGRAPH + 0xEE82: 0x9850, //CJK UNIFIED IDEOGRAPH + 0xEE83: 0x9851, //CJK UNIFIED IDEOGRAPH + 0xEE84: 0x9852, //CJK UNIFIED IDEOGRAPH + 0xEE85: 0x9853, //CJK UNIFIED IDEOGRAPH + 0xEE86: 0x9854, //CJK UNIFIED IDEOGRAPH + 0xEE87: 0x9855, //CJK UNIFIED IDEOGRAPH + 0xEE88: 0x9856, //CJK UNIFIED IDEOGRAPH + 0xEE89: 0x9857, //CJK UNIFIED IDEOGRAPH + 0xEE8A: 0x9858, //CJK UNIFIED IDEOGRAPH + 0xEE8B: 0x9859, //CJK UNIFIED IDEOGRAPH + 0xEE8C: 0x985A, //CJK UNIFIED IDEOGRAPH + 0xEE8D: 0x985B, //CJK UNIFIED IDEOGRAPH + 0xEE8E: 0x985C, //CJK UNIFIED IDEOGRAPH + 0xEE8F: 0x985D, //CJK UNIFIED IDEOGRAPH + 0xEE90: 0x985E, //CJK UNIFIED IDEOGRAPH + 0xEE91: 0x985F, //CJK UNIFIED IDEOGRAPH + 0xEE92: 0x9860, //CJK UNIFIED IDEOGRAPH + 0xEE93: 0x9861, //CJK UNIFIED IDEOGRAPH + 0xEE94: 0x9862, //CJK UNIFIED IDEOGRAPH + 0xEE95: 0x9863, //CJK UNIFIED IDEOGRAPH + 0xEE96: 0x9864, //CJK UNIFIED IDEOGRAPH + 0xEE97: 0x9865, //CJK UNIFIED IDEOGRAPH + 0xEE98: 0x9866, //CJK UNIFIED IDEOGRAPH + 0xEE99: 0x9867, //CJK UNIFIED IDEOGRAPH + 0xEE9A: 0x9868, //CJK UNIFIED IDEOGRAPH + 0xEE9B: 0x9869, //CJK UNIFIED IDEOGRAPH + 0xEE9C: 0x986A, //CJK UNIFIED IDEOGRAPH + 0xEE9D: 0x986B, //CJK UNIFIED IDEOGRAPH + 0xEE9E: 0x986C, //CJK UNIFIED IDEOGRAPH + 0xEE9F: 0x986D, //CJK UNIFIED IDEOGRAPH + 0xEEA0: 0x986E, //CJK UNIFIED IDEOGRAPH + 0xEEA1: 0x7762, //CJK UNIFIED IDEOGRAPH + 0xEEA2: 0x7765, //CJK UNIFIED IDEOGRAPH + 0xEEA3: 0x777F, //CJK UNIFIED IDEOGRAPH + 0xEEA4: 0x778D, //CJK UNIFIED IDEOGRAPH + 0xEEA5: 0x777D, //CJK UNIFIED IDEOGRAPH + 0xEEA6: 0x7780, //CJK UNIFIED IDEOGRAPH + 0xEEA7: 0x778C, //CJK UNIFIED IDEOGRAPH + 0xEEA8: 0x7791, //CJK UNIFIED IDEOGRAPH + 0xEEA9: 0x779F, //CJK UNIFIED IDEOGRAPH + 0xEEAA: 0x77A0, //CJK UNIFIED IDEOGRAPH + 0xEEAB: 0x77B0, //CJK UNIFIED IDEOGRAPH + 0xEEAC: 0x77B5, //CJK UNIFIED IDEOGRAPH + 0xEEAD: 0x77BD, //CJK UNIFIED IDEOGRAPH + 0xEEAE: 0x753A, //CJK UNIFIED IDEOGRAPH + 0xEEAF: 0x7540, //CJK UNIFIED IDEOGRAPH + 0xEEB0: 0x754E, //CJK UNIFIED IDEOGRAPH + 0xEEB1: 0x754B, //CJK UNIFIED IDEOGRAPH + 0xEEB2: 0x7548, //CJK UNIFIED IDEOGRAPH + 0xEEB3: 0x755B, //CJK UNIFIED IDEOGRAPH + 0xEEB4: 0x7572, //CJK UNIFIED IDEOGRAPH + 0xEEB5: 0x7579, //CJK UNIFIED IDEOGRAPH + 0xEEB6: 0x7583, //CJK UNIFIED IDEOGRAPH + 0xEEB7: 0x7F58, //CJK UNIFIED IDEOGRAPH + 0xEEB8: 0x7F61, //CJK UNIFIED IDEOGRAPH + 0xEEB9: 0x7F5F, //CJK UNIFIED IDEOGRAPH + 0xEEBA: 0x8A48, //CJK UNIFIED IDEOGRAPH + 0xEEBB: 0x7F68, //CJK UNIFIED IDEOGRAPH + 0xEEBC: 0x7F74, //CJK UNIFIED IDEOGRAPH + 0xEEBD: 0x7F71, //CJK UNIFIED IDEOGRAPH + 0xEEBE: 0x7F79, //CJK UNIFIED IDEOGRAPH + 0xEEBF: 0x7F81, //CJK UNIFIED IDEOGRAPH + 0xEEC0: 0x7F7E, //CJK UNIFIED IDEOGRAPH + 0xEEC1: 0x76CD, //CJK UNIFIED IDEOGRAPH + 0xEEC2: 0x76E5, //CJK UNIFIED IDEOGRAPH + 0xEEC3: 0x8832, //CJK UNIFIED IDEOGRAPH + 0xEEC4: 0x9485, //CJK UNIFIED IDEOGRAPH + 0xEEC5: 0x9486, //CJK UNIFIED IDEOGRAPH + 0xEEC6: 0x9487, //CJK UNIFIED IDEOGRAPH + 0xEEC7: 0x948B, //CJK UNIFIED IDEOGRAPH + 0xEEC8: 0x948A, //CJK UNIFIED IDEOGRAPH + 0xEEC9: 0x948C, //CJK UNIFIED IDEOGRAPH + 0xEECA: 0x948D, //CJK UNIFIED IDEOGRAPH + 0xEECB: 0x948F, //CJK UNIFIED IDEOGRAPH + 0xEECC: 0x9490, //CJK UNIFIED IDEOGRAPH + 0xEECD: 0x9494, //CJK UNIFIED IDEOGRAPH + 0xEECE: 0x9497, //CJK UNIFIED IDEOGRAPH + 0xEECF: 0x9495, //CJK UNIFIED IDEOGRAPH + 0xEED0: 0x949A, //CJK UNIFIED IDEOGRAPH + 0xEED1: 0x949B, //CJK UNIFIED IDEOGRAPH + 0xEED2: 0x949C, //CJK UNIFIED IDEOGRAPH + 0xEED3: 0x94A3, //CJK UNIFIED IDEOGRAPH + 0xEED4: 0x94A4, //CJK UNIFIED IDEOGRAPH + 0xEED5: 0x94AB, //CJK UNIFIED IDEOGRAPH + 0xEED6: 0x94AA, //CJK UNIFIED IDEOGRAPH + 0xEED7: 0x94AD, //CJK UNIFIED IDEOGRAPH + 0xEED8: 0x94AC, //CJK UNIFIED IDEOGRAPH + 0xEED9: 0x94AF, //CJK UNIFIED IDEOGRAPH + 0xEEDA: 0x94B0, //CJK UNIFIED IDEOGRAPH + 0xEEDB: 0x94B2, //CJK UNIFIED IDEOGRAPH + 0xEEDC: 0x94B4, //CJK UNIFIED IDEOGRAPH + 0xEEDD: 0x94B6, //CJK UNIFIED IDEOGRAPH + 0xEEDE: 0x94B7, //CJK UNIFIED IDEOGRAPH + 0xEEDF: 0x94B8, //CJK UNIFIED IDEOGRAPH + 0xEEE0: 0x94B9, //CJK UNIFIED IDEOGRAPH + 0xEEE1: 0x94BA, //CJK UNIFIED IDEOGRAPH + 0xEEE2: 0x94BC, //CJK UNIFIED IDEOGRAPH + 0xEEE3: 0x94BD, //CJK UNIFIED IDEOGRAPH + 0xEEE4: 0x94BF, //CJK UNIFIED IDEOGRAPH + 0xEEE5: 0x94C4, //CJK UNIFIED IDEOGRAPH + 0xEEE6: 0x94C8, //CJK UNIFIED IDEOGRAPH + 0xEEE7: 0x94C9, //CJK UNIFIED IDEOGRAPH + 0xEEE8: 0x94CA, //CJK UNIFIED IDEOGRAPH + 0xEEE9: 0x94CB, //CJK UNIFIED IDEOGRAPH + 0xEEEA: 0x94CC, //CJK UNIFIED IDEOGRAPH + 0xEEEB: 0x94CD, //CJK UNIFIED IDEOGRAPH + 0xEEEC: 0x94CE, //CJK UNIFIED IDEOGRAPH + 0xEEED: 0x94D0, //CJK UNIFIED IDEOGRAPH + 0xEEEE: 0x94D1, //CJK UNIFIED IDEOGRAPH + 0xEEEF: 0x94D2, //CJK UNIFIED IDEOGRAPH + 0xEEF0: 0x94D5, //CJK UNIFIED IDEOGRAPH + 0xEEF1: 0x94D6, //CJK UNIFIED IDEOGRAPH + 0xEEF2: 0x94D7, //CJK UNIFIED IDEOGRAPH + 0xEEF3: 0x94D9, //CJK UNIFIED IDEOGRAPH + 0xEEF4: 0x94D8, //CJK UNIFIED IDEOGRAPH + 0xEEF5: 0x94DB, //CJK UNIFIED IDEOGRAPH + 0xEEF6: 0x94DE, //CJK UNIFIED IDEOGRAPH + 0xEEF7: 0x94DF, //CJK UNIFIED IDEOGRAPH + 0xEEF8: 0x94E0, //CJK UNIFIED IDEOGRAPH + 0xEEF9: 0x94E2, //CJK UNIFIED IDEOGRAPH + 0xEEFA: 0x94E4, //CJK UNIFIED IDEOGRAPH + 0xEEFB: 0x94E5, //CJK UNIFIED IDEOGRAPH + 0xEEFC: 0x94E7, //CJK UNIFIED IDEOGRAPH + 0xEEFD: 0x94E8, //CJK UNIFIED IDEOGRAPH + 0xEEFE: 0x94EA, //CJK UNIFIED IDEOGRAPH + 0xEF40: 0x986F, //CJK UNIFIED IDEOGRAPH + 0xEF41: 0x9870, //CJK UNIFIED IDEOGRAPH + 0xEF42: 0x9871, //CJK UNIFIED IDEOGRAPH + 0xEF43: 0x9872, //CJK UNIFIED IDEOGRAPH + 0xEF44: 0x9873, //CJK UNIFIED IDEOGRAPH + 0xEF45: 0x9874, //CJK UNIFIED IDEOGRAPH + 0xEF46: 0x988B, //CJK UNIFIED IDEOGRAPH + 0xEF47: 0x988E, //CJK UNIFIED IDEOGRAPH + 0xEF48: 0x9892, //CJK UNIFIED IDEOGRAPH + 0xEF49: 0x9895, //CJK UNIFIED IDEOGRAPH + 0xEF4A: 0x9899, //CJK UNIFIED IDEOGRAPH + 0xEF4B: 0x98A3, //CJK UNIFIED IDEOGRAPH + 0xEF4C: 0x98A8, //CJK UNIFIED IDEOGRAPH + 0xEF4D: 0x98A9, //CJK UNIFIED IDEOGRAPH + 0xEF4E: 0x98AA, //CJK UNIFIED IDEOGRAPH + 0xEF4F: 0x98AB, //CJK UNIFIED IDEOGRAPH + 0xEF50: 0x98AC, //CJK UNIFIED IDEOGRAPH + 0xEF51: 0x98AD, //CJK UNIFIED IDEOGRAPH + 0xEF52: 0x98AE, //CJK UNIFIED IDEOGRAPH + 0xEF53: 0x98AF, //CJK UNIFIED IDEOGRAPH + 0xEF54: 0x98B0, //CJK UNIFIED IDEOGRAPH + 0xEF55: 0x98B1, //CJK UNIFIED IDEOGRAPH + 0xEF56: 0x98B2, //CJK UNIFIED IDEOGRAPH + 0xEF57: 0x98B3, //CJK UNIFIED IDEOGRAPH + 0xEF58: 0x98B4, //CJK UNIFIED IDEOGRAPH + 0xEF59: 0x98B5, //CJK UNIFIED IDEOGRAPH + 0xEF5A: 0x98B6, //CJK UNIFIED IDEOGRAPH + 0xEF5B: 0x98B7, //CJK UNIFIED IDEOGRAPH + 0xEF5C: 0x98B8, //CJK UNIFIED IDEOGRAPH + 0xEF5D: 0x98B9, //CJK UNIFIED IDEOGRAPH + 0xEF5E: 0x98BA, //CJK UNIFIED IDEOGRAPH + 0xEF5F: 0x98BB, //CJK UNIFIED IDEOGRAPH + 0xEF60: 0x98BC, //CJK UNIFIED IDEOGRAPH + 0xEF61: 0x98BD, //CJK UNIFIED IDEOGRAPH + 0xEF62: 0x98BE, //CJK UNIFIED IDEOGRAPH + 0xEF63: 0x98BF, //CJK UNIFIED IDEOGRAPH + 0xEF64: 0x98C0, //CJK UNIFIED IDEOGRAPH + 0xEF65: 0x98C1, //CJK UNIFIED IDEOGRAPH + 0xEF66: 0x98C2, //CJK UNIFIED IDEOGRAPH + 0xEF67: 0x98C3, //CJK UNIFIED IDEOGRAPH + 0xEF68: 0x98C4, //CJK UNIFIED IDEOGRAPH + 0xEF69: 0x98C5, //CJK UNIFIED IDEOGRAPH + 0xEF6A: 0x98C6, //CJK UNIFIED IDEOGRAPH + 0xEF6B: 0x98C7, //CJK UNIFIED IDEOGRAPH + 0xEF6C: 0x98C8, //CJK UNIFIED IDEOGRAPH + 0xEF6D: 0x98C9, //CJK UNIFIED IDEOGRAPH + 0xEF6E: 0x98CA, //CJK UNIFIED IDEOGRAPH + 0xEF6F: 0x98CB, //CJK UNIFIED IDEOGRAPH + 0xEF70: 0x98CC, //CJK UNIFIED IDEOGRAPH + 0xEF71: 0x98CD, //CJK UNIFIED IDEOGRAPH + 0xEF72: 0x98CF, //CJK UNIFIED IDEOGRAPH + 0xEF73: 0x98D0, //CJK UNIFIED IDEOGRAPH + 0xEF74: 0x98D4, //CJK UNIFIED IDEOGRAPH + 0xEF75: 0x98D6, //CJK UNIFIED IDEOGRAPH + 0xEF76: 0x98D7, //CJK UNIFIED IDEOGRAPH + 0xEF77: 0x98DB, //CJK UNIFIED IDEOGRAPH + 0xEF78: 0x98DC, //CJK UNIFIED IDEOGRAPH + 0xEF79: 0x98DD, //CJK UNIFIED IDEOGRAPH + 0xEF7A: 0x98E0, //CJK UNIFIED IDEOGRAPH + 0xEF7B: 0x98E1, //CJK UNIFIED IDEOGRAPH + 0xEF7C: 0x98E2, //CJK UNIFIED IDEOGRAPH + 0xEF7D: 0x98E3, //CJK UNIFIED IDEOGRAPH + 0xEF7E: 0x98E4, //CJK UNIFIED IDEOGRAPH + 0xEF80: 0x98E5, //CJK UNIFIED IDEOGRAPH + 0xEF81: 0x98E6, //CJK UNIFIED IDEOGRAPH + 0xEF82: 0x98E9, //CJK UNIFIED IDEOGRAPH + 0xEF83: 0x98EA, //CJK UNIFIED IDEOGRAPH + 0xEF84: 0x98EB, //CJK UNIFIED IDEOGRAPH + 0xEF85: 0x98EC, //CJK UNIFIED IDEOGRAPH + 0xEF86: 0x98ED, //CJK UNIFIED IDEOGRAPH + 0xEF87: 0x98EE, //CJK UNIFIED IDEOGRAPH + 0xEF88: 0x98EF, //CJK UNIFIED IDEOGRAPH + 0xEF89: 0x98F0, //CJK UNIFIED IDEOGRAPH + 0xEF8A: 0x98F1, //CJK UNIFIED IDEOGRAPH + 0xEF8B: 0x98F2, //CJK UNIFIED IDEOGRAPH + 0xEF8C: 0x98F3, //CJK UNIFIED IDEOGRAPH + 0xEF8D: 0x98F4, //CJK UNIFIED IDEOGRAPH + 0xEF8E: 0x98F5, //CJK UNIFIED IDEOGRAPH + 0xEF8F: 0x98F6, //CJK UNIFIED IDEOGRAPH + 0xEF90: 0x98F7, //CJK UNIFIED IDEOGRAPH + 0xEF91: 0x98F8, //CJK UNIFIED IDEOGRAPH + 0xEF92: 0x98F9, //CJK UNIFIED IDEOGRAPH + 0xEF93: 0x98FA, //CJK UNIFIED IDEOGRAPH + 0xEF94: 0x98FB, //CJK UNIFIED IDEOGRAPH + 0xEF95: 0x98FC, //CJK UNIFIED IDEOGRAPH + 0xEF96: 0x98FD, //CJK UNIFIED IDEOGRAPH + 0xEF97: 0x98FE, //CJK UNIFIED IDEOGRAPH + 0xEF98: 0x98FF, //CJK UNIFIED IDEOGRAPH + 0xEF99: 0x9900, //CJK UNIFIED IDEOGRAPH + 0xEF9A: 0x9901, //CJK UNIFIED IDEOGRAPH + 0xEF9B: 0x9902, //CJK UNIFIED IDEOGRAPH + 0xEF9C: 0x9903, //CJK UNIFIED IDEOGRAPH + 0xEF9D: 0x9904, //CJK UNIFIED IDEOGRAPH + 0xEF9E: 0x9905, //CJK UNIFIED IDEOGRAPH + 0xEF9F: 0x9906, //CJK UNIFIED IDEOGRAPH + 0xEFA0: 0x9907, //CJK UNIFIED IDEOGRAPH + 0xEFA1: 0x94E9, //CJK UNIFIED IDEOGRAPH + 0xEFA2: 0x94EB, //CJK UNIFIED IDEOGRAPH + 0xEFA3: 0x94EE, //CJK UNIFIED IDEOGRAPH + 0xEFA4: 0x94EF, //CJK UNIFIED IDEOGRAPH + 0xEFA5: 0x94F3, //CJK UNIFIED IDEOGRAPH + 0xEFA6: 0x94F4, //CJK UNIFIED IDEOGRAPH + 0xEFA7: 0x94F5, //CJK UNIFIED IDEOGRAPH + 0xEFA8: 0x94F7, //CJK UNIFIED IDEOGRAPH + 0xEFA9: 0x94F9, //CJK UNIFIED IDEOGRAPH + 0xEFAA: 0x94FC, //CJK UNIFIED IDEOGRAPH + 0xEFAB: 0x94FD, //CJK UNIFIED IDEOGRAPH + 0xEFAC: 0x94FF, //CJK UNIFIED IDEOGRAPH + 0xEFAD: 0x9503, //CJK UNIFIED IDEOGRAPH + 0xEFAE: 0x9502, //CJK UNIFIED IDEOGRAPH + 0xEFAF: 0x9506, //CJK UNIFIED IDEOGRAPH + 0xEFB0: 0x9507, //CJK UNIFIED IDEOGRAPH + 0xEFB1: 0x9509, //CJK UNIFIED IDEOGRAPH + 0xEFB2: 0x950A, //CJK UNIFIED IDEOGRAPH + 0xEFB3: 0x950D, //CJK UNIFIED IDEOGRAPH + 0xEFB4: 0x950E, //CJK UNIFIED IDEOGRAPH + 0xEFB5: 0x950F, //CJK UNIFIED IDEOGRAPH + 0xEFB6: 0x9512, //CJK UNIFIED IDEOGRAPH + 0xEFB7: 0x9513, //CJK UNIFIED IDEOGRAPH + 0xEFB8: 0x9514, //CJK UNIFIED IDEOGRAPH + 0xEFB9: 0x9515, //CJK UNIFIED IDEOGRAPH + 0xEFBA: 0x9516, //CJK UNIFIED IDEOGRAPH + 0xEFBB: 0x9518, //CJK UNIFIED IDEOGRAPH + 0xEFBC: 0x951B, //CJK UNIFIED IDEOGRAPH + 0xEFBD: 0x951D, //CJK UNIFIED IDEOGRAPH + 0xEFBE: 0x951E, //CJK UNIFIED IDEOGRAPH + 0xEFBF: 0x951F, //CJK UNIFIED IDEOGRAPH + 0xEFC0: 0x9522, //CJK UNIFIED IDEOGRAPH + 0xEFC1: 0x952A, //CJK UNIFIED IDEOGRAPH + 0xEFC2: 0x952B, //CJK UNIFIED IDEOGRAPH + 0xEFC3: 0x9529, //CJK UNIFIED IDEOGRAPH + 0xEFC4: 0x952C, //CJK UNIFIED IDEOGRAPH + 0xEFC5: 0x9531, //CJK UNIFIED IDEOGRAPH + 0xEFC6: 0x9532, //CJK UNIFIED IDEOGRAPH + 0xEFC7: 0x9534, //CJK UNIFIED IDEOGRAPH + 0xEFC8: 0x9536, //CJK UNIFIED IDEOGRAPH + 0xEFC9: 0x9537, //CJK UNIFIED IDEOGRAPH + 0xEFCA: 0x9538, //CJK UNIFIED IDEOGRAPH + 0xEFCB: 0x953C, //CJK UNIFIED IDEOGRAPH + 0xEFCC: 0x953E, //CJK UNIFIED IDEOGRAPH + 0xEFCD: 0x953F, //CJK UNIFIED IDEOGRAPH + 0xEFCE: 0x9542, //CJK UNIFIED IDEOGRAPH + 0xEFCF: 0x9535, //CJK UNIFIED IDEOGRAPH + 0xEFD0: 0x9544, //CJK UNIFIED IDEOGRAPH + 0xEFD1: 0x9545, //CJK UNIFIED IDEOGRAPH + 0xEFD2: 0x9546, //CJK UNIFIED IDEOGRAPH + 0xEFD3: 0x9549, //CJK UNIFIED IDEOGRAPH + 0xEFD4: 0x954C, //CJK UNIFIED IDEOGRAPH + 0xEFD5: 0x954E, //CJK UNIFIED IDEOGRAPH + 0xEFD6: 0x954F, //CJK UNIFIED IDEOGRAPH + 0xEFD7: 0x9552, //CJK UNIFIED IDEOGRAPH + 0xEFD8: 0x9553, //CJK UNIFIED IDEOGRAPH + 0xEFD9: 0x9554, //CJK UNIFIED IDEOGRAPH + 0xEFDA: 0x9556, //CJK UNIFIED IDEOGRAPH + 0xEFDB: 0x9557, //CJK UNIFIED IDEOGRAPH + 0xEFDC: 0x9558, //CJK UNIFIED IDEOGRAPH + 0xEFDD: 0x9559, //CJK UNIFIED IDEOGRAPH + 0xEFDE: 0x955B, //CJK UNIFIED IDEOGRAPH + 0xEFDF: 0x955E, //CJK UNIFIED IDEOGRAPH + 0xEFE0: 0x955F, //CJK UNIFIED IDEOGRAPH + 0xEFE1: 0x955D, //CJK UNIFIED IDEOGRAPH + 0xEFE2: 0x9561, //CJK UNIFIED IDEOGRAPH + 0xEFE3: 0x9562, //CJK UNIFIED IDEOGRAPH + 0xEFE4: 0x9564, //CJK UNIFIED IDEOGRAPH + 0xEFE5: 0x9565, //CJK UNIFIED IDEOGRAPH + 0xEFE6: 0x9566, //CJK UNIFIED IDEOGRAPH + 0xEFE7: 0x9567, //CJK UNIFIED IDEOGRAPH + 0xEFE8: 0x9568, //CJK UNIFIED IDEOGRAPH + 0xEFE9: 0x9569, //CJK UNIFIED IDEOGRAPH + 0xEFEA: 0x956A, //CJK UNIFIED IDEOGRAPH + 0xEFEB: 0x956B, //CJK UNIFIED IDEOGRAPH + 0xEFEC: 0x956C, //CJK UNIFIED IDEOGRAPH + 0xEFED: 0x956F, //CJK UNIFIED IDEOGRAPH + 0xEFEE: 0x9571, //CJK UNIFIED IDEOGRAPH + 0xEFEF: 0x9572, //CJK UNIFIED IDEOGRAPH + 0xEFF0: 0x9573, //CJK UNIFIED IDEOGRAPH + 0xEFF1: 0x953A, //CJK UNIFIED IDEOGRAPH + 0xEFF2: 0x77E7, //CJK UNIFIED IDEOGRAPH + 0xEFF3: 0x77EC, //CJK UNIFIED IDEOGRAPH + 0xEFF4: 0x96C9, //CJK UNIFIED IDEOGRAPH + 0xEFF5: 0x79D5, //CJK UNIFIED IDEOGRAPH + 0xEFF6: 0x79ED, //CJK UNIFIED IDEOGRAPH + 0xEFF7: 0x79E3, //CJK UNIFIED IDEOGRAPH + 0xEFF8: 0x79EB, //CJK UNIFIED IDEOGRAPH + 0xEFF9: 0x7A06, //CJK UNIFIED IDEOGRAPH + 0xEFFA: 0x5D47, //CJK UNIFIED IDEOGRAPH + 0xEFFB: 0x7A03, //CJK UNIFIED IDEOGRAPH + 0xEFFC: 0x7A02, //CJK UNIFIED IDEOGRAPH + 0xEFFD: 0x7A1E, //CJK UNIFIED IDEOGRAPH + 0xEFFE: 0x7A14, //CJK UNIFIED IDEOGRAPH + 0xF040: 0x9908, //CJK UNIFIED IDEOGRAPH + 0xF041: 0x9909, //CJK UNIFIED IDEOGRAPH + 0xF042: 0x990A, //CJK UNIFIED IDEOGRAPH + 0xF043: 0x990B, //CJK UNIFIED IDEOGRAPH + 0xF044: 0x990C, //CJK UNIFIED IDEOGRAPH + 0xF045: 0x990E, //CJK UNIFIED IDEOGRAPH + 0xF046: 0x990F, //CJK UNIFIED IDEOGRAPH + 0xF047: 0x9911, //CJK UNIFIED IDEOGRAPH + 0xF048: 0x9912, //CJK UNIFIED IDEOGRAPH + 0xF049: 0x9913, //CJK UNIFIED IDEOGRAPH + 0xF04A: 0x9914, //CJK UNIFIED IDEOGRAPH + 0xF04B: 0x9915, //CJK UNIFIED IDEOGRAPH + 0xF04C: 0x9916, //CJK UNIFIED IDEOGRAPH + 0xF04D: 0x9917, //CJK UNIFIED IDEOGRAPH + 0xF04E: 0x9918, //CJK UNIFIED IDEOGRAPH + 0xF04F: 0x9919, //CJK UNIFIED IDEOGRAPH + 0xF050: 0x991A, //CJK UNIFIED IDEOGRAPH + 0xF051: 0x991B, //CJK UNIFIED IDEOGRAPH + 0xF052: 0x991C, //CJK UNIFIED IDEOGRAPH + 0xF053: 0x991D, //CJK UNIFIED IDEOGRAPH + 0xF054: 0x991E, //CJK UNIFIED IDEOGRAPH + 0xF055: 0x991F, //CJK UNIFIED IDEOGRAPH + 0xF056: 0x9920, //CJK UNIFIED IDEOGRAPH + 0xF057: 0x9921, //CJK UNIFIED IDEOGRAPH + 0xF058: 0x9922, //CJK UNIFIED IDEOGRAPH + 0xF059: 0x9923, //CJK UNIFIED IDEOGRAPH + 0xF05A: 0x9924, //CJK UNIFIED IDEOGRAPH + 0xF05B: 0x9925, //CJK UNIFIED IDEOGRAPH + 0xF05C: 0x9926, //CJK UNIFIED IDEOGRAPH + 0xF05D: 0x9927, //CJK UNIFIED IDEOGRAPH + 0xF05E: 0x9928, //CJK UNIFIED IDEOGRAPH + 0xF05F: 0x9929, //CJK UNIFIED IDEOGRAPH + 0xF060: 0x992A, //CJK UNIFIED IDEOGRAPH + 0xF061: 0x992B, //CJK UNIFIED IDEOGRAPH + 0xF062: 0x992C, //CJK UNIFIED IDEOGRAPH + 0xF063: 0x992D, //CJK UNIFIED IDEOGRAPH + 0xF064: 0x992F, //CJK UNIFIED IDEOGRAPH + 0xF065: 0x9930, //CJK UNIFIED IDEOGRAPH + 0xF066: 0x9931, //CJK UNIFIED IDEOGRAPH + 0xF067: 0x9932, //CJK UNIFIED IDEOGRAPH + 0xF068: 0x9933, //CJK UNIFIED IDEOGRAPH + 0xF069: 0x9934, //CJK UNIFIED IDEOGRAPH + 0xF06A: 0x9935, //CJK UNIFIED IDEOGRAPH + 0xF06B: 0x9936, //CJK UNIFIED IDEOGRAPH + 0xF06C: 0x9937, //CJK UNIFIED IDEOGRAPH + 0xF06D: 0x9938, //CJK UNIFIED IDEOGRAPH + 0xF06E: 0x9939, //CJK UNIFIED IDEOGRAPH + 0xF06F: 0x993A, //CJK UNIFIED IDEOGRAPH + 0xF070: 0x993B, //CJK UNIFIED IDEOGRAPH + 0xF071: 0x993C, //CJK UNIFIED IDEOGRAPH + 0xF072: 0x993D, //CJK UNIFIED IDEOGRAPH + 0xF073: 0x993E, //CJK UNIFIED IDEOGRAPH + 0xF074: 0x993F, //CJK UNIFIED IDEOGRAPH + 0xF075: 0x9940, //CJK UNIFIED IDEOGRAPH + 0xF076: 0x9941, //CJK UNIFIED IDEOGRAPH + 0xF077: 0x9942, //CJK UNIFIED IDEOGRAPH + 0xF078: 0x9943, //CJK UNIFIED IDEOGRAPH + 0xF079: 0x9944, //CJK UNIFIED IDEOGRAPH + 0xF07A: 0x9945, //CJK UNIFIED IDEOGRAPH + 0xF07B: 0x9946, //CJK UNIFIED IDEOGRAPH + 0xF07C: 0x9947, //CJK UNIFIED IDEOGRAPH + 0xF07D: 0x9948, //CJK UNIFIED IDEOGRAPH + 0xF07E: 0x9949, //CJK UNIFIED IDEOGRAPH + 0xF080: 0x994A, //CJK UNIFIED IDEOGRAPH + 0xF081: 0x994B, //CJK UNIFIED IDEOGRAPH + 0xF082: 0x994C, //CJK UNIFIED IDEOGRAPH + 0xF083: 0x994D, //CJK UNIFIED IDEOGRAPH + 0xF084: 0x994E, //CJK UNIFIED IDEOGRAPH + 0xF085: 0x994F, //CJK UNIFIED IDEOGRAPH + 0xF086: 0x9950, //CJK UNIFIED IDEOGRAPH + 0xF087: 0x9951, //CJK UNIFIED IDEOGRAPH + 0xF088: 0x9952, //CJK UNIFIED IDEOGRAPH + 0xF089: 0x9953, //CJK UNIFIED IDEOGRAPH + 0xF08A: 0x9956, //CJK UNIFIED IDEOGRAPH + 0xF08B: 0x9957, //CJK UNIFIED IDEOGRAPH + 0xF08C: 0x9958, //CJK UNIFIED IDEOGRAPH + 0xF08D: 0x9959, //CJK UNIFIED IDEOGRAPH + 0xF08E: 0x995A, //CJK UNIFIED IDEOGRAPH + 0xF08F: 0x995B, //CJK UNIFIED IDEOGRAPH + 0xF090: 0x995C, //CJK UNIFIED IDEOGRAPH + 0xF091: 0x995D, //CJK UNIFIED IDEOGRAPH + 0xF092: 0x995E, //CJK UNIFIED IDEOGRAPH + 0xF093: 0x995F, //CJK UNIFIED IDEOGRAPH + 0xF094: 0x9960, //CJK UNIFIED IDEOGRAPH + 0xF095: 0x9961, //CJK UNIFIED IDEOGRAPH + 0xF096: 0x9962, //CJK UNIFIED IDEOGRAPH + 0xF097: 0x9964, //CJK UNIFIED IDEOGRAPH + 0xF098: 0x9966, //CJK UNIFIED IDEOGRAPH + 0xF099: 0x9973, //CJK UNIFIED IDEOGRAPH + 0xF09A: 0x9978, //CJK UNIFIED IDEOGRAPH + 0xF09B: 0x9979, //CJK UNIFIED IDEOGRAPH + 0xF09C: 0x997B, //CJK UNIFIED IDEOGRAPH + 0xF09D: 0x997E, //CJK UNIFIED IDEOGRAPH + 0xF09E: 0x9982, //CJK UNIFIED IDEOGRAPH + 0xF09F: 0x9983, //CJK UNIFIED IDEOGRAPH + 0xF0A0: 0x9989, //CJK UNIFIED IDEOGRAPH + 0xF0A1: 0x7A39, //CJK UNIFIED IDEOGRAPH + 0xF0A2: 0x7A37, //CJK UNIFIED IDEOGRAPH + 0xF0A3: 0x7A51, //CJK UNIFIED IDEOGRAPH + 0xF0A4: 0x9ECF, //CJK UNIFIED IDEOGRAPH + 0xF0A5: 0x99A5, //CJK UNIFIED IDEOGRAPH + 0xF0A6: 0x7A70, //CJK UNIFIED IDEOGRAPH + 0xF0A7: 0x7688, //CJK UNIFIED IDEOGRAPH + 0xF0A8: 0x768E, //CJK UNIFIED IDEOGRAPH + 0xF0A9: 0x7693, //CJK UNIFIED IDEOGRAPH + 0xF0AA: 0x7699, //CJK UNIFIED IDEOGRAPH + 0xF0AB: 0x76A4, //CJK UNIFIED IDEOGRAPH + 0xF0AC: 0x74DE, //CJK UNIFIED IDEOGRAPH + 0xF0AD: 0x74E0, //CJK UNIFIED IDEOGRAPH + 0xF0AE: 0x752C, //CJK UNIFIED IDEOGRAPH + 0xF0AF: 0x9E20, //CJK UNIFIED IDEOGRAPH + 0xF0B0: 0x9E22, //CJK UNIFIED IDEOGRAPH + 0xF0B1: 0x9E28, //CJK UNIFIED IDEOGRAPH + 0xF0B2: 0x9E29, //CJK UNIFIED IDEOGRAPH + 0xF0B3: 0x9E2A, //CJK UNIFIED IDEOGRAPH + 0xF0B4: 0x9E2B, //CJK UNIFIED IDEOGRAPH + 0xF0B5: 0x9E2C, //CJK UNIFIED IDEOGRAPH + 0xF0B6: 0x9E32, //CJK UNIFIED IDEOGRAPH + 0xF0B7: 0x9E31, //CJK UNIFIED IDEOGRAPH + 0xF0B8: 0x9E36, //CJK UNIFIED IDEOGRAPH + 0xF0B9: 0x9E38, //CJK UNIFIED IDEOGRAPH + 0xF0BA: 0x9E37, //CJK UNIFIED IDEOGRAPH + 0xF0BB: 0x9E39, //CJK UNIFIED IDEOGRAPH + 0xF0BC: 0x9E3A, //CJK UNIFIED IDEOGRAPH + 0xF0BD: 0x9E3E, //CJK UNIFIED IDEOGRAPH + 0xF0BE: 0x9E41, //CJK UNIFIED IDEOGRAPH + 0xF0BF: 0x9E42, //CJK UNIFIED IDEOGRAPH + 0xF0C0: 0x9E44, //CJK UNIFIED IDEOGRAPH + 0xF0C1: 0x9E46, //CJK UNIFIED IDEOGRAPH + 0xF0C2: 0x9E47, //CJK UNIFIED IDEOGRAPH + 0xF0C3: 0x9E48, //CJK UNIFIED IDEOGRAPH + 0xF0C4: 0x9E49, //CJK UNIFIED IDEOGRAPH + 0xF0C5: 0x9E4B, //CJK UNIFIED IDEOGRAPH + 0xF0C6: 0x9E4C, //CJK UNIFIED IDEOGRAPH + 0xF0C7: 0x9E4E, //CJK UNIFIED IDEOGRAPH + 0xF0C8: 0x9E51, //CJK UNIFIED IDEOGRAPH + 0xF0C9: 0x9E55, //CJK UNIFIED IDEOGRAPH + 0xF0CA: 0x9E57, //CJK UNIFIED IDEOGRAPH + 0xF0CB: 0x9E5A, //CJK UNIFIED IDEOGRAPH + 0xF0CC: 0x9E5B, //CJK UNIFIED IDEOGRAPH + 0xF0CD: 0x9E5C, //CJK UNIFIED IDEOGRAPH + 0xF0CE: 0x9E5E, //CJK UNIFIED IDEOGRAPH + 0xF0CF: 0x9E63, //CJK UNIFIED IDEOGRAPH + 0xF0D0: 0x9E66, //CJK UNIFIED IDEOGRAPH + 0xF0D1: 0x9E67, //CJK UNIFIED IDEOGRAPH + 0xF0D2: 0x9E68, //CJK UNIFIED IDEOGRAPH + 0xF0D3: 0x9E69, //CJK UNIFIED IDEOGRAPH + 0xF0D4: 0x9E6A, //CJK UNIFIED IDEOGRAPH + 0xF0D5: 0x9E6B, //CJK UNIFIED IDEOGRAPH + 0xF0D6: 0x9E6C, //CJK UNIFIED IDEOGRAPH + 0xF0D7: 0x9E71, //CJK UNIFIED IDEOGRAPH + 0xF0D8: 0x9E6D, //CJK UNIFIED IDEOGRAPH + 0xF0D9: 0x9E73, //CJK UNIFIED IDEOGRAPH + 0xF0DA: 0x7592, //CJK UNIFIED IDEOGRAPH + 0xF0DB: 0x7594, //CJK UNIFIED IDEOGRAPH + 0xF0DC: 0x7596, //CJK UNIFIED IDEOGRAPH + 0xF0DD: 0x75A0, //CJK UNIFIED IDEOGRAPH + 0xF0DE: 0x759D, //CJK UNIFIED IDEOGRAPH + 0xF0DF: 0x75AC, //CJK UNIFIED IDEOGRAPH + 0xF0E0: 0x75A3, //CJK UNIFIED IDEOGRAPH + 0xF0E1: 0x75B3, //CJK UNIFIED IDEOGRAPH + 0xF0E2: 0x75B4, //CJK UNIFIED IDEOGRAPH + 0xF0E3: 0x75B8, //CJK UNIFIED IDEOGRAPH + 0xF0E4: 0x75C4, //CJK UNIFIED IDEOGRAPH + 0xF0E5: 0x75B1, //CJK UNIFIED IDEOGRAPH + 0xF0E6: 0x75B0, //CJK UNIFIED IDEOGRAPH + 0xF0E7: 0x75C3, //CJK UNIFIED IDEOGRAPH + 0xF0E8: 0x75C2, //CJK UNIFIED IDEOGRAPH + 0xF0E9: 0x75D6, //CJK UNIFIED IDEOGRAPH + 0xF0EA: 0x75CD, //CJK UNIFIED IDEOGRAPH + 0xF0EB: 0x75E3, //CJK UNIFIED IDEOGRAPH + 0xF0EC: 0x75E8, //CJK UNIFIED IDEOGRAPH + 0xF0ED: 0x75E6, //CJK UNIFIED IDEOGRAPH + 0xF0EE: 0x75E4, //CJK UNIFIED IDEOGRAPH + 0xF0EF: 0x75EB, //CJK UNIFIED IDEOGRAPH + 0xF0F0: 0x75E7, //CJK UNIFIED IDEOGRAPH + 0xF0F1: 0x7603, //CJK UNIFIED IDEOGRAPH + 0xF0F2: 0x75F1, //CJK UNIFIED IDEOGRAPH + 0xF0F3: 0x75FC, //CJK UNIFIED IDEOGRAPH + 0xF0F4: 0x75FF, //CJK UNIFIED IDEOGRAPH + 0xF0F5: 0x7610, //CJK UNIFIED IDEOGRAPH + 0xF0F6: 0x7600, //CJK UNIFIED IDEOGRAPH + 0xF0F7: 0x7605, //CJK UNIFIED IDEOGRAPH + 0xF0F8: 0x760C, //CJK UNIFIED IDEOGRAPH + 0xF0F9: 0x7617, //CJK UNIFIED IDEOGRAPH + 0xF0FA: 0x760A, //CJK UNIFIED IDEOGRAPH + 0xF0FB: 0x7625, //CJK UNIFIED IDEOGRAPH + 0xF0FC: 0x7618, //CJK UNIFIED IDEOGRAPH + 0xF0FD: 0x7615, //CJK UNIFIED IDEOGRAPH + 0xF0FE: 0x7619, //CJK UNIFIED IDEOGRAPH + 0xF140: 0x998C, //CJK UNIFIED IDEOGRAPH + 0xF141: 0x998E, //CJK UNIFIED IDEOGRAPH + 0xF142: 0x999A, //CJK UNIFIED IDEOGRAPH + 0xF143: 0x999B, //CJK UNIFIED IDEOGRAPH + 0xF144: 0x999C, //CJK UNIFIED IDEOGRAPH + 0xF145: 0x999D, //CJK UNIFIED IDEOGRAPH + 0xF146: 0x999E, //CJK UNIFIED IDEOGRAPH + 0xF147: 0x999F, //CJK UNIFIED IDEOGRAPH + 0xF148: 0x99A0, //CJK UNIFIED IDEOGRAPH + 0xF149: 0x99A1, //CJK UNIFIED IDEOGRAPH + 0xF14A: 0x99A2, //CJK UNIFIED IDEOGRAPH + 0xF14B: 0x99A3, //CJK UNIFIED IDEOGRAPH + 0xF14C: 0x99A4, //CJK UNIFIED IDEOGRAPH + 0xF14D: 0x99A6, //CJK UNIFIED IDEOGRAPH + 0xF14E: 0x99A7, //CJK UNIFIED IDEOGRAPH + 0xF14F: 0x99A9, //CJK UNIFIED IDEOGRAPH + 0xF150: 0x99AA, //CJK UNIFIED IDEOGRAPH + 0xF151: 0x99AB, //CJK UNIFIED IDEOGRAPH + 0xF152: 0x99AC, //CJK UNIFIED IDEOGRAPH + 0xF153: 0x99AD, //CJK UNIFIED IDEOGRAPH + 0xF154: 0x99AE, //CJK UNIFIED IDEOGRAPH + 0xF155: 0x99AF, //CJK UNIFIED IDEOGRAPH + 0xF156: 0x99B0, //CJK UNIFIED IDEOGRAPH + 0xF157: 0x99B1, //CJK UNIFIED IDEOGRAPH + 0xF158: 0x99B2, //CJK UNIFIED IDEOGRAPH + 0xF159: 0x99B3, //CJK UNIFIED IDEOGRAPH + 0xF15A: 0x99B4, //CJK UNIFIED IDEOGRAPH + 0xF15B: 0x99B5, //CJK UNIFIED IDEOGRAPH + 0xF15C: 0x99B6, //CJK UNIFIED IDEOGRAPH + 0xF15D: 0x99B7, //CJK UNIFIED IDEOGRAPH + 0xF15E: 0x99B8, //CJK UNIFIED IDEOGRAPH + 0xF15F: 0x99B9, //CJK UNIFIED IDEOGRAPH + 0xF160: 0x99BA, //CJK UNIFIED IDEOGRAPH + 0xF161: 0x99BB, //CJK UNIFIED IDEOGRAPH + 0xF162: 0x99BC, //CJK UNIFIED IDEOGRAPH + 0xF163: 0x99BD, //CJK UNIFIED IDEOGRAPH + 0xF164: 0x99BE, //CJK UNIFIED IDEOGRAPH + 0xF165: 0x99BF, //CJK UNIFIED IDEOGRAPH + 0xF166: 0x99C0, //CJK UNIFIED IDEOGRAPH + 0xF167: 0x99C1, //CJK UNIFIED IDEOGRAPH + 0xF168: 0x99C2, //CJK UNIFIED IDEOGRAPH + 0xF169: 0x99C3, //CJK UNIFIED IDEOGRAPH + 0xF16A: 0x99C4, //CJK UNIFIED IDEOGRAPH + 0xF16B: 0x99C5, //CJK UNIFIED IDEOGRAPH + 0xF16C: 0x99C6, //CJK UNIFIED IDEOGRAPH + 0xF16D: 0x99C7, //CJK UNIFIED IDEOGRAPH + 0xF16E: 0x99C8, //CJK UNIFIED IDEOGRAPH + 0xF16F: 0x99C9, //CJK UNIFIED IDEOGRAPH + 0xF170: 0x99CA, //CJK UNIFIED IDEOGRAPH + 0xF171: 0x99CB, //CJK UNIFIED IDEOGRAPH + 0xF172: 0x99CC, //CJK UNIFIED IDEOGRAPH + 0xF173: 0x99CD, //CJK UNIFIED IDEOGRAPH + 0xF174: 0x99CE, //CJK UNIFIED IDEOGRAPH + 0xF175: 0x99CF, //CJK UNIFIED IDEOGRAPH + 0xF176: 0x99D0, //CJK UNIFIED IDEOGRAPH + 0xF177: 0x99D1, //CJK UNIFIED IDEOGRAPH + 0xF178: 0x99D2, //CJK UNIFIED IDEOGRAPH + 0xF179: 0x99D3, //CJK UNIFIED IDEOGRAPH + 0xF17A: 0x99D4, //CJK UNIFIED IDEOGRAPH + 0xF17B: 0x99D5, //CJK UNIFIED IDEOGRAPH + 0xF17C: 0x99D6, //CJK UNIFIED IDEOGRAPH + 0xF17D: 0x99D7, //CJK UNIFIED IDEOGRAPH + 0xF17E: 0x99D8, //CJK UNIFIED IDEOGRAPH + 0xF180: 0x99D9, //CJK UNIFIED IDEOGRAPH + 0xF181: 0x99DA, //CJK UNIFIED IDEOGRAPH + 0xF182: 0x99DB, //CJK UNIFIED IDEOGRAPH + 0xF183: 0x99DC, //CJK UNIFIED IDEOGRAPH + 0xF184: 0x99DD, //CJK UNIFIED IDEOGRAPH + 0xF185: 0x99DE, //CJK UNIFIED IDEOGRAPH + 0xF186: 0x99DF, //CJK UNIFIED IDEOGRAPH + 0xF187: 0x99E0, //CJK UNIFIED IDEOGRAPH + 0xF188: 0x99E1, //CJK UNIFIED IDEOGRAPH + 0xF189: 0x99E2, //CJK UNIFIED IDEOGRAPH + 0xF18A: 0x99E3, //CJK UNIFIED IDEOGRAPH + 0xF18B: 0x99E4, //CJK UNIFIED IDEOGRAPH + 0xF18C: 0x99E5, //CJK UNIFIED IDEOGRAPH + 0xF18D: 0x99E6, //CJK UNIFIED IDEOGRAPH + 0xF18E: 0x99E7, //CJK UNIFIED IDEOGRAPH + 0xF18F: 0x99E8, //CJK UNIFIED IDEOGRAPH + 0xF190: 0x99E9, //CJK UNIFIED IDEOGRAPH + 0xF191: 0x99EA, //CJK UNIFIED IDEOGRAPH + 0xF192: 0x99EB, //CJK UNIFIED IDEOGRAPH + 0xF193: 0x99EC, //CJK UNIFIED IDEOGRAPH + 0xF194: 0x99ED, //CJK UNIFIED IDEOGRAPH + 0xF195: 0x99EE, //CJK UNIFIED IDEOGRAPH + 0xF196: 0x99EF, //CJK UNIFIED IDEOGRAPH + 0xF197: 0x99F0, //CJK UNIFIED IDEOGRAPH + 0xF198: 0x99F1, //CJK UNIFIED IDEOGRAPH + 0xF199: 0x99F2, //CJK UNIFIED IDEOGRAPH + 0xF19A: 0x99F3, //CJK UNIFIED IDEOGRAPH + 0xF19B: 0x99F4, //CJK UNIFIED IDEOGRAPH + 0xF19C: 0x99F5, //CJK UNIFIED IDEOGRAPH + 0xF19D: 0x99F6, //CJK UNIFIED IDEOGRAPH + 0xF19E: 0x99F7, //CJK UNIFIED IDEOGRAPH + 0xF19F: 0x99F8, //CJK UNIFIED IDEOGRAPH + 0xF1A0: 0x99F9, //CJK UNIFIED IDEOGRAPH + 0xF1A1: 0x761B, //CJK UNIFIED IDEOGRAPH + 0xF1A2: 0x763C, //CJK UNIFIED IDEOGRAPH + 0xF1A3: 0x7622, //CJK UNIFIED IDEOGRAPH + 0xF1A4: 0x7620, //CJK UNIFIED IDEOGRAPH + 0xF1A5: 0x7640, //CJK UNIFIED IDEOGRAPH + 0xF1A6: 0x762D, //CJK UNIFIED IDEOGRAPH + 0xF1A7: 0x7630, //CJK UNIFIED IDEOGRAPH + 0xF1A8: 0x763F, //CJK UNIFIED IDEOGRAPH + 0xF1A9: 0x7635, //CJK UNIFIED IDEOGRAPH + 0xF1AA: 0x7643, //CJK UNIFIED IDEOGRAPH + 0xF1AB: 0x763E, //CJK UNIFIED IDEOGRAPH + 0xF1AC: 0x7633, //CJK UNIFIED IDEOGRAPH + 0xF1AD: 0x764D, //CJK UNIFIED IDEOGRAPH + 0xF1AE: 0x765E, //CJK UNIFIED IDEOGRAPH + 0xF1AF: 0x7654, //CJK UNIFIED IDEOGRAPH + 0xF1B0: 0x765C, //CJK UNIFIED IDEOGRAPH + 0xF1B1: 0x7656, //CJK UNIFIED IDEOGRAPH + 0xF1B2: 0x766B, //CJK UNIFIED IDEOGRAPH + 0xF1B3: 0x766F, //CJK UNIFIED IDEOGRAPH + 0xF1B4: 0x7FCA, //CJK UNIFIED IDEOGRAPH + 0xF1B5: 0x7AE6, //CJK UNIFIED IDEOGRAPH + 0xF1B6: 0x7A78, //CJK UNIFIED IDEOGRAPH + 0xF1B7: 0x7A79, //CJK UNIFIED IDEOGRAPH + 0xF1B8: 0x7A80, //CJK UNIFIED IDEOGRAPH + 0xF1B9: 0x7A86, //CJK UNIFIED IDEOGRAPH + 0xF1BA: 0x7A88, //CJK UNIFIED IDEOGRAPH + 0xF1BB: 0x7A95, //CJK UNIFIED IDEOGRAPH + 0xF1BC: 0x7AA6, //CJK UNIFIED IDEOGRAPH + 0xF1BD: 0x7AA0, //CJK UNIFIED IDEOGRAPH + 0xF1BE: 0x7AAC, //CJK UNIFIED IDEOGRAPH + 0xF1BF: 0x7AA8, //CJK UNIFIED IDEOGRAPH + 0xF1C0: 0x7AAD, //CJK UNIFIED IDEOGRAPH + 0xF1C1: 0x7AB3, //CJK UNIFIED IDEOGRAPH + 0xF1C2: 0x8864, //CJK UNIFIED IDEOGRAPH + 0xF1C3: 0x8869, //CJK UNIFIED IDEOGRAPH + 0xF1C4: 0x8872, //CJK UNIFIED IDEOGRAPH + 0xF1C5: 0x887D, //CJK UNIFIED IDEOGRAPH + 0xF1C6: 0x887F, //CJK UNIFIED IDEOGRAPH + 0xF1C7: 0x8882, //CJK UNIFIED IDEOGRAPH + 0xF1C8: 0x88A2, //CJK UNIFIED IDEOGRAPH + 0xF1C9: 0x88C6, //CJK UNIFIED IDEOGRAPH + 0xF1CA: 0x88B7, //CJK UNIFIED IDEOGRAPH + 0xF1CB: 0x88BC, //CJK UNIFIED IDEOGRAPH + 0xF1CC: 0x88C9, //CJK UNIFIED IDEOGRAPH + 0xF1CD: 0x88E2, //CJK UNIFIED IDEOGRAPH + 0xF1CE: 0x88CE, //CJK UNIFIED IDEOGRAPH + 0xF1CF: 0x88E3, //CJK UNIFIED IDEOGRAPH + 0xF1D0: 0x88E5, //CJK UNIFIED IDEOGRAPH + 0xF1D1: 0x88F1, //CJK UNIFIED IDEOGRAPH + 0xF1D2: 0x891A, //CJK UNIFIED IDEOGRAPH + 0xF1D3: 0x88FC, //CJK UNIFIED IDEOGRAPH + 0xF1D4: 0x88E8, //CJK UNIFIED IDEOGRAPH + 0xF1D5: 0x88FE, //CJK UNIFIED IDEOGRAPH + 0xF1D6: 0x88F0, //CJK UNIFIED IDEOGRAPH + 0xF1D7: 0x8921, //CJK UNIFIED IDEOGRAPH + 0xF1D8: 0x8919, //CJK UNIFIED IDEOGRAPH + 0xF1D9: 0x8913, //CJK UNIFIED IDEOGRAPH + 0xF1DA: 0x891B, //CJK UNIFIED IDEOGRAPH + 0xF1DB: 0x890A, //CJK UNIFIED IDEOGRAPH + 0xF1DC: 0x8934, //CJK UNIFIED IDEOGRAPH + 0xF1DD: 0x892B, //CJK UNIFIED IDEOGRAPH + 0xF1DE: 0x8936, //CJK UNIFIED IDEOGRAPH + 0xF1DF: 0x8941, //CJK UNIFIED IDEOGRAPH + 0xF1E0: 0x8966, //CJK UNIFIED IDEOGRAPH + 0xF1E1: 0x897B, //CJK UNIFIED IDEOGRAPH + 0xF1E2: 0x758B, //CJK UNIFIED IDEOGRAPH + 0xF1E3: 0x80E5, //CJK UNIFIED IDEOGRAPH + 0xF1E4: 0x76B2, //CJK UNIFIED IDEOGRAPH + 0xF1E5: 0x76B4, //CJK UNIFIED IDEOGRAPH + 0xF1E6: 0x77DC, //CJK UNIFIED IDEOGRAPH + 0xF1E7: 0x8012, //CJK UNIFIED IDEOGRAPH + 0xF1E8: 0x8014, //CJK UNIFIED IDEOGRAPH + 0xF1E9: 0x8016, //CJK UNIFIED IDEOGRAPH + 0xF1EA: 0x801C, //CJK UNIFIED IDEOGRAPH + 0xF1EB: 0x8020, //CJK UNIFIED IDEOGRAPH + 0xF1EC: 0x8022, //CJK UNIFIED IDEOGRAPH + 0xF1ED: 0x8025, //CJK UNIFIED IDEOGRAPH + 0xF1EE: 0x8026, //CJK UNIFIED IDEOGRAPH + 0xF1EF: 0x8027, //CJK UNIFIED IDEOGRAPH + 0xF1F0: 0x8029, //CJK UNIFIED IDEOGRAPH + 0xF1F1: 0x8028, //CJK UNIFIED IDEOGRAPH + 0xF1F2: 0x8031, //CJK UNIFIED IDEOGRAPH + 0xF1F3: 0x800B, //CJK UNIFIED IDEOGRAPH + 0xF1F4: 0x8035, //CJK UNIFIED IDEOGRAPH + 0xF1F5: 0x8043, //CJK UNIFIED IDEOGRAPH + 0xF1F6: 0x8046, //CJK UNIFIED IDEOGRAPH + 0xF1F7: 0x804D, //CJK UNIFIED IDEOGRAPH + 0xF1F8: 0x8052, //CJK UNIFIED IDEOGRAPH + 0xF1F9: 0x8069, //CJK UNIFIED IDEOGRAPH + 0xF1FA: 0x8071, //CJK UNIFIED IDEOGRAPH + 0xF1FB: 0x8983, //CJK UNIFIED IDEOGRAPH + 0xF1FC: 0x9878, //CJK UNIFIED IDEOGRAPH + 0xF1FD: 0x9880, //CJK UNIFIED IDEOGRAPH + 0xF1FE: 0x9883, //CJK UNIFIED IDEOGRAPH + 0xF240: 0x99FA, //CJK UNIFIED IDEOGRAPH + 0xF241: 0x99FB, //CJK UNIFIED IDEOGRAPH + 0xF242: 0x99FC, //CJK UNIFIED IDEOGRAPH + 0xF243: 0x99FD, //CJK UNIFIED IDEOGRAPH + 0xF244: 0x99FE, //CJK UNIFIED IDEOGRAPH + 0xF245: 0x99FF, //CJK UNIFIED IDEOGRAPH + 0xF246: 0x9A00, //CJK UNIFIED IDEOGRAPH + 0xF247: 0x9A01, //CJK UNIFIED IDEOGRAPH + 0xF248: 0x9A02, //CJK UNIFIED IDEOGRAPH + 0xF249: 0x9A03, //CJK UNIFIED IDEOGRAPH + 0xF24A: 0x9A04, //CJK UNIFIED IDEOGRAPH + 0xF24B: 0x9A05, //CJK UNIFIED IDEOGRAPH + 0xF24C: 0x9A06, //CJK UNIFIED IDEOGRAPH + 0xF24D: 0x9A07, //CJK UNIFIED IDEOGRAPH + 0xF24E: 0x9A08, //CJK UNIFIED IDEOGRAPH + 0xF24F: 0x9A09, //CJK UNIFIED IDEOGRAPH + 0xF250: 0x9A0A, //CJK UNIFIED IDEOGRAPH + 0xF251: 0x9A0B, //CJK UNIFIED IDEOGRAPH + 0xF252: 0x9A0C, //CJK UNIFIED IDEOGRAPH + 0xF253: 0x9A0D, //CJK UNIFIED IDEOGRAPH + 0xF254: 0x9A0E, //CJK UNIFIED IDEOGRAPH + 0xF255: 0x9A0F, //CJK UNIFIED IDEOGRAPH + 0xF256: 0x9A10, //CJK UNIFIED IDEOGRAPH + 0xF257: 0x9A11, //CJK UNIFIED IDEOGRAPH + 0xF258: 0x9A12, //CJK UNIFIED IDEOGRAPH + 0xF259: 0x9A13, //CJK UNIFIED IDEOGRAPH + 0xF25A: 0x9A14, //CJK UNIFIED IDEOGRAPH + 0xF25B: 0x9A15, //CJK UNIFIED IDEOGRAPH + 0xF25C: 0x9A16, //CJK UNIFIED IDEOGRAPH + 0xF25D: 0x9A17, //CJK UNIFIED IDEOGRAPH + 0xF25E: 0x9A18, //CJK UNIFIED IDEOGRAPH + 0xF25F: 0x9A19, //CJK UNIFIED IDEOGRAPH + 0xF260: 0x9A1A, //CJK UNIFIED IDEOGRAPH + 0xF261: 0x9A1B, //CJK UNIFIED IDEOGRAPH + 0xF262: 0x9A1C, //CJK UNIFIED IDEOGRAPH + 0xF263: 0x9A1D, //CJK UNIFIED IDEOGRAPH + 0xF264: 0x9A1E, //CJK UNIFIED IDEOGRAPH + 0xF265: 0x9A1F, //CJK UNIFIED IDEOGRAPH + 0xF266: 0x9A20, //CJK UNIFIED IDEOGRAPH + 0xF267: 0x9A21, //CJK UNIFIED IDEOGRAPH + 0xF268: 0x9A22, //CJK UNIFIED IDEOGRAPH + 0xF269: 0x9A23, //CJK UNIFIED IDEOGRAPH + 0xF26A: 0x9A24, //CJK UNIFIED IDEOGRAPH + 0xF26B: 0x9A25, //CJK UNIFIED IDEOGRAPH + 0xF26C: 0x9A26, //CJK UNIFIED IDEOGRAPH + 0xF26D: 0x9A27, //CJK UNIFIED IDEOGRAPH + 0xF26E: 0x9A28, //CJK UNIFIED IDEOGRAPH + 0xF26F: 0x9A29, //CJK UNIFIED IDEOGRAPH + 0xF270: 0x9A2A, //CJK UNIFIED IDEOGRAPH + 0xF271: 0x9A2B, //CJK UNIFIED IDEOGRAPH + 0xF272: 0x9A2C, //CJK UNIFIED IDEOGRAPH + 0xF273: 0x9A2D, //CJK UNIFIED IDEOGRAPH + 0xF274: 0x9A2E, //CJK UNIFIED IDEOGRAPH + 0xF275: 0x9A2F, //CJK UNIFIED IDEOGRAPH + 0xF276: 0x9A30, //CJK UNIFIED IDEOGRAPH + 0xF277: 0x9A31, //CJK UNIFIED IDEOGRAPH + 0xF278: 0x9A32, //CJK UNIFIED IDEOGRAPH + 0xF279: 0x9A33, //CJK UNIFIED IDEOGRAPH + 0xF27A: 0x9A34, //CJK UNIFIED IDEOGRAPH + 0xF27B: 0x9A35, //CJK UNIFIED IDEOGRAPH + 0xF27C: 0x9A36, //CJK UNIFIED IDEOGRAPH + 0xF27D: 0x9A37, //CJK UNIFIED IDEOGRAPH + 0xF27E: 0x9A38, //CJK UNIFIED IDEOGRAPH + 0xF280: 0x9A39, //CJK UNIFIED IDEOGRAPH + 0xF281: 0x9A3A, //CJK UNIFIED IDEOGRAPH + 0xF282: 0x9A3B, //CJK UNIFIED IDEOGRAPH + 0xF283: 0x9A3C, //CJK UNIFIED IDEOGRAPH + 0xF284: 0x9A3D, //CJK UNIFIED IDEOGRAPH + 0xF285: 0x9A3E, //CJK UNIFIED IDEOGRAPH + 0xF286: 0x9A3F, //CJK UNIFIED IDEOGRAPH + 0xF287: 0x9A40, //CJK UNIFIED IDEOGRAPH + 0xF288: 0x9A41, //CJK UNIFIED IDEOGRAPH + 0xF289: 0x9A42, //CJK UNIFIED IDEOGRAPH + 0xF28A: 0x9A43, //CJK UNIFIED IDEOGRAPH + 0xF28B: 0x9A44, //CJK UNIFIED IDEOGRAPH + 0xF28C: 0x9A45, //CJK UNIFIED IDEOGRAPH + 0xF28D: 0x9A46, //CJK UNIFIED IDEOGRAPH + 0xF28E: 0x9A47, //CJK UNIFIED IDEOGRAPH + 0xF28F: 0x9A48, //CJK UNIFIED IDEOGRAPH + 0xF290: 0x9A49, //CJK UNIFIED IDEOGRAPH + 0xF291: 0x9A4A, //CJK UNIFIED IDEOGRAPH + 0xF292: 0x9A4B, //CJK UNIFIED IDEOGRAPH + 0xF293: 0x9A4C, //CJK UNIFIED IDEOGRAPH + 0xF294: 0x9A4D, //CJK UNIFIED IDEOGRAPH + 0xF295: 0x9A4E, //CJK UNIFIED IDEOGRAPH + 0xF296: 0x9A4F, //CJK UNIFIED IDEOGRAPH + 0xF297: 0x9A50, //CJK UNIFIED IDEOGRAPH + 0xF298: 0x9A51, //CJK UNIFIED IDEOGRAPH + 0xF299: 0x9A52, //CJK UNIFIED IDEOGRAPH + 0xF29A: 0x9A53, //CJK UNIFIED IDEOGRAPH + 0xF29B: 0x9A54, //CJK UNIFIED IDEOGRAPH + 0xF29C: 0x9A55, //CJK UNIFIED IDEOGRAPH + 0xF29D: 0x9A56, //CJK UNIFIED IDEOGRAPH + 0xF29E: 0x9A57, //CJK UNIFIED IDEOGRAPH + 0xF29F: 0x9A58, //CJK UNIFIED IDEOGRAPH + 0xF2A0: 0x9A59, //CJK UNIFIED IDEOGRAPH + 0xF2A1: 0x9889, //CJK UNIFIED IDEOGRAPH + 0xF2A2: 0x988C, //CJK UNIFIED IDEOGRAPH + 0xF2A3: 0x988D, //CJK UNIFIED IDEOGRAPH + 0xF2A4: 0x988F, //CJK UNIFIED IDEOGRAPH + 0xF2A5: 0x9894, //CJK UNIFIED IDEOGRAPH + 0xF2A6: 0x989A, //CJK UNIFIED IDEOGRAPH + 0xF2A7: 0x989B, //CJK UNIFIED IDEOGRAPH + 0xF2A8: 0x989E, //CJK UNIFIED IDEOGRAPH + 0xF2A9: 0x989F, //CJK UNIFIED IDEOGRAPH + 0xF2AA: 0x98A1, //CJK UNIFIED IDEOGRAPH + 0xF2AB: 0x98A2, //CJK UNIFIED IDEOGRAPH + 0xF2AC: 0x98A5, //CJK UNIFIED IDEOGRAPH + 0xF2AD: 0x98A6, //CJK UNIFIED IDEOGRAPH + 0xF2AE: 0x864D, //CJK UNIFIED IDEOGRAPH + 0xF2AF: 0x8654, //CJK UNIFIED IDEOGRAPH + 0xF2B0: 0x866C, //CJK UNIFIED IDEOGRAPH + 0xF2B1: 0x866E, //CJK UNIFIED IDEOGRAPH + 0xF2B2: 0x867F, //CJK UNIFIED IDEOGRAPH + 0xF2B3: 0x867A, //CJK UNIFIED IDEOGRAPH + 0xF2B4: 0x867C, //CJK UNIFIED IDEOGRAPH + 0xF2B5: 0x867B, //CJK UNIFIED IDEOGRAPH + 0xF2B6: 0x86A8, //CJK UNIFIED IDEOGRAPH + 0xF2B7: 0x868D, //CJK UNIFIED IDEOGRAPH + 0xF2B8: 0x868B, //CJK UNIFIED IDEOGRAPH + 0xF2B9: 0x86AC, //CJK UNIFIED IDEOGRAPH + 0xF2BA: 0x869D, //CJK UNIFIED IDEOGRAPH + 0xF2BB: 0x86A7, //CJK UNIFIED IDEOGRAPH + 0xF2BC: 0x86A3, //CJK UNIFIED IDEOGRAPH + 0xF2BD: 0x86AA, //CJK UNIFIED IDEOGRAPH + 0xF2BE: 0x8693, //CJK UNIFIED IDEOGRAPH + 0xF2BF: 0x86A9, //CJK UNIFIED IDEOGRAPH + 0xF2C0: 0x86B6, //CJK UNIFIED IDEOGRAPH + 0xF2C1: 0x86C4, //CJK UNIFIED IDEOGRAPH + 0xF2C2: 0x86B5, //CJK UNIFIED IDEOGRAPH + 0xF2C3: 0x86CE, //CJK UNIFIED IDEOGRAPH + 0xF2C4: 0x86B0, //CJK UNIFIED IDEOGRAPH + 0xF2C5: 0x86BA, //CJK UNIFIED IDEOGRAPH + 0xF2C6: 0x86B1, //CJK UNIFIED IDEOGRAPH + 0xF2C7: 0x86AF, //CJK UNIFIED IDEOGRAPH + 0xF2C8: 0x86C9, //CJK UNIFIED IDEOGRAPH + 0xF2C9: 0x86CF, //CJK UNIFIED IDEOGRAPH + 0xF2CA: 0x86B4, //CJK UNIFIED IDEOGRAPH + 0xF2CB: 0x86E9, //CJK UNIFIED IDEOGRAPH + 0xF2CC: 0x86F1, //CJK UNIFIED IDEOGRAPH + 0xF2CD: 0x86F2, //CJK UNIFIED IDEOGRAPH + 0xF2CE: 0x86ED, //CJK UNIFIED IDEOGRAPH + 0xF2CF: 0x86F3, //CJK UNIFIED IDEOGRAPH + 0xF2D0: 0x86D0, //CJK UNIFIED IDEOGRAPH + 0xF2D1: 0x8713, //CJK UNIFIED IDEOGRAPH + 0xF2D2: 0x86DE, //CJK UNIFIED IDEOGRAPH + 0xF2D3: 0x86F4, //CJK UNIFIED IDEOGRAPH + 0xF2D4: 0x86DF, //CJK UNIFIED IDEOGRAPH + 0xF2D5: 0x86D8, //CJK UNIFIED IDEOGRAPH + 0xF2D6: 0x86D1, //CJK UNIFIED IDEOGRAPH + 0xF2D7: 0x8703, //CJK UNIFIED IDEOGRAPH + 0xF2D8: 0x8707, //CJK UNIFIED IDEOGRAPH + 0xF2D9: 0x86F8, //CJK UNIFIED IDEOGRAPH + 0xF2DA: 0x8708, //CJK UNIFIED IDEOGRAPH + 0xF2DB: 0x870A, //CJK UNIFIED IDEOGRAPH + 0xF2DC: 0x870D, //CJK UNIFIED IDEOGRAPH + 0xF2DD: 0x8709, //CJK UNIFIED IDEOGRAPH + 0xF2DE: 0x8723, //CJK UNIFIED IDEOGRAPH + 0xF2DF: 0x873B, //CJK UNIFIED IDEOGRAPH + 0xF2E0: 0x871E, //CJK UNIFIED IDEOGRAPH + 0xF2E1: 0x8725, //CJK UNIFIED IDEOGRAPH + 0xF2E2: 0x872E, //CJK UNIFIED IDEOGRAPH + 0xF2E3: 0x871A, //CJK UNIFIED IDEOGRAPH + 0xF2E4: 0x873E, //CJK UNIFIED IDEOGRAPH + 0xF2E5: 0x8748, //CJK UNIFIED IDEOGRAPH + 0xF2E6: 0x8734, //CJK UNIFIED IDEOGRAPH + 0xF2E7: 0x8731, //CJK UNIFIED IDEOGRAPH + 0xF2E8: 0x8729, //CJK UNIFIED IDEOGRAPH + 0xF2E9: 0x8737, //CJK UNIFIED IDEOGRAPH + 0xF2EA: 0x873F, //CJK UNIFIED IDEOGRAPH + 0xF2EB: 0x8782, //CJK UNIFIED IDEOGRAPH + 0xF2EC: 0x8722, //CJK UNIFIED IDEOGRAPH + 0xF2ED: 0x877D, //CJK UNIFIED IDEOGRAPH + 0xF2EE: 0x877E, //CJK UNIFIED IDEOGRAPH + 0xF2EF: 0x877B, //CJK UNIFIED IDEOGRAPH + 0xF2F0: 0x8760, //CJK UNIFIED IDEOGRAPH + 0xF2F1: 0x8770, //CJK UNIFIED IDEOGRAPH + 0xF2F2: 0x874C, //CJK UNIFIED IDEOGRAPH + 0xF2F3: 0x876E, //CJK UNIFIED IDEOGRAPH + 0xF2F4: 0x878B, //CJK UNIFIED IDEOGRAPH + 0xF2F5: 0x8753, //CJK UNIFIED IDEOGRAPH + 0xF2F6: 0x8763, //CJK UNIFIED IDEOGRAPH + 0xF2F7: 0x877C, //CJK UNIFIED IDEOGRAPH + 0xF2F8: 0x8764, //CJK UNIFIED IDEOGRAPH + 0xF2F9: 0x8759, //CJK UNIFIED IDEOGRAPH + 0xF2FA: 0x8765, //CJK UNIFIED IDEOGRAPH + 0xF2FB: 0x8793, //CJK UNIFIED IDEOGRAPH + 0xF2FC: 0x87AF, //CJK UNIFIED IDEOGRAPH + 0xF2FD: 0x87A8, //CJK UNIFIED IDEOGRAPH + 0xF2FE: 0x87D2, //CJK UNIFIED IDEOGRAPH + 0xF340: 0x9A5A, //CJK UNIFIED IDEOGRAPH + 0xF341: 0x9A5B, //CJK UNIFIED IDEOGRAPH + 0xF342: 0x9A5C, //CJK UNIFIED IDEOGRAPH + 0xF343: 0x9A5D, //CJK UNIFIED IDEOGRAPH + 0xF344: 0x9A5E, //CJK UNIFIED IDEOGRAPH + 0xF345: 0x9A5F, //CJK UNIFIED IDEOGRAPH + 0xF346: 0x9A60, //CJK UNIFIED IDEOGRAPH + 0xF347: 0x9A61, //CJK UNIFIED IDEOGRAPH + 0xF348: 0x9A62, //CJK UNIFIED IDEOGRAPH + 0xF349: 0x9A63, //CJK UNIFIED IDEOGRAPH + 0xF34A: 0x9A64, //CJK UNIFIED IDEOGRAPH + 0xF34B: 0x9A65, //CJK UNIFIED IDEOGRAPH + 0xF34C: 0x9A66, //CJK UNIFIED IDEOGRAPH + 0xF34D: 0x9A67, //CJK UNIFIED IDEOGRAPH + 0xF34E: 0x9A68, //CJK UNIFIED IDEOGRAPH + 0xF34F: 0x9A69, //CJK UNIFIED IDEOGRAPH + 0xF350: 0x9A6A, //CJK UNIFIED IDEOGRAPH + 0xF351: 0x9A6B, //CJK UNIFIED IDEOGRAPH + 0xF352: 0x9A72, //CJK UNIFIED IDEOGRAPH + 0xF353: 0x9A83, //CJK UNIFIED IDEOGRAPH + 0xF354: 0x9A89, //CJK UNIFIED IDEOGRAPH + 0xF355: 0x9A8D, //CJK UNIFIED IDEOGRAPH + 0xF356: 0x9A8E, //CJK UNIFIED IDEOGRAPH + 0xF357: 0x9A94, //CJK UNIFIED IDEOGRAPH + 0xF358: 0x9A95, //CJK UNIFIED IDEOGRAPH + 0xF359: 0x9A99, //CJK UNIFIED IDEOGRAPH + 0xF35A: 0x9AA6, //CJK UNIFIED IDEOGRAPH + 0xF35B: 0x9AA9, //CJK UNIFIED IDEOGRAPH + 0xF35C: 0x9AAA, //CJK UNIFIED IDEOGRAPH + 0xF35D: 0x9AAB, //CJK UNIFIED IDEOGRAPH + 0xF35E: 0x9AAC, //CJK UNIFIED IDEOGRAPH + 0xF35F: 0x9AAD, //CJK UNIFIED IDEOGRAPH + 0xF360: 0x9AAE, //CJK UNIFIED IDEOGRAPH + 0xF361: 0x9AAF, //CJK UNIFIED IDEOGRAPH + 0xF362: 0x9AB2, //CJK UNIFIED IDEOGRAPH + 0xF363: 0x9AB3, //CJK UNIFIED IDEOGRAPH + 0xF364: 0x9AB4, //CJK UNIFIED IDEOGRAPH + 0xF365: 0x9AB5, //CJK UNIFIED IDEOGRAPH + 0xF366: 0x9AB9, //CJK UNIFIED IDEOGRAPH + 0xF367: 0x9ABB, //CJK UNIFIED IDEOGRAPH + 0xF368: 0x9ABD, //CJK UNIFIED IDEOGRAPH + 0xF369: 0x9ABE, //CJK UNIFIED IDEOGRAPH + 0xF36A: 0x9ABF, //CJK UNIFIED IDEOGRAPH + 0xF36B: 0x9AC3, //CJK UNIFIED IDEOGRAPH + 0xF36C: 0x9AC4, //CJK UNIFIED IDEOGRAPH + 0xF36D: 0x9AC6, //CJK UNIFIED IDEOGRAPH + 0xF36E: 0x9AC7, //CJK UNIFIED IDEOGRAPH + 0xF36F: 0x9AC8, //CJK UNIFIED IDEOGRAPH + 0xF370: 0x9AC9, //CJK UNIFIED IDEOGRAPH + 0xF371: 0x9ACA, //CJK UNIFIED IDEOGRAPH + 0xF372: 0x9ACD, //CJK UNIFIED IDEOGRAPH + 0xF373: 0x9ACE, //CJK UNIFIED IDEOGRAPH + 0xF374: 0x9ACF, //CJK UNIFIED IDEOGRAPH + 0xF375: 0x9AD0, //CJK UNIFIED IDEOGRAPH + 0xF376: 0x9AD2, //CJK UNIFIED IDEOGRAPH + 0xF377: 0x9AD4, //CJK UNIFIED IDEOGRAPH + 0xF378: 0x9AD5, //CJK UNIFIED IDEOGRAPH + 0xF379: 0x9AD6, //CJK UNIFIED IDEOGRAPH + 0xF37A: 0x9AD7, //CJK UNIFIED IDEOGRAPH + 0xF37B: 0x9AD9, //CJK UNIFIED IDEOGRAPH + 0xF37C: 0x9ADA, //CJK UNIFIED IDEOGRAPH + 0xF37D: 0x9ADB, //CJK UNIFIED IDEOGRAPH + 0xF37E: 0x9ADC, //CJK UNIFIED IDEOGRAPH + 0xF380: 0x9ADD, //CJK UNIFIED IDEOGRAPH + 0xF381: 0x9ADE, //CJK UNIFIED IDEOGRAPH + 0xF382: 0x9AE0, //CJK UNIFIED IDEOGRAPH + 0xF383: 0x9AE2, //CJK UNIFIED IDEOGRAPH + 0xF384: 0x9AE3, //CJK UNIFIED IDEOGRAPH + 0xF385: 0x9AE4, //CJK UNIFIED IDEOGRAPH + 0xF386: 0x9AE5, //CJK UNIFIED IDEOGRAPH + 0xF387: 0x9AE7, //CJK UNIFIED IDEOGRAPH + 0xF388: 0x9AE8, //CJK UNIFIED IDEOGRAPH + 0xF389: 0x9AE9, //CJK UNIFIED IDEOGRAPH + 0xF38A: 0x9AEA, //CJK UNIFIED IDEOGRAPH + 0xF38B: 0x9AEC, //CJK UNIFIED IDEOGRAPH + 0xF38C: 0x9AEE, //CJK UNIFIED IDEOGRAPH + 0xF38D: 0x9AF0, //CJK UNIFIED IDEOGRAPH + 0xF38E: 0x9AF1, //CJK UNIFIED IDEOGRAPH + 0xF38F: 0x9AF2, //CJK UNIFIED IDEOGRAPH + 0xF390: 0x9AF3, //CJK UNIFIED IDEOGRAPH + 0xF391: 0x9AF4, //CJK UNIFIED IDEOGRAPH + 0xF392: 0x9AF5, //CJK UNIFIED IDEOGRAPH + 0xF393: 0x9AF6, //CJK UNIFIED IDEOGRAPH + 0xF394: 0x9AF7, //CJK UNIFIED IDEOGRAPH + 0xF395: 0x9AF8, //CJK UNIFIED IDEOGRAPH + 0xF396: 0x9AFA, //CJK UNIFIED IDEOGRAPH + 0xF397: 0x9AFC, //CJK UNIFIED IDEOGRAPH + 0xF398: 0x9AFD, //CJK UNIFIED IDEOGRAPH + 0xF399: 0x9AFE, //CJK UNIFIED IDEOGRAPH + 0xF39A: 0x9AFF, //CJK UNIFIED IDEOGRAPH + 0xF39B: 0x9B00, //CJK UNIFIED IDEOGRAPH + 0xF39C: 0x9B01, //CJK UNIFIED IDEOGRAPH + 0xF39D: 0x9B02, //CJK UNIFIED IDEOGRAPH + 0xF39E: 0x9B04, //CJK UNIFIED IDEOGRAPH + 0xF39F: 0x9B05, //CJK UNIFIED IDEOGRAPH + 0xF3A0: 0x9B06, //CJK UNIFIED IDEOGRAPH + 0xF3A1: 0x87C6, //CJK UNIFIED IDEOGRAPH + 0xF3A2: 0x8788, //CJK UNIFIED IDEOGRAPH + 0xF3A3: 0x8785, //CJK UNIFIED IDEOGRAPH + 0xF3A4: 0x87AD, //CJK UNIFIED IDEOGRAPH + 0xF3A5: 0x8797, //CJK UNIFIED IDEOGRAPH + 0xF3A6: 0x8783, //CJK UNIFIED IDEOGRAPH + 0xF3A7: 0x87AB, //CJK UNIFIED IDEOGRAPH + 0xF3A8: 0x87E5, //CJK UNIFIED IDEOGRAPH + 0xF3A9: 0x87AC, //CJK UNIFIED IDEOGRAPH + 0xF3AA: 0x87B5, //CJK UNIFIED IDEOGRAPH + 0xF3AB: 0x87B3, //CJK UNIFIED IDEOGRAPH + 0xF3AC: 0x87CB, //CJK UNIFIED IDEOGRAPH + 0xF3AD: 0x87D3, //CJK UNIFIED IDEOGRAPH + 0xF3AE: 0x87BD, //CJK UNIFIED IDEOGRAPH + 0xF3AF: 0x87D1, //CJK UNIFIED IDEOGRAPH + 0xF3B0: 0x87C0, //CJK UNIFIED IDEOGRAPH + 0xF3B1: 0x87CA, //CJK UNIFIED IDEOGRAPH + 0xF3B2: 0x87DB, //CJK UNIFIED IDEOGRAPH + 0xF3B3: 0x87EA, //CJK UNIFIED IDEOGRAPH + 0xF3B4: 0x87E0, //CJK UNIFIED IDEOGRAPH + 0xF3B5: 0x87EE, //CJK UNIFIED IDEOGRAPH + 0xF3B6: 0x8816, //CJK UNIFIED IDEOGRAPH + 0xF3B7: 0x8813, //CJK UNIFIED IDEOGRAPH + 0xF3B8: 0x87FE, //CJK UNIFIED IDEOGRAPH + 0xF3B9: 0x880A, //CJK UNIFIED IDEOGRAPH + 0xF3BA: 0x881B, //CJK UNIFIED IDEOGRAPH + 0xF3BB: 0x8821, //CJK UNIFIED IDEOGRAPH + 0xF3BC: 0x8839, //CJK UNIFIED IDEOGRAPH + 0xF3BD: 0x883C, //CJK UNIFIED IDEOGRAPH + 0xF3BE: 0x7F36, //CJK UNIFIED IDEOGRAPH + 0xF3BF: 0x7F42, //CJK UNIFIED IDEOGRAPH + 0xF3C0: 0x7F44, //CJK UNIFIED IDEOGRAPH + 0xF3C1: 0x7F45, //CJK UNIFIED IDEOGRAPH + 0xF3C2: 0x8210, //CJK UNIFIED IDEOGRAPH + 0xF3C3: 0x7AFA, //CJK UNIFIED IDEOGRAPH + 0xF3C4: 0x7AFD, //CJK UNIFIED IDEOGRAPH + 0xF3C5: 0x7B08, //CJK UNIFIED IDEOGRAPH + 0xF3C6: 0x7B03, //CJK UNIFIED IDEOGRAPH + 0xF3C7: 0x7B04, //CJK UNIFIED IDEOGRAPH + 0xF3C8: 0x7B15, //CJK UNIFIED IDEOGRAPH + 0xF3C9: 0x7B0A, //CJK UNIFIED IDEOGRAPH + 0xF3CA: 0x7B2B, //CJK UNIFIED IDEOGRAPH + 0xF3CB: 0x7B0F, //CJK UNIFIED IDEOGRAPH + 0xF3CC: 0x7B47, //CJK UNIFIED IDEOGRAPH + 0xF3CD: 0x7B38, //CJK UNIFIED IDEOGRAPH + 0xF3CE: 0x7B2A, //CJK UNIFIED IDEOGRAPH + 0xF3CF: 0x7B19, //CJK UNIFIED IDEOGRAPH + 0xF3D0: 0x7B2E, //CJK UNIFIED IDEOGRAPH + 0xF3D1: 0x7B31, //CJK UNIFIED IDEOGRAPH + 0xF3D2: 0x7B20, //CJK UNIFIED IDEOGRAPH + 0xF3D3: 0x7B25, //CJK UNIFIED IDEOGRAPH + 0xF3D4: 0x7B24, //CJK UNIFIED IDEOGRAPH + 0xF3D5: 0x7B33, //CJK UNIFIED IDEOGRAPH + 0xF3D6: 0x7B3E, //CJK UNIFIED IDEOGRAPH + 0xF3D7: 0x7B1E, //CJK UNIFIED IDEOGRAPH + 0xF3D8: 0x7B58, //CJK UNIFIED IDEOGRAPH + 0xF3D9: 0x7B5A, //CJK UNIFIED IDEOGRAPH + 0xF3DA: 0x7B45, //CJK UNIFIED IDEOGRAPH + 0xF3DB: 0x7B75, //CJK UNIFIED IDEOGRAPH + 0xF3DC: 0x7B4C, //CJK UNIFIED IDEOGRAPH + 0xF3DD: 0x7B5D, //CJK UNIFIED IDEOGRAPH + 0xF3DE: 0x7B60, //CJK UNIFIED IDEOGRAPH + 0xF3DF: 0x7B6E, //CJK UNIFIED IDEOGRAPH + 0xF3E0: 0x7B7B, //CJK UNIFIED IDEOGRAPH + 0xF3E1: 0x7B62, //CJK UNIFIED IDEOGRAPH + 0xF3E2: 0x7B72, //CJK UNIFIED IDEOGRAPH + 0xF3E3: 0x7B71, //CJK UNIFIED IDEOGRAPH + 0xF3E4: 0x7B90, //CJK UNIFIED IDEOGRAPH + 0xF3E5: 0x7BA6, //CJK UNIFIED IDEOGRAPH + 0xF3E6: 0x7BA7, //CJK UNIFIED IDEOGRAPH + 0xF3E7: 0x7BB8, //CJK UNIFIED IDEOGRAPH + 0xF3E8: 0x7BAC, //CJK UNIFIED IDEOGRAPH + 0xF3E9: 0x7B9D, //CJK UNIFIED IDEOGRAPH + 0xF3EA: 0x7BA8, //CJK UNIFIED IDEOGRAPH + 0xF3EB: 0x7B85, //CJK UNIFIED IDEOGRAPH + 0xF3EC: 0x7BAA, //CJK UNIFIED IDEOGRAPH + 0xF3ED: 0x7B9C, //CJK UNIFIED IDEOGRAPH + 0xF3EE: 0x7BA2, //CJK UNIFIED IDEOGRAPH + 0xF3EF: 0x7BAB, //CJK UNIFIED IDEOGRAPH + 0xF3F0: 0x7BB4, //CJK UNIFIED IDEOGRAPH + 0xF3F1: 0x7BD1, //CJK UNIFIED IDEOGRAPH + 0xF3F2: 0x7BC1, //CJK UNIFIED IDEOGRAPH + 0xF3F3: 0x7BCC, //CJK UNIFIED IDEOGRAPH + 0xF3F4: 0x7BDD, //CJK UNIFIED IDEOGRAPH + 0xF3F5: 0x7BDA, //CJK UNIFIED IDEOGRAPH + 0xF3F6: 0x7BE5, //CJK UNIFIED IDEOGRAPH + 0xF3F7: 0x7BE6, //CJK UNIFIED IDEOGRAPH + 0xF3F8: 0x7BEA, //CJK UNIFIED IDEOGRAPH + 0xF3F9: 0x7C0C, //CJK UNIFIED IDEOGRAPH + 0xF3FA: 0x7BFE, //CJK UNIFIED IDEOGRAPH + 0xF3FB: 0x7BFC, //CJK UNIFIED IDEOGRAPH + 0xF3FC: 0x7C0F, //CJK UNIFIED IDEOGRAPH + 0xF3FD: 0x7C16, //CJK UNIFIED IDEOGRAPH + 0xF3FE: 0x7C0B, //CJK UNIFIED IDEOGRAPH + 0xF440: 0x9B07, //CJK UNIFIED IDEOGRAPH + 0xF441: 0x9B09, //CJK UNIFIED IDEOGRAPH + 0xF442: 0x9B0A, //CJK UNIFIED IDEOGRAPH + 0xF443: 0x9B0B, //CJK UNIFIED IDEOGRAPH + 0xF444: 0x9B0C, //CJK UNIFIED IDEOGRAPH + 0xF445: 0x9B0D, //CJK UNIFIED IDEOGRAPH + 0xF446: 0x9B0E, //CJK UNIFIED IDEOGRAPH + 0xF447: 0x9B10, //CJK UNIFIED IDEOGRAPH + 0xF448: 0x9B11, //CJK UNIFIED IDEOGRAPH + 0xF449: 0x9B12, //CJK UNIFIED IDEOGRAPH + 0xF44A: 0x9B14, //CJK UNIFIED IDEOGRAPH + 0xF44B: 0x9B15, //CJK UNIFIED IDEOGRAPH + 0xF44C: 0x9B16, //CJK UNIFIED IDEOGRAPH + 0xF44D: 0x9B17, //CJK UNIFIED IDEOGRAPH + 0xF44E: 0x9B18, //CJK UNIFIED IDEOGRAPH + 0xF44F: 0x9B19, //CJK UNIFIED IDEOGRAPH + 0xF450: 0x9B1A, //CJK UNIFIED IDEOGRAPH + 0xF451: 0x9B1B, //CJK UNIFIED IDEOGRAPH + 0xF452: 0x9B1C, //CJK UNIFIED IDEOGRAPH + 0xF453: 0x9B1D, //CJK UNIFIED IDEOGRAPH + 0xF454: 0x9B1E, //CJK UNIFIED IDEOGRAPH + 0xF455: 0x9B20, //CJK UNIFIED IDEOGRAPH + 0xF456: 0x9B21, //CJK UNIFIED IDEOGRAPH + 0xF457: 0x9B22, //CJK UNIFIED IDEOGRAPH + 0xF458: 0x9B24, //CJK UNIFIED IDEOGRAPH + 0xF459: 0x9B25, //CJK UNIFIED IDEOGRAPH + 0xF45A: 0x9B26, //CJK UNIFIED IDEOGRAPH + 0xF45B: 0x9B27, //CJK UNIFIED IDEOGRAPH + 0xF45C: 0x9B28, //CJK UNIFIED IDEOGRAPH + 0xF45D: 0x9B29, //CJK UNIFIED IDEOGRAPH + 0xF45E: 0x9B2A, //CJK UNIFIED IDEOGRAPH + 0xF45F: 0x9B2B, //CJK UNIFIED IDEOGRAPH + 0xF460: 0x9B2C, //CJK UNIFIED IDEOGRAPH + 0xF461: 0x9B2D, //CJK UNIFIED IDEOGRAPH + 0xF462: 0x9B2E, //CJK UNIFIED IDEOGRAPH + 0xF463: 0x9B30, //CJK UNIFIED IDEOGRAPH + 0xF464: 0x9B31, //CJK UNIFIED IDEOGRAPH + 0xF465: 0x9B33, //CJK UNIFIED IDEOGRAPH + 0xF466: 0x9B34, //CJK UNIFIED IDEOGRAPH + 0xF467: 0x9B35, //CJK UNIFIED IDEOGRAPH + 0xF468: 0x9B36, //CJK UNIFIED IDEOGRAPH + 0xF469: 0x9B37, //CJK UNIFIED IDEOGRAPH + 0xF46A: 0x9B38, //CJK UNIFIED IDEOGRAPH + 0xF46B: 0x9B39, //CJK UNIFIED IDEOGRAPH + 0xF46C: 0x9B3A, //CJK UNIFIED IDEOGRAPH + 0xF46D: 0x9B3D, //CJK UNIFIED IDEOGRAPH + 0xF46E: 0x9B3E, //CJK UNIFIED IDEOGRAPH + 0xF46F: 0x9B3F, //CJK UNIFIED IDEOGRAPH + 0xF470: 0x9B40, //CJK UNIFIED IDEOGRAPH + 0xF471: 0x9B46, //CJK UNIFIED IDEOGRAPH + 0xF472: 0x9B4A, //CJK UNIFIED IDEOGRAPH + 0xF473: 0x9B4B, //CJK UNIFIED IDEOGRAPH + 0xF474: 0x9B4C, //CJK UNIFIED IDEOGRAPH + 0xF475: 0x9B4E, //CJK UNIFIED IDEOGRAPH + 0xF476: 0x9B50, //CJK UNIFIED IDEOGRAPH + 0xF477: 0x9B52, //CJK UNIFIED IDEOGRAPH + 0xF478: 0x9B53, //CJK UNIFIED IDEOGRAPH + 0xF479: 0x9B55, //CJK UNIFIED IDEOGRAPH + 0xF47A: 0x9B56, //CJK UNIFIED IDEOGRAPH + 0xF47B: 0x9B57, //CJK UNIFIED IDEOGRAPH + 0xF47C: 0x9B58, //CJK UNIFIED IDEOGRAPH + 0xF47D: 0x9B59, //CJK UNIFIED IDEOGRAPH + 0xF47E: 0x9B5A, //CJK UNIFIED IDEOGRAPH + 0xF480: 0x9B5B, //CJK UNIFIED IDEOGRAPH + 0xF481: 0x9B5C, //CJK UNIFIED IDEOGRAPH + 0xF482: 0x9B5D, //CJK UNIFIED IDEOGRAPH + 0xF483: 0x9B5E, //CJK UNIFIED IDEOGRAPH + 0xF484: 0x9B5F, //CJK UNIFIED IDEOGRAPH + 0xF485: 0x9B60, //CJK UNIFIED IDEOGRAPH + 0xF486: 0x9B61, //CJK UNIFIED IDEOGRAPH + 0xF487: 0x9B62, //CJK UNIFIED IDEOGRAPH + 0xF488: 0x9B63, //CJK UNIFIED IDEOGRAPH + 0xF489: 0x9B64, //CJK UNIFIED IDEOGRAPH + 0xF48A: 0x9B65, //CJK UNIFIED IDEOGRAPH + 0xF48B: 0x9B66, //CJK UNIFIED IDEOGRAPH + 0xF48C: 0x9B67, //CJK UNIFIED IDEOGRAPH + 0xF48D: 0x9B68, //CJK UNIFIED IDEOGRAPH + 0xF48E: 0x9B69, //CJK UNIFIED IDEOGRAPH + 0xF48F: 0x9B6A, //CJK UNIFIED IDEOGRAPH + 0xF490: 0x9B6B, //CJK UNIFIED IDEOGRAPH + 0xF491: 0x9B6C, //CJK UNIFIED IDEOGRAPH + 0xF492: 0x9B6D, //CJK UNIFIED IDEOGRAPH + 0xF493: 0x9B6E, //CJK UNIFIED IDEOGRAPH + 0xF494: 0x9B6F, //CJK UNIFIED IDEOGRAPH + 0xF495: 0x9B70, //CJK UNIFIED IDEOGRAPH + 0xF496: 0x9B71, //CJK UNIFIED IDEOGRAPH + 0xF497: 0x9B72, //CJK UNIFIED IDEOGRAPH + 0xF498: 0x9B73, //CJK UNIFIED IDEOGRAPH + 0xF499: 0x9B74, //CJK UNIFIED IDEOGRAPH + 0xF49A: 0x9B75, //CJK UNIFIED IDEOGRAPH + 0xF49B: 0x9B76, //CJK UNIFIED IDEOGRAPH + 0xF49C: 0x9B77, //CJK UNIFIED IDEOGRAPH + 0xF49D: 0x9B78, //CJK UNIFIED IDEOGRAPH + 0xF49E: 0x9B79, //CJK UNIFIED IDEOGRAPH + 0xF49F: 0x9B7A, //CJK UNIFIED IDEOGRAPH + 0xF4A0: 0x9B7B, //CJK UNIFIED IDEOGRAPH + 0xF4A1: 0x7C1F, //CJK UNIFIED IDEOGRAPH + 0xF4A2: 0x7C2A, //CJK UNIFIED IDEOGRAPH + 0xF4A3: 0x7C26, //CJK UNIFIED IDEOGRAPH + 0xF4A4: 0x7C38, //CJK UNIFIED IDEOGRAPH + 0xF4A5: 0x7C41, //CJK UNIFIED IDEOGRAPH + 0xF4A6: 0x7C40, //CJK UNIFIED IDEOGRAPH + 0xF4A7: 0x81FE, //CJK UNIFIED IDEOGRAPH + 0xF4A8: 0x8201, //CJK UNIFIED IDEOGRAPH + 0xF4A9: 0x8202, //CJK UNIFIED IDEOGRAPH + 0xF4AA: 0x8204, //CJK UNIFIED IDEOGRAPH + 0xF4AB: 0x81EC, //CJK UNIFIED IDEOGRAPH + 0xF4AC: 0x8844, //CJK UNIFIED IDEOGRAPH + 0xF4AD: 0x8221, //CJK UNIFIED IDEOGRAPH + 0xF4AE: 0x8222, //CJK UNIFIED IDEOGRAPH + 0xF4AF: 0x8223, //CJK UNIFIED IDEOGRAPH + 0xF4B0: 0x822D, //CJK UNIFIED IDEOGRAPH + 0xF4B1: 0x822F, //CJK UNIFIED IDEOGRAPH + 0xF4B2: 0x8228, //CJK UNIFIED IDEOGRAPH + 0xF4B3: 0x822B, //CJK UNIFIED IDEOGRAPH + 0xF4B4: 0x8238, //CJK UNIFIED IDEOGRAPH + 0xF4B5: 0x823B, //CJK UNIFIED IDEOGRAPH + 0xF4B6: 0x8233, //CJK UNIFIED IDEOGRAPH + 0xF4B7: 0x8234, //CJK UNIFIED IDEOGRAPH + 0xF4B8: 0x823E, //CJK UNIFIED IDEOGRAPH + 0xF4B9: 0x8244, //CJK UNIFIED IDEOGRAPH + 0xF4BA: 0x8249, //CJK UNIFIED IDEOGRAPH + 0xF4BB: 0x824B, //CJK UNIFIED IDEOGRAPH + 0xF4BC: 0x824F, //CJK UNIFIED IDEOGRAPH + 0xF4BD: 0x825A, //CJK UNIFIED IDEOGRAPH + 0xF4BE: 0x825F, //CJK UNIFIED IDEOGRAPH + 0xF4BF: 0x8268, //CJK UNIFIED IDEOGRAPH + 0xF4C0: 0x887E, //CJK UNIFIED IDEOGRAPH + 0xF4C1: 0x8885, //CJK UNIFIED IDEOGRAPH + 0xF4C2: 0x8888, //CJK UNIFIED IDEOGRAPH + 0xF4C3: 0x88D8, //CJK UNIFIED IDEOGRAPH + 0xF4C4: 0x88DF, //CJK UNIFIED IDEOGRAPH + 0xF4C5: 0x895E, //CJK UNIFIED IDEOGRAPH + 0xF4C6: 0x7F9D, //CJK UNIFIED IDEOGRAPH + 0xF4C7: 0x7F9F, //CJK UNIFIED IDEOGRAPH + 0xF4C8: 0x7FA7, //CJK UNIFIED IDEOGRAPH + 0xF4C9: 0x7FAF, //CJK UNIFIED IDEOGRAPH + 0xF4CA: 0x7FB0, //CJK UNIFIED IDEOGRAPH + 0xF4CB: 0x7FB2, //CJK UNIFIED IDEOGRAPH + 0xF4CC: 0x7C7C, //CJK UNIFIED IDEOGRAPH + 0xF4CD: 0x6549, //CJK UNIFIED IDEOGRAPH + 0xF4CE: 0x7C91, //CJK UNIFIED IDEOGRAPH + 0xF4CF: 0x7C9D, //CJK UNIFIED IDEOGRAPH + 0xF4D0: 0x7C9C, //CJK UNIFIED IDEOGRAPH + 0xF4D1: 0x7C9E, //CJK UNIFIED IDEOGRAPH + 0xF4D2: 0x7CA2, //CJK UNIFIED IDEOGRAPH + 0xF4D3: 0x7CB2, //CJK UNIFIED IDEOGRAPH + 0xF4D4: 0x7CBC, //CJK UNIFIED IDEOGRAPH + 0xF4D5: 0x7CBD, //CJK UNIFIED IDEOGRAPH + 0xF4D6: 0x7CC1, //CJK UNIFIED IDEOGRAPH + 0xF4D7: 0x7CC7, //CJK UNIFIED IDEOGRAPH + 0xF4D8: 0x7CCC, //CJK UNIFIED IDEOGRAPH + 0xF4D9: 0x7CCD, //CJK UNIFIED IDEOGRAPH + 0xF4DA: 0x7CC8, //CJK UNIFIED IDEOGRAPH + 0xF4DB: 0x7CC5, //CJK UNIFIED IDEOGRAPH + 0xF4DC: 0x7CD7, //CJK UNIFIED IDEOGRAPH + 0xF4DD: 0x7CE8, //CJK UNIFIED IDEOGRAPH + 0xF4DE: 0x826E, //CJK UNIFIED IDEOGRAPH + 0xF4DF: 0x66A8, //CJK UNIFIED IDEOGRAPH + 0xF4E0: 0x7FBF, //CJK UNIFIED IDEOGRAPH + 0xF4E1: 0x7FCE, //CJK UNIFIED IDEOGRAPH + 0xF4E2: 0x7FD5, //CJK UNIFIED IDEOGRAPH + 0xF4E3: 0x7FE5, //CJK UNIFIED IDEOGRAPH + 0xF4E4: 0x7FE1, //CJK UNIFIED IDEOGRAPH + 0xF4E5: 0x7FE6, //CJK UNIFIED IDEOGRAPH + 0xF4E6: 0x7FE9, //CJK UNIFIED IDEOGRAPH + 0xF4E7: 0x7FEE, //CJK UNIFIED IDEOGRAPH + 0xF4E8: 0x7FF3, //CJK UNIFIED IDEOGRAPH + 0xF4E9: 0x7CF8, //CJK UNIFIED IDEOGRAPH + 0xF4EA: 0x7D77, //CJK UNIFIED IDEOGRAPH + 0xF4EB: 0x7DA6, //CJK UNIFIED IDEOGRAPH + 0xF4EC: 0x7DAE, //CJK UNIFIED IDEOGRAPH + 0xF4ED: 0x7E47, //CJK UNIFIED IDEOGRAPH + 0xF4EE: 0x7E9B, //CJK UNIFIED IDEOGRAPH + 0xF4EF: 0x9EB8, //CJK UNIFIED IDEOGRAPH + 0xF4F0: 0x9EB4, //CJK UNIFIED IDEOGRAPH + 0xF4F1: 0x8D73, //CJK UNIFIED IDEOGRAPH + 0xF4F2: 0x8D84, //CJK UNIFIED IDEOGRAPH + 0xF4F3: 0x8D94, //CJK UNIFIED IDEOGRAPH + 0xF4F4: 0x8D91, //CJK UNIFIED IDEOGRAPH + 0xF4F5: 0x8DB1, //CJK UNIFIED IDEOGRAPH + 0xF4F6: 0x8D67, //CJK UNIFIED IDEOGRAPH + 0xF4F7: 0x8D6D, //CJK UNIFIED IDEOGRAPH + 0xF4F8: 0x8C47, //CJK UNIFIED IDEOGRAPH + 0xF4F9: 0x8C49, //CJK UNIFIED IDEOGRAPH + 0xF4FA: 0x914A, //CJK UNIFIED IDEOGRAPH + 0xF4FB: 0x9150, //CJK UNIFIED IDEOGRAPH + 0xF4FC: 0x914E, //CJK UNIFIED IDEOGRAPH + 0xF4FD: 0x914F, //CJK UNIFIED IDEOGRAPH + 0xF4FE: 0x9164, //CJK UNIFIED IDEOGRAPH + 0xF540: 0x9B7C, //CJK UNIFIED IDEOGRAPH + 0xF541: 0x9B7D, //CJK UNIFIED IDEOGRAPH + 0xF542: 0x9B7E, //CJK UNIFIED IDEOGRAPH + 0xF543: 0x9B7F, //CJK UNIFIED IDEOGRAPH + 0xF544: 0x9B80, //CJK UNIFIED IDEOGRAPH + 0xF545: 0x9B81, //CJK UNIFIED IDEOGRAPH + 0xF546: 0x9B82, //CJK UNIFIED IDEOGRAPH + 0xF547: 0x9B83, //CJK UNIFIED IDEOGRAPH + 0xF548: 0x9B84, //CJK UNIFIED IDEOGRAPH + 0xF549: 0x9B85, //CJK UNIFIED IDEOGRAPH + 0xF54A: 0x9B86, //CJK UNIFIED IDEOGRAPH + 0xF54B: 0x9B87, //CJK UNIFIED IDEOGRAPH + 0xF54C: 0x9B88, //CJK UNIFIED IDEOGRAPH + 0xF54D: 0x9B89, //CJK UNIFIED IDEOGRAPH + 0xF54E: 0x9B8A, //CJK UNIFIED IDEOGRAPH + 0xF54F: 0x9B8B, //CJK UNIFIED IDEOGRAPH + 0xF550: 0x9B8C, //CJK UNIFIED IDEOGRAPH + 0xF551: 0x9B8D, //CJK UNIFIED IDEOGRAPH + 0xF552: 0x9B8E, //CJK UNIFIED IDEOGRAPH + 0xF553: 0x9B8F, //CJK UNIFIED IDEOGRAPH + 0xF554: 0x9B90, //CJK UNIFIED IDEOGRAPH + 0xF555: 0x9B91, //CJK UNIFIED IDEOGRAPH + 0xF556: 0x9B92, //CJK UNIFIED IDEOGRAPH + 0xF557: 0x9B93, //CJK UNIFIED IDEOGRAPH + 0xF558: 0x9B94, //CJK UNIFIED IDEOGRAPH + 0xF559: 0x9B95, //CJK UNIFIED IDEOGRAPH + 0xF55A: 0x9B96, //CJK UNIFIED IDEOGRAPH + 0xF55B: 0x9B97, //CJK UNIFIED IDEOGRAPH + 0xF55C: 0x9B98, //CJK UNIFIED IDEOGRAPH + 0xF55D: 0x9B99, //CJK UNIFIED IDEOGRAPH + 0xF55E: 0x9B9A, //CJK UNIFIED IDEOGRAPH + 0xF55F: 0x9B9B, //CJK UNIFIED IDEOGRAPH + 0xF560: 0x9B9C, //CJK UNIFIED IDEOGRAPH + 0xF561: 0x9B9D, //CJK UNIFIED IDEOGRAPH + 0xF562: 0x9B9E, //CJK UNIFIED IDEOGRAPH + 0xF563: 0x9B9F, //CJK UNIFIED IDEOGRAPH + 0xF564: 0x9BA0, //CJK UNIFIED IDEOGRAPH + 0xF565: 0x9BA1, //CJK UNIFIED IDEOGRAPH + 0xF566: 0x9BA2, //CJK UNIFIED IDEOGRAPH + 0xF567: 0x9BA3, //CJK UNIFIED IDEOGRAPH + 0xF568: 0x9BA4, //CJK UNIFIED IDEOGRAPH + 0xF569: 0x9BA5, //CJK UNIFIED IDEOGRAPH + 0xF56A: 0x9BA6, //CJK UNIFIED IDEOGRAPH + 0xF56B: 0x9BA7, //CJK UNIFIED IDEOGRAPH + 0xF56C: 0x9BA8, //CJK UNIFIED IDEOGRAPH + 0xF56D: 0x9BA9, //CJK UNIFIED IDEOGRAPH + 0xF56E: 0x9BAA, //CJK UNIFIED IDEOGRAPH + 0xF56F: 0x9BAB, //CJK UNIFIED IDEOGRAPH + 0xF570: 0x9BAC, //CJK UNIFIED IDEOGRAPH + 0xF571: 0x9BAD, //CJK UNIFIED IDEOGRAPH + 0xF572: 0x9BAE, //CJK UNIFIED IDEOGRAPH + 0xF573: 0x9BAF, //CJK UNIFIED IDEOGRAPH + 0xF574: 0x9BB0, //CJK UNIFIED IDEOGRAPH + 0xF575: 0x9BB1, //CJK UNIFIED IDEOGRAPH + 0xF576: 0x9BB2, //CJK UNIFIED IDEOGRAPH + 0xF577: 0x9BB3, //CJK UNIFIED IDEOGRAPH + 0xF578: 0x9BB4, //CJK UNIFIED IDEOGRAPH + 0xF579: 0x9BB5, //CJK UNIFIED IDEOGRAPH + 0xF57A: 0x9BB6, //CJK UNIFIED IDEOGRAPH + 0xF57B: 0x9BB7, //CJK UNIFIED IDEOGRAPH + 0xF57C: 0x9BB8, //CJK UNIFIED IDEOGRAPH + 0xF57D: 0x9BB9, //CJK UNIFIED IDEOGRAPH + 0xF57E: 0x9BBA, //CJK UNIFIED IDEOGRAPH + 0xF580: 0x9BBB, //CJK UNIFIED IDEOGRAPH + 0xF581: 0x9BBC, //CJK UNIFIED IDEOGRAPH + 0xF582: 0x9BBD, //CJK UNIFIED IDEOGRAPH + 0xF583: 0x9BBE, //CJK UNIFIED IDEOGRAPH + 0xF584: 0x9BBF, //CJK UNIFIED IDEOGRAPH + 0xF585: 0x9BC0, //CJK UNIFIED IDEOGRAPH + 0xF586: 0x9BC1, //CJK UNIFIED IDEOGRAPH + 0xF587: 0x9BC2, //CJK UNIFIED IDEOGRAPH + 0xF588: 0x9BC3, //CJK UNIFIED IDEOGRAPH + 0xF589: 0x9BC4, //CJK UNIFIED IDEOGRAPH + 0xF58A: 0x9BC5, //CJK UNIFIED IDEOGRAPH + 0xF58B: 0x9BC6, //CJK UNIFIED IDEOGRAPH + 0xF58C: 0x9BC7, //CJK UNIFIED IDEOGRAPH + 0xF58D: 0x9BC8, //CJK UNIFIED IDEOGRAPH + 0xF58E: 0x9BC9, //CJK UNIFIED IDEOGRAPH + 0xF58F: 0x9BCA, //CJK UNIFIED IDEOGRAPH + 0xF590: 0x9BCB, //CJK UNIFIED IDEOGRAPH + 0xF591: 0x9BCC, //CJK UNIFIED IDEOGRAPH + 0xF592: 0x9BCD, //CJK UNIFIED IDEOGRAPH + 0xF593: 0x9BCE, //CJK UNIFIED IDEOGRAPH + 0xF594: 0x9BCF, //CJK UNIFIED IDEOGRAPH + 0xF595: 0x9BD0, //CJK UNIFIED IDEOGRAPH + 0xF596: 0x9BD1, //CJK UNIFIED IDEOGRAPH + 0xF597: 0x9BD2, //CJK UNIFIED IDEOGRAPH + 0xF598: 0x9BD3, //CJK UNIFIED IDEOGRAPH + 0xF599: 0x9BD4, //CJK UNIFIED IDEOGRAPH + 0xF59A: 0x9BD5, //CJK UNIFIED IDEOGRAPH + 0xF59B: 0x9BD6, //CJK UNIFIED IDEOGRAPH + 0xF59C: 0x9BD7, //CJK UNIFIED IDEOGRAPH + 0xF59D: 0x9BD8, //CJK UNIFIED IDEOGRAPH + 0xF59E: 0x9BD9, //CJK UNIFIED IDEOGRAPH + 0xF59F: 0x9BDA, //CJK UNIFIED IDEOGRAPH + 0xF5A0: 0x9BDB, //CJK UNIFIED IDEOGRAPH + 0xF5A1: 0x9162, //CJK UNIFIED IDEOGRAPH + 0xF5A2: 0x9161, //CJK UNIFIED IDEOGRAPH + 0xF5A3: 0x9170, //CJK UNIFIED IDEOGRAPH + 0xF5A4: 0x9169, //CJK UNIFIED IDEOGRAPH + 0xF5A5: 0x916F, //CJK UNIFIED IDEOGRAPH + 0xF5A6: 0x917D, //CJK UNIFIED IDEOGRAPH + 0xF5A7: 0x917E, //CJK UNIFIED IDEOGRAPH + 0xF5A8: 0x9172, //CJK UNIFIED IDEOGRAPH + 0xF5A9: 0x9174, //CJK UNIFIED IDEOGRAPH + 0xF5AA: 0x9179, //CJK UNIFIED IDEOGRAPH + 0xF5AB: 0x918C, //CJK UNIFIED IDEOGRAPH + 0xF5AC: 0x9185, //CJK UNIFIED IDEOGRAPH + 0xF5AD: 0x9190, //CJK UNIFIED IDEOGRAPH + 0xF5AE: 0x918D, //CJK UNIFIED IDEOGRAPH + 0xF5AF: 0x9191, //CJK UNIFIED IDEOGRAPH + 0xF5B0: 0x91A2, //CJK UNIFIED IDEOGRAPH + 0xF5B1: 0x91A3, //CJK UNIFIED IDEOGRAPH + 0xF5B2: 0x91AA, //CJK UNIFIED IDEOGRAPH + 0xF5B3: 0x91AD, //CJK UNIFIED IDEOGRAPH + 0xF5B4: 0x91AE, //CJK UNIFIED IDEOGRAPH + 0xF5B5: 0x91AF, //CJK UNIFIED IDEOGRAPH + 0xF5B6: 0x91B5, //CJK UNIFIED IDEOGRAPH + 0xF5B7: 0x91B4, //CJK UNIFIED IDEOGRAPH + 0xF5B8: 0x91BA, //CJK UNIFIED IDEOGRAPH + 0xF5B9: 0x8C55, //CJK UNIFIED IDEOGRAPH + 0xF5BA: 0x9E7E, //CJK UNIFIED IDEOGRAPH + 0xF5BB: 0x8DB8, //CJK UNIFIED IDEOGRAPH + 0xF5BC: 0x8DEB, //CJK UNIFIED IDEOGRAPH + 0xF5BD: 0x8E05, //CJK UNIFIED IDEOGRAPH + 0xF5BE: 0x8E59, //CJK UNIFIED IDEOGRAPH + 0xF5BF: 0x8E69, //CJK UNIFIED IDEOGRAPH + 0xF5C0: 0x8DB5, //CJK UNIFIED IDEOGRAPH + 0xF5C1: 0x8DBF, //CJK UNIFIED IDEOGRAPH + 0xF5C2: 0x8DBC, //CJK UNIFIED IDEOGRAPH + 0xF5C3: 0x8DBA, //CJK UNIFIED IDEOGRAPH + 0xF5C4: 0x8DC4, //CJK UNIFIED IDEOGRAPH + 0xF5C5: 0x8DD6, //CJK UNIFIED IDEOGRAPH + 0xF5C6: 0x8DD7, //CJK UNIFIED IDEOGRAPH + 0xF5C7: 0x8DDA, //CJK UNIFIED IDEOGRAPH + 0xF5C8: 0x8DDE, //CJK UNIFIED IDEOGRAPH + 0xF5C9: 0x8DCE, //CJK UNIFIED IDEOGRAPH + 0xF5CA: 0x8DCF, //CJK UNIFIED IDEOGRAPH + 0xF5CB: 0x8DDB, //CJK UNIFIED IDEOGRAPH + 0xF5CC: 0x8DC6, //CJK UNIFIED IDEOGRAPH + 0xF5CD: 0x8DEC, //CJK UNIFIED IDEOGRAPH + 0xF5CE: 0x8DF7, //CJK UNIFIED IDEOGRAPH + 0xF5CF: 0x8DF8, //CJK UNIFIED IDEOGRAPH + 0xF5D0: 0x8DE3, //CJK UNIFIED IDEOGRAPH + 0xF5D1: 0x8DF9, //CJK UNIFIED IDEOGRAPH + 0xF5D2: 0x8DFB, //CJK UNIFIED IDEOGRAPH + 0xF5D3: 0x8DE4, //CJK UNIFIED IDEOGRAPH + 0xF5D4: 0x8E09, //CJK UNIFIED IDEOGRAPH + 0xF5D5: 0x8DFD, //CJK UNIFIED IDEOGRAPH + 0xF5D6: 0x8E14, //CJK UNIFIED IDEOGRAPH + 0xF5D7: 0x8E1D, //CJK UNIFIED IDEOGRAPH + 0xF5D8: 0x8E1F, //CJK UNIFIED IDEOGRAPH + 0xF5D9: 0x8E2C, //CJK UNIFIED IDEOGRAPH + 0xF5DA: 0x8E2E, //CJK UNIFIED IDEOGRAPH + 0xF5DB: 0x8E23, //CJK UNIFIED IDEOGRAPH + 0xF5DC: 0x8E2F, //CJK UNIFIED IDEOGRAPH + 0xF5DD: 0x8E3A, //CJK UNIFIED IDEOGRAPH + 0xF5DE: 0x8E40, //CJK UNIFIED IDEOGRAPH + 0xF5DF: 0x8E39, //CJK UNIFIED IDEOGRAPH + 0xF5E0: 0x8E35, //CJK UNIFIED IDEOGRAPH + 0xF5E1: 0x8E3D, //CJK UNIFIED IDEOGRAPH + 0xF5E2: 0x8E31, //CJK UNIFIED IDEOGRAPH + 0xF5E3: 0x8E49, //CJK UNIFIED IDEOGRAPH + 0xF5E4: 0x8E41, //CJK UNIFIED IDEOGRAPH + 0xF5E5: 0x8E42, //CJK UNIFIED IDEOGRAPH + 0xF5E6: 0x8E51, //CJK UNIFIED IDEOGRAPH + 0xF5E7: 0x8E52, //CJK UNIFIED IDEOGRAPH + 0xF5E8: 0x8E4A, //CJK UNIFIED IDEOGRAPH + 0xF5E9: 0x8E70, //CJK UNIFIED IDEOGRAPH + 0xF5EA: 0x8E76, //CJK UNIFIED IDEOGRAPH + 0xF5EB: 0x8E7C, //CJK UNIFIED IDEOGRAPH + 0xF5EC: 0x8E6F, //CJK UNIFIED IDEOGRAPH + 0xF5ED: 0x8E74, //CJK UNIFIED IDEOGRAPH + 0xF5EE: 0x8E85, //CJK UNIFIED IDEOGRAPH + 0xF5EF: 0x8E8F, //CJK UNIFIED IDEOGRAPH + 0xF5F0: 0x8E94, //CJK UNIFIED IDEOGRAPH + 0xF5F1: 0x8E90, //CJK UNIFIED IDEOGRAPH + 0xF5F2: 0x8E9C, //CJK UNIFIED IDEOGRAPH + 0xF5F3: 0x8E9E, //CJK UNIFIED IDEOGRAPH + 0xF5F4: 0x8C78, //CJK UNIFIED IDEOGRAPH + 0xF5F5: 0x8C82, //CJK UNIFIED IDEOGRAPH + 0xF5F6: 0x8C8A, //CJK UNIFIED IDEOGRAPH + 0xF5F7: 0x8C85, //CJK UNIFIED IDEOGRAPH + 0xF5F8: 0x8C98, //CJK UNIFIED IDEOGRAPH + 0xF5F9: 0x8C94, //CJK UNIFIED IDEOGRAPH + 0xF5FA: 0x659B, //CJK UNIFIED IDEOGRAPH + 0xF5FB: 0x89D6, //CJK UNIFIED IDEOGRAPH + 0xF5FC: 0x89DE, //CJK UNIFIED IDEOGRAPH + 0xF5FD: 0x89DA, //CJK UNIFIED IDEOGRAPH + 0xF5FE: 0x89DC, //CJK UNIFIED IDEOGRAPH + 0xF640: 0x9BDC, //CJK UNIFIED IDEOGRAPH + 0xF641: 0x9BDD, //CJK UNIFIED IDEOGRAPH + 0xF642: 0x9BDE, //CJK UNIFIED IDEOGRAPH + 0xF643: 0x9BDF, //CJK UNIFIED IDEOGRAPH + 0xF644: 0x9BE0, //CJK UNIFIED IDEOGRAPH + 0xF645: 0x9BE1, //CJK UNIFIED IDEOGRAPH + 0xF646: 0x9BE2, //CJK UNIFIED IDEOGRAPH + 0xF647: 0x9BE3, //CJK UNIFIED IDEOGRAPH + 0xF648: 0x9BE4, //CJK UNIFIED IDEOGRAPH + 0xF649: 0x9BE5, //CJK UNIFIED IDEOGRAPH + 0xF64A: 0x9BE6, //CJK UNIFIED IDEOGRAPH + 0xF64B: 0x9BE7, //CJK UNIFIED IDEOGRAPH + 0xF64C: 0x9BE8, //CJK UNIFIED IDEOGRAPH + 0xF64D: 0x9BE9, //CJK UNIFIED IDEOGRAPH + 0xF64E: 0x9BEA, //CJK UNIFIED IDEOGRAPH + 0xF64F: 0x9BEB, //CJK UNIFIED IDEOGRAPH + 0xF650: 0x9BEC, //CJK UNIFIED IDEOGRAPH + 0xF651: 0x9BED, //CJK UNIFIED IDEOGRAPH + 0xF652: 0x9BEE, //CJK UNIFIED IDEOGRAPH + 0xF653: 0x9BEF, //CJK UNIFIED IDEOGRAPH + 0xF654: 0x9BF0, //CJK UNIFIED IDEOGRAPH + 0xF655: 0x9BF1, //CJK UNIFIED IDEOGRAPH + 0xF656: 0x9BF2, //CJK UNIFIED IDEOGRAPH + 0xF657: 0x9BF3, //CJK UNIFIED IDEOGRAPH + 0xF658: 0x9BF4, //CJK UNIFIED IDEOGRAPH + 0xF659: 0x9BF5, //CJK UNIFIED IDEOGRAPH + 0xF65A: 0x9BF6, //CJK UNIFIED IDEOGRAPH + 0xF65B: 0x9BF7, //CJK UNIFIED IDEOGRAPH + 0xF65C: 0x9BF8, //CJK UNIFIED IDEOGRAPH + 0xF65D: 0x9BF9, //CJK UNIFIED IDEOGRAPH + 0xF65E: 0x9BFA, //CJK UNIFIED IDEOGRAPH + 0xF65F: 0x9BFB, //CJK UNIFIED IDEOGRAPH + 0xF660: 0x9BFC, //CJK UNIFIED IDEOGRAPH + 0xF661: 0x9BFD, //CJK UNIFIED IDEOGRAPH + 0xF662: 0x9BFE, //CJK UNIFIED IDEOGRAPH + 0xF663: 0x9BFF, //CJK UNIFIED IDEOGRAPH + 0xF664: 0x9C00, //CJK UNIFIED IDEOGRAPH + 0xF665: 0x9C01, //CJK UNIFIED IDEOGRAPH + 0xF666: 0x9C02, //CJK UNIFIED IDEOGRAPH + 0xF667: 0x9C03, //CJK UNIFIED IDEOGRAPH + 0xF668: 0x9C04, //CJK UNIFIED IDEOGRAPH + 0xF669: 0x9C05, //CJK UNIFIED IDEOGRAPH + 0xF66A: 0x9C06, //CJK UNIFIED IDEOGRAPH + 0xF66B: 0x9C07, //CJK UNIFIED IDEOGRAPH + 0xF66C: 0x9C08, //CJK UNIFIED IDEOGRAPH + 0xF66D: 0x9C09, //CJK UNIFIED IDEOGRAPH + 0xF66E: 0x9C0A, //CJK UNIFIED IDEOGRAPH + 0xF66F: 0x9C0B, //CJK UNIFIED IDEOGRAPH + 0xF670: 0x9C0C, //CJK UNIFIED IDEOGRAPH + 0xF671: 0x9C0D, //CJK UNIFIED IDEOGRAPH + 0xF672: 0x9C0E, //CJK UNIFIED IDEOGRAPH + 0xF673: 0x9C0F, //CJK UNIFIED IDEOGRAPH + 0xF674: 0x9C10, //CJK UNIFIED IDEOGRAPH + 0xF675: 0x9C11, //CJK UNIFIED IDEOGRAPH + 0xF676: 0x9C12, //CJK UNIFIED IDEOGRAPH + 0xF677: 0x9C13, //CJK UNIFIED IDEOGRAPH + 0xF678: 0x9C14, //CJK UNIFIED IDEOGRAPH + 0xF679: 0x9C15, //CJK UNIFIED IDEOGRAPH + 0xF67A: 0x9C16, //CJK UNIFIED IDEOGRAPH + 0xF67B: 0x9C17, //CJK UNIFIED IDEOGRAPH + 0xF67C: 0x9C18, //CJK UNIFIED IDEOGRAPH + 0xF67D: 0x9C19, //CJK UNIFIED IDEOGRAPH + 0xF67E: 0x9C1A, //CJK UNIFIED IDEOGRAPH + 0xF680: 0x9C1B, //CJK UNIFIED IDEOGRAPH + 0xF681: 0x9C1C, //CJK UNIFIED IDEOGRAPH + 0xF682: 0x9C1D, //CJK UNIFIED IDEOGRAPH + 0xF683: 0x9C1E, //CJK UNIFIED IDEOGRAPH + 0xF684: 0x9C1F, //CJK UNIFIED IDEOGRAPH + 0xF685: 0x9C20, //CJK UNIFIED IDEOGRAPH + 0xF686: 0x9C21, //CJK UNIFIED IDEOGRAPH + 0xF687: 0x9C22, //CJK UNIFIED IDEOGRAPH + 0xF688: 0x9C23, //CJK UNIFIED IDEOGRAPH + 0xF689: 0x9C24, //CJK UNIFIED IDEOGRAPH + 0xF68A: 0x9C25, //CJK UNIFIED IDEOGRAPH + 0xF68B: 0x9C26, //CJK UNIFIED IDEOGRAPH + 0xF68C: 0x9C27, //CJK UNIFIED IDEOGRAPH + 0xF68D: 0x9C28, //CJK UNIFIED IDEOGRAPH + 0xF68E: 0x9C29, //CJK UNIFIED IDEOGRAPH + 0xF68F: 0x9C2A, //CJK UNIFIED IDEOGRAPH + 0xF690: 0x9C2B, //CJK UNIFIED IDEOGRAPH + 0xF691: 0x9C2C, //CJK UNIFIED IDEOGRAPH + 0xF692: 0x9C2D, //CJK UNIFIED IDEOGRAPH + 0xF693: 0x9C2E, //CJK UNIFIED IDEOGRAPH + 0xF694: 0x9C2F, //CJK UNIFIED IDEOGRAPH + 0xF695: 0x9C30, //CJK UNIFIED IDEOGRAPH + 0xF696: 0x9C31, //CJK UNIFIED IDEOGRAPH + 0xF697: 0x9C32, //CJK UNIFIED IDEOGRAPH + 0xF698: 0x9C33, //CJK UNIFIED IDEOGRAPH + 0xF699: 0x9C34, //CJK UNIFIED IDEOGRAPH + 0xF69A: 0x9C35, //CJK UNIFIED IDEOGRAPH + 0xF69B: 0x9C36, //CJK UNIFIED IDEOGRAPH + 0xF69C: 0x9C37, //CJK UNIFIED IDEOGRAPH + 0xF69D: 0x9C38, //CJK UNIFIED IDEOGRAPH + 0xF69E: 0x9C39, //CJK UNIFIED IDEOGRAPH + 0xF69F: 0x9C3A, //CJK UNIFIED IDEOGRAPH + 0xF6A0: 0x9C3B, //CJK UNIFIED IDEOGRAPH + 0xF6A1: 0x89E5, //CJK UNIFIED IDEOGRAPH + 0xF6A2: 0x89EB, //CJK UNIFIED IDEOGRAPH + 0xF6A3: 0x89EF, //CJK UNIFIED IDEOGRAPH + 0xF6A4: 0x8A3E, //CJK UNIFIED IDEOGRAPH + 0xF6A5: 0x8B26, //CJK UNIFIED IDEOGRAPH + 0xF6A6: 0x9753, //CJK UNIFIED IDEOGRAPH + 0xF6A7: 0x96E9, //CJK UNIFIED IDEOGRAPH + 0xF6A8: 0x96F3, //CJK UNIFIED IDEOGRAPH + 0xF6A9: 0x96EF, //CJK UNIFIED IDEOGRAPH + 0xF6AA: 0x9706, //CJK UNIFIED IDEOGRAPH + 0xF6AB: 0x9701, //CJK UNIFIED IDEOGRAPH + 0xF6AC: 0x9708, //CJK UNIFIED IDEOGRAPH + 0xF6AD: 0x970F, //CJK UNIFIED IDEOGRAPH + 0xF6AE: 0x970E, //CJK UNIFIED IDEOGRAPH + 0xF6AF: 0x972A, //CJK UNIFIED IDEOGRAPH + 0xF6B0: 0x972D, //CJK UNIFIED IDEOGRAPH + 0xF6B1: 0x9730, //CJK UNIFIED IDEOGRAPH + 0xF6B2: 0x973E, //CJK UNIFIED IDEOGRAPH + 0xF6B3: 0x9F80, //CJK UNIFIED IDEOGRAPH + 0xF6B4: 0x9F83, //CJK UNIFIED IDEOGRAPH + 0xF6B5: 0x9F85, //CJK UNIFIED IDEOGRAPH + 0xF6B6: 0x9F86, //CJK UNIFIED IDEOGRAPH + 0xF6B7: 0x9F87, //CJK UNIFIED IDEOGRAPH + 0xF6B8: 0x9F88, //CJK UNIFIED IDEOGRAPH + 0xF6B9: 0x9F89, //CJK UNIFIED IDEOGRAPH + 0xF6BA: 0x9F8A, //CJK UNIFIED IDEOGRAPH + 0xF6BB: 0x9F8C, //CJK UNIFIED IDEOGRAPH + 0xF6BC: 0x9EFE, //CJK UNIFIED IDEOGRAPH + 0xF6BD: 0x9F0B, //CJK UNIFIED IDEOGRAPH + 0xF6BE: 0x9F0D, //CJK UNIFIED IDEOGRAPH + 0xF6BF: 0x96B9, //CJK UNIFIED IDEOGRAPH + 0xF6C0: 0x96BC, //CJK UNIFIED IDEOGRAPH + 0xF6C1: 0x96BD, //CJK UNIFIED IDEOGRAPH + 0xF6C2: 0x96CE, //CJK UNIFIED IDEOGRAPH + 0xF6C3: 0x96D2, //CJK UNIFIED IDEOGRAPH + 0xF6C4: 0x77BF, //CJK UNIFIED IDEOGRAPH + 0xF6C5: 0x96E0, //CJK UNIFIED IDEOGRAPH + 0xF6C6: 0x928E, //CJK UNIFIED IDEOGRAPH + 0xF6C7: 0x92AE, //CJK UNIFIED IDEOGRAPH + 0xF6C8: 0x92C8, //CJK UNIFIED IDEOGRAPH + 0xF6C9: 0x933E, //CJK UNIFIED IDEOGRAPH + 0xF6CA: 0x936A, //CJK UNIFIED IDEOGRAPH + 0xF6CB: 0x93CA, //CJK UNIFIED IDEOGRAPH + 0xF6CC: 0x938F, //CJK UNIFIED IDEOGRAPH + 0xF6CD: 0x943E, //CJK UNIFIED IDEOGRAPH + 0xF6CE: 0x946B, //CJK UNIFIED IDEOGRAPH + 0xF6CF: 0x9C7F, //CJK UNIFIED IDEOGRAPH + 0xF6D0: 0x9C82, //CJK UNIFIED IDEOGRAPH + 0xF6D1: 0x9C85, //CJK UNIFIED IDEOGRAPH + 0xF6D2: 0x9C86, //CJK UNIFIED IDEOGRAPH + 0xF6D3: 0x9C87, //CJK UNIFIED IDEOGRAPH + 0xF6D4: 0x9C88, //CJK UNIFIED IDEOGRAPH + 0xF6D5: 0x7A23, //CJK UNIFIED IDEOGRAPH + 0xF6D6: 0x9C8B, //CJK UNIFIED IDEOGRAPH + 0xF6D7: 0x9C8E, //CJK UNIFIED IDEOGRAPH + 0xF6D8: 0x9C90, //CJK UNIFIED IDEOGRAPH + 0xF6D9: 0x9C91, //CJK UNIFIED IDEOGRAPH + 0xF6DA: 0x9C92, //CJK UNIFIED IDEOGRAPH + 0xF6DB: 0x9C94, //CJK UNIFIED IDEOGRAPH + 0xF6DC: 0x9C95, //CJK UNIFIED IDEOGRAPH + 0xF6DD: 0x9C9A, //CJK UNIFIED IDEOGRAPH + 0xF6DE: 0x9C9B, //CJK UNIFIED IDEOGRAPH + 0xF6DF: 0x9C9E, //CJK UNIFIED IDEOGRAPH + 0xF6E0: 0x9C9F, //CJK UNIFIED IDEOGRAPH + 0xF6E1: 0x9CA0, //CJK UNIFIED IDEOGRAPH + 0xF6E2: 0x9CA1, //CJK UNIFIED IDEOGRAPH + 0xF6E3: 0x9CA2, //CJK UNIFIED IDEOGRAPH + 0xF6E4: 0x9CA3, //CJK UNIFIED IDEOGRAPH + 0xF6E5: 0x9CA5, //CJK UNIFIED IDEOGRAPH + 0xF6E6: 0x9CA6, //CJK UNIFIED IDEOGRAPH + 0xF6E7: 0x9CA7, //CJK UNIFIED IDEOGRAPH + 0xF6E8: 0x9CA8, //CJK UNIFIED IDEOGRAPH + 0xF6E9: 0x9CA9, //CJK UNIFIED IDEOGRAPH + 0xF6EA: 0x9CAB, //CJK UNIFIED IDEOGRAPH + 0xF6EB: 0x9CAD, //CJK UNIFIED IDEOGRAPH + 0xF6EC: 0x9CAE, //CJK UNIFIED IDEOGRAPH + 0xF6ED: 0x9CB0, //CJK UNIFIED IDEOGRAPH + 0xF6EE: 0x9CB1, //CJK UNIFIED IDEOGRAPH + 0xF6EF: 0x9CB2, //CJK UNIFIED IDEOGRAPH + 0xF6F0: 0x9CB3, //CJK UNIFIED IDEOGRAPH + 0xF6F1: 0x9CB4, //CJK UNIFIED IDEOGRAPH + 0xF6F2: 0x9CB5, //CJK UNIFIED IDEOGRAPH + 0xF6F3: 0x9CB6, //CJK UNIFIED IDEOGRAPH + 0xF6F4: 0x9CB7, //CJK UNIFIED IDEOGRAPH + 0xF6F5: 0x9CBA, //CJK UNIFIED IDEOGRAPH + 0xF6F6: 0x9CBB, //CJK UNIFIED IDEOGRAPH + 0xF6F7: 0x9CBC, //CJK UNIFIED IDEOGRAPH + 0xF6F8: 0x9CBD, //CJK UNIFIED IDEOGRAPH + 0xF6F9: 0x9CC4, //CJK UNIFIED IDEOGRAPH + 0xF6FA: 0x9CC5, //CJK UNIFIED IDEOGRAPH + 0xF6FB: 0x9CC6, //CJK UNIFIED IDEOGRAPH + 0xF6FC: 0x9CC7, //CJK UNIFIED IDEOGRAPH + 0xF6FD: 0x9CCA, //CJK UNIFIED IDEOGRAPH + 0xF6FE: 0x9CCB, //CJK UNIFIED IDEOGRAPH + 0xF740: 0x9C3C, //CJK UNIFIED IDEOGRAPH + 0xF741: 0x9C3D, //CJK UNIFIED IDEOGRAPH + 0xF742: 0x9C3E, //CJK UNIFIED IDEOGRAPH + 0xF743: 0x9C3F, //CJK UNIFIED IDEOGRAPH + 0xF744: 0x9C40, //CJK UNIFIED IDEOGRAPH + 0xF745: 0x9C41, //CJK UNIFIED IDEOGRAPH + 0xF746: 0x9C42, //CJK UNIFIED IDEOGRAPH + 0xF747: 0x9C43, //CJK UNIFIED IDEOGRAPH + 0xF748: 0x9C44, //CJK UNIFIED IDEOGRAPH + 0xF749: 0x9C45, //CJK UNIFIED IDEOGRAPH + 0xF74A: 0x9C46, //CJK UNIFIED IDEOGRAPH + 0xF74B: 0x9C47, //CJK UNIFIED IDEOGRAPH + 0xF74C: 0x9C48, //CJK UNIFIED IDEOGRAPH + 0xF74D: 0x9C49, //CJK UNIFIED IDEOGRAPH + 0xF74E: 0x9C4A, //CJK UNIFIED IDEOGRAPH + 0xF74F: 0x9C4B, //CJK UNIFIED IDEOGRAPH + 0xF750: 0x9C4C, //CJK UNIFIED IDEOGRAPH + 0xF751: 0x9C4D, //CJK UNIFIED IDEOGRAPH + 0xF752: 0x9C4E, //CJK UNIFIED IDEOGRAPH + 0xF753: 0x9C4F, //CJK UNIFIED IDEOGRAPH + 0xF754: 0x9C50, //CJK UNIFIED IDEOGRAPH + 0xF755: 0x9C51, //CJK UNIFIED IDEOGRAPH + 0xF756: 0x9C52, //CJK UNIFIED IDEOGRAPH + 0xF757: 0x9C53, //CJK UNIFIED IDEOGRAPH + 0xF758: 0x9C54, //CJK UNIFIED IDEOGRAPH + 0xF759: 0x9C55, //CJK UNIFIED IDEOGRAPH + 0xF75A: 0x9C56, //CJK UNIFIED IDEOGRAPH + 0xF75B: 0x9C57, //CJK UNIFIED IDEOGRAPH + 0xF75C: 0x9C58, //CJK UNIFIED IDEOGRAPH + 0xF75D: 0x9C59, //CJK UNIFIED IDEOGRAPH + 0xF75E: 0x9C5A, //CJK UNIFIED IDEOGRAPH + 0xF75F: 0x9C5B, //CJK UNIFIED IDEOGRAPH + 0xF760: 0x9C5C, //CJK UNIFIED IDEOGRAPH + 0xF761: 0x9C5D, //CJK UNIFIED IDEOGRAPH + 0xF762: 0x9C5E, //CJK UNIFIED IDEOGRAPH + 0xF763: 0x9C5F, //CJK UNIFIED IDEOGRAPH + 0xF764: 0x9C60, //CJK UNIFIED IDEOGRAPH + 0xF765: 0x9C61, //CJK UNIFIED IDEOGRAPH + 0xF766: 0x9C62, //CJK UNIFIED IDEOGRAPH + 0xF767: 0x9C63, //CJK UNIFIED IDEOGRAPH + 0xF768: 0x9C64, //CJK UNIFIED IDEOGRAPH + 0xF769: 0x9C65, //CJK UNIFIED IDEOGRAPH + 0xF76A: 0x9C66, //CJK UNIFIED IDEOGRAPH + 0xF76B: 0x9C67, //CJK UNIFIED IDEOGRAPH + 0xF76C: 0x9C68, //CJK UNIFIED IDEOGRAPH + 0xF76D: 0x9C69, //CJK UNIFIED IDEOGRAPH + 0xF76E: 0x9C6A, //CJK UNIFIED IDEOGRAPH + 0xF76F: 0x9C6B, //CJK UNIFIED IDEOGRAPH + 0xF770: 0x9C6C, //CJK UNIFIED IDEOGRAPH + 0xF771: 0x9C6D, //CJK UNIFIED IDEOGRAPH + 0xF772: 0x9C6E, //CJK UNIFIED IDEOGRAPH + 0xF773: 0x9C6F, //CJK UNIFIED IDEOGRAPH + 0xF774: 0x9C70, //CJK UNIFIED IDEOGRAPH + 0xF775: 0x9C71, //CJK UNIFIED IDEOGRAPH + 0xF776: 0x9C72, //CJK UNIFIED IDEOGRAPH + 0xF777: 0x9C73, //CJK UNIFIED IDEOGRAPH + 0xF778: 0x9C74, //CJK UNIFIED IDEOGRAPH + 0xF779: 0x9C75, //CJK UNIFIED IDEOGRAPH + 0xF77A: 0x9C76, //CJK UNIFIED IDEOGRAPH + 0xF77B: 0x9C77, //CJK UNIFIED IDEOGRAPH + 0xF77C: 0x9C78, //CJK UNIFIED IDEOGRAPH + 0xF77D: 0x9C79, //CJK UNIFIED IDEOGRAPH + 0xF77E: 0x9C7A, //CJK UNIFIED IDEOGRAPH + 0xF780: 0x9C7B, //CJK UNIFIED IDEOGRAPH + 0xF781: 0x9C7D, //CJK UNIFIED IDEOGRAPH + 0xF782: 0x9C7E, //CJK UNIFIED IDEOGRAPH + 0xF783: 0x9C80, //CJK UNIFIED IDEOGRAPH + 0xF784: 0x9C83, //CJK UNIFIED IDEOGRAPH + 0xF785: 0x9C84, //CJK UNIFIED IDEOGRAPH + 0xF786: 0x9C89, //CJK UNIFIED IDEOGRAPH + 0xF787: 0x9C8A, //CJK UNIFIED IDEOGRAPH + 0xF788: 0x9C8C, //CJK UNIFIED IDEOGRAPH + 0xF789: 0x9C8F, //CJK UNIFIED IDEOGRAPH + 0xF78A: 0x9C93, //CJK UNIFIED IDEOGRAPH + 0xF78B: 0x9C96, //CJK UNIFIED IDEOGRAPH + 0xF78C: 0x9C97, //CJK UNIFIED IDEOGRAPH + 0xF78D: 0x9C98, //CJK UNIFIED IDEOGRAPH + 0xF78E: 0x9C99, //CJK UNIFIED IDEOGRAPH + 0xF78F: 0x9C9D, //CJK UNIFIED IDEOGRAPH + 0xF790: 0x9CAA, //CJK UNIFIED IDEOGRAPH + 0xF791: 0x9CAC, //CJK UNIFIED IDEOGRAPH + 0xF792: 0x9CAF, //CJK UNIFIED IDEOGRAPH + 0xF793: 0x9CB9, //CJK UNIFIED IDEOGRAPH + 0xF794: 0x9CBE, //CJK UNIFIED IDEOGRAPH + 0xF795: 0x9CBF, //CJK UNIFIED IDEOGRAPH + 0xF796: 0x9CC0, //CJK UNIFIED IDEOGRAPH + 0xF797: 0x9CC1, //CJK UNIFIED IDEOGRAPH + 0xF798: 0x9CC2, //CJK UNIFIED IDEOGRAPH + 0xF799: 0x9CC8, //CJK UNIFIED IDEOGRAPH + 0xF79A: 0x9CC9, //CJK UNIFIED IDEOGRAPH + 0xF79B: 0x9CD1, //CJK UNIFIED IDEOGRAPH + 0xF79C: 0x9CD2, //CJK UNIFIED IDEOGRAPH + 0xF79D: 0x9CDA, //CJK UNIFIED IDEOGRAPH + 0xF79E: 0x9CDB, //CJK UNIFIED IDEOGRAPH + 0xF79F: 0x9CE0, //CJK UNIFIED IDEOGRAPH + 0xF7A0: 0x9CE1, //CJK UNIFIED IDEOGRAPH + 0xF7A1: 0x9CCC, //CJK UNIFIED IDEOGRAPH + 0xF7A2: 0x9CCD, //CJK UNIFIED IDEOGRAPH + 0xF7A3: 0x9CCE, //CJK UNIFIED IDEOGRAPH + 0xF7A4: 0x9CCF, //CJK UNIFIED IDEOGRAPH + 0xF7A5: 0x9CD0, //CJK UNIFIED IDEOGRAPH + 0xF7A6: 0x9CD3, //CJK UNIFIED IDEOGRAPH + 0xF7A7: 0x9CD4, //CJK UNIFIED IDEOGRAPH + 0xF7A8: 0x9CD5, //CJK UNIFIED IDEOGRAPH + 0xF7A9: 0x9CD7, //CJK UNIFIED IDEOGRAPH + 0xF7AA: 0x9CD8, //CJK UNIFIED IDEOGRAPH + 0xF7AB: 0x9CD9, //CJK UNIFIED IDEOGRAPH + 0xF7AC: 0x9CDC, //CJK UNIFIED IDEOGRAPH + 0xF7AD: 0x9CDD, //CJK UNIFIED IDEOGRAPH + 0xF7AE: 0x9CDF, //CJK UNIFIED IDEOGRAPH + 0xF7AF: 0x9CE2, //CJK UNIFIED IDEOGRAPH + 0xF7B0: 0x977C, //CJK UNIFIED IDEOGRAPH + 0xF7B1: 0x9785, //CJK UNIFIED IDEOGRAPH + 0xF7B2: 0x9791, //CJK UNIFIED IDEOGRAPH + 0xF7B3: 0x9792, //CJK UNIFIED IDEOGRAPH + 0xF7B4: 0x9794, //CJK UNIFIED IDEOGRAPH + 0xF7B5: 0x97AF, //CJK UNIFIED IDEOGRAPH + 0xF7B6: 0x97AB, //CJK UNIFIED IDEOGRAPH + 0xF7B7: 0x97A3, //CJK UNIFIED IDEOGRAPH + 0xF7B8: 0x97B2, //CJK UNIFIED IDEOGRAPH + 0xF7B9: 0x97B4, //CJK UNIFIED IDEOGRAPH + 0xF7BA: 0x9AB1, //CJK UNIFIED IDEOGRAPH + 0xF7BB: 0x9AB0, //CJK UNIFIED IDEOGRAPH + 0xF7BC: 0x9AB7, //CJK UNIFIED IDEOGRAPH + 0xF7BD: 0x9E58, //CJK UNIFIED IDEOGRAPH + 0xF7BE: 0x9AB6, //CJK UNIFIED IDEOGRAPH + 0xF7BF: 0x9ABA, //CJK UNIFIED IDEOGRAPH + 0xF7C0: 0x9ABC, //CJK UNIFIED IDEOGRAPH + 0xF7C1: 0x9AC1, //CJK UNIFIED IDEOGRAPH + 0xF7C2: 0x9AC0, //CJK UNIFIED IDEOGRAPH + 0xF7C3: 0x9AC5, //CJK UNIFIED IDEOGRAPH + 0xF7C4: 0x9AC2, //CJK UNIFIED IDEOGRAPH + 0xF7C5: 0x9ACB, //CJK UNIFIED IDEOGRAPH + 0xF7C6: 0x9ACC, //CJK UNIFIED IDEOGRAPH + 0xF7C7: 0x9AD1, //CJK UNIFIED IDEOGRAPH + 0xF7C8: 0x9B45, //CJK UNIFIED IDEOGRAPH + 0xF7C9: 0x9B43, //CJK UNIFIED IDEOGRAPH + 0xF7CA: 0x9B47, //CJK UNIFIED IDEOGRAPH + 0xF7CB: 0x9B49, //CJK UNIFIED IDEOGRAPH + 0xF7CC: 0x9B48, //CJK UNIFIED IDEOGRAPH + 0xF7CD: 0x9B4D, //CJK UNIFIED IDEOGRAPH + 0xF7CE: 0x9B51, //CJK UNIFIED IDEOGRAPH + 0xF7CF: 0x98E8, //CJK UNIFIED IDEOGRAPH + 0xF7D0: 0x990D, //CJK UNIFIED IDEOGRAPH + 0xF7D1: 0x992E, //CJK UNIFIED IDEOGRAPH + 0xF7D2: 0x9955, //CJK UNIFIED IDEOGRAPH + 0xF7D3: 0x9954, //CJK UNIFIED IDEOGRAPH + 0xF7D4: 0x9ADF, //CJK UNIFIED IDEOGRAPH + 0xF7D5: 0x9AE1, //CJK UNIFIED IDEOGRAPH + 0xF7D6: 0x9AE6, //CJK UNIFIED IDEOGRAPH + 0xF7D7: 0x9AEF, //CJK UNIFIED IDEOGRAPH + 0xF7D8: 0x9AEB, //CJK UNIFIED IDEOGRAPH + 0xF7D9: 0x9AFB, //CJK UNIFIED IDEOGRAPH + 0xF7DA: 0x9AED, //CJK UNIFIED IDEOGRAPH + 0xF7DB: 0x9AF9, //CJK UNIFIED IDEOGRAPH + 0xF7DC: 0x9B08, //CJK UNIFIED IDEOGRAPH + 0xF7DD: 0x9B0F, //CJK UNIFIED IDEOGRAPH + 0xF7DE: 0x9B13, //CJK UNIFIED IDEOGRAPH + 0xF7DF: 0x9B1F, //CJK UNIFIED IDEOGRAPH + 0xF7E0: 0x9B23, //CJK UNIFIED IDEOGRAPH + 0xF7E1: 0x9EBD, //CJK UNIFIED IDEOGRAPH + 0xF7E2: 0x9EBE, //CJK UNIFIED IDEOGRAPH + 0xF7E3: 0x7E3B, //CJK UNIFIED IDEOGRAPH + 0xF7E4: 0x9E82, //CJK UNIFIED IDEOGRAPH + 0xF7E5: 0x9E87, //CJK UNIFIED IDEOGRAPH + 0xF7E6: 0x9E88, //CJK UNIFIED IDEOGRAPH + 0xF7E7: 0x9E8B, //CJK UNIFIED IDEOGRAPH + 0xF7E8: 0x9E92, //CJK UNIFIED IDEOGRAPH + 0xF7E9: 0x93D6, //CJK UNIFIED IDEOGRAPH + 0xF7EA: 0x9E9D, //CJK UNIFIED IDEOGRAPH + 0xF7EB: 0x9E9F, //CJK UNIFIED IDEOGRAPH + 0xF7EC: 0x9EDB, //CJK UNIFIED IDEOGRAPH + 0xF7ED: 0x9EDC, //CJK UNIFIED IDEOGRAPH + 0xF7EE: 0x9EDD, //CJK UNIFIED IDEOGRAPH + 0xF7EF: 0x9EE0, //CJK UNIFIED IDEOGRAPH + 0xF7F0: 0x9EDF, //CJK UNIFIED IDEOGRAPH + 0xF7F1: 0x9EE2, //CJK UNIFIED IDEOGRAPH + 0xF7F2: 0x9EE9, //CJK UNIFIED IDEOGRAPH + 0xF7F3: 0x9EE7, //CJK UNIFIED IDEOGRAPH + 0xF7F4: 0x9EE5, //CJK UNIFIED IDEOGRAPH + 0xF7F5: 0x9EEA, //CJK UNIFIED IDEOGRAPH + 0xF7F6: 0x9EEF, //CJK UNIFIED IDEOGRAPH + 0xF7F7: 0x9F22, //CJK UNIFIED IDEOGRAPH + 0xF7F8: 0x9F2C, //CJK UNIFIED IDEOGRAPH + 0xF7F9: 0x9F2F, //CJK UNIFIED IDEOGRAPH + 0xF7FA: 0x9F39, //CJK UNIFIED IDEOGRAPH + 0xF7FB: 0x9F37, //CJK UNIFIED IDEOGRAPH + 0xF7FC: 0x9F3D, //CJK UNIFIED IDEOGRAPH + 0xF7FD: 0x9F3E, //CJK UNIFIED IDEOGRAPH + 0xF7FE: 0x9F44, //CJK UNIFIED IDEOGRAPH + 0xF840: 0x9CE3, //CJK UNIFIED IDEOGRAPH + 0xF841: 0x9CE4, //CJK UNIFIED IDEOGRAPH + 0xF842: 0x9CE5, //CJK UNIFIED IDEOGRAPH + 0xF843: 0x9CE6, //CJK UNIFIED IDEOGRAPH + 0xF844: 0x9CE7, //CJK UNIFIED IDEOGRAPH + 0xF845: 0x9CE8, //CJK UNIFIED IDEOGRAPH + 0xF846: 0x9CE9, //CJK UNIFIED IDEOGRAPH + 0xF847: 0x9CEA, //CJK UNIFIED IDEOGRAPH + 0xF848: 0x9CEB, //CJK UNIFIED IDEOGRAPH + 0xF849: 0x9CEC, //CJK UNIFIED IDEOGRAPH + 0xF84A: 0x9CED, //CJK UNIFIED IDEOGRAPH + 0xF84B: 0x9CEE, //CJK UNIFIED IDEOGRAPH + 0xF84C: 0x9CEF, //CJK UNIFIED IDEOGRAPH + 0xF84D: 0x9CF0, //CJK UNIFIED IDEOGRAPH + 0xF84E: 0x9CF1, //CJK UNIFIED IDEOGRAPH + 0xF84F: 0x9CF2, //CJK UNIFIED IDEOGRAPH + 0xF850: 0x9CF3, //CJK UNIFIED IDEOGRAPH + 0xF851: 0x9CF4, //CJK UNIFIED IDEOGRAPH + 0xF852: 0x9CF5, //CJK UNIFIED IDEOGRAPH + 0xF853: 0x9CF6, //CJK UNIFIED IDEOGRAPH + 0xF854: 0x9CF7, //CJK UNIFIED IDEOGRAPH + 0xF855: 0x9CF8, //CJK UNIFIED IDEOGRAPH + 0xF856: 0x9CF9, //CJK UNIFIED IDEOGRAPH + 0xF857: 0x9CFA, //CJK UNIFIED IDEOGRAPH + 0xF858: 0x9CFB, //CJK UNIFIED IDEOGRAPH + 0xF859: 0x9CFC, //CJK UNIFIED IDEOGRAPH + 0xF85A: 0x9CFD, //CJK UNIFIED IDEOGRAPH + 0xF85B: 0x9CFE, //CJK UNIFIED IDEOGRAPH + 0xF85C: 0x9CFF, //CJK UNIFIED IDEOGRAPH + 0xF85D: 0x9D00, //CJK UNIFIED IDEOGRAPH + 0xF85E: 0x9D01, //CJK UNIFIED IDEOGRAPH + 0xF85F: 0x9D02, //CJK UNIFIED IDEOGRAPH + 0xF860: 0x9D03, //CJK UNIFIED IDEOGRAPH + 0xF861: 0x9D04, //CJK UNIFIED IDEOGRAPH + 0xF862: 0x9D05, //CJK UNIFIED IDEOGRAPH + 0xF863: 0x9D06, //CJK UNIFIED IDEOGRAPH + 0xF864: 0x9D07, //CJK UNIFIED IDEOGRAPH + 0xF865: 0x9D08, //CJK UNIFIED IDEOGRAPH + 0xF866: 0x9D09, //CJK UNIFIED IDEOGRAPH + 0xF867: 0x9D0A, //CJK UNIFIED IDEOGRAPH + 0xF868: 0x9D0B, //CJK UNIFIED IDEOGRAPH + 0xF869: 0x9D0C, //CJK UNIFIED IDEOGRAPH + 0xF86A: 0x9D0D, //CJK UNIFIED IDEOGRAPH + 0xF86B: 0x9D0E, //CJK UNIFIED IDEOGRAPH + 0xF86C: 0x9D0F, //CJK UNIFIED IDEOGRAPH + 0xF86D: 0x9D10, //CJK UNIFIED IDEOGRAPH + 0xF86E: 0x9D11, //CJK UNIFIED IDEOGRAPH + 0xF86F: 0x9D12, //CJK UNIFIED IDEOGRAPH + 0xF870: 0x9D13, //CJK UNIFIED IDEOGRAPH + 0xF871: 0x9D14, //CJK UNIFIED IDEOGRAPH + 0xF872: 0x9D15, //CJK UNIFIED IDEOGRAPH + 0xF873: 0x9D16, //CJK UNIFIED IDEOGRAPH + 0xF874: 0x9D17, //CJK UNIFIED IDEOGRAPH + 0xF875: 0x9D18, //CJK UNIFIED IDEOGRAPH + 0xF876: 0x9D19, //CJK UNIFIED IDEOGRAPH + 0xF877: 0x9D1A, //CJK UNIFIED IDEOGRAPH + 0xF878: 0x9D1B, //CJK UNIFIED IDEOGRAPH + 0xF879: 0x9D1C, //CJK UNIFIED IDEOGRAPH + 0xF87A: 0x9D1D, //CJK UNIFIED IDEOGRAPH + 0xF87B: 0x9D1E, //CJK UNIFIED IDEOGRAPH + 0xF87C: 0x9D1F, //CJK UNIFIED IDEOGRAPH + 0xF87D: 0x9D20, //CJK UNIFIED IDEOGRAPH + 0xF87E: 0x9D21, //CJK UNIFIED IDEOGRAPH + 0xF880: 0x9D22, //CJK UNIFIED IDEOGRAPH + 0xF881: 0x9D23, //CJK UNIFIED IDEOGRAPH + 0xF882: 0x9D24, //CJK UNIFIED IDEOGRAPH + 0xF883: 0x9D25, //CJK UNIFIED IDEOGRAPH + 0xF884: 0x9D26, //CJK UNIFIED IDEOGRAPH + 0xF885: 0x9D27, //CJK UNIFIED IDEOGRAPH + 0xF886: 0x9D28, //CJK UNIFIED IDEOGRAPH + 0xF887: 0x9D29, //CJK UNIFIED IDEOGRAPH + 0xF888: 0x9D2A, //CJK UNIFIED IDEOGRAPH + 0xF889: 0x9D2B, //CJK UNIFIED IDEOGRAPH + 0xF88A: 0x9D2C, //CJK UNIFIED IDEOGRAPH + 0xF88B: 0x9D2D, //CJK UNIFIED IDEOGRAPH + 0xF88C: 0x9D2E, //CJK UNIFIED IDEOGRAPH + 0xF88D: 0x9D2F, //CJK UNIFIED IDEOGRAPH + 0xF88E: 0x9D30, //CJK UNIFIED IDEOGRAPH + 0xF88F: 0x9D31, //CJK UNIFIED IDEOGRAPH + 0xF890: 0x9D32, //CJK UNIFIED IDEOGRAPH + 0xF891: 0x9D33, //CJK UNIFIED IDEOGRAPH + 0xF892: 0x9D34, //CJK UNIFIED IDEOGRAPH + 0xF893: 0x9D35, //CJK UNIFIED IDEOGRAPH + 0xF894: 0x9D36, //CJK UNIFIED IDEOGRAPH + 0xF895: 0x9D37, //CJK UNIFIED IDEOGRAPH + 0xF896: 0x9D38, //CJK UNIFIED IDEOGRAPH + 0xF897: 0x9D39, //CJK UNIFIED IDEOGRAPH + 0xF898: 0x9D3A, //CJK UNIFIED IDEOGRAPH + 0xF899: 0x9D3B, //CJK UNIFIED IDEOGRAPH + 0xF89A: 0x9D3C, //CJK UNIFIED IDEOGRAPH + 0xF89B: 0x9D3D, //CJK UNIFIED IDEOGRAPH + 0xF89C: 0x9D3E, //CJK UNIFIED IDEOGRAPH + 0xF89D: 0x9D3F, //CJK UNIFIED IDEOGRAPH + 0xF89E: 0x9D40, //CJK UNIFIED IDEOGRAPH + 0xF89F: 0x9D41, //CJK UNIFIED IDEOGRAPH + 0xF8A0: 0x9D42, //CJK UNIFIED IDEOGRAPH + 0xF940: 0x9D43, //CJK UNIFIED IDEOGRAPH + 0xF941: 0x9D44, //CJK UNIFIED IDEOGRAPH + 0xF942: 0x9D45, //CJK UNIFIED IDEOGRAPH + 0xF943: 0x9D46, //CJK UNIFIED IDEOGRAPH + 0xF944: 0x9D47, //CJK UNIFIED IDEOGRAPH + 0xF945: 0x9D48, //CJK UNIFIED IDEOGRAPH + 0xF946: 0x9D49, //CJK UNIFIED IDEOGRAPH + 0xF947: 0x9D4A, //CJK UNIFIED IDEOGRAPH + 0xF948: 0x9D4B, //CJK UNIFIED IDEOGRAPH + 0xF949: 0x9D4C, //CJK UNIFIED IDEOGRAPH + 0xF94A: 0x9D4D, //CJK UNIFIED IDEOGRAPH + 0xF94B: 0x9D4E, //CJK UNIFIED IDEOGRAPH + 0xF94C: 0x9D4F, //CJK UNIFIED IDEOGRAPH + 0xF94D: 0x9D50, //CJK UNIFIED IDEOGRAPH + 0xF94E: 0x9D51, //CJK UNIFIED IDEOGRAPH + 0xF94F: 0x9D52, //CJK UNIFIED IDEOGRAPH + 0xF950: 0x9D53, //CJK UNIFIED IDEOGRAPH + 0xF951: 0x9D54, //CJK UNIFIED IDEOGRAPH + 0xF952: 0x9D55, //CJK UNIFIED IDEOGRAPH + 0xF953: 0x9D56, //CJK UNIFIED IDEOGRAPH + 0xF954: 0x9D57, //CJK UNIFIED IDEOGRAPH + 0xF955: 0x9D58, //CJK UNIFIED IDEOGRAPH + 0xF956: 0x9D59, //CJK UNIFIED IDEOGRAPH + 0xF957: 0x9D5A, //CJK UNIFIED IDEOGRAPH + 0xF958: 0x9D5B, //CJK UNIFIED IDEOGRAPH + 0xF959: 0x9D5C, //CJK UNIFIED IDEOGRAPH + 0xF95A: 0x9D5D, //CJK UNIFIED IDEOGRAPH + 0xF95B: 0x9D5E, //CJK UNIFIED IDEOGRAPH + 0xF95C: 0x9D5F, //CJK UNIFIED IDEOGRAPH + 0xF95D: 0x9D60, //CJK UNIFIED IDEOGRAPH + 0xF95E: 0x9D61, //CJK UNIFIED IDEOGRAPH + 0xF95F: 0x9D62, //CJK UNIFIED IDEOGRAPH + 0xF960: 0x9D63, //CJK UNIFIED IDEOGRAPH + 0xF961: 0x9D64, //CJK UNIFIED IDEOGRAPH + 0xF962: 0x9D65, //CJK UNIFIED IDEOGRAPH + 0xF963: 0x9D66, //CJK UNIFIED IDEOGRAPH + 0xF964: 0x9D67, //CJK UNIFIED IDEOGRAPH + 0xF965: 0x9D68, //CJK UNIFIED IDEOGRAPH + 0xF966: 0x9D69, //CJK UNIFIED IDEOGRAPH + 0xF967: 0x9D6A, //CJK UNIFIED IDEOGRAPH + 0xF968: 0x9D6B, //CJK UNIFIED IDEOGRAPH + 0xF969: 0x9D6C, //CJK UNIFIED IDEOGRAPH + 0xF96A: 0x9D6D, //CJK UNIFIED IDEOGRAPH + 0xF96B: 0x9D6E, //CJK UNIFIED IDEOGRAPH + 0xF96C: 0x9D6F, //CJK UNIFIED IDEOGRAPH + 0xF96D: 0x9D70, //CJK UNIFIED IDEOGRAPH + 0xF96E: 0x9D71, //CJK UNIFIED IDEOGRAPH + 0xF96F: 0x9D72, //CJK UNIFIED IDEOGRAPH + 0xF970: 0x9D73, //CJK UNIFIED IDEOGRAPH + 0xF971: 0x9D74, //CJK UNIFIED IDEOGRAPH + 0xF972: 0x9D75, //CJK UNIFIED IDEOGRAPH + 0xF973: 0x9D76, //CJK UNIFIED IDEOGRAPH + 0xF974: 0x9D77, //CJK UNIFIED IDEOGRAPH + 0xF975: 0x9D78, //CJK UNIFIED IDEOGRAPH + 0xF976: 0x9D79, //CJK UNIFIED IDEOGRAPH + 0xF977: 0x9D7A, //CJK UNIFIED IDEOGRAPH + 0xF978: 0x9D7B, //CJK UNIFIED IDEOGRAPH + 0xF979: 0x9D7C, //CJK UNIFIED IDEOGRAPH + 0xF97A: 0x9D7D, //CJK UNIFIED IDEOGRAPH + 0xF97B: 0x9D7E, //CJK UNIFIED IDEOGRAPH + 0xF97C: 0x9D7F, //CJK UNIFIED IDEOGRAPH + 0xF97D: 0x9D80, //CJK UNIFIED IDEOGRAPH + 0xF97E: 0x9D81, //CJK UNIFIED IDEOGRAPH + 0xF980: 0x9D82, //CJK UNIFIED IDEOGRAPH + 0xF981: 0x9D83, //CJK UNIFIED IDEOGRAPH + 0xF982: 0x9D84, //CJK UNIFIED IDEOGRAPH + 0xF983: 0x9D85, //CJK UNIFIED IDEOGRAPH + 0xF984: 0x9D86, //CJK UNIFIED IDEOGRAPH + 0xF985: 0x9D87, //CJK UNIFIED IDEOGRAPH + 0xF986: 0x9D88, //CJK UNIFIED IDEOGRAPH + 0xF987: 0x9D89, //CJK UNIFIED IDEOGRAPH + 0xF988: 0x9D8A, //CJK UNIFIED IDEOGRAPH + 0xF989: 0x9D8B, //CJK UNIFIED IDEOGRAPH + 0xF98A: 0x9D8C, //CJK UNIFIED IDEOGRAPH + 0xF98B: 0x9D8D, //CJK UNIFIED IDEOGRAPH + 0xF98C: 0x9D8E, //CJK UNIFIED IDEOGRAPH + 0xF98D: 0x9D8F, //CJK UNIFIED IDEOGRAPH + 0xF98E: 0x9D90, //CJK UNIFIED IDEOGRAPH + 0xF98F: 0x9D91, //CJK UNIFIED IDEOGRAPH + 0xF990: 0x9D92, //CJK UNIFIED IDEOGRAPH + 0xF991: 0x9D93, //CJK UNIFIED IDEOGRAPH + 0xF992: 0x9D94, //CJK UNIFIED IDEOGRAPH + 0xF993: 0x9D95, //CJK UNIFIED IDEOGRAPH + 0xF994: 0x9D96, //CJK UNIFIED IDEOGRAPH + 0xF995: 0x9D97, //CJK UNIFIED IDEOGRAPH + 0xF996: 0x9D98, //CJK UNIFIED IDEOGRAPH + 0xF997: 0x9D99, //CJK UNIFIED IDEOGRAPH + 0xF998: 0x9D9A, //CJK UNIFIED IDEOGRAPH + 0xF999: 0x9D9B, //CJK UNIFIED IDEOGRAPH + 0xF99A: 0x9D9C, //CJK UNIFIED IDEOGRAPH + 0xF99B: 0x9D9D, //CJK UNIFIED IDEOGRAPH + 0xF99C: 0x9D9E, //CJK UNIFIED IDEOGRAPH + 0xF99D: 0x9D9F, //CJK UNIFIED IDEOGRAPH + 0xF99E: 0x9DA0, //CJK UNIFIED IDEOGRAPH + 0xF99F: 0x9DA1, //CJK UNIFIED IDEOGRAPH + 0xF9A0: 0x9DA2, //CJK UNIFIED IDEOGRAPH + 0xFA40: 0x9DA3, //CJK UNIFIED IDEOGRAPH + 0xFA41: 0x9DA4, //CJK UNIFIED IDEOGRAPH + 0xFA42: 0x9DA5, //CJK UNIFIED IDEOGRAPH + 0xFA43: 0x9DA6, //CJK UNIFIED IDEOGRAPH + 0xFA44: 0x9DA7, //CJK UNIFIED IDEOGRAPH + 0xFA45: 0x9DA8, //CJK UNIFIED IDEOGRAPH + 0xFA46: 0x9DA9, //CJK UNIFIED IDEOGRAPH + 0xFA47: 0x9DAA, //CJK UNIFIED IDEOGRAPH + 0xFA48: 0x9DAB, //CJK UNIFIED IDEOGRAPH + 0xFA49: 0x9DAC, //CJK UNIFIED IDEOGRAPH + 0xFA4A: 0x9DAD, //CJK UNIFIED IDEOGRAPH + 0xFA4B: 0x9DAE, //CJK UNIFIED IDEOGRAPH + 0xFA4C: 0x9DAF, //CJK UNIFIED IDEOGRAPH + 0xFA4D: 0x9DB0, //CJK UNIFIED IDEOGRAPH + 0xFA4E: 0x9DB1, //CJK UNIFIED IDEOGRAPH + 0xFA4F: 0x9DB2, //CJK UNIFIED IDEOGRAPH + 0xFA50: 0x9DB3, //CJK UNIFIED IDEOGRAPH + 0xFA51: 0x9DB4, //CJK UNIFIED IDEOGRAPH + 0xFA52: 0x9DB5, //CJK UNIFIED IDEOGRAPH + 0xFA53: 0x9DB6, //CJK UNIFIED IDEOGRAPH + 0xFA54: 0x9DB7, //CJK UNIFIED IDEOGRAPH + 0xFA55: 0x9DB8, //CJK UNIFIED IDEOGRAPH + 0xFA56: 0x9DB9, //CJK UNIFIED IDEOGRAPH + 0xFA57: 0x9DBA, //CJK UNIFIED IDEOGRAPH + 0xFA58: 0x9DBB, //CJK UNIFIED IDEOGRAPH + 0xFA59: 0x9DBC, //CJK UNIFIED IDEOGRAPH + 0xFA5A: 0x9DBD, //CJK UNIFIED IDEOGRAPH + 0xFA5B: 0x9DBE, //CJK UNIFIED IDEOGRAPH + 0xFA5C: 0x9DBF, //CJK UNIFIED IDEOGRAPH + 0xFA5D: 0x9DC0, //CJK UNIFIED IDEOGRAPH + 0xFA5E: 0x9DC1, //CJK UNIFIED IDEOGRAPH + 0xFA5F: 0x9DC2, //CJK UNIFIED IDEOGRAPH + 0xFA60: 0x9DC3, //CJK UNIFIED IDEOGRAPH + 0xFA61: 0x9DC4, //CJK UNIFIED IDEOGRAPH + 0xFA62: 0x9DC5, //CJK UNIFIED IDEOGRAPH + 0xFA63: 0x9DC6, //CJK UNIFIED IDEOGRAPH + 0xFA64: 0x9DC7, //CJK UNIFIED IDEOGRAPH + 0xFA65: 0x9DC8, //CJK UNIFIED IDEOGRAPH + 0xFA66: 0x9DC9, //CJK UNIFIED IDEOGRAPH + 0xFA67: 0x9DCA, //CJK UNIFIED IDEOGRAPH + 0xFA68: 0x9DCB, //CJK UNIFIED IDEOGRAPH + 0xFA69: 0x9DCC, //CJK UNIFIED IDEOGRAPH + 0xFA6A: 0x9DCD, //CJK UNIFIED IDEOGRAPH + 0xFA6B: 0x9DCE, //CJK UNIFIED IDEOGRAPH + 0xFA6C: 0x9DCF, //CJK UNIFIED IDEOGRAPH + 0xFA6D: 0x9DD0, //CJK UNIFIED IDEOGRAPH + 0xFA6E: 0x9DD1, //CJK UNIFIED IDEOGRAPH + 0xFA6F: 0x9DD2, //CJK UNIFIED IDEOGRAPH + 0xFA70: 0x9DD3, //CJK UNIFIED IDEOGRAPH + 0xFA71: 0x9DD4, //CJK UNIFIED IDEOGRAPH + 0xFA72: 0x9DD5, //CJK UNIFIED IDEOGRAPH + 0xFA73: 0x9DD6, //CJK UNIFIED IDEOGRAPH + 0xFA74: 0x9DD7, //CJK UNIFIED IDEOGRAPH + 0xFA75: 0x9DD8, //CJK UNIFIED IDEOGRAPH + 0xFA76: 0x9DD9, //CJK UNIFIED IDEOGRAPH + 0xFA77: 0x9DDA, //CJK UNIFIED IDEOGRAPH + 0xFA78: 0x9DDB, //CJK UNIFIED IDEOGRAPH + 0xFA79: 0x9DDC, //CJK UNIFIED IDEOGRAPH + 0xFA7A: 0x9DDD, //CJK UNIFIED IDEOGRAPH + 0xFA7B: 0x9DDE, //CJK UNIFIED IDEOGRAPH + 0xFA7C: 0x9DDF, //CJK UNIFIED IDEOGRAPH + 0xFA7D: 0x9DE0, //CJK UNIFIED IDEOGRAPH + 0xFA7E: 0x9DE1, //CJK UNIFIED IDEOGRAPH + 0xFA80: 0x9DE2, //CJK UNIFIED IDEOGRAPH + 0xFA81: 0x9DE3, //CJK UNIFIED IDEOGRAPH + 0xFA82: 0x9DE4, //CJK UNIFIED IDEOGRAPH + 0xFA83: 0x9DE5, //CJK UNIFIED IDEOGRAPH + 0xFA84: 0x9DE6, //CJK UNIFIED IDEOGRAPH + 0xFA85: 0x9DE7, //CJK UNIFIED IDEOGRAPH + 0xFA86: 0x9DE8, //CJK UNIFIED IDEOGRAPH + 0xFA87: 0x9DE9, //CJK UNIFIED IDEOGRAPH + 0xFA88: 0x9DEA, //CJK UNIFIED IDEOGRAPH + 0xFA89: 0x9DEB, //CJK UNIFIED IDEOGRAPH + 0xFA8A: 0x9DEC, //CJK UNIFIED IDEOGRAPH + 0xFA8B: 0x9DED, //CJK UNIFIED IDEOGRAPH + 0xFA8C: 0x9DEE, //CJK UNIFIED IDEOGRAPH + 0xFA8D: 0x9DEF, //CJK UNIFIED IDEOGRAPH + 0xFA8E: 0x9DF0, //CJK UNIFIED IDEOGRAPH + 0xFA8F: 0x9DF1, //CJK UNIFIED IDEOGRAPH + 0xFA90: 0x9DF2, //CJK UNIFIED IDEOGRAPH + 0xFA91: 0x9DF3, //CJK UNIFIED IDEOGRAPH + 0xFA92: 0x9DF4, //CJK UNIFIED IDEOGRAPH + 0xFA93: 0x9DF5, //CJK UNIFIED IDEOGRAPH + 0xFA94: 0x9DF6, //CJK UNIFIED IDEOGRAPH + 0xFA95: 0x9DF7, //CJK UNIFIED IDEOGRAPH + 0xFA96: 0x9DF8, //CJK UNIFIED IDEOGRAPH + 0xFA97: 0x9DF9, //CJK UNIFIED IDEOGRAPH + 0xFA98: 0x9DFA, //CJK UNIFIED IDEOGRAPH + 0xFA99: 0x9DFB, //CJK UNIFIED IDEOGRAPH + 0xFA9A: 0x9DFC, //CJK UNIFIED IDEOGRAPH + 0xFA9B: 0x9DFD, //CJK UNIFIED IDEOGRAPH + 0xFA9C: 0x9DFE, //CJK UNIFIED IDEOGRAPH + 0xFA9D: 0x9DFF, //CJK UNIFIED IDEOGRAPH + 0xFA9E: 0x9E00, //CJK UNIFIED IDEOGRAPH + 0xFA9F: 0x9E01, //CJK UNIFIED IDEOGRAPH + 0xFAA0: 0x9E02, //CJK UNIFIED IDEOGRAPH + 0xFB40: 0x9E03, //CJK UNIFIED IDEOGRAPH + 0xFB41: 0x9E04, //CJK UNIFIED IDEOGRAPH + 0xFB42: 0x9E05, //CJK UNIFIED IDEOGRAPH + 0xFB43: 0x9E06, //CJK UNIFIED IDEOGRAPH + 0xFB44: 0x9E07, //CJK UNIFIED IDEOGRAPH + 0xFB45: 0x9E08, //CJK UNIFIED IDEOGRAPH + 0xFB46: 0x9E09, //CJK UNIFIED IDEOGRAPH + 0xFB47: 0x9E0A, //CJK UNIFIED IDEOGRAPH + 0xFB48: 0x9E0B, //CJK UNIFIED IDEOGRAPH + 0xFB49: 0x9E0C, //CJK UNIFIED IDEOGRAPH + 0xFB4A: 0x9E0D, //CJK UNIFIED IDEOGRAPH + 0xFB4B: 0x9E0E, //CJK UNIFIED IDEOGRAPH + 0xFB4C: 0x9E0F, //CJK UNIFIED IDEOGRAPH + 0xFB4D: 0x9E10, //CJK UNIFIED IDEOGRAPH + 0xFB4E: 0x9E11, //CJK UNIFIED IDEOGRAPH + 0xFB4F: 0x9E12, //CJK UNIFIED IDEOGRAPH + 0xFB50: 0x9E13, //CJK UNIFIED IDEOGRAPH + 0xFB51: 0x9E14, //CJK UNIFIED IDEOGRAPH + 0xFB52: 0x9E15, //CJK UNIFIED IDEOGRAPH + 0xFB53: 0x9E16, //CJK UNIFIED IDEOGRAPH + 0xFB54: 0x9E17, //CJK UNIFIED IDEOGRAPH + 0xFB55: 0x9E18, //CJK UNIFIED IDEOGRAPH + 0xFB56: 0x9E19, //CJK UNIFIED IDEOGRAPH + 0xFB57: 0x9E1A, //CJK UNIFIED IDEOGRAPH + 0xFB58: 0x9E1B, //CJK UNIFIED IDEOGRAPH + 0xFB59: 0x9E1C, //CJK UNIFIED IDEOGRAPH + 0xFB5A: 0x9E1D, //CJK UNIFIED IDEOGRAPH + 0xFB5B: 0x9E1E, //CJK UNIFIED IDEOGRAPH + 0xFB5C: 0x9E24, //CJK UNIFIED IDEOGRAPH + 0xFB5D: 0x9E27, //CJK UNIFIED IDEOGRAPH + 0xFB5E: 0x9E2E, //CJK UNIFIED IDEOGRAPH + 0xFB5F: 0x9E30, //CJK UNIFIED IDEOGRAPH + 0xFB60: 0x9E34, //CJK UNIFIED IDEOGRAPH + 0xFB61: 0x9E3B, //CJK UNIFIED IDEOGRAPH + 0xFB62: 0x9E3C, //CJK UNIFIED IDEOGRAPH + 0xFB63: 0x9E40, //CJK UNIFIED IDEOGRAPH + 0xFB64: 0x9E4D, //CJK UNIFIED IDEOGRAPH + 0xFB65: 0x9E50, //CJK UNIFIED IDEOGRAPH + 0xFB66: 0x9E52, //CJK UNIFIED IDEOGRAPH + 0xFB67: 0x9E53, //CJK UNIFIED IDEOGRAPH + 0xFB68: 0x9E54, //CJK UNIFIED IDEOGRAPH + 0xFB69: 0x9E56, //CJK UNIFIED IDEOGRAPH + 0xFB6A: 0x9E59, //CJK UNIFIED IDEOGRAPH + 0xFB6B: 0x9E5D, //CJK UNIFIED IDEOGRAPH + 0xFB6C: 0x9E5F, //CJK UNIFIED IDEOGRAPH + 0xFB6D: 0x9E60, //CJK UNIFIED IDEOGRAPH + 0xFB6E: 0x9E61, //CJK UNIFIED IDEOGRAPH + 0xFB6F: 0x9E62, //CJK UNIFIED IDEOGRAPH + 0xFB70: 0x9E65, //CJK UNIFIED IDEOGRAPH + 0xFB71: 0x9E6E, //CJK UNIFIED IDEOGRAPH + 0xFB72: 0x9E6F, //CJK UNIFIED IDEOGRAPH + 0xFB73: 0x9E72, //CJK UNIFIED IDEOGRAPH + 0xFB74: 0x9E74, //CJK UNIFIED IDEOGRAPH + 0xFB75: 0x9E75, //CJK UNIFIED IDEOGRAPH + 0xFB76: 0x9E76, //CJK UNIFIED IDEOGRAPH + 0xFB77: 0x9E77, //CJK UNIFIED IDEOGRAPH + 0xFB78: 0x9E78, //CJK UNIFIED IDEOGRAPH + 0xFB79: 0x9E79, //CJK UNIFIED IDEOGRAPH + 0xFB7A: 0x9E7A, //CJK UNIFIED IDEOGRAPH + 0xFB7B: 0x9E7B, //CJK UNIFIED IDEOGRAPH + 0xFB7C: 0x9E7C, //CJK UNIFIED IDEOGRAPH + 0xFB7D: 0x9E7D, //CJK UNIFIED IDEOGRAPH + 0xFB7E: 0x9E80, //CJK UNIFIED IDEOGRAPH + 0xFB80: 0x9E81, //CJK UNIFIED IDEOGRAPH + 0xFB81: 0x9E83, //CJK UNIFIED IDEOGRAPH + 0xFB82: 0x9E84, //CJK UNIFIED IDEOGRAPH + 0xFB83: 0x9E85, //CJK UNIFIED IDEOGRAPH + 0xFB84: 0x9E86, //CJK UNIFIED IDEOGRAPH + 0xFB85: 0x9E89, //CJK UNIFIED IDEOGRAPH + 0xFB86: 0x9E8A, //CJK UNIFIED IDEOGRAPH + 0xFB87: 0x9E8C, //CJK UNIFIED IDEOGRAPH + 0xFB88: 0x9E8D, //CJK UNIFIED IDEOGRAPH + 0xFB89: 0x9E8E, //CJK UNIFIED IDEOGRAPH + 0xFB8A: 0x9E8F, //CJK UNIFIED IDEOGRAPH + 0xFB8B: 0x9E90, //CJK UNIFIED IDEOGRAPH + 0xFB8C: 0x9E91, //CJK UNIFIED IDEOGRAPH + 0xFB8D: 0x9E94, //CJK UNIFIED IDEOGRAPH + 0xFB8E: 0x9E95, //CJK UNIFIED IDEOGRAPH + 0xFB8F: 0x9E96, //CJK UNIFIED IDEOGRAPH + 0xFB90: 0x9E97, //CJK UNIFIED IDEOGRAPH + 0xFB91: 0x9E98, //CJK UNIFIED IDEOGRAPH + 0xFB92: 0x9E99, //CJK UNIFIED IDEOGRAPH + 0xFB93: 0x9E9A, //CJK UNIFIED IDEOGRAPH + 0xFB94: 0x9E9B, //CJK UNIFIED IDEOGRAPH + 0xFB95: 0x9E9C, //CJK UNIFIED IDEOGRAPH + 0xFB96: 0x9E9E, //CJK UNIFIED IDEOGRAPH + 0xFB97: 0x9EA0, //CJK UNIFIED IDEOGRAPH + 0xFB98: 0x9EA1, //CJK UNIFIED IDEOGRAPH + 0xFB99: 0x9EA2, //CJK UNIFIED IDEOGRAPH + 0xFB9A: 0x9EA3, //CJK UNIFIED IDEOGRAPH + 0xFB9B: 0x9EA4, //CJK UNIFIED IDEOGRAPH + 0xFB9C: 0x9EA5, //CJK UNIFIED IDEOGRAPH + 0xFB9D: 0x9EA7, //CJK UNIFIED IDEOGRAPH + 0xFB9E: 0x9EA8, //CJK UNIFIED IDEOGRAPH + 0xFB9F: 0x9EA9, //CJK UNIFIED IDEOGRAPH + 0xFBA0: 0x9EAA, //CJK UNIFIED IDEOGRAPH + 0xFC40: 0x9EAB, //CJK UNIFIED IDEOGRAPH + 0xFC41: 0x9EAC, //CJK UNIFIED IDEOGRAPH + 0xFC42: 0x9EAD, //CJK UNIFIED IDEOGRAPH + 0xFC43: 0x9EAE, //CJK UNIFIED IDEOGRAPH + 0xFC44: 0x9EAF, //CJK UNIFIED IDEOGRAPH + 0xFC45: 0x9EB0, //CJK UNIFIED IDEOGRAPH + 0xFC46: 0x9EB1, //CJK UNIFIED IDEOGRAPH + 0xFC47: 0x9EB2, //CJK UNIFIED IDEOGRAPH + 0xFC48: 0x9EB3, //CJK UNIFIED IDEOGRAPH + 0xFC49: 0x9EB5, //CJK UNIFIED IDEOGRAPH + 0xFC4A: 0x9EB6, //CJK UNIFIED IDEOGRAPH + 0xFC4B: 0x9EB7, //CJK UNIFIED IDEOGRAPH + 0xFC4C: 0x9EB9, //CJK UNIFIED IDEOGRAPH + 0xFC4D: 0x9EBA, //CJK UNIFIED IDEOGRAPH + 0xFC4E: 0x9EBC, //CJK UNIFIED IDEOGRAPH + 0xFC4F: 0x9EBF, //CJK UNIFIED IDEOGRAPH + 0xFC50: 0x9EC0, //CJK UNIFIED IDEOGRAPH + 0xFC51: 0x9EC1, //CJK UNIFIED IDEOGRAPH + 0xFC52: 0x9EC2, //CJK UNIFIED IDEOGRAPH + 0xFC53: 0x9EC3, //CJK UNIFIED IDEOGRAPH + 0xFC54: 0x9EC5, //CJK UNIFIED IDEOGRAPH + 0xFC55: 0x9EC6, //CJK UNIFIED IDEOGRAPH + 0xFC56: 0x9EC7, //CJK UNIFIED IDEOGRAPH + 0xFC57: 0x9EC8, //CJK UNIFIED IDEOGRAPH + 0xFC58: 0x9ECA, //CJK UNIFIED IDEOGRAPH + 0xFC59: 0x9ECB, //CJK UNIFIED IDEOGRAPH + 0xFC5A: 0x9ECC, //CJK UNIFIED IDEOGRAPH + 0xFC5B: 0x9ED0, //CJK UNIFIED IDEOGRAPH + 0xFC5C: 0x9ED2, //CJK UNIFIED IDEOGRAPH + 0xFC5D: 0x9ED3, //CJK UNIFIED IDEOGRAPH + 0xFC5E: 0x9ED5, //CJK UNIFIED IDEOGRAPH + 0xFC5F: 0x9ED6, //CJK UNIFIED IDEOGRAPH + 0xFC60: 0x9ED7, //CJK UNIFIED IDEOGRAPH + 0xFC61: 0x9ED9, //CJK UNIFIED IDEOGRAPH + 0xFC62: 0x9EDA, //CJK UNIFIED IDEOGRAPH + 0xFC63: 0x9EDE, //CJK UNIFIED IDEOGRAPH + 0xFC64: 0x9EE1, //CJK UNIFIED IDEOGRAPH + 0xFC65: 0x9EE3, //CJK UNIFIED IDEOGRAPH + 0xFC66: 0x9EE4, //CJK UNIFIED IDEOGRAPH + 0xFC67: 0x9EE6, //CJK UNIFIED IDEOGRAPH + 0xFC68: 0x9EE8, //CJK UNIFIED IDEOGRAPH + 0xFC69: 0x9EEB, //CJK UNIFIED IDEOGRAPH + 0xFC6A: 0x9EEC, //CJK UNIFIED IDEOGRAPH + 0xFC6B: 0x9EED, //CJK UNIFIED IDEOGRAPH + 0xFC6C: 0x9EEE, //CJK UNIFIED IDEOGRAPH + 0xFC6D: 0x9EF0, //CJK UNIFIED IDEOGRAPH + 0xFC6E: 0x9EF1, //CJK UNIFIED IDEOGRAPH + 0xFC6F: 0x9EF2, //CJK UNIFIED IDEOGRAPH + 0xFC70: 0x9EF3, //CJK UNIFIED IDEOGRAPH + 0xFC71: 0x9EF4, //CJK UNIFIED IDEOGRAPH + 0xFC72: 0x9EF5, //CJK UNIFIED IDEOGRAPH + 0xFC73: 0x9EF6, //CJK UNIFIED IDEOGRAPH + 0xFC74: 0x9EF7, //CJK UNIFIED IDEOGRAPH + 0xFC75: 0x9EF8, //CJK UNIFIED IDEOGRAPH + 0xFC76: 0x9EFA, //CJK UNIFIED IDEOGRAPH + 0xFC77: 0x9EFD, //CJK UNIFIED IDEOGRAPH + 0xFC78: 0x9EFF, //CJK UNIFIED IDEOGRAPH + 0xFC79: 0x9F00, //CJK UNIFIED IDEOGRAPH + 0xFC7A: 0x9F01, //CJK UNIFIED IDEOGRAPH + 0xFC7B: 0x9F02, //CJK UNIFIED IDEOGRAPH + 0xFC7C: 0x9F03, //CJK UNIFIED IDEOGRAPH + 0xFC7D: 0x9F04, //CJK UNIFIED IDEOGRAPH + 0xFC7E: 0x9F05, //CJK UNIFIED IDEOGRAPH + 0xFC80: 0x9F06, //CJK UNIFIED IDEOGRAPH + 0xFC81: 0x9F07, //CJK UNIFIED IDEOGRAPH + 0xFC82: 0x9F08, //CJK UNIFIED IDEOGRAPH + 0xFC83: 0x9F09, //CJK UNIFIED IDEOGRAPH + 0xFC84: 0x9F0A, //CJK UNIFIED IDEOGRAPH + 0xFC85: 0x9F0C, //CJK UNIFIED IDEOGRAPH + 0xFC86: 0x9F0F, //CJK UNIFIED IDEOGRAPH + 0xFC87: 0x9F11, //CJK UNIFIED IDEOGRAPH + 0xFC88: 0x9F12, //CJK UNIFIED IDEOGRAPH + 0xFC89: 0x9F14, //CJK UNIFIED IDEOGRAPH + 0xFC8A: 0x9F15, //CJK UNIFIED IDEOGRAPH + 0xFC8B: 0x9F16, //CJK UNIFIED IDEOGRAPH + 0xFC8C: 0x9F18, //CJK UNIFIED IDEOGRAPH + 0xFC8D: 0x9F1A, //CJK UNIFIED IDEOGRAPH + 0xFC8E: 0x9F1B, //CJK UNIFIED IDEOGRAPH + 0xFC8F: 0x9F1C, //CJK UNIFIED IDEOGRAPH + 0xFC90: 0x9F1D, //CJK UNIFIED IDEOGRAPH + 0xFC91: 0x9F1E, //CJK UNIFIED IDEOGRAPH + 0xFC92: 0x9F1F, //CJK UNIFIED IDEOGRAPH + 0xFC93: 0x9F21, //CJK UNIFIED IDEOGRAPH + 0xFC94: 0x9F23, //CJK UNIFIED IDEOGRAPH + 0xFC95: 0x9F24, //CJK UNIFIED IDEOGRAPH + 0xFC96: 0x9F25, //CJK UNIFIED IDEOGRAPH + 0xFC97: 0x9F26, //CJK UNIFIED IDEOGRAPH + 0xFC98: 0x9F27, //CJK UNIFIED IDEOGRAPH + 0xFC99: 0x9F28, //CJK UNIFIED IDEOGRAPH + 0xFC9A: 0x9F29, //CJK UNIFIED IDEOGRAPH + 0xFC9B: 0x9F2A, //CJK UNIFIED IDEOGRAPH + 0xFC9C: 0x9F2B, //CJK UNIFIED IDEOGRAPH + 0xFC9D: 0x9F2D, //CJK UNIFIED IDEOGRAPH + 0xFC9E: 0x9F2E, //CJK UNIFIED IDEOGRAPH + 0xFC9F: 0x9F30, //CJK UNIFIED IDEOGRAPH + 0xFCA0: 0x9F31, //CJK UNIFIED IDEOGRAPH + 0xFD40: 0x9F32, //CJK UNIFIED IDEOGRAPH + 0xFD41: 0x9F33, //CJK UNIFIED IDEOGRAPH + 0xFD42: 0x9F34, //CJK UNIFIED IDEOGRAPH + 0xFD43: 0x9F35, //CJK UNIFIED IDEOGRAPH + 0xFD44: 0x9F36, //CJK UNIFIED IDEOGRAPH + 0xFD45: 0x9F38, //CJK UNIFIED IDEOGRAPH + 0xFD46: 0x9F3A, //CJK UNIFIED IDEOGRAPH + 0xFD47: 0x9F3C, //CJK UNIFIED IDEOGRAPH + 0xFD48: 0x9F3F, //CJK UNIFIED IDEOGRAPH + 0xFD49: 0x9F40, //CJK UNIFIED IDEOGRAPH + 0xFD4A: 0x9F41, //CJK UNIFIED IDEOGRAPH + 0xFD4B: 0x9F42, //CJK UNIFIED IDEOGRAPH + 0xFD4C: 0x9F43, //CJK UNIFIED IDEOGRAPH + 0xFD4D: 0x9F45, //CJK UNIFIED IDEOGRAPH + 0xFD4E: 0x9F46, //CJK UNIFIED IDEOGRAPH + 0xFD4F: 0x9F47, //CJK UNIFIED IDEOGRAPH + 0xFD50: 0x9F48, //CJK UNIFIED IDEOGRAPH + 0xFD51: 0x9F49, //CJK UNIFIED IDEOGRAPH + 0xFD52: 0x9F4A, //CJK UNIFIED IDEOGRAPH + 0xFD53: 0x9F4B, //CJK UNIFIED IDEOGRAPH + 0xFD54: 0x9F4C, //CJK UNIFIED IDEOGRAPH + 0xFD55: 0x9F4D, //CJK UNIFIED IDEOGRAPH + 0xFD56: 0x9F4E, //CJK UNIFIED IDEOGRAPH + 0xFD57: 0x9F4F, //CJK UNIFIED IDEOGRAPH + 0xFD58: 0x9F52, //CJK UNIFIED IDEOGRAPH + 0xFD59: 0x9F53, //CJK UNIFIED IDEOGRAPH + 0xFD5A: 0x9F54, //CJK UNIFIED IDEOGRAPH + 0xFD5B: 0x9F55, //CJK UNIFIED IDEOGRAPH + 0xFD5C: 0x9F56, //CJK UNIFIED IDEOGRAPH + 0xFD5D: 0x9F57, //CJK UNIFIED IDEOGRAPH + 0xFD5E: 0x9F58, //CJK UNIFIED IDEOGRAPH + 0xFD5F: 0x9F59, //CJK UNIFIED IDEOGRAPH + 0xFD60: 0x9F5A, //CJK UNIFIED IDEOGRAPH + 0xFD61: 0x9F5B, //CJK UNIFIED IDEOGRAPH + 0xFD62: 0x9F5C, //CJK UNIFIED IDEOGRAPH + 0xFD63: 0x9F5D, //CJK UNIFIED IDEOGRAPH + 0xFD64: 0x9F5E, //CJK UNIFIED IDEOGRAPH + 0xFD65: 0x9F5F, //CJK UNIFIED IDEOGRAPH + 0xFD66: 0x9F60, //CJK UNIFIED IDEOGRAPH + 0xFD67: 0x9F61, //CJK UNIFIED IDEOGRAPH + 0xFD68: 0x9F62, //CJK UNIFIED IDEOGRAPH + 0xFD69: 0x9F63, //CJK UNIFIED IDEOGRAPH + 0xFD6A: 0x9F64, //CJK UNIFIED IDEOGRAPH + 0xFD6B: 0x9F65, //CJK UNIFIED IDEOGRAPH + 0xFD6C: 0x9F66, //CJK UNIFIED IDEOGRAPH + 0xFD6D: 0x9F67, //CJK UNIFIED IDEOGRAPH + 0xFD6E: 0x9F68, //CJK UNIFIED IDEOGRAPH + 0xFD6F: 0x9F69, //CJK UNIFIED IDEOGRAPH + 0xFD70: 0x9F6A, //CJK UNIFIED IDEOGRAPH + 0xFD71: 0x9F6B, //CJK UNIFIED IDEOGRAPH + 0xFD72: 0x9F6C, //CJK UNIFIED IDEOGRAPH + 0xFD73: 0x9F6D, //CJK UNIFIED IDEOGRAPH + 0xFD74: 0x9F6E, //CJK UNIFIED IDEOGRAPH + 0xFD75: 0x9F6F, //CJK UNIFIED IDEOGRAPH + 0xFD76: 0x9F70, //CJK UNIFIED IDEOGRAPH + 0xFD77: 0x9F71, //CJK UNIFIED IDEOGRAPH + 0xFD78: 0x9F72, //CJK UNIFIED IDEOGRAPH + 0xFD79: 0x9F73, //CJK UNIFIED IDEOGRAPH + 0xFD7A: 0x9F74, //CJK UNIFIED IDEOGRAPH + 0xFD7B: 0x9F75, //CJK UNIFIED IDEOGRAPH + 0xFD7C: 0x9F76, //CJK UNIFIED IDEOGRAPH + 0xFD7D: 0x9F77, //CJK UNIFIED IDEOGRAPH + 0xFD7E: 0x9F78, //CJK UNIFIED IDEOGRAPH + 0xFD80: 0x9F79, //CJK UNIFIED IDEOGRAPH + 0xFD81: 0x9F7A, //CJK UNIFIED IDEOGRAPH + 0xFD82: 0x9F7B, //CJK UNIFIED IDEOGRAPH + 0xFD83: 0x9F7C, //CJK UNIFIED IDEOGRAPH + 0xFD84: 0x9F7D, //CJK UNIFIED IDEOGRAPH + 0xFD85: 0x9F7E, //CJK UNIFIED IDEOGRAPH + 0xFD86: 0x9F81, //CJK UNIFIED IDEOGRAPH + 0xFD87: 0x9F82, //CJK UNIFIED IDEOGRAPH + 0xFD88: 0x9F8D, //CJK UNIFIED IDEOGRAPH + 0xFD89: 0x9F8E, //CJK UNIFIED IDEOGRAPH + 0xFD8A: 0x9F8F, //CJK UNIFIED IDEOGRAPH + 0xFD8B: 0x9F90, //CJK UNIFIED IDEOGRAPH + 0xFD8C: 0x9F91, //CJK UNIFIED IDEOGRAPH + 0xFD8D: 0x9F92, //CJK UNIFIED IDEOGRAPH + 0xFD8E: 0x9F93, //CJK UNIFIED IDEOGRAPH + 0xFD8F: 0x9F94, //CJK UNIFIED IDEOGRAPH + 0xFD90: 0x9F95, //CJK UNIFIED IDEOGRAPH + 0xFD91: 0x9F96, //CJK UNIFIED IDEOGRAPH + 0xFD92: 0x9F97, //CJK UNIFIED IDEOGRAPH + 0xFD93: 0x9F98, //CJK UNIFIED IDEOGRAPH + 0xFD94: 0x9F9C, //CJK UNIFIED IDEOGRAPH + 0xFD95: 0x9F9D, //CJK UNIFIED IDEOGRAPH + 0xFD96: 0x9F9E, //CJK UNIFIED IDEOGRAPH + 0xFD97: 0x9FA1, //CJK UNIFIED IDEOGRAPH + 0xFD98: 0x9FA2, //CJK UNIFIED IDEOGRAPH + 0xFD99: 0x9FA3, //CJK UNIFIED IDEOGRAPH + 0xFD9A: 0x9FA4, //CJK UNIFIED IDEOGRAPH + 0xFD9B: 0x9FA5, //CJK UNIFIED IDEOGRAPH + 0xFD9C: 0xF92C, //CJK COMPATIBILITY IDEOGRAPH + 0xFD9D: 0xF979, //CJK COMPATIBILITY IDEOGRAPH + 0xFD9E: 0xF995, //CJK COMPATIBILITY IDEOGRAPH + 0xFD9F: 0xF9E7, //CJK COMPATIBILITY IDEOGRAPH + 0xFDA0: 0xF9F1, //CJK COMPATIBILITY IDEOGRAPH + 0xFE40: 0xFA0C, //CJK COMPATIBILITY IDEOGRAPH + 0xFE41: 0xFA0D, //CJK COMPATIBILITY IDEOGRAPH + 0xFE42: 0xFA0E, //CJK COMPATIBILITY IDEOGRAPH + 0xFE43: 0xFA0F, //CJK COMPATIBILITY IDEOGRAPH + 0xFE44: 0xFA11, //CJK COMPATIBILITY IDEOGRAPH + 0xFE45: 0xFA13, //CJK COMPATIBILITY IDEOGRAPH + 0xFE46: 0xFA14, //CJK COMPATIBILITY IDEOGRAPH + 0xFE47: 0xFA18, //CJK COMPATIBILITY IDEOGRAPH + 0xFE48: 0xFA1F, //CJK COMPATIBILITY IDEOGRAPH + 0xFE49: 0xFA20, //CJK COMPATIBILITY IDEOGRAPH + 0xFE4A: 0xFA21, //CJK COMPATIBILITY IDEOGRAPH + 0xFE4B: 0xFA23, //CJK COMPATIBILITY IDEOGRAPH + 0xFE4C: 0xFA24, //CJK COMPATIBILITY IDEOGRAPH + 0xFE4D: 0xFA27, //CJK COMPATIBILITY IDEOGRAPH + 0xFE4E: 0xFA28, //CJK COMPATIBILITY IDEOGRAPH + 0xFE4F: 0xFA29, //CJK COMPATIBILITY IDEOGRAPH + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp949.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp949.go new file mode 100644 index 00000000..52c708df --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp949.go @@ -0,0 +1,17312 @@ +package cp + +var cp949 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0xFFFD, //UNDEFINED + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + 0xFFFD, //UNDEFINED + }, + db: map[int]rune{ + 0x8141: 0xAC02, //HANGUL SYLLABLE KIYEOK A SSANGKIYEOK + 0x8142: 0xAC03, //HANGUL SYLLABLE KIYEOK A KIYEOKSIOS + 0x8143: 0xAC05, //HANGUL SYLLABLE KIYEOK A NIEUNCIEUC + 0x8144: 0xAC06, //HANGUL SYLLABLE KIYEOK A NIEUNHIEUH + 0x8145: 0xAC0B, //HANGUL SYLLABLE KIYEOK A RIEULPIEUP + 0x8146: 0xAC0C, //HANGUL SYLLABLE KIYEOK A RIEULSIOS + 0x8147: 0xAC0D, //HANGUL SYLLABLE KIYEOK A RIEULTHIEUTH + 0x8148: 0xAC0E, //HANGUL SYLLABLE KIYEOK A RIEULPHIEUPH + 0x8149: 0xAC0F, //HANGUL SYLLABLE KIYEOK A RIEULHIEUH + 0x814A: 0xAC18, //HANGUL SYLLABLE KIYEOK A KHIEUKH + 0x814B: 0xAC1E, //HANGUL SYLLABLE KIYEOK AE SSANGKIYEOK + 0x814C: 0xAC1F, //HANGUL SYLLABLE KIYEOK AE KIYEOKSIOS + 0x814D: 0xAC21, //HANGUL SYLLABLE KIYEOK AE NIEUNCIEUC + 0x814E: 0xAC22, //HANGUL SYLLABLE KIYEOK AE NIEUNHIEUH + 0x814F: 0xAC23, //HANGUL SYLLABLE KIYEOK AE TIKEUT + 0x8150: 0xAC25, //HANGUL SYLLABLE KIYEOK AE RIEULKIYEOK + 0x8151: 0xAC26, //HANGUL SYLLABLE KIYEOK AE RIEULMIEUM + 0x8152: 0xAC27, //HANGUL SYLLABLE KIYEOK AE RIEULPIEUP + 0x8153: 0xAC28, //HANGUL SYLLABLE KIYEOK AE RIEULSIOS + 0x8154: 0xAC29, //HANGUL SYLLABLE KIYEOK AE RIEULTHIEUTH + 0x8155: 0xAC2A, //HANGUL SYLLABLE KIYEOK AE RIEULPHIEUPH + 0x8156: 0xAC2B, //HANGUL SYLLABLE KIYEOK AE RIEULHIEUH + 0x8157: 0xAC2E, //HANGUL SYLLABLE KIYEOK AE PIEUPSIOS + 0x8158: 0xAC32, //HANGUL SYLLABLE KIYEOK AE CIEUC + 0x8159: 0xAC33, //HANGUL SYLLABLE KIYEOK AE CHIEUCH + 0x815A: 0xAC34, //HANGUL SYLLABLE KIYEOK AE KHIEUKH + 0x8161: 0xAC35, //HANGUL SYLLABLE KIYEOK AE THIEUTH + 0x8162: 0xAC36, //HANGUL SYLLABLE KIYEOK AE PHIEUPH + 0x8163: 0xAC37, //HANGUL SYLLABLE KIYEOK AE HIEUH + 0x8164: 0xAC3A, //HANGUL SYLLABLE KIYEOK YA SSANGKIYEOK + 0x8165: 0xAC3B, //HANGUL SYLLABLE KIYEOK YA KIYEOKSIOS + 0x8166: 0xAC3D, //HANGUL SYLLABLE KIYEOK YA NIEUNCIEUC + 0x8167: 0xAC3E, //HANGUL SYLLABLE KIYEOK YA NIEUNHIEUH + 0x8168: 0xAC3F, //HANGUL SYLLABLE KIYEOK YA TIKEUT + 0x8169: 0xAC41, //HANGUL SYLLABLE KIYEOK YA RIEULKIYEOK + 0x816A: 0xAC42, //HANGUL SYLLABLE KIYEOK YA RIEULMIEUM + 0x816B: 0xAC43, //HANGUL SYLLABLE KIYEOK YA RIEULPIEUP + 0x816C: 0xAC44, //HANGUL SYLLABLE KIYEOK YA RIEULSIOS + 0x816D: 0xAC45, //HANGUL SYLLABLE KIYEOK YA RIEULTHIEUTH + 0x816E: 0xAC46, //HANGUL SYLLABLE KIYEOK YA RIEULPHIEUPH + 0x816F: 0xAC47, //HANGUL SYLLABLE KIYEOK YA RIEULHIEUH + 0x8170: 0xAC48, //HANGUL SYLLABLE KIYEOK YA MIEUM + 0x8171: 0xAC49, //HANGUL SYLLABLE KIYEOK YA PIEUP + 0x8172: 0xAC4A, //HANGUL SYLLABLE KIYEOK YA PIEUPSIOS + 0x8173: 0xAC4C, //HANGUL SYLLABLE KIYEOK YA SSANGSIOS + 0x8174: 0xAC4E, //HANGUL SYLLABLE KIYEOK YA CIEUC + 0x8175: 0xAC4F, //HANGUL SYLLABLE KIYEOK YA CHIEUCH + 0x8176: 0xAC50, //HANGUL SYLLABLE KIYEOK YA KHIEUKH + 0x8177: 0xAC51, //HANGUL SYLLABLE KIYEOK YA THIEUTH + 0x8178: 0xAC52, //HANGUL SYLLABLE KIYEOK YA PHIEUPH + 0x8179: 0xAC53, //HANGUL SYLLABLE KIYEOK YA HIEUH + 0x817A: 0xAC55, //HANGUL SYLLABLE KIYEOK YAE KIYEOK + 0x8181: 0xAC56, //HANGUL SYLLABLE KIYEOK YAE SSANGKIYEOK + 0x8182: 0xAC57, //HANGUL SYLLABLE KIYEOK YAE KIYEOKSIOS + 0x8183: 0xAC59, //HANGUL SYLLABLE KIYEOK YAE NIEUNCIEUC + 0x8184: 0xAC5A, //HANGUL SYLLABLE KIYEOK YAE NIEUNHIEUH + 0x8185: 0xAC5B, //HANGUL SYLLABLE KIYEOK YAE TIKEUT + 0x8186: 0xAC5D, //HANGUL SYLLABLE KIYEOK YAE RIEULKIYEOK + 0x8187: 0xAC5E, //HANGUL SYLLABLE KIYEOK YAE RIEULMIEUM + 0x8188: 0xAC5F, //HANGUL SYLLABLE KIYEOK YAE RIEULPIEUP + 0x8189: 0xAC60, //HANGUL SYLLABLE KIYEOK YAE RIEULSIOS + 0x818A: 0xAC61, //HANGUL SYLLABLE KIYEOK YAE RIEULTHIEUTH + 0x818B: 0xAC62, //HANGUL SYLLABLE KIYEOK YAE RIEULPHIEUPH + 0x818C: 0xAC63, //HANGUL SYLLABLE KIYEOK YAE RIEULHIEUH + 0x818D: 0xAC64, //HANGUL SYLLABLE KIYEOK YAE MIEUM + 0x818E: 0xAC65, //HANGUL SYLLABLE KIYEOK YAE PIEUP + 0x818F: 0xAC66, //HANGUL SYLLABLE KIYEOK YAE PIEUPSIOS + 0x8190: 0xAC67, //HANGUL SYLLABLE KIYEOK YAE SIOS + 0x8191: 0xAC68, //HANGUL SYLLABLE KIYEOK YAE SSANGSIOS + 0x8192: 0xAC69, //HANGUL SYLLABLE KIYEOK YAE IEUNG + 0x8193: 0xAC6A, //HANGUL SYLLABLE KIYEOK YAE CIEUC + 0x8194: 0xAC6B, //HANGUL SYLLABLE KIYEOK YAE CHIEUCH + 0x8195: 0xAC6C, //HANGUL SYLLABLE KIYEOK YAE KHIEUKH + 0x8196: 0xAC6D, //HANGUL SYLLABLE KIYEOK YAE THIEUTH + 0x8197: 0xAC6E, //HANGUL SYLLABLE KIYEOK YAE PHIEUPH + 0x8198: 0xAC6F, //HANGUL SYLLABLE KIYEOK YAE HIEUH + 0x8199: 0xAC72, //HANGUL SYLLABLE KIYEOK EO SSANGKIYEOK + 0x819A: 0xAC73, //HANGUL SYLLABLE KIYEOK EO KIYEOKSIOS + 0x819B: 0xAC75, //HANGUL SYLLABLE KIYEOK EO NIEUNCIEUC + 0x819C: 0xAC76, //HANGUL SYLLABLE KIYEOK EO NIEUNHIEUH + 0x819D: 0xAC79, //HANGUL SYLLABLE KIYEOK EO RIEULKIYEOK + 0x819E: 0xAC7B, //HANGUL SYLLABLE KIYEOK EO RIEULPIEUP + 0x819F: 0xAC7C, //HANGUL SYLLABLE KIYEOK EO RIEULSIOS + 0x81A0: 0xAC7D, //HANGUL SYLLABLE KIYEOK EO RIEULTHIEUTH + 0x81A1: 0xAC7E, //HANGUL SYLLABLE KIYEOK EO RIEULPHIEUPH + 0x81A2: 0xAC7F, //HANGUL SYLLABLE KIYEOK EO RIEULHIEUH + 0x81A3: 0xAC82, //HANGUL SYLLABLE KIYEOK EO PIEUPSIOS + 0x81A4: 0xAC87, //HANGUL SYLLABLE KIYEOK EO CHIEUCH + 0x81A5: 0xAC88, //HANGUL SYLLABLE KIYEOK EO KHIEUKH + 0x81A6: 0xAC8D, //HANGUL SYLLABLE KIYEOK E KIYEOK + 0x81A7: 0xAC8E, //HANGUL SYLLABLE KIYEOK E SSANGKIYEOK + 0x81A8: 0xAC8F, //HANGUL SYLLABLE KIYEOK E KIYEOKSIOS + 0x81A9: 0xAC91, //HANGUL SYLLABLE KIYEOK E NIEUNCIEUC + 0x81AA: 0xAC92, //HANGUL SYLLABLE KIYEOK E NIEUNHIEUH + 0x81AB: 0xAC93, //HANGUL SYLLABLE KIYEOK E TIKEUT + 0x81AC: 0xAC95, //HANGUL SYLLABLE KIYEOK E RIEULKIYEOK + 0x81AD: 0xAC96, //HANGUL SYLLABLE KIYEOK E RIEULMIEUM + 0x81AE: 0xAC97, //HANGUL SYLLABLE KIYEOK E RIEULPIEUP + 0x81AF: 0xAC98, //HANGUL SYLLABLE KIYEOK E RIEULSIOS + 0x81B0: 0xAC99, //HANGUL SYLLABLE KIYEOK E RIEULTHIEUTH + 0x81B1: 0xAC9A, //HANGUL SYLLABLE KIYEOK E RIEULPHIEUPH + 0x81B2: 0xAC9B, //HANGUL SYLLABLE KIYEOK E RIEULHIEUH + 0x81B3: 0xAC9E, //HANGUL SYLLABLE KIYEOK E PIEUPSIOS + 0x81B4: 0xACA2, //HANGUL SYLLABLE KIYEOK E CIEUC + 0x81B5: 0xACA3, //HANGUL SYLLABLE KIYEOK E CHIEUCH + 0x81B6: 0xACA4, //HANGUL SYLLABLE KIYEOK E KHIEUKH + 0x81B7: 0xACA5, //HANGUL SYLLABLE KIYEOK E THIEUTH + 0x81B8: 0xACA6, //HANGUL SYLLABLE KIYEOK E PHIEUPH + 0x81B9: 0xACA7, //HANGUL SYLLABLE KIYEOK E HIEUH + 0x81BA: 0xACAB, //HANGUL SYLLABLE KIYEOK YEO KIYEOKSIOS + 0x81BB: 0xACAD, //HANGUL SYLLABLE KIYEOK YEO NIEUNCIEUC + 0x81BC: 0xACAE, //HANGUL SYLLABLE KIYEOK YEO NIEUNHIEUH + 0x81BD: 0xACB1, //HANGUL SYLLABLE KIYEOK YEO RIEULKIYEOK + 0x81BE: 0xACB2, //HANGUL SYLLABLE KIYEOK YEO RIEULMIEUM + 0x81BF: 0xACB3, //HANGUL SYLLABLE KIYEOK YEO RIEULPIEUP + 0x81C0: 0xACB4, //HANGUL SYLLABLE KIYEOK YEO RIEULSIOS + 0x81C1: 0xACB5, //HANGUL SYLLABLE KIYEOK YEO RIEULTHIEUTH + 0x81C2: 0xACB6, //HANGUL SYLLABLE KIYEOK YEO RIEULPHIEUPH + 0x81C3: 0xACB7, //HANGUL SYLLABLE KIYEOK YEO RIEULHIEUH + 0x81C4: 0xACBA, //HANGUL SYLLABLE KIYEOK YEO PIEUPSIOS + 0x81C5: 0xACBE, //HANGUL SYLLABLE KIYEOK YEO CIEUC + 0x81C6: 0xACBF, //HANGUL SYLLABLE KIYEOK YEO CHIEUCH + 0x81C7: 0xACC0, //HANGUL SYLLABLE KIYEOK YEO KHIEUKH + 0x81C8: 0xACC2, //HANGUL SYLLABLE KIYEOK YEO PHIEUPH + 0x81C9: 0xACC3, //HANGUL SYLLABLE KIYEOK YEO HIEUH + 0x81CA: 0xACC5, //HANGUL SYLLABLE KIYEOK YE KIYEOK + 0x81CB: 0xACC6, //HANGUL SYLLABLE KIYEOK YE SSANGKIYEOK + 0x81CC: 0xACC7, //HANGUL SYLLABLE KIYEOK YE KIYEOKSIOS + 0x81CD: 0xACC9, //HANGUL SYLLABLE KIYEOK YE NIEUNCIEUC + 0x81CE: 0xACCA, //HANGUL SYLLABLE KIYEOK YE NIEUNHIEUH + 0x81CF: 0xACCB, //HANGUL SYLLABLE KIYEOK YE TIKEUT + 0x81D0: 0xACCD, //HANGUL SYLLABLE KIYEOK YE RIEULKIYEOK + 0x81D1: 0xACCE, //HANGUL SYLLABLE KIYEOK YE RIEULMIEUM + 0x81D2: 0xACCF, //HANGUL SYLLABLE KIYEOK YE RIEULPIEUP + 0x81D3: 0xACD0, //HANGUL SYLLABLE KIYEOK YE RIEULSIOS + 0x81D4: 0xACD1, //HANGUL SYLLABLE KIYEOK YE RIEULTHIEUTH + 0x81D5: 0xACD2, //HANGUL SYLLABLE KIYEOK YE RIEULPHIEUPH + 0x81D6: 0xACD3, //HANGUL SYLLABLE KIYEOK YE RIEULHIEUH + 0x81D7: 0xACD4, //HANGUL SYLLABLE KIYEOK YE MIEUM + 0x81D8: 0xACD6, //HANGUL SYLLABLE KIYEOK YE PIEUPSIOS + 0x81D9: 0xACD8, //HANGUL SYLLABLE KIYEOK YE SSANGSIOS + 0x81DA: 0xACD9, //HANGUL SYLLABLE KIYEOK YE IEUNG + 0x81DB: 0xACDA, //HANGUL SYLLABLE KIYEOK YE CIEUC + 0x81DC: 0xACDB, //HANGUL SYLLABLE KIYEOK YE CHIEUCH + 0x81DD: 0xACDC, //HANGUL SYLLABLE KIYEOK YE KHIEUKH + 0x81DE: 0xACDD, //HANGUL SYLLABLE KIYEOK YE THIEUTH + 0x81DF: 0xACDE, //HANGUL SYLLABLE KIYEOK YE PHIEUPH + 0x81E0: 0xACDF, //HANGUL SYLLABLE KIYEOK YE HIEUH + 0x81E1: 0xACE2, //HANGUL SYLLABLE KIYEOK O SSANGKIYEOK + 0x81E2: 0xACE3, //HANGUL SYLLABLE KIYEOK O KIYEOKSIOS + 0x81E3: 0xACE5, //HANGUL SYLLABLE KIYEOK O NIEUNCIEUC + 0x81E4: 0xACE6, //HANGUL SYLLABLE KIYEOK O NIEUNHIEUH + 0x81E5: 0xACE9, //HANGUL SYLLABLE KIYEOK O RIEULKIYEOK + 0x81E6: 0xACEB, //HANGUL SYLLABLE KIYEOK O RIEULPIEUP + 0x81E7: 0xACED, //HANGUL SYLLABLE KIYEOK O RIEULTHIEUTH + 0x81E8: 0xACEE, //HANGUL SYLLABLE KIYEOK O RIEULPHIEUPH + 0x81E9: 0xACF2, //HANGUL SYLLABLE KIYEOK O PIEUPSIOS + 0x81EA: 0xACF4, //HANGUL SYLLABLE KIYEOK O SSANGSIOS + 0x81EB: 0xACF7, //HANGUL SYLLABLE KIYEOK O CHIEUCH + 0x81EC: 0xACF8, //HANGUL SYLLABLE KIYEOK O KHIEUKH + 0x81ED: 0xACF9, //HANGUL SYLLABLE KIYEOK O THIEUTH + 0x81EE: 0xACFA, //HANGUL SYLLABLE KIYEOK O PHIEUPH + 0x81EF: 0xACFB, //HANGUL SYLLABLE KIYEOK O HIEUH + 0x81F0: 0xACFE, //HANGUL SYLLABLE KIYEOK WA SSANGKIYEOK + 0x81F1: 0xACFF, //HANGUL SYLLABLE KIYEOK WA KIYEOKSIOS + 0x81F2: 0xAD01, //HANGUL SYLLABLE KIYEOK WA NIEUNCIEUC + 0x81F3: 0xAD02, //HANGUL SYLLABLE KIYEOK WA NIEUNHIEUH + 0x81F4: 0xAD03, //HANGUL SYLLABLE KIYEOK WA TIKEUT + 0x81F5: 0xAD05, //HANGUL SYLLABLE KIYEOK WA RIEULKIYEOK + 0x81F6: 0xAD07, //HANGUL SYLLABLE KIYEOK WA RIEULPIEUP + 0x81F7: 0xAD08, //HANGUL SYLLABLE KIYEOK WA RIEULSIOS + 0x81F8: 0xAD09, //HANGUL SYLLABLE KIYEOK WA RIEULTHIEUTH + 0x81F9: 0xAD0A, //HANGUL SYLLABLE KIYEOK WA RIEULPHIEUPH + 0x81FA: 0xAD0B, //HANGUL SYLLABLE KIYEOK WA RIEULHIEUH + 0x81FB: 0xAD0E, //HANGUL SYLLABLE KIYEOK WA PIEUPSIOS + 0x81FC: 0xAD10, //HANGUL SYLLABLE KIYEOK WA SSANGSIOS + 0x81FD: 0xAD12, //HANGUL SYLLABLE KIYEOK WA CIEUC + 0x81FE: 0xAD13, //HANGUL SYLLABLE KIYEOK WA CHIEUCH + 0x8241: 0xAD14, //HANGUL SYLLABLE KIYEOK WA KHIEUKH + 0x8242: 0xAD15, //HANGUL SYLLABLE KIYEOK WA THIEUTH + 0x8243: 0xAD16, //HANGUL SYLLABLE KIYEOK WA PHIEUPH + 0x8244: 0xAD17, //HANGUL SYLLABLE KIYEOK WA HIEUH + 0x8245: 0xAD19, //HANGUL SYLLABLE KIYEOK WAE KIYEOK + 0x8246: 0xAD1A, //HANGUL SYLLABLE KIYEOK WAE SSANGKIYEOK + 0x8247: 0xAD1B, //HANGUL SYLLABLE KIYEOK WAE KIYEOKSIOS + 0x8248: 0xAD1D, //HANGUL SYLLABLE KIYEOK WAE NIEUNCIEUC + 0x8249: 0xAD1E, //HANGUL SYLLABLE KIYEOK WAE NIEUNHIEUH + 0x824A: 0xAD1F, //HANGUL SYLLABLE KIYEOK WAE TIKEUT + 0x824B: 0xAD21, //HANGUL SYLLABLE KIYEOK WAE RIEULKIYEOK + 0x824C: 0xAD22, //HANGUL SYLLABLE KIYEOK WAE RIEULMIEUM + 0x824D: 0xAD23, //HANGUL SYLLABLE KIYEOK WAE RIEULPIEUP + 0x824E: 0xAD24, //HANGUL SYLLABLE KIYEOK WAE RIEULSIOS + 0x824F: 0xAD25, //HANGUL SYLLABLE KIYEOK WAE RIEULTHIEUTH + 0x8250: 0xAD26, //HANGUL SYLLABLE KIYEOK WAE RIEULPHIEUPH + 0x8251: 0xAD27, //HANGUL SYLLABLE KIYEOK WAE RIEULHIEUH + 0x8252: 0xAD28, //HANGUL SYLLABLE KIYEOK WAE MIEUM + 0x8253: 0xAD2A, //HANGUL SYLLABLE KIYEOK WAE PIEUPSIOS + 0x8254: 0xAD2B, //HANGUL SYLLABLE KIYEOK WAE SIOS + 0x8255: 0xAD2E, //HANGUL SYLLABLE KIYEOK WAE CIEUC + 0x8256: 0xAD2F, //HANGUL SYLLABLE KIYEOK WAE CHIEUCH + 0x8257: 0xAD30, //HANGUL SYLLABLE KIYEOK WAE KHIEUKH + 0x8258: 0xAD31, //HANGUL SYLLABLE KIYEOK WAE THIEUTH + 0x8259: 0xAD32, //HANGUL SYLLABLE KIYEOK WAE PHIEUPH + 0x825A: 0xAD33, //HANGUL SYLLABLE KIYEOK WAE HIEUH + 0x8261: 0xAD36, //HANGUL SYLLABLE KIYEOK OE SSANGKIYEOK + 0x8262: 0xAD37, //HANGUL SYLLABLE KIYEOK OE KIYEOKSIOS + 0x8263: 0xAD39, //HANGUL SYLLABLE KIYEOK OE NIEUNCIEUC + 0x8264: 0xAD3A, //HANGUL SYLLABLE KIYEOK OE NIEUNHIEUH + 0x8265: 0xAD3B, //HANGUL SYLLABLE KIYEOK OE TIKEUT + 0x8266: 0xAD3D, //HANGUL SYLLABLE KIYEOK OE RIEULKIYEOK + 0x8267: 0xAD3E, //HANGUL SYLLABLE KIYEOK OE RIEULMIEUM + 0x8268: 0xAD3F, //HANGUL SYLLABLE KIYEOK OE RIEULPIEUP + 0x8269: 0xAD40, //HANGUL SYLLABLE KIYEOK OE RIEULSIOS + 0x826A: 0xAD41, //HANGUL SYLLABLE KIYEOK OE RIEULTHIEUTH + 0x826B: 0xAD42, //HANGUL SYLLABLE KIYEOK OE RIEULPHIEUPH + 0x826C: 0xAD43, //HANGUL SYLLABLE KIYEOK OE RIEULHIEUH + 0x826D: 0xAD46, //HANGUL SYLLABLE KIYEOK OE PIEUPSIOS + 0x826E: 0xAD48, //HANGUL SYLLABLE KIYEOK OE SSANGSIOS + 0x826F: 0xAD4A, //HANGUL SYLLABLE KIYEOK OE CIEUC + 0x8270: 0xAD4B, //HANGUL SYLLABLE KIYEOK OE CHIEUCH + 0x8271: 0xAD4C, //HANGUL SYLLABLE KIYEOK OE KHIEUKH + 0x8272: 0xAD4D, //HANGUL SYLLABLE KIYEOK OE THIEUTH + 0x8273: 0xAD4E, //HANGUL SYLLABLE KIYEOK OE PHIEUPH + 0x8274: 0xAD4F, //HANGUL SYLLABLE KIYEOK OE HIEUH + 0x8275: 0xAD51, //HANGUL SYLLABLE KIYEOK YO KIYEOK + 0x8276: 0xAD52, //HANGUL SYLLABLE KIYEOK YO SSANGKIYEOK + 0x8277: 0xAD53, //HANGUL SYLLABLE KIYEOK YO KIYEOKSIOS + 0x8278: 0xAD55, //HANGUL SYLLABLE KIYEOK YO NIEUNCIEUC + 0x8279: 0xAD56, //HANGUL SYLLABLE KIYEOK YO NIEUNHIEUH + 0x827A: 0xAD57, //HANGUL SYLLABLE KIYEOK YO TIKEUT + 0x8281: 0xAD59, //HANGUL SYLLABLE KIYEOK YO RIEULKIYEOK + 0x8282: 0xAD5A, //HANGUL SYLLABLE KIYEOK YO RIEULMIEUM + 0x8283: 0xAD5B, //HANGUL SYLLABLE KIYEOK YO RIEULPIEUP + 0x8284: 0xAD5C, //HANGUL SYLLABLE KIYEOK YO RIEULSIOS + 0x8285: 0xAD5D, //HANGUL SYLLABLE KIYEOK YO RIEULTHIEUTH + 0x8286: 0xAD5E, //HANGUL SYLLABLE KIYEOK YO RIEULPHIEUPH + 0x8287: 0xAD5F, //HANGUL SYLLABLE KIYEOK YO RIEULHIEUH + 0x8288: 0xAD60, //HANGUL SYLLABLE KIYEOK YO MIEUM + 0x8289: 0xAD62, //HANGUL SYLLABLE KIYEOK YO PIEUPSIOS + 0x828A: 0xAD64, //HANGUL SYLLABLE KIYEOK YO SSANGSIOS + 0x828B: 0xAD65, //HANGUL SYLLABLE KIYEOK YO IEUNG + 0x828C: 0xAD66, //HANGUL SYLLABLE KIYEOK YO CIEUC + 0x828D: 0xAD67, //HANGUL SYLLABLE KIYEOK YO CHIEUCH + 0x828E: 0xAD68, //HANGUL SYLLABLE KIYEOK YO KHIEUKH + 0x828F: 0xAD69, //HANGUL SYLLABLE KIYEOK YO THIEUTH + 0x8290: 0xAD6A, //HANGUL SYLLABLE KIYEOK YO PHIEUPH + 0x8291: 0xAD6B, //HANGUL SYLLABLE KIYEOK YO HIEUH + 0x8292: 0xAD6E, //HANGUL SYLLABLE KIYEOK U SSANGKIYEOK + 0x8293: 0xAD6F, //HANGUL SYLLABLE KIYEOK U KIYEOKSIOS + 0x8294: 0xAD71, //HANGUL SYLLABLE KIYEOK U NIEUNCIEUC + 0x8295: 0xAD72, //HANGUL SYLLABLE KIYEOK U NIEUNHIEUH + 0x8296: 0xAD77, //HANGUL SYLLABLE KIYEOK U RIEULPIEUP + 0x8297: 0xAD78, //HANGUL SYLLABLE KIYEOK U RIEULSIOS + 0x8298: 0xAD79, //HANGUL SYLLABLE KIYEOK U RIEULTHIEUTH + 0x8299: 0xAD7A, //HANGUL SYLLABLE KIYEOK U RIEULPHIEUPH + 0x829A: 0xAD7E, //HANGUL SYLLABLE KIYEOK U PIEUPSIOS + 0x829B: 0xAD80, //HANGUL SYLLABLE KIYEOK U SSANGSIOS + 0x829C: 0xAD83, //HANGUL SYLLABLE KIYEOK U CHIEUCH + 0x829D: 0xAD84, //HANGUL SYLLABLE KIYEOK U KHIEUKH + 0x829E: 0xAD85, //HANGUL SYLLABLE KIYEOK U THIEUTH + 0x829F: 0xAD86, //HANGUL SYLLABLE KIYEOK U PHIEUPH + 0x82A0: 0xAD87, //HANGUL SYLLABLE KIYEOK U HIEUH + 0x82A1: 0xAD8A, //HANGUL SYLLABLE KIYEOK WEO SSANGKIYEOK + 0x82A2: 0xAD8B, //HANGUL SYLLABLE KIYEOK WEO KIYEOKSIOS + 0x82A3: 0xAD8D, //HANGUL SYLLABLE KIYEOK WEO NIEUNCIEUC + 0x82A4: 0xAD8E, //HANGUL SYLLABLE KIYEOK WEO NIEUNHIEUH + 0x82A5: 0xAD8F, //HANGUL SYLLABLE KIYEOK WEO TIKEUT + 0x82A6: 0xAD91, //HANGUL SYLLABLE KIYEOK WEO RIEULKIYEOK + 0x82A7: 0xAD92, //HANGUL SYLLABLE KIYEOK WEO RIEULMIEUM + 0x82A8: 0xAD93, //HANGUL SYLLABLE KIYEOK WEO RIEULPIEUP + 0x82A9: 0xAD94, //HANGUL SYLLABLE KIYEOK WEO RIEULSIOS + 0x82AA: 0xAD95, //HANGUL SYLLABLE KIYEOK WEO RIEULTHIEUTH + 0x82AB: 0xAD96, //HANGUL SYLLABLE KIYEOK WEO RIEULPHIEUPH + 0x82AC: 0xAD97, //HANGUL SYLLABLE KIYEOK WEO RIEULHIEUH + 0x82AD: 0xAD98, //HANGUL SYLLABLE KIYEOK WEO MIEUM + 0x82AE: 0xAD99, //HANGUL SYLLABLE KIYEOK WEO PIEUP + 0x82AF: 0xAD9A, //HANGUL SYLLABLE KIYEOK WEO PIEUPSIOS + 0x82B0: 0xAD9B, //HANGUL SYLLABLE KIYEOK WEO SIOS + 0x82B1: 0xAD9E, //HANGUL SYLLABLE KIYEOK WEO CIEUC + 0x82B2: 0xAD9F, //HANGUL SYLLABLE KIYEOK WEO CHIEUCH + 0x82B3: 0xADA0, //HANGUL SYLLABLE KIYEOK WEO KHIEUKH + 0x82B4: 0xADA1, //HANGUL SYLLABLE KIYEOK WEO THIEUTH + 0x82B5: 0xADA2, //HANGUL SYLLABLE KIYEOK WEO PHIEUPH + 0x82B6: 0xADA3, //HANGUL SYLLABLE KIYEOK WEO HIEUH + 0x82B7: 0xADA5, //HANGUL SYLLABLE KIYEOK WE KIYEOK + 0x82B8: 0xADA6, //HANGUL SYLLABLE KIYEOK WE SSANGKIYEOK + 0x82B9: 0xADA7, //HANGUL SYLLABLE KIYEOK WE KIYEOKSIOS + 0x82BA: 0xADA8, //HANGUL SYLLABLE KIYEOK WE NIEUN + 0x82BB: 0xADA9, //HANGUL SYLLABLE KIYEOK WE NIEUNCIEUC + 0x82BC: 0xADAA, //HANGUL SYLLABLE KIYEOK WE NIEUNHIEUH + 0x82BD: 0xADAB, //HANGUL SYLLABLE KIYEOK WE TIKEUT + 0x82BE: 0xADAC, //HANGUL SYLLABLE KIYEOK WE RIEUL + 0x82BF: 0xADAD, //HANGUL SYLLABLE KIYEOK WE RIEULKIYEOK + 0x82C0: 0xADAE, //HANGUL SYLLABLE KIYEOK WE RIEULMIEUM + 0x82C1: 0xADAF, //HANGUL SYLLABLE KIYEOK WE RIEULPIEUP + 0x82C2: 0xADB0, //HANGUL SYLLABLE KIYEOK WE RIEULSIOS + 0x82C3: 0xADB1, //HANGUL SYLLABLE KIYEOK WE RIEULTHIEUTH + 0x82C4: 0xADB2, //HANGUL SYLLABLE KIYEOK WE RIEULPHIEUPH + 0x82C5: 0xADB3, //HANGUL SYLLABLE KIYEOK WE RIEULHIEUH + 0x82C6: 0xADB4, //HANGUL SYLLABLE KIYEOK WE MIEUM + 0x82C7: 0xADB5, //HANGUL SYLLABLE KIYEOK WE PIEUP + 0x82C8: 0xADB6, //HANGUL SYLLABLE KIYEOK WE PIEUPSIOS + 0x82C9: 0xADB8, //HANGUL SYLLABLE KIYEOK WE SSANGSIOS + 0x82CA: 0xADB9, //HANGUL SYLLABLE KIYEOK WE IEUNG + 0x82CB: 0xADBA, //HANGUL SYLLABLE KIYEOK WE CIEUC + 0x82CC: 0xADBB, //HANGUL SYLLABLE KIYEOK WE CHIEUCH + 0x82CD: 0xADBC, //HANGUL SYLLABLE KIYEOK WE KHIEUKH + 0x82CE: 0xADBD, //HANGUL SYLLABLE KIYEOK WE THIEUTH + 0x82CF: 0xADBE, //HANGUL SYLLABLE KIYEOK WE PHIEUPH + 0x82D0: 0xADBF, //HANGUL SYLLABLE KIYEOK WE HIEUH + 0x82D1: 0xADC2, //HANGUL SYLLABLE KIYEOK WI SSANGKIYEOK + 0x82D2: 0xADC3, //HANGUL SYLLABLE KIYEOK WI KIYEOKSIOS + 0x82D3: 0xADC5, //HANGUL SYLLABLE KIYEOK WI NIEUNCIEUC + 0x82D4: 0xADC6, //HANGUL SYLLABLE KIYEOK WI NIEUNHIEUH + 0x82D5: 0xADC7, //HANGUL SYLLABLE KIYEOK WI TIKEUT + 0x82D6: 0xADC9, //HANGUL SYLLABLE KIYEOK WI RIEULKIYEOK + 0x82D7: 0xADCA, //HANGUL SYLLABLE KIYEOK WI RIEULMIEUM + 0x82D8: 0xADCB, //HANGUL SYLLABLE KIYEOK WI RIEULPIEUP + 0x82D9: 0xADCC, //HANGUL SYLLABLE KIYEOK WI RIEULSIOS + 0x82DA: 0xADCD, //HANGUL SYLLABLE KIYEOK WI RIEULTHIEUTH + 0x82DB: 0xADCE, //HANGUL SYLLABLE KIYEOK WI RIEULPHIEUPH + 0x82DC: 0xADCF, //HANGUL SYLLABLE KIYEOK WI RIEULHIEUH + 0x82DD: 0xADD2, //HANGUL SYLLABLE KIYEOK WI PIEUPSIOS + 0x82DE: 0xADD4, //HANGUL SYLLABLE KIYEOK WI SSANGSIOS + 0x82DF: 0xADD5, //HANGUL SYLLABLE KIYEOK WI IEUNG + 0x82E0: 0xADD6, //HANGUL SYLLABLE KIYEOK WI CIEUC + 0x82E1: 0xADD7, //HANGUL SYLLABLE KIYEOK WI CHIEUCH + 0x82E2: 0xADD8, //HANGUL SYLLABLE KIYEOK WI KHIEUKH + 0x82E3: 0xADD9, //HANGUL SYLLABLE KIYEOK WI THIEUTH + 0x82E4: 0xADDA, //HANGUL SYLLABLE KIYEOK WI PHIEUPH + 0x82E5: 0xADDB, //HANGUL SYLLABLE KIYEOK WI HIEUH + 0x82E6: 0xADDD, //HANGUL SYLLABLE KIYEOK YU KIYEOK + 0x82E7: 0xADDE, //HANGUL SYLLABLE KIYEOK YU SSANGKIYEOK + 0x82E8: 0xADDF, //HANGUL SYLLABLE KIYEOK YU KIYEOKSIOS + 0x82E9: 0xADE1, //HANGUL SYLLABLE KIYEOK YU NIEUNCIEUC + 0x82EA: 0xADE2, //HANGUL SYLLABLE KIYEOK YU NIEUNHIEUH + 0x82EB: 0xADE3, //HANGUL SYLLABLE KIYEOK YU TIKEUT + 0x82EC: 0xADE5, //HANGUL SYLLABLE KIYEOK YU RIEULKIYEOK + 0x82ED: 0xADE6, //HANGUL SYLLABLE KIYEOK YU RIEULMIEUM + 0x82EE: 0xADE7, //HANGUL SYLLABLE KIYEOK YU RIEULPIEUP + 0x82EF: 0xADE8, //HANGUL SYLLABLE KIYEOK YU RIEULSIOS + 0x82F0: 0xADE9, //HANGUL SYLLABLE KIYEOK YU RIEULTHIEUTH + 0x82F1: 0xADEA, //HANGUL SYLLABLE KIYEOK YU RIEULPHIEUPH + 0x82F2: 0xADEB, //HANGUL SYLLABLE KIYEOK YU RIEULHIEUH + 0x82F3: 0xADEC, //HANGUL SYLLABLE KIYEOK YU MIEUM + 0x82F4: 0xADED, //HANGUL SYLLABLE KIYEOK YU PIEUP + 0x82F5: 0xADEE, //HANGUL SYLLABLE KIYEOK YU PIEUPSIOS + 0x82F6: 0xADEF, //HANGUL SYLLABLE KIYEOK YU SIOS + 0x82F7: 0xADF0, //HANGUL SYLLABLE KIYEOK YU SSANGSIOS + 0x82F8: 0xADF1, //HANGUL SYLLABLE KIYEOK YU IEUNG + 0x82F9: 0xADF2, //HANGUL SYLLABLE KIYEOK YU CIEUC + 0x82FA: 0xADF3, //HANGUL SYLLABLE KIYEOK YU CHIEUCH + 0x82FB: 0xADF4, //HANGUL SYLLABLE KIYEOK YU KHIEUKH + 0x82FC: 0xADF5, //HANGUL SYLLABLE KIYEOK YU THIEUTH + 0x82FD: 0xADF6, //HANGUL SYLLABLE KIYEOK YU PHIEUPH + 0x82FE: 0xADF7, //HANGUL SYLLABLE KIYEOK YU HIEUH + 0x8341: 0xADFA, //HANGUL SYLLABLE KIYEOK EU SSANGKIYEOK + 0x8342: 0xADFB, //HANGUL SYLLABLE KIYEOK EU KIYEOKSIOS + 0x8343: 0xADFD, //HANGUL SYLLABLE KIYEOK EU NIEUNCIEUC + 0x8344: 0xADFE, //HANGUL SYLLABLE KIYEOK EU NIEUNHIEUH + 0x8345: 0xAE02, //HANGUL SYLLABLE KIYEOK EU RIEULMIEUM + 0x8346: 0xAE03, //HANGUL SYLLABLE KIYEOK EU RIEULPIEUP + 0x8347: 0xAE04, //HANGUL SYLLABLE KIYEOK EU RIEULSIOS + 0x8348: 0xAE05, //HANGUL SYLLABLE KIYEOK EU RIEULTHIEUTH + 0x8349: 0xAE06, //HANGUL SYLLABLE KIYEOK EU RIEULPHIEUPH + 0x834A: 0xAE07, //HANGUL SYLLABLE KIYEOK EU RIEULHIEUH + 0x834B: 0xAE0A, //HANGUL SYLLABLE KIYEOK EU PIEUPSIOS + 0x834C: 0xAE0C, //HANGUL SYLLABLE KIYEOK EU SSANGSIOS + 0x834D: 0xAE0E, //HANGUL SYLLABLE KIYEOK EU CIEUC + 0x834E: 0xAE0F, //HANGUL SYLLABLE KIYEOK EU CHIEUCH + 0x834F: 0xAE10, //HANGUL SYLLABLE KIYEOK EU KHIEUKH + 0x8350: 0xAE11, //HANGUL SYLLABLE KIYEOK EU THIEUTH + 0x8351: 0xAE12, //HANGUL SYLLABLE KIYEOK EU PHIEUPH + 0x8352: 0xAE13, //HANGUL SYLLABLE KIYEOK EU HIEUH + 0x8353: 0xAE15, //HANGUL SYLLABLE KIYEOK YI KIYEOK + 0x8354: 0xAE16, //HANGUL SYLLABLE KIYEOK YI SSANGKIYEOK + 0x8355: 0xAE17, //HANGUL SYLLABLE KIYEOK YI KIYEOKSIOS + 0x8356: 0xAE18, //HANGUL SYLLABLE KIYEOK YI NIEUN + 0x8357: 0xAE19, //HANGUL SYLLABLE KIYEOK YI NIEUNCIEUC + 0x8358: 0xAE1A, //HANGUL SYLLABLE KIYEOK YI NIEUNHIEUH + 0x8359: 0xAE1B, //HANGUL SYLLABLE KIYEOK YI TIKEUT + 0x835A: 0xAE1C, //HANGUL SYLLABLE KIYEOK YI RIEUL + 0x8361: 0xAE1D, //HANGUL SYLLABLE KIYEOK YI RIEULKIYEOK + 0x8362: 0xAE1E, //HANGUL SYLLABLE KIYEOK YI RIEULMIEUM + 0x8363: 0xAE1F, //HANGUL SYLLABLE KIYEOK YI RIEULPIEUP + 0x8364: 0xAE20, //HANGUL SYLLABLE KIYEOK YI RIEULSIOS + 0x8365: 0xAE21, //HANGUL SYLLABLE KIYEOK YI RIEULTHIEUTH + 0x8366: 0xAE22, //HANGUL SYLLABLE KIYEOK YI RIEULPHIEUPH + 0x8367: 0xAE23, //HANGUL SYLLABLE KIYEOK YI RIEULHIEUH + 0x8368: 0xAE24, //HANGUL SYLLABLE KIYEOK YI MIEUM + 0x8369: 0xAE25, //HANGUL SYLLABLE KIYEOK YI PIEUP + 0x836A: 0xAE26, //HANGUL SYLLABLE KIYEOK YI PIEUPSIOS + 0x836B: 0xAE27, //HANGUL SYLLABLE KIYEOK YI SIOS + 0x836C: 0xAE28, //HANGUL SYLLABLE KIYEOK YI SSANGSIOS + 0x836D: 0xAE29, //HANGUL SYLLABLE KIYEOK YI IEUNG + 0x836E: 0xAE2A, //HANGUL SYLLABLE KIYEOK YI CIEUC + 0x836F: 0xAE2B, //HANGUL SYLLABLE KIYEOK YI CHIEUCH + 0x8370: 0xAE2C, //HANGUL SYLLABLE KIYEOK YI KHIEUKH + 0x8371: 0xAE2D, //HANGUL SYLLABLE KIYEOK YI THIEUTH + 0x8372: 0xAE2E, //HANGUL SYLLABLE KIYEOK YI PHIEUPH + 0x8373: 0xAE2F, //HANGUL SYLLABLE KIYEOK YI HIEUH + 0x8374: 0xAE32, //HANGUL SYLLABLE KIYEOK I SSANGKIYEOK + 0x8375: 0xAE33, //HANGUL SYLLABLE KIYEOK I KIYEOKSIOS + 0x8376: 0xAE35, //HANGUL SYLLABLE KIYEOK I NIEUNCIEUC + 0x8377: 0xAE36, //HANGUL SYLLABLE KIYEOK I NIEUNHIEUH + 0x8378: 0xAE39, //HANGUL SYLLABLE KIYEOK I RIEULKIYEOK + 0x8379: 0xAE3B, //HANGUL SYLLABLE KIYEOK I RIEULPIEUP + 0x837A: 0xAE3C, //HANGUL SYLLABLE KIYEOK I RIEULSIOS + 0x8381: 0xAE3D, //HANGUL SYLLABLE KIYEOK I RIEULTHIEUTH + 0x8382: 0xAE3E, //HANGUL SYLLABLE KIYEOK I RIEULPHIEUPH + 0x8383: 0xAE3F, //HANGUL SYLLABLE KIYEOK I RIEULHIEUH + 0x8384: 0xAE42, //HANGUL SYLLABLE KIYEOK I PIEUPSIOS + 0x8385: 0xAE44, //HANGUL SYLLABLE KIYEOK I SSANGSIOS + 0x8386: 0xAE47, //HANGUL SYLLABLE KIYEOK I CHIEUCH + 0x8387: 0xAE48, //HANGUL SYLLABLE KIYEOK I KHIEUKH + 0x8388: 0xAE49, //HANGUL SYLLABLE KIYEOK I THIEUTH + 0x8389: 0xAE4B, //HANGUL SYLLABLE KIYEOK I HIEUH + 0x838A: 0xAE4F, //HANGUL SYLLABLE SSANGKIYEOK A KIYEOKSIOS + 0x838B: 0xAE51, //HANGUL SYLLABLE SSANGKIYEOK A NIEUNCIEUC + 0x838C: 0xAE52, //HANGUL SYLLABLE SSANGKIYEOK A NIEUNHIEUH + 0x838D: 0xAE53, //HANGUL SYLLABLE SSANGKIYEOK A TIKEUT + 0x838E: 0xAE55, //HANGUL SYLLABLE SSANGKIYEOK A RIEULKIYEOK + 0x838F: 0xAE57, //HANGUL SYLLABLE SSANGKIYEOK A RIEULPIEUP + 0x8390: 0xAE58, //HANGUL SYLLABLE SSANGKIYEOK A RIEULSIOS + 0x8391: 0xAE59, //HANGUL SYLLABLE SSANGKIYEOK A RIEULTHIEUTH + 0x8392: 0xAE5A, //HANGUL SYLLABLE SSANGKIYEOK A RIEULPHIEUPH + 0x8393: 0xAE5B, //HANGUL SYLLABLE SSANGKIYEOK A RIEULHIEUH + 0x8394: 0xAE5E, //HANGUL SYLLABLE SSANGKIYEOK A PIEUPSIOS + 0x8395: 0xAE62, //HANGUL SYLLABLE SSANGKIYEOK A CIEUC + 0x8396: 0xAE63, //HANGUL SYLLABLE SSANGKIYEOK A CHIEUCH + 0x8397: 0xAE64, //HANGUL SYLLABLE SSANGKIYEOK A KHIEUKH + 0x8398: 0xAE66, //HANGUL SYLLABLE SSANGKIYEOK A PHIEUPH + 0x8399: 0xAE67, //HANGUL SYLLABLE SSANGKIYEOK A HIEUH + 0x839A: 0xAE6A, //HANGUL SYLLABLE SSANGKIYEOK AE SSANGKIYEOK + 0x839B: 0xAE6B, //HANGUL SYLLABLE SSANGKIYEOK AE KIYEOKSIOS + 0x839C: 0xAE6D, //HANGUL SYLLABLE SSANGKIYEOK AE NIEUNCIEUC + 0x839D: 0xAE6E, //HANGUL SYLLABLE SSANGKIYEOK AE NIEUNHIEUH + 0x839E: 0xAE6F, //HANGUL SYLLABLE SSANGKIYEOK AE TIKEUT + 0x839F: 0xAE71, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULKIYEOK + 0x83A0: 0xAE72, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULMIEUM + 0x83A1: 0xAE73, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULPIEUP + 0x83A2: 0xAE74, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULSIOS + 0x83A3: 0xAE75, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULTHIEUTH + 0x83A4: 0xAE76, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULPHIEUPH + 0x83A5: 0xAE77, //HANGUL SYLLABLE SSANGKIYEOK AE RIEULHIEUH + 0x83A6: 0xAE7A, //HANGUL SYLLABLE SSANGKIYEOK AE PIEUPSIOS + 0x83A7: 0xAE7E, //HANGUL SYLLABLE SSANGKIYEOK AE CIEUC + 0x83A8: 0xAE7F, //HANGUL SYLLABLE SSANGKIYEOK AE CHIEUCH + 0x83A9: 0xAE80, //HANGUL SYLLABLE SSANGKIYEOK AE KHIEUKH + 0x83AA: 0xAE81, //HANGUL SYLLABLE SSANGKIYEOK AE THIEUTH + 0x83AB: 0xAE82, //HANGUL SYLLABLE SSANGKIYEOK AE PHIEUPH + 0x83AC: 0xAE83, //HANGUL SYLLABLE SSANGKIYEOK AE HIEUH + 0x83AD: 0xAE86, //HANGUL SYLLABLE SSANGKIYEOK YA SSANGKIYEOK + 0x83AE: 0xAE87, //HANGUL SYLLABLE SSANGKIYEOK YA KIYEOKSIOS + 0x83AF: 0xAE88, //HANGUL SYLLABLE SSANGKIYEOK YA NIEUN + 0x83B0: 0xAE89, //HANGUL SYLLABLE SSANGKIYEOK YA NIEUNCIEUC + 0x83B1: 0xAE8A, //HANGUL SYLLABLE SSANGKIYEOK YA NIEUNHIEUH + 0x83B2: 0xAE8B, //HANGUL SYLLABLE SSANGKIYEOK YA TIKEUT + 0x83B3: 0xAE8D, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULKIYEOK + 0x83B4: 0xAE8E, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULMIEUM + 0x83B5: 0xAE8F, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULPIEUP + 0x83B6: 0xAE90, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULSIOS + 0x83B7: 0xAE91, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULTHIEUTH + 0x83B8: 0xAE92, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULPHIEUPH + 0x83B9: 0xAE93, //HANGUL SYLLABLE SSANGKIYEOK YA RIEULHIEUH + 0x83BA: 0xAE94, //HANGUL SYLLABLE SSANGKIYEOK YA MIEUM + 0x83BB: 0xAE95, //HANGUL SYLLABLE SSANGKIYEOK YA PIEUP + 0x83BC: 0xAE96, //HANGUL SYLLABLE SSANGKIYEOK YA PIEUPSIOS + 0x83BD: 0xAE97, //HANGUL SYLLABLE SSANGKIYEOK YA SIOS + 0x83BE: 0xAE98, //HANGUL SYLLABLE SSANGKIYEOK YA SSANGSIOS + 0x83BF: 0xAE99, //HANGUL SYLLABLE SSANGKIYEOK YA IEUNG + 0x83C0: 0xAE9A, //HANGUL SYLLABLE SSANGKIYEOK YA CIEUC + 0x83C1: 0xAE9B, //HANGUL SYLLABLE SSANGKIYEOK YA CHIEUCH + 0x83C2: 0xAE9C, //HANGUL SYLLABLE SSANGKIYEOK YA KHIEUKH + 0x83C3: 0xAE9D, //HANGUL SYLLABLE SSANGKIYEOK YA THIEUTH + 0x83C4: 0xAE9E, //HANGUL SYLLABLE SSANGKIYEOK YA PHIEUPH + 0x83C5: 0xAE9F, //HANGUL SYLLABLE SSANGKIYEOK YA HIEUH + 0x83C6: 0xAEA0, //HANGUL SYLLABLE SSANGKIYEOK YAE + 0x83C7: 0xAEA1, //HANGUL SYLLABLE SSANGKIYEOK YAE KIYEOK + 0x83C8: 0xAEA2, //HANGUL SYLLABLE SSANGKIYEOK YAE SSANGKIYEOK + 0x83C9: 0xAEA3, //HANGUL SYLLABLE SSANGKIYEOK YAE KIYEOKSIOS + 0x83CA: 0xAEA4, //HANGUL SYLLABLE SSANGKIYEOK YAE NIEUN + 0x83CB: 0xAEA5, //HANGUL SYLLABLE SSANGKIYEOK YAE NIEUNCIEUC + 0x83CC: 0xAEA6, //HANGUL SYLLABLE SSANGKIYEOK YAE NIEUNHIEUH + 0x83CD: 0xAEA7, //HANGUL SYLLABLE SSANGKIYEOK YAE TIKEUT + 0x83CE: 0xAEA8, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEUL + 0x83CF: 0xAEA9, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULKIYEOK + 0x83D0: 0xAEAA, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULMIEUM + 0x83D1: 0xAEAB, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULPIEUP + 0x83D2: 0xAEAC, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULSIOS + 0x83D3: 0xAEAD, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULTHIEUTH + 0x83D4: 0xAEAE, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULPHIEUPH + 0x83D5: 0xAEAF, //HANGUL SYLLABLE SSANGKIYEOK YAE RIEULHIEUH + 0x83D6: 0xAEB0, //HANGUL SYLLABLE SSANGKIYEOK YAE MIEUM + 0x83D7: 0xAEB1, //HANGUL SYLLABLE SSANGKIYEOK YAE PIEUP + 0x83D8: 0xAEB2, //HANGUL SYLLABLE SSANGKIYEOK YAE PIEUPSIOS + 0x83D9: 0xAEB3, //HANGUL SYLLABLE SSANGKIYEOK YAE SIOS + 0x83DA: 0xAEB4, //HANGUL SYLLABLE SSANGKIYEOK YAE SSANGSIOS + 0x83DB: 0xAEB5, //HANGUL SYLLABLE SSANGKIYEOK YAE IEUNG + 0x83DC: 0xAEB6, //HANGUL SYLLABLE SSANGKIYEOK YAE CIEUC + 0x83DD: 0xAEB7, //HANGUL SYLLABLE SSANGKIYEOK YAE CHIEUCH + 0x83DE: 0xAEB8, //HANGUL SYLLABLE SSANGKIYEOK YAE KHIEUKH + 0x83DF: 0xAEB9, //HANGUL SYLLABLE SSANGKIYEOK YAE THIEUTH + 0x83E0: 0xAEBA, //HANGUL SYLLABLE SSANGKIYEOK YAE PHIEUPH + 0x83E1: 0xAEBB, //HANGUL SYLLABLE SSANGKIYEOK YAE HIEUH + 0x83E2: 0xAEBF, //HANGUL SYLLABLE SSANGKIYEOK EO KIYEOKSIOS + 0x83E3: 0xAEC1, //HANGUL SYLLABLE SSANGKIYEOK EO NIEUNCIEUC + 0x83E4: 0xAEC2, //HANGUL SYLLABLE SSANGKIYEOK EO NIEUNHIEUH + 0x83E5: 0xAEC3, //HANGUL SYLLABLE SSANGKIYEOK EO TIKEUT + 0x83E6: 0xAEC5, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULKIYEOK + 0x83E7: 0xAEC6, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULMIEUM + 0x83E8: 0xAEC7, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULPIEUP + 0x83E9: 0xAEC8, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULSIOS + 0x83EA: 0xAEC9, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULTHIEUTH + 0x83EB: 0xAECA, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULPHIEUPH + 0x83EC: 0xAECB, //HANGUL SYLLABLE SSANGKIYEOK EO RIEULHIEUH + 0x83ED: 0xAECE, //HANGUL SYLLABLE SSANGKIYEOK EO PIEUPSIOS + 0x83EE: 0xAED2, //HANGUL SYLLABLE SSANGKIYEOK EO CIEUC + 0x83EF: 0xAED3, //HANGUL SYLLABLE SSANGKIYEOK EO CHIEUCH + 0x83F0: 0xAED4, //HANGUL SYLLABLE SSANGKIYEOK EO KHIEUKH + 0x83F1: 0xAED5, //HANGUL SYLLABLE SSANGKIYEOK EO THIEUTH + 0x83F2: 0xAED6, //HANGUL SYLLABLE SSANGKIYEOK EO PHIEUPH + 0x83F3: 0xAED7, //HANGUL SYLLABLE SSANGKIYEOK EO HIEUH + 0x83F4: 0xAEDA, //HANGUL SYLLABLE SSANGKIYEOK E SSANGKIYEOK + 0x83F5: 0xAEDB, //HANGUL SYLLABLE SSANGKIYEOK E KIYEOKSIOS + 0x83F6: 0xAEDD, //HANGUL SYLLABLE SSANGKIYEOK E NIEUNCIEUC + 0x83F7: 0xAEDE, //HANGUL SYLLABLE SSANGKIYEOK E NIEUNHIEUH + 0x83F8: 0xAEDF, //HANGUL SYLLABLE SSANGKIYEOK E TIKEUT + 0x83F9: 0xAEE0, //HANGUL SYLLABLE SSANGKIYEOK E RIEUL + 0x83FA: 0xAEE1, //HANGUL SYLLABLE SSANGKIYEOK E RIEULKIYEOK + 0x83FB: 0xAEE2, //HANGUL SYLLABLE SSANGKIYEOK E RIEULMIEUM + 0x83FC: 0xAEE3, //HANGUL SYLLABLE SSANGKIYEOK E RIEULPIEUP + 0x83FD: 0xAEE4, //HANGUL SYLLABLE SSANGKIYEOK E RIEULSIOS + 0x83FE: 0xAEE5, //HANGUL SYLLABLE SSANGKIYEOK E RIEULTHIEUTH + 0x8441: 0xAEE6, //HANGUL SYLLABLE SSANGKIYEOK E RIEULPHIEUPH + 0x8442: 0xAEE7, //HANGUL SYLLABLE SSANGKIYEOK E RIEULHIEUH + 0x8443: 0xAEE9, //HANGUL SYLLABLE SSANGKIYEOK E PIEUP + 0x8444: 0xAEEA, //HANGUL SYLLABLE SSANGKIYEOK E PIEUPSIOS + 0x8445: 0xAEEC, //HANGUL SYLLABLE SSANGKIYEOK E SSANGSIOS + 0x8446: 0xAEEE, //HANGUL SYLLABLE SSANGKIYEOK E CIEUC + 0x8447: 0xAEEF, //HANGUL SYLLABLE SSANGKIYEOK E CHIEUCH + 0x8448: 0xAEF0, //HANGUL SYLLABLE SSANGKIYEOK E KHIEUKH + 0x8449: 0xAEF1, //HANGUL SYLLABLE SSANGKIYEOK E THIEUTH + 0x844A: 0xAEF2, //HANGUL SYLLABLE SSANGKIYEOK E PHIEUPH + 0x844B: 0xAEF3, //HANGUL SYLLABLE SSANGKIYEOK E HIEUH + 0x844C: 0xAEF5, //HANGUL SYLLABLE SSANGKIYEOK YEO KIYEOK + 0x844D: 0xAEF6, //HANGUL SYLLABLE SSANGKIYEOK YEO SSANGKIYEOK + 0x844E: 0xAEF7, //HANGUL SYLLABLE SSANGKIYEOK YEO KIYEOKSIOS + 0x844F: 0xAEF9, //HANGUL SYLLABLE SSANGKIYEOK YEO NIEUNCIEUC + 0x8450: 0xAEFA, //HANGUL SYLLABLE SSANGKIYEOK YEO NIEUNHIEUH + 0x8451: 0xAEFB, //HANGUL SYLLABLE SSANGKIYEOK YEO TIKEUT + 0x8452: 0xAEFD, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULKIYEOK + 0x8453: 0xAEFE, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULMIEUM + 0x8454: 0xAEFF, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULPIEUP + 0x8455: 0xAF00, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULSIOS + 0x8456: 0xAF01, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULTHIEUTH + 0x8457: 0xAF02, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULPHIEUPH + 0x8458: 0xAF03, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEULHIEUH + 0x8459: 0xAF04, //HANGUL SYLLABLE SSANGKIYEOK YEO MIEUM + 0x845A: 0xAF05, //HANGUL SYLLABLE SSANGKIYEOK YEO PIEUP + 0x8461: 0xAF06, //HANGUL SYLLABLE SSANGKIYEOK YEO PIEUPSIOS + 0x8462: 0xAF09, //HANGUL SYLLABLE SSANGKIYEOK YEO IEUNG + 0x8463: 0xAF0A, //HANGUL SYLLABLE SSANGKIYEOK YEO CIEUC + 0x8464: 0xAF0B, //HANGUL SYLLABLE SSANGKIYEOK YEO CHIEUCH + 0x8465: 0xAF0C, //HANGUL SYLLABLE SSANGKIYEOK YEO KHIEUKH + 0x8466: 0xAF0E, //HANGUL SYLLABLE SSANGKIYEOK YEO PHIEUPH + 0x8467: 0xAF0F, //HANGUL SYLLABLE SSANGKIYEOK YEO HIEUH + 0x8468: 0xAF11, //HANGUL SYLLABLE SSANGKIYEOK YE KIYEOK + 0x8469: 0xAF12, //HANGUL SYLLABLE SSANGKIYEOK YE SSANGKIYEOK + 0x846A: 0xAF13, //HANGUL SYLLABLE SSANGKIYEOK YE KIYEOKSIOS + 0x846B: 0xAF14, //HANGUL SYLLABLE SSANGKIYEOK YE NIEUN + 0x846C: 0xAF15, //HANGUL SYLLABLE SSANGKIYEOK YE NIEUNCIEUC + 0x846D: 0xAF16, //HANGUL SYLLABLE SSANGKIYEOK YE NIEUNHIEUH + 0x846E: 0xAF17, //HANGUL SYLLABLE SSANGKIYEOK YE TIKEUT + 0x846F: 0xAF18, //HANGUL SYLLABLE SSANGKIYEOK YE RIEUL + 0x8470: 0xAF19, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULKIYEOK + 0x8471: 0xAF1A, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULMIEUM + 0x8472: 0xAF1B, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULPIEUP + 0x8473: 0xAF1C, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULSIOS + 0x8474: 0xAF1D, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULTHIEUTH + 0x8475: 0xAF1E, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULPHIEUPH + 0x8476: 0xAF1F, //HANGUL SYLLABLE SSANGKIYEOK YE RIEULHIEUH + 0x8477: 0xAF20, //HANGUL SYLLABLE SSANGKIYEOK YE MIEUM + 0x8478: 0xAF21, //HANGUL SYLLABLE SSANGKIYEOK YE PIEUP + 0x8479: 0xAF22, //HANGUL SYLLABLE SSANGKIYEOK YE PIEUPSIOS + 0x847A: 0xAF23, //HANGUL SYLLABLE SSANGKIYEOK YE SIOS + 0x8481: 0xAF24, //HANGUL SYLLABLE SSANGKIYEOK YE SSANGSIOS + 0x8482: 0xAF25, //HANGUL SYLLABLE SSANGKIYEOK YE IEUNG + 0x8483: 0xAF26, //HANGUL SYLLABLE SSANGKIYEOK YE CIEUC + 0x8484: 0xAF27, //HANGUL SYLLABLE SSANGKIYEOK YE CHIEUCH + 0x8485: 0xAF28, //HANGUL SYLLABLE SSANGKIYEOK YE KHIEUKH + 0x8486: 0xAF29, //HANGUL SYLLABLE SSANGKIYEOK YE THIEUTH + 0x8487: 0xAF2A, //HANGUL SYLLABLE SSANGKIYEOK YE PHIEUPH + 0x8488: 0xAF2B, //HANGUL SYLLABLE SSANGKIYEOK YE HIEUH + 0x8489: 0xAF2E, //HANGUL SYLLABLE SSANGKIYEOK O SSANGKIYEOK + 0x848A: 0xAF2F, //HANGUL SYLLABLE SSANGKIYEOK O KIYEOKSIOS + 0x848B: 0xAF31, //HANGUL SYLLABLE SSANGKIYEOK O NIEUNCIEUC + 0x848C: 0xAF33, //HANGUL SYLLABLE SSANGKIYEOK O TIKEUT + 0x848D: 0xAF35, //HANGUL SYLLABLE SSANGKIYEOK O RIEULKIYEOK + 0x848E: 0xAF36, //HANGUL SYLLABLE SSANGKIYEOK O RIEULMIEUM + 0x848F: 0xAF37, //HANGUL SYLLABLE SSANGKIYEOK O RIEULPIEUP + 0x8490: 0xAF38, //HANGUL SYLLABLE SSANGKIYEOK O RIEULSIOS + 0x8491: 0xAF39, //HANGUL SYLLABLE SSANGKIYEOK O RIEULTHIEUTH + 0x8492: 0xAF3A, //HANGUL SYLLABLE SSANGKIYEOK O RIEULPHIEUPH + 0x8493: 0xAF3B, //HANGUL SYLLABLE SSANGKIYEOK O RIEULHIEUH + 0x8494: 0xAF3E, //HANGUL SYLLABLE SSANGKIYEOK O PIEUPSIOS + 0x8495: 0xAF40, //HANGUL SYLLABLE SSANGKIYEOK O SSANGSIOS + 0x8496: 0xAF44, //HANGUL SYLLABLE SSANGKIYEOK O KHIEUKH + 0x8497: 0xAF45, //HANGUL SYLLABLE SSANGKIYEOK O THIEUTH + 0x8498: 0xAF46, //HANGUL SYLLABLE SSANGKIYEOK O PHIEUPH + 0x8499: 0xAF47, //HANGUL SYLLABLE SSANGKIYEOK O HIEUH + 0x849A: 0xAF4A, //HANGUL SYLLABLE SSANGKIYEOK WA SSANGKIYEOK + 0x849B: 0xAF4B, //HANGUL SYLLABLE SSANGKIYEOK WA KIYEOKSIOS + 0x849C: 0xAF4C, //HANGUL SYLLABLE SSANGKIYEOK WA NIEUN + 0x849D: 0xAF4D, //HANGUL SYLLABLE SSANGKIYEOK WA NIEUNCIEUC + 0x849E: 0xAF4E, //HANGUL SYLLABLE SSANGKIYEOK WA NIEUNHIEUH + 0x849F: 0xAF4F, //HANGUL SYLLABLE SSANGKIYEOK WA TIKEUT + 0x84A0: 0xAF51, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULKIYEOK + 0x84A1: 0xAF52, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULMIEUM + 0x84A2: 0xAF53, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULPIEUP + 0x84A3: 0xAF54, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULSIOS + 0x84A4: 0xAF55, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULTHIEUTH + 0x84A5: 0xAF56, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULPHIEUPH + 0x84A6: 0xAF57, //HANGUL SYLLABLE SSANGKIYEOK WA RIEULHIEUH + 0x84A7: 0xAF58, //HANGUL SYLLABLE SSANGKIYEOK WA MIEUM + 0x84A8: 0xAF59, //HANGUL SYLLABLE SSANGKIYEOK WA PIEUP + 0x84A9: 0xAF5A, //HANGUL SYLLABLE SSANGKIYEOK WA PIEUPSIOS + 0x84AA: 0xAF5B, //HANGUL SYLLABLE SSANGKIYEOK WA SIOS + 0x84AB: 0xAF5E, //HANGUL SYLLABLE SSANGKIYEOK WA CIEUC + 0x84AC: 0xAF5F, //HANGUL SYLLABLE SSANGKIYEOK WA CHIEUCH + 0x84AD: 0xAF60, //HANGUL SYLLABLE SSANGKIYEOK WA KHIEUKH + 0x84AE: 0xAF61, //HANGUL SYLLABLE SSANGKIYEOK WA THIEUTH + 0x84AF: 0xAF62, //HANGUL SYLLABLE SSANGKIYEOK WA PHIEUPH + 0x84B0: 0xAF63, //HANGUL SYLLABLE SSANGKIYEOK WA HIEUH + 0x84B1: 0xAF66, //HANGUL SYLLABLE SSANGKIYEOK WAE SSANGKIYEOK + 0x84B2: 0xAF67, //HANGUL SYLLABLE SSANGKIYEOK WAE KIYEOKSIOS + 0x84B3: 0xAF68, //HANGUL SYLLABLE SSANGKIYEOK WAE NIEUN + 0x84B4: 0xAF69, //HANGUL SYLLABLE SSANGKIYEOK WAE NIEUNCIEUC + 0x84B5: 0xAF6A, //HANGUL SYLLABLE SSANGKIYEOK WAE NIEUNHIEUH + 0x84B6: 0xAF6B, //HANGUL SYLLABLE SSANGKIYEOK WAE TIKEUT + 0x84B7: 0xAF6C, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEUL + 0x84B8: 0xAF6D, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULKIYEOK + 0x84B9: 0xAF6E, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULMIEUM + 0x84BA: 0xAF6F, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULPIEUP + 0x84BB: 0xAF70, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULSIOS + 0x84BC: 0xAF71, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULTHIEUTH + 0x84BD: 0xAF72, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULPHIEUPH + 0x84BE: 0xAF73, //HANGUL SYLLABLE SSANGKIYEOK WAE RIEULHIEUH + 0x84BF: 0xAF74, //HANGUL SYLLABLE SSANGKIYEOK WAE MIEUM + 0x84C0: 0xAF75, //HANGUL SYLLABLE SSANGKIYEOK WAE PIEUP + 0x84C1: 0xAF76, //HANGUL SYLLABLE SSANGKIYEOK WAE PIEUPSIOS + 0x84C2: 0xAF77, //HANGUL SYLLABLE SSANGKIYEOK WAE SIOS + 0x84C3: 0xAF78, //HANGUL SYLLABLE SSANGKIYEOK WAE SSANGSIOS + 0x84C4: 0xAF7A, //HANGUL SYLLABLE SSANGKIYEOK WAE CIEUC + 0x84C5: 0xAF7B, //HANGUL SYLLABLE SSANGKIYEOK WAE CHIEUCH + 0x84C6: 0xAF7C, //HANGUL SYLLABLE SSANGKIYEOK WAE KHIEUKH + 0x84C7: 0xAF7D, //HANGUL SYLLABLE SSANGKIYEOK WAE THIEUTH + 0x84C8: 0xAF7E, //HANGUL SYLLABLE SSANGKIYEOK WAE PHIEUPH + 0x84C9: 0xAF7F, //HANGUL SYLLABLE SSANGKIYEOK WAE HIEUH + 0x84CA: 0xAF81, //HANGUL SYLLABLE SSANGKIYEOK OE KIYEOK + 0x84CB: 0xAF82, //HANGUL SYLLABLE SSANGKIYEOK OE SSANGKIYEOK + 0x84CC: 0xAF83, //HANGUL SYLLABLE SSANGKIYEOK OE KIYEOKSIOS + 0x84CD: 0xAF85, //HANGUL SYLLABLE SSANGKIYEOK OE NIEUNCIEUC + 0x84CE: 0xAF86, //HANGUL SYLLABLE SSANGKIYEOK OE NIEUNHIEUH + 0x84CF: 0xAF87, //HANGUL SYLLABLE SSANGKIYEOK OE TIKEUT + 0x84D0: 0xAF89, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULKIYEOK + 0x84D1: 0xAF8A, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULMIEUM + 0x84D2: 0xAF8B, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULPIEUP + 0x84D3: 0xAF8C, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULSIOS + 0x84D4: 0xAF8D, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULTHIEUTH + 0x84D5: 0xAF8E, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULPHIEUPH + 0x84D6: 0xAF8F, //HANGUL SYLLABLE SSANGKIYEOK OE RIEULHIEUH + 0x84D7: 0xAF92, //HANGUL SYLLABLE SSANGKIYEOK OE PIEUPSIOS + 0x84D8: 0xAF93, //HANGUL SYLLABLE SSANGKIYEOK OE SIOS + 0x84D9: 0xAF94, //HANGUL SYLLABLE SSANGKIYEOK OE SSANGSIOS + 0x84DA: 0xAF96, //HANGUL SYLLABLE SSANGKIYEOK OE CIEUC + 0x84DB: 0xAF97, //HANGUL SYLLABLE SSANGKIYEOK OE CHIEUCH + 0x84DC: 0xAF98, //HANGUL SYLLABLE SSANGKIYEOK OE KHIEUKH + 0x84DD: 0xAF99, //HANGUL SYLLABLE SSANGKIYEOK OE THIEUTH + 0x84DE: 0xAF9A, //HANGUL SYLLABLE SSANGKIYEOK OE PHIEUPH + 0x84DF: 0xAF9B, //HANGUL SYLLABLE SSANGKIYEOK OE HIEUH + 0x84E0: 0xAF9D, //HANGUL SYLLABLE SSANGKIYEOK YO KIYEOK + 0x84E1: 0xAF9E, //HANGUL SYLLABLE SSANGKIYEOK YO SSANGKIYEOK + 0x84E2: 0xAF9F, //HANGUL SYLLABLE SSANGKIYEOK YO KIYEOKSIOS + 0x84E3: 0xAFA0, //HANGUL SYLLABLE SSANGKIYEOK YO NIEUN + 0x84E4: 0xAFA1, //HANGUL SYLLABLE SSANGKIYEOK YO NIEUNCIEUC + 0x84E5: 0xAFA2, //HANGUL SYLLABLE SSANGKIYEOK YO NIEUNHIEUH + 0x84E6: 0xAFA3, //HANGUL SYLLABLE SSANGKIYEOK YO TIKEUT + 0x84E7: 0xAFA4, //HANGUL SYLLABLE SSANGKIYEOK YO RIEUL + 0x84E8: 0xAFA5, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULKIYEOK + 0x84E9: 0xAFA6, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULMIEUM + 0x84EA: 0xAFA7, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULPIEUP + 0x84EB: 0xAFA8, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULSIOS + 0x84EC: 0xAFA9, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULTHIEUTH + 0x84ED: 0xAFAA, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULPHIEUPH + 0x84EE: 0xAFAB, //HANGUL SYLLABLE SSANGKIYEOK YO RIEULHIEUH + 0x84EF: 0xAFAC, //HANGUL SYLLABLE SSANGKIYEOK YO MIEUM + 0x84F0: 0xAFAD, //HANGUL SYLLABLE SSANGKIYEOK YO PIEUP + 0x84F1: 0xAFAE, //HANGUL SYLLABLE SSANGKIYEOK YO PIEUPSIOS + 0x84F2: 0xAFAF, //HANGUL SYLLABLE SSANGKIYEOK YO SIOS + 0x84F3: 0xAFB0, //HANGUL SYLLABLE SSANGKIYEOK YO SSANGSIOS + 0x84F4: 0xAFB1, //HANGUL SYLLABLE SSANGKIYEOK YO IEUNG + 0x84F5: 0xAFB2, //HANGUL SYLLABLE SSANGKIYEOK YO CIEUC + 0x84F6: 0xAFB3, //HANGUL SYLLABLE SSANGKIYEOK YO CHIEUCH + 0x84F7: 0xAFB4, //HANGUL SYLLABLE SSANGKIYEOK YO KHIEUKH + 0x84F8: 0xAFB5, //HANGUL SYLLABLE SSANGKIYEOK YO THIEUTH + 0x84F9: 0xAFB6, //HANGUL SYLLABLE SSANGKIYEOK YO PHIEUPH + 0x84FA: 0xAFB7, //HANGUL SYLLABLE SSANGKIYEOK YO HIEUH + 0x84FB: 0xAFBA, //HANGUL SYLLABLE SSANGKIYEOK U SSANGKIYEOK + 0x84FC: 0xAFBB, //HANGUL SYLLABLE SSANGKIYEOK U KIYEOKSIOS + 0x84FD: 0xAFBD, //HANGUL SYLLABLE SSANGKIYEOK U NIEUNCIEUC + 0x84FE: 0xAFBE, //HANGUL SYLLABLE SSANGKIYEOK U NIEUNHIEUH + 0x8541: 0xAFBF, //HANGUL SYLLABLE SSANGKIYEOK U TIKEUT + 0x8542: 0xAFC1, //HANGUL SYLLABLE SSANGKIYEOK U RIEULKIYEOK + 0x8543: 0xAFC2, //HANGUL SYLLABLE SSANGKIYEOK U RIEULMIEUM + 0x8544: 0xAFC3, //HANGUL SYLLABLE SSANGKIYEOK U RIEULPIEUP + 0x8545: 0xAFC4, //HANGUL SYLLABLE SSANGKIYEOK U RIEULSIOS + 0x8546: 0xAFC5, //HANGUL SYLLABLE SSANGKIYEOK U RIEULTHIEUTH + 0x8547: 0xAFC6, //HANGUL SYLLABLE SSANGKIYEOK U RIEULPHIEUPH + 0x8548: 0xAFCA, //HANGUL SYLLABLE SSANGKIYEOK U PIEUPSIOS + 0x8549: 0xAFCC, //HANGUL SYLLABLE SSANGKIYEOK U SSANGSIOS + 0x854A: 0xAFCF, //HANGUL SYLLABLE SSANGKIYEOK U CHIEUCH + 0x854B: 0xAFD0, //HANGUL SYLLABLE SSANGKIYEOK U KHIEUKH + 0x854C: 0xAFD1, //HANGUL SYLLABLE SSANGKIYEOK U THIEUTH + 0x854D: 0xAFD2, //HANGUL SYLLABLE SSANGKIYEOK U PHIEUPH + 0x854E: 0xAFD3, //HANGUL SYLLABLE SSANGKIYEOK U HIEUH + 0x854F: 0xAFD5, //HANGUL SYLLABLE SSANGKIYEOK WEO KIYEOK + 0x8550: 0xAFD6, //HANGUL SYLLABLE SSANGKIYEOK WEO SSANGKIYEOK + 0x8551: 0xAFD7, //HANGUL SYLLABLE SSANGKIYEOK WEO KIYEOKSIOS + 0x8552: 0xAFD8, //HANGUL SYLLABLE SSANGKIYEOK WEO NIEUN + 0x8553: 0xAFD9, //HANGUL SYLLABLE SSANGKIYEOK WEO NIEUNCIEUC + 0x8554: 0xAFDA, //HANGUL SYLLABLE SSANGKIYEOK WEO NIEUNHIEUH + 0x8555: 0xAFDB, //HANGUL SYLLABLE SSANGKIYEOK WEO TIKEUT + 0x8556: 0xAFDD, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULKIYEOK + 0x8557: 0xAFDE, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULMIEUM + 0x8558: 0xAFDF, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULPIEUP + 0x8559: 0xAFE0, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULSIOS + 0x855A: 0xAFE1, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULTHIEUTH + 0x8561: 0xAFE2, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULPHIEUPH + 0x8562: 0xAFE3, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEULHIEUH + 0x8563: 0xAFE4, //HANGUL SYLLABLE SSANGKIYEOK WEO MIEUM + 0x8564: 0xAFE5, //HANGUL SYLLABLE SSANGKIYEOK WEO PIEUP + 0x8565: 0xAFE6, //HANGUL SYLLABLE SSANGKIYEOK WEO PIEUPSIOS + 0x8566: 0xAFE7, //HANGUL SYLLABLE SSANGKIYEOK WEO SIOS + 0x8567: 0xAFEA, //HANGUL SYLLABLE SSANGKIYEOK WEO CIEUC + 0x8568: 0xAFEB, //HANGUL SYLLABLE SSANGKIYEOK WEO CHIEUCH + 0x8569: 0xAFEC, //HANGUL SYLLABLE SSANGKIYEOK WEO KHIEUKH + 0x856A: 0xAFED, //HANGUL SYLLABLE SSANGKIYEOK WEO THIEUTH + 0x856B: 0xAFEE, //HANGUL SYLLABLE SSANGKIYEOK WEO PHIEUPH + 0x856C: 0xAFEF, //HANGUL SYLLABLE SSANGKIYEOK WEO HIEUH + 0x856D: 0xAFF2, //HANGUL SYLLABLE SSANGKIYEOK WE SSANGKIYEOK + 0x856E: 0xAFF3, //HANGUL SYLLABLE SSANGKIYEOK WE KIYEOKSIOS + 0x856F: 0xAFF5, //HANGUL SYLLABLE SSANGKIYEOK WE NIEUNCIEUC + 0x8570: 0xAFF6, //HANGUL SYLLABLE SSANGKIYEOK WE NIEUNHIEUH + 0x8571: 0xAFF7, //HANGUL SYLLABLE SSANGKIYEOK WE TIKEUT + 0x8572: 0xAFF9, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULKIYEOK + 0x8573: 0xAFFA, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULMIEUM + 0x8574: 0xAFFB, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULPIEUP + 0x8575: 0xAFFC, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULSIOS + 0x8576: 0xAFFD, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULTHIEUTH + 0x8577: 0xAFFE, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULPHIEUPH + 0x8578: 0xAFFF, //HANGUL SYLLABLE SSANGKIYEOK WE RIEULHIEUH + 0x8579: 0xB002, //HANGUL SYLLABLE SSANGKIYEOK WE PIEUPSIOS + 0x857A: 0xB003, //HANGUL SYLLABLE SSANGKIYEOK WE SIOS + 0x8581: 0xB005, //HANGUL SYLLABLE SSANGKIYEOK WE IEUNG + 0x8582: 0xB006, //HANGUL SYLLABLE SSANGKIYEOK WE CIEUC + 0x8583: 0xB007, //HANGUL SYLLABLE SSANGKIYEOK WE CHIEUCH + 0x8584: 0xB008, //HANGUL SYLLABLE SSANGKIYEOK WE KHIEUKH + 0x8585: 0xB009, //HANGUL SYLLABLE SSANGKIYEOK WE THIEUTH + 0x8586: 0xB00A, //HANGUL SYLLABLE SSANGKIYEOK WE PHIEUPH + 0x8587: 0xB00B, //HANGUL SYLLABLE SSANGKIYEOK WE HIEUH + 0x8588: 0xB00D, //HANGUL SYLLABLE SSANGKIYEOK WI KIYEOK + 0x8589: 0xB00E, //HANGUL SYLLABLE SSANGKIYEOK WI SSANGKIYEOK + 0x858A: 0xB00F, //HANGUL SYLLABLE SSANGKIYEOK WI KIYEOKSIOS + 0x858B: 0xB011, //HANGUL SYLLABLE SSANGKIYEOK WI NIEUNCIEUC + 0x858C: 0xB012, //HANGUL SYLLABLE SSANGKIYEOK WI NIEUNHIEUH + 0x858D: 0xB013, //HANGUL SYLLABLE SSANGKIYEOK WI TIKEUT + 0x858E: 0xB015, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULKIYEOK + 0x858F: 0xB016, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULMIEUM + 0x8590: 0xB017, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULPIEUP + 0x8591: 0xB018, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULSIOS + 0x8592: 0xB019, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULTHIEUTH + 0x8593: 0xB01A, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULPHIEUPH + 0x8594: 0xB01B, //HANGUL SYLLABLE SSANGKIYEOK WI RIEULHIEUH + 0x8595: 0xB01E, //HANGUL SYLLABLE SSANGKIYEOK WI PIEUPSIOS + 0x8596: 0xB01F, //HANGUL SYLLABLE SSANGKIYEOK WI SIOS + 0x8597: 0xB020, //HANGUL SYLLABLE SSANGKIYEOK WI SSANGSIOS + 0x8598: 0xB021, //HANGUL SYLLABLE SSANGKIYEOK WI IEUNG + 0x8599: 0xB022, //HANGUL SYLLABLE SSANGKIYEOK WI CIEUC + 0x859A: 0xB023, //HANGUL SYLLABLE SSANGKIYEOK WI CHIEUCH + 0x859B: 0xB024, //HANGUL SYLLABLE SSANGKIYEOK WI KHIEUKH + 0x859C: 0xB025, //HANGUL SYLLABLE SSANGKIYEOK WI THIEUTH + 0x859D: 0xB026, //HANGUL SYLLABLE SSANGKIYEOK WI PHIEUPH + 0x859E: 0xB027, //HANGUL SYLLABLE SSANGKIYEOK WI HIEUH + 0x859F: 0xB029, //HANGUL SYLLABLE SSANGKIYEOK YU KIYEOK + 0x85A0: 0xB02A, //HANGUL SYLLABLE SSANGKIYEOK YU SSANGKIYEOK + 0x85A1: 0xB02B, //HANGUL SYLLABLE SSANGKIYEOK YU KIYEOKSIOS + 0x85A2: 0xB02C, //HANGUL SYLLABLE SSANGKIYEOK YU NIEUN + 0x85A3: 0xB02D, //HANGUL SYLLABLE SSANGKIYEOK YU NIEUNCIEUC + 0x85A4: 0xB02E, //HANGUL SYLLABLE SSANGKIYEOK YU NIEUNHIEUH + 0x85A5: 0xB02F, //HANGUL SYLLABLE SSANGKIYEOK YU TIKEUT + 0x85A6: 0xB030, //HANGUL SYLLABLE SSANGKIYEOK YU RIEUL + 0x85A7: 0xB031, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULKIYEOK + 0x85A8: 0xB032, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULMIEUM + 0x85A9: 0xB033, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULPIEUP + 0x85AA: 0xB034, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULSIOS + 0x85AB: 0xB035, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULTHIEUTH + 0x85AC: 0xB036, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULPHIEUPH + 0x85AD: 0xB037, //HANGUL SYLLABLE SSANGKIYEOK YU RIEULHIEUH + 0x85AE: 0xB038, //HANGUL SYLLABLE SSANGKIYEOK YU MIEUM + 0x85AF: 0xB039, //HANGUL SYLLABLE SSANGKIYEOK YU PIEUP + 0x85B0: 0xB03A, //HANGUL SYLLABLE SSANGKIYEOK YU PIEUPSIOS + 0x85B1: 0xB03B, //HANGUL SYLLABLE SSANGKIYEOK YU SIOS + 0x85B2: 0xB03C, //HANGUL SYLLABLE SSANGKIYEOK YU SSANGSIOS + 0x85B3: 0xB03D, //HANGUL SYLLABLE SSANGKIYEOK YU IEUNG + 0x85B4: 0xB03E, //HANGUL SYLLABLE SSANGKIYEOK YU CIEUC + 0x85B5: 0xB03F, //HANGUL SYLLABLE SSANGKIYEOK YU CHIEUCH + 0x85B6: 0xB040, //HANGUL SYLLABLE SSANGKIYEOK YU KHIEUKH + 0x85B7: 0xB041, //HANGUL SYLLABLE SSANGKIYEOK YU THIEUTH + 0x85B8: 0xB042, //HANGUL SYLLABLE SSANGKIYEOK YU PHIEUPH + 0x85B9: 0xB043, //HANGUL SYLLABLE SSANGKIYEOK YU HIEUH + 0x85BA: 0xB046, //HANGUL SYLLABLE SSANGKIYEOK EU SSANGKIYEOK + 0x85BB: 0xB047, //HANGUL SYLLABLE SSANGKIYEOK EU KIYEOKSIOS + 0x85BC: 0xB049, //HANGUL SYLLABLE SSANGKIYEOK EU NIEUNCIEUC + 0x85BD: 0xB04B, //HANGUL SYLLABLE SSANGKIYEOK EU TIKEUT + 0x85BE: 0xB04D, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULKIYEOK + 0x85BF: 0xB04F, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULPIEUP + 0x85C0: 0xB050, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULSIOS + 0x85C1: 0xB051, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULTHIEUTH + 0x85C2: 0xB052, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULPHIEUPH + 0x85C3: 0xB056, //HANGUL SYLLABLE SSANGKIYEOK EU PIEUPSIOS + 0x85C4: 0xB058, //HANGUL SYLLABLE SSANGKIYEOK EU SSANGSIOS + 0x85C5: 0xB05A, //HANGUL SYLLABLE SSANGKIYEOK EU CIEUC + 0x85C6: 0xB05B, //HANGUL SYLLABLE SSANGKIYEOK EU CHIEUCH + 0x85C7: 0xB05C, //HANGUL SYLLABLE SSANGKIYEOK EU KHIEUKH + 0x85C8: 0xB05E, //HANGUL SYLLABLE SSANGKIYEOK EU PHIEUPH + 0x85C9: 0xB05F, //HANGUL SYLLABLE SSANGKIYEOK EU HIEUH + 0x85CA: 0xB060, //HANGUL SYLLABLE SSANGKIYEOK YI + 0x85CB: 0xB061, //HANGUL SYLLABLE SSANGKIYEOK YI KIYEOK + 0x85CC: 0xB062, //HANGUL SYLLABLE SSANGKIYEOK YI SSANGKIYEOK + 0x85CD: 0xB063, //HANGUL SYLLABLE SSANGKIYEOK YI KIYEOKSIOS + 0x85CE: 0xB064, //HANGUL SYLLABLE SSANGKIYEOK YI NIEUN + 0x85CF: 0xB065, //HANGUL SYLLABLE SSANGKIYEOK YI NIEUNCIEUC + 0x85D0: 0xB066, //HANGUL SYLLABLE SSANGKIYEOK YI NIEUNHIEUH + 0x85D1: 0xB067, //HANGUL SYLLABLE SSANGKIYEOK YI TIKEUT + 0x85D2: 0xB068, //HANGUL SYLLABLE SSANGKIYEOK YI RIEUL + 0x85D3: 0xB069, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULKIYEOK + 0x85D4: 0xB06A, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULMIEUM + 0x85D5: 0xB06B, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULPIEUP + 0x85D6: 0xB06C, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULSIOS + 0x85D7: 0xB06D, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULTHIEUTH + 0x85D8: 0xB06E, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULPHIEUPH + 0x85D9: 0xB06F, //HANGUL SYLLABLE SSANGKIYEOK YI RIEULHIEUH + 0x85DA: 0xB070, //HANGUL SYLLABLE SSANGKIYEOK YI MIEUM + 0x85DB: 0xB071, //HANGUL SYLLABLE SSANGKIYEOK YI PIEUP + 0x85DC: 0xB072, //HANGUL SYLLABLE SSANGKIYEOK YI PIEUPSIOS + 0x85DD: 0xB073, //HANGUL SYLLABLE SSANGKIYEOK YI SIOS + 0x85DE: 0xB074, //HANGUL SYLLABLE SSANGKIYEOK YI SSANGSIOS + 0x85DF: 0xB075, //HANGUL SYLLABLE SSANGKIYEOK YI IEUNG + 0x85E0: 0xB076, //HANGUL SYLLABLE SSANGKIYEOK YI CIEUC + 0x85E1: 0xB077, //HANGUL SYLLABLE SSANGKIYEOK YI CHIEUCH + 0x85E2: 0xB078, //HANGUL SYLLABLE SSANGKIYEOK YI KHIEUKH + 0x85E3: 0xB079, //HANGUL SYLLABLE SSANGKIYEOK YI THIEUTH + 0x85E4: 0xB07A, //HANGUL SYLLABLE SSANGKIYEOK YI PHIEUPH + 0x85E5: 0xB07B, //HANGUL SYLLABLE SSANGKIYEOK YI HIEUH + 0x85E6: 0xB07E, //HANGUL SYLLABLE SSANGKIYEOK I SSANGKIYEOK + 0x85E7: 0xB07F, //HANGUL SYLLABLE SSANGKIYEOK I KIYEOKSIOS + 0x85E8: 0xB081, //HANGUL SYLLABLE SSANGKIYEOK I NIEUNCIEUC + 0x85E9: 0xB082, //HANGUL SYLLABLE SSANGKIYEOK I NIEUNHIEUH + 0x85EA: 0xB083, //HANGUL SYLLABLE SSANGKIYEOK I TIKEUT + 0x85EB: 0xB085, //HANGUL SYLLABLE SSANGKIYEOK I RIEULKIYEOK + 0x85EC: 0xB086, //HANGUL SYLLABLE SSANGKIYEOK I RIEULMIEUM + 0x85ED: 0xB087, //HANGUL SYLLABLE SSANGKIYEOK I RIEULPIEUP + 0x85EE: 0xB088, //HANGUL SYLLABLE SSANGKIYEOK I RIEULSIOS + 0x85EF: 0xB089, //HANGUL SYLLABLE SSANGKIYEOK I RIEULTHIEUTH + 0x85F0: 0xB08A, //HANGUL SYLLABLE SSANGKIYEOK I RIEULPHIEUPH + 0x85F1: 0xB08B, //HANGUL SYLLABLE SSANGKIYEOK I RIEULHIEUH + 0x85F2: 0xB08E, //HANGUL SYLLABLE SSANGKIYEOK I PIEUPSIOS + 0x85F3: 0xB090, //HANGUL SYLLABLE SSANGKIYEOK I SSANGSIOS + 0x85F4: 0xB092, //HANGUL SYLLABLE SSANGKIYEOK I CIEUC + 0x85F5: 0xB093, //HANGUL SYLLABLE SSANGKIYEOK I CHIEUCH + 0x85F6: 0xB094, //HANGUL SYLLABLE SSANGKIYEOK I KHIEUKH + 0x85F7: 0xB095, //HANGUL SYLLABLE SSANGKIYEOK I THIEUTH + 0x85F8: 0xB096, //HANGUL SYLLABLE SSANGKIYEOK I PHIEUPH + 0x85F9: 0xB097, //HANGUL SYLLABLE SSANGKIYEOK I HIEUH + 0x85FA: 0xB09B, //HANGUL SYLLABLE NIEUN A KIYEOKSIOS + 0x85FB: 0xB09D, //HANGUL SYLLABLE NIEUN A NIEUNCIEUC + 0x85FC: 0xB09E, //HANGUL SYLLABLE NIEUN A NIEUNHIEUH + 0x85FD: 0xB0A3, //HANGUL SYLLABLE NIEUN A RIEULPIEUP + 0x85FE: 0xB0A4, //HANGUL SYLLABLE NIEUN A RIEULSIOS + 0x8641: 0xB0A5, //HANGUL SYLLABLE NIEUN A RIEULTHIEUTH + 0x8642: 0xB0A6, //HANGUL SYLLABLE NIEUN A RIEULPHIEUPH + 0x8643: 0xB0A7, //HANGUL SYLLABLE NIEUN A RIEULHIEUH + 0x8644: 0xB0AA, //HANGUL SYLLABLE NIEUN A PIEUPSIOS + 0x8645: 0xB0B0, //HANGUL SYLLABLE NIEUN A KHIEUKH + 0x8646: 0xB0B2, //HANGUL SYLLABLE NIEUN A PHIEUPH + 0x8647: 0xB0B6, //HANGUL SYLLABLE NIEUN AE SSANGKIYEOK + 0x8648: 0xB0B7, //HANGUL SYLLABLE NIEUN AE KIYEOKSIOS + 0x8649: 0xB0B9, //HANGUL SYLLABLE NIEUN AE NIEUNCIEUC + 0x864A: 0xB0BA, //HANGUL SYLLABLE NIEUN AE NIEUNHIEUH + 0x864B: 0xB0BB, //HANGUL SYLLABLE NIEUN AE TIKEUT + 0x864C: 0xB0BD, //HANGUL SYLLABLE NIEUN AE RIEULKIYEOK + 0x864D: 0xB0BE, //HANGUL SYLLABLE NIEUN AE RIEULMIEUM + 0x864E: 0xB0BF, //HANGUL SYLLABLE NIEUN AE RIEULPIEUP + 0x864F: 0xB0C0, //HANGUL SYLLABLE NIEUN AE RIEULSIOS + 0x8650: 0xB0C1, //HANGUL SYLLABLE NIEUN AE RIEULTHIEUTH + 0x8651: 0xB0C2, //HANGUL SYLLABLE NIEUN AE RIEULPHIEUPH + 0x8652: 0xB0C3, //HANGUL SYLLABLE NIEUN AE RIEULHIEUH + 0x8653: 0xB0C6, //HANGUL SYLLABLE NIEUN AE PIEUPSIOS + 0x8654: 0xB0CA, //HANGUL SYLLABLE NIEUN AE CIEUC + 0x8655: 0xB0CB, //HANGUL SYLLABLE NIEUN AE CHIEUCH + 0x8656: 0xB0CC, //HANGUL SYLLABLE NIEUN AE KHIEUKH + 0x8657: 0xB0CD, //HANGUL SYLLABLE NIEUN AE THIEUTH + 0x8658: 0xB0CE, //HANGUL SYLLABLE NIEUN AE PHIEUPH + 0x8659: 0xB0CF, //HANGUL SYLLABLE NIEUN AE HIEUH + 0x865A: 0xB0D2, //HANGUL SYLLABLE NIEUN YA SSANGKIYEOK + 0x8661: 0xB0D3, //HANGUL SYLLABLE NIEUN YA KIYEOKSIOS + 0x8662: 0xB0D5, //HANGUL SYLLABLE NIEUN YA NIEUNCIEUC + 0x8663: 0xB0D6, //HANGUL SYLLABLE NIEUN YA NIEUNHIEUH + 0x8664: 0xB0D7, //HANGUL SYLLABLE NIEUN YA TIKEUT + 0x8665: 0xB0D9, //HANGUL SYLLABLE NIEUN YA RIEULKIYEOK + 0x8666: 0xB0DA, //HANGUL SYLLABLE NIEUN YA RIEULMIEUM + 0x8667: 0xB0DB, //HANGUL SYLLABLE NIEUN YA RIEULPIEUP + 0x8668: 0xB0DC, //HANGUL SYLLABLE NIEUN YA RIEULSIOS + 0x8669: 0xB0DD, //HANGUL SYLLABLE NIEUN YA RIEULTHIEUTH + 0x866A: 0xB0DE, //HANGUL SYLLABLE NIEUN YA RIEULPHIEUPH + 0x866B: 0xB0DF, //HANGUL SYLLABLE NIEUN YA RIEULHIEUH + 0x866C: 0xB0E1, //HANGUL SYLLABLE NIEUN YA PIEUP + 0x866D: 0xB0E2, //HANGUL SYLLABLE NIEUN YA PIEUPSIOS + 0x866E: 0xB0E3, //HANGUL SYLLABLE NIEUN YA SIOS + 0x866F: 0xB0E4, //HANGUL SYLLABLE NIEUN YA SSANGSIOS + 0x8670: 0xB0E6, //HANGUL SYLLABLE NIEUN YA CIEUC + 0x8671: 0xB0E7, //HANGUL SYLLABLE NIEUN YA CHIEUCH + 0x8672: 0xB0E8, //HANGUL SYLLABLE NIEUN YA KHIEUKH + 0x8673: 0xB0E9, //HANGUL SYLLABLE NIEUN YA THIEUTH + 0x8674: 0xB0EA, //HANGUL SYLLABLE NIEUN YA PHIEUPH + 0x8675: 0xB0EB, //HANGUL SYLLABLE NIEUN YA HIEUH + 0x8676: 0xB0EC, //HANGUL SYLLABLE NIEUN YAE + 0x8677: 0xB0ED, //HANGUL SYLLABLE NIEUN YAE KIYEOK + 0x8678: 0xB0EE, //HANGUL SYLLABLE NIEUN YAE SSANGKIYEOK + 0x8679: 0xB0EF, //HANGUL SYLLABLE NIEUN YAE KIYEOKSIOS + 0x867A: 0xB0F0, //HANGUL SYLLABLE NIEUN YAE NIEUN + 0x8681: 0xB0F1, //HANGUL SYLLABLE NIEUN YAE NIEUNCIEUC + 0x8682: 0xB0F2, //HANGUL SYLLABLE NIEUN YAE NIEUNHIEUH + 0x8683: 0xB0F3, //HANGUL SYLLABLE NIEUN YAE TIKEUT + 0x8684: 0xB0F4, //HANGUL SYLLABLE NIEUN YAE RIEUL + 0x8685: 0xB0F5, //HANGUL SYLLABLE NIEUN YAE RIEULKIYEOK + 0x8686: 0xB0F6, //HANGUL SYLLABLE NIEUN YAE RIEULMIEUM + 0x8687: 0xB0F7, //HANGUL SYLLABLE NIEUN YAE RIEULPIEUP + 0x8688: 0xB0F8, //HANGUL SYLLABLE NIEUN YAE RIEULSIOS + 0x8689: 0xB0F9, //HANGUL SYLLABLE NIEUN YAE RIEULTHIEUTH + 0x868A: 0xB0FA, //HANGUL SYLLABLE NIEUN YAE RIEULPHIEUPH + 0x868B: 0xB0FB, //HANGUL SYLLABLE NIEUN YAE RIEULHIEUH + 0x868C: 0xB0FC, //HANGUL SYLLABLE NIEUN YAE MIEUM + 0x868D: 0xB0FD, //HANGUL SYLLABLE NIEUN YAE PIEUP + 0x868E: 0xB0FE, //HANGUL SYLLABLE NIEUN YAE PIEUPSIOS + 0x868F: 0xB0FF, //HANGUL SYLLABLE NIEUN YAE SIOS + 0x8690: 0xB100, //HANGUL SYLLABLE NIEUN YAE SSANGSIOS + 0x8691: 0xB101, //HANGUL SYLLABLE NIEUN YAE IEUNG + 0x8692: 0xB102, //HANGUL SYLLABLE NIEUN YAE CIEUC + 0x8693: 0xB103, //HANGUL SYLLABLE NIEUN YAE CHIEUCH + 0x8694: 0xB104, //HANGUL SYLLABLE NIEUN YAE KHIEUKH + 0x8695: 0xB105, //HANGUL SYLLABLE NIEUN YAE THIEUTH + 0x8696: 0xB106, //HANGUL SYLLABLE NIEUN YAE PHIEUPH + 0x8697: 0xB107, //HANGUL SYLLABLE NIEUN YAE HIEUH + 0x8698: 0xB10A, //HANGUL SYLLABLE NIEUN EO SSANGKIYEOK + 0x8699: 0xB10D, //HANGUL SYLLABLE NIEUN EO NIEUNCIEUC + 0x869A: 0xB10E, //HANGUL SYLLABLE NIEUN EO NIEUNHIEUH + 0x869B: 0xB10F, //HANGUL SYLLABLE NIEUN EO TIKEUT + 0x869C: 0xB111, //HANGUL SYLLABLE NIEUN EO RIEULKIYEOK + 0x869D: 0xB114, //HANGUL SYLLABLE NIEUN EO RIEULSIOS + 0x869E: 0xB115, //HANGUL SYLLABLE NIEUN EO RIEULTHIEUTH + 0x869F: 0xB116, //HANGUL SYLLABLE NIEUN EO RIEULPHIEUPH + 0x86A0: 0xB117, //HANGUL SYLLABLE NIEUN EO RIEULHIEUH + 0x86A1: 0xB11A, //HANGUL SYLLABLE NIEUN EO PIEUPSIOS + 0x86A2: 0xB11E, //HANGUL SYLLABLE NIEUN EO CIEUC + 0x86A3: 0xB11F, //HANGUL SYLLABLE NIEUN EO CHIEUCH + 0x86A4: 0xB120, //HANGUL SYLLABLE NIEUN EO KHIEUKH + 0x86A5: 0xB121, //HANGUL SYLLABLE NIEUN EO THIEUTH + 0x86A6: 0xB122, //HANGUL SYLLABLE NIEUN EO PHIEUPH + 0x86A7: 0xB126, //HANGUL SYLLABLE NIEUN E SSANGKIYEOK + 0x86A8: 0xB127, //HANGUL SYLLABLE NIEUN E KIYEOKSIOS + 0x86A9: 0xB129, //HANGUL SYLLABLE NIEUN E NIEUNCIEUC + 0x86AA: 0xB12A, //HANGUL SYLLABLE NIEUN E NIEUNHIEUH + 0x86AB: 0xB12B, //HANGUL SYLLABLE NIEUN E TIKEUT + 0x86AC: 0xB12D, //HANGUL SYLLABLE NIEUN E RIEULKIYEOK + 0x86AD: 0xB12E, //HANGUL SYLLABLE NIEUN E RIEULMIEUM + 0x86AE: 0xB12F, //HANGUL SYLLABLE NIEUN E RIEULPIEUP + 0x86AF: 0xB130, //HANGUL SYLLABLE NIEUN E RIEULSIOS + 0x86B0: 0xB131, //HANGUL SYLLABLE NIEUN E RIEULTHIEUTH + 0x86B1: 0xB132, //HANGUL SYLLABLE NIEUN E RIEULPHIEUPH + 0x86B2: 0xB133, //HANGUL SYLLABLE NIEUN E RIEULHIEUH + 0x86B3: 0xB136, //HANGUL SYLLABLE NIEUN E PIEUPSIOS + 0x86B4: 0xB13A, //HANGUL SYLLABLE NIEUN E CIEUC + 0x86B5: 0xB13B, //HANGUL SYLLABLE NIEUN E CHIEUCH + 0x86B6: 0xB13C, //HANGUL SYLLABLE NIEUN E KHIEUKH + 0x86B7: 0xB13D, //HANGUL SYLLABLE NIEUN E THIEUTH + 0x86B8: 0xB13E, //HANGUL SYLLABLE NIEUN E PHIEUPH + 0x86B9: 0xB13F, //HANGUL SYLLABLE NIEUN E HIEUH + 0x86BA: 0xB142, //HANGUL SYLLABLE NIEUN YEO SSANGKIYEOK + 0x86BB: 0xB143, //HANGUL SYLLABLE NIEUN YEO KIYEOKSIOS + 0x86BC: 0xB145, //HANGUL SYLLABLE NIEUN YEO NIEUNCIEUC + 0x86BD: 0xB146, //HANGUL SYLLABLE NIEUN YEO NIEUNHIEUH + 0x86BE: 0xB147, //HANGUL SYLLABLE NIEUN YEO TIKEUT + 0x86BF: 0xB149, //HANGUL SYLLABLE NIEUN YEO RIEULKIYEOK + 0x86C0: 0xB14A, //HANGUL SYLLABLE NIEUN YEO RIEULMIEUM + 0x86C1: 0xB14B, //HANGUL SYLLABLE NIEUN YEO RIEULPIEUP + 0x86C2: 0xB14C, //HANGUL SYLLABLE NIEUN YEO RIEULSIOS + 0x86C3: 0xB14D, //HANGUL SYLLABLE NIEUN YEO RIEULTHIEUTH + 0x86C4: 0xB14E, //HANGUL SYLLABLE NIEUN YEO RIEULPHIEUPH + 0x86C5: 0xB14F, //HANGUL SYLLABLE NIEUN YEO RIEULHIEUH + 0x86C6: 0xB152, //HANGUL SYLLABLE NIEUN YEO PIEUPSIOS + 0x86C7: 0xB153, //HANGUL SYLLABLE NIEUN YEO SIOS + 0x86C8: 0xB156, //HANGUL SYLLABLE NIEUN YEO CIEUC + 0x86C9: 0xB157, //HANGUL SYLLABLE NIEUN YEO CHIEUCH + 0x86CA: 0xB159, //HANGUL SYLLABLE NIEUN YEO THIEUTH + 0x86CB: 0xB15A, //HANGUL SYLLABLE NIEUN YEO PHIEUPH + 0x86CC: 0xB15B, //HANGUL SYLLABLE NIEUN YEO HIEUH + 0x86CD: 0xB15D, //HANGUL SYLLABLE NIEUN YE KIYEOK + 0x86CE: 0xB15E, //HANGUL SYLLABLE NIEUN YE SSANGKIYEOK + 0x86CF: 0xB15F, //HANGUL SYLLABLE NIEUN YE KIYEOKSIOS + 0x86D0: 0xB161, //HANGUL SYLLABLE NIEUN YE NIEUNCIEUC + 0x86D1: 0xB162, //HANGUL SYLLABLE NIEUN YE NIEUNHIEUH + 0x86D2: 0xB163, //HANGUL SYLLABLE NIEUN YE TIKEUT + 0x86D3: 0xB164, //HANGUL SYLLABLE NIEUN YE RIEUL + 0x86D4: 0xB165, //HANGUL SYLLABLE NIEUN YE RIEULKIYEOK + 0x86D5: 0xB166, //HANGUL SYLLABLE NIEUN YE RIEULMIEUM + 0x86D6: 0xB167, //HANGUL SYLLABLE NIEUN YE RIEULPIEUP + 0x86D7: 0xB168, //HANGUL SYLLABLE NIEUN YE RIEULSIOS + 0x86D8: 0xB169, //HANGUL SYLLABLE NIEUN YE RIEULTHIEUTH + 0x86D9: 0xB16A, //HANGUL SYLLABLE NIEUN YE RIEULPHIEUPH + 0x86DA: 0xB16B, //HANGUL SYLLABLE NIEUN YE RIEULHIEUH + 0x86DB: 0xB16C, //HANGUL SYLLABLE NIEUN YE MIEUM + 0x86DC: 0xB16D, //HANGUL SYLLABLE NIEUN YE PIEUP + 0x86DD: 0xB16E, //HANGUL SYLLABLE NIEUN YE PIEUPSIOS + 0x86DE: 0xB16F, //HANGUL SYLLABLE NIEUN YE SIOS + 0x86DF: 0xB170, //HANGUL SYLLABLE NIEUN YE SSANGSIOS + 0x86E0: 0xB171, //HANGUL SYLLABLE NIEUN YE IEUNG + 0x86E1: 0xB172, //HANGUL SYLLABLE NIEUN YE CIEUC + 0x86E2: 0xB173, //HANGUL SYLLABLE NIEUN YE CHIEUCH + 0x86E3: 0xB174, //HANGUL SYLLABLE NIEUN YE KHIEUKH + 0x86E4: 0xB175, //HANGUL SYLLABLE NIEUN YE THIEUTH + 0x86E5: 0xB176, //HANGUL SYLLABLE NIEUN YE PHIEUPH + 0x86E6: 0xB177, //HANGUL SYLLABLE NIEUN YE HIEUH + 0x86E7: 0xB17A, //HANGUL SYLLABLE NIEUN O SSANGKIYEOK + 0x86E8: 0xB17B, //HANGUL SYLLABLE NIEUN O KIYEOKSIOS + 0x86E9: 0xB17D, //HANGUL SYLLABLE NIEUN O NIEUNCIEUC + 0x86EA: 0xB17E, //HANGUL SYLLABLE NIEUN O NIEUNHIEUH + 0x86EB: 0xB17F, //HANGUL SYLLABLE NIEUN O TIKEUT + 0x86EC: 0xB181, //HANGUL SYLLABLE NIEUN O RIEULKIYEOK + 0x86ED: 0xB183, //HANGUL SYLLABLE NIEUN O RIEULPIEUP + 0x86EE: 0xB184, //HANGUL SYLLABLE NIEUN O RIEULSIOS + 0x86EF: 0xB185, //HANGUL SYLLABLE NIEUN O RIEULTHIEUTH + 0x86F0: 0xB186, //HANGUL SYLLABLE NIEUN O RIEULPHIEUPH + 0x86F1: 0xB187, //HANGUL SYLLABLE NIEUN O RIEULHIEUH + 0x86F2: 0xB18A, //HANGUL SYLLABLE NIEUN O PIEUPSIOS + 0x86F3: 0xB18C, //HANGUL SYLLABLE NIEUN O SSANGSIOS + 0x86F4: 0xB18E, //HANGUL SYLLABLE NIEUN O CIEUC + 0x86F5: 0xB18F, //HANGUL SYLLABLE NIEUN O CHIEUCH + 0x86F6: 0xB190, //HANGUL SYLLABLE NIEUN O KHIEUKH + 0x86F7: 0xB191, //HANGUL SYLLABLE NIEUN O THIEUTH + 0x86F8: 0xB195, //HANGUL SYLLABLE NIEUN WA KIYEOK + 0x86F9: 0xB196, //HANGUL SYLLABLE NIEUN WA SSANGKIYEOK + 0x86FA: 0xB197, //HANGUL SYLLABLE NIEUN WA KIYEOKSIOS + 0x86FB: 0xB199, //HANGUL SYLLABLE NIEUN WA NIEUNCIEUC + 0x86FC: 0xB19A, //HANGUL SYLLABLE NIEUN WA NIEUNHIEUH + 0x86FD: 0xB19B, //HANGUL SYLLABLE NIEUN WA TIKEUT + 0x86FE: 0xB19D, //HANGUL SYLLABLE NIEUN WA RIEULKIYEOK + 0x8741: 0xB19E, //HANGUL SYLLABLE NIEUN WA RIEULMIEUM + 0x8742: 0xB19F, //HANGUL SYLLABLE NIEUN WA RIEULPIEUP + 0x8743: 0xB1A0, //HANGUL SYLLABLE NIEUN WA RIEULSIOS + 0x8744: 0xB1A1, //HANGUL SYLLABLE NIEUN WA RIEULTHIEUTH + 0x8745: 0xB1A2, //HANGUL SYLLABLE NIEUN WA RIEULPHIEUPH + 0x8746: 0xB1A3, //HANGUL SYLLABLE NIEUN WA RIEULHIEUH + 0x8747: 0xB1A4, //HANGUL SYLLABLE NIEUN WA MIEUM + 0x8748: 0xB1A5, //HANGUL SYLLABLE NIEUN WA PIEUP + 0x8749: 0xB1A6, //HANGUL SYLLABLE NIEUN WA PIEUPSIOS + 0x874A: 0xB1A7, //HANGUL SYLLABLE NIEUN WA SIOS + 0x874B: 0xB1A9, //HANGUL SYLLABLE NIEUN WA IEUNG + 0x874C: 0xB1AA, //HANGUL SYLLABLE NIEUN WA CIEUC + 0x874D: 0xB1AB, //HANGUL SYLLABLE NIEUN WA CHIEUCH + 0x874E: 0xB1AC, //HANGUL SYLLABLE NIEUN WA KHIEUKH + 0x874F: 0xB1AD, //HANGUL SYLLABLE NIEUN WA THIEUTH + 0x8750: 0xB1AE, //HANGUL SYLLABLE NIEUN WA PHIEUPH + 0x8751: 0xB1AF, //HANGUL SYLLABLE NIEUN WA HIEUH + 0x8752: 0xB1B0, //HANGUL SYLLABLE NIEUN WAE + 0x8753: 0xB1B1, //HANGUL SYLLABLE NIEUN WAE KIYEOK + 0x8754: 0xB1B2, //HANGUL SYLLABLE NIEUN WAE SSANGKIYEOK + 0x8755: 0xB1B3, //HANGUL SYLLABLE NIEUN WAE KIYEOKSIOS + 0x8756: 0xB1B4, //HANGUL SYLLABLE NIEUN WAE NIEUN + 0x8757: 0xB1B5, //HANGUL SYLLABLE NIEUN WAE NIEUNCIEUC + 0x8758: 0xB1B6, //HANGUL SYLLABLE NIEUN WAE NIEUNHIEUH + 0x8759: 0xB1B7, //HANGUL SYLLABLE NIEUN WAE TIKEUT + 0x875A: 0xB1B8, //HANGUL SYLLABLE NIEUN WAE RIEUL + 0x8761: 0xB1B9, //HANGUL SYLLABLE NIEUN WAE RIEULKIYEOK + 0x8762: 0xB1BA, //HANGUL SYLLABLE NIEUN WAE RIEULMIEUM + 0x8763: 0xB1BB, //HANGUL SYLLABLE NIEUN WAE RIEULPIEUP + 0x8764: 0xB1BC, //HANGUL SYLLABLE NIEUN WAE RIEULSIOS + 0x8765: 0xB1BD, //HANGUL SYLLABLE NIEUN WAE RIEULTHIEUTH + 0x8766: 0xB1BE, //HANGUL SYLLABLE NIEUN WAE RIEULPHIEUPH + 0x8767: 0xB1BF, //HANGUL SYLLABLE NIEUN WAE RIEULHIEUH + 0x8768: 0xB1C0, //HANGUL SYLLABLE NIEUN WAE MIEUM + 0x8769: 0xB1C1, //HANGUL SYLLABLE NIEUN WAE PIEUP + 0x876A: 0xB1C2, //HANGUL SYLLABLE NIEUN WAE PIEUPSIOS + 0x876B: 0xB1C3, //HANGUL SYLLABLE NIEUN WAE SIOS + 0x876C: 0xB1C4, //HANGUL SYLLABLE NIEUN WAE SSANGSIOS + 0x876D: 0xB1C5, //HANGUL SYLLABLE NIEUN WAE IEUNG + 0x876E: 0xB1C6, //HANGUL SYLLABLE NIEUN WAE CIEUC + 0x876F: 0xB1C7, //HANGUL SYLLABLE NIEUN WAE CHIEUCH + 0x8770: 0xB1C8, //HANGUL SYLLABLE NIEUN WAE KHIEUKH + 0x8771: 0xB1C9, //HANGUL SYLLABLE NIEUN WAE THIEUTH + 0x8772: 0xB1CA, //HANGUL SYLLABLE NIEUN WAE PHIEUPH + 0x8773: 0xB1CB, //HANGUL SYLLABLE NIEUN WAE HIEUH + 0x8774: 0xB1CD, //HANGUL SYLLABLE NIEUN OE KIYEOK + 0x8775: 0xB1CE, //HANGUL SYLLABLE NIEUN OE SSANGKIYEOK + 0x8776: 0xB1CF, //HANGUL SYLLABLE NIEUN OE KIYEOKSIOS + 0x8777: 0xB1D1, //HANGUL SYLLABLE NIEUN OE NIEUNCIEUC + 0x8778: 0xB1D2, //HANGUL SYLLABLE NIEUN OE NIEUNHIEUH + 0x8779: 0xB1D3, //HANGUL SYLLABLE NIEUN OE TIKEUT + 0x877A: 0xB1D5, //HANGUL SYLLABLE NIEUN OE RIEULKIYEOK + 0x8781: 0xB1D6, //HANGUL SYLLABLE NIEUN OE RIEULMIEUM + 0x8782: 0xB1D7, //HANGUL SYLLABLE NIEUN OE RIEULPIEUP + 0x8783: 0xB1D8, //HANGUL SYLLABLE NIEUN OE RIEULSIOS + 0x8784: 0xB1D9, //HANGUL SYLLABLE NIEUN OE RIEULTHIEUTH + 0x8785: 0xB1DA, //HANGUL SYLLABLE NIEUN OE RIEULPHIEUPH + 0x8786: 0xB1DB, //HANGUL SYLLABLE NIEUN OE RIEULHIEUH + 0x8787: 0xB1DE, //HANGUL SYLLABLE NIEUN OE PIEUPSIOS + 0x8788: 0xB1E0, //HANGUL SYLLABLE NIEUN OE SSANGSIOS + 0x8789: 0xB1E1, //HANGUL SYLLABLE NIEUN OE IEUNG + 0x878A: 0xB1E2, //HANGUL SYLLABLE NIEUN OE CIEUC + 0x878B: 0xB1E3, //HANGUL SYLLABLE NIEUN OE CHIEUCH + 0x878C: 0xB1E4, //HANGUL SYLLABLE NIEUN OE KHIEUKH + 0x878D: 0xB1E5, //HANGUL SYLLABLE NIEUN OE THIEUTH + 0x878E: 0xB1E6, //HANGUL SYLLABLE NIEUN OE PHIEUPH + 0x878F: 0xB1E7, //HANGUL SYLLABLE NIEUN OE HIEUH + 0x8790: 0xB1EA, //HANGUL SYLLABLE NIEUN YO SSANGKIYEOK + 0x8791: 0xB1EB, //HANGUL SYLLABLE NIEUN YO KIYEOKSIOS + 0x8792: 0xB1ED, //HANGUL SYLLABLE NIEUN YO NIEUNCIEUC + 0x8793: 0xB1EE, //HANGUL SYLLABLE NIEUN YO NIEUNHIEUH + 0x8794: 0xB1EF, //HANGUL SYLLABLE NIEUN YO TIKEUT + 0x8795: 0xB1F1, //HANGUL SYLLABLE NIEUN YO RIEULKIYEOK + 0x8796: 0xB1F2, //HANGUL SYLLABLE NIEUN YO RIEULMIEUM + 0x8797: 0xB1F3, //HANGUL SYLLABLE NIEUN YO RIEULPIEUP + 0x8798: 0xB1F4, //HANGUL SYLLABLE NIEUN YO RIEULSIOS + 0x8799: 0xB1F5, //HANGUL SYLLABLE NIEUN YO RIEULTHIEUTH + 0x879A: 0xB1F6, //HANGUL SYLLABLE NIEUN YO RIEULPHIEUPH + 0x879B: 0xB1F7, //HANGUL SYLLABLE NIEUN YO RIEULHIEUH + 0x879C: 0xB1F8, //HANGUL SYLLABLE NIEUN YO MIEUM + 0x879D: 0xB1FA, //HANGUL SYLLABLE NIEUN YO PIEUPSIOS + 0x879E: 0xB1FC, //HANGUL SYLLABLE NIEUN YO SSANGSIOS + 0x879F: 0xB1FE, //HANGUL SYLLABLE NIEUN YO CIEUC + 0x87A0: 0xB1FF, //HANGUL SYLLABLE NIEUN YO CHIEUCH + 0x87A1: 0xB200, //HANGUL SYLLABLE NIEUN YO KHIEUKH + 0x87A2: 0xB201, //HANGUL SYLLABLE NIEUN YO THIEUTH + 0x87A3: 0xB202, //HANGUL SYLLABLE NIEUN YO PHIEUPH + 0x87A4: 0xB203, //HANGUL SYLLABLE NIEUN YO HIEUH + 0x87A5: 0xB206, //HANGUL SYLLABLE NIEUN U SSANGKIYEOK + 0x87A6: 0xB207, //HANGUL SYLLABLE NIEUN U KIYEOKSIOS + 0x87A7: 0xB209, //HANGUL SYLLABLE NIEUN U NIEUNCIEUC + 0x87A8: 0xB20A, //HANGUL SYLLABLE NIEUN U NIEUNHIEUH + 0x87A9: 0xB20D, //HANGUL SYLLABLE NIEUN U RIEULKIYEOK + 0x87AA: 0xB20E, //HANGUL SYLLABLE NIEUN U RIEULMIEUM + 0x87AB: 0xB20F, //HANGUL SYLLABLE NIEUN U RIEULPIEUP + 0x87AC: 0xB210, //HANGUL SYLLABLE NIEUN U RIEULSIOS + 0x87AD: 0xB211, //HANGUL SYLLABLE NIEUN U RIEULTHIEUTH + 0x87AE: 0xB212, //HANGUL SYLLABLE NIEUN U RIEULPHIEUPH + 0x87AF: 0xB213, //HANGUL SYLLABLE NIEUN U RIEULHIEUH + 0x87B0: 0xB216, //HANGUL SYLLABLE NIEUN U PIEUPSIOS + 0x87B1: 0xB218, //HANGUL SYLLABLE NIEUN U SSANGSIOS + 0x87B2: 0xB21A, //HANGUL SYLLABLE NIEUN U CIEUC + 0x87B3: 0xB21B, //HANGUL SYLLABLE NIEUN U CHIEUCH + 0x87B4: 0xB21C, //HANGUL SYLLABLE NIEUN U KHIEUKH + 0x87B5: 0xB21D, //HANGUL SYLLABLE NIEUN U THIEUTH + 0x87B6: 0xB21E, //HANGUL SYLLABLE NIEUN U PHIEUPH + 0x87B7: 0xB21F, //HANGUL SYLLABLE NIEUN U HIEUH + 0x87B8: 0xB221, //HANGUL SYLLABLE NIEUN WEO KIYEOK + 0x87B9: 0xB222, //HANGUL SYLLABLE NIEUN WEO SSANGKIYEOK + 0x87BA: 0xB223, //HANGUL SYLLABLE NIEUN WEO KIYEOKSIOS + 0x87BB: 0xB224, //HANGUL SYLLABLE NIEUN WEO NIEUN + 0x87BC: 0xB225, //HANGUL SYLLABLE NIEUN WEO NIEUNCIEUC + 0x87BD: 0xB226, //HANGUL SYLLABLE NIEUN WEO NIEUNHIEUH + 0x87BE: 0xB227, //HANGUL SYLLABLE NIEUN WEO TIKEUT + 0x87BF: 0xB228, //HANGUL SYLLABLE NIEUN WEO RIEUL + 0x87C0: 0xB229, //HANGUL SYLLABLE NIEUN WEO RIEULKIYEOK + 0x87C1: 0xB22A, //HANGUL SYLLABLE NIEUN WEO RIEULMIEUM + 0x87C2: 0xB22B, //HANGUL SYLLABLE NIEUN WEO RIEULPIEUP + 0x87C3: 0xB22C, //HANGUL SYLLABLE NIEUN WEO RIEULSIOS + 0x87C4: 0xB22D, //HANGUL SYLLABLE NIEUN WEO RIEULTHIEUTH + 0x87C5: 0xB22E, //HANGUL SYLLABLE NIEUN WEO RIEULPHIEUPH + 0x87C6: 0xB22F, //HANGUL SYLLABLE NIEUN WEO RIEULHIEUH + 0x87C7: 0xB230, //HANGUL SYLLABLE NIEUN WEO MIEUM + 0x87C8: 0xB231, //HANGUL SYLLABLE NIEUN WEO PIEUP + 0x87C9: 0xB232, //HANGUL SYLLABLE NIEUN WEO PIEUPSIOS + 0x87CA: 0xB233, //HANGUL SYLLABLE NIEUN WEO SIOS + 0x87CB: 0xB235, //HANGUL SYLLABLE NIEUN WEO IEUNG + 0x87CC: 0xB236, //HANGUL SYLLABLE NIEUN WEO CIEUC + 0x87CD: 0xB237, //HANGUL SYLLABLE NIEUN WEO CHIEUCH + 0x87CE: 0xB238, //HANGUL SYLLABLE NIEUN WEO KHIEUKH + 0x87CF: 0xB239, //HANGUL SYLLABLE NIEUN WEO THIEUTH + 0x87D0: 0xB23A, //HANGUL SYLLABLE NIEUN WEO PHIEUPH + 0x87D1: 0xB23B, //HANGUL SYLLABLE NIEUN WEO HIEUH + 0x87D2: 0xB23D, //HANGUL SYLLABLE NIEUN WE KIYEOK + 0x87D3: 0xB23E, //HANGUL SYLLABLE NIEUN WE SSANGKIYEOK + 0x87D4: 0xB23F, //HANGUL SYLLABLE NIEUN WE KIYEOKSIOS + 0x87D5: 0xB240, //HANGUL SYLLABLE NIEUN WE NIEUN + 0x87D6: 0xB241, //HANGUL SYLLABLE NIEUN WE NIEUNCIEUC + 0x87D7: 0xB242, //HANGUL SYLLABLE NIEUN WE NIEUNHIEUH + 0x87D8: 0xB243, //HANGUL SYLLABLE NIEUN WE TIKEUT + 0x87D9: 0xB244, //HANGUL SYLLABLE NIEUN WE RIEUL + 0x87DA: 0xB245, //HANGUL SYLLABLE NIEUN WE RIEULKIYEOK + 0x87DB: 0xB246, //HANGUL SYLLABLE NIEUN WE RIEULMIEUM + 0x87DC: 0xB247, //HANGUL SYLLABLE NIEUN WE RIEULPIEUP + 0x87DD: 0xB248, //HANGUL SYLLABLE NIEUN WE RIEULSIOS + 0x87DE: 0xB249, //HANGUL SYLLABLE NIEUN WE RIEULTHIEUTH + 0x87DF: 0xB24A, //HANGUL SYLLABLE NIEUN WE RIEULPHIEUPH + 0x87E0: 0xB24B, //HANGUL SYLLABLE NIEUN WE RIEULHIEUH + 0x87E1: 0xB24C, //HANGUL SYLLABLE NIEUN WE MIEUM + 0x87E2: 0xB24D, //HANGUL SYLLABLE NIEUN WE PIEUP + 0x87E3: 0xB24E, //HANGUL SYLLABLE NIEUN WE PIEUPSIOS + 0x87E4: 0xB24F, //HANGUL SYLLABLE NIEUN WE SIOS + 0x87E5: 0xB250, //HANGUL SYLLABLE NIEUN WE SSANGSIOS + 0x87E6: 0xB251, //HANGUL SYLLABLE NIEUN WE IEUNG + 0x87E7: 0xB252, //HANGUL SYLLABLE NIEUN WE CIEUC + 0x87E8: 0xB253, //HANGUL SYLLABLE NIEUN WE CHIEUCH + 0x87E9: 0xB254, //HANGUL SYLLABLE NIEUN WE KHIEUKH + 0x87EA: 0xB255, //HANGUL SYLLABLE NIEUN WE THIEUTH + 0x87EB: 0xB256, //HANGUL SYLLABLE NIEUN WE PHIEUPH + 0x87EC: 0xB257, //HANGUL SYLLABLE NIEUN WE HIEUH + 0x87ED: 0xB259, //HANGUL SYLLABLE NIEUN WI KIYEOK + 0x87EE: 0xB25A, //HANGUL SYLLABLE NIEUN WI SSANGKIYEOK + 0x87EF: 0xB25B, //HANGUL SYLLABLE NIEUN WI KIYEOKSIOS + 0x87F0: 0xB25D, //HANGUL SYLLABLE NIEUN WI NIEUNCIEUC + 0x87F1: 0xB25E, //HANGUL SYLLABLE NIEUN WI NIEUNHIEUH + 0x87F2: 0xB25F, //HANGUL SYLLABLE NIEUN WI TIKEUT + 0x87F3: 0xB261, //HANGUL SYLLABLE NIEUN WI RIEULKIYEOK + 0x87F4: 0xB262, //HANGUL SYLLABLE NIEUN WI RIEULMIEUM + 0x87F5: 0xB263, //HANGUL SYLLABLE NIEUN WI RIEULPIEUP + 0x87F6: 0xB264, //HANGUL SYLLABLE NIEUN WI RIEULSIOS + 0x87F7: 0xB265, //HANGUL SYLLABLE NIEUN WI RIEULTHIEUTH + 0x87F8: 0xB266, //HANGUL SYLLABLE NIEUN WI RIEULPHIEUPH + 0x87F9: 0xB267, //HANGUL SYLLABLE NIEUN WI RIEULHIEUH + 0x87FA: 0xB26A, //HANGUL SYLLABLE NIEUN WI PIEUPSIOS + 0x87FB: 0xB26B, //HANGUL SYLLABLE NIEUN WI SIOS + 0x87FC: 0xB26C, //HANGUL SYLLABLE NIEUN WI SSANGSIOS + 0x87FD: 0xB26D, //HANGUL SYLLABLE NIEUN WI IEUNG + 0x87FE: 0xB26E, //HANGUL SYLLABLE NIEUN WI CIEUC + 0x8841: 0xB26F, //HANGUL SYLLABLE NIEUN WI CHIEUCH + 0x8842: 0xB270, //HANGUL SYLLABLE NIEUN WI KHIEUKH + 0x8843: 0xB271, //HANGUL SYLLABLE NIEUN WI THIEUTH + 0x8844: 0xB272, //HANGUL SYLLABLE NIEUN WI PHIEUPH + 0x8845: 0xB273, //HANGUL SYLLABLE NIEUN WI HIEUH + 0x8846: 0xB276, //HANGUL SYLLABLE NIEUN YU SSANGKIYEOK + 0x8847: 0xB277, //HANGUL SYLLABLE NIEUN YU KIYEOKSIOS + 0x8848: 0xB278, //HANGUL SYLLABLE NIEUN YU NIEUN + 0x8849: 0xB279, //HANGUL SYLLABLE NIEUN YU NIEUNCIEUC + 0x884A: 0xB27A, //HANGUL SYLLABLE NIEUN YU NIEUNHIEUH + 0x884B: 0xB27B, //HANGUL SYLLABLE NIEUN YU TIKEUT + 0x884C: 0xB27D, //HANGUL SYLLABLE NIEUN YU RIEULKIYEOK + 0x884D: 0xB27E, //HANGUL SYLLABLE NIEUN YU RIEULMIEUM + 0x884E: 0xB27F, //HANGUL SYLLABLE NIEUN YU RIEULPIEUP + 0x884F: 0xB280, //HANGUL SYLLABLE NIEUN YU RIEULSIOS + 0x8850: 0xB281, //HANGUL SYLLABLE NIEUN YU RIEULTHIEUTH + 0x8851: 0xB282, //HANGUL SYLLABLE NIEUN YU RIEULPHIEUPH + 0x8852: 0xB283, //HANGUL SYLLABLE NIEUN YU RIEULHIEUH + 0x8853: 0xB286, //HANGUL SYLLABLE NIEUN YU PIEUPSIOS + 0x8854: 0xB287, //HANGUL SYLLABLE NIEUN YU SIOS + 0x8855: 0xB288, //HANGUL SYLLABLE NIEUN YU SSANGSIOS + 0x8856: 0xB28A, //HANGUL SYLLABLE NIEUN YU CIEUC + 0x8857: 0xB28B, //HANGUL SYLLABLE NIEUN YU CHIEUCH + 0x8858: 0xB28C, //HANGUL SYLLABLE NIEUN YU KHIEUKH + 0x8859: 0xB28D, //HANGUL SYLLABLE NIEUN YU THIEUTH + 0x885A: 0xB28E, //HANGUL SYLLABLE NIEUN YU PHIEUPH + 0x8861: 0xB28F, //HANGUL SYLLABLE NIEUN YU HIEUH + 0x8862: 0xB292, //HANGUL SYLLABLE NIEUN EU SSANGKIYEOK + 0x8863: 0xB293, //HANGUL SYLLABLE NIEUN EU KIYEOKSIOS + 0x8864: 0xB295, //HANGUL SYLLABLE NIEUN EU NIEUNCIEUC + 0x8865: 0xB296, //HANGUL SYLLABLE NIEUN EU NIEUNHIEUH + 0x8866: 0xB297, //HANGUL SYLLABLE NIEUN EU TIKEUT + 0x8867: 0xB29B, //HANGUL SYLLABLE NIEUN EU RIEULPIEUP + 0x8868: 0xB29C, //HANGUL SYLLABLE NIEUN EU RIEULSIOS + 0x8869: 0xB29D, //HANGUL SYLLABLE NIEUN EU RIEULTHIEUTH + 0x886A: 0xB29E, //HANGUL SYLLABLE NIEUN EU RIEULPHIEUPH + 0x886B: 0xB29F, //HANGUL SYLLABLE NIEUN EU RIEULHIEUH + 0x886C: 0xB2A2, //HANGUL SYLLABLE NIEUN EU PIEUPSIOS + 0x886D: 0xB2A4, //HANGUL SYLLABLE NIEUN EU SSANGSIOS + 0x886E: 0xB2A7, //HANGUL SYLLABLE NIEUN EU CHIEUCH + 0x886F: 0xB2A8, //HANGUL SYLLABLE NIEUN EU KHIEUKH + 0x8870: 0xB2A9, //HANGUL SYLLABLE NIEUN EU THIEUTH + 0x8871: 0xB2AB, //HANGUL SYLLABLE NIEUN EU HIEUH + 0x8872: 0xB2AD, //HANGUL SYLLABLE NIEUN YI KIYEOK + 0x8873: 0xB2AE, //HANGUL SYLLABLE NIEUN YI SSANGKIYEOK + 0x8874: 0xB2AF, //HANGUL SYLLABLE NIEUN YI KIYEOKSIOS + 0x8875: 0xB2B1, //HANGUL SYLLABLE NIEUN YI NIEUNCIEUC + 0x8876: 0xB2B2, //HANGUL SYLLABLE NIEUN YI NIEUNHIEUH + 0x8877: 0xB2B3, //HANGUL SYLLABLE NIEUN YI TIKEUT + 0x8878: 0xB2B5, //HANGUL SYLLABLE NIEUN YI RIEULKIYEOK + 0x8879: 0xB2B6, //HANGUL SYLLABLE NIEUN YI RIEULMIEUM + 0x887A: 0xB2B7, //HANGUL SYLLABLE NIEUN YI RIEULPIEUP + 0x8881: 0xB2B8, //HANGUL SYLLABLE NIEUN YI RIEULSIOS + 0x8882: 0xB2B9, //HANGUL SYLLABLE NIEUN YI RIEULTHIEUTH + 0x8883: 0xB2BA, //HANGUL SYLLABLE NIEUN YI RIEULPHIEUPH + 0x8884: 0xB2BB, //HANGUL SYLLABLE NIEUN YI RIEULHIEUH + 0x8885: 0xB2BC, //HANGUL SYLLABLE NIEUN YI MIEUM + 0x8886: 0xB2BD, //HANGUL SYLLABLE NIEUN YI PIEUP + 0x8887: 0xB2BE, //HANGUL SYLLABLE NIEUN YI PIEUPSIOS + 0x8888: 0xB2BF, //HANGUL SYLLABLE NIEUN YI SIOS + 0x8889: 0xB2C0, //HANGUL SYLLABLE NIEUN YI SSANGSIOS + 0x888A: 0xB2C1, //HANGUL SYLLABLE NIEUN YI IEUNG + 0x888B: 0xB2C2, //HANGUL SYLLABLE NIEUN YI CIEUC + 0x888C: 0xB2C3, //HANGUL SYLLABLE NIEUN YI CHIEUCH + 0x888D: 0xB2C4, //HANGUL SYLLABLE NIEUN YI KHIEUKH + 0x888E: 0xB2C5, //HANGUL SYLLABLE NIEUN YI THIEUTH + 0x888F: 0xB2C6, //HANGUL SYLLABLE NIEUN YI PHIEUPH + 0x8890: 0xB2C7, //HANGUL SYLLABLE NIEUN YI HIEUH + 0x8891: 0xB2CA, //HANGUL SYLLABLE NIEUN I SSANGKIYEOK + 0x8892: 0xB2CB, //HANGUL SYLLABLE NIEUN I KIYEOKSIOS + 0x8893: 0xB2CD, //HANGUL SYLLABLE NIEUN I NIEUNCIEUC + 0x8894: 0xB2CE, //HANGUL SYLLABLE NIEUN I NIEUNHIEUH + 0x8895: 0xB2CF, //HANGUL SYLLABLE NIEUN I TIKEUT + 0x8896: 0xB2D1, //HANGUL SYLLABLE NIEUN I RIEULKIYEOK + 0x8897: 0xB2D3, //HANGUL SYLLABLE NIEUN I RIEULPIEUP + 0x8898: 0xB2D4, //HANGUL SYLLABLE NIEUN I RIEULSIOS + 0x8899: 0xB2D5, //HANGUL SYLLABLE NIEUN I RIEULTHIEUTH + 0x889A: 0xB2D6, //HANGUL SYLLABLE NIEUN I RIEULPHIEUPH + 0x889B: 0xB2D7, //HANGUL SYLLABLE NIEUN I RIEULHIEUH + 0x889C: 0xB2DA, //HANGUL SYLLABLE NIEUN I PIEUPSIOS + 0x889D: 0xB2DC, //HANGUL SYLLABLE NIEUN I SSANGSIOS + 0x889E: 0xB2DE, //HANGUL SYLLABLE NIEUN I CIEUC + 0x889F: 0xB2DF, //HANGUL SYLLABLE NIEUN I CHIEUCH + 0x88A0: 0xB2E0, //HANGUL SYLLABLE NIEUN I KHIEUKH + 0x88A1: 0xB2E1, //HANGUL SYLLABLE NIEUN I THIEUTH + 0x88A2: 0xB2E3, //HANGUL SYLLABLE NIEUN I HIEUH + 0x88A3: 0xB2E7, //HANGUL SYLLABLE TIKEUT A KIYEOKSIOS + 0x88A4: 0xB2E9, //HANGUL SYLLABLE TIKEUT A NIEUNCIEUC + 0x88A5: 0xB2EA, //HANGUL SYLLABLE TIKEUT A NIEUNHIEUH + 0x88A6: 0xB2F0, //HANGUL SYLLABLE TIKEUT A RIEULSIOS + 0x88A7: 0xB2F1, //HANGUL SYLLABLE TIKEUT A RIEULTHIEUTH + 0x88A8: 0xB2F2, //HANGUL SYLLABLE TIKEUT A RIEULPHIEUPH + 0x88A9: 0xB2F6, //HANGUL SYLLABLE TIKEUT A PIEUPSIOS + 0x88AA: 0xB2FC, //HANGUL SYLLABLE TIKEUT A KHIEUKH + 0x88AB: 0xB2FD, //HANGUL SYLLABLE TIKEUT A THIEUTH + 0x88AC: 0xB2FE, //HANGUL SYLLABLE TIKEUT A PHIEUPH + 0x88AD: 0xB302, //HANGUL SYLLABLE TIKEUT AE SSANGKIYEOK + 0x88AE: 0xB303, //HANGUL SYLLABLE TIKEUT AE KIYEOKSIOS + 0x88AF: 0xB305, //HANGUL SYLLABLE TIKEUT AE NIEUNCIEUC + 0x88B0: 0xB306, //HANGUL SYLLABLE TIKEUT AE NIEUNHIEUH + 0x88B1: 0xB307, //HANGUL SYLLABLE TIKEUT AE TIKEUT + 0x88B2: 0xB309, //HANGUL SYLLABLE TIKEUT AE RIEULKIYEOK + 0x88B3: 0xB30A, //HANGUL SYLLABLE TIKEUT AE RIEULMIEUM + 0x88B4: 0xB30B, //HANGUL SYLLABLE TIKEUT AE RIEULPIEUP + 0x88B5: 0xB30C, //HANGUL SYLLABLE TIKEUT AE RIEULSIOS + 0x88B6: 0xB30D, //HANGUL SYLLABLE TIKEUT AE RIEULTHIEUTH + 0x88B7: 0xB30E, //HANGUL SYLLABLE TIKEUT AE RIEULPHIEUPH + 0x88B8: 0xB30F, //HANGUL SYLLABLE TIKEUT AE RIEULHIEUH + 0x88B9: 0xB312, //HANGUL SYLLABLE TIKEUT AE PIEUPSIOS + 0x88BA: 0xB316, //HANGUL SYLLABLE TIKEUT AE CIEUC + 0x88BB: 0xB317, //HANGUL SYLLABLE TIKEUT AE CHIEUCH + 0x88BC: 0xB318, //HANGUL SYLLABLE TIKEUT AE KHIEUKH + 0x88BD: 0xB319, //HANGUL SYLLABLE TIKEUT AE THIEUTH + 0x88BE: 0xB31A, //HANGUL SYLLABLE TIKEUT AE PHIEUPH + 0x88BF: 0xB31B, //HANGUL SYLLABLE TIKEUT AE HIEUH + 0x88C0: 0xB31D, //HANGUL SYLLABLE TIKEUT YA KIYEOK + 0x88C1: 0xB31E, //HANGUL SYLLABLE TIKEUT YA SSANGKIYEOK + 0x88C2: 0xB31F, //HANGUL SYLLABLE TIKEUT YA KIYEOKSIOS + 0x88C3: 0xB320, //HANGUL SYLLABLE TIKEUT YA NIEUN + 0x88C4: 0xB321, //HANGUL SYLLABLE TIKEUT YA NIEUNCIEUC + 0x88C5: 0xB322, //HANGUL SYLLABLE TIKEUT YA NIEUNHIEUH + 0x88C6: 0xB323, //HANGUL SYLLABLE TIKEUT YA TIKEUT + 0x88C7: 0xB324, //HANGUL SYLLABLE TIKEUT YA RIEUL + 0x88C8: 0xB325, //HANGUL SYLLABLE TIKEUT YA RIEULKIYEOK + 0x88C9: 0xB326, //HANGUL SYLLABLE TIKEUT YA RIEULMIEUM + 0x88CA: 0xB327, //HANGUL SYLLABLE TIKEUT YA RIEULPIEUP + 0x88CB: 0xB328, //HANGUL SYLLABLE TIKEUT YA RIEULSIOS + 0x88CC: 0xB329, //HANGUL SYLLABLE TIKEUT YA RIEULTHIEUTH + 0x88CD: 0xB32A, //HANGUL SYLLABLE TIKEUT YA RIEULPHIEUPH + 0x88CE: 0xB32B, //HANGUL SYLLABLE TIKEUT YA RIEULHIEUH + 0x88CF: 0xB32C, //HANGUL SYLLABLE TIKEUT YA MIEUM + 0x88D0: 0xB32D, //HANGUL SYLLABLE TIKEUT YA PIEUP + 0x88D1: 0xB32E, //HANGUL SYLLABLE TIKEUT YA PIEUPSIOS + 0x88D2: 0xB32F, //HANGUL SYLLABLE TIKEUT YA SIOS + 0x88D3: 0xB330, //HANGUL SYLLABLE TIKEUT YA SSANGSIOS + 0x88D4: 0xB331, //HANGUL SYLLABLE TIKEUT YA IEUNG + 0x88D5: 0xB332, //HANGUL SYLLABLE TIKEUT YA CIEUC + 0x88D6: 0xB333, //HANGUL SYLLABLE TIKEUT YA CHIEUCH + 0x88D7: 0xB334, //HANGUL SYLLABLE TIKEUT YA KHIEUKH + 0x88D8: 0xB335, //HANGUL SYLLABLE TIKEUT YA THIEUTH + 0x88D9: 0xB336, //HANGUL SYLLABLE TIKEUT YA PHIEUPH + 0x88DA: 0xB337, //HANGUL SYLLABLE TIKEUT YA HIEUH + 0x88DB: 0xB338, //HANGUL SYLLABLE TIKEUT YAE + 0x88DC: 0xB339, //HANGUL SYLLABLE TIKEUT YAE KIYEOK + 0x88DD: 0xB33A, //HANGUL SYLLABLE TIKEUT YAE SSANGKIYEOK + 0x88DE: 0xB33B, //HANGUL SYLLABLE TIKEUT YAE KIYEOKSIOS + 0x88DF: 0xB33C, //HANGUL SYLLABLE TIKEUT YAE NIEUN + 0x88E0: 0xB33D, //HANGUL SYLLABLE TIKEUT YAE NIEUNCIEUC + 0x88E1: 0xB33E, //HANGUL SYLLABLE TIKEUT YAE NIEUNHIEUH + 0x88E2: 0xB33F, //HANGUL SYLLABLE TIKEUT YAE TIKEUT + 0x88E3: 0xB340, //HANGUL SYLLABLE TIKEUT YAE RIEUL + 0x88E4: 0xB341, //HANGUL SYLLABLE TIKEUT YAE RIEULKIYEOK + 0x88E5: 0xB342, //HANGUL SYLLABLE TIKEUT YAE RIEULMIEUM + 0x88E6: 0xB343, //HANGUL SYLLABLE TIKEUT YAE RIEULPIEUP + 0x88E7: 0xB344, //HANGUL SYLLABLE TIKEUT YAE RIEULSIOS + 0x88E8: 0xB345, //HANGUL SYLLABLE TIKEUT YAE RIEULTHIEUTH + 0x88E9: 0xB346, //HANGUL SYLLABLE TIKEUT YAE RIEULPHIEUPH + 0x88EA: 0xB347, //HANGUL SYLLABLE TIKEUT YAE RIEULHIEUH + 0x88EB: 0xB348, //HANGUL SYLLABLE TIKEUT YAE MIEUM + 0x88EC: 0xB349, //HANGUL SYLLABLE TIKEUT YAE PIEUP + 0x88ED: 0xB34A, //HANGUL SYLLABLE TIKEUT YAE PIEUPSIOS + 0x88EE: 0xB34B, //HANGUL SYLLABLE TIKEUT YAE SIOS + 0x88EF: 0xB34C, //HANGUL SYLLABLE TIKEUT YAE SSANGSIOS + 0x88F0: 0xB34D, //HANGUL SYLLABLE TIKEUT YAE IEUNG + 0x88F1: 0xB34E, //HANGUL SYLLABLE TIKEUT YAE CIEUC + 0x88F2: 0xB34F, //HANGUL SYLLABLE TIKEUT YAE CHIEUCH + 0x88F3: 0xB350, //HANGUL SYLLABLE TIKEUT YAE KHIEUKH + 0x88F4: 0xB351, //HANGUL SYLLABLE TIKEUT YAE THIEUTH + 0x88F5: 0xB352, //HANGUL SYLLABLE TIKEUT YAE PHIEUPH + 0x88F6: 0xB353, //HANGUL SYLLABLE TIKEUT YAE HIEUH + 0x88F7: 0xB357, //HANGUL SYLLABLE TIKEUT EO KIYEOKSIOS + 0x88F8: 0xB359, //HANGUL SYLLABLE TIKEUT EO NIEUNCIEUC + 0x88F9: 0xB35A, //HANGUL SYLLABLE TIKEUT EO NIEUNHIEUH + 0x88FA: 0xB35D, //HANGUL SYLLABLE TIKEUT EO RIEULKIYEOK + 0x88FB: 0xB360, //HANGUL SYLLABLE TIKEUT EO RIEULSIOS + 0x88FC: 0xB361, //HANGUL SYLLABLE TIKEUT EO RIEULTHIEUTH + 0x88FD: 0xB362, //HANGUL SYLLABLE TIKEUT EO RIEULPHIEUPH + 0x88FE: 0xB363, //HANGUL SYLLABLE TIKEUT EO RIEULHIEUH + 0x8941: 0xB366, //HANGUL SYLLABLE TIKEUT EO PIEUPSIOS + 0x8942: 0xB368, //HANGUL SYLLABLE TIKEUT EO SSANGSIOS + 0x8943: 0xB36A, //HANGUL SYLLABLE TIKEUT EO CIEUC + 0x8944: 0xB36C, //HANGUL SYLLABLE TIKEUT EO KHIEUKH + 0x8945: 0xB36D, //HANGUL SYLLABLE TIKEUT EO THIEUTH + 0x8946: 0xB36F, //HANGUL SYLLABLE TIKEUT EO HIEUH + 0x8947: 0xB372, //HANGUL SYLLABLE TIKEUT E SSANGKIYEOK + 0x8948: 0xB373, //HANGUL SYLLABLE TIKEUT E KIYEOKSIOS + 0x8949: 0xB375, //HANGUL SYLLABLE TIKEUT E NIEUNCIEUC + 0x894A: 0xB376, //HANGUL SYLLABLE TIKEUT E NIEUNHIEUH + 0x894B: 0xB377, //HANGUL SYLLABLE TIKEUT E TIKEUT + 0x894C: 0xB379, //HANGUL SYLLABLE TIKEUT E RIEULKIYEOK + 0x894D: 0xB37A, //HANGUL SYLLABLE TIKEUT E RIEULMIEUM + 0x894E: 0xB37B, //HANGUL SYLLABLE TIKEUT E RIEULPIEUP + 0x894F: 0xB37C, //HANGUL SYLLABLE TIKEUT E RIEULSIOS + 0x8950: 0xB37D, //HANGUL SYLLABLE TIKEUT E RIEULTHIEUTH + 0x8951: 0xB37E, //HANGUL SYLLABLE TIKEUT E RIEULPHIEUPH + 0x8952: 0xB37F, //HANGUL SYLLABLE TIKEUT E RIEULHIEUH + 0x8953: 0xB382, //HANGUL SYLLABLE TIKEUT E PIEUPSIOS + 0x8954: 0xB386, //HANGUL SYLLABLE TIKEUT E CIEUC + 0x8955: 0xB387, //HANGUL SYLLABLE TIKEUT E CHIEUCH + 0x8956: 0xB388, //HANGUL SYLLABLE TIKEUT E KHIEUKH + 0x8957: 0xB389, //HANGUL SYLLABLE TIKEUT E THIEUTH + 0x8958: 0xB38A, //HANGUL SYLLABLE TIKEUT E PHIEUPH + 0x8959: 0xB38B, //HANGUL SYLLABLE TIKEUT E HIEUH + 0x895A: 0xB38D, //HANGUL SYLLABLE TIKEUT YEO KIYEOK + 0x8961: 0xB38E, //HANGUL SYLLABLE TIKEUT YEO SSANGKIYEOK + 0x8962: 0xB38F, //HANGUL SYLLABLE TIKEUT YEO KIYEOKSIOS + 0x8963: 0xB391, //HANGUL SYLLABLE TIKEUT YEO NIEUNCIEUC + 0x8964: 0xB392, //HANGUL SYLLABLE TIKEUT YEO NIEUNHIEUH + 0x8965: 0xB393, //HANGUL SYLLABLE TIKEUT YEO TIKEUT + 0x8966: 0xB395, //HANGUL SYLLABLE TIKEUT YEO RIEULKIYEOK + 0x8967: 0xB396, //HANGUL SYLLABLE TIKEUT YEO RIEULMIEUM + 0x8968: 0xB397, //HANGUL SYLLABLE TIKEUT YEO RIEULPIEUP + 0x8969: 0xB398, //HANGUL SYLLABLE TIKEUT YEO RIEULSIOS + 0x896A: 0xB399, //HANGUL SYLLABLE TIKEUT YEO RIEULTHIEUTH + 0x896B: 0xB39A, //HANGUL SYLLABLE TIKEUT YEO RIEULPHIEUPH + 0x896C: 0xB39B, //HANGUL SYLLABLE TIKEUT YEO RIEULHIEUH + 0x896D: 0xB39C, //HANGUL SYLLABLE TIKEUT YEO MIEUM + 0x896E: 0xB39D, //HANGUL SYLLABLE TIKEUT YEO PIEUP + 0x896F: 0xB39E, //HANGUL SYLLABLE TIKEUT YEO PIEUPSIOS + 0x8970: 0xB39F, //HANGUL SYLLABLE TIKEUT YEO SIOS + 0x8971: 0xB3A2, //HANGUL SYLLABLE TIKEUT YEO CIEUC + 0x8972: 0xB3A3, //HANGUL SYLLABLE TIKEUT YEO CHIEUCH + 0x8973: 0xB3A4, //HANGUL SYLLABLE TIKEUT YEO KHIEUKH + 0x8974: 0xB3A5, //HANGUL SYLLABLE TIKEUT YEO THIEUTH + 0x8975: 0xB3A6, //HANGUL SYLLABLE TIKEUT YEO PHIEUPH + 0x8976: 0xB3A7, //HANGUL SYLLABLE TIKEUT YEO HIEUH + 0x8977: 0xB3A9, //HANGUL SYLLABLE TIKEUT YE KIYEOK + 0x8978: 0xB3AA, //HANGUL SYLLABLE TIKEUT YE SSANGKIYEOK + 0x8979: 0xB3AB, //HANGUL SYLLABLE TIKEUT YE KIYEOKSIOS + 0x897A: 0xB3AD, //HANGUL SYLLABLE TIKEUT YE NIEUNCIEUC + 0x8981: 0xB3AE, //HANGUL SYLLABLE TIKEUT YE NIEUNHIEUH + 0x8982: 0xB3AF, //HANGUL SYLLABLE TIKEUT YE TIKEUT + 0x8983: 0xB3B0, //HANGUL SYLLABLE TIKEUT YE RIEUL + 0x8984: 0xB3B1, //HANGUL SYLLABLE TIKEUT YE RIEULKIYEOK + 0x8985: 0xB3B2, //HANGUL SYLLABLE TIKEUT YE RIEULMIEUM + 0x8986: 0xB3B3, //HANGUL SYLLABLE TIKEUT YE RIEULPIEUP + 0x8987: 0xB3B4, //HANGUL SYLLABLE TIKEUT YE RIEULSIOS + 0x8988: 0xB3B5, //HANGUL SYLLABLE TIKEUT YE RIEULTHIEUTH + 0x8989: 0xB3B6, //HANGUL SYLLABLE TIKEUT YE RIEULPHIEUPH + 0x898A: 0xB3B7, //HANGUL SYLLABLE TIKEUT YE RIEULHIEUH + 0x898B: 0xB3B8, //HANGUL SYLLABLE TIKEUT YE MIEUM + 0x898C: 0xB3B9, //HANGUL SYLLABLE TIKEUT YE PIEUP + 0x898D: 0xB3BA, //HANGUL SYLLABLE TIKEUT YE PIEUPSIOS + 0x898E: 0xB3BB, //HANGUL SYLLABLE TIKEUT YE SIOS + 0x898F: 0xB3BC, //HANGUL SYLLABLE TIKEUT YE SSANGSIOS + 0x8990: 0xB3BD, //HANGUL SYLLABLE TIKEUT YE IEUNG + 0x8991: 0xB3BE, //HANGUL SYLLABLE TIKEUT YE CIEUC + 0x8992: 0xB3BF, //HANGUL SYLLABLE TIKEUT YE CHIEUCH + 0x8993: 0xB3C0, //HANGUL SYLLABLE TIKEUT YE KHIEUKH + 0x8994: 0xB3C1, //HANGUL SYLLABLE TIKEUT YE THIEUTH + 0x8995: 0xB3C2, //HANGUL SYLLABLE TIKEUT YE PHIEUPH + 0x8996: 0xB3C3, //HANGUL SYLLABLE TIKEUT YE HIEUH + 0x8997: 0xB3C6, //HANGUL SYLLABLE TIKEUT O SSANGKIYEOK + 0x8998: 0xB3C7, //HANGUL SYLLABLE TIKEUT O KIYEOKSIOS + 0x8999: 0xB3C9, //HANGUL SYLLABLE TIKEUT O NIEUNCIEUC + 0x899A: 0xB3CA, //HANGUL SYLLABLE TIKEUT O NIEUNHIEUH + 0x899B: 0xB3CD, //HANGUL SYLLABLE TIKEUT O RIEULKIYEOK + 0x899C: 0xB3CF, //HANGUL SYLLABLE TIKEUT O RIEULPIEUP + 0x899D: 0xB3D1, //HANGUL SYLLABLE TIKEUT O RIEULTHIEUTH + 0x899E: 0xB3D2, //HANGUL SYLLABLE TIKEUT O RIEULPHIEUPH + 0x899F: 0xB3D3, //HANGUL SYLLABLE TIKEUT O RIEULHIEUH + 0x89A0: 0xB3D6, //HANGUL SYLLABLE TIKEUT O PIEUPSIOS + 0x89A1: 0xB3D8, //HANGUL SYLLABLE TIKEUT O SSANGSIOS + 0x89A2: 0xB3DA, //HANGUL SYLLABLE TIKEUT O CIEUC + 0x89A3: 0xB3DC, //HANGUL SYLLABLE TIKEUT O KHIEUKH + 0x89A4: 0xB3DE, //HANGUL SYLLABLE TIKEUT O PHIEUPH + 0x89A5: 0xB3DF, //HANGUL SYLLABLE TIKEUT O HIEUH + 0x89A6: 0xB3E1, //HANGUL SYLLABLE TIKEUT WA KIYEOK + 0x89A7: 0xB3E2, //HANGUL SYLLABLE TIKEUT WA SSANGKIYEOK + 0x89A8: 0xB3E3, //HANGUL SYLLABLE TIKEUT WA KIYEOKSIOS + 0x89A9: 0xB3E5, //HANGUL SYLLABLE TIKEUT WA NIEUNCIEUC + 0x89AA: 0xB3E6, //HANGUL SYLLABLE TIKEUT WA NIEUNHIEUH + 0x89AB: 0xB3E7, //HANGUL SYLLABLE TIKEUT WA TIKEUT + 0x89AC: 0xB3E9, //HANGUL SYLLABLE TIKEUT WA RIEULKIYEOK + 0x89AD: 0xB3EA, //HANGUL SYLLABLE TIKEUT WA RIEULMIEUM + 0x89AE: 0xB3EB, //HANGUL SYLLABLE TIKEUT WA RIEULPIEUP + 0x89AF: 0xB3EC, //HANGUL SYLLABLE TIKEUT WA RIEULSIOS + 0x89B0: 0xB3ED, //HANGUL SYLLABLE TIKEUT WA RIEULTHIEUTH + 0x89B1: 0xB3EE, //HANGUL SYLLABLE TIKEUT WA RIEULPHIEUPH + 0x89B2: 0xB3EF, //HANGUL SYLLABLE TIKEUT WA RIEULHIEUH + 0x89B3: 0xB3F0, //HANGUL SYLLABLE TIKEUT WA MIEUM + 0x89B4: 0xB3F1, //HANGUL SYLLABLE TIKEUT WA PIEUP + 0x89B5: 0xB3F2, //HANGUL SYLLABLE TIKEUT WA PIEUPSIOS + 0x89B6: 0xB3F3, //HANGUL SYLLABLE TIKEUT WA SIOS + 0x89B7: 0xB3F4, //HANGUL SYLLABLE TIKEUT WA SSANGSIOS + 0x89B8: 0xB3F5, //HANGUL SYLLABLE TIKEUT WA IEUNG + 0x89B9: 0xB3F6, //HANGUL SYLLABLE TIKEUT WA CIEUC + 0x89BA: 0xB3F7, //HANGUL SYLLABLE TIKEUT WA CHIEUCH + 0x89BB: 0xB3F8, //HANGUL SYLLABLE TIKEUT WA KHIEUKH + 0x89BC: 0xB3F9, //HANGUL SYLLABLE TIKEUT WA THIEUTH + 0x89BD: 0xB3FA, //HANGUL SYLLABLE TIKEUT WA PHIEUPH + 0x89BE: 0xB3FB, //HANGUL SYLLABLE TIKEUT WA HIEUH + 0x89BF: 0xB3FD, //HANGUL SYLLABLE TIKEUT WAE KIYEOK + 0x89C0: 0xB3FE, //HANGUL SYLLABLE TIKEUT WAE SSANGKIYEOK + 0x89C1: 0xB3FF, //HANGUL SYLLABLE TIKEUT WAE KIYEOKSIOS + 0x89C2: 0xB400, //HANGUL SYLLABLE TIKEUT WAE NIEUN + 0x89C3: 0xB401, //HANGUL SYLLABLE TIKEUT WAE NIEUNCIEUC + 0x89C4: 0xB402, //HANGUL SYLLABLE TIKEUT WAE NIEUNHIEUH + 0x89C5: 0xB403, //HANGUL SYLLABLE TIKEUT WAE TIKEUT + 0x89C6: 0xB404, //HANGUL SYLLABLE TIKEUT WAE RIEUL + 0x89C7: 0xB405, //HANGUL SYLLABLE TIKEUT WAE RIEULKIYEOK + 0x89C8: 0xB406, //HANGUL SYLLABLE TIKEUT WAE RIEULMIEUM + 0x89C9: 0xB407, //HANGUL SYLLABLE TIKEUT WAE RIEULPIEUP + 0x89CA: 0xB408, //HANGUL SYLLABLE TIKEUT WAE RIEULSIOS + 0x89CB: 0xB409, //HANGUL SYLLABLE TIKEUT WAE RIEULTHIEUTH + 0x89CC: 0xB40A, //HANGUL SYLLABLE TIKEUT WAE RIEULPHIEUPH + 0x89CD: 0xB40B, //HANGUL SYLLABLE TIKEUT WAE RIEULHIEUH + 0x89CE: 0xB40C, //HANGUL SYLLABLE TIKEUT WAE MIEUM + 0x89CF: 0xB40D, //HANGUL SYLLABLE TIKEUT WAE PIEUP + 0x89D0: 0xB40E, //HANGUL SYLLABLE TIKEUT WAE PIEUPSIOS + 0x89D1: 0xB40F, //HANGUL SYLLABLE TIKEUT WAE SIOS + 0x89D2: 0xB411, //HANGUL SYLLABLE TIKEUT WAE IEUNG + 0x89D3: 0xB412, //HANGUL SYLLABLE TIKEUT WAE CIEUC + 0x89D4: 0xB413, //HANGUL SYLLABLE TIKEUT WAE CHIEUCH + 0x89D5: 0xB414, //HANGUL SYLLABLE TIKEUT WAE KHIEUKH + 0x89D6: 0xB415, //HANGUL SYLLABLE TIKEUT WAE THIEUTH + 0x89D7: 0xB416, //HANGUL SYLLABLE TIKEUT WAE PHIEUPH + 0x89D8: 0xB417, //HANGUL SYLLABLE TIKEUT WAE HIEUH + 0x89D9: 0xB419, //HANGUL SYLLABLE TIKEUT OE KIYEOK + 0x89DA: 0xB41A, //HANGUL SYLLABLE TIKEUT OE SSANGKIYEOK + 0x89DB: 0xB41B, //HANGUL SYLLABLE TIKEUT OE KIYEOKSIOS + 0x89DC: 0xB41D, //HANGUL SYLLABLE TIKEUT OE NIEUNCIEUC + 0x89DD: 0xB41E, //HANGUL SYLLABLE TIKEUT OE NIEUNHIEUH + 0x89DE: 0xB41F, //HANGUL SYLLABLE TIKEUT OE TIKEUT + 0x89DF: 0xB421, //HANGUL SYLLABLE TIKEUT OE RIEULKIYEOK + 0x89E0: 0xB422, //HANGUL SYLLABLE TIKEUT OE RIEULMIEUM + 0x89E1: 0xB423, //HANGUL SYLLABLE TIKEUT OE RIEULPIEUP + 0x89E2: 0xB424, //HANGUL SYLLABLE TIKEUT OE RIEULSIOS + 0x89E3: 0xB425, //HANGUL SYLLABLE TIKEUT OE RIEULTHIEUTH + 0x89E4: 0xB426, //HANGUL SYLLABLE TIKEUT OE RIEULPHIEUPH + 0x89E5: 0xB427, //HANGUL SYLLABLE TIKEUT OE RIEULHIEUH + 0x89E6: 0xB42A, //HANGUL SYLLABLE TIKEUT OE PIEUPSIOS + 0x89E7: 0xB42C, //HANGUL SYLLABLE TIKEUT OE SSANGSIOS + 0x89E8: 0xB42D, //HANGUL SYLLABLE TIKEUT OE IEUNG + 0x89E9: 0xB42E, //HANGUL SYLLABLE TIKEUT OE CIEUC + 0x89EA: 0xB42F, //HANGUL SYLLABLE TIKEUT OE CHIEUCH + 0x89EB: 0xB430, //HANGUL SYLLABLE TIKEUT OE KHIEUKH + 0x89EC: 0xB431, //HANGUL SYLLABLE TIKEUT OE THIEUTH + 0x89ED: 0xB432, //HANGUL SYLLABLE TIKEUT OE PHIEUPH + 0x89EE: 0xB433, //HANGUL SYLLABLE TIKEUT OE HIEUH + 0x89EF: 0xB435, //HANGUL SYLLABLE TIKEUT YO KIYEOK + 0x89F0: 0xB436, //HANGUL SYLLABLE TIKEUT YO SSANGKIYEOK + 0x89F1: 0xB437, //HANGUL SYLLABLE TIKEUT YO KIYEOKSIOS + 0x89F2: 0xB438, //HANGUL SYLLABLE TIKEUT YO NIEUN + 0x89F3: 0xB439, //HANGUL SYLLABLE TIKEUT YO NIEUNCIEUC + 0x89F4: 0xB43A, //HANGUL SYLLABLE TIKEUT YO NIEUNHIEUH + 0x89F5: 0xB43B, //HANGUL SYLLABLE TIKEUT YO TIKEUT + 0x89F6: 0xB43C, //HANGUL SYLLABLE TIKEUT YO RIEUL + 0x89F7: 0xB43D, //HANGUL SYLLABLE TIKEUT YO RIEULKIYEOK + 0x89F8: 0xB43E, //HANGUL SYLLABLE TIKEUT YO RIEULMIEUM + 0x89F9: 0xB43F, //HANGUL SYLLABLE TIKEUT YO RIEULPIEUP + 0x89FA: 0xB440, //HANGUL SYLLABLE TIKEUT YO RIEULSIOS + 0x89FB: 0xB441, //HANGUL SYLLABLE TIKEUT YO RIEULTHIEUTH + 0x89FC: 0xB442, //HANGUL SYLLABLE TIKEUT YO RIEULPHIEUPH + 0x89FD: 0xB443, //HANGUL SYLLABLE TIKEUT YO RIEULHIEUH + 0x89FE: 0xB444, //HANGUL SYLLABLE TIKEUT YO MIEUM + 0x8A41: 0xB445, //HANGUL SYLLABLE TIKEUT YO PIEUP + 0x8A42: 0xB446, //HANGUL SYLLABLE TIKEUT YO PIEUPSIOS + 0x8A43: 0xB447, //HANGUL SYLLABLE TIKEUT YO SIOS + 0x8A44: 0xB448, //HANGUL SYLLABLE TIKEUT YO SSANGSIOS + 0x8A45: 0xB449, //HANGUL SYLLABLE TIKEUT YO IEUNG + 0x8A46: 0xB44A, //HANGUL SYLLABLE TIKEUT YO CIEUC + 0x8A47: 0xB44B, //HANGUL SYLLABLE TIKEUT YO CHIEUCH + 0x8A48: 0xB44C, //HANGUL SYLLABLE TIKEUT YO KHIEUKH + 0x8A49: 0xB44D, //HANGUL SYLLABLE TIKEUT YO THIEUTH + 0x8A4A: 0xB44E, //HANGUL SYLLABLE TIKEUT YO PHIEUPH + 0x8A4B: 0xB44F, //HANGUL SYLLABLE TIKEUT YO HIEUH + 0x8A4C: 0xB452, //HANGUL SYLLABLE TIKEUT U SSANGKIYEOK + 0x8A4D: 0xB453, //HANGUL SYLLABLE TIKEUT U KIYEOKSIOS + 0x8A4E: 0xB455, //HANGUL SYLLABLE TIKEUT U NIEUNCIEUC + 0x8A4F: 0xB456, //HANGUL SYLLABLE TIKEUT U NIEUNHIEUH + 0x8A50: 0xB457, //HANGUL SYLLABLE TIKEUT U TIKEUT + 0x8A51: 0xB459, //HANGUL SYLLABLE TIKEUT U RIEULKIYEOK + 0x8A52: 0xB45A, //HANGUL SYLLABLE TIKEUT U RIEULMIEUM + 0x8A53: 0xB45B, //HANGUL SYLLABLE TIKEUT U RIEULPIEUP + 0x8A54: 0xB45C, //HANGUL SYLLABLE TIKEUT U RIEULSIOS + 0x8A55: 0xB45D, //HANGUL SYLLABLE TIKEUT U RIEULTHIEUTH + 0x8A56: 0xB45E, //HANGUL SYLLABLE TIKEUT U RIEULPHIEUPH + 0x8A57: 0xB45F, //HANGUL SYLLABLE TIKEUT U RIEULHIEUH + 0x8A58: 0xB462, //HANGUL SYLLABLE TIKEUT U PIEUPSIOS + 0x8A59: 0xB464, //HANGUL SYLLABLE TIKEUT U SSANGSIOS + 0x8A5A: 0xB466, //HANGUL SYLLABLE TIKEUT U CIEUC + 0x8A61: 0xB467, //HANGUL SYLLABLE TIKEUT U CHIEUCH + 0x8A62: 0xB468, //HANGUL SYLLABLE TIKEUT U KHIEUKH + 0x8A63: 0xB469, //HANGUL SYLLABLE TIKEUT U THIEUTH + 0x8A64: 0xB46A, //HANGUL SYLLABLE TIKEUT U PHIEUPH + 0x8A65: 0xB46B, //HANGUL SYLLABLE TIKEUT U HIEUH + 0x8A66: 0xB46D, //HANGUL SYLLABLE TIKEUT WEO KIYEOK + 0x8A67: 0xB46E, //HANGUL SYLLABLE TIKEUT WEO SSANGKIYEOK + 0x8A68: 0xB46F, //HANGUL SYLLABLE TIKEUT WEO KIYEOKSIOS + 0x8A69: 0xB470, //HANGUL SYLLABLE TIKEUT WEO NIEUN + 0x8A6A: 0xB471, //HANGUL SYLLABLE TIKEUT WEO NIEUNCIEUC + 0x8A6B: 0xB472, //HANGUL SYLLABLE TIKEUT WEO NIEUNHIEUH + 0x8A6C: 0xB473, //HANGUL SYLLABLE TIKEUT WEO TIKEUT + 0x8A6D: 0xB474, //HANGUL SYLLABLE TIKEUT WEO RIEUL + 0x8A6E: 0xB475, //HANGUL SYLLABLE TIKEUT WEO RIEULKIYEOK + 0x8A6F: 0xB476, //HANGUL SYLLABLE TIKEUT WEO RIEULMIEUM + 0x8A70: 0xB477, //HANGUL SYLLABLE TIKEUT WEO RIEULPIEUP + 0x8A71: 0xB478, //HANGUL SYLLABLE TIKEUT WEO RIEULSIOS + 0x8A72: 0xB479, //HANGUL SYLLABLE TIKEUT WEO RIEULTHIEUTH + 0x8A73: 0xB47A, //HANGUL SYLLABLE TIKEUT WEO RIEULPHIEUPH + 0x8A74: 0xB47B, //HANGUL SYLLABLE TIKEUT WEO RIEULHIEUH + 0x8A75: 0xB47C, //HANGUL SYLLABLE TIKEUT WEO MIEUM + 0x8A76: 0xB47D, //HANGUL SYLLABLE TIKEUT WEO PIEUP + 0x8A77: 0xB47E, //HANGUL SYLLABLE TIKEUT WEO PIEUPSIOS + 0x8A78: 0xB47F, //HANGUL SYLLABLE TIKEUT WEO SIOS + 0x8A79: 0xB481, //HANGUL SYLLABLE TIKEUT WEO IEUNG + 0x8A7A: 0xB482, //HANGUL SYLLABLE TIKEUT WEO CIEUC + 0x8A81: 0xB483, //HANGUL SYLLABLE TIKEUT WEO CHIEUCH + 0x8A82: 0xB484, //HANGUL SYLLABLE TIKEUT WEO KHIEUKH + 0x8A83: 0xB485, //HANGUL SYLLABLE TIKEUT WEO THIEUTH + 0x8A84: 0xB486, //HANGUL SYLLABLE TIKEUT WEO PHIEUPH + 0x8A85: 0xB487, //HANGUL SYLLABLE TIKEUT WEO HIEUH + 0x8A86: 0xB489, //HANGUL SYLLABLE TIKEUT WE KIYEOK + 0x8A87: 0xB48A, //HANGUL SYLLABLE TIKEUT WE SSANGKIYEOK + 0x8A88: 0xB48B, //HANGUL SYLLABLE TIKEUT WE KIYEOKSIOS + 0x8A89: 0xB48C, //HANGUL SYLLABLE TIKEUT WE NIEUN + 0x8A8A: 0xB48D, //HANGUL SYLLABLE TIKEUT WE NIEUNCIEUC + 0x8A8B: 0xB48E, //HANGUL SYLLABLE TIKEUT WE NIEUNHIEUH + 0x8A8C: 0xB48F, //HANGUL SYLLABLE TIKEUT WE TIKEUT + 0x8A8D: 0xB490, //HANGUL SYLLABLE TIKEUT WE RIEUL + 0x8A8E: 0xB491, //HANGUL SYLLABLE TIKEUT WE RIEULKIYEOK + 0x8A8F: 0xB492, //HANGUL SYLLABLE TIKEUT WE RIEULMIEUM + 0x8A90: 0xB493, //HANGUL SYLLABLE TIKEUT WE RIEULPIEUP + 0x8A91: 0xB494, //HANGUL SYLLABLE TIKEUT WE RIEULSIOS + 0x8A92: 0xB495, //HANGUL SYLLABLE TIKEUT WE RIEULTHIEUTH + 0x8A93: 0xB496, //HANGUL SYLLABLE TIKEUT WE RIEULPHIEUPH + 0x8A94: 0xB497, //HANGUL SYLLABLE TIKEUT WE RIEULHIEUH + 0x8A95: 0xB498, //HANGUL SYLLABLE TIKEUT WE MIEUM + 0x8A96: 0xB499, //HANGUL SYLLABLE TIKEUT WE PIEUP + 0x8A97: 0xB49A, //HANGUL SYLLABLE TIKEUT WE PIEUPSIOS + 0x8A98: 0xB49B, //HANGUL SYLLABLE TIKEUT WE SIOS + 0x8A99: 0xB49C, //HANGUL SYLLABLE TIKEUT WE SSANGSIOS + 0x8A9A: 0xB49E, //HANGUL SYLLABLE TIKEUT WE CIEUC + 0x8A9B: 0xB49F, //HANGUL SYLLABLE TIKEUT WE CHIEUCH + 0x8A9C: 0xB4A0, //HANGUL SYLLABLE TIKEUT WE KHIEUKH + 0x8A9D: 0xB4A1, //HANGUL SYLLABLE TIKEUT WE THIEUTH + 0x8A9E: 0xB4A2, //HANGUL SYLLABLE TIKEUT WE PHIEUPH + 0x8A9F: 0xB4A3, //HANGUL SYLLABLE TIKEUT WE HIEUH + 0x8AA0: 0xB4A5, //HANGUL SYLLABLE TIKEUT WI KIYEOK + 0x8AA1: 0xB4A6, //HANGUL SYLLABLE TIKEUT WI SSANGKIYEOK + 0x8AA2: 0xB4A7, //HANGUL SYLLABLE TIKEUT WI KIYEOKSIOS + 0x8AA3: 0xB4A9, //HANGUL SYLLABLE TIKEUT WI NIEUNCIEUC + 0x8AA4: 0xB4AA, //HANGUL SYLLABLE TIKEUT WI NIEUNHIEUH + 0x8AA5: 0xB4AB, //HANGUL SYLLABLE TIKEUT WI TIKEUT + 0x8AA6: 0xB4AD, //HANGUL SYLLABLE TIKEUT WI RIEULKIYEOK + 0x8AA7: 0xB4AE, //HANGUL SYLLABLE TIKEUT WI RIEULMIEUM + 0x8AA8: 0xB4AF, //HANGUL SYLLABLE TIKEUT WI RIEULPIEUP + 0x8AA9: 0xB4B0, //HANGUL SYLLABLE TIKEUT WI RIEULSIOS + 0x8AAA: 0xB4B1, //HANGUL SYLLABLE TIKEUT WI RIEULTHIEUTH + 0x8AAB: 0xB4B2, //HANGUL SYLLABLE TIKEUT WI RIEULPHIEUPH + 0x8AAC: 0xB4B3, //HANGUL SYLLABLE TIKEUT WI RIEULHIEUH + 0x8AAD: 0xB4B4, //HANGUL SYLLABLE TIKEUT WI MIEUM + 0x8AAE: 0xB4B6, //HANGUL SYLLABLE TIKEUT WI PIEUPSIOS + 0x8AAF: 0xB4B8, //HANGUL SYLLABLE TIKEUT WI SSANGSIOS + 0x8AB0: 0xB4BA, //HANGUL SYLLABLE TIKEUT WI CIEUC + 0x8AB1: 0xB4BB, //HANGUL SYLLABLE TIKEUT WI CHIEUCH + 0x8AB2: 0xB4BC, //HANGUL SYLLABLE TIKEUT WI KHIEUKH + 0x8AB3: 0xB4BD, //HANGUL SYLLABLE TIKEUT WI THIEUTH + 0x8AB4: 0xB4BE, //HANGUL SYLLABLE TIKEUT WI PHIEUPH + 0x8AB5: 0xB4BF, //HANGUL SYLLABLE TIKEUT WI HIEUH + 0x8AB6: 0xB4C1, //HANGUL SYLLABLE TIKEUT YU KIYEOK + 0x8AB7: 0xB4C2, //HANGUL SYLLABLE TIKEUT YU SSANGKIYEOK + 0x8AB8: 0xB4C3, //HANGUL SYLLABLE TIKEUT YU KIYEOKSIOS + 0x8AB9: 0xB4C5, //HANGUL SYLLABLE TIKEUT YU NIEUNCIEUC + 0x8ABA: 0xB4C6, //HANGUL SYLLABLE TIKEUT YU NIEUNHIEUH + 0x8ABB: 0xB4C7, //HANGUL SYLLABLE TIKEUT YU TIKEUT + 0x8ABC: 0xB4C9, //HANGUL SYLLABLE TIKEUT YU RIEULKIYEOK + 0x8ABD: 0xB4CA, //HANGUL SYLLABLE TIKEUT YU RIEULMIEUM + 0x8ABE: 0xB4CB, //HANGUL SYLLABLE TIKEUT YU RIEULPIEUP + 0x8ABF: 0xB4CC, //HANGUL SYLLABLE TIKEUT YU RIEULSIOS + 0x8AC0: 0xB4CD, //HANGUL SYLLABLE TIKEUT YU RIEULTHIEUTH + 0x8AC1: 0xB4CE, //HANGUL SYLLABLE TIKEUT YU RIEULPHIEUPH + 0x8AC2: 0xB4CF, //HANGUL SYLLABLE TIKEUT YU RIEULHIEUH + 0x8AC3: 0xB4D1, //HANGUL SYLLABLE TIKEUT YU PIEUP + 0x8AC4: 0xB4D2, //HANGUL SYLLABLE TIKEUT YU PIEUPSIOS + 0x8AC5: 0xB4D3, //HANGUL SYLLABLE TIKEUT YU SIOS + 0x8AC6: 0xB4D4, //HANGUL SYLLABLE TIKEUT YU SSANGSIOS + 0x8AC7: 0xB4D6, //HANGUL SYLLABLE TIKEUT YU CIEUC + 0x8AC8: 0xB4D7, //HANGUL SYLLABLE TIKEUT YU CHIEUCH + 0x8AC9: 0xB4D8, //HANGUL SYLLABLE TIKEUT YU KHIEUKH + 0x8ACA: 0xB4D9, //HANGUL SYLLABLE TIKEUT YU THIEUTH + 0x8ACB: 0xB4DA, //HANGUL SYLLABLE TIKEUT YU PHIEUPH + 0x8ACC: 0xB4DB, //HANGUL SYLLABLE TIKEUT YU HIEUH + 0x8ACD: 0xB4DE, //HANGUL SYLLABLE TIKEUT EU SSANGKIYEOK + 0x8ACE: 0xB4DF, //HANGUL SYLLABLE TIKEUT EU KIYEOKSIOS + 0x8ACF: 0xB4E1, //HANGUL SYLLABLE TIKEUT EU NIEUNCIEUC + 0x8AD0: 0xB4E2, //HANGUL SYLLABLE TIKEUT EU NIEUNHIEUH + 0x8AD1: 0xB4E5, //HANGUL SYLLABLE TIKEUT EU RIEULKIYEOK + 0x8AD2: 0xB4E7, //HANGUL SYLLABLE TIKEUT EU RIEULPIEUP + 0x8AD3: 0xB4E8, //HANGUL SYLLABLE TIKEUT EU RIEULSIOS + 0x8AD4: 0xB4E9, //HANGUL SYLLABLE TIKEUT EU RIEULTHIEUTH + 0x8AD5: 0xB4EA, //HANGUL SYLLABLE TIKEUT EU RIEULPHIEUPH + 0x8AD6: 0xB4EB, //HANGUL SYLLABLE TIKEUT EU RIEULHIEUH + 0x8AD7: 0xB4EE, //HANGUL SYLLABLE TIKEUT EU PIEUPSIOS + 0x8AD8: 0xB4F0, //HANGUL SYLLABLE TIKEUT EU SSANGSIOS + 0x8AD9: 0xB4F2, //HANGUL SYLLABLE TIKEUT EU CIEUC + 0x8ADA: 0xB4F3, //HANGUL SYLLABLE TIKEUT EU CHIEUCH + 0x8ADB: 0xB4F4, //HANGUL SYLLABLE TIKEUT EU KHIEUKH + 0x8ADC: 0xB4F5, //HANGUL SYLLABLE TIKEUT EU THIEUTH + 0x8ADD: 0xB4F6, //HANGUL SYLLABLE TIKEUT EU PHIEUPH + 0x8ADE: 0xB4F7, //HANGUL SYLLABLE TIKEUT EU HIEUH + 0x8ADF: 0xB4F9, //HANGUL SYLLABLE TIKEUT YI KIYEOK + 0x8AE0: 0xB4FA, //HANGUL SYLLABLE TIKEUT YI SSANGKIYEOK + 0x8AE1: 0xB4FB, //HANGUL SYLLABLE TIKEUT YI KIYEOKSIOS + 0x8AE2: 0xB4FC, //HANGUL SYLLABLE TIKEUT YI NIEUN + 0x8AE3: 0xB4FD, //HANGUL SYLLABLE TIKEUT YI NIEUNCIEUC + 0x8AE4: 0xB4FE, //HANGUL SYLLABLE TIKEUT YI NIEUNHIEUH + 0x8AE5: 0xB4FF, //HANGUL SYLLABLE TIKEUT YI TIKEUT + 0x8AE6: 0xB500, //HANGUL SYLLABLE TIKEUT YI RIEUL + 0x8AE7: 0xB501, //HANGUL SYLLABLE TIKEUT YI RIEULKIYEOK + 0x8AE8: 0xB502, //HANGUL SYLLABLE TIKEUT YI RIEULMIEUM + 0x8AE9: 0xB503, //HANGUL SYLLABLE TIKEUT YI RIEULPIEUP + 0x8AEA: 0xB504, //HANGUL SYLLABLE TIKEUT YI RIEULSIOS + 0x8AEB: 0xB505, //HANGUL SYLLABLE TIKEUT YI RIEULTHIEUTH + 0x8AEC: 0xB506, //HANGUL SYLLABLE TIKEUT YI RIEULPHIEUPH + 0x8AED: 0xB507, //HANGUL SYLLABLE TIKEUT YI RIEULHIEUH + 0x8AEE: 0xB508, //HANGUL SYLLABLE TIKEUT YI MIEUM + 0x8AEF: 0xB509, //HANGUL SYLLABLE TIKEUT YI PIEUP + 0x8AF0: 0xB50A, //HANGUL SYLLABLE TIKEUT YI PIEUPSIOS + 0x8AF1: 0xB50B, //HANGUL SYLLABLE TIKEUT YI SIOS + 0x8AF2: 0xB50C, //HANGUL SYLLABLE TIKEUT YI SSANGSIOS + 0x8AF3: 0xB50D, //HANGUL SYLLABLE TIKEUT YI IEUNG + 0x8AF4: 0xB50E, //HANGUL SYLLABLE TIKEUT YI CIEUC + 0x8AF5: 0xB50F, //HANGUL SYLLABLE TIKEUT YI CHIEUCH + 0x8AF6: 0xB510, //HANGUL SYLLABLE TIKEUT YI KHIEUKH + 0x8AF7: 0xB511, //HANGUL SYLLABLE TIKEUT YI THIEUTH + 0x8AF8: 0xB512, //HANGUL SYLLABLE TIKEUT YI PHIEUPH + 0x8AF9: 0xB513, //HANGUL SYLLABLE TIKEUT YI HIEUH + 0x8AFA: 0xB516, //HANGUL SYLLABLE TIKEUT I SSANGKIYEOK + 0x8AFB: 0xB517, //HANGUL SYLLABLE TIKEUT I KIYEOKSIOS + 0x8AFC: 0xB519, //HANGUL SYLLABLE TIKEUT I NIEUNCIEUC + 0x8AFD: 0xB51A, //HANGUL SYLLABLE TIKEUT I NIEUNHIEUH + 0x8AFE: 0xB51D, //HANGUL SYLLABLE TIKEUT I RIEULKIYEOK + 0x8B41: 0xB51E, //HANGUL SYLLABLE TIKEUT I RIEULMIEUM + 0x8B42: 0xB51F, //HANGUL SYLLABLE TIKEUT I RIEULPIEUP + 0x8B43: 0xB520, //HANGUL SYLLABLE TIKEUT I RIEULSIOS + 0x8B44: 0xB521, //HANGUL SYLLABLE TIKEUT I RIEULTHIEUTH + 0x8B45: 0xB522, //HANGUL SYLLABLE TIKEUT I RIEULPHIEUPH + 0x8B46: 0xB523, //HANGUL SYLLABLE TIKEUT I RIEULHIEUH + 0x8B47: 0xB526, //HANGUL SYLLABLE TIKEUT I PIEUPSIOS + 0x8B48: 0xB52B, //HANGUL SYLLABLE TIKEUT I CHIEUCH + 0x8B49: 0xB52C, //HANGUL SYLLABLE TIKEUT I KHIEUKH + 0x8B4A: 0xB52D, //HANGUL SYLLABLE TIKEUT I THIEUTH + 0x8B4B: 0xB52E, //HANGUL SYLLABLE TIKEUT I PHIEUPH + 0x8B4C: 0xB52F, //HANGUL SYLLABLE TIKEUT I HIEUH + 0x8B4D: 0xB532, //HANGUL SYLLABLE SSANGTIKEUT A SSANGKIYEOK + 0x8B4E: 0xB533, //HANGUL SYLLABLE SSANGTIKEUT A KIYEOKSIOS + 0x8B4F: 0xB535, //HANGUL SYLLABLE SSANGTIKEUT A NIEUNCIEUC + 0x8B50: 0xB536, //HANGUL SYLLABLE SSANGTIKEUT A NIEUNHIEUH + 0x8B51: 0xB537, //HANGUL SYLLABLE SSANGTIKEUT A TIKEUT + 0x8B52: 0xB539, //HANGUL SYLLABLE SSANGTIKEUT A RIEULKIYEOK + 0x8B53: 0xB53A, //HANGUL SYLLABLE SSANGTIKEUT A RIEULMIEUM + 0x8B54: 0xB53B, //HANGUL SYLLABLE SSANGTIKEUT A RIEULPIEUP + 0x8B55: 0xB53C, //HANGUL SYLLABLE SSANGTIKEUT A RIEULSIOS + 0x8B56: 0xB53D, //HANGUL SYLLABLE SSANGTIKEUT A RIEULTHIEUTH + 0x8B57: 0xB53E, //HANGUL SYLLABLE SSANGTIKEUT A RIEULPHIEUPH + 0x8B58: 0xB53F, //HANGUL SYLLABLE SSANGTIKEUT A RIEULHIEUH + 0x8B59: 0xB542, //HANGUL SYLLABLE SSANGTIKEUT A PIEUPSIOS + 0x8B5A: 0xB546, //HANGUL SYLLABLE SSANGTIKEUT A CIEUC + 0x8B61: 0xB547, //HANGUL SYLLABLE SSANGTIKEUT A CHIEUCH + 0x8B62: 0xB548, //HANGUL SYLLABLE SSANGTIKEUT A KHIEUKH + 0x8B63: 0xB549, //HANGUL SYLLABLE SSANGTIKEUT A THIEUTH + 0x8B64: 0xB54A, //HANGUL SYLLABLE SSANGTIKEUT A PHIEUPH + 0x8B65: 0xB54E, //HANGUL SYLLABLE SSANGTIKEUT AE SSANGKIYEOK + 0x8B66: 0xB54F, //HANGUL SYLLABLE SSANGTIKEUT AE KIYEOKSIOS + 0x8B67: 0xB551, //HANGUL SYLLABLE SSANGTIKEUT AE NIEUNCIEUC + 0x8B68: 0xB552, //HANGUL SYLLABLE SSANGTIKEUT AE NIEUNHIEUH + 0x8B69: 0xB553, //HANGUL SYLLABLE SSANGTIKEUT AE TIKEUT + 0x8B6A: 0xB555, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULKIYEOK + 0x8B6B: 0xB556, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULMIEUM + 0x8B6C: 0xB557, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULPIEUP + 0x8B6D: 0xB558, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULSIOS + 0x8B6E: 0xB559, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULTHIEUTH + 0x8B6F: 0xB55A, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULPHIEUPH + 0x8B70: 0xB55B, //HANGUL SYLLABLE SSANGTIKEUT AE RIEULHIEUH + 0x8B71: 0xB55E, //HANGUL SYLLABLE SSANGTIKEUT AE PIEUPSIOS + 0x8B72: 0xB562, //HANGUL SYLLABLE SSANGTIKEUT AE CIEUC + 0x8B73: 0xB563, //HANGUL SYLLABLE SSANGTIKEUT AE CHIEUCH + 0x8B74: 0xB564, //HANGUL SYLLABLE SSANGTIKEUT AE KHIEUKH + 0x8B75: 0xB565, //HANGUL SYLLABLE SSANGTIKEUT AE THIEUTH + 0x8B76: 0xB566, //HANGUL SYLLABLE SSANGTIKEUT AE PHIEUPH + 0x8B77: 0xB567, //HANGUL SYLLABLE SSANGTIKEUT AE HIEUH + 0x8B78: 0xB568, //HANGUL SYLLABLE SSANGTIKEUT YA + 0x8B79: 0xB569, //HANGUL SYLLABLE SSANGTIKEUT YA KIYEOK + 0x8B7A: 0xB56A, //HANGUL SYLLABLE SSANGTIKEUT YA SSANGKIYEOK + 0x8B81: 0xB56B, //HANGUL SYLLABLE SSANGTIKEUT YA KIYEOKSIOS + 0x8B82: 0xB56C, //HANGUL SYLLABLE SSANGTIKEUT YA NIEUN + 0x8B83: 0xB56D, //HANGUL SYLLABLE SSANGTIKEUT YA NIEUNCIEUC + 0x8B84: 0xB56E, //HANGUL SYLLABLE SSANGTIKEUT YA NIEUNHIEUH + 0x8B85: 0xB56F, //HANGUL SYLLABLE SSANGTIKEUT YA TIKEUT + 0x8B86: 0xB570, //HANGUL SYLLABLE SSANGTIKEUT YA RIEUL + 0x8B87: 0xB571, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULKIYEOK + 0x8B88: 0xB572, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULMIEUM + 0x8B89: 0xB573, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULPIEUP + 0x8B8A: 0xB574, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULSIOS + 0x8B8B: 0xB575, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULTHIEUTH + 0x8B8C: 0xB576, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULPHIEUPH + 0x8B8D: 0xB577, //HANGUL SYLLABLE SSANGTIKEUT YA RIEULHIEUH + 0x8B8E: 0xB578, //HANGUL SYLLABLE SSANGTIKEUT YA MIEUM + 0x8B8F: 0xB579, //HANGUL SYLLABLE SSANGTIKEUT YA PIEUP + 0x8B90: 0xB57A, //HANGUL SYLLABLE SSANGTIKEUT YA PIEUPSIOS + 0x8B91: 0xB57B, //HANGUL SYLLABLE SSANGTIKEUT YA SIOS + 0x8B92: 0xB57C, //HANGUL SYLLABLE SSANGTIKEUT YA SSANGSIOS + 0x8B93: 0xB57D, //HANGUL SYLLABLE SSANGTIKEUT YA IEUNG + 0x8B94: 0xB57E, //HANGUL SYLLABLE SSANGTIKEUT YA CIEUC + 0x8B95: 0xB57F, //HANGUL SYLLABLE SSANGTIKEUT YA CHIEUCH + 0x8B96: 0xB580, //HANGUL SYLLABLE SSANGTIKEUT YA KHIEUKH + 0x8B97: 0xB581, //HANGUL SYLLABLE SSANGTIKEUT YA THIEUTH + 0x8B98: 0xB582, //HANGUL SYLLABLE SSANGTIKEUT YA PHIEUPH + 0x8B99: 0xB583, //HANGUL SYLLABLE SSANGTIKEUT YA HIEUH + 0x8B9A: 0xB584, //HANGUL SYLLABLE SSANGTIKEUT YAE + 0x8B9B: 0xB585, //HANGUL SYLLABLE SSANGTIKEUT YAE KIYEOK + 0x8B9C: 0xB586, //HANGUL SYLLABLE SSANGTIKEUT YAE SSANGKIYEOK + 0x8B9D: 0xB587, //HANGUL SYLLABLE SSANGTIKEUT YAE KIYEOKSIOS + 0x8B9E: 0xB588, //HANGUL SYLLABLE SSANGTIKEUT YAE NIEUN + 0x8B9F: 0xB589, //HANGUL SYLLABLE SSANGTIKEUT YAE NIEUNCIEUC + 0x8BA0: 0xB58A, //HANGUL SYLLABLE SSANGTIKEUT YAE NIEUNHIEUH + 0x8BA1: 0xB58B, //HANGUL SYLLABLE SSANGTIKEUT YAE TIKEUT + 0x8BA2: 0xB58C, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEUL + 0x8BA3: 0xB58D, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULKIYEOK + 0x8BA4: 0xB58E, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULMIEUM + 0x8BA5: 0xB58F, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULPIEUP + 0x8BA6: 0xB590, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULSIOS + 0x8BA7: 0xB591, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULTHIEUTH + 0x8BA8: 0xB592, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULPHIEUPH + 0x8BA9: 0xB593, //HANGUL SYLLABLE SSANGTIKEUT YAE RIEULHIEUH + 0x8BAA: 0xB594, //HANGUL SYLLABLE SSANGTIKEUT YAE MIEUM + 0x8BAB: 0xB595, //HANGUL SYLLABLE SSANGTIKEUT YAE PIEUP + 0x8BAC: 0xB596, //HANGUL SYLLABLE SSANGTIKEUT YAE PIEUPSIOS + 0x8BAD: 0xB597, //HANGUL SYLLABLE SSANGTIKEUT YAE SIOS + 0x8BAE: 0xB598, //HANGUL SYLLABLE SSANGTIKEUT YAE SSANGSIOS + 0x8BAF: 0xB599, //HANGUL SYLLABLE SSANGTIKEUT YAE IEUNG + 0x8BB0: 0xB59A, //HANGUL SYLLABLE SSANGTIKEUT YAE CIEUC + 0x8BB1: 0xB59B, //HANGUL SYLLABLE SSANGTIKEUT YAE CHIEUCH + 0x8BB2: 0xB59C, //HANGUL SYLLABLE SSANGTIKEUT YAE KHIEUKH + 0x8BB3: 0xB59D, //HANGUL SYLLABLE SSANGTIKEUT YAE THIEUTH + 0x8BB4: 0xB59E, //HANGUL SYLLABLE SSANGTIKEUT YAE PHIEUPH + 0x8BB5: 0xB59F, //HANGUL SYLLABLE SSANGTIKEUT YAE HIEUH + 0x8BB6: 0xB5A2, //HANGUL SYLLABLE SSANGTIKEUT EO SSANGKIYEOK + 0x8BB7: 0xB5A3, //HANGUL SYLLABLE SSANGTIKEUT EO KIYEOKSIOS + 0x8BB8: 0xB5A5, //HANGUL SYLLABLE SSANGTIKEUT EO NIEUNCIEUC + 0x8BB9: 0xB5A6, //HANGUL SYLLABLE SSANGTIKEUT EO NIEUNHIEUH + 0x8BBA: 0xB5A7, //HANGUL SYLLABLE SSANGTIKEUT EO TIKEUT + 0x8BBB: 0xB5A9, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULKIYEOK + 0x8BBC: 0xB5AC, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULSIOS + 0x8BBD: 0xB5AD, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULTHIEUTH + 0x8BBE: 0xB5AE, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULPHIEUPH + 0x8BBF: 0xB5AF, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULHIEUH + 0x8BC0: 0xB5B2, //HANGUL SYLLABLE SSANGTIKEUT EO PIEUPSIOS + 0x8BC1: 0xB5B6, //HANGUL SYLLABLE SSANGTIKEUT EO CIEUC + 0x8BC2: 0xB5B7, //HANGUL SYLLABLE SSANGTIKEUT EO CHIEUCH + 0x8BC3: 0xB5B8, //HANGUL SYLLABLE SSANGTIKEUT EO KHIEUKH + 0x8BC4: 0xB5B9, //HANGUL SYLLABLE SSANGTIKEUT EO THIEUTH + 0x8BC5: 0xB5BA, //HANGUL SYLLABLE SSANGTIKEUT EO PHIEUPH + 0x8BC6: 0xB5BE, //HANGUL SYLLABLE SSANGTIKEUT E SSANGKIYEOK + 0x8BC7: 0xB5BF, //HANGUL SYLLABLE SSANGTIKEUT E KIYEOKSIOS + 0x8BC8: 0xB5C1, //HANGUL SYLLABLE SSANGTIKEUT E NIEUNCIEUC + 0x8BC9: 0xB5C2, //HANGUL SYLLABLE SSANGTIKEUT E NIEUNHIEUH + 0x8BCA: 0xB5C3, //HANGUL SYLLABLE SSANGTIKEUT E TIKEUT + 0x8BCB: 0xB5C5, //HANGUL SYLLABLE SSANGTIKEUT E RIEULKIYEOK + 0x8BCC: 0xB5C6, //HANGUL SYLLABLE SSANGTIKEUT E RIEULMIEUM + 0x8BCD: 0xB5C7, //HANGUL SYLLABLE SSANGTIKEUT E RIEULPIEUP + 0x8BCE: 0xB5C8, //HANGUL SYLLABLE SSANGTIKEUT E RIEULSIOS + 0x8BCF: 0xB5C9, //HANGUL SYLLABLE SSANGTIKEUT E RIEULTHIEUTH + 0x8BD0: 0xB5CA, //HANGUL SYLLABLE SSANGTIKEUT E RIEULPHIEUPH + 0x8BD1: 0xB5CB, //HANGUL SYLLABLE SSANGTIKEUT E RIEULHIEUH + 0x8BD2: 0xB5CE, //HANGUL SYLLABLE SSANGTIKEUT E PIEUPSIOS + 0x8BD3: 0xB5D2, //HANGUL SYLLABLE SSANGTIKEUT E CIEUC + 0x8BD4: 0xB5D3, //HANGUL SYLLABLE SSANGTIKEUT E CHIEUCH + 0x8BD5: 0xB5D4, //HANGUL SYLLABLE SSANGTIKEUT E KHIEUKH + 0x8BD6: 0xB5D5, //HANGUL SYLLABLE SSANGTIKEUT E THIEUTH + 0x8BD7: 0xB5D6, //HANGUL SYLLABLE SSANGTIKEUT E PHIEUPH + 0x8BD8: 0xB5D7, //HANGUL SYLLABLE SSANGTIKEUT E HIEUH + 0x8BD9: 0xB5D9, //HANGUL SYLLABLE SSANGTIKEUT YEO KIYEOK + 0x8BDA: 0xB5DA, //HANGUL SYLLABLE SSANGTIKEUT YEO SSANGKIYEOK + 0x8BDB: 0xB5DB, //HANGUL SYLLABLE SSANGTIKEUT YEO KIYEOKSIOS + 0x8BDC: 0xB5DC, //HANGUL SYLLABLE SSANGTIKEUT YEO NIEUN + 0x8BDD: 0xB5DD, //HANGUL SYLLABLE SSANGTIKEUT YEO NIEUNCIEUC + 0x8BDE: 0xB5DE, //HANGUL SYLLABLE SSANGTIKEUT YEO NIEUNHIEUH + 0x8BDF: 0xB5DF, //HANGUL SYLLABLE SSANGTIKEUT YEO TIKEUT + 0x8BE0: 0xB5E0, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEUL + 0x8BE1: 0xB5E1, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULKIYEOK + 0x8BE2: 0xB5E2, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULMIEUM + 0x8BE3: 0xB5E3, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULPIEUP + 0x8BE4: 0xB5E4, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULSIOS + 0x8BE5: 0xB5E5, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULTHIEUTH + 0x8BE6: 0xB5E6, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULPHIEUPH + 0x8BE7: 0xB5E7, //HANGUL SYLLABLE SSANGTIKEUT YEO RIEULHIEUH + 0x8BE8: 0xB5E8, //HANGUL SYLLABLE SSANGTIKEUT YEO MIEUM + 0x8BE9: 0xB5E9, //HANGUL SYLLABLE SSANGTIKEUT YEO PIEUP + 0x8BEA: 0xB5EA, //HANGUL SYLLABLE SSANGTIKEUT YEO PIEUPSIOS + 0x8BEB: 0xB5EB, //HANGUL SYLLABLE SSANGTIKEUT YEO SIOS + 0x8BEC: 0xB5ED, //HANGUL SYLLABLE SSANGTIKEUT YEO IEUNG + 0x8BED: 0xB5EE, //HANGUL SYLLABLE SSANGTIKEUT YEO CIEUC + 0x8BEE: 0xB5EF, //HANGUL SYLLABLE SSANGTIKEUT YEO CHIEUCH + 0x8BEF: 0xB5F0, //HANGUL SYLLABLE SSANGTIKEUT YEO KHIEUKH + 0x8BF0: 0xB5F1, //HANGUL SYLLABLE SSANGTIKEUT YEO THIEUTH + 0x8BF1: 0xB5F2, //HANGUL SYLLABLE SSANGTIKEUT YEO PHIEUPH + 0x8BF2: 0xB5F3, //HANGUL SYLLABLE SSANGTIKEUT YEO HIEUH + 0x8BF3: 0xB5F4, //HANGUL SYLLABLE SSANGTIKEUT YE + 0x8BF4: 0xB5F5, //HANGUL SYLLABLE SSANGTIKEUT YE KIYEOK + 0x8BF5: 0xB5F6, //HANGUL SYLLABLE SSANGTIKEUT YE SSANGKIYEOK + 0x8BF6: 0xB5F7, //HANGUL SYLLABLE SSANGTIKEUT YE KIYEOKSIOS + 0x8BF7: 0xB5F8, //HANGUL SYLLABLE SSANGTIKEUT YE NIEUN + 0x8BF8: 0xB5F9, //HANGUL SYLLABLE SSANGTIKEUT YE NIEUNCIEUC + 0x8BF9: 0xB5FA, //HANGUL SYLLABLE SSANGTIKEUT YE NIEUNHIEUH + 0x8BFA: 0xB5FB, //HANGUL SYLLABLE SSANGTIKEUT YE TIKEUT + 0x8BFB: 0xB5FC, //HANGUL SYLLABLE SSANGTIKEUT YE RIEUL + 0x8BFC: 0xB5FD, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULKIYEOK + 0x8BFD: 0xB5FE, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULMIEUM + 0x8BFE: 0xB5FF, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULPIEUP + 0x8C41: 0xB600, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULSIOS + 0x8C42: 0xB601, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULTHIEUTH + 0x8C43: 0xB602, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULPHIEUPH + 0x8C44: 0xB603, //HANGUL SYLLABLE SSANGTIKEUT YE RIEULHIEUH + 0x8C45: 0xB604, //HANGUL SYLLABLE SSANGTIKEUT YE MIEUM + 0x8C46: 0xB605, //HANGUL SYLLABLE SSANGTIKEUT YE PIEUP + 0x8C47: 0xB606, //HANGUL SYLLABLE SSANGTIKEUT YE PIEUPSIOS + 0x8C48: 0xB607, //HANGUL SYLLABLE SSANGTIKEUT YE SIOS + 0x8C49: 0xB608, //HANGUL SYLLABLE SSANGTIKEUT YE SSANGSIOS + 0x8C4A: 0xB609, //HANGUL SYLLABLE SSANGTIKEUT YE IEUNG + 0x8C4B: 0xB60A, //HANGUL SYLLABLE SSANGTIKEUT YE CIEUC + 0x8C4C: 0xB60B, //HANGUL SYLLABLE SSANGTIKEUT YE CHIEUCH + 0x8C4D: 0xB60C, //HANGUL SYLLABLE SSANGTIKEUT YE KHIEUKH + 0x8C4E: 0xB60D, //HANGUL SYLLABLE SSANGTIKEUT YE THIEUTH + 0x8C4F: 0xB60E, //HANGUL SYLLABLE SSANGTIKEUT YE PHIEUPH + 0x8C50: 0xB60F, //HANGUL SYLLABLE SSANGTIKEUT YE HIEUH + 0x8C51: 0xB612, //HANGUL SYLLABLE SSANGTIKEUT O SSANGKIYEOK + 0x8C52: 0xB613, //HANGUL SYLLABLE SSANGTIKEUT O KIYEOKSIOS + 0x8C53: 0xB615, //HANGUL SYLLABLE SSANGTIKEUT O NIEUNCIEUC + 0x8C54: 0xB616, //HANGUL SYLLABLE SSANGTIKEUT O NIEUNHIEUH + 0x8C55: 0xB617, //HANGUL SYLLABLE SSANGTIKEUT O TIKEUT + 0x8C56: 0xB619, //HANGUL SYLLABLE SSANGTIKEUT O RIEULKIYEOK + 0x8C57: 0xB61A, //HANGUL SYLLABLE SSANGTIKEUT O RIEULMIEUM + 0x8C58: 0xB61B, //HANGUL SYLLABLE SSANGTIKEUT O RIEULPIEUP + 0x8C59: 0xB61C, //HANGUL SYLLABLE SSANGTIKEUT O RIEULSIOS + 0x8C5A: 0xB61D, //HANGUL SYLLABLE SSANGTIKEUT O RIEULTHIEUTH + 0x8C61: 0xB61E, //HANGUL SYLLABLE SSANGTIKEUT O RIEULPHIEUPH + 0x8C62: 0xB61F, //HANGUL SYLLABLE SSANGTIKEUT O RIEULHIEUH + 0x8C63: 0xB620, //HANGUL SYLLABLE SSANGTIKEUT O MIEUM + 0x8C64: 0xB621, //HANGUL SYLLABLE SSANGTIKEUT O PIEUP + 0x8C65: 0xB622, //HANGUL SYLLABLE SSANGTIKEUT O PIEUPSIOS + 0x8C66: 0xB623, //HANGUL SYLLABLE SSANGTIKEUT O SIOS + 0x8C67: 0xB624, //HANGUL SYLLABLE SSANGTIKEUT O SSANGSIOS + 0x8C68: 0xB626, //HANGUL SYLLABLE SSANGTIKEUT O CIEUC + 0x8C69: 0xB627, //HANGUL SYLLABLE SSANGTIKEUT O CHIEUCH + 0x8C6A: 0xB628, //HANGUL SYLLABLE SSANGTIKEUT O KHIEUKH + 0x8C6B: 0xB629, //HANGUL SYLLABLE SSANGTIKEUT O THIEUTH + 0x8C6C: 0xB62A, //HANGUL SYLLABLE SSANGTIKEUT O PHIEUPH + 0x8C6D: 0xB62B, //HANGUL SYLLABLE SSANGTIKEUT O HIEUH + 0x8C6E: 0xB62D, //HANGUL SYLLABLE SSANGTIKEUT WA KIYEOK + 0x8C6F: 0xB62E, //HANGUL SYLLABLE SSANGTIKEUT WA SSANGKIYEOK + 0x8C70: 0xB62F, //HANGUL SYLLABLE SSANGTIKEUT WA KIYEOKSIOS + 0x8C71: 0xB630, //HANGUL SYLLABLE SSANGTIKEUT WA NIEUN + 0x8C72: 0xB631, //HANGUL SYLLABLE SSANGTIKEUT WA NIEUNCIEUC + 0x8C73: 0xB632, //HANGUL SYLLABLE SSANGTIKEUT WA NIEUNHIEUH + 0x8C74: 0xB633, //HANGUL SYLLABLE SSANGTIKEUT WA TIKEUT + 0x8C75: 0xB635, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULKIYEOK + 0x8C76: 0xB636, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULMIEUM + 0x8C77: 0xB637, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULPIEUP + 0x8C78: 0xB638, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULSIOS + 0x8C79: 0xB639, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULTHIEUTH + 0x8C7A: 0xB63A, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULPHIEUPH + 0x8C81: 0xB63B, //HANGUL SYLLABLE SSANGTIKEUT WA RIEULHIEUH + 0x8C82: 0xB63C, //HANGUL SYLLABLE SSANGTIKEUT WA MIEUM + 0x8C83: 0xB63D, //HANGUL SYLLABLE SSANGTIKEUT WA PIEUP + 0x8C84: 0xB63E, //HANGUL SYLLABLE SSANGTIKEUT WA PIEUPSIOS + 0x8C85: 0xB63F, //HANGUL SYLLABLE SSANGTIKEUT WA SIOS + 0x8C86: 0xB640, //HANGUL SYLLABLE SSANGTIKEUT WA SSANGSIOS + 0x8C87: 0xB641, //HANGUL SYLLABLE SSANGTIKEUT WA IEUNG + 0x8C88: 0xB642, //HANGUL SYLLABLE SSANGTIKEUT WA CIEUC + 0x8C89: 0xB643, //HANGUL SYLLABLE SSANGTIKEUT WA CHIEUCH + 0x8C8A: 0xB644, //HANGUL SYLLABLE SSANGTIKEUT WA KHIEUKH + 0x8C8B: 0xB645, //HANGUL SYLLABLE SSANGTIKEUT WA THIEUTH + 0x8C8C: 0xB646, //HANGUL SYLLABLE SSANGTIKEUT WA PHIEUPH + 0x8C8D: 0xB647, //HANGUL SYLLABLE SSANGTIKEUT WA HIEUH + 0x8C8E: 0xB649, //HANGUL SYLLABLE SSANGTIKEUT WAE KIYEOK + 0x8C8F: 0xB64A, //HANGUL SYLLABLE SSANGTIKEUT WAE SSANGKIYEOK + 0x8C90: 0xB64B, //HANGUL SYLLABLE SSANGTIKEUT WAE KIYEOKSIOS + 0x8C91: 0xB64C, //HANGUL SYLLABLE SSANGTIKEUT WAE NIEUN + 0x8C92: 0xB64D, //HANGUL SYLLABLE SSANGTIKEUT WAE NIEUNCIEUC + 0x8C93: 0xB64E, //HANGUL SYLLABLE SSANGTIKEUT WAE NIEUNHIEUH + 0x8C94: 0xB64F, //HANGUL SYLLABLE SSANGTIKEUT WAE TIKEUT + 0x8C95: 0xB650, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEUL + 0x8C96: 0xB651, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULKIYEOK + 0x8C97: 0xB652, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULMIEUM + 0x8C98: 0xB653, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULPIEUP + 0x8C99: 0xB654, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULSIOS + 0x8C9A: 0xB655, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULTHIEUTH + 0x8C9B: 0xB656, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULPHIEUPH + 0x8C9C: 0xB657, //HANGUL SYLLABLE SSANGTIKEUT WAE RIEULHIEUH + 0x8C9D: 0xB658, //HANGUL SYLLABLE SSANGTIKEUT WAE MIEUM + 0x8C9E: 0xB659, //HANGUL SYLLABLE SSANGTIKEUT WAE PIEUP + 0x8C9F: 0xB65A, //HANGUL SYLLABLE SSANGTIKEUT WAE PIEUPSIOS + 0x8CA0: 0xB65B, //HANGUL SYLLABLE SSANGTIKEUT WAE SIOS + 0x8CA1: 0xB65C, //HANGUL SYLLABLE SSANGTIKEUT WAE SSANGSIOS + 0x8CA2: 0xB65D, //HANGUL SYLLABLE SSANGTIKEUT WAE IEUNG + 0x8CA3: 0xB65E, //HANGUL SYLLABLE SSANGTIKEUT WAE CIEUC + 0x8CA4: 0xB65F, //HANGUL SYLLABLE SSANGTIKEUT WAE CHIEUCH + 0x8CA5: 0xB660, //HANGUL SYLLABLE SSANGTIKEUT WAE KHIEUKH + 0x8CA6: 0xB661, //HANGUL SYLLABLE SSANGTIKEUT WAE THIEUTH + 0x8CA7: 0xB662, //HANGUL SYLLABLE SSANGTIKEUT WAE PHIEUPH + 0x8CA8: 0xB663, //HANGUL SYLLABLE SSANGTIKEUT WAE HIEUH + 0x8CA9: 0xB665, //HANGUL SYLLABLE SSANGTIKEUT OE KIYEOK + 0x8CAA: 0xB666, //HANGUL SYLLABLE SSANGTIKEUT OE SSANGKIYEOK + 0x8CAB: 0xB667, //HANGUL SYLLABLE SSANGTIKEUT OE KIYEOKSIOS + 0x8CAC: 0xB669, //HANGUL SYLLABLE SSANGTIKEUT OE NIEUNCIEUC + 0x8CAD: 0xB66A, //HANGUL SYLLABLE SSANGTIKEUT OE NIEUNHIEUH + 0x8CAE: 0xB66B, //HANGUL SYLLABLE SSANGTIKEUT OE TIKEUT + 0x8CAF: 0xB66C, //HANGUL SYLLABLE SSANGTIKEUT OE RIEUL + 0x8CB0: 0xB66D, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULKIYEOK + 0x8CB1: 0xB66E, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULMIEUM + 0x8CB2: 0xB66F, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULPIEUP + 0x8CB3: 0xB670, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULSIOS + 0x8CB4: 0xB671, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULTHIEUTH + 0x8CB5: 0xB672, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULPHIEUPH + 0x8CB6: 0xB673, //HANGUL SYLLABLE SSANGTIKEUT OE RIEULHIEUH + 0x8CB7: 0xB674, //HANGUL SYLLABLE SSANGTIKEUT OE MIEUM + 0x8CB8: 0xB675, //HANGUL SYLLABLE SSANGTIKEUT OE PIEUP + 0x8CB9: 0xB676, //HANGUL SYLLABLE SSANGTIKEUT OE PIEUPSIOS + 0x8CBA: 0xB677, //HANGUL SYLLABLE SSANGTIKEUT OE SIOS + 0x8CBB: 0xB678, //HANGUL SYLLABLE SSANGTIKEUT OE SSANGSIOS + 0x8CBC: 0xB679, //HANGUL SYLLABLE SSANGTIKEUT OE IEUNG + 0x8CBD: 0xB67A, //HANGUL SYLLABLE SSANGTIKEUT OE CIEUC + 0x8CBE: 0xB67B, //HANGUL SYLLABLE SSANGTIKEUT OE CHIEUCH + 0x8CBF: 0xB67C, //HANGUL SYLLABLE SSANGTIKEUT OE KHIEUKH + 0x8CC0: 0xB67D, //HANGUL SYLLABLE SSANGTIKEUT OE THIEUTH + 0x8CC1: 0xB67E, //HANGUL SYLLABLE SSANGTIKEUT OE PHIEUPH + 0x8CC2: 0xB67F, //HANGUL SYLLABLE SSANGTIKEUT OE HIEUH + 0x8CC3: 0xB680, //HANGUL SYLLABLE SSANGTIKEUT YO + 0x8CC4: 0xB681, //HANGUL SYLLABLE SSANGTIKEUT YO KIYEOK + 0x8CC5: 0xB682, //HANGUL SYLLABLE SSANGTIKEUT YO SSANGKIYEOK + 0x8CC6: 0xB683, //HANGUL SYLLABLE SSANGTIKEUT YO KIYEOKSIOS + 0x8CC7: 0xB684, //HANGUL SYLLABLE SSANGTIKEUT YO NIEUN + 0x8CC8: 0xB685, //HANGUL SYLLABLE SSANGTIKEUT YO NIEUNCIEUC + 0x8CC9: 0xB686, //HANGUL SYLLABLE SSANGTIKEUT YO NIEUNHIEUH + 0x8CCA: 0xB687, //HANGUL SYLLABLE SSANGTIKEUT YO TIKEUT + 0x8CCB: 0xB688, //HANGUL SYLLABLE SSANGTIKEUT YO RIEUL + 0x8CCC: 0xB689, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULKIYEOK + 0x8CCD: 0xB68A, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULMIEUM + 0x8CCE: 0xB68B, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULPIEUP + 0x8CCF: 0xB68C, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULSIOS + 0x8CD0: 0xB68D, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULTHIEUTH + 0x8CD1: 0xB68E, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULPHIEUPH + 0x8CD2: 0xB68F, //HANGUL SYLLABLE SSANGTIKEUT YO RIEULHIEUH + 0x8CD3: 0xB690, //HANGUL SYLLABLE SSANGTIKEUT YO MIEUM + 0x8CD4: 0xB691, //HANGUL SYLLABLE SSANGTIKEUT YO PIEUP + 0x8CD5: 0xB692, //HANGUL SYLLABLE SSANGTIKEUT YO PIEUPSIOS + 0x8CD6: 0xB693, //HANGUL SYLLABLE SSANGTIKEUT YO SIOS + 0x8CD7: 0xB694, //HANGUL SYLLABLE SSANGTIKEUT YO SSANGSIOS + 0x8CD8: 0xB695, //HANGUL SYLLABLE SSANGTIKEUT YO IEUNG + 0x8CD9: 0xB696, //HANGUL SYLLABLE SSANGTIKEUT YO CIEUC + 0x8CDA: 0xB697, //HANGUL SYLLABLE SSANGTIKEUT YO CHIEUCH + 0x8CDB: 0xB698, //HANGUL SYLLABLE SSANGTIKEUT YO KHIEUKH + 0x8CDC: 0xB699, //HANGUL SYLLABLE SSANGTIKEUT YO THIEUTH + 0x8CDD: 0xB69A, //HANGUL SYLLABLE SSANGTIKEUT YO PHIEUPH + 0x8CDE: 0xB69B, //HANGUL SYLLABLE SSANGTIKEUT YO HIEUH + 0x8CDF: 0xB69E, //HANGUL SYLLABLE SSANGTIKEUT U SSANGKIYEOK + 0x8CE0: 0xB69F, //HANGUL SYLLABLE SSANGTIKEUT U KIYEOKSIOS + 0x8CE1: 0xB6A1, //HANGUL SYLLABLE SSANGTIKEUT U NIEUNCIEUC + 0x8CE2: 0xB6A2, //HANGUL SYLLABLE SSANGTIKEUT U NIEUNHIEUH + 0x8CE3: 0xB6A3, //HANGUL SYLLABLE SSANGTIKEUT U TIKEUT + 0x8CE4: 0xB6A5, //HANGUL SYLLABLE SSANGTIKEUT U RIEULKIYEOK + 0x8CE5: 0xB6A6, //HANGUL SYLLABLE SSANGTIKEUT U RIEULMIEUM + 0x8CE6: 0xB6A7, //HANGUL SYLLABLE SSANGTIKEUT U RIEULPIEUP + 0x8CE7: 0xB6A8, //HANGUL SYLLABLE SSANGTIKEUT U RIEULSIOS + 0x8CE8: 0xB6A9, //HANGUL SYLLABLE SSANGTIKEUT U RIEULTHIEUTH + 0x8CE9: 0xB6AA, //HANGUL SYLLABLE SSANGTIKEUT U RIEULPHIEUPH + 0x8CEA: 0xB6AD, //HANGUL SYLLABLE SSANGTIKEUT U PIEUP + 0x8CEB: 0xB6AE, //HANGUL SYLLABLE SSANGTIKEUT U PIEUPSIOS + 0x8CEC: 0xB6AF, //HANGUL SYLLABLE SSANGTIKEUT U SIOS + 0x8CED: 0xB6B0, //HANGUL SYLLABLE SSANGTIKEUT U SSANGSIOS + 0x8CEE: 0xB6B2, //HANGUL SYLLABLE SSANGTIKEUT U CIEUC + 0x8CEF: 0xB6B3, //HANGUL SYLLABLE SSANGTIKEUT U CHIEUCH + 0x8CF0: 0xB6B4, //HANGUL SYLLABLE SSANGTIKEUT U KHIEUKH + 0x8CF1: 0xB6B5, //HANGUL SYLLABLE SSANGTIKEUT U THIEUTH + 0x8CF2: 0xB6B6, //HANGUL SYLLABLE SSANGTIKEUT U PHIEUPH + 0x8CF3: 0xB6B7, //HANGUL SYLLABLE SSANGTIKEUT U HIEUH + 0x8CF4: 0xB6B8, //HANGUL SYLLABLE SSANGTIKEUT WEO + 0x8CF5: 0xB6B9, //HANGUL SYLLABLE SSANGTIKEUT WEO KIYEOK + 0x8CF6: 0xB6BA, //HANGUL SYLLABLE SSANGTIKEUT WEO SSANGKIYEOK + 0x8CF7: 0xB6BB, //HANGUL SYLLABLE SSANGTIKEUT WEO KIYEOKSIOS + 0x8CF8: 0xB6BC, //HANGUL SYLLABLE SSANGTIKEUT WEO NIEUN + 0x8CF9: 0xB6BD, //HANGUL SYLLABLE SSANGTIKEUT WEO NIEUNCIEUC + 0x8CFA: 0xB6BE, //HANGUL SYLLABLE SSANGTIKEUT WEO NIEUNHIEUH + 0x8CFB: 0xB6BF, //HANGUL SYLLABLE SSANGTIKEUT WEO TIKEUT + 0x8CFC: 0xB6C0, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEUL + 0x8CFD: 0xB6C1, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULKIYEOK + 0x8CFE: 0xB6C2, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULMIEUM + 0x8D41: 0xB6C3, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULPIEUP + 0x8D42: 0xB6C4, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULSIOS + 0x8D43: 0xB6C5, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULTHIEUTH + 0x8D44: 0xB6C6, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULPHIEUPH + 0x8D45: 0xB6C7, //HANGUL SYLLABLE SSANGTIKEUT WEO RIEULHIEUH + 0x8D46: 0xB6C8, //HANGUL SYLLABLE SSANGTIKEUT WEO MIEUM + 0x8D47: 0xB6C9, //HANGUL SYLLABLE SSANGTIKEUT WEO PIEUP + 0x8D48: 0xB6CA, //HANGUL SYLLABLE SSANGTIKEUT WEO PIEUPSIOS + 0x8D49: 0xB6CB, //HANGUL SYLLABLE SSANGTIKEUT WEO SIOS + 0x8D4A: 0xB6CC, //HANGUL SYLLABLE SSANGTIKEUT WEO SSANGSIOS + 0x8D4B: 0xB6CD, //HANGUL SYLLABLE SSANGTIKEUT WEO IEUNG + 0x8D4C: 0xB6CE, //HANGUL SYLLABLE SSANGTIKEUT WEO CIEUC + 0x8D4D: 0xB6CF, //HANGUL SYLLABLE SSANGTIKEUT WEO CHIEUCH + 0x8D4E: 0xB6D0, //HANGUL SYLLABLE SSANGTIKEUT WEO KHIEUKH + 0x8D4F: 0xB6D1, //HANGUL SYLLABLE SSANGTIKEUT WEO THIEUTH + 0x8D50: 0xB6D2, //HANGUL SYLLABLE SSANGTIKEUT WEO PHIEUPH + 0x8D51: 0xB6D3, //HANGUL SYLLABLE SSANGTIKEUT WEO HIEUH + 0x8D52: 0xB6D5, //HANGUL SYLLABLE SSANGTIKEUT WE KIYEOK + 0x8D53: 0xB6D6, //HANGUL SYLLABLE SSANGTIKEUT WE SSANGKIYEOK + 0x8D54: 0xB6D7, //HANGUL SYLLABLE SSANGTIKEUT WE KIYEOKSIOS + 0x8D55: 0xB6D8, //HANGUL SYLLABLE SSANGTIKEUT WE NIEUN + 0x8D56: 0xB6D9, //HANGUL SYLLABLE SSANGTIKEUT WE NIEUNCIEUC + 0x8D57: 0xB6DA, //HANGUL SYLLABLE SSANGTIKEUT WE NIEUNHIEUH + 0x8D58: 0xB6DB, //HANGUL SYLLABLE SSANGTIKEUT WE TIKEUT + 0x8D59: 0xB6DC, //HANGUL SYLLABLE SSANGTIKEUT WE RIEUL + 0x8D5A: 0xB6DD, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULKIYEOK + 0x8D61: 0xB6DE, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULMIEUM + 0x8D62: 0xB6DF, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULPIEUP + 0x8D63: 0xB6E0, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULSIOS + 0x8D64: 0xB6E1, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULTHIEUTH + 0x8D65: 0xB6E2, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULPHIEUPH + 0x8D66: 0xB6E3, //HANGUL SYLLABLE SSANGTIKEUT WE RIEULHIEUH + 0x8D67: 0xB6E4, //HANGUL SYLLABLE SSANGTIKEUT WE MIEUM + 0x8D68: 0xB6E5, //HANGUL SYLLABLE SSANGTIKEUT WE PIEUP + 0x8D69: 0xB6E6, //HANGUL SYLLABLE SSANGTIKEUT WE PIEUPSIOS + 0x8D6A: 0xB6E7, //HANGUL SYLLABLE SSANGTIKEUT WE SIOS + 0x8D6B: 0xB6E8, //HANGUL SYLLABLE SSANGTIKEUT WE SSANGSIOS + 0x8D6C: 0xB6E9, //HANGUL SYLLABLE SSANGTIKEUT WE IEUNG + 0x8D6D: 0xB6EA, //HANGUL SYLLABLE SSANGTIKEUT WE CIEUC + 0x8D6E: 0xB6EB, //HANGUL SYLLABLE SSANGTIKEUT WE CHIEUCH + 0x8D6F: 0xB6EC, //HANGUL SYLLABLE SSANGTIKEUT WE KHIEUKH + 0x8D70: 0xB6ED, //HANGUL SYLLABLE SSANGTIKEUT WE THIEUTH + 0x8D71: 0xB6EE, //HANGUL SYLLABLE SSANGTIKEUT WE PHIEUPH + 0x8D72: 0xB6EF, //HANGUL SYLLABLE SSANGTIKEUT WE HIEUH + 0x8D73: 0xB6F1, //HANGUL SYLLABLE SSANGTIKEUT WI KIYEOK + 0x8D74: 0xB6F2, //HANGUL SYLLABLE SSANGTIKEUT WI SSANGKIYEOK + 0x8D75: 0xB6F3, //HANGUL SYLLABLE SSANGTIKEUT WI KIYEOKSIOS + 0x8D76: 0xB6F5, //HANGUL SYLLABLE SSANGTIKEUT WI NIEUNCIEUC + 0x8D77: 0xB6F6, //HANGUL SYLLABLE SSANGTIKEUT WI NIEUNHIEUH + 0x8D78: 0xB6F7, //HANGUL SYLLABLE SSANGTIKEUT WI TIKEUT + 0x8D79: 0xB6F9, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULKIYEOK + 0x8D7A: 0xB6FA, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULMIEUM + 0x8D81: 0xB6FB, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULPIEUP + 0x8D82: 0xB6FC, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULSIOS + 0x8D83: 0xB6FD, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULTHIEUTH + 0x8D84: 0xB6FE, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULPHIEUPH + 0x8D85: 0xB6FF, //HANGUL SYLLABLE SSANGTIKEUT WI RIEULHIEUH + 0x8D86: 0xB702, //HANGUL SYLLABLE SSANGTIKEUT WI PIEUPSIOS + 0x8D87: 0xB703, //HANGUL SYLLABLE SSANGTIKEUT WI SIOS + 0x8D88: 0xB704, //HANGUL SYLLABLE SSANGTIKEUT WI SSANGSIOS + 0x8D89: 0xB706, //HANGUL SYLLABLE SSANGTIKEUT WI CIEUC + 0x8D8A: 0xB707, //HANGUL SYLLABLE SSANGTIKEUT WI CHIEUCH + 0x8D8B: 0xB708, //HANGUL SYLLABLE SSANGTIKEUT WI KHIEUKH + 0x8D8C: 0xB709, //HANGUL SYLLABLE SSANGTIKEUT WI THIEUTH + 0x8D8D: 0xB70A, //HANGUL SYLLABLE SSANGTIKEUT WI PHIEUPH + 0x8D8E: 0xB70B, //HANGUL SYLLABLE SSANGTIKEUT WI HIEUH + 0x8D8F: 0xB70C, //HANGUL SYLLABLE SSANGTIKEUT YU + 0x8D90: 0xB70D, //HANGUL SYLLABLE SSANGTIKEUT YU KIYEOK + 0x8D91: 0xB70E, //HANGUL SYLLABLE SSANGTIKEUT YU SSANGKIYEOK + 0x8D92: 0xB70F, //HANGUL SYLLABLE SSANGTIKEUT YU KIYEOKSIOS + 0x8D93: 0xB710, //HANGUL SYLLABLE SSANGTIKEUT YU NIEUN + 0x8D94: 0xB711, //HANGUL SYLLABLE SSANGTIKEUT YU NIEUNCIEUC + 0x8D95: 0xB712, //HANGUL SYLLABLE SSANGTIKEUT YU NIEUNHIEUH + 0x8D96: 0xB713, //HANGUL SYLLABLE SSANGTIKEUT YU TIKEUT + 0x8D97: 0xB714, //HANGUL SYLLABLE SSANGTIKEUT YU RIEUL + 0x8D98: 0xB715, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULKIYEOK + 0x8D99: 0xB716, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULMIEUM + 0x8D9A: 0xB717, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULPIEUP + 0x8D9B: 0xB718, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULSIOS + 0x8D9C: 0xB719, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULTHIEUTH + 0x8D9D: 0xB71A, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULPHIEUPH + 0x8D9E: 0xB71B, //HANGUL SYLLABLE SSANGTIKEUT YU RIEULHIEUH + 0x8D9F: 0xB71C, //HANGUL SYLLABLE SSANGTIKEUT YU MIEUM + 0x8DA0: 0xB71D, //HANGUL SYLLABLE SSANGTIKEUT YU PIEUP + 0x8DA1: 0xB71E, //HANGUL SYLLABLE SSANGTIKEUT YU PIEUPSIOS + 0x8DA2: 0xB71F, //HANGUL SYLLABLE SSANGTIKEUT YU SIOS + 0x8DA3: 0xB720, //HANGUL SYLLABLE SSANGTIKEUT YU SSANGSIOS + 0x8DA4: 0xB721, //HANGUL SYLLABLE SSANGTIKEUT YU IEUNG + 0x8DA5: 0xB722, //HANGUL SYLLABLE SSANGTIKEUT YU CIEUC + 0x8DA6: 0xB723, //HANGUL SYLLABLE SSANGTIKEUT YU CHIEUCH + 0x8DA7: 0xB724, //HANGUL SYLLABLE SSANGTIKEUT YU KHIEUKH + 0x8DA8: 0xB725, //HANGUL SYLLABLE SSANGTIKEUT YU THIEUTH + 0x8DA9: 0xB726, //HANGUL SYLLABLE SSANGTIKEUT YU PHIEUPH + 0x8DAA: 0xB727, //HANGUL SYLLABLE SSANGTIKEUT YU HIEUH + 0x8DAB: 0xB72A, //HANGUL SYLLABLE SSANGTIKEUT EU SSANGKIYEOK + 0x8DAC: 0xB72B, //HANGUL SYLLABLE SSANGTIKEUT EU KIYEOKSIOS + 0x8DAD: 0xB72D, //HANGUL SYLLABLE SSANGTIKEUT EU NIEUNCIEUC + 0x8DAE: 0xB72E, //HANGUL SYLLABLE SSANGTIKEUT EU NIEUNHIEUH + 0x8DAF: 0xB731, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULKIYEOK + 0x8DB0: 0xB732, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULMIEUM + 0x8DB1: 0xB733, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULPIEUP + 0x8DB2: 0xB734, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULSIOS + 0x8DB3: 0xB735, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULTHIEUTH + 0x8DB4: 0xB736, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULPHIEUPH + 0x8DB5: 0xB737, //HANGUL SYLLABLE SSANGTIKEUT EU RIEULHIEUH + 0x8DB6: 0xB73A, //HANGUL SYLLABLE SSANGTIKEUT EU PIEUPSIOS + 0x8DB7: 0xB73C, //HANGUL SYLLABLE SSANGTIKEUT EU SSANGSIOS + 0x8DB8: 0xB73D, //HANGUL SYLLABLE SSANGTIKEUT EU IEUNG + 0x8DB9: 0xB73E, //HANGUL SYLLABLE SSANGTIKEUT EU CIEUC + 0x8DBA: 0xB73F, //HANGUL SYLLABLE SSANGTIKEUT EU CHIEUCH + 0x8DBB: 0xB740, //HANGUL SYLLABLE SSANGTIKEUT EU KHIEUKH + 0x8DBC: 0xB741, //HANGUL SYLLABLE SSANGTIKEUT EU THIEUTH + 0x8DBD: 0xB742, //HANGUL SYLLABLE SSANGTIKEUT EU PHIEUPH + 0x8DBE: 0xB743, //HANGUL SYLLABLE SSANGTIKEUT EU HIEUH + 0x8DBF: 0xB745, //HANGUL SYLLABLE SSANGTIKEUT YI KIYEOK + 0x8DC0: 0xB746, //HANGUL SYLLABLE SSANGTIKEUT YI SSANGKIYEOK + 0x8DC1: 0xB747, //HANGUL SYLLABLE SSANGTIKEUT YI KIYEOKSIOS + 0x8DC2: 0xB749, //HANGUL SYLLABLE SSANGTIKEUT YI NIEUNCIEUC + 0x8DC3: 0xB74A, //HANGUL SYLLABLE SSANGTIKEUT YI NIEUNHIEUH + 0x8DC4: 0xB74B, //HANGUL SYLLABLE SSANGTIKEUT YI TIKEUT + 0x8DC5: 0xB74D, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULKIYEOK + 0x8DC6: 0xB74E, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULMIEUM + 0x8DC7: 0xB74F, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULPIEUP + 0x8DC8: 0xB750, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULSIOS + 0x8DC9: 0xB751, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULTHIEUTH + 0x8DCA: 0xB752, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULPHIEUPH + 0x8DCB: 0xB753, //HANGUL SYLLABLE SSANGTIKEUT YI RIEULHIEUH + 0x8DCC: 0xB756, //HANGUL SYLLABLE SSANGTIKEUT YI PIEUPSIOS + 0x8DCD: 0xB757, //HANGUL SYLLABLE SSANGTIKEUT YI SIOS + 0x8DCE: 0xB758, //HANGUL SYLLABLE SSANGTIKEUT YI SSANGSIOS + 0x8DCF: 0xB759, //HANGUL SYLLABLE SSANGTIKEUT YI IEUNG + 0x8DD0: 0xB75A, //HANGUL SYLLABLE SSANGTIKEUT YI CIEUC + 0x8DD1: 0xB75B, //HANGUL SYLLABLE SSANGTIKEUT YI CHIEUCH + 0x8DD2: 0xB75C, //HANGUL SYLLABLE SSANGTIKEUT YI KHIEUKH + 0x8DD3: 0xB75D, //HANGUL SYLLABLE SSANGTIKEUT YI THIEUTH + 0x8DD4: 0xB75E, //HANGUL SYLLABLE SSANGTIKEUT YI PHIEUPH + 0x8DD5: 0xB75F, //HANGUL SYLLABLE SSANGTIKEUT YI HIEUH + 0x8DD6: 0xB761, //HANGUL SYLLABLE SSANGTIKEUT I KIYEOK + 0x8DD7: 0xB762, //HANGUL SYLLABLE SSANGTIKEUT I SSANGKIYEOK + 0x8DD8: 0xB763, //HANGUL SYLLABLE SSANGTIKEUT I KIYEOKSIOS + 0x8DD9: 0xB765, //HANGUL SYLLABLE SSANGTIKEUT I NIEUNCIEUC + 0x8DDA: 0xB766, //HANGUL SYLLABLE SSANGTIKEUT I NIEUNHIEUH + 0x8DDB: 0xB767, //HANGUL SYLLABLE SSANGTIKEUT I TIKEUT + 0x8DDC: 0xB769, //HANGUL SYLLABLE SSANGTIKEUT I RIEULKIYEOK + 0x8DDD: 0xB76A, //HANGUL SYLLABLE SSANGTIKEUT I RIEULMIEUM + 0x8DDE: 0xB76B, //HANGUL SYLLABLE SSANGTIKEUT I RIEULPIEUP + 0x8DDF: 0xB76C, //HANGUL SYLLABLE SSANGTIKEUT I RIEULSIOS + 0x8DE0: 0xB76D, //HANGUL SYLLABLE SSANGTIKEUT I RIEULTHIEUTH + 0x8DE1: 0xB76E, //HANGUL SYLLABLE SSANGTIKEUT I RIEULPHIEUPH + 0x8DE2: 0xB76F, //HANGUL SYLLABLE SSANGTIKEUT I RIEULHIEUH + 0x8DE3: 0xB772, //HANGUL SYLLABLE SSANGTIKEUT I PIEUPSIOS + 0x8DE4: 0xB774, //HANGUL SYLLABLE SSANGTIKEUT I SSANGSIOS + 0x8DE5: 0xB776, //HANGUL SYLLABLE SSANGTIKEUT I CIEUC + 0x8DE6: 0xB777, //HANGUL SYLLABLE SSANGTIKEUT I CHIEUCH + 0x8DE7: 0xB778, //HANGUL SYLLABLE SSANGTIKEUT I KHIEUKH + 0x8DE8: 0xB779, //HANGUL SYLLABLE SSANGTIKEUT I THIEUTH + 0x8DE9: 0xB77A, //HANGUL SYLLABLE SSANGTIKEUT I PHIEUPH + 0x8DEA: 0xB77B, //HANGUL SYLLABLE SSANGTIKEUT I HIEUH + 0x8DEB: 0xB77E, //HANGUL SYLLABLE RIEUL A SSANGKIYEOK + 0x8DEC: 0xB77F, //HANGUL SYLLABLE RIEUL A KIYEOKSIOS + 0x8DED: 0xB781, //HANGUL SYLLABLE RIEUL A NIEUNCIEUC + 0x8DEE: 0xB782, //HANGUL SYLLABLE RIEUL A NIEUNHIEUH + 0x8DEF: 0xB783, //HANGUL SYLLABLE RIEUL A TIKEUT + 0x8DF0: 0xB785, //HANGUL SYLLABLE RIEUL A RIEULKIYEOK + 0x8DF1: 0xB786, //HANGUL SYLLABLE RIEUL A RIEULMIEUM + 0x8DF2: 0xB787, //HANGUL SYLLABLE RIEUL A RIEULPIEUP + 0x8DF3: 0xB788, //HANGUL SYLLABLE RIEUL A RIEULSIOS + 0x8DF4: 0xB789, //HANGUL SYLLABLE RIEUL A RIEULTHIEUTH + 0x8DF5: 0xB78A, //HANGUL SYLLABLE RIEUL A RIEULPHIEUPH + 0x8DF6: 0xB78B, //HANGUL SYLLABLE RIEUL A RIEULHIEUH + 0x8DF7: 0xB78E, //HANGUL SYLLABLE RIEUL A PIEUPSIOS + 0x8DF8: 0xB793, //HANGUL SYLLABLE RIEUL A CHIEUCH + 0x8DF9: 0xB794, //HANGUL SYLLABLE RIEUL A KHIEUKH + 0x8DFA: 0xB795, //HANGUL SYLLABLE RIEUL A THIEUTH + 0x8DFB: 0xB79A, //HANGUL SYLLABLE RIEUL AE SSANGKIYEOK + 0x8DFC: 0xB79B, //HANGUL SYLLABLE RIEUL AE KIYEOKSIOS + 0x8DFD: 0xB79D, //HANGUL SYLLABLE RIEUL AE NIEUNCIEUC + 0x8DFE: 0xB79E, //HANGUL SYLLABLE RIEUL AE NIEUNHIEUH + 0x8E41: 0xB79F, //HANGUL SYLLABLE RIEUL AE TIKEUT + 0x8E42: 0xB7A1, //HANGUL SYLLABLE RIEUL AE RIEULKIYEOK + 0x8E43: 0xB7A2, //HANGUL SYLLABLE RIEUL AE RIEULMIEUM + 0x8E44: 0xB7A3, //HANGUL SYLLABLE RIEUL AE RIEULPIEUP + 0x8E45: 0xB7A4, //HANGUL SYLLABLE RIEUL AE RIEULSIOS + 0x8E46: 0xB7A5, //HANGUL SYLLABLE RIEUL AE RIEULTHIEUTH + 0x8E47: 0xB7A6, //HANGUL SYLLABLE RIEUL AE RIEULPHIEUPH + 0x8E48: 0xB7A7, //HANGUL SYLLABLE RIEUL AE RIEULHIEUH + 0x8E49: 0xB7AA, //HANGUL SYLLABLE RIEUL AE PIEUPSIOS + 0x8E4A: 0xB7AE, //HANGUL SYLLABLE RIEUL AE CIEUC + 0x8E4B: 0xB7AF, //HANGUL SYLLABLE RIEUL AE CHIEUCH + 0x8E4C: 0xB7B0, //HANGUL SYLLABLE RIEUL AE KHIEUKH + 0x8E4D: 0xB7B1, //HANGUL SYLLABLE RIEUL AE THIEUTH + 0x8E4E: 0xB7B2, //HANGUL SYLLABLE RIEUL AE PHIEUPH + 0x8E4F: 0xB7B3, //HANGUL SYLLABLE RIEUL AE HIEUH + 0x8E50: 0xB7B6, //HANGUL SYLLABLE RIEUL YA SSANGKIYEOK + 0x8E51: 0xB7B7, //HANGUL SYLLABLE RIEUL YA KIYEOKSIOS + 0x8E52: 0xB7B9, //HANGUL SYLLABLE RIEUL YA NIEUNCIEUC + 0x8E53: 0xB7BA, //HANGUL SYLLABLE RIEUL YA NIEUNHIEUH + 0x8E54: 0xB7BB, //HANGUL SYLLABLE RIEUL YA TIKEUT + 0x8E55: 0xB7BC, //HANGUL SYLLABLE RIEUL YA RIEUL + 0x8E56: 0xB7BD, //HANGUL SYLLABLE RIEUL YA RIEULKIYEOK + 0x8E57: 0xB7BE, //HANGUL SYLLABLE RIEUL YA RIEULMIEUM + 0x8E58: 0xB7BF, //HANGUL SYLLABLE RIEUL YA RIEULPIEUP + 0x8E59: 0xB7C0, //HANGUL SYLLABLE RIEUL YA RIEULSIOS + 0x8E5A: 0xB7C1, //HANGUL SYLLABLE RIEUL YA RIEULTHIEUTH + 0x8E61: 0xB7C2, //HANGUL SYLLABLE RIEUL YA RIEULPHIEUPH + 0x8E62: 0xB7C3, //HANGUL SYLLABLE RIEUL YA RIEULHIEUH + 0x8E63: 0xB7C4, //HANGUL SYLLABLE RIEUL YA MIEUM + 0x8E64: 0xB7C5, //HANGUL SYLLABLE RIEUL YA PIEUP + 0x8E65: 0xB7C6, //HANGUL SYLLABLE RIEUL YA PIEUPSIOS + 0x8E66: 0xB7C8, //HANGUL SYLLABLE RIEUL YA SSANGSIOS + 0x8E67: 0xB7CA, //HANGUL SYLLABLE RIEUL YA CIEUC + 0x8E68: 0xB7CB, //HANGUL SYLLABLE RIEUL YA CHIEUCH + 0x8E69: 0xB7CC, //HANGUL SYLLABLE RIEUL YA KHIEUKH + 0x8E6A: 0xB7CD, //HANGUL SYLLABLE RIEUL YA THIEUTH + 0x8E6B: 0xB7CE, //HANGUL SYLLABLE RIEUL YA PHIEUPH + 0x8E6C: 0xB7CF, //HANGUL SYLLABLE RIEUL YA HIEUH + 0x8E6D: 0xB7D0, //HANGUL SYLLABLE RIEUL YAE + 0x8E6E: 0xB7D1, //HANGUL SYLLABLE RIEUL YAE KIYEOK + 0x8E6F: 0xB7D2, //HANGUL SYLLABLE RIEUL YAE SSANGKIYEOK + 0x8E70: 0xB7D3, //HANGUL SYLLABLE RIEUL YAE KIYEOKSIOS + 0x8E71: 0xB7D4, //HANGUL SYLLABLE RIEUL YAE NIEUN + 0x8E72: 0xB7D5, //HANGUL SYLLABLE RIEUL YAE NIEUNCIEUC + 0x8E73: 0xB7D6, //HANGUL SYLLABLE RIEUL YAE NIEUNHIEUH + 0x8E74: 0xB7D7, //HANGUL SYLLABLE RIEUL YAE TIKEUT + 0x8E75: 0xB7D8, //HANGUL SYLLABLE RIEUL YAE RIEUL + 0x8E76: 0xB7D9, //HANGUL SYLLABLE RIEUL YAE RIEULKIYEOK + 0x8E77: 0xB7DA, //HANGUL SYLLABLE RIEUL YAE RIEULMIEUM + 0x8E78: 0xB7DB, //HANGUL SYLLABLE RIEUL YAE RIEULPIEUP + 0x8E79: 0xB7DC, //HANGUL SYLLABLE RIEUL YAE RIEULSIOS + 0x8E7A: 0xB7DD, //HANGUL SYLLABLE RIEUL YAE RIEULTHIEUTH + 0x8E81: 0xB7DE, //HANGUL SYLLABLE RIEUL YAE RIEULPHIEUPH + 0x8E82: 0xB7DF, //HANGUL SYLLABLE RIEUL YAE RIEULHIEUH + 0x8E83: 0xB7E0, //HANGUL SYLLABLE RIEUL YAE MIEUM + 0x8E84: 0xB7E1, //HANGUL SYLLABLE RIEUL YAE PIEUP + 0x8E85: 0xB7E2, //HANGUL SYLLABLE RIEUL YAE PIEUPSIOS + 0x8E86: 0xB7E3, //HANGUL SYLLABLE RIEUL YAE SIOS + 0x8E87: 0xB7E4, //HANGUL SYLLABLE RIEUL YAE SSANGSIOS + 0x8E88: 0xB7E5, //HANGUL SYLLABLE RIEUL YAE IEUNG + 0x8E89: 0xB7E6, //HANGUL SYLLABLE RIEUL YAE CIEUC + 0x8E8A: 0xB7E7, //HANGUL SYLLABLE RIEUL YAE CHIEUCH + 0x8E8B: 0xB7E8, //HANGUL SYLLABLE RIEUL YAE KHIEUKH + 0x8E8C: 0xB7E9, //HANGUL SYLLABLE RIEUL YAE THIEUTH + 0x8E8D: 0xB7EA, //HANGUL SYLLABLE RIEUL YAE PHIEUPH + 0x8E8E: 0xB7EB, //HANGUL SYLLABLE RIEUL YAE HIEUH + 0x8E8F: 0xB7EE, //HANGUL SYLLABLE RIEUL EO SSANGKIYEOK + 0x8E90: 0xB7EF, //HANGUL SYLLABLE RIEUL EO KIYEOKSIOS + 0x8E91: 0xB7F1, //HANGUL SYLLABLE RIEUL EO NIEUNCIEUC + 0x8E92: 0xB7F2, //HANGUL SYLLABLE RIEUL EO NIEUNHIEUH + 0x8E93: 0xB7F3, //HANGUL SYLLABLE RIEUL EO TIKEUT + 0x8E94: 0xB7F5, //HANGUL SYLLABLE RIEUL EO RIEULKIYEOK + 0x8E95: 0xB7F6, //HANGUL SYLLABLE RIEUL EO RIEULMIEUM + 0x8E96: 0xB7F7, //HANGUL SYLLABLE RIEUL EO RIEULPIEUP + 0x8E97: 0xB7F8, //HANGUL SYLLABLE RIEUL EO RIEULSIOS + 0x8E98: 0xB7F9, //HANGUL SYLLABLE RIEUL EO RIEULTHIEUTH + 0x8E99: 0xB7FA, //HANGUL SYLLABLE RIEUL EO RIEULPHIEUPH + 0x8E9A: 0xB7FB, //HANGUL SYLLABLE RIEUL EO RIEULHIEUH + 0x8E9B: 0xB7FE, //HANGUL SYLLABLE RIEUL EO PIEUPSIOS + 0x8E9C: 0xB802, //HANGUL SYLLABLE RIEUL EO CIEUC + 0x8E9D: 0xB803, //HANGUL SYLLABLE RIEUL EO CHIEUCH + 0x8E9E: 0xB804, //HANGUL SYLLABLE RIEUL EO KHIEUKH + 0x8E9F: 0xB805, //HANGUL SYLLABLE RIEUL EO THIEUTH + 0x8EA0: 0xB806, //HANGUL SYLLABLE RIEUL EO PHIEUPH + 0x8EA1: 0xB80A, //HANGUL SYLLABLE RIEUL E SSANGKIYEOK + 0x8EA2: 0xB80B, //HANGUL SYLLABLE RIEUL E KIYEOKSIOS + 0x8EA3: 0xB80D, //HANGUL SYLLABLE RIEUL E NIEUNCIEUC + 0x8EA4: 0xB80E, //HANGUL SYLLABLE RIEUL E NIEUNHIEUH + 0x8EA5: 0xB80F, //HANGUL SYLLABLE RIEUL E TIKEUT + 0x8EA6: 0xB811, //HANGUL SYLLABLE RIEUL E RIEULKIYEOK + 0x8EA7: 0xB812, //HANGUL SYLLABLE RIEUL E RIEULMIEUM + 0x8EA8: 0xB813, //HANGUL SYLLABLE RIEUL E RIEULPIEUP + 0x8EA9: 0xB814, //HANGUL SYLLABLE RIEUL E RIEULSIOS + 0x8EAA: 0xB815, //HANGUL SYLLABLE RIEUL E RIEULTHIEUTH + 0x8EAB: 0xB816, //HANGUL SYLLABLE RIEUL E RIEULPHIEUPH + 0x8EAC: 0xB817, //HANGUL SYLLABLE RIEUL E RIEULHIEUH + 0x8EAD: 0xB81A, //HANGUL SYLLABLE RIEUL E PIEUPSIOS + 0x8EAE: 0xB81C, //HANGUL SYLLABLE RIEUL E SSANGSIOS + 0x8EAF: 0xB81E, //HANGUL SYLLABLE RIEUL E CIEUC + 0x8EB0: 0xB81F, //HANGUL SYLLABLE RIEUL E CHIEUCH + 0x8EB1: 0xB820, //HANGUL SYLLABLE RIEUL E KHIEUKH + 0x8EB2: 0xB821, //HANGUL SYLLABLE RIEUL E THIEUTH + 0x8EB3: 0xB822, //HANGUL SYLLABLE RIEUL E PHIEUPH + 0x8EB4: 0xB823, //HANGUL SYLLABLE RIEUL E HIEUH + 0x8EB5: 0xB826, //HANGUL SYLLABLE RIEUL YEO SSANGKIYEOK + 0x8EB6: 0xB827, //HANGUL SYLLABLE RIEUL YEO KIYEOKSIOS + 0x8EB7: 0xB829, //HANGUL SYLLABLE RIEUL YEO NIEUNCIEUC + 0x8EB8: 0xB82A, //HANGUL SYLLABLE RIEUL YEO NIEUNHIEUH + 0x8EB9: 0xB82B, //HANGUL SYLLABLE RIEUL YEO TIKEUT + 0x8EBA: 0xB82D, //HANGUL SYLLABLE RIEUL YEO RIEULKIYEOK + 0x8EBB: 0xB82E, //HANGUL SYLLABLE RIEUL YEO RIEULMIEUM + 0x8EBC: 0xB82F, //HANGUL SYLLABLE RIEUL YEO RIEULPIEUP + 0x8EBD: 0xB830, //HANGUL SYLLABLE RIEUL YEO RIEULSIOS + 0x8EBE: 0xB831, //HANGUL SYLLABLE RIEUL YEO RIEULTHIEUTH + 0x8EBF: 0xB832, //HANGUL SYLLABLE RIEUL YEO RIEULPHIEUPH + 0x8EC0: 0xB833, //HANGUL SYLLABLE RIEUL YEO RIEULHIEUH + 0x8EC1: 0xB836, //HANGUL SYLLABLE RIEUL YEO PIEUPSIOS + 0x8EC2: 0xB83A, //HANGUL SYLLABLE RIEUL YEO CIEUC + 0x8EC3: 0xB83B, //HANGUL SYLLABLE RIEUL YEO CHIEUCH + 0x8EC4: 0xB83C, //HANGUL SYLLABLE RIEUL YEO KHIEUKH + 0x8EC5: 0xB83D, //HANGUL SYLLABLE RIEUL YEO THIEUTH + 0x8EC6: 0xB83E, //HANGUL SYLLABLE RIEUL YEO PHIEUPH + 0x8EC7: 0xB83F, //HANGUL SYLLABLE RIEUL YEO HIEUH + 0x8EC8: 0xB841, //HANGUL SYLLABLE RIEUL YE KIYEOK + 0x8EC9: 0xB842, //HANGUL SYLLABLE RIEUL YE SSANGKIYEOK + 0x8ECA: 0xB843, //HANGUL SYLLABLE RIEUL YE KIYEOKSIOS + 0x8ECB: 0xB845, //HANGUL SYLLABLE RIEUL YE NIEUNCIEUC + 0x8ECC: 0xB846, //HANGUL SYLLABLE RIEUL YE NIEUNHIEUH + 0x8ECD: 0xB847, //HANGUL SYLLABLE RIEUL YE TIKEUT + 0x8ECE: 0xB848, //HANGUL SYLLABLE RIEUL YE RIEUL + 0x8ECF: 0xB849, //HANGUL SYLLABLE RIEUL YE RIEULKIYEOK + 0x8ED0: 0xB84A, //HANGUL SYLLABLE RIEUL YE RIEULMIEUM + 0x8ED1: 0xB84B, //HANGUL SYLLABLE RIEUL YE RIEULPIEUP + 0x8ED2: 0xB84C, //HANGUL SYLLABLE RIEUL YE RIEULSIOS + 0x8ED3: 0xB84D, //HANGUL SYLLABLE RIEUL YE RIEULTHIEUTH + 0x8ED4: 0xB84E, //HANGUL SYLLABLE RIEUL YE RIEULPHIEUPH + 0x8ED5: 0xB84F, //HANGUL SYLLABLE RIEUL YE RIEULHIEUH + 0x8ED6: 0xB850, //HANGUL SYLLABLE RIEUL YE MIEUM + 0x8ED7: 0xB852, //HANGUL SYLLABLE RIEUL YE PIEUPSIOS + 0x8ED8: 0xB854, //HANGUL SYLLABLE RIEUL YE SSANGSIOS + 0x8ED9: 0xB855, //HANGUL SYLLABLE RIEUL YE IEUNG + 0x8EDA: 0xB856, //HANGUL SYLLABLE RIEUL YE CIEUC + 0x8EDB: 0xB857, //HANGUL SYLLABLE RIEUL YE CHIEUCH + 0x8EDC: 0xB858, //HANGUL SYLLABLE RIEUL YE KHIEUKH + 0x8EDD: 0xB859, //HANGUL SYLLABLE RIEUL YE THIEUTH + 0x8EDE: 0xB85A, //HANGUL SYLLABLE RIEUL YE PHIEUPH + 0x8EDF: 0xB85B, //HANGUL SYLLABLE RIEUL YE HIEUH + 0x8EE0: 0xB85E, //HANGUL SYLLABLE RIEUL O SSANGKIYEOK + 0x8EE1: 0xB85F, //HANGUL SYLLABLE RIEUL O KIYEOKSIOS + 0x8EE2: 0xB861, //HANGUL SYLLABLE RIEUL O NIEUNCIEUC + 0x8EE3: 0xB862, //HANGUL SYLLABLE RIEUL O NIEUNHIEUH + 0x8EE4: 0xB863, //HANGUL SYLLABLE RIEUL O TIKEUT + 0x8EE5: 0xB865, //HANGUL SYLLABLE RIEUL O RIEULKIYEOK + 0x8EE6: 0xB866, //HANGUL SYLLABLE RIEUL O RIEULMIEUM + 0x8EE7: 0xB867, //HANGUL SYLLABLE RIEUL O RIEULPIEUP + 0x8EE8: 0xB868, //HANGUL SYLLABLE RIEUL O RIEULSIOS + 0x8EE9: 0xB869, //HANGUL SYLLABLE RIEUL O RIEULTHIEUTH + 0x8EEA: 0xB86A, //HANGUL SYLLABLE RIEUL O RIEULPHIEUPH + 0x8EEB: 0xB86B, //HANGUL SYLLABLE RIEUL O RIEULHIEUH + 0x8EEC: 0xB86E, //HANGUL SYLLABLE RIEUL O PIEUPSIOS + 0x8EED: 0xB870, //HANGUL SYLLABLE RIEUL O SSANGSIOS + 0x8EEE: 0xB872, //HANGUL SYLLABLE RIEUL O CIEUC + 0x8EEF: 0xB873, //HANGUL SYLLABLE RIEUL O CHIEUCH + 0x8EF0: 0xB874, //HANGUL SYLLABLE RIEUL O KHIEUKH + 0x8EF1: 0xB875, //HANGUL SYLLABLE RIEUL O THIEUTH + 0x8EF2: 0xB876, //HANGUL SYLLABLE RIEUL O PHIEUPH + 0x8EF3: 0xB877, //HANGUL SYLLABLE RIEUL O HIEUH + 0x8EF4: 0xB879, //HANGUL SYLLABLE RIEUL WA KIYEOK + 0x8EF5: 0xB87A, //HANGUL SYLLABLE RIEUL WA SSANGKIYEOK + 0x8EF6: 0xB87B, //HANGUL SYLLABLE RIEUL WA KIYEOKSIOS + 0x8EF7: 0xB87D, //HANGUL SYLLABLE RIEUL WA NIEUNCIEUC + 0x8EF8: 0xB87E, //HANGUL SYLLABLE RIEUL WA NIEUNHIEUH + 0x8EF9: 0xB87F, //HANGUL SYLLABLE RIEUL WA TIKEUT + 0x8EFA: 0xB880, //HANGUL SYLLABLE RIEUL WA RIEUL + 0x8EFB: 0xB881, //HANGUL SYLLABLE RIEUL WA RIEULKIYEOK + 0x8EFC: 0xB882, //HANGUL SYLLABLE RIEUL WA RIEULMIEUM + 0x8EFD: 0xB883, //HANGUL SYLLABLE RIEUL WA RIEULPIEUP + 0x8EFE: 0xB884, //HANGUL SYLLABLE RIEUL WA RIEULSIOS + 0x8F41: 0xB885, //HANGUL SYLLABLE RIEUL WA RIEULTHIEUTH + 0x8F42: 0xB886, //HANGUL SYLLABLE RIEUL WA RIEULPHIEUPH + 0x8F43: 0xB887, //HANGUL SYLLABLE RIEUL WA RIEULHIEUH + 0x8F44: 0xB888, //HANGUL SYLLABLE RIEUL WA MIEUM + 0x8F45: 0xB889, //HANGUL SYLLABLE RIEUL WA PIEUP + 0x8F46: 0xB88A, //HANGUL SYLLABLE RIEUL WA PIEUPSIOS + 0x8F47: 0xB88B, //HANGUL SYLLABLE RIEUL WA SIOS + 0x8F48: 0xB88C, //HANGUL SYLLABLE RIEUL WA SSANGSIOS + 0x8F49: 0xB88E, //HANGUL SYLLABLE RIEUL WA CIEUC + 0x8F4A: 0xB88F, //HANGUL SYLLABLE RIEUL WA CHIEUCH + 0x8F4B: 0xB890, //HANGUL SYLLABLE RIEUL WA KHIEUKH + 0x8F4C: 0xB891, //HANGUL SYLLABLE RIEUL WA THIEUTH + 0x8F4D: 0xB892, //HANGUL SYLLABLE RIEUL WA PHIEUPH + 0x8F4E: 0xB893, //HANGUL SYLLABLE RIEUL WA HIEUH + 0x8F4F: 0xB894, //HANGUL SYLLABLE RIEUL WAE + 0x8F50: 0xB895, //HANGUL SYLLABLE RIEUL WAE KIYEOK + 0x8F51: 0xB896, //HANGUL SYLLABLE RIEUL WAE SSANGKIYEOK + 0x8F52: 0xB897, //HANGUL SYLLABLE RIEUL WAE KIYEOKSIOS + 0x8F53: 0xB898, //HANGUL SYLLABLE RIEUL WAE NIEUN + 0x8F54: 0xB899, //HANGUL SYLLABLE RIEUL WAE NIEUNCIEUC + 0x8F55: 0xB89A, //HANGUL SYLLABLE RIEUL WAE NIEUNHIEUH + 0x8F56: 0xB89B, //HANGUL SYLLABLE RIEUL WAE TIKEUT + 0x8F57: 0xB89C, //HANGUL SYLLABLE RIEUL WAE RIEUL + 0x8F58: 0xB89D, //HANGUL SYLLABLE RIEUL WAE RIEULKIYEOK + 0x8F59: 0xB89E, //HANGUL SYLLABLE RIEUL WAE RIEULMIEUM + 0x8F5A: 0xB89F, //HANGUL SYLLABLE RIEUL WAE RIEULPIEUP + 0x8F61: 0xB8A0, //HANGUL SYLLABLE RIEUL WAE RIEULSIOS + 0x8F62: 0xB8A1, //HANGUL SYLLABLE RIEUL WAE RIEULTHIEUTH + 0x8F63: 0xB8A2, //HANGUL SYLLABLE RIEUL WAE RIEULPHIEUPH + 0x8F64: 0xB8A3, //HANGUL SYLLABLE RIEUL WAE RIEULHIEUH + 0x8F65: 0xB8A4, //HANGUL SYLLABLE RIEUL WAE MIEUM + 0x8F66: 0xB8A5, //HANGUL SYLLABLE RIEUL WAE PIEUP + 0x8F67: 0xB8A6, //HANGUL SYLLABLE RIEUL WAE PIEUPSIOS + 0x8F68: 0xB8A7, //HANGUL SYLLABLE RIEUL WAE SIOS + 0x8F69: 0xB8A9, //HANGUL SYLLABLE RIEUL WAE IEUNG + 0x8F6A: 0xB8AA, //HANGUL SYLLABLE RIEUL WAE CIEUC + 0x8F6B: 0xB8AB, //HANGUL SYLLABLE RIEUL WAE CHIEUCH + 0x8F6C: 0xB8AC, //HANGUL SYLLABLE RIEUL WAE KHIEUKH + 0x8F6D: 0xB8AD, //HANGUL SYLLABLE RIEUL WAE THIEUTH + 0x8F6E: 0xB8AE, //HANGUL SYLLABLE RIEUL WAE PHIEUPH + 0x8F6F: 0xB8AF, //HANGUL SYLLABLE RIEUL WAE HIEUH + 0x8F70: 0xB8B1, //HANGUL SYLLABLE RIEUL OE KIYEOK + 0x8F71: 0xB8B2, //HANGUL SYLLABLE RIEUL OE SSANGKIYEOK + 0x8F72: 0xB8B3, //HANGUL SYLLABLE RIEUL OE KIYEOKSIOS + 0x8F73: 0xB8B5, //HANGUL SYLLABLE RIEUL OE NIEUNCIEUC + 0x8F74: 0xB8B6, //HANGUL SYLLABLE RIEUL OE NIEUNHIEUH + 0x8F75: 0xB8B7, //HANGUL SYLLABLE RIEUL OE TIKEUT + 0x8F76: 0xB8B9, //HANGUL SYLLABLE RIEUL OE RIEULKIYEOK + 0x8F77: 0xB8BA, //HANGUL SYLLABLE RIEUL OE RIEULMIEUM + 0x8F78: 0xB8BB, //HANGUL SYLLABLE RIEUL OE RIEULPIEUP + 0x8F79: 0xB8BC, //HANGUL SYLLABLE RIEUL OE RIEULSIOS + 0x8F7A: 0xB8BD, //HANGUL SYLLABLE RIEUL OE RIEULTHIEUTH + 0x8F81: 0xB8BE, //HANGUL SYLLABLE RIEUL OE RIEULPHIEUPH + 0x8F82: 0xB8BF, //HANGUL SYLLABLE RIEUL OE RIEULHIEUH + 0x8F83: 0xB8C2, //HANGUL SYLLABLE RIEUL OE PIEUPSIOS + 0x8F84: 0xB8C4, //HANGUL SYLLABLE RIEUL OE SSANGSIOS + 0x8F85: 0xB8C6, //HANGUL SYLLABLE RIEUL OE CIEUC + 0x8F86: 0xB8C7, //HANGUL SYLLABLE RIEUL OE CHIEUCH + 0x8F87: 0xB8C8, //HANGUL SYLLABLE RIEUL OE KHIEUKH + 0x8F88: 0xB8C9, //HANGUL SYLLABLE RIEUL OE THIEUTH + 0x8F89: 0xB8CA, //HANGUL SYLLABLE RIEUL OE PHIEUPH + 0x8F8A: 0xB8CB, //HANGUL SYLLABLE RIEUL OE HIEUH + 0x8F8B: 0xB8CD, //HANGUL SYLLABLE RIEUL YO KIYEOK + 0x8F8C: 0xB8CE, //HANGUL SYLLABLE RIEUL YO SSANGKIYEOK + 0x8F8D: 0xB8CF, //HANGUL SYLLABLE RIEUL YO KIYEOKSIOS + 0x8F8E: 0xB8D1, //HANGUL SYLLABLE RIEUL YO NIEUNCIEUC + 0x8F8F: 0xB8D2, //HANGUL SYLLABLE RIEUL YO NIEUNHIEUH + 0x8F90: 0xB8D3, //HANGUL SYLLABLE RIEUL YO TIKEUT + 0x8F91: 0xB8D5, //HANGUL SYLLABLE RIEUL YO RIEULKIYEOK + 0x8F92: 0xB8D6, //HANGUL SYLLABLE RIEUL YO RIEULMIEUM + 0x8F93: 0xB8D7, //HANGUL SYLLABLE RIEUL YO RIEULPIEUP + 0x8F94: 0xB8D8, //HANGUL SYLLABLE RIEUL YO RIEULSIOS + 0x8F95: 0xB8D9, //HANGUL SYLLABLE RIEUL YO RIEULTHIEUTH + 0x8F96: 0xB8DA, //HANGUL SYLLABLE RIEUL YO RIEULPHIEUPH + 0x8F97: 0xB8DB, //HANGUL SYLLABLE RIEUL YO RIEULHIEUH + 0x8F98: 0xB8DC, //HANGUL SYLLABLE RIEUL YO MIEUM + 0x8F99: 0xB8DE, //HANGUL SYLLABLE RIEUL YO PIEUPSIOS + 0x8F9A: 0xB8E0, //HANGUL SYLLABLE RIEUL YO SSANGSIOS + 0x8F9B: 0xB8E2, //HANGUL SYLLABLE RIEUL YO CIEUC + 0x8F9C: 0xB8E3, //HANGUL SYLLABLE RIEUL YO CHIEUCH + 0x8F9D: 0xB8E4, //HANGUL SYLLABLE RIEUL YO KHIEUKH + 0x8F9E: 0xB8E5, //HANGUL SYLLABLE RIEUL YO THIEUTH + 0x8F9F: 0xB8E6, //HANGUL SYLLABLE RIEUL YO PHIEUPH + 0x8FA0: 0xB8E7, //HANGUL SYLLABLE RIEUL YO HIEUH + 0x8FA1: 0xB8EA, //HANGUL SYLLABLE RIEUL U SSANGKIYEOK + 0x8FA2: 0xB8EB, //HANGUL SYLLABLE RIEUL U KIYEOKSIOS + 0x8FA3: 0xB8ED, //HANGUL SYLLABLE RIEUL U NIEUNCIEUC + 0x8FA4: 0xB8EE, //HANGUL SYLLABLE RIEUL U NIEUNHIEUH + 0x8FA5: 0xB8EF, //HANGUL SYLLABLE RIEUL U TIKEUT + 0x8FA6: 0xB8F1, //HANGUL SYLLABLE RIEUL U RIEULKIYEOK + 0x8FA7: 0xB8F2, //HANGUL SYLLABLE RIEUL U RIEULMIEUM + 0x8FA8: 0xB8F3, //HANGUL SYLLABLE RIEUL U RIEULPIEUP + 0x8FA9: 0xB8F4, //HANGUL SYLLABLE RIEUL U RIEULSIOS + 0x8FAA: 0xB8F5, //HANGUL SYLLABLE RIEUL U RIEULTHIEUTH + 0x8FAB: 0xB8F6, //HANGUL SYLLABLE RIEUL U RIEULPHIEUPH + 0x8FAC: 0xB8F7, //HANGUL SYLLABLE RIEUL U RIEULHIEUH + 0x8FAD: 0xB8FA, //HANGUL SYLLABLE RIEUL U PIEUPSIOS + 0x8FAE: 0xB8FC, //HANGUL SYLLABLE RIEUL U SSANGSIOS + 0x8FAF: 0xB8FE, //HANGUL SYLLABLE RIEUL U CIEUC + 0x8FB0: 0xB8FF, //HANGUL SYLLABLE RIEUL U CHIEUCH + 0x8FB1: 0xB900, //HANGUL SYLLABLE RIEUL U KHIEUKH + 0x8FB2: 0xB901, //HANGUL SYLLABLE RIEUL U THIEUTH + 0x8FB3: 0xB902, //HANGUL SYLLABLE RIEUL U PHIEUPH + 0x8FB4: 0xB903, //HANGUL SYLLABLE RIEUL U HIEUH + 0x8FB5: 0xB905, //HANGUL SYLLABLE RIEUL WEO KIYEOK + 0x8FB6: 0xB906, //HANGUL SYLLABLE RIEUL WEO SSANGKIYEOK + 0x8FB7: 0xB907, //HANGUL SYLLABLE RIEUL WEO KIYEOKSIOS + 0x8FB8: 0xB908, //HANGUL SYLLABLE RIEUL WEO NIEUN + 0x8FB9: 0xB909, //HANGUL SYLLABLE RIEUL WEO NIEUNCIEUC + 0x8FBA: 0xB90A, //HANGUL SYLLABLE RIEUL WEO NIEUNHIEUH + 0x8FBB: 0xB90B, //HANGUL SYLLABLE RIEUL WEO TIKEUT + 0x8FBC: 0xB90C, //HANGUL SYLLABLE RIEUL WEO RIEUL + 0x8FBD: 0xB90D, //HANGUL SYLLABLE RIEUL WEO RIEULKIYEOK + 0x8FBE: 0xB90E, //HANGUL SYLLABLE RIEUL WEO RIEULMIEUM + 0x8FBF: 0xB90F, //HANGUL SYLLABLE RIEUL WEO RIEULPIEUP + 0x8FC0: 0xB910, //HANGUL SYLLABLE RIEUL WEO RIEULSIOS + 0x8FC1: 0xB911, //HANGUL SYLLABLE RIEUL WEO RIEULTHIEUTH + 0x8FC2: 0xB912, //HANGUL SYLLABLE RIEUL WEO RIEULPHIEUPH + 0x8FC3: 0xB913, //HANGUL SYLLABLE RIEUL WEO RIEULHIEUH + 0x8FC4: 0xB914, //HANGUL SYLLABLE RIEUL WEO MIEUM + 0x8FC5: 0xB915, //HANGUL SYLLABLE RIEUL WEO PIEUP + 0x8FC6: 0xB916, //HANGUL SYLLABLE RIEUL WEO PIEUPSIOS + 0x8FC7: 0xB917, //HANGUL SYLLABLE RIEUL WEO SIOS + 0x8FC8: 0xB919, //HANGUL SYLLABLE RIEUL WEO IEUNG + 0x8FC9: 0xB91A, //HANGUL SYLLABLE RIEUL WEO CIEUC + 0x8FCA: 0xB91B, //HANGUL SYLLABLE RIEUL WEO CHIEUCH + 0x8FCB: 0xB91C, //HANGUL SYLLABLE RIEUL WEO KHIEUKH + 0x8FCC: 0xB91D, //HANGUL SYLLABLE RIEUL WEO THIEUTH + 0x8FCD: 0xB91E, //HANGUL SYLLABLE RIEUL WEO PHIEUPH + 0x8FCE: 0xB91F, //HANGUL SYLLABLE RIEUL WEO HIEUH + 0x8FCF: 0xB921, //HANGUL SYLLABLE RIEUL WE KIYEOK + 0x8FD0: 0xB922, //HANGUL SYLLABLE RIEUL WE SSANGKIYEOK + 0x8FD1: 0xB923, //HANGUL SYLLABLE RIEUL WE KIYEOKSIOS + 0x8FD2: 0xB924, //HANGUL SYLLABLE RIEUL WE NIEUN + 0x8FD3: 0xB925, //HANGUL SYLLABLE RIEUL WE NIEUNCIEUC + 0x8FD4: 0xB926, //HANGUL SYLLABLE RIEUL WE NIEUNHIEUH + 0x8FD5: 0xB927, //HANGUL SYLLABLE RIEUL WE TIKEUT + 0x8FD6: 0xB928, //HANGUL SYLLABLE RIEUL WE RIEUL + 0x8FD7: 0xB929, //HANGUL SYLLABLE RIEUL WE RIEULKIYEOK + 0x8FD8: 0xB92A, //HANGUL SYLLABLE RIEUL WE RIEULMIEUM + 0x8FD9: 0xB92B, //HANGUL SYLLABLE RIEUL WE RIEULPIEUP + 0x8FDA: 0xB92C, //HANGUL SYLLABLE RIEUL WE RIEULSIOS + 0x8FDB: 0xB92D, //HANGUL SYLLABLE RIEUL WE RIEULTHIEUTH + 0x8FDC: 0xB92E, //HANGUL SYLLABLE RIEUL WE RIEULPHIEUPH + 0x8FDD: 0xB92F, //HANGUL SYLLABLE RIEUL WE RIEULHIEUH + 0x8FDE: 0xB930, //HANGUL SYLLABLE RIEUL WE MIEUM + 0x8FDF: 0xB931, //HANGUL SYLLABLE RIEUL WE PIEUP + 0x8FE0: 0xB932, //HANGUL SYLLABLE RIEUL WE PIEUPSIOS + 0x8FE1: 0xB933, //HANGUL SYLLABLE RIEUL WE SIOS + 0x8FE2: 0xB934, //HANGUL SYLLABLE RIEUL WE SSANGSIOS + 0x8FE3: 0xB935, //HANGUL SYLLABLE RIEUL WE IEUNG + 0x8FE4: 0xB936, //HANGUL SYLLABLE RIEUL WE CIEUC + 0x8FE5: 0xB937, //HANGUL SYLLABLE RIEUL WE CHIEUCH + 0x8FE6: 0xB938, //HANGUL SYLLABLE RIEUL WE KHIEUKH + 0x8FE7: 0xB939, //HANGUL SYLLABLE RIEUL WE THIEUTH + 0x8FE8: 0xB93A, //HANGUL SYLLABLE RIEUL WE PHIEUPH + 0x8FE9: 0xB93B, //HANGUL SYLLABLE RIEUL WE HIEUH + 0x8FEA: 0xB93E, //HANGUL SYLLABLE RIEUL WI SSANGKIYEOK + 0x8FEB: 0xB93F, //HANGUL SYLLABLE RIEUL WI KIYEOKSIOS + 0x8FEC: 0xB941, //HANGUL SYLLABLE RIEUL WI NIEUNCIEUC + 0x8FED: 0xB942, //HANGUL SYLLABLE RIEUL WI NIEUNHIEUH + 0x8FEE: 0xB943, //HANGUL SYLLABLE RIEUL WI TIKEUT + 0x8FEF: 0xB945, //HANGUL SYLLABLE RIEUL WI RIEULKIYEOK + 0x8FF0: 0xB946, //HANGUL SYLLABLE RIEUL WI RIEULMIEUM + 0x8FF1: 0xB947, //HANGUL SYLLABLE RIEUL WI RIEULPIEUP + 0x8FF2: 0xB948, //HANGUL SYLLABLE RIEUL WI RIEULSIOS + 0x8FF3: 0xB949, //HANGUL SYLLABLE RIEUL WI RIEULTHIEUTH + 0x8FF4: 0xB94A, //HANGUL SYLLABLE RIEUL WI RIEULPHIEUPH + 0x8FF5: 0xB94B, //HANGUL SYLLABLE RIEUL WI RIEULHIEUH + 0x8FF6: 0xB94D, //HANGUL SYLLABLE RIEUL WI PIEUP + 0x8FF7: 0xB94E, //HANGUL SYLLABLE RIEUL WI PIEUPSIOS + 0x8FF8: 0xB950, //HANGUL SYLLABLE RIEUL WI SSANGSIOS + 0x8FF9: 0xB952, //HANGUL SYLLABLE RIEUL WI CIEUC + 0x8FFA: 0xB953, //HANGUL SYLLABLE RIEUL WI CHIEUCH + 0x8FFB: 0xB954, //HANGUL SYLLABLE RIEUL WI KHIEUKH + 0x8FFC: 0xB955, //HANGUL SYLLABLE RIEUL WI THIEUTH + 0x8FFD: 0xB956, //HANGUL SYLLABLE RIEUL WI PHIEUPH + 0x8FFE: 0xB957, //HANGUL SYLLABLE RIEUL WI HIEUH + 0x9041: 0xB95A, //HANGUL SYLLABLE RIEUL YU SSANGKIYEOK + 0x9042: 0xB95B, //HANGUL SYLLABLE RIEUL YU KIYEOKSIOS + 0x9043: 0xB95D, //HANGUL SYLLABLE RIEUL YU NIEUNCIEUC + 0x9044: 0xB95E, //HANGUL SYLLABLE RIEUL YU NIEUNHIEUH + 0x9045: 0xB95F, //HANGUL SYLLABLE RIEUL YU TIKEUT + 0x9046: 0xB961, //HANGUL SYLLABLE RIEUL YU RIEULKIYEOK + 0x9047: 0xB962, //HANGUL SYLLABLE RIEUL YU RIEULMIEUM + 0x9048: 0xB963, //HANGUL SYLLABLE RIEUL YU RIEULPIEUP + 0x9049: 0xB964, //HANGUL SYLLABLE RIEUL YU RIEULSIOS + 0x904A: 0xB965, //HANGUL SYLLABLE RIEUL YU RIEULTHIEUTH + 0x904B: 0xB966, //HANGUL SYLLABLE RIEUL YU RIEULPHIEUPH + 0x904C: 0xB967, //HANGUL SYLLABLE RIEUL YU RIEULHIEUH + 0x904D: 0xB96A, //HANGUL SYLLABLE RIEUL YU PIEUPSIOS + 0x904E: 0xB96C, //HANGUL SYLLABLE RIEUL YU SSANGSIOS + 0x904F: 0xB96E, //HANGUL SYLLABLE RIEUL YU CIEUC + 0x9050: 0xB96F, //HANGUL SYLLABLE RIEUL YU CHIEUCH + 0x9051: 0xB970, //HANGUL SYLLABLE RIEUL YU KHIEUKH + 0x9052: 0xB971, //HANGUL SYLLABLE RIEUL YU THIEUTH + 0x9053: 0xB972, //HANGUL SYLLABLE RIEUL YU PHIEUPH + 0x9054: 0xB973, //HANGUL SYLLABLE RIEUL YU HIEUH + 0x9055: 0xB976, //HANGUL SYLLABLE RIEUL EU SSANGKIYEOK + 0x9056: 0xB977, //HANGUL SYLLABLE RIEUL EU KIYEOKSIOS + 0x9057: 0xB979, //HANGUL SYLLABLE RIEUL EU NIEUNCIEUC + 0x9058: 0xB97A, //HANGUL SYLLABLE RIEUL EU NIEUNHIEUH + 0x9059: 0xB97B, //HANGUL SYLLABLE RIEUL EU TIKEUT + 0x905A: 0xB97D, //HANGUL SYLLABLE RIEUL EU RIEULKIYEOK + 0x9061: 0xB97E, //HANGUL SYLLABLE RIEUL EU RIEULMIEUM + 0x9062: 0xB97F, //HANGUL SYLLABLE RIEUL EU RIEULPIEUP + 0x9063: 0xB980, //HANGUL SYLLABLE RIEUL EU RIEULSIOS + 0x9064: 0xB981, //HANGUL SYLLABLE RIEUL EU RIEULTHIEUTH + 0x9065: 0xB982, //HANGUL SYLLABLE RIEUL EU RIEULPHIEUPH + 0x9066: 0xB983, //HANGUL SYLLABLE RIEUL EU RIEULHIEUH + 0x9067: 0xB986, //HANGUL SYLLABLE RIEUL EU PIEUPSIOS + 0x9068: 0xB988, //HANGUL SYLLABLE RIEUL EU SSANGSIOS + 0x9069: 0xB98B, //HANGUL SYLLABLE RIEUL EU CHIEUCH + 0x906A: 0xB98C, //HANGUL SYLLABLE RIEUL EU KHIEUKH + 0x906B: 0xB98F, //HANGUL SYLLABLE RIEUL EU HIEUH + 0x906C: 0xB990, //HANGUL SYLLABLE RIEUL YI + 0x906D: 0xB991, //HANGUL SYLLABLE RIEUL YI KIYEOK + 0x906E: 0xB992, //HANGUL SYLLABLE RIEUL YI SSANGKIYEOK + 0x906F: 0xB993, //HANGUL SYLLABLE RIEUL YI KIYEOKSIOS + 0x9070: 0xB994, //HANGUL SYLLABLE RIEUL YI NIEUN + 0x9071: 0xB995, //HANGUL SYLLABLE RIEUL YI NIEUNCIEUC + 0x9072: 0xB996, //HANGUL SYLLABLE RIEUL YI NIEUNHIEUH + 0x9073: 0xB997, //HANGUL SYLLABLE RIEUL YI TIKEUT + 0x9074: 0xB998, //HANGUL SYLLABLE RIEUL YI RIEUL + 0x9075: 0xB999, //HANGUL SYLLABLE RIEUL YI RIEULKIYEOK + 0x9076: 0xB99A, //HANGUL SYLLABLE RIEUL YI RIEULMIEUM + 0x9077: 0xB99B, //HANGUL SYLLABLE RIEUL YI RIEULPIEUP + 0x9078: 0xB99C, //HANGUL SYLLABLE RIEUL YI RIEULSIOS + 0x9079: 0xB99D, //HANGUL SYLLABLE RIEUL YI RIEULTHIEUTH + 0x907A: 0xB99E, //HANGUL SYLLABLE RIEUL YI RIEULPHIEUPH + 0x9081: 0xB99F, //HANGUL SYLLABLE RIEUL YI RIEULHIEUH + 0x9082: 0xB9A0, //HANGUL SYLLABLE RIEUL YI MIEUM + 0x9083: 0xB9A1, //HANGUL SYLLABLE RIEUL YI PIEUP + 0x9084: 0xB9A2, //HANGUL SYLLABLE RIEUL YI PIEUPSIOS + 0x9085: 0xB9A3, //HANGUL SYLLABLE RIEUL YI SIOS + 0x9086: 0xB9A4, //HANGUL SYLLABLE RIEUL YI SSANGSIOS + 0x9087: 0xB9A5, //HANGUL SYLLABLE RIEUL YI IEUNG + 0x9088: 0xB9A6, //HANGUL SYLLABLE RIEUL YI CIEUC + 0x9089: 0xB9A7, //HANGUL SYLLABLE RIEUL YI CHIEUCH + 0x908A: 0xB9A8, //HANGUL SYLLABLE RIEUL YI KHIEUKH + 0x908B: 0xB9A9, //HANGUL SYLLABLE RIEUL YI THIEUTH + 0x908C: 0xB9AA, //HANGUL SYLLABLE RIEUL YI PHIEUPH + 0x908D: 0xB9AB, //HANGUL SYLLABLE RIEUL YI HIEUH + 0x908E: 0xB9AE, //HANGUL SYLLABLE RIEUL I SSANGKIYEOK + 0x908F: 0xB9AF, //HANGUL SYLLABLE RIEUL I KIYEOKSIOS + 0x9090: 0xB9B1, //HANGUL SYLLABLE RIEUL I NIEUNCIEUC + 0x9091: 0xB9B2, //HANGUL SYLLABLE RIEUL I NIEUNHIEUH + 0x9092: 0xB9B3, //HANGUL SYLLABLE RIEUL I TIKEUT + 0x9093: 0xB9B5, //HANGUL SYLLABLE RIEUL I RIEULKIYEOK + 0x9094: 0xB9B6, //HANGUL SYLLABLE RIEUL I RIEULMIEUM + 0x9095: 0xB9B7, //HANGUL SYLLABLE RIEUL I RIEULPIEUP + 0x9096: 0xB9B8, //HANGUL SYLLABLE RIEUL I RIEULSIOS + 0x9097: 0xB9B9, //HANGUL SYLLABLE RIEUL I RIEULTHIEUTH + 0x9098: 0xB9BA, //HANGUL SYLLABLE RIEUL I RIEULPHIEUPH + 0x9099: 0xB9BB, //HANGUL SYLLABLE RIEUL I RIEULHIEUH + 0x909A: 0xB9BE, //HANGUL SYLLABLE RIEUL I PIEUPSIOS + 0x909B: 0xB9C0, //HANGUL SYLLABLE RIEUL I SSANGSIOS + 0x909C: 0xB9C2, //HANGUL SYLLABLE RIEUL I CIEUC + 0x909D: 0xB9C3, //HANGUL SYLLABLE RIEUL I CHIEUCH + 0x909E: 0xB9C4, //HANGUL SYLLABLE RIEUL I KHIEUKH + 0x909F: 0xB9C5, //HANGUL SYLLABLE RIEUL I THIEUTH + 0x90A0: 0xB9C6, //HANGUL SYLLABLE RIEUL I PHIEUPH + 0x90A1: 0xB9C7, //HANGUL SYLLABLE RIEUL I HIEUH + 0x90A2: 0xB9CA, //HANGUL SYLLABLE MIEUM A SSANGKIYEOK + 0x90A3: 0xB9CB, //HANGUL SYLLABLE MIEUM A KIYEOKSIOS + 0x90A4: 0xB9CD, //HANGUL SYLLABLE MIEUM A NIEUNCIEUC + 0x90A5: 0xB9D3, //HANGUL SYLLABLE MIEUM A RIEULPIEUP + 0x90A6: 0xB9D4, //HANGUL SYLLABLE MIEUM A RIEULSIOS + 0x90A7: 0xB9D5, //HANGUL SYLLABLE MIEUM A RIEULTHIEUTH + 0x90A8: 0xB9D6, //HANGUL SYLLABLE MIEUM A RIEULPHIEUPH + 0x90A9: 0xB9D7, //HANGUL SYLLABLE MIEUM A RIEULHIEUH + 0x90AA: 0xB9DA, //HANGUL SYLLABLE MIEUM A PIEUPSIOS + 0x90AB: 0xB9DC, //HANGUL SYLLABLE MIEUM A SSANGSIOS + 0x90AC: 0xB9DF, //HANGUL SYLLABLE MIEUM A CHIEUCH + 0x90AD: 0xB9E0, //HANGUL SYLLABLE MIEUM A KHIEUKH + 0x90AE: 0xB9E2, //HANGUL SYLLABLE MIEUM A PHIEUPH + 0x90AF: 0xB9E6, //HANGUL SYLLABLE MIEUM AE SSANGKIYEOK + 0x90B0: 0xB9E7, //HANGUL SYLLABLE MIEUM AE KIYEOKSIOS + 0x90B1: 0xB9E9, //HANGUL SYLLABLE MIEUM AE NIEUNCIEUC + 0x90B2: 0xB9EA, //HANGUL SYLLABLE MIEUM AE NIEUNHIEUH + 0x90B3: 0xB9EB, //HANGUL SYLLABLE MIEUM AE TIKEUT + 0x90B4: 0xB9ED, //HANGUL SYLLABLE MIEUM AE RIEULKIYEOK + 0x90B5: 0xB9EE, //HANGUL SYLLABLE MIEUM AE RIEULMIEUM + 0x90B6: 0xB9EF, //HANGUL SYLLABLE MIEUM AE RIEULPIEUP + 0x90B7: 0xB9F0, //HANGUL SYLLABLE MIEUM AE RIEULSIOS + 0x90B8: 0xB9F1, //HANGUL SYLLABLE MIEUM AE RIEULTHIEUTH + 0x90B9: 0xB9F2, //HANGUL SYLLABLE MIEUM AE RIEULPHIEUPH + 0x90BA: 0xB9F3, //HANGUL SYLLABLE MIEUM AE RIEULHIEUH + 0x90BB: 0xB9F6, //HANGUL SYLLABLE MIEUM AE PIEUPSIOS + 0x90BC: 0xB9FB, //HANGUL SYLLABLE MIEUM AE CHIEUCH + 0x90BD: 0xB9FC, //HANGUL SYLLABLE MIEUM AE KHIEUKH + 0x90BE: 0xB9FD, //HANGUL SYLLABLE MIEUM AE THIEUTH + 0x90BF: 0xB9FE, //HANGUL SYLLABLE MIEUM AE PHIEUPH + 0x90C0: 0xB9FF, //HANGUL SYLLABLE MIEUM AE HIEUH + 0x90C1: 0xBA02, //HANGUL SYLLABLE MIEUM YA SSANGKIYEOK + 0x90C2: 0xBA03, //HANGUL SYLLABLE MIEUM YA KIYEOKSIOS + 0x90C3: 0xBA04, //HANGUL SYLLABLE MIEUM YA NIEUN + 0x90C4: 0xBA05, //HANGUL SYLLABLE MIEUM YA NIEUNCIEUC + 0x90C5: 0xBA06, //HANGUL SYLLABLE MIEUM YA NIEUNHIEUH + 0x90C6: 0xBA07, //HANGUL SYLLABLE MIEUM YA TIKEUT + 0x90C7: 0xBA09, //HANGUL SYLLABLE MIEUM YA RIEULKIYEOK + 0x90C8: 0xBA0A, //HANGUL SYLLABLE MIEUM YA RIEULMIEUM + 0x90C9: 0xBA0B, //HANGUL SYLLABLE MIEUM YA RIEULPIEUP + 0x90CA: 0xBA0C, //HANGUL SYLLABLE MIEUM YA RIEULSIOS + 0x90CB: 0xBA0D, //HANGUL SYLLABLE MIEUM YA RIEULTHIEUTH + 0x90CC: 0xBA0E, //HANGUL SYLLABLE MIEUM YA RIEULPHIEUPH + 0x90CD: 0xBA0F, //HANGUL SYLLABLE MIEUM YA RIEULHIEUH + 0x90CE: 0xBA10, //HANGUL SYLLABLE MIEUM YA MIEUM + 0x90CF: 0xBA11, //HANGUL SYLLABLE MIEUM YA PIEUP + 0x90D0: 0xBA12, //HANGUL SYLLABLE MIEUM YA PIEUPSIOS + 0x90D1: 0xBA13, //HANGUL SYLLABLE MIEUM YA SIOS + 0x90D2: 0xBA14, //HANGUL SYLLABLE MIEUM YA SSANGSIOS + 0x90D3: 0xBA16, //HANGUL SYLLABLE MIEUM YA CIEUC + 0x90D4: 0xBA17, //HANGUL SYLLABLE MIEUM YA CHIEUCH + 0x90D5: 0xBA18, //HANGUL SYLLABLE MIEUM YA KHIEUKH + 0x90D6: 0xBA19, //HANGUL SYLLABLE MIEUM YA THIEUTH + 0x90D7: 0xBA1A, //HANGUL SYLLABLE MIEUM YA PHIEUPH + 0x90D8: 0xBA1B, //HANGUL SYLLABLE MIEUM YA HIEUH + 0x90D9: 0xBA1C, //HANGUL SYLLABLE MIEUM YAE + 0x90DA: 0xBA1D, //HANGUL SYLLABLE MIEUM YAE KIYEOK + 0x90DB: 0xBA1E, //HANGUL SYLLABLE MIEUM YAE SSANGKIYEOK + 0x90DC: 0xBA1F, //HANGUL SYLLABLE MIEUM YAE KIYEOKSIOS + 0x90DD: 0xBA20, //HANGUL SYLLABLE MIEUM YAE NIEUN + 0x90DE: 0xBA21, //HANGUL SYLLABLE MIEUM YAE NIEUNCIEUC + 0x90DF: 0xBA22, //HANGUL SYLLABLE MIEUM YAE NIEUNHIEUH + 0x90E0: 0xBA23, //HANGUL SYLLABLE MIEUM YAE TIKEUT + 0x90E1: 0xBA24, //HANGUL SYLLABLE MIEUM YAE RIEUL + 0x90E2: 0xBA25, //HANGUL SYLLABLE MIEUM YAE RIEULKIYEOK + 0x90E3: 0xBA26, //HANGUL SYLLABLE MIEUM YAE RIEULMIEUM + 0x90E4: 0xBA27, //HANGUL SYLLABLE MIEUM YAE RIEULPIEUP + 0x90E5: 0xBA28, //HANGUL SYLLABLE MIEUM YAE RIEULSIOS + 0x90E6: 0xBA29, //HANGUL SYLLABLE MIEUM YAE RIEULTHIEUTH + 0x90E7: 0xBA2A, //HANGUL SYLLABLE MIEUM YAE RIEULPHIEUPH + 0x90E8: 0xBA2B, //HANGUL SYLLABLE MIEUM YAE RIEULHIEUH + 0x90E9: 0xBA2C, //HANGUL SYLLABLE MIEUM YAE MIEUM + 0x90EA: 0xBA2D, //HANGUL SYLLABLE MIEUM YAE PIEUP + 0x90EB: 0xBA2E, //HANGUL SYLLABLE MIEUM YAE PIEUPSIOS + 0x90EC: 0xBA2F, //HANGUL SYLLABLE MIEUM YAE SIOS + 0x90ED: 0xBA30, //HANGUL SYLLABLE MIEUM YAE SSANGSIOS + 0x90EE: 0xBA31, //HANGUL SYLLABLE MIEUM YAE IEUNG + 0x90EF: 0xBA32, //HANGUL SYLLABLE MIEUM YAE CIEUC + 0x90F0: 0xBA33, //HANGUL SYLLABLE MIEUM YAE CHIEUCH + 0x90F1: 0xBA34, //HANGUL SYLLABLE MIEUM YAE KHIEUKH + 0x90F2: 0xBA35, //HANGUL SYLLABLE MIEUM YAE THIEUTH + 0x90F3: 0xBA36, //HANGUL SYLLABLE MIEUM YAE PHIEUPH + 0x90F4: 0xBA37, //HANGUL SYLLABLE MIEUM YAE HIEUH + 0x90F5: 0xBA3A, //HANGUL SYLLABLE MIEUM EO SSANGKIYEOK + 0x90F6: 0xBA3B, //HANGUL SYLLABLE MIEUM EO KIYEOKSIOS + 0x90F7: 0xBA3D, //HANGUL SYLLABLE MIEUM EO NIEUNCIEUC + 0x90F8: 0xBA3E, //HANGUL SYLLABLE MIEUM EO NIEUNHIEUH + 0x90F9: 0xBA3F, //HANGUL SYLLABLE MIEUM EO TIKEUT + 0x90FA: 0xBA41, //HANGUL SYLLABLE MIEUM EO RIEULKIYEOK + 0x90FB: 0xBA43, //HANGUL SYLLABLE MIEUM EO RIEULPIEUP + 0x90FC: 0xBA44, //HANGUL SYLLABLE MIEUM EO RIEULSIOS + 0x90FD: 0xBA45, //HANGUL SYLLABLE MIEUM EO RIEULTHIEUTH + 0x90FE: 0xBA46, //HANGUL SYLLABLE MIEUM EO RIEULPHIEUPH + 0x9141: 0xBA47, //HANGUL SYLLABLE MIEUM EO RIEULHIEUH + 0x9142: 0xBA4A, //HANGUL SYLLABLE MIEUM EO PIEUPSIOS + 0x9143: 0xBA4C, //HANGUL SYLLABLE MIEUM EO SSANGSIOS + 0x9144: 0xBA4F, //HANGUL SYLLABLE MIEUM EO CHIEUCH + 0x9145: 0xBA50, //HANGUL SYLLABLE MIEUM EO KHIEUKH + 0x9146: 0xBA51, //HANGUL SYLLABLE MIEUM EO THIEUTH + 0x9147: 0xBA52, //HANGUL SYLLABLE MIEUM EO PHIEUPH + 0x9148: 0xBA56, //HANGUL SYLLABLE MIEUM E SSANGKIYEOK + 0x9149: 0xBA57, //HANGUL SYLLABLE MIEUM E KIYEOKSIOS + 0x914A: 0xBA59, //HANGUL SYLLABLE MIEUM E NIEUNCIEUC + 0x914B: 0xBA5A, //HANGUL SYLLABLE MIEUM E NIEUNHIEUH + 0x914C: 0xBA5B, //HANGUL SYLLABLE MIEUM E TIKEUT + 0x914D: 0xBA5D, //HANGUL SYLLABLE MIEUM E RIEULKIYEOK + 0x914E: 0xBA5E, //HANGUL SYLLABLE MIEUM E RIEULMIEUM + 0x914F: 0xBA5F, //HANGUL SYLLABLE MIEUM E RIEULPIEUP + 0x9150: 0xBA60, //HANGUL SYLLABLE MIEUM E RIEULSIOS + 0x9151: 0xBA61, //HANGUL SYLLABLE MIEUM E RIEULTHIEUTH + 0x9152: 0xBA62, //HANGUL SYLLABLE MIEUM E RIEULPHIEUPH + 0x9153: 0xBA63, //HANGUL SYLLABLE MIEUM E RIEULHIEUH + 0x9154: 0xBA66, //HANGUL SYLLABLE MIEUM E PIEUPSIOS + 0x9155: 0xBA6A, //HANGUL SYLLABLE MIEUM E CIEUC + 0x9156: 0xBA6B, //HANGUL SYLLABLE MIEUM E CHIEUCH + 0x9157: 0xBA6C, //HANGUL SYLLABLE MIEUM E KHIEUKH + 0x9158: 0xBA6D, //HANGUL SYLLABLE MIEUM E THIEUTH + 0x9159: 0xBA6E, //HANGUL SYLLABLE MIEUM E PHIEUPH + 0x915A: 0xBA6F, //HANGUL SYLLABLE MIEUM E HIEUH + 0x9161: 0xBA72, //HANGUL SYLLABLE MIEUM YEO SSANGKIYEOK + 0x9162: 0xBA73, //HANGUL SYLLABLE MIEUM YEO KIYEOKSIOS + 0x9163: 0xBA75, //HANGUL SYLLABLE MIEUM YEO NIEUNCIEUC + 0x9164: 0xBA76, //HANGUL SYLLABLE MIEUM YEO NIEUNHIEUH + 0x9165: 0xBA77, //HANGUL SYLLABLE MIEUM YEO TIKEUT + 0x9166: 0xBA79, //HANGUL SYLLABLE MIEUM YEO RIEULKIYEOK + 0x9167: 0xBA7A, //HANGUL SYLLABLE MIEUM YEO RIEULMIEUM + 0x9168: 0xBA7B, //HANGUL SYLLABLE MIEUM YEO RIEULPIEUP + 0x9169: 0xBA7C, //HANGUL SYLLABLE MIEUM YEO RIEULSIOS + 0x916A: 0xBA7D, //HANGUL SYLLABLE MIEUM YEO RIEULTHIEUTH + 0x916B: 0xBA7E, //HANGUL SYLLABLE MIEUM YEO RIEULPHIEUPH + 0x916C: 0xBA7F, //HANGUL SYLLABLE MIEUM YEO RIEULHIEUH + 0x916D: 0xBA80, //HANGUL SYLLABLE MIEUM YEO MIEUM + 0x916E: 0xBA81, //HANGUL SYLLABLE MIEUM YEO PIEUP + 0x916F: 0xBA82, //HANGUL SYLLABLE MIEUM YEO PIEUPSIOS + 0x9170: 0xBA86, //HANGUL SYLLABLE MIEUM YEO CIEUC + 0x9171: 0xBA88, //HANGUL SYLLABLE MIEUM YEO KHIEUKH + 0x9172: 0xBA89, //HANGUL SYLLABLE MIEUM YEO THIEUTH + 0x9173: 0xBA8A, //HANGUL SYLLABLE MIEUM YEO PHIEUPH + 0x9174: 0xBA8B, //HANGUL SYLLABLE MIEUM YEO HIEUH + 0x9175: 0xBA8D, //HANGUL SYLLABLE MIEUM YE KIYEOK + 0x9176: 0xBA8E, //HANGUL SYLLABLE MIEUM YE SSANGKIYEOK + 0x9177: 0xBA8F, //HANGUL SYLLABLE MIEUM YE KIYEOKSIOS + 0x9178: 0xBA90, //HANGUL SYLLABLE MIEUM YE NIEUN + 0x9179: 0xBA91, //HANGUL SYLLABLE MIEUM YE NIEUNCIEUC + 0x917A: 0xBA92, //HANGUL SYLLABLE MIEUM YE NIEUNHIEUH + 0x9181: 0xBA93, //HANGUL SYLLABLE MIEUM YE TIKEUT + 0x9182: 0xBA94, //HANGUL SYLLABLE MIEUM YE RIEUL + 0x9183: 0xBA95, //HANGUL SYLLABLE MIEUM YE RIEULKIYEOK + 0x9184: 0xBA96, //HANGUL SYLLABLE MIEUM YE RIEULMIEUM + 0x9185: 0xBA97, //HANGUL SYLLABLE MIEUM YE RIEULPIEUP + 0x9186: 0xBA98, //HANGUL SYLLABLE MIEUM YE RIEULSIOS + 0x9187: 0xBA99, //HANGUL SYLLABLE MIEUM YE RIEULTHIEUTH + 0x9188: 0xBA9A, //HANGUL SYLLABLE MIEUM YE RIEULPHIEUPH + 0x9189: 0xBA9B, //HANGUL SYLLABLE MIEUM YE RIEULHIEUH + 0x918A: 0xBA9C, //HANGUL SYLLABLE MIEUM YE MIEUM + 0x918B: 0xBA9D, //HANGUL SYLLABLE MIEUM YE PIEUP + 0x918C: 0xBA9E, //HANGUL SYLLABLE MIEUM YE PIEUPSIOS + 0x918D: 0xBA9F, //HANGUL SYLLABLE MIEUM YE SIOS + 0x918E: 0xBAA0, //HANGUL SYLLABLE MIEUM YE SSANGSIOS + 0x918F: 0xBAA1, //HANGUL SYLLABLE MIEUM YE IEUNG + 0x9190: 0xBAA2, //HANGUL SYLLABLE MIEUM YE CIEUC + 0x9191: 0xBAA3, //HANGUL SYLLABLE MIEUM YE CHIEUCH + 0x9192: 0xBAA4, //HANGUL SYLLABLE MIEUM YE KHIEUKH + 0x9193: 0xBAA5, //HANGUL SYLLABLE MIEUM YE THIEUTH + 0x9194: 0xBAA6, //HANGUL SYLLABLE MIEUM YE PHIEUPH + 0x9195: 0xBAA7, //HANGUL SYLLABLE MIEUM YE HIEUH + 0x9196: 0xBAAA, //HANGUL SYLLABLE MIEUM O SSANGKIYEOK + 0x9197: 0xBAAD, //HANGUL SYLLABLE MIEUM O NIEUNCIEUC + 0x9198: 0xBAAE, //HANGUL SYLLABLE MIEUM O NIEUNHIEUH + 0x9199: 0xBAAF, //HANGUL SYLLABLE MIEUM O TIKEUT + 0x919A: 0xBAB1, //HANGUL SYLLABLE MIEUM O RIEULKIYEOK + 0x919B: 0xBAB3, //HANGUL SYLLABLE MIEUM O RIEULPIEUP + 0x919C: 0xBAB4, //HANGUL SYLLABLE MIEUM O RIEULSIOS + 0x919D: 0xBAB5, //HANGUL SYLLABLE MIEUM O RIEULTHIEUTH + 0x919E: 0xBAB6, //HANGUL SYLLABLE MIEUM O RIEULPHIEUPH + 0x919F: 0xBAB7, //HANGUL SYLLABLE MIEUM O RIEULHIEUH + 0x91A0: 0xBABA, //HANGUL SYLLABLE MIEUM O PIEUPSIOS + 0x91A1: 0xBABC, //HANGUL SYLLABLE MIEUM O SSANGSIOS + 0x91A2: 0xBABE, //HANGUL SYLLABLE MIEUM O CIEUC + 0x91A3: 0xBABF, //HANGUL SYLLABLE MIEUM O CHIEUCH + 0x91A4: 0xBAC0, //HANGUL SYLLABLE MIEUM O KHIEUKH + 0x91A5: 0xBAC1, //HANGUL SYLLABLE MIEUM O THIEUTH + 0x91A6: 0xBAC2, //HANGUL SYLLABLE MIEUM O PHIEUPH + 0x91A7: 0xBAC3, //HANGUL SYLLABLE MIEUM O HIEUH + 0x91A8: 0xBAC5, //HANGUL SYLLABLE MIEUM WA KIYEOK + 0x91A9: 0xBAC6, //HANGUL SYLLABLE MIEUM WA SSANGKIYEOK + 0x91AA: 0xBAC7, //HANGUL SYLLABLE MIEUM WA KIYEOKSIOS + 0x91AB: 0xBAC9, //HANGUL SYLLABLE MIEUM WA NIEUNCIEUC + 0x91AC: 0xBACA, //HANGUL SYLLABLE MIEUM WA NIEUNHIEUH + 0x91AD: 0xBACB, //HANGUL SYLLABLE MIEUM WA TIKEUT + 0x91AE: 0xBACC, //HANGUL SYLLABLE MIEUM WA RIEUL + 0x91AF: 0xBACD, //HANGUL SYLLABLE MIEUM WA RIEULKIYEOK + 0x91B0: 0xBACE, //HANGUL SYLLABLE MIEUM WA RIEULMIEUM + 0x91B1: 0xBACF, //HANGUL SYLLABLE MIEUM WA RIEULPIEUP + 0x91B2: 0xBAD0, //HANGUL SYLLABLE MIEUM WA RIEULSIOS + 0x91B3: 0xBAD1, //HANGUL SYLLABLE MIEUM WA RIEULTHIEUTH + 0x91B4: 0xBAD2, //HANGUL SYLLABLE MIEUM WA RIEULPHIEUPH + 0x91B5: 0xBAD3, //HANGUL SYLLABLE MIEUM WA RIEULHIEUH + 0x91B6: 0xBAD4, //HANGUL SYLLABLE MIEUM WA MIEUM + 0x91B7: 0xBAD5, //HANGUL SYLLABLE MIEUM WA PIEUP + 0x91B8: 0xBAD6, //HANGUL SYLLABLE MIEUM WA PIEUPSIOS + 0x91B9: 0xBAD7, //HANGUL SYLLABLE MIEUM WA SIOS + 0x91BA: 0xBADA, //HANGUL SYLLABLE MIEUM WA CIEUC + 0x91BB: 0xBADB, //HANGUL SYLLABLE MIEUM WA CHIEUCH + 0x91BC: 0xBADC, //HANGUL SYLLABLE MIEUM WA KHIEUKH + 0x91BD: 0xBADD, //HANGUL SYLLABLE MIEUM WA THIEUTH + 0x91BE: 0xBADE, //HANGUL SYLLABLE MIEUM WA PHIEUPH + 0x91BF: 0xBADF, //HANGUL SYLLABLE MIEUM WA HIEUH + 0x91C0: 0xBAE0, //HANGUL SYLLABLE MIEUM WAE + 0x91C1: 0xBAE1, //HANGUL SYLLABLE MIEUM WAE KIYEOK + 0x91C2: 0xBAE2, //HANGUL SYLLABLE MIEUM WAE SSANGKIYEOK + 0x91C3: 0xBAE3, //HANGUL SYLLABLE MIEUM WAE KIYEOKSIOS + 0x91C4: 0xBAE4, //HANGUL SYLLABLE MIEUM WAE NIEUN + 0x91C5: 0xBAE5, //HANGUL SYLLABLE MIEUM WAE NIEUNCIEUC + 0x91C6: 0xBAE6, //HANGUL SYLLABLE MIEUM WAE NIEUNHIEUH + 0x91C7: 0xBAE7, //HANGUL SYLLABLE MIEUM WAE TIKEUT + 0x91C8: 0xBAE8, //HANGUL SYLLABLE MIEUM WAE RIEUL + 0x91C9: 0xBAE9, //HANGUL SYLLABLE MIEUM WAE RIEULKIYEOK + 0x91CA: 0xBAEA, //HANGUL SYLLABLE MIEUM WAE RIEULMIEUM + 0x91CB: 0xBAEB, //HANGUL SYLLABLE MIEUM WAE RIEULPIEUP + 0x91CC: 0xBAEC, //HANGUL SYLLABLE MIEUM WAE RIEULSIOS + 0x91CD: 0xBAED, //HANGUL SYLLABLE MIEUM WAE RIEULTHIEUTH + 0x91CE: 0xBAEE, //HANGUL SYLLABLE MIEUM WAE RIEULPHIEUPH + 0x91CF: 0xBAEF, //HANGUL SYLLABLE MIEUM WAE RIEULHIEUH + 0x91D0: 0xBAF0, //HANGUL SYLLABLE MIEUM WAE MIEUM + 0x91D1: 0xBAF1, //HANGUL SYLLABLE MIEUM WAE PIEUP + 0x91D2: 0xBAF2, //HANGUL SYLLABLE MIEUM WAE PIEUPSIOS + 0x91D3: 0xBAF3, //HANGUL SYLLABLE MIEUM WAE SIOS + 0x91D4: 0xBAF4, //HANGUL SYLLABLE MIEUM WAE SSANGSIOS + 0x91D5: 0xBAF5, //HANGUL SYLLABLE MIEUM WAE IEUNG + 0x91D6: 0xBAF6, //HANGUL SYLLABLE MIEUM WAE CIEUC + 0x91D7: 0xBAF7, //HANGUL SYLLABLE MIEUM WAE CHIEUCH + 0x91D8: 0xBAF8, //HANGUL SYLLABLE MIEUM WAE KHIEUKH + 0x91D9: 0xBAF9, //HANGUL SYLLABLE MIEUM WAE THIEUTH + 0x91DA: 0xBAFA, //HANGUL SYLLABLE MIEUM WAE PHIEUPH + 0x91DB: 0xBAFB, //HANGUL SYLLABLE MIEUM WAE HIEUH + 0x91DC: 0xBAFD, //HANGUL SYLLABLE MIEUM OE KIYEOK + 0x91DD: 0xBAFE, //HANGUL SYLLABLE MIEUM OE SSANGKIYEOK + 0x91DE: 0xBAFF, //HANGUL SYLLABLE MIEUM OE KIYEOKSIOS + 0x91DF: 0xBB01, //HANGUL SYLLABLE MIEUM OE NIEUNCIEUC + 0x91E0: 0xBB02, //HANGUL SYLLABLE MIEUM OE NIEUNHIEUH + 0x91E1: 0xBB03, //HANGUL SYLLABLE MIEUM OE TIKEUT + 0x91E2: 0xBB05, //HANGUL SYLLABLE MIEUM OE RIEULKIYEOK + 0x91E3: 0xBB06, //HANGUL SYLLABLE MIEUM OE RIEULMIEUM + 0x91E4: 0xBB07, //HANGUL SYLLABLE MIEUM OE RIEULPIEUP + 0x91E5: 0xBB08, //HANGUL SYLLABLE MIEUM OE RIEULSIOS + 0x91E6: 0xBB09, //HANGUL SYLLABLE MIEUM OE RIEULTHIEUTH + 0x91E7: 0xBB0A, //HANGUL SYLLABLE MIEUM OE RIEULPHIEUPH + 0x91E8: 0xBB0B, //HANGUL SYLLABLE MIEUM OE RIEULHIEUH + 0x91E9: 0xBB0C, //HANGUL SYLLABLE MIEUM OE MIEUM + 0x91EA: 0xBB0E, //HANGUL SYLLABLE MIEUM OE PIEUPSIOS + 0x91EB: 0xBB10, //HANGUL SYLLABLE MIEUM OE SSANGSIOS + 0x91EC: 0xBB12, //HANGUL SYLLABLE MIEUM OE CIEUC + 0x91ED: 0xBB13, //HANGUL SYLLABLE MIEUM OE CHIEUCH + 0x91EE: 0xBB14, //HANGUL SYLLABLE MIEUM OE KHIEUKH + 0x91EF: 0xBB15, //HANGUL SYLLABLE MIEUM OE THIEUTH + 0x91F0: 0xBB16, //HANGUL SYLLABLE MIEUM OE PHIEUPH + 0x91F1: 0xBB17, //HANGUL SYLLABLE MIEUM OE HIEUH + 0x91F2: 0xBB19, //HANGUL SYLLABLE MIEUM YO KIYEOK + 0x91F3: 0xBB1A, //HANGUL SYLLABLE MIEUM YO SSANGKIYEOK + 0x91F4: 0xBB1B, //HANGUL SYLLABLE MIEUM YO KIYEOKSIOS + 0x91F5: 0xBB1D, //HANGUL SYLLABLE MIEUM YO NIEUNCIEUC + 0x91F6: 0xBB1E, //HANGUL SYLLABLE MIEUM YO NIEUNHIEUH + 0x91F7: 0xBB1F, //HANGUL SYLLABLE MIEUM YO TIKEUT + 0x91F8: 0xBB21, //HANGUL SYLLABLE MIEUM YO RIEULKIYEOK + 0x91F9: 0xBB22, //HANGUL SYLLABLE MIEUM YO RIEULMIEUM + 0x91FA: 0xBB23, //HANGUL SYLLABLE MIEUM YO RIEULPIEUP + 0x91FB: 0xBB24, //HANGUL SYLLABLE MIEUM YO RIEULSIOS + 0x91FC: 0xBB25, //HANGUL SYLLABLE MIEUM YO RIEULTHIEUTH + 0x91FD: 0xBB26, //HANGUL SYLLABLE MIEUM YO RIEULPHIEUPH + 0x91FE: 0xBB27, //HANGUL SYLLABLE MIEUM YO RIEULHIEUH + 0x9241: 0xBB28, //HANGUL SYLLABLE MIEUM YO MIEUM + 0x9242: 0xBB2A, //HANGUL SYLLABLE MIEUM YO PIEUPSIOS + 0x9243: 0xBB2C, //HANGUL SYLLABLE MIEUM YO SSANGSIOS + 0x9244: 0xBB2D, //HANGUL SYLLABLE MIEUM YO IEUNG + 0x9245: 0xBB2E, //HANGUL SYLLABLE MIEUM YO CIEUC + 0x9246: 0xBB2F, //HANGUL SYLLABLE MIEUM YO CHIEUCH + 0x9247: 0xBB30, //HANGUL SYLLABLE MIEUM YO KHIEUKH + 0x9248: 0xBB31, //HANGUL SYLLABLE MIEUM YO THIEUTH + 0x9249: 0xBB32, //HANGUL SYLLABLE MIEUM YO PHIEUPH + 0x924A: 0xBB33, //HANGUL SYLLABLE MIEUM YO HIEUH + 0x924B: 0xBB37, //HANGUL SYLLABLE MIEUM U KIYEOKSIOS + 0x924C: 0xBB39, //HANGUL SYLLABLE MIEUM U NIEUNCIEUC + 0x924D: 0xBB3A, //HANGUL SYLLABLE MIEUM U NIEUNHIEUH + 0x924E: 0xBB3F, //HANGUL SYLLABLE MIEUM U RIEULPIEUP + 0x924F: 0xBB40, //HANGUL SYLLABLE MIEUM U RIEULSIOS + 0x9250: 0xBB41, //HANGUL SYLLABLE MIEUM U RIEULTHIEUTH + 0x9251: 0xBB42, //HANGUL SYLLABLE MIEUM U RIEULPHIEUPH + 0x9252: 0xBB43, //HANGUL SYLLABLE MIEUM U RIEULHIEUH + 0x9253: 0xBB46, //HANGUL SYLLABLE MIEUM U PIEUPSIOS + 0x9254: 0xBB48, //HANGUL SYLLABLE MIEUM U SSANGSIOS + 0x9255: 0xBB4A, //HANGUL SYLLABLE MIEUM U CIEUC + 0x9256: 0xBB4B, //HANGUL SYLLABLE MIEUM U CHIEUCH + 0x9257: 0xBB4C, //HANGUL SYLLABLE MIEUM U KHIEUKH + 0x9258: 0xBB4E, //HANGUL SYLLABLE MIEUM U PHIEUPH + 0x9259: 0xBB51, //HANGUL SYLLABLE MIEUM WEO KIYEOK + 0x925A: 0xBB52, //HANGUL SYLLABLE MIEUM WEO SSANGKIYEOK + 0x9261: 0xBB53, //HANGUL SYLLABLE MIEUM WEO KIYEOKSIOS + 0x9262: 0xBB55, //HANGUL SYLLABLE MIEUM WEO NIEUNCIEUC + 0x9263: 0xBB56, //HANGUL SYLLABLE MIEUM WEO NIEUNHIEUH + 0x9264: 0xBB57, //HANGUL SYLLABLE MIEUM WEO TIKEUT + 0x9265: 0xBB59, //HANGUL SYLLABLE MIEUM WEO RIEULKIYEOK + 0x9266: 0xBB5A, //HANGUL SYLLABLE MIEUM WEO RIEULMIEUM + 0x9267: 0xBB5B, //HANGUL SYLLABLE MIEUM WEO RIEULPIEUP + 0x9268: 0xBB5C, //HANGUL SYLLABLE MIEUM WEO RIEULSIOS + 0x9269: 0xBB5D, //HANGUL SYLLABLE MIEUM WEO RIEULTHIEUTH + 0x926A: 0xBB5E, //HANGUL SYLLABLE MIEUM WEO RIEULPHIEUPH + 0x926B: 0xBB5F, //HANGUL SYLLABLE MIEUM WEO RIEULHIEUH + 0x926C: 0xBB60, //HANGUL SYLLABLE MIEUM WEO MIEUM + 0x926D: 0xBB62, //HANGUL SYLLABLE MIEUM WEO PIEUPSIOS + 0x926E: 0xBB64, //HANGUL SYLLABLE MIEUM WEO SSANGSIOS + 0x926F: 0xBB65, //HANGUL SYLLABLE MIEUM WEO IEUNG + 0x9270: 0xBB66, //HANGUL SYLLABLE MIEUM WEO CIEUC + 0x9271: 0xBB67, //HANGUL SYLLABLE MIEUM WEO CHIEUCH + 0x9272: 0xBB68, //HANGUL SYLLABLE MIEUM WEO KHIEUKH + 0x9273: 0xBB69, //HANGUL SYLLABLE MIEUM WEO THIEUTH + 0x9274: 0xBB6A, //HANGUL SYLLABLE MIEUM WEO PHIEUPH + 0x9275: 0xBB6B, //HANGUL SYLLABLE MIEUM WEO HIEUH + 0x9276: 0xBB6D, //HANGUL SYLLABLE MIEUM WE KIYEOK + 0x9277: 0xBB6E, //HANGUL SYLLABLE MIEUM WE SSANGKIYEOK + 0x9278: 0xBB6F, //HANGUL SYLLABLE MIEUM WE KIYEOKSIOS + 0x9279: 0xBB70, //HANGUL SYLLABLE MIEUM WE NIEUN + 0x927A: 0xBB71, //HANGUL SYLLABLE MIEUM WE NIEUNCIEUC + 0x9281: 0xBB72, //HANGUL SYLLABLE MIEUM WE NIEUNHIEUH + 0x9282: 0xBB73, //HANGUL SYLLABLE MIEUM WE TIKEUT + 0x9283: 0xBB74, //HANGUL SYLLABLE MIEUM WE RIEUL + 0x9284: 0xBB75, //HANGUL SYLLABLE MIEUM WE RIEULKIYEOK + 0x9285: 0xBB76, //HANGUL SYLLABLE MIEUM WE RIEULMIEUM + 0x9286: 0xBB77, //HANGUL SYLLABLE MIEUM WE RIEULPIEUP + 0x9287: 0xBB78, //HANGUL SYLLABLE MIEUM WE RIEULSIOS + 0x9288: 0xBB79, //HANGUL SYLLABLE MIEUM WE RIEULTHIEUTH + 0x9289: 0xBB7A, //HANGUL SYLLABLE MIEUM WE RIEULPHIEUPH + 0x928A: 0xBB7B, //HANGUL SYLLABLE MIEUM WE RIEULHIEUH + 0x928B: 0xBB7C, //HANGUL SYLLABLE MIEUM WE MIEUM + 0x928C: 0xBB7D, //HANGUL SYLLABLE MIEUM WE PIEUP + 0x928D: 0xBB7E, //HANGUL SYLLABLE MIEUM WE PIEUPSIOS + 0x928E: 0xBB7F, //HANGUL SYLLABLE MIEUM WE SIOS + 0x928F: 0xBB80, //HANGUL SYLLABLE MIEUM WE SSANGSIOS + 0x9290: 0xBB81, //HANGUL SYLLABLE MIEUM WE IEUNG + 0x9291: 0xBB82, //HANGUL SYLLABLE MIEUM WE CIEUC + 0x9292: 0xBB83, //HANGUL SYLLABLE MIEUM WE CHIEUCH + 0x9293: 0xBB84, //HANGUL SYLLABLE MIEUM WE KHIEUKH + 0x9294: 0xBB85, //HANGUL SYLLABLE MIEUM WE THIEUTH + 0x9295: 0xBB86, //HANGUL SYLLABLE MIEUM WE PHIEUPH + 0x9296: 0xBB87, //HANGUL SYLLABLE MIEUM WE HIEUH + 0x9297: 0xBB89, //HANGUL SYLLABLE MIEUM WI KIYEOK + 0x9298: 0xBB8A, //HANGUL SYLLABLE MIEUM WI SSANGKIYEOK + 0x9299: 0xBB8B, //HANGUL SYLLABLE MIEUM WI KIYEOKSIOS + 0x929A: 0xBB8D, //HANGUL SYLLABLE MIEUM WI NIEUNCIEUC + 0x929B: 0xBB8E, //HANGUL SYLLABLE MIEUM WI NIEUNHIEUH + 0x929C: 0xBB8F, //HANGUL SYLLABLE MIEUM WI TIKEUT + 0x929D: 0xBB91, //HANGUL SYLLABLE MIEUM WI RIEULKIYEOK + 0x929E: 0xBB92, //HANGUL SYLLABLE MIEUM WI RIEULMIEUM + 0x929F: 0xBB93, //HANGUL SYLLABLE MIEUM WI RIEULPIEUP + 0x92A0: 0xBB94, //HANGUL SYLLABLE MIEUM WI RIEULSIOS + 0x92A1: 0xBB95, //HANGUL SYLLABLE MIEUM WI RIEULTHIEUTH + 0x92A2: 0xBB96, //HANGUL SYLLABLE MIEUM WI RIEULPHIEUPH + 0x92A3: 0xBB97, //HANGUL SYLLABLE MIEUM WI RIEULHIEUH + 0x92A4: 0xBB98, //HANGUL SYLLABLE MIEUM WI MIEUM + 0x92A5: 0xBB99, //HANGUL SYLLABLE MIEUM WI PIEUP + 0x92A6: 0xBB9A, //HANGUL SYLLABLE MIEUM WI PIEUPSIOS + 0x92A7: 0xBB9B, //HANGUL SYLLABLE MIEUM WI SIOS + 0x92A8: 0xBB9C, //HANGUL SYLLABLE MIEUM WI SSANGSIOS + 0x92A9: 0xBB9D, //HANGUL SYLLABLE MIEUM WI IEUNG + 0x92AA: 0xBB9E, //HANGUL SYLLABLE MIEUM WI CIEUC + 0x92AB: 0xBB9F, //HANGUL SYLLABLE MIEUM WI CHIEUCH + 0x92AC: 0xBBA0, //HANGUL SYLLABLE MIEUM WI KHIEUKH + 0x92AD: 0xBBA1, //HANGUL SYLLABLE MIEUM WI THIEUTH + 0x92AE: 0xBBA2, //HANGUL SYLLABLE MIEUM WI PHIEUPH + 0x92AF: 0xBBA3, //HANGUL SYLLABLE MIEUM WI HIEUH + 0x92B0: 0xBBA5, //HANGUL SYLLABLE MIEUM YU KIYEOK + 0x92B1: 0xBBA6, //HANGUL SYLLABLE MIEUM YU SSANGKIYEOK + 0x92B2: 0xBBA7, //HANGUL SYLLABLE MIEUM YU KIYEOKSIOS + 0x92B3: 0xBBA9, //HANGUL SYLLABLE MIEUM YU NIEUNCIEUC + 0x92B4: 0xBBAA, //HANGUL SYLLABLE MIEUM YU NIEUNHIEUH + 0x92B5: 0xBBAB, //HANGUL SYLLABLE MIEUM YU TIKEUT + 0x92B6: 0xBBAD, //HANGUL SYLLABLE MIEUM YU RIEULKIYEOK + 0x92B7: 0xBBAE, //HANGUL SYLLABLE MIEUM YU RIEULMIEUM + 0x92B8: 0xBBAF, //HANGUL SYLLABLE MIEUM YU RIEULPIEUP + 0x92B9: 0xBBB0, //HANGUL SYLLABLE MIEUM YU RIEULSIOS + 0x92BA: 0xBBB1, //HANGUL SYLLABLE MIEUM YU RIEULTHIEUTH + 0x92BB: 0xBBB2, //HANGUL SYLLABLE MIEUM YU RIEULPHIEUPH + 0x92BC: 0xBBB3, //HANGUL SYLLABLE MIEUM YU RIEULHIEUH + 0x92BD: 0xBBB5, //HANGUL SYLLABLE MIEUM YU PIEUP + 0x92BE: 0xBBB6, //HANGUL SYLLABLE MIEUM YU PIEUPSIOS + 0x92BF: 0xBBB8, //HANGUL SYLLABLE MIEUM YU SSANGSIOS + 0x92C0: 0xBBB9, //HANGUL SYLLABLE MIEUM YU IEUNG + 0x92C1: 0xBBBA, //HANGUL SYLLABLE MIEUM YU CIEUC + 0x92C2: 0xBBBB, //HANGUL SYLLABLE MIEUM YU CHIEUCH + 0x92C3: 0xBBBC, //HANGUL SYLLABLE MIEUM YU KHIEUKH + 0x92C4: 0xBBBD, //HANGUL SYLLABLE MIEUM YU THIEUTH + 0x92C5: 0xBBBE, //HANGUL SYLLABLE MIEUM YU PHIEUPH + 0x92C6: 0xBBBF, //HANGUL SYLLABLE MIEUM YU HIEUH + 0x92C7: 0xBBC1, //HANGUL SYLLABLE MIEUM EU KIYEOK + 0x92C8: 0xBBC2, //HANGUL SYLLABLE MIEUM EU SSANGKIYEOK + 0x92C9: 0xBBC3, //HANGUL SYLLABLE MIEUM EU KIYEOKSIOS + 0x92CA: 0xBBC5, //HANGUL SYLLABLE MIEUM EU NIEUNCIEUC + 0x92CB: 0xBBC6, //HANGUL SYLLABLE MIEUM EU NIEUNHIEUH + 0x92CC: 0xBBC7, //HANGUL SYLLABLE MIEUM EU TIKEUT + 0x92CD: 0xBBC9, //HANGUL SYLLABLE MIEUM EU RIEULKIYEOK + 0x92CE: 0xBBCA, //HANGUL SYLLABLE MIEUM EU RIEULMIEUM + 0x92CF: 0xBBCB, //HANGUL SYLLABLE MIEUM EU RIEULPIEUP + 0x92D0: 0xBBCC, //HANGUL SYLLABLE MIEUM EU RIEULSIOS + 0x92D1: 0xBBCD, //HANGUL SYLLABLE MIEUM EU RIEULTHIEUTH + 0x92D2: 0xBBCE, //HANGUL SYLLABLE MIEUM EU RIEULPHIEUPH + 0x92D3: 0xBBCF, //HANGUL SYLLABLE MIEUM EU RIEULHIEUH + 0x92D4: 0xBBD1, //HANGUL SYLLABLE MIEUM EU PIEUP + 0x92D5: 0xBBD2, //HANGUL SYLLABLE MIEUM EU PIEUPSIOS + 0x92D6: 0xBBD4, //HANGUL SYLLABLE MIEUM EU SSANGSIOS + 0x92D7: 0xBBD5, //HANGUL SYLLABLE MIEUM EU IEUNG + 0x92D8: 0xBBD6, //HANGUL SYLLABLE MIEUM EU CIEUC + 0x92D9: 0xBBD7, //HANGUL SYLLABLE MIEUM EU CHIEUCH + 0x92DA: 0xBBD8, //HANGUL SYLLABLE MIEUM EU KHIEUKH + 0x92DB: 0xBBD9, //HANGUL SYLLABLE MIEUM EU THIEUTH + 0x92DC: 0xBBDA, //HANGUL SYLLABLE MIEUM EU PHIEUPH + 0x92DD: 0xBBDB, //HANGUL SYLLABLE MIEUM EU HIEUH + 0x92DE: 0xBBDC, //HANGUL SYLLABLE MIEUM YI + 0x92DF: 0xBBDD, //HANGUL SYLLABLE MIEUM YI KIYEOK + 0x92E0: 0xBBDE, //HANGUL SYLLABLE MIEUM YI SSANGKIYEOK + 0x92E1: 0xBBDF, //HANGUL SYLLABLE MIEUM YI KIYEOKSIOS + 0x92E2: 0xBBE0, //HANGUL SYLLABLE MIEUM YI NIEUN + 0x92E3: 0xBBE1, //HANGUL SYLLABLE MIEUM YI NIEUNCIEUC + 0x92E4: 0xBBE2, //HANGUL SYLLABLE MIEUM YI NIEUNHIEUH + 0x92E5: 0xBBE3, //HANGUL SYLLABLE MIEUM YI TIKEUT + 0x92E6: 0xBBE4, //HANGUL SYLLABLE MIEUM YI RIEUL + 0x92E7: 0xBBE5, //HANGUL SYLLABLE MIEUM YI RIEULKIYEOK + 0x92E8: 0xBBE6, //HANGUL SYLLABLE MIEUM YI RIEULMIEUM + 0x92E9: 0xBBE7, //HANGUL SYLLABLE MIEUM YI RIEULPIEUP + 0x92EA: 0xBBE8, //HANGUL SYLLABLE MIEUM YI RIEULSIOS + 0x92EB: 0xBBE9, //HANGUL SYLLABLE MIEUM YI RIEULTHIEUTH + 0x92EC: 0xBBEA, //HANGUL SYLLABLE MIEUM YI RIEULPHIEUPH + 0x92ED: 0xBBEB, //HANGUL SYLLABLE MIEUM YI RIEULHIEUH + 0x92EE: 0xBBEC, //HANGUL SYLLABLE MIEUM YI MIEUM + 0x92EF: 0xBBED, //HANGUL SYLLABLE MIEUM YI PIEUP + 0x92F0: 0xBBEE, //HANGUL SYLLABLE MIEUM YI PIEUPSIOS + 0x92F1: 0xBBEF, //HANGUL SYLLABLE MIEUM YI SIOS + 0x92F2: 0xBBF0, //HANGUL SYLLABLE MIEUM YI SSANGSIOS + 0x92F3: 0xBBF1, //HANGUL SYLLABLE MIEUM YI IEUNG + 0x92F4: 0xBBF2, //HANGUL SYLLABLE MIEUM YI CIEUC + 0x92F5: 0xBBF3, //HANGUL SYLLABLE MIEUM YI CHIEUCH + 0x92F6: 0xBBF4, //HANGUL SYLLABLE MIEUM YI KHIEUKH + 0x92F7: 0xBBF5, //HANGUL SYLLABLE MIEUM YI THIEUTH + 0x92F8: 0xBBF6, //HANGUL SYLLABLE MIEUM YI PHIEUPH + 0x92F9: 0xBBF7, //HANGUL SYLLABLE MIEUM YI HIEUH + 0x92FA: 0xBBFA, //HANGUL SYLLABLE MIEUM I SSANGKIYEOK + 0x92FB: 0xBBFB, //HANGUL SYLLABLE MIEUM I KIYEOKSIOS + 0x92FC: 0xBBFD, //HANGUL SYLLABLE MIEUM I NIEUNCIEUC + 0x92FD: 0xBBFE, //HANGUL SYLLABLE MIEUM I NIEUNHIEUH + 0x92FE: 0xBC01, //HANGUL SYLLABLE MIEUM I RIEULKIYEOK + 0x9341: 0xBC03, //HANGUL SYLLABLE MIEUM I RIEULPIEUP + 0x9342: 0xBC04, //HANGUL SYLLABLE MIEUM I RIEULSIOS + 0x9343: 0xBC05, //HANGUL SYLLABLE MIEUM I RIEULTHIEUTH + 0x9344: 0xBC06, //HANGUL SYLLABLE MIEUM I RIEULPHIEUPH + 0x9345: 0xBC07, //HANGUL SYLLABLE MIEUM I RIEULHIEUH + 0x9346: 0xBC0A, //HANGUL SYLLABLE MIEUM I PIEUPSIOS + 0x9347: 0xBC0E, //HANGUL SYLLABLE MIEUM I CIEUC + 0x9348: 0xBC10, //HANGUL SYLLABLE MIEUM I KHIEUKH + 0x9349: 0xBC12, //HANGUL SYLLABLE MIEUM I PHIEUPH + 0x934A: 0xBC13, //HANGUL SYLLABLE MIEUM I HIEUH + 0x934B: 0xBC19, //HANGUL SYLLABLE PIEUP A NIEUNCIEUC + 0x934C: 0xBC1A, //HANGUL SYLLABLE PIEUP A NIEUNHIEUH + 0x934D: 0xBC20, //HANGUL SYLLABLE PIEUP A RIEULSIOS + 0x934E: 0xBC21, //HANGUL SYLLABLE PIEUP A RIEULTHIEUTH + 0x934F: 0xBC22, //HANGUL SYLLABLE PIEUP A RIEULPHIEUPH + 0x9350: 0xBC23, //HANGUL SYLLABLE PIEUP A RIEULHIEUH + 0x9351: 0xBC26, //HANGUL SYLLABLE PIEUP A PIEUPSIOS + 0x9352: 0xBC28, //HANGUL SYLLABLE PIEUP A SSANGSIOS + 0x9353: 0xBC2A, //HANGUL SYLLABLE PIEUP A CIEUC + 0x9354: 0xBC2B, //HANGUL SYLLABLE PIEUP A CHIEUCH + 0x9355: 0xBC2C, //HANGUL SYLLABLE PIEUP A KHIEUKH + 0x9356: 0xBC2E, //HANGUL SYLLABLE PIEUP A PHIEUPH + 0x9357: 0xBC2F, //HANGUL SYLLABLE PIEUP A HIEUH + 0x9358: 0xBC32, //HANGUL SYLLABLE PIEUP AE SSANGKIYEOK + 0x9359: 0xBC33, //HANGUL SYLLABLE PIEUP AE KIYEOKSIOS + 0x935A: 0xBC35, //HANGUL SYLLABLE PIEUP AE NIEUNCIEUC + 0x9361: 0xBC36, //HANGUL SYLLABLE PIEUP AE NIEUNHIEUH + 0x9362: 0xBC37, //HANGUL SYLLABLE PIEUP AE TIKEUT + 0x9363: 0xBC39, //HANGUL SYLLABLE PIEUP AE RIEULKIYEOK + 0x9364: 0xBC3A, //HANGUL SYLLABLE PIEUP AE RIEULMIEUM + 0x9365: 0xBC3B, //HANGUL SYLLABLE PIEUP AE RIEULPIEUP + 0x9366: 0xBC3C, //HANGUL SYLLABLE PIEUP AE RIEULSIOS + 0x9367: 0xBC3D, //HANGUL SYLLABLE PIEUP AE RIEULTHIEUTH + 0x9368: 0xBC3E, //HANGUL SYLLABLE PIEUP AE RIEULPHIEUPH + 0x9369: 0xBC3F, //HANGUL SYLLABLE PIEUP AE RIEULHIEUH + 0x936A: 0xBC42, //HANGUL SYLLABLE PIEUP AE PIEUPSIOS + 0x936B: 0xBC46, //HANGUL SYLLABLE PIEUP AE CIEUC + 0x936C: 0xBC47, //HANGUL SYLLABLE PIEUP AE CHIEUCH + 0x936D: 0xBC48, //HANGUL SYLLABLE PIEUP AE KHIEUKH + 0x936E: 0xBC4A, //HANGUL SYLLABLE PIEUP AE PHIEUPH + 0x936F: 0xBC4B, //HANGUL SYLLABLE PIEUP AE HIEUH + 0x9370: 0xBC4E, //HANGUL SYLLABLE PIEUP YA SSANGKIYEOK + 0x9371: 0xBC4F, //HANGUL SYLLABLE PIEUP YA KIYEOKSIOS + 0x9372: 0xBC51, //HANGUL SYLLABLE PIEUP YA NIEUNCIEUC + 0x9373: 0xBC52, //HANGUL SYLLABLE PIEUP YA NIEUNHIEUH + 0x9374: 0xBC53, //HANGUL SYLLABLE PIEUP YA TIKEUT + 0x9375: 0xBC54, //HANGUL SYLLABLE PIEUP YA RIEUL + 0x9376: 0xBC55, //HANGUL SYLLABLE PIEUP YA RIEULKIYEOK + 0x9377: 0xBC56, //HANGUL SYLLABLE PIEUP YA RIEULMIEUM + 0x9378: 0xBC57, //HANGUL SYLLABLE PIEUP YA RIEULPIEUP + 0x9379: 0xBC58, //HANGUL SYLLABLE PIEUP YA RIEULSIOS + 0x937A: 0xBC59, //HANGUL SYLLABLE PIEUP YA RIEULTHIEUTH + 0x9381: 0xBC5A, //HANGUL SYLLABLE PIEUP YA RIEULPHIEUPH + 0x9382: 0xBC5B, //HANGUL SYLLABLE PIEUP YA RIEULHIEUH + 0x9383: 0xBC5C, //HANGUL SYLLABLE PIEUP YA MIEUM + 0x9384: 0xBC5E, //HANGUL SYLLABLE PIEUP YA PIEUPSIOS + 0x9385: 0xBC5F, //HANGUL SYLLABLE PIEUP YA SIOS + 0x9386: 0xBC60, //HANGUL SYLLABLE PIEUP YA SSANGSIOS + 0x9387: 0xBC61, //HANGUL SYLLABLE PIEUP YA IEUNG + 0x9388: 0xBC62, //HANGUL SYLLABLE PIEUP YA CIEUC + 0x9389: 0xBC63, //HANGUL SYLLABLE PIEUP YA CHIEUCH + 0x938A: 0xBC64, //HANGUL SYLLABLE PIEUP YA KHIEUKH + 0x938B: 0xBC65, //HANGUL SYLLABLE PIEUP YA THIEUTH + 0x938C: 0xBC66, //HANGUL SYLLABLE PIEUP YA PHIEUPH + 0x938D: 0xBC67, //HANGUL SYLLABLE PIEUP YA HIEUH + 0x938E: 0xBC68, //HANGUL SYLLABLE PIEUP YAE + 0x938F: 0xBC69, //HANGUL SYLLABLE PIEUP YAE KIYEOK + 0x9390: 0xBC6A, //HANGUL SYLLABLE PIEUP YAE SSANGKIYEOK + 0x9391: 0xBC6B, //HANGUL SYLLABLE PIEUP YAE KIYEOKSIOS + 0x9392: 0xBC6C, //HANGUL SYLLABLE PIEUP YAE NIEUN + 0x9393: 0xBC6D, //HANGUL SYLLABLE PIEUP YAE NIEUNCIEUC + 0x9394: 0xBC6E, //HANGUL SYLLABLE PIEUP YAE NIEUNHIEUH + 0x9395: 0xBC6F, //HANGUL SYLLABLE PIEUP YAE TIKEUT + 0x9396: 0xBC70, //HANGUL SYLLABLE PIEUP YAE RIEUL + 0x9397: 0xBC71, //HANGUL SYLLABLE PIEUP YAE RIEULKIYEOK + 0x9398: 0xBC72, //HANGUL SYLLABLE PIEUP YAE RIEULMIEUM + 0x9399: 0xBC73, //HANGUL SYLLABLE PIEUP YAE RIEULPIEUP + 0x939A: 0xBC74, //HANGUL SYLLABLE PIEUP YAE RIEULSIOS + 0x939B: 0xBC75, //HANGUL SYLLABLE PIEUP YAE RIEULTHIEUTH + 0x939C: 0xBC76, //HANGUL SYLLABLE PIEUP YAE RIEULPHIEUPH + 0x939D: 0xBC77, //HANGUL SYLLABLE PIEUP YAE RIEULHIEUH + 0x939E: 0xBC78, //HANGUL SYLLABLE PIEUP YAE MIEUM + 0x939F: 0xBC79, //HANGUL SYLLABLE PIEUP YAE PIEUP + 0x93A0: 0xBC7A, //HANGUL SYLLABLE PIEUP YAE PIEUPSIOS + 0x93A1: 0xBC7B, //HANGUL SYLLABLE PIEUP YAE SIOS + 0x93A2: 0xBC7C, //HANGUL SYLLABLE PIEUP YAE SSANGSIOS + 0x93A3: 0xBC7D, //HANGUL SYLLABLE PIEUP YAE IEUNG + 0x93A4: 0xBC7E, //HANGUL SYLLABLE PIEUP YAE CIEUC + 0x93A5: 0xBC7F, //HANGUL SYLLABLE PIEUP YAE CHIEUCH + 0x93A6: 0xBC80, //HANGUL SYLLABLE PIEUP YAE KHIEUKH + 0x93A7: 0xBC81, //HANGUL SYLLABLE PIEUP YAE THIEUTH + 0x93A8: 0xBC82, //HANGUL SYLLABLE PIEUP YAE PHIEUPH + 0x93A9: 0xBC83, //HANGUL SYLLABLE PIEUP YAE HIEUH + 0x93AA: 0xBC86, //HANGUL SYLLABLE PIEUP EO SSANGKIYEOK + 0x93AB: 0xBC87, //HANGUL SYLLABLE PIEUP EO KIYEOKSIOS + 0x93AC: 0xBC89, //HANGUL SYLLABLE PIEUP EO NIEUNCIEUC + 0x93AD: 0xBC8A, //HANGUL SYLLABLE PIEUP EO NIEUNHIEUH + 0x93AE: 0xBC8D, //HANGUL SYLLABLE PIEUP EO RIEULKIYEOK + 0x93AF: 0xBC8F, //HANGUL SYLLABLE PIEUP EO RIEULPIEUP + 0x93B0: 0xBC90, //HANGUL SYLLABLE PIEUP EO RIEULSIOS + 0x93B1: 0xBC91, //HANGUL SYLLABLE PIEUP EO RIEULTHIEUTH + 0x93B2: 0xBC92, //HANGUL SYLLABLE PIEUP EO RIEULPHIEUPH + 0x93B3: 0xBC93, //HANGUL SYLLABLE PIEUP EO RIEULHIEUH + 0x93B4: 0xBC96, //HANGUL SYLLABLE PIEUP EO PIEUPSIOS + 0x93B5: 0xBC98, //HANGUL SYLLABLE PIEUP EO SSANGSIOS + 0x93B6: 0xBC9B, //HANGUL SYLLABLE PIEUP EO CHIEUCH + 0x93B7: 0xBC9C, //HANGUL SYLLABLE PIEUP EO KHIEUKH + 0x93B8: 0xBC9D, //HANGUL SYLLABLE PIEUP EO THIEUTH + 0x93B9: 0xBC9E, //HANGUL SYLLABLE PIEUP EO PHIEUPH + 0x93BA: 0xBC9F, //HANGUL SYLLABLE PIEUP EO HIEUH + 0x93BB: 0xBCA2, //HANGUL SYLLABLE PIEUP E SSANGKIYEOK + 0x93BC: 0xBCA3, //HANGUL SYLLABLE PIEUP E KIYEOKSIOS + 0x93BD: 0xBCA5, //HANGUL SYLLABLE PIEUP E NIEUNCIEUC + 0x93BE: 0xBCA6, //HANGUL SYLLABLE PIEUP E NIEUNHIEUH + 0x93BF: 0xBCA9, //HANGUL SYLLABLE PIEUP E RIEULKIYEOK + 0x93C0: 0xBCAA, //HANGUL SYLLABLE PIEUP E RIEULMIEUM + 0x93C1: 0xBCAB, //HANGUL SYLLABLE PIEUP E RIEULPIEUP + 0x93C2: 0xBCAC, //HANGUL SYLLABLE PIEUP E RIEULSIOS + 0x93C3: 0xBCAD, //HANGUL SYLLABLE PIEUP E RIEULTHIEUTH + 0x93C4: 0xBCAE, //HANGUL SYLLABLE PIEUP E RIEULPHIEUPH + 0x93C5: 0xBCAF, //HANGUL SYLLABLE PIEUP E RIEULHIEUH + 0x93C6: 0xBCB2, //HANGUL SYLLABLE PIEUP E PIEUPSIOS + 0x93C7: 0xBCB6, //HANGUL SYLLABLE PIEUP E CIEUC + 0x93C8: 0xBCB7, //HANGUL SYLLABLE PIEUP E CHIEUCH + 0x93C9: 0xBCB8, //HANGUL SYLLABLE PIEUP E KHIEUKH + 0x93CA: 0xBCB9, //HANGUL SYLLABLE PIEUP E THIEUTH + 0x93CB: 0xBCBA, //HANGUL SYLLABLE PIEUP E PHIEUPH + 0x93CC: 0xBCBB, //HANGUL SYLLABLE PIEUP E HIEUH + 0x93CD: 0xBCBE, //HANGUL SYLLABLE PIEUP YEO SSANGKIYEOK + 0x93CE: 0xBCBF, //HANGUL SYLLABLE PIEUP YEO KIYEOKSIOS + 0x93CF: 0xBCC1, //HANGUL SYLLABLE PIEUP YEO NIEUNCIEUC + 0x93D0: 0xBCC2, //HANGUL SYLLABLE PIEUP YEO NIEUNHIEUH + 0x93D1: 0xBCC3, //HANGUL SYLLABLE PIEUP YEO TIKEUT + 0x93D2: 0xBCC5, //HANGUL SYLLABLE PIEUP YEO RIEULKIYEOK + 0x93D3: 0xBCC6, //HANGUL SYLLABLE PIEUP YEO RIEULMIEUM + 0x93D4: 0xBCC7, //HANGUL SYLLABLE PIEUP YEO RIEULPIEUP + 0x93D5: 0xBCC8, //HANGUL SYLLABLE PIEUP YEO RIEULSIOS + 0x93D6: 0xBCC9, //HANGUL SYLLABLE PIEUP YEO RIEULTHIEUTH + 0x93D7: 0xBCCA, //HANGUL SYLLABLE PIEUP YEO RIEULPHIEUPH + 0x93D8: 0xBCCB, //HANGUL SYLLABLE PIEUP YEO RIEULHIEUH + 0x93D9: 0xBCCC, //HANGUL SYLLABLE PIEUP YEO MIEUM + 0x93DA: 0xBCCE, //HANGUL SYLLABLE PIEUP YEO PIEUPSIOS + 0x93DB: 0xBCD2, //HANGUL SYLLABLE PIEUP YEO CIEUC + 0x93DC: 0xBCD3, //HANGUL SYLLABLE PIEUP YEO CHIEUCH + 0x93DD: 0xBCD4, //HANGUL SYLLABLE PIEUP YEO KHIEUKH + 0x93DE: 0xBCD6, //HANGUL SYLLABLE PIEUP YEO PHIEUPH + 0x93DF: 0xBCD7, //HANGUL SYLLABLE PIEUP YEO HIEUH + 0x93E0: 0xBCD9, //HANGUL SYLLABLE PIEUP YE KIYEOK + 0x93E1: 0xBCDA, //HANGUL SYLLABLE PIEUP YE SSANGKIYEOK + 0x93E2: 0xBCDB, //HANGUL SYLLABLE PIEUP YE KIYEOKSIOS + 0x93E3: 0xBCDD, //HANGUL SYLLABLE PIEUP YE NIEUNCIEUC + 0x93E4: 0xBCDE, //HANGUL SYLLABLE PIEUP YE NIEUNHIEUH + 0x93E5: 0xBCDF, //HANGUL SYLLABLE PIEUP YE TIKEUT + 0x93E6: 0xBCE0, //HANGUL SYLLABLE PIEUP YE RIEUL + 0x93E7: 0xBCE1, //HANGUL SYLLABLE PIEUP YE RIEULKIYEOK + 0x93E8: 0xBCE2, //HANGUL SYLLABLE PIEUP YE RIEULMIEUM + 0x93E9: 0xBCE3, //HANGUL SYLLABLE PIEUP YE RIEULPIEUP + 0x93EA: 0xBCE4, //HANGUL SYLLABLE PIEUP YE RIEULSIOS + 0x93EB: 0xBCE5, //HANGUL SYLLABLE PIEUP YE RIEULTHIEUTH + 0x93EC: 0xBCE6, //HANGUL SYLLABLE PIEUP YE RIEULPHIEUPH + 0x93ED: 0xBCE7, //HANGUL SYLLABLE PIEUP YE RIEULHIEUH + 0x93EE: 0xBCE8, //HANGUL SYLLABLE PIEUP YE MIEUM + 0x93EF: 0xBCE9, //HANGUL SYLLABLE PIEUP YE PIEUP + 0x93F0: 0xBCEA, //HANGUL SYLLABLE PIEUP YE PIEUPSIOS + 0x93F1: 0xBCEB, //HANGUL SYLLABLE PIEUP YE SIOS + 0x93F2: 0xBCEC, //HANGUL SYLLABLE PIEUP YE SSANGSIOS + 0x93F3: 0xBCED, //HANGUL SYLLABLE PIEUP YE IEUNG + 0x93F4: 0xBCEE, //HANGUL SYLLABLE PIEUP YE CIEUC + 0x93F5: 0xBCEF, //HANGUL SYLLABLE PIEUP YE CHIEUCH + 0x93F6: 0xBCF0, //HANGUL SYLLABLE PIEUP YE KHIEUKH + 0x93F7: 0xBCF1, //HANGUL SYLLABLE PIEUP YE THIEUTH + 0x93F8: 0xBCF2, //HANGUL SYLLABLE PIEUP YE PHIEUPH + 0x93F9: 0xBCF3, //HANGUL SYLLABLE PIEUP YE HIEUH + 0x93FA: 0xBCF7, //HANGUL SYLLABLE PIEUP O KIYEOKSIOS + 0x93FB: 0xBCF9, //HANGUL SYLLABLE PIEUP O NIEUNCIEUC + 0x93FC: 0xBCFA, //HANGUL SYLLABLE PIEUP O NIEUNHIEUH + 0x93FD: 0xBCFB, //HANGUL SYLLABLE PIEUP O TIKEUT + 0x93FE: 0xBCFD, //HANGUL SYLLABLE PIEUP O RIEULKIYEOK + 0x9441: 0xBCFE, //HANGUL SYLLABLE PIEUP O RIEULMIEUM + 0x9442: 0xBCFF, //HANGUL SYLLABLE PIEUP O RIEULPIEUP + 0x9443: 0xBD00, //HANGUL SYLLABLE PIEUP O RIEULSIOS + 0x9444: 0xBD01, //HANGUL SYLLABLE PIEUP O RIEULTHIEUTH + 0x9445: 0xBD02, //HANGUL SYLLABLE PIEUP O RIEULPHIEUPH + 0x9446: 0xBD03, //HANGUL SYLLABLE PIEUP O RIEULHIEUH + 0x9447: 0xBD06, //HANGUL SYLLABLE PIEUP O PIEUPSIOS + 0x9448: 0xBD08, //HANGUL SYLLABLE PIEUP O SSANGSIOS + 0x9449: 0xBD0A, //HANGUL SYLLABLE PIEUP O CIEUC + 0x944A: 0xBD0B, //HANGUL SYLLABLE PIEUP O CHIEUCH + 0x944B: 0xBD0C, //HANGUL SYLLABLE PIEUP O KHIEUKH + 0x944C: 0xBD0D, //HANGUL SYLLABLE PIEUP O THIEUTH + 0x944D: 0xBD0E, //HANGUL SYLLABLE PIEUP O PHIEUPH + 0x944E: 0xBD0F, //HANGUL SYLLABLE PIEUP O HIEUH + 0x944F: 0xBD11, //HANGUL SYLLABLE PIEUP WA KIYEOK + 0x9450: 0xBD12, //HANGUL SYLLABLE PIEUP WA SSANGKIYEOK + 0x9451: 0xBD13, //HANGUL SYLLABLE PIEUP WA KIYEOKSIOS + 0x9452: 0xBD15, //HANGUL SYLLABLE PIEUP WA NIEUNCIEUC + 0x9453: 0xBD16, //HANGUL SYLLABLE PIEUP WA NIEUNHIEUH + 0x9454: 0xBD17, //HANGUL SYLLABLE PIEUP WA TIKEUT + 0x9455: 0xBD18, //HANGUL SYLLABLE PIEUP WA RIEUL + 0x9456: 0xBD19, //HANGUL SYLLABLE PIEUP WA RIEULKIYEOK + 0x9457: 0xBD1A, //HANGUL SYLLABLE PIEUP WA RIEULMIEUM + 0x9458: 0xBD1B, //HANGUL SYLLABLE PIEUP WA RIEULPIEUP + 0x9459: 0xBD1C, //HANGUL SYLLABLE PIEUP WA RIEULSIOS + 0x945A: 0xBD1D, //HANGUL SYLLABLE PIEUP WA RIEULTHIEUTH + 0x9461: 0xBD1E, //HANGUL SYLLABLE PIEUP WA RIEULPHIEUPH + 0x9462: 0xBD1F, //HANGUL SYLLABLE PIEUP WA RIEULHIEUH + 0x9463: 0xBD20, //HANGUL SYLLABLE PIEUP WA MIEUM + 0x9464: 0xBD21, //HANGUL SYLLABLE PIEUP WA PIEUP + 0x9465: 0xBD22, //HANGUL SYLLABLE PIEUP WA PIEUPSIOS + 0x9466: 0xBD23, //HANGUL SYLLABLE PIEUP WA SIOS + 0x9467: 0xBD25, //HANGUL SYLLABLE PIEUP WA IEUNG + 0x9468: 0xBD26, //HANGUL SYLLABLE PIEUP WA CIEUC + 0x9469: 0xBD27, //HANGUL SYLLABLE PIEUP WA CHIEUCH + 0x946A: 0xBD28, //HANGUL SYLLABLE PIEUP WA KHIEUKH + 0x946B: 0xBD29, //HANGUL SYLLABLE PIEUP WA THIEUTH + 0x946C: 0xBD2A, //HANGUL SYLLABLE PIEUP WA PHIEUPH + 0x946D: 0xBD2B, //HANGUL SYLLABLE PIEUP WA HIEUH + 0x946E: 0xBD2D, //HANGUL SYLLABLE PIEUP WAE KIYEOK + 0x946F: 0xBD2E, //HANGUL SYLLABLE PIEUP WAE SSANGKIYEOK + 0x9470: 0xBD2F, //HANGUL SYLLABLE PIEUP WAE KIYEOKSIOS + 0x9471: 0xBD30, //HANGUL SYLLABLE PIEUP WAE NIEUN + 0x9472: 0xBD31, //HANGUL SYLLABLE PIEUP WAE NIEUNCIEUC + 0x9473: 0xBD32, //HANGUL SYLLABLE PIEUP WAE NIEUNHIEUH + 0x9474: 0xBD33, //HANGUL SYLLABLE PIEUP WAE TIKEUT + 0x9475: 0xBD34, //HANGUL SYLLABLE PIEUP WAE RIEUL + 0x9476: 0xBD35, //HANGUL SYLLABLE PIEUP WAE RIEULKIYEOK + 0x9477: 0xBD36, //HANGUL SYLLABLE PIEUP WAE RIEULMIEUM + 0x9478: 0xBD37, //HANGUL SYLLABLE PIEUP WAE RIEULPIEUP + 0x9479: 0xBD38, //HANGUL SYLLABLE PIEUP WAE RIEULSIOS + 0x947A: 0xBD39, //HANGUL SYLLABLE PIEUP WAE RIEULTHIEUTH + 0x9481: 0xBD3A, //HANGUL SYLLABLE PIEUP WAE RIEULPHIEUPH + 0x9482: 0xBD3B, //HANGUL SYLLABLE PIEUP WAE RIEULHIEUH + 0x9483: 0xBD3C, //HANGUL SYLLABLE PIEUP WAE MIEUM + 0x9484: 0xBD3D, //HANGUL SYLLABLE PIEUP WAE PIEUP + 0x9485: 0xBD3E, //HANGUL SYLLABLE PIEUP WAE PIEUPSIOS + 0x9486: 0xBD3F, //HANGUL SYLLABLE PIEUP WAE SIOS + 0x9487: 0xBD41, //HANGUL SYLLABLE PIEUP WAE IEUNG + 0x9488: 0xBD42, //HANGUL SYLLABLE PIEUP WAE CIEUC + 0x9489: 0xBD43, //HANGUL SYLLABLE PIEUP WAE CHIEUCH + 0x948A: 0xBD44, //HANGUL SYLLABLE PIEUP WAE KHIEUKH + 0x948B: 0xBD45, //HANGUL SYLLABLE PIEUP WAE THIEUTH + 0x948C: 0xBD46, //HANGUL SYLLABLE PIEUP WAE PHIEUPH + 0x948D: 0xBD47, //HANGUL SYLLABLE PIEUP WAE HIEUH + 0x948E: 0xBD4A, //HANGUL SYLLABLE PIEUP OE SSANGKIYEOK + 0x948F: 0xBD4B, //HANGUL SYLLABLE PIEUP OE KIYEOKSIOS + 0x9490: 0xBD4D, //HANGUL SYLLABLE PIEUP OE NIEUNCIEUC + 0x9491: 0xBD4E, //HANGUL SYLLABLE PIEUP OE NIEUNHIEUH + 0x9492: 0xBD4F, //HANGUL SYLLABLE PIEUP OE TIKEUT + 0x9493: 0xBD51, //HANGUL SYLLABLE PIEUP OE RIEULKIYEOK + 0x9494: 0xBD52, //HANGUL SYLLABLE PIEUP OE RIEULMIEUM + 0x9495: 0xBD53, //HANGUL SYLLABLE PIEUP OE RIEULPIEUP + 0x9496: 0xBD54, //HANGUL SYLLABLE PIEUP OE RIEULSIOS + 0x9497: 0xBD55, //HANGUL SYLLABLE PIEUP OE RIEULTHIEUTH + 0x9498: 0xBD56, //HANGUL SYLLABLE PIEUP OE RIEULPHIEUPH + 0x9499: 0xBD57, //HANGUL SYLLABLE PIEUP OE RIEULHIEUH + 0x949A: 0xBD5A, //HANGUL SYLLABLE PIEUP OE PIEUPSIOS + 0x949B: 0xBD5B, //HANGUL SYLLABLE PIEUP OE SIOS + 0x949C: 0xBD5C, //HANGUL SYLLABLE PIEUP OE SSANGSIOS + 0x949D: 0xBD5D, //HANGUL SYLLABLE PIEUP OE IEUNG + 0x949E: 0xBD5E, //HANGUL SYLLABLE PIEUP OE CIEUC + 0x949F: 0xBD5F, //HANGUL SYLLABLE PIEUP OE CHIEUCH + 0x94A0: 0xBD60, //HANGUL SYLLABLE PIEUP OE KHIEUKH + 0x94A1: 0xBD61, //HANGUL SYLLABLE PIEUP OE THIEUTH + 0x94A2: 0xBD62, //HANGUL SYLLABLE PIEUP OE PHIEUPH + 0x94A3: 0xBD63, //HANGUL SYLLABLE PIEUP OE HIEUH + 0x94A4: 0xBD65, //HANGUL SYLLABLE PIEUP YO KIYEOK + 0x94A5: 0xBD66, //HANGUL SYLLABLE PIEUP YO SSANGKIYEOK + 0x94A6: 0xBD67, //HANGUL SYLLABLE PIEUP YO KIYEOKSIOS + 0x94A7: 0xBD69, //HANGUL SYLLABLE PIEUP YO NIEUNCIEUC + 0x94A8: 0xBD6A, //HANGUL SYLLABLE PIEUP YO NIEUNHIEUH + 0x94A9: 0xBD6B, //HANGUL SYLLABLE PIEUP YO TIKEUT + 0x94AA: 0xBD6C, //HANGUL SYLLABLE PIEUP YO RIEUL + 0x94AB: 0xBD6D, //HANGUL SYLLABLE PIEUP YO RIEULKIYEOK + 0x94AC: 0xBD6E, //HANGUL SYLLABLE PIEUP YO RIEULMIEUM + 0x94AD: 0xBD6F, //HANGUL SYLLABLE PIEUP YO RIEULPIEUP + 0x94AE: 0xBD70, //HANGUL SYLLABLE PIEUP YO RIEULSIOS + 0x94AF: 0xBD71, //HANGUL SYLLABLE PIEUP YO RIEULTHIEUTH + 0x94B0: 0xBD72, //HANGUL SYLLABLE PIEUP YO RIEULPHIEUPH + 0x94B1: 0xBD73, //HANGUL SYLLABLE PIEUP YO RIEULHIEUH + 0x94B2: 0xBD74, //HANGUL SYLLABLE PIEUP YO MIEUM + 0x94B3: 0xBD75, //HANGUL SYLLABLE PIEUP YO PIEUP + 0x94B4: 0xBD76, //HANGUL SYLLABLE PIEUP YO PIEUPSIOS + 0x94B5: 0xBD77, //HANGUL SYLLABLE PIEUP YO SIOS + 0x94B6: 0xBD78, //HANGUL SYLLABLE PIEUP YO SSANGSIOS + 0x94B7: 0xBD79, //HANGUL SYLLABLE PIEUP YO IEUNG + 0x94B8: 0xBD7A, //HANGUL SYLLABLE PIEUP YO CIEUC + 0x94B9: 0xBD7B, //HANGUL SYLLABLE PIEUP YO CHIEUCH + 0x94BA: 0xBD7C, //HANGUL SYLLABLE PIEUP YO KHIEUKH + 0x94BB: 0xBD7D, //HANGUL SYLLABLE PIEUP YO THIEUTH + 0x94BC: 0xBD7E, //HANGUL SYLLABLE PIEUP YO PHIEUPH + 0x94BD: 0xBD7F, //HANGUL SYLLABLE PIEUP YO HIEUH + 0x94BE: 0xBD82, //HANGUL SYLLABLE PIEUP U SSANGKIYEOK + 0x94BF: 0xBD83, //HANGUL SYLLABLE PIEUP U KIYEOKSIOS + 0x94C0: 0xBD85, //HANGUL SYLLABLE PIEUP U NIEUNCIEUC + 0x94C1: 0xBD86, //HANGUL SYLLABLE PIEUP U NIEUNHIEUH + 0x94C2: 0xBD8B, //HANGUL SYLLABLE PIEUP U RIEULPIEUP + 0x94C3: 0xBD8C, //HANGUL SYLLABLE PIEUP U RIEULSIOS + 0x94C4: 0xBD8D, //HANGUL SYLLABLE PIEUP U RIEULTHIEUTH + 0x94C5: 0xBD8E, //HANGUL SYLLABLE PIEUP U RIEULPHIEUPH + 0x94C6: 0xBD8F, //HANGUL SYLLABLE PIEUP U RIEULHIEUH + 0x94C7: 0xBD92, //HANGUL SYLLABLE PIEUP U PIEUPSIOS + 0x94C8: 0xBD94, //HANGUL SYLLABLE PIEUP U SSANGSIOS + 0x94C9: 0xBD96, //HANGUL SYLLABLE PIEUP U CIEUC + 0x94CA: 0xBD97, //HANGUL SYLLABLE PIEUP U CHIEUCH + 0x94CB: 0xBD98, //HANGUL SYLLABLE PIEUP U KHIEUKH + 0x94CC: 0xBD9B, //HANGUL SYLLABLE PIEUP U HIEUH + 0x94CD: 0xBD9D, //HANGUL SYLLABLE PIEUP WEO KIYEOK + 0x94CE: 0xBD9E, //HANGUL SYLLABLE PIEUP WEO SSANGKIYEOK + 0x94CF: 0xBD9F, //HANGUL SYLLABLE PIEUP WEO KIYEOKSIOS + 0x94D0: 0xBDA0, //HANGUL SYLLABLE PIEUP WEO NIEUN + 0x94D1: 0xBDA1, //HANGUL SYLLABLE PIEUP WEO NIEUNCIEUC + 0x94D2: 0xBDA2, //HANGUL SYLLABLE PIEUP WEO NIEUNHIEUH + 0x94D3: 0xBDA3, //HANGUL SYLLABLE PIEUP WEO TIKEUT + 0x94D4: 0xBDA5, //HANGUL SYLLABLE PIEUP WEO RIEULKIYEOK + 0x94D5: 0xBDA6, //HANGUL SYLLABLE PIEUP WEO RIEULMIEUM + 0x94D6: 0xBDA7, //HANGUL SYLLABLE PIEUP WEO RIEULPIEUP + 0x94D7: 0xBDA8, //HANGUL SYLLABLE PIEUP WEO RIEULSIOS + 0x94D8: 0xBDA9, //HANGUL SYLLABLE PIEUP WEO RIEULTHIEUTH + 0x94D9: 0xBDAA, //HANGUL SYLLABLE PIEUP WEO RIEULPHIEUPH + 0x94DA: 0xBDAB, //HANGUL SYLLABLE PIEUP WEO RIEULHIEUH + 0x94DB: 0xBDAC, //HANGUL SYLLABLE PIEUP WEO MIEUM + 0x94DC: 0xBDAD, //HANGUL SYLLABLE PIEUP WEO PIEUP + 0x94DD: 0xBDAE, //HANGUL SYLLABLE PIEUP WEO PIEUPSIOS + 0x94DE: 0xBDAF, //HANGUL SYLLABLE PIEUP WEO SIOS + 0x94DF: 0xBDB1, //HANGUL SYLLABLE PIEUP WEO IEUNG + 0x94E0: 0xBDB2, //HANGUL SYLLABLE PIEUP WEO CIEUC + 0x94E1: 0xBDB3, //HANGUL SYLLABLE PIEUP WEO CHIEUCH + 0x94E2: 0xBDB4, //HANGUL SYLLABLE PIEUP WEO KHIEUKH + 0x94E3: 0xBDB5, //HANGUL SYLLABLE PIEUP WEO THIEUTH + 0x94E4: 0xBDB6, //HANGUL SYLLABLE PIEUP WEO PHIEUPH + 0x94E5: 0xBDB7, //HANGUL SYLLABLE PIEUP WEO HIEUH + 0x94E6: 0xBDB9, //HANGUL SYLLABLE PIEUP WE KIYEOK + 0x94E7: 0xBDBA, //HANGUL SYLLABLE PIEUP WE SSANGKIYEOK + 0x94E8: 0xBDBB, //HANGUL SYLLABLE PIEUP WE KIYEOKSIOS + 0x94E9: 0xBDBC, //HANGUL SYLLABLE PIEUP WE NIEUN + 0x94EA: 0xBDBD, //HANGUL SYLLABLE PIEUP WE NIEUNCIEUC + 0x94EB: 0xBDBE, //HANGUL SYLLABLE PIEUP WE NIEUNHIEUH + 0x94EC: 0xBDBF, //HANGUL SYLLABLE PIEUP WE TIKEUT + 0x94ED: 0xBDC0, //HANGUL SYLLABLE PIEUP WE RIEUL + 0x94EE: 0xBDC1, //HANGUL SYLLABLE PIEUP WE RIEULKIYEOK + 0x94EF: 0xBDC2, //HANGUL SYLLABLE PIEUP WE RIEULMIEUM + 0x94F0: 0xBDC3, //HANGUL SYLLABLE PIEUP WE RIEULPIEUP + 0x94F1: 0xBDC4, //HANGUL SYLLABLE PIEUP WE RIEULSIOS + 0x94F2: 0xBDC5, //HANGUL SYLLABLE PIEUP WE RIEULTHIEUTH + 0x94F3: 0xBDC6, //HANGUL SYLLABLE PIEUP WE RIEULPHIEUPH + 0x94F4: 0xBDC7, //HANGUL SYLLABLE PIEUP WE RIEULHIEUH + 0x94F5: 0xBDC8, //HANGUL SYLLABLE PIEUP WE MIEUM + 0x94F6: 0xBDC9, //HANGUL SYLLABLE PIEUP WE PIEUP + 0x94F7: 0xBDCA, //HANGUL SYLLABLE PIEUP WE PIEUPSIOS + 0x94F8: 0xBDCB, //HANGUL SYLLABLE PIEUP WE SIOS + 0x94F9: 0xBDCC, //HANGUL SYLLABLE PIEUP WE SSANGSIOS + 0x94FA: 0xBDCD, //HANGUL SYLLABLE PIEUP WE IEUNG + 0x94FB: 0xBDCE, //HANGUL SYLLABLE PIEUP WE CIEUC + 0x94FC: 0xBDCF, //HANGUL SYLLABLE PIEUP WE CHIEUCH + 0x94FD: 0xBDD0, //HANGUL SYLLABLE PIEUP WE KHIEUKH + 0x94FE: 0xBDD1, //HANGUL SYLLABLE PIEUP WE THIEUTH + 0x9541: 0xBDD2, //HANGUL SYLLABLE PIEUP WE PHIEUPH + 0x9542: 0xBDD3, //HANGUL SYLLABLE PIEUP WE HIEUH + 0x9543: 0xBDD6, //HANGUL SYLLABLE PIEUP WI SSANGKIYEOK + 0x9544: 0xBDD7, //HANGUL SYLLABLE PIEUP WI KIYEOKSIOS + 0x9545: 0xBDD9, //HANGUL SYLLABLE PIEUP WI NIEUNCIEUC + 0x9546: 0xBDDA, //HANGUL SYLLABLE PIEUP WI NIEUNHIEUH + 0x9547: 0xBDDB, //HANGUL SYLLABLE PIEUP WI TIKEUT + 0x9548: 0xBDDD, //HANGUL SYLLABLE PIEUP WI RIEULKIYEOK + 0x9549: 0xBDDE, //HANGUL SYLLABLE PIEUP WI RIEULMIEUM + 0x954A: 0xBDDF, //HANGUL SYLLABLE PIEUP WI RIEULPIEUP + 0x954B: 0xBDE0, //HANGUL SYLLABLE PIEUP WI RIEULSIOS + 0x954C: 0xBDE1, //HANGUL SYLLABLE PIEUP WI RIEULTHIEUTH + 0x954D: 0xBDE2, //HANGUL SYLLABLE PIEUP WI RIEULPHIEUPH + 0x954E: 0xBDE3, //HANGUL SYLLABLE PIEUP WI RIEULHIEUH + 0x954F: 0xBDE4, //HANGUL SYLLABLE PIEUP WI MIEUM + 0x9550: 0xBDE5, //HANGUL SYLLABLE PIEUP WI PIEUP + 0x9551: 0xBDE6, //HANGUL SYLLABLE PIEUP WI PIEUPSIOS + 0x9552: 0xBDE7, //HANGUL SYLLABLE PIEUP WI SIOS + 0x9553: 0xBDE8, //HANGUL SYLLABLE PIEUP WI SSANGSIOS + 0x9554: 0xBDEA, //HANGUL SYLLABLE PIEUP WI CIEUC + 0x9555: 0xBDEB, //HANGUL SYLLABLE PIEUP WI CHIEUCH + 0x9556: 0xBDEC, //HANGUL SYLLABLE PIEUP WI KHIEUKH + 0x9557: 0xBDED, //HANGUL SYLLABLE PIEUP WI THIEUTH + 0x9558: 0xBDEE, //HANGUL SYLLABLE PIEUP WI PHIEUPH + 0x9559: 0xBDEF, //HANGUL SYLLABLE PIEUP WI HIEUH + 0x955A: 0xBDF1, //HANGUL SYLLABLE PIEUP YU KIYEOK + 0x9561: 0xBDF2, //HANGUL SYLLABLE PIEUP YU SSANGKIYEOK + 0x9562: 0xBDF3, //HANGUL SYLLABLE PIEUP YU KIYEOKSIOS + 0x9563: 0xBDF5, //HANGUL SYLLABLE PIEUP YU NIEUNCIEUC + 0x9564: 0xBDF6, //HANGUL SYLLABLE PIEUP YU NIEUNHIEUH + 0x9565: 0xBDF7, //HANGUL SYLLABLE PIEUP YU TIKEUT + 0x9566: 0xBDF9, //HANGUL SYLLABLE PIEUP YU RIEULKIYEOK + 0x9567: 0xBDFA, //HANGUL SYLLABLE PIEUP YU RIEULMIEUM + 0x9568: 0xBDFB, //HANGUL SYLLABLE PIEUP YU RIEULPIEUP + 0x9569: 0xBDFC, //HANGUL SYLLABLE PIEUP YU RIEULSIOS + 0x956A: 0xBDFD, //HANGUL SYLLABLE PIEUP YU RIEULTHIEUTH + 0x956B: 0xBDFE, //HANGUL SYLLABLE PIEUP YU RIEULPHIEUPH + 0x956C: 0xBDFF, //HANGUL SYLLABLE PIEUP YU RIEULHIEUH + 0x956D: 0xBE01, //HANGUL SYLLABLE PIEUP YU PIEUP + 0x956E: 0xBE02, //HANGUL SYLLABLE PIEUP YU PIEUPSIOS + 0x956F: 0xBE04, //HANGUL SYLLABLE PIEUP YU SSANGSIOS + 0x9570: 0xBE06, //HANGUL SYLLABLE PIEUP YU CIEUC + 0x9571: 0xBE07, //HANGUL SYLLABLE PIEUP YU CHIEUCH + 0x9572: 0xBE08, //HANGUL SYLLABLE PIEUP YU KHIEUKH + 0x9573: 0xBE09, //HANGUL SYLLABLE PIEUP YU THIEUTH + 0x9574: 0xBE0A, //HANGUL SYLLABLE PIEUP YU PHIEUPH + 0x9575: 0xBE0B, //HANGUL SYLLABLE PIEUP YU HIEUH + 0x9576: 0xBE0E, //HANGUL SYLLABLE PIEUP EU SSANGKIYEOK + 0x9577: 0xBE0F, //HANGUL SYLLABLE PIEUP EU KIYEOKSIOS + 0x9578: 0xBE11, //HANGUL SYLLABLE PIEUP EU NIEUNCIEUC + 0x9579: 0xBE12, //HANGUL SYLLABLE PIEUP EU NIEUNHIEUH + 0x957A: 0xBE13, //HANGUL SYLLABLE PIEUP EU TIKEUT + 0x9581: 0xBE15, //HANGUL SYLLABLE PIEUP EU RIEULKIYEOK + 0x9582: 0xBE16, //HANGUL SYLLABLE PIEUP EU RIEULMIEUM + 0x9583: 0xBE17, //HANGUL SYLLABLE PIEUP EU RIEULPIEUP + 0x9584: 0xBE18, //HANGUL SYLLABLE PIEUP EU RIEULSIOS + 0x9585: 0xBE19, //HANGUL SYLLABLE PIEUP EU RIEULTHIEUTH + 0x9586: 0xBE1A, //HANGUL SYLLABLE PIEUP EU RIEULPHIEUPH + 0x9587: 0xBE1B, //HANGUL SYLLABLE PIEUP EU RIEULHIEUH + 0x9588: 0xBE1E, //HANGUL SYLLABLE PIEUP EU PIEUPSIOS + 0x9589: 0xBE20, //HANGUL SYLLABLE PIEUP EU SSANGSIOS + 0x958A: 0xBE21, //HANGUL SYLLABLE PIEUP EU IEUNG + 0x958B: 0xBE22, //HANGUL SYLLABLE PIEUP EU CIEUC + 0x958C: 0xBE23, //HANGUL SYLLABLE PIEUP EU CHIEUCH + 0x958D: 0xBE24, //HANGUL SYLLABLE PIEUP EU KHIEUKH + 0x958E: 0xBE25, //HANGUL SYLLABLE PIEUP EU THIEUTH + 0x958F: 0xBE26, //HANGUL SYLLABLE PIEUP EU PHIEUPH + 0x9590: 0xBE27, //HANGUL SYLLABLE PIEUP EU HIEUH + 0x9591: 0xBE28, //HANGUL SYLLABLE PIEUP YI + 0x9592: 0xBE29, //HANGUL SYLLABLE PIEUP YI KIYEOK + 0x9593: 0xBE2A, //HANGUL SYLLABLE PIEUP YI SSANGKIYEOK + 0x9594: 0xBE2B, //HANGUL SYLLABLE PIEUP YI KIYEOKSIOS + 0x9595: 0xBE2C, //HANGUL SYLLABLE PIEUP YI NIEUN + 0x9596: 0xBE2D, //HANGUL SYLLABLE PIEUP YI NIEUNCIEUC + 0x9597: 0xBE2E, //HANGUL SYLLABLE PIEUP YI NIEUNHIEUH + 0x9598: 0xBE2F, //HANGUL SYLLABLE PIEUP YI TIKEUT + 0x9599: 0xBE30, //HANGUL SYLLABLE PIEUP YI RIEUL + 0x959A: 0xBE31, //HANGUL SYLLABLE PIEUP YI RIEULKIYEOK + 0x959B: 0xBE32, //HANGUL SYLLABLE PIEUP YI RIEULMIEUM + 0x959C: 0xBE33, //HANGUL SYLLABLE PIEUP YI RIEULPIEUP + 0x959D: 0xBE34, //HANGUL SYLLABLE PIEUP YI RIEULSIOS + 0x959E: 0xBE35, //HANGUL SYLLABLE PIEUP YI RIEULTHIEUTH + 0x959F: 0xBE36, //HANGUL SYLLABLE PIEUP YI RIEULPHIEUPH + 0x95A0: 0xBE37, //HANGUL SYLLABLE PIEUP YI RIEULHIEUH + 0x95A1: 0xBE38, //HANGUL SYLLABLE PIEUP YI MIEUM + 0x95A2: 0xBE39, //HANGUL SYLLABLE PIEUP YI PIEUP + 0x95A3: 0xBE3A, //HANGUL SYLLABLE PIEUP YI PIEUPSIOS + 0x95A4: 0xBE3B, //HANGUL SYLLABLE PIEUP YI SIOS + 0x95A5: 0xBE3C, //HANGUL SYLLABLE PIEUP YI SSANGSIOS + 0x95A6: 0xBE3D, //HANGUL SYLLABLE PIEUP YI IEUNG + 0x95A7: 0xBE3E, //HANGUL SYLLABLE PIEUP YI CIEUC + 0x95A8: 0xBE3F, //HANGUL SYLLABLE PIEUP YI CHIEUCH + 0x95A9: 0xBE40, //HANGUL SYLLABLE PIEUP YI KHIEUKH + 0x95AA: 0xBE41, //HANGUL SYLLABLE PIEUP YI THIEUTH + 0x95AB: 0xBE42, //HANGUL SYLLABLE PIEUP YI PHIEUPH + 0x95AC: 0xBE43, //HANGUL SYLLABLE PIEUP YI HIEUH + 0x95AD: 0xBE46, //HANGUL SYLLABLE PIEUP I SSANGKIYEOK + 0x95AE: 0xBE47, //HANGUL SYLLABLE PIEUP I KIYEOKSIOS + 0x95AF: 0xBE49, //HANGUL SYLLABLE PIEUP I NIEUNCIEUC + 0x95B0: 0xBE4A, //HANGUL SYLLABLE PIEUP I NIEUNHIEUH + 0x95B1: 0xBE4B, //HANGUL SYLLABLE PIEUP I TIKEUT + 0x95B2: 0xBE4D, //HANGUL SYLLABLE PIEUP I RIEULKIYEOK + 0x95B3: 0xBE4F, //HANGUL SYLLABLE PIEUP I RIEULPIEUP + 0x95B4: 0xBE50, //HANGUL SYLLABLE PIEUP I RIEULSIOS + 0x95B5: 0xBE51, //HANGUL SYLLABLE PIEUP I RIEULTHIEUTH + 0x95B6: 0xBE52, //HANGUL SYLLABLE PIEUP I RIEULPHIEUPH + 0x95B7: 0xBE53, //HANGUL SYLLABLE PIEUP I RIEULHIEUH + 0x95B8: 0xBE56, //HANGUL SYLLABLE PIEUP I PIEUPSIOS + 0x95B9: 0xBE58, //HANGUL SYLLABLE PIEUP I SSANGSIOS + 0x95BA: 0xBE5C, //HANGUL SYLLABLE PIEUP I KHIEUKH + 0x95BB: 0xBE5D, //HANGUL SYLLABLE PIEUP I THIEUTH + 0x95BC: 0xBE5E, //HANGUL SYLLABLE PIEUP I PHIEUPH + 0x95BD: 0xBE5F, //HANGUL SYLLABLE PIEUP I HIEUH + 0x95BE: 0xBE62, //HANGUL SYLLABLE SSANGPIEUP A SSANGKIYEOK + 0x95BF: 0xBE63, //HANGUL SYLLABLE SSANGPIEUP A KIYEOKSIOS + 0x95C0: 0xBE65, //HANGUL SYLLABLE SSANGPIEUP A NIEUNCIEUC + 0x95C1: 0xBE66, //HANGUL SYLLABLE SSANGPIEUP A NIEUNHIEUH + 0x95C2: 0xBE67, //HANGUL SYLLABLE SSANGPIEUP A TIKEUT + 0x95C3: 0xBE69, //HANGUL SYLLABLE SSANGPIEUP A RIEULKIYEOK + 0x95C4: 0xBE6B, //HANGUL SYLLABLE SSANGPIEUP A RIEULPIEUP + 0x95C5: 0xBE6C, //HANGUL SYLLABLE SSANGPIEUP A RIEULSIOS + 0x95C6: 0xBE6D, //HANGUL SYLLABLE SSANGPIEUP A RIEULTHIEUTH + 0x95C7: 0xBE6E, //HANGUL SYLLABLE SSANGPIEUP A RIEULPHIEUPH + 0x95C8: 0xBE6F, //HANGUL SYLLABLE SSANGPIEUP A RIEULHIEUH + 0x95C9: 0xBE72, //HANGUL SYLLABLE SSANGPIEUP A PIEUPSIOS + 0x95CA: 0xBE76, //HANGUL SYLLABLE SSANGPIEUP A CIEUC + 0x95CB: 0xBE77, //HANGUL SYLLABLE SSANGPIEUP A CHIEUCH + 0x95CC: 0xBE78, //HANGUL SYLLABLE SSANGPIEUP A KHIEUKH + 0x95CD: 0xBE79, //HANGUL SYLLABLE SSANGPIEUP A THIEUTH + 0x95CE: 0xBE7A, //HANGUL SYLLABLE SSANGPIEUP A PHIEUPH + 0x95CF: 0xBE7E, //HANGUL SYLLABLE SSANGPIEUP AE SSANGKIYEOK + 0x95D0: 0xBE7F, //HANGUL SYLLABLE SSANGPIEUP AE KIYEOKSIOS + 0x95D1: 0xBE81, //HANGUL SYLLABLE SSANGPIEUP AE NIEUNCIEUC + 0x95D2: 0xBE82, //HANGUL SYLLABLE SSANGPIEUP AE NIEUNHIEUH + 0x95D3: 0xBE83, //HANGUL SYLLABLE SSANGPIEUP AE TIKEUT + 0x95D4: 0xBE85, //HANGUL SYLLABLE SSANGPIEUP AE RIEULKIYEOK + 0x95D5: 0xBE86, //HANGUL SYLLABLE SSANGPIEUP AE RIEULMIEUM + 0x95D6: 0xBE87, //HANGUL SYLLABLE SSANGPIEUP AE RIEULPIEUP + 0x95D7: 0xBE88, //HANGUL SYLLABLE SSANGPIEUP AE RIEULSIOS + 0x95D8: 0xBE89, //HANGUL SYLLABLE SSANGPIEUP AE RIEULTHIEUTH + 0x95D9: 0xBE8A, //HANGUL SYLLABLE SSANGPIEUP AE RIEULPHIEUPH + 0x95DA: 0xBE8B, //HANGUL SYLLABLE SSANGPIEUP AE RIEULHIEUH + 0x95DB: 0xBE8E, //HANGUL SYLLABLE SSANGPIEUP AE PIEUPSIOS + 0x95DC: 0xBE92, //HANGUL SYLLABLE SSANGPIEUP AE CIEUC + 0x95DD: 0xBE93, //HANGUL SYLLABLE SSANGPIEUP AE CHIEUCH + 0x95DE: 0xBE94, //HANGUL SYLLABLE SSANGPIEUP AE KHIEUKH + 0x95DF: 0xBE95, //HANGUL SYLLABLE SSANGPIEUP AE THIEUTH + 0x95E0: 0xBE96, //HANGUL SYLLABLE SSANGPIEUP AE PHIEUPH + 0x95E1: 0xBE97, //HANGUL SYLLABLE SSANGPIEUP AE HIEUH + 0x95E2: 0xBE9A, //HANGUL SYLLABLE SSANGPIEUP YA SSANGKIYEOK + 0x95E3: 0xBE9B, //HANGUL SYLLABLE SSANGPIEUP YA KIYEOKSIOS + 0x95E4: 0xBE9C, //HANGUL SYLLABLE SSANGPIEUP YA NIEUN + 0x95E5: 0xBE9D, //HANGUL SYLLABLE SSANGPIEUP YA NIEUNCIEUC + 0x95E6: 0xBE9E, //HANGUL SYLLABLE SSANGPIEUP YA NIEUNHIEUH + 0x95E7: 0xBE9F, //HANGUL SYLLABLE SSANGPIEUP YA TIKEUT + 0x95E8: 0xBEA0, //HANGUL SYLLABLE SSANGPIEUP YA RIEUL + 0x95E9: 0xBEA1, //HANGUL SYLLABLE SSANGPIEUP YA RIEULKIYEOK + 0x95EA: 0xBEA2, //HANGUL SYLLABLE SSANGPIEUP YA RIEULMIEUM + 0x95EB: 0xBEA3, //HANGUL SYLLABLE SSANGPIEUP YA RIEULPIEUP + 0x95EC: 0xBEA4, //HANGUL SYLLABLE SSANGPIEUP YA RIEULSIOS + 0x95ED: 0xBEA5, //HANGUL SYLLABLE SSANGPIEUP YA RIEULTHIEUTH + 0x95EE: 0xBEA6, //HANGUL SYLLABLE SSANGPIEUP YA RIEULPHIEUPH + 0x95EF: 0xBEA7, //HANGUL SYLLABLE SSANGPIEUP YA RIEULHIEUH + 0x95F0: 0xBEA9, //HANGUL SYLLABLE SSANGPIEUP YA PIEUP + 0x95F1: 0xBEAA, //HANGUL SYLLABLE SSANGPIEUP YA PIEUPSIOS + 0x95F2: 0xBEAB, //HANGUL SYLLABLE SSANGPIEUP YA SIOS + 0x95F3: 0xBEAC, //HANGUL SYLLABLE SSANGPIEUP YA SSANGSIOS + 0x95F4: 0xBEAD, //HANGUL SYLLABLE SSANGPIEUP YA IEUNG + 0x95F5: 0xBEAE, //HANGUL SYLLABLE SSANGPIEUP YA CIEUC + 0x95F6: 0xBEAF, //HANGUL SYLLABLE SSANGPIEUP YA CHIEUCH + 0x95F7: 0xBEB0, //HANGUL SYLLABLE SSANGPIEUP YA KHIEUKH + 0x95F8: 0xBEB1, //HANGUL SYLLABLE SSANGPIEUP YA THIEUTH + 0x95F9: 0xBEB2, //HANGUL SYLLABLE SSANGPIEUP YA PHIEUPH + 0x95FA: 0xBEB3, //HANGUL SYLLABLE SSANGPIEUP YA HIEUH + 0x95FB: 0xBEB4, //HANGUL SYLLABLE SSANGPIEUP YAE + 0x95FC: 0xBEB5, //HANGUL SYLLABLE SSANGPIEUP YAE KIYEOK + 0x95FD: 0xBEB6, //HANGUL SYLLABLE SSANGPIEUP YAE SSANGKIYEOK + 0x95FE: 0xBEB7, //HANGUL SYLLABLE SSANGPIEUP YAE KIYEOKSIOS + 0x9641: 0xBEB8, //HANGUL SYLLABLE SSANGPIEUP YAE NIEUN + 0x9642: 0xBEB9, //HANGUL SYLLABLE SSANGPIEUP YAE NIEUNCIEUC + 0x9643: 0xBEBA, //HANGUL SYLLABLE SSANGPIEUP YAE NIEUNHIEUH + 0x9644: 0xBEBB, //HANGUL SYLLABLE SSANGPIEUP YAE TIKEUT + 0x9645: 0xBEBC, //HANGUL SYLLABLE SSANGPIEUP YAE RIEUL + 0x9646: 0xBEBD, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULKIYEOK + 0x9647: 0xBEBE, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULMIEUM + 0x9648: 0xBEBF, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULPIEUP + 0x9649: 0xBEC0, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULSIOS + 0x964A: 0xBEC1, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULTHIEUTH + 0x964B: 0xBEC2, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULPHIEUPH + 0x964C: 0xBEC3, //HANGUL SYLLABLE SSANGPIEUP YAE RIEULHIEUH + 0x964D: 0xBEC4, //HANGUL SYLLABLE SSANGPIEUP YAE MIEUM + 0x964E: 0xBEC5, //HANGUL SYLLABLE SSANGPIEUP YAE PIEUP + 0x964F: 0xBEC6, //HANGUL SYLLABLE SSANGPIEUP YAE PIEUPSIOS + 0x9650: 0xBEC7, //HANGUL SYLLABLE SSANGPIEUP YAE SIOS + 0x9651: 0xBEC8, //HANGUL SYLLABLE SSANGPIEUP YAE SSANGSIOS + 0x9652: 0xBEC9, //HANGUL SYLLABLE SSANGPIEUP YAE IEUNG + 0x9653: 0xBECA, //HANGUL SYLLABLE SSANGPIEUP YAE CIEUC + 0x9654: 0xBECB, //HANGUL SYLLABLE SSANGPIEUP YAE CHIEUCH + 0x9655: 0xBECC, //HANGUL SYLLABLE SSANGPIEUP YAE KHIEUKH + 0x9656: 0xBECD, //HANGUL SYLLABLE SSANGPIEUP YAE THIEUTH + 0x9657: 0xBECE, //HANGUL SYLLABLE SSANGPIEUP YAE PHIEUPH + 0x9658: 0xBECF, //HANGUL SYLLABLE SSANGPIEUP YAE HIEUH + 0x9659: 0xBED2, //HANGUL SYLLABLE SSANGPIEUP EO SSANGKIYEOK + 0x965A: 0xBED3, //HANGUL SYLLABLE SSANGPIEUP EO KIYEOKSIOS + 0x9661: 0xBED5, //HANGUL SYLLABLE SSANGPIEUP EO NIEUNCIEUC + 0x9662: 0xBED6, //HANGUL SYLLABLE SSANGPIEUP EO NIEUNHIEUH + 0x9663: 0xBED9, //HANGUL SYLLABLE SSANGPIEUP EO RIEULKIYEOK + 0x9664: 0xBEDA, //HANGUL SYLLABLE SSANGPIEUP EO RIEULMIEUM + 0x9665: 0xBEDB, //HANGUL SYLLABLE SSANGPIEUP EO RIEULPIEUP + 0x9666: 0xBEDC, //HANGUL SYLLABLE SSANGPIEUP EO RIEULSIOS + 0x9667: 0xBEDD, //HANGUL SYLLABLE SSANGPIEUP EO RIEULTHIEUTH + 0x9668: 0xBEDE, //HANGUL SYLLABLE SSANGPIEUP EO RIEULPHIEUPH + 0x9669: 0xBEDF, //HANGUL SYLLABLE SSANGPIEUP EO RIEULHIEUH + 0x966A: 0xBEE1, //HANGUL SYLLABLE SSANGPIEUP EO PIEUP + 0x966B: 0xBEE2, //HANGUL SYLLABLE SSANGPIEUP EO PIEUPSIOS + 0x966C: 0xBEE6, //HANGUL SYLLABLE SSANGPIEUP EO CIEUC + 0x966D: 0xBEE7, //HANGUL SYLLABLE SSANGPIEUP EO CHIEUCH + 0x966E: 0xBEE8, //HANGUL SYLLABLE SSANGPIEUP EO KHIEUKH + 0x966F: 0xBEE9, //HANGUL SYLLABLE SSANGPIEUP EO THIEUTH + 0x9670: 0xBEEA, //HANGUL SYLLABLE SSANGPIEUP EO PHIEUPH + 0x9671: 0xBEEB, //HANGUL SYLLABLE SSANGPIEUP EO HIEUH + 0x9672: 0xBEED, //HANGUL SYLLABLE SSANGPIEUP E KIYEOK + 0x9673: 0xBEEE, //HANGUL SYLLABLE SSANGPIEUP E SSANGKIYEOK + 0x9674: 0xBEEF, //HANGUL SYLLABLE SSANGPIEUP E KIYEOKSIOS + 0x9675: 0xBEF0, //HANGUL SYLLABLE SSANGPIEUP E NIEUN + 0x9676: 0xBEF1, //HANGUL SYLLABLE SSANGPIEUP E NIEUNCIEUC + 0x9677: 0xBEF2, //HANGUL SYLLABLE SSANGPIEUP E NIEUNHIEUH + 0x9678: 0xBEF3, //HANGUL SYLLABLE SSANGPIEUP E TIKEUT + 0x9679: 0xBEF4, //HANGUL SYLLABLE SSANGPIEUP E RIEUL + 0x967A: 0xBEF5, //HANGUL SYLLABLE SSANGPIEUP E RIEULKIYEOK + 0x9681: 0xBEF6, //HANGUL SYLLABLE SSANGPIEUP E RIEULMIEUM + 0x9682: 0xBEF7, //HANGUL SYLLABLE SSANGPIEUP E RIEULPIEUP + 0x9683: 0xBEF8, //HANGUL SYLLABLE SSANGPIEUP E RIEULSIOS + 0x9684: 0xBEF9, //HANGUL SYLLABLE SSANGPIEUP E RIEULTHIEUTH + 0x9685: 0xBEFA, //HANGUL SYLLABLE SSANGPIEUP E RIEULPHIEUPH + 0x9686: 0xBEFB, //HANGUL SYLLABLE SSANGPIEUP E RIEULHIEUH + 0x9687: 0xBEFC, //HANGUL SYLLABLE SSANGPIEUP E MIEUM + 0x9688: 0xBEFD, //HANGUL SYLLABLE SSANGPIEUP E PIEUP + 0x9689: 0xBEFE, //HANGUL SYLLABLE SSANGPIEUP E PIEUPSIOS + 0x968A: 0xBEFF, //HANGUL SYLLABLE SSANGPIEUP E SIOS + 0x968B: 0xBF00, //HANGUL SYLLABLE SSANGPIEUP E SSANGSIOS + 0x968C: 0xBF02, //HANGUL SYLLABLE SSANGPIEUP E CIEUC + 0x968D: 0xBF03, //HANGUL SYLLABLE SSANGPIEUP E CHIEUCH + 0x968E: 0xBF04, //HANGUL SYLLABLE SSANGPIEUP E KHIEUKH + 0x968F: 0xBF05, //HANGUL SYLLABLE SSANGPIEUP E THIEUTH + 0x9690: 0xBF06, //HANGUL SYLLABLE SSANGPIEUP E PHIEUPH + 0x9691: 0xBF07, //HANGUL SYLLABLE SSANGPIEUP E HIEUH + 0x9692: 0xBF0A, //HANGUL SYLLABLE SSANGPIEUP YEO SSANGKIYEOK + 0x9693: 0xBF0B, //HANGUL SYLLABLE SSANGPIEUP YEO KIYEOKSIOS + 0x9694: 0xBF0C, //HANGUL SYLLABLE SSANGPIEUP YEO NIEUN + 0x9695: 0xBF0D, //HANGUL SYLLABLE SSANGPIEUP YEO NIEUNCIEUC + 0x9696: 0xBF0E, //HANGUL SYLLABLE SSANGPIEUP YEO NIEUNHIEUH + 0x9697: 0xBF0F, //HANGUL SYLLABLE SSANGPIEUP YEO TIKEUT + 0x9698: 0xBF10, //HANGUL SYLLABLE SSANGPIEUP YEO RIEUL + 0x9699: 0xBF11, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULKIYEOK + 0x969A: 0xBF12, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULMIEUM + 0x969B: 0xBF13, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULPIEUP + 0x969C: 0xBF14, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULSIOS + 0x969D: 0xBF15, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULTHIEUTH + 0x969E: 0xBF16, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULPHIEUPH + 0x969F: 0xBF17, //HANGUL SYLLABLE SSANGPIEUP YEO RIEULHIEUH + 0x96A0: 0xBF1A, //HANGUL SYLLABLE SSANGPIEUP YEO PIEUPSIOS + 0x96A1: 0xBF1E, //HANGUL SYLLABLE SSANGPIEUP YEO CIEUC + 0x96A2: 0xBF1F, //HANGUL SYLLABLE SSANGPIEUP YEO CHIEUCH + 0x96A3: 0xBF20, //HANGUL SYLLABLE SSANGPIEUP YEO KHIEUKH + 0x96A4: 0xBF21, //HANGUL SYLLABLE SSANGPIEUP YEO THIEUTH + 0x96A5: 0xBF22, //HANGUL SYLLABLE SSANGPIEUP YEO PHIEUPH + 0x96A6: 0xBF23, //HANGUL SYLLABLE SSANGPIEUP YEO HIEUH + 0x96A7: 0xBF24, //HANGUL SYLLABLE SSANGPIEUP YE + 0x96A8: 0xBF25, //HANGUL SYLLABLE SSANGPIEUP YE KIYEOK + 0x96A9: 0xBF26, //HANGUL SYLLABLE SSANGPIEUP YE SSANGKIYEOK + 0x96AA: 0xBF27, //HANGUL SYLLABLE SSANGPIEUP YE KIYEOKSIOS + 0x96AB: 0xBF28, //HANGUL SYLLABLE SSANGPIEUP YE NIEUN + 0x96AC: 0xBF29, //HANGUL SYLLABLE SSANGPIEUP YE NIEUNCIEUC + 0x96AD: 0xBF2A, //HANGUL SYLLABLE SSANGPIEUP YE NIEUNHIEUH + 0x96AE: 0xBF2B, //HANGUL SYLLABLE SSANGPIEUP YE TIKEUT + 0x96AF: 0xBF2C, //HANGUL SYLLABLE SSANGPIEUP YE RIEUL + 0x96B0: 0xBF2D, //HANGUL SYLLABLE SSANGPIEUP YE RIEULKIYEOK + 0x96B1: 0xBF2E, //HANGUL SYLLABLE SSANGPIEUP YE RIEULMIEUM + 0x96B2: 0xBF2F, //HANGUL SYLLABLE SSANGPIEUP YE RIEULPIEUP + 0x96B3: 0xBF30, //HANGUL SYLLABLE SSANGPIEUP YE RIEULSIOS + 0x96B4: 0xBF31, //HANGUL SYLLABLE SSANGPIEUP YE RIEULTHIEUTH + 0x96B5: 0xBF32, //HANGUL SYLLABLE SSANGPIEUP YE RIEULPHIEUPH + 0x96B6: 0xBF33, //HANGUL SYLLABLE SSANGPIEUP YE RIEULHIEUH + 0x96B7: 0xBF34, //HANGUL SYLLABLE SSANGPIEUP YE MIEUM + 0x96B8: 0xBF35, //HANGUL SYLLABLE SSANGPIEUP YE PIEUP + 0x96B9: 0xBF36, //HANGUL SYLLABLE SSANGPIEUP YE PIEUPSIOS + 0x96BA: 0xBF37, //HANGUL SYLLABLE SSANGPIEUP YE SIOS + 0x96BB: 0xBF38, //HANGUL SYLLABLE SSANGPIEUP YE SSANGSIOS + 0x96BC: 0xBF39, //HANGUL SYLLABLE SSANGPIEUP YE IEUNG + 0x96BD: 0xBF3A, //HANGUL SYLLABLE SSANGPIEUP YE CIEUC + 0x96BE: 0xBF3B, //HANGUL SYLLABLE SSANGPIEUP YE CHIEUCH + 0x96BF: 0xBF3C, //HANGUL SYLLABLE SSANGPIEUP YE KHIEUKH + 0x96C0: 0xBF3D, //HANGUL SYLLABLE SSANGPIEUP YE THIEUTH + 0x96C1: 0xBF3E, //HANGUL SYLLABLE SSANGPIEUP YE PHIEUPH + 0x96C2: 0xBF3F, //HANGUL SYLLABLE SSANGPIEUP YE HIEUH + 0x96C3: 0xBF42, //HANGUL SYLLABLE SSANGPIEUP O SSANGKIYEOK + 0x96C4: 0xBF43, //HANGUL SYLLABLE SSANGPIEUP O KIYEOKSIOS + 0x96C5: 0xBF45, //HANGUL SYLLABLE SSANGPIEUP O NIEUNCIEUC + 0x96C6: 0xBF46, //HANGUL SYLLABLE SSANGPIEUP O NIEUNHIEUH + 0x96C7: 0xBF47, //HANGUL SYLLABLE SSANGPIEUP O TIKEUT + 0x96C8: 0xBF49, //HANGUL SYLLABLE SSANGPIEUP O RIEULKIYEOK + 0x96C9: 0xBF4A, //HANGUL SYLLABLE SSANGPIEUP O RIEULMIEUM + 0x96CA: 0xBF4B, //HANGUL SYLLABLE SSANGPIEUP O RIEULPIEUP + 0x96CB: 0xBF4C, //HANGUL SYLLABLE SSANGPIEUP O RIEULSIOS + 0x96CC: 0xBF4D, //HANGUL SYLLABLE SSANGPIEUP O RIEULTHIEUTH + 0x96CD: 0xBF4E, //HANGUL SYLLABLE SSANGPIEUP O RIEULPHIEUPH + 0x96CE: 0xBF4F, //HANGUL SYLLABLE SSANGPIEUP O RIEULHIEUH + 0x96CF: 0xBF52, //HANGUL SYLLABLE SSANGPIEUP O PIEUPSIOS + 0x96D0: 0xBF53, //HANGUL SYLLABLE SSANGPIEUP O SIOS + 0x96D1: 0xBF54, //HANGUL SYLLABLE SSANGPIEUP O SSANGSIOS + 0x96D2: 0xBF56, //HANGUL SYLLABLE SSANGPIEUP O CIEUC + 0x96D3: 0xBF57, //HANGUL SYLLABLE SSANGPIEUP O CHIEUCH + 0x96D4: 0xBF58, //HANGUL SYLLABLE SSANGPIEUP O KHIEUKH + 0x96D5: 0xBF59, //HANGUL SYLLABLE SSANGPIEUP O THIEUTH + 0x96D6: 0xBF5A, //HANGUL SYLLABLE SSANGPIEUP O PHIEUPH + 0x96D7: 0xBF5B, //HANGUL SYLLABLE SSANGPIEUP O HIEUH + 0x96D8: 0xBF5C, //HANGUL SYLLABLE SSANGPIEUP WA + 0x96D9: 0xBF5D, //HANGUL SYLLABLE SSANGPIEUP WA KIYEOK + 0x96DA: 0xBF5E, //HANGUL SYLLABLE SSANGPIEUP WA SSANGKIYEOK + 0x96DB: 0xBF5F, //HANGUL SYLLABLE SSANGPIEUP WA KIYEOKSIOS + 0x96DC: 0xBF60, //HANGUL SYLLABLE SSANGPIEUP WA NIEUN + 0x96DD: 0xBF61, //HANGUL SYLLABLE SSANGPIEUP WA NIEUNCIEUC + 0x96DE: 0xBF62, //HANGUL SYLLABLE SSANGPIEUP WA NIEUNHIEUH + 0x96DF: 0xBF63, //HANGUL SYLLABLE SSANGPIEUP WA TIKEUT + 0x96E0: 0xBF64, //HANGUL SYLLABLE SSANGPIEUP WA RIEUL + 0x96E1: 0xBF65, //HANGUL SYLLABLE SSANGPIEUP WA RIEULKIYEOK + 0x96E2: 0xBF66, //HANGUL SYLLABLE SSANGPIEUP WA RIEULMIEUM + 0x96E3: 0xBF67, //HANGUL SYLLABLE SSANGPIEUP WA RIEULPIEUP + 0x96E4: 0xBF68, //HANGUL SYLLABLE SSANGPIEUP WA RIEULSIOS + 0x96E5: 0xBF69, //HANGUL SYLLABLE SSANGPIEUP WA RIEULTHIEUTH + 0x96E6: 0xBF6A, //HANGUL SYLLABLE SSANGPIEUP WA RIEULPHIEUPH + 0x96E7: 0xBF6B, //HANGUL SYLLABLE SSANGPIEUP WA RIEULHIEUH + 0x96E8: 0xBF6C, //HANGUL SYLLABLE SSANGPIEUP WA MIEUM + 0x96E9: 0xBF6D, //HANGUL SYLLABLE SSANGPIEUP WA PIEUP + 0x96EA: 0xBF6E, //HANGUL SYLLABLE SSANGPIEUP WA PIEUPSIOS + 0x96EB: 0xBF6F, //HANGUL SYLLABLE SSANGPIEUP WA SIOS + 0x96EC: 0xBF70, //HANGUL SYLLABLE SSANGPIEUP WA SSANGSIOS + 0x96ED: 0xBF71, //HANGUL SYLLABLE SSANGPIEUP WA IEUNG + 0x96EE: 0xBF72, //HANGUL SYLLABLE SSANGPIEUP WA CIEUC + 0x96EF: 0xBF73, //HANGUL SYLLABLE SSANGPIEUP WA CHIEUCH + 0x96F0: 0xBF74, //HANGUL SYLLABLE SSANGPIEUP WA KHIEUKH + 0x96F1: 0xBF75, //HANGUL SYLLABLE SSANGPIEUP WA THIEUTH + 0x96F2: 0xBF76, //HANGUL SYLLABLE SSANGPIEUP WA PHIEUPH + 0x96F3: 0xBF77, //HANGUL SYLLABLE SSANGPIEUP WA HIEUH + 0x96F4: 0xBF78, //HANGUL SYLLABLE SSANGPIEUP WAE + 0x96F5: 0xBF79, //HANGUL SYLLABLE SSANGPIEUP WAE KIYEOK + 0x96F6: 0xBF7A, //HANGUL SYLLABLE SSANGPIEUP WAE SSANGKIYEOK + 0x96F7: 0xBF7B, //HANGUL SYLLABLE SSANGPIEUP WAE KIYEOKSIOS + 0x96F8: 0xBF7C, //HANGUL SYLLABLE SSANGPIEUP WAE NIEUN + 0x96F9: 0xBF7D, //HANGUL SYLLABLE SSANGPIEUP WAE NIEUNCIEUC + 0x96FA: 0xBF7E, //HANGUL SYLLABLE SSANGPIEUP WAE NIEUNHIEUH + 0x96FB: 0xBF7F, //HANGUL SYLLABLE SSANGPIEUP WAE TIKEUT + 0x96FC: 0xBF80, //HANGUL SYLLABLE SSANGPIEUP WAE RIEUL + 0x96FD: 0xBF81, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULKIYEOK + 0x96FE: 0xBF82, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULMIEUM + 0x9741: 0xBF83, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULPIEUP + 0x9742: 0xBF84, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULSIOS + 0x9743: 0xBF85, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULTHIEUTH + 0x9744: 0xBF86, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULPHIEUPH + 0x9745: 0xBF87, //HANGUL SYLLABLE SSANGPIEUP WAE RIEULHIEUH + 0x9746: 0xBF88, //HANGUL SYLLABLE SSANGPIEUP WAE MIEUM + 0x9747: 0xBF89, //HANGUL SYLLABLE SSANGPIEUP WAE PIEUP + 0x9748: 0xBF8A, //HANGUL SYLLABLE SSANGPIEUP WAE PIEUPSIOS + 0x9749: 0xBF8B, //HANGUL SYLLABLE SSANGPIEUP WAE SIOS + 0x974A: 0xBF8C, //HANGUL SYLLABLE SSANGPIEUP WAE SSANGSIOS + 0x974B: 0xBF8D, //HANGUL SYLLABLE SSANGPIEUP WAE IEUNG + 0x974C: 0xBF8E, //HANGUL SYLLABLE SSANGPIEUP WAE CIEUC + 0x974D: 0xBF8F, //HANGUL SYLLABLE SSANGPIEUP WAE CHIEUCH + 0x974E: 0xBF90, //HANGUL SYLLABLE SSANGPIEUP WAE KHIEUKH + 0x974F: 0xBF91, //HANGUL SYLLABLE SSANGPIEUP WAE THIEUTH + 0x9750: 0xBF92, //HANGUL SYLLABLE SSANGPIEUP WAE PHIEUPH + 0x9751: 0xBF93, //HANGUL SYLLABLE SSANGPIEUP WAE HIEUH + 0x9752: 0xBF95, //HANGUL SYLLABLE SSANGPIEUP OE KIYEOK + 0x9753: 0xBF96, //HANGUL SYLLABLE SSANGPIEUP OE SSANGKIYEOK + 0x9754: 0xBF97, //HANGUL SYLLABLE SSANGPIEUP OE KIYEOKSIOS + 0x9755: 0xBF98, //HANGUL SYLLABLE SSANGPIEUP OE NIEUN + 0x9756: 0xBF99, //HANGUL SYLLABLE SSANGPIEUP OE NIEUNCIEUC + 0x9757: 0xBF9A, //HANGUL SYLLABLE SSANGPIEUP OE NIEUNHIEUH + 0x9758: 0xBF9B, //HANGUL SYLLABLE SSANGPIEUP OE TIKEUT + 0x9759: 0xBF9C, //HANGUL SYLLABLE SSANGPIEUP OE RIEUL + 0x975A: 0xBF9D, //HANGUL SYLLABLE SSANGPIEUP OE RIEULKIYEOK + 0x9761: 0xBF9E, //HANGUL SYLLABLE SSANGPIEUP OE RIEULMIEUM + 0x9762: 0xBF9F, //HANGUL SYLLABLE SSANGPIEUP OE RIEULPIEUP + 0x9763: 0xBFA0, //HANGUL SYLLABLE SSANGPIEUP OE RIEULSIOS + 0x9764: 0xBFA1, //HANGUL SYLLABLE SSANGPIEUP OE RIEULTHIEUTH + 0x9765: 0xBFA2, //HANGUL SYLLABLE SSANGPIEUP OE RIEULPHIEUPH + 0x9766: 0xBFA3, //HANGUL SYLLABLE SSANGPIEUP OE RIEULHIEUH + 0x9767: 0xBFA4, //HANGUL SYLLABLE SSANGPIEUP OE MIEUM + 0x9768: 0xBFA5, //HANGUL SYLLABLE SSANGPIEUP OE PIEUP + 0x9769: 0xBFA6, //HANGUL SYLLABLE SSANGPIEUP OE PIEUPSIOS + 0x976A: 0xBFA7, //HANGUL SYLLABLE SSANGPIEUP OE SIOS + 0x976B: 0xBFA8, //HANGUL SYLLABLE SSANGPIEUP OE SSANGSIOS + 0x976C: 0xBFA9, //HANGUL SYLLABLE SSANGPIEUP OE IEUNG + 0x976D: 0xBFAA, //HANGUL SYLLABLE SSANGPIEUP OE CIEUC + 0x976E: 0xBFAB, //HANGUL SYLLABLE SSANGPIEUP OE CHIEUCH + 0x976F: 0xBFAC, //HANGUL SYLLABLE SSANGPIEUP OE KHIEUKH + 0x9770: 0xBFAD, //HANGUL SYLLABLE SSANGPIEUP OE THIEUTH + 0x9771: 0xBFAE, //HANGUL SYLLABLE SSANGPIEUP OE PHIEUPH + 0x9772: 0xBFAF, //HANGUL SYLLABLE SSANGPIEUP OE HIEUH + 0x9773: 0xBFB1, //HANGUL SYLLABLE SSANGPIEUP YO KIYEOK + 0x9774: 0xBFB2, //HANGUL SYLLABLE SSANGPIEUP YO SSANGKIYEOK + 0x9775: 0xBFB3, //HANGUL SYLLABLE SSANGPIEUP YO KIYEOKSIOS + 0x9776: 0xBFB4, //HANGUL SYLLABLE SSANGPIEUP YO NIEUN + 0x9777: 0xBFB5, //HANGUL SYLLABLE SSANGPIEUP YO NIEUNCIEUC + 0x9778: 0xBFB6, //HANGUL SYLLABLE SSANGPIEUP YO NIEUNHIEUH + 0x9779: 0xBFB7, //HANGUL SYLLABLE SSANGPIEUP YO TIKEUT + 0x977A: 0xBFB8, //HANGUL SYLLABLE SSANGPIEUP YO RIEUL + 0x9781: 0xBFB9, //HANGUL SYLLABLE SSANGPIEUP YO RIEULKIYEOK + 0x9782: 0xBFBA, //HANGUL SYLLABLE SSANGPIEUP YO RIEULMIEUM + 0x9783: 0xBFBB, //HANGUL SYLLABLE SSANGPIEUP YO RIEULPIEUP + 0x9784: 0xBFBC, //HANGUL SYLLABLE SSANGPIEUP YO RIEULSIOS + 0x9785: 0xBFBD, //HANGUL SYLLABLE SSANGPIEUP YO RIEULTHIEUTH + 0x9786: 0xBFBE, //HANGUL SYLLABLE SSANGPIEUP YO RIEULPHIEUPH + 0x9787: 0xBFBF, //HANGUL SYLLABLE SSANGPIEUP YO RIEULHIEUH + 0x9788: 0xBFC0, //HANGUL SYLLABLE SSANGPIEUP YO MIEUM + 0x9789: 0xBFC1, //HANGUL SYLLABLE SSANGPIEUP YO PIEUP + 0x978A: 0xBFC2, //HANGUL SYLLABLE SSANGPIEUP YO PIEUPSIOS + 0x978B: 0xBFC3, //HANGUL SYLLABLE SSANGPIEUP YO SIOS + 0x978C: 0xBFC4, //HANGUL SYLLABLE SSANGPIEUP YO SSANGSIOS + 0x978D: 0xBFC6, //HANGUL SYLLABLE SSANGPIEUP YO CIEUC + 0x978E: 0xBFC7, //HANGUL SYLLABLE SSANGPIEUP YO CHIEUCH + 0x978F: 0xBFC8, //HANGUL SYLLABLE SSANGPIEUP YO KHIEUKH + 0x9790: 0xBFC9, //HANGUL SYLLABLE SSANGPIEUP YO THIEUTH + 0x9791: 0xBFCA, //HANGUL SYLLABLE SSANGPIEUP YO PHIEUPH + 0x9792: 0xBFCB, //HANGUL SYLLABLE SSANGPIEUP YO HIEUH + 0x9793: 0xBFCE, //HANGUL SYLLABLE SSANGPIEUP U SSANGKIYEOK + 0x9794: 0xBFCF, //HANGUL SYLLABLE SSANGPIEUP U KIYEOKSIOS + 0x9795: 0xBFD1, //HANGUL SYLLABLE SSANGPIEUP U NIEUNCIEUC + 0x9796: 0xBFD2, //HANGUL SYLLABLE SSANGPIEUP U NIEUNHIEUH + 0x9797: 0xBFD3, //HANGUL SYLLABLE SSANGPIEUP U TIKEUT + 0x9798: 0xBFD5, //HANGUL SYLLABLE SSANGPIEUP U RIEULKIYEOK + 0x9799: 0xBFD6, //HANGUL SYLLABLE SSANGPIEUP U RIEULMIEUM + 0x979A: 0xBFD7, //HANGUL SYLLABLE SSANGPIEUP U RIEULPIEUP + 0x979B: 0xBFD8, //HANGUL SYLLABLE SSANGPIEUP U RIEULSIOS + 0x979C: 0xBFD9, //HANGUL SYLLABLE SSANGPIEUP U RIEULTHIEUTH + 0x979D: 0xBFDA, //HANGUL SYLLABLE SSANGPIEUP U RIEULPHIEUPH + 0x979E: 0xBFDB, //HANGUL SYLLABLE SSANGPIEUP U RIEULHIEUH + 0x979F: 0xBFDD, //HANGUL SYLLABLE SSANGPIEUP U PIEUP + 0x97A0: 0xBFDE, //HANGUL SYLLABLE SSANGPIEUP U PIEUPSIOS + 0x97A1: 0xBFE0, //HANGUL SYLLABLE SSANGPIEUP U SSANGSIOS + 0x97A2: 0xBFE2, //HANGUL SYLLABLE SSANGPIEUP U CIEUC + 0x97A3: 0xBFE3, //HANGUL SYLLABLE SSANGPIEUP U CHIEUCH + 0x97A4: 0xBFE4, //HANGUL SYLLABLE SSANGPIEUP U KHIEUKH + 0x97A5: 0xBFE5, //HANGUL SYLLABLE SSANGPIEUP U THIEUTH + 0x97A6: 0xBFE6, //HANGUL SYLLABLE SSANGPIEUP U PHIEUPH + 0x97A7: 0xBFE7, //HANGUL SYLLABLE SSANGPIEUP U HIEUH + 0x97A8: 0xBFE8, //HANGUL SYLLABLE SSANGPIEUP WEO + 0x97A9: 0xBFE9, //HANGUL SYLLABLE SSANGPIEUP WEO KIYEOK + 0x97AA: 0xBFEA, //HANGUL SYLLABLE SSANGPIEUP WEO SSANGKIYEOK + 0x97AB: 0xBFEB, //HANGUL SYLLABLE SSANGPIEUP WEO KIYEOKSIOS + 0x97AC: 0xBFEC, //HANGUL SYLLABLE SSANGPIEUP WEO NIEUN + 0x97AD: 0xBFED, //HANGUL SYLLABLE SSANGPIEUP WEO NIEUNCIEUC + 0x97AE: 0xBFEE, //HANGUL SYLLABLE SSANGPIEUP WEO NIEUNHIEUH + 0x97AF: 0xBFEF, //HANGUL SYLLABLE SSANGPIEUP WEO TIKEUT + 0x97B0: 0xBFF0, //HANGUL SYLLABLE SSANGPIEUP WEO RIEUL + 0x97B1: 0xBFF1, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULKIYEOK + 0x97B2: 0xBFF2, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULMIEUM + 0x97B3: 0xBFF3, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULPIEUP + 0x97B4: 0xBFF4, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULSIOS + 0x97B5: 0xBFF5, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULTHIEUTH + 0x97B6: 0xBFF6, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULPHIEUPH + 0x97B7: 0xBFF7, //HANGUL SYLLABLE SSANGPIEUP WEO RIEULHIEUH + 0x97B8: 0xBFF8, //HANGUL SYLLABLE SSANGPIEUP WEO MIEUM + 0x97B9: 0xBFF9, //HANGUL SYLLABLE SSANGPIEUP WEO PIEUP + 0x97BA: 0xBFFA, //HANGUL SYLLABLE SSANGPIEUP WEO PIEUPSIOS + 0x97BB: 0xBFFB, //HANGUL SYLLABLE SSANGPIEUP WEO SIOS + 0x97BC: 0xBFFC, //HANGUL SYLLABLE SSANGPIEUP WEO SSANGSIOS + 0x97BD: 0xBFFD, //HANGUL SYLLABLE SSANGPIEUP WEO IEUNG + 0x97BE: 0xBFFE, //HANGUL SYLLABLE SSANGPIEUP WEO CIEUC + 0x97BF: 0xBFFF, //HANGUL SYLLABLE SSANGPIEUP WEO CHIEUCH + 0x97C0: 0xC000, //HANGUL SYLLABLE SSANGPIEUP WEO KHIEUKH + 0x97C1: 0xC001, //HANGUL SYLLABLE SSANGPIEUP WEO THIEUTH + 0x97C2: 0xC002, //HANGUL SYLLABLE SSANGPIEUP WEO PHIEUPH + 0x97C3: 0xC003, //HANGUL SYLLABLE SSANGPIEUP WEO HIEUH + 0x97C4: 0xC004, //HANGUL SYLLABLE SSANGPIEUP WE + 0x97C5: 0xC005, //HANGUL SYLLABLE SSANGPIEUP WE KIYEOK + 0x97C6: 0xC006, //HANGUL SYLLABLE SSANGPIEUP WE SSANGKIYEOK + 0x97C7: 0xC007, //HANGUL SYLLABLE SSANGPIEUP WE KIYEOKSIOS + 0x97C8: 0xC008, //HANGUL SYLLABLE SSANGPIEUP WE NIEUN + 0x97C9: 0xC009, //HANGUL SYLLABLE SSANGPIEUP WE NIEUNCIEUC + 0x97CA: 0xC00A, //HANGUL SYLLABLE SSANGPIEUP WE NIEUNHIEUH + 0x97CB: 0xC00B, //HANGUL SYLLABLE SSANGPIEUP WE TIKEUT + 0x97CC: 0xC00C, //HANGUL SYLLABLE SSANGPIEUP WE RIEUL + 0x97CD: 0xC00D, //HANGUL SYLLABLE SSANGPIEUP WE RIEULKIYEOK + 0x97CE: 0xC00E, //HANGUL SYLLABLE SSANGPIEUP WE RIEULMIEUM + 0x97CF: 0xC00F, //HANGUL SYLLABLE SSANGPIEUP WE RIEULPIEUP + 0x97D0: 0xC010, //HANGUL SYLLABLE SSANGPIEUP WE RIEULSIOS + 0x97D1: 0xC011, //HANGUL SYLLABLE SSANGPIEUP WE RIEULTHIEUTH + 0x97D2: 0xC012, //HANGUL SYLLABLE SSANGPIEUP WE RIEULPHIEUPH + 0x97D3: 0xC013, //HANGUL SYLLABLE SSANGPIEUP WE RIEULHIEUH + 0x97D4: 0xC014, //HANGUL SYLLABLE SSANGPIEUP WE MIEUM + 0x97D5: 0xC015, //HANGUL SYLLABLE SSANGPIEUP WE PIEUP + 0x97D6: 0xC016, //HANGUL SYLLABLE SSANGPIEUP WE PIEUPSIOS + 0x97D7: 0xC017, //HANGUL SYLLABLE SSANGPIEUP WE SIOS + 0x97D8: 0xC018, //HANGUL SYLLABLE SSANGPIEUP WE SSANGSIOS + 0x97D9: 0xC019, //HANGUL SYLLABLE SSANGPIEUP WE IEUNG + 0x97DA: 0xC01A, //HANGUL SYLLABLE SSANGPIEUP WE CIEUC + 0x97DB: 0xC01B, //HANGUL SYLLABLE SSANGPIEUP WE CHIEUCH + 0x97DC: 0xC01C, //HANGUL SYLLABLE SSANGPIEUP WE KHIEUKH + 0x97DD: 0xC01D, //HANGUL SYLLABLE SSANGPIEUP WE THIEUTH + 0x97DE: 0xC01E, //HANGUL SYLLABLE SSANGPIEUP WE PHIEUPH + 0x97DF: 0xC01F, //HANGUL SYLLABLE SSANGPIEUP WE HIEUH + 0x97E0: 0xC020, //HANGUL SYLLABLE SSANGPIEUP WI + 0x97E1: 0xC021, //HANGUL SYLLABLE SSANGPIEUP WI KIYEOK + 0x97E2: 0xC022, //HANGUL SYLLABLE SSANGPIEUP WI SSANGKIYEOK + 0x97E3: 0xC023, //HANGUL SYLLABLE SSANGPIEUP WI KIYEOKSIOS + 0x97E4: 0xC024, //HANGUL SYLLABLE SSANGPIEUP WI NIEUN + 0x97E5: 0xC025, //HANGUL SYLLABLE SSANGPIEUP WI NIEUNCIEUC + 0x97E6: 0xC026, //HANGUL SYLLABLE SSANGPIEUP WI NIEUNHIEUH + 0x97E7: 0xC027, //HANGUL SYLLABLE SSANGPIEUP WI TIKEUT + 0x97E8: 0xC028, //HANGUL SYLLABLE SSANGPIEUP WI RIEUL + 0x97E9: 0xC029, //HANGUL SYLLABLE SSANGPIEUP WI RIEULKIYEOK + 0x97EA: 0xC02A, //HANGUL SYLLABLE SSANGPIEUP WI RIEULMIEUM + 0x97EB: 0xC02B, //HANGUL SYLLABLE SSANGPIEUP WI RIEULPIEUP + 0x97EC: 0xC02C, //HANGUL SYLLABLE SSANGPIEUP WI RIEULSIOS + 0x97ED: 0xC02D, //HANGUL SYLLABLE SSANGPIEUP WI RIEULTHIEUTH + 0x97EE: 0xC02E, //HANGUL SYLLABLE SSANGPIEUP WI RIEULPHIEUPH + 0x97EF: 0xC02F, //HANGUL SYLLABLE SSANGPIEUP WI RIEULHIEUH + 0x97F0: 0xC030, //HANGUL SYLLABLE SSANGPIEUP WI MIEUM + 0x97F1: 0xC031, //HANGUL SYLLABLE SSANGPIEUP WI PIEUP + 0x97F2: 0xC032, //HANGUL SYLLABLE SSANGPIEUP WI PIEUPSIOS + 0x97F3: 0xC033, //HANGUL SYLLABLE SSANGPIEUP WI SIOS + 0x97F4: 0xC034, //HANGUL SYLLABLE SSANGPIEUP WI SSANGSIOS + 0x97F5: 0xC035, //HANGUL SYLLABLE SSANGPIEUP WI IEUNG + 0x97F6: 0xC036, //HANGUL SYLLABLE SSANGPIEUP WI CIEUC + 0x97F7: 0xC037, //HANGUL SYLLABLE SSANGPIEUP WI CHIEUCH + 0x97F8: 0xC038, //HANGUL SYLLABLE SSANGPIEUP WI KHIEUKH + 0x97F9: 0xC039, //HANGUL SYLLABLE SSANGPIEUP WI THIEUTH + 0x97FA: 0xC03A, //HANGUL SYLLABLE SSANGPIEUP WI PHIEUPH + 0x97FB: 0xC03B, //HANGUL SYLLABLE SSANGPIEUP WI HIEUH + 0x97FC: 0xC03D, //HANGUL SYLLABLE SSANGPIEUP YU KIYEOK + 0x97FD: 0xC03E, //HANGUL SYLLABLE SSANGPIEUP YU SSANGKIYEOK + 0x97FE: 0xC03F, //HANGUL SYLLABLE SSANGPIEUP YU KIYEOKSIOS + 0x9841: 0xC040, //HANGUL SYLLABLE SSANGPIEUP YU NIEUN + 0x9842: 0xC041, //HANGUL SYLLABLE SSANGPIEUP YU NIEUNCIEUC + 0x9843: 0xC042, //HANGUL SYLLABLE SSANGPIEUP YU NIEUNHIEUH + 0x9844: 0xC043, //HANGUL SYLLABLE SSANGPIEUP YU TIKEUT + 0x9845: 0xC044, //HANGUL SYLLABLE SSANGPIEUP YU RIEUL + 0x9846: 0xC045, //HANGUL SYLLABLE SSANGPIEUP YU RIEULKIYEOK + 0x9847: 0xC046, //HANGUL SYLLABLE SSANGPIEUP YU RIEULMIEUM + 0x9848: 0xC047, //HANGUL SYLLABLE SSANGPIEUP YU RIEULPIEUP + 0x9849: 0xC048, //HANGUL SYLLABLE SSANGPIEUP YU RIEULSIOS + 0x984A: 0xC049, //HANGUL SYLLABLE SSANGPIEUP YU RIEULTHIEUTH + 0x984B: 0xC04A, //HANGUL SYLLABLE SSANGPIEUP YU RIEULPHIEUPH + 0x984C: 0xC04B, //HANGUL SYLLABLE SSANGPIEUP YU RIEULHIEUH + 0x984D: 0xC04C, //HANGUL SYLLABLE SSANGPIEUP YU MIEUM + 0x984E: 0xC04D, //HANGUL SYLLABLE SSANGPIEUP YU PIEUP + 0x984F: 0xC04E, //HANGUL SYLLABLE SSANGPIEUP YU PIEUPSIOS + 0x9850: 0xC04F, //HANGUL SYLLABLE SSANGPIEUP YU SIOS + 0x9851: 0xC050, //HANGUL SYLLABLE SSANGPIEUP YU SSANGSIOS + 0x9852: 0xC052, //HANGUL SYLLABLE SSANGPIEUP YU CIEUC + 0x9853: 0xC053, //HANGUL SYLLABLE SSANGPIEUP YU CHIEUCH + 0x9854: 0xC054, //HANGUL SYLLABLE SSANGPIEUP YU KHIEUKH + 0x9855: 0xC055, //HANGUL SYLLABLE SSANGPIEUP YU THIEUTH + 0x9856: 0xC056, //HANGUL SYLLABLE SSANGPIEUP YU PHIEUPH + 0x9857: 0xC057, //HANGUL SYLLABLE SSANGPIEUP YU HIEUH + 0x9858: 0xC059, //HANGUL SYLLABLE SSANGPIEUP EU KIYEOK + 0x9859: 0xC05A, //HANGUL SYLLABLE SSANGPIEUP EU SSANGKIYEOK + 0x985A: 0xC05B, //HANGUL SYLLABLE SSANGPIEUP EU KIYEOKSIOS + 0x9861: 0xC05D, //HANGUL SYLLABLE SSANGPIEUP EU NIEUNCIEUC + 0x9862: 0xC05E, //HANGUL SYLLABLE SSANGPIEUP EU NIEUNHIEUH + 0x9863: 0xC05F, //HANGUL SYLLABLE SSANGPIEUP EU TIKEUT + 0x9864: 0xC061, //HANGUL SYLLABLE SSANGPIEUP EU RIEULKIYEOK + 0x9865: 0xC062, //HANGUL SYLLABLE SSANGPIEUP EU RIEULMIEUM + 0x9866: 0xC063, //HANGUL SYLLABLE SSANGPIEUP EU RIEULPIEUP + 0x9867: 0xC064, //HANGUL SYLLABLE SSANGPIEUP EU RIEULSIOS + 0x9868: 0xC065, //HANGUL SYLLABLE SSANGPIEUP EU RIEULTHIEUTH + 0x9869: 0xC066, //HANGUL SYLLABLE SSANGPIEUP EU RIEULPHIEUPH + 0x986A: 0xC067, //HANGUL SYLLABLE SSANGPIEUP EU RIEULHIEUH + 0x986B: 0xC06A, //HANGUL SYLLABLE SSANGPIEUP EU PIEUPSIOS + 0x986C: 0xC06B, //HANGUL SYLLABLE SSANGPIEUP EU SIOS + 0x986D: 0xC06C, //HANGUL SYLLABLE SSANGPIEUP EU SSANGSIOS + 0x986E: 0xC06D, //HANGUL SYLLABLE SSANGPIEUP EU IEUNG + 0x986F: 0xC06E, //HANGUL SYLLABLE SSANGPIEUP EU CIEUC + 0x9870: 0xC06F, //HANGUL SYLLABLE SSANGPIEUP EU CHIEUCH + 0x9871: 0xC070, //HANGUL SYLLABLE SSANGPIEUP EU KHIEUKH + 0x9872: 0xC071, //HANGUL SYLLABLE SSANGPIEUP EU THIEUTH + 0x9873: 0xC072, //HANGUL SYLLABLE SSANGPIEUP EU PHIEUPH + 0x9874: 0xC073, //HANGUL SYLLABLE SSANGPIEUP EU HIEUH + 0x9875: 0xC074, //HANGUL SYLLABLE SSANGPIEUP YI + 0x9876: 0xC075, //HANGUL SYLLABLE SSANGPIEUP YI KIYEOK + 0x9877: 0xC076, //HANGUL SYLLABLE SSANGPIEUP YI SSANGKIYEOK + 0x9878: 0xC077, //HANGUL SYLLABLE SSANGPIEUP YI KIYEOKSIOS + 0x9879: 0xC078, //HANGUL SYLLABLE SSANGPIEUP YI NIEUN + 0x987A: 0xC079, //HANGUL SYLLABLE SSANGPIEUP YI NIEUNCIEUC + 0x9881: 0xC07A, //HANGUL SYLLABLE SSANGPIEUP YI NIEUNHIEUH + 0x9882: 0xC07B, //HANGUL SYLLABLE SSANGPIEUP YI TIKEUT + 0x9883: 0xC07C, //HANGUL SYLLABLE SSANGPIEUP YI RIEUL + 0x9884: 0xC07D, //HANGUL SYLLABLE SSANGPIEUP YI RIEULKIYEOK + 0x9885: 0xC07E, //HANGUL SYLLABLE SSANGPIEUP YI RIEULMIEUM + 0x9886: 0xC07F, //HANGUL SYLLABLE SSANGPIEUP YI RIEULPIEUP + 0x9887: 0xC080, //HANGUL SYLLABLE SSANGPIEUP YI RIEULSIOS + 0x9888: 0xC081, //HANGUL SYLLABLE SSANGPIEUP YI RIEULTHIEUTH + 0x9889: 0xC082, //HANGUL SYLLABLE SSANGPIEUP YI RIEULPHIEUPH + 0x988A: 0xC083, //HANGUL SYLLABLE SSANGPIEUP YI RIEULHIEUH + 0x988B: 0xC084, //HANGUL SYLLABLE SSANGPIEUP YI MIEUM + 0x988C: 0xC085, //HANGUL SYLLABLE SSANGPIEUP YI PIEUP + 0x988D: 0xC086, //HANGUL SYLLABLE SSANGPIEUP YI PIEUPSIOS + 0x988E: 0xC087, //HANGUL SYLLABLE SSANGPIEUP YI SIOS + 0x988F: 0xC088, //HANGUL SYLLABLE SSANGPIEUP YI SSANGSIOS + 0x9890: 0xC089, //HANGUL SYLLABLE SSANGPIEUP YI IEUNG + 0x9891: 0xC08A, //HANGUL SYLLABLE SSANGPIEUP YI CIEUC + 0x9892: 0xC08B, //HANGUL SYLLABLE SSANGPIEUP YI CHIEUCH + 0x9893: 0xC08C, //HANGUL SYLLABLE SSANGPIEUP YI KHIEUKH + 0x9894: 0xC08D, //HANGUL SYLLABLE SSANGPIEUP YI THIEUTH + 0x9895: 0xC08E, //HANGUL SYLLABLE SSANGPIEUP YI PHIEUPH + 0x9896: 0xC08F, //HANGUL SYLLABLE SSANGPIEUP YI HIEUH + 0x9897: 0xC092, //HANGUL SYLLABLE SSANGPIEUP I SSANGKIYEOK + 0x9898: 0xC093, //HANGUL SYLLABLE SSANGPIEUP I KIYEOKSIOS + 0x9899: 0xC095, //HANGUL SYLLABLE SSANGPIEUP I NIEUNCIEUC + 0x989A: 0xC096, //HANGUL SYLLABLE SSANGPIEUP I NIEUNHIEUH + 0x989B: 0xC097, //HANGUL SYLLABLE SSANGPIEUP I TIKEUT + 0x989C: 0xC099, //HANGUL SYLLABLE SSANGPIEUP I RIEULKIYEOK + 0x989D: 0xC09A, //HANGUL SYLLABLE SSANGPIEUP I RIEULMIEUM + 0x989E: 0xC09B, //HANGUL SYLLABLE SSANGPIEUP I RIEULPIEUP + 0x989F: 0xC09C, //HANGUL SYLLABLE SSANGPIEUP I RIEULSIOS + 0x98A0: 0xC09D, //HANGUL SYLLABLE SSANGPIEUP I RIEULTHIEUTH + 0x98A1: 0xC09E, //HANGUL SYLLABLE SSANGPIEUP I RIEULPHIEUPH + 0x98A2: 0xC09F, //HANGUL SYLLABLE SSANGPIEUP I RIEULHIEUH + 0x98A3: 0xC0A2, //HANGUL SYLLABLE SSANGPIEUP I PIEUPSIOS + 0x98A4: 0xC0A4, //HANGUL SYLLABLE SSANGPIEUP I SSANGSIOS + 0x98A5: 0xC0A6, //HANGUL SYLLABLE SSANGPIEUP I CIEUC + 0x98A6: 0xC0A7, //HANGUL SYLLABLE SSANGPIEUP I CHIEUCH + 0x98A7: 0xC0A8, //HANGUL SYLLABLE SSANGPIEUP I KHIEUKH + 0x98A8: 0xC0A9, //HANGUL SYLLABLE SSANGPIEUP I THIEUTH + 0x98A9: 0xC0AA, //HANGUL SYLLABLE SSANGPIEUP I PHIEUPH + 0x98AA: 0xC0AB, //HANGUL SYLLABLE SSANGPIEUP I HIEUH + 0x98AB: 0xC0AE, //HANGUL SYLLABLE SIOS A SSANGKIYEOK + 0x98AC: 0xC0B1, //HANGUL SYLLABLE SIOS A NIEUNCIEUC + 0x98AD: 0xC0B2, //HANGUL SYLLABLE SIOS A NIEUNHIEUH + 0x98AE: 0xC0B7, //HANGUL SYLLABLE SIOS A RIEULPIEUP + 0x98AF: 0xC0B8, //HANGUL SYLLABLE SIOS A RIEULSIOS + 0x98B0: 0xC0B9, //HANGUL SYLLABLE SIOS A RIEULTHIEUTH + 0x98B1: 0xC0BA, //HANGUL SYLLABLE SIOS A RIEULPHIEUPH + 0x98B2: 0xC0BB, //HANGUL SYLLABLE SIOS A RIEULHIEUH + 0x98B3: 0xC0BE, //HANGUL SYLLABLE SIOS A PIEUPSIOS + 0x98B4: 0xC0C2, //HANGUL SYLLABLE SIOS A CIEUC + 0x98B5: 0xC0C3, //HANGUL SYLLABLE SIOS A CHIEUCH + 0x98B6: 0xC0C4, //HANGUL SYLLABLE SIOS A KHIEUKH + 0x98B7: 0xC0C6, //HANGUL SYLLABLE SIOS A PHIEUPH + 0x98B8: 0xC0C7, //HANGUL SYLLABLE SIOS A HIEUH + 0x98B9: 0xC0CA, //HANGUL SYLLABLE SIOS AE SSANGKIYEOK + 0x98BA: 0xC0CB, //HANGUL SYLLABLE SIOS AE KIYEOKSIOS + 0x98BB: 0xC0CD, //HANGUL SYLLABLE SIOS AE NIEUNCIEUC + 0x98BC: 0xC0CE, //HANGUL SYLLABLE SIOS AE NIEUNHIEUH + 0x98BD: 0xC0CF, //HANGUL SYLLABLE SIOS AE TIKEUT + 0x98BE: 0xC0D1, //HANGUL SYLLABLE SIOS AE RIEULKIYEOK + 0x98BF: 0xC0D2, //HANGUL SYLLABLE SIOS AE RIEULMIEUM + 0x98C0: 0xC0D3, //HANGUL SYLLABLE SIOS AE RIEULPIEUP + 0x98C1: 0xC0D4, //HANGUL SYLLABLE SIOS AE RIEULSIOS + 0x98C2: 0xC0D5, //HANGUL SYLLABLE SIOS AE RIEULTHIEUTH + 0x98C3: 0xC0D6, //HANGUL SYLLABLE SIOS AE RIEULPHIEUPH + 0x98C4: 0xC0D7, //HANGUL SYLLABLE SIOS AE RIEULHIEUH + 0x98C5: 0xC0DA, //HANGUL SYLLABLE SIOS AE PIEUPSIOS + 0x98C6: 0xC0DE, //HANGUL SYLLABLE SIOS AE CIEUC + 0x98C7: 0xC0DF, //HANGUL SYLLABLE SIOS AE CHIEUCH + 0x98C8: 0xC0E0, //HANGUL SYLLABLE SIOS AE KHIEUKH + 0x98C9: 0xC0E1, //HANGUL SYLLABLE SIOS AE THIEUTH + 0x98CA: 0xC0E2, //HANGUL SYLLABLE SIOS AE PHIEUPH + 0x98CB: 0xC0E3, //HANGUL SYLLABLE SIOS AE HIEUH + 0x98CC: 0xC0E6, //HANGUL SYLLABLE SIOS YA SSANGKIYEOK + 0x98CD: 0xC0E7, //HANGUL SYLLABLE SIOS YA KIYEOKSIOS + 0x98CE: 0xC0E9, //HANGUL SYLLABLE SIOS YA NIEUNCIEUC + 0x98CF: 0xC0EA, //HANGUL SYLLABLE SIOS YA NIEUNHIEUH + 0x98D0: 0xC0EB, //HANGUL SYLLABLE SIOS YA TIKEUT + 0x98D1: 0xC0ED, //HANGUL SYLLABLE SIOS YA RIEULKIYEOK + 0x98D2: 0xC0EE, //HANGUL SYLLABLE SIOS YA RIEULMIEUM + 0x98D3: 0xC0EF, //HANGUL SYLLABLE SIOS YA RIEULPIEUP + 0x98D4: 0xC0F0, //HANGUL SYLLABLE SIOS YA RIEULSIOS + 0x98D5: 0xC0F1, //HANGUL SYLLABLE SIOS YA RIEULTHIEUTH + 0x98D6: 0xC0F2, //HANGUL SYLLABLE SIOS YA RIEULPHIEUPH + 0x98D7: 0xC0F3, //HANGUL SYLLABLE SIOS YA RIEULHIEUH + 0x98D8: 0xC0F6, //HANGUL SYLLABLE SIOS YA PIEUPSIOS + 0x98D9: 0xC0F8, //HANGUL SYLLABLE SIOS YA SSANGSIOS + 0x98DA: 0xC0FA, //HANGUL SYLLABLE SIOS YA CIEUC + 0x98DB: 0xC0FB, //HANGUL SYLLABLE SIOS YA CHIEUCH + 0x98DC: 0xC0FC, //HANGUL SYLLABLE SIOS YA KHIEUKH + 0x98DD: 0xC0FD, //HANGUL SYLLABLE SIOS YA THIEUTH + 0x98DE: 0xC0FE, //HANGUL SYLLABLE SIOS YA PHIEUPH + 0x98DF: 0xC0FF, //HANGUL SYLLABLE SIOS YA HIEUH + 0x98E0: 0xC101, //HANGUL SYLLABLE SIOS YAE KIYEOK + 0x98E1: 0xC102, //HANGUL SYLLABLE SIOS YAE SSANGKIYEOK + 0x98E2: 0xC103, //HANGUL SYLLABLE SIOS YAE KIYEOKSIOS + 0x98E3: 0xC105, //HANGUL SYLLABLE SIOS YAE NIEUNCIEUC + 0x98E4: 0xC106, //HANGUL SYLLABLE SIOS YAE NIEUNHIEUH + 0x98E5: 0xC107, //HANGUL SYLLABLE SIOS YAE TIKEUT + 0x98E6: 0xC109, //HANGUL SYLLABLE SIOS YAE RIEULKIYEOK + 0x98E7: 0xC10A, //HANGUL SYLLABLE SIOS YAE RIEULMIEUM + 0x98E8: 0xC10B, //HANGUL SYLLABLE SIOS YAE RIEULPIEUP + 0x98E9: 0xC10C, //HANGUL SYLLABLE SIOS YAE RIEULSIOS + 0x98EA: 0xC10D, //HANGUL SYLLABLE SIOS YAE RIEULTHIEUTH + 0x98EB: 0xC10E, //HANGUL SYLLABLE SIOS YAE RIEULPHIEUPH + 0x98EC: 0xC10F, //HANGUL SYLLABLE SIOS YAE RIEULHIEUH + 0x98ED: 0xC111, //HANGUL SYLLABLE SIOS YAE PIEUP + 0x98EE: 0xC112, //HANGUL SYLLABLE SIOS YAE PIEUPSIOS + 0x98EF: 0xC113, //HANGUL SYLLABLE SIOS YAE SIOS + 0x98F0: 0xC114, //HANGUL SYLLABLE SIOS YAE SSANGSIOS + 0x98F1: 0xC116, //HANGUL SYLLABLE SIOS YAE CIEUC + 0x98F2: 0xC117, //HANGUL SYLLABLE SIOS YAE CHIEUCH + 0x98F3: 0xC118, //HANGUL SYLLABLE SIOS YAE KHIEUKH + 0x98F4: 0xC119, //HANGUL SYLLABLE SIOS YAE THIEUTH + 0x98F5: 0xC11A, //HANGUL SYLLABLE SIOS YAE PHIEUPH + 0x98F6: 0xC11B, //HANGUL SYLLABLE SIOS YAE HIEUH + 0x98F7: 0xC121, //HANGUL SYLLABLE SIOS EO NIEUNCIEUC + 0x98F8: 0xC122, //HANGUL SYLLABLE SIOS EO NIEUNHIEUH + 0x98F9: 0xC125, //HANGUL SYLLABLE SIOS EO RIEULKIYEOK + 0x98FA: 0xC128, //HANGUL SYLLABLE SIOS EO RIEULSIOS + 0x98FB: 0xC129, //HANGUL SYLLABLE SIOS EO RIEULTHIEUTH + 0x98FC: 0xC12A, //HANGUL SYLLABLE SIOS EO RIEULPHIEUPH + 0x98FD: 0xC12B, //HANGUL SYLLABLE SIOS EO RIEULHIEUH + 0x98FE: 0xC12E, //HANGUL SYLLABLE SIOS EO PIEUPSIOS + 0x9941: 0xC132, //HANGUL SYLLABLE SIOS EO CIEUC + 0x9942: 0xC133, //HANGUL SYLLABLE SIOS EO CHIEUCH + 0x9943: 0xC134, //HANGUL SYLLABLE SIOS EO KHIEUKH + 0x9944: 0xC135, //HANGUL SYLLABLE SIOS EO THIEUTH + 0x9945: 0xC137, //HANGUL SYLLABLE SIOS EO HIEUH + 0x9946: 0xC13A, //HANGUL SYLLABLE SIOS E SSANGKIYEOK + 0x9947: 0xC13B, //HANGUL SYLLABLE SIOS E KIYEOKSIOS + 0x9948: 0xC13D, //HANGUL SYLLABLE SIOS E NIEUNCIEUC + 0x9949: 0xC13E, //HANGUL SYLLABLE SIOS E NIEUNHIEUH + 0x994A: 0xC13F, //HANGUL SYLLABLE SIOS E TIKEUT + 0x994B: 0xC141, //HANGUL SYLLABLE SIOS E RIEULKIYEOK + 0x994C: 0xC142, //HANGUL SYLLABLE SIOS E RIEULMIEUM + 0x994D: 0xC143, //HANGUL SYLLABLE SIOS E RIEULPIEUP + 0x994E: 0xC144, //HANGUL SYLLABLE SIOS E RIEULSIOS + 0x994F: 0xC145, //HANGUL SYLLABLE SIOS E RIEULTHIEUTH + 0x9950: 0xC146, //HANGUL SYLLABLE SIOS E RIEULPHIEUPH + 0x9951: 0xC147, //HANGUL SYLLABLE SIOS E RIEULHIEUH + 0x9952: 0xC14A, //HANGUL SYLLABLE SIOS E PIEUPSIOS + 0x9953: 0xC14E, //HANGUL SYLLABLE SIOS E CIEUC + 0x9954: 0xC14F, //HANGUL SYLLABLE SIOS E CHIEUCH + 0x9955: 0xC150, //HANGUL SYLLABLE SIOS E KHIEUKH + 0x9956: 0xC151, //HANGUL SYLLABLE SIOS E THIEUTH + 0x9957: 0xC152, //HANGUL SYLLABLE SIOS E PHIEUPH + 0x9958: 0xC153, //HANGUL SYLLABLE SIOS E HIEUH + 0x9959: 0xC156, //HANGUL SYLLABLE SIOS YEO SSANGKIYEOK + 0x995A: 0xC157, //HANGUL SYLLABLE SIOS YEO KIYEOKSIOS + 0x9961: 0xC159, //HANGUL SYLLABLE SIOS YEO NIEUNCIEUC + 0x9962: 0xC15A, //HANGUL SYLLABLE SIOS YEO NIEUNHIEUH + 0x9963: 0xC15B, //HANGUL SYLLABLE SIOS YEO TIKEUT + 0x9964: 0xC15D, //HANGUL SYLLABLE SIOS YEO RIEULKIYEOK + 0x9965: 0xC15E, //HANGUL SYLLABLE SIOS YEO RIEULMIEUM + 0x9966: 0xC15F, //HANGUL SYLLABLE SIOS YEO RIEULPIEUP + 0x9967: 0xC160, //HANGUL SYLLABLE SIOS YEO RIEULSIOS + 0x9968: 0xC161, //HANGUL SYLLABLE SIOS YEO RIEULTHIEUTH + 0x9969: 0xC162, //HANGUL SYLLABLE SIOS YEO RIEULPHIEUPH + 0x996A: 0xC163, //HANGUL SYLLABLE SIOS YEO RIEULHIEUH + 0x996B: 0xC166, //HANGUL SYLLABLE SIOS YEO PIEUPSIOS + 0x996C: 0xC16A, //HANGUL SYLLABLE SIOS YEO CIEUC + 0x996D: 0xC16B, //HANGUL SYLLABLE SIOS YEO CHIEUCH + 0x996E: 0xC16C, //HANGUL SYLLABLE SIOS YEO KHIEUKH + 0x996F: 0xC16D, //HANGUL SYLLABLE SIOS YEO THIEUTH + 0x9970: 0xC16E, //HANGUL SYLLABLE SIOS YEO PHIEUPH + 0x9971: 0xC16F, //HANGUL SYLLABLE SIOS YEO HIEUH + 0x9972: 0xC171, //HANGUL SYLLABLE SIOS YE KIYEOK + 0x9973: 0xC172, //HANGUL SYLLABLE SIOS YE SSANGKIYEOK + 0x9974: 0xC173, //HANGUL SYLLABLE SIOS YE KIYEOKSIOS + 0x9975: 0xC175, //HANGUL SYLLABLE SIOS YE NIEUNCIEUC + 0x9976: 0xC176, //HANGUL SYLLABLE SIOS YE NIEUNHIEUH + 0x9977: 0xC177, //HANGUL SYLLABLE SIOS YE TIKEUT + 0x9978: 0xC179, //HANGUL SYLLABLE SIOS YE RIEULKIYEOK + 0x9979: 0xC17A, //HANGUL SYLLABLE SIOS YE RIEULMIEUM + 0x997A: 0xC17B, //HANGUL SYLLABLE SIOS YE RIEULPIEUP + 0x9981: 0xC17C, //HANGUL SYLLABLE SIOS YE RIEULSIOS + 0x9982: 0xC17D, //HANGUL SYLLABLE SIOS YE RIEULTHIEUTH + 0x9983: 0xC17E, //HANGUL SYLLABLE SIOS YE RIEULPHIEUPH + 0x9984: 0xC17F, //HANGUL SYLLABLE SIOS YE RIEULHIEUH + 0x9985: 0xC180, //HANGUL SYLLABLE SIOS YE MIEUM + 0x9986: 0xC181, //HANGUL SYLLABLE SIOS YE PIEUP + 0x9987: 0xC182, //HANGUL SYLLABLE SIOS YE PIEUPSIOS + 0x9988: 0xC183, //HANGUL SYLLABLE SIOS YE SIOS + 0x9989: 0xC184, //HANGUL SYLLABLE SIOS YE SSANGSIOS + 0x998A: 0xC186, //HANGUL SYLLABLE SIOS YE CIEUC + 0x998B: 0xC187, //HANGUL SYLLABLE SIOS YE CHIEUCH + 0x998C: 0xC188, //HANGUL SYLLABLE SIOS YE KHIEUKH + 0x998D: 0xC189, //HANGUL SYLLABLE SIOS YE THIEUTH + 0x998E: 0xC18A, //HANGUL SYLLABLE SIOS YE PHIEUPH + 0x998F: 0xC18B, //HANGUL SYLLABLE SIOS YE HIEUH + 0x9990: 0xC18F, //HANGUL SYLLABLE SIOS O KIYEOKSIOS + 0x9991: 0xC191, //HANGUL SYLLABLE SIOS O NIEUNCIEUC + 0x9992: 0xC192, //HANGUL SYLLABLE SIOS O NIEUNHIEUH + 0x9993: 0xC193, //HANGUL SYLLABLE SIOS O TIKEUT + 0x9994: 0xC195, //HANGUL SYLLABLE SIOS O RIEULKIYEOK + 0x9995: 0xC197, //HANGUL SYLLABLE SIOS O RIEULPIEUP + 0x9996: 0xC198, //HANGUL SYLLABLE SIOS O RIEULSIOS + 0x9997: 0xC199, //HANGUL SYLLABLE SIOS O RIEULTHIEUTH + 0x9998: 0xC19A, //HANGUL SYLLABLE SIOS O RIEULPHIEUPH + 0x9999: 0xC19B, //HANGUL SYLLABLE SIOS O RIEULHIEUH + 0x999A: 0xC19E, //HANGUL SYLLABLE SIOS O PIEUPSIOS + 0x999B: 0xC1A0, //HANGUL SYLLABLE SIOS O SSANGSIOS + 0x999C: 0xC1A2, //HANGUL SYLLABLE SIOS O CIEUC + 0x999D: 0xC1A3, //HANGUL SYLLABLE SIOS O CHIEUCH + 0x999E: 0xC1A4, //HANGUL SYLLABLE SIOS O KHIEUKH + 0x999F: 0xC1A6, //HANGUL SYLLABLE SIOS O PHIEUPH + 0x99A0: 0xC1A7, //HANGUL SYLLABLE SIOS O HIEUH + 0x99A1: 0xC1AA, //HANGUL SYLLABLE SIOS WA SSANGKIYEOK + 0x99A2: 0xC1AB, //HANGUL SYLLABLE SIOS WA KIYEOKSIOS + 0x99A3: 0xC1AD, //HANGUL SYLLABLE SIOS WA NIEUNCIEUC + 0x99A4: 0xC1AE, //HANGUL SYLLABLE SIOS WA NIEUNHIEUH + 0x99A5: 0xC1AF, //HANGUL SYLLABLE SIOS WA TIKEUT + 0x99A6: 0xC1B1, //HANGUL SYLLABLE SIOS WA RIEULKIYEOK + 0x99A7: 0xC1B2, //HANGUL SYLLABLE SIOS WA RIEULMIEUM + 0x99A8: 0xC1B3, //HANGUL SYLLABLE SIOS WA RIEULPIEUP + 0x99A9: 0xC1B4, //HANGUL SYLLABLE SIOS WA RIEULSIOS + 0x99AA: 0xC1B5, //HANGUL SYLLABLE SIOS WA RIEULTHIEUTH + 0x99AB: 0xC1B6, //HANGUL SYLLABLE SIOS WA RIEULPHIEUPH + 0x99AC: 0xC1B7, //HANGUL SYLLABLE SIOS WA RIEULHIEUH + 0x99AD: 0xC1B8, //HANGUL SYLLABLE SIOS WA MIEUM + 0x99AE: 0xC1B9, //HANGUL SYLLABLE SIOS WA PIEUP + 0x99AF: 0xC1BA, //HANGUL SYLLABLE SIOS WA PIEUPSIOS + 0x99B0: 0xC1BB, //HANGUL SYLLABLE SIOS WA SIOS + 0x99B1: 0xC1BC, //HANGUL SYLLABLE SIOS WA SSANGSIOS + 0x99B2: 0xC1BE, //HANGUL SYLLABLE SIOS WA CIEUC + 0x99B3: 0xC1BF, //HANGUL SYLLABLE SIOS WA CHIEUCH + 0x99B4: 0xC1C0, //HANGUL SYLLABLE SIOS WA KHIEUKH + 0x99B5: 0xC1C1, //HANGUL SYLLABLE SIOS WA THIEUTH + 0x99B6: 0xC1C2, //HANGUL SYLLABLE SIOS WA PHIEUPH + 0x99B7: 0xC1C3, //HANGUL SYLLABLE SIOS WA HIEUH + 0x99B8: 0xC1C5, //HANGUL SYLLABLE SIOS WAE KIYEOK + 0x99B9: 0xC1C6, //HANGUL SYLLABLE SIOS WAE SSANGKIYEOK + 0x99BA: 0xC1C7, //HANGUL SYLLABLE SIOS WAE KIYEOKSIOS + 0x99BB: 0xC1C9, //HANGUL SYLLABLE SIOS WAE NIEUNCIEUC + 0x99BC: 0xC1CA, //HANGUL SYLLABLE SIOS WAE NIEUNHIEUH + 0x99BD: 0xC1CB, //HANGUL SYLLABLE SIOS WAE TIKEUT + 0x99BE: 0xC1CD, //HANGUL SYLLABLE SIOS WAE RIEULKIYEOK + 0x99BF: 0xC1CE, //HANGUL SYLLABLE SIOS WAE RIEULMIEUM + 0x99C0: 0xC1CF, //HANGUL SYLLABLE SIOS WAE RIEULPIEUP + 0x99C1: 0xC1D0, //HANGUL SYLLABLE SIOS WAE RIEULSIOS + 0x99C2: 0xC1D1, //HANGUL SYLLABLE SIOS WAE RIEULTHIEUTH + 0x99C3: 0xC1D2, //HANGUL SYLLABLE SIOS WAE RIEULPHIEUPH + 0x99C4: 0xC1D3, //HANGUL SYLLABLE SIOS WAE RIEULHIEUH + 0x99C5: 0xC1D5, //HANGUL SYLLABLE SIOS WAE PIEUP + 0x99C6: 0xC1D6, //HANGUL SYLLABLE SIOS WAE PIEUPSIOS + 0x99C7: 0xC1D9, //HANGUL SYLLABLE SIOS WAE IEUNG + 0x99C8: 0xC1DA, //HANGUL SYLLABLE SIOS WAE CIEUC + 0x99C9: 0xC1DB, //HANGUL SYLLABLE SIOS WAE CHIEUCH + 0x99CA: 0xC1DC, //HANGUL SYLLABLE SIOS WAE KHIEUKH + 0x99CB: 0xC1DD, //HANGUL SYLLABLE SIOS WAE THIEUTH + 0x99CC: 0xC1DE, //HANGUL SYLLABLE SIOS WAE PHIEUPH + 0x99CD: 0xC1DF, //HANGUL SYLLABLE SIOS WAE HIEUH + 0x99CE: 0xC1E1, //HANGUL SYLLABLE SIOS OE KIYEOK + 0x99CF: 0xC1E2, //HANGUL SYLLABLE SIOS OE SSANGKIYEOK + 0x99D0: 0xC1E3, //HANGUL SYLLABLE SIOS OE KIYEOKSIOS + 0x99D1: 0xC1E5, //HANGUL SYLLABLE SIOS OE NIEUNCIEUC + 0x99D2: 0xC1E6, //HANGUL SYLLABLE SIOS OE NIEUNHIEUH + 0x99D3: 0xC1E7, //HANGUL SYLLABLE SIOS OE TIKEUT + 0x99D4: 0xC1E9, //HANGUL SYLLABLE SIOS OE RIEULKIYEOK + 0x99D5: 0xC1EA, //HANGUL SYLLABLE SIOS OE RIEULMIEUM + 0x99D6: 0xC1EB, //HANGUL SYLLABLE SIOS OE RIEULPIEUP + 0x99D7: 0xC1EC, //HANGUL SYLLABLE SIOS OE RIEULSIOS + 0x99D8: 0xC1ED, //HANGUL SYLLABLE SIOS OE RIEULTHIEUTH + 0x99D9: 0xC1EE, //HANGUL SYLLABLE SIOS OE RIEULPHIEUPH + 0x99DA: 0xC1EF, //HANGUL SYLLABLE SIOS OE RIEULHIEUH + 0x99DB: 0xC1F2, //HANGUL SYLLABLE SIOS OE PIEUPSIOS + 0x99DC: 0xC1F4, //HANGUL SYLLABLE SIOS OE SSANGSIOS + 0x99DD: 0xC1F5, //HANGUL SYLLABLE SIOS OE IEUNG + 0x99DE: 0xC1F6, //HANGUL SYLLABLE SIOS OE CIEUC + 0x99DF: 0xC1F7, //HANGUL SYLLABLE SIOS OE CHIEUCH + 0x99E0: 0xC1F8, //HANGUL SYLLABLE SIOS OE KHIEUKH + 0x99E1: 0xC1F9, //HANGUL SYLLABLE SIOS OE THIEUTH + 0x99E2: 0xC1FA, //HANGUL SYLLABLE SIOS OE PHIEUPH + 0x99E3: 0xC1FB, //HANGUL SYLLABLE SIOS OE HIEUH + 0x99E4: 0xC1FE, //HANGUL SYLLABLE SIOS YO SSANGKIYEOK + 0x99E5: 0xC1FF, //HANGUL SYLLABLE SIOS YO KIYEOKSIOS + 0x99E6: 0xC201, //HANGUL SYLLABLE SIOS YO NIEUNCIEUC + 0x99E7: 0xC202, //HANGUL SYLLABLE SIOS YO NIEUNHIEUH + 0x99E8: 0xC203, //HANGUL SYLLABLE SIOS YO TIKEUT + 0x99E9: 0xC205, //HANGUL SYLLABLE SIOS YO RIEULKIYEOK + 0x99EA: 0xC206, //HANGUL SYLLABLE SIOS YO RIEULMIEUM + 0x99EB: 0xC207, //HANGUL SYLLABLE SIOS YO RIEULPIEUP + 0x99EC: 0xC208, //HANGUL SYLLABLE SIOS YO RIEULSIOS + 0x99ED: 0xC209, //HANGUL SYLLABLE SIOS YO RIEULTHIEUTH + 0x99EE: 0xC20A, //HANGUL SYLLABLE SIOS YO RIEULPHIEUPH + 0x99EF: 0xC20B, //HANGUL SYLLABLE SIOS YO RIEULHIEUH + 0x99F0: 0xC20E, //HANGUL SYLLABLE SIOS YO PIEUPSIOS + 0x99F1: 0xC210, //HANGUL SYLLABLE SIOS YO SSANGSIOS + 0x99F2: 0xC212, //HANGUL SYLLABLE SIOS YO CIEUC + 0x99F3: 0xC213, //HANGUL SYLLABLE SIOS YO CHIEUCH + 0x99F4: 0xC214, //HANGUL SYLLABLE SIOS YO KHIEUKH + 0x99F5: 0xC215, //HANGUL SYLLABLE SIOS YO THIEUTH + 0x99F6: 0xC216, //HANGUL SYLLABLE SIOS YO PHIEUPH + 0x99F7: 0xC217, //HANGUL SYLLABLE SIOS YO HIEUH + 0x99F8: 0xC21A, //HANGUL SYLLABLE SIOS U SSANGKIYEOK + 0x99F9: 0xC21B, //HANGUL SYLLABLE SIOS U KIYEOKSIOS + 0x99FA: 0xC21D, //HANGUL SYLLABLE SIOS U NIEUNCIEUC + 0x99FB: 0xC21E, //HANGUL SYLLABLE SIOS U NIEUNHIEUH + 0x99FC: 0xC221, //HANGUL SYLLABLE SIOS U RIEULKIYEOK + 0x99FD: 0xC222, //HANGUL SYLLABLE SIOS U RIEULMIEUM + 0x99FE: 0xC223, //HANGUL SYLLABLE SIOS U RIEULPIEUP + 0x9A41: 0xC224, //HANGUL SYLLABLE SIOS U RIEULSIOS + 0x9A42: 0xC225, //HANGUL SYLLABLE SIOS U RIEULTHIEUTH + 0x9A43: 0xC226, //HANGUL SYLLABLE SIOS U RIEULPHIEUPH + 0x9A44: 0xC227, //HANGUL SYLLABLE SIOS U RIEULHIEUH + 0x9A45: 0xC22A, //HANGUL SYLLABLE SIOS U PIEUPSIOS + 0x9A46: 0xC22C, //HANGUL SYLLABLE SIOS U SSANGSIOS + 0x9A47: 0xC22E, //HANGUL SYLLABLE SIOS U CIEUC + 0x9A48: 0xC230, //HANGUL SYLLABLE SIOS U KHIEUKH + 0x9A49: 0xC233, //HANGUL SYLLABLE SIOS U HIEUH + 0x9A4A: 0xC235, //HANGUL SYLLABLE SIOS WEO KIYEOK + 0x9A4B: 0xC236, //HANGUL SYLLABLE SIOS WEO SSANGKIYEOK + 0x9A4C: 0xC237, //HANGUL SYLLABLE SIOS WEO KIYEOKSIOS + 0x9A4D: 0xC238, //HANGUL SYLLABLE SIOS WEO NIEUN + 0x9A4E: 0xC239, //HANGUL SYLLABLE SIOS WEO NIEUNCIEUC + 0x9A4F: 0xC23A, //HANGUL SYLLABLE SIOS WEO NIEUNHIEUH + 0x9A50: 0xC23B, //HANGUL SYLLABLE SIOS WEO TIKEUT + 0x9A51: 0xC23C, //HANGUL SYLLABLE SIOS WEO RIEUL + 0x9A52: 0xC23D, //HANGUL SYLLABLE SIOS WEO RIEULKIYEOK + 0x9A53: 0xC23E, //HANGUL SYLLABLE SIOS WEO RIEULMIEUM + 0x9A54: 0xC23F, //HANGUL SYLLABLE SIOS WEO RIEULPIEUP + 0x9A55: 0xC240, //HANGUL SYLLABLE SIOS WEO RIEULSIOS + 0x9A56: 0xC241, //HANGUL SYLLABLE SIOS WEO RIEULTHIEUTH + 0x9A57: 0xC242, //HANGUL SYLLABLE SIOS WEO RIEULPHIEUPH + 0x9A58: 0xC243, //HANGUL SYLLABLE SIOS WEO RIEULHIEUH + 0x9A59: 0xC244, //HANGUL SYLLABLE SIOS WEO MIEUM + 0x9A5A: 0xC245, //HANGUL SYLLABLE SIOS WEO PIEUP + 0x9A61: 0xC246, //HANGUL SYLLABLE SIOS WEO PIEUPSIOS + 0x9A62: 0xC247, //HANGUL SYLLABLE SIOS WEO SIOS + 0x9A63: 0xC249, //HANGUL SYLLABLE SIOS WEO IEUNG + 0x9A64: 0xC24A, //HANGUL SYLLABLE SIOS WEO CIEUC + 0x9A65: 0xC24B, //HANGUL SYLLABLE SIOS WEO CHIEUCH + 0x9A66: 0xC24C, //HANGUL SYLLABLE SIOS WEO KHIEUKH + 0x9A67: 0xC24D, //HANGUL SYLLABLE SIOS WEO THIEUTH + 0x9A68: 0xC24E, //HANGUL SYLLABLE SIOS WEO PHIEUPH + 0x9A69: 0xC24F, //HANGUL SYLLABLE SIOS WEO HIEUH + 0x9A6A: 0xC252, //HANGUL SYLLABLE SIOS WE SSANGKIYEOK + 0x9A6B: 0xC253, //HANGUL SYLLABLE SIOS WE KIYEOKSIOS + 0x9A6C: 0xC255, //HANGUL SYLLABLE SIOS WE NIEUNCIEUC + 0x9A6D: 0xC256, //HANGUL SYLLABLE SIOS WE NIEUNHIEUH + 0x9A6E: 0xC257, //HANGUL SYLLABLE SIOS WE TIKEUT + 0x9A6F: 0xC259, //HANGUL SYLLABLE SIOS WE RIEULKIYEOK + 0x9A70: 0xC25A, //HANGUL SYLLABLE SIOS WE RIEULMIEUM + 0x9A71: 0xC25B, //HANGUL SYLLABLE SIOS WE RIEULPIEUP + 0x9A72: 0xC25C, //HANGUL SYLLABLE SIOS WE RIEULSIOS + 0x9A73: 0xC25D, //HANGUL SYLLABLE SIOS WE RIEULTHIEUTH + 0x9A74: 0xC25E, //HANGUL SYLLABLE SIOS WE RIEULPHIEUPH + 0x9A75: 0xC25F, //HANGUL SYLLABLE SIOS WE RIEULHIEUH + 0x9A76: 0xC261, //HANGUL SYLLABLE SIOS WE PIEUP + 0x9A77: 0xC262, //HANGUL SYLLABLE SIOS WE PIEUPSIOS + 0x9A78: 0xC263, //HANGUL SYLLABLE SIOS WE SIOS + 0x9A79: 0xC264, //HANGUL SYLLABLE SIOS WE SSANGSIOS + 0x9A7A: 0xC266, //HANGUL SYLLABLE SIOS WE CIEUC + 0x9A81: 0xC267, //HANGUL SYLLABLE SIOS WE CHIEUCH + 0x9A82: 0xC268, //HANGUL SYLLABLE SIOS WE KHIEUKH + 0x9A83: 0xC269, //HANGUL SYLLABLE SIOS WE THIEUTH + 0x9A84: 0xC26A, //HANGUL SYLLABLE SIOS WE PHIEUPH + 0x9A85: 0xC26B, //HANGUL SYLLABLE SIOS WE HIEUH + 0x9A86: 0xC26E, //HANGUL SYLLABLE SIOS WI SSANGKIYEOK + 0x9A87: 0xC26F, //HANGUL SYLLABLE SIOS WI KIYEOKSIOS + 0x9A88: 0xC271, //HANGUL SYLLABLE SIOS WI NIEUNCIEUC + 0x9A89: 0xC272, //HANGUL SYLLABLE SIOS WI NIEUNHIEUH + 0x9A8A: 0xC273, //HANGUL SYLLABLE SIOS WI TIKEUT + 0x9A8B: 0xC275, //HANGUL SYLLABLE SIOS WI RIEULKIYEOK + 0x9A8C: 0xC276, //HANGUL SYLLABLE SIOS WI RIEULMIEUM + 0x9A8D: 0xC277, //HANGUL SYLLABLE SIOS WI RIEULPIEUP + 0x9A8E: 0xC278, //HANGUL SYLLABLE SIOS WI RIEULSIOS + 0x9A8F: 0xC279, //HANGUL SYLLABLE SIOS WI RIEULTHIEUTH + 0x9A90: 0xC27A, //HANGUL SYLLABLE SIOS WI RIEULPHIEUPH + 0x9A91: 0xC27B, //HANGUL SYLLABLE SIOS WI RIEULHIEUH + 0x9A92: 0xC27E, //HANGUL SYLLABLE SIOS WI PIEUPSIOS + 0x9A93: 0xC280, //HANGUL SYLLABLE SIOS WI SSANGSIOS + 0x9A94: 0xC282, //HANGUL SYLLABLE SIOS WI CIEUC + 0x9A95: 0xC283, //HANGUL SYLLABLE SIOS WI CHIEUCH + 0x9A96: 0xC284, //HANGUL SYLLABLE SIOS WI KHIEUKH + 0x9A97: 0xC285, //HANGUL SYLLABLE SIOS WI THIEUTH + 0x9A98: 0xC286, //HANGUL SYLLABLE SIOS WI PHIEUPH + 0x9A99: 0xC287, //HANGUL SYLLABLE SIOS WI HIEUH + 0x9A9A: 0xC28A, //HANGUL SYLLABLE SIOS YU SSANGKIYEOK + 0x9A9B: 0xC28B, //HANGUL SYLLABLE SIOS YU KIYEOKSIOS + 0x9A9C: 0xC28C, //HANGUL SYLLABLE SIOS YU NIEUN + 0x9A9D: 0xC28D, //HANGUL SYLLABLE SIOS YU NIEUNCIEUC + 0x9A9E: 0xC28E, //HANGUL SYLLABLE SIOS YU NIEUNHIEUH + 0x9A9F: 0xC28F, //HANGUL SYLLABLE SIOS YU TIKEUT + 0x9AA0: 0xC291, //HANGUL SYLLABLE SIOS YU RIEULKIYEOK + 0x9AA1: 0xC292, //HANGUL SYLLABLE SIOS YU RIEULMIEUM + 0x9AA2: 0xC293, //HANGUL SYLLABLE SIOS YU RIEULPIEUP + 0x9AA3: 0xC294, //HANGUL SYLLABLE SIOS YU RIEULSIOS + 0x9AA4: 0xC295, //HANGUL SYLLABLE SIOS YU RIEULTHIEUTH + 0x9AA5: 0xC296, //HANGUL SYLLABLE SIOS YU RIEULPHIEUPH + 0x9AA6: 0xC297, //HANGUL SYLLABLE SIOS YU RIEULHIEUH + 0x9AA7: 0xC299, //HANGUL SYLLABLE SIOS YU PIEUP + 0x9AA8: 0xC29A, //HANGUL SYLLABLE SIOS YU PIEUPSIOS + 0x9AA9: 0xC29C, //HANGUL SYLLABLE SIOS YU SSANGSIOS + 0x9AAA: 0xC29E, //HANGUL SYLLABLE SIOS YU CIEUC + 0x9AAB: 0xC29F, //HANGUL SYLLABLE SIOS YU CHIEUCH + 0x9AAC: 0xC2A0, //HANGUL SYLLABLE SIOS YU KHIEUKH + 0x9AAD: 0xC2A1, //HANGUL SYLLABLE SIOS YU THIEUTH + 0x9AAE: 0xC2A2, //HANGUL SYLLABLE SIOS YU PHIEUPH + 0x9AAF: 0xC2A3, //HANGUL SYLLABLE SIOS YU HIEUH + 0x9AB0: 0xC2A6, //HANGUL SYLLABLE SIOS EU SSANGKIYEOK + 0x9AB1: 0xC2A7, //HANGUL SYLLABLE SIOS EU KIYEOKSIOS + 0x9AB2: 0xC2A9, //HANGUL SYLLABLE SIOS EU NIEUNCIEUC + 0x9AB3: 0xC2AA, //HANGUL SYLLABLE SIOS EU NIEUNHIEUH + 0x9AB4: 0xC2AB, //HANGUL SYLLABLE SIOS EU TIKEUT + 0x9AB5: 0xC2AE, //HANGUL SYLLABLE SIOS EU RIEULMIEUM + 0x9AB6: 0xC2AF, //HANGUL SYLLABLE SIOS EU RIEULPIEUP + 0x9AB7: 0xC2B0, //HANGUL SYLLABLE SIOS EU RIEULSIOS + 0x9AB8: 0xC2B1, //HANGUL SYLLABLE SIOS EU RIEULTHIEUTH + 0x9AB9: 0xC2B2, //HANGUL SYLLABLE SIOS EU RIEULPHIEUPH + 0x9ABA: 0xC2B3, //HANGUL SYLLABLE SIOS EU RIEULHIEUH + 0x9ABB: 0xC2B6, //HANGUL SYLLABLE SIOS EU PIEUPSIOS + 0x9ABC: 0xC2B8, //HANGUL SYLLABLE SIOS EU SSANGSIOS + 0x9ABD: 0xC2BA, //HANGUL SYLLABLE SIOS EU CIEUC + 0x9ABE: 0xC2BB, //HANGUL SYLLABLE SIOS EU CHIEUCH + 0x9ABF: 0xC2BC, //HANGUL SYLLABLE SIOS EU KHIEUKH + 0x9AC0: 0xC2BD, //HANGUL SYLLABLE SIOS EU THIEUTH + 0x9AC1: 0xC2BE, //HANGUL SYLLABLE SIOS EU PHIEUPH + 0x9AC2: 0xC2BF, //HANGUL SYLLABLE SIOS EU HIEUH + 0x9AC3: 0xC2C0, //HANGUL SYLLABLE SIOS YI + 0x9AC4: 0xC2C1, //HANGUL SYLLABLE SIOS YI KIYEOK + 0x9AC5: 0xC2C2, //HANGUL SYLLABLE SIOS YI SSANGKIYEOK + 0x9AC6: 0xC2C3, //HANGUL SYLLABLE SIOS YI KIYEOKSIOS + 0x9AC7: 0xC2C4, //HANGUL SYLLABLE SIOS YI NIEUN + 0x9AC8: 0xC2C5, //HANGUL SYLLABLE SIOS YI NIEUNCIEUC + 0x9AC9: 0xC2C6, //HANGUL SYLLABLE SIOS YI NIEUNHIEUH + 0x9ACA: 0xC2C7, //HANGUL SYLLABLE SIOS YI TIKEUT + 0x9ACB: 0xC2C8, //HANGUL SYLLABLE SIOS YI RIEUL + 0x9ACC: 0xC2C9, //HANGUL SYLLABLE SIOS YI RIEULKIYEOK + 0x9ACD: 0xC2CA, //HANGUL SYLLABLE SIOS YI RIEULMIEUM + 0x9ACE: 0xC2CB, //HANGUL SYLLABLE SIOS YI RIEULPIEUP + 0x9ACF: 0xC2CC, //HANGUL SYLLABLE SIOS YI RIEULSIOS + 0x9AD0: 0xC2CD, //HANGUL SYLLABLE SIOS YI RIEULTHIEUTH + 0x9AD1: 0xC2CE, //HANGUL SYLLABLE SIOS YI RIEULPHIEUPH + 0x9AD2: 0xC2CF, //HANGUL SYLLABLE SIOS YI RIEULHIEUH + 0x9AD3: 0xC2D0, //HANGUL SYLLABLE SIOS YI MIEUM + 0x9AD4: 0xC2D1, //HANGUL SYLLABLE SIOS YI PIEUP + 0x9AD5: 0xC2D2, //HANGUL SYLLABLE SIOS YI PIEUPSIOS + 0x9AD6: 0xC2D3, //HANGUL SYLLABLE SIOS YI SIOS + 0x9AD7: 0xC2D4, //HANGUL SYLLABLE SIOS YI SSANGSIOS + 0x9AD8: 0xC2D5, //HANGUL SYLLABLE SIOS YI IEUNG + 0x9AD9: 0xC2D6, //HANGUL SYLLABLE SIOS YI CIEUC + 0x9ADA: 0xC2D7, //HANGUL SYLLABLE SIOS YI CHIEUCH + 0x9ADB: 0xC2D8, //HANGUL SYLLABLE SIOS YI KHIEUKH + 0x9ADC: 0xC2D9, //HANGUL SYLLABLE SIOS YI THIEUTH + 0x9ADD: 0xC2DA, //HANGUL SYLLABLE SIOS YI PHIEUPH + 0x9ADE: 0xC2DB, //HANGUL SYLLABLE SIOS YI HIEUH + 0x9ADF: 0xC2DE, //HANGUL SYLLABLE SIOS I SSANGKIYEOK + 0x9AE0: 0xC2DF, //HANGUL SYLLABLE SIOS I KIYEOKSIOS + 0x9AE1: 0xC2E1, //HANGUL SYLLABLE SIOS I NIEUNCIEUC + 0x9AE2: 0xC2E2, //HANGUL SYLLABLE SIOS I NIEUNHIEUH + 0x9AE3: 0xC2E5, //HANGUL SYLLABLE SIOS I RIEULKIYEOK + 0x9AE4: 0xC2E6, //HANGUL SYLLABLE SIOS I RIEULMIEUM + 0x9AE5: 0xC2E7, //HANGUL SYLLABLE SIOS I RIEULPIEUP + 0x9AE6: 0xC2E8, //HANGUL SYLLABLE SIOS I RIEULSIOS + 0x9AE7: 0xC2E9, //HANGUL SYLLABLE SIOS I RIEULTHIEUTH + 0x9AE8: 0xC2EA, //HANGUL SYLLABLE SIOS I RIEULPHIEUPH + 0x9AE9: 0xC2EE, //HANGUL SYLLABLE SIOS I PIEUPSIOS + 0x9AEA: 0xC2F0, //HANGUL SYLLABLE SIOS I SSANGSIOS + 0x9AEB: 0xC2F2, //HANGUL SYLLABLE SIOS I CIEUC + 0x9AEC: 0xC2F3, //HANGUL SYLLABLE SIOS I CHIEUCH + 0x9AED: 0xC2F4, //HANGUL SYLLABLE SIOS I KHIEUKH + 0x9AEE: 0xC2F5, //HANGUL SYLLABLE SIOS I THIEUTH + 0x9AEF: 0xC2F7, //HANGUL SYLLABLE SIOS I HIEUH + 0x9AF0: 0xC2FA, //HANGUL SYLLABLE SSANGSIOS A SSANGKIYEOK + 0x9AF1: 0xC2FD, //HANGUL SYLLABLE SSANGSIOS A NIEUNCIEUC + 0x9AF2: 0xC2FE, //HANGUL SYLLABLE SSANGSIOS A NIEUNHIEUH + 0x9AF3: 0xC2FF, //HANGUL SYLLABLE SSANGSIOS A TIKEUT + 0x9AF4: 0xC301, //HANGUL SYLLABLE SSANGSIOS A RIEULKIYEOK + 0x9AF5: 0xC302, //HANGUL SYLLABLE SSANGSIOS A RIEULMIEUM + 0x9AF6: 0xC303, //HANGUL SYLLABLE SSANGSIOS A RIEULPIEUP + 0x9AF7: 0xC304, //HANGUL SYLLABLE SSANGSIOS A RIEULSIOS + 0x9AF8: 0xC305, //HANGUL SYLLABLE SSANGSIOS A RIEULTHIEUTH + 0x9AF9: 0xC306, //HANGUL SYLLABLE SSANGSIOS A RIEULPHIEUPH + 0x9AFA: 0xC307, //HANGUL SYLLABLE SSANGSIOS A RIEULHIEUH + 0x9AFB: 0xC30A, //HANGUL SYLLABLE SSANGSIOS A PIEUPSIOS + 0x9AFC: 0xC30B, //HANGUL SYLLABLE SSANGSIOS A SIOS + 0x9AFD: 0xC30E, //HANGUL SYLLABLE SSANGSIOS A CIEUC + 0x9AFE: 0xC30F, //HANGUL SYLLABLE SSANGSIOS A CHIEUCH + 0x9B41: 0xC310, //HANGUL SYLLABLE SSANGSIOS A KHIEUKH + 0x9B42: 0xC311, //HANGUL SYLLABLE SSANGSIOS A THIEUTH + 0x9B43: 0xC312, //HANGUL SYLLABLE SSANGSIOS A PHIEUPH + 0x9B44: 0xC316, //HANGUL SYLLABLE SSANGSIOS AE SSANGKIYEOK + 0x9B45: 0xC317, //HANGUL SYLLABLE SSANGSIOS AE KIYEOKSIOS + 0x9B46: 0xC319, //HANGUL SYLLABLE SSANGSIOS AE NIEUNCIEUC + 0x9B47: 0xC31A, //HANGUL SYLLABLE SSANGSIOS AE NIEUNHIEUH + 0x9B48: 0xC31B, //HANGUL SYLLABLE SSANGSIOS AE TIKEUT + 0x9B49: 0xC31D, //HANGUL SYLLABLE SSANGSIOS AE RIEULKIYEOK + 0x9B4A: 0xC31E, //HANGUL SYLLABLE SSANGSIOS AE RIEULMIEUM + 0x9B4B: 0xC31F, //HANGUL SYLLABLE SSANGSIOS AE RIEULPIEUP + 0x9B4C: 0xC320, //HANGUL SYLLABLE SSANGSIOS AE RIEULSIOS + 0x9B4D: 0xC321, //HANGUL SYLLABLE SSANGSIOS AE RIEULTHIEUTH + 0x9B4E: 0xC322, //HANGUL SYLLABLE SSANGSIOS AE RIEULPHIEUPH + 0x9B4F: 0xC323, //HANGUL SYLLABLE SSANGSIOS AE RIEULHIEUH + 0x9B50: 0xC326, //HANGUL SYLLABLE SSANGSIOS AE PIEUPSIOS + 0x9B51: 0xC327, //HANGUL SYLLABLE SSANGSIOS AE SIOS + 0x9B52: 0xC32A, //HANGUL SYLLABLE SSANGSIOS AE CIEUC + 0x9B53: 0xC32B, //HANGUL SYLLABLE SSANGSIOS AE CHIEUCH + 0x9B54: 0xC32C, //HANGUL SYLLABLE SSANGSIOS AE KHIEUKH + 0x9B55: 0xC32D, //HANGUL SYLLABLE SSANGSIOS AE THIEUTH + 0x9B56: 0xC32E, //HANGUL SYLLABLE SSANGSIOS AE PHIEUPH + 0x9B57: 0xC32F, //HANGUL SYLLABLE SSANGSIOS AE HIEUH + 0x9B58: 0xC330, //HANGUL SYLLABLE SSANGSIOS YA + 0x9B59: 0xC331, //HANGUL SYLLABLE SSANGSIOS YA KIYEOK + 0x9B5A: 0xC332, //HANGUL SYLLABLE SSANGSIOS YA SSANGKIYEOK + 0x9B61: 0xC333, //HANGUL SYLLABLE SSANGSIOS YA KIYEOKSIOS + 0x9B62: 0xC334, //HANGUL SYLLABLE SSANGSIOS YA NIEUN + 0x9B63: 0xC335, //HANGUL SYLLABLE SSANGSIOS YA NIEUNCIEUC + 0x9B64: 0xC336, //HANGUL SYLLABLE SSANGSIOS YA NIEUNHIEUH + 0x9B65: 0xC337, //HANGUL SYLLABLE SSANGSIOS YA TIKEUT + 0x9B66: 0xC338, //HANGUL SYLLABLE SSANGSIOS YA RIEUL + 0x9B67: 0xC339, //HANGUL SYLLABLE SSANGSIOS YA RIEULKIYEOK + 0x9B68: 0xC33A, //HANGUL SYLLABLE SSANGSIOS YA RIEULMIEUM + 0x9B69: 0xC33B, //HANGUL SYLLABLE SSANGSIOS YA RIEULPIEUP + 0x9B6A: 0xC33C, //HANGUL SYLLABLE SSANGSIOS YA RIEULSIOS + 0x9B6B: 0xC33D, //HANGUL SYLLABLE SSANGSIOS YA RIEULTHIEUTH + 0x9B6C: 0xC33E, //HANGUL SYLLABLE SSANGSIOS YA RIEULPHIEUPH + 0x9B6D: 0xC33F, //HANGUL SYLLABLE SSANGSIOS YA RIEULHIEUH + 0x9B6E: 0xC340, //HANGUL SYLLABLE SSANGSIOS YA MIEUM + 0x9B6F: 0xC341, //HANGUL SYLLABLE SSANGSIOS YA PIEUP + 0x9B70: 0xC342, //HANGUL SYLLABLE SSANGSIOS YA PIEUPSIOS + 0x9B71: 0xC343, //HANGUL SYLLABLE SSANGSIOS YA SIOS + 0x9B72: 0xC344, //HANGUL SYLLABLE SSANGSIOS YA SSANGSIOS + 0x9B73: 0xC346, //HANGUL SYLLABLE SSANGSIOS YA CIEUC + 0x9B74: 0xC347, //HANGUL SYLLABLE SSANGSIOS YA CHIEUCH + 0x9B75: 0xC348, //HANGUL SYLLABLE SSANGSIOS YA KHIEUKH + 0x9B76: 0xC349, //HANGUL SYLLABLE SSANGSIOS YA THIEUTH + 0x9B77: 0xC34A, //HANGUL SYLLABLE SSANGSIOS YA PHIEUPH + 0x9B78: 0xC34B, //HANGUL SYLLABLE SSANGSIOS YA HIEUH + 0x9B79: 0xC34C, //HANGUL SYLLABLE SSANGSIOS YAE + 0x9B7A: 0xC34D, //HANGUL SYLLABLE SSANGSIOS YAE KIYEOK + 0x9B81: 0xC34E, //HANGUL SYLLABLE SSANGSIOS YAE SSANGKIYEOK + 0x9B82: 0xC34F, //HANGUL SYLLABLE SSANGSIOS YAE KIYEOKSIOS + 0x9B83: 0xC350, //HANGUL SYLLABLE SSANGSIOS YAE NIEUN + 0x9B84: 0xC351, //HANGUL SYLLABLE SSANGSIOS YAE NIEUNCIEUC + 0x9B85: 0xC352, //HANGUL SYLLABLE SSANGSIOS YAE NIEUNHIEUH + 0x9B86: 0xC353, //HANGUL SYLLABLE SSANGSIOS YAE TIKEUT + 0x9B87: 0xC354, //HANGUL SYLLABLE SSANGSIOS YAE RIEUL + 0x9B88: 0xC355, //HANGUL SYLLABLE SSANGSIOS YAE RIEULKIYEOK + 0x9B89: 0xC356, //HANGUL SYLLABLE SSANGSIOS YAE RIEULMIEUM + 0x9B8A: 0xC357, //HANGUL SYLLABLE SSANGSIOS YAE RIEULPIEUP + 0x9B8B: 0xC358, //HANGUL SYLLABLE SSANGSIOS YAE RIEULSIOS + 0x9B8C: 0xC359, //HANGUL SYLLABLE SSANGSIOS YAE RIEULTHIEUTH + 0x9B8D: 0xC35A, //HANGUL SYLLABLE SSANGSIOS YAE RIEULPHIEUPH + 0x9B8E: 0xC35B, //HANGUL SYLLABLE SSANGSIOS YAE RIEULHIEUH + 0x9B8F: 0xC35C, //HANGUL SYLLABLE SSANGSIOS YAE MIEUM + 0x9B90: 0xC35D, //HANGUL SYLLABLE SSANGSIOS YAE PIEUP + 0x9B91: 0xC35E, //HANGUL SYLLABLE SSANGSIOS YAE PIEUPSIOS + 0x9B92: 0xC35F, //HANGUL SYLLABLE SSANGSIOS YAE SIOS + 0x9B93: 0xC360, //HANGUL SYLLABLE SSANGSIOS YAE SSANGSIOS + 0x9B94: 0xC361, //HANGUL SYLLABLE SSANGSIOS YAE IEUNG + 0x9B95: 0xC362, //HANGUL SYLLABLE SSANGSIOS YAE CIEUC + 0x9B96: 0xC363, //HANGUL SYLLABLE SSANGSIOS YAE CHIEUCH + 0x9B97: 0xC364, //HANGUL SYLLABLE SSANGSIOS YAE KHIEUKH + 0x9B98: 0xC365, //HANGUL SYLLABLE SSANGSIOS YAE THIEUTH + 0x9B99: 0xC366, //HANGUL SYLLABLE SSANGSIOS YAE PHIEUPH + 0x9B9A: 0xC367, //HANGUL SYLLABLE SSANGSIOS YAE HIEUH + 0x9B9B: 0xC36A, //HANGUL SYLLABLE SSANGSIOS EO SSANGKIYEOK + 0x9B9C: 0xC36B, //HANGUL SYLLABLE SSANGSIOS EO KIYEOKSIOS + 0x9B9D: 0xC36D, //HANGUL SYLLABLE SSANGSIOS EO NIEUNCIEUC + 0x9B9E: 0xC36E, //HANGUL SYLLABLE SSANGSIOS EO NIEUNHIEUH + 0x9B9F: 0xC36F, //HANGUL SYLLABLE SSANGSIOS EO TIKEUT + 0x9BA0: 0xC371, //HANGUL SYLLABLE SSANGSIOS EO RIEULKIYEOK + 0x9BA1: 0xC373, //HANGUL SYLLABLE SSANGSIOS EO RIEULPIEUP + 0x9BA2: 0xC374, //HANGUL SYLLABLE SSANGSIOS EO RIEULSIOS + 0x9BA3: 0xC375, //HANGUL SYLLABLE SSANGSIOS EO RIEULTHIEUTH + 0x9BA4: 0xC376, //HANGUL SYLLABLE SSANGSIOS EO RIEULPHIEUPH + 0x9BA5: 0xC377, //HANGUL SYLLABLE SSANGSIOS EO RIEULHIEUH + 0x9BA6: 0xC37A, //HANGUL SYLLABLE SSANGSIOS EO PIEUPSIOS + 0x9BA7: 0xC37B, //HANGUL SYLLABLE SSANGSIOS EO SIOS + 0x9BA8: 0xC37E, //HANGUL SYLLABLE SSANGSIOS EO CIEUC + 0x9BA9: 0xC37F, //HANGUL SYLLABLE SSANGSIOS EO CHIEUCH + 0x9BAA: 0xC380, //HANGUL SYLLABLE SSANGSIOS EO KHIEUKH + 0x9BAB: 0xC381, //HANGUL SYLLABLE SSANGSIOS EO THIEUTH + 0x9BAC: 0xC382, //HANGUL SYLLABLE SSANGSIOS EO PHIEUPH + 0x9BAD: 0xC383, //HANGUL SYLLABLE SSANGSIOS EO HIEUH + 0x9BAE: 0xC385, //HANGUL SYLLABLE SSANGSIOS E KIYEOK + 0x9BAF: 0xC386, //HANGUL SYLLABLE SSANGSIOS E SSANGKIYEOK + 0x9BB0: 0xC387, //HANGUL SYLLABLE SSANGSIOS E KIYEOKSIOS + 0x9BB1: 0xC389, //HANGUL SYLLABLE SSANGSIOS E NIEUNCIEUC + 0x9BB2: 0xC38A, //HANGUL SYLLABLE SSANGSIOS E NIEUNHIEUH + 0x9BB3: 0xC38B, //HANGUL SYLLABLE SSANGSIOS E TIKEUT + 0x9BB4: 0xC38D, //HANGUL SYLLABLE SSANGSIOS E RIEULKIYEOK + 0x9BB5: 0xC38E, //HANGUL SYLLABLE SSANGSIOS E RIEULMIEUM + 0x9BB6: 0xC38F, //HANGUL SYLLABLE SSANGSIOS E RIEULPIEUP + 0x9BB7: 0xC390, //HANGUL SYLLABLE SSANGSIOS E RIEULSIOS + 0x9BB8: 0xC391, //HANGUL SYLLABLE SSANGSIOS E RIEULTHIEUTH + 0x9BB9: 0xC392, //HANGUL SYLLABLE SSANGSIOS E RIEULPHIEUPH + 0x9BBA: 0xC393, //HANGUL SYLLABLE SSANGSIOS E RIEULHIEUH + 0x9BBB: 0xC394, //HANGUL SYLLABLE SSANGSIOS E MIEUM + 0x9BBC: 0xC395, //HANGUL SYLLABLE SSANGSIOS E PIEUP + 0x9BBD: 0xC396, //HANGUL SYLLABLE SSANGSIOS E PIEUPSIOS + 0x9BBE: 0xC397, //HANGUL SYLLABLE SSANGSIOS E SIOS + 0x9BBF: 0xC398, //HANGUL SYLLABLE SSANGSIOS E SSANGSIOS + 0x9BC0: 0xC399, //HANGUL SYLLABLE SSANGSIOS E IEUNG + 0x9BC1: 0xC39A, //HANGUL SYLLABLE SSANGSIOS E CIEUC + 0x9BC2: 0xC39B, //HANGUL SYLLABLE SSANGSIOS E CHIEUCH + 0x9BC3: 0xC39C, //HANGUL SYLLABLE SSANGSIOS E KHIEUKH + 0x9BC4: 0xC39D, //HANGUL SYLLABLE SSANGSIOS E THIEUTH + 0x9BC5: 0xC39E, //HANGUL SYLLABLE SSANGSIOS E PHIEUPH + 0x9BC6: 0xC39F, //HANGUL SYLLABLE SSANGSIOS E HIEUH + 0x9BC7: 0xC3A0, //HANGUL SYLLABLE SSANGSIOS YEO + 0x9BC8: 0xC3A1, //HANGUL SYLLABLE SSANGSIOS YEO KIYEOK + 0x9BC9: 0xC3A2, //HANGUL SYLLABLE SSANGSIOS YEO SSANGKIYEOK + 0x9BCA: 0xC3A3, //HANGUL SYLLABLE SSANGSIOS YEO KIYEOKSIOS + 0x9BCB: 0xC3A4, //HANGUL SYLLABLE SSANGSIOS YEO NIEUN + 0x9BCC: 0xC3A5, //HANGUL SYLLABLE SSANGSIOS YEO NIEUNCIEUC + 0x9BCD: 0xC3A6, //HANGUL SYLLABLE SSANGSIOS YEO NIEUNHIEUH + 0x9BCE: 0xC3A7, //HANGUL SYLLABLE SSANGSIOS YEO TIKEUT + 0x9BCF: 0xC3A8, //HANGUL SYLLABLE SSANGSIOS YEO RIEUL + 0x9BD0: 0xC3A9, //HANGUL SYLLABLE SSANGSIOS YEO RIEULKIYEOK + 0x9BD1: 0xC3AA, //HANGUL SYLLABLE SSANGSIOS YEO RIEULMIEUM + 0x9BD2: 0xC3AB, //HANGUL SYLLABLE SSANGSIOS YEO RIEULPIEUP + 0x9BD3: 0xC3AC, //HANGUL SYLLABLE SSANGSIOS YEO RIEULSIOS + 0x9BD4: 0xC3AD, //HANGUL SYLLABLE SSANGSIOS YEO RIEULTHIEUTH + 0x9BD5: 0xC3AE, //HANGUL SYLLABLE SSANGSIOS YEO RIEULPHIEUPH + 0x9BD6: 0xC3AF, //HANGUL SYLLABLE SSANGSIOS YEO RIEULHIEUH + 0x9BD7: 0xC3B0, //HANGUL SYLLABLE SSANGSIOS YEO MIEUM + 0x9BD8: 0xC3B1, //HANGUL SYLLABLE SSANGSIOS YEO PIEUP + 0x9BD9: 0xC3B2, //HANGUL SYLLABLE SSANGSIOS YEO PIEUPSIOS + 0x9BDA: 0xC3B3, //HANGUL SYLLABLE SSANGSIOS YEO SIOS + 0x9BDB: 0xC3B4, //HANGUL SYLLABLE SSANGSIOS YEO SSANGSIOS + 0x9BDC: 0xC3B5, //HANGUL SYLLABLE SSANGSIOS YEO IEUNG + 0x9BDD: 0xC3B6, //HANGUL SYLLABLE SSANGSIOS YEO CIEUC + 0x9BDE: 0xC3B7, //HANGUL SYLLABLE SSANGSIOS YEO CHIEUCH + 0x9BDF: 0xC3B8, //HANGUL SYLLABLE SSANGSIOS YEO KHIEUKH + 0x9BE0: 0xC3B9, //HANGUL SYLLABLE SSANGSIOS YEO THIEUTH + 0x9BE1: 0xC3BA, //HANGUL SYLLABLE SSANGSIOS YEO PHIEUPH + 0x9BE2: 0xC3BB, //HANGUL SYLLABLE SSANGSIOS YEO HIEUH + 0x9BE3: 0xC3BC, //HANGUL SYLLABLE SSANGSIOS YE + 0x9BE4: 0xC3BD, //HANGUL SYLLABLE SSANGSIOS YE KIYEOK + 0x9BE5: 0xC3BE, //HANGUL SYLLABLE SSANGSIOS YE SSANGKIYEOK + 0x9BE6: 0xC3BF, //HANGUL SYLLABLE SSANGSIOS YE KIYEOKSIOS + 0x9BE7: 0xC3C1, //HANGUL SYLLABLE SSANGSIOS YE NIEUNCIEUC + 0x9BE8: 0xC3C2, //HANGUL SYLLABLE SSANGSIOS YE NIEUNHIEUH + 0x9BE9: 0xC3C3, //HANGUL SYLLABLE SSANGSIOS YE TIKEUT + 0x9BEA: 0xC3C4, //HANGUL SYLLABLE SSANGSIOS YE RIEUL + 0x9BEB: 0xC3C5, //HANGUL SYLLABLE SSANGSIOS YE RIEULKIYEOK + 0x9BEC: 0xC3C6, //HANGUL SYLLABLE SSANGSIOS YE RIEULMIEUM + 0x9BED: 0xC3C7, //HANGUL SYLLABLE SSANGSIOS YE RIEULPIEUP + 0x9BEE: 0xC3C8, //HANGUL SYLLABLE SSANGSIOS YE RIEULSIOS + 0x9BEF: 0xC3C9, //HANGUL SYLLABLE SSANGSIOS YE RIEULTHIEUTH + 0x9BF0: 0xC3CA, //HANGUL SYLLABLE SSANGSIOS YE RIEULPHIEUPH + 0x9BF1: 0xC3CB, //HANGUL SYLLABLE SSANGSIOS YE RIEULHIEUH + 0x9BF2: 0xC3CC, //HANGUL SYLLABLE SSANGSIOS YE MIEUM + 0x9BF3: 0xC3CD, //HANGUL SYLLABLE SSANGSIOS YE PIEUP + 0x9BF4: 0xC3CE, //HANGUL SYLLABLE SSANGSIOS YE PIEUPSIOS + 0x9BF5: 0xC3CF, //HANGUL SYLLABLE SSANGSIOS YE SIOS + 0x9BF6: 0xC3D0, //HANGUL SYLLABLE SSANGSIOS YE SSANGSIOS + 0x9BF7: 0xC3D1, //HANGUL SYLLABLE SSANGSIOS YE IEUNG + 0x9BF8: 0xC3D2, //HANGUL SYLLABLE SSANGSIOS YE CIEUC + 0x9BF9: 0xC3D3, //HANGUL SYLLABLE SSANGSIOS YE CHIEUCH + 0x9BFA: 0xC3D4, //HANGUL SYLLABLE SSANGSIOS YE KHIEUKH + 0x9BFB: 0xC3D5, //HANGUL SYLLABLE SSANGSIOS YE THIEUTH + 0x9BFC: 0xC3D6, //HANGUL SYLLABLE SSANGSIOS YE PHIEUPH + 0x9BFD: 0xC3D7, //HANGUL SYLLABLE SSANGSIOS YE HIEUH + 0x9BFE: 0xC3DA, //HANGUL SYLLABLE SSANGSIOS O SSANGKIYEOK + 0x9C41: 0xC3DB, //HANGUL SYLLABLE SSANGSIOS O KIYEOKSIOS + 0x9C42: 0xC3DD, //HANGUL SYLLABLE SSANGSIOS O NIEUNCIEUC + 0x9C43: 0xC3DE, //HANGUL SYLLABLE SSANGSIOS O NIEUNHIEUH + 0x9C44: 0xC3E1, //HANGUL SYLLABLE SSANGSIOS O RIEULKIYEOK + 0x9C45: 0xC3E3, //HANGUL SYLLABLE SSANGSIOS O RIEULPIEUP + 0x9C46: 0xC3E4, //HANGUL SYLLABLE SSANGSIOS O RIEULSIOS + 0x9C47: 0xC3E5, //HANGUL SYLLABLE SSANGSIOS O RIEULTHIEUTH + 0x9C48: 0xC3E6, //HANGUL SYLLABLE SSANGSIOS O RIEULPHIEUPH + 0x9C49: 0xC3E7, //HANGUL SYLLABLE SSANGSIOS O RIEULHIEUH + 0x9C4A: 0xC3EA, //HANGUL SYLLABLE SSANGSIOS O PIEUPSIOS + 0x9C4B: 0xC3EB, //HANGUL SYLLABLE SSANGSIOS O SIOS + 0x9C4C: 0xC3EC, //HANGUL SYLLABLE SSANGSIOS O SSANGSIOS + 0x9C4D: 0xC3EE, //HANGUL SYLLABLE SSANGSIOS O CIEUC + 0x9C4E: 0xC3EF, //HANGUL SYLLABLE SSANGSIOS O CHIEUCH + 0x9C4F: 0xC3F0, //HANGUL SYLLABLE SSANGSIOS O KHIEUKH + 0x9C50: 0xC3F1, //HANGUL SYLLABLE SSANGSIOS O THIEUTH + 0x9C51: 0xC3F2, //HANGUL SYLLABLE SSANGSIOS O PHIEUPH + 0x9C52: 0xC3F3, //HANGUL SYLLABLE SSANGSIOS O HIEUH + 0x9C53: 0xC3F6, //HANGUL SYLLABLE SSANGSIOS WA SSANGKIYEOK + 0x9C54: 0xC3F7, //HANGUL SYLLABLE SSANGSIOS WA KIYEOKSIOS + 0x9C55: 0xC3F9, //HANGUL SYLLABLE SSANGSIOS WA NIEUNCIEUC + 0x9C56: 0xC3FA, //HANGUL SYLLABLE SSANGSIOS WA NIEUNHIEUH + 0x9C57: 0xC3FB, //HANGUL SYLLABLE SSANGSIOS WA TIKEUT + 0x9C58: 0xC3FC, //HANGUL SYLLABLE SSANGSIOS WA RIEUL + 0x9C59: 0xC3FD, //HANGUL SYLLABLE SSANGSIOS WA RIEULKIYEOK + 0x9C5A: 0xC3FE, //HANGUL SYLLABLE SSANGSIOS WA RIEULMIEUM + 0x9C61: 0xC3FF, //HANGUL SYLLABLE SSANGSIOS WA RIEULPIEUP + 0x9C62: 0xC400, //HANGUL SYLLABLE SSANGSIOS WA RIEULSIOS + 0x9C63: 0xC401, //HANGUL SYLLABLE SSANGSIOS WA RIEULTHIEUTH + 0x9C64: 0xC402, //HANGUL SYLLABLE SSANGSIOS WA RIEULPHIEUPH + 0x9C65: 0xC403, //HANGUL SYLLABLE SSANGSIOS WA RIEULHIEUH + 0x9C66: 0xC404, //HANGUL SYLLABLE SSANGSIOS WA MIEUM + 0x9C67: 0xC405, //HANGUL SYLLABLE SSANGSIOS WA PIEUP + 0x9C68: 0xC406, //HANGUL SYLLABLE SSANGSIOS WA PIEUPSIOS + 0x9C69: 0xC407, //HANGUL SYLLABLE SSANGSIOS WA SIOS + 0x9C6A: 0xC409, //HANGUL SYLLABLE SSANGSIOS WA IEUNG + 0x9C6B: 0xC40A, //HANGUL SYLLABLE SSANGSIOS WA CIEUC + 0x9C6C: 0xC40B, //HANGUL SYLLABLE SSANGSIOS WA CHIEUCH + 0x9C6D: 0xC40C, //HANGUL SYLLABLE SSANGSIOS WA KHIEUKH + 0x9C6E: 0xC40D, //HANGUL SYLLABLE SSANGSIOS WA THIEUTH + 0x9C6F: 0xC40E, //HANGUL SYLLABLE SSANGSIOS WA PHIEUPH + 0x9C70: 0xC40F, //HANGUL SYLLABLE SSANGSIOS WA HIEUH + 0x9C71: 0xC411, //HANGUL SYLLABLE SSANGSIOS WAE KIYEOK + 0x9C72: 0xC412, //HANGUL SYLLABLE SSANGSIOS WAE SSANGKIYEOK + 0x9C73: 0xC413, //HANGUL SYLLABLE SSANGSIOS WAE KIYEOKSIOS + 0x9C74: 0xC414, //HANGUL SYLLABLE SSANGSIOS WAE NIEUN + 0x9C75: 0xC415, //HANGUL SYLLABLE SSANGSIOS WAE NIEUNCIEUC + 0x9C76: 0xC416, //HANGUL SYLLABLE SSANGSIOS WAE NIEUNHIEUH + 0x9C77: 0xC417, //HANGUL SYLLABLE SSANGSIOS WAE TIKEUT + 0x9C78: 0xC418, //HANGUL SYLLABLE SSANGSIOS WAE RIEUL + 0x9C79: 0xC419, //HANGUL SYLLABLE SSANGSIOS WAE RIEULKIYEOK + 0x9C7A: 0xC41A, //HANGUL SYLLABLE SSANGSIOS WAE RIEULMIEUM + 0x9C81: 0xC41B, //HANGUL SYLLABLE SSANGSIOS WAE RIEULPIEUP + 0x9C82: 0xC41C, //HANGUL SYLLABLE SSANGSIOS WAE RIEULSIOS + 0x9C83: 0xC41D, //HANGUL SYLLABLE SSANGSIOS WAE RIEULTHIEUTH + 0x9C84: 0xC41E, //HANGUL SYLLABLE SSANGSIOS WAE RIEULPHIEUPH + 0x9C85: 0xC41F, //HANGUL SYLLABLE SSANGSIOS WAE RIEULHIEUH + 0x9C86: 0xC420, //HANGUL SYLLABLE SSANGSIOS WAE MIEUM + 0x9C87: 0xC421, //HANGUL SYLLABLE SSANGSIOS WAE PIEUP + 0x9C88: 0xC422, //HANGUL SYLLABLE SSANGSIOS WAE PIEUPSIOS + 0x9C89: 0xC423, //HANGUL SYLLABLE SSANGSIOS WAE SIOS + 0x9C8A: 0xC425, //HANGUL SYLLABLE SSANGSIOS WAE IEUNG + 0x9C8B: 0xC426, //HANGUL SYLLABLE SSANGSIOS WAE CIEUC + 0x9C8C: 0xC427, //HANGUL SYLLABLE SSANGSIOS WAE CHIEUCH + 0x9C8D: 0xC428, //HANGUL SYLLABLE SSANGSIOS WAE KHIEUKH + 0x9C8E: 0xC429, //HANGUL SYLLABLE SSANGSIOS WAE THIEUTH + 0x9C8F: 0xC42A, //HANGUL SYLLABLE SSANGSIOS WAE PHIEUPH + 0x9C90: 0xC42B, //HANGUL SYLLABLE SSANGSIOS WAE HIEUH + 0x9C91: 0xC42D, //HANGUL SYLLABLE SSANGSIOS OE KIYEOK + 0x9C92: 0xC42E, //HANGUL SYLLABLE SSANGSIOS OE SSANGKIYEOK + 0x9C93: 0xC42F, //HANGUL SYLLABLE SSANGSIOS OE KIYEOKSIOS + 0x9C94: 0xC431, //HANGUL SYLLABLE SSANGSIOS OE NIEUNCIEUC + 0x9C95: 0xC432, //HANGUL SYLLABLE SSANGSIOS OE NIEUNHIEUH + 0x9C96: 0xC433, //HANGUL SYLLABLE SSANGSIOS OE TIKEUT + 0x9C97: 0xC435, //HANGUL SYLLABLE SSANGSIOS OE RIEULKIYEOK + 0x9C98: 0xC436, //HANGUL SYLLABLE SSANGSIOS OE RIEULMIEUM + 0x9C99: 0xC437, //HANGUL SYLLABLE SSANGSIOS OE RIEULPIEUP + 0x9C9A: 0xC438, //HANGUL SYLLABLE SSANGSIOS OE RIEULSIOS + 0x9C9B: 0xC439, //HANGUL SYLLABLE SSANGSIOS OE RIEULTHIEUTH + 0x9C9C: 0xC43A, //HANGUL SYLLABLE SSANGSIOS OE RIEULPHIEUPH + 0x9C9D: 0xC43B, //HANGUL SYLLABLE SSANGSIOS OE RIEULHIEUH + 0x9C9E: 0xC43E, //HANGUL SYLLABLE SSANGSIOS OE PIEUPSIOS + 0x9C9F: 0xC43F, //HANGUL SYLLABLE SSANGSIOS OE SIOS + 0x9CA0: 0xC440, //HANGUL SYLLABLE SSANGSIOS OE SSANGSIOS + 0x9CA1: 0xC441, //HANGUL SYLLABLE SSANGSIOS OE IEUNG + 0x9CA2: 0xC442, //HANGUL SYLLABLE SSANGSIOS OE CIEUC + 0x9CA3: 0xC443, //HANGUL SYLLABLE SSANGSIOS OE CHIEUCH + 0x9CA4: 0xC444, //HANGUL SYLLABLE SSANGSIOS OE KHIEUKH + 0x9CA5: 0xC445, //HANGUL SYLLABLE SSANGSIOS OE THIEUTH + 0x9CA6: 0xC446, //HANGUL SYLLABLE SSANGSIOS OE PHIEUPH + 0x9CA7: 0xC447, //HANGUL SYLLABLE SSANGSIOS OE HIEUH + 0x9CA8: 0xC449, //HANGUL SYLLABLE SSANGSIOS YO KIYEOK + 0x9CA9: 0xC44A, //HANGUL SYLLABLE SSANGSIOS YO SSANGKIYEOK + 0x9CAA: 0xC44B, //HANGUL SYLLABLE SSANGSIOS YO KIYEOKSIOS + 0x9CAB: 0xC44C, //HANGUL SYLLABLE SSANGSIOS YO NIEUN + 0x9CAC: 0xC44D, //HANGUL SYLLABLE SSANGSIOS YO NIEUNCIEUC + 0x9CAD: 0xC44E, //HANGUL SYLLABLE SSANGSIOS YO NIEUNHIEUH + 0x9CAE: 0xC44F, //HANGUL SYLLABLE SSANGSIOS YO TIKEUT + 0x9CAF: 0xC450, //HANGUL SYLLABLE SSANGSIOS YO RIEUL + 0x9CB0: 0xC451, //HANGUL SYLLABLE SSANGSIOS YO RIEULKIYEOK + 0x9CB1: 0xC452, //HANGUL SYLLABLE SSANGSIOS YO RIEULMIEUM + 0x9CB2: 0xC453, //HANGUL SYLLABLE SSANGSIOS YO RIEULPIEUP + 0x9CB3: 0xC454, //HANGUL SYLLABLE SSANGSIOS YO RIEULSIOS + 0x9CB4: 0xC455, //HANGUL SYLLABLE SSANGSIOS YO RIEULTHIEUTH + 0x9CB5: 0xC456, //HANGUL SYLLABLE SSANGSIOS YO RIEULPHIEUPH + 0x9CB6: 0xC457, //HANGUL SYLLABLE SSANGSIOS YO RIEULHIEUH + 0x9CB7: 0xC458, //HANGUL SYLLABLE SSANGSIOS YO MIEUM + 0x9CB8: 0xC459, //HANGUL SYLLABLE SSANGSIOS YO PIEUP + 0x9CB9: 0xC45A, //HANGUL SYLLABLE SSANGSIOS YO PIEUPSIOS + 0x9CBA: 0xC45B, //HANGUL SYLLABLE SSANGSIOS YO SIOS + 0x9CBB: 0xC45C, //HANGUL SYLLABLE SSANGSIOS YO SSANGSIOS + 0x9CBC: 0xC45D, //HANGUL SYLLABLE SSANGSIOS YO IEUNG + 0x9CBD: 0xC45E, //HANGUL SYLLABLE SSANGSIOS YO CIEUC + 0x9CBE: 0xC45F, //HANGUL SYLLABLE SSANGSIOS YO CHIEUCH + 0x9CBF: 0xC460, //HANGUL SYLLABLE SSANGSIOS YO KHIEUKH + 0x9CC0: 0xC461, //HANGUL SYLLABLE SSANGSIOS YO THIEUTH + 0x9CC1: 0xC462, //HANGUL SYLLABLE SSANGSIOS YO PHIEUPH + 0x9CC2: 0xC463, //HANGUL SYLLABLE SSANGSIOS YO HIEUH + 0x9CC3: 0xC466, //HANGUL SYLLABLE SSANGSIOS U SSANGKIYEOK + 0x9CC4: 0xC467, //HANGUL SYLLABLE SSANGSIOS U KIYEOKSIOS + 0x9CC5: 0xC469, //HANGUL SYLLABLE SSANGSIOS U NIEUNCIEUC + 0x9CC6: 0xC46A, //HANGUL SYLLABLE SSANGSIOS U NIEUNHIEUH + 0x9CC7: 0xC46B, //HANGUL SYLLABLE SSANGSIOS U TIKEUT + 0x9CC8: 0xC46D, //HANGUL SYLLABLE SSANGSIOS U RIEULKIYEOK + 0x9CC9: 0xC46E, //HANGUL SYLLABLE SSANGSIOS U RIEULMIEUM + 0x9CCA: 0xC46F, //HANGUL SYLLABLE SSANGSIOS U RIEULPIEUP + 0x9CCB: 0xC470, //HANGUL SYLLABLE SSANGSIOS U RIEULSIOS + 0x9CCC: 0xC471, //HANGUL SYLLABLE SSANGSIOS U RIEULTHIEUTH + 0x9CCD: 0xC472, //HANGUL SYLLABLE SSANGSIOS U RIEULPHIEUPH + 0x9CCE: 0xC473, //HANGUL SYLLABLE SSANGSIOS U RIEULHIEUH + 0x9CCF: 0xC476, //HANGUL SYLLABLE SSANGSIOS U PIEUPSIOS + 0x9CD0: 0xC477, //HANGUL SYLLABLE SSANGSIOS U SIOS + 0x9CD1: 0xC478, //HANGUL SYLLABLE SSANGSIOS U SSANGSIOS + 0x9CD2: 0xC47A, //HANGUL SYLLABLE SSANGSIOS U CIEUC + 0x9CD3: 0xC47B, //HANGUL SYLLABLE SSANGSIOS U CHIEUCH + 0x9CD4: 0xC47C, //HANGUL SYLLABLE SSANGSIOS U KHIEUKH + 0x9CD5: 0xC47D, //HANGUL SYLLABLE SSANGSIOS U THIEUTH + 0x9CD6: 0xC47E, //HANGUL SYLLABLE SSANGSIOS U PHIEUPH + 0x9CD7: 0xC47F, //HANGUL SYLLABLE SSANGSIOS U HIEUH + 0x9CD8: 0xC481, //HANGUL SYLLABLE SSANGSIOS WEO KIYEOK + 0x9CD9: 0xC482, //HANGUL SYLLABLE SSANGSIOS WEO SSANGKIYEOK + 0x9CDA: 0xC483, //HANGUL SYLLABLE SSANGSIOS WEO KIYEOKSIOS + 0x9CDB: 0xC484, //HANGUL SYLLABLE SSANGSIOS WEO NIEUN + 0x9CDC: 0xC485, //HANGUL SYLLABLE SSANGSIOS WEO NIEUNCIEUC + 0x9CDD: 0xC486, //HANGUL SYLLABLE SSANGSIOS WEO NIEUNHIEUH + 0x9CDE: 0xC487, //HANGUL SYLLABLE SSANGSIOS WEO TIKEUT + 0x9CDF: 0xC488, //HANGUL SYLLABLE SSANGSIOS WEO RIEUL + 0x9CE0: 0xC489, //HANGUL SYLLABLE SSANGSIOS WEO RIEULKIYEOK + 0x9CE1: 0xC48A, //HANGUL SYLLABLE SSANGSIOS WEO RIEULMIEUM + 0x9CE2: 0xC48B, //HANGUL SYLLABLE SSANGSIOS WEO RIEULPIEUP + 0x9CE3: 0xC48C, //HANGUL SYLLABLE SSANGSIOS WEO RIEULSIOS + 0x9CE4: 0xC48D, //HANGUL SYLLABLE SSANGSIOS WEO RIEULTHIEUTH + 0x9CE5: 0xC48E, //HANGUL SYLLABLE SSANGSIOS WEO RIEULPHIEUPH + 0x9CE6: 0xC48F, //HANGUL SYLLABLE SSANGSIOS WEO RIEULHIEUH + 0x9CE7: 0xC490, //HANGUL SYLLABLE SSANGSIOS WEO MIEUM + 0x9CE8: 0xC491, //HANGUL SYLLABLE SSANGSIOS WEO PIEUP + 0x9CE9: 0xC492, //HANGUL SYLLABLE SSANGSIOS WEO PIEUPSIOS + 0x9CEA: 0xC493, //HANGUL SYLLABLE SSANGSIOS WEO SIOS + 0x9CEB: 0xC495, //HANGUL SYLLABLE SSANGSIOS WEO IEUNG + 0x9CEC: 0xC496, //HANGUL SYLLABLE SSANGSIOS WEO CIEUC + 0x9CED: 0xC497, //HANGUL SYLLABLE SSANGSIOS WEO CHIEUCH + 0x9CEE: 0xC498, //HANGUL SYLLABLE SSANGSIOS WEO KHIEUKH + 0x9CEF: 0xC499, //HANGUL SYLLABLE SSANGSIOS WEO THIEUTH + 0x9CF0: 0xC49A, //HANGUL SYLLABLE SSANGSIOS WEO PHIEUPH + 0x9CF1: 0xC49B, //HANGUL SYLLABLE SSANGSIOS WEO HIEUH + 0x9CF2: 0xC49D, //HANGUL SYLLABLE SSANGSIOS WE KIYEOK + 0x9CF3: 0xC49E, //HANGUL SYLLABLE SSANGSIOS WE SSANGKIYEOK + 0x9CF4: 0xC49F, //HANGUL SYLLABLE SSANGSIOS WE KIYEOKSIOS + 0x9CF5: 0xC4A0, //HANGUL SYLLABLE SSANGSIOS WE NIEUN + 0x9CF6: 0xC4A1, //HANGUL SYLLABLE SSANGSIOS WE NIEUNCIEUC + 0x9CF7: 0xC4A2, //HANGUL SYLLABLE SSANGSIOS WE NIEUNHIEUH + 0x9CF8: 0xC4A3, //HANGUL SYLLABLE SSANGSIOS WE TIKEUT + 0x9CF9: 0xC4A4, //HANGUL SYLLABLE SSANGSIOS WE RIEUL + 0x9CFA: 0xC4A5, //HANGUL SYLLABLE SSANGSIOS WE RIEULKIYEOK + 0x9CFB: 0xC4A6, //HANGUL SYLLABLE SSANGSIOS WE RIEULMIEUM + 0x9CFC: 0xC4A7, //HANGUL SYLLABLE SSANGSIOS WE RIEULPIEUP + 0x9CFD: 0xC4A8, //HANGUL SYLLABLE SSANGSIOS WE RIEULSIOS + 0x9CFE: 0xC4A9, //HANGUL SYLLABLE SSANGSIOS WE RIEULTHIEUTH + 0x9D41: 0xC4AA, //HANGUL SYLLABLE SSANGSIOS WE RIEULPHIEUPH + 0x9D42: 0xC4AB, //HANGUL SYLLABLE SSANGSIOS WE RIEULHIEUH + 0x9D43: 0xC4AC, //HANGUL SYLLABLE SSANGSIOS WE MIEUM + 0x9D44: 0xC4AD, //HANGUL SYLLABLE SSANGSIOS WE PIEUP + 0x9D45: 0xC4AE, //HANGUL SYLLABLE SSANGSIOS WE PIEUPSIOS + 0x9D46: 0xC4AF, //HANGUL SYLLABLE SSANGSIOS WE SIOS + 0x9D47: 0xC4B0, //HANGUL SYLLABLE SSANGSIOS WE SSANGSIOS + 0x9D48: 0xC4B1, //HANGUL SYLLABLE SSANGSIOS WE IEUNG + 0x9D49: 0xC4B2, //HANGUL SYLLABLE SSANGSIOS WE CIEUC + 0x9D4A: 0xC4B3, //HANGUL SYLLABLE SSANGSIOS WE CHIEUCH + 0x9D4B: 0xC4B4, //HANGUL SYLLABLE SSANGSIOS WE KHIEUKH + 0x9D4C: 0xC4B5, //HANGUL SYLLABLE SSANGSIOS WE THIEUTH + 0x9D4D: 0xC4B6, //HANGUL SYLLABLE SSANGSIOS WE PHIEUPH + 0x9D4E: 0xC4B7, //HANGUL SYLLABLE SSANGSIOS WE HIEUH + 0x9D4F: 0xC4B9, //HANGUL SYLLABLE SSANGSIOS WI KIYEOK + 0x9D50: 0xC4BA, //HANGUL SYLLABLE SSANGSIOS WI SSANGKIYEOK + 0x9D51: 0xC4BB, //HANGUL SYLLABLE SSANGSIOS WI KIYEOKSIOS + 0x9D52: 0xC4BD, //HANGUL SYLLABLE SSANGSIOS WI NIEUNCIEUC + 0x9D53: 0xC4BE, //HANGUL SYLLABLE SSANGSIOS WI NIEUNHIEUH + 0x9D54: 0xC4BF, //HANGUL SYLLABLE SSANGSIOS WI TIKEUT + 0x9D55: 0xC4C0, //HANGUL SYLLABLE SSANGSIOS WI RIEUL + 0x9D56: 0xC4C1, //HANGUL SYLLABLE SSANGSIOS WI RIEULKIYEOK + 0x9D57: 0xC4C2, //HANGUL SYLLABLE SSANGSIOS WI RIEULMIEUM + 0x9D58: 0xC4C3, //HANGUL SYLLABLE SSANGSIOS WI RIEULPIEUP + 0x9D59: 0xC4C4, //HANGUL SYLLABLE SSANGSIOS WI RIEULSIOS + 0x9D5A: 0xC4C5, //HANGUL SYLLABLE SSANGSIOS WI RIEULTHIEUTH + 0x9D61: 0xC4C6, //HANGUL SYLLABLE SSANGSIOS WI RIEULPHIEUPH + 0x9D62: 0xC4C7, //HANGUL SYLLABLE SSANGSIOS WI RIEULHIEUH + 0x9D63: 0xC4C8, //HANGUL SYLLABLE SSANGSIOS WI MIEUM + 0x9D64: 0xC4C9, //HANGUL SYLLABLE SSANGSIOS WI PIEUP + 0x9D65: 0xC4CA, //HANGUL SYLLABLE SSANGSIOS WI PIEUPSIOS + 0x9D66: 0xC4CB, //HANGUL SYLLABLE SSANGSIOS WI SIOS + 0x9D67: 0xC4CC, //HANGUL SYLLABLE SSANGSIOS WI SSANGSIOS + 0x9D68: 0xC4CD, //HANGUL SYLLABLE SSANGSIOS WI IEUNG + 0x9D69: 0xC4CE, //HANGUL SYLLABLE SSANGSIOS WI CIEUC + 0x9D6A: 0xC4CF, //HANGUL SYLLABLE SSANGSIOS WI CHIEUCH + 0x9D6B: 0xC4D0, //HANGUL SYLLABLE SSANGSIOS WI KHIEUKH + 0x9D6C: 0xC4D1, //HANGUL SYLLABLE SSANGSIOS WI THIEUTH + 0x9D6D: 0xC4D2, //HANGUL SYLLABLE SSANGSIOS WI PHIEUPH + 0x9D6E: 0xC4D3, //HANGUL SYLLABLE SSANGSIOS WI HIEUH + 0x9D6F: 0xC4D4, //HANGUL SYLLABLE SSANGSIOS YU + 0x9D70: 0xC4D5, //HANGUL SYLLABLE SSANGSIOS YU KIYEOK + 0x9D71: 0xC4D6, //HANGUL SYLLABLE SSANGSIOS YU SSANGKIYEOK + 0x9D72: 0xC4D7, //HANGUL SYLLABLE SSANGSIOS YU KIYEOKSIOS + 0x9D73: 0xC4D8, //HANGUL SYLLABLE SSANGSIOS YU NIEUN + 0x9D74: 0xC4D9, //HANGUL SYLLABLE SSANGSIOS YU NIEUNCIEUC + 0x9D75: 0xC4DA, //HANGUL SYLLABLE SSANGSIOS YU NIEUNHIEUH + 0x9D76: 0xC4DB, //HANGUL SYLLABLE SSANGSIOS YU TIKEUT + 0x9D77: 0xC4DC, //HANGUL SYLLABLE SSANGSIOS YU RIEUL + 0x9D78: 0xC4DD, //HANGUL SYLLABLE SSANGSIOS YU RIEULKIYEOK + 0x9D79: 0xC4DE, //HANGUL SYLLABLE SSANGSIOS YU RIEULMIEUM + 0x9D7A: 0xC4DF, //HANGUL SYLLABLE SSANGSIOS YU RIEULPIEUP + 0x9D81: 0xC4E0, //HANGUL SYLLABLE SSANGSIOS YU RIEULSIOS + 0x9D82: 0xC4E1, //HANGUL SYLLABLE SSANGSIOS YU RIEULTHIEUTH + 0x9D83: 0xC4E2, //HANGUL SYLLABLE SSANGSIOS YU RIEULPHIEUPH + 0x9D84: 0xC4E3, //HANGUL SYLLABLE SSANGSIOS YU RIEULHIEUH + 0x9D85: 0xC4E4, //HANGUL SYLLABLE SSANGSIOS YU MIEUM + 0x9D86: 0xC4E5, //HANGUL SYLLABLE SSANGSIOS YU PIEUP + 0x9D87: 0xC4E6, //HANGUL SYLLABLE SSANGSIOS YU PIEUPSIOS + 0x9D88: 0xC4E7, //HANGUL SYLLABLE SSANGSIOS YU SIOS + 0x9D89: 0xC4E8, //HANGUL SYLLABLE SSANGSIOS YU SSANGSIOS + 0x9D8A: 0xC4EA, //HANGUL SYLLABLE SSANGSIOS YU CIEUC + 0x9D8B: 0xC4EB, //HANGUL SYLLABLE SSANGSIOS YU CHIEUCH + 0x9D8C: 0xC4EC, //HANGUL SYLLABLE SSANGSIOS YU KHIEUKH + 0x9D8D: 0xC4ED, //HANGUL SYLLABLE SSANGSIOS YU THIEUTH + 0x9D8E: 0xC4EE, //HANGUL SYLLABLE SSANGSIOS YU PHIEUPH + 0x9D8F: 0xC4EF, //HANGUL SYLLABLE SSANGSIOS YU HIEUH + 0x9D90: 0xC4F2, //HANGUL SYLLABLE SSANGSIOS EU SSANGKIYEOK + 0x9D91: 0xC4F3, //HANGUL SYLLABLE SSANGSIOS EU KIYEOKSIOS + 0x9D92: 0xC4F5, //HANGUL SYLLABLE SSANGSIOS EU NIEUNCIEUC + 0x9D93: 0xC4F6, //HANGUL SYLLABLE SSANGSIOS EU NIEUNHIEUH + 0x9D94: 0xC4F7, //HANGUL SYLLABLE SSANGSIOS EU TIKEUT + 0x9D95: 0xC4F9, //HANGUL SYLLABLE SSANGSIOS EU RIEULKIYEOK + 0x9D96: 0xC4FB, //HANGUL SYLLABLE SSANGSIOS EU RIEULPIEUP + 0x9D97: 0xC4FC, //HANGUL SYLLABLE SSANGSIOS EU RIEULSIOS + 0x9D98: 0xC4FD, //HANGUL SYLLABLE SSANGSIOS EU RIEULTHIEUTH + 0x9D99: 0xC4FE, //HANGUL SYLLABLE SSANGSIOS EU RIEULPHIEUPH + 0x9D9A: 0xC502, //HANGUL SYLLABLE SSANGSIOS EU PIEUPSIOS + 0x9D9B: 0xC503, //HANGUL SYLLABLE SSANGSIOS EU SIOS + 0x9D9C: 0xC504, //HANGUL SYLLABLE SSANGSIOS EU SSANGSIOS + 0x9D9D: 0xC505, //HANGUL SYLLABLE SSANGSIOS EU IEUNG + 0x9D9E: 0xC506, //HANGUL SYLLABLE SSANGSIOS EU CIEUC + 0x9D9F: 0xC507, //HANGUL SYLLABLE SSANGSIOS EU CHIEUCH + 0x9DA0: 0xC508, //HANGUL SYLLABLE SSANGSIOS EU KHIEUKH + 0x9DA1: 0xC509, //HANGUL SYLLABLE SSANGSIOS EU THIEUTH + 0x9DA2: 0xC50A, //HANGUL SYLLABLE SSANGSIOS EU PHIEUPH + 0x9DA3: 0xC50B, //HANGUL SYLLABLE SSANGSIOS EU HIEUH + 0x9DA4: 0xC50D, //HANGUL SYLLABLE SSANGSIOS YI KIYEOK + 0x9DA5: 0xC50E, //HANGUL SYLLABLE SSANGSIOS YI SSANGKIYEOK + 0x9DA6: 0xC50F, //HANGUL SYLLABLE SSANGSIOS YI KIYEOKSIOS + 0x9DA7: 0xC511, //HANGUL SYLLABLE SSANGSIOS YI NIEUNCIEUC + 0x9DA8: 0xC512, //HANGUL SYLLABLE SSANGSIOS YI NIEUNHIEUH + 0x9DA9: 0xC513, //HANGUL SYLLABLE SSANGSIOS YI TIKEUT + 0x9DAA: 0xC515, //HANGUL SYLLABLE SSANGSIOS YI RIEULKIYEOK + 0x9DAB: 0xC516, //HANGUL SYLLABLE SSANGSIOS YI RIEULMIEUM + 0x9DAC: 0xC517, //HANGUL SYLLABLE SSANGSIOS YI RIEULPIEUP + 0x9DAD: 0xC518, //HANGUL SYLLABLE SSANGSIOS YI RIEULSIOS + 0x9DAE: 0xC519, //HANGUL SYLLABLE SSANGSIOS YI RIEULTHIEUTH + 0x9DAF: 0xC51A, //HANGUL SYLLABLE SSANGSIOS YI RIEULPHIEUPH + 0x9DB0: 0xC51B, //HANGUL SYLLABLE SSANGSIOS YI RIEULHIEUH + 0x9DB1: 0xC51D, //HANGUL SYLLABLE SSANGSIOS YI PIEUP + 0x9DB2: 0xC51E, //HANGUL SYLLABLE SSANGSIOS YI PIEUPSIOS + 0x9DB3: 0xC51F, //HANGUL SYLLABLE SSANGSIOS YI SIOS + 0x9DB4: 0xC520, //HANGUL SYLLABLE SSANGSIOS YI SSANGSIOS + 0x9DB5: 0xC521, //HANGUL SYLLABLE SSANGSIOS YI IEUNG + 0x9DB6: 0xC522, //HANGUL SYLLABLE SSANGSIOS YI CIEUC + 0x9DB7: 0xC523, //HANGUL SYLLABLE SSANGSIOS YI CHIEUCH + 0x9DB8: 0xC524, //HANGUL SYLLABLE SSANGSIOS YI KHIEUKH + 0x9DB9: 0xC525, //HANGUL SYLLABLE SSANGSIOS YI THIEUTH + 0x9DBA: 0xC526, //HANGUL SYLLABLE SSANGSIOS YI PHIEUPH + 0x9DBB: 0xC527, //HANGUL SYLLABLE SSANGSIOS YI HIEUH + 0x9DBC: 0xC52A, //HANGUL SYLLABLE SSANGSIOS I SSANGKIYEOK + 0x9DBD: 0xC52B, //HANGUL SYLLABLE SSANGSIOS I KIYEOKSIOS + 0x9DBE: 0xC52D, //HANGUL SYLLABLE SSANGSIOS I NIEUNCIEUC + 0x9DBF: 0xC52E, //HANGUL SYLLABLE SSANGSIOS I NIEUNHIEUH + 0x9DC0: 0xC52F, //HANGUL SYLLABLE SSANGSIOS I TIKEUT + 0x9DC1: 0xC531, //HANGUL SYLLABLE SSANGSIOS I RIEULKIYEOK + 0x9DC2: 0xC532, //HANGUL SYLLABLE SSANGSIOS I RIEULMIEUM + 0x9DC3: 0xC533, //HANGUL SYLLABLE SSANGSIOS I RIEULPIEUP + 0x9DC4: 0xC534, //HANGUL SYLLABLE SSANGSIOS I RIEULSIOS + 0x9DC5: 0xC535, //HANGUL SYLLABLE SSANGSIOS I RIEULTHIEUTH + 0x9DC6: 0xC536, //HANGUL SYLLABLE SSANGSIOS I RIEULPHIEUPH + 0x9DC7: 0xC537, //HANGUL SYLLABLE SSANGSIOS I RIEULHIEUH + 0x9DC8: 0xC53A, //HANGUL SYLLABLE SSANGSIOS I PIEUPSIOS + 0x9DC9: 0xC53C, //HANGUL SYLLABLE SSANGSIOS I SSANGSIOS + 0x9DCA: 0xC53E, //HANGUL SYLLABLE SSANGSIOS I CIEUC + 0x9DCB: 0xC53F, //HANGUL SYLLABLE SSANGSIOS I CHIEUCH + 0x9DCC: 0xC540, //HANGUL SYLLABLE SSANGSIOS I KHIEUKH + 0x9DCD: 0xC541, //HANGUL SYLLABLE SSANGSIOS I THIEUTH + 0x9DCE: 0xC542, //HANGUL SYLLABLE SSANGSIOS I PHIEUPH + 0x9DCF: 0xC543, //HANGUL SYLLABLE SSANGSIOS I HIEUH + 0x9DD0: 0xC546, //HANGUL SYLLABLE IEUNG A SSANGKIYEOK + 0x9DD1: 0xC547, //HANGUL SYLLABLE IEUNG A KIYEOKSIOS + 0x9DD2: 0xC54B, //HANGUL SYLLABLE IEUNG A TIKEUT + 0x9DD3: 0xC54F, //HANGUL SYLLABLE IEUNG A RIEULPIEUP + 0x9DD4: 0xC550, //HANGUL SYLLABLE IEUNG A RIEULSIOS + 0x9DD5: 0xC551, //HANGUL SYLLABLE IEUNG A RIEULTHIEUTH + 0x9DD6: 0xC552, //HANGUL SYLLABLE IEUNG A RIEULPHIEUPH + 0x9DD7: 0xC556, //HANGUL SYLLABLE IEUNG A PIEUPSIOS + 0x9DD8: 0xC55A, //HANGUL SYLLABLE IEUNG A CIEUC + 0x9DD9: 0xC55B, //HANGUL SYLLABLE IEUNG A CHIEUCH + 0x9DDA: 0xC55C, //HANGUL SYLLABLE IEUNG A KHIEUKH + 0x9DDB: 0xC55F, //HANGUL SYLLABLE IEUNG A HIEUH + 0x9DDC: 0xC562, //HANGUL SYLLABLE IEUNG AE SSANGKIYEOK + 0x9DDD: 0xC563, //HANGUL SYLLABLE IEUNG AE KIYEOKSIOS + 0x9DDE: 0xC565, //HANGUL SYLLABLE IEUNG AE NIEUNCIEUC + 0x9DDF: 0xC566, //HANGUL SYLLABLE IEUNG AE NIEUNHIEUH + 0x9DE0: 0xC567, //HANGUL SYLLABLE IEUNG AE TIKEUT + 0x9DE1: 0xC569, //HANGUL SYLLABLE IEUNG AE RIEULKIYEOK + 0x9DE2: 0xC56A, //HANGUL SYLLABLE IEUNG AE RIEULMIEUM + 0x9DE3: 0xC56B, //HANGUL SYLLABLE IEUNG AE RIEULPIEUP + 0x9DE4: 0xC56C, //HANGUL SYLLABLE IEUNG AE RIEULSIOS + 0x9DE5: 0xC56D, //HANGUL SYLLABLE IEUNG AE RIEULTHIEUTH + 0x9DE6: 0xC56E, //HANGUL SYLLABLE IEUNG AE RIEULPHIEUPH + 0x9DE7: 0xC56F, //HANGUL SYLLABLE IEUNG AE RIEULHIEUH + 0x9DE8: 0xC572, //HANGUL SYLLABLE IEUNG AE PIEUPSIOS + 0x9DE9: 0xC576, //HANGUL SYLLABLE IEUNG AE CIEUC + 0x9DEA: 0xC577, //HANGUL SYLLABLE IEUNG AE CHIEUCH + 0x9DEB: 0xC578, //HANGUL SYLLABLE IEUNG AE KHIEUKH + 0x9DEC: 0xC579, //HANGUL SYLLABLE IEUNG AE THIEUTH + 0x9DED: 0xC57A, //HANGUL SYLLABLE IEUNG AE PHIEUPH + 0x9DEE: 0xC57B, //HANGUL SYLLABLE IEUNG AE HIEUH + 0x9DEF: 0xC57E, //HANGUL SYLLABLE IEUNG YA SSANGKIYEOK + 0x9DF0: 0xC57F, //HANGUL SYLLABLE IEUNG YA KIYEOKSIOS + 0x9DF1: 0xC581, //HANGUL SYLLABLE IEUNG YA NIEUNCIEUC + 0x9DF2: 0xC582, //HANGUL SYLLABLE IEUNG YA NIEUNHIEUH + 0x9DF3: 0xC583, //HANGUL SYLLABLE IEUNG YA TIKEUT + 0x9DF4: 0xC585, //HANGUL SYLLABLE IEUNG YA RIEULKIYEOK + 0x9DF5: 0xC586, //HANGUL SYLLABLE IEUNG YA RIEULMIEUM + 0x9DF6: 0xC588, //HANGUL SYLLABLE IEUNG YA RIEULSIOS + 0x9DF7: 0xC589, //HANGUL SYLLABLE IEUNG YA RIEULTHIEUTH + 0x9DF8: 0xC58A, //HANGUL SYLLABLE IEUNG YA RIEULPHIEUPH + 0x9DF9: 0xC58B, //HANGUL SYLLABLE IEUNG YA RIEULHIEUH + 0x9DFA: 0xC58E, //HANGUL SYLLABLE IEUNG YA PIEUPSIOS + 0x9DFB: 0xC590, //HANGUL SYLLABLE IEUNG YA SSANGSIOS + 0x9DFC: 0xC592, //HANGUL SYLLABLE IEUNG YA CIEUC + 0x9DFD: 0xC593, //HANGUL SYLLABLE IEUNG YA CHIEUCH + 0x9DFE: 0xC594, //HANGUL SYLLABLE IEUNG YA KHIEUKH + 0x9E41: 0xC596, //HANGUL SYLLABLE IEUNG YA PHIEUPH + 0x9E42: 0xC599, //HANGUL SYLLABLE IEUNG YAE KIYEOK + 0x9E43: 0xC59A, //HANGUL SYLLABLE IEUNG YAE SSANGKIYEOK + 0x9E44: 0xC59B, //HANGUL SYLLABLE IEUNG YAE KIYEOKSIOS + 0x9E45: 0xC59D, //HANGUL SYLLABLE IEUNG YAE NIEUNCIEUC + 0x9E46: 0xC59E, //HANGUL SYLLABLE IEUNG YAE NIEUNHIEUH + 0x9E47: 0xC59F, //HANGUL SYLLABLE IEUNG YAE TIKEUT + 0x9E48: 0xC5A1, //HANGUL SYLLABLE IEUNG YAE RIEULKIYEOK + 0x9E49: 0xC5A2, //HANGUL SYLLABLE IEUNG YAE RIEULMIEUM + 0x9E4A: 0xC5A3, //HANGUL SYLLABLE IEUNG YAE RIEULPIEUP + 0x9E4B: 0xC5A4, //HANGUL SYLLABLE IEUNG YAE RIEULSIOS + 0x9E4C: 0xC5A5, //HANGUL SYLLABLE IEUNG YAE RIEULTHIEUTH + 0x9E4D: 0xC5A6, //HANGUL SYLLABLE IEUNG YAE RIEULPHIEUPH + 0x9E4E: 0xC5A7, //HANGUL SYLLABLE IEUNG YAE RIEULHIEUH + 0x9E4F: 0xC5A8, //HANGUL SYLLABLE IEUNG YAE MIEUM + 0x9E50: 0xC5AA, //HANGUL SYLLABLE IEUNG YAE PIEUPSIOS + 0x9E51: 0xC5AB, //HANGUL SYLLABLE IEUNG YAE SIOS + 0x9E52: 0xC5AC, //HANGUL SYLLABLE IEUNG YAE SSANGSIOS + 0x9E53: 0xC5AD, //HANGUL SYLLABLE IEUNG YAE IEUNG + 0x9E54: 0xC5AE, //HANGUL SYLLABLE IEUNG YAE CIEUC + 0x9E55: 0xC5AF, //HANGUL SYLLABLE IEUNG YAE CHIEUCH + 0x9E56: 0xC5B0, //HANGUL SYLLABLE IEUNG YAE KHIEUKH + 0x9E57: 0xC5B1, //HANGUL SYLLABLE IEUNG YAE THIEUTH + 0x9E58: 0xC5B2, //HANGUL SYLLABLE IEUNG YAE PHIEUPH + 0x9E59: 0xC5B3, //HANGUL SYLLABLE IEUNG YAE HIEUH + 0x9E5A: 0xC5B6, //HANGUL SYLLABLE IEUNG EO SSANGKIYEOK + 0x9E61: 0xC5B7, //HANGUL SYLLABLE IEUNG EO KIYEOKSIOS + 0x9E62: 0xC5BA, //HANGUL SYLLABLE IEUNG EO NIEUNHIEUH + 0x9E63: 0xC5BF, //HANGUL SYLLABLE IEUNG EO RIEULPIEUP + 0x9E64: 0xC5C0, //HANGUL SYLLABLE IEUNG EO RIEULSIOS + 0x9E65: 0xC5C1, //HANGUL SYLLABLE IEUNG EO RIEULTHIEUTH + 0x9E66: 0xC5C2, //HANGUL SYLLABLE IEUNG EO RIEULPHIEUPH + 0x9E67: 0xC5C3, //HANGUL SYLLABLE IEUNG EO RIEULHIEUH + 0x9E68: 0xC5CB, //HANGUL SYLLABLE IEUNG EO CHIEUCH + 0x9E69: 0xC5CD, //HANGUL SYLLABLE IEUNG EO THIEUTH + 0x9E6A: 0xC5CF, //HANGUL SYLLABLE IEUNG EO HIEUH + 0x9E6B: 0xC5D2, //HANGUL SYLLABLE IEUNG E SSANGKIYEOK + 0x9E6C: 0xC5D3, //HANGUL SYLLABLE IEUNG E KIYEOKSIOS + 0x9E6D: 0xC5D5, //HANGUL SYLLABLE IEUNG E NIEUNCIEUC + 0x9E6E: 0xC5D6, //HANGUL SYLLABLE IEUNG E NIEUNHIEUH + 0x9E6F: 0xC5D7, //HANGUL SYLLABLE IEUNG E TIKEUT + 0x9E70: 0xC5D9, //HANGUL SYLLABLE IEUNG E RIEULKIYEOK + 0x9E71: 0xC5DA, //HANGUL SYLLABLE IEUNG E RIEULMIEUM + 0x9E72: 0xC5DB, //HANGUL SYLLABLE IEUNG E RIEULPIEUP + 0x9E73: 0xC5DC, //HANGUL SYLLABLE IEUNG E RIEULSIOS + 0x9E74: 0xC5DD, //HANGUL SYLLABLE IEUNG E RIEULTHIEUTH + 0x9E75: 0xC5DE, //HANGUL SYLLABLE IEUNG E RIEULPHIEUPH + 0x9E76: 0xC5DF, //HANGUL SYLLABLE IEUNG E RIEULHIEUH + 0x9E77: 0xC5E2, //HANGUL SYLLABLE IEUNG E PIEUPSIOS + 0x9E78: 0xC5E4, //HANGUL SYLLABLE IEUNG E SSANGSIOS + 0x9E79: 0xC5E6, //HANGUL SYLLABLE IEUNG E CIEUC + 0x9E7A: 0xC5E7, //HANGUL SYLLABLE IEUNG E CHIEUCH + 0x9E81: 0xC5E8, //HANGUL SYLLABLE IEUNG E KHIEUKH + 0x9E82: 0xC5E9, //HANGUL SYLLABLE IEUNG E THIEUTH + 0x9E83: 0xC5EA, //HANGUL SYLLABLE IEUNG E PHIEUPH + 0x9E84: 0xC5EB, //HANGUL SYLLABLE IEUNG E HIEUH + 0x9E85: 0xC5EF, //HANGUL SYLLABLE IEUNG YEO KIYEOKSIOS + 0x9E86: 0xC5F1, //HANGUL SYLLABLE IEUNG YEO NIEUNCIEUC + 0x9E87: 0xC5F2, //HANGUL SYLLABLE IEUNG YEO NIEUNHIEUH + 0x9E88: 0xC5F3, //HANGUL SYLLABLE IEUNG YEO TIKEUT + 0x9E89: 0xC5F5, //HANGUL SYLLABLE IEUNG YEO RIEULKIYEOK + 0x9E8A: 0xC5F8, //HANGUL SYLLABLE IEUNG YEO RIEULSIOS + 0x9E8B: 0xC5F9, //HANGUL SYLLABLE IEUNG YEO RIEULTHIEUTH + 0x9E8C: 0xC5FA, //HANGUL SYLLABLE IEUNG YEO RIEULPHIEUPH + 0x9E8D: 0xC5FB, //HANGUL SYLLABLE IEUNG YEO RIEULHIEUH + 0x9E8E: 0xC602, //HANGUL SYLLABLE IEUNG YEO CIEUC + 0x9E8F: 0xC603, //HANGUL SYLLABLE IEUNG YEO CHIEUCH + 0x9E90: 0xC604, //HANGUL SYLLABLE IEUNG YEO KHIEUKH + 0x9E91: 0xC609, //HANGUL SYLLABLE IEUNG YE KIYEOK + 0x9E92: 0xC60A, //HANGUL SYLLABLE IEUNG YE SSANGKIYEOK + 0x9E93: 0xC60B, //HANGUL SYLLABLE IEUNG YE KIYEOKSIOS + 0x9E94: 0xC60D, //HANGUL SYLLABLE IEUNG YE NIEUNCIEUC + 0x9E95: 0xC60E, //HANGUL SYLLABLE IEUNG YE NIEUNHIEUH + 0x9E96: 0xC60F, //HANGUL SYLLABLE IEUNG YE TIKEUT + 0x9E97: 0xC611, //HANGUL SYLLABLE IEUNG YE RIEULKIYEOK + 0x9E98: 0xC612, //HANGUL SYLLABLE IEUNG YE RIEULMIEUM + 0x9E99: 0xC613, //HANGUL SYLLABLE IEUNG YE RIEULPIEUP + 0x9E9A: 0xC614, //HANGUL SYLLABLE IEUNG YE RIEULSIOS + 0x9E9B: 0xC615, //HANGUL SYLLABLE IEUNG YE RIEULTHIEUTH + 0x9E9C: 0xC616, //HANGUL SYLLABLE IEUNG YE RIEULPHIEUPH + 0x9E9D: 0xC617, //HANGUL SYLLABLE IEUNG YE RIEULHIEUH + 0x9E9E: 0xC61A, //HANGUL SYLLABLE IEUNG YE PIEUPSIOS + 0x9E9F: 0xC61D, //HANGUL SYLLABLE IEUNG YE IEUNG + 0x9EA0: 0xC61E, //HANGUL SYLLABLE IEUNG YE CIEUC + 0x9EA1: 0xC61F, //HANGUL SYLLABLE IEUNG YE CHIEUCH + 0x9EA2: 0xC620, //HANGUL SYLLABLE IEUNG YE KHIEUKH + 0x9EA3: 0xC621, //HANGUL SYLLABLE IEUNG YE THIEUTH + 0x9EA4: 0xC622, //HANGUL SYLLABLE IEUNG YE PHIEUPH + 0x9EA5: 0xC623, //HANGUL SYLLABLE IEUNG YE HIEUH + 0x9EA6: 0xC626, //HANGUL SYLLABLE IEUNG O SSANGKIYEOK + 0x9EA7: 0xC627, //HANGUL SYLLABLE IEUNG O KIYEOKSIOS + 0x9EA8: 0xC629, //HANGUL SYLLABLE IEUNG O NIEUNCIEUC + 0x9EA9: 0xC62A, //HANGUL SYLLABLE IEUNG O NIEUNHIEUH + 0x9EAA: 0xC62B, //HANGUL SYLLABLE IEUNG O TIKEUT + 0x9EAB: 0xC62F, //HANGUL SYLLABLE IEUNG O RIEULPIEUP + 0x9EAC: 0xC631, //HANGUL SYLLABLE IEUNG O RIEULTHIEUTH + 0x9EAD: 0xC632, //HANGUL SYLLABLE IEUNG O RIEULPHIEUPH + 0x9EAE: 0xC636, //HANGUL SYLLABLE IEUNG O PIEUPSIOS + 0x9EAF: 0xC638, //HANGUL SYLLABLE IEUNG O SSANGSIOS + 0x9EB0: 0xC63A, //HANGUL SYLLABLE IEUNG O CIEUC + 0x9EB1: 0xC63C, //HANGUL SYLLABLE IEUNG O KHIEUKH + 0x9EB2: 0xC63D, //HANGUL SYLLABLE IEUNG O THIEUTH + 0x9EB3: 0xC63E, //HANGUL SYLLABLE IEUNG O PHIEUPH + 0x9EB4: 0xC63F, //HANGUL SYLLABLE IEUNG O HIEUH + 0x9EB5: 0xC642, //HANGUL SYLLABLE IEUNG WA SSANGKIYEOK + 0x9EB6: 0xC643, //HANGUL SYLLABLE IEUNG WA KIYEOKSIOS + 0x9EB7: 0xC645, //HANGUL SYLLABLE IEUNG WA NIEUNCIEUC + 0x9EB8: 0xC646, //HANGUL SYLLABLE IEUNG WA NIEUNHIEUH + 0x9EB9: 0xC647, //HANGUL SYLLABLE IEUNG WA TIKEUT + 0x9EBA: 0xC649, //HANGUL SYLLABLE IEUNG WA RIEULKIYEOK + 0x9EBB: 0xC64A, //HANGUL SYLLABLE IEUNG WA RIEULMIEUM + 0x9EBC: 0xC64B, //HANGUL SYLLABLE IEUNG WA RIEULPIEUP + 0x9EBD: 0xC64C, //HANGUL SYLLABLE IEUNG WA RIEULSIOS + 0x9EBE: 0xC64D, //HANGUL SYLLABLE IEUNG WA RIEULTHIEUTH + 0x9EBF: 0xC64E, //HANGUL SYLLABLE IEUNG WA RIEULPHIEUPH + 0x9EC0: 0xC64F, //HANGUL SYLLABLE IEUNG WA RIEULHIEUH + 0x9EC1: 0xC652, //HANGUL SYLLABLE IEUNG WA PIEUPSIOS + 0x9EC2: 0xC656, //HANGUL SYLLABLE IEUNG WA CIEUC + 0x9EC3: 0xC657, //HANGUL SYLLABLE IEUNG WA CHIEUCH + 0x9EC4: 0xC658, //HANGUL SYLLABLE IEUNG WA KHIEUKH + 0x9EC5: 0xC659, //HANGUL SYLLABLE IEUNG WA THIEUTH + 0x9EC6: 0xC65A, //HANGUL SYLLABLE IEUNG WA PHIEUPH + 0x9EC7: 0xC65B, //HANGUL SYLLABLE IEUNG WA HIEUH + 0x9EC8: 0xC65E, //HANGUL SYLLABLE IEUNG WAE SSANGKIYEOK + 0x9EC9: 0xC65F, //HANGUL SYLLABLE IEUNG WAE KIYEOKSIOS + 0x9ECA: 0xC661, //HANGUL SYLLABLE IEUNG WAE NIEUNCIEUC + 0x9ECB: 0xC662, //HANGUL SYLLABLE IEUNG WAE NIEUNHIEUH + 0x9ECC: 0xC663, //HANGUL SYLLABLE IEUNG WAE TIKEUT + 0x9ECD: 0xC664, //HANGUL SYLLABLE IEUNG WAE RIEUL + 0x9ECE: 0xC665, //HANGUL SYLLABLE IEUNG WAE RIEULKIYEOK + 0x9ECF: 0xC666, //HANGUL SYLLABLE IEUNG WAE RIEULMIEUM + 0x9ED0: 0xC667, //HANGUL SYLLABLE IEUNG WAE RIEULPIEUP + 0x9ED1: 0xC668, //HANGUL SYLLABLE IEUNG WAE RIEULSIOS + 0x9ED2: 0xC669, //HANGUL SYLLABLE IEUNG WAE RIEULTHIEUTH + 0x9ED3: 0xC66A, //HANGUL SYLLABLE IEUNG WAE RIEULPHIEUPH + 0x9ED4: 0xC66B, //HANGUL SYLLABLE IEUNG WAE RIEULHIEUH + 0x9ED5: 0xC66D, //HANGUL SYLLABLE IEUNG WAE PIEUP + 0x9ED6: 0xC66E, //HANGUL SYLLABLE IEUNG WAE PIEUPSIOS + 0x9ED7: 0xC670, //HANGUL SYLLABLE IEUNG WAE SSANGSIOS + 0x9ED8: 0xC672, //HANGUL SYLLABLE IEUNG WAE CIEUC + 0x9ED9: 0xC673, //HANGUL SYLLABLE IEUNG WAE CHIEUCH + 0x9EDA: 0xC674, //HANGUL SYLLABLE IEUNG WAE KHIEUKH + 0x9EDB: 0xC675, //HANGUL SYLLABLE IEUNG WAE THIEUTH + 0x9EDC: 0xC676, //HANGUL SYLLABLE IEUNG WAE PHIEUPH + 0x9EDD: 0xC677, //HANGUL SYLLABLE IEUNG WAE HIEUH + 0x9EDE: 0xC67A, //HANGUL SYLLABLE IEUNG OE SSANGKIYEOK + 0x9EDF: 0xC67B, //HANGUL SYLLABLE IEUNG OE KIYEOKSIOS + 0x9EE0: 0xC67D, //HANGUL SYLLABLE IEUNG OE NIEUNCIEUC + 0x9EE1: 0xC67E, //HANGUL SYLLABLE IEUNG OE NIEUNHIEUH + 0x9EE2: 0xC67F, //HANGUL SYLLABLE IEUNG OE TIKEUT + 0x9EE3: 0xC681, //HANGUL SYLLABLE IEUNG OE RIEULKIYEOK + 0x9EE4: 0xC682, //HANGUL SYLLABLE IEUNG OE RIEULMIEUM + 0x9EE5: 0xC683, //HANGUL SYLLABLE IEUNG OE RIEULPIEUP + 0x9EE6: 0xC684, //HANGUL SYLLABLE IEUNG OE RIEULSIOS + 0x9EE7: 0xC685, //HANGUL SYLLABLE IEUNG OE RIEULTHIEUTH + 0x9EE8: 0xC686, //HANGUL SYLLABLE IEUNG OE RIEULPHIEUPH + 0x9EE9: 0xC687, //HANGUL SYLLABLE IEUNG OE RIEULHIEUH + 0x9EEA: 0xC68A, //HANGUL SYLLABLE IEUNG OE PIEUPSIOS + 0x9EEB: 0xC68C, //HANGUL SYLLABLE IEUNG OE SSANGSIOS + 0x9EEC: 0xC68E, //HANGUL SYLLABLE IEUNG OE CIEUC + 0x9EED: 0xC68F, //HANGUL SYLLABLE IEUNG OE CHIEUCH + 0x9EEE: 0xC690, //HANGUL SYLLABLE IEUNG OE KHIEUKH + 0x9EEF: 0xC691, //HANGUL SYLLABLE IEUNG OE THIEUTH + 0x9EF0: 0xC692, //HANGUL SYLLABLE IEUNG OE PHIEUPH + 0x9EF1: 0xC693, //HANGUL SYLLABLE IEUNG OE HIEUH + 0x9EF2: 0xC696, //HANGUL SYLLABLE IEUNG YO SSANGKIYEOK + 0x9EF3: 0xC697, //HANGUL SYLLABLE IEUNG YO KIYEOKSIOS + 0x9EF4: 0xC699, //HANGUL SYLLABLE IEUNG YO NIEUNCIEUC + 0x9EF5: 0xC69A, //HANGUL SYLLABLE IEUNG YO NIEUNHIEUH + 0x9EF6: 0xC69B, //HANGUL SYLLABLE IEUNG YO TIKEUT + 0x9EF7: 0xC69D, //HANGUL SYLLABLE IEUNG YO RIEULKIYEOK + 0x9EF8: 0xC69E, //HANGUL SYLLABLE IEUNG YO RIEULMIEUM + 0x9EF9: 0xC69F, //HANGUL SYLLABLE IEUNG YO RIEULPIEUP + 0x9EFA: 0xC6A0, //HANGUL SYLLABLE IEUNG YO RIEULSIOS + 0x9EFB: 0xC6A1, //HANGUL SYLLABLE IEUNG YO RIEULTHIEUTH + 0x9EFC: 0xC6A2, //HANGUL SYLLABLE IEUNG YO RIEULPHIEUPH + 0x9EFD: 0xC6A3, //HANGUL SYLLABLE IEUNG YO RIEULHIEUH + 0x9EFE: 0xC6A6, //HANGUL SYLLABLE IEUNG YO PIEUPSIOS + 0x9F41: 0xC6A8, //HANGUL SYLLABLE IEUNG YO SSANGSIOS + 0x9F42: 0xC6AA, //HANGUL SYLLABLE IEUNG YO CIEUC + 0x9F43: 0xC6AB, //HANGUL SYLLABLE IEUNG YO CHIEUCH + 0x9F44: 0xC6AC, //HANGUL SYLLABLE IEUNG YO KHIEUKH + 0x9F45: 0xC6AD, //HANGUL SYLLABLE IEUNG YO THIEUTH + 0x9F46: 0xC6AE, //HANGUL SYLLABLE IEUNG YO PHIEUPH + 0x9F47: 0xC6AF, //HANGUL SYLLABLE IEUNG YO HIEUH + 0x9F48: 0xC6B2, //HANGUL SYLLABLE IEUNG U SSANGKIYEOK + 0x9F49: 0xC6B3, //HANGUL SYLLABLE IEUNG U KIYEOKSIOS + 0x9F4A: 0xC6B5, //HANGUL SYLLABLE IEUNG U NIEUNCIEUC + 0x9F4B: 0xC6B6, //HANGUL SYLLABLE IEUNG U NIEUNHIEUH + 0x9F4C: 0xC6B7, //HANGUL SYLLABLE IEUNG U TIKEUT + 0x9F4D: 0xC6BB, //HANGUL SYLLABLE IEUNG U RIEULPIEUP + 0x9F4E: 0xC6BC, //HANGUL SYLLABLE IEUNG U RIEULSIOS + 0x9F4F: 0xC6BD, //HANGUL SYLLABLE IEUNG U RIEULTHIEUTH + 0x9F50: 0xC6BE, //HANGUL SYLLABLE IEUNG U RIEULPHIEUPH + 0x9F51: 0xC6BF, //HANGUL SYLLABLE IEUNG U RIEULHIEUH + 0x9F52: 0xC6C2, //HANGUL SYLLABLE IEUNG U PIEUPSIOS + 0x9F53: 0xC6C4, //HANGUL SYLLABLE IEUNG U SSANGSIOS + 0x9F54: 0xC6C6, //HANGUL SYLLABLE IEUNG U CIEUC + 0x9F55: 0xC6C7, //HANGUL SYLLABLE IEUNG U CHIEUCH + 0x9F56: 0xC6C8, //HANGUL SYLLABLE IEUNG U KHIEUKH + 0x9F57: 0xC6C9, //HANGUL SYLLABLE IEUNG U THIEUTH + 0x9F58: 0xC6CA, //HANGUL SYLLABLE IEUNG U PHIEUPH + 0x9F59: 0xC6CB, //HANGUL SYLLABLE IEUNG U HIEUH + 0x9F5A: 0xC6CE, //HANGUL SYLLABLE IEUNG WEO SSANGKIYEOK + 0x9F61: 0xC6CF, //HANGUL SYLLABLE IEUNG WEO KIYEOKSIOS + 0x9F62: 0xC6D1, //HANGUL SYLLABLE IEUNG WEO NIEUNCIEUC + 0x9F63: 0xC6D2, //HANGUL SYLLABLE IEUNG WEO NIEUNHIEUH + 0x9F64: 0xC6D3, //HANGUL SYLLABLE IEUNG WEO TIKEUT + 0x9F65: 0xC6D5, //HANGUL SYLLABLE IEUNG WEO RIEULKIYEOK + 0x9F66: 0xC6D6, //HANGUL SYLLABLE IEUNG WEO RIEULMIEUM + 0x9F67: 0xC6D7, //HANGUL SYLLABLE IEUNG WEO RIEULPIEUP + 0x9F68: 0xC6D8, //HANGUL SYLLABLE IEUNG WEO RIEULSIOS + 0x9F69: 0xC6D9, //HANGUL SYLLABLE IEUNG WEO RIEULTHIEUTH + 0x9F6A: 0xC6DA, //HANGUL SYLLABLE IEUNG WEO RIEULPHIEUPH + 0x9F6B: 0xC6DB, //HANGUL SYLLABLE IEUNG WEO RIEULHIEUH + 0x9F6C: 0xC6DE, //HANGUL SYLLABLE IEUNG WEO PIEUPSIOS + 0x9F6D: 0xC6DF, //HANGUL SYLLABLE IEUNG WEO SIOS + 0x9F6E: 0xC6E2, //HANGUL SYLLABLE IEUNG WEO CIEUC + 0x9F6F: 0xC6E3, //HANGUL SYLLABLE IEUNG WEO CHIEUCH + 0x9F70: 0xC6E4, //HANGUL SYLLABLE IEUNG WEO KHIEUKH + 0x9F71: 0xC6E5, //HANGUL SYLLABLE IEUNG WEO THIEUTH + 0x9F72: 0xC6E6, //HANGUL SYLLABLE IEUNG WEO PHIEUPH + 0x9F73: 0xC6E7, //HANGUL SYLLABLE IEUNG WEO HIEUH + 0x9F74: 0xC6EA, //HANGUL SYLLABLE IEUNG WE SSANGKIYEOK + 0x9F75: 0xC6EB, //HANGUL SYLLABLE IEUNG WE KIYEOKSIOS + 0x9F76: 0xC6ED, //HANGUL SYLLABLE IEUNG WE NIEUNCIEUC + 0x9F77: 0xC6EE, //HANGUL SYLLABLE IEUNG WE NIEUNHIEUH + 0x9F78: 0xC6EF, //HANGUL SYLLABLE IEUNG WE TIKEUT + 0x9F79: 0xC6F1, //HANGUL SYLLABLE IEUNG WE RIEULKIYEOK + 0x9F7A: 0xC6F2, //HANGUL SYLLABLE IEUNG WE RIEULMIEUM + 0x9F81: 0xC6F3, //HANGUL SYLLABLE IEUNG WE RIEULPIEUP + 0x9F82: 0xC6F4, //HANGUL SYLLABLE IEUNG WE RIEULSIOS + 0x9F83: 0xC6F5, //HANGUL SYLLABLE IEUNG WE RIEULTHIEUTH + 0x9F84: 0xC6F6, //HANGUL SYLLABLE IEUNG WE RIEULPHIEUPH + 0x9F85: 0xC6F7, //HANGUL SYLLABLE IEUNG WE RIEULHIEUH + 0x9F86: 0xC6FA, //HANGUL SYLLABLE IEUNG WE PIEUPSIOS + 0x9F87: 0xC6FB, //HANGUL SYLLABLE IEUNG WE SIOS + 0x9F88: 0xC6FC, //HANGUL SYLLABLE IEUNG WE SSANGSIOS + 0x9F89: 0xC6FE, //HANGUL SYLLABLE IEUNG WE CIEUC + 0x9F8A: 0xC6FF, //HANGUL SYLLABLE IEUNG WE CHIEUCH + 0x9F8B: 0xC700, //HANGUL SYLLABLE IEUNG WE KHIEUKH + 0x9F8C: 0xC701, //HANGUL SYLLABLE IEUNG WE THIEUTH + 0x9F8D: 0xC702, //HANGUL SYLLABLE IEUNG WE PHIEUPH + 0x9F8E: 0xC703, //HANGUL SYLLABLE IEUNG WE HIEUH + 0x9F8F: 0xC706, //HANGUL SYLLABLE IEUNG WI SSANGKIYEOK + 0x9F90: 0xC707, //HANGUL SYLLABLE IEUNG WI KIYEOKSIOS + 0x9F91: 0xC709, //HANGUL SYLLABLE IEUNG WI NIEUNCIEUC + 0x9F92: 0xC70A, //HANGUL SYLLABLE IEUNG WI NIEUNHIEUH + 0x9F93: 0xC70B, //HANGUL SYLLABLE IEUNG WI TIKEUT + 0x9F94: 0xC70D, //HANGUL SYLLABLE IEUNG WI RIEULKIYEOK + 0x9F95: 0xC70E, //HANGUL SYLLABLE IEUNG WI RIEULMIEUM + 0x9F96: 0xC70F, //HANGUL SYLLABLE IEUNG WI RIEULPIEUP + 0x9F97: 0xC710, //HANGUL SYLLABLE IEUNG WI RIEULSIOS + 0x9F98: 0xC711, //HANGUL SYLLABLE IEUNG WI RIEULTHIEUTH + 0x9F99: 0xC712, //HANGUL SYLLABLE IEUNG WI RIEULPHIEUPH + 0x9F9A: 0xC713, //HANGUL SYLLABLE IEUNG WI RIEULHIEUH + 0x9F9B: 0xC716, //HANGUL SYLLABLE IEUNG WI PIEUPSIOS + 0x9F9C: 0xC718, //HANGUL SYLLABLE IEUNG WI SSANGSIOS + 0x9F9D: 0xC71A, //HANGUL SYLLABLE IEUNG WI CIEUC + 0x9F9E: 0xC71B, //HANGUL SYLLABLE IEUNG WI CHIEUCH + 0x9F9F: 0xC71C, //HANGUL SYLLABLE IEUNG WI KHIEUKH + 0x9FA0: 0xC71D, //HANGUL SYLLABLE IEUNG WI THIEUTH + 0x9FA1: 0xC71E, //HANGUL SYLLABLE IEUNG WI PHIEUPH + 0x9FA2: 0xC71F, //HANGUL SYLLABLE IEUNG WI HIEUH + 0x9FA3: 0xC722, //HANGUL SYLLABLE IEUNG YU SSANGKIYEOK + 0x9FA4: 0xC723, //HANGUL SYLLABLE IEUNG YU KIYEOKSIOS + 0x9FA5: 0xC725, //HANGUL SYLLABLE IEUNG YU NIEUNCIEUC + 0x9FA6: 0xC726, //HANGUL SYLLABLE IEUNG YU NIEUNHIEUH + 0x9FA7: 0xC727, //HANGUL SYLLABLE IEUNG YU TIKEUT + 0x9FA8: 0xC729, //HANGUL SYLLABLE IEUNG YU RIEULKIYEOK + 0x9FA9: 0xC72A, //HANGUL SYLLABLE IEUNG YU RIEULMIEUM + 0x9FAA: 0xC72B, //HANGUL SYLLABLE IEUNG YU RIEULPIEUP + 0x9FAB: 0xC72C, //HANGUL SYLLABLE IEUNG YU RIEULSIOS + 0x9FAC: 0xC72D, //HANGUL SYLLABLE IEUNG YU RIEULTHIEUTH + 0x9FAD: 0xC72E, //HANGUL SYLLABLE IEUNG YU RIEULPHIEUPH + 0x9FAE: 0xC72F, //HANGUL SYLLABLE IEUNG YU RIEULHIEUH + 0x9FAF: 0xC732, //HANGUL SYLLABLE IEUNG YU PIEUPSIOS + 0x9FB0: 0xC734, //HANGUL SYLLABLE IEUNG YU SSANGSIOS + 0x9FB1: 0xC736, //HANGUL SYLLABLE IEUNG YU CIEUC + 0x9FB2: 0xC738, //HANGUL SYLLABLE IEUNG YU KHIEUKH + 0x9FB3: 0xC739, //HANGUL SYLLABLE IEUNG YU THIEUTH + 0x9FB4: 0xC73A, //HANGUL SYLLABLE IEUNG YU PHIEUPH + 0x9FB5: 0xC73B, //HANGUL SYLLABLE IEUNG YU HIEUH + 0x9FB6: 0xC73E, //HANGUL SYLLABLE IEUNG EU SSANGKIYEOK + 0x9FB7: 0xC73F, //HANGUL SYLLABLE IEUNG EU KIYEOKSIOS + 0x9FB8: 0xC741, //HANGUL SYLLABLE IEUNG EU NIEUNCIEUC + 0x9FB9: 0xC742, //HANGUL SYLLABLE IEUNG EU NIEUNHIEUH + 0x9FBA: 0xC743, //HANGUL SYLLABLE IEUNG EU TIKEUT + 0x9FBB: 0xC745, //HANGUL SYLLABLE IEUNG EU RIEULKIYEOK + 0x9FBC: 0xC746, //HANGUL SYLLABLE IEUNG EU RIEULMIEUM + 0x9FBD: 0xC747, //HANGUL SYLLABLE IEUNG EU RIEULPIEUP + 0x9FBE: 0xC748, //HANGUL SYLLABLE IEUNG EU RIEULSIOS + 0x9FBF: 0xC749, //HANGUL SYLLABLE IEUNG EU RIEULTHIEUTH + 0x9FC0: 0xC74B, //HANGUL SYLLABLE IEUNG EU RIEULHIEUH + 0x9FC1: 0xC74E, //HANGUL SYLLABLE IEUNG EU PIEUPSIOS + 0x9FC2: 0xC750, //HANGUL SYLLABLE IEUNG EU SSANGSIOS + 0x9FC3: 0xC759, //HANGUL SYLLABLE IEUNG YI KIYEOK + 0x9FC4: 0xC75A, //HANGUL SYLLABLE IEUNG YI SSANGKIYEOK + 0x9FC5: 0xC75B, //HANGUL SYLLABLE IEUNG YI KIYEOKSIOS + 0x9FC6: 0xC75D, //HANGUL SYLLABLE IEUNG YI NIEUNCIEUC + 0x9FC7: 0xC75E, //HANGUL SYLLABLE IEUNG YI NIEUNHIEUH + 0x9FC8: 0xC75F, //HANGUL SYLLABLE IEUNG YI TIKEUT + 0x9FC9: 0xC761, //HANGUL SYLLABLE IEUNG YI RIEULKIYEOK + 0x9FCA: 0xC762, //HANGUL SYLLABLE IEUNG YI RIEULMIEUM + 0x9FCB: 0xC763, //HANGUL SYLLABLE IEUNG YI RIEULPIEUP + 0x9FCC: 0xC764, //HANGUL SYLLABLE IEUNG YI RIEULSIOS + 0x9FCD: 0xC765, //HANGUL SYLLABLE IEUNG YI RIEULTHIEUTH + 0x9FCE: 0xC766, //HANGUL SYLLABLE IEUNG YI RIEULPHIEUPH + 0x9FCF: 0xC767, //HANGUL SYLLABLE IEUNG YI RIEULHIEUH + 0x9FD0: 0xC769, //HANGUL SYLLABLE IEUNG YI PIEUP + 0x9FD1: 0xC76A, //HANGUL SYLLABLE IEUNG YI PIEUPSIOS + 0x9FD2: 0xC76C, //HANGUL SYLLABLE IEUNG YI SSANGSIOS + 0x9FD3: 0xC76D, //HANGUL SYLLABLE IEUNG YI IEUNG + 0x9FD4: 0xC76E, //HANGUL SYLLABLE IEUNG YI CIEUC + 0x9FD5: 0xC76F, //HANGUL SYLLABLE IEUNG YI CHIEUCH + 0x9FD6: 0xC770, //HANGUL SYLLABLE IEUNG YI KHIEUKH + 0x9FD7: 0xC771, //HANGUL SYLLABLE IEUNG YI THIEUTH + 0x9FD8: 0xC772, //HANGUL SYLLABLE IEUNG YI PHIEUPH + 0x9FD9: 0xC773, //HANGUL SYLLABLE IEUNG YI HIEUH + 0x9FDA: 0xC776, //HANGUL SYLLABLE IEUNG I SSANGKIYEOK + 0x9FDB: 0xC777, //HANGUL SYLLABLE IEUNG I KIYEOKSIOS + 0x9FDC: 0xC779, //HANGUL SYLLABLE IEUNG I NIEUNCIEUC + 0x9FDD: 0xC77A, //HANGUL SYLLABLE IEUNG I NIEUNHIEUH + 0x9FDE: 0xC77B, //HANGUL SYLLABLE IEUNG I TIKEUT + 0x9FDF: 0xC77F, //HANGUL SYLLABLE IEUNG I RIEULPIEUP + 0x9FE0: 0xC780, //HANGUL SYLLABLE IEUNG I RIEULSIOS + 0x9FE1: 0xC781, //HANGUL SYLLABLE IEUNG I RIEULTHIEUTH + 0x9FE2: 0xC782, //HANGUL SYLLABLE IEUNG I RIEULPHIEUPH + 0x9FE3: 0xC786, //HANGUL SYLLABLE IEUNG I PIEUPSIOS + 0x9FE4: 0xC78B, //HANGUL SYLLABLE IEUNG I CHIEUCH + 0x9FE5: 0xC78C, //HANGUL SYLLABLE IEUNG I KHIEUKH + 0x9FE6: 0xC78D, //HANGUL SYLLABLE IEUNG I THIEUTH + 0x9FE7: 0xC78F, //HANGUL SYLLABLE IEUNG I HIEUH + 0x9FE8: 0xC792, //HANGUL SYLLABLE CIEUC A SSANGKIYEOK + 0x9FE9: 0xC793, //HANGUL SYLLABLE CIEUC A KIYEOKSIOS + 0x9FEA: 0xC795, //HANGUL SYLLABLE CIEUC A NIEUNCIEUC + 0x9FEB: 0xC799, //HANGUL SYLLABLE CIEUC A RIEULKIYEOK + 0x9FEC: 0xC79B, //HANGUL SYLLABLE CIEUC A RIEULPIEUP + 0x9FED: 0xC79C, //HANGUL SYLLABLE CIEUC A RIEULSIOS + 0x9FEE: 0xC79D, //HANGUL SYLLABLE CIEUC A RIEULTHIEUTH + 0x9FEF: 0xC79E, //HANGUL SYLLABLE CIEUC A RIEULPHIEUPH + 0x9FF0: 0xC79F, //HANGUL SYLLABLE CIEUC A RIEULHIEUH + 0x9FF1: 0xC7A2, //HANGUL SYLLABLE CIEUC A PIEUPSIOS + 0x9FF2: 0xC7A7, //HANGUL SYLLABLE CIEUC A CHIEUCH + 0x9FF3: 0xC7A8, //HANGUL SYLLABLE CIEUC A KHIEUKH + 0x9FF4: 0xC7A9, //HANGUL SYLLABLE CIEUC A THIEUTH + 0x9FF5: 0xC7AA, //HANGUL SYLLABLE CIEUC A PHIEUPH + 0x9FF6: 0xC7AB, //HANGUL SYLLABLE CIEUC A HIEUH + 0x9FF7: 0xC7AE, //HANGUL SYLLABLE CIEUC AE SSANGKIYEOK + 0x9FF8: 0xC7AF, //HANGUL SYLLABLE CIEUC AE KIYEOKSIOS + 0x9FF9: 0xC7B1, //HANGUL SYLLABLE CIEUC AE NIEUNCIEUC + 0x9FFA: 0xC7B2, //HANGUL SYLLABLE CIEUC AE NIEUNHIEUH + 0x9FFB: 0xC7B3, //HANGUL SYLLABLE CIEUC AE TIKEUT + 0x9FFC: 0xC7B5, //HANGUL SYLLABLE CIEUC AE RIEULKIYEOK + 0x9FFD: 0xC7B6, //HANGUL SYLLABLE CIEUC AE RIEULMIEUM + 0x9FFE: 0xC7B7, //HANGUL SYLLABLE CIEUC AE RIEULPIEUP + 0xA041: 0xC7B8, //HANGUL SYLLABLE CIEUC AE RIEULSIOS + 0xA042: 0xC7B9, //HANGUL SYLLABLE CIEUC AE RIEULTHIEUTH + 0xA043: 0xC7BA, //HANGUL SYLLABLE CIEUC AE RIEULPHIEUPH + 0xA044: 0xC7BB, //HANGUL SYLLABLE CIEUC AE RIEULHIEUH + 0xA045: 0xC7BE, //HANGUL SYLLABLE CIEUC AE PIEUPSIOS + 0xA046: 0xC7C2, //HANGUL SYLLABLE CIEUC AE CIEUC + 0xA047: 0xC7C3, //HANGUL SYLLABLE CIEUC AE CHIEUCH + 0xA048: 0xC7C4, //HANGUL SYLLABLE CIEUC AE KHIEUKH + 0xA049: 0xC7C5, //HANGUL SYLLABLE CIEUC AE THIEUTH + 0xA04A: 0xC7C6, //HANGUL SYLLABLE CIEUC AE PHIEUPH + 0xA04B: 0xC7C7, //HANGUL SYLLABLE CIEUC AE HIEUH + 0xA04C: 0xC7CA, //HANGUL SYLLABLE CIEUC YA SSANGKIYEOK + 0xA04D: 0xC7CB, //HANGUL SYLLABLE CIEUC YA KIYEOKSIOS + 0xA04E: 0xC7CD, //HANGUL SYLLABLE CIEUC YA NIEUNCIEUC + 0xA04F: 0xC7CF, //HANGUL SYLLABLE CIEUC YA TIKEUT + 0xA050: 0xC7D1, //HANGUL SYLLABLE CIEUC YA RIEULKIYEOK + 0xA051: 0xC7D2, //HANGUL SYLLABLE CIEUC YA RIEULMIEUM + 0xA052: 0xC7D3, //HANGUL SYLLABLE CIEUC YA RIEULPIEUP + 0xA053: 0xC7D4, //HANGUL SYLLABLE CIEUC YA RIEULSIOS + 0xA054: 0xC7D5, //HANGUL SYLLABLE CIEUC YA RIEULTHIEUTH + 0xA055: 0xC7D6, //HANGUL SYLLABLE CIEUC YA RIEULPHIEUPH + 0xA056: 0xC7D7, //HANGUL SYLLABLE CIEUC YA RIEULHIEUH + 0xA057: 0xC7D9, //HANGUL SYLLABLE CIEUC YA PIEUP + 0xA058: 0xC7DA, //HANGUL SYLLABLE CIEUC YA PIEUPSIOS + 0xA059: 0xC7DB, //HANGUL SYLLABLE CIEUC YA SIOS + 0xA05A: 0xC7DC, //HANGUL SYLLABLE CIEUC YA SSANGSIOS + 0xA061: 0xC7DE, //HANGUL SYLLABLE CIEUC YA CIEUC + 0xA062: 0xC7DF, //HANGUL SYLLABLE CIEUC YA CHIEUCH + 0xA063: 0xC7E0, //HANGUL SYLLABLE CIEUC YA KHIEUKH + 0xA064: 0xC7E1, //HANGUL SYLLABLE CIEUC YA THIEUTH + 0xA065: 0xC7E2, //HANGUL SYLLABLE CIEUC YA PHIEUPH + 0xA066: 0xC7E3, //HANGUL SYLLABLE CIEUC YA HIEUH + 0xA067: 0xC7E5, //HANGUL SYLLABLE CIEUC YAE KIYEOK + 0xA068: 0xC7E6, //HANGUL SYLLABLE CIEUC YAE SSANGKIYEOK + 0xA069: 0xC7E7, //HANGUL SYLLABLE CIEUC YAE KIYEOKSIOS + 0xA06A: 0xC7E9, //HANGUL SYLLABLE CIEUC YAE NIEUNCIEUC + 0xA06B: 0xC7EA, //HANGUL SYLLABLE CIEUC YAE NIEUNHIEUH + 0xA06C: 0xC7EB, //HANGUL SYLLABLE CIEUC YAE TIKEUT + 0xA06D: 0xC7ED, //HANGUL SYLLABLE CIEUC YAE RIEULKIYEOK + 0xA06E: 0xC7EE, //HANGUL SYLLABLE CIEUC YAE RIEULMIEUM + 0xA06F: 0xC7EF, //HANGUL SYLLABLE CIEUC YAE RIEULPIEUP + 0xA070: 0xC7F0, //HANGUL SYLLABLE CIEUC YAE RIEULSIOS + 0xA071: 0xC7F1, //HANGUL SYLLABLE CIEUC YAE RIEULTHIEUTH + 0xA072: 0xC7F2, //HANGUL SYLLABLE CIEUC YAE RIEULPHIEUPH + 0xA073: 0xC7F3, //HANGUL SYLLABLE CIEUC YAE RIEULHIEUH + 0xA074: 0xC7F4, //HANGUL SYLLABLE CIEUC YAE MIEUM + 0xA075: 0xC7F5, //HANGUL SYLLABLE CIEUC YAE PIEUP + 0xA076: 0xC7F6, //HANGUL SYLLABLE CIEUC YAE PIEUPSIOS + 0xA077: 0xC7F7, //HANGUL SYLLABLE CIEUC YAE SIOS + 0xA078: 0xC7F8, //HANGUL SYLLABLE CIEUC YAE SSANGSIOS + 0xA079: 0xC7F9, //HANGUL SYLLABLE CIEUC YAE IEUNG + 0xA07A: 0xC7FA, //HANGUL SYLLABLE CIEUC YAE CIEUC + 0xA081: 0xC7FB, //HANGUL SYLLABLE CIEUC YAE CHIEUCH + 0xA082: 0xC7FC, //HANGUL SYLLABLE CIEUC YAE KHIEUKH + 0xA083: 0xC7FD, //HANGUL SYLLABLE CIEUC YAE THIEUTH + 0xA084: 0xC7FE, //HANGUL SYLLABLE CIEUC YAE PHIEUPH + 0xA085: 0xC7FF, //HANGUL SYLLABLE CIEUC YAE HIEUH + 0xA086: 0xC802, //HANGUL SYLLABLE CIEUC EO SSANGKIYEOK + 0xA087: 0xC803, //HANGUL SYLLABLE CIEUC EO KIYEOKSIOS + 0xA088: 0xC805, //HANGUL SYLLABLE CIEUC EO NIEUNCIEUC + 0xA089: 0xC806, //HANGUL SYLLABLE CIEUC EO NIEUNHIEUH + 0xA08A: 0xC807, //HANGUL SYLLABLE CIEUC EO TIKEUT + 0xA08B: 0xC809, //HANGUL SYLLABLE CIEUC EO RIEULKIYEOK + 0xA08C: 0xC80B, //HANGUL SYLLABLE CIEUC EO RIEULPIEUP + 0xA08D: 0xC80C, //HANGUL SYLLABLE CIEUC EO RIEULSIOS + 0xA08E: 0xC80D, //HANGUL SYLLABLE CIEUC EO RIEULTHIEUTH + 0xA08F: 0xC80E, //HANGUL SYLLABLE CIEUC EO RIEULPHIEUPH + 0xA090: 0xC80F, //HANGUL SYLLABLE CIEUC EO RIEULHIEUH + 0xA091: 0xC812, //HANGUL SYLLABLE CIEUC EO PIEUPSIOS + 0xA092: 0xC814, //HANGUL SYLLABLE CIEUC EO SSANGSIOS + 0xA093: 0xC817, //HANGUL SYLLABLE CIEUC EO CHIEUCH + 0xA094: 0xC818, //HANGUL SYLLABLE CIEUC EO KHIEUKH + 0xA095: 0xC819, //HANGUL SYLLABLE CIEUC EO THIEUTH + 0xA096: 0xC81A, //HANGUL SYLLABLE CIEUC EO PHIEUPH + 0xA097: 0xC81B, //HANGUL SYLLABLE CIEUC EO HIEUH + 0xA098: 0xC81E, //HANGUL SYLLABLE CIEUC E SSANGKIYEOK + 0xA099: 0xC81F, //HANGUL SYLLABLE CIEUC E KIYEOKSIOS + 0xA09A: 0xC821, //HANGUL SYLLABLE CIEUC E NIEUNCIEUC + 0xA09B: 0xC822, //HANGUL SYLLABLE CIEUC E NIEUNHIEUH + 0xA09C: 0xC823, //HANGUL SYLLABLE CIEUC E TIKEUT + 0xA09D: 0xC825, //HANGUL SYLLABLE CIEUC E RIEULKIYEOK + 0xA09E: 0xC826, //HANGUL SYLLABLE CIEUC E RIEULMIEUM + 0xA09F: 0xC827, //HANGUL SYLLABLE CIEUC E RIEULPIEUP + 0xA0A0: 0xC828, //HANGUL SYLLABLE CIEUC E RIEULSIOS + 0xA0A1: 0xC829, //HANGUL SYLLABLE CIEUC E RIEULTHIEUTH + 0xA0A2: 0xC82A, //HANGUL SYLLABLE CIEUC E RIEULPHIEUPH + 0xA0A3: 0xC82B, //HANGUL SYLLABLE CIEUC E RIEULHIEUH + 0xA0A4: 0xC82E, //HANGUL SYLLABLE CIEUC E PIEUPSIOS + 0xA0A5: 0xC830, //HANGUL SYLLABLE CIEUC E SSANGSIOS + 0xA0A6: 0xC832, //HANGUL SYLLABLE CIEUC E CIEUC + 0xA0A7: 0xC833, //HANGUL SYLLABLE CIEUC E CHIEUCH + 0xA0A8: 0xC834, //HANGUL SYLLABLE CIEUC E KHIEUKH + 0xA0A9: 0xC835, //HANGUL SYLLABLE CIEUC E THIEUTH + 0xA0AA: 0xC836, //HANGUL SYLLABLE CIEUC E PHIEUPH + 0xA0AB: 0xC837, //HANGUL SYLLABLE CIEUC E HIEUH + 0xA0AC: 0xC839, //HANGUL SYLLABLE CIEUC YEO KIYEOK + 0xA0AD: 0xC83A, //HANGUL SYLLABLE CIEUC YEO SSANGKIYEOK + 0xA0AE: 0xC83B, //HANGUL SYLLABLE CIEUC YEO KIYEOKSIOS + 0xA0AF: 0xC83D, //HANGUL SYLLABLE CIEUC YEO NIEUNCIEUC + 0xA0B0: 0xC83E, //HANGUL SYLLABLE CIEUC YEO NIEUNHIEUH + 0xA0B1: 0xC83F, //HANGUL SYLLABLE CIEUC YEO TIKEUT + 0xA0B2: 0xC841, //HANGUL SYLLABLE CIEUC YEO RIEULKIYEOK + 0xA0B3: 0xC842, //HANGUL SYLLABLE CIEUC YEO RIEULMIEUM + 0xA0B4: 0xC843, //HANGUL SYLLABLE CIEUC YEO RIEULPIEUP + 0xA0B5: 0xC844, //HANGUL SYLLABLE CIEUC YEO RIEULSIOS + 0xA0B6: 0xC845, //HANGUL SYLLABLE CIEUC YEO RIEULTHIEUTH + 0xA0B7: 0xC846, //HANGUL SYLLABLE CIEUC YEO RIEULPHIEUPH + 0xA0B8: 0xC847, //HANGUL SYLLABLE CIEUC YEO RIEULHIEUH + 0xA0B9: 0xC84A, //HANGUL SYLLABLE CIEUC YEO PIEUPSIOS + 0xA0BA: 0xC84B, //HANGUL SYLLABLE CIEUC YEO SIOS + 0xA0BB: 0xC84E, //HANGUL SYLLABLE CIEUC YEO CIEUC + 0xA0BC: 0xC84F, //HANGUL SYLLABLE CIEUC YEO CHIEUCH + 0xA0BD: 0xC850, //HANGUL SYLLABLE CIEUC YEO KHIEUKH + 0xA0BE: 0xC851, //HANGUL SYLLABLE CIEUC YEO THIEUTH + 0xA0BF: 0xC852, //HANGUL SYLLABLE CIEUC YEO PHIEUPH + 0xA0C0: 0xC853, //HANGUL SYLLABLE CIEUC YEO HIEUH + 0xA0C1: 0xC855, //HANGUL SYLLABLE CIEUC YE KIYEOK + 0xA0C2: 0xC856, //HANGUL SYLLABLE CIEUC YE SSANGKIYEOK + 0xA0C3: 0xC857, //HANGUL SYLLABLE CIEUC YE KIYEOKSIOS + 0xA0C4: 0xC858, //HANGUL SYLLABLE CIEUC YE NIEUN + 0xA0C5: 0xC859, //HANGUL SYLLABLE CIEUC YE NIEUNCIEUC + 0xA0C6: 0xC85A, //HANGUL SYLLABLE CIEUC YE NIEUNHIEUH + 0xA0C7: 0xC85B, //HANGUL SYLLABLE CIEUC YE TIKEUT + 0xA0C8: 0xC85C, //HANGUL SYLLABLE CIEUC YE RIEUL + 0xA0C9: 0xC85D, //HANGUL SYLLABLE CIEUC YE RIEULKIYEOK + 0xA0CA: 0xC85E, //HANGUL SYLLABLE CIEUC YE RIEULMIEUM + 0xA0CB: 0xC85F, //HANGUL SYLLABLE CIEUC YE RIEULPIEUP + 0xA0CC: 0xC860, //HANGUL SYLLABLE CIEUC YE RIEULSIOS + 0xA0CD: 0xC861, //HANGUL SYLLABLE CIEUC YE RIEULTHIEUTH + 0xA0CE: 0xC862, //HANGUL SYLLABLE CIEUC YE RIEULPHIEUPH + 0xA0CF: 0xC863, //HANGUL SYLLABLE CIEUC YE RIEULHIEUH + 0xA0D0: 0xC864, //HANGUL SYLLABLE CIEUC YE MIEUM + 0xA0D1: 0xC865, //HANGUL SYLLABLE CIEUC YE PIEUP + 0xA0D2: 0xC866, //HANGUL SYLLABLE CIEUC YE PIEUPSIOS + 0xA0D3: 0xC867, //HANGUL SYLLABLE CIEUC YE SIOS + 0xA0D4: 0xC868, //HANGUL SYLLABLE CIEUC YE SSANGSIOS + 0xA0D5: 0xC869, //HANGUL SYLLABLE CIEUC YE IEUNG + 0xA0D6: 0xC86A, //HANGUL SYLLABLE CIEUC YE CIEUC + 0xA0D7: 0xC86B, //HANGUL SYLLABLE CIEUC YE CHIEUCH + 0xA0D8: 0xC86C, //HANGUL SYLLABLE CIEUC YE KHIEUKH + 0xA0D9: 0xC86D, //HANGUL SYLLABLE CIEUC YE THIEUTH + 0xA0DA: 0xC86E, //HANGUL SYLLABLE CIEUC YE PHIEUPH + 0xA0DB: 0xC86F, //HANGUL SYLLABLE CIEUC YE HIEUH + 0xA0DC: 0xC872, //HANGUL SYLLABLE CIEUC O SSANGKIYEOK + 0xA0DD: 0xC873, //HANGUL SYLLABLE CIEUC O KIYEOKSIOS + 0xA0DE: 0xC875, //HANGUL SYLLABLE CIEUC O NIEUNCIEUC + 0xA0DF: 0xC876, //HANGUL SYLLABLE CIEUC O NIEUNHIEUH + 0xA0E0: 0xC877, //HANGUL SYLLABLE CIEUC O TIKEUT + 0xA0E1: 0xC879, //HANGUL SYLLABLE CIEUC O RIEULKIYEOK + 0xA0E2: 0xC87B, //HANGUL SYLLABLE CIEUC O RIEULPIEUP + 0xA0E3: 0xC87C, //HANGUL SYLLABLE CIEUC O RIEULSIOS + 0xA0E4: 0xC87D, //HANGUL SYLLABLE CIEUC O RIEULTHIEUTH + 0xA0E5: 0xC87E, //HANGUL SYLLABLE CIEUC O RIEULPHIEUPH + 0xA0E6: 0xC87F, //HANGUL SYLLABLE CIEUC O RIEULHIEUH + 0xA0E7: 0xC882, //HANGUL SYLLABLE CIEUC O PIEUPSIOS + 0xA0E8: 0xC884, //HANGUL SYLLABLE CIEUC O SSANGSIOS + 0xA0E9: 0xC888, //HANGUL SYLLABLE CIEUC O KHIEUKH + 0xA0EA: 0xC889, //HANGUL SYLLABLE CIEUC O THIEUTH + 0xA0EB: 0xC88A, //HANGUL SYLLABLE CIEUC O PHIEUPH + 0xA0EC: 0xC88E, //HANGUL SYLLABLE CIEUC WA SSANGKIYEOK + 0xA0ED: 0xC88F, //HANGUL SYLLABLE CIEUC WA KIYEOKSIOS + 0xA0EE: 0xC890, //HANGUL SYLLABLE CIEUC WA NIEUN + 0xA0EF: 0xC891, //HANGUL SYLLABLE CIEUC WA NIEUNCIEUC + 0xA0F0: 0xC892, //HANGUL SYLLABLE CIEUC WA NIEUNHIEUH + 0xA0F1: 0xC893, //HANGUL SYLLABLE CIEUC WA TIKEUT + 0xA0F2: 0xC895, //HANGUL SYLLABLE CIEUC WA RIEULKIYEOK + 0xA0F3: 0xC896, //HANGUL SYLLABLE CIEUC WA RIEULMIEUM + 0xA0F4: 0xC897, //HANGUL SYLLABLE CIEUC WA RIEULPIEUP + 0xA0F5: 0xC898, //HANGUL SYLLABLE CIEUC WA RIEULSIOS + 0xA0F6: 0xC899, //HANGUL SYLLABLE CIEUC WA RIEULTHIEUTH + 0xA0F7: 0xC89A, //HANGUL SYLLABLE CIEUC WA RIEULPHIEUPH + 0xA0F8: 0xC89B, //HANGUL SYLLABLE CIEUC WA RIEULHIEUH + 0xA0F9: 0xC89C, //HANGUL SYLLABLE CIEUC WA MIEUM + 0xA0FA: 0xC89E, //HANGUL SYLLABLE CIEUC WA PIEUPSIOS + 0xA0FB: 0xC8A0, //HANGUL SYLLABLE CIEUC WA SSANGSIOS + 0xA0FC: 0xC8A2, //HANGUL SYLLABLE CIEUC WA CIEUC + 0xA0FD: 0xC8A3, //HANGUL SYLLABLE CIEUC WA CHIEUCH + 0xA0FE: 0xC8A4, //HANGUL SYLLABLE CIEUC WA KHIEUKH + 0xA141: 0xC8A5, //HANGUL SYLLABLE CIEUC WA THIEUTH + 0xA142: 0xC8A6, //HANGUL SYLLABLE CIEUC WA PHIEUPH + 0xA143: 0xC8A7, //HANGUL SYLLABLE CIEUC WA HIEUH + 0xA144: 0xC8A9, //HANGUL SYLLABLE CIEUC WAE KIYEOK + 0xA145: 0xC8AA, //HANGUL SYLLABLE CIEUC WAE SSANGKIYEOK + 0xA146: 0xC8AB, //HANGUL SYLLABLE CIEUC WAE KIYEOKSIOS + 0xA147: 0xC8AC, //HANGUL SYLLABLE CIEUC WAE NIEUN + 0xA148: 0xC8AD, //HANGUL SYLLABLE CIEUC WAE NIEUNCIEUC + 0xA149: 0xC8AE, //HANGUL SYLLABLE CIEUC WAE NIEUNHIEUH + 0xA14A: 0xC8AF, //HANGUL SYLLABLE CIEUC WAE TIKEUT + 0xA14B: 0xC8B0, //HANGUL SYLLABLE CIEUC WAE RIEUL + 0xA14C: 0xC8B1, //HANGUL SYLLABLE CIEUC WAE RIEULKIYEOK + 0xA14D: 0xC8B2, //HANGUL SYLLABLE CIEUC WAE RIEULMIEUM + 0xA14E: 0xC8B3, //HANGUL SYLLABLE CIEUC WAE RIEULPIEUP + 0xA14F: 0xC8B4, //HANGUL SYLLABLE CIEUC WAE RIEULSIOS + 0xA150: 0xC8B5, //HANGUL SYLLABLE CIEUC WAE RIEULTHIEUTH + 0xA151: 0xC8B6, //HANGUL SYLLABLE CIEUC WAE RIEULPHIEUPH + 0xA152: 0xC8B7, //HANGUL SYLLABLE CIEUC WAE RIEULHIEUH + 0xA153: 0xC8B8, //HANGUL SYLLABLE CIEUC WAE MIEUM + 0xA154: 0xC8B9, //HANGUL SYLLABLE CIEUC WAE PIEUP + 0xA155: 0xC8BA, //HANGUL SYLLABLE CIEUC WAE PIEUPSIOS + 0xA156: 0xC8BB, //HANGUL SYLLABLE CIEUC WAE SIOS + 0xA157: 0xC8BE, //HANGUL SYLLABLE CIEUC WAE CIEUC + 0xA158: 0xC8BF, //HANGUL SYLLABLE CIEUC WAE CHIEUCH + 0xA159: 0xC8C0, //HANGUL SYLLABLE CIEUC WAE KHIEUKH + 0xA15A: 0xC8C1, //HANGUL SYLLABLE CIEUC WAE THIEUTH + 0xA161: 0xC8C2, //HANGUL SYLLABLE CIEUC WAE PHIEUPH + 0xA162: 0xC8C3, //HANGUL SYLLABLE CIEUC WAE HIEUH + 0xA163: 0xC8C5, //HANGUL SYLLABLE CIEUC OE KIYEOK + 0xA164: 0xC8C6, //HANGUL SYLLABLE CIEUC OE SSANGKIYEOK + 0xA165: 0xC8C7, //HANGUL SYLLABLE CIEUC OE KIYEOKSIOS + 0xA166: 0xC8C9, //HANGUL SYLLABLE CIEUC OE NIEUNCIEUC + 0xA167: 0xC8CA, //HANGUL SYLLABLE CIEUC OE NIEUNHIEUH + 0xA168: 0xC8CB, //HANGUL SYLLABLE CIEUC OE TIKEUT + 0xA169: 0xC8CD, //HANGUL SYLLABLE CIEUC OE RIEULKIYEOK + 0xA16A: 0xC8CE, //HANGUL SYLLABLE CIEUC OE RIEULMIEUM + 0xA16B: 0xC8CF, //HANGUL SYLLABLE CIEUC OE RIEULPIEUP + 0xA16C: 0xC8D0, //HANGUL SYLLABLE CIEUC OE RIEULSIOS + 0xA16D: 0xC8D1, //HANGUL SYLLABLE CIEUC OE RIEULTHIEUTH + 0xA16E: 0xC8D2, //HANGUL SYLLABLE CIEUC OE RIEULPHIEUPH + 0xA16F: 0xC8D3, //HANGUL SYLLABLE CIEUC OE RIEULHIEUH + 0xA170: 0xC8D6, //HANGUL SYLLABLE CIEUC OE PIEUPSIOS + 0xA171: 0xC8D8, //HANGUL SYLLABLE CIEUC OE SSANGSIOS + 0xA172: 0xC8DA, //HANGUL SYLLABLE CIEUC OE CIEUC + 0xA173: 0xC8DB, //HANGUL SYLLABLE CIEUC OE CHIEUCH + 0xA174: 0xC8DC, //HANGUL SYLLABLE CIEUC OE KHIEUKH + 0xA175: 0xC8DD, //HANGUL SYLLABLE CIEUC OE THIEUTH + 0xA176: 0xC8DE, //HANGUL SYLLABLE CIEUC OE PHIEUPH + 0xA177: 0xC8DF, //HANGUL SYLLABLE CIEUC OE HIEUH + 0xA178: 0xC8E2, //HANGUL SYLLABLE CIEUC YO SSANGKIYEOK + 0xA179: 0xC8E3, //HANGUL SYLLABLE CIEUC YO KIYEOKSIOS + 0xA17A: 0xC8E5, //HANGUL SYLLABLE CIEUC YO NIEUNCIEUC + 0xA181: 0xC8E6, //HANGUL SYLLABLE CIEUC YO NIEUNHIEUH + 0xA182: 0xC8E7, //HANGUL SYLLABLE CIEUC YO TIKEUT + 0xA183: 0xC8E8, //HANGUL SYLLABLE CIEUC YO RIEUL + 0xA184: 0xC8E9, //HANGUL SYLLABLE CIEUC YO RIEULKIYEOK + 0xA185: 0xC8EA, //HANGUL SYLLABLE CIEUC YO RIEULMIEUM + 0xA186: 0xC8EB, //HANGUL SYLLABLE CIEUC YO RIEULPIEUP + 0xA187: 0xC8EC, //HANGUL SYLLABLE CIEUC YO RIEULSIOS + 0xA188: 0xC8ED, //HANGUL SYLLABLE CIEUC YO RIEULTHIEUTH + 0xA189: 0xC8EE, //HANGUL SYLLABLE CIEUC YO RIEULPHIEUPH + 0xA18A: 0xC8EF, //HANGUL SYLLABLE CIEUC YO RIEULHIEUH + 0xA18B: 0xC8F0, //HANGUL SYLLABLE CIEUC YO MIEUM + 0xA18C: 0xC8F1, //HANGUL SYLLABLE CIEUC YO PIEUP + 0xA18D: 0xC8F2, //HANGUL SYLLABLE CIEUC YO PIEUPSIOS + 0xA18E: 0xC8F3, //HANGUL SYLLABLE CIEUC YO SIOS + 0xA18F: 0xC8F4, //HANGUL SYLLABLE CIEUC YO SSANGSIOS + 0xA190: 0xC8F6, //HANGUL SYLLABLE CIEUC YO CIEUC + 0xA191: 0xC8F7, //HANGUL SYLLABLE CIEUC YO CHIEUCH + 0xA192: 0xC8F8, //HANGUL SYLLABLE CIEUC YO KHIEUKH + 0xA193: 0xC8F9, //HANGUL SYLLABLE CIEUC YO THIEUTH + 0xA194: 0xC8FA, //HANGUL SYLLABLE CIEUC YO PHIEUPH + 0xA195: 0xC8FB, //HANGUL SYLLABLE CIEUC YO HIEUH + 0xA196: 0xC8FE, //HANGUL SYLLABLE CIEUC U SSANGKIYEOK + 0xA197: 0xC8FF, //HANGUL SYLLABLE CIEUC U KIYEOKSIOS + 0xA198: 0xC901, //HANGUL SYLLABLE CIEUC U NIEUNCIEUC + 0xA199: 0xC902, //HANGUL SYLLABLE CIEUC U NIEUNHIEUH + 0xA19A: 0xC903, //HANGUL SYLLABLE CIEUC U TIKEUT + 0xA19B: 0xC907, //HANGUL SYLLABLE CIEUC U RIEULPIEUP + 0xA19C: 0xC908, //HANGUL SYLLABLE CIEUC U RIEULSIOS + 0xA19D: 0xC909, //HANGUL SYLLABLE CIEUC U RIEULTHIEUTH + 0xA19E: 0xC90A, //HANGUL SYLLABLE CIEUC U RIEULPHIEUPH + 0xA19F: 0xC90B, //HANGUL SYLLABLE CIEUC U RIEULHIEUH + 0xA1A0: 0xC90E, //HANGUL SYLLABLE CIEUC U PIEUPSIOS + 0xA1A1: 0x3000, //IDEOGRAPHIC SPACE + 0xA1A2: 0x3001, //IDEOGRAPHIC COMMA + 0xA1A3: 0x3002, //IDEOGRAPHIC FULL STOP + 0xA1A4: 0x00B7, //MIDDLE DOT + 0xA1A5: 0x2025, //TWO DOT LEADER + 0xA1A6: 0x2026, //HORIZONTAL ELLIPSIS + 0xA1A7: 0x00A8, //DIAERESIS + 0xA1A8: 0x3003, //DITTO MARK + 0xA1A9: 0x00AD, //SOFT HYPHEN + 0xA1AA: 0x2015, //HORIZONTAL BAR + 0xA1AB: 0x2225, //PARALLEL TO + 0xA1AC: 0xFF3C, //FULLWIDTH REVERSE SOLIDUS + 0xA1AD: 0x223C, //TILDE OPERATOR + 0xA1AE: 0x2018, //LEFT SINGLE QUOTATION MARK + 0xA1AF: 0x2019, //RIGHT SINGLE QUOTATION MARK + 0xA1B0: 0x201C, //LEFT DOUBLE QUOTATION MARK + 0xA1B1: 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0xA1B2: 0x3014, //LEFT TORTOISE SHELL BRACKET + 0xA1B3: 0x3015, //RIGHT TORTOISE SHELL BRACKET + 0xA1B4: 0x3008, //LEFT ANGLE BRACKET + 0xA1B5: 0x3009, //RIGHT ANGLE BRACKET + 0xA1B6: 0x300A, //LEFT DOUBLE ANGLE BRACKET + 0xA1B7: 0x300B, //RIGHT DOUBLE ANGLE BRACKET + 0xA1B8: 0x300C, //LEFT CORNER BRACKET + 0xA1B9: 0x300D, //RIGHT CORNER BRACKET + 0xA1BA: 0x300E, //LEFT WHITE CORNER BRACKET + 0xA1BB: 0x300F, //RIGHT WHITE CORNER BRACKET + 0xA1BC: 0x3010, //LEFT BLACK LENTICULAR BRACKET + 0xA1BD: 0x3011, //RIGHT BLACK LENTICULAR BRACKET + 0xA1BE: 0x00B1, //PLUS-MINUS SIGN + 0xA1BF: 0x00D7, //MULTIPLICATION SIGN + 0xA1C0: 0x00F7, //DIVISION SIGN + 0xA1C1: 0x2260, //NOT EQUAL TO + 0xA1C2: 0x2264, //LESS-THAN OR EQUAL TO + 0xA1C3: 0x2265, //GREATER-THAN OR EQUAL TO + 0xA1C4: 0x221E, //INFINITY + 0xA1C5: 0x2234, //THEREFORE + 0xA1C6: 0x00B0, //DEGREE SIGN + 0xA1C7: 0x2032, //PRIME + 0xA1C8: 0x2033, //DOUBLE PRIME + 0xA1C9: 0x2103, //DEGREE CELSIUS + 0xA1CA: 0x212B, //ANGSTROM SIGN + 0xA1CB: 0xFFE0, //FULLWIDTH CENT SIGN + 0xA1CC: 0xFFE1, //FULLWIDTH POUND SIGN + 0xA1CD: 0xFFE5, //FULLWIDTH YEN SIGN + 0xA1CE: 0x2642, //MALE SIGN + 0xA1CF: 0x2640, //FEMALE SIGN + 0xA1D0: 0x2220, //ANGLE + 0xA1D1: 0x22A5, //UP TACK + 0xA1D2: 0x2312, //ARC + 0xA1D3: 0x2202, //PARTIAL DIFFERENTIAL + 0xA1D4: 0x2207, //NABLA + 0xA1D5: 0x2261, //IDENTICAL TO + 0xA1D6: 0x2252, //APPROXIMATELY EQUAL TO OR THE IMAGE OF + 0xA1D7: 0x00A7, //SECTION SIGN + 0xA1D8: 0x203B, //REFERENCE MARK + 0xA1D9: 0x2606, //WHITE STAR + 0xA1DA: 0x2605, //BLACK STAR + 0xA1DB: 0x25CB, //WHITE CIRCLE + 0xA1DC: 0x25CF, //BLACK CIRCLE + 0xA1DD: 0x25CE, //BULLSEYE + 0xA1DE: 0x25C7, //WHITE DIAMOND + 0xA1DF: 0x25C6, //BLACK DIAMOND + 0xA1E0: 0x25A1, //WHITE SQUARE + 0xA1E1: 0x25A0, //BLACK SQUARE + 0xA1E2: 0x25B3, //WHITE UP-POINTING TRIANGLE + 0xA1E3: 0x25B2, //BLACK UP-POINTING TRIANGLE + 0xA1E4: 0x25BD, //WHITE DOWN-POINTING TRIANGLE + 0xA1E5: 0x25BC, //BLACK DOWN-POINTING TRIANGLE + 0xA1E6: 0x2192, //RIGHTWARDS ARROW + 0xA1E7: 0x2190, //LEFTWARDS ARROW + 0xA1E8: 0x2191, //UPWARDS ARROW + 0xA1E9: 0x2193, //DOWNWARDS ARROW + 0xA1EA: 0x2194, //LEFT RIGHT ARROW + 0xA1EB: 0x3013, //GETA MARK + 0xA1EC: 0x226A, //MUCH LESS-THAN + 0xA1ED: 0x226B, //MUCH GREATER-THAN + 0xA1EE: 0x221A, //SQUARE ROOT + 0xA1EF: 0x223D, //REVERSED TILDE + 0xA1F0: 0x221D, //PROPORTIONAL TO + 0xA1F1: 0x2235, //BECAUSE + 0xA1F2: 0x222B, //INTEGRAL + 0xA1F3: 0x222C, //DOUBLE INTEGRAL + 0xA1F4: 0x2208, //ELEMENT OF + 0xA1F5: 0x220B, //CONTAINS AS MEMBER + 0xA1F6: 0x2286, //SUBSET OF OR EQUAL TO + 0xA1F7: 0x2287, //SUPERSET OF OR EQUAL TO + 0xA1F8: 0x2282, //SUBSET OF + 0xA1F9: 0x2283, //SUPERSET OF + 0xA1FA: 0x222A, //UNION + 0xA1FB: 0x2229, //INTERSECTION + 0xA1FC: 0x2227, //LOGICAL AND + 0xA1FD: 0x2228, //LOGICAL OR + 0xA1FE: 0xFFE2, //FULLWIDTH NOT SIGN + 0xA241: 0xC910, //HANGUL SYLLABLE CIEUC U SSANGSIOS + 0xA242: 0xC912, //HANGUL SYLLABLE CIEUC U CIEUC + 0xA243: 0xC913, //HANGUL SYLLABLE CIEUC U CHIEUCH + 0xA244: 0xC914, //HANGUL SYLLABLE CIEUC U KHIEUKH + 0xA245: 0xC915, //HANGUL SYLLABLE CIEUC U THIEUTH + 0xA246: 0xC916, //HANGUL SYLLABLE CIEUC U PHIEUPH + 0xA247: 0xC917, //HANGUL SYLLABLE CIEUC U HIEUH + 0xA248: 0xC919, //HANGUL SYLLABLE CIEUC WEO KIYEOK + 0xA249: 0xC91A, //HANGUL SYLLABLE CIEUC WEO SSANGKIYEOK + 0xA24A: 0xC91B, //HANGUL SYLLABLE CIEUC WEO KIYEOKSIOS + 0xA24B: 0xC91C, //HANGUL SYLLABLE CIEUC WEO NIEUN + 0xA24C: 0xC91D, //HANGUL SYLLABLE CIEUC WEO NIEUNCIEUC + 0xA24D: 0xC91E, //HANGUL SYLLABLE CIEUC WEO NIEUNHIEUH + 0xA24E: 0xC91F, //HANGUL SYLLABLE CIEUC WEO TIKEUT + 0xA24F: 0xC920, //HANGUL SYLLABLE CIEUC WEO RIEUL + 0xA250: 0xC921, //HANGUL SYLLABLE CIEUC WEO RIEULKIYEOK + 0xA251: 0xC922, //HANGUL SYLLABLE CIEUC WEO RIEULMIEUM + 0xA252: 0xC923, //HANGUL SYLLABLE CIEUC WEO RIEULPIEUP + 0xA253: 0xC924, //HANGUL SYLLABLE CIEUC WEO RIEULSIOS + 0xA254: 0xC925, //HANGUL SYLLABLE CIEUC WEO RIEULTHIEUTH + 0xA255: 0xC926, //HANGUL SYLLABLE CIEUC WEO RIEULPHIEUPH + 0xA256: 0xC927, //HANGUL SYLLABLE CIEUC WEO RIEULHIEUH + 0xA257: 0xC928, //HANGUL SYLLABLE CIEUC WEO MIEUM + 0xA258: 0xC929, //HANGUL SYLLABLE CIEUC WEO PIEUP + 0xA259: 0xC92A, //HANGUL SYLLABLE CIEUC WEO PIEUPSIOS + 0xA25A: 0xC92B, //HANGUL SYLLABLE CIEUC WEO SIOS + 0xA261: 0xC92D, //HANGUL SYLLABLE CIEUC WEO IEUNG + 0xA262: 0xC92E, //HANGUL SYLLABLE CIEUC WEO CIEUC + 0xA263: 0xC92F, //HANGUL SYLLABLE CIEUC WEO CHIEUCH + 0xA264: 0xC930, //HANGUL SYLLABLE CIEUC WEO KHIEUKH + 0xA265: 0xC931, //HANGUL SYLLABLE CIEUC WEO THIEUTH + 0xA266: 0xC932, //HANGUL SYLLABLE CIEUC WEO PHIEUPH + 0xA267: 0xC933, //HANGUL SYLLABLE CIEUC WEO HIEUH + 0xA268: 0xC935, //HANGUL SYLLABLE CIEUC WE KIYEOK + 0xA269: 0xC936, //HANGUL SYLLABLE CIEUC WE SSANGKIYEOK + 0xA26A: 0xC937, //HANGUL SYLLABLE CIEUC WE KIYEOKSIOS + 0xA26B: 0xC938, //HANGUL SYLLABLE CIEUC WE NIEUN + 0xA26C: 0xC939, //HANGUL SYLLABLE CIEUC WE NIEUNCIEUC + 0xA26D: 0xC93A, //HANGUL SYLLABLE CIEUC WE NIEUNHIEUH + 0xA26E: 0xC93B, //HANGUL SYLLABLE CIEUC WE TIKEUT + 0xA26F: 0xC93C, //HANGUL SYLLABLE CIEUC WE RIEUL + 0xA270: 0xC93D, //HANGUL SYLLABLE CIEUC WE RIEULKIYEOK + 0xA271: 0xC93E, //HANGUL SYLLABLE CIEUC WE RIEULMIEUM + 0xA272: 0xC93F, //HANGUL SYLLABLE CIEUC WE RIEULPIEUP + 0xA273: 0xC940, //HANGUL SYLLABLE CIEUC WE RIEULSIOS + 0xA274: 0xC941, //HANGUL SYLLABLE CIEUC WE RIEULTHIEUTH + 0xA275: 0xC942, //HANGUL SYLLABLE CIEUC WE RIEULPHIEUPH + 0xA276: 0xC943, //HANGUL SYLLABLE CIEUC WE RIEULHIEUH + 0xA277: 0xC944, //HANGUL SYLLABLE CIEUC WE MIEUM + 0xA278: 0xC945, //HANGUL SYLLABLE CIEUC WE PIEUP + 0xA279: 0xC946, //HANGUL SYLLABLE CIEUC WE PIEUPSIOS + 0xA27A: 0xC947, //HANGUL SYLLABLE CIEUC WE SIOS + 0xA281: 0xC948, //HANGUL SYLLABLE CIEUC WE SSANGSIOS + 0xA282: 0xC949, //HANGUL SYLLABLE CIEUC WE IEUNG + 0xA283: 0xC94A, //HANGUL SYLLABLE CIEUC WE CIEUC + 0xA284: 0xC94B, //HANGUL SYLLABLE CIEUC WE CHIEUCH + 0xA285: 0xC94C, //HANGUL SYLLABLE CIEUC WE KHIEUKH + 0xA286: 0xC94D, //HANGUL SYLLABLE CIEUC WE THIEUTH + 0xA287: 0xC94E, //HANGUL SYLLABLE CIEUC WE PHIEUPH + 0xA288: 0xC94F, //HANGUL SYLLABLE CIEUC WE HIEUH + 0xA289: 0xC952, //HANGUL SYLLABLE CIEUC WI SSANGKIYEOK + 0xA28A: 0xC953, //HANGUL SYLLABLE CIEUC WI KIYEOKSIOS + 0xA28B: 0xC955, //HANGUL SYLLABLE CIEUC WI NIEUNCIEUC + 0xA28C: 0xC956, //HANGUL SYLLABLE CIEUC WI NIEUNHIEUH + 0xA28D: 0xC957, //HANGUL SYLLABLE CIEUC WI TIKEUT + 0xA28E: 0xC959, //HANGUL SYLLABLE CIEUC WI RIEULKIYEOK + 0xA28F: 0xC95A, //HANGUL SYLLABLE CIEUC WI RIEULMIEUM + 0xA290: 0xC95B, //HANGUL SYLLABLE CIEUC WI RIEULPIEUP + 0xA291: 0xC95C, //HANGUL SYLLABLE CIEUC WI RIEULSIOS + 0xA292: 0xC95D, //HANGUL SYLLABLE CIEUC WI RIEULTHIEUTH + 0xA293: 0xC95E, //HANGUL SYLLABLE CIEUC WI RIEULPHIEUPH + 0xA294: 0xC95F, //HANGUL SYLLABLE CIEUC WI RIEULHIEUH + 0xA295: 0xC962, //HANGUL SYLLABLE CIEUC WI PIEUPSIOS + 0xA296: 0xC964, //HANGUL SYLLABLE CIEUC WI SSANGSIOS + 0xA297: 0xC965, //HANGUL SYLLABLE CIEUC WI IEUNG + 0xA298: 0xC966, //HANGUL SYLLABLE CIEUC WI CIEUC + 0xA299: 0xC967, //HANGUL SYLLABLE CIEUC WI CHIEUCH + 0xA29A: 0xC968, //HANGUL SYLLABLE CIEUC WI KHIEUKH + 0xA29B: 0xC969, //HANGUL SYLLABLE CIEUC WI THIEUTH + 0xA29C: 0xC96A, //HANGUL SYLLABLE CIEUC WI PHIEUPH + 0xA29D: 0xC96B, //HANGUL SYLLABLE CIEUC WI HIEUH + 0xA29E: 0xC96D, //HANGUL SYLLABLE CIEUC YU KIYEOK + 0xA29F: 0xC96E, //HANGUL SYLLABLE CIEUC YU SSANGKIYEOK + 0xA2A0: 0xC96F, //HANGUL SYLLABLE CIEUC YU KIYEOKSIOS + 0xA2A1: 0x21D2, //RIGHTWARDS DOUBLE ARROW + 0xA2A2: 0x21D4, //LEFT RIGHT DOUBLE ARROW + 0xA2A3: 0x2200, //FOR ALL + 0xA2A4: 0x2203, //THERE EXISTS + 0xA2A5: 0x00B4, //ACUTE ACCENT + 0xA2A6: 0xFF5E, //FULLWIDTH TILDE + 0xA2A7: 0x02C7, //CARON + 0xA2A8: 0x02D8, //BREVE + 0xA2A9: 0x02DD, //DOUBLE ACUTE ACCENT + 0xA2AA: 0x02DA, //RING ABOVE + 0xA2AB: 0x02D9, //DOT ABOVE + 0xA2AC: 0x00B8, //CEDILLA + 0xA2AD: 0x02DB, //OGONEK + 0xA2AE: 0x00A1, //INVERTED EXCLAMATION MARK + 0xA2AF: 0x00BF, //INVERTED QUESTION MARK + 0xA2B0: 0x02D0, //MODIFIER LETTER TRIANGULAR COLON + 0xA2B1: 0x222E, //CONTOUR INTEGRAL + 0xA2B2: 0x2211, //N-ARY SUMMATION + 0xA2B3: 0x220F, //N-ARY PRODUCT + 0xA2B4: 0x00A4, //CURRENCY SIGN + 0xA2B5: 0x2109, //DEGREE FAHRENHEIT + 0xA2B6: 0x2030, //PER MILLE SIGN + 0xA2B7: 0x25C1, //WHITE LEFT-POINTING TRIANGLE + 0xA2B8: 0x25C0, //BLACK LEFT-POINTING TRIANGLE + 0xA2B9: 0x25B7, //WHITE RIGHT-POINTING TRIANGLE + 0xA2BA: 0x25B6, //BLACK RIGHT-POINTING TRIANGLE + 0xA2BB: 0x2664, //WHITE SPADE SUIT + 0xA2BC: 0x2660, //BLACK SPADE SUIT + 0xA2BD: 0x2661, //WHITE HEART SUIT + 0xA2BE: 0x2665, //BLACK HEART SUIT + 0xA2BF: 0x2667, //WHITE CLUB SUIT + 0xA2C0: 0x2663, //BLACK CLUB SUIT + 0xA2C1: 0x2299, //CIRCLED DOT OPERATOR + 0xA2C2: 0x25C8, //WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND + 0xA2C3: 0x25A3, //WHITE SQUARE CONTAINING BLACK SMALL SQUARE + 0xA2C4: 0x25D0, //CIRCLE WITH LEFT HALF BLACK + 0xA2C5: 0x25D1, //CIRCLE WITH RIGHT HALF BLACK + 0xA2C6: 0x2592, //MEDIUM SHADE + 0xA2C7: 0x25A4, //SQUARE WITH HORIZONTAL FILL + 0xA2C8: 0x25A5, //SQUARE WITH VERTICAL FILL + 0xA2C9: 0x25A8, //SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL + 0xA2CA: 0x25A7, //SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL + 0xA2CB: 0x25A6, //SQUARE WITH ORTHOGONAL CROSSHATCH FILL + 0xA2CC: 0x25A9, //SQUARE WITH DIAGONAL CROSSHATCH FILL + 0xA2CD: 0x2668, //HOT SPRINGS + 0xA2CE: 0x260F, //WHITE TELEPHONE + 0xA2CF: 0x260E, //BLACK TELEPHONE + 0xA2D0: 0x261C, //WHITE LEFT POINTING INDEX + 0xA2D1: 0x261E, //WHITE RIGHT POINTING INDEX + 0xA2D2: 0x00B6, //PILCROW SIGN + 0xA2D3: 0x2020, //DAGGER + 0xA2D4: 0x2021, //DOUBLE DAGGER + 0xA2D5: 0x2195, //UP DOWN ARROW + 0xA2D6: 0x2197, //NORTH EAST ARROW + 0xA2D7: 0x2199, //SOUTH WEST ARROW + 0xA2D8: 0x2196, //NORTH WEST ARROW + 0xA2D9: 0x2198, //SOUTH EAST ARROW + 0xA2DA: 0x266D, //MUSIC FLAT SIGN + 0xA2DB: 0x2669, //QUARTER NOTE + 0xA2DC: 0x266A, //EIGHTH NOTE + 0xA2DD: 0x266C, //BEAMED SIXTEENTH NOTES + 0xA2DE: 0x327F, //KOREAN STANDARD SYMBOL + 0xA2DF: 0x321C, //PARENTHESIZED HANGUL CIEUC U + 0xA2E0: 0x2116, //NUMERO SIGN + 0xA2E1: 0x33C7, //SQUARE CO + 0xA2E2: 0x2122, //TRADE MARK SIGN + 0xA2E3: 0x33C2, //SQUARE AM + 0xA2E4: 0x33D8, //SQUARE PM + 0xA2E5: 0x2121, //TELEPHONE SIGN + 0xA2E6: 0x20AC, //EURO SIGN + 0xA2E7: 0x00AE, //REGISTERED SIGN + 0xA341: 0xC971, //HANGUL SYLLABLE CIEUC YU NIEUNCIEUC + 0xA342: 0xC972, //HANGUL SYLLABLE CIEUC YU NIEUNHIEUH + 0xA343: 0xC973, //HANGUL SYLLABLE CIEUC YU TIKEUT + 0xA344: 0xC975, //HANGUL SYLLABLE CIEUC YU RIEULKIYEOK + 0xA345: 0xC976, //HANGUL SYLLABLE CIEUC YU RIEULMIEUM + 0xA346: 0xC977, //HANGUL SYLLABLE CIEUC YU RIEULPIEUP + 0xA347: 0xC978, //HANGUL SYLLABLE CIEUC YU RIEULSIOS + 0xA348: 0xC979, //HANGUL SYLLABLE CIEUC YU RIEULTHIEUTH + 0xA349: 0xC97A, //HANGUL SYLLABLE CIEUC YU RIEULPHIEUPH + 0xA34A: 0xC97B, //HANGUL SYLLABLE CIEUC YU RIEULHIEUH + 0xA34B: 0xC97D, //HANGUL SYLLABLE CIEUC YU PIEUP + 0xA34C: 0xC97E, //HANGUL SYLLABLE CIEUC YU PIEUPSIOS + 0xA34D: 0xC97F, //HANGUL SYLLABLE CIEUC YU SIOS + 0xA34E: 0xC980, //HANGUL SYLLABLE CIEUC YU SSANGSIOS + 0xA34F: 0xC981, //HANGUL SYLLABLE CIEUC YU IEUNG + 0xA350: 0xC982, //HANGUL SYLLABLE CIEUC YU CIEUC + 0xA351: 0xC983, //HANGUL SYLLABLE CIEUC YU CHIEUCH + 0xA352: 0xC984, //HANGUL SYLLABLE CIEUC YU KHIEUKH + 0xA353: 0xC985, //HANGUL SYLLABLE CIEUC YU THIEUTH + 0xA354: 0xC986, //HANGUL SYLLABLE CIEUC YU PHIEUPH + 0xA355: 0xC987, //HANGUL SYLLABLE CIEUC YU HIEUH + 0xA356: 0xC98A, //HANGUL SYLLABLE CIEUC EU SSANGKIYEOK + 0xA357: 0xC98B, //HANGUL SYLLABLE CIEUC EU KIYEOKSIOS + 0xA358: 0xC98D, //HANGUL SYLLABLE CIEUC EU NIEUNCIEUC + 0xA359: 0xC98E, //HANGUL SYLLABLE CIEUC EU NIEUNHIEUH + 0xA35A: 0xC98F, //HANGUL SYLLABLE CIEUC EU TIKEUT + 0xA361: 0xC991, //HANGUL SYLLABLE CIEUC EU RIEULKIYEOK + 0xA362: 0xC992, //HANGUL SYLLABLE CIEUC EU RIEULMIEUM + 0xA363: 0xC993, //HANGUL SYLLABLE CIEUC EU RIEULPIEUP + 0xA364: 0xC994, //HANGUL SYLLABLE CIEUC EU RIEULSIOS + 0xA365: 0xC995, //HANGUL SYLLABLE CIEUC EU RIEULTHIEUTH + 0xA366: 0xC996, //HANGUL SYLLABLE CIEUC EU RIEULPHIEUPH + 0xA367: 0xC997, //HANGUL SYLLABLE CIEUC EU RIEULHIEUH + 0xA368: 0xC99A, //HANGUL SYLLABLE CIEUC EU PIEUPSIOS + 0xA369: 0xC99C, //HANGUL SYLLABLE CIEUC EU SSANGSIOS + 0xA36A: 0xC99E, //HANGUL SYLLABLE CIEUC EU CIEUC + 0xA36B: 0xC99F, //HANGUL SYLLABLE CIEUC EU CHIEUCH + 0xA36C: 0xC9A0, //HANGUL SYLLABLE CIEUC EU KHIEUKH + 0xA36D: 0xC9A1, //HANGUL SYLLABLE CIEUC EU THIEUTH + 0xA36E: 0xC9A2, //HANGUL SYLLABLE CIEUC EU PHIEUPH + 0xA36F: 0xC9A3, //HANGUL SYLLABLE CIEUC EU HIEUH + 0xA370: 0xC9A4, //HANGUL SYLLABLE CIEUC YI + 0xA371: 0xC9A5, //HANGUL SYLLABLE CIEUC YI KIYEOK + 0xA372: 0xC9A6, //HANGUL SYLLABLE CIEUC YI SSANGKIYEOK + 0xA373: 0xC9A7, //HANGUL SYLLABLE CIEUC YI KIYEOKSIOS + 0xA374: 0xC9A8, //HANGUL SYLLABLE CIEUC YI NIEUN + 0xA375: 0xC9A9, //HANGUL SYLLABLE CIEUC YI NIEUNCIEUC + 0xA376: 0xC9AA, //HANGUL SYLLABLE CIEUC YI NIEUNHIEUH + 0xA377: 0xC9AB, //HANGUL SYLLABLE CIEUC YI TIKEUT + 0xA378: 0xC9AC, //HANGUL SYLLABLE CIEUC YI RIEUL + 0xA379: 0xC9AD, //HANGUL SYLLABLE CIEUC YI RIEULKIYEOK + 0xA37A: 0xC9AE, //HANGUL SYLLABLE CIEUC YI RIEULMIEUM + 0xA381: 0xC9AF, //HANGUL SYLLABLE CIEUC YI RIEULPIEUP + 0xA382: 0xC9B0, //HANGUL SYLLABLE CIEUC YI RIEULSIOS + 0xA383: 0xC9B1, //HANGUL SYLLABLE CIEUC YI RIEULTHIEUTH + 0xA384: 0xC9B2, //HANGUL SYLLABLE CIEUC YI RIEULPHIEUPH + 0xA385: 0xC9B3, //HANGUL SYLLABLE CIEUC YI RIEULHIEUH + 0xA386: 0xC9B4, //HANGUL SYLLABLE CIEUC YI MIEUM + 0xA387: 0xC9B5, //HANGUL SYLLABLE CIEUC YI PIEUP + 0xA388: 0xC9B6, //HANGUL SYLLABLE CIEUC YI PIEUPSIOS + 0xA389: 0xC9B7, //HANGUL SYLLABLE CIEUC YI SIOS + 0xA38A: 0xC9B8, //HANGUL SYLLABLE CIEUC YI SSANGSIOS + 0xA38B: 0xC9B9, //HANGUL SYLLABLE CIEUC YI IEUNG + 0xA38C: 0xC9BA, //HANGUL SYLLABLE CIEUC YI CIEUC + 0xA38D: 0xC9BB, //HANGUL SYLLABLE CIEUC YI CHIEUCH + 0xA38E: 0xC9BC, //HANGUL SYLLABLE CIEUC YI KHIEUKH + 0xA38F: 0xC9BD, //HANGUL SYLLABLE CIEUC YI THIEUTH + 0xA390: 0xC9BE, //HANGUL SYLLABLE CIEUC YI PHIEUPH + 0xA391: 0xC9BF, //HANGUL SYLLABLE CIEUC YI HIEUH + 0xA392: 0xC9C2, //HANGUL SYLLABLE CIEUC I SSANGKIYEOK + 0xA393: 0xC9C3, //HANGUL SYLLABLE CIEUC I KIYEOKSIOS + 0xA394: 0xC9C5, //HANGUL SYLLABLE CIEUC I NIEUNCIEUC + 0xA395: 0xC9C6, //HANGUL SYLLABLE CIEUC I NIEUNHIEUH + 0xA396: 0xC9C9, //HANGUL SYLLABLE CIEUC I RIEULKIYEOK + 0xA397: 0xC9CB, //HANGUL SYLLABLE CIEUC I RIEULPIEUP + 0xA398: 0xC9CC, //HANGUL SYLLABLE CIEUC I RIEULSIOS + 0xA399: 0xC9CD, //HANGUL SYLLABLE CIEUC I RIEULTHIEUTH + 0xA39A: 0xC9CE, //HANGUL SYLLABLE CIEUC I RIEULPHIEUPH + 0xA39B: 0xC9CF, //HANGUL SYLLABLE CIEUC I RIEULHIEUH + 0xA39C: 0xC9D2, //HANGUL SYLLABLE CIEUC I PIEUPSIOS + 0xA39D: 0xC9D4, //HANGUL SYLLABLE CIEUC I SSANGSIOS + 0xA39E: 0xC9D7, //HANGUL SYLLABLE CIEUC I CHIEUCH + 0xA39F: 0xC9D8, //HANGUL SYLLABLE CIEUC I KHIEUKH + 0xA3A0: 0xC9DB, //HANGUL SYLLABLE CIEUC I HIEUH + 0xA3A1: 0xFF01, //FULLWIDTH EXCLAMATION MARK + 0xA3A2: 0xFF02, //FULLWIDTH QUOTATION MARK + 0xA3A3: 0xFF03, //FULLWIDTH NUMBER SIGN + 0xA3A4: 0xFF04, //FULLWIDTH DOLLAR SIGN + 0xA3A5: 0xFF05, //FULLWIDTH PERCENT SIGN + 0xA3A6: 0xFF06, //FULLWIDTH AMPERSAND + 0xA3A7: 0xFF07, //FULLWIDTH APOSTROPHE + 0xA3A8: 0xFF08, //FULLWIDTH LEFT PARENTHESIS + 0xA3A9: 0xFF09, //FULLWIDTH RIGHT PARENTHESIS + 0xA3AA: 0xFF0A, //FULLWIDTH ASTERISK + 0xA3AB: 0xFF0B, //FULLWIDTH PLUS SIGN + 0xA3AC: 0xFF0C, //FULLWIDTH COMMA + 0xA3AD: 0xFF0D, //FULLWIDTH HYPHEN-MINUS + 0xA3AE: 0xFF0E, //FULLWIDTH FULL STOP + 0xA3AF: 0xFF0F, //FULLWIDTH SOLIDUS + 0xA3B0: 0xFF10, //FULLWIDTH DIGIT ZERO + 0xA3B1: 0xFF11, //FULLWIDTH DIGIT ONE + 0xA3B2: 0xFF12, //FULLWIDTH DIGIT TWO + 0xA3B3: 0xFF13, //FULLWIDTH DIGIT THREE + 0xA3B4: 0xFF14, //FULLWIDTH DIGIT FOUR + 0xA3B5: 0xFF15, //FULLWIDTH DIGIT FIVE + 0xA3B6: 0xFF16, //FULLWIDTH DIGIT SIX + 0xA3B7: 0xFF17, //FULLWIDTH DIGIT SEVEN + 0xA3B8: 0xFF18, //FULLWIDTH DIGIT EIGHT + 0xA3B9: 0xFF19, //FULLWIDTH DIGIT NINE + 0xA3BA: 0xFF1A, //FULLWIDTH COLON + 0xA3BB: 0xFF1B, //FULLWIDTH SEMICOLON + 0xA3BC: 0xFF1C, //FULLWIDTH LESS-THAN SIGN + 0xA3BD: 0xFF1D, //FULLWIDTH EQUALS SIGN + 0xA3BE: 0xFF1E, //FULLWIDTH GREATER-THAN SIGN + 0xA3BF: 0xFF1F, //FULLWIDTH QUESTION MARK + 0xA3C0: 0xFF20, //FULLWIDTH COMMERCIAL AT + 0xA3C1: 0xFF21, //FULLWIDTH LATIN CAPITAL LETTER A + 0xA3C2: 0xFF22, //FULLWIDTH LATIN CAPITAL LETTER B + 0xA3C3: 0xFF23, //FULLWIDTH LATIN CAPITAL LETTER C + 0xA3C4: 0xFF24, //FULLWIDTH LATIN CAPITAL LETTER D + 0xA3C5: 0xFF25, //FULLWIDTH LATIN CAPITAL LETTER E + 0xA3C6: 0xFF26, //FULLWIDTH LATIN CAPITAL LETTER F + 0xA3C7: 0xFF27, //FULLWIDTH LATIN CAPITAL LETTER G + 0xA3C8: 0xFF28, //FULLWIDTH LATIN CAPITAL LETTER H + 0xA3C9: 0xFF29, //FULLWIDTH LATIN CAPITAL LETTER I + 0xA3CA: 0xFF2A, //FULLWIDTH LATIN CAPITAL LETTER J + 0xA3CB: 0xFF2B, //FULLWIDTH LATIN CAPITAL LETTER K + 0xA3CC: 0xFF2C, //FULLWIDTH LATIN CAPITAL LETTER L + 0xA3CD: 0xFF2D, //FULLWIDTH LATIN CAPITAL LETTER M + 0xA3CE: 0xFF2E, //FULLWIDTH LATIN CAPITAL LETTER N + 0xA3CF: 0xFF2F, //FULLWIDTH LATIN CAPITAL LETTER O + 0xA3D0: 0xFF30, //FULLWIDTH LATIN CAPITAL LETTER P + 0xA3D1: 0xFF31, //FULLWIDTH LATIN CAPITAL LETTER Q + 0xA3D2: 0xFF32, //FULLWIDTH LATIN CAPITAL LETTER R + 0xA3D3: 0xFF33, //FULLWIDTH LATIN CAPITAL LETTER S + 0xA3D4: 0xFF34, //FULLWIDTH LATIN CAPITAL LETTER T + 0xA3D5: 0xFF35, //FULLWIDTH LATIN CAPITAL LETTER U + 0xA3D6: 0xFF36, //FULLWIDTH LATIN CAPITAL LETTER V + 0xA3D7: 0xFF37, //FULLWIDTH LATIN CAPITAL LETTER W + 0xA3D8: 0xFF38, //FULLWIDTH LATIN CAPITAL LETTER X + 0xA3D9: 0xFF39, //FULLWIDTH LATIN CAPITAL LETTER Y + 0xA3DA: 0xFF3A, //FULLWIDTH LATIN CAPITAL LETTER Z + 0xA3DB: 0xFF3B, //FULLWIDTH LEFT SQUARE BRACKET + 0xA3DC: 0xFFE6, //FULLWIDTH WON SIGN + 0xA3DD: 0xFF3D, //FULLWIDTH RIGHT SQUARE BRACKET + 0xA3DE: 0xFF3E, //FULLWIDTH CIRCUMFLEX ACCENT + 0xA3DF: 0xFF3F, //FULLWIDTH LOW LINE + 0xA3E0: 0xFF40, //FULLWIDTH GRAVE ACCENT + 0xA3E1: 0xFF41, //FULLWIDTH LATIN SMALL LETTER A + 0xA3E2: 0xFF42, //FULLWIDTH LATIN SMALL LETTER B + 0xA3E3: 0xFF43, //FULLWIDTH LATIN SMALL LETTER C + 0xA3E4: 0xFF44, //FULLWIDTH LATIN SMALL LETTER D + 0xA3E5: 0xFF45, //FULLWIDTH LATIN SMALL LETTER E + 0xA3E6: 0xFF46, //FULLWIDTH LATIN SMALL LETTER F + 0xA3E7: 0xFF47, //FULLWIDTH LATIN SMALL LETTER G + 0xA3E8: 0xFF48, //FULLWIDTH LATIN SMALL LETTER H + 0xA3E9: 0xFF49, //FULLWIDTH LATIN SMALL LETTER I + 0xA3EA: 0xFF4A, //FULLWIDTH LATIN SMALL LETTER J + 0xA3EB: 0xFF4B, //FULLWIDTH LATIN SMALL LETTER K + 0xA3EC: 0xFF4C, //FULLWIDTH LATIN SMALL LETTER L + 0xA3ED: 0xFF4D, //FULLWIDTH LATIN SMALL LETTER M + 0xA3EE: 0xFF4E, //FULLWIDTH LATIN SMALL LETTER N + 0xA3EF: 0xFF4F, //FULLWIDTH LATIN SMALL LETTER O + 0xA3F0: 0xFF50, //FULLWIDTH LATIN SMALL LETTER P + 0xA3F1: 0xFF51, //FULLWIDTH LATIN SMALL LETTER Q + 0xA3F2: 0xFF52, //FULLWIDTH LATIN SMALL LETTER R + 0xA3F3: 0xFF53, //FULLWIDTH LATIN SMALL LETTER S + 0xA3F4: 0xFF54, //FULLWIDTH LATIN SMALL LETTER T + 0xA3F5: 0xFF55, //FULLWIDTH LATIN SMALL LETTER U + 0xA3F6: 0xFF56, //FULLWIDTH LATIN SMALL LETTER V + 0xA3F7: 0xFF57, //FULLWIDTH LATIN SMALL LETTER W + 0xA3F8: 0xFF58, //FULLWIDTH LATIN SMALL LETTER X + 0xA3F9: 0xFF59, //FULLWIDTH LATIN SMALL LETTER Y + 0xA3FA: 0xFF5A, //FULLWIDTH LATIN SMALL LETTER Z + 0xA3FB: 0xFF5B, //FULLWIDTH LEFT CURLY BRACKET + 0xA3FC: 0xFF5C, //FULLWIDTH VERTICAL LINE + 0xA3FD: 0xFF5D, //FULLWIDTH RIGHT CURLY BRACKET + 0xA3FE: 0xFFE3, //FULLWIDTH MACRON + 0xA441: 0xC9DE, //HANGUL SYLLABLE SSANGCIEUC A SSANGKIYEOK + 0xA442: 0xC9DF, //HANGUL SYLLABLE SSANGCIEUC A KIYEOKSIOS + 0xA443: 0xC9E1, //HANGUL SYLLABLE SSANGCIEUC A NIEUNCIEUC + 0xA444: 0xC9E3, //HANGUL SYLLABLE SSANGCIEUC A TIKEUT + 0xA445: 0xC9E5, //HANGUL SYLLABLE SSANGCIEUC A RIEULKIYEOK + 0xA446: 0xC9E6, //HANGUL SYLLABLE SSANGCIEUC A RIEULMIEUM + 0xA447: 0xC9E8, //HANGUL SYLLABLE SSANGCIEUC A RIEULSIOS + 0xA448: 0xC9E9, //HANGUL SYLLABLE SSANGCIEUC A RIEULTHIEUTH + 0xA449: 0xC9EA, //HANGUL SYLLABLE SSANGCIEUC A RIEULPHIEUPH + 0xA44A: 0xC9EB, //HANGUL SYLLABLE SSANGCIEUC A RIEULHIEUH + 0xA44B: 0xC9EE, //HANGUL SYLLABLE SSANGCIEUC A PIEUPSIOS + 0xA44C: 0xC9F2, //HANGUL SYLLABLE SSANGCIEUC A CIEUC + 0xA44D: 0xC9F3, //HANGUL SYLLABLE SSANGCIEUC A CHIEUCH + 0xA44E: 0xC9F4, //HANGUL SYLLABLE SSANGCIEUC A KHIEUKH + 0xA44F: 0xC9F5, //HANGUL SYLLABLE SSANGCIEUC A THIEUTH + 0xA450: 0xC9F6, //HANGUL SYLLABLE SSANGCIEUC A PHIEUPH + 0xA451: 0xC9F7, //HANGUL SYLLABLE SSANGCIEUC A HIEUH + 0xA452: 0xC9FA, //HANGUL SYLLABLE SSANGCIEUC AE SSANGKIYEOK + 0xA453: 0xC9FB, //HANGUL SYLLABLE SSANGCIEUC AE KIYEOKSIOS + 0xA454: 0xC9FD, //HANGUL SYLLABLE SSANGCIEUC AE NIEUNCIEUC + 0xA455: 0xC9FE, //HANGUL SYLLABLE SSANGCIEUC AE NIEUNHIEUH + 0xA456: 0xC9FF, //HANGUL SYLLABLE SSANGCIEUC AE TIKEUT + 0xA457: 0xCA01, //HANGUL SYLLABLE SSANGCIEUC AE RIEULKIYEOK + 0xA458: 0xCA02, //HANGUL SYLLABLE SSANGCIEUC AE RIEULMIEUM + 0xA459: 0xCA03, //HANGUL SYLLABLE SSANGCIEUC AE RIEULPIEUP + 0xA45A: 0xCA04, //HANGUL SYLLABLE SSANGCIEUC AE RIEULSIOS + 0xA461: 0xCA05, //HANGUL SYLLABLE SSANGCIEUC AE RIEULTHIEUTH + 0xA462: 0xCA06, //HANGUL SYLLABLE SSANGCIEUC AE RIEULPHIEUPH + 0xA463: 0xCA07, //HANGUL SYLLABLE SSANGCIEUC AE RIEULHIEUH + 0xA464: 0xCA0A, //HANGUL SYLLABLE SSANGCIEUC AE PIEUPSIOS + 0xA465: 0xCA0E, //HANGUL SYLLABLE SSANGCIEUC AE CIEUC + 0xA466: 0xCA0F, //HANGUL SYLLABLE SSANGCIEUC AE CHIEUCH + 0xA467: 0xCA10, //HANGUL SYLLABLE SSANGCIEUC AE KHIEUKH + 0xA468: 0xCA11, //HANGUL SYLLABLE SSANGCIEUC AE THIEUTH + 0xA469: 0xCA12, //HANGUL SYLLABLE SSANGCIEUC AE PHIEUPH + 0xA46A: 0xCA13, //HANGUL SYLLABLE SSANGCIEUC AE HIEUH + 0xA46B: 0xCA15, //HANGUL SYLLABLE SSANGCIEUC YA KIYEOK + 0xA46C: 0xCA16, //HANGUL SYLLABLE SSANGCIEUC YA SSANGKIYEOK + 0xA46D: 0xCA17, //HANGUL SYLLABLE SSANGCIEUC YA KIYEOKSIOS + 0xA46E: 0xCA19, //HANGUL SYLLABLE SSANGCIEUC YA NIEUNCIEUC + 0xA46F: 0xCA1A, //HANGUL SYLLABLE SSANGCIEUC YA NIEUNHIEUH + 0xA470: 0xCA1B, //HANGUL SYLLABLE SSANGCIEUC YA TIKEUT + 0xA471: 0xCA1C, //HANGUL SYLLABLE SSANGCIEUC YA RIEUL + 0xA472: 0xCA1D, //HANGUL SYLLABLE SSANGCIEUC YA RIEULKIYEOK + 0xA473: 0xCA1E, //HANGUL SYLLABLE SSANGCIEUC YA RIEULMIEUM + 0xA474: 0xCA1F, //HANGUL SYLLABLE SSANGCIEUC YA RIEULPIEUP + 0xA475: 0xCA20, //HANGUL SYLLABLE SSANGCIEUC YA RIEULSIOS + 0xA476: 0xCA21, //HANGUL SYLLABLE SSANGCIEUC YA RIEULTHIEUTH + 0xA477: 0xCA22, //HANGUL SYLLABLE SSANGCIEUC YA RIEULPHIEUPH + 0xA478: 0xCA23, //HANGUL SYLLABLE SSANGCIEUC YA RIEULHIEUH + 0xA479: 0xCA24, //HANGUL SYLLABLE SSANGCIEUC YA MIEUM + 0xA47A: 0xCA25, //HANGUL SYLLABLE SSANGCIEUC YA PIEUP + 0xA481: 0xCA26, //HANGUL SYLLABLE SSANGCIEUC YA PIEUPSIOS + 0xA482: 0xCA27, //HANGUL SYLLABLE SSANGCIEUC YA SIOS + 0xA483: 0xCA28, //HANGUL SYLLABLE SSANGCIEUC YA SSANGSIOS + 0xA484: 0xCA2A, //HANGUL SYLLABLE SSANGCIEUC YA CIEUC + 0xA485: 0xCA2B, //HANGUL SYLLABLE SSANGCIEUC YA CHIEUCH + 0xA486: 0xCA2C, //HANGUL SYLLABLE SSANGCIEUC YA KHIEUKH + 0xA487: 0xCA2D, //HANGUL SYLLABLE SSANGCIEUC YA THIEUTH + 0xA488: 0xCA2E, //HANGUL SYLLABLE SSANGCIEUC YA PHIEUPH + 0xA489: 0xCA2F, //HANGUL SYLLABLE SSANGCIEUC YA HIEUH + 0xA48A: 0xCA30, //HANGUL SYLLABLE SSANGCIEUC YAE + 0xA48B: 0xCA31, //HANGUL SYLLABLE SSANGCIEUC YAE KIYEOK + 0xA48C: 0xCA32, //HANGUL SYLLABLE SSANGCIEUC YAE SSANGKIYEOK + 0xA48D: 0xCA33, //HANGUL SYLLABLE SSANGCIEUC YAE KIYEOKSIOS + 0xA48E: 0xCA34, //HANGUL SYLLABLE SSANGCIEUC YAE NIEUN + 0xA48F: 0xCA35, //HANGUL SYLLABLE SSANGCIEUC YAE NIEUNCIEUC + 0xA490: 0xCA36, //HANGUL SYLLABLE SSANGCIEUC YAE NIEUNHIEUH + 0xA491: 0xCA37, //HANGUL SYLLABLE SSANGCIEUC YAE TIKEUT + 0xA492: 0xCA38, //HANGUL SYLLABLE SSANGCIEUC YAE RIEUL + 0xA493: 0xCA39, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULKIYEOK + 0xA494: 0xCA3A, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULMIEUM + 0xA495: 0xCA3B, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULPIEUP + 0xA496: 0xCA3C, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULSIOS + 0xA497: 0xCA3D, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULTHIEUTH + 0xA498: 0xCA3E, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULPHIEUPH + 0xA499: 0xCA3F, //HANGUL SYLLABLE SSANGCIEUC YAE RIEULHIEUH + 0xA49A: 0xCA40, //HANGUL SYLLABLE SSANGCIEUC YAE MIEUM + 0xA49B: 0xCA41, //HANGUL SYLLABLE SSANGCIEUC YAE PIEUP + 0xA49C: 0xCA42, //HANGUL SYLLABLE SSANGCIEUC YAE PIEUPSIOS + 0xA49D: 0xCA43, //HANGUL SYLLABLE SSANGCIEUC YAE SIOS + 0xA49E: 0xCA44, //HANGUL SYLLABLE SSANGCIEUC YAE SSANGSIOS + 0xA49F: 0xCA45, //HANGUL SYLLABLE SSANGCIEUC YAE IEUNG + 0xA4A0: 0xCA46, //HANGUL SYLLABLE SSANGCIEUC YAE CIEUC + 0xA4A1: 0x3131, //HANGUL LETTER KIYEOK + 0xA4A2: 0x3132, //HANGUL LETTER SSANGKIYEOK + 0xA4A3: 0x3133, //HANGUL LETTER KIYEOK-SIOS + 0xA4A4: 0x3134, //HANGUL LETTER NIEUN + 0xA4A5: 0x3135, //HANGUL LETTER NIEUN-CIEUC + 0xA4A6: 0x3136, //HANGUL LETTER NIEUN-HIEUH + 0xA4A7: 0x3137, //HANGUL LETTER TIKEUT + 0xA4A8: 0x3138, //HANGUL LETTER SSANGTIKEUT + 0xA4A9: 0x3139, //HANGUL LETTER RIEUL + 0xA4AA: 0x313A, //HANGUL LETTER RIEUL-KIYEOK + 0xA4AB: 0x313B, //HANGUL LETTER RIEUL-MIEUM + 0xA4AC: 0x313C, //HANGUL LETTER RIEUL-PIEUP + 0xA4AD: 0x313D, //HANGUL LETTER RIEUL-SIOS + 0xA4AE: 0x313E, //HANGUL LETTER RIEUL-THIEUTH + 0xA4AF: 0x313F, //HANGUL LETTER RIEUL-PHIEUPH + 0xA4B0: 0x3140, //HANGUL LETTER RIEUL-HIEUH + 0xA4B1: 0x3141, //HANGUL LETTER MIEUM + 0xA4B2: 0x3142, //HANGUL LETTER PIEUP + 0xA4B3: 0x3143, //HANGUL LETTER SSANGPIEUP + 0xA4B4: 0x3144, //HANGUL LETTER PIEUP-SIOS + 0xA4B5: 0x3145, //HANGUL LETTER SIOS + 0xA4B6: 0x3146, //HANGUL LETTER SSANGSIOS + 0xA4B7: 0x3147, //HANGUL LETTER IEUNG + 0xA4B8: 0x3148, //HANGUL LETTER CIEUC + 0xA4B9: 0x3149, //HANGUL LETTER SSANGCIEUC + 0xA4BA: 0x314A, //HANGUL LETTER CHIEUCH + 0xA4BB: 0x314B, //HANGUL LETTER KHIEUKH + 0xA4BC: 0x314C, //HANGUL LETTER THIEUTH + 0xA4BD: 0x314D, //HANGUL LETTER PHIEUPH + 0xA4BE: 0x314E, //HANGUL LETTER HIEUH + 0xA4BF: 0x314F, //HANGUL LETTER A + 0xA4C0: 0x3150, //HANGUL LETTER AE + 0xA4C1: 0x3151, //HANGUL LETTER YA + 0xA4C2: 0x3152, //HANGUL LETTER YAE + 0xA4C3: 0x3153, //HANGUL LETTER EO + 0xA4C4: 0x3154, //HANGUL LETTER E + 0xA4C5: 0x3155, //HANGUL LETTER YEO + 0xA4C6: 0x3156, //HANGUL LETTER YE + 0xA4C7: 0x3157, //HANGUL LETTER O + 0xA4C8: 0x3158, //HANGUL LETTER WA + 0xA4C9: 0x3159, //HANGUL LETTER WAE + 0xA4CA: 0x315A, //HANGUL LETTER OE + 0xA4CB: 0x315B, //HANGUL LETTER YO + 0xA4CC: 0x315C, //HANGUL LETTER U + 0xA4CD: 0x315D, //HANGUL LETTER WEO + 0xA4CE: 0x315E, //HANGUL LETTER WE + 0xA4CF: 0x315F, //HANGUL LETTER WI + 0xA4D0: 0x3160, //HANGUL LETTER YU + 0xA4D1: 0x3161, //HANGUL LETTER EU + 0xA4D2: 0x3162, //HANGUL LETTER YI + 0xA4D3: 0x3163, //HANGUL LETTER I + 0xA4D4: 0x3164, //HANGUL FILLER + 0xA4D5: 0x3165, //HANGUL LETTER SSANGNIEUN + 0xA4D6: 0x3166, //HANGUL LETTER NIEUN-TIKEUT + 0xA4D7: 0x3167, //HANGUL LETTER NIEUN-SIOS + 0xA4D8: 0x3168, //HANGUL LETTER NIEUN-PANSIOS + 0xA4D9: 0x3169, //HANGUL LETTER RIEUL-KIYEOK-SIOS + 0xA4DA: 0x316A, //HANGUL LETTER RIEUL-TIKEUT + 0xA4DB: 0x316B, //HANGUL LETTER RIEUL-PIEUP-SIOS + 0xA4DC: 0x316C, //HANGUL LETTER RIEUL-PANSIOS + 0xA4DD: 0x316D, //HANGUL LETTER RIEUL-YEORINHIEUH + 0xA4DE: 0x316E, //HANGUL LETTER MIEUM-PIEUP + 0xA4DF: 0x316F, //HANGUL LETTER MIEUM-SIOS + 0xA4E0: 0x3170, //HANGUL LETTER MIEUM-PANSIOS + 0xA4E1: 0x3171, //HANGUL LETTER KAPYEOUNMIEUM + 0xA4E2: 0x3172, //HANGUL LETTER PIEUP-KIYEOK + 0xA4E3: 0x3173, //HANGUL LETTER PIEUP-TIKEUT + 0xA4E4: 0x3174, //HANGUL LETTER PIEUP-SIOS-KIYEOK + 0xA4E5: 0x3175, //HANGUL LETTER PIEUP-SIOS-TIKEUT + 0xA4E6: 0x3176, //HANGUL LETTER PIEUP-CIEUC + 0xA4E7: 0x3177, //HANGUL LETTER PIEUP-THIEUTH + 0xA4E8: 0x3178, //HANGUL LETTER KAPYEOUNPIEUP + 0xA4E9: 0x3179, //HANGUL LETTER KAPYEOUNSSANGPIEUP + 0xA4EA: 0x317A, //HANGUL LETTER SIOS-KIYEOK + 0xA4EB: 0x317B, //HANGUL LETTER SIOS-NIEUN + 0xA4EC: 0x317C, //HANGUL LETTER SIOS-TIKEUT + 0xA4ED: 0x317D, //HANGUL LETTER SIOS-PIEUP + 0xA4EE: 0x317E, //HANGUL LETTER SIOS-CIEUC + 0xA4EF: 0x317F, //HANGUL LETTER PANSIOS + 0xA4F0: 0x3180, //HANGUL LETTER SSANGIEUNG + 0xA4F1: 0x3181, //HANGUL LETTER YESIEUNG + 0xA4F2: 0x3182, //HANGUL LETTER YESIEUNG-SIOS + 0xA4F3: 0x3183, //HANGUL LETTER YESIEUNG-PANSIOS + 0xA4F4: 0x3184, //HANGUL LETTER KAPYEOUNPHIEUPH + 0xA4F5: 0x3185, //HANGUL LETTER SSANGHIEUH + 0xA4F6: 0x3186, //HANGUL LETTER YEORINHIEUH + 0xA4F7: 0x3187, //HANGUL LETTER YO-YA + 0xA4F8: 0x3188, //HANGUL LETTER YO-YAE + 0xA4F9: 0x3189, //HANGUL LETTER YO-I + 0xA4FA: 0x318A, //HANGUL LETTER YU-YEO + 0xA4FB: 0x318B, //HANGUL LETTER YU-YE + 0xA4FC: 0x318C, //HANGUL LETTER YU-I + 0xA4FD: 0x318D, //HANGUL LETTER ARAEA + 0xA4FE: 0x318E, //HANGUL LETTER ARAEAE + 0xA541: 0xCA47, //HANGUL SYLLABLE SSANGCIEUC YAE CHIEUCH + 0xA542: 0xCA48, //HANGUL SYLLABLE SSANGCIEUC YAE KHIEUKH + 0xA543: 0xCA49, //HANGUL SYLLABLE SSANGCIEUC YAE THIEUTH + 0xA544: 0xCA4A, //HANGUL SYLLABLE SSANGCIEUC YAE PHIEUPH + 0xA545: 0xCA4B, //HANGUL SYLLABLE SSANGCIEUC YAE HIEUH + 0xA546: 0xCA4E, //HANGUL SYLLABLE SSANGCIEUC EO SSANGKIYEOK + 0xA547: 0xCA4F, //HANGUL SYLLABLE SSANGCIEUC EO KIYEOKSIOS + 0xA548: 0xCA51, //HANGUL SYLLABLE SSANGCIEUC EO NIEUNCIEUC + 0xA549: 0xCA52, //HANGUL SYLLABLE SSANGCIEUC EO NIEUNHIEUH + 0xA54A: 0xCA53, //HANGUL SYLLABLE SSANGCIEUC EO TIKEUT + 0xA54B: 0xCA55, //HANGUL SYLLABLE SSANGCIEUC EO RIEULKIYEOK + 0xA54C: 0xCA56, //HANGUL SYLLABLE SSANGCIEUC EO RIEULMIEUM + 0xA54D: 0xCA57, //HANGUL SYLLABLE SSANGCIEUC EO RIEULPIEUP + 0xA54E: 0xCA58, //HANGUL SYLLABLE SSANGCIEUC EO RIEULSIOS + 0xA54F: 0xCA59, //HANGUL SYLLABLE SSANGCIEUC EO RIEULTHIEUTH + 0xA550: 0xCA5A, //HANGUL SYLLABLE SSANGCIEUC EO RIEULPHIEUPH + 0xA551: 0xCA5B, //HANGUL SYLLABLE SSANGCIEUC EO RIEULHIEUH + 0xA552: 0xCA5E, //HANGUL SYLLABLE SSANGCIEUC EO PIEUPSIOS + 0xA553: 0xCA62, //HANGUL SYLLABLE SSANGCIEUC EO CIEUC + 0xA554: 0xCA63, //HANGUL SYLLABLE SSANGCIEUC EO CHIEUCH + 0xA555: 0xCA64, //HANGUL SYLLABLE SSANGCIEUC EO KHIEUKH + 0xA556: 0xCA65, //HANGUL SYLLABLE SSANGCIEUC EO THIEUTH + 0xA557: 0xCA66, //HANGUL SYLLABLE SSANGCIEUC EO PHIEUPH + 0xA558: 0xCA67, //HANGUL SYLLABLE SSANGCIEUC EO HIEUH + 0xA559: 0xCA69, //HANGUL SYLLABLE SSANGCIEUC E KIYEOK + 0xA55A: 0xCA6A, //HANGUL SYLLABLE SSANGCIEUC E SSANGKIYEOK + 0xA561: 0xCA6B, //HANGUL SYLLABLE SSANGCIEUC E KIYEOKSIOS + 0xA562: 0xCA6C, //HANGUL SYLLABLE SSANGCIEUC E NIEUN + 0xA563: 0xCA6D, //HANGUL SYLLABLE SSANGCIEUC E NIEUNCIEUC + 0xA564: 0xCA6E, //HANGUL SYLLABLE SSANGCIEUC E NIEUNHIEUH + 0xA565: 0xCA6F, //HANGUL SYLLABLE SSANGCIEUC E TIKEUT + 0xA566: 0xCA70, //HANGUL SYLLABLE SSANGCIEUC E RIEUL + 0xA567: 0xCA71, //HANGUL SYLLABLE SSANGCIEUC E RIEULKIYEOK + 0xA568: 0xCA72, //HANGUL SYLLABLE SSANGCIEUC E RIEULMIEUM + 0xA569: 0xCA73, //HANGUL SYLLABLE SSANGCIEUC E RIEULPIEUP + 0xA56A: 0xCA74, //HANGUL SYLLABLE SSANGCIEUC E RIEULSIOS + 0xA56B: 0xCA75, //HANGUL SYLLABLE SSANGCIEUC E RIEULTHIEUTH + 0xA56C: 0xCA76, //HANGUL SYLLABLE SSANGCIEUC E RIEULPHIEUPH + 0xA56D: 0xCA77, //HANGUL SYLLABLE SSANGCIEUC E RIEULHIEUH + 0xA56E: 0xCA78, //HANGUL SYLLABLE SSANGCIEUC E MIEUM + 0xA56F: 0xCA79, //HANGUL SYLLABLE SSANGCIEUC E PIEUP + 0xA570: 0xCA7A, //HANGUL SYLLABLE SSANGCIEUC E PIEUPSIOS + 0xA571: 0xCA7B, //HANGUL SYLLABLE SSANGCIEUC E SIOS + 0xA572: 0xCA7C, //HANGUL SYLLABLE SSANGCIEUC E SSANGSIOS + 0xA573: 0xCA7E, //HANGUL SYLLABLE SSANGCIEUC E CIEUC + 0xA574: 0xCA7F, //HANGUL SYLLABLE SSANGCIEUC E CHIEUCH + 0xA575: 0xCA80, //HANGUL SYLLABLE SSANGCIEUC E KHIEUKH + 0xA576: 0xCA81, //HANGUL SYLLABLE SSANGCIEUC E THIEUTH + 0xA577: 0xCA82, //HANGUL SYLLABLE SSANGCIEUC E PHIEUPH + 0xA578: 0xCA83, //HANGUL SYLLABLE SSANGCIEUC E HIEUH + 0xA579: 0xCA85, //HANGUL SYLLABLE SSANGCIEUC YEO KIYEOK + 0xA57A: 0xCA86, //HANGUL SYLLABLE SSANGCIEUC YEO SSANGKIYEOK + 0xA581: 0xCA87, //HANGUL SYLLABLE SSANGCIEUC YEO KIYEOKSIOS + 0xA582: 0xCA88, //HANGUL SYLLABLE SSANGCIEUC YEO NIEUN + 0xA583: 0xCA89, //HANGUL SYLLABLE SSANGCIEUC YEO NIEUNCIEUC + 0xA584: 0xCA8A, //HANGUL SYLLABLE SSANGCIEUC YEO NIEUNHIEUH + 0xA585: 0xCA8B, //HANGUL SYLLABLE SSANGCIEUC YEO TIKEUT + 0xA586: 0xCA8C, //HANGUL SYLLABLE SSANGCIEUC YEO RIEUL + 0xA587: 0xCA8D, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULKIYEOK + 0xA588: 0xCA8E, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULMIEUM + 0xA589: 0xCA8F, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULPIEUP + 0xA58A: 0xCA90, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULSIOS + 0xA58B: 0xCA91, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULTHIEUTH + 0xA58C: 0xCA92, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULPHIEUPH + 0xA58D: 0xCA93, //HANGUL SYLLABLE SSANGCIEUC YEO RIEULHIEUH + 0xA58E: 0xCA94, //HANGUL SYLLABLE SSANGCIEUC YEO MIEUM + 0xA58F: 0xCA95, //HANGUL SYLLABLE SSANGCIEUC YEO PIEUP + 0xA590: 0xCA96, //HANGUL SYLLABLE SSANGCIEUC YEO PIEUPSIOS + 0xA591: 0xCA97, //HANGUL SYLLABLE SSANGCIEUC YEO SIOS + 0xA592: 0xCA99, //HANGUL SYLLABLE SSANGCIEUC YEO IEUNG + 0xA593: 0xCA9A, //HANGUL SYLLABLE SSANGCIEUC YEO CIEUC + 0xA594: 0xCA9B, //HANGUL SYLLABLE SSANGCIEUC YEO CHIEUCH + 0xA595: 0xCA9C, //HANGUL SYLLABLE SSANGCIEUC YEO KHIEUKH + 0xA596: 0xCA9D, //HANGUL SYLLABLE SSANGCIEUC YEO THIEUTH + 0xA597: 0xCA9E, //HANGUL SYLLABLE SSANGCIEUC YEO PHIEUPH + 0xA598: 0xCA9F, //HANGUL SYLLABLE SSANGCIEUC YEO HIEUH + 0xA599: 0xCAA0, //HANGUL SYLLABLE SSANGCIEUC YE + 0xA59A: 0xCAA1, //HANGUL SYLLABLE SSANGCIEUC YE KIYEOK + 0xA59B: 0xCAA2, //HANGUL SYLLABLE SSANGCIEUC YE SSANGKIYEOK + 0xA59C: 0xCAA3, //HANGUL SYLLABLE SSANGCIEUC YE KIYEOKSIOS + 0xA59D: 0xCAA4, //HANGUL SYLLABLE SSANGCIEUC YE NIEUN + 0xA59E: 0xCAA5, //HANGUL SYLLABLE SSANGCIEUC YE NIEUNCIEUC + 0xA59F: 0xCAA6, //HANGUL SYLLABLE SSANGCIEUC YE NIEUNHIEUH + 0xA5A0: 0xCAA7, //HANGUL SYLLABLE SSANGCIEUC YE TIKEUT + 0xA5A1: 0x2170, //SMALL ROMAN NUMERAL ONE + 0xA5A2: 0x2171, //SMALL ROMAN NUMERAL TWO + 0xA5A3: 0x2172, //SMALL ROMAN NUMERAL THREE + 0xA5A4: 0x2173, //SMALL ROMAN NUMERAL FOUR + 0xA5A5: 0x2174, //SMALL ROMAN NUMERAL FIVE + 0xA5A6: 0x2175, //SMALL ROMAN NUMERAL SIX + 0xA5A7: 0x2176, //SMALL ROMAN NUMERAL SEVEN + 0xA5A8: 0x2177, //SMALL ROMAN NUMERAL EIGHT + 0xA5A9: 0x2178, //SMALL ROMAN NUMERAL NINE + 0xA5AA: 0x2179, //SMALL ROMAN NUMERAL TEN + 0xA5B0: 0x2160, //ROMAN NUMERAL ONE + 0xA5B1: 0x2161, //ROMAN NUMERAL TWO + 0xA5B2: 0x2162, //ROMAN NUMERAL THREE + 0xA5B3: 0x2163, //ROMAN NUMERAL FOUR + 0xA5B4: 0x2164, //ROMAN NUMERAL FIVE + 0xA5B5: 0x2165, //ROMAN NUMERAL SIX + 0xA5B6: 0x2166, //ROMAN NUMERAL SEVEN + 0xA5B7: 0x2167, //ROMAN NUMERAL EIGHT + 0xA5B8: 0x2168, //ROMAN NUMERAL NINE + 0xA5B9: 0x2169, //ROMAN NUMERAL TEN + 0xA5C1: 0x0391, //GREEK CAPITAL LETTER ALPHA + 0xA5C2: 0x0392, //GREEK CAPITAL LETTER BETA + 0xA5C3: 0x0393, //GREEK CAPITAL LETTER GAMMA + 0xA5C4: 0x0394, //GREEK CAPITAL LETTER DELTA + 0xA5C5: 0x0395, //GREEK CAPITAL LETTER EPSILON + 0xA5C6: 0x0396, //GREEK CAPITAL LETTER ZETA + 0xA5C7: 0x0397, //GREEK CAPITAL LETTER ETA + 0xA5C8: 0x0398, //GREEK CAPITAL LETTER THETA + 0xA5C9: 0x0399, //GREEK CAPITAL LETTER IOTA + 0xA5CA: 0x039A, //GREEK CAPITAL LETTER KAPPA + 0xA5CB: 0x039B, //GREEK CAPITAL LETTER LAMDA + 0xA5CC: 0x039C, //GREEK CAPITAL LETTER MU + 0xA5CD: 0x039D, //GREEK CAPITAL LETTER NU + 0xA5CE: 0x039E, //GREEK CAPITAL LETTER XI + 0xA5CF: 0x039F, //GREEK CAPITAL LETTER OMICRON + 0xA5D0: 0x03A0, //GREEK CAPITAL LETTER PI + 0xA5D1: 0x03A1, //GREEK CAPITAL LETTER RHO + 0xA5D2: 0x03A3, //GREEK CAPITAL LETTER SIGMA + 0xA5D3: 0x03A4, //GREEK CAPITAL LETTER TAU + 0xA5D4: 0x03A5, //GREEK CAPITAL LETTER UPSILON + 0xA5D5: 0x03A6, //GREEK CAPITAL LETTER PHI + 0xA5D6: 0x03A7, //GREEK CAPITAL LETTER CHI + 0xA5D7: 0x03A8, //GREEK CAPITAL LETTER PSI + 0xA5D8: 0x03A9, //GREEK CAPITAL LETTER OMEGA + 0xA5E1: 0x03B1, //GREEK SMALL LETTER ALPHA + 0xA5E2: 0x03B2, //GREEK SMALL LETTER BETA + 0xA5E3: 0x03B3, //GREEK SMALL LETTER GAMMA + 0xA5E4: 0x03B4, //GREEK SMALL LETTER DELTA + 0xA5E5: 0x03B5, //GREEK SMALL LETTER EPSILON + 0xA5E6: 0x03B6, //GREEK SMALL LETTER ZETA + 0xA5E7: 0x03B7, //GREEK SMALL LETTER ETA + 0xA5E8: 0x03B8, //GREEK SMALL LETTER THETA + 0xA5E9: 0x03B9, //GREEK SMALL LETTER IOTA + 0xA5EA: 0x03BA, //GREEK SMALL LETTER KAPPA + 0xA5EB: 0x03BB, //GREEK SMALL LETTER LAMDA + 0xA5EC: 0x03BC, //GREEK SMALL LETTER MU + 0xA5ED: 0x03BD, //GREEK SMALL LETTER NU + 0xA5EE: 0x03BE, //GREEK SMALL LETTER XI + 0xA5EF: 0x03BF, //GREEK SMALL LETTER OMICRON + 0xA5F0: 0x03C0, //GREEK SMALL LETTER PI + 0xA5F1: 0x03C1, //GREEK SMALL LETTER RHO + 0xA5F2: 0x03C3, //GREEK SMALL LETTER SIGMA + 0xA5F3: 0x03C4, //GREEK SMALL LETTER TAU + 0xA5F4: 0x03C5, //GREEK SMALL LETTER UPSILON + 0xA5F5: 0x03C6, //GREEK SMALL LETTER PHI + 0xA5F6: 0x03C7, //GREEK SMALL LETTER CHI + 0xA5F7: 0x03C8, //GREEK SMALL LETTER PSI + 0xA5F8: 0x03C9, //GREEK SMALL LETTER OMEGA + 0xA641: 0xCAA8, //HANGUL SYLLABLE SSANGCIEUC YE RIEUL + 0xA642: 0xCAA9, //HANGUL SYLLABLE SSANGCIEUC YE RIEULKIYEOK + 0xA643: 0xCAAA, //HANGUL SYLLABLE SSANGCIEUC YE RIEULMIEUM + 0xA644: 0xCAAB, //HANGUL SYLLABLE SSANGCIEUC YE RIEULPIEUP + 0xA645: 0xCAAC, //HANGUL SYLLABLE SSANGCIEUC YE RIEULSIOS + 0xA646: 0xCAAD, //HANGUL SYLLABLE SSANGCIEUC YE RIEULTHIEUTH + 0xA647: 0xCAAE, //HANGUL SYLLABLE SSANGCIEUC YE RIEULPHIEUPH + 0xA648: 0xCAAF, //HANGUL SYLLABLE SSANGCIEUC YE RIEULHIEUH + 0xA649: 0xCAB0, //HANGUL SYLLABLE SSANGCIEUC YE MIEUM + 0xA64A: 0xCAB1, //HANGUL SYLLABLE SSANGCIEUC YE PIEUP + 0xA64B: 0xCAB2, //HANGUL SYLLABLE SSANGCIEUC YE PIEUPSIOS + 0xA64C: 0xCAB3, //HANGUL SYLLABLE SSANGCIEUC YE SIOS + 0xA64D: 0xCAB4, //HANGUL SYLLABLE SSANGCIEUC YE SSANGSIOS + 0xA64E: 0xCAB5, //HANGUL SYLLABLE SSANGCIEUC YE IEUNG + 0xA64F: 0xCAB6, //HANGUL SYLLABLE SSANGCIEUC YE CIEUC + 0xA650: 0xCAB7, //HANGUL SYLLABLE SSANGCIEUC YE CHIEUCH + 0xA651: 0xCAB8, //HANGUL SYLLABLE SSANGCIEUC YE KHIEUKH + 0xA652: 0xCAB9, //HANGUL SYLLABLE SSANGCIEUC YE THIEUTH + 0xA653: 0xCABA, //HANGUL SYLLABLE SSANGCIEUC YE PHIEUPH + 0xA654: 0xCABB, //HANGUL SYLLABLE SSANGCIEUC YE HIEUH + 0xA655: 0xCABE, //HANGUL SYLLABLE SSANGCIEUC O SSANGKIYEOK + 0xA656: 0xCABF, //HANGUL SYLLABLE SSANGCIEUC O KIYEOKSIOS + 0xA657: 0xCAC1, //HANGUL SYLLABLE SSANGCIEUC O NIEUNCIEUC + 0xA658: 0xCAC2, //HANGUL SYLLABLE SSANGCIEUC O NIEUNHIEUH + 0xA659: 0xCAC3, //HANGUL SYLLABLE SSANGCIEUC O TIKEUT + 0xA65A: 0xCAC5, //HANGUL SYLLABLE SSANGCIEUC O RIEULKIYEOK + 0xA661: 0xCAC6, //HANGUL SYLLABLE SSANGCIEUC O RIEULMIEUM + 0xA662: 0xCAC7, //HANGUL SYLLABLE SSANGCIEUC O RIEULPIEUP + 0xA663: 0xCAC8, //HANGUL SYLLABLE SSANGCIEUC O RIEULSIOS + 0xA664: 0xCAC9, //HANGUL SYLLABLE SSANGCIEUC O RIEULTHIEUTH + 0xA665: 0xCACA, //HANGUL SYLLABLE SSANGCIEUC O RIEULPHIEUPH + 0xA666: 0xCACB, //HANGUL SYLLABLE SSANGCIEUC O RIEULHIEUH + 0xA667: 0xCACE, //HANGUL SYLLABLE SSANGCIEUC O PIEUPSIOS + 0xA668: 0xCAD0, //HANGUL SYLLABLE SSANGCIEUC O SSANGSIOS + 0xA669: 0xCAD2, //HANGUL SYLLABLE SSANGCIEUC O CIEUC + 0xA66A: 0xCAD4, //HANGUL SYLLABLE SSANGCIEUC O KHIEUKH + 0xA66B: 0xCAD5, //HANGUL SYLLABLE SSANGCIEUC O THIEUTH + 0xA66C: 0xCAD6, //HANGUL SYLLABLE SSANGCIEUC O PHIEUPH + 0xA66D: 0xCAD7, //HANGUL SYLLABLE SSANGCIEUC O HIEUH + 0xA66E: 0xCADA, //HANGUL SYLLABLE SSANGCIEUC WA SSANGKIYEOK + 0xA66F: 0xCADB, //HANGUL SYLLABLE SSANGCIEUC WA KIYEOKSIOS + 0xA670: 0xCADC, //HANGUL SYLLABLE SSANGCIEUC WA NIEUN + 0xA671: 0xCADD, //HANGUL SYLLABLE SSANGCIEUC WA NIEUNCIEUC + 0xA672: 0xCADE, //HANGUL SYLLABLE SSANGCIEUC WA NIEUNHIEUH + 0xA673: 0xCADF, //HANGUL SYLLABLE SSANGCIEUC WA TIKEUT + 0xA674: 0xCAE1, //HANGUL SYLLABLE SSANGCIEUC WA RIEULKIYEOK + 0xA675: 0xCAE2, //HANGUL SYLLABLE SSANGCIEUC WA RIEULMIEUM + 0xA676: 0xCAE3, //HANGUL SYLLABLE SSANGCIEUC WA RIEULPIEUP + 0xA677: 0xCAE4, //HANGUL SYLLABLE SSANGCIEUC WA RIEULSIOS + 0xA678: 0xCAE5, //HANGUL SYLLABLE SSANGCIEUC WA RIEULTHIEUTH + 0xA679: 0xCAE6, //HANGUL SYLLABLE SSANGCIEUC WA RIEULPHIEUPH + 0xA67A: 0xCAE7, //HANGUL SYLLABLE SSANGCIEUC WA RIEULHIEUH + 0xA681: 0xCAE8, //HANGUL SYLLABLE SSANGCIEUC WA MIEUM + 0xA682: 0xCAE9, //HANGUL SYLLABLE SSANGCIEUC WA PIEUP + 0xA683: 0xCAEA, //HANGUL SYLLABLE SSANGCIEUC WA PIEUPSIOS + 0xA684: 0xCAEB, //HANGUL SYLLABLE SSANGCIEUC WA SIOS + 0xA685: 0xCAED, //HANGUL SYLLABLE SSANGCIEUC WA IEUNG + 0xA686: 0xCAEE, //HANGUL SYLLABLE SSANGCIEUC WA CIEUC + 0xA687: 0xCAEF, //HANGUL SYLLABLE SSANGCIEUC WA CHIEUCH + 0xA688: 0xCAF0, //HANGUL SYLLABLE SSANGCIEUC WA KHIEUKH + 0xA689: 0xCAF1, //HANGUL SYLLABLE SSANGCIEUC WA THIEUTH + 0xA68A: 0xCAF2, //HANGUL SYLLABLE SSANGCIEUC WA PHIEUPH + 0xA68B: 0xCAF3, //HANGUL SYLLABLE SSANGCIEUC WA HIEUH + 0xA68C: 0xCAF5, //HANGUL SYLLABLE SSANGCIEUC WAE KIYEOK + 0xA68D: 0xCAF6, //HANGUL SYLLABLE SSANGCIEUC WAE SSANGKIYEOK + 0xA68E: 0xCAF7, //HANGUL SYLLABLE SSANGCIEUC WAE KIYEOKSIOS + 0xA68F: 0xCAF8, //HANGUL SYLLABLE SSANGCIEUC WAE NIEUN + 0xA690: 0xCAF9, //HANGUL SYLLABLE SSANGCIEUC WAE NIEUNCIEUC + 0xA691: 0xCAFA, //HANGUL SYLLABLE SSANGCIEUC WAE NIEUNHIEUH + 0xA692: 0xCAFB, //HANGUL SYLLABLE SSANGCIEUC WAE TIKEUT + 0xA693: 0xCAFC, //HANGUL SYLLABLE SSANGCIEUC WAE RIEUL + 0xA694: 0xCAFD, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULKIYEOK + 0xA695: 0xCAFE, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULMIEUM + 0xA696: 0xCAFF, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULPIEUP + 0xA697: 0xCB00, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULSIOS + 0xA698: 0xCB01, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULTHIEUTH + 0xA699: 0xCB02, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULPHIEUPH + 0xA69A: 0xCB03, //HANGUL SYLLABLE SSANGCIEUC WAE RIEULHIEUH + 0xA69B: 0xCB04, //HANGUL SYLLABLE SSANGCIEUC WAE MIEUM + 0xA69C: 0xCB05, //HANGUL SYLLABLE SSANGCIEUC WAE PIEUP + 0xA69D: 0xCB06, //HANGUL SYLLABLE SSANGCIEUC WAE PIEUPSIOS + 0xA69E: 0xCB07, //HANGUL SYLLABLE SSANGCIEUC WAE SIOS + 0xA69F: 0xCB09, //HANGUL SYLLABLE SSANGCIEUC WAE IEUNG + 0xA6A0: 0xCB0A, //HANGUL SYLLABLE SSANGCIEUC WAE CIEUC + 0xA6A1: 0x2500, //BOX DRAWINGS LIGHT HORIZONTAL + 0xA6A2: 0x2502, //BOX DRAWINGS LIGHT VERTICAL + 0xA6A3: 0x250C, //BOX DRAWINGS LIGHT DOWN AND RIGHT + 0xA6A4: 0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT + 0xA6A5: 0x2518, //BOX DRAWINGS LIGHT UP AND LEFT + 0xA6A6: 0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT + 0xA6A7: 0x251C, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0xA6A8: 0x252C, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0xA6A9: 0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0xA6AA: 0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0xA6AB: 0x253C, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0xA6AC: 0x2501, //BOX DRAWINGS HEAVY HORIZONTAL + 0xA6AD: 0x2503, //BOX DRAWINGS HEAVY VERTICAL + 0xA6AE: 0x250F, //BOX DRAWINGS HEAVY DOWN AND RIGHT + 0xA6AF: 0x2513, //BOX DRAWINGS HEAVY DOWN AND LEFT + 0xA6B0: 0x251B, //BOX DRAWINGS HEAVY UP AND LEFT + 0xA6B1: 0x2517, //BOX DRAWINGS HEAVY UP AND RIGHT + 0xA6B2: 0x2523, //BOX DRAWINGS HEAVY VERTICAL AND RIGHT + 0xA6B3: 0x2533, //BOX DRAWINGS HEAVY DOWN AND HORIZONTAL + 0xA6B4: 0x252B, //BOX DRAWINGS HEAVY VERTICAL AND LEFT + 0xA6B5: 0x253B, //BOX DRAWINGS HEAVY UP AND HORIZONTAL + 0xA6B6: 0x254B, //BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL + 0xA6B7: 0x2520, //BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT + 0xA6B8: 0x252F, //BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY + 0xA6B9: 0x2528, //BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT + 0xA6BA: 0x2537, //BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY + 0xA6BB: 0x253F, //BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY + 0xA6BC: 0x251D, //BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY + 0xA6BD: 0x2530, //BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT + 0xA6BE: 0x2525, //BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY + 0xA6BF: 0x2538, //BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT + 0xA6C0: 0x2542, //BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT + 0xA6C1: 0x2512, //BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT + 0xA6C2: 0x2511, //BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY + 0xA6C3: 0x251A, //BOX DRAWINGS UP HEAVY AND LEFT LIGHT + 0xA6C4: 0x2519, //BOX DRAWINGS UP LIGHT AND LEFT HEAVY + 0xA6C5: 0x2516, //BOX DRAWINGS UP HEAVY AND RIGHT LIGHT + 0xA6C6: 0x2515, //BOX DRAWINGS UP LIGHT AND RIGHT HEAVY + 0xA6C7: 0x250E, //BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT + 0xA6C8: 0x250D, //BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY + 0xA6C9: 0x251E, //BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT + 0xA6CA: 0x251F, //BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT + 0xA6CB: 0x2521, //BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY + 0xA6CC: 0x2522, //BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY + 0xA6CD: 0x2526, //BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT + 0xA6CE: 0x2527, //BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT + 0xA6CF: 0x2529, //BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY + 0xA6D0: 0x252A, //BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY + 0xA6D1: 0x252D, //BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT + 0xA6D2: 0x252E, //BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT + 0xA6D3: 0x2531, //BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY + 0xA6D4: 0x2532, //BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY + 0xA6D5: 0x2535, //BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT + 0xA6D6: 0x2536, //BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT + 0xA6D7: 0x2539, //BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY + 0xA6D8: 0x253A, //BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY + 0xA6D9: 0x253D, //BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT + 0xA6DA: 0x253E, //BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT + 0xA6DB: 0x2540, //BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT + 0xA6DC: 0x2541, //BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT + 0xA6DD: 0x2543, //BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT + 0xA6DE: 0x2544, //BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT + 0xA6DF: 0x2545, //BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT + 0xA6E0: 0x2546, //BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT + 0xA6E1: 0x2547, //BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY + 0xA6E2: 0x2548, //BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY + 0xA6E3: 0x2549, //BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY + 0xA6E4: 0x254A, //BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY + 0xA741: 0xCB0B, //HANGUL SYLLABLE SSANGCIEUC WAE CHIEUCH + 0xA742: 0xCB0C, //HANGUL SYLLABLE SSANGCIEUC WAE KHIEUKH + 0xA743: 0xCB0D, //HANGUL SYLLABLE SSANGCIEUC WAE THIEUTH + 0xA744: 0xCB0E, //HANGUL SYLLABLE SSANGCIEUC WAE PHIEUPH + 0xA745: 0xCB0F, //HANGUL SYLLABLE SSANGCIEUC WAE HIEUH + 0xA746: 0xCB11, //HANGUL SYLLABLE SSANGCIEUC OE KIYEOK + 0xA747: 0xCB12, //HANGUL SYLLABLE SSANGCIEUC OE SSANGKIYEOK + 0xA748: 0xCB13, //HANGUL SYLLABLE SSANGCIEUC OE KIYEOKSIOS + 0xA749: 0xCB15, //HANGUL SYLLABLE SSANGCIEUC OE NIEUNCIEUC + 0xA74A: 0xCB16, //HANGUL SYLLABLE SSANGCIEUC OE NIEUNHIEUH + 0xA74B: 0xCB17, //HANGUL SYLLABLE SSANGCIEUC OE TIKEUT + 0xA74C: 0xCB19, //HANGUL SYLLABLE SSANGCIEUC OE RIEULKIYEOK + 0xA74D: 0xCB1A, //HANGUL SYLLABLE SSANGCIEUC OE RIEULMIEUM + 0xA74E: 0xCB1B, //HANGUL SYLLABLE SSANGCIEUC OE RIEULPIEUP + 0xA74F: 0xCB1C, //HANGUL SYLLABLE SSANGCIEUC OE RIEULSIOS + 0xA750: 0xCB1D, //HANGUL SYLLABLE SSANGCIEUC OE RIEULTHIEUTH + 0xA751: 0xCB1E, //HANGUL SYLLABLE SSANGCIEUC OE RIEULPHIEUPH + 0xA752: 0xCB1F, //HANGUL SYLLABLE SSANGCIEUC OE RIEULHIEUH + 0xA753: 0xCB22, //HANGUL SYLLABLE SSANGCIEUC OE PIEUPSIOS + 0xA754: 0xCB23, //HANGUL SYLLABLE SSANGCIEUC OE SIOS + 0xA755: 0xCB24, //HANGUL SYLLABLE SSANGCIEUC OE SSANGSIOS + 0xA756: 0xCB25, //HANGUL SYLLABLE SSANGCIEUC OE IEUNG + 0xA757: 0xCB26, //HANGUL SYLLABLE SSANGCIEUC OE CIEUC + 0xA758: 0xCB27, //HANGUL SYLLABLE SSANGCIEUC OE CHIEUCH + 0xA759: 0xCB28, //HANGUL SYLLABLE SSANGCIEUC OE KHIEUKH + 0xA75A: 0xCB29, //HANGUL SYLLABLE SSANGCIEUC OE THIEUTH + 0xA761: 0xCB2A, //HANGUL SYLLABLE SSANGCIEUC OE PHIEUPH + 0xA762: 0xCB2B, //HANGUL SYLLABLE SSANGCIEUC OE HIEUH + 0xA763: 0xCB2C, //HANGUL SYLLABLE SSANGCIEUC YO + 0xA764: 0xCB2D, //HANGUL SYLLABLE SSANGCIEUC YO KIYEOK + 0xA765: 0xCB2E, //HANGUL SYLLABLE SSANGCIEUC YO SSANGKIYEOK + 0xA766: 0xCB2F, //HANGUL SYLLABLE SSANGCIEUC YO KIYEOKSIOS + 0xA767: 0xCB30, //HANGUL SYLLABLE SSANGCIEUC YO NIEUN + 0xA768: 0xCB31, //HANGUL SYLLABLE SSANGCIEUC YO NIEUNCIEUC + 0xA769: 0xCB32, //HANGUL SYLLABLE SSANGCIEUC YO NIEUNHIEUH + 0xA76A: 0xCB33, //HANGUL SYLLABLE SSANGCIEUC YO TIKEUT + 0xA76B: 0xCB34, //HANGUL SYLLABLE SSANGCIEUC YO RIEUL + 0xA76C: 0xCB35, //HANGUL SYLLABLE SSANGCIEUC YO RIEULKIYEOK + 0xA76D: 0xCB36, //HANGUL SYLLABLE SSANGCIEUC YO RIEULMIEUM + 0xA76E: 0xCB37, //HANGUL SYLLABLE SSANGCIEUC YO RIEULPIEUP + 0xA76F: 0xCB38, //HANGUL SYLLABLE SSANGCIEUC YO RIEULSIOS + 0xA770: 0xCB39, //HANGUL SYLLABLE SSANGCIEUC YO RIEULTHIEUTH + 0xA771: 0xCB3A, //HANGUL SYLLABLE SSANGCIEUC YO RIEULPHIEUPH + 0xA772: 0xCB3B, //HANGUL SYLLABLE SSANGCIEUC YO RIEULHIEUH + 0xA773: 0xCB3C, //HANGUL SYLLABLE SSANGCIEUC YO MIEUM + 0xA774: 0xCB3D, //HANGUL SYLLABLE SSANGCIEUC YO PIEUP + 0xA775: 0xCB3E, //HANGUL SYLLABLE SSANGCIEUC YO PIEUPSIOS + 0xA776: 0xCB3F, //HANGUL SYLLABLE SSANGCIEUC YO SIOS + 0xA777: 0xCB40, //HANGUL SYLLABLE SSANGCIEUC YO SSANGSIOS + 0xA778: 0xCB42, //HANGUL SYLLABLE SSANGCIEUC YO CIEUC + 0xA779: 0xCB43, //HANGUL SYLLABLE SSANGCIEUC YO CHIEUCH + 0xA77A: 0xCB44, //HANGUL SYLLABLE SSANGCIEUC YO KHIEUKH + 0xA781: 0xCB45, //HANGUL SYLLABLE SSANGCIEUC YO THIEUTH + 0xA782: 0xCB46, //HANGUL SYLLABLE SSANGCIEUC YO PHIEUPH + 0xA783: 0xCB47, //HANGUL SYLLABLE SSANGCIEUC YO HIEUH + 0xA784: 0xCB4A, //HANGUL SYLLABLE SSANGCIEUC U SSANGKIYEOK + 0xA785: 0xCB4B, //HANGUL SYLLABLE SSANGCIEUC U KIYEOKSIOS + 0xA786: 0xCB4D, //HANGUL SYLLABLE SSANGCIEUC U NIEUNCIEUC + 0xA787: 0xCB4E, //HANGUL SYLLABLE SSANGCIEUC U NIEUNHIEUH + 0xA788: 0xCB4F, //HANGUL SYLLABLE SSANGCIEUC U TIKEUT + 0xA789: 0xCB51, //HANGUL SYLLABLE SSANGCIEUC U RIEULKIYEOK + 0xA78A: 0xCB52, //HANGUL SYLLABLE SSANGCIEUC U RIEULMIEUM + 0xA78B: 0xCB53, //HANGUL SYLLABLE SSANGCIEUC U RIEULPIEUP + 0xA78C: 0xCB54, //HANGUL SYLLABLE SSANGCIEUC U RIEULSIOS + 0xA78D: 0xCB55, //HANGUL SYLLABLE SSANGCIEUC U RIEULTHIEUTH + 0xA78E: 0xCB56, //HANGUL SYLLABLE SSANGCIEUC U RIEULPHIEUPH + 0xA78F: 0xCB57, //HANGUL SYLLABLE SSANGCIEUC U RIEULHIEUH + 0xA790: 0xCB5A, //HANGUL SYLLABLE SSANGCIEUC U PIEUPSIOS + 0xA791: 0xCB5B, //HANGUL SYLLABLE SSANGCIEUC U SIOS + 0xA792: 0xCB5C, //HANGUL SYLLABLE SSANGCIEUC U SSANGSIOS + 0xA793: 0xCB5E, //HANGUL SYLLABLE SSANGCIEUC U CIEUC + 0xA794: 0xCB5F, //HANGUL SYLLABLE SSANGCIEUC U CHIEUCH + 0xA795: 0xCB60, //HANGUL SYLLABLE SSANGCIEUC U KHIEUKH + 0xA796: 0xCB61, //HANGUL SYLLABLE SSANGCIEUC U THIEUTH + 0xA797: 0xCB62, //HANGUL SYLLABLE SSANGCIEUC U PHIEUPH + 0xA798: 0xCB63, //HANGUL SYLLABLE SSANGCIEUC U HIEUH + 0xA799: 0xCB65, //HANGUL SYLLABLE SSANGCIEUC WEO KIYEOK + 0xA79A: 0xCB66, //HANGUL SYLLABLE SSANGCIEUC WEO SSANGKIYEOK + 0xA79B: 0xCB67, //HANGUL SYLLABLE SSANGCIEUC WEO KIYEOKSIOS + 0xA79C: 0xCB68, //HANGUL SYLLABLE SSANGCIEUC WEO NIEUN + 0xA79D: 0xCB69, //HANGUL SYLLABLE SSANGCIEUC WEO NIEUNCIEUC + 0xA79E: 0xCB6A, //HANGUL SYLLABLE SSANGCIEUC WEO NIEUNHIEUH + 0xA79F: 0xCB6B, //HANGUL SYLLABLE SSANGCIEUC WEO TIKEUT + 0xA7A0: 0xCB6C, //HANGUL SYLLABLE SSANGCIEUC WEO RIEUL + 0xA7A1: 0x3395, //SQUARE MU L + 0xA7A2: 0x3396, //SQUARE ML + 0xA7A3: 0x3397, //SQUARE DL + 0xA7A4: 0x2113, //SCRIPT SMALL L + 0xA7A5: 0x3398, //SQUARE KL + 0xA7A6: 0x33C4, //SQUARE CC + 0xA7A7: 0x33A3, //SQUARE MM CUBED + 0xA7A8: 0x33A4, //SQUARE CM CUBED + 0xA7A9: 0x33A5, //SQUARE M CUBED + 0xA7AA: 0x33A6, //SQUARE KM CUBED + 0xA7AB: 0x3399, //SQUARE FM + 0xA7AC: 0x339A, //SQUARE NM + 0xA7AD: 0x339B, //SQUARE MU M + 0xA7AE: 0x339C, //SQUARE MM + 0xA7AF: 0x339D, //SQUARE CM + 0xA7B0: 0x339E, //SQUARE KM + 0xA7B1: 0x339F, //SQUARE MM SQUARED + 0xA7B2: 0x33A0, //SQUARE CM SQUARED + 0xA7B3: 0x33A1, //SQUARE M SQUARED + 0xA7B4: 0x33A2, //SQUARE KM SQUARED + 0xA7B5: 0x33CA, //SQUARE HA + 0xA7B6: 0x338D, //SQUARE MU G + 0xA7B7: 0x338E, //SQUARE MG + 0xA7B8: 0x338F, //SQUARE KG + 0xA7B9: 0x33CF, //SQUARE KT + 0xA7BA: 0x3388, //SQUARE CAL + 0xA7BB: 0x3389, //SQUARE KCAL + 0xA7BC: 0x33C8, //SQUARE DB + 0xA7BD: 0x33A7, //SQUARE M OVER S + 0xA7BE: 0x33A8, //SQUARE M OVER S SQUARED + 0xA7BF: 0x33B0, //SQUARE PS + 0xA7C0: 0x33B1, //SQUARE NS + 0xA7C1: 0x33B2, //SQUARE MU S + 0xA7C2: 0x33B3, //SQUARE MS + 0xA7C3: 0x33B4, //SQUARE PV + 0xA7C4: 0x33B5, //SQUARE NV + 0xA7C5: 0x33B6, //SQUARE MU V + 0xA7C6: 0x33B7, //SQUARE MV + 0xA7C7: 0x33B8, //SQUARE KV + 0xA7C8: 0x33B9, //SQUARE MV MEGA + 0xA7C9: 0x3380, //SQUARE PA AMPS + 0xA7CA: 0x3381, //SQUARE NA + 0xA7CB: 0x3382, //SQUARE MU A + 0xA7CC: 0x3383, //SQUARE MA + 0xA7CD: 0x3384, //SQUARE KA + 0xA7CE: 0x33BA, //SQUARE PW + 0xA7CF: 0x33BB, //SQUARE NW + 0xA7D0: 0x33BC, //SQUARE MU W + 0xA7D1: 0x33BD, //SQUARE MW + 0xA7D2: 0x33BE, //SQUARE KW + 0xA7D3: 0x33BF, //SQUARE MW MEGA + 0xA7D4: 0x3390, //SQUARE HZ + 0xA7D5: 0x3391, //SQUARE KHZ + 0xA7D6: 0x3392, //SQUARE MHZ + 0xA7D7: 0x3393, //SQUARE GHZ + 0xA7D8: 0x3394, //SQUARE THZ + 0xA7D9: 0x2126, //OHM SIGN + 0xA7DA: 0x33C0, //SQUARE K OHM + 0xA7DB: 0x33C1, //SQUARE M OHM + 0xA7DC: 0x338A, //SQUARE PF + 0xA7DD: 0x338B, //SQUARE NF + 0xA7DE: 0x338C, //SQUARE MU F + 0xA7DF: 0x33D6, //SQUARE MOL + 0xA7E0: 0x33C5, //SQUARE CD + 0xA7E1: 0x33AD, //SQUARE RAD + 0xA7E2: 0x33AE, //SQUARE RAD OVER S + 0xA7E3: 0x33AF, //SQUARE RAD OVER S SQUARED + 0xA7E4: 0x33DB, //SQUARE SR + 0xA7E5: 0x33A9, //SQUARE PA + 0xA7E6: 0x33AA, //SQUARE KPA + 0xA7E7: 0x33AB, //SQUARE MPA + 0xA7E8: 0x33AC, //SQUARE GPA + 0xA7E9: 0x33DD, //SQUARE WB + 0xA7EA: 0x33D0, //SQUARE LM + 0xA7EB: 0x33D3, //SQUARE LX + 0xA7EC: 0x33C3, //SQUARE BQ + 0xA7ED: 0x33C9, //SQUARE GY + 0xA7EE: 0x33DC, //SQUARE SV + 0xA7EF: 0x33C6, //SQUARE C OVER KG + 0xA841: 0xCB6D, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULKIYEOK + 0xA842: 0xCB6E, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULMIEUM + 0xA843: 0xCB6F, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULPIEUP + 0xA844: 0xCB70, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULSIOS + 0xA845: 0xCB71, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULTHIEUTH + 0xA846: 0xCB72, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULPHIEUPH + 0xA847: 0xCB73, //HANGUL SYLLABLE SSANGCIEUC WEO RIEULHIEUH + 0xA848: 0xCB74, //HANGUL SYLLABLE SSANGCIEUC WEO MIEUM + 0xA849: 0xCB75, //HANGUL SYLLABLE SSANGCIEUC WEO PIEUP + 0xA84A: 0xCB76, //HANGUL SYLLABLE SSANGCIEUC WEO PIEUPSIOS + 0xA84B: 0xCB77, //HANGUL SYLLABLE SSANGCIEUC WEO SIOS + 0xA84C: 0xCB7A, //HANGUL SYLLABLE SSANGCIEUC WEO CIEUC + 0xA84D: 0xCB7B, //HANGUL SYLLABLE SSANGCIEUC WEO CHIEUCH + 0xA84E: 0xCB7C, //HANGUL SYLLABLE SSANGCIEUC WEO KHIEUKH + 0xA84F: 0xCB7D, //HANGUL SYLLABLE SSANGCIEUC WEO THIEUTH + 0xA850: 0xCB7E, //HANGUL SYLLABLE SSANGCIEUC WEO PHIEUPH + 0xA851: 0xCB7F, //HANGUL SYLLABLE SSANGCIEUC WEO HIEUH + 0xA852: 0xCB80, //HANGUL SYLLABLE SSANGCIEUC WE + 0xA853: 0xCB81, //HANGUL SYLLABLE SSANGCIEUC WE KIYEOK + 0xA854: 0xCB82, //HANGUL SYLLABLE SSANGCIEUC WE SSANGKIYEOK + 0xA855: 0xCB83, //HANGUL SYLLABLE SSANGCIEUC WE KIYEOKSIOS + 0xA856: 0xCB84, //HANGUL SYLLABLE SSANGCIEUC WE NIEUN + 0xA857: 0xCB85, //HANGUL SYLLABLE SSANGCIEUC WE NIEUNCIEUC + 0xA858: 0xCB86, //HANGUL SYLLABLE SSANGCIEUC WE NIEUNHIEUH + 0xA859: 0xCB87, //HANGUL SYLLABLE SSANGCIEUC WE TIKEUT + 0xA85A: 0xCB88, //HANGUL SYLLABLE SSANGCIEUC WE RIEUL + 0xA861: 0xCB89, //HANGUL SYLLABLE SSANGCIEUC WE RIEULKIYEOK + 0xA862: 0xCB8A, //HANGUL SYLLABLE SSANGCIEUC WE RIEULMIEUM + 0xA863: 0xCB8B, //HANGUL SYLLABLE SSANGCIEUC WE RIEULPIEUP + 0xA864: 0xCB8C, //HANGUL SYLLABLE SSANGCIEUC WE RIEULSIOS + 0xA865: 0xCB8D, //HANGUL SYLLABLE SSANGCIEUC WE RIEULTHIEUTH + 0xA866: 0xCB8E, //HANGUL SYLLABLE SSANGCIEUC WE RIEULPHIEUPH + 0xA867: 0xCB8F, //HANGUL SYLLABLE SSANGCIEUC WE RIEULHIEUH + 0xA868: 0xCB90, //HANGUL SYLLABLE SSANGCIEUC WE MIEUM + 0xA869: 0xCB91, //HANGUL SYLLABLE SSANGCIEUC WE PIEUP + 0xA86A: 0xCB92, //HANGUL SYLLABLE SSANGCIEUC WE PIEUPSIOS + 0xA86B: 0xCB93, //HANGUL SYLLABLE SSANGCIEUC WE SIOS + 0xA86C: 0xCB94, //HANGUL SYLLABLE SSANGCIEUC WE SSANGSIOS + 0xA86D: 0xCB95, //HANGUL SYLLABLE SSANGCIEUC WE IEUNG + 0xA86E: 0xCB96, //HANGUL SYLLABLE SSANGCIEUC WE CIEUC + 0xA86F: 0xCB97, //HANGUL SYLLABLE SSANGCIEUC WE CHIEUCH + 0xA870: 0xCB98, //HANGUL SYLLABLE SSANGCIEUC WE KHIEUKH + 0xA871: 0xCB99, //HANGUL SYLLABLE SSANGCIEUC WE THIEUTH + 0xA872: 0xCB9A, //HANGUL SYLLABLE SSANGCIEUC WE PHIEUPH + 0xA873: 0xCB9B, //HANGUL SYLLABLE SSANGCIEUC WE HIEUH + 0xA874: 0xCB9D, //HANGUL SYLLABLE SSANGCIEUC WI KIYEOK + 0xA875: 0xCB9E, //HANGUL SYLLABLE SSANGCIEUC WI SSANGKIYEOK + 0xA876: 0xCB9F, //HANGUL SYLLABLE SSANGCIEUC WI KIYEOKSIOS + 0xA877: 0xCBA0, //HANGUL SYLLABLE SSANGCIEUC WI NIEUN + 0xA878: 0xCBA1, //HANGUL SYLLABLE SSANGCIEUC WI NIEUNCIEUC + 0xA879: 0xCBA2, //HANGUL SYLLABLE SSANGCIEUC WI NIEUNHIEUH + 0xA87A: 0xCBA3, //HANGUL SYLLABLE SSANGCIEUC WI TIKEUT + 0xA881: 0xCBA4, //HANGUL SYLLABLE SSANGCIEUC WI RIEUL + 0xA882: 0xCBA5, //HANGUL SYLLABLE SSANGCIEUC WI RIEULKIYEOK + 0xA883: 0xCBA6, //HANGUL SYLLABLE SSANGCIEUC WI RIEULMIEUM + 0xA884: 0xCBA7, //HANGUL SYLLABLE SSANGCIEUC WI RIEULPIEUP + 0xA885: 0xCBA8, //HANGUL SYLLABLE SSANGCIEUC WI RIEULSIOS + 0xA886: 0xCBA9, //HANGUL SYLLABLE SSANGCIEUC WI RIEULTHIEUTH + 0xA887: 0xCBAA, //HANGUL SYLLABLE SSANGCIEUC WI RIEULPHIEUPH + 0xA888: 0xCBAB, //HANGUL SYLLABLE SSANGCIEUC WI RIEULHIEUH + 0xA889: 0xCBAC, //HANGUL SYLLABLE SSANGCIEUC WI MIEUM + 0xA88A: 0xCBAD, //HANGUL SYLLABLE SSANGCIEUC WI PIEUP + 0xA88B: 0xCBAE, //HANGUL SYLLABLE SSANGCIEUC WI PIEUPSIOS + 0xA88C: 0xCBAF, //HANGUL SYLLABLE SSANGCIEUC WI SIOS + 0xA88D: 0xCBB0, //HANGUL SYLLABLE SSANGCIEUC WI SSANGSIOS + 0xA88E: 0xCBB1, //HANGUL SYLLABLE SSANGCIEUC WI IEUNG + 0xA88F: 0xCBB2, //HANGUL SYLLABLE SSANGCIEUC WI CIEUC + 0xA890: 0xCBB3, //HANGUL SYLLABLE SSANGCIEUC WI CHIEUCH + 0xA891: 0xCBB4, //HANGUL SYLLABLE SSANGCIEUC WI KHIEUKH + 0xA892: 0xCBB5, //HANGUL SYLLABLE SSANGCIEUC WI THIEUTH + 0xA893: 0xCBB6, //HANGUL SYLLABLE SSANGCIEUC WI PHIEUPH + 0xA894: 0xCBB7, //HANGUL SYLLABLE SSANGCIEUC WI HIEUH + 0xA895: 0xCBB9, //HANGUL SYLLABLE SSANGCIEUC YU KIYEOK + 0xA896: 0xCBBA, //HANGUL SYLLABLE SSANGCIEUC YU SSANGKIYEOK + 0xA897: 0xCBBB, //HANGUL SYLLABLE SSANGCIEUC YU KIYEOKSIOS + 0xA898: 0xCBBC, //HANGUL SYLLABLE SSANGCIEUC YU NIEUN + 0xA899: 0xCBBD, //HANGUL SYLLABLE SSANGCIEUC YU NIEUNCIEUC + 0xA89A: 0xCBBE, //HANGUL SYLLABLE SSANGCIEUC YU NIEUNHIEUH + 0xA89B: 0xCBBF, //HANGUL SYLLABLE SSANGCIEUC YU TIKEUT + 0xA89C: 0xCBC0, //HANGUL SYLLABLE SSANGCIEUC YU RIEUL + 0xA89D: 0xCBC1, //HANGUL SYLLABLE SSANGCIEUC YU RIEULKIYEOK + 0xA89E: 0xCBC2, //HANGUL SYLLABLE SSANGCIEUC YU RIEULMIEUM + 0xA89F: 0xCBC3, //HANGUL SYLLABLE SSANGCIEUC YU RIEULPIEUP + 0xA8A0: 0xCBC4, //HANGUL SYLLABLE SSANGCIEUC YU RIEULSIOS + 0xA8A1: 0x00C6, //LATIN CAPITAL LETTER AE + 0xA8A2: 0x00D0, //LATIN CAPITAL LETTER ETH + 0xA8A3: 0x00AA, //FEMININE ORDINAL INDICATOR + 0xA8A4: 0x0126, //LATIN CAPITAL LETTER H WITH STROKE + 0xA8A6: 0x0132, //LATIN CAPITAL LIGATURE IJ + 0xA8A8: 0x013F, //LATIN CAPITAL LETTER L WITH MIDDLE DOT + 0xA8A9: 0x0141, //LATIN CAPITAL LETTER L WITH STROKE + 0xA8AA: 0x00D8, //LATIN CAPITAL LETTER O WITH STROKE + 0xA8AB: 0x0152, //LATIN CAPITAL LIGATURE OE + 0xA8AC: 0x00BA, //MASCULINE ORDINAL INDICATOR + 0xA8AD: 0x00DE, //LATIN CAPITAL LETTER THORN + 0xA8AE: 0x0166, //LATIN CAPITAL LETTER T WITH STROKE + 0xA8AF: 0x014A, //LATIN CAPITAL LETTER ENG + 0xA8B1: 0x3260, //CIRCLED HANGUL KIYEOK + 0xA8B2: 0x3261, //CIRCLED HANGUL NIEUN + 0xA8B3: 0x3262, //CIRCLED HANGUL TIKEUT + 0xA8B4: 0x3263, //CIRCLED HANGUL RIEUL + 0xA8B5: 0x3264, //CIRCLED HANGUL MIEUM + 0xA8B6: 0x3265, //CIRCLED HANGUL PIEUP + 0xA8B7: 0x3266, //CIRCLED HANGUL SIOS + 0xA8B8: 0x3267, //CIRCLED HANGUL IEUNG + 0xA8B9: 0x3268, //CIRCLED HANGUL CIEUC + 0xA8BA: 0x3269, //CIRCLED HANGUL CHIEUCH + 0xA8BB: 0x326A, //CIRCLED HANGUL KHIEUKH + 0xA8BC: 0x326B, //CIRCLED HANGUL THIEUTH + 0xA8BD: 0x326C, //CIRCLED HANGUL PHIEUPH + 0xA8BE: 0x326D, //CIRCLED HANGUL HIEUH + 0xA8BF: 0x326E, //CIRCLED HANGUL KIYEOK A + 0xA8C0: 0x326F, //CIRCLED HANGUL NIEUN A + 0xA8C1: 0x3270, //CIRCLED HANGUL TIKEUT A + 0xA8C2: 0x3271, //CIRCLED HANGUL RIEUL A + 0xA8C3: 0x3272, //CIRCLED HANGUL MIEUM A + 0xA8C4: 0x3273, //CIRCLED HANGUL PIEUP A + 0xA8C5: 0x3274, //CIRCLED HANGUL SIOS A + 0xA8C6: 0x3275, //CIRCLED HANGUL IEUNG A + 0xA8C7: 0x3276, //CIRCLED HANGUL CIEUC A + 0xA8C8: 0x3277, //CIRCLED HANGUL CHIEUCH A + 0xA8C9: 0x3278, //CIRCLED HANGUL KHIEUKH A + 0xA8CA: 0x3279, //CIRCLED HANGUL THIEUTH A + 0xA8CB: 0x327A, //CIRCLED HANGUL PHIEUPH A + 0xA8CC: 0x327B, //CIRCLED HANGUL HIEUH A + 0xA8CD: 0x24D0, //CIRCLED LATIN SMALL LETTER A + 0xA8CE: 0x24D1, //CIRCLED LATIN SMALL LETTER B + 0xA8CF: 0x24D2, //CIRCLED LATIN SMALL LETTER C + 0xA8D0: 0x24D3, //CIRCLED LATIN SMALL LETTER D + 0xA8D1: 0x24D4, //CIRCLED LATIN SMALL LETTER E + 0xA8D2: 0x24D5, //CIRCLED LATIN SMALL LETTER F + 0xA8D3: 0x24D6, //CIRCLED LATIN SMALL LETTER G + 0xA8D4: 0x24D7, //CIRCLED LATIN SMALL LETTER H + 0xA8D5: 0x24D8, //CIRCLED LATIN SMALL LETTER I + 0xA8D6: 0x24D9, //CIRCLED LATIN SMALL LETTER J + 0xA8D7: 0x24DA, //CIRCLED LATIN SMALL LETTER K + 0xA8D8: 0x24DB, //CIRCLED LATIN SMALL LETTER L + 0xA8D9: 0x24DC, //CIRCLED LATIN SMALL LETTER M + 0xA8DA: 0x24DD, //CIRCLED LATIN SMALL LETTER N + 0xA8DB: 0x24DE, //CIRCLED LATIN SMALL LETTER O + 0xA8DC: 0x24DF, //CIRCLED LATIN SMALL LETTER P + 0xA8DD: 0x24E0, //CIRCLED LATIN SMALL LETTER Q + 0xA8DE: 0x24E1, //CIRCLED LATIN SMALL LETTER R + 0xA8DF: 0x24E2, //CIRCLED LATIN SMALL LETTER S + 0xA8E0: 0x24E3, //CIRCLED LATIN SMALL LETTER T + 0xA8E1: 0x24E4, //CIRCLED LATIN SMALL LETTER U + 0xA8E2: 0x24E5, //CIRCLED LATIN SMALL LETTER V + 0xA8E3: 0x24E6, //CIRCLED LATIN SMALL LETTER W + 0xA8E4: 0x24E7, //CIRCLED LATIN SMALL LETTER X + 0xA8E5: 0x24E8, //CIRCLED LATIN SMALL LETTER Y + 0xA8E6: 0x24E9, //CIRCLED LATIN SMALL LETTER Z + 0xA8E7: 0x2460, //CIRCLED DIGIT ONE + 0xA8E8: 0x2461, //CIRCLED DIGIT TWO + 0xA8E9: 0x2462, //CIRCLED DIGIT THREE + 0xA8EA: 0x2463, //CIRCLED DIGIT FOUR + 0xA8EB: 0x2464, //CIRCLED DIGIT FIVE + 0xA8EC: 0x2465, //CIRCLED DIGIT SIX + 0xA8ED: 0x2466, //CIRCLED DIGIT SEVEN + 0xA8EE: 0x2467, //CIRCLED DIGIT EIGHT + 0xA8EF: 0x2468, //CIRCLED DIGIT NINE + 0xA8F0: 0x2469, //CIRCLED NUMBER TEN + 0xA8F1: 0x246A, //CIRCLED NUMBER ELEVEN + 0xA8F2: 0x246B, //CIRCLED NUMBER TWELVE + 0xA8F3: 0x246C, //CIRCLED NUMBER THIRTEEN + 0xA8F4: 0x246D, //CIRCLED NUMBER FOURTEEN + 0xA8F5: 0x246E, //CIRCLED NUMBER FIFTEEN + 0xA8F6: 0x00BD, //VULGAR FRACTION ONE HALF + 0xA8F7: 0x2153, //VULGAR FRACTION ONE THIRD + 0xA8F8: 0x2154, //VULGAR FRACTION TWO THIRDS + 0xA8F9: 0x00BC, //VULGAR FRACTION ONE QUARTER + 0xA8FA: 0x00BE, //VULGAR FRACTION THREE QUARTERS + 0xA8FB: 0x215B, //VULGAR FRACTION ONE EIGHTH + 0xA8FC: 0x215C, //VULGAR FRACTION THREE EIGHTHS + 0xA8FD: 0x215D, //VULGAR FRACTION FIVE EIGHTHS + 0xA8FE: 0x215E, //VULGAR FRACTION SEVEN EIGHTHS + 0xA941: 0xCBC5, //HANGUL SYLLABLE SSANGCIEUC YU RIEULTHIEUTH + 0xA942: 0xCBC6, //HANGUL SYLLABLE SSANGCIEUC YU RIEULPHIEUPH + 0xA943: 0xCBC7, //HANGUL SYLLABLE SSANGCIEUC YU RIEULHIEUH + 0xA944: 0xCBC8, //HANGUL SYLLABLE SSANGCIEUC YU MIEUM + 0xA945: 0xCBC9, //HANGUL SYLLABLE SSANGCIEUC YU PIEUP + 0xA946: 0xCBCA, //HANGUL SYLLABLE SSANGCIEUC YU PIEUPSIOS + 0xA947: 0xCBCB, //HANGUL SYLLABLE SSANGCIEUC YU SIOS + 0xA948: 0xCBCC, //HANGUL SYLLABLE SSANGCIEUC YU SSANGSIOS + 0xA949: 0xCBCD, //HANGUL SYLLABLE SSANGCIEUC YU IEUNG + 0xA94A: 0xCBCE, //HANGUL SYLLABLE SSANGCIEUC YU CIEUC + 0xA94B: 0xCBCF, //HANGUL SYLLABLE SSANGCIEUC YU CHIEUCH + 0xA94C: 0xCBD0, //HANGUL SYLLABLE SSANGCIEUC YU KHIEUKH + 0xA94D: 0xCBD1, //HANGUL SYLLABLE SSANGCIEUC YU THIEUTH + 0xA94E: 0xCBD2, //HANGUL SYLLABLE SSANGCIEUC YU PHIEUPH + 0xA94F: 0xCBD3, //HANGUL SYLLABLE SSANGCIEUC YU HIEUH + 0xA950: 0xCBD5, //HANGUL SYLLABLE SSANGCIEUC EU KIYEOK + 0xA951: 0xCBD6, //HANGUL SYLLABLE SSANGCIEUC EU SSANGKIYEOK + 0xA952: 0xCBD7, //HANGUL SYLLABLE SSANGCIEUC EU KIYEOKSIOS + 0xA953: 0xCBD8, //HANGUL SYLLABLE SSANGCIEUC EU NIEUN + 0xA954: 0xCBD9, //HANGUL SYLLABLE SSANGCIEUC EU NIEUNCIEUC + 0xA955: 0xCBDA, //HANGUL SYLLABLE SSANGCIEUC EU NIEUNHIEUH + 0xA956: 0xCBDB, //HANGUL SYLLABLE SSANGCIEUC EU TIKEUT + 0xA957: 0xCBDC, //HANGUL SYLLABLE SSANGCIEUC EU RIEUL + 0xA958: 0xCBDD, //HANGUL SYLLABLE SSANGCIEUC EU RIEULKIYEOK + 0xA959: 0xCBDE, //HANGUL SYLLABLE SSANGCIEUC EU RIEULMIEUM + 0xA95A: 0xCBDF, //HANGUL SYLLABLE SSANGCIEUC EU RIEULPIEUP + 0xA961: 0xCBE0, //HANGUL SYLLABLE SSANGCIEUC EU RIEULSIOS + 0xA962: 0xCBE1, //HANGUL SYLLABLE SSANGCIEUC EU RIEULTHIEUTH + 0xA963: 0xCBE2, //HANGUL SYLLABLE SSANGCIEUC EU RIEULPHIEUPH + 0xA964: 0xCBE3, //HANGUL SYLLABLE SSANGCIEUC EU RIEULHIEUH + 0xA965: 0xCBE5, //HANGUL SYLLABLE SSANGCIEUC EU PIEUP + 0xA966: 0xCBE6, //HANGUL SYLLABLE SSANGCIEUC EU PIEUPSIOS + 0xA967: 0xCBE8, //HANGUL SYLLABLE SSANGCIEUC EU SSANGSIOS + 0xA968: 0xCBEA, //HANGUL SYLLABLE SSANGCIEUC EU CIEUC + 0xA969: 0xCBEB, //HANGUL SYLLABLE SSANGCIEUC EU CHIEUCH + 0xA96A: 0xCBEC, //HANGUL SYLLABLE SSANGCIEUC EU KHIEUKH + 0xA96B: 0xCBED, //HANGUL SYLLABLE SSANGCIEUC EU THIEUTH + 0xA96C: 0xCBEE, //HANGUL SYLLABLE SSANGCIEUC EU PHIEUPH + 0xA96D: 0xCBEF, //HANGUL SYLLABLE SSANGCIEUC EU HIEUH + 0xA96E: 0xCBF0, //HANGUL SYLLABLE SSANGCIEUC YI + 0xA96F: 0xCBF1, //HANGUL SYLLABLE SSANGCIEUC YI KIYEOK + 0xA970: 0xCBF2, //HANGUL SYLLABLE SSANGCIEUC YI SSANGKIYEOK + 0xA971: 0xCBF3, //HANGUL SYLLABLE SSANGCIEUC YI KIYEOKSIOS + 0xA972: 0xCBF4, //HANGUL SYLLABLE SSANGCIEUC YI NIEUN + 0xA973: 0xCBF5, //HANGUL SYLLABLE SSANGCIEUC YI NIEUNCIEUC + 0xA974: 0xCBF6, //HANGUL SYLLABLE SSANGCIEUC YI NIEUNHIEUH + 0xA975: 0xCBF7, //HANGUL SYLLABLE SSANGCIEUC YI TIKEUT + 0xA976: 0xCBF8, //HANGUL SYLLABLE SSANGCIEUC YI RIEUL + 0xA977: 0xCBF9, //HANGUL SYLLABLE SSANGCIEUC YI RIEULKIYEOK + 0xA978: 0xCBFA, //HANGUL SYLLABLE SSANGCIEUC YI RIEULMIEUM + 0xA979: 0xCBFB, //HANGUL SYLLABLE SSANGCIEUC YI RIEULPIEUP + 0xA97A: 0xCBFC, //HANGUL SYLLABLE SSANGCIEUC YI RIEULSIOS + 0xA981: 0xCBFD, //HANGUL SYLLABLE SSANGCIEUC YI RIEULTHIEUTH + 0xA982: 0xCBFE, //HANGUL SYLLABLE SSANGCIEUC YI RIEULPHIEUPH + 0xA983: 0xCBFF, //HANGUL SYLLABLE SSANGCIEUC YI RIEULHIEUH + 0xA984: 0xCC00, //HANGUL SYLLABLE SSANGCIEUC YI MIEUM + 0xA985: 0xCC01, //HANGUL SYLLABLE SSANGCIEUC YI PIEUP + 0xA986: 0xCC02, //HANGUL SYLLABLE SSANGCIEUC YI PIEUPSIOS + 0xA987: 0xCC03, //HANGUL SYLLABLE SSANGCIEUC YI SIOS + 0xA988: 0xCC04, //HANGUL SYLLABLE SSANGCIEUC YI SSANGSIOS + 0xA989: 0xCC05, //HANGUL SYLLABLE SSANGCIEUC YI IEUNG + 0xA98A: 0xCC06, //HANGUL SYLLABLE SSANGCIEUC YI CIEUC + 0xA98B: 0xCC07, //HANGUL SYLLABLE SSANGCIEUC YI CHIEUCH + 0xA98C: 0xCC08, //HANGUL SYLLABLE SSANGCIEUC YI KHIEUKH + 0xA98D: 0xCC09, //HANGUL SYLLABLE SSANGCIEUC YI THIEUTH + 0xA98E: 0xCC0A, //HANGUL SYLLABLE SSANGCIEUC YI PHIEUPH + 0xA98F: 0xCC0B, //HANGUL SYLLABLE SSANGCIEUC YI HIEUH + 0xA990: 0xCC0E, //HANGUL SYLLABLE SSANGCIEUC I SSANGKIYEOK + 0xA991: 0xCC0F, //HANGUL SYLLABLE SSANGCIEUC I KIYEOKSIOS + 0xA992: 0xCC11, //HANGUL SYLLABLE SSANGCIEUC I NIEUNCIEUC + 0xA993: 0xCC12, //HANGUL SYLLABLE SSANGCIEUC I NIEUNHIEUH + 0xA994: 0xCC13, //HANGUL SYLLABLE SSANGCIEUC I TIKEUT + 0xA995: 0xCC15, //HANGUL SYLLABLE SSANGCIEUC I RIEULKIYEOK + 0xA996: 0xCC16, //HANGUL SYLLABLE SSANGCIEUC I RIEULMIEUM + 0xA997: 0xCC17, //HANGUL SYLLABLE SSANGCIEUC I RIEULPIEUP + 0xA998: 0xCC18, //HANGUL SYLLABLE SSANGCIEUC I RIEULSIOS + 0xA999: 0xCC19, //HANGUL SYLLABLE SSANGCIEUC I RIEULTHIEUTH + 0xA99A: 0xCC1A, //HANGUL SYLLABLE SSANGCIEUC I RIEULPHIEUPH + 0xA99B: 0xCC1B, //HANGUL SYLLABLE SSANGCIEUC I RIEULHIEUH + 0xA99C: 0xCC1E, //HANGUL SYLLABLE SSANGCIEUC I PIEUPSIOS + 0xA99D: 0xCC1F, //HANGUL SYLLABLE SSANGCIEUC I SIOS + 0xA99E: 0xCC20, //HANGUL SYLLABLE SSANGCIEUC I SSANGSIOS + 0xA99F: 0xCC23, //HANGUL SYLLABLE SSANGCIEUC I CHIEUCH + 0xA9A0: 0xCC24, //HANGUL SYLLABLE SSANGCIEUC I KHIEUKH + 0xA9A1: 0x00E6, //LATIN SMALL LETTER AE + 0xA9A2: 0x0111, //LATIN SMALL LETTER D WITH STROKE + 0xA9A3: 0x00F0, //LATIN SMALL LETTER ETH + 0xA9A4: 0x0127, //LATIN SMALL LETTER H WITH STROKE + 0xA9A5: 0x0131, //LATIN SMALL LETTER DOTLESS I + 0xA9A6: 0x0133, //LATIN SMALL LIGATURE IJ + 0xA9A7: 0x0138, //LATIN SMALL LETTER KRA + 0xA9A8: 0x0140, //LATIN SMALL LETTER L WITH MIDDLE DOT + 0xA9A9: 0x0142, //LATIN SMALL LETTER L WITH STROKE + 0xA9AA: 0x00F8, //LATIN SMALL LETTER O WITH STROKE + 0xA9AB: 0x0153, //LATIN SMALL LIGATURE OE + 0xA9AC: 0x00DF, //LATIN SMALL LETTER SHARP S + 0xA9AD: 0x00FE, //LATIN SMALL LETTER THORN + 0xA9AE: 0x0167, //LATIN SMALL LETTER T WITH STROKE + 0xA9AF: 0x014B, //LATIN SMALL LETTER ENG + 0xA9B0: 0x0149, //LATIN SMALL LETTER N PRECEDED BY APOSTROPHE + 0xA9B1: 0x3200, //PARENTHESIZED HANGUL KIYEOK + 0xA9B2: 0x3201, //PARENTHESIZED HANGUL NIEUN + 0xA9B3: 0x3202, //PARENTHESIZED HANGUL TIKEUT + 0xA9B4: 0x3203, //PARENTHESIZED HANGUL RIEUL + 0xA9B5: 0x3204, //PARENTHESIZED HANGUL MIEUM + 0xA9B6: 0x3205, //PARENTHESIZED HANGUL PIEUP + 0xA9B7: 0x3206, //PARENTHESIZED HANGUL SIOS + 0xA9B8: 0x3207, //PARENTHESIZED HANGUL IEUNG + 0xA9B9: 0x3208, //PARENTHESIZED HANGUL CIEUC + 0xA9BA: 0x3209, //PARENTHESIZED HANGUL CHIEUCH + 0xA9BB: 0x320A, //PARENTHESIZED HANGUL KHIEUKH + 0xA9BC: 0x320B, //PARENTHESIZED HANGUL THIEUTH + 0xA9BD: 0x320C, //PARENTHESIZED HANGUL PHIEUPH + 0xA9BE: 0x320D, //PARENTHESIZED HANGUL HIEUH + 0xA9BF: 0x320E, //PARENTHESIZED HANGUL KIYEOK A + 0xA9C0: 0x320F, //PARENTHESIZED HANGUL NIEUN A + 0xA9C1: 0x3210, //PARENTHESIZED HANGUL TIKEUT A + 0xA9C2: 0x3211, //PARENTHESIZED HANGUL RIEUL A + 0xA9C3: 0x3212, //PARENTHESIZED HANGUL MIEUM A + 0xA9C4: 0x3213, //PARENTHESIZED HANGUL PIEUP A + 0xA9C5: 0x3214, //PARENTHESIZED HANGUL SIOS A + 0xA9C6: 0x3215, //PARENTHESIZED HANGUL IEUNG A + 0xA9C7: 0x3216, //PARENTHESIZED HANGUL CIEUC A + 0xA9C8: 0x3217, //PARENTHESIZED HANGUL CHIEUCH A + 0xA9C9: 0x3218, //PARENTHESIZED HANGUL KHIEUKH A + 0xA9CA: 0x3219, //PARENTHESIZED HANGUL THIEUTH A + 0xA9CB: 0x321A, //PARENTHESIZED HANGUL PHIEUPH A + 0xA9CC: 0x321B, //PARENTHESIZED HANGUL HIEUH A + 0xA9CD: 0x249C, //PARENTHESIZED LATIN SMALL LETTER A + 0xA9CE: 0x249D, //PARENTHESIZED LATIN SMALL LETTER B + 0xA9CF: 0x249E, //PARENTHESIZED LATIN SMALL LETTER C + 0xA9D0: 0x249F, //PARENTHESIZED LATIN SMALL LETTER D + 0xA9D1: 0x24A0, //PARENTHESIZED LATIN SMALL LETTER E + 0xA9D2: 0x24A1, //PARENTHESIZED LATIN SMALL LETTER F + 0xA9D3: 0x24A2, //PARENTHESIZED LATIN SMALL LETTER G + 0xA9D4: 0x24A3, //PARENTHESIZED LATIN SMALL LETTER H + 0xA9D5: 0x24A4, //PARENTHESIZED LATIN SMALL LETTER I + 0xA9D6: 0x24A5, //PARENTHESIZED LATIN SMALL LETTER J + 0xA9D7: 0x24A6, //PARENTHESIZED LATIN SMALL LETTER K + 0xA9D8: 0x24A7, //PARENTHESIZED LATIN SMALL LETTER L + 0xA9D9: 0x24A8, //PARENTHESIZED LATIN SMALL LETTER M + 0xA9DA: 0x24A9, //PARENTHESIZED LATIN SMALL LETTER N + 0xA9DB: 0x24AA, //PARENTHESIZED LATIN SMALL LETTER O + 0xA9DC: 0x24AB, //PARENTHESIZED LATIN SMALL LETTER P + 0xA9DD: 0x24AC, //PARENTHESIZED LATIN SMALL LETTER Q + 0xA9DE: 0x24AD, //PARENTHESIZED LATIN SMALL LETTER R + 0xA9DF: 0x24AE, //PARENTHESIZED LATIN SMALL LETTER S + 0xA9E0: 0x24AF, //PARENTHESIZED LATIN SMALL LETTER T + 0xA9E1: 0x24B0, //PARENTHESIZED LATIN SMALL LETTER U + 0xA9E2: 0x24B1, //PARENTHESIZED LATIN SMALL LETTER V + 0xA9E3: 0x24B2, //PARENTHESIZED LATIN SMALL LETTER W + 0xA9E4: 0x24B3, //PARENTHESIZED LATIN SMALL LETTER X + 0xA9E5: 0x24B4, //PARENTHESIZED LATIN SMALL LETTER Y + 0xA9E6: 0x24B5, //PARENTHESIZED LATIN SMALL LETTER Z + 0xA9E7: 0x2474, //PARENTHESIZED DIGIT ONE + 0xA9E8: 0x2475, //PARENTHESIZED DIGIT TWO + 0xA9E9: 0x2476, //PARENTHESIZED DIGIT THREE + 0xA9EA: 0x2477, //PARENTHESIZED DIGIT FOUR + 0xA9EB: 0x2478, //PARENTHESIZED DIGIT FIVE + 0xA9EC: 0x2479, //PARENTHESIZED DIGIT SIX + 0xA9ED: 0x247A, //PARENTHESIZED DIGIT SEVEN + 0xA9EE: 0x247B, //PARENTHESIZED DIGIT EIGHT + 0xA9EF: 0x247C, //PARENTHESIZED DIGIT NINE + 0xA9F0: 0x247D, //PARENTHESIZED NUMBER TEN + 0xA9F1: 0x247E, //PARENTHESIZED NUMBER ELEVEN + 0xA9F2: 0x247F, //PARENTHESIZED NUMBER TWELVE + 0xA9F3: 0x2480, //PARENTHESIZED NUMBER THIRTEEN + 0xA9F4: 0x2481, //PARENTHESIZED NUMBER FOURTEEN + 0xA9F5: 0x2482, //PARENTHESIZED NUMBER FIFTEEN + 0xA9F6: 0x00B9, //SUPERSCRIPT ONE + 0xA9F7: 0x00B2, //SUPERSCRIPT TWO + 0xA9F8: 0x00B3, //SUPERSCRIPT THREE + 0xA9F9: 0x2074, //SUPERSCRIPT FOUR + 0xA9FA: 0x207F, //SUPERSCRIPT LATIN SMALL LETTER N + 0xA9FB: 0x2081, //SUBSCRIPT ONE + 0xA9FC: 0x2082, //SUBSCRIPT TWO + 0xA9FD: 0x2083, //SUBSCRIPT THREE + 0xA9FE: 0x2084, //SUBSCRIPT FOUR + 0xAA41: 0xCC25, //HANGUL SYLLABLE SSANGCIEUC I THIEUTH + 0xAA42: 0xCC26, //HANGUL SYLLABLE SSANGCIEUC I PHIEUPH + 0xAA43: 0xCC2A, //HANGUL SYLLABLE CHIEUCH A SSANGKIYEOK + 0xAA44: 0xCC2B, //HANGUL SYLLABLE CHIEUCH A KIYEOKSIOS + 0xAA45: 0xCC2D, //HANGUL SYLLABLE CHIEUCH A NIEUNCIEUC + 0xAA46: 0xCC2F, //HANGUL SYLLABLE CHIEUCH A TIKEUT + 0xAA47: 0xCC31, //HANGUL SYLLABLE CHIEUCH A RIEULKIYEOK + 0xAA48: 0xCC32, //HANGUL SYLLABLE CHIEUCH A RIEULMIEUM + 0xAA49: 0xCC33, //HANGUL SYLLABLE CHIEUCH A RIEULPIEUP + 0xAA4A: 0xCC34, //HANGUL SYLLABLE CHIEUCH A RIEULSIOS + 0xAA4B: 0xCC35, //HANGUL SYLLABLE CHIEUCH A RIEULTHIEUTH + 0xAA4C: 0xCC36, //HANGUL SYLLABLE CHIEUCH A RIEULPHIEUPH + 0xAA4D: 0xCC37, //HANGUL SYLLABLE CHIEUCH A RIEULHIEUH + 0xAA4E: 0xCC3A, //HANGUL SYLLABLE CHIEUCH A PIEUPSIOS + 0xAA4F: 0xCC3F, //HANGUL SYLLABLE CHIEUCH A CHIEUCH + 0xAA50: 0xCC40, //HANGUL SYLLABLE CHIEUCH A KHIEUKH + 0xAA51: 0xCC41, //HANGUL SYLLABLE CHIEUCH A THIEUTH + 0xAA52: 0xCC42, //HANGUL SYLLABLE CHIEUCH A PHIEUPH + 0xAA53: 0xCC43, //HANGUL SYLLABLE CHIEUCH A HIEUH + 0xAA54: 0xCC46, //HANGUL SYLLABLE CHIEUCH AE SSANGKIYEOK + 0xAA55: 0xCC47, //HANGUL SYLLABLE CHIEUCH AE KIYEOKSIOS + 0xAA56: 0xCC49, //HANGUL SYLLABLE CHIEUCH AE NIEUNCIEUC + 0xAA57: 0xCC4A, //HANGUL SYLLABLE CHIEUCH AE NIEUNHIEUH + 0xAA58: 0xCC4B, //HANGUL SYLLABLE CHIEUCH AE TIKEUT + 0xAA59: 0xCC4D, //HANGUL SYLLABLE CHIEUCH AE RIEULKIYEOK + 0xAA5A: 0xCC4E, //HANGUL SYLLABLE CHIEUCH AE RIEULMIEUM + 0xAA61: 0xCC4F, //HANGUL SYLLABLE CHIEUCH AE RIEULPIEUP + 0xAA62: 0xCC50, //HANGUL SYLLABLE CHIEUCH AE RIEULSIOS + 0xAA63: 0xCC51, //HANGUL SYLLABLE CHIEUCH AE RIEULTHIEUTH + 0xAA64: 0xCC52, //HANGUL SYLLABLE CHIEUCH AE RIEULPHIEUPH + 0xAA65: 0xCC53, //HANGUL SYLLABLE CHIEUCH AE RIEULHIEUH + 0xAA66: 0xCC56, //HANGUL SYLLABLE CHIEUCH AE PIEUPSIOS + 0xAA67: 0xCC5A, //HANGUL SYLLABLE CHIEUCH AE CIEUC + 0xAA68: 0xCC5B, //HANGUL SYLLABLE CHIEUCH AE CHIEUCH + 0xAA69: 0xCC5C, //HANGUL SYLLABLE CHIEUCH AE KHIEUKH + 0xAA6A: 0xCC5D, //HANGUL SYLLABLE CHIEUCH AE THIEUTH + 0xAA6B: 0xCC5E, //HANGUL SYLLABLE CHIEUCH AE PHIEUPH + 0xAA6C: 0xCC5F, //HANGUL SYLLABLE CHIEUCH AE HIEUH + 0xAA6D: 0xCC61, //HANGUL SYLLABLE CHIEUCH YA KIYEOK + 0xAA6E: 0xCC62, //HANGUL SYLLABLE CHIEUCH YA SSANGKIYEOK + 0xAA6F: 0xCC63, //HANGUL SYLLABLE CHIEUCH YA KIYEOKSIOS + 0xAA70: 0xCC65, //HANGUL SYLLABLE CHIEUCH YA NIEUNCIEUC + 0xAA71: 0xCC67, //HANGUL SYLLABLE CHIEUCH YA TIKEUT + 0xAA72: 0xCC69, //HANGUL SYLLABLE CHIEUCH YA RIEULKIYEOK + 0xAA73: 0xCC6A, //HANGUL SYLLABLE CHIEUCH YA RIEULMIEUM + 0xAA74: 0xCC6B, //HANGUL SYLLABLE CHIEUCH YA RIEULPIEUP + 0xAA75: 0xCC6C, //HANGUL SYLLABLE CHIEUCH YA RIEULSIOS + 0xAA76: 0xCC6D, //HANGUL SYLLABLE CHIEUCH YA RIEULTHIEUTH + 0xAA77: 0xCC6E, //HANGUL SYLLABLE CHIEUCH YA RIEULPHIEUPH + 0xAA78: 0xCC6F, //HANGUL SYLLABLE CHIEUCH YA RIEULHIEUH + 0xAA79: 0xCC71, //HANGUL SYLLABLE CHIEUCH YA PIEUP + 0xAA7A: 0xCC72, //HANGUL SYLLABLE CHIEUCH YA PIEUPSIOS + 0xAA81: 0xCC73, //HANGUL SYLLABLE CHIEUCH YA SIOS + 0xAA82: 0xCC74, //HANGUL SYLLABLE CHIEUCH YA SSANGSIOS + 0xAA83: 0xCC76, //HANGUL SYLLABLE CHIEUCH YA CIEUC + 0xAA84: 0xCC77, //HANGUL SYLLABLE CHIEUCH YA CHIEUCH + 0xAA85: 0xCC78, //HANGUL SYLLABLE CHIEUCH YA KHIEUKH + 0xAA86: 0xCC79, //HANGUL SYLLABLE CHIEUCH YA THIEUTH + 0xAA87: 0xCC7A, //HANGUL SYLLABLE CHIEUCH YA PHIEUPH + 0xAA88: 0xCC7B, //HANGUL SYLLABLE CHIEUCH YA HIEUH + 0xAA89: 0xCC7C, //HANGUL SYLLABLE CHIEUCH YAE + 0xAA8A: 0xCC7D, //HANGUL SYLLABLE CHIEUCH YAE KIYEOK + 0xAA8B: 0xCC7E, //HANGUL SYLLABLE CHIEUCH YAE SSANGKIYEOK + 0xAA8C: 0xCC7F, //HANGUL SYLLABLE CHIEUCH YAE KIYEOKSIOS + 0xAA8D: 0xCC80, //HANGUL SYLLABLE CHIEUCH YAE NIEUN + 0xAA8E: 0xCC81, //HANGUL SYLLABLE CHIEUCH YAE NIEUNCIEUC + 0xAA8F: 0xCC82, //HANGUL SYLLABLE CHIEUCH YAE NIEUNHIEUH + 0xAA90: 0xCC83, //HANGUL SYLLABLE CHIEUCH YAE TIKEUT + 0xAA91: 0xCC84, //HANGUL SYLLABLE CHIEUCH YAE RIEUL + 0xAA92: 0xCC85, //HANGUL SYLLABLE CHIEUCH YAE RIEULKIYEOK + 0xAA93: 0xCC86, //HANGUL SYLLABLE CHIEUCH YAE RIEULMIEUM + 0xAA94: 0xCC87, //HANGUL SYLLABLE CHIEUCH YAE RIEULPIEUP + 0xAA95: 0xCC88, //HANGUL SYLLABLE CHIEUCH YAE RIEULSIOS + 0xAA96: 0xCC89, //HANGUL SYLLABLE CHIEUCH YAE RIEULTHIEUTH + 0xAA97: 0xCC8A, //HANGUL SYLLABLE CHIEUCH YAE RIEULPHIEUPH + 0xAA98: 0xCC8B, //HANGUL SYLLABLE CHIEUCH YAE RIEULHIEUH + 0xAA99: 0xCC8C, //HANGUL SYLLABLE CHIEUCH YAE MIEUM + 0xAA9A: 0xCC8D, //HANGUL SYLLABLE CHIEUCH YAE PIEUP + 0xAA9B: 0xCC8E, //HANGUL SYLLABLE CHIEUCH YAE PIEUPSIOS + 0xAA9C: 0xCC8F, //HANGUL SYLLABLE CHIEUCH YAE SIOS + 0xAA9D: 0xCC90, //HANGUL SYLLABLE CHIEUCH YAE SSANGSIOS + 0xAA9E: 0xCC91, //HANGUL SYLLABLE CHIEUCH YAE IEUNG + 0xAA9F: 0xCC92, //HANGUL SYLLABLE CHIEUCH YAE CIEUC + 0xAAA0: 0xCC93, //HANGUL SYLLABLE CHIEUCH YAE CHIEUCH + 0xAAA1: 0x3041, //HIRAGANA LETTER SMALL A + 0xAAA2: 0x3042, //HIRAGANA LETTER A + 0xAAA3: 0x3043, //HIRAGANA LETTER SMALL I + 0xAAA4: 0x3044, //HIRAGANA LETTER I + 0xAAA5: 0x3045, //HIRAGANA LETTER SMALL U + 0xAAA6: 0x3046, //HIRAGANA LETTER U + 0xAAA7: 0x3047, //HIRAGANA LETTER SMALL E + 0xAAA8: 0x3048, //HIRAGANA LETTER E + 0xAAA9: 0x3049, //HIRAGANA LETTER SMALL O + 0xAAAA: 0x304A, //HIRAGANA LETTER O + 0xAAAB: 0x304B, //HIRAGANA LETTER KA + 0xAAAC: 0x304C, //HIRAGANA LETTER GA + 0xAAAD: 0x304D, //HIRAGANA LETTER KI + 0xAAAE: 0x304E, //HIRAGANA LETTER GI + 0xAAAF: 0x304F, //HIRAGANA LETTER KU + 0xAAB0: 0x3050, //HIRAGANA LETTER GU + 0xAAB1: 0x3051, //HIRAGANA LETTER KE + 0xAAB2: 0x3052, //HIRAGANA LETTER GE + 0xAAB3: 0x3053, //HIRAGANA LETTER KO + 0xAAB4: 0x3054, //HIRAGANA LETTER GO + 0xAAB5: 0x3055, //HIRAGANA LETTER SA + 0xAAB6: 0x3056, //HIRAGANA LETTER ZA + 0xAAB7: 0x3057, //HIRAGANA LETTER SI + 0xAAB8: 0x3058, //HIRAGANA LETTER ZI + 0xAAB9: 0x3059, //HIRAGANA LETTER SU + 0xAABA: 0x305A, //HIRAGANA LETTER ZU + 0xAABB: 0x305B, //HIRAGANA LETTER SE + 0xAABC: 0x305C, //HIRAGANA LETTER ZE + 0xAABD: 0x305D, //HIRAGANA LETTER SO + 0xAABE: 0x305E, //HIRAGANA LETTER ZO + 0xAABF: 0x305F, //HIRAGANA LETTER TA + 0xAAC0: 0x3060, //HIRAGANA LETTER DA + 0xAAC1: 0x3061, //HIRAGANA LETTER TI + 0xAAC2: 0x3062, //HIRAGANA LETTER DI + 0xAAC3: 0x3063, //HIRAGANA LETTER SMALL TU + 0xAAC4: 0x3064, //HIRAGANA LETTER TU + 0xAAC5: 0x3065, //HIRAGANA LETTER DU + 0xAAC6: 0x3066, //HIRAGANA LETTER TE + 0xAAC7: 0x3067, //HIRAGANA LETTER DE + 0xAAC8: 0x3068, //HIRAGANA LETTER TO + 0xAAC9: 0x3069, //HIRAGANA LETTER DO + 0xAACA: 0x306A, //HIRAGANA LETTER NA + 0xAACB: 0x306B, //HIRAGANA LETTER NI + 0xAACC: 0x306C, //HIRAGANA LETTER NU + 0xAACD: 0x306D, //HIRAGANA LETTER NE + 0xAACE: 0x306E, //HIRAGANA LETTER NO + 0xAACF: 0x306F, //HIRAGANA LETTER HA + 0xAAD0: 0x3070, //HIRAGANA LETTER BA + 0xAAD1: 0x3071, //HIRAGANA LETTER PA + 0xAAD2: 0x3072, //HIRAGANA LETTER HI + 0xAAD3: 0x3073, //HIRAGANA LETTER BI + 0xAAD4: 0x3074, //HIRAGANA LETTER PI + 0xAAD5: 0x3075, //HIRAGANA LETTER HU + 0xAAD6: 0x3076, //HIRAGANA LETTER BU + 0xAAD7: 0x3077, //HIRAGANA LETTER PU + 0xAAD8: 0x3078, //HIRAGANA LETTER HE + 0xAAD9: 0x3079, //HIRAGANA LETTER BE + 0xAADA: 0x307A, //HIRAGANA LETTER PE + 0xAADB: 0x307B, //HIRAGANA LETTER HO + 0xAADC: 0x307C, //HIRAGANA LETTER BO + 0xAADD: 0x307D, //HIRAGANA LETTER PO + 0xAADE: 0x307E, //HIRAGANA LETTER MA + 0xAADF: 0x307F, //HIRAGANA LETTER MI + 0xAAE0: 0x3080, //HIRAGANA LETTER MU + 0xAAE1: 0x3081, //HIRAGANA LETTER ME + 0xAAE2: 0x3082, //HIRAGANA LETTER MO + 0xAAE3: 0x3083, //HIRAGANA LETTER SMALL YA + 0xAAE4: 0x3084, //HIRAGANA LETTER YA + 0xAAE5: 0x3085, //HIRAGANA LETTER SMALL YU + 0xAAE6: 0x3086, //HIRAGANA LETTER YU + 0xAAE7: 0x3087, //HIRAGANA LETTER SMALL YO + 0xAAE8: 0x3088, //HIRAGANA LETTER YO + 0xAAE9: 0x3089, //HIRAGANA LETTER RA + 0xAAEA: 0x308A, //HIRAGANA LETTER RI + 0xAAEB: 0x308B, //HIRAGANA LETTER RU + 0xAAEC: 0x308C, //HIRAGANA LETTER RE + 0xAAED: 0x308D, //HIRAGANA LETTER RO + 0xAAEE: 0x308E, //HIRAGANA LETTER SMALL WA + 0xAAEF: 0x308F, //HIRAGANA LETTER WA + 0xAAF0: 0x3090, //HIRAGANA LETTER WI + 0xAAF1: 0x3091, //HIRAGANA LETTER WE + 0xAAF2: 0x3092, //HIRAGANA LETTER WO + 0xAAF3: 0x3093, //HIRAGANA LETTER N + 0xAB41: 0xCC94, //HANGUL SYLLABLE CHIEUCH YAE KHIEUKH + 0xAB42: 0xCC95, //HANGUL SYLLABLE CHIEUCH YAE THIEUTH + 0xAB43: 0xCC96, //HANGUL SYLLABLE CHIEUCH YAE PHIEUPH + 0xAB44: 0xCC97, //HANGUL SYLLABLE CHIEUCH YAE HIEUH + 0xAB45: 0xCC9A, //HANGUL SYLLABLE CHIEUCH EO SSANGKIYEOK + 0xAB46: 0xCC9B, //HANGUL SYLLABLE CHIEUCH EO KIYEOKSIOS + 0xAB47: 0xCC9D, //HANGUL SYLLABLE CHIEUCH EO NIEUNCIEUC + 0xAB48: 0xCC9E, //HANGUL SYLLABLE CHIEUCH EO NIEUNHIEUH + 0xAB49: 0xCC9F, //HANGUL SYLLABLE CHIEUCH EO TIKEUT + 0xAB4A: 0xCCA1, //HANGUL SYLLABLE CHIEUCH EO RIEULKIYEOK + 0xAB4B: 0xCCA2, //HANGUL SYLLABLE CHIEUCH EO RIEULMIEUM + 0xAB4C: 0xCCA3, //HANGUL SYLLABLE CHIEUCH EO RIEULPIEUP + 0xAB4D: 0xCCA4, //HANGUL SYLLABLE CHIEUCH EO RIEULSIOS + 0xAB4E: 0xCCA5, //HANGUL SYLLABLE CHIEUCH EO RIEULTHIEUTH + 0xAB4F: 0xCCA6, //HANGUL SYLLABLE CHIEUCH EO RIEULPHIEUPH + 0xAB50: 0xCCA7, //HANGUL SYLLABLE CHIEUCH EO RIEULHIEUH + 0xAB51: 0xCCAA, //HANGUL SYLLABLE CHIEUCH EO PIEUPSIOS + 0xAB52: 0xCCAE, //HANGUL SYLLABLE CHIEUCH EO CIEUC + 0xAB53: 0xCCAF, //HANGUL SYLLABLE CHIEUCH EO CHIEUCH + 0xAB54: 0xCCB0, //HANGUL SYLLABLE CHIEUCH EO KHIEUKH + 0xAB55: 0xCCB1, //HANGUL SYLLABLE CHIEUCH EO THIEUTH + 0xAB56: 0xCCB2, //HANGUL SYLLABLE CHIEUCH EO PHIEUPH + 0xAB57: 0xCCB3, //HANGUL SYLLABLE CHIEUCH EO HIEUH + 0xAB58: 0xCCB6, //HANGUL SYLLABLE CHIEUCH E SSANGKIYEOK + 0xAB59: 0xCCB7, //HANGUL SYLLABLE CHIEUCH E KIYEOKSIOS + 0xAB5A: 0xCCB9, //HANGUL SYLLABLE CHIEUCH E NIEUNCIEUC + 0xAB61: 0xCCBA, //HANGUL SYLLABLE CHIEUCH E NIEUNHIEUH + 0xAB62: 0xCCBB, //HANGUL SYLLABLE CHIEUCH E TIKEUT + 0xAB63: 0xCCBD, //HANGUL SYLLABLE CHIEUCH E RIEULKIYEOK + 0xAB64: 0xCCBE, //HANGUL SYLLABLE CHIEUCH E RIEULMIEUM + 0xAB65: 0xCCBF, //HANGUL SYLLABLE CHIEUCH E RIEULPIEUP + 0xAB66: 0xCCC0, //HANGUL SYLLABLE CHIEUCH E RIEULSIOS + 0xAB67: 0xCCC1, //HANGUL SYLLABLE CHIEUCH E RIEULTHIEUTH + 0xAB68: 0xCCC2, //HANGUL SYLLABLE CHIEUCH E RIEULPHIEUPH + 0xAB69: 0xCCC3, //HANGUL SYLLABLE CHIEUCH E RIEULHIEUH + 0xAB6A: 0xCCC6, //HANGUL SYLLABLE CHIEUCH E PIEUPSIOS + 0xAB6B: 0xCCC8, //HANGUL SYLLABLE CHIEUCH E SSANGSIOS + 0xAB6C: 0xCCCA, //HANGUL SYLLABLE CHIEUCH E CIEUC + 0xAB6D: 0xCCCB, //HANGUL SYLLABLE CHIEUCH E CHIEUCH + 0xAB6E: 0xCCCC, //HANGUL SYLLABLE CHIEUCH E KHIEUKH + 0xAB6F: 0xCCCD, //HANGUL SYLLABLE CHIEUCH E THIEUTH + 0xAB70: 0xCCCE, //HANGUL SYLLABLE CHIEUCH E PHIEUPH + 0xAB71: 0xCCCF, //HANGUL SYLLABLE CHIEUCH E HIEUH + 0xAB72: 0xCCD1, //HANGUL SYLLABLE CHIEUCH YEO KIYEOK + 0xAB73: 0xCCD2, //HANGUL SYLLABLE CHIEUCH YEO SSANGKIYEOK + 0xAB74: 0xCCD3, //HANGUL SYLLABLE CHIEUCH YEO KIYEOKSIOS + 0xAB75: 0xCCD5, //HANGUL SYLLABLE CHIEUCH YEO NIEUNCIEUC + 0xAB76: 0xCCD6, //HANGUL SYLLABLE CHIEUCH YEO NIEUNHIEUH + 0xAB77: 0xCCD7, //HANGUL SYLLABLE CHIEUCH YEO TIKEUT + 0xAB78: 0xCCD8, //HANGUL SYLLABLE CHIEUCH YEO RIEUL + 0xAB79: 0xCCD9, //HANGUL SYLLABLE CHIEUCH YEO RIEULKIYEOK + 0xAB7A: 0xCCDA, //HANGUL SYLLABLE CHIEUCH YEO RIEULMIEUM + 0xAB81: 0xCCDB, //HANGUL SYLLABLE CHIEUCH YEO RIEULPIEUP + 0xAB82: 0xCCDC, //HANGUL SYLLABLE CHIEUCH YEO RIEULSIOS + 0xAB83: 0xCCDD, //HANGUL SYLLABLE CHIEUCH YEO RIEULTHIEUTH + 0xAB84: 0xCCDE, //HANGUL SYLLABLE CHIEUCH YEO RIEULPHIEUPH + 0xAB85: 0xCCDF, //HANGUL SYLLABLE CHIEUCH YEO RIEULHIEUH + 0xAB86: 0xCCE0, //HANGUL SYLLABLE CHIEUCH YEO MIEUM + 0xAB87: 0xCCE1, //HANGUL SYLLABLE CHIEUCH YEO PIEUP + 0xAB88: 0xCCE2, //HANGUL SYLLABLE CHIEUCH YEO PIEUPSIOS + 0xAB89: 0xCCE3, //HANGUL SYLLABLE CHIEUCH YEO SIOS + 0xAB8A: 0xCCE5, //HANGUL SYLLABLE CHIEUCH YEO IEUNG + 0xAB8B: 0xCCE6, //HANGUL SYLLABLE CHIEUCH YEO CIEUC + 0xAB8C: 0xCCE7, //HANGUL SYLLABLE CHIEUCH YEO CHIEUCH + 0xAB8D: 0xCCE8, //HANGUL SYLLABLE CHIEUCH YEO KHIEUKH + 0xAB8E: 0xCCE9, //HANGUL SYLLABLE CHIEUCH YEO THIEUTH + 0xAB8F: 0xCCEA, //HANGUL SYLLABLE CHIEUCH YEO PHIEUPH + 0xAB90: 0xCCEB, //HANGUL SYLLABLE CHIEUCH YEO HIEUH + 0xAB91: 0xCCED, //HANGUL SYLLABLE CHIEUCH YE KIYEOK + 0xAB92: 0xCCEE, //HANGUL SYLLABLE CHIEUCH YE SSANGKIYEOK + 0xAB93: 0xCCEF, //HANGUL SYLLABLE CHIEUCH YE KIYEOKSIOS + 0xAB94: 0xCCF1, //HANGUL SYLLABLE CHIEUCH YE NIEUNCIEUC + 0xAB95: 0xCCF2, //HANGUL SYLLABLE CHIEUCH YE NIEUNHIEUH + 0xAB96: 0xCCF3, //HANGUL SYLLABLE CHIEUCH YE TIKEUT + 0xAB97: 0xCCF4, //HANGUL SYLLABLE CHIEUCH YE RIEUL + 0xAB98: 0xCCF5, //HANGUL SYLLABLE CHIEUCH YE RIEULKIYEOK + 0xAB99: 0xCCF6, //HANGUL SYLLABLE CHIEUCH YE RIEULMIEUM + 0xAB9A: 0xCCF7, //HANGUL SYLLABLE CHIEUCH YE RIEULPIEUP + 0xAB9B: 0xCCF8, //HANGUL SYLLABLE CHIEUCH YE RIEULSIOS + 0xAB9C: 0xCCF9, //HANGUL SYLLABLE CHIEUCH YE RIEULTHIEUTH + 0xAB9D: 0xCCFA, //HANGUL SYLLABLE CHIEUCH YE RIEULPHIEUPH + 0xAB9E: 0xCCFB, //HANGUL SYLLABLE CHIEUCH YE RIEULHIEUH + 0xAB9F: 0xCCFC, //HANGUL SYLLABLE CHIEUCH YE MIEUM + 0xABA0: 0xCCFD, //HANGUL SYLLABLE CHIEUCH YE PIEUP + 0xABA1: 0x30A1, //KATAKANA LETTER SMALL A + 0xABA2: 0x30A2, //KATAKANA LETTER A + 0xABA3: 0x30A3, //KATAKANA LETTER SMALL I + 0xABA4: 0x30A4, //KATAKANA LETTER I + 0xABA5: 0x30A5, //KATAKANA LETTER SMALL U + 0xABA6: 0x30A6, //KATAKANA LETTER U + 0xABA7: 0x30A7, //KATAKANA LETTER SMALL E + 0xABA8: 0x30A8, //KATAKANA LETTER E + 0xABA9: 0x30A9, //KATAKANA LETTER SMALL O + 0xABAA: 0x30AA, //KATAKANA LETTER O + 0xABAB: 0x30AB, //KATAKANA LETTER KA + 0xABAC: 0x30AC, //KATAKANA LETTER GA + 0xABAD: 0x30AD, //KATAKANA LETTER KI + 0xABAE: 0x30AE, //KATAKANA LETTER GI + 0xABAF: 0x30AF, //KATAKANA LETTER KU + 0xABB0: 0x30B0, //KATAKANA LETTER GU + 0xABB1: 0x30B1, //KATAKANA LETTER KE + 0xABB2: 0x30B2, //KATAKANA LETTER GE + 0xABB3: 0x30B3, //KATAKANA LETTER KO + 0xABB4: 0x30B4, //KATAKANA LETTER GO + 0xABB5: 0x30B5, //KATAKANA LETTER SA + 0xABB6: 0x30B6, //KATAKANA LETTER ZA + 0xABB7: 0x30B7, //KATAKANA LETTER SI + 0xABB8: 0x30B8, //KATAKANA LETTER ZI + 0xABB9: 0x30B9, //KATAKANA LETTER SU + 0xABBA: 0x30BA, //KATAKANA LETTER ZU + 0xABBB: 0x30BB, //KATAKANA LETTER SE + 0xABBC: 0x30BC, //KATAKANA LETTER ZE + 0xABBD: 0x30BD, //KATAKANA LETTER SO + 0xABBE: 0x30BE, //KATAKANA LETTER ZO + 0xABBF: 0x30BF, //KATAKANA LETTER TA + 0xABC0: 0x30C0, //KATAKANA LETTER DA + 0xABC1: 0x30C1, //KATAKANA LETTER TI + 0xABC2: 0x30C2, //KATAKANA LETTER DI + 0xABC3: 0x30C3, //KATAKANA LETTER SMALL TU + 0xABC4: 0x30C4, //KATAKANA LETTER TU + 0xABC5: 0x30C5, //KATAKANA LETTER DU + 0xABC6: 0x30C6, //KATAKANA LETTER TE + 0xABC7: 0x30C7, //KATAKANA LETTER DE + 0xABC8: 0x30C8, //KATAKANA LETTER TO + 0xABC9: 0x30C9, //KATAKANA LETTER DO + 0xABCA: 0x30CA, //KATAKANA LETTER NA + 0xABCB: 0x30CB, //KATAKANA LETTER NI + 0xABCC: 0x30CC, //KATAKANA LETTER NU + 0xABCD: 0x30CD, //KATAKANA LETTER NE + 0xABCE: 0x30CE, //KATAKANA LETTER NO + 0xABCF: 0x30CF, //KATAKANA LETTER HA + 0xABD0: 0x30D0, //KATAKANA LETTER BA + 0xABD1: 0x30D1, //KATAKANA LETTER PA + 0xABD2: 0x30D2, //KATAKANA LETTER HI + 0xABD3: 0x30D3, //KATAKANA LETTER BI + 0xABD4: 0x30D4, //KATAKANA LETTER PI + 0xABD5: 0x30D5, //KATAKANA LETTER HU + 0xABD6: 0x30D6, //KATAKANA LETTER BU + 0xABD7: 0x30D7, //KATAKANA LETTER PU + 0xABD8: 0x30D8, //KATAKANA LETTER HE + 0xABD9: 0x30D9, //KATAKANA LETTER BE + 0xABDA: 0x30DA, //KATAKANA LETTER PE + 0xABDB: 0x30DB, //KATAKANA LETTER HO + 0xABDC: 0x30DC, //KATAKANA LETTER BO + 0xABDD: 0x30DD, //KATAKANA LETTER PO + 0xABDE: 0x30DE, //KATAKANA LETTER MA + 0xABDF: 0x30DF, //KATAKANA LETTER MI + 0xABE0: 0x30E0, //KATAKANA LETTER MU + 0xABE1: 0x30E1, //KATAKANA LETTER ME + 0xABE2: 0x30E2, //KATAKANA LETTER MO + 0xABE3: 0x30E3, //KATAKANA LETTER SMALL YA + 0xABE4: 0x30E4, //KATAKANA LETTER YA + 0xABE5: 0x30E5, //KATAKANA LETTER SMALL YU + 0xABE6: 0x30E6, //KATAKANA LETTER YU + 0xABE7: 0x30E7, //KATAKANA LETTER SMALL YO + 0xABE8: 0x30E8, //KATAKANA LETTER YO + 0xABE9: 0x30E9, //KATAKANA LETTER RA + 0xABEA: 0x30EA, //KATAKANA LETTER RI + 0xABEB: 0x30EB, //KATAKANA LETTER RU + 0xABEC: 0x30EC, //KATAKANA LETTER RE + 0xABED: 0x30ED, //KATAKANA LETTER RO + 0xABEE: 0x30EE, //KATAKANA LETTER SMALL WA + 0xABEF: 0x30EF, //KATAKANA LETTER WA + 0xABF0: 0x30F0, //KATAKANA LETTER WI + 0xABF1: 0x30F1, //KATAKANA LETTER WE + 0xABF2: 0x30F2, //KATAKANA LETTER WO + 0xABF3: 0x30F3, //KATAKANA LETTER N + 0xABF4: 0x30F4, //KATAKANA LETTER VU + 0xABF5: 0x30F5, //KATAKANA LETTER SMALL KA + 0xABF6: 0x30F6, //KATAKANA LETTER SMALL KE + 0xAC41: 0xCCFE, //HANGUL SYLLABLE CHIEUCH YE PIEUPSIOS + 0xAC42: 0xCCFF, //HANGUL SYLLABLE CHIEUCH YE SIOS + 0xAC43: 0xCD00, //HANGUL SYLLABLE CHIEUCH YE SSANGSIOS + 0xAC44: 0xCD02, //HANGUL SYLLABLE CHIEUCH YE CIEUC + 0xAC45: 0xCD03, //HANGUL SYLLABLE CHIEUCH YE CHIEUCH + 0xAC46: 0xCD04, //HANGUL SYLLABLE CHIEUCH YE KHIEUKH + 0xAC47: 0xCD05, //HANGUL SYLLABLE CHIEUCH YE THIEUTH + 0xAC48: 0xCD06, //HANGUL SYLLABLE CHIEUCH YE PHIEUPH + 0xAC49: 0xCD07, //HANGUL SYLLABLE CHIEUCH YE HIEUH + 0xAC4A: 0xCD0A, //HANGUL SYLLABLE CHIEUCH O SSANGKIYEOK + 0xAC4B: 0xCD0B, //HANGUL SYLLABLE CHIEUCH O KIYEOKSIOS + 0xAC4C: 0xCD0D, //HANGUL SYLLABLE CHIEUCH O NIEUNCIEUC + 0xAC4D: 0xCD0E, //HANGUL SYLLABLE CHIEUCH O NIEUNHIEUH + 0xAC4E: 0xCD0F, //HANGUL SYLLABLE CHIEUCH O TIKEUT + 0xAC4F: 0xCD11, //HANGUL SYLLABLE CHIEUCH O RIEULKIYEOK + 0xAC50: 0xCD12, //HANGUL SYLLABLE CHIEUCH O RIEULMIEUM + 0xAC51: 0xCD13, //HANGUL SYLLABLE CHIEUCH O RIEULPIEUP + 0xAC52: 0xCD14, //HANGUL SYLLABLE CHIEUCH O RIEULSIOS + 0xAC53: 0xCD15, //HANGUL SYLLABLE CHIEUCH O RIEULTHIEUTH + 0xAC54: 0xCD16, //HANGUL SYLLABLE CHIEUCH O RIEULPHIEUPH + 0xAC55: 0xCD17, //HANGUL SYLLABLE CHIEUCH O RIEULHIEUH + 0xAC56: 0xCD1A, //HANGUL SYLLABLE CHIEUCH O PIEUPSIOS + 0xAC57: 0xCD1C, //HANGUL SYLLABLE CHIEUCH O SSANGSIOS + 0xAC58: 0xCD1E, //HANGUL SYLLABLE CHIEUCH O CIEUC + 0xAC59: 0xCD1F, //HANGUL SYLLABLE CHIEUCH O CHIEUCH + 0xAC5A: 0xCD20, //HANGUL SYLLABLE CHIEUCH O KHIEUKH + 0xAC61: 0xCD21, //HANGUL SYLLABLE CHIEUCH O THIEUTH + 0xAC62: 0xCD22, //HANGUL SYLLABLE CHIEUCH O PHIEUPH + 0xAC63: 0xCD23, //HANGUL SYLLABLE CHIEUCH O HIEUH + 0xAC64: 0xCD25, //HANGUL SYLLABLE CHIEUCH WA KIYEOK + 0xAC65: 0xCD26, //HANGUL SYLLABLE CHIEUCH WA SSANGKIYEOK + 0xAC66: 0xCD27, //HANGUL SYLLABLE CHIEUCH WA KIYEOKSIOS + 0xAC67: 0xCD29, //HANGUL SYLLABLE CHIEUCH WA NIEUNCIEUC + 0xAC68: 0xCD2A, //HANGUL SYLLABLE CHIEUCH WA NIEUNHIEUH + 0xAC69: 0xCD2B, //HANGUL SYLLABLE CHIEUCH WA TIKEUT + 0xAC6A: 0xCD2D, //HANGUL SYLLABLE CHIEUCH WA RIEULKIYEOK + 0xAC6B: 0xCD2E, //HANGUL SYLLABLE CHIEUCH WA RIEULMIEUM + 0xAC6C: 0xCD2F, //HANGUL SYLLABLE CHIEUCH WA RIEULPIEUP + 0xAC6D: 0xCD30, //HANGUL SYLLABLE CHIEUCH WA RIEULSIOS + 0xAC6E: 0xCD31, //HANGUL SYLLABLE CHIEUCH WA RIEULTHIEUTH + 0xAC6F: 0xCD32, //HANGUL SYLLABLE CHIEUCH WA RIEULPHIEUPH + 0xAC70: 0xCD33, //HANGUL SYLLABLE CHIEUCH WA RIEULHIEUH + 0xAC71: 0xCD34, //HANGUL SYLLABLE CHIEUCH WA MIEUM + 0xAC72: 0xCD35, //HANGUL SYLLABLE CHIEUCH WA PIEUP + 0xAC73: 0xCD36, //HANGUL SYLLABLE CHIEUCH WA PIEUPSIOS + 0xAC74: 0xCD37, //HANGUL SYLLABLE CHIEUCH WA SIOS + 0xAC75: 0xCD38, //HANGUL SYLLABLE CHIEUCH WA SSANGSIOS + 0xAC76: 0xCD3A, //HANGUL SYLLABLE CHIEUCH WA CIEUC + 0xAC77: 0xCD3B, //HANGUL SYLLABLE CHIEUCH WA CHIEUCH + 0xAC78: 0xCD3C, //HANGUL SYLLABLE CHIEUCH WA KHIEUKH + 0xAC79: 0xCD3D, //HANGUL SYLLABLE CHIEUCH WA THIEUTH + 0xAC7A: 0xCD3E, //HANGUL SYLLABLE CHIEUCH WA PHIEUPH + 0xAC81: 0xCD3F, //HANGUL SYLLABLE CHIEUCH WA HIEUH + 0xAC82: 0xCD40, //HANGUL SYLLABLE CHIEUCH WAE + 0xAC83: 0xCD41, //HANGUL SYLLABLE CHIEUCH WAE KIYEOK + 0xAC84: 0xCD42, //HANGUL SYLLABLE CHIEUCH WAE SSANGKIYEOK + 0xAC85: 0xCD43, //HANGUL SYLLABLE CHIEUCH WAE KIYEOKSIOS + 0xAC86: 0xCD44, //HANGUL SYLLABLE CHIEUCH WAE NIEUN + 0xAC87: 0xCD45, //HANGUL SYLLABLE CHIEUCH WAE NIEUNCIEUC + 0xAC88: 0xCD46, //HANGUL SYLLABLE CHIEUCH WAE NIEUNHIEUH + 0xAC89: 0xCD47, //HANGUL SYLLABLE CHIEUCH WAE TIKEUT + 0xAC8A: 0xCD48, //HANGUL SYLLABLE CHIEUCH WAE RIEUL + 0xAC8B: 0xCD49, //HANGUL SYLLABLE CHIEUCH WAE RIEULKIYEOK + 0xAC8C: 0xCD4A, //HANGUL SYLLABLE CHIEUCH WAE RIEULMIEUM + 0xAC8D: 0xCD4B, //HANGUL SYLLABLE CHIEUCH WAE RIEULPIEUP + 0xAC8E: 0xCD4C, //HANGUL SYLLABLE CHIEUCH WAE RIEULSIOS + 0xAC8F: 0xCD4D, //HANGUL SYLLABLE CHIEUCH WAE RIEULTHIEUTH + 0xAC90: 0xCD4E, //HANGUL SYLLABLE CHIEUCH WAE RIEULPHIEUPH + 0xAC91: 0xCD4F, //HANGUL SYLLABLE CHIEUCH WAE RIEULHIEUH + 0xAC92: 0xCD50, //HANGUL SYLLABLE CHIEUCH WAE MIEUM + 0xAC93: 0xCD51, //HANGUL SYLLABLE CHIEUCH WAE PIEUP + 0xAC94: 0xCD52, //HANGUL SYLLABLE CHIEUCH WAE PIEUPSIOS + 0xAC95: 0xCD53, //HANGUL SYLLABLE CHIEUCH WAE SIOS + 0xAC96: 0xCD54, //HANGUL SYLLABLE CHIEUCH WAE SSANGSIOS + 0xAC97: 0xCD55, //HANGUL SYLLABLE CHIEUCH WAE IEUNG + 0xAC98: 0xCD56, //HANGUL SYLLABLE CHIEUCH WAE CIEUC + 0xAC99: 0xCD57, //HANGUL SYLLABLE CHIEUCH WAE CHIEUCH + 0xAC9A: 0xCD58, //HANGUL SYLLABLE CHIEUCH WAE KHIEUKH + 0xAC9B: 0xCD59, //HANGUL SYLLABLE CHIEUCH WAE THIEUTH + 0xAC9C: 0xCD5A, //HANGUL SYLLABLE CHIEUCH WAE PHIEUPH + 0xAC9D: 0xCD5B, //HANGUL SYLLABLE CHIEUCH WAE HIEUH + 0xAC9E: 0xCD5D, //HANGUL SYLLABLE CHIEUCH OE KIYEOK + 0xAC9F: 0xCD5E, //HANGUL SYLLABLE CHIEUCH OE SSANGKIYEOK + 0xACA0: 0xCD5F, //HANGUL SYLLABLE CHIEUCH OE KIYEOKSIOS + 0xACA1: 0x0410, //CYRILLIC CAPITAL LETTER A + 0xACA2: 0x0411, //CYRILLIC CAPITAL LETTER BE + 0xACA3: 0x0412, //CYRILLIC CAPITAL LETTER VE + 0xACA4: 0x0413, //CYRILLIC CAPITAL LETTER GHE + 0xACA5: 0x0414, //CYRILLIC CAPITAL LETTER DE + 0xACA6: 0x0415, //CYRILLIC CAPITAL LETTER IE + 0xACA7: 0x0401, //CYRILLIC CAPITAL LETTER IO + 0xACA8: 0x0416, //CYRILLIC CAPITAL LETTER ZHE + 0xACA9: 0x0417, //CYRILLIC CAPITAL LETTER ZE + 0xACAA: 0x0418, //CYRILLIC CAPITAL LETTER I + 0xACAB: 0x0419, //CYRILLIC CAPITAL LETTER SHORT I + 0xACAC: 0x041A, //CYRILLIC CAPITAL LETTER KA + 0xACAD: 0x041B, //CYRILLIC CAPITAL LETTER EL + 0xACAE: 0x041C, //CYRILLIC CAPITAL LETTER EM + 0xACAF: 0x041D, //CYRILLIC CAPITAL LETTER EN + 0xACB0: 0x041E, //CYRILLIC CAPITAL LETTER O + 0xACB1: 0x041F, //CYRILLIC CAPITAL LETTER PE + 0xACB2: 0x0420, //CYRILLIC CAPITAL LETTER ER + 0xACB3: 0x0421, //CYRILLIC CAPITAL LETTER ES + 0xACB4: 0x0422, //CYRILLIC CAPITAL LETTER TE + 0xACB5: 0x0423, //CYRILLIC CAPITAL LETTER U + 0xACB6: 0x0424, //CYRILLIC CAPITAL LETTER EF + 0xACB7: 0x0425, //CYRILLIC CAPITAL LETTER HA + 0xACB8: 0x0426, //CYRILLIC CAPITAL LETTER TSE + 0xACB9: 0x0427, //CYRILLIC CAPITAL LETTER CHE + 0xACBA: 0x0428, //CYRILLIC CAPITAL LETTER SHA + 0xACBB: 0x0429, //CYRILLIC CAPITAL LETTER SHCHA + 0xACBC: 0x042A, //CYRILLIC CAPITAL LETTER HARD SIGN + 0xACBD: 0x042B, //CYRILLIC CAPITAL LETTER YERU + 0xACBE: 0x042C, //CYRILLIC CAPITAL LETTER SOFT SIGN + 0xACBF: 0x042D, //CYRILLIC CAPITAL LETTER E + 0xACC0: 0x042E, //CYRILLIC CAPITAL LETTER YU + 0xACC1: 0x042F, //CYRILLIC CAPITAL LETTER YA + 0xACD1: 0x0430, //CYRILLIC SMALL LETTER A + 0xACD2: 0x0431, //CYRILLIC SMALL LETTER BE + 0xACD3: 0x0432, //CYRILLIC SMALL LETTER VE + 0xACD4: 0x0433, //CYRILLIC SMALL LETTER GHE + 0xACD5: 0x0434, //CYRILLIC SMALL LETTER DE + 0xACD6: 0x0435, //CYRILLIC SMALL LETTER IE + 0xACD7: 0x0451, //CYRILLIC SMALL LETTER IO + 0xACD8: 0x0436, //CYRILLIC SMALL LETTER ZHE + 0xACD9: 0x0437, //CYRILLIC SMALL LETTER ZE + 0xACDA: 0x0438, //CYRILLIC SMALL LETTER I + 0xACDB: 0x0439, //CYRILLIC SMALL LETTER SHORT I + 0xACDC: 0x043A, //CYRILLIC SMALL LETTER KA + 0xACDD: 0x043B, //CYRILLIC SMALL LETTER EL + 0xACDE: 0x043C, //CYRILLIC SMALL LETTER EM + 0xACDF: 0x043D, //CYRILLIC SMALL LETTER EN + 0xACE0: 0x043E, //CYRILLIC SMALL LETTER O + 0xACE1: 0x043F, //CYRILLIC SMALL LETTER PE + 0xACE2: 0x0440, //CYRILLIC SMALL LETTER ER + 0xACE3: 0x0441, //CYRILLIC SMALL LETTER ES + 0xACE4: 0x0442, //CYRILLIC SMALL LETTER TE + 0xACE5: 0x0443, //CYRILLIC SMALL LETTER U + 0xACE6: 0x0444, //CYRILLIC SMALL LETTER EF + 0xACE7: 0x0445, //CYRILLIC SMALL LETTER HA + 0xACE8: 0x0446, //CYRILLIC SMALL LETTER TSE + 0xACE9: 0x0447, //CYRILLIC SMALL LETTER CHE + 0xACEA: 0x0448, //CYRILLIC SMALL LETTER SHA + 0xACEB: 0x0449, //CYRILLIC SMALL LETTER SHCHA + 0xACEC: 0x044A, //CYRILLIC SMALL LETTER HARD SIGN + 0xACED: 0x044B, //CYRILLIC SMALL LETTER YERU + 0xACEE: 0x044C, //CYRILLIC SMALL LETTER SOFT SIGN + 0xACEF: 0x044D, //CYRILLIC SMALL LETTER E + 0xACF0: 0x044E, //CYRILLIC SMALL LETTER YU + 0xACF1: 0x044F, //CYRILLIC SMALL LETTER YA + 0xAD41: 0xCD61, //HANGUL SYLLABLE CHIEUCH OE NIEUNCIEUC + 0xAD42: 0xCD62, //HANGUL SYLLABLE CHIEUCH OE NIEUNHIEUH + 0xAD43: 0xCD63, //HANGUL SYLLABLE CHIEUCH OE TIKEUT + 0xAD44: 0xCD65, //HANGUL SYLLABLE CHIEUCH OE RIEULKIYEOK + 0xAD45: 0xCD66, //HANGUL SYLLABLE CHIEUCH OE RIEULMIEUM + 0xAD46: 0xCD67, //HANGUL SYLLABLE CHIEUCH OE RIEULPIEUP + 0xAD47: 0xCD68, //HANGUL SYLLABLE CHIEUCH OE RIEULSIOS + 0xAD48: 0xCD69, //HANGUL SYLLABLE CHIEUCH OE RIEULTHIEUTH + 0xAD49: 0xCD6A, //HANGUL SYLLABLE CHIEUCH OE RIEULPHIEUPH + 0xAD4A: 0xCD6B, //HANGUL SYLLABLE CHIEUCH OE RIEULHIEUH + 0xAD4B: 0xCD6E, //HANGUL SYLLABLE CHIEUCH OE PIEUPSIOS + 0xAD4C: 0xCD70, //HANGUL SYLLABLE CHIEUCH OE SSANGSIOS + 0xAD4D: 0xCD72, //HANGUL SYLLABLE CHIEUCH OE CIEUC + 0xAD4E: 0xCD73, //HANGUL SYLLABLE CHIEUCH OE CHIEUCH + 0xAD4F: 0xCD74, //HANGUL SYLLABLE CHIEUCH OE KHIEUKH + 0xAD50: 0xCD75, //HANGUL SYLLABLE CHIEUCH OE THIEUTH + 0xAD51: 0xCD76, //HANGUL SYLLABLE CHIEUCH OE PHIEUPH + 0xAD52: 0xCD77, //HANGUL SYLLABLE CHIEUCH OE HIEUH + 0xAD53: 0xCD79, //HANGUL SYLLABLE CHIEUCH YO KIYEOK + 0xAD54: 0xCD7A, //HANGUL SYLLABLE CHIEUCH YO SSANGKIYEOK + 0xAD55: 0xCD7B, //HANGUL SYLLABLE CHIEUCH YO KIYEOKSIOS + 0xAD56: 0xCD7C, //HANGUL SYLLABLE CHIEUCH YO NIEUN + 0xAD57: 0xCD7D, //HANGUL SYLLABLE CHIEUCH YO NIEUNCIEUC + 0xAD58: 0xCD7E, //HANGUL SYLLABLE CHIEUCH YO NIEUNHIEUH + 0xAD59: 0xCD7F, //HANGUL SYLLABLE CHIEUCH YO TIKEUT + 0xAD5A: 0xCD80, //HANGUL SYLLABLE CHIEUCH YO RIEUL + 0xAD61: 0xCD81, //HANGUL SYLLABLE CHIEUCH YO RIEULKIYEOK + 0xAD62: 0xCD82, //HANGUL SYLLABLE CHIEUCH YO RIEULMIEUM + 0xAD63: 0xCD83, //HANGUL SYLLABLE CHIEUCH YO RIEULPIEUP + 0xAD64: 0xCD84, //HANGUL SYLLABLE CHIEUCH YO RIEULSIOS + 0xAD65: 0xCD85, //HANGUL SYLLABLE CHIEUCH YO RIEULTHIEUTH + 0xAD66: 0xCD86, //HANGUL SYLLABLE CHIEUCH YO RIEULPHIEUPH + 0xAD67: 0xCD87, //HANGUL SYLLABLE CHIEUCH YO RIEULHIEUH + 0xAD68: 0xCD89, //HANGUL SYLLABLE CHIEUCH YO PIEUP + 0xAD69: 0xCD8A, //HANGUL SYLLABLE CHIEUCH YO PIEUPSIOS + 0xAD6A: 0xCD8B, //HANGUL SYLLABLE CHIEUCH YO SIOS + 0xAD6B: 0xCD8C, //HANGUL SYLLABLE CHIEUCH YO SSANGSIOS + 0xAD6C: 0xCD8D, //HANGUL SYLLABLE CHIEUCH YO IEUNG + 0xAD6D: 0xCD8E, //HANGUL SYLLABLE CHIEUCH YO CIEUC + 0xAD6E: 0xCD8F, //HANGUL SYLLABLE CHIEUCH YO CHIEUCH + 0xAD6F: 0xCD90, //HANGUL SYLLABLE CHIEUCH YO KHIEUKH + 0xAD70: 0xCD91, //HANGUL SYLLABLE CHIEUCH YO THIEUTH + 0xAD71: 0xCD92, //HANGUL SYLLABLE CHIEUCH YO PHIEUPH + 0xAD72: 0xCD93, //HANGUL SYLLABLE CHIEUCH YO HIEUH + 0xAD73: 0xCD96, //HANGUL SYLLABLE CHIEUCH U SSANGKIYEOK + 0xAD74: 0xCD97, //HANGUL SYLLABLE CHIEUCH U KIYEOKSIOS + 0xAD75: 0xCD99, //HANGUL SYLLABLE CHIEUCH U NIEUNCIEUC + 0xAD76: 0xCD9A, //HANGUL SYLLABLE CHIEUCH U NIEUNHIEUH + 0xAD77: 0xCD9B, //HANGUL SYLLABLE CHIEUCH U TIKEUT + 0xAD78: 0xCD9D, //HANGUL SYLLABLE CHIEUCH U RIEULKIYEOK + 0xAD79: 0xCD9E, //HANGUL SYLLABLE CHIEUCH U RIEULMIEUM + 0xAD7A: 0xCD9F, //HANGUL SYLLABLE CHIEUCH U RIEULPIEUP + 0xAD81: 0xCDA0, //HANGUL SYLLABLE CHIEUCH U RIEULSIOS + 0xAD82: 0xCDA1, //HANGUL SYLLABLE CHIEUCH U RIEULTHIEUTH + 0xAD83: 0xCDA2, //HANGUL SYLLABLE CHIEUCH U RIEULPHIEUPH + 0xAD84: 0xCDA3, //HANGUL SYLLABLE CHIEUCH U RIEULHIEUH + 0xAD85: 0xCDA6, //HANGUL SYLLABLE CHIEUCH U PIEUPSIOS + 0xAD86: 0xCDA8, //HANGUL SYLLABLE CHIEUCH U SSANGSIOS + 0xAD87: 0xCDAA, //HANGUL SYLLABLE CHIEUCH U CIEUC + 0xAD88: 0xCDAB, //HANGUL SYLLABLE CHIEUCH U CHIEUCH + 0xAD89: 0xCDAC, //HANGUL SYLLABLE CHIEUCH U KHIEUKH + 0xAD8A: 0xCDAD, //HANGUL SYLLABLE CHIEUCH U THIEUTH + 0xAD8B: 0xCDAE, //HANGUL SYLLABLE CHIEUCH U PHIEUPH + 0xAD8C: 0xCDAF, //HANGUL SYLLABLE CHIEUCH U HIEUH + 0xAD8D: 0xCDB1, //HANGUL SYLLABLE CHIEUCH WEO KIYEOK + 0xAD8E: 0xCDB2, //HANGUL SYLLABLE CHIEUCH WEO SSANGKIYEOK + 0xAD8F: 0xCDB3, //HANGUL SYLLABLE CHIEUCH WEO KIYEOKSIOS + 0xAD90: 0xCDB4, //HANGUL SYLLABLE CHIEUCH WEO NIEUN + 0xAD91: 0xCDB5, //HANGUL SYLLABLE CHIEUCH WEO NIEUNCIEUC + 0xAD92: 0xCDB6, //HANGUL SYLLABLE CHIEUCH WEO NIEUNHIEUH + 0xAD93: 0xCDB7, //HANGUL SYLLABLE CHIEUCH WEO TIKEUT + 0xAD94: 0xCDB8, //HANGUL SYLLABLE CHIEUCH WEO RIEUL + 0xAD95: 0xCDB9, //HANGUL SYLLABLE CHIEUCH WEO RIEULKIYEOK + 0xAD96: 0xCDBA, //HANGUL SYLLABLE CHIEUCH WEO RIEULMIEUM + 0xAD97: 0xCDBB, //HANGUL SYLLABLE CHIEUCH WEO RIEULPIEUP + 0xAD98: 0xCDBC, //HANGUL SYLLABLE CHIEUCH WEO RIEULSIOS + 0xAD99: 0xCDBD, //HANGUL SYLLABLE CHIEUCH WEO RIEULTHIEUTH + 0xAD9A: 0xCDBE, //HANGUL SYLLABLE CHIEUCH WEO RIEULPHIEUPH + 0xAD9B: 0xCDBF, //HANGUL SYLLABLE CHIEUCH WEO RIEULHIEUH + 0xAD9C: 0xCDC0, //HANGUL SYLLABLE CHIEUCH WEO MIEUM + 0xAD9D: 0xCDC1, //HANGUL SYLLABLE CHIEUCH WEO PIEUP + 0xAD9E: 0xCDC2, //HANGUL SYLLABLE CHIEUCH WEO PIEUPSIOS + 0xAD9F: 0xCDC3, //HANGUL SYLLABLE CHIEUCH WEO SIOS + 0xADA0: 0xCDC5, //HANGUL SYLLABLE CHIEUCH WEO IEUNG + 0xAE41: 0xCDC6, //HANGUL SYLLABLE CHIEUCH WEO CIEUC + 0xAE42: 0xCDC7, //HANGUL SYLLABLE CHIEUCH WEO CHIEUCH + 0xAE43: 0xCDC8, //HANGUL SYLLABLE CHIEUCH WEO KHIEUKH + 0xAE44: 0xCDC9, //HANGUL SYLLABLE CHIEUCH WEO THIEUTH + 0xAE45: 0xCDCA, //HANGUL SYLLABLE CHIEUCH WEO PHIEUPH + 0xAE46: 0xCDCB, //HANGUL SYLLABLE CHIEUCH WEO HIEUH + 0xAE47: 0xCDCD, //HANGUL SYLLABLE CHIEUCH WE KIYEOK + 0xAE48: 0xCDCE, //HANGUL SYLLABLE CHIEUCH WE SSANGKIYEOK + 0xAE49: 0xCDCF, //HANGUL SYLLABLE CHIEUCH WE KIYEOKSIOS + 0xAE4A: 0xCDD1, //HANGUL SYLLABLE CHIEUCH WE NIEUNCIEUC + 0xAE4B: 0xCDD2, //HANGUL SYLLABLE CHIEUCH WE NIEUNHIEUH + 0xAE4C: 0xCDD3, //HANGUL SYLLABLE CHIEUCH WE TIKEUT + 0xAE4D: 0xCDD4, //HANGUL SYLLABLE CHIEUCH WE RIEUL + 0xAE4E: 0xCDD5, //HANGUL SYLLABLE CHIEUCH WE RIEULKIYEOK + 0xAE4F: 0xCDD6, //HANGUL SYLLABLE CHIEUCH WE RIEULMIEUM + 0xAE50: 0xCDD7, //HANGUL SYLLABLE CHIEUCH WE RIEULPIEUP + 0xAE51: 0xCDD8, //HANGUL SYLLABLE CHIEUCH WE RIEULSIOS + 0xAE52: 0xCDD9, //HANGUL SYLLABLE CHIEUCH WE RIEULTHIEUTH + 0xAE53: 0xCDDA, //HANGUL SYLLABLE CHIEUCH WE RIEULPHIEUPH + 0xAE54: 0xCDDB, //HANGUL SYLLABLE CHIEUCH WE RIEULHIEUH + 0xAE55: 0xCDDC, //HANGUL SYLLABLE CHIEUCH WE MIEUM + 0xAE56: 0xCDDD, //HANGUL SYLLABLE CHIEUCH WE PIEUP + 0xAE57: 0xCDDE, //HANGUL SYLLABLE CHIEUCH WE PIEUPSIOS + 0xAE58: 0xCDDF, //HANGUL SYLLABLE CHIEUCH WE SIOS + 0xAE59: 0xCDE0, //HANGUL SYLLABLE CHIEUCH WE SSANGSIOS + 0xAE5A: 0xCDE1, //HANGUL SYLLABLE CHIEUCH WE IEUNG + 0xAE61: 0xCDE2, //HANGUL SYLLABLE CHIEUCH WE CIEUC + 0xAE62: 0xCDE3, //HANGUL SYLLABLE CHIEUCH WE CHIEUCH + 0xAE63: 0xCDE4, //HANGUL SYLLABLE CHIEUCH WE KHIEUKH + 0xAE64: 0xCDE5, //HANGUL SYLLABLE CHIEUCH WE THIEUTH + 0xAE65: 0xCDE6, //HANGUL SYLLABLE CHIEUCH WE PHIEUPH + 0xAE66: 0xCDE7, //HANGUL SYLLABLE CHIEUCH WE HIEUH + 0xAE67: 0xCDE9, //HANGUL SYLLABLE CHIEUCH WI KIYEOK + 0xAE68: 0xCDEA, //HANGUL SYLLABLE CHIEUCH WI SSANGKIYEOK + 0xAE69: 0xCDEB, //HANGUL SYLLABLE CHIEUCH WI KIYEOKSIOS + 0xAE6A: 0xCDED, //HANGUL SYLLABLE CHIEUCH WI NIEUNCIEUC + 0xAE6B: 0xCDEE, //HANGUL SYLLABLE CHIEUCH WI NIEUNHIEUH + 0xAE6C: 0xCDEF, //HANGUL SYLLABLE CHIEUCH WI TIKEUT + 0xAE6D: 0xCDF1, //HANGUL SYLLABLE CHIEUCH WI RIEULKIYEOK + 0xAE6E: 0xCDF2, //HANGUL SYLLABLE CHIEUCH WI RIEULMIEUM + 0xAE6F: 0xCDF3, //HANGUL SYLLABLE CHIEUCH WI RIEULPIEUP + 0xAE70: 0xCDF4, //HANGUL SYLLABLE CHIEUCH WI RIEULSIOS + 0xAE71: 0xCDF5, //HANGUL SYLLABLE CHIEUCH WI RIEULTHIEUTH + 0xAE72: 0xCDF6, //HANGUL SYLLABLE CHIEUCH WI RIEULPHIEUPH + 0xAE73: 0xCDF7, //HANGUL SYLLABLE CHIEUCH WI RIEULHIEUH + 0xAE74: 0xCDFA, //HANGUL SYLLABLE CHIEUCH WI PIEUPSIOS + 0xAE75: 0xCDFC, //HANGUL SYLLABLE CHIEUCH WI SSANGSIOS + 0xAE76: 0xCDFE, //HANGUL SYLLABLE CHIEUCH WI CIEUC + 0xAE77: 0xCDFF, //HANGUL SYLLABLE CHIEUCH WI CHIEUCH + 0xAE78: 0xCE00, //HANGUL SYLLABLE CHIEUCH WI KHIEUKH + 0xAE79: 0xCE01, //HANGUL SYLLABLE CHIEUCH WI THIEUTH + 0xAE7A: 0xCE02, //HANGUL SYLLABLE CHIEUCH WI PHIEUPH + 0xAE81: 0xCE03, //HANGUL SYLLABLE CHIEUCH WI HIEUH + 0xAE82: 0xCE05, //HANGUL SYLLABLE CHIEUCH YU KIYEOK + 0xAE83: 0xCE06, //HANGUL SYLLABLE CHIEUCH YU SSANGKIYEOK + 0xAE84: 0xCE07, //HANGUL SYLLABLE CHIEUCH YU KIYEOKSIOS + 0xAE85: 0xCE09, //HANGUL SYLLABLE CHIEUCH YU NIEUNCIEUC + 0xAE86: 0xCE0A, //HANGUL SYLLABLE CHIEUCH YU NIEUNHIEUH + 0xAE87: 0xCE0B, //HANGUL SYLLABLE CHIEUCH YU TIKEUT + 0xAE88: 0xCE0D, //HANGUL SYLLABLE CHIEUCH YU RIEULKIYEOK + 0xAE89: 0xCE0E, //HANGUL SYLLABLE CHIEUCH YU RIEULMIEUM + 0xAE8A: 0xCE0F, //HANGUL SYLLABLE CHIEUCH YU RIEULPIEUP + 0xAE8B: 0xCE10, //HANGUL SYLLABLE CHIEUCH YU RIEULSIOS + 0xAE8C: 0xCE11, //HANGUL SYLLABLE CHIEUCH YU RIEULTHIEUTH + 0xAE8D: 0xCE12, //HANGUL SYLLABLE CHIEUCH YU RIEULPHIEUPH + 0xAE8E: 0xCE13, //HANGUL SYLLABLE CHIEUCH YU RIEULHIEUH + 0xAE8F: 0xCE15, //HANGUL SYLLABLE CHIEUCH YU PIEUP + 0xAE90: 0xCE16, //HANGUL SYLLABLE CHIEUCH YU PIEUPSIOS + 0xAE91: 0xCE17, //HANGUL SYLLABLE CHIEUCH YU SIOS + 0xAE92: 0xCE18, //HANGUL SYLLABLE CHIEUCH YU SSANGSIOS + 0xAE93: 0xCE1A, //HANGUL SYLLABLE CHIEUCH YU CIEUC + 0xAE94: 0xCE1B, //HANGUL SYLLABLE CHIEUCH YU CHIEUCH + 0xAE95: 0xCE1C, //HANGUL SYLLABLE CHIEUCH YU KHIEUKH + 0xAE96: 0xCE1D, //HANGUL SYLLABLE CHIEUCH YU THIEUTH + 0xAE97: 0xCE1E, //HANGUL SYLLABLE CHIEUCH YU PHIEUPH + 0xAE98: 0xCE1F, //HANGUL SYLLABLE CHIEUCH YU HIEUH + 0xAE99: 0xCE22, //HANGUL SYLLABLE CHIEUCH EU SSANGKIYEOK + 0xAE9A: 0xCE23, //HANGUL SYLLABLE CHIEUCH EU KIYEOKSIOS + 0xAE9B: 0xCE25, //HANGUL SYLLABLE CHIEUCH EU NIEUNCIEUC + 0xAE9C: 0xCE26, //HANGUL SYLLABLE CHIEUCH EU NIEUNHIEUH + 0xAE9D: 0xCE27, //HANGUL SYLLABLE CHIEUCH EU TIKEUT + 0xAE9E: 0xCE29, //HANGUL SYLLABLE CHIEUCH EU RIEULKIYEOK + 0xAE9F: 0xCE2A, //HANGUL SYLLABLE CHIEUCH EU RIEULMIEUM + 0xAEA0: 0xCE2B, //HANGUL SYLLABLE CHIEUCH EU RIEULPIEUP + 0xAF41: 0xCE2C, //HANGUL SYLLABLE CHIEUCH EU RIEULSIOS + 0xAF42: 0xCE2D, //HANGUL SYLLABLE CHIEUCH EU RIEULTHIEUTH + 0xAF43: 0xCE2E, //HANGUL SYLLABLE CHIEUCH EU RIEULPHIEUPH + 0xAF44: 0xCE2F, //HANGUL SYLLABLE CHIEUCH EU RIEULHIEUH + 0xAF45: 0xCE32, //HANGUL SYLLABLE CHIEUCH EU PIEUPSIOS + 0xAF46: 0xCE34, //HANGUL SYLLABLE CHIEUCH EU SSANGSIOS + 0xAF47: 0xCE36, //HANGUL SYLLABLE CHIEUCH EU CIEUC + 0xAF48: 0xCE37, //HANGUL SYLLABLE CHIEUCH EU CHIEUCH + 0xAF49: 0xCE38, //HANGUL SYLLABLE CHIEUCH EU KHIEUKH + 0xAF4A: 0xCE39, //HANGUL SYLLABLE CHIEUCH EU THIEUTH + 0xAF4B: 0xCE3A, //HANGUL SYLLABLE CHIEUCH EU PHIEUPH + 0xAF4C: 0xCE3B, //HANGUL SYLLABLE CHIEUCH EU HIEUH + 0xAF4D: 0xCE3C, //HANGUL SYLLABLE CHIEUCH YI + 0xAF4E: 0xCE3D, //HANGUL SYLLABLE CHIEUCH YI KIYEOK + 0xAF4F: 0xCE3E, //HANGUL SYLLABLE CHIEUCH YI SSANGKIYEOK + 0xAF50: 0xCE3F, //HANGUL SYLLABLE CHIEUCH YI KIYEOKSIOS + 0xAF51: 0xCE40, //HANGUL SYLLABLE CHIEUCH YI NIEUN + 0xAF52: 0xCE41, //HANGUL SYLLABLE CHIEUCH YI NIEUNCIEUC + 0xAF53: 0xCE42, //HANGUL SYLLABLE CHIEUCH YI NIEUNHIEUH + 0xAF54: 0xCE43, //HANGUL SYLLABLE CHIEUCH YI TIKEUT + 0xAF55: 0xCE44, //HANGUL SYLLABLE CHIEUCH YI RIEUL + 0xAF56: 0xCE45, //HANGUL SYLLABLE CHIEUCH YI RIEULKIYEOK + 0xAF57: 0xCE46, //HANGUL SYLLABLE CHIEUCH YI RIEULMIEUM + 0xAF58: 0xCE47, //HANGUL SYLLABLE CHIEUCH YI RIEULPIEUP + 0xAF59: 0xCE48, //HANGUL SYLLABLE CHIEUCH YI RIEULSIOS + 0xAF5A: 0xCE49, //HANGUL SYLLABLE CHIEUCH YI RIEULTHIEUTH + 0xAF61: 0xCE4A, //HANGUL SYLLABLE CHIEUCH YI RIEULPHIEUPH + 0xAF62: 0xCE4B, //HANGUL SYLLABLE CHIEUCH YI RIEULHIEUH + 0xAF63: 0xCE4C, //HANGUL SYLLABLE CHIEUCH YI MIEUM + 0xAF64: 0xCE4D, //HANGUL SYLLABLE CHIEUCH YI PIEUP + 0xAF65: 0xCE4E, //HANGUL SYLLABLE CHIEUCH YI PIEUPSIOS + 0xAF66: 0xCE4F, //HANGUL SYLLABLE CHIEUCH YI SIOS + 0xAF67: 0xCE50, //HANGUL SYLLABLE CHIEUCH YI SSANGSIOS + 0xAF68: 0xCE51, //HANGUL SYLLABLE CHIEUCH YI IEUNG + 0xAF69: 0xCE52, //HANGUL SYLLABLE CHIEUCH YI CIEUC + 0xAF6A: 0xCE53, //HANGUL SYLLABLE CHIEUCH YI CHIEUCH + 0xAF6B: 0xCE54, //HANGUL SYLLABLE CHIEUCH YI KHIEUKH + 0xAF6C: 0xCE55, //HANGUL SYLLABLE CHIEUCH YI THIEUTH + 0xAF6D: 0xCE56, //HANGUL SYLLABLE CHIEUCH YI PHIEUPH + 0xAF6E: 0xCE57, //HANGUL SYLLABLE CHIEUCH YI HIEUH + 0xAF6F: 0xCE5A, //HANGUL SYLLABLE CHIEUCH I SSANGKIYEOK + 0xAF70: 0xCE5B, //HANGUL SYLLABLE CHIEUCH I KIYEOKSIOS + 0xAF71: 0xCE5D, //HANGUL SYLLABLE CHIEUCH I NIEUNCIEUC + 0xAF72: 0xCE5E, //HANGUL SYLLABLE CHIEUCH I NIEUNHIEUH + 0xAF73: 0xCE62, //HANGUL SYLLABLE CHIEUCH I RIEULMIEUM + 0xAF74: 0xCE63, //HANGUL SYLLABLE CHIEUCH I RIEULPIEUP + 0xAF75: 0xCE64, //HANGUL SYLLABLE CHIEUCH I RIEULSIOS + 0xAF76: 0xCE65, //HANGUL SYLLABLE CHIEUCH I RIEULTHIEUTH + 0xAF77: 0xCE66, //HANGUL SYLLABLE CHIEUCH I RIEULPHIEUPH + 0xAF78: 0xCE67, //HANGUL SYLLABLE CHIEUCH I RIEULHIEUH + 0xAF79: 0xCE6A, //HANGUL SYLLABLE CHIEUCH I PIEUPSIOS + 0xAF7A: 0xCE6C, //HANGUL SYLLABLE CHIEUCH I SSANGSIOS + 0xAF81: 0xCE6E, //HANGUL SYLLABLE CHIEUCH I CIEUC + 0xAF82: 0xCE6F, //HANGUL SYLLABLE CHIEUCH I CHIEUCH + 0xAF83: 0xCE70, //HANGUL SYLLABLE CHIEUCH I KHIEUKH + 0xAF84: 0xCE71, //HANGUL SYLLABLE CHIEUCH I THIEUTH + 0xAF85: 0xCE72, //HANGUL SYLLABLE CHIEUCH I PHIEUPH + 0xAF86: 0xCE73, //HANGUL SYLLABLE CHIEUCH I HIEUH + 0xAF87: 0xCE76, //HANGUL SYLLABLE KHIEUKH A SSANGKIYEOK + 0xAF88: 0xCE77, //HANGUL SYLLABLE KHIEUKH A KIYEOKSIOS + 0xAF89: 0xCE79, //HANGUL SYLLABLE KHIEUKH A NIEUNCIEUC + 0xAF8A: 0xCE7A, //HANGUL SYLLABLE KHIEUKH A NIEUNHIEUH + 0xAF8B: 0xCE7B, //HANGUL SYLLABLE KHIEUKH A TIKEUT + 0xAF8C: 0xCE7D, //HANGUL SYLLABLE KHIEUKH A RIEULKIYEOK + 0xAF8D: 0xCE7E, //HANGUL SYLLABLE KHIEUKH A RIEULMIEUM + 0xAF8E: 0xCE7F, //HANGUL SYLLABLE KHIEUKH A RIEULPIEUP + 0xAF8F: 0xCE80, //HANGUL SYLLABLE KHIEUKH A RIEULSIOS + 0xAF90: 0xCE81, //HANGUL SYLLABLE KHIEUKH A RIEULTHIEUTH + 0xAF91: 0xCE82, //HANGUL SYLLABLE KHIEUKH A RIEULPHIEUPH + 0xAF92: 0xCE83, //HANGUL SYLLABLE KHIEUKH A RIEULHIEUH + 0xAF93: 0xCE86, //HANGUL SYLLABLE KHIEUKH A PIEUPSIOS + 0xAF94: 0xCE88, //HANGUL SYLLABLE KHIEUKH A SSANGSIOS + 0xAF95: 0xCE8A, //HANGUL SYLLABLE KHIEUKH A CIEUC + 0xAF96: 0xCE8B, //HANGUL SYLLABLE KHIEUKH A CHIEUCH + 0xAF97: 0xCE8C, //HANGUL SYLLABLE KHIEUKH A KHIEUKH + 0xAF98: 0xCE8D, //HANGUL SYLLABLE KHIEUKH A THIEUTH + 0xAF99: 0xCE8E, //HANGUL SYLLABLE KHIEUKH A PHIEUPH + 0xAF9A: 0xCE8F, //HANGUL SYLLABLE KHIEUKH A HIEUH + 0xAF9B: 0xCE92, //HANGUL SYLLABLE KHIEUKH AE SSANGKIYEOK + 0xAF9C: 0xCE93, //HANGUL SYLLABLE KHIEUKH AE KIYEOKSIOS + 0xAF9D: 0xCE95, //HANGUL SYLLABLE KHIEUKH AE NIEUNCIEUC + 0xAF9E: 0xCE96, //HANGUL SYLLABLE KHIEUKH AE NIEUNHIEUH + 0xAF9F: 0xCE97, //HANGUL SYLLABLE KHIEUKH AE TIKEUT + 0xAFA0: 0xCE99, //HANGUL SYLLABLE KHIEUKH AE RIEULKIYEOK + 0xB041: 0xCE9A, //HANGUL SYLLABLE KHIEUKH AE RIEULMIEUM + 0xB042: 0xCE9B, //HANGUL SYLLABLE KHIEUKH AE RIEULPIEUP + 0xB043: 0xCE9C, //HANGUL SYLLABLE KHIEUKH AE RIEULSIOS + 0xB044: 0xCE9D, //HANGUL SYLLABLE KHIEUKH AE RIEULTHIEUTH + 0xB045: 0xCE9E, //HANGUL SYLLABLE KHIEUKH AE RIEULPHIEUPH + 0xB046: 0xCE9F, //HANGUL SYLLABLE KHIEUKH AE RIEULHIEUH + 0xB047: 0xCEA2, //HANGUL SYLLABLE KHIEUKH AE PIEUPSIOS + 0xB048: 0xCEA6, //HANGUL SYLLABLE KHIEUKH AE CIEUC + 0xB049: 0xCEA7, //HANGUL SYLLABLE KHIEUKH AE CHIEUCH + 0xB04A: 0xCEA8, //HANGUL SYLLABLE KHIEUKH AE KHIEUKH + 0xB04B: 0xCEA9, //HANGUL SYLLABLE KHIEUKH AE THIEUTH + 0xB04C: 0xCEAA, //HANGUL SYLLABLE KHIEUKH AE PHIEUPH + 0xB04D: 0xCEAB, //HANGUL SYLLABLE KHIEUKH AE HIEUH + 0xB04E: 0xCEAE, //HANGUL SYLLABLE KHIEUKH YA SSANGKIYEOK + 0xB04F: 0xCEAF, //HANGUL SYLLABLE KHIEUKH YA KIYEOKSIOS + 0xB050: 0xCEB0, //HANGUL SYLLABLE KHIEUKH YA NIEUN + 0xB051: 0xCEB1, //HANGUL SYLLABLE KHIEUKH YA NIEUNCIEUC + 0xB052: 0xCEB2, //HANGUL SYLLABLE KHIEUKH YA NIEUNHIEUH + 0xB053: 0xCEB3, //HANGUL SYLLABLE KHIEUKH YA TIKEUT + 0xB054: 0xCEB4, //HANGUL SYLLABLE KHIEUKH YA RIEUL + 0xB055: 0xCEB5, //HANGUL SYLLABLE KHIEUKH YA RIEULKIYEOK + 0xB056: 0xCEB6, //HANGUL SYLLABLE KHIEUKH YA RIEULMIEUM + 0xB057: 0xCEB7, //HANGUL SYLLABLE KHIEUKH YA RIEULPIEUP + 0xB058: 0xCEB8, //HANGUL SYLLABLE KHIEUKH YA RIEULSIOS + 0xB059: 0xCEB9, //HANGUL SYLLABLE KHIEUKH YA RIEULTHIEUTH + 0xB05A: 0xCEBA, //HANGUL SYLLABLE KHIEUKH YA RIEULPHIEUPH + 0xB061: 0xCEBB, //HANGUL SYLLABLE KHIEUKH YA RIEULHIEUH + 0xB062: 0xCEBC, //HANGUL SYLLABLE KHIEUKH YA MIEUM + 0xB063: 0xCEBD, //HANGUL SYLLABLE KHIEUKH YA PIEUP + 0xB064: 0xCEBE, //HANGUL SYLLABLE KHIEUKH YA PIEUPSIOS + 0xB065: 0xCEBF, //HANGUL SYLLABLE KHIEUKH YA SIOS + 0xB066: 0xCEC0, //HANGUL SYLLABLE KHIEUKH YA SSANGSIOS + 0xB067: 0xCEC2, //HANGUL SYLLABLE KHIEUKH YA CIEUC + 0xB068: 0xCEC3, //HANGUL SYLLABLE KHIEUKH YA CHIEUCH + 0xB069: 0xCEC4, //HANGUL SYLLABLE KHIEUKH YA KHIEUKH + 0xB06A: 0xCEC5, //HANGUL SYLLABLE KHIEUKH YA THIEUTH + 0xB06B: 0xCEC6, //HANGUL SYLLABLE KHIEUKH YA PHIEUPH + 0xB06C: 0xCEC7, //HANGUL SYLLABLE KHIEUKH YA HIEUH + 0xB06D: 0xCEC8, //HANGUL SYLLABLE KHIEUKH YAE + 0xB06E: 0xCEC9, //HANGUL SYLLABLE KHIEUKH YAE KIYEOK + 0xB06F: 0xCECA, //HANGUL SYLLABLE KHIEUKH YAE SSANGKIYEOK + 0xB070: 0xCECB, //HANGUL SYLLABLE KHIEUKH YAE KIYEOKSIOS + 0xB071: 0xCECC, //HANGUL SYLLABLE KHIEUKH YAE NIEUN + 0xB072: 0xCECD, //HANGUL SYLLABLE KHIEUKH YAE NIEUNCIEUC + 0xB073: 0xCECE, //HANGUL SYLLABLE KHIEUKH YAE NIEUNHIEUH + 0xB074: 0xCECF, //HANGUL SYLLABLE KHIEUKH YAE TIKEUT + 0xB075: 0xCED0, //HANGUL SYLLABLE KHIEUKH YAE RIEUL + 0xB076: 0xCED1, //HANGUL SYLLABLE KHIEUKH YAE RIEULKIYEOK + 0xB077: 0xCED2, //HANGUL SYLLABLE KHIEUKH YAE RIEULMIEUM + 0xB078: 0xCED3, //HANGUL SYLLABLE KHIEUKH YAE RIEULPIEUP + 0xB079: 0xCED4, //HANGUL SYLLABLE KHIEUKH YAE RIEULSIOS + 0xB07A: 0xCED5, //HANGUL SYLLABLE KHIEUKH YAE RIEULTHIEUTH + 0xB081: 0xCED6, //HANGUL SYLLABLE KHIEUKH YAE RIEULPHIEUPH + 0xB082: 0xCED7, //HANGUL SYLLABLE KHIEUKH YAE RIEULHIEUH + 0xB083: 0xCED8, //HANGUL SYLLABLE KHIEUKH YAE MIEUM + 0xB084: 0xCED9, //HANGUL SYLLABLE KHIEUKH YAE PIEUP + 0xB085: 0xCEDA, //HANGUL SYLLABLE KHIEUKH YAE PIEUPSIOS + 0xB086: 0xCEDB, //HANGUL SYLLABLE KHIEUKH YAE SIOS + 0xB087: 0xCEDC, //HANGUL SYLLABLE KHIEUKH YAE SSANGSIOS + 0xB088: 0xCEDD, //HANGUL SYLLABLE KHIEUKH YAE IEUNG + 0xB089: 0xCEDE, //HANGUL SYLLABLE KHIEUKH YAE CIEUC + 0xB08A: 0xCEDF, //HANGUL SYLLABLE KHIEUKH YAE CHIEUCH + 0xB08B: 0xCEE0, //HANGUL SYLLABLE KHIEUKH YAE KHIEUKH + 0xB08C: 0xCEE1, //HANGUL SYLLABLE KHIEUKH YAE THIEUTH + 0xB08D: 0xCEE2, //HANGUL SYLLABLE KHIEUKH YAE PHIEUPH + 0xB08E: 0xCEE3, //HANGUL SYLLABLE KHIEUKH YAE HIEUH + 0xB08F: 0xCEE6, //HANGUL SYLLABLE KHIEUKH EO SSANGKIYEOK + 0xB090: 0xCEE7, //HANGUL SYLLABLE KHIEUKH EO KIYEOKSIOS + 0xB091: 0xCEE9, //HANGUL SYLLABLE KHIEUKH EO NIEUNCIEUC + 0xB092: 0xCEEA, //HANGUL SYLLABLE KHIEUKH EO NIEUNHIEUH + 0xB093: 0xCEED, //HANGUL SYLLABLE KHIEUKH EO RIEULKIYEOK + 0xB094: 0xCEEE, //HANGUL SYLLABLE KHIEUKH EO RIEULMIEUM + 0xB095: 0xCEEF, //HANGUL SYLLABLE KHIEUKH EO RIEULPIEUP + 0xB096: 0xCEF0, //HANGUL SYLLABLE KHIEUKH EO RIEULSIOS + 0xB097: 0xCEF1, //HANGUL SYLLABLE KHIEUKH EO RIEULTHIEUTH + 0xB098: 0xCEF2, //HANGUL SYLLABLE KHIEUKH EO RIEULPHIEUPH + 0xB099: 0xCEF3, //HANGUL SYLLABLE KHIEUKH EO RIEULHIEUH + 0xB09A: 0xCEF6, //HANGUL SYLLABLE KHIEUKH EO PIEUPSIOS + 0xB09B: 0xCEFA, //HANGUL SYLLABLE KHIEUKH EO CIEUC + 0xB09C: 0xCEFB, //HANGUL SYLLABLE KHIEUKH EO CHIEUCH + 0xB09D: 0xCEFC, //HANGUL SYLLABLE KHIEUKH EO KHIEUKH + 0xB09E: 0xCEFD, //HANGUL SYLLABLE KHIEUKH EO THIEUTH + 0xB09F: 0xCEFE, //HANGUL SYLLABLE KHIEUKH EO PHIEUPH + 0xB0A0: 0xCEFF, //HANGUL SYLLABLE KHIEUKH EO HIEUH + 0xB0A1: 0xAC00, //HANGUL SYLLABLE KIYEOK A + 0xB0A2: 0xAC01, //HANGUL SYLLABLE KIYEOK A KIYEOK + 0xB0A3: 0xAC04, //HANGUL SYLLABLE KIYEOK A NIEUN + 0xB0A4: 0xAC07, //HANGUL SYLLABLE KIYEOK A TIKEUT + 0xB0A5: 0xAC08, //HANGUL SYLLABLE KIYEOK A RIEUL + 0xB0A6: 0xAC09, //HANGUL SYLLABLE KIYEOK A RIEULKIYEOK + 0xB0A7: 0xAC0A, //HANGUL SYLLABLE KIYEOK A RIEULMIEUM + 0xB0A8: 0xAC10, //HANGUL SYLLABLE KIYEOK A MIEUM + 0xB0A9: 0xAC11, //HANGUL SYLLABLE KIYEOK A PIEUP + 0xB0AA: 0xAC12, //HANGUL SYLLABLE KIYEOK A PIEUPSIOS + 0xB0AB: 0xAC13, //HANGUL SYLLABLE KIYEOK A SIOS + 0xB0AC: 0xAC14, //HANGUL SYLLABLE KIYEOK A SSANGSIOS + 0xB0AD: 0xAC15, //HANGUL SYLLABLE KIYEOK A IEUNG + 0xB0AE: 0xAC16, //HANGUL SYLLABLE KIYEOK A CIEUC + 0xB0AF: 0xAC17, //HANGUL SYLLABLE KIYEOK A CHIEUCH + 0xB0B0: 0xAC19, //HANGUL SYLLABLE KIYEOK A THIEUTH + 0xB0B1: 0xAC1A, //HANGUL SYLLABLE KIYEOK A PHIEUPH + 0xB0B2: 0xAC1B, //HANGUL SYLLABLE KIYEOK A HIEUH + 0xB0B3: 0xAC1C, //HANGUL SYLLABLE KIYEOK AE + 0xB0B4: 0xAC1D, //HANGUL SYLLABLE KIYEOK AE KIYEOK + 0xB0B5: 0xAC20, //HANGUL SYLLABLE KIYEOK AE NIEUN + 0xB0B6: 0xAC24, //HANGUL SYLLABLE KIYEOK AE RIEUL + 0xB0B7: 0xAC2C, //HANGUL SYLLABLE KIYEOK AE MIEUM + 0xB0B8: 0xAC2D, //HANGUL SYLLABLE KIYEOK AE PIEUP + 0xB0B9: 0xAC2F, //HANGUL SYLLABLE KIYEOK AE SIOS + 0xB0BA: 0xAC30, //HANGUL SYLLABLE KIYEOK AE SSANGSIOS + 0xB0BB: 0xAC31, //HANGUL SYLLABLE KIYEOK AE IEUNG + 0xB0BC: 0xAC38, //HANGUL SYLLABLE KIYEOK YA + 0xB0BD: 0xAC39, //HANGUL SYLLABLE KIYEOK YA KIYEOK + 0xB0BE: 0xAC3C, //HANGUL SYLLABLE KIYEOK YA NIEUN + 0xB0BF: 0xAC40, //HANGUL SYLLABLE KIYEOK YA RIEUL + 0xB0C0: 0xAC4B, //HANGUL SYLLABLE KIYEOK YA SIOS + 0xB0C1: 0xAC4D, //HANGUL SYLLABLE KIYEOK YA IEUNG + 0xB0C2: 0xAC54, //HANGUL SYLLABLE KIYEOK YAE + 0xB0C3: 0xAC58, //HANGUL SYLLABLE KIYEOK YAE NIEUN + 0xB0C4: 0xAC5C, //HANGUL SYLLABLE KIYEOK YAE RIEUL + 0xB0C5: 0xAC70, //HANGUL SYLLABLE KIYEOK EO + 0xB0C6: 0xAC71, //HANGUL SYLLABLE KIYEOK EO KIYEOK + 0xB0C7: 0xAC74, //HANGUL SYLLABLE KIYEOK EO NIEUN + 0xB0C8: 0xAC77, //HANGUL SYLLABLE KIYEOK EO TIKEUT + 0xB0C9: 0xAC78, //HANGUL SYLLABLE KIYEOK EO RIEUL + 0xB0CA: 0xAC7A, //HANGUL SYLLABLE KIYEOK EO RIEULMIEUM + 0xB0CB: 0xAC80, //HANGUL SYLLABLE KIYEOK EO MIEUM + 0xB0CC: 0xAC81, //HANGUL SYLLABLE KIYEOK EO PIEUP + 0xB0CD: 0xAC83, //HANGUL SYLLABLE KIYEOK EO SIOS + 0xB0CE: 0xAC84, //HANGUL SYLLABLE KIYEOK EO SSANGSIOS + 0xB0CF: 0xAC85, //HANGUL SYLLABLE KIYEOK EO IEUNG + 0xB0D0: 0xAC86, //HANGUL SYLLABLE KIYEOK EO CIEUC + 0xB0D1: 0xAC89, //HANGUL SYLLABLE KIYEOK EO THIEUTH + 0xB0D2: 0xAC8A, //HANGUL SYLLABLE KIYEOK EO PHIEUPH + 0xB0D3: 0xAC8B, //HANGUL SYLLABLE KIYEOK EO HIEUH + 0xB0D4: 0xAC8C, //HANGUL SYLLABLE KIYEOK E + 0xB0D5: 0xAC90, //HANGUL SYLLABLE KIYEOK E NIEUN + 0xB0D6: 0xAC94, //HANGUL SYLLABLE KIYEOK E RIEUL + 0xB0D7: 0xAC9C, //HANGUL SYLLABLE KIYEOK E MIEUM + 0xB0D8: 0xAC9D, //HANGUL SYLLABLE KIYEOK E PIEUP + 0xB0D9: 0xAC9F, //HANGUL SYLLABLE KIYEOK E SIOS + 0xB0DA: 0xACA0, //HANGUL SYLLABLE KIYEOK E SSANGSIOS + 0xB0DB: 0xACA1, //HANGUL SYLLABLE KIYEOK E IEUNG + 0xB0DC: 0xACA8, //HANGUL SYLLABLE KIYEOK YEO + 0xB0DD: 0xACA9, //HANGUL SYLLABLE KIYEOK YEO KIYEOK + 0xB0DE: 0xACAA, //HANGUL SYLLABLE KIYEOK YEO SSANGKIYEOK + 0xB0DF: 0xACAC, //HANGUL SYLLABLE KIYEOK YEO NIEUN + 0xB0E0: 0xACAF, //HANGUL SYLLABLE KIYEOK YEO TIKEUT + 0xB0E1: 0xACB0, //HANGUL SYLLABLE KIYEOK YEO RIEUL + 0xB0E2: 0xACB8, //HANGUL SYLLABLE KIYEOK YEO MIEUM + 0xB0E3: 0xACB9, //HANGUL SYLLABLE KIYEOK YEO PIEUP + 0xB0E4: 0xACBB, //HANGUL SYLLABLE KIYEOK YEO SIOS + 0xB0E5: 0xACBC, //HANGUL SYLLABLE KIYEOK YEO SSANGSIOS + 0xB0E6: 0xACBD, //HANGUL SYLLABLE KIYEOK YEO IEUNG + 0xB0E7: 0xACC1, //HANGUL SYLLABLE KIYEOK YEO THIEUTH + 0xB0E8: 0xACC4, //HANGUL SYLLABLE KIYEOK YE + 0xB0E9: 0xACC8, //HANGUL SYLLABLE KIYEOK YE NIEUN + 0xB0EA: 0xACCC, //HANGUL SYLLABLE KIYEOK YE RIEUL + 0xB0EB: 0xACD5, //HANGUL SYLLABLE KIYEOK YE PIEUP + 0xB0EC: 0xACD7, //HANGUL SYLLABLE KIYEOK YE SIOS + 0xB0ED: 0xACE0, //HANGUL SYLLABLE KIYEOK O + 0xB0EE: 0xACE1, //HANGUL SYLLABLE KIYEOK O KIYEOK + 0xB0EF: 0xACE4, //HANGUL SYLLABLE KIYEOK O NIEUN + 0xB0F0: 0xACE7, //HANGUL SYLLABLE KIYEOK O TIKEUT + 0xB0F1: 0xACE8, //HANGUL SYLLABLE KIYEOK O RIEUL + 0xB0F2: 0xACEA, //HANGUL SYLLABLE KIYEOK O RIEULMIEUM + 0xB0F3: 0xACEC, //HANGUL SYLLABLE KIYEOK O RIEULSIOS + 0xB0F4: 0xACEF, //HANGUL SYLLABLE KIYEOK O RIEULHIEUH + 0xB0F5: 0xACF0, //HANGUL SYLLABLE KIYEOK O MIEUM + 0xB0F6: 0xACF1, //HANGUL SYLLABLE KIYEOK O PIEUP + 0xB0F7: 0xACF3, //HANGUL SYLLABLE KIYEOK O SIOS + 0xB0F8: 0xACF5, //HANGUL SYLLABLE KIYEOK O IEUNG + 0xB0F9: 0xACF6, //HANGUL SYLLABLE KIYEOK O CIEUC + 0xB0FA: 0xACFC, //HANGUL SYLLABLE KIYEOK WA + 0xB0FB: 0xACFD, //HANGUL SYLLABLE KIYEOK WA KIYEOK + 0xB0FC: 0xAD00, //HANGUL SYLLABLE KIYEOK WA NIEUN + 0xB0FD: 0xAD04, //HANGUL SYLLABLE KIYEOK WA RIEUL + 0xB0FE: 0xAD06, //HANGUL SYLLABLE KIYEOK WA RIEULMIEUM + 0xB141: 0xCF02, //HANGUL SYLLABLE KHIEUKH E SSANGKIYEOK + 0xB142: 0xCF03, //HANGUL SYLLABLE KHIEUKH E KIYEOKSIOS + 0xB143: 0xCF05, //HANGUL SYLLABLE KHIEUKH E NIEUNCIEUC + 0xB144: 0xCF06, //HANGUL SYLLABLE KHIEUKH E NIEUNHIEUH + 0xB145: 0xCF07, //HANGUL SYLLABLE KHIEUKH E TIKEUT + 0xB146: 0xCF09, //HANGUL SYLLABLE KHIEUKH E RIEULKIYEOK + 0xB147: 0xCF0A, //HANGUL SYLLABLE KHIEUKH E RIEULMIEUM + 0xB148: 0xCF0B, //HANGUL SYLLABLE KHIEUKH E RIEULPIEUP + 0xB149: 0xCF0C, //HANGUL SYLLABLE KHIEUKH E RIEULSIOS + 0xB14A: 0xCF0D, //HANGUL SYLLABLE KHIEUKH E RIEULTHIEUTH + 0xB14B: 0xCF0E, //HANGUL SYLLABLE KHIEUKH E RIEULPHIEUPH + 0xB14C: 0xCF0F, //HANGUL SYLLABLE KHIEUKH E RIEULHIEUH + 0xB14D: 0xCF12, //HANGUL SYLLABLE KHIEUKH E PIEUPSIOS + 0xB14E: 0xCF14, //HANGUL SYLLABLE KHIEUKH E SSANGSIOS + 0xB14F: 0xCF16, //HANGUL SYLLABLE KHIEUKH E CIEUC + 0xB150: 0xCF17, //HANGUL SYLLABLE KHIEUKH E CHIEUCH + 0xB151: 0xCF18, //HANGUL SYLLABLE KHIEUKH E KHIEUKH + 0xB152: 0xCF19, //HANGUL SYLLABLE KHIEUKH E THIEUTH + 0xB153: 0xCF1A, //HANGUL SYLLABLE KHIEUKH E PHIEUPH + 0xB154: 0xCF1B, //HANGUL SYLLABLE KHIEUKH E HIEUH + 0xB155: 0xCF1D, //HANGUL SYLLABLE KHIEUKH YEO KIYEOK + 0xB156: 0xCF1E, //HANGUL SYLLABLE KHIEUKH YEO SSANGKIYEOK + 0xB157: 0xCF1F, //HANGUL SYLLABLE KHIEUKH YEO KIYEOKSIOS + 0xB158: 0xCF21, //HANGUL SYLLABLE KHIEUKH YEO NIEUNCIEUC + 0xB159: 0xCF22, //HANGUL SYLLABLE KHIEUKH YEO NIEUNHIEUH + 0xB15A: 0xCF23, //HANGUL SYLLABLE KHIEUKH YEO TIKEUT + 0xB161: 0xCF25, //HANGUL SYLLABLE KHIEUKH YEO RIEULKIYEOK + 0xB162: 0xCF26, //HANGUL SYLLABLE KHIEUKH YEO RIEULMIEUM + 0xB163: 0xCF27, //HANGUL SYLLABLE KHIEUKH YEO RIEULPIEUP + 0xB164: 0xCF28, //HANGUL SYLLABLE KHIEUKH YEO RIEULSIOS + 0xB165: 0xCF29, //HANGUL SYLLABLE KHIEUKH YEO RIEULTHIEUTH + 0xB166: 0xCF2A, //HANGUL SYLLABLE KHIEUKH YEO RIEULPHIEUPH + 0xB167: 0xCF2B, //HANGUL SYLLABLE KHIEUKH YEO RIEULHIEUH + 0xB168: 0xCF2E, //HANGUL SYLLABLE KHIEUKH YEO PIEUPSIOS + 0xB169: 0xCF32, //HANGUL SYLLABLE KHIEUKH YEO CIEUC + 0xB16A: 0xCF33, //HANGUL SYLLABLE KHIEUKH YEO CHIEUCH + 0xB16B: 0xCF34, //HANGUL SYLLABLE KHIEUKH YEO KHIEUKH + 0xB16C: 0xCF35, //HANGUL SYLLABLE KHIEUKH YEO THIEUTH + 0xB16D: 0xCF36, //HANGUL SYLLABLE KHIEUKH YEO PHIEUPH + 0xB16E: 0xCF37, //HANGUL SYLLABLE KHIEUKH YEO HIEUH + 0xB16F: 0xCF39, //HANGUL SYLLABLE KHIEUKH YE KIYEOK + 0xB170: 0xCF3A, //HANGUL SYLLABLE KHIEUKH YE SSANGKIYEOK + 0xB171: 0xCF3B, //HANGUL SYLLABLE KHIEUKH YE KIYEOKSIOS + 0xB172: 0xCF3C, //HANGUL SYLLABLE KHIEUKH YE NIEUN + 0xB173: 0xCF3D, //HANGUL SYLLABLE KHIEUKH YE NIEUNCIEUC + 0xB174: 0xCF3E, //HANGUL SYLLABLE KHIEUKH YE NIEUNHIEUH + 0xB175: 0xCF3F, //HANGUL SYLLABLE KHIEUKH YE TIKEUT + 0xB176: 0xCF40, //HANGUL SYLLABLE KHIEUKH YE RIEUL + 0xB177: 0xCF41, //HANGUL SYLLABLE KHIEUKH YE RIEULKIYEOK + 0xB178: 0xCF42, //HANGUL SYLLABLE KHIEUKH YE RIEULMIEUM + 0xB179: 0xCF43, //HANGUL SYLLABLE KHIEUKH YE RIEULPIEUP + 0xB17A: 0xCF44, //HANGUL SYLLABLE KHIEUKH YE RIEULSIOS + 0xB181: 0xCF45, //HANGUL SYLLABLE KHIEUKH YE RIEULTHIEUTH + 0xB182: 0xCF46, //HANGUL SYLLABLE KHIEUKH YE RIEULPHIEUPH + 0xB183: 0xCF47, //HANGUL SYLLABLE KHIEUKH YE RIEULHIEUH + 0xB184: 0xCF48, //HANGUL SYLLABLE KHIEUKH YE MIEUM + 0xB185: 0xCF49, //HANGUL SYLLABLE KHIEUKH YE PIEUP + 0xB186: 0xCF4A, //HANGUL SYLLABLE KHIEUKH YE PIEUPSIOS + 0xB187: 0xCF4B, //HANGUL SYLLABLE KHIEUKH YE SIOS + 0xB188: 0xCF4C, //HANGUL SYLLABLE KHIEUKH YE SSANGSIOS + 0xB189: 0xCF4D, //HANGUL SYLLABLE KHIEUKH YE IEUNG + 0xB18A: 0xCF4E, //HANGUL SYLLABLE KHIEUKH YE CIEUC + 0xB18B: 0xCF4F, //HANGUL SYLLABLE KHIEUKH YE CHIEUCH + 0xB18C: 0xCF50, //HANGUL SYLLABLE KHIEUKH YE KHIEUKH + 0xB18D: 0xCF51, //HANGUL SYLLABLE KHIEUKH YE THIEUTH + 0xB18E: 0xCF52, //HANGUL SYLLABLE KHIEUKH YE PHIEUPH + 0xB18F: 0xCF53, //HANGUL SYLLABLE KHIEUKH YE HIEUH + 0xB190: 0xCF56, //HANGUL SYLLABLE KHIEUKH O SSANGKIYEOK + 0xB191: 0xCF57, //HANGUL SYLLABLE KHIEUKH O KIYEOKSIOS + 0xB192: 0xCF59, //HANGUL SYLLABLE KHIEUKH O NIEUNCIEUC + 0xB193: 0xCF5A, //HANGUL SYLLABLE KHIEUKH O NIEUNHIEUH + 0xB194: 0xCF5B, //HANGUL SYLLABLE KHIEUKH O TIKEUT + 0xB195: 0xCF5D, //HANGUL SYLLABLE KHIEUKH O RIEULKIYEOK + 0xB196: 0xCF5E, //HANGUL SYLLABLE KHIEUKH O RIEULMIEUM + 0xB197: 0xCF5F, //HANGUL SYLLABLE KHIEUKH O RIEULPIEUP + 0xB198: 0xCF60, //HANGUL SYLLABLE KHIEUKH O RIEULSIOS + 0xB199: 0xCF61, //HANGUL SYLLABLE KHIEUKH O RIEULTHIEUTH + 0xB19A: 0xCF62, //HANGUL SYLLABLE KHIEUKH O RIEULPHIEUPH + 0xB19B: 0xCF63, //HANGUL SYLLABLE KHIEUKH O RIEULHIEUH + 0xB19C: 0xCF66, //HANGUL SYLLABLE KHIEUKH O PIEUPSIOS + 0xB19D: 0xCF68, //HANGUL SYLLABLE KHIEUKH O SSANGSIOS + 0xB19E: 0xCF6A, //HANGUL SYLLABLE KHIEUKH O CIEUC + 0xB19F: 0xCF6B, //HANGUL SYLLABLE KHIEUKH O CHIEUCH + 0xB1A0: 0xCF6C, //HANGUL SYLLABLE KHIEUKH O KHIEUKH + 0xB1A1: 0xAD0C, //HANGUL SYLLABLE KIYEOK WA MIEUM + 0xB1A2: 0xAD0D, //HANGUL SYLLABLE KIYEOK WA PIEUP + 0xB1A3: 0xAD0F, //HANGUL SYLLABLE KIYEOK WA SIOS + 0xB1A4: 0xAD11, //HANGUL SYLLABLE KIYEOK WA IEUNG + 0xB1A5: 0xAD18, //HANGUL SYLLABLE KIYEOK WAE + 0xB1A6: 0xAD1C, //HANGUL SYLLABLE KIYEOK WAE NIEUN + 0xB1A7: 0xAD20, //HANGUL SYLLABLE KIYEOK WAE RIEUL + 0xB1A8: 0xAD29, //HANGUL SYLLABLE KIYEOK WAE PIEUP + 0xB1A9: 0xAD2C, //HANGUL SYLLABLE KIYEOK WAE SSANGSIOS + 0xB1AA: 0xAD2D, //HANGUL SYLLABLE KIYEOK WAE IEUNG + 0xB1AB: 0xAD34, //HANGUL SYLLABLE KIYEOK OE + 0xB1AC: 0xAD35, //HANGUL SYLLABLE KIYEOK OE KIYEOK + 0xB1AD: 0xAD38, //HANGUL SYLLABLE KIYEOK OE NIEUN + 0xB1AE: 0xAD3C, //HANGUL SYLLABLE KIYEOK OE RIEUL + 0xB1AF: 0xAD44, //HANGUL SYLLABLE KIYEOK OE MIEUM + 0xB1B0: 0xAD45, //HANGUL SYLLABLE KIYEOK OE PIEUP + 0xB1B1: 0xAD47, //HANGUL SYLLABLE KIYEOK OE SIOS + 0xB1B2: 0xAD49, //HANGUL SYLLABLE KIYEOK OE IEUNG + 0xB1B3: 0xAD50, //HANGUL SYLLABLE KIYEOK YO + 0xB1B4: 0xAD54, //HANGUL SYLLABLE KIYEOK YO NIEUN + 0xB1B5: 0xAD58, //HANGUL SYLLABLE KIYEOK YO RIEUL + 0xB1B6: 0xAD61, //HANGUL SYLLABLE KIYEOK YO PIEUP + 0xB1B7: 0xAD63, //HANGUL SYLLABLE KIYEOK YO SIOS + 0xB1B8: 0xAD6C, //HANGUL SYLLABLE KIYEOK U + 0xB1B9: 0xAD6D, //HANGUL SYLLABLE KIYEOK U KIYEOK + 0xB1BA: 0xAD70, //HANGUL SYLLABLE KIYEOK U NIEUN + 0xB1BB: 0xAD73, //HANGUL SYLLABLE KIYEOK U TIKEUT + 0xB1BC: 0xAD74, //HANGUL SYLLABLE KIYEOK U RIEUL + 0xB1BD: 0xAD75, //HANGUL SYLLABLE KIYEOK U RIEULKIYEOK + 0xB1BE: 0xAD76, //HANGUL SYLLABLE KIYEOK U RIEULMIEUM + 0xB1BF: 0xAD7B, //HANGUL SYLLABLE KIYEOK U RIEULHIEUH + 0xB1C0: 0xAD7C, //HANGUL SYLLABLE KIYEOK U MIEUM + 0xB1C1: 0xAD7D, //HANGUL SYLLABLE KIYEOK U PIEUP + 0xB1C2: 0xAD7F, //HANGUL SYLLABLE KIYEOK U SIOS + 0xB1C3: 0xAD81, //HANGUL SYLLABLE KIYEOK U IEUNG + 0xB1C4: 0xAD82, //HANGUL SYLLABLE KIYEOK U CIEUC + 0xB1C5: 0xAD88, //HANGUL SYLLABLE KIYEOK WEO + 0xB1C6: 0xAD89, //HANGUL SYLLABLE KIYEOK WEO KIYEOK + 0xB1C7: 0xAD8C, //HANGUL SYLLABLE KIYEOK WEO NIEUN + 0xB1C8: 0xAD90, //HANGUL SYLLABLE KIYEOK WEO RIEUL + 0xB1C9: 0xAD9C, //HANGUL SYLLABLE KIYEOK WEO SSANGSIOS + 0xB1CA: 0xAD9D, //HANGUL SYLLABLE KIYEOK WEO IEUNG + 0xB1CB: 0xADA4, //HANGUL SYLLABLE KIYEOK WE + 0xB1CC: 0xADB7, //HANGUL SYLLABLE KIYEOK WE SIOS + 0xB1CD: 0xADC0, //HANGUL SYLLABLE KIYEOK WI + 0xB1CE: 0xADC1, //HANGUL SYLLABLE KIYEOK WI KIYEOK + 0xB1CF: 0xADC4, //HANGUL SYLLABLE KIYEOK WI NIEUN + 0xB1D0: 0xADC8, //HANGUL SYLLABLE KIYEOK WI RIEUL + 0xB1D1: 0xADD0, //HANGUL SYLLABLE KIYEOK WI MIEUM + 0xB1D2: 0xADD1, //HANGUL SYLLABLE KIYEOK WI PIEUP + 0xB1D3: 0xADD3, //HANGUL SYLLABLE KIYEOK WI SIOS + 0xB1D4: 0xADDC, //HANGUL SYLLABLE KIYEOK YU + 0xB1D5: 0xADE0, //HANGUL SYLLABLE KIYEOK YU NIEUN + 0xB1D6: 0xADE4, //HANGUL SYLLABLE KIYEOK YU RIEUL + 0xB1D7: 0xADF8, //HANGUL SYLLABLE KIYEOK EU + 0xB1D8: 0xADF9, //HANGUL SYLLABLE KIYEOK EU KIYEOK + 0xB1D9: 0xADFC, //HANGUL SYLLABLE KIYEOK EU NIEUN + 0xB1DA: 0xADFF, //HANGUL SYLLABLE KIYEOK EU TIKEUT + 0xB1DB: 0xAE00, //HANGUL SYLLABLE KIYEOK EU RIEUL + 0xB1DC: 0xAE01, //HANGUL SYLLABLE KIYEOK EU RIEULKIYEOK + 0xB1DD: 0xAE08, //HANGUL SYLLABLE KIYEOK EU MIEUM + 0xB1DE: 0xAE09, //HANGUL SYLLABLE KIYEOK EU PIEUP + 0xB1DF: 0xAE0B, //HANGUL SYLLABLE KIYEOK EU SIOS + 0xB1E0: 0xAE0D, //HANGUL SYLLABLE KIYEOK EU IEUNG + 0xB1E1: 0xAE14, //HANGUL SYLLABLE KIYEOK YI + 0xB1E2: 0xAE30, //HANGUL SYLLABLE KIYEOK I + 0xB1E3: 0xAE31, //HANGUL SYLLABLE KIYEOK I KIYEOK + 0xB1E4: 0xAE34, //HANGUL SYLLABLE KIYEOK I NIEUN + 0xB1E5: 0xAE37, //HANGUL SYLLABLE KIYEOK I TIKEUT + 0xB1E6: 0xAE38, //HANGUL SYLLABLE KIYEOK I RIEUL + 0xB1E7: 0xAE3A, //HANGUL SYLLABLE KIYEOK I RIEULMIEUM + 0xB1E8: 0xAE40, //HANGUL SYLLABLE KIYEOK I MIEUM + 0xB1E9: 0xAE41, //HANGUL SYLLABLE KIYEOK I PIEUP + 0xB1EA: 0xAE43, //HANGUL SYLLABLE KIYEOK I SIOS + 0xB1EB: 0xAE45, //HANGUL SYLLABLE KIYEOK I IEUNG + 0xB1EC: 0xAE46, //HANGUL SYLLABLE KIYEOK I CIEUC + 0xB1ED: 0xAE4A, //HANGUL SYLLABLE KIYEOK I PHIEUPH + 0xB1EE: 0xAE4C, //HANGUL SYLLABLE SSANGKIYEOK A + 0xB1EF: 0xAE4D, //HANGUL SYLLABLE SSANGKIYEOK A KIYEOK + 0xB1F0: 0xAE4E, //HANGUL SYLLABLE SSANGKIYEOK A SSANGKIYEOK + 0xB1F1: 0xAE50, //HANGUL SYLLABLE SSANGKIYEOK A NIEUN + 0xB1F2: 0xAE54, //HANGUL SYLLABLE SSANGKIYEOK A RIEUL + 0xB1F3: 0xAE56, //HANGUL SYLLABLE SSANGKIYEOK A RIEULMIEUM + 0xB1F4: 0xAE5C, //HANGUL SYLLABLE SSANGKIYEOK A MIEUM + 0xB1F5: 0xAE5D, //HANGUL SYLLABLE SSANGKIYEOK A PIEUP + 0xB1F6: 0xAE5F, //HANGUL SYLLABLE SSANGKIYEOK A SIOS + 0xB1F7: 0xAE60, //HANGUL SYLLABLE SSANGKIYEOK A SSANGSIOS + 0xB1F8: 0xAE61, //HANGUL SYLLABLE SSANGKIYEOK A IEUNG + 0xB1F9: 0xAE65, //HANGUL SYLLABLE SSANGKIYEOK A THIEUTH + 0xB1FA: 0xAE68, //HANGUL SYLLABLE SSANGKIYEOK AE + 0xB1FB: 0xAE69, //HANGUL SYLLABLE SSANGKIYEOK AE KIYEOK + 0xB1FC: 0xAE6C, //HANGUL SYLLABLE SSANGKIYEOK AE NIEUN + 0xB1FD: 0xAE70, //HANGUL SYLLABLE SSANGKIYEOK AE RIEUL + 0xB1FE: 0xAE78, //HANGUL SYLLABLE SSANGKIYEOK AE MIEUM + 0xB241: 0xCF6D, //HANGUL SYLLABLE KHIEUKH O THIEUTH + 0xB242: 0xCF6E, //HANGUL SYLLABLE KHIEUKH O PHIEUPH + 0xB243: 0xCF6F, //HANGUL SYLLABLE KHIEUKH O HIEUH + 0xB244: 0xCF72, //HANGUL SYLLABLE KHIEUKH WA SSANGKIYEOK + 0xB245: 0xCF73, //HANGUL SYLLABLE KHIEUKH WA KIYEOKSIOS + 0xB246: 0xCF75, //HANGUL SYLLABLE KHIEUKH WA NIEUNCIEUC + 0xB247: 0xCF76, //HANGUL SYLLABLE KHIEUKH WA NIEUNHIEUH + 0xB248: 0xCF77, //HANGUL SYLLABLE KHIEUKH WA TIKEUT + 0xB249: 0xCF79, //HANGUL SYLLABLE KHIEUKH WA RIEULKIYEOK + 0xB24A: 0xCF7A, //HANGUL SYLLABLE KHIEUKH WA RIEULMIEUM + 0xB24B: 0xCF7B, //HANGUL SYLLABLE KHIEUKH WA RIEULPIEUP + 0xB24C: 0xCF7C, //HANGUL SYLLABLE KHIEUKH WA RIEULSIOS + 0xB24D: 0xCF7D, //HANGUL SYLLABLE KHIEUKH WA RIEULTHIEUTH + 0xB24E: 0xCF7E, //HANGUL SYLLABLE KHIEUKH WA RIEULPHIEUPH + 0xB24F: 0xCF7F, //HANGUL SYLLABLE KHIEUKH WA RIEULHIEUH + 0xB250: 0xCF81, //HANGUL SYLLABLE KHIEUKH WA PIEUP + 0xB251: 0xCF82, //HANGUL SYLLABLE KHIEUKH WA PIEUPSIOS + 0xB252: 0xCF83, //HANGUL SYLLABLE KHIEUKH WA SIOS + 0xB253: 0xCF84, //HANGUL SYLLABLE KHIEUKH WA SSANGSIOS + 0xB254: 0xCF86, //HANGUL SYLLABLE KHIEUKH WA CIEUC + 0xB255: 0xCF87, //HANGUL SYLLABLE KHIEUKH WA CHIEUCH + 0xB256: 0xCF88, //HANGUL SYLLABLE KHIEUKH WA KHIEUKH + 0xB257: 0xCF89, //HANGUL SYLLABLE KHIEUKH WA THIEUTH + 0xB258: 0xCF8A, //HANGUL SYLLABLE KHIEUKH WA PHIEUPH + 0xB259: 0xCF8B, //HANGUL SYLLABLE KHIEUKH WA HIEUH + 0xB25A: 0xCF8D, //HANGUL SYLLABLE KHIEUKH WAE KIYEOK + 0xB261: 0xCF8E, //HANGUL SYLLABLE KHIEUKH WAE SSANGKIYEOK + 0xB262: 0xCF8F, //HANGUL SYLLABLE KHIEUKH WAE KIYEOKSIOS + 0xB263: 0xCF90, //HANGUL SYLLABLE KHIEUKH WAE NIEUN + 0xB264: 0xCF91, //HANGUL SYLLABLE KHIEUKH WAE NIEUNCIEUC + 0xB265: 0xCF92, //HANGUL SYLLABLE KHIEUKH WAE NIEUNHIEUH + 0xB266: 0xCF93, //HANGUL SYLLABLE KHIEUKH WAE TIKEUT + 0xB267: 0xCF94, //HANGUL SYLLABLE KHIEUKH WAE RIEUL + 0xB268: 0xCF95, //HANGUL SYLLABLE KHIEUKH WAE RIEULKIYEOK + 0xB269: 0xCF96, //HANGUL SYLLABLE KHIEUKH WAE RIEULMIEUM + 0xB26A: 0xCF97, //HANGUL SYLLABLE KHIEUKH WAE RIEULPIEUP + 0xB26B: 0xCF98, //HANGUL SYLLABLE KHIEUKH WAE RIEULSIOS + 0xB26C: 0xCF99, //HANGUL SYLLABLE KHIEUKH WAE RIEULTHIEUTH + 0xB26D: 0xCF9A, //HANGUL SYLLABLE KHIEUKH WAE RIEULPHIEUPH + 0xB26E: 0xCF9B, //HANGUL SYLLABLE KHIEUKH WAE RIEULHIEUH + 0xB26F: 0xCF9C, //HANGUL SYLLABLE KHIEUKH WAE MIEUM + 0xB270: 0xCF9D, //HANGUL SYLLABLE KHIEUKH WAE PIEUP + 0xB271: 0xCF9E, //HANGUL SYLLABLE KHIEUKH WAE PIEUPSIOS + 0xB272: 0xCF9F, //HANGUL SYLLABLE KHIEUKH WAE SIOS + 0xB273: 0xCFA0, //HANGUL SYLLABLE KHIEUKH WAE SSANGSIOS + 0xB274: 0xCFA2, //HANGUL SYLLABLE KHIEUKH WAE CIEUC + 0xB275: 0xCFA3, //HANGUL SYLLABLE KHIEUKH WAE CHIEUCH + 0xB276: 0xCFA4, //HANGUL SYLLABLE KHIEUKH WAE KHIEUKH + 0xB277: 0xCFA5, //HANGUL SYLLABLE KHIEUKH WAE THIEUTH + 0xB278: 0xCFA6, //HANGUL SYLLABLE KHIEUKH WAE PHIEUPH + 0xB279: 0xCFA7, //HANGUL SYLLABLE KHIEUKH WAE HIEUH + 0xB27A: 0xCFA9, //HANGUL SYLLABLE KHIEUKH OE KIYEOK + 0xB281: 0xCFAA, //HANGUL SYLLABLE KHIEUKH OE SSANGKIYEOK + 0xB282: 0xCFAB, //HANGUL SYLLABLE KHIEUKH OE KIYEOKSIOS + 0xB283: 0xCFAC, //HANGUL SYLLABLE KHIEUKH OE NIEUN + 0xB284: 0xCFAD, //HANGUL SYLLABLE KHIEUKH OE NIEUNCIEUC + 0xB285: 0xCFAE, //HANGUL SYLLABLE KHIEUKH OE NIEUNHIEUH + 0xB286: 0xCFAF, //HANGUL SYLLABLE KHIEUKH OE TIKEUT + 0xB287: 0xCFB1, //HANGUL SYLLABLE KHIEUKH OE RIEULKIYEOK + 0xB288: 0xCFB2, //HANGUL SYLLABLE KHIEUKH OE RIEULMIEUM + 0xB289: 0xCFB3, //HANGUL SYLLABLE KHIEUKH OE RIEULPIEUP + 0xB28A: 0xCFB4, //HANGUL SYLLABLE KHIEUKH OE RIEULSIOS + 0xB28B: 0xCFB5, //HANGUL SYLLABLE KHIEUKH OE RIEULTHIEUTH + 0xB28C: 0xCFB6, //HANGUL SYLLABLE KHIEUKH OE RIEULPHIEUPH + 0xB28D: 0xCFB7, //HANGUL SYLLABLE KHIEUKH OE RIEULHIEUH + 0xB28E: 0xCFB8, //HANGUL SYLLABLE KHIEUKH OE MIEUM + 0xB28F: 0xCFB9, //HANGUL SYLLABLE KHIEUKH OE PIEUP + 0xB290: 0xCFBA, //HANGUL SYLLABLE KHIEUKH OE PIEUPSIOS + 0xB291: 0xCFBB, //HANGUL SYLLABLE KHIEUKH OE SIOS + 0xB292: 0xCFBC, //HANGUL SYLLABLE KHIEUKH OE SSANGSIOS + 0xB293: 0xCFBD, //HANGUL SYLLABLE KHIEUKH OE IEUNG + 0xB294: 0xCFBE, //HANGUL SYLLABLE KHIEUKH OE CIEUC + 0xB295: 0xCFBF, //HANGUL SYLLABLE KHIEUKH OE CHIEUCH + 0xB296: 0xCFC0, //HANGUL SYLLABLE KHIEUKH OE KHIEUKH + 0xB297: 0xCFC1, //HANGUL SYLLABLE KHIEUKH OE THIEUTH + 0xB298: 0xCFC2, //HANGUL SYLLABLE KHIEUKH OE PHIEUPH + 0xB299: 0xCFC3, //HANGUL SYLLABLE KHIEUKH OE HIEUH + 0xB29A: 0xCFC5, //HANGUL SYLLABLE KHIEUKH YO KIYEOK + 0xB29B: 0xCFC6, //HANGUL SYLLABLE KHIEUKH YO SSANGKIYEOK + 0xB29C: 0xCFC7, //HANGUL SYLLABLE KHIEUKH YO KIYEOKSIOS + 0xB29D: 0xCFC8, //HANGUL SYLLABLE KHIEUKH YO NIEUN + 0xB29E: 0xCFC9, //HANGUL SYLLABLE KHIEUKH YO NIEUNCIEUC + 0xB29F: 0xCFCA, //HANGUL SYLLABLE KHIEUKH YO NIEUNHIEUH + 0xB2A0: 0xCFCB, //HANGUL SYLLABLE KHIEUKH YO TIKEUT + 0xB2A1: 0xAE79, //HANGUL SYLLABLE SSANGKIYEOK AE PIEUP + 0xB2A2: 0xAE7B, //HANGUL SYLLABLE SSANGKIYEOK AE SIOS + 0xB2A3: 0xAE7C, //HANGUL SYLLABLE SSANGKIYEOK AE SSANGSIOS + 0xB2A4: 0xAE7D, //HANGUL SYLLABLE SSANGKIYEOK AE IEUNG + 0xB2A5: 0xAE84, //HANGUL SYLLABLE SSANGKIYEOK YA + 0xB2A6: 0xAE85, //HANGUL SYLLABLE SSANGKIYEOK YA KIYEOK + 0xB2A7: 0xAE8C, //HANGUL SYLLABLE SSANGKIYEOK YA RIEUL + 0xB2A8: 0xAEBC, //HANGUL SYLLABLE SSANGKIYEOK EO + 0xB2A9: 0xAEBD, //HANGUL SYLLABLE SSANGKIYEOK EO KIYEOK + 0xB2AA: 0xAEBE, //HANGUL SYLLABLE SSANGKIYEOK EO SSANGKIYEOK + 0xB2AB: 0xAEC0, //HANGUL SYLLABLE SSANGKIYEOK EO NIEUN + 0xB2AC: 0xAEC4, //HANGUL SYLLABLE SSANGKIYEOK EO RIEUL + 0xB2AD: 0xAECC, //HANGUL SYLLABLE SSANGKIYEOK EO MIEUM + 0xB2AE: 0xAECD, //HANGUL SYLLABLE SSANGKIYEOK EO PIEUP + 0xB2AF: 0xAECF, //HANGUL SYLLABLE SSANGKIYEOK EO SIOS + 0xB2B0: 0xAED0, //HANGUL SYLLABLE SSANGKIYEOK EO SSANGSIOS + 0xB2B1: 0xAED1, //HANGUL SYLLABLE SSANGKIYEOK EO IEUNG + 0xB2B2: 0xAED8, //HANGUL SYLLABLE SSANGKIYEOK E + 0xB2B3: 0xAED9, //HANGUL SYLLABLE SSANGKIYEOK E KIYEOK + 0xB2B4: 0xAEDC, //HANGUL SYLLABLE SSANGKIYEOK E NIEUN + 0xB2B5: 0xAEE8, //HANGUL SYLLABLE SSANGKIYEOK E MIEUM + 0xB2B6: 0xAEEB, //HANGUL SYLLABLE SSANGKIYEOK E SIOS + 0xB2B7: 0xAEED, //HANGUL SYLLABLE SSANGKIYEOK E IEUNG + 0xB2B8: 0xAEF4, //HANGUL SYLLABLE SSANGKIYEOK YEO + 0xB2B9: 0xAEF8, //HANGUL SYLLABLE SSANGKIYEOK YEO NIEUN + 0xB2BA: 0xAEFC, //HANGUL SYLLABLE SSANGKIYEOK YEO RIEUL + 0xB2BB: 0xAF07, //HANGUL SYLLABLE SSANGKIYEOK YEO SIOS + 0xB2BC: 0xAF08, //HANGUL SYLLABLE SSANGKIYEOK YEO SSANGSIOS + 0xB2BD: 0xAF0D, //HANGUL SYLLABLE SSANGKIYEOK YEO THIEUTH + 0xB2BE: 0xAF10, //HANGUL SYLLABLE SSANGKIYEOK YE + 0xB2BF: 0xAF2C, //HANGUL SYLLABLE SSANGKIYEOK O + 0xB2C0: 0xAF2D, //HANGUL SYLLABLE SSANGKIYEOK O KIYEOK + 0xB2C1: 0xAF30, //HANGUL SYLLABLE SSANGKIYEOK O NIEUN + 0xB2C2: 0xAF32, //HANGUL SYLLABLE SSANGKIYEOK O NIEUNHIEUH + 0xB2C3: 0xAF34, //HANGUL SYLLABLE SSANGKIYEOK O RIEUL + 0xB2C4: 0xAF3C, //HANGUL SYLLABLE SSANGKIYEOK O MIEUM + 0xB2C5: 0xAF3D, //HANGUL SYLLABLE SSANGKIYEOK O PIEUP + 0xB2C6: 0xAF3F, //HANGUL SYLLABLE SSANGKIYEOK O SIOS + 0xB2C7: 0xAF41, //HANGUL SYLLABLE SSANGKIYEOK O IEUNG + 0xB2C8: 0xAF42, //HANGUL SYLLABLE SSANGKIYEOK O CIEUC + 0xB2C9: 0xAF43, //HANGUL SYLLABLE SSANGKIYEOK O CHIEUCH + 0xB2CA: 0xAF48, //HANGUL SYLLABLE SSANGKIYEOK WA + 0xB2CB: 0xAF49, //HANGUL SYLLABLE SSANGKIYEOK WA KIYEOK + 0xB2CC: 0xAF50, //HANGUL SYLLABLE SSANGKIYEOK WA RIEUL + 0xB2CD: 0xAF5C, //HANGUL SYLLABLE SSANGKIYEOK WA SSANGSIOS + 0xB2CE: 0xAF5D, //HANGUL SYLLABLE SSANGKIYEOK WA IEUNG + 0xB2CF: 0xAF64, //HANGUL SYLLABLE SSANGKIYEOK WAE + 0xB2D0: 0xAF65, //HANGUL SYLLABLE SSANGKIYEOK WAE KIYEOK + 0xB2D1: 0xAF79, //HANGUL SYLLABLE SSANGKIYEOK WAE IEUNG + 0xB2D2: 0xAF80, //HANGUL SYLLABLE SSANGKIYEOK OE + 0xB2D3: 0xAF84, //HANGUL SYLLABLE SSANGKIYEOK OE NIEUN + 0xB2D4: 0xAF88, //HANGUL SYLLABLE SSANGKIYEOK OE RIEUL + 0xB2D5: 0xAF90, //HANGUL SYLLABLE SSANGKIYEOK OE MIEUM + 0xB2D6: 0xAF91, //HANGUL SYLLABLE SSANGKIYEOK OE PIEUP + 0xB2D7: 0xAF95, //HANGUL SYLLABLE SSANGKIYEOK OE IEUNG + 0xB2D8: 0xAF9C, //HANGUL SYLLABLE SSANGKIYEOK YO + 0xB2D9: 0xAFB8, //HANGUL SYLLABLE SSANGKIYEOK U + 0xB2DA: 0xAFB9, //HANGUL SYLLABLE SSANGKIYEOK U KIYEOK + 0xB2DB: 0xAFBC, //HANGUL SYLLABLE SSANGKIYEOK U NIEUN + 0xB2DC: 0xAFC0, //HANGUL SYLLABLE SSANGKIYEOK U RIEUL + 0xB2DD: 0xAFC7, //HANGUL SYLLABLE SSANGKIYEOK U RIEULHIEUH + 0xB2DE: 0xAFC8, //HANGUL SYLLABLE SSANGKIYEOK U MIEUM + 0xB2DF: 0xAFC9, //HANGUL SYLLABLE SSANGKIYEOK U PIEUP + 0xB2E0: 0xAFCB, //HANGUL SYLLABLE SSANGKIYEOK U SIOS + 0xB2E1: 0xAFCD, //HANGUL SYLLABLE SSANGKIYEOK U IEUNG + 0xB2E2: 0xAFCE, //HANGUL SYLLABLE SSANGKIYEOK U CIEUC + 0xB2E3: 0xAFD4, //HANGUL SYLLABLE SSANGKIYEOK WEO + 0xB2E4: 0xAFDC, //HANGUL SYLLABLE SSANGKIYEOK WEO RIEUL + 0xB2E5: 0xAFE8, //HANGUL SYLLABLE SSANGKIYEOK WEO SSANGSIOS + 0xB2E6: 0xAFE9, //HANGUL SYLLABLE SSANGKIYEOK WEO IEUNG + 0xB2E7: 0xAFF0, //HANGUL SYLLABLE SSANGKIYEOK WE + 0xB2E8: 0xAFF1, //HANGUL SYLLABLE SSANGKIYEOK WE KIYEOK + 0xB2E9: 0xAFF4, //HANGUL SYLLABLE SSANGKIYEOK WE NIEUN + 0xB2EA: 0xAFF8, //HANGUL SYLLABLE SSANGKIYEOK WE RIEUL + 0xB2EB: 0xB000, //HANGUL SYLLABLE SSANGKIYEOK WE MIEUM + 0xB2EC: 0xB001, //HANGUL SYLLABLE SSANGKIYEOK WE PIEUP + 0xB2ED: 0xB004, //HANGUL SYLLABLE SSANGKIYEOK WE SSANGSIOS + 0xB2EE: 0xB00C, //HANGUL SYLLABLE SSANGKIYEOK WI + 0xB2EF: 0xB010, //HANGUL SYLLABLE SSANGKIYEOK WI NIEUN + 0xB2F0: 0xB014, //HANGUL SYLLABLE SSANGKIYEOK WI RIEUL + 0xB2F1: 0xB01C, //HANGUL SYLLABLE SSANGKIYEOK WI MIEUM + 0xB2F2: 0xB01D, //HANGUL SYLLABLE SSANGKIYEOK WI PIEUP + 0xB2F3: 0xB028, //HANGUL SYLLABLE SSANGKIYEOK YU + 0xB2F4: 0xB044, //HANGUL SYLLABLE SSANGKIYEOK EU + 0xB2F5: 0xB045, //HANGUL SYLLABLE SSANGKIYEOK EU KIYEOK + 0xB2F6: 0xB048, //HANGUL SYLLABLE SSANGKIYEOK EU NIEUN + 0xB2F7: 0xB04A, //HANGUL SYLLABLE SSANGKIYEOK EU NIEUNHIEUH + 0xB2F8: 0xB04C, //HANGUL SYLLABLE SSANGKIYEOK EU RIEUL + 0xB2F9: 0xB04E, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULMIEUM + 0xB2FA: 0xB053, //HANGUL SYLLABLE SSANGKIYEOK EU RIEULHIEUH + 0xB2FB: 0xB054, //HANGUL SYLLABLE SSANGKIYEOK EU MIEUM + 0xB2FC: 0xB055, //HANGUL SYLLABLE SSANGKIYEOK EU PIEUP + 0xB2FD: 0xB057, //HANGUL SYLLABLE SSANGKIYEOK EU SIOS + 0xB2FE: 0xB059, //HANGUL SYLLABLE SSANGKIYEOK EU IEUNG + 0xB341: 0xCFCC, //HANGUL SYLLABLE KHIEUKH YO RIEUL + 0xB342: 0xCFCD, //HANGUL SYLLABLE KHIEUKH YO RIEULKIYEOK + 0xB343: 0xCFCE, //HANGUL SYLLABLE KHIEUKH YO RIEULMIEUM + 0xB344: 0xCFCF, //HANGUL SYLLABLE KHIEUKH YO RIEULPIEUP + 0xB345: 0xCFD0, //HANGUL SYLLABLE KHIEUKH YO RIEULSIOS + 0xB346: 0xCFD1, //HANGUL SYLLABLE KHIEUKH YO RIEULTHIEUTH + 0xB347: 0xCFD2, //HANGUL SYLLABLE KHIEUKH YO RIEULPHIEUPH + 0xB348: 0xCFD3, //HANGUL SYLLABLE KHIEUKH YO RIEULHIEUH + 0xB349: 0xCFD4, //HANGUL SYLLABLE KHIEUKH YO MIEUM + 0xB34A: 0xCFD5, //HANGUL SYLLABLE KHIEUKH YO PIEUP + 0xB34B: 0xCFD6, //HANGUL SYLLABLE KHIEUKH YO PIEUPSIOS + 0xB34C: 0xCFD7, //HANGUL SYLLABLE KHIEUKH YO SIOS + 0xB34D: 0xCFD8, //HANGUL SYLLABLE KHIEUKH YO SSANGSIOS + 0xB34E: 0xCFD9, //HANGUL SYLLABLE KHIEUKH YO IEUNG + 0xB34F: 0xCFDA, //HANGUL SYLLABLE KHIEUKH YO CIEUC + 0xB350: 0xCFDB, //HANGUL SYLLABLE KHIEUKH YO CHIEUCH + 0xB351: 0xCFDC, //HANGUL SYLLABLE KHIEUKH YO KHIEUKH + 0xB352: 0xCFDD, //HANGUL SYLLABLE KHIEUKH YO THIEUTH + 0xB353: 0xCFDE, //HANGUL SYLLABLE KHIEUKH YO PHIEUPH + 0xB354: 0xCFDF, //HANGUL SYLLABLE KHIEUKH YO HIEUH + 0xB355: 0xCFE2, //HANGUL SYLLABLE KHIEUKH U SSANGKIYEOK + 0xB356: 0xCFE3, //HANGUL SYLLABLE KHIEUKH U KIYEOKSIOS + 0xB357: 0xCFE5, //HANGUL SYLLABLE KHIEUKH U NIEUNCIEUC + 0xB358: 0xCFE6, //HANGUL SYLLABLE KHIEUKH U NIEUNHIEUH + 0xB359: 0xCFE7, //HANGUL SYLLABLE KHIEUKH U TIKEUT + 0xB35A: 0xCFE9, //HANGUL SYLLABLE KHIEUKH U RIEULKIYEOK + 0xB361: 0xCFEA, //HANGUL SYLLABLE KHIEUKH U RIEULMIEUM + 0xB362: 0xCFEB, //HANGUL SYLLABLE KHIEUKH U RIEULPIEUP + 0xB363: 0xCFEC, //HANGUL SYLLABLE KHIEUKH U RIEULSIOS + 0xB364: 0xCFED, //HANGUL SYLLABLE KHIEUKH U RIEULTHIEUTH + 0xB365: 0xCFEE, //HANGUL SYLLABLE KHIEUKH U RIEULPHIEUPH + 0xB366: 0xCFEF, //HANGUL SYLLABLE KHIEUKH U RIEULHIEUH + 0xB367: 0xCFF2, //HANGUL SYLLABLE KHIEUKH U PIEUPSIOS + 0xB368: 0xCFF4, //HANGUL SYLLABLE KHIEUKH U SSANGSIOS + 0xB369: 0xCFF6, //HANGUL SYLLABLE KHIEUKH U CIEUC + 0xB36A: 0xCFF7, //HANGUL SYLLABLE KHIEUKH U CHIEUCH + 0xB36B: 0xCFF8, //HANGUL SYLLABLE KHIEUKH U KHIEUKH + 0xB36C: 0xCFF9, //HANGUL SYLLABLE KHIEUKH U THIEUTH + 0xB36D: 0xCFFA, //HANGUL SYLLABLE KHIEUKH U PHIEUPH + 0xB36E: 0xCFFB, //HANGUL SYLLABLE KHIEUKH U HIEUH + 0xB36F: 0xCFFD, //HANGUL SYLLABLE KHIEUKH WEO KIYEOK + 0xB370: 0xCFFE, //HANGUL SYLLABLE KHIEUKH WEO SSANGKIYEOK + 0xB371: 0xCFFF, //HANGUL SYLLABLE KHIEUKH WEO KIYEOKSIOS + 0xB372: 0xD001, //HANGUL SYLLABLE KHIEUKH WEO NIEUNCIEUC + 0xB373: 0xD002, //HANGUL SYLLABLE KHIEUKH WEO NIEUNHIEUH + 0xB374: 0xD003, //HANGUL SYLLABLE KHIEUKH WEO TIKEUT + 0xB375: 0xD005, //HANGUL SYLLABLE KHIEUKH WEO RIEULKIYEOK + 0xB376: 0xD006, //HANGUL SYLLABLE KHIEUKH WEO RIEULMIEUM + 0xB377: 0xD007, //HANGUL SYLLABLE KHIEUKH WEO RIEULPIEUP + 0xB378: 0xD008, //HANGUL SYLLABLE KHIEUKH WEO RIEULSIOS + 0xB379: 0xD009, //HANGUL SYLLABLE KHIEUKH WEO RIEULTHIEUTH + 0xB37A: 0xD00A, //HANGUL SYLLABLE KHIEUKH WEO RIEULPHIEUPH + 0xB381: 0xD00B, //HANGUL SYLLABLE KHIEUKH WEO RIEULHIEUH + 0xB382: 0xD00C, //HANGUL SYLLABLE KHIEUKH WEO MIEUM + 0xB383: 0xD00D, //HANGUL SYLLABLE KHIEUKH WEO PIEUP + 0xB384: 0xD00E, //HANGUL SYLLABLE KHIEUKH WEO PIEUPSIOS + 0xB385: 0xD00F, //HANGUL SYLLABLE KHIEUKH WEO SIOS + 0xB386: 0xD010, //HANGUL SYLLABLE KHIEUKH WEO SSANGSIOS + 0xB387: 0xD012, //HANGUL SYLLABLE KHIEUKH WEO CIEUC + 0xB388: 0xD013, //HANGUL SYLLABLE KHIEUKH WEO CHIEUCH + 0xB389: 0xD014, //HANGUL SYLLABLE KHIEUKH WEO KHIEUKH + 0xB38A: 0xD015, //HANGUL SYLLABLE KHIEUKH WEO THIEUTH + 0xB38B: 0xD016, //HANGUL SYLLABLE KHIEUKH WEO PHIEUPH + 0xB38C: 0xD017, //HANGUL SYLLABLE KHIEUKH WEO HIEUH + 0xB38D: 0xD019, //HANGUL SYLLABLE KHIEUKH WE KIYEOK + 0xB38E: 0xD01A, //HANGUL SYLLABLE KHIEUKH WE SSANGKIYEOK + 0xB38F: 0xD01B, //HANGUL SYLLABLE KHIEUKH WE KIYEOKSIOS + 0xB390: 0xD01C, //HANGUL SYLLABLE KHIEUKH WE NIEUN + 0xB391: 0xD01D, //HANGUL SYLLABLE KHIEUKH WE NIEUNCIEUC + 0xB392: 0xD01E, //HANGUL SYLLABLE KHIEUKH WE NIEUNHIEUH + 0xB393: 0xD01F, //HANGUL SYLLABLE KHIEUKH WE TIKEUT + 0xB394: 0xD020, //HANGUL SYLLABLE KHIEUKH WE RIEUL + 0xB395: 0xD021, //HANGUL SYLLABLE KHIEUKH WE RIEULKIYEOK + 0xB396: 0xD022, //HANGUL SYLLABLE KHIEUKH WE RIEULMIEUM + 0xB397: 0xD023, //HANGUL SYLLABLE KHIEUKH WE RIEULPIEUP + 0xB398: 0xD024, //HANGUL SYLLABLE KHIEUKH WE RIEULSIOS + 0xB399: 0xD025, //HANGUL SYLLABLE KHIEUKH WE RIEULTHIEUTH + 0xB39A: 0xD026, //HANGUL SYLLABLE KHIEUKH WE RIEULPHIEUPH + 0xB39B: 0xD027, //HANGUL SYLLABLE KHIEUKH WE RIEULHIEUH + 0xB39C: 0xD028, //HANGUL SYLLABLE KHIEUKH WE MIEUM + 0xB39D: 0xD029, //HANGUL SYLLABLE KHIEUKH WE PIEUP + 0xB39E: 0xD02A, //HANGUL SYLLABLE KHIEUKH WE PIEUPSIOS + 0xB39F: 0xD02B, //HANGUL SYLLABLE KHIEUKH WE SIOS + 0xB3A0: 0xD02C, //HANGUL SYLLABLE KHIEUKH WE SSANGSIOS + 0xB3A1: 0xB05D, //HANGUL SYLLABLE SSANGKIYEOK EU THIEUTH + 0xB3A2: 0xB07C, //HANGUL SYLLABLE SSANGKIYEOK I + 0xB3A3: 0xB07D, //HANGUL SYLLABLE SSANGKIYEOK I KIYEOK + 0xB3A4: 0xB080, //HANGUL SYLLABLE SSANGKIYEOK I NIEUN + 0xB3A5: 0xB084, //HANGUL SYLLABLE SSANGKIYEOK I RIEUL + 0xB3A6: 0xB08C, //HANGUL SYLLABLE SSANGKIYEOK I MIEUM + 0xB3A7: 0xB08D, //HANGUL SYLLABLE SSANGKIYEOK I PIEUP + 0xB3A8: 0xB08F, //HANGUL SYLLABLE SSANGKIYEOK I SIOS + 0xB3A9: 0xB091, //HANGUL SYLLABLE SSANGKIYEOK I IEUNG + 0xB3AA: 0xB098, //HANGUL SYLLABLE NIEUN A + 0xB3AB: 0xB099, //HANGUL SYLLABLE NIEUN A KIYEOK + 0xB3AC: 0xB09A, //HANGUL SYLLABLE NIEUN A SSANGKIYEOK + 0xB3AD: 0xB09C, //HANGUL SYLLABLE NIEUN A NIEUN + 0xB3AE: 0xB09F, //HANGUL SYLLABLE NIEUN A TIKEUT + 0xB3AF: 0xB0A0, //HANGUL SYLLABLE NIEUN A RIEUL + 0xB3B0: 0xB0A1, //HANGUL SYLLABLE NIEUN A RIEULKIYEOK + 0xB3B1: 0xB0A2, //HANGUL SYLLABLE NIEUN A RIEULMIEUM + 0xB3B2: 0xB0A8, //HANGUL SYLLABLE NIEUN A MIEUM + 0xB3B3: 0xB0A9, //HANGUL SYLLABLE NIEUN A PIEUP + 0xB3B4: 0xB0AB, //HANGUL SYLLABLE NIEUN A SIOS + 0xB3B5: 0xB0AC, //HANGUL SYLLABLE NIEUN A SSANGSIOS + 0xB3B6: 0xB0AD, //HANGUL SYLLABLE NIEUN A IEUNG + 0xB3B7: 0xB0AE, //HANGUL SYLLABLE NIEUN A CIEUC + 0xB3B8: 0xB0AF, //HANGUL SYLLABLE NIEUN A CHIEUCH + 0xB3B9: 0xB0B1, //HANGUL SYLLABLE NIEUN A THIEUTH + 0xB3BA: 0xB0B3, //HANGUL SYLLABLE NIEUN A HIEUH + 0xB3BB: 0xB0B4, //HANGUL SYLLABLE NIEUN AE + 0xB3BC: 0xB0B5, //HANGUL SYLLABLE NIEUN AE KIYEOK + 0xB3BD: 0xB0B8, //HANGUL SYLLABLE NIEUN AE NIEUN + 0xB3BE: 0xB0BC, //HANGUL SYLLABLE NIEUN AE RIEUL + 0xB3BF: 0xB0C4, //HANGUL SYLLABLE NIEUN AE MIEUM + 0xB3C0: 0xB0C5, //HANGUL SYLLABLE NIEUN AE PIEUP + 0xB3C1: 0xB0C7, //HANGUL SYLLABLE NIEUN AE SIOS + 0xB3C2: 0xB0C8, //HANGUL SYLLABLE NIEUN AE SSANGSIOS + 0xB3C3: 0xB0C9, //HANGUL SYLLABLE NIEUN AE IEUNG + 0xB3C4: 0xB0D0, //HANGUL SYLLABLE NIEUN YA + 0xB3C5: 0xB0D1, //HANGUL SYLLABLE NIEUN YA KIYEOK + 0xB3C6: 0xB0D4, //HANGUL SYLLABLE NIEUN YA NIEUN + 0xB3C7: 0xB0D8, //HANGUL SYLLABLE NIEUN YA RIEUL + 0xB3C8: 0xB0E0, //HANGUL SYLLABLE NIEUN YA MIEUM + 0xB3C9: 0xB0E5, //HANGUL SYLLABLE NIEUN YA IEUNG + 0xB3CA: 0xB108, //HANGUL SYLLABLE NIEUN EO + 0xB3CB: 0xB109, //HANGUL SYLLABLE NIEUN EO KIYEOK + 0xB3CC: 0xB10B, //HANGUL SYLLABLE NIEUN EO KIYEOKSIOS + 0xB3CD: 0xB10C, //HANGUL SYLLABLE NIEUN EO NIEUN + 0xB3CE: 0xB110, //HANGUL SYLLABLE NIEUN EO RIEUL + 0xB3CF: 0xB112, //HANGUL SYLLABLE NIEUN EO RIEULMIEUM + 0xB3D0: 0xB113, //HANGUL SYLLABLE NIEUN EO RIEULPIEUP + 0xB3D1: 0xB118, //HANGUL SYLLABLE NIEUN EO MIEUM + 0xB3D2: 0xB119, //HANGUL SYLLABLE NIEUN EO PIEUP + 0xB3D3: 0xB11B, //HANGUL SYLLABLE NIEUN EO SIOS + 0xB3D4: 0xB11C, //HANGUL SYLLABLE NIEUN EO SSANGSIOS + 0xB3D5: 0xB11D, //HANGUL SYLLABLE NIEUN EO IEUNG + 0xB3D6: 0xB123, //HANGUL SYLLABLE NIEUN EO HIEUH + 0xB3D7: 0xB124, //HANGUL SYLLABLE NIEUN E + 0xB3D8: 0xB125, //HANGUL SYLLABLE NIEUN E KIYEOK + 0xB3D9: 0xB128, //HANGUL SYLLABLE NIEUN E NIEUN + 0xB3DA: 0xB12C, //HANGUL SYLLABLE NIEUN E RIEUL + 0xB3DB: 0xB134, //HANGUL SYLLABLE NIEUN E MIEUM + 0xB3DC: 0xB135, //HANGUL SYLLABLE NIEUN E PIEUP + 0xB3DD: 0xB137, //HANGUL SYLLABLE NIEUN E SIOS + 0xB3DE: 0xB138, //HANGUL SYLLABLE NIEUN E SSANGSIOS + 0xB3DF: 0xB139, //HANGUL SYLLABLE NIEUN E IEUNG + 0xB3E0: 0xB140, //HANGUL SYLLABLE NIEUN YEO + 0xB3E1: 0xB141, //HANGUL SYLLABLE NIEUN YEO KIYEOK + 0xB3E2: 0xB144, //HANGUL SYLLABLE NIEUN YEO NIEUN + 0xB3E3: 0xB148, //HANGUL SYLLABLE NIEUN YEO RIEUL + 0xB3E4: 0xB150, //HANGUL SYLLABLE NIEUN YEO MIEUM + 0xB3E5: 0xB151, //HANGUL SYLLABLE NIEUN YEO PIEUP + 0xB3E6: 0xB154, //HANGUL SYLLABLE NIEUN YEO SSANGSIOS + 0xB3E7: 0xB155, //HANGUL SYLLABLE NIEUN YEO IEUNG + 0xB3E8: 0xB158, //HANGUL SYLLABLE NIEUN YEO KHIEUKH + 0xB3E9: 0xB15C, //HANGUL SYLLABLE NIEUN YE + 0xB3EA: 0xB160, //HANGUL SYLLABLE NIEUN YE NIEUN + 0xB3EB: 0xB178, //HANGUL SYLLABLE NIEUN O + 0xB3EC: 0xB179, //HANGUL SYLLABLE NIEUN O KIYEOK + 0xB3ED: 0xB17C, //HANGUL SYLLABLE NIEUN O NIEUN + 0xB3EE: 0xB180, //HANGUL SYLLABLE NIEUN O RIEUL + 0xB3EF: 0xB182, //HANGUL SYLLABLE NIEUN O RIEULMIEUM + 0xB3F0: 0xB188, //HANGUL SYLLABLE NIEUN O MIEUM + 0xB3F1: 0xB189, //HANGUL SYLLABLE NIEUN O PIEUP + 0xB3F2: 0xB18B, //HANGUL SYLLABLE NIEUN O SIOS + 0xB3F3: 0xB18D, //HANGUL SYLLABLE NIEUN O IEUNG + 0xB3F4: 0xB192, //HANGUL SYLLABLE NIEUN O PHIEUPH + 0xB3F5: 0xB193, //HANGUL SYLLABLE NIEUN O HIEUH + 0xB3F6: 0xB194, //HANGUL SYLLABLE NIEUN WA + 0xB3F7: 0xB198, //HANGUL SYLLABLE NIEUN WA NIEUN + 0xB3F8: 0xB19C, //HANGUL SYLLABLE NIEUN WA RIEUL + 0xB3F9: 0xB1A8, //HANGUL SYLLABLE NIEUN WA SSANGSIOS + 0xB3FA: 0xB1CC, //HANGUL SYLLABLE NIEUN OE + 0xB3FB: 0xB1D0, //HANGUL SYLLABLE NIEUN OE NIEUN + 0xB3FC: 0xB1D4, //HANGUL SYLLABLE NIEUN OE RIEUL + 0xB3FD: 0xB1DC, //HANGUL SYLLABLE NIEUN OE MIEUM + 0xB3FE: 0xB1DD, //HANGUL SYLLABLE NIEUN OE PIEUP + 0xB441: 0xD02E, //HANGUL SYLLABLE KHIEUKH WE CIEUC + 0xB442: 0xD02F, //HANGUL SYLLABLE KHIEUKH WE CHIEUCH + 0xB443: 0xD030, //HANGUL SYLLABLE KHIEUKH WE KHIEUKH + 0xB444: 0xD031, //HANGUL SYLLABLE KHIEUKH WE THIEUTH + 0xB445: 0xD032, //HANGUL SYLLABLE KHIEUKH WE PHIEUPH + 0xB446: 0xD033, //HANGUL SYLLABLE KHIEUKH WE HIEUH + 0xB447: 0xD036, //HANGUL SYLLABLE KHIEUKH WI SSANGKIYEOK + 0xB448: 0xD037, //HANGUL SYLLABLE KHIEUKH WI KIYEOKSIOS + 0xB449: 0xD039, //HANGUL SYLLABLE KHIEUKH WI NIEUNCIEUC + 0xB44A: 0xD03A, //HANGUL SYLLABLE KHIEUKH WI NIEUNHIEUH + 0xB44B: 0xD03B, //HANGUL SYLLABLE KHIEUKH WI TIKEUT + 0xB44C: 0xD03D, //HANGUL SYLLABLE KHIEUKH WI RIEULKIYEOK + 0xB44D: 0xD03E, //HANGUL SYLLABLE KHIEUKH WI RIEULMIEUM + 0xB44E: 0xD03F, //HANGUL SYLLABLE KHIEUKH WI RIEULPIEUP + 0xB44F: 0xD040, //HANGUL SYLLABLE KHIEUKH WI RIEULSIOS + 0xB450: 0xD041, //HANGUL SYLLABLE KHIEUKH WI RIEULTHIEUTH + 0xB451: 0xD042, //HANGUL SYLLABLE KHIEUKH WI RIEULPHIEUPH + 0xB452: 0xD043, //HANGUL SYLLABLE KHIEUKH WI RIEULHIEUH + 0xB453: 0xD046, //HANGUL SYLLABLE KHIEUKH WI PIEUPSIOS + 0xB454: 0xD048, //HANGUL SYLLABLE KHIEUKH WI SSANGSIOS + 0xB455: 0xD04A, //HANGUL SYLLABLE KHIEUKH WI CIEUC + 0xB456: 0xD04B, //HANGUL SYLLABLE KHIEUKH WI CHIEUCH + 0xB457: 0xD04C, //HANGUL SYLLABLE KHIEUKH WI KHIEUKH + 0xB458: 0xD04D, //HANGUL SYLLABLE KHIEUKH WI THIEUTH + 0xB459: 0xD04E, //HANGUL SYLLABLE KHIEUKH WI PHIEUPH + 0xB45A: 0xD04F, //HANGUL SYLLABLE KHIEUKH WI HIEUH + 0xB461: 0xD051, //HANGUL SYLLABLE KHIEUKH YU KIYEOK + 0xB462: 0xD052, //HANGUL SYLLABLE KHIEUKH YU SSANGKIYEOK + 0xB463: 0xD053, //HANGUL SYLLABLE KHIEUKH YU KIYEOKSIOS + 0xB464: 0xD055, //HANGUL SYLLABLE KHIEUKH YU NIEUNCIEUC + 0xB465: 0xD056, //HANGUL SYLLABLE KHIEUKH YU NIEUNHIEUH + 0xB466: 0xD057, //HANGUL SYLLABLE KHIEUKH YU TIKEUT + 0xB467: 0xD059, //HANGUL SYLLABLE KHIEUKH YU RIEULKIYEOK + 0xB468: 0xD05A, //HANGUL SYLLABLE KHIEUKH YU RIEULMIEUM + 0xB469: 0xD05B, //HANGUL SYLLABLE KHIEUKH YU RIEULPIEUP + 0xB46A: 0xD05C, //HANGUL SYLLABLE KHIEUKH YU RIEULSIOS + 0xB46B: 0xD05D, //HANGUL SYLLABLE KHIEUKH YU RIEULTHIEUTH + 0xB46C: 0xD05E, //HANGUL SYLLABLE KHIEUKH YU RIEULPHIEUPH + 0xB46D: 0xD05F, //HANGUL SYLLABLE KHIEUKH YU RIEULHIEUH + 0xB46E: 0xD061, //HANGUL SYLLABLE KHIEUKH YU PIEUP + 0xB46F: 0xD062, //HANGUL SYLLABLE KHIEUKH YU PIEUPSIOS + 0xB470: 0xD063, //HANGUL SYLLABLE KHIEUKH YU SIOS + 0xB471: 0xD064, //HANGUL SYLLABLE KHIEUKH YU SSANGSIOS + 0xB472: 0xD065, //HANGUL SYLLABLE KHIEUKH YU IEUNG + 0xB473: 0xD066, //HANGUL SYLLABLE KHIEUKH YU CIEUC + 0xB474: 0xD067, //HANGUL SYLLABLE KHIEUKH YU CHIEUCH + 0xB475: 0xD068, //HANGUL SYLLABLE KHIEUKH YU KHIEUKH + 0xB476: 0xD069, //HANGUL SYLLABLE KHIEUKH YU THIEUTH + 0xB477: 0xD06A, //HANGUL SYLLABLE KHIEUKH YU PHIEUPH + 0xB478: 0xD06B, //HANGUL SYLLABLE KHIEUKH YU HIEUH + 0xB479: 0xD06E, //HANGUL SYLLABLE KHIEUKH EU SSANGKIYEOK + 0xB47A: 0xD06F, //HANGUL SYLLABLE KHIEUKH EU KIYEOKSIOS + 0xB481: 0xD071, //HANGUL SYLLABLE KHIEUKH EU NIEUNCIEUC + 0xB482: 0xD072, //HANGUL SYLLABLE KHIEUKH EU NIEUNHIEUH + 0xB483: 0xD073, //HANGUL SYLLABLE KHIEUKH EU TIKEUT + 0xB484: 0xD075, //HANGUL SYLLABLE KHIEUKH EU RIEULKIYEOK + 0xB485: 0xD076, //HANGUL SYLLABLE KHIEUKH EU RIEULMIEUM + 0xB486: 0xD077, //HANGUL SYLLABLE KHIEUKH EU RIEULPIEUP + 0xB487: 0xD078, //HANGUL SYLLABLE KHIEUKH EU RIEULSIOS + 0xB488: 0xD079, //HANGUL SYLLABLE KHIEUKH EU RIEULTHIEUTH + 0xB489: 0xD07A, //HANGUL SYLLABLE KHIEUKH EU RIEULPHIEUPH + 0xB48A: 0xD07B, //HANGUL SYLLABLE KHIEUKH EU RIEULHIEUH + 0xB48B: 0xD07E, //HANGUL SYLLABLE KHIEUKH EU PIEUPSIOS + 0xB48C: 0xD07F, //HANGUL SYLLABLE KHIEUKH EU SIOS + 0xB48D: 0xD080, //HANGUL SYLLABLE KHIEUKH EU SSANGSIOS + 0xB48E: 0xD082, //HANGUL SYLLABLE KHIEUKH EU CIEUC + 0xB48F: 0xD083, //HANGUL SYLLABLE KHIEUKH EU CHIEUCH + 0xB490: 0xD084, //HANGUL SYLLABLE KHIEUKH EU KHIEUKH + 0xB491: 0xD085, //HANGUL SYLLABLE KHIEUKH EU THIEUTH + 0xB492: 0xD086, //HANGUL SYLLABLE KHIEUKH EU PHIEUPH + 0xB493: 0xD087, //HANGUL SYLLABLE KHIEUKH EU HIEUH + 0xB494: 0xD088, //HANGUL SYLLABLE KHIEUKH YI + 0xB495: 0xD089, //HANGUL SYLLABLE KHIEUKH YI KIYEOK + 0xB496: 0xD08A, //HANGUL SYLLABLE KHIEUKH YI SSANGKIYEOK + 0xB497: 0xD08B, //HANGUL SYLLABLE KHIEUKH YI KIYEOKSIOS + 0xB498: 0xD08C, //HANGUL SYLLABLE KHIEUKH YI NIEUN + 0xB499: 0xD08D, //HANGUL SYLLABLE KHIEUKH YI NIEUNCIEUC + 0xB49A: 0xD08E, //HANGUL SYLLABLE KHIEUKH YI NIEUNHIEUH + 0xB49B: 0xD08F, //HANGUL SYLLABLE KHIEUKH YI TIKEUT + 0xB49C: 0xD090, //HANGUL SYLLABLE KHIEUKH YI RIEUL + 0xB49D: 0xD091, //HANGUL SYLLABLE KHIEUKH YI RIEULKIYEOK + 0xB49E: 0xD092, //HANGUL SYLLABLE KHIEUKH YI RIEULMIEUM + 0xB49F: 0xD093, //HANGUL SYLLABLE KHIEUKH YI RIEULPIEUP + 0xB4A0: 0xD094, //HANGUL SYLLABLE KHIEUKH YI RIEULSIOS + 0xB4A1: 0xB1DF, //HANGUL SYLLABLE NIEUN OE SIOS + 0xB4A2: 0xB1E8, //HANGUL SYLLABLE NIEUN YO + 0xB4A3: 0xB1E9, //HANGUL SYLLABLE NIEUN YO KIYEOK + 0xB4A4: 0xB1EC, //HANGUL SYLLABLE NIEUN YO NIEUN + 0xB4A5: 0xB1F0, //HANGUL SYLLABLE NIEUN YO RIEUL + 0xB4A6: 0xB1F9, //HANGUL SYLLABLE NIEUN YO PIEUP + 0xB4A7: 0xB1FB, //HANGUL SYLLABLE NIEUN YO SIOS + 0xB4A8: 0xB1FD, //HANGUL SYLLABLE NIEUN YO IEUNG + 0xB4A9: 0xB204, //HANGUL SYLLABLE NIEUN U + 0xB4AA: 0xB205, //HANGUL SYLLABLE NIEUN U KIYEOK + 0xB4AB: 0xB208, //HANGUL SYLLABLE NIEUN U NIEUN + 0xB4AC: 0xB20B, //HANGUL SYLLABLE NIEUN U TIKEUT + 0xB4AD: 0xB20C, //HANGUL SYLLABLE NIEUN U RIEUL + 0xB4AE: 0xB214, //HANGUL SYLLABLE NIEUN U MIEUM + 0xB4AF: 0xB215, //HANGUL SYLLABLE NIEUN U PIEUP + 0xB4B0: 0xB217, //HANGUL SYLLABLE NIEUN U SIOS + 0xB4B1: 0xB219, //HANGUL SYLLABLE NIEUN U IEUNG + 0xB4B2: 0xB220, //HANGUL SYLLABLE NIEUN WEO + 0xB4B3: 0xB234, //HANGUL SYLLABLE NIEUN WEO SSANGSIOS + 0xB4B4: 0xB23C, //HANGUL SYLLABLE NIEUN WE + 0xB4B5: 0xB258, //HANGUL SYLLABLE NIEUN WI + 0xB4B6: 0xB25C, //HANGUL SYLLABLE NIEUN WI NIEUN + 0xB4B7: 0xB260, //HANGUL SYLLABLE NIEUN WI RIEUL + 0xB4B8: 0xB268, //HANGUL SYLLABLE NIEUN WI MIEUM + 0xB4B9: 0xB269, //HANGUL SYLLABLE NIEUN WI PIEUP + 0xB4BA: 0xB274, //HANGUL SYLLABLE NIEUN YU + 0xB4BB: 0xB275, //HANGUL SYLLABLE NIEUN YU KIYEOK + 0xB4BC: 0xB27C, //HANGUL SYLLABLE NIEUN YU RIEUL + 0xB4BD: 0xB284, //HANGUL SYLLABLE NIEUN YU MIEUM + 0xB4BE: 0xB285, //HANGUL SYLLABLE NIEUN YU PIEUP + 0xB4BF: 0xB289, //HANGUL SYLLABLE NIEUN YU IEUNG + 0xB4C0: 0xB290, //HANGUL SYLLABLE NIEUN EU + 0xB4C1: 0xB291, //HANGUL SYLLABLE NIEUN EU KIYEOK + 0xB4C2: 0xB294, //HANGUL SYLLABLE NIEUN EU NIEUN + 0xB4C3: 0xB298, //HANGUL SYLLABLE NIEUN EU RIEUL + 0xB4C4: 0xB299, //HANGUL SYLLABLE NIEUN EU RIEULKIYEOK + 0xB4C5: 0xB29A, //HANGUL SYLLABLE NIEUN EU RIEULMIEUM + 0xB4C6: 0xB2A0, //HANGUL SYLLABLE NIEUN EU MIEUM + 0xB4C7: 0xB2A1, //HANGUL SYLLABLE NIEUN EU PIEUP + 0xB4C8: 0xB2A3, //HANGUL SYLLABLE NIEUN EU SIOS + 0xB4C9: 0xB2A5, //HANGUL SYLLABLE NIEUN EU IEUNG + 0xB4CA: 0xB2A6, //HANGUL SYLLABLE NIEUN EU CIEUC + 0xB4CB: 0xB2AA, //HANGUL SYLLABLE NIEUN EU PHIEUPH + 0xB4CC: 0xB2AC, //HANGUL SYLLABLE NIEUN YI + 0xB4CD: 0xB2B0, //HANGUL SYLLABLE NIEUN YI NIEUN + 0xB4CE: 0xB2B4, //HANGUL SYLLABLE NIEUN YI RIEUL + 0xB4CF: 0xB2C8, //HANGUL SYLLABLE NIEUN I + 0xB4D0: 0xB2C9, //HANGUL SYLLABLE NIEUN I KIYEOK + 0xB4D1: 0xB2CC, //HANGUL SYLLABLE NIEUN I NIEUN + 0xB4D2: 0xB2D0, //HANGUL SYLLABLE NIEUN I RIEUL + 0xB4D3: 0xB2D2, //HANGUL SYLLABLE NIEUN I RIEULMIEUM + 0xB4D4: 0xB2D8, //HANGUL SYLLABLE NIEUN I MIEUM + 0xB4D5: 0xB2D9, //HANGUL SYLLABLE NIEUN I PIEUP + 0xB4D6: 0xB2DB, //HANGUL SYLLABLE NIEUN I SIOS + 0xB4D7: 0xB2DD, //HANGUL SYLLABLE NIEUN I IEUNG + 0xB4D8: 0xB2E2, //HANGUL SYLLABLE NIEUN I PHIEUPH + 0xB4D9: 0xB2E4, //HANGUL SYLLABLE TIKEUT A + 0xB4DA: 0xB2E5, //HANGUL SYLLABLE TIKEUT A KIYEOK + 0xB4DB: 0xB2E6, //HANGUL SYLLABLE TIKEUT A SSANGKIYEOK + 0xB4DC: 0xB2E8, //HANGUL SYLLABLE TIKEUT A NIEUN + 0xB4DD: 0xB2EB, //HANGUL SYLLABLE TIKEUT A TIKEUT + 0xB4DE: 0xB2EC, //HANGUL SYLLABLE TIKEUT A RIEUL + 0xB4DF: 0xB2ED, //HANGUL SYLLABLE TIKEUT A RIEULKIYEOK + 0xB4E0: 0xB2EE, //HANGUL SYLLABLE TIKEUT A RIEULMIEUM + 0xB4E1: 0xB2EF, //HANGUL SYLLABLE TIKEUT A RIEULPIEUP + 0xB4E2: 0xB2F3, //HANGUL SYLLABLE TIKEUT A RIEULHIEUH + 0xB4E3: 0xB2F4, //HANGUL SYLLABLE TIKEUT A MIEUM + 0xB4E4: 0xB2F5, //HANGUL SYLLABLE TIKEUT A PIEUP + 0xB4E5: 0xB2F7, //HANGUL SYLLABLE TIKEUT A SIOS + 0xB4E6: 0xB2F8, //HANGUL SYLLABLE TIKEUT A SSANGSIOS + 0xB4E7: 0xB2F9, //HANGUL SYLLABLE TIKEUT A IEUNG + 0xB4E8: 0xB2FA, //HANGUL SYLLABLE TIKEUT A CIEUC + 0xB4E9: 0xB2FB, //HANGUL SYLLABLE TIKEUT A CHIEUCH + 0xB4EA: 0xB2FF, //HANGUL SYLLABLE TIKEUT A HIEUH + 0xB4EB: 0xB300, //HANGUL SYLLABLE TIKEUT AE + 0xB4EC: 0xB301, //HANGUL SYLLABLE TIKEUT AE KIYEOK + 0xB4ED: 0xB304, //HANGUL SYLLABLE TIKEUT AE NIEUN + 0xB4EE: 0xB308, //HANGUL SYLLABLE TIKEUT AE RIEUL + 0xB4EF: 0xB310, //HANGUL SYLLABLE TIKEUT AE MIEUM + 0xB4F0: 0xB311, //HANGUL SYLLABLE TIKEUT AE PIEUP + 0xB4F1: 0xB313, //HANGUL SYLLABLE TIKEUT AE SIOS + 0xB4F2: 0xB314, //HANGUL SYLLABLE TIKEUT AE SSANGSIOS + 0xB4F3: 0xB315, //HANGUL SYLLABLE TIKEUT AE IEUNG + 0xB4F4: 0xB31C, //HANGUL SYLLABLE TIKEUT YA + 0xB4F5: 0xB354, //HANGUL SYLLABLE TIKEUT EO + 0xB4F6: 0xB355, //HANGUL SYLLABLE TIKEUT EO KIYEOK + 0xB4F7: 0xB356, //HANGUL SYLLABLE TIKEUT EO SSANGKIYEOK + 0xB4F8: 0xB358, //HANGUL SYLLABLE TIKEUT EO NIEUN + 0xB4F9: 0xB35B, //HANGUL SYLLABLE TIKEUT EO TIKEUT + 0xB4FA: 0xB35C, //HANGUL SYLLABLE TIKEUT EO RIEUL + 0xB4FB: 0xB35E, //HANGUL SYLLABLE TIKEUT EO RIEULMIEUM + 0xB4FC: 0xB35F, //HANGUL SYLLABLE TIKEUT EO RIEULPIEUP + 0xB4FD: 0xB364, //HANGUL SYLLABLE TIKEUT EO MIEUM + 0xB4FE: 0xB365, //HANGUL SYLLABLE TIKEUT EO PIEUP + 0xB541: 0xD095, //HANGUL SYLLABLE KHIEUKH YI RIEULTHIEUTH + 0xB542: 0xD096, //HANGUL SYLLABLE KHIEUKH YI RIEULPHIEUPH + 0xB543: 0xD097, //HANGUL SYLLABLE KHIEUKH YI RIEULHIEUH + 0xB544: 0xD098, //HANGUL SYLLABLE KHIEUKH YI MIEUM + 0xB545: 0xD099, //HANGUL SYLLABLE KHIEUKH YI PIEUP + 0xB546: 0xD09A, //HANGUL SYLLABLE KHIEUKH YI PIEUPSIOS + 0xB547: 0xD09B, //HANGUL SYLLABLE KHIEUKH YI SIOS + 0xB548: 0xD09C, //HANGUL SYLLABLE KHIEUKH YI SSANGSIOS + 0xB549: 0xD09D, //HANGUL SYLLABLE KHIEUKH YI IEUNG + 0xB54A: 0xD09E, //HANGUL SYLLABLE KHIEUKH YI CIEUC + 0xB54B: 0xD09F, //HANGUL SYLLABLE KHIEUKH YI CHIEUCH + 0xB54C: 0xD0A0, //HANGUL SYLLABLE KHIEUKH YI KHIEUKH + 0xB54D: 0xD0A1, //HANGUL SYLLABLE KHIEUKH YI THIEUTH + 0xB54E: 0xD0A2, //HANGUL SYLLABLE KHIEUKH YI PHIEUPH + 0xB54F: 0xD0A3, //HANGUL SYLLABLE KHIEUKH YI HIEUH + 0xB550: 0xD0A6, //HANGUL SYLLABLE KHIEUKH I SSANGKIYEOK + 0xB551: 0xD0A7, //HANGUL SYLLABLE KHIEUKH I KIYEOKSIOS + 0xB552: 0xD0A9, //HANGUL SYLLABLE KHIEUKH I NIEUNCIEUC + 0xB553: 0xD0AA, //HANGUL SYLLABLE KHIEUKH I NIEUNHIEUH + 0xB554: 0xD0AB, //HANGUL SYLLABLE KHIEUKH I TIKEUT + 0xB555: 0xD0AD, //HANGUL SYLLABLE KHIEUKH I RIEULKIYEOK + 0xB556: 0xD0AE, //HANGUL SYLLABLE KHIEUKH I RIEULMIEUM + 0xB557: 0xD0AF, //HANGUL SYLLABLE KHIEUKH I RIEULPIEUP + 0xB558: 0xD0B0, //HANGUL SYLLABLE KHIEUKH I RIEULSIOS + 0xB559: 0xD0B1, //HANGUL SYLLABLE KHIEUKH I RIEULTHIEUTH + 0xB55A: 0xD0B2, //HANGUL SYLLABLE KHIEUKH I RIEULPHIEUPH + 0xB561: 0xD0B3, //HANGUL SYLLABLE KHIEUKH I RIEULHIEUH + 0xB562: 0xD0B6, //HANGUL SYLLABLE KHIEUKH I PIEUPSIOS + 0xB563: 0xD0B8, //HANGUL SYLLABLE KHIEUKH I SSANGSIOS + 0xB564: 0xD0BA, //HANGUL SYLLABLE KHIEUKH I CIEUC + 0xB565: 0xD0BB, //HANGUL SYLLABLE KHIEUKH I CHIEUCH + 0xB566: 0xD0BC, //HANGUL SYLLABLE KHIEUKH I KHIEUKH + 0xB567: 0xD0BD, //HANGUL SYLLABLE KHIEUKH I THIEUTH + 0xB568: 0xD0BE, //HANGUL SYLLABLE KHIEUKH I PHIEUPH + 0xB569: 0xD0BF, //HANGUL SYLLABLE KHIEUKH I HIEUH + 0xB56A: 0xD0C2, //HANGUL SYLLABLE THIEUTH A SSANGKIYEOK + 0xB56B: 0xD0C3, //HANGUL SYLLABLE THIEUTH A KIYEOKSIOS + 0xB56C: 0xD0C5, //HANGUL SYLLABLE THIEUTH A NIEUNCIEUC + 0xB56D: 0xD0C6, //HANGUL SYLLABLE THIEUTH A NIEUNHIEUH + 0xB56E: 0xD0C7, //HANGUL SYLLABLE THIEUTH A TIKEUT + 0xB56F: 0xD0CA, //HANGUL SYLLABLE THIEUTH A RIEULMIEUM + 0xB570: 0xD0CB, //HANGUL SYLLABLE THIEUTH A RIEULPIEUP + 0xB571: 0xD0CC, //HANGUL SYLLABLE THIEUTH A RIEULSIOS + 0xB572: 0xD0CD, //HANGUL SYLLABLE THIEUTH A RIEULTHIEUTH + 0xB573: 0xD0CE, //HANGUL SYLLABLE THIEUTH A RIEULPHIEUPH + 0xB574: 0xD0CF, //HANGUL SYLLABLE THIEUTH A RIEULHIEUH + 0xB575: 0xD0D2, //HANGUL SYLLABLE THIEUTH A PIEUPSIOS + 0xB576: 0xD0D6, //HANGUL SYLLABLE THIEUTH A CIEUC + 0xB577: 0xD0D7, //HANGUL SYLLABLE THIEUTH A CHIEUCH + 0xB578: 0xD0D8, //HANGUL SYLLABLE THIEUTH A KHIEUKH + 0xB579: 0xD0D9, //HANGUL SYLLABLE THIEUTH A THIEUTH + 0xB57A: 0xD0DA, //HANGUL SYLLABLE THIEUTH A PHIEUPH + 0xB581: 0xD0DB, //HANGUL SYLLABLE THIEUTH A HIEUH + 0xB582: 0xD0DE, //HANGUL SYLLABLE THIEUTH AE SSANGKIYEOK + 0xB583: 0xD0DF, //HANGUL SYLLABLE THIEUTH AE KIYEOKSIOS + 0xB584: 0xD0E1, //HANGUL SYLLABLE THIEUTH AE NIEUNCIEUC + 0xB585: 0xD0E2, //HANGUL SYLLABLE THIEUTH AE NIEUNHIEUH + 0xB586: 0xD0E3, //HANGUL SYLLABLE THIEUTH AE TIKEUT + 0xB587: 0xD0E5, //HANGUL SYLLABLE THIEUTH AE RIEULKIYEOK + 0xB588: 0xD0E6, //HANGUL SYLLABLE THIEUTH AE RIEULMIEUM + 0xB589: 0xD0E7, //HANGUL SYLLABLE THIEUTH AE RIEULPIEUP + 0xB58A: 0xD0E8, //HANGUL SYLLABLE THIEUTH AE RIEULSIOS + 0xB58B: 0xD0E9, //HANGUL SYLLABLE THIEUTH AE RIEULTHIEUTH + 0xB58C: 0xD0EA, //HANGUL SYLLABLE THIEUTH AE RIEULPHIEUPH + 0xB58D: 0xD0EB, //HANGUL SYLLABLE THIEUTH AE RIEULHIEUH + 0xB58E: 0xD0EE, //HANGUL SYLLABLE THIEUTH AE PIEUPSIOS + 0xB58F: 0xD0F2, //HANGUL SYLLABLE THIEUTH AE CIEUC + 0xB590: 0xD0F3, //HANGUL SYLLABLE THIEUTH AE CHIEUCH + 0xB591: 0xD0F4, //HANGUL SYLLABLE THIEUTH AE KHIEUKH + 0xB592: 0xD0F5, //HANGUL SYLLABLE THIEUTH AE THIEUTH + 0xB593: 0xD0F6, //HANGUL SYLLABLE THIEUTH AE PHIEUPH + 0xB594: 0xD0F7, //HANGUL SYLLABLE THIEUTH AE HIEUH + 0xB595: 0xD0F9, //HANGUL SYLLABLE THIEUTH YA KIYEOK + 0xB596: 0xD0FA, //HANGUL SYLLABLE THIEUTH YA SSANGKIYEOK + 0xB597: 0xD0FB, //HANGUL SYLLABLE THIEUTH YA KIYEOKSIOS + 0xB598: 0xD0FC, //HANGUL SYLLABLE THIEUTH YA NIEUN + 0xB599: 0xD0FD, //HANGUL SYLLABLE THIEUTH YA NIEUNCIEUC + 0xB59A: 0xD0FE, //HANGUL SYLLABLE THIEUTH YA NIEUNHIEUH + 0xB59B: 0xD0FF, //HANGUL SYLLABLE THIEUTH YA TIKEUT + 0xB59C: 0xD100, //HANGUL SYLLABLE THIEUTH YA RIEUL + 0xB59D: 0xD101, //HANGUL SYLLABLE THIEUTH YA RIEULKIYEOK + 0xB59E: 0xD102, //HANGUL SYLLABLE THIEUTH YA RIEULMIEUM + 0xB59F: 0xD103, //HANGUL SYLLABLE THIEUTH YA RIEULPIEUP + 0xB5A0: 0xD104, //HANGUL SYLLABLE THIEUTH YA RIEULSIOS + 0xB5A1: 0xB367, //HANGUL SYLLABLE TIKEUT EO SIOS + 0xB5A2: 0xB369, //HANGUL SYLLABLE TIKEUT EO IEUNG + 0xB5A3: 0xB36B, //HANGUL SYLLABLE TIKEUT EO CHIEUCH + 0xB5A4: 0xB36E, //HANGUL SYLLABLE TIKEUT EO PHIEUPH + 0xB5A5: 0xB370, //HANGUL SYLLABLE TIKEUT E + 0xB5A6: 0xB371, //HANGUL SYLLABLE TIKEUT E KIYEOK + 0xB5A7: 0xB374, //HANGUL SYLLABLE TIKEUT E NIEUN + 0xB5A8: 0xB378, //HANGUL SYLLABLE TIKEUT E RIEUL + 0xB5A9: 0xB380, //HANGUL SYLLABLE TIKEUT E MIEUM + 0xB5AA: 0xB381, //HANGUL SYLLABLE TIKEUT E PIEUP + 0xB5AB: 0xB383, //HANGUL SYLLABLE TIKEUT E SIOS + 0xB5AC: 0xB384, //HANGUL SYLLABLE TIKEUT E SSANGSIOS + 0xB5AD: 0xB385, //HANGUL SYLLABLE TIKEUT E IEUNG + 0xB5AE: 0xB38C, //HANGUL SYLLABLE TIKEUT YEO + 0xB5AF: 0xB390, //HANGUL SYLLABLE TIKEUT YEO NIEUN + 0xB5B0: 0xB394, //HANGUL SYLLABLE TIKEUT YEO RIEUL + 0xB5B1: 0xB3A0, //HANGUL SYLLABLE TIKEUT YEO SSANGSIOS + 0xB5B2: 0xB3A1, //HANGUL SYLLABLE TIKEUT YEO IEUNG + 0xB5B3: 0xB3A8, //HANGUL SYLLABLE TIKEUT YE + 0xB5B4: 0xB3AC, //HANGUL SYLLABLE TIKEUT YE NIEUN + 0xB5B5: 0xB3C4, //HANGUL SYLLABLE TIKEUT O + 0xB5B6: 0xB3C5, //HANGUL SYLLABLE TIKEUT O KIYEOK + 0xB5B7: 0xB3C8, //HANGUL SYLLABLE TIKEUT O NIEUN + 0xB5B8: 0xB3CB, //HANGUL SYLLABLE TIKEUT O TIKEUT + 0xB5B9: 0xB3CC, //HANGUL SYLLABLE TIKEUT O RIEUL + 0xB5BA: 0xB3CE, //HANGUL SYLLABLE TIKEUT O RIEULMIEUM + 0xB5BB: 0xB3D0, //HANGUL SYLLABLE TIKEUT O RIEULSIOS + 0xB5BC: 0xB3D4, //HANGUL SYLLABLE TIKEUT O MIEUM + 0xB5BD: 0xB3D5, //HANGUL SYLLABLE TIKEUT O PIEUP + 0xB5BE: 0xB3D7, //HANGUL SYLLABLE TIKEUT O SIOS + 0xB5BF: 0xB3D9, //HANGUL SYLLABLE TIKEUT O IEUNG + 0xB5C0: 0xB3DB, //HANGUL SYLLABLE TIKEUT O CHIEUCH + 0xB5C1: 0xB3DD, //HANGUL SYLLABLE TIKEUT O THIEUTH + 0xB5C2: 0xB3E0, //HANGUL SYLLABLE TIKEUT WA + 0xB5C3: 0xB3E4, //HANGUL SYLLABLE TIKEUT WA NIEUN + 0xB5C4: 0xB3E8, //HANGUL SYLLABLE TIKEUT WA RIEUL + 0xB5C5: 0xB3FC, //HANGUL SYLLABLE TIKEUT WAE + 0xB5C6: 0xB410, //HANGUL SYLLABLE TIKEUT WAE SSANGSIOS + 0xB5C7: 0xB418, //HANGUL SYLLABLE TIKEUT OE + 0xB5C8: 0xB41C, //HANGUL SYLLABLE TIKEUT OE NIEUN + 0xB5C9: 0xB420, //HANGUL SYLLABLE TIKEUT OE RIEUL + 0xB5CA: 0xB428, //HANGUL SYLLABLE TIKEUT OE MIEUM + 0xB5CB: 0xB429, //HANGUL SYLLABLE TIKEUT OE PIEUP + 0xB5CC: 0xB42B, //HANGUL SYLLABLE TIKEUT OE SIOS + 0xB5CD: 0xB434, //HANGUL SYLLABLE TIKEUT YO + 0xB5CE: 0xB450, //HANGUL SYLLABLE TIKEUT U + 0xB5CF: 0xB451, //HANGUL SYLLABLE TIKEUT U KIYEOK + 0xB5D0: 0xB454, //HANGUL SYLLABLE TIKEUT U NIEUN + 0xB5D1: 0xB458, //HANGUL SYLLABLE TIKEUT U RIEUL + 0xB5D2: 0xB460, //HANGUL SYLLABLE TIKEUT U MIEUM + 0xB5D3: 0xB461, //HANGUL SYLLABLE TIKEUT U PIEUP + 0xB5D4: 0xB463, //HANGUL SYLLABLE TIKEUT U SIOS + 0xB5D5: 0xB465, //HANGUL SYLLABLE TIKEUT U IEUNG + 0xB5D6: 0xB46C, //HANGUL SYLLABLE TIKEUT WEO + 0xB5D7: 0xB480, //HANGUL SYLLABLE TIKEUT WEO SSANGSIOS + 0xB5D8: 0xB488, //HANGUL SYLLABLE TIKEUT WE + 0xB5D9: 0xB49D, //HANGUL SYLLABLE TIKEUT WE IEUNG + 0xB5DA: 0xB4A4, //HANGUL SYLLABLE TIKEUT WI + 0xB5DB: 0xB4A8, //HANGUL SYLLABLE TIKEUT WI NIEUN + 0xB5DC: 0xB4AC, //HANGUL SYLLABLE TIKEUT WI RIEUL + 0xB5DD: 0xB4B5, //HANGUL SYLLABLE TIKEUT WI PIEUP + 0xB5DE: 0xB4B7, //HANGUL SYLLABLE TIKEUT WI SIOS + 0xB5DF: 0xB4B9, //HANGUL SYLLABLE TIKEUT WI IEUNG + 0xB5E0: 0xB4C0, //HANGUL SYLLABLE TIKEUT YU + 0xB5E1: 0xB4C4, //HANGUL SYLLABLE TIKEUT YU NIEUN + 0xB5E2: 0xB4C8, //HANGUL SYLLABLE TIKEUT YU RIEUL + 0xB5E3: 0xB4D0, //HANGUL SYLLABLE TIKEUT YU MIEUM + 0xB5E4: 0xB4D5, //HANGUL SYLLABLE TIKEUT YU IEUNG + 0xB5E5: 0xB4DC, //HANGUL SYLLABLE TIKEUT EU + 0xB5E6: 0xB4DD, //HANGUL SYLLABLE TIKEUT EU KIYEOK + 0xB5E7: 0xB4E0, //HANGUL SYLLABLE TIKEUT EU NIEUN + 0xB5E8: 0xB4E3, //HANGUL SYLLABLE TIKEUT EU TIKEUT + 0xB5E9: 0xB4E4, //HANGUL SYLLABLE TIKEUT EU RIEUL + 0xB5EA: 0xB4E6, //HANGUL SYLLABLE TIKEUT EU RIEULMIEUM + 0xB5EB: 0xB4EC, //HANGUL SYLLABLE TIKEUT EU MIEUM + 0xB5EC: 0xB4ED, //HANGUL SYLLABLE TIKEUT EU PIEUP + 0xB5ED: 0xB4EF, //HANGUL SYLLABLE TIKEUT EU SIOS + 0xB5EE: 0xB4F1, //HANGUL SYLLABLE TIKEUT EU IEUNG + 0xB5EF: 0xB4F8, //HANGUL SYLLABLE TIKEUT YI + 0xB5F0: 0xB514, //HANGUL SYLLABLE TIKEUT I + 0xB5F1: 0xB515, //HANGUL SYLLABLE TIKEUT I KIYEOK + 0xB5F2: 0xB518, //HANGUL SYLLABLE TIKEUT I NIEUN + 0xB5F3: 0xB51B, //HANGUL SYLLABLE TIKEUT I TIKEUT + 0xB5F4: 0xB51C, //HANGUL SYLLABLE TIKEUT I RIEUL + 0xB5F5: 0xB524, //HANGUL SYLLABLE TIKEUT I MIEUM + 0xB5F6: 0xB525, //HANGUL SYLLABLE TIKEUT I PIEUP + 0xB5F7: 0xB527, //HANGUL SYLLABLE TIKEUT I SIOS + 0xB5F8: 0xB528, //HANGUL SYLLABLE TIKEUT I SSANGSIOS + 0xB5F9: 0xB529, //HANGUL SYLLABLE TIKEUT I IEUNG + 0xB5FA: 0xB52A, //HANGUL SYLLABLE TIKEUT I CIEUC + 0xB5FB: 0xB530, //HANGUL SYLLABLE SSANGTIKEUT A + 0xB5FC: 0xB531, //HANGUL SYLLABLE SSANGTIKEUT A KIYEOK + 0xB5FD: 0xB534, //HANGUL SYLLABLE SSANGTIKEUT A NIEUN + 0xB5FE: 0xB538, //HANGUL SYLLABLE SSANGTIKEUT A RIEUL + 0xB641: 0xD105, //HANGUL SYLLABLE THIEUTH YA RIEULTHIEUTH + 0xB642: 0xD106, //HANGUL SYLLABLE THIEUTH YA RIEULPHIEUPH + 0xB643: 0xD107, //HANGUL SYLLABLE THIEUTH YA RIEULHIEUH + 0xB644: 0xD108, //HANGUL SYLLABLE THIEUTH YA MIEUM + 0xB645: 0xD109, //HANGUL SYLLABLE THIEUTH YA PIEUP + 0xB646: 0xD10A, //HANGUL SYLLABLE THIEUTH YA PIEUPSIOS + 0xB647: 0xD10B, //HANGUL SYLLABLE THIEUTH YA SIOS + 0xB648: 0xD10C, //HANGUL SYLLABLE THIEUTH YA SSANGSIOS + 0xB649: 0xD10E, //HANGUL SYLLABLE THIEUTH YA CIEUC + 0xB64A: 0xD10F, //HANGUL SYLLABLE THIEUTH YA CHIEUCH + 0xB64B: 0xD110, //HANGUL SYLLABLE THIEUTH YA KHIEUKH + 0xB64C: 0xD111, //HANGUL SYLLABLE THIEUTH YA THIEUTH + 0xB64D: 0xD112, //HANGUL SYLLABLE THIEUTH YA PHIEUPH + 0xB64E: 0xD113, //HANGUL SYLLABLE THIEUTH YA HIEUH + 0xB64F: 0xD114, //HANGUL SYLLABLE THIEUTH YAE + 0xB650: 0xD115, //HANGUL SYLLABLE THIEUTH YAE KIYEOK + 0xB651: 0xD116, //HANGUL SYLLABLE THIEUTH YAE SSANGKIYEOK + 0xB652: 0xD117, //HANGUL SYLLABLE THIEUTH YAE KIYEOKSIOS + 0xB653: 0xD118, //HANGUL SYLLABLE THIEUTH YAE NIEUN + 0xB654: 0xD119, //HANGUL SYLLABLE THIEUTH YAE NIEUNCIEUC + 0xB655: 0xD11A, //HANGUL SYLLABLE THIEUTH YAE NIEUNHIEUH + 0xB656: 0xD11B, //HANGUL SYLLABLE THIEUTH YAE TIKEUT + 0xB657: 0xD11C, //HANGUL SYLLABLE THIEUTH YAE RIEUL + 0xB658: 0xD11D, //HANGUL SYLLABLE THIEUTH YAE RIEULKIYEOK + 0xB659: 0xD11E, //HANGUL SYLLABLE THIEUTH YAE RIEULMIEUM + 0xB65A: 0xD11F, //HANGUL SYLLABLE THIEUTH YAE RIEULPIEUP + 0xB661: 0xD120, //HANGUL SYLLABLE THIEUTH YAE RIEULSIOS + 0xB662: 0xD121, //HANGUL SYLLABLE THIEUTH YAE RIEULTHIEUTH + 0xB663: 0xD122, //HANGUL SYLLABLE THIEUTH YAE RIEULPHIEUPH + 0xB664: 0xD123, //HANGUL SYLLABLE THIEUTH YAE RIEULHIEUH + 0xB665: 0xD124, //HANGUL SYLLABLE THIEUTH YAE MIEUM + 0xB666: 0xD125, //HANGUL SYLLABLE THIEUTH YAE PIEUP + 0xB667: 0xD126, //HANGUL SYLLABLE THIEUTH YAE PIEUPSIOS + 0xB668: 0xD127, //HANGUL SYLLABLE THIEUTH YAE SIOS + 0xB669: 0xD128, //HANGUL SYLLABLE THIEUTH YAE SSANGSIOS + 0xB66A: 0xD129, //HANGUL SYLLABLE THIEUTH YAE IEUNG + 0xB66B: 0xD12A, //HANGUL SYLLABLE THIEUTH YAE CIEUC + 0xB66C: 0xD12B, //HANGUL SYLLABLE THIEUTH YAE CHIEUCH + 0xB66D: 0xD12C, //HANGUL SYLLABLE THIEUTH YAE KHIEUKH + 0xB66E: 0xD12D, //HANGUL SYLLABLE THIEUTH YAE THIEUTH + 0xB66F: 0xD12E, //HANGUL SYLLABLE THIEUTH YAE PHIEUPH + 0xB670: 0xD12F, //HANGUL SYLLABLE THIEUTH YAE HIEUH + 0xB671: 0xD132, //HANGUL SYLLABLE THIEUTH EO SSANGKIYEOK + 0xB672: 0xD133, //HANGUL SYLLABLE THIEUTH EO KIYEOKSIOS + 0xB673: 0xD135, //HANGUL SYLLABLE THIEUTH EO NIEUNCIEUC + 0xB674: 0xD136, //HANGUL SYLLABLE THIEUTH EO NIEUNHIEUH + 0xB675: 0xD137, //HANGUL SYLLABLE THIEUTH EO TIKEUT + 0xB676: 0xD139, //HANGUL SYLLABLE THIEUTH EO RIEULKIYEOK + 0xB677: 0xD13B, //HANGUL SYLLABLE THIEUTH EO RIEULPIEUP + 0xB678: 0xD13C, //HANGUL SYLLABLE THIEUTH EO RIEULSIOS + 0xB679: 0xD13D, //HANGUL SYLLABLE THIEUTH EO RIEULTHIEUTH + 0xB67A: 0xD13E, //HANGUL SYLLABLE THIEUTH EO RIEULPHIEUPH + 0xB681: 0xD13F, //HANGUL SYLLABLE THIEUTH EO RIEULHIEUH + 0xB682: 0xD142, //HANGUL SYLLABLE THIEUTH EO PIEUPSIOS + 0xB683: 0xD146, //HANGUL SYLLABLE THIEUTH EO CIEUC + 0xB684: 0xD147, //HANGUL SYLLABLE THIEUTH EO CHIEUCH + 0xB685: 0xD148, //HANGUL SYLLABLE THIEUTH EO KHIEUKH + 0xB686: 0xD149, //HANGUL SYLLABLE THIEUTH EO THIEUTH + 0xB687: 0xD14A, //HANGUL SYLLABLE THIEUTH EO PHIEUPH + 0xB688: 0xD14B, //HANGUL SYLLABLE THIEUTH EO HIEUH + 0xB689: 0xD14E, //HANGUL SYLLABLE THIEUTH E SSANGKIYEOK + 0xB68A: 0xD14F, //HANGUL SYLLABLE THIEUTH E KIYEOKSIOS + 0xB68B: 0xD151, //HANGUL SYLLABLE THIEUTH E NIEUNCIEUC + 0xB68C: 0xD152, //HANGUL SYLLABLE THIEUTH E NIEUNHIEUH + 0xB68D: 0xD153, //HANGUL SYLLABLE THIEUTH E TIKEUT + 0xB68E: 0xD155, //HANGUL SYLLABLE THIEUTH E RIEULKIYEOK + 0xB68F: 0xD156, //HANGUL SYLLABLE THIEUTH E RIEULMIEUM + 0xB690: 0xD157, //HANGUL SYLLABLE THIEUTH E RIEULPIEUP + 0xB691: 0xD158, //HANGUL SYLLABLE THIEUTH E RIEULSIOS + 0xB692: 0xD159, //HANGUL SYLLABLE THIEUTH E RIEULTHIEUTH + 0xB693: 0xD15A, //HANGUL SYLLABLE THIEUTH E RIEULPHIEUPH + 0xB694: 0xD15B, //HANGUL SYLLABLE THIEUTH E RIEULHIEUH + 0xB695: 0xD15E, //HANGUL SYLLABLE THIEUTH E PIEUPSIOS + 0xB696: 0xD160, //HANGUL SYLLABLE THIEUTH E SSANGSIOS + 0xB697: 0xD162, //HANGUL SYLLABLE THIEUTH E CIEUC + 0xB698: 0xD163, //HANGUL SYLLABLE THIEUTH E CHIEUCH + 0xB699: 0xD164, //HANGUL SYLLABLE THIEUTH E KHIEUKH + 0xB69A: 0xD165, //HANGUL SYLLABLE THIEUTH E THIEUTH + 0xB69B: 0xD166, //HANGUL SYLLABLE THIEUTH E PHIEUPH + 0xB69C: 0xD167, //HANGUL SYLLABLE THIEUTH E HIEUH + 0xB69D: 0xD169, //HANGUL SYLLABLE THIEUTH YEO KIYEOK + 0xB69E: 0xD16A, //HANGUL SYLLABLE THIEUTH YEO SSANGKIYEOK + 0xB69F: 0xD16B, //HANGUL SYLLABLE THIEUTH YEO KIYEOKSIOS + 0xB6A0: 0xD16D, //HANGUL SYLLABLE THIEUTH YEO NIEUNCIEUC + 0xB6A1: 0xB540, //HANGUL SYLLABLE SSANGTIKEUT A MIEUM + 0xB6A2: 0xB541, //HANGUL SYLLABLE SSANGTIKEUT A PIEUP + 0xB6A3: 0xB543, //HANGUL SYLLABLE SSANGTIKEUT A SIOS + 0xB6A4: 0xB544, //HANGUL SYLLABLE SSANGTIKEUT A SSANGSIOS + 0xB6A5: 0xB545, //HANGUL SYLLABLE SSANGTIKEUT A IEUNG + 0xB6A6: 0xB54B, //HANGUL SYLLABLE SSANGTIKEUT A HIEUH + 0xB6A7: 0xB54C, //HANGUL SYLLABLE SSANGTIKEUT AE + 0xB6A8: 0xB54D, //HANGUL SYLLABLE SSANGTIKEUT AE KIYEOK + 0xB6A9: 0xB550, //HANGUL SYLLABLE SSANGTIKEUT AE NIEUN + 0xB6AA: 0xB554, //HANGUL SYLLABLE SSANGTIKEUT AE RIEUL + 0xB6AB: 0xB55C, //HANGUL SYLLABLE SSANGTIKEUT AE MIEUM + 0xB6AC: 0xB55D, //HANGUL SYLLABLE SSANGTIKEUT AE PIEUP + 0xB6AD: 0xB55F, //HANGUL SYLLABLE SSANGTIKEUT AE SIOS + 0xB6AE: 0xB560, //HANGUL SYLLABLE SSANGTIKEUT AE SSANGSIOS + 0xB6AF: 0xB561, //HANGUL SYLLABLE SSANGTIKEUT AE IEUNG + 0xB6B0: 0xB5A0, //HANGUL SYLLABLE SSANGTIKEUT EO + 0xB6B1: 0xB5A1, //HANGUL SYLLABLE SSANGTIKEUT EO KIYEOK + 0xB6B2: 0xB5A4, //HANGUL SYLLABLE SSANGTIKEUT EO NIEUN + 0xB6B3: 0xB5A8, //HANGUL SYLLABLE SSANGTIKEUT EO RIEUL + 0xB6B4: 0xB5AA, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULMIEUM + 0xB6B5: 0xB5AB, //HANGUL SYLLABLE SSANGTIKEUT EO RIEULPIEUP + 0xB6B6: 0xB5B0, //HANGUL SYLLABLE SSANGTIKEUT EO MIEUM + 0xB6B7: 0xB5B1, //HANGUL SYLLABLE SSANGTIKEUT EO PIEUP + 0xB6B8: 0xB5B3, //HANGUL SYLLABLE SSANGTIKEUT EO SIOS + 0xB6B9: 0xB5B4, //HANGUL SYLLABLE SSANGTIKEUT EO SSANGSIOS + 0xB6BA: 0xB5B5, //HANGUL SYLLABLE SSANGTIKEUT EO IEUNG + 0xB6BB: 0xB5BB, //HANGUL SYLLABLE SSANGTIKEUT EO HIEUH + 0xB6BC: 0xB5BC, //HANGUL SYLLABLE SSANGTIKEUT E + 0xB6BD: 0xB5BD, //HANGUL SYLLABLE SSANGTIKEUT E KIYEOK + 0xB6BE: 0xB5C0, //HANGUL SYLLABLE SSANGTIKEUT E NIEUN + 0xB6BF: 0xB5C4, //HANGUL SYLLABLE SSANGTIKEUT E RIEUL + 0xB6C0: 0xB5CC, //HANGUL SYLLABLE SSANGTIKEUT E MIEUM + 0xB6C1: 0xB5CD, //HANGUL SYLLABLE SSANGTIKEUT E PIEUP + 0xB6C2: 0xB5CF, //HANGUL SYLLABLE SSANGTIKEUT E SIOS + 0xB6C3: 0xB5D0, //HANGUL SYLLABLE SSANGTIKEUT E SSANGSIOS + 0xB6C4: 0xB5D1, //HANGUL SYLLABLE SSANGTIKEUT E IEUNG + 0xB6C5: 0xB5D8, //HANGUL SYLLABLE SSANGTIKEUT YEO + 0xB6C6: 0xB5EC, //HANGUL SYLLABLE SSANGTIKEUT YEO SSANGSIOS + 0xB6C7: 0xB610, //HANGUL SYLLABLE SSANGTIKEUT O + 0xB6C8: 0xB611, //HANGUL SYLLABLE SSANGTIKEUT O KIYEOK + 0xB6C9: 0xB614, //HANGUL SYLLABLE SSANGTIKEUT O NIEUN + 0xB6CA: 0xB618, //HANGUL SYLLABLE SSANGTIKEUT O RIEUL + 0xB6CB: 0xB625, //HANGUL SYLLABLE SSANGTIKEUT O IEUNG + 0xB6CC: 0xB62C, //HANGUL SYLLABLE SSANGTIKEUT WA + 0xB6CD: 0xB634, //HANGUL SYLLABLE SSANGTIKEUT WA RIEUL + 0xB6CE: 0xB648, //HANGUL SYLLABLE SSANGTIKEUT WAE + 0xB6CF: 0xB664, //HANGUL SYLLABLE SSANGTIKEUT OE + 0xB6D0: 0xB668, //HANGUL SYLLABLE SSANGTIKEUT OE NIEUN + 0xB6D1: 0xB69C, //HANGUL SYLLABLE SSANGTIKEUT U + 0xB6D2: 0xB69D, //HANGUL SYLLABLE SSANGTIKEUT U KIYEOK + 0xB6D3: 0xB6A0, //HANGUL SYLLABLE SSANGTIKEUT U NIEUN + 0xB6D4: 0xB6A4, //HANGUL SYLLABLE SSANGTIKEUT U RIEUL + 0xB6D5: 0xB6AB, //HANGUL SYLLABLE SSANGTIKEUT U RIEULHIEUH + 0xB6D6: 0xB6AC, //HANGUL SYLLABLE SSANGTIKEUT U MIEUM + 0xB6D7: 0xB6B1, //HANGUL SYLLABLE SSANGTIKEUT U IEUNG + 0xB6D8: 0xB6D4, //HANGUL SYLLABLE SSANGTIKEUT WE + 0xB6D9: 0xB6F0, //HANGUL SYLLABLE SSANGTIKEUT WI + 0xB6DA: 0xB6F4, //HANGUL SYLLABLE SSANGTIKEUT WI NIEUN + 0xB6DB: 0xB6F8, //HANGUL SYLLABLE SSANGTIKEUT WI RIEUL + 0xB6DC: 0xB700, //HANGUL SYLLABLE SSANGTIKEUT WI MIEUM + 0xB6DD: 0xB701, //HANGUL SYLLABLE SSANGTIKEUT WI PIEUP + 0xB6DE: 0xB705, //HANGUL SYLLABLE SSANGTIKEUT WI IEUNG + 0xB6DF: 0xB728, //HANGUL SYLLABLE SSANGTIKEUT EU + 0xB6E0: 0xB729, //HANGUL SYLLABLE SSANGTIKEUT EU KIYEOK + 0xB6E1: 0xB72C, //HANGUL SYLLABLE SSANGTIKEUT EU NIEUN + 0xB6E2: 0xB72F, //HANGUL SYLLABLE SSANGTIKEUT EU TIKEUT + 0xB6E3: 0xB730, //HANGUL SYLLABLE SSANGTIKEUT EU RIEUL + 0xB6E4: 0xB738, //HANGUL SYLLABLE SSANGTIKEUT EU MIEUM + 0xB6E5: 0xB739, //HANGUL SYLLABLE SSANGTIKEUT EU PIEUP + 0xB6E6: 0xB73B, //HANGUL SYLLABLE SSANGTIKEUT EU SIOS + 0xB6E7: 0xB744, //HANGUL SYLLABLE SSANGTIKEUT YI + 0xB6E8: 0xB748, //HANGUL SYLLABLE SSANGTIKEUT YI NIEUN + 0xB6E9: 0xB74C, //HANGUL SYLLABLE SSANGTIKEUT YI RIEUL + 0xB6EA: 0xB754, //HANGUL SYLLABLE SSANGTIKEUT YI MIEUM + 0xB6EB: 0xB755, //HANGUL SYLLABLE SSANGTIKEUT YI PIEUP + 0xB6EC: 0xB760, //HANGUL SYLLABLE SSANGTIKEUT I + 0xB6ED: 0xB764, //HANGUL SYLLABLE SSANGTIKEUT I NIEUN + 0xB6EE: 0xB768, //HANGUL SYLLABLE SSANGTIKEUT I RIEUL + 0xB6EF: 0xB770, //HANGUL SYLLABLE SSANGTIKEUT I MIEUM + 0xB6F0: 0xB771, //HANGUL SYLLABLE SSANGTIKEUT I PIEUP + 0xB6F1: 0xB773, //HANGUL SYLLABLE SSANGTIKEUT I SIOS + 0xB6F2: 0xB775, //HANGUL SYLLABLE SSANGTIKEUT I IEUNG + 0xB6F3: 0xB77C, //HANGUL SYLLABLE RIEUL A + 0xB6F4: 0xB77D, //HANGUL SYLLABLE RIEUL A KIYEOK + 0xB6F5: 0xB780, //HANGUL SYLLABLE RIEUL A NIEUN + 0xB6F6: 0xB784, //HANGUL SYLLABLE RIEUL A RIEUL + 0xB6F7: 0xB78C, //HANGUL SYLLABLE RIEUL A MIEUM + 0xB6F8: 0xB78D, //HANGUL SYLLABLE RIEUL A PIEUP + 0xB6F9: 0xB78F, //HANGUL SYLLABLE RIEUL A SIOS + 0xB6FA: 0xB790, //HANGUL SYLLABLE RIEUL A SSANGSIOS + 0xB6FB: 0xB791, //HANGUL SYLLABLE RIEUL A IEUNG + 0xB6FC: 0xB792, //HANGUL SYLLABLE RIEUL A CIEUC + 0xB6FD: 0xB796, //HANGUL SYLLABLE RIEUL A PHIEUPH + 0xB6FE: 0xB797, //HANGUL SYLLABLE RIEUL A HIEUH + 0xB741: 0xD16E, //HANGUL SYLLABLE THIEUTH YEO NIEUNHIEUH + 0xB742: 0xD16F, //HANGUL SYLLABLE THIEUTH YEO TIKEUT + 0xB743: 0xD170, //HANGUL SYLLABLE THIEUTH YEO RIEUL + 0xB744: 0xD171, //HANGUL SYLLABLE THIEUTH YEO RIEULKIYEOK + 0xB745: 0xD172, //HANGUL SYLLABLE THIEUTH YEO RIEULMIEUM + 0xB746: 0xD173, //HANGUL SYLLABLE THIEUTH YEO RIEULPIEUP + 0xB747: 0xD174, //HANGUL SYLLABLE THIEUTH YEO RIEULSIOS + 0xB748: 0xD175, //HANGUL SYLLABLE THIEUTH YEO RIEULTHIEUTH + 0xB749: 0xD176, //HANGUL SYLLABLE THIEUTH YEO RIEULPHIEUPH + 0xB74A: 0xD177, //HANGUL SYLLABLE THIEUTH YEO RIEULHIEUH + 0xB74B: 0xD178, //HANGUL SYLLABLE THIEUTH YEO MIEUM + 0xB74C: 0xD179, //HANGUL SYLLABLE THIEUTH YEO PIEUP + 0xB74D: 0xD17A, //HANGUL SYLLABLE THIEUTH YEO PIEUPSIOS + 0xB74E: 0xD17B, //HANGUL SYLLABLE THIEUTH YEO SIOS + 0xB74F: 0xD17D, //HANGUL SYLLABLE THIEUTH YEO IEUNG + 0xB750: 0xD17E, //HANGUL SYLLABLE THIEUTH YEO CIEUC + 0xB751: 0xD17F, //HANGUL SYLLABLE THIEUTH YEO CHIEUCH + 0xB752: 0xD180, //HANGUL SYLLABLE THIEUTH YEO KHIEUKH + 0xB753: 0xD181, //HANGUL SYLLABLE THIEUTH YEO THIEUTH + 0xB754: 0xD182, //HANGUL SYLLABLE THIEUTH YEO PHIEUPH + 0xB755: 0xD183, //HANGUL SYLLABLE THIEUTH YEO HIEUH + 0xB756: 0xD185, //HANGUL SYLLABLE THIEUTH YE KIYEOK + 0xB757: 0xD186, //HANGUL SYLLABLE THIEUTH YE SSANGKIYEOK + 0xB758: 0xD187, //HANGUL SYLLABLE THIEUTH YE KIYEOKSIOS + 0xB759: 0xD189, //HANGUL SYLLABLE THIEUTH YE NIEUNCIEUC + 0xB75A: 0xD18A, //HANGUL SYLLABLE THIEUTH YE NIEUNHIEUH + 0xB761: 0xD18B, //HANGUL SYLLABLE THIEUTH YE TIKEUT + 0xB762: 0xD18C, //HANGUL SYLLABLE THIEUTH YE RIEUL + 0xB763: 0xD18D, //HANGUL SYLLABLE THIEUTH YE RIEULKIYEOK + 0xB764: 0xD18E, //HANGUL SYLLABLE THIEUTH YE RIEULMIEUM + 0xB765: 0xD18F, //HANGUL SYLLABLE THIEUTH YE RIEULPIEUP + 0xB766: 0xD190, //HANGUL SYLLABLE THIEUTH YE RIEULSIOS + 0xB767: 0xD191, //HANGUL SYLLABLE THIEUTH YE RIEULTHIEUTH + 0xB768: 0xD192, //HANGUL SYLLABLE THIEUTH YE RIEULPHIEUPH + 0xB769: 0xD193, //HANGUL SYLLABLE THIEUTH YE RIEULHIEUH + 0xB76A: 0xD194, //HANGUL SYLLABLE THIEUTH YE MIEUM + 0xB76B: 0xD195, //HANGUL SYLLABLE THIEUTH YE PIEUP + 0xB76C: 0xD196, //HANGUL SYLLABLE THIEUTH YE PIEUPSIOS + 0xB76D: 0xD197, //HANGUL SYLLABLE THIEUTH YE SIOS + 0xB76E: 0xD198, //HANGUL SYLLABLE THIEUTH YE SSANGSIOS + 0xB76F: 0xD199, //HANGUL SYLLABLE THIEUTH YE IEUNG + 0xB770: 0xD19A, //HANGUL SYLLABLE THIEUTH YE CIEUC + 0xB771: 0xD19B, //HANGUL SYLLABLE THIEUTH YE CHIEUCH + 0xB772: 0xD19C, //HANGUL SYLLABLE THIEUTH YE KHIEUKH + 0xB773: 0xD19D, //HANGUL SYLLABLE THIEUTH YE THIEUTH + 0xB774: 0xD19E, //HANGUL SYLLABLE THIEUTH YE PHIEUPH + 0xB775: 0xD19F, //HANGUL SYLLABLE THIEUTH YE HIEUH + 0xB776: 0xD1A2, //HANGUL SYLLABLE THIEUTH O SSANGKIYEOK + 0xB777: 0xD1A3, //HANGUL SYLLABLE THIEUTH O KIYEOKSIOS + 0xB778: 0xD1A5, //HANGUL SYLLABLE THIEUTH O NIEUNCIEUC + 0xB779: 0xD1A6, //HANGUL SYLLABLE THIEUTH O NIEUNHIEUH + 0xB77A: 0xD1A7, //HANGUL SYLLABLE THIEUTH O TIKEUT + 0xB781: 0xD1A9, //HANGUL SYLLABLE THIEUTH O RIEULKIYEOK + 0xB782: 0xD1AA, //HANGUL SYLLABLE THIEUTH O RIEULMIEUM + 0xB783: 0xD1AB, //HANGUL SYLLABLE THIEUTH O RIEULPIEUP + 0xB784: 0xD1AC, //HANGUL SYLLABLE THIEUTH O RIEULSIOS + 0xB785: 0xD1AD, //HANGUL SYLLABLE THIEUTH O RIEULTHIEUTH + 0xB786: 0xD1AE, //HANGUL SYLLABLE THIEUTH O RIEULPHIEUPH + 0xB787: 0xD1AF, //HANGUL SYLLABLE THIEUTH O RIEULHIEUH + 0xB788: 0xD1B2, //HANGUL SYLLABLE THIEUTH O PIEUPSIOS + 0xB789: 0xD1B4, //HANGUL SYLLABLE THIEUTH O SSANGSIOS + 0xB78A: 0xD1B6, //HANGUL SYLLABLE THIEUTH O CIEUC + 0xB78B: 0xD1B7, //HANGUL SYLLABLE THIEUTH O CHIEUCH + 0xB78C: 0xD1B8, //HANGUL SYLLABLE THIEUTH O KHIEUKH + 0xB78D: 0xD1B9, //HANGUL SYLLABLE THIEUTH O THIEUTH + 0xB78E: 0xD1BB, //HANGUL SYLLABLE THIEUTH O HIEUH + 0xB78F: 0xD1BD, //HANGUL SYLLABLE THIEUTH WA KIYEOK + 0xB790: 0xD1BE, //HANGUL SYLLABLE THIEUTH WA SSANGKIYEOK + 0xB791: 0xD1BF, //HANGUL SYLLABLE THIEUTH WA KIYEOKSIOS + 0xB792: 0xD1C1, //HANGUL SYLLABLE THIEUTH WA NIEUNCIEUC + 0xB793: 0xD1C2, //HANGUL SYLLABLE THIEUTH WA NIEUNHIEUH + 0xB794: 0xD1C3, //HANGUL SYLLABLE THIEUTH WA TIKEUT + 0xB795: 0xD1C4, //HANGUL SYLLABLE THIEUTH WA RIEUL + 0xB796: 0xD1C5, //HANGUL SYLLABLE THIEUTH WA RIEULKIYEOK + 0xB797: 0xD1C6, //HANGUL SYLLABLE THIEUTH WA RIEULMIEUM + 0xB798: 0xD1C7, //HANGUL SYLLABLE THIEUTH WA RIEULPIEUP + 0xB799: 0xD1C8, //HANGUL SYLLABLE THIEUTH WA RIEULSIOS + 0xB79A: 0xD1C9, //HANGUL SYLLABLE THIEUTH WA RIEULTHIEUTH + 0xB79B: 0xD1CA, //HANGUL SYLLABLE THIEUTH WA RIEULPHIEUPH + 0xB79C: 0xD1CB, //HANGUL SYLLABLE THIEUTH WA RIEULHIEUH + 0xB79D: 0xD1CC, //HANGUL SYLLABLE THIEUTH WA MIEUM + 0xB79E: 0xD1CD, //HANGUL SYLLABLE THIEUTH WA PIEUP + 0xB79F: 0xD1CE, //HANGUL SYLLABLE THIEUTH WA PIEUPSIOS + 0xB7A0: 0xD1CF, //HANGUL SYLLABLE THIEUTH WA SIOS + 0xB7A1: 0xB798, //HANGUL SYLLABLE RIEUL AE + 0xB7A2: 0xB799, //HANGUL SYLLABLE RIEUL AE KIYEOK + 0xB7A3: 0xB79C, //HANGUL SYLLABLE RIEUL AE NIEUN + 0xB7A4: 0xB7A0, //HANGUL SYLLABLE RIEUL AE RIEUL + 0xB7A5: 0xB7A8, //HANGUL SYLLABLE RIEUL AE MIEUM + 0xB7A6: 0xB7A9, //HANGUL SYLLABLE RIEUL AE PIEUP + 0xB7A7: 0xB7AB, //HANGUL SYLLABLE RIEUL AE SIOS + 0xB7A8: 0xB7AC, //HANGUL SYLLABLE RIEUL AE SSANGSIOS + 0xB7A9: 0xB7AD, //HANGUL SYLLABLE RIEUL AE IEUNG + 0xB7AA: 0xB7B4, //HANGUL SYLLABLE RIEUL YA + 0xB7AB: 0xB7B5, //HANGUL SYLLABLE RIEUL YA KIYEOK + 0xB7AC: 0xB7B8, //HANGUL SYLLABLE RIEUL YA NIEUN + 0xB7AD: 0xB7C7, //HANGUL SYLLABLE RIEUL YA SIOS + 0xB7AE: 0xB7C9, //HANGUL SYLLABLE RIEUL YA IEUNG + 0xB7AF: 0xB7EC, //HANGUL SYLLABLE RIEUL EO + 0xB7B0: 0xB7ED, //HANGUL SYLLABLE RIEUL EO KIYEOK + 0xB7B1: 0xB7F0, //HANGUL SYLLABLE RIEUL EO NIEUN + 0xB7B2: 0xB7F4, //HANGUL SYLLABLE RIEUL EO RIEUL + 0xB7B3: 0xB7FC, //HANGUL SYLLABLE RIEUL EO MIEUM + 0xB7B4: 0xB7FD, //HANGUL SYLLABLE RIEUL EO PIEUP + 0xB7B5: 0xB7FF, //HANGUL SYLLABLE RIEUL EO SIOS + 0xB7B6: 0xB800, //HANGUL SYLLABLE RIEUL EO SSANGSIOS + 0xB7B7: 0xB801, //HANGUL SYLLABLE RIEUL EO IEUNG + 0xB7B8: 0xB807, //HANGUL SYLLABLE RIEUL EO HIEUH + 0xB7B9: 0xB808, //HANGUL SYLLABLE RIEUL E + 0xB7BA: 0xB809, //HANGUL SYLLABLE RIEUL E KIYEOK + 0xB7BB: 0xB80C, //HANGUL SYLLABLE RIEUL E NIEUN + 0xB7BC: 0xB810, //HANGUL SYLLABLE RIEUL E RIEUL + 0xB7BD: 0xB818, //HANGUL SYLLABLE RIEUL E MIEUM + 0xB7BE: 0xB819, //HANGUL SYLLABLE RIEUL E PIEUP + 0xB7BF: 0xB81B, //HANGUL SYLLABLE RIEUL E SIOS + 0xB7C0: 0xB81D, //HANGUL SYLLABLE RIEUL E IEUNG + 0xB7C1: 0xB824, //HANGUL SYLLABLE RIEUL YEO + 0xB7C2: 0xB825, //HANGUL SYLLABLE RIEUL YEO KIYEOK + 0xB7C3: 0xB828, //HANGUL SYLLABLE RIEUL YEO NIEUN + 0xB7C4: 0xB82C, //HANGUL SYLLABLE RIEUL YEO RIEUL + 0xB7C5: 0xB834, //HANGUL SYLLABLE RIEUL YEO MIEUM + 0xB7C6: 0xB835, //HANGUL SYLLABLE RIEUL YEO PIEUP + 0xB7C7: 0xB837, //HANGUL SYLLABLE RIEUL YEO SIOS + 0xB7C8: 0xB838, //HANGUL SYLLABLE RIEUL YEO SSANGSIOS + 0xB7C9: 0xB839, //HANGUL SYLLABLE RIEUL YEO IEUNG + 0xB7CA: 0xB840, //HANGUL SYLLABLE RIEUL YE + 0xB7CB: 0xB844, //HANGUL SYLLABLE RIEUL YE NIEUN + 0xB7CC: 0xB851, //HANGUL SYLLABLE RIEUL YE PIEUP + 0xB7CD: 0xB853, //HANGUL SYLLABLE RIEUL YE SIOS + 0xB7CE: 0xB85C, //HANGUL SYLLABLE RIEUL O + 0xB7CF: 0xB85D, //HANGUL SYLLABLE RIEUL O KIYEOK + 0xB7D0: 0xB860, //HANGUL SYLLABLE RIEUL O NIEUN + 0xB7D1: 0xB864, //HANGUL SYLLABLE RIEUL O RIEUL + 0xB7D2: 0xB86C, //HANGUL SYLLABLE RIEUL O MIEUM + 0xB7D3: 0xB86D, //HANGUL SYLLABLE RIEUL O PIEUP + 0xB7D4: 0xB86F, //HANGUL SYLLABLE RIEUL O SIOS + 0xB7D5: 0xB871, //HANGUL SYLLABLE RIEUL O IEUNG + 0xB7D6: 0xB878, //HANGUL SYLLABLE RIEUL WA + 0xB7D7: 0xB87C, //HANGUL SYLLABLE RIEUL WA NIEUN + 0xB7D8: 0xB88D, //HANGUL SYLLABLE RIEUL WA IEUNG + 0xB7D9: 0xB8A8, //HANGUL SYLLABLE RIEUL WAE SSANGSIOS + 0xB7DA: 0xB8B0, //HANGUL SYLLABLE RIEUL OE + 0xB7DB: 0xB8B4, //HANGUL SYLLABLE RIEUL OE NIEUN + 0xB7DC: 0xB8B8, //HANGUL SYLLABLE RIEUL OE RIEUL + 0xB7DD: 0xB8C0, //HANGUL SYLLABLE RIEUL OE MIEUM + 0xB7DE: 0xB8C1, //HANGUL SYLLABLE RIEUL OE PIEUP + 0xB7DF: 0xB8C3, //HANGUL SYLLABLE RIEUL OE SIOS + 0xB7E0: 0xB8C5, //HANGUL SYLLABLE RIEUL OE IEUNG + 0xB7E1: 0xB8CC, //HANGUL SYLLABLE RIEUL YO + 0xB7E2: 0xB8D0, //HANGUL SYLLABLE RIEUL YO NIEUN + 0xB7E3: 0xB8D4, //HANGUL SYLLABLE RIEUL YO RIEUL + 0xB7E4: 0xB8DD, //HANGUL SYLLABLE RIEUL YO PIEUP + 0xB7E5: 0xB8DF, //HANGUL SYLLABLE RIEUL YO SIOS + 0xB7E6: 0xB8E1, //HANGUL SYLLABLE RIEUL YO IEUNG + 0xB7E7: 0xB8E8, //HANGUL SYLLABLE RIEUL U + 0xB7E8: 0xB8E9, //HANGUL SYLLABLE RIEUL U KIYEOK + 0xB7E9: 0xB8EC, //HANGUL SYLLABLE RIEUL U NIEUN + 0xB7EA: 0xB8F0, //HANGUL SYLLABLE RIEUL U RIEUL + 0xB7EB: 0xB8F8, //HANGUL SYLLABLE RIEUL U MIEUM + 0xB7EC: 0xB8F9, //HANGUL SYLLABLE RIEUL U PIEUP + 0xB7ED: 0xB8FB, //HANGUL SYLLABLE RIEUL U SIOS + 0xB7EE: 0xB8FD, //HANGUL SYLLABLE RIEUL U IEUNG + 0xB7EF: 0xB904, //HANGUL SYLLABLE RIEUL WEO + 0xB7F0: 0xB918, //HANGUL SYLLABLE RIEUL WEO SSANGSIOS + 0xB7F1: 0xB920, //HANGUL SYLLABLE RIEUL WE + 0xB7F2: 0xB93C, //HANGUL SYLLABLE RIEUL WI + 0xB7F3: 0xB93D, //HANGUL SYLLABLE RIEUL WI KIYEOK + 0xB7F4: 0xB940, //HANGUL SYLLABLE RIEUL WI NIEUN + 0xB7F5: 0xB944, //HANGUL SYLLABLE RIEUL WI RIEUL + 0xB7F6: 0xB94C, //HANGUL SYLLABLE RIEUL WI MIEUM + 0xB7F7: 0xB94F, //HANGUL SYLLABLE RIEUL WI SIOS + 0xB7F8: 0xB951, //HANGUL SYLLABLE RIEUL WI IEUNG + 0xB7F9: 0xB958, //HANGUL SYLLABLE RIEUL YU + 0xB7FA: 0xB959, //HANGUL SYLLABLE RIEUL YU KIYEOK + 0xB7FB: 0xB95C, //HANGUL SYLLABLE RIEUL YU NIEUN + 0xB7FC: 0xB960, //HANGUL SYLLABLE RIEUL YU RIEUL + 0xB7FD: 0xB968, //HANGUL SYLLABLE RIEUL YU MIEUM + 0xB7FE: 0xB969, //HANGUL SYLLABLE RIEUL YU PIEUP + 0xB841: 0xD1D0, //HANGUL SYLLABLE THIEUTH WA SSANGSIOS + 0xB842: 0xD1D1, //HANGUL SYLLABLE THIEUTH WA IEUNG + 0xB843: 0xD1D2, //HANGUL SYLLABLE THIEUTH WA CIEUC + 0xB844: 0xD1D3, //HANGUL SYLLABLE THIEUTH WA CHIEUCH + 0xB845: 0xD1D4, //HANGUL SYLLABLE THIEUTH WA KHIEUKH + 0xB846: 0xD1D5, //HANGUL SYLLABLE THIEUTH WA THIEUTH + 0xB847: 0xD1D6, //HANGUL SYLLABLE THIEUTH WA PHIEUPH + 0xB848: 0xD1D7, //HANGUL SYLLABLE THIEUTH WA HIEUH + 0xB849: 0xD1D9, //HANGUL SYLLABLE THIEUTH WAE KIYEOK + 0xB84A: 0xD1DA, //HANGUL SYLLABLE THIEUTH WAE SSANGKIYEOK + 0xB84B: 0xD1DB, //HANGUL SYLLABLE THIEUTH WAE KIYEOKSIOS + 0xB84C: 0xD1DC, //HANGUL SYLLABLE THIEUTH WAE NIEUN + 0xB84D: 0xD1DD, //HANGUL SYLLABLE THIEUTH WAE NIEUNCIEUC + 0xB84E: 0xD1DE, //HANGUL SYLLABLE THIEUTH WAE NIEUNHIEUH + 0xB84F: 0xD1DF, //HANGUL SYLLABLE THIEUTH WAE TIKEUT + 0xB850: 0xD1E0, //HANGUL SYLLABLE THIEUTH WAE RIEUL + 0xB851: 0xD1E1, //HANGUL SYLLABLE THIEUTH WAE RIEULKIYEOK + 0xB852: 0xD1E2, //HANGUL SYLLABLE THIEUTH WAE RIEULMIEUM + 0xB853: 0xD1E3, //HANGUL SYLLABLE THIEUTH WAE RIEULPIEUP + 0xB854: 0xD1E4, //HANGUL SYLLABLE THIEUTH WAE RIEULSIOS + 0xB855: 0xD1E5, //HANGUL SYLLABLE THIEUTH WAE RIEULTHIEUTH + 0xB856: 0xD1E6, //HANGUL SYLLABLE THIEUTH WAE RIEULPHIEUPH + 0xB857: 0xD1E7, //HANGUL SYLLABLE THIEUTH WAE RIEULHIEUH + 0xB858: 0xD1E8, //HANGUL SYLLABLE THIEUTH WAE MIEUM + 0xB859: 0xD1E9, //HANGUL SYLLABLE THIEUTH WAE PIEUP + 0xB85A: 0xD1EA, //HANGUL SYLLABLE THIEUTH WAE PIEUPSIOS + 0xB861: 0xD1EB, //HANGUL SYLLABLE THIEUTH WAE SIOS + 0xB862: 0xD1EC, //HANGUL SYLLABLE THIEUTH WAE SSANGSIOS + 0xB863: 0xD1ED, //HANGUL SYLLABLE THIEUTH WAE IEUNG + 0xB864: 0xD1EE, //HANGUL SYLLABLE THIEUTH WAE CIEUC + 0xB865: 0xD1EF, //HANGUL SYLLABLE THIEUTH WAE CHIEUCH + 0xB866: 0xD1F0, //HANGUL SYLLABLE THIEUTH WAE KHIEUKH + 0xB867: 0xD1F1, //HANGUL SYLLABLE THIEUTH WAE THIEUTH + 0xB868: 0xD1F2, //HANGUL SYLLABLE THIEUTH WAE PHIEUPH + 0xB869: 0xD1F3, //HANGUL SYLLABLE THIEUTH WAE HIEUH + 0xB86A: 0xD1F5, //HANGUL SYLLABLE THIEUTH OE KIYEOK + 0xB86B: 0xD1F6, //HANGUL SYLLABLE THIEUTH OE SSANGKIYEOK + 0xB86C: 0xD1F7, //HANGUL SYLLABLE THIEUTH OE KIYEOKSIOS + 0xB86D: 0xD1F9, //HANGUL SYLLABLE THIEUTH OE NIEUNCIEUC + 0xB86E: 0xD1FA, //HANGUL SYLLABLE THIEUTH OE NIEUNHIEUH + 0xB86F: 0xD1FB, //HANGUL SYLLABLE THIEUTH OE TIKEUT + 0xB870: 0xD1FC, //HANGUL SYLLABLE THIEUTH OE RIEUL + 0xB871: 0xD1FD, //HANGUL SYLLABLE THIEUTH OE RIEULKIYEOK + 0xB872: 0xD1FE, //HANGUL SYLLABLE THIEUTH OE RIEULMIEUM + 0xB873: 0xD1FF, //HANGUL SYLLABLE THIEUTH OE RIEULPIEUP + 0xB874: 0xD200, //HANGUL SYLLABLE THIEUTH OE RIEULSIOS + 0xB875: 0xD201, //HANGUL SYLLABLE THIEUTH OE RIEULTHIEUTH + 0xB876: 0xD202, //HANGUL SYLLABLE THIEUTH OE RIEULPHIEUPH + 0xB877: 0xD203, //HANGUL SYLLABLE THIEUTH OE RIEULHIEUH + 0xB878: 0xD204, //HANGUL SYLLABLE THIEUTH OE MIEUM + 0xB879: 0xD205, //HANGUL SYLLABLE THIEUTH OE PIEUP + 0xB87A: 0xD206, //HANGUL SYLLABLE THIEUTH OE PIEUPSIOS + 0xB881: 0xD208, //HANGUL SYLLABLE THIEUTH OE SSANGSIOS + 0xB882: 0xD20A, //HANGUL SYLLABLE THIEUTH OE CIEUC + 0xB883: 0xD20B, //HANGUL SYLLABLE THIEUTH OE CHIEUCH + 0xB884: 0xD20C, //HANGUL SYLLABLE THIEUTH OE KHIEUKH + 0xB885: 0xD20D, //HANGUL SYLLABLE THIEUTH OE THIEUTH + 0xB886: 0xD20E, //HANGUL SYLLABLE THIEUTH OE PHIEUPH + 0xB887: 0xD20F, //HANGUL SYLLABLE THIEUTH OE HIEUH + 0xB888: 0xD211, //HANGUL SYLLABLE THIEUTH YO KIYEOK + 0xB889: 0xD212, //HANGUL SYLLABLE THIEUTH YO SSANGKIYEOK + 0xB88A: 0xD213, //HANGUL SYLLABLE THIEUTH YO KIYEOKSIOS + 0xB88B: 0xD214, //HANGUL SYLLABLE THIEUTH YO NIEUN + 0xB88C: 0xD215, //HANGUL SYLLABLE THIEUTH YO NIEUNCIEUC + 0xB88D: 0xD216, //HANGUL SYLLABLE THIEUTH YO NIEUNHIEUH + 0xB88E: 0xD217, //HANGUL SYLLABLE THIEUTH YO TIKEUT + 0xB88F: 0xD218, //HANGUL SYLLABLE THIEUTH YO RIEUL + 0xB890: 0xD219, //HANGUL SYLLABLE THIEUTH YO RIEULKIYEOK + 0xB891: 0xD21A, //HANGUL SYLLABLE THIEUTH YO RIEULMIEUM + 0xB892: 0xD21B, //HANGUL SYLLABLE THIEUTH YO RIEULPIEUP + 0xB893: 0xD21C, //HANGUL SYLLABLE THIEUTH YO RIEULSIOS + 0xB894: 0xD21D, //HANGUL SYLLABLE THIEUTH YO RIEULTHIEUTH + 0xB895: 0xD21E, //HANGUL SYLLABLE THIEUTH YO RIEULPHIEUPH + 0xB896: 0xD21F, //HANGUL SYLLABLE THIEUTH YO RIEULHIEUH + 0xB897: 0xD220, //HANGUL SYLLABLE THIEUTH YO MIEUM + 0xB898: 0xD221, //HANGUL SYLLABLE THIEUTH YO PIEUP + 0xB899: 0xD222, //HANGUL SYLLABLE THIEUTH YO PIEUPSIOS + 0xB89A: 0xD223, //HANGUL SYLLABLE THIEUTH YO SIOS + 0xB89B: 0xD224, //HANGUL SYLLABLE THIEUTH YO SSANGSIOS + 0xB89C: 0xD225, //HANGUL SYLLABLE THIEUTH YO IEUNG + 0xB89D: 0xD226, //HANGUL SYLLABLE THIEUTH YO CIEUC + 0xB89E: 0xD227, //HANGUL SYLLABLE THIEUTH YO CHIEUCH + 0xB89F: 0xD228, //HANGUL SYLLABLE THIEUTH YO KHIEUKH + 0xB8A0: 0xD229, //HANGUL SYLLABLE THIEUTH YO THIEUTH + 0xB8A1: 0xB96B, //HANGUL SYLLABLE RIEUL YU SIOS + 0xB8A2: 0xB96D, //HANGUL SYLLABLE RIEUL YU IEUNG + 0xB8A3: 0xB974, //HANGUL SYLLABLE RIEUL EU + 0xB8A4: 0xB975, //HANGUL SYLLABLE RIEUL EU KIYEOK + 0xB8A5: 0xB978, //HANGUL SYLLABLE RIEUL EU NIEUN + 0xB8A6: 0xB97C, //HANGUL SYLLABLE RIEUL EU RIEUL + 0xB8A7: 0xB984, //HANGUL SYLLABLE RIEUL EU MIEUM + 0xB8A8: 0xB985, //HANGUL SYLLABLE RIEUL EU PIEUP + 0xB8A9: 0xB987, //HANGUL SYLLABLE RIEUL EU SIOS + 0xB8AA: 0xB989, //HANGUL SYLLABLE RIEUL EU IEUNG + 0xB8AB: 0xB98A, //HANGUL SYLLABLE RIEUL EU CIEUC + 0xB8AC: 0xB98D, //HANGUL SYLLABLE RIEUL EU THIEUTH + 0xB8AD: 0xB98E, //HANGUL SYLLABLE RIEUL EU PHIEUPH + 0xB8AE: 0xB9AC, //HANGUL SYLLABLE RIEUL I + 0xB8AF: 0xB9AD, //HANGUL SYLLABLE RIEUL I KIYEOK + 0xB8B0: 0xB9B0, //HANGUL SYLLABLE RIEUL I NIEUN + 0xB8B1: 0xB9B4, //HANGUL SYLLABLE RIEUL I RIEUL + 0xB8B2: 0xB9BC, //HANGUL SYLLABLE RIEUL I MIEUM + 0xB8B3: 0xB9BD, //HANGUL SYLLABLE RIEUL I PIEUP + 0xB8B4: 0xB9BF, //HANGUL SYLLABLE RIEUL I SIOS + 0xB8B5: 0xB9C1, //HANGUL SYLLABLE RIEUL I IEUNG + 0xB8B6: 0xB9C8, //HANGUL SYLLABLE MIEUM A + 0xB8B7: 0xB9C9, //HANGUL SYLLABLE MIEUM A KIYEOK + 0xB8B8: 0xB9CC, //HANGUL SYLLABLE MIEUM A NIEUN + 0xB8B9: 0xB9CE, //HANGUL SYLLABLE MIEUM A NIEUNHIEUH + 0xB8BA: 0xB9CF, //HANGUL SYLLABLE MIEUM A TIKEUT + 0xB8BB: 0xB9D0, //HANGUL SYLLABLE MIEUM A RIEUL + 0xB8BC: 0xB9D1, //HANGUL SYLLABLE MIEUM A RIEULKIYEOK + 0xB8BD: 0xB9D2, //HANGUL SYLLABLE MIEUM A RIEULMIEUM + 0xB8BE: 0xB9D8, //HANGUL SYLLABLE MIEUM A MIEUM + 0xB8BF: 0xB9D9, //HANGUL SYLLABLE MIEUM A PIEUP + 0xB8C0: 0xB9DB, //HANGUL SYLLABLE MIEUM A SIOS + 0xB8C1: 0xB9DD, //HANGUL SYLLABLE MIEUM A IEUNG + 0xB8C2: 0xB9DE, //HANGUL SYLLABLE MIEUM A CIEUC + 0xB8C3: 0xB9E1, //HANGUL SYLLABLE MIEUM A THIEUTH + 0xB8C4: 0xB9E3, //HANGUL SYLLABLE MIEUM A HIEUH + 0xB8C5: 0xB9E4, //HANGUL SYLLABLE MIEUM AE + 0xB8C6: 0xB9E5, //HANGUL SYLLABLE MIEUM AE KIYEOK + 0xB8C7: 0xB9E8, //HANGUL SYLLABLE MIEUM AE NIEUN + 0xB8C8: 0xB9EC, //HANGUL SYLLABLE MIEUM AE RIEUL + 0xB8C9: 0xB9F4, //HANGUL SYLLABLE MIEUM AE MIEUM + 0xB8CA: 0xB9F5, //HANGUL SYLLABLE MIEUM AE PIEUP + 0xB8CB: 0xB9F7, //HANGUL SYLLABLE MIEUM AE SIOS + 0xB8CC: 0xB9F8, //HANGUL SYLLABLE MIEUM AE SSANGSIOS + 0xB8CD: 0xB9F9, //HANGUL SYLLABLE MIEUM AE IEUNG + 0xB8CE: 0xB9FA, //HANGUL SYLLABLE MIEUM AE CIEUC + 0xB8CF: 0xBA00, //HANGUL SYLLABLE MIEUM YA + 0xB8D0: 0xBA01, //HANGUL SYLLABLE MIEUM YA KIYEOK + 0xB8D1: 0xBA08, //HANGUL SYLLABLE MIEUM YA RIEUL + 0xB8D2: 0xBA15, //HANGUL SYLLABLE MIEUM YA IEUNG + 0xB8D3: 0xBA38, //HANGUL SYLLABLE MIEUM EO + 0xB8D4: 0xBA39, //HANGUL SYLLABLE MIEUM EO KIYEOK + 0xB8D5: 0xBA3C, //HANGUL SYLLABLE MIEUM EO NIEUN + 0xB8D6: 0xBA40, //HANGUL SYLLABLE MIEUM EO RIEUL + 0xB8D7: 0xBA42, //HANGUL SYLLABLE MIEUM EO RIEULMIEUM + 0xB8D8: 0xBA48, //HANGUL SYLLABLE MIEUM EO MIEUM + 0xB8D9: 0xBA49, //HANGUL SYLLABLE MIEUM EO PIEUP + 0xB8DA: 0xBA4B, //HANGUL SYLLABLE MIEUM EO SIOS + 0xB8DB: 0xBA4D, //HANGUL SYLLABLE MIEUM EO IEUNG + 0xB8DC: 0xBA4E, //HANGUL SYLLABLE MIEUM EO CIEUC + 0xB8DD: 0xBA53, //HANGUL SYLLABLE MIEUM EO HIEUH + 0xB8DE: 0xBA54, //HANGUL SYLLABLE MIEUM E + 0xB8DF: 0xBA55, //HANGUL SYLLABLE MIEUM E KIYEOK + 0xB8E0: 0xBA58, //HANGUL SYLLABLE MIEUM E NIEUN + 0xB8E1: 0xBA5C, //HANGUL SYLLABLE MIEUM E RIEUL + 0xB8E2: 0xBA64, //HANGUL SYLLABLE MIEUM E MIEUM + 0xB8E3: 0xBA65, //HANGUL SYLLABLE MIEUM E PIEUP + 0xB8E4: 0xBA67, //HANGUL SYLLABLE MIEUM E SIOS + 0xB8E5: 0xBA68, //HANGUL SYLLABLE MIEUM E SSANGSIOS + 0xB8E6: 0xBA69, //HANGUL SYLLABLE MIEUM E IEUNG + 0xB8E7: 0xBA70, //HANGUL SYLLABLE MIEUM YEO + 0xB8E8: 0xBA71, //HANGUL SYLLABLE MIEUM YEO KIYEOK + 0xB8E9: 0xBA74, //HANGUL SYLLABLE MIEUM YEO NIEUN + 0xB8EA: 0xBA78, //HANGUL SYLLABLE MIEUM YEO RIEUL + 0xB8EB: 0xBA83, //HANGUL SYLLABLE MIEUM YEO SIOS + 0xB8EC: 0xBA84, //HANGUL SYLLABLE MIEUM YEO SSANGSIOS + 0xB8ED: 0xBA85, //HANGUL SYLLABLE MIEUM YEO IEUNG + 0xB8EE: 0xBA87, //HANGUL SYLLABLE MIEUM YEO CHIEUCH + 0xB8EF: 0xBA8C, //HANGUL SYLLABLE MIEUM YE + 0xB8F0: 0xBAA8, //HANGUL SYLLABLE MIEUM O + 0xB8F1: 0xBAA9, //HANGUL SYLLABLE MIEUM O KIYEOK + 0xB8F2: 0xBAAB, //HANGUL SYLLABLE MIEUM O KIYEOKSIOS + 0xB8F3: 0xBAAC, //HANGUL SYLLABLE MIEUM O NIEUN + 0xB8F4: 0xBAB0, //HANGUL SYLLABLE MIEUM O RIEUL + 0xB8F5: 0xBAB2, //HANGUL SYLLABLE MIEUM O RIEULMIEUM + 0xB8F6: 0xBAB8, //HANGUL SYLLABLE MIEUM O MIEUM + 0xB8F7: 0xBAB9, //HANGUL SYLLABLE MIEUM O PIEUP + 0xB8F8: 0xBABB, //HANGUL SYLLABLE MIEUM O SIOS + 0xB8F9: 0xBABD, //HANGUL SYLLABLE MIEUM O IEUNG + 0xB8FA: 0xBAC4, //HANGUL SYLLABLE MIEUM WA + 0xB8FB: 0xBAC8, //HANGUL SYLLABLE MIEUM WA NIEUN + 0xB8FC: 0xBAD8, //HANGUL SYLLABLE MIEUM WA SSANGSIOS + 0xB8FD: 0xBAD9, //HANGUL SYLLABLE MIEUM WA IEUNG + 0xB8FE: 0xBAFC, //HANGUL SYLLABLE MIEUM OE + 0xB941: 0xD22A, //HANGUL SYLLABLE THIEUTH YO PHIEUPH + 0xB942: 0xD22B, //HANGUL SYLLABLE THIEUTH YO HIEUH + 0xB943: 0xD22E, //HANGUL SYLLABLE THIEUTH U SSANGKIYEOK + 0xB944: 0xD22F, //HANGUL SYLLABLE THIEUTH U KIYEOKSIOS + 0xB945: 0xD231, //HANGUL SYLLABLE THIEUTH U NIEUNCIEUC + 0xB946: 0xD232, //HANGUL SYLLABLE THIEUTH U NIEUNHIEUH + 0xB947: 0xD233, //HANGUL SYLLABLE THIEUTH U TIKEUT + 0xB948: 0xD235, //HANGUL SYLLABLE THIEUTH U RIEULKIYEOK + 0xB949: 0xD236, //HANGUL SYLLABLE THIEUTH U RIEULMIEUM + 0xB94A: 0xD237, //HANGUL SYLLABLE THIEUTH U RIEULPIEUP + 0xB94B: 0xD238, //HANGUL SYLLABLE THIEUTH U RIEULSIOS + 0xB94C: 0xD239, //HANGUL SYLLABLE THIEUTH U RIEULTHIEUTH + 0xB94D: 0xD23A, //HANGUL SYLLABLE THIEUTH U RIEULPHIEUPH + 0xB94E: 0xD23B, //HANGUL SYLLABLE THIEUTH U RIEULHIEUH + 0xB94F: 0xD23E, //HANGUL SYLLABLE THIEUTH U PIEUPSIOS + 0xB950: 0xD240, //HANGUL SYLLABLE THIEUTH U SSANGSIOS + 0xB951: 0xD242, //HANGUL SYLLABLE THIEUTH U CIEUC + 0xB952: 0xD243, //HANGUL SYLLABLE THIEUTH U CHIEUCH + 0xB953: 0xD244, //HANGUL SYLLABLE THIEUTH U KHIEUKH + 0xB954: 0xD245, //HANGUL SYLLABLE THIEUTH U THIEUTH + 0xB955: 0xD246, //HANGUL SYLLABLE THIEUTH U PHIEUPH + 0xB956: 0xD247, //HANGUL SYLLABLE THIEUTH U HIEUH + 0xB957: 0xD249, //HANGUL SYLLABLE THIEUTH WEO KIYEOK + 0xB958: 0xD24A, //HANGUL SYLLABLE THIEUTH WEO SSANGKIYEOK + 0xB959: 0xD24B, //HANGUL SYLLABLE THIEUTH WEO KIYEOKSIOS + 0xB95A: 0xD24C, //HANGUL SYLLABLE THIEUTH WEO NIEUN + 0xB961: 0xD24D, //HANGUL SYLLABLE THIEUTH WEO NIEUNCIEUC + 0xB962: 0xD24E, //HANGUL SYLLABLE THIEUTH WEO NIEUNHIEUH + 0xB963: 0xD24F, //HANGUL SYLLABLE THIEUTH WEO TIKEUT + 0xB964: 0xD250, //HANGUL SYLLABLE THIEUTH WEO RIEUL + 0xB965: 0xD251, //HANGUL SYLLABLE THIEUTH WEO RIEULKIYEOK + 0xB966: 0xD252, //HANGUL SYLLABLE THIEUTH WEO RIEULMIEUM + 0xB967: 0xD253, //HANGUL SYLLABLE THIEUTH WEO RIEULPIEUP + 0xB968: 0xD254, //HANGUL SYLLABLE THIEUTH WEO RIEULSIOS + 0xB969: 0xD255, //HANGUL SYLLABLE THIEUTH WEO RIEULTHIEUTH + 0xB96A: 0xD256, //HANGUL SYLLABLE THIEUTH WEO RIEULPHIEUPH + 0xB96B: 0xD257, //HANGUL SYLLABLE THIEUTH WEO RIEULHIEUH + 0xB96C: 0xD258, //HANGUL SYLLABLE THIEUTH WEO MIEUM + 0xB96D: 0xD259, //HANGUL SYLLABLE THIEUTH WEO PIEUP + 0xB96E: 0xD25A, //HANGUL SYLLABLE THIEUTH WEO PIEUPSIOS + 0xB96F: 0xD25B, //HANGUL SYLLABLE THIEUTH WEO SIOS + 0xB970: 0xD25D, //HANGUL SYLLABLE THIEUTH WEO IEUNG + 0xB971: 0xD25E, //HANGUL SYLLABLE THIEUTH WEO CIEUC + 0xB972: 0xD25F, //HANGUL SYLLABLE THIEUTH WEO CHIEUCH + 0xB973: 0xD260, //HANGUL SYLLABLE THIEUTH WEO KHIEUKH + 0xB974: 0xD261, //HANGUL SYLLABLE THIEUTH WEO THIEUTH + 0xB975: 0xD262, //HANGUL SYLLABLE THIEUTH WEO PHIEUPH + 0xB976: 0xD263, //HANGUL SYLLABLE THIEUTH WEO HIEUH + 0xB977: 0xD265, //HANGUL SYLLABLE THIEUTH WE KIYEOK + 0xB978: 0xD266, //HANGUL SYLLABLE THIEUTH WE SSANGKIYEOK + 0xB979: 0xD267, //HANGUL SYLLABLE THIEUTH WE KIYEOKSIOS + 0xB97A: 0xD268, //HANGUL SYLLABLE THIEUTH WE NIEUN + 0xB981: 0xD269, //HANGUL SYLLABLE THIEUTH WE NIEUNCIEUC + 0xB982: 0xD26A, //HANGUL SYLLABLE THIEUTH WE NIEUNHIEUH + 0xB983: 0xD26B, //HANGUL SYLLABLE THIEUTH WE TIKEUT + 0xB984: 0xD26C, //HANGUL SYLLABLE THIEUTH WE RIEUL + 0xB985: 0xD26D, //HANGUL SYLLABLE THIEUTH WE RIEULKIYEOK + 0xB986: 0xD26E, //HANGUL SYLLABLE THIEUTH WE RIEULMIEUM + 0xB987: 0xD26F, //HANGUL SYLLABLE THIEUTH WE RIEULPIEUP + 0xB988: 0xD270, //HANGUL SYLLABLE THIEUTH WE RIEULSIOS + 0xB989: 0xD271, //HANGUL SYLLABLE THIEUTH WE RIEULTHIEUTH + 0xB98A: 0xD272, //HANGUL SYLLABLE THIEUTH WE RIEULPHIEUPH + 0xB98B: 0xD273, //HANGUL SYLLABLE THIEUTH WE RIEULHIEUH + 0xB98C: 0xD274, //HANGUL SYLLABLE THIEUTH WE MIEUM + 0xB98D: 0xD275, //HANGUL SYLLABLE THIEUTH WE PIEUP + 0xB98E: 0xD276, //HANGUL SYLLABLE THIEUTH WE PIEUPSIOS + 0xB98F: 0xD277, //HANGUL SYLLABLE THIEUTH WE SIOS + 0xB990: 0xD278, //HANGUL SYLLABLE THIEUTH WE SSANGSIOS + 0xB991: 0xD279, //HANGUL SYLLABLE THIEUTH WE IEUNG + 0xB992: 0xD27A, //HANGUL SYLLABLE THIEUTH WE CIEUC + 0xB993: 0xD27B, //HANGUL SYLLABLE THIEUTH WE CHIEUCH + 0xB994: 0xD27C, //HANGUL SYLLABLE THIEUTH WE KHIEUKH + 0xB995: 0xD27D, //HANGUL SYLLABLE THIEUTH WE THIEUTH + 0xB996: 0xD27E, //HANGUL SYLLABLE THIEUTH WE PHIEUPH + 0xB997: 0xD27F, //HANGUL SYLLABLE THIEUTH WE HIEUH + 0xB998: 0xD282, //HANGUL SYLLABLE THIEUTH WI SSANGKIYEOK + 0xB999: 0xD283, //HANGUL SYLLABLE THIEUTH WI KIYEOKSIOS + 0xB99A: 0xD285, //HANGUL SYLLABLE THIEUTH WI NIEUNCIEUC + 0xB99B: 0xD286, //HANGUL SYLLABLE THIEUTH WI NIEUNHIEUH + 0xB99C: 0xD287, //HANGUL SYLLABLE THIEUTH WI TIKEUT + 0xB99D: 0xD289, //HANGUL SYLLABLE THIEUTH WI RIEULKIYEOK + 0xB99E: 0xD28A, //HANGUL SYLLABLE THIEUTH WI RIEULMIEUM + 0xB99F: 0xD28B, //HANGUL SYLLABLE THIEUTH WI RIEULPIEUP + 0xB9A0: 0xD28C, //HANGUL SYLLABLE THIEUTH WI RIEULSIOS + 0xB9A1: 0xBB00, //HANGUL SYLLABLE MIEUM OE NIEUN + 0xB9A2: 0xBB04, //HANGUL SYLLABLE MIEUM OE RIEUL + 0xB9A3: 0xBB0D, //HANGUL SYLLABLE MIEUM OE PIEUP + 0xB9A4: 0xBB0F, //HANGUL SYLLABLE MIEUM OE SIOS + 0xB9A5: 0xBB11, //HANGUL SYLLABLE MIEUM OE IEUNG + 0xB9A6: 0xBB18, //HANGUL SYLLABLE MIEUM YO + 0xB9A7: 0xBB1C, //HANGUL SYLLABLE MIEUM YO NIEUN + 0xB9A8: 0xBB20, //HANGUL SYLLABLE MIEUM YO RIEUL + 0xB9A9: 0xBB29, //HANGUL SYLLABLE MIEUM YO PIEUP + 0xB9AA: 0xBB2B, //HANGUL SYLLABLE MIEUM YO SIOS + 0xB9AB: 0xBB34, //HANGUL SYLLABLE MIEUM U + 0xB9AC: 0xBB35, //HANGUL SYLLABLE MIEUM U KIYEOK + 0xB9AD: 0xBB36, //HANGUL SYLLABLE MIEUM U SSANGKIYEOK + 0xB9AE: 0xBB38, //HANGUL SYLLABLE MIEUM U NIEUN + 0xB9AF: 0xBB3B, //HANGUL SYLLABLE MIEUM U TIKEUT + 0xB9B0: 0xBB3C, //HANGUL SYLLABLE MIEUM U RIEUL + 0xB9B1: 0xBB3D, //HANGUL SYLLABLE MIEUM U RIEULKIYEOK + 0xB9B2: 0xBB3E, //HANGUL SYLLABLE MIEUM U RIEULMIEUM + 0xB9B3: 0xBB44, //HANGUL SYLLABLE MIEUM U MIEUM + 0xB9B4: 0xBB45, //HANGUL SYLLABLE MIEUM U PIEUP + 0xB9B5: 0xBB47, //HANGUL SYLLABLE MIEUM U SIOS + 0xB9B6: 0xBB49, //HANGUL SYLLABLE MIEUM U IEUNG + 0xB9B7: 0xBB4D, //HANGUL SYLLABLE MIEUM U THIEUTH + 0xB9B8: 0xBB4F, //HANGUL SYLLABLE MIEUM U HIEUH + 0xB9B9: 0xBB50, //HANGUL SYLLABLE MIEUM WEO + 0xB9BA: 0xBB54, //HANGUL SYLLABLE MIEUM WEO NIEUN + 0xB9BB: 0xBB58, //HANGUL SYLLABLE MIEUM WEO RIEUL + 0xB9BC: 0xBB61, //HANGUL SYLLABLE MIEUM WEO PIEUP + 0xB9BD: 0xBB63, //HANGUL SYLLABLE MIEUM WEO SIOS + 0xB9BE: 0xBB6C, //HANGUL SYLLABLE MIEUM WE + 0xB9BF: 0xBB88, //HANGUL SYLLABLE MIEUM WI + 0xB9C0: 0xBB8C, //HANGUL SYLLABLE MIEUM WI NIEUN + 0xB9C1: 0xBB90, //HANGUL SYLLABLE MIEUM WI RIEUL + 0xB9C2: 0xBBA4, //HANGUL SYLLABLE MIEUM YU + 0xB9C3: 0xBBA8, //HANGUL SYLLABLE MIEUM YU NIEUN + 0xB9C4: 0xBBAC, //HANGUL SYLLABLE MIEUM YU RIEUL + 0xB9C5: 0xBBB4, //HANGUL SYLLABLE MIEUM YU MIEUM + 0xB9C6: 0xBBB7, //HANGUL SYLLABLE MIEUM YU SIOS + 0xB9C7: 0xBBC0, //HANGUL SYLLABLE MIEUM EU + 0xB9C8: 0xBBC4, //HANGUL SYLLABLE MIEUM EU NIEUN + 0xB9C9: 0xBBC8, //HANGUL SYLLABLE MIEUM EU RIEUL + 0xB9CA: 0xBBD0, //HANGUL SYLLABLE MIEUM EU MIEUM + 0xB9CB: 0xBBD3, //HANGUL SYLLABLE MIEUM EU SIOS + 0xB9CC: 0xBBF8, //HANGUL SYLLABLE MIEUM I + 0xB9CD: 0xBBF9, //HANGUL SYLLABLE MIEUM I KIYEOK + 0xB9CE: 0xBBFC, //HANGUL SYLLABLE MIEUM I NIEUN + 0xB9CF: 0xBBFF, //HANGUL SYLLABLE MIEUM I TIKEUT + 0xB9D0: 0xBC00, //HANGUL SYLLABLE MIEUM I RIEUL + 0xB9D1: 0xBC02, //HANGUL SYLLABLE MIEUM I RIEULMIEUM + 0xB9D2: 0xBC08, //HANGUL SYLLABLE MIEUM I MIEUM + 0xB9D3: 0xBC09, //HANGUL SYLLABLE MIEUM I PIEUP + 0xB9D4: 0xBC0B, //HANGUL SYLLABLE MIEUM I SIOS + 0xB9D5: 0xBC0C, //HANGUL SYLLABLE MIEUM I SSANGSIOS + 0xB9D6: 0xBC0D, //HANGUL SYLLABLE MIEUM I IEUNG + 0xB9D7: 0xBC0F, //HANGUL SYLLABLE MIEUM I CHIEUCH + 0xB9D8: 0xBC11, //HANGUL SYLLABLE MIEUM I THIEUTH + 0xB9D9: 0xBC14, //HANGUL SYLLABLE PIEUP A + 0xB9DA: 0xBC15, //HANGUL SYLLABLE PIEUP A KIYEOK + 0xB9DB: 0xBC16, //HANGUL SYLLABLE PIEUP A SSANGKIYEOK + 0xB9DC: 0xBC17, //HANGUL SYLLABLE PIEUP A KIYEOKSIOS + 0xB9DD: 0xBC18, //HANGUL SYLLABLE PIEUP A NIEUN + 0xB9DE: 0xBC1B, //HANGUL SYLLABLE PIEUP A TIKEUT + 0xB9DF: 0xBC1C, //HANGUL SYLLABLE PIEUP A RIEUL + 0xB9E0: 0xBC1D, //HANGUL SYLLABLE PIEUP A RIEULKIYEOK + 0xB9E1: 0xBC1E, //HANGUL SYLLABLE PIEUP A RIEULMIEUM + 0xB9E2: 0xBC1F, //HANGUL SYLLABLE PIEUP A RIEULPIEUP + 0xB9E3: 0xBC24, //HANGUL SYLLABLE PIEUP A MIEUM + 0xB9E4: 0xBC25, //HANGUL SYLLABLE PIEUP A PIEUP + 0xB9E5: 0xBC27, //HANGUL SYLLABLE PIEUP A SIOS + 0xB9E6: 0xBC29, //HANGUL SYLLABLE PIEUP A IEUNG + 0xB9E7: 0xBC2D, //HANGUL SYLLABLE PIEUP A THIEUTH + 0xB9E8: 0xBC30, //HANGUL SYLLABLE PIEUP AE + 0xB9E9: 0xBC31, //HANGUL SYLLABLE PIEUP AE KIYEOK + 0xB9EA: 0xBC34, //HANGUL SYLLABLE PIEUP AE NIEUN + 0xB9EB: 0xBC38, //HANGUL SYLLABLE PIEUP AE RIEUL + 0xB9EC: 0xBC40, //HANGUL SYLLABLE PIEUP AE MIEUM + 0xB9ED: 0xBC41, //HANGUL SYLLABLE PIEUP AE PIEUP + 0xB9EE: 0xBC43, //HANGUL SYLLABLE PIEUP AE SIOS + 0xB9EF: 0xBC44, //HANGUL SYLLABLE PIEUP AE SSANGSIOS + 0xB9F0: 0xBC45, //HANGUL SYLLABLE PIEUP AE IEUNG + 0xB9F1: 0xBC49, //HANGUL SYLLABLE PIEUP AE THIEUTH + 0xB9F2: 0xBC4C, //HANGUL SYLLABLE PIEUP YA + 0xB9F3: 0xBC4D, //HANGUL SYLLABLE PIEUP YA KIYEOK + 0xB9F4: 0xBC50, //HANGUL SYLLABLE PIEUP YA NIEUN + 0xB9F5: 0xBC5D, //HANGUL SYLLABLE PIEUP YA PIEUP + 0xB9F6: 0xBC84, //HANGUL SYLLABLE PIEUP EO + 0xB9F7: 0xBC85, //HANGUL SYLLABLE PIEUP EO KIYEOK + 0xB9F8: 0xBC88, //HANGUL SYLLABLE PIEUP EO NIEUN + 0xB9F9: 0xBC8B, //HANGUL SYLLABLE PIEUP EO TIKEUT + 0xB9FA: 0xBC8C, //HANGUL SYLLABLE PIEUP EO RIEUL + 0xB9FB: 0xBC8E, //HANGUL SYLLABLE PIEUP EO RIEULMIEUM + 0xB9FC: 0xBC94, //HANGUL SYLLABLE PIEUP EO MIEUM + 0xB9FD: 0xBC95, //HANGUL SYLLABLE PIEUP EO PIEUP + 0xB9FE: 0xBC97, //HANGUL SYLLABLE PIEUP EO SIOS + 0xBA41: 0xD28D, //HANGUL SYLLABLE THIEUTH WI RIEULTHIEUTH + 0xBA42: 0xD28E, //HANGUL SYLLABLE THIEUTH WI RIEULPHIEUPH + 0xBA43: 0xD28F, //HANGUL SYLLABLE THIEUTH WI RIEULHIEUH + 0xBA44: 0xD292, //HANGUL SYLLABLE THIEUTH WI PIEUPSIOS + 0xBA45: 0xD293, //HANGUL SYLLABLE THIEUTH WI SIOS + 0xBA46: 0xD294, //HANGUL SYLLABLE THIEUTH WI SSANGSIOS + 0xBA47: 0xD296, //HANGUL SYLLABLE THIEUTH WI CIEUC + 0xBA48: 0xD297, //HANGUL SYLLABLE THIEUTH WI CHIEUCH + 0xBA49: 0xD298, //HANGUL SYLLABLE THIEUTH WI KHIEUKH + 0xBA4A: 0xD299, //HANGUL SYLLABLE THIEUTH WI THIEUTH + 0xBA4B: 0xD29A, //HANGUL SYLLABLE THIEUTH WI PHIEUPH + 0xBA4C: 0xD29B, //HANGUL SYLLABLE THIEUTH WI HIEUH + 0xBA4D: 0xD29D, //HANGUL SYLLABLE THIEUTH YU KIYEOK + 0xBA4E: 0xD29E, //HANGUL SYLLABLE THIEUTH YU SSANGKIYEOK + 0xBA4F: 0xD29F, //HANGUL SYLLABLE THIEUTH YU KIYEOKSIOS + 0xBA50: 0xD2A1, //HANGUL SYLLABLE THIEUTH YU NIEUNCIEUC + 0xBA51: 0xD2A2, //HANGUL SYLLABLE THIEUTH YU NIEUNHIEUH + 0xBA52: 0xD2A3, //HANGUL SYLLABLE THIEUTH YU TIKEUT + 0xBA53: 0xD2A5, //HANGUL SYLLABLE THIEUTH YU RIEULKIYEOK + 0xBA54: 0xD2A6, //HANGUL SYLLABLE THIEUTH YU RIEULMIEUM + 0xBA55: 0xD2A7, //HANGUL SYLLABLE THIEUTH YU RIEULPIEUP + 0xBA56: 0xD2A8, //HANGUL SYLLABLE THIEUTH YU RIEULSIOS + 0xBA57: 0xD2A9, //HANGUL SYLLABLE THIEUTH YU RIEULTHIEUTH + 0xBA58: 0xD2AA, //HANGUL SYLLABLE THIEUTH YU RIEULPHIEUPH + 0xBA59: 0xD2AB, //HANGUL SYLLABLE THIEUTH YU RIEULHIEUH + 0xBA5A: 0xD2AD, //HANGUL SYLLABLE THIEUTH YU PIEUP + 0xBA61: 0xD2AE, //HANGUL SYLLABLE THIEUTH YU PIEUPSIOS + 0xBA62: 0xD2AF, //HANGUL SYLLABLE THIEUTH YU SIOS + 0xBA63: 0xD2B0, //HANGUL SYLLABLE THIEUTH YU SSANGSIOS + 0xBA64: 0xD2B2, //HANGUL SYLLABLE THIEUTH YU CIEUC + 0xBA65: 0xD2B3, //HANGUL SYLLABLE THIEUTH YU CHIEUCH + 0xBA66: 0xD2B4, //HANGUL SYLLABLE THIEUTH YU KHIEUKH + 0xBA67: 0xD2B5, //HANGUL SYLLABLE THIEUTH YU THIEUTH + 0xBA68: 0xD2B6, //HANGUL SYLLABLE THIEUTH YU PHIEUPH + 0xBA69: 0xD2B7, //HANGUL SYLLABLE THIEUTH YU HIEUH + 0xBA6A: 0xD2BA, //HANGUL SYLLABLE THIEUTH EU SSANGKIYEOK + 0xBA6B: 0xD2BB, //HANGUL SYLLABLE THIEUTH EU KIYEOKSIOS + 0xBA6C: 0xD2BD, //HANGUL SYLLABLE THIEUTH EU NIEUNCIEUC + 0xBA6D: 0xD2BE, //HANGUL SYLLABLE THIEUTH EU NIEUNHIEUH + 0xBA6E: 0xD2C1, //HANGUL SYLLABLE THIEUTH EU RIEULKIYEOK + 0xBA6F: 0xD2C3, //HANGUL SYLLABLE THIEUTH EU RIEULPIEUP + 0xBA70: 0xD2C4, //HANGUL SYLLABLE THIEUTH EU RIEULSIOS + 0xBA71: 0xD2C5, //HANGUL SYLLABLE THIEUTH EU RIEULTHIEUTH + 0xBA72: 0xD2C6, //HANGUL SYLLABLE THIEUTH EU RIEULPHIEUPH + 0xBA73: 0xD2C7, //HANGUL SYLLABLE THIEUTH EU RIEULHIEUH + 0xBA74: 0xD2CA, //HANGUL SYLLABLE THIEUTH EU PIEUPSIOS + 0xBA75: 0xD2CC, //HANGUL SYLLABLE THIEUTH EU SSANGSIOS + 0xBA76: 0xD2CD, //HANGUL SYLLABLE THIEUTH EU IEUNG + 0xBA77: 0xD2CE, //HANGUL SYLLABLE THIEUTH EU CIEUC + 0xBA78: 0xD2CF, //HANGUL SYLLABLE THIEUTH EU CHIEUCH + 0xBA79: 0xD2D0, //HANGUL SYLLABLE THIEUTH EU KHIEUKH + 0xBA7A: 0xD2D1, //HANGUL SYLLABLE THIEUTH EU THIEUTH + 0xBA81: 0xD2D2, //HANGUL SYLLABLE THIEUTH EU PHIEUPH + 0xBA82: 0xD2D3, //HANGUL SYLLABLE THIEUTH EU HIEUH + 0xBA83: 0xD2D5, //HANGUL SYLLABLE THIEUTH YI KIYEOK + 0xBA84: 0xD2D6, //HANGUL SYLLABLE THIEUTH YI SSANGKIYEOK + 0xBA85: 0xD2D7, //HANGUL SYLLABLE THIEUTH YI KIYEOKSIOS + 0xBA86: 0xD2D9, //HANGUL SYLLABLE THIEUTH YI NIEUNCIEUC + 0xBA87: 0xD2DA, //HANGUL SYLLABLE THIEUTH YI NIEUNHIEUH + 0xBA88: 0xD2DB, //HANGUL SYLLABLE THIEUTH YI TIKEUT + 0xBA89: 0xD2DD, //HANGUL SYLLABLE THIEUTH YI RIEULKIYEOK + 0xBA8A: 0xD2DE, //HANGUL SYLLABLE THIEUTH YI RIEULMIEUM + 0xBA8B: 0xD2DF, //HANGUL SYLLABLE THIEUTH YI RIEULPIEUP + 0xBA8C: 0xD2E0, //HANGUL SYLLABLE THIEUTH YI RIEULSIOS + 0xBA8D: 0xD2E1, //HANGUL SYLLABLE THIEUTH YI RIEULTHIEUTH + 0xBA8E: 0xD2E2, //HANGUL SYLLABLE THIEUTH YI RIEULPHIEUPH + 0xBA8F: 0xD2E3, //HANGUL SYLLABLE THIEUTH YI RIEULHIEUH + 0xBA90: 0xD2E6, //HANGUL SYLLABLE THIEUTH YI PIEUPSIOS + 0xBA91: 0xD2E7, //HANGUL SYLLABLE THIEUTH YI SIOS + 0xBA92: 0xD2E8, //HANGUL SYLLABLE THIEUTH YI SSANGSIOS + 0xBA93: 0xD2E9, //HANGUL SYLLABLE THIEUTH YI IEUNG + 0xBA94: 0xD2EA, //HANGUL SYLLABLE THIEUTH YI CIEUC + 0xBA95: 0xD2EB, //HANGUL SYLLABLE THIEUTH YI CHIEUCH + 0xBA96: 0xD2EC, //HANGUL SYLLABLE THIEUTH YI KHIEUKH + 0xBA97: 0xD2ED, //HANGUL SYLLABLE THIEUTH YI THIEUTH + 0xBA98: 0xD2EE, //HANGUL SYLLABLE THIEUTH YI PHIEUPH + 0xBA99: 0xD2EF, //HANGUL SYLLABLE THIEUTH YI HIEUH + 0xBA9A: 0xD2F2, //HANGUL SYLLABLE THIEUTH I SSANGKIYEOK + 0xBA9B: 0xD2F3, //HANGUL SYLLABLE THIEUTH I KIYEOKSIOS + 0xBA9C: 0xD2F5, //HANGUL SYLLABLE THIEUTH I NIEUNCIEUC + 0xBA9D: 0xD2F6, //HANGUL SYLLABLE THIEUTH I NIEUNHIEUH + 0xBA9E: 0xD2F7, //HANGUL SYLLABLE THIEUTH I TIKEUT + 0xBA9F: 0xD2F9, //HANGUL SYLLABLE THIEUTH I RIEULKIYEOK + 0xBAA0: 0xD2FA, //HANGUL SYLLABLE THIEUTH I RIEULMIEUM + 0xBAA1: 0xBC99, //HANGUL SYLLABLE PIEUP EO IEUNG + 0xBAA2: 0xBC9A, //HANGUL SYLLABLE PIEUP EO CIEUC + 0xBAA3: 0xBCA0, //HANGUL SYLLABLE PIEUP E + 0xBAA4: 0xBCA1, //HANGUL SYLLABLE PIEUP E KIYEOK + 0xBAA5: 0xBCA4, //HANGUL SYLLABLE PIEUP E NIEUN + 0xBAA6: 0xBCA7, //HANGUL SYLLABLE PIEUP E TIKEUT + 0xBAA7: 0xBCA8, //HANGUL SYLLABLE PIEUP E RIEUL + 0xBAA8: 0xBCB0, //HANGUL SYLLABLE PIEUP E MIEUM + 0xBAA9: 0xBCB1, //HANGUL SYLLABLE PIEUP E PIEUP + 0xBAAA: 0xBCB3, //HANGUL SYLLABLE PIEUP E SIOS + 0xBAAB: 0xBCB4, //HANGUL SYLLABLE PIEUP E SSANGSIOS + 0xBAAC: 0xBCB5, //HANGUL SYLLABLE PIEUP E IEUNG + 0xBAAD: 0xBCBC, //HANGUL SYLLABLE PIEUP YEO + 0xBAAE: 0xBCBD, //HANGUL SYLLABLE PIEUP YEO KIYEOK + 0xBAAF: 0xBCC0, //HANGUL SYLLABLE PIEUP YEO NIEUN + 0xBAB0: 0xBCC4, //HANGUL SYLLABLE PIEUP YEO RIEUL + 0xBAB1: 0xBCCD, //HANGUL SYLLABLE PIEUP YEO PIEUP + 0xBAB2: 0xBCCF, //HANGUL SYLLABLE PIEUP YEO SIOS + 0xBAB3: 0xBCD0, //HANGUL SYLLABLE PIEUP YEO SSANGSIOS + 0xBAB4: 0xBCD1, //HANGUL SYLLABLE PIEUP YEO IEUNG + 0xBAB5: 0xBCD5, //HANGUL SYLLABLE PIEUP YEO THIEUTH + 0xBAB6: 0xBCD8, //HANGUL SYLLABLE PIEUP YE + 0xBAB7: 0xBCDC, //HANGUL SYLLABLE PIEUP YE NIEUN + 0xBAB8: 0xBCF4, //HANGUL SYLLABLE PIEUP O + 0xBAB9: 0xBCF5, //HANGUL SYLLABLE PIEUP O KIYEOK + 0xBABA: 0xBCF6, //HANGUL SYLLABLE PIEUP O SSANGKIYEOK + 0xBABB: 0xBCF8, //HANGUL SYLLABLE PIEUP O NIEUN + 0xBABC: 0xBCFC, //HANGUL SYLLABLE PIEUP O RIEUL + 0xBABD: 0xBD04, //HANGUL SYLLABLE PIEUP O MIEUM + 0xBABE: 0xBD05, //HANGUL SYLLABLE PIEUP O PIEUP + 0xBABF: 0xBD07, //HANGUL SYLLABLE PIEUP O SIOS + 0xBAC0: 0xBD09, //HANGUL SYLLABLE PIEUP O IEUNG + 0xBAC1: 0xBD10, //HANGUL SYLLABLE PIEUP WA + 0xBAC2: 0xBD14, //HANGUL SYLLABLE PIEUP WA NIEUN + 0xBAC3: 0xBD24, //HANGUL SYLLABLE PIEUP WA SSANGSIOS + 0xBAC4: 0xBD2C, //HANGUL SYLLABLE PIEUP WAE + 0xBAC5: 0xBD40, //HANGUL SYLLABLE PIEUP WAE SSANGSIOS + 0xBAC6: 0xBD48, //HANGUL SYLLABLE PIEUP OE + 0xBAC7: 0xBD49, //HANGUL SYLLABLE PIEUP OE KIYEOK + 0xBAC8: 0xBD4C, //HANGUL SYLLABLE PIEUP OE NIEUN + 0xBAC9: 0xBD50, //HANGUL SYLLABLE PIEUP OE RIEUL + 0xBACA: 0xBD58, //HANGUL SYLLABLE PIEUP OE MIEUM + 0xBACB: 0xBD59, //HANGUL SYLLABLE PIEUP OE PIEUP + 0xBACC: 0xBD64, //HANGUL SYLLABLE PIEUP YO + 0xBACD: 0xBD68, //HANGUL SYLLABLE PIEUP YO NIEUN + 0xBACE: 0xBD80, //HANGUL SYLLABLE PIEUP U + 0xBACF: 0xBD81, //HANGUL SYLLABLE PIEUP U KIYEOK + 0xBAD0: 0xBD84, //HANGUL SYLLABLE PIEUP U NIEUN + 0xBAD1: 0xBD87, //HANGUL SYLLABLE PIEUP U TIKEUT + 0xBAD2: 0xBD88, //HANGUL SYLLABLE PIEUP U RIEUL + 0xBAD3: 0xBD89, //HANGUL SYLLABLE PIEUP U RIEULKIYEOK + 0xBAD4: 0xBD8A, //HANGUL SYLLABLE PIEUP U RIEULMIEUM + 0xBAD5: 0xBD90, //HANGUL SYLLABLE PIEUP U MIEUM + 0xBAD6: 0xBD91, //HANGUL SYLLABLE PIEUP U PIEUP + 0xBAD7: 0xBD93, //HANGUL SYLLABLE PIEUP U SIOS + 0xBAD8: 0xBD95, //HANGUL SYLLABLE PIEUP U IEUNG + 0xBAD9: 0xBD99, //HANGUL SYLLABLE PIEUP U THIEUTH + 0xBADA: 0xBD9A, //HANGUL SYLLABLE PIEUP U PHIEUPH + 0xBADB: 0xBD9C, //HANGUL SYLLABLE PIEUP WEO + 0xBADC: 0xBDA4, //HANGUL SYLLABLE PIEUP WEO RIEUL + 0xBADD: 0xBDB0, //HANGUL SYLLABLE PIEUP WEO SSANGSIOS + 0xBADE: 0xBDB8, //HANGUL SYLLABLE PIEUP WE + 0xBADF: 0xBDD4, //HANGUL SYLLABLE PIEUP WI + 0xBAE0: 0xBDD5, //HANGUL SYLLABLE PIEUP WI KIYEOK + 0xBAE1: 0xBDD8, //HANGUL SYLLABLE PIEUP WI NIEUN + 0xBAE2: 0xBDDC, //HANGUL SYLLABLE PIEUP WI RIEUL + 0xBAE3: 0xBDE9, //HANGUL SYLLABLE PIEUP WI IEUNG + 0xBAE4: 0xBDF0, //HANGUL SYLLABLE PIEUP YU + 0xBAE5: 0xBDF4, //HANGUL SYLLABLE PIEUP YU NIEUN + 0xBAE6: 0xBDF8, //HANGUL SYLLABLE PIEUP YU RIEUL + 0xBAE7: 0xBE00, //HANGUL SYLLABLE PIEUP YU MIEUM + 0xBAE8: 0xBE03, //HANGUL SYLLABLE PIEUP YU SIOS + 0xBAE9: 0xBE05, //HANGUL SYLLABLE PIEUP YU IEUNG + 0xBAEA: 0xBE0C, //HANGUL SYLLABLE PIEUP EU + 0xBAEB: 0xBE0D, //HANGUL SYLLABLE PIEUP EU KIYEOK + 0xBAEC: 0xBE10, //HANGUL SYLLABLE PIEUP EU NIEUN + 0xBAED: 0xBE14, //HANGUL SYLLABLE PIEUP EU RIEUL + 0xBAEE: 0xBE1C, //HANGUL SYLLABLE PIEUP EU MIEUM + 0xBAEF: 0xBE1D, //HANGUL SYLLABLE PIEUP EU PIEUP + 0xBAF0: 0xBE1F, //HANGUL SYLLABLE PIEUP EU SIOS + 0xBAF1: 0xBE44, //HANGUL SYLLABLE PIEUP I + 0xBAF2: 0xBE45, //HANGUL SYLLABLE PIEUP I KIYEOK + 0xBAF3: 0xBE48, //HANGUL SYLLABLE PIEUP I NIEUN + 0xBAF4: 0xBE4C, //HANGUL SYLLABLE PIEUP I RIEUL + 0xBAF5: 0xBE4E, //HANGUL SYLLABLE PIEUP I RIEULMIEUM + 0xBAF6: 0xBE54, //HANGUL SYLLABLE PIEUP I MIEUM + 0xBAF7: 0xBE55, //HANGUL SYLLABLE PIEUP I PIEUP + 0xBAF8: 0xBE57, //HANGUL SYLLABLE PIEUP I SIOS + 0xBAF9: 0xBE59, //HANGUL SYLLABLE PIEUP I IEUNG + 0xBAFA: 0xBE5A, //HANGUL SYLLABLE PIEUP I CIEUC + 0xBAFB: 0xBE5B, //HANGUL SYLLABLE PIEUP I CHIEUCH + 0xBAFC: 0xBE60, //HANGUL SYLLABLE SSANGPIEUP A + 0xBAFD: 0xBE61, //HANGUL SYLLABLE SSANGPIEUP A KIYEOK + 0xBAFE: 0xBE64, //HANGUL SYLLABLE SSANGPIEUP A NIEUN + 0xBB41: 0xD2FB, //HANGUL SYLLABLE THIEUTH I RIEULPIEUP + 0xBB42: 0xD2FC, //HANGUL SYLLABLE THIEUTH I RIEULSIOS + 0xBB43: 0xD2FD, //HANGUL SYLLABLE THIEUTH I RIEULTHIEUTH + 0xBB44: 0xD2FE, //HANGUL SYLLABLE THIEUTH I RIEULPHIEUPH + 0xBB45: 0xD2FF, //HANGUL SYLLABLE THIEUTH I RIEULHIEUH + 0xBB46: 0xD302, //HANGUL SYLLABLE THIEUTH I PIEUPSIOS + 0xBB47: 0xD304, //HANGUL SYLLABLE THIEUTH I SSANGSIOS + 0xBB48: 0xD306, //HANGUL SYLLABLE THIEUTH I CIEUC + 0xBB49: 0xD307, //HANGUL SYLLABLE THIEUTH I CHIEUCH + 0xBB4A: 0xD308, //HANGUL SYLLABLE THIEUTH I KHIEUKH + 0xBB4B: 0xD309, //HANGUL SYLLABLE THIEUTH I THIEUTH + 0xBB4C: 0xD30A, //HANGUL SYLLABLE THIEUTH I PHIEUPH + 0xBB4D: 0xD30B, //HANGUL SYLLABLE THIEUTH I HIEUH + 0xBB4E: 0xD30F, //HANGUL SYLLABLE PHIEUPH A KIYEOKSIOS + 0xBB4F: 0xD311, //HANGUL SYLLABLE PHIEUPH A NIEUNCIEUC + 0xBB50: 0xD312, //HANGUL SYLLABLE PHIEUPH A NIEUNHIEUH + 0xBB51: 0xD313, //HANGUL SYLLABLE PHIEUPH A TIKEUT + 0xBB52: 0xD315, //HANGUL SYLLABLE PHIEUPH A RIEULKIYEOK + 0xBB53: 0xD317, //HANGUL SYLLABLE PHIEUPH A RIEULPIEUP + 0xBB54: 0xD318, //HANGUL SYLLABLE PHIEUPH A RIEULSIOS + 0xBB55: 0xD319, //HANGUL SYLLABLE PHIEUPH A RIEULTHIEUTH + 0xBB56: 0xD31A, //HANGUL SYLLABLE PHIEUPH A RIEULPHIEUPH + 0xBB57: 0xD31B, //HANGUL SYLLABLE PHIEUPH A RIEULHIEUH + 0xBB58: 0xD31E, //HANGUL SYLLABLE PHIEUPH A PIEUPSIOS + 0xBB59: 0xD322, //HANGUL SYLLABLE PHIEUPH A CIEUC + 0xBB5A: 0xD323, //HANGUL SYLLABLE PHIEUPH A CHIEUCH + 0xBB61: 0xD324, //HANGUL SYLLABLE PHIEUPH A KHIEUKH + 0xBB62: 0xD326, //HANGUL SYLLABLE PHIEUPH A PHIEUPH + 0xBB63: 0xD327, //HANGUL SYLLABLE PHIEUPH A HIEUH + 0xBB64: 0xD32A, //HANGUL SYLLABLE PHIEUPH AE SSANGKIYEOK + 0xBB65: 0xD32B, //HANGUL SYLLABLE PHIEUPH AE KIYEOKSIOS + 0xBB66: 0xD32D, //HANGUL SYLLABLE PHIEUPH AE NIEUNCIEUC + 0xBB67: 0xD32E, //HANGUL SYLLABLE PHIEUPH AE NIEUNHIEUH + 0xBB68: 0xD32F, //HANGUL SYLLABLE PHIEUPH AE TIKEUT + 0xBB69: 0xD331, //HANGUL SYLLABLE PHIEUPH AE RIEULKIYEOK + 0xBB6A: 0xD332, //HANGUL SYLLABLE PHIEUPH AE RIEULMIEUM + 0xBB6B: 0xD333, //HANGUL SYLLABLE PHIEUPH AE RIEULPIEUP + 0xBB6C: 0xD334, //HANGUL SYLLABLE PHIEUPH AE RIEULSIOS + 0xBB6D: 0xD335, //HANGUL SYLLABLE PHIEUPH AE RIEULTHIEUTH + 0xBB6E: 0xD336, //HANGUL SYLLABLE PHIEUPH AE RIEULPHIEUPH + 0xBB6F: 0xD337, //HANGUL SYLLABLE PHIEUPH AE RIEULHIEUH + 0xBB70: 0xD33A, //HANGUL SYLLABLE PHIEUPH AE PIEUPSIOS + 0xBB71: 0xD33E, //HANGUL SYLLABLE PHIEUPH AE CIEUC + 0xBB72: 0xD33F, //HANGUL SYLLABLE PHIEUPH AE CHIEUCH + 0xBB73: 0xD340, //HANGUL SYLLABLE PHIEUPH AE KHIEUKH + 0xBB74: 0xD341, //HANGUL SYLLABLE PHIEUPH AE THIEUTH + 0xBB75: 0xD342, //HANGUL SYLLABLE PHIEUPH AE PHIEUPH + 0xBB76: 0xD343, //HANGUL SYLLABLE PHIEUPH AE HIEUH + 0xBB77: 0xD346, //HANGUL SYLLABLE PHIEUPH YA SSANGKIYEOK + 0xBB78: 0xD347, //HANGUL SYLLABLE PHIEUPH YA KIYEOKSIOS + 0xBB79: 0xD348, //HANGUL SYLLABLE PHIEUPH YA NIEUN + 0xBB7A: 0xD349, //HANGUL SYLLABLE PHIEUPH YA NIEUNCIEUC + 0xBB81: 0xD34A, //HANGUL SYLLABLE PHIEUPH YA NIEUNHIEUH + 0xBB82: 0xD34B, //HANGUL SYLLABLE PHIEUPH YA TIKEUT + 0xBB83: 0xD34C, //HANGUL SYLLABLE PHIEUPH YA RIEUL + 0xBB84: 0xD34D, //HANGUL SYLLABLE PHIEUPH YA RIEULKIYEOK + 0xBB85: 0xD34E, //HANGUL SYLLABLE PHIEUPH YA RIEULMIEUM + 0xBB86: 0xD34F, //HANGUL SYLLABLE PHIEUPH YA RIEULPIEUP + 0xBB87: 0xD350, //HANGUL SYLLABLE PHIEUPH YA RIEULSIOS + 0xBB88: 0xD351, //HANGUL SYLLABLE PHIEUPH YA RIEULTHIEUTH + 0xBB89: 0xD352, //HANGUL SYLLABLE PHIEUPH YA RIEULPHIEUPH + 0xBB8A: 0xD353, //HANGUL SYLLABLE PHIEUPH YA RIEULHIEUH + 0xBB8B: 0xD354, //HANGUL SYLLABLE PHIEUPH YA MIEUM + 0xBB8C: 0xD355, //HANGUL SYLLABLE PHIEUPH YA PIEUP + 0xBB8D: 0xD356, //HANGUL SYLLABLE PHIEUPH YA PIEUPSIOS + 0xBB8E: 0xD357, //HANGUL SYLLABLE PHIEUPH YA SIOS + 0xBB8F: 0xD358, //HANGUL SYLLABLE PHIEUPH YA SSANGSIOS + 0xBB90: 0xD359, //HANGUL SYLLABLE PHIEUPH YA IEUNG + 0xBB91: 0xD35A, //HANGUL SYLLABLE PHIEUPH YA CIEUC + 0xBB92: 0xD35B, //HANGUL SYLLABLE PHIEUPH YA CHIEUCH + 0xBB93: 0xD35C, //HANGUL SYLLABLE PHIEUPH YA KHIEUKH + 0xBB94: 0xD35D, //HANGUL SYLLABLE PHIEUPH YA THIEUTH + 0xBB95: 0xD35E, //HANGUL SYLLABLE PHIEUPH YA PHIEUPH + 0xBB96: 0xD35F, //HANGUL SYLLABLE PHIEUPH YA HIEUH + 0xBB97: 0xD360, //HANGUL SYLLABLE PHIEUPH YAE + 0xBB98: 0xD361, //HANGUL SYLLABLE PHIEUPH YAE KIYEOK + 0xBB99: 0xD362, //HANGUL SYLLABLE PHIEUPH YAE SSANGKIYEOK + 0xBB9A: 0xD363, //HANGUL SYLLABLE PHIEUPH YAE KIYEOKSIOS + 0xBB9B: 0xD364, //HANGUL SYLLABLE PHIEUPH YAE NIEUN + 0xBB9C: 0xD365, //HANGUL SYLLABLE PHIEUPH YAE NIEUNCIEUC + 0xBB9D: 0xD366, //HANGUL SYLLABLE PHIEUPH YAE NIEUNHIEUH + 0xBB9E: 0xD367, //HANGUL SYLLABLE PHIEUPH YAE TIKEUT + 0xBB9F: 0xD368, //HANGUL SYLLABLE PHIEUPH YAE RIEUL + 0xBBA0: 0xD369, //HANGUL SYLLABLE PHIEUPH YAE RIEULKIYEOK + 0xBBA1: 0xBE68, //HANGUL SYLLABLE SSANGPIEUP A RIEUL + 0xBBA2: 0xBE6A, //HANGUL SYLLABLE SSANGPIEUP A RIEULMIEUM + 0xBBA3: 0xBE70, //HANGUL SYLLABLE SSANGPIEUP A MIEUM + 0xBBA4: 0xBE71, //HANGUL SYLLABLE SSANGPIEUP A PIEUP + 0xBBA5: 0xBE73, //HANGUL SYLLABLE SSANGPIEUP A SIOS + 0xBBA6: 0xBE74, //HANGUL SYLLABLE SSANGPIEUP A SSANGSIOS + 0xBBA7: 0xBE75, //HANGUL SYLLABLE SSANGPIEUP A IEUNG + 0xBBA8: 0xBE7B, //HANGUL SYLLABLE SSANGPIEUP A HIEUH + 0xBBA9: 0xBE7C, //HANGUL SYLLABLE SSANGPIEUP AE + 0xBBAA: 0xBE7D, //HANGUL SYLLABLE SSANGPIEUP AE KIYEOK + 0xBBAB: 0xBE80, //HANGUL SYLLABLE SSANGPIEUP AE NIEUN + 0xBBAC: 0xBE84, //HANGUL SYLLABLE SSANGPIEUP AE RIEUL + 0xBBAD: 0xBE8C, //HANGUL SYLLABLE SSANGPIEUP AE MIEUM + 0xBBAE: 0xBE8D, //HANGUL SYLLABLE SSANGPIEUP AE PIEUP + 0xBBAF: 0xBE8F, //HANGUL SYLLABLE SSANGPIEUP AE SIOS + 0xBBB0: 0xBE90, //HANGUL SYLLABLE SSANGPIEUP AE SSANGSIOS + 0xBBB1: 0xBE91, //HANGUL SYLLABLE SSANGPIEUP AE IEUNG + 0xBBB2: 0xBE98, //HANGUL SYLLABLE SSANGPIEUP YA + 0xBBB3: 0xBE99, //HANGUL SYLLABLE SSANGPIEUP YA KIYEOK + 0xBBB4: 0xBEA8, //HANGUL SYLLABLE SSANGPIEUP YA MIEUM + 0xBBB5: 0xBED0, //HANGUL SYLLABLE SSANGPIEUP EO + 0xBBB6: 0xBED1, //HANGUL SYLLABLE SSANGPIEUP EO KIYEOK + 0xBBB7: 0xBED4, //HANGUL SYLLABLE SSANGPIEUP EO NIEUN + 0xBBB8: 0xBED7, //HANGUL SYLLABLE SSANGPIEUP EO TIKEUT + 0xBBB9: 0xBED8, //HANGUL SYLLABLE SSANGPIEUP EO RIEUL + 0xBBBA: 0xBEE0, //HANGUL SYLLABLE SSANGPIEUP EO MIEUM + 0xBBBB: 0xBEE3, //HANGUL SYLLABLE SSANGPIEUP EO SIOS + 0xBBBC: 0xBEE4, //HANGUL SYLLABLE SSANGPIEUP EO SSANGSIOS + 0xBBBD: 0xBEE5, //HANGUL SYLLABLE SSANGPIEUP EO IEUNG + 0xBBBE: 0xBEEC, //HANGUL SYLLABLE SSANGPIEUP E + 0xBBBF: 0xBF01, //HANGUL SYLLABLE SSANGPIEUP E IEUNG + 0xBBC0: 0xBF08, //HANGUL SYLLABLE SSANGPIEUP YEO + 0xBBC1: 0xBF09, //HANGUL SYLLABLE SSANGPIEUP YEO KIYEOK + 0xBBC2: 0xBF18, //HANGUL SYLLABLE SSANGPIEUP YEO MIEUM + 0xBBC3: 0xBF19, //HANGUL SYLLABLE SSANGPIEUP YEO PIEUP + 0xBBC4: 0xBF1B, //HANGUL SYLLABLE SSANGPIEUP YEO SIOS + 0xBBC5: 0xBF1C, //HANGUL SYLLABLE SSANGPIEUP YEO SSANGSIOS + 0xBBC6: 0xBF1D, //HANGUL SYLLABLE SSANGPIEUP YEO IEUNG + 0xBBC7: 0xBF40, //HANGUL SYLLABLE SSANGPIEUP O + 0xBBC8: 0xBF41, //HANGUL SYLLABLE SSANGPIEUP O KIYEOK + 0xBBC9: 0xBF44, //HANGUL SYLLABLE SSANGPIEUP O NIEUN + 0xBBCA: 0xBF48, //HANGUL SYLLABLE SSANGPIEUP O RIEUL + 0xBBCB: 0xBF50, //HANGUL SYLLABLE SSANGPIEUP O MIEUM + 0xBBCC: 0xBF51, //HANGUL SYLLABLE SSANGPIEUP O PIEUP + 0xBBCD: 0xBF55, //HANGUL SYLLABLE SSANGPIEUP O IEUNG + 0xBBCE: 0xBF94, //HANGUL SYLLABLE SSANGPIEUP OE + 0xBBCF: 0xBFB0, //HANGUL SYLLABLE SSANGPIEUP YO + 0xBBD0: 0xBFC5, //HANGUL SYLLABLE SSANGPIEUP YO IEUNG + 0xBBD1: 0xBFCC, //HANGUL SYLLABLE SSANGPIEUP U + 0xBBD2: 0xBFCD, //HANGUL SYLLABLE SSANGPIEUP U KIYEOK + 0xBBD3: 0xBFD0, //HANGUL SYLLABLE SSANGPIEUP U NIEUN + 0xBBD4: 0xBFD4, //HANGUL SYLLABLE SSANGPIEUP U RIEUL + 0xBBD5: 0xBFDC, //HANGUL SYLLABLE SSANGPIEUP U MIEUM + 0xBBD6: 0xBFDF, //HANGUL SYLLABLE SSANGPIEUP U SIOS + 0xBBD7: 0xBFE1, //HANGUL SYLLABLE SSANGPIEUP U IEUNG + 0xBBD8: 0xC03C, //HANGUL SYLLABLE SSANGPIEUP YU + 0xBBD9: 0xC051, //HANGUL SYLLABLE SSANGPIEUP YU IEUNG + 0xBBDA: 0xC058, //HANGUL SYLLABLE SSANGPIEUP EU + 0xBBDB: 0xC05C, //HANGUL SYLLABLE SSANGPIEUP EU NIEUN + 0xBBDC: 0xC060, //HANGUL SYLLABLE SSANGPIEUP EU RIEUL + 0xBBDD: 0xC068, //HANGUL SYLLABLE SSANGPIEUP EU MIEUM + 0xBBDE: 0xC069, //HANGUL SYLLABLE SSANGPIEUP EU PIEUP + 0xBBDF: 0xC090, //HANGUL SYLLABLE SSANGPIEUP I + 0xBBE0: 0xC091, //HANGUL SYLLABLE SSANGPIEUP I KIYEOK + 0xBBE1: 0xC094, //HANGUL SYLLABLE SSANGPIEUP I NIEUN + 0xBBE2: 0xC098, //HANGUL SYLLABLE SSANGPIEUP I RIEUL + 0xBBE3: 0xC0A0, //HANGUL SYLLABLE SSANGPIEUP I MIEUM + 0xBBE4: 0xC0A1, //HANGUL SYLLABLE SSANGPIEUP I PIEUP + 0xBBE5: 0xC0A3, //HANGUL SYLLABLE SSANGPIEUP I SIOS + 0xBBE6: 0xC0A5, //HANGUL SYLLABLE SSANGPIEUP I IEUNG + 0xBBE7: 0xC0AC, //HANGUL SYLLABLE SIOS A + 0xBBE8: 0xC0AD, //HANGUL SYLLABLE SIOS A KIYEOK + 0xBBE9: 0xC0AF, //HANGUL SYLLABLE SIOS A KIYEOKSIOS + 0xBBEA: 0xC0B0, //HANGUL SYLLABLE SIOS A NIEUN + 0xBBEB: 0xC0B3, //HANGUL SYLLABLE SIOS A TIKEUT + 0xBBEC: 0xC0B4, //HANGUL SYLLABLE SIOS A RIEUL + 0xBBED: 0xC0B5, //HANGUL SYLLABLE SIOS A RIEULKIYEOK + 0xBBEE: 0xC0B6, //HANGUL SYLLABLE SIOS A RIEULMIEUM + 0xBBEF: 0xC0BC, //HANGUL SYLLABLE SIOS A MIEUM + 0xBBF0: 0xC0BD, //HANGUL SYLLABLE SIOS A PIEUP + 0xBBF1: 0xC0BF, //HANGUL SYLLABLE SIOS A SIOS + 0xBBF2: 0xC0C0, //HANGUL SYLLABLE SIOS A SSANGSIOS + 0xBBF3: 0xC0C1, //HANGUL SYLLABLE SIOS A IEUNG + 0xBBF4: 0xC0C5, //HANGUL SYLLABLE SIOS A THIEUTH + 0xBBF5: 0xC0C8, //HANGUL SYLLABLE SIOS AE + 0xBBF6: 0xC0C9, //HANGUL SYLLABLE SIOS AE KIYEOK + 0xBBF7: 0xC0CC, //HANGUL SYLLABLE SIOS AE NIEUN + 0xBBF8: 0xC0D0, //HANGUL SYLLABLE SIOS AE RIEUL + 0xBBF9: 0xC0D8, //HANGUL SYLLABLE SIOS AE MIEUM + 0xBBFA: 0xC0D9, //HANGUL SYLLABLE SIOS AE PIEUP + 0xBBFB: 0xC0DB, //HANGUL SYLLABLE SIOS AE SIOS + 0xBBFC: 0xC0DC, //HANGUL SYLLABLE SIOS AE SSANGSIOS + 0xBBFD: 0xC0DD, //HANGUL SYLLABLE SIOS AE IEUNG + 0xBBFE: 0xC0E4, //HANGUL SYLLABLE SIOS YA + 0xBC41: 0xD36A, //HANGUL SYLLABLE PHIEUPH YAE RIEULMIEUM + 0xBC42: 0xD36B, //HANGUL SYLLABLE PHIEUPH YAE RIEULPIEUP + 0xBC43: 0xD36C, //HANGUL SYLLABLE PHIEUPH YAE RIEULSIOS + 0xBC44: 0xD36D, //HANGUL SYLLABLE PHIEUPH YAE RIEULTHIEUTH + 0xBC45: 0xD36E, //HANGUL SYLLABLE PHIEUPH YAE RIEULPHIEUPH + 0xBC46: 0xD36F, //HANGUL SYLLABLE PHIEUPH YAE RIEULHIEUH + 0xBC47: 0xD370, //HANGUL SYLLABLE PHIEUPH YAE MIEUM + 0xBC48: 0xD371, //HANGUL SYLLABLE PHIEUPH YAE PIEUP + 0xBC49: 0xD372, //HANGUL SYLLABLE PHIEUPH YAE PIEUPSIOS + 0xBC4A: 0xD373, //HANGUL SYLLABLE PHIEUPH YAE SIOS + 0xBC4B: 0xD374, //HANGUL SYLLABLE PHIEUPH YAE SSANGSIOS + 0xBC4C: 0xD375, //HANGUL SYLLABLE PHIEUPH YAE IEUNG + 0xBC4D: 0xD376, //HANGUL SYLLABLE PHIEUPH YAE CIEUC + 0xBC4E: 0xD377, //HANGUL SYLLABLE PHIEUPH YAE CHIEUCH + 0xBC4F: 0xD378, //HANGUL SYLLABLE PHIEUPH YAE KHIEUKH + 0xBC50: 0xD379, //HANGUL SYLLABLE PHIEUPH YAE THIEUTH + 0xBC51: 0xD37A, //HANGUL SYLLABLE PHIEUPH YAE PHIEUPH + 0xBC52: 0xD37B, //HANGUL SYLLABLE PHIEUPH YAE HIEUH + 0xBC53: 0xD37E, //HANGUL SYLLABLE PHIEUPH EO SSANGKIYEOK + 0xBC54: 0xD37F, //HANGUL SYLLABLE PHIEUPH EO KIYEOKSIOS + 0xBC55: 0xD381, //HANGUL SYLLABLE PHIEUPH EO NIEUNCIEUC + 0xBC56: 0xD382, //HANGUL SYLLABLE PHIEUPH EO NIEUNHIEUH + 0xBC57: 0xD383, //HANGUL SYLLABLE PHIEUPH EO TIKEUT + 0xBC58: 0xD385, //HANGUL SYLLABLE PHIEUPH EO RIEULKIYEOK + 0xBC59: 0xD386, //HANGUL SYLLABLE PHIEUPH EO RIEULMIEUM + 0xBC5A: 0xD387, //HANGUL SYLLABLE PHIEUPH EO RIEULPIEUP + 0xBC61: 0xD388, //HANGUL SYLLABLE PHIEUPH EO RIEULSIOS + 0xBC62: 0xD389, //HANGUL SYLLABLE PHIEUPH EO RIEULTHIEUTH + 0xBC63: 0xD38A, //HANGUL SYLLABLE PHIEUPH EO RIEULPHIEUPH + 0xBC64: 0xD38B, //HANGUL SYLLABLE PHIEUPH EO RIEULHIEUH + 0xBC65: 0xD38E, //HANGUL SYLLABLE PHIEUPH EO PIEUPSIOS + 0xBC66: 0xD392, //HANGUL SYLLABLE PHIEUPH EO CIEUC + 0xBC67: 0xD393, //HANGUL SYLLABLE PHIEUPH EO CHIEUCH + 0xBC68: 0xD394, //HANGUL SYLLABLE PHIEUPH EO KHIEUKH + 0xBC69: 0xD395, //HANGUL SYLLABLE PHIEUPH EO THIEUTH + 0xBC6A: 0xD396, //HANGUL SYLLABLE PHIEUPH EO PHIEUPH + 0xBC6B: 0xD397, //HANGUL SYLLABLE PHIEUPH EO HIEUH + 0xBC6C: 0xD39A, //HANGUL SYLLABLE PHIEUPH E SSANGKIYEOK + 0xBC6D: 0xD39B, //HANGUL SYLLABLE PHIEUPH E KIYEOKSIOS + 0xBC6E: 0xD39D, //HANGUL SYLLABLE PHIEUPH E NIEUNCIEUC + 0xBC6F: 0xD39E, //HANGUL SYLLABLE PHIEUPH E NIEUNHIEUH + 0xBC70: 0xD39F, //HANGUL SYLLABLE PHIEUPH E TIKEUT + 0xBC71: 0xD3A1, //HANGUL SYLLABLE PHIEUPH E RIEULKIYEOK + 0xBC72: 0xD3A2, //HANGUL SYLLABLE PHIEUPH E RIEULMIEUM + 0xBC73: 0xD3A3, //HANGUL SYLLABLE PHIEUPH E RIEULPIEUP + 0xBC74: 0xD3A4, //HANGUL SYLLABLE PHIEUPH E RIEULSIOS + 0xBC75: 0xD3A5, //HANGUL SYLLABLE PHIEUPH E RIEULTHIEUTH + 0xBC76: 0xD3A6, //HANGUL SYLLABLE PHIEUPH E RIEULPHIEUPH + 0xBC77: 0xD3A7, //HANGUL SYLLABLE PHIEUPH E RIEULHIEUH + 0xBC78: 0xD3AA, //HANGUL SYLLABLE PHIEUPH E PIEUPSIOS + 0xBC79: 0xD3AC, //HANGUL SYLLABLE PHIEUPH E SSANGSIOS + 0xBC7A: 0xD3AE, //HANGUL SYLLABLE PHIEUPH E CIEUC + 0xBC81: 0xD3AF, //HANGUL SYLLABLE PHIEUPH E CHIEUCH + 0xBC82: 0xD3B0, //HANGUL SYLLABLE PHIEUPH E KHIEUKH + 0xBC83: 0xD3B1, //HANGUL SYLLABLE PHIEUPH E THIEUTH + 0xBC84: 0xD3B2, //HANGUL SYLLABLE PHIEUPH E PHIEUPH + 0xBC85: 0xD3B3, //HANGUL SYLLABLE PHIEUPH E HIEUH + 0xBC86: 0xD3B5, //HANGUL SYLLABLE PHIEUPH YEO KIYEOK + 0xBC87: 0xD3B6, //HANGUL SYLLABLE PHIEUPH YEO SSANGKIYEOK + 0xBC88: 0xD3B7, //HANGUL SYLLABLE PHIEUPH YEO KIYEOKSIOS + 0xBC89: 0xD3B9, //HANGUL SYLLABLE PHIEUPH YEO NIEUNCIEUC + 0xBC8A: 0xD3BA, //HANGUL SYLLABLE PHIEUPH YEO NIEUNHIEUH + 0xBC8B: 0xD3BB, //HANGUL SYLLABLE PHIEUPH YEO TIKEUT + 0xBC8C: 0xD3BD, //HANGUL SYLLABLE PHIEUPH YEO RIEULKIYEOK + 0xBC8D: 0xD3BE, //HANGUL SYLLABLE PHIEUPH YEO RIEULMIEUM + 0xBC8E: 0xD3BF, //HANGUL SYLLABLE PHIEUPH YEO RIEULPIEUP + 0xBC8F: 0xD3C0, //HANGUL SYLLABLE PHIEUPH YEO RIEULSIOS + 0xBC90: 0xD3C1, //HANGUL SYLLABLE PHIEUPH YEO RIEULTHIEUTH + 0xBC91: 0xD3C2, //HANGUL SYLLABLE PHIEUPH YEO RIEULPHIEUPH + 0xBC92: 0xD3C3, //HANGUL SYLLABLE PHIEUPH YEO RIEULHIEUH + 0xBC93: 0xD3C6, //HANGUL SYLLABLE PHIEUPH YEO PIEUPSIOS + 0xBC94: 0xD3C7, //HANGUL SYLLABLE PHIEUPH YEO SIOS + 0xBC95: 0xD3CA, //HANGUL SYLLABLE PHIEUPH YEO CIEUC + 0xBC96: 0xD3CB, //HANGUL SYLLABLE PHIEUPH YEO CHIEUCH + 0xBC97: 0xD3CC, //HANGUL SYLLABLE PHIEUPH YEO KHIEUKH + 0xBC98: 0xD3CD, //HANGUL SYLLABLE PHIEUPH YEO THIEUTH + 0xBC99: 0xD3CE, //HANGUL SYLLABLE PHIEUPH YEO PHIEUPH + 0xBC9A: 0xD3CF, //HANGUL SYLLABLE PHIEUPH YEO HIEUH + 0xBC9B: 0xD3D1, //HANGUL SYLLABLE PHIEUPH YE KIYEOK + 0xBC9C: 0xD3D2, //HANGUL SYLLABLE PHIEUPH YE SSANGKIYEOK + 0xBC9D: 0xD3D3, //HANGUL SYLLABLE PHIEUPH YE KIYEOKSIOS + 0xBC9E: 0xD3D4, //HANGUL SYLLABLE PHIEUPH YE NIEUN + 0xBC9F: 0xD3D5, //HANGUL SYLLABLE PHIEUPH YE NIEUNCIEUC + 0xBCA0: 0xD3D6, //HANGUL SYLLABLE PHIEUPH YE NIEUNHIEUH + 0xBCA1: 0xC0E5, //HANGUL SYLLABLE SIOS YA KIYEOK + 0xBCA2: 0xC0E8, //HANGUL SYLLABLE SIOS YA NIEUN + 0xBCA3: 0xC0EC, //HANGUL SYLLABLE SIOS YA RIEUL + 0xBCA4: 0xC0F4, //HANGUL SYLLABLE SIOS YA MIEUM + 0xBCA5: 0xC0F5, //HANGUL SYLLABLE SIOS YA PIEUP + 0xBCA6: 0xC0F7, //HANGUL SYLLABLE SIOS YA SIOS + 0xBCA7: 0xC0F9, //HANGUL SYLLABLE SIOS YA IEUNG + 0xBCA8: 0xC100, //HANGUL SYLLABLE SIOS YAE + 0xBCA9: 0xC104, //HANGUL SYLLABLE SIOS YAE NIEUN + 0xBCAA: 0xC108, //HANGUL SYLLABLE SIOS YAE RIEUL + 0xBCAB: 0xC110, //HANGUL SYLLABLE SIOS YAE MIEUM + 0xBCAC: 0xC115, //HANGUL SYLLABLE SIOS YAE IEUNG + 0xBCAD: 0xC11C, //HANGUL SYLLABLE SIOS EO + 0xBCAE: 0xC11D, //HANGUL SYLLABLE SIOS EO KIYEOK + 0xBCAF: 0xC11E, //HANGUL SYLLABLE SIOS EO SSANGKIYEOK + 0xBCB0: 0xC11F, //HANGUL SYLLABLE SIOS EO KIYEOKSIOS + 0xBCB1: 0xC120, //HANGUL SYLLABLE SIOS EO NIEUN + 0xBCB2: 0xC123, //HANGUL SYLLABLE SIOS EO TIKEUT + 0xBCB3: 0xC124, //HANGUL SYLLABLE SIOS EO RIEUL + 0xBCB4: 0xC126, //HANGUL SYLLABLE SIOS EO RIEULMIEUM + 0xBCB5: 0xC127, //HANGUL SYLLABLE SIOS EO RIEULPIEUP + 0xBCB6: 0xC12C, //HANGUL SYLLABLE SIOS EO MIEUM + 0xBCB7: 0xC12D, //HANGUL SYLLABLE SIOS EO PIEUP + 0xBCB8: 0xC12F, //HANGUL SYLLABLE SIOS EO SIOS + 0xBCB9: 0xC130, //HANGUL SYLLABLE SIOS EO SSANGSIOS + 0xBCBA: 0xC131, //HANGUL SYLLABLE SIOS EO IEUNG + 0xBCBB: 0xC136, //HANGUL SYLLABLE SIOS EO PHIEUPH + 0xBCBC: 0xC138, //HANGUL SYLLABLE SIOS E + 0xBCBD: 0xC139, //HANGUL SYLLABLE SIOS E KIYEOK + 0xBCBE: 0xC13C, //HANGUL SYLLABLE SIOS E NIEUN + 0xBCBF: 0xC140, //HANGUL SYLLABLE SIOS E RIEUL + 0xBCC0: 0xC148, //HANGUL SYLLABLE SIOS E MIEUM + 0xBCC1: 0xC149, //HANGUL SYLLABLE SIOS E PIEUP + 0xBCC2: 0xC14B, //HANGUL SYLLABLE SIOS E SIOS + 0xBCC3: 0xC14C, //HANGUL SYLLABLE SIOS E SSANGSIOS + 0xBCC4: 0xC14D, //HANGUL SYLLABLE SIOS E IEUNG + 0xBCC5: 0xC154, //HANGUL SYLLABLE SIOS YEO + 0xBCC6: 0xC155, //HANGUL SYLLABLE SIOS YEO KIYEOK + 0xBCC7: 0xC158, //HANGUL SYLLABLE SIOS YEO NIEUN + 0xBCC8: 0xC15C, //HANGUL SYLLABLE SIOS YEO RIEUL + 0xBCC9: 0xC164, //HANGUL SYLLABLE SIOS YEO MIEUM + 0xBCCA: 0xC165, //HANGUL SYLLABLE SIOS YEO PIEUP + 0xBCCB: 0xC167, //HANGUL SYLLABLE SIOS YEO SIOS + 0xBCCC: 0xC168, //HANGUL SYLLABLE SIOS YEO SSANGSIOS + 0xBCCD: 0xC169, //HANGUL SYLLABLE SIOS YEO IEUNG + 0xBCCE: 0xC170, //HANGUL SYLLABLE SIOS YE + 0xBCCF: 0xC174, //HANGUL SYLLABLE SIOS YE NIEUN + 0xBCD0: 0xC178, //HANGUL SYLLABLE SIOS YE RIEUL + 0xBCD1: 0xC185, //HANGUL SYLLABLE SIOS YE IEUNG + 0xBCD2: 0xC18C, //HANGUL SYLLABLE SIOS O + 0xBCD3: 0xC18D, //HANGUL SYLLABLE SIOS O KIYEOK + 0xBCD4: 0xC18E, //HANGUL SYLLABLE SIOS O SSANGKIYEOK + 0xBCD5: 0xC190, //HANGUL SYLLABLE SIOS O NIEUN + 0xBCD6: 0xC194, //HANGUL SYLLABLE SIOS O RIEUL + 0xBCD7: 0xC196, //HANGUL SYLLABLE SIOS O RIEULMIEUM + 0xBCD8: 0xC19C, //HANGUL SYLLABLE SIOS O MIEUM + 0xBCD9: 0xC19D, //HANGUL SYLLABLE SIOS O PIEUP + 0xBCDA: 0xC19F, //HANGUL SYLLABLE SIOS O SIOS + 0xBCDB: 0xC1A1, //HANGUL SYLLABLE SIOS O IEUNG + 0xBCDC: 0xC1A5, //HANGUL SYLLABLE SIOS O THIEUTH + 0xBCDD: 0xC1A8, //HANGUL SYLLABLE SIOS WA + 0xBCDE: 0xC1A9, //HANGUL SYLLABLE SIOS WA KIYEOK + 0xBCDF: 0xC1AC, //HANGUL SYLLABLE SIOS WA NIEUN + 0xBCE0: 0xC1B0, //HANGUL SYLLABLE SIOS WA RIEUL + 0xBCE1: 0xC1BD, //HANGUL SYLLABLE SIOS WA IEUNG + 0xBCE2: 0xC1C4, //HANGUL SYLLABLE SIOS WAE + 0xBCE3: 0xC1C8, //HANGUL SYLLABLE SIOS WAE NIEUN + 0xBCE4: 0xC1CC, //HANGUL SYLLABLE SIOS WAE RIEUL + 0xBCE5: 0xC1D4, //HANGUL SYLLABLE SIOS WAE MIEUM + 0xBCE6: 0xC1D7, //HANGUL SYLLABLE SIOS WAE SIOS + 0xBCE7: 0xC1D8, //HANGUL SYLLABLE SIOS WAE SSANGSIOS + 0xBCE8: 0xC1E0, //HANGUL SYLLABLE SIOS OE + 0xBCE9: 0xC1E4, //HANGUL SYLLABLE SIOS OE NIEUN + 0xBCEA: 0xC1E8, //HANGUL SYLLABLE SIOS OE RIEUL + 0xBCEB: 0xC1F0, //HANGUL SYLLABLE SIOS OE MIEUM + 0xBCEC: 0xC1F1, //HANGUL SYLLABLE SIOS OE PIEUP + 0xBCED: 0xC1F3, //HANGUL SYLLABLE SIOS OE SIOS + 0xBCEE: 0xC1FC, //HANGUL SYLLABLE SIOS YO + 0xBCEF: 0xC1FD, //HANGUL SYLLABLE SIOS YO KIYEOK + 0xBCF0: 0xC200, //HANGUL SYLLABLE SIOS YO NIEUN + 0xBCF1: 0xC204, //HANGUL SYLLABLE SIOS YO RIEUL + 0xBCF2: 0xC20C, //HANGUL SYLLABLE SIOS YO MIEUM + 0xBCF3: 0xC20D, //HANGUL SYLLABLE SIOS YO PIEUP + 0xBCF4: 0xC20F, //HANGUL SYLLABLE SIOS YO SIOS + 0xBCF5: 0xC211, //HANGUL SYLLABLE SIOS YO IEUNG + 0xBCF6: 0xC218, //HANGUL SYLLABLE SIOS U + 0xBCF7: 0xC219, //HANGUL SYLLABLE SIOS U KIYEOK + 0xBCF8: 0xC21C, //HANGUL SYLLABLE SIOS U NIEUN + 0xBCF9: 0xC21F, //HANGUL SYLLABLE SIOS U TIKEUT + 0xBCFA: 0xC220, //HANGUL SYLLABLE SIOS U RIEUL + 0xBCFB: 0xC228, //HANGUL SYLLABLE SIOS U MIEUM + 0xBCFC: 0xC229, //HANGUL SYLLABLE SIOS U PIEUP + 0xBCFD: 0xC22B, //HANGUL SYLLABLE SIOS U SIOS + 0xBCFE: 0xC22D, //HANGUL SYLLABLE SIOS U IEUNG + 0xBD41: 0xD3D7, //HANGUL SYLLABLE PHIEUPH YE TIKEUT + 0xBD42: 0xD3D9, //HANGUL SYLLABLE PHIEUPH YE RIEULKIYEOK + 0xBD43: 0xD3DA, //HANGUL SYLLABLE PHIEUPH YE RIEULMIEUM + 0xBD44: 0xD3DB, //HANGUL SYLLABLE PHIEUPH YE RIEULPIEUP + 0xBD45: 0xD3DC, //HANGUL SYLLABLE PHIEUPH YE RIEULSIOS + 0xBD46: 0xD3DD, //HANGUL SYLLABLE PHIEUPH YE RIEULTHIEUTH + 0xBD47: 0xD3DE, //HANGUL SYLLABLE PHIEUPH YE RIEULPHIEUPH + 0xBD48: 0xD3DF, //HANGUL SYLLABLE PHIEUPH YE RIEULHIEUH + 0xBD49: 0xD3E0, //HANGUL SYLLABLE PHIEUPH YE MIEUM + 0xBD4A: 0xD3E2, //HANGUL SYLLABLE PHIEUPH YE PIEUPSIOS + 0xBD4B: 0xD3E4, //HANGUL SYLLABLE PHIEUPH YE SSANGSIOS + 0xBD4C: 0xD3E5, //HANGUL SYLLABLE PHIEUPH YE IEUNG + 0xBD4D: 0xD3E6, //HANGUL SYLLABLE PHIEUPH YE CIEUC + 0xBD4E: 0xD3E7, //HANGUL SYLLABLE PHIEUPH YE CHIEUCH + 0xBD4F: 0xD3E8, //HANGUL SYLLABLE PHIEUPH YE KHIEUKH + 0xBD50: 0xD3E9, //HANGUL SYLLABLE PHIEUPH YE THIEUTH + 0xBD51: 0xD3EA, //HANGUL SYLLABLE PHIEUPH YE PHIEUPH + 0xBD52: 0xD3EB, //HANGUL SYLLABLE PHIEUPH YE HIEUH + 0xBD53: 0xD3EE, //HANGUL SYLLABLE PHIEUPH O SSANGKIYEOK + 0xBD54: 0xD3EF, //HANGUL SYLLABLE PHIEUPH O KIYEOKSIOS + 0xBD55: 0xD3F1, //HANGUL SYLLABLE PHIEUPH O NIEUNCIEUC + 0xBD56: 0xD3F2, //HANGUL SYLLABLE PHIEUPH O NIEUNHIEUH + 0xBD57: 0xD3F3, //HANGUL SYLLABLE PHIEUPH O TIKEUT + 0xBD58: 0xD3F5, //HANGUL SYLLABLE PHIEUPH O RIEULKIYEOK + 0xBD59: 0xD3F6, //HANGUL SYLLABLE PHIEUPH O RIEULMIEUM + 0xBD5A: 0xD3F7, //HANGUL SYLLABLE PHIEUPH O RIEULPIEUP + 0xBD61: 0xD3F8, //HANGUL SYLLABLE PHIEUPH O RIEULSIOS + 0xBD62: 0xD3F9, //HANGUL SYLLABLE PHIEUPH O RIEULTHIEUTH + 0xBD63: 0xD3FA, //HANGUL SYLLABLE PHIEUPH O RIEULPHIEUPH + 0xBD64: 0xD3FB, //HANGUL SYLLABLE PHIEUPH O RIEULHIEUH + 0xBD65: 0xD3FE, //HANGUL SYLLABLE PHIEUPH O PIEUPSIOS + 0xBD66: 0xD400, //HANGUL SYLLABLE PHIEUPH O SSANGSIOS + 0xBD67: 0xD402, //HANGUL SYLLABLE PHIEUPH O CIEUC + 0xBD68: 0xD403, //HANGUL SYLLABLE PHIEUPH O CHIEUCH + 0xBD69: 0xD404, //HANGUL SYLLABLE PHIEUPH O KHIEUKH + 0xBD6A: 0xD405, //HANGUL SYLLABLE PHIEUPH O THIEUTH + 0xBD6B: 0xD406, //HANGUL SYLLABLE PHIEUPH O PHIEUPH + 0xBD6C: 0xD407, //HANGUL SYLLABLE PHIEUPH O HIEUH + 0xBD6D: 0xD409, //HANGUL SYLLABLE PHIEUPH WA KIYEOK + 0xBD6E: 0xD40A, //HANGUL SYLLABLE PHIEUPH WA SSANGKIYEOK + 0xBD6F: 0xD40B, //HANGUL SYLLABLE PHIEUPH WA KIYEOKSIOS + 0xBD70: 0xD40C, //HANGUL SYLLABLE PHIEUPH WA NIEUN + 0xBD71: 0xD40D, //HANGUL SYLLABLE PHIEUPH WA NIEUNCIEUC + 0xBD72: 0xD40E, //HANGUL SYLLABLE PHIEUPH WA NIEUNHIEUH + 0xBD73: 0xD40F, //HANGUL SYLLABLE PHIEUPH WA TIKEUT + 0xBD74: 0xD410, //HANGUL SYLLABLE PHIEUPH WA RIEUL + 0xBD75: 0xD411, //HANGUL SYLLABLE PHIEUPH WA RIEULKIYEOK + 0xBD76: 0xD412, //HANGUL SYLLABLE PHIEUPH WA RIEULMIEUM + 0xBD77: 0xD413, //HANGUL SYLLABLE PHIEUPH WA RIEULPIEUP + 0xBD78: 0xD414, //HANGUL SYLLABLE PHIEUPH WA RIEULSIOS + 0xBD79: 0xD415, //HANGUL SYLLABLE PHIEUPH WA RIEULTHIEUTH + 0xBD7A: 0xD416, //HANGUL SYLLABLE PHIEUPH WA RIEULPHIEUPH + 0xBD81: 0xD417, //HANGUL SYLLABLE PHIEUPH WA RIEULHIEUH + 0xBD82: 0xD418, //HANGUL SYLLABLE PHIEUPH WA MIEUM + 0xBD83: 0xD419, //HANGUL SYLLABLE PHIEUPH WA PIEUP + 0xBD84: 0xD41A, //HANGUL SYLLABLE PHIEUPH WA PIEUPSIOS + 0xBD85: 0xD41B, //HANGUL SYLLABLE PHIEUPH WA SIOS + 0xBD86: 0xD41C, //HANGUL SYLLABLE PHIEUPH WA SSANGSIOS + 0xBD87: 0xD41E, //HANGUL SYLLABLE PHIEUPH WA CIEUC + 0xBD88: 0xD41F, //HANGUL SYLLABLE PHIEUPH WA CHIEUCH + 0xBD89: 0xD420, //HANGUL SYLLABLE PHIEUPH WA KHIEUKH + 0xBD8A: 0xD421, //HANGUL SYLLABLE PHIEUPH WA THIEUTH + 0xBD8B: 0xD422, //HANGUL SYLLABLE PHIEUPH WA PHIEUPH + 0xBD8C: 0xD423, //HANGUL SYLLABLE PHIEUPH WA HIEUH + 0xBD8D: 0xD424, //HANGUL SYLLABLE PHIEUPH WAE + 0xBD8E: 0xD425, //HANGUL SYLLABLE PHIEUPH WAE KIYEOK + 0xBD8F: 0xD426, //HANGUL SYLLABLE PHIEUPH WAE SSANGKIYEOK + 0xBD90: 0xD427, //HANGUL SYLLABLE PHIEUPH WAE KIYEOKSIOS + 0xBD91: 0xD428, //HANGUL SYLLABLE PHIEUPH WAE NIEUN + 0xBD92: 0xD429, //HANGUL SYLLABLE PHIEUPH WAE NIEUNCIEUC + 0xBD93: 0xD42A, //HANGUL SYLLABLE PHIEUPH WAE NIEUNHIEUH + 0xBD94: 0xD42B, //HANGUL SYLLABLE PHIEUPH WAE TIKEUT + 0xBD95: 0xD42C, //HANGUL SYLLABLE PHIEUPH WAE RIEUL + 0xBD96: 0xD42D, //HANGUL SYLLABLE PHIEUPH WAE RIEULKIYEOK + 0xBD97: 0xD42E, //HANGUL SYLLABLE PHIEUPH WAE RIEULMIEUM + 0xBD98: 0xD42F, //HANGUL SYLLABLE PHIEUPH WAE RIEULPIEUP + 0xBD99: 0xD430, //HANGUL SYLLABLE PHIEUPH WAE RIEULSIOS + 0xBD9A: 0xD431, //HANGUL SYLLABLE PHIEUPH WAE RIEULTHIEUTH + 0xBD9B: 0xD432, //HANGUL SYLLABLE PHIEUPH WAE RIEULPHIEUPH + 0xBD9C: 0xD433, //HANGUL SYLLABLE PHIEUPH WAE RIEULHIEUH + 0xBD9D: 0xD434, //HANGUL SYLLABLE PHIEUPH WAE MIEUM + 0xBD9E: 0xD435, //HANGUL SYLLABLE PHIEUPH WAE PIEUP + 0xBD9F: 0xD436, //HANGUL SYLLABLE PHIEUPH WAE PIEUPSIOS + 0xBDA0: 0xD437, //HANGUL SYLLABLE PHIEUPH WAE SIOS + 0xBDA1: 0xC22F, //HANGUL SYLLABLE SIOS U CHIEUCH + 0xBDA2: 0xC231, //HANGUL SYLLABLE SIOS U THIEUTH + 0xBDA3: 0xC232, //HANGUL SYLLABLE SIOS U PHIEUPH + 0xBDA4: 0xC234, //HANGUL SYLLABLE SIOS WEO + 0xBDA5: 0xC248, //HANGUL SYLLABLE SIOS WEO SSANGSIOS + 0xBDA6: 0xC250, //HANGUL SYLLABLE SIOS WE + 0xBDA7: 0xC251, //HANGUL SYLLABLE SIOS WE KIYEOK + 0xBDA8: 0xC254, //HANGUL SYLLABLE SIOS WE NIEUN + 0xBDA9: 0xC258, //HANGUL SYLLABLE SIOS WE RIEUL + 0xBDAA: 0xC260, //HANGUL SYLLABLE SIOS WE MIEUM + 0xBDAB: 0xC265, //HANGUL SYLLABLE SIOS WE IEUNG + 0xBDAC: 0xC26C, //HANGUL SYLLABLE SIOS WI + 0xBDAD: 0xC26D, //HANGUL SYLLABLE SIOS WI KIYEOK + 0xBDAE: 0xC270, //HANGUL SYLLABLE SIOS WI NIEUN + 0xBDAF: 0xC274, //HANGUL SYLLABLE SIOS WI RIEUL + 0xBDB0: 0xC27C, //HANGUL SYLLABLE SIOS WI MIEUM + 0xBDB1: 0xC27D, //HANGUL SYLLABLE SIOS WI PIEUP + 0xBDB2: 0xC27F, //HANGUL SYLLABLE SIOS WI SIOS + 0xBDB3: 0xC281, //HANGUL SYLLABLE SIOS WI IEUNG + 0xBDB4: 0xC288, //HANGUL SYLLABLE SIOS YU + 0xBDB5: 0xC289, //HANGUL SYLLABLE SIOS YU KIYEOK + 0xBDB6: 0xC290, //HANGUL SYLLABLE SIOS YU RIEUL + 0xBDB7: 0xC298, //HANGUL SYLLABLE SIOS YU MIEUM + 0xBDB8: 0xC29B, //HANGUL SYLLABLE SIOS YU SIOS + 0xBDB9: 0xC29D, //HANGUL SYLLABLE SIOS YU IEUNG + 0xBDBA: 0xC2A4, //HANGUL SYLLABLE SIOS EU + 0xBDBB: 0xC2A5, //HANGUL SYLLABLE SIOS EU KIYEOK + 0xBDBC: 0xC2A8, //HANGUL SYLLABLE SIOS EU NIEUN + 0xBDBD: 0xC2AC, //HANGUL SYLLABLE SIOS EU RIEUL + 0xBDBE: 0xC2AD, //HANGUL SYLLABLE SIOS EU RIEULKIYEOK + 0xBDBF: 0xC2B4, //HANGUL SYLLABLE SIOS EU MIEUM + 0xBDC0: 0xC2B5, //HANGUL SYLLABLE SIOS EU PIEUP + 0xBDC1: 0xC2B7, //HANGUL SYLLABLE SIOS EU SIOS + 0xBDC2: 0xC2B9, //HANGUL SYLLABLE SIOS EU IEUNG + 0xBDC3: 0xC2DC, //HANGUL SYLLABLE SIOS I + 0xBDC4: 0xC2DD, //HANGUL SYLLABLE SIOS I KIYEOK + 0xBDC5: 0xC2E0, //HANGUL SYLLABLE SIOS I NIEUN + 0xBDC6: 0xC2E3, //HANGUL SYLLABLE SIOS I TIKEUT + 0xBDC7: 0xC2E4, //HANGUL SYLLABLE SIOS I RIEUL + 0xBDC8: 0xC2EB, //HANGUL SYLLABLE SIOS I RIEULHIEUH + 0xBDC9: 0xC2EC, //HANGUL SYLLABLE SIOS I MIEUM + 0xBDCA: 0xC2ED, //HANGUL SYLLABLE SIOS I PIEUP + 0xBDCB: 0xC2EF, //HANGUL SYLLABLE SIOS I SIOS + 0xBDCC: 0xC2F1, //HANGUL SYLLABLE SIOS I IEUNG + 0xBDCD: 0xC2F6, //HANGUL SYLLABLE SIOS I PHIEUPH + 0xBDCE: 0xC2F8, //HANGUL SYLLABLE SSANGSIOS A + 0xBDCF: 0xC2F9, //HANGUL SYLLABLE SSANGSIOS A KIYEOK + 0xBDD0: 0xC2FB, //HANGUL SYLLABLE SSANGSIOS A KIYEOKSIOS + 0xBDD1: 0xC2FC, //HANGUL SYLLABLE SSANGSIOS A NIEUN + 0xBDD2: 0xC300, //HANGUL SYLLABLE SSANGSIOS A RIEUL + 0xBDD3: 0xC308, //HANGUL SYLLABLE SSANGSIOS A MIEUM + 0xBDD4: 0xC309, //HANGUL SYLLABLE SSANGSIOS A PIEUP + 0xBDD5: 0xC30C, //HANGUL SYLLABLE SSANGSIOS A SSANGSIOS + 0xBDD6: 0xC30D, //HANGUL SYLLABLE SSANGSIOS A IEUNG + 0xBDD7: 0xC313, //HANGUL SYLLABLE SSANGSIOS A HIEUH + 0xBDD8: 0xC314, //HANGUL SYLLABLE SSANGSIOS AE + 0xBDD9: 0xC315, //HANGUL SYLLABLE SSANGSIOS AE KIYEOK + 0xBDDA: 0xC318, //HANGUL SYLLABLE SSANGSIOS AE NIEUN + 0xBDDB: 0xC31C, //HANGUL SYLLABLE SSANGSIOS AE RIEUL + 0xBDDC: 0xC324, //HANGUL SYLLABLE SSANGSIOS AE MIEUM + 0xBDDD: 0xC325, //HANGUL SYLLABLE SSANGSIOS AE PIEUP + 0xBDDE: 0xC328, //HANGUL SYLLABLE SSANGSIOS AE SSANGSIOS + 0xBDDF: 0xC329, //HANGUL SYLLABLE SSANGSIOS AE IEUNG + 0xBDE0: 0xC345, //HANGUL SYLLABLE SSANGSIOS YA IEUNG + 0xBDE1: 0xC368, //HANGUL SYLLABLE SSANGSIOS EO + 0xBDE2: 0xC369, //HANGUL SYLLABLE SSANGSIOS EO KIYEOK + 0xBDE3: 0xC36C, //HANGUL SYLLABLE SSANGSIOS EO NIEUN + 0xBDE4: 0xC370, //HANGUL SYLLABLE SSANGSIOS EO RIEUL + 0xBDE5: 0xC372, //HANGUL SYLLABLE SSANGSIOS EO RIEULMIEUM + 0xBDE6: 0xC378, //HANGUL SYLLABLE SSANGSIOS EO MIEUM + 0xBDE7: 0xC379, //HANGUL SYLLABLE SSANGSIOS EO PIEUP + 0xBDE8: 0xC37C, //HANGUL SYLLABLE SSANGSIOS EO SSANGSIOS + 0xBDE9: 0xC37D, //HANGUL SYLLABLE SSANGSIOS EO IEUNG + 0xBDEA: 0xC384, //HANGUL SYLLABLE SSANGSIOS E + 0xBDEB: 0xC388, //HANGUL SYLLABLE SSANGSIOS E NIEUN + 0xBDEC: 0xC38C, //HANGUL SYLLABLE SSANGSIOS E RIEUL + 0xBDED: 0xC3C0, //HANGUL SYLLABLE SSANGSIOS YE NIEUN + 0xBDEE: 0xC3D8, //HANGUL SYLLABLE SSANGSIOS O + 0xBDEF: 0xC3D9, //HANGUL SYLLABLE SSANGSIOS O KIYEOK + 0xBDF0: 0xC3DC, //HANGUL SYLLABLE SSANGSIOS O NIEUN + 0xBDF1: 0xC3DF, //HANGUL SYLLABLE SSANGSIOS O TIKEUT + 0xBDF2: 0xC3E0, //HANGUL SYLLABLE SSANGSIOS O RIEUL + 0xBDF3: 0xC3E2, //HANGUL SYLLABLE SSANGSIOS O RIEULMIEUM + 0xBDF4: 0xC3E8, //HANGUL SYLLABLE SSANGSIOS O MIEUM + 0xBDF5: 0xC3E9, //HANGUL SYLLABLE SSANGSIOS O PIEUP + 0xBDF6: 0xC3ED, //HANGUL SYLLABLE SSANGSIOS O IEUNG + 0xBDF7: 0xC3F4, //HANGUL SYLLABLE SSANGSIOS WA + 0xBDF8: 0xC3F5, //HANGUL SYLLABLE SSANGSIOS WA KIYEOK + 0xBDF9: 0xC3F8, //HANGUL SYLLABLE SSANGSIOS WA NIEUN + 0xBDFA: 0xC408, //HANGUL SYLLABLE SSANGSIOS WA SSANGSIOS + 0xBDFB: 0xC410, //HANGUL SYLLABLE SSANGSIOS WAE + 0xBDFC: 0xC424, //HANGUL SYLLABLE SSANGSIOS WAE SSANGSIOS + 0xBDFD: 0xC42C, //HANGUL SYLLABLE SSANGSIOS OE + 0xBDFE: 0xC430, //HANGUL SYLLABLE SSANGSIOS OE NIEUN + 0xBE41: 0xD438, //HANGUL SYLLABLE PHIEUPH WAE SSANGSIOS + 0xBE42: 0xD439, //HANGUL SYLLABLE PHIEUPH WAE IEUNG + 0xBE43: 0xD43A, //HANGUL SYLLABLE PHIEUPH WAE CIEUC + 0xBE44: 0xD43B, //HANGUL SYLLABLE PHIEUPH WAE CHIEUCH + 0xBE45: 0xD43C, //HANGUL SYLLABLE PHIEUPH WAE KHIEUKH + 0xBE46: 0xD43D, //HANGUL SYLLABLE PHIEUPH WAE THIEUTH + 0xBE47: 0xD43E, //HANGUL SYLLABLE PHIEUPH WAE PHIEUPH + 0xBE48: 0xD43F, //HANGUL SYLLABLE PHIEUPH WAE HIEUH + 0xBE49: 0xD441, //HANGUL SYLLABLE PHIEUPH OE KIYEOK + 0xBE4A: 0xD442, //HANGUL SYLLABLE PHIEUPH OE SSANGKIYEOK + 0xBE4B: 0xD443, //HANGUL SYLLABLE PHIEUPH OE KIYEOKSIOS + 0xBE4C: 0xD445, //HANGUL SYLLABLE PHIEUPH OE NIEUNCIEUC + 0xBE4D: 0xD446, //HANGUL SYLLABLE PHIEUPH OE NIEUNHIEUH + 0xBE4E: 0xD447, //HANGUL SYLLABLE PHIEUPH OE TIKEUT + 0xBE4F: 0xD448, //HANGUL SYLLABLE PHIEUPH OE RIEUL + 0xBE50: 0xD449, //HANGUL SYLLABLE PHIEUPH OE RIEULKIYEOK + 0xBE51: 0xD44A, //HANGUL SYLLABLE PHIEUPH OE RIEULMIEUM + 0xBE52: 0xD44B, //HANGUL SYLLABLE PHIEUPH OE RIEULPIEUP + 0xBE53: 0xD44C, //HANGUL SYLLABLE PHIEUPH OE RIEULSIOS + 0xBE54: 0xD44D, //HANGUL SYLLABLE PHIEUPH OE RIEULTHIEUTH + 0xBE55: 0xD44E, //HANGUL SYLLABLE PHIEUPH OE RIEULPHIEUPH + 0xBE56: 0xD44F, //HANGUL SYLLABLE PHIEUPH OE RIEULHIEUH + 0xBE57: 0xD450, //HANGUL SYLLABLE PHIEUPH OE MIEUM + 0xBE58: 0xD451, //HANGUL SYLLABLE PHIEUPH OE PIEUP + 0xBE59: 0xD452, //HANGUL SYLLABLE PHIEUPH OE PIEUPSIOS + 0xBE5A: 0xD453, //HANGUL SYLLABLE PHIEUPH OE SIOS + 0xBE61: 0xD454, //HANGUL SYLLABLE PHIEUPH OE SSANGSIOS + 0xBE62: 0xD455, //HANGUL SYLLABLE PHIEUPH OE IEUNG + 0xBE63: 0xD456, //HANGUL SYLLABLE PHIEUPH OE CIEUC + 0xBE64: 0xD457, //HANGUL SYLLABLE PHIEUPH OE CHIEUCH + 0xBE65: 0xD458, //HANGUL SYLLABLE PHIEUPH OE KHIEUKH + 0xBE66: 0xD459, //HANGUL SYLLABLE PHIEUPH OE THIEUTH + 0xBE67: 0xD45A, //HANGUL SYLLABLE PHIEUPH OE PHIEUPH + 0xBE68: 0xD45B, //HANGUL SYLLABLE PHIEUPH OE HIEUH + 0xBE69: 0xD45D, //HANGUL SYLLABLE PHIEUPH YO KIYEOK + 0xBE6A: 0xD45E, //HANGUL SYLLABLE PHIEUPH YO SSANGKIYEOK + 0xBE6B: 0xD45F, //HANGUL SYLLABLE PHIEUPH YO KIYEOKSIOS + 0xBE6C: 0xD461, //HANGUL SYLLABLE PHIEUPH YO NIEUNCIEUC + 0xBE6D: 0xD462, //HANGUL SYLLABLE PHIEUPH YO NIEUNHIEUH + 0xBE6E: 0xD463, //HANGUL SYLLABLE PHIEUPH YO TIKEUT + 0xBE6F: 0xD465, //HANGUL SYLLABLE PHIEUPH YO RIEULKIYEOK + 0xBE70: 0xD466, //HANGUL SYLLABLE PHIEUPH YO RIEULMIEUM + 0xBE71: 0xD467, //HANGUL SYLLABLE PHIEUPH YO RIEULPIEUP + 0xBE72: 0xD468, //HANGUL SYLLABLE PHIEUPH YO RIEULSIOS + 0xBE73: 0xD469, //HANGUL SYLLABLE PHIEUPH YO RIEULTHIEUTH + 0xBE74: 0xD46A, //HANGUL SYLLABLE PHIEUPH YO RIEULPHIEUPH + 0xBE75: 0xD46B, //HANGUL SYLLABLE PHIEUPH YO RIEULHIEUH + 0xBE76: 0xD46C, //HANGUL SYLLABLE PHIEUPH YO MIEUM + 0xBE77: 0xD46E, //HANGUL SYLLABLE PHIEUPH YO PIEUPSIOS + 0xBE78: 0xD470, //HANGUL SYLLABLE PHIEUPH YO SSANGSIOS + 0xBE79: 0xD471, //HANGUL SYLLABLE PHIEUPH YO IEUNG + 0xBE7A: 0xD472, //HANGUL SYLLABLE PHIEUPH YO CIEUC + 0xBE81: 0xD473, //HANGUL SYLLABLE PHIEUPH YO CHIEUCH + 0xBE82: 0xD474, //HANGUL SYLLABLE PHIEUPH YO KHIEUKH + 0xBE83: 0xD475, //HANGUL SYLLABLE PHIEUPH YO THIEUTH + 0xBE84: 0xD476, //HANGUL SYLLABLE PHIEUPH YO PHIEUPH + 0xBE85: 0xD477, //HANGUL SYLLABLE PHIEUPH YO HIEUH + 0xBE86: 0xD47A, //HANGUL SYLLABLE PHIEUPH U SSANGKIYEOK + 0xBE87: 0xD47B, //HANGUL SYLLABLE PHIEUPH U KIYEOKSIOS + 0xBE88: 0xD47D, //HANGUL SYLLABLE PHIEUPH U NIEUNCIEUC + 0xBE89: 0xD47E, //HANGUL SYLLABLE PHIEUPH U NIEUNHIEUH + 0xBE8A: 0xD481, //HANGUL SYLLABLE PHIEUPH U RIEULKIYEOK + 0xBE8B: 0xD483, //HANGUL SYLLABLE PHIEUPH U RIEULPIEUP + 0xBE8C: 0xD484, //HANGUL SYLLABLE PHIEUPH U RIEULSIOS + 0xBE8D: 0xD485, //HANGUL SYLLABLE PHIEUPH U RIEULTHIEUTH + 0xBE8E: 0xD486, //HANGUL SYLLABLE PHIEUPH U RIEULPHIEUPH + 0xBE8F: 0xD487, //HANGUL SYLLABLE PHIEUPH U RIEULHIEUH + 0xBE90: 0xD48A, //HANGUL SYLLABLE PHIEUPH U PIEUPSIOS + 0xBE91: 0xD48C, //HANGUL SYLLABLE PHIEUPH U SSANGSIOS + 0xBE92: 0xD48E, //HANGUL SYLLABLE PHIEUPH U CIEUC + 0xBE93: 0xD48F, //HANGUL SYLLABLE PHIEUPH U CHIEUCH + 0xBE94: 0xD490, //HANGUL SYLLABLE PHIEUPH U KHIEUKH + 0xBE95: 0xD491, //HANGUL SYLLABLE PHIEUPH U THIEUTH + 0xBE96: 0xD492, //HANGUL SYLLABLE PHIEUPH U PHIEUPH + 0xBE97: 0xD493, //HANGUL SYLLABLE PHIEUPH U HIEUH + 0xBE98: 0xD495, //HANGUL SYLLABLE PHIEUPH WEO KIYEOK + 0xBE99: 0xD496, //HANGUL SYLLABLE PHIEUPH WEO SSANGKIYEOK + 0xBE9A: 0xD497, //HANGUL SYLLABLE PHIEUPH WEO KIYEOKSIOS + 0xBE9B: 0xD498, //HANGUL SYLLABLE PHIEUPH WEO NIEUN + 0xBE9C: 0xD499, //HANGUL SYLLABLE PHIEUPH WEO NIEUNCIEUC + 0xBE9D: 0xD49A, //HANGUL SYLLABLE PHIEUPH WEO NIEUNHIEUH + 0xBE9E: 0xD49B, //HANGUL SYLLABLE PHIEUPH WEO TIKEUT + 0xBE9F: 0xD49C, //HANGUL SYLLABLE PHIEUPH WEO RIEUL + 0xBEA0: 0xD49D, //HANGUL SYLLABLE PHIEUPH WEO RIEULKIYEOK + 0xBEA1: 0xC434, //HANGUL SYLLABLE SSANGSIOS OE RIEUL + 0xBEA2: 0xC43C, //HANGUL SYLLABLE SSANGSIOS OE MIEUM + 0xBEA3: 0xC43D, //HANGUL SYLLABLE SSANGSIOS OE PIEUP + 0xBEA4: 0xC448, //HANGUL SYLLABLE SSANGSIOS YO + 0xBEA5: 0xC464, //HANGUL SYLLABLE SSANGSIOS U + 0xBEA6: 0xC465, //HANGUL SYLLABLE SSANGSIOS U KIYEOK + 0xBEA7: 0xC468, //HANGUL SYLLABLE SSANGSIOS U NIEUN + 0xBEA8: 0xC46C, //HANGUL SYLLABLE SSANGSIOS U RIEUL + 0xBEA9: 0xC474, //HANGUL SYLLABLE SSANGSIOS U MIEUM + 0xBEAA: 0xC475, //HANGUL SYLLABLE SSANGSIOS U PIEUP + 0xBEAB: 0xC479, //HANGUL SYLLABLE SSANGSIOS U IEUNG + 0xBEAC: 0xC480, //HANGUL SYLLABLE SSANGSIOS WEO + 0xBEAD: 0xC494, //HANGUL SYLLABLE SSANGSIOS WEO SSANGSIOS + 0xBEAE: 0xC49C, //HANGUL SYLLABLE SSANGSIOS WE + 0xBEAF: 0xC4B8, //HANGUL SYLLABLE SSANGSIOS WI + 0xBEB0: 0xC4BC, //HANGUL SYLLABLE SSANGSIOS WI NIEUN + 0xBEB1: 0xC4E9, //HANGUL SYLLABLE SSANGSIOS YU IEUNG + 0xBEB2: 0xC4F0, //HANGUL SYLLABLE SSANGSIOS EU + 0xBEB3: 0xC4F1, //HANGUL SYLLABLE SSANGSIOS EU KIYEOK + 0xBEB4: 0xC4F4, //HANGUL SYLLABLE SSANGSIOS EU NIEUN + 0xBEB5: 0xC4F8, //HANGUL SYLLABLE SSANGSIOS EU RIEUL + 0xBEB6: 0xC4FA, //HANGUL SYLLABLE SSANGSIOS EU RIEULMIEUM + 0xBEB7: 0xC4FF, //HANGUL SYLLABLE SSANGSIOS EU RIEULHIEUH + 0xBEB8: 0xC500, //HANGUL SYLLABLE SSANGSIOS EU MIEUM + 0xBEB9: 0xC501, //HANGUL SYLLABLE SSANGSIOS EU PIEUP + 0xBEBA: 0xC50C, //HANGUL SYLLABLE SSANGSIOS YI + 0xBEBB: 0xC510, //HANGUL SYLLABLE SSANGSIOS YI NIEUN + 0xBEBC: 0xC514, //HANGUL SYLLABLE SSANGSIOS YI RIEUL + 0xBEBD: 0xC51C, //HANGUL SYLLABLE SSANGSIOS YI MIEUM + 0xBEBE: 0xC528, //HANGUL SYLLABLE SSANGSIOS I + 0xBEBF: 0xC529, //HANGUL SYLLABLE SSANGSIOS I KIYEOK + 0xBEC0: 0xC52C, //HANGUL SYLLABLE SSANGSIOS I NIEUN + 0xBEC1: 0xC530, //HANGUL SYLLABLE SSANGSIOS I RIEUL + 0xBEC2: 0xC538, //HANGUL SYLLABLE SSANGSIOS I MIEUM + 0xBEC3: 0xC539, //HANGUL SYLLABLE SSANGSIOS I PIEUP + 0xBEC4: 0xC53B, //HANGUL SYLLABLE SSANGSIOS I SIOS + 0xBEC5: 0xC53D, //HANGUL SYLLABLE SSANGSIOS I IEUNG + 0xBEC6: 0xC544, //HANGUL SYLLABLE IEUNG A + 0xBEC7: 0xC545, //HANGUL SYLLABLE IEUNG A KIYEOK + 0xBEC8: 0xC548, //HANGUL SYLLABLE IEUNG A NIEUN + 0xBEC9: 0xC549, //HANGUL SYLLABLE IEUNG A NIEUNCIEUC + 0xBECA: 0xC54A, //HANGUL SYLLABLE IEUNG A NIEUNHIEUH + 0xBECB: 0xC54C, //HANGUL SYLLABLE IEUNG A RIEUL + 0xBECC: 0xC54D, //HANGUL SYLLABLE IEUNG A RIEULKIYEOK + 0xBECD: 0xC54E, //HANGUL SYLLABLE IEUNG A RIEULMIEUM + 0xBECE: 0xC553, //HANGUL SYLLABLE IEUNG A RIEULHIEUH + 0xBECF: 0xC554, //HANGUL SYLLABLE IEUNG A MIEUM + 0xBED0: 0xC555, //HANGUL SYLLABLE IEUNG A PIEUP + 0xBED1: 0xC557, //HANGUL SYLLABLE IEUNG A SIOS + 0xBED2: 0xC558, //HANGUL SYLLABLE IEUNG A SSANGSIOS + 0xBED3: 0xC559, //HANGUL SYLLABLE IEUNG A IEUNG + 0xBED4: 0xC55D, //HANGUL SYLLABLE IEUNG A THIEUTH + 0xBED5: 0xC55E, //HANGUL SYLLABLE IEUNG A PHIEUPH + 0xBED6: 0xC560, //HANGUL SYLLABLE IEUNG AE + 0xBED7: 0xC561, //HANGUL SYLLABLE IEUNG AE KIYEOK + 0xBED8: 0xC564, //HANGUL SYLLABLE IEUNG AE NIEUN + 0xBED9: 0xC568, //HANGUL SYLLABLE IEUNG AE RIEUL + 0xBEDA: 0xC570, //HANGUL SYLLABLE IEUNG AE MIEUM + 0xBEDB: 0xC571, //HANGUL SYLLABLE IEUNG AE PIEUP + 0xBEDC: 0xC573, //HANGUL SYLLABLE IEUNG AE SIOS + 0xBEDD: 0xC574, //HANGUL SYLLABLE IEUNG AE SSANGSIOS + 0xBEDE: 0xC575, //HANGUL SYLLABLE IEUNG AE IEUNG + 0xBEDF: 0xC57C, //HANGUL SYLLABLE IEUNG YA + 0xBEE0: 0xC57D, //HANGUL SYLLABLE IEUNG YA KIYEOK + 0xBEE1: 0xC580, //HANGUL SYLLABLE IEUNG YA NIEUN + 0xBEE2: 0xC584, //HANGUL SYLLABLE IEUNG YA RIEUL + 0xBEE3: 0xC587, //HANGUL SYLLABLE IEUNG YA RIEULPIEUP + 0xBEE4: 0xC58C, //HANGUL SYLLABLE IEUNG YA MIEUM + 0xBEE5: 0xC58D, //HANGUL SYLLABLE IEUNG YA PIEUP + 0xBEE6: 0xC58F, //HANGUL SYLLABLE IEUNG YA SIOS + 0xBEE7: 0xC591, //HANGUL SYLLABLE IEUNG YA IEUNG + 0xBEE8: 0xC595, //HANGUL SYLLABLE IEUNG YA THIEUTH + 0xBEE9: 0xC597, //HANGUL SYLLABLE IEUNG YA HIEUH + 0xBEEA: 0xC598, //HANGUL SYLLABLE IEUNG YAE + 0xBEEB: 0xC59C, //HANGUL SYLLABLE IEUNG YAE NIEUN + 0xBEEC: 0xC5A0, //HANGUL SYLLABLE IEUNG YAE RIEUL + 0xBEED: 0xC5A9, //HANGUL SYLLABLE IEUNG YAE PIEUP + 0xBEEE: 0xC5B4, //HANGUL SYLLABLE IEUNG EO + 0xBEEF: 0xC5B5, //HANGUL SYLLABLE IEUNG EO KIYEOK + 0xBEF0: 0xC5B8, //HANGUL SYLLABLE IEUNG EO NIEUN + 0xBEF1: 0xC5B9, //HANGUL SYLLABLE IEUNG EO NIEUNCIEUC + 0xBEF2: 0xC5BB, //HANGUL SYLLABLE IEUNG EO TIKEUT + 0xBEF3: 0xC5BC, //HANGUL SYLLABLE IEUNG EO RIEUL + 0xBEF4: 0xC5BD, //HANGUL SYLLABLE IEUNG EO RIEULKIYEOK + 0xBEF5: 0xC5BE, //HANGUL SYLLABLE IEUNG EO RIEULMIEUM + 0xBEF6: 0xC5C4, //HANGUL SYLLABLE IEUNG EO MIEUM + 0xBEF7: 0xC5C5, //HANGUL SYLLABLE IEUNG EO PIEUP + 0xBEF8: 0xC5C6, //HANGUL SYLLABLE IEUNG EO PIEUPSIOS + 0xBEF9: 0xC5C7, //HANGUL SYLLABLE IEUNG EO SIOS + 0xBEFA: 0xC5C8, //HANGUL SYLLABLE IEUNG EO SSANGSIOS + 0xBEFB: 0xC5C9, //HANGUL SYLLABLE IEUNG EO IEUNG + 0xBEFC: 0xC5CA, //HANGUL SYLLABLE IEUNG EO CIEUC + 0xBEFD: 0xC5CC, //HANGUL SYLLABLE IEUNG EO KHIEUKH + 0xBEFE: 0xC5CE, //HANGUL SYLLABLE IEUNG EO PHIEUPH + 0xBF41: 0xD49E, //HANGUL SYLLABLE PHIEUPH WEO RIEULMIEUM + 0xBF42: 0xD49F, //HANGUL SYLLABLE PHIEUPH WEO RIEULPIEUP + 0xBF43: 0xD4A0, //HANGUL SYLLABLE PHIEUPH WEO RIEULSIOS + 0xBF44: 0xD4A1, //HANGUL SYLLABLE PHIEUPH WEO RIEULTHIEUTH + 0xBF45: 0xD4A2, //HANGUL SYLLABLE PHIEUPH WEO RIEULPHIEUPH + 0xBF46: 0xD4A3, //HANGUL SYLLABLE PHIEUPH WEO RIEULHIEUH + 0xBF47: 0xD4A4, //HANGUL SYLLABLE PHIEUPH WEO MIEUM + 0xBF48: 0xD4A5, //HANGUL SYLLABLE PHIEUPH WEO PIEUP + 0xBF49: 0xD4A6, //HANGUL SYLLABLE PHIEUPH WEO PIEUPSIOS + 0xBF4A: 0xD4A7, //HANGUL SYLLABLE PHIEUPH WEO SIOS + 0xBF4B: 0xD4A8, //HANGUL SYLLABLE PHIEUPH WEO SSANGSIOS + 0xBF4C: 0xD4AA, //HANGUL SYLLABLE PHIEUPH WEO CIEUC + 0xBF4D: 0xD4AB, //HANGUL SYLLABLE PHIEUPH WEO CHIEUCH + 0xBF4E: 0xD4AC, //HANGUL SYLLABLE PHIEUPH WEO KHIEUKH + 0xBF4F: 0xD4AD, //HANGUL SYLLABLE PHIEUPH WEO THIEUTH + 0xBF50: 0xD4AE, //HANGUL SYLLABLE PHIEUPH WEO PHIEUPH + 0xBF51: 0xD4AF, //HANGUL SYLLABLE PHIEUPH WEO HIEUH + 0xBF52: 0xD4B0, //HANGUL SYLLABLE PHIEUPH WE + 0xBF53: 0xD4B1, //HANGUL SYLLABLE PHIEUPH WE KIYEOK + 0xBF54: 0xD4B2, //HANGUL SYLLABLE PHIEUPH WE SSANGKIYEOK + 0xBF55: 0xD4B3, //HANGUL SYLLABLE PHIEUPH WE KIYEOKSIOS + 0xBF56: 0xD4B4, //HANGUL SYLLABLE PHIEUPH WE NIEUN + 0xBF57: 0xD4B5, //HANGUL SYLLABLE PHIEUPH WE NIEUNCIEUC + 0xBF58: 0xD4B6, //HANGUL SYLLABLE PHIEUPH WE NIEUNHIEUH + 0xBF59: 0xD4B7, //HANGUL SYLLABLE PHIEUPH WE TIKEUT + 0xBF5A: 0xD4B8, //HANGUL SYLLABLE PHIEUPH WE RIEUL + 0xBF61: 0xD4B9, //HANGUL SYLLABLE PHIEUPH WE RIEULKIYEOK + 0xBF62: 0xD4BA, //HANGUL SYLLABLE PHIEUPH WE RIEULMIEUM + 0xBF63: 0xD4BB, //HANGUL SYLLABLE PHIEUPH WE RIEULPIEUP + 0xBF64: 0xD4BC, //HANGUL SYLLABLE PHIEUPH WE RIEULSIOS + 0xBF65: 0xD4BD, //HANGUL SYLLABLE PHIEUPH WE RIEULTHIEUTH + 0xBF66: 0xD4BE, //HANGUL SYLLABLE PHIEUPH WE RIEULPHIEUPH + 0xBF67: 0xD4BF, //HANGUL SYLLABLE PHIEUPH WE RIEULHIEUH + 0xBF68: 0xD4C0, //HANGUL SYLLABLE PHIEUPH WE MIEUM + 0xBF69: 0xD4C1, //HANGUL SYLLABLE PHIEUPH WE PIEUP + 0xBF6A: 0xD4C2, //HANGUL SYLLABLE PHIEUPH WE PIEUPSIOS + 0xBF6B: 0xD4C3, //HANGUL SYLLABLE PHIEUPH WE SIOS + 0xBF6C: 0xD4C4, //HANGUL SYLLABLE PHIEUPH WE SSANGSIOS + 0xBF6D: 0xD4C5, //HANGUL SYLLABLE PHIEUPH WE IEUNG + 0xBF6E: 0xD4C6, //HANGUL SYLLABLE PHIEUPH WE CIEUC + 0xBF6F: 0xD4C7, //HANGUL SYLLABLE PHIEUPH WE CHIEUCH + 0xBF70: 0xD4C8, //HANGUL SYLLABLE PHIEUPH WE KHIEUKH + 0xBF71: 0xD4C9, //HANGUL SYLLABLE PHIEUPH WE THIEUTH + 0xBF72: 0xD4CA, //HANGUL SYLLABLE PHIEUPH WE PHIEUPH + 0xBF73: 0xD4CB, //HANGUL SYLLABLE PHIEUPH WE HIEUH + 0xBF74: 0xD4CD, //HANGUL SYLLABLE PHIEUPH WI KIYEOK + 0xBF75: 0xD4CE, //HANGUL SYLLABLE PHIEUPH WI SSANGKIYEOK + 0xBF76: 0xD4CF, //HANGUL SYLLABLE PHIEUPH WI KIYEOKSIOS + 0xBF77: 0xD4D1, //HANGUL SYLLABLE PHIEUPH WI NIEUNCIEUC + 0xBF78: 0xD4D2, //HANGUL SYLLABLE PHIEUPH WI NIEUNHIEUH + 0xBF79: 0xD4D3, //HANGUL SYLLABLE PHIEUPH WI TIKEUT + 0xBF7A: 0xD4D5, //HANGUL SYLLABLE PHIEUPH WI RIEULKIYEOK + 0xBF81: 0xD4D6, //HANGUL SYLLABLE PHIEUPH WI RIEULMIEUM + 0xBF82: 0xD4D7, //HANGUL SYLLABLE PHIEUPH WI RIEULPIEUP + 0xBF83: 0xD4D8, //HANGUL SYLLABLE PHIEUPH WI RIEULSIOS + 0xBF84: 0xD4D9, //HANGUL SYLLABLE PHIEUPH WI RIEULTHIEUTH + 0xBF85: 0xD4DA, //HANGUL SYLLABLE PHIEUPH WI RIEULPHIEUPH + 0xBF86: 0xD4DB, //HANGUL SYLLABLE PHIEUPH WI RIEULHIEUH + 0xBF87: 0xD4DD, //HANGUL SYLLABLE PHIEUPH WI PIEUP + 0xBF88: 0xD4DE, //HANGUL SYLLABLE PHIEUPH WI PIEUPSIOS + 0xBF89: 0xD4E0, //HANGUL SYLLABLE PHIEUPH WI SSANGSIOS + 0xBF8A: 0xD4E1, //HANGUL SYLLABLE PHIEUPH WI IEUNG + 0xBF8B: 0xD4E2, //HANGUL SYLLABLE PHIEUPH WI CIEUC + 0xBF8C: 0xD4E3, //HANGUL SYLLABLE PHIEUPH WI CHIEUCH + 0xBF8D: 0xD4E4, //HANGUL SYLLABLE PHIEUPH WI KHIEUKH + 0xBF8E: 0xD4E5, //HANGUL SYLLABLE PHIEUPH WI THIEUTH + 0xBF8F: 0xD4E6, //HANGUL SYLLABLE PHIEUPH WI PHIEUPH + 0xBF90: 0xD4E7, //HANGUL SYLLABLE PHIEUPH WI HIEUH + 0xBF91: 0xD4E9, //HANGUL SYLLABLE PHIEUPH YU KIYEOK + 0xBF92: 0xD4EA, //HANGUL SYLLABLE PHIEUPH YU SSANGKIYEOK + 0xBF93: 0xD4EB, //HANGUL SYLLABLE PHIEUPH YU KIYEOKSIOS + 0xBF94: 0xD4ED, //HANGUL SYLLABLE PHIEUPH YU NIEUNCIEUC + 0xBF95: 0xD4EE, //HANGUL SYLLABLE PHIEUPH YU NIEUNHIEUH + 0xBF96: 0xD4EF, //HANGUL SYLLABLE PHIEUPH YU TIKEUT + 0xBF97: 0xD4F1, //HANGUL SYLLABLE PHIEUPH YU RIEULKIYEOK + 0xBF98: 0xD4F2, //HANGUL SYLLABLE PHIEUPH YU RIEULMIEUM + 0xBF99: 0xD4F3, //HANGUL SYLLABLE PHIEUPH YU RIEULPIEUP + 0xBF9A: 0xD4F4, //HANGUL SYLLABLE PHIEUPH YU RIEULSIOS + 0xBF9B: 0xD4F5, //HANGUL SYLLABLE PHIEUPH YU RIEULTHIEUTH + 0xBF9C: 0xD4F6, //HANGUL SYLLABLE PHIEUPH YU RIEULPHIEUPH + 0xBF9D: 0xD4F7, //HANGUL SYLLABLE PHIEUPH YU RIEULHIEUH + 0xBF9E: 0xD4F9, //HANGUL SYLLABLE PHIEUPH YU PIEUP + 0xBF9F: 0xD4FA, //HANGUL SYLLABLE PHIEUPH YU PIEUPSIOS + 0xBFA0: 0xD4FC, //HANGUL SYLLABLE PHIEUPH YU SSANGSIOS + 0xBFA1: 0xC5D0, //HANGUL SYLLABLE IEUNG E + 0xBFA2: 0xC5D1, //HANGUL SYLLABLE IEUNG E KIYEOK + 0xBFA3: 0xC5D4, //HANGUL SYLLABLE IEUNG E NIEUN + 0xBFA4: 0xC5D8, //HANGUL SYLLABLE IEUNG E RIEUL + 0xBFA5: 0xC5E0, //HANGUL SYLLABLE IEUNG E MIEUM + 0xBFA6: 0xC5E1, //HANGUL SYLLABLE IEUNG E PIEUP + 0xBFA7: 0xC5E3, //HANGUL SYLLABLE IEUNG E SIOS + 0xBFA8: 0xC5E5, //HANGUL SYLLABLE IEUNG E IEUNG + 0xBFA9: 0xC5EC, //HANGUL SYLLABLE IEUNG YEO + 0xBFAA: 0xC5ED, //HANGUL SYLLABLE IEUNG YEO KIYEOK + 0xBFAB: 0xC5EE, //HANGUL SYLLABLE IEUNG YEO SSANGKIYEOK + 0xBFAC: 0xC5F0, //HANGUL SYLLABLE IEUNG YEO NIEUN + 0xBFAD: 0xC5F4, //HANGUL SYLLABLE IEUNG YEO RIEUL + 0xBFAE: 0xC5F6, //HANGUL SYLLABLE IEUNG YEO RIEULMIEUM + 0xBFAF: 0xC5F7, //HANGUL SYLLABLE IEUNG YEO RIEULPIEUP + 0xBFB0: 0xC5FC, //HANGUL SYLLABLE IEUNG YEO MIEUM + 0xBFB1: 0xC5FD, //HANGUL SYLLABLE IEUNG YEO PIEUP + 0xBFB2: 0xC5FE, //HANGUL SYLLABLE IEUNG YEO PIEUPSIOS + 0xBFB3: 0xC5FF, //HANGUL SYLLABLE IEUNG YEO SIOS + 0xBFB4: 0xC600, //HANGUL SYLLABLE IEUNG YEO SSANGSIOS + 0xBFB5: 0xC601, //HANGUL SYLLABLE IEUNG YEO IEUNG + 0xBFB6: 0xC605, //HANGUL SYLLABLE IEUNG YEO THIEUTH + 0xBFB7: 0xC606, //HANGUL SYLLABLE IEUNG YEO PHIEUPH + 0xBFB8: 0xC607, //HANGUL SYLLABLE IEUNG YEO HIEUH + 0xBFB9: 0xC608, //HANGUL SYLLABLE IEUNG YE + 0xBFBA: 0xC60C, //HANGUL SYLLABLE IEUNG YE NIEUN + 0xBFBB: 0xC610, //HANGUL SYLLABLE IEUNG YE RIEUL + 0xBFBC: 0xC618, //HANGUL SYLLABLE IEUNG YE MIEUM + 0xBFBD: 0xC619, //HANGUL SYLLABLE IEUNG YE PIEUP + 0xBFBE: 0xC61B, //HANGUL SYLLABLE IEUNG YE SIOS + 0xBFBF: 0xC61C, //HANGUL SYLLABLE IEUNG YE SSANGSIOS + 0xBFC0: 0xC624, //HANGUL SYLLABLE IEUNG O + 0xBFC1: 0xC625, //HANGUL SYLLABLE IEUNG O KIYEOK + 0xBFC2: 0xC628, //HANGUL SYLLABLE IEUNG O NIEUN + 0xBFC3: 0xC62C, //HANGUL SYLLABLE IEUNG O RIEUL + 0xBFC4: 0xC62D, //HANGUL SYLLABLE IEUNG O RIEULKIYEOK + 0xBFC5: 0xC62E, //HANGUL SYLLABLE IEUNG O RIEULMIEUM + 0xBFC6: 0xC630, //HANGUL SYLLABLE IEUNG O RIEULSIOS + 0xBFC7: 0xC633, //HANGUL SYLLABLE IEUNG O RIEULHIEUH + 0xBFC8: 0xC634, //HANGUL SYLLABLE IEUNG O MIEUM + 0xBFC9: 0xC635, //HANGUL SYLLABLE IEUNG O PIEUP + 0xBFCA: 0xC637, //HANGUL SYLLABLE IEUNG O SIOS + 0xBFCB: 0xC639, //HANGUL SYLLABLE IEUNG O IEUNG + 0xBFCC: 0xC63B, //HANGUL SYLLABLE IEUNG O CHIEUCH + 0xBFCD: 0xC640, //HANGUL SYLLABLE IEUNG WA + 0xBFCE: 0xC641, //HANGUL SYLLABLE IEUNG WA KIYEOK + 0xBFCF: 0xC644, //HANGUL SYLLABLE IEUNG WA NIEUN + 0xBFD0: 0xC648, //HANGUL SYLLABLE IEUNG WA RIEUL + 0xBFD1: 0xC650, //HANGUL SYLLABLE IEUNG WA MIEUM + 0xBFD2: 0xC651, //HANGUL SYLLABLE IEUNG WA PIEUP + 0xBFD3: 0xC653, //HANGUL SYLLABLE IEUNG WA SIOS + 0xBFD4: 0xC654, //HANGUL SYLLABLE IEUNG WA SSANGSIOS + 0xBFD5: 0xC655, //HANGUL SYLLABLE IEUNG WA IEUNG + 0xBFD6: 0xC65C, //HANGUL SYLLABLE IEUNG WAE + 0xBFD7: 0xC65D, //HANGUL SYLLABLE IEUNG WAE KIYEOK + 0xBFD8: 0xC660, //HANGUL SYLLABLE IEUNG WAE NIEUN + 0xBFD9: 0xC66C, //HANGUL SYLLABLE IEUNG WAE MIEUM + 0xBFDA: 0xC66F, //HANGUL SYLLABLE IEUNG WAE SIOS + 0xBFDB: 0xC671, //HANGUL SYLLABLE IEUNG WAE IEUNG + 0xBFDC: 0xC678, //HANGUL SYLLABLE IEUNG OE + 0xBFDD: 0xC679, //HANGUL SYLLABLE IEUNG OE KIYEOK + 0xBFDE: 0xC67C, //HANGUL SYLLABLE IEUNG OE NIEUN + 0xBFDF: 0xC680, //HANGUL SYLLABLE IEUNG OE RIEUL + 0xBFE0: 0xC688, //HANGUL SYLLABLE IEUNG OE MIEUM + 0xBFE1: 0xC689, //HANGUL SYLLABLE IEUNG OE PIEUP + 0xBFE2: 0xC68B, //HANGUL SYLLABLE IEUNG OE SIOS + 0xBFE3: 0xC68D, //HANGUL SYLLABLE IEUNG OE IEUNG + 0xBFE4: 0xC694, //HANGUL SYLLABLE IEUNG YO + 0xBFE5: 0xC695, //HANGUL SYLLABLE IEUNG YO KIYEOK + 0xBFE6: 0xC698, //HANGUL SYLLABLE IEUNG YO NIEUN + 0xBFE7: 0xC69C, //HANGUL SYLLABLE IEUNG YO RIEUL + 0xBFE8: 0xC6A4, //HANGUL SYLLABLE IEUNG YO MIEUM + 0xBFE9: 0xC6A5, //HANGUL SYLLABLE IEUNG YO PIEUP + 0xBFEA: 0xC6A7, //HANGUL SYLLABLE IEUNG YO SIOS + 0xBFEB: 0xC6A9, //HANGUL SYLLABLE IEUNG YO IEUNG + 0xBFEC: 0xC6B0, //HANGUL SYLLABLE IEUNG U + 0xBFED: 0xC6B1, //HANGUL SYLLABLE IEUNG U KIYEOK + 0xBFEE: 0xC6B4, //HANGUL SYLLABLE IEUNG U NIEUN + 0xBFEF: 0xC6B8, //HANGUL SYLLABLE IEUNG U RIEUL + 0xBFF0: 0xC6B9, //HANGUL SYLLABLE IEUNG U RIEULKIYEOK + 0xBFF1: 0xC6BA, //HANGUL SYLLABLE IEUNG U RIEULMIEUM + 0xBFF2: 0xC6C0, //HANGUL SYLLABLE IEUNG U MIEUM + 0xBFF3: 0xC6C1, //HANGUL SYLLABLE IEUNG U PIEUP + 0xBFF4: 0xC6C3, //HANGUL SYLLABLE IEUNG U SIOS + 0xBFF5: 0xC6C5, //HANGUL SYLLABLE IEUNG U IEUNG + 0xBFF6: 0xC6CC, //HANGUL SYLLABLE IEUNG WEO + 0xBFF7: 0xC6CD, //HANGUL SYLLABLE IEUNG WEO KIYEOK + 0xBFF8: 0xC6D0, //HANGUL SYLLABLE IEUNG WEO NIEUN + 0xBFF9: 0xC6D4, //HANGUL SYLLABLE IEUNG WEO RIEUL + 0xBFFA: 0xC6DC, //HANGUL SYLLABLE IEUNG WEO MIEUM + 0xBFFB: 0xC6DD, //HANGUL SYLLABLE IEUNG WEO PIEUP + 0xBFFC: 0xC6E0, //HANGUL SYLLABLE IEUNG WEO SSANGSIOS + 0xBFFD: 0xC6E1, //HANGUL SYLLABLE IEUNG WEO IEUNG + 0xBFFE: 0xC6E8, //HANGUL SYLLABLE IEUNG WE + 0xC041: 0xD4FE, //HANGUL SYLLABLE PHIEUPH YU CIEUC + 0xC042: 0xD4FF, //HANGUL SYLLABLE PHIEUPH YU CHIEUCH + 0xC043: 0xD500, //HANGUL SYLLABLE PHIEUPH YU KHIEUKH + 0xC044: 0xD501, //HANGUL SYLLABLE PHIEUPH YU THIEUTH + 0xC045: 0xD502, //HANGUL SYLLABLE PHIEUPH YU PHIEUPH + 0xC046: 0xD503, //HANGUL SYLLABLE PHIEUPH YU HIEUH + 0xC047: 0xD505, //HANGUL SYLLABLE PHIEUPH EU KIYEOK + 0xC048: 0xD506, //HANGUL SYLLABLE PHIEUPH EU SSANGKIYEOK + 0xC049: 0xD507, //HANGUL SYLLABLE PHIEUPH EU KIYEOKSIOS + 0xC04A: 0xD509, //HANGUL SYLLABLE PHIEUPH EU NIEUNCIEUC + 0xC04B: 0xD50A, //HANGUL SYLLABLE PHIEUPH EU NIEUNHIEUH + 0xC04C: 0xD50B, //HANGUL SYLLABLE PHIEUPH EU TIKEUT + 0xC04D: 0xD50D, //HANGUL SYLLABLE PHIEUPH EU RIEULKIYEOK + 0xC04E: 0xD50E, //HANGUL SYLLABLE PHIEUPH EU RIEULMIEUM + 0xC04F: 0xD50F, //HANGUL SYLLABLE PHIEUPH EU RIEULPIEUP + 0xC050: 0xD510, //HANGUL SYLLABLE PHIEUPH EU RIEULSIOS + 0xC051: 0xD511, //HANGUL SYLLABLE PHIEUPH EU RIEULTHIEUTH + 0xC052: 0xD512, //HANGUL SYLLABLE PHIEUPH EU RIEULPHIEUPH + 0xC053: 0xD513, //HANGUL SYLLABLE PHIEUPH EU RIEULHIEUH + 0xC054: 0xD516, //HANGUL SYLLABLE PHIEUPH EU PIEUPSIOS + 0xC055: 0xD518, //HANGUL SYLLABLE PHIEUPH EU SSANGSIOS + 0xC056: 0xD519, //HANGUL SYLLABLE PHIEUPH EU IEUNG + 0xC057: 0xD51A, //HANGUL SYLLABLE PHIEUPH EU CIEUC + 0xC058: 0xD51B, //HANGUL SYLLABLE PHIEUPH EU CHIEUCH + 0xC059: 0xD51C, //HANGUL SYLLABLE PHIEUPH EU KHIEUKH + 0xC05A: 0xD51D, //HANGUL SYLLABLE PHIEUPH EU THIEUTH + 0xC061: 0xD51E, //HANGUL SYLLABLE PHIEUPH EU PHIEUPH + 0xC062: 0xD51F, //HANGUL SYLLABLE PHIEUPH EU HIEUH + 0xC063: 0xD520, //HANGUL SYLLABLE PHIEUPH YI + 0xC064: 0xD521, //HANGUL SYLLABLE PHIEUPH YI KIYEOK + 0xC065: 0xD522, //HANGUL SYLLABLE PHIEUPH YI SSANGKIYEOK + 0xC066: 0xD523, //HANGUL SYLLABLE PHIEUPH YI KIYEOKSIOS + 0xC067: 0xD524, //HANGUL SYLLABLE PHIEUPH YI NIEUN + 0xC068: 0xD525, //HANGUL SYLLABLE PHIEUPH YI NIEUNCIEUC + 0xC069: 0xD526, //HANGUL SYLLABLE PHIEUPH YI NIEUNHIEUH + 0xC06A: 0xD527, //HANGUL SYLLABLE PHIEUPH YI TIKEUT + 0xC06B: 0xD528, //HANGUL SYLLABLE PHIEUPH YI RIEUL + 0xC06C: 0xD529, //HANGUL SYLLABLE PHIEUPH YI RIEULKIYEOK + 0xC06D: 0xD52A, //HANGUL SYLLABLE PHIEUPH YI RIEULMIEUM + 0xC06E: 0xD52B, //HANGUL SYLLABLE PHIEUPH YI RIEULPIEUP + 0xC06F: 0xD52C, //HANGUL SYLLABLE PHIEUPH YI RIEULSIOS + 0xC070: 0xD52D, //HANGUL SYLLABLE PHIEUPH YI RIEULTHIEUTH + 0xC071: 0xD52E, //HANGUL SYLLABLE PHIEUPH YI RIEULPHIEUPH + 0xC072: 0xD52F, //HANGUL SYLLABLE PHIEUPH YI RIEULHIEUH + 0xC073: 0xD530, //HANGUL SYLLABLE PHIEUPH YI MIEUM + 0xC074: 0xD531, //HANGUL SYLLABLE PHIEUPH YI PIEUP + 0xC075: 0xD532, //HANGUL SYLLABLE PHIEUPH YI PIEUPSIOS + 0xC076: 0xD533, //HANGUL SYLLABLE PHIEUPH YI SIOS + 0xC077: 0xD534, //HANGUL SYLLABLE PHIEUPH YI SSANGSIOS + 0xC078: 0xD535, //HANGUL SYLLABLE PHIEUPH YI IEUNG + 0xC079: 0xD536, //HANGUL SYLLABLE PHIEUPH YI CIEUC + 0xC07A: 0xD537, //HANGUL SYLLABLE PHIEUPH YI CHIEUCH + 0xC081: 0xD538, //HANGUL SYLLABLE PHIEUPH YI KHIEUKH + 0xC082: 0xD539, //HANGUL SYLLABLE PHIEUPH YI THIEUTH + 0xC083: 0xD53A, //HANGUL SYLLABLE PHIEUPH YI PHIEUPH + 0xC084: 0xD53B, //HANGUL SYLLABLE PHIEUPH YI HIEUH + 0xC085: 0xD53E, //HANGUL SYLLABLE PHIEUPH I SSANGKIYEOK + 0xC086: 0xD53F, //HANGUL SYLLABLE PHIEUPH I KIYEOKSIOS + 0xC087: 0xD541, //HANGUL SYLLABLE PHIEUPH I NIEUNCIEUC + 0xC088: 0xD542, //HANGUL SYLLABLE PHIEUPH I NIEUNHIEUH + 0xC089: 0xD543, //HANGUL SYLLABLE PHIEUPH I TIKEUT + 0xC08A: 0xD545, //HANGUL SYLLABLE PHIEUPH I RIEULKIYEOK + 0xC08B: 0xD546, //HANGUL SYLLABLE PHIEUPH I RIEULMIEUM + 0xC08C: 0xD547, //HANGUL SYLLABLE PHIEUPH I RIEULPIEUP + 0xC08D: 0xD548, //HANGUL SYLLABLE PHIEUPH I RIEULSIOS + 0xC08E: 0xD549, //HANGUL SYLLABLE PHIEUPH I RIEULTHIEUTH + 0xC08F: 0xD54A, //HANGUL SYLLABLE PHIEUPH I RIEULPHIEUPH + 0xC090: 0xD54B, //HANGUL SYLLABLE PHIEUPH I RIEULHIEUH + 0xC091: 0xD54E, //HANGUL SYLLABLE PHIEUPH I PIEUPSIOS + 0xC092: 0xD550, //HANGUL SYLLABLE PHIEUPH I SSANGSIOS + 0xC093: 0xD552, //HANGUL SYLLABLE PHIEUPH I CIEUC + 0xC094: 0xD553, //HANGUL SYLLABLE PHIEUPH I CHIEUCH + 0xC095: 0xD554, //HANGUL SYLLABLE PHIEUPH I KHIEUKH + 0xC096: 0xD555, //HANGUL SYLLABLE PHIEUPH I THIEUTH + 0xC097: 0xD556, //HANGUL SYLLABLE PHIEUPH I PHIEUPH + 0xC098: 0xD557, //HANGUL SYLLABLE PHIEUPH I HIEUH + 0xC099: 0xD55A, //HANGUL SYLLABLE HIEUH A SSANGKIYEOK + 0xC09A: 0xD55B, //HANGUL SYLLABLE HIEUH A KIYEOKSIOS + 0xC09B: 0xD55D, //HANGUL SYLLABLE HIEUH A NIEUNCIEUC + 0xC09C: 0xD55E, //HANGUL SYLLABLE HIEUH A NIEUNHIEUH + 0xC09D: 0xD55F, //HANGUL SYLLABLE HIEUH A TIKEUT + 0xC09E: 0xD561, //HANGUL SYLLABLE HIEUH A RIEULKIYEOK + 0xC09F: 0xD562, //HANGUL SYLLABLE HIEUH A RIEULMIEUM + 0xC0A0: 0xD563, //HANGUL SYLLABLE HIEUH A RIEULPIEUP + 0xC0A1: 0xC6E9, //HANGUL SYLLABLE IEUNG WE KIYEOK + 0xC0A2: 0xC6EC, //HANGUL SYLLABLE IEUNG WE NIEUN + 0xC0A3: 0xC6F0, //HANGUL SYLLABLE IEUNG WE RIEUL + 0xC0A4: 0xC6F8, //HANGUL SYLLABLE IEUNG WE MIEUM + 0xC0A5: 0xC6F9, //HANGUL SYLLABLE IEUNG WE PIEUP + 0xC0A6: 0xC6FD, //HANGUL SYLLABLE IEUNG WE IEUNG + 0xC0A7: 0xC704, //HANGUL SYLLABLE IEUNG WI + 0xC0A8: 0xC705, //HANGUL SYLLABLE IEUNG WI KIYEOK + 0xC0A9: 0xC708, //HANGUL SYLLABLE IEUNG WI NIEUN + 0xC0AA: 0xC70C, //HANGUL SYLLABLE IEUNG WI RIEUL + 0xC0AB: 0xC714, //HANGUL SYLLABLE IEUNG WI MIEUM + 0xC0AC: 0xC715, //HANGUL SYLLABLE IEUNG WI PIEUP + 0xC0AD: 0xC717, //HANGUL SYLLABLE IEUNG WI SIOS + 0xC0AE: 0xC719, //HANGUL SYLLABLE IEUNG WI IEUNG + 0xC0AF: 0xC720, //HANGUL SYLLABLE IEUNG YU + 0xC0B0: 0xC721, //HANGUL SYLLABLE IEUNG YU KIYEOK + 0xC0B1: 0xC724, //HANGUL SYLLABLE IEUNG YU NIEUN + 0xC0B2: 0xC728, //HANGUL SYLLABLE IEUNG YU RIEUL + 0xC0B3: 0xC730, //HANGUL SYLLABLE IEUNG YU MIEUM + 0xC0B4: 0xC731, //HANGUL SYLLABLE IEUNG YU PIEUP + 0xC0B5: 0xC733, //HANGUL SYLLABLE IEUNG YU SIOS + 0xC0B6: 0xC735, //HANGUL SYLLABLE IEUNG YU IEUNG + 0xC0B7: 0xC737, //HANGUL SYLLABLE IEUNG YU CHIEUCH + 0xC0B8: 0xC73C, //HANGUL SYLLABLE IEUNG EU + 0xC0B9: 0xC73D, //HANGUL SYLLABLE IEUNG EU KIYEOK + 0xC0BA: 0xC740, //HANGUL SYLLABLE IEUNG EU NIEUN + 0xC0BB: 0xC744, //HANGUL SYLLABLE IEUNG EU RIEUL + 0xC0BC: 0xC74A, //HANGUL SYLLABLE IEUNG EU RIEULPHIEUPH + 0xC0BD: 0xC74C, //HANGUL SYLLABLE IEUNG EU MIEUM + 0xC0BE: 0xC74D, //HANGUL SYLLABLE IEUNG EU PIEUP + 0xC0BF: 0xC74F, //HANGUL SYLLABLE IEUNG EU SIOS + 0xC0C0: 0xC751, //HANGUL SYLLABLE IEUNG EU IEUNG + 0xC0C1: 0xC752, //HANGUL SYLLABLE IEUNG EU CIEUC + 0xC0C2: 0xC753, //HANGUL SYLLABLE IEUNG EU CHIEUCH + 0xC0C3: 0xC754, //HANGUL SYLLABLE IEUNG EU KHIEUKH + 0xC0C4: 0xC755, //HANGUL SYLLABLE IEUNG EU THIEUTH + 0xC0C5: 0xC756, //HANGUL SYLLABLE IEUNG EU PHIEUPH + 0xC0C6: 0xC757, //HANGUL SYLLABLE IEUNG EU HIEUH + 0xC0C7: 0xC758, //HANGUL SYLLABLE IEUNG YI + 0xC0C8: 0xC75C, //HANGUL SYLLABLE IEUNG YI NIEUN + 0xC0C9: 0xC760, //HANGUL SYLLABLE IEUNG YI RIEUL + 0xC0CA: 0xC768, //HANGUL SYLLABLE IEUNG YI MIEUM + 0xC0CB: 0xC76B, //HANGUL SYLLABLE IEUNG YI SIOS + 0xC0CC: 0xC774, //HANGUL SYLLABLE IEUNG I + 0xC0CD: 0xC775, //HANGUL SYLLABLE IEUNG I KIYEOK + 0xC0CE: 0xC778, //HANGUL SYLLABLE IEUNG I NIEUN + 0xC0CF: 0xC77C, //HANGUL SYLLABLE IEUNG I RIEUL + 0xC0D0: 0xC77D, //HANGUL SYLLABLE IEUNG I RIEULKIYEOK + 0xC0D1: 0xC77E, //HANGUL SYLLABLE IEUNG I RIEULMIEUM + 0xC0D2: 0xC783, //HANGUL SYLLABLE IEUNG I RIEULHIEUH + 0xC0D3: 0xC784, //HANGUL SYLLABLE IEUNG I MIEUM + 0xC0D4: 0xC785, //HANGUL SYLLABLE IEUNG I PIEUP + 0xC0D5: 0xC787, //HANGUL SYLLABLE IEUNG I SIOS + 0xC0D6: 0xC788, //HANGUL SYLLABLE IEUNG I SSANGSIOS + 0xC0D7: 0xC789, //HANGUL SYLLABLE IEUNG I IEUNG + 0xC0D8: 0xC78A, //HANGUL SYLLABLE IEUNG I CIEUC + 0xC0D9: 0xC78E, //HANGUL SYLLABLE IEUNG I PHIEUPH + 0xC0DA: 0xC790, //HANGUL SYLLABLE CIEUC A + 0xC0DB: 0xC791, //HANGUL SYLLABLE CIEUC A KIYEOK + 0xC0DC: 0xC794, //HANGUL SYLLABLE CIEUC A NIEUN + 0xC0DD: 0xC796, //HANGUL SYLLABLE CIEUC A NIEUNHIEUH + 0xC0DE: 0xC797, //HANGUL SYLLABLE CIEUC A TIKEUT + 0xC0DF: 0xC798, //HANGUL SYLLABLE CIEUC A RIEUL + 0xC0E0: 0xC79A, //HANGUL SYLLABLE CIEUC A RIEULMIEUM + 0xC0E1: 0xC7A0, //HANGUL SYLLABLE CIEUC A MIEUM + 0xC0E2: 0xC7A1, //HANGUL SYLLABLE CIEUC A PIEUP + 0xC0E3: 0xC7A3, //HANGUL SYLLABLE CIEUC A SIOS + 0xC0E4: 0xC7A4, //HANGUL SYLLABLE CIEUC A SSANGSIOS + 0xC0E5: 0xC7A5, //HANGUL SYLLABLE CIEUC A IEUNG + 0xC0E6: 0xC7A6, //HANGUL SYLLABLE CIEUC A CIEUC + 0xC0E7: 0xC7AC, //HANGUL SYLLABLE CIEUC AE + 0xC0E8: 0xC7AD, //HANGUL SYLLABLE CIEUC AE KIYEOK + 0xC0E9: 0xC7B0, //HANGUL SYLLABLE CIEUC AE NIEUN + 0xC0EA: 0xC7B4, //HANGUL SYLLABLE CIEUC AE RIEUL + 0xC0EB: 0xC7BC, //HANGUL SYLLABLE CIEUC AE MIEUM + 0xC0EC: 0xC7BD, //HANGUL SYLLABLE CIEUC AE PIEUP + 0xC0ED: 0xC7BF, //HANGUL SYLLABLE CIEUC AE SIOS + 0xC0EE: 0xC7C0, //HANGUL SYLLABLE CIEUC AE SSANGSIOS + 0xC0EF: 0xC7C1, //HANGUL SYLLABLE CIEUC AE IEUNG + 0xC0F0: 0xC7C8, //HANGUL SYLLABLE CIEUC YA + 0xC0F1: 0xC7C9, //HANGUL SYLLABLE CIEUC YA KIYEOK + 0xC0F2: 0xC7CC, //HANGUL SYLLABLE CIEUC YA NIEUN + 0xC0F3: 0xC7CE, //HANGUL SYLLABLE CIEUC YA NIEUNHIEUH + 0xC0F4: 0xC7D0, //HANGUL SYLLABLE CIEUC YA RIEUL + 0xC0F5: 0xC7D8, //HANGUL SYLLABLE CIEUC YA MIEUM + 0xC0F6: 0xC7DD, //HANGUL SYLLABLE CIEUC YA IEUNG + 0xC0F7: 0xC7E4, //HANGUL SYLLABLE CIEUC YAE + 0xC0F8: 0xC7E8, //HANGUL SYLLABLE CIEUC YAE NIEUN + 0xC0F9: 0xC7EC, //HANGUL SYLLABLE CIEUC YAE RIEUL + 0xC0FA: 0xC800, //HANGUL SYLLABLE CIEUC EO + 0xC0FB: 0xC801, //HANGUL SYLLABLE CIEUC EO KIYEOK + 0xC0FC: 0xC804, //HANGUL SYLLABLE CIEUC EO NIEUN + 0xC0FD: 0xC808, //HANGUL SYLLABLE CIEUC EO RIEUL + 0xC0FE: 0xC80A, //HANGUL SYLLABLE CIEUC EO RIEULMIEUM + 0xC141: 0xD564, //HANGUL SYLLABLE HIEUH A RIEULSIOS + 0xC142: 0xD566, //HANGUL SYLLABLE HIEUH A RIEULPHIEUPH + 0xC143: 0xD567, //HANGUL SYLLABLE HIEUH A RIEULHIEUH + 0xC144: 0xD56A, //HANGUL SYLLABLE HIEUH A PIEUPSIOS + 0xC145: 0xD56C, //HANGUL SYLLABLE HIEUH A SSANGSIOS + 0xC146: 0xD56E, //HANGUL SYLLABLE HIEUH A CIEUC + 0xC147: 0xD56F, //HANGUL SYLLABLE HIEUH A CHIEUCH + 0xC148: 0xD570, //HANGUL SYLLABLE HIEUH A KHIEUKH + 0xC149: 0xD571, //HANGUL SYLLABLE HIEUH A THIEUTH + 0xC14A: 0xD572, //HANGUL SYLLABLE HIEUH A PHIEUPH + 0xC14B: 0xD573, //HANGUL SYLLABLE HIEUH A HIEUH + 0xC14C: 0xD576, //HANGUL SYLLABLE HIEUH AE SSANGKIYEOK + 0xC14D: 0xD577, //HANGUL SYLLABLE HIEUH AE KIYEOKSIOS + 0xC14E: 0xD579, //HANGUL SYLLABLE HIEUH AE NIEUNCIEUC + 0xC14F: 0xD57A, //HANGUL SYLLABLE HIEUH AE NIEUNHIEUH + 0xC150: 0xD57B, //HANGUL SYLLABLE HIEUH AE TIKEUT + 0xC151: 0xD57D, //HANGUL SYLLABLE HIEUH AE RIEULKIYEOK + 0xC152: 0xD57E, //HANGUL SYLLABLE HIEUH AE RIEULMIEUM + 0xC153: 0xD57F, //HANGUL SYLLABLE HIEUH AE RIEULPIEUP + 0xC154: 0xD580, //HANGUL SYLLABLE HIEUH AE RIEULSIOS + 0xC155: 0xD581, //HANGUL SYLLABLE HIEUH AE RIEULTHIEUTH + 0xC156: 0xD582, //HANGUL SYLLABLE HIEUH AE RIEULPHIEUPH + 0xC157: 0xD583, //HANGUL SYLLABLE HIEUH AE RIEULHIEUH + 0xC158: 0xD586, //HANGUL SYLLABLE HIEUH AE PIEUPSIOS + 0xC159: 0xD58A, //HANGUL SYLLABLE HIEUH AE CIEUC + 0xC15A: 0xD58B, //HANGUL SYLLABLE HIEUH AE CHIEUCH + 0xC161: 0xD58C, //HANGUL SYLLABLE HIEUH AE KHIEUKH + 0xC162: 0xD58D, //HANGUL SYLLABLE HIEUH AE THIEUTH + 0xC163: 0xD58E, //HANGUL SYLLABLE HIEUH AE PHIEUPH + 0xC164: 0xD58F, //HANGUL SYLLABLE HIEUH AE HIEUH + 0xC165: 0xD591, //HANGUL SYLLABLE HIEUH YA KIYEOK + 0xC166: 0xD592, //HANGUL SYLLABLE HIEUH YA SSANGKIYEOK + 0xC167: 0xD593, //HANGUL SYLLABLE HIEUH YA KIYEOKSIOS + 0xC168: 0xD594, //HANGUL SYLLABLE HIEUH YA NIEUN + 0xC169: 0xD595, //HANGUL SYLLABLE HIEUH YA NIEUNCIEUC + 0xC16A: 0xD596, //HANGUL SYLLABLE HIEUH YA NIEUNHIEUH + 0xC16B: 0xD597, //HANGUL SYLLABLE HIEUH YA TIKEUT + 0xC16C: 0xD598, //HANGUL SYLLABLE HIEUH YA RIEUL + 0xC16D: 0xD599, //HANGUL SYLLABLE HIEUH YA RIEULKIYEOK + 0xC16E: 0xD59A, //HANGUL SYLLABLE HIEUH YA RIEULMIEUM + 0xC16F: 0xD59B, //HANGUL SYLLABLE HIEUH YA RIEULPIEUP + 0xC170: 0xD59C, //HANGUL SYLLABLE HIEUH YA RIEULSIOS + 0xC171: 0xD59D, //HANGUL SYLLABLE HIEUH YA RIEULTHIEUTH + 0xC172: 0xD59E, //HANGUL SYLLABLE HIEUH YA RIEULPHIEUPH + 0xC173: 0xD59F, //HANGUL SYLLABLE HIEUH YA RIEULHIEUH + 0xC174: 0xD5A0, //HANGUL SYLLABLE HIEUH YA MIEUM + 0xC175: 0xD5A1, //HANGUL SYLLABLE HIEUH YA PIEUP + 0xC176: 0xD5A2, //HANGUL SYLLABLE HIEUH YA PIEUPSIOS + 0xC177: 0xD5A3, //HANGUL SYLLABLE HIEUH YA SIOS + 0xC178: 0xD5A4, //HANGUL SYLLABLE HIEUH YA SSANGSIOS + 0xC179: 0xD5A6, //HANGUL SYLLABLE HIEUH YA CIEUC + 0xC17A: 0xD5A7, //HANGUL SYLLABLE HIEUH YA CHIEUCH + 0xC181: 0xD5A8, //HANGUL SYLLABLE HIEUH YA KHIEUKH + 0xC182: 0xD5A9, //HANGUL SYLLABLE HIEUH YA THIEUTH + 0xC183: 0xD5AA, //HANGUL SYLLABLE HIEUH YA PHIEUPH + 0xC184: 0xD5AB, //HANGUL SYLLABLE HIEUH YA HIEUH + 0xC185: 0xD5AC, //HANGUL SYLLABLE HIEUH YAE + 0xC186: 0xD5AD, //HANGUL SYLLABLE HIEUH YAE KIYEOK + 0xC187: 0xD5AE, //HANGUL SYLLABLE HIEUH YAE SSANGKIYEOK + 0xC188: 0xD5AF, //HANGUL SYLLABLE HIEUH YAE KIYEOKSIOS + 0xC189: 0xD5B0, //HANGUL SYLLABLE HIEUH YAE NIEUN + 0xC18A: 0xD5B1, //HANGUL SYLLABLE HIEUH YAE NIEUNCIEUC + 0xC18B: 0xD5B2, //HANGUL SYLLABLE HIEUH YAE NIEUNHIEUH + 0xC18C: 0xD5B3, //HANGUL SYLLABLE HIEUH YAE TIKEUT + 0xC18D: 0xD5B4, //HANGUL SYLLABLE HIEUH YAE RIEUL + 0xC18E: 0xD5B5, //HANGUL SYLLABLE HIEUH YAE RIEULKIYEOK + 0xC18F: 0xD5B6, //HANGUL SYLLABLE HIEUH YAE RIEULMIEUM + 0xC190: 0xD5B7, //HANGUL SYLLABLE HIEUH YAE RIEULPIEUP + 0xC191: 0xD5B8, //HANGUL SYLLABLE HIEUH YAE RIEULSIOS + 0xC192: 0xD5B9, //HANGUL SYLLABLE HIEUH YAE RIEULTHIEUTH + 0xC193: 0xD5BA, //HANGUL SYLLABLE HIEUH YAE RIEULPHIEUPH + 0xC194: 0xD5BB, //HANGUL SYLLABLE HIEUH YAE RIEULHIEUH + 0xC195: 0xD5BC, //HANGUL SYLLABLE HIEUH YAE MIEUM + 0xC196: 0xD5BD, //HANGUL SYLLABLE HIEUH YAE PIEUP + 0xC197: 0xD5BE, //HANGUL SYLLABLE HIEUH YAE PIEUPSIOS + 0xC198: 0xD5BF, //HANGUL SYLLABLE HIEUH YAE SIOS + 0xC199: 0xD5C0, //HANGUL SYLLABLE HIEUH YAE SSANGSIOS + 0xC19A: 0xD5C1, //HANGUL SYLLABLE HIEUH YAE IEUNG + 0xC19B: 0xD5C2, //HANGUL SYLLABLE HIEUH YAE CIEUC + 0xC19C: 0xD5C3, //HANGUL SYLLABLE HIEUH YAE CHIEUCH + 0xC19D: 0xD5C4, //HANGUL SYLLABLE HIEUH YAE KHIEUKH + 0xC19E: 0xD5C5, //HANGUL SYLLABLE HIEUH YAE THIEUTH + 0xC19F: 0xD5C6, //HANGUL SYLLABLE HIEUH YAE PHIEUPH + 0xC1A0: 0xD5C7, //HANGUL SYLLABLE HIEUH YAE HIEUH + 0xC1A1: 0xC810, //HANGUL SYLLABLE CIEUC EO MIEUM + 0xC1A2: 0xC811, //HANGUL SYLLABLE CIEUC EO PIEUP + 0xC1A3: 0xC813, //HANGUL SYLLABLE CIEUC EO SIOS + 0xC1A4: 0xC815, //HANGUL SYLLABLE CIEUC EO IEUNG + 0xC1A5: 0xC816, //HANGUL SYLLABLE CIEUC EO CIEUC + 0xC1A6: 0xC81C, //HANGUL SYLLABLE CIEUC E + 0xC1A7: 0xC81D, //HANGUL SYLLABLE CIEUC E KIYEOK + 0xC1A8: 0xC820, //HANGUL SYLLABLE CIEUC E NIEUN + 0xC1A9: 0xC824, //HANGUL SYLLABLE CIEUC E RIEUL + 0xC1AA: 0xC82C, //HANGUL SYLLABLE CIEUC E MIEUM + 0xC1AB: 0xC82D, //HANGUL SYLLABLE CIEUC E PIEUP + 0xC1AC: 0xC82F, //HANGUL SYLLABLE CIEUC E SIOS + 0xC1AD: 0xC831, //HANGUL SYLLABLE CIEUC E IEUNG + 0xC1AE: 0xC838, //HANGUL SYLLABLE CIEUC YEO + 0xC1AF: 0xC83C, //HANGUL SYLLABLE CIEUC YEO NIEUN + 0xC1B0: 0xC840, //HANGUL SYLLABLE CIEUC YEO RIEUL + 0xC1B1: 0xC848, //HANGUL SYLLABLE CIEUC YEO MIEUM + 0xC1B2: 0xC849, //HANGUL SYLLABLE CIEUC YEO PIEUP + 0xC1B3: 0xC84C, //HANGUL SYLLABLE CIEUC YEO SSANGSIOS + 0xC1B4: 0xC84D, //HANGUL SYLLABLE CIEUC YEO IEUNG + 0xC1B5: 0xC854, //HANGUL SYLLABLE CIEUC YE + 0xC1B6: 0xC870, //HANGUL SYLLABLE CIEUC O + 0xC1B7: 0xC871, //HANGUL SYLLABLE CIEUC O KIYEOK + 0xC1B8: 0xC874, //HANGUL SYLLABLE CIEUC O NIEUN + 0xC1B9: 0xC878, //HANGUL SYLLABLE CIEUC O RIEUL + 0xC1BA: 0xC87A, //HANGUL SYLLABLE CIEUC O RIEULMIEUM + 0xC1BB: 0xC880, //HANGUL SYLLABLE CIEUC O MIEUM + 0xC1BC: 0xC881, //HANGUL SYLLABLE CIEUC O PIEUP + 0xC1BD: 0xC883, //HANGUL SYLLABLE CIEUC O SIOS + 0xC1BE: 0xC885, //HANGUL SYLLABLE CIEUC O IEUNG + 0xC1BF: 0xC886, //HANGUL SYLLABLE CIEUC O CIEUC + 0xC1C0: 0xC887, //HANGUL SYLLABLE CIEUC O CHIEUCH + 0xC1C1: 0xC88B, //HANGUL SYLLABLE CIEUC O HIEUH + 0xC1C2: 0xC88C, //HANGUL SYLLABLE CIEUC WA + 0xC1C3: 0xC88D, //HANGUL SYLLABLE CIEUC WA KIYEOK + 0xC1C4: 0xC894, //HANGUL SYLLABLE CIEUC WA RIEUL + 0xC1C5: 0xC89D, //HANGUL SYLLABLE CIEUC WA PIEUP + 0xC1C6: 0xC89F, //HANGUL SYLLABLE CIEUC WA SIOS + 0xC1C7: 0xC8A1, //HANGUL SYLLABLE CIEUC WA IEUNG + 0xC1C8: 0xC8A8, //HANGUL SYLLABLE CIEUC WAE + 0xC1C9: 0xC8BC, //HANGUL SYLLABLE CIEUC WAE SSANGSIOS + 0xC1CA: 0xC8BD, //HANGUL SYLLABLE CIEUC WAE IEUNG + 0xC1CB: 0xC8C4, //HANGUL SYLLABLE CIEUC OE + 0xC1CC: 0xC8C8, //HANGUL SYLLABLE CIEUC OE NIEUN + 0xC1CD: 0xC8CC, //HANGUL SYLLABLE CIEUC OE RIEUL + 0xC1CE: 0xC8D4, //HANGUL SYLLABLE CIEUC OE MIEUM + 0xC1CF: 0xC8D5, //HANGUL SYLLABLE CIEUC OE PIEUP + 0xC1D0: 0xC8D7, //HANGUL SYLLABLE CIEUC OE SIOS + 0xC1D1: 0xC8D9, //HANGUL SYLLABLE CIEUC OE IEUNG + 0xC1D2: 0xC8E0, //HANGUL SYLLABLE CIEUC YO + 0xC1D3: 0xC8E1, //HANGUL SYLLABLE CIEUC YO KIYEOK + 0xC1D4: 0xC8E4, //HANGUL SYLLABLE CIEUC YO NIEUN + 0xC1D5: 0xC8F5, //HANGUL SYLLABLE CIEUC YO IEUNG + 0xC1D6: 0xC8FC, //HANGUL SYLLABLE CIEUC U + 0xC1D7: 0xC8FD, //HANGUL SYLLABLE CIEUC U KIYEOK + 0xC1D8: 0xC900, //HANGUL SYLLABLE CIEUC U NIEUN + 0xC1D9: 0xC904, //HANGUL SYLLABLE CIEUC U RIEUL + 0xC1DA: 0xC905, //HANGUL SYLLABLE CIEUC U RIEULKIYEOK + 0xC1DB: 0xC906, //HANGUL SYLLABLE CIEUC U RIEULMIEUM + 0xC1DC: 0xC90C, //HANGUL SYLLABLE CIEUC U MIEUM + 0xC1DD: 0xC90D, //HANGUL SYLLABLE CIEUC U PIEUP + 0xC1DE: 0xC90F, //HANGUL SYLLABLE CIEUC U SIOS + 0xC1DF: 0xC911, //HANGUL SYLLABLE CIEUC U IEUNG + 0xC1E0: 0xC918, //HANGUL SYLLABLE CIEUC WEO + 0xC1E1: 0xC92C, //HANGUL SYLLABLE CIEUC WEO SSANGSIOS + 0xC1E2: 0xC934, //HANGUL SYLLABLE CIEUC WE + 0xC1E3: 0xC950, //HANGUL SYLLABLE CIEUC WI + 0xC1E4: 0xC951, //HANGUL SYLLABLE CIEUC WI KIYEOK + 0xC1E5: 0xC954, //HANGUL SYLLABLE CIEUC WI NIEUN + 0xC1E6: 0xC958, //HANGUL SYLLABLE CIEUC WI RIEUL + 0xC1E7: 0xC960, //HANGUL SYLLABLE CIEUC WI MIEUM + 0xC1E8: 0xC961, //HANGUL SYLLABLE CIEUC WI PIEUP + 0xC1E9: 0xC963, //HANGUL SYLLABLE CIEUC WI SIOS + 0xC1EA: 0xC96C, //HANGUL SYLLABLE CIEUC YU + 0xC1EB: 0xC970, //HANGUL SYLLABLE CIEUC YU NIEUN + 0xC1EC: 0xC974, //HANGUL SYLLABLE CIEUC YU RIEUL + 0xC1ED: 0xC97C, //HANGUL SYLLABLE CIEUC YU MIEUM + 0xC1EE: 0xC988, //HANGUL SYLLABLE CIEUC EU + 0xC1EF: 0xC989, //HANGUL SYLLABLE CIEUC EU KIYEOK + 0xC1F0: 0xC98C, //HANGUL SYLLABLE CIEUC EU NIEUN + 0xC1F1: 0xC990, //HANGUL SYLLABLE CIEUC EU RIEUL + 0xC1F2: 0xC998, //HANGUL SYLLABLE CIEUC EU MIEUM + 0xC1F3: 0xC999, //HANGUL SYLLABLE CIEUC EU PIEUP + 0xC1F4: 0xC99B, //HANGUL SYLLABLE CIEUC EU SIOS + 0xC1F5: 0xC99D, //HANGUL SYLLABLE CIEUC EU IEUNG + 0xC1F6: 0xC9C0, //HANGUL SYLLABLE CIEUC I + 0xC1F7: 0xC9C1, //HANGUL SYLLABLE CIEUC I KIYEOK + 0xC1F8: 0xC9C4, //HANGUL SYLLABLE CIEUC I NIEUN + 0xC1F9: 0xC9C7, //HANGUL SYLLABLE CIEUC I TIKEUT + 0xC1FA: 0xC9C8, //HANGUL SYLLABLE CIEUC I RIEUL + 0xC1FB: 0xC9CA, //HANGUL SYLLABLE CIEUC I RIEULMIEUM + 0xC1FC: 0xC9D0, //HANGUL SYLLABLE CIEUC I MIEUM + 0xC1FD: 0xC9D1, //HANGUL SYLLABLE CIEUC I PIEUP + 0xC1FE: 0xC9D3, //HANGUL SYLLABLE CIEUC I SIOS + 0xC241: 0xD5CA, //HANGUL SYLLABLE HIEUH EO SSANGKIYEOK + 0xC242: 0xD5CB, //HANGUL SYLLABLE HIEUH EO KIYEOKSIOS + 0xC243: 0xD5CD, //HANGUL SYLLABLE HIEUH EO NIEUNCIEUC + 0xC244: 0xD5CE, //HANGUL SYLLABLE HIEUH EO NIEUNHIEUH + 0xC245: 0xD5CF, //HANGUL SYLLABLE HIEUH EO TIKEUT + 0xC246: 0xD5D1, //HANGUL SYLLABLE HIEUH EO RIEULKIYEOK + 0xC247: 0xD5D3, //HANGUL SYLLABLE HIEUH EO RIEULPIEUP + 0xC248: 0xD5D4, //HANGUL SYLLABLE HIEUH EO RIEULSIOS + 0xC249: 0xD5D5, //HANGUL SYLLABLE HIEUH EO RIEULTHIEUTH + 0xC24A: 0xD5D6, //HANGUL SYLLABLE HIEUH EO RIEULPHIEUPH + 0xC24B: 0xD5D7, //HANGUL SYLLABLE HIEUH EO RIEULHIEUH + 0xC24C: 0xD5DA, //HANGUL SYLLABLE HIEUH EO PIEUPSIOS + 0xC24D: 0xD5DC, //HANGUL SYLLABLE HIEUH EO SSANGSIOS + 0xC24E: 0xD5DE, //HANGUL SYLLABLE HIEUH EO CIEUC + 0xC24F: 0xD5DF, //HANGUL SYLLABLE HIEUH EO CHIEUCH + 0xC250: 0xD5E0, //HANGUL SYLLABLE HIEUH EO KHIEUKH + 0xC251: 0xD5E1, //HANGUL SYLLABLE HIEUH EO THIEUTH + 0xC252: 0xD5E2, //HANGUL SYLLABLE HIEUH EO PHIEUPH + 0xC253: 0xD5E3, //HANGUL SYLLABLE HIEUH EO HIEUH + 0xC254: 0xD5E6, //HANGUL SYLLABLE HIEUH E SSANGKIYEOK + 0xC255: 0xD5E7, //HANGUL SYLLABLE HIEUH E KIYEOKSIOS + 0xC256: 0xD5E9, //HANGUL SYLLABLE HIEUH E NIEUNCIEUC + 0xC257: 0xD5EA, //HANGUL SYLLABLE HIEUH E NIEUNHIEUH + 0xC258: 0xD5EB, //HANGUL SYLLABLE HIEUH E TIKEUT + 0xC259: 0xD5ED, //HANGUL SYLLABLE HIEUH E RIEULKIYEOK + 0xC25A: 0xD5EE, //HANGUL SYLLABLE HIEUH E RIEULMIEUM + 0xC261: 0xD5EF, //HANGUL SYLLABLE HIEUH E RIEULPIEUP + 0xC262: 0xD5F0, //HANGUL SYLLABLE HIEUH E RIEULSIOS + 0xC263: 0xD5F1, //HANGUL SYLLABLE HIEUH E RIEULTHIEUTH + 0xC264: 0xD5F2, //HANGUL SYLLABLE HIEUH E RIEULPHIEUPH + 0xC265: 0xD5F3, //HANGUL SYLLABLE HIEUH E RIEULHIEUH + 0xC266: 0xD5F6, //HANGUL SYLLABLE HIEUH E PIEUPSIOS + 0xC267: 0xD5F8, //HANGUL SYLLABLE HIEUH E SSANGSIOS + 0xC268: 0xD5FA, //HANGUL SYLLABLE HIEUH E CIEUC + 0xC269: 0xD5FB, //HANGUL SYLLABLE HIEUH E CHIEUCH + 0xC26A: 0xD5FC, //HANGUL SYLLABLE HIEUH E KHIEUKH + 0xC26B: 0xD5FD, //HANGUL SYLLABLE HIEUH E THIEUTH + 0xC26C: 0xD5FE, //HANGUL SYLLABLE HIEUH E PHIEUPH + 0xC26D: 0xD5FF, //HANGUL SYLLABLE HIEUH E HIEUH + 0xC26E: 0xD602, //HANGUL SYLLABLE HIEUH YEO SSANGKIYEOK + 0xC26F: 0xD603, //HANGUL SYLLABLE HIEUH YEO KIYEOKSIOS + 0xC270: 0xD605, //HANGUL SYLLABLE HIEUH YEO NIEUNCIEUC + 0xC271: 0xD606, //HANGUL SYLLABLE HIEUH YEO NIEUNHIEUH + 0xC272: 0xD607, //HANGUL SYLLABLE HIEUH YEO TIKEUT + 0xC273: 0xD609, //HANGUL SYLLABLE HIEUH YEO RIEULKIYEOK + 0xC274: 0xD60A, //HANGUL SYLLABLE HIEUH YEO RIEULMIEUM + 0xC275: 0xD60B, //HANGUL SYLLABLE HIEUH YEO RIEULPIEUP + 0xC276: 0xD60C, //HANGUL SYLLABLE HIEUH YEO RIEULSIOS + 0xC277: 0xD60D, //HANGUL SYLLABLE HIEUH YEO RIEULTHIEUTH + 0xC278: 0xD60E, //HANGUL SYLLABLE HIEUH YEO RIEULPHIEUPH + 0xC279: 0xD60F, //HANGUL SYLLABLE HIEUH YEO RIEULHIEUH + 0xC27A: 0xD612, //HANGUL SYLLABLE HIEUH YEO PIEUPSIOS + 0xC281: 0xD616, //HANGUL SYLLABLE HIEUH YEO CIEUC + 0xC282: 0xD617, //HANGUL SYLLABLE HIEUH YEO CHIEUCH + 0xC283: 0xD618, //HANGUL SYLLABLE HIEUH YEO KHIEUKH + 0xC284: 0xD619, //HANGUL SYLLABLE HIEUH YEO THIEUTH + 0xC285: 0xD61A, //HANGUL SYLLABLE HIEUH YEO PHIEUPH + 0xC286: 0xD61B, //HANGUL SYLLABLE HIEUH YEO HIEUH + 0xC287: 0xD61D, //HANGUL SYLLABLE HIEUH YE KIYEOK + 0xC288: 0xD61E, //HANGUL SYLLABLE HIEUH YE SSANGKIYEOK + 0xC289: 0xD61F, //HANGUL SYLLABLE HIEUH YE KIYEOKSIOS + 0xC28A: 0xD621, //HANGUL SYLLABLE HIEUH YE NIEUNCIEUC + 0xC28B: 0xD622, //HANGUL SYLLABLE HIEUH YE NIEUNHIEUH + 0xC28C: 0xD623, //HANGUL SYLLABLE HIEUH YE TIKEUT + 0xC28D: 0xD625, //HANGUL SYLLABLE HIEUH YE RIEULKIYEOK + 0xC28E: 0xD626, //HANGUL SYLLABLE HIEUH YE RIEULMIEUM + 0xC28F: 0xD627, //HANGUL SYLLABLE HIEUH YE RIEULPIEUP + 0xC290: 0xD628, //HANGUL SYLLABLE HIEUH YE RIEULSIOS + 0xC291: 0xD629, //HANGUL SYLLABLE HIEUH YE RIEULTHIEUTH + 0xC292: 0xD62A, //HANGUL SYLLABLE HIEUH YE RIEULPHIEUPH + 0xC293: 0xD62B, //HANGUL SYLLABLE HIEUH YE RIEULHIEUH + 0xC294: 0xD62C, //HANGUL SYLLABLE HIEUH YE MIEUM + 0xC295: 0xD62E, //HANGUL SYLLABLE HIEUH YE PIEUPSIOS + 0xC296: 0xD62F, //HANGUL SYLLABLE HIEUH YE SIOS + 0xC297: 0xD630, //HANGUL SYLLABLE HIEUH YE SSANGSIOS + 0xC298: 0xD631, //HANGUL SYLLABLE HIEUH YE IEUNG + 0xC299: 0xD632, //HANGUL SYLLABLE HIEUH YE CIEUC + 0xC29A: 0xD633, //HANGUL SYLLABLE HIEUH YE CHIEUCH + 0xC29B: 0xD634, //HANGUL SYLLABLE HIEUH YE KHIEUKH + 0xC29C: 0xD635, //HANGUL SYLLABLE HIEUH YE THIEUTH + 0xC29D: 0xD636, //HANGUL SYLLABLE HIEUH YE PHIEUPH + 0xC29E: 0xD637, //HANGUL SYLLABLE HIEUH YE HIEUH + 0xC29F: 0xD63A, //HANGUL SYLLABLE HIEUH O SSANGKIYEOK + 0xC2A0: 0xD63B, //HANGUL SYLLABLE HIEUH O KIYEOKSIOS + 0xC2A1: 0xC9D5, //HANGUL SYLLABLE CIEUC I IEUNG + 0xC2A2: 0xC9D6, //HANGUL SYLLABLE CIEUC I CIEUC + 0xC2A3: 0xC9D9, //HANGUL SYLLABLE CIEUC I THIEUTH + 0xC2A4: 0xC9DA, //HANGUL SYLLABLE CIEUC I PHIEUPH + 0xC2A5: 0xC9DC, //HANGUL SYLLABLE SSANGCIEUC A + 0xC2A6: 0xC9DD, //HANGUL SYLLABLE SSANGCIEUC A KIYEOK + 0xC2A7: 0xC9E0, //HANGUL SYLLABLE SSANGCIEUC A NIEUN + 0xC2A8: 0xC9E2, //HANGUL SYLLABLE SSANGCIEUC A NIEUNHIEUH + 0xC2A9: 0xC9E4, //HANGUL SYLLABLE SSANGCIEUC A RIEUL + 0xC2AA: 0xC9E7, //HANGUL SYLLABLE SSANGCIEUC A RIEULPIEUP + 0xC2AB: 0xC9EC, //HANGUL SYLLABLE SSANGCIEUC A MIEUM + 0xC2AC: 0xC9ED, //HANGUL SYLLABLE SSANGCIEUC A PIEUP + 0xC2AD: 0xC9EF, //HANGUL SYLLABLE SSANGCIEUC A SIOS + 0xC2AE: 0xC9F0, //HANGUL SYLLABLE SSANGCIEUC A SSANGSIOS + 0xC2AF: 0xC9F1, //HANGUL SYLLABLE SSANGCIEUC A IEUNG + 0xC2B0: 0xC9F8, //HANGUL SYLLABLE SSANGCIEUC AE + 0xC2B1: 0xC9F9, //HANGUL SYLLABLE SSANGCIEUC AE KIYEOK + 0xC2B2: 0xC9FC, //HANGUL SYLLABLE SSANGCIEUC AE NIEUN + 0xC2B3: 0xCA00, //HANGUL SYLLABLE SSANGCIEUC AE RIEUL + 0xC2B4: 0xCA08, //HANGUL SYLLABLE SSANGCIEUC AE MIEUM + 0xC2B5: 0xCA09, //HANGUL SYLLABLE SSANGCIEUC AE PIEUP + 0xC2B6: 0xCA0B, //HANGUL SYLLABLE SSANGCIEUC AE SIOS + 0xC2B7: 0xCA0C, //HANGUL SYLLABLE SSANGCIEUC AE SSANGSIOS + 0xC2B8: 0xCA0D, //HANGUL SYLLABLE SSANGCIEUC AE IEUNG + 0xC2B9: 0xCA14, //HANGUL SYLLABLE SSANGCIEUC YA + 0xC2BA: 0xCA18, //HANGUL SYLLABLE SSANGCIEUC YA NIEUN + 0xC2BB: 0xCA29, //HANGUL SYLLABLE SSANGCIEUC YA IEUNG + 0xC2BC: 0xCA4C, //HANGUL SYLLABLE SSANGCIEUC EO + 0xC2BD: 0xCA4D, //HANGUL SYLLABLE SSANGCIEUC EO KIYEOK + 0xC2BE: 0xCA50, //HANGUL SYLLABLE SSANGCIEUC EO NIEUN + 0xC2BF: 0xCA54, //HANGUL SYLLABLE SSANGCIEUC EO RIEUL + 0xC2C0: 0xCA5C, //HANGUL SYLLABLE SSANGCIEUC EO MIEUM + 0xC2C1: 0xCA5D, //HANGUL SYLLABLE SSANGCIEUC EO PIEUP + 0xC2C2: 0xCA5F, //HANGUL SYLLABLE SSANGCIEUC EO SIOS + 0xC2C3: 0xCA60, //HANGUL SYLLABLE SSANGCIEUC EO SSANGSIOS + 0xC2C4: 0xCA61, //HANGUL SYLLABLE SSANGCIEUC EO IEUNG + 0xC2C5: 0xCA68, //HANGUL SYLLABLE SSANGCIEUC E + 0xC2C6: 0xCA7D, //HANGUL SYLLABLE SSANGCIEUC E IEUNG + 0xC2C7: 0xCA84, //HANGUL SYLLABLE SSANGCIEUC YEO + 0xC2C8: 0xCA98, //HANGUL SYLLABLE SSANGCIEUC YEO SSANGSIOS + 0xC2C9: 0xCABC, //HANGUL SYLLABLE SSANGCIEUC O + 0xC2CA: 0xCABD, //HANGUL SYLLABLE SSANGCIEUC O KIYEOK + 0xC2CB: 0xCAC0, //HANGUL SYLLABLE SSANGCIEUC O NIEUN + 0xC2CC: 0xCAC4, //HANGUL SYLLABLE SSANGCIEUC O RIEUL + 0xC2CD: 0xCACC, //HANGUL SYLLABLE SSANGCIEUC O MIEUM + 0xC2CE: 0xCACD, //HANGUL SYLLABLE SSANGCIEUC O PIEUP + 0xC2CF: 0xCACF, //HANGUL SYLLABLE SSANGCIEUC O SIOS + 0xC2D0: 0xCAD1, //HANGUL SYLLABLE SSANGCIEUC O IEUNG + 0xC2D1: 0xCAD3, //HANGUL SYLLABLE SSANGCIEUC O CHIEUCH + 0xC2D2: 0xCAD8, //HANGUL SYLLABLE SSANGCIEUC WA + 0xC2D3: 0xCAD9, //HANGUL SYLLABLE SSANGCIEUC WA KIYEOK + 0xC2D4: 0xCAE0, //HANGUL SYLLABLE SSANGCIEUC WA RIEUL + 0xC2D5: 0xCAEC, //HANGUL SYLLABLE SSANGCIEUC WA SSANGSIOS + 0xC2D6: 0xCAF4, //HANGUL SYLLABLE SSANGCIEUC WAE + 0xC2D7: 0xCB08, //HANGUL SYLLABLE SSANGCIEUC WAE SSANGSIOS + 0xC2D8: 0xCB10, //HANGUL SYLLABLE SSANGCIEUC OE + 0xC2D9: 0xCB14, //HANGUL SYLLABLE SSANGCIEUC OE NIEUN + 0xC2DA: 0xCB18, //HANGUL SYLLABLE SSANGCIEUC OE RIEUL + 0xC2DB: 0xCB20, //HANGUL SYLLABLE SSANGCIEUC OE MIEUM + 0xC2DC: 0xCB21, //HANGUL SYLLABLE SSANGCIEUC OE PIEUP + 0xC2DD: 0xCB41, //HANGUL SYLLABLE SSANGCIEUC YO IEUNG + 0xC2DE: 0xCB48, //HANGUL SYLLABLE SSANGCIEUC U + 0xC2DF: 0xCB49, //HANGUL SYLLABLE SSANGCIEUC U KIYEOK + 0xC2E0: 0xCB4C, //HANGUL SYLLABLE SSANGCIEUC U NIEUN + 0xC2E1: 0xCB50, //HANGUL SYLLABLE SSANGCIEUC U RIEUL + 0xC2E2: 0xCB58, //HANGUL SYLLABLE SSANGCIEUC U MIEUM + 0xC2E3: 0xCB59, //HANGUL SYLLABLE SSANGCIEUC U PIEUP + 0xC2E4: 0xCB5D, //HANGUL SYLLABLE SSANGCIEUC U IEUNG + 0xC2E5: 0xCB64, //HANGUL SYLLABLE SSANGCIEUC WEO + 0xC2E6: 0xCB78, //HANGUL SYLLABLE SSANGCIEUC WEO SSANGSIOS + 0xC2E7: 0xCB79, //HANGUL SYLLABLE SSANGCIEUC WEO IEUNG + 0xC2E8: 0xCB9C, //HANGUL SYLLABLE SSANGCIEUC WI + 0xC2E9: 0xCBB8, //HANGUL SYLLABLE SSANGCIEUC YU + 0xC2EA: 0xCBD4, //HANGUL SYLLABLE SSANGCIEUC EU + 0xC2EB: 0xCBE4, //HANGUL SYLLABLE SSANGCIEUC EU MIEUM + 0xC2EC: 0xCBE7, //HANGUL SYLLABLE SSANGCIEUC EU SIOS + 0xC2ED: 0xCBE9, //HANGUL SYLLABLE SSANGCIEUC EU IEUNG + 0xC2EE: 0xCC0C, //HANGUL SYLLABLE SSANGCIEUC I + 0xC2EF: 0xCC0D, //HANGUL SYLLABLE SSANGCIEUC I KIYEOK + 0xC2F0: 0xCC10, //HANGUL SYLLABLE SSANGCIEUC I NIEUN + 0xC2F1: 0xCC14, //HANGUL SYLLABLE SSANGCIEUC I RIEUL + 0xC2F2: 0xCC1C, //HANGUL SYLLABLE SSANGCIEUC I MIEUM + 0xC2F3: 0xCC1D, //HANGUL SYLLABLE SSANGCIEUC I PIEUP + 0xC2F4: 0xCC21, //HANGUL SYLLABLE SSANGCIEUC I IEUNG + 0xC2F5: 0xCC22, //HANGUL SYLLABLE SSANGCIEUC I CIEUC + 0xC2F6: 0xCC27, //HANGUL SYLLABLE SSANGCIEUC I HIEUH + 0xC2F7: 0xCC28, //HANGUL SYLLABLE CHIEUCH A + 0xC2F8: 0xCC29, //HANGUL SYLLABLE CHIEUCH A KIYEOK + 0xC2F9: 0xCC2C, //HANGUL SYLLABLE CHIEUCH A NIEUN + 0xC2FA: 0xCC2E, //HANGUL SYLLABLE CHIEUCH A NIEUNHIEUH + 0xC2FB: 0xCC30, //HANGUL SYLLABLE CHIEUCH A RIEUL + 0xC2FC: 0xCC38, //HANGUL SYLLABLE CHIEUCH A MIEUM + 0xC2FD: 0xCC39, //HANGUL SYLLABLE CHIEUCH A PIEUP + 0xC2FE: 0xCC3B, //HANGUL SYLLABLE CHIEUCH A SIOS + 0xC341: 0xD63D, //HANGUL SYLLABLE HIEUH O NIEUNCIEUC + 0xC342: 0xD63E, //HANGUL SYLLABLE HIEUH O NIEUNHIEUH + 0xC343: 0xD63F, //HANGUL SYLLABLE HIEUH O TIKEUT + 0xC344: 0xD641, //HANGUL SYLLABLE HIEUH O RIEULKIYEOK + 0xC345: 0xD642, //HANGUL SYLLABLE HIEUH O RIEULMIEUM + 0xC346: 0xD643, //HANGUL SYLLABLE HIEUH O RIEULPIEUP + 0xC347: 0xD644, //HANGUL SYLLABLE HIEUH O RIEULSIOS + 0xC348: 0xD646, //HANGUL SYLLABLE HIEUH O RIEULPHIEUPH + 0xC349: 0xD647, //HANGUL SYLLABLE HIEUH O RIEULHIEUH + 0xC34A: 0xD64A, //HANGUL SYLLABLE HIEUH O PIEUPSIOS + 0xC34B: 0xD64C, //HANGUL SYLLABLE HIEUH O SSANGSIOS + 0xC34C: 0xD64E, //HANGUL SYLLABLE HIEUH O CIEUC + 0xC34D: 0xD64F, //HANGUL SYLLABLE HIEUH O CHIEUCH + 0xC34E: 0xD650, //HANGUL SYLLABLE HIEUH O KHIEUKH + 0xC34F: 0xD652, //HANGUL SYLLABLE HIEUH O PHIEUPH + 0xC350: 0xD653, //HANGUL SYLLABLE HIEUH O HIEUH + 0xC351: 0xD656, //HANGUL SYLLABLE HIEUH WA SSANGKIYEOK + 0xC352: 0xD657, //HANGUL SYLLABLE HIEUH WA KIYEOKSIOS + 0xC353: 0xD659, //HANGUL SYLLABLE HIEUH WA NIEUNCIEUC + 0xC354: 0xD65A, //HANGUL SYLLABLE HIEUH WA NIEUNHIEUH + 0xC355: 0xD65B, //HANGUL SYLLABLE HIEUH WA TIKEUT + 0xC356: 0xD65D, //HANGUL SYLLABLE HIEUH WA RIEULKIYEOK + 0xC357: 0xD65E, //HANGUL SYLLABLE HIEUH WA RIEULMIEUM + 0xC358: 0xD65F, //HANGUL SYLLABLE HIEUH WA RIEULPIEUP + 0xC359: 0xD660, //HANGUL SYLLABLE HIEUH WA RIEULSIOS + 0xC35A: 0xD661, //HANGUL SYLLABLE HIEUH WA RIEULTHIEUTH + 0xC361: 0xD662, //HANGUL SYLLABLE HIEUH WA RIEULPHIEUPH + 0xC362: 0xD663, //HANGUL SYLLABLE HIEUH WA RIEULHIEUH + 0xC363: 0xD664, //HANGUL SYLLABLE HIEUH WA MIEUM + 0xC364: 0xD665, //HANGUL SYLLABLE HIEUH WA PIEUP + 0xC365: 0xD666, //HANGUL SYLLABLE HIEUH WA PIEUPSIOS + 0xC366: 0xD668, //HANGUL SYLLABLE HIEUH WA SSANGSIOS + 0xC367: 0xD66A, //HANGUL SYLLABLE HIEUH WA CIEUC + 0xC368: 0xD66B, //HANGUL SYLLABLE HIEUH WA CHIEUCH + 0xC369: 0xD66C, //HANGUL SYLLABLE HIEUH WA KHIEUKH + 0xC36A: 0xD66D, //HANGUL SYLLABLE HIEUH WA THIEUTH + 0xC36B: 0xD66E, //HANGUL SYLLABLE HIEUH WA PHIEUPH + 0xC36C: 0xD66F, //HANGUL SYLLABLE HIEUH WA HIEUH + 0xC36D: 0xD672, //HANGUL SYLLABLE HIEUH WAE SSANGKIYEOK + 0xC36E: 0xD673, //HANGUL SYLLABLE HIEUH WAE KIYEOKSIOS + 0xC36F: 0xD675, //HANGUL SYLLABLE HIEUH WAE NIEUNCIEUC + 0xC370: 0xD676, //HANGUL SYLLABLE HIEUH WAE NIEUNHIEUH + 0xC371: 0xD677, //HANGUL SYLLABLE HIEUH WAE TIKEUT + 0xC372: 0xD678, //HANGUL SYLLABLE HIEUH WAE RIEUL + 0xC373: 0xD679, //HANGUL SYLLABLE HIEUH WAE RIEULKIYEOK + 0xC374: 0xD67A, //HANGUL SYLLABLE HIEUH WAE RIEULMIEUM + 0xC375: 0xD67B, //HANGUL SYLLABLE HIEUH WAE RIEULPIEUP + 0xC376: 0xD67C, //HANGUL SYLLABLE HIEUH WAE RIEULSIOS + 0xC377: 0xD67D, //HANGUL SYLLABLE HIEUH WAE RIEULTHIEUTH + 0xC378: 0xD67E, //HANGUL SYLLABLE HIEUH WAE RIEULPHIEUPH + 0xC379: 0xD67F, //HANGUL SYLLABLE HIEUH WAE RIEULHIEUH + 0xC37A: 0xD680, //HANGUL SYLLABLE HIEUH WAE MIEUM + 0xC381: 0xD681, //HANGUL SYLLABLE HIEUH WAE PIEUP + 0xC382: 0xD682, //HANGUL SYLLABLE HIEUH WAE PIEUPSIOS + 0xC383: 0xD684, //HANGUL SYLLABLE HIEUH WAE SSANGSIOS + 0xC384: 0xD686, //HANGUL SYLLABLE HIEUH WAE CIEUC + 0xC385: 0xD687, //HANGUL SYLLABLE HIEUH WAE CHIEUCH + 0xC386: 0xD688, //HANGUL SYLLABLE HIEUH WAE KHIEUKH + 0xC387: 0xD689, //HANGUL SYLLABLE HIEUH WAE THIEUTH + 0xC388: 0xD68A, //HANGUL SYLLABLE HIEUH WAE PHIEUPH + 0xC389: 0xD68B, //HANGUL SYLLABLE HIEUH WAE HIEUH + 0xC38A: 0xD68E, //HANGUL SYLLABLE HIEUH OE SSANGKIYEOK + 0xC38B: 0xD68F, //HANGUL SYLLABLE HIEUH OE KIYEOKSIOS + 0xC38C: 0xD691, //HANGUL SYLLABLE HIEUH OE NIEUNCIEUC + 0xC38D: 0xD692, //HANGUL SYLLABLE HIEUH OE NIEUNHIEUH + 0xC38E: 0xD693, //HANGUL SYLLABLE HIEUH OE TIKEUT + 0xC38F: 0xD695, //HANGUL SYLLABLE HIEUH OE RIEULKIYEOK + 0xC390: 0xD696, //HANGUL SYLLABLE HIEUH OE RIEULMIEUM + 0xC391: 0xD697, //HANGUL SYLLABLE HIEUH OE RIEULPIEUP + 0xC392: 0xD698, //HANGUL SYLLABLE HIEUH OE RIEULSIOS + 0xC393: 0xD699, //HANGUL SYLLABLE HIEUH OE RIEULTHIEUTH + 0xC394: 0xD69A, //HANGUL SYLLABLE HIEUH OE RIEULPHIEUPH + 0xC395: 0xD69B, //HANGUL SYLLABLE HIEUH OE RIEULHIEUH + 0xC396: 0xD69C, //HANGUL SYLLABLE HIEUH OE MIEUM + 0xC397: 0xD69E, //HANGUL SYLLABLE HIEUH OE PIEUPSIOS + 0xC398: 0xD6A0, //HANGUL SYLLABLE HIEUH OE SSANGSIOS + 0xC399: 0xD6A2, //HANGUL SYLLABLE HIEUH OE CIEUC + 0xC39A: 0xD6A3, //HANGUL SYLLABLE HIEUH OE CHIEUCH + 0xC39B: 0xD6A4, //HANGUL SYLLABLE HIEUH OE KHIEUKH + 0xC39C: 0xD6A5, //HANGUL SYLLABLE HIEUH OE THIEUTH + 0xC39D: 0xD6A6, //HANGUL SYLLABLE HIEUH OE PHIEUPH + 0xC39E: 0xD6A7, //HANGUL SYLLABLE HIEUH OE HIEUH + 0xC39F: 0xD6A9, //HANGUL SYLLABLE HIEUH YO KIYEOK + 0xC3A0: 0xD6AA, //HANGUL SYLLABLE HIEUH YO SSANGKIYEOK + 0xC3A1: 0xCC3C, //HANGUL SYLLABLE CHIEUCH A SSANGSIOS + 0xC3A2: 0xCC3D, //HANGUL SYLLABLE CHIEUCH A IEUNG + 0xC3A3: 0xCC3E, //HANGUL SYLLABLE CHIEUCH A CIEUC + 0xC3A4: 0xCC44, //HANGUL SYLLABLE CHIEUCH AE + 0xC3A5: 0xCC45, //HANGUL SYLLABLE CHIEUCH AE KIYEOK + 0xC3A6: 0xCC48, //HANGUL SYLLABLE CHIEUCH AE NIEUN + 0xC3A7: 0xCC4C, //HANGUL SYLLABLE CHIEUCH AE RIEUL + 0xC3A8: 0xCC54, //HANGUL SYLLABLE CHIEUCH AE MIEUM + 0xC3A9: 0xCC55, //HANGUL SYLLABLE CHIEUCH AE PIEUP + 0xC3AA: 0xCC57, //HANGUL SYLLABLE CHIEUCH AE SIOS + 0xC3AB: 0xCC58, //HANGUL SYLLABLE CHIEUCH AE SSANGSIOS + 0xC3AC: 0xCC59, //HANGUL SYLLABLE CHIEUCH AE IEUNG + 0xC3AD: 0xCC60, //HANGUL SYLLABLE CHIEUCH YA + 0xC3AE: 0xCC64, //HANGUL SYLLABLE CHIEUCH YA NIEUN + 0xC3AF: 0xCC66, //HANGUL SYLLABLE CHIEUCH YA NIEUNHIEUH + 0xC3B0: 0xCC68, //HANGUL SYLLABLE CHIEUCH YA RIEUL + 0xC3B1: 0xCC70, //HANGUL SYLLABLE CHIEUCH YA MIEUM + 0xC3B2: 0xCC75, //HANGUL SYLLABLE CHIEUCH YA IEUNG + 0xC3B3: 0xCC98, //HANGUL SYLLABLE CHIEUCH EO + 0xC3B4: 0xCC99, //HANGUL SYLLABLE CHIEUCH EO KIYEOK + 0xC3B5: 0xCC9C, //HANGUL SYLLABLE CHIEUCH EO NIEUN + 0xC3B6: 0xCCA0, //HANGUL SYLLABLE CHIEUCH EO RIEUL + 0xC3B7: 0xCCA8, //HANGUL SYLLABLE CHIEUCH EO MIEUM + 0xC3B8: 0xCCA9, //HANGUL SYLLABLE CHIEUCH EO PIEUP + 0xC3B9: 0xCCAB, //HANGUL SYLLABLE CHIEUCH EO SIOS + 0xC3BA: 0xCCAC, //HANGUL SYLLABLE CHIEUCH EO SSANGSIOS + 0xC3BB: 0xCCAD, //HANGUL SYLLABLE CHIEUCH EO IEUNG + 0xC3BC: 0xCCB4, //HANGUL SYLLABLE CHIEUCH E + 0xC3BD: 0xCCB5, //HANGUL SYLLABLE CHIEUCH E KIYEOK + 0xC3BE: 0xCCB8, //HANGUL SYLLABLE CHIEUCH E NIEUN + 0xC3BF: 0xCCBC, //HANGUL SYLLABLE CHIEUCH E RIEUL + 0xC3C0: 0xCCC4, //HANGUL SYLLABLE CHIEUCH E MIEUM + 0xC3C1: 0xCCC5, //HANGUL SYLLABLE CHIEUCH E PIEUP + 0xC3C2: 0xCCC7, //HANGUL SYLLABLE CHIEUCH E SIOS + 0xC3C3: 0xCCC9, //HANGUL SYLLABLE CHIEUCH E IEUNG + 0xC3C4: 0xCCD0, //HANGUL SYLLABLE CHIEUCH YEO + 0xC3C5: 0xCCD4, //HANGUL SYLLABLE CHIEUCH YEO NIEUN + 0xC3C6: 0xCCE4, //HANGUL SYLLABLE CHIEUCH YEO SSANGSIOS + 0xC3C7: 0xCCEC, //HANGUL SYLLABLE CHIEUCH YE + 0xC3C8: 0xCCF0, //HANGUL SYLLABLE CHIEUCH YE NIEUN + 0xC3C9: 0xCD01, //HANGUL SYLLABLE CHIEUCH YE IEUNG + 0xC3CA: 0xCD08, //HANGUL SYLLABLE CHIEUCH O + 0xC3CB: 0xCD09, //HANGUL SYLLABLE CHIEUCH O KIYEOK + 0xC3CC: 0xCD0C, //HANGUL SYLLABLE CHIEUCH O NIEUN + 0xC3CD: 0xCD10, //HANGUL SYLLABLE CHIEUCH O RIEUL + 0xC3CE: 0xCD18, //HANGUL SYLLABLE CHIEUCH O MIEUM + 0xC3CF: 0xCD19, //HANGUL SYLLABLE CHIEUCH O PIEUP + 0xC3D0: 0xCD1B, //HANGUL SYLLABLE CHIEUCH O SIOS + 0xC3D1: 0xCD1D, //HANGUL SYLLABLE CHIEUCH O IEUNG + 0xC3D2: 0xCD24, //HANGUL SYLLABLE CHIEUCH WA + 0xC3D3: 0xCD28, //HANGUL SYLLABLE CHIEUCH WA NIEUN + 0xC3D4: 0xCD2C, //HANGUL SYLLABLE CHIEUCH WA RIEUL + 0xC3D5: 0xCD39, //HANGUL SYLLABLE CHIEUCH WA IEUNG + 0xC3D6: 0xCD5C, //HANGUL SYLLABLE CHIEUCH OE + 0xC3D7: 0xCD60, //HANGUL SYLLABLE CHIEUCH OE NIEUN + 0xC3D8: 0xCD64, //HANGUL SYLLABLE CHIEUCH OE RIEUL + 0xC3D9: 0xCD6C, //HANGUL SYLLABLE CHIEUCH OE MIEUM + 0xC3DA: 0xCD6D, //HANGUL SYLLABLE CHIEUCH OE PIEUP + 0xC3DB: 0xCD6F, //HANGUL SYLLABLE CHIEUCH OE SIOS + 0xC3DC: 0xCD71, //HANGUL SYLLABLE CHIEUCH OE IEUNG + 0xC3DD: 0xCD78, //HANGUL SYLLABLE CHIEUCH YO + 0xC3DE: 0xCD88, //HANGUL SYLLABLE CHIEUCH YO MIEUM + 0xC3DF: 0xCD94, //HANGUL SYLLABLE CHIEUCH U + 0xC3E0: 0xCD95, //HANGUL SYLLABLE CHIEUCH U KIYEOK + 0xC3E1: 0xCD98, //HANGUL SYLLABLE CHIEUCH U NIEUN + 0xC3E2: 0xCD9C, //HANGUL SYLLABLE CHIEUCH U RIEUL + 0xC3E3: 0xCDA4, //HANGUL SYLLABLE CHIEUCH U MIEUM + 0xC3E4: 0xCDA5, //HANGUL SYLLABLE CHIEUCH U PIEUP + 0xC3E5: 0xCDA7, //HANGUL SYLLABLE CHIEUCH U SIOS + 0xC3E6: 0xCDA9, //HANGUL SYLLABLE CHIEUCH U IEUNG + 0xC3E7: 0xCDB0, //HANGUL SYLLABLE CHIEUCH WEO + 0xC3E8: 0xCDC4, //HANGUL SYLLABLE CHIEUCH WEO SSANGSIOS + 0xC3E9: 0xCDCC, //HANGUL SYLLABLE CHIEUCH WE + 0xC3EA: 0xCDD0, //HANGUL SYLLABLE CHIEUCH WE NIEUN + 0xC3EB: 0xCDE8, //HANGUL SYLLABLE CHIEUCH WI + 0xC3EC: 0xCDEC, //HANGUL SYLLABLE CHIEUCH WI NIEUN + 0xC3ED: 0xCDF0, //HANGUL SYLLABLE CHIEUCH WI RIEUL + 0xC3EE: 0xCDF8, //HANGUL SYLLABLE CHIEUCH WI MIEUM + 0xC3EF: 0xCDF9, //HANGUL SYLLABLE CHIEUCH WI PIEUP + 0xC3F0: 0xCDFB, //HANGUL SYLLABLE CHIEUCH WI SIOS + 0xC3F1: 0xCDFD, //HANGUL SYLLABLE CHIEUCH WI IEUNG + 0xC3F2: 0xCE04, //HANGUL SYLLABLE CHIEUCH YU + 0xC3F3: 0xCE08, //HANGUL SYLLABLE CHIEUCH YU NIEUN + 0xC3F4: 0xCE0C, //HANGUL SYLLABLE CHIEUCH YU RIEUL + 0xC3F5: 0xCE14, //HANGUL SYLLABLE CHIEUCH YU MIEUM + 0xC3F6: 0xCE19, //HANGUL SYLLABLE CHIEUCH YU IEUNG + 0xC3F7: 0xCE20, //HANGUL SYLLABLE CHIEUCH EU + 0xC3F8: 0xCE21, //HANGUL SYLLABLE CHIEUCH EU KIYEOK + 0xC3F9: 0xCE24, //HANGUL SYLLABLE CHIEUCH EU NIEUN + 0xC3FA: 0xCE28, //HANGUL SYLLABLE CHIEUCH EU RIEUL + 0xC3FB: 0xCE30, //HANGUL SYLLABLE CHIEUCH EU MIEUM + 0xC3FC: 0xCE31, //HANGUL SYLLABLE CHIEUCH EU PIEUP + 0xC3FD: 0xCE33, //HANGUL SYLLABLE CHIEUCH EU SIOS + 0xC3FE: 0xCE35, //HANGUL SYLLABLE CHIEUCH EU IEUNG + 0xC441: 0xD6AB, //HANGUL SYLLABLE HIEUH YO KIYEOKSIOS + 0xC442: 0xD6AD, //HANGUL SYLLABLE HIEUH YO NIEUNCIEUC + 0xC443: 0xD6AE, //HANGUL SYLLABLE HIEUH YO NIEUNHIEUH + 0xC444: 0xD6AF, //HANGUL SYLLABLE HIEUH YO TIKEUT + 0xC445: 0xD6B1, //HANGUL SYLLABLE HIEUH YO RIEULKIYEOK + 0xC446: 0xD6B2, //HANGUL SYLLABLE HIEUH YO RIEULMIEUM + 0xC447: 0xD6B3, //HANGUL SYLLABLE HIEUH YO RIEULPIEUP + 0xC448: 0xD6B4, //HANGUL SYLLABLE HIEUH YO RIEULSIOS + 0xC449: 0xD6B5, //HANGUL SYLLABLE HIEUH YO RIEULTHIEUTH + 0xC44A: 0xD6B6, //HANGUL SYLLABLE HIEUH YO RIEULPHIEUPH + 0xC44B: 0xD6B7, //HANGUL SYLLABLE HIEUH YO RIEULHIEUH + 0xC44C: 0xD6B8, //HANGUL SYLLABLE HIEUH YO MIEUM + 0xC44D: 0xD6BA, //HANGUL SYLLABLE HIEUH YO PIEUPSIOS + 0xC44E: 0xD6BC, //HANGUL SYLLABLE HIEUH YO SSANGSIOS + 0xC44F: 0xD6BD, //HANGUL SYLLABLE HIEUH YO IEUNG + 0xC450: 0xD6BE, //HANGUL SYLLABLE HIEUH YO CIEUC + 0xC451: 0xD6BF, //HANGUL SYLLABLE HIEUH YO CHIEUCH + 0xC452: 0xD6C0, //HANGUL SYLLABLE HIEUH YO KHIEUKH + 0xC453: 0xD6C1, //HANGUL SYLLABLE HIEUH YO THIEUTH + 0xC454: 0xD6C2, //HANGUL SYLLABLE HIEUH YO PHIEUPH + 0xC455: 0xD6C3, //HANGUL SYLLABLE HIEUH YO HIEUH + 0xC456: 0xD6C6, //HANGUL SYLLABLE HIEUH U SSANGKIYEOK + 0xC457: 0xD6C7, //HANGUL SYLLABLE HIEUH U KIYEOKSIOS + 0xC458: 0xD6C9, //HANGUL SYLLABLE HIEUH U NIEUNCIEUC + 0xC459: 0xD6CA, //HANGUL SYLLABLE HIEUH U NIEUNHIEUH + 0xC45A: 0xD6CB, //HANGUL SYLLABLE HIEUH U TIKEUT + 0xC461: 0xD6CD, //HANGUL SYLLABLE HIEUH U RIEULKIYEOK + 0xC462: 0xD6CE, //HANGUL SYLLABLE HIEUH U RIEULMIEUM + 0xC463: 0xD6CF, //HANGUL SYLLABLE HIEUH U RIEULPIEUP + 0xC464: 0xD6D0, //HANGUL SYLLABLE HIEUH U RIEULSIOS + 0xC465: 0xD6D2, //HANGUL SYLLABLE HIEUH U RIEULPHIEUPH + 0xC466: 0xD6D3, //HANGUL SYLLABLE HIEUH U RIEULHIEUH + 0xC467: 0xD6D5, //HANGUL SYLLABLE HIEUH U PIEUP + 0xC468: 0xD6D6, //HANGUL SYLLABLE HIEUH U PIEUPSIOS + 0xC469: 0xD6D8, //HANGUL SYLLABLE HIEUH U SSANGSIOS + 0xC46A: 0xD6DA, //HANGUL SYLLABLE HIEUH U CIEUC + 0xC46B: 0xD6DB, //HANGUL SYLLABLE HIEUH U CHIEUCH + 0xC46C: 0xD6DC, //HANGUL SYLLABLE HIEUH U KHIEUKH + 0xC46D: 0xD6DD, //HANGUL SYLLABLE HIEUH U THIEUTH + 0xC46E: 0xD6DE, //HANGUL SYLLABLE HIEUH U PHIEUPH + 0xC46F: 0xD6DF, //HANGUL SYLLABLE HIEUH U HIEUH + 0xC470: 0xD6E1, //HANGUL SYLLABLE HIEUH WEO KIYEOK + 0xC471: 0xD6E2, //HANGUL SYLLABLE HIEUH WEO SSANGKIYEOK + 0xC472: 0xD6E3, //HANGUL SYLLABLE HIEUH WEO KIYEOKSIOS + 0xC473: 0xD6E5, //HANGUL SYLLABLE HIEUH WEO NIEUNCIEUC + 0xC474: 0xD6E6, //HANGUL SYLLABLE HIEUH WEO NIEUNHIEUH + 0xC475: 0xD6E7, //HANGUL SYLLABLE HIEUH WEO TIKEUT + 0xC476: 0xD6E9, //HANGUL SYLLABLE HIEUH WEO RIEULKIYEOK + 0xC477: 0xD6EA, //HANGUL SYLLABLE HIEUH WEO RIEULMIEUM + 0xC478: 0xD6EB, //HANGUL SYLLABLE HIEUH WEO RIEULPIEUP + 0xC479: 0xD6EC, //HANGUL SYLLABLE HIEUH WEO RIEULSIOS + 0xC47A: 0xD6ED, //HANGUL SYLLABLE HIEUH WEO RIEULTHIEUTH + 0xC481: 0xD6EE, //HANGUL SYLLABLE HIEUH WEO RIEULPHIEUPH + 0xC482: 0xD6EF, //HANGUL SYLLABLE HIEUH WEO RIEULHIEUH + 0xC483: 0xD6F1, //HANGUL SYLLABLE HIEUH WEO PIEUP + 0xC484: 0xD6F2, //HANGUL SYLLABLE HIEUH WEO PIEUPSIOS + 0xC485: 0xD6F3, //HANGUL SYLLABLE HIEUH WEO SIOS + 0xC486: 0xD6F4, //HANGUL SYLLABLE HIEUH WEO SSANGSIOS + 0xC487: 0xD6F6, //HANGUL SYLLABLE HIEUH WEO CIEUC + 0xC488: 0xD6F7, //HANGUL SYLLABLE HIEUH WEO CHIEUCH + 0xC489: 0xD6F8, //HANGUL SYLLABLE HIEUH WEO KHIEUKH + 0xC48A: 0xD6F9, //HANGUL SYLLABLE HIEUH WEO THIEUTH + 0xC48B: 0xD6FA, //HANGUL SYLLABLE HIEUH WEO PHIEUPH + 0xC48C: 0xD6FB, //HANGUL SYLLABLE HIEUH WEO HIEUH + 0xC48D: 0xD6FE, //HANGUL SYLLABLE HIEUH WE SSANGKIYEOK + 0xC48E: 0xD6FF, //HANGUL SYLLABLE HIEUH WE KIYEOKSIOS + 0xC48F: 0xD701, //HANGUL SYLLABLE HIEUH WE NIEUNCIEUC + 0xC490: 0xD702, //HANGUL SYLLABLE HIEUH WE NIEUNHIEUH + 0xC491: 0xD703, //HANGUL SYLLABLE HIEUH WE TIKEUT + 0xC492: 0xD705, //HANGUL SYLLABLE HIEUH WE RIEULKIYEOK + 0xC493: 0xD706, //HANGUL SYLLABLE HIEUH WE RIEULMIEUM + 0xC494: 0xD707, //HANGUL SYLLABLE HIEUH WE RIEULPIEUP + 0xC495: 0xD708, //HANGUL SYLLABLE HIEUH WE RIEULSIOS + 0xC496: 0xD709, //HANGUL SYLLABLE HIEUH WE RIEULTHIEUTH + 0xC497: 0xD70A, //HANGUL SYLLABLE HIEUH WE RIEULPHIEUPH + 0xC498: 0xD70B, //HANGUL SYLLABLE HIEUH WE RIEULHIEUH + 0xC499: 0xD70C, //HANGUL SYLLABLE HIEUH WE MIEUM + 0xC49A: 0xD70D, //HANGUL SYLLABLE HIEUH WE PIEUP + 0xC49B: 0xD70E, //HANGUL SYLLABLE HIEUH WE PIEUPSIOS + 0xC49C: 0xD70F, //HANGUL SYLLABLE HIEUH WE SIOS + 0xC49D: 0xD710, //HANGUL SYLLABLE HIEUH WE SSANGSIOS + 0xC49E: 0xD712, //HANGUL SYLLABLE HIEUH WE CIEUC + 0xC49F: 0xD713, //HANGUL SYLLABLE HIEUH WE CHIEUCH + 0xC4A0: 0xD714, //HANGUL SYLLABLE HIEUH WE KHIEUKH + 0xC4A1: 0xCE58, //HANGUL SYLLABLE CHIEUCH I + 0xC4A2: 0xCE59, //HANGUL SYLLABLE CHIEUCH I KIYEOK + 0xC4A3: 0xCE5C, //HANGUL SYLLABLE CHIEUCH I NIEUN + 0xC4A4: 0xCE5F, //HANGUL SYLLABLE CHIEUCH I TIKEUT + 0xC4A5: 0xCE60, //HANGUL SYLLABLE CHIEUCH I RIEUL + 0xC4A6: 0xCE61, //HANGUL SYLLABLE CHIEUCH I RIEULKIYEOK + 0xC4A7: 0xCE68, //HANGUL SYLLABLE CHIEUCH I MIEUM + 0xC4A8: 0xCE69, //HANGUL SYLLABLE CHIEUCH I PIEUP + 0xC4A9: 0xCE6B, //HANGUL SYLLABLE CHIEUCH I SIOS + 0xC4AA: 0xCE6D, //HANGUL SYLLABLE CHIEUCH I IEUNG + 0xC4AB: 0xCE74, //HANGUL SYLLABLE KHIEUKH A + 0xC4AC: 0xCE75, //HANGUL SYLLABLE KHIEUKH A KIYEOK + 0xC4AD: 0xCE78, //HANGUL SYLLABLE KHIEUKH A NIEUN + 0xC4AE: 0xCE7C, //HANGUL SYLLABLE KHIEUKH A RIEUL + 0xC4AF: 0xCE84, //HANGUL SYLLABLE KHIEUKH A MIEUM + 0xC4B0: 0xCE85, //HANGUL SYLLABLE KHIEUKH A PIEUP + 0xC4B1: 0xCE87, //HANGUL SYLLABLE KHIEUKH A SIOS + 0xC4B2: 0xCE89, //HANGUL SYLLABLE KHIEUKH A IEUNG + 0xC4B3: 0xCE90, //HANGUL SYLLABLE KHIEUKH AE + 0xC4B4: 0xCE91, //HANGUL SYLLABLE KHIEUKH AE KIYEOK + 0xC4B5: 0xCE94, //HANGUL SYLLABLE KHIEUKH AE NIEUN + 0xC4B6: 0xCE98, //HANGUL SYLLABLE KHIEUKH AE RIEUL + 0xC4B7: 0xCEA0, //HANGUL SYLLABLE KHIEUKH AE MIEUM + 0xC4B8: 0xCEA1, //HANGUL SYLLABLE KHIEUKH AE PIEUP + 0xC4B9: 0xCEA3, //HANGUL SYLLABLE KHIEUKH AE SIOS + 0xC4BA: 0xCEA4, //HANGUL SYLLABLE KHIEUKH AE SSANGSIOS + 0xC4BB: 0xCEA5, //HANGUL SYLLABLE KHIEUKH AE IEUNG + 0xC4BC: 0xCEAC, //HANGUL SYLLABLE KHIEUKH YA + 0xC4BD: 0xCEAD, //HANGUL SYLLABLE KHIEUKH YA KIYEOK + 0xC4BE: 0xCEC1, //HANGUL SYLLABLE KHIEUKH YA IEUNG + 0xC4BF: 0xCEE4, //HANGUL SYLLABLE KHIEUKH EO + 0xC4C0: 0xCEE5, //HANGUL SYLLABLE KHIEUKH EO KIYEOK + 0xC4C1: 0xCEE8, //HANGUL SYLLABLE KHIEUKH EO NIEUN + 0xC4C2: 0xCEEB, //HANGUL SYLLABLE KHIEUKH EO TIKEUT + 0xC4C3: 0xCEEC, //HANGUL SYLLABLE KHIEUKH EO RIEUL + 0xC4C4: 0xCEF4, //HANGUL SYLLABLE KHIEUKH EO MIEUM + 0xC4C5: 0xCEF5, //HANGUL SYLLABLE KHIEUKH EO PIEUP + 0xC4C6: 0xCEF7, //HANGUL SYLLABLE KHIEUKH EO SIOS + 0xC4C7: 0xCEF8, //HANGUL SYLLABLE KHIEUKH EO SSANGSIOS + 0xC4C8: 0xCEF9, //HANGUL SYLLABLE KHIEUKH EO IEUNG + 0xC4C9: 0xCF00, //HANGUL SYLLABLE KHIEUKH E + 0xC4CA: 0xCF01, //HANGUL SYLLABLE KHIEUKH E KIYEOK + 0xC4CB: 0xCF04, //HANGUL SYLLABLE KHIEUKH E NIEUN + 0xC4CC: 0xCF08, //HANGUL SYLLABLE KHIEUKH E RIEUL + 0xC4CD: 0xCF10, //HANGUL SYLLABLE KHIEUKH E MIEUM + 0xC4CE: 0xCF11, //HANGUL SYLLABLE KHIEUKH E PIEUP + 0xC4CF: 0xCF13, //HANGUL SYLLABLE KHIEUKH E SIOS + 0xC4D0: 0xCF15, //HANGUL SYLLABLE KHIEUKH E IEUNG + 0xC4D1: 0xCF1C, //HANGUL SYLLABLE KHIEUKH YEO + 0xC4D2: 0xCF20, //HANGUL SYLLABLE KHIEUKH YEO NIEUN + 0xC4D3: 0xCF24, //HANGUL SYLLABLE KHIEUKH YEO RIEUL + 0xC4D4: 0xCF2C, //HANGUL SYLLABLE KHIEUKH YEO MIEUM + 0xC4D5: 0xCF2D, //HANGUL SYLLABLE KHIEUKH YEO PIEUP + 0xC4D6: 0xCF2F, //HANGUL SYLLABLE KHIEUKH YEO SIOS + 0xC4D7: 0xCF30, //HANGUL SYLLABLE KHIEUKH YEO SSANGSIOS + 0xC4D8: 0xCF31, //HANGUL SYLLABLE KHIEUKH YEO IEUNG + 0xC4D9: 0xCF38, //HANGUL SYLLABLE KHIEUKH YE + 0xC4DA: 0xCF54, //HANGUL SYLLABLE KHIEUKH O + 0xC4DB: 0xCF55, //HANGUL SYLLABLE KHIEUKH O KIYEOK + 0xC4DC: 0xCF58, //HANGUL SYLLABLE KHIEUKH O NIEUN + 0xC4DD: 0xCF5C, //HANGUL SYLLABLE KHIEUKH O RIEUL + 0xC4DE: 0xCF64, //HANGUL SYLLABLE KHIEUKH O MIEUM + 0xC4DF: 0xCF65, //HANGUL SYLLABLE KHIEUKH O PIEUP + 0xC4E0: 0xCF67, //HANGUL SYLLABLE KHIEUKH O SIOS + 0xC4E1: 0xCF69, //HANGUL SYLLABLE KHIEUKH O IEUNG + 0xC4E2: 0xCF70, //HANGUL SYLLABLE KHIEUKH WA + 0xC4E3: 0xCF71, //HANGUL SYLLABLE KHIEUKH WA KIYEOK + 0xC4E4: 0xCF74, //HANGUL SYLLABLE KHIEUKH WA NIEUN + 0xC4E5: 0xCF78, //HANGUL SYLLABLE KHIEUKH WA RIEUL + 0xC4E6: 0xCF80, //HANGUL SYLLABLE KHIEUKH WA MIEUM + 0xC4E7: 0xCF85, //HANGUL SYLLABLE KHIEUKH WA IEUNG + 0xC4E8: 0xCF8C, //HANGUL SYLLABLE KHIEUKH WAE + 0xC4E9: 0xCFA1, //HANGUL SYLLABLE KHIEUKH WAE IEUNG + 0xC4EA: 0xCFA8, //HANGUL SYLLABLE KHIEUKH OE + 0xC4EB: 0xCFB0, //HANGUL SYLLABLE KHIEUKH OE RIEUL + 0xC4EC: 0xCFC4, //HANGUL SYLLABLE KHIEUKH YO + 0xC4ED: 0xCFE0, //HANGUL SYLLABLE KHIEUKH U + 0xC4EE: 0xCFE1, //HANGUL SYLLABLE KHIEUKH U KIYEOK + 0xC4EF: 0xCFE4, //HANGUL SYLLABLE KHIEUKH U NIEUN + 0xC4F0: 0xCFE8, //HANGUL SYLLABLE KHIEUKH U RIEUL + 0xC4F1: 0xCFF0, //HANGUL SYLLABLE KHIEUKH U MIEUM + 0xC4F2: 0xCFF1, //HANGUL SYLLABLE KHIEUKH U PIEUP + 0xC4F3: 0xCFF3, //HANGUL SYLLABLE KHIEUKH U SIOS + 0xC4F4: 0xCFF5, //HANGUL SYLLABLE KHIEUKH U IEUNG + 0xC4F5: 0xCFFC, //HANGUL SYLLABLE KHIEUKH WEO + 0xC4F6: 0xD000, //HANGUL SYLLABLE KHIEUKH WEO NIEUN + 0xC4F7: 0xD004, //HANGUL SYLLABLE KHIEUKH WEO RIEUL + 0xC4F8: 0xD011, //HANGUL SYLLABLE KHIEUKH WEO IEUNG + 0xC4F9: 0xD018, //HANGUL SYLLABLE KHIEUKH WE + 0xC4FA: 0xD02D, //HANGUL SYLLABLE KHIEUKH WE IEUNG + 0xC4FB: 0xD034, //HANGUL SYLLABLE KHIEUKH WI + 0xC4FC: 0xD035, //HANGUL SYLLABLE KHIEUKH WI KIYEOK + 0xC4FD: 0xD038, //HANGUL SYLLABLE KHIEUKH WI NIEUN + 0xC4FE: 0xD03C, //HANGUL SYLLABLE KHIEUKH WI RIEUL + 0xC541: 0xD715, //HANGUL SYLLABLE HIEUH WE THIEUTH + 0xC542: 0xD716, //HANGUL SYLLABLE HIEUH WE PHIEUPH + 0xC543: 0xD717, //HANGUL SYLLABLE HIEUH WE HIEUH + 0xC544: 0xD71A, //HANGUL SYLLABLE HIEUH WI SSANGKIYEOK + 0xC545: 0xD71B, //HANGUL SYLLABLE HIEUH WI KIYEOKSIOS + 0xC546: 0xD71D, //HANGUL SYLLABLE HIEUH WI NIEUNCIEUC + 0xC547: 0xD71E, //HANGUL SYLLABLE HIEUH WI NIEUNHIEUH + 0xC548: 0xD71F, //HANGUL SYLLABLE HIEUH WI TIKEUT + 0xC549: 0xD721, //HANGUL SYLLABLE HIEUH WI RIEULKIYEOK + 0xC54A: 0xD722, //HANGUL SYLLABLE HIEUH WI RIEULMIEUM + 0xC54B: 0xD723, //HANGUL SYLLABLE HIEUH WI RIEULPIEUP + 0xC54C: 0xD724, //HANGUL SYLLABLE HIEUH WI RIEULSIOS + 0xC54D: 0xD725, //HANGUL SYLLABLE HIEUH WI RIEULTHIEUTH + 0xC54E: 0xD726, //HANGUL SYLLABLE HIEUH WI RIEULPHIEUPH + 0xC54F: 0xD727, //HANGUL SYLLABLE HIEUH WI RIEULHIEUH + 0xC550: 0xD72A, //HANGUL SYLLABLE HIEUH WI PIEUPSIOS + 0xC551: 0xD72C, //HANGUL SYLLABLE HIEUH WI SSANGSIOS + 0xC552: 0xD72E, //HANGUL SYLLABLE HIEUH WI CIEUC + 0xC553: 0xD72F, //HANGUL SYLLABLE HIEUH WI CHIEUCH + 0xC554: 0xD730, //HANGUL SYLLABLE HIEUH WI KHIEUKH + 0xC555: 0xD731, //HANGUL SYLLABLE HIEUH WI THIEUTH + 0xC556: 0xD732, //HANGUL SYLLABLE HIEUH WI PHIEUPH + 0xC557: 0xD733, //HANGUL SYLLABLE HIEUH WI HIEUH + 0xC558: 0xD736, //HANGUL SYLLABLE HIEUH YU SSANGKIYEOK + 0xC559: 0xD737, //HANGUL SYLLABLE HIEUH YU KIYEOKSIOS + 0xC55A: 0xD739, //HANGUL SYLLABLE HIEUH YU NIEUNCIEUC + 0xC561: 0xD73A, //HANGUL SYLLABLE HIEUH YU NIEUNHIEUH + 0xC562: 0xD73B, //HANGUL SYLLABLE HIEUH YU TIKEUT + 0xC563: 0xD73D, //HANGUL SYLLABLE HIEUH YU RIEULKIYEOK + 0xC564: 0xD73E, //HANGUL SYLLABLE HIEUH YU RIEULMIEUM + 0xC565: 0xD73F, //HANGUL SYLLABLE HIEUH YU RIEULPIEUP + 0xC566: 0xD740, //HANGUL SYLLABLE HIEUH YU RIEULSIOS + 0xC567: 0xD741, //HANGUL SYLLABLE HIEUH YU RIEULTHIEUTH + 0xC568: 0xD742, //HANGUL SYLLABLE HIEUH YU RIEULPHIEUPH + 0xC569: 0xD743, //HANGUL SYLLABLE HIEUH YU RIEULHIEUH + 0xC56A: 0xD745, //HANGUL SYLLABLE HIEUH YU PIEUP + 0xC56B: 0xD746, //HANGUL SYLLABLE HIEUH YU PIEUPSIOS + 0xC56C: 0xD748, //HANGUL SYLLABLE HIEUH YU SSANGSIOS + 0xC56D: 0xD74A, //HANGUL SYLLABLE HIEUH YU CIEUC + 0xC56E: 0xD74B, //HANGUL SYLLABLE HIEUH YU CHIEUCH + 0xC56F: 0xD74C, //HANGUL SYLLABLE HIEUH YU KHIEUKH + 0xC570: 0xD74D, //HANGUL SYLLABLE HIEUH YU THIEUTH + 0xC571: 0xD74E, //HANGUL SYLLABLE HIEUH YU PHIEUPH + 0xC572: 0xD74F, //HANGUL SYLLABLE HIEUH YU HIEUH + 0xC573: 0xD752, //HANGUL SYLLABLE HIEUH EU SSANGKIYEOK + 0xC574: 0xD753, //HANGUL SYLLABLE HIEUH EU KIYEOKSIOS + 0xC575: 0xD755, //HANGUL SYLLABLE HIEUH EU NIEUNCIEUC + 0xC576: 0xD75A, //HANGUL SYLLABLE HIEUH EU RIEULMIEUM + 0xC577: 0xD75B, //HANGUL SYLLABLE HIEUH EU RIEULPIEUP + 0xC578: 0xD75C, //HANGUL SYLLABLE HIEUH EU RIEULSIOS + 0xC579: 0xD75D, //HANGUL SYLLABLE HIEUH EU RIEULTHIEUTH + 0xC57A: 0xD75E, //HANGUL SYLLABLE HIEUH EU RIEULPHIEUPH + 0xC581: 0xD75F, //HANGUL SYLLABLE HIEUH EU RIEULHIEUH + 0xC582: 0xD762, //HANGUL SYLLABLE HIEUH EU PIEUPSIOS + 0xC583: 0xD764, //HANGUL SYLLABLE HIEUH EU SSANGSIOS + 0xC584: 0xD766, //HANGUL SYLLABLE HIEUH EU CIEUC + 0xC585: 0xD767, //HANGUL SYLLABLE HIEUH EU CHIEUCH + 0xC586: 0xD768, //HANGUL SYLLABLE HIEUH EU KHIEUKH + 0xC587: 0xD76A, //HANGUL SYLLABLE HIEUH EU PHIEUPH + 0xC588: 0xD76B, //HANGUL SYLLABLE HIEUH EU HIEUH + 0xC589: 0xD76D, //HANGUL SYLLABLE HIEUH YI KIYEOK + 0xC58A: 0xD76E, //HANGUL SYLLABLE HIEUH YI SSANGKIYEOK + 0xC58B: 0xD76F, //HANGUL SYLLABLE HIEUH YI KIYEOKSIOS + 0xC58C: 0xD771, //HANGUL SYLLABLE HIEUH YI NIEUNCIEUC + 0xC58D: 0xD772, //HANGUL SYLLABLE HIEUH YI NIEUNHIEUH + 0xC58E: 0xD773, //HANGUL SYLLABLE HIEUH YI TIKEUT + 0xC58F: 0xD775, //HANGUL SYLLABLE HIEUH YI RIEULKIYEOK + 0xC590: 0xD776, //HANGUL SYLLABLE HIEUH YI RIEULMIEUM + 0xC591: 0xD777, //HANGUL SYLLABLE HIEUH YI RIEULPIEUP + 0xC592: 0xD778, //HANGUL SYLLABLE HIEUH YI RIEULSIOS + 0xC593: 0xD779, //HANGUL SYLLABLE HIEUH YI RIEULTHIEUTH + 0xC594: 0xD77A, //HANGUL SYLLABLE HIEUH YI RIEULPHIEUPH + 0xC595: 0xD77B, //HANGUL SYLLABLE HIEUH YI RIEULHIEUH + 0xC596: 0xD77E, //HANGUL SYLLABLE HIEUH YI PIEUPSIOS + 0xC597: 0xD77F, //HANGUL SYLLABLE HIEUH YI SIOS + 0xC598: 0xD780, //HANGUL SYLLABLE HIEUH YI SSANGSIOS + 0xC599: 0xD782, //HANGUL SYLLABLE HIEUH YI CIEUC + 0xC59A: 0xD783, //HANGUL SYLLABLE HIEUH YI CHIEUCH + 0xC59B: 0xD784, //HANGUL SYLLABLE HIEUH YI KHIEUKH + 0xC59C: 0xD785, //HANGUL SYLLABLE HIEUH YI THIEUTH + 0xC59D: 0xD786, //HANGUL SYLLABLE HIEUH YI PHIEUPH + 0xC59E: 0xD787, //HANGUL SYLLABLE HIEUH YI HIEUH + 0xC59F: 0xD78A, //HANGUL SYLLABLE HIEUH I SSANGKIYEOK + 0xC5A0: 0xD78B, //HANGUL SYLLABLE HIEUH I KIYEOKSIOS + 0xC5A1: 0xD044, //HANGUL SYLLABLE KHIEUKH WI MIEUM + 0xC5A2: 0xD045, //HANGUL SYLLABLE KHIEUKH WI PIEUP + 0xC5A3: 0xD047, //HANGUL SYLLABLE KHIEUKH WI SIOS + 0xC5A4: 0xD049, //HANGUL SYLLABLE KHIEUKH WI IEUNG + 0xC5A5: 0xD050, //HANGUL SYLLABLE KHIEUKH YU + 0xC5A6: 0xD054, //HANGUL SYLLABLE KHIEUKH YU NIEUN + 0xC5A7: 0xD058, //HANGUL SYLLABLE KHIEUKH YU RIEUL + 0xC5A8: 0xD060, //HANGUL SYLLABLE KHIEUKH YU MIEUM + 0xC5A9: 0xD06C, //HANGUL SYLLABLE KHIEUKH EU + 0xC5AA: 0xD06D, //HANGUL SYLLABLE KHIEUKH EU KIYEOK + 0xC5AB: 0xD070, //HANGUL SYLLABLE KHIEUKH EU NIEUN + 0xC5AC: 0xD074, //HANGUL SYLLABLE KHIEUKH EU RIEUL + 0xC5AD: 0xD07C, //HANGUL SYLLABLE KHIEUKH EU MIEUM + 0xC5AE: 0xD07D, //HANGUL SYLLABLE KHIEUKH EU PIEUP + 0xC5AF: 0xD081, //HANGUL SYLLABLE KHIEUKH EU IEUNG + 0xC5B0: 0xD0A4, //HANGUL SYLLABLE KHIEUKH I + 0xC5B1: 0xD0A5, //HANGUL SYLLABLE KHIEUKH I KIYEOK + 0xC5B2: 0xD0A8, //HANGUL SYLLABLE KHIEUKH I NIEUN + 0xC5B3: 0xD0AC, //HANGUL SYLLABLE KHIEUKH I RIEUL + 0xC5B4: 0xD0B4, //HANGUL SYLLABLE KHIEUKH I MIEUM + 0xC5B5: 0xD0B5, //HANGUL SYLLABLE KHIEUKH I PIEUP + 0xC5B6: 0xD0B7, //HANGUL SYLLABLE KHIEUKH I SIOS + 0xC5B7: 0xD0B9, //HANGUL SYLLABLE KHIEUKH I IEUNG + 0xC5B8: 0xD0C0, //HANGUL SYLLABLE THIEUTH A + 0xC5B9: 0xD0C1, //HANGUL SYLLABLE THIEUTH A KIYEOK + 0xC5BA: 0xD0C4, //HANGUL SYLLABLE THIEUTH A NIEUN + 0xC5BB: 0xD0C8, //HANGUL SYLLABLE THIEUTH A RIEUL + 0xC5BC: 0xD0C9, //HANGUL SYLLABLE THIEUTH A RIEULKIYEOK + 0xC5BD: 0xD0D0, //HANGUL SYLLABLE THIEUTH A MIEUM + 0xC5BE: 0xD0D1, //HANGUL SYLLABLE THIEUTH A PIEUP + 0xC5BF: 0xD0D3, //HANGUL SYLLABLE THIEUTH A SIOS + 0xC5C0: 0xD0D4, //HANGUL SYLLABLE THIEUTH A SSANGSIOS + 0xC5C1: 0xD0D5, //HANGUL SYLLABLE THIEUTH A IEUNG + 0xC5C2: 0xD0DC, //HANGUL SYLLABLE THIEUTH AE + 0xC5C3: 0xD0DD, //HANGUL SYLLABLE THIEUTH AE KIYEOK + 0xC5C4: 0xD0E0, //HANGUL SYLLABLE THIEUTH AE NIEUN + 0xC5C5: 0xD0E4, //HANGUL SYLLABLE THIEUTH AE RIEUL + 0xC5C6: 0xD0EC, //HANGUL SYLLABLE THIEUTH AE MIEUM + 0xC5C7: 0xD0ED, //HANGUL SYLLABLE THIEUTH AE PIEUP + 0xC5C8: 0xD0EF, //HANGUL SYLLABLE THIEUTH AE SIOS + 0xC5C9: 0xD0F0, //HANGUL SYLLABLE THIEUTH AE SSANGSIOS + 0xC5CA: 0xD0F1, //HANGUL SYLLABLE THIEUTH AE IEUNG + 0xC5CB: 0xD0F8, //HANGUL SYLLABLE THIEUTH YA + 0xC5CC: 0xD10D, //HANGUL SYLLABLE THIEUTH YA IEUNG + 0xC5CD: 0xD130, //HANGUL SYLLABLE THIEUTH EO + 0xC5CE: 0xD131, //HANGUL SYLLABLE THIEUTH EO KIYEOK + 0xC5CF: 0xD134, //HANGUL SYLLABLE THIEUTH EO NIEUN + 0xC5D0: 0xD138, //HANGUL SYLLABLE THIEUTH EO RIEUL + 0xC5D1: 0xD13A, //HANGUL SYLLABLE THIEUTH EO RIEULMIEUM + 0xC5D2: 0xD140, //HANGUL SYLLABLE THIEUTH EO MIEUM + 0xC5D3: 0xD141, //HANGUL SYLLABLE THIEUTH EO PIEUP + 0xC5D4: 0xD143, //HANGUL SYLLABLE THIEUTH EO SIOS + 0xC5D5: 0xD144, //HANGUL SYLLABLE THIEUTH EO SSANGSIOS + 0xC5D6: 0xD145, //HANGUL SYLLABLE THIEUTH EO IEUNG + 0xC5D7: 0xD14C, //HANGUL SYLLABLE THIEUTH E + 0xC5D8: 0xD14D, //HANGUL SYLLABLE THIEUTH E KIYEOK + 0xC5D9: 0xD150, //HANGUL SYLLABLE THIEUTH E NIEUN + 0xC5DA: 0xD154, //HANGUL SYLLABLE THIEUTH E RIEUL + 0xC5DB: 0xD15C, //HANGUL SYLLABLE THIEUTH E MIEUM + 0xC5DC: 0xD15D, //HANGUL SYLLABLE THIEUTH E PIEUP + 0xC5DD: 0xD15F, //HANGUL SYLLABLE THIEUTH E SIOS + 0xC5DE: 0xD161, //HANGUL SYLLABLE THIEUTH E IEUNG + 0xC5DF: 0xD168, //HANGUL SYLLABLE THIEUTH YEO + 0xC5E0: 0xD16C, //HANGUL SYLLABLE THIEUTH YEO NIEUN + 0xC5E1: 0xD17C, //HANGUL SYLLABLE THIEUTH YEO SSANGSIOS + 0xC5E2: 0xD184, //HANGUL SYLLABLE THIEUTH YE + 0xC5E3: 0xD188, //HANGUL SYLLABLE THIEUTH YE NIEUN + 0xC5E4: 0xD1A0, //HANGUL SYLLABLE THIEUTH O + 0xC5E5: 0xD1A1, //HANGUL SYLLABLE THIEUTH O KIYEOK + 0xC5E6: 0xD1A4, //HANGUL SYLLABLE THIEUTH O NIEUN + 0xC5E7: 0xD1A8, //HANGUL SYLLABLE THIEUTH O RIEUL + 0xC5E8: 0xD1B0, //HANGUL SYLLABLE THIEUTH O MIEUM + 0xC5E9: 0xD1B1, //HANGUL SYLLABLE THIEUTH O PIEUP + 0xC5EA: 0xD1B3, //HANGUL SYLLABLE THIEUTH O SIOS + 0xC5EB: 0xD1B5, //HANGUL SYLLABLE THIEUTH O IEUNG + 0xC5EC: 0xD1BA, //HANGUL SYLLABLE THIEUTH O PHIEUPH + 0xC5ED: 0xD1BC, //HANGUL SYLLABLE THIEUTH WA + 0xC5EE: 0xD1C0, //HANGUL SYLLABLE THIEUTH WA NIEUN + 0xC5EF: 0xD1D8, //HANGUL SYLLABLE THIEUTH WAE + 0xC5F0: 0xD1F4, //HANGUL SYLLABLE THIEUTH OE + 0xC5F1: 0xD1F8, //HANGUL SYLLABLE THIEUTH OE NIEUN + 0xC5F2: 0xD207, //HANGUL SYLLABLE THIEUTH OE SIOS + 0xC5F3: 0xD209, //HANGUL SYLLABLE THIEUTH OE IEUNG + 0xC5F4: 0xD210, //HANGUL SYLLABLE THIEUTH YO + 0xC5F5: 0xD22C, //HANGUL SYLLABLE THIEUTH U + 0xC5F6: 0xD22D, //HANGUL SYLLABLE THIEUTH U KIYEOK + 0xC5F7: 0xD230, //HANGUL SYLLABLE THIEUTH U NIEUN + 0xC5F8: 0xD234, //HANGUL SYLLABLE THIEUTH U RIEUL + 0xC5F9: 0xD23C, //HANGUL SYLLABLE THIEUTH U MIEUM + 0xC5FA: 0xD23D, //HANGUL SYLLABLE THIEUTH U PIEUP + 0xC5FB: 0xD23F, //HANGUL SYLLABLE THIEUTH U SIOS + 0xC5FC: 0xD241, //HANGUL SYLLABLE THIEUTH U IEUNG + 0xC5FD: 0xD248, //HANGUL SYLLABLE THIEUTH WEO + 0xC5FE: 0xD25C, //HANGUL SYLLABLE THIEUTH WEO SSANGSIOS + 0xC641: 0xD78D, //HANGUL SYLLABLE HIEUH I NIEUNCIEUC + 0xC642: 0xD78E, //HANGUL SYLLABLE HIEUH I NIEUNHIEUH + 0xC643: 0xD78F, //HANGUL SYLLABLE HIEUH I TIKEUT + 0xC644: 0xD791, //HANGUL SYLLABLE HIEUH I RIEULKIYEOK + 0xC645: 0xD792, //HANGUL SYLLABLE HIEUH I RIEULMIEUM + 0xC646: 0xD793, //HANGUL SYLLABLE HIEUH I RIEULPIEUP + 0xC647: 0xD794, //HANGUL SYLLABLE HIEUH I RIEULSIOS + 0xC648: 0xD795, //HANGUL SYLLABLE HIEUH I RIEULTHIEUTH + 0xC649: 0xD796, //HANGUL SYLLABLE HIEUH I RIEULPHIEUPH + 0xC64A: 0xD797, //HANGUL SYLLABLE HIEUH I RIEULHIEUH + 0xC64B: 0xD79A, //HANGUL SYLLABLE HIEUH I PIEUPSIOS + 0xC64C: 0xD79C, //HANGUL SYLLABLE HIEUH I SSANGSIOS + 0xC64D: 0xD79E, //HANGUL SYLLABLE HIEUH I CIEUC + 0xC64E: 0xD79F, //HANGUL SYLLABLE HIEUH I CHIEUCH + 0xC64F: 0xD7A0, //HANGUL SYLLABLE HIEUH I KHIEUKH + 0xC650: 0xD7A1, //HANGUL SYLLABLE HIEUH I THIEUTH + 0xC651: 0xD7A2, //HANGUL SYLLABLE HIEUH I PHIEUPH + 0xC652: 0xD7A3, //HANGUL SYLLABLE HIEUH I HIEUH + 0xC6A1: 0xD264, //HANGUL SYLLABLE THIEUTH WE + 0xC6A2: 0xD280, //HANGUL SYLLABLE THIEUTH WI + 0xC6A3: 0xD281, //HANGUL SYLLABLE THIEUTH WI KIYEOK + 0xC6A4: 0xD284, //HANGUL SYLLABLE THIEUTH WI NIEUN + 0xC6A5: 0xD288, //HANGUL SYLLABLE THIEUTH WI RIEUL + 0xC6A6: 0xD290, //HANGUL SYLLABLE THIEUTH WI MIEUM + 0xC6A7: 0xD291, //HANGUL SYLLABLE THIEUTH WI PIEUP + 0xC6A8: 0xD295, //HANGUL SYLLABLE THIEUTH WI IEUNG + 0xC6A9: 0xD29C, //HANGUL SYLLABLE THIEUTH YU + 0xC6AA: 0xD2A0, //HANGUL SYLLABLE THIEUTH YU NIEUN + 0xC6AB: 0xD2A4, //HANGUL SYLLABLE THIEUTH YU RIEUL + 0xC6AC: 0xD2AC, //HANGUL SYLLABLE THIEUTH YU MIEUM + 0xC6AD: 0xD2B1, //HANGUL SYLLABLE THIEUTH YU IEUNG + 0xC6AE: 0xD2B8, //HANGUL SYLLABLE THIEUTH EU + 0xC6AF: 0xD2B9, //HANGUL SYLLABLE THIEUTH EU KIYEOK + 0xC6B0: 0xD2BC, //HANGUL SYLLABLE THIEUTH EU NIEUN + 0xC6B1: 0xD2BF, //HANGUL SYLLABLE THIEUTH EU TIKEUT + 0xC6B2: 0xD2C0, //HANGUL SYLLABLE THIEUTH EU RIEUL + 0xC6B3: 0xD2C2, //HANGUL SYLLABLE THIEUTH EU RIEULMIEUM + 0xC6B4: 0xD2C8, //HANGUL SYLLABLE THIEUTH EU MIEUM + 0xC6B5: 0xD2C9, //HANGUL SYLLABLE THIEUTH EU PIEUP + 0xC6B6: 0xD2CB, //HANGUL SYLLABLE THIEUTH EU SIOS + 0xC6B7: 0xD2D4, //HANGUL SYLLABLE THIEUTH YI + 0xC6B8: 0xD2D8, //HANGUL SYLLABLE THIEUTH YI NIEUN + 0xC6B9: 0xD2DC, //HANGUL SYLLABLE THIEUTH YI RIEUL + 0xC6BA: 0xD2E4, //HANGUL SYLLABLE THIEUTH YI MIEUM + 0xC6BB: 0xD2E5, //HANGUL SYLLABLE THIEUTH YI PIEUP + 0xC6BC: 0xD2F0, //HANGUL SYLLABLE THIEUTH I + 0xC6BD: 0xD2F1, //HANGUL SYLLABLE THIEUTH I KIYEOK + 0xC6BE: 0xD2F4, //HANGUL SYLLABLE THIEUTH I NIEUN + 0xC6BF: 0xD2F8, //HANGUL SYLLABLE THIEUTH I RIEUL + 0xC6C0: 0xD300, //HANGUL SYLLABLE THIEUTH I MIEUM + 0xC6C1: 0xD301, //HANGUL SYLLABLE THIEUTH I PIEUP + 0xC6C2: 0xD303, //HANGUL SYLLABLE THIEUTH I SIOS + 0xC6C3: 0xD305, //HANGUL SYLLABLE THIEUTH I IEUNG + 0xC6C4: 0xD30C, //HANGUL SYLLABLE PHIEUPH A + 0xC6C5: 0xD30D, //HANGUL SYLLABLE PHIEUPH A KIYEOK + 0xC6C6: 0xD30E, //HANGUL SYLLABLE PHIEUPH A SSANGKIYEOK + 0xC6C7: 0xD310, //HANGUL SYLLABLE PHIEUPH A NIEUN + 0xC6C8: 0xD314, //HANGUL SYLLABLE PHIEUPH A RIEUL + 0xC6C9: 0xD316, //HANGUL SYLLABLE PHIEUPH A RIEULMIEUM + 0xC6CA: 0xD31C, //HANGUL SYLLABLE PHIEUPH A MIEUM + 0xC6CB: 0xD31D, //HANGUL SYLLABLE PHIEUPH A PIEUP + 0xC6CC: 0xD31F, //HANGUL SYLLABLE PHIEUPH A SIOS + 0xC6CD: 0xD320, //HANGUL SYLLABLE PHIEUPH A SSANGSIOS + 0xC6CE: 0xD321, //HANGUL SYLLABLE PHIEUPH A IEUNG + 0xC6CF: 0xD325, //HANGUL SYLLABLE PHIEUPH A THIEUTH + 0xC6D0: 0xD328, //HANGUL SYLLABLE PHIEUPH AE + 0xC6D1: 0xD329, //HANGUL SYLLABLE PHIEUPH AE KIYEOK + 0xC6D2: 0xD32C, //HANGUL SYLLABLE PHIEUPH AE NIEUN + 0xC6D3: 0xD330, //HANGUL SYLLABLE PHIEUPH AE RIEUL + 0xC6D4: 0xD338, //HANGUL SYLLABLE PHIEUPH AE MIEUM + 0xC6D5: 0xD339, //HANGUL SYLLABLE PHIEUPH AE PIEUP + 0xC6D6: 0xD33B, //HANGUL SYLLABLE PHIEUPH AE SIOS + 0xC6D7: 0xD33C, //HANGUL SYLLABLE PHIEUPH AE SSANGSIOS + 0xC6D8: 0xD33D, //HANGUL SYLLABLE PHIEUPH AE IEUNG + 0xC6D9: 0xD344, //HANGUL SYLLABLE PHIEUPH YA + 0xC6DA: 0xD345, //HANGUL SYLLABLE PHIEUPH YA KIYEOK + 0xC6DB: 0xD37C, //HANGUL SYLLABLE PHIEUPH EO + 0xC6DC: 0xD37D, //HANGUL SYLLABLE PHIEUPH EO KIYEOK + 0xC6DD: 0xD380, //HANGUL SYLLABLE PHIEUPH EO NIEUN + 0xC6DE: 0xD384, //HANGUL SYLLABLE PHIEUPH EO RIEUL + 0xC6DF: 0xD38C, //HANGUL SYLLABLE PHIEUPH EO MIEUM + 0xC6E0: 0xD38D, //HANGUL SYLLABLE PHIEUPH EO PIEUP + 0xC6E1: 0xD38F, //HANGUL SYLLABLE PHIEUPH EO SIOS + 0xC6E2: 0xD390, //HANGUL SYLLABLE PHIEUPH EO SSANGSIOS + 0xC6E3: 0xD391, //HANGUL SYLLABLE PHIEUPH EO IEUNG + 0xC6E4: 0xD398, //HANGUL SYLLABLE PHIEUPH E + 0xC6E5: 0xD399, //HANGUL SYLLABLE PHIEUPH E KIYEOK + 0xC6E6: 0xD39C, //HANGUL SYLLABLE PHIEUPH E NIEUN + 0xC6E7: 0xD3A0, //HANGUL SYLLABLE PHIEUPH E RIEUL + 0xC6E8: 0xD3A8, //HANGUL SYLLABLE PHIEUPH E MIEUM + 0xC6E9: 0xD3A9, //HANGUL SYLLABLE PHIEUPH E PIEUP + 0xC6EA: 0xD3AB, //HANGUL SYLLABLE PHIEUPH E SIOS + 0xC6EB: 0xD3AD, //HANGUL SYLLABLE PHIEUPH E IEUNG + 0xC6EC: 0xD3B4, //HANGUL SYLLABLE PHIEUPH YEO + 0xC6ED: 0xD3B8, //HANGUL SYLLABLE PHIEUPH YEO NIEUN + 0xC6EE: 0xD3BC, //HANGUL SYLLABLE PHIEUPH YEO RIEUL + 0xC6EF: 0xD3C4, //HANGUL SYLLABLE PHIEUPH YEO MIEUM + 0xC6F0: 0xD3C5, //HANGUL SYLLABLE PHIEUPH YEO PIEUP + 0xC6F1: 0xD3C8, //HANGUL SYLLABLE PHIEUPH YEO SSANGSIOS + 0xC6F2: 0xD3C9, //HANGUL SYLLABLE PHIEUPH YEO IEUNG + 0xC6F3: 0xD3D0, //HANGUL SYLLABLE PHIEUPH YE + 0xC6F4: 0xD3D8, //HANGUL SYLLABLE PHIEUPH YE RIEUL + 0xC6F5: 0xD3E1, //HANGUL SYLLABLE PHIEUPH YE PIEUP + 0xC6F6: 0xD3E3, //HANGUL SYLLABLE PHIEUPH YE SIOS + 0xC6F7: 0xD3EC, //HANGUL SYLLABLE PHIEUPH O + 0xC6F8: 0xD3ED, //HANGUL SYLLABLE PHIEUPH O KIYEOK + 0xC6F9: 0xD3F0, //HANGUL SYLLABLE PHIEUPH O NIEUN + 0xC6FA: 0xD3F4, //HANGUL SYLLABLE PHIEUPH O RIEUL + 0xC6FB: 0xD3FC, //HANGUL SYLLABLE PHIEUPH O MIEUM + 0xC6FC: 0xD3FD, //HANGUL SYLLABLE PHIEUPH O PIEUP + 0xC6FD: 0xD3FF, //HANGUL SYLLABLE PHIEUPH O SIOS + 0xC6FE: 0xD401, //HANGUL SYLLABLE PHIEUPH O IEUNG + 0xC7A1: 0xD408, //HANGUL SYLLABLE PHIEUPH WA + 0xC7A2: 0xD41D, //HANGUL SYLLABLE PHIEUPH WA IEUNG + 0xC7A3: 0xD440, //HANGUL SYLLABLE PHIEUPH OE + 0xC7A4: 0xD444, //HANGUL SYLLABLE PHIEUPH OE NIEUN + 0xC7A5: 0xD45C, //HANGUL SYLLABLE PHIEUPH YO + 0xC7A6: 0xD460, //HANGUL SYLLABLE PHIEUPH YO NIEUN + 0xC7A7: 0xD464, //HANGUL SYLLABLE PHIEUPH YO RIEUL + 0xC7A8: 0xD46D, //HANGUL SYLLABLE PHIEUPH YO PIEUP + 0xC7A9: 0xD46F, //HANGUL SYLLABLE PHIEUPH YO SIOS + 0xC7AA: 0xD478, //HANGUL SYLLABLE PHIEUPH U + 0xC7AB: 0xD479, //HANGUL SYLLABLE PHIEUPH U KIYEOK + 0xC7AC: 0xD47C, //HANGUL SYLLABLE PHIEUPH U NIEUN + 0xC7AD: 0xD47F, //HANGUL SYLLABLE PHIEUPH U TIKEUT + 0xC7AE: 0xD480, //HANGUL SYLLABLE PHIEUPH U RIEUL + 0xC7AF: 0xD482, //HANGUL SYLLABLE PHIEUPH U RIEULMIEUM + 0xC7B0: 0xD488, //HANGUL SYLLABLE PHIEUPH U MIEUM + 0xC7B1: 0xD489, //HANGUL SYLLABLE PHIEUPH U PIEUP + 0xC7B2: 0xD48B, //HANGUL SYLLABLE PHIEUPH U SIOS + 0xC7B3: 0xD48D, //HANGUL SYLLABLE PHIEUPH U IEUNG + 0xC7B4: 0xD494, //HANGUL SYLLABLE PHIEUPH WEO + 0xC7B5: 0xD4A9, //HANGUL SYLLABLE PHIEUPH WEO IEUNG + 0xC7B6: 0xD4CC, //HANGUL SYLLABLE PHIEUPH WI + 0xC7B7: 0xD4D0, //HANGUL SYLLABLE PHIEUPH WI NIEUN + 0xC7B8: 0xD4D4, //HANGUL SYLLABLE PHIEUPH WI RIEUL + 0xC7B9: 0xD4DC, //HANGUL SYLLABLE PHIEUPH WI MIEUM + 0xC7BA: 0xD4DF, //HANGUL SYLLABLE PHIEUPH WI SIOS + 0xC7BB: 0xD4E8, //HANGUL SYLLABLE PHIEUPH YU + 0xC7BC: 0xD4EC, //HANGUL SYLLABLE PHIEUPH YU NIEUN + 0xC7BD: 0xD4F0, //HANGUL SYLLABLE PHIEUPH YU RIEUL + 0xC7BE: 0xD4F8, //HANGUL SYLLABLE PHIEUPH YU MIEUM + 0xC7BF: 0xD4FB, //HANGUL SYLLABLE PHIEUPH YU SIOS + 0xC7C0: 0xD4FD, //HANGUL SYLLABLE PHIEUPH YU IEUNG + 0xC7C1: 0xD504, //HANGUL SYLLABLE PHIEUPH EU + 0xC7C2: 0xD508, //HANGUL SYLLABLE PHIEUPH EU NIEUN + 0xC7C3: 0xD50C, //HANGUL SYLLABLE PHIEUPH EU RIEUL + 0xC7C4: 0xD514, //HANGUL SYLLABLE PHIEUPH EU MIEUM + 0xC7C5: 0xD515, //HANGUL SYLLABLE PHIEUPH EU PIEUP + 0xC7C6: 0xD517, //HANGUL SYLLABLE PHIEUPH EU SIOS + 0xC7C7: 0xD53C, //HANGUL SYLLABLE PHIEUPH I + 0xC7C8: 0xD53D, //HANGUL SYLLABLE PHIEUPH I KIYEOK + 0xC7C9: 0xD540, //HANGUL SYLLABLE PHIEUPH I NIEUN + 0xC7CA: 0xD544, //HANGUL SYLLABLE PHIEUPH I RIEUL + 0xC7CB: 0xD54C, //HANGUL SYLLABLE PHIEUPH I MIEUM + 0xC7CC: 0xD54D, //HANGUL SYLLABLE PHIEUPH I PIEUP + 0xC7CD: 0xD54F, //HANGUL SYLLABLE PHIEUPH I SIOS + 0xC7CE: 0xD551, //HANGUL SYLLABLE PHIEUPH I IEUNG + 0xC7CF: 0xD558, //HANGUL SYLLABLE HIEUH A + 0xC7D0: 0xD559, //HANGUL SYLLABLE HIEUH A KIYEOK + 0xC7D1: 0xD55C, //HANGUL SYLLABLE HIEUH A NIEUN + 0xC7D2: 0xD560, //HANGUL SYLLABLE HIEUH A RIEUL + 0xC7D3: 0xD565, //HANGUL SYLLABLE HIEUH A RIEULTHIEUTH + 0xC7D4: 0xD568, //HANGUL SYLLABLE HIEUH A MIEUM + 0xC7D5: 0xD569, //HANGUL SYLLABLE HIEUH A PIEUP + 0xC7D6: 0xD56B, //HANGUL SYLLABLE HIEUH A SIOS + 0xC7D7: 0xD56D, //HANGUL SYLLABLE HIEUH A IEUNG + 0xC7D8: 0xD574, //HANGUL SYLLABLE HIEUH AE + 0xC7D9: 0xD575, //HANGUL SYLLABLE HIEUH AE KIYEOK + 0xC7DA: 0xD578, //HANGUL SYLLABLE HIEUH AE NIEUN + 0xC7DB: 0xD57C, //HANGUL SYLLABLE HIEUH AE RIEUL + 0xC7DC: 0xD584, //HANGUL SYLLABLE HIEUH AE MIEUM + 0xC7DD: 0xD585, //HANGUL SYLLABLE HIEUH AE PIEUP + 0xC7DE: 0xD587, //HANGUL SYLLABLE HIEUH AE SIOS + 0xC7DF: 0xD588, //HANGUL SYLLABLE HIEUH AE SSANGSIOS + 0xC7E0: 0xD589, //HANGUL SYLLABLE HIEUH AE IEUNG + 0xC7E1: 0xD590, //HANGUL SYLLABLE HIEUH YA + 0xC7E2: 0xD5A5, //HANGUL SYLLABLE HIEUH YA IEUNG + 0xC7E3: 0xD5C8, //HANGUL SYLLABLE HIEUH EO + 0xC7E4: 0xD5C9, //HANGUL SYLLABLE HIEUH EO KIYEOK + 0xC7E5: 0xD5CC, //HANGUL SYLLABLE HIEUH EO NIEUN + 0xC7E6: 0xD5D0, //HANGUL SYLLABLE HIEUH EO RIEUL + 0xC7E7: 0xD5D2, //HANGUL SYLLABLE HIEUH EO RIEULMIEUM + 0xC7E8: 0xD5D8, //HANGUL SYLLABLE HIEUH EO MIEUM + 0xC7E9: 0xD5D9, //HANGUL SYLLABLE HIEUH EO PIEUP + 0xC7EA: 0xD5DB, //HANGUL SYLLABLE HIEUH EO SIOS + 0xC7EB: 0xD5DD, //HANGUL SYLLABLE HIEUH EO IEUNG + 0xC7EC: 0xD5E4, //HANGUL SYLLABLE HIEUH E + 0xC7ED: 0xD5E5, //HANGUL SYLLABLE HIEUH E KIYEOK + 0xC7EE: 0xD5E8, //HANGUL SYLLABLE HIEUH E NIEUN + 0xC7EF: 0xD5EC, //HANGUL SYLLABLE HIEUH E RIEUL + 0xC7F0: 0xD5F4, //HANGUL SYLLABLE HIEUH E MIEUM + 0xC7F1: 0xD5F5, //HANGUL SYLLABLE HIEUH E PIEUP + 0xC7F2: 0xD5F7, //HANGUL SYLLABLE HIEUH E SIOS + 0xC7F3: 0xD5F9, //HANGUL SYLLABLE HIEUH E IEUNG + 0xC7F4: 0xD600, //HANGUL SYLLABLE HIEUH YEO + 0xC7F5: 0xD601, //HANGUL SYLLABLE HIEUH YEO KIYEOK + 0xC7F6: 0xD604, //HANGUL SYLLABLE HIEUH YEO NIEUN + 0xC7F7: 0xD608, //HANGUL SYLLABLE HIEUH YEO RIEUL + 0xC7F8: 0xD610, //HANGUL SYLLABLE HIEUH YEO MIEUM + 0xC7F9: 0xD611, //HANGUL SYLLABLE HIEUH YEO PIEUP + 0xC7FA: 0xD613, //HANGUL SYLLABLE HIEUH YEO SIOS + 0xC7FB: 0xD614, //HANGUL SYLLABLE HIEUH YEO SSANGSIOS + 0xC7FC: 0xD615, //HANGUL SYLLABLE HIEUH YEO IEUNG + 0xC7FD: 0xD61C, //HANGUL SYLLABLE HIEUH YE + 0xC7FE: 0xD620, //HANGUL SYLLABLE HIEUH YE NIEUN + 0xC8A1: 0xD624, //HANGUL SYLLABLE HIEUH YE RIEUL + 0xC8A2: 0xD62D, //HANGUL SYLLABLE HIEUH YE PIEUP + 0xC8A3: 0xD638, //HANGUL SYLLABLE HIEUH O + 0xC8A4: 0xD639, //HANGUL SYLLABLE HIEUH O KIYEOK + 0xC8A5: 0xD63C, //HANGUL SYLLABLE HIEUH O NIEUN + 0xC8A6: 0xD640, //HANGUL SYLLABLE HIEUH O RIEUL + 0xC8A7: 0xD645, //HANGUL SYLLABLE HIEUH O RIEULTHIEUTH + 0xC8A8: 0xD648, //HANGUL SYLLABLE HIEUH O MIEUM + 0xC8A9: 0xD649, //HANGUL SYLLABLE HIEUH O PIEUP + 0xC8AA: 0xD64B, //HANGUL SYLLABLE HIEUH O SIOS + 0xC8AB: 0xD64D, //HANGUL SYLLABLE HIEUH O IEUNG + 0xC8AC: 0xD651, //HANGUL SYLLABLE HIEUH O THIEUTH + 0xC8AD: 0xD654, //HANGUL SYLLABLE HIEUH WA + 0xC8AE: 0xD655, //HANGUL SYLLABLE HIEUH WA KIYEOK + 0xC8AF: 0xD658, //HANGUL SYLLABLE HIEUH WA NIEUN + 0xC8B0: 0xD65C, //HANGUL SYLLABLE HIEUH WA RIEUL + 0xC8B1: 0xD667, //HANGUL SYLLABLE HIEUH WA SIOS + 0xC8B2: 0xD669, //HANGUL SYLLABLE HIEUH WA IEUNG + 0xC8B3: 0xD670, //HANGUL SYLLABLE HIEUH WAE + 0xC8B4: 0xD671, //HANGUL SYLLABLE HIEUH WAE KIYEOK + 0xC8B5: 0xD674, //HANGUL SYLLABLE HIEUH WAE NIEUN + 0xC8B6: 0xD683, //HANGUL SYLLABLE HIEUH WAE SIOS + 0xC8B7: 0xD685, //HANGUL SYLLABLE HIEUH WAE IEUNG + 0xC8B8: 0xD68C, //HANGUL SYLLABLE HIEUH OE + 0xC8B9: 0xD68D, //HANGUL SYLLABLE HIEUH OE KIYEOK + 0xC8BA: 0xD690, //HANGUL SYLLABLE HIEUH OE NIEUN + 0xC8BB: 0xD694, //HANGUL SYLLABLE HIEUH OE RIEUL + 0xC8BC: 0xD69D, //HANGUL SYLLABLE HIEUH OE PIEUP + 0xC8BD: 0xD69F, //HANGUL SYLLABLE HIEUH OE SIOS + 0xC8BE: 0xD6A1, //HANGUL SYLLABLE HIEUH OE IEUNG + 0xC8BF: 0xD6A8, //HANGUL SYLLABLE HIEUH YO + 0xC8C0: 0xD6AC, //HANGUL SYLLABLE HIEUH YO NIEUN + 0xC8C1: 0xD6B0, //HANGUL SYLLABLE HIEUH YO RIEUL + 0xC8C2: 0xD6B9, //HANGUL SYLLABLE HIEUH YO PIEUP + 0xC8C3: 0xD6BB, //HANGUL SYLLABLE HIEUH YO SIOS + 0xC8C4: 0xD6C4, //HANGUL SYLLABLE HIEUH U + 0xC8C5: 0xD6C5, //HANGUL SYLLABLE HIEUH U KIYEOK + 0xC8C6: 0xD6C8, //HANGUL SYLLABLE HIEUH U NIEUN + 0xC8C7: 0xD6CC, //HANGUL SYLLABLE HIEUH U RIEUL + 0xC8C8: 0xD6D1, //HANGUL SYLLABLE HIEUH U RIEULTHIEUTH + 0xC8C9: 0xD6D4, //HANGUL SYLLABLE HIEUH U MIEUM + 0xC8CA: 0xD6D7, //HANGUL SYLLABLE HIEUH U SIOS + 0xC8CB: 0xD6D9, //HANGUL SYLLABLE HIEUH U IEUNG + 0xC8CC: 0xD6E0, //HANGUL SYLLABLE HIEUH WEO + 0xC8CD: 0xD6E4, //HANGUL SYLLABLE HIEUH WEO NIEUN + 0xC8CE: 0xD6E8, //HANGUL SYLLABLE HIEUH WEO RIEUL + 0xC8CF: 0xD6F0, //HANGUL SYLLABLE HIEUH WEO MIEUM + 0xC8D0: 0xD6F5, //HANGUL SYLLABLE HIEUH WEO IEUNG + 0xC8D1: 0xD6FC, //HANGUL SYLLABLE HIEUH WE + 0xC8D2: 0xD6FD, //HANGUL SYLLABLE HIEUH WE KIYEOK + 0xC8D3: 0xD700, //HANGUL SYLLABLE HIEUH WE NIEUN + 0xC8D4: 0xD704, //HANGUL SYLLABLE HIEUH WE RIEUL + 0xC8D5: 0xD711, //HANGUL SYLLABLE HIEUH WE IEUNG + 0xC8D6: 0xD718, //HANGUL SYLLABLE HIEUH WI + 0xC8D7: 0xD719, //HANGUL SYLLABLE HIEUH WI KIYEOK + 0xC8D8: 0xD71C, //HANGUL SYLLABLE HIEUH WI NIEUN + 0xC8D9: 0xD720, //HANGUL SYLLABLE HIEUH WI RIEUL + 0xC8DA: 0xD728, //HANGUL SYLLABLE HIEUH WI MIEUM + 0xC8DB: 0xD729, //HANGUL SYLLABLE HIEUH WI PIEUP + 0xC8DC: 0xD72B, //HANGUL SYLLABLE HIEUH WI SIOS + 0xC8DD: 0xD72D, //HANGUL SYLLABLE HIEUH WI IEUNG + 0xC8DE: 0xD734, //HANGUL SYLLABLE HIEUH YU + 0xC8DF: 0xD735, //HANGUL SYLLABLE HIEUH YU KIYEOK + 0xC8E0: 0xD738, //HANGUL SYLLABLE HIEUH YU NIEUN + 0xC8E1: 0xD73C, //HANGUL SYLLABLE HIEUH YU RIEUL + 0xC8E2: 0xD744, //HANGUL SYLLABLE HIEUH YU MIEUM + 0xC8E3: 0xD747, //HANGUL SYLLABLE HIEUH YU SIOS + 0xC8E4: 0xD749, //HANGUL SYLLABLE HIEUH YU IEUNG + 0xC8E5: 0xD750, //HANGUL SYLLABLE HIEUH EU + 0xC8E6: 0xD751, //HANGUL SYLLABLE HIEUH EU KIYEOK + 0xC8E7: 0xD754, //HANGUL SYLLABLE HIEUH EU NIEUN + 0xC8E8: 0xD756, //HANGUL SYLLABLE HIEUH EU NIEUNHIEUH + 0xC8E9: 0xD757, //HANGUL SYLLABLE HIEUH EU TIKEUT + 0xC8EA: 0xD758, //HANGUL SYLLABLE HIEUH EU RIEUL + 0xC8EB: 0xD759, //HANGUL SYLLABLE HIEUH EU RIEULKIYEOK + 0xC8EC: 0xD760, //HANGUL SYLLABLE HIEUH EU MIEUM + 0xC8ED: 0xD761, //HANGUL SYLLABLE HIEUH EU PIEUP + 0xC8EE: 0xD763, //HANGUL SYLLABLE HIEUH EU SIOS + 0xC8EF: 0xD765, //HANGUL SYLLABLE HIEUH EU IEUNG + 0xC8F0: 0xD769, //HANGUL SYLLABLE HIEUH EU THIEUTH + 0xC8F1: 0xD76C, //HANGUL SYLLABLE HIEUH YI + 0xC8F2: 0xD770, //HANGUL SYLLABLE HIEUH YI NIEUN + 0xC8F3: 0xD774, //HANGUL SYLLABLE HIEUH YI RIEUL + 0xC8F4: 0xD77C, //HANGUL SYLLABLE HIEUH YI MIEUM + 0xC8F5: 0xD77D, //HANGUL SYLLABLE HIEUH YI PIEUP + 0xC8F6: 0xD781, //HANGUL SYLLABLE HIEUH YI IEUNG + 0xC8F7: 0xD788, //HANGUL SYLLABLE HIEUH I + 0xC8F8: 0xD789, //HANGUL SYLLABLE HIEUH I KIYEOK + 0xC8F9: 0xD78C, //HANGUL SYLLABLE HIEUH I NIEUN + 0xC8FA: 0xD790, //HANGUL SYLLABLE HIEUH I RIEUL + 0xC8FB: 0xD798, //HANGUL SYLLABLE HIEUH I MIEUM + 0xC8FC: 0xD799, //HANGUL SYLLABLE HIEUH I PIEUP + 0xC8FD: 0xD79B, //HANGUL SYLLABLE HIEUH I SIOS + 0xC8FE: 0xD79D, //HANGUL SYLLABLE HIEUH I IEUNG + 0xCAA1: 0x4F3D, //CJK UNIFIED IDEOGRAPH + 0xCAA2: 0x4F73, //CJK UNIFIED IDEOGRAPH + 0xCAA3: 0x5047, //CJK UNIFIED IDEOGRAPH + 0xCAA4: 0x50F9, //CJK UNIFIED IDEOGRAPH + 0xCAA5: 0x52A0, //CJK UNIFIED IDEOGRAPH + 0xCAA6: 0x53EF, //CJK UNIFIED IDEOGRAPH + 0xCAA7: 0x5475, //CJK UNIFIED IDEOGRAPH + 0xCAA8: 0x54E5, //CJK UNIFIED IDEOGRAPH + 0xCAA9: 0x5609, //CJK UNIFIED IDEOGRAPH + 0xCAAA: 0x5AC1, //CJK UNIFIED IDEOGRAPH + 0xCAAB: 0x5BB6, //CJK UNIFIED IDEOGRAPH + 0xCAAC: 0x6687, //CJK UNIFIED IDEOGRAPH + 0xCAAD: 0x67B6, //CJK UNIFIED IDEOGRAPH + 0xCAAE: 0x67B7, //CJK UNIFIED IDEOGRAPH + 0xCAAF: 0x67EF, //CJK UNIFIED IDEOGRAPH + 0xCAB0: 0x6B4C, //CJK UNIFIED IDEOGRAPH + 0xCAB1: 0x73C2, //CJK UNIFIED IDEOGRAPH + 0xCAB2: 0x75C2, //CJK UNIFIED IDEOGRAPH + 0xCAB3: 0x7A3C, //CJK UNIFIED IDEOGRAPH + 0xCAB4: 0x82DB, //CJK UNIFIED IDEOGRAPH + 0xCAB5: 0x8304, //CJK UNIFIED IDEOGRAPH + 0xCAB6: 0x8857, //CJK UNIFIED IDEOGRAPH + 0xCAB7: 0x8888, //CJK UNIFIED IDEOGRAPH + 0xCAB8: 0x8A36, //CJK UNIFIED IDEOGRAPH + 0xCAB9: 0x8CC8, //CJK UNIFIED IDEOGRAPH + 0xCABA: 0x8DCF, //CJK UNIFIED IDEOGRAPH + 0xCABB: 0x8EFB, //CJK UNIFIED IDEOGRAPH + 0xCABC: 0x8FE6, //CJK UNIFIED IDEOGRAPH + 0xCABD: 0x99D5, //CJK UNIFIED IDEOGRAPH + 0xCABE: 0x523B, //CJK UNIFIED IDEOGRAPH + 0xCABF: 0x5374, //CJK UNIFIED IDEOGRAPH + 0xCAC0: 0x5404, //CJK UNIFIED IDEOGRAPH + 0xCAC1: 0x606A, //CJK UNIFIED IDEOGRAPH + 0xCAC2: 0x6164, //CJK UNIFIED IDEOGRAPH + 0xCAC3: 0x6BBC, //CJK UNIFIED IDEOGRAPH + 0xCAC4: 0x73CF, //CJK UNIFIED IDEOGRAPH + 0xCAC5: 0x811A, //CJK UNIFIED IDEOGRAPH + 0xCAC6: 0x89BA, //CJK UNIFIED IDEOGRAPH + 0xCAC7: 0x89D2, //CJK UNIFIED IDEOGRAPH + 0xCAC8: 0x95A3, //CJK UNIFIED IDEOGRAPH + 0xCAC9: 0x4F83, //CJK UNIFIED IDEOGRAPH + 0xCACA: 0x520A, //CJK UNIFIED IDEOGRAPH + 0xCACB: 0x58BE, //CJK UNIFIED IDEOGRAPH + 0xCACC: 0x5978, //CJK UNIFIED IDEOGRAPH + 0xCACD: 0x59E6, //CJK UNIFIED IDEOGRAPH + 0xCACE: 0x5E72, //CJK UNIFIED IDEOGRAPH + 0xCACF: 0x5E79, //CJK UNIFIED IDEOGRAPH + 0xCAD0: 0x61C7, //CJK UNIFIED IDEOGRAPH + 0xCAD1: 0x63C0, //CJK UNIFIED IDEOGRAPH + 0xCAD2: 0x6746, //CJK UNIFIED IDEOGRAPH + 0xCAD3: 0x67EC, //CJK UNIFIED IDEOGRAPH + 0xCAD4: 0x687F, //CJK UNIFIED IDEOGRAPH + 0xCAD5: 0x6F97, //CJK UNIFIED IDEOGRAPH + 0xCAD6: 0x764E, //CJK UNIFIED IDEOGRAPH + 0xCAD7: 0x770B, //CJK UNIFIED IDEOGRAPH + 0xCAD8: 0x78F5, //CJK UNIFIED IDEOGRAPH + 0xCAD9: 0x7A08, //CJK UNIFIED IDEOGRAPH + 0xCADA: 0x7AFF, //CJK UNIFIED IDEOGRAPH + 0xCADB: 0x7C21, //CJK UNIFIED IDEOGRAPH + 0xCADC: 0x809D, //CJK UNIFIED IDEOGRAPH + 0xCADD: 0x826E, //CJK UNIFIED IDEOGRAPH + 0xCADE: 0x8271, //CJK UNIFIED IDEOGRAPH + 0xCADF: 0x8AEB, //CJK UNIFIED IDEOGRAPH + 0xCAE0: 0x9593, //CJK UNIFIED IDEOGRAPH + 0xCAE1: 0x4E6B, //CJK UNIFIED IDEOGRAPH + 0xCAE2: 0x559D, //CJK UNIFIED IDEOGRAPH + 0xCAE3: 0x66F7, //CJK UNIFIED IDEOGRAPH + 0xCAE4: 0x6E34, //CJK UNIFIED IDEOGRAPH + 0xCAE5: 0x78A3, //CJK UNIFIED IDEOGRAPH + 0xCAE6: 0x7AED, //CJK UNIFIED IDEOGRAPH + 0xCAE7: 0x845B, //CJK UNIFIED IDEOGRAPH + 0xCAE8: 0x8910, //CJK UNIFIED IDEOGRAPH + 0xCAE9: 0x874E, //CJK UNIFIED IDEOGRAPH + 0xCAEA: 0x97A8, //CJK UNIFIED IDEOGRAPH + 0xCAEB: 0x52D8, //CJK UNIFIED IDEOGRAPH + 0xCAEC: 0x574E, //CJK UNIFIED IDEOGRAPH + 0xCAED: 0x582A, //CJK UNIFIED IDEOGRAPH + 0xCAEE: 0x5D4C, //CJK UNIFIED IDEOGRAPH + 0xCAEF: 0x611F, //CJK UNIFIED IDEOGRAPH + 0xCAF0: 0x61BE, //CJK UNIFIED IDEOGRAPH + 0xCAF1: 0x6221, //CJK UNIFIED IDEOGRAPH + 0xCAF2: 0x6562, //CJK UNIFIED IDEOGRAPH + 0xCAF3: 0x67D1, //CJK UNIFIED IDEOGRAPH + 0xCAF4: 0x6A44, //CJK UNIFIED IDEOGRAPH + 0xCAF5: 0x6E1B, //CJK UNIFIED IDEOGRAPH + 0xCAF6: 0x7518, //CJK UNIFIED IDEOGRAPH + 0xCAF7: 0x75B3, //CJK UNIFIED IDEOGRAPH + 0xCAF8: 0x76E3, //CJK UNIFIED IDEOGRAPH + 0xCAF9: 0x77B0, //CJK UNIFIED IDEOGRAPH + 0xCAFA: 0x7D3A, //CJK UNIFIED IDEOGRAPH + 0xCAFB: 0x90AF, //CJK UNIFIED IDEOGRAPH + 0xCAFC: 0x9451, //CJK UNIFIED IDEOGRAPH + 0xCAFD: 0x9452, //CJK UNIFIED IDEOGRAPH + 0xCAFE: 0x9F95, //CJK UNIFIED IDEOGRAPH + 0xCBA1: 0x5323, //CJK UNIFIED IDEOGRAPH + 0xCBA2: 0x5CAC, //CJK UNIFIED IDEOGRAPH + 0xCBA3: 0x7532, //CJK UNIFIED IDEOGRAPH + 0xCBA4: 0x80DB, //CJK UNIFIED IDEOGRAPH + 0xCBA5: 0x9240, //CJK UNIFIED IDEOGRAPH + 0xCBA6: 0x9598, //CJK UNIFIED IDEOGRAPH + 0xCBA7: 0x525B, //CJK UNIFIED IDEOGRAPH + 0xCBA8: 0x5808, //CJK UNIFIED IDEOGRAPH + 0xCBA9: 0x59DC, //CJK UNIFIED IDEOGRAPH + 0xCBAA: 0x5CA1, //CJK UNIFIED IDEOGRAPH + 0xCBAB: 0x5D17, //CJK UNIFIED IDEOGRAPH + 0xCBAC: 0x5EB7, //CJK UNIFIED IDEOGRAPH + 0xCBAD: 0x5F3A, //CJK UNIFIED IDEOGRAPH + 0xCBAE: 0x5F4A, //CJK UNIFIED IDEOGRAPH + 0xCBAF: 0x6177, //CJK UNIFIED IDEOGRAPH + 0xCBB0: 0x6C5F, //CJK UNIFIED IDEOGRAPH + 0xCBB1: 0x757A, //CJK UNIFIED IDEOGRAPH + 0xCBB2: 0x7586, //CJK UNIFIED IDEOGRAPH + 0xCBB3: 0x7CE0, //CJK UNIFIED IDEOGRAPH + 0xCBB4: 0x7D73, //CJK UNIFIED IDEOGRAPH + 0xCBB5: 0x7DB1, //CJK UNIFIED IDEOGRAPH + 0xCBB6: 0x7F8C, //CJK UNIFIED IDEOGRAPH + 0xCBB7: 0x8154, //CJK UNIFIED IDEOGRAPH + 0xCBB8: 0x8221, //CJK UNIFIED IDEOGRAPH + 0xCBB9: 0x8591, //CJK UNIFIED IDEOGRAPH + 0xCBBA: 0x8941, //CJK UNIFIED IDEOGRAPH + 0xCBBB: 0x8B1B, //CJK UNIFIED IDEOGRAPH + 0xCBBC: 0x92FC, //CJK UNIFIED IDEOGRAPH + 0xCBBD: 0x964D, //CJK UNIFIED IDEOGRAPH + 0xCBBE: 0x9C47, //CJK UNIFIED IDEOGRAPH + 0xCBBF: 0x4ECB, //CJK UNIFIED IDEOGRAPH + 0xCBC0: 0x4EF7, //CJK UNIFIED IDEOGRAPH + 0xCBC1: 0x500B, //CJK UNIFIED IDEOGRAPH + 0xCBC2: 0x51F1, //CJK UNIFIED IDEOGRAPH + 0xCBC3: 0x584F, //CJK UNIFIED IDEOGRAPH + 0xCBC4: 0x6137, //CJK UNIFIED IDEOGRAPH + 0xCBC5: 0x613E, //CJK UNIFIED IDEOGRAPH + 0xCBC6: 0x6168, //CJK UNIFIED IDEOGRAPH + 0xCBC7: 0x6539, //CJK UNIFIED IDEOGRAPH + 0xCBC8: 0x69EA, //CJK UNIFIED IDEOGRAPH + 0xCBC9: 0x6F11, //CJK UNIFIED IDEOGRAPH + 0xCBCA: 0x75A5, //CJK UNIFIED IDEOGRAPH + 0xCBCB: 0x7686, //CJK UNIFIED IDEOGRAPH + 0xCBCC: 0x76D6, //CJK UNIFIED IDEOGRAPH + 0xCBCD: 0x7B87, //CJK UNIFIED IDEOGRAPH + 0xCBCE: 0x82A5, //CJK UNIFIED IDEOGRAPH + 0xCBCF: 0x84CB, //CJK UNIFIED IDEOGRAPH + 0xCBD0: 0xF900, //CJK COMPATIBILITY IDEOGRAPH + 0xCBD1: 0x93A7, //CJK UNIFIED IDEOGRAPH + 0xCBD2: 0x958B, //CJK UNIFIED IDEOGRAPH + 0xCBD3: 0x5580, //CJK UNIFIED IDEOGRAPH + 0xCBD4: 0x5BA2, //CJK UNIFIED IDEOGRAPH + 0xCBD5: 0x5751, //CJK UNIFIED IDEOGRAPH + 0xCBD6: 0xF901, //CJK COMPATIBILITY IDEOGRAPH + 0xCBD7: 0x7CB3, //CJK UNIFIED IDEOGRAPH + 0xCBD8: 0x7FB9, //CJK UNIFIED IDEOGRAPH + 0xCBD9: 0x91B5, //CJK UNIFIED IDEOGRAPH + 0xCBDA: 0x5028, //CJK UNIFIED IDEOGRAPH + 0xCBDB: 0x53BB, //CJK UNIFIED IDEOGRAPH + 0xCBDC: 0x5C45, //CJK UNIFIED IDEOGRAPH + 0xCBDD: 0x5DE8, //CJK UNIFIED IDEOGRAPH + 0xCBDE: 0x62D2, //CJK UNIFIED IDEOGRAPH + 0xCBDF: 0x636E, //CJK UNIFIED IDEOGRAPH + 0xCBE0: 0x64DA, //CJK UNIFIED IDEOGRAPH + 0xCBE1: 0x64E7, //CJK UNIFIED IDEOGRAPH + 0xCBE2: 0x6E20, //CJK UNIFIED IDEOGRAPH + 0xCBE3: 0x70AC, //CJK UNIFIED IDEOGRAPH + 0xCBE4: 0x795B, //CJK UNIFIED IDEOGRAPH + 0xCBE5: 0x8DDD, //CJK UNIFIED IDEOGRAPH + 0xCBE6: 0x8E1E, //CJK UNIFIED IDEOGRAPH + 0xCBE7: 0xF902, //CJK COMPATIBILITY IDEOGRAPH + 0xCBE8: 0x907D, //CJK UNIFIED IDEOGRAPH + 0xCBE9: 0x9245, //CJK UNIFIED IDEOGRAPH + 0xCBEA: 0x92F8, //CJK UNIFIED IDEOGRAPH + 0xCBEB: 0x4E7E, //CJK UNIFIED IDEOGRAPH + 0xCBEC: 0x4EF6, //CJK UNIFIED IDEOGRAPH + 0xCBED: 0x5065, //CJK UNIFIED IDEOGRAPH + 0xCBEE: 0x5DFE, //CJK UNIFIED IDEOGRAPH + 0xCBEF: 0x5EFA, //CJK UNIFIED IDEOGRAPH + 0xCBF0: 0x6106, //CJK UNIFIED IDEOGRAPH + 0xCBF1: 0x6957, //CJK UNIFIED IDEOGRAPH + 0xCBF2: 0x8171, //CJK UNIFIED IDEOGRAPH + 0xCBF3: 0x8654, //CJK UNIFIED IDEOGRAPH + 0xCBF4: 0x8E47, //CJK UNIFIED IDEOGRAPH + 0xCBF5: 0x9375, //CJK UNIFIED IDEOGRAPH + 0xCBF6: 0x9A2B, //CJK UNIFIED IDEOGRAPH + 0xCBF7: 0x4E5E, //CJK UNIFIED IDEOGRAPH + 0xCBF8: 0x5091, //CJK UNIFIED IDEOGRAPH + 0xCBF9: 0x6770, //CJK UNIFIED IDEOGRAPH + 0xCBFA: 0x6840, //CJK UNIFIED IDEOGRAPH + 0xCBFB: 0x5109, //CJK UNIFIED IDEOGRAPH + 0xCBFC: 0x528D, //CJK UNIFIED IDEOGRAPH + 0xCBFD: 0x5292, //CJK UNIFIED IDEOGRAPH + 0xCBFE: 0x6AA2, //CJK UNIFIED IDEOGRAPH + 0xCCA1: 0x77BC, //CJK UNIFIED IDEOGRAPH + 0xCCA2: 0x9210, //CJK UNIFIED IDEOGRAPH + 0xCCA3: 0x9ED4, //CJK UNIFIED IDEOGRAPH + 0xCCA4: 0x52AB, //CJK UNIFIED IDEOGRAPH + 0xCCA5: 0x602F, //CJK UNIFIED IDEOGRAPH + 0xCCA6: 0x8FF2, //CJK UNIFIED IDEOGRAPH + 0xCCA7: 0x5048, //CJK UNIFIED IDEOGRAPH + 0xCCA8: 0x61A9, //CJK UNIFIED IDEOGRAPH + 0xCCA9: 0x63ED, //CJK UNIFIED IDEOGRAPH + 0xCCAA: 0x64CA, //CJK UNIFIED IDEOGRAPH + 0xCCAB: 0x683C, //CJK UNIFIED IDEOGRAPH + 0xCCAC: 0x6A84, //CJK UNIFIED IDEOGRAPH + 0xCCAD: 0x6FC0, //CJK UNIFIED IDEOGRAPH + 0xCCAE: 0x8188, //CJK UNIFIED IDEOGRAPH + 0xCCAF: 0x89A1, //CJK UNIFIED IDEOGRAPH + 0xCCB0: 0x9694, //CJK UNIFIED IDEOGRAPH + 0xCCB1: 0x5805, //CJK UNIFIED IDEOGRAPH + 0xCCB2: 0x727D, //CJK UNIFIED IDEOGRAPH + 0xCCB3: 0x72AC, //CJK UNIFIED IDEOGRAPH + 0xCCB4: 0x7504, //CJK UNIFIED IDEOGRAPH + 0xCCB5: 0x7D79, //CJK UNIFIED IDEOGRAPH + 0xCCB6: 0x7E6D, //CJK UNIFIED IDEOGRAPH + 0xCCB7: 0x80A9, //CJK UNIFIED IDEOGRAPH + 0xCCB8: 0x898B, //CJK UNIFIED IDEOGRAPH + 0xCCB9: 0x8B74, //CJK UNIFIED IDEOGRAPH + 0xCCBA: 0x9063, //CJK UNIFIED IDEOGRAPH + 0xCCBB: 0x9D51, //CJK UNIFIED IDEOGRAPH + 0xCCBC: 0x6289, //CJK UNIFIED IDEOGRAPH + 0xCCBD: 0x6C7A, //CJK UNIFIED IDEOGRAPH + 0xCCBE: 0x6F54, //CJK UNIFIED IDEOGRAPH + 0xCCBF: 0x7D50, //CJK UNIFIED IDEOGRAPH + 0xCCC0: 0x7F3A, //CJK UNIFIED IDEOGRAPH + 0xCCC1: 0x8A23, //CJK UNIFIED IDEOGRAPH + 0xCCC2: 0x517C, //CJK UNIFIED IDEOGRAPH + 0xCCC3: 0x614A, //CJK UNIFIED IDEOGRAPH + 0xCCC4: 0x7B9D, //CJK UNIFIED IDEOGRAPH + 0xCCC5: 0x8B19, //CJK UNIFIED IDEOGRAPH + 0xCCC6: 0x9257, //CJK UNIFIED IDEOGRAPH + 0xCCC7: 0x938C, //CJK UNIFIED IDEOGRAPH + 0xCCC8: 0x4EAC, //CJK UNIFIED IDEOGRAPH + 0xCCC9: 0x4FD3, //CJK UNIFIED IDEOGRAPH + 0xCCCA: 0x501E, //CJK UNIFIED IDEOGRAPH + 0xCCCB: 0x50BE, //CJK UNIFIED IDEOGRAPH + 0xCCCC: 0x5106, //CJK UNIFIED IDEOGRAPH + 0xCCCD: 0x52C1, //CJK UNIFIED IDEOGRAPH + 0xCCCE: 0x52CD, //CJK UNIFIED IDEOGRAPH + 0xCCCF: 0x537F, //CJK UNIFIED IDEOGRAPH + 0xCCD0: 0x5770, //CJK UNIFIED IDEOGRAPH + 0xCCD1: 0x5883, //CJK UNIFIED IDEOGRAPH + 0xCCD2: 0x5E9A, //CJK UNIFIED IDEOGRAPH + 0xCCD3: 0x5F91, //CJK UNIFIED IDEOGRAPH + 0xCCD4: 0x6176, //CJK UNIFIED IDEOGRAPH + 0xCCD5: 0x61AC, //CJK UNIFIED IDEOGRAPH + 0xCCD6: 0x64CE, //CJK UNIFIED IDEOGRAPH + 0xCCD7: 0x656C, //CJK UNIFIED IDEOGRAPH + 0xCCD8: 0x666F, //CJK UNIFIED IDEOGRAPH + 0xCCD9: 0x66BB, //CJK UNIFIED IDEOGRAPH + 0xCCDA: 0x66F4, //CJK UNIFIED IDEOGRAPH + 0xCCDB: 0x6897, //CJK UNIFIED IDEOGRAPH + 0xCCDC: 0x6D87, //CJK UNIFIED IDEOGRAPH + 0xCCDD: 0x7085, //CJK UNIFIED IDEOGRAPH + 0xCCDE: 0x70F1, //CJK UNIFIED IDEOGRAPH + 0xCCDF: 0x749F, //CJK UNIFIED IDEOGRAPH + 0xCCE0: 0x74A5, //CJK UNIFIED IDEOGRAPH + 0xCCE1: 0x74CA, //CJK UNIFIED IDEOGRAPH + 0xCCE2: 0x75D9, //CJK UNIFIED IDEOGRAPH + 0xCCE3: 0x786C, //CJK UNIFIED IDEOGRAPH + 0xCCE4: 0x78EC, //CJK UNIFIED IDEOGRAPH + 0xCCE5: 0x7ADF, //CJK UNIFIED IDEOGRAPH + 0xCCE6: 0x7AF6, //CJK UNIFIED IDEOGRAPH + 0xCCE7: 0x7D45, //CJK UNIFIED IDEOGRAPH + 0xCCE8: 0x7D93, //CJK UNIFIED IDEOGRAPH + 0xCCE9: 0x8015, //CJK UNIFIED IDEOGRAPH + 0xCCEA: 0x803F, //CJK UNIFIED IDEOGRAPH + 0xCCEB: 0x811B, //CJK UNIFIED IDEOGRAPH + 0xCCEC: 0x8396, //CJK UNIFIED IDEOGRAPH + 0xCCED: 0x8B66, //CJK UNIFIED IDEOGRAPH + 0xCCEE: 0x8F15, //CJK UNIFIED IDEOGRAPH + 0xCCEF: 0x9015, //CJK UNIFIED IDEOGRAPH + 0xCCF0: 0x93E1, //CJK UNIFIED IDEOGRAPH + 0xCCF1: 0x9803, //CJK UNIFIED IDEOGRAPH + 0xCCF2: 0x9838, //CJK UNIFIED IDEOGRAPH + 0xCCF3: 0x9A5A, //CJK UNIFIED IDEOGRAPH + 0xCCF4: 0x9BE8, //CJK UNIFIED IDEOGRAPH + 0xCCF5: 0x4FC2, //CJK UNIFIED IDEOGRAPH + 0xCCF6: 0x5553, //CJK UNIFIED IDEOGRAPH + 0xCCF7: 0x583A, //CJK UNIFIED IDEOGRAPH + 0xCCF8: 0x5951, //CJK UNIFIED IDEOGRAPH + 0xCCF9: 0x5B63, //CJK UNIFIED IDEOGRAPH + 0xCCFA: 0x5C46, //CJK UNIFIED IDEOGRAPH + 0xCCFB: 0x60B8, //CJK UNIFIED IDEOGRAPH + 0xCCFC: 0x6212, //CJK UNIFIED IDEOGRAPH + 0xCCFD: 0x6842, //CJK UNIFIED IDEOGRAPH + 0xCCFE: 0x68B0, //CJK UNIFIED IDEOGRAPH + 0xCDA1: 0x68E8, //CJK UNIFIED IDEOGRAPH + 0xCDA2: 0x6EAA, //CJK UNIFIED IDEOGRAPH + 0xCDA3: 0x754C, //CJK UNIFIED IDEOGRAPH + 0xCDA4: 0x7678, //CJK UNIFIED IDEOGRAPH + 0xCDA5: 0x78CE, //CJK UNIFIED IDEOGRAPH + 0xCDA6: 0x7A3D, //CJK UNIFIED IDEOGRAPH + 0xCDA7: 0x7CFB, //CJK UNIFIED IDEOGRAPH + 0xCDA8: 0x7E6B, //CJK UNIFIED IDEOGRAPH + 0xCDA9: 0x7E7C, //CJK UNIFIED IDEOGRAPH + 0xCDAA: 0x8A08, //CJK UNIFIED IDEOGRAPH + 0xCDAB: 0x8AA1, //CJK UNIFIED IDEOGRAPH + 0xCDAC: 0x8C3F, //CJK UNIFIED IDEOGRAPH + 0xCDAD: 0x968E, //CJK UNIFIED IDEOGRAPH + 0xCDAE: 0x9DC4, //CJK UNIFIED IDEOGRAPH + 0xCDAF: 0x53E4, //CJK UNIFIED IDEOGRAPH + 0xCDB0: 0x53E9, //CJK UNIFIED IDEOGRAPH + 0xCDB1: 0x544A, //CJK UNIFIED IDEOGRAPH + 0xCDB2: 0x5471, //CJK UNIFIED IDEOGRAPH + 0xCDB3: 0x56FA, //CJK UNIFIED IDEOGRAPH + 0xCDB4: 0x59D1, //CJK UNIFIED IDEOGRAPH + 0xCDB5: 0x5B64, //CJK UNIFIED IDEOGRAPH + 0xCDB6: 0x5C3B, //CJK UNIFIED IDEOGRAPH + 0xCDB7: 0x5EAB, //CJK UNIFIED IDEOGRAPH + 0xCDB8: 0x62F7, //CJK UNIFIED IDEOGRAPH + 0xCDB9: 0x6537, //CJK UNIFIED IDEOGRAPH + 0xCDBA: 0x6545, //CJK UNIFIED IDEOGRAPH + 0xCDBB: 0x6572, //CJK UNIFIED IDEOGRAPH + 0xCDBC: 0x66A0, //CJK UNIFIED IDEOGRAPH + 0xCDBD: 0x67AF, //CJK UNIFIED IDEOGRAPH + 0xCDBE: 0x69C1, //CJK UNIFIED IDEOGRAPH + 0xCDBF: 0x6CBD, //CJK UNIFIED IDEOGRAPH + 0xCDC0: 0x75FC, //CJK UNIFIED IDEOGRAPH + 0xCDC1: 0x7690, //CJK UNIFIED IDEOGRAPH + 0xCDC2: 0x777E, //CJK UNIFIED IDEOGRAPH + 0xCDC3: 0x7A3F, //CJK UNIFIED IDEOGRAPH + 0xCDC4: 0x7F94, //CJK UNIFIED IDEOGRAPH + 0xCDC5: 0x8003, //CJK UNIFIED IDEOGRAPH + 0xCDC6: 0x80A1, //CJK UNIFIED IDEOGRAPH + 0xCDC7: 0x818F, //CJK UNIFIED IDEOGRAPH + 0xCDC8: 0x82E6, //CJK UNIFIED IDEOGRAPH + 0xCDC9: 0x82FD, //CJK UNIFIED IDEOGRAPH + 0xCDCA: 0x83F0, //CJK UNIFIED IDEOGRAPH + 0xCDCB: 0x85C1, //CJK UNIFIED IDEOGRAPH + 0xCDCC: 0x8831, //CJK UNIFIED IDEOGRAPH + 0xCDCD: 0x88B4, //CJK UNIFIED IDEOGRAPH + 0xCDCE: 0x8AA5, //CJK UNIFIED IDEOGRAPH + 0xCDCF: 0xF903, //CJK COMPATIBILITY IDEOGRAPH + 0xCDD0: 0x8F9C, //CJK UNIFIED IDEOGRAPH + 0xCDD1: 0x932E, //CJK UNIFIED IDEOGRAPH + 0xCDD2: 0x96C7, //CJK UNIFIED IDEOGRAPH + 0xCDD3: 0x9867, //CJK UNIFIED IDEOGRAPH + 0xCDD4: 0x9AD8, //CJK UNIFIED IDEOGRAPH + 0xCDD5: 0x9F13, //CJK UNIFIED IDEOGRAPH + 0xCDD6: 0x54ED, //CJK UNIFIED IDEOGRAPH + 0xCDD7: 0x659B, //CJK UNIFIED IDEOGRAPH + 0xCDD8: 0x66F2, //CJK UNIFIED IDEOGRAPH + 0xCDD9: 0x688F, //CJK UNIFIED IDEOGRAPH + 0xCDDA: 0x7A40, //CJK UNIFIED IDEOGRAPH + 0xCDDB: 0x8C37, //CJK UNIFIED IDEOGRAPH + 0xCDDC: 0x9D60, //CJK UNIFIED IDEOGRAPH + 0xCDDD: 0x56F0, //CJK UNIFIED IDEOGRAPH + 0xCDDE: 0x5764, //CJK UNIFIED IDEOGRAPH + 0xCDDF: 0x5D11, //CJK UNIFIED IDEOGRAPH + 0xCDE0: 0x6606, //CJK UNIFIED IDEOGRAPH + 0xCDE1: 0x68B1, //CJK UNIFIED IDEOGRAPH + 0xCDE2: 0x68CD, //CJK UNIFIED IDEOGRAPH + 0xCDE3: 0x6EFE, //CJK UNIFIED IDEOGRAPH + 0xCDE4: 0x7428, //CJK UNIFIED IDEOGRAPH + 0xCDE5: 0x889E, //CJK UNIFIED IDEOGRAPH + 0xCDE6: 0x9BE4, //CJK UNIFIED IDEOGRAPH + 0xCDE7: 0x6C68, //CJK UNIFIED IDEOGRAPH + 0xCDE8: 0xF904, //CJK COMPATIBILITY IDEOGRAPH + 0xCDE9: 0x9AA8, //CJK UNIFIED IDEOGRAPH + 0xCDEA: 0x4F9B, //CJK UNIFIED IDEOGRAPH + 0xCDEB: 0x516C, //CJK UNIFIED IDEOGRAPH + 0xCDEC: 0x5171, //CJK UNIFIED IDEOGRAPH + 0xCDED: 0x529F, //CJK UNIFIED IDEOGRAPH + 0xCDEE: 0x5B54, //CJK UNIFIED IDEOGRAPH + 0xCDEF: 0x5DE5, //CJK UNIFIED IDEOGRAPH + 0xCDF0: 0x6050, //CJK UNIFIED IDEOGRAPH + 0xCDF1: 0x606D, //CJK UNIFIED IDEOGRAPH + 0xCDF2: 0x62F1, //CJK UNIFIED IDEOGRAPH + 0xCDF3: 0x63A7, //CJK UNIFIED IDEOGRAPH + 0xCDF4: 0x653B, //CJK UNIFIED IDEOGRAPH + 0xCDF5: 0x73D9, //CJK UNIFIED IDEOGRAPH + 0xCDF6: 0x7A7A, //CJK UNIFIED IDEOGRAPH + 0xCDF7: 0x86A3, //CJK UNIFIED IDEOGRAPH + 0xCDF8: 0x8CA2, //CJK UNIFIED IDEOGRAPH + 0xCDF9: 0x978F, //CJK UNIFIED IDEOGRAPH + 0xCDFA: 0x4E32, //CJK UNIFIED IDEOGRAPH + 0xCDFB: 0x5BE1, //CJK UNIFIED IDEOGRAPH + 0xCDFC: 0x6208, //CJK UNIFIED IDEOGRAPH + 0xCDFD: 0x679C, //CJK UNIFIED IDEOGRAPH + 0xCDFE: 0x74DC, //CJK UNIFIED IDEOGRAPH + 0xCEA1: 0x79D1, //CJK UNIFIED IDEOGRAPH + 0xCEA2: 0x83D3, //CJK UNIFIED IDEOGRAPH + 0xCEA3: 0x8A87, //CJK UNIFIED IDEOGRAPH + 0xCEA4: 0x8AB2, //CJK UNIFIED IDEOGRAPH + 0xCEA5: 0x8DE8, //CJK UNIFIED IDEOGRAPH + 0xCEA6: 0x904E, //CJK UNIFIED IDEOGRAPH + 0xCEA7: 0x934B, //CJK UNIFIED IDEOGRAPH + 0xCEA8: 0x9846, //CJK UNIFIED IDEOGRAPH + 0xCEA9: 0x5ED3, //CJK UNIFIED IDEOGRAPH + 0xCEAA: 0x69E8, //CJK UNIFIED IDEOGRAPH + 0xCEAB: 0x85FF, //CJK UNIFIED IDEOGRAPH + 0xCEAC: 0x90ED, //CJK UNIFIED IDEOGRAPH + 0xCEAD: 0xF905, //CJK COMPATIBILITY IDEOGRAPH + 0xCEAE: 0x51A0, //CJK UNIFIED IDEOGRAPH + 0xCEAF: 0x5B98, //CJK UNIFIED IDEOGRAPH + 0xCEB0: 0x5BEC, //CJK UNIFIED IDEOGRAPH + 0xCEB1: 0x6163, //CJK UNIFIED IDEOGRAPH + 0xCEB2: 0x68FA, //CJK UNIFIED IDEOGRAPH + 0xCEB3: 0x6B3E, //CJK UNIFIED IDEOGRAPH + 0xCEB4: 0x704C, //CJK UNIFIED IDEOGRAPH + 0xCEB5: 0x742F, //CJK UNIFIED IDEOGRAPH + 0xCEB6: 0x74D8, //CJK UNIFIED IDEOGRAPH + 0xCEB7: 0x7BA1, //CJK UNIFIED IDEOGRAPH + 0xCEB8: 0x7F50, //CJK UNIFIED IDEOGRAPH + 0xCEB9: 0x83C5, //CJK UNIFIED IDEOGRAPH + 0xCEBA: 0x89C0, //CJK UNIFIED IDEOGRAPH + 0xCEBB: 0x8CAB, //CJK UNIFIED IDEOGRAPH + 0xCEBC: 0x95DC, //CJK UNIFIED IDEOGRAPH + 0xCEBD: 0x9928, //CJK UNIFIED IDEOGRAPH + 0xCEBE: 0x522E, //CJK UNIFIED IDEOGRAPH + 0xCEBF: 0x605D, //CJK UNIFIED IDEOGRAPH + 0xCEC0: 0x62EC, //CJK UNIFIED IDEOGRAPH + 0xCEC1: 0x9002, //CJK UNIFIED IDEOGRAPH + 0xCEC2: 0x4F8A, //CJK UNIFIED IDEOGRAPH + 0xCEC3: 0x5149, //CJK UNIFIED IDEOGRAPH + 0xCEC4: 0x5321, //CJK UNIFIED IDEOGRAPH + 0xCEC5: 0x58D9, //CJK UNIFIED IDEOGRAPH + 0xCEC6: 0x5EE3, //CJK UNIFIED IDEOGRAPH + 0xCEC7: 0x66E0, //CJK UNIFIED IDEOGRAPH + 0xCEC8: 0x6D38, //CJK UNIFIED IDEOGRAPH + 0xCEC9: 0x709A, //CJK UNIFIED IDEOGRAPH + 0xCECA: 0x72C2, //CJK UNIFIED IDEOGRAPH + 0xCECB: 0x73D6, //CJK UNIFIED IDEOGRAPH + 0xCECC: 0x7B50, //CJK UNIFIED IDEOGRAPH + 0xCECD: 0x80F1, //CJK UNIFIED IDEOGRAPH + 0xCECE: 0x945B, //CJK UNIFIED IDEOGRAPH + 0xCECF: 0x5366, //CJK UNIFIED IDEOGRAPH + 0xCED0: 0x639B, //CJK UNIFIED IDEOGRAPH + 0xCED1: 0x7F6B, //CJK UNIFIED IDEOGRAPH + 0xCED2: 0x4E56, //CJK UNIFIED IDEOGRAPH + 0xCED3: 0x5080, //CJK UNIFIED IDEOGRAPH + 0xCED4: 0x584A, //CJK UNIFIED IDEOGRAPH + 0xCED5: 0x58DE, //CJK UNIFIED IDEOGRAPH + 0xCED6: 0x602A, //CJK UNIFIED IDEOGRAPH + 0xCED7: 0x6127, //CJK UNIFIED IDEOGRAPH + 0xCED8: 0x62D0, //CJK UNIFIED IDEOGRAPH + 0xCED9: 0x69D0, //CJK UNIFIED IDEOGRAPH + 0xCEDA: 0x9B41, //CJK UNIFIED IDEOGRAPH + 0xCEDB: 0x5B8F, //CJK UNIFIED IDEOGRAPH + 0xCEDC: 0x7D18, //CJK UNIFIED IDEOGRAPH + 0xCEDD: 0x80B1, //CJK UNIFIED IDEOGRAPH + 0xCEDE: 0x8F5F, //CJK UNIFIED IDEOGRAPH + 0xCEDF: 0x4EA4, //CJK UNIFIED IDEOGRAPH + 0xCEE0: 0x50D1, //CJK UNIFIED IDEOGRAPH + 0xCEE1: 0x54AC, //CJK UNIFIED IDEOGRAPH + 0xCEE2: 0x55AC, //CJK UNIFIED IDEOGRAPH + 0xCEE3: 0x5B0C, //CJK UNIFIED IDEOGRAPH + 0xCEE4: 0x5DA0, //CJK UNIFIED IDEOGRAPH + 0xCEE5: 0x5DE7, //CJK UNIFIED IDEOGRAPH + 0xCEE6: 0x652A, //CJK UNIFIED IDEOGRAPH + 0xCEE7: 0x654E, //CJK UNIFIED IDEOGRAPH + 0xCEE8: 0x6821, //CJK UNIFIED IDEOGRAPH + 0xCEE9: 0x6A4B, //CJK UNIFIED IDEOGRAPH + 0xCEEA: 0x72E1, //CJK UNIFIED IDEOGRAPH + 0xCEEB: 0x768E, //CJK UNIFIED IDEOGRAPH + 0xCEEC: 0x77EF, //CJK UNIFIED IDEOGRAPH + 0xCEED: 0x7D5E, //CJK UNIFIED IDEOGRAPH + 0xCEEE: 0x7FF9, //CJK UNIFIED IDEOGRAPH + 0xCEEF: 0x81A0, //CJK UNIFIED IDEOGRAPH + 0xCEF0: 0x854E, //CJK UNIFIED IDEOGRAPH + 0xCEF1: 0x86DF, //CJK UNIFIED IDEOGRAPH + 0xCEF2: 0x8F03, //CJK UNIFIED IDEOGRAPH + 0xCEF3: 0x8F4E, //CJK UNIFIED IDEOGRAPH + 0xCEF4: 0x90CA, //CJK UNIFIED IDEOGRAPH + 0xCEF5: 0x9903, //CJK UNIFIED IDEOGRAPH + 0xCEF6: 0x9A55, //CJK UNIFIED IDEOGRAPH + 0xCEF7: 0x9BAB, //CJK UNIFIED IDEOGRAPH + 0xCEF8: 0x4E18, //CJK UNIFIED IDEOGRAPH + 0xCEF9: 0x4E45, //CJK UNIFIED IDEOGRAPH + 0xCEFA: 0x4E5D, //CJK UNIFIED IDEOGRAPH + 0xCEFB: 0x4EC7, //CJK UNIFIED IDEOGRAPH + 0xCEFC: 0x4FF1, //CJK UNIFIED IDEOGRAPH + 0xCEFD: 0x5177, //CJK UNIFIED IDEOGRAPH + 0xCEFE: 0x52FE, //CJK UNIFIED IDEOGRAPH + 0xCFA1: 0x5340, //CJK UNIFIED IDEOGRAPH + 0xCFA2: 0x53E3, //CJK UNIFIED IDEOGRAPH + 0xCFA3: 0x53E5, //CJK UNIFIED IDEOGRAPH + 0xCFA4: 0x548E, //CJK UNIFIED IDEOGRAPH + 0xCFA5: 0x5614, //CJK UNIFIED IDEOGRAPH + 0xCFA6: 0x5775, //CJK UNIFIED IDEOGRAPH + 0xCFA7: 0x57A2, //CJK UNIFIED IDEOGRAPH + 0xCFA8: 0x5BC7, //CJK UNIFIED IDEOGRAPH + 0xCFA9: 0x5D87, //CJK UNIFIED IDEOGRAPH + 0xCFAA: 0x5ED0, //CJK UNIFIED IDEOGRAPH + 0xCFAB: 0x61FC, //CJK UNIFIED IDEOGRAPH + 0xCFAC: 0x62D8, //CJK UNIFIED IDEOGRAPH + 0xCFAD: 0x6551, //CJK UNIFIED IDEOGRAPH + 0xCFAE: 0x67B8, //CJK UNIFIED IDEOGRAPH + 0xCFAF: 0x67E9, //CJK UNIFIED IDEOGRAPH + 0xCFB0: 0x69CB, //CJK UNIFIED IDEOGRAPH + 0xCFB1: 0x6B50, //CJK UNIFIED IDEOGRAPH + 0xCFB2: 0x6BC6, //CJK UNIFIED IDEOGRAPH + 0xCFB3: 0x6BEC, //CJK UNIFIED IDEOGRAPH + 0xCFB4: 0x6C42, //CJK UNIFIED IDEOGRAPH + 0xCFB5: 0x6E9D, //CJK UNIFIED IDEOGRAPH + 0xCFB6: 0x7078, //CJK UNIFIED IDEOGRAPH + 0xCFB7: 0x72D7, //CJK UNIFIED IDEOGRAPH + 0xCFB8: 0x7396, //CJK UNIFIED IDEOGRAPH + 0xCFB9: 0x7403, //CJK UNIFIED IDEOGRAPH + 0xCFBA: 0x77BF, //CJK UNIFIED IDEOGRAPH + 0xCFBB: 0x77E9, //CJK UNIFIED IDEOGRAPH + 0xCFBC: 0x7A76, //CJK UNIFIED IDEOGRAPH + 0xCFBD: 0x7D7F, //CJK UNIFIED IDEOGRAPH + 0xCFBE: 0x8009, //CJK UNIFIED IDEOGRAPH + 0xCFBF: 0x81FC, //CJK UNIFIED IDEOGRAPH + 0xCFC0: 0x8205, //CJK UNIFIED IDEOGRAPH + 0xCFC1: 0x820A, //CJK UNIFIED IDEOGRAPH + 0xCFC2: 0x82DF, //CJK UNIFIED IDEOGRAPH + 0xCFC3: 0x8862, //CJK UNIFIED IDEOGRAPH + 0xCFC4: 0x8B33, //CJK UNIFIED IDEOGRAPH + 0xCFC5: 0x8CFC, //CJK UNIFIED IDEOGRAPH + 0xCFC6: 0x8EC0, //CJK UNIFIED IDEOGRAPH + 0xCFC7: 0x9011, //CJK UNIFIED IDEOGRAPH + 0xCFC8: 0x90B1, //CJK UNIFIED IDEOGRAPH + 0xCFC9: 0x9264, //CJK UNIFIED IDEOGRAPH + 0xCFCA: 0x92B6, //CJK UNIFIED IDEOGRAPH + 0xCFCB: 0x99D2, //CJK UNIFIED IDEOGRAPH + 0xCFCC: 0x9A45, //CJK UNIFIED IDEOGRAPH + 0xCFCD: 0x9CE9, //CJK UNIFIED IDEOGRAPH + 0xCFCE: 0x9DD7, //CJK UNIFIED IDEOGRAPH + 0xCFCF: 0x9F9C, //CJK UNIFIED IDEOGRAPH + 0xCFD0: 0x570B, //CJK UNIFIED IDEOGRAPH + 0xCFD1: 0x5C40, //CJK UNIFIED IDEOGRAPH + 0xCFD2: 0x83CA, //CJK UNIFIED IDEOGRAPH + 0xCFD3: 0x97A0, //CJK UNIFIED IDEOGRAPH + 0xCFD4: 0x97AB, //CJK UNIFIED IDEOGRAPH + 0xCFD5: 0x9EB4, //CJK UNIFIED IDEOGRAPH + 0xCFD6: 0x541B, //CJK UNIFIED IDEOGRAPH + 0xCFD7: 0x7A98, //CJK UNIFIED IDEOGRAPH + 0xCFD8: 0x7FA4, //CJK UNIFIED IDEOGRAPH + 0xCFD9: 0x88D9, //CJK UNIFIED IDEOGRAPH + 0xCFDA: 0x8ECD, //CJK UNIFIED IDEOGRAPH + 0xCFDB: 0x90E1, //CJK UNIFIED IDEOGRAPH + 0xCFDC: 0x5800, //CJK UNIFIED IDEOGRAPH + 0xCFDD: 0x5C48, //CJK UNIFIED IDEOGRAPH + 0xCFDE: 0x6398, //CJK UNIFIED IDEOGRAPH + 0xCFDF: 0x7A9F, //CJK UNIFIED IDEOGRAPH + 0xCFE0: 0x5BAE, //CJK UNIFIED IDEOGRAPH + 0xCFE1: 0x5F13, //CJK UNIFIED IDEOGRAPH + 0xCFE2: 0x7A79, //CJK UNIFIED IDEOGRAPH + 0xCFE3: 0x7AAE, //CJK UNIFIED IDEOGRAPH + 0xCFE4: 0x828E, //CJK UNIFIED IDEOGRAPH + 0xCFE5: 0x8EAC, //CJK UNIFIED IDEOGRAPH + 0xCFE6: 0x5026, //CJK UNIFIED IDEOGRAPH + 0xCFE7: 0x5238, //CJK UNIFIED IDEOGRAPH + 0xCFE8: 0x52F8, //CJK UNIFIED IDEOGRAPH + 0xCFE9: 0x5377, //CJK UNIFIED IDEOGRAPH + 0xCFEA: 0x5708, //CJK UNIFIED IDEOGRAPH + 0xCFEB: 0x62F3, //CJK UNIFIED IDEOGRAPH + 0xCFEC: 0x6372, //CJK UNIFIED IDEOGRAPH + 0xCFED: 0x6B0A, //CJK UNIFIED IDEOGRAPH + 0xCFEE: 0x6DC3, //CJK UNIFIED IDEOGRAPH + 0xCFEF: 0x7737, //CJK UNIFIED IDEOGRAPH + 0xCFF0: 0x53A5, //CJK UNIFIED IDEOGRAPH + 0xCFF1: 0x7357, //CJK UNIFIED IDEOGRAPH + 0xCFF2: 0x8568, //CJK UNIFIED IDEOGRAPH + 0xCFF3: 0x8E76, //CJK UNIFIED IDEOGRAPH + 0xCFF4: 0x95D5, //CJK UNIFIED IDEOGRAPH + 0xCFF5: 0x673A, //CJK UNIFIED IDEOGRAPH + 0xCFF6: 0x6AC3, //CJK UNIFIED IDEOGRAPH + 0xCFF7: 0x6F70, //CJK UNIFIED IDEOGRAPH + 0xCFF8: 0x8A6D, //CJK UNIFIED IDEOGRAPH + 0xCFF9: 0x8ECC, //CJK UNIFIED IDEOGRAPH + 0xCFFA: 0x994B, //CJK UNIFIED IDEOGRAPH + 0xCFFB: 0xF906, //CJK COMPATIBILITY IDEOGRAPH + 0xCFFC: 0x6677, //CJK UNIFIED IDEOGRAPH + 0xCFFD: 0x6B78, //CJK UNIFIED IDEOGRAPH + 0xCFFE: 0x8CB4, //CJK UNIFIED IDEOGRAPH + 0xD0A1: 0x9B3C, //CJK UNIFIED IDEOGRAPH + 0xD0A2: 0xF907, //CJK COMPATIBILITY IDEOGRAPH + 0xD0A3: 0x53EB, //CJK UNIFIED IDEOGRAPH + 0xD0A4: 0x572D, //CJK UNIFIED IDEOGRAPH + 0xD0A5: 0x594E, //CJK UNIFIED IDEOGRAPH + 0xD0A6: 0x63C6, //CJK UNIFIED IDEOGRAPH + 0xD0A7: 0x69FB, //CJK UNIFIED IDEOGRAPH + 0xD0A8: 0x73EA, //CJK UNIFIED IDEOGRAPH + 0xD0A9: 0x7845, //CJK UNIFIED IDEOGRAPH + 0xD0AA: 0x7ABA, //CJK UNIFIED IDEOGRAPH + 0xD0AB: 0x7AC5, //CJK UNIFIED IDEOGRAPH + 0xD0AC: 0x7CFE, //CJK UNIFIED IDEOGRAPH + 0xD0AD: 0x8475, //CJK UNIFIED IDEOGRAPH + 0xD0AE: 0x898F, //CJK UNIFIED IDEOGRAPH + 0xD0AF: 0x8D73, //CJK UNIFIED IDEOGRAPH + 0xD0B0: 0x9035, //CJK UNIFIED IDEOGRAPH + 0xD0B1: 0x95A8, //CJK UNIFIED IDEOGRAPH + 0xD0B2: 0x52FB, //CJK UNIFIED IDEOGRAPH + 0xD0B3: 0x5747, //CJK UNIFIED IDEOGRAPH + 0xD0B4: 0x7547, //CJK UNIFIED IDEOGRAPH + 0xD0B5: 0x7B60, //CJK UNIFIED IDEOGRAPH + 0xD0B6: 0x83CC, //CJK UNIFIED IDEOGRAPH + 0xD0B7: 0x921E, //CJK UNIFIED IDEOGRAPH + 0xD0B8: 0xF908, //CJK COMPATIBILITY IDEOGRAPH + 0xD0B9: 0x6A58, //CJK UNIFIED IDEOGRAPH + 0xD0BA: 0x514B, //CJK UNIFIED IDEOGRAPH + 0xD0BB: 0x524B, //CJK UNIFIED IDEOGRAPH + 0xD0BC: 0x5287, //CJK UNIFIED IDEOGRAPH + 0xD0BD: 0x621F, //CJK UNIFIED IDEOGRAPH + 0xD0BE: 0x68D8, //CJK UNIFIED IDEOGRAPH + 0xD0BF: 0x6975, //CJK UNIFIED IDEOGRAPH + 0xD0C0: 0x9699, //CJK UNIFIED IDEOGRAPH + 0xD0C1: 0x50C5, //CJK UNIFIED IDEOGRAPH + 0xD0C2: 0x52A4, //CJK UNIFIED IDEOGRAPH + 0xD0C3: 0x52E4, //CJK UNIFIED IDEOGRAPH + 0xD0C4: 0x61C3, //CJK UNIFIED IDEOGRAPH + 0xD0C5: 0x65A4, //CJK UNIFIED IDEOGRAPH + 0xD0C6: 0x6839, //CJK UNIFIED IDEOGRAPH + 0xD0C7: 0x69FF, //CJK UNIFIED IDEOGRAPH + 0xD0C8: 0x747E, //CJK UNIFIED IDEOGRAPH + 0xD0C9: 0x7B4B, //CJK UNIFIED IDEOGRAPH + 0xD0CA: 0x82B9, //CJK UNIFIED IDEOGRAPH + 0xD0CB: 0x83EB, //CJK UNIFIED IDEOGRAPH + 0xD0CC: 0x89B2, //CJK UNIFIED IDEOGRAPH + 0xD0CD: 0x8B39, //CJK UNIFIED IDEOGRAPH + 0xD0CE: 0x8FD1, //CJK UNIFIED IDEOGRAPH + 0xD0CF: 0x9949, //CJK UNIFIED IDEOGRAPH + 0xD0D0: 0xF909, //CJK COMPATIBILITY IDEOGRAPH + 0xD0D1: 0x4ECA, //CJK UNIFIED IDEOGRAPH + 0xD0D2: 0x5997, //CJK UNIFIED IDEOGRAPH + 0xD0D3: 0x64D2, //CJK UNIFIED IDEOGRAPH + 0xD0D4: 0x6611, //CJK UNIFIED IDEOGRAPH + 0xD0D5: 0x6A8E, //CJK UNIFIED IDEOGRAPH + 0xD0D6: 0x7434, //CJK UNIFIED IDEOGRAPH + 0xD0D7: 0x7981, //CJK UNIFIED IDEOGRAPH + 0xD0D8: 0x79BD, //CJK UNIFIED IDEOGRAPH + 0xD0D9: 0x82A9, //CJK UNIFIED IDEOGRAPH + 0xD0DA: 0x887E, //CJK UNIFIED IDEOGRAPH + 0xD0DB: 0x887F, //CJK UNIFIED IDEOGRAPH + 0xD0DC: 0x895F, //CJK UNIFIED IDEOGRAPH + 0xD0DD: 0xF90A, //CJK COMPATIBILITY IDEOGRAPH + 0xD0DE: 0x9326, //CJK UNIFIED IDEOGRAPH + 0xD0DF: 0x4F0B, //CJK UNIFIED IDEOGRAPH + 0xD0E0: 0x53CA, //CJK UNIFIED IDEOGRAPH + 0xD0E1: 0x6025, //CJK UNIFIED IDEOGRAPH + 0xD0E2: 0x6271, //CJK UNIFIED IDEOGRAPH + 0xD0E3: 0x6C72, //CJK UNIFIED IDEOGRAPH + 0xD0E4: 0x7D1A, //CJK UNIFIED IDEOGRAPH + 0xD0E5: 0x7D66, //CJK UNIFIED IDEOGRAPH + 0xD0E6: 0x4E98, //CJK UNIFIED IDEOGRAPH + 0xD0E7: 0x5162, //CJK UNIFIED IDEOGRAPH + 0xD0E8: 0x77DC, //CJK UNIFIED IDEOGRAPH + 0xD0E9: 0x80AF, //CJK UNIFIED IDEOGRAPH + 0xD0EA: 0x4F01, //CJK UNIFIED IDEOGRAPH + 0xD0EB: 0x4F0E, //CJK UNIFIED IDEOGRAPH + 0xD0EC: 0x5176, //CJK UNIFIED IDEOGRAPH + 0xD0ED: 0x5180, //CJK UNIFIED IDEOGRAPH + 0xD0EE: 0x55DC, //CJK UNIFIED IDEOGRAPH + 0xD0EF: 0x5668, //CJK UNIFIED IDEOGRAPH + 0xD0F0: 0x573B, //CJK UNIFIED IDEOGRAPH + 0xD0F1: 0x57FA, //CJK UNIFIED IDEOGRAPH + 0xD0F2: 0x57FC, //CJK UNIFIED IDEOGRAPH + 0xD0F3: 0x5914, //CJK UNIFIED IDEOGRAPH + 0xD0F4: 0x5947, //CJK UNIFIED IDEOGRAPH + 0xD0F5: 0x5993, //CJK UNIFIED IDEOGRAPH + 0xD0F6: 0x5BC4, //CJK UNIFIED IDEOGRAPH + 0xD0F7: 0x5C90, //CJK UNIFIED IDEOGRAPH + 0xD0F8: 0x5D0E, //CJK UNIFIED IDEOGRAPH + 0xD0F9: 0x5DF1, //CJK UNIFIED IDEOGRAPH + 0xD0FA: 0x5E7E, //CJK UNIFIED IDEOGRAPH + 0xD0FB: 0x5FCC, //CJK UNIFIED IDEOGRAPH + 0xD0FC: 0x6280, //CJK UNIFIED IDEOGRAPH + 0xD0FD: 0x65D7, //CJK UNIFIED IDEOGRAPH + 0xD0FE: 0x65E3, //CJK UNIFIED IDEOGRAPH + 0xD1A1: 0x671E, //CJK UNIFIED IDEOGRAPH + 0xD1A2: 0x671F, //CJK UNIFIED IDEOGRAPH + 0xD1A3: 0x675E, //CJK UNIFIED IDEOGRAPH + 0xD1A4: 0x68CB, //CJK UNIFIED IDEOGRAPH + 0xD1A5: 0x68C4, //CJK UNIFIED IDEOGRAPH + 0xD1A6: 0x6A5F, //CJK UNIFIED IDEOGRAPH + 0xD1A7: 0x6B3A, //CJK UNIFIED IDEOGRAPH + 0xD1A8: 0x6C23, //CJK UNIFIED IDEOGRAPH + 0xD1A9: 0x6C7D, //CJK UNIFIED IDEOGRAPH + 0xD1AA: 0x6C82, //CJK UNIFIED IDEOGRAPH + 0xD1AB: 0x6DC7, //CJK UNIFIED IDEOGRAPH + 0xD1AC: 0x7398, //CJK UNIFIED IDEOGRAPH + 0xD1AD: 0x7426, //CJK UNIFIED IDEOGRAPH + 0xD1AE: 0x742A, //CJK UNIFIED IDEOGRAPH + 0xD1AF: 0x7482, //CJK UNIFIED IDEOGRAPH + 0xD1B0: 0x74A3, //CJK UNIFIED IDEOGRAPH + 0xD1B1: 0x7578, //CJK UNIFIED IDEOGRAPH + 0xD1B2: 0x757F, //CJK UNIFIED IDEOGRAPH + 0xD1B3: 0x7881, //CJK UNIFIED IDEOGRAPH + 0xD1B4: 0x78EF, //CJK UNIFIED IDEOGRAPH + 0xD1B5: 0x7941, //CJK UNIFIED IDEOGRAPH + 0xD1B6: 0x7947, //CJK UNIFIED IDEOGRAPH + 0xD1B7: 0x7948, //CJK UNIFIED IDEOGRAPH + 0xD1B8: 0x797A, //CJK UNIFIED IDEOGRAPH + 0xD1B9: 0x7B95, //CJK UNIFIED IDEOGRAPH + 0xD1BA: 0x7D00, //CJK UNIFIED IDEOGRAPH + 0xD1BB: 0x7DBA, //CJK UNIFIED IDEOGRAPH + 0xD1BC: 0x7F88, //CJK UNIFIED IDEOGRAPH + 0xD1BD: 0x8006, //CJK UNIFIED IDEOGRAPH + 0xD1BE: 0x802D, //CJK UNIFIED IDEOGRAPH + 0xD1BF: 0x808C, //CJK UNIFIED IDEOGRAPH + 0xD1C0: 0x8A18, //CJK UNIFIED IDEOGRAPH + 0xD1C1: 0x8B4F, //CJK UNIFIED IDEOGRAPH + 0xD1C2: 0x8C48, //CJK UNIFIED IDEOGRAPH + 0xD1C3: 0x8D77, //CJK UNIFIED IDEOGRAPH + 0xD1C4: 0x9321, //CJK UNIFIED IDEOGRAPH + 0xD1C5: 0x9324, //CJK UNIFIED IDEOGRAPH + 0xD1C6: 0x98E2, //CJK UNIFIED IDEOGRAPH + 0xD1C7: 0x9951, //CJK UNIFIED IDEOGRAPH + 0xD1C8: 0x9A0E, //CJK UNIFIED IDEOGRAPH + 0xD1C9: 0x9A0F, //CJK UNIFIED IDEOGRAPH + 0xD1CA: 0x9A65, //CJK UNIFIED IDEOGRAPH + 0xD1CB: 0x9E92, //CJK UNIFIED IDEOGRAPH + 0xD1CC: 0x7DCA, //CJK UNIFIED IDEOGRAPH + 0xD1CD: 0x4F76, //CJK UNIFIED IDEOGRAPH + 0xD1CE: 0x5409, //CJK UNIFIED IDEOGRAPH + 0xD1CF: 0x62EE, //CJK UNIFIED IDEOGRAPH + 0xD1D0: 0x6854, //CJK UNIFIED IDEOGRAPH + 0xD1D1: 0x91D1, //CJK UNIFIED IDEOGRAPH + 0xD1D2: 0x55AB, //CJK UNIFIED IDEOGRAPH + 0xD1D3: 0x513A, //CJK UNIFIED IDEOGRAPH + 0xD1D4: 0xF90B, //CJK COMPATIBILITY IDEOGRAPH + 0xD1D5: 0xF90C, //CJK COMPATIBILITY IDEOGRAPH + 0xD1D6: 0x5A1C, //CJK UNIFIED IDEOGRAPH + 0xD1D7: 0x61E6, //CJK UNIFIED IDEOGRAPH + 0xD1D8: 0xF90D, //CJK COMPATIBILITY IDEOGRAPH + 0xD1D9: 0x62CF, //CJK UNIFIED IDEOGRAPH + 0xD1DA: 0x62FF, //CJK UNIFIED IDEOGRAPH + 0xD1DB: 0xF90E, //CJK COMPATIBILITY IDEOGRAPH + 0xD1DC: 0xF90F, //CJK COMPATIBILITY IDEOGRAPH + 0xD1DD: 0xF910, //CJK COMPATIBILITY IDEOGRAPH + 0xD1DE: 0xF911, //CJK COMPATIBILITY IDEOGRAPH + 0xD1DF: 0xF912, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E0: 0xF913, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E1: 0x90A3, //CJK UNIFIED IDEOGRAPH + 0xD1E2: 0xF914, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E3: 0xF915, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E4: 0xF916, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E5: 0xF917, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E6: 0xF918, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E7: 0x8AFE, //CJK UNIFIED IDEOGRAPH + 0xD1E8: 0xF919, //CJK COMPATIBILITY IDEOGRAPH + 0xD1E9: 0xF91A, //CJK COMPATIBILITY IDEOGRAPH + 0xD1EA: 0xF91B, //CJK COMPATIBILITY IDEOGRAPH + 0xD1EB: 0xF91C, //CJK COMPATIBILITY IDEOGRAPH + 0xD1EC: 0x6696, //CJK UNIFIED IDEOGRAPH + 0xD1ED: 0xF91D, //CJK COMPATIBILITY IDEOGRAPH + 0xD1EE: 0x7156, //CJK UNIFIED IDEOGRAPH + 0xD1EF: 0xF91E, //CJK COMPATIBILITY IDEOGRAPH + 0xD1F0: 0xF91F, //CJK COMPATIBILITY IDEOGRAPH + 0xD1F1: 0x96E3, //CJK UNIFIED IDEOGRAPH + 0xD1F2: 0xF920, //CJK COMPATIBILITY IDEOGRAPH + 0xD1F3: 0x634F, //CJK UNIFIED IDEOGRAPH + 0xD1F4: 0x637A, //CJK UNIFIED IDEOGRAPH + 0xD1F5: 0x5357, //CJK UNIFIED IDEOGRAPH + 0xD1F6: 0xF921, //CJK COMPATIBILITY IDEOGRAPH + 0xD1F7: 0x678F, //CJK UNIFIED IDEOGRAPH + 0xD1F8: 0x6960, //CJK UNIFIED IDEOGRAPH + 0xD1F9: 0x6E73, //CJK UNIFIED IDEOGRAPH + 0xD1FA: 0xF922, //CJK COMPATIBILITY IDEOGRAPH + 0xD1FB: 0x7537, //CJK UNIFIED IDEOGRAPH + 0xD1FC: 0xF923, //CJK COMPATIBILITY IDEOGRAPH + 0xD1FD: 0xF924, //CJK COMPATIBILITY IDEOGRAPH + 0xD1FE: 0xF925, //CJK COMPATIBILITY IDEOGRAPH + 0xD2A1: 0x7D0D, //CJK UNIFIED IDEOGRAPH + 0xD2A2: 0xF926, //CJK COMPATIBILITY IDEOGRAPH + 0xD2A3: 0xF927, //CJK COMPATIBILITY IDEOGRAPH + 0xD2A4: 0x8872, //CJK UNIFIED IDEOGRAPH + 0xD2A5: 0x56CA, //CJK UNIFIED IDEOGRAPH + 0xD2A6: 0x5A18, //CJK UNIFIED IDEOGRAPH + 0xD2A7: 0xF928, //CJK COMPATIBILITY IDEOGRAPH + 0xD2A8: 0xF929, //CJK COMPATIBILITY IDEOGRAPH + 0xD2A9: 0xF92A, //CJK COMPATIBILITY IDEOGRAPH + 0xD2AA: 0xF92B, //CJK COMPATIBILITY IDEOGRAPH + 0xD2AB: 0xF92C, //CJK COMPATIBILITY IDEOGRAPH + 0xD2AC: 0x4E43, //CJK UNIFIED IDEOGRAPH + 0xD2AD: 0xF92D, //CJK COMPATIBILITY IDEOGRAPH + 0xD2AE: 0x5167, //CJK UNIFIED IDEOGRAPH + 0xD2AF: 0x5948, //CJK UNIFIED IDEOGRAPH + 0xD2B0: 0x67F0, //CJK UNIFIED IDEOGRAPH + 0xD2B1: 0x8010, //CJK UNIFIED IDEOGRAPH + 0xD2B2: 0xF92E, //CJK COMPATIBILITY IDEOGRAPH + 0xD2B3: 0x5973, //CJK UNIFIED IDEOGRAPH + 0xD2B4: 0x5E74, //CJK UNIFIED IDEOGRAPH + 0xD2B5: 0x649A, //CJK UNIFIED IDEOGRAPH + 0xD2B6: 0x79CA, //CJK UNIFIED IDEOGRAPH + 0xD2B7: 0x5FF5, //CJK UNIFIED IDEOGRAPH + 0xD2B8: 0x606C, //CJK UNIFIED IDEOGRAPH + 0xD2B9: 0x62C8, //CJK UNIFIED IDEOGRAPH + 0xD2BA: 0x637B, //CJK UNIFIED IDEOGRAPH + 0xD2BB: 0x5BE7, //CJK UNIFIED IDEOGRAPH + 0xD2BC: 0x5BD7, //CJK UNIFIED IDEOGRAPH + 0xD2BD: 0x52AA, //CJK UNIFIED IDEOGRAPH + 0xD2BE: 0xF92F, //CJK COMPATIBILITY IDEOGRAPH + 0xD2BF: 0x5974, //CJK UNIFIED IDEOGRAPH + 0xD2C0: 0x5F29, //CJK UNIFIED IDEOGRAPH + 0xD2C1: 0x6012, //CJK UNIFIED IDEOGRAPH + 0xD2C2: 0xF930, //CJK COMPATIBILITY IDEOGRAPH + 0xD2C3: 0xF931, //CJK COMPATIBILITY IDEOGRAPH + 0xD2C4: 0xF932, //CJK COMPATIBILITY IDEOGRAPH + 0xD2C5: 0x7459, //CJK UNIFIED IDEOGRAPH + 0xD2C6: 0xF933, //CJK COMPATIBILITY IDEOGRAPH + 0xD2C7: 0xF934, //CJK COMPATIBILITY IDEOGRAPH + 0xD2C8: 0xF935, //CJK COMPATIBILITY IDEOGRAPH + 0xD2C9: 0xF936, //CJK COMPATIBILITY IDEOGRAPH + 0xD2CA: 0xF937, //CJK COMPATIBILITY IDEOGRAPH + 0xD2CB: 0xF938, //CJK COMPATIBILITY IDEOGRAPH + 0xD2CC: 0x99D1, //CJK UNIFIED IDEOGRAPH + 0xD2CD: 0xF939, //CJK COMPATIBILITY IDEOGRAPH + 0xD2CE: 0xF93A, //CJK COMPATIBILITY IDEOGRAPH + 0xD2CF: 0xF93B, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D0: 0xF93C, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D1: 0xF93D, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D2: 0xF93E, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D3: 0xF93F, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D4: 0xF940, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D5: 0xF941, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D6: 0xF942, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D7: 0xF943, //CJK COMPATIBILITY IDEOGRAPH + 0xD2D8: 0x6FC3, //CJK UNIFIED IDEOGRAPH + 0xD2D9: 0xF944, //CJK COMPATIBILITY IDEOGRAPH + 0xD2DA: 0xF945, //CJK COMPATIBILITY IDEOGRAPH + 0xD2DB: 0x81BF, //CJK UNIFIED IDEOGRAPH + 0xD2DC: 0x8FB2, //CJK UNIFIED IDEOGRAPH + 0xD2DD: 0x60F1, //CJK UNIFIED IDEOGRAPH + 0xD2DE: 0xF946, //CJK COMPATIBILITY IDEOGRAPH + 0xD2DF: 0xF947, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E0: 0x8166, //CJK UNIFIED IDEOGRAPH + 0xD2E1: 0xF948, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E2: 0xF949, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E3: 0x5C3F, //CJK UNIFIED IDEOGRAPH + 0xD2E4: 0xF94A, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E5: 0xF94B, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E6: 0xF94C, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E7: 0xF94D, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E8: 0xF94E, //CJK COMPATIBILITY IDEOGRAPH + 0xD2E9: 0xF94F, //CJK COMPATIBILITY IDEOGRAPH + 0xD2EA: 0xF950, //CJK COMPATIBILITY IDEOGRAPH + 0xD2EB: 0xF951, //CJK COMPATIBILITY IDEOGRAPH + 0xD2EC: 0x5AE9, //CJK UNIFIED IDEOGRAPH + 0xD2ED: 0x8A25, //CJK UNIFIED IDEOGRAPH + 0xD2EE: 0x677B, //CJK UNIFIED IDEOGRAPH + 0xD2EF: 0x7D10, //CJK UNIFIED IDEOGRAPH + 0xD2F0: 0xF952, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F1: 0xF953, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F2: 0xF954, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F3: 0xF955, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F4: 0xF956, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F5: 0xF957, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F6: 0x80FD, //CJK UNIFIED IDEOGRAPH + 0xD2F7: 0xF958, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F8: 0xF959, //CJK COMPATIBILITY IDEOGRAPH + 0xD2F9: 0x5C3C, //CJK UNIFIED IDEOGRAPH + 0xD2FA: 0x6CE5, //CJK UNIFIED IDEOGRAPH + 0xD2FB: 0x533F, //CJK UNIFIED IDEOGRAPH + 0xD2FC: 0x6EBA, //CJK UNIFIED IDEOGRAPH + 0xD2FD: 0x591A, //CJK UNIFIED IDEOGRAPH + 0xD2FE: 0x8336, //CJK UNIFIED IDEOGRAPH + 0xD3A1: 0x4E39, //CJK UNIFIED IDEOGRAPH + 0xD3A2: 0x4EB6, //CJK UNIFIED IDEOGRAPH + 0xD3A3: 0x4F46, //CJK UNIFIED IDEOGRAPH + 0xD3A4: 0x55AE, //CJK UNIFIED IDEOGRAPH + 0xD3A5: 0x5718, //CJK UNIFIED IDEOGRAPH + 0xD3A6: 0x58C7, //CJK UNIFIED IDEOGRAPH + 0xD3A7: 0x5F56, //CJK UNIFIED IDEOGRAPH + 0xD3A8: 0x65B7, //CJK UNIFIED IDEOGRAPH + 0xD3A9: 0x65E6, //CJK UNIFIED IDEOGRAPH + 0xD3AA: 0x6A80, //CJK UNIFIED IDEOGRAPH + 0xD3AB: 0x6BB5, //CJK UNIFIED IDEOGRAPH + 0xD3AC: 0x6E4D, //CJK UNIFIED IDEOGRAPH + 0xD3AD: 0x77ED, //CJK UNIFIED IDEOGRAPH + 0xD3AE: 0x7AEF, //CJK UNIFIED IDEOGRAPH + 0xD3AF: 0x7C1E, //CJK UNIFIED IDEOGRAPH + 0xD3B0: 0x7DDE, //CJK UNIFIED IDEOGRAPH + 0xD3B1: 0x86CB, //CJK UNIFIED IDEOGRAPH + 0xD3B2: 0x8892, //CJK UNIFIED IDEOGRAPH + 0xD3B3: 0x9132, //CJK UNIFIED IDEOGRAPH + 0xD3B4: 0x935B, //CJK UNIFIED IDEOGRAPH + 0xD3B5: 0x64BB, //CJK UNIFIED IDEOGRAPH + 0xD3B6: 0x6FBE, //CJK UNIFIED IDEOGRAPH + 0xD3B7: 0x737A, //CJK UNIFIED IDEOGRAPH + 0xD3B8: 0x75B8, //CJK UNIFIED IDEOGRAPH + 0xD3B9: 0x9054, //CJK UNIFIED IDEOGRAPH + 0xD3BA: 0x5556, //CJK UNIFIED IDEOGRAPH + 0xD3BB: 0x574D, //CJK UNIFIED IDEOGRAPH + 0xD3BC: 0x61BA, //CJK UNIFIED IDEOGRAPH + 0xD3BD: 0x64D4, //CJK UNIFIED IDEOGRAPH + 0xD3BE: 0x66C7, //CJK UNIFIED IDEOGRAPH + 0xD3BF: 0x6DE1, //CJK UNIFIED IDEOGRAPH + 0xD3C0: 0x6E5B, //CJK UNIFIED IDEOGRAPH + 0xD3C1: 0x6F6D, //CJK UNIFIED IDEOGRAPH + 0xD3C2: 0x6FB9, //CJK UNIFIED IDEOGRAPH + 0xD3C3: 0x75F0, //CJK UNIFIED IDEOGRAPH + 0xD3C4: 0x8043, //CJK UNIFIED IDEOGRAPH + 0xD3C5: 0x81BD, //CJK UNIFIED IDEOGRAPH + 0xD3C6: 0x8541, //CJK UNIFIED IDEOGRAPH + 0xD3C7: 0x8983, //CJK UNIFIED IDEOGRAPH + 0xD3C8: 0x8AC7, //CJK UNIFIED IDEOGRAPH + 0xD3C9: 0x8B5A, //CJK UNIFIED IDEOGRAPH + 0xD3CA: 0x931F, //CJK UNIFIED IDEOGRAPH + 0xD3CB: 0x6C93, //CJK UNIFIED IDEOGRAPH + 0xD3CC: 0x7553, //CJK UNIFIED IDEOGRAPH + 0xD3CD: 0x7B54, //CJK UNIFIED IDEOGRAPH + 0xD3CE: 0x8E0F, //CJK UNIFIED IDEOGRAPH + 0xD3CF: 0x905D, //CJK UNIFIED IDEOGRAPH + 0xD3D0: 0x5510, //CJK UNIFIED IDEOGRAPH + 0xD3D1: 0x5802, //CJK UNIFIED IDEOGRAPH + 0xD3D2: 0x5858, //CJK UNIFIED IDEOGRAPH + 0xD3D3: 0x5E62, //CJK UNIFIED IDEOGRAPH + 0xD3D4: 0x6207, //CJK UNIFIED IDEOGRAPH + 0xD3D5: 0x649E, //CJK UNIFIED IDEOGRAPH + 0xD3D6: 0x68E0, //CJK UNIFIED IDEOGRAPH + 0xD3D7: 0x7576, //CJK UNIFIED IDEOGRAPH + 0xD3D8: 0x7CD6, //CJK UNIFIED IDEOGRAPH + 0xD3D9: 0x87B3, //CJK UNIFIED IDEOGRAPH + 0xD3DA: 0x9EE8, //CJK UNIFIED IDEOGRAPH + 0xD3DB: 0x4EE3, //CJK UNIFIED IDEOGRAPH + 0xD3DC: 0x5788, //CJK UNIFIED IDEOGRAPH + 0xD3DD: 0x576E, //CJK UNIFIED IDEOGRAPH + 0xD3DE: 0x5927, //CJK UNIFIED IDEOGRAPH + 0xD3DF: 0x5C0D, //CJK UNIFIED IDEOGRAPH + 0xD3E0: 0x5CB1, //CJK UNIFIED IDEOGRAPH + 0xD3E1: 0x5E36, //CJK UNIFIED IDEOGRAPH + 0xD3E2: 0x5F85, //CJK UNIFIED IDEOGRAPH + 0xD3E3: 0x6234, //CJK UNIFIED IDEOGRAPH + 0xD3E4: 0x64E1, //CJK UNIFIED IDEOGRAPH + 0xD3E5: 0x73B3, //CJK UNIFIED IDEOGRAPH + 0xD3E6: 0x81FA, //CJK UNIFIED IDEOGRAPH + 0xD3E7: 0x888B, //CJK UNIFIED IDEOGRAPH + 0xD3E8: 0x8CB8, //CJK UNIFIED IDEOGRAPH + 0xD3E9: 0x968A, //CJK UNIFIED IDEOGRAPH + 0xD3EA: 0x9EDB, //CJK UNIFIED IDEOGRAPH + 0xD3EB: 0x5B85, //CJK UNIFIED IDEOGRAPH + 0xD3EC: 0x5FB7, //CJK UNIFIED IDEOGRAPH + 0xD3ED: 0x60B3, //CJK UNIFIED IDEOGRAPH + 0xD3EE: 0x5012, //CJK UNIFIED IDEOGRAPH + 0xD3EF: 0x5200, //CJK UNIFIED IDEOGRAPH + 0xD3F0: 0x5230, //CJK UNIFIED IDEOGRAPH + 0xD3F1: 0x5716, //CJK UNIFIED IDEOGRAPH + 0xD3F2: 0x5835, //CJK UNIFIED IDEOGRAPH + 0xD3F3: 0x5857, //CJK UNIFIED IDEOGRAPH + 0xD3F4: 0x5C0E, //CJK UNIFIED IDEOGRAPH + 0xD3F5: 0x5C60, //CJK UNIFIED IDEOGRAPH + 0xD3F6: 0x5CF6, //CJK UNIFIED IDEOGRAPH + 0xD3F7: 0x5D8B, //CJK UNIFIED IDEOGRAPH + 0xD3F8: 0x5EA6, //CJK UNIFIED IDEOGRAPH + 0xD3F9: 0x5F92, //CJK UNIFIED IDEOGRAPH + 0xD3FA: 0x60BC, //CJK UNIFIED IDEOGRAPH + 0xD3FB: 0x6311, //CJK UNIFIED IDEOGRAPH + 0xD3FC: 0x6389, //CJK UNIFIED IDEOGRAPH + 0xD3FD: 0x6417, //CJK UNIFIED IDEOGRAPH + 0xD3FE: 0x6843, //CJK UNIFIED IDEOGRAPH + 0xD4A1: 0x68F9, //CJK UNIFIED IDEOGRAPH + 0xD4A2: 0x6AC2, //CJK UNIFIED IDEOGRAPH + 0xD4A3: 0x6DD8, //CJK UNIFIED IDEOGRAPH + 0xD4A4: 0x6E21, //CJK UNIFIED IDEOGRAPH + 0xD4A5: 0x6ED4, //CJK UNIFIED IDEOGRAPH + 0xD4A6: 0x6FE4, //CJK UNIFIED IDEOGRAPH + 0xD4A7: 0x71FE, //CJK UNIFIED IDEOGRAPH + 0xD4A8: 0x76DC, //CJK UNIFIED IDEOGRAPH + 0xD4A9: 0x7779, //CJK UNIFIED IDEOGRAPH + 0xD4AA: 0x79B1, //CJK UNIFIED IDEOGRAPH + 0xD4AB: 0x7A3B, //CJK UNIFIED IDEOGRAPH + 0xD4AC: 0x8404, //CJK UNIFIED IDEOGRAPH + 0xD4AD: 0x89A9, //CJK UNIFIED IDEOGRAPH + 0xD4AE: 0x8CED, //CJK UNIFIED IDEOGRAPH + 0xD4AF: 0x8DF3, //CJK UNIFIED IDEOGRAPH + 0xD4B0: 0x8E48, //CJK UNIFIED IDEOGRAPH + 0xD4B1: 0x9003, //CJK UNIFIED IDEOGRAPH + 0xD4B2: 0x9014, //CJK UNIFIED IDEOGRAPH + 0xD4B3: 0x9053, //CJK UNIFIED IDEOGRAPH + 0xD4B4: 0x90FD, //CJK UNIFIED IDEOGRAPH + 0xD4B5: 0x934D, //CJK UNIFIED IDEOGRAPH + 0xD4B6: 0x9676, //CJK UNIFIED IDEOGRAPH + 0xD4B7: 0x97DC, //CJK UNIFIED IDEOGRAPH + 0xD4B8: 0x6BD2, //CJK UNIFIED IDEOGRAPH + 0xD4B9: 0x7006, //CJK UNIFIED IDEOGRAPH + 0xD4BA: 0x7258, //CJK UNIFIED IDEOGRAPH + 0xD4BB: 0x72A2, //CJK UNIFIED IDEOGRAPH + 0xD4BC: 0x7368, //CJK UNIFIED IDEOGRAPH + 0xD4BD: 0x7763, //CJK UNIFIED IDEOGRAPH + 0xD4BE: 0x79BF, //CJK UNIFIED IDEOGRAPH + 0xD4BF: 0x7BE4, //CJK UNIFIED IDEOGRAPH + 0xD4C0: 0x7E9B, //CJK UNIFIED IDEOGRAPH + 0xD4C1: 0x8B80, //CJK UNIFIED IDEOGRAPH + 0xD4C2: 0x58A9, //CJK UNIFIED IDEOGRAPH + 0xD4C3: 0x60C7, //CJK UNIFIED IDEOGRAPH + 0xD4C4: 0x6566, //CJK UNIFIED IDEOGRAPH + 0xD4C5: 0x65FD, //CJK UNIFIED IDEOGRAPH + 0xD4C6: 0x66BE, //CJK UNIFIED IDEOGRAPH + 0xD4C7: 0x6C8C, //CJK UNIFIED IDEOGRAPH + 0xD4C8: 0x711E, //CJK UNIFIED IDEOGRAPH + 0xD4C9: 0x71C9, //CJK UNIFIED IDEOGRAPH + 0xD4CA: 0x8C5A, //CJK UNIFIED IDEOGRAPH + 0xD4CB: 0x9813, //CJK UNIFIED IDEOGRAPH + 0xD4CC: 0x4E6D, //CJK UNIFIED IDEOGRAPH + 0xD4CD: 0x7A81, //CJK UNIFIED IDEOGRAPH + 0xD4CE: 0x4EDD, //CJK UNIFIED IDEOGRAPH + 0xD4CF: 0x51AC, //CJK UNIFIED IDEOGRAPH + 0xD4D0: 0x51CD, //CJK UNIFIED IDEOGRAPH + 0xD4D1: 0x52D5, //CJK UNIFIED IDEOGRAPH + 0xD4D2: 0x540C, //CJK UNIFIED IDEOGRAPH + 0xD4D3: 0x61A7, //CJK UNIFIED IDEOGRAPH + 0xD4D4: 0x6771, //CJK UNIFIED IDEOGRAPH + 0xD4D5: 0x6850, //CJK UNIFIED IDEOGRAPH + 0xD4D6: 0x68DF, //CJK UNIFIED IDEOGRAPH + 0xD4D7: 0x6D1E, //CJK UNIFIED IDEOGRAPH + 0xD4D8: 0x6F7C, //CJK UNIFIED IDEOGRAPH + 0xD4D9: 0x75BC, //CJK UNIFIED IDEOGRAPH + 0xD4DA: 0x77B3, //CJK UNIFIED IDEOGRAPH + 0xD4DB: 0x7AE5, //CJK UNIFIED IDEOGRAPH + 0xD4DC: 0x80F4, //CJK UNIFIED IDEOGRAPH + 0xD4DD: 0x8463, //CJK UNIFIED IDEOGRAPH + 0xD4DE: 0x9285, //CJK UNIFIED IDEOGRAPH + 0xD4DF: 0x515C, //CJK UNIFIED IDEOGRAPH + 0xD4E0: 0x6597, //CJK UNIFIED IDEOGRAPH + 0xD4E1: 0x675C, //CJK UNIFIED IDEOGRAPH + 0xD4E2: 0x6793, //CJK UNIFIED IDEOGRAPH + 0xD4E3: 0x75D8, //CJK UNIFIED IDEOGRAPH + 0xD4E4: 0x7AC7, //CJK UNIFIED IDEOGRAPH + 0xD4E5: 0x8373, //CJK UNIFIED IDEOGRAPH + 0xD4E6: 0xF95A, //CJK COMPATIBILITY IDEOGRAPH + 0xD4E7: 0x8C46, //CJK UNIFIED IDEOGRAPH + 0xD4E8: 0x9017, //CJK UNIFIED IDEOGRAPH + 0xD4E9: 0x982D, //CJK UNIFIED IDEOGRAPH + 0xD4EA: 0x5C6F, //CJK UNIFIED IDEOGRAPH + 0xD4EB: 0x81C0, //CJK UNIFIED IDEOGRAPH + 0xD4EC: 0x829A, //CJK UNIFIED IDEOGRAPH + 0xD4ED: 0x9041, //CJK UNIFIED IDEOGRAPH + 0xD4EE: 0x906F, //CJK UNIFIED IDEOGRAPH + 0xD4EF: 0x920D, //CJK UNIFIED IDEOGRAPH + 0xD4F0: 0x5F97, //CJK UNIFIED IDEOGRAPH + 0xD4F1: 0x5D9D, //CJK UNIFIED IDEOGRAPH + 0xD4F2: 0x6A59, //CJK UNIFIED IDEOGRAPH + 0xD4F3: 0x71C8, //CJK UNIFIED IDEOGRAPH + 0xD4F4: 0x767B, //CJK UNIFIED IDEOGRAPH + 0xD4F5: 0x7B49, //CJK UNIFIED IDEOGRAPH + 0xD4F6: 0x85E4, //CJK UNIFIED IDEOGRAPH + 0xD4F7: 0x8B04, //CJK UNIFIED IDEOGRAPH + 0xD4F8: 0x9127, //CJK UNIFIED IDEOGRAPH + 0xD4F9: 0x9A30, //CJK UNIFIED IDEOGRAPH + 0xD4FA: 0x5587, //CJK UNIFIED IDEOGRAPH + 0xD4FB: 0x61F6, //CJK UNIFIED IDEOGRAPH + 0xD4FC: 0xF95B, //CJK COMPATIBILITY IDEOGRAPH + 0xD4FD: 0x7669, //CJK UNIFIED IDEOGRAPH + 0xD4FE: 0x7F85, //CJK UNIFIED IDEOGRAPH + 0xD5A1: 0x863F, //CJK UNIFIED IDEOGRAPH + 0xD5A2: 0x87BA, //CJK UNIFIED IDEOGRAPH + 0xD5A3: 0x88F8, //CJK UNIFIED IDEOGRAPH + 0xD5A4: 0x908F, //CJK UNIFIED IDEOGRAPH + 0xD5A5: 0xF95C, //CJK COMPATIBILITY IDEOGRAPH + 0xD5A6: 0x6D1B, //CJK UNIFIED IDEOGRAPH + 0xD5A7: 0x70D9, //CJK UNIFIED IDEOGRAPH + 0xD5A8: 0x73DE, //CJK UNIFIED IDEOGRAPH + 0xD5A9: 0x7D61, //CJK UNIFIED IDEOGRAPH + 0xD5AA: 0x843D, //CJK UNIFIED IDEOGRAPH + 0xD5AB: 0xF95D, //CJK COMPATIBILITY IDEOGRAPH + 0xD5AC: 0x916A, //CJK UNIFIED IDEOGRAPH + 0xD5AD: 0x99F1, //CJK UNIFIED IDEOGRAPH + 0xD5AE: 0xF95E, //CJK COMPATIBILITY IDEOGRAPH + 0xD5AF: 0x4E82, //CJK UNIFIED IDEOGRAPH + 0xD5B0: 0x5375, //CJK UNIFIED IDEOGRAPH + 0xD5B1: 0x6B04, //CJK UNIFIED IDEOGRAPH + 0xD5B2: 0x6B12, //CJK UNIFIED IDEOGRAPH + 0xD5B3: 0x703E, //CJK UNIFIED IDEOGRAPH + 0xD5B4: 0x721B, //CJK UNIFIED IDEOGRAPH + 0xD5B5: 0x862D, //CJK UNIFIED IDEOGRAPH + 0xD5B6: 0x9E1E, //CJK UNIFIED IDEOGRAPH + 0xD5B7: 0x524C, //CJK UNIFIED IDEOGRAPH + 0xD5B8: 0x8FA3, //CJK UNIFIED IDEOGRAPH + 0xD5B9: 0x5D50, //CJK UNIFIED IDEOGRAPH + 0xD5BA: 0x64E5, //CJK UNIFIED IDEOGRAPH + 0xD5BB: 0x652C, //CJK UNIFIED IDEOGRAPH + 0xD5BC: 0x6B16, //CJK UNIFIED IDEOGRAPH + 0xD5BD: 0x6FEB, //CJK UNIFIED IDEOGRAPH + 0xD5BE: 0x7C43, //CJK UNIFIED IDEOGRAPH + 0xD5BF: 0x7E9C, //CJK UNIFIED IDEOGRAPH + 0xD5C0: 0x85CD, //CJK UNIFIED IDEOGRAPH + 0xD5C1: 0x8964, //CJK UNIFIED IDEOGRAPH + 0xD5C2: 0x89BD, //CJK UNIFIED IDEOGRAPH + 0xD5C3: 0x62C9, //CJK UNIFIED IDEOGRAPH + 0xD5C4: 0x81D8, //CJK UNIFIED IDEOGRAPH + 0xD5C5: 0x881F, //CJK UNIFIED IDEOGRAPH + 0xD5C6: 0x5ECA, //CJK UNIFIED IDEOGRAPH + 0xD5C7: 0x6717, //CJK UNIFIED IDEOGRAPH + 0xD5C8: 0x6D6A, //CJK UNIFIED IDEOGRAPH + 0xD5C9: 0x72FC, //CJK UNIFIED IDEOGRAPH + 0xD5CA: 0x7405, //CJK UNIFIED IDEOGRAPH + 0xD5CB: 0x746F, //CJK UNIFIED IDEOGRAPH + 0xD5CC: 0x8782, //CJK UNIFIED IDEOGRAPH + 0xD5CD: 0x90DE, //CJK UNIFIED IDEOGRAPH + 0xD5CE: 0x4F86, //CJK UNIFIED IDEOGRAPH + 0xD5CF: 0x5D0D, //CJK UNIFIED IDEOGRAPH + 0xD5D0: 0x5FA0, //CJK UNIFIED IDEOGRAPH + 0xD5D1: 0x840A, //CJK UNIFIED IDEOGRAPH + 0xD5D2: 0x51B7, //CJK UNIFIED IDEOGRAPH + 0xD5D3: 0x63A0, //CJK UNIFIED IDEOGRAPH + 0xD5D4: 0x7565, //CJK UNIFIED IDEOGRAPH + 0xD5D5: 0x4EAE, //CJK UNIFIED IDEOGRAPH + 0xD5D6: 0x5006, //CJK UNIFIED IDEOGRAPH + 0xD5D7: 0x5169, //CJK UNIFIED IDEOGRAPH + 0xD5D8: 0x51C9, //CJK UNIFIED IDEOGRAPH + 0xD5D9: 0x6881, //CJK UNIFIED IDEOGRAPH + 0xD5DA: 0x6A11, //CJK UNIFIED IDEOGRAPH + 0xD5DB: 0x7CAE, //CJK UNIFIED IDEOGRAPH + 0xD5DC: 0x7CB1, //CJK UNIFIED IDEOGRAPH + 0xD5DD: 0x7CE7, //CJK UNIFIED IDEOGRAPH + 0xD5DE: 0x826F, //CJK UNIFIED IDEOGRAPH + 0xD5DF: 0x8AD2, //CJK UNIFIED IDEOGRAPH + 0xD5E0: 0x8F1B, //CJK UNIFIED IDEOGRAPH + 0xD5E1: 0x91CF, //CJK UNIFIED IDEOGRAPH + 0xD5E2: 0x4FB6, //CJK UNIFIED IDEOGRAPH + 0xD5E3: 0x5137, //CJK UNIFIED IDEOGRAPH + 0xD5E4: 0x52F5, //CJK UNIFIED IDEOGRAPH + 0xD5E5: 0x5442, //CJK UNIFIED IDEOGRAPH + 0xD5E6: 0x5EEC, //CJK UNIFIED IDEOGRAPH + 0xD5E7: 0x616E, //CJK UNIFIED IDEOGRAPH + 0xD5E8: 0x623E, //CJK UNIFIED IDEOGRAPH + 0xD5E9: 0x65C5, //CJK UNIFIED IDEOGRAPH + 0xD5EA: 0x6ADA, //CJK UNIFIED IDEOGRAPH + 0xD5EB: 0x6FFE, //CJK UNIFIED IDEOGRAPH + 0xD5EC: 0x792A, //CJK UNIFIED IDEOGRAPH + 0xD5ED: 0x85DC, //CJK UNIFIED IDEOGRAPH + 0xD5EE: 0x8823, //CJK UNIFIED IDEOGRAPH + 0xD5EF: 0x95AD, //CJK UNIFIED IDEOGRAPH + 0xD5F0: 0x9A62, //CJK UNIFIED IDEOGRAPH + 0xD5F1: 0x9A6A, //CJK UNIFIED IDEOGRAPH + 0xD5F2: 0x9E97, //CJK UNIFIED IDEOGRAPH + 0xD5F3: 0x9ECE, //CJK UNIFIED IDEOGRAPH + 0xD5F4: 0x529B, //CJK UNIFIED IDEOGRAPH + 0xD5F5: 0x66C6, //CJK UNIFIED IDEOGRAPH + 0xD5F6: 0x6B77, //CJK UNIFIED IDEOGRAPH + 0xD5F7: 0x701D, //CJK UNIFIED IDEOGRAPH + 0xD5F8: 0x792B, //CJK UNIFIED IDEOGRAPH + 0xD5F9: 0x8F62, //CJK UNIFIED IDEOGRAPH + 0xD5FA: 0x9742, //CJK UNIFIED IDEOGRAPH + 0xD5FB: 0x6190, //CJK UNIFIED IDEOGRAPH + 0xD5FC: 0x6200, //CJK UNIFIED IDEOGRAPH + 0xD5FD: 0x6523, //CJK UNIFIED IDEOGRAPH + 0xD5FE: 0x6F23, //CJK UNIFIED IDEOGRAPH + 0xD6A1: 0x7149, //CJK UNIFIED IDEOGRAPH + 0xD6A2: 0x7489, //CJK UNIFIED IDEOGRAPH + 0xD6A3: 0x7DF4, //CJK UNIFIED IDEOGRAPH + 0xD6A4: 0x806F, //CJK UNIFIED IDEOGRAPH + 0xD6A5: 0x84EE, //CJK UNIFIED IDEOGRAPH + 0xD6A6: 0x8F26, //CJK UNIFIED IDEOGRAPH + 0xD6A7: 0x9023, //CJK UNIFIED IDEOGRAPH + 0xD6A8: 0x934A, //CJK UNIFIED IDEOGRAPH + 0xD6A9: 0x51BD, //CJK UNIFIED IDEOGRAPH + 0xD6AA: 0x5217, //CJK UNIFIED IDEOGRAPH + 0xD6AB: 0x52A3, //CJK UNIFIED IDEOGRAPH + 0xD6AC: 0x6D0C, //CJK UNIFIED IDEOGRAPH + 0xD6AD: 0x70C8, //CJK UNIFIED IDEOGRAPH + 0xD6AE: 0x88C2, //CJK UNIFIED IDEOGRAPH + 0xD6AF: 0x5EC9, //CJK UNIFIED IDEOGRAPH + 0xD6B0: 0x6582, //CJK UNIFIED IDEOGRAPH + 0xD6B1: 0x6BAE, //CJK UNIFIED IDEOGRAPH + 0xD6B2: 0x6FC2, //CJK UNIFIED IDEOGRAPH + 0xD6B3: 0x7C3E, //CJK UNIFIED IDEOGRAPH + 0xD6B4: 0x7375, //CJK UNIFIED IDEOGRAPH + 0xD6B5: 0x4EE4, //CJK UNIFIED IDEOGRAPH + 0xD6B6: 0x4F36, //CJK UNIFIED IDEOGRAPH + 0xD6B7: 0x56F9, //CJK UNIFIED IDEOGRAPH + 0xD6B8: 0xF95F, //CJK COMPATIBILITY IDEOGRAPH + 0xD6B9: 0x5CBA, //CJK UNIFIED IDEOGRAPH + 0xD6BA: 0x5DBA, //CJK UNIFIED IDEOGRAPH + 0xD6BB: 0x601C, //CJK UNIFIED IDEOGRAPH + 0xD6BC: 0x73B2, //CJK UNIFIED IDEOGRAPH + 0xD6BD: 0x7B2D, //CJK UNIFIED IDEOGRAPH + 0xD6BE: 0x7F9A, //CJK UNIFIED IDEOGRAPH + 0xD6BF: 0x7FCE, //CJK UNIFIED IDEOGRAPH + 0xD6C0: 0x8046, //CJK UNIFIED IDEOGRAPH + 0xD6C1: 0x901E, //CJK UNIFIED IDEOGRAPH + 0xD6C2: 0x9234, //CJK UNIFIED IDEOGRAPH + 0xD6C3: 0x96F6, //CJK UNIFIED IDEOGRAPH + 0xD6C4: 0x9748, //CJK UNIFIED IDEOGRAPH + 0xD6C5: 0x9818, //CJK UNIFIED IDEOGRAPH + 0xD6C6: 0x9F61, //CJK UNIFIED IDEOGRAPH + 0xD6C7: 0x4F8B, //CJK UNIFIED IDEOGRAPH + 0xD6C8: 0x6FA7, //CJK UNIFIED IDEOGRAPH + 0xD6C9: 0x79AE, //CJK UNIFIED IDEOGRAPH + 0xD6CA: 0x91B4, //CJK UNIFIED IDEOGRAPH + 0xD6CB: 0x96B7, //CJK UNIFIED IDEOGRAPH + 0xD6CC: 0x52DE, //CJK UNIFIED IDEOGRAPH + 0xD6CD: 0xF960, //CJK COMPATIBILITY IDEOGRAPH + 0xD6CE: 0x6488, //CJK UNIFIED IDEOGRAPH + 0xD6CF: 0x64C4, //CJK UNIFIED IDEOGRAPH + 0xD6D0: 0x6AD3, //CJK UNIFIED IDEOGRAPH + 0xD6D1: 0x6F5E, //CJK UNIFIED IDEOGRAPH + 0xD6D2: 0x7018, //CJK UNIFIED IDEOGRAPH + 0xD6D3: 0x7210, //CJK UNIFIED IDEOGRAPH + 0xD6D4: 0x76E7, //CJK UNIFIED IDEOGRAPH + 0xD6D5: 0x8001, //CJK UNIFIED IDEOGRAPH + 0xD6D6: 0x8606, //CJK UNIFIED IDEOGRAPH + 0xD6D7: 0x865C, //CJK UNIFIED IDEOGRAPH + 0xD6D8: 0x8DEF, //CJK UNIFIED IDEOGRAPH + 0xD6D9: 0x8F05, //CJK UNIFIED IDEOGRAPH + 0xD6DA: 0x9732, //CJK UNIFIED IDEOGRAPH + 0xD6DB: 0x9B6F, //CJK UNIFIED IDEOGRAPH + 0xD6DC: 0x9DFA, //CJK UNIFIED IDEOGRAPH + 0xD6DD: 0x9E75, //CJK UNIFIED IDEOGRAPH + 0xD6DE: 0x788C, //CJK UNIFIED IDEOGRAPH + 0xD6DF: 0x797F, //CJK UNIFIED IDEOGRAPH + 0xD6E0: 0x7DA0, //CJK UNIFIED IDEOGRAPH + 0xD6E1: 0x83C9, //CJK UNIFIED IDEOGRAPH + 0xD6E2: 0x9304, //CJK UNIFIED IDEOGRAPH + 0xD6E3: 0x9E7F, //CJK UNIFIED IDEOGRAPH + 0xD6E4: 0x9E93, //CJK UNIFIED IDEOGRAPH + 0xD6E5: 0x8AD6, //CJK UNIFIED IDEOGRAPH + 0xD6E6: 0x58DF, //CJK UNIFIED IDEOGRAPH + 0xD6E7: 0x5F04, //CJK UNIFIED IDEOGRAPH + 0xD6E8: 0x6727, //CJK UNIFIED IDEOGRAPH + 0xD6E9: 0x7027, //CJK UNIFIED IDEOGRAPH + 0xD6EA: 0x74CF, //CJK UNIFIED IDEOGRAPH + 0xD6EB: 0x7C60, //CJK UNIFIED IDEOGRAPH + 0xD6EC: 0x807E, //CJK UNIFIED IDEOGRAPH + 0xD6ED: 0x5121, //CJK UNIFIED IDEOGRAPH + 0xD6EE: 0x7028, //CJK UNIFIED IDEOGRAPH + 0xD6EF: 0x7262, //CJK UNIFIED IDEOGRAPH + 0xD6F0: 0x78CA, //CJK UNIFIED IDEOGRAPH + 0xD6F1: 0x8CC2, //CJK UNIFIED IDEOGRAPH + 0xD6F2: 0x8CDA, //CJK UNIFIED IDEOGRAPH + 0xD6F3: 0x8CF4, //CJK UNIFIED IDEOGRAPH + 0xD6F4: 0x96F7, //CJK UNIFIED IDEOGRAPH + 0xD6F5: 0x4E86, //CJK UNIFIED IDEOGRAPH + 0xD6F6: 0x50DA, //CJK UNIFIED IDEOGRAPH + 0xD6F7: 0x5BEE, //CJK UNIFIED IDEOGRAPH + 0xD6F8: 0x5ED6, //CJK UNIFIED IDEOGRAPH + 0xD6F9: 0x6599, //CJK UNIFIED IDEOGRAPH + 0xD6FA: 0x71CE, //CJK UNIFIED IDEOGRAPH + 0xD6FB: 0x7642, //CJK UNIFIED IDEOGRAPH + 0xD6FC: 0x77AD, //CJK UNIFIED IDEOGRAPH + 0xD6FD: 0x804A, //CJK UNIFIED IDEOGRAPH + 0xD6FE: 0x84FC, //CJK UNIFIED IDEOGRAPH + 0xD7A1: 0x907C, //CJK UNIFIED IDEOGRAPH + 0xD7A2: 0x9B27, //CJK UNIFIED IDEOGRAPH + 0xD7A3: 0x9F8D, //CJK UNIFIED IDEOGRAPH + 0xD7A4: 0x58D8, //CJK UNIFIED IDEOGRAPH + 0xD7A5: 0x5A41, //CJK UNIFIED IDEOGRAPH + 0xD7A6: 0x5C62, //CJK UNIFIED IDEOGRAPH + 0xD7A7: 0x6A13, //CJK UNIFIED IDEOGRAPH + 0xD7A8: 0x6DDA, //CJK UNIFIED IDEOGRAPH + 0xD7A9: 0x6F0F, //CJK UNIFIED IDEOGRAPH + 0xD7AA: 0x763B, //CJK UNIFIED IDEOGRAPH + 0xD7AB: 0x7D2F, //CJK UNIFIED IDEOGRAPH + 0xD7AC: 0x7E37, //CJK UNIFIED IDEOGRAPH + 0xD7AD: 0x851E, //CJK UNIFIED IDEOGRAPH + 0xD7AE: 0x8938, //CJK UNIFIED IDEOGRAPH + 0xD7AF: 0x93E4, //CJK UNIFIED IDEOGRAPH + 0xD7B0: 0x964B, //CJK UNIFIED IDEOGRAPH + 0xD7B1: 0x5289, //CJK UNIFIED IDEOGRAPH + 0xD7B2: 0x65D2, //CJK UNIFIED IDEOGRAPH + 0xD7B3: 0x67F3, //CJK UNIFIED IDEOGRAPH + 0xD7B4: 0x69B4, //CJK UNIFIED IDEOGRAPH + 0xD7B5: 0x6D41, //CJK UNIFIED IDEOGRAPH + 0xD7B6: 0x6E9C, //CJK UNIFIED IDEOGRAPH + 0xD7B7: 0x700F, //CJK UNIFIED IDEOGRAPH + 0xD7B8: 0x7409, //CJK UNIFIED IDEOGRAPH + 0xD7B9: 0x7460, //CJK UNIFIED IDEOGRAPH + 0xD7BA: 0x7559, //CJK UNIFIED IDEOGRAPH + 0xD7BB: 0x7624, //CJK UNIFIED IDEOGRAPH + 0xD7BC: 0x786B, //CJK UNIFIED IDEOGRAPH + 0xD7BD: 0x8B2C, //CJK UNIFIED IDEOGRAPH + 0xD7BE: 0x985E, //CJK UNIFIED IDEOGRAPH + 0xD7BF: 0x516D, //CJK UNIFIED IDEOGRAPH + 0xD7C0: 0x622E, //CJK UNIFIED IDEOGRAPH + 0xD7C1: 0x9678, //CJK UNIFIED IDEOGRAPH + 0xD7C2: 0x4F96, //CJK UNIFIED IDEOGRAPH + 0xD7C3: 0x502B, //CJK UNIFIED IDEOGRAPH + 0xD7C4: 0x5D19, //CJK UNIFIED IDEOGRAPH + 0xD7C5: 0x6DEA, //CJK UNIFIED IDEOGRAPH + 0xD7C6: 0x7DB8, //CJK UNIFIED IDEOGRAPH + 0xD7C7: 0x8F2A, //CJK UNIFIED IDEOGRAPH + 0xD7C8: 0x5F8B, //CJK UNIFIED IDEOGRAPH + 0xD7C9: 0x6144, //CJK UNIFIED IDEOGRAPH + 0xD7CA: 0x6817, //CJK UNIFIED IDEOGRAPH + 0xD7CB: 0xF961, //CJK COMPATIBILITY IDEOGRAPH + 0xD7CC: 0x9686, //CJK UNIFIED IDEOGRAPH + 0xD7CD: 0x52D2, //CJK UNIFIED IDEOGRAPH + 0xD7CE: 0x808B, //CJK UNIFIED IDEOGRAPH + 0xD7CF: 0x51DC, //CJK UNIFIED IDEOGRAPH + 0xD7D0: 0x51CC, //CJK UNIFIED IDEOGRAPH + 0xD7D1: 0x695E, //CJK UNIFIED IDEOGRAPH + 0xD7D2: 0x7A1C, //CJK UNIFIED IDEOGRAPH + 0xD7D3: 0x7DBE, //CJK UNIFIED IDEOGRAPH + 0xD7D4: 0x83F1, //CJK UNIFIED IDEOGRAPH + 0xD7D5: 0x9675, //CJK UNIFIED IDEOGRAPH + 0xD7D6: 0x4FDA, //CJK UNIFIED IDEOGRAPH + 0xD7D7: 0x5229, //CJK UNIFIED IDEOGRAPH + 0xD7D8: 0x5398, //CJK UNIFIED IDEOGRAPH + 0xD7D9: 0x540F, //CJK UNIFIED IDEOGRAPH + 0xD7DA: 0x550E, //CJK UNIFIED IDEOGRAPH + 0xD7DB: 0x5C65, //CJK UNIFIED IDEOGRAPH + 0xD7DC: 0x60A7, //CJK UNIFIED IDEOGRAPH + 0xD7DD: 0x674E, //CJK UNIFIED IDEOGRAPH + 0xD7DE: 0x68A8, //CJK UNIFIED IDEOGRAPH + 0xD7DF: 0x6D6C, //CJK UNIFIED IDEOGRAPH + 0xD7E0: 0x7281, //CJK UNIFIED IDEOGRAPH + 0xD7E1: 0x72F8, //CJK UNIFIED IDEOGRAPH + 0xD7E2: 0x7406, //CJK UNIFIED IDEOGRAPH + 0xD7E3: 0x7483, //CJK UNIFIED IDEOGRAPH + 0xD7E4: 0xF962, //CJK COMPATIBILITY IDEOGRAPH + 0xD7E5: 0x75E2, //CJK UNIFIED IDEOGRAPH + 0xD7E6: 0x7C6C, //CJK UNIFIED IDEOGRAPH + 0xD7E7: 0x7F79, //CJK UNIFIED IDEOGRAPH + 0xD7E8: 0x7FB8, //CJK UNIFIED IDEOGRAPH + 0xD7E9: 0x8389, //CJK UNIFIED IDEOGRAPH + 0xD7EA: 0x88CF, //CJK UNIFIED IDEOGRAPH + 0xD7EB: 0x88E1, //CJK UNIFIED IDEOGRAPH + 0xD7EC: 0x91CC, //CJK UNIFIED IDEOGRAPH + 0xD7ED: 0x91D0, //CJK UNIFIED IDEOGRAPH + 0xD7EE: 0x96E2, //CJK UNIFIED IDEOGRAPH + 0xD7EF: 0x9BC9, //CJK UNIFIED IDEOGRAPH + 0xD7F0: 0x541D, //CJK UNIFIED IDEOGRAPH + 0xD7F1: 0x6F7E, //CJK UNIFIED IDEOGRAPH + 0xD7F2: 0x71D0, //CJK UNIFIED IDEOGRAPH + 0xD7F3: 0x7498, //CJK UNIFIED IDEOGRAPH + 0xD7F4: 0x85FA, //CJK UNIFIED IDEOGRAPH + 0xD7F5: 0x8EAA, //CJK UNIFIED IDEOGRAPH + 0xD7F6: 0x96A3, //CJK UNIFIED IDEOGRAPH + 0xD7F7: 0x9C57, //CJK UNIFIED IDEOGRAPH + 0xD7F8: 0x9E9F, //CJK UNIFIED IDEOGRAPH + 0xD7F9: 0x6797, //CJK UNIFIED IDEOGRAPH + 0xD7FA: 0x6DCB, //CJK UNIFIED IDEOGRAPH + 0xD7FB: 0x7433, //CJK UNIFIED IDEOGRAPH + 0xD7FC: 0x81E8, //CJK UNIFIED IDEOGRAPH + 0xD7FD: 0x9716, //CJK UNIFIED IDEOGRAPH + 0xD7FE: 0x782C, //CJK UNIFIED IDEOGRAPH + 0xD8A1: 0x7ACB, //CJK UNIFIED IDEOGRAPH + 0xD8A2: 0x7B20, //CJK UNIFIED IDEOGRAPH + 0xD8A3: 0x7C92, //CJK UNIFIED IDEOGRAPH + 0xD8A4: 0x6469, //CJK UNIFIED IDEOGRAPH + 0xD8A5: 0x746A, //CJK UNIFIED IDEOGRAPH + 0xD8A6: 0x75F2, //CJK UNIFIED IDEOGRAPH + 0xD8A7: 0x78BC, //CJK UNIFIED IDEOGRAPH + 0xD8A8: 0x78E8, //CJK UNIFIED IDEOGRAPH + 0xD8A9: 0x99AC, //CJK UNIFIED IDEOGRAPH + 0xD8AA: 0x9B54, //CJK UNIFIED IDEOGRAPH + 0xD8AB: 0x9EBB, //CJK UNIFIED IDEOGRAPH + 0xD8AC: 0x5BDE, //CJK UNIFIED IDEOGRAPH + 0xD8AD: 0x5E55, //CJK UNIFIED IDEOGRAPH + 0xD8AE: 0x6F20, //CJK UNIFIED IDEOGRAPH + 0xD8AF: 0x819C, //CJK UNIFIED IDEOGRAPH + 0xD8B0: 0x83AB, //CJK UNIFIED IDEOGRAPH + 0xD8B1: 0x9088, //CJK UNIFIED IDEOGRAPH + 0xD8B2: 0x4E07, //CJK UNIFIED IDEOGRAPH + 0xD8B3: 0x534D, //CJK UNIFIED IDEOGRAPH + 0xD8B4: 0x5A29, //CJK UNIFIED IDEOGRAPH + 0xD8B5: 0x5DD2, //CJK UNIFIED IDEOGRAPH + 0xD8B6: 0x5F4E, //CJK UNIFIED IDEOGRAPH + 0xD8B7: 0x6162, //CJK UNIFIED IDEOGRAPH + 0xD8B8: 0x633D, //CJK UNIFIED IDEOGRAPH + 0xD8B9: 0x6669, //CJK UNIFIED IDEOGRAPH + 0xD8BA: 0x66FC, //CJK UNIFIED IDEOGRAPH + 0xD8BB: 0x6EFF, //CJK UNIFIED IDEOGRAPH + 0xD8BC: 0x6F2B, //CJK UNIFIED IDEOGRAPH + 0xD8BD: 0x7063, //CJK UNIFIED IDEOGRAPH + 0xD8BE: 0x779E, //CJK UNIFIED IDEOGRAPH + 0xD8BF: 0x842C, //CJK UNIFIED IDEOGRAPH + 0xD8C0: 0x8513, //CJK UNIFIED IDEOGRAPH + 0xD8C1: 0x883B, //CJK UNIFIED IDEOGRAPH + 0xD8C2: 0x8F13, //CJK UNIFIED IDEOGRAPH + 0xD8C3: 0x9945, //CJK UNIFIED IDEOGRAPH + 0xD8C4: 0x9C3B, //CJK UNIFIED IDEOGRAPH + 0xD8C5: 0x551C, //CJK UNIFIED IDEOGRAPH + 0xD8C6: 0x62B9, //CJK UNIFIED IDEOGRAPH + 0xD8C7: 0x672B, //CJK UNIFIED IDEOGRAPH + 0xD8C8: 0x6CAB, //CJK UNIFIED IDEOGRAPH + 0xD8C9: 0x8309, //CJK UNIFIED IDEOGRAPH + 0xD8CA: 0x896A, //CJK UNIFIED IDEOGRAPH + 0xD8CB: 0x977A, //CJK UNIFIED IDEOGRAPH + 0xD8CC: 0x4EA1, //CJK UNIFIED IDEOGRAPH + 0xD8CD: 0x5984, //CJK UNIFIED IDEOGRAPH + 0xD8CE: 0x5FD8, //CJK UNIFIED IDEOGRAPH + 0xD8CF: 0x5FD9, //CJK UNIFIED IDEOGRAPH + 0xD8D0: 0x671B, //CJK UNIFIED IDEOGRAPH + 0xD8D1: 0x7DB2, //CJK UNIFIED IDEOGRAPH + 0xD8D2: 0x7F54, //CJK UNIFIED IDEOGRAPH + 0xD8D3: 0x8292, //CJK UNIFIED IDEOGRAPH + 0xD8D4: 0x832B, //CJK UNIFIED IDEOGRAPH + 0xD8D5: 0x83BD, //CJK UNIFIED IDEOGRAPH + 0xD8D6: 0x8F1E, //CJK UNIFIED IDEOGRAPH + 0xD8D7: 0x9099, //CJK UNIFIED IDEOGRAPH + 0xD8D8: 0x57CB, //CJK UNIFIED IDEOGRAPH + 0xD8D9: 0x59B9, //CJK UNIFIED IDEOGRAPH + 0xD8DA: 0x5A92, //CJK UNIFIED IDEOGRAPH + 0xD8DB: 0x5BD0, //CJK UNIFIED IDEOGRAPH + 0xD8DC: 0x6627, //CJK UNIFIED IDEOGRAPH + 0xD8DD: 0x679A, //CJK UNIFIED IDEOGRAPH + 0xD8DE: 0x6885, //CJK UNIFIED IDEOGRAPH + 0xD8DF: 0x6BCF, //CJK UNIFIED IDEOGRAPH + 0xD8E0: 0x7164, //CJK UNIFIED IDEOGRAPH + 0xD8E1: 0x7F75, //CJK UNIFIED IDEOGRAPH + 0xD8E2: 0x8CB7, //CJK UNIFIED IDEOGRAPH + 0xD8E3: 0x8CE3, //CJK UNIFIED IDEOGRAPH + 0xD8E4: 0x9081, //CJK UNIFIED IDEOGRAPH + 0xD8E5: 0x9B45, //CJK UNIFIED IDEOGRAPH + 0xD8E6: 0x8108, //CJK UNIFIED IDEOGRAPH + 0xD8E7: 0x8C8A, //CJK UNIFIED IDEOGRAPH + 0xD8E8: 0x964C, //CJK UNIFIED IDEOGRAPH + 0xD8E9: 0x9A40, //CJK UNIFIED IDEOGRAPH + 0xD8EA: 0x9EA5, //CJK UNIFIED IDEOGRAPH + 0xD8EB: 0x5B5F, //CJK UNIFIED IDEOGRAPH + 0xD8EC: 0x6C13, //CJK UNIFIED IDEOGRAPH + 0xD8ED: 0x731B, //CJK UNIFIED IDEOGRAPH + 0xD8EE: 0x76F2, //CJK UNIFIED IDEOGRAPH + 0xD8EF: 0x76DF, //CJK UNIFIED IDEOGRAPH + 0xD8F0: 0x840C, //CJK UNIFIED IDEOGRAPH + 0xD8F1: 0x51AA, //CJK UNIFIED IDEOGRAPH + 0xD8F2: 0x8993, //CJK UNIFIED IDEOGRAPH + 0xD8F3: 0x514D, //CJK UNIFIED IDEOGRAPH + 0xD8F4: 0x5195, //CJK UNIFIED IDEOGRAPH + 0xD8F5: 0x52C9, //CJK UNIFIED IDEOGRAPH + 0xD8F6: 0x68C9, //CJK UNIFIED IDEOGRAPH + 0xD8F7: 0x6C94, //CJK UNIFIED IDEOGRAPH + 0xD8F8: 0x7704, //CJK UNIFIED IDEOGRAPH + 0xD8F9: 0x7720, //CJK UNIFIED IDEOGRAPH + 0xD8FA: 0x7DBF, //CJK UNIFIED IDEOGRAPH + 0xD8FB: 0x7DEC, //CJK UNIFIED IDEOGRAPH + 0xD8FC: 0x9762, //CJK UNIFIED IDEOGRAPH + 0xD8FD: 0x9EB5, //CJK UNIFIED IDEOGRAPH + 0xD8FE: 0x6EC5, //CJK UNIFIED IDEOGRAPH + 0xD9A1: 0x8511, //CJK UNIFIED IDEOGRAPH + 0xD9A2: 0x51A5, //CJK UNIFIED IDEOGRAPH + 0xD9A3: 0x540D, //CJK UNIFIED IDEOGRAPH + 0xD9A4: 0x547D, //CJK UNIFIED IDEOGRAPH + 0xD9A5: 0x660E, //CJK UNIFIED IDEOGRAPH + 0xD9A6: 0x669D, //CJK UNIFIED IDEOGRAPH + 0xD9A7: 0x6927, //CJK UNIFIED IDEOGRAPH + 0xD9A8: 0x6E9F, //CJK UNIFIED IDEOGRAPH + 0xD9A9: 0x76BF, //CJK UNIFIED IDEOGRAPH + 0xD9AA: 0x7791, //CJK UNIFIED IDEOGRAPH + 0xD9AB: 0x8317, //CJK UNIFIED IDEOGRAPH + 0xD9AC: 0x84C2, //CJK UNIFIED IDEOGRAPH + 0xD9AD: 0x879F, //CJK UNIFIED IDEOGRAPH + 0xD9AE: 0x9169, //CJK UNIFIED IDEOGRAPH + 0xD9AF: 0x9298, //CJK UNIFIED IDEOGRAPH + 0xD9B0: 0x9CF4, //CJK UNIFIED IDEOGRAPH + 0xD9B1: 0x8882, //CJK UNIFIED IDEOGRAPH + 0xD9B2: 0x4FAE, //CJK UNIFIED IDEOGRAPH + 0xD9B3: 0x5192, //CJK UNIFIED IDEOGRAPH + 0xD9B4: 0x52DF, //CJK UNIFIED IDEOGRAPH + 0xD9B5: 0x59C6, //CJK UNIFIED IDEOGRAPH + 0xD9B6: 0x5E3D, //CJK UNIFIED IDEOGRAPH + 0xD9B7: 0x6155, //CJK UNIFIED IDEOGRAPH + 0xD9B8: 0x6478, //CJK UNIFIED IDEOGRAPH + 0xD9B9: 0x6479, //CJK UNIFIED IDEOGRAPH + 0xD9BA: 0x66AE, //CJK UNIFIED IDEOGRAPH + 0xD9BB: 0x67D0, //CJK UNIFIED IDEOGRAPH + 0xD9BC: 0x6A21, //CJK UNIFIED IDEOGRAPH + 0xD9BD: 0x6BCD, //CJK UNIFIED IDEOGRAPH + 0xD9BE: 0x6BDB, //CJK UNIFIED IDEOGRAPH + 0xD9BF: 0x725F, //CJK UNIFIED IDEOGRAPH + 0xD9C0: 0x7261, //CJK UNIFIED IDEOGRAPH + 0xD9C1: 0x7441, //CJK UNIFIED IDEOGRAPH + 0xD9C2: 0x7738, //CJK UNIFIED IDEOGRAPH + 0xD9C3: 0x77DB, //CJK UNIFIED IDEOGRAPH + 0xD9C4: 0x8017, //CJK UNIFIED IDEOGRAPH + 0xD9C5: 0x82BC, //CJK UNIFIED IDEOGRAPH + 0xD9C6: 0x8305, //CJK UNIFIED IDEOGRAPH + 0xD9C7: 0x8B00, //CJK UNIFIED IDEOGRAPH + 0xD9C8: 0x8B28, //CJK UNIFIED IDEOGRAPH + 0xD9C9: 0x8C8C, //CJK UNIFIED IDEOGRAPH + 0xD9CA: 0x6728, //CJK UNIFIED IDEOGRAPH + 0xD9CB: 0x6C90, //CJK UNIFIED IDEOGRAPH + 0xD9CC: 0x7267, //CJK UNIFIED IDEOGRAPH + 0xD9CD: 0x76EE, //CJK UNIFIED IDEOGRAPH + 0xD9CE: 0x7766, //CJK UNIFIED IDEOGRAPH + 0xD9CF: 0x7A46, //CJK UNIFIED IDEOGRAPH + 0xD9D0: 0x9DA9, //CJK UNIFIED IDEOGRAPH + 0xD9D1: 0x6B7F, //CJK UNIFIED IDEOGRAPH + 0xD9D2: 0x6C92, //CJK UNIFIED IDEOGRAPH + 0xD9D3: 0x5922, //CJK UNIFIED IDEOGRAPH + 0xD9D4: 0x6726, //CJK UNIFIED IDEOGRAPH + 0xD9D5: 0x8499, //CJK UNIFIED IDEOGRAPH + 0xD9D6: 0x536F, //CJK UNIFIED IDEOGRAPH + 0xD9D7: 0x5893, //CJK UNIFIED IDEOGRAPH + 0xD9D8: 0x5999, //CJK UNIFIED IDEOGRAPH + 0xD9D9: 0x5EDF, //CJK UNIFIED IDEOGRAPH + 0xD9DA: 0x63CF, //CJK UNIFIED IDEOGRAPH + 0xD9DB: 0x6634, //CJK UNIFIED IDEOGRAPH + 0xD9DC: 0x6773, //CJK UNIFIED IDEOGRAPH + 0xD9DD: 0x6E3A, //CJK UNIFIED IDEOGRAPH + 0xD9DE: 0x732B, //CJK UNIFIED IDEOGRAPH + 0xD9DF: 0x7AD7, //CJK UNIFIED IDEOGRAPH + 0xD9E0: 0x82D7, //CJK UNIFIED IDEOGRAPH + 0xD9E1: 0x9328, //CJK UNIFIED IDEOGRAPH + 0xD9E2: 0x52D9, //CJK UNIFIED IDEOGRAPH + 0xD9E3: 0x5DEB, //CJK UNIFIED IDEOGRAPH + 0xD9E4: 0x61AE, //CJK UNIFIED IDEOGRAPH + 0xD9E5: 0x61CB, //CJK UNIFIED IDEOGRAPH + 0xD9E6: 0x620A, //CJK UNIFIED IDEOGRAPH + 0xD9E7: 0x62C7, //CJK UNIFIED IDEOGRAPH + 0xD9E8: 0x64AB, //CJK UNIFIED IDEOGRAPH + 0xD9E9: 0x65E0, //CJK UNIFIED IDEOGRAPH + 0xD9EA: 0x6959, //CJK UNIFIED IDEOGRAPH + 0xD9EB: 0x6B66, //CJK UNIFIED IDEOGRAPH + 0xD9EC: 0x6BCB, //CJK UNIFIED IDEOGRAPH + 0xD9ED: 0x7121, //CJK UNIFIED IDEOGRAPH + 0xD9EE: 0x73F7, //CJK UNIFIED IDEOGRAPH + 0xD9EF: 0x755D, //CJK UNIFIED IDEOGRAPH + 0xD9F0: 0x7E46, //CJK UNIFIED IDEOGRAPH + 0xD9F1: 0x821E, //CJK UNIFIED IDEOGRAPH + 0xD9F2: 0x8302, //CJK UNIFIED IDEOGRAPH + 0xD9F3: 0x856A, //CJK UNIFIED IDEOGRAPH + 0xD9F4: 0x8AA3, //CJK UNIFIED IDEOGRAPH + 0xD9F5: 0x8CBF, //CJK UNIFIED IDEOGRAPH + 0xD9F6: 0x9727, //CJK UNIFIED IDEOGRAPH + 0xD9F7: 0x9D61, //CJK UNIFIED IDEOGRAPH + 0xD9F8: 0x58A8, //CJK UNIFIED IDEOGRAPH + 0xD9F9: 0x9ED8, //CJK UNIFIED IDEOGRAPH + 0xD9FA: 0x5011, //CJK UNIFIED IDEOGRAPH + 0xD9FB: 0x520E, //CJK UNIFIED IDEOGRAPH + 0xD9FC: 0x543B, //CJK UNIFIED IDEOGRAPH + 0xD9FD: 0x554F, //CJK UNIFIED IDEOGRAPH + 0xD9FE: 0x6587, //CJK UNIFIED IDEOGRAPH + 0xDAA1: 0x6C76, //CJK UNIFIED IDEOGRAPH + 0xDAA2: 0x7D0A, //CJK UNIFIED IDEOGRAPH + 0xDAA3: 0x7D0B, //CJK UNIFIED IDEOGRAPH + 0xDAA4: 0x805E, //CJK UNIFIED IDEOGRAPH + 0xDAA5: 0x868A, //CJK UNIFIED IDEOGRAPH + 0xDAA6: 0x9580, //CJK UNIFIED IDEOGRAPH + 0xDAA7: 0x96EF, //CJK UNIFIED IDEOGRAPH + 0xDAA8: 0x52FF, //CJK UNIFIED IDEOGRAPH + 0xDAA9: 0x6C95, //CJK UNIFIED IDEOGRAPH + 0xDAAA: 0x7269, //CJK UNIFIED IDEOGRAPH + 0xDAAB: 0x5473, //CJK UNIFIED IDEOGRAPH + 0xDAAC: 0x5A9A, //CJK UNIFIED IDEOGRAPH + 0xDAAD: 0x5C3E, //CJK UNIFIED IDEOGRAPH + 0xDAAE: 0x5D4B, //CJK UNIFIED IDEOGRAPH + 0xDAAF: 0x5F4C, //CJK UNIFIED IDEOGRAPH + 0xDAB0: 0x5FAE, //CJK UNIFIED IDEOGRAPH + 0xDAB1: 0x672A, //CJK UNIFIED IDEOGRAPH + 0xDAB2: 0x68B6, //CJK UNIFIED IDEOGRAPH + 0xDAB3: 0x6963, //CJK UNIFIED IDEOGRAPH + 0xDAB4: 0x6E3C, //CJK UNIFIED IDEOGRAPH + 0xDAB5: 0x6E44, //CJK UNIFIED IDEOGRAPH + 0xDAB6: 0x7709, //CJK UNIFIED IDEOGRAPH + 0xDAB7: 0x7C73, //CJK UNIFIED IDEOGRAPH + 0xDAB8: 0x7F8E, //CJK UNIFIED IDEOGRAPH + 0xDAB9: 0x8587, //CJK UNIFIED IDEOGRAPH + 0xDABA: 0x8B0E, //CJK UNIFIED IDEOGRAPH + 0xDABB: 0x8FF7, //CJK UNIFIED IDEOGRAPH + 0xDABC: 0x9761, //CJK UNIFIED IDEOGRAPH + 0xDABD: 0x9EF4, //CJK UNIFIED IDEOGRAPH + 0xDABE: 0x5CB7, //CJK UNIFIED IDEOGRAPH + 0xDABF: 0x60B6, //CJK UNIFIED IDEOGRAPH + 0xDAC0: 0x610D, //CJK UNIFIED IDEOGRAPH + 0xDAC1: 0x61AB, //CJK UNIFIED IDEOGRAPH + 0xDAC2: 0x654F, //CJK UNIFIED IDEOGRAPH + 0xDAC3: 0x65FB, //CJK UNIFIED IDEOGRAPH + 0xDAC4: 0x65FC, //CJK UNIFIED IDEOGRAPH + 0xDAC5: 0x6C11, //CJK UNIFIED IDEOGRAPH + 0xDAC6: 0x6CEF, //CJK UNIFIED IDEOGRAPH + 0xDAC7: 0x739F, //CJK UNIFIED IDEOGRAPH + 0xDAC8: 0x73C9, //CJK UNIFIED IDEOGRAPH + 0xDAC9: 0x7DE1, //CJK UNIFIED IDEOGRAPH + 0xDACA: 0x9594, //CJK UNIFIED IDEOGRAPH + 0xDACB: 0x5BC6, //CJK UNIFIED IDEOGRAPH + 0xDACC: 0x871C, //CJK UNIFIED IDEOGRAPH + 0xDACD: 0x8B10, //CJK UNIFIED IDEOGRAPH + 0xDACE: 0x525D, //CJK UNIFIED IDEOGRAPH + 0xDACF: 0x535A, //CJK UNIFIED IDEOGRAPH + 0xDAD0: 0x62CD, //CJK UNIFIED IDEOGRAPH + 0xDAD1: 0x640F, //CJK UNIFIED IDEOGRAPH + 0xDAD2: 0x64B2, //CJK UNIFIED IDEOGRAPH + 0xDAD3: 0x6734, //CJK UNIFIED IDEOGRAPH + 0xDAD4: 0x6A38, //CJK UNIFIED IDEOGRAPH + 0xDAD5: 0x6CCA, //CJK UNIFIED IDEOGRAPH + 0xDAD6: 0x73C0, //CJK UNIFIED IDEOGRAPH + 0xDAD7: 0x749E, //CJK UNIFIED IDEOGRAPH + 0xDAD8: 0x7B94, //CJK UNIFIED IDEOGRAPH + 0xDAD9: 0x7C95, //CJK UNIFIED IDEOGRAPH + 0xDADA: 0x7E1B, //CJK UNIFIED IDEOGRAPH + 0xDADB: 0x818A, //CJK UNIFIED IDEOGRAPH + 0xDADC: 0x8236, //CJK UNIFIED IDEOGRAPH + 0xDADD: 0x8584, //CJK UNIFIED IDEOGRAPH + 0xDADE: 0x8FEB, //CJK UNIFIED IDEOGRAPH + 0xDADF: 0x96F9, //CJK UNIFIED IDEOGRAPH + 0xDAE0: 0x99C1, //CJK UNIFIED IDEOGRAPH + 0xDAE1: 0x4F34, //CJK UNIFIED IDEOGRAPH + 0xDAE2: 0x534A, //CJK UNIFIED IDEOGRAPH + 0xDAE3: 0x53CD, //CJK UNIFIED IDEOGRAPH + 0xDAE4: 0x53DB, //CJK UNIFIED IDEOGRAPH + 0xDAE5: 0x62CC, //CJK UNIFIED IDEOGRAPH + 0xDAE6: 0x642C, //CJK UNIFIED IDEOGRAPH + 0xDAE7: 0x6500, //CJK UNIFIED IDEOGRAPH + 0xDAE8: 0x6591, //CJK UNIFIED IDEOGRAPH + 0xDAE9: 0x69C3, //CJK UNIFIED IDEOGRAPH + 0xDAEA: 0x6CEE, //CJK UNIFIED IDEOGRAPH + 0xDAEB: 0x6F58, //CJK UNIFIED IDEOGRAPH + 0xDAEC: 0x73ED, //CJK UNIFIED IDEOGRAPH + 0xDAED: 0x7554, //CJK UNIFIED IDEOGRAPH + 0xDAEE: 0x7622, //CJK UNIFIED IDEOGRAPH + 0xDAEF: 0x76E4, //CJK UNIFIED IDEOGRAPH + 0xDAF0: 0x76FC, //CJK UNIFIED IDEOGRAPH + 0xDAF1: 0x78D0, //CJK UNIFIED IDEOGRAPH + 0xDAF2: 0x78FB, //CJK UNIFIED IDEOGRAPH + 0xDAF3: 0x792C, //CJK UNIFIED IDEOGRAPH + 0xDAF4: 0x7D46, //CJK UNIFIED IDEOGRAPH + 0xDAF5: 0x822C, //CJK UNIFIED IDEOGRAPH + 0xDAF6: 0x87E0, //CJK UNIFIED IDEOGRAPH + 0xDAF7: 0x8FD4, //CJK UNIFIED IDEOGRAPH + 0xDAF8: 0x9812, //CJK UNIFIED IDEOGRAPH + 0xDAF9: 0x98EF, //CJK UNIFIED IDEOGRAPH + 0xDAFA: 0x52C3, //CJK UNIFIED IDEOGRAPH + 0xDAFB: 0x62D4, //CJK UNIFIED IDEOGRAPH + 0xDAFC: 0x64A5, //CJK UNIFIED IDEOGRAPH + 0xDAFD: 0x6E24, //CJK UNIFIED IDEOGRAPH + 0xDAFE: 0x6F51, //CJK UNIFIED IDEOGRAPH + 0xDBA1: 0x767C, //CJK UNIFIED IDEOGRAPH + 0xDBA2: 0x8DCB, //CJK UNIFIED IDEOGRAPH + 0xDBA3: 0x91B1, //CJK UNIFIED IDEOGRAPH + 0xDBA4: 0x9262, //CJK UNIFIED IDEOGRAPH + 0xDBA5: 0x9AEE, //CJK UNIFIED IDEOGRAPH + 0xDBA6: 0x9B43, //CJK UNIFIED IDEOGRAPH + 0xDBA7: 0x5023, //CJK UNIFIED IDEOGRAPH + 0xDBA8: 0x508D, //CJK UNIFIED IDEOGRAPH + 0xDBA9: 0x574A, //CJK UNIFIED IDEOGRAPH + 0xDBAA: 0x59A8, //CJK UNIFIED IDEOGRAPH + 0xDBAB: 0x5C28, //CJK UNIFIED IDEOGRAPH + 0xDBAC: 0x5E47, //CJK UNIFIED IDEOGRAPH + 0xDBAD: 0x5F77, //CJK UNIFIED IDEOGRAPH + 0xDBAE: 0x623F, //CJK UNIFIED IDEOGRAPH + 0xDBAF: 0x653E, //CJK UNIFIED IDEOGRAPH + 0xDBB0: 0x65B9, //CJK UNIFIED IDEOGRAPH + 0xDBB1: 0x65C1, //CJK UNIFIED IDEOGRAPH + 0xDBB2: 0x6609, //CJK UNIFIED IDEOGRAPH + 0xDBB3: 0x678B, //CJK UNIFIED IDEOGRAPH + 0xDBB4: 0x699C, //CJK UNIFIED IDEOGRAPH + 0xDBB5: 0x6EC2, //CJK UNIFIED IDEOGRAPH + 0xDBB6: 0x78C5, //CJK UNIFIED IDEOGRAPH + 0xDBB7: 0x7D21, //CJK UNIFIED IDEOGRAPH + 0xDBB8: 0x80AA, //CJK UNIFIED IDEOGRAPH + 0xDBB9: 0x8180, //CJK UNIFIED IDEOGRAPH + 0xDBBA: 0x822B, //CJK UNIFIED IDEOGRAPH + 0xDBBB: 0x82B3, //CJK UNIFIED IDEOGRAPH + 0xDBBC: 0x84A1, //CJK UNIFIED IDEOGRAPH + 0xDBBD: 0x868C, //CJK UNIFIED IDEOGRAPH + 0xDBBE: 0x8A2A, //CJK UNIFIED IDEOGRAPH + 0xDBBF: 0x8B17, //CJK UNIFIED IDEOGRAPH + 0xDBC0: 0x90A6, //CJK UNIFIED IDEOGRAPH + 0xDBC1: 0x9632, //CJK UNIFIED IDEOGRAPH + 0xDBC2: 0x9F90, //CJK UNIFIED IDEOGRAPH + 0xDBC3: 0x500D, //CJK UNIFIED IDEOGRAPH + 0xDBC4: 0x4FF3, //CJK UNIFIED IDEOGRAPH + 0xDBC5: 0xF963, //CJK COMPATIBILITY IDEOGRAPH + 0xDBC6: 0x57F9, //CJK UNIFIED IDEOGRAPH + 0xDBC7: 0x5F98, //CJK UNIFIED IDEOGRAPH + 0xDBC8: 0x62DC, //CJK UNIFIED IDEOGRAPH + 0xDBC9: 0x6392, //CJK UNIFIED IDEOGRAPH + 0xDBCA: 0x676F, //CJK UNIFIED IDEOGRAPH + 0xDBCB: 0x6E43, //CJK UNIFIED IDEOGRAPH + 0xDBCC: 0x7119, //CJK UNIFIED IDEOGRAPH + 0xDBCD: 0x76C3, //CJK UNIFIED IDEOGRAPH + 0xDBCE: 0x80CC, //CJK UNIFIED IDEOGRAPH + 0xDBCF: 0x80DA, //CJK UNIFIED IDEOGRAPH + 0xDBD0: 0x88F4, //CJK UNIFIED IDEOGRAPH + 0xDBD1: 0x88F5, //CJK UNIFIED IDEOGRAPH + 0xDBD2: 0x8919, //CJK UNIFIED IDEOGRAPH + 0xDBD3: 0x8CE0, //CJK UNIFIED IDEOGRAPH + 0xDBD4: 0x8F29, //CJK UNIFIED IDEOGRAPH + 0xDBD5: 0x914D, //CJK UNIFIED IDEOGRAPH + 0xDBD6: 0x966A, //CJK UNIFIED IDEOGRAPH + 0xDBD7: 0x4F2F, //CJK UNIFIED IDEOGRAPH + 0xDBD8: 0x4F70, //CJK UNIFIED IDEOGRAPH + 0xDBD9: 0x5E1B, //CJK UNIFIED IDEOGRAPH + 0xDBDA: 0x67CF, //CJK UNIFIED IDEOGRAPH + 0xDBDB: 0x6822, //CJK UNIFIED IDEOGRAPH + 0xDBDC: 0x767D, //CJK UNIFIED IDEOGRAPH + 0xDBDD: 0x767E, //CJK UNIFIED IDEOGRAPH + 0xDBDE: 0x9B44, //CJK UNIFIED IDEOGRAPH + 0xDBDF: 0x5E61, //CJK UNIFIED IDEOGRAPH + 0xDBE0: 0x6A0A, //CJK UNIFIED IDEOGRAPH + 0xDBE1: 0x7169, //CJK UNIFIED IDEOGRAPH + 0xDBE2: 0x71D4, //CJK UNIFIED IDEOGRAPH + 0xDBE3: 0x756A, //CJK UNIFIED IDEOGRAPH + 0xDBE4: 0xF964, //CJK COMPATIBILITY IDEOGRAPH + 0xDBE5: 0x7E41, //CJK UNIFIED IDEOGRAPH + 0xDBE6: 0x8543, //CJK UNIFIED IDEOGRAPH + 0xDBE7: 0x85E9, //CJK UNIFIED IDEOGRAPH + 0xDBE8: 0x98DC, //CJK UNIFIED IDEOGRAPH + 0xDBE9: 0x4F10, //CJK UNIFIED IDEOGRAPH + 0xDBEA: 0x7B4F, //CJK UNIFIED IDEOGRAPH + 0xDBEB: 0x7F70, //CJK UNIFIED IDEOGRAPH + 0xDBEC: 0x95A5, //CJK UNIFIED IDEOGRAPH + 0xDBED: 0x51E1, //CJK UNIFIED IDEOGRAPH + 0xDBEE: 0x5E06, //CJK UNIFIED IDEOGRAPH + 0xDBEF: 0x68B5, //CJK UNIFIED IDEOGRAPH + 0xDBF0: 0x6C3E, //CJK UNIFIED IDEOGRAPH + 0xDBF1: 0x6C4E, //CJK UNIFIED IDEOGRAPH + 0xDBF2: 0x6CDB, //CJK UNIFIED IDEOGRAPH + 0xDBF3: 0x72AF, //CJK UNIFIED IDEOGRAPH + 0xDBF4: 0x7BC4, //CJK UNIFIED IDEOGRAPH + 0xDBF5: 0x8303, //CJK UNIFIED IDEOGRAPH + 0xDBF6: 0x6CD5, //CJK UNIFIED IDEOGRAPH + 0xDBF7: 0x743A, //CJK UNIFIED IDEOGRAPH + 0xDBF8: 0x50FB, //CJK UNIFIED IDEOGRAPH + 0xDBF9: 0x5288, //CJK UNIFIED IDEOGRAPH + 0xDBFA: 0x58C1, //CJK UNIFIED IDEOGRAPH + 0xDBFB: 0x64D8, //CJK UNIFIED IDEOGRAPH + 0xDBFC: 0x6A97, //CJK UNIFIED IDEOGRAPH + 0xDBFD: 0x74A7, //CJK UNIFIED IDEOGRAPH + 0xDBFE: 0x7656, //CJK UNIFIED IDEOGRAPH + 0xDCA1: 0x78A7, //CJK UNIFIED IDEOGRAPH + 0xDCA2: 0x8617, //CJK UNIFIED IDEOGRAPH + 0xDCA3: 0x95E2, //CJK UNIFIED IDEOGRAPH + 0xDCA4: 0x9739, //CJK UNIFIED IDEOGRAPH + 0xDCA5: 0xF965, //CJK COMPATIBILITY IDEOGRAPH + 0xDCA6: 0x535E, //CJK UNIFIED IDEOGRAPH + 0xDCA7: 0x5F01, //CJK UNIFIED IDEOGRAPH + 0xDCA8: 0x8B8A, //CJK UNIFIED IDEOGRAPH + 0xDCA9: 0x8FA8, //CJK UNIFIED IDEOGRAPH + 0xDCAA: 0x8FAF, //CJK UNIFIED IDEOGRAPH + 0xDCAB: 0x908A, //CJK UNIFIED IDEOGRAPH + 0xDCAC: 0x5225, //CJK UNIFIED IDEOGRAPH + 0xDCAD: 0x77A5, //CJK UNIFIED IDEOGRAPH + 0xDCAE: 0x9C49, //CJK UNIFIED IDEOGRAPH + 0xDCAF: 0x9F08, //CJK UNIFIED IDEOGRAPH + 0xDCB0: 0x4E19, //CJK UNIFIED IDEOGRAPH + 0xDCB1: 0x5002, //CJK UNIFIED IDEOGRAPH + 0xDCB2: 0x5175, //CJK UNIFIED IDEOGRAPH + 0xDCB3: 0x5C5B, //CJK UNIFIED IDEOGRAPH + 0xDCB4: 0x5E77, //CJK UNIFIED IDEOGRAPH + 0xDCB5: 0x661E, //CJK UNIFIED IDEOGRAPH + 0xDCB6: 0x663A, //CJK UNIFIED IDEOGRAPH + 0xDCB7: 0x67C4, //CJK UNIFIED IDEOGRAPH + 0xDCB8: 0x68C5, //CJK UNIFIED IDEOGRAPH + 0xDCB9: 0x70B3, //CJK UNIFIED IDEOGRAPH + 0xDCBA: 0x7501, //CJK UNIFIED IDEOGRAPH + 0xDCBB: 0x75C5, //CJK UNIFIED IDEOGRAPH + 0xDCBC: 0x79C9, //CJK UNIFIED IDEOGRAPH + 0xDCBD: 0x7ADD, //CJK UNIFIED IDEOGRAPH + 0xDCBE: 0x8F27, //CJK UNIFIED IDEOGRAPH + 0xDCBF: 0x9920, //CJK UNIFIED IDEOGRAPH + 0xDCC0: 0x9A08, //CJK UNIFIED IDEOGRAPH + 0xDCC1: 0x4FDD, //CJK UNIFIED IDEOGRAPH + 0xDCC2: 0x5821, //CJK UNIFIED IDEOGRAPH + 0xDCC3: 0x5831, //CJK UNIFIED IDEOGRAPH + 0xDCC4: 0x5BF6, //CJK UNIFIED IDEOGRAPH + 0xDCC5: 0x666E, //CJK UNIFIED IDEOGRAPH + 0xDCC6: 0x6B65, //CJK UNIFIED IDEOGRAPH + 0xDCC7: 0x6D11, //CJK UNIFIED IDEOGRAPH + 0xDCC8: 0x6E7A, //CJK UNIFIED IDEOGRAPH + 0xDCC9: 0x6F7D, //CJK UNIFIED IDEOGRAPH + 0xDCCA: 0x73E4, //CJK UNIFIED IDEOGRAPH + 0xDCCB: 0x752B, //CJK UNIFIED IDEOGRAPH + 0xDCCC: 0x83E9, //CJK UNIFIED IDEOGRAPH + 0xDCCD: 0x88DC, //CJK UNIFIED IDEOGRAPH + 0xDCCE: 0x8913, //CJK UNIFIED IDEOGRAPH + 0xDCCF: 0x8B5C, //CJK UNIFIED IDEOGRAPH + 0xDCD0: 0x8F14, //CJK UNIFIED IDEOGRAPH + 0xDCD1: 0x4F0F, //CJK UNIFIED IDEOGRAPH + 0xDCD2: 0x50D5, //CJK UNIFIED IDEOGRAPH + 0xDCD3: 0x5310, //CJK UNIFIED IDEOGRAPH + 0xDCD4: 0x535C, //CJK UNIFIED IDEOGRAPH + 0xDCD5: 0x5B93, //CJK UNIFIED IDEOGRAPH + 0xDCD6: 0x5FA9, //CJK UNIFIED IDEOGRAPH + 0xDCD7: 0x670D, //CJK UNIFIED IDEOGRAPH + 0xDCD8: 0x798F, //CJK UNIFIED IDEOGRAPH + 0xDCD9: 0x8179, //CJK UNIFIED IDEOGRAPH + 0xDCDA: 0x832F, //CJK UNIFIED IDEOGRAPH + 0xDCDB: 0x8514, //CJK UNIFIED IDEOGRAPH + 0xDCDC: 0x8907, //CJK UNIFIED IDEOGRAPH + 0xDCDD: 0x8986, //CJK UNIFIED IDEOGRAPH + 0xDCDE: 0x8F39, //CJK UNIFIED IDEOGRAPH + 0xDCDF: 0x8F3B, //CJK UNIFIED IDEOGRAPH + 0xDCE0: 0x99A5, //CJK UNIFIED IDEOGRAPH + 0xDCE1: 0x9C12, //CJK UNIFIED IDEOGRAPH + 0xDCE2: 0x672C, //CJK UNIFIED IDEOGRAPH + 0xDCE3: 0x4E76, //CJK UNIFIED IDEOGRAPH + 0xDCE4: 0x4FF8, //CJK UNIFIED IDEOGRAPH + 0xDCE5: 0x5949, //CJK UNIFIED IDEOGRAPH + 0xDCE6: 0x5C01, //CJK UNIFIED IDEOGRAPH + 0xDCE7: 0x5CEF, //CJK UNIFIED IDEOGRAPH + 0xDCE8: 0x5CF0, //CJK UNIFIED IDEOGRAPH + 0xDCE9: 0x6367, //CJK UNIFIED IDEOGRAPH + 0xDCEA: 0x68D2, //CJK UNIFIED IDEOGRAPH + 0xDCEB: 0x70FD, //CJK UNIFIED IDEOGRAPH + 0xDCEC: 0x71A2, //CJK UNIFIED IDEOGRAPH + 0xDCED: 0x742B, //CJK UNIFIED IDEOGRAPH + 0xDCEE: 0x7E2B, //CJK UNIFIED IDEOGRAPH + 0xDCEF: 0x84EC, //CJK UNIFIED IDEOGRAPH + 0xDCF0: 0x8702, //CJK UNIFIED IDEOGRAPH + 0xDCF1: 0x9022, //CJK UNIFIED IDEOGRAPH + 0xDCF2: 0x92D2, //CJK UNIFIED IDEOGRAPH + 0xDCF3: 0x9CF3, //CJK UNIFIED IDEOGRAPH + 0xDCF4: 0x4E0D, //CJK UNIFIED IDEOGRAPH + 0xDCF5: 0x4ED8, //CJK UNIFIED IDEOGRAPH + 0xDCF6: 0x4FEF, //CJK UNIFIED IDEOGRAPH + 0xDCF7: 0x5085, //CJK UNIFIED IDEOGRAPH + 0xDCF8: 0x5256, //CJK UNIFIED IDEOGRAPH + 0xDCF9: 0x526F, //CJK UNIFIED IDEOGRAPH + 0xDCFA: 0x5426, //CJK UNIFIED IDEOGRAPH + 0xDCFB: 0x5490, //CJK UNIFIED IDEOGRAPH + 0xDCFC: 0x57E0, //CJK UNIFIED IDEOGRAPH + 0xDCFD: 0x592B, //CJK UNIFIED IDEOGRAPH + 0xDCFE: 0x5A66, //CJK UNIFIED IDEOGRAPH + 0xDDA1: 0x5B5A, //CJK UNIFIED IDEOGRAPH + 0xDDA2: 0x5B75, //CJK UNIFIED IDEOGRAPH + 0xDDA3: 0x5BCC, //CJK UNIFIED IDEOGRAPH + 0xDDA4: 0x5E9C, //CJK UNIFIED IDEOGRAPH + 0xDDA5: 0xF966, //CJK COMPATIBILITY IDEOGRAPH + 0xDDA6: 0x6276, //CJK UNIFIED IDEOGRAPH + 0xDDA7: 0x6577, //CJK UNIFIED IDEOGRAPH + 0xDDA8: 0x65A7, //CJK UNIFIED IDEOGRAPH + 0xDDA9: 0x6D6E, //CJK UNIFIED IDEOGRAPH + 0xDDAA: 0x6EA5, //CJK UNIFIED IDEOGRAPH + 0xDDAB: 0x7236, //CJK UNIFIED IDEOGRAPH + 0xDDAC: 0x7B26, //CJK UNIFIED IDEOGRAPH + 0xDDAD: 0x7C3F, //CJK UNIFIED IDEOGRAPH + 0xDDAE: 0x7F36, //CJK UNIFIED IDEOGRAPH + 0xDDAF: 0x8150, //CJK UNIFIED IDEOGRAPH + 0xDDB0: 0x8151, //CJK UNIFIED IDEOGRAPH + 0xDDB1: 0x819A, //CJK UNIFIED IDEOGRAPH + 0xDDB2: 0x8240, //CJK UNIFIED IDEOGRAPH + 0xDDB3: 0x8299, //CJK UNIFIED IDEOGRAPH + 0xDDB4: 0x83A9, //CJK UNIFIED IDEOGRAPH + 0xDDB5: 0x8A03, //CJK UNIFIED IDEOGRAPH + 0xDDB6: 0x8CA0, //CJK UNIFIED IDEOGRAPH + 0xDDB7: 0x8CE6, //CJK UNIFIED IDEOGRAPH + 0xDDB8: 0x8CFB, //CJK UNIFIED IDEOGRAPH + 0xDDB9: 0x8D74, //CJK UNIFIED IDEOGRAPH + 0xDDBA: 0x8DBA, //CJK UNIFIED IDEOGRAPH + 0xDDBB: 0x90E8, //CJK UNIFIED IDEOGRAPH + 0xDDBC: 0x91DC, //CJK UNIFIED IDEOGRAPH + 0xDDBD: 0x961C, //CJK UNIFIED IDEOGRAPH + 0xDDBE: 0x9644, //CJK UNIFIED IDEOGRAPH + 0xDDBF: 0x99D9, //CJK UNIFIED IDEOGRAPH + 0xDDC0: 0x9CE7, //CJK UNIFIED IDEOGRAPH + 0xDDC1: 0x5317, //CJK UNIFIED IDEOGRAPH + 0xDDC2: 0x5206, //CJK UNIFIED IDEOGRAPH + 0xDDC3: 0x5429, //CJK UNIFIED IDEOGRAPH + 0xDDC4: 0x5674, //CJK UNIFIED IDEOGRAPH + 0xDDC5: 0x58B3, //CJK UNIFIED IDEOGRAPH + 0xDDC6: 0x5954, //CJK UNIFIED IDEOGRAPH + 0xDDC7: 0x596E, //CJK UNIFIED IDEOGRAPH + 0xDDC8: 0x5FFF, //CJK UNIFIED IDEOGRAPH + 0xDDC9: 0x61A4, //CJK UNIFIED IDEOGRAPH + 0xDDCA: 0x626E, //CJK UNIFIED IDEOGRAPH + 0xDDCB: 0x6610, //CJK UNIFIED IDEOGRAPH + 0xDDCC: 0x6C7E, //CJK UNIFIED IDEOGRAPH + 0xDDCD: 0x711A, //CJK UNIFIED IDEOGRAPH + 0xDDCE: 0x76C6, //CJK UNIFIED IDEOGRAPH + 0xDDCF: 0x7C89, //CJK UNIFIED IDEOGRAPH + 0xDDD0: 0x7CDE, //CJK UNIFIED IDEOGRAPH + 0xDDD1: 0x7D1B, //CJK UNIFIED IDEOGRAPH + 0xDDD2: 0x82AC, //CJK UNIFIED IDEOGRAPH + 0xDDD3: 0x8CC1, //CJK UNIFIED IDEOGRAPH + 0xDDD4: 0x96F0, //CJK UNIFIED IDEOGRAPH + 0xDDD5: 0xF967, //CJK COMPATIBILITY IDEOGRAPH + 0xDDD6: 0x4F5B, //CJK UNIFIED IDEOGRAPH + 0xDDD7: 0x5F17, //CJK UNIFIED IDEOGRAPH + 0xDDD8: 0x5F7F, //CJK UNIFIED IDEOGRAPH + 0xDDD9: 0x62C2, //CJK UNIFIED IDEOGRAPH + 0xDDDA: 0x5D29, //CJK UNIFIED IDEOGRAPH + 0xDDDB: 0x670B, //CJK UNIFIED IDEOGRAPH + 0xDDDC: 0x68DA, //CJK UNIFIED IDEOGRAPH + 0xDDDD: 0x787C, //CJK UNIFIED IDEOGRAPH + 0xDDDE: 0x7E43, //CJK UNIFIED IDEOGRAPH + 0xDDDF: 0x9D6C, //CJK UNIFIED IDEOGRAPH + 0xDDE0: 0x4E15, //CJK UNIFIED IDEOGRAPH + 0xDDE1: 0x5099, //CJK UNIFIED IDEOGRAPH + 0xDDE2: 0x5315, //CJK UNIFIED IDEOGRAPH + 0xDDE3: 0x532A, //CJK UNIFIED IDEOGRAPH + 0xDDE4: 0x5351, //CJK UNIFIED IDEOGRAPH + 0xDDE5: 0x5983, //CJK UNIFIED IDEOGRAPH + 0xDDE6: 0x5A62, //CJK UNIFIED IDEOGRAPH + 0xDDE7: 0x5E87, //CJK UNIFIED IDEOGRAPH + 0xDDE8: 0x60B2, //CJK UNIFIED IDEOGRAPH + 0xDDE9: 0x618A, //CJK UNIFIED IDEOGRAPH + 0xDDEA: 0x6249, //CJK UNIFIED IDEOGRAPH + 0xDDEB: 0x6279, //CJK UNIFIED IDEOGRAPH + 0xDDEC: 0x6590, //CJK UNIFIED IDEOGRAPH + 0xDDED: 0x6787, //CJK UNIFIED IDEOGRAPH + 0xDDEE: 0x69A7, //CJK UNIFIED IDEOGRAPH + 0xDDEF: 0x6BD4, //CJK UNIFIED IDEOGRAPH + 0xDDF0: 0x6BD6, //CJK UNIFIED IDEOGRAPH + 0xDDF1: 0x6BD7, //CJK UNIFIED IDEOGRAPH + 0xDDF2: 0x6BD8, //CJK UNIFIED IDEOGRAPH + 0xDDF3: 0x6CB8, //CJK UNIFIED IDEOGRAPH + 0xDDF4: 0xF968, //CJK COMPATIBILITY IDEOGRAPH + 0xDDF5: 0x7435, //CJK UNIFIED IDEOGRAPH + 0xDDF6: 0x75FA, //CJK UNIFIED IDEOGRAPH + 0xDDF7: 0x7812, //CJK UNIFIED IDEOGRAPH + 0xDDF8: 0x7891, //CJK UNIFIED IDEOGRAPH + 0xDDF9: 0x79D5, //CJK UNIFIED IDEOGRAPH + 0xDDFA: 0x79D8, //CJK UNIFIED IDEOGRAPH + 0xDDFB: 0x7C83, //CJK UNIFIED IDEOGRAPH + 0xDDFC: 0x7DCB, //CJK UNIFIED IDEOGRAPH + 0xDDFD: 0x7FE1, //CJK UNIFIED IDEOGRAPH + 0xDDFE: 0x80A5, //CJK UNIFIED IDEOGRAPH + 0xDEA1: 0x813E, //CJK UNIFIED IDEOGRAPH + 0xDEA2: 0x81C2, //CJK UNIFIED IDEOGRAPH + 0xDEA3: 0x83F2, //CJK UNIFIED IDEOGRAPH + 0xDEA4: 0x871A, //CJK UNIFIED IDEOGRAPH + 0xDEA5: 0x88E8, //CJK UNIFIED IDEOGRAPH + 0xDEA6: 0x8AB9, //CJK UNIFIED IDEOGRAPH + 0xDEA7: 0x8B6C, //CJK UNIFIED IDEOGRAPH + 0xDEA8: 0x8CBB, //CJK UNIFIED IDEOGRAPH + 0xDEA9: 0x9119, //CJK UNIFIED IDEOGRAPH + 0xDEAA: 0x975E, //CJK UNIFIED IDEOGRAPH + 0xDEAB: 0x98DB, //CJK UNIFIED IDEOGRAPH + 0xDEAC: 0x9F3B, //CJK UNIFIED IDEOGRAPH + 0xDEAD: 0x56AC, //CJK UNIFIED IDEOGRAPH + 0xDEAE: 0x5B2A, //CJK UNIFIED IDEOGRAPH + 0xDEAF: 0x5F6C, //CJK UNIFIED IDEOGRAPH + 0xDEB0: 0x658C, //CJK UNIFIED IDEOGRAPH + 0xDEB1: 0x6AB3, //CJK UNIFIED IDEOGRAPH + 0xDEB2: 0x6BAF, //CJK UNIFIED IDEOGRAPH + 0xDEB3: 0x6D5C, //CJK UNIFIED IDEOGRAPH + 0xDEB4: 0x6FF1, //CJK UNIFIED IDEOGRAPH + 0xDEB5: 0x7015, //CJK UNIFIED IDEOGRAPH + 0xDEB6: 0x725D, //CJK UNIFIED IDEOGRAPH + 0xDEB7: 0x73AD, //CJK UNIFIED IDEOGRAPH + 0xDEB8: 0x8CA7, //CJK UNIFIED IDEOGRAPH + 0xDEB9: 0x8CD3, //CJK UNIFIED IDEOGRAPH + 0xDEBA: 0x983B, //CJK UNIFIED IDEOGRAPH + 0xDEBB: 0x6191, //CJK UNIFIED IDEOGRAPH + 0xDEBC: 0x6C37, //CJK UNIFIED IDEOGRAPH + 0xDEBD: 0x8058, //CJK UNIFIED IDEOGRAPH + 0xDEBE: 0x9A01, //CJK UNIFIED IDEOGRAPH + 0xDEBF: 0x4E4D, //CJK UNIFIED IDEOGRAPH + 0xDEC0: 0x4E8B, //CJK UNIFIED IDEOGRAPH + 0xDEC1: 0x4E9B, //CJK UNIFIED IDEOGRAPH + 0xDEC2: 0x4ED5, //CJK UNIFIED IDEOGRAPH + 0xDEC3: 0x4F3A, //CJK UNIFIED IDEOGRAPH + 0xDEC4: 0x4F3C, //CJK UNIFIED IDEOGRAPH + 0xDEC5: 0x4F7F, //CJK UNIFIED IDEOGRAPH + 0xDEC6: 0x4FDF, //CJK UNIFIED IDEOGRAPH + 0xDEC7: 0x50FF, //CJK UNIFIED IDEOGRAPH + 0xDEC8: 0x53F2, //CJK UNIFIED IDEOGRAPH + 0xDEC9: 0x53F8, //CJK UNIFIED IDEOGRAPH + 0xDECA: 0x5506, //CJK UNIFIED IDEOGRAPH + 0xDECB: 0x55E3, //CJK UNIFIED IDEOGRAPH + 0xDECC: 0x56DB, //CJK UNIFIED IDEOGRAPH + 0xDECD: 0x58EB, //CJK UNIFIED IDEOGRAPH + 0xDECE: 0x5962, //CJK UNIFIED IDEOGRAPH + 0xDECF: 0x5A11, //CJK UNIFIED IDEOGRAPH + 0xDED0: 0x5BEB, //CJK UNIFIED IDEOGRAPH + 0xDED1: 0x5BFA, //CJK UNIFIED IDEOGRAPH + 0xDED2: 0x5C04, //CJK UNIFIED IDEOGRAPH + 0xDED3: 0x5DF3, //CJK UNIFIED IDEOGRAPH + 0xDED4: 0x5E2B, //CJK UNIFIED IDEOGRAPH + 0xDED5: 0x5F99, //CJK UNIFIED IDEOGRAPH + 0xDED6: 0x601D, //CJK UNIFIED IDEOGRAPH + 0xDED7: 0x6368, //CJK UNIFIED IDEOGRAPH + 0xDED8: 0x659C, //CJK UNIFIED IDEOGRAPH + 0xDED9: 0x65AF, //CJK UNIFIED IDEOGRAPH + 0xDEDA: 0x67F6, //CJK UNIFIED IDEOGRAPH + 0xDEDB: 0x67FB, //CJK UNIFIED IDEOGRAPH + 0xDEDC: 0x68AD, //CJK UNIFIED IDEOGRAPH + 0xDEDD: 0x6B7B, //CJK UNIFIED IDEOGRAPH + 0xDEDE: 0x6C99, //CJK UNIFIED IDEOGRAPH + 0xDEDF: 0x6CD7, //CJK UNIFIED IDEOGRAPH + 0xDEE0: 0x6E23, //CJK UNIFIED IDEOGRAPH + 0xDEE1: 0x7009, //CJK UNIFIED IDEOGRAPH + 0xDEE2: 0x7345, //CJK UNIFIED IDEOGRAPH + 0xDEE3: 0x7802, //CJK UNIFIED IDEOGRAPH + 0xDEE4: 0x793E, //CJK UNIFIED IDEOGRAPH + 0xDEE5: 0x7940, //CJK UNIFIED IDEOGRAPH + 0xDEE6: 0x7960, //CJK UNIFIED IDEOGRAPH + 0xDEE7: 0x79C1, //CJK UNIFIED IDEOGRAPH + 0xDEE8: 0x7BE9, //CJK UNIFIED IDEOGRAPH + 0xDEE9: 0x7D17, //CJK UNIFIED IDEOGRAPH + 0xDEEA: 0x7D72, //CJK UNIFIED IDEOGRAPH + 0xDEEB: 0x8086, //CJK UNIFIED IDEOGRAPH + 0xDEEC: 0x820D, //CJK UNIFIED IDEOGRAPH + 0xDEED: 0x838E, //CJK UNIFIED IDEOGRAPH + 0xDEEE: 0x84D1, //CJK UNIFIED IDEOGRAPH + 0xDEEF: 0x86C7, //CJK UNIFIED IDEOGRAPH + 0xDEF0: 0x88DF, //CJK UNIFIED IDEOGRAPH + 0xDEF1: 0x8A50, //CJK UNIFIED IDEOGRAPH + 0xDEF2: 0x8A5E, //CJK UNIFIED IDEOGRAPH + 0xDEF3: 0x8B1D, //CJK UNIFIED IDEOGRAPH + 0xDEF4: 0x8CDC, //CJK UNIFIED IDEOGRAPH + 0xDEF5: 0x8D66, //CJK UNIFIED IDEOGRAPH + 0xDEF6: 0x8FAD, //CJK UNIFIED IDEOGRAPH + 0xDEF7: 0x90AA, //CJK UNIFIED IDEOGRAPH + 0xDEF8: 0x98FC, //CJK UNIFIED IDEOGRAPH + 0xDEF9: 0x99DF, //CJK UNIFIED IDEOGRAPH + 0xDEFA: 0x9E9D, //CJK UNIFIED IDEOGRAPH + 0xDEFB: 0x524A, //CJK UNIFIED IDEOGRAPH + 0xDEFC: 0xF969, //CJK COMPATIBILITY IDEOGRAPH + 0xDEFD: 0x6714, //CJK UNIFIED IDEOGRAPH + 0xDEFE: 0xF96A, //CJK COMPATIBILITY IDEOGRAPH + 0xDFA1: 0x5098, //CJK UNIFIED IDEOGRAPH + 0xDFA2: 0x522A, //CJK UNIFIED IDEOGRAPH + 0xDFA3: 0x5C71, //CJK UNIFIED IDEOGRAPH + 0xDFA4: 0x6563, //CJK UNIFIED IDEOGRAPH + 0xDFA5: 0x6C55, //CJK UNIFIED IDEOGRAPH + 0xDFA6: 0x73CA, //CJK UNIFIED IDEOGRAPH + 0xDFA7: 0x7523, //CJK UNIFIED IDEOGRAPH + 0xDFA8: 0x759D, //CJK UNIFIED IDEOGRAPH + 0xDFA9: 0x7B97, //CJK UNIFIED IDEOGRAPH + 0xDFAA: 0x849C, //CJK UNIFIED IDEOGRAPH + 0xDFAB: 0x9178, //CJK UNIFIED IDEOGRAPH + 0xDFAC: 0x9730, //CJK UNIFIED IDEOGRAPH + 0xDFAD: 0x4E77, //CJK UNIFIED IDEOGRAPH + 0xDFAE: 0x6492, //CJK UNIFIED IDEOGRAPH + 0xDFAF: 0x6BBA, //CJK UNIFIED IDEOGRAPH + 0xDFB0: 0x715E, //CJK UNIFIED IDEOGRAPH + 0xDFB1: 0x85A9, //CJK UNIFIED IDEOGRAPH + 0xDFB2: 0x4E09, //CJK UNIFIED IDEOGRAPH + 0xDFB3: 0xF96B, //CJK COMPATIBILITY IDEOGRAPH + 0xDFB4: 0x6749, //CJK UNIFIED IDEOGRAPH + 0xDFB5: 0x68EE, //CJK UNIFIED IDEOGRAPH + 0xDFB6: 0x6E17, //CJK UNIFIED IDEOGRAPH + 0xDFB7: 0x829F, //CJK UNIFIED IDEOGRAPH + 0xDFB8: 0x8518, //CJK UNIFIED IDEOGRAPH + 0xDFB9: 0x886B, //CJK UNIFIED IDEOGRAPH + 0xDFBA: 0x63F7, //CJK UNIFIED IDEOGRAPH + 0xDFBB: 0x6F81, //CJK UNIFIED IDEOGRAPH + 0xDFBC: 0x9212, //CJK UNIFIED IDEOGRAPH + 0xDFBD: 0x98AF, //CJK UNIFIED IDEOGRAPH + 0xDFBE: 0x4E0A, //CJK UNIFIED IDEOGRAPH + 0xDFBF: 0x50B7, //CJK UNIFIED IDEOGRAPH + 0xDFC0: 0x50CF, //CJK UNIFIED IDEOGRAPH + 0xDFC1: 0x511F, //CJK UNIFIED IDEOGRAPH + 0xDFC2: 0x5546, //CJK UNIFIED IDEOGRAPH + 0xDFC3: 0x55AA, //CJK UNIFIED IDEOGRAPH + 0xDFC4: 0x5617, //CJK UNIFIED IDEOGRAPH + 0xDFC5: 0x5B40, //CJK UNIFIED IDEOGRAPH + 0xDFC6: 0x5C19, //CJK UNIFIED IDEOGRAPH + 0xDFC7: 0x5CE0, //CJK UNIFIED IDEOGRAPH + 0xDFC8: 0x5E38, //CJK UNIFIED IDEOGRAPH + 0xDFC9: 0x5E8A, //CJK UNIFIED IDEOGRAPH + 0xDFCA: 0x5EA0, //CJK UNIFIED IDEOGRAPH + 0xDFCB: 0x5EC2, //CJK UNIFIED IDEOGRAPH + 0xDFCC: 0x60F3, //CJK UNIFIED IDEOGRAPH + 0xDFCD: 0x6851, //CJK UNIFIED IDEOGRAPH + 0xDFCE: 0x6A61, //CJK UNIFIED IDEOGRAPH + 0xDFCF: 0x6E58, //CJK UNIFIED IDEOGRAPH + 0xDFD0: 0x723D, //CJK UNIFIED IDEOGRAPH + 0xDFD1: 0x7240, //CJK UNIFIED IDEOGRAPH + 0xDFD2: 0x72C0, //CJK UNIFIED IDEOGRAPH + 0xDFD3: 0x76F8, //CJK UNIFIED IDEOGRAPH + 0xDFD4: 0x7965, //CJK UNIFIED IDEOGRAPH + 0xDFD5: 0x7BB1, //CJK UNIFIED IDEOGRAPH + 0xDFD6: 0x7FD4, //CJK UNIFIED IDEOGRAPH + 0xDFD7: 0x88F3, //CJK UNIFIED IDEOGRAPH + 0xDFD8: 0x89F4, //CJK UNIFIED IDEOGRAPH + 0xDFD9: 0x8A73, //CJK UNIFIED IDEOGRAPH + 0xDFDA: 0x8C61, //CJK UNIFIED IDEOGRAPH + 0xDFDB: 0x8CDE, //CJK UNIFIED IDEOGRAPH + 0xDFDC: 0x971C, //CJK UNIFIED IDEOGRAPH + 0xDFDD: 0x585E, //CJK UNIFIED IDEOGRAPH + 0xDFDE: 0x74BD, //CJK UNIFIED IDEOGRAPH + 0xDFDF: 0x8CFD, //CJK UNIFIED IDEOGRAPH + 0xDFE0: 0x55C7, //CJK UNIFIED IDEOGRAPH + 0xDFE1: 0xF96C, //CJK COMPATIBILITY IDEOGRAPH + 0xDFE2: 0x7A61, //CJK UNIFIED IDEOGRAPH + 0xDFE3: 0x7D22, //CJK UNIFIED IDEOGRAPH + 0xDFE4: 0x8272, //CJK UNIFIED IDEOGRAPH + 0xDFE5: 0x7272, //CJK UNIFIED IDEOGRAPH + 0xDFE6: 0x751F, //CJK UNIFIED IDEOGRAPH + 0xDFE7: 0x7525, //CJK UNIFIED IDEOGRAPH + 0xDFE8: 0xF96D, //CJK COMPATIBILITY IDEOGRAPH + 0xDFE9: 0x7B19, //CJK UNIFIED IDEOGRAPH + 0xDFEA: 0x5885, //CJK UNIFIED IDEOGRAPH + 0xDFEB: 0x58FB, //CJK UNIFIED IDEOGRAPH + 0xDFEC: 0x5DBC, //CJK UNIFIED IDEOGRAPH + 0xDFED: 0x5E8F, //CJK UNIFIED IDEOGRAPH + 0xDFEE: 0x5EB6, //CJK UNIFIED IDEOGRAPH + 0xDFEF: 0x5F90, //CJK UNIFIED IDEOGRAPH + 0xDFF0: 0x6055, //CJK UNIFIED IDEOGRAPH + 0xDFF1: 0x6292, //CJK UNIFIED IDEOGRAPH + 0xDFF2: 0x637F, //CJK UNIFIED IDEOGRAPH + 0xDFF3: 0x654D, //CJK UNIFIED IDEOGRAPH + 0xDFF4: 0x6691, //CJK UNIFIED IDEOGRAPH + 0xDFF5: 0x66D9, //CJK UNIFIED IDEOGRAPH + 0xDFF6: 0x66F8, //CJK UNIFIED IDEOGRAPH + 0xDFF7: 0x6816, //CJK UNIFIED IDEOGRAPH + 0xDFF8: 0x68F2, //CJK UNIFIED IDEOGRAPH + 0xDFF9: 0x7280, //CJK UNIFIED IDEOGRAPH + 0xDFFA: 0x745E, //CJK UNIFIED IDEOGRAPH + 0xDFFB: 0x7B6E, //CJK UNIFIED IDEOGRAPH + 0xDFFC: 0x7D6E, //CJK UNIFIED IDEOGRAPH + 0xDFFD: 0x7DD6, //CJK UNIFIED IDEOGRAPH + 0xDFFE: 0x7F72, //CJK UNIFIED IDEOGRAPH + 0xE0A1: 0x80E5, //CJK UNIFIED IDEOGRAPH + 0xE0A2: 0x8212, //CJK UNIFIED IDEOGRAPH + 0xE0A3: 0x85AF, //CJK UNIFIED IDEOGRAPH + 0xE0A4: 0x897F, //CJK UNIFIED IDEOGRAPH + 0xE0A5: 0x8A93, //CJK UNIFIED IDEOGRAPH + 0xE0A6: 0x901D, //CJK UNIFIED IDEOGRAPH + 0xE0A7: 0x92E4, //CJK UNIFIED IDEOGRAPH + 0xE0A8: 0x9ECD, //CJK UNIFIED IDEOGRAPH + 0xE0A9: 0x9F20, //CJK UNIFIED IDEOGRAPH + 0xE0AA: 0x5915, //CJK UNIFIED IDEOGRAPH + 0xE0AB: 0x596D, //CJK UNIFIED IDEOGRAPH + 0xE0AC: 0x5E2D, //CJK UNIFIED IDEOGRAPH + 0xE0AD: 0x60DC, //CJK UNIFIED IDEOGRAPH + 0xE0AE: 0x6614, //CJK UNIFIED IDEOGRAPH + 0xE0AF: 0x6673, //CJK UNIFIED IDEOGRAPH + 0xE0B0: 0x6790, //CJK UNIFIED IDEOGRAPH + 0xE0B1: 0x6C50, //CJK UNIFIED IDEOGRAPH + 0xE0B2: 0x6DC5, //CJK UNIFIED IDEOGRAPH + 0xE0B3: 0x6F5F, //CJK UNIFIED IDEOGRAPH + 0xE0B4: 0x77F3, //CJK UNIFIED IDEOGRAPH + 0xE0B5: 0x78A9, //CJK UNIFIED IDEOGRAPH + 0xE0B6: 0x84C6, //CJK UNIFIED IDEOGRAPH + 0xE0B7: 0x91CB, //CJK UNIFIED IDEOGRAPH + 0xE0B8: 0x932B, //CJK UNIFIED IDEOGRAPH + 0xE0B9: 0x4ED9, //CJK UNIFIED IDEOGRAPH + 0xE0BA: 0x50CA, //CJK UNIFIED IDEOGRAPH + 0xE0BB: 0x5148, //CJK UNIFIED IDEOGRAPH + 0xE0BC: 0x5584, //CJK UNIFIED IDEOGRAPH + 0xE0BD: 0x5B0B, //CJK UNIFIED IDEOGRAPH + 0xE0BE: 0x5BA3, //CJK UNIFIED IDEOGRAPH + 0xE0BF: 0x6247, //CJK UNIFIED IDEOGRAPH + 0xE0C0: 0x657E, //CJK UNIFIED IDEOGRAPH + 0xE0C1: 0x65CB, //CJK UNIFIED IDEOGRAPH + 0xE0C2: 0x6E32, //CJK UNIFIED IDEOGRAPH + 0xE0C3: 0x717D, //CJK UNIFIED IDEOGRAPH + 0xE0C4: 0x7401, //CJK UNIFIED IDEOGRAPH + 0xE0C5: 0x7444, //CJK UNIFIED IDEOGRAPH + 0xE0C6: 0x7487, //CJK UNIFIED IDEOGRAPH + 0xE0C7: 0x74BF, //CJK UNIFIED IDEOGRAPH + 0xE0C8: 0x766C, //CJK UNIFIED IDEOGRAPH + 0xE0C9: 0x79AA, //CJK UNIFIED IDEOGRAPH + 0xE0CA: 0x7DDA, //CJK UNIFIED IDEOGRAPH + 0xE0CB: 0x7E55, //CJK UNIFIED IDEOGRAPH + 0xE0CC: 0x7FA8, //CJK UNIFIED IDEOGRAPH + 0xE0CD: 0x817A, //CJK UNIFIED IDEOGRAPH + 0xE0CE: 0x81B3, //CJK UNIFIED IDEOGRAPH + 0xE0CF: 0x8239, //CJK UNIFIED IDEOGRAPH + 0xE0D0: 0x861A, //CJK UNIFIED IDEOGRAPH + 0xE0D1: 0x87EC, //CJK UNIFIED IDEOGRAPH + 0xE0D2: 0x8A75, //CJK UNIFIED IDEOGRAPH + 0xE0D3: 0x8DE3, //CJK UNIFIED IDEOGRAPH + 0xE0D4: 0x9078, //CJK UNIFIED IDEOGRAPH + 0xE0D5: 0x9291, //CJK UNIFIED IDEOGRAPH + 0xE0D6: 0x9425, //CJK UNIFIED IDEOGRAPH + 0xE0D7: 0x994D, //CJK UNIFIED IDEOGRAPH + 0xE0D8: 0x9BAE, //CJK UNIFIED IDEOGRAPH + 0xE0D9: 0x5368, //CJK UNIFIED IDEOGRAPH + 0xE0DA: 0x5C51, //CJK UNIFIED IDEOGRAPH + 0xE0DB: 0x6954, //CJK UNIFIED IDEOGRAPH + 0xE0DC: 0x6CC4, //CJK UNIFIED IDEOGRAPH + 0xE0DD: 0x6D29, //CJK UNIFIED IDEOGRAPH + 0xE0DE: 0x6E2B, //CJK UNIFIED IDEOGRAPH + 0xE0DF: 0x820C, //CJK UNIFIED IDEOGRAPH + 0xE0E0: 0x859B, //CJK UNIFIED IDEOGRAPH + 0xE0E1: 0x893B, //CJK UNIFIED IDEOGRAPH + 0xE0E2: 0x8A2D, //CJK UNIFIED IDEOGRAPH + 0xE0E3: 0x8AAA, //CJK UNIFIED IDEOGRAPH + 0xE0E4: 0x96EA, //CJK UNIFIED IDEOGRAPH + 0xE0E5: 0x9F67, //CJK UNIFIED IDEOGRAPH + 0xE0E6: 0x5261, //CJK UNIFIED IDEOGRAPH + 0xE0E7: 0x66B9, //CJK UNIFIED IDEOGRAPH + 0xE0E8: 0x6BB2, //CJK UNIFIED IDEOGRAPH + 0xE0E9: 0x7E96, //CJK UNIFIED IDEOGRAPH + 0xE0EA: 0x87FE, //CJK UNIFIED IDEOGRAPH + 0xE0EB: 0x8D0D, //CJK UNIFIED IDEOGRAPH + 0xE0EC: 0x9583, //CJK UNIFIED IDEOGRAPH + 0xE0ED: 0x965D, //CJK UNIFIED IDEOGRAPH + 0xE0EE: 0x651D, //CJK UNIFIED IDEOGRAPH + 0xE0EF: 0x6D89, //CJK UNIFIED IDEOGRAPH + 0xE0F0: 0x71EE, //CJK UNIFIED IDEOGRAPH + 0xE0F1: 0xF96E, //CJK COMPATIBILITY IDEOGRAPH + 0xE0F2: 0x57CE, //CJK UNIFIED IDEOGRAPH + 0xE0F3: 0x59D3, //CJK UNIFIED IDEOGRAPH + 0xE0F4: 0x5BAC, //CJK UNIFIED IDEOGRAPH + 0xE0F5: 0x6027, //CJK UNIFIED IDEOGRAPH + 0xE0F6: 0x60FA, //CJK UNIFIED IDEOGRAPH + 0xE0F7: 0x6210, //CJK UNIFIED IDEOGRAPH + 0xE0F8: 0x661F, //CJK UNIFIED IDEOGRAPH + 0xE0F9: 0x665F, //CJK UNIFIED IDEOGRAPH + 0xE0FA: 0x7329, //CJK UNIFIED IDEOGRAPH + 0xE0FB: 0x73F9, //CJK UNIFIED IDEOGRAPH + 0xE0FC: 0x76DB, //CJK UNIFIED IDEOGRAPH + 0xE0FD: 0x7701, //CJK UNIFIED IDEOGRAPH + 0xE0FE: 0x7B6C, //CJK UNIFIED IDEOGRAPH + 0xE1A1: 0x8056, //CJK UNIFIED IDEOGRAPH + 0xE1A2: 0x8072, //CJK UNIFIED IDEOGRAPH + 0xE1A3: 0x8165, //CJK UNIFIED IDEOGRAPH + 0xE1A4: 0x8AA0, //CJK UNIFIED IDEOGRAPH + 0xE1A5: 0x9192, //CJK UNIFIED IDEOGRAPH + 0xE1A6: 0x4E16, //CJK UNIFIED IDEOGRAPH + 0xE1A7: 0x52E2, //CJK UNIFIED IDEOGRAPH + 0xE1A8: 0x6B72, //CJK UNIFIED IDEOGRAPH + 0xE1A9: 0x6D17, //CJK UNIFIED IDEOGRAPH + 0xE1AA: 0x7A05, //CJK UNIFIED IDEOGRAPH + 0xE1AB: 0x7B39, //CJK UNIFIED IDEOGRAPH + 0xE1AC: 0x7D30, //CJK UNIFIED IDEOGRAPH + 0xE1AD: 0xF96F, //CJK COMPATIBILITY IDEOGRAPH + 0xE1AE: 0x8CB0, //CJK UNIFIED IDEOGRAPH + 0xE1AF: 0x53EC, //CJK UNIFIED IDEOGRAPH + 0xE1B0: 0x562F, //CJK UNIFIED IDEOGRAPH + 0xE1B1: 0x5851, //CJK UNIFIED IDEOGRAPH + 0xE1B2: 0x5BB5, //CJK UNIFIED IDEOGRAPH + 0xE1B3: 0x5C0F, //CJK UNIFIED IDEOGRAPH + 0xE1B4: 0x5C11, //CJK UNIFIED IDEOGRAPH + 0xE1B5: 0x5DE2, //CJK UNIFIED IDEOGRAPH + 0xE1B6: 0x6240, //CJK UNIFIED IDEOGRAPH + 0xE1B7: 0x6383, //CJK UNIFIED IDEOGRAPH + 0xE1B8: 0x6414, //CJK UNIFIED IDEOGRAPH + 0xE1B9: 0x662D, //CJK UNIFIED IDEOGRAPH + 0xE1BA: 0x68B3, //CJK UNIFIED IDEOGRAPH + 0xE1BB: 0x6CBC, //CJK UNIFIED IDEOGRAPH + 0xE1BC: 0x6D88, //CJK UNIFIED IDEOGRAPH + 0xE1BD: 0x6EAF, //CJK UNIFIED IDEOGRAPH + 0xE1BE: 0x701F, //CJK UNIFIED IDEOGRAPH + 0xE1BF: 0x70A4, //CJK UNIFIED IDEOGRAPH + 0xE1C0: 0x71D2, //CJK UNIFIED IDEOGRAPH + 0xE1C1: 0x7526, //CJK UNIFIED IDEOGRAPH + 0xE1C2: 0x758F, //CJK UNIFIED IDEOGRAPH + 0xE1C3: 0x758E, //CJK UNIFIED IDEOGRAPH + 0xE1C4: 0x7619, //CJK UNIFIED IDEOGRAPH + 0xE1C5: 0x7B11, //CJK UNIFIED IDEOGRAPH + 0xE1C6: 0x7BE0, //CJK UNIFIED IDEOGRAPH + 0xE1C7: 0x7C2B, //CJK UNIFIED IDEOGRAPH + 0xE1C8: 0x7D20, //CJK UNIFIED IDEOGRAPH + 0xE1C9: 0x7D39, //CJK UNIFIED IDEOGRAPH + 0xE1CA: 0x852C, //CJK UNIFIED IDEOGRAPH + 0xE1CB: 0x856D, //CJK UNIFIED IDEOGRAPH + 0xE1CC: 0x8607, //CJK UNIFIED IDEOGRAPH + 0xE1CD: 0x8A34, //CJK UNIFIED IDEOGRAPH + 0xE1CE: 0x900D, //CJK UNIFIED IDEOGRAPH + 0xE1CF: 0x9061, //CJK UNIFIED IDEOGRAPH + 0xE1D0: 0x90B5, //CJK UNIFIED IDEOGRAPH + 0xE1D1: 0x92B7, //CJK UNIFIED IDEOGRAPH + 0xE1D2: 0x97F6, //CJK UNIFIED IDEOGRAPH + 0xE1D3: 0x9A37, //CJK UNIFIED IDEOGRAPH + 0xE1D4: 0x4FD7, //CJK UNIFIED IDEOGRAPH + 0xE1D5: 0x5C6C, //CJK UNIFIED IDEOGRAPH + 0xE1D6: 0x675F, //CJK UNIFIED IDEOGRAPH + 0xE1D7: 0x6D91, //CJK UNIFIED IDEOGRAPH + 0xE1D8: 0x7C9F, //CJK UNIFIED IDEOGRAPH + 0xE1D9: 0x7E8C, //CJK UNIFIED IDEOGRAPH + 0xE1DA: 0x8B16, //CJK UNIFIED IDEOGRAPH + 0xE1DB: 0x8D16, //CJK UNIFIED IDEOGRAPH + 0xE1DC: 0x901F, //CJK UNIFIED IDEOGRAPH + 0xE1DD: 0x5B6B, //CJK UNIFIED IDEOGRAPH + 0xE1DE: 0x5DFD, //CJK UNIFIED IDEOGRAPH + 0xE1DF: 0x640D, //CJK UNIFIED IDEOGRAPH + 0xE1E0: 0x84C0, //CJK UNIFIED IDEOGRAPH + 0xE1E1: 0x905C, //CJK UNIFIED IDEOGRAPH + 0xE1E2: 0x98E1, //CJK UNIFIED IDEOGRAPH + 0xE1E3: 0x7387, //CJK UNIFIED IDEOGRAPH + 0xE1E4: 0x5B8B, //CJK UNIFIED IDEOGRAPH + 0xE1E5: 0x609A, //CJK UNIFIED IDEOGRAPH + 0xE1E6: 0x677E, //CJK UNIFIED IDEOGRAPH + 0xE1E7: 0x6DDE, //CJK UNIFIED IDEOGRAPH + 0xE1E8: 0x8A1F, //CJK UNIFIED IDEOGRAPH + 0xE1E9: 0x8AA6, //CJK UNIFIED IDEOGRAPH + 0xE1EA: 0x9001, //CJK UNIFIED IDEOGRAPH + 0xE1EB: 0x980C, //CJK UNIFIED IDEOGRAPH + 0xE1EC: 0x5237, //CJK UNIFIED IDEOGRAPH + 0xE1ED: 0xF970, //CJK COMPATIBILITY IDEOGRAPH + 0xE1EE: 0x7051, //CJK UNIFIED IDEOGRAPH + 0xE1EF: 0x788E, //CJK UNIFIED IDEOGRAPH + 0xE1F0: 0x9396, //CJK UNIFIED IDEOGRAPH + 0xE1F1: 0x8870, //CJK UNIFIED IDEOGRAPH + 0xE1F2: 0x91D7, //CJK UNIFIED IDEOGRAPH + 0xE1F3: 0x4FEE, //CJK UNIFIED IDEOGRAPH + 0xE1F4: 0x53D7, //CJK UNIFIED IDEOGRAPH + 0xE1F5: 0x55FD, //CJK UNIFIED IDEOGRAPH + 0xE1F6: 0x56DA, //CJK UNIFIED IDEOGRAPH + 0xE1F7: 0x5782, //CJK UNIFIED IDEOGRAPH + 0xE1F8: 0x58FD, //CJK UNIFIED IDEOGRAPH + 0xE1F9: 0x5AC2, //CJK UNIFIED IDEOGRAPH + 0xE1FA: 0x5B88, //CJK UNIFIED IDEOGRAPH + 0xE1FB: 0x5CAB, //CJK UNIFIED IDEOGRAPH + 0xE1FC: 0x5CC0, //CJK UNIFIED IDEOGRAPH + 0xE1FD: 0x5E25, //CJK UNIFIED IDEOGRAPH + 0xE1FE: 0x6101, //CJK UNIFIED IDEOGRAPH + 0xE2A1: 0x620D, //CJK UNIFIED IDEOGRAPH + 0xE2A2: 0x624B, //CJK UNIFIED IDEOGRAPH + 0xE2A3: 0x6388, //CJK UNIFIED IDEOGRAPH + 0xE2A4: 0x641C, //CJK UNIFIED IDEOGRAPH + 0xE2A5: 0x6536, //CJK UNIFIED IDEOGRAPH + 0xE2A6: 0x6578, //CJK UNIFIED IDEOGRAPH + 0xE2A7: 0x6A39, //CJK UNIFIED IDEOGRAPH + 0xE2A8: 0x6B8A, //CJK UNIFIED IDEOGRAPH + 0xE2A9: 0x6C34, //CJK UNIFIED IDEOGRAPH + 0xE2AA: 0x6D19, //CJK UNIFIED IDEOGRAPH + 0xE2AB: 0x6F31, //CJK UNIFIED IDEOGRAPH + 0xE2AC: 0x71E7, //CJK UNIFIED IDEOGRAPH + 0xE2AD: 0x72E9, //CJK UNIFIED IDEOGRAPH + 0xE2AE: 0x7378, //CJK UNIFIED IDEOGRAPH + 0xE2AF: 0x7407, //CJK UNIFIED IDEOGRAPH + 0xE2B0: 0x74B2, //CJK UNIFIED IDEOGRAPH + 0xE2B1: 0x7626, //CJK UNIFIED IDEOGRAPH + 0xE2B2: 0x7761, //CJK UNIFIED IDEOGRAPH + 0xE2B3: 0x79C0, //CJK UNIFIED IDEOGRAPH + 0xE2B4: 0x7A57, //CJK UNIFIED IDEOGRAPH + 0xE2B5: 0x7AEA, //CJK UNIFIED IDEOGRAPH + 0xE2B6: 0x7CB9, //CJK UNIFIED IDEOGRAPH + 0xE2B7: 0x7D8F, //CJK UNIFIED IDEOGRAPH + 0xE2B8: 0x7DAC, //CJK UNIFIED IDEOGRAPH + 0xE2B9: 0x7E61, //CJK UNIFIED IDEOGRAPH + 0xE2BA: 0x7F9E, //CJK UNIFIED IDEOGRAPH + 0xE2BB: 0x8129, //CJK UNIFIED IDEOGRAPH + 0xE2BC: 0x8331, //CJK UNIFIED IDEOGRAPH + 0xE2BD: 0x8490, //CJK UNIFIED IDEOGRAPH + 0xE2BE: 0x84DA, //CJK UNIFIED IDEOGRAPH + 0xE2BF: 0x85EA, //CJK UNIFIED IDEOGRAPH + 0xE2C0: 0x8896, //CJK UNIFIED IDEOGRAPH + 0xE2C1: 0x8AB0, //CJK UNIFIED IDEOGRAPH + 0xE2C2: 0x8B90, //CJK UNIFIED IDEOGRAPH + 0xE2C3: 0x8F38, //CJK UNIFIED IDEOGRAPH + 0xE2C4: 0x9042, //CJK UNIFIED IDEOGRAPH + 0xE2C5: 0x9083, //CJK UNIFIED IDEOGRAPH + 0xE2C6: 0x916C, //CJK UNIFIED IDEOGRAPH + 0xE2C7: 0x9296, //CJK UNIFIED IDEOGRAPH + 0xE2C8: 0x92B9, //CJK UNIFIED IDEOGRAPH + 0xE2C9: 0x968B, //CJK UNIFIED IDEOGRAPH + 0xE2CA: 0x96A7, //CJK UNIFIED IDEOGRAPH + 0xE2CB: 0x96A8, //CJK UNIFIED IDEOGRAPH + 0xE2CC: 0x96D6, //CJK UNIFIED IDEOGRAPH + 0xE2CD: 0x9700, //CJK UNIFIED IDEOGRAPH + 0xE2CE: 0x9808, //CJK UNIFIED IDEOGRAPH + 0xE2CF: 0x9996, //CJK UNIFIED IDEOGRAPH + 0xE2D0: 0x9AD3, //CJK UNIFIED IDEOGRAPH + 0xE2D1: 0x9B1A, //CJK UNIFIED IDEOGRAPH + 0xE2D2: 0x53D4, //CJK UNIFIED IDEOGRAPH + 0xE2D3: 0x587E, //CJK UNIFIED IDEOGRAPH + 0xE2D4: 0x5919, //CJK UNIFIED IDEOGRAPH + 0xE2D5: 0x5B70, //CJK UNIFIED IDEOGRAPH + 0xE2D6: 0x5BBF, //CJK UNIFIED IDEOGRAPH + 0xE2D7: 0x6DD1, //CJK UNIFIED IDEOGRAPH + 0xE2D8: 0x6F5A, //CJK UNIFIED IDEOGRAPH + 0xE2D9: 0x719F, //CJK UNIFIED IDEOGRAPH + 0xE2DA: 0x7421, //CJK UNIFIED IDEOGRAPH + 0xE2DB: 0x74B9, //CJK UNIFIED IDEOGRAPH + 0xE2DC: 0x8085, //CJK UNIFIED IDEOGRAPH + 0xE2DD: 0x83FD, //CJK UNIFIED IDEOGRAPH + 0xE2DE: 0x5DE1, //CJK UNIFIED IDEOGRAPH + 0xE2DF: 0x5F87, //CJK UNIFIED IDEOGRAPH + 0xE2E0: 0x5FAA, //CJK UNIFIED IDEOGRAPH + 0xE2E1: 0x6042, //CJK UNIFIED IDEOGRAPH + 0xE2E2: 0x65EC, //CJK UNIFIED IDEOGRAPH + 0xE2E3: 0x6812, //CJK UNIFIED IDEOGRAPH + 0xE2E4: 0x696F, //CJK UNIFIED IDEOGRAPH + 0xE2E5: 0x6A53, //CJK UNIFIED IDEOGRAPH + 0xE2E6: 0x6B89, //CJK UNIFIED IDEOGRAPH + 0xE2E7: 0x6D35, //CJK UNIFIED IDEOGRAPH + 0xE2E8: 0x6DF3, //CJK UNIFIED IDEOGRAPH + 0xE2E9: 0x73E3, //CJK UNIFIED IDEOGRAPH + 0xE2EA: 0x76FE, //CJK UNIFIED IDEOGRAPH + 0xE2EB: 0x77AC, //CJK UNIFIED IDEOGRAPH + 0xE2EC: 0x7B4D, //CJK UNIFIED IDEOGRAPH + 0xE2ED: 0x7D14, //CJK UNIFIED IDEOGRAPH + 0xE2EE: 0x8123, //CJK UNIFIED IDEOGRAPH + 0xE2EF: 0x821C, //CJK UNIFIED IDEOGRAPH + 0xE2F0: 0x8340, //CJK UNIFIED IDEOGRAPH + 0xE2F1: 0x84F4, //CJK UNIFIED IDEOGRAPH + 0xE2F2: 0x8563, //CJK UNIFIED IDEOGRAPH + 0xE2F3: 0x8A62, //CJK UNIFIED IDEOGRAPH + 0xE2F4: 0x8AC4, //CJK UNIFIED IDEOGRAPH + 0xE2F5: 0x9187, //CJK UNIFIED IDEOGRAPH + 0xE2F6: 0x931E, //CJK UNIFIED IDEOGRAPH + 0xE2F7: 0x9806, //CJK UNIFIED IDEOGRAPH + 0xE2F8: 0x99B4, //CJK UNIFIED IDEOGRAPH + 0xE2F9: 0x620C, //CJK UNIFIED IDEOGRAPH + 0xE2FA: 0x8853, //CJK UNIFIED IDEOGRAPH + 0xE2FB: 0x8FF0, //CJK UNIFIED IDEOGRAPH + 0xE2FC: 0x9265, //CJK UNIFIED IDEOGRAPH + 0xE2FD: 0x5D07, //CJK UNIFIED IDEOGRAPH + 0xE2FE: 0x5D27, //CJK UNIFIED IDEOGRAPH + 0xE3A1: 0x5D69, //CJK UNIFIED IDEOGRAPH + 0xE3A2: 0x745F, //CJK UNIFIED IDEOGRAPH + 0xE3A3: 0x819D, //CJK UNIFIED IDEOGRAPH + 0xE3A4: 0x8768, //CJK UNIFIED IDEOGRAPH + 0xE3A5: 0x6FD5, //CJK UNIFIED IDEOGRAPH + 0xE3A6: 0x62FE, //CJK UNIFIED IDEOGRAPH + 0xE3A7: 0x7FD2, //CJK UNIFIED IDEOGRAPH + 0xE3A8: 0x8936, //CJK UNIFIED IDEOGRAPH + 0xE3A9: 0x8972, //CJK UNIFIED IDEOGRAPH + 0xE3AA: 0x4E1E, //CJK UNIFIED IDEOGRAPH + 0xE3AB: 0x4E58, //CJK UNIFIED IDEOGRAPH + 0xE3AC: 0x50E7, //CJK UNIFIED IDEOGRAPH + 0xE3AD: 0x52DD, //CJK UNIFIED IDEOGRAPH + 0xE3AE: 0x5347, //CJK UNIFIED IDEOGRAPH + 0xE3AF: 0x627F, //CJK UNIFIED IDEOGRAPH + 0xE3B0: 0x6607, //CJK UNIFIED IDEOGRAPH + 0xE3B1: 0x7E69, //CJK UNIFIED IDEOGRAPH + 0xE3B2: 0x8805, //CJK UNIFIED IDEOGRAPH + 0xE3B3: 0x965E, //CJK UNIFIED IDEOGRAPH + 0xE3B4: 0x4F8D, //CJK UNIFIED IDEOGRAPH + 0xE3B5: 0x5319, //CJK UNIFIED IDEOGRAPH + 0xE3B6: 0x5636, //CJK UNIFIED IDEOGRAPH + 0xE3B7: 0x59CB, //CJK UNIFIED IDEOGRAPH + 0xE3B8: 0x5AA4, //CJK UNIFIED IDEOGRAPH + 0xE3B9: 0x5C38, //CJK UNIFIED IDEOGRAPH + 0xE3BA: 0x5C4E, //CJK UNIFIED IDEOGRAPH + 0xE3BB: 0x5C4D, //CJK UNIFIED IDEOGRAPH + 0xE3BC: 0x5E02, //CJK UNIFIED IDEOGRAPH + 0xE3BD: 0x5F11, //CJK UNIFIED IDEOGRAPH + 0xE3BE: 0x6043, //CJK UNIFIED IDEOGRAPH + 0xE3BF: 0x65BD, //CJK UNIFIED IDEOGRAPH + 0xE3C0: 0x662F, //CJK UNIFIED IDEOGRAPH + 0xE3C1: 0x6642, //CJK UNIFIED IDEOGRAPH + 0xE3C2: 0x67BE, //CJK UNIFIED IDEOGRAPH + 0xE3C3: 0x67F4, //CJK UNIFIED IDEOGRAPH + 0xE3C4: 0x731C, //CJK UNIFIED IDEOGRAPH + 0xE3C5: 0x77E2, //CJK UNIFIED IDEOGRAPH + 0xE3C6: 0x793A, //CJK UNIFIED IDEOGRAPH + 0xE3C7: 0x7FC5, //CJK UNIFIED IDEOGRAPH + 0xE3C8: 0x8494, //CJK UNIFIED IDEOGRAPH + 0xE3C9: 0x84CD, //CJK UNIFIED IDEOGRAPH + 0xE3CA: 0x8996, //CJK UNIFIED IDEOGRAPH + 0xE3CB: 0x8A66, //CJK UNIFIED IDEOGRAPH + 0xE3CC: 0x8A69, //CJK UNIFIED IDEOGRAPH + 0xE3CD: 0x8AE1, //CJK UNIFIED IDEOGRAPH + 0xE3CE: 0x8C55, //CJK UNIFIED IDEOGRAPH + 0xE3CF: 0x8C7A, //CJK UNIFIED IDEOGRAPH + 0xE3D0: 0x57F4, //CJK UNIFIED IDEOGRAPH + 0xE3D1: 0x5BD4, //CJK UNIFIED IDEOGRAPH + 0xE3D2: 0x5F0F, //CJK UNIFIED IDEOGRAPH + 0xE3D3: 0x606F, //CJK UNIFIED IDEOGRAPH + 0xE3D4: 0x62ED, //CJK UNIFIED IDEOGRAPH + 0xE3D5: 0x690D, //CJK UNIFIED IDEOGRAPH + 0xE3D6: 0x6B96, //CJK UNIFIED IDEOGRAPH + 0xE3D7: 0x6E5C, //CJK UNIFIED IDEOGRAPH + 0xE3D8: 0x7184, //CJK UNIFIED IDEOGRAPH + 0xE3D9: 0x7BD2, //CJK UNIFIED IDEOGRAPH + 0xE3DA: 0x8755, //CJK UNIFIED IDEOGRAPH + 0xE3DB: 0x8B58, //CJK UNIFIED IDEOGRAPH + 0xE3DC: 0x8EFE, //CJK UNIFIED IDEOGRAPH + 0xE3DD: 0x98DF, //CJK UNIFIED IDEOGRAPH + 0xE3DE: 0x98FE, //CJK UNIFIED IDEOGRAPH + 0xE3DF: 0x4F38, //CJK UNIFIED IDEOGRAPH + 0xE3E0: 0x4F81, //CJK UNIFIED IDEOGRAPH + 0xE3E1: 0x4FE1, //CJK UNIFIED IDEOGRAPH + 0xE3E2: 0x547B, //CJK UNIFIED IDEOGRAPH + 0xE3E3: 0x5A20, //CJK UNIFIED IDEOGRAPH + 0xE3E4: 0x5BB8, //CJK UNIFIED IDEOGRAPH + 0xE3E5: 0x613C, //CJK UNIFIED IDEOGRAPH + 0xE3E6: 0x65B0, //CJK UNIFIED IDEOGRAPH + 0xE3E7: 0x6668, //CJK UNIFIED IDEOGRAPH + 0xE3E8: 0x71FC, //CJK UNIFIED IDEOGRAPH + 0xE3E9: 0x7533, //CJK UNIFIED IDEOGRAPH + 0xE3EA: 0x795E, //CJK UNIFIED IDEOGRAPH + 0xE3EB: 0x7D33, //CJK UNIFIED IDEOGRAPH + 0xE3EC: 0x814E, //CJK UNIFIED IDEOGRAPH + 0xE3ED: 0x81E3, //CJK UNIFIED IDEOGRAPH + 0xE3EE: 0x8398, //CJK UNIFIED IDEOGRAPH + 0xE3EF: 0x85AA, //CJK UNIFIED IDEOGRAPH + 0xE3F0: 0x85CE, //CJK UNIFIED IDEOGRAPH + 0xE3F1: 0x8703, //CJK UNIFIED IDEOGRAPH + 0xE3F2: 0x8A0A, //CJK UNIFIED IDEOGRAPH + 0xE3F3: 0x8EAB, //CJK UNIFIED IDEOGRAPH + 0xE3F4: 0x8F9B, //CJK UNIFIED IDEOGRAPH + 0xE3F5: 0xF971, //CJK COMPATIBILITY IDEOGRAPH + 0xE3F6: 0x8FC5, //CJK UNIFIED IDEOGRAPH + 0xE3F7: 0x5931, //CJK UNIFIED IDEOGRAPH + 0xE3F8: 0x5BA4, //CJK UNIFIED IDEOGRAPH + 0xE3F9: 0x5BE6, //CJK UNIFIED IDEOGRAPH + 0xE3FA: 0x6089, //CJK UNIFIED IDEOGRAPH + 0xE3FB: 0x5BE9, //CJK UNIFIED IDEOGRAPH + 0xE3FC: 0x5C0B, //CJK UNIFIED IDEOGRAPH + 0xE3FD: 0x5FC3, //CJK UNIFIED IDEOGRAPH + 0xE3FE: 0x6C81, //CJK UNIFIED IDEOGRAPH + 0xE4A1: 0xF972, //CJK COMPATIBILITY IDEOGRAPH + 0xE4A2: 0x6DF1, //CJK UNIFIED IDEOGRAPH + 0xE4A3: 0x700B, //CJK UNIFIED IDEOGRAPH + 0xE4A4: 0x751A, //CJK UNIFIED IDEOGRAPH + 0xE4A5: 0x82AF, //CJK UNIFIED IDEOGRAPH + 0xE4A6: 0x8AF6, //CJK UNIFIED IDEOGRAPH + 0xE4A7: 0x4EC0, //CJK UNIFIED IDEOGRAPH + 0xE4A8: 0x5341, //CJK UNIFIED IDEOGRAPH + 0xE4A9: 0xF973, //CJK COMPATIBILITY IDEOGRAPH + 0xE4AA: 0x96D9, //CJK UNIFIED IDEOGRAPH + 0xE4AB: 0x6C0F, //CJK UNIFIED IDEOGRAPH + 0xE4AC: 0x4E9E, //CJK UNIFIED IDEOGRAPH + 0xE4AD: 0x4FC4, //CJK UNIFIED IDEOGRAPH + 0xE4AE: 0x5152, //CJK UNIFIED IDEOGRAPH + 0xE4AF: 0x555E, //CJK UNIFIED IDEOGRAPH + 0xE4B0: 0x5A25, //CJK UNIFIED IDEOGRAPH + 0xE4B1: 0x5CE8, //CJK UNIFIED IDEOGRAPH + 0xE4B2: 0x6211, //CJK UNIFIED IDEOGRAPH + 0xE4B3: 0x7259, //CJK UNIFIED IDEOGRAPH + 0xE4B4: 0x82BD, //CJK UNIFIED IDEOGRAPH + 0xE4B5: 0x83AA, //CJK UNIFIED IDEOGRAPH + 0xE4B6: 0x86FE, //CJK UNIFIED IDEOGRAPH + 0xE4B7: 0x8859, //CJK UNIFIED IDEOGRAPH + 0xE4B8: 0x8A1D, //CJK UNIFIED IDEOGRAPH + 0xE4B9: 0x963F, //CJK UNIFIED IDEOGRAPH + 0xE4BA: 0x96C5, //CJK UNIFIED IDEOGRAPH + 0xE4BB: 0x9913, //CJK UNIFIED IDEOGRAPH + 0xE4BC: 0x9D09, //CJK UNIFIED IDEOGRAPH + 0xE4BD: 0x9D5D, //CJK UNIFIED IDEOGRAPH + 0xE4BE: 0x580A, //CJK UNIFIED IDEOGRAPH + 0xE4BF: 0x5CB3, //CJK UNIFIED IDEOGRAPH + 0xE4C0: 0x5DBD, //CJK UNIFIED IDEOGRAPH + 0xE4C1: 0x5E44, //CJK UNIFIED IDEOGRAPH + 0xE4C2: 0x60E1, //CJK UNIFIED IDEOGRAPH + 0xE4C3: 0x6115, //CJK UNIFIED IDEOGRAPH + 0xE4C4: 0x63E1, //CJK UNIFIED IDEOGRAPH + 0xE4C5: 0x6A02, //CJK UNIFIED IDEOGRAPH + 0xE4C6: 0x6E25, //CJK UNIFIED IDEOGRAPH + 0xE4C7: 0x9102, //CJK UNIFIED IDEOGRAPH + 0xE4C8: 0x9354, //CJK UNIFIED IDEOGRAPH + 0xE4C9: 0x984E, //CJK UNIFIED IDEOGRAPH + 0xE4CA: 0x9C10, //CJK UNIFIED IDEOGRAPH + 0xE4CB: 0x9F77, //CJK UNIFIED IDEOGRAPH + 0xE4CC: 0x5B89, //CJK UNIFIED IDEOGRAPH + 0xE4CD: 0x5CB8, //CJK UNIFIED IDEOGRAPH + 0xE4CE: 0x6309, //CJK UNIFIED IDEOGRAPH + 0xE4CF: 0x664F, //CJK UNIFIED IDEOGRAPH + 0xE4D0: 0x6848, //CJK UNIFIED IDEOGRAPH + 0xE4D1: 0x773C, //CJK UNIFIED IDEOGRAPH + 0xE4D2: 0x96C1, //CJK UNIFIED IDEOGRAPH + 0xE4D3: 0x978D, //CJK UNIFIED IDEOGRAPH + 0xE4D4: 0x9854, //CJK UNIFIED IDEOGRAPH + 0xE4D5: 0x9B9F, //CJK UNIFIED IDEOGRAPH + 0xE4D6: 0x65A1, //CJK UNIFIED IDEOGRAPH + 0xE4D7: 0x8B01, //CJK UNIFIED IDEOGRAPH + 0xE4D8: 0x8ECB, //CJK UNIFIED IDEOGRAPH + 0xE4D9: 0x95BC, //CJK UNIFIED IDEOGRAPH + 0xE4DA: 0x5535, //CJK UNIFIED IDEOGRAPH + 0xE4DB: 0x5CA9, //CJK UNIFIED IDEOGRAPH + 0xE4DC: 0x5DD6, //CJK UNIFIED IDEOGRAPH + 0xE4DD: 0x5EB5, //CJK UNIFIED IDEOGRAPH + 0xE4DE: 0x6697, //CJK UNIFIED IDEOGRAPH + 0xE4DF: 0x764C, //CJK UNIFIED IDEOGRAPH + 0xE4E0: 0x83F4, //CJK UNIFIED IDEOGRAPH + 0xE4E1: 0x95C7, //CJK UNIFIED IDEOGRAPH + 0xE4E2: 0x58D3, //CJK UNIFIED IDEOGRAPH + 0xE4E3: 0x62BC, //CJK UNIFIED IDEOGRAPH + 0xE4E4: 0x72CE, //CJK UNIFIED IDEOGRAPH + 0xE4E5: 0x9D28, //CJK UNIFIED IDEOGRAPH + 0xE4E6: 0x4EF0, //CJK UNIFIED IDEOGRAPH + 0xE4E7: 0x592E, //CJK UNIFIED IDEOGRAPH + 0xE4E8: 0x600F, //CJK UNIFIED IDEOGRAPH + 0xE4E9: 0x663B, //CJK UNIFIED IDEOGRAPH + 0xE4EA: 0x6B83, //CJK UNIFIED IDEOGRAPH + 0xE4EB: 0x79E7, //CJK UNIFIED IDEOGRAPH + 0xE4EC: 0x9D26, //CJK UNIFIED IDEOGRAPH + 0xE4ED: 0x5393, //CJK UNIFIED IDEOGRAPH + 0xE4EE: 0x54C0, //CJK UNIFIED IDEOGRAPH + 0xE4EF: 0x57C3, //CJK UNIFIED IDEOGRAPH + 0xE4F0: 0x5D16, //CJK UNIFIED IDEOGRAPH + 0xE4F1: 0x611B, //CJK UNIFIED IDEOGRAPH + 0xE4F2: 0x66D6, //CJK UNIFIED IDEOGRAPH + 0xE4F3: 0x6DAF, //CJK UNIFIED IDEOGRAPH + 0xE4F4: 0x788D, //CJK UNIFIED IDEOGRAPH + 0xE4F5: 0x827E, //CJK UNIFIED IDEOGRAPH + 0xE4F6: 0x9698, //CJK UNIFIED IDEOGRAPH + 0xE4F7: 0x9744, //CJK UNIFIED IDEOGRAPH + 0xE4F8: 0x5384, //CJK UNIFIED IDEOGRAPH + 0xE4F9: 0x627C, //CJK UNIFIED IDEOGRAPH + 0xE4FA: 0x6396, //CJK UNIFIED IDEOGRAPH + 0xE4FB: 0x6DB2, //CJK UNIFIED IDEOGRAPH + 0xE4FC: 0x7E0A, //CJK UNIFIED IDEOGRAPH + 0xE4FD: 0x814B, //CJK UNIFIED IDEOGRAPH + 0xE4FE: 0x984D, //CJK UNIFIED IDEOGRAPH + 0xE5A1: 0x6AFB, //CJK UNIFIED IDEOGRAPH + 0xE5A2: 0x7F4C, //CJK UNIFIED IDEOGRAPH + 0xE5A3: 0x9DAF, //CJK UNIFIED IDEOGRAPH + 0xE5A4: 0x9E1A, //CJK UNIFIED IDEOGRAPH + 0xE5A5: 0x4E5F, //CJK UNIFIED IDEOGRAPH + 0xE5A6: 0x503B, //CJK UNIFIED IDEOGRAPH + 0xE5A7: 0x51B6, //CJK UNIFIED IDEOGRAPH + 0xE5A8: 0x591C, //CJK UNIFIED IDEOGRAPH + 0xE5A9: 0x60F9, //CJK UNIFIED IDEOGRAPH + 0xE5AA: 0x63F6, //CJK UNIFIED IDEOGRAPH + 0xE5AB: 0x6930, //CJK UNIFIED IDEOGRAPH + 0xE5AC: 0x723A, //CJK UNIFIED IDEOGRAPH + 0xE5AD: 0x8036, //CJK UNIFIED IDEOGRAPH + 0xE5AE: 0xF974, //CJK COMPATIBILITY IDEOGRAPH + 0xE5AF: 0x91CE, //CJK UNIFIED IDEOGRAPH + 0xE5B0: 0x5F31, //CJK UNIFIED IDEOGRAPH + 0xE5B1: 0xF975, //CJK COMPATIBILITY IDEOGRAPH + 0xE5B2: 0xF976, //CJK COMPATIBILITY IDEOGRAPH + 0xE5B3: 0x7D04, //CJK UNIFIED IDEOGRAPH + 0xE5B4: 0x82E5, //CJK UNIFIED IDEOGRAPH + 0xE5B5: 0x846F, //CJK UNIFIED IDEOGRAPH + 0xE5B6: 0x84BB, //CJK UNIFIED IDEOGRAPH + 0xE5B7: 0x85E5, //CJK UNIFIED IDEOGRAPH + 0xE5B8: 0x8E8D, //CJK UNIFIED IDEOGRAPH + 0xE5B9: 0xF977, //CJK COMPATIBILITY IDEOGRAPH + 0xE5BA: 0x4F6F, //CJK UNIFIED IDEOGRAPH + 0xE5BB: 0xF978, //CJK COMPATIBILITY IDEOGRAPH + 0xE5BC: 0xF979, //CJK COMPATIBILITY IDEOGRAPH + 0xE5BD: 0x58E4, //CJK UNIFIED IDEOGRAPH + 0xE5BE: 0x5B43, //CJK UNIFIED IDEOGRAPH + 0xE5BF: 0x6059, //CJK UNIFIED IDEOGRAPH + 0xE5C0: 0x63DA, //CJK UNIFIED IDEOGRAPH + 0xE5C1: 0x6518, //CJK UNIFIED IDEOGRAPH + 0xE5C2: 0x656D, //CJK UNIFIED IDEOGRAPH + 0xE5C3: 0x6698, //CJK UNIFIED IDEOGRAPH + 0xE5C4: 0xF97A, //CJK COMPATIBILITY IDEOGRAPH + 0xE5C5: 0x694A, //CJK UNIFIED IDEOGRAPH + 0xE5C6: 0x6A23, //CJK UNIFIED IDEOGRAPH + 0xE5C7: 0x6D0B, //CJK UNIFIED IDEOGRAPH + 0xE5C8: 0x7001, //CJK UNIFIED IDEOGRAPH + 0xE5C9: 0x716C, //CJK UNIFIED IDEOGRAPH + 0xE5CA: 0x75D2, //CJK UNIFIED IDEOGRAPH + 0xE5CB: 0x760D, //CJK UNIFIED IDEOGRAPH + 0xE5CC: 0x79B3, //CJK UNIFIED IDEOGRAPH + 0xE5CD: 0x7A70, //CJK UNIFIED IDEOGRAPH + 0xE5CE: 0xF97B, //CJK COMPATIBILITY IDEOGRAPH + 0xE5CF: 0x7F8A, //CJK UNIFIED IDEOGRAPH + 0xE5D0: 0xF97C, //CJK COMPATIBILITY IDEOGRAPH + 0xE5D1: 0x8944, //CJK UNIFIED IDEOGRAPH + 0xE5D2: 0xF97D, //CJK COMPATIBILITY IDEOGRAPH + 0xE5D3: 0x8B93, //CJK UNIFIED IDEOGRAPH + 0xE5D4: 0x91C0, //CJK UNIFIED IDEOGRAPH + 0xE5D5: 0x967D, //CJK UNIFIED IDEOGRAPH + 0xE5D6: 0xF97E, //CJK COMPATIBILITY IDEOGRAPH + 0xE5D7: 0x990A, //CJK UNIFIED IDEOGRAPH + 0xE5D8: 0x5704, //CJK UNIFIED IDEOGRAPH + 0xE5D9: 0x5FA1, //CJK UNIFIED IDEOGRAPH + 0xE5DA: 0x65BC, //CJK UNIFIED IDEOGRAPH + 0xE5DB: 0x6F01, //CJK UNIFIED IDEOGRAPH + 0xE5DC: 0x7600, //CJK UNIFIED IDEOGRAPH + 0xE5DD: 0x79A6, //CJK UNIFIED IDEOGRAPH + 0xE5DE: 0x8A9E, //CJK UNIFIED IDEOGRAPH + 0xE5DF: 0x99AD, //CJK UNIFIED IDEOGRAPH + 0xE5E0: 0x9B5A, //CJK UNIFIED IDEOGRAPH + 0xE5E1: 0x9F6C, //CJK UNIFIED IDEOGRAPH + 0xE5E2: 0x5104, //CJK UNIFIED IDEOGRAPH + 0xE5E3: 0x61B6, //CJK UNIFIED IDEOGRAPH + 0xE5E4: 0x6291, //CJK UNIFIED IDEOGRAPH + 0xE5E5: 0x6A8D, //CJK UNIFIED IDEOGRAPH + 0xE5E6: 0x81C6, //CJK UNIFIED IDEOGRAPH + 0xE5E7: 0x5043, //CJK UNIFIED IDEOGRAPH + 0xE5E8: 0x5830, //CJK UNIFIED IDEOGRAPH + 0xE5E9: 0x5F66, //CJK UNIFIED IDEOGRAPH + 0xE5EA: 0x7109, //CJK UNIFIED IDEOGRAPH + 0xE5EB: 0x8A00, //CJK UNIFIED IDEOGRAPH + 0xE5EC: 0x8AFA, //CJK UNIFIED IDEOGRAPH + 0xE5ED: 0x5B7C, //CJK UNIFIED IDEOGRAPH + 0xE5EE: 0x8616, //CJK UNIFIED IDEOGRAPH + 0xE5EF: 0x4FFA, //CJK UNIFIED IDEOGRAPH + 0xE5F0: 0x513C, //CJK UNIFIED IDEOGRAPH + 0xE5F1: 0x56B4, //CJK UNIFIED IDEOGRAPH + 0xE5F2: 0x5944, //CJK UNIFIED IDEOGRAPH + 0xE5F3: 0x63A9, //CJK UNIFIED IDEOGRAPH + 0xE5F4: 0x6DF9, //CJK UNIFIED IDEOGRAPH + 0xE5F5: 0x5DAA, //CJK UNIFIED IDEOGRAPH + 0xE5F6: 0x696D, //CJK UNIFIED IDEOGRAPH + 0xE5F7: 0x5186, //CJK UNIFIED IDEOGRAPH + 0xE5F8: 0x4E88, //CJK UNIFIED IDEOGRAPH + 0xE5F9: 0x4F59, //CJK UNIFIED IDEOGRAPH + 0xE5FA: 0xF97F, //CJK COMPATIBILITY IDEOGRAPH + 0xE5FB: 0xF980, //CJK COMPATIBILITY IDEOGRAPH + 0xE5FC: 0xF981, //CJK COMPATIBILITY IDEOGRAPH + 0xE5FD: 0x5982, //CJK UNIFIED IDEOGRAPH + 0xE5FE: 0xF982, //CJK COMPATIBILITY IDEOGRAPH + 0xE6A1: 0xF983, //CJK COMPATIBILITY IDEOGRAPH + 0xE6A2: 0x6B5F, //CJK UNIFIED IDEOGRAPH + 0xE6A3: 0x6C5D, //CJK UNIFIED IDEOGRAPH + 0xE6A4: 0xF984, //CJK COMPATIBILITY IDEOGRAPH + 0xE6A5: 0x74B5, //CJK UNIFIED IDEOGRAPH + 0xE6A6: 0x7916, //CJK UNIFIED IDEOGRAPH + 0xE6A7: 0xF985, //CJK COMPATIBILITY IDEOGRAPH + 0xE6A8: 0x8207, //CJK UNIFIED IDEOGRAPH + 0xE6A9: 0x8245, //CJK UNIFIED IDEOGRAPH + 0xE6AA: 0x8339, //CJK UNIFIED IDEOGRAPH + 0xE6AB: 0x8F3F, //CJK UNIFIED IDEOGRAPH + 0xE6AC: 0x8F5D, //CJK UNIFIED IDEOGRAPH + 0xE6AD: 0xF986, //CJK COMPATIBILITY IDEOGRAPH + 0xE6AE: 0x9918, //CJK UNIFIED IDEOGRAPH + 0xE6AF: 0xF987, //CJK COMPATIBILITY IDEOGRAPH + 0xE6B0: 0xF988, //CJK COMPATIBILITY IDEOGRAPH + 0xE6B1: 0xF989, //CJK COMPATIBILITY IDEOGRAPH + 0xE6B2: 0x4EA6, //CJK UNIFIED IDEOGRAPH + 0xE6B3: 0xF98A, //CJK COMPATIBILITY IDEOGRAPH + 0xE6B4: 0x57DF, //CJK UNIFIED IDEOGRAPH + 0xE6B5: 0x5F79, //CJK UNIFIED IDEOGRAPH + 0xE6B6: 0x6613, //CJK UNIFIED IDEOGRAPH + 0xE6B7: 0xF98B, //CJK COMPATIBILITY IDEOGRAPH + 0xE6B8: 0xF98C, //CJK COMPATIBILITY IDEOGRAPH + 0xE6B9: 0x75AB, //CJK UNIFIED IDEOGRAPH + 0xE6BA: 0x7E79, //CJK UNIFIED IDEOGRAPH + 0xE6BB: 0x8B6F, //CJK UNIFIED IDEOGRAPH + 0xE6BC: 0xF98D, //CJK COMPATIBILITY IDEOGRAPH + 0xE6BD: 0x9006, //CJK UNIFIED IDEOGRAPH + 0xE6BE: 0x9A5B, //CJK UNIFIED IDEOGRAPH + 0xE6BF: 0x56A5, //CJK UNIFIED IDEOGRAPH + 0xE6C0: 0x5827, //CJK UNIFIED IDEOGRAPH + 0xE6C1: 0x59F8, //CJK UNIFIED IDEOGRAPH + 0xE6C2: 0x5A1F, //CJK UNIFIED IDEOGRAPH + 0xE6C3: 0x5BB4, //CJK UNIFIED IDEOGRAPH + 0xE6C4: 0xF98E, //CJK COMPATIBILITY IDEOGRAPH + 0xE6C5: 0x5EF6, //CJK UNIFIED IDEOGRAPH + 0xE6C6: 0xF98F, //CJK COMPATIBILITY IDEOGRAPH + 0xE6C7: 0xF990, //CJK COMPATIBILITY IDEOGRAPH + 0xE6C8: 0x6350, //CJK UNIFIED IDEOGRAPH + 0xE6C9: 0x633B, //CJK UNIFIED IDEOGRAPH + 0xE6CA: 0xF991, //CJK COMPATIBILITY IDEOGRAPH + 0xE6CB: 0x693D, //CJK UNIFIED IDEOGRAPH + 0xE6CC: 0x6C87, //CJK UNIFIED IDEOGRAPH + 0xE6CD: 0x6CBF, //CJK UNIFIED IDEOGRAPH + 0xE6CE: 0x6D8E, //CJK UNIFIED IDEOGRAPH + 0xE6CF: 0x6D93, //CJK UNIFIED IDEOGRAPH + 0xE6D0: 0x6DF5, //CJK UNIFIED IDEOGRAPH + 0xE6D1: 0x6F14, //CJK UNIFIED IDEOGRAPH + 0xE6D2: 0xF992, //CJK COMPATIBILITY IDEOGRAPH + 0xE6D3: 0x70DF, //CJK UNIFIED IDEOGRAPH + 0xE6D4: 0x7136, //CJK UNIFIED IDEOGRAPH + 0xE6D5: 0x7159, //CJK UNIFIED IDEOGRAPH + 0xE6D6: 0xF993, //CJK COMPATIBILITY IDEOGRAPH + 0xE6D7: 0x71C3, //CJK UNIFIED IDEOGRAPH + 0xE6D8: 0x71D5, //CJK UNIFIED IDEOGRAPH + 0xE6D9: 0xF994, //CJK COMPATIBILITY IDEOGRAPH + 0xE6DA: 0x784F, //CJK UNIFIED IDEOGRAPH + 0xE6DB: 0x786F, //CJK UNIFIED IDEOGRAPH + 0xE6DC: 0xF995, //CJK COMPATIBILITY IDEOGRAPH + 0xE6DD: 0x7B75, //CJK UNIFIED IDEOGRAPH + 0xE6DE: 0x7DE3, //CJK UNIFIED IDEOGRAPH + 0xE6DF: 0xF996, //CJK COMPATIBILITY IDEOGRAPH + 0xE6E0: 0x7E2F, //CJK UNIFIED IDEOGRAPH + 0xE6E1: 0xF997, //CJK COMPATIBILITY IDEOGRAPH + 0xE6E2: 0x884D, //CJK UNIFIED IDEOGRAPH + 0xE6E3: 0x8EDF, //CJK UNIFIED IDEOGRAPH + 0xE6E4: 0xF998, //CJK COMPATIBILITY IDEOGRAPH + 0xE6E5: 0xF999, //CJK COMPATIBILITY IDEOGRAPH + 0xE6E6: 0xF99A, //CJK COMPATIBILITY IDEOGRAPH + 0xE6E7: 0x925B, //CJK UNIFIED IDEOGRAPH + 0xE6E8: 0xF99B, //CJK COMPATIBILITY IDEOGRAPH + 0xE6E9: 0x9CF6, //CJK UNIFIED IDEOGRAPH + 0xE6EA: 0xF99C, //CJK COMPATIBILITY IDEOGRAPH + 0xE6EB: 0xF99D, //CJK COMPATIBILITY IDEOGRAPH + 0xE6EC: 0xF99E, //CJK COMPATIBILITY IDEOGRAPH + 0xE6ED: 0x6085, //CJK UNIFIED IDEOGRAPH + 0xE6EE: 0x6D85, //CJK UNIFIED IDEOGRAPH + 0xE6EF: 0xF99F, //CJK COMPATIBILITY IDEOGRAPH + 0xE6F0: 0x71B1, //CJK UNIFIED IDEOGRAPH + 0xE6F1: 0xF9A0, //CJK COMPATIBILITY IDEOGRAPH + 0xE6F2: 0xF9A1, //CJK COMPATIBILITY IDEOGRAPH + 0xE6F3: 0x95B1, //CJK UNIFIED IDEOGRAPH + 0xE6F4: 0x53AD, //CJK UNIFIED IDEOGRAPH + 0xE6F5: 0xF9A2, //CJK COMPATIBILITY IDEOGRAPH + 0xE6F6: 0xF9A3, //CJK COMPATIBILITY IDEOGRAPH + 0xE6F7: 0xF9A4, //CJK COMPATIBILITY IDEOGRAPH + 0xE6F8: 0x67D3, //CJK UNIFIED IDEOGRAPH + 0xE6F9: 0xF9A5, //CJK COMPATIBILITY IDEOGRAPH + 0xE6FA: 0x708E, //CJK UNIFIED IDEOGRAPH + 0xE6FB: 0x7130, //CJK UNIFIED IDEOGRAPH + 0xE6FC: 0x7430, //CJK UNIFIED IDEOGRAPH + 0xE6FD: 0x8276, //CJK UNIFIED IDEOGRAPH + 0xE6FE: 0x82D2, //CJK UNIFIED IDEOGRAPH + 0xE7A1: 0xF9A6, //CJK COMPATIBILITY IDEOGRAPH + 0xE7A2: 0x95BB, //CJK UNIFIED IDEOGRAPH + 0xE7A3: 0x9AE5, //CJK UNIFIED IDEOGRAPH + 0xE7A4: 0x9E7D, //CJK UNIFIED IDEOGRAPH + 0xE7A5: 0x66C4, //CJK UNIFIED IDEOGRAPH + 0xE7A6: 0xF9A7, //CJK COMPATIBILITY IDEOGRAPH + 0xE7A7: 0x71C1, //CJK UNIFIED IDEOGRAPH + 0xE7A8: 0x8449, //CJK UNIFIED IDEOGRAPH + 0xE7A9: 0xF9A8, //CJK COMPATIBILITY IDEOGRAPH + 0xE7AA: 0xF9A9, //CJK COMPATIBILITY IDEOGRAPH + 0xE7AB: 0x584B, //CJK UNIFIED IDEOGRAPH + 0xE7AC: 0xF9AA, //CJK COMPATIBILITY IDEOGRAPH + 0xE7AD: 0xF9AB, //CJK COMPATIBILITY IDEOGRAPH + 0xE7AE: 0x5DB8, //CJK UNIFIED IDEOGRAPH + 0xE7AF: 0x5F71, //CJK UNIFIED IDEOGRAPH + 0xE7B0: 0xF9AC, //CJK COMPATIBILITY IDEOGRAPH + 0xE7B1: 0x6620, //CJK UNIFIED IDEOGRAPH + 0xE7B2: 0x668E, //CJK UNIFIED IDEOGRAPH + 0xE7B3: 0x6979, //CJK UNIFIED IDEOGRAPH + 0xE7B4: 0x69AE, //CJK UNIFIED IDEOGRAPH + 0xE7B5: 0x6C38, //CJK UNIFIED IDEOGRAPH + 0xE7B6: 0x6CF3, //CJK UNIFIED IDEOGRAPH + 0xE7B7: 0x6E36, //CJK UNIFIED IDEOGRAPH + 0xE7B8: 0x6F41, //CJK UNIFIED IDEOGRAPH + 0xE7B9: 0x6FDA, //CJK UNIFIED IDEOGRAPH + 0xE7BA: 0x701B, //CJK UNIFIED IDEOGRAPH + 0xE7BB: 0x702F, //CJK UNIFIED IDEOGRAPH + 0xE7BC: 0x7150, //CJK UNIFIED IDEOGRAPH + 0xE7BD: 0x71DF, //CJK UNIFIED IDEOGRAPH + 0xE7BE: 0x7370, //CJK UNIFIED IDEOGRAPH + 0xE7BF: 0xF9AD, //CJK COMPATIBILITY IDEOGRAPH + 0xE7C0: 0x745B, //CJK UNIFIED IDEOGRAPH + 0xE7C1: 0xF9AE, //CJK COMPATIBILITY IDEOGRAPH + 0xE7C2: 0x74D4, //CJK UNIFIED IDEOGRAPH + 0xE7C3: 0x76C8, //CJK UNIFIED IDEOGRAPH + 0xE7C4: 0x7A4E, //CJK UNIFIED IDEOGRAPH + 0xE7C5: 0x7E93, //CJK UNIFIED IDEOGRAPH + 0xE7C6: 0xF9AF, //CJK COMPATIBILITY IDEOGRAPH + 0xE7C7: 0xF9B0, //CJK COMPATIBILITY IDEOGRAPH + 0xE7C8: 0x82F1, //CJK UNIFIED IDEOGRAPH + 0xE7C9: 0x8A60, //CJK UNIFIED IDEOGRAPH + 0xE7CA: 0x8FCE, //CJK UNIFIED IDEOGRAPH + 0xE7CB: 0xF9B1, //CJK COMPATIBILITY IDEOGRAPH + 0xE7CC: 0x9348, //CJK UNIFIED IDEOGRAPH + 0xE7CD: 0xF9B2, //CJK COMPATIBILITY IDEOGRAPH + 0xE7CE: 0x9719, //CJK UNIFIED IDEOGRAPH + 0xE7CF: 0xF9B3, //CJK COMPATIBILITY IDEOGRAPH + 0xE7D0: 0xF9B4, //CJK COMPATIBILITY IDEOGRAPH + 0xE7D1: 0x4E42, //CJK UNIFIED IDEOGRAPH + 0xE7D2: 0x502A, //CJK UNIFIED IDEOGRAPH + 0xE7D3: 0xF9B5, //CJK COMPATIBILITY IDEOGRAPH + 0xE7D4: 0x5208, //CJK UNIFIED IDEOGRAPH + 0xE7D5: 0x53E1, //CJK UNIFIED IDEOGRAPH + 0xE7D6: 0x66F3, //CJK UNIFIED IDEOGRAPH + 0xE7D7: 0x6C6D, //CJK UNIFIED IDEOGRAPH + 0xE7D8: 0x6FCA, //CJK UNIFIED IDEOGRAPH + 0xE7D9: 0x730A, //CJK UNIFIED IDEOGRAPH + 0xE7DA: 0x777F, //CJK UNIFIED IDEOGRAPH + 0xE7DB: 0x7A62, //CJK UNIFIED IDEOGRAPH + 0xE7DC: 0x82AE, //CJK UNIFIED IDEOGRAPH + 0xE7DD: 0x85DD, //CJK UNIFIED IDEOGRAPH + 0xE7DE: 0x8602, //CJK UNIFIED IDEOGRAPH + 0xE7DF: 0xF9B6, //CJK COMPATIBILITY IDEOGRAPH + 0xE7E0: 0x88D4, //CJK UNIFIED IDEOGRAPH + 0xE7E1: 0x8A63, //CJK UNIFIED IDEOGRAPH + 0xE7E2: 0x8B7D, //CJK UNIFIED IDEOGRAPH + 0xE7E3: 0x8C6B, //CJK UNIFIED IDEOGRAPH + 0xE7E4: 0xF9B7, //CJK COMPATIBILITY IDEOGRAPH + 0xE7E5: 0x92B3, //CJK UNIFIED IDEOGRAPH + 0xE7E6: 0xF9B8, //CJK COMPATIBILITY IDEOGRAPH + 0xE7E7: 0x9713, //CJK UNIFIED IDEOGRAPH + 0xE7E8: 0x9810, //CJK UNIFIED IDEOGRAPH + 0xE7E9: 0x4E94, //CJK UNIFIED IDEOGRAPH + 0xE7EA: 0x4F0D, //CJK UNIFIED IDEOGRAPH + 0xE7EB: 0x4FC9, //CJK UNIFIED IDEOGRAPH + 0xE7EC: 0x50B2, //CJK UNIFIED IDEOGRAPH + 0xE7ED: 0x5348, //CJK UNIFIED IDEOGRAPH + 0xE7EE: 0x543E, //CJK UNIFIED IDEOGRAPH + 0xE7EF: 0x5433, //CJK UNIFIED IDEOGRAPH + 0xE7F0: 0x55DA, //CJK UNIFIED IDEOGRAPH + 0xE7F1: 0x5862, //CJK UNIFIED IDEOGRAPH + 0xE7F2: 0x58BA, //CJK UNIFIED IDEOGRAPH + 0xE7F3: 0x5967, //CJK UNIFIED IDEOGRAPH + 0xE7F4: 0x5A1B, //CJK UNIFIED IDEOGRAPH + 0xE7F5: 0x5BE4, //CJK UNIFIED IDEOGRAPH + 0xE7F6: 0x609F, //CJK UNIFIED IDEOGRAPH + 0xE7F7: 0xF9B9, //CJK COMPATIBILITY IDEOGRAPH + 0xE7F8: 0x61CA, //CJK UNIFIED IDEOGRAPH + 0xE7F9: 0x6556, //CJK UNIFIED IDEOGRAPH + 0xE7FA: 0x65FF, //CJK UNIFIED IDEOGRAPH + 0xE7FB: 0x6664, //CJK UNIFIED IDEOGRAPH + 0xE7FC: 0x68A7, //CJK UNIFIED IDEOGRAPH + 0xE7FD: 0x6C5A, //CJK UNIFIED IDEOGRAPH + 0xE7FE: 0x6FB3, //CJK UNIFIED IDEOGRAPH + 0xE8A1: 0x70CF, //CJK UNIFIED IDEOGRAPH + 0xE8A2: 0x71AC, //CJK UNIFIED IDEOGRAPH + 0xE8A3: 0x7352, //CJK UNIFIED IDEOGRAPH + 0xE8A4: 0x7B7D, //CJK UNIFIED IDEOGRAPH + 0xE8A5: 0x8708, //CJK UNIFIED IDEOGRAPH + 0xE8A6: 0x8AA4, //CJK UNIFIED IDEOGRAPH + 0xE8A7: 0x9C32, //CJK UNIFIED IDEOGRAPH + 0xE8A8: 0x9F07, //CJK UNIFIED IDEOGRAPH + 0xE8A9: 0x5C4B, //CJK UNIFIED IDEOGRAPH + 0xE8AA: 0x6C83, //CJK UNIFIED IDEOGRAPH + 0xE8AB: 0x7344, //CJK UNIFIED IDEOGRAPH + 0xE8AC: 0x7389, //CJK UNIFIED IDEOGRAPH + 0xE8AD: 0x923A, //CJK UNIFIED IDEOGRAPH + 0xE8AE: 0x6EAB, //CJK UNIFIED IDEOGRAPH + 0xE8AF: 0x7465, //CJK UNIFIED IDEOGRAPH + 0xE8B0: 0x761F, //CJK UNIFIED IDEOGRAPH + 0xE8B1: 0x7A69, //CJK UNIFIED IDEOGRAPH + 0xE8B2: 0x7E15, //CJK UNIFIED IDEOGRAPH + 0xE8B3: 0x860A, //CJK UNIFIED IDEOGRAPH + 0xE8B4: 0x5140, //CJK UNIFIED IDEOGRAPH + 0xE8B5: 0x58C5, //CJK UNIFIED IDEOGRAPH + 0xE8B6: 0x64C1, //CJK UNIFIED IDEOGRAPH + 0xE8B7: 0x74EE, //CJK UNIFIED IDEOGRAPH + 0xE8B8: 0x7515, //CJK UNIFIED IDEOGRAPH + 0xE8B9: 0x7670, //CJK UNIFIED IDEOGRAPH + 0xE8BA: 0x7FC1, //CJK UNIFIED IDEOGRAPH + 0xE8BB: 0x9095, //CJK UNIFIED IDEOGRAPH + 0xE8BC: 0x96CD, //CJK UNIFIED IDEOGRAPH + 0xE8BD: 0x9954, //CJK UNIFIED IDEOGRAPH + 0xE8BE: 0x6E26, //CJK UNIFIED IDEOGRAPH + 0xE8BF: 0x74E6, //CJK UNIFIED IDEOGRAPH + 0xE8C0: 0x7AA9, //CJK UNIFIED IDEOGRAPH + 0xE8C1: 0x7AAA, //CJK UNIFIED IDEOGRAPH + 0xE8C2: 0x81E5, //CJK UNIFIED IDEOGRAPH + 0xE8C3: 0x86D9, //CJK UNIFIED IDEOGRAPH + 0xE8C4: 0x8778, //CJK UNIFIED IDEOGRAPH + 0xE8C5: 0x8A1B, //CJK UNIFIED IDEOGRAPH + 0xE8C6: 0x5A49, //CJK UNIFIED IDEOGRAPH + 0xE8C7: 0x5B8C, //CJK UNIFIED IDEOGRAPH + 0xE8C8: 0x5B9B, //CJK UNIFIED IDEOGRAPH + 0xE8C9: 0x68A1, //CJK UNIFIED IDEOGRAPH + 0xE8CA: 0x6900, //CJK UNIFIED IDEOGRAPH + 0xE8CB: 0x6D63, //CJK UNIFIED IDEOGRAPH + 0xE8CC: 0x73A9, //CJK UNIFIED IDEOGRAPH + 0xE8CD: 0x7413, //CJK UNIFIED IDEOGRAPH + 0xE8CE: 0x742C, //CJK UNIFIED IDEOGRAPH + 0xE8CF: 0x7897, //CJK UNIFIED IDEOGRAPH + 0xE8D0: 0x7DE9, //CJK UNIFIED IDEOGRAPH + 0xE8D1: 0x7FEB, //CJK UNIFIED IDEOGRAPH + 0xE8D2: 0x8118, //CJK UNIFIED IDEOGRAPH + 0xE8D3: 0x8155, //CJK UNIFIED IDEOGRAPH + 0xE8D4: 0x839E, //CJK UNIFIED IDEOGRAPH + 0xE8D5: 0x8C4C, //CJK UNIFIED IDEOGRAPH + 0xE8D6: 0x962E, //CJK UNIFIED IDEOGRAPH + 0xE8D7: 0x9811, //CJK UNIFIED IDEOGRAPH + 0xE8D8: 0x66F0, //CJK UNIFIED IDEOGRAPH + 0xE8D9: 0x5F80, //CJK UNIFIED IDEOGRAPH + 0xE8DA: 0x65FA, //CJK UNIFIED IDEOGRAPH + 0xE8DB: 0x6789, //CJK UNIFIED IDEOGRAPH + 0xE8DC: 0x6C6A, //CJK UNIFIED IDEOGRAPH + 0xE8DD: 0x738B, //CJK UNIFIED IDEOGRAPH + 0xE8DE: 0x502D, //CJK UNIFIED IDEOGRAPH + 0xE8DF: 0x5A03, //CJK UNIFIED IDEOGRAPH + 0xE8E0: 0x6B6A, //CJK UNIFIED IDEOGRAPH + 0xE8E1: 0x77EE, //CJK UNIFIED IDEOGRAPH + 0xE8E2: 0x5916, //CJK UNIFIED IDEOGRAPH + 0xE8E3: 0x5D6C, //CJK UNIFIED IDEOGRAPH + 0xE8E4: 0x5DCD, //CJK UNIFIED IDEOGRAPH + 0xE8E5: 0x7325, //CJK UNIFIED IDEOGRAPH + 0xE8E6: 0x754F, //CJK UNIFIED IDEOGRAPH + 0xE8E7: 0xF9BA, //CJK COMPATIBILITY IDEOGRAPH + 0xE8E8: 0xF9BB, //CJK COMPATIBILITY IDEOGRAPH + 0xE8E9: 0x50E5, //CJK UNIFIED IDEOGRAPH + 0xE8EA: 0x51F9, //CJK UNIFIED IDEOGRAPH + 0xE8EB: 0x582F, //CJK UNIFIED IDEOGRAPH + 0xE8EC: 0x592D, //CJK UNIFIED IDEOGRAPH + 0xE8ED: 0x5996, //CJK UNIFIED IDEOGRAPH + 0xE8EE: 0x59DA, //CJK UNIFIED IDEOGRAPH + 0xE8EF: 0x5BE5, //CJK UNIFIED IDEOGRAPH + 0xE8F0: 0xF9BC, //CJK COMPATIBILITY IDEOGRAPH + 0xE8F1: 0xF9BD, //CJK COMPATIBILITY IDEOGRAPH + 0xE8F2: 0x5DA2, //CJK UNIFIED IDEOGRAPH + 0xE8F3: 0x62D7, //CJK UNIFIED IDEOGRAPH + 0xE8F4: 0x6416, //CJK UNIFIED IDEOGRAPH + 0xE8F5: 0x6493, //CJK UNIFIED IDEOGRAPH + 0xE8F6: 0x64FE, //CJK UNIFIED IDEOGRAPH + 0xE8F7: 0xF9BE, //CJK COMPATIBILITY IDEOGRAPH + 0xE8F8: 0x66DC, //CJK UNIFIED IDEOGRAPH + 0xE8F9: 0xF9BF, //CJK COMPATIBILITY IDEOGRAPH + 0xE8FA: 0x6A48, //CJK UNIFIED IDEOGRAPH + 0xE8FB: 0xF9C0, //CJK COMPATIBILITY IDEOGRAPH + 0xE8FC: 0x71FF, //CJK UNIFIED IDEOGRAPH + 0xE8FD: 0x7464, //CJK UNIFIED IDEOGRAPH + 0xE8FE: 0xF9C1, //CJK COMPATIBILITY IDEOGRAPH + 0xE9A1: 0x7A88, //CJK UNIFIED IDEOGRAPH + 0xE9A2: 0x7AAF, //CJK UNIFIED IDEOGRAPH + 0xE9A3: 0x7E47, //CJK UNIFIED IDEOGRAPH + 0xE9A4: 0x7E5E, //CJK UNIFIED IDEOGRAPH + 0xE9A5: 0x8000, //CJK UNIFIED IDEOGRAPH + 0xE9A6: 0x8170, //CJK UNIFIED IDEOGRAPH + 0xE9A7: 0xF9C2, //CJK COMPATIBILITY IDEOGRAPH + 0xE9A8: 0x87EF, //CJK UNIFIED IDEOGRAPH + 0xE9A9: 0x8981, //CJK UNIFIED IDEOGRAPH + 0xE9AA: 0x8B20, //CJK UNIFIED IDEOGRAPH + 0xE9AB: 0x9059, //CJK UNIFIED IDEOGRAPH + 0xE9AC: 0xF9C3, //CJK COMPATIBILITY IDEOGRAPH + 0xE9AD: 0x9080, //CJK UNIFIED IDEOGRAPH + 0xE9AE: 0x9952, //CJK UNIFIED IDEOGRAPH + 0xE9AF: 0x617E, //CJK UNIFIED IDEOGRAPH + 0xE9B0: 0x6B32, //CJK UNIFIED IDEOGRAPH + 0xE9B1: 0x6D74, //CJK UNIFIED IDEOGRAPH + 0xE9B2: 0x7E1F, //CJK UNIFIED IDEOGRAPH + 0xE9B3: 0x8925, //CJK UNIFIED IDEOGRAPH + 0xE9B4: 0x8FB1, //CJK UNIFIED IDEOGRAPH + 0xE9B5: 0x4FD1, //CJK UNIFIED IDEOGRAPH + 0xE9B6: 0x50AD, //CJK UNIFIED IDEOGRAPH + 0xE9B7: 0x5197, //CJK UNIFIED IDEOGRAPH + 0xE9B8: 0x52C7, //CJK UNIFIED IDEOGRAPH + 0xE9B9: 0x57C7, //CJK UNIFIED IDEOGRAPH + 0xE9BA: 0x5889, //CJK UNIFIED IDEOGRAPH + 0xE9BB: 0x5BB9, //CJK UNIFIED IDEOGRAPH + 0xE9BC: 0x5EB8, //CJK UNIFIED IDEOGRAPH + 0xE9BD: 0x6142, //CJK UNIFIED IDEOGRAPH + 0xE9BE: 0x6995, //CJK UNIFIED IDEOGRAPH + 0xE9BF: 0x6D8C, //CJK UNIFIED IDEOGRAPH + 0xE9C0: 0x6E67, //CJK UNIFIED IDEOGRAPH + 0xE9C1: 0x6EB6, //CJK UNIFIED IDEOGRAPH + 0xE9C2: 0x7194, //CJK UNIFIED IDEOGRAPH + 0xE9C3: 0x7462, //CJK UNIFIED IDEOGRAPH + 0xE9C4: 0x7528, //CJK UNIFIED IDEOGRAPH + 0xE9C5: 0x752C, //CJK UNIFIED IDEOGRAPH + 0xE9C6: 0x8073, //CJK UNIFIED IDEOGRAPH + 0xE9C7: 0x8338, //CJK UNIFIED IDEOGRAPH + 0xE9C8: 0x84C9, //CJK UNIFIED IDEOGRAPH + 0xE9C9: 0x8E0A, //CJK UNIFIED IDEOGRAPH + 0xE9CA: 0x9394, //CJK UNIFIED IDEOGRAPH + 0xE9CB: 0x93DE, //CJK UNIFIED IDEOGRAPH + 0xE9CC: 0xF9C4, //CJK COMPATIBILITY IDEOGRAPH + 0xE9CD: 0x4E8E, //CJK UNIFIED IDEOGRAPH + 0xE9CE: 0x4F51, //CJK UNIFIED IDEOGRAPH + 0xE9CF: 0x5076, //CJK UNIFIED IDEOGRAPH + 0xE9D0: 0x512A, //CJK UNIFIED IDEOGRAPH + 0xE9D1: 0x53C8, //CJK UNIFIED IDEOGRAPH + 0xE9D2: 0x53CB, //CJK UNIFIED IDEOGRAPH + 0xE9D3: 0x53F3, //CJK UNIFIED IDEOGRAPH + 0xE9D4: 0x5B87, //CJK UNIFIED IDEOGRAPH + 0xE9D5: 0x5BD3, //CJK UNIFIED IDEOGRAPH + 0xE9D6: 0x5C24, //CJK UNIFIED IDEOGRAPH + 0xE9D7: 0x611A, //CJK UNIFIED IDEOGRAPH + 0xE9D8: 0x6182, //CJK UNIFIED IDEOGRAPH + 0xE9D9: 0x65F4, //CJK UNIFIED IDEOGRAPH + 0xE9DA: 0x725B, //CJK UNIFIED IDEOGRAPH + 0xE9DB: 0x7397, //CJK UNIFIED IDEOGRAPH + 0xE9DC: 0x7440, //CJK UNIFIED IDEOGRAPH + 0xE9DD: 0x76C2, //CJK UNIFIED IDEOGRAPH + 0xE9DE: 0x7950, //CJK UNIFIED IDEOGRAPH + 0xE9DF: 0x7991, //CJK UNIFIED IDEOGRAPH + 0xE9E0: 0x79B9, //CJK UNIFIED IDEOGRAPH + 0xE9E1: 0x7D06, //CJK UNIFIED IDEOGRAPH + 0xE9E2: 0x7FBD, //CJK UNIFIED IDEOGRAPH + 0xE9E3: 0x828B, //CJK UNIFIED IDEOGRAPH + 0xE9E4: 0x85D5, //CJK UNIFIED IDEOGRAPH + 0xE9E5: 0x865E, //CJK UNIFIED IDEOGRAPH + 0xE9E6: 0x8FC2, //CJK UNIFIED IDEOGRAPH + 0xE9E7: 0x9047, //CJK UNIFIED IDEOGRAPH + 0xE9E8: 0x90F5, //CJK UNIFIED IDEOGRAPH + 0xE9E9: 0x91EA, //CJK UNIFIED IDEOGRAPH + 0xE9EA: 0x9685, //CJK UNIFIED IDEOGRAPH + 0xE9EB: 0x96E8, //CJK UNIFIED IDEOGRAPH + 0xE9EC: 0x96E9, //CJK UNIFIED IDEOGRAPH + 0xE9ED: 0x52D6, //CJK UNIFIED IDEOGRAPH + 0xE9EE: 0x5F67, //CJK UNIFIED IDEOGRAPH + 0xE9EF: 0x65ED, //CJK UNIFIED IDEOGRAPH + 0xE9F0: 0x6631, //CJK UNIFIED IDEOGRAPH + 0xE9F1: 0x682F, //CJK UNIFIED IDEOGRAPH + 0xE9F2: 0x715C, //CJK UNIFIED IDEOGRAPH + 0xE9F3: 0x7A36, //CJK UNIFIED IDEOGRAPH + 0xE9F4: 0x90C1, //CJK UNIFIED IDEOGRAPH + 0xE9F5: 0x980A, //CJK UNIFIED IDEOGRAPH + 0xE9F6: 0x4E91, //CJK UNIFIED IDEOGRAPH + 0xE9F7: 0xF9C5, //CJK COMPATIBILITY IDEOGRAPH + 0xE9F8: 0x6A52, //CJK UNIFIED IDEOGRAPH + 0xE9F9: 0x6B9E, //CJK UNIFIED IDEOGRAPH + 0xE9FA: 0x6F90, //CJK UNIFIED IDEOGRAPH + 0xE9FB: 0x7189, //CJK UNIFIED IDEOGRAPH + 0xE9FC: 0x8018, //CJK UNIFIED IDEOGRAPH + 0xE9FD: 0x82B8, //CJK UNIFIED IDEOGRAPH + 0xE9FE: 0x8553, //CJK UNIFIED IDEOGRAPH + 0xEAA1: 0x904B, //CJK UNIFIED IDEOGRAPH + 0xEAA2: 0x9695, //CJK UNIFIED IDEOGRAPH + 0xEAA3: 0x96F2, //CJK UNIFIED IDEOGRAPH + 0xEAA4: 0x97FB, //CJK UNIFIED IDEOGRAPH + 0xEAA5: 0x851A, //CJK UNIFIED IDEOGRAPH + 0xEAA6: 0x9B31, //CJK UNIFIED IDEOGRAPH + 0xEAA7: 0x4E90, //CJK UNIFIED IDEOGRAPH + 0xEAA8: 0x718A, //CJK UNIFIED IDEOGRAPH + 0xEAA9: 0x96C4, //CJK UNIFIED IDEOGRAPH + 0xEAAA: 0x5143, //CJK UNIFIED IDEOGRAPH + 0xEAAB: 0x539F, //CJK UNIFIED IDEOGRAPH + 0xEAAC: 0x54E1, //CJK UNIFIED IDEOGRAPH + 0xEAAD: 0x5713, //CJK UNIFIED IDEOGRAPH + 0xEAAE: 0x5712, //CJK UNIFIED IDEOGRAPH + 0xEAAF: 0x57A3, //CJK UNIFIED IDEOGRAPH + 0xEAB0: 0x5A9B, //CJK UNIFIED IDEOGRAPH + 0xEAB1: 0x5AC4, //CJK UNIFIED IDEOGRAPH + 0xEAB2: 0x5BC3, //CJK UNIFIED IDEOGRAPH + 0xEAB3: 0x6028, //CJK UNIFIED IDEOGRAPH + 0xEAB4: 0x613F, //CJK UNIFIED IDEOGRAPH + 0xEAB5: 0x63F4, //CJK UNIFIED IDEOGRAPH + 0xEAB6: 0x6C85, //CJK UNIFIED IDEOGRAPH + 0xEAB7: 0x6D39, //CJK UNIFIED IDEOGRAPH + 0xEAB8: 0x6E72, //CJK UNIFIED IDEOGRAPH + 0xEAB9: 0x6E90, //CJK UNIFIED IDEOGRAPH + 0xEABA: 0x7230, //CJK UNIFIED IDEOGRAPH + 0xEABB: 0x733F, //CJK UNIFIED IDEOGRAPH + 0xEABC: 0x7457, //CJK UNIFIED IDEOGRAPH + 0xEABD: 0x82D1, //CJK UNIFIED IDEOGRAPH + 0xEABE: 0x8881, //CJK UNIFIED IDEOGRAPH + 0xEABF: 0x8F45, //CJK UNIFIED IDEOGRAPH + 0xEAC0: 0x9060, //CJK UNIFIED IDEOGRAPH + 0xEAC1: 0xF9C6, //CJK COMPATIBILITY IDEOGRAPH + 0xEAC2: 0x9662, //CJK UNIFIED IDEOGRAPH + 0xEAC3: 0x9858, //CJK UNIFIED IDEOGRAPH + 0xEAC4: 0x9D1B, //CJK UNIFIED IDEOGRAPH + 0xEAC5: 0x6708, //CJK UNIFIED IDEOGRAPH + 0xEAC6: 0x8D8A, //CJK UNIFIED IDEOGRAPH + 0xEAC7: 0x925E, //CJK UNIFIED IDEOGRAPH + 0xEAC8: 0x4F4D, //CJK UNIFIED IDEOGRAPH + 0xEAC9: 0x5049, //CJK UNIFIED IDEOGRAPH + 0xEACA: 0x50DE, //CJK UNIFIED IDEOGRAPH + 0xEACB: 0x5371, //CJK UNIFIED IDEOGRAPH + 0xEACC: 0x570D, //CJK UNIFIED IDEOGRAPH + 0xEACD: 0x59D4, //CJK UNIFIED IDEOGRAPH + 0xEACE: 0x5A01, //CJK UNIFIED IDEOGRAPH + 0xEACF: 0x5C09, //CJK UNIFIED IDEOGRAPH + 0xEAD0: 0x6170, //CJK UNIFIED IDEOGRAPH + 0xEAD1: 0x6690, //CJK UNIFIED IDEOGRAPH + 0xEAD2: 0x6E2D, //CJK UNIFIED IDEOGRAPH + 0xEAD3: 0x7232, //CJK UNIFIED IDEOGRAPH + 0xEAD4: 0x744B, //CJK UNIFIED IDEOGRAPH + 0xEAD5: 0x7DEF, //CJK UNIFIED IDEOGRAPH + 0xEAD6: 0x80C3, //CJK UNIFIED IDEOGRAPH + 0xEAD7: 0x840E, //CJK UNIFIED IDEOGRAPH + 0xEAD8: 0x8466, //CJK UNIFIED IDEOGRAPH + 0xEAD9: 0x853F, //CJK UNIFIED IDEOGRAPH + 0xEADA: 0x875F, //CJK UNIFIED IDEOGRAPH + 0xEADB: 0x885B, //CJK UNIFIED IDEOGRAPH + 0xEADC: 0x8918, //CJK UNIFIED IDEOGRAPH + 0xEADD: 0x8B02, //CJK UNIFIED IDEOGRAPH + 0xEADE: 0x9055, //CJK UNIFIED IDEOGRAPH + 0xEADF: 0x97CB, //CJK UNIFIED IDEOGRAPH + 0xEAE0: 0x9B4F, //CJK UNIFIED IDEOGRAPH + 0xEAE1: 0x4E73, //CJK UNIFIED IDEOGRAPH + 0xEAE2: 0x4F91, //CJK UNIFIED IDEOGRAPH + 0xEAE3: 0x5112, //CJK UNIFIED IDEOGRAPH + 0xEAE4: 0x516A, //CJK UNIFIED IDEOGRAPH + 0xEAE5: 0xF9C7, //CJK COMPATIBILITY IDEOGRAPH + 0xEAE6: 0x552F, //CJK UNIFIED IDEOGRAPH + 0xEAE7: 0x55A9, //CJK UNIFIED IDEOGRAPH + 0xEAE8: 0x5B7A, //CJK UNIFIED IDEOGRAPH + 0xEAE9: 0x5BA5, //CJK UNIFIED IDEOGRAPH + 0xEAEA: 0x5E7C, //CJK UNIFIED IDEOGRAPH + 0xEAEB: 0x5E7D, //CJK UNIFIED IDEOGRAPH + 0xEAEC: 0x5EBE, //CJK UNIFIED IDEOGRAPH + 0xEAED: 0x60A0, //CJK UNIFIED IDEOGRAPH + 0xEAEE: 0x60DF, //CJK UNIFIED IDEOGRAPH + 0xEAEF: 0x6108, //CJK UNIFIED IDEOGRAPH + 0xEAF0: 0x6109, //CJK UNIFIED IDEOGRAPH + 0xEAF1: 0x63C4, //CJK UNIFIED IDEOGRAPH + 0xEAF2: 0x6538, //CJK UNIFIED IDEOGRAPH + 0xEAF3: 0x6709, //CJK UNIFIED IDEOGRAPH + 0xEAF4: 0xF9C8, //CJK COMPATIBILITY IDEOGRAPH + 0xEAF5: 0x67D4, //CJK UNIFIED IDEOGRAPH + 0xEAF6: 0x67DA, //CJK UNIFIED IDEOGRAPH + 0xEAF7: 0xF9C9, //CJK COMPATIBILITY IDEOGRAPH + 0xEAF8: 0x6961, //CJK UNIFIED IDEOGRAPH + 0xEAF9: 0x6962, //CJK UNIFIED IDEOGRAPH + 0xEAFA: 0x6CB9, //CJK UNIFIED IDEOGRAPH + 0xEAFB: 0x6D27, //CJK UNIFIED IDEOGRAPH + 0xEAFC: 0xF9CA, //CJK COMPATIBILITY IDEOGRAPH + 0xEAFD: 0x6E38, //CJK UNIFIED IDEOGRAPH + 0xEAFE: 0xF9CB, //CJK COMPATIBILITY IDEOGRAPH + 0xEBA1: 0x6FE1, //CJK UNIFIED IDEOGRAPH + 0xEBA2: 0x7336, //CJK UNIFIED IDEOGRAPH + 0xEBA3: 0x7337, //CJK UNIFIED IDEOGRAPH + 0xEBA4: 0xF9CC, //CJK COMPATIBILITY IDEOGRAPH + 0xEBA5: 0x745C, //CJK UNIFIED IDEOGRAPH + 0xEBA6: 0x7531, //CJK UNIFIED IDEOGRAPH + 0xEBA7: 0xF9CD, //CJK COMPATIBILITY IDEOGRAPH + 0xEBA8: 0x7652, //CJK UNIFIED IDEOGRAPH + 0xEBA9: 0xF9CE, //CJK COMPATIBILITY IDEOGRAPH + 0xEBAA: 0xF9CF, //CJK COMPATIBILITY IDEOGRAPH + 0xEBAB: 0x7DAD, //CJK UNIFIED IDEOGRAPH + 0xEBAC: 0x81FE, //CJK UNIFIED IDEOGRAPH + 0xEBAD: 0x8438, //CJK UNIFIED IDEOGRAPH + 0xEBAE: 0x88D5, //CJK UNIFIED IDEOGRAPH + 0xEBAF: 0x8A98, //CJK UNIFIED IDEOGRAPH + 0xEBB0: 0x8ADB, //CJK UNIFIED IDEOGRAPH + 0xEBB1: 0x8AED, //CJK UNIFIED IDEOGRAPH + 0xEBB2: 0x8E30, //CJK UNIFIED IDEOGRAPH + 0xEBB3: 0x8E42, //CJK UNIFIED IDEOGRAPH + 0xEBB4: 0x904A, //CJK UNIFIED IDEOGRAPH + 0xEBB5: 0x903E, //CJK UNIFIED IDEOGRAPH + 0xEBB6: 0x907A, //CJK UNIFIED IDEOGRAPH + 0xEBB7: 0x9149, //CJK UNIFIED IDEOGRAPH + 0xEBB8: 0x91C9, //CJK UNIFIED IDEOGRAPH + 0xEBB9: 0x936E, //CJK UNIFIED IDEOGRAPH + 0xEBBA: 0xF9D0, //CJK COMPATIBILITY IDEOGRAPH + 0xEBBB: 0xF9D1, //CJK COMPATIBILITY IDEOGRAPH + 0xEBBC: 0x5809, //CJK UNIFIED IDEOGRAPH + 0xEBBD: 0xF9D2, //CJK COMPATIBILITY IDEOGRAPH + 0xEBBE: 0x6BD3, //CJK UNIFIED IDEOGRAPH + 0xEBBF: 0x8089, //CJK UNIFIED IDEOGRAPH + 0xEBC0: 0x80B2, //CJK UNIFIED IDEOGRAPH + 0xEBC1: 0xF9D3, //CJK COMPATIBILITY IDEOGRAPH + 0xEBC2: 0xF9D4, //CJK COMPATIBILITY IDEOGRAPH + 0xEBC3: 0x5141, //CJK UNIFIED IDEOGRAPH + 0xEBC4: 0x596B, //CJK UNIFIED IDEOGRAPH + 0xEBC5: 0x5C39, //CJK UNIFIED IDEOGRAPH + 0xEBC6: 0xF9D5, //CJK COMPATIBILITY IDEOGRAPH + 0xEBC7: 0xF9D6, //CJK COMPATIBILITY IDEOGRAPH + 0xEBC8: 0x6F64, //CJK UNIFIED IDEOGRAPH + 0xEBC9: 0x73A7, //CJK UNIFIED IDEOGRAPH + 0xEBCA: 0x80E4, //CJK UNIFIED IDEOGRAPH + 0xEBCB: 0x8D07, //CJK UNIFIED IDEOGRAPH + 0xEBCC: 0xF9D7, //CJK COMPATIBILITY IDEOGRAPH + 0xEBCD: 0x9217, //CJK UNIFIED IDEOGRAPH + 0xEBCE: 0x958F, //CJK UNIFIED IDEOGRAPH + 0xEBCF: 0xF9D8, //CJK COMPATIBILITY IDEOGRAPH + 0xEBD0: 0xF9D9, //CJK COMPATIBILITY IDEOGRAPH + 0xEBD1: 0xF9DA, //CJK COMPATIBILITY IDEOGRAPH + 0xEBD2: 0xF9DB, //CJK COMPATIBILITY IDEOGRAPH + 0xEBD3: 0x807F, //CJK UNIFIED IDEOGRAPH + 0xEBD4: 0x620E, //CJK UNIFIED IDEOGRAPH + 0xEBD5: 0x701C, //CJK UNIFIED IDEOGRAPH + 0xEBD6: 0x7D68, //CJK UNIFIED IDEOGRAPH + 0xEBD7: 0x878D, //CJK UNIFIED IDEOGRAPH + 0xEBD8: 0xF9DC, //CJK COMPATIBILITY IDEOGRAPH + 0xEBD9: 0x57A0, //CJK UNIFIED IDEOGRAPH + 0xEBDA: 0x6069, //CJK UNIFIED IDEOGRAPH + 0xEBDB: 0x6147, //CJK UNIFIED IDEOGRAPH + 0xEBDC: 0x6BB7, //CJK UNIFIED IDEOGRAPH + 0xEBDD: 0x8ABE, //CJK UNIFIED IDEOGRAPH + 0xEBDE: 0x9280, //CJK UNIFIED IDEOGRAPH + 0xEBDF: 0x96B1, //CJK UNIFIED IDEOGRAPH + 0xEBE0: 0x4E59, //CJK UNIFIED IDEOGRAPH + 0xEBE1: 0x541F, //CJK UNIFIED IDEOGRAPH + 0xEBE2: 0x6DEB, //CJK UNIFIED IDEOGRAPH + 0xEBE3: 0x852D, //CJK UNIFIED IDEOGRAPH + 0xEBE4: 0x9670, //CJK UNIFIED IDEOGRAPH + 0xEBE5: 0x97F3, //CJK UNIFIED IDEOGRAPH + 0xEBE6: 0x98EE, //CJK UNIFIED IDEOGRAPH + 0xEBE7: 0x63D6, //CJK UNIFIED IDEOGRAPH + 0xEBE8: 0x6CE3, //CJK UNIFIED IDEOGRAPH + 0xEBE9: 0x9091, //CJK UNIFIED IDEOGRAPH + 0xEBEA: 0x51DD, //CJK UNIFIED IDEOGRAPH + 0xEBEB: 0x61C9, //CJK UNIFIED IDEOGRAPH + 0xEBEC: 0x81BA, //CJK UNIFIED IDEOGRAPH + 0xEBED: 0x9DF9, //CJK UNIFIED IDEOGRAPH + 0xEBEE: 0x4F9D, //CJK UNIFIED IDEOGRAPH + 0xEBEF: 0x501A, //CJK UNIFIED IDEOGRAPH + 0xEBF0: 0x5100, //CJK UNIFIED IDEOGRAPH + 0xEBF1: 0x5B9C, //CJK UNIFIED IDEOGRAPH + 0xEBF2: 0x610F, //CJK UNIFIED IDEOGRAPH + 0xEBF3: 0x61FF, //CJK UNIFIED IDEOGRAPH + 0xEBF4: 0x64EC, //CJK UNIFIED IDEOGRAPH + 0xEBF5: 0x6905, //CJK UNIFIED IDEOGRAPH + 0xEBF6: 0x6BC5, //CJK UNIFIED IDEOGRAPH + 0xEBF7: 0x7591, //CJK UNIFIED IDEOGRAPH + 0xEBF8: 0x77E3, //CJK UNIFIED IDEOGRAPH + 0xEBF9: 0x7FA9, //CJK UNIFIED IDEOGRAPH + 0xEBFA: 0x8264, //CJK UNIFIED IDEOGRAPH + 0xEBFB: 0x858F, //CJK UNIFIED IDEOGRAPH + 0xEBFC: 0x87FB, //CJK UNIFIED IDEOGRAPH + 0xEBFD: 0x8863, //CJK UNIFIED IDEOGRAPH + 0xEBFE: 0x8ABC, //CJK UNIFIED IDEOGRAPH + 0xECA1: 0x8B70, //CJK UNIFIED IDEOGRAPH + 0xECA2: 0x91AB, //CJK UNIFIED IDEOGRAPH + 0xECA3: 0x4E8C, //CJK UNIFIED IDEOGRAPH + 0xECA4: 0x4EE5, //CJK UNIFIED IDEOGRAPH + 0xECA5: 0x4F0A, //CJK UNIFIED IDEOGRAPH + 0xECA6: 0xF9DD, //CJK COMPATIBILITY IDEOGRAPH + 0xECA7: 0xF9DE, //CJK COMPATIBILITY IDEOGRAPH + 0xECA8: 0x5937, //CJK UNIFIED IDEOGRAPH + 0xECA9: 0x59E8, //CJK UNIFIED IDEOGRAPH + 0xECAA: 0xF9DF, //CJK COMPATIBILITY IDEOGRAPH + 0xECAB: 0x5DF2, //CJK UNIFIED IDEOGRAPH + 0xECAC: 0x5F1B, //CJK UNIFIED IDEOGRAPH + 0xECAD: 0x5F5B, //CJK UNIFIED IDEOGRAPH + 0xECAE: 0x6021, //CJK UNIFIED IDEOGRAPH + 0xECAF: 0xF9E0, //CJK COMPATIBILITY IDEOGRAPH + 0xECB0: 0xF9E1, //CJK COMPATIBILITY IDEOGRAPH + 0xECB1: 0xF9E2, //CJK COMPATIBILITY IDEOGRAPH + 0xECB2: 0xF9E3, //CJK COMPATIBILITY IDEOGRAPH + 0xECB3: 0x723E, //CJK UNIFIED IDEOGRAPH + 0xECB4: 0x73E5, //CJK UNIFIED IDEOGRAPH + 0xECB5: 0xF9E4, //CJK COMPATIBILITY IDEOGRAPH + 0xECB6: 0x7570, //CJK UNIFIED IDEOGRAPH + 0xECB7: 0x75CD, //CJK UNIFIED IDEOGRAPH + 0xECB8: 0xF9E5, //CJK COMPATIBILITY IDEOGRAPH + 0xECB9: 0x79FB, //CJK UNIFIED IDEOGRAPH + 0xECBA: 0xF9E6, //CJK COMPATIBILITY IDEOGRAPH + 0xECBB: 0x800C, //CJK UNIFIED IDEOGRAPH + 0xECBC: 0x8033, //CJK UNIFIED IDEOGRAPH + 0xECBD: 0x8084, //CJK UNIFIED IDEOGRAPH + 0xECBE: 0x82E1, //CJK UNIFIED IDEOGRAPH + 0xECBF: 0x8351, //CJK UNIFIED IDEOGRAPH + 0xECC0: 0xF9E7, //CJK COMPATIBILITY IDEOGRAPH + 0xECC1: 0xF9E8, //CJK COMPATIBILITY IDEOGRAPH + 0xECC2: 0x8CBD, //CJK UNIFIED IDEOGRAPH + 0xECC3: 0x8CB3, //CJK UNIFIED IDEOGRAPH + 0xECC4: 0x9087, //CJK UNIFIED IDEOGRAPH + 0xECC5: 0xF9E9, //CJK COMPATIBILITY IDEOGRAPH + 0xECC6: 0xF9EA, //CJK COMPATIBILITY IDEOGRAPH + 0xECC7: 0x98F4, //CJK UNIFIED IDEOGRAPH + 0xECC8: 0x990C, //CJK UNIFIED IDEOGRAPH + 0xECC9: 0xF9EB, //CJK COMPATIBILITY IDEOGRAPH + 0xECCA: 0xF9EC, //CJK COMPATIBILITY IDEOGRAPH + 0xECCB: 0x7037, //CJK UNIFIED IDEOGRAPH + 0xECCC: 0x76CA, //CJK UNIFIED IDEOGRAPH + 0xECCD: 0x7FCA, //CJK UNIFIED IDEOGRAPH + 0xECCE: 0x7FCC, //CJK UNIFIED IDEOGRAPH + 0xECCF: 0x7FFC, //CJK UNIFIED IDEOGRAPH + 0xECD0: 0x8B1A, //CJK UNIFIED IDEOGRAPH + 0xECD1: 0x4EBA, //CJK UNIFIED IDEOGRAPH + 0xECD2: 0x4EC1, //CJK UNIFIED IDEOGRAPH + 0xECD3: 0x5203, //CJK UNIFIED IDEOGRAPH + 0xECD4: 0x5370, //CJK UNIFIED IDEOGRAPH + 0xECD5: 0xF9ED, //CJK COMPATIBILITY IDEOGRAPH + 0xECD6: 0x54BD, //CJK UNIFIED IDEOGRAPH + 0xECD7: 0x56E0, //CJK UNIFIED IDEOGRAPH + 0xECD8: 0x59FB, //CJK UNIFIED IDEOGRAPH + 0xECD9: 0x5BC5, //CJK UNIFIED IDEOGRAPH + 0xECDA: 0x5F15, //CJK UNIFIED IDEOGRAPH + 0xECDB: 0x5FCD, //CJK UNIFIED IDEOGRAPH + 0xECDC: 0x6E6E, //CJK UNIFIED IDEOGRAPH + 0xECDD: 0xF9EE, //CJK COMPATIBILITY IDEOGRAPH + 0xECDE: 0xF9EF, //CJK COMPATIBILITY IDEOGRAPH + 0xECDF: 0x7D6A, //CJK UNIFIED IDEOGRAPH + 0xECE0: 0x8335, //CJK UNIFIED IDEOGRAPH + 0xECE1: 0xF9F0, //CJK COMPATIBILITY IDEOGRAPH + 0xECE2: 0x8693, //CJK UNIFIED IDEOGRAPH + 0xECE3: 0x8A8D, //CJK UNIFIED IDEOGRAPH + 0xECE4: 0xF9F1, //CJK COMPATIBILITY IDEOGRAPH + 0xECE5: 0x976D, //CJK UNIFIED IDEOGRAPH + 0xECE6: 0x9777, //CJK UNIFIED IDEOGRAPH + 0xECE7: 0xF9F2, //CJK COMPATIBILITY IDEOGRAPH + 0xECE8: 0xF9F3, //CJK COMPATIBILITY IDEOGRAPH + 0xECE9: 0x4E00, //CJK UNIFIED IDEOGRAPH + 0xECEA: 0x4F5A, //CJK UNIFIED IDEOGRAPH + 0xECEB: 0x4F7E, //CJK UNIFIED IDEOGRAPH + 0xECEC: 0x58F9, //CJK UNIFIED IDEOGRAPH + 0xECED: 0x65E5, //CJK UNIFIED IDEOGRAPH + 0xECEE: 0x6EA2, //CJK UNIFIED IDEOGRAPH + 0xECEF: 0x9038, //CJK UNIFIED IDEOGRAPH + 0xECF0: 0x93B0, //CJK UNIFIED IDEOGRAPH + 0xECF1: 0x99B9, //CJK UNIFIED IDEOGRAPH + 0xECF2: 0x4EFB, //CJK UNIFIED IDEOGRAPH + 0xECF3: 0x58EC, //CJK UNIFIED IDEOGRAPH + 0xECF4: 0x598A, //CJK UNIFIED IDEOGRAPH + 0xECF5: 0x59D9, //CJK UNIFIED IDEOGRAPH + 0xECF6: 0x6041, //CJK UNIFIED IDEOGRAPH + 0xECF7: 0xF9F4, //CJK COMPATIBILITY IDEOGRAPH + 0xECF8: 0xF9F5, //CJK COMPATIBILITY IDEOGRAPH + 0xECF9: 0x7A14, //CJK UNIFIED IDEOGRAPH + 0xECFA: 0xF9F6, //CJK COMPATIBILITY IDEOGRAPH + 0xECFB: 0x834F, //CJK UNIFIED IDEOGRAPH + 0xECFC: 0x8CC3, //CJK UNIFIED IDEOGRAPH + 0xECFD: 0x5165, //CJK UNIFIED IDEOGRAPH + 0xECFE: 0x5344, //CJK UNIFIED IDEOGRAPH + 0xEDA1: 0xF9F7, //CJK COMPATIBILITY IDEOGRAPH + 0xEDA2: 0xF9F8, //CJK COMPATIBILITY IDEOGRAPH + 0xEDA3: 0xF9F9, //CJK COMPATIBILITY IDEOGRAPH + 0xEDA4: 0x4ECD, //CJK UNIFIED IDEOGRAPH + 0xEDA5: 0x5269, //CJK UNIFIED IDEOGRAPH + 0xEDA6: 0x5B55, //CJK UNIFIED IDEOGRAPH + 0xEDA7: 0x82BF, //CJK UNIFIED IDEOGRAPH + 0xEDA8: 0x4ED4, //CJK UNIFIED IDEOGRAPH + 0xEDA9: 0x523A, //CJK UNIFIED IDEOGRAPH + 0xEDAA: 0x54A8, //CJK UNIFIED IDEOGRAPH + 0xEDAB: 0x59C9, //CJK UNIFIED IDEOGRAPH + 0xEDAC: 0x59FF, //CJK UNIFIED IDEOGRAPH + 0xEDAD: 0x5B50, //CJK UNIFIED IDEOGRAPH + 0xEDAE: 0x5B57, //CJK UNIFIED IDEOGRAPH + 0xEDAF: 0x5B5C, //CJK UNIFIED IDEOGRAPH + 0xEDB0: 0x6063, //CJK UNIFIED IDEOGRAPH + 0xEDB1: 0x6148, //CJK UNIFIED IDEOGRAPH + 0xEDB2: 0x6ECB, //CJK UNIFIED IDEOGRAPH + 0xEDB3: 0x7099, //CJK UNIFIED IDEOGRAPH + 0xEDB4: 0x716E, //CJK UNIFIED IDEOGRAPH + 0xEDB5: 0x7386, //CJK UNIFIED IDEOGRAPH + 0xEDB6: 0x74F7, //CJK UNIFIED IDEOGRAPH + 0xEDB7: 0x75B5, //CJK UNIFIED IDEOGRAPH + 0xEDB8: 0x78C1, //CJK UNIFIED IDEOGRAPH + 0xEDB9: 0x7D2B, //CJK UNIFIED IDEOGRAPH + 0xEDBA: 0x8005, //CJK UNIFIED IDEOGRAPH + 0xEDBB: 0x81EA, //CJK UNIFIED IDEOGRAPH + 0xEDBC: 0x8328, //CJK UNIFIED IDEOGRAPH + 0xEDBD: 0x8517, //CJK UNIFIED IDEOGRAPH + 0xEDBE: 0x85C9, //CJK UNIFIED IDEOGRAPH + 0xEDBF: 0x8AEE, //CJK UNIFIED IDEOGRAPH + 0xEDC0: 0x8CC7, //CJK UNIFIED IDEOGRAPH + 0xEDC1: 0x96CC, //CJK UNIFIED IDEOGRAPH + 0xEDC2: 0x4F5C, //CJK UNIFIED IDEOGRAPH + 0xEDC3: 0x52FA, //CJK UNIFIED IDEOGRAPH + 0xEDC4: 0x56BC, //CJK UNIFIED IDEOGRAPH + 0xEDC5: 0x65AB, //CJK UNIFIED IDEOGRAPH + 0xEDC6: 0x6628, //CJK UNIFIED IDEOGRAPH + 0xEDC7: 0x707C, //CJK UNIFIED IDEOGRAPH + 0xEDC8: 0x70B8, //CJK UNIFIED IDEOGRAPH + 0xEDC9: 0x7235, //CJK UNIFIED IDEOGRAPH + 0xEDCA: 0x7DBD, //CJK UNIFIED IDEOGRAPH + 0xEDCB: 0x828D, //CJK UNIFIED IDEOGRAPH + 0xEDCC: 0x914C, //CJK UNIFIED IDEOGRAPH + 0xEDCD: 0x96C0, //CJK UNIFIED IDEOGRAPH + 0xEDCE: 0x9D72, //CJK UNIFIED IDEOGRAPH + 0xEDCF: 0x5B71, //CJK UNIFIED IDEOGRAPH + 0xEDD0: 0x68E7, //CJK UNIFIED IDEOGRAPH + 0xEDD1: 0x6B98, //CJK UNIFIED IDEOGRAPH + 0xEDD2: 0x6F7A, //CJK UNIFIED IDEOGRAPH + 0xEDD3: 0x76DE, //CJK UNIFIED IDEOGRAPH + 0xEDD4: 0x5C91, //CJK UNIFIED IDEOGRAPH + 0xEDD5: 0x66AB, //CJK UNIFIED IDEOGRAPH + 0xEDD6: 0x6F5B, //CJK UNIFIED IDEOGRAPH + 0xEDD7: 0x7BB4, //CJK UNIFIED IDEOGRAPH + 0xEDD8: 0x7C2A, //CJK UNIFIED IDEOGRAPH + 0xEDD9: 0x8836, //CJK UNIFIED IDEOGRAPH + 0xEDDA: 0x96DC, //CJK UNIFIED IDEOGRAPH + 0xEDDB: 0x4E08, //CJK UNIFIED IDEOGRAPH + 0xEDDC: 0x4ED7, //CJK UNIFIED IDEOGRAPH + 0xEDDD: 0x5320, //CJK UNIFIED IDEOGRAPH + 0xEDDE: 0x5834, //CJK UNIFIED IDEOGRAPH + 0xEDDF: 0x58BB, //CJK UNIFIED IDEOGRAPH + 0xEDE0: 0x58EF, //CJK UNIFIED IDEOGRAPH + 0xEDE1: 0x596C, //CJK UNIFIED IDEOGRAPH + 0xEDE2: 0x5C07, //CJK UNIFIED IDEOGRAPH + 0xEDE3: 0x5E33, //CJK UNIFIED IDEOGRAPH + 0xEDE4: 0x5E84, //CJK UNIFIED IDEOGRAPH + 0xEDE5: 0x5F35, //CJK UNIFIED IDEOGRAPH + 0xEDE6: 0x638C, //CJK UNIFIED IDEOGRAPH + 0xEDE7: 0x66B2, //CJK UNIFIED IDEOGRAPH + 0xEDE8: 0x6756, //CJK UNIFIED IDEOGRAPH + 0xEDE9: 0x6A1F, //CJK UNIFIED IDEOGRAPH + 0xEDEA: 0x6AA3, //CJK UNIFIED IDEOGRAPH + 0xEDEB: 0x6B0C, //CJK UNIFIED IDEOGRAPH + 0xEDEC: 0x6F3F, //CJK UNIFIED IDEOGRAPH + 0xEDED: 0x7246, //CJK UNIFIED IDEOGRAPH + 0xEDEE: 0xF9FA, //CJK COMPATIBILITY IDEOGRAPH + 0xEDEF: 0x7350, //CJK UNIFIED IDEOGRAPH + 0xEDF0: 0x748B, //CJK UNIFIED IDEOGRAPH + 0xEDF1: 0x7AE0, //CJK UNIFIED IDEOGRAPH + 0xEDF2: 0x7CA7, //CJK UNIFIED IDEOGRAPH + 0xEDF3: 0x8178, //CJK UNIFIED IDEOGRAPH + 0xEDF4: 0x81DF, //CJK UNIFIED IDEOGRAPH + 0xEDF5: 0x81E7, //CJK UNIFIED IDEOGRAPH + 0xEDF6: 0x838A, //CJK UNIFIED IDEOGRAPH + 0xEDF7: 0x846C, //CJK UNIFIED IDEOGRAPH + 0xEDF8: 0x8523, //CJK UNIFIED IDEOGRAPH + 0xEDF9: 0x8594, //CJK UNIFIED IDEOGRAPH + 0xEDFA: 0x85CF, //CJK UNIFIED IDEOGRAPH + 0xEDFB: 0x88DD, //CJK UNIFIED IDEOGRAPH + 0xEDFC: 0x8D13, //CJK UNIFIED IDEOGRAPH + 0xEDFD: 0x91AC, //CJK UNIFIED IDEOGRAPH + 0xEDFE: 0x9577, //CJK UNIFIED IDEOGRAPH + 0xEEA1: 0x969C, //CJK UNIFIED IDEOGRAPH + 0xEEA2: 0x518D, //CJK UNIFIED IDEOGRAPH + 0xEEA3: 0x54C9, //CJK UNIFIED IDEOGRAPH + 0xEEA4: 0x5728, //CJK UNIFIED IDEOGRAPH + 0xEEA5: 0x5BB0, //CJK UNIFIED IDEOGRAPH + 0xEEA6: 0x624D, //CJK UNIFIED IDEOGRAPH + 0xEEA7: 0x6750, //CJK UNIFIED IDEOGRAPH + 0xEEA8: 0x683D, //CJK UNIFIED IDEOGRAPH + 0xEEA9: 0x6893, //CJK UNIFIED IDEOGRAPH + 0xEEAA: 0x6E3D, //CJK UNIFIED IDEOGRAPH + 0xEEAB: 0x6ED3, //CJK UNIFIED IDEOGRAPH + 0xEEAC: 0x707D, //CJK UNIFIED IDEOGRAPH + 0xEEAD: 0x7E21, //CJK UNIFIED IDEOGRAPH + 0xEEAE: 0x88C1, //CJK UNIFIED IDEOGRAPH + 0xEEAF: 0x8CA1, //CJK UNIFIED IDEOGRAPH + 0xEEB0: 0x8F09, //CJK UNIFIED IDEOGRAPH + 0xEEB1: 0x9F4B, //CJK UNIFIED IDEOGRAPH + 0xEEB2: 0x9F4E, //CJK UNIFIED IDEOGRAPH + 0xEEB3: 0x722D, //CJK UNIFIED IDEOGRAPH + 0xEEB4: 0x7B8F, //CJK UNIFIED IDEOGRAPH + 0xEEB5: 0x8ACD, //CJK UNIFIED IDEOGRAPH + 0xEEB6: 0x931A, //CJK UNIFIED IDEOGRAPH + 0xEEB7: 0x4F47, //CJK UNIFIED IDEOGRAPH + 0xEEB8: 0x4F4E, //CJK UNIFIED IDEOGRAPH + 0xEEB9: 0x5132, //CJK UNIFIED IDEOGRAPH + 0xEEBA: 0x5480, //CJK UNIFIED IDEOGRAPH + 0xEEBB: 0x59D0, //CJK UNIFIED IDEOGRAPH + 0xEEBC: 0x5E95, //CJK UNIFIED IDEOGRAPH + 0xEEBD: 0x62B5, //CJK UNIFIED IDEOGRAPH + 0xEEBE: 0x6775, //CJK UNIFIED IDEOGRAPH + 0xEEBF: 0x696E, //CJK UNIFIED IDEOGRAPH + 0xEEC0: 0x6A17, //CJK UNIFIED IDEOGRAPH + 0xEEC1: 0x6CAE, //CJK UNIFIED IDEOGRAPH + 0xEEC2: 0x6E1A, //CJK UNIFIED IDEOGRAPH + 0xEEC3: 0x72D9, //CJK UNIFIED IDEOGRAPH + 0xEEC4: 0x732A, //CJK UNIFIED IDEOGRAPH + 0xEEC5: 0x75BD, //CJK UNIFIED IDEOGRAPH + 0xEEC6: 0x7BB8, //CJK UNIFIED IDEOGRAPH + 0xEEC7: 0x7D35, //CJK UNIFIED IDEOGRAPH + 0xEEC8: 0x82E7, //CJK UNIFIED IDEOGRAPH + 0xEEC9: 0x83F9, //CJK UNIFIED IDEOGRAPH + 0xEECA: 0x8457, //CJK UNIFIED IDEOGRAPH + 0xEECB: 0x85F7, //CJK UNIFIED IDEOGRAPH + 0xEECC: 0x8A5B, //CJK UNIFIED IDEOGRAPH + 0xEECD: 0x8CAF, //CJK UNIFIED IDEOGRAPH + 0xEECE: 0x8E87, //CJK UNIFIED IDEOGRAPH + 0xEECF: 0x9019, //CJK UNIFIED IDEOGRAPH + 0xEED0: 0x90B8, //CJK UNIFIED IDEOGRAPH + 0xEED1: 0x96CE, //CJK UNIFIED IDEOGRAPH + 0xEED2: 0x9F5F, //CJK UNIFIED IDEOGRAPH + 0xEED3: 0x52E3, //CJK UNIFIED IDEOGRAPH + 0xEED4: 0x540A, //CJK UNIFIED IDEOGRAPH + 0xEED5: 0x5AE1, //CJK UNIFIED IDEOGRAPH + 0xEED6: 0x5BC2, //CJK UNIFIED IDEOGRAPH + 0xEED7: 0x6458, //CJK UNIFIED IDEOGRAPH + 0xEED8: 0x6575, //CJK UNIFIED IDEOGRAPH + 0xEED9: 0x6EF4, //CJK UNIFIED IDEOGRAPH + 0xEEDA: 0x72C4, //CJK UNIFIED IDEOGRAPH + 0xEEDB: 0xF9FB, //CJK COMPATIBILITY IDEOGRAPH + 0xEEDC: 0x7684, //CJK UNIFIED IDEOGRAPH + 0xEEDD: 0x7A4D, //CJK UNIFIED IDEOGRAPH + 0xEEDE: 0x7B1B, //CJK UNIFIED IDEOGRAPH + 0xEEDF: 0x7C4D, //CJK UNIFIED IDEOGRAPH + 0xEEE0: 0x7E3E, //CJK UNIFIED IDEOGRAPH + 0xEEE1: 0x7FDF, //CJK UNIFIED IDEOGRAPH + 0xEEE2: 0x837B, //CJK UNIFIED IDEOGRAPH + 0xEEE3: 0x8B2B, //CJK UNIFIED IDEOGRAPH + 0xEEE4: 0x8CCA, //CJK UNIFIED IDEOGRAPH + 0xEEE5: 0x8D64, //CJK UNIFIED IDEOGRAPH + 0xEEE6: 0x8DE1, //CJK UNIFIED IDEOGRAPH + 0xEEE7: 0x8E5F, //CJK UNIFIED IDEOGRAPH + 0xEEE8: 0x8FEA, //CJK UNIFIED IDEOGRAPH + 0xEEE9: 0x8FF9, //CJK UNIFIED IDEOGRAPH + 0xEEEA: 0x9069, //CJK UNIFIED IDEOGRAPH + 0xEEEB: 0x93D1, //CJK UNIFIED IDEOGRAPH + 0xEEEC: 0x4F43, //CJK UNIFIED IDEOGRAPH + 0xEEED: 0x4F7A, //CJK UNIFIED IDEOGRAPH + 0xEEEE: 0x50B3, //CJK UNIFIED IDEOGRAPH + 0xEEEF: 0x5168, //CJK UNIFIED IDEOGRAPH + 0xEEF0: 0x5178, //CJK UNIFIED IDEOGRAPH + 0xEEF1: 0x524D, //CJK UNIFIED IDEOGRAPH + 0xEEF2: 0x526A, //CJK UNIFIED IDEOGRAPH + 0xEEF3: 0x5861, //CJK UNIFIED IDEOGRAPH + 0xEEF4: 0x587C, //CJK UNIFIED IDEOGRAPH + 0xEEF5: 0x5960, //CJK UNIFIED IDEOGRAPH + 0xEEF6: 0x5C08, //CJK UNIFIED IDEOGRAPH + 0xEEF7: 0x5C55, //CJK UNIFIED IDEOGRAPH + 0xEEF8: 0x5EDB, //CJK UNIFIED IDEOGRAPH + 0xEEF9: 0x609B, //CJK UNIFIED IDEOGRAPH + 0xEEFA: 0x6230, //CJK UNIFIED IDEOGRAPH + 0xEEFB: 0x6813, //CJK UNIFIED IDEOGRAPH + 0xEEFC: 0x6BBF, //CJK UNIFIED IDEOGRAPH + 0xEEFD: 0x6C08, //CJK UNIFIED IDEOGRAPH + 0xEEFE: 0x6FB1, //CJK UNIFIED IDEOGRAPH + 0xEFA1: 0x714E, //CJK UNIFIED IDEOGRAPH + 0xEFA2: 0x7420, //CJK UNIFIED IDEOGRAPH + 0xEFA3: 0x7530, //CJK UNIFIED IDEOGRAPH + 0xEFA4: 0x7538, //CJK UNIFIED IDEOGRAPH + 0xEFA5: 0x7551, //CJK UNIFIED IDEOGRAPH + 0xEFA6: 0x7672, //CJK UNIFIED IDEOGRAPH + 0xEFA7: 0x7B4C, //CJK UNIFIED IDEOGRAPH + 0xEFA8: 0x7B8B, //CJK UNIFIED IDEOGRAPH + 0xEFA9: 0x7BAD, //CJK UNIFIED IDEOGRAPH + 0xEFAA: 0x7BC6, //CJK UNIFIED IDEOGRAPH + 0xEFAB: 0x7E8F, //CJK UNIFIED IDEOGRAPH + 0xEFAC: 0x8A6E, //CJK UNIFIED IDEOGRAPH + 0xEFAD: 0x8F3E, //CJK UNIFIED IDEOGRAPH + 0xEFAE: 0x8F49, //CJK UNIFIED IDEOGRAPH + 0xEFAF: 0x923F, //CJK UNIFIED IDEOGRAPH + 0xEFB0: 0x9293, //CJK UNIFIED IDEOGRAPH + 0xEFB1: 0x9322, //CJK UNIFIED IDEOGRAPH + 0xEFB2: 0x942B, //CJK UNIFIED IDEOGRAPH + 0xEFB3: 0x96FB, //CJK UNIFIED IDEOGRAPH + 0xEFB4: 0x985A, //CJK UNIFIED IDEOGRAPH + 0xEFB5: 0x986B, //CJK UNIFIED IDEOGRAPH + 0xEFB6: 0x991E, //CJK UNIFIED IDEOGRAPH + 0xEFB7: 0x5207, //CJK UNIFIED IDEOGRAPH + 0xEFB8: 0x622A, //CJK UNIFIED IDEOGRAPH + 0xEFB9: 0x6298, //CJK UNIFIED IDEOGRAPH + 0xEFBA: 0x6D59, //CJK UNIFIED IDEOGRAPH + 0xEFBB: 0x7664, //CJK UNIFIED IDEOGRAPH + 0xEFBC: 0x7ACA, //CJK UNIFIED IDEOGRAPH + 0xEFBD: 0x7BC0, //CJK UNIFIED IDEOGRAPH + 0xEFBE: 0x7D76, //CJK UNIFIED IDEOGRAPH + 0xEFBF: 0x5360, //CJK UNIFIED IDEOGRAPH + 0xEFC0: 0x5CBE, //CJK UNIFIED IDEOGRAPH + 0xEFC1: 0x5E97, //CJK UNIFIED IDEOGRAPH + 0xEFC2: 0x6F38, //CJK UNIFIED IDEOGRAPH + 0xEFC3: 0x70B9, //CJK UNIFIED IDEOGRAPH + 0xEFC4: 0x7C98, //CJK UNIFIED IDEOGRAPH + 0xEFC5: 0x9711, //CJK UNIFIED IDEOGRAPH + 0xEFC6: 0x9B8E, //CJK UNIFIED IDEOGRAPH + 0xEFC7: 0x9EDE, //CJK UNIFIED IDEOGRAPH + 0xEFC8: 0x63A5, //CJK UNIFIED IDEOGRAPH + 0xEFC9: 0x647A, //CJK UNIFIED IDEOGRAPH + 0xEFCA: 0x8776, //CJK UNIFIED IDEOGRAPH + 0xEFCB: 0x4E01, //CJK UNIFIED IDEOGRAPH + 0xEFCC: 0x4E95, //CJK UNIFIED IDEOGRAPH + 0xEFCD: 0x4EAD, //CJK UNIFIED IDEOGRAPH + 0xEFCE: 0x505C, //CJK UNIFIED IDEOGRAPH + 0xEFCF: 0x5075, //CJK UNIFIED IDEOGRAPH + 0xEFD0: 0x5448, //CJK UNIFIED IDEOGRAPH + 0xEFD1: 0x59C3, //CJK UNIFIED IDEOGRAPH + 0xEFD2: 0x5B9A, //CJK UNIFIED IDEOGRAPH + 0xEFD3: 0x5E40, //CJK UNIFIED IDEOGRAPH + 0xEFD4: 0x5EAD, //CJK UNIFIED IDEOGRAPH + 0xEFD5: 0x5EF7, //CJK UNIFIED IDEOGRAPH + 0xEFD6: 0x5F81, //CJK UNIFIED IDEOGRAPH + 0xEFD7: 0x60C5, //CJK UNIFIED IDEOGRAPH + 0xEFD8: 0x633A, //CJK UNIFIED IDEOGRAPH + 0xEFD9: 0x653F, //CJK UNIFIED IDEOGRAPH + 0xEFDA: 0x6574, //CJK UNIFIED IDEOGRAPH + 0xEFDB: 0x65CC, //CJK UNIFIED IDEOGRAPH + 0xEFDC: 0x6676, //CJK UNIFIED IDEOGRAPH + 0xEFDD: 0x6678, //CJK UNIFIED IDEOGRAPH + 0xEFDE: 0x67FE, //CJK UNIFIED IDEOGRAPH + 0xEFDF: 0x6968, //CJK UNIFIED IDEOGRAPH + 0xEFE0: 0x6A89, //CJK UNIFIED IDEOGRAPH + 0xEFE1: 0x6B63, //CJK UNIFIED IDEOGRAPH + 0xEFE2: 0x6C40, //CJK UNIFIED IDEOGRAPH + 0xEFE3: 0x6DC0, //CJK UNIFIED IDEOGRAPH + 0xEFE4: 0x6DE8, //CJK UNIFIED IDEOGRAPH + 0xEFE5: 0x6E1F, //CJK UNIFIED IDEOGRAPH + 0xEFE6: 0x6E5E, //CJK UNIFIED IDEOGRAPH + 0xEFE7: 0x701E, //CJK UNIFIED IDEOGRAPH + 0xEFE8: 0x70A1, //CJK UNIFIED IDEOGRAPH + 0xEFE9: 0x738E, //CJK UNIFIED IDEOGRAPH + 0xEFEA: 0x73FD, //CJK UNIFIED IDEOGRAPH + 0xEFEB: 0x753A, //CJK UNIFIED IDEOGRAPH + 0xEFEC: 0x775B, //CJK UNIFIED IDEOGRAPH + 0xEFED: 0x7887, //CJK UNIFIED IDEOGRAPH + 0xEFEE: 0x798E, //CJK UNIFIED IDEOGRAPH + 0xEFEF: 0x7A0B, //CJK UNIFIED IDEOGRAPH + 0xEFF0: 0x7A7D, //CJK UNIFIED IDEOGRAPH + 0xEFF1: 0x7CBE, //CJK UNIFIED IDEOGRAPH + 0xEFF2: 0x7D8E, //CJK UNIFIED IDEOGRAPH + 0xEFF3: 0x8247, //CJK UNIFIED IDEOGRAPH + 0xEFF4: 0x8A02, //CJK UNIFIED IDEOGRAPH + 0xEFF5: 0x8AEA, //CJK UNIFIED IDEOGRAPH + 0xEFF6: 0x8C9E, //CJK UNIFIED IDEOGRAPH + 0xEFF7: 0x912D, //CJK UNIFIED IDEOGRAPH + 0xEFF8: 0x914A, //CJK UNIFIED IDEOGRAPH + 0xEFF9: 0x91D8, //CJK UNIFIED IDEOGRAPH + 0xEFFA: 0x9266, //CJK UNIFIED IDEOGRAPH + 0xEFFB: 0x92CC, //CJK UNIFIED IDEOGRAPH + 0xEFFC: 0x9320, //CJK UNIFIED IDEOGRAPH + 0xEFFD: 0x9706, //CJK UNIFIED IDEOGRAPH + 0xEFFE: 0x9756, //CJK UNIFIED IDEOGRAPH + 0xF0A1: 0x975C, //CJK UNIFIED IDEOGRAPH + 0xF0A2: 0x9802, //CJK UNIFIED IDEOGRAPH + 0xF0A3: 0x9F0E, //CJK UNIFIED IDEOGRAPH + 0xF0A4: 0x5236, //CJK UNIFIED IDEOGRAPH + 0xF0A5: 0x5291, //CJK UNIFIED IDEOGRAPH + 0xF0A6: 0x557C, //CJK UNIFIED IDEOGRAPH + 0xF0A7: 0x5824, //CJK UNIFIED IDEOGRAPH + 0xF0A8: 0x5E1D, //CJK UNIFIED IDEOGRAPH + 0xF0A9: 0x5F1F, //CJK UNIFIED IDEOGRAPH + 0xF0AA: 0x608C, //CJK UNIFIED IDEOGRAPH + 0xF0AB: 0x63D0, //CJK UNIFIED IDEOGRAPH + 0xF0AC: 0x68AF, //CJK UNIFIED IDEOGRAPH + 0xF0AD: 0x6FDF, //CJK UNIFIED IDEOGRAPH + 0xF0AE: 0x796D, //CJK UNIFIED IDEOGRAPH + 0xF0AF: 0x7B2C, //CJK UNIFIED IDEOGRAPH + 0xF0B0: 0x81CD, //CJK UNIFIED IDEOGRAPH + 0xF0B1: 0x85BA, //CJK UNIFIED IDEOGRAPH + 0xF0B2: 0x88FD, //CJK UNIFIED IDEOGRAPH + 0xF0B3: 0x8AF8, //CJK UNIFIED IDEOGRAPH + 0xF0B4: 0x8E44, //CJK UNIFIED IDEOGRAPH + 0xF0B5: 0x918D, //CJK UNIFIED IDEOGRAPH + 0xF0B6: 0x9664, //CJK UNIFIED IDEOGRAPH + 0xF0B7: 0x969B, //CJK UNIFIED IDEOGRAPH + 0xF0B8: 0x973D, //CJK UNIFIED IDEOGRAPH + 0xF0B9: 0x984C, //CJK UNIFIED IDEOGRAPH + 0xF0BA: 0x9F4A, //CJK UNIFIED IDEOGRAPH + 0xF0BB: 0x4FCE, //CJK UNIFIED IDEOGRAPH + 0xF0BC: 0x5146, //CJK UNIFIED IDEOGRAPH + 0xF0BD: 0x51CB, //CJK UNIFIED IDEOGRAPH + 0xF0BE: 0x52A9, //CJK UNIFIED IDEOGRAPH + 0xF0BF: 0x5632, //CJK UNIFIED IDEOGRAPH + 0xF0C0: 0x5F14, //CJK UNIFIED IDEOGRAPH + 0xF0C1: 0x5F6B, //CJK UNIFIED IDEOGRAPH + 0xF0C2: 0x63AA, //CJK UNIFIED IDEOGRAPH + 0xF0C3: 0x64CD, //CJK UNIFIED IDEOGRAPH + 0xF0C4: 0x65E9, //CJK UNIFIED IDEOGRAPH + 0xF0C5: 0x6641, //CJK UNIFIED IDEOGRAPH + 0xF0C6: 0x66FA, //CJK UNIFIED IDEOGRAPH + 0xF0C7: 0x66F9, //CJK UNIFIED IDEOGRAPH + 0xF0C8: 0x671D, //CJK UNIFIED IDEOGRAPH + 0xF0C9: 0x689D, //CJK UNIFIED IDEOGRAPH + 0xF0CA: 0x68D7, //CJK UNIFIED IDEOGRAPH + 0xF0CB: 0x69FD, //CJK UNIFIED IDEOGRAPH + 0xF0CC: 0x6F15, //CJK UNIFIED IDEOGRAPH + 0xF0CD: 0x6F6E, //CJK UNIFIED IDEOGRAPH + 0xF0CE: 0x7167, //CJK UNIFIED IDEOGRAPH + 0xF0CF: 0x71E5, //CJK UNIFIED IDEOGRAPH + 0xF0D0: 0x722A, //CJK UNIFIED IDEOGRAPH + 0xF0D1: 0x74AA, //CJK UNIFIED IDEOGRAPH + 0xF0D2: 0x773A, //CJK UNIFIED IDEOGRAPH + 0xF0D3: 0x7956, //CJK UNIFIED IDEOGRAPH + 0xF0D4: 0x795A, //CJK UNIFIED IDEOGRAPH + 0xF0D5: 0x79DF, //CJK UNIFIED IDEOGRAPH + 0xF0D6: 0x7A20, //CJK UNIFIED IDEOGRAPH + 0xF0D7: 0x7A95, //CJK UNIFIED IDEOGRAPH + 0xF0D8: 0x7C97, //CJK UNIFIED IDEOGRAPH + 0xF0D9: 0x7CDF, //CJK UNIFIED IDEOGRAPH + 0xF0DA: 0x7D44, //CJK UNIFIED IDEOGRAPH + 0xF0DB: 0x7E70, //CJK UNIFIED IDEOGRAPH + 0xF0DC: 0x8087, //CJK UNIFIED IDEOGRAPH + 0xF0DD: 0x85FB, //CJK UNIFIED IDEOGRAPH + 0xF0DE: 0x86A4, //CJK UNIFIED IDEOGRAPH + 0xF0DF: 0x8A54, //CJK UNIFIED IDEOGRAPH + 0xF0E0: 0x8ABF, //CJK UNIFIED IDEOGRAPH + 0xF0E1: 0x8D99, //CJK UNIFIED IDEOGRAPH + 0xF0E2: 0x8E81, //CJK UNIFIED IDEOGRAPH + 0xF0E3: 0x9020, //CJK UNIFIED IDEOGRAPH + 0xF0E4: 0x906D, //CJK UNIFIED IDEOGRAPH + 0xF0E5: 0x91E3, //CJK UNIFIED IDEOGRAPH + 0xF0E6: 0x963B, //CJK UNIFIED IDEOGRAPH + 0xF0E7: 0x96D5, //CJK UNIFIED IDEOGRAPH + 0xF0E8: 0x9CE5, //CJK UNIFIED IDEOGRAPH + 0xF0E9: 0x65CF, //CJK UNIFIED IDEOGRAPH + 0xF0EA: 0x7C07, //CJK UNIFIED IDEOGRAPH + 0xF0EB: 0x8DB3, //CJK UNIFIED IDEOGRAPH + 0xF0EC: 0x93C3, //CJK UNIFIED IDEOGRAPH + 0xF0ED: 0x5B58, //CJK UNIFIED IDEOGRAPH + 0xF0EE: 0x5C0A, //CJK UNIFIED IDEOGRAPH + 0xF0EF: 0x5352, //CJK UNIFIED IDEOGRAPH + 0xF0F0: 0x62D9, //CJK UNIFIED IDEOGRAPH + 0xF0F1: 0x731D, //CJK UNIFIED IDEOGRAPH + 0xF0F2: 0x5027, //CJK UNIFIED IDEOGRAPH + 0xF0F3: 0x5B97, //CJK UNIFIED IDEOGRAPH + 0xF0F4: 0x5F9E, //CJK UNIFIED IDEOGRAPH + 0xF0F5: 0x60B0, //CJK UNIFIED IDEOGRAPH + 0xF0F6: 0x616B, //CJK UNIFIED IDEOGRAPH + 0xF0F7: 0x68D5, //CJK UNIFIED IDEOGRAPH + 0xF0F8: 0x6DD9, //CJK UNIFIED IDEOGRAPH + 0xF0F9: 0x742E, //CJK UNIFIED IDEOGRAPH + 0xF0FA: 0x7A2E, //CJK UNIFIED IDEOGRAPH + 0xF0FB: 0x7D42, //CJK UNIFIED IDEOGRAPH + 0xF0FC: 0x7D9C, //CJK UNIFIED IDEOGRAPH + 0xF0FD: 0x7E31, //CJK UNIFIED IDEOGRAPH + 0xF0FE: 0x816B, //CJK UNIFIED IDEOGRAPH + 0xF1A1: 0x8E2A, //CJK UNIFIED IDEOGRAPH + 0xF1A2: 0x8E35, //CJK UNIFIED IDEOGRAPH + 0xF1A3: 0x937E, //CJK UNIFIED IDEOGRAPH + 0xF1A4: 0x9418, //CJK UNIFIED IDEOGRAPH + 0xF1A5: 0x4F50, //CJK UNIFIED IDEOGRAPH + 0xF1A6: 0x5750, //CJK UNIFIED IDEOGRAPH + 0xF1A7: 0x5DE6, //CJK UNIFIED IDEOGRAPH + 0xF1A8: 0x5EA7, //CJK UNIFIED IDEOGRAPH + 0xF1A9: 0x632B, //CJK UNIFIED IDEOGRAPH + 0xF1AA: 0x7F6A, //CJK UNIFIED IDEOGRAPH + 0xF1AB: 0x4E3B, //CJK UNIFIED IDEOGRAPH + 0xF1AC: 0x4F4F, //CJK UNIFIED IDEOGRAPH + 0xF1AD: 0x4F8F, //CJK UNIFIED IDEOGRAPH + 0xF1AE: 0x505A, //CJK UNIFIED IDEOGRAPH + 0xF1AF: 0x59DD, //CJK UNIFIED IDEOGRAPH + 0xF1B0: 0x80C4, //CJK UNIFIED IDEOGRAPH + 0xF1B1: 0x546A, //CJK UNIFIED IDEOGRAPH + 0xF1B2: 0x5468, //CJK UNIFIED IDEOGRAPH + 0xF1B3: 0x55FE, //CJK UNIFIED IDEOGRAPH + 0xF1B4: 0x594F, //CJK UNIFIED IDEOGRAPH + 0xF1B5: 0x5B99, //CJK UNIFIED IDEOGRAPH + 0xF1B6: 0x5DDE, //CJK UNIFIED IDEOGRAPH + 0xF1B7: 0x5EDA, //CJK UNIFIED IDEOGRAPH + 0xF1B8: 0x665D, //CJK UNIFIED IDEOGRAPH + 0xF1B9: 0x6731, //CJK UNIFIED IDEOGRAPH + 0xF1BA: 0x67F1, //CJK UNIFIED IDEOGRAPH + 0xF1BB: 0x682A, //CJK UNIFIED IDEOGRAPH + 0xF1BC: 0x6CE8, //CJK UNIFIED IDEOGRAPH + 0xF1BD: 0x6D32, //CJK UNIFIED IDEOGRAPH + 0xF1BE: 0x6E4A, //CJK UNIFIED IDEOGRAPH + 0xF1BF: 0x6F8D, //CJK UNIFIED IDEOGRAPH + 0xF1C0: 0x70B7, //CJK UNIFIED IDEOGRAPH + 0xF1C1: 0x73E0, //CJK UNIFIED IDEOGRAPH + 0xF1C2: 0x7587, //CJK UNIFIED IDEOGRAPH + 0xF1C3: 0x7C4C, //CJK UNIFIED IDEOGRAPH + 0xF1C4: 0x7D02, //CJK UNIFIED IDEOGRAPH + 0xF1C5: 0x7D2C, //CJK UNIFIED IDEOGRAPH + 0xF1C6: 0x7DA2, //CJK UNIFIED IDEOGRAPH + 0xF1C7: 0x821F, //CJK UNIFIED IDEOGRAPH + 0xF1C8: 0x86DB, //CJK UNIFIED IDEOGRAPH + 0xF1C9: 0x8A3B, //CJK UNIFIED IDEOGRAPH + 0xF1CA: 0x8A85, //CJK UNIFIED IDEOGRAPH + 0xF1CB: 0x8D70, //CJK UNIFIED IDEOGRAPH + 0xF1CC: 0x8E8A, //CJK UNIFIED IDEOGRAPH + 0xF1CD: 0x8F33, //CJK UNIFIED IDEOGRAPH + 0xF1CE: 0x9031, //CJK UNIFIED IDEOGRAPH + 0xF1CF: 0x914E, //CJK UNIFIED IDEOGRAPH + 0xF1D0: 0x9152, //CJK UNIFIED IDEOGRAPH + 0xF1D1: 0x9444, //CJK UNIFIED IDEOGRAPH + 0xF1D2: 0x99D0, //CJK UNIFIED IDEOGRAPH + 0xF1D3: 0x7AF9, //CJK UNIFIED IDEOGRAPH + 0xF1D4: 0x7CA5, //CJK UNIFIED IDEOGRAPH + 0xF1D5: 0x4FCA, //CJK UNIFIED IDEOGRAPH + 0xF1D6: 0x5101, //CJK UNIFIED IDEOGRAPH + 0xF1D7: 0x51C6, //CJK UNIFIED IDEOGRAPH + 0xF1D8: 0x57C8, //CJK UNIFIED IDEOGRAPH + 0xF1D9: 0x5BEF, //CJK UNIFIED IDEOGRAPH + 0xF1DA: 0x5CFB, //CJK UNIFIED IDEOGRAPH + 0xF1DB: 0x6659, //CJK UNIFIED IDEOGRAPH + 0xF1DC: 0x6A3D, //CJK UNIFIED IDEOGRAPH + 0xF1DD: 0x6D5A, //CJK UNIFIED IDEOGRAPH + 0xF1DE: 0x6E96, //CJK UNIFIED IDEOGRAPH + 0xF1DF: 0x6FEC, //CJK UNIFIED IDEOGRAPH + 0xF1E0: 0x710C, //CJK UNIFIED IDEOGRAPH + 0xF1E1: 0x756F, //CJK UNIFIED IDEOGRAPH + 0xF1E2: 0x7AE3, //CJK UNIFIED IDEOGRAPH + 0xF1E3: 0x8822, //CJK UNIFIED IDEOGRAPH + 0xF1E4: 0x9021, //CJK UNIFIED IDEOGRAPH + 0xF1E5: 0x9075, //CJK UNIFIED IDEOGRAPH + 0xF1E6: 0x96CB, //CJK UNIFIED IDEOGRAPH + 0xF1E7: 0x99FF, //CJK UNIFIED IDEOGRAPH + 0xF1E8: 0x8301, //CJK UNIFIED IDEOGRAPH + 0xF1E9: 0x4E2D, //CJK UNIFIED IDEOGRAPH + 0xF1EA: 0x4EF2, //CJK UNIFIED IDEOGRAPH + 0xF1EB: 0x8846, //CJK UNIFIED IDEOGRAPH + 0xF1EC: 0x91CD, //CJK UNIFIED IDEOGRAPH + 0xF1ED: 0x537D, //CJK UNIFIED IDEOGRAPH + 0xF1EE: 0x6ADB, //CJK UNIFIED IDEOGRAPH + 0xF1EF: 0x696B, //CJK UNIFIED IDEOGRAPH + 0xF1F0: 0x6C41, //CJK UNIFIED IDEOGRAPH + 0xF1F1: 0x847A, //CJK UNIFIED IDEOGRAPH + 0xF1F2: 0x589E, //CJK UNIFIED IDEOGRAPH + 0xF1F3: 0x618E, //CJK UNIFIED IDEOGRAPH + 0xF1F4: 0x66FE, //CJK UNIFIED IDEOGRAPH + 0xF1F5: 0x62EF, //CJK UNIFIED IDEOGRAPH + 0xF1F6: 0x70DD, //CJK UNIFIED IDEOGRAPH + 0xF1F7: 0x7511, //CJK UNIFIED IDEOGRAPH + 0xF1F8: 0x75C7, //CJK UNIFIED IDEOGRAPH + 0xF1F9: 0x7E52, //CJK UNIFIED IDEOGRAPH + 0xF1FA: 0x84B8, //CJK UNIFIED IDEOGRAPH + 0xF1FB: 0x8B49, //CJK UNIFIED IDEOGRAPH + 0xF1FC: 0x8D08, //CJK UNIFIED IDEOGRAPH + 0xF1FD: 0x4E4B, //CJK UNIFIED IDEOGRAPH + 0xF1FE: 0x53EA, //CJK UNIFIED IDEOGRAPH + 0xF2A1: 0x54AB, //CJK UNIFIED IDEOGRAPH + 0xF2A2: 0x5730, //CJK UNIFIED IDEOGRAPH + 0xF2A3: 0x5740, //CJK UNIFIED IDEOGRAPH + 0xF2A4: 0x5FD7, //CJK UNIFIED IDEOGRAPH + 0xF2A5: 0x6301, //CJK UNIFIED IDEOGRAPH + 0xF2A6: 0x6307, //CJK UNIFIED IDEOGRAPH + 0xF2A7: 0x646F, //CJK UNIFIED IDEOGRAPH + 0xF2A8: 0x652F, //CJK UNIFIED IDEOGRAPH + 0xF2A9: 0x65E8, //CJK UNIFIED IDEOGRAPH + 0xF2AA: 0x667A, //CJK UNIFIED IDEOGRAPH + 0xF2AB: 0x679D, //CJK UNIFIED IDEOGRAPH + 0xF2AC: 0x67B3, //CJK UNIFIED IDEOGRAPH + 0xF2AD: 0x6B62, //CJK UNIFIED IDEOGRAPH + 0xF2AE: 0x6C60, //CJK UNIFIED IDEOGRAPH + 0xF2AF: 0x6C9A, //CJK UNIFIED IDEOGRAPH + 0xF2B0: 0x6F2C, //CJK UNIFIED IDEOGRAPH + 0xF2B1: 0x77E5, //CJK UNIFIED IDEOGRAPH + 0xF2B2: 0x7825, //CJK UNIFIED IDEOGRAPH + 0xF2B3: 0x7949, //CJK UNIFIED IDEOGRAPH + 0xF2B4: 0x7957, //CJK UNIFIED IDEOGRAPH + 0xF2B5: 0x7D19, //CJK UNIFIED IDEOGRAPH + 0xF2B6: 0x80A2, //CJK UNIFIED IDEOGRAPH + 0xF2B7: 0x8102, //CJK UNIFIED IDEOGRAPH + 0xF2B8: 0x81F3, //CJK UNIFIED IDEOGRAPH + 0xF2B9: 0x829D, //CJK UNIFIED IDEOGRAPH + 0xF2BA: 0x82B7, //CJK UNIFIED IDEOGRAPH + 0xF2BB: 0x8718, //CJK UNIFIED IDEOGRAPH + 0xF2BC: 0x8A8C, //CJK UNIFIED IDEOGRAPH + 0xF2BD: 0xF9FC, //CJK COMPATIBILITY IDEOGRAPH + 0xF2BE: 0x8D04, //CJK UNIFIED IDEOGRAPH + 0xF2BF: 0x8DBE, //CJK UNIFIED IDEOGRAPH + 0xF2C0: 0x9072, //CJK UNIFIED IDEOGRAPH + 0xF2C1: 0x76F4, //CJK UNIFIED IDEOGRAPH + 0xF2C2: 0x7A19, //CJK UNIFIED IDEOGRAPH + 0xF2C3: 0x7A37, //CJK UNIFIED IDEOGRAPH + 0xF2C4: 0x7E54, //CJK UNIFIED IDEOGRAPH + 0xF2C5: 0x8077, //CJK UNIFIED IDEOGRAPH + 0xF2C6: 0x5507, //CJK UNIFIED IDEOGRAPH + 0xF2C7: 0x55D4, //CJK UNIFIED IDEOGRAPH + 0xF2C8: 0x5875, //CJK UNIFIED IDEOGRAPH + 0xF2C9: 0x632F, //CJK UNIFIED IDEOGRAPH + 0xF2CA: 0x6422, //CJK UNIFIED IDEOGRAPH + 0xF2CB: 0x6649, //CJK UNIFIED IDEOGRAPH + 0xF2CC: 0x664B, //CJK UNIFIED IDEOGRAPH + 0xF2CD: 0x686D, //CJK UNIFIED IDEOGRAPH + 0xF2CE: 0x699B, //CJK UNIFIED IDEOGRAPH + 0xF2CF: 0x6B84, //CJK UNIFIED IDEOGRAPH + 0xF2D0: 0x6D25, //CJK UNIFIED IDEOGRAPH + 0xF2D1: 0x6EB1, //CJK UNIFIED IDEOGRAPH + 0xF2D2: 0x73CD, //CJK UNIFIED IDEOGRAPH + 0xF2D3: 0x7468, //CJK UNIFIED IDEOGRAPH + 0xF2D4: 0x74A1, //CJK UNIFIED IDEOGRAPH + 0xF2D5: 0x755B, //CJK UNIFIED IDEOGRAPH + 0xF2D6: 0x75B9, //CJK UNIFIED IDEOGRAPH + 0xF2D7: 0x76E1, //CJK UNIFIED IDEOGRAPH + 0xF2D8: 0x771E, //CJK UNIFIED IDEOGRAPH + 0xF2D9: 0x778B, //CJK UNIFIED IDEOGRAPH + 0xF2DA: 0x79E6, //CJK UNIFIED IDEOGRAPH + 0xF2DB: 0x7E09, //CJK UNIFIED IDEOGRAPH + 0xF2DC: 0x7E1D, //CJK UNIFIED IDEOGRAPH + 0xF2DD: 0x81FB, //CJK UNIFIED IDEOGRAPH + 0xF2DE: 0x852F, //CJK UNIFIED IDEOGRAPH + 0xF2DF: 0x8897, //CJK UNIFIED IDEOGRAPH + 0xF2E0: 0x8A3A, //CJK UNIFIED IDEOGRAPH + 0xF2E1: 0x8CD1, //CJK UNIFIED IDEOGRAPH + 0xF2E2: 0x8EEB, //CJK UNIFIED IDEOGRAPH + 0xF2E3: 0x8FB0, //CJK UNIFIED IDEOGRAPH + 0xF2E4: 0x9032, //CJK UNIFIED IDEOGRAPH + 0xF2E5: 0x93AD, //CJK UNIFIED IDEOGRAPH + 0xF2E6: 0x9663, //CJK UNIFIED IDEOGRAPH + 0xF2E7: 0x9673, //CJK UNIFIED IDEOGRAPH + 0xF2E8: 0x9707, //CJK UNIFIED IDEOGRAPH + 0xF2E9: 0x4F84, //CJK UNIFIED IDEOGRAPH + 0xF2EA: 0x53F1, //CJK UNIFIED IDEOGRAPH + 0xF2EB: 0x59EA, //CJK UNIFIED IDEOGRAPH + 0xF2EC: 0x5AC9, //CJK UNIFIED IDEOGRAPH + 0xF2ED: 0x5E19, //CJK UNIFIED IDEOGRAPH + 0xF2EE: 0x684E, //CJK UNIFIED IDEOGRAPH + 0xF2EF: 0x74C6, //CJK UNIFIED IDEOGRAPH + 0xF2F0: 0x75BE, //CJK UNIFIED IDEOGRAPH + 0xF2F1: 0x79E9, //CJK UNIFIED IDEOGRAPH + 0xF2F2: 0x7A92, //CJK UNIFIED IDEOGRAPH + 0xF2F3: 0x81A3, //CJK UNIFIED IDEOGRAPH + 0xF2F4: 0x86ED, //CJK UNIFIED IDEOGRAPH + 0xF2F5: 0x8CEA, //CJK UNIFIED IDEOGRAPH + 0xF2F6: 0x8DCC, //CJK UNIFIED IDEOGRAPH + 0xF2F7: 0x8FED, //CJK UNIFIED IDEOGRAPH + 0xF2F8: 0x659F, //CJK UNIFIED IDEOGRAPH + 0xF2F9: 0x6715, //CJK UNIFIED IDEOGRAPH + 0xF2FA: 0xF9FD, //CJK COMPATIBILITY IDEOGRAPH + 0xF2FB: 0x57F7, //CJK UNIFIED IDEOGRAPH + 0xF2FC: 0x6F57, //CJK UNIFIED IDEOGRAPH + 0xF2FD: 0x7DDD, //CJK UNIFIED IDEOGRAPH + 0xF2FE: 0x8F2F, //CJK UNIFIED IDEOGRAPH + 0xF3A1: 0x93F6, //CJK UNIFIED IDEOGRAPH + 0xF3A2: 0x96C6, //CJK UNIFIED IDEOGRAPH + 0xF3A3: 0x5FB5, //CJK UNIFIED IDEOGRAPH + 0xF3A4: 0x61F2, //CJK UNIFIED IDEOGRAPH + 0xF3A5: 0x6F84, //CJK UNIFIED IDEOGRAPH + 0xF3A6: 0x4E14, //CJK UNIFIED IDEOGRAPH + 0xF3A7: 0x4F98, //CJK UNIFIED IDEOGRAPH + 0xF3A8: 0x501F, //CJK UNIFIED IDEOGRAPH + 0xF3A9: 0x53C9, //CJK UNIFIED IDEOGRAPH + 0xF3AA: 0x55DF, //CJK UNIFIED IDEOGRAPH + 0xF3AB: 0x5D6F, //CJK UNIFIED IDEOGRAPH + 0xF3AC: 0x5DEE, //CJK UNIFIED IDEOGRAPH + 0xF3AD: 0x6B21, //CJK UNIFIED IDEOGRAPH + 0xF3AE: 0x6B64, //CJK UNIFIED IDEOGRAPH + 0xF3AF: 0x78CB, //CJK UNIFIED IDEOGRAPH + 0xF3B0: 0x7B9A, //CJK UNIFIED IDEOGRAPH + 0xF3B1: 0xF9FE, //CJK COMPATIBILITY IDEOGRAPH + 0xF3B2: 0x8E49, //CJK UNIFIED IDEOGRAPH + 0xF3B3: 0x8ECA, //CJK UNIFIED IDEOGRAPH + 0xF3B4: 0x906E, //CJK UNIFIED IDEOGRAPH + 0xF3B5: 0x6349, //CJK UNIFIED IDEOGRAPH + 0xF3B6: 0x643E, //CJK UNIFIED IDEOGRAPH + 0xF3B7: 0x7740, //CJK UNIFIED IDEOGRAPH + 0xF3B8: 0x7A84, //CJK UNIFIED IDEOGRAPH + 0xF3B9: 0x932F, //CJK UNIFIED IDEOGRAPH + 0xF3BA: 0x947F, //CJK UNIFIED IDEOGRAPH + 0xF3BB: 0x9F6A, //CJK UNIFIED IDEOGRAPH + 0xF3BC: 0x64B0, //CJK UNIFIED IDEOGRAPH + 0xF3BD: 0x6FAF, //CJK UNIFIED IDEOGRAPH + 0xF3BE: 0x71E6, //CJK UNIFIED IDEOGRAPH + 0xF3BF: 0x74A8, //CJK UNIFIED IDEOGRAPH + 0xF3C0: 0x74DA, //CJK UNIFIED IDEOGRAPH + 0xF3C1: 0x7AC4, //CJK UNIFIED IDEOGRAPH + 0xF3C2: 0x7C12, //CJK UNIFIED IDEOGRAPH + 0xF3C3: 0x7E82, //CJK UNIFIED IDEOGRAPH + 0xF3C4: 0x7CB2, //CJK UNIFIED IDEOGRAPH + 0xF3C5: 0x7E98, //CJK UNIFIED IDEOGRAPH + 0xF3C6: 0x8B9A, //CJK UNIFIED IDEOGRAPH + 0xF3C7: 0x8D0A, //CJK UNIFIED IDEOGRAPH + 0xF3C8: 0x947D, //CJK UNIFIED IDEOGRAPH + 0xF3C9: 0x9910, //CJK UNIFIED IDEOGRAPH + 0xF3CA: 0x994C, //CJK UNIFIED IDEOGRAPH + 0xF3CB: 0x5239, //CJK UNIFIED IDEOGRAPH + 0xF3CC: 0x5BDF, //CJK UNIFIED IDEOGRAPH + 0xF3CD: 0x64E6, //CJK UNIFIED IDEOGRAPH + 0xF3CE: 0x672D, //CJK UNIFIED IDEOGRAPH + 0xF3CF: 0x7D2E, //CJK UNIFIED IDEOGRAPH + 0xF3D0: 0x50ED, //CJK UNIFIED IDEOGRAPH + 0xF3D1: 0x53C3, //CJK UNIFIED IDEOGRAPH + 0xF3D2: 0x5879, //CJK UNIFIED IDEOGRAPH + 0xF3D3: 0x6158, //CJK UNIFIED IDEOGRAPH + 0xF3D4: 0x6159, //CJK UNIFIED IDEOGRAPH + 0xF3D5: 0x61FA, //CJK UNIFIED IDEOGRAPH + 0xF3D6: 0x65AC, //CJK UNIFIED IDEOGRAPH + 0xF3D7: 0x7AD9, //CJK UNIFIED IDEOGRAPH + 0xF3D8: 0x8B92, //CJK UNIFIED IDEOGRAPH + 0xF3D9: 0x8B96, //CJK UNIFIED IDEOGRAPH + 0xF3DA: 0x5009, //CJK UNIFIED IDEOGRAPH + 0xF3DB: 0x5021, //CJK UNIFIED IDEOGRAPH + 0xF3DC: 0x5275, //CJK UNIFIED IDEOGRAPH + 0xF3DD: 0x5531, //CJK UNIFIED IDEOGRAPH + 0xF3DE: 0x5A3C, //CJK UNIFIED IDEOGRAPH + 0xF3DF: 0x5EE0, //CJK UNIFIED IDEOGRAPH + 0xF3E0: 0x5F70, //CJK UNIFIED IDEOGRAPH + 0xF3E1: 0x6134, //CJK UNIFIED IDEOGRAPH + 0xF3E2: 0x655E, //CJK UNIFIED IDEOGRAPH + 0xF3E3: 0x660C, //CJK UNIFIED IDEOGRAPH + 0xF3E4: 0x6636, //CJK UNIFIED IDEOGRAPH + 0xF3E5: 0x66A2, //CJK UNIFIED IDEOGRAPH + 0xF3E6: 0x69CD, //CJK UNIFIED IDEOGRAPH + 0xF3E7: 0x6EC4, //CJK UNIFIED IDEOGRAPH + 0xF3E8: 0x6F32, //CJK UNIFIED IDEOGRAPH + 0xF3E9: 0x7316, //CJK UNIFIED IDEOGRAPH + 0xF3EA: 0x7621, //CJK UNIFIED IDEOGRAPH + 0xF3EB: 0x7A93, //CJK UNIFIED IDEOGRAPH + 0xF3EC: 0x8139, //CJK UNIFIED IDEOGRAPH + 0xF3ED: 0x8259, //CJK UNIFIED IDEOGRAPH + 0xF3EE: 0x83D6, //CJK UNIFIED IDEOGRAPH + 0xF3EF: 0x84BC, //CJK UNIFIED IDEOGRAPH + 0xF3F0: 0x50B5, //CJK UNIFIED IDEOGRAPH + 0xF3F1: 0x57F0, //CJK UNIFIED IDEOGRAPH + 0xF3F2: 0x5BC0, //CJK UNIFIED IDEOGRAPH + 0xF3F3: 0x5BE8, //CJK UNIFIED IDEOGRAPH + 0xF3F4: 0x5F69, //CJK UNIFIED IDEOGRAPH + 0xF3F5: 0x63A1, //CJK UNIFIED IDEOGRAPH + 0xF3F6: 0x7826, //CJK UNIFIED IDEOGRAPH + 0xF3F7: 0x7DB5, //CJK UNIFIED IDEOGRAPH + 0xF3F8: 0x83DC, //CJK UNIFIED IDEOGRAPH + 0xF3F9: 0x8521, //CJK UNIFIED IDEOGRAPH + 0xF3FA: 0x91C7, //CJK UNIFIED IDEOGRAPH + 0xF3FB: 0x91F5, //CJK UNIFIED IDEOGRAPH + 0xF3FC: 0x518A, //CJK UNIFIED IDEOGRAPH + 0xF3FD: 0x67F5, //CJK UNIFIED IDEOGRAPH + 0xF3FE: 0x7B56, //CJK UNIFIED IDEOGRAPH + 0xF4A1: 0x8CAC, //CJK UNIFIED IDEOGRAPH + 0xF4A2: 0x51C4, //CJK UNIFIED IDEOGRAPH + 0xF4A3: 0x59BB, //CJK UNIFIED IDEOGRAPH + 0xF4A4: 0x60BD, //CJK UNIFIED IDEOGRAPH + 0xF4A5: 0x8655, //CJK UNIFIED IDEOGRAPH + 0xF4A6: 0x501C, //CJK UNIFIED IDEOGRAPH + 0xF4A7: 0xF9FF, //CJK COMPATIBILITY IDEOGRAPH + 0xF4A8: 0x5254, //CJK UNIFIED IDEOGRAPH + 0xF4A9: 0x5C3A, //CJK UNIFIED IDEOGRAPH + 0xF4AA: 0x617D, //CJK UNIFIED IDEOGRAPH + 0xF4AB: 0x621A, //CJK UNIFIED IDEOGRAPH + 0xF4AC: 0x62D3, //CJK UNIFIED IDEOGRAPH + 0xF4AD: 0x64F2, //CJK UNIFIED IDEOGRAPH + 0xF4AE: 0x65A5, //CJK UNIFIED IDEOGRAPH + 0xF4AF: 0x6ECC, //CJK UNIFIED IDEOGRAPH + 0xF4B0: 0x7620, //CJK UNIFIED IDEOGRAPH + 0xF4B1: 0x810A, //CJK UNIFIED IDEOGRAPH + 0xF4B2: 0x8E60, //CJK UNIFIED IDEOGRAPH + 0xF4B3: 0x965F, //CJK UNIFIED IDEOGRAPH + 0xF4B4: 0x96BB, //CJK UNIFIED IDEOGRAPH + 0xF4B5: 0x4EDF, //CJK UNIFIED IDEOGRAPH + 0xF4B6: 0x5343, //CJK UNIFIED IDEOGRAPH + 0xF4B7: 0x5598, //CJK UNIFIED IDEOGRAPH + 0xF4B8: 0x5929, //CJK UNIFIED IDEOGRAPH + 0xF4B9: 0x5DDD, //CJK UNIFIED IDEOGRAPH + 0xF4BA: 0x64C5, //CJK UNIFIED IDEOGRAPH + 0xF4BB: 0x6CC9, //CJK UNIFIED IDEOGRAPH + 0xF4BC: 0x6DFA, //CJK UNIFIED IDEOGRAPH + 0xF4BD: 0x7394, //CJK UNIFIED IDEOGRAPH + 0xF4BE: 0x7A7F, //CJK UNIFIED IDEOGRAPH + 0xF4BF: 0x821B, //CJK UNIFIED IDEOGRAPH + 0xF4C0: 0x85A6, //CJK UNIFIED IDEOGRAPH + 0xF4C1: 0x8CE4, //CJK UNIFIED IDEOGRAPH + 0xF4C2: 0x8E10, //CJK UNIFIED IDEOGRAPH + 0xF4C3: 0x9077, //CJK UNIFIED IDEOGRAPH + 0xF4C4: 0x91E7, //CJK UNIFIED IDEOGRAPH + 0xF4C5: 0x95E1, //CJK UNIFIED IDEOGRAPH + 0xF4C6: 0x9621, //CJK UNIFIED IDEOGRAPH + 0xF4C7: 0x97C6, //CJK UNIFIED IDEOGRAPH + 0xF4C8: 0x51F8, //CJK UNIFIED IDEOGRAPH + 0xF4C9: 0x54F2, //CJK UNIFIED IDEOGRAPH + 0xF4CA: 0x5586, //CJK UNIFIED IDEOGRAPH + 0xF4CB: 0x5FB9, //CJK UNIFIED IDEOGRAPH + 0xF4CC: 0x64A4, //CJK UNIFIED IDEOGRAPH + 0xF4CD: 0x6F88, //CJK UNIFIED IDEOGRAPH + 0xF4CE: 0x7DB4, //CJK UNIFIED IDEOGRAPH + 0xF4CF: 0x8F1F, //CJK UNIFIED IDEOGRAPH + 0xF4D0: 0x8F4D, //CJK UNIFIED IDEOGRAPH + 0xF4D1: 0x9435, //CJK UNIFIED IDEOGRAPH + 0xF4D2: 0x50C9, //CJK UNIFIED IDEOGRAPH + 0xF4D3: 0x5C16, //CJK UNIFIED IDEOGRAPH + 0xF4D4: 0x6CBE, //CJK UNIFIED IDEOGRAPH + 0xF4D5: 0x6DFB, //CJK UNIFIED IDEOGRAPH + 0xF4D6: 0x751B, //CJK UNIFIED IDEOGRAPH + 0xF4D7: 0x77BB, //CJK UNIFIED IDEOGRAPH + 0xF4D8: 0x7C3D, //CJK UNIFIED IDEOGRAPH + 0xF4D9: 0x7C64, //CJK UNIFIED IDEOGRAPH + 0xF4DA: 0x8A79, //CJK UNIFIED IDEOGRAPH + 0xF4DB: 0x8AC2, //CJK UNIFIED IDEOGRAPH + 0xF4DC: 0x581E, //CJK UNIFIED IDEOGRAPH + 0xF4DD: 0x59BE, //CJK UNIFIED IDEOGRAPH + 0xF4DE: 0x5E16, //CJK UNIFIED IDEOGRAPH + 0xF4DF: 0x6377, //CJK UNIFIED IDEOGRAPH + 0xF4E0: 0x7252, //CJK UNIFIED IDEOGRAPH + 0xF4E1: 0x758A, //CJK UNIFIED IDEOGRAPH + 0xF4E2: 0x776B, //CJK UNIFIED IDEOGRAPH + 0xF4E3: 0x8ADC, //CJK UNIFIED IDEOGRAPH + 0xF4E4: 0x8CBC, //CJK UNIFIED IDEOGRAPH + 0xF4E5: 0x8F12, //CJK UNIFIED IDEOGRAPH + 0xF4E6: 0x5EF3, //CJK UNIFIED IDEOGRAPH + 0xF4E7: 0x6674, //CJK UNIFIED IDEOGRAPH + 0xF4E8: 0x6DF8, //CJK UNIFIED IDEOGRAPH + 0xF4E9: 0x807D, //CJK UNIFIED IDEOGRAPH + 0xF4EA: 0x83C1, //CJK UNIFIED IDEOGRAPH + 0xF4EB: 0x8ACB, //CJK UNIFIED IDEOGRAPH + 0xF4EC: 0x9751, //CJK UNIFIED IDEOGRAPH + 0xF4ED: 0x9BD6, //CJK UNIFIED IDEOGRAPH + 0xF4EE: 0xFA00, //CJK COMPATIBILITY IDEOGRAPH + 0xF4EF: 0x5243, //CJK UNIFIED IDEOGRAPH + 0xF4F0: 0x66FF, //CJK UNIFIED IDEOGRAPH + 0xF4F1: 0x6D95, //CJK UNIFIED IDEOGRAPH + 0xF4F2: 0x6EEF, //CJK UNIFIED IDEOGRAPH + 0xF4F3: 0x7DE0, //CJK UNIFIED IDEOGRAPH + 0xF4F4: 0x8AE6, //CJK UNIFIED IDEOGRAPH + 0xF4F5: 0x902E, //CJK UNIFIED IDEOGRAPH + 0xF4F6: 0x905E, //CJK UNIFIED IDEOGRAPH + 0xF4F7: 0x9AD4, //CJK UNIFIED IDEOGRAPH + 0xF4F8: 0x521D, //CJK UNIFIED IDEOGRAPH + 0xF4F9: 0x527F, //CJK UNIFIED IDEOGRAPH + 0xF4FA: 0x54E8, //CJK UNIFIED IDEOGRAPH + 0xF4FB: 0x6194, //CJK UNIFIED IDEOGRAPH + 0xF4FC: 0x6284, //CJK UNIFIED IDEOGRAPH + 0xF4FD: 0x62DB, //CJK UNIFIED IDEOGRAPH + 0xF4FE: 0x68A2, //CJK UNIFIED IDEOGRAPH + 0xF5A1: 0x6912, //CJK UNIFIED IDEOGRAPH + 0xF5A2: 0x695A, //CJK UNIFIED IDEOGRAPH + 0xF5A3: 0x6A35, //CJK UNIFIED IDEOGRAPH + 0xF5A4: 0x7092, //CJK UNIFIED IDEOGRAPH + 0xF5A5: 0x7126, //CJK UNIFIED IDEOGRAPH + 0xF5A6: 0x785D, //CJK UNIFIED IDEOGRAPH + 0xF5A7: 0x7901, //CJK UNIFIED IDEOGRAPH + 0xF5A8: 0x790E, //CJK UNIFIED IDEOGRAPH + 0xF5A9: 0x79D2, //CJK UNIFIED IDEOGRAPH + 0xF5AA: 0x7A0D, //CJK UNIFIED IDEOGRAPH + 0xF5AB: 0x8096, //CJK UNIFIED IDEOGRAPH + 0xF5AC: 0x8278, //CJK UNIFIED IDEOGRAPH + 0xF5AD: 0x82D5, //CJK UNIFIED IDEOGRAPH + 0xF5AE: 0x8349, //CJK UNIFIED IDEOGRAPH + 0xF5AF: 0x8549, //CJK UNIFIED IDEOGRAPH + 0xF5B0: 0x8C82, //CJK UNIFIED IDEOGRAPH + 0xF5B1: 0x8D85, //CJK UNIFIED IDEOGRAPH + 0xF5B2: 0x9162, //CJK UNIFIED IDEOGRAPH + 0xF5B3: 0x918B, //CJK UNIFIED IDEOGRAPH + 0xF5B4: 0x91AE, //CJK UNIFIED IDEOGRAPH + 0xF5B5: 0x4FC3, //CJK UNIFIED IDEOGRAPH + 0xF5B6: 0x56D1, //CJK UNIFIED IDEOGRAPH + 0xF5B7: 0x71ED, //CJK UNIFIED IDEOGRAPH + 0xF5B8: 0x77D7, //CJK UNIFIED IDEOGRAPH + 0xF5B9: 0x8700, //CJK UNIFIED IDEOGRAPH + 0xF5BA: 0x89F8, //CJK UNIFIED IDEOGRAPH + 0xF5BB: 0x5BF8, //CJK UNIFIED IDEOGRAPH + 0xF5BC: 0x5FD6, //CJK UNIFIED IDEOGRAPH + 0xF5BD: 0x6751, //CJK UNIFIED IDEOGRAPH + 0xF5BE: 0x90A8, //CJK UNIFIED IDEOGRAPH + 0xF5BF: 0x53E2, //CJK UNIFIED IDEOGRAPH + 0xF5C0: 0x585A, //CJK UNIFIED IDEOGRAPH + 0xF5C1: 0x5BF5, //CJK UNIFIED IDEOGRAPH + 0xF5C2: 0x60A4, //CJK UNIFIED IDEOGRAPH + 0xF5C3: 0x6181, //CJK UNIFIED IDEOGRAPH + 0xF5C4: 0x6460, //CJK UNIFIED IDEOGRAPH + 0xF5C5: 0x7E3D, //CJK UNIFIED IDEOGRAPH + 0xF5C6: 0x8070, //CJK UNIFIED IDEOGRAPH + 0xF5C7: 0x8525, //CJK UNIFIED IDEOGRAPH + 0xF5C8: 0x9283, //CJK UNIFIED IDEOGRAPH + 0xF5C9: 0x64AE, //CJK UNIFIED IDEOGRAPH + 0xF5CA: 0x50AC, //CJK UNIFIED IDEOGRAPH + 0xF5CB: 0x5D14, //CJK UNIFIED IDEOGRAPH + 0xF5CC: 0x6700, //CJK UNIFIED IDEOGRAPH + 0xF5CD: 0x589C, //CJK UNIFIED IDEOGRAPH + 0xF5CE: 0x62BD, //CJK UNIFIED IDEOGRAPH + 0xF5CF: 0x63A8, //CJK UNIFIED IDEOGRAPH + 0xF5D0: 0x690E, //CJK UNIFIED IDEOGRAPH + 0xF5D1: 0x6978, //CJK UNIFIED IDEOGRAPH + 0xF5D2: 0x6A1E, //CJK UNIFIED IDEOGRAPH + 0xF5D3: 0x6E6B, //CJK UNIFIED IDEOGRAPH + 0xF5D4: 0x76BA, //CJK UNIFIED IDEOGRAPH + 0xF5D5: 0x79CB, //CJK UNIFIED IDEOGRAPH + 0xF5D6: 0x82BB, //CJK UNIFIED IDEOGRAPH + 0xF5D7: 0x8429, //CJK UNIFIED IDEOGRAPH + 0xF5D8: 0x8ACF, //CJK UNIFIED IDEOGRAPH + 0xF5D9: 0x8DA8, //CJK UNIFIED IDEOGRAPH + 0xF5DA: 0x8FFD, //CJK UNIFIED IDEOGRAPH + 0xF5DB: 0x9112, //CJK UNIFIED IDEOGRAPH + 0xF5DC: 0x914B, //CJK UNIFIED IDEOGRAPH + 0xF5DD: 0x919C, //CJK UNIFIED IDEOGRAPH + 0xF5DE: 0x9310, //CJK UNIFIED IDEOGRAPH + 0xF5DF: 0x9318, //CJK UNIFIED IDEOGRAPH + 0xF5E0: 0x939A, //CJK UNIFIED IDEOGRAPH + 0xF5E1: 0x96DB, //CJK UNIFIED IDEOGRAPH + 0xF5E2: 0x9A36, //CJK UNIFIED IDEOGRAPH + 0xF5E3: 0x9C0D, //CJK UNIFIED IDEOGRAPH + 0xF5E4: 0x4E11, //CJK UNIFIED IDEOGRAPH + 0xF5E5: 0x755C, //CJK UNIFIED IDEOGRAPH + 0xF5E6: 0x795D, //CJK UNIFIED IDEOGRAPH + 0xF5E7: 0x7AFA, //CJK UNIFIED IDEOGRAPH + 0xF5E8: 0x7B51, //CJK UNIFIED IDEOGRAPH + 0xF5E9: 0x7BC9, //CJK UNIFIED IDEOGRAPH + 0xF5EA: 0x7E2E, //CJK UNIFIED IDEOGRAPH + 0xF5EB: 0x84C4, //CJK UNIFIED IDEOGRAPH + 0xF5EC: 0x8E59, //CJK UNIFIED IDEOGRAPH + 0xF5ED: 0x8E74, //CJK UNIFIED IDEOGRAPH + 0xF5EE: 0x8EF8, //CJK UNIFIED IDEOGRAPH + 0xF5EF: 0x9010, //CJK UNIFIED IDEOGRAPH + 0xF5F0: 0x6625, //CJK UNIFIED IDEOGRAPH + 0xF5F1: 0x693F, //CJK UNIFIED IDEOGRAPH + 0xF5F2: 0x7443, //CJK UNIFIED IDEOGRAPH + 0xF5F3: 0x51FA, //CJK UNIFIED IDEOGRAPH + 0xF5F4: 0x672E, //CJK UNIFIED IDEOGRAPH + 0xF5F5: 0x9EDC, //CJK UNIFIED IDEOGRAPH + 0xF5F6: 0x5145, //CJK UNIFIED IDEOGRAPH + 0xF5F7: 0x5FE0, //CJK UNIFIED IDEOGRAPH + 0xF5F8: 0x6C96, //CJK UNIFIED IDEOGRAPH + 0xF5F9: 0x87F2, //CJK UNIFIED IDEOGRAPH + 0xF5FA: 0x885D, //CJK UNIFIED IDEOGRAPH + 0xF5FB: 0x8877, //CJK UNIFIED IDEOGRAPH + 0xF5FC: 0x60B4, //CJK UNIFIED IDEOGRAPH + 0xF5FD: 0x81B5, //CJK UNIFIED IDEOGRAPH + 0xF5FE: 0x8403, //CJK UNIFIED IDEOGRAPH + 0xF6A1: 0x8D05, //CJK UNIFIED IDEOGRAPH + 0xF6A2: 0x53D6, //CJK UNIFIED IDEOGRAPH + 0xF6A3: 0x5439, //CJK UNIFIED IDEOGRAPH + 0xF6A4: 0x5634, //CJK UNIFIED IDEOGRAPH + 0xF6A5: 0x5A36, //CJK UNIFIED IDEOGRAPH + 0xF6A6: 0x5C31, //CJK UNIFIED IDEOGRAPH + 0xF6A7: 0x708A, //CJK UNIFIED IDEOGRAPH + 0xF6A8: 0x7FE0, //CJK UNIFIED IDEOGRAPH + 0xF6A9: 0x805A, //CJK UNIFIED IDEOGRAPH + 0xF6AA: 0x8106, //CJK UNIFIED IDEOGRAPH + 0xF6AB: 0x81ED, //CJK UNIFIED IDEOGRAPH + 0xF6AC: 0x8DA3, //CJK UNIFIED IDEOGRAPH + 0xF6AD: 0x9189, //CJK UNIFIED IDEOGRAPH + 0xF6AE: 0x9A5F, //CJK UNIFIED IDEOGRAPH + 0xF6AF: 0x9DF2, //CJK UNIFIED IDEOGRAPH + 0xF6B0: 0x5074, //CJK UNIFIED IDEOGRAPH + 0xF6B1: 0x4EC4, //CJK UNIFIED IDEOGRAPH + 0xF6B2: 0x53A0, //CJK UNIFIED IDEOGRAPH + 0xF6B3: 0x60FB, //CJK UNIFIED IDEOGRAPH + 0xF6B4: 0x6E2C, //CJK UNIFIED IDEOGRAPH + 0xF6B5: 0x5C64, //CJK UNIFIED IDEOGRAPH + 0xF6B6: 0x4F88, //CJK UNIFIED IDEOGRAPH + 0xF6B7: 0x5024, //CJK UNIFIED IDEOGRAPH + 0xF6B8: 0x55E4, //CJK UNIFIED IDEOGRAPH + 0xF6B9: 0x5CD9, //CJK UNIFIED IDEOGRAPH + 0xF6BA: 0x5E5F, //CJK UNIFIED IDEOGRAPH + 0xF6BB: 0x6065, //CJK UNIFIED IDEOGRAPH + 0xF6BC: 0x6894, //CJK UNIFIED IDEOGRAPH + 0xF6BD: 0x6CBB, //CJK UNIFIED IDEOGRAPH + 0xF6BE: 0x6DC4, //CJK UNIFIED IDEOGRAPH + 0xF6BF: 0x71BE, //CJK UNIFIED IDEOGRAPH + 0xF6C0: 0x75D4, //CJK UNIFIED IDEOGRAPH + 0xF6C1: 0x75F4, //CJK UNIFIED IDEOGRAPH + 0xF6C2: 0x7661, //CJK UNIFIED IDEOGRAPH + 0xF6C3: 0x7A1A, //CJK UNIFIED IDEOGRAPH + 0xF6C4: 0x7A49, //CJK UNIFIED IDEOGRAPH + 0xF6C5: 0x7DC7, //CJK UNIFIED IDEOGRAPH + 0xF6C6: 0x7DFB, //CJK UNIFIED IDEOGRAPH + 0xF6C7: 0x7F6E, //CJK UNIFIED IDEOGRAPH + 0xF6C8: 0x81F4, //CJK UNIFIED IDEOGRAPH + 0xF6C9: 0x86A9, //CJK UNIFIED IDEOGRAPH + 0xF6CA: 0x8F1C, //CJK UNIFIED IDEOGRAPH + 0xF6CB: 0x96C9, //CJK UNIFIED IDEOGRAPH + 0xF6CC: 0x99B3, //CJK UNIFIED IDEOGRAPH + 0xF6CD: 0x9F52, //CJK UNIFIED IDEOGRAPH + 0xF6CE: 0x5247, //CJK UNIFIED IDEOGRAPH + 0xF6CF: 0x52C5, //CJK UNIFIED IDEOGRAPH + 0xF6D0: 0x98ED, //CJK UNIFIED IDEOGRAPH + 0xF6D1: 0x89AA, //CJK UNIFIED IDEOGRAPH + 0xF6D2: 0x4E03, //CJK UNIFIED IDEOGRAPH + 0xF6D3: 0x67D2, //CJK UNIFIED IDEOGRAPH + 0xF6D4: 0x6F06, //CJK UNIFIED IDEOGRAPH + 0xF6D5: 0x4FB5, //CJK UNIFIED IDEOGRAPH + 0xF6D6: 0x5BE2, //CJK UNIFIED IDEOGRAPH + 0xF6D7: 0x6795, //CJK UNIFIED IDEOGRAPH + 0xF6D8: 0x6C88, //CJK UNIFIED IDEOGRAPH + 0xF6D9: 0x6D78, //CJK UNIFIED IDEOGRAPH + 0xF6DA: 0x741B, //CJK UNIFIED IDEOGRAPH + 0xF6DB: 0x7827, //CJK UNIFIED IDEOGRAPH + 0xF6DC: 0x91DD, //CJK UNIFIED IDEOGRAPH + 0xF6DD: 0x937C, //CJK UNIFIED IDEOGRAPH + 0xF6DE: 0x87C4, //CJK UNIFIED IDEOGRAPH + 0xF6DF: 0x79E4, //CJK UNIFIED IDEOGRAPH + 0xF6E0: 0x7A31, //CJK UNIFIED IDEOGRAPH + 0xF6E1: 0x5FEB, //CJK UNIFIED IDEOGRAPH + 0xF6E2: 0x4ED6, //CJK UNIFIED IDEOGRAPH + 0xF6E3: 0x54A4, //CJK UNIFIED IDEOGRAPH + 0xF6E4: 0x553E, //CJK UNIFIED IDEOGRAPH + 0xF6E5: 0x58AE, //CJK UNIFIED IDEOGRAPH + 0xF6E6: 0x59A5, //CJK UNIFIED IDEOGRAPH + 0xF6E7: 0x60F0, //CJK UNIFIED IDEOGRAPH + 0xF6E8: 0x6253, //CJK UNIFIED IDEOGRAPH + 0xF6E9: 0x62D6, //CJK UNIFIED IDEOGRAPH + 0xF6EA: 0x6736, //CJK UNIFIED IDEOGRAPH + 0xF6EB: 0x6955, //CJK UNIFIED IDEOGRAPH + 0xF6EC: 0x8235, //CJK UNIFIED IDEOGRAPH + 0xF6ED: 0x9640, //CJK UNIFIED IDEOGRAPH + 0xF6EE: 0x99B1, //CJK UNIFIED IDEOGRAPH + 0xF6EF: 0x99DD, //CJK UNIFIED IDEOGRAPH + 0xF6F0: 0x502C, //CJK UNIFIED IDEOGRAPH + 0xF6F1: 0x5353, //CJK UNIFIED IDEOGRAPH + 0xF6F2: 0x5544, //CJK UNIFIED IDEOGRAPH + 0xF6F3: 0x577C, //CJK UNIFIED IDEOGRAPH + 0xF6F4: 0xFA01, //CJK COMPATIBILITY IDEOGRAPH + 0xF6F5: 0x6258, //CJK UNIFIED IDEOGRAPH + 0xF6F6: 0xFA02, //CJK COMPATIBILITY IDEOGRAPH + 0xF6F7: 0x64E2, //CJK UNIFIED IDEOGRAPH + 0xF6F8: 0x666B, //CJK UNIFIED IDEOGRAPH + 0xF6F9: 0x67DD, //CJK UNIFIED IDEOGRAPH + 0xF6FA: 0x6FC1, //CJK UNIFIED IDEOGRAPH + 0xF6FB: 0x6FEF, //CJK UNIFIED IDEOGRAPH + 0xF6FC: 0x7422, //CJK UNIFIED IDEOGRAPH + 0xF6FD: 0x7438, //CJK UNIFIED IDEOGRAPH + 0xF6FE: 0x8A17, //CJK UNIFIED IDEOGRAPH + 0xF7A1: 0x9438, //CJK UNIFIED IDEOGRAPH + 0xF7A2: 0x5451, //CJK UNIFIED IDEOGRAPH + 0xF7A3: 0x5606, //CJK UNIFIED IDEOGRAPH + 0xF7A4: 0x5766, //CJK UNIFIED IDEOGRAPH + 0xF7A5: 0x5F48, //CJK UNIFIED IDEOGRAPH + 0xF7A6: 0x619A, //CJK UNIFIED IDEOGRAPH + 0xF7A7: 0x6B4E, //CJK UNIFIED IDEOGRAPH + 0xF7A8: 0x7058, //CJK UNIFIED IDEOGRAPH + 0xF7A9: 0x70AD, //CJK UNIFIED IDEOGRAPH + 0xF7AA: 0x7DBB, //CJK UNIFIED IDEOGRAPH + 0xF7AB: 0x8A95, //CJK UNIFIED IDEOGRAPH + 0xF7AC: 0x596A, //CJK UNIFIED IDEOGRAPH + 0xF7AD: 0x812B, //CJK UNIFIED IDEOGRAPH + 0xF7AE: 0x63A2, //CJK UNIFIED IDEOGRAPH + 0xF7AF: 0x7708, //CJK UNIFIED IDEOGRAPH + 0xF7B0: 0x803D, //CJK UNIFIED IDEOGRAPH + 0xF7B1: 0x8CAA, //CJK UNIFIED IDEOGRAPH + 0xF7B2: 0x5854, //CJK UNIFIED IDEOGRAPH + 0xF7B3: 0x642D, //CJK UNIFIED IDEOGRAPH + 0xF7B4: 0x69BB, //CJK UNIFIED IDEOGRAPH + 0xF7B5: 0x5B95, //CJK UNIFIED IDEOGRAPH + 0xF7B6: 0x5E11, //CJK UNIFIED IDEOGRAPH + 0xF7B7: 0x6E6F, //CJK UNIFIED IDEOGRAPH + 0xF7B8: 0xFA03, //CJK COMPATIBILITY IDEOGRAPH + 0xF7B9: 0x8569, //CJK UNIFIED IDEOGRAPH + 0xF7BA: 0x514C, //CJK UNIFIED IDEOGRAPH + 0xF7BB: 0x53F0, //CJK UNIFIED IDEOGRAPH + 0xF7BC: 0x592A, //CJK UNIFIED IDEOGRAPH + 0xF7BD: 0x6020, //CJK UNIFIED IDEOGRAPH + 0xF7BE: 0x614B, //CJK UNIFIED IDEOGRAPH + 0xF7BF: 0x6B86, //CJK UNIFIED IDEOGRAPH + 0xF7C0: 0x6C70, //CJK UNIFIED IDEOGRAPH + 0xF7C1: 0x6CF0, //CJK UNIFIED IDEOGRAPH + 0xF7C2: 0x7B1E, //CJK UNIFIED IDEOGRAPH + 0xF7C3: 0x80CE, //CJK UNIFIED IDEOGRAPH + 0xF7C4: 0x82D4, //CJK UNIFIED IDEOGRAPH + 0xF7C5: 0x8DC6, //CJK UNIFIED IDEOGRAPH + 0xF7C6: 0x90B0, //CJK UNIFIED IDEOGRAPH + 0xF7C7: 0x98B1, //CJK UNIFIED IDEOGRAPH + 0xF7C8: 0xFA04, //CJK COMPATIBILITY IDEOGRAPH + 0xF7C9: 0x64C7, //CJK UNIFIED IDEOGRAPH + 0xF7CA: 0x6FA4, //CJK UNIFIED IDEOGRAPH + 0xF7CB: 0x6491, //CJK UNIFIED IDEOGRAPH + 0xF7CC: 0x6504, //CJK UNIFIED IDEOGRAPH + 0xF7CD: 0x514E, //CJK UNIFIED IDEOGRAPH + 0xF7CE: 0x5410, //CJK UNIFIED IDEOGRAPH + 0xF7CF: 0x571F, //CJK UNIFIED IDEOGRAPH + 0xF7D0: 0x8A0E, //CJK UNIFIED IDEOGRAPH + 0xF7D1: 0x615F, //CJK UNIFIED IDEOGRAPH + 0xF7D2: 0x6876, //CJK UNIFIED IDEOGRAPH + 0xF7D3: 0xFA05, //CJK COMPATIBILITY IDEOGRAPH + 0xF7D4: 0x75DB, //CJK UNIFIED IDEOGRAPH + 0xF7D5: 0x7B52, //CJK UNIFIED IDEOGRAPH + 0xF7D6: 0x7D71, //CJK UNIFIED IDEOGRAPH + 0xF7D7: 0x901A, //CJK UNIFIED IDEOGRAPH + 0xF7D8: 0x5806, //CJK UNIFIED IDEOGRAPH + 0xF7D9: 0x69CC, //CJK UNIFIED IDEOGRAPH + 0xF7DA: 0x817F, //CJK UNIFIED IDEOGRAPH + 0xF7DB: 0x892A, //CJK UNIFIED IDEOGRAPH + 0xF7DC: 0x9000, //CJK UNIFIED IDEOGRAPH + 0xF7DD: 0x9839, //CJK UNIFIED IDEOGRAPH + 0xF7DE: 0x5078, //CJK UNIFIED IDEOGRAPH + 0xF7DF: 0x5957, //CJK UNIFIED IDEOGRAPH + 0xF7E0: 0x59AC, //CJK UNIFIED IDEOGRAPH + 0xF7E1: 0x6295, //CJK UNIFIED IDEOGRAPH + 0xF7E2: 0x900F, //CJK UNIFIED IDEOGRAPH + 0xF7E3: 0x9B2A, //CJK UNIFIED IDEOGRAPH + 0xF7E4: 0x615D, //CJK UNIFIED IDEOGRAPH + 0xF7E5: 0x7279, //CJK UNIFIED IDEOGRAPH + 0xF7E6: 0x95D6, //CJK UNIFIED IDEOGRAPH + 0xF7E7: 0x5761, //CJK UNIFIED IDEOGRAPH + 0xF7E8: 0x5A46, //CJK UNIFIED IDEOGRAPH + 0xF7E9: 0x5DF4, //CJK UNIFIED IDEOGRAPH + 0xF7EA: 0x628A, //CJK UNIFIED IDEOGRAPH + 0xF7EB: 0x64AD, //CJK UNIFIED IDEOGRAPH + 0xF7EC: 0x64FA, //CJK UNIFIED IDEOGRAPH + 0xF7ED: 0x6777, //CJK UNIFIED IDEOGRAPH + 0xF7EE: 0x6CE2, //CJK UNIFIED IDEOGRAPH + 0xF7EF: 0x6D3E, //CJK UNIFIED IDEOGRAPH + 0xF7F0: 0x722C, //CJK UNIFIED IDEOGRAPH + 0xF7F1: 0x7436, //CJK UNIFIED IDEOGRAPH + 0xF7F2: 0x7834, //CJK UNIFIED IDEOGRAPH + 0xF7F3: 0x7F77, //CJK UNIFIED IDEOGRAPH + 0xF7F4: 0x82AD, //CJK UNIFIED IDEOGRAPH + 0xF7F5: 0x8DDB, //CJK UNIFIED IDEOGRAPH + 0xF7F6: 0x9817, //CJK UNIFIED IDEOGRAPH + 0xF7F7: 0x5224, //CJK UNIFIED IDEOGRAPH + 0xF7F8: 0x5742, //CJK UNIFIED IDEOGRAPH + 0xF7F9: 0x677F, //CJK UNIFIED IDEOGRAPH + 0xF7FA: 0x7248, //CJK UNIFIED IDEOGRAPH + 0xF7FB: 0x74E3, //CJK UNIFIED IDEOGRAPH + 0xF7FC: 0x8CA9, //CJK UNIFIED IDEOGRAPH + 0xF7FD: 0x8FA6, //CJK UNIFIED IDEOGRAPH + 0xF7FE: 0x9211, //CJK UNIFIED IDEOGRAPH + 0xF8A1: 0x962A, //CJK UNIFIED IDEOGRAPH + 0xF8A2: 0x516B, //CJK UNIFIED IDEOGRAPH + 0xF8A3: 0x53ED, //CJK UNIFIED IDEOGRAPH + 0xF8A4: 0x634C, //CJK UNIFIED IDEOGRAPH + 0xF8A5: 0x4F69, //CJK UNIFIED IDEOGRAPH + 0xF8A6: 0x5504, //CJK UNIFIED IDEOGRAPH + 0xF8A7: 0x6096, //CJK UNIFIED IDEOGRAPH + 0xF8A8: 0x6557, //CJK UNIFIED IDEOGRAPH + 0xF8A9: 0x6C9B, //CJK UNIFIED IDEOGRAPH + 0xF8AA: 0x6D7F, //CJK UNIFIED IDEOGRAPH + 0xF8AB: 0x724C, //CJK UNIFIED IDEOGRAPH + 0xF8AC: 0x72FD, //CJK UNIFIED IDEOGRAPH + 0xF8AD: 0x7A17, //CJK UNIFIED IDEOGRAPH + 0xF8AE: 0x8987, //CJK UNIFIED IDEOGRAPH + 0xF8AF: 0x8C9D, //CJK UNIFIED IDEOGRAPH + 0xF8B0: 0x5F6D, //CJK UNIFIED IDEOGRAPH + 0xF8B1: 0x6F8E, //CJK UNIFIED IDEOGRAPH + 0xF8B2: 0x70F9, //CJK UNIFIED IDEOGRAPH + 0xF8B3: 0x81A8, //CJK UNIFIED IDEOGRAPH + 0xF8B4: 0x610E, //CJK UNIFIED IDEOGRAPH + 0xF8B5: 0x4FBF, //CJK UNIFIED IDEOGRAPH + 0xF8B6: 0x504F, //CJK UNIFIED IDEOGRAPH + 0xF8B7: 0x6241, //CJK UNIFIED IDEOGRAPH + 0xF8B8: 0x7247, //CJK UNIFIED IDEOGRAPH + 0xF8B9: 0x7BC7, //CJK UNIFIED IDEOGRAPH + 0xF8BA: 0x7DE8, //CJK UNIFIED IDEOGRAPH + 0xF8BB: 0x7FE9, //CJK UNIFIED IDEOGRAPH + 0xF8BC: 0x904D, //CJK UNIFIED IDEOGRAPH + 0xF8BD: 0x97AD, //CJK UNIFIED IDEOGRAPH + 0xF8BE: 0x9A19, //CJK UNIFIED IDEOGRAPH + 0xF8BF: 0x8CB6, //CJK UNIFIED IDEOGRAPH + 0xF8C0: 0x576A, //CJK UNIFIED IDEOGRAPH + 0xF8C1: 0x5E73, //CJK UNIFIED IDEOGRAPH + 0xF8C2: 0x67B0, //CJK UNIFIED IDEOGRAPH + 0xF8C3: 0x840D, //CJK UNIFIED IDEOGRAPH + 0xF8C4: 0x8A55, //CJK UNIFIED IDEOGRAPH + 0xF8C5: 0x5420, //CJK UNIFIED IDEOGRAPH + 0xF8C6: 0x5B16, //CJK UNIFIED IDEOGRAPH + 0xF8C7: 0x5E63, //CJK UNIFIED IDEOGRAPH + 0xF8C8: 0x5EE2, //CJK UNIFIED IDEOGRAPH + 0xF8C9: 0x5F0A, //CJK UNIFIED IDEOGRAPH + 0xF8CA: 0x6583, //CJK UNIFIED IDEOGRAPH + 0xF8CB: 0x80BA, //CJK UNIFIED IDEOGRAPH + 0xF8CC: 0x853D, //CJK UNIFIED IDEOGRAPH + 0xF8CD: 0x9589, //CJK UNIFIED IDEOGRAPH + 0xF8CE: 0x965B, //CJK UNIFIED IDEOGRAPH + 0xF8CF: 0x4F48, //CJK UNIFIED IDEOGRAPH + 0xF8D0: 0x5305, //CJK UNIFIED IDEOGRAPH + 0xF8D1: 0x530D, //CJK UNIFIED IDEOGRAPH + 0xF8D2: 0x530F, //CJK UNIFIED IDEOGRAPH + 0xF8D3: 0x5486, //CJK UNIFIED IDEOGRAPH + 0xF8D4: 0x54FA, //CJK UNIFIED IDEOGRAPH + 0xF8D5: 0x5703, //CJK UNIFIED IDEOGRAPH + 0xF8D6: 0x5E03, //CJK UNIFIED IDEOGRAPH + 0xF8D7: 0x6016, //CJK UNIFIED IDEOGRAPH + 0xF8D8: 0x629B, //CJK UNIFIED IDEOGRAPH + 0xF8D9: 0x62B1, //CJK UNIFIED IDEOGRAPH + 0xF8DA: 0x6355, //CJK UNIFIED IDEOGRAPH + 0xF8DB: 0xFA06, //CJK COMPATIBILITY IDEOGRAPH + 0xF8DC: 0x6CE1, //CJK UNIFIED IDEOGRAPH + 0xF8DD: 0x6D66, //CJK UNIFIED IDEOGRAPH + 0xF8DE: 0x75B1, //CJK UNIFIED IDEOGRAPH + 0xF8DF: 0x7832, //CJK UNIFIED IDEOGRAPH + 0xF8E0: 0x80DE, //CJK UNIFIED IDEOGRAPH + 0xF8E1: 0x812F, //CJK UNIFIED IDEOGRAPH + 0xF8E2: 0x82DE, //CJK UNIFIED IDEOGRAPH + 0xF8E3: 0x8461, //CJK UNIFIED IDEOGRAPH + 0xF8E4: 0x84B2, //CJK UNIFIED IDEOGRAPH + 0xF8E5: 0x888D, //CJK UNIFIED IDEOGRAPH + 0xF8E6: 0x8912, //CJK UNIFIED IDEOGRAPH + 0xF8E7: 0x900B, //CJK UNIFIED IDEOGRAPH + 0xF8E8: 0x92EA, //CJK UNIFIED IDEOGRAPH + 0xF8E9: 0x98FD, //CJK UNIFIED IDEOGRAPH + 0xF8EA: 0x9B91, //CJK UNIFIED IDEOGRAPH + 0xF8EB: 0x5E45, //CJK UNIFIED IDEOGRAPH + 0xF8EC: 0x66B4, //CJK UNIFIED IDEOGRAPH + 0xF8ED: 0x66DD, //CJK UNIFIED IDEOGRAPH + 0xF8EE: 0x7011, //CJK UNIFIED IDEOGRAPH + 0xF8EF: 0x7206, //CJK UNIFIED IDEOGRAPH + 0xF8F0: 0xFA07, //CJK COMPATIBILITY IDEOGRAPH + 0xF8F1: 0x4FF5, //CJK UNIFIED IDEOGRAPH + 0xF8F2: 0x527D, //CJK UNIFIED IDEOGRAPH + 0xF8F3: 0x5F6A, //CJK UNIFIED IDEOGRAPH + 0xF8F4: 0x6153, //CJK UNIFIED IDEOGRAPH + 0xF8F5: 0x6753, //CJK UNIFIED IDEOGRAPH + 0xF8F6: 0x6A19, //CJK UNIFIED IDEOGRAPH + 0xF8F7: 0x6F02, //CJK UNIFIED IDEOGRAPH + 0xF8F8: 0x74E2, //CJK UNIFIED IDEOGRAPH + 0xF8F9: 0x7968, //CJK UNIFIED IDEOGRAPH + 0xF8FA: 0x8868, //CJK UNIFIED IDEOGRAPH + 0xF8FB: 0x8C79, //CJK UNIFIED IDEOGRAPH + 0xF8FC: 0x98C7, //CJK UNIFIED IDEOGRAPH + 0xF8FD: 0x98C4, //CJK UNIFIED IDEOGRAPH + 0xF8FE: 0x9A43, //CJK UNIFIED IDEOGRAPH + 0xF9A1: 0x54C1, //CJK UNIFIED IDEOGRAPH + 0xF9A2: 0x7A1F, //CJK UNIFIED IDEOGRAPH + 0xF9A3: 0x6953, //CJK UNIFIED IDEOGRAPH + 0xF9A4: 0x8AF7, //CJK UNIFIED IDEOGRAPH + 0xF9A5: 0x8C4A, //CJK UNIFIED IDEOGRAPH + 0xF9A6: 0x98A8, //CJK UNIFIED IDEOGRAPH + 0xF9A7: 0x99AE, //CJK UNIFIED IDEOGRAPH + 0xF9A8: 0x5F7C, //CJK UNIFIED IDEOGRAPH + 0xF9A9: 0x62AB, //CJK UNIFIED IDEOGRAPH + 0xF9AA: 0x75B2, //CJK UNIFIED IDEOGRAPH + 0xF9AB: 0x76AE, //CJK UNIFIED IDEOGRAPH + 0xF9AC: 0x88AB, //CJK UNIFIED IDEOGRAPH + 0xF9AD: 0x907F, //CJK UNIFIED IDEOGRAPH + 0xF9AE: 0x9642, //CJK UNIFIED IDEOGRAPH + 0xF9AF: 0x5339, //CJK UNIFIED IDEOGRAPH + 0xF9B0: 0x5F3C, //CJK UNIFIED IDEOGRAPH + 0xF9B1: 0x5FC5, //CJK UNIFIED IDEOGRAPH + 0xF9B2: 0x6CCC, //CJK UNIFIED IDEOGRAPH + 0xF9B3: 0x73CC, //CJK UNIFIED IDEOGRAPH + 0xF9B4: 0x7562, //CJK UNIFIED IDEOGRAPH + 0xF9B5: 0x758B, //CJK UNIFIED IDEOGRAPH + 0xF9B6: 0x7B46, //CJK UNIFIED IDEOGRAPH + 0xF9B7: 0x82FE, //CJK UNIFIED IDEOGRAPH + 0xF9B8: 0x999D, //CJK UNIFIED IDEOGRAPH + 0xF9B9: 0x4E4F, //CJK UNIFIED IDEOGRAPH + 0xF9BA: 0x903C, //CJK UNIFIED IDEOGRAPH + 0xF9BB: 0x4E0B, //CJK UNIFIED IDEOGRAPH + 0xF9BC: 0x4F55, //CJK UNIFIED IDEOGRAPH + 0xF9BD: 0x53A6, //CJK UNIFIED IDEOGRAPH + 0xF9BE: 0x590F, //CJK UNIFIED IDEOGRAPH + 0xF9BF: 0x5EC8, //CJK UNIFIED IDEOGRAPH + 0xF9C0: 0x6630, //CJK UNIFIED IDEOGRAPH + 0xF9C1: 0x6CB3, //CJK UNIFIED IDEOGRAPH + 0xF9C2: 0x7455, //CJK UNIFIED IDEOGRAPH + 0xF9C3: 0x8377, //CJK UNIFIED IDEOGRAPH + 0xF9C4: 0x8766, //CJK UNIFIED IDEOGRAPH + 0xF9C5: 0x8CC0, //CJK UNIFIED IDEOGRAPH + 0xF9C6: 0x9050, //CJK UNIFIED IDEOGRAPH + 0xF9C7: 0x971E, //CJK UNIFIED IDEOGRAPH + 0xF9C8: 0x9C15, //CJK UNIFIED IDEOGRAPH + 0xF9C9: 0x58D1, //CJK UNIFIED IDEOGRAPH + 0xF9CA: 0x5B78, //CJK UNIFIED IDEOGRAPH + 0xF9CB: 0x8650, //CJK UNIFIED IDEOGRAPH + 0xF9CC: 0x8B14, //CJK UNIFIED IDEOGRAPH + 0xF9CD: 0x9DB4, //CJK UNIFIED IDEOGRAPH + 0xF9CE: 0x5BD2, //CJK UNIFIED IDEOGRAPH + 0xF9CF: 0x6068, //CJK UNIFIED IDEOGRAPH + 0xF9D0: 0x608D, //CJK UNIFIED IDEOGRAPH + 0xF9D1: 0x65F1, //CJK UNIFIED IDEOGRAPH + 0xF9D2: 0x6C57, //CJK UNIFIED IDEOGRAPH + 0xF9D3: 0x6F22, //CJK UNIFIED IDEOGRAPH + 0xF9D4: 0x6FA3, //CJK UNIFIED IDEOGRAPH + 0xF9D5: 0x701A, //CJK UNIFIED IDEOGRAPH + 0xF9D6: 0x7F55, //CJK UNIFIED IDEOGRAPH + 0xF9D7: 0x7FF0, //CJK UNIFIED IDEOGRAPH + 0xF9D8: 0x9591, //CJK UNIFIED IDEOGRAPH + 0xF9D9: 0x9592, //CJK UNIFIED IDEOGRAPH + 0xF9DA: 0x9650, //CJK UNIFIED IDEOGRAPH + 0xF9DB: 0x97D3, //CJK UNIFIED IDEOGRAPH + 0xF9DC: 0x5272, //CJK UNIFIED IDEOGRAPH + 0xF9DD: 0x8F44, //CJK UNIFIED IDEOGRAPH + 0xF9DE: 0x51FD, //CJK UNIFIED IDEOGRAPH + 0xF9DF: 0x542B, //CJK UNIFIED IDEOGRAPH + 0xF9E0: 0x54B8, //CJK UNIFIED IDEOGRAPH + 0xF9E1: 0x5563, //CJK UNIFIED IDEOGRAPH + 0xF9E2: 0x558A, //CJK UNIFIED IDEOGRAPH + 0xF9E3: 0x6ABB, //CJK UNIFIED IDEOGRAPH + 0xF9E4: 0x6DB5, //CJK UNIFIED IDEOGRAPH + 0xF9E5: 0x7DD8, //CJK UNIFIED IDEOGRAPH + 0xF9E6: 0x8266, //CJK UNIFIED IDEOGRAPH + 0xF9E7: 0x929C, //CJK UNIFIED IDEOGRAPH + 0xF9E8: 0x9677, //CJK UNIFIED IDEOGRAPH + 0xF9E9: 0x9E79, //CJK UNIFIED IDEOGRAPH + 0xF9EA: 0x5408, //CJK UNIFIED IDEOGRAPH + 0xF9EB: 0x54C8, //CJK UNIFIED IDEOGRAPH + 0xF9EC: 0x76D2, //CJK UNIFIED IDEOGRAPH + 0xF9ED: 0x86E4, //CJK UNIFIED IDEOGRAPH + 0xF9EE: 0x95A4, //CJK UNIFIED IDEOGRAPH + 0xF9EF: 0x95D4, //CJK UNIFIED IDEOGRAPH + 0xF9F0: 0x965C, //CJK UNIFIED IDEOGRAPH + 0xF9F1: 0x4EA2, //CJK UNIFIED IDEOGRAPH + 0xF9F2: 0x4F09, //CJK UNIFIED IDEOGRAPH + 0xF9F3: 0x59EE, //CJK UNIFIED IDEOGRAPH + 0xF9F4: 0x5AE6, //CJK UNIFIED IDEOGRAPH + 0xF9F5: 0x5DF7, //CJK UNIFIED IDEOGRAPH + 0xF9F6: 0x6052, //CJK UNIFIED IDEOGRAPH + 0xF9F7: 0x6297, //CJK UNIFIED IDEOGRAPH + 0xF9F8: 0x676D, //CJK UNIFIED IDEOGRAPH + 0xF9F9: 0x6841, //CJK UNIFIED IDEOGRAPH + 0xF9FA: 0x6C86, //CJK UNIFIED IDEOGRAPH + 0xF9FB: 0x6E2F, //CJK UNIFIED IDEOGRAPH + 0xF9FC: 0x7F38, //CJK UNIFIED IDEOGRAPH + 0xF9FD: 0x809B, //CJK UNIFIED IDEOGRAPH + 0xF9FE: 0x822A, //CJK UNIFIED IDEOGRAPH + 0xFAA1: 0xFA08, //CJK COMPATIBILITY IDEOGRAPH + 0xFAA2: 0xFA09, //CJK COMPATIBILITY IDEOGRAPH + 0xFAA3: 0x9805, //CJK UNIFIED IDEOGRAPH + 0xFAA4: 0x4EA5, //CJK UNIFIED IDEOGRAPH + 0xFAA5: 0x5055, //CJK UNIFIED IDEOGRAPH + 0xFAA6: 0x54B3, //CJK UNIFIED IDEOGRAPH + 0xFAA7: 0x5793, //CJK UNIFIED IDEOGRAPH + 0xFAA8: 0x595A, //CJK UNIFIED IDEOGRAPH + 0xFAA9: 0x5B69, //CJK UNIFIED IDEOGRAPH + 0xFAAA: 0x5BB3, //CJK UNIFIED IDEOGRAPH + 0xFAAB: 0x61C8, //CJK UNIFIED IDEOGRAPH + 0xFAAC: 0x6977, //CJK UNIFIED IDEOGRAPH + 0xFAAD: 0x6D77, //CJK UNIFIED IDEOGRAPH + 0xFAAE: 0x7023, //CJK UNIFIED IDEOGRAPH + 0xFAAF: 0x87F9, //CJK UNIFIED IDEOGRAPH + 0xFAB0: 0x89E3, //CJK UNIFIED IDEOGRAPH + 0xFAB1: 0x8A72, //CJK UNIFIED IDEOGRAPH + 0xFAB2: 0x8AE7, //CJK UNIFIED IDEOGRAPH + 0xFAB3: 0x9082, //CJK UNIFIED IDEOGRAPH + 0xFAB4: 0x99ED, //CJK UNIFIED IDEOGRAPH + 0xFAB5: 0x9AB8, //CJK UNIFIED IDEOGRAPH + 0xFAB6: 0x52BE, //CJK UNIFIED IDEOGRAPH + 0xFAB7: 0x6838, //CJK UNIFIED IDEOGRAPH + 0xFAB8: 0x5016, //CJK UNIFIED IDEOGRAPH + 0xFAB9: 0x5E78, //CJK UNIFIED IDEOGRAPH + 0xFABA: 0x674F, //CJK UNIFIED IDEOGRAPH + 0xFABB: 0x8347, //CJK UNIFIED IDEOGRAPH + 0xFABC: 0x884C, //CJK UNIFIED IDEOGRAPH + 0xFABD: 0x4EAB, //CJK UNIFIED IDEOGRAPH + 0xFABE: 0x5411, //CJK UNIFIED IDEOGRAPH + 0xFABF: 0x56AE, //CJK UNIFIED IDEOGRAPH + 0xFAC0: 0x73E6, //CJK UNIFIED IDEOGRAPH + 0xFAC1: 0x9115, //CJK UNIFIED IDEOGRAPH + 0xFAC2: 0x97FF, //CJK UNIFIED IDEOGRAPH + 0xFAC3: 0x9909, //CJK UNIFIED IDEOGRAPH + 0xFAC4: 0x9957, //CJK UNIFIED IDEOGRAPH + 0xFAC5: 0x9999, //CJK UNIFIED IDEOGRAPH + 0xFAC6: 0x5653, //CJK UNIFIED IDEOGRAPH + 0xFAC7: 0x589F, //CJK UNIFIED IDEOGRAPH + 0xFAC8: 0x865B, //CJK UNIFIED IDEOGRAPH + 0xFAC9: 0x8A31, //CJK UNIFIED IDEOGRAPH + 0xFACA: 0x61B2, //CJK UNIFIED IDEOGRAPH + 0xFACB: 0x6AF6, //CJK UNIFIED IDEOGRAPH + 0xFACC: 0x737B, //CJK UNIFIED IDEOGRAPH + 0xFACD: 0x8ED2, //CJK UNIFIED IDEOGRAPH + 0xFACE: 0x6B47, //CJK UNIFIED IDEOGRAPH + 0xFACF: 0x96AA, //CJK UNIFIED IDEOGRAPH + 0xFAD0: 0x9A57, //CJK UNIFIED IDEOGRAPH + 0xFAD1: 0x5955, //CJK UNIFIED IDEOGRAPH + 0xFAD2: 0x7200, //CJK UNIFIED IDEOGRAPH + 0xFAD3: 0x8D6B, //CJK UNIFIED IDEOGRAPH + 0xFAD4: 0x9769, //CJK UNIFIED IDEOGRAPH + 0xFAD5: 0x4FD4, //CJK UNIFIED IDEOGRAPH + 0xFAD6: 0x5CF4, //CJK UNIFIED IDEOGRAPH + 0xFAD7: 0x5F26, //CJK UNIFIED IDEOGRAPH + 0xFAD8: 0x61F8, //CJK UNIFIED IDEOGRAPH + 0xFAD9: 0x665B, //CJK UNIFIED IDEOGRAPH + 0xFADA: 0x6CEB, //CJK UNIFIED IDEOGRAPH + 0xFADB: 0x70AB, //CJK UNIFIED IDEOGRAPH + 0xFADC: 0x7384, //CJK UNIFIED IDEOGRAPH + 0xFADD: 0x73B9, //CJK UNIFIED IDEOGRAPH + 0xFADE: 0x73FE, //CJK UNIFIED IDEOGRAPH + 0xFADF: 0x7729, //CJK UNIFIED IDEOGRAPH + 0xFAE0: 0x774D, //CJK UNIFIED IDEOGRAPH + 0xFAE1: 0x7D43, //CJK UNIFIED IDEOGRAPH + 0xFAE2: 0x7D62, //CJK UNIFIED IDEOGRAPH + 0xFAE3: 0x7E23, //CJK UNIFIED IDEOGRAPH + 0xFAE4: 0x8237, //CJK UNIFIED IDEOGRAPH + 0xFAE5: 0x8852, //CJK UNIFIED IDEOGRAPH + 0xFAE6: 0xFA0A, //CJK COMPATIBILITY IDEOGRAPH + 0xFAE7: 0x8CE2, //CJK UNIFIED IDEOGRAPH + 0xFAE8: 0x9249, //CJK UNIFIED IDEOGRAPH + 0xFAE9: 0x986F, //CJK UNIFIED IDEOGRAPH + 0xFAEA: 0x5B51, //CJK UNIFIED IDEOGRAPH + 0xFAEB: 0x7A74, //CJK UNIFIED IDEOGRAPH + 0xFAEC: 0x8840, //CJK UNIFIED IDEOGRAPH + 0xFAED: 0x9801, //CJK UNIFIED IDEOGRAPH + 0xFAEE: 0x5ACC, //CJK UNIFIED IDEOGRAPH + 0xFAEF: 0x4FE0, //CJK UNIFIED IDEOGRAPH + 0xFAF0: 0x5354, //CJK UNIFIED IDEOGRAPH + 0xFAF1: 0x593E, //CJK UNIFIED IDEOGRAPH + 0xFAF2: 0x5CFD, //CJK UNIFIED IDEOGRAPH + 0xFAF3: 0x633E, //CJK UNIFIED IDEOGRAPH + 0xFAF4: 0x6D79, //CJK UNIFIED IDEOGRAPH + 0xFAF5: 0x72F9, //CJK UNIFIED IDEOGRAPH + 0xFAF6: 0x8105, //CJK UNIFIED IDEOGRAPH + 0xFAF7: 0x8107, //CJK UNIFIED IDEOGRAPH + 0xFAF8: 0x83A2, //CJK UNIFIED IDEOGRAPH + 0xFAF9: 0x92CF, //CJK UNIFIED IDEOGRAPH + 0xFAFA: 0x9830, //CJK UNIFIED IDEOGRAPH + 0xFAFB: 0x4EA8, //CJK UNIFIED IDEOGRAPH + 0xFAFC: 0x5144, //CJK UNIFIED IDEOGRAPH + 0xFAFD: 0x5211, //CJK UNIFIED IDEOGRAPH + 0xFAFE: 0x578B, //CJK UNIFIED IDEOGRAPH + 0xFBA1: 0x5F62, //CJK UNIFIED IDEOGRAPH + 0xFBA2: 0x6CC2, //CJK UNIFIED IDEOGRAPH + 0xFBA3: 0x6ECE, //CJK UNIFIED IDEOGRAPH + 0xFBA4: 0x7005, //CJK UNIFIED IDEOGRAPH + 0xFBA5: 0x7050, //CJK UNIFIED IDEOGRAPH + 0xFBA6: 0x70AF, //CJK UNIFIED IDEOGRAPH + 0xFBA7: 0x7192, //CJK UNIFIED IDEOGRAPH + 0xFBA8: 0x73E9, //CJK UNIFIED IDEOGRAPH + 0xFBA9: 0x7469, //CJK UNIFIED IDEOGRAPH + 0xFBAA: 0x834A, //CJK UNIFIED IDEOGRAPH + 0xFBAB: 0x87A2, //CJK UNIFIED IDEOGRAPH + 0xFBAC: 0x8861, //CJK UNIFIED IDEOGRAPH + 0xFBAD: 0x9008, //CJK UNIFIED IDEOGRAPH + 0xFBAE: 0x90A2, //CJK UNIFIED IDEOGRAPH + 0xFBAF: 0x93A3, //CJK UNIFIED IDEOGRAPH + 0xFBB0: 0x99A8, //CJK UNIFIED IDEOGRAPH + 0xFBB1: 0x516E, //CJK UNIFIED IDEOGRAPH + 0xFBB2: 0x5F57, //CJK UNIFIED IDEOGRAPH + 0xFBB3: 0x60E0, //CJK UNIFIED IDEOGRAPH + 0xFBB4: 0x6167, //CJK UNIFIED IDEOGRAPH + 0xFBB5: 0x66B3, //CJK UNIFIED IDEOGRAPH + 0xFBB6: 0x8559, //CJK UNIFIED IDEOGRAPH + 0xFBB7: 0x8E4A, //CJK UNIFIED IDEOGRAPH + 0xFBB8: 0x91AF, //CJK UNIFIED IDEOGRAPH + 0xFBB9: 0x978B, //CJK UNIFIED IDEOGRAPH + 0xFBBA: 0x4E4E, //CJK UNIFIED IDEOGRAPH + 0xFBBB: 0x4E92, //CJK UNIFIED IDEOGRAPH + 0xFBBC: 0x547C, //CJK UNIFIED IDEOGRAPH + 0xFBBD: 0x58D5, //CJK UNIFIED IDEOGRAPH + 0xFBBE: 0x58FA, //CJK UNIFIED IDEOGRAPH + 0xFBBF: 0x597D, //CJK UNIFIED IDEOGRAPH + 0xFBC0: 0x5CB5, //CJK UNIFIED IDEOGRAPH + 0xFBC1: 0x5F27, //CJK UNIFIED IDEOGRAPH + 0xFBC2: 0x6236, //CJK UNIFIED IDEOGRAPH + 0xFBC3: 0x6248, //CJK UNIFIED IDEOGRAPH + 0xFBC4: 0x660A, //CJK UNIFIED IDEOGRAPH + 0xFBC5: 0x6667, //CJK UNIFIED IDEOGRAPH + 0xFBC6: 0x6BEB, //CJK UNIFIED IDEOGRAPH + 0xFBC7: 0x6D69, //CJK UNIFIED IDEOGRAPH + 0xFBC8: 0x6DCF, //CJK UNIFIED IDEOGRAPH + 0xFBC9: 0x6E56, //CJK UNIFIED IDEOGRAPH + 0xFBCA: 0x6EF8, //CJK UNIFIED IDEOGRAPH + 0xFBCB: 0x6F94, //CJK UNIFIED IDEOGRAPH + 0xFBCC: 0x6FE0, //CJK UNIFIED IDEOGRAPH + 0xFBCD: 0x6FE9, //CJK UNIFIED IDEOGRAPH + 0xFBCE: 0x705D, //CJK UNIFIED IDEOGRAPH + 0xFBCF: 0x72D0, //CJK UNIFIED IDEOGRAPH + 0xFBD0: 0x7425, //CJK UNIFIED IDEOGRAPH + 0xFBD1: 0x745A, //CJK UNIFIED IDEOGRAPH + 0xFBD2: 0x74E0, //CJK UNIFIED IDEOGRAPH + 0xFBD3: 0x7693, //CJK UNIFIED IDEOGRAPH + 0xFBD4: 0x795C, //CJK UNIFIED IDEOGRAPH + 0xFBD5: 0x7CCA, //CJK UNIFIED IDEOGRAPH + 0xFBD6: 0x7E1E, //CJK UNIFIED IDEOGRAPH + 0xFBD7: 0x80E1, //CJK UNIFIED IDEOGRAPH + 0xFBD8: 0x82A6, //CJK UNIFIED IDEOGRAPH + 0xFBD9: 0x846B, //CJK UNIFIED IDEOGRAPH + 0xFBDA: 0x84BF, //CJK UNIFIED IDEOGRAPH + 0xFBDB: 0x864E, //CJK UNIFIED IDEOGRAPH + 0xFBDC: 0x865F, //CJK UNIFIED IDEOGRAPH + 0xFBDD: 0x8774, //CJK UNIFIED IDEOGRAPH + 0xFBDE: 0x8B77, //CJK UNIFIED IDEOGRAPH + 0xFBDF: 0x8C6A, //CJK UNIFIED IDEOGRAPH + 0xFBE0: 0x93AC, //CJK UNIFIED IDEOGRAPH + 0xFBE1: 0x9800, //CJK UNIFIED IDEOGRAPH + 0xFBE2: 0x9865, //CJK UNIFIED IDEOGRAPH + 0xFBE3: 0x60D1, //CJK UNIFIED IDEOGRAPH + 0xFBE4: 0x6216, //CJK UNIFIED IDEOGRAPH + 0xFBE5: 0x9177, //CJK UNIFIED IDEOGRAPH + 0xFBE6: 0x5A5A, //CJK UNIFIED IDEOGRAPH + 0xFBE7: 0x660F, //CJK UNIFIED IDEOGRAPH + 0xFBE8: 0x6DF7, //CJK UNIFIED IDEOGRAPH + 0xFBE9: 0x6E3E, //CJK UNIFIED IDEOGRAPH + 0xFBEA: 0x743F, //CJK UNIFIED IDEOGRAPH + 0xFBEB: 0x9B42, //CJK UNIFIED IDEOGRAPH + 0xFBEC: 0x5FFD, //CJK UNIFIED IDEOGRAPH + 0xFBED: 0x60DA, //CJK UNIFIED IDEOGRAPH + 0xFBEE: 0x7B0F, //CJK UNIFIED IDEOGRAPH + 0xFBEF: 0x54C4, //CJK UNIFIED IDEOGRAPH + 0xFBF0: 0x5F18, //CJK UNIFIED IDEOGRAPH + 0xFBF1: 0x6C5E, //CJK UNIFIED IDEOGRAPH + 0xFBF2: 0x6CD3, //CJK UNIFIED IDEOGRAPH + 0xFBF3: 0x6D2A, //CJK UNIFIED IDEOGRAPH + 0xFBF4: 0x70D8, //CJK UNIFIED IDEOGRAPH + 0xFBF5: 0x7D05, //CJK UNIFIED IDEOGRAPH + 0xFBF6: 0x8679, //CJK UNIFIED IDEOGRAPH + 0xFBF7: 0x8A0C, //CJK UNIFIED IDEOGRAPH + 0xFBF8: 0x9D3B, //CJK UNIFIED IDEOGRAPH + 0xFBF9: 0x5316, //CJK UNIFIED IDEOGRAPH + 0xFBFA: 0x548C, //CJK UNIFIED IDEOGRAPH + 0xFBFB: 0x5B05, //CJK UNIFIED IDEOGRAPH + 0xFBFC: 0x6A3A, //CJK UNIFIED IDEOGRAPH + 0xFBFD: 0x706B, //CJK UNIFIED IDEOGRAPH + 0xFBFE: 0x7575, //CJK UNIFIED IDEOGRAPH + 0xFCA1: 0x798D, //CJK UNIFIED IDEOGRAPH + 0xFCA2: 0x79BE, //CJK UNIFIED IDEOGRAPH + 0xFCA3: 0x82B1, //CJK UNIFIED IDEOGRAPH + 0xFCA4: 0x83EF, //CJK UNIFIED IDEOGRAPH + 0xFCA5: 0x8A71, //CJK UNIFIED IDEOGRAPH + 0xFCA6: 0x8B41, //CJK UNIFIED IDEOGRAPH + 0xFCA7: 0x8CA8, //CJK UNIFIED IDEOGRAPH + 0xFCA8: 0x9774, //CJK UNIFIED IDEOGRAPH + 0xFCA9: 0xFA0B, //CJK COMPATIBILITY IDEOGRAPH + 0xFCAA: 0x64F4, //CJK UNIFIED IDEOGRAPH + 0xFCAB: 0x652B, //CJK UNIFIED IDEOGRAPH + 0xFCAC: 0x78BA, //CJK UNIFIED IDEOGRAPH + 0xFCAD: 0x78BB, //CJK UNIFIED IDEOGRAPH + 0xFCAE: 0x7A6B, //CJK UNIFIED IDEOGRAPH + 0xFCAF: 0x4E38, //CJK UNIFIED IDEOGRAPH + 0xFCB0: 0x559A, //CJK UNIFIED IDEOGRAPH + 0xFCB1: 0x5950, //CJK UNIFIED IDEOGRAPH + 0xFCB2: 0x5BA6, //CJK UNIFIED IDEOGRAPH + 0xFCB3: 0x5E7B, //CJK UNIFIED IDEOGRAPH + 0xFCB4: 0x60A3, //CJK UNIFIED IDEOGRAPH + 0xFCB5: 0x63DB, //CJK UNIFIED IDEOGRAPH + 0xFCB6: 0x6B61, //CJK UNIFIED IDEOGRAPH + 0xFCB7: 0x6665, //CJK UNIFIED IDEOGRAPH + 0xFCB8: 0x6853, //CJK UNIFIED IDEOGRAPH + 0xFCB9: 0x6E19, //CJK UNIFIED IDEOGRAPH + 0xFCBA: 0x7165, //CJK UNIFIED IDEOGRAPH + 0xFCBB: 0x74B0, //CJK UNIFIED IDEOGRAPH + 0xFCBC: 0x7D08, //CJK UNIFIED IDEOGRAPH + 0xFCBD: 0x9084, //CJK UNIFIED IDEOGRAPH + 0xFCBE: 0x9A69, //CJK UNIFIED IDEOGRAPH + 0xFCBF: 0x9C25, //CJK UNIFIED IDEOGRAPH + 0xFCC0: 0x6D3B, //CJK UNIFIED IDEOGRAPH + 0xFCC1: 0x6ED1, //CJK UNIFIED IDEOGRAPH + 0xFCC2: 0x733E, //CJK UNIFIED IDEOGRAPH + 0xFCC3: 0x8C41, //CJK UNIFIED IDEOGRAPH + 0xFCC4: 0x95CA, //CJK UNIFIED IDEOGRAPH + 0xFCC5: 0x51F0, //CJK UNIFIED IDEOGRAPH + 0xFCC6: 0x5E4C, //CJK UNIFIED IDEOGRAPH + 0xFCC7: 0x5FA8, //CJK UNIFIED IDEOGRAPH + 0xFCC8: 0x604D, //CJK UNIFIED IDEOGRAPH + 0xFCC9: 0x60F6, //CJK UNIFIED IDEOGRAPH + 0xFCCA: 0x6130, //CJK UNIFIED IDEOGRAPH + 0xFCCB: 0x614C, //CJK UNIFIED IDEOGRAPH + 0xFCCC: 0x6643, //CJK UNIFIED IDEOGRAPH + 0xFCCD: 0x6644, //CJK UNIFIED IDEOGRAPH + 0xFCCE: 0x69A5, //CJK UNIFIED IDEOGRAPH + 0xFCCF: 0x6CC1, //CJK UNIFIED IDEOGRAPH + 0xFCD0: 0x6E5F, //CJK UNIFIED IDEOGRAPH + 0xFCD1: 0x6EC9, //CJK UNIFIED IDEOGRAPH + 0xFCD2: 0x6F62, //CJK UNIFIED IDEOGRAPH + 0xFCD3: 0x714C, //CJK UNIFIED IDEOGRAPH + 0xFCD4: 0x749C, //CJK UNIFIED IDEOGRAPH + 0xFCD5: 0x7687, //CJK UNIFIED IDEOGRAPH + 0xFCD6: 0x7BC1, //CJK UNIFIED IDEOGRAPH + 0xFCD7: 0x7C27, //CJK UNIFIED IDEOGRAPH + 0xFCD8: 0x8352, //CJK UNIFIED IDEOGRAPH + 0xFCD9: 0x8757, //CJK UNIFIED IDEOGRAPH + 0xFCDA: 0x9051, //CJK UNIFIED IDEOGRAPH + 0xFCDB: 0x968D, //CJK UNIFIED IDEOGRAPH + 0xFCDC: 0x9EC3, //CJK UNIFIED IDEOGRAPH + 0xFCDD: 0x532F, //CJK UNIFIED IDEOGRAPH + 0xFCDE: 0x56DE, //CJK UNIFIED IDEOGRAPH + 0xFCDF: 0x5EFB, //CJK UNIFIED IDEOGRAPH + 0xFCE0: 0x5F8A, //CJK UNIFIED IDEOGRAPH + 0xFCE1: 0x6062, //CJK UNIFIED IDEOGRAPH + 0xFCE2: 0x6094, //CJK UNIFIED IDEOGRAPH + 0xFCE3: 0x61F7, //CJK UNIFIED IDEOGRAPH + 0xFCE4: 0x6666, //CJK UNIFIED IDEOGRAPH + 0xFCE5: 0x6703, //CJK UNIFIED IDEOGRAPH + 0xFCE6: 0x6A9C, //CJK UNIFIED IDEOGRAPH + 0xFCE7: 0x6DEE, //CJK UNIFIED IDEOGRAPH + 0xFCE8: 0x6FAE, //CJK UNIFIED IDEOGRAPH + 0xFCE9: 0x7070, //CJK UNIFIED IDEOGRAPH + 0xFCEA: 0x736A, //CJK UNIFIED IDEOGRAPH + 0xFCEB: 0x7E6A, //CJK UNIFIED IDEOGRAPH + 0xFCEC: 0x81BE, //CJK UNIFIED IDEOGRAPH + 0xFCED: 0x8334, //CJK UNIFIED IDEOGRAPH + 0xFCEE: 0x86D4, //CJK UNIFIED IDEOGRAPH + 0xFCEF: 0x8AA8, //CJK UNIFIED IDEOGRAPH + 0xFCF0: 0x8CC4, //CJK UNIFIED IDEOGRAPH + 0xFCF1: 0x5283, //CJK UNIFIED IDEOGRAPH + 0xFCF2: 0x7372, //CJK UNIFIED IDEOGRAPH + 0xFCF3: 0x5B96, //CJK UNIFIED IDEOGRAPH + 0xFCF4: 0x6A6B, //CJK UNIFIED IDEOGRAPH + 0xFCF5: 0x9404, //CJK UNIFIED IDEOGRAPH + 0xFCF6: 0x54EE, //CJK UNIFIED IDEOGRAPH + 0xFCF7: 0x5686, //CJK UNIFIED IDEOGRAPH + 0xFCF8: 0x5B5D, //CJK UNIFIED IDEOGRAPH + 0xFCF9: 0x6548, //CJK UNIFIED IDEOGRAPH + 0xFCFA: 0x6585, //CJK UNIFIED IDEOGRAPH + 0xFCFB: 0x66C9, //CJK UNIFIED IDEOGRAPH + 0xFCFC: 0x689F, //CJK UNIFIED IDEOGRAPH + 0xFCFD: 0x6D8D, //CJK UNIFIED IDEOGRAPH + 0xFCFE: 0x6DC6, //CJK UNIFIED IDEOGRAPH + 0xFDA1: 0x723B, //CJK UNIFIED IDEOGRAPH + 0xFDA2: 0x80B4, //CJK UNIFIED IDEOGRAPH + 0xFDA3: 0x9175, //CJK UNIFIED IDEOGRAPH + 0xFDA4: 0x9A4D, //CJK UNIFIED IDEOGRAPH + 0xFDA5: 0x4FAF, //CJK UNIFIED IDEOGRAPH + 0xFDA6: 0x5019, //CJK UNIFIED IDEOGRAPH + 0xFDA7: 0x539A, //CJK UNIFIED IDEOGRAPH + 0xFDA8: 0x540E, //CJK UNIFIED IDEOGRAPH + 0xFDA9: 0x543C, //CJK UNIFIED IDEOGRAPH + 0xFDAA: 0x5589, //CJK UNIFIED IDEOGRAPH + 0xFDAB: 0x55C5, //CJK UNIFIED IDEOGRAPH + 0xFDAC: 0x5E3F, //CJK UNIFIED IDEOGRAPH + 0xFDAD: 0x5F8C, //CJK UNIFIED IDEOGRAPH + 0xFDAE: 0x673D, //CJK UNIFIED IDEOGRAPH + 0xFDAF: 0x7166, //CJK UNIFIED IDEOGRAPH + 0xFDB0: 0x73DD, //CJK UNIFIED IDEOGRAPH + 0xFDB1: 0x9005, //CJK UNIFIED IDEOGRAPH + 0xFDB2: 0x52DB, //CJK UNIFIED IDEOGRAPH + 0xFDB3: 0x52F3, //CJK UNIFIED IDEOGRAPH + 0xFDB4: 0x5864, //CJK UNIFIED IDEOGRAPH + 0xFDB5: 0x58CE, //CJK UNIFIED IDEOGRAPH + 0xFDB6: 0x7104, //CJK UNIFIED IDEOGRAPH + 0xFDB7: 0x718F, //CJK UNIFIED IDEOGRAPH + 0xFDB8: 0x71FB, //CJK UNIFIED IDEOGRAPH + 0xFDB9: 0x85B0, //CJK UNIFIED IDEOGRAPH + 0xFDBA: 0x8A13, //CJK UNIFIED IDEOGRAPH + 0xFDBB: 0x6688, //CJK UNIFIED IDEOGRAPH + 0xFDBC: 0x85A8, //CJK UNIFIED IDEOGRAPH + 0xFDBD: 0x55A7, //CJK UNIFIED IDEOGRAPH + 0xFDBE: 0x6684, //CJK UNIFIED IDEOGRAPH + 0xFDBF: 0x714A, //CJK UNIFIED IDEOGRAPH + 0xFDC0: 0x8431, //CJK UNIFIED IDEOGRAPH + 0xFDC1: 0x5349, //CJK UNIFIED IDEOGRAPH + 0xFDC2: 0x5599, //CJK UNIFIED IDEOGRAPH + 0xFDC3: 0x6BC1, //CJK UNIFIED IDEOGRAPH + 0xFDC4: 0x5F59, //CJK UNIFIED IDEOGRAPH + 0xFDC5: 0x5FBD, //CJK UNIFIED IDEOGRAPH + 0xFDC6: 0x63EE, //CJK UNIFIED IDEOGRAPH + 0xFDC7: 0x6689, //CJK UNIFIED IDEOGRAPH + 0xFDC8: 0x7147, //CJK UNIFIED IDEOGRAPH + 0xFDC9: 0x8AF1, //CJK UNIFIED IDEOGRAPH + 0xFDCA: 0x8F1D, //CJK UNIFIED IDEOGRAPH + 0xFDCB: 0x9EBE, //CJK UNIFIED IDEOGRAPH + 0xFDCC: 0x4F11, //CJK UNIFIED IDEOGRAPH + 0xFDCD: 0x643A, //CJK UNIFIED IDEOGRAPH + 0xFDCE: 0x70CB, //CJK UNIFIED IDEOGRAPH + 0xFDCF: 0x7566, //CJK UNIFIED IDEOGRAPH + 0xFDD0: 0x8667, //CJK UNIFIED IDEOGRAPH + 0xFDD1: 0x6064, //CJK UNIFIED IDEOGRAPH + 0xFDD2: 0x8B4E, //CJK UNIFIED IDEOGRAPH + 0xFDD3: 0x9DF8, //CJK UNIFIED IDEOGRAPH + 0xFDD4: 0x5147, //CJK UNIFIED IDEOGRAPH + 0xFDD5: 0x51F6, //CJK UNIFIED IDEOGRAPH + 0xFDD6: 0x5308, //CJK UNIFIED IDEOGRAPH + 0xFDD7: 0x6D36, //CJK UNIFIED IDEOGRAPH + 0xFDD8: 0x80F8, //CJK UNIFIED IDEOGRAPH + 0xFDD9: 0x9ED1, //CJK UNIFIED IDEOGRAPH + 0xFDDA: 0x6615, //CJK UNIFIED IDEOGRAPH + 0xFDDB: 0x6B23, //CJK UNIFIED IDEOGRAPH + 0xFDDC: 0x7098, //CJK UNIFIED IDEOGRAPH + 0xFDDD: 0x75D5, //CJK UNIFIED IDEOGRAPH + 0xFDDE: 0x5403, //CJK UNIFIED IDEOGRAPH + 0xFDDF: 0x5C79, //CJK UNIFIED IDEOGRAPH + 0xFDE0: 0x7D07, //CJK UNIFIED IDEOGRAPH + 0xFDE1: 0x8A16, //CJK UNIFIED IDEOGRAPH + 0xFDE2: 0x6B20, //CJK UNIFIED IDEOGRAPH + 0xFDE3: 0x6B3D, //CJK UNIFIED IDEOGRAPH + 0xFDE4: 0x6B46, //CJK UNIFIED IDEOGRAPH + 0xFDE5: 0x5438, //CJK UNIFIED IDEOGRAPH + 0xFDE6: 0x6070, //CJK UNIFIED IDEOGRAPH + 0xFDE7: 0x6D3D, //CJK UNIFIED IDEOGRAPH + 0xFDE8: 0x7FD5, //CJK UNIFIED IDEOGRAPH + 0xFDE9: 0x8208, //CJK UNIFIED IDEOGRAPH + 0xFDEA: 0x50D6, //CJK UNIFIED IDEOGRAPH + 0xFDEB: 0x51DE, //CJK UNIFIED IDEOGRAPH + 0xFDEC: 0x559C, //CJK UNIFIED IDEOGRAPH + 0xFDED: 0x566B, //CJK UNIFIED IDEOGRAPH + 0xFDEE: 0x56CD, //CJK UNIFIED IDEOGRAPH + 0xFDEF: 0x59EC, //CJK UNIFIED IDEOGRAPH + 0xFDF0: 0x5B09, //CJK UNIFIED IDEOGRAPH + 0xFDF1: 0x5E0C, //CJK UNIFIED IDEOGRAPH + 0xFDF2: 0x6199, //CJK UNIFIED IDEOGRAPH + 0xFDF3: 0x6198, //CJK UNIFIED IDEOGRAPH + 0xFDF4: 0x6231, //CJK UNIFIED IDEOGRAPH + 0xFDF5: 0x665E, //CJK UNIFIED IDEOGRAPH + 0xFDF6: 0x66E6, //CJK UNIFIED IDEOGRAPH + 0xFDF7: 0x7199, //CJK UNIFIED IDEOGRAPH + 0xFDF8: 0x71B9, //CJK UNIFIED IDEOGRAPH + 0xFDF9: 0x71BA, //CJK UNIFIED IDEOGRAPH + 0xFDFA: 0x72A7, //CJK UNIFIED IDEOGRAPH + 0xFDFB: 0x79A7, //CJK UNIFIED IDEOGRAPH + 0xFDFC: 0x7A00, //CJK UNIFIED IDEOGRAPH + 0xFDFD: 0x7FB2, //CJK UNIFIED IDEOGRAPH + 0xFDFE: 0x8A70, //CJK UNIFIED IDEOGRAPH + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp950.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp950.go new file mode 100644 index 00000000..1301cd0f --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp950.go @@ -0,0 +1,13767 @@ +package cp + +var cp950 *charsetMap = &charsetMap{ + sb: [256]rune{ + 0x0000, //NULL + 0x0001, //START OF HEADING + 0x0002, //START OF TEXT + 0x0003, //END OF TEXT + 0x0004, //END OF TRANSMISSION + 0x0005, //ENQUIRY + 0x0006, //ACKNOWLEDGE + 0x0007, //BELL + 0x0008, //BACKSPACE + 0x0009, //HORIZONTAL TABULATION + 0x000A, //LINE FEED + 0x000B, //VERTICAL TABULATION + 0x000C, //FORM FEED + 0x000D, //CARRIAGE RETURN + 0x000E, //SHIFT OUT + 0x000F, //SHIFT IN + 0x0010, //DATA LINK ESCAPE + 0x0011, //DEVICE CONTROL ONE + 0x0012, //DEVICE CONTROL TWO + 0x0013, //DEVICE CONTROL THREE + 0x0014, //DEVICE CONTROL FOUR + 0x0015, //NEGATIVE ACKNOWLEDGE + 0x0016, //SYNCHRONOUS IDLE + 0x0017, //END OF TRANSMISSION BLOCK + 0x0018, //CANCEL + 0x0019, //END OF MEDIUM + 0x001A, //SUBSTITUTE + 0x001B, //ESCAPE + 0x001C, //FILE SEPARATOR + 0x001D, //GROUP SEPARATOR + 0x001E, //RECORD SEPARATOR + 0x001F, //UNIT SEPARATOR + 0x0020, //SPACE + 0x0021, //EXCLAMATION MARK + 0x0022, //QUOTATION MARK + 0x0023, //NUMBER SIGN + 0x0024, //DOLLAR SIGN + 0x0025, //PERCENT SIGN + 0x0026, //AMPERSAND + 0x0027, //APOSTROPHE + 0x0028, //LEFT PARENTHESIS + 0x0029, //RIGHT PARENTHESIS + 0x002A, //ASTERISK + 0x002B, //PLUS SIGN + 0x002C, //COMMA + 0x002D, //HYPHEN-MINUS + 0x002E, //FULL STOP + 0x002F, //SOLIDUS + 0x0030, //DIGIT ZERO + 0x0031, //DIGIT ONE + 0x0032, //DIGIT TWO + 0x0033, //DIGIT THREE + 0x0034, //DIGIT FOUR + 0x0035, //DIGIT FIVE + 0x0036, //DIGIT SIX + 0x0037, //DIGIT SEVEN + 0x0038, //DIGIT EIGHT + 0x0039, //DIGIT NINE + 0x003A, //COLON + 0x003B, //SEMICOLON + 0x003C, //LESS-THAN SIGN + 0x003D, //EQUALS SIGN + 0x003E, //GREATER-THAN SIGN + 0x003F, //QUESTION MARK + 0x0040, //COMMERCIAL AT + 0x0041, //LATIN CAPITAL LETTER A + 0x0042, //LATIN CAPITAL LETTER B + 0x0043, //LATIN CAPITAL LETTER C + 0x0044, //LATIN CAPITAL LETTER D + 0x0045, //LATIN CAPITAL LETTER E + 0x0046, //LATIN CAPITAL LETTER F + 0x0047, //LATIN CAPITAL LETTER G + 0x0048, //LATIN CAPITAL LETTER H + 0x0049, //LATIN CAPITAL LETTER I + 0x004A, //LATIN CAPITAL LETTER J + 0x004B, //LATIN CAPITAL LETTER K + 0x004C, //LATIN CAPITAL LETTER L + 0x004D, //LATIN CAPITAL LETTER M + 0x004E, //LATIN CAPITAL LETTER N + 0x004F, //LATIN CAPITAL LETTER O + 0x0050, //LATIN CAPITAL LETTER P + 0x0051, //LATIN CAPITAL LETTER Q + 0x0052, //LATIN CAPITAL LETTER R + 0x0053, //LATIN CAPITAL LETTER S + 0x0054, //LATIN CAPITAL LETTER T + 0x0055, //LATIN CAPITAL LETTER U + 0x0056, //LATIN CAPITAL LETTER V + 0x0057, //LATIN CAPITAL LETTER W + 0x0058, //LATIN CAPITAL LETTER X + 0x0059, //LATIN CAPITAL LETTER Y + 0x005A, //LATIN CAPITAL LETTER Z + 0x005B, //LEFT SQUARE BRACKET + 0x005C, //REVERSE SOLIDUS + 0x005D, //RIGHT SQUARE BRACKET + 0x005E, //CIRCUMFLEX ACCENT + 0x005F, //LOW LINE + 0x0060, //GRAVE ACCENT + 0x0061, //LATIN SMALL LETTER A + 0x0062, //LATIN SMALL LETTER B + 0x0063, //LATIN SMALL LETTER C + 0x0064, //LATIN SMALL LETTER D + 0x0065, //LATIN SMALL LETTER E + 0x0066, //LATIN SMALL LETTER F + 0x0067, //LATIN SMALL LETTER G + 0x0068, //LATIN SMALL LETTER H + 0x0069, //LATIN SMALL LETTER I + 0x006A, //LATIN SMALL LETTER J + 0x006B, //LATIN SMALL LETTER K + 0x006C, //LATIN SMALL LETTER L + 0x006D, //LATIN SMALL LETTER M + 0x006E, //LATIN SMALL LETTER N + 0x006F, //LATIN SMALL LETTER O + 0x0070, //LATIN SMALL LETTER P + 0x0071, //LATIN SMALL LETTER Q + 0x0072, //LATIN SMALL LETTER R + 0x0073, //LATIN SMALL LETTER S + 0x0074, //LATIN SMALL LETTER T + 0x0075, //LATIN SMALL LETTER U + 0x0076, //LATIN SMALL LETTER V + 0x0077, //LATIN SMALL LETTER W + 0x0078, //LATIN SMALL LETTER X + 0x0079, //LATIN SMALL LETTER Y + 0x007A, //LATIN SMALL LETTER Z + 0x007B, //LEFT CURLY BRACKET + 0x007C, //VERTICAL LINE + 0x007D, //RIGHT CURLY BRACKET + 0x007E, //TILDE + 0x007F, //DELETE + 0xFFFD, //UNDEFINED + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + -1, //DBCS LEAD BYTE + 0xFFFD, //UNDEFINED + }, + db: map[int]rune{ + 0xA140: 0x3000, //IDEOGRAPHIC SPACE + 0xA141: 0xFF0C, //FULLWIDTH COMMA + 0xA142: 0x3001, //IDEOGRAPHIC COMMA + 0xA143: 0x3002, //IDEOGRAPHIC FULL STOP + 0xA144: 0xFF0E, //FULLWIDTH FULL STOP + 0xA145: 0x2027, //HYPHENATION POINT + 0xA146: 0xFF1B, //FULLWIDTH SEMICOLON + 0xA147: 0xFF1A, //FULLWIDTH COLON + 0xA148: 0xFF1F, //FULLWIDTH QUESTION MARK + 0xA149: 0xFF01, //FULLWIDTH EXCLAMATION MARK + 0xA14A: 0xFE30, //PRESENTATION FORM FOR VERTICAL TWO DOT LEADER + 0xA14B: 0x2026, //HORIZONTAL ELLIPSIS + 0xA14C: 0x2025, //TWO DOT LEADER + 0xA14D: 0xFE50, //SMALL COMMA + 0xA14E: 0xFE51, //SMALL IDEOGRAPHIC COMMA + 0xA14F: 0xFE52, //SMALL FULL STOP + 0xA150: 0x00B7, //MIDDLE DOT + 0xA151: 0xFE54, //SMALL SEMICOLON + 0xA152: 0xFE55, //SMALL COLON + 0xA153: 0xFE56, //SMALL QUESTION MARK + 0xA154: 0xFE57, //SMALL EXCLAMATION MARK + 0xA155: 0xFF5C, //FULLWIDTH VERTICAL LINE + 0xA156: 0x2013, //EN DASH + 0xA157: 0xFE31, //PRESENTATION FORM FOR VERTICAL EM DASH + 0xA158: 0x2014, //EM DASH + 0xA159: 0xFE33, //PRESENTATION FORM FOR VERTICAL LOW LINE + 0xA15A: 0x2574, //BOX DRAWINGS LIGHT LEFT + 0xA15B: 0xFE34, //PRESENTATION FORM FOR VERTICAL WAVY LOW LINE + 0xA15C: 0xFE4F, //WAVY LOW LINE + 0xA15D: 0xFF08, //FULLWIDTH LEFT PARENTHESIS + 0xA15E: 0xFF09, //FULLWIDTH RIGHT PARENTHESIS + 0xA15F: 0xFE35, //PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS + 0xA160: 0xFE36, //PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS + 0xA161: 0xFF5B, //FULLWIDTH LEFT CURLY BRACKET + 0xA162: 0xFF5D, //FULLWIDTH RIGHT CURLY BRACKET + 0xA163: 0xFE37, //PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET + 0xA164: 0xFE38, //PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET + 0xA165: 0x3014, //LEFT TORTOISE SHELL BRACKET + 0xA166: 0x3015, //RIGHT TORTOISE SHELL BRACKET + 0xA167: 0xFE39, //PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET + 0xA168: 0xFE3A, //PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET + 0xA169: 0x3010, //LEFT BLACK LENTICULAR BRACKET + 0xA16A: 0x3011, //RIGHT BLACK LENTICULAR BRACKET + 0xA16B: 0xFE3B, //PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET + 0xA16C: 0xFE3C, //PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET + 0xA16D: 0x300A, //LEFT DOUBLE ANGLE BRACKET + 0xA16E: 0x300B, //RIGHT DOUBLE ANGLE BRACKET + 0xA16F: 0xFE3D, //PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET + 0xA170: 0xFE3E, //PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET + 0xA171: 0x3008, //LEFT ANGLE BRACKET + 0xA172: 0x3009, //RIGHT ANGLE BRACKET + 0xA173: 0xFE3F, //PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET + 0xA174: 0xFE40, //PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET + 0xA175: 0x300C, //LEFT CORNER BRACKET + 0xA176: 0x300D, //RIGHT CORNER BRACKET + 0xA177: 0xFE41, //PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET + 0xA178: 0xFE42, //PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET + 0xA179: 0x300E, //LEFT WHITE CORNER BRACKET + 0xA17A: 0x300F, //RIGHT WHITE CORNER BRACKET + 0xA17B: 0xFE43, //PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET + 0xA17C: 0xFE44, //PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET + 0xA17D: 0xFE59, //SMALL LEFT PARENTHESIS + 0xA17E: 0xFE5A, //SMALL RIGHT PARENTHESIS + 0xA1A1: 0xFE5B, //SMALL LEFT CURLY BRACKET + 0xA1A2: 0xFE5C, //SMALL RIGHT CURLY BRACKET + 0xA1A3: 0xFE5D, //SMALL LEFT TORTOISE SHELL BRACKET + 0xA1A4: 0xFE5E, //SMALL RIGHT TORTOISE SHELL BRACKET + 0xA1A5: 0x2018, //LEFT SINGLE QUOTATION MARK + 0xA1A6: 0x2019, //RIGHT SINGLE QUOTATION MARK + 0xA1A7: 0x201C, //LEFT DOUBLE QUOTATION MARK + 0xA1A8: 0x201D, //RIGHT DOUBLE QUOTATION MARK + 0xA1A9: 0x301D, //REVERSED DOUBLE PRIME QUOTATION MARK + 0xA1AA: 0x301E, //DOUBLE PRIME QUOTATION MARK + 0xA1AB: 0x2035, //REVERSED PRIME + 0xA1AC: 0x2032, //PRIME + 0xA1AD: 0xFF03, //FULLWIDTH NUMBER SIGN + 0xA1AE: 0xFF06, //FULLWIDTH AMPERSAND + 0xA1AF: 0xFF0A, //FULLWIDTH ASTERISK + 0xA1B0: 0x203B, //REFERENCE MARK + 0xA1B1: 0x00A7, //SECTION SIGN + 0xA1B2: 0x3003, //DITTO MARK + 0xA1B3: 0x25CB, //WHITE CIRCLE + 0xA1B4: 0x25CF, //BLACK CIRCLE + 0xA1B5: 0x25B3, //WHITE UP-POINTING TRIANGLE + 0xA1B6: 0x25B2, //BLACK UP-POINTING TRIANGLE + 0xA1B7: 0x25CE, //BULLSEYE + 0xA1B8: 0x2606, //WHITE STAR + 0xA1B9: 0x2605, //BLACK STAR + 0xA1BA: 0x25C7, //WHITE DIAMOND + 0xA1BB: 0x25C6, //BLACK DIAMOND + 0xA1BC: 0x25A1, //WHITE SQUARE + 0xA1BD: 0x25A0, //BLACK SQUARE + 0xA1BE: 0x25BD, //WHITE DOWN-POINTING TRIANGLE + 0xA1BF: 0x25BC, //BLACK DOWN-POINTING TRIANGLE + 0xA1C0: 0x32A3, //CIRCLED IDEOGRAPH CORRECT + 0xA1C1: 0x2105, //CARE OF + 0xA1C2: 0x00AF, //MACRON + 0xA1C3: 0xFFE3, //FULLWIDTH MACRON + 0xA1C4: 0xFF3F, //FULLWIDTH LOW LINE + 0xA1C5: 0x02CD, //MODIFIER LETTER LOW MACRON + 0xA1C6: 0xFE49, //DASHED OVERLINE + 0xA1C7: 0xFE4A, //CENTRELINE OVERLINE + 0xA1C8: 0xFE4D, //DASHED LOW LINE + 0xA1C9: 0xFE4E, //CENTRELINE LOW LINE + 0xA1CA: 0xFE4B, //WAVY OVERLINE + 0xA1CB: 0xFE4C, //DOUBLE WAVY OVERLINE + 0xA1CC: 0xFE5F, //SMALL NUMBER SIGN + 0xA1CD: 0xFE60, //SMALL AMPERSAND + 0xA1CE: 0xFE61, //SMALL ASTERISK + 0xA1CF: 0xFF0B, //FULLWIDTH PLUS SIGN + 0xA1D0: 0xFF0D, //FULLWIDTH HYPHEN-MINUS + 0xA1D1: 0x00D7, //MULTIPLICATION SIGN + 0xA1D2: 0x00F7, //DIVISION SIGN + 0xA1D3: 0x00B1, //PLUS-MINUS SIGN + 0xA1D4: 0x221A, //SQUARE ROOT + 0xA1D5: 0xFF1C, //FULLWIDTH LESS-THAN SIGN + 0xA1D6: 0xFF1E, //FULLWIDTH GREATER-THAN SIGN + 0xA1D7: 0xFF1D, //FULLWIDTH EQUALS SIGN + 0xA1D8: 0x2266, //LESS-THAN OVER EQUAL TO + 0xA1D9: 0x2267, //GREATER-THAN OVER EQUAL TO + 0xA1DA: 0x2260, //NOT EQUAL TO + 0xA1DB: 0x221E, //INFINITY + 0xA1DC: 0x2252, //APPROXIMATELY EQUAL TO OR THE IMAGE OF + 0xA1DD: 0x2261, //IDENTICAL TO + 0xA1DE: 0xFE62, //SMALL PLUS SIGN + 0xA1DF: 0xFE63, //SMALL HYPHEN-MINUS + 0xA1E0: 0xFE64, //SMALL LESS-THAN SIGN + 0xA1E1: 0xFE65, //SMALL GREATER-THAN SIGN + 0xA1E2: 0xFE66, //SMALL EQUALS SIGN + 0xA1E3: 0xFF5E, //FULLWIDTH TILDE + 0xA1E4: 0x2229, //INTERSECTION + 0xA1E5: 0x222A, //UNION + 0xA1E6: 0x22A5, //UP TACK + 0xA1E7: 0x2220, //ANGLE + 0xA1E8: 0x221F, //RIGHT ANGLE + 0xA1E9: 0x22BF, //RIGHT TRIANGLE + 0xA1EA: 0x33D2, //SQUARE LOG + 0xA1EB: 0x33D1, //SQUARE LN + 0xA1EC: 0x222B, //INTEGRAL + 0xA1ED: 0x222E, //CONTOUR INTEGRAL + 0xA1EE: 0x2235, //BECAUSE + 0xA1EF: 0x2234, //THEREFORE + 0xA1F0: 0x2640, //FEMALE SIGN + 0xA1F1: 0x2642, //MALE SIGN + 0xA1F2: 0x2295, //CIRCLED PLUS + 0xA1F3: 0x2299, //CIRCLED DOT OPERATOR + 0xA1F4: 0x2191, //UPWARDS ARROW + 0xA1F5: 0x2193, //DOWNWARDS ARROW + 0xA1F6: 0x2190, //LEFTWARDS ARROW + 0xA1F7: 0x2192, //RIGHTWARDS ARROW + 0xA1F8: 0x2196, //NORTH WEST ARROW + 0xA1F9: 0x2197, //NORTH EAST ARROW + 0xA1FA: 0x2199, //SOUTH WEST ARROW + 0xA1FB: 0x2198, //SOUTH EAST ARROW + 0xA1FC: 0x2225, //PARALLEL TO + 0xA1FD: 0x2223, //DIVIDES + 0xA1FE: 0xFF0F, //FULLWIDTH SOLIDUS + 0xA240: 0xFF3C, //FULLWIDTH REVERSE SOLIDUS + 0xA241: 0x2215, //DIVISION SLASH + 0xA242: 0xFE68, //SMALL REVERSE SOLIDUS + 0xA243: 0xFF04, //FULLWIDTH DOLLAR SIGN + 0xA244: 0xFFE5, //FULLWIDTH YEN SIGN + 0xA245: 0x3012, //POSTAL MARK + 0xA246: 0xFFE0, //FULLWIDTH CENT SIGN + 0xA247: 0xFFE1, //FULLWIDTH POUND SIGN + 0xA248: 0xFF05, //FULLWIDTH PERCENT SIGN + 0xA249: 0xFF20, //FULLWIDTH COMMERCIAL AT + 0xA24A: 0x2103, //DEGREE CELSIUS + 0xA24B: 0x2109, //DEGREE FAHRENHEIT + 0xA24C: 0xFE69, //SMALL DOLLAR SIGN + 0xA24D: 0xFE6A, //SMALL PERCENT SIGN + 0xA24E: 0xFE6B, //SMALL COMMERCIAL AT + 0xA24F: 0x33D5, //SQUARE MIL + 0xA250: 0x339C, //SQUARE MM + 0xA251: 0x339D, //SQUARE CM + 0xA252: 0x339E, //SQUARE KM + 0xA253: 0x33CE, //SQUARE KM CAPITAL + 0xA254: 0x33A1, //SQUARE M SQUARED + 0xA255: 0x338E, //SQUARE MG + 0xA256: 0x338F, //SQUARE KG + 0xA257: 0x33C4, //SQUARE CC + 0xA258: 0x00B0, //DEGREE SIGN + 0xA259: 0x5159, //CJK UNIFIED IDEOGRAPH + 0xA25A: 0x515B, //CJK UNIFIED IDEOGRAPH + 0xA25B: 0x515E, //CJK UNIFIED IDEOGRAPH + 0xA25C: 0x515D, //CJK UNIFIED IDEOGRAPH + 0xA25D: 0x5161, //CJK UNIFIED IDEOGRAPH + 0xA25E: 0x5163, //CJK UNIFIED IDEOGRAPH + 0xA25F: 0x55E7, //CJK UNIFIED IDEOGRAPH + 0xA260: 0x74E9, //CJK UNIFIED IDEOGRAPH + 0xA261: 0x7CCE, //CJK UNIFIED IDEOGRAPH + 0xA262: 0x2581, //LOWER ONE EIGHTH BLOCK + 0xA263: 0x2582, //LOWER ONE QUARTER BLOCK + 0xA264: 0x2583, //LOWER THREE EIGHTHS BLOCK + 0xA265: 0x2584, //LOWER HALF BLOCK + 0xA266: 0x2585, //LOWER FIVE EIGHTHS BLOCK + 0xA267: 0x2586, //LOWER THREE QUARTERS BLOCK + 0xA268: 0x2587, //LOWER SEVEN EIGHTHS BLOCK + 0xA269: 0x2588, //FULL BLOCK + 0xA26A: 0x258F, //LEFT ONE EIGHTH BLOCK + 0xA26B: 0x258E, //LEFT ONE QUARTER BLOCK + 0xA26C: 0x258D, //LEFT THREE EIGHTHS BLOCK + 0xA26D: 0x258C, //LEFT HALF BLOCK + 0xA26E: 0x258B, //LEFT FIVE EIGHTHS BLOCK + 0xA26F: 0x258A, //LEFT THREE QUARTERS BLOCK + 0xA270: 0x2589, //LEFT SEVEN EIGHTHS BLOCK + 0xA271: 0x253C, //BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0xA272: 0x2534, //BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0xA273: 0x252C, //BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0xA274: 0x2524, //BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0xA275: 0x251C, //BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0xA276: 0x2594, //UPPER ONE EIGHTH BLOCK + 0xA277: 0x2500, //BOX DRAWINGS LIGHT HORIZONTAL + 0xA278: 0x2502, //BOX DRAWINGS LIGHT VERTICAL + 0xA279: 0x2595, //RIGHT ONE EIGHTH BLOCK + 0xA27A: 0x250C, //BOX DRAWINGS LIGHT DOWN AND RIGHT + 0xA27B: 0x2510, //BOX DRAWINGS LIGHT DOWN AND LEFT + 0xA27C: 0x2514, //BOX DRAWINGS LIGHT UP AND RIGHT + 0xA27D: 0x2518, //BOX DRAWINGS LIGHT UP AND LEFT + 0xA27E: 0x256D, //BOX DRAWINGS LIGHT ARC DOWN AND RIGHT + 0xA2A1: 0x256E, //BOX DRAWINGS LIGHT ARC DOWN AND LEFT + 0xA2A2: 0x2570, //BOX DRAWINGS LIGHT ARC UP AND RIGHT + 0xA2A3: 0x256F, //BOX DRAWINGS LIGHT ARC UP AND LEFT + 0xA2A4: 0x2550, //BOX DRAWINGS DOUBLE HORIZONTAL + 0xA2A5: 0x255E, //BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + 0xA2A6: 0x256A, //BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + 0xA2A7: 0x2561, //BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + 0xA2A8: 0x25E2, //BLACK LOWER RIGHT TRIANGLE + 0xA2A9: 0x25E3, //BLACK LOWER LEFT TRIANGLE + 0xA2AA: 0x25E5, //BLACK UPPER RIGHT TRIANGLE + 0xA2AB: 0x25E4, //BLACK UPPER LEFT TRIANGLE + 0xA2AC: 0x2571, //BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + 0xA2AD: 0x2572, //BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + 0xA2AE: 0x2573, //BOX DRAWINGS LIGHT DIAGONAL CROSS + 0xA2AF: 0xFF10, //FULLWIDTH DIGIT ZERO + 0xA2B0: 0xFF11, //FULLWIDTH DIGIT ONE + 0xA2B1: 0xFF12, //FULLWIDTH DIGIT TWO + 0xA2B2: 0xFF13, //FULLWIDTH DIGIT THREE + 0xA2B3: 0xFF14, //FULLWIDTH DIGIT FOUR + 0xA2B4: 0xFF15, //FULLWIDTH DIGIT FIVE + 0xA2B5: 0xFF16, //FULLWIDTH DIGIT SIX + 0xA2B6: 0xFF17, //FULLWIDTH DIGIT SEVEN + 0xA2B7: 0xFF18, //FULLWIDTH DIGIT EIGHT + 0xA2B8: 0xFF19, //FULLWIDTH DIGIT NINE + 0xA2B9: 0x2160, //ROMAN NUMERAL ONE + 0xA2BA: 0x2161, //ROMAN NUMERAL TWO + 0xA2BB: 0x2162, //ROMAN NUMERAL THREE + 0xA2BC: 0x2163, //ROMAN NUMERAL FOUR + 0xA2BD: 0x2164, //ROMAN NUMERAL FIVE + 0xA2BE: 0x2165, //ROMAN NUMERAL SIX + 0xA2BF: 0x2166, //ROMAN NUMERAL SEVEN + 0xA2C0: 0x2167, //ROMAN NUMERAL EIGHT + 0xA2C1: 0x2168, //ROMAN NUMERAL NINE + 0xA2C2: 0x2169, //ROMAN NUMERAL TEN + 0xA2C3: 0x3021, //HANGZHOU NUMERAL ONE + 0xA2C4: 0x3022, //HANGZHOU NUMERAL TWO + 0xA2C5: 0x3023, //HANGZHOU NUMERAL THREE + 0xA2C6: 0x3024, //HANGZHOU NUMERAL FOUR + 0xA2C7: 0x3025, //HANGZHOU NUMERAL FIVE + 0xA2C8: 0x3026, //HANGZHOU NUMERAL SIX + 0xA2C9: 0x3027, //HANGZHOU NUMERAL SEVEN + 0xA2CA: 0x3028, //HANGZHOU NUMERAL EIGHT + 0xA2CB: 0x3029, //HANGZHOU NUMERAL NINE + 0xA2CC: 0x5341, //CJK UNIFIED IDEOGRAPH + 0xA2CD: 0x5344, //CJK UNIFIED IDEOGRAPH + 0xA2CE: 0x5345, //CJK UNIFIED IDEOGRAPH + 0xA2CF: 0xFF21, //FULLWIDTH LATIN CAPITAL LETTER A + 0xA2D0: 0xFF22, //FULLWIDTH LATIN CAPITAL LETTER B + 0xA2D1: 0xFF23, //FULLWIDTH LATIN CAPITAL LETTER C + 0xA2D2: 0xFF24, //FULLWIDTH LATIN CAPITAL LETTER D + 0xA2D3: 0xFF25, //FULLWIDTH LATIN CAPITAL LETTER E + 0xA2D4: 0xFF26, //FULLWIDTH LATIN CAPITAL LETTER F + 0xA2D5: 0xFF27, //FULLWIDTH LATIN CAPITAL LETTER G + 0xA2D6: 0xFF28, //FULLWIDTH LATIN CAPITAL LETTER H + 0xA2D7: 0xFF29, //FULLWIDTH LATIN CAPITAL LETTER I + 0xA2D8: 0xFF2A, //FULLWIDTH LATIN CAPITAL LETTER J + 0xA2D9: 0xFF2B, //FULLWIDTH LATIN CAPITAL LETTER K + 0xA2DA: 0xFF2C, //FULLWIDTH LATIN CAPITAL LETTER L + 0xA2DB: 0xFF2D, //FULLWIDTH LATIN CAPITAL LETTER M + 0xA2DC: 0xFF2E, //FULLWIDTH LATIN CAPITAL LETTER N + 0xA2DD: 0xFF2F, //FULLWIDTH LATIN CAPITAL LETTER O + 0xA2DE: 0xFF30, //FULLWIDTH LATIN CAPITAL LETTER P + 0xA2DF: 0xFF31, //FULLWIDTH LATIN CAPITAL LETTER Q + 0xA2E0: 0xFF32, //FULLWIDTH LATIN CAPITAL LETTER R + 0xA2E1: 0xFF33, //FULLWIDTH LATIN CAPITAL LETTER S + 0xA2E2: 0xFF34, //FULLWIDTH LATIN CAPITAL LETTER T + 0xA2E3: 0xFF35, //FULLWIDTH LATIN CAPITAL LETTER U + 0xA2E4: 0xFF36, //FULLWIDTH LATIN CAPITAL LETTER V + 0xA2E5: 0xFF37, //FULLWIDTH LATIN CAPITAL LETTER W + 0xA2E6: 0xFF38, //FULLWIDTH LATIN CAPITAL LETTER X + 0xA2E7: 0xFF39, //FULLWIDTH LATIN CAPITAL LETTER Y + 0xA2E8: 0xFF3A, //FULLWIDTH LATIN CAPITAL LETTER Z + 0xA2E9: 0xFF41, //FULLWIDTH LATIN SMALL LETTER A + 0xA2EA: 0xFF42, //FULLWIDTH LATIN SMALL LETTER B + 0xA2EB: 0xFF43, //FULLWIDTH LATIN SMALL LETTER C + 0xA2EC: 0xFF44, //FULLWIDTH LATIN SMALL LETTER D + 0xA2ED: 0xFF45, //FULLWIDTH LATIN SMALL LETTER E + 0xA2EE: 0xFF46, //FULLWIDTH LATIN SMALL LETTER F + 0xA2EF: 0xFF47, //FULLWIDTH LATIN SMALL LETTER G + 0xA2F0: 0xFF48, //FULLWIDTH LATIN SMALL LETTER H + 0xA2F1: 0xFF49, //FULLWIDTH LATIN SMALL LETTER I + 0xA2F2: 0xFF4A, //FULLWIDTH LATIN SMALL LETTER J + 0xA2F3: 0xFF4B, //FULLWIDTH LATIN SMALL LETTER K + 0xA2F4: 0xFF4C, //FULLWIDTH LATIN SMALL LETTER L + 0xA2F5: 0xFF4D, //FULLWIDTH LATIN SMALL LETTER M + 0xA2F6: 0xFF4E, //FULLWIDTH LATIN SMALL LETTER N + 0xA2F7: 0xFF4F, //FULLWIDTH LATIN SMALL LETTER O + 0xA2F8: 0xFF50, //FULLWIDTH LATIN SMALL LETTER P + 0xA2F9: 0xFF51, //FULLWIDTH LATIN SMALL LETTER Q + 0xA2FA: 0xFF52, //FULLWIDTH LATIN SMALL LETTER R + 0xA2FB: 0xFF53, //FULLWIDTH LATIN SMALL LETTER S + 0xA2FC: 0xFF54, //FULLWIDTH LATIN SMALL LETTER T + 0xA2FD: 0xFF55, //FULLWIDTH LATIN SMALL LETTER U + 0xA2FE: 0xFF56, //FULLWIDTH LATIN SMALL LETTER V + 0xA340: 0xFF57, //FULLWIDTH LATIN SMALL LETTER W + 0xA341: 0xFF58, //FULLWIDTH LATIN SMALL LETTER X + 0xA342: 0xFF59, //FULLWIDTH LATIN SMALL LETTER Y + 0xA343: 0xFF5A, //FULLWIDTH LATIN SMALL LETTER Z + 0xA344: 0x0391, //GREEK CAPITAL LETTER ALPHA + 0xA345: 0x0392, //GREEK CAPITAL LETTER BETA + 0xA346: 0x0393, //GREEK CAPITAL LETTER GAMMA + 0xA347: 0x0394, //GREEK CAPITAL LETTER DELTA + 0xA348: 0x0395, //GREEK CAPITAL LETTER EPSILON + 0xA349: 0x0396, //GREEK CAPITAL LETTER ZETA + 0xA34A: 0x0397, //GREEK CAPITAL LETTER ETA + 0xA34B: 0x0398, //GREEK CAPITAL LETTER THETA + 0xA34C: 0x0399, //GREEK CAPITAL LETTER IOTA + 0xA34D: 0x039A, //GREEK CAPITAL LETTER KAPPA + 0xA34E: 0x039B, //GREEK CAPITAL LETTER LAMDA + 0xA34F: 0x039C, //GREEK CAPITAL LETTER MU + 0xA350: 0x039D, //GREEK CAPITAL LETTER NU + 0xA351: 0x039E, //GREEK CAPITAL LETTER XI + 0xA352: 0x039F, //GREEK CAPITAL LETTER OMICRON + 0xA353: 0x03A0, //GREEK CAPITAL LETTER PI + 0xA354: 0x03A1, //GREEK CAPITAL LETTER RHO + 0xA355: 0x03A3, //GREEK CAPITAL LETTER SIGMA + 0xA356: 0x03A4, //GREEK CAPITAL LETTER TAU + 0xA357: 0x03A5, //GREEK CAPITAL LETTER UPSILON + 0xA358: 0x03A6, //GREEK CAPITAL LETTER PHI + 0xA359: 0x03A7, //GREEK CAPITAL LETTER CHI + 0xA35A: 0x03A8, //GREEK CAPITAL LETTER PSI + 0xA35B: 0x03A9, //GREEK CAPITAL LETTER OMEGA + 0xA35C: 0x03B1, //GREEK SMALL LETTER ALPHA + 0xA35D: 0x03B2, //GREEK SMALL LETTER BETA + 0xA35E: 0x03B3, //GREEK SMALL LETTER GAMMA + 0xA35F: 0x03B4, //GREEK SMALL LETTER DELTA + 0xA360: 0x03B5, //GREEK SMALL LETTER EPSILON + 0xA361: 0x03B6, //GREEK SMALL LETTER ZETA + 0xA362: 0x03B7, //GREEK SMALL LETTER ETA + 0xA363: 0x03B8, //GREEK SMALL LETTER THETA + 0xA364: 0x03B9, //GREEK SMALL LETTER IOTA + 0xA365: 0x03BA, //GREEK SMALL LETTER KAPPA + 0xA366: 0x03BB, //GREEK SMALL LETTER LAMDA + 0xA367: 0x03BC, //GREEK SMALL LETTER MU + 0xA368: 0x03BD, //GREEK SMALL LETTER NU + 0xA369: 0x03BE, //GREEK SMALL LETTER XI + 0xA36A: 0x03BF, //GREEK SMALL LETTER OMICRON + 0xA36B: 0x03C0, //GREEK SMALL LETTER PI + 0xA36C: 0x03C1, //GREEK SMALL LETTER RHO + 0xA36D: 0x03C3, //GREEK SMALL LETTER SIGMA + 0xA36E: 0x03C4, //GREEK SMALL LETTER TAU + 0xA36F: 0x03C5, //GREEK SMALL LETTER UPSILON + 0xA370: 0x03C6, //GREEK SMALL LETTER PHI + 0xA371: 0x03C7, //GREEK SMALL LETTER CHI + 0xA372: 0x03C8, //GREEK SMALL LETTER PSI + 0xA373: 0x03C9, //GREEK SMALL LETTER OMEGA + 0xA374: 0x3105, //BOPOMOFO LETTER B + 0xA375: 0x3106, //BOPOMOFO LETTER P + 0xA376: 0x3107, //BOPOMOFO LETTER M + 0xA377: 0x3108, //BOPOMOFO LETTER F + 0xA378: 0x3109, //BOPOMOFO LETTER D + 0xA379: 0x310A, //BOPOMOFO LETTER T + 0xA37A: 0x310B, //BOPOMOFO LETTER N + 0xA37B: 0x310C, //BOPOMOFO LETTER L + 0xA37C: 0x310D, //BOPOMOFO LETTER G + 0xA37D: 0x310E, //BOPOMOFO LETTER K + 0xA37E: 0x310F, //BOPOMOFO LETTER H + 0xA3A1: 0x3110, //BOPOMOFO LETTER J + 0xA3A2: 0x3111, //BOPOMOFO LETTER Q + 0xA3A3: 0x3112, //BOPOMOFO LETTER X + 0xA3A4: 0x3113, //BOPOMOFO LETTER ZH + 0xA3A5: 0x3114, //BOPOMOFO LETTER CH + 0xA3A6: 0x3115, //BOPOMOFO LETTER SH + 0xA3A7: 0x3116, //BOPOMOFO LETTER R + 0xA3A8: 0x3117, //BOPOMOFO LETTER Z + 0xA3A9: 0x3118, //BOPOMOFO LETTER C + 0xA3AA: 0x3119, //BOPOMOFO LETTER S + 0xA3AB: 0x311A, //BOPOMOFO LETTER A + 0xA3AC: 0x311B, //BOPOMOFO LETTER O + 0xA3AD: 0x311C, //BOPOMOFO LETTER E + 0xA3AE: 0x311D, //BOPOMOFO LETTER EH + 0xA3AF: 0x311E, //BOPOMOFO LETTER AI + 0xA3B0: 0x311F, //BOPOMOFO LETTER EI + 0xA3B1: 0x3120, //BOPOMOFO LETTER AU + 0xA3B2: 0x3121, //BOPOMOFO LETTER OU + 0xA3B3: 0x3122, //BOPOMOFO LETTER AN + 0xA3B4: 0x3123, //BOPOMOFO LETTER EN + 0xA3B5: 0x3124, //BOPOMOFO LETTER ANG + 0xA3B6: 0x3125, //BOPOMOFO LETTER ENG + 0xA3B7: 0x3126, //BOPOMOFO LETTER ER + 0xA3B8: 0x3127, //BOPOMOFO LETTER I + 0xA3B9: 0x3128, //BOPOMOFO LETTER U + 0xA3BA: 0x3129, //BOPOMOFO LETTER IU + 0xA3BB: 0x02D9, //DOT ABOVE + 0xA3BC: 0x02C9, //MODIFIER LETTER MACRON + 0xA3BD: 0x02CA, //MODIFIER LETTER ACUTE ACCENT + 0xA3BE: 0x02C7, //CARON + 0xA3BF: 0x02CB, //MODIFIER LETTER GRAVE ACCENT + 0xA3E1: 0x20AC, //EURO SIGN + 0xA440: 0x4E00, //CJK UNIFIED IDEOGRAPH + 0xA441: 0x4E59, //CJK UNIFIED IDEOGRAPH + 0xA442: 0x4E01, //CJK UNIFIED IDEOGRAPH + 0xA443: 0x4E03, //CJK UNIFIED IDEOGRAPH + 0xA444: 0x4E43, //CJK UNIFIED IDEOGRAPH + 0xA445: 0x4E5D, //CJK UNIFIED IDEOGRAPH + 0xA446: 0x4E86, //CJK UNIFIED IDEOGRAPH + 0xA447: 0x4E8C, //CJK UNIFIED IDEOGRAPH + 0xA448: 0x4EBA, //CJK UNIFIED IDEOGRAPH + 0xA449: 0x513F, //CJK UNIFIED IDEOGRAPH + 0xA44A: 0x5165, //CJK UNIFIED IDEOGRAPH + 0xA44B: 0x516B, //CJK UNIFIED IDEOGRAPH + 0xA44C: 0x51E0, //CJK UNIFIED IDEOGRAPH + 0xA44D: 0x5200, //CJK UNIFIED IDEOGRAPH + 0xA44E: 0x5201, //CJK UNIFIED IDEOGRAPH + 0xA44F: 0x529B, //CJK UNIFIED IDEOGRAPH + 0xA450: 0x5315, //CJK UNIFIED IDEOGRAPH + 0xA451: 0x5341, //CJK UNIFIED IDEOGRAPH + 0xA452: 0x535C, //CJK UNIFIED IDEOGRAPH + 0xA453: 0x53C8, //CJK UNIFIED IDEOGRAPH + 0xA454: 0x4E09, //CJK UNIFIED IDEOGRAPH + 0xA455: 0x4E0B, //CJK UNIFIED IDEOGRAPH + 0xA456: 0x4E08, //CJK UNIFIED IDEOGRAPH + 0xA457: 0x4E0A, //CJK UNIFIED IDEOGRAPH + 0xA458: 0x4E2B, //CJK UNIFIED IDEOGRAPH + 0xA459: 0x4E38, //CJK UNIFIED IDEOGRAPH + 0xA45A: 0x51E1, //CJK UNIFIED IDEOGRAPH + 0xA45B: 0x4E45, //CJK UNIFIED IDEOGRAPH + 0xA45C: 0x4E48, //CJK UNIFIED IDEOGRAPH + 0xA45D: 0x4E5F, //CJK UNIFIED IDEOGRAPH + 0xA45E: 0x4E5E, //CJK UNIFIED IDEOGRAPH + 0xA45F: 0x4E8E, //CJK UNIFIED IDEOGRAPH + 0xA460: 0x4EA1, //CJK UNIFIED IDEOGRAPH + 0xA461: 0x5140, //CJK UNIFIED IDEOGRAPH + 0xA462: 0x5203, //CJK UNIFIED IDEOGRAPH + 0xA463: 0x52FA, //CJK UNIFIED IDEOGRAPH + 0xA464: 0x5343, //CJK UNIFIED IDEOGRAPH + 0xA465: 0x53C9, //CJK UNIFIED IDEOGRAPH + 0xA466: 0x53E3, //CJK UNIFIED IDEOGRAPH + 0xA467: 0x571F, //CJK UNIFIED IDEOGRAPH + 0xA468: 0x58EB, //CJK UNIFIED IDEOGRAPH + 0xA469: 0x5915, //CJK UNIFIED IDEOGRAPH + 0xA46A: 0x5927, //CJK UNIFIED IDEOGRAPH + 0xA46B: 0x5973, //CJK UNIFIED IDEOGRAPH + 0xA46C: 0x5B50, //CJK UNIFIED IDEOGRAPH + 0xA46D: 0x5B51, //CJK UNIFIED IDEOGRAPH + 0xA46E: 0x5B53, //CJK UNIFIED IDEOGRAPH + 0xA46F: 0x5BF8, //CJK UNIFIED IDEOGRAPH + 0xA470: 0x5C0F, //CJK UNIFIED IDEOGRAPH + 0xA471: 0x5C22, //CJK UNIFIED IDEOGRAPH + 0xA472: 0x5C38, //CJK UNIFIED IDEOGRAPH + 0xA473: 0x5C71, //CJK UNIFIED IDEOGRAPH + 0xA474: 0x5DDD, //CJK UNIFIED IDEOGRAPH + 0xA475: 0x5DE5, //CJK UNIFIED IDEOGRAPH + 0xA476: 0x5DF1, //CJK UNIFIED IDEOGRAPH + 0xA477: 0x5DF2, //CJK UNIFIED IDEOGRAPH + 0xA478: 0x5DF3, //CJK UNIFIED IDEOGRAPH + 0xA479: 0x5DFE, //CJK UNIFIED IDEOGRAPH + 0xA47A: 0x5E72, //CJK UNIFIED IDEOGRAPH + 0xA47B: 0x5EFE, //CJK UNIFIED IDEOGRAPH + 0xA47C: 0x5F0B, //CJK UNIFIED IDEOGRAPH + 0xA47D: 0x5F13, //CJK UNIFIED IDEOGRAPH + 0xA47E: 0x624D, //CJK UNIFIED IDEOGRAPH + 0xA4A1: 0x4E11, //CJK UNIFIED IDEOGRAPH + 0xA4A2: 0x4E10, //CJK UNIFIED IDEOGRAPH + 0xA4A3: 0x4E0D, //CJK UNIFIED IDEOGRAPH + 0xA4A4: 0x4E2D, //CJK UNIFIED IDEOGRAPH + 0xA4A5: 0x4E30, //CJK UNIFIED IDEOGRAPH + 0xA4A6: 0x4E39, //CJK UNIFIED IDEOGRAPH + 0xA4A7: 0x4E4B, //CJK UNIFIED IDEOGRAPH + 0xA4A8: 0x5C39, //CJK UNIFIED IDEOGRAPH + 0xA4A9: 0x4E88, //CJK UNIFIED IDEOGRAPH + 0xA4AA: 0x4E91, //CJK UNIFIED IDEOGRAPH + 0xA4AB: 0x4E95, //CJK UNIFIED IDEOGRAPH + 0xA4AC: 0x4E92, //CJK UNIFIED IDEOGRAPH + 0xA4AD: 0x4E94, //CJK UNIFIED IDEOGRAPH + 0xA4AE: 0x4EA2, //CJK UNIFIED IDEOGRAPH + 0xA4AF: 0x4EC1, //CJK UNIFIED IDEOGRAPH + 0xA4B0: 0x4EC0, //CJK UNIFIED IDEOGRAPH + 0xA4B1: 0x4EC3, //CJK UNIFIED IDEOGRAPH + 0xA4B2: 0x4EC6, //CJK UNIFIED IDEOGRAPH + 0xA4B3: 0x4EC7, //CJK UNIFIED IDEOGRAPH + 0xA4B4: 0x4ECD, //CJK UNIFIED IDEOGRAPH + 0xA4B5: 0x4ECA, //CJK UNIFIED IDEOGRAPH + 0xA4B6: 0x4ECB, //CJK UNIFIED IDEOGRAPH + 0xA4B7: 0x4EC4, //CJK UNIFIED IDEOGRAPH + 0xA4B8: 0x5143, //CJK UNIFIED IDEOGRAPH + 0xA4B9: 0x5141, //CJK UNIFIED IDEOGRAPH + 0xA4BA: 0x5167, //CJK UNIFIED IDEOGRAPH + 0xA4BB: 0x516D, //CJK UNIFIED IDEOGRAPH + 0xA4BC: 0x516E, //CJK UNIFIED IDEOGRAPH + 0xA4BD: 0x516C, //CJK UNIFIED IDEOGRAPH + 0xA4BE: 0x5197, //CJK UNIFIED IDEOGRAPH + 0xA4BF: 0x51F6, //CJK UNIFIED IDEOGRAPH + 0xA4C0: 0x5206, //CJK UNIFIED IDEOGRAPH + 0xA4C1: 0x5207, //CJK UNIFIED IDEOGRAPH + 0xA4C2: 0x5208, //CJK UNIFIED IDEOGRAPH + 0xA4C3: 0x52FB, //CJK UNIFIED IDEOGRAPH + 0xA4C4: 0x52FE, //CJK UNIFIED IDEOGRAPH + 0xA4C5: 0x52FF, //CJK UNIFIED IDEOGRAPH + 0xA4C6: 0x5316, //CJK UNIFIED IDEOGRAPH + 0xA4C7: 0x5339, //CJK UNIFIED IDEOGRAPH + 0xA4C8: 0x5348, //CJK UNIFIED IDEOGRAPH + 0xA4C9: 0x5347, //CJK UNIFIED IDEOGRAPH + 0xA4CA: 0x5345, //CJK UNIFIED IDEOGRAPH + 0xA4CB: 0x535E, //CJK UNIFIED IDEOGRAPH + 0xA4CC: 0x5384, //CJK UNIFIED IDEOGRAPH + 0xA4CD: 0x53CB, //CJK UNIFIED IDEOGRAPH + 0xA4CE: 0x53CA, //CJK UNIFIED IDEOGRAPH + 0xA4CF: 0x53CD, //CJK UNIFIED IDEOGRAPH + 0xA4D0: 0x58EC, //CJK UNIFIED IDEOGRAPH + 0xA4D1: 0x5929, //CJK UNIFIED IDEOGRAPH + 0xA4D2: 0x592B, //CJK UNIFIED IDEOGRAPH + 0xA4D3: 0x592A, //CJK UNIFIED IDEOGRAPH + 0xA4D4: 0x592D, //CJK UNIFIED IDEOGRAPH + 0xA4D5: 0x5B54, //CJK UNIFIED IDEOGRAPH + 0xA4D6: 0x5C11, //CJK UNIFIED IDEOGRAPH + 0xA4D7: 0x5C24, //CJK UNIFIED IDEOGRAPH + 0xA4D8: 0x5C3A, //CJK UNIFIED IDEOGRAPH + 0xA4D9: 0x5C6F, //CJK UNIFIED IDEOGRAPH + 0xA4DA: 0x5DF4, //CJK UNIFIED IDEOGRAPH + 0xA4DB: 0x5E7B, //CJK UNIFIED IDEOGRAPH + 0xA4DC: 0x5EFF, //CJK UNIFIED IDEOGRAPH + 0xA4DD: 0x5F14, //CJK UNIFIED IDEOGRAPH + 0xA4DE: 0x5F15, //CJK UNIFIED IDEOGRAPH + 0xA4DF: 0x5FC3, //CJK UNIFIED IDEOGRAPH + 0xA4E0: 0x6208, //CJK UNIFIED IDEOGRAPH + 0xA4E1: 0x6236, //CJK UNIFIED IDEOGRAPH + 0xA4E2: 0x624B, //CJK UNIFIED IDEOGRAPH + 0xA4E3: 0x624E, //CJK UNIFIED IDEOGRAPH + 0xA4E4: 0x652F, //CJK UNIFIED IDEOGRAPH + 0xA4E5: 0x6587, //CJK UNIFIED IDEOGRAPH + 0xA4E6: 0x6597, //CJK UNIFIED IDEOGRAPH + 0xA4E7: 0x65A4, //CJK UNIFIED IDEOGRAPH + 0xA4E8: 0x65B9, //CJK UNIFIED IDEOGRAPH + 0xA4E9: 0x65E5, //CJK UNIFIED IDEOGRAPH + 0xA4EA: 0x66F0, //CJK UNIFIED IDEOGRAPH + 0xA4EB: 0x6708, //CJK UNIFIED IDEOGRAPH + 0xA4EC: 0x6728, //CJK UNIFIED IDEOGRAPH + 0xA4ED: 0x6B20, //CJK UNIFIED IDEOGRAPH + 0xA4EE: 0x6B62, //CJK UNIFIED IDEOGRAPH + 0xA4EF: 0x6B79, //CJK UNIFIED IDEOGRAPH + 0xA4F0: 0x6BCB, //CJK UNIFIED IDEOGRAPH + 0xA4F1: 0x6BD4, //CJK UNIFIED IDEOGRAPH + 0xA4F2: 0x6BDB, //CJK UNIFIED IDEOGRAPH + 0xA4F3: 0x6C0F, //CJK UNIFIED IDEOGRAPH + 0xA4F4: 0x6C34, //CJK UNIFIED IDEOGRAPH + 0xA4F5: 0x706B, //CJK UNIFIED IDEOGRAPH + 0xA4F6: 0x722A, //CJK UNIFIED IDEOGRAPH + 0xA4F7: 0x7236, //CJK UNIFIED IDEOGRAPH + 0xA4F8: 0x723B, //CJK UNIFIED IDEOGRAPH + 0xA4F9: 0x7247, //CJK UNIFIED IDEOGRAPH + 0xA4FA: 0x7259, //CJK UNIFIED IDEOGRAPH + 0xA4FB: 0x725B, //CJK UNIFIED IDEOGRAPH + 0xA4FC: 0x72AC, //CJK UNIFIED IDEOGRAPH + 0xA4FD: 0x738B, //CJK UNIFIED IDEOGRAPH + 0xA4FE: 0x4E19, //CJK UNIFIED IDEOGRAPH + 0xA540: 0x4E16, //CJK UNIFIED IDEOGRAPH + 0xA541: 0x4E15, //CJK UNIFIED IDEOGRAPH + 0xA542: 0x4E14, //CJK UNIFIED IDEOGRAPH + 0xA543: 0x4E18, //CJK UNIFIED IDEOGRAPH + 0xA544: 0x4E3B, //CJK UNIFIED IDEOGRAPH + 0xA545: 0x4E4D, //CJK UNIFIED IDEOGRAPH + 0xA546: 0x4E4F, //CJK UNIFIED IDEOGRAPH + 0xA547: 0x4E4E, //CJK UNIFIED IDEOGRAPH + 0xA548: 0x4EE5, //CJK UNIFIED IDEOGRAPH + 0xA549: 0x4ED8, //CJK UNIFIED IDEOGRAPH + 0xA54A: 0x4ED4, //CJK UNIFIED IDEOGRAPH + 0xA54B: 0x4ED5, //CJK UNIFIED IDEOGRAPH + 0xA54C: 0x4ED6, //CJK UNIFIED IDEOGRAPH + 0xA54D: 0x4ED7, //CJK UNIFIED IDEOGRAPH + 0xA54E: 0x4EE3, //CJK UNIFIED IDEOGRAPH + 0xA54F: 0x4EE4, //CJK UNIFIED IDEOGRAPH + 0xA550: 0x4ED9, //CJK UNIFIED IDEOGRAPH + 0xA551: 0x4EDE, //CJK UNIFIED IDEOGRAPH + 0xA552: 0x5145, //CJK UNIFIED IDEOGRAPH + 0xA553: 0x5144, //CJK UNIFIED IDEOGRAPH + 0xA554: 0x5189, //CJK UNIFIED IDEOGRAPH + 0xA555: 0x518A, //CJK UNIFIED IDEOGRAPH + 0xA556: 0x51AC, //CJK UNIFIED IDEOGRAPH + 0xA557: 0x51F9, //CJK UNIFIED IDEOGRAPH + 0xA558: 0x51FA, //CJK UNIFIED IDEOGRAPH + 0xA559: 0x51F8, //CJK UNIFIED IDEOGRAPH + 0xA55A: 0x520A, //CJK UNIFIED IDEOGRAPH + 0xA55B: 0x52A0, //CJK UNIFIED IDEOGRAPH + 0xA55C: 0x529F, //CJK UNIFIED IDEOGRAPH + 0xA55D: 0x5305, //CJK UNIFIED IDEOGRAPH + 0xA55E: 0x5306, //CJK UNIFIED IDEOGRAPH + 0xA55F: 0x5317, //CJK UNIFIED IDEOGRAPH + 0xA560: 0x531D, //CJK UNIFIED IDEOGRAPH + 0xA561: 0x4EDF, //CJK UNIFIED IDEOGRAPH + 0xA562: 0x534A, //CJK UNIFIED IDEOGRAPH + 0xA563: 0x5349, //CJK UNIFIED IDEOGRAPH + 0xA564: 0x5361, //CJK UNIFIED IDEOGRAPH + 0xA565: 0x5360, //CJK UNIFIED IDEOGRAPH + 0xA566: 0x536F, //CJK UNIFIED IDEOGRAPH + 0xA567: 0x536E, //CJK UNIFIED IDEOGRAPH + 0xA568: 0x53BB, //CJK UNIFIED IDEOGRAPH + 0xA569: 0x53EF, //CJK UNIFIED IDEOGRAPH + 0xA56A: 0x53E4, //CJK UNIFIED IDEOGRAPH + 0xA56B: 0x53F3, //CJK UNIFIED IDEOGRAPH + 0xA56C: 0x53EC, //CJK UNIFIED IDEOGRAPH + 0xA56D: 0x53EE, //CJK UNIFIED IDEOGRAPH + 0xA56E: 0x53E9, //CJK UNIFIED IDEOGRAPH + 0xA56F: 0x53E8, //CJK UNIFIED IDEOGRAPH + 0xA570: 0x53FC, //CJK UNIFIED IDEOGRAPH + 0xA571: 0x53F8, //CJK UNIFIED IDEOGRAPH + 0xA572: 0x53F5, //CJK UNIFIED IDEOGRAPH + 0xA573: 0x53EB, //CJK UNIFIED IDEOGRAPH + 0xA574: 0x53E6, //CJK UNIFIED IDEOGRAPH + 0xA575: 0x53EA, //CJK UNIFIED IDEOGRAPH + 0xA576: 0x53F2, //CJK UNIFIED IDEOGRAPH + 0xA577: 0x53F1, //CJK UNIFIED IDEOGRAPH + 0xA578: 0x53F0, //CJK UNIFIED IDEOGRAPH + 0xA579: 0x53E5, //CJK UNIFIED IDEOGRAPH + 0xA57A: 0x53ED, //CJK UNIFIED IDEOGRAPH + 0xA57B: 0x53FB, //CJK UNIFIED IDEOGRAPH + 0xA57C: 0x56DB, //CJK UNIFIED IDEOGRAPH + 0xA57D: 0x56DA, //CJK UNIFIED IDEOGRAPH + 0xA57E: 0x5916, //CJK UNIFIED IDEOGRAPH + 0xA5A1: 0x592E, //CJK UNIFIED IDEOGRAPH + 0xA5A2: 0x5931, //CJK UNIFIED IDEOGRAPH + 0xA5A3: 0x5974, //CJK UNIFIED IDEOGRAPH + 0xA5A4: 0x5976, //CJK UNIFIED IDEOGRAPH + 0xA5A5: 0x5B55, //CJK UNIFIED IDEOGRAPH + 0xA5A6: 0x5B83, //CJK UNIFIED IDEOGRAPH + 0xA5A7: 0x5C3C, //CJK UNIFIED IDEOGRAPH + 0xA5A8: 0x5DE8, //CJK UNIFIED IDEOGRAPH + 0xA5A9: 0x5DE7, //CJK UNIFIED IDEOGRAPH + 0xA5AA: 0x5DE6, //CJK UNIFIED IDEOGRAPH + 0xA5AB: 0x5E02, //CJK UNIFIED IDEOGRAPH + 0xA5AC: 0x5E03, //CJK UNIFIED IDEOGRAPH + 0xA5AD: 0x5E73, //CJK UNIFIED IDEOGRAPH + 0xA5AE: 0x5E7C, //CJK UNIFIED IDEOGRAPH + 0xA5AF: 0x5F01, //CJK UNIFIED IDEOGRAPH + 0xA5B0: 0x5F18, //CJK UNIFIED IDEOGRAPH + 0xA5B1: 0x5F17, //CJK UNIFIED IDEOGRAPH + 0xA5B2: 0x5FC5, //CJK UNIFIED IDEOGRAPH + 0xA5B3: 0x620A, //CJK UNIFIED IDEOGRAPH + 0xA5B4: 0x6253, //CJK UNIFIED IDEOGRAPH + 0xA5B5: 0x6254, //CJK UNIFIED IDEOGRAPH + 0xA5B6: 0x6252, //CJK UNIFIED IDEOGRAPH + 0xA5B7: 0x6251, //CJK UNIFIED IDEOGRAPH + 0xA5B8: 0x65A5, //CJK UNIFIED IDEOGRAPH + 0xA5B9: 0x65E6, //CJK UNIFIED IDEOGRAPH + 0xA5BA: 0x672E, //CJK UNIFIED IDEOGRAPH + 0xA5BB: 0x672C, //CJK UNIFIED IDEOGRAPH + 0xA5BC: 0x672A, //CJK UNIFIED IDEOGRAPH + 0xA5BD: 0x672B, //CJK UNIFIED IDEOGRAPH + 0xA5BE: 0x672D, //CJK UNIFIED IDEOGRAPH + 0xA5BF: 0x6B63, //CJK UNIFIED IDEOGRAPH + 0xA5C0: 0x6BCD, //CJK UNIFIED IDEOGRAPH + 0xA5C1: 0x6C11, //CJK UNIFIED IDEOGRAPH + 0xA5C2: 0x6C10, //CJK UNIFIED IDEOGRAPH + 0xA5C3: 0x6C38, //CJK UNIFIED IDEOGRAPH + 0xA5C4: 0x6C41, //CJK UNIFIED IDEOGRAPH + 0xA5C5: 0x6C40, //CJK UNIFIED IDEOGRAPH + 0xA5C6: 0x6C3E, //CJK UNIFIED IDEOGRAPH + 0xA5C7: 0x72AF, //CJK UNIFIED IDEOGRAPH + 0xA5C8: 0x7384, //CJK UNIFIED IDEOGRAPH + 0xA5C9: 0x7389, //CJK UNIFIED IDEOGRAPH + 0xA5CA: 0x74DC, //CJK UNIFIED IDEOGRAPH + 0xA5CB: 0x74E6, //CJK UNIFIED IDEOGRAPH + 0xA5CC: 0x7518, //CJK UNIFIED IDEOGRAPH + 0xA5CD: 0x751F, //CJK UNIFIED IDEOGRAPH + 0xA5CE: 0x7528, //CJK UNIFIED IDEOGRAPH + 0xA5CF: 0x7529, //CJK UNIFIED IDEOGRAPH + 0xA5D0: 0x7530, //CJK UNIFIED IDEOGRAPH + 0xA5D1: 0x7531, //CJK UNIFIED IDEOGRAPH + 0xA5D2: 0x7532, //CJK UNIFIED IDEOGRAPH + 0xA5D3: 0x7533, //CJK UNIFIED IDEOGRAPH + 0xA5D4: 0x758B, //CJK UNIFIED IDEOGRAPH + 0xA5D5: 0x767D, //CJK UNIFIED IDEOGRAPH + 0xA5D6: 0x76AE, //CJK UNIFIED IDEOGRAPH + 0xA5D7: 0x76BF, //CJK UNIFIED IDEOGRAPH + 0xA5D8: 0x76EE, //CJK UNIFIED IDEOGRAPH + 0xA5D9: 0x77DB, //CJK UNIFIED IDEOGRAPH + 0xA5DA: 0x77E2, //CJK UNIFIED IDEOGRAPH + 0xA5DB: 0x77F3, //CJK UNIFIED IDEOGRAPH + 0xA5DC: 0x793A, //CJK UNIFIED IDEOGRAPH + 0xA5DD: 0x79BE, //CJK UNIFIED IDEOGRAPH + 0xA5DE: 0x7A74, //CJK UNIFIED IDEOGRAPH + 0xA5DF: 0x7ACB, //CJK UNIFIED IDEOGRAPH + 0xA5E0: 0x4E1E, //CJK UNIFIED IDEOGRAPH + 0xA5E1: 0x4E1F, //CJK UNIFIED IDEOGRAPH + 0xA5E2: 0x4E52, //CJK UNIFIED IDEOGRAPH + 0xA5E3: 0x4E53, //CJK UNIFIED IDEOGRAPH + 0xA5E4: 0x4E69, //CJK UNIFIED IDEOGRAPH + 0xA5E5: 0x4E99, //CJK UNIFIED IDEOGRAPH + 0xA5E6: 0x4EA4, //CJK UNIFIED IDEOGRAPH + 0xA5E7: 0x4EA6, //CJK UNIFIED IDEOGRAPH + 0xA5E8: 0x4EA5, //CJK UNIFIED IDEOGRAPH + 0xA5E9: 0x4EFF, //CJK UNIFIED IDEOGRAPH + 0xA5EA: 0x4F09, //CJK UNIFIED IDEOGRAPH + 0xA5EB: 0x4F19, //CJK UNIFIED IDEOGRAPH + 0xA5EC: 0x4F0A, //CJK UNIFIED IDEOGRAPH + 0xA5ED: 0x4F15, //CJK UNIFIED IDEOGRAPH + 0xA5EE: 0x4F0D, //CJK UNIFIED IDEOGRAPH + 0xA5EF: 0x4F10, //CJK UNIFIED IDEOGRAPH + 0xA5F0: 0x4F11, //CJK UNIFIED IDEOGRAPH + 0xA5F1: 0x4F0F, //CJK UNIFIED IDEOGRAPH + 0xA5F2: 0x4EF2, //CJK UNIFIED IDEOGRAPH + 0xA5F3: 0x4EF6, //CJK UNIFIED IDEOGRAPH + 0xA5F4: 0x4EFB, //CJK UNIFIED IDEOGRAPH + 0xA5F5: 0x4EF0, //CJK UNIFIED IDEOGRAPH + 0xA5F6: 0x4EF3, //CJK UNIFIED IDEOGRAPH + 0xA5F7: 0x4EFD, //CJK UNIFIED IDEOGRAPH + 0xA5F8: 0x4F01, //CJK UNIFIED IDEOGRAPH + 0xA5F9: 0x4F0B, //CJK UNIFIED IDEOGRAPH + 0xA5FA: 0x5149, //CJK UNIFIED IDEOGRAPH + 0xA5FB: 0x5147, //CJK UNIFIED IDEOGRAPH + 0xA5FC: 0x5146, //CJK UNIFIED IDEOGRAPH + 0xA5FD: 0x5148, //CJK UNIFIED IDEOGRAPH + 0xA5FE: 0x5168, //CJK UNIFIED IDEOGRAPH + 0xA640: 0x5171, //CJK UNIFIED IDEOGRAPH + 0xA641: 0x518D, //CJK UNIFIED IDEOGRAPH + 0xA642: 0x51B0, //CJK UNIFIED IDEOGRAPH + 0xA643: 0x5217, //CJK UNIFIED IDEOGRAPH + 0xA644: 0x5211, //CJK UNIFIED IDEOGRAPH + 0xA645: 0x5212, //CJK UNIFIED IDEOGRAPH + 0xA646: 0x520E, //CJK UNIFIED IDEOGRAPH + 0xA647: 0x5216, //CJK UNIFIED IDEOGRAPH + 0xA648: 0x52A3, //CJK UNIFIED IDEOGRAPH + 0xA649: 0x5308, //CJK UNIFIED IDEOGRAPH + 0xA64A: 0x5321, //CJK UNIFIED IDEOGRAPH + 0xA64B: 0x5320, //CJK UNIFIED IDEOGRAPH + 0xA64C: 0x5370, //CJK UNIFIED IDEOGRAPH + 0xA64D: 0x5371, //CJK UNIFIED IDEOGRAPH + 0xA64E: 0x5409, //CJK UNIFIED IDEOGRAPH + 0xA64F: 0x540F, //CJK UNIFIED IDEOGRAPH + 0xA650: 0x540C, //CJK UNIFIED IDEOGRAPH + 0xA651: 0x540A, //CJK UNIFIED IDEOGRAPH + 0xA652: 0x5410, //CJK UNIFIED IDEOGRAPH + 0xA653: 0x5401, //CJK UNIFIED IDEOGRAPH + 0xA654: 0x540B, //CJK UNIFIED IDEOGRAPH + 0xA655: 0x5404, //CJK UNIFIED IDEOGRAPH + 0xA656: 0x5411, //CJK UNIFIED IDEOGRAPH + 0xA657: 0x540D, //CJK UNIFIED IDEOGRAPH + 0xA658: 0x5408, //CJK UNIFIED IDEOGRAPH + 0xA659: 0x5403, //CJK UNIFIED IDEOGRAPH + 0xA65A: 0x540E, //CJK UNIFIED IDEOGRAPH + 0xA65B: 0x5406, //CJK UNIFIED IDEOGRAPH + 0xA65C: 0x5412, //CJK UNIFIED IDEOGRAPH + 0xA65D: 0x56E0, //CJK UNIFIED IDEOGRAPH + 0xA65E: 0x56DE, //CJK UNIFIED IDEOGRAPH + 0xA65F: 0x56DD, //CJK UNIFIED IDEOGRAPH + 0xA660: 0x5733, //CJK UNIFIED IDEOGRAPH + 0xA661: 0x5730, //CJK UNIFIED IDEOGRAPH + 0xA662: 0x5728, //CJK UNIFIED IDEOGRAPH + 0xA663: 0x572D, //CJK UNIFIED IDEOGRAPH + 0xA664: 0x572C, //CJK UNIFIED IDEOGRAPH + 0xA665: 0x572F, //CJK UNIFIED IDEOGRAPH + 0xA666: 0x5729, //CJK UNIFIED IDEOGRAPH + 0xA667: 0x5919, //CJK UNIFIED IDEOGRAPH + 0xA668: 0x591A, //CJK UNIFIED IDEOGRAPH + 0xA669: 0x5937, //CJK UNIFIED IDEOGRAPH + 0xA66A: 0x5938, //CJK UNIFIED IDEOGRAPH + 0xA66B: 0x5984, //CJK UNIFIED IDEOGRAPH + 0xA66C: 0x5978, //CJK UNIFIED IDEOGRAPH + 0xA66D: 0x5983, //CJK UNIFIED IDEOGRAPH + 0xA66E: 0x597D, //CJK UNIFIED IDEOGRAPH + 0xA66F: 0x5979, //CJK UNIFIED IDEOGRAPH + 0xA670: 0x5982, //CJK UNIFIED IDEOGRAPH + 0xA671: 0x5981, //CJK UNIFIED IDEOGRAPH + 0xA672: 0x5B57, //CJK UNIFIED IDEOGRAPH + 0xA673: 0x5B58, //CJK UNIFIED IDEOGRAPH + 0xA674: 0x5B87, //CJK UNIFIED IDEOGRAPH + 0xA675: 0x5B88, //CJK UNIFIED IDEOGRAPH + 0xA676: 0x5B85, //CJK UNIFIED IDEOGRAPH + 0xA677: 0x5B89, //CJK UNIFIED IDEOGRAPH + 0xA678: 0x5BFA, //CJK UNIFIED IDEOGRAPH + 0xA679: 0x5C16, //CJK UNIFIED IDEOGRAPH + 0xA67A: 0x5C79, //CJK UNIFIED IDEOGRAPH + 0xA67B: 0x5DDE, //CJK UNIFIED IDEOGRAPH + 0xA67C: 0x5E06, //CJK UNIFIED IDEOGRAPH + 0xA67D: 0x5E76, //CJK UNIFIED IDEOGRAPH + 0xA67E: 0x5E74, //CJK UNIFIED IDEOGRAPH + 0xA6A1: 0x5F0F, //CJK UNIFIED IDEOGRAPH + 0xA6A2: 0x5F1B, //CJK UNIFIED IDEOGRAPH + 0xA6A3: 0x5FD9, //CJK UNIFIED IDEOGRAPH + 0xA6A4: 0x5FD6, //CJK UNIFIED IDEOGRAPH + 0xA6A5: 0x620E, //CJK UNIFIED IDEOGRAPH + 0xA6A6: 0x620C, //CJK UNIFIED IDEOGRAPH + 0xA6A7: 0x620D, //CJK UNIFIED IDEOGRAPH + 0xA6A8: 0x6210, //CJK UNIFIED IDEOGRAPH + 0xA6A9: 0x6263, //CJK UNIFIED IDEOGRAPH + 0xA6AA: 0x625B, //CJK UNIFIED IDEOGRAPH + 0xA6AB: 0x6258, //CJK UNIFIED IDEOGRAPH + 0xA6AC: 0x6536, //CJK UNIFIED IDEOGRAPH + 0xA6AD: 0x65E9, //CJK UNIFIED IDEOGRAPH + 0xA6AE: 0x65E8, //CJK UNIFIED IDEOGRAPH + 0xA6AF: 0x65EC, //CJK UNIFIED IDEOGRAPH + 0xA6B0: 0x65ED, //CJK UNIFIED IDEOGRAPH + 0xA6B1: 0x66F2, //CJK UNIFIED IDEOGRAPH + 0xA6B2: 0x66F3, //CJK UNIFIED IDEOGRAPH + 0xA6B3: 0x6709, //CJK UNIFIED IDEOGRAPH + 0xA6B4: 0x673D, //CJK UNIFIED IDEOGRAPH + 0xA6B5: 0x6734, //CJK UNIFIED IDEOGRAPH + 0xA6B6: 0x6731, //CJK UNIFIED IDEOGRAPH + 0xA6B7: 0x6735, //CJK UNIFIED IDEOGRAPH + 0xA6B8: 0x6B21, //CJK UNIFIED IDEOGRAPH + 0xA6B9: 0x6B64, //CJK UNIFIED IDEOGRAPH + 0xA6BA: 0x6B7B, //CJK UNIFIED IDEOGRAPH + 0xA6BB: 0x6C16, //CJK UNIFIED IDEOGRAPH + 0xA6BC: 0x6C5D, //CJK UNIFIED IDEOGRAPH + 0xA6BD: 0x6C57, //CJK UNIFIED IDEOGRAPH + 0xA6BE: 0x6C59, //CJK UNIFIED IDEOGRAPH + 0xA6BF: 0x6C5F, //CJK UNIFIED IDEOGRAPH + 0xA6C0: 0x6C60, //CJK UNIFIED IDEOGRAPH + 0xA6C1: 0x6C50, //CJK UNIFIED IDEOGRAPH + 0xA6C2: 0x6C55, //CJK UNIFIED IDEOGRAPH + 0xA6C3: 0x6C61, //CJK UNIFIED IDEOGRAPH + 0xA6C4: 0x6C5B, //CJK UNIFIED IDEOGRAPH + 0xA6C5: 0x6C4D, //CJK UNIFIED IDEOGRAPH + 0xA6C6: 0x6C4E, //CJK UNIFIED IDEOGRAPH + 0xA6C7: 0x7070, //CJK UNIFIED IDEOGRAPH + 0xA6C8: 0x725F, //CJK UNIFIED IDEOGRAPH + 0xA6C9: 0x725D, //CJK UNIFIED IDEOGRAPH + 0xA6CA: 0x767E, //CJK UNIFIED IDEOGRAPH + 0xA6CB: 0x7AF9, //CJK UNIFIED IDEOGRAPH + 0xA6CC: 0x7C73, //CJK UNIFIED IDEOGRAPH + 0xA6CD: 0x7CF8, //CJK UNIFIED IDEOGRAPH + 0xA6CE: 0x7F36, //CJK UNIFIED IDEOGRAPH + 0xA6CF: 0x7F8A, //CJK UNIFIED IDEOGRAPH + 0xA6D0: 0x7FBD, //CJK UNIFIED IDEOGRAPH + 0xA6D1: 0x8001, //CJK UNIFIED IDEOGRAPH + 0xA6D2: 0x8003, //CJK UNIFIED IDEOGRAPH + 0xA6D3: 0x800C, //CJK UNIFIED IDEOGRAPH + 0xA6D4: 0x8012, //CJK UNIFIED IDEOGRAPH + 0xA6D5: 0x8033, //CJK UNIFIED IDEOGRAPH + 0xA6D6: 0x807F, //CJK UNIFIED IDEOGRAPH + 0xA6D7: 0x8089, //CJK UNIFIED IDEOGRAPH + 0xA6D8: 0x808B, //CJK UNIFIED IDEOGRAPH + 0xA6D9: 0x808C, //CJK UNIFIED IDEOGRAPH + 0xA6DA: 0x81E3, //CJK UNIFIED IDEOGRAPH + 0xA6DB: 0x81EA, //CJK UNIFIED IDEOGRAPH + 0xA6DC: 0x81F3, //CJK UNIFIED IDEOGRAPH + 0xA6DD: 0x81FC, //CJK UNIFIED IDEOGRAPH + 0xA6DE: 0x820C, //CJK UNIFIED IDEOGRAPH + 0xA6DF: 0x821B, //CJK UNIFIED IDEOGRAPH + 0xA6E0: 0x821F, //CJK UNIFIED IDEOGRAPH + 0xA6E1: 0x826E, //CJK UNIFIED IDEOGRAPH + 0xA6E2: 0x8272, //CJK UNIFIED IDEOGRAPH + 0xA6E3: 0x827E, //CJK UNIFIED IDEOGRAPH + 0xA6E4: 0x866B, //CJK UNIFIED IDEOGRAPH + 0xA6E5: 0x8840, //CJK UNIFIED IDEOGRAPH + 0xA6E6: 0x884C, //CJK UNIFIED IDEOGRAPH + 0xA6E7: 0x8863, //CJK UNIFIED IDEOGRAPH + 0xA6E8: 0x897F, //CJK UNIFIED IDEOGRAPH + 0xA6E9: 0x9621, //CJK UNIFIED IDEOGRAPH + 0xA6EA: 0x4E32, //CJK UNIFIED IDEOGRAPH + 0xA6EB: 0x4EA8, //CJK UNIFIED IDEOGRAPH + 0xA6EC: 0x4F4D, //CJK UNIFIED IDEOGRAPH + 0xA6ED: 0x4F4F, //CJK UNIFIED IDEOGRAPH + 0xA6EE: 0x4F47, //CJK UNIFIED IDEOGRAPH + 0xA6EF: 0x4F57, //CJK UNIFIED IDEOGRAPH + 0xA6F0: 0x4F5E, //CJK UNIFIED IDEOGRAPH + 0xA6F1: 0x4F34, //CJK UNIFIED IDEOGRAPH + 0xA6F2: 0x4F5B, //CJK UNIFIED IDEOGRAPH + 0xA6F3: 0x4F55, //CJK UNIFIED IDEOGRAPH + 0xA6F4: 0x4F30, //CJK UNIFIED IDEOGRAPH + 0xA6F5: 0x4F50, //CJK UNIFIED IDEOGRAPH + 0xA6F6: 0x4F51, //CJK UNIFIED IDEOGRAPH + 0xA6F7: 0x4F3D, //CJK UNIFIED IDEOGRAPH + 0xA6F8: 0x4F3A, //CJK UNIFIED IDEOGRAPH + 0xA6F9: 0x4F38, //CJK UNIFIED IDEOGRAPH + 0xA6FA: 0x4F43, //CJK UNIFIED IDEOGRAPH + 0xA6FB: 0x4F54, //CJK UNIFIED IDEOGRAPH + 0xA6FC: 0x4F3C, //CJK UNIFIED IDEOGRAPH + 0xA6FD: 0x4F46, //CJK UNIFIED IDEOGRAPH + 0xA6FE: 0x4F63, //CJK UNIFIED IDEOGRAPH + 0xA740: 0x4F5C, //CJK UNIFIED IDEOGRAPH + 0xA741: 0x4F60, //CJK UNIFIED IDEOGRAPH + 0xA742: 0x4F2F, //CJK UNIFIED IDEOGRAPH + 0xA743: 0x4F4E, //CJK UNIFIED IDEOGRAPH + 0xA744: 0x4F36, //CJK UNIFIED IDEOGRAPH + 0xA745: 0x4F59, //CJK UNIFIED IDEOGRAPH + 0xA746: 0x4F5D, //CJK UNIFIED IDEOGRAPH + 0xA747: 0x4F48, //CJK UNIFIED IDEOGRAPH + 0xA748: 0x4F5A, //CJK UNIFIED IDEOGRAPH + 0xA749: 0x514C, //CJK UNIFIED IDEOGRAPH + 0xA74A: 0x514B, //CJK UNIFIED IDEOGRAPH + 0xA74B: 0x514D, //CJK UNIFIED IDEOGRAPH + 0xA74C: 0x5175, //CJK UNIFIED IDEOGRAPH + 0xA74D: 0x51B6, //CJK UNIFIED IDEOGRAPH + 0xA74E: 0x51B7, //CJK UNIFIED IDEOGRAPH + 0xA74F: 0x5225, //CJK UNIFIED IDEOGRAPH + 0xA750: 0x5224, //CJK UNIFIED IDEOGRAPH + 0xA751: 0x5229, //CJK UNIFIED IDEOGRAPH + 0xA752: 0x522A, //CJK UNIFIED IDEOGRAPH + 0xA753: 0x5228, //CJK UNIFIED IDEOGRAPH + 0xA754: 0x52AB, //CJK UNIFIED IDEOGRAPH + 0xA755: 0x52A9, //CJK UNIFIED IDEOGRAPH + 0xA756: 0x52AA, //CJK UNIFIED IDEOGRAPH + 0xA757: 0x52AC, //CJK UNIFIED IDEOGRAPH + 0xA758: 0x5323, //CJK UNIFIED IDEOGRAPH + 0xA759: 0x5373, //CJK UNIFIED IDEOGRAPH + 0xA75A: 0x5375, //CJK UNIFIED IDEOGRAPH + 0xA75B: 0x541D, //CJK UNIFIED IDEOGRAPH + 0xA75C: 0x542D, //CJK UNIFIED IDEOGRAPH + 0xA75D: 0x541E, //CJK UNIFIED IDEOGRAPH + 0xA75E: 0x543E, //CJK UNIFIED IDEOGRAPH + 0xA75F: 0x5426, //CJK UNIFIED IDEOGRAPH + 0xA760: 0x544E, //CJK UNIFIED IDEOGRAPH + 0xA761: 0x5427, //CJK UNIFIED IDEOGRAPH + 0xA762: 0x5446, //CJK UNIFIED IDEOGRAPH + 0xA763: 0x5443, //CJK UNIFIED IDEOGRAPH + 0xA764: 0x5433, //CJK UNIFIED IDEOGRAPH + 0xA765: 0x5448, //CJK UNIFIED IDEOGRAPH + 0xA766: 0x5442, //CJK UNIFIED IDEOGRAPH + 0xA767: 0x541B, //CJK UNIFIED IDEOGRAPH + 0xA768: 0x5429, //CJK UNIFIED IDEOGRAPH + 0xA769: 0x544A, //CJK UNIFIED IDEOGRAPH + 0xA76A: 0x5439, //CJK UNIFIED IDEOGRAPH + 0xA76B: 0x543B, //CJK UNIFIED IDEOGRAPH + 0xA76C: 0x5438, //CJK UNIFIED IDEOGRAPH + 0xA76D: 0x542E, //CJK UNIFIED IDEOGRAPH + 0xA76E: 0x5435, //CJK UNIFIED IDEOGRAPH + 0xA76F: 0x5436, //CJK UNIFIED IDEOGRAPH + 0xA770: 0x5420, //CJK UNIFIED IDEOGRAPH + 0xA771: 0x543C, //CJK UNIFIED IDEOGRAPH + 0xA772: 0x5440, //CJK UNIFIED IDEOGRAPH + 0xA773: 0x5431, //CJK UNIFIED IDEOGRAPH + 0xA774: 0x542B, //CJK UNIFIED IDEOGRAPH + 0xA775: 0x541F, //CJK UNIFIED IDEOGRAPH + 0xA776: 0x542C, //CJK UNIFIED IDEOGRAPH + 0xA777: 0x56EA, //CJK UNIFIED IDEOGRAPH + 0xA778: 0x56F0, //CJK UNIFIED IDEOGRAPH + 0xA779: 0x56E4, //CJK UNIFIED IDEOGRAPH + 0xA77A: 0x56EB, //CJK UNIFIED IDEOGRAPH + 0xA77B: 0x574A, //CJK UNIFIED IDEOGRAPH + 0xA77C: 0x5751, //CJK UNIFIED IDEOGRAPH + 0xA77D: 0x5740, //CJK UNIFIED IDEOGRAPH + 0xA77E: 0x574D, //CJK UNIFIED IDEOGRAPH + 0xA7A1: 0x5747, //CJK UNIFIED IDEOGRAPH + 0xA7A2: 0x574E, //CJK UNIFIED IDEOGRAPH + 0xA7A3: 0x573E, //CJK UNIFIED IDEOGRAPH + 0xA7A4: 0x5750, //CJK UNIFIED IDEOGRAPH + 0xA7A5: 0x574F, //CJK UNIFIED IDEOGRAPH + 0xA7A6: 0x573B, //CJK UNIFIED IDEOGRAPH + 0xA7A7: 0x58EF, //CJK UNIFIED IDEOGRAPH + 0xA7A8: 0x593E, //CJK UNIFIED IDEOGRAPH + 0xA7A9: 0x599D, //CJK UNIFIED IDEOGRAPH + 0xA7AA: 0x5992, //CJK UNIFIED IDEOGRAPH + 0xA7AB: 0x59A8, //CJK UNIFIED IDEOGRAPH + 0xA7AC: 0x599E, //CJK UNIFIED IDEOGRAPH + 0xA7AD: 0x59A3, //CJK UNIFIED IDEOGRAPH + 0xA7AE: 0x5999, //CJK UNIFIED IDEOGRAPH + 0xA7AF: 0x5996, //CJK UNIFIED IDEOGRAPH + 0xA7B0: 0x598D, //CJK UNIFIED IDEOGRAPH + 0xA7B1: 0x59A4, //CJK UNIFIED IDEOGRAPH + 0xA7B2: 0x5993, //CJK UNIFIED IDEOGRAPH + 0xA7B3: 0x598A, //CJK UNIFIED IDEOGRAPH + 0xA7B4: 0x59A5, //CJK UNIFIED IDEOGRAPH + 0xA7B5: 0x5B5D, //CJK UNIFIED IDEOGRAPH + 0xA7B6: 0x5B5C, //CJK UNIFIED IDEOGRAPH + 0xA7B7: 0x5B5A, //CJK UNIFIED IDEOGRAPH + 0xA7B8: 0x5B5B, //CJK UNIFIED IDEOGRAPH + 0xA7B9: 0x5B8C, //CJK UNIFIED IDEOGRAPH + 0xA7BA: 0x5B8B, //CJK UNIFIED IDEOGRAPH + 0xA7BB: 0x5B8F, //CJK UNIFIED IDEOGRAPH + 0xA7BC: 0x5C2C, //CJK UNIFIED IDEOGRAPH + 0xA7BD: 0x5C40, //CJK UNIFIED IDEOGRAPH + 0xA7BE: 0x5C41, //CJK UNIFIED IDEOGRAPH + 0xA7BF: 0x5C3F, //CJK UNIFIED IDEOGRAPH + 0xA7C0: 0x5C3E, //CJK UNIFIED IDEOGRAPH + 0xA7C1: 0x5C90, //CJK UNIFIED IDEOGRAPH + 0xA7C2: 0x5C91, //CJK UNIFIED IDEOGRAPH + 0xA7C3: 0x5C94, //CJK UNIFIED IDEOGRAPH + 0xA7C4: 0x5C8C, //CJK UNIFIED IDEOGRAPH + 0xA7C5: 0x5DEB, //CJK UNIFIED IDEOGRAPH + 0xA7C6: 0x5E0C, //CJK UNIFIED IDEOGRAPH + 0xA7C7: 0x5E8F, //CJK UNIFIED IDEOGRAPH + 0xA7C8: 0x5E87, //CJK UNIFIED IDEOGRAPH + 0xA7C9: 0x5E8A, //CJK UNIFIED IDEOGRAPH + 0xA7CA: 0x5EF7, //CJK UNIFIED IDEOGRAPH + 0xA7CB: 0x5F04, //CJK UNIFIED IDEOGRAPH + 0xA7CC: 0x5F1F, //CJK UNIFIED IDEOGRAPH + 0xA7CD: 0x5F64, //CJK UNIFIED IDEOGRAPH + 0xA7CE: 0x5F62, //CJK UNIFIED IDEOGRAPH + 0xA7CF: 0x5F77, //CJK UNIFIED IDEOGRAPH + 0xA7D0: 0x5F79, //CJK UNIFIED IDEOGRAPH + 0xA7D1: 0x5FD8, //CJK UNIFIED IDEOGRAPH + 0xA7D2: 0x5FCC, //CJK UNIFIED IDEOGRAPH + 0xA7D3: 0x5FD7, //CJK UNIFIED IDEOGRAPH + 0xA7D4: 0x5FCD, //CJK UNIFIED IDEOGRAPH + 0xA7D5: 0x5FF1, //CJK UNIFIED IDEOGRAPH + 0xA7D6: 0x5FEB, //CJK UNIFIED IDEOGRAPH + 0xA7D7: 0x5FF8, //CJK UNIFIED IDEOGRAPH + 0xA7D8: 0x5FEA, //CJK UNIFIED IDEOGRAPH + 0xA7D9: 0x6212, //CJK UNIFIED IDEOGRAPH + 0xA7DA: 0x6211, //CJK UNIFIED IDEOGRAPH + 0xA7DB: 0x6284, //CJK UNIFIED IDEOGRAPH + 0xA7DC: 0x6297, //CJK UNIFIED IDEOGRAPH + 0xA7DD: 0x6296, //CJK UNIFIED IDEOGRAPH + 0xA7DE: 0x6280, //CJK UNIFIED IDEOGRAPH + 0xA7DF: 0x6276, //CJK UNIFIED IDEOGRAPH + 0xA7E0: 0x6289, //CJK UNIFIED IDEOGRAPH + 0xA7E1: 0x626D, //CJK UNIFIED IDEOGRAPH + 0xA7E2: 0x628A, //CJK UNIFIED IDEOGRAPH + 0xA7E3: 0x627C, //CJK UNIFIED IDEOGRAPH + 0xA7E4: 0x627E, //CJK UNIFIED IDEOGRAPH + 0xA7E5: 0x6279, //CJK UNIFIED IDEOGRAPH + 0xA7E6: 0x6273, //CJK UNIFIED IDEOGRAPH + 0xA7E7: 0x6292, //CJK UNIFIED IDEOGRAPH + 0xA7E8: 0x626F, //CJK UNIFIED IDEOGRAPH + 0xA7E9: 0x6298, //CJK UNIFIED IDEOGRAPH + 0xA7EA: 0x626E, //CJK UNIFIED IDEOGRAPH + 0xA7EB: 0x6295, //CJK UNIFIED IDEOGRAPH + 0xA7EC: 0x6293, //CJK UNIFIED IDEOGRAPH + 0xA7ED: 0x6291, //CJK UNIFIED IDEOGRAPH + 0xA7EE: 0x6286, //CJK UNIFIED IDEOGRAPH + 0xA7EF: 0x6539, //CJK UNIFIED IDEOGRAPH + 0xA7F0: 0x653B, //CJK UNIFIED IDEOGRAPH + 0xA7F1: 0x6538, //CJK UNIFIED IDEOGRAPH + 0xA7F2: 0x65F1, //CJK UNIFIED IDEOGRAPH + 0xA7F3: 0x66F4, //CJK UNIFIED IDEOGRAPH + 0xA7F4: 0x675F, //CJK UNIFIED IDEOGRAPH + 0xA7F5: 0x674E, //CJK UNIFIED IDEOGRAPH + 0xA7F6: 0x674F, //CJK UNIFIED IDEOGRAPH + 0xA7F7: 0x6750, //CJK UNIFIED IDEOGRAPH + 0xA7F8: 0x6751, //CJK UNIFIED IDEOGRAPH + 0xA7F9: 0x675C, //CJK UNIFIED IDEOGRAPH + 0xA7FA: 0x6756, //CJK UNIFIED IDEOGRAPH + 0xA7FB: 0x675E, //CJK UNIFIED IDEOGRAPH + 0xA7FC: 0x6749, //CJK UNIFIED IDEOGRAPH + 0xA7FD: 0x6746, //CJK UNIFIED IDEOGRAPH + 0xA7FE: 0x6760, //CJK UNIFIED IDEOGRAPH + 0xA840: 0x6753, //CJK UNIFIED IDEOGRAPH + 0xA841: 0x6757, //CJK UNIFIED IDEOGRAPH + 0xA842: 0x6B65, //CJK UNIFIED IDEOGRAPH + 0xA843: 0x6BCF, //CJK UNIFIED IDEOGRAPH + 0xA844: 0x6C42, //CJK UNIFIED IDEOGRAPH + 0xA845: 0x6C5E, //CJK UNIFIED IDEOGRAPH + 0xA846: 0x6C99, //CJK UNIFIED IDEOGRAPH + 0xA847: 0x6C81, //CJK UNIFIED IDEOGRAPH + 0xA848: 0x6C88, //CJK UNIFIED IDEOGRAPH + 0xA849: 0x6C89, //CJK UNIFIED IDEOGRAPH + 0xA84A: 0x6C85, //CJK UNIFIED IDEOGRAPH + 0xA84B: 0x6C9B, //CJK UNIFIED IDEOGRAPH + 0xA84C: 0x6C6A, //CJK UNIFIED IDEOGRAPH + 0xA84D: 0x6C7A, //CJK UNIFIED IDEOGRAPH + 0xA84E: 0x6C90, //CJK UNIFIED IDEOGRAPH + 0xA84F: 0x6C70, //CJK UNIFIED IDEOGRAPH + 0xA850: 0x6C8C, //CJK UNIFIED IDEOGRAPH + 0xA851: 0x6C68, //CJK UNIFIED IDEOGRAPH + 0xA852: 0x6C96, //CJK UNIFIED IDEOGRAPH + 0xA853: 0x6C92, //CJK UNIFIED IDEOGRAPH + 0xA854: 0x6C7D, //CJK UNIFIED IDEOGRAPH + 0xA855: 0x6C83, //CJK UNIFIED IDEOGRAPH + 0xA856: 0x6C72, //CJK UNIFIED IDEOGRAPH + 0xA857: 0x6C7E, //CJK UNIFIED IDEOGRAPH + 0xA858: 0x6C74, //CJK UNIFIED IDEOGRAPH + 0xA859: 0x6C86, //CJK UNIFIED IDEOGRAPH + 0xA85A: 0x6C76, //CJK UNIFIED IDEOGRAPH + 0xA85B: 0x6C8D, //CJK UNIFIED IDEOGRAPH + 0xA85C: 0x6C94, //CJK UNIFIED IDEOGRAPH + 0xA85D: 0x6C98, //CJK UNIFIED IDEOGRAPH + 0xA85E: 0x6C82, //CJK UNIFIED IDEOGRAPH + 0xA85F: 0x7076, //CJK UNIFIED IDEOGRAPH + 0xA860: 0x707C, //CJK UNIFIED IDEOGRAPH + 0xA861: 0x707D, //CJK UNIFIED IDEOGRAPH + 0xA862: 0x7078, //CJK UNIFIED IDEOGRAPH + 0xA863: 0x7262, //CJK UNIFIED IDEOGRAPH + 0xA864: 0x7261, //CJK UNIFIED IDEOGRAPH + 0xA865: 0x7260, //CJK UNIFIED IDEOGRAPH + 0xA866: 0x72C4, //CJK UNIFIED IDEOGRAPH + 0xA867: 0x72C2, //CJK UNIFIED IDEOGRAPH + 0xA868: 0x7396, //CJK UNIFIED IDEOGRAPH + 0xA869: 0x752C, //CJK UNIFIED IDEOGRAPH + 0xA86A: 0x752B, //CJK UNIFIED IDEOGRAPH + 0xA86B: 0x7537, //CJK UNIFIED IDEOGRAPH + 0xA86C: 0x7538, //CJK UNIFIED IDEOGRAPH + 0xA86D: 0x7682, //CJK UNIFIED IDEOGRAPH + 0xA86E: 0x76EF, //CJK UNIFIED IDEOGRAPH + 0xA86F: 0x77E3, //CJK UNIFIED IDEOGRAPH + 0xA870: 0x79C1, //CJK UNIFIED IDEOGRAPH + 0xA871: 0x79C0, //CJK UNIFIED IDEOGRAPH + 0xA872: 0x79BF, //CJK UNIFIED IDEOGRAPH + 0xA873: 0x7A76, //CJK UNIFIED IDEOGRAPH + 0xA874: 0x7CFB, //CJK UNIFIED IDEOGRAPH + 0xA875: 0x7F55, //CJK UNIFIED IDEOGRAPH + 0xA876: 0x8096, //CJK UNIFIED IDEOGRAPH + 0xA877: 0x8093, //CJK UNIFIED IDEOGRAPH + 0xA878: 0x809D, //CJK UNIFIED IDEOGRAPH + 0xA879: 0x8098, //CJK UNIFIED IDEOGRAPH + 0xA87A: 0x809B, //CJK UNIFIED IDEOGRAPH + 0xA87B: 0x809A, //CJK UNIFIED IDEOGRAPH + 0xA87C: 0x80B2, //CJK UNIFIED IDEOGRAPH + 0xA87D: 0x826F, //CJK UNIFIED IDEOGRAPH + 0xA87E: 0x8292, //CJK UNIFIED IDEOGRAPH + 0xA8A1: 0x828B, //CJK UNIFIED IDEOGRAPH + 0xA8A2: 0x828D, //CJK UNIFIED IDEOGRAPH + 0xA8A3: 0x898B, //CJK UNIFIED IDEOGRAPH + 0xA8A4: 0x89D2, //CJK UNIFIED IDEOGRAPH + 0xA8A5: 0x8A00, //CJK UNIFIED IDEOGRAPH + 0xA8A6: 0x8C37, //CJK UNIFIED IDEOGRAPH + 0xA8A7: 0x8C46, //CJK UNIFIED IDEOGRAPH + 0xA8A8: 0x8C55, //CJK UNIFIED IDEOGRAPH + 0xA8A9: 0x8C9D, //CJK UNIFIED IDEOGRAPH + 0xA8AA: 0x8D64, //CJK UNIFIED IDEOGRAPH + 0xA8AB: 0x8D70, //CJK UNIFIED IDEOGRAPH + 0xA8AC: 0x8DB3, //CJK UNIFIED IDEOGRAPH + 0xA8AD: 0x8EAB, //CJK UNIFIED IDEOGRAPH + 0xA8AE: 0x8ECA, //CJK UNIFIED IDEOGRAPH + 0xA8AF: 0x8F9B, //CJK UNIFIED IDEOGRAPH + 0xA8B0: 0x8FB0, //CJK UNIFIED IDEOGRAPH + 0xA8B1: 0x8FC2, //CJK UNIFIED IDEOGRAPH + 0xA8B2: 0x8FC6, //CJK UNIFIED IDEOGRAPH + 0xA8B3: 0x8FC5, //CJK UNIFIED IDEOGRAPH + 0xA8B4: 0x8FC4, //CJK UNIFIED IDEOGRAPH + 0xA8B5: 0x5DE1, //CJK UNIFIED IDEOGRAPH + 0xA8B6: 0x9091, //CJK UNIFIED IDEOGRAPH + 0xA8B7: 0x90A2, //CJK UNIFIED IDEOGRAPH + 0xA8B8: 0x90AA, //CJK UNIFIED IDEOGRAPH + 0xA8B9: 0x90A6, //CJK UNIFIED IDEOGRAPH + 0xA8BA: 0x90A3, //CJK UNIFIED IDEOGRAPH + 0xA8BB: 0x9149, //CJK UNIFIED IDEOGRAPH + 0xA8BC: 0x91C6, //CJK UNIFIED IDEOGRAPH + 0xA8BD: 0x91CC, //CJK UNIFIED IDEOGRAPH + 0xA8BE: 0x9632, //CJK UNIFIED IDEOGRAPH + 0xA8BF: 0x962E, //CJK UNIFIED IDEOGRAPH + 0xA8C0: 0x9631, //CJK UNIFIED IDEOGRAPH + 0xA8C1: 0x962A, //CJK UNIFIED IDEOGRAPH + 0xA8C2: 0x962C, //CJK UNIFIED IDEOGRAPH + 0xA8C3: 0x4E26, //CJK UNIFIED IDEOGRAPH + 0xA8C4: 0x4E56, //CJK UNIFIED IDEOGRAPH + 0xA8C5: 0x4E73, //CJK UNIFIED IDEOGRAPH + 0xA8C6: 0x4E8B, //CJK UNIFIED IDEOGRAPH + 0xA8C7: 0x4E9B, //CJK UNIFIED IDEOGRAPH + 0xA8C8: 0x4E9E, //CJK UNIFIED IDEOGRAPH + 0xA8C9: 0x4EAB, //CJK UNIFIED IDEOGRAPH + 0xA8CA: 0x4EAC, //CJK UNIFIED IDEOGRAPH + 0xA8CB: 0x4F6F, //CJK UNIFIED IDEOGRAPH + 0xA8CC: 0x4F9D, //CJK UNIFIED IDEOGRAPH + 0xA8CD: 0x4F8D, //CJK UNIFIED IDEOGRAPH + 0xA8CE: 0x4F73, //CJK UNIFIED IDEOGRAPH + 0xA8CF: 0x4F7F, //CJK UNIFIED IDEOGRAPH + 0xA8D0: 0x4F6C, //CJK UNIFIED IDEOGRAPH + 0xA8D1: 0x4F9B, //CJK UNIFIED IDEOGRAPH + 0xA8D2: 0x4F8B, //CJK UNIFIED IDEOGRAPH + 0xA8D3: 0x4F86, //CJK UNIFIED IDEOGRAPH + 0xA8D4: 0x4F83, //CJK UNIFIED IDEOGRAPH + 0xA8D5: 0x4F70, //CJK UNIFIED IDEOGRAPH + 0xA8D6: 0x4F75, //CJK UNIFIED IDEOGRAPH + 0xA8D7: 0x4F88, //CJK UNIFIED IDEOGRAPH + 0xA8D8: 0x4F69, //CJK UNIFIED IDEOGRAPH + 0xA8D9: 0x4F7B, //CJK UNIFIED IDEOGRAPH + 0xA8DA: 0x4F96, //CJK UNIFIED IDEOGRAPH + 0xA8DB: 0x4F7E, //CJK UNIFIED IDEOGRAPH + 0xA8DC: 0x4F8F, //CJK UNIFIED IDEOGRAPH + 0xA8DD: 0x4F91, //CJK UNIFIED IDEOGRAPH + 0xA8DE: 0x4F7A, //CJK UNIFIED IDEOGRAPH + 0xA8DF: 0x5154, //CJK UNIFIED IDEOGRAPH + 0xA8E0: 0x5152, //CJK UNIFIED IDEOGRAPH + 0xA8E1: 0x5155, //CJK UNIFIED IDEOGRAPH + 0xA8E2: 0x5169, //CJK UNIFIED IDEOGRAPH + 0xA8E3: 0x5177, //CJK UNIFIED IDEOGRAPH + 0xA8E4: 0x5176, //CJK UNIFIED IDEOGRAPH + 0xA8E5: 0x5178, //CJK UNIFIED IDEOGRAPH + 0xA8E6: 0x51BD, //CJK UNIFIED IDEOGRAPH + 0xA8E7: 0x51FD, //CJK UNIFIED IDEOGRAPH + 0xA8E8: 0x523B, //CJK UNIFIED IDEOGRAPH + 0xA8E9: 0x5238, //CJK UNIFIED IDEOGRAPH + 0xA8EA: 0x5237, //CJK UNIFIED IDEOGRAPH + 0xA8EB: 0x523A, //CJK UNIFIED IDEOGRAPH + 0xA8EC: 0x5230, //CJK UNIFIED IDEOGRAPH + 0xA8ED: 0x522E, //CJK UNIFIED IDEOGRAPH + 0xA8EE: 0x5236, //CJK UNIFIED IDEOGRAPH + 0xA8EF: 0x5241, //CJK UNIFIED IDEOGRAPH + 0xA8F0: 0x52BE, //CJK UNIFIED IDEOGRAPH + 0xA8F1: 0x52BB, //CJK UNIFIED IDEOGRAPH + 0xA8F2: 0x5352, //CJK UNIFIED IDEOGRAPH + 0xA8F3: 0x5354, //CJK UNIFIED IDEOGRAPH + 0xA8F4: 0x5353, //CJK UNIFIED IDEOGRAPH + 0xA8F5: 0x5351, //CJK UNIFIED IDEOGRAPH + 0xA8F6: 0x5366, //CJK UNIFIED IDEOGRAPH + 0xA8F7: 0x5377, //CJK UNIFIED IDEOGRAPH + 0xA8F8: 0x5378, //CJK UNIFIED IDEOGRAPH + 0xA8F9: 0x5379, //CJK UNIFIED IDEOGRAPH + 0xA8FA: 0x53D6, //CJK UNIFIED IDEOGRAPH + 0xA8FB: 0x53D4, //CJK UNIFIED IDEOGRAPH + 0xA8FC: 0x53D7, //CJK UNIFIED IDEOGRAPH + 0xA8FD: 0x5473, //CJK UNIFIED IDEOGRAPH + 0xA8FE: 0x5475, //CJK UNIFIED IDEOGRAPH + 0xA940: 0x5496, //CJK UNIFIED IDEOGRAPH + 0xA941: 0x5478, //CJK UNIFIED IDEOGRAPH + 0xA942: 0x5495, //CJK UNIFIED IDEOGRAPH + 0xA943: 0x5480, //CJK UNIFIED IDEOGRAPH + 0xA944: 0x547B, //CJK UNIFIED IDEOGRAPH + 0xA945: 0x5477, //CJK UNIFIED IDEOGRAPH + 0xA946: 0x5484, //CJK UNIFIED IDEOGRAPH + 0xA947: 0x5492, //CJK UNIFIED IDEOGRAPH + 0xA948: 0x5486, //CJK UNIFIED IDEOGRAPH + 0xA949: 0x547C, //CJK UNIFIED IDEOGRAPH + 0xA94A: 0x5490, //CJK UNIFIED IDEOGRAPH + 0xA94B: 0x5471, //CJK UNIFIED IDEOGRAPH + 0xA94C: 0x5476, //CJK UNIFIED IDEOGRAPH + 0xA94D: 0x548C, //CJK UNIFIED IDEOGRAPH + 0xA94E: 0x549A, //CJK UNIFIED IDEOGRAPH + 0xA94F: 0x5462, //CJK UNIFIED IDEOGRAPH + 0xA950: 0x5468, //CJK UNIFIED IDEOGRAPH + 0xA951: 0x548B, //CJK UNIFIED IDEOGRAPH + 0xA952: 0x547D, //CJK UNIFIED IDEOGRAPH + 0xA953: 0x548E, //CJK UNIFIED IDEOGRAPH + 0xA954: 0x56FA, //CJK UNIFIED IDEOGRAPH + 0xA955: 0x5783, //CJK UNIFIED IDEOGRAPH + 0xA956: 0x5777, //CJK UNIFIED IDEOGRAPH + 0xA957: 0x576A, //CJK UNIFIED IDEOGRAPH + 0xA958: 0x5769, //CJK UNIFIED IDEOGRAPH + 0xA959: 0x5761, //CJK UNIFIED IDEOGRAPH + 0xA95A: 0x5766, //CJK UNIFIED IDEOGRAPH + 0xA95B: 0x5764, //CJK UNIFIED IDEOGRAPH + 0xA95C: 0x577C, //CJK UNIFIED IDEOGRAPH + 0xA95D: 0x591C, //CJK UNIFIED IDEOGRAPH + 0xA95E: 0x5949, //CJK UNIFIED IDEOGRAPH + 0xA95F: 0x5947, //CJK UNIFIED IDEOGRAPH + 0xA960: 0x5948, //CJK UNIFIED IDEOGRAPH + 0xA961: 0x5944, //CJK UNIFIED IDEOGRAPH + 0xA962: 0x5954, //CJK UNIFIED IDEOGRAPH + 0xA963: 0x59BE, //CJK UNIFIED IDEOGRAPH + 0xA964: 0x59BB, //CJK UNIFIED IDEOGRAPH + 0xA965: 0x59D4, //CJK UNIFIED IDEOGRAPH + 0xA966: 0x59B9, //CJK UNIFIED IDEOGRAPH + 0xA967: 0x59AE, //CJK UNIFIED IDEOGRAPH + 0xA968: 0x59D1, //CJK UNIFIED IDEOGRAPH + 0xA969: 0x59C6, //CJK UNIFIED IDEOGRAPH + 0xA96A: 0x59D0, //CJK UNIFIED IDEOGRAPH + 0xA96B: 0x59CD, //CJK UNIFIED IDEOGRAPH + 0xA96C: 0x59CB, //CJK UNIFIED IDEOGRAPH + 0xA96D: 0x59D3, //CJK UNIFIED IDEOGRAPH + 0xA96E: 0x59CA, //CJK UNIFIED IDEOGRAPH + 0xA96F: 0x59AF, //CJK UNIFIED IDEOGRAPH + 0xA970: 0x59B3, //CJK UNIFIED IDEOGRAPH + 0xA971: 0x59D2, //CJK UNIFIED IDEOGRAPH + 0xA972: 0x59C5, //CJK UNIFIED IDEOGRAPH + 0xA973: 0x5B5F, //CJK UNIFIED IDEOGRAPH + 0xA974: 0x5B64, //CJK UNIFIED IDEOGRAPH + 0xA975: 0x5B63, //CJK UNIFIED IDEOGRAPH + 0xA976: 0x5B97, //CJK UNIFIED IDEOGRAPH + 0xA977: 0x5B9A, //CJK UNIFIED IDEOGRAPH + 0xA978: 0x5B98, //CJK UNIFIED IDEOGRAPH + 0xA979: 0x5B9C, //CJK UNIFIED IDEOGRAPH + 0xA97A: 0x5B99, //CJK UNIFIED IDEOGRAPH + 0xA97B: 0x5B9B, //CJK UNIFIED IDEOGRAPH + 0xA97C: 0x5C1A, //CJK UNIFIED IDEOGRAPH + 0xA97D: 0x5C48, //CJK UNIFIED IDEOGRAPH + 0xA97E: 0x5C45, //CJK UNIFIED IDEOGRAPH + 0xA9A1: 0x5C46, //CJK UNIFIED IDEOGRAPH + 0xA9A2: 0x5CB7, //CJK UNIFIED IDEOGRAPH + 0xA9A3: 0x5CA1, //CJK UNIFIED IDEOGRAPH + 0xA9A4: 0x5CB8, //CJK UNIFIED IDEOGRAPH + 0xA9A5: 0x5CA9, //CJK UNIFIED IDEOGRAPH + 0xA9A6: 0x5CAB, //CJK UNIFIED IDEOGRAPH + 0xA9A7: 0x5CB1, //CJK UNIFIED IDEOGRAPH + 0xA9A8: 0x5CB3, //CJK UNIFIED IDEOGRAPH + 0xA9A9: 0x5E18, //CJK UNIFIED IDEOGRAPH + 0xA9AA: 0x5E1A, //CJK UNIFIED IDEOGRAPH + 0xA9AB: 0x5E16, //CJK UNIFIED IDEOGRAPH + 0xA9AC: 0x5E15, //CJK UNIFIED IDEOGRAPH + 0xA9AD: 0x5E1B, //CJK UNIFIED IDEOGRAPH + 0xA9AE: 0x5E11, //CJK UNIFIED IDEOGRAPH + 0xA9AF: 0x5E78, //CJK UNIFIED IDEOGRAPH + 0xA9B0: 0x5E9A, //CJK UNIFIED IDEOGRAPH + 0xA9B1: 0x5E97, //CJK UNIFIED IDEOGRAPH + 0xA9B2: 0x5E9C, //CJK UNIFIED IDEOGRAPH + 0xA9B3: 0x5E95, //CJK UNIFIED IDEOGRAPH + 0xA9B4: 0x5E96, //CJK UNIFIED IDEOGRAPH + 0xA9B5: 0x5EF6, //CJK UNIFIED IDEOGRAPH + 0xA9B6: 0x5F26, //CJK UNIFIED IDEOGRAPH + 0xA9B7: 0x5F27, //CJK UNIFIED IDEOGRAPH + 0xA9B8: 0x5F29, //CJK UNIFIED IDEOGRAPH + 0xA9B9: 0x5F80, //CJK UNIFIED IDEOGRAPH + 0xA9BA: 0x5F81, //CJK UNIFIED IDEOGRAPH + 0xA9BB: 0x5F7F, //CJK UNIFIED IDEOGRAPH + 0xA9BC: 0x5F7C, //CJK UNIFIED IDEOGRAPH + 0xA9BD: 0x5FDD, //CJK UNIFIED IDEOGRAPH + 0xA9BE: 0x5FE0, //CJK UNIFIED IDEOGRAPH + 0xA9BF: 0x5FFD, //CJK UNIFIED IDEOGRAPH + 0xA9C0: 0x5FF5, //CJK UNIFIED IDEOGRAPH + 0xA9C1: 0x5FFF, //CJK UNIFIED IDEOGRAPH + 0xA9C2: 0x600F, //CJK UNIFIED IDEOGRAPH + 0xA9C3: 0x6014, //CJK UNIFIED IDEOGRAPH + 0xA9C4: 0x602F, //CJK UNIFIED IDEOGRAPH + 0xA9C5: 0x6035, //CJK UNIFIED IDEOGRAPH + 0xA9C6: 0x6016, //CJK UNIFIED IDEOGRAPH + 0xA9C7: 0x602A, //CJK UNIFIED IDEOGRAPH + 0xA9C8: 0x6015, //CJK UNIFIED IDEOGRAPH + 0xA9C9: 0x6021, //CJK UNIFIED IDEOGRAPH + 0xA9CA: 0x6027, //CJK UNIFIED IDEOGRAPH + 0xA9CB: 0x6029, //CJK UNIFIED IDEOGRAPH + 0xA9CC: 0x602B, //CJK UNIFIED IDEOGRAPH + 0xA9CD: 0x601B, //CJK UNIFIED IDEOGRAPH + 0xA9CE: 0x6216, //CJK UNIFIED IDEOGRAPH + 0xA9CF: 0x6215, //CJK UNIFIED IDEOGRAPH + 0xA9D0: 0x623F, //CJK UNIFIED IDEOGRAPH + 0xA9D1: 0x623E, //CJK UNIFIED IDEOGRAPH + 0xA9D2: 0x6240, //CJK UNIFIED IDEOGRAPH + 0xA9D3: 0x627F, //CJK UNIFIED IDEOGRAPH + 0xA9D4: 0x62C9, //CJK UNIFIED IDEOGRAPH + 0xA9D5: 0x62CC, //CJK UNIFIED IDEOGRAPH + 0xA9D6: 0x62C4, //CJK UNIFIED IDEOGRAPH + 0xA9D7: 0x62BF, //CJK UNIFIED IDEOGRAPH + 0xA9D8: 0x62C2, //CJK UNIFIED IDEOGRAPH + 0xA9D9: 0x62B9, //CJK UNIFIED IDEOGRAPH + 0xA9DA: 0x62D2, //CJK UNIFIED IDEOGRAPH + 0xA9DB: 0x62DB, //CJK UNIFIED IDEOGRAPH + 0xA9DC: 0x62AB, //CJK UNIFIED IDEOGRAPH + 0xA9DD: 0x62D3, //CJK UNIFIED IDEOGRAPH + 0xA9DE: 0x62D4, //CJK UNIFIED IDEOGRAPH + 0xA9DF: 0x62CB, //CJK UNIFIED IDEOGRAPH + 0xA9E0: 0x62C8, //CJK UNIFIED IDEOGRAPH + 0xA9E1: 0x62A8, //CJK UNIFIED IDEOGRAPH + 0xA9E2: 0x62BD, //CJK UNIFIED IDEOGRAPH + 0xA9E3: 0x62BC, //CJK UNIFIED IDEOGRAPH + 0xA9E4: 0x62D0, //CJK UNIFIED IDEOGRAPH + 0xA9E5: 0x62D9, //CJK UNIFIED IDEOGRAPH + 0xA9E6: 0x62C7, //CJK UNIFIED IDEOGRAPH + 0xA9E7: 0x62CD, //CJK UNIFIED IDEOGRAPH + 0xA9E8: 0x62B5, //CJK UNIFIED IDEOGRAPH + 0xA9E9: 0x62DA, //CJK UNIFIED IDEOGRAPH + 0xA9EA: 0x62B1, //CJK UNIFIED IDEOGRAPH + 0xA9EB: 0x62D8, //CJK UNIFIED IDEOGRAPH + 0xA9EC: 0x62D6, //CJK UNIFIED IDEOGRAPH + 0xA9ED: 0x62D7, //CJK UNIFIED IDEOGRAPH + 0xA9EE: 0x62C6, //CJK UNIFIED IDEOGRAPH + 0xA9EF: 0x62AC, //CJK UNIFIED IDEOGRAPH + 0xA9F0: 0x62CE, //CJK UNIFIED IDEOGRAPH + 0xA9F1: 0x653E, //CJK UNIFIED IDEOGRAPH + 0xA9F2: 0x65A7, //CJK UNIFIED IDEOGRAPH + 0xA9F3: 0x65BC, //CJK UNIFIED IDEOGRAPH + 0xA9F4: 0x65FA, //CJK UNIFIED IDEOGRAPH + 0xA9F5: 0x6614, //CJK UNIFIED IDEOGRAPH + 0xA9F6: 0x6613, //CJK UNIFIED IDEOGRAPH + 0xA9F7: 0x660C, //CJK UNIFIED IDEOGRAPH + 0xA9F8: 0x6606, //CJK UNIFIED IDEOGRAPH + 0xA9F9: 0x6602, //CJK UNIFIED IDEOGRAPH + 0xA9FA: 0x660E, //CJK UNIFIED IDEOGRAPH + 0xA9FB: 0x6600, //CJK UNIFIED IDEOGRAPH + 0xA9FC: 0x660F, //CJK UNIFIED IDEOGRAPH + 0xA9FD: 0x6615, //CJK UNIFIED IDEOGRAPH + 0xA9FE: 0x660A, //CJK UNIFIED IDEOGRAPH + 0xAA40: 0x6607, //CJK UNIFIED IDEOGRAPH + 0xAA41: 0x670D, //CJK UNIFIED IDEOGRAPH + 0xAA42: 0x670B, //CJK UNIFIED IDEOGRAPH + 0xAA43: 0x676D, //CJK UNIFIED IDEOGRAPH + 0xAA44: 0x678B, //CJK UNIFIED IDEOGRAPH + 0xAA45: 0x6795, //CJK UNIFIED IDEOGRAPH + 0xAA46: 0x6771, //CJK UNIFIED IDEOGRAPH + 0xAA47: 0x679C, //CJK UNIFIED IDEOGRAPH + 0xAA48: 0x6773, //CJK UNIFIED IDEOGRAPH + 0xAA49: 0x6777, //CJK UNIFIED IDEOGRAPH + 0xAA4A: 0x6787, //CJK UNIFIED IDEOGRAPH + 0xAA4B: 0x679D, //CJK UNIFIED IDEOGRAPH + 0xAA4C: 0x6797, //CJK UNIFIED IDEOGRAPH + 0xAA4D: 0x676F, //CJK UNIFIED IDEOGRAPH + 0xAA4E: 0x6770, //CJK UNIFIED IDEOGRAPH + 0xAA4F: 0x677F, //CJK UNIFIED IDEOGRAPH + 0xAA50: 0x6789, //CJK UNIFIED IDEOGRAPH + 0xAA51: 0x677E, //CJK UNIFIED IDEOGRAPH + 0xAA52: 0x6790, //CJK UNIFIED IDEOGRAPH + 0xAA53: 0x6775, //CJK UNIFIED IDEOGRAPH + 0xAA54: 0x679A, //CJK UNIFIED IDEOGRAPH + 0xAA55: 0x6793, //CJK UNIFIED IDEOGRAPH + 0xAA56: 0x677C, //CJK UNIFIED IDEOGRAPH + 0xAA57: 0x676A, //CJK UNIFIED IDEOGRAPH + 0xAA58: 0x6772, //CJK UNIFIED IDEOGRAPH + 0xAA59: 0x6B23, //CJK UNIFIED IDEOGRAPH + 0xAA5A: 0x6B66, //CJK UNIFIED IDEOGRAPH + 0xAA5B: 0x6B67, //CJK UNIFIED IDEOGRAPH + 0xAA5C: 0x6B7F, //CJK UNIFIED IDEOGRAPH + 0xAA5D: 0x6C13, //CJK UNIFIED IDEOGRAPH + 0xAA5E: 0x6C1B, //CJK UNIFIED IDEOGRAPH + 0xAA5F: 0x6CE3, //CJK UNIFIED IDEOGRAPH + 0xAA60: 0x6CE8, //CJK UNIFIED IDEOGRAPH + 0xAA61: 0x6CF3, //CJK UNIFIED IDEOGRAPH + 0xAA62: 0x6CB1, //CJK UNIFIED IDEOGRAPH + 0xAA63: 0x6CCC, //CJK UNIFIED IDEOGRAPH + 0xAA64: 0x6CE5, //CJK UNIFIED IDEOGRAPH + 0xAA65: 0x6CB3, //CJK UNIFIED IDEOGRAPH + 0xAA66: 0x6CBD, //CJK UNIFIED IDEOGRAPH + 0xAA67: 0x6CBE, //CJK UNIFIED IDEOGRAPH + 0xAA68: 0x6CBC, //CJK UNIFIED IDEOGRAPH + 0xAA69: 0x6CE2, //CJK UNIFIED IDEOGRAPH + 0xAA6A: 0x6CAB, //CJK UNIFIED IDEOGRAPH + 0xAA6B: 0x6CD5, //CJK UNIFIED IDEOGRAPH + 0xAA6C: 0x6CD3, //CJK UNIFIED IDEOGRAPH + 0xAA6D: 0x6CB8, //CJK UNIFIED IDEOGRAPH + 0xAA6E: 0x6CC4, //CJK UNIFIED IDEOGRAPH + 0xAA6F: 0x6CB9, //CJK UNIFIED IDEOGRAPH + 0xAA70: 0x6CC1, //CJK UNIFIED IDEOGRAPH + 0xAA71: 0x6CAE, //CJK UNIFIED IDEOGRAPH + 0xAA72: 0x6CD7, //CJK UNIFIED IDEOGRAPH + 0xAA73: 0x6CC5, //CJK UNIFIED IDEOGRAPH + 0xAA74: 0x6CF1, //CJK UNIFIED IDEOGRAPH + 0xAA75: 0x6CBF, //CJK UNIFIED IDEOGRAPH + 0xAA76: 0x6CBB, //CJK UNIFIED IDEOGRAPH + 0xAA77: 0x6CE1, //CJK UNIFIED IDEOGRAPH + 0xAA78: 0x6CDB, //CJK UNIFIED IDEOGRAPH + 0xAA79: 0x6CCA, //CJK UNIFIED IDEOGRAPH + 0xAA7A: 0x6CAC, //CJK UNIFIED IDEOGRAPH + 0xAA7B: 0x6CEF, //CJK UNIFIED IDEOGRAPH + 0xAA7C: 0x6CDC, //CJK UNIFIED IDEOGRAPH + 0xAA7D: 0x6CD6, //CJK UNIFIED IDEOGRAPH + 0xAA7E: 0x6CE0, //CJK UNIFIED IDEOGRAPH + 0xAAA1: 0x7095, //CJK UNIFIED IDEOGRAPH + 0xAAA2: 0x708E, //CJK UNIFIED IDEOGRAPH + 0xAAA3: 0x7092, //CJK UNIFIED IDEOGRAPH + 0xAAA4: 0x708A, //CJK UNIFIED IDEOGRAPH + 0xAAA5: 0x7099, //CJK UNIFIED IDEOGRAPH + 0xAAA6: 0x722C, //CJK UNIFIED IDEOGRAPH + 0xAAA7: 0x722D, //CJK UNIFIED IDEOGRAPH + 0xAAA8: 0x7238, //CJK UNIFIED IDEOGRAPH + 0xAAA9: 0x7248, //CJK UNIFIED IDEOGRAPH + 0xAAAA: 0x7267, //CJK UNIFIED IDEOGRAPH + 0xAAAB: 0x7269, //CJK UNIFIED IDEOGRAPH + 0xAAAC: 0x72C0, //CJK UNIFIED IDEOGRAPH + 0xAAAD: 0x72CE, //CJK UNIFIED IDEOGRAPH + 0xAAAE: 0x72D9, //CJK UNIFIED IDEOGRAPH + 0xAAAF: 0x72D7, //CJK UNIFIED IDEOGRAPH + 0xAAB0: 0x72D0, //CJK UNIFIED IDEOGRAPH + 0xAAB1: 0x73A9, //CJK UNIFIED IDEOGRAPH + 0xAAB2: 0x73A8, //CJK UNIFIED IDEOGRAPH + 0xAAB3: 0x739F, //CJK UNIFIED IDEOGRAPH + 0xAAB4: 0x73AB, //CJK UNIFIED IDEOGRAPH + 0xAAB5: 0x73A5, //CJK UNIFIED IDEOGRAPH + 0xAAB6: 0x753D, //CJK UNIFIED IDEOGRAPH + 0xAAB7: 0x759D, //CJK UNIFIED IDEOGRAPH + 0xAAB8: 0x7599, //CJK UNIFIED IDEOGRAPH + 0xAAB9: 0x759A, //CJK UNIFIED IDEOGRAPH + 0xAABA: 0x7684, //CJK UNIFIED IDEOGRAPH + 0xAABB: 0x76C2, //CJK UNIFIED IDEOGRAPH + 0xAABC: 0x76F2, //CJK UNIFIED IDEOGRAPH + 0xAABD: 0x76F4, //CJK UNIFIED IDEOGRAPH + 0xAABE: 0x77E5, //CJK UNIFIED IDEOGRAPH + 0xAABF: 0x77FD, //CJK UNIFIED IDEOGRAPH + 0xAAC0: 0x793E, //CJK UNIFIED IDEOGRAPH + 0xAAC1: 0x7940, //CJK UNIFIED IDEOGRAPH + 0xAAC2: 0x7941, //CJK UNIFIED IDEOGRAPH + 0xAAC3: 0x79C9, //CJK UNIFIED IDEOGRAPH + 0xAAC4: 0x79C8, //CJK UNIFIED IDEOGRAPH + 0xAAC5: 0x7A7A, //CJK UNIFIED IDEOGRAPH + 0xAAC6: 0x7A79, //CJK UNIFIED IDEOGRAPH + 0xAAC7: 0x7AFA, //CJK UNIFIED IDEOGRAPH + 0xAAC8: 0x7CFE, //CJK UNIFIED IDEOGRAPH + 0xAAC9: 0x7F54, //CJK UNIFIED IDEOGRAPH + 0xAACA: 0x7F8C, //CJK UNIFIED IDEOGRAPH + 0xAACB: 0x7F8B, //CJK UNIFIED IDEOGRAPH + 0xAACC: 0x8005, //CJK UNIFIED IDEOGRAPH + 0xAACD: 0x80BA, //CJK UNIFIED IDEOGRAPH + 0xAACE: 0x80A5, //CJK UNIFIED IDEOGRAPH + 0xAACF: 0x80A2, //CJK UNIFIED IDEOGRAPH + 0xAAD0: 0x80B1, //CJK UNIFIED IDEOGRAPH + 0xAAD1: 0x80A1, //CJK UNIFIED IDEOGRAPH + 0xAAD2: 0x80AB, //CJK UNIFIED IDEOGRAPH + 0xAAD3: 0x80A9, //CJK UNIFIED IDEOGRAPH + 0xAAD4: 0x80B4, //CJK UNIFIED IDEOGRAPH + 0xAAD5: 0x80AA, //CJK UNIFIED IDEOGRAPH + 0xAAD6: 0x80AF, //CJK UNIFIED IDEOGRAPH + 0xAAD7: 0x81E5, //CJK UNIFIED IDEOGRAPH + 0xAAD8: 0x81FE, //CJK UNIFIED IDEOGRAPH + 0xAAD9: 0x820D, //CJK UNIFIED IDEOGRAPH + 0xAADA: 0x82B3, //CJK UNIFIED IDEOGRAPH + 0xAADB: 0x829D, //CJK UNIFIED IDEOGRAPH + 0xAADC: 0x8299, //CJK UNIFIED IDEOGRAPH + 0xAADD: 0x82AD, //CJK UNIFIED IDEOGRAPH + 0xAADE: 0x82BD, //CJK UNIFIED IDEOGRAPH + 0xAADF: 0x829F, //CJK UNIFIED IDEOGRAPH + 0xAAE0: 0x82B9, //CJK UNIFIED IDEOGRAPH + 0xAAE1: 0x82B1, //CJK UNIFIED IDEOGRAPH + 0xAAE2: 0x82AC, //CJK UNIFIED IDEOGRAPH + 0xAAE3: 0x82A5, //CJK UNIFIED IDEOGRAPH + 0xAAE4: 0x82AF, //CJK UNIFIED IDEOGRAPH + 0xAAE5: 0x82B8, //CJK UNIFIED IDEOGRAPH + 0xAAE6: 0x82A3, //CJK UNIFIED IDEOGRAPH + 0xAAE7: 0x82B0, //CJK UNIFIED IDEOGRAPH + 0xAAE8: 0x82BE, //CJK UNIFIED IDEOGRAPH + 0xAAE9: 0x82B7, //CJK UNIFIED IDEOGRAPH + 0xAAEA: 0x864E, //CJK UNIFIED IDEOGRAPH + 0xAAEB: 0x8671, //CJK UNIFIED IDEOGRAPH + 0xAAEC: 0x521D, //CJK UNIFIED IDEOGRAPH + 0xAAED: 0x8868, //CJK UNIFIED IDEOGRAPH + 0xAAEE: 0x8ECB, //CJK UNIFIED IDEOGRAPH + 0xAAEF: 0x8FCE, //CJK UNIFIED IDEOGRAPH + 0xAAF0: 0x8FD4, //CJK UNIFIED IDEOGRAPH + 0xAAF1: 0x8FD1, //CJK UNIFIED IDEOGRAPH + 0xAAF2: 0x90B5, //CJK UNIFIED IDEOGRAPH + 0xAAF3: 0x90B8, //CJK UNIFIED IDEOGRAPH + 0xAAF4: 0x90B1, //CJK UNIFIED IDEOGRAPH + 0xAAF5: 0x90B6, //CJK UNIFIED IDEOGRAPH + 0xAAF6: 0x91C7, //CJK UNIFIED IDEOGRAPH + 0xAAF7: 0x91D1, //CJK UNIFIED IDEOGRAPH + 0xAAF8: 0x9577, //CJK UNIFIED IDEOGRAPH + 0xAAF9: 0x9580, //CJK UNIFIED IDEOGRAPH + 0xAAFA: 0x961C, //CJK UNIFIED IDEOGRAPH + 0xAAFB: 0x9640, //CJK UNIFIED IDEOGRAPH + 0xAAFC: 0x963F, //CJK UNIFIED IDEOGRAPH + 0xAAFD: 0x963B, //CJK UNIFIED IDEOGRAPH + 0xAAFE: 0x9644, //CJK UNIFIED IDEOGRAPH + 0xAB40: 0x9642, //CJK UNIFIED IDEOGRAPH + 0xAB41: 0x96B9, //CJK UNIFIED IDEOGRAPH + 0xAB42: 0x96E8, //CJK UNIFIED IDEOGRAPH + 0xAB43: 0x9752, //CJK UNIFIED IDEOGRAPH + 0xAB44: 0x975E, //CJK UNIFIED IDEOGRAPH + 0xAB45: 0x4E9F, //CJK UNIFIED IDEOGRAPH + 0xAB46: 0x4EAD, //CJK UNIFIED IDEOGRAPH + 0xAB47: 0x4EAE, //CJK UNIFIED IDEOGRAPH + 0xAB48: 0x4FE1, //CJK UNIFIED IDEOGRAPH + 0xAB49: 0x4FB5, //CJK UNIFIED IDEOGRAPH + 0xAB4A: 0x4FAF, //CJK UNIFIED IDEOGRAPH + 0xAB4B: 0x4FBF, //CJK UNIFIED IDEOGRAPH + 0xAB4C: 0x4FE0, //CJK UNIFIED IDEOGRAPH + 0xAB4D: 0x4FD1, //CJK UNIFIED IDEOGRAPH + 0xAB4E: 0x4FCF, //CJK UNIFIED IDEOGRAPH + 0xAB4F: 0x4FDD, //CJK UNIFIED IDEOGRAPH + 0xAB50: 0x4FC3, //CJK UNIFIED IDEOGRAPH + 0xAB51: 0x4FB6, //CJK UNIFIED IDEOGRAPH + 0xAB52: 0x4FD8, //CJK UNIFIED IDEOGRAPH + 0xAB53: 0x4FDF, //CJK UNIFIED IDEOGRAPH + 0xAB54: 0x4FCA, //CJK UNIFIED IDEOGRAPH + 0xAB55: 0x4FD7, //CJK UNIFIED IDEOGRAPH + 0xAB56: 0x4FAE, //CJK UNIFIED IDEOGRAPH + 0xAB57: 0x4FD0, //CJK UNIFIED IDEOGRAPH + 0xAB58: 0x4FC4, //CJK UNIFIED IDEOGRAPH + 0xAB59: 0x4FC2, //CJK UNIFIED IDEOGRAPH + 0xAB5A: 0x4FDA, //CJK UNIFIED IDEOGRAPH + 0xAB5B: 0x4FCE, //CJK UNIFIED IDEOGRAPH + 0xAB5C: 0x4FDE, //CJK UNIFIED IDEOGRAPH + 0xAB5D: 0x4FB7, //CJK UNIFIED IDEOGRAPH + 0xAB5E: 0x5157, //CJK UNIFIED IDEOGRAPH + 0xAB5F: 0x5192, //CJK UNIFIED IDEOGRAPH + 0xAB60: 0x5191, //CJK UNIFIED IDEOGRAPH + 0xAB61: 0x51A0, //CJK UNIFIED IDEOGRAPH + 0xAB62: 0x524E, //CJK UNIFIED IDEOGRAPH + 0xAB63: 0x5243, //CJK UNIFIED IDEOGRAPH + 0xAB64: 0x524A, //CJK UNIFIED IDEOGRAPH + 0xAB65: 0x524D, //CJK UNIFIED IDEOGRAPH + 0xAB66: 0x524C, //CJK UNIFIED IDEOGRAPH + 0xAB67: 0x524B, //CJK UNIFIED IDEOGRAPH + 0xAB68: 0x5247, //CJK UNIFIED IDEOGRAPH + 0xAB69: 0x52C7, //CJK UNIFIED IDEOGRAPH + 0xAB6A: 0x52C9, //CJK UNIFIED IDEOGRAPH + 0xAB6B: 0x52C3, //CJK UNIFIED IDEOGRAPH + 0xAB6C: 0x52C1, //CJK UNIFIED IDEOGRAPH + 0xAB6D: 0x530D, //CJK UNIFIED IDEOGRAPH + 0xAB6E: 0x5357, //CJK UNIFIED IDEOGRAPH + 0xAB6F: 0x537B, //CJK UNIFIED IDEOGRAPH + 0xAB70: 0x539A, //CJK UNIFIED IDEOGRAPH + 0xAB71: 0x53DB, //CJK UNIFIED IDEOGRAPH + 0xAB72: 0x54AC, //CJK UNIFIED IDEOGRAPH + 0xAB73: 0x54C0, //CJK UNIFIED IDEOGRAPH + 0xAB74: 0x54A8, //CJK UNIFIED IDEOGRAPH + 0xAB75: 0x54CE, //CJK UNIFIED IDEOGRAPH + 0xAB76: 0x54C9, //CJK UNIFIED IDEOGRAPH + 0xAB77: 0x54B8, //CJK UNIFIED IDEOGRAPH + 0xAB78: 0x54A6, //CJK UNIFIED IDEOGRAPH + 0xAB79: 0x54B3, //CJK UNIFIED IDEOGRAPH + 0xAB7A: 0x54C7, //CJK UNIFIED IDEOGRAPH + 0xAB7B: 0x54C2, //CJK UNIFIED IDEOGRAPH + 0xAB7C: 0x54BD, //CJK UNIFIED IDEOGRAPH + 0xAB7D: 0x54AA, //CJK UNIFIED IDEOGRAPH + 0xAB7E: 0x54C1, //CJK UNIFIED IDEOGRAPH + 0xABA1: 0x54C4, //CJK UNIFIED IDEOGRAPH + 0xABA2: 0x54C8, //CJK UNIFIED IDEOGRAPH + 0xABA3: 0x54AF, //CJK UNIFIED IDEOGRAPH + 0xABA4: 0x54AB, //CJK UNIFIED IDEOGRAPH + 0xABA5: 0x54B1, //CJK UNIFIED IDEOGRAPH + 0xABA6: 0x54BB, //CJK UNIFIED IDEOGRAPH + 0xABA7: 0x54A9, //CJK UNIFIED IDEOGRAPH + 0xABA8: 0x54A7, //CJK UNIFIED IDEOGRAPH + 0xABA9: 0x54BF, //CJK UNIFIED IDEOGRAPH + 0xABAA: 0x56FF, //CJK UNIFIED IDEOGRAPH + 0xABAB: 0x5782, //CJK UNIFIED IDEOGRAPH + 0xABAC: 0x578B, //CJK UNIFIED IDEOGRAPH + 0xABAD: 0x57A0, //CJK UNIFIED IDEOGRAPH + 0xABAE: 0x57A3, //CJK UNIFIED IDEOGRAPH + 0xABAF: 0x57A2, //CJK UNIFIED IDEOGRAPH + 0xABB0: 0x57CE, //CJK UNIFIED IDEOGRAPH + 0xABB1: 0x57AE, //CJK UNIFIED IDEOGRAPH + 0xABB2: 0x5793, //CJK UNIFIED IDEOGRAPH + 0xABB3: 0x5955, //CJK UNIFIED IDEOGRAPH + 0xABB4: 0x5951, //CJK UNIFIED IDEOGRAPH + 0xABB5: 0x594F, //CJK UNIFIED IDEOGRAPH + 0xABB6: 0x594E, //CJK UNIFIED IDEOGRAPH + 0xABB7: 0x5950, //CJK UNIFIED IDEOGRAPH + 0xABB8: 0x59DC, //CJK UNIFIED IDEOGRAPH + 0xABB9: 0x59D8, //CJK UNIFIED IDEOGRAPH + 0xABBA: 0x59FF, //CJK UNIFIED IDEOGRAPH + 0xABBB: 0x59E3, //CJK UNIFIED IDEOGRAPH + 0xABBC: 0x59E8, //CJK UNIFIED IDEOGRAPH + 0xABBD: 0x5A03, //CJK UNIFIED IDEOGRAPH + 0xABBE: 0x59E5, //CJK UNIFIED IDEOGRAPH + 0xABBF: 0x59EA, //CJK UNIFIED IDEOGRAPH + 0xABC0: 0x59DA, //CJK UNIFIED IDEOGRAPH + 0xABC1: 0x59E6, //CJK UNIFIED IDEOGRAPH + 0xABC2: 0x5A01, //CJK UNIFIED IDEOGRAPH + 0xABC3: 0x59FB, //CJK UNIFIED IDEOGRAPH + 0xABC4: 0x5B69, //CJK UNIFIED IDEOGRAPH + 0xABC5: 0x5BA3, //CJK UNIFIED IDEOGRAPH + 0xABC6: 0x5BA6, //CJK UNIFIED IDEOGRAPH + 0xABC7: 0x5BA4, //CJK UNIFIED IDEOGRAPH + 0xABC8: 0x5BA2, //CJK UNIFIED IDEOGRAPH + 0xABC9: 0x5BA5, //CJK UNIFIED IDEOGRAPH + 0xABCA: 0x5C01, //CJK UNIFIED IDEOGRAPH + 0xABCB: 0x5C4E, //CJK UNIFIED IDEOGRAPH + 0xABCC: 0x5C4F, //CJK UNIFIED IDEOGRAPH + 0xABCD: 0x5C4D, //CJK UNIFIED IDEOGRAPH + 0xABCE: 0x5C4B, //CJK UNIFIED IDEOGRAPH + 0xABCF: 0x5CD9, //CJK UNIFIED IDEOGRAPH + 0xABD0: 0x5CD2, //CJK UNIFIED IDEOGRAPH + 0xABD1: 0x5DF7, //CJK UNIFIED IDEOGRAPH + 0xABD2: 0x5E1D, //CJK UNIFIED IDEOGRAPH + 0xABD3: 0x5E25, //CJK UNIFIED IDEOGRAPH + 0xABD4: 0x5E1F, //CJK UNIFIED IDEOGRAPH + 0xABD5: 0x5E7D, //CJK UNIFIED IDEOGRAPH + 0xABD6: 0x5EA0, //CJK UNIFIED IDEOGRAPH + 0xABD7: 0x5EA6, //CJK UNIFIED IDEOGRAPH + 0xABD8: 0x5EFA, //CJK UNIFIED IDEOGRAPH + 0xABD9: 0x5F08, //CJK UNIFIED IDEOGRAPH + 0xABDA: 0x5F2D, //CJK UNIFIED IDEOGRAPH + 0xABDB: 0x5F65, //CJK UNIFIED IDEOGRAPH + 0xABDC: 0x5F88, //CJK UNIFIED IDEOGRAPH + 0xABDD: 0x5F85, //CJK UNIFIED IDEOGRAPH + 0xABDE: 0x5F8A, //CJK UNIFIED IDEOGRAPH + 0xABDF: 0x5F8B, //CJK UNIFIED IDEOGRAPH + 0xABE0: 0x5F87, //CJK UNIFIED IDEOGRAPH + 0xABE1: 0x5F8C, //CJK UNIFIED IDEOGRAPH + 0xABE2: 0x5F89, //CJK UNIFIED IDEOGRAPH + 0xABE3: 0x6012, //CJK UNIFIED IDEOGRAPH + 0xABE4: 0x601D, //CJK UNIFIED IDEOGRAPH + 0xABE5: 0x6020, //CJK UNIFIED IDEOGRAPH + 0xABE6: 0x6025, //CJK UNIFIED IDEOGRAPH + 0xABE7: 0x600E, //CJK UNIFIED IDEOGRAPH + 0xABE8: 0x6028, //CJK UNIFIED IDEOGRAPH + 0xABE9: 0x604D, //CJK UNIFIED IDEOGRAPH + 0xABEA: 0x6070, //CJK UNIFIED IDEOGRAPH + 0xABEB: 0x6068, //CJK UNIFIED IDEOGRAPH + 0xABEC: 0x6062, //CJK UNIFIED IDEOGRAPH + 0xABED: 0x6046, //CJK UNIFIED IDEOGRAPH + 0xABEE: 0x6043, //CJK UNIFIED IDEOGRAPH + 0xABEF: 0x606C, //CJK UNIFIED IDEOGRAPH + 0xABF0: 0x606B, //CJK UNIFIED IDEOGRAPH + 0xABF1: 0x606A, //CJK UNIFIED IDEOGRAPH + 0xABF2: 0x6064, //CJK UNIFIED IDEOGRAPH + 0xABF3: 0x6241, //CJK UNIFIED IDEOGRAPH + 0xABF4: 0x62DC, //CJK UNIFIED IDEOGRAPH + 0xABF5: 0x6316, //CJK UNIFIED IDEOGRAPH + 0xABF6: 0x6309, //CJK UNIFIED IDEOGRAPH + 0xABF7: 0x62FC, //CJK UNIFIED IDEOGRAPH + 0xABF8: 0x62ED, //CJK UNIFIED IDEOGRAPH + 0xABF9: 0x6301, //CJK UNIFIED IDEOGRAPH + 0xABFA: 0x62EE, //CJK UNIFIED IDEOGRAPH + 0xABFB: 0x62FD, //CJK UNIFIED IDEOGRAPH + 0xABFC: 0x6307, //CJK UNIFIED IDEOGRAPH + 0xABFD: 0x62F1, //CJK UNIFIED IDEOGRAPH + 0xABFE: 0x62F7, //CJK UNIFIED IDEOGRAPH + 0xAC40: 0x62EF, //CJK UNIFIED IDEOGRAPH + 0xAC41: 0x62EC, //CJK UNIFIED IDEOGRAPH + 0xAC42: 0x62FE, //CJK UNIFIED IDEOGRAPH + 0xAC43: 0x62F4, //CJK UNIFIED IDEOGRAPH + 0xAC44: 0x6311, //CJK UNIFIED IDEOGRAPH + 0xAC45: 0x6302, //CJK UNIFIED IDEOGRAPH + 0xAC46: 0x653F, //CJK UNIFIED IDEOGRAPH + 0xAC47: 0x6545, //CJK UNIFIED IDEOGRAPH + 0xAC48: 0x65AB, //CJK UNIFIED IDEOGRAPH + 0xAC49: 0x65BD, //CJK UNIFIED IDEOGRAPH + 0xAC4A: 0x65E2, //CJK UNIFIED IDEOGRAPH + 0xAC4B: 0x6625, //CJK UNIFIED IDEOGRAPH + 0xAC4C: 0x662D, //CJK UNIFIED IDEOGRAPH + 0xAC4D: 0x6620, //CJK UNIFIED IDEOGRAPH + 0xAC4E: 0x6627, //CJK UNIFIED IDEOGRAPH + 0xAC4F: 0x662F, //CJK UNIFIED IDEOGRAPH + 0xAC50: 0x661F, //CJK UNIFIED IDEOGRAPH + 0xAC51: 0x6628, //CJK UNIFIED IDEOGRAPH + 0xAC52: 0x6631, //CJK UNIFIED IDEOGRAPH + 0xAC53: 0x6624, //CJK UNIFIED IDEOGRAPH + 0xAC54: 0x66F7, //CJK UNIFIED IDEOGRAPH + 0xAC55: 0x67FF, //CJK UNIFIED IDEOGRAPH + 0xAC56: 0x67D3, //CJK UNIFIED IDEOGRAPH + 0xAC57: 0x67F1, //CJK UNIFIED IDEOGRAPH + 0xAC58: 0x67D4, //CJK UNIFIED IDEOGRAPH + 0xAC59: 0x67D0, //CJK UNIFIED IDEOGRAPH + 0xAC5A: 0x67EC, //CJK UNIFIED IDEOGRAPH + 0xAC5B: 0x67B6, //CJK UNIFIED IDEOGRAPH + 0xAC5C: 0x67AF, //CJK UNIFIED IDEOGRAPH + 0xAC5D: 0x67F5, //CJK UNIFIED IDEOGRAPH + 0xAC5E: 0x67E9, //CJK UNIFIED IDEOGRAPH + 0xAC5F: 0x67EF, //CJK UNIFIED IDEOGRAPH + 0xAC60: 0x67C4, //CJK UNIFIED IDEOGRAPH + 0xAC61: 0x67D1, //CJK UNIFIED IDEOGRAPH + 0xAC62: 0x67B4, //CJK UNIFIED IDEOGRAPH + 0xAC63: 0x67DA, //CJK UNIFIED IDEOGRAPH + 0xAC64: 0x67E5, //CJK UNIFIED IDEOGRAPH + 0xAC65: 0x67B8, //CJK UNIFIED IDEOGRAPH + 0xAC66: 0x67CF, //CJK UNIFIED IDEOGRAPH + 0xAC67: 0x67DE, //CJK UNIFIED IDEOGRAPH + 0xAC68: 0x67F3, //CJK UNIFIED IDEOGRAPH + 0xAC69: 0x67B0, //CJK UNIFIED IDEOGRAPH + 0xAC6A: 0x67D9, //CJK UNIFIED IDEOGRAPH + 0xAC6B: 0x67E2, //CJK UNIFIED IDEOGRAPH + 0xAC6C: 0x67DD, //CJK UNIFIED IDEOGRAPH + 0xAC6D: 0x67D2, //CJK UNIFIED IDEOGRAPH + 0xAC6E: 0x6B6A, //CJK UNIFIED IDEOGRAPH + 0xAC6F: 0x6B83, //CJK UNIFIED IDEOGRAPH + 0xAC70: 0x6B86, //CJK UNIFIED IDEOGRAPH + 0xAC71: 0x6BB5, //CJK UNIFIED IDEOGRAPH + 0xAC72: 0x6BD2, //CJK UNIFIED IDEOGRAPH + 0xAC73: 0x6BD7, //CJK UNIFIED IDEOGRAPH + 0xAC74: 0x6C1F, //CJK UNIFIED IDEOGRAPH + 0xAC75: 0x6CC9, //CJK UNIFIED IDEOGRAPH + 0xAC76: 0x6D0B, //CJK UNIFIED IDEOGRAPH + 0xAC77: 0x6D32, //CJK UNIFIED IDEOGRAPH + 0xAC78: 0x6D2A, //CJK UNIFIED IDEOGRAPH + 0xAC79: 0x6D41, //CJK UNIFIED IDEOGRAPH + 0xAC7A: 0x6D25, //CJK UNIFIED IDEOGRAPH + 0xAC7B: 0x6D0C, //CJK UNIFIED IDEOGRAPH + 0xAC7C: 0x6D31, //CJK UNIFIED IDEOGRAPH + 0xAC7D: 0x6D1E, //CJK UNIFIED IDEOGRAPH + 0xAC7E: 0x6D17, //CJK UNIFIED IDEOGRAPH + 0xACA1: 0x6D3B, //CJK UNIFIED IDEOGRAPH + 0xACA2: 0x6D3D, //CJK UNIFIED IDEOGRAPH + 0xACA3: 0x6D3E, //CJK UNIFIED IDEOGRAPH + 0xACA4: 0x6D36, //CJK UNIFIED IDEOGRAPH + 0xACA5: 0x6D1B, //CJK UNIFIED IDEOGRAPH + 0xACA6: 0x6CF5, //CJK UNIFIED IDEOGRAPH + 0xACA7: 0x6D39, //CJK UNIFIED IDEOGRAPH + 0xACA8: 0x6D27, //CJK UNIFIED IDEOGRAPH + 0xACA9: 0x6D38, //CJK UNIFIED IDEOGRAPH + 0xACAA: 0x6D29, //CJK UNIFIED IDEOGRAPH + 0xACAB: 0x6D2E, //CJK UNIFIED IDEOGRAPH + 0xACAC: 0x6D35, //CJK UNIFIED IDEOGRAPH + 0xACAD: 0x6D0E, //CJK UNIFIED IDEOGRAPH + 0xACAE: 0x6D2B, //CJK UNIFIED IDEOGRAPH + 0xACAF: 0x70AB, //CJK UNIFIED IDEOGRAPH + 0xACB0: 0x70BA, //CJK UNIFIED IDEOGRAPH + 0xACB1: 0x70B3, //CJK UNIFIED IDEOGRAPH + 0xACB2: 0x70AC, //CJK UNIFIED IDEOGRAPH + 0xACB3: 0x70AF, //CJK UNIFIED IDEOGRAPH + 0xACB4: 0x70AD, //CJK UNIFIED IDEOGRAPH + 0xACB5: 0x70B8, //CJK UNIFIED IDEOGRAPH + 0xACB6: 0x70AE, //CJK UNIFIED IDEOGRAPH + 0xACB7: 0x70A4, //CJK UNIFIED IDEOGRAPH + 0xACB8: 0x7230, //CJK UNIFIED IDEOGRAPH + 0xACB9: 0x7272, //CJK UNIFIED IDEOGRAPH + 0xACBA: 0x726F, //CJK UNIFIED IDEOGRAPH + 0xACBB: 0x7274, //CJK UNIFIED IDEOGRAPH + 0xACBC: 0x72E9, //CJK UNIFIED IDEOGRAPH + 0xACBD: 0x72E0, //CJK UNIFIED IDEOGRAPH + 0xACBE: 0x72E1, //CJK UNIFIED IDEOGRAPH + 0xACBF: 0x73B7, //CJK UNIFIED IDEOGRAPH + 0xACC0: 0x73CA, //CJK UNIFIED IDEOGRAPH + 0xACC1: 0x73BB, //CJK UNIFIED IDEOGRAPH + 0xACC2: 0x73B2, //CJK UNIFIED IDEOGRAPH + 0xACC3: 0x73CD, //CJK UNIFIED IDEOGRAPH + 0xACC4: 0x73C0, //CJK UNIFIED IDEOGRAPH + 0xACC5: 0x73B3, //CJK UNIFIED IDEOGRAPH + 0xACC6: 0x751A, //CJK UNIFIED IDEOGRAPH + 0xACC7: 0x752D, //CJK UNIFIED IDEOGRAPH + 0xACC8: 0x754F, //CJK UNIFIED IDEOGRAPH + 0xACC9: 0x754C, //CJK UNIFIED IDEOGRAPH + 0xACCA: 0x754E, //CJK UNIFIED IDEOGRAPH + 0xACCB: 0x754B, //CJK UNIFIED IDEOGRAPH + 0xACCC: 0x75AB, //CJK UNIFIED IDEOGRAPH + 0xACCD: 0x75A4, //CJK UNIFIED IDEOGRAPH + 0xACCE: 0x75A5, //CJK UNIFIED IDEOGRAPH + 0xACCF: 0x75A2, //CJK UNIFIED IDEOGRAPH + 0xACD0: 0x75A3, //CJK UNIFIED IDEOGRAPH + 0xACD1: 0x7678, //CJK UNIFIED IDEOGRAPH + 0xACD2: 0x7686, //CJK UNIFIED IDEOGRAPH + 0xACD3: 0x7687, //CJK UNIFIED IDEOGRAPH + 0xACD4: 0x7688, //CJK UNIFIED IDEOGRAPH + 0xACD5: 0x76C8, //CJK UNIFIED IDEOGRAPH + 0xACD6: 0x76C6, //CJK UNIFIED IDEOGRAPH + 0xACD7: 0x76C3, //CJK UNIFIED IDEOGRAPH + 0xACD8: 0x76C5, //CJK UNIFIED IDEOGRAPH + 0xACD9: 0x7701, //CJK UNIFIED IDEOGRAPH + 0xACDA: 0x76F9, //CJK UNIFIED IDEOGRAPH + 0xACDB: 0x76F8, //CJK UNIFIED IDEOGRAPH + 0xACDC: 0x7709, //CJK UNIFIED IDEOGRAPH + 0xACDD: 0x770B, //CJK UNIFIED IDEOGRAPH + 0xACDE: 0x76FE, //CJK UNIFIED IDEOGRAPH + 0xACDF: 0x76FC, //CJK UNIFIED IDEOGRAPH + 0xACE0: 0x7707, //CJK UNIFIED IDEOGRAPH + 0xACE1: 0x77DC, //CJK UNIFIED IDEOGRAPH + 0xACE2: 0x7802, //CJK UNIFIED IDEOGRAPH + 0xACE3: 0x7814, //CJK UNIFIED IDEOGRAPH + 0xACE4: 0x780C, //CJK UNIFIED IDEOGRAPH + 0xACE5: 0x780D, //CJK UNIFIED IDEOGRAPH + 0xACE6: 0x7946, //CJK UNIFIED IDEOGRAPH + 0xACE7: 0x7949, //CJK UNIFIED IDEOGRAPH + 0xACE8: 0x7948, //CJK UNIFIED IDEOGRAPH + 0xACE9: 0x7947, //CJK UNIFIED IDEOGRAPH + 0xACEA: 0x79B9, //CJK UNIFIED IDEOGRAPH + 0xACEB: 0x79BA, //CJK UNIFIED IDEOGRAPH + 0xACEC: 0x79D1, //CJK UNIFIED IDEOGRAPH + 0xACED: 0x79D2, //CJK UNIFIED IDEOGRAPH + 0xACEE: 0x79CB, //CJK UNIFIED IDEOGRAPH + 0xACEF: 0x7A7F, //CJK UNIFIED IDEOGRAPH + 0xACF0: 0x7A81, //CJK UNIFIED IDEOGRAPH + 0xACF1: 0x7AFF, //CJK UNIFIED IDEOGRAPH + 0xACF2: 0x7AFD, //CJK UNIFIED IDEOGRAPH + 0xACF3: 0x7C7D, //CJK UNIFIED IDEOGRAPH + 0xACF4: 0x7D02, //CJK UNIFIED IDEOGRAPH + 0xACF5: 0x7D05, //CJK UNIFIED IDEOGRAPH + 0xACF6: 0x7D00, //CJK UNIFIED IDEOGRAPH + 0xACF7: 0x7D09, //CJK UNIFIED IDEOGRAPH + 0xACF8: 0x7D07, //CJK UNIFIED IDEOGRAPH + 0xACF9: 0x7D04, //CJK UNIFIED IDEOGRAPH + 0xACFA: 0x7D06, //CJK UNIFIED IDEOGRAPH + 0xACFB: 0x7F38, //CJK UNIFIED IDEOGRAPH + 0xACFC: 0x7F8E, //CJK UNIFIED IDEOGRAPH + 0xACFD: 0x7FBF, //CJK UNIFIED IDEOGRAPH + 0xACFE: 0x8004, //CJK UNIFIED IDEOGRAPH + 0xAD40: 0x8010, //CJK UNIFIED IDEOGRAPH + 0xAD41: 0x800D, //CJK UNIFIED IDEOGRAPH + 0xAD42: 0x8011, //CJK UNIFIED IDEOGRAPH + 0xAD43: 0x8036, //CJK UNIFIED IDEOGRAPH + 0xAD44: 0x80D6, //CJK UNIFIED IDEOGRAPH + 0xAD45: 0x80E5, //CJK UNIFIED IDEOGRAPH + 0xAD46: 0x80DA, //CJK UNIFIED IDEOGRAPH + 0xAD47: 0x80C3, //CJK UNIFIED IDEOGRAPH + 0xAD48: 0x80C4, //CJK UNIFIED IDEOGRAPH + 0xAD49: 0x80CC, //CJK UNIFIED IDEOGRAPH + 0xAD4A: 0x80E1, //CJK UNIFIED IDEOGRAPH + 0xAD4B: 0x80DB, //CJK UNIFIED IDEOGRAPH + 0xAD4C: 0x80CE, //CJK UNIFIED IDEOGRAPH + 0xAD4D: 0x80DE, //CJK UNIFIED IDEOGRAPH + 0xAD4E: 0x80E4, //CJK UNIFIED IDEOGRAPH + 0xAD4F: 0x80DD, //CJK UNIFIED IDEOGRAPH + 0xAD50: 0x81F4, //CJK UNIFIED IDEOGRAPH + 0xAD51: 0x8222, //CJK UNIFIED IDEOGRAPH + 0xAD52: 0x82E7, //CJK UNIFIED IDEOGRAPH + 0xAD53: 0x8303, //CJK UNIFIED IDEOGRAPH + 0xAD54: 0x8305, //CJK UNIFIED IDEOGRAPH + 0xAD55: 0x82E3, //CJK UNIFIED IDEOGRAPH + 0xAD56: 0x82DB, //CJK UNIFIED IDEOGRAPH + 0xAD57: 0x82E6, //CJK UNIFIED IDEOGRAPH + 0xAD58: 0x8304, //CJK UNIFIED IDEOGRAPH + 0xAD59: 0x82E5, //CJK UNIFIED IDEOGRAPH + 0xAD5A: 0x8302, //CJK UNIFIED IDEOGRAPH + 0xAD5B: 0x8309, //CJK UNIFIED IDEOGRAPH + 0xAD5C: 0x82D2, //CJK UNIFIED IDEOGRAPH + 0xAD5D: 0x82D7, //CJK UNIFIED IDEOGRAPH + 0xAD5E: 0x82F1, //CJK UNIFIED IDEOGRAPH + 0xAD5F: 0x8301, //CJK UNIFIED IDEOGRAPH + 0xAD60: 0x82DC, //CJK UNIFIED IDEOGRAPH + 0xAD61: 0x82D4, //CJK UNIFIED IDEOGRAPH + 0xAD62: 0x82D1, //CJK UNIFIED IDEOGRAPH + 0xAD63: 0x82DE, //CJK UNIFIED IDEOGRAPH + 0xAD64: 0x82D3, //CJK UNIFIED IDEOGRAPH + 0xAD65: 0x82DF, //CJK UNIFIED IDEOGRAPH + 0xAD66: 0x82EF, //CJK UNIFIED IDEOGRAPH + 0xAD67: 0x8306, //CJK UNIFIED IDEOGRAPH + 0xAD68: 0x8650, //CJK UNIFIED IDEOGRAPH + 0xAD69: 0x8679, //CJK UNIFIED IDEOGRAPH + 0xAD6A: 0x867B, //CJK UNIFIED IDEOGRAPH + 0xAD6B: 0x867A, //CJK UNIFIED IDEOGRAPH + 0xAD6C: 0x884D, //CJK UNIFIED IDEOGRAPH + 0xAD6D: 0x886B, //CJK UNIFIED IDEOGRAPH + 0xAD6E: 0x8981, //CJK UNIFIED IDEOGRAPH + 0xAD6F: 0x89D4, //CJK UNIFIED IDEOGRAPH + 0xAD70: 0x8A08, //CJK UNIFIED IDEOGRAPH + 0xAD71: 0x8A02, //CJK UNIFIED IDEOGRAPH + 0xAD72: 0x8A03, //CJK UNIFIED IDEOGRAPH + 0xAD73: 0x8C9E, //CJK UNIFIED IDEOGRAPH + 0xAD74: 0x8CA0, //CJK UNIFIED IDEOGRAPH + 0xAD75: 0x8D74, //CJK UNIFIED IDEOGRAPH + 0xAD76: 0x8D73, //CJK UNIFIED IDEOGRAPH + 0xAD77: 0x8DB4, //CJK UNIFIED IDEOGRAPH + 0xAD78: 0x8ECD, //CJK UNIFIED IDEOGRAPH + 0xAD79: 0x8ECC, //CJK UNIFIED IDEOGRAPH + 0xAD7A: 0x8FF0, //CJK UNIFIED IDEOGRAPH + 0xAD7B: 0x8FE6, //CJK UNIFIED IDEOGRAPH + 0xAD7C: 0x8FE2, //CJK UNIFIED IDEOGRAPH + 0xAD7D: 0x8FEA, //CJK UNIFIED IDEOGRAPH + 0xAD7E: 0x8FE5, //CJK UNIFIED IDEOGRAPH + 0xADA1: 0x8FED, //CJK UNIFIED IDEOGRAPH + 0xADA2: 0x8FEB, //CJK UNIFIED IDEOGRAPH + 0xADA3: 0x8FE4, //CJK UNIFIED IDEOGRAPH + 0xADA4: 0x8FE8, //CJK UNIFIED IDEOGRAPH + 0xADA5: 0x90CA, //CJK UNIFIED IDEOGRAPH + 0xADA6: 0x90CE, //CJK UNIFIED IDEOGRAPH + 0xADA7: 0x90C1, //CJK UNIFIED IDEOGRAPH + 0xADA8: 0x90C3, //CJK UNIFIED IDEOGRAPH + 0xADA9: 0x914B, //CJK UNIFIED IDEOGRAPH + 0xADAA: 0x914A, //CJK UNIFIED IDEOGRAPH + 0xADAB: 0x91CD, //CJK UNIFIED IDEOGRAPH + 0xADAC: 0x9582, //CJK UNIFIED IDEOGRAPH + 0xADAD: 0x9650, //CJK UNIFIED IDEOGRAPH + 0xADAE: 0x964B, //CJK UNIFIED IDEOGRAPH + 0xADAF: 0x964C, //CJK UNIFIED IDEOGRAPH + 0xADB0: 0x964D, //CJK UNIFIED IDEOGRAPH + 0xADB1: 0x9762, //CJK UNIFIED IDEOGRAPH + 0xADB2: 0x9769, //CJK UNIFIED IDEOGRAPH + 0xADB3: 0x97CB, //CJK UNIFIED IDEOGRAPH + 0xADB4: 0x97ED, //CJK UNIFIED IDEOGRAPH + 0xADB5: 0x97F3, //CJK UNIFIED IDEOGRAPH + 0xADB6: 0x9801, //CJK UNIFIED IDEOGRAPH + 0xADB7: 0x98A8, //CJK UNIFIED IDEOGRAPH + 0xADB8: 0x98DB, //CJK UNIFIED IDEOGRAPH + 0xADB9: 0x98DF, //CJK UNIFIED IDEOGRAPH + 0xADBA: 0x9996, //CJK UNIFIED IDEOGRAPH + 0xADBB: 0x9999, //CJK UNIFIED IDEOGRAPH + 0xADBC: 0x4E58, //CJK UNIFIED IDEOGRAPH + 0xADBD: 0x4EB3, //CJK UNIFIED IDEOGRAPH + 0xADBE: 0x500C, //CJK UNIFIED IDEOGRAPH + 0xADBF: 0x500D, //CJK UNIFIED IDEOGRAPH + 0xADC0: 0x5023, //CJK UNIFIED IDEOGRAPH + 0xADC1: 0x4FEF, //CJK UNIFIED IDEOGRAPH + 0xADC2: 0x5026, //CJK UNIFIED IDEOGRAPH + 0xADC3: 0x5025, //CJK UNIFIED IDEOGRAPH + 0xADC4: 0x4FF8, //CJK UNIFIED IDEOGRAPH + 0xADC5: 0x5029, //CJK UNIFIED IDEOGRAPH + 0xADC6: 0x5016, //CJK UNIFIED IDEOGRAPH + 0xADC7: 0x5006, //CJK UNIFIED IDEOGRAPH + 0xADC8: 0x503C, //CJK UNIFIED IDEOGRAPH + 0xADC9: 0x501F, //CJK UNIFIED IDEOGRAPH + 0xADCA: 0x501A, //CJK UNIFIED IDEOGRAPH + 0xADCB: 0x5012, //CJK UNIFIED IDEOGRAPH + 0xADCC: 0x5011, //CJK UNIFIED IDEOGRAPH + 0xADCD: 0x4FFA, //CJK UNIFIED IDEOGRAPH + 0xADCE: 0x5000, //CJK UNIFIED IDEOGRAPH + 0xADCF: 0x5014, //CJK UNIFIED IDEOGRAPH + 0xADD0: 0x5028, //CJK UNIFIED IDEOGRAPH + 0xADD1: 0x4FF1, //CJK UNIFIED IDEOGRAPH + 0xADD2: 0x5021, //CJK UNIFIED IDEOGRAPH + 0xADD3: 0x500B, //CJK UNIFIED IDEOGRAPH + 0xADD4: 0x5019, //CJK UNIFIED IDEOGRAPH + 0xADD5: 0x5018, //CJK UNIFIED IDEOGRAPH + 0xADD6: 0x4FF3, //CJK UNIFIED IDEOGRAPH + 0xADD7: 0x4FEE, //CJK UNIFIED IDEOGRAPH + 0xADD8: 0x502D, //CJK UNIFIED IDEOGRAPH + 0xADD9: 0x502A, //CJK UNIFIED IDEOGRAPH + 0xADDA: 0x4FFE, //CJK UNIFIED IDEOGRAPH + 0xADDB: 0x502B, //CJK UNIFIED IDEOGRAPH + 0xADDC: 0x5009, //CJK UNIFIED IDEOGRAPH + 0xADDD: 0x517C, //CJK UNIFIED IDEOGRAPH + 0xADDE: 0x51A4, //CJK UNIFIED IDEOGRAPH + 0xADDF: 0x51A5, //CJK UNIFIED IDEOGRAPH + 0xADE0: 0x51A2, //CJK UNIFIED IDEOGRAPH + 0xADE1: 0x51CD, //CJK UNIFIED IDEOGRAPH + 0xADE2: 0x51CC, //CJK UNIFIED IDEOGRAPH + 0xADE3: 0x51C6, //CJK UNIFIED IDEOGRAPH + 0xADE4: 0x51CB, //CJK UNIFIED IDEOGRAPH + 0xADE5: 0x5256, //CJK UNIFIED IDEOGRAPH + 0xADE6: 0x525C, //CJK UNIFIED IDEOGRAPH + 0xADE7: 0x5254, //CJK UNIFIED IDEOGRAPH + 0xADE8: 0x525B, //CJK UNIFIED IDEOGRAPH + 0xADE9: 0x525D, //CJK UNIFIED IDEOGRAPH + 0xADEA: 0x532A, //CJK UNIFIED IDEOGRAPH + 0xADEB: 0x537F, //CJK UNIFIED IDEOGRAPH + 0xADEC: 0x539F, //CJK UNIFIED IDEOGRAPH + 0xADED: 0x539D, //CJK UNIFIED IDEOGRAPH + 0xADEE: 0x53DF, //CJK UNIFIED IDEOGRAPH + 0xADEF: 0x54E8, //CJK UNIFIED IDEOGRAPH + 0xADF0: 0x5510, //CJK UNIFIED IDEOGRAPH + 0xADF1: 0x5501, //CJK UNIFIED IDEOGRAPH + 0xADF2: 0x5537, //CJK UNIFIED IDEOGRAPH + 0xADF3: 0x54FC, //CJK UNIFIED IDEOGRAPH + 0xADF4: 0x54E5, //CJK UNIFIED IDEOGRAPH + 0xADF5: 0x54F2, //CJK UNIFIED IDEOGRAPH + 0xADF6: 0x5506, //CJK UNIFIED IDEOGRAPH + 0xADF7: 0x54FA, //CJK UNIFIED IDEOGRAPH + 0xADF8: 0x5514, //CJK UNIFIED IDEOGRAPH + 0xADF9: 0x54E9, //CJK UNIFIED IDEOGRAPH + 0xADFA: 0x54ED, //CJK UNIFIED IDEOGRAPH + 0xADFB: 0x54E1, //CJK UNIFIED IDEOGRAPH + 0xADFC: 0x5509, //CJK UNIFIED IDEOGRAPH + 0xADFD: 0x54EE, //CJK UNIFIED IDEOGRAPH + 0xADFE: 0x54EA, //CJK UNIFIED IDEOGRAPH + 0xAE40: 0x54E6, //CJK UNIFIED IDEOGRAPH + 0xAE41: 0x5527, //CJK UNIFIED IDEOGRAPH + 0xAE42: 0x5507, //CJK UNIFIED IDEOGRAPH + 0xAE43: 0x54FD, //CJK UNIFIED IDEOGRAPH + 0xAE44: 0x550F, //CJK UNIFIED IDEOGRAPH + 0xAE45: 0x5703, //CJK UNIFIED IDEOGRAPH + 0xAE46: 0x5704, //CJK UNIFIED IDEOGRAPH + 0xAE47: 0x57C2, //CJK UNIFIED IDEOGRAPH + 0xAE48: 0x57D4, //CJK UNIFIED IDEOGRAPH + 0xAE49: 0x57CB, //CJK UNIFIED IDEOGRAPH + 0xAE4A: 0x57C3, //CJK UNIFIED IDEOGRAPH + 0xAE4B: 0x5809, //CJK UNIFIED IDEOGRAPH + 0xAE4C: 0x590F, //CJK UNIFIED IDEOGRAPH + 0xAE4D: 0x5957, //CJK UNIFIED IDEOGRAPH + 0xAE4E: 0x5958, //CJK UNIFIED IDEOGRAPH + 0xAE4F: 0x595A, //CJK UNIFIED IDEOGRAPH + 0xAE50: 0x5A11, //CJK UNIFIED IDEOGRAPH + 0xAE51: 0x5A18, //CJK UNIFIED IDEOGRAPH + 0xAE52: 0x5A1C, //CJK UNIFIED IDEOGRAPH + 0xAE53: 0x5A1F, //CJK UNIFIED IDEOGRAPH + 0xAE54: 0x5A1B, //CJK UNIFIED IDEOGRAPH + 0xAE55: 0x5A13, //CJK UNIFIED IDEOGRAPH + 0xAE56: 0x59EC, //CJK UNIFIED IDEOGRAPH + 0xAE57: 0x5A20, //CJK UNIFIED IDEOGRAPH + 0xAE58: 0x5A23, //CJK UNIFIED IDEOGRAPH + 0xAE59: 0x5A29, //CJK UNIFIED IDEOGRAPH + 0xAE5A: 0x5A25, //CJK UNIFIED IDEOGRAPH + 0xAE5B: 0x5A0C, //CJK UNIFIED IDEOGRAPH + 0xAE5C: 0x5A09, //CJK UNIFIED IDEOGRAPH + 0xAE5D: 0x5B6B, //CJK UNIFIED IDEOGRAPH + 0xAE5E: 0x5C58, //CJK UNIFIED IDEOGRAPH + 0xAE5F: 0x5BB0, //CJK UNIFIED IDEOGRAPH + 0xAE60: 0x5BB3, //CJK UNIFIED IDEOGRAPH + 0xAE61: 0x5BB6, //CJK UNIFIED IDEOGRAPH + 0xAE62: 0x5BB4, //CJK UNIFIED IDEOGRAPH + 0xAE63: 0x5BAE, //CJK UNIFIED IDEOGRAPH + 0xAE64: 0x5BB5, //CJK UNIFIED IDEOGRAPH + 0xAE65: 0x5BB9, //CJK UNIFIED IDEOGRAPH + 0xAE66: 0x5BB8, //CJK UNIFIED IDEOGRAPH + 0xAE67: 0x5C04, //CJK UNIFIED IDEOGRAPH + 0xAE68: 0x5C51, //CJK UNIFIED IDEOGRAPH + 0xAE69: 0x5C55, //CJK UNIFIED IDEOGRAPH + 0xAE6A: 0x5C50, //CJK UNIFIED IDEOGRAPH + 0xAE6B: 0x5CED, //CJK UNIFIED IDEOGRAPH + 0xAE6C: 0x5CFD, //CJK UNIFIED IDEOGRAPH + 0xAE6D: 0x5CFB, //CJK UNIFIED IDEOGRAPH + 0xAE6E: 0x5CEA, //CJK UNIFIED IDEOGRAPH + 0xAE6F: 0x5CE8, //CJK UNIFIED IDEOGRAPH + 0xAE70: 0x5CF0, //CJK UNIFIED IDEOGRAPH + 0xAE71: 0x5CF6, //CJK UNIFIED IDEOGRAPH + 0xAE72: 0x5D01, //CJK UNIFIED IDEOGRAPH + 0xAE73: 0x5CF4, //CJK UNIFIED IDEOGRAPH + 0xAE74: 0x5DEE, //CJK UNIFIED IDEOGRAPH + 0xAE75: 0x5E2D, //CJK UNIFIED IDEOGRAPH + 0xAE76: 0x5E2B, //CJK UNIFIED IDEOGRAPH + 0xAE77: 0x5EAB, //CJK UNIFIED IDEOGRAPH + 0xAE78: 0x5EAD, //CJK UNIFIED IDEOGRAPH + 0xAE79: 0x5EA7, //CJK UNIFIED IDEOGRAPH + 0xAE7A: 0x5F31, //CJK UNIFIED IDEOGRAPH + 0xAE7B: 0x5F92, //CJK UNIFIED IDEOGRAPH + 0xAE7C: 0x5F91, //CJK UNIFIED IDEOGRAPH + 0xAE7D: 0x5F90, //CJK UNIFIED IDEOGRAPH + 0xAE7E: 0x6059, //CJK UNIFIED IDEOGRAPH + 0xAEA1: 0x6063, //CJK UNIFIED IDEOGRAPH + 0xAEA2: 0x6065, //CJK UNIFIED IDEOGRAPH + 0xAEA3: 0x6050, //CJK UNIFIED IDEOGRAPH + 0xAEA4: 0x6055, //CJK UNIFIED IDEOGRAPH + 0xAEA5: 0x606D, //CJK UNIFIED IDEOGRAPH + 0xAEA6: 0x6069, //CJK UNIFIED IDEOGRAPH + 0xAEA7: 0x606F, //CJK UNIFIED IDEOGRAPH + 0xAEA8: 0x6084, //CJK UNIFIED IDEOGRAPH + 0xAEA9: 0x609F, //CJK UNIFIED IDEOGRAPH + 0xAEAA: 0x609A, //CJK UNIFIED IDEOGRAPH + 0xAEAB: 0x608D, //CJK UNIFIED IDEOGRAPH + 0xAEAC: 0x6094, //CJK UNIFIED IDEOGRAPH + 0xAEAD: 0x608C, //CJK UNIFIED IDEOGRAPH + 0xAEAE: 0x6085, //CJK UNIFIED IDEOGRAPH + 0xAEAF: 0x6096, //CJK UNIFIED IDEOGRAPH + 0xAEB0: 0x6247, //CJK UNIFIED IDEOGRAPH + 0xAEB1: 0x62F3, //CJK UNIFIED IDEOGRAPH + 0xAEB2: 0x6308, //CJK UNIFIED IDEOGRAPH + 0xAEB3: 0x62FF, //CJK UNIFIED IDEOGRAPH + 0xAEB4: 0x634E, //CJK UNIFIED IDEOGRAPH + 0xAEB5: 0x633E, //CJK UNIFIED IDEOGRAPH + 0xAEB6: 0x632F, //CJK UNIFIED IDEOGRAPH + 0xAEB7: 0x6355, //CJK UNIFIED IDEOGRAPH + 0xAEB8: 0x6342, //CJK UNIFIED IDEOGRAPH + 0xAEB9: 0x6346, //CJK UNIFIED IDEOGRAPH + 0xAEBA: 0x634F, //CJK UNIFIED IDEOGRAPH + 0xAEBB: 0x6349, //CJK UNIFIED IDEOGRAPH + 0xAEBC: 0x633A, //CJK UNIFIED IDEOGRAPH + 0xAEBD: 0x6350, //CJK UNIFIED IDEOGRAPH + 0xAEBE: 0x633D, //CJK UNIFIED IDEOGRAPH + 0xAEBF: 0x632A, //CJK UNIFIED IDEOGRAPH + 0xAEC0: 0x632B, //CJK UNIFIED IDEOGRAPH + 0xAEC1: 0x6328, //CJK UNIFIED IDEOGRAPH + 0xAEC2: 0x634D, //CJK UNIFIED IDEOGRAPH + 0xAEC3: 0x634C, //CJK UNIFIED IDEOGRAPH + 0xAEC4: 0x6548, //CJK UNIFIED IDEOGRAPH + 0xAEC5: 0x6549, //CJK UNIFIED IDEOGRAPH + 0xAEC6: 0x6599, //CJK UNIFIED IDEOGRAPH + 0xAEC7: 0x65C1, //CJK UNIFIED IDEOGRAPH + 0xAEC8: 0x65C5, //CJK UNIFIED IDEOGRAPH + 0xAEC9: 0x6642, //CJK UNIFIED IDEOGRAPH + 0xAECA: 0x6649, //CJK UNIFIED IDEOGRAPH + 0xAECB: 0x664F, //CJK UNIFIED IDEOGRAPH + 0xAECC: 0x6643, //CJK UNIFIED IDEOGRAPH + 0xAECD: 0x6652, //CJK UNIFIED IDEOGRAPH + 0xAECE: 0x664C, //CJK UNIFIED IDEOGRAPH + 0xAECF: 0x6645, //CJK UNIFIED IDEOGRAPH + 0xAED0: 0x6641, //CJK UNIFIED IDEOGRAPH + 0xAED1: 0x66F8, //CJK UNIFIED IDEOGRAPH + 0xAED2: 0x6714, //CJK UNIFIED IDEOGRAPH + 0xAED3: 0x6715, //CJK UNIFIED IDEOGRAPH + 0xAED4: 0x6717, //CJK UNIFIED IDEOGRAPH + 0xAED5: 0x6821, //CJK UNIFIED IDEOGRAPH + 0xAED6: 0x6838, //CJK UNIFIED IDEOGRAPH + 0xAED7: 0x6848, //CJK UNIFIED IDEOGRAPH + 0xAED8: 0x6846, //CJK UNIFIED IDEOGRAPH + 0xAED9: 0x6853, //CJK UNIFIED IDEOGRAPH + 0xAEDA: 0x6839, //CJK UNIFIED IDEOGRAPH + 0xAEDB: 0x6842, //CJK UNIFIED IDEOGRAPH + 0xAEDC: 0x6854, //CJK UNIFIED IDEOGRAPH + 0xAEDD: 0x6829, //CJK UNIFIED IDEOGRAPH + 0xAEDE: 0x68B3, //CJK UNIFIED IDEOGRAPH + 0xAEDF: 0x6817, //CJK UNIFIED IDEOGRAPH + 0xAEE0: 0x684C, //CJK UNIFIED IDEOGRAPH + 0xAEE1: 0x6851, //CJK UNIFIED IDEOGRAPH + 0xAEE2: 0x683D, //CJK UNIFIED IDEOGRAPH + 0xAEE3: 0x67F4, //CJK UNIFIED IDEOGRAPH + 0xAEE4: 0x6850, //CJK UNIFIED IDEOGRAPH + 0xAEE5: 0x6840, //CJK UNIFIED IDEOGRAPH + 0xAEE6: 0x683C, //CJK UNIFIED IDEOGRAPH + 0xAEE7: 0x6843, //CJK UNIFIED IDEOGRAPH + 0xAEE8: 0x682A, //CJK UNIFIED IDEOGRAPH + 0xAEE9: 0x6845, //CJK UNIFIED IDEOGRAPH + 0xAEEA: 0x6813, //CJK UNIFIED IDEOGRAPH + 0xAEEB: 0x6818, //CJK UNIFIED IDEOGRAPH + 0xAEEC: 0x6841, //CJK UNIFIED IDEOGRAPH + 0xAEED: 0x6B8A, //CJK UNIFIED IDEOGRAPH + 0xAEEE: 0x6B89, //CJK UNIFIED IDEOGRAPH + 0xAEEF: 0x6BB7, //CJK UNIFIED IDEOGRAPH + 0xAEF0: 0x6C23, //CJK UNIFIED IDEOGRAPH + 0xAEF1: 0x6C27, //CJK UNIFIED IDEOGRAPH + 0xAEF2: 0x6C28, //CJK UNIFIED IDEOGRAPH + 0xAEF3: 0x6C26, //CJK UNIFIED IDEOGRAPH + 0xAEF4: 0x6C24, //CJK UNIFIED IDEOGRAPH + 0xAEF5: 0x6CF0, //CJK UNIFIED IDEOGRAPH + 0xAEF6: 0x6D6A, //CJK UNIFIED IDEOGRAPH + 0xAEF7: 0x6D95, //CJK UNIFIED IDEOGRAPH + 0xAEF8: 0x6D88, //CJK UNIFIED IDEOGRAPH + 0xAEF9: 0x6D87, //CJK UNIFIED IDEOGRAPH + 0xAEFA: 0x6D66, //CJK UNIFIED IDEOGRAPH + 0xAEFB: 0x6D78, //CJK UNIFIED IDEOGRAPH + 0xAEFC: 0x6D77, //CJK UNIFIED IDEOGRAPH + 0xAEFD: 0x6D59, //CJK UNIFIED IDEOGRAPH + 0xAEFE: 0x6D93, //CJK UNIFIED IDEOGRAPH + 0xAF40: 0x6D6C, //CJK UNIFIED IDEOGRAPH + 0xAF41: 0x6D89, //CJK UNIFIED IDEOGRAPH + 0xAF42: 0x6D6E, //CJK UNIFIED IDEOGRAPH + 0xAF43: 0x6D5A, //CJK UNIFIED IDEOGRAPH + 0xAF44: 0x6D74, //CJK UNIFIED IDEOGRAPH + 0xAF45: 0x6D69, //CJK UNIFIED IDEOGRAPH + 0xAF46: 0x6D8C, //CJK UNIFIED IDEOGRAPH + 0xAF47: 0x6D8A, //CJK UNIFIED IDEOGRAPH + 0xAF48: 0x6D79, //CJK UNIFIED IDEOGRAPH + 0xAF49: 0x6D85, //CJK UNIFIED IDEOGRAPH + 0xAF4A: 0x6D65, //CJK UNIFIED IDEOGRAPH + 0xAF4B: 0x6D94, //CJK UNIFIED IDEOGRAPH + 0xAF4C: 0x70CA, //CJK UNIFIED IDEOGRAPH + 0xAF4D: 0x70D8, //CJK UNIFIED IDEOGRAPH + 0xAF4E: 0x70E4, //CJK UNIFIED IDEOGRAPH + 0xAF4F: 0x70D9, //CJK UNIFIED IDEOGRAPH + 0xAF50: 0x70C8, //CJK UNIFIED IDEOGRAPH + 0xAF51: 0x70CF, //CJK UNIFIED IDEOGRAPH + 0xAF52: 0x7239, //CJK UNIFIED IDEOGRAPH + 0xAF53: 0x7279, //CJK UNIFIED IDEOGRAPH + 0xAF54: 0x72FC, //CJK UNIFIED IDEOGRAPH + 0xAF55: 0x72F9, //CJK UNIFIED IDEOGRAPH + 0xAF56: 0x72FD, //CJK UNIFIED IDEOGRAPH + 0xAF57: 0x72F8, //CJK UNIFIED IDEOGRAPH + 0xAF58: 0x72F7, //CJK UNIFIED IDEOGRAPH + 0xAF59: 0x7386, //CJK UNIFIED IDEOGRAPH + 0xAF5A: 0x73ED, //CJK UNIFIED IDEOGRAPH + 0xAF5B: 0x7409, //CJK UNIFIED IDEOGRAPH + 0xAF5C: 0x73EE, //CJK UNIFIED IDEOGRAPH + 0xAF5D: 0x73E0, //CJK UNIFIED IDEOGRAPH + 0xAF5E: 0x73EA, //CJK UNIFIED IDEOGRAPH + 0xAF5F: 0x73DE, //CJK UNIFIED IDEOGRAPH + 0xAF60: 0x7554, //CJK UNIFIED IDEOGRAPH + 0xAF61: 0x755D, //CJK UNIFIED IDEOGRAPH + 0xAF62: 0x755C, //CJK UNIFIED IDEOGRAPH + 0xAF63: 0x755A, //CJK UNIFIED IDEOGRAPH + 0xAF64: 0x7559, //CJK UNIFIED IDEOGRAPH + 0xAF65: 0x75BE, //CJK UNIFIED IDEOGRAPH + 0xAF66: 0x75C5, //CJK UNIFIED IDEOGRAPH + 0xAF67: 0x75C7, //CJK UNIFIED IDEOGRAPH + 0xAF68: 0x75B2, //CJK UNIFIED IDEOGRAPH + 0xAF69: 0x75B3, //CJK UNIFIED IDEOGRAPH + 0xAF6A: 0x75BD, //CJK UNIFIED IDEOGRAPH + 0xAF6B: 0x75BC, //CJK UNIFIED IDEOGRAPH + 0xAF6C: 0x75B9, //CJK UNIFIED IDEOGRAPH + 0xAF6D: 0x75C2, //CJK UNIFIED IDEOGRAPH + 0xAF6E: 0x75B8, //CJK UNIFIED IDEOGRAPH + 0xAF6F: 0x768B, //CJK UNIFIED IDEOGRAPH + 0xAF70: 0x76B0, //CJK UNIFIED IDEOGRAPH + 0xAF71: 0x76CA, //CJK UNIFIED IDEOGRAPH + 0xAF72: 0x76CD, //CJK UNIFIED IDEOGRAPH + 0xAF73: 0x76CE, //CJK UNIFIED IDEOGRAPH + 0xAF74: 0x7729, //CJK UNIFIED IDEOGRAPH + 0xAF75: 0x771F, //CJK UNIFIED IDEOGRAPH + 0xAF76: 0x7720, //CJK UNIFIED IDEOGRAPH + 0xAF77: 0x7728, //CJK UNIFIED IDEOGRAPH + 0xAF78: 0x77E9, //CJK UNIFIED IDEOGRAPH + 0xAF79: 0x7830, //CJK UNIFIED IDEOGRAPH + 0xAF7A: 0x7827, //CJK UNIFIED IDEOGRAPH + 0xAF7B: 0x7838, //CJK UNIFIED IDEOGRAPH + 0xAF7C: 0x781D, //CJK UNIFIED IDEOGRAPH + 0xAF7D: 0x7834, //CJK UNIFIED IDEOGRAPH + 0xAF7E: 0x7837, //CJK UNIFIED IDEOGRAPH + 0xAFA1: 0x7825, //CJK UNIFIED IDEOGRAPH + 0xAFA2: 0x782D, //CJK UNIFIED IDEOGRAPH + 0xAFA3: 0x7820, //CJK UNIFIED IDEOGRAPH + 0xAFA4: 0x781F, //CJK UNIFIED IDEOGRAPH + 0xAFA5: 0x7832, //CJK UNIFIED IDEOGRAPH + 0xAFA6: 0x7955, //CJK UNIFIED IDEOGRAPH + 0xAFA7: 0x7950, //CJK UNIFIED IDEOGRAPH + 0xAFA8: 0x7960, //CJK UNIFIED IDEOGRAPH + 0xAFA9: 0x795F, //CJK UNIFIED IDEOGRAPH + 0xAFAA: 0x7956, //CJK UNIFIED IDEOGRAPH + 0xAFAB: 0x795E, //CJK UNIFIED IDEOGRAPH + 0xAFAC: 0x795D, //CJK UNIFIED IDEOGRAPH + 0xAFAD: 0x7957, //CJK UNIFIED IDEOGRAPH + 0xAFAE: 0x795A, //CJK UNIFIED IDEOGRAPH + 0xAFAF: 0x79E4, //CJK UNIFIED IDEOGRAPH + 0xAFB0: 0x79E3, //CJK UNIFIED IDEOGRAPH + 0xAFB1: 0x79E7, //CJK UNIFIED IDEOGRAPH + 0xAFB2: 0x79DF, //CJK UNIFIED IDEOGRAPH + 0xAFB3: 0x79E6, //CJK UNIFIED IDEOGRAPH + 0xAFB4: 0x79E9, //CJK UNIFIED IDEOGRAPH + 0xAFB5: 0x79D8, //CJK UNIFIED IDEOGRAPH + 0xAFB6: 0x7A84, //CJK UNIFIED IDEOGRAPH + 0xAFB7: 0x7A88, //CJK UNIFIED IDEOGRAPH + 0xAFB8: 0x7AD9, //CJK UNIFIED IDEOGRAPH + 0xAFB9: 0x7B06, //CJK UNIFIED IDEOGRAPH + 0xAFBA: 0x7B11, //CJK UNIFIED IDEOGRAPH + 0xAFBB: 0x7C89, //CJK UNIFIED IDEOGRAPH + 0xAFBC: 0x7D21, //CJK UNIFIED IDEOGRAPH + 0xAFBD: 0x7D17, //CJK UNIFIED IDEOGRAPH + 0xAFBE: 0x7D0B, //CJK UNIFIED IDEOGRAPH + 0xAFBF: 0x7D0A, //CJK UNIFIED IDEOGRAPH + 0xAFC0: 0x7D20, //CJK UNIFIED IDEOGRAPH + 0xAFC1: 0x7D22, //CJK UNIFIED IDEOGRAPH + 0xAFC2: 0x7D14, //CJK UNIFIED IDEOGRAPH + 0xAFC3: 0x7D10, //CJK UNIFIED IDEOGRAPH + 0xAFC4: 0x7D15, //CJK UNIFIED IDEOGRAPH + 0xAFC5: 0x7D1A, //CJK UNIFIED IDEOGRAPH + 0xAFC6: 0x7D1C, //CJK UNIFIED IDEOGRAPH + 0xAFC7: 0x7D0D, //CJK UNIFIED IDEOGRAPH + 0xAFC8: 0x7D19, //CJK UNIFIED IDEOGRAPH + 0xAFC9: 0x7D1B, //CJK UNIFIED IDEOGRAPH + 0xAFCA: 0x7F3A, //CJK UNIFIED IDEOGRAPH + 0xAFCB: 0x7F5F, //CJK UNIFIED IDEOGRAPH + 0xAFCC: 0x7F94, //CJK UNIFIED IDEOGRAPH + 0xAFCD: 0x7FC5, //CJK UNIFIED IDEOGRAPH + 0xAFCE: 0x7FC1, //CJK UNIFIED IDEOGRAPH + 0xAFCF: 0x8006, //CJK UNIFIED IDEOGRAPH + 0xAFD0: 0x8018, //CJK UNIFIED IDEOGRAPH + 0xAFD1: 0x8015, //CJK UNIFIED IDEOGRAPH + 0xAFD2: 0x8019, //CJK UNIFIED IDEOGRAPH + 0xAFD3: 0x8017, //CJK UNIFIED IDEOGRAPH + 0xAFD4: 0x803D, //CJK UNIFIED IDEOGRAPH + 0xAFD5: 0x803F, //CJK UNIFIED IDEOGRAPH + 0xAFD6: 0x80F1, //CJK UNIFIED IDEOGRAPH + 0xAFD7: 0x8102, //CJK UNIFIED IDEOGRAPH + 0xAFD8: 0x80F0, //CJK UNIFIED IDEOGRAPH + 0xAFD9: 0x8105, //CJK UNIFIED IDEOGRAPH + 0xAFDA: 0x80ED, //CJK UNIFIED IDEOGRAPH + 0xAFDB: 0x80F4, //CJK UNIFIED IDEOGRAPH + 0xAFDC: 0x8106, //CJK UNIFIED IDEOGRAPH + 0xAFDD: 0x80F8, //CJK UNIFIED IDEOGRAPH + 0xAFDE: 0x80F3, //CJK UNIFIED IDEOGRAPH + 0xAFDF: 0x8108, //CJK UNIFIED IDEOGRAPH + 0xAFE0: 0x80FD, //CJK UNIFIED IDEOGRAPH + 0xAFE1: 0x810A, //CJK UNIFIED IDEOGRAPH + 0xAFE2: 0x80FC, //CJK UNIFIED IDEOGRAPH + 0xAFE3: 0x80EF, //CJK UNIFIED IDEOGRAPH + 0xAFE4: 0x81ED, //CJK UNIFIED IDEOGRAPH + 0xAFE5: 0x81EC, //CJK UNIFIED IDEOGRAPH + 0xAFE6: 0x8200, //CJK UNIFIED IDEOGRAPH + 0xAFE7: 0x8210, //CJK UNIFIED IDEOGRAPH + 0xAFE8: 0x822A, //CJK UNIFIED IDEOGRAPH + 0xAFE9: 0x822B, //CJK UNIFIED IDEOGRAPH + 0xAFEA: 0x8228, //CJK UNIFIED IDEOGRAPH + 0xAFEB: 0x822C, //CJK UNIFIED IDEOGRAPH + 0xAFEC: 0x82BB, //CJK UNIFIED IDEOGRAPH + 0xAFED: 0x832B, //CJK UNIFIED IDEOGRAPH + 0xAFEE: 0x8352, //CJK UNIFIED IDEOGRAPH + 0xAFEF: 0x8354, //CJK UNIFIED IDEOGRAPH + 0xAFF0: 0x834A, //CJK UNIFIED IDEOGRAPH + 0xAFF1: 0x8338, //CJK UNIFIED IDEOGRAPH + 0xAFF2: 0x8350, //CJK UNIFIED IDEOGRAPH + 0xAFF3: 0x8349, //CJK UNIFIED IDEOGRAPH + 0xAFF4: 0x8335, //CJK UNIFIED IDEOGRAPH + 0xAFF5: 0x8334, //CJK UNIFIED IDEOGRAPH + 0xAFF6: 0x834F, //CJK UNIFIED IDEOGRAPH + 0xAFF7: 0x8332, //CJK UNIFIED IDEOGRAPH + 0xAFF8: 0x8339, //CJK UNIFIED IDEOGRAPH + 0xAFF9: 0x8336, //CJK UNIFIED IDEOGRAPH + 0xAFFA: 0x8317, //CJK UNIFIED IDEOGRAPH + 0xAFFB: 0x8340, //CJK UNIFIED IDEOGRAPH + 0xAFFC: 0x8331, //CJK UNIFIED IDEOGRAPH + 0xAFFD: 0x8328, //CJK UNIFIED IDEOGRAPH + 0xAFFE: 0x8343, //CJK UNIFIED IDEOGRAPH + 0xB040: 0x8654, //CJK UNIFIED IDEOGRAPH + 0xB041: 0x868A, //CJK UNIFIED IDEOGRAPH + 0xB042: 0x86AA, //CJK UNIFIED IDEOGRAPH + 0xB043: 0x8693, //CJK UNIFIED IDEOGRAPH + 0xB044: 0x86A4, //CJK UNIFIED IDEOGRAPH + 0xB045: 0x86A9, //CJK UNIFIED IDEOGRAPH + 0xB046: 0x868C, //CJK UNIFIED IDEOGRAPH + 0xB047: 0x86A3, //CJK UNIFIED IDEOGRAPH + 0xB048: 0x869C, //CJK UNIFIED IDEOGRAPH + 0xB049: 0x8870, //CJK UNIFIED IDEOGRAPH + 0xB04A: 0x8877, //CJK UNIFIED IDEOGRAPH + 0xB04B: 0x8881, //CJK UNIFIED IDEOGRAPH + 0xB04C: 0x8882, //CJK UNIFIED IDEOGRAPH + 0xB04D: 0x887D, //CJK UNIFIED IDEOGRAPH + 0xB04E: 0x8879, //CJK UNIFIED IDEOGRAPH + 0xB04F: 0x8A18, //CJK UNIFIED IDEOGRAPH + 0xB050: 0x8A10, //CJK UNIFIED IDEOGRAPH + 0xB051: 0x8A0E, //CJK UNIFIED IDEOGRAPH + 0xB052: 0x8A0C, //CJK UNIFIED IDEOGRAPH + 0xB053: 0x8A15, //CJK UNIFIED IDEOGRAPH + 0xB054: 0x8A0A, //CJK UNIFIED IDEOGRAPH + 0xB055: 0x8A17, //CJK UNIFIED IDEOGRAPH + 0xB056: 0x8A13, //CJK UNIFIED IDEOGRAPH + 0xB057: 0x8A16, //CJK UNIFIED IDEOGRAPH + 0xB058: 0x8A0F, //CJK UNIFIED IDEOGRAPH + 0xB059: 0x8A11, //CJK UNIFIED IDEOGRAPH + 0xB05A: 0x8C48, //CJK UNIFIED IDEOGRAPH + 0xB05B: 0x8C7A, //CJK UNIFIED IDEOGRAPH + 0xB05C: 0x8C79, //CJK UNIFIED IDEOGRAPH + 0xB05D: 0x8CA1, //CJK UNIFIED IDEOGRAPH + 0xB05E: 0x8CA2, //CJK UNIFIED IDEOGRAPH + 0xB05F: 0x8D77, //CJK UNIFIED IDEOGRAPH + 0xB060: 0x8EAC, //CJK UNIFIED IDEOGRAPH + 0xB061: 0x8ED2, //CJK UNIFIED IDEOGRAPH + 0xB062: 0x8ED4, //CJK UNIFIED IDEOGRAPH + 0xB063: 0x8ECF, //CJK UNIFIED IDEOGRAPH + 0xB064: 0x8FB1, //CJK UNIFIED IDEOGRAPH + 0xB065: 0x9001, //CJK UNIFIED IDEOGRAPH + 0xB066: 0x9006, //CJK UNIFIED IDEOGRAPH + 0xB067: 0x8FF7, //CJK UNIFIED IDEOGRAPH + 0xB068: 0x9000, //CJK UNIFIED IDEOGRAPH + 0xB069: 0x8FFA, //CJK UNIFIED IDEOGRAPH + 0xB06A: 0x8FF4, //CJK UNIFIED IDEOGRAPH + 0xB06B: 0x9003, //CJK UNIFIED IDEOGRAPH + 0xB06C: 0x8FFD, //CJK UNIFIED IDEOGRAPH + 0xB06D: 0x9005, //CJK UNIFIED IDEOGRAPH + 0xB06E: 0x8FF8, //CJK UNIFIED IDEOGRAPH + 0xB06F: 0x9095, //CJK UNIFIED IDEOGRAPH + 0xB070: 0x90E1, //CJK UNIFIED IDEOGRAPH + 0xB071: 0x90DD, //CJK UNIFIED IDEOGRAPH + 0xB072: 0x90E2, //CJK UNIFIED IDEOGRAPH + 0xB073: 0x9152, //CJK UNIFIED IDEOGRAPH + 0xB074: 0x914D, //CJK UNIFIED IDEOGRAPH + 0xB075: 0x914C, //CJK UNIFIED IDEOGRAPH + 0xB076: 0x91D8, //CJK UNIFIED IDEOGRAPH + 0xB077: 0x91DD, //CJK UNIFIED IDEOGRAPH + 0xB078: 0x91D7, //CJK UNIFIED IDEOGRAPH + 0xB079: 0x91DC, //CJK UNIFIED IDEOGRAPH + 0xB07A: 0x91D9, //CJK UNIFIED IDEOGRAPH + 0xB07B: 0x9583, //CJK UNIFIED IDEOGRAPH + 0xB07C: 0x9662, //CJK UNIFIED IDEOGRAPH + 0xB07D: 0x9663, //CJK UNIFIED IDEOGRAPH + 0xB07E: 0x9661, //CJK UNIFIED IDEOGRAPH + 0xB0A1: 0x965B, //CJK UNIFIED IDEOGRAPH + 0xB0A2: 0x965D, //CJK UNIFIED IDEOGRAPH + 0xB0A3: 0x9664, //CJK UNIFIED IDEOGRAPH + 0xB0A4: 0x9658, //CJK UNIFIED IDEOGRAPH + 0xB0A5: 0x965E, //CJK UNIFIED IDEOGRAPH + 0xB0A6: 0x96BB, //CJK UNIFIED IDEOGRAPH + 0xB0A7: 0x98E2, //CJK UNIFIED IDEOGRAPH + 0xB0A8: 0x99AC, //CJK UNIFIED IDEOGRAPH + 0xB0A9: 0x9AA8, //CJK UNIFIED IDEOGRAPH + 0xB0AA: 0x9AD8, //CJK UNIFIED IDEOGRAPH + 0xB0AB: 0x9B25, //CJK UNIFIED IDEOGRAPH + 0xB0AC: 0x9B32, //CJK UNIFIED IDEOGRAPH + 0xB0AD: 0x9B3C, //CJK UNIFIED IDEOGRAPH + 0xB0AE: 0x4E7E, //CJK UNIFIED IDEOGRAPH + 0xB0AF: 0x507A, //CJK UNIFIED IDEOGRAPH + 0xB0B0: 0x507D, //CJK UNIFIED IDEOGRAPH + 0xB0B1: 0x505C, //CJK UNIFIED IDEOGRAPH + 0xB0B2: 0x5047, //CJK UNIFIED IDEOGRAPH + 0xB0B3: 0x5043, //CJK UNIFIED IDEOGRAPH + 0xB0B4: 0x504C, //CJK UNIFIED IDEOGRAPH + 0xB0B5: 0x505A, //CJK UNIFIED IDEOGRAPH + 0xB0B6: 0x5049, //CJK UNIFIED IDEOGRAPH + 0xB0B7: 0x5065, //CJK UNIFIED IDEOGRAPH + 0xB0B8: 0x5076, //CJK UNIFIED IDEOGRAPH + 0xB0B9: 0x504E, //CJK UNIFIED IDEOGRAPH + 0xB0BA: 0x5055, //CJK UNIFIED IDEOGRAPH + 0xB0BB: 0x5075, //CJK UNIFIED IDEOGRAPH + 0xB0BC: 0x5074, //CJK UNIFIED IDEOGRAPH + 0xB0BD: 0x5077, //CJK UNIFIED IDEOGRAPH + 0xB0BE: 0x504F, //CJK UNIFIED IDEOGRAPH + 0xB0BF: 0x500F, //CJK UNIFIED IDEOGRAPH + 0xB0C0: 0x506F, //CJK UNIFIED IDEOGRAPH + 0xB0C1: 0x506D, //CJK UNIFIED IDEOGRAPH + 0xB0C2: 0x515C, //CJK UNIFIED IDEOGRAPH + 0xB0C3: 0x5195, //CJK UNIFIED IDEOGRAPH + 0xB0C4: 0x51F0, //CJK UNIFIED IDEOGRAPH + 0xB0C5: 0x526A, //CJK UNIFIED IDEOGRAPH + 0xB0C6: 0x526F, //CJK UNIFIED IDEOGRAPH + 0xB0C7: 0x52D2, //CJK UNIFIED IDEOGRAPH + 0xB0C8: 0x52D9, //CJK UNIFIED IDEOGRAPH + 0xB0C9: 0x52D8, //CJK UNIFIED IDEOGRAPH + 0xB0CA: 0x52D5, //CJK UNIFIED IDEOGRAPH + 0xB0CB: 0x5310, //CJK UNIFIED IDEOGRAPH + 0xB0CC: 0x530F, //CJK UNIFIED IDEOGRAPH + 0xB0CD: 0x5319, //CJK UNIFIED IDEOGRAPH + 0xB0CE: 0x533F, //CJK UNIFIED IDEOGRAPH + 0xB0CF: 0x5340, //CJK UNIFIED IDEOGRAPH + 0xB0D0: 0x533E, //CJK UNIFIED IDEOGRAPH + 0xB0D1: 0x53C3, //CJK UNIFIED IDEOGRAPH + 0xB0D2: 0x66FC, //CJK UNIFIED IDEOGRAPH + 0xB0D3: 0x5546, //CJK UNIFIED IDEOGRAPH + 0xB0D4: 0x556A, //CJK UNIFIED IDEOGRAPH + 0xB0D5: 0x5566, //CJK UNIFIED IDEOGRAPH + 0xB0D6: 0x5544, //CJK UNIFIED IDEOGRAPH + 0xB0D7: 0x555E, //CJK UNIFIED IDEOGRAPH + 0xB0D8: 0x5561, //CJK UNIFIED IDEOGRAPH + 0xB0D9: 0x5543, //CJK UNIFIED IDEOGRAPH + 0xB0DA: 0x554A, //CJK UNIFIED IDEOGRAPH + 0xB0DB: 0x5531, //CJK UNIFIED IDEOGRAPH + 0xB0DC: 0x5556, //CJK UNIFIED IDEOGRAPH + 0xB0DD: 0x554F, //CJK UNIFIED IDEOGRAPH + 0xB0DE: 0x5555, //CJK UNIFIED IDEOGRAPH + 0xB0DF: 0x552F, //CJK UNIFIED IDEOGRAPH + 0xB0E0: 0x5564, //CJK UNIFIED IDEOGRAPH + 0xB0E1: 0x5538, //CJK UNIFIED IDEOGRAPH + 0xB0E2: 0x552E, //CJK UNIFIED IDEOGRAPH + 0xB0E3: 0x555C, //CJK UNIFIED IDEOGRAPH + 0xB0E4: 0x552C, //CJK UNIFIED IDEOGRAPH + 0xB0E5: 0x5563, //CJK UNIFIED IDEOGRAPH + 0xB0E6: 0x5533, //CJK UNIFIED IDEOGRAPH + 0xB0E7: 0x5541, //CJK UNIFIED IDEOGRAPH + 0xB0E8: 0x5557, //CJK UNIFIED IDEOGRAPH + 0xB0E9: 0x5708, //CJK UNIFIED IDEOGRAPH + 0xB0EA: 0x570B, //CJK UNIFIED IDEOGRAPH + 0xB0EB: 0x5709, //CJK UNIFIED IDEOGRAPH + 0xB0EC: 0x57DF, //CJK UNIFIED IDEOGRAPH + 0xB0ED: 0x5805, //CJK UNIFIED IDEOGRAPH + 0xB0EE: 0x580A, //CJK UNIFIED IDEOGRAPH + 0xB0EF: 0x5806, //CJK UNIFIED IDEOGRAPH + 0xB0F0: 0x57E0, //CJK UNIFIED IDEOGRAPH + 0xB0F1: 0x57E4, //CJK UNIFIED IDEOGRAPH + 0xB0F2: 0x57FA, //CJK UNIFIED IDEOGRAPH + 0xB0F3: 0x5802, //CJK UNIFIED IDEOGRAPH + 0xB0F4: 0x5835, //CJK UNIFIED IDEOGRAPH + 0xB0F5: 0x57F7, //CJK UNIFIED IDEOGRAPH + 0xB0F6: 0x57F9, //CJK UNIFIED IDEOGRAPH + 0xB0F7: 0x5920, //CJK UNIFIED IDEOGRAPH + 0xB0F8: 0x5962, //CJK UNIFIED IDEOGRAPH + 0xB0F9: 0x5A36, //CJK UNIFIED IDEOGRAPH + 0xB0FA: 0x5A41, //CJK UNIFIED IDEOGRAPH + 0xB0FB: 0x5A49, //CJK UNIFIED IDEOGRAPH + 0xB0FC: 0x5A66, //CJK UNIFIED IDEOGRAPH + 0xB0FD: 0x5A6A, //CJK UNIFIED IDEOGRAPH + 0xB0FE: 0x5A40, //CJK UNIFIED IDEOGRAPH + 0xB140: 0x5A3C, //CJK UNIFIED IDEOGRAPH + 0xB141: 0x5A62, //CJK UNIFIED IDEOGRAPH + 0xB142: 0x5A5A, //CJK UNIFIED IDEOGRAPH + 0xB143: 0x5A46, //CJK UNIFIED IDEOGRAPH + 0xB144: 0x5A4A, //CJK UNIFIED IDEOGRAPH + 0xB145: 0x5B70, //CJK UNIFIED IDEOGRAPH + 0xB146: 0x5BC7, //CJK UNIFIED IDEOGRAPH + 0xB147: 0x5BC5, //CJK UNIFIED IDEOGRAPH + 0xB148: 0x5BC4, //CJK UNIFIED IDEOGRAPH + 0xB149: 0x5BC2, //CJK UNIFIED IDEOGRAPH + 0xB14A: 0x5BBF, //CJK UNIFIED IDEOGRAPH + 0xB14B: 0x5BC6, //CJK UNIFIED IDEOGRAPH + 0xB14C: 0x5C09, //CJK UNIFIED IDEOGRAPH + 0xB14D: 0x5C08, //CJK UNIFIED IDEOGRAPH + 0xB14E: 0x5C07, //CJK UNIFIED IDEOGRAPH + 0xB14F: 0x5C60, //CJK UNIFIED IDEOGRAPH + 0xB150: 0x5C5C, //CJK UNIFIED IDEOGRAPH + 0xB151: 0x5C5D, //CJK UNIFIED IDEOGRAPH + 0xB152: 0x5D07, //CJK UNIFIED IDEOGRAPH + 0xB153: 0x5D06, //CJK UNIFIED IDEOGRAPH + 0xB154: 0x5D0E, //CJK UNIFIED IDEOGRAPH + 0xB155: 0x5D1B, //CJK UNIFIED IDEOGRAPH + 0xB156: 0x5D16, //CJK UNIFIED IDEOGRAPH + 0xB157: 0x5D22, //CJK UNIFIED IDEOGRAPH + 0xB158: 0x5D11, //CJK UNIFIED IDEOGRAPH + 0xB159: 0x5D29, //CJK UNIFIED IDEOGRAPH + 0xB15A: 0x5D14, //CJK UNIFIED IDEOGRAPH + 0xB15B: 0x5D19, //CJK UNIFIED IDEOGRAPH + 0xB15C: 0x5D24, //CJK UNIFIED IDEOGRAPH + 0xB15D: 0x5D27, //CJK UNIFIED IDEOGRAPH + 0xB15E: 0x5D17, //CJK UNIFIED IDEOGRAPH + 0xB15F: 0x5DE2, //CJK UNIFIED IDEOGRAPH + 0xB160: 0x5E38, //CJK UNIFIED IDEOGRAPH + 0xB161: 0x5E36, //CJK UNIFIED IDEOGRAPH + 0xB162: 0x5E33, //CJK UNIFIED IDEOGRAPH + 0xB163: 0x5E37, //CJK UNIFIED IDEOGRAPH + 0xB164: 0x5EB7, //CJK UNIFIED IDEOGRAPH + 0xB165: 0x5EB8, //CJK UNIFIED IDEOGRAPH + 0xB166: 0x5EB6, //CJK UNIFIED IDEOGRAPH + 0xB167: 0x5EB5, //CJK UNIFIED IDEOGRAPH + 0xB168: 0x5EBE, //CJK UNIFIED IDEOGRAPH + 0xB169: 0x5F35, //CJK UNIFIED IDEOGRAPH + 0xB16A: 0x5F37, //CJK UNIFIED IDEOGRAPH + 0xB16B: 0x5F57, //CJK UNIFIED IDEOGRAPH + 0xB16C: 0x5F6C, //CJK UNIFIED IDEOGRAPH + 0xB16D: 0x5F69, //CJK UNIFIED IDEOGRAPH + 0xB16E: 0x5F6B, //CJK UNIFIED IDEOGRAPH + 0xB16F: 0x5F97, //CJK UNIFIED IDEOGRAPH + 0xB170: 0x5F99, //CJK UNIFIED IDEOGRAPH + 0xB171: 0x5F9E, //CJK UNIFIED IDEOGRAPH + 0xB172: 0x5F98, //CJK UNIFIED IDEOGRAPH + 0xB173: 0x5FA1, //CJK UNIFIED IDEOGRAPH + 0xB174: 0x5FA0, //CJK UNIFIED IDEOGRAPH + 0xB175: 0x5F9C, //CJK UNIFIED IDEOGRAPH + 0xB176: 0x607F, //CJK UNIFIED IDEOGRAPH + 0xB177: 0x60A3, //CJK UNIFIED IDEOGRAPH + 0xB178: 0x6089, //CJK UNIFIED IDEOGRAPH + 0xB179: 0x60A0, //CJK UNIFIED IDEOGRAPH + 0xB17A: 0x60A8, //CJK UNIFIED IDEOGRAPH + 0xB17B: 0x60CB, //CJK UNIFIED IDEOGRAPH + 0xB17C: 0x60B4, //CJK UNIFIED IDEOGRAPH + 0xB17D: 0x60E6, //CJK UNIFIED IDEOGRAPH + 0xB17E: 0x60BD, //CJK UNIFIED IDEOGRAPH + 0xB1A1: 0x60C5, //CJK UNIFIED IDEOGRAPH + 0xB1A2: 0x60BB, //CJK UNIFIED IDEOGRAPH + 0xB1A3: 0x60B5, //CJK UNIFIED IDEOGRAPH + 0xB1A4: 0x60DC, //CJK UNIFIED IDEOGRAPH + 0xB1A5: 0x60BC, //CJK UNIFIED IDEOGRAPH + 0xB1A6: 0x60D8, //CJK UNIFIED IDEOGRAPH + 0xB1A7: 0x60D5, //CJK UNIFIED IDEOGRAPH + 0xB1A8: 0x60C6, //CJK UNIFIED IDEOGRAPH + 0xB1A9: 0x60DF, //CJK UNIFIED IDEOGRAPH + 0xB1AA: 0x60B8, //CJK UNIFIED IDEOGRAPH + 0xB1AB: 0x60DA, //CJK UNIFIED IDEOGRAPH + 0xB1AC: 0x60C7, //CJK UNIFIED IDEOGRAPH + 0xB1AD: 0x621A, //CJK UNIFIED IDEOGRAPH + 0xB1AE: 0x621B, //CJK UNIFIED IDEOGRAPH + 0xB1AF: 0x6248, //CJK UNIFIED IDEOGRAPH + 0xB1B0: 0x63A0, //CJK UNIFIED IDEOGRAPH + 0xB1B1: 0x63A7, //CJK UNIFIED IDEOGRAPH + 0xB1B2: 0x6372, //CJK UNIFIED IDEOGRAPH + 0xB1B3: 0x6396, //CJK UNIFIED IDEOGRAPH + 0xB1B4: 0x63A2, //CJK UNIFIED IDEOGRAPH + 0xB1B5: 0x63A5, //CJK UNIFIED IDEOGRAPH + 0xB1B6: 0x6377, //CJK UNIFIED IDEOGRAPH + 0xB1B7: 0x6367, //CJK UNIFIED IDEOGRAPH + 0xB1B8: 0x6398, //CJK UNIFIED IDEOGRAPH + 0xB1B9: 0x63AA, //CJK UNIFIED IDEOGRAPH + 0xB1BA: 0x6371, //CJK UNIFIED IDEOGRAPH + 0xB1BB: 0x63A9, //CJK UNIFIED IDEOGRAPH + 0xB1BC: 0x6389, //CJK UNIFIED IDEOGRAPH + 0xB1BD: 0x6383, //CJK UNIFIED IDEOGRAPH + 0xB1BE: 0x639B, //CJK UNIFIED IDEOGRAPH + 0xB1BF: 0x636B, //CJK UNIFIED IDEOGRAPH + 0xB1C0: 0x63A8, //CJK UNIFIED IDEOGRAPH + 0xB1C1: 0x6384, //CJK UNIFIED IDEOGRAPH + 0xB1C2: 0x6388, //CJK UNIFIED IDEOGRAPH + 0xB1C3: 0x6399, //CJK UNIFIED IDEOGRAPH + 0xB1C4: 0x63A1, //CJK UNIFIED IDEOGRAPH + 0xB1C5: 0x63AC, //CJK UNIFIED IDEOGRAPH + 0xB1C6: 0x6392, //CJK UNIFIED IDEOGRAPH + 0xB1C7: 0x638F, //CJK UNIFIED IDEOGRAPH + 0xB1C8: 0x6380, //CJK UNIFIED IDEOGRAPH + 0xB1C9: 0x637B, //CJK UNIFIED IDEOGRAPH + 0xB1CA: 0x6369, //CJK UNIFIED IDEOGRAPH + 0xB1CB: 0x6368, //CJK UNIFIED IDEOGRAPH + 0xB1CC: 0x637A, //CJK UNIFIED IDEOGRAPH + 0xB1CD: 0x655D, //CJK UNIFIED IDEOGRAPH + 0xB1CE: 0x6556, //CJK UNIFIED IDEOGRAPH + 0xB1CF: 0x6551, //CJK UNIFIED IDEOGRAPH + 0xB1D0: 0x6559, //CJK UNIFIED IDEOGRAPH + 0xB1D1: 0x6557, //CJK UNIFIED IDEOGRAPH + 0xB1D2: 0x555F, //CJK UNIFIED IDEOGRAPH + 0xB1D3: 0x654F, //CJK UNIFIED IDEOGRAPH + 0xB1D4: 0x6558, //CJK UNIFIED IDEOGRAPH + 0xB1D5: 0x6555, //CJK UNIFIED IDEOGRAPH + 0xB1D6: 0x6554, //CJK UNIFIED IDEOGRAPH + 0xB1D7: 0x659C, //CJK UNIFIED IDEOGRAPH + 0xB1D8: 0x659B, //CJK UNIFIED IDEOGRAPH + 0xB1D9: 0x65AC, //CJK UNIFIED IDEOGRAPH + 0xB1DA: 0x65CF, //CJK UNIFIED IDEOGRAPH + 0xB1DB: 0x65CB, //CJK UNIFIED IDEOGRAPH + 0xB1DC: 0x65CC, //CJK UNIFIED IDEOGRAPH + 0xB1DD: 0x65CE, //CJK UNIFIED IDEOGRAPH + 0xB1DE: 0x665D, //CJK UNIFIED IDEOGRAPH + 0xB1DF: 0x665A, //CJK UNIFIED IDEOGRAPH + 0xB1E0: 0x6664, //CJK UNIFIED IDEOGRAPH + 0xB1E1: 0x6668, //CJK UNIFIED IDEOGRAPH + 0xB1E2: 0x6666, //CJK UNIFIED IDEOGRAPH + 0xB1E3: 0x665E, //CJK UNIFIED IDEOGRAPH + 0xB1E4: 0x66F9, //CJK UNIFIED IDEOGRAPH + 0xB1E5: 0x52D7, //CJK UNIFIED IDEOGRAPH + 0xB1E6: 0x671B, //CJK UNIFIED IDEOGRAPH + 0xB1E7: 0x6881, //CJK UNIFIED IDEOGRAPH + 0xB1E8: 0x68AF, //CJK UNIFIED IDEOGRAPH + 0xB1E9: 0x68A2, //CJK UNIFIED IDEOGRAPH + 0xB1EA: 0x6893, //CJK UNIFIED IDEOGRAPH + 0xB1EB: 0x68B5, //CJK UNIFIED IDEOGRAPH + 0xB1EC: 0x687F, //CJK UNIFIED IDEOGRAPH + 0xB1ED: 0x6876, //CJK UNIFIED IDEOGRAPH + 0xB1EE: 0x68B1, //CJK UNIFIED IDEOGRAPH + 0xB1EF: 0x68A7, //CJK UNIFIED IDEOGRAPH + 0xB1F0: 0x6897, //CJK UNIFIED IDEOGRAPH + 0xB1F1: 0x68B0, //CJK UNIFIED IDEOGRAPH + 0xB1F2: 0x6883, //CJK UNIFIED IDEOGRAPH + 0xB1F3: 0x68C4, //CJK UNIFIED IDEOGRAPH + 0xB1F4: 0x68AD, //CJK UNIFIED IDEOGRAPH + 0xB1F5: 0x6886, //CJK UNIFIED IDEOGRAPH + 0xB1F6: 0x6885, //CJK UNIFIED IDEOGRAPH + 0xB1F7: 0x6894, //CJK UNIFIED IDEOGRAPH + 0xB1F8: 0x689D, //CJK UNIFIED IDEOGRAPH + 0xB1F9: 0x68A8, //CJK UNIFIED IDEOGRAPH + 0xB1FA: 0x689F, //CJK UNIFIED IDEOGRAPH + 0xB1FB: 0x68A1, //CJK UNIFIED IDEOGRAPH + 0xB1FC: 0x6882, //CJK UNIFIED IDEOGRAPH + 0xB1FD: 0x6B32, //CJK UNIFIED IDEOGRAPH + 0xB1FE: 0x6BBA, //CJK UNIFIED IDEOGRAPH + 0xB240: 0x6BEB, //CJK UNIFIED IDEOGRAPH + 0xB241: 0x6BEC, //CJK UNIFIED IDEOGRAPH + 0xB242: 0x6C2B, //CJK UNIFIED IDEOGRAPH + 0xB243: 0x6D8E, //CJK UNIFIED IDEOGRAPH + 0xB244: 0x6DBC, //CJK UNIFIED IDEOGRAPH + 0xB245: 0x6DF3, //CJK UNIFIED IDEOGRAPH + 0xB246: 0x6DD9, //CJK UNIFIED IDEOGRAPH + 0xB247: 0x6DB2, //CJK UNIFIED IDEOGRAPH + 0xB248: 0x6DE1, //CJK UNIFIED IDEOGRAPH + 0xB249: 0x6DCC, //CJK UNIFIED IDEOGRAPH + 0xB24A: 0x6DE4, //CJK UNIFIED IDEOGRAPH + 0xB24B: 0x6DFB, //CJK UNIFIED IDEOGRAPH + 0xB24C: 0x6DFA, //CJK UNIFIED IDEOGRAPH + 0xB24D: 0x6E05, //CJK UNIFIED IDEOGRAPH + 0xB24E: 0x6DC7, //CJK UNIFIED IDEOGRAPH + 0xB24F: 0x6DCB, //CJK UNIFIED IDEOGRAPH + 0xB250: 0x6DAF, //CJK UNIFIED IDEOGRAPH + 0xB251: 0x6DD1, //CJK UNIFIED IDEOGRAPH + 0xB252: 0x6DAE, //CJK UNIFIED IDEOGRAPH + 0xB253: 0x6DDE, //CJK UNIFIED IDEOGRAPH + 0xB254: 0x6DF9, //CJK UNIFIED IDEOGRAPH + 0xB255: 0x6DB8, //CJK UNIFIED IDEOGRAPH + 0xB256: 0x6DF7, //CJK UNIFIED IDEOGRAPH + 0xB257: 0x6DF5, //CJK UNIFIED IDEOGRAPH + 0xB258: 0x6DC5, //CJK UNIFIED IDEOGRAPH + 0xB259: 0x6DD2, //CJK UNIFIED IDEOGRAPH + 0xB25A: 0x6E1A, //CJK UNIFIED IDEOGRAPH + 0xB25B: 0x6DB5, //CJK UNIFIED IDEOGRAPH + 0xB25C: 0x6DDA, //CJK UNIFIED IDEOGRAPH + 0xB25D: 0x6DEB, //CJK UNIFIED IDEOGRAPH + 0xB25E: 0x6DD8, //CJK UNIFIED IDEOGRAPH + 0xB25F: 0x6DEA, //CJK UNIFIED IDEOGRAPH + 0xB260: 0x6DF1, //CJK UNIFIED IDEOGRAPH + 0xB261: 0x6DEE, //CJK UNIFIED IDEOGRAPH + 0xB262: 0x6DE8, //CJK UNIFIED IDEOGRAPH + 0xB263: 0x6DC6, //CJK UNIFIED IDEOGRAPH + 0xB264: 0x6DC4, //CJK UNIFIED IDEOGRAPH + 0xB265: 0x6DAA, //CJK UNIFIED IDEOGRAPH + 0xB266: 0x6DEC, //CJK UNIFIED IDEOGRAPH + 0xB267: 0x6DBF, //CJK UNIFIED IDEOGRAPH + 0xB268: 0x6DE6, //CJK UNIFIED IDEOGRAPH + 0xB269: 0x70F9, //CJK UNIFIED IDEOGRAPH + 0xB26A: 0x7109, //CJK UNIFIED IDEOGRAPH + 0xB26B: 0x710A, //CJK UNIFIED IDEOGRAPH + 0xB26C: 0x70FD, //CJK UNIFIED IDEOGRAPH + 0xB26D: 0x70EF, //CJK UNIFIED IDEOGRAPH + 0xB26E: 0x723D, //CJK UNIFIED IDEOGRAPH + 0xB26F: 0x727D, //CJK UNIFIED IDEOGRAPH + 0xB270: 0x7281, //CJK UNIFIED IDEOGRAPH + 0xB271: 0x731C, //CJK UNIFIED IDEOGRAPH + 0xB272: 0x731B, //CJK UNIFIED IDEOGRAPH + 0xB273: 0x7316, //CJK UNIFIED IDEOGRAPH + 0xB274: 0x7313, //CJK UNIFIED IDEOGRAPH + 0xB275: 0x7319, //CJK UNIFIED IDEOGRAPH + 0xB276: 0x7387, //CJK UNIFIED IDEOGRAPH + 0xB277: 0x7405, //CJK UNIFIED IDEOGRAPH + 0xB278: 0x740A, //CJK UNIFIED IDEOGRAPH + 0xB279: 0x7403, //CJK UNIFIED IDEOGRAPH + 0xB27A: 0x7406, //CJK UNIFIED IDEOGRAPH + 0xB27B: 0x73FE, //CJK UNIFIED IDEOGRAPH + 0xB27C: 0x740D, //CJK UNIFIED IDEOGRAPH + 0xB27D: 0x74E0, //CJK UNIFIED IDEOGRAPH + 0xB27E: 0x74F6, //CJK UNIFIED IDEOGRAPH + 0xB2A1: 0x74F7, //CJK UNIFIED IDEOGRAPH + 0xB2A2: 0x751C, //CJK UNIFIED IDEOGRAPH + 0xB2A3: 0x7522, //CJK UNIFIED IDEOGRAPH + 0xB2A4: 0x7565, //CJK UNIFIED IDEOGRAPH + 0xB2A5: 0x7566, //CJK UNIFIED IDEOGRAPH + 0xB2A6: 0x7562, //CJK UNIFIED IDEOGRAPH + 0xB2A7: 0x7570, //CJK UNIFIED IDEOGRAPH + 0xB2A8: 0x758F, //CJK UNIFIED IDEOGRAPH + 0xB2A9: 0x75D4, //CJK UNIFIED IDEOGRAPH + 0xB2AA: 0x75D5, //CJK UNIFIED IDEOGRAPH + 0xB2AB: 0x75B5, //CJK UNIFIED IDEOGRAPH + 0xB2AC: 0x75CA, //CJK UNIFIED IDEOGRAPH + 0xB2AD: 0x75CD, //CJK UNIFIED IDEOGRAPH + 0xB2AE: 0x768E, //CJK UNIFIED IDEOGRAPH + 0xB2AF: 0x76D4, //CJK UNIFIED IDEOGRAPH + 0xB2B0: 0x76D2, //CJK UNIFIED IDEOGRAPH + 0xB2B1: 0x76DB, //CJK UNIFIED IDEOGRAPH + 0xB2B2: 0x7737, //CJK UNIFIED IDEOGRAPH + 0xB2B3: 0x773E, //CJK UNIFIED IDEOGRAPH + 0xB2B4: 0x773C, //CJK UNIFIED IDEOGRAPH + 0xB2B5: 0x7736, //CJK UNIFIED IDEOGRAPH + 0xB2B6: 0x7738, //CJK UNIFIED IDEOGRAPH + 0xB2B7: 0x773A, //CJK UNIFIED IDEOGRAPH + 0xB2B8: 0x786B, //CJK UNIFIED IDEOGRAPH + 0xB2B9: 0x7843, //CJK UNIFIED IDEOGRAPH + 0xB2BA: 0x784E, //CJK UNIFIED IDEOGRAPH + 0xB2BB: 0x7965, //CJK UNIFIED IDEOGRAPH + 0xB2BC: 0x7968, //CJK UNIFIED IDEOGRAPH + 0xB2BD: 0x796D, //CJK UNIFIED IDEOGRAPH + 0xB2BE: 0x79FB, //CJK UNIFIED IDEOGRAPH + 0xB2BF: 0x7A92, //CJK UNIFIED IDEOGRAPH + 0xB2C0: 0x7A95, //CJK UNIFIED IDEOGRAPH + 0xB2C1: 0x7B20, //CJK UNIFIED IDEOGRAPH + 0xB2C2: 0x7B28, //CJK UNIFIED IDEOGRAPH + 0xB2C3: 0x7B1B, //CJK UNIFIED IDEOGRAPH + 0xB2C4: 0x7B2C, //CJK UNIFIED IDEOGRAPH + 0xB2C5: 0x7B26, //CJK UNIFIED IDEOGRAPH + 0xB2C6: 0x7B19, //CJK UNIFIED IDEOGRAPH + 0xB2C7: 0x7B1E, //CJK UNIFIED IDEOGRAPH + 0xB2C8: 0x7B2E, //CJK UNIFIED IDEOGRAPH + 0xB2C9: 0x7C92, //CJK UNIFIED IDEOGRAPH + 0xB2CA: 0x7C97, //CJK UNIFIED IDEOGRAPH + 0xB2CB: 0x7C95, //CJK UNIFIED IDEOGRAPH + 0xB2CC: 0x7D46, //CJK UNIFIED IDEOGRAPH + 0xB2CD: 0x7D43, //CJK UNIFIED IDEOGRAPH + 0xB2CE: 0x7D71, //CJK UNIFIED IDEOGRAPH + 0xB2CF: 0x7D2E, //CJK UNIFIED IDEOGRAPH + 0xB2D0: 0x7D39, //CJK UNIFIED IDEOGRAPH + 0xB2D1: 0x7D3C, //CJK UNIFIED IDEOGRAPH + 0xB2D2: 0x7D40, //CJK UNIFIED IDEOGRAPH + 0xB2D3: 0x7D30, //CJK UNIFIED IDEOGRAPH + 0xB2D4: 0x7D33, //CJK UNIFIED IDEOGRAPH + 0xB2D5: 0x7D44, //CJK UNIFIED IDEOGRAPH + 0xB2D6: 0x7D2F, //CJK UNIFIED IDEOGRAPH + 0xB2D7: 0x7D42, //CJK UNIFIED IDEOGRAPH + 0xB2D8: 0x7D32, //CJK UNIFIED IDEOGRAPH + 0xB2D9: 0x7D31, //CJK UNIFIED IDEOGRAPH + 0xB2DA: 0x7F3D, //CJK UNIFIED IDEOGRAPH + 0xB2DB: 0x7F9E, //CJK UNIFIED IDEOGRAPH + 0xB2DC: 0x7F9A, //CJK UNIFIED IDEOGRAPH + 0xB2DD: 0x7FCC, //CJK UNIFIED IDEOGRAPH + 0xB2DE: 0x7FCE, //CJK UNIFIED IDEOGRAPH + 0xB2DF: 0x7FD2, //CJK UNIFIED IDEOGRAPH + 0xB2E0: 0x801C, //CJK UNIFIED IDEOGRAPH + 0xB2E1: 0x804A, //CJK UNIFIED IDEOGRAPH + 0xB2E2: 0x8046, //CJK UNIFIED IDEOGRAPH + 0xB2E3: 0x812F, //CJK UNIFIED IDEOGRAPH + 0xB2E4: 0x8116, //CJK UNIFIED IDEOGRAPH + 0xB2E5: 0x8123, //CJK UNIFIED IDEOGRAPH + 0xB2E6: 0x812B, //CJK UNIFIED IDEOGRAPH + 0xB2E7: 0x8129, //CJK UNIFIED IDEOGRAPH + 0xB2E8: 0x8130, //CJK UNIFIED IDEOGRAPH + 0xB2E9: 0x8124, //CJK UNIFIED IDEOGRAPH + 0xB2EA: 0x8202, //CJK UNIFIED IDEOGRAPH + 0xB2EB: 0x8235, //CJK UNIFIED IDEOGRAPH + 0xB2EC: 0x8237, //CJK UNIFIED IDEOGRAPH + 0xB2ED: 0x8236, //CJK UNIFIED IDEOGRAPH + 0xB2EE: 0x8239, //CJK UNIFIED IDEOGRAPH + 0xB2EF: 0x838E, //CJK UNIFIED IDEOGRAPH + 0xB2F0: 0x839E, //CJK UNIFIED IDEOGRAPH + 0xB2F1: 0x8398, //CJK UNIFIED IDEOGRAPH + 0xB2F2: 0x8378, //CJK UNIFIED IDEOGRAPH + 0xB2F3: 0x83A2, //CJK UNIFIED IDEOGRAPH + 0xB2F4: 0x8396, //CJK UNIFIED IDEOGRAPH + 0xB2F5: 0x83BD, //CJK UNIFIED IDEOGRAPH + 0xB2F6: 0x83AB, //CJK UNIFIED IDEOGRAPH + 0xB2F7: 0x8392, //CJK UNIFIED IDEOGRAPH + 0xB2F8: 0x838A, //CJK UNIFIED IDEOGRAPH + 0xB2F9: 0x8393, //CJK UNIFIED IDEOGRAPH + 0xB2FA: 0x8389, //CJK UNIFIED IDEOGRAPH + 0xB2FB: 0x83A0, //CJK UNIFIED IDEOGRAPH + 0xB2FC: 0x8377, //CJK UNIFIED IDEOGRAPH + 0xB2FD: 0x837B, //CJK UNIFIED IDEOGRAPH + 0xB2FE: 0x837C, //CJK UNIFIED IDEOGRAPH + 0xB340: 0x8386, //CJK UNIFIED IDEOGRAPH + 0xB341: 0x83A7, //CJK UNIFIED IDEOGRAPH + 0xB342: 0x8655, //CJK UNIFIED IDEOGRAPH + 0xB343: 0x5F6A, //CJK UNIFIED IDEOGRAPH + 0xB344: 0x86C7, //CJK UNIFIED IDEOGRAPH + 0xB345: 0x86C0, //CJK UNIFIED IDEOGRAPH + 0xB346: 0x86B6, //CJK UNIFIED IDEOGRAPH + 0xB347: 0x86C4, //CJK UNIFIED IDEOGRAPH + 0xB348: 0x86B5, //CJK UNIFIED IDEOGRAPH + 0xB349: 0x86C6, //CJK UNIFIED IDEOGRAPH + 0xB34A: 0x86CB, //CJK UNIFIED IDEOGRAPH + 0xB34B: 0x86B1, //CJK UNIFIED IDEOGRAPH + 0xB34C: 0x86AF, //CJK UNIFIED IDEOGRAPH + 0xB34D: 0x86C9, //CJK UNIFIED IDEOGRAPH + 0xB34E: 0x8853, //CJK UNIFIED IDEOGRAPH + 0xB34F: 0x889E, //CJK UNIFIED IDEOGRAPH + 0xB350: 0x8888, //CJK UNIFIED IDEOGRAPH + 0xB351: 0x88AB, //CJK UNIFIED IDEOGRAPH + 0xB352: 0x8892, //CJK UNIFIED IDEOGRAPH + 0xB353: 0x8896, //CJK UNIFIED IDEOGRAPH + 0xB354: 0x888D, //CJK UNIFIED IDEOGRAPH + 0xB355: 0x888B, //CJK UNIFIED IDEOGRAPH + 0xB356: 0x8993, //CJK UNIFIED IDEOGRAPH + 0xB357: 0x898F, //CJK UNIFIED IDEOGRAPH + 0xB358: 0x8A2A, //CJK UNIFIED IDEOGRAPH + 0xB359: 0x8A1D, //CJK UNIFIED IDEOGRAPH + 0xB35A: 0x8A23, //CJK UNIFIED IDEOGRAPH + 0xB35B: 0x8A25, //CJK UNIFIED IDEOGRAPH + 0xB35C: 0x8A31, //CJK UNIFIED IDEOGRAPH + 0xB35D: 0x8A2D, //CJK UNIFIED IDEOGRAPH + 0xB35E: 0x8A1F, //CJK UNIFIED IDEOGRAPH + 0xB35F: 0x8A1B, //CJK UNIFIED IDEOGRAPH + 0xB360: 0x8A22, //CJK UNIFIED IDEOGRAPH + 0xB361: 0x8C49, //CJK UNIFIED IDEOGRAPH + 0xB362: 0x8C5A, //CJK UNIFIED IDEOGRAPH + 0xB363: 0x8CA9, //CJK UNIFIED IDEOGRAPH + 0xB364: 0x8CAC, //CJK UNIFIED IDEOGRAPH + 0xB365: 0x8CAB, //CJK UNIFIED IDEOGRAPH + 0xB366: 0x8CA8, //CJK UNIFIED IDEOGRAPH + 0xB367: 0x8CAA, //CJK UNIFIED IDEOGRAPH + 0xB368: 0x8CA7, //CJK UNIFIED IDEOGRAPH + 0xB369: 0x8D67, //CJK UNIFIED IDEOGRAPH + 0xB36A: 0x8D66, //CJK UNIFIED IDEOGRAPH + 0xB36B: 0x8DBE, //CJK UNIFIED IDEOGRAPH + 0xB36C: 0x8DBA, //CJK UNIFIED IDEOGRAPH + 0xB36D: 0x8EDB, //CJK UNIFIED IDEOGRAPH + 0xB36E: 0x8EDF, //CJK UNIFIED IDEOGRAPH + 0xB36F: 0x9019, //CJK UNIFIED IDEOGRAPH + 0xB370: 0x900D, //CJK UNIFIED IDEOGRAPH + 0xB371: 0x901A, //CJK UNIFIED IDEOGRAPH + 0xB372: 0x9017, //CJK UNIFIED IDEOGRAPH + 0xB373: 0x9023, //CJK UNIFIED IDEOGRAPH + 0xB374: 0x901F, //CJK UNIFIED IDEOGRAPH + 0xB375: 0x901D, //CJK UNIFIED IDEOGRAPH + 0xB376: 0x9010, //CJK UNIFIED IDEOGRAPH + 0xB377: 0x9015, //CJK UNIFIED IDEOGRAPH + 0xB378: 0x901E, //CJK UNIFIED IDEOGRAPH + 0xB379: 0x9020, //CJK UNIFIED IDEOGRAPH + 0xB37A: 0x900F, //CJK UNIFIED IDEOGRAPH + 0xB37B: 0x9022, //CJK UNIFIED IDEOGRAPH + 0xB37C: 0x9016, //CJK UNIFIED IDEOGRAPH + 0xB37D: 0x901B, //CJK UNIFIED IDEOGRAPH + 0xB37E: 0x9014, //CJK UNIFIED IDEOGRAPH + 0xB3A1: 0x90E8, //CJK UNIFIED IDEOGRAPH + 0xB3A2: 0x90ED, //CJK UNIFIED IDEOGRAPH + 0xB3A3: 0x90FD, //CJK UNIFIED IDEOGRAPH + 0xB3A4: 0x9157, //CJK UNIFIED IDEOGRAPH + 0xB3A5: 0x91CE, //CJK UNIFIED IDEOGRAPH + 0xB3A6: 0x91F5, //CJK UNIFIED IDEOGRAPH + 0xB3A7: 0x91E6, //CJK UNIFIED IDEOGRAPH + 0xB3A8: 0x91E3, //CJK UNIFIED IDEOGRAPH + 0xB3A9: 0x91E7, //CJK UNIFIED IDEOGRAPH + 0xB3AA: 0x91ED, //CJK UNIFIED IDEOGRAPH + 0xB3AB: 0x91E9, //CJK UNIFIED IDEOGRAPH + 0xB3AC: 0x9589, //CJK UNIFIED IDEOGRAPH + 0xB3AD: 0x966A, //CJK UNIFIED IDEOGRAPH + 0xB3AE: 0x9675, //CJK UNIFIED IDEOGRAPH + 0xB3AF: 0x9673, //CJK UNIFIED IDEOGRAPH + 0xB3B0: 0x9678, //CJK UNIFIED IDEOGRAPH + 0xB3B1: 0x9670, //CJK UNIFIED IDEOGRAPH + 0xB3B2: 0x9674, //CJK UNIFIED IDEOGRAPH + 0xB3B3: 0x9676, //CJK UNIFIED IDEOGRAPH + 0xB3B4: 0x9677, //CJK UNIFIED IDEOGRAPH + 0xB3B5: 0x966C, //CJK UNIFIED IDEOGRAPH + 0xB3B6: 0x96C0, //CJK UNIFIED IDEOGRAPH + 0xB3B7: 0x96EA, //CJK UNIFIED IDEOGRAPH + 0xB3B8: 0x96E9, //CJK UNIFIED IDEOGRAPH + 0xB3B9: 0x7AE0, //CJK UNIFIED IDEOGRAPH + 0xB3BA: 0x7ADF, //CJK UNIFIED IDEOGRAPH + 0xB3BB: 0x9802, //CJK UNIFIED IDEOGRAPH + 0xB3BC: 0x9803, //CJK UNIFIED IDEOGRAPH + 0xB3BD: 0x9B5A, //CJK UNIFIED IDEOGRAPH + 0xB3BE: 0x9CE5, //CJK UNIFIED IDEOGRAPH + 0xB3BF: 0x9E75, //CJK UNIFIED IDEOGRAPH + 0xB3C0: 0x9E7F, //CJK UNIFIED IDEOGRAPH + 0xB3C1: 0x9EA5, //CJK UNIFIED IDEOGRAPH + 0xB3C2: 0x9EBB, //CJK UNIFIED IDEOGRAPH + 0xB3C3: 0x50A2, //CJK UNIFIED IDEOGRAPH + 0xB3C4: 0x508D, //CJK UNIFIED IDEOGRAPH + 0xB3C5: 0x5085, //CJK UNIFIED IDEOGRAPH + 0xB3C6: 0x5099, //CJK UNIFIED IDEOGRAPH + 0xB3C7: 0x5091, //CJK UNIFIED IDEOGRAPH + 0xB3C8: 0x5080, //CJK UNIFIED IDEOGRAPH + 0xB3C9: 0x5096, //CJK UNIFIED IDEOGRAPH + 0xB3CA: 0x5098, //CJK UNIFIED IDEOGRAPH + 0xB3CB: 0x509A, //CJK UNIFIED IDEOGRAPH + 0xB3CC: 0x6700, //CJK UNIFIED IDEOGRAPH + 0xB3CD: 0x51F1, //CJK UNIFIED IDEOGRAPH + 0xB3CE: 0x5272, //CJK UNIFIED IDEOGRAPH + 0xB3CF: 0x5274, //CJK UNIFIED IDEOGRAPH + 0xB3D0: 0x5275, //CJK UNIFIED IDEOGRAPH + 0xB3D1: 0x5269, //CJK UNIFIED IDEOGRAPH + 0xB3D2: 0x52DE, //CJK UNIFIED IDEOGRAPH + 0xB3D3: 0x52DD, //CJK UNIFIED IDEOGRAPH + 0xB3D4: 0x52DB, //CJK UNIFIED IDEOGRAPH + 0xB3D5: 0x535A, //CJK UNIFIED IDEOGRAPH + 0xB3D6: 0x53A5, //CJK UNIFIED IDEOGRAPH + 0xB3D7: 0x557B, //CJK UNIFIED IDEOGRAPH + 0xB3D8: 0x5580, //CJK UNIFIED IDEOGRAPH + 0xB3D9: 0x55A7, //CJK UNIFIED IDEOGRAPH + 0xB3DA: 0x557C, //CJK UNIFIED IDEOGRAPH + 0xB3DB: 0x558A, //CJK UNIFIED IDEOGRAPH + 0xB3DC: 0x559D, //CJK UNIFIED IDEOGRAPH + 0xB3DD: 0x5598, //CJK UNIFIED IDEOGRAPH + 0xB3DE: 0x5582, //CJK UNIFIED IDEOGRAPH + 0xB3DF: 0x559C, //CJK UNIFIED IDEOGRAPH + 0xB3E0: 0x55AA, //CJK UNIFIED IDEOGRAPH + 0xB3E1: 0x5594, //CJK UNIFIED IDEOGRAPH + 0xB3E2: 0x5587, //CJK UNIFIED IDEOGRAPH + 0xB3E3: 0x558B, //CJK UNIFIED IDEOGRAPH + 0xB3E4: 0x5583, //CJK UNIFIED IDEOGRAPH + 0xB3E5: 0x55B3, //CJK UNIFIED IDEOGRAPH + 0xB3E6: 0x55AE, //CJK UNIFIED IDEOGRAPH + 0xB3E7: 0x559F, //CJK UNIFIED IDEOGRAPH + 0xB3E8: 0x553E, //CJK UNIFIED IDEOGRAPH + 0xB3E9: 0x55B2, //CJK UNIFIED IDEOGRAPH + 0xB3EA: 0x559A, //CJK UNIFIED IDEOGRAPH + 0xB3EB: 0x55BB, //CJK UNIFIED IDEOGRAPH + 0xB3EC: 0x55AC, //CJK UNIFIED IDEOGRAPH + 0xB3ED: 0x55B1, //CJK UNIFIED IDEOGRAPH + 0xB3EE: 0x557E, //CJK UNIFIED IDEOGRAPH + 0xB3EF: 0x5589, //CJK UNIFIED IDEOGRAPH + 0xB3F0: 0x55AB, //CJK UNIFIED IDEOGRAPH + 0xB3F1: 0x5599, //CJK UNIFIED IDEOGRAPH + 0xB3F2: 0x570D, //CJK UNIFIED IDEOGRAPH + 0xB3F3: 0x582F, //CJK UNIFIED IDEOGRAPH + 0xB3F4: 0x582A, //CJK UNIFIED IDEOGRAPH + 0xB3F5: 0x5834, //CJK UNIFIED IDEOGRAPH + 0xB3F6: 0x5824, //CJK UNIFIED IDEOGRAPH + 0xB3F7: 0x5830, //CJK UNIFIED IDEOGRAPH + 0xB3F8: 0x5831, //CJK UNIFIED IDEOGRAPH + 0xB3F9: 0x5821, //CJK UNIFIED IDEOGRAPH + 0xB3FA: 0x581D, //CJK UNIFIED IDEOGRAPH + 0xB3FB: 0x5820, //CJK UNIFIED IDEOGRAPH + 0xB3FC: 0x58F9, //CJK UNIFIED IDEOGRAPH + 0xB3FD: 0x58FA, //CJK UNIFIED IDEOGRAPH + 0xB3FE: 0x5960, //CJK UNIFIED IDEOGRAPH + 0xB440: 0x5A77, //CJK UNIFIED IDEOGRAPH + 0xB441: 0x5A9A, //CJK UNIFIED IDEOGRAPH + 0xB442: 0x5A7F, //CJK UNIFIED IDEOGRAPH + 0xB443: 0x5A92, //CJK UNIFIED IDEOGRAPH + 0xB444: 0x5A9B, //CJK UNIFIED IDEOGRAPH + 0xB445: 0x5AA7, //CJK UNIFIED IDEOGRAPH + 0xB446: 0x5B73, //CJK UNIFIED IDEOGRAPH + 0xB447: 0x5B71, //CJK UNIFIED IDEOGRAPH + 0xB448: 0x5BD2, //CJK UNIFIED IDEOGRAPH + 0xB449: 0x5BCC, //CJK UNIFIED IDEOGRAPH + 0xB44A: 0x5BD3, //CJK UNIFIED IDEOGRAPH + 0xB44B: 0x5BD0, //CJK UNIFIED IDEOGRAPH + 0xB44C: 0x5C0A, //CJK UNIFIED IDEOGRAPH + 0xB44D: 0x5C0B, //CJK UNIFIED IDEOGRAPH + 0xB44E: 0x5C31, //CJK UNIFIED IDEOGRAPH + 0xB44F: 0x5D4C, //CJK UNIFIED IDEOGRAPH + 0xB450: 0x5D50, //CJK UNIFIED IDEOGRAPH + 0xB451: 0x5D34, //CJK UNIFIED IDEOGRAPH + 0xB452: 0x5D47, //CJK UNIFIED IDEOGRAPH + 0xB453: 0x5DFD, //CJK UNIFIED IDEOGRAPH + 0xB454: 0x5E45, //CJK UNIFIED IDEOGRAPH + 0xB455: 0x5E3D, //CJK UNIFIED IDEOGRAPH + 0xB456: 0x5E40, //CJK UNIFIED IDEOGRAPH + 0xB457: 0x5E43, //CJK UNIFIED IDEOGRAPH + 0xB458: 0x5E7E, //CJK UNIFIED IDEOGRAPH + 0xB459: 0x5ECA, //CJK UNIFIED IDEOGRAPH + 0xB45A: 0x5EC1, //CJK UNIFIED IDEOGRAPH + 0xB45B: 0x5EC2, //CJK UNIFIED IDEOGRAPH + 0xB45C: 0x5EC4, //CJK UNIFIED IDEOGRAPH + 0xB45D: 0x5F3C, //CJK UNIFIED IDEOGRAPH + 0xB45E: 0x5F6D, //CJK UNIFIED IDEOGRAPH + 0xB45F: 0x5FA9, //CJK UNIFIED IDEOGRAPH + 0xB460: 0x5FAA, //CJK UNIFIED IDEOGRAPH + 0xB461: 0x5FA8, //CJK UNIFIED IDEOGRAPH + 0xB462: 0x60D1, //CJK UNIFIED IDEOGRAPH + 0xB463: 0x60E1, //CJK UNIFIED IDEOGRAPH + 0xB464: 0x60B2, //CJK UNIFIED IDEOGRAPH + 0xB465: 0x60B6, //CJK UNIFIED IDEOGRAPH + 0xB466: 0x60E0, //CJK UNIFIED IDEOGRAPH + 0xB467: 0x611C, //CJK UNIFIED IDEOGRAPH + 0xB468: 0x6123, //CJK UNIFIED IDEOGRAPH + 0xB469: 0x60FA, //CJK UNIFIED IDEOGRAPH + 0xB46A: 0x6115, //CJK UNIFIED IDEOGRAPH + 0xB46B: 0x60F0, //CJK UNIFIED IDEOGRAPH + 0xB46C: 0x60FB, //CJK UNIFIED IDEOGRAPH + 0xB46D: 0x60F4, //CJK UNIFIED IDEOGRAPH + 0xB46E: 0x6168, //CJK UNIFIED IDEOGRAPH + 0xB46F: 0x60F1, //CJK UNIFIED IDEOGRAPH + 0xB470: 0x610E, //CJK UNIFIED IDEOGRAPH + 0xB471: 0x60F6, //CJK UNIFIED IDEOGRAPH + 0xB472: 0x6109, //CJK UNIFIED IDEOGRAPH + 0xB473: 0x6100, //CJK UNIFIED IDEOGRAPH + 0xB474: 0x6112, //CJK UNIFIED IDEOGRAPH + 0xB475: 0x621F, //CJK UNIFIED IDEOGRAPH + 0xB476: 0x6249, //CJK UNIFIED IDEOGRAPH + 0xB477: 0x63A3, //CJK UNIFIED IDEOGRAPH + 0xB478: 0x638C, //CJK UNIFIED IDEOGRAPH + 0xB479: 0x63CF, //CJK UNIFIED IDEOGRAPH + 0xB47A: 0x63C0, //CJK UNIFIED IDEOGRAPH + 0xB47B: 0x63E9, //CJK UNIFIED IDEOGRAPH + 0xB47C: 0x63C9, //CJK UNIFIED IDEOGRAPH + 0xB47D: 0x63C6, //CJK UNIFIED IDEOGRAPH + 0xB47E: 0x63CD, //CJK UNIFIED IDEOGRAPH + 0xB4A1: 0x63D2, //CJK UNIFIED IDEOGRAPH + 0xB4A2: 0x63E3, //CJK UNIFIED IDEOGRAPH + 0xB4A3: 0x63D0, //CJK UNIFIED IDEOGRAPH + 0xB4A4: 0x63E1, //CJK UNIFIED IDEOGRAPH + 0xB4A5: 0x63D6, //CJK UNIFIED IDEOGRAPH + 0xB4A6: 0x63ED, //CJK UNIFIED IDEOGRAPH + 0xB4A7: 0x63EE, //CJK UNIFIED IDEOGRAPH + 0xB4A8: 0x6376, //CJK UNIFIED IDEOGRAPH + 0xB4A9: 0x63F4, //CJK UNIFIED IDEOGRAPH + 0xB4AA: 0x63EA, //CJK UNIFIED IDEOGRAPH + 0xB4AB: 0x63DB, //CJK UNIFIED IDEOGRAPH + 0xB4AC: 0x6452, //CJK UNIFIED IDEOGRAPH + 0xB4AD: 0x63DA, //CJK UNIFIED IDEOGRAPH + 0xB4AE: 0x63F9, //CJK UNIFIED IDEOGRAPH + 0xB4AF: 0x655E, //CJK UNIFIED IDEOGRAPH + 0xB4B0: 0x6566, //CJK UNIFIED IDEOGRAPH + 0xB4B1: 0x6562, //CJK UNIFIED IDEOGRAPH + 0xB4B2: 0x6563, //CJK UNIFIED IDEOGRAPH + 0xB4B3: 0x6591, //CJK UNIFIED IDEOGRAPH + 0xB4B4: 0x6590, //CJK UNIFIED IDEOGRAPH + 0xB4B5: 0x65AF, //CJK UNIFIED IDEOGRAPH + 0xB4B6: 0x666E, //CJK UNIFIED IDEOGRAPH + 0xB4B7: 0x6670, //CJK UNIFIED IDEOGRAPH + 0xB4B8: 0x6674, //CJK UNIFIED IDEOGRAPH + 0xB4B9: 0x6676, //CJK UNIFIED IDEOGRAPH + 0xB4BA: 0x666F, //CJK UNIFIED IDEOGRAPH + 0xB4BB: 0x6691, //CJK UNIFIED IDEOGRAPH + 0xB4BC: 0x667A, //CJK UNIFIED IDEOGRAPH + 0xB4BD: 0x667E, //CJK UNIFIED IDEOGRAPH + 0xB4BE: 0x6677, //CJK UNIFIED IDEOGRAPH + 0xB4BF: 0x66FE, //CJK UNIFIED IDEOGRAPH + 0xB4C0: 0x66FF, //CJK UNIFIED IDEOGRAPH + 0xB4C1: 0x671F, //CJK UNIFIED IDEOGRAPH + 0xB4C2: 0x671D, //CJK UNIFIED IDEOGRAPH + 0xB4C3: 0x68FA, //CJK UNIFIED IDEOGRAPH + 0xB4C4: 0x68D5, //CJK UNIFIED IDEOGRAPH + 0xB4C5: 0x68E0, //CJK UNIFIED IDEOGRAPH + 0xB4C6: 0x68D8, //CJK UNIFIED IDEOGRAPH + 0xB4C7: 0x68D7, //CJK UNIFIED IDEOGRAPH + 0xB4C8: 0x6905, //CJK UNIFIED IDEOGRAPH + 0xB4C9: 0x68DF, //CJK UNIFIED IDEOGRAPH + 0xB4CA: 0x68F5, //CJK UNIFIED IDEOGRAPH + 0xB4CB: 0x68EE, //CJK UNIFIED IDEOGRAPH + 0xB4CC: 0x68E7, //CJK UNIFIED IDEOGRAPH + 0xB4CD: 0x68F9, //CJK UNIFIED IDEOGRAPH + 0xB4CE: 0x68D2, //CJK UNIFIED IDEOGRAPH + 0xB4CF: 0x68F2, //CJK UNIFIED IDEOGRAPH + 0xB4D0: 0x68E3, //CJK UNIFIED IDEOGRAPH + 0xB4D1: 0x68CB, //CJK UNIFIED IDEOGRAPH + 0xB4D2: 0x68CD, //CJK UNIFIED IDEOGRAPH + 0xB4D3: 0x690D, //CJK UNIFIED IDEOGRAPH + 0xB4D4: 0x6912, //CJK UNIFIED IDEOGRAPH + 0xB4D5: 0x690E, //CJK UNIFIED IDEOGRAPH + 0xB4D6: 0x68C9, //CJK UNIFIED IDEOGRAPH + 0xB4D7: 0x68DA, //CJK UNIFIED IDEOGRAPH + 0xB4D8: 0x696E, //CJK UNIFIED IDEOGRAPH + 0xB4D9: 0x68FB, //CJK UNIFIED IDEOGRAPH + 0xB4DA: 0x6B3E, //CJK UNIFIED IDEOGRAPH + 0xB4DB: 0x6B3A, //CJK UNIFIED IDEOGRAPH + 0xB4DC: 0x6B3D, //CJK UNIFIED IDEOGRAPH + 0xB4DD: 0x6B98, //CJK UNIFIED IDEOGRAPH + 0xB4DE: 0x6B96, //CJK UNIFIED IDEOGRAPH + 0xB4DF: 0x6BBC, //CJK UNIFIED IDEOGRAPH + 0xB4E0: 0x6BEF, //CJK UNIFIED IDEOGRAPH + 0xB4E1: 0x6C2E, //CJK UNIFIED IDEOGRAPH + 0xB4E2: 0x6C2F, //CJK UNIFIED IDEOGRAPH + 0xB4E3: 0x6C2C, //CJK UNIFIED IDEOGRAPH + 0xB4E4: 0x6E2F, //CJK UNIFIED IDEOGRAPH + 0xB4E5: 0x6E38, //CJK UNIFIED IDEOGRAPH + 0xB4E6: 0x6E54, //CJK UNIFIED IDEOGRAPH + 0xB4E7: 0x6E21, //CJK UNIFIED IDEOGRAPH + 0xB4E8: 0x6E32, //CJK UNIFIED IDEOGRAPH + 0xB4E9: 0x6E67, //CJK UNIFIED IDEOGRAPH + 0xB4EA: 0x6E4A, //CJK UNIFIED IDEOGRAPH + 0xB4EB: 0x6E20, //CJK UNIFIED IDEOGRAPH + 0xB4EC: 0x6E25, //CJK UNIFIED IDEOGRAPH + 0xB4ED: 0x6E23, //CJK UNIFIED IDEOGRAPH + 0xB4EE: 0x6E1B, //CJK UNIFIED IDEOGRAPH + 0xB4EF: 0x6E5B, //CJK UNIFIED IDEOGRAPH + 0xB4F0: 0x6E58, //CJK UNIFIED IDEOGRAPH + 0xB4F1: 0x6E24, //CJK UNIFIED IDEOGRAPH + 0xB4F2: 0x6E56, //CJK UNIFIED IDEOGRAPH + 0xB4F3: 0x6E6E, //CJK UNIFIED IDEOGRAPH + 0xB4F4: 0x6E2D, //CJK UNIFIED IDEOGRAPH + 0xB4F5: 0x6E26, //CJK UNIFIED IDEOGRAPH + 0xB4F6: 0x6E6F, //CJK UNIFIED IDEOGRAPH + 0xB4F7: 0x6E34, //CJK UNIFIED IDEOGRAPH + 0xB4F8: 0x6E4D, //CJK UNIFIED IDEOGRAPH + 0xB4F9: 0x6E3A, //CJK UNIFIED IDEOGRAPH + 0xB4FA: 0x6E2C, //CJK UNIFIED IDEOGRAPH + 0xB4FB: 0x6E43, //CJK UNIFIED IDEOGRAPH + 0xB4FC: 0x6E1D, //CJK UNIFIED IDEOGRAPH + 0xB4FD: 0x6E3E, //CJK UNIFIED IDEOGRAPH + 0xB4FE: 0x6ECB, //CJK UNIFIED IDEOGRAPH + 0xB540: 0x6E89, //CJK UNIFIED IDEOGRAPH + 0xB541: 0x6E19, //CJK UNIFIED IDEOGRAPH + 0xB542: 0x6E4E, //CJK UNIFIED IDEOGRAPH + 0xB543: 0x6E63, //CJK UNIFIED IDEOGRAPH + 0xB544: 0x6E44, //CJK UNIFIED IDEOGRAPH + 0xB545: 0x6E72, //CJK UNIFIED IDEOGRAPH + 0xB546: 0x6E69, //CJK UNIFIED IDEOGRAPH + 0xB547: 0x6E5F, //CJK UNIFIED IDEOGRAPH + 0xB548: 0x7119, //CJK UNIFIED IDEOGRAPH + 0xB549: 0x711A, //CJK UNIFIED IDEOGRAPH + 0xB54A: 0x7126, //CJK UNIFIED IDEOGRAPH + 0xB54B: 0x7130, //CJK UNIFIED IDEOGRAPH + 0xB54C: 0x7121, //CJK UNIFIED IDEOGRAPH + 0xB54D: 0x7136, //CJK UNIFIED IDEOGRAPH + 0xB54E: 0x716E, //CJK UNIFIED IDEOGRAPH + 0xB54F: 0x711C, //CJK UNIFIED IDEOGRAPH + 0xB550: 0x724C, //CJK UNIFIED IDEOGRAPH + 0xB551: 0x7284, //CJK UNIFIED IDEOGRAPH + 0xB552: 0x7280, //CJK UNIFIED IDEOGRAPH + 0xB553: 0x7336, //CJK UNIFIED IDEOGRAPH + 0xB554: 0x7325, //CJK UNIFIED IDEOGRAPH + 0xB555: 0x7334, //CJK UNIFIED IDEOGRAPH + 0xB556: 0x7329, //CJK UNIFIED IDEOGRAPH + 0xB557: 0x743A, //CJK UNIFIED IDEOGRAPH + 0xB558: 0x742A, //CJK UNIFIED IDEOGRAPH + 0xB559: 0x7433, //CJK UNIFIED IDEOGRAPH + 0xB55A: 0x7422, //CJK UNIFIED IDEOGRAPH + 0xB55B: 0x7425, //CJK UNIFIED IDEOGRAPH + 0xB55C: 0x7435, //CJK UNIFIED IDEOGRAPH + 0xB55D: 0x7436, //CJK UNIFIED IDEOGRAPH + 0xB55E: 0x7434, //CJK UNIFIED IDEOGRAPH + 0xB55F: 0x742F, //CJK UNIFIED IDEOGRAPH + 0xB560: 0x741B, //CJK UNIFIED IDEOGRAPH + 0xB561: 0x7426, //CJK UNIFIED IDEOGRAPH + 0xB562: 0x7428, //CJK UNIFIED IDEOGRAPH + 0xB563: 0x7525, //CJK UNIFIED IDEOGRAPH + 0xB564: 0x7526, //CJK UNIFIED IDEOGRAPH + 0xB565: 0x756B, //CJK UNIFIED IDEOGRAPH + 0xB566: 0x756A, //CJK UNIFIED IDEOGRAPH + 0xB567: 0x75E2, //CJK UNIFIED IDEOGRAPH + 0xB568: 0x75DB, //CJK UNIFIED IDEOGRAPH + 0xB569: 0x75E3, //CJK UNIFIED IDEOGRAPH + 0xB56A: 0x75D9, //CJK UNIFIED IDEOGRAPH + 0xB56B: 0x75D8, //CJK UNIFIED IDEOGRAPH + 0xB56C: 0x75DE, //CJK UNIFIED IDEOGRAPH + 0xB56D: 0x75E0, //CJK UNIFIED IDEOGRAPH + 0xB56E: 0x767B, //CJK UNIFIED IDEOGRAPH + 0xB56F: 0x767C, //CJK UNIFIED IDEOGRAPH + 0xB570: 0x7696, //CJK UNIFIED IDEOGRAPH + 0xB571: 0x7693, //CJK UNIFIED IDEOGRAPH + 0xB572: 0x76B4, //CJK UNIFIED IDEOGRAPH + 0xB573: 0x76DC, //CJK UNIFIED IDEOGRAPH + 0xB574: 0x774F, //CJK UNIFIED IDEOGRAPH + 0xB575: 0x77ED, //CJK UNIFIED IDEOGRAPH + 0xB576: 0x785D, //CJK UNIFIED IDEOGRAPH + 0xB577: 0x786C, //CJK UNIFIED IDEOGRAPH + 0xB578: 0x786F, //CJK UNIFIED IDEOGRAPH + 0xB579: 0x7A0D, //CJK UNIFIED IDEOGRAPH + 0xB57A: 0x7A08, //CJK UNIFIED IDEOGRAPH + 0xB57B: 0x7A0B, //CJK UNIFIED IDEOGRAPH + 0xB57C: 0x7A05, //CJK UNIFIED IDEOGRAPH + 0xB57D: 0x7A00, //CJK UNIFIED IDEOGRAPH + 0xB57E: 0x7A98, //CJK UNIFIED IDEOGRAPH + 0xB5A1: 0x7A97, //CJK UNIFIED IDEOGRAPH + 0xB5A2: 0x7A96, //CJK UNIFIED IDEOGRAPH + 0xB5A3: 0x7AE5, //CJK UNIFIED IDEOGRAPH + 0xB5A4: 0x7AE3, //CJK UNIFIED IDEOGRAPH + 0xB5A5: 0x7B49, //CJK UNIFIED IDEOGRAPH + 0xB5A6: 0x7B56, //CJK UNIFIED IDEOGRAPH + 0xB5A7: 0x7B46, //CJK UNIFIED IDEOGRAPH + 0xB5A8: 0x7B50, //CJK UNIFIED IDEOGRAPH + 0xB5A9: 0x7B52, //CJK UNIFIED IDEOGRAPH + 0xB5AA: 0x7B54, //CJK UNIFIED IDEOGRAPH + 0xB5AB: 0x7B4D, //CJK UNIFIED IDEOGRAPH + 0xB5AC: 0x7B4B, //CJK UNIFIED IDEOGRAPH + 0xB5AD: 0x7B4F, //CJK UNIFIED IDEOGRAPH + 0xB5AE: 0x7B51, //CJK UNIFIED IDEOGRAPH + 0xB5AF: 0x7C9F, //CJK UNIFIED IDEOGRAPH + 0xB5B0: 0x7CA5, //CJK UNIFIED IDEOGRAPH + 0xB5B1: 0x7D5E, //CJK UNIFIED IDEOGRAPH + 0xB5B2: 0x7D50, //CJK UNIFIED IDEOGRAPH + 0xB5B3: 0x7D68, //CJK UNIFIED IDEOGRAPH + 0xB5B4: 0x7D55, //CJK UNIFIED IDEOGRAPH + 0xB5B5: 0x7D2B, //CJK UNIFIED IDEOGRAPH + 0xB5B6: 0x7D6E, //CJK UNIFIED IDEOGRAPH + 0xB5B7: 0x7D72, //CJK UNIFIED IDEOGRAPH + 0xB5B8: 0x7D61, //CJK UNIFIED IDEOGRAPH + 0xB5B9: 0x7D66, //CJK UNIFIED IDEOGRAPH + 0xB5BA: 0x7D62, //CJK UNIFIED IDEOGRAPH + 0xB5BB: 0x7D70, //CJK UNIFIED IDEOGRAPH + 0xB5BC: 0x7D73, //CJK UNIFIED IDEOGRAPH + 0xB5BD: 0x5584, //CJK UNIFIED IDEOGRAPH + 0xB5BE: 0x7FD4, //CJK UNIFIED IDEOGRAPH + 0xB5BF: 0x7FD5, //CJK UNIFIED IDEOGRAPH + 0xB5C0: 0x800B, //CJK UNIFIED IDEOGRAPH + 0xB5C1: 0x8052, //CJK UNIFIED IDEOGRAPH + 0xB5C2: 0x8085, //CJK UNIFIED IDEOGRAPH + 0xB5C3: 0x8155, //CJK UNIFIED IDEOGRAPH + 0xB5C4: 0x8154, //CJK UNIFIED IDEOGRAPH + 0xB5C5: 0x814B, //CJK UNIFIED IDEOGRAPH + 0xB5C6: 0x8151, //CJK UNIFIED IDEOGRAPH + 0xB5C7: 0x814E, //CJK UNIFIED IDEOGRAPH + 0xB5C8: 0x8139, //CJK UNIFIED IDEOGRAPH + 0xB5C9: 0x8146, //CJK UNIFIED IDEOGRAPH + 0xB5CA: 0x813E, //CJK UNIFIED IDEOGRAPH + 0xB5CB: 0x814C, //CJK UNIFIED IDEOGRAPH + 0xB5CC: 0x8153, //CJK UNIFIED IDEOGRAPH + 0xB5CD: 0x8174, //CJK UNIFIED IDEOGRAPH + 0xB5CE: 0x8212, //CJK UNIFIED IDEOGRAPH + 0xB5CF: 0x821C, //CJK UNIFIED IDEOGRAPH + 0xB5D0: 0x83E9, //CJK UNIFIED IDEOGRAPH + 0xB5D1: 0x8403, //CJK UNIFIED IDEOGRAPH + 0xB5D2: 0x83F8, //CJK UNIFIED IDEOGRAPH + 0xB5D3: 0x840D, //CJK UNIFIED IDEOGRAPH + 0xB5D4: 0x83E0, //CJK UNIFIED IDEOGRAPH + 0xB5D5: 0x83C5, //CJK UNIFIED IDEOGRAPH + 0xB5D6: 0x840B, //CJK UNIFIED IDEOGRAPH + 0xB5D7: 0x83C1, //CJK UNIFIED IDEOGRAPH + 0xB5D8: 0x83EF, //CJK UNIFIED IDEOGRAPH + 0xB5D9: 0x83F1, //CJK UNIFIED IDEOGRAPH + 0xB5DA: 0x83F4, //CJK UNIFIED IDEOGRAPH + 0xB5DB: 0x8457, //CJK UNIFIED IDEOGRAPH + 0xB5DC: 0x840A, //CJK UNIFIED IDEOGRAPH + 0xB5DD: 0x83F0, //CJK UNIFIED IDEOGRAPH + 0xB5DE: 0x840C, //CJK UNIFIED IDEOGRAPH + 0xB5DF: 0x83CC, //CJK UNIFIED IDEOGRAPH + 0xB5E0: 0x83FD, //CJK UNIFIED IDEOGRAPH + 0xB5E1: 0x83F2, //CJK UNIFIED IDEOGRAPH + 0xB5E2: 0x83CA, //CJK UNIFIED IDEOGRAPH + 0xB5E3: 0x8438, //CJK UNIFIED IDEOGRAPH + 0xB5E4: 0x840E, //CJK UNIFIED IDEOGRAPH + 0xB5E5: 0x8404, //CJK UNIFIED IDEOGRAPH + 0xB5E6: 0x83DC, //CJK UNIFIED IDEOGRAPH + 0xB5E7: 0x8407, //CJK UNIFIED IDEOGRAPH + 0xB5E8: 0x83D4, //CJK UNIFIED IDEOGRAPH + 0xB5E9: 0x83DF, //CJK UNIFIED IDEOGRAPH + 0xB5EA: 0x865B, //CJK UNIFIED IDEOGRAPH + 0xB5EB: 0x86DF, //CJK UNIFIED IDEOGRAPH + 0xB5EC: 0x86D9, //CJK UNIFIED IDEOGRAPH + 0xB5ED: 0x86ED, //CJK UNIFIED IDEOGRAPH + 0xB5EE: 0x86D4, //CJK UNIFIED IDEOGRAPH + 0xB5EF: 0x86DB, //CJK UNIFIED IDEOGRAPH + 0xB5F0: 0x86E4, //CJK UNIFIED IDEOGRAPH + 0xB5F1: 0x86D0, //CJK UNIFIED IDEOGRAPH + 0xB5F2: 0x86DE, //CJK UNIFIED IDEOGRAPH + 0xB5F3: 0x8857, //CJK UNIFIED IDEOGRAPH + 0xB5F4: 0x88C1, //CJK UNIFIED IDEOGRAPH + 0xB5F5: 0x88C2, //CJK UNIFIED IDEOGRAPH + 0xB5F6: 0x88B1, //CJK UNIFIED IDEOGRAPH + 0xB5F7: 0x8983, //CJK UNIFIED IDEOGRAPH + 0xB5F8: 0x8996, //CJK UNIFIED IDEOGRAPH + 0xB5F9: 0x8A3B, //CJK UNIFIED IDEOGRAPH + 0xB5FA: 0x8A60, //CJK UNIFIED IDEOGRAPH + 0xB5FB: 0x8A55, //CJK UNIFIED IDEOGRAPH + 0xB5FC: 0x8A5E, //CJK UNIFIED IDEOGRAPH + 0xB5FD: 0x8A3C, //CJK UNIFIED IDEOGRAPH + 0xB5FE: 0x8A41, //CJK UNIFIED IDEOGRAPH + 0xB640: 0x8A54, //CJK UNIFIED IDEOGRAPH + 0xB641: 0x8A5B, //CJK UNIFIED IDEOGRAPH + 0xB642: 0x8A50, //CJK UNIFIED IDEOGRAPH + 0xB643: 0x8A46, //CJK UNIFIED IDEOGRAPH + 0xB644: 0x8A34, //CJK UNIFIED IDEOGRAPH + 0xB645: 0x8A3A, //CJK UNIFIED IDEOGRAPH + 0xB646: 0x8A36, //CJK UNIFIED IDEOGRAPH + 0xB647: 0x8A56, //CJK UNIFIED IDEOGRAPH + 0xB648: 0x8C61, //CJK UNIFIED IDEOGRAPH + 0xB649: 0x8C82, //CJK UNIFIED IDEOGRAPH + 0xB64A: 0x8CAF, //CJK UNIFIED IDEOGRAPH + 0xB64B: 0x8CBC, //CJK UNIFIED IDEOGRAPH + 0xB64C: 0x8CB3, //CJK UNIFIED IDEOGRAPH + 0xB64D: 0x8CBD, //CJK UNIFIED IDEOGRAPH + 0xB64E: 0x8CC1, //CJK UNIFIED IDEOGRAPH + 0xB64F: 0x8CBB, //CJK UNIFIED IDEOGRAPH + 0xB650: 0x8CC0, //CJK UNIFIED IDEOGRAPH + 0xB651: 0x8CB4, //CJK UNIFIED IDEOGRAPH + 0xB652: 0x8CB7, //CJK UNIFIED IDEOGRAPH + 0xB653: 0x8CB6, //CJK UNIFIED IDEOGRAPH + 0xB654: 0x8CBF, //CJK UNIFIED IDEOGRAPH + 0xB655: 0x8CB8, //CJK UNIFIED IDEOGRAPH + 0xB656: 0x8D8A, //CJK UNIFIED IDEOGRAPH + 0xB657: 0x8D85, //CJK UNIFIED IDEOGRAPH + 0xB658: 0x8D81, //CJK UNIFIED IDEOGRAPH + 0xB659: 0x8DCE, //CJK UNIFIED IDEOGRAPH + 0xB65A: 0x8DDD, //CJK UNIFIED IDEOGRAPH + 0xB65B: 0x8DCB, //CJK UNIFIED IDEOGRAPH + 0xB65C: 0x8DDA, //CJK UNIFIED IDEOGRAPH + 0xB65D: 0x8DD1, //CJK UNIFIED IDEOGRAPH + 0xB65E: 0x8DCC, //CJK UNIFIED IDEOGRAPH + 0xB65F: 0x8DDB, //CJK UNIFIED IDEOGRAPH + 0xB660: 0x8DC6, //CJK UNIFIED IDEOGRAPH + 0xB661: 0x8EFB, //CJK UNIFIED IDEOGRAPH + 0xB662: 0x8EF8, //CJK UNIFIED IDEOGRAPH + 0xB663: 0x8EFC, //CJK UNIFIED IDEOGRAPH + 0xB664: 0x8F9C, //CJK UNIFIED IDEOGRAPH + 0xB665: 0x902E, //CJK UNIFIED IDEOGRAPH + 0xB666: 0x9035, //CJK UNIFIED IDEOGRAPH + 0xB667: 0x9031, //CJK UNIFIED IDEOGRAPH + 0xB668: 0x9038, //CJK UNIFIED IDEOGRAPH + 0xB669: 0x9032, //CJK UNIFIED IDEOGRAPH + 0xB66A: 0x9036, //CJK UNIFIED IDEOGRAPH + 0xB66B: 0x9102, //CJK UNIFIED IDEOGRAPH + 0xB66C: 0x90F5, //CJK UNIFIED IDEOGRAPH + 0xB66D: 0x9109, //CJK UNIFIED IDEOGRAPH + 0xB66E: 0x90FE, //CJK UNIFIED IDEOGRAPH + 0xB66F: 0x9163, //CJK UNIFIED IDEOGRAPH + 0xB670: 0x9165, //CJK UNIFIED IDEOGRAPH + 0xB671: 0x91CF, //CJK UNIFIED IDEOGRAPH + 0xB672: 0x9214, //CJK UNIFIED IDEOGRAPH + 0xB673: 0x9215, //CJK UNIFIED IDEOGRAPH + 0xB674: 0x9223, //CJK UNIFIED IDEOGRAPH + 0xB675: 0x9209, //CJK UNIFIED IDEOGRAPH + 0xB676: 0x921E, //CJK UNIFIED IDEOGRAPH + 0xB677: 0x920D, //CJK UNIFIED IDEOGRAPH + 0xB678: 0x9210, //CJK UNIFIED IDEOGRAPH + 0xB679: 0x9207, //CJK UNIFIED IDEOGRAPH + 0xB67A: 0x9211, //CJK UNIFIED IDEOGRAPH + 0xB67B: 0x9594, //CJK UNIFIED IDEOGRAPH + 0xB67C: 0x958F, //CJK UNIFIED IDEOGRAPH + 0xB67D: 0x958B, //CJK UNIFIED IDEOGRAPH + 0xB67E: 0x9591, //CJK UNIFIED IDEOGRAPH + 0xB6A1: 0x9593, //CJK UNIFIED IDEOGRAPH + 0xB6A2: 0x9592, //CJK UNIFIED IDEOGRAPH + 0xB6A3: 0x958E, //CJK UNIFIED IDEOGRAPH + 0xB6A4: 0x968A, //CJK UNIFIED IDEOGRAPH + 0xB6A5: 0x968E, //CJK UNIFIED IDEOGRAPH + 0xB6A6: 0x968B, //CJK UNIFIED IDEOGRAPH + 0xB6A7: 0x967D, //CJK UNIFIED IDEOGRAPH + 0xB6A8: 0x9685, //CJK UNIFIED IDEOGRAPH + 0xB6A9: 0x9686, //CJK UNIFIED IDEOGRAPH + 0xB6AA: 0x968D, //CJK UNIFIED IDEOGRAPH + 0xB6AB: 0x9672, //CJK UNIFIED IDEOGRAPH + 0xB6AC: 0x9684, //CJK UNIFIED IDEOGRAPH + 0xB6AD: 0x96C1, //CJK UNIFIED IDEOGRAPH + 0xB6AE: 0x96C5, //CJK UNIFIED IDEOGRAPH + 0xB6AF: 0x96C4, //CJK UNIFIED IDEOGRAPH + 0xB6B0: 0x96C6, //CJK UNIFIED IDEOGRAPH + 0xB6B1: 0x96C7, //CJK UNIFIED IDEOGRAPH + 0xB6B2: 0x96EF, //CJK UNIFIED IDEOGRAPH + 0xB6B3: 0x96F2, //CJK UNIFIED IDEOGRAPH + 0xB6B4: 0x97CC, //CJK UNIFIED IDEOGRAPH + 0xB6B5: 0x9805, //CJK UNIFIED IDEOGRAPH + 0xB6B6: 0x9806, //CJK UNIFIED IDEOGRAPH + 0xB6B7: 0x9808, //CJK UNIFIED IDEOGRAPH + 0xB6B8: 0x98E7, //CJK UNIFIED IDEOGRAPH + 0xB6B9: 0x98EA, //CJK UNIFIED IDEOGRAPH + 0xB6BA: 0x98EF, //CJK UNIFIED IDEOGRAPH + 0xB6BB: 0x98E9, //CJK UNIFIED IDEOGRAPH + 0xB6BC: 0x98F2, //CJK UNIFIED IDEOGRAPH + 0xB6BD: 0x98ED, //CJK UNIFIED IDEOGRAPH + 0xB6BE: 0x99AE, //CJK UNIFIED IDEOGRAPH + 0xB6BF: 0x99AD, //CJK UNIFIED IDEOGRAPH + 0xB6C0: 0x9EC3, //CJK UNIFIED IDEOGRAPH + 0xB6C1: 0x9ECD, //CJK UNIFIED IDEOGRAPH + 0xB6C2: 0x9ED1, //CJK UNIFIED IDEOGRAPH + 0xB6C3: 0x4E82, //CJK UNIFIED IDEOGRAPH + 0xB6C4: 0x50AD, //CJK UNIFIED IDEOGRAPH + 0xB6C5: 0x50B5, //CJK UNIFIED IDEOGRAPH + 0xB6C6: 0x50B2, //CJK UNIFIED IDEOGRAPH + 0xB6C7: 0x50B3, //CJK UNIFIED IDEOGRAPH + 0xB6C8: 0x50C5, //CJK UNIFIED IDEOGRAPH + 0xB6C9: 0x50BE, //CJK UNIFIED IDEOGRAPH + 0xB6CA: 0x50AC, //CJK UNIFIED IDEOGRAPH + 0xB6CB: 0x50B7, //CJK UNIFIED IDEOGRAPH + 0xB6CC: 0x50BB, //CJK UNIFIED IDEOGRAPH + 0xB6CD: 0x50AF, //CJK UNIFIED IDEOGRAPH + 0xB6CE: 0x50C7, //CJK UNIFIED IDEOGRAPH + 0xB6CF: 0x527F, //CJK UNIFIED IDEOGRAPH + 0xB6D0: 0x5277, //CJK UNIFIED IDEOGRAPH + 0xB6D1: 0x527D, //CJK UNIFIED IDEOGRAPH + 0xB6D2: 0x52DF, //CJK UNIFIED IDEOGRAPH + 0xB6D3: 0x52E6, //CJK UNIFIED IDEOGRAPH + 0xB6D4: 0x52E4, //CJK UNIFIED IDEOGRAPH + 0xB6D5: 0x52E2, //CJK UNIFIED IDEOGRAPH + 0xB6D6: 0x52E3, //CJK UNIFIED IDEOGRAPH + 0xB6D7: 0x532F, //CJK UNIFIED IDEOGRAPH + 0xB6D8: 0x55DF, //CJK UNIFIED IDEOGRAPH + 0xB6D9: 0x55E8, //CJK UNIFIED IDEOGRAPH + 0xB6DA: 0x55D3, //CJK UNIFIED IDEOGRAPH + 0xB6DB: 0x55E6, //CJK UNIFIED IDEOGRAPH + 0xB6DC: 0x55CE, //CJK UNIFIED IDEOGRAPH + 0xB6DD: 0x55DC, //CJK UNIFIED IDEOGRAPH + 0xB6DE: 0x55C7, //CJK UNIFIED IDEOGRAPH + 0xB6DF: 0x55D1, //CJK UNIFIED IDEOGRAPH + 0xB6E0: 0x55E3, //CJK UNIFIED IDEOGRAPH + 0xB6E1: 0x55E4, //CJK UNIFIED IDEOGRAPH + 0xB6E2: 0x55EF, //CJK UNIFIED IDEOGRAPH + 0xB6E3: 0x55DA, //CJK UNIFIED IDEOGRAPH + 0xB6E4: 0x55E1, //CJK UNIFIED IDEOGRAPH + 0xB6E5: 0x55C5, //CJK UNIFIED IDEOGRAPH + 0xB6E6: 0x55C6, //CJK UNIFIED IDEOGRAPH + 0xB6E7: 0x55E5, //CJK UNIFIED IDEOGRAPH + 0xB6E8: 0x55C9, //CJK UNIFIED IDEOGRAPH + 0xB6E9: 0x5712, //CJK UNIFIED IDEOGRAPH + 0xB6EA: 0x5713, //CJK UNIFIED IDEOGRAPH + 0xB6EB: 0x585E, //CJK UNIFIED IDEOGRAPH + 0xB6EC: 0x5851, //CJK UNIFIED IDEOGRAPH + 0xB6ED: 0x5858, //CJK UNIFIED IDEOGRAPH + 0xB6EE: 0x5857, //CJK UNIFIED IDEOGRAPH + 0xB6EF: 0x585A, //CJK UNIFIED IDEOGRAPH + 0xB6F0: 0x5854, //CJK UNIFIED IDEOGRAPH + 0xB6F1: 0x586B, //CJK UNIFIED IDEOGRAPH + 0xB6F2: 0x584C, //CJK UNIFIED IDEOGRAPH + 0xB6F3: 0x586D, //CJK UNIFIED IDEOGRAPH + 0xB6F4: 0x584A, //CJK UNIFIED IDEOGRAPH + 0xB6F5: 0x5862, //CJK UNIFIED IDEOGRAPH + 0xB6F6: 0x5852, //CJK UNIFIED IDEOGRAPH + 0xB6F7: 0x584B, //CJK UNIFIED IDEOGRAPH + 0xB6F8: 0x5967, //CJK UNIFIED IDEOGRAPH + 0xB6F9: 0x5AC1, //CJK UNIFIED IDEOGRAPH + 0xB6FA: 0x5AC9, //CJK UNIFIED IDEOGRAPH + 0xB6FB: 0x5ACC, //CJK UNIFIED IDEOGRAPH + 0xB6FC: 0x5ABE, //CJK UNIFIED IDEOGRAPH + 0xB6FD: 0x5ABD, //CJK UNIFIED IDEOGRAPH + 0xB6FE: 0x5ABC, //CJK UNIFIED IDEOGRAPH + 0xB740: 0x5AB3, //CJK UNIFIED IDEOGRAPH + 0xB741: 0x5AC2, //CJK UNIFIED IDEOGRAPH + 0xB742: 0x5AB2, //CJK UNIFIED IDEOGRAPH + 0xB743: 0x5D69, //CJK UNIFIED IDEOGRAPH + 0xB744: 0x5D6F, //CJK UNIFIED IDEOGRAPH + 0xB745: 0x5E4C, //CJK UNIFIED IDEOGRAPH + 0xB746: 0x5E79, //CJK UNIFIED IDEOGRAPH + 0xB747: 0x5EC9, //CJK UNIFIED IDEOGRAPH + 0xB748: 0x5EC8, //CJK UNIFIED IDEOGRAPH + 0xB749: 0x5F12, //CJK UNIFIED IDEOGRAPH + 0xB74A: 0x5F59, //CJK UNIFIED IDEOGRAPH + 0xB74B: 0x5FAC, //CJK UNIFIED IDEOGRAPH + 0xB74C: 0x5FAE, //CJK UNIFIED IDEOGRAPH + 0xB74D: 0x611A, //CJK UNIFIED IDEOGRAPH + 0xB74E: 0x610F, //CJK UNIFIED IDEOGRAPH + 0xB74F: 0x6148, //CJK UNIFIED IDEOGRAPH + 0xB750: 0x611F, //CJK UNIFIED IDEOGRAPH + 0xB751: 0x60F3, //CJK UNIFIED IDEOGRAPH + 0xB752: 0x611B, //CJK UNIFIED IDEOGRAPH + 0xB753: 0x60F9, //CJK UNIFIED IDEOGRAPH + 0xB754: 0x6101, //CJK UNIFIED IDEOGRAPH + 0xB755: 0x6108, //CJK UNIFIED IDEOGRAPH + 0xB756: 0x614E, //CJK UNIFIED IDEOGRAPH + 0xB757: 0x614C, //CJK UNIFIED IDEOGRAPH + 0xB758: 0x6144, //CJK UNIFIED IDEOGRAPH + 0xB759: 0x614D, //CJK UNIFIED IDEOGRAPH + 0xB75A: 0x613E, //CJK UNIFIED IDEOGRAPH + 0xB75B: 0x6134, //CJK UNIFIED IDEOGRAPH + 0xB75C: 0x6127, //CJK UNIFIED IDEOGRAPH + 0xB75D: 0x610D, //CJK UNIFIED IDEOGRAPH + 0xB75E: 0x6106, //CJK UNIFIED IDEOGRAPH + 0xB75F: 0x6137, //CJK UNIFIED IDEOGRAPH + 0xB760: 0x6221, //CJK UNIFIED IDEOGRAPH + 0xB761: 0x6222, //CJK UNIFIED IDEOGRAPH + 0xB762: 0x6413, //CJK UNIFIED IDEOGRAPH + 0xB763: 0x643E, //CJK UNIFIED IDEOGRAPH + 0xB764: 0x641E, //CJK UNIFIED IDEOGRAPH + 0xB765: 0x642A, //CJK UNIFIED IDEOGRAPH + 0xB766: 0x642D, //CJK UNIFIED IDEOGRAPH + 0xB767: 0x643D, //CJK UNIFIED IDEOGRAPH + 0xB768: 0x642C, //CJK UNIFIED IDEOGRAPH + 0xB769: 0x640F, //CJK UNIFIED IDEOGRAPH + 0xB76A: 0x641C, //CJK UNIFIED IDEOGRAPH + 0xB76B: 0x6414, //CJK UNIFIED IDEOGRAPH + 0xB76C: 0x640D, //CJK UNIFIED IDEOGRAPH + 0xB76D: 0x6436, //CJK UNIFIED IDEOGRAPH + 0xB76E: 0x6416, //CJK UNIFIED IDEOGRAPH + 0xB76F: 0x6417, //CJK UNIFIED IDEOGRAPH + 0xB770: 0x6406, //CJK UNIFIED IDEOGRAPH + 0xB771: 0x656C, //CJK UNIFIED IDEOGRAPH + 0xB772: 0x659F, //CJK UNIFIED IDEOGRAPH + 0xB773: 0x65B0, //CJK UNIFIED IDEOGRAPH + 0xB774: 0x6697, //CJK UNIFIED IDEOGRAPH + 0xB775: 0x6689, //CJK UNIFIED IDEOGRAPH + 0xB776: 0x6687, //CJK UNIFIED IDEOGRAPH + 0xB777: 0x6688, //CJK UNIFIED IDEOGRAPH + 0xB778: 0x6696, //CJK UNIFIED IDEOGRAPH + 0xB779: 0x6684, //CJK UNIFIED IDEOGRAPH + 0xB77A: 0x6698, //CJK UNIFIED IDEOGRAPH + 0xB77B: 0x668D, //CJK UNIFIED IDEOGRAPH + 0xB77C: 0x6703, //CJK UNIFIED IDEOGRAPH + 0xB77D: 0x6994, //CJK UNIFIED IDEOGRAPH + 0xB77E: 0x696D, //CJK UNIFIED IDEOGRAPH + 0xB7A1: 0x695A, //CJK UNIFIED IDEOGRAPH + 0xB7A2: 0x6977, //CJK UNIFIED IDEOGRAPH + 0xB7A3: 0x6960, //CJK UNIFIED IDEOGRAPH + 0xB7A4: 0x6954, //CJK UNIFIED IDEOGRAPH + 0xB7A5: 0x6975, //CJK UNIFIED IDEOGRAPH + 0xB7A6: 0x6930, //CJK UNIFIED IDEOGRAPH + 0xB7A7: 0x6982, //CJK UNIFIED IDEOGRAPH + 0xB7A8: 0x694A, //CJK UNIFIED IDEOGRAPH + 0xB7A9: 0x6968, //CJK UNIFIED IDEOGRAPH + 0xB7AA: 0x696B, //CJK UNIFIED IDEOGRAPH + 0xB7AB: 0x695E, //CJK UNIFIED IDEOGRAPH + 0xB7AC: 0x6953, //CJK UNIFIED IDEOGRAPH + 0xB7AD: 0x6979, //CJK UNIFIED IDEOGRAPH + 0xB7AE: 0x6986, //CJK UNIFIED IDEOGRAPH + 0xB7AF: 0x695D, //CJK UNIFIED IDEOGRAPH + 0xB7B0: 0x6963, //CJK UNIFIED IDEOGRAPH + 0xB7B1: 0x695B, //CJK UNIFIED IDEOGRAPH + 0xB7B2: 0x6B47, //CJK UNIFIED IDEOGRAPH + 0xB7B3: 0x6B72, //CJK UNIFIED IDEOGRAPH + 0xB7B4: 0x6BC0, //CJK UNIFIED IDEOGRAPH + 0xB7B5: 0x6BBF, //CJK UNIFIED IDEOGRAPH + 0xB7B6: 0x6BD3, //CJK UNIFIED IDEOGRAPH + 0xB7B7: 0x6BFD, //CJK UNIFIED IDEOGRAPH + 0xB7B8: 0x6EA2, //CJK UNIFIED IDEOGRAPH + 0xB7B9: 0x6EAF, //CJK UNIFIED IDEOGRAPH + 0xB7BA: 0x6ED3, //CJK UNIFIED IDEOGRAPH + 0xB7BB: 0x6EB6, //CJK UNIFIED IDEOGRAPH + 0xB7BC: 0x6EC2, //CJK UNIFIED IDEOGRAPH + 0xB7BD: 0x6E90, //CJK UNIFIED IDEOGRAPH + 0xB7BE: 0x6E9D, //CJK UNIFIED IDEOGRAPH + 0xB7BF: 0x6EC7, //CJK UNIFIED IDEOGRAPH + 0xB7C0: 0x6EC5, //CJK UNIFIED IDEOGRAPH + 0xB7C1: 0x6EA5, //CJK UNIFIED IDEOGRAPH + 0xB7C2: 0x6E98, //CJK UNIFIED IDEOGRAPH + 0xB7C3: 0x6EBC, //CJK UNIFIED IDEOGRAPH + 0xB7C4: 0x6EBA, //CJK UNIFIED IDEOGRAPH + 0xB7C5: 0x6EAB, //CJK UNIFIED IDEOGRAPH + 0xB7C6: 0x6ED1, //CJK UNIFIED IDEOGRAPH + 0xB7C7: 0x6E96, //CJK UNIFIED IDEOGRAPH + 0xB7C8: 0x6E9C, //CJK UNIFIED IDEOGRAPH + 0xB7C9: 0x6EC4, //CJK UNIFIED IDEOGRAPH + 0xB7CA: 0x6ED4, //CJK UNIFIED IDEOGRAPH + 0xB7CB: 0x6EAA, //CJK UNIFIED IDEOGRAPH + 0xB7CC: 0x6EA7, //CJK UNIFIED IDEOGRAPH + 0xB7CD: 0x6EB4, //CJK UNIFIED IDEOGRAPH + 0xB7CE: 0x714E, //CJK UNIFIED IDEOGRAPH + 0xB7CF: 0x7159, //CJK UNIFIED IDEOGRAPH + 0xB7D0: 0x7169, //CJK UNIFIED IDEOGRAPH + 0xB7D1: 0x7164, //CJK UNIFIED IDEOGRAPH + 0xB7D2: 0x7149, //CJK UNIFIED IDEOGRAPH + 0xB7D3: 0x7167, //CJK UNIFIED IDEOGRAPH + 0xB7D4: 0x715C, //CJK UNIFIED IDEOGRAPH + 0xB7D5: 0x716C, //CJK UNIFIED IDEOGRAPH + 0xB7D6: 0x7166, //CJK UNIFIED IDEOGRAPH + 0xB7D7: 0x714C, //CJK UNIFIED IDEOGRAPH + 0xB7D8: 0x7165, //CJK UNIFIED IDEOGRAPH + 0xB7D9: 0x715E, //CJK UNIFIED IDEOGRAPH + 0xB7DA: 0x7146, //CJK UNIFIED IDEOGRAPH + 0xB7DB: 0x7168, //CJK UNIFIED IDEOGRAPH + 0xB7DC: 0x7156, //CJK UNIFIED IDEOGRAPH + 0xB7DD: 0x723A, //CJK UNIFIED IDEOGRAPH + 0xB7DE: 0x7252, //CJK UNIFIED IDEOGRAPH + 0xB7DF: 0x7337, //CJK UNIFIED IDEOGRAPH + 0xB7E0: 0x7345, //CJK UNIFIED IDEOGRAPH + 0xB7E1: 0x733F, //CJK UNIFIED IDEOGRAPH + 0xB7E2: 0x733E, //CJK UNIFIED IDEOGRAPH + 0xB7E3: 0x746F, //CJK UNIFIED IDEOGRAPH + 0xB7E4: 0x745A, //CJK UNIFIED IDEOGRAPH + 0xB7E5: 0x7455, //CJK UNIFIED IDEOGRAPH + 0xB7E6: 0x745F, //CJK UNIFIED IDEOGRAPH + 0xB7E7: 0x745E, //CJK UNIFIED IDEOGRAPH + 0xB7E8: 0x7441, //CJK UNIFIED IDEOGRAPH + 0xB7E9: 0x743F, //CJK UNIFIED IDEOGRAPH + 0xB7EA: 0x7459, //CJK UNIFIED IDEOGRAPH + 0xB7EB: 0x745B, //CJK UNIFIED IDEOGRAPH + 0xB7EC: 0x745C, //CJK UNIFIED IDEOGRAPH + 0xB7ED: 0x7576, //CJK UNIFIED IDEOGRAPH + 0xB7EE: 0x7578, //CJK UNIFIED IDEOGRAPH + 0xB7EF: 0x7600, //CJK UNIFIED IDEOGRAPH + 0xB7F0: 0x75F0, //CJK UNIFIED IDEOGRAPH + 0xB7F1: 0x7601, //CJK UNIFIED IDEOGRAPH + 0xB7F2: 0x75F2, //CJK UNIFIED IDEOGRAPH + 0xB7F3: 0x75F1, //CJK UNIFIED IDEOGRAPH + 0xB7F4: 0x75FA, //CJK UNIFIED IDEOGRAPH + 0xB7F5: 0x75FF, //CJK UNIFIED IDEOGRAPH + 0xB7F6: 0x75F4, //CJK UNIFIED IDEOGRAPH + 0xB7F7: 0x75F3, //CJK UNIFIED IDEOGRAPH + 0xB7F8: 0x76DE, //CJK UNIFIED IDEOGRAPH + 0xB7F9: 0x76DF, //CJK UNIFIED IDEOGRAPH + 0xB7FA: 0x775B, //CJK UNIFIED IDEOGRAPH + 0xB7FB: 0x776B, //CJK UNIFIED IDEOGRAPH + 0xB7FC: 0x7766, //CJK UNIFIED IDEOGRAPH + 0xB7FD: 0x775E, //CJK UNIFIED IDEOGRAPH + 0xB7FE: 0x7763, //CJK UNIFIED IDEOGRAPH + 0xB840: 0x7779, //CJK UNIFIED IDEOGRAPH + 0xB841: 0x776A, //CJK UNIFIED IDEOGRAPH + 0xB842: 0x776C, //CJK UNIFIED IDEOGRAPH + 0xB843: 0x775C, //CJK UNIFIED IDEOGRAPH + 0xB844: 0x7765, //CJK UNIFIED IDEOGRAPH + 0xB845: 0x7768, //CJK UNIFIED IDEOGRAPH + 0xB846: 0x7762, //CJK UNIFIED IDEOGRAPH + 0xB847: 0x77EE, //CJK UNIFIED IDEOGRAPH + 0xB848: 0x788E, //CJK UNIFIED IDEOGRAPH + 0xB849: 0x78B0, //CJK UNIFIED IDEOGRAPH + 0xB84A: 0x7897, //CJK UNIFIED IDEOGRAPH + 0xB84B: 0x7898, //CJK UNIFIED IDEOGRAPH + 0xB84C: 0x788C, //CJK UNIFIED IDEOGRAPH + 0xB84D: 0x7889, //CJK UNIFIED IDEOGRAPH + 0xB84E: 0x787C, //CJK UNIFIED IDEOGRAPH + 0xB84F: 0x7891, //CJK UNIFIED IDEOGRAPH + 0xB850: 0x7893, //CJK UNIFIED IDEOGRAPH + 0xB851: 0x787F, //CJK UNIFIED IDEOGRAPH + 0xB852: 0x797A, //CJK UNIFIED IDEOGRAPH + 0xB853: 0x797F, //CJK UNIFIED IDEOGRAPH + 0xB854: 0x7981, //CJK UNIFIED IDEOGRAPH + 0xB855: 0x842C, //CJK UNIFIED IDEOGRAPH + 0xB856: 0x79BD, //CJK UNIFIED IDEOGRAPH + 0xB857: 0x7A1C, //CJK UNIFIED IDEOGRAPH + 0xB858: 0x7A1A, //CJK UNIFIED IDEOGRAPH + 0xB859: 0x7A20, //CJK UNIFIED IDEOGRAPH + 0xB85A: 0x7A14, //CJK UNIFIED IDEOGRAPH + 0xB85B: 0x7A1F, //CJK UNIFIED IDEOGRAPH + 0xB85C: 0x7A1E, //CJK UNIFIED IDEOGRAPH + 0xB85D: 0x7A9F, //CJK UNIFIED IDEOGRAPH + 0xB85E: 0x7AA0, //CJK UNIFIED IDEOGRAPH + 0xB85F: 0x7B77, //CJK UNIFIED IDEOGRAPH + 0xB860: 0x7BC0, //CJK UNIFIED IDEOGRAPH + 0xB861: 0x7B60, //CJK UNIFIED IDEOGRAPH + 0xB862: 0x7B6E, //CJK UNIFIED IDEOGRAPH + 0xB863: 0x7B67, //CJK UNIFIED IDEOGRAPH + 0xB864: 0x7CB1, //CJK UNIFIED IDEOGRAPH + 0xB865: 0x7CB3, //CJK UNIFIED IDEOGRAPH + 0xB866: 0x7CB5, //CJK UNIFIED IDEOGRAPH + 0xB867: 0x7D93, //CJK UNIFIED IDEOGRAPH + 0xB868: 0x7D79, //CJK UNIFIED IDEOGRAPH + 0xB869: 0x7D91, //CJK UNIFIED IDEOGRAPH + 0xB86A: 0x7D81, //CJK UNIFIED IDEOGRAPH + 0xB86B: 0x7D8F, //CJK UNIFIED IDEOGRAPH + 0xB86C: 0x7D5B, //CJK UNIFIED IDEOGRAPH + 0xB86D: 0x7F6E, //CJK UNIFIED IDEOGRAPH + 0xB86E: 0x7F69, //CJK UNIFIED IDEOGRAPH + 0xB86F: 0x7F6A, //CJK UNIFIED IDEOGRAPH + 0xB870: 0x7F72, //CJK UNIFIED IDEOGRAPH + 0xB871: 0x7FA9, //CJK UNIFIED IDEOGRAPH + 0xB872: 0x7FA8, //CJK UNIFIED IDEOGRAPH + 0xB873: 0x7FA4, //CJK UNIFIED IDEOGRAPH + 0xB874: 0x8056, //CJK UNIFIED IDEOGRAPH + 0xB875: 0x8058, //CJK UNIFIED IDEOGRAPH + 0xB876: 0x8086, //CJK UNIFIED IDEOGRAPH + 0xB877: 0x8084, //CJK UNIFIED IDEOGRAPH + 0xB878: 0x8171, //CJK UNIFIED IDEOGRAPH + 0xB879: 0x8170, //CJK UNIFIED IDEOGRAPH + 0xB87A: 0x8178, //CJK UNIFIED IDEOGRAPH + 0xB87B: 0x8165, //CJK UNIFIED IDEOGRAPH + 0xB87C: 0x816E, //CJK UNIFIED IDEOGRAPH + 0xB87D: 0x8173, //CJK UNIFIED IDEOGRAPH + 0xB87E: 0x816B, //CJK UNIFIED IDEOGRAPH + 0xB8A1: 0x8179, //CJK UNIFIED IDEOGRAPH + 0xB8A2: 0x817A, //CJK UNIFIED IDEOGRAPH + 0xB8A3: 0x8166, //CJK UNIFIED IDEOGRAPH + 0xB8A4: 0x8205, //CJK UNIFIED IDEOGRAPH + 0xB8A5: 0x8247, //CJK UNIFIED IDEOGRAPH + 0xB8A6: 0x8482, //CJK UNIFIED IDEOGRAPH + 0xB8A7: 0x8477, //CJK UNIFIED IDEOGRAPH + 0xB8A8: 0x843D, //CJK UNIFIED IDEOGRAPH + 0xB8A9: 0x8431, //CJK UNIFIED IDEOGRAPH + 0xB8AA: 0x8475, //CJK UNIFIED IDEOGRAPH + 0xB8AB: 0x8466, //CJK UNIFIED IDEOGRAPH + 0xB8AC: 0x846B, //CJK UNIFIED IDEOGRAPH + 0xB8AD: 0x8449, //CJK UNIFIED IDEOGRAPH + 0xB8AE: 0x846C, //CJK UNIFIED IDEOGRAPH + 0xB8AF: 0x845B, //CJK UNIFIED IDEOGRAPH + 0xB8B0: 0x843C, //CJK UNIFIED IDEOGRAPH + 0xB8B1: 0x8435, //CJK UNIFIED IDEOGRAPH + 0xB8B2: 0x8461, //CJK UNIFIED IDEOGRAPH + 0xB8B3: 0x8463, //CJK UNIFIED IDEOGRAPH + 0xB8B4: 0x8469, //CJK UNIFIED IDEOGRAPH + 0xB8B5: 0x846D, //CJK UNIFIED IDEOGRAPH + 0xB8B6: 0x8446, //CJK UNIFIED IDEOGRAPH + 0xB8B7: 0x865E, //CJK UNIFIED IDEOGRAPH + 0xB8B8: 0x865C, //CJK UNIFIED IDEOGRAPH + 0xB8B9: 0x865F, //CJK UNIFIED IDEOGRAPH + 0xB8BA: 0x86F9, //CJK UNIFIED IDEOGRAPH + 0xB8BB: 0x8713, //CJK UNIFIED IDEOGRAPH + 0xB8BC: 0x8708, //CJK UNIFIED IDEOGRAPH + 0xB8BD: 0x8707, //CJK UNIFIED IDEOGRAPH + 0xB8BE: 0x8700, //CJK UNIFIED IDEOGRAPH + 0xB8BF: 0x86FE, //CJK UNIFIED IDEOGRAPH + 0xB8C0: 0x86FB, //CJK UNIFIED IDEOGRAPH + 0xB8C1: 0x8702, //CJK UNIFIED IDEOGRAPH + 0xB8C2: 0x8703, //CJK UNIFIED IDEOGRAPH + 0xB8C3: 0x8706, //CJK UNIFIED IDEOGRAPH + 0xB8C4: 0x870A, //CJK UNIFIED IDEOGRAPH + 0xB8C5: 0x8859, //CJK UNIFIED IDEOGRAPH + 0xB8C6: 0x88DF, //CJK UNIFIED IDEOGRAPH + 0xB8C7: 0x88D4, //CJK UNIFIED IDEOGRAPH + 0xB8C8: 0x88D9, //CJK UNIFIED IDEOGRAPH + 0xB8C9: 0x88DC, //CJK UNIFIED IDEOGRAPH + 0xB8CA: 0x88D8, //CJK UNIFIED IDEOGRAPH + 0xB8CB: 0x88DD, //CJK UNIFIED IDEOGRAPH + 0xB8CC: 0x88E1, //CJK UNIFIED IDEOGRAPH + 0xB8CD: 0x88CA, //CJK UNIFIED IDEOGRAPH + 0xB8CE: 0x88D5, //CJK UNIFIED IDEOGRAPH + 0xB8CF: 0x88D2, //CJK UNIFIED IDEOGRAPH + 0xB8D0: 0x899C, //CJK UNIFIED IDEOGRAPH + 0xB8D1: 0x89E3, //CJK UNIFIED IDEOGRAPH + 0xB8D2: 0x8A6B, //CJK UNIFIED IDEOGRAPH + 0xB8D3: 0x8A72, //CJK UNIFIED IDEOGRAPH + 0xB8D4: 0x8A73, //CJK UNIFIED IDEOGRAPH + 0xB8D5: 0x8A66, //CJK UNIFIED IDEOGRAPH + 0xB8D6: 0x8A69, //CJK UNIFIED IDEOGRAPH + 0xB8D7: 0x8A70, //CJK UNIFIED IDEOGRAPH + 0xB8D8: 0x8A87, //CJK UNIFIED IDEOGRAPH + 0xB8D9: 0x8A7C, //CJK UNIFIED IDEOGRAPH + 0xB8DA: 0x8A63, //CJK UNIFIED IDEOGRAPH + 0xB8DB: 0x8AA0, //CJK UNIFIED IDEOGRAPH + 0xB8DC: 0x8A71, //CJK UNIFIED IDEOGRAPH + 0xB8DD: 0x8A85, //CJK UNIFIED IDEOGRAPH + 0xB8DE: 0x8A6D, //CJK UNIFIED IDEOGRAPH + 0xB8DF: 0x8A62, //CJK UNIFIED IDEOGRAPH + 0xB8E0: 0x8A6E, //CJK UNIFIED IDEOGRAPH + 0xB8E1: 0x8A6C, //CJK UNIFIED IDEOGRAPH + 0xB8E2: 0x8A79, //CJK UNIFIED IDEOGRAPH + 0xB8E3: 0x8A7B, //CJK UNIFIED IDEOGRAPH + 0xB8E4: 0x8A3E, //CJK UNIFIED IDEOGRAPH + 0xB8E5: 0x8A68, //CJK UNIFIED IDEOGRAPH + 0xB8E6: 0x8C62, //CJK UNIFIED IDEOGRAPH + 0xB8E7: 0x8C8A, //CJK UNIFIED IDEOGRAPH + 0xB8E8: 0x8C89, //CJK UNIFIED IDEOGRAPH + 0xB8E9: 0x8CCA, //CJK UNIFIED IDEOGRAPH + 0xB8EA: 0x8CC7, //CJK UNIFIED IDEOGRAPH + 0xB8EB: 0x8CC8, //CJK UNIFIED IDEOGRAPH + 0xB8EC: 0x8CC4, //CJK UNIFIED IDEOGRAPH + 0xB8ED: 0x8CB2, //CJK UNIFIED IDEOGRAPH + 0xB8EE: 0x8CC3, //CJK UNIFIED IDEOGRAPH + 0xB8EF: 0x8CC2, //CJK UNIFIED IDEOGRAPH + 0xB8F0: 0x8CC5, //CJK UNIFIED IDEOGRAPH + 0xB8F1: 0x8DE1, //CJK UNIFIED IDEOGRAPH + 0xB8F2: 0x8DDF, //CJK UNIFIED IDEOGRAPH + 0xB8F3: 0x8DE8, //CJK UNIFIED IDEOGRAPH + 0xB8F4: 0x8DEF, //CJK UNIFIED IDEOGRAPH + 0xB8F5: 0x8DF3, //CJK UNIFIED IDEOGRAPH + 0xB8F6: 0x8DFA, //CJK UNIFIED IDEOGRAPH + 0xB8F7: 0x8DEA, //CJK UNIFIED IDEOGRAPH + 0xB8F8: 0x8DE4, //CJK UNIFIED IDEOGRAPH + 0xB8F9: 0x8DE6, //CJK UNIFIED IDEOGRAPH + 0xB8FA: 0x8EB2, //CJK UNIFIED IDEOGRAPH + 0xB8FB: 0x8F03, //CJK UNIFIED IDEOGRAPH + 0xB8FC: 0x8F09, //CJK UNIFIED IDEOGRAPH + 0xB8FD: 0x8EFE, //CJK UNIFIED IDEOGRAPH + 0xB8FE: 0x8F0A, //CJK UNIFIED IDEOGRAPH + 0xB940: 0x8F9F, //CJK UNIFIED IDEOGRAPH + 0xB941: 0x8FB2, //CJK UNIFIED IDEOGRAPH + 0xB942: 0x904B, //CJK UNIFIED IDEOGRAPH + 0xB943: 0x904A, //CJK UNIFIED IDEOGRAPH + 0xB944: 0x9053, //CJK UNIFIED IDEOGRAPH + 0xB945: 0x9042, //CJK UNIFIED IDEOGRAPH + 0xB946: 0x9054, //CJK UNIFIED IDEOGRAPH + 0xB947: 0x903C, //CJK UNIFIED IDEOGRAPH + 0xB948: 0x9055, //CJK UNIFIED IDEOGRAPH + 0xB949: 0x9050, //CJK UNIFIED IDEOGRAPH + 0xB94A: 0x9047, //CJK UNIFIED IDEOGRAPH + 0xB94B: 0x904F, //CJK UNIFIED IDEOGRAPH + 0xB94C: 0x904E, //CJK UNIFIED IDEOGRAPH + 0xB94D: 0x904D, //CJK UNIFIED IDEOGRAPH + 0xB94E: 0x9051, //CJK UNIFIED IDEOGRAPH + 0xB94F: 0x903E, //CJK UNIFIED IDEOGRAPH + 0xB950: 0x9041, //CJK UNIFIED IDEOGRAPH + 0xB951: 0x9112, //CJK UNIFIED IDEOGRAPH + 0xB952: 0x9117, //CJK UNIFIED IDEOGRAPH + 0xB953: 0x916C, //CJK UNIFIED IDEOGRAPH + 0xB954: 0x916A, //CJK UNIFIED IDEOGRAPH + 0xB955: 0x9169, //CJK UNIFIED IDEOGRAPH + 0xB956: 0x91C9, //CJK UNIFIED IDEOGRAPH + 0xB957: 0x9237, //CJK UNIFIED IDEOGRAPH + 0xB958: 0x9257, //CJK UNIFIED IDEOGRAPH + 0xB959: 0x9238, //CJK UNIFIED IDEOGRAPH + 0xB95A: 0x923D, //CJK UNIFIED IDEOGRAPH + 0xB95B: 0x9240, //CJK UNIFIED IDEOGRAPH + 0xB95C: 0x923E, //CJK UNIFIED IDEOGRAPH + 0xB95D: 0x925B, //CJK UNIFIED IDEOGRAPH + 0xB95E: 0x924B, //CJK UNIFIED IDEOGRAPH + 0xB95F: 0x9264, //CJK UNIFIED IDEOGRAPH + 0xB960: 0x9251, //CJK UNIFIED IDEOGRAPH + 0xB961: 0x9234, //CJK UNIFIED IDEOGRAPH + 0xB962: 0x9249, //CJK UNIFIED IDEOGRAPH + 0xB963: 0x924D, //CJK UNIFIED IDEOGRAPH + 0xB964: 0x9245, //CJK UNIFIED IDEOGRAPH + 0xB965: 0x9239, //CJK UNIFIED IDEOGRAPH + 0xB966: 0x923F, //CJK UNIFIED IDEOGRAPH + 0xB967: 0x925A, //CJK UNIFIED IDEOGRAPH + 0xB968: 0x9598, //CJK UNIFIED IDEOGRAPH + 0xB969: 0x9698, //CJK UNIFIED IDEOGRAPH + 0xB96A: 0x9694, //CJK UNIFIED IDEOGRAPH + 0xB96B: 0x9695, //CJK UNIFIED IDEOGRAPH + 0xB96C: 0x96CD, //CJK UNIFIED IDEOGRAPH + 0xB96D: 0x96CB, //CJK UNIFIED IDEOGRAPH + 0xB96E: 0x96C9, //CJK UNIFIED IDEOGRAPH + 0xB96F: 0x96CA, //CJK UNIFIED IDEOGRAPH + 0xB970: 0x96F7, //CJK UNIFIED IDEOGRAPH + 0xB971: 0x96FB, //CJK UNIFIED IDEOGRAPH + 0xB972: 0x96F9, //CJK UNIFIED IDEOGRAPH + 0xB973: 0x96F6, //CJK UNIFIED IDEOGRAPH + 0xB974: 0x9756, //CJK UNIFIED IDEOGRAPH + 0xB975: 0x9774, //CJK UNIFIED IDEOGRAPH + 0xB976: 0x9776, //CJK UNIFIED IDEOGRAPH + 0xB977: 0x9810, //CJK UNIFIED IDEOGRAPH + 0xB978: 0x9811, //CJK UNIFIED IDEOGRAPH + 0xB979: 0x9813, //CJK UNIFIED IDEOGRAPH + 0xB97A: 0x980A, //CJK UNIFIED IDEOGRAPH + 0xB97B: 0x9812, //CJK UNIFIED IDEOGRAPH + 0xB97C: 0x980C, //CJK UNIFIED IDEOGRAPH + 0xB97D: 0x98FC, //CJK UNIFIED IDEOGRAPH + 0xB97E: 0x98F4, //CJK UNIFIED IDEOGRAPH + 0xB9A1: 0x98FD, //CJK UNIFIED IDEOGRAPH + 0xB9A2: 0x98FE, //CJK UNIFIED IDEOGRAPH + 0xB9A3: 0x99B3, //CJK UNIFIED IDEOGRAPH + 0xB9A4: 0x99B1, //CJK UNIFIED IDEOGRAPH + 0xB9A5: 0x99B4, //CJK UNIFIED IDEOGRAPH + 0xB9A6: 0x9AE1, //CJK UNIFIED IDEOGRAPH + 0xB9A7: 0x9CE9, //CJK UNIFIED IDEOGRAPH + 0xB9A8: 0x9E82, //CJK UNIFIED IDEOGRAPH + 0xB9A9: 0x9F0E, //CJK UNIFIED IDEOGRAPH + 0xB9AA: 0x9F13, //CJK UNIFIED IDEOGRAPH + 0xB9AB: 0x9F20, //CJK UNIFIED IDEOGRAPH + 0xB9AC: 0x50E7, //CJK UNIFIED IDEOGRAPH + 0xB9AD: 0x50EE, //CJK UNIFIED IDEOGRAPH + 0xB9AE: 0x50E5, //CJK UNIFIED IDEOGRAPH + 0xB9AF: 0x50D6, //CJK UNIFIED IDEOGRAPH + 0xB9B0: 0x50ED, //CJK UNIFIED IDEOGRAPH + 0xB9B1: 0x50DA, //CJK UNIFIED IDEOGRAPH + 0xB9B2: 0x50D5, //CJK UNIFIED IDEOGRAPH + 0xB9B3: 0x50CF, //CJK UNIFIED IDEOGRAPH + 0xB9B4: 0x50D1, //CJK UNIFIED IDEOGRAPH + 0xB9B5: 0x50F1, //CJK UNIFIED IDEOGRAPH + 0xB9B6: 0x50CE, //CJK UNIFIED IDEOGRAPH + 0xB9B7: 0x50E9, //CJK UNIFIED IDEOGRAPH + 0xB9B8: 0x5162, //CJK UNIFIED IDEOGRAPH + 0xB9B9: 0x51F3, //CJK UNIFIED IDEOGRAPH + 0xB9BA: 0x5283, //CJK UNIFIED IDEOGRAPH + 0xB9BB: 0x5282, //CJK UNIFIED IDEOGRAPH + 0xB9BC: 0x5331, //CJK UNIFIED IDEOGRAPH + 0xB9BD: 0x53AD, //CJK UNIFIED IDEOGRAPH + 0xB9BE: 0x55FE, //CJK UNIFIED IDEOGRAPH + 0xB9BF: 0x5600, //CJK UNIFIED IDEOGRAPH + 0xB9C0: 0x561B, //CJK UNIFIED IDEOGRAPH + 0xB9C1: 0x5617, //CJK UNIFIED IDEOGRAPH + 0xB9C2: 0x55FD, //CJK UNIFIED IDEOGRAPH + 0xB9C3: 0x5614, //CJK UNIFIED IDEOGRAPH + 0xB9C4: 0x5606, //CJK UNIFIED IDEOGRAPH + 0xB9C5: 0x5609, //CJK UNIFIED IDEOGRAPH + 0xB9C6: 0x560D, //CJK UNIFIED IDEOGRAPH + 0xB9C7: 0x560E, //CJK UNIFIED IDEOGRAPH + 0xB9C8: 0x55F7, //CJK UNIFIED IDEOGRAPH + 0xB9C9: 0x5616, //CJK UNIFIED IDEOGRAPH + 0xB9CA: 0x561F, //CJK UNIFIED IDEOGRAPH + 0xB9CB: 0x5608, //CJK UNIFIED IDEOGRAPH + 0xB9CC: 0x5610, //CJK UNIFIED IDEOGRAPH + 0xB9CD: 0x55F6, //CJK UNIFIED IDEOGRAPH + 0xB9CE: 0x5718, //CJK UNIFIED IDEOGRAPH + 0xB9CF: 0x5716, //CJK UNIFIED IDEOGRAPH + 0xB9D0: 0x5875, //CJK UNIFIED IDEOGRAPH + 0xB9D1: 0x587E, //CJK UNIFIED IDEOGRAPH + 0xB9D2: 0x5883, //CJK UNIFIED IDEOGRAPH + 0xB9D3: 0x5893, //CJK UNIFIED IDEOGRAPH + 0xB9D4: 0x588A, //CJK UNIFIED IDEOGRAPH + 0xB9D5: 0x5879, //CJK UNIFIED IDEOGRAPH + 0xB9D6: 0x5885, //CJK UNIFIED IDEOGRAPH + 0xB9D7: 0x587D, //CJK UNIFIED IDEOGRAPH + 0xB9D8: 0x58FD, //CJK UNIFIED IDEOGRAPH + 0xB9D9: 0x5925, //CJK UNIFIED IDEOGRAPH + 0xB9DA: 0x5922, //CJK UNIFIED IDEOGRAPH + 0xB9DB: 0x5924, //CJK UNIFIED IDEOGRAPH + 0xB9DC: 0x596A, //CJK UNIFIED IDEOGRAPH + 0xB9DD: 0x5969, //CJK UNIFIED IDEOGRAPH + 0xB9DE: 0x5AE1, //CJK UNIFIED IDEOGRAPH + 0xB9DF: 0x5AE6, //CJK UNIFIED IDEOGRAPH + 0xB9E0: 0x5AE9, //CJK UNIFIED IDEOGRAPH + 0xB9E1: 0x5AD7, //CJK UNIFIED IDEOGRAPH + 0xB9E2: 0x5AD6, //CJK UNIFIED IDEOGRAPH + 0xB9E3: 0x5AD8, //CJK UNIFIED IDEOGRAPH + 0xB9E4: 0x5AE3, //CJK UNIFIED IDEOGRAPH + 0xB9E5: 0x5B75, //CJK UNIFIED IDEOGRAPH + 0xB9E6: 0x5BDE, //CJK UNIFIED IDEOGRAPH + 0xB9E7: 0x5BE7, //CJK UNIFIED IDEOGRAPH + 0xB9E8: 0x5BE1, //CJK UNIFIED IDEOGRAPH + 0xB9E9: 0x5BE5, //CJK UNIFIED IDEOGRAPH + 0xB9EA: 0x5BE6, //CJK UNIFIED IDEOGRAPH + 0xB9EB: 0x5BE8, //CJK UNIFIED IDEOGRAPH + 0xB9EC: 0x5BE2, //CJK UNIFIED IDEOGRAPH + 0xB9ED: 0x5BE4, //CJK UNIFIED IDEOGRAPH + 0xB9EE: 0x5BDF, //CJK UNIFIED IDEOGRAPH + 0xB9EF: 0x5C0D, //CJK UNIFIED IDEOGRAPH + 0xB9F0: 0x5C62, //CJK UNIFIED IDEOGRAPH + 0xB9F1: 0x5D84, //CJK UNIFIED IDEOGRAPH + 0xB9F2: 0x5D87, //CJK UNIFIED IDEOGRAPH + 0xB9F3: 0x5E5B, //CJK UNIFIED IDEOGRAPH + 0xB9F4: 0x5E63, //CJK UNIFIED IDEOGRAPH + 0xB9F5: 0x5E55, //CJK UNIFIED IDEOGRAPH + 0xB9F6: 0x5E57, //CJK UNIFIED IDEOGRAPH + 0xB9F7: 0x5E54, //CJK UNIFIED IDEOGRAPH + 0xB9F8: 0x5ED3, //CJK UNIFIED IDEOGRAPH + 0xB9F9: 0x5ED6, //CJK UNIFIED IDEOGRAPH + 0xB9FA: 0x5F0A, //CJK UNIFIED IDEOGRAPH + 0xB9FB: 0x5F46, //CJK UNIFIED IDEOGRAPH + 0xB9FC: 0x5F70, //CJK UNIFIED IDEOGRAPH + 0xB9FD: 0x5FB9, //CJK UNIFIED IDEOGRAPH + 0xB9FE: 0x6147, //CJK UNIFIED IDEOGRAPH + 0xBA40: 0x613F, //CJK UNIFIED IDEOGRAPH + 0xBA41: 0x614B, //CJK UNIFIED IDEOGRAPH + 0xBA42: 0x6177, //CJK UNIFIED IDEOGRAPH + 0xBA43: 0x6162, //CJK UNIFIED IDEOGRAPH + 0xBA44: 0x6163, //CJK UNIFIED IDEOGRAPH + 0xBA45: 0x615F, //CJK UNIFIED IDEOGRAPH + 0xBA46: 0x615A, //CJK UNIFIED IDEOGRAPH + 0xBA47: 0x6158, //CJK UNIFIED IDEOGRAPH + 0xBA48: 0x6175, //CJK UNIFIED IDEOGRAPH + 0xBA49: 0x622A, //CJK UNIFIED IDEOGRAPH + 0xBA4A: 0x6487, //CJK UNIFIED IDEOGRAPH + 0xBA4B: 0x6458, //CJK UNIFIED IDEOGRAPH + 0xBA4C: 0x6454, //CJK UNIFIED IDEOGRAPH + 0xBA4D: 0x64A4, //CJK UNIFIED IDEOGRAPH + 0xBA4E: 0x6478, //CJK UNIFIED IDEOGRAPH + 0xBA4F: 0x645F, //CJK UNIFIED IDEOGRAPH + 0xBA50: 0x647A, //CJK UNIFIED IDEOGRAPH + 0xBA51: 0x6451, //CJK UNIFIED IDEOGRAPH + 0xBA52: 0x6467, //CJK UNIFIED IDEOGRAPH + 0xBA53: 0x6434, //CJK UNIFIED IDEOGRAPH + 0xBA54: 0x646D, //CJK UNIFIED IDEOGRAPH + 0xBA55: 0x647B, //CJK UNIFIED IDEOGRAPH + 0xBA56: 0x6572, //CJK UNIFIED IDEOGRAPH + 0xBA57: 0x65A1, //CJK UNIFIED IDEOGRAPH + 0xBA58: 0x65D7, //CJK UNIFIED IDEOGRAPH + 0xBA59: 0x65D6, //CJK UNIFIED IDEOGRAPH + 0xBA5A: 0x66A2, //CJK UNIFIED IDEOGRAPH + 0xBA5B: 0x66A8, //CJK UNIFIED IDEOGRAPH + 0xBA5C: 0x669D, //CJK UNIFIED IDEOGRAPH + 0xBA5D: 0x699C, //CJK UNIFIED IDEOGRAPH + 0xBA5E: 0x69A8, //CJK UNIFIED IDEOGRAPH + 0xBA5F: 0x6995, //CJK UNIFIED IDEOGRAPH + 0xBA60: 0x69C1, //CJK UNIFIED IDEOGRAPH + 0xBA61: 0x69AE, //CJK UNIFIED IDEOGRAPH + 0xBA62: 0x69D3, //CJK UNIFIED IDEOGRAPH + 0xBA63: 0x69CB, //CJK UNIFIED IDEOGRAPH + 0xBA64: 0x699B, //CJK UNIFIED IDEOGRAPH + 0xBA65: 0x69B7, //CJK UNIFIED IDEOGRAPH + 0xBA66: 0x69BB, //CJK UNIFIED IDEOGRAPH + 0xBA67: 0x69AB, //CJK UNIFIED IDEOGRAPH + 0xBA68: 0x69B4, //CJK UNIFIED IDEOGRAPH + 0xBA69: 0x69D0, //CJK UNIFIED IDEOGRAPH + 0xBA6A: 0x69CD, //CJK UNIFIED IDEOGRAPH + 0xBA6B: 0x69AD, //CJK UNIFIED IDEOGRAPH + 0xBA6C: 0x69CC, //CJK UNIFIED IDEOGRAPH + 0xBA6D: 0x69A6, //CJK UNIFIED IDEOGRAPH + 0xBA6E: 0x69C3, //CJK UNIFIED IDEOGRAPH + 0xBA6F: 0x69A3, //CJK UNIFIED IDEOGRAPH + 0xBA70: 0x6B49, //CJK UNIFIED IDEOGRAPH + 0xBA71: 0x6B4C, //CJK UNIFIED IDEOGRAPH + 0xBA72: 0x6C33, //CJK UNIFIED IDEOGRAPH + 0xBA73: 0x6F33, //CJK UNIFIED IDEOGRAPH + 0xBA74: 0x6F14, //CJK UNIFIED IDEOGRAPH + 0xBA75: 0x6EFE, //CJK UNIFIED IDEOGRAPH + 0xBA76: 0x6F13, //CJK UNIFIED IDEOGRAPH + 0xBA77: 0x6EF4, //CJK UNIFIED IDEOGRAPH + 0xBA78: 0x6F29, //CJK UNIFIED IDEOGRAPH + 0xBA79: 0x6F3E, //CJK UNIFIED IDEOGRAPH + 0xBA7A: 0x6F20, //CJK UNIFIED IDEOGRAPH + 0xBA7B: 0x6F2C, //CJK UNIFIED IDEOGRAPH + 0xBA7C: 0x6F0F, //CJK UNIFIED IDEOGRAPH + 0xBA7D: 0x6F02, //CJK UNIFIED IDEOGRAPH + 0xBA7E: 0x6F22, //CJK UNIFIED IDEOGRAPH + 0xBAA1: 0x6EFF, //CJK UNIFIED IDEOGRAPH + 0xBAA2: 0x6EEF, //CJK UNIFIED IDEOGRAPH + 0xBAA3: 0x6F06, //CJK UNIFIED IDEOGRAPH + 0xBAA4: 0x6F31, //CJK UNIFIED IDEOGRAPH + 0xBAA5: 0x6F38, //CJK UNIFIED IDEOGRAPH + 0xBAA6: 0x6F32, //CJK UNIFIED IDEOGRAPH + 0xBAA7: 0x6F23, //CJK UNIFIED IDEOGRAPH + 0xBAA8: 0x6F15, //CJK UNIFIED IDEOGRAPH + 0xBAA9: 0x6F2B, //CJK UNIFIED IDEOGRAPH + 0xBAAA: 0x6F2F, //CJK UNIFIED IDEOGRAPH + 0xBAAB: 0x6F88, //CJK UNIFIED IDEOGRAPH + 0xBAAC: 0x6F2A, //CJK UNIFIED IDEOGRAPH + 0xBAAD: 0x6EEC, //CJK UNIFIED IDEOGRAPH + 0xBAAE: 0x6F01, //CJK UNIFIED IDEOGRAPH + 0xBAAF: 0x6EF2, //CJK UNIFIED IDEOGRAPH + 0xBAB0: 0x6ECC, //CJK UNIFIED IDEOGRAPH + 0xBAB1: 0x6EF7, //CJK UNIFIED IDEOGRAPH + 0xBAB2: 0x7194, //CJK UNIFIED IDEOGRAPH + 0xBAB3: 0x7199, //CJK UNIFIED IDEOGRAPH + 0xBAB4: 0x717D, //CJK UNIFIED IDEOGRAPH + 0xBAB5: 0x718A, //CJK UNIFIED IDEOGRAPH + 0xBAB6: 0x7184, //CJK UNIFIED IDEOGRAPH + 0xBAB7: 0x7192, //CJK UNIFIED IDEOGRAPH + 0xBAB8: 0x723E, //CJK UNIFIED IDEOGRAPH + 0xBAB9: 0x7292, //CJK UNIFIED IDEOGRAPH + 0xBABA: 0x7296, //CJK UNIFIED IDEOGRAPH + 0xBABB: 0x7344, //CJK UNIFIED IDEOGRAPH + 0xBABC: 0x7350, //CJK UNIFIED IDEOGRAPH + 0xBABD: 0x7464, //CJK UNIFIED IDEOGRAPH + 0xBABE: 0x7463, //CJK UNIFIED IDEOGRAPH + 0xBABF: 0x746A, //CJK UNIFIED IDEOGRAPH + 0xBAC0: 0x7470, //CJK UNIFIED IDEOGRAPH + 0xBAC1: 0x746D, //CJK UNIFIED IDEOGRAPH + 0xBAC2: 0x7504, //CJK UNIFIED IDEOGRAPH + 0xBAC3: 0x7591, //CJK UNIFIED IDEOGRAPH + 0xBAC4: 0x7627, //CJK UNIFIED IDEOGRAPH + 0xBAC5: 0x760D, //CJK UNIFIED IDEOGRAPH + 0xBAC6: 0x760B, //CJK UNIFIED IDEOGRAPH + 0xBAC7: 0x7609, //CJK UNIFIED IDEOGRAPH + 0xBAC8: 0x7613, //CJK UNIFIED IDEOGRAPH + 0xBAC9: 0x76E1, //CJK UNIFIED IDEOGRAPH + 0xBACA: 0x76E3, //CJK UNIFIED IDEOGRAPH + 0xBACB: 0x7784, //CJK UNIFIED IDEOGRAPH + 0xBACC: 0x777D, //CJK UNIFIED IDEOGRAPH + 0xBACD: 0x777F, //CJK UNIFIED IDEOGRAPH + 0xBACE: 0x7761, //CJK UNIFIED IDEOGRAPH + 0xBACF: 0x78C1, //CJK UNIFIED IDEOGRAPH + 0xBAD0: 0x789F, //CJK UNIFIED IDEOGRAPH + 0xBAD1: 0x78A7, //CJK UNIFIED IDEOGRAPH + 0xBAD2: 0x78B3, //CJK UNIFIED IDEOGRAPH + 0xBAD3: 0x78A9, //CJK UNIFIED IDEOGRAPH + 0xBAD4: 0x78A3, //CJK UNIFIED IDEOGRAPH + 0xBAD5: 0x798E, //CJK UNIFIED IDEOGRAPH + 0xBAD6: 0x798F, //CJK UNIFIED IDEOGRAPH + 0xBAD7: 0x798D, //CJK UNIFIED IDEOGRAPH + 0xBAD8: 0x7A2E, //CJK UNIFIED IDEOGRAPH + 0xBAD9: 0x7A31, //CJK UNIFIED IDEOGRAPH + 0xBADA: 0x7AAA, //CJK UNIFIED IDEOGRAPH + 0xBADB: 0x7AA9, //CJK UNIFIED IDEOGRAPH + 0xBADC: 0x7AED, //CJK UNIFIED IDEOGRAPH + 0xBADD: 0x7AEF, //CJK UNIFIED IDEOGRAPH + 0xBADE: 0x7BA1, //CJK UNIFIED IDEOGRAPH + 0xBADF: 0x7B95, //CJK UNIFIED IDEOGRAPH + 0xBAE0: 0x7B8B, //CJK UNIFIED IDEOGRAPH + 0xBAE1: 0x7B75, //CJK UNIFIED IDEOGRAPH + 0xBAE2: 0x7B97, //CJK UNIFIED IDEOGRAPH + 0xBAE3: 0x7B9D, //CJK UNIFIED IDEOGRAPH + 0xBAE4: 0x7B94, //CJK UNIFIED IDEOGRAPH + 0xBAE5: 0x7B8F, //CJK UNIFIED IDEOGRAPH + 0xBAE6: 0x7BB8, //CJK UNIFIED IDEOGRAPH + 0xBAE7: 0x7B87, //CJK UNIFIED IDEOGRAPH + 0xBAE8: 0x7B84, //CJK UNIFIED IDEOGRAPH + 0xBAE9: 0x7CB9, //CJK UNIFIED IDEOGRAPH + 0xBAEA: 0x7CBD, //CJK UNIFIED IDEOGRAPH + 0xBAEB: 0x7CBE, //CJK UNIFIED IDEOGRAPH + 0xBAEC: 0x7DBB, //CJK UNIFIED IDEOGRAPH + 0xBAED: 0x7DB0, //CJK UNIFIED IDEOGRAPH + 0xBAEE: 0x7D9C, //CJK UNIFIED IDEOGRAPH + 0xBAEF: 0x7DBD, //CJK UNIFIED IDEOGRAPH + 0xBAF0: 0x7DBE, //CJK UNIFIED IDEOGRAPH + 0xBAF1: 0x7DA0, //CJK UNIFIED IDEOGRAPH + 0xBAF2: 0x7DCA, //CJK UNIFIED IDEOGRAPH + 0xBAF3: 0x7DB4, //CJK UNIFIED IDEOGRAPH + 0xBAF4: 0x7DB2, //CJK UNIFIED IDEOGRAPH + 0xBAF5: 0x7DB1, //CJK UNIFIED IDEOGRAPH + 0xBAF6: 0x7DBA, //CJK UNIFIED IDEOGRAPH + 0xBAF7: 0x7DA2, //CJK UNIFIED IDEOGRAPH + 0xBAF8: 0x7DBF, //CJK UNIFIED IDEOGRAPH + 0xBAF9: 0x7DB5, //CJK UNIFIED IDEOGRAPH + 0xBAFA: 0x7DB8, //CJK UNIFIED IDEOGRAPH + 0xBAFB: 0x7DAD, //CJK UNIFIED IDEOGRAPH + 0xBAFC: 0x7DD2, //CJK UNIFIED IDEOGRAPH + 0xBAFD: 0x7DC7, //CJK UNIFIED IDEOGRAPH + 0xBAFE: 0x7DAC, //CJK UNIFIED IDEOGRAPH + 0xBB40: 0x7F70, //CJK UNIFIED IDEOGRAPH + 0xBB41: 0x7FE0, //CJK UNIFIED IDEOGRAPH + 0xBB42: 0x7FE1, //CJK UNIFIED IDEOGRAPH + 0xBB43: 0x7FDF, //CJK UNIFIED IDEOGRAPH + 0xBB44: 0x805E, //CJK UNIFIED IDEOGRAPH + 0xBB45: 0x805A, //CJK UNIFIED IDEOGRAPH + 0xBB46: 0x8087, //CJK UNIFIED IDEOGRAPH + 0xBB47: 0x8150, //CJK UNIFIED IDEOGRAPH + 0xBB48: 0x8180, //CJK UNIFIED IDEOGRAPH + 0xBB49: 0x818F, //CJK UNIFIED IDEOGRAPH + 0xBB4A: 0x8188, //CJK UNIFIED IDEOGRAPH + 0xBB4B: 0x818A, //CJK UNIFIED IDEOGRAPH + 0xBB4C: 0x817F, //CJK UNIFIED IDEOGRAPH + 0xBB4D: 0x8182, //CJK UNIFIED IDEOGRAPH + 0xBB4E: 0x81E7, //CJK UNIFIED IDEOGRAPH + 0xBB4F: 0x81FA, //CJK UNIFIED IDEOGRAPH + 0xBB50: 0x8207, //CJK UNIFIED IDEOGRAPH + 0xBB51: 0x8214, //CJK UNIFIED IDEOGRAPH + 0xBB52: 0x821E, //CJK UNIFIED IDEOGRAPH + 0xBB53: 0x824B, //CJK UNIFIED IDEOGRAPH + 0xBB54: 0x84C9, //CJK UNIFIED IDEOGRAPH + 0xBB55: 0x84BF, //CJK UNIFIED IDEOGRAPH + 0xBB56: 0x84C6, //CJK UNIFIED IDEOGRAPH + 0xBB57: 0x84C4, //CJK UNIFIED IDEOGRAPH + 0xBB58: 0x8499, //CJK UNIFIED IDEOGRAPH + 0xBB59: 0x849E, //CJK UNIFIED IDEOGRAPH + 0xBB5A: 0x84B2, //CJK UNIFIED IDEOGRAPH + 0xBB5B: 0x849C, //CJK UNIFIED IDEOGRAPH + 0xBB5C: 0x84CB, //CJK UNIFIED IDEOGRAPH + 0xBB5D: 0x84B8, //CJK UNIFIED IDEOGRAPH + 0xBB5E: 0x84C0, //CJK UNIFIED IDEOGRAPH + 0xBB5F: 0x84D3, //CJK UNIFIED IDEOGRAPH + 0xBB60: 0x8490, //CJK UNIFIED IDEOGRAPH + 0xBB61: 0x84BC, //CJK UNIFIED IDEOGRAPH + 0xBB62: 0x84D1, //CJK UNIFIED IDEOGRAPH + 0xBB63: 0x84CA, //CJK UNIFIED IDEOGRAPH + 0xBB64: 0x873F, //CJK UNIFIED IDEOGRAPH + 0xBB65: 0x871C, //CJK UNIFIED IDEOGRAPH + 0xBB66: 0x873B, //CJK UNIFIED IDEOGRAPH + 0xBB67: 0x8722, //CJK UNIFIED IDEOGRAPH + 0xBB68: 0x8725, //CJK UNIFIED IDEOGRAPH + 0xBB69: 0x8734, //CJK UNIFIED IDEOGRAPH + 0xBB6A: 0x8718, //CJK UNIFIED IDEOGRAPH + 0xBB6B: 0x8755, //CJK UNIFIED IDEOGRAPH + 0xBB6C: 0x8737, //CJK UNIFIED IDEOGRAPH + 0xBB6D: 0x8729, //CJK UNIFIED IDEOGRAPH + 0xBB6E: 0x88F3, //CJK UNIFIED IDEOGRAPH + 0xBB6F: 0x8902, //CJK UNIFIED IDEOGRAPH + 0xBB70: 0x88F4, //CJK UNIFIED IDEOGRAPH + 0xBB71: 0x88F9, //CJK UNIFIED IDEOGRAPH + 0xBB72: 0x88F8, //CJK UNIFIED IDEOGRAPH + 0xBB73: 0x88FD, //CJK UNIFIED IDEOGRAPH + 0xBB74: 0x88E8, //CJK UNIFIED IDEOGRAPH + 0xBB75: 0x891A, //CJK UNIFIED IDEOGRAPH + 0xBB76: 0x88EF, //CJK UNIFIED IDEOGRAPH + 0xBB77: 0x8AA6, //CJK UNIFIED IDEOGRAPH + 0xBB78: 0x8A8C, //CJK UNIFIED IDEOGRAPH + 0xBB79: 0x8A9E, //CJK UNIFIED IDEOGRAPH + 0xBB7A: 0x8AA3, //CJK UNIFIED IDEOGRAPH + 0xBB7B: 0x8A8D, //CJK UNIFIED IDEOGRAPH + 0xBB7C: 0x8AA1, //CJK UNIFIED IDEOGRAPH + 0xBB7D: 0x8A93, //CJK UNIFIED IDEOGRAPH + 0xBB7E: 0x8AA4, //CJK UNIFIED IDEOGRAPH + 0xBBA1: 0x8AAA, //CJK UNIFIED IDEOGRAPH + 0xBBA2: 0x8AA5, //CJK UNIFIED IDEOGRAPH + 0xBBA3: 0x8AA8, //CJK UNIFIED IDEOGRAPH + 0xBBA4: 0x8A98, //CJK UNIFIED IDEOGRAPH + 0xBBA5: 0x8A91, //CJK UNIFIED IDEOGRAPH + 0xBBA6: 0x8A9A, //CJK UNIFIED IDEOGRAPH + 0xBBA7: 0x8AA7, //CJK UNIFIED IDEOGRAPH + 0xBBA8: 0x8C6A, //CJK UNIFIED IDEOGRAPH + 0xBBA9: 0x8C8D, //CJK UNIFIED IDEOGRAPH + 0xBBAA: 0x8C8C, //CJK UNIFIED IDEOGRAPH + 0xBBAB: 0x8CD3, //CJK UNIFIED IDEOGRAPH + 0xBBAC: 0x8CD1, //CJK UNIFIED IDEOGRAPH + 0xBBAD: 0x8CD2, //CJK UNIFIED IDEOGRAPH + 0xBBAE: 0x8D6B, //CJK UNIFIED IDEOGRAPH + 0xBBAF: 0x8D99, //CJK UNIFIED IDEOGRAPH + 0xBBB0: 0x8D95, //CJK UNIFIED IDEOGRAPH + 0xBBB1: 0x8DFC, //CJK UNIFIED IDEOGRAPH + 0xBBB2: 0x8F14, //CJK UNIFIED IDEOGRAPH + 0xBBB3: 0x8F12, //CJK UNIFIED IDEOGRAPH + 0xBBB4: 0x8F15, //CJK UNIFIED IDEOGRAPH + 0xBBB5: 0x8F13, //CJK UNIFIED IDEOGRAPH + 0xBBB6: 0x8FA3, //CJK UNIFIED IDEOGRAPH + 0xBBB7: 0x9060, //CJK UNIFIED IDEOGRAPH + 0xBBB8: 0x9058, //CJK UNIFIED IDEOGRAPH + 0xBBB9: 0x905C, //CJK UNIFIED IDEOGRAPH + 0xBBBA: 0x9063, //CJK UNIFIED IDEOGRAPH + 0xBBBB: 0x9059, //CJK UNIFIED IDEOGRAPH + 0xBBBC: 0x905E, //CJK UNIFIED IDEOGRAPH + 0xBBBD: 0x9062, //CJK UNIFIED IDEOGRAPH + 0xBBBE: 0x905D, //CJK UNIFIED IDEOGRAPH + 0xBBBF: 0x905B, //CJK UNIFIED IDEOGRAPH + 0xBBC0: 0x9119, //CJK UNIFIED IDEOGRAPH + 0xBBC1: 0x9118, //CJK UNIFIED IDEOGRAPH + 0xBBC2: 0x911E, //CJK UNIFIED IDEOGRAPH + 0xBBC3: 0x9175, //CJK UNIFIED IDEOGRAPH + 0xBBC4: 0x9178, //CJK UNIFIED IDEOGRAPH + 0xBBC5: 0x9177, //CJK UNIFIED IDEOGRAPH + 0xBBC6: 0x9174, //CJK UNIFIED IDEOGRAPH + 0xBBC7: 0x9278, //CJK UNIFIED IDEOGRAPH + 0xBBC8: 0x9280, //CJK UNIFIED IDEOGRAPH + 0xBBC9: 0x9285, //CJK UNIFIED IDEOGRAPH + 0xBBCA: 0x9298, //CJK UNIFIED IDEOGRAPH + 0xBBCB: 0x9296, //CJK UNIFIED IDEOGRAPH + 0xBBCC: 0x927B, //CJK UNIFIED IDEOGRAPH + 0xBBCD: 0x9293, //CJK UNIFIED IDEOGRAPH + 0xBBCE: 0x929C, //CJK UNIFIED IDEOGRAPH + 0xBBCF: 0x92A8, //CJK UNIFIED IDEOGRAPH + 0xBBD0: 0x927C, //CJK UNIFIED IDEOGRAPH + 0xBBD1: 0x9291, //CJK UNIFIED IDEOGRAPH + 0xBBD2: 0x95A1, //CJK UNIFIED IDEOGRAPH + 0xBBD3: 0x95A8, //CJK UNIFIED IDEOGRAPH + 0xBBD4: 0x95A9, //CJK UNIFIED IDEOGRAPH + 0xBBD5: 0x95A3, //CJK UNIFIED IDEOGRAPH + 0xBBD6: 0x95A5, //CJK UNIFIED IDEOGRAPH + 0xBBD7: 0x95A4, //CJK UNIFIED IDEOGRAPH + 0xBBD8: 0x9699, //CJK UNIFIED IDEOGRAPH + 0xBBD9: 0x969C, //CJK UNIFIED IDEOGRAPH + 0xBBDA: 0x969B, //CJK UNIFIED IDEOGRAPH + 0xBBDB: 0x96CC, //CJK UNIFIED IDEOGRAPH + 0xBBDC: 0x96D2, //CJK UNIFIED IDEOGRAPH + 0xBBDD: 0x9700, //CJK UNIFIED IDEOGRAPH + 0xBBDE: 0x977C, //CJK UNIFIED IDEOGRAPH + 0xBBDF: 0x9785, //CJK UNIFIED IDEOGRAPH + 0xBBE0: 0x97F6, //CJK UNIFIED IDEOGRAPH + 0xBBE1: 0x9817, //CJK UNIFIED IDEOGRAPH + 0xBBE2: 0x9818, //CJK UNIFIED IDEOGRAPH + 0xBBE3: 0x98AF, //CJK UNIFIED IDEOGRAPH + 0xBBE4: 0x98B1, //CJK UNIFIED IDEOGRAPH + 0xBBE5: 0x9903, //CJK UNIFIED IDEOGRAPH + 0xBBE6: 0x9905, //CJK UNIFIED IDEOGRAPH + 0xBBE7: 0x990C, //CJK UNIFIED IDEOGRAPH + 0xBBE8: 0x9909, //CJK UNIFIED IDEOGRAPH + 0xBBE9: 0x99C1, //CJK UNIFIED IDEOGRAPH + 0xBBEA: 0x9AAF, //CJK UNIFIED IDEOGRAPH + 0xBBEB: 0x9AB0, //CJK UNIFIED IDEOGRAPH + 0xBBEC: 0x9AE6, //CJK UNIFIED IDEOGRAPH + 0xBBED: 0x9B41, //CJK UNIFIED IDEOGRAPH + 0xBBEE: 0x9B42, //CJK UNIFIED IDEOGRAPH + 0xBBEF: 0x9CF4, //CJK UNIFIED IDEOGRAPH + 0xBBF0: 0x9CF6, //CJK UNIFIED IDEOGRAPH + 0xBBF1: 0x9CF3, //CJK UNIFIED IDEOGRAPH + 0xBBF2: 0x9EBC, //CJK UNIFIED IDEOGRAPH + 0xBBF3: 0x9F3B, //CJK UNIFIED IDEOGRAPH + 0xBBF4: 0x9F4A, //CJK UNIFIED IDEOGRAPH + 0xBBF5: 0x5104, //CJK UNIFIED IDEOGRAPH + 0xBBF6: 0x5100, //CJK UNIFIED IDEOGRAPH + 0xBBF7: 0x50FB, //CJK UNIFIED IDEOGRAPH + 0xBBF8: 0x50F5, //CJK UNIFIED IDEOGRAPH + 0xBBF9: 0x50F9, //CJK UNIFIED IDEOGRAPH + 0xBBFA: 0x5102, //CJK UNIFIED IDEOGRAPH + 0xBBFB: 0x5108, //CJK UNIFIED IDEOGRAPH + 0xBBFC: 0x5109, //CJK UNIFIED IDEOGRAPH + 0xBBFD: 0x5105, //CJK UNIFIED IDEOGRAPH + 0xBBFE: 0x51DC, //CJK UNIFIED IDEOGRAPH + 0xBC40: 0x5287, //CJK UNIFIED IDEOGRAPH + 0xBC41: 0x5288, //CJK UNIFIED IDEOGRAPH + 0xBC42: 0x5289, //CJK UNIFIED IDEOGRAPH + 0xBC43: 0x528D, //CJK UNIFIED IDEOGRAPH + 0xBC44: 0x528A, //CJK UNIFIED IDEOGRAPH + 0xBC45: 0x52F0, //CJK UNIFIED IDEOGRAPH + 0xBC46: 0x53B2, //CJK UNIFIED IDEOGRAPH + 0xBC47: 0x562E, //CJK UNIFIED IDEOGRAPH + 0xBC48: 0x563B, //CJK UNIFIED IDEOGRAPH + 0xBC49: 0x5639, //CJK UNIFIED IDEOGRAPH + 0xBC4A: 0x5632, //CJK UNIFIED IDEOGRAPH + 0xBC4B: 0x563F, //CJK UNIFIED IDEOGRAPH + 0xBC4C: 0x5634, //CJK UNIFIED IDEOGRAPH + 0xBC4D: 0x5629, //CJK UNIFIED IDEOGRAPH + 0xBC4E: 0x5653, //CJK UNIFIED IDEOGRAPH + 0xBC4F: 0x564E, //CJK UNIFIED IDEOGRAPH + 0xBC50: 0x5657, //CJK UNIFIED IDEOGRAPH + 0xBC51: 0x5674, //CJK UNIFIED IDEOGRAPH + 0xBC52: 0x5636, //CJK UNIFIED IDEOGRAPH + 0xBC53: 0x562F, //CJK UNIFIED IDEOGRAPH + 0xBC54: 0x5630, //CJK UNIFIED IDEOGRAPH + 0xBC55: 0x5880, //CJK UNIFIED IDEOGRAPH + 0xBC56: 0x589F, //CJK UNIFIED IDEOGRAPH + 0xBC57: 0x589E, //CJK UNIFIED IDEOGRAPH + 0xBC58: 0x58B3, //CJK UNIFIED IDEOGRAPH + 0xBC59: 0x589C, //CJK UNIFIED IDEOGRAPH + 0xBC5A: 0x58AE, //CJK UNIFIED IDEOGRAPH + 0xBC5B: 0x58A9, //CJK UNIFIED IDEOGRAPH + 0xBC5C: 0x58A6, //CJK UNIFIED IDEOGRAPH + 0xBC5D: 0x596D, //CJK UNIFIED IDEOGRAPH + 0xBC5E: 0x5B09, //CJK UNIFIED IDEOGRAPH + 0xBC5F: 0x5AFB, //CJK UNIFIED IDEOGRAPH + 0xBC60: 0x5B0B, //CJK UNIFIED IDEOGRAPH + 0xBC61: 0x5AF5, //CJK UNIFIED IDEOGRAPH + 0xBC62: 0x5B0C, //CJK UNIFIED IDEOGRAPH + 0xBC63: 0x5B08, //CJK UNIFIED IDEOGRAPH + 0xBC64: 0x5BEE, //CJK UNIFIED IDEOGRAPH + 0xBC65: 0x5BEC, //CJK UNIFIED IDEOGRAPH + 0xBC66: 0x5BE9, //CJK UNIFIED IDEOGRAPH + 0xBC67: 0x5BEB, //CJK UNIFIED IDEOGRAPH + 0xBC68: 0x5C64, //CJK UNIFIED IDEOGRAPH + 0xBC69: 0x5C65, //CJK UNIFIED IDEOGRAPH + 0xBC6A: 0x5D9D, //CJK UNIFIED IDEOGRAPH + 0xBC6B: 0x5D94, //CJK UNIFIED IDEOGRAPH + 0xBC6C: 0x5E62, //CJK UNIFIED IDEOGRAPH + 0xBC6D: 0x5E5F, //CJK UNIFIED IDEOGRAPH + 0xBC6E: 0x5E61, //CJK UNIFIED IDEOGRAPH + 0xBC6F: 0x5EE2, //CJK UNIFIED IDEOGRAPH + 0xBC70: 0x5EDA, //CJK UNIFIED IDEOGRAPH + 0xBC71: 0x5EDF, //CJK UNIFIED IDEOGRAPH + 0xBC72: 0x5EDD, //CJK UNIFIED IDEOGRAPH + 0xBC73: 0x5EE3, //CJK UNIFIED IDEOGRAPH + 0xBC74: 0x5EE0, //CJK UNIFIED IDEOGRAPH + 0xBC75: 0x5F48, //CJK UNIFIED IDEOGRAPH + 0xBC76: 0x5F71, //CJK UNIFIED IDEOGRAPH + 0xBC77: 0x5FB7, //CJK UNIFIED IDEOGRAPH + 0xBC78: 0x5FB5, //CJK UNIFIED IDEOGRAPH + 0xBC79: 0x6176, //CJK UNIFIED IDEOGRAPH + 0xBC7A: 0x6167, //CJK UNIFIED IDEOGRAPH + 0xBC7B: 0x616E, //CJK UNIFIED IDEOGRAPH + 0xBC7C: 0x615D, //CJK UNIFIED IDEOGRAPH + 0xBC7D: 0x6155, //CJK UNIFIED IDEOGRAPH + 0xBC7E: 0x6182, //CJK UNIFIED IDEOGRAPH + 0xBCA1: 0x617C, //CJK UNIFIED IDEOGRAPH + 0xBCA2: 0x6170, //CJK UNIFIED IDEOGRAPH + 0xBCA3: 0x616B, //CJK UNIFIED IDEOGRAPH + 0xBCA4: 0x617E, //CJK UNIFIED IDEOGRAPH + 0xBCA5: 0x61A7, //CJK UNIFIED IDEOGRAPH + 0xBCA6: 0x6190, //CJK UNIFIED IDEOGRAPH + 0xBCA7: 0x61AB, //CJK UNIFIED IDEOGRAPH + 0xBCA8: 0x618E, //CJK UNIFIED IDEOGRAPH + 0xBCA9: 0x61AC, //CJK UNIFIED IDEOGRAPH + 0xBCAA: 0x619A, //CJK UNIFIED IDEOGRAPH + 0xBCAB: 0x61A4, //CJK UNIFIED IDEOGRAPH + 0xBCAC: 0x6194, //CJK UNIFIED IDEOGRAPH + 0xBCAD: 0x61AE, //CJK UNIFIED IDEOGRAPH + 0xBCAE: 0x622E, //CJK UNIFIED IDEOGRAPH + 0xBCAF: 0x6469, //CJK UNIFIED IDEOGRAPH + 0xBCB0: 0x646F, //CJK UNIFIED IDEOGRAPH + 0xBCB1: 0x6479, //CJK UNIFIED IDEOGRAPH + 0xBCB2: 0x649E, //CJK UNIFIED IDEOGRAPH + 0xBCB3: 0x64B2, //CJK UNIFIED IDEOGRAPH + 0xBCB4: 0x6488, //CJK UNIFIED IDEOGRAPH + 0xBCB5: 0x6490, //CJK UNIFIED IDEOGRAPH + 0xBCB6: 0x64B0, //CJK UNIFIED IDEOGRAPH + 0xBCB7: 0x64A5, //CJK UNIFIED IDEOGRAPH + 0xBCB8: 0x6493, //CJK UNIFIED IDEOGRAPH + 0xBCB9: 0x6495, //CJK UNIFIED IDEOGRAPH + 0xBCBA: 0x64A9, //CJK UNIFIED IDEOGRAPH + 0xBCBB: 0x6492, //CJK UNIFIED IDEOGRAPH + 0xBCBC: 0x64AE, //CJK UNIFIED IDEOGRAPH + 0xBCBD: 0x64AD, //CJK UNIFIED IDEOGRAPH + 0xBCBE: 0x64AB, //CJK UNIFIED IDEOGRAPH + 0xBCBF: 0x649A, //CJK UNIFIED IDEOGRAPH + 0xBCC0: 0x64AC, //CJK UNIFIED IDEOGRAPH + 0xBCC1: 0x6499, //CJK UNIFIED IDEOGRAPH + 0xBCC2: 0x64A2, //CJK UNIFIED IDEOGRAPH + 0xBCC3: 0x64B3, //CJK UNIFIED IDEOGRAPH + 0xBCC4: 0x6575, //CJK UNIFIED IDEOGRAPH + 0xBCC5: 0x6577, //CJK UNIFIED IDEOGRAPH + 0xBCC6: 0x6578, //CJK UNIFIED IDEOGRAPH + 0xBCC7: 0x66AE, //CJK UNIFIED IDEOGRAPH + 0xBCC8: 0x66AB, //CJK UNIFIED IDEOGRAPH + 0xBCC9: 0x66B4, //CJK UNIFIED IDEOGRAPH + 0xBCCA: 0x66B1, //CJK UNIFIED IDEOGRAPH + 0xBCCB: 0x6A23, //CJK UNIFIED IDEOGRAPH + 0xBCCC: 0x6A1F, //CJK UNIFIED IDEOGRAPH + 0xBCCD: 0x69E8, //CJK UNIFIED IDEOGRAPH + 0xBCCE: 0x6A01, //CJK UNIFIED IDEOGRAPH + 0xBCCF: 0x6A1E, //CJK UNIFIED IDEOGRAPH + 0xBCD0: 0x6A19, //CJK UNIFIED IDEOGRAPH + 0xBCD1: 0x69FD, //CJK UNIFIED IDEOGRAPH + 0xBCD2: 0x6A21, //CJK UNIFIED IDEOGRAPH + 0xBCD3: 0x6A13, //CJK UNIFIED IDEOGRAPH + 0xBCD4: 0x6A0A, //CJK UNIFIED IDEOGRAPH + 0xBCD5: 0x69F3, //CJK UNIFIED IDEOGRAPH + 0xBCD6: 0x6A02, //CJK UNIFIED IDEOGRAPH + 0xBCD7: 0x6A05, //CJK UNIFIED IDEOGRAPH + 0xBCD8: 0x69ED, //CJK UNIFIED IDEOGRAPH + 0xBCD9: 0x6A11, //CJK UNIFIED IDEOGRAPH + 0xBCDA: 0x6B50, //CJK UNIFIED IDEOGRAPH + 0xBCDB: 0x6B4E, //CJK UNIFIED IDEOGRAPH + 0xBCDC: 0x6BA4, //CJK UNIFIED IDEOGRAPH + 0xBCDD: 0x6BC5, //CJK UNIFIED IDEOGRAPH + 0xBCDE: 0x6BC6, //CJK UNIFIED IDEOGRAPH + 0xBCDF: 0x6F3F, //CJK UNIFIED IDEOGRAPH + 0xBCE0: 0x6F7C, //CJK UNIFIED IDEOGRAPH + 0xBCE1: 0x6F84, //CJK UNIFIED IDEOGRAPH + 0xBCE2: 0x6F51, //CJK UNIFIED IDEOGRAPH + 0xBCE3: 0x6F66, //CJK UNIFIED IDEOGRAPH + 0xBCE4: 0x6F54, //CJK UNIFIED IDEOGRAPH + 0xBCE5: 0x6F86, //CJK UNIFIED IDEOGRAPH + 0xBCE6: 0x6F6D, //CJK UNIFIED IDEOGRAPH + 0xBCE7: 0x6F5B, //CJK UNIFIED IDEOGRAPH + 0xBCE8: 0x6F78, //CJK UNIFIED IDEOGRAPH + 0xBCE9: 0x6F6E, //CJK UNIFIED IDEOGRAPH + 0xBCEA: 0x6F8E, //CJK UNIFIED IDEOGRAPH + 0xBCEB: 0x6F7A, //CJK UNIFIED IDEOGRAPH + 0xBCEC: 0x6F70, //CJK UNIFIED IDEOGRAPH + 0xBCED: 0x6F64, //CJK UNIFIED IDEOGRAPH + 0xBCEE: 0x6F97, //CJK UNIFIED IDEOGRAPH + 0xBCEF: 0x6F58, //CJK UNIFIED IDEOGRAPH + 0xBCF0: 0x6ED5, //CJK UNIFIED IDEOGRAPH + 0xBCF1: 0x6F6F, //CJK UNIFIED IDEOGRAPH + 0xBCF2: 0x6F60, //CJK UNIFIED IDEOGRAPH + 0xBCF3: 0x6F5F, //CJK UNIFIED IDEOGRAPH + 0xBCF4: 0x719F, //CJK UNIFIED IDEOGRAPH + 0xBCF5: 0x71AC, //CJK UNIFIED IDEOGRAPH + 0xBCF6: 0x71B1, //CJK UNIFIED IDEOGRAPH + 0xBCF7: 0x71A8, //CJK UNIFIED IDEOGRAPH + 0xBCF8: 0x7256, //CJK UNIFIED IDEOGRAPH + 0xBCF9: 0x729B, //CJK UNIFIED IDEOGRAPH + 0xBCFA: 0x734E, //CJK UNIFIED IDEOGRAPH + 0xBCFB: 0x7357, //CJK UNIFIED IDEOGRAPH + 0xBCFC: 0x7469, //CJK UNIFIED IDEOGRAPH + 0xBCFD: 0x748B, //CJK UNIFIED IDEOGRAPH + 0xBCFE: 0x7483, //CJK UNIFIED IDEOGRAPH + 0xBD40: 0x747E, //CJK UNIFIED IDEOGRAPH + 0xBD41: 0x7480, //CJK UNIFIED IDEOGRAPH + 0xBD42: 0x757F, //CJK UNIFIED IDEOGRAPH + 0xBD43: 0x7620, //CJK UNIFIED IDEOGRAPH + 0xBD44: 0x7629, //CJK UNIFIED IDEOGRAPH + 0xBD45: 0x761F, //CJK UNIFIED IDEOGRAPH + 0xBD46: 0x7624, //CJK UNIFIED IDEOGRAPH + 0xBD47: 0x7626, //CJK UNIFIED IDEOGRAPH + 0xBD48: 0x7621, //CJK UNIFIED IDEOGRAPH + 0xBD49: 0x7622, //CJK UNIFIED IDEOGRAPH + 0xBD4A: 0x769A, //CJK UNIFIED IDEOGRAPH + 0xBD4B: 0x76BA, //CJK UNIFIED IDEOGRAPH + 0xBD4C: 0x76E4, //CJK UNIFIED IDEOGRAPH + 0xBD4D: 0x778E, //CJK UNIFIED IDEOGRAPH + 0xBD4E: 0x7787, //CJK UNIFIED IDEOGRAPH + 0xBD4F: 0x778C, //CJK UNIFIED IDEOGRAPH + 0xBD50: 0x7791, //CJK UNIFIED IDEOGRAPH + 0xBD51: 0x778B, //CJK UNIFIED IDEOGRAPH + 0xBD52: 0x78CB, //CJK UNIFIED IDEOGRAPH + 0xBD53: 0x78C5, //CJK UNIFIED IDEOGRAPH + 0xBD54: 0x78BA, //CJK UNIFIED IDEOGRAPH + 0xBD55: 0x78CA, //CJK UNIFIED IDEOGRAPH + 0xBD56: 0x78BE, //CJK UNIFIED IDEOGRAPH + 0xBD57: 0x78D5, //CJK UNIFIED IDEOGRAPH + 0xBD58: 0x78BC, //CJK UNIFIED IDEOGRAPH + 0xBD59: 0x78D0, //CJK UNIFIED IDEOGRAPH + 0xBD5A: 0x7A3F, //CJK UNIFIED IDEOGRAPH + 0xBD5B: 0x7A3C, //CJK UNIFIED IDEOGRAPH + 0xBD5C: 0x7A40, //CJK UNIFIED IDEOGRAPH + 0xBD5D: 0x7A3D, //CJK UNIFIED IDEOGRAPH + 0xBD5E: 0x7A37, //CJK UNIFIED IDEOGRAPH + 0xBD5F: 0x7A3B, //CJK UNIFIED IDEOGRAPH + 0xBD60: 0x7AAF, //CJK UNIFIED IDEOGRAPH + 0xBD61: 0x7AAE, //CJK UNIFIED IDEOGRAPH + 0xBD62: 0x7BAD, //CJK UNIFIED IDEOGRAPH + 0xBD63: 0x7BB1, //CJK UNIFIED IDEOGRAPH + 0xBD64: 0x7BC4, //CJK UNIFIED IDEOGRAPH + 0xBD65: 0x7BB4, //CJK UNIFIED IDEOGRAPH + 0xBD66: 0x7BC6, //CJK UNIFIED IDEOGRAPH + 0xBD67: 0x7BC7, //CJK UNIFIED IDEOGRAPH + 0xBD68: 0x7BC1, //CJK UNIFIED IDEOGRAPH + 0xBD69: 0x7BA0, //CJK UNIFIED IDEOGRAPH + 0xBD6A: 0x7BCC, //CJK UNIFIED IDEOGRAPH + 0xBD6B: 0x7CCA, //CJK UNIFIED IDEOGRAPH + 0xBD6C: 0x7DE0, //CJK UNIFIED IDEOGRAPH + 0xBD6D: 0x7DF4, //CJK UNIFIED IDEOGRAPH + 0xBD6E: 0x7DEF, //CJK UNIFIED IDEOGRAPH + 0xBD6F: 0x7DFB, //CJK UNIFIED IDEOGRAPH + 0xBD70: 0x7DD8, //CJK UNIFIED IDEOGRAPH + 0xBD71: 0x7DEC, //CJK UNIFIED IDEOGRAPH + 0xBD72: 0x7DDD, //CJK UNIFIED IDEOGRAPH + 0xBD73: 0x7DE8, //CJK UNIFIED IDEOGRAPH + 0xBD74: 0x7DE3, //CJK UNIFIED IDEOGRAPH + 0xBD75: 0x7DDA, //CJK UNIFIED IDEOGRAPH + 0xBD76: 0x7DDE, //CJK UNIFIED IDEOGRAPH + 0xBD77: 0x7DE9, //CJK UNIFIED IDEOGRAPH + 0xBD78: 0x7D9E, //CJK UNIFIED IDEOGRAPH + 0xBD79: 0x7DD9, //CJK UNIFIED IDEOGRAPH + 0xBD7A: 0x7DF2, //CJK UNIFIED IDEOGRAPH + 0xBD7B: 0x7DF9, //CJK UNIFIED IDEOGRAPH + 0xBD7C: 0x7F75, //CJK UNIFIED IDEOGRAPH + 0xBD7D: 0x7F77, //CJK UNIFIED IDEOGRAPH + 0xBD7E: 0x7FAF, //CJK UNIFIED IDEOGRAPH + 0xBDA1: 0x7FE9, //CJK UNIFIED IDEOGRAPH + 0xBDA2: 0x8026, //CJK UNIFIED IDEOGRAPH + 0xBDA3: 0x819B, //CJK UNIFIED IDEOGRAPH + 0xBDA4: 0x819C, //CJK UNIFIED IDEOGRAPH + 0xBDA5: 0x819D, //CJK UNIFIED IDEOGRAPH + 0xBDA6: 0x81A0, //CJK UNIFIED IDEOGRAPH + 0xBDA7: 0x819A, //CJK UNIFIED IDEOGRAPH + 0xBDA8: 0x8198, //CJK UNIFIED IDEOGRAPH + 0xBDA9: 0x8517, //CJK UNIFIED IDEOGRAPH + 0xBDAA: 0x853D, //CJK UNIFIED IDEOGRAPH + 0xBDAB: 0x851A, //CJK UNIFIED IDEOGRAPH + 0xBDAC: 0x84EE, //CJK UNIFIED IDEOGRAPH + 0xBDAD: 0x852C, //CJK UNIFIED IDEOGRAPH + 0xBDAE: 0x852D, //CJK UNIFIED IDEOGRAPH + 0xBDAF: 0x8513, //CJK UNIFIED IDEOGRAPH + 0xBDB0: 0x8511, //CJK UNIFIED IDEOGRAPH + 0xBDB1: 0x8523, //CJK UNIFIED IDEOGRAPH + 0xBDB2: 0x8521, //CJK UNIFIED IDEOGRAPH + 0xBDB3: 0x8514, //CJK UNIFIED IDEOGRAPH + 0xBDB4: 0x84EC, //CJK UNIFIED IDEOGRAPH + 0xBDB5: 0x8525, //CJK UNIFIED IDEOGRAPH + 0xBDB6: 0x84FF, //CJK UNIFIED IDEOGRAPH + 0xBDB7: 0x8506, //CJK UNIFIED IDEOGRAPH + 0xBDB8: 0x8782, //CJK UNIFIED IDEOGRAPH + 0xBDB9: 0x8774, //CJK UNIFIED IDEOGRAPH + 0xBDBA: 0x8776, //CJK UNIFIED IDEOGRAPH + 0xBDBB: 0x8760, //CJK UNIFIED IDEOGRAPH + 0xBDBC: 0x8766, //CJK UNIFIED IDEOGRAPH + 0xBDBD: 0x8778, //CJK UNIFIED IDEOGRAPH + 0xBDBE: 0x8768, //CJK UNIFIED IDEOGRAPH + 0xBDBF: 0x8759, //CJK UNIFIED IDEOGRAPH + 0xBDC0: 0x8757, //CJK UNIFIED IDEOGRAPH + 0xBDC1: 0x874C, //CJK UNIFIED IDEOGRAPH + 0xBDC2: 0x8753, //CJK UNIFIED IDEOGRAPH + 0xBDC3: 0x885B, //CJK UNIFIED IDEOGRAPH + 0xBDC4: 0x885D, //CJK UNIFIED IDEOGRAPH + 0xBDC5: 0x8910, //CJK UNIFIED IDEOGRAPH + 0xBDC6: 0x8907, //CJK UNIFIED IDEOGRAPH + 0xBDC7: 0x8912, //CJK UNIFIED IDEOGRAPH + 0xBDC8: 0x8913, //CJK UNIFIED IDEOGRAPH + 0xBDC9: 0x8915, //CJK UNIFIED IDEOGRAPH + 0xBDCA: 0x890A, //CJK UNIFIED IDEOGRAPH + 0xBDCB: 0x8ABC, //CJK UNIFIED IDEOGRAPH + 0xBDCC: 0x8AD2, //CJK UNIFIED IDEOGRAPH + 0xBDCD: 0x8AC7, //CJK UNIFIED IDEOGRAPH + 0xBDCE: 0x8AC4, //CJK UNIFIED IDEOGRAPH + 0xBDCF: 0x8A95, //CJK UNIFIED IDEOGRAPH + 0xBDD0: 0x8ACB, //CJK UNIFIED IDEOGRAPH + 0xBDD1: 0x8AF8, //CJK UNIFIED IDEOGRAPH + 0xBDD2: 0x8AB2, //CJK UNIFIED IDEOGRAPH + 0xBDD3: 0x8AC9, //CJK UNIFIED IDEOGRAPH + 0xBDD4: 0x8AC2, //CJK UNIFIED IDEOGRAPH + 0xBDD5: 0x8ABF, //CJK UNIFIED IDEOGRAPH + 0xBDD6: 0x8AB0, //CJK UNIFIED IDEOGRAPH + 0xBDD7: 0x8AD6, //CJK UNIFIED IDEOGRAPH + 0xBDD8: 0x8ACD, //CJK UNIFIED IDEOGRAPH + 0xBDD9: 0x8AB6, //CJK UNIFIED IDEOGRAPH + 0xBDDA: 0x8AB9, //CJK UNIFIED IDEOGRAPH + 0xBDDB: 0x8ADB, //CJK UNIFIED IDEOGRAPH + 0xBDDC: 0x8C4C, //CJK UNIFIED IDEOGRAPH + 0xBDDD: 0x8C4E, //CJK UNIFIED IDEOGRAPH + 0xBDDE: 0x8C6C, //CJK UNIFIED IDEOGRAPH + 0xBDDF: 0x8CE0, //CJK UNIFIED IDEOGRAPH + 0xBDE0: 0x8CDE, //CJK UNIFIED IDEOGRAPH + 0xBDE1: 0x8CE6, //CJK UNIFIED IDEOGRAPH + 0xBDE2: 0x8CE4, //CJK UNIFIED IDEOGRAPH + 0xBDE3: 0x8CEC, //CJK UNIFIED IDEOGRAPH + 0xBDE4: 0x8CED, //CJK UNIFIED IDEOGRAPH + 0xBDE5: 0x8CE2, //CJK UNIFIED IDEOGRAPH + 0xBDE6: 0x8CE3, //CJK UNIFIED IDEOGRAPH + 0xBDE7: 0x8CDC, //CJK UNIFIED IDEOGRAPH + 0xBDE8: 0x8CEA, //CJK UNIFIED IDEOGRAPH + 0xBDE9: 0x8CE1, //CJK UNIFIED IDEOGRAPH + 0xBDEA: 0x8D6D, //CJK UNIFIED IDEOGRAPH + 0xBDEB: 0x8D9F, //CJK UNIFIED IDEOGRAPH + 0xBDEC: 0x8DA3, //CJK UNIFIED IDEOGRAPH + 0xBDED: 0x8E2B, //CJK UNIFIED IDEOGRAPH + 0xBDEE: 0x8E10, //CJK UNIFIED IDEOGRAPH + 0xBDEF: 0x8E1D, //CJK UNIFIED IDEOGRAPH + 0xBDF0: 0x8E22, //CJK UNIFIED IDEOGRAPH + 0xBDF1: 0x8E0F, //CJK UNIFIED IDEOGRAPH + 0xBDF2: 0x8E29, //CJK UNIFIED IDEOGRAPH + 0xBDF3: 0x8E1F, //CJK UNIFIED IDEOGRAPH + 0xBDF4: 0x8E21, //CJK UNIFIED IDEOGRAPH + 0xBDF5: 0x8E1E, //CJK UNIFIED IDEOGRAPH + 0xBDF6: 0x8EBA, //CJK UNIFIED IDEOGRAPH + 0xBDF7: 0x8F1D, //CJK UNIFIED IDEOGRAPH + 0xBDF8: 0x8F1B, //CJK UNIFIED IDEOGRAPH + 0xBDF9: 0x8F1F, //CJK UNIFIED IDEOGRAPH + 0xBDFA: 0x8F29, //CJK UNIFIED IDEOGRAPH + 0xBDFB: 0x8F26, //CJK UNIFIED IDEOGRAPH + 0xBDFC: 0x8F2A, //CJK UNIFIED IDEOGRAPH + 0xBDFD: 0x8F1C, //CJK UNIFIED IDEOGRAPH + 0xBDFE: 0x8F1E, //CJK UNIFIED IDEOGRAPH + 0xBE40: 0x8F25, //CJK UNIFIED IDEOGRAPH + 0xBE41: 0x9069, //CJK UNIFIED IDEOGRAPH + 0xBE42: 0x906E, //CJK UNIFIED IDEOGRAPH + 0xBE43: 0x9068, //CJK UNIFIED IDEOGRAPH + 0xBE44: 0x906D, //CJK UNIFIED IDEOGRAPH + 0xBE45: 0x9077, //CJK UNIFIED IDEOGRAPH + 0xBE46: 0x9130, //CJK UNIFIED IDEOGRAPH + 0xBE47: 0x912D, //CJK UNIFIED IDEOGRAPH + 0xBE48: 0x9127, //CJK UNIFIED IDEOGRAPH + 0xBE49: 0x9131, //CJK UNIFIED IDEOGRAPH + 0xBE4A: 0x9187, //CJK UNIFIED IDEOGRAPH + 0xBE4B: 0x9189, //CJK UNIFIED IDEOGRAPH + 0xBE4C: 0x918B, //CJK UNIFIED IDEOGRAPH + 0xBE4D: 0x9183, //CJK UNIFIED IDEOGRAPH + 0xBE4E: 0x92C5, //CJK UNIFIED IDEOGRAPH + 0xBE4F: 0x92BB, //CJK UNIFIED IDEOGRAPH + 0xBE50: 0x92B7, //CJK UNIFIED IDEOGRAPH + 0xBE51: 0x92EA, //CJK UNIFIED IDEOGRAPH + 0xBE52: 0x92AC, //CJK UNIFIED IDEOGRAPH + 0xBE53: 0x92E4, //CJK UNIFIED IDEOGRAPH + 0xBE54: 0x92C1, //CJK UNIFIED IDEOGRAPH + 0xBE55: 0x92B3, //CJK UNIFIED IDEOGRAPH + 0xBE56: 0x92BC, //CJK UNIFIED IDEOGRAPH + 0xBE57: 0x92D2, //CJK UNIFIED IDEOGRAPH + 0xBE58: 0x92C7, //CJK UNIFIED IDEOGRAPH + 0xBE59: 0x92F0, //CJK UNIFIED IDEOGRAPH + 0xBE5A: 0x92B2, //CJK UNIFIED IDEOGRAPH + 0xBE5B: 0x95AD, //CJK UNIFIED IDEOGRAPH + 0xBE5C: 0x95B1, //CJK UNIFIED IDEOGRAPH + 0xBE5D: 0x9704, //CJK UNIFIED IDEOGRAPH + 0xBE5E: 0x9706, //CJK UNIFIED IDEOGRAPH + 0xBE5F: 0x9707, //CJK UNIFIED IDEOGRAPH + 0xBE60: 0x9709, //CJK UNIFIED IDEOGRAPH + 0xBE61: 0x9760, //CJK UNIFIED IDEOGRAPH + 0xBE62: 0x978D, //CJK UNIFIED IDEOGRAPH + 0xBE63: 0x978B, //CJK UNIFIED IDEOGRAPH + 0xBE64: 0x978F, //CJK UNIFIED IDEOGRAPH + 0xBE65: 0x9821, //CJK UNIFIED IDEOGRAPH + 0xBE66: 0x982B, //CJK UNIFIED IDEOGRAPH + 0xBE67: 0x981C, //CJK UNIFIED IDEOGRAPH + 0xBE68: 0x98B3, //CJK UNIFIED IDEOGRAPH + 0xBE69: 0x990A, //CJK UNIFIED IDEOGRAPH + 0xBE6A: 0x9913, //CJK UNIFIED IDEOGRAPH + 0xBE6B: 0x9912, //CJK UNIFIED IDEOGRAPH + 0xBE6C: 0x9918, //CJK UNIFIED IDEOGRAPH + 0xBE6D: 0x99DD, //CJK UNIFIED IDEOGRAPH + 0xBE6E: 0x99D0, //CJK UNIFIED IDEOGRAPH + 0xBE6F: 0x99DF, //CJK UNIFIED IDEOGRAPH + 0xBE70: 0x99DB, //CJK UNIFIED IDEOGRAPH + 0xBE71: 0x99D1, //CJK UNIFIED IDEOGRAPH + 0xBE72: 0x99D5, //CJK UNIFIED IDEOGRAPH + 0xBE73: 0x99D2, //CJK UNIFIED IDEOGRAPH + 0xBE74: 0x99D9, //CJK UNIFIED IDEOGRAPH + 0xBE75: 0x9AB7, //CJK UNIFIED IDEOGRAPH + 0xBE76: 0x9AEE, //CJK UNIFIED IDEOGRAPH + 0xBE77: 0x9AEF, //CJK UNIFIED IDEOGRAPH + 0xBE78: 0x9B27, //CJK UNIFIED IDEOGRAPH + 0xBE79: 0x9B45, //CJK UNIFIED IDEOGRAPH + 0xBE7A: 0x9B44, //CJK UNIFIED IDEOGRAPH + 0xBE7B: 0x9B77, //CJK UNIFIED IDEOGRAPH + 0xBE7C: 0x9B6F, //CJK UNIFIED IDEOGRAPH + 0xBE7D: 0x9D06, //CJK UNIFIED IDEOGRAPH + 0xBE7E: 0x9D09, //CJK UNIFIED IDEOGRAPH + 0xBEA1: 0x9D03, //CJK UNIFIED IDEOGRAPH + 0xBEA2: 0x9EA9, //CJK UNIFIED IDEOGRAPH + 0xBEA3: 0x9EBE, //CJK UNIFIED IDEOGRAPH + 0xBEA4: 0x9ECE, //CJK UNIFIED IDEOGRAPH + 0xBEA5: 0x58A8, //CJK UNIFIED IDEOGRAPH + 0xBEA6: 0x9F52, //CJK UNIFIED IDEOGRAPH + 0xBEA7: 0x5112, //CJK UNIFIED IDEOGRAPH + 0xBEA8: 0x5118, //CJK UNIFIED IDEOGRAPH + 0xBEA9: 0x5114, //CJK UNIFIED IDEOGRAPH + 0xBEAA: 0x5110, //CJK UNIFIED IDEOGRAPH + 0xBEAB: 0x5115, //CJK UNIFIED IDEOGRAPH + 0xBEAC: 0x5180, //CJK UNIFIED IDEOGRAPH + 0xBEAD: 0x51AA, //CJK UNIFIED IDEOGRAPH + 0xBEAE: 0x51DD, //CJK UNIFIED IDEOGRAPH + 0xBEAF: 0x5291, //CJK UNIFIED IDEOGRAPH + 0xBEB0: 0x5293, //CJK UNIFIED IDEOGRAPH + 0xBEB1: 0x52F3, //CJK UNIFIED IDEOGRAPH + 0xBEB2: 0x5659, //CJK UNIFIED IDEOGRAPH + 0xBEB3: 0x566B, //CJK UNIFIED IDEOGRAPH + 0xBEB4: 0x5679, //CJK UNIFIED IDEOGRAPH + 0xBEB5: 0x5669, //CJK UNIFIED IDEOGRAPH + 0xBEB6: 0x5664, //CJK UNIFIED IDEOGRAPH + 0xBEB7: 0x5678, //CJK UNIFIED IDEOGRAPH + 0xBEB8: 0x566A, //CJK UNIFIED IDEOGRAPH + 0xBEB9: 0x5668, //CJK UNIFIED IDEOGRAPH + 0xBEBA: 0x5665, //CJK UNIFIED IDEOGRAPH + 0xBEBB: 0x5671, //CJK UNIFIED IDEOGRAPH + 0xBEBC: 0x566F, //CJK UNIFIED IDEOGRAPH + 0xBEBD: 0x566C, //CJK UNIFIED IDEOGRAPH + 0xBEBE: 0x5662, //CJK UNIFIED IDEOGRAPH + 0xBEBF: 0x5676, //CJK UNIFIED IDEOGRAPH + 0xBEC0: 0x58C1, //CJK UNIFIED IDEOGRAPH + 0xBEC1: 0x58BE, //CJK UNIFIED IDEOGRAPH + 0xBEC2: 0x58C7, //CJK UNIFIED IDEOGRAPH + 0xBEC3: 0x58C5, //CJK UNIFIED IDEOGRAPH + 0xBEC4: 0x596E, //CJK UNIFIED IDEOGRAPH + 0xBEC5: 0x5B1D, //CJK UNIFIED IDEOGRAPH + 0xBEC6: 0x5B34, //CJK UNIFIED IDEOGRAPH + 0xBEC7: 0x5B78, //CJK UNIFIED IDEOGRAPH + 0xBEC8: 0x5BF0, //CJK UNIFIED IDEOGRAPH + 0xBEC9: 0x5C0E, //CJK UNIFIED IDEOGRAPH + 0xBECA: 0x5F4A, //CJK UNIFIED IDEOGRAPH + 0xBECB: 0x61B2, //CJK UNIFIED IDEOGRAPH + 0xBECC: 0x6191, //CJK UNIFIED IDEOGRAPH + 0xBECD: 0x61A9, //CJK UNIFIED IDEOGRAPH + 0xBECE: 0x618A, //CJK UNIFIED IDEOGRAPH + 0xBECF: 0x61CD, //CJK UNIFIED IDEOGRAPH + 0xBED0: 0x61B6, //CJK UNIFIED IDEOGRAPH + 0xBED1: 0x61BE, //CJK UNIFIED IDEOGRAPH + 0xBED2: 0x61CA, //CJK UNIFIED IDEOGRAPH + 0xBED3: 0x61C8, //CJK UNIFIED IDEOGRAPH + 0xBED4: 0x6230, //CJK UNIFIED IDEOGRAPH + 0xBED5: 0x64C5, //CJK UNIFIED IDEOGRAPH + 0xBED6: 0x64C1, //CJK UNIFIED IDEOGRAPH + 0xBED7: 0x64CB, //CJK UNIFIED IDEOGRAPH + 0xBED8: 0x64BB, //CJK UNIFIED IDEOGRAPH + 0xBED9: 0x64BC, //CJK UNIFIED IDEOGRAPH + 0xBEDA: 0x64DA, //CJK UNIFIED IDEOGRAPH + 0xBEDB: 0x64C4, //CJK UNIFIED IDEOGRAPH + 0xBEDC: 0x64C7, //CJK UNIFIED IDEOGRAPH + 0xBEDD: 0x64C2, //CJK UNIFIED IDEOGRAPH + 0xBEDE: 0x64CD, //CJK UNIFIED IDEOGRAPH + 0xBEDF: 0x64BF, //CJK UNIFIED IDEOGRAPH + 0xBEE0: 0x64D2, //CJK UNIFIED IDEOGRAPH + 0xBEE1: 0x64D4, //CJK UNIFIED IDEOGRAPH + 0xBEE2: 0x64BE, //CJK UNIFIED IDEOGRAPH + 0xBEE3: 0x6574, //CJK UNIFIED IDEOGRAPH + 0xBEE4: 0x66C6, //CJK UNIFIED IDEOGRAPH + 0xBEE5: 0x66C9, //CJK UNIFIED IDEOGRAPH + 0xBEE6: 0x66B9, //CJK UNIFIED IDEOGRAPH + 0xBEE7: 0x66C4, //CJK UNIFIED IDEOGRAPH + 0xBEE8: 0x66C7, //CJK UNIFIED IDEOGRAPH + 0xBEE9: 0x66B8, //CJK UNIFIED IDEOGRAPH + 0xBEEA: 0x6A3D, //CJK UNIFIED IDEOGRAPH + 0xBEEB: 0x6A38, //CJK UNIFIED IDEOGRAPH + 0xBEEC: 0x6A3A, //CJK UNIFIED IDEOGRAPH + 0xBEED: 0x6A59, //CJK UNIFIED IDEOGRAPH + 0xBEEE: 0x6A6B, //CJK UNIFIED IDEOGRAPH + 0xBEEF: 0x6A58, //CJK UNIFIED IDEOGRAPH + 0xBEF0: 0x6A39, //CJK UNIFIED IDEOGRAPH + 0xBEF1: 0x6A44, //CJK UNIFIED IDEOGRAPH + 0xBEF2: 0x6A62, //CJK UNIFIED IDEOGRAPH + 0xBEF3: 0x6A61, //CJK UNIFIED IDEOGRAPH + 0xBEF4: 0x6A4B, //CJK UNIFIED IDEOGRAPH + 0xBEF5: 0x6A47, //CJK UNIFIED IDEOGRAPH + 0xBEF6: 0x6A35, //CJK UNIFIED IDEOGRAPH + 0xBEF7: 0x6A5F, //CJK UNIFIED IDEOGRAPH + 0xBEF8: 0x6A48, //CJK UNIFIED IDEOGRAPH + 0xBEF9: 0x6B59, //CJK UNIFIED IDEOGRAPH + 0xBEFA: 0x6B77, //CJK UNIFIED IDEOGRAPH + 0xBEFB: 0x6C05, //CJK UNIFIED IDEOGRAPH + 0xBEFC: 0x6FC2, //CJK UNIFIED IDEOGRAPH + 0xBEFD: 0x6FB1, //CJK UNIFIED IDEOGRAPH + 0xBEFE: 0x6FA1, //CJK UNIFIED IDEOGRAPH + 0xBF40: 0x6FC3, //CJK UNIFIED IDEOGRAPH + 0xBF41: 0x6FA4, //CJK UNIFIED IDEOGRAPH + 0xBF42: 0x6FC1, //CJK UNIFIED IDEOGRAPH + 0xBF43: 0x6FA7, //CJK UNIFIED IDEOGRAPH + 0xBF44: 0x6FB3, //CJK UNIFIED IDEOGRAPH + 0xBF45: 0x6FC0, //CJK UNIFIED IDEOGRAPH + 0xBF46: 0x6FB9, //CJK UNIFIED IDEOGRAPH + 0xBF47: 0x6FB6, //CJK UNIFIED IDEOGRAPH + 0xBF48: 0x6FA6, //CJK UNIFIED IDEOGRAPH + 0xBF49: 0x6FA0, //CJK UNIFIED IDEOGRAPH + 0xBF4A: 0x6FB4, //CJK UNIFIED IDEOGRAPH + 0xBF4B: 0x71BE, //CJK UNIFIED IDEOGRAPH + 0xBF4C: 0x71C9, //CJK UNIFIED IDEOGRAPH + 0xBF4D: 0x71D0, //CJK UNIFIED IDEOGRAPH + 0xBF4E: 0x71D2, //CJK UNIFIED IDEOGRAPH + 0xBF4F: 0x71C8, //CJK UNIFIED IDEOGRAPH + 0xBF50: 0x71D5, //CJK UNIFIED IDEOGRAPH + 0xBF51: 0x71B9, //CJK UNIFIED IDEOGRAPH + 0xBF52: 0x71CE, //CJK UNIFIED IDEOGRAPH + 0xBF53: 0x71D9, //CJK UNIFIED IDEOGRAPH + 0xBF54: 0x71DC, //CJK UNIFIED IDEOGRAPH + 0xBF55: 0x71C3, //CJK UNIFIED IDEOGRAPH + 0xBF56: 0x71C4, //CJK UNIFIED IDEOGRAPH + 0xBF57: 0x7368, //CJK UNIFIED IDEOGRAPH + 0xBF58: 0x749C, //CJK UNIFIED IDEOGRAPH + 0xBF59: 0x74A3, //CJK UNIFIED IDEOGRAPH + 0xBF5A: 0x7498, //CJK UNIFIED IDEOGRAPH + 0xBF5B: 0x749F, //CJK UNIFIED IDEOGRAPH + 0xBF5C: 0x749E, //CJK UNIFIED IDEOGRAPH + 0xBF5D: 0x74E2, //CJK UNIFIED IDEOGRAPH + 0xBF5E: 0x750C, //CJK UNIFIED IDEOGRAPH + 0xBF5F: 0x750D, //CJK UNIFIED IDEOGRAPH + 0xBF60: 0x7634, //CJK UNIFIED IDEOGRAPH + 0xBF61: 0x7638, //CJK UNIFIED IDEOGRAPH + 0xBF62: 0x763A, //CJK UNIFIED IDEOGRAPH + 0xBF63: 0x76E7, //CJK UNIFIED IDEOGRAPH + 0xBF64: 0x76E5, //CJK UNIFIED IDEOGRAPH + 0xBF65: 0x77A0, //CJK UNIFIED IDEOGRAPH + 0xBF66: 0x779E, //CJK UNIFIED IDEOGRAPH + 0xBF67: 0x779F, //CJK UNIFIED IDEOGRAPH + 0xBF68: 0x77A5, //CJK UNIFIED IDEOGRAPH + 0xBF69: 0x78E8, //CJK UNIFIED IDEOGRAPH + 0xBF6A: 0x78DA, //CJK UNIFIED IDEOGRAPH + 0xBF6B: 0x78EC, //CJK UNIFIED IDEOGRAPH + 0xBF6C: 0x78E7, //CJK UNIFIED IDEOGRAPH + 0xBF6D: 0x79A6, //CJK UNIFIED IDEOGRAPH + 0xBF6E: 0x7A4D, //CJK UNIFIED IDEOGRAPH + 0xBF6F: 0x7A4E, //CJK UNIFIED IDEOGRAPH + 0xBF70: 0x7A46, //CJK UNIFIED IDEOGRAPH + 0xBF71: 0x7A4C, //CJK UNIFIED IDEOGRAPH + 0xBF72: 0x7A4B, //CJK UNIFIED IDEOGRAPH + 0xBF73: 0x7ABA, //CJK UNIFIED IDEOGRAPH + 0xBF74: 0x7BD9, //CJK UNIFIED IDEOGRAPH + 0xBF75: 0x7C11, //CJK UNIFIED IDEOGRAPH + 0xBF76: 0x7BC9, //CJK UNIFIED IDEOGRAPH + 0xBF77: 0x7BE4, //CJK UNIFIED IDEOGRAPH + 0xBF78: 0x7BDB, //CJK UNIFIED IDEOGRAPH + 0xBF79: 0x7BE1, //CJK UNIFIED IDEOGRAPH + 0xBF7A: 0x7BE9, //CJK UNIFIED IDEOGRAPH + 0xBF7B: 0x7BE6, //CJK UNIFIED IDEOGRAPH + 0xBF7C: 0x7CD5, //CJK UNIFIED IDEOGRAPH + 0xBF7D: 0x7CD6, //CJK UNIFIED IDEOGRAPH + 0xBF7E: 0x7E0A, //CJK UNIFIED IDEOGRAPH + 0xBFA1: 0x7E11, //CJK UNIFIED IDEOGRAPH + 0xBFA2: 0x7E08, //CJK UNIFIED IDEOGRAPH + 0xBFA3: 0x7E1B, //CJK UNIFIED IDEOGRAPH + 0xBFA4: 0x7E23, //CJK UNIFIED IDEOGRAPH + 0xBFA5: 0x7E1E, //CJK UNIFIED IDEOGRAPH + 0xBFA6: 0x7E1D, //CJK UNIFIED IDEOGRAPH + 0xBFA7: 0x7E09, //CJK UNIFIED IDEOGRAPH + 0xBFA8: 0x7E10, //CJK UNIFIED IDEOGRAPH + 0xBFA9: 0x7F79, //CJK UNIFIED IDEOGRAPH + 0xBFAA: 0x7FB2, //CJK UNIFIED IDEOGRAPH + 0xBFAB: 0x7FF0, //CJK UNIFIED IDEOGRAPH + 0xBFAC: 0x7FF1, //CJK UNIFIED IDEOGRAPH + 0xBFAD: 0x7FEE, //CJK UNIFIED IDEOGRAPH + 0xBFAE: 0x8028, //CJK UNIFIED IDEOGRAPH + 0xBFAF: 0x81B3, //CJK UNIFIED IDEOGRAPH + 0xBFB0: 0x81A9, //CJK UNIFIED IDEOGRAPH + 0xBFB1: 0x81A8, //CJK UNIFIED IDEOGRAPH + 0xBFB2: 0x81FB, //CJK UNIFIED IDEOGRAPH + 0xBFB3: 0x8208, //CJK UNIFIED IDEOGRAPH + 0xBFB4: 0x8258, //CJK UNIFIED IDEOGRAPH + 0xBFB5: 0x8259, //CJK UNIFIED IDEOGRAPH + 0xBFB6: 0x854A, //CJK UNIFIED IDEOGRAPH + 0xBFB7: 0x8559, //CJK UNIFIED IDEOGRAPH + 0xBFB8: 0x8548, //CJK UNIFIED IDEOGRAPH + 0xBFB9: 0x8568, //CJK UNIFIED IDEOGRAPH + 0xBFBA: 0x8569, //CJK UNIFIED IDEOGRAPH + 0xBFBB: 0x8543, //CJK UNIFIED IDEOGRAPH + 0xBFBC: 0x8549, //CJK UNIFIED IDEOGRAPH + 0xBFBD: 0x856D, //CJK UNIFIED IDEOGRAPH + 0xBFBE: 0x856A, //CJK UNIFIED IDEOGRAPH + 0xBFBF: 0x855E, //CJK UNIFIED IDEOGRAPH + 0xBFC0: 0x8783, //CJK UNIFIED IDEOGRAPH + 0xBFC1: 0x879F, //CJK UNIFIED IDEOGRAPH + 0xBFC2: 0x879E, //CJK UNIFIED IDEOGRAPH + 0xBFC3: 0x87A2, //CJK UNIFIED IDEOGRAPH + 0xBFC4: 0x878D, //CJK UNIFIED IDEOGRAPH + 0xBFC5: 0x8861, //CJK UNIFIED IDEOGRAPH + 0xBFC6: 0x892A, //CJK UNIFIED IDEOGRAPH + 0xBFC7: 0x8932, //CJK UNIFIED IDEOGRAPH + 0xBFC8: 0x8925, //CJK UNIFIED IDEOGRAPH + 0xBFC9: 0x892B, //CJK UNIFIED IDEOGRAPH + 0xBFCA: 0x8921, //CJK UNIFIED IDEOGRAPH + 0xBFCB: 0x89AA, //CJK UNIFIED IDEOGRAPH + 0xBFCC: 0x89A6, //CJK UNIFIED IDEOGRAPH + 0xBFCD: 0x8AE6, //CJK UNIFIED IDEOGRAPH + 0xBFCE: 0x8AFA, //CJK UNIFIED IDEOGRAPH + 0xBFCF: 0x8AEB, //CJK UNIFIED IDEOGRAPH + 0xBFD0: 0x8AF1, //CJK UNIFIED IDEOGRAPH + 0xBFD1: 0x8B00, //CJK UNIFIED IDEOGRAPH + 0xBFD2: 0x8ADC, //CJK UNIFIED IDEOGRAPH + 0xBFD3: 0x8AE7, //CJK UNIFIED IDEOGRAPH + 0xBFD4: 0x8AEE, //CJK UNIFIED IDEOGRAPH + 0xBFD5: 0x8AFE, //CJK UNIFIED IDEOGRAPH + 0xBFD6: 0x8B01, //CJK UNIFIED IDEOGRAPH + 0xBFD7: 0x8B02, //CJK UNIFIED IDEOGRAPH + 0xBFD8: 0x8AF7, //CJK UNIFIED IDEOGRAPH + 0xBFD9: 0x8AED, //CJK UNIFIED IDEOGRAPH + 0xBFDA: 0x8AF3, //CJK UNIFIED IDEOGRAPH + 0xBFDB: 0x8AF6, //CJK UNIFIED IDEOGRAPH + 0xBFDC: 0x8AFC, //CJK UNIFIED IDEOGRAPH + 0xBFDD: 0x8C6B, //CJK UNIFIED IDEOGRAPH + 0xBFDE: 0x8C6D, //CJK UNIFIED IDEOGRAPH + 0xBFDF: 0x8C93, //CJK UNIFIED IDEOGRAPH + 0xBFE0: 0x8CF4, //CJK UNIFIED IDEOGRAPH + 0xBFE1: 0x8E44, //CJK UNIFIED IDEOGRAPH + 0xBFE2: 0x8E31, //CJK UNIFIED IDEOGRAPH + 0xBFE3: 0x8E34, //CJK UNIFIED IDEOGRAPH + 0xBFE4: 0x8E42, //CJK UNIFIED IDEOGRAPH + 0xBFE5: 0x8E39, //CJK UNIFIED IDEOGRAPH + 0xBFE6: 0x8E35, //CJK UNIFIED IDEOGRAPH + 0xBFE7: 0x8F3B, //CJK UNIFIED IDEOGRAPH + 0xBFE8: 0x8F2F, //CJK UNIFIED IDEOGRAPH + 0xBFE9: 0x8F38, //CJK UNIFIED IDEOGRAPH + 0xBFEA: 0x8F33, //CJK UNIFIED IDEOGRAPH + 0xBFEB: 0x8FA8, //CJK UNIFIED IDEOGRAPH + 0xBFEC: 0x8FA6, //CJK UNIFIED IDEOGRAPH + 0xBFED: 0x9075, //CJK UNIFIED IDEOGRAPH + 0xBFEE: 0x9074, //CJK UNIFIED IDEOGRAPH + 0xBFEF: 0x9078, //CJK UNIFIED IDEOGRAPH + 0xBFF0: 0x9072, //CJK UNIFIED IDEOGRAPH + 0xBFF1: 0x907C, //CJK UNIFIED IDEOGRAPH + 0xBFF2: 0x907A, //CJK UNIFIED IDEOGRAPH + 0xBFF3: 0x9134, //CJK UNIFIED IDEOGRAPH + 0xBFF4: 0x9192, //CJK UNIFIED IDEOGRAPH + 0xBFF5: 0x9320, //CJK UNIFIED IDEOGRAPH + 0xBFF6: 0x9336, //CJK UNIFIED IDEOGRAPH + 0xBFF7: 0x92F8, //CJK UNIFIED IDEOGRAPH + 0xBFF8: 0x9333, //CJK UNIFIED IDEOGRAPH + 0xBFF9: 0x932F, //CJK UNIFIED IDEOGRAPH + 0xBFFA: 0x9322, //CJK UNIFIED IDEOGRAPH + 0xBFFB: 0x92FC, //CJK UNIFIED IDEOGRAPH + 0xBFFC: 0x932B, //CJK UNIFIED IDEOGRAPH + 0xBFFD: 0x9304, //CJK UNIFIED IDEOGRAPH + 0xBFFE: 0x931A, //CJK UNIFIED IDEOGRAPH + 0xC040: 0x9310, //CJK UNIFIED IDEOGRAPH + 0xC041: 0x9326, //CJK UNIFIED IDEOGRAPH + 0xC042: 0x9321, //CJK UNIFIED IDEOGRAPH + 0xC043: 0x9315, //CJK UNIFIED IDEOGRAPH + 0xC044: 0x932E, //CJK UNIFIED IDEOGRAPH + 0xC045: 0x9319, //CJK UNIFIED IDEOGRAPH + 0xC046: 0x95BB, //CJK UNIFIED IDEOGRAPH + 0xC047: 0x96A7, //CJK UNIFIED IDEOGRAPH + 0xC048: 0x96A8, //CJK UNIFIED IDEOGRAPH + 0xC049: 0x96AA, //CJK UNIFIED IDEOGRAPH + 0xC04A: 0x96D5, //CJK UNIFIED IDEOGRAPH + 0xC04B: 0x970E, //CJK UNIFIED IDEOGRAPH + 0xC04C: 0x9711, //CJK UNIFIED IDEOGRAPH + 0xC04D: 0x9716, //CJK UNIFIED IDEOGRAPH + 0xC04E: 0x970D, //CJK UNIFIED IDEOGRAPH + 0xC04F: 0x9713, //CJK UNIFIED IDEOGRAPH + 0xC050: 0x970F, //CJK UNIFIED IDEOGRAPH + 0xC051: 0x975B, //CJK UNIFIED IDEOGRAPH + 0xC052: 0x975C, //CJK UNIFIED IDEOGRAPH + 0xC053: 0x9766, //CJK UNIFIED IDEOGRAPH + 0xC054: 0x9798, //CJK UNIFIED IDEOGRAPH + 0xC055: 0x9830, //CJK UNIFIED IDEOGRAPH + 0xC056: 0x9838, //CJK UNIFIED IDEOGRAPH + 0xC057: 0x983B, //CJK UNIFIED IDEOGRAPH + 0xC058: 0x9837, //CJK UNIFIED IDEOGRAPH + 0xC059: 0x982D, //CJK UNIFIED IDEOGRAPH + 0xC05A: 0x9839, //CJK UNIFIED IDEOGRAPH + 0xC05B: 0x9824, //CJK UNIFIED IDEOGRAPH + 0xC05C: 0x9910, //CJK UNIFIED IDEOGRAPH + 0xC05D: 0x9928, //CJK UNIFIED IDEOGRAPH + 0xC05E: 0x991E, //CJK UNIFIED IDEOGRAPH + 0xC05F: 0x991B, //CJK UNIFIED IDEOGRAPH + 0xC060: 0x9921, //CJK UNIFIED IDEOGRAPH + 0xC061: 0x991A, //CJK UNIFIED IDEOGRAPH + 0xC062: 0x99ED, //CJK UNIFIED IDEOGRAPH + 0xC063: 0x99E2, //CJK UNIFIED IDEOGRAPH + 0xC064: 0x99F1, //CJK UNIFIED IDEOGRAPH + 0xC065: 0x9AB8, //CJK UNIFIED IDEOGRAPH + 0xC066: 0x9ABC, //CJK UNIFIED IDEOGRAPH + 0xC067: 0x9AFB, //CJK UNIFIED IDEOGRAPH + 0xC068: 0x9AED, //CJK UNIFIED IDEOGRAPH + 0xC069: 0x9B28, //CJK UNIFIED IDEOGRAPH + 0xC06A: 0x9B91, //CJK UNIFIED IDEOGRAPH + 0xC06B: 0x9D15, //CJK UNIFIED IDEOGRAPH + 0xC06C: 0x9D23, //CJK UNIFIED IDEOGRAPH + 0xC06D: 0x9D26, //CJK UNIFIED IDEOGRAPH + 0xC06E: 0x9D28, //CJK UNIFIED IDEOGRAPH + 0xC06F: 0x9D12, //CJK UNIFIED IDEOGRAPH + 0xC070: 0x9D1B, //CJK UNIFIED IDEOGRAPH + 0xC071: 0x9ED8, //CJK UNIFIED IDEOGRAPH + 0xC072: 0x9ED4, //CJK UNIFIED IDEOGRAPH + 0xC073: 0x9F8D, //CJK UNIFIED IDEOGRAPH + 0xC074: 0x9F9C, //CJK UNIFIED IDEOGRAPH + 0xC075: 0x512A, //CJK UNIFIED IDEOGRAPH + 0xC076: 0x511F, //CJK UNIFIED IDEOGRAPH + 0xC077: 0x5121, //CJK UNIFIED IDEOGRAPH + 0xC078: 0x5132, //CJK UNIFIED IDEOGRAPH + 0xC079: 0x52F5, //CJK UNIFIED IDEOGRAPH + 0xC07A: 0x568E, //CJK UNIFIED IDEOGRAPH + 0xC07B: 0x5680, //CJK UNIFIED IDEOGRAPH + 0xC07C: 0x5690, //CJK UNIFIED IDEOGRAPH + 0xC07D: 0x5685, //CJK UNIFIED IDEOGRAPH + 0xC07E: 0x5687, //CJK UNIFIED IDEOGRAPH + 0xC0A1: 0x568F, //CJK UNIFIED IDEOGRAPH + 0xC0A2: 0x58D5, //CJK UNIFIED IDEOGRAPH + 0xC0A3: 0x58D3, //CJK UNIFIED IDEOGRAPH + 0xC0A4: 0x58D1, //CJK UNIFIED IDEOGRAPH + 0xC0A5: 0x58CE, //CJK UNIFIED IDEOGRAPH + 0xC0A6: 0x5B30, //CJK UNIFIED IDEOGRAPH + 0xC0A7: 0x5B2A, //CJK UNIFIED IDEOGRAPH + 0xC0A8: 0x5B24, //CJK UNIFIED IDEOGRAPH + 0xC0A9: 0x5B7A, //CJK UNIFIED IDEOGRAPH + 0xC0AA: 0x5C37, //CJK UNIFIED IDEOGRAPH + 0xC0AB: 0x5C68, //CJK UNIFIED IDEOGRAPH + 0xC0AC: 0x5DBC, //CJK UNIFIED IDEOGRAPH + 0xC0AD: 0x5DBA, //CJK UNIFIED IDEOGRAPH + 0xC0AE: 0x5DBD, //CJK UNIFIED IDEOGRAPH + 0xC0AF: 0x5DB8, //CJK UNIFIED IDEOGRAPH + 0xC0B0: 0x5E6B, //CJK UNIFIED IDEOGRAPH + 0xC0B1: 0x5F4C, //CJK UNIFIED IDEOGRAPH + 0xC0B2: 0x5FBD, //CJK UNIFIED IDEOGRAPH + 0xC0B3: 0x61C9, //CJK UNIFIED IDEOGRAPH + 0xC0B4: 0x61C2, //CJK UNIFIED IDEOGRAPH + 0xC0B5: 0x61C7, //CJK UNIFIED IDEOGRAPH + 0xC0B6: 0x61E6, //CJK UNIFIED IDEOGRAPH + 0xC0B7: 0x61CB, //CJK UNIFIED IDEOGRAPH + 0xC0B8: 0x6232, //CJK UNIFIED IDEOGRAPH + 0xC0B9: 0x6234, //CJK UNIFIED IDEOGRAPH + 0xC0BA: 0x64CE, //CJK UNIFIED IDEOGRAPH + 0xC0BB: 0x64CA, //CJK UNIFIED IDEOGRAPH + 0xC0BC: 0x64D8, //CJK UNIFIED IDEOGRAPH + 0xC0BD: 0x64E0, //CJK UNIFIED IDEOGRAPH + 0xC0BE: 0x64F0, //CJK UNIFIED IDEOGRAPH + 0xC0BF: 0x64E6, //CJK UNIFIED IDEOGRAPH + 0xC0C0: 0x64EC, //CJK UNIFIED IDEOGRAPH + 0xC0C1: 0x64F1, //CJK UNIFIED IDEOGRAPH + 0xC0C2: 0x64E2, //CJK UNIFIED IDEOGRAPH + 0xC0C3: 0x64ED, //CJK UNIFIED IDEOGRAPH + 0xC0C4: 0x6582, //CJK UNIFIED IDEOGRAPH + 0xC0C5: 0x6583, //CJK UNIFIED IDEOGRAPH + 0xC0C6: 0x66D9, //CJK UNIFIED IDEOGRAPH + 0xC0C7: 0x66D6, //CJK UNIFIED IDEOGRAPH + 0xC0C8: 0x6A80, //CJK UNIFIED IDEOGRAPH + 0xC0C9: 0x6A94, //CJK UNIFIED IDEOGRAPH + 0xC0CA: 0x6A84, //CJK UNIFIED IDEOGRAPH + 0xC0CB: 0x6AA2, //CJK UNIFIED IDEOGRAPH + 0xC0CC: 0x6A9C, //CJK UNIFIED IDEOGRAPH + 0xC0CD: 0x6ADB, //CJK UNIFIED IDEOGRAPH + 0xC0CE: 0x6AA3, //CJK UNIFIED IDEOGRAPH + 0xC0CF: 0x6A7E, //CJK UNIFIED IDEOGRAPH + 0xC0D0: 0x6A97, //CJK UNIFIED IDEOGRAPH + 0xC0D1: 0x6A90, //CJK UNIFIED IDEOGRAPH + 0xC0D2: 0x6AA0, //CJK UNIFIED IDEOGRAPH + 0xC0D3: 0x6B5C, //CJK UNIFIED IDEOGRAPH + 0xC0D4: 0x6BAE, //CJK UNIFIED IDEOGRAPH + 0xC0D5: 0x6BDA, //CJK UNIFIED IDEOGRAPH + 0xC0D6: 0x6C08, //CJK UNIFIED IDEOGRAPH + 0xC0D7: 0x6FD8, //CJK UNIFIED IDEOGRAPH + 0xC0D8: 0x6FF1, //CJK UNIFIED IDEOGRAPH + 0xC0D9: 0x6FDF, //CJK UNIFIED IDEOGRAPH + 0xC0DA: 0x6FE0, //CJK UNIFIED IDEOGRAPH + 0xC0DB: 0x6FDB, //CJK UNIFIED IDEOGRAPH + 0xC0DC: 0x6FE4, //CJK UNIFIED IDEOGRAPH + 0xC0DD: 0x6FEB, //CJK UNIFIED IDEOGRAPH + 0xC0DE: 0x6FEF, //CJK UNIFIED IDEOGRAPH + 0xC0DF: 0x6F80, //CJK UNIFIED IDEOGRAPH + 0xC0E0: 0x6FEC, //CJK UNIFIED IDEOGRAPH + 0xC0E1: 0x6FE1, //CJK UNIFIED IDEOGRAPH + 0xC0E2: 0x6FE9, //CJK UNIFIED IDEOGRAPH + 0xC0E3: 0x6FD5, //CJK UNIFIED IDEOGRAPH + 0xC0E4: 0x6FEE, //CJK UNIFIED IDEOGRAPH + 0xC0E5: 0x6FF0, //CJK UNIFIED IDEOGRAPH + 0xC0E6: 0x71E7, //CJK UNIFIED IDEOGRAPH + 0xC0E7: 0x71DF, //CJK UNIFIED IDEOGRAPH + 0xC0E8: 0x71EE, //CJK UNIFIED IDEOGRAPH + 0xC0E9: 0x71E6, //CJK UNIFIED IDEOGRAPH + 0xC0EA: 0x71E5, //CJK UNIFIED IDEOGRAPH + 0xC0EB: 0x71ED, //CJK UNIFIED IDEOGRAPH + 0xC0EC: 0x71EC, //CJK UNIFIED IDEOGRAPH + 0xC0ED: 0x71F4, //CJK UNIFIED IDEOGRAPH + 0xC0EE: 0x71E0, //CJK UNIFIED IDEOGRAPH + 0xC0EF: 0x7235, //CJK UNIFIED IDEOGRAPH + 0xC0F0: 0x7246, //CJK UNIFIED IDEOGRAPH + 0xC0F1: 0x7370, //CJK UNIFIED IDEOGRAPH + 0xC0F2: 0x7372, //CJK UNIFIED IDEOGRAPH + 0xC0F3: 0x74A9, //CJK UNIFIED IDEOGRAPH + 0xC0F4: 0x74B0, //CJK UNIFIED IDEOGRAPH + 0xC0F5: 0x74A6, //CJK UNIFIED IDEOGRAPH + 0xC0F6: 0x74A8, //CJK UNIFIED IDEOGRAPH + 0xC0F7: 0x7646, //CJK UNIFIED IDEOGRAPH + 0xC0F8: 0x7642, //CJK UNIFIED IDEOGRAPH + 0xC0F9: 0x764C, //CJK UNIFIED IDEOGRAPH + 0xC0FA: 0x76EA, //CJK UNIFIED IDEOGRAPH + 0xC0FB: 0x77B3, //CJK UNIFIED IDEOGRAPH + 0xC0FC: 0x77AA, //CJK UNIFIED IDEOGRAPH + 0xC0FD: 0x77B0, //CJK UNIFIED IDEOGRAPH + 0xC0FE: 0x77AC, //CJK UNIFIED IDEOGRAPH + 0xC140: 0x77A7, //CJK UNIFIED IDEOGRAPH + 0xC141: 0x77AD, //CJK UNIFIED IDEOGRAPH + 0xC142: 0x77EF, //CJK UNIFIED IDEOGRAPH + 0xC143: 0x78F7, //CJK UNIFIED IDEOGRAPH + 0xC144: 0x78FA, //CJK UNIFIED IDEOGRAPH + 0xC145: 0x78F4, //CJK UNIFIED IDEOGRAPH + 0xC146: 0x78EF, //CJK UNIFIED IDEOGRAPH + 0xC147: 0x7901, //CJK UNIFIED IDEOGRAPH + 0xC148: 0x79A7, //CJK UNIFIED IDEOGRAPH + 0xC149: 0x79AA, //CJK UNIFIED IDEOGRAPH + 0xC14A: 0x7A57, //CJK UNIFIED IDEOGRAPH + 0xC14B: 0x7ABF, //CJK UNIFIED IDEOGRAPH + 0xC14C: 0x7C07, //CJK UNIFIED IDEOGRAPH + 0xC14D: 0x7C0D, //CJK UNIFIED IDEOGRAPH + 0xC14E: 0x7BFE, //CJK UNIFIED IDEOGRAPH + 0xC14F: 0x7BF7, //CJK UNIFIED IDEOGRAPH + 0xC150: 0x7C0C, //CJK UNIFIED IDEOGRAPH + 0xC151: 0x7BE0, //CJK UNIFIED IDEOGRAPH + 0xC152: 0x7CE0, //CJK UNIFIED IDEOGRAPH + 0xC153: 0x7CDC, //CJK UNIFIED IDEOGRAPH + 0xC154: 0x7CDE, //CJK UNIFIED IDEOGRAPH + 0xC155: 0x7CE2, //CJK UNIFIED IDEOGRAPH + 0xC156: 0x7CDF, //CJK UNIFIED IDEOGRAPH + 0xC157: 0x7CD9, //CJK UNIFIED IDEOGRAPH + 0xC158: 0x7CDD, //CJK UNIFIED IDEOGRAPH + 0xC159: 0x7E2E, //CJK UNIFIED IDEOGRAPH + 0xC15A: 0x7E3E, //CJK UNIFIED IDEOGRAPH + 0xC15B: 0x7E46, //CJK UNIFIED IDEOGRAPH + 0xC15C: 0x7E37, //CJK UNIFIED IDEOGRAPH + 0xC15D: 0x7E32, //CJK UNIFIED IDEOGRAPH + 0xC15E: 0x7E43, //CJK UNIFIED IDEOGRAPH + 0xC15F: 0x7E2B, //CJK UNIFIED IDEOGRAPH + 0xC160: 0x7E3D, //CJK UNIFIED IDEOGRAPH + 0xC161: 0x7E31, //CJK UNIFIED IDEOGRAPH + 0xC162: 0x7E45, //CJK UNIFIED IDEOGRAPH + 0xC163: 0x7E41, //CJK UNIFIED IDEOGRAPH + 0xC164: 0x7E34, //CJK UNIFIED IDEOGRAPH + 0xC165: 0x7E39, //CJK UNIFIED IDEOGRAPH + 0xC166: 0x7E48, //CJK UNIFIED IDEOGRAPH + 0xC167: 0x7E35, //CJK UNIFIED IDEOGRAPH + 0xC168: 0x7E3F, //CJK UNIFIED IDEOGRAPH + 0xC169: 0x7E2F, //CJK UNIFIED IDEOGRAPH + 0xC16A: 0x7F44, //CJK UNIFIED IDEOGRAPH + 0xC16B: 0x7FF3, //CJK UNIFIED IDEOGRAPH + 0xC16C: 0x7FFC, //CJK UNIFIED IDEOGRAPH + 0xC16D: 0x8071, //CJK UNIFIED IDEOGRAPH + 0xC16E: 0x8072, //CJK UNIFIED IDEOGRAPH + 0xC16F: 0x8070, //CJK UNIFIED IDEOGRAPH + 0xC170: 0x806F, //CJK UNIFIED IDEOGRAPH + 0xC171: 0x8073, //CJK UNIFIED IDEOGRAPH + 0xC172: 0x81C6, //CJK UNIFIED IDEOGRAPH + 0xC173: 0x81C3, //CJK UNIFIED IDEOGRAPH + 0xC174: 0x81BA, //CJK UNIFIED IDEOGRAPH + 0xC175: 0x81C2, //CJK UNIFIED IDEOGRAPH + 0xC176: 0x81C0, //CJK UNIFIED IDEOGRAPH + 0xC177: 0x81BF, //CJK UNIFIED IDEOGRAPH + 0xC178: 0x81BD, //CJK UNIFIED IDEOGRAPH + 0xC179: 0x81C9, //CJK UNIFIED IDEOGRAPH + 0xC17A: 0x81BE, //CJK UNIFIED IDEOGRAPH + 0xC17B: 0x81E8, //CJK UNIFIED IDEOGRAPH + 0xC17C: 0x8209, //CJK UNIFIED IDEOGRAPH + 0xC17D: 0x8271, //CJK UNIFIED IDEOGRAPH + 0xC17E: 0x85AA, //CJK UNIFIED IDEOGRAPH + 0xC1A1: 0x8584, //CJK UNIFIED IDEOGRAPH + 0xC1A2: 0x857E, //CJK UNIFIED IDEOGRAPH + 0xC1A3: 0x859C, //CJK UNIFIED IDEOGRAPH + 0xC1A4: 0x8591, //CJK UNIFIED IDEOGRAPH + 0xC1A5: 0x8594, //CJK UNIFIED IDEOGRAPH + 0xC1A6: 0x85AF, //CJK UNIFIED IDEOGRAPH + 0xC1A7: 0x859B, //CJK UNIFIED IDEOGRAPH + 0xC1A8: 0x8587, //CJK UNIFIED IDEOGRAPH + 0xC1A9: 0x85A8, //CJK UNIFIED IDEOGRAPH + 0xC1AA: 0x858A, //CJK UNIFIED IDEOGRAPH + 0xC1AB: 0x8667, //CJK UNIFIED IDEOGRAPH + 0xC1AC: 0x87C0, //CJK UNIFIED IDEOGRAPH + 0xC1AD: 0x87D1, //CJK UNIFIED IDEOGRAPH + 0xC1AE: 0x87B3, //CJK UNIFIED IDEOGRAPH + 0xC1AF: 0x87D2, //CJK UNIFIED IDEOGRAPH + 0xC1B0: 0x87C6, //CJK UNIFIED IDEOGRAPH + 0xC1B1: 0x87AB, //CJK UNIFIED IDEOGRAPH + 0xC1B2: 0x87BB, //CJK UNIFIED IDEOGRAPH + 0xC1B3: 0x87BA, //CJK UNIFIED IDEOGRAPH + 0xC1B4: 0x87C8, //CJK UNIFIED IDEOGRAPH + 0xC1B5: 0x87CB, //CJK UNIFIED IDEOGRAPH + 0xC1B6: 0x893B, //CJK UNIFIED IDEOGRAPH + 0xC1B7: 0x8936, //CJK UNIFIED IDEOGRAPH + 0xC1B8: 0x8944, //CJK UNIFIED IDEOGRAPH + 0xC1B9: 0x8938, //CJK UNIFIED IDEOGRAPH + 0xC1BA: 0x893D, //CJK UNIFIED IDEOGRAPH + 0xC1BB: 0x89AC, //CJK UNIFIED IDEOGRAPH + 0xC1BC: 0x8B0E, //CJK UNIFIED IDEOGRAPH + 0xC1BD: 0x8B17, //CJK UNIFIED IDEOGRAPH + 0xC1BE: 0x8B19, //CJK UNIFIED IDEOGRAPH + 0xC1BF: 0x8B1B, //CJK UNIFIED IDEOGRAPH + 0xC1C0: 0x8B0A, //CJK UNIFIED IDEOGRAPH + 0xC1C1: 0x8B20, //CJK UNIFIED IDEOGRAPH + 0xC1C2: 0x8B1D, //CJK UNIFIED IDEOGRAPH + 0xC1C3: 0x8B04, //CJK UNIFIED IDEOGRAPH + 0xC1C4: 0x8B10, //CJK UNIFIED IDEOGRAPH + 0xC1C5: 0x8C41, //CJK UNIFIED IDEOGRAPH + 0xC1C6: 0x8C3F, //CJK UNIFIED IDEOGRAPH + 0xC1C7: 0x8C73, //CJK UNIFIED IDEOGRAPH + 0xC1C8: 0x8CFA, //CJK UNIFIED IDEOGRAPH + 0xC1C9: 0x8CFD, //CJK UNIFIED IDEOGRAPH + 0xC1CA: 0x8CFC, //CJK UNIFIED IDEOGRAPH + 0xC1CB: 0x8CF8, //CJK UNIFIED IDEOGRAPH + 0xC1CC: 0x8CFB, //CJK UNIFIED IDEOGRAPH + 0xC1CD: 0x8DA8, //CJK UNIFIED IDEOGRAPH + 0xC1CE: 0x8E49, //CJK UNIFIED IDEOGRAPH + 0xC1CF: 0x8E4B, //CJK UNIFIED IDEOGRAPH + 0xC1D0: 0x8E48, //CJK UNIFIED IDEOGRAPH + 0xC1D1: 0x8E4A, //CJK UNIFIED IDEOGRAPH + 0xC1D2: 0x8F44, //CJK UNIFIED IDEOGRAPH + 0xC1D3: 0x8F3E, //CJK UNIFIED IDEOGRAPH + 0xC1D4: 0x8F42, //CJK UNIFIED IDEOGRAPH + 0xC1D5: 0x8F45, //CJK UNIFIED IDEOGRAPH + 0xC1D6: 0x8F3F, //CJK UNIFIED IDEOGRAPH + 0xC1D7: 0x907F, //CJK UNIFIED IDEOGRAPH + 0xC1D8: 0x907D, //CJK UNIFIED IDEOGRAPH + 0xC1D9: 0x9084, //CJK UNIFIED IDEOGRAPH + 0xC1DA: 0x9081, //CJK UNIFIED IDEOGRAPH + 0xC1DB: 0x9082, //CJK UNIFIED IDEOGRAPH + 0xC1DC: 0x9080, //CJK UNIFIED IDEOGRAPH + 0xC1DD: 0x9139, //CJK UNIFIED IDEOGRAPH + 0xC1DE: 0x91A3, //CJK UNIFIED IDEOGRAPH + 0xC1DF: 0x919E, //CJK UNIFIED IDEOGRAPH + 0xC1E0: 0x919C, //CJK UNIFIED IDEOGRAPH + 0xC1E1: 0x934D, //CJK UNIFIED IDEOGRAPH + 0xC1E2: 0x9382, //CJK UNIFIED IDEOGRAPH + 0xC1E3: 0x9328, //CJK UNIFIED IDEOGRAPH + 0xC1E4: 0x9375, //CJK UNIFIED IDEOGRAPH + 0xC1E5: 0x934A, //CJK UNIFIED IDEOGRAPH + 0xC1E6: 0x9365, //CJK UNIFIED IDEOGRAPH + 0xC1E7: 0x934B, //CJK UNIFIED IDEOGRAPH + 0xC1E8: 0x9318, //CJK UNIFIED IDEOGRAPH + 0xC1E9: 0x937E, //CJK UNIFIED IDEOGRAPH + 0xC1EA: 0x936C, //CJK UNIFIED IDEOGRAPH + 0xC1EB: 0x935B, //CJK UNIFIED IDEOGRAPH + 0xC1EC: 0x9370, //CJK UNIFIED IDEOGRAPH + 0xC1ED: 0x935A, //CJK UNIFIED IDEOGRAPH + 0xC1EE: 0x9354, //CJK UNIFIED IDEOGRAPH + 0xC1EF: 0x95CA, //CJK UNIFIED IDEOGRAPH + 0xC1F0: 0x95CB, //CJK UNIFIED IDEOGRAPH + 0xC1F1: 0x95CC, //CJK UNIFIED IDEOGRAPH + 0xC1F2: 0x95C8, //CJK UNIFIED IDEOGRAPH + 0xC1F3: 0x95C6, //CJK UNIFIED IDEOGRAPH + 0xC1F4: 0x96B1, //CJK UNIFIED IDEOGRAPH + 0xC1F5: 0x96B8, //CJK UNIFIED IDEOGRAPH + 0xC1F6: 0x96D6, //CJK UNIFIED IDEOGRAPH + 0xC1F7: 0x971C, //CJK UNIFIED IDEOGRAPH + 0xC1F8: 0x971E, //CJK UNIFIED IDEOGRAPH + 0xC1F9: 0x97A0, //CJK UNIFIED IDEOGRAPH + 0xC1FA: 0x97D3, //CJK UNIFIED IDEOGRAPH + 0xC1FB: 0x9846, //CJK UNIFIED IDEOGRAPH + 0xC1FC: 0x98B6, //CJK UNIFIED IDEOGRAPH + 0xC1FD: 0x9935, //CJK UNIFIED IDEOGRAPH + 0xC1FE: 0x9A01, //CJK UNIFIED IDEOGRAPH + 0xC240: 0x99FF, //CJK UNIFIED IDEOGRAPH + 0xC241: 0x9BAE, //CJK UNIFIED IDEOGRAPH + 0xC242: 0x9BAB, //CJK UNIFIED IDEOGRAPH + 0xC243: 0x9BAA, //CJK UNIFIED IDEOGRAPH + 0xC244: 0x9BAD, //CJK UNIFIED IDEOGRAPH + 0xC245: 0x9D3B, //CJK UNIFIED IDEOGRAPH + 0xC246: 0x9D3F, //CJK UNIFIED IDEOGRAPH + 0xC247: 0x9E8B, //CJK UNIFIED IDEOGRAPH + 0xC248: 0x9ECF, //CJK UNIFIED IDEOGRAPH + 0xC249: 0x9EDE, //CJK UNIFIED IDEOGRAPH + 0xC24A: 0x9EDC, //CJK UNIFIED IDEOGRAPH + 0xC24B: 0x9EDD, //CJK UNIFIED IDEOGRAPH + 0xC24C: 0x9EDB, //CJK UNIFIED IDEOGRAPH + 0xC24D: 0x9F3E, //CJK UNIFIED IDEOGRAPH + 0xC24E: 0x9F4B, //CJK UNIFIED IDEOGRAPH + 0xC24F: 0x53E2, //CJK UNIFIED IDEOGRAPH + 0xC250: 0x5695, //CJK UNIFIED IDEOGRAPH + 0xC251: 0x56AE, //CJK UNIFIED IDEOGRAPH + 0xC252: 0x58D9, //CJK UNIFIED IDEOGRAPH + 0xC253: 0x58D8, //CJK UNIFIED IDEOGRAPH + 0xC254: 0x5B38, //CJK UNIFIED IDEOGRAPH + 0xC255: 0x5F5D, //CJK UNIFIED IDEOGRAPH + 0xC256: 0x61E3, //CJK UNIFIED IDEOGRAPH + 0xC257: 0x6233, //CJK UNIFIED IDEOGRAPH + 0xC258: 0x64F4, //CJK UNIFIED IDEOGRAPH + 0xC259: 0x64F2, //CJK UNIFIED IDEOGRAPH + 0xC25A: 0x64FE, //CJK UNIFIED IDEOGRAPH + 0xC25B: 0x6506, //CJK UNIFIED IDEOGRAPH + 0xC25C: 0x64FA, //CJK UNIFIED IDEOGRAPH + 0xC25D: 0x64FB, //CJK UNIFIED IDEOGRAPH + 0xC25E: 0x64F7, //CJK UNIFIED IDEOGRAPH + 0xC25F: 0x65B7, //CJK UNIFIED IDEOGRAPH + 0xC260: 0x66DC, //CJK UNIFIED IDEOGRAPH + 0xC261: 0x6726, //CJK UNIFIED IDEOGRAPH + 0xC262: 0x6AB3, //CJK UNIFIED IDEOGRAPH + 0xC263: 0x6AAC, //CJK UNIFIED IDEOGRAPH + 0xC264: 0x6AC3, //CJK UNIFIED IDEOGRAPH + 0xC265: 0x6ABB, //CJK UNIFIED IDEOGRAPH + 0xC266: 0x6AB8, //CJK UNIFIED IDEOGRAPH + 0xC267: 0x6AC2, //CJK UNIFIED IDEOGRAPH + 0xC268: 0x6AAE, //CJK UNIFIED IDEOGRAPH + 0xC269: 0x6AAF, //CJK UNIFIED IDEOGRAPH + 0xC26A: 0x6B5F, //CJK UNIFIED IDEOGRAPH + 0xC26B: 0x6B78, //CJK UNIFIED IDEOGRAPH + 0xC26C: 0x6BAF, //CJK UNIFIED IDEOGRAPH + 0xC26D: 0x7009, //CJK UNIFIED IDEOGRAPH + 0xC26E: 0x700B, //CJK UNIFIED IDEOGRAPH + 0xC26F: 0x6FFE, //CJK UNIFIED IDEOGRAPH + 0xC270: 0x7006, //CJK UNIFIED IDEOGRAPH + 0xC271: 0x6FFA, //CJK UNIFIED IDEOGRAPH + 0xC272: 0x7011, //CJK UNIFIED IDEOGRAPH + 0xC273: 0x700F, //CJK UNIFIED IDEOGRAPH + 0xC274: 0x71FB, //CJK UNIFIED IDEOGRAPH + 0xC275: 0x71FC, //CJK UNIFIED IDEOGRAPH + 0xC276: 0x71FE, //CJK UNIFIED IDEOGRAPH + 0xC277: 0x71F8, //CJK UNIFIED IDEOGRAPH + 0xC278: 0x7377, //CJK UNIFIED IDEOGRAPH + 0xC279: 0x7375, //CJK UNIFIED IDEOGRAPH + 0xC27A: 0x74A7, //CJK UNIFIED IDEOGRAPH + 0xC27B: 0x74BF, //CJK UNIFIED IDEOGRAPH + 0xC27C: 0x7515, //CJK UNIFIED IDEOGRAPH + 0xC27D: 0x7656, //CJK UNIFIED IDEOGRAPH + 0xC27E: 0x7658, //CJK UNIFIED IDEOGRAPH + 0xC2A1: 0x7652, //CJK UNIFIED IDEOGRAPH + 0xC2A2: 0x77BD, //CJK UNIFIED IDEOGRAPH + 0xC2A3: 0x77BF, //CJK UNIFIED IDEOGRAPH + 0xC2A4: 0x77BB, //CJK UNIFIED IDEOGRAPH + 0xC2A5: 0x77BC, //CJK UNIFIED IDEOGRAPH + 0xC2A6: 0x790E, //CJK UNIFIED IDEOGRAPH + 0xC2A7: 0x79AE, //CJK UNIFIED IDEOGRAPH + 0xC2A8: 0x7A61, //CJK UNIFIED IDEOGRAPH + 0xC2A9: 0x7A62, //CJK UNIFIED IDEOGRAPH + 0xC2AA: 0x7A60, //CJK UNIFIED IDEOGRAPH + 0xC2AB: 0x7AC4, //CJK UNIFIED IDEOGRAPH + 0xC2AC: 0x7AC5, //CJK UNIFIED IDEOGRAPH + 0xC2AD: 0x7C2B, //CJK UNIFIED IDEOGRAPH + 0xC2AE: 0x7C27, //CJK UNIFIED IDEOGRAPH + 0xC2AF: 0x7C2A, //CJK UNIFIED IDEOGRAPH + 0xC2B0: 0x7C1E, //CJK UNIFIED IDEOGRAPH + 0xC2B1: 0x7C23, //CJK UNIFIED IDEOGRAPH + 0xC2B2: 0x7C21, //CJK UNIFIED IDEOGRAPH + 0xC2B3: 0x7CE7, //CJK UNIFIED IDEOGRAPH + 0xC2B4: 0x7E54, //CJK UNIFIED IDEOGRAPH + 0xC2B5: 0x7E55, //CJK UNIFIED IDEOGRAPH + 0xC2B6: 0x7E5E, //CJK UNIFIED IDEOGRAPH + 0xC2B7: 0x7E5A, //CJK UNIFIED IDEOGRAPH + 0xC2B8: 0x7E61, //CJK UNIFIED IDEOGRAPH + 0xC2B9: 0x7E52, //CJK UNIFIED IDEOGRAPH + 0xC2BA: 0x7E59, //CJK UNIFIED IDEOGRAPH + 0xC2BB: 0x7F48, //CJK UNIFIED IDEOGRAPH + 0xC2BC: 0x7FF9, //CJK UNIFIED IDEOGRAPH + 0xC2BD: 0x7FFB, //CJK UNIFIED IDEOGRAPH + 0xC2BE: 0x8077, //CJK UNIFIED IDEOGRAPH + 0xC2BF: 0x8076, //CJK UNIFIED IDEOGRAPH + 0xC2C0: 0x81CD, //CJK UNIFIED IDEOGRAPH + 0xC2C1: 0x81CF, //CJK UNIFIED IDEOGRAPH + 0xC2C2: 0x820A, //CJK UNIFIED IDEOGRAPH + 0xC2C3: 0x85CF, //CJK UNIFIED IDEOGRAPH + 0xC2C4: 0x85A9, //CJK UNIFIED IDEOGRAPH + 0xC2C5: 0x85CD, //CJK UNIFIED IDEOGRAPH + 0xC2C6: 0x85D0, //CJK UNIFIED IDEOGRAPH + 0xC2C7: 0x85C9, //CJK UNIFIED IDEOGRAPH + 0xC2C8: 0x85B0, //CJK UNIFIED IDEOGRAPH + 0xC2C9: 0x85BA, //CJK UNIFIED IDEOGRAPH + 0xC2CA: 0x85B9, //CJK UNIFIED IDEOGRAPH + 0xC2CB: 0x85A6, //CJK UNIFIED IDEOGRAPH + 0xC2CC: 0x87EF, //CJK UNIFIED IDEOGRAPH + 0xC2CD: 0x87EC, //CJK UNIFIED IDEOGRAPH + 0xC2CE: 0x87F2, //CJK UNIFIED IDEOGRAPH + 0xC2CF: 0x87E0, //CJK UNIFIED IDEOGRAPH + 0xC2D0: 0x8986, //CJK UNIFIED IDEOGRAPH + 0xC2D1: 0x89B2, //CJK UNIFIED IDEOGRAPH + 0xC2D2: 0x89F4, //CJK UNIFIED IDEOGRAPH + 0xC2D3: 0x8B28, //CJK UNIFIED IDEOGRAPH + 0xC2D4: 0x8B39, //CJK UNIFIED IDEOGRAPH + 0xC2D5: 0x8B2C, //CJK UNIFIED IDEOGRAPH + 0xC2D6: 0x8B2B, //CJK UNIFIED IDEOGRAPH + 0xC2D7: 0x8C50, //CJK UNIFIED IDEOGRAPH + 0xC2D8: 0x8D05, //CJK UNIFIED IDEOGRAPH + 0xC2D9: 0x8E59, //CJK UNIFIED IDEOGRAPH + 0xC2DA: 0x8E63, //CJK UNIFIED IDEOGRAPH + 0xC2DB: 0x8E66, //CJK UNIFIED IDEOGRAPH + 0xC2DC: 0x8E64, //CJK UNIFIED IDEOGRAPH + 0xC2DD: 0x8E5F, //CJK UNIFIED IDEOGRAPH + 0xC2DE: 0x8E55, //CJK UNIFIED IDEOGRAPH + 0xC2DF: 0x8EC0, //CJK UNIFIED IDEOGRAPH + 0xC2E0: 0x8F49, //CJK UNIFIED IDEOGRAPH + 0xC2E1: 0x8F4D, //CJK UNIFIED IDEOGRAPH + 0xC2E2: 0x9087, //CJK UNIFIED IDEOGRAPH + 0xC2E3: 0x9083, //CJK UNIFIED IDEOGRAPH + 0xC2E4: 0x9088, //CJK UNIFIED IDEOGRAPH + 0xC2E5: 0x91AB, //CJK UNIFIED IDEOGRAPH + 0xC2E6: 0x91AC, //CJK UNIFIED IDEOGRAPH + 0xC2E7: 0x91D0, //CJK UNIFIED IDEOGRAPH + 0xC2E8: 0x9394, //CJK UNIFIED IDEOGRAPH + 0xC2E9: 0x938A, //CJK UNIFIED IDEOGRAPH + 0xC2EA: 0x9396, //CJK UNIFIED IDEOGRAPH + 0xC2EB: 0x93A2, //CJK UNIFIED IDEOGRAPH + 0xC2EC: 0x93B3, //CJK UNIFIED IDEOGRAPH + 0xC2ED: 0x93AE, //CJK UNIFIED IDEOGRAPH + 0xC2EE: 0x93AC, //CJK UNIFIED IDEOGRAPH + 0xC2EF: 0x93B0, //CJK UNIFIED IDEOGRAPH + 0xC2F0: 0x9398, //CJK UNIFIED IDEOGRAPH + 0xC2F1: 0x939A, //CJK UNIFIED IDEOGRAPH + 0xC2F2: 0x9397, //CJK UNIFIED IDEOGRAPH + 0xC2F3: 0x95D4, //CJK UNIFIED IDEOGRAPH + 0xC2F4: 0x95D6, //CJK UNIFIED IDEOGRAPH + 0xC2F5: 0x95D0, //CJK UNIFIED IDEOGRAPH + 0xC2F6: 0x95D5, //CJK UNIFIED IDEOGRAPH + 0xC2F7: 0x96E2, //CJK UNIFIED IDEOGRAPH + 0xC2F8: 0x96DC, //CJK UNIFIED IDEOGRAPH + 0xC2F9: 0x96D9, //CJK UNIFIED IDEOGRAPH + 0xC2FA: 0x96DB, //CJK UNIFIED IDEOGRAPH + 0xC2FB: 0x96DE, //CJK UNIFIED IDEOGRAPH + 0xC2FC: 0x9724, //CJK UNIFIED IDEOGRAPH + 0xC2FD: 0x97A3, //CJK UNIFIED IDEOGRAPH + 0xC2FE: 0x97A6, //CJK UNIFIED IDEOGRAPH + 0xC340: 0x97AD, //CJK UNIFIED IDEOGRAPH + 0xC341: 0x97F9, //CJK UNIFIED IDEOGRAPH + 0xC342: 0x984D, //CJK UNIFIED IDEOGRAPH + 0xC343: 0x984F, //CJK UNIFIED IDEOGRAPH + 0xC344: 0x984C, //CJK UNIFIED IDEOGRAPH + 0xC345: 0x984E, //CJK UNIFIED IDEOGRAPH + 0xC346: 0x9853, //CJK UNIFIED IDEOGRAPH + 0xC347: 0x98BA, //CJK UNIFIED IDEOGRAPH + 0xC348: 0x993E, //CJK UNIFIED IDEOGRAPH + 0xC349: 0x993F, //CJK UNIFIED IDEOGRAPH + 0xC34A: 0x993D, //CJK UNIFIED IDEOGRAPH + 0xC34B: 0x992E, //CJK UNIFIED IDEOGRAPH + 0xC34C: 0x99A5, //CJK UNIFIED IDEOGRAPH + 0xC34D: 0x9A0E, //CJK UNIFIED IDEOGRAPH + 0xC34E: 0x9AC1, //CJK UNIFIED IDEOGRAPH + 0xC34F: 0x9B03, //CJK UNIFIED IDEOGRAPH + 0xC350: 0x9B06, //CJK UNIFIED IDEOGRAPH + 0xC351: 0x9B4F, //CJK UNIFIED IDEOGRAPH + 0xC352: 0x9B4E, //CJK UNIFIED IDEOGRAPH + 0xC353: 0x9B4D, //CJK UNIFIED IDEOGRAPH + 0xC354: 0x9BCA, //CJK UNIFIED IDEOGRAPH + 0xC355: 0x9BC9, //CJK UNIFIED IDEOGRAPH + 0xC356: 0x9BFD, //CJK UNIFIED IDEOGRAPH + 0xC357: 0x9BC8, //CJK UNIFIED IDEOGRAPH + 0xC358: 0x9BC0, //CJK UNIFIED IDEOGRAPH + 0xC359: 0x9D51, //CJK UNIFIED IDEOGRAPH + 0xC35A: 0x9D5D, //CJK UNIFIED IDEOGRAPH + 0xC35B: 0x9D60, //CJK UNIFIED IDEOGRAPH + 0xC35C: 0x9EE0, //CJK UNIFIED IDEOGRAPH + 0xC35D: 0x9F15, //CJK UNIFIED IDEOGRAPH + 0xC35E: 0x9F2C, //CJK UNIFIED IDEOGRAPH + 0xC35F: 0x5133, //CJK UNIFIED IDEOGRAPH + 0xC360: 0x56A5, //CJK UNIFIED IDEOGRAPH + 0xC361: 0x58DE, //CJK UNIFIED IDEOGRAPH + 0xC362: 0x58DF, //CJK UNIFIED IDEOGRAPH + 0xC363: 0x58E2, //CJK UNIFIED IDEOGRAPH + 0xC364: 0x5BF5, //CJK UNIFIED IDEOGRAPH + 0xC365: 0x9F90, //CJK UNIFIED IDEOGRAPH + 0xC366: 0x5EEC, //CJK UNIFIED IDEOGRAPH + 0xC367: 0x61F2, //CJK UNIFIED IDEOGRAPH + 0xC368: 0x61F7, //CJK UNIFIED IDEOGRAPH + 0xC369: 0x61F6, //CJK UNIFIED IDEOGRAPH + 0xC36A: 0x61F5, //CJK UNIFIED IDEOGRAPH + 0xC36B: 0x6500, //CJK UNIFIED IDEOGRAPH + 0xC36C: 0x650F, //CJK UNIFIED IDEOGRAPH + 0xC36D: 0x66E0, //CJK UNIFIED IDEOGRAPH + 0xC36E: 0x66DD, //CJK UNIFIED IDEOGRAPH + 0xC36F: 0x6AE5, //CJK UNIFIED IDEOGRAPH + 0xC370: 0x6ADD, //CJK UNIFIED IDEOGRAPH + 0xC371: 0x6ADA, //CJK UNIFIED IDEOGRAPH + 0xC372: 0x6AD3, //CJK UNIFIED IDEOGRAPH + 0xC373: 0x701B, //CJK UNIFIED IDEOGRAPH + 0xC374: 0x701F, //CJK UNIFIED IDEOGRAPH + 0xC375: 0x7028, //CJK UNIFIED IDEOGRAPH + 0xC376: 0x701A, //CJK UNIFIED IDEOGRAPH + 0xC377: 0x701D, //CJK UNIFIED IDEOGRAPH + 0xC378: 0x7015, //CJK UNIFIED IDEOGRAPH + 0xC379: 0x7018, //CJK UNIFIED IDEOGRAPH + 0xC37A: 0x7206, //CJK UNIFIED IDEOGRAPH + 0xC37B: 0x720D, //CJK UNIFIED IDEOGRAPH + 0xC37C: 0x7258, //CJK UNIFIED IDEOGRAPH + 0xC37D: 0x72A2, //CJK UNIFIED IDEOGRAPH + 0xC37E: 0x7378, //CJK UNIFIED IDEOGRAPH + 0xC3A1: 0x737A, //CJK UNIFIED IDEOGRAPH + 0xC3A2: 0x74BD, //CJK UNIFIED IDEOGRAPH + 0xC3A3: 0x74CA, //CJK UNIFIED IDEOGRAPH + 0xC3A4: 0x74E3, //CJK UNIFIED IDEOGRAPH + 0xC3A5: 0x7587, //CJK UNIFIED IDEOGRAPH + 0xC3A6: 0x7586, //CJK UNIFIED IDEOGRAPH + 0xC3A7: 0x765F, //CJK UNIFIED IDEOGRAPH + 0xC3A8: 0x7661, //CJK UNIFIED IDEOGRAPH + 0xC3A9: 0x77C7, //CJK UNIFIED IDEOGRAPH + 0xC3AA: 0x7919, //CJK UNIFIED IDEOGRAPH + 0xC3AB: 0x79B1, //CJK UNIFIED IDEOGRAPH + 0xC3AC: 0x7A6B, //CJK UNIFIED IDEOGRAPH + 0xC3AD: 0x7A69, //CJK UNIFIED IDEOGRAPH + 0xC3AE: 0x7C3E, //CJK UNIFIED IDEOGRAPH + 0xC3AF: 0x7C3F, //CJK UNIFIED IDEOGRAPH + 0xC3B0: 0x7C38, //CJK UNIFIED IDEOGRAPH + 0xC3B1: 0x7C3D, //CJK UNIFIED IDEOGRAPH + 0xC3B2: 0x7C37, //CJK UNIFIED IDEOGRAPH + 0xC3B3: 0x7C40, //CJK UNIFIED IDEOGRAPH + 0xC3B4: 0x7E6B, //CJK UNIFIED IDEOGRAPH + 0xC3B5: 0x7E6D, //CJK UNIFIED IDEOGRAPH + 0xC3B6: 0x7E79, //CJK UNIFIED IDEOGRAPH + 0xC3B7: 0x7E69, //CJK UNIFIED IDEOGRAPH + 0xC3B8: 0x7E6A, //CJK UNIFIED IDEOGRAPH + 0xC3B9: 0x7F85, //CJK UNIFIED IDEOGRAPH + 0xC3BA: 0x7E73, //CJK UNIFIED IDEOGRAPH + 0xC3BB: 0x7FB6, //CJK UNIFIED IDEOGRAPH + 0xC3BC: 0x7FB9, //CJK UNIFIED IDEOGRAPH + 0xC3BD: 0x7FB8, //CJK UNIFIED IDEOGRAPH + 0xC3BE: 0x81D8, //CJK UNIFIED IDEOGRAPH + 0xC3BF: 0x85E9, //CJK UNIFIED IDEOGRAPH + 0xC3C0: 0x85DD, //CJK UNIFIED IDEOGRAPH + 0xC3C1: 0x85EA, //CJK UNIFIED IDEOGRAPH + 0xC3C2: 0x85D5, //CJK UNIFIED IDEOGRAPH + 0xC3C3: 0x85E4, //CJK UNIFIED IDEOGRAPH + 0xC3C4: 0x85E5, //CJK UNIFIED IDEOGRAPH + 0xC3C5: 0x85F7, //CJK UNIFIED IDEOGRAPH + 0xC3C6: 0x87FB, //CJK UNIFIED IDEOGRAPH + 0xC3C7: 0x8805, //CJK UNIFIED IDEOGRAPH + 0xC3C8: 0x880D, //CJK UNIFIED IDEOGRAPH + 0xC3C9: 0x87F9, //CJK UNIFIED IDEOGRAPH + 0xC3CA: 0x87FE, //CJK UNIFIED IDEOGRAPH + 0xC3CB: 0x8960, //CJK UNIFIED IDEOGRAPH + 0xC3CC: 0x895F, //CJK UNIFIED IDEOGRAPH + 0xC3CD: 0x8956, //CJK UNIFIED IDEOGRAPH + 0xC3CE: 0x895E, //CJK UNIFIED IDEOGRAPH + 0xC3CF: 0x8B41, //CJK UNIFIED IDEOGRAPH + 0xC3D0: 0x8B5C, //CJK UNIFIED IDEOGRAPH + 0xC3D1: 0x8B58, //CJK UNIFIED IDEOGRAPH + 0xC3D2: 0x8B49, //CJK UNIFIED IDEOGRAPH + 0xC3D3: 0x8B5A, //CJK UNIFIED IDEOGRAPH + 0xC3D4: 0x8B4E, //CJK UNIFIED IDEOGRAPH + 0xC3D5: 0x8B4F, //CJK UNIFIED IDEOGRAPH + 0xC3D6: 0x8B46, //CJK UNIFIED IDEOGRAPH + 0xC3D7: 0x8B59, //CJK UNIFIED IDEOGRAPH + 0xC3D8: 0x8D08, //CJK UNIFIED IDEOGRAPH + 0xC3D9: 0x8D0A, //CJK UNIFIED IDEOGRAPH + 0xC3DA: 0x8E7C, //CJK UNIFIED IDEOGRAPH + 0xC3DB: 0x8E72, //CJK UNIFIED IDEOGRAPH + 0xC3DC: 0x8E87, //CJK UNIFIED IDEOGRAPH + 0xC3DD: 0x8E76, //CJK UNIFIED IDEOGRAPH + 0xC3DE: 0x8E6C, //CJK UNIFIED IDEOGRAPH + 0xC3DF: 0x8E7A, //CJK UNIFIED IDEOGRAPH + 0xC3E0: 0x8E74, //CJK UNIFIED IDEOGRAPH + 0xC3E1: 0x8F54, //CJK UNIFIED IDEOGRAPH + 0xC3E2: 0x8F4E, //CJK UNIFIED IDEOGRAPH + 0xC3E3: 0x8FAD, //CJK UNIFIED IDEOGRAPH + 0xC3E4: 0x908A, //CJK UNIFIED IDEOGRAPH + 0xC3E5: 0x908B, //CJK UNIFIED IDEOGRAPH + 0xC3E6: 0x91B1, //CJK UNIFIED IDEOGRAPH + 0xC3E7: 0x91AE, //CJK UNIFIED IDEOGRAPH + 0xC3E8: 0x93E1, //CJK UNIFIED IDEOGRAPH + 0xC3E9: 0x93D1, //CJK UNIFIED IDEOGRAPH + 0xC3EA: 0x93DF, //CJK UNIFIED IDEOGRAPH + 0xC3EB: 0x93C3, //CJK UNIFIED IDEOGRAPH + 0xC3EC: 0x93C8, //CJK UNIFIED IDEOGRAPH + 0xC3ED: 0x93DC, //CJK UNIFIED IDEOGRAPH + 0xC3EE: 0x93DD, //CJK UNIFIED IDEOGRAPH + 0xC3EF: 0x93D6, //CJK UNIFIED IDEOGRAPH + 0xC3F0: 0x93E2, //CJK UNIFIED IDEOGRAPH + 0xC3F1: 0x93CD, //CJK UNIFIED IDEOGRAPH + 0xC3F2: 0x93D8, //CJK UNIFIED IDEOGRAPH + 0xC3F3: 0x93E4, //CJK UNIFIED IDEOGRAPH + 0xC3F4: 0x93D7, //CJK UNIFIED IDEOGRAPH + 0xC3F5: 0x93E8, //CJK UNIFIED IDEOGRAPH + 0xC3F6: 0x95DC, //CJK UNIFIED IDEOGRAPH + 0xC3F7: 0x96B4, //CJK UNIFIED IDEOGRAPH + 0xC3F8: 0x96E3, //CJK UNIFIED IDEOGRAPH + 0xC3F9: 0x972A, //CJK UNIFIED IDEOGRAPH + 0xC3FA: 0x9727, //CJK UNIFIED IDEOGRAPH + 0xC3FB: 0x9761, //CJK UNIFIED IDEOGRAPH + 0xC3FC: 0x97DC, //CJK UNIFIED IDEOGRAPH + 0xC3FD: 0x97FB, //CJK UNIFIED IDEOGRAPH + 0xC3FE: 0x985E, //CJK UNIFIED IDEOGRAPH + 0xC440: 0x9858, //CJK UNIFIED IDEOGRAPH + 0xC441: 0x985B, //CJK UNIFIED IDEOGRAPH + 0xC442: 0x98BC, //CJK UNIFIED IDEOGRAPH + 0xC443: 0x9945, //CJK UNIFIED IDEOGRAPH + 0xC444: 0x9949, //CJK UNIFIED IDEOGRAPH + 0xC445: 0x9A16, //CJK UNIFIED IDEOGRAPH + 0xC446: 0x9A19, //CJK UNIFIED IDEOGRAPH + 0xC447: 0x9B0D, //CJK UNIFIED IDEOGRAPH + 0xC448: 0x9BE8, //CJK UNIFIED IDEOGRAPH + 0xC449: 0x9BE7, //CJK UNIFIED IDEOGRAPH + 0xC44A: 0x9BD6, //CJK UNIFIED IDEOGRAPH + 0xC44B: 0x9BDB, //CJK UNIFIED IDEOGRAPH + 0xC44C: 0x9D89, //CJK UNIFIED IDEOGRAPH + 0xC44D: 0x9D61, //CJK UNIFIED IDEOGRAPH + 0xC44E: 0x9D72, //CJK UNIFIED IDEOGRAPH + 0xC44F: 0x9D6A, //CJK UNIFIED IDEOGRAPH + 0xC450: 0x9D6C, //CJK UNIFIED IDEOGRAPH + 0xC451: 0x9E92, //CJK UNIFIED IDEOGRAPH + 0xC452: 0x9E97, //CJK UNIFIED IDEOGRAPH + 0xC453: 0x9E93, //CJK UNIFIED IDEOGRAPH + 0xC454: 0x9EB4, //CJK UNIFIED IDEOGRAPH + 0xC455: 0x52F8, //CJK UNIFIED IDEOGRAPH + 0xC456: 0x56A8, //CJK UNIFIED IDEOGRAPH + 0xC457: 0x56B7, //CJK UNIFIED IDEOGRAPH + 0xC458: 0x56B6, //CJK UNIFIED IDEOGRAPH + 0xC459: 0x56B4, //CJK UNIFIED IDEOGRAPH + 0xC45A: 0x56BC, //CJK UNIFIED IDEOGRAPH + 0xC45B: 0x58E4, //CJK UNIFIED IDEOGRAPH + 0xC45C: 0x5B40, //CJK UNIFIED IDEOGRAPH + 0xC45D: 0x5B43, //CJK UNIFIED IDEOGRAPH + 0xC45E: 0x5B7D, //CJK UNIFIED IDEOGRAPH + 0xC45F: 0x5BF6, //CJK UNIFIED IDEOGRAPH + 0xC460: 0x5DC9, //CJK UNIFIED IDEOGRAPH + 0xC461: 0x61F8, //CJK UNIFIED IDEOGRAPH + 0xC462: 0x61FA, //CJK UNIFIED IDEOGRAPH + 0xC463: 0x6518, //CJK UNIFIED IDEOGRAPH + 0xC464: 0x6514, //CJK UNIFIED IDEOGRAPH + 0xC465: 0x6519, //CJK UNIFIED IDEOGRAPH + 0xC466: 0x66E6, //CJK UNIFIED IDEOGRAPH + 0xC467: 0x6727, //CJK UNIFIED IDEOGRAPH + 0xC468: 0x6AEC, //CJK UNIFIED IDEOGRAPH + 0xC469: 0x703E, //CJK UNIFIED IDEOGRAPH + 0xC46A: 0x7030, //CJK UNIFIED IDEOGRAPH + 0xC46B: 0x7032, //CJK UNIFIED IDEOGRAPH + 0xC46C: 0x7210, //CJK UNIFIED IDEOGRAPH + 0xC46D: 0x737B, //CJK UNIFIED IDEOGRAPH + 0xC46E: 0x74CF, //CJK UNIFIED IDEOGRAPH + 0xC46F: 0x7662, //CJK UNIFIED IDEOGRAPH + 0xC470: 0x7665, //CJK UNIFIED IDEOGRAPH + 0xC471: 0x7926, //CJK UNIFIED IDEOGRAPH + 0xC472: 0x792A, //CJK UNIFIED IDEOGRAPH + 0xC473: 0x792C, //CJK UNIFIED IDEOGRAPH + 0xC474: 0x792B, //CJK UNIFIED IDEOGRAPH + 0xC475: 0x7AC7, //CJK UNIFIED IDEOGRAPH + 0xC476: 0x7AF6, //CJK UNIFIED IDEOGRAPH + 0xC477: 0x7C4C, //CJK UNIFIED IDEOGRAPH + 0xC478: 0x7C43, //CJK UNIFIED IDEOGRAPH + 0xC479: 0x7C4D, //CJK UNIFIED IDEOGRAPH + 0xC47A: 0x7CEF, //CJK UNIFIED IDEOGRAPH + 0xC47B: 0x7CF0, //CJK UNIFIED IDEOGRAPH + 0xC47C: 0x8FAE, //CJK UNIFIED IDEOGRAPH + 0xC47D: 0x7E7D, //CJK UNIFIED IDEOGRAPH + 0xC47E: 0x7E7C, //CJK UNIFIED IDEOGRAPH + 0xC4A1: 0x7E82, //CJK UNIFIED IDEOGRAPH + 0xC4A2: 0x7F4C, //CJK UNIFIED IDEOGRAPH + 0xC4A3: 0x8000, //CJK UNIFIED IDEOGRAPH + 0xC4A4: 0x81DA, //CJK UNIFIED IDEOGRAPH + 0xC4A5: 0x8266, //CJK UNIFIED IDEOGRAPH + 0xC4A6: 0x85FB, //CJK UNIFIED IDEOGRAPH + 0xC4A7: 0x85F9, //CJK UNIFIED IDEOGRAPH + 0xC4A8: 0x8611, //CJK UNIFIED IDEOGRAPH + 0xC4A9: 0x85FA, //CJK UNIFIED IDEOGRAPH + 0xC4AA: 0x8606, //CJK UNIFIED IDEOGRAPH + 0xC4AB: 0x860B, //CJK UNIFIED IDEOGRAPH + 0xC4AC: 0x8607, //CJK UNIFIED IDEOGRAPH + 0xC4AD: 0x860A, //CJK UNIFIED IDEOGRAPH + 0xC4AE: 0x8814, //CJK UNIFIED IDEOGRAPH + 0xC4AF: 0x8815, //CJK UNIFIED IDEOGRAPH + 0xC4B0: 0x8964, //CJK UNIFIED IDEOGRAPH + 0xC4B1: 0x89BA, //CJK UNIFIED IDEOGRAPH + 0xC4B2: 0x89F8, //CJK UNIFIED IDEOGRAPH + 0xC4B3: 0x8B70, //CJK UNIFIED IDEOGRAPH + 0xC4B4: 0x8B6C, //CJK UNIFIED IDEOGRAPH + 0xC4B5: 0x8B66, //CJK UNIFIED IDEOGRAPH + 0xC4B6: 0x8B6F, //CJK UNIFIED IDEOGRAPH + 0xC4B7: 0x8B5F, //CJK UNIFIED IDEOGRAPH + 0xC4B8: 0x8B6B, //CJK UNIFIED IDEOGRAPH + 0xC4B9: 0x8D0F, //CJK UNIFIED IDEOGRAPH + 0xC4BA: 0x8D0D, //CJK UNIFIED IDEOGRAPH + 0xC4BB: 0x8E89, //CJK UNIFIED IDEOGRAPH + 0xC4BC: 0x8E81, //CJK UNIFIED IDEOGRAPH + 0xC4BD: 0x8E85, //CJK UNIFIED IDEOGRAPH + 0xC4BE: 0x8E82, //CJK UNIFIED IDEOGRAPH + 0xC4BF: 0x91B4, //CJK UNIFIED IDEOGRAPH + 0xC4C0: 0x91CB, //CJK UNIFIED IDEOGRAPH + 0xC4C1: 0x9418, //CJK UNIFIED IDEOGRAPH + 0xC4C2: 0x9403, //CJK UNIFIED IDEOGRAPH + 0xC4C3: 0x93FD, //CJK UNIFIED IDEOGRAPH + 0xC4C4: 0x95E1, //CJK UNIFIED IDEOGRAPH + 0xC4C5: 0x9730, //CJK UNIFIED IDEOGRAPH + 0xC4C6: 0x98C4, //CJK UNIFIED IDEOGRAPH + 0xC4C7: 0x9952, //CJK UNIFIED IDEOGRAPH + 0xC4C8: 0x9951, //CJK UNIFIED IDEOGRAPH + 0xC4C9: 0x99A8, //CJK UNIFIED IDEOGRAPH + 0xC4CA: 0x9A2B, //CJK UNIFIED IDEOGRAPH + 0xC4CB: 0x9A30, //CJK UNIFIED IDEOGRAPH + 0xC4CC: 0x9A37, //CJK UNIFIED IDEOGRAPH + 0xC4CD: 0x9A35, //CJK UNIFIED IDEOGRAPH + 0xC4CE: 0x9C13, //CJK UNIFIED IDEOGRAPH + 0xC4CF: 0x9C0D, //CJK UNIFIED IDEOGRAPH + 0xC4D0: 0x9E79, //CJK UNIFIED IDEOGRAPH + 0xC4D1: 0x9EB5, //CJK UNIFIED IDEOGRAPH + 0xC4D2: 0x9EE8, //CJK UNIFIED IDEOGRAPH + 0xC4D3: 0x9F2F, //CJK UNIFIED IDEOGRAPH + 0xC4D4: 0x9F5F, //CJK UNIFIED IDEOGRAPH + 0xC4D5: 0x9F63, //CJK UNIFIED IDEOGRAPH + 0xC4D6: 0x9F61, //CJK UNIFIED IDEOGRAPH + 0xC4D7: 0x5137, //CJK UNIFIED IDEOGRAPH + 0xC4D8: 0x5138, //CJK UNIFIED IDEOGRAPH + 0xC4D9: 0x56C1, //CJK UNIFIED IDEOGRAPH + 0xC4DA: 0x56C0, //CJK UNIFIED IDEOGRAPH + 0xC4DB: 0x56C2, //CJK UNIFIED IDEOGRAPH + 0xC4DC: 0x5914, //CJK UNIFIED IDEOGRAPH + 0xC4DD: 0x5C6C, //CJK UNIFIED IDEOGRAPH + 0xC4DE: 0x5DCD, //CJK UNIFIED IDEOGRAPH + 0xC4DF: 0x61FC, //CJK UNIFIED IDEOGRAPH + 0xC4E0: 0x61FE, //CJK UNIFIED IDEOGRAPH + 0xC4E1: 0x651D, //CJK UNIFIED IDEOGRAPH + 0xC4E2: 0x651C, //CJK UNIFIED IDEOGRAPH + 0xC4E3: 0x6595, //CJK UNIFIED IDEOGRAPH + 0xC4E4: 0x66E9, //CJK UNIFIED IDEOGRAPH + 0xC4E5: 0x6AFB, //CJK UNIFIED IDEOGRAPH + 0xC4E6: 0x6B04, //CJK UNIFIED IDEOGRAPH + 0xC4E7: 0x6AFA, //CJK UNIFIED IDEOGRAPH + 0xC4E8: 0x6BB2, //CJK UNIFIED IDEOGRAPH + 0xC4E9: 0x704C, //CJK UNIFIED IDEOGRAPH + 0xC4EA: 0x721B, //CJK UNIFIED IDEOGRAPH + 0xC4EB: 0x72A7, //CJK UNIFIED IDEOGRAPH + 0xC4EC: 0x74D6, //CJK UNIFIED IDEOGRAPH + 0xC4ED: 0x74D4, //CJK UNIFIED IDEOGRAPH + 0xC4EE: 0x7669, //CJK UNIFIED IDEOGRAPH + 0xC4EF: 0x77D3, //CJK UNIFIED IDEOGRAPH + 0xC4F0: 0x7C50, //CJK UNIFIED IDEOGRAPH + 0xC4F1: 0x7E8F, //CJK UNIFIED IDEOGRAPH + 0xC4F2: 0x7E8C, //CJK UNIFIED IDEOGRAPH + 0xC4F3: 0x7FBC, //CJK UNIFIED IDEOGRAPH + 0xC4F4: 0x8617, //CJK UNIFIED IDEOGRAPH + 0xC4F5: 0x862D, //CJK UNIFIED IDEOGRAPH + 0xC4F6: 0x861A, //CJK UNIFIED IDEOGRAPH + 0xC4F7: 0x8823, //CJK UNIFIED IDEOGRAPH + 0xC4F8: 0x8822, //CJK UNIFIED IDEOGRAPH + 0xC4F9: 0x8821, //CJK UNIFIED IDEOGRAPH + 0xC4FA: 0x881F, //CJK UNIFIED IDEOGRAPH + 0xC4FB: 0x896A, //CJK UNIFIED IDEOGRAPH + 0xC4FC: 0x896C, //CJK UNIFIED IDEOGRAPH + 0xC4FD: 0x89BD, //CJK UNIFIED IDEOGRAPH + 0xC4FE: 0x8B74, //CJK UNIFIED IDEOGRAPH + 0xC540: 0x8B77, //CJK UNIFIED IDEOGRAPH + 0xC541: 0x8B7D, //CJK UNIFIED IDEOGRAPH + 0xC542: 0x8D13, //CJK UNIFIED IDEOGRAPH + 0xC543: 0x8E8A, //CJK UNIFIED IDEOGRAPH + 0xC544: 0x8E8D, //CJK UNIFIED IDEOGRAPH + 0xC545: 0x8E8B, //CJK UNIFIED IDEOGRAPH + 0xC546: 0x8F5F, //CJK UNIFIED IDEOGRAPH + 0xC547: 0x8FAF, //CJK UNIFIED IDEOGRAPH + 0xC548: 0x91BA, //CJK UNIFIED IDEOGRAPH + 0xC549: 0x942E, //CJK UNIFIED IDEOGRAPH + 0xC54A: 0x9433, //CJK UNIFIED IDEOGRAPH + 0xC54B: 0x9435, //CJK UNIFIED IDEOGRAPH + 0xC54C: 0x943A, //CJK UNIFIED IDEOGRAPH + 0xC54D: 0x9438, //CJK UNIFIED IDEOGRAPH + 0xC54E: 0x9432, //CJK UNIFIED IDEOGRAPH + 0xC54F: 0x942B, //CJK UNIFIED IDEOGRAPH + 0xC550: 0x95E2, //CJK UNIFIED IDEOGRAPH + 0xC551: 0x9738, //CJK UNIFIED IDEOGRAPH + 0xC552: 0x9739, //CJK UNIFIED IDEOGRAPH + 0xC553: 0x9732, //CJK UNIFIED IDEOGRAPH + 0xC554: 0x97FF, //CJK UNIFIED IDEOGRAPH + 0xC555: 0x9867, //CJK UNIFIED IDEOGRAPH + 0xC556: 0x9865, //CJK UNIFIED IDEOGRAPH + 0xC557: 0x9957, //CJK UNIFIED IDEOGRAPH + 0xC558: 0x9A45, //CJK UNIFIED IDEOGRAPH + 0xC559: 0x9A43, //CJK UNIFIED IDEOGRAPH + 0xC55A: 0x9A40, //CJK UNIFIED IDEOGRAPH + 0xC55B: 0x9A3E, //CJK UNIFIED IDEOGRAPH + 0xC55C: 0x9ACF, //CJK UNIFIED IDEOGRAPH + 0xC55D: 0x9B54, //CJK UNIFIED IDEOGRAPH + 0xC55E: 0x9B51, //CJK UNIFIED IDEOGRAPH + 0xC55F: 0x9C2D, //CJK UNIFIED IDEOGRAPH + 0xC560: 0x9C25, //CJK UNIFIED IDEOGRAPH + 0xC561: 0x9DAF, //CJK UNIFIED IDEOGRAPH + 0xC562: 0x9DB4, //CJK UNIFIED IDEOGRAPH + 0xC563: 0x9DC2, //CJK UNIFIED IDEOGRAPH + 0xC564: 0x9DB8, //CJK UNIFIED IDEOGRAPH + 0xC565: 0x9E9D, //CJK UNIFIED IDEOGRAPH + 0xC566: 0x9EEF, //CJK UNIFIED IDEOGRAPH + 0xC567: 0x9F19, //CJK UNIFIED IDEOGRAPH + 0xC568: 0x9F5C, //CJK UNIFIED IDEOGRAPH + 0xC569: 0x9F66, //CJK UNIFIED IDEOGRAPH + 0xC56A: 0x9F67, //CJK UNIFIED IDEOGRAPH + 0xC56B: 0x513C, //CJK UNIFIED IDEOGRAPH + 0xC56C: 0x513B, //CJK UNIFIED IDEOGRAPH + 0xC56D: 0x56C8, //CJK UNIFIED IDEOGRAPH + 0xC56E: 0x56CA, //CJK UNIFIED IDEOGRAPH + 0xC56F: 0x56C9, //CJK UNIFIED IDEOGRAPH + 0xC570: 0x5B7F, //CJK UNIFIED IDEOGRAPH + 0xC571: 0x5DD4, //CJK UNIFIED IDEOGRAPH + 0xC572: 0x5DD2, //CJK UNIFIED IDEOGRAPH + 0xC573: 0x5F4E, //CJK UNIFIED IDEOGRAPH + 0xC574: 0x61FF, //CJK UNIFIED IDEOGRAPH + 0xC575: 0x6524, //CJK UNIFIED IDEOGRAPH + 0xC576: 0x6B0A, //CJK UNIFIED IDEOGRAPH + 0xC577: 0x6B61, //CJK UNIFIED IDEOGRAPH + 0xC578: 0x7051, //CJK UNIFIED IDEOGRAPH + 0xC579: 0x7058, //CJK UNIFIED IDEOGRAPH + 0xC57A: 0x7380, //CJK UNIFIED IDEOGRAPH + 0xC57B: 0x74E4, //CJK UNIFIED IDEOGRAPH + 0xC57C: 0x758A, //CJK UNIFIED IDEOGRAPH + 0xC57D: 0x766E, //CJK UNIFIED IDEOGRAPH + 0xC57E: 0x766C, //CJK UNIFIED IDEOGRAPH + 0xC5A1: 0x79B3, //CJK UNIFIED IDEOGRAPH + 0xC5A2: 0x7C60, //CJK UNIFIED IDEOGRAPH + 0xC5A3: 0x7C5F, //CJK UNIFIED IDEOGRAPH + 0xC5A4: 0x807E, //CJK UNIFIED IDEOGRAPH + 0xC5A5: 0x807D, //CJK UNIFIED IDEOGRAPH + 0xC5A6: 0x81DF, //CJK UNIFIED IDEOGRAPH + 0xC5A7: 0x8972, //CJK UNIFIED IDEOGRAPH + 0xC5A8: 0x896F, //CJK UNIFIED IDEOGRAPH + 0xC5A9: 0x89FC, //CJK UNIFIED IDEOGRAPH + 0xC5AA: 0x8B80, //CJK UNIFIED IDEOGRAPH + 0xC5AB: 0x8D16, //CJK UNIFIED IDEOGRAPH + 0xC5AC: 0x8D17, //CJK UNIFIED IDEOGRAPH + 0xC5AD: 0x8E91, //CJK UNIFIED IDEOGRAPH + 0xC5AE: 0x8E93, //CJK UNIFIED IDEOGRAPH + 0xC5AF: 0x8F61, //CJK UNIFIED IDEOGRAPH + 0xC5B0: 0x9148, //CJK UNIFIED IDEOGRAPH + 0xC5B1: 0x9444, //CJK UNIFIED IDEOGRAPH + 0xC5B2: 0x9451, //CJK UNIFIED IDEOGRAPH + 0xC5B3: 0x9452, //CJK UNIFIED IDEOGRAPH + 0xC5B4: 0x973D, //CJK UNIFIED IDEOGRAPH + 0xC5B5: 0x973E, //CJK UNIFIED IDEOGRAPH + 0xC5B6: 0x97C3, //CJK UNIFIED IDEOGRAPH + 0xC5B7: 0x97C1, //CJK UNIFIED IDEOGRAPH + 0xC5B8: 0x986B, //CJK UNIFIED IDEOGRAPH + 0xC5B9: 0x9955, //CJK UNIFIED IDEOGRAPH + 0xC5BA: 0x9A55, //CJK UNIFIED IDEOGRAPH + 0xC5BB: 0x9A4D, //CJK UNIFIED IDEOGRAPH + 0xC5BC: 0x9AD2, //CJK UNIFIED IDEOGRAPH + 0xC5BD: 0x9B1A, //CJK UNIFIED IDEOGRAPH + 0xC5BE: 0x9C49, //CJK UNIFIED IDEOGRAPH + 0xC5BF: 0x9C31, //CJK UNIFIED IDEOGRAPH + 0xC5C0: 0x9C3E, //CJK UNIFIED IDEOGRAPH + 0xC5C1: 0x9C3B, //CJK UNIFIED IDEOGRAPH + 0xC5C2: 0x9DD3, //CJK UNIFIED IDEOGRAPH + 0xC5C3: 0x9DD7, //CJK UNIFIED IDEOGRAPH + 0xC5C4: 0x9F34, //CJK UNIFIED IDEOGRAPH + 0xC5C5: 0x9F6C, //CJK UNIFIED IDEOGRAPH + 0xC5C6: 0x9F6A, //CJK UNIFIED IDEOGRAPH + 0xC5C7: 0x9F94, //CJK UNIFIED IDEOGRAPH + 0xC5C8: 0x56CC, //CJK UNIFIED IDEOGRAPH + 0xC5C9: 0x5DD6, //CJK UNIFIED IDEOGRAPH + 0xC5CA: 0x6200, //CJK UNIFIED IDEOGRAPH + 0xC5CB: 0x6523, //CJK UNIFIED IDEOGRAPH + 0xC5CC: 0x652B, //CJK UNIFIED IDEOGRAPH + 0xC5CD: 0x652A, //CJK UNIFIED IDEOGRAPH + 0xC5CE: 0x66EC, //CJK UNIFIED IDEOGRAPH + 0xC5CF: 0x6B10, //CJK UNIFIED IDEOGRAPH + 0xC5D0: 0x74DA, //CJK UNIFIED IDEOGRAPH + 0xC5D1: 0x7ACA, //CJK UNIFIED IDEOGRAPH + 0xC5D2: 0x7C64, //CJK UNIFIED IDEOGRAPH + 0xC5D3: 0x7C63, //CJK UNIFIED IDEOGRAPH + 0xC5D4: 0x7C65, //CJK UNIFIED IDEOGRAPH + 0xC5D5: 0x7E93, //CJK UNIFIED IDEOGRAPH + 0xC5D6: 0x7E96, //CJK UNIFIED IDEOGRAPH + 0xC5D7: 0x7E94, //CJK UNIFIED IDEOGRAPH + 0xC5D8: 0x81E2, //CJK UNIFIED IDEOGRAPH + 0xC5D9: 0x8638, //CJK UNIFIED IDEOGRAPH + 0xC5DA: 0x863F, //CJK UNIFIED IDEOGRAPH + 0xC5DB: 0x8831, //CJK UNIFIED IDEOGRAPH + 0xC5DC: 0x8B8A, //CJK UNIFIED IDEOGRAPH + 0xC5DD: 0x9090, //CJK UNIFIED IDEOGRAPH + 0xC5DE: 0x908F, //CJK UNIFIED IDEOGRAPH + 0xC5DF: 0x9463, //CJK UNIFIED IDEOGRAPH + 0xC5E0: 0x9460, //CJK UNIFIED IDEOGRAPH + 0xC5E1: 0x9464, //CJK UNIFIED IDEOGRAPH + 0xC5E2: 0x9768, //CJK UNIFIED IDEOGRAPH + 0xC5E3: 0x986F, //CJK UNIFIED IDEOGRAPH + 0xC5E4: 0x995C, //CJK UNIFIED IDEOGRAPH + 0xC5E5: 0x9A5A, //CJK UNIFIED IDEOGRAPH + 0xC5E6: 0x9A5B, //CJK UNIFIED IDEOGRAPH + 0xC5E7: 0x9A57, //CJK UNIFIED IDEOGRAPH + 0xC5E8: 0x9AD3, //CJK UNIFIED IDEOGRAPH + 0xC5E9: 0x9AD4, //CJK UNIFIED IDEOGRAPH + 0xC5EA: 0x9AD1, //CJK UNIFIED IDEOGRAPH + 0xC5EB: 0x9C54, //CJK UNIFIED IDEOGRAPH + 0xC5EC: 0x9C57, //CJK UNIFIED IDEOGRAPH + 0xC5ED: 0x9C56, //CJK UNIFIED IDEOGRAPH + 0xC5EE: 0x9DE5, //CJK UNIFIED IDEOGRAPH + 0xC5EF: 0x9E9F, //CJK UNIFIED IDEOGRAPH + 0xC5F0: 0x9EF4, //CJK UNIFIED IDEOGRAPH + 0xC5F1: 0x56D1, //CJK UNIFIED IDEOGRAPH + 0xC5F2: 0x58E9, //CJK UNIFIED IDEOGRAPH + 0xC5F3: 0x652C, //CJK UNIFIED IDEOGRAPH + 0xC5F4: 0x705E, //CJK UNIFIED IDEOGRAPH + 0xC5F5: 0x7671, //CJK UNIFIED IDEOGRAPH + 0xC5F6: 0x7672, //CJK UNIFIED IDEOGRAPH + 0xC5F7: 0x77D7, //CJK UNIFIED IDEOGRAPH + 0xC5F8: 0x7F50, //CJK UNIFIED IDEOGRAPH + 0xC5F9: 0x7F88, //CJK UNIFIED IDEOGRAPH + 0xC5FA: 0x8836, //CJK UNIFIED IDEOGRAPH + 0xC5FB: 0x8839, //CJK UNIFIED IDEOGRAPH + 0xC5FC: 0x8862, //CJK UNIFIED IDEOGRAPH + 0xC5FD: 0x8B93, //CJK UNIFIED IDEOGRAPH + 0xC5FE: 0x8B92, //CJK UNIFIED IDEOGRAPH + 0xC640: 0x8B96, //CJK UNIFIED IDEOGRAPH + 0xC641: 0x8277, //CJK UNIFIED IDEOGRAPH + 0xC642: 0x8D1B, //CJK UNIFIED IDEOGRAPH + 0xC643: 0x91C0, //CJK UNIFIED IDEOGRAPH + 0xC644: 0x946A, //CJK UNIFIED IDEOGRAPH + 0xC645: 0x9742, //CJK UNIFIED IDEOGRAPH + 0xC646: 0x9748, //CJK UNIFIED IDEOGRAPH + 0xC647: 0x9744, //CJK UNIFIED IDEOGRAPH + 0xC648: 0x97C6, //CJK UNIFIED IDEOGRAPH + 0xC649: 0x9870, //CJK UNIFIED IDEOGRAPH + 0xC64A: 0x9A5F, //CJK UNIFIED IDEOGRAPH + 0xC64B: 0x9B22, //CJK UNIFIED IDEOGRAPH + 0xC64C: 0x9B58, //CJK UNIFIED IDEOGRAPH + 0xC64D: 0x9C5F, //CJK UNIFIED IDEOGRAPH + 0xC64E: 0x9DF9, //CJK UNIFIED IDEOGRAPH + 0xC64F: 0x9DFA, //CJK UNIFIED IDEOGRAPH + 0xC650: 0x9E7C, //CJK UNIFIED IDEOGRAPH + 0xC651: 0x9E7D, //CJK UNIFIED IDEOGRAPH + 0xC652: 0x9F07, //CJK UNIFIED IDEOGRAPH + 0xC653: 0x9F77, //CJK UNIFIED IDEOGRAPH + 0xC654: 0x9F72, //CJK UNIFIED IDEOGRAPH + 0xC655: 0x5EF3, //CJK UNIFIED IDEOGRAPH + 0xC656: 0x6B16, //CJK UNIFIED IDEOGRAPH + 0xC657: 0x7063, //CJK UNIFIED IDEOGRAPH + 0xC658: 0x7C6C, //CJK UNIFIED IDEOGRAPH + 0xC659: 0x7C6E, //CJK UNIFIED IDEOGRAPH + 0xC65A: 0x883B, //CJK UNIFIED IDEOGRAPH + 0xC65B: 0x89C0, //CJK UNIFIED IDEOGRAPH + 0xC65C: 0x8EA1, //CJK UNIFIED IDEOGRAPH + 0xC65D: 0x91C1, //CJK UNIFIED IDEOGRAPH + 0xC65E: 0x9472, //CJK UNIFIED IDEOGRAPH + 0xC65F: 0x9470, //CJK UNIFIED IDEOGRAPH + 0xC660: 0x9871, //CJK UNIFIED IDEOGRAPH + 0xC661: 0x995E, //CJK UNIFIED IDEOGRAPH + 0xC662: 0x9AD6, //CJK UNIFIED IDEOGRAPH + 0xC663: 0x9B23, //CJK UNIFIED IDEOGRAPH + 0xC664: 0x9ECC, //CJK UNIFIED IDEOGRAPH + 0xC665: 0x7064, //CJK UNIFIED IDEOGRAPH + 0xC666: 0x77DA, //CJK UNIFIED IDEOGRAPH + 0xC667: 0x8B9A, //CJK UNIFIED IDEOGRAPH + 0xC668: 0x9477, //CJK UNIFIED IDEOGRAPH + 0xC669: 0x97C9, //CJK UNIFIED IDEOGRAPH + 0xC66A: 0x9A62, //CJK UNIFIED IDEOGRAPH + 0xC66B: 0x9A65, //CJK UNIFIED IDEOGRAPH + 0xC66C: 0x7E9C, //CJK UNIFIED IDEOGRAPH + 0xC66D: 0x8B9C, //CJK UNIFIED IDEOGRAPH + 0xC66E: 0x8EAA, //CJK UNIFIED IDEOGRAPH + 0xC66F: 0x91C5, //CJK UNIFIED IDEOGRAPH + 0xC670: 0x947D, //CJK UNIFIED IDEOGRAPH + 0xC671: 0x947E, //CJK UNIFIED IDEOGRAPH + 0xC672: 0x947C, //CJK UNIFIED IDEOGRAPH + 0xC673: 0x9C77, //CJK UNIFIED IDEOGRAPH + 0xC674: 0x9C78, //CJK UNIFIED IDEOGRAPH + 0xC675: 0x9EF7, //CJK UNIFIED IDEOGRAPH + 0xC676: 0x8C54, //CJK UNIFIED IDEOGRAPH + 0xC677: 0x947F, //CJK UNIFIED IDEOGRAPH + 0xC678: 0x9E1A, //CJK UNIFIED IDEOGRAPH + 0xC679: 0x7228, //CJK UNIFIED IDEOGRAPH + 0xC67A: 0x9A6A, //CJK UNIFIED IDEOGRAPH + 0xC67B: 0x9B31, //CJK UNIFIED IDEOGRAPH + 0xC67C: 0x9E1B, //CJK UNIFIED IDEOGRAPH + 0xC67D: 0x9E1E, //CJK UNIFIED IDEOGRAPH + 0xC67E: 0x7C72, //CJK UNIFIED IDEOGRAPH + 0xC940: 0x4E42, //CJK UNIFIED IDEOGRAPH + 0xC941: 0x4E5C, //CJK UNIFIED IDEOGRAPH + 0xC942: 0x51F5, //CJK UNIFIED IDEOGRAPH + 0xC943: 0x531A, //CJK UNIFIED IDEOGRAPH + 0xC944: 0x5382, //CJK UNIFIED IDEOGRAPH + 0xC945: 0x4E07, //CJK UNIFIED IDEOGRAPH + 0xC946: 0x4E0C, //CJK UNIFIED IDEOGRAPH + 0xC947: 0x4E47, //CJK UNIFIED IDEOGRAPH + 0xC948: 0x4E8D, //CJK UNIFIED IDEOGRAPH + 0xC949: 0x56D7, //CJK UNIFIED IDEOGRAPH + 0xC94A: 0xFA0C, //CJK COMPATIBILITY IDEOGRAPH + 0xC94B: 0x5C6E, //CJK UNIFIED IDEOGRAPH + 0xC94C: 0x5F73, //CJK UNIFIED IDEOGRAPH + 0xC94D: 0x4E0F, //CJK UNIFIED IDEOGRAPH + 0xC94E: 0x5187, //CJK UNIFIED IDEOGRAPH + 0xC94F: 0x4E0E, //CJK UNIFIED IDEOGRAPH + 0xC950: 0x4E2E, //CJK UNIFIED IDEOGRAPH + 0xC951: 0x4E93, //CJK UNIFIED IDEOGRAPH + 0xC952: 0x4EC2, //CJK UNIFIED IDEOGRAPH + 0xC953: 0x4EC9, //CJK UNIFIED IDEOGRAPH + 0xC954: 0x4EC8, //CJK UNIFIED IDEOGRAPH + 0xC955: 0x5198, //CJK UNIFIED IDEOGRAPH + 0xC956: 0x52FC, //CJK UNIFIED IDEOGRAPH + 0xC957: 0x536C, //CJK UNIFIED IDEOGRAPH + 0xC958: 0x53B9, //CJK UNIFIED IDEOGRAPH + 0xC959: 0x5720, //CJK UNIFIED IDEOGRAPH + 0xC95A: 0x5903, //CJK UNIFIED IDEOGRAPH + 0xC95B: 0x592C, //CJK UNIFIED IDEOGRAPH + 0xC95C: 0x5C10, //CJK UNIFIED IDEOGRAPH + 0xC95D: 0x5DFF, //CJK UNIFIED IDEOGRAPH + 0xC95E: 0x65E1, //CJK UNIFIED IDEOGRAPH + 0xC95F: 0x6BB3, //CJK UNIFIED IDEOGRAPH + 0xC960: 0x6BCC, //CJK UNIFIED IDEOGRAPH + 0xC961: 0x6C14, //CJK UNIFIED IDEOGRAPH + 0xC962: 0x723F, //CJK UNIFIED IDEOGRAPH + 0xC963: 0x4E31, //CJK UNIFIED IDEOGRAPH + 0xC964: 0x4E3C, //CJK UNIFIED IDEOGRAPH + 0xC965: 0x4EE8, //CJK UNIFIED IDEOGRAPH + 0xC966: 0x4EDC, //CJK UNIFIED IDEOGRAPH + 0xC967: 0x4EE9, //CJK UNIFIED IDEOGRAPH + 0xC968: 0x4EE1, //CJK UNIFIED IDEOGRAPH + 0xC969: 0x4EDD, //CJK UNIFIED IDEOGRAPH + 0xC96A: 0x4EDA, //CJK UNIFIED IDEOGRAPH + 0xC96B: 0x520C, //CJK UNIFIED IDEOGRAPH + 0xC96C: 0x531C, //CJK UNIFIED IDEOGRAPH + 0xC96D: 0x534C, //CJK UNIFIED IDEOGRAPH + 0xC96E: 0x5722, //CJK UNIFIED IDEOGRAPH + 0xC96F: 0x5723, //CJK UNIFIED IDEOGRAPH + 0xC970: 0x5917, //CJK UNIFIED IDEOGRAPH + 0xC971: 0x592F, //CJK UNIFIED IDEOGRAPH + 0xC972: 0x5B81, //CJK UNIFIED IDEOGRAPH + 0xC973: 0x5B84, //CJK UNIFIED IDEOGRAPH + 0xC974: 0x5C12, //CJK UNIFIED IDEOGRAPH + 0xC975: 0x5C3B, //CJK UNIFIED IDEOGRAPH + 0xC976: 0x5C74, //CJK UNIFIED IDEOGRAPH + 0xC977: 0x5C73, //CJK UNIFIED IDEOGRAPH + 0xC978: 0x5E04, //CJK UNIFIED IDEOGRAPH + 0xC979: 0x5E80, //CJK UNIFIED IDEOGRAPH + 0xC97A: 0x5E82, //CJK UNIFIED IDEOGRAPH + 0xC97B: 0x5FC9, //CJK UNIFIED IDEOGRAPH + 0xC97C: 0x6209, //CJK UNIFIED IDEOGRAPH + 0xC97D: 0x6250, //CJK UNIFIED IDEOGRAPH + 0xC97E: 0x6C15, //CJK UNIFIED IDEOGRAPH + 0xC9A1: 0x6C36, //CJK UNIFIED IDEOGRAPH + 0xC9A2: 0x6C43, //CJK UNIFIED IDEOGRAPH + 0xC9A3: 0x6C3F, //CJK UNIFIED IDEOGRAPH + 0xC9A4: 0x6C3B, //CJK UNIFIED IDEOGRAPH + 0xC9A5: 0x72AE, //CJK UNIFIED IDEOGRAPH + 0xC9A6: 0x72B0, //CJK UNIFIED IDEOGRAPH + 0xC9A7: 0x738A, //CJK UNIFIED IDEOGRAPH + 0xC9A8: 0x79B8, //CJK UNIFIED IDEOGRAPH + 0xC9A9: 0x808A, //CJK UNIFIED IDEOGRAPH + 0xC9AA: 0x961E, //CJK UNIFIED IDEOGRAPH + 0xC9AB: 0x4F0E, //CJK UNIFIED IDEOGRAPH + 0xC9AC: 0x4F18, //CJK UNIFIED IDEOGRAPH + 0xC9AD: 0x4F2C, //CJK UNIFIED IDEOGRAPH + 0xC9AE: 0x4EF5, //CJK UNIFIED IDEOGRAPH + 0xC9AF: 0x4F14, //CJK UNIFIED IDEOGRAPH + 0xC9B0: 0x4EF1, //CJK UNIFIED IDEOGRAPH + 0xC9B1: 0x4F00, //CJK UNIFIED IDEOGRAPH + 0xC9B2: 0x4EF7, //CJK UNIFIED IDEOGRAPH + 0xC9B3: 0x4F08, //CJK UNIFIED IDEOGRAPH + 0xC9B4: 0x4F1D, //CJK UNIFIED IDEOGRAPH + 0xC9B5: 0x4F02, //CJK UNIFIED IDEOGRAPH + 0xC9B6: 0x4F05, //CJK UNIFIED IDEOGRAPH + 0xC9B7: 0x4F22, //CJK UNIFIED IDEOGRAPH + 0xC9B8: 0x4F13, //CJK UNIFIED IDEOGRAPH + 0xC9B9: 0x4F04, //CJK UNIFIED IDEOGRAPH + 0xC9BA: 0x4EF4, //CJK UNIFIED IDEOGRAPH + 0xC9BB: 0x4F12, //CJK UNIFIED IDEOGRAPH + 0xC9BC: 0x51B1, //CJK UNIFIED IDEOGRAPH + 0xC9BD: 0x5213, //CJK UNIFIED IDEOGRAPH + 0xC9BE: 0x5209, //CJK UNIFIED IDEOGRAPH + 0xC9BF: 0x5210, //CJK UNIFIED IDEOGRAPH + 0xC9C0: 0x52A6, //CJK UNIFIED IDEOGRAPH + 0xC9C1: 0x5322, //CJK UNIFIED IDEOGRAPH + 0xC9C2: 0x531F, //CJK UNIFIED IDEOGRAPH + 0xC9C3: 0x534D, //CJK UNIFIED IDEOGRAPH + 0xC9C4: 0x538A, //CJK UNIFIED IDEOGRAPH + 0xC9C5: 0x5407, //CJK UNIFIED IDEOGRAPH + 0xC9C6: 0x56E1, //CJK UNIFIED IDEOGRAPH + 0xC9C7: 0x56DF, //CJK UNIFIED IDEOGRAPH + 0xC9C8: 0x572E, //CJK UNIFIED IDEOGRAPH + 0xC9C9: 0x572A, //CJK UNIFIED IDEOGRAPH + 0xC9CA: 0x5734, //CJK UNIFIED IDEOGRAPH + 0xC9CB: 0x593C, //CJK UNIFIED IDEOGRAPH + 0xC9CC: 0x5980, //CJK UNIFIED IDEOGRAPH + 0xC9CD: 0x597C, //CJK UNIFIED IDEOGRAPH + 0xC9CE: 0x5985, //CJK UNIFIED IDEOGRAPH + 0xC9CF: 0x597B, //CJK UNIFIED IDEOGRAPH + 0xC9D0: 0x597E, //CJK UNIFIED IDEOGRAPH + 0xC9D1: 0x5977, //CJK UNIFIED IDEOGRAPH + 0xC9D2: 0x597F, //CJK UNIFIED IDEOGRAPH + 0xC9D3: 0x5B56, //CJK UNIFIED IDEOGRAPH + 0xC9D4: 0x5C15, //CJK UNIFIED IDEOGRAPH + 0xC9D5: 0x5C25, //CJK UNIFIED IDEOGRAPH + 0xC9D6: 0x5C7C, //CJK UNIFIED IDEOGRAPH + 0xC9D7: 0x5C7A, //CJK UNIFIED IDEOGRAPH + 0xC9D8: 0x5C7B, //CJK UNIFIED IDEOGRAPH + 0xC9D9: 0x5C7E, //CJK UNIFIED IDEOGRAPH + 0xC9DA: 0x5DDF, //CJK UNIFIED IDEOGRAPH + 0xC9DB: 0x5E75, //CJK UNIFIED IDEOGRAPH + 0xC9DC: 0x5E84, //CJK UNIFIED IDEOGRAPH + 0xC9DD: 0x5F02, //CJK UNIFIED IDEOGRAPH + 0xC9DE: 0x5F1A, //CJK UNIFIED IDEOGRAPH + 0xC9DF: 0x5F74, //CJK UNIFIED IDEOGRAPH + 0xC9E0: 0x5FD5, //CJK UNIFIED IDEOGRAPH + 0xC9E1: 0x5FD4, //CJK UNIFIED IDEOGRAPH + 0xC9E2: 0x5FCF, //CJK UNIFIED IDEOGRAPH + 0xC9E3: 0x625C, //CJK UNIFIED IDEOGRAPH + 0xC9E4: 0x625E, //CJK UNIFIED IDEOGRAPH + 0xC9E5: 0x6264, //CJK UNIFIED IDEOGRAPH + 0xC9E6: 0x6261, //CJK UNIFIED IDEOGRAPH + 0xC9E7: 0x6266, //CJK UNIFIED IDEOGRAPH + 0xC9E8: 0x6262, //CJK UNIFIED IDEOGRAPH + 0xC9E9: 0x6259, //CJK UNIFIED IDEOGRAPH + 0xC9EA: 0x6260, //CJK UNIFIED IDEOGRAPH + 0xC9EB: 0x625A, //CJK UNIFIED IDEOGRAPH + 0xC9EC: 0x6265, //CJK UNIFIED IDEOGRAPH + 0xC9ED: 0x65EF, //CJK UNIFIED IDEOGRAPH + 0xC9EE: 0x65EE, //CJK UNIFIED IDEOGRAPH + 0xC9EF: 0x673E, //CJK UNIFIED IDEOGRAPH + 0xC9F0: 0x6739, //CJK UNIFIED IDEOGRAPH + 0xC9F1: 0x6738, //CJK UNIFIED IDEOGRAPH + 0xC9F2: 0x673B, //CJK UNIFIED IDEOGRAPH + 0xC9F3: 0x673A, //CJK UNIFIED IDEOGRAPH + 0xC9F4: 0x673F, //CJK UNIFIED IDEOGRAPH + 0xC9F5: 0x673C, //CJK UNIFIED IDEOGRAPH + 0xC9F6: 0x6733, //CJK UNIFIED IDEOGRAPH + 0xC9F7: 0x6C18, //CJK UNIFIED IDEOGRAPH + 0xC9F8: 0x6C46, //CJK UNIFIED IDEOGRAPH + 0xC9F9: 0x6C52, //CJK UNIFIED IDEOGRAPH + 0xC9FA: 0x6C5C, //CJK UNIFIED IDEOGRAPH + 0xC9FB: 0x6C4F, //CJK UNIFIED IDEOGRAPH + 0xC9FC: 0x6C4A, //CJK UNIFIED IDEOGRAPH + 0xC9FD: 0x6C54, //CJK UNIFIED IDEOGRAPH + 0xC9FE: 0x6C4B, //CJK UNIFIED IDEOGRAPH + 0xCA40: 0x6C4C, //CJK UNIFIED IDEOGRAPH + 0xCA41: 0x7071, //CJK UNIFIED IDEOGRAPH + 0xCA42: 0x725E, //CJK UNIFIED IDEOGRAPH + 0xCA43: 0x72B4, //CJK UNIFIED IDEOGRAPH + 0xCA44: 0x72B5, //CJK UNIFIED IDEOGRAPH + 0xCA45: 0x738E, //CJK UNIFIED IDEOGRAPH + 0xCA46: 0x752A, //CJK UNIFIED IDEOGRAPH + 0xCA47: 0x767F, //CJK UNIFIED IDEOGRAPH + 0xCA48: 0x7A75, //CJK UNIFIED IDEOGRAPH + 0xCA49: 0x7F51, //CJK UNIFIED IDEOGRAPH + 0xCA4A: 0x8278, //CJK UNIFIED IDEOGRAPH + 0xCA4B: 0x827C, //CJK UNIFIED IDEOGRAPH + 0xCA4C: 0x8280, //CJK UNIFIED IDEOGRAPH + 0xCA4D: 0x827D, //CJK UNIFIED IDEOGRAPH + 0xCA4E: 0x827F, //CJK UNIFIED IDEOGRAPH + 0xCA4F: 0x864D, //CJK UNIFIED IDEOGRAPH + 0xCA50: 0x897E, //CJK UNIFIED IDEOGRAPH + 0xCA51: 0x9099, //CJK UNIFIED IDEOGRAPH + 0xCA52: 0x9097, //CJK UNIFIED IDEOGRAPH + 0xCA53: 0x9098, //CJK UNIFIED IDEOGRAPH + 0xCA54: 0x909B, //CJK UNIFIED IDEOGRAPH + 0xCA55: 0x9094, //CJK UNIFIED IDEOGRAPH + 0xCA56: 0x9622, //CJK UNIFIED IDEOGRAPH + 0xCA57: 0x9624, //CJK UNIFIED IDEOGRAPH + 0xCA58: 0x9620, //CJK UNIFIED IDEOGRAPH + 0xCA59: 0x9623, //CJK UNIFIED IDEOGRAPH + 0xCA5A: 0x4F56, //CJK UNIFIED IDEOGRAPH + 0xCA5B: 0x4F3B, //CJK UNIFIED IDEOGRAPH + 0xCA5C: 0x4F62, //CJK UNIFIED IDEOGRAPH + 0xCA5D: 0x4F49, //CJK UNIFIED IDEOGRAPH + 0xCA5E: 0x4F53, //CJK UNIFIED IDEOGRAPH + 0xCA5F: 0x4F64, //CJK UNIFIED IDEOGRAPH + 0xCA60: 0x4F3E, //CJK UNIFIED IDEOGRAPH + 0xCA61: 0x4F67, //CJK UNIFIED IDEOGRAPH + 0xCA62: 0x4F52, //CJK UNIFIED IDEOGRAPH + 0xCA63: 0x4F5F, //CJK UNIFIED IDEOGRAPH + 0xCA64: 0x4F41, //CJK UNIFIED IDEOGRAPH + 0xCA65: 0x4F58, //CJK UNIFIED IDEOGRAPH + 0xCA66: 0x4F2D, //CJK UNIFIED IDEOGRAPH + 0xCA67: 0x4F33, //CJK UNIFIED IDEOGRAPH + 0xCA68: 0x4F3F, //CJK UNIFIED IDEOGRAPH + 0xCA69: 0x4F61, //CJK UNIFIED IDEOGRAPH + 0xCA6A: 0x518F, //CJK UNIFIED IDEOGRAPH + 0xCA6B: 0x51B9, //CJK UNIFIED IDEOGRAPH + 0xCA6C: 0x521C, //CJK UNIFIED IDEOGRAPH + 0xCA6D: 0x521E, //CJK UNIFIED IDEOGRAPH + 0xCA6E: 0x5221, //CJK UNIFIED IDEOGRAPH + 0xCA6F: 0x52AD, //CJK UNIFIED IDEOGRAPH + 0xCA70: 0x52AE, //CJK UNIFIED IDEOGRAPH + 0xCA71: 0x5309, //CJK UNIFIED IDEOGRAPH + 0xCA72: 0x5363, //CJK UNIFIED IDEOGRAPH + 0xCA73: 0x5372, //CJK UNIFIED IDEOGRAPH + 0xCA74: 0x538E, //CJK UNIFIED IDEOGRAPH + 0xCA75: 0x538F, //CJK UNIFIED IDEOGRAPH + 0xCA76: 0x5430, //CJK UNIFIED IDEOGRAPH + 0xCA77: 0x5437, //CJK UNIFIED IDEOGRAPH + 0xCA78: 0x542A, //CJK UNIFIED IDEOGRAPH + 0xCA79: 0x5454, //CJK UNIFIED IDEOGRAPH + 0xCA7A: 0x5445, //CJK UNIFIED IDEOGRAPH + 0xCA7B: 0x5419, //CJK UNIFIED IDEOGRAPH + 0xCA7C: 0x541C, //CJK UNIFIED IDEOGRAPH + 0xCA7D: 0x5425, //CJK UNIFIED IDEOGRAPH + 0xCA7E: 0x5418, //CJK UNIFIED IDEOGRAPH + 0xCAA1: 0x543D, //CJK UNIFIED IDEOGRAPH + 0xCAA2: 0x544F, //CJK UNIFIED IDEOGRAPH + 0xCAA3: 0x5441, //CJK UNIFIED IDEOGRAPH + 0xCAA4: 0x5428, //CJK UNIFIED IDEOGRAPH + 0xCAA5: 0x5424, //CJK UNIFIED IDEOGRAPH + 0xCAA6: 0x5447, //CJK UNIFIED IDEOGRAPH + 0xCAA7: 0x56EE, //CJK UNIFIED IDEOGRAPH + 0xCAA8: 0x56E7, //CJK UNIFIED IDEOGRAPH + 0xCAA9: 0x56E5, //CJK UNIFIED IDEOGRAPH + 0xCAAA: 0x5741, //CJK UNIFIED IDEOGRAPH + 0xCAAB: 0x5745, //CJK UNIFIED IDEOGRAPH + 0xCAAC: 0x574C, //CJK UNIFIED IDEOGRAPH + 0xCAAD: 0x5749, //CJK UNIFIED IDEOGRAPH + 0xCAAE: 0x574B, //CJK UNIFIED IDEOGRAPH + 0xCAAF: 0x5752, //CJK UNIFIED IDEOGRAPH + 0xCAB0: 0x5906, //CJK UNIFIED IDEOGRAPH + 0xCAB1: 0x5940, //CJK UNIFIED IDEOGRAPH + 0xCAB2: 0x59A6, //CJK UNIFIED IDEOGRAPH + 0xCAB3: 0x5998, //CJK UNIFIED IDEOGRAPH + 0xCAB4: 0x59A0, //CJK UNIFIED IDEOGRAPH + 0xCAB5: 0x5997, //CJK UNIFIED IDEOGRAPH + 0xCAB6: 0x598E, //CJK UNIFIED IDEOGRAPH + 0xCAB7: 0x59A2, //CJK UNIFIED IDEOGRAPH + 0xCAB8: 0x5990, //CJK UNIFIED IDEOGRAPH + 0xCAB9: 0x598F, //CJK UNIFIED IDEOGRAPH + 0xCABA: 0x59A7, //CJK UNIFIED IDEOGRAPH + 0xCABB: 0x59A1, //CJK UNIFIED IDEOGRAPH + 0xCABC: 0x5B8E, //CJK UNIFIED IDEOGRAPH + 0xCABD: 0x5B92, //CJK UNIFIED IDEOGRAPH + 0xCABE: 0x5C28, //CJK UNIFIED IDEOGRAPH + 0xCABF: 0x5C2A, //CJK UNIFIED IDEOGRAPH + 0xCAC0: 0x5C8D, //CJK UNIFIED IDEOGRAPH + 0xCAC1: 0x5C8F, //CJK UNIFIED IDEOGRAPH + 0xCAC2: 0x5C88, //CJK UNIFIED IDEOGRAPH + 0xCAC3: 0x5C8B, //CJK UNIFIED IDEOGRAPH + 0xCAC4: 0x5C89, //CJK UNIFIED IDEOGRAPH + 0xCAC5: 0x5C92, //CJK UNIFIED IDEOGRAPH + 0xCAC6: 0x5C8A, //CJK UNIFIED IDEOGRAPH + 0xCAC7: 0x5C86, //CJK UNIFIED IDEOGRAPH + 0xCAC8: 0x5C93, //CJK UNIFIED IDEOGRAPH + 0xCAC9: 0x5C95, //CJK UNIFIED IDEOGRAPH + 0xCACA: 0x5DE0, //CJK UNIFIED IDEOGRAPH + 0xCACB: 0x5E0A, //CJK UNIFIED IDEOGRAPH + 0xCACC: 0x5E0E, //CJK UNIFIED IDEOGRAPH + 0xCACD: 0x5E8B, //CJK UNIFIED IDEOGRAPH + 0xCACE: 0x5E89, //CJK UNIFIED IDEOGRAPH + 0xCACF: 0x5E8C, //CJK UNIFIED IDEOGRAPH + 0xCAD0: 0x5E88, //CJK UNIFIED IDEOGRAPH + 0xCAD1: 0x5E8D, //CJK UNIFIED IDEOGRAPH + 0xCAD2: 0x5F05, //CJK UNIFIED IDEOGRAPH + 0xCAD3: 0x5F1D, //CJK UNIFIED IDEOGRAPH + 0xCAD4: 0x5F78, //CJK UNIFIED IDEOGRAPH + 0xCAD5: 0x5F76, //CJK UNIFIED IDEOGRAPH + 0xCAD6: 0x5FD2, //CJK UNIFIED IDEOGRAPH + 0xCAD7: 0x5FD1, //CJK UNIFIED IDEOGRAPH + 0xCAD8: 0x5FD0, //CJK UNIFIED IDEOGRAPH + 0xCAD9: 0x5FED, //CJK UNIFIED IDEOGRAPH + 0xCADA: 0x5FE8, //CJK UNIFIED IDEOGRAPH + 0xCADB: 0x5FEE, //CJK UNIFIED IDEOGRAPH + 0xCADC: 0x5FF3, //CJK UNIFIED IDEOGRAPH + 0xCADD: 0x5FE1, //CJK UNIFIED IDEOGRAPH + 0xCADE: 0x5FE4, //CJK UNIFIED IDEOGRAPH + 0xCADF: 0x5FE3, //CJK UNIFIED IDEOGRAPH + 0xCAE0: 0x5FFA, //CJK UNIFIED IDEOGRAPH + 0xCAE1: 0x5FEF, //CJK UNIFIED IDEOGRAPH + 0xCAE2: 0x5FF7, //CJK UNIFIED IDEOGRAPH + 0xCAE3: 0x5FFB, //CJK UNIFIED IDEOGRAPH + 0xCAE4: 0x6000, //CJK UNIFIED IDEOGRAPH + 0xCAE5: 0x5FF4, //CJK UNIFIED IDEOGRAPH + 0xCAE6: 0x623A, //CJK UNIFIED IDEOGRAPH + 0xCAE7: 0x6283, //CJK UNIFIED IDEOGRAPH + 0xCAE8: 0x628C, //CJK UNIFIED IDEOGRAPH + 0xCAE9: 0x628E, //CJK UNIFIED IDEOGRAPH + 0xCAEA: 0x628F, //CJK UNIFIED IDEOGRAPH + 0xCAEB: 0x6294, //CJK UNIFIED IDEOGRAPH + 0xCAEC: 0x6287, //CJK UNIFIED IDEOGRAPH + 0xCAED: 0x6271, //CJK UNIFIED IDEOGRAPH + 0xCAEE: 0x627B, //CJK UNIFIED IDEOGRAPH + 0xCAEF: 0x627A, //CJK UNIFIED IDEOGRAPH + 0xCAF0: 0x6270, //CJK UNIFIED IDEOGRAPH + 0xCAF1: 0x6281, //CJK UNIFIED IDEOGRAPH + 0xCAF2: 0x6288, //CJK UNIFIED IDEOGRAPH + 0xCAF3: 0x6277, //CJK UNIFIED IDEOGRAPH + 0xCAF4: 0x627D, //CJK UNIFIED IDEOGRAPH + 0xCAF5: 0x6272, //CJK UNIFIED IDEOGRAPH + 0xCAF6: 0x6274, //CJK UNIFIED IDEOGRAPH + 0xCAF7: 0x6537, //CJK UNIFIED IDEOGRAPH + 0xCAF8: 0x65F0, //CJK UNIFIED IDEOGRAPH + 0xCAF9: 0x65F4, //CJK UNIFIED IDEOGRAPH + 0xCAFA: 0x65F3, //CJK UNIFIED IDEOGRAPH + 0xCAFB: 0x65F2, //CJK UNIFIED IDEOGRAPH + 0xCAFC: 0x65F5, //CJK UNIFIED IDEOGRAPH + 0xCAFD: 0x6745, //CJK UNIFIED IDEOGRAPH + 0xCAFE: 0x6747, //CJK UNIFIED IDEOGRAPH + 0xCB40: 0x6759, //CJK UNIFIED IDEOGRAPH + 0xCB41: 0x6755, //CJK UNIFIED IDEOGRAPH + 0xCB42: 0x674C, //CJK UNIFIED IDEOGRAPH + 0xCB43: 0x6748, //CJK UNIFIED IDEOGRAPH + 0xCB44: 0x675D, //CJK UNIFIED IDEOGRAPH + 0xCB45: 0x674D, //CJK UNIFIED IDEOGRAPH + 0xCB46: 0x675A, //CJK UNIFIED IDEOGRAPH + 0xCB47: 0x674B, //CJK UNIFIED IDEOGRAPH + 0xCB48: 0x6BD0, //CJK UNIFIED IDEOGRAPH + 0xCB49: 0x6C19, //CJK UNIFIED IDEOGRAPH + 0xCB4A: 0x6C1A, //CJK UNIFIED IDEOGRAPH + 0xCB4B: 0x6C78, //CJK UNIFIED IDEOGRAPH + 0xCB4C: 0x6C67, //CJK UNIFIED IDEOGRAPH + 0xCB4D: 0x6C6B, //CJK UNIFIED IDEOGRAPH + 0xCB4E: 0x6C84, //CJK UNIFIED IDEOGRAPH + 0xCB4F: 0x6C8B, //CJK UNIFIED IDEOGRAPH + 0xCB50: 0x6C8F, //CJK UNIFIED IDEOGRAPH + 0xCB51: 0x6C71, //CJK UNIFIED IDEOGRAPH + 0xCB52: 0x6C6F, //CJK UNIFIED IDEOGRAPH + 0xCB53: 0x6C69, //CJK UNIFIED IDEOGRAPH + 0xCB54: 0x6C9A, //CJK UNIFIED IDEOGRAPH + 0xCB55: 0x6C6D, //CJK UNIFIED IDEOGRAPH + 0xCB56: 0x6C87, //CJK UNIFIED IDEOGRAPH + 0xCB57: 0x6C95, //CJK UNIFIED IDEOGRAPH + 0xCB58: 0x6C9C, //CJK UNIFIED IDEOGRAPH + 0xCB59: 0x6C66, //CJK UNIFIED IDEOGRAPH + 0xCB5A: 0x6C73, //CJK UNIFIED IDEOGRAPH + 0xCB5B: 0x6C65, //CJK UNIFIED IDEOGRAPH + 0xCB5C: 0x6C7B, //CJK UNIFIED IDEOGRAPH + 0xCB5D: 0x6C8E, //CJK UNIFIED IDEOGRAPH + 0xCB5E: 0x7074, //CJK UNIFIED IDEOGRAPH + 0xCB5F: 0x707A, //CJK UNIFIED IDEOGRAPH + 0xCB60: 0x7263, //CJK UNIFIED IDEOGRAPH + 0xCB61: 0x72BF, //CJK UNIFIED IDEOGRAPH + 0xCB62: 0x72BD, //CJK UNIFIED IDEOGRAPH + 0xCB63: 0x72C3, //CJK UNIFIED IDEOGRAPH + 0xCB64: 0x72C6, //CJK UNIFIED IDEOGRAPH + 0xCB65: 0x72C1, //CJK UNIFIED IDEOGRAPH + 0xCB66: 0x72BA, //CJK UNIFIED IDEOGRAPH + 0xCB67: 0x72C5, //CJK UNIFIED IDEOGRAPH + 0xCB68: 0x7395, //CJK UNIFIED IDEOGRAPH + 0xCB69: 0x7397, //CJK UNIFIED IDEOGRAPH + 0xCB6A: 0x7393, //CJK UNIFIED IDEOGRAPH + 0xCB6B: 0x7394, //CJK UNIFIED IDEOGRAPH + 0xCB6C: 0x7392, //CJK UNIFIED IDEOGRAPH + 0xCB6D: 0x753A, //CJK UNIFIED IDEOGRAPH + 0xCB6E: 0x7539, //CJK UNIFIED IDEOGRAPH + 0xCB6F: 0x7594, //CJK UNIFIED IDEOGRAPH + 0xCB70: 0x7595, //CJK UNIFIED IDEOGRAPH + 0xCB71: 0x7681, //CJK UNIFIED IDEOGRAPH + 0xCB72: 0x793D, //CJK UNIFIED IDEOGRAPH + 0xCB73: 0x8034, //CJK UNIFIED IDEOGRAPH + 0xCB74: 0x8095, //CJK UNIFIED IDEOGRAPH + 0xCB75: 0x8099, //CJK UNIFIED IDEOGRAPH + 0xCB76: 0x8090, //CJK UNIFIED IDEOGRAPH + 0xCB77: 0x8092, //CJK UNIFIED IDEOGRAPH + 0xCB78: 0x809C, //CJK UNIFIED IDEOGRAPH + 0xCB79: 0x8290, //CJK UNIFIED IDEOGRAPH + 0xCB7A: 0x828F, //CJK UNIFIED IDEOGRAPH + 0xCB7B: 0x8285, //CJK UNIFIED IDEOGRAPH + 0xCB7C: 0x828E, //CJK UNIFIED IDEOGRAPH + 0xCB7D: 0x8291, //CJK UNIFIED IDEOGRAPH + 0xCB7E: 0x8293, //CJK UNIFIED IDEOGRAPH + 0xCBA1: 0x828A, //CJK UNIFIED IDEOGRAPH + 0xCBA2: 0x8283, //CJK UNIFIED IDEOGRAPH + 0xCBA3: 0x8284, //CJK UNIFIED IDEOGRAPH + 0xCBA4: 0x8C78, //CJK UNIFIED IDEOGRAPH + 0xCBA5: 0x8FC9, //CJK UNIFIED IDEOGRAPH + 0xCBA6: 0x8FBF, //CJK UNIFIED IDEOGRAPH + 0xCBA7: 0x909F, //CJK UNIFIED IDEOGRAPH + 0xCBA8: 0x90A1, //CJK UNIFIED IDEOGRAPH + 0xCBA9: 0x90A5, //CJK UNIFIED IDEOGRAPH + 0xCBAA: 0x909E, //CJK UNIFIED IDEOGRAPH + 0xCBAB: 0x90A7, //CJK UNIFIED IDEOGRAPH + 0xCBAC: 0x90A0, //CJK UNIFIED IDEOGRAPH + 0xCBAD: 0x9630, //CJK UNIFIED IDEOGRAPH + 0xCBAE: 0x9628, //CJK UNIFIED IDEOGRAPH + 0xCBAF: 0x962F, //CJK UNIFIED IDEOGRAPH + 0xCBB0: 0x962D, //CJK UNIFIED IDEOGRAPH + 0xCBB1: 0x4E33, //CJK UNIFIED IDEOGRAPH + 0xCBB2: 0x4F98, //CJK UNIFIED IDEOGRAPH + 0xCBB3: 0x4F7C, //CJK UNIFIED IDEOGRAPH + 0xCBB4: 0x4F85, //CJK UNIFIED IDEOGRAPH + 0xCBB5: 0x4F7D, //CJK UNIFIED IDEOGRAPH + 0xCBB6: 0x4F80, //CJK UNIFIED IDEOGRAPH + 0xCBB7: 0x4F87, //CJK UNIFIED IDEOGRAPH + 0xCBB8: 0x4F76, //CJK UNIFIED IDEOGRAPH + 0xCBB9: 0x4F74, //CJK UNIFIED IDEOGRAPH + 0xCBBA: 0x4F89, //CJK UNIFIED IDEOGRAPH + 0xCBBB: 0x4F84, //CJK UNIFIED IDEOGRAPH + 0xCBBC: 0x4F77, //CJK UNIFIED IDEOGRAPH + 0xCBBD: 0x4F4C, //CJK UNIFIED IDEOGRAPH + 0xCBBE: 0x4F97, //CJK UNIFIED IDEOGRAPH + 0xCBBF: 0x4F6A, //CJK UNIFIED IDEOGRAPH + 0xCBC0: 0x4F9A, //CJK UNIFIED IDEOGRAPH + 0xCBC1: 0x4F79, //CJK UNIFIED IDEOGRAPH + 0xCBC2: 0x4F81, //CJK UNIFIED IDEOGRAPH + 0xCBC3: 0x4F78, //CJK UNIFIED IDEOGRAPH + 0xCBC4: 0x4F90, //CJK UNIFIED IDEOGRAPH + 0xCBC5: 0x4F9C, //CJK UNIFIED IDEOGRAPH + 0xCBC6: 0x4F94, //CJK UNIFIED IDEOGRAPH + 0xCBC7: 0x4F9E, //CJK UNIFIED IDEOGRAPH + 0xCBC8: 0x4F92, //CJK UNIFIED IDEOGRAPH + 0xCBC9: 0x4F82, //CJK UNIFIED IDEOGRAPH + 0xCBCA: 0x4F95, //CJK UNIFIED IDEOGRAPH + 0xCBCB: 0x4F6B, //CJK UNIFIED IDEOGRAPH + 0xCBCC: 0x4F6E, //CJK UNIFIED IDEOGRAPH + 0xCBCD: 0x519E, //CJK UNIFIED IDEOGRAPH + 0xCBCE: 0x51BC, //CJK UNIFIED IDEOGRAPH + 0xCBCF: 0x51BE, //CJK UNIFIED IDEOGRAPH + 0xCBD0: 0x5235, //CJK UNIFIED IDEOGRAPH + 0xCBD1: 0x5232, //CJK UNIFIED IDEOGRAPH + 0xCBD2: 0x5233, //CJK UNIFIED IDEOGRAPH + 0xCBD3: 0x5246, //CJK UNIFIED IDEOGRAPH + 0xCBD4: 0x5231, //CJK UNIFIED IDEOGRAPH + 0xCBD5: 0x52BC, //CJK UNIFIED IDEOGRAPH + 0xCBD6: 0x530A, //CJK UNIFIED IDEOGRAPH + 0xCBD7: 0x530B, //CJK UNIFIED IDEOGRAPH + 0xCBD8: 0x533C, //CJK UNIFIED IDEOGRAPH + 0xCBD9: 0x5392, //CJK UNIFIED IDEOGRAPH + 0xCBDA: 0x5394, //CJK UNIFIED IDEOGRAPH + 0xCBDB: 0x5487, //CJK UNIFIED IDEOGRAPH + 0xCBDC: 0x547F, //CJK UNIFIED IDEOGRAPH + 0xCBDD: 0x5481, //CJK UNIFIED IDEOGRAPH + 0xCBDE: 0x5491, //CJK UNIFIED IDEOGRAPH + 0xCBDF: 0x5482, //CJK UNIFIED IDEOGRAPH + 0xCBE0: 0x5488, //CJK UNIFIED IDEOGRAPH + 0xCBE1: 0x546B, //CJK UNIFIED IDEOGRAPH + 0xCBE2: 0x547A, //CJK UNIFIED IDEOGRAPH + 0xCBE3: 0x547E, //CJK UNIFIED IDEOGRAPH + 0xCBE4: 0x5465, //CJK UNIFIED IDEOGRAPH + 0xCBE5: 0x546C, //CJK UNIFIED IDEOGRAPH + 0xCBE6: 0x5474, //CJK UNIFIED IDEOGRAPH + 0xCBE7: 0x5466, //CJK UNIFIED IDEOGRAPH + 0xCBE8: 0x548D, //CJK UNIFIED IDEOGRAPH + 0xCBE9: 0x546F, //CJK UNIFIED IDEOGRAPH + 0xCBEA: 0x5461, //CJK UNIFIED IDEOGRAPH + 0xCBEB: 0x5460, //CJK UNIFIED IDEOGRAPH + 0xCBEC: 0x5498, //CJK UNIFIED IDEOGRAPH + 0xCBED: 0x5463, //CJK UNIFIED IDEOGRAPH + 0xCBEE: 0x5467, //CJK UNIFIED IDEOGRAPH + 0xCBEF: 0x5464, //CJK UNIFIED IDEOGRAPH + 0xCBF0: 0x56F7, //CJK UNIFIED IDEOGRAPH + 0xCBF1: 0x56F9, //CJK UNIFIED IDEOGRAPH + 0xCBF2: 0x576F, //CJK UNIFIED IDEOGRAPH + 0xCBF3: 0x5772, //CJK UNIFIED IDEOGRAPH + 0xCBF4: 0x576D, //CJK UNIFIED IDEOGRAPH + 0xCBF5: 0x576B, //CJK UNIFIED IDEOGRAPH + 0xCBF6: 0x5771, //CJK UNIFIED IDEOGRAPH + 0xCBF7: 0x5770, //CJK UNIFIED IDEOGRAPH + 0xCBF8: 0x5776, //CJK UNIFIED IDEOGRAPH + 0xCBF9: 0x5780, //CJK UNIFIED IDEOGRAPH + 0xCBFA: 0x5775, //CJK UNIFIED IDEOGRAPH + 0xCBFB: 0x577B, //CJK UNIFIED IDEOGRAPH + 0xCBFC: 0x5773, //CJK UNIFIED IDEOGRAPH + 0xCBFD: 0x5774, //CJK UNIFIED IDEOGRAPH + 0xCBFE: 0x5762, //CJK UNIFIED IDEOGRAPH + 0xCC40: 0x5768, //CJK UNIFIED IDEOGRAPH + 0xCC41: 0x577D, //CJK UNIFIED IDEOGRAPH + 0xCC42: 0x590C, //CJK UNIFIED IDEOGRAPH + 0xCC43: 0x5945, //CJK UNIFIED IDEOGRAPH + 0xCC44: 0x59B5, //CJK UNIFIED IDEOGRAPH + 0xCC45: 0x59BA, //CJK UNIFIED IDEOGRAPH + 0xCC46: 0x59CF, //CJK UNIFIED IDEOGRAPH + 0xCC47: 0x59CE, //CJK UNIFIED IDEOGRAPH + 0xCC48: 0x59B2, //CJK UNIFIED IDEOGRAPH + 0xCC49: 0x59CC, //CJK UNIFIED IDEOGRAPH + 0xCC4A: 0x59C1, //CJK UNIFIED IDEOGRAPH + 0xCC4B: 0x59B6, //CJK UNIFIED IDEOGRAPH + 0xCC4C: 0x59BC, //CJK UNIFIED IDEOGRAPH + 0xCC4D: 0x59C3, //CJK UNIFIED IDEOGRAPH + 0xCC4E: 0x59D6, //CJK UNIFIED IDEOGRAPH + 0xCC4F: 0x59B1, //CJK UNIFIED IDEOGRAPH + 0xCC50: 0x59BD, //CJK UNIFIED IDEOGRAPH + 0xCC51: 0x59C0, //CJK UNIFIED IDEOGRAPH + 0xCC52: 0x59C8, //CJK UNIFIED IDEOGRAPH + 0xCC53: 0x59B4, //CJK UNIFIED IDEOGRAPH + 0xCC54: 0x59C7, //CJK UNIFIED IDEOGRAPH + 0xCC55: 0x5B62, //CJK UNIFIED IDEOGRAPH + 0xCC56: 0x5B65, //CJK UNIFIED IDEOGRAPH + 0xCC57: 0x5B93, //CJK UNIFIED IDEOGRAPH + 0xCC58: 0x5B95, //CJK UNIFIED IDEOGRAPH + 0xCC59: 0x5C44, //CJK UNIFIED IDEOGRAPH + 0xCC5A: 0x5C47, //CJK UNIFIED IDEOGRAPH + 0xCC5B: 0x5CAE, //CJK UNIFIED IDEOGRAPH + 0xCC5C: 0x5CA4, //CJK UNIFIED IDEOGRAPH + 0xCC5D: 0x5CA0, //CJK UNIFIED IDEOGRAPH + 0xCC5E: 0x5CB5, //CJK UNIFIED IDEOGRAPH + 0xCC5F: 0x5CAF, //CJK UNIFIED IDEOGRAPH + 0xCC60: 0x5CA8, //CJK UNIFIED IDEOGRAPH + 0xCC61: 0x5CAC, //CJK UNIFIED IDEOGRAPH + 0xCC62: 0x5C9F, //CJK UNIFIED IDEOGRAPH + 0xCC63: 0x5CA3, //CJK UNIFIED IDEOGRAPH + 0xCC64: 0x5CAD, //CJK UNIFIED IDEOGRAPH + 0xCC65: 0x5CA2, //CJK UNIFIED IDEOGRAPH + 0xCC66: 0x5CAA, //CJK UNIFIED IDEOGRAPH + 0xCC67: 0x5CA7, //CJK UNIFIED IDEOGRAPH + 0xCC68: 0x5C9D, //CJK UNIFIED IDEOGRAPH + 0xCC69: 0x5CA5, //CJK UNIFIED IDEOGRAPH + 0xCC6A: 0x5CB6, //CJK UNIFIED IDEOGRAPH + 0xCC6B: 0x5CB0, //CJK UNIFIED IDEOGRAPH + 0xCC6C: 0x5CA6, //CJK UNIFIED IDEOGRAPH + 0xCC6D: 0x5E17, //CJK UNIFIED IDEOGRAPH + 0xCC6E: 0x5E14, //CJK UNIFIED IDEOGRAPH + 0xCC6F: 0x5E19, //CJK UNIFIED IDEOGRAPH + 0xCC70: 0x5F28, //CJK UNIFIED IDEOGRAPH + 0xCC71: 0x5F22, //CJK UNIFIED IDEOGRAPH + 0xCC72: 0x5F23, //CJK UNIFIED IDEOGRAPH + 0xCC73: 0x5F24, //CJK UNIFIED IDEOGRAPH + 0xCC74: 0x5F54, //CJK UNIFIED IDEOGRAPH + 0xCC75: 0x5F82, //CJK UNIFIED IDEOGRAPH + 0xCC76: 0x5F7E, //CJK UNIFIED IDEOGRAPH + 0xCC77: 0x5F7D, //CJK UNIFIED IDEOGRAPH + 0xCC78: 0x5FDE, //CJK UNIFIED IDEOGRAPH + 0xCC79: 0x5FE5, //CJK UNIFIED IDEOGRAPH + 0xCC7A: 0x602D, //CJK UNIFIED IDEOGRAPH + 0xCC7B: 0x6026, //CJK UNIFIED IDEOGRAPH + 0xCC7C: 0x6019, //CJK UNIFIED IDEOGRAPH + 0xCC7D: 0x6032, //CJK UNIFIED IDEOGRAPH + 0xCC7E: 0x600B, //CJK UNIFIED IDEOGRAPH + 0xCCA1: 0x6034, //CJK UNIFIED IDEOGRAPH + 0xCCA2: 0x600A, //CJK UNIFIED IDEOGRAPH + 0xCCA3: 0x6017, //CJK UNIFIED IDEOGRAPH + 0xCCA4: 0x6033, //CJK UNIFIED IDEOGRAPH + 0xCCA5: 0x601A, //CJK UNIFIED IDEOGRAPH + 0xCCA6: 0x601E, //CJK UNIFIED IDEOGRAPH + 0xCCA7: 0x602C, //CJK UNIFIED IDEOGRAPH + 0xCCA8: 0x6022, //CJK UNIFIED IDEOGRAPH + 0xCCA9: 0x600D, //CJK UNIFIED IDEOGRAPH + 0xCCAA: 0x6010, //CJK UNIFIED IDEOGRAPH + 0xCCAB: 0x602E, //CJK UNIFIED IDEOGRAPH + 0xCCAC: 0x6013, //CJK UNIFIED IDEOGRAPH + 0xCCAD: 0x6011, //CJK UNIFIED IDEOGRAPH + 0xCCAE: 0x600C, //CJK UNIFIED IDEOGRAPH + 0xCCAF: 0x6009, //CJK UNIFIED IDEOGRAPH + 0xCCB0: 0x601C, //CJK UNIFIED IDEOGRAPH + 0xCCB1: 0x6214, //CJK UNIFIED IDEOGRAPH + 0xCCB2: 0x623D, //CJK UNIFIED IDEOGRAPH + 0xCCB3: 0x62AD, //CJK UNIFIED IDEOGRAPH + 0xCCB4: 0x62B4, //CJK UNIFIED IDEOGRAPH + 0xCCB5: 0x62D1, //CJK UNIFIED IDEOGRAPH + 0xCCB6: 0x62BE, //CJK UNIFIED IDEOGRAPH + 0xCCB7: 0x62AA, //CJK UNIFIED IDEOGRAPH + 0xCCB8: 0x62B6, //CJK UNIFIED IDEOGRAPH + 0xCCB9: 0x62CA, //CJK UNIFIED IDEOGRAPH + 0xCCBA: 0x62AE, //CJK UNIFIED IDEOGRAPH + 0xCCBB: 0x62B3, //CJK UNIFIED IDEOGRAPH + 0xCCBC: 0x62AF, //CJK UNIFIED IDEOGRAPH + 0xCCBD: 0x62BB, //CJK UNIFIED IDEOGRAPH + 0xCCBE: 0x62A9, //CJK UNIFIED IDEOGRAPH + 0xCCBF: 0x62B0, //CJK UNIFIED IDEOGRAPH + 0xCCC0: 0x62B8, //CJK UNIFIED IDEOGRAPH + 0xCCC1: 0x653D, //CJK UNIFIED IDEOGRAPH + 0xCCC2: 0x65A8, //CJK UNIFIED IDEOGRAPH + 0xCCC3: 0x65BB, //CJK UNIFIED IDEOGRAPH + 0xCCC4: 0x6609, //CJK UNIFIED IDEOGRAPH + 0xCCC5: 0x65FC, //CJK UNIFIED IDEOGRAPH + 0xCCC6: 0x6604, //CJK UNIFIED IDEOGRAPH + 0xCCC7: 0x6612, //CJK UNIFIED IDEOGRAPH + 0xCCC8: 0x6608, //CJK UNIFIED IDEOGRAPH + 0xCCC9: 0x65FB, //CJK UNIFIED IDEOGRAPH + 0xCCCA: 0x6603, //CJK UNIFIED IDEOGRAPH + 0xCCCB: 0x660B, //CJK UNIFIED IDEOGRAPH + 0xCCCC: 0x660D, //CJK UNIFIED IDEOGRAPH + 0xCCCD: 0x6605, //CJK UNIFIED IDEOGRAPH + 0xCCCE: 0x65FD, //CJK UNIFIED IDEOGRAPH + 0xCCCF: 0x6611, //CJK UNIFIED IDEOGRAPH + 0xCCD0: 0x6610, //CJK UNIFIED IDEOGRAPH + 0xCCD1: 0x66F6, //CJK UNIFIED IDEOGRAPH + 0xCCD2: 0x670A, //CJK UNIFIED IDEOGRAPH + 0xCCD3: 0x6785, //CJK UNIFIED IDEOGRAPH + 0xCCD4: 0x676C, //CJK UNIFIED IDEOGRAPH + 0xCCD5: 0x678E, //CJK UNIFIED IDEOGRAPH + 0xCCD6: 0x6792, //CJK UNIFIED IDEOGRAPH + 0xCCD7: 0x6776, //CJK UNIFIED IDEOGRAPH + 0xCCD8: 0x677B, //CJK UNIFIED IDEOGRAPH + 0xCCD9: 0x6798, //CJK UNIFIED IDEOGRAPH + 0xCCDA: 0x6786, //CJK UNIFIED IDEOGRAPH + 0xCCDB: 0x6784, //CJK UNIFIED IDEOGRAPH + 0xCCDC: 0x6774, //CJK UNIFIED IDEOGRAPH + 0xCCDD: 0x678D, //CJK UNIFIED IDEOGRAPH + 0xCCDE: 0x678C, //CJK UNIFIED IDEOGRAPH + 0xCCDF: 0x677A, //CJK UNIFIED IDEOGRAPH + 0xCCE0: 0x679F, //CJK UNIFIED IDEOGRAPH + 0xCCE1: 0x6791, //CJK UNIFIED IDEOGRAPH + 0xCCE2: 0x6799, //CJK UNIFIED IDEOGRAPH + 0xCCE3: 0x6783, //CJK UNIFIED IDEOGRAPH + 0xCCE4: 0x677D, //CJK UNIFIED IDEOGRAPH + 0xCCE5: 0x6781, //CJK UNIFIED IDEOGRAPH + 0xCCE6: 0x6778, //CJK UNIFIED IDEOGRAPH + 0xCCE7: 0x6779, //CJK UNIFIED IDEOGRAPH + 0xCCE8: 0x6794, //CJK UNIFIED IDEOGRAPH + 0xCCE9: 0x6B25, //CJK UNIFIED IDEOGRAPH + 0xCCEA: 0x6B80, //CJK UNIFIED IDEOGRAPH + 0xCCEB: 0x6B7E, //CJK UNIFIED IDEOGRAPH + 0xCCEC: 0x6BDE, //CJK UNIFIED IDEOGRAPH + 0xCCED: 0x6C1D, //CJK UNIFIED IDEOGRAPH + 0xCCEE: 0x6C93, //CJK UNIFIED IDEOGRAPH + 0xCCEF: 0x6CEC, //CJK UNIFIED IDEOGRAPH + 0xCCF0: 0x6CEB, //CJK UNIFIED IDEOGRAPH + 0xCCF1: 0x6CEE, //CJK UNIFIED IDEOGRAPH + 0xCCF2: 0x6CD9, //CJK UNIFIED IDEOGRAPH + 0xCCF3: 0x6CB6, //CJK UNIFIED IDEOGRAPH + 0xCCF4: 0x6CD4, //CJK UNIFIED IDEOGRAPH + 0xCCF5: 0x6CAD, //CJK UNIFIED IDEOGRAPH + 0xCCF6: 0x6CE7, //CJK UNIFIED IDEOGRAPH + 0xCCF7: 0x6CB7, //CJK UNIFIED IDEOGRAPH + 0xCCF8: 0x6CD0, //CJK UNIFIED IDEOGRAPH + 0xCCF9: 0x6CC2, //CJK UNIFIED IDEOGRAPH + 0xCCFA: 0x6CBA, //CJK UNIFIED IDEOGRAPH + 0xCCFB: 0x6CC3, //CJK UNIFIED IDEOGRAPH + 0xCCFC: 0x6CC6, //CJK UNIFIED IDEOGRAPH + 0xCCFD: 0x6CED, //CJK UNIFIED IDEOGRAPH + 0xCCFE: 0x6CF2, //CJK UNIFIED IDEOGRAPH + 0xCD40: 0x6CD2, //CJK UNIFIED IDEOGRAPH + 0xCD41: 0x6CDD, //CJK UNIFIED IDEOGRAPH + 0xCD42: 0x6CB4, //CJK UNIFIED IDEOGRAPH + 0xCD43: 0x6C8A, //CJK UNIFIED IDEOGRAPH + 0xCD44: 0x6C9D, //CJK UNIFIED IDEOGRAPH + 0xCD45: 0x6C80, //CJK UNIFIED IDEOGRAPH + 0xCD46: 0x6CDE, //CJK UNIFIED IDEOGRAPH + 0xCD47: 0x6CC0, //CJK UNIFIED IDEOGRAPH + 0xCD48: 0x6D30, //CJK UNIFIED IDEOGRAPH + 0xCD49: 0x6CCD, //CJK UNIFIED IDEOGRAPH + 0xCD4A: 0x6CC7, //CJK UNIFIED IDEOGRAPH + 0xCD4B: 0x6CB0, //CJK UNIFIED IDEOGRAPH + 0xCD4C: 0x6CF9, //CJK UNIFIED IDEOGRAPH + 0xCD4D: 0x6CCF, //CJK UNIFIED IDEOGRAPH + 0xCD4E: 0x6CE9, //CJK UNIFIED IDEOGRAPH + 0xCD4F: 0x6CD1, //CJK UNIFIED IDEOGRAPH + 0xCD50: 0x7094, //CJK UNIFIED IDEOGRAPH + 0xCD51: 0x7098, //CJK UNIFIED IDEOGRAPH + 0xCD52: 0x7085, //CJK UNIFIED IDEOGRAPH + 0xCD53: 0x7093, //CJK UNIFIED IDEOGRAPH + 0xCD54: 0x7086, //CJK UNIFIED IDEOGRAPH + 0xCD55: 0x7084, //CJK UNIFIED IDEOGRAPH + 0xCD56: 0x7091, //CJK UNIFIED IDEOGRAPH + 0xCD57: 0x7096, //CJK UNIFIED IDEOGRAPH + 0xCD58: 0x7082, //CJK UNIFIED IDEOGRAPH + 0xCD59: 0x709A, //CJK UNIFIED IDEOGRAPH + 0xCD5A: 0x7083, //CJK UNIFIED IDEOGRAPH + 0xCD5B: 0x726A, //CJK UNIFIED IDEOGRAPH + 0xCD5C: 0x72D6, //CJK UNIFIED IDEOGRAPH + 0xCD5D: 0x72CB, //CJK UNIFIED IDEOGRAPH + 0xCD5E: 0x72D8, //CJK UNIFIED IDEOGRAPH + 0xCD5F: 0x72C9, //CJK UNIFIED IDEOGRAPH + 0xCD60: 0x72DC, //CJK UNIFIED IDEOGRAPH + 0xCD61: 0x72D2, //CJK UNIFIED IDEOGRAPH + 0xCD62: 0x72D4, //CJK UNIFIED IDEOGRAPH + 0xCD63: 0x72DA, //CJK UNIFIED IDEOGRAPH + 0xCD64: 0x72CC, //CJK UNIFIED IDEOGRAPH + 0xCD65: 0x72D1, //CJK UNIFIED IDEOGRAPH + 0xCD66: 0x73A4, //CJK UNIFIED IDEOGRAPH + 0xCD67: 0x73A1, //CJK UNIFIED IDEOGRAPH + 0xCD68: 0x73AD, //CJK UNIFIED IDEOGRAPH + 0xCD69: 0x73A6, //CJK UNIFIED IDEOGRAPH + 0xCD6A: 0x73A2, //CJK UNIFIED IDEOGRAPH + 0xCD6B: 0x73A0, //CJK UNIFIED IDEOGRAPH + 0xCD6C: 0x73AC, //CJK UNIFIED IDEOGRAPH + 0xCD6D: 0x739D, //CJK UNIFIED IDEOGRAPH + 0xCD6E: 0x74DD, //CJK UNIFIED IDEOGRAPH + 0xCD6F: 0x74E8, //CJK UNIFIED IDEOGRAPH + 0xCD70: 0x753F, //CJK UNIFIED IDEOGRAPH + 0xCD71: 0x7540, //CJK UNIFIED IDEOGRAPH + 0xCD72: 0x753E, //CJK UNIFIED IDEOGRAPH + 0xCD73: 0x758C, //CJK UNIFIED IDEOGRAPH + 0xCD74: 0x7598, //CJK UNIFIED IDEOGRAPH + 0xCD75: 0x76AF, //CJK UNIFIED IDEOGRAPH + 0xCD76: 0x76F3, //CJK UNIFIED IDEOGRAPH + 0xCD77: 0x76F1, //CJK UNIFIED IDEOGRAPH + 0xCD78: 0x76F0, //CJK UNIFIED IDEOGRAPH + 0xCD79: 0x76F5, //CJK UNIFIED IDEOGRAPH + 0xCD7A: 0x77F8, //CJK UNIFIED IDEOGRAPH + 0xCD7B: 0x77FC, //CJK UNIFIED IDEOGRAPH + 0xCD7C: 0x77F9, //CJK UNIFIED IDEOGRAPH + 0xCD7D: 0x77FB, //CJK UNIFIED IDEOGRAPH + 0xCD7E: 0x77FA, //CJK UNIFIED IDEOGRAPH + 0xCDA1: 0x77F7, //CJK UNIFIED IDEOGRAPH + 0xCDA2: 0x7942, //CJK UNIFIED IDEOGRAPH + 0xCDA3: 0x793F, //CJK UNIFIED IDEOGRAPH + 0xCDA4: 0x79C5, //CJK UNIFIED IDEOGRAPH + 0xCDA5: 0x7A78, //CJK UNIFIED IDEOGRAPH + 0xCDA6: 0x7A7B, //CJK UNIFIED IDEOGRAPH + 0xCDA7: 0x7AFB, //CJK UNIFIED IDEOGRAPH + 0xCDA8: 0x7C75, //CJK UNIFIED IDEOGRAPH + 0xCDA9: 0x7CFD, //CJK UNIFIED IDEOGRAPH + 0xCDAA: 0x8035, //CJK UNIFIED IDEOGRAPH + 0xCDAB: 0x808F, //CJK UNIFIED IDEOGRAPH + 0xCDAC: 0x80AE, //CJK UNIFIED IDEOGRAPH + 0xCDAD: 0x80A3, //CJK UNIFIED IDEOGRAPH + 0xCDAE: 0x80B8, //CJK UNIFIED IDEOGRAPH + 0xCDAF: 0x80B5, //CJK UNIFIED IDEOGRAPH + 0xCDB0: 0x80AD, //CJK UNIFIED IDEOGRAPH + 0xCDB1: 0x8220, //CJK UNIFIED IDEOGRAPH + 0xCDB2: 0x82A0, //CJK UNIFIED IDEOGRAPH + 0xCDB3: 0x82C0, //CJK UNIFIED IDEOGRAPH + 0xCDB4: 0x82AB, //CJK UNIFIED IDEOGRAPH + 0xCDB5: 0x829A, //CJK UNIFIED IDEOGRAPH + 0xCDB6: 0x8298, //CJK UNIFIED IDEOGRAPH + 0xCDB7: 0x829B, //CJK UNIFIED IDEOGRAPH + 0xCDB8: 0x82B5, //CJK UNIFIED IDEOGRAPH + 0xCDB9: 0x82A7, //CJK UNIFIED IDEOGRAPH + 0xCDBA: 0x82AE, //CJK UNIFIED IDEOGRAPH + 0xCDBB: 0x82BC, //CJK UNIFIED IDEOGRAPH + 0xCDBC: 0x829E, //CJK UNIFIED IDEOGRAPH + 0xCDBD: 0x82BA, //CJK UNIFIED IDEOGRAPH + 0xCDBE: 0x82B4, //CJK UNIFIED IDEOGRAPH + 0xCDBF: 0x82A8, //CJK UNIFIED IDEOGRAPH + 0xCDC0: 0x82A1, //CJK UNIFIED IDEOGRAPH + 0xCDC1: 0x82A9, //CJK UNIFIED IDEOGRAPH + 0xCDC2: 0x82C2, //CJK UNIFIED IDEOGRAPH + 0xCDC3: 0x82A4, //CJK UNIFIED IDEOGRAPH + 0xCDC4: 0x82C3, //CJK UNIFIED IDEOGRAPH + 0xCDC5: 0x82B6, //CJK UNIFIED IDEOGRAPH + 0xCDC6: 0x82A2, //CJK UNIFIED IDEOGRAPH + 0xCDC7: 0x8670, //CJK UNIFIED IDEOGRAPH + 0xCDC8: 0x866F, //CJK UNIFIED IDEOGRAPH + 0xCDC9: 0x866D, //CJK UNIFIED IDEOGRAPH + 0xCDCA: 0x866E, //CJK UNIFIED IDEOGRAPH + 0xCDCB: 0x8C56, //CJK UNIFIED IDEOGRAPH + 0xCDCC: 0x8FD2, //CJK UNIFIED IDEOGRAPH + 0xCDCD: 0x8FCB, //CJK UNIFIED IDEOGRAPH + 0xCDCE: 0x8FD3, //CJK UNIFIED IDEOGRAPH + 0xCDCF: 0x8FCD, //CJK UNIFIED IDEOGRAPH + 0xCDD0: 0x8FD6, //CJK UNIFIED IDEOGRAPH + 0xCDD1: 0x8FD5, //CJK UNIFIED IDEOGRAPH + 0xCDD2: 0x8FD7, //CJK UNIFIED IDEOGRAPH + 0xCDD3: 0x90B2, //CJK UNIFIED IDEOGRAPH + 0xCDD4: 0x90B4, //CJK UNIFIED IDEOGRAPH + 0xCDD5: 0x90AF, //CJK UNIFIED IDEOGRAPH + 0xCDD6: 0x90B3, //CJK UNIFIED IDEOGRAPH + 0xCDD7: 0x90B0, //CJK UNIFIED IDEOGRAPH + 0xCDD8: 0x9639, //CJK UNIFIED IDEOGRAPH + 0xCDD9: 0x963D, //CJK UNIFIED IDEOGRAPH + 0xCDDA: 0x963C, //CJK UNIFIED IDEOGRAPH + 0xCDDB: 0x963A, //CJK UNIFIED IDEOGRAPH + 0xCDDC: 0x9643, //CJK UNIFIED IDEOGRAPH + 0xCDDD: 0x4FCD, //CJK UNIFIED IDEOGRAPH + 0xCDDE: 0x4FC5, //CJK UNIFIED IDEOGRAPH + 0xCDDF: 0x4FD3, //CJK UNIFIED IDEOGRAPH + 0xCDE0: 0x4FB2, //CJK UNIFIED IDEOGRAPH + 0xCDE1: 0x4FC9, //CJK UNIFIED IDEOGRAPH + 0xCDE2: 0x4FCB, //CJK UNIFIED IDEOGRAPH + 0xCDE3: 0x4FC1, //CJK UNIFIED IDEOGRAPH + 0xCDE4: 0x4FD4, //CJK UNIFIED IDEOGRAPH + 0xCDE5: 0x4FDC, //CJK UNIFIED IDEOGRAPH + 0xCDE6: 0x4FD9, //CJK UNIFIED IDEOGRAPH + 0xCDE7: 0x4FBB, //CJK UNIFIED IDEOGRAPH + 0xCDE8: 0x4FB3, //CJK UNIFIED IDEOGRAPH + 0xCDE9: 0x4FDB, //CJK UNIFIED IDEOGRAPH + 0xCDEA: 0x4FC7, //CJK UNIFIED IDEOGRAPH + 0xCDEB: 0x4FD6, //CJK UNIFIED IDEOGRAPH + 0xCDEC: 0x4FBA, //CJK UNIFIED IDEOGRAPH + 0xCDED: 0x4FC0, //CJK UNIFIED IDEOGRAPH + 0xCDEE: 0x4FB9, //CJK UNIFIED IDEOGRAPH + 0xCDEF: 0x4FEC, //CJK UNIFIED IDEOGRAPH + 0xCDF0: 0x5244, //CJK UNIFIED IDEOGRAPH + 0xCDF1: 0x5249, //CJK UNIFIED IDEOGRAPH + 0xCDF2: 0x52C0, //CJK UNIFIED IDEOGRAPH + 0xCDF3: 0x52C2, //CJK UNIFIED IDEOGRAPH + 0xCDF4: 0x533D, //CJK UNIFIED IDEOGRAPH + 0xCDF5: 0x537C, //CJK UNIFIED IDEOGRAPH + 0xCDF6: 0x5397, //CJK UNIFIED IDEOGRAPH + 0xCDF7: 0x5396, //CJK UNIFIED IDEOGRAPH + 0xCDF8: 0x5399, //CJK UNIFIED IDEOGRAPH + 0xCDF9: 0x5398, //CJK UNIFIED IDEOGRAPH + 0xCDFA: 0x54BA, //CJK UNIFIED IDEOGRAPH + 0xCDFB: 0x54A1, //CJK UNIFIED IDEOGRAPH + 0xCDFC: 0x54AD, //CJK UNIFIED IDEOGRAPH + 0xCDFD: 0x54A5, //CJK UNIFIED IDEOGRAPH + 0xCDFE: 0x54CF, //CJK UNIFIED IDEOGRAPH + 0xCE40: 0x54C3, //CJK UNIFIED IDEOGRAPH + 0xCE41: 0x830D, //CJK UNIFIED IDEOGRAPH + 0xCE42: 0x54B7, //CJK UNIFIED IDEOGRAPH + 0xCE43: 0x54AE, //CJK UNIFIED IDEOGRAPH + 0xCE44: 0x54D6, //CJK UNIFIED IDEOGRAPH + 0xCE45: 0x54B6, //CJK UNIFIED IDEOGRAPH + 0xCE46: 0x54C5, //CJK UNIFIED IDEOGRAPH + 0xCE47: 0x54C6, //CJK UNIFIED IDEOGRAPH + 0xCE48: 0x54A0, //CJK UNIFIED IDEOGRAPH + 0xCE49: 0x5470, //CJK UNIFIED IDEOGRAPH + 0xCE4A: 0x54BC, //CJK UNIFIED IDEOGRAPH + 0xCE4B: 0x54A2, //CJK UNIFIED IDEOGRAPH + 0xCE4C: 0x54BE, //CJK UNIFIED IDEOGRAPH + 0xCE4D: 0x5472, //CJK UNIFIED IDEOGRAPH + 0xCE4E: 0x54DE, //CJK UNIFIED IDEOGRAPH + 0xCE4F: 0x54B0, //CJK UNIFIED IDEOGRAPH + 0xCE50: 0x57B5, //CJK UNIFIED IDEOGRAPH + 0xCE51: 0x579E, //CJK UNIFIED IDEOGRAPH + 0xCE52: 0x579F, //CJK UNIFIED IDEOGRAPH + 0xCE53: 0x57A4, //CJK UNIFIED IDEOGRAPH + 0xCE54: 0x578C, //CJK UNIFIED IDEOGRAPH + 0xCE55: 0x5797, //CJK UNIFIED IDEOGRAPH + 0xCE56: 0x579D, //CJK UNIFIED IDEOGRAPH + 0xCE57: 0x579B, //CJK UNIFIED IDEOGRAPH + 0xCE58: 0x5794, //CJK UNIFIED IDEOGRAPH + 0xCE59: 0x5798, //CJK UNIFIED IDEOGRAPH + 0xCE5A: 0x578F, //CJK UNIFIED IDEOGRAPH + 0xCE5B: 0x5799, //CJK UNIFIED IDEOGRAPH + 0xCE5C: 0x57A5, //CJK UNIFIED IDEOGRAPH + 0xCE5D: 0x579A, //CJK UNIFIED IDEOGRAPH + 0xCE5E: 0x5795, //CJK UNIFIED IDEOGRAPH + 0xCE5F: 0x58F4, //CJK UNIFIED IDEOGRAPH + 0xCE60: 0x590D, //CJK UNIFIED IDEOGRAPH + 0xCE61: 0x5953, //CJK UNIFIED IDEOGRAPH + 0xCE62: 0x59E1, //CJK UNIFIED IDEOGRAPH + 0xCE63: 0x59DE, //CJK UNIFIED IDEOGRAPH + 0xCE64: 0x59EE, //CJK UNIFIED IDEOGRAPH + 0xCE65: 0x5A00, //CJK UNIFIED IDEOGRAPH + 0xCE66: 0x59F1, //CJK UNIFIED IDEOGRAPH + 0xCE67: 0x59DD, //CJK UNIFIED IDEOGRAPH + 0xCE68: 0x59FA, //CJK UNIFIED IDEOGRAPH + 0xCE69: 0x59FD, //CJK UNIFIED IDEOGRAPH + 0xCE6A: 0x59FC, //CJK UNIFIED IDEOGRAPH + 0xCE6B: 0x59F6, //CJK UNIFIED IDEOGRAPH + 0xCE6C: 0x59E4, //CJK UNIFIED IDEOGRAPH + 0xCE6D: 0x59F2, //CJK UNIFIED IDEOGRAPH + 0xCE6E: 0x59F7, //CJK UNIFIED IDEOGRAPH + 0xCE6F: 0x59DB, //CJK UNIFIED IDEOGRAPH + 0xCE70: 0x59E9, //CJK UNIFIED IDEOGRAPH + 0xCE71: 0x59F3, //CJK UNIFIED IDEOGRAPH + 0xCE72: 0x59F5, //CJK UNIFIED IDEOGRAPH + 0xCE73: 0x59E0, //CJK UNIFIED IDEOGRAPH + 0xCE74: 0x59FE, //CJK UNIFIED IDEOGRAPH + 0xCE75: 0x59F4, //CJK UNIFIED IDEOGRAPH + 0xCE76: 0x59ED, //CJK UNIFIED IDEOGRAPH + 0xCE77: 0x5BA8, //CJK UNIFIED IDEOGRAPH + 0xCE78: 0x5C4C, //CJK UNIFIED IDEOGRAPH + 0xCE79: 0x5CD0, //CJK UNIFIED IDEOGRAPH + 0xCE7A: 0x5CD8, //CJK UNIFIED IDEOGRAPH + 0xCE7B: 0x5CCC, //CJK UNIFIED IDEOGRAPH + 0xCE7C: 0x5CD7, //CJK UNIFIED IDEOGRAPH + 0xCE7D: 0x5CCB, //CJK UNIFIED IDEOGRAPH + 0xCE7E: 0x5CDB, //CJK UNIFIED IDEOGRAPH + 0xCEA1: 0x5CDE, //CJK UNIFIED IDEOGRAPH + 0xCEA2: 0x5CDA, //CJK UNIFIED IDEOGRAPH + 0xCEA3: 0x5CC9, //CJK UNIFIED IDEOGRAPH + 0xCEA4: 0x5CC7, //CJK UNIFIED IDEOGRAPH + 0xCEA5: 0x5CCA, //CJK UNIFIED IDEOGRAPH + 0xCEA6: 0x5CD6, //CJK UNIFIED IDEOGRAPH + 0xCEA7: 0x5CD3, //CJK UNIFIED IDEOGRAPH + 0xCEA8: 0x5CD4, //CJK UNIFIED IDEOGRAPH + 0xCEA9: 0x5CCF, //CJK UNIFIED IDEOGRAPH + 0xCEAA: 0x5CC8, //CJK UNIFIED IDEOGRAPH + 0xCEAB: 0x5CC6, //CJK UNIFIED IDEOGRAPH + 0xCEAC: 0x5CCE, //CJK UNIFIED IDEOGRAPH + 0xCEAD: 0x5CDF, //CJK UNIFIED IDEOGRAPH + 0xCEAE: 0x5CF8, //CJK UNIFIED IDEOGRAPH + 0xCEAF: 0x5DF9, //CJK UNIFIED IDEOGRAPH + 0xCEB0: 0x5E21, //CJK UNIFIED IDEOGRAPH + 0xCEB1: 0x5E22, //CJK UNIFIED IDEOGRAPH + 0xCEB2: 0x5E23, //CJK UNIFIED IDEOGRAPH + 0xCEB3: 0x5E20, //CJK UNIFIED IDEOGRAPH + 0xCEB4: 0x5E24, //CJK UNIFIED IDEOGRAPH + 0xCEB5: 0x5EB0, //CJK UNIFIED IDEOGRAPH + 0xCEB6: 0x5EA4, //CJK UNIFIED IDEOGRAPH + 0xCEB7: 0x5EA2, //CJK UNIFIED IDEOGRAPH + 0xCEB8: 0x5E9B, //CJK UNIFIED IDEOGRAPH + 0xCEB9: 0x5EA3, //CJK UNIFIED IDEOGRAPH + 0xCEBA: 0x5EA5, //CJK UNIFIED IDEOGRAPH + 0xCEBB: 0x5F07, //CJK UNIFIED IDEOGRAPH + 0xCEBC: 0x5F2E, //CJK UNIFIED IDEOGRAPH + 0xCEBD: 0x5F56, //CJK UNIFIED IDEOGRAPH + 0xCEBE: 0x5F86, //CJK UNIFIED IDEOGRAPH + 0xCEBF: 0x6037, //CJK UNIFIED IDEOGRAPH + 0xCEC0: 0x6039, //CJK UNIFIED IDEOGRAPH + 0xCEC1: 0x6054, //CJK UNIFIED IDEOGRAPH + 0xCEC2: 0x6072, //CJK UNIFIED IDEOGRAPH + 0xCEC3: 0x605E, //CJK UNIFIED IDEOGRAPH + 0xCEC4: 0x6045, //CJK UNIFIED IDEOGRAPH + 0xCEC5: 0x6053, //CJK UNIFIED IDEOGRAPH + 0xCEC6: 0x6047, //CJK UNIFIED IDEOGRAPH + 0xCEC7: 0x6049, //CJK UNIFIED IDEOGRAPH + 0xCEC8: 0x605B, //CJK UNIFIED IDEOGRAPH + 0xCEC9: 0x604C, //CJK UNIFIED IDEOGRAPH + 0xCECA: 0x6040, //CJK UNIFIED IDEOGRAPH + 0xCECB: 0x6042, //CJK UNIFIED IDEOGRAPH + 0xCECC: 0x605F, //CJK UNIFIED IDEOGRAPH + 0xCECD: 0x6024, //CJK UNIFIED IDEOGRAPH + 0xCECE: 0x6044, //CJK UNIFIED IDEOGRAPH + 0xCECF: 0x6058, //CJK UNIFIED IDEOGRAPH + 0xCED0: 0x6066, //CJK UNIFIED IDEOGRAPH + 0xCED1: 0x606E, //CJK UNIFIED IDEOGRAPH + 0xCED2: 0x6242, //CJK UNIFIED IDEOGRAPH + 0xCED3: 0x6243, //CJK UNIFIED IDEOGRAPH + 0xCED4: 0x62CF, //CJK UNIFIED IDEOGRAPH + 0xCED5: 0x630D, //CJK UNIFIED IDEOGRAPH + 0xCED6: 0x630B, //CJK UNIFIED IDEOGRAPH + 0xCED7: 0x62F5, //CJK UNIFIED IDEOGRAPH + 0xCED8: 0x630E, //CJK UNIFIED IDEOGRAPH + 0xCED9: 0x6303, //CJK UNIFIED IDEOGRAPH + 0xCEDA: 0x62EB, //CJK UNIFIED IDEOGRAPH + 0xCEDB: 0x62F9, //CJK UNIFIED IDEOGRAPH + 0xCEDC: 0x630F, //CJK UNIFIED IDEOGRAPH + 0xCEDD: 0x630C, //CJK UNIFIED IDEOGRAPH + 0xCEDE: 0x62F8, //CJK UNIFIED IDEOGRAPH + 0xCEDF: 0x62F6, //CJK UNIFIED IDEOGRAPH + 0xCEE0: 0x6300, //CJK UNIFIED IDEOGRAPH + 0xCEE1: 0x6313, //CJK UNIFIED IDEOGRAPH + 0xCEE2: 0x6314, //CJK UNIFIED IDEOGRAPH + 0xCEE3: 0x62FA, //CJK UNIFIED IDEOGRAPH + 0xCEE4: 0x6315, //CJK UNIFIED IDEOGRAPH + 0xCEE5: 0x62FB, //CJK UNIFIED IDEOGRAPH + 0xCEE6: 0x62F0, //CJK UNIFIED IDEOGRAPH + 0xCEE7: 0x6541, //CJK UNIFIED IDEOGRAPH + 0xCEE8: 0x6543, //CJK UNIFIED IDEOGRAPH + 0xCEE9: 0x65AA, //CJK UNIFIED IDEOGRAPH + 0xCEEA: 0x65BF, //CJK UNIFIED IDEOGRAPH + 0xCEEB: 0x6636, //CJK UNIFIED IDEOGRAPH + 0xCEEC: 0x6621, //CJK UNIFIED IDEOGRAPH + 0xCEED: 0x6632, //CJK UNIFIED IDEOGRAPH + 0xCEEE: 0x6635, //CJK UNIFIED IDEOGRAPH + 0xCEEF: 0x661C, //CJK UNIFIED IDEOGRAPH + 0xCEF0: 0x6626, //CJK UNIFIED IDEOGRAPH + 0xCEF1: 0x6622, //CJK UNIFIED IDEOGRAPH + 0xCEF2: 0x6633, //CJK UNIFIED IDEOGRAPH + 0xCEF3: 0x662B, //CJK UNIFIED IDEOGRAPH + 0xCEF4: 0x663A, //CJK UNIFIED IDEOGRAPH + 0xCEF5: 0x661D, //CJK UNIFIED IDEOGRAPH + 0xCEF6: 0x6634, //CJK UNIFIED IDEOGRAPH + 0xCEF7: 0x6639, //CJK UNIFIED IDEOGRAPH + 0xCEF8: 0x662E, //CJK UNIFIED IDEOGRAPH + 0xCEF9: 0x670F, //CJK UNIFIED IDEOGRAPH + 0xCEFA: 0x6710, //CJK UNIFIED IDEOGRAPH + 0xCEFB: 0x67C1, //CJK UNIFIED IDEOGRAPH + 0xCEFC: 0x67F2, //CJK UNIFIED IDEOGRAPH + 0xCEFD: 0x67C8, //CJK UNIFIED IDEOGRAPH + 0xCEFE: 0x67BA, //CJK UNIFIED IDEOGRAPH + 0xCF40: 0x67DC, //CJK UNIFIED IDEOGRAPH + 0xCF41: 0x67BB, //CJK UNIFIED IDEOGRAPH + 0xCF42: 0x67F8, //CJK UNIFIED IDEOGRAPH + 0xCF43: 0x67D8, //CJK UNIFIED IDEOGRAPH + 0xCF44: 0x67C0, //CJK UNIFIED IDEOGRAPH + 0xCF45: 0x67B7, //CJK UNIFIED IDEOGRAPH + 0xCF46: 0x67C5, //CJK UNIFIED IDEOGRAPH + 0xCF47: 0x67EB, //CJK UNIFIED IDEOGRAPH + 0xCF48: 0x67E4, //CJK UNIFIED IDEOGRAPH + 0xCF49: 0x67DF, //CJK UNIFIED IDEOGRAPH + 0xCF4A: 0x67B5, //CJK UNIFIED IDEOGRAPH + 0xCF4B: 0x67CD, //CJK UNIFIED IDEOGRAPH + 0xCF4C: 0x67B3, //CJK UNIFIED IDEOGRAPH + 0xCF4D: 0x67F7, //CJK UNIFIED IDEOGRAPH + 0xCF4E: 0x67F6, //CJK UNIFIED IDEOGRAPH + 0xCF4F: 0x67EE, //CJK UNIFIED IDEOGRAPH + 0xCF50: 0x67E3, //CJK UNIFIED IDEOGRAPH + 0xCF51: 0x67C2, //CJK UNIFIED IDEOGRAPH + 0xCF52: 0x67B9, //CJK UNIFIED IDEOGRAPH + 0xCF53: 0x67CE, //CJK UNIFIED IDEOGRAPH + 0xCF54: 0x67E7, //CJK UNIFIED IDEOGRAPH + 0xCF55: 0x67F0, //CJK UNIFIED IDEOGRAPH + 0xCF56: 0x67B2, //CJK UNIFIED IDEOGRAPH + 0xCF57: 0x67FC, //CJK UNIFIED IDEOGRAPH + 0xCF58: 0x67C6, //CJK UNIFIED IDEOGRAPH + 0xCF59: 0x67ED, //CJK UNIFIED IDEOGRAPH + 0xCF5A: 0x67CC, //CJK UNIFIED IDEOGRAPH + 0xCF5B: 0x67AE, //CJK UNIFIED IDEOGRAPH + 0xCF5C: 0x67E6, //CJK UNIFIED IDEOGRAPH + 0xCF5D: 0x67DB, //CJK UNIFIED IDEOGRAPH + 0xCF5E: 0x67FA, //CJK UNIFIED IDEOGRAPH + 0xCF5F: 0x67C9, //CJK UNIFIED IDEOGRAPH + 0xCF60: 0x67CA, //CJK UNIFIED IDEOGRAPH + 0xCF61: 0x67C3, //CJK UNIFIED IDEOGRAPH + 0xCF62: 0x67EA, //CJK UNIFIED IDEOGRAPH + 0xCF63: 0x67CB, //CJK UNIFIED IDEOGRAPH + 0xCF64: 0x6B28, //CJK UNIFIED IDEOGRAPH + 0xCF65: 0x6B82, //CJK UNIFIED IDEOGRAPH + 0xCF66: 0x6B84, //CJK UNIFIED IDEOGRAPH + 0xCF67: 0x6BB6, //CJK UNIFIED IDEOGRAPH + 0xCF68: 0x6BD6, //CJK UNIFIED IDEOGRAPH + 0xCF69: 0x6BD8, //CJK UNIFIED IDEOGRAPH + 0xCF6A: 0x6BE0, //CJK UNIFIED IDEOGRAPH + 0xCF6B: 0x6C20, //CJK UNIFIED IDEOGRAPH + 0xCF6C: 0x6C21, //CJK UNIFIED IDEOGRAPH + 0xCF6D: 0x6D28, //CJK UNIFIED IDEOGRAPH + 0xCF6E: 0x6D34, //CJK UNIFIED IDEOGRAPH + 0xCF6F: 0x6D2D, //CJK UNIFIED IDEOGRAPH + 0xCF70: 0x6D1F, //CJK UNIFIED IDEOGRAPH + 0xCF71: 0x6D3C, //CJK UNIFIED IDEOGRAPH + 0xCF72: 0x6D3F, //CJK UNIFIED IDEOGRAPH + 0xCF73: 0x6D12, //CJK UNIFIED IDEOGRAPH + 0xCF74: 0x6D0A, //CJK UNIFIED IDEOGRAPH + 0xCF75: 0x6CDA, //CJK UNIFIED IDEOGRAPH + 0xCF76: 0x6D33, //CJK UNIFIED IDEOGRAPH + 0xCF77: 0x6D04, //CJK UNIFIED IDEOGRAPH + 0xCF78: 0x6D19, //CJK UNIFIED IDEOGRAPH + 0xCF79: 0x6D3A, //CJK UNIFIED IDEOGRAPH + 0xCF7A: 0x6D1A, //CJK UNIFIED IDEOGRAPH + 0xCF7B: 0x6D11, //CJK UNIFIED IDEOGRAPH + 0xCF7C: 0x6D00, //CJK UNIFIED IDEOGRAPH + 0xCF7D: 0x6D1D, //CJK UNIFIED IDEOGRAPH + 0xCF7E: 0x6D42, //CJK UNIFIED IDEOGRAPH + 0xCFA1: 0x6D01, //CJK UNIFIED IDEOGRAPH + 0xCFA2: 0x6D18, //CJK UNIFIED IDEOGRAPH + 0xCFA3: 0x6D37, //CJK UNIFIED IDEOGRAPH + 0xCFA4: 0x6D03, //CJK UNIFIED IDEOGRAPH + 0xCFA5: 0x6D0F, //CJK UNIFIED IDEOGRAPH + 0xCFA6: 0x6D40, //CJK UNIFIED IDEOGRAPH + 0xCFA7: 0x6D07, //CJK UNIFIED IDEOGRAPH + 0xCFA8: 0x6D20, //CJK UNIFIED IDEOGRAPH + 0xCFA9: 0x6D2C, //CJK UNIFIED IDEOGRAPH + 0xCFAA: 0x6D08, //CJK UNIFIED IDEOGRAPH + 0xCFAB: 0x6D22, //CJK UNIFIED IDEOGRAPH + 0xCFAC: 0x6D09, //CJK UNIFIED IDEOGRAPH + 0xCFAD: 0x6D10, //CJK UNIFIED IDEOGRAPH + 0xCFAE: 0x70B7, //CJK UNIFIED IDEOGRAPH + 0xCFAF: 0x709F, //CJK UNIFIED IDEOGRAPH + 0xCFB0: 0x70BE, //CJK UNIFIED IDEOGRAPH + 0xCFB1: 0x70B1, //CJK UNIFIED IDEOGRAPH + 0xCFB2: 0x70B0, //CJK UNIFIED IDEOGRAPH + 0xCFB3: 0x70A1, //CJK UNIFIED IDEOGRAPH + 0xCFB4: 0x70B4, //CJK UNIFIED IDEOGRAPH + 0xCFB5: 0x70B5, //CJK UNIFIED IDEOGRAPH + 0xCFB6: 0x70A9, //CJK UNIFIED IDEOGRAPH + 0xCFB7: 0x7241, //CJK UNIFIED IDEOGRAPH + 0xCFB8: 0x7249, //CJK UNIFIED IDEOGRAPH + 0xCFB9: 0x724A, //CJK UNIFIED IDEOGRAPH + 0xCFBA: 0x726C, //CJK UNIFIED IDEOGRAPH + 0xCFBB: 0x7270, //CJK UNIFIED IDEOGRAPH + 0xCFBC: 0x7273, //CJK UNIFIED IDEOGRAPH + 0xCFBD: 0x726E, //CJK UNIFIED IDEOGRAPH + 0xCFBE: 0x72CA, //CJK UNIFIED IDEOGRAPH + 0xCFBF: 0x72E4, //CJK UNIFIED IDEOGRAPH + 0xCFC0: 0x72E8, //CJK UNIFIED IDEOGRAPH + 0xCFC1: 0x72EB, //CJK UNIFIED IDEOGRAPH + 0xCFC2: 0x72DF, //CJK UNIFIED IDEOGRAPH + 0xCFC3: 0x72EA, //CJK UNIFIED IDEOGRAPH + 0xCFC4: 0x72E6, //CJK UNIFIED IDEOGRAPH + 0xCFC5: 0x72E3, //CJK UNIFIED IDEOGRAPH + 0xCFC6: 0x7385, //CJK UNIFIED IDEOGRAPH + 0xCFC7: 0x73CC, //CJK UNIFIED IDEOGRAPH + 0xCFC8: 0x73C2, //CJK UNIFIED IDEOGRAPH + 0xCFC9: 0x73C8, //CJK UNIFIED IDEOGRAPH + 0xCFCA: 0x73C5, //CJK UNIFIED IDEOGRAPH + 0xCFCB: 0x73B9, //CJK UNIFIED IDEOGRAPH + 0xCFCC: 0x73B6, //CJK UNIFIED IDEOGRAPH + 0xCFCD: 0x73B5, //CJK UNIFIED IDEOGRAPH + 0xCFCE: 0x73B4, //CJK UNIFIED IDEOGRAPH + 0xCFCF: 0x73EB, //CJK UNIFIED IDEOGRAPH + 0xCFD0: 0x73BF, //CJK UNIFIED IDEOGRAPH + 0xCFD1: 0x73C7, //CJK UNIFIED IDEOGRAPH + 0xCFD2: 0x73BE, //CJK UNIFIED IDEOGRAPH + 0xCFD3: 0x73C3, //CJK UNIFIED IDEOGRAPH + 0xCFD4: 0x73C6, //CJK UNIFIED IDEOGRAPH + 0xCFD5: 0x73B8, //CJK UNIFIED IDEOGRAPH + 0xCFD6: 0x73CB, //CJK UNIFIED IDEOGRAPH + 0xCFD7: 0x74EC, //CJK UNIFIED IDEOGRAPH + 0xCFD8: 0x74EE, //CJK UNIFIED IDEOGRAPH + 0xCFD9: 0x752E, //CJK UNIFIED IDEOGRAPH + 0xCFDA: 0x7547, //CJK UNIFIED IDEOGRAPH + 0xCFDB: 0x7548, //CJK UNIFIED IDEOGRAPH + 0xCFDC: 0x75A7, //CJK UNIFIED IDEOGRAPH + 0xCFDD: 0x75AA, //CJK UNIFIED IDEOGRAPH + 0xCFDE: 0x7679, //CJK UNIFIED IDEOGRAPH + 0xCFDF: 0x76C4, //CJK UNIFIED IDEOGRAPH + 0xCFE0: 0x7708, //CJK UNIFIED IDEOGRAPH + 0xCFE1: 0x7703, //CJK UNIFIED IDEOGRAPH + 0xCFE2: 0x7704, //CJK UNIFIED IDEOGRAPH + 0xCFE3: 0x7705, //CJK UNIFIED IDEOGRAPH + 0xCFE4: 0x770A, //CJK UNIFIED IDEOGRAPH + 0xCFE5: 0x76F7, //CJK UNIFIED IDEOGRAPH + 0xCFE6: 0x76FB, //CJK UNIFIED IDEOGRAPH + 0xCFE7: 0x76FA, //CJK UNIFIED IDEOGRAPH + 0xCFE8: 0x77E7, //CJK UNIFIED IDEOGRAPH + 0xCFE9: 0x77E8, //CJK UNIFIED IDEOGRAPH + 0xCFEA: 0x7806, //CJK UNIFIED IDEOGRAPH + 0xCFEB: 0x7811, //CJK UNIFIED IDEOGRAPH + 0xCFEC: 0x7812, //CJK UNIFIED IDEOGRAPH + 0xCFED: 0x7805, //CJK UNIFIED IDEOGRAPH + 0xCFEE: 0x7810, //CJK UNIFIED IDEOGRAPH + 0xCFEF: 0x780F, //CJK UNIFIED IDEOGRAPH + 0xCFF0: 0x780E, //CJK UNIFIED IDEOGRAPH + 0xCFF1: 0x7809, //CJK UNIFIED IDEOGRAPH + 0xCFF2: 0x7803, //CJK UNIFIED IDEOGRAPH + 0xCFF3: 0x7813, //CJK UNIFIED IDEOGRAPH + 0xCFF4: 0x794A, //CJK UNIFIED IDEOGRAPH + 0xCFF5: 0x794C, //CJK UNIFIED IDEOGRAPH + 0xCFF6: 0x794B, //CJK UNIFIED IDEOGRAPH + 0xCFF7: 0x7945, //CJK UNIFIED IDEOGRAPH + 0xCFF8: 0x7944, //CJK UNIFIED IDEOGRAPH + 0xCFF9: 0x79D5, //CJK UNIFIED IDEOGRAPH + 0xCFFA: 0x79CD, //CJK UNIFIED IDEOGRAPH + 0xCFFB: 0x79CF, //CJK UNIFIED IDEOGRAPH + 0xCFFC: 0x79D6, //CJK UNIFIED IDEOGRAPH + 0xCFFD: 0x79CE, //CJK UNIFIED IDEOGRAPH + 0xCFFE: 0x7A80, //CJK UNIFIED IDEOGRAPH + 0xD040: 0x7A7E, //CJK UNIFIED IDEOGRAPH + 0xD041: 0x7AD1, //CJK UNIFIED IDEOGRAPH + 0xD042: 0x7B00, //CJK UNIFIED IDEOGRAPH + 0xD043: 0x7B01, //CJK UNIFIED IDEOGRAPH + 0xD044: 0x7C7A, //CJK UNIFIED IDEOGRAPH + 0xD045: 0x7C78, //CJK UNIFIED IDEOGRAPH + 0xD046: 0x7C79, //CJK UNIFIED IDEOGRAPH + 0xD047: 0x7C7F, //CJK UNIFIED IDEOGRAPH + 0xD048: 0x7C80, //CJK UNIFIED IDEOGRAPH + 0xD049: 0x7C81, //CJK UNIFIED IDEOGRAPH + 0xD04A: 0x7D03, //CJK UNIFIED IDEOGRAPH + 0xD04B: 0x7D08, //CJK UNIFIED IDEOGRAPH + 0xD04C: 0x7D01, //CJK UNIFIED IDEOGRAPH + 0xD04D: 0x7F58, //CJK UNIFIED IDEOGRAPH + 0xD04E: 0x7F91, //CJK UNIFIED IDEOGRAPH + 0xD04F: 0x7F8D, //CJK UNIFIED IDEOGRAPH + 0xD050: 0x7FBE, //CJK UNIFIED IDEOGRAPH + 0xD051: 0x8007, //CJK UNIFIED IDEOGRAPH + 0xD052: 0x800E, //CJK UNIFIED IDEOGRAPH + 0xD053: 0x800F, //CJK UNIFIED IDEOGRAPH + 0xD054: 0x8014, //CJK UNIFIED IDEOGRAPH + 0xD055: 0x8037, //CJK UNIFIED IDEOGRAPH + 0xD056: 0x80D8, //CJK UNIFIED IDEOGRAPH + 0xD057: 0x80C7, //CJK UNIFIED IDEOGRAPH + 0xD058: 0x80E0, //CJK UNIFIED IDEOGRAPH + 0xD059: 0x80D1, //CJK UNIFIED IDEOGRAPH + 0xD05A: 0x80C8, //CJK UNIFIED IDEOGRAPH + 0xD05B: 0x80C2, //CJK UNIFIED IDEOGRAPH + 0xD05C: 0x80D0, //CJK UNIFIED IDEOGRAPH + 0xD05D: 0x80C5, //CJK UNIFIED IDEOGRAPH + 0xD05E: 0x80E3, //CJK UNIFIED IDEOGRAPH + 0xD05F: 0x80D9, //CJK UNIFIED IDEOGRAPH + 0xD060: 0x80DC, //CJK UNIFIED IDEOGRAPH + 0xD061: 0x80CA, //CJK UNIFIED IDEOGRAPH + 0xD062: 0x80D5, //CJK UNIFIED IDEOGRAPH + 0xD063: 0x80C9, //CJK UNIFIED IDEOGRAPH + 0xD064: 0x80CF, //CJK UNIFIED IDEOGRAPH + 0xD065: 0x80D7, //CJK UNIFIED IDEOGRAPH + 0xD066: 0x80E6, //CJK UNIFIED IDEOGRAPH + 0xD067: 0x80CD, //CJK UNIFIED IDEOGRAPH + 0xD068: 0x81FF, //CJK UNIFIED IDEOGRAPH + 0xD069: 0x8221, //CJK UNIFIED IDEOGRAPH + 0xD06A: 0x8294, //CJK UNIFIED IDEOGRAPH + 0xD06B: 0x82D9, //CJK UNIFIED IDEOGRAPH + 0xD06C: 0x82FE, //CJK UNIFIED IDEOGRAPH + 0xD06D: 0x82F9, //CJK UNIFIED IDEOGRAPH + 0xD06E: 0x8307, //CJK UNIFIED IDEOGRAPH + 0xD06F: 0x82E8, //CJK UNIFIED IDEOGRAPH + 0xD070: 0x8300, //CJK UNIFIED IDEOGRAPH + 0xD071: 0x82D5, //CJK UNIFIED IDEOGRAPH + 0xD072: 0x833A, //CJK UNIFIED IDEOGRAPH + 0xD073: 0x82EB, //CJK UNIFIED IDEOGRAPH + 0xD074: 0x82D6, //CJK UNIFIED IDEOGRAPH + 0xD075: 0x82F4, //CJK UNIFIED IDEOGRAPH + 0xD076: 0x82EC, //CJK UNIFIED IDEOGRAPH + 0xD077: 0x82E1, //CJK UNIFIED IDEOGRAPH + 0xD078: 0x82F2, //CJK UNIFIED IDEOGRAPH + 0xD079: 0x82F5, //CJK UNIFIED IDEOGRAPH + 0xD07A: 0x830C, //CJK UNIFIED IDEOGRAPH + 0xD07B: 0x82FB, //CJK UNIFIED IDEOGRAPH + 0xD07C: 0x82F6, //CJK UNIFIED IDEOGRAPH + 0xD07D: 0x82F0, //CJK UNIFIED IDEOGRAPH + 0xD07E: 0x82EA, //CJK UNIFIED IDEOGRAPH + 0xD0A1: 0x82E4, //CJK UNIFIED IDEOGRAPH + 0xD0A2: 0x82E0, //CJK UNIFIED IDEOGRAPH + 0xD0A3: 0x82FA, //CJK UNIFIED IDEOGRAPH + 0xD0A4: 0x82F3, //CJK UNIFIED IDEOGRAPH + 0xD0A5: 0x82ED, //CJK UNIFIED IDEOGRAPH + 0xD0A6: 0x8677, //CJK UNIFIED IDEOGRAPH + 0xD0A7: 0x8674, //CJK UNIFIED IDEOGRAPH + 0xD0A8: 0x867C, //CJK UNIFIED IDEOGRAPH + 0xD0A9: 0x8673, //CJK UNIFIED IDEOGRAPH + 0xD0AA: 0x8841, //CJK UNIFIED IDEOGRAPH + 0xD0AB: 0x884E, //CJK UNIFIED IDEOGRAPH + 0xD0AC: 0x8867, //CJK UNIFIED IDEOGRAPH + 0xD0AD: 0x886A, //CJK UNIFIED IDEOGRAPH + 0xD0AE: 0x8869, //CJK UNIFIED IDEOGRAPH + 0xD0AF: 0x89D3, //CJK UNIFIED IDEOGRAPH + 0xD0B0: 0x8A04, //CJK UNIFIED IDEOGRAPH + 0xD0B1: 0x8A07, //CJK UNIFIED IDEOGRAPH + 0xD0B2: 0x8D72, //CJK UNIFIED IDEOGRAPH + 0xD0B3: 0x8FE3, //CJK UNIFIED IDEOGRAPH + 0xD0B4: 0x8FE1, //CJK UNIFIED IDEOGRAPH + 0xD0B5: 0x8FEE, //CJK UNIFIED IDEOGRAPH + 0xD0B6: 0x8FE0, //CJK UNIFIED IDEOGRAPH + 0xD0B7: 0x90F1, //CJK UNIFIED IDEOGRAPH + 0xD0B8: 0x90BD, //CJK UNIFIED IDEOGRAPH + 0xD0B9: 0x90BF, //CJK UNIFIED IDEOGRAPH + 0xD0BA: 0x90D5, //CJK UNIFIED IDEOGRAPH + 0xD0BB: 0x90C5, //CJK UNIFIED IDEOGRAPH + 0xD0BC: 0x90BE, //CJK UNIFIED IDEOGRAPH + 0xD0BD: 0x90C7, //CJK UNIFIED IDEOGRAPH + 0xD0BE: 0x90CB, //CJK UNIFIED IDEOGRAPH + 0xD0BF: 0x90C8, //CJK UNIFIED IDEOGRAPH + 0xD0C0: 0x91D4, //CJK UNIFIED IDEOGRAPH + 0xD0C1: 0x91D3, //CJK UNIFIED IDEOGRAPH + 0xD0C2: 0x9654, //CJK UNIFIED IDEOGRAPH + 0xD0C3: 0x964F, //CJK UNIFIED IDEOGRAPH + 0xD0C4: 0x9651, //CJK UNIFIED IDEOGRAPH + 0xD0C5: 0x9653, //CJK UNIFIED IDEOGRAPH + 0xD0C6: 0x964A, //CJK UNIFIED IDEOGRAPH + 0xD0C7: 0x964E, //CJK UNIFIED IDEOGRAPH + 0xD0C8: 0x501E, //CJK UNIFIED IDEOGRAPH + 0xD0C9: 0x5005, //CJK UNIFIED IDEOGRAPH + 0xD0CA: 0x5007, //CJK UNIFIED IDEOGRAPH + 0xD0CB: 0x5013, //CJK UNIFIED IDEOGRAPH + 0xD0CC: 0x5022, //CJK UNIFIED IDEOGRAPH + 0xD0CD: 0x5030, //CJK UNIFIED IDEOGRAPH + 0xD0CE: 0x501B, //CJK UNIFIED IDEOGRAPH + 0xD0CF: 0x4FF5, //CJK UNIFIED IDEOGRAPH + 0xD0D0: 0x4FF4, //CJK UNIFIED IDEOGRAPH + 0xD0D1: 0x5033, //CJK UNIFIED IDEOGRAPH + 0xD0D2: 0x5037, //CJK UNIFIED IDEOGRAPH + 0xD0D3: 0x502C, //CJK UNIFIED IDEOGRAPH + 0xD0D4: 0x4FF6, //CJK UNIFIED IDEOGRAPH + 0xD0D5: 0x4FF7, //CJK UNIFIED IDEOGRAPH + 0xD0D6: 0x5017, //CJK UNIFIED IDEOGRAPH + 0xD0D7: 0x501C, //CJK UNIFIED IDEOGRAPH + 0xD0D8: 0x5020, //CJK UNIFIED IDEOGRAPH + 0xD0D9: 0x5027, //CJK UNIFIED IDEOGRAPH + 0xD0DA: 0x5035, //CJK UNIFIED IDEOGRAPH + 0xD0DB: 0x502F, //CJK UNIFIED IDEOGRAPH + 0xD0DC: 0x5031, //CJK UNIFIED IDEOGRAPH + 0xD0DD: 0x500E, //CJK UNIFIED IDEOGRAPH + 0xD0DE: 0x515A, //CJK UNIFIED IDEOGRAPH + 0xD0DF: 0x5194, //CJK UNIFIED IDEOGRAPH + 0xD0E0: 0x5193, //CJK UNIFIED IDEOGRAPH + 0xD0E1: 0x51CA, //CJK UNIFIED IDEOGRAPH + 0xD0E2: 0x51C4, //CJK UNIFIED IDEOGRAPH + 0xD0E3: 0x51C5, //CJK UNIFIED IDEOGRAPH + 0xD0E4: 0x51C8, //CJK UNIFIED IDEOGRAPH + 0xD0E5: 0x51CE, //CJK UNIFIED IDEOGRAPH + 0xD0E6: 0x5261, //CJK UNIFIED IDEOGRAPH + 0xD0E7: 0x525A, //CJK UNIFIED IDEOGRAPH + 0xD0E8: 0x5252, //CJK UNIFIED IDEOGRAPH + 0xD0E9: 0x525E, //CJK UNIFIED IDEOGRAPH + 0xD0EA: 0x525F, //CJK UNIFIED IDEOGRAPH + 0xD0EB: 0x5255, //CJK UNIFIED IDEOGRAPH + 0xD0EC: 0x5262, //CJK UNIFIED IDEOGRAPH + 0xD0ED: 0x52CD, //CJK UNIFIED IDEOGRAPH + 0xD0EE: 0x530E, //CJK UNIFIED IDEOGRAPH + 0xD0EF: 0x539E, //CJK UNIFIED IDEOGRAPH + 0xD0F0: 0x5526, //CJK UNIFIED IDEOGRAPH + 0xD0F1: 0x54E2, //CJK UNIFIED IDEOGRAPH + 0xD0F2: 0x5517, //CJK UNIFIED IDEOGRAPH + 0xD0F3: 0x5512, //CJK UNIFIED IDEOGRAPH + 0xD0F4: 0x54E7, //CJK UNIFIED IDEOGRAPH + 0xD0F5: 0x54F3, //CJK UNIFIED IDEOGRAPH + 0xD0F6: 0x54E4, //CJK UNIFIED IDEOGRAPH + 0xD0F7: 0x551A, //CJK UNIFIED IDEOGRAPH + 0xD0F8: 0x54FF, //CJK UNIFIED IDEOGRAPH + 0xD0F9: 0x5504, //CJK UNIFIED IDEOGRAPH + 0xD0FA: 0x5508, //CJK UNIFIED IDEOGRAPH + 0xD0FB: 0x54EB, //CJK UNIFIED IDEOGRAPH + 0xD0FC: 0x5511, //CJK UNIFIED IDEOGRAPH + 0xD0FD: 0x5505, //CJK UNIFIED IDEOGRAPH + 0xD0FE: 0x54F1, //CJK UNIFIED IDEOGRAPH + 0xD140: 0x550A, //CJK UNIFIED IDEOGRAPH + 0xD141: 0x54FB, //CJK UNIFIED IDEOGRAPH + 0xD142: 0x54F7, //CJK UNIFIED IDEOGRAPH + 0xD143: 0x54F8, //CJK UNIFIED IDEOGRAPH + 0xD144: 0x54E0, //CJK UNIFIED IDEOGRAPH + 0xD145: 0x550E, //CJK UNIFIED IDEOGRAPH + 0xD146: 0x5503, //CJK UNIFIED IDEOGRAPH + 0xD147: 0x550B, //CJK UNIFIED IDEOGRAPH + 0xD148: 0x5701, //CJK UNIFIED IDEOGRAPH + 0xD149: 0x5702, //CJK UNIFIED IDEOGRAPH + 0xD14A: 0x57CC, //CJK UNIFIED IDEOGRAPH + 0xD14B: 0x5832, //CJK UNIFIED IDEOGRAPH + 0xD14C: 0x57D5, //CJK UNIFIED IDEOGRAPH + 0xD14D: 0x57D2, //CJK UNIFIED IDEOGRAPH + 0xD14E: 0x57BA, //CJK UNIFIED IDEOGRAPH + 0xD14F: 0x57C6, //CJK UNIFIED IDEOGRAPH + 0xD150: 0x57BD, //CJK UNIFIED IDEOGRAPH + 0xD151: 0x57BC, //CJK UNIFIED IDEOGRAPH + 0xD152: 0x57B8, //CJK UNIFIED IDEOGRAPH + 0xD153: 0x57B6, //CJK UNIFIED IDEOGRAPH + 0xD154: 0x57BF, //CJK UNIFIED IDEOGRAPH + 0xD155: 0x57C7, //CJK UNIFIED IDEOGRAPH + 0xD156: 0x57D0, //CJK UNIFIED IDEOGRAPH + 0xD157: 0x57B9, //CJK UNIFIED IDEOGRAPH + 0xD158: 0x57C1, //CJK UNIFIED IDEOGRAPH + 0xD159: 0x590E, //CJK UNIFIED IDEOGRAPH + 0xD15A: 0x594A, //CJK UNIFIED IDEOGRAPH + 0xD15B: 0x5A19, //CJK UNIFIED IDEOGRAPH + 0xD15C: 0x5A16, //CJK UNIFIED IDEOGRAPH + 0xD15D: 0x5A2D, //CJK UNIFIED IDEOGRAPH + 0xD15E: 0x5A2E, //CJK UNIFIED IDEOGRAPH + 0xD15F: 0x5A15, //CJK UNIFIED IDEOGRAPH + 0xD160: 0x5A0F, //CJK UNIFIED IDEOGRAPH + 0xD161: 0x5A17, //CJK UNIFIED IDEOGRAPH + 0xD162: 0x5A0A, //CJK UNIFIED IDEOGRAPH + 0xD163: 0x5A1E, //CJK UNIFIED IDEOGRAPH + 0xD164: 0x5A33, //CJK UNIFIED IDEOGRAPH + 0xD165: 0x5B6C, //CJK UNIFIED IDEOGRAPH + 0xD166: 0x5BA7, //CJK UNIFIED IDEOGRAPH + 0xD167: 0x5BAD, //CJK UNIFIED IDEOGRAPH + 0xD168: 0x5BAC, //CJK UNIFIED IDEOGRAPH + 0xD169: 0x5C03, //CJK UNIFIED IDEOGRAPH + 0xD16A: 0x5C56, //CJK UNIFIED IDEOGRAPH + 0xD16B: 0x5C54, //CJK UNIFIED IDEOGRAPH + 0xD16C: 0x5CEC, //CJK UNIFIED IDEOGRAPH + 0xD16D: 0x5CFF, //CJK UNIFIED IDEOGRAPH + 0xD16E: 0x5CEE, //CJK UNIFIED IDEOGRAPH + 0xD16F: 0x5CF1, //CJK UNIFIED IDEOGRAPH + 0xD170: 0x5CF7, //CJK UNIFIED IDEOGRAPH + 0xD171: 0x5D00, //CJK UNIFIED IDEOGRAPH + 0xD172: 0x5CF9, //CJK UNIFIED IDEOGRAPH + 0xD173: 0x5E29, //CJK UNIFIED IDEOGRAPH + 0xD174: 0x5E28, //CJK UNIFIED IDEOGRAPH + 0xD175: 0x5EA8, //CJK UNIFIED IDEOGRAPH + 0xD176: 0x5EAE, //CJK UNIFIED IDEOGRAPH + 0xD177: 0x5EAA, //CJK UNIFIED IDEOGRAPH + 0xD178: 0x5EAC, //CJK UNIFIED IDEOGRAPH + 0xD179: 0x5F33, //CJK UNIFIED IDEOGRAPH + 0xD17A: 0x5F30, //CJK UNIFIED IDEOGRAPH + 0xD17B: 0x5F67, //CJK UNIFIED IDEOGRAPH + 0xD17C: 0x605D, //CJK UNIFIED IDEOGRAPH + 0xD17D: 0x605A, //CJK UNIFIED IDEOGRAPH + 0xD17E: 0x6067, //CJK UNIFIED IDEOGRAPH + 0xD1A1: 0x6041, //CJK UNIFIED IDEOGRAPH + 0xD1A2: 0x60A2, //CJK UNIFIED IDEOGRAPH + 0xD1A3: 0x6088, //CJK UNIFIED IDEOGRAPH + 0xD1A4: 0x6080, //CJK UNIFIED IDEOGRAPH + 0xD1A5: 0x6092, //CJK UNIFIED IDEOGRAPH + 0xD1A6: 0x6081, //CJK UNIFIED IDEOGRAPH + 0xD1A7: 0x609D, //CJK UNIFIED IDEOGRAPH + 0xD1A8: 0x6083, //CJK UNIFIED IDEOGRAPH + 0xD1A9: 0x6095, //CJK UNIFIED IDEOGRAPH + 0xD1AA: 0x609B, //CJK UNIFIED IDEOGRAPH + 0xD1AB: 0x6097, //CJK UNIFIED IDEOGRAPH + 0xD1AC: 0x6087, //CJK UNIFIED IDEOGRAPH + 0xD1AD: 0x609C, //CJK UNIFIED IDEOGRAPH + 0xD1AE: 0x608E, //CJK UNIFIED IDEOGRAPH + 0xD1AF: 0x6219, //CJK UNIFIED IDEOGRAPH + 0xD1B0: 0x6246, //CJK UNIFIED IDEOGRAPH + 0xD1B1: 0x62F2, //CJK UNIFIED IDEOGRAPH + 0xD1B2: 0x6310, //CJK UNIFIED IDEOGRAPH + 0xD1B3: 0x6356, //CJK UNIFIED IDEOGRAPH + 0xD1B4: 0x632C, //CJK UNIFIED IDEOGRAPH + 0xD1B5: 0x6344, //CJK UNIFIED IDEOGRAPH + 0xD1B6: 0x6345, //CJK UNIFIED IDEOGRAPH + 0xD1B7: 0x6336, //CJK UNIFIED IDEOGRAPH + 0xD1B8: 0x6343, //CJK UNIFIED IDEOGRAPH + 0xD1B9: 0x63E4, //CJK UNIFIED IDEOGRAPH + 0xD1BA: 0x6339, //CJK UNIFIED IDEOGRAPH + 0xD1BB: 0x634B, //CJK UNIFIED IDEOGRAPH + 0xD1BC: 0x634A, //CJK UNIFIED IDEOGRAPH + 0xD1BD: 0x633C, //CJK UNIFIED IDEOGRAPH + 0xD1BE: 0x6329, //CJK UNIFIED IDEOGRAPH + 0xD1BF: 0x6341, //CJK UNIFIED IDEOGRAPH + 0xD1C0: 0x6334, //CJK UNIFIED IDEOGRAPH + 0xD1C1: 0x6358, //CJK UNIFIED IDEOGRAPH + 0xD1C2: 0x6354, //CJK UNIFIED IDEOGRAPH + 0xD1C3: 0x6359, //CJK UNIFIED IDEOGRAPH + 0xD1C4: 0x632D, //CJK UNIFIED IDEOGRAPH + 0xD1C5: 0x6347, //CJK UNIFIED IDEOGRAPH + 0xD1C6: 0x6333, //CJK UNIFIED IDEOGRAPH + 0xD1C7: 0x635A, //CJK UNIFIED IDEOGRAPH + 0xD1C8: 0x6351, //CJK UNIFIED IDEOGRAPH + 0xD1C9: 0x6338, //CJK UNIFIED IDEOGRAPH + 0xD1CA: 0x6357, //CJK UNIFIED IDEOGRAPH + 0xD1CB: 0x6340, //CJK UNIFIED IDEOGRAPH + 0xD1CC: 0x6348, //CJK UNIFIED IDEOGRAPH + 0xD1CD: 0x654A, //CJK UNIFIED IDEOGRAPH + 0xD1CE: 0x6546, //CJK UNIFIED IDEOGRAPH + 0xD1CF: 0x65C6, //CJK UNIFIED IDEOGRAPH + 0xD1D0: 0x65C3, //CJK UNIFIED IDEOGRAPH + 0xD1D1: 0x65C4, //CJK UNIFIED IDEOGRAPH + 0xD1D2: 0x65C2, //CJK UNIFIED IDEOGRAPH + 0xD1D3: 0x664A, //CJK UNIFIED IDEOGRAPH + 0xD1D4: 0x665F, //CJK UNIFIED IDEOGRAPH + 0xD1D5: 0x6647, //CJK UNIFIED IDEOGRAPH + 0xD1D6: 0x6651, //CJK UNIFIED IDEOGRAPH + 0xD1D7: 0x6712, //CJK UNIFIED IDEOGRAPH + 0xD1D8: 0x6713, //CJK UNIFIED IDEOGRAPH + 0xD1D9: 0x681F, //CJK UNIFIED IDEOGRAPH + 0xD1DA: 0x681A, //CJK UNIFIED IDEOGRAPH + 0xD1DB: 0x6849, //CJK UNIFIED IDEOGRAPH + 0xD1DC: 0x6832, //CJK UNIFIED IDEOGRAPH + 0xD1DD: 0x6833, //CJK UNIFIED IDEOGRAPH + 0xD1DE: 0x683B, //CJK UNIFIED IDEOGRAPH + 0xD1DF: 0x684B, //CJK UNIFIED IDEOGRAPH + 0xD1E0: 0x684F, //CJK UNIFIED IDEOGRAPH + 0xD1E1: 0x6816, //CJK UNIFIED IDEOGRAPH + 0xD1E2: 0x6831, //CJK UNIFIED IDEOGRAPH + 0xD1E3: 0x681C, //CJK UNIFIED IDEOGRAPH + 0xD1E4: 0x6835, //CJK UNIFIED IDEOGRAPH + 0xD1E5: 0x682B, //CJK UNIFIED IDEOGRAPH + 0xD1E6: 0x682D, //CJK UNIFIED IDEOGRAPH + 0xD1E7: 0x682F, //CJK UNIFIED IDEOGRAPH + 0xD1E8: 0x684E, //CJK UNIFIED IDEOGRAPH + 0xD1E9: 0x6844, //CJK UNIFIED IDEOGRAPH + 0xD1EA: 0x6834, //CJK UNIFIED IDEOGRAPH + 0xD1EB: 0x681D, //CJK UNIFIED IDEOGRAPH + 0xD1EC: 0x6812, //CJK UNIFIED IDEOGRAPH + 0xD1ED: 0x6814, //CJK UNIFIED IDEOGRAPH + 0xD1EE: 0x6826, //CJK UNIFIED IDEOGRAPH + 0xD1EF: 0x6828, //CJK UNIFIED IDEOGRAPH + 0xD1F0: 0x682E, //CJK UNIFIED IDEOGRAPH + 0xD1F1: 0x684D, //CJK UNIFIED IDEOGRAPH + 0xD1F2: 0x683A, //CJK UNIFIED IDEOGRAPH + 0xD1F3: 0x6825, //CJK UNIFIED IDEOGRAPH + 0xD1F4: 0x6820, //CJK UNIFIED IDEOGRAPH + 0xD1F5: 0x6B2C, //CJK UNIFIED IDEOGRAPH + 0xD1F6: 0x6B2F, //CJK UNIFIED IDEOGRAPH + 0xD1F7: 0x6B2D, //CJK UNIFIED IDEOGRAPH + 0xD1F8: 0x6B31, //CJK UNIFIED IDEOGRAPH + 0xD1F9: 0x6B34, //CJK UNIFIED IDEOGRAPH + 0xD1FA: 0x6B6D, //CJK UNIFIED IDEOGRAPH + 0xD1FB: 0x8082, //CJK UNIFIED IDEOGRAPH + 0xD1FC: 0x6B88, //CJK UNIFIED IDEOGRAPH + 0xD1FD: 0x6BE6, //CJK UNIFIED IDEOGRAPH + 0xD1FE: 0x6BE4, //CJK UNIFIED IDEOGRAPH + 0xD240: 0x6BE8, //CJK UNIFIED IDEOGRAPH + 0xD241: 0x6BE3, //CJK UNIFIED IDEOGRAPH + 0xD242: 0x6BE2, //CJK UNIFIED IDEOGRAPH + 0xD243: 0x6BE7, //CJK UNIFIED IDEOGRAPH + 0xD244: 0x6C25, //CJK UNIFIED IDEOGRAPH + 0xD245: 0x6D7A, //CJK UNIFIED IDEOGRAPH + 0xD246: 0x6D63, //CJK UNIFIED IDEOGRAPH + 0xD247: 0x6D64, //CJK UNIFIED IDEOGRAPH + 0xD248: 0x6D76, //CJK UNIFIED IDEOGRAPH + 0xD249: 0x6D0D, //CJK UNIFIED IDEOGRAPH + 0xD24A: 0x6D61, //CJK UNIFIED IDEOGRAPH + 0xD24B: 0x6D92, //CJK UNIFIED IDEOGRAPH + 0xD24C: 0x6D58, //CJK UNIFIED IDEOGRAPH + 0xD24D: 0x6D62, //CJK UNIFIED IDEOGRAPH + 0xD24E: 0x6D6D, //CJK UNIFIED IDEOGRAPH + 0xD24F: 0x6D6F, //CJK UNIFIED IDEOGRAPH + 0xD250: 0x6D91, //CJK UNIFIED IDEOGRAPH + 0xD251: 0x6D8D, //CJK UNIFIED IDEOGRAPH + 0xD252: 0x6DEF, //CJK UNIFIED IDEOGRAPH + 0xD253: 0x6D7F, //CJK UNIFIED IDEOGRAPH + 0xD254: 0x6D86, //CJK UNIFIED IDEOGRAPH + 0xD255: 0x6D5E, //CJK UNIFIED IDEOGRAPH + 0xD256: 0x6D67, //CJK UNIFIED IDEOGRAPH + 0xD257: 0x6D60, //CJK UNIFIED IDEOGRAPH + 0xD258: 0x6D97, //CJK UNIFIED IDEOGRAPH + 0xD259: 0x6D70, //CJK UNIFIED IDEOGRAPH + 0xD25A: 0x6D7C, //CJK UNIFIED IDEOGRAPH + 0xD25B: 0x6D5F, //CJK UNIFIED IDEOGRAPH + 0xD25C: 0x6D82, //CJK UNIFIED IDEOGRAPH + 0xD25D: 0x6D98, //CJK UNIFIED IDEOGRAPH + 0xD25E: 0x6D2F, //CJK UNIFIED IDEOGRAPH + 0xD25F: 0x6D68, //CJK UNIFIED IDEOGRAPH + 0xD260: 0x6D8B, //CJK UNIFIED IDEOGRAPH + 0xD261: 0x6D7E, //CJK UNIFIED IDEOGRAPH + 0xD262: 0x6D80, //CJK UNIFIED IDEOGRAPH + 0xD263: 0x6D84, //CJK UNIFIED IDEOGRAPH + 0xD264: 0x6D16, //CJK UNIFIED IDEOGRAPH + 0xD265: 0x6D83, //CJK UNIFIED IDEOGRAPH + 0xD266: 0x6D7B, //CJK UNIFIED IDEOGRAPH + 0xD267: 0x6D7D, //CJK UNIFIED IDEOGRAPH + 0xD268: 0x6D75, //CJK UNIFIED IDEOGRAPH + 0xD269: 0x6D90, //CJK UNIFIED IDEOGRAPH + 0xD26A: 0x70DC, //CJK UNIFIED IDEOGRAPH + 0xD26B: 0x70D3, //CJK UNIFIED IDEOGRAPH + 0xD26C: 0x70D1, //CJK UNIFIED IDEOGRAPH + 0xD26D: 0x70DD, //CJK UNIFIED IDEOGRAPH + 0xD26E: 0x70CB, //CJK UNIFIED IDEOGRAPH + 0xD26F: 0x7F39, //CJK UNIFIED IDEOGRAPH + 0xD270: 0x70E2, //CJK UNIFIED IDEOGRAPH + 0xD271: 0x70D7, //CJK UNIFIED IDEOGRAPH + 0xD272: 0x70D2, //CJK UNIFIED IDEOGRAPH + 0xD273: 0x70DE, //CJK UNIFIED IDEOGRAPH + 0xD274: 0x70E0, //CJK UNIFIED IDEOGRAPH + 0xD275: 0x70D4, //CJK UNIFIED IDEOGRAPH + 0xD276: 0x70CD, //CJK UNIFIED IDEOGRAPH + 0xD277: 0x70C5, //CJK UNIFIED IDEOGRAPH + 0xD278: 0x70C6, //CJK UNIFIED IDEOGRAPH + 0xD279: 0x70C7, //CJK UNIFIED IDEOGRAPH + 0xD27A: 0x70DA, //CJK UNIFIED IDEOGRAPH + 0xD27B: 0x70CE, //CJK UNIFIED IDEOGRAPH + 0xD27C: 0x70E1, //CJK UNIFIED IDEOGRAPH + 0xD27D: 0x7242, //CJK UNIFIED IDEOGRAPH + 0xD27E: 0x7278, //CJK UNIFIED IDEOGRAPH + 0xD2A1: 0x7277, //CJK UNIFIED IDEOGRAPH + 0xD2A2: 0x7276, //CJK UNIFIED IDEOGRAPH + 0xD2A3: 0x7300, //CJK UNIFIED IDEOGRAPH + 0xD2A4: 0x72FA, //CJK UNIFIED IDEOGRAPH + 0xD2A5: 0x72F4, //CJK UNIFIED IDEOGRAPH + 0xD2A6: 0x72FE, //CJK UNIFIED IDEOGRAPH + 0xD2A7: 0x72F6, //CJK UNIFIED IDEOGRAPH + 0xD2A8: 0x72F3, //CJK UNIFIED IDEOGRAPH + 0xD2A9: 0x72FB, //CJK UNIFIED IDEOGRAPH + 0xD2AA: 0x7301, //CJK UNIFIED IDEOGRAPH + 0xD2AB: 0x73D3, //CJK UNIFIED IDEOGRAPH + 0xD2AC: 0x73D9, //CJK UNIFIED IDEOGRAPH + 0xD2AD: 0x73E5, //CJK UNIFIED IDEOGRAPH + 0xD2AE: 0x73D6, //CJK UNIFIED IDEOGRAPH + 0xD2AF: 0x73BC, //CJK UNIFIED IDEOGRAPH + 0xD2B0: 0x73E7, //CJK UNIFIED IDEOGRAPH + 0xD2B1: 0x73E3, //CJK UNIFIED IDEOGRAPH + 0xD2B2: 0x73E9, //CJK UNIFIED IDEOGRAPH + 0xD2B3: 0x73DC, //CJK UNIFIED IDEOGRAPH + 0xD2B4: 0x73D2, //CJK UNIFIED IDEOGRAPH + 0xD2B5: 0x73DB, //CJK UNIFIED IDEOGRAPH + 0xD2B6: 0x73D4, //CJK UNIFIED IDEOGRAPH + 0xD2B7: 0x73DD, //CJK UNIFIED IDEOGRAPH + 0xD2B8: 0x73DA, //CJK UNIFIED IDEOGRAPH + 0xD2B9: 0x73D7, //CJK UNIFIED IDEOGRAPH + 0xD2BA: 0x73D8, //CJK UNIFIED IDEOGRAPH + 0xD2BB: 0x73E8, //CJK UNIFIED IDEOGRAPH + 0xD2BC: 0x74DE, //CJK UNIFIED IDEOGRAPH + 0xD2BD: 0x74DF, //CJK UNIFIED IDEOGRAPH + 0xD2BE: 0x74F4, //CJK UNIFIED IDEOGRAPH + 0xD2BF: 0x74F5, //CJK UNIFIED IDEOGRAPH + 0xD2C0: 0x7521, //CJK UNIFIED IDEOGRAPH + 0xD2C1: 0x755B, //CJK UNIFIED IDEOGRAPH + 0xD2C2: 0x755F, //CJK UNIFIED IDEOGRAPH + 0xD2C3: 0x75B0, //CJK UNIFIED IDEOGRAPH + 0xD2C4: 0x75C1, //CJK UNIFIED IDEOGRAPH + 0xD2C5: 0x75BB, //CJK UNIFIED IDEOGRAPH + 0xD2C6: 0x75C4, //CJK UNIFIED IDEOGRAPH + 0xD2C7: 0x75C0, //CJK UNIFIED IDEOGRAPH + 0xD2C8: 0x75BF, //CJK UNIFIED IDEOGRAPH + 0xD2C9: 0x75B6, //CJK UNIFIED IDEOGRAPH + 0xD2CA: 0x75BA, //CJK UNIFIED IDEOGRAPH + 0xD2CB: 0x768A, //CJK UNIFIED IDEOGRAPH + 0xD2CC: 0x76C9, //CJK UNIFIED IDEOGRAPH + 0xD2CD: 0x771D, //CJK UNIFIED IDEOGRAPH + 0xD2CE: 0x771B, //CJK UNIFIED IDEOGRAPH + 0xD2CF: 0x7710, //CJK UNIFIED IDEOGRAPH + 0xD2D0: 0x7713, //CJK UNIFIED IDEOGRAPH + 0xD2D1: 0x7712, //CJK UNIFIED IDEOGRAPH + 0xD2D2: 0x7723, //CJK UNIFIED IDEOGRAPH + 0xD2D3: 0x7711, //CJK UNIFIED IDEOGRAPH + 0xD2D4: 0x7715, //CJK UNIFIED IDEOGRAPH + 0xD2D5: 0x7719, //CJK UNIFIED IDEOGRAPH + 0xD2D6: 0x771A, //CJK UNIFIED IDEOGRAPH + 0xD2D7: 0x7722, //CJK UNIFIED IDEOGRAPH + 0xD2D8: 0x7727, //CJK UNIFIED IDEOGRAPH + 0xD2D9: 0x7823, //CJK UNIFIED IDEOGRAPH + 0xD2DA: 0x782C, //CJK UNIFIED IDEOGRAPH + 0xD2DB: 0x7822, //CJK UNIFIED IDEOGRAPH + 0xD2DC: 0x7835, //CJK UNIFIED IDEOGRAPH + 0xD2DD: 0x782F, //CJK UNIFIED IDEOGRAPH + 0xD2DE: 0x7828, //CJK UNIFIED IDEOGRAPH + 0xD2DF: 0x782E, //CJK UNIFIED IDEOGRAPH + 0xD2E0: 0x782B, //CJK UNIFIED IDEOGRAPH + 0xD2E1: 0x7821, //CJK UNIFIED IDEOGRAPH + 0xD2E2: 0x7829, //CJK UNIFIED IDEOGRAPH + 0xD2E3: 0x7833, //CJK UNIFIED IDEOGRAPH + 0xD2E4: 0x782A, //CJK UNIFIED IDEOGRAPH + 0xD2E5: 0x7831, //CJK UNIFIED IDEOGRAPH + 0xD2E6: 0x7954, //CJK UNIFIED IDEOGRAPH + 0xD2E7: 0x795B, //CJK UNIFIED IDEOGRAPH + 0xD2E8: 0x794F, //CJK UNIFIED IDEOGRAPH + 0xD2E9: 0x795C, //CJK UNIFIED IDEOGRAPH + 0xD2EA: 0x7953, //CJK UNIFIED IDEOGRAPH + 0xD2EB: 0x7952, //CJK UNIFIED IDEOGRAPH + 0xD2EC: 0x7951, //CJK UNIFIED IDEOGRAPH + 0xD2ED: 0x79EB, //CJK UNIFIED IDEOGRAPH + 0xD2EE: 0x79EC, //CJK UNIFIED IDEOGRAPH + 0xD2EF: 0x79E0, //CJK UNIFIED IDEOGRAPH + 0xD2F0: 0x79EE, //CJK UNIFIED IDEOGRAPH + 0xD2F1: 0x79ED, //CJK UNIFIED IDEOGRAPH + 0xD2F2: 0x79EA, //CJK UNIFIED IDEOGRAPH + 0xD2F3: 0x79DC, //CJK UNIFIED IDEOGRAPH + 0xD2F4: 0x79DE, //CJK UNIFIED IDEOGRAPH + 0xD2F5: 0x79DD, //CJK UNIFIED IDEOGRAPH + 0xD2F6: 0x7A86, //CJK UNIFIED IDEOGRAPH + 0xD2F7: 0x7A89, //CJK UNIFIED IDEOGRAPH + 0xD2F8: 0x7A85, //CJK UNIFIED IDEOGRAPH + 0xD2F9: 0x7A8B, //CJK UNIFIED IDEOGRAPH + 0xD2FA: 0x7A8C, //CJK UNIFIED IDEOGRAPH + 0xD2FB: 0x7A8A, //CJK UNIFIED IDEOGRAPH + 0xD2FC: 0x7A87, //CJK UNIFIED IDEOGRAPH + 0xD2FD: 0x7AD8, //CJK UNIFIED IDEOGRAPH + 0xD2FE: 0x7B10, //CJK UNIFIED IDEOGRAPH + 0xD340: 0x7B04, //CJK UNIFIED IDEOGRAPH + 0xD341: 0x7B13, //CJK UNIFIED IDEOGRAPH + 0xD342: 0x7B05, //CJK UNIFIED IDEOGRAPH + 0xD343: 0x7B0F, //CJK UNIFIED IDEOGRAPH + 0xD344: 0x7B08, //CJK UNIFIED IDEOGRAPH + 0xD345: 0x7B0A, //CJK UNIFIED IDEOGRAPH + 0xD346: 0x7B0E, //CJK UNIFIED IDEOGRAPH + 0xD347: 0x7B09, //CJK UNIFIED IDEOGRAPH + 0xD348: 0x7B12, //CJK UNIFIED IDEOGRAPH + 0xD349: 0x7C84, //CJK UNIFIED IDEOGRAPH + 0xD34A: 0x7C91, //CJK UNIFIED IDEOGRAPH + 0xD34B: 0x7C8A, //CJK UNIFIED IDEOGRAPH + 0xD34C: 0x7C8C, //CJK UNIFIED IDEOGRAPH + 0xD34D: 0x7C88, //CJK UNIFIED IDEOGRAPH + 0xD34E: 0x7C8D, //CJK UNIFIED IDEOGRAPH + 0xD34F: 0x7C85, //CJK UNIFIED IDEOGRAPH + 0xD350: 0x7D1E, //CJK UNIFIED IDEOGRAPH + 0xD351: 0x7D1D, //CJK UNIFIED IDEOGRAPH + 0xD352: 0x7D11, //CJK UNIFIED IDEOGRAPH + 0xD353: 0x7D0E, //CJK UNIFIED IDEOGRAPH + 0xD354: 0x7D18, //CJK UNIFIED IDEOGRAPH + 0xD355: 0x7D16, //CJK UNIFIED IDEOGRAPH + 0xD356: 0x7D13, //CJK UNIFIED IDEOGRAPH + 0xD357: 0x7D1F, //CJK UNIFIED IDEOGRAPH + 0xD358: 0x7D12, //CJK UNIFIED IDEOGRAPH + 0xD359: 0x7D0F, //CJK UNIFIED IDEOGRAPH + 0xD35A: 0x7D0C, //CJK UNIFIED IDEOGRAPH + 0xD35B: 0x7F5C, //CJK UNIFIED IDEOGRAPH + 0xD35C: 0x7F61, //CJK UNIFIED IDEOGRAPH + 0xD35D: 0x7F5E, //CJK UNIFIED IDEOGRAPH + 0xD35E: 0x7F60, //CJK UNIFIED IDEOGRAPH + 0xD35F: 0x7F5D, //CJK UNIFIED IDEOGRAPH + 0xD360: 0x7F5B, //CJK UNIFIED IDEOGRAPH + 0xD361: 0x7F96, //CJK UNIFIED IDEOGRAPH + 0xD362: 0x7F92, //CJK UNIFIED IDEOGRAPH + 0xD363: 0x7FC3, //CJK UNIFIED IDEOGRAPH + 0xD364: 0x7FC2, //CJK UNIFIED IDEOGRAPH + 0xD365: 0x7FC0, //CJK UNIFIED IDEOGRAPH + 0xD366: 0x8016, //CJK UNIFIED IDEOGRAPH + 0xD367: 0x803E, //CJK UNIFIED IDEOGRAPH + 0xD368: 0x8039, //CJK UNIFIED IDEOGRAPH + 0xD369: 0x80FA, //CJK UNIFIED IDEOGRAPH + 0xD36A: 0x80F2, //CJK UNIFIED IDEOGRAPH + 0xD36B: 0x80F9, //CJK UNIFIED IDEOGRAPH + 0xD36C: 0x80F5, //CJK UNIFIED IDEOGRAPH + 0xD36D: 0x8101, //CJK UNIFIED IDEOGRAPH + 0xD36E: 0x80FB, //CJK UNIFIED IDEOGRAPH + 0xD36F: 0x8100, //CJK UNIFIED IDEOGRAPH + 0xD370: 0x8201, //CJK UNIFIED IDEOGRAPH + 0xD371: 0x822F, //CJK UNIFIED IDEOGRAPH + 0xD372: 0x8225, //CJK UNIFIED IDEOGRAPH + 0xD373: 0x8333, //CJK UNIFIED IDEOGRAPH + 0xD374: 0x832D, //CJK UNIFIED IDEOGRAPH + 0xD375: 0x8344, //CJK UNIFIED IDEOGRAPH + 0xD376: 0x8319, //CJK UNIFIED IDEOGRAPH + 0xD377: 0x8351, //CJK UNIFIED IDEOGRAPH + 0xD378: 0x8325, //CJK UNIFIED IDEOGRAPH + 0xD379: 0x8356, //CJK UNIFIED IDEOGRAPH + 0xD37A: 0x833F, //CJK UNIFIED IDEOGRAPH + 0xD37B: 0x8341, //CJK UNIFIED IDEOGRAPH + 0xD37C: 0x8326, //CJK UNIFIED IDEOGRAPH + 0xD37D: 0x831C, //CJK UNIFIED IDEOGRAPH + 0xD37E: 0x8322, //CJK UNIFIED IDEOGRAPH + 0xD3A1: 0x8342, //CJK UNIFIED IDEOGRAPH + 0xD3A2: 0x834E, //CJK UNIFIED IDEOGRAPH + 0xD3A3: 0x831B, //CJK UNIFIED IDEOGRAPH + 0xD3A4: 0x832A, //CJK UNIFIED IDEOGRAPH + 0xD3A5: 0x8308, //CJK UNIFIED IDEOGRAPH + 0xD3A6: 0x833C, //CJK UNIFIED IDEOGRAPH + 0xD3A7: 0x834D, //CJK UNIFIED IDEOGRAPH + 0xD3A8: 0x8316, //CJK UNIFIED IDEOGRAPH + 0xD3A9: 0x8324, //CJK UNIFIED IDEOGRAPH + 0xD3AA: 0x8320, //CJK UNIFIED IDEOGRAPH + 0xD3AB: 0x8337, //CJK UNIFIED IDEOGRAPH + 0xD3AC: 0x832F, //CJK UNIFIED IDEOGRAPH + 0xD3AD: 0x8329, //CJK UNIFIED IDEOGRAPH + 0xD3AE: 0x8347, //CJK UNIFIED IDEOGRAPH + 0xD3AF: 0x8345, //CJK UNIFIED IDEOGRAPH + 0xD3B0: 0x834C, //CJK UNIFIED IDEOGRAPH + 0xD3B1: 0x8353, //CJK UNIFIED IDEOGRAPH + 0xD3B2: 0x831E, //CJK UNIFIED IDEOGRAPH + 0xD3B3: 0x832C, //CJK UNIFIED IDEOGRAPH + 0xD3B4: 0x834B, //CJK UNIFIED IDEOGRAPH + 0xD3B5: 0x8327, //CJK UNIFIED IDEOGRAPH + 0xD3B6: 0x8348, //CJK UNIFIED IDEOGRAPH + 0xD3B7: 0x8653, //CJK UNIFIED IDEOGRAPH + 0xD3B8: 0x8652, //CJK UNIFIED IDEOGRAPH + 0xD3B9: 0x86A2, //CJK UNIFIED IDEOGRAPH + 0xD3BA: 0x86A8, //CJK UNIFIED IDEOGRAPH + 0xD3BB: 0x8696, //CJK UNIFIED IDEOGRAPH + 0xD3BC: 0x868D, //CJK UNIFIED IDEOGRAPH + 0xD3BD: 0x8691, //CJK UNIFIED IDEOGRAPH + 0xD3BE: 0x869E, //CJK UNIFIED IDEOGRAPH + 0xD3BF: 0x8687, //CJK UNIFIED IDEOGRAPH + 0xD3C0: 0x8697, //CJK UNIFIED IDEOGRAPH + 0xD3C1: 0x8686, //CJK UNIFIED IDEOGRAPH + 0xD3C2: 0x868B, //CJK UNIFIED IDEOGRAPH + 0xD3C3: 0x869A, //CJK UNIFIED IDEOGRAPH + 0xD3C4: 0x8685, //CJK UNIFIED IDEOGRAPH + 0xD3C5: 0x86A5, //CJK UNIFIED IDEOGRAPH + 0xD3C6: 0x8699, //CJK UNIFIED IDEOGRAPH + 0xD3C7: 0x86A1, //CJK UNIFIED IDEOGRAPH + 0xD3C8: 0x86A7, //CJK UNIFIED IDEOGRAPH + 0xD3C9: 0x8695, //CJK UNIFIED IDEOGRAPH + 0xD3CA: 0x8698, //CJK UNIFIED IDEOGRAPH + 0xD3CB: 0x868E, //CJK UNIFIED IDEOGRAPH + 0xD3CC: 0x869D, //CJK UNIFIED IDEOGRAPH + 0xD3CD: 0x8690, //CJK UNIFIED IDEOGRAPH + 0xD3CE: 0x8694, //CJK UNIFIED IDEOGRAPH + 0xD3CF: 0x8843, //CJK UNIFIED IDEOGRAPH + 0xD3D0: 0x8844, //CJK UNIFIED IDEOGRAPH + 0xD3D1: 0x886D, //CJK UNIFIED IDEOGRAPH + 0xD3D2: 0x8875, //CJK UNIFIED IDEOGRAPH + 0xD3D3: 0x8876, //CJK UNIFIED IDEOGRAPH + 0xD3D4: 0x8872, //CJK UNIFIED IDEOGRAPH + 0xD3D5: 0x8880, //CJK UNIFIED IDEOGRAPH + 0xD3D6: 0x8871, //CJK UNIFIED IDEOGRAPH + 0xD3D7: 0x887F, //CJK UNIFIED IDEOGRAPH + 0xD3D8: 0x886F, //CJK UNIFIED IDEOGRAPH + 0xD3D9: 0x8883, //CJK UNIFIED IDEOGRAPH + 0xD3DA: 0x887E, //CJK UNIFIED IDEOGRAPH + 0xD3DB: 0x8874, //CJK UNIFIED IDEOGRAPH + 0xD3DC: 0x887C, //CJK UNIFIED IDEOGRAPH + 0xD3DD: 0x8A12, //CJK UNIFIED IDEOGRAPH + 0xD3DE: 0x8C47, //CJK UNIFIED IDEOGRAPH + 0xD3DF: 0x8C57, //CJK UNIFIED IDEOGRAPH + 0xD3E0: 0x8C7B, //CJK UNIFIED IDEOGRAPH + 0xD3E1: 0x8CA4, //CJK UNIFIED IDEOGRAPH + 0xD3E2: 0x8CA3, //CJK UNIFIED IDEOGRAPH + 0xD3E3: 0x8D76, //CJK UNIFIED IDEOGRAPH + 0xD3E4: 0x8D78, //CJK UNIFIED IDEOGRAPH + 0xD3E5: 0x8DB5, //CJK UNIFIED IDEOGRAPH + 0xD3E6: 0x8DB7, //CJK UNIFIED IDEOGRAPH + 0xD3E7: 0x8DB6, //CJK UNIFIED IDEOGRAPH + 0xD3E8: 0x8ED1, //CJK UNIFIED IDEOGRAPH + 0xD3E9: 0x8ED3, //CJK UNIFIED IDEOGRAPH + 0xD3EA: 0x8FFE, //CJK UNIFIED IDEOGRAPH + 0xD3EB: 0x8FF5, //CJK UNIFIED IDEOGRAPH + 0xD3EC: 0x9002, //CJK UNIFIED IDEOGRAPH + 0xD3ED: 0x8FFF, //CJK UNIFIED IDEOGRAPH + 0xD3EE: 0x8FFB, //CJK UNIFIED IDEOGRAPH + 0xD3EF: 0x9004, //CJK UNIFIED IDEOGRAPH + 0xD3F0: 0x8FFC, //CJK UNIFIED IDEOGRAPH + 0xD3F1: 0x8FF6, //CJK UNIFIED IDEOGRAPH + 0xD3F2: 0x90D6, //CJK UNIFIED IDEOGRAPH + 0xD3F3: 0x90E0, //CJK UNIFIED IDEOGRAPH + 0xD3F4: 0x90D9, //CJK UNIFIED IDEOGRAPH + 0xD3F5: 0x90DA, //CJK UNIFIED IDEOGRAPH + 0xD3F6: 0x90E3, //CJK UNIFIED IDEOGRAPH + 0xD3F7: 0x90DF, //CJK UNIFIED IDEOGRAPH + 0xD3F8: 0x90E5, //CJK UNIFIED IDEOGRAPH + 0xD3F9: 0x90D8, //CJK UNIFIED IDEOGRAPH + 0xD3FA: 0x90DB, //CJK UNIFIED IDEOGRAPH + 0xD3FB: 0x90D7, //CJK UNIFIED IDEOGRAPH + 0xD3FC: 0x90DC, //CJK UNIFIED IDEOGRAPH + 0xD3FD: 0x90E4, //CJK UNIFIED IDEOGRAPH + 0xD3FE: 0x9150, //CJK UNIFIED IDEOGRAPH + 0xD440: 0x914E, //CJK UNIFIED IDEOGRAPH + 0xD441: 0x914F, //CJK UNIFIED IDEOGRAPH + 0xD442: 0x91D5, //CJK UNIFIED IDEOGRAPH + 0xD443: 0x91E2, //CJK UNIFIED IDEOGRAPH + 0xD444: 0x91DA, //CJK UNIFIED IDEOGRAPH + 0xD445: 0x965C, //CJK UNIFIED IDEOGRAPH + 0xD446: 0x965F, //CJK UNIFIED IDEOGRAPH + 0xD447: 0x96BC, //CJK UNIFIED IDEOGRAPH + 0xD448: 0x98E3, //CJK UNIFIED IDEOGRAPH + 0xD449: 0x9ADF, //CJK UNIFIED IDEOGRAPH + 0xD44A: 0x9B2F, //CJK UNIFIED IDEOGRAPH + 0xD44B: 0x4E7F, //CJK UNIFIED IDEOGRAPH + 0xD44C: 0x5070, //CJK UNIFIED IDEOGRAPH + 0xD44D: 0x506A, //CJK UNIFIED IDEOGRAPH + 0xD44E: 0x5061, //CJK UNIFIED IDEOGRAPH + 0xD44F: 0x505E, //CJK UNIFIED IDEOGRAPH + 0xD450: 0x5060, //CJK UNIFIED IDEOGRAPH + 0xD451: 0x5053, //CJK UNIFIED IDEOGRAPH + 0xD452: 0x504B, //CJK UNIFIED IDEOGRAPH + 0xD453: 0x505D, //CJK UNIFIED IDEOGRAPH + 0xD454: 0x5072, //CJK UNIFIED IDEOGRAPH + 0xD455: 0x5048, //CJK UNIFIED IDEOGRAPH + 0xD456: 0x504D, //CJK UNIFIED IDEOGRAPH + 0xD457: 0x5041, //CJK UNIFIED IDEOGRAPH + 0xD458: 0x505B, //CJK UNIFIED IDEOGRAPH + 0xD459: 0x504A, //CJK UNIFIED IDEOGRAPH + 0xD45A: 0x5062, //CJK UNIFIED IDEOGRAPH + 0xD45B: 0x5015, //CJK UNIFIED IDEOGRAPH + 0xD45C: 0x5045, //CJK UNIFIED IDEOGRAPH + 0xD45D: 0x505F, //CJK UNIFIED IDEOGRAPH + 0xD45E: 0x5069, //CJK UNIFIED IDEOGRAPH + 0xD45F: 0x506B, //CJK UNIFIED IDEOGRAPH + 0xD460: 0x5063, //CJK UNIFIED IDEOGRAPH + 0xD461: 0x5064, //CJK UNIFIED IDEOGRAPH + 0xD462: 0x5046, //CJK UNIFIED IDEOGRAPH + 0xD463: 0x5040, //CJK UNIFIED IDEOGRAPH + 0xD464: 0x506E, //CJK UNIFIED IDEOGRAPH + 0xD465: 0x5073, //CJK UNIFIED IDEOGRAPH + 0xD466: 0x5057, //CJK UNIFIED IDEOGRAPH + 0xD467: 0x5051, //CJK UNIFIED IDEOGRAPH + 0xD468: 0x51D0, //CJK UNIFIED IDEOGRAPH + 0xD469: 0x526B, //CJK UNIFIED IDEOGRAPH + 0xD46A: 0x526D, //CJK UNIFIED IDEOGRAPH + 0xD46B: 0x526C, //CJK UNIFIED IDEOGRAPH + 0xD46C: 0x526E, //CJK UNIFIED IDEOGRAPH + 0xD46D: 0x52D6, //CJK UNIFIED IDEOGRAPH + 0xD46E: 0x52D3, //CJK UNIFIED IDEOGRAPH + 0xD46F: 0x532D, //CJK UNIFIED IDEOGRAPH + 0xD470: 0x539C, //CJK UNIFIED IDEOGRAPH + 0xD471: 0x5575, //CJK UNIFIED IDEOGRAPH + 0xD472: 0x5576, //CJK UNIFIED IDEOGRAPH + 0xD473: 0x553C, //CJK UNIFIED IDEOGRAPH + 0xD474: 0x554D, //CJK UNIFIED IDEOGRAPH + 0xD475: 0x5550, //CJK UNIFIED IDEOGRAPH + 0xD476: 0x5534, //CJK UNIFIED IDEOGRAPH + 0xD477: 0x552A, //CJK UNIFIED IDEOGRAPH + 0xD478: 0x5551, //CJK UNIFIED IDEOGRAPH + 0xD479: 0x5562, //CJK UNIFIED IDEOGRAPH + 0xD47A: 0x5536, //CJK UNIFIED IDEOGRAPH + 0xD47B: 0x5535, //CJK UNIFIED IDEOGRAPH + 0xD47C: 0x5530, //CJK UNIFIED IDEOGRAPH + 0xD47D: 0x5552, //CJK UNIFIED IDEOGRAPH + 0xD47E: 0x5545, //CJK UNIFIED IDEOGRAPH + 0xD4A1: 0x550C, //CJK UNIFIED IDEOGRAPH + 0xD4A2: 0x5532, //CJK UNIFIED IDEOGRAPH + 0xD4A3: 0x5565, //CJK UNIFIED IDEOGRAPH + 0xD4A4: 0x554E, //CJK UNIFIED IDEOGRAPH + 0xD4A5: 0x5539, //CJK UNIFIED IDEOGRAPH + 0xD4A6: 0x5548, //CJK UNIFIED IDEOGRAPH + 0xD4A7: 0x552D, //CJK UNIFIED IDEOGRAPH + 0xD4A8: 0x553B, //CJK UNIFIED IDEOGRAPH + 0xD4A9: 0x5540, //CJK UNIFIED IDEOGRAPH + 0xD4AA: 0x554B, //CJK UNIFIED IDEOGRAPH + 0xD4AB: 0x570A, //CJK UNIFIED IDEOGRAPH + 0xD4AC: 0x5707, //CJK UNIFIED IDEOGRAPH + 0xD4AD: 0x57FB, //CJK UNIFIED IDEOGRAPH + 0xD4AE: 0x5814, //CJK UNIFIED IDEOGRAPH + 0xD4AF: 0x57E2, //CJK UNIFIED IDEOGRAPH + 0xD4B0: 0x57F6, //CJK UNIFIED IDEOGRAPH + 0xD4B1: 0x57DC, //CJK UNIFIED IDEOGRAPH + 0xD4B2: 0x57F4, //CJK UNIFIED IDEOGRAPH + 0xD4B3: 0x5800, //CJK UNIFIED IDEOGRAPH + 0xD4B4: 0x57ED, //CJK UNIFIED IDEOGRAPH + 0xD4B5: 0x57FD, //CJK UNIFIED IDEOGRAPH + 0xD4B6: 0x5808, //CJK UNIFIED IDEOGRAPH + 0xD4B7: 0x57F8, //CJK UNIFIED IDEOGRAPH + 0xD4B8: 0x580B, //CJK UNIFIED IDEOGRAPH + 0xD4B9: 0x57F3, //CJK UNIFIED IDEOGRAPH + 0xD4BA: 0x57CF, //CJK UNIFIED IDEOGRAPH + 0xD4BB: 0x5807, //CJK UNIFIED IDEOGRAPH + 0xD4BC: 0x57EE, //CJK UNIFIED IDEOGRAPH + 0xD4BD: 0x57E3, //CJK UNIFIED IDEOGRAPH + 0xD4BE: 0x57F2, //CJK UNIFIED IDEOGRAPH + 0xD4BF: 0x57E5, //CJK UNIFIED IDEOGRAPH + 0xD4C0: 0x57EC, //CJK UNIFIED IDEOGRAPH + 0xD4C1: 0x57E1, //CJK UNIFIED IDEOGRAPH + 0xD4C2: 0x580E, //CJK UNIFIED IDEOGRAPH + 0xD4C3: 0x57FC, //CJK UNIFIED IDEOGRAPH + 0xD4C4: 0x5810, //CJK UNIFIED IDEOGRAPH + 0xD4C5: 0x57E7, //CJK UNIFIED IDEOGRAPH + 0xD4C6: 0x5801, //CJK UNIFIED IDEOGRAPH + 0xD4C7: 0x580C, //CJK UNIFIED IDEOGRAPH + 0xD4C8: 0x57F1, //CJK UNIFIED IDEOGRAPH + 0xD4C9: 0x57E9, //CJK UNIFIED IDEOGRAPH + 0xD4CA: 0x57F0, //CJK UNIFIED IDEOGRAPH + 0xD4CB: 0x580D, //CJK UNIFIED IDEOGRAPH + 0xD4CC: 0x5804, //CJK UNIFIED IDEOGRAPH + 0xD4CD: 0x595C, //CJK UNIFIED IDEOGRAPH + 0xD4CE: 0x5A60, //CJK UNIFIED IDEOGRAPH + 0xD4CF: 0x5A58, //CJK UNIFIED IDEOGRAPH + 0xD4D0: 0x5A55, //CJK UNIFIED IDEOGRAPH + 0xD4D1: 0x5A67, //CJK UNIFIED IDEOGRAPH + 0xD4D2: 0x5A5E, //CJK UNIFIED IDEOGRAPH + 0xD4D3: 0x5A38, //CJK UNIFIED IDEOGRAPH + 0xD4D4: 0x5A35, //CJK UNIFIED IDEOGRAPH + 0xD4D5: 0x5A6D, //CJK UNIFIED IDEOGRAPH + 0xD4D6: 0x5A50, //CJK UNIFIED IDEOGRAPH + 0xD4D7: 0x5A5F, //CJK UNIFIED IDEOGRAPH + 0xD4D8: 0x5A65, //CJK UNIFIED IDEOGRAPH + 0xD4D9: 0x5A6C, //CJK UNIFIED IDEOGRAPH + 0xD4DA: 0x5A53, //CJK UNIFIED IDEOGRAPH + 0xD4DB: 0x5A64, //CJK UNIFIED IDEOGRAPH + 0xD4DC: 0x5A57, //CJK UNIFIED IDEOGRAPH + 0xD4DD: 0x5A43, //CJK UNIFIED IDEOGRAPH + 0xD4DE: 0x5A5D, //CJK UNIFIED IDEOGRAPH + 0xD4DF: 0x5A52, //CJK UNIFIED IDEOGRAPH + 0xD4E0: 0x5A44, //CJK UNIFIED IDEOGRAPH + 0xD4E1: 0x5A5B, //CJK UNIFIED IDEOGRAPH + 0xD4E2: 0x5A48, //CJK UNIFIED IDEOGRAPH + 0xD4E3: 0x5A8E, //CJK UNIFIED IDEOGRAPH + 0xD4E4: 0x5A3E, //CJK UNIFIED IDEOGRAPH + 0xD4E5: 0x5A4D, //CJK UNIFIED IDEOGRAPH + 0xD4E6: 0x5A39, //CJK UNIFIED IDEOGRAPH + 0xD4E7: 0x5A4C, //CJK UNIFIED IDEOGRAPH + 0xD4E8: 0x5A70, //CJK UNIFIED IDEOGRAPH + 0xD4E9: 0x5A69, //CJK UNIFIED IDEOGRAPH + 0xD4EA: 0x5A47, //CJK UNIFIED IDEOGRAPH + 0xD4EB: 0x5A51, //CJK UNIFIED IDEOGRAPH + 0xD4EC: 0x5A56, //CJK UNIFIED IDEOGRAPH + 0xD4ED: 0x5A42, //CJK UNIFIED IDEOGRAPH + 0xD4EE: 0x5A5C, //CJK UNIFIED IDEOGRAPH + 0xD4EF: 0x5B72, //CJK UNIFIED IDEOGRAPH + 0xD4F0: 0x5B6E, //CJK UNIFIED IDEOGRAPH + 0xD4F1: 0x5BC1, //CJK UNIFIED IDEOGRAPH + 0xD4F2: 0x5BC0, //CJK UNIFIED IDEOGRAPH + 0xD4F3: 0x5C59, //CJK UNIFIED IDEOGRAPH + 0xD4F4: 0x5D1E, //CJK UNIFIED IDEOGRAPH + 0xD4F5: 0x5D0B, //CJK UNIFIED IDEOGRAPH + 0xD4F6: 0x5D1D, //CJK UNIFIED IDEOGRAPH + 0xD4F7: 0x5D1A, //CJK UNIFIED IDEOGRAPH + 0xD4F8: 0x5D20, //CJK UNIFIED IDEOGRAPH + 0xD4F9: 0x5D0C, //CJK UNIFIED IDEOGRAPH + 0xD4FA: 0x5D28, //CJK UNIFIED IDEOGRAPH + 0xD4FB: 0x5D0D, //CJK UNIFIED IDEOGRAPH + 0xD4FC: 0x5D26, //CJK UNIFIED IDEOGRAPH + 0xD4FD: 0x5D25, //CJK UNIFIED IDEOGRAPH + 0xD4FE: 0x5D0F, //CJK UNIFIED IDEOGRAPH + 0xD540: 0x5D30, //CJK UNIFIED IDEOGRAPH + 0xD541: 0x5D12, //CJK UNIFIED IDEOGRAPH + 0xD542: 0x5D23, //CJK UNIFIED IDEOGRAPH + 0xD543: 0x5D1F, //CJK UNIFIED IDEOGRAPH + 0xD544: 0x5D2E, //CJK UNIFIED IDEOGRAPH + 0xD545: 0x5E3E, //CJK UNIFIED IDEOGRAPH + 0xD546: 0x5E34, //CJK UNIFIED IDEOGRAPH + 0xD547: 0x5EB1, //CJK UNIFIED IDEOGRAPH + 0xD548: 0x5EB4, //CJK UNIFIED IDEOGRAPH + 0xD549: 0x5EB9, //CJK UNIFIED IDEOGRAPH + 0xD54A: 0x5EB2, //CJK UNIFIED IDEOGRAPH + 0xD54B: 0x5EB3, //CJK UNIFIED IDEOGRAPH + 0xD54C: 0x5F36, //CJK UNIFIED IDEOGRAPH + 0xD54D: 0x5F38, //CJK UNIFIED IDEOGRAPH + 0xD54E: 0x5F9B, //CJK UNIFIED IDEOGRAPH + 0xD54F: 0x5F96, //CJK UNIFIED IDEOGRAPH + 0xD550: 0x5F9F, //CJK UNIFIED IDEOGRAPH + 0xD551: 0x608A, //CJK UNIFIED IDEOGRAPH + 0xD552: 0x6090, //CJK UNIFIED IDEOGRAPH + 0xD553: 0x6086, //CJK UNIFIED IDEOGRAPH + 0xD554: 0x60BE, //CJK UNIFIED IDEOGRAPH + 0xD555: 0x60B0, //CJK UNIFIED IDEOGRAPH + 0xD556: 0x60BA, //CJK UNIFIED IDEOGRAPH + 0xD557: 0x60D3, //CJK UNIFIED IDEOGRAPH + 0xD558: 0x60D4, //CJK UNIFIED IDEOGRAPH + 0xD559: 0x60CF, //CJK UNIFIED IDEOGRAPH + 0xD55A: 0x60E4, //CJK UNIFIED IDEOGRAPH + 0xD55B: 0x60D9, //CJK UNIFIED IDEOGRAPH + 0xD55C: 0x60DD, //CJK UNIFIED IDEOGRAPH + 0xD55D: 0x60C8, //CJK UNIFIED IDEOGRAPH + 0xD55E: 0x60B1, //CJK UNIFIED IDEOGRAPH + 0xD55F: 0x60DB, //CJK UNIFIED IDEOGRAPH + 0xD560: 0x60B7, //CJK UNIFIED IDEOGRAPH + 0xD561: 0x60CA, //CJK UNIFIED IDEOGRAPH + 0xD562: 0x60BF, //CJK UNIFIED IDEOGRAPH + 0xD563: 0x60C3, //CJK UNIFIED IDEOGRAPH + 0xD564: 0x60CD, //CJK UNIFIED IDEOGRAPH + 0xD565: 0x60C0, //CJK UNIFIED IDEOGRAPH + 0xD566: 0x6332, //CJK UNIFIED IDEOGRAPH + 0xD567: 0x6365, //CJK UNIFIED IDEOGRAPH + 0xD568: 0x638A, //CJK UNIFIED IDEOGRAPH + 0xD569: 0x6382, //CJK UNIFIED IDEOGRAPH + 0xD56A: 0x637D, //CJK UNIFIED IDEOGRAPH + 0xD56B: 0x63BD, //CJK UNIFIED IDEOGRAPH + 0xD56C: 0x639E, //CJK UNIFIED IDEOGRAPH + 0xD56D: 0x63AD, //CJK UNIFIED IDEOGRAPH + 0xD56E: 0x639D, //CJK UNIFIED IDEOGRAPH + 0xD56F: 0x6397, //CJK UNIFIED IDEOGRAPH + 0xD570: 0x63AB, //CJK UNIFIED IDEOGRAPH + 0xD571: 0x638E, //CJK UNIFIED IDEOGRAPH + 0xD572: 0x636F, //CJK UNIFIED IDEOGRAPH + 0xD573: 0x6387, //CJK UNIFIED IDEOGRAPH + 0xD574: 0x6390, //CJK UNIFIED IDEOGRAPH + 0xD575: 0x636E, //CJK UNIFIED IDEOGRAPH + 0xD576: 0x63AF, //CJK UNIFIED IDEOGRAPH + 0xD577: 0x6375, //CJK UNIFIED IDEOGRAPH + 0xD578: 0x639C, //CJK UNIFIED IDEOGRAPH + 0xD579: 0x636D, //CJK UNIFIED IDEOGRAPH + 0xD57A: 0x63AE, //CJK UNIFIED IDEOGRAPH + 0xD57B: 0x637C, //CJK UNIFIED IDEOGRAPH + 0xD57C: 0x63A4, //CJK UNIFIED IDEOGRAPH + 0xD57D: 0x633B, //CJK UNIFIED IDEOGRAPH + 0xD57E: 0x639F, //CJK UNIFIED IDEOGRAPH + 0xD5A1: 0x6378, //CJK UNIFIED IDEOGRAPH + 0xD5A2: 0x6385, //CJK UNIFIED IDEOGRAPH + 0xD5A3: 0x6381, //CJK UNIFIED IDEOGRAPH + 0xD5A4: 0x6391, //CJK UNIFIED IDEOGRAPH + 0xD5A5: 0x638D, //CJK UNIFIED IDEOGRAPH + 0xD5A6: 0x6370, //CJK UNIFIED IDEOGRAPH + 0xD5A7: 0x6553, //CJK UNIFIED IDEOGRAPH + 0xD5A8: 0x65CD, //CJK UNIFIED IDEOGRAPH + 0xD5A9: 0x6665, //CJK UNIFIED IDEOGRAPH + 0xD5AA: 0x6661, //CJK UNIFIED IDEOGRAPH + 0xD5AB: 0x665B, //CJK UNIFIED IDEOGRAPH + 0xD5AC: 0x6659, //CJK UNIFIED IDEOGRAPH + 0xD5AD: 0x665C, //CJK UNIFIED IDEOGRAPH + 0xD5AE: 0x6662, //CJK UNIFIED IDEOGRAPH + 0xD5AF: 0x6718, //CJK UNIFIED IDEOGRAPH + 0xD5B0: 0x6879, //CJK UNIFIED IDEOGRAPH + 0xD5B1: 0x6887, //CJK UNIFIED IDEOGRAPH + 0xD5B2: 0x6890, //CJK UNIFIED IDEOGRAPH + 0xD5B3: 0x689C, //CJK UNIFIED IDEOGRAPH + 0xD5B4: 0x686D, //CJK UNIFIED IDEOGRAPH + 0xD5B5: 0x686E, //CJK UNIFIED IDEOGRAPH + 0xD5B6: 0x68AE, //CJK UNIFIED IDEOGRAPH + 0xD5B7: 0x68AB, //CJK UNIFIED IDEOGRAPH + 0xD5B8: 0x6956, //CJK UNIFIED IDEOGRAPH + 0xD5B9: 0x686F, //CJK UNIFIED IDEOGRAPH + 0xD5BA: 0x68A3, //CJK UNIFIED IDEOGRAPH + 0xD5BB: 0x68AC, //CJK UNIFIED IDEOGRAPH + 0xD5BC: 0x68A9, //CJK UNIFIED IDEOGRAPH + 0xD5BD: 0x6875, //CJK UNIFIED IDEOGRAPH + 0xD5BE: 0x6874, //CJK UNIFIED IDEOGRAPH + 0xD5BF: 0x68B2, //CJK UNIFIED IDEOGRAPH + 0xD5C0: 0x688F, //CJK UNIFIED IDEOGRAPH + 0xD5C1: 0x6877, //CJK UNIFIED IDEOGRAPH + 0xD5C2: 0x6892, //CJK UNIFIED IDEOGRAPH + 0xD5C3: 0x687C, //CJK UNIFIED IDEOGRAPH + 0xD5C4: 0x686B, //CJK UNIFIED IDEOGRAPH + 0xD5C5: 0x6872, //CJK UNIFIED IDEOGRAPH + 0xD5C6: 0x68AA, //CJK UNIFIED IDEOGRAPH + 0xD5C7: 0x6880, //CJK UNIFIED IDEOGRAPH + 0xD5C8: 0x6871, //CJK UNIFIED IDEOGRAPH + 0xD5C9: 0x687E, //CJK UNIFIED IDEOGRAPH + 0xD5CA: 0x689B, //CJK UNIFIED IDEOGRAPH + 0xD5CB: 0x6896, //CJK UNIFIED IDEOGRAPH + 0xD5CC: 0x688B, //CJK UNIFIED IDEOGRAPH + 0xD5CD: 0x68A0, //CJK UNIFIED IDEOGRAPH + 0xD5CE: 0x6889, //CJK UNIFIED IDEOGRAPH + 0xD5CF: 0x68A4, //CJK UNIFIED IDEOGRAPH + 0xD5D0: 0x6878, //CJK UNIFIED IDEOGRAPH + 0xD5D1: 0x687B, //CJK UNIFIED IDEOGRAPH + 0xD5D2: 0x6891, //CJK UNIFIED IDEOGRAPH + 0xD5D3: 0x688C, //CJK UNIFIED IDEOGRAPH + 0xD5D4: 0x688A, //CJK UNIFIED IDEOGRAPH + 0xD5D5: 0x687D, //CJK UNIFIED IDEOGRAPH + 0xD5D6: 0x6B36, //CJK UNIFIED IDEOGRAPH + 0xD5D7: 0x6B33, //CJK UNIFIED IDEOGRAPH + 0xD5D8: 0x6B37, //CJK UNIFIED IDEOGRAPH + 0xD5D9: 0x6B38, //CJK UNIFIED IDEOGRAPH + 0xD5DA: 0x6B91, //CJK UNIFIED IDEOGRAPH + 0xD5DB: 0x6B8F, //CJK UNIFIED IDEOGRAPH + 0xD5DC: 0x6B8D, //CJK UNIFIED IDEOGRAPH + 0xD5DD: 0x6B8E, //CJK UNIFIED IDEOGRAPH + 0xD5DE: 0x6B8C, //CJK UNIFIED IDEOGRAPH + 0xD5DF: 0x6C2A, //CJK UNIFIED IDEOGRAPH + 0xD5E0: 0x6DC0, //CJK UNIFIED IDEOGRAPH + 0xD5E1: 0x6DAB, //CJK UNIFIED IDEOGRAPH + 0xD5E2: 0x6DB4, //CJK UNIFIED IDEOGRAPH + 0xD5E3: 0x6DB3, //CJK UNIFIED IDEOGRAPH + 0xD5E4: 0x6E74, //CJK UNIFIED IDEOGRAPH + 0xD5E5: 0x6DAC, //CJK UNIFIED IDEOGRAPH + 0xD5E6: 0x6DE9, //CJK UNIFIED IDEOGRAPH + 0xD5E7: 0x6DE2, //CJK UNIFIED IDEOGRAPH + 0xD5E8: 0x6DB7, //CJK UNIFIED IDEOGRAPH + 0xD5E9: 0x6DF6, //CJK UNIFIED IDEOGRAPH + 0xD5EA: 0x6DD4, //CJK UNIFIED IDEOGRAPH + 0xD5EB: 0x6E00, //CJK UNIFIED IDEOGRAPH + 0xD5EC: 0x6DC8, //CJK UNIFIED IDEOGRAPH + 0xD5ED: 0x6DE0, //CJK UNIFIED IDEOGRAPH + 0xD5EE: 0x6DDF, //CJK UNIFIED IDEOGRAPH + 0xD5EF: 0x6DD6, //CJK UNIFIED IDEOGRAPH + 0xD5F0: 0x6DBE, //CJK UNIFIED IDEOGRAPH + 0xD5F1: 0x6DE5, //CJK UNIFIED IDEOGRAPH + 0xD5F2: 0x6DDC, //CJK UNIFIED IDEOGRAPH + 0xD5F3: 0x6DDD, //CJK UNIFIED IDEOGRAPH + 0xD5F4: 0x6DDB, //CJK UNIFIED IDEOGRAPH + 0xD5F5: 0x6DF4, //CJK UNIFIED IDEOGRAPH + 0xD5F6: 0x6DCA, //CJK UNIFIED IDEOGRAPH + 0xD5F7: 0x6DBD, //CJK UNIFIED IDEOGRAPH + 0xD5F8: 0x6DED, //CJK UNIFIED IDEOGRAPH + 0xD5F9: 0x6DF0, //CJK UNIFIED IDEOGRAPH + 0xD5FA: 0x6DBA, //CJK UNIFIED IDEOGRAPH + 0xD5FB: 0x6DD5, //CJK UNIFIED IDEOGRAPH + 0xD5FC: 0x6DC2, //CJK UNIFIED IDEOGRAPH + 0xD5FD: 0x6DCF, //CJK UNIFIED IDEOGRAPH + 0xD5FE: 0x6DC9, //CJK UNIFIED IDEOGRAPH + 0xD640: 0x6DD0, //CJK UNIFIED IDEOGRAPH + 0xD641: 0x6DF2, //CJK UNIFIED IDEOGRAPH + 0xD642: 0x6DD3, //CJK UNIFIED IDEOGRAPH + 0xD643: 0x6DFD, //CJK UNIFIED IDEOGRAPH + 0xD644: 0x6DD7, //CJK UNIFIED IDEOGRAPH + 0xD645: 0x6DCD, //CJK UNIFIED IDEOGRAPH + 0xD646: 0x6DE3, //CJK UNIFIED IDEOGRAPH + 0xD647: 0x6DBB, //CJK UNIFIED IDEOGRAPH + 0xD648: 0x70FA, //CJK UNIFIED IDEOGRAPH + 0xD649: 0x710D, //CJK UNIFIED IDEOGRAPH + 0xD64A: 0x70F7, //CJK UNIFIED IDEOGRAPH + 0xD64B: 0x7117, //CJK UNIFIED IDEOGRAPH + 0xD64C: 0x70F4, //CJK UNIFIED IDEOGRAPH + 0xD64D: 0x710C, //CJK UNIFIED IDEOGRAPH + 0xD64E: 0x70F0, //CJK UNIFIED IDEOGRAPH + 0xD64F: 0x7104, //CJK UNIFIED IDEOGRAPH + 0xD650: 0x70F3, //CJK UNIFIED IDEOGRAPH + 0xD651: 0x7110, //CJK UNIFIED IDEOGRAPH + 0xD652: 0x70FC, //CJK UNIFIED IDEOGRAPH + 0xD653: 0x70FF, //CJK UNIFIED IDEOGRAPH + 0xD654: 0x7106, //CJK UNIFIED IDEOGRAPH + 0xD655: 0x7113, //CJK UNIFIED IDEOGRAPH + 0xD656: 0x7100, //CJK UNIFIED IDEOGRAPH + 0xD657: 0x70F8, //CJK UNIFIED IDEOGRAPH + 0xD658: 0x70F6, //CJK UNIFIED IDEOGRAPH + 0xD659: 0x710B, //CJK UNIFIED IDEOGRAPH + 0xD65A: 0x7102, //CJK UNIFIED IDEOGRAPH + 0xD65B: 0x710E, //CJK UNIFIED IDEOGRAPH + 0xD65C: 0x727E, //CJK UNIFIED IDEOGRAPH + 0xD65D: 0x727B, //CJK UNIFIED IDEOGRAPH + 0xD65E: 0x727C, //CJK UNIFIED IDEOGRAPH + 0xD65F: 0x727F, //CJK UNIFIED IDEOGRAPH + 0xD660: 0x731D, //CJK UNIFIED IDEOGRAPH + 0xD661: 0x7317, //CJK UNIFIED IDEOGRAPH + 0xD662: 0x7307, //CJK UNIFIED IDEOGRAPH + 0xD663: 0x7311, //CJK UNIFIED IDEOGRAPH + 0xD664: 0x7318, //CJK UNIFIED IDEOGRAPH + 0xD665: 0x730A, //CJK UNIFIED IDEOGRAPH + 0xD666: 0x7308, //CJK UNIFIED IDEOGRAPH + 0xD667: 0x72FF, //CJK UNIFIED IDEOGRAPH + 0xD668: 0x730F, //CJK UNIFIED IDEOGRAPH + 0xD669: 0x731E, //CJK UNIFIED IDEOGRAPH + 0xD66A: 0x7388, //CJK UNIFIED IDEOGRAPH + 0xD66B: 0x73F6, //CJK UNIFIED IDEOGRAPH + 0xD66C: 0x73F8, //CJK UNIFIED IDEOGRAPH + 0xD66D: 0x73F5, //CJK UNIFIED IDEOGRAPH + 0xD66E: 0x7404, //CJK UNIFIED IDEOGRAPH + 0xD66F: 0x7401, //CJK UNIFIED IDEOGRAPH + 0xD670: 0x73FD, //CJK UNIFIED IDEOGRAPH + 0xD671: 0x7407, //CJK UNIFIED IDEOGRAPH + 0xD672: 0x7400, //CJK UNIFIED IDEOGRAPH + 0xD673: 0x73FA, //CJK UNIFIED IDEOGRAPH + 0xD674: 0x73FC, //CJK UNIFIED IDEOGRAPH + 0xD675: 0x73FF, //CJK UNIFIED IDEOGRAPH + 0xD676: 0x740C, //CJK UNIFIED IDEOGRAPH + 0xD677: 0x740B, //CJK UNIFIED IDEOGRAPH + 0xD678: 0x73F4, //CJK UNIFIED IDEOGRAPH + 0xD679: 0x7408, //CJK UNIFIED IDEOGRAPH + 0xD67A: 0x7564, //CJK UNIFIED IDEOGRAPH + 0xD67B: 0x7563, //CJK UNIFIED IDEOGRAPH + 0xD67C: 0x75CE, //CJK UNIFIED IDEOGRAPH + 0xD67D: 0x75D2, //CJK UNIFIED IDEOGRAPH + 0xD67E: 0x75CF, //CJK UNIFIED IDEOGRAPH + 0xD6A1: 0x75CB, //CJK UNIFIED IDEOGRAPH + 0xD6A2: 0x75CC, //CJK UNIFIED IDEOGRAPH + 0xD6A3: 0x75D1, //CJK UNIFIED IDEOGRAPH + 0xD6A4: 0x75D0, //CJK UNIFIED IDEOGRAPH + 0xD6A5: 0x768F, //CJK UNIFIED IDEOGRAPH + 0xD6A6: 0x7689, //CJK UNIFIED IDEOGRAPH + 0xD6A7: 0x76D3, //CJK UNIFIED IDEOGRAPH + 0xD6A8: 0x7739, //CJK UNIFIED IDEOGRAPH + 0xD6A9: 0x772F, //CJK UNIFIED IDEOGRAPH + 0xD6AA: 0x772D, //CJK UNIFIED IDEOGRAPH + 0xD6AB: 0x7731, //CJK UNIFIED IDEOGRAPH + 0xD6AC: 0x7732, //CJK UNIFIED IDEOGRAPH + 0xD6AD: 0x7734, //CJK UNIFIED IDEOGRAPH + 0xD6AE: 0x7733, //CJK UNIFIED IDEOGRAPH + 0xD6AF: 0x773D, //CJK UNIFIED IDEOGRAPH + 0xD6B0: 0x7725, //CJK UNIFIED IDEOGRAPH + 0xD6B1: 0x773B, //CJK UNIFIED IDEOGRAPH + 0xD6B2: 0x7735, //CJK UNIFIED IDEOGRAPH + 0xD6B3: 0x7848, //CJK UNIFIED IDEOGRAPH + 0xD6B4: 0x7852, //CJK UNIFIED IDEOGRAPH + 0xD6B5: 0x7849, //CJK UNIFIED IDEOGRAPH + 0xD6B6: 0x784D, //CJK UNIFIED IDEOGRAPH + 0xD6B7: 0x784A, //CJK UNIFIED IDEOGRAPH + 0xD6B8: 0x784C, //CJK UNIFIED IDEOGRAPH + 0xD6B9: 0x7826, //CJK UNIFIED IDEOGRAPH + 0xD6BA: 0x7845, //CJK UNIFIED IDEOGRAPH + 0xD6BB: 0x7850, //CJK UNIFIED IDEOGRAPH + 0xD6BC: 0x7964, //CJK UNIFIED IDEOGRAPH + 0xD6BD: 0x7967, //CJK UNIFIED IDEOGRAPH + 0xD6BE: 0x7969, //CJK UNIFIED IDEOGRAPH + 0xD6BF: 0x796A, //CJK UNIFIED IDEOGRAPH + 0xD6C0: 0x7963, //CJK UNIFIED IDEOGRAPH + 0xD6C1: 0x796B, //CJK UNIFIED IDEOGRAPH + 0xD6C2: 0x7961, //CJK UNIFIED IDEOGRAPH + 0xD6C3: 0x79BB, //CJK UNIFIED IDEOGRAPH + 0xD6C4: 0x79FA, //CJK UNIFIED IDEOGRAPH + 0xD6C5: 0x79F8, //CJK UNIFIED IDEOGRAPH + 0xD6C6: 0x79F6, //CJK UNIFIED IDEOGRAPH + 0xD6C7: 0x79F7, //CJK UNIFIED IDEOGRAPH + 0xD6C8: 0x7A8F, //CJK UNIFIED IDEOGRAPH + 0xD6C9: 0x7A94, //CJK UNIFIED IDEOGRAPH + 0xD6CA: 0x7A90, //CJK UNIFIED IDEOGRAPH + 0xD6CB: 0x7B35, //CJK UNIFIED IDEOGRAPH + 0xD6CC: 0x7B47, //CJK UNIFIED IDEOGRAPH + 0xD6CD: 0x7B34, //CJK UNIFIED IDEOGRAPH + 0xD6CE: 0x7B25, //CJK UNIFIED IDEOGRAPH + 0xD6CF: 0x7B30, //CJK UNIFIED IDEOGRAPH + 0xD6D0: 0x7B22, //CJK UNIFIED IDEOGRAPH + 0xD6D1: 0x7B24, //CJK UNIFIED IDEOGRAPH + 0xD6D2: 0x7B33, //CJK UNIFIED IDEOGRAPH + 0xD6D3: 0x7B18, //CJK UNIFIED IDEOGRAPH + 0xD6D4: 0x7B2A, //CJK UNIFIED IDEOGRAPH + 0xD6D5: 0x7B1D, //CJK UNIFIED IDEOGRAPH + 0xD6D6: 0x7B31, //CJK UNIFIED IDEOGRAPH + 0xD6D7: 0x7B2B, //CJK UNIFIED IDEOGRAPH + 0xD6D8: 0x7B2D, //CJK UNIFIED IDEOGRAPH + 0xD6D9: 0x7B2F, //CJK UNIFIED IDEOGRAPH + 0xD6DA: 0x7B32, //CJK UNIFIED IDEOGRAPH + 0xD6DB: 0x7B38, //CJK UNIFIED IDEOGRAPH + 0xD6DC: 0x7B1A, //CJK UNIFIED IDEOGRAPH + 0xD6DD: 0x7B23, //CJK UNIFIED IDEOGRAPH + 0xD6DE: 0x7C94, //CJK UNIFIED IDEOGRAPH + 0xD6DF: 0x7C98, //CJK UNIFIED IDEOGRAPH + 0xD6E0: 0x7C96, //CJK UNIFIED IDEOGRAPH + 0xD6E1: 0x7CA3, //CJK UNIFIED IDEOGRAPH + 0xD6E2: 0x7D35, //CJK UNIFIED IDEOGRAPH + 0xD6E3: 0x7D3D, //CJK UNIFIED IDEOGRAPH + 0xD6E4: 0x7D38, //CJK UNIFIED IDEOGRAPH + 0xD6E5: 0x7D36, //CJK UNIFIED IDEOGRAPH + 0xD6E6: 0x7D3A, //CJK UNIFIED IDEOGRAPH + 0xD6E7: 0x7D45, //CJK UNIFIED IDEOGRAPH + 0xD6E8: 0x7D2C, //CJK UNIFIED IDEOGRAPH + 0xD6E9: 0x7D29, //CJK UNIFIED IDEOGRAPH + 0xD6EA: 0x7D41, //CJK UNIFIED IDEOGRAPH + 0xD6EB: 0x7D47, //CJK UNIFIED IDEOGRAPH + 0xD6EC: 0x7D3E, //CJK UNIFIED IDEOGRAPH + 0xD6ED: 0x7D3F, //CJK UNIFIED IDEOGRAPH + 0xD6EE: 0x7D4A, //CJK UNIFIED IDEOGRAPH + 0xD6EF: 0x7D3B, //CJK UNIFIED IDEOGRAPH + 0xD6F0: 0x7D28, //CJK UNIFIED IDEOGRAPH + 0xD6F1: 0x7F63, //CJK UNIFIED IDEOGRAPH + 0xD6F2: 0x7F95, //CJK UNIFIED IDEOGRAPH + 0xD6F3: 0x7F9C, //CJK UNIFIED IDEOGRAPH + 0xD6F4: 0x7F9D, //CJK UNIFIED IDEOGRAPH + 0xD6F5: 0x7F9B, //CJK UNIFIED IDEOGRAPH + 0xD6F6: 0x7FCA, //CJK UNIFIED IDEOGRAPH + 0xD6F7: 0x7FCB, //CJK UNIFIED IDEOGRAPH + 0xD6F8: 0x7FCD, //CJK UNIFIED IDEOGRAPH + 0xD6F9: 0x7FD0, //CJK UNIFIED IDEOGRAPH + 0xD6FA: 0x7FD1, //CJK UNIFIED IDEOGRAPH + 0xD6FB: 0x7FC7, //CJK UNIFIED IDEOGRAPH + 0xD6FC: 0x7FCF, //CJK UNIFIED IDEOGRAPH + 0xD6FD: 0x7FC9, //CJK UNIFIED IDEOGRAPH + 0xD6FE: 0x801F, //CJK UNIFIED IDEOGRAPH + 0xD740: 0x801E, //CJK UNIFIED IDEOGRAPH + 0xD741: 0x801B, //CJK UNIFIED IDEOGRAPH + 0xD742: 0x8047, //CJK UNIFIED IDEOGRAPH + 0xD743: 0x8043, //CJK UNIFIED IDEOGRAPH + 0xD744: 0x8048, //CJK UNIFIED IDEOGRAPH + 0xD745: 0x8118, //CJK UNIFIED IDEOGRAPH + 0xD746: 0x8125, //CJK UNIFIED IDEOGRAPH + 0xD747: 0x8119, //CJK UNIFIED IDEOGRAPH + 0xD748: 0x811B, //CJK UNIFIED IDEOGRAPH + 0xD749: 0x812D, //CJK UNIFIED IDEOGRAPH + 0xD74A: 0x811F, //CJK UNIFIED IDEOGRAPH + 0xD74B: 0x812C, //CJK UNIFIED IDEOGRAPH + 0xD74C: 0x811E, //CJK UNIFIED IDEOGRAPH + 0xD74D: 0x8121, //CJK UNIFIED IDEOGRAPH + 0xD74E: 0x8115, //CJK UNIFIED IDEOGRAPH + 0xD74F: 0x8127, //CJK UNIFIED IDEOGRAPH + 0xD750: 0x811D, //CJK UNIFIED IDEOGRAPH + 0xD751: 0x8122, //CJK UNIFIED IDEOGRAPH + 0xD752: 0x8211, //CJK UNIFIED IDEOGRAPH + 0xD753: 0x8238, //CJK UNIFIED IDEOGRAPH + 0xD754: 0x8233, //CJK UNIFIED IDEOGRAPH + 0xD755: 0x823A, //CJK UNIFIED IDEOGRAPH + 0xD756: 0x8234, //CJK UNIFIED IDEOGRAPH + 0xD757: 0x8232, //CJK UNIFIED IDEOGRAPH + 0xD758: 0x8274, //CJK UNIFIED IDEOGRAPH + 0xD759: 0x8390, //CJK UNIFIED IDEOGRAPH + 0xD75A: 0x83A3, //CJK UNIFIED IDEOGRAPH + 0xD75B: 0x83A8, //CJK UNIFIED IDEOGRAPH + 0xD75C: 0x838D, //CJK UNIFIED IDEOGRAPH + 0xD75D: 0x837A, //CJK UNIFIED IDEOGRAPH + 0xD75E: 0x8373, //CJK UNIFIED IDEOGRAPH + 0xD75F: 0x83A4, //CJK UNIFIED IDEOGRAPH + 0xD760: 0x8374, //CJK UNIFIED IDEOGRAPH + 0xD761: 0x838F, //CJK UNIFIED IDEOGRAPH + 0xD762: 0x8381, //CJK UNIFIED IDEOGRAPH + 0xD763: 0x8395, //CJK UNIFIED IDEOGRAPH + 0xD764: 0x8399, //CJK UNIFIED IDEOGRAPH + 0xD765: 0x8375, //CJK UNIFIED IDEOGRAPH + 0xD766: 0x8394, //CJK UNIFIED IDEOGRAPH + 0xD767: 0x83A9, //CJK UNIFIED IDEOGRAPH + 0xD768: 0x837D, //CJK UNIFIED IDEOGRAPH + 0xD769: 0x8383, //CJK UNIFIED IDEOGRAPH + 0xD76A: 0x838C, //CJK UNIFIED IDEOGRAPH + 0xD76B: 0x839D, //CJK UNIFIED IDEOGRAPH + 0xD76C: 0x839B, //CJK UNIFIED IDEOGRAPH + 0xD76D: 0x83AA, //CJK UNIFIED IDEOGRAPH + 0xD76E: 0x838B, //CJK UNIFIED IDEOGRAPH + 0xD76F: 0x837E, //CJK UNIFIED IDEOGRAPH + 0xD770: 0x83A5, //CJK UNIFIED IDEOGRAPH + 0xD771: 0x83AF, //CJK UNIFIED IDEOGRAPH + 0xD772: 0x8388, //CJK UNIFIED IDEOGRAPH + 0xD773: 0x8397, //CJK UNIFIED IDEOGRAPH + 0xD774: 0x83B0, //CJK UNIFIED IDEOGRAPH + 0xD775: 0x837F, //CJK UNIFIED IDEOGRAPH + 0xD776: 0x83A6, //CJK UNIFIED IDEOGRAPH + 0xD777: 0x8387, //CJK UNIFIED IDEOGRAPH + 0xD778: 0x83AE, //CJK UNIFIED IDEOGRAPH + 0xD779: 0x8376, //CJK UNIFIED IDEOGRAPH + 0xD77A: 0x839A, //CJK UNIFIED IDEOGRAPH + 0xD77B: 0x8659, //CJK UNIFIED IDEOGRAPH + 0xD77C: 0x8656, //CJK UNIFIED IDEOGRAPH + 0xD77D: 0x86BF, //CJK UNIFIED IDEOGRAPH + 0xD77E: 0x86B7, //CJK UNIFIED IDEOGRAPH + 0xD7A1: 0x86C2, //CJK UNIFIED IDEOGRAPH + 0xD7A2: 0x86C1, //CJK UNIFIED IDEOGRAPH + 0xD7A3: 0x86C5, //CJK UNIFIED IDEOGRAPH + 0xD7A4: 0x86BA, //CJK UNIFIED IDEOGRAPH + 0xD7A5: 0x86B0, //CJK UNIFIED IDEOGRAPH + 0xD7A6: 0x86C8, //CJK UNIFIED IDEOGRAPH + 0xD7A7: 0x86B9, //CJK UNIFIED IDEOGRAPH + 0xD7A8: 0x86B3, //CJK UNIFIED IDEOGRAPH + 0xD7A9: 0x86B8, //CJK UNIFIED IDEOGRAPH + 0xD7AA: 0x86CC, //CJK UNIFIED IDEOGRAPH + 0xD7AB: 0x86B4, //CJK UNIFIED IDEOGRAPH + 0xD7AC: 0x86BB, //CJK UNIFIED IDEOGRAPH + 0xD7AD: 0x86BC, //CJK UNIFIED IDEOGRAPH + 0xD7AE: 0x86C3, //CJK UNIFIED IDEOGRAPH + 0xD7AF: 0x86BD, //CJK UNIFIED IDEOGRAPH + 0xD7B0: 0x86BE, //CJK UNIFIED IDEOGRAPH + 0xD7B1: 0x8852, //CJK UNIFIED IDEOGRAPH + 0xD7B2: 0x8889, //CJK UNIFIED IDEOGRAPH + 0xD7B3: 0x8895, //CJK UNIFIED IDEOGRAPH + 0xD7B4: 0x88A8, //CJK UNIFIED IDEOGRAPH + 0xD7B5: 0x88A2, //CJK UNIFIED IDEOGRAPH + 0xD7B6: 0x88AA, //CJK UNIFIED IDEOGRAPH + 0xD7B7: 0x889A, //CJK UNIFIED IDEOGRAPH + 0xD7B8: 0x8891, //CJK UNIFIED IDEOGRAPH + 0xD7B9: 0x88A1, //CJK UNIFIED IDEOGRAPH + 0xD7BA: 0x889F, //CJK UNIFIED IDEOGRAPH + 0xD7BB: 0x8898, //CJK UNIFIED IDEOGRAPH + 0xD7BC: 0x88A7, //CJK UNIFIED IDEOGRAPH + 0xD7BD: 0x8899, //CJK UNIFIED IDEOGRAPH + 0xD7BE: 0x889B, //CJK UNIFIED IDEOGRAPH + 0xD7BF: 0x8897, //CJK UNIFIED IDEOGRAPH + 0xD7C0: 0x88A4, //CJK UNIFIED IDEOGRAPH + 0xD7C1: 0x88AC, //CJK UNIFIED IDEOGRAPH + 0xD7C2: 0x888C, //CJK UNIFIED IDEOGRAPH + 0xD7C3: 0x8893, //CJK UNIFIED IDEOGRAPH + 0xD7C4: 0x888E, //CJK UNIFIED IDEOGRAPH + 0xD7C5: 0x8982, //CJK UNIFIED IDEOGRAPH + 0xD7C6: 0x89D6, //CJK UNIFIED IDEOGRAPH + 0xD7C7: 0x89D9, //CJK UNIFIED IDEOGRAPH + 0xD7C8: 0x89D5, //CJK UNIFIED IDEOGRAPH + 0xD7C9: 0x8A30, //CJK UNIFIED IDEOGRAPH + 0xD7CA: 0x8A27, //CJK UNIFIED IDEOGRAPH + 0xD7CB: 0x8A2C, //CJK UNIFIED IDEOGRAPH + 0xD7CC: 0x8A1E, //CJK UNIFIED IDEOGRAPH + 0xD7CD: 0x8C39, //CJK UNIFIED IDEOGRAPH + 0xD7CE: 0x8C3B, //CJK UNIFIED IDEOGRAPH + 0xD7CF: 0x8C5C, //CJK UNIFIED IDEOGRAPH + 0xD7D0: 0x8C5D, //CJK UNIFIED IDEOGRAPH + 0xD7D1: 0x8C7D, //CJK UNIFIED IDEOGRAPH + 0xD7D2: 0x8CA5, //CJK UNIFIED IDEOGRAPH + 0xD7D3: 0x8D7D, //CJK UNIFIED IDEOGRAPH + 0xD7D4: 0x8D7B, //CJK UNIFIED IDEOGRAPH + 0xD7D5: 0x8D79, //CJK UNIFIED IDEOGRAPH + 0xD7D6: 0x8DBC, //CJK UNIFIED IDEOGRAPH + 0xD7D7: 0x8DC2, //CJK UNIFIED IDEOGRAPH + 0xD7D8: 0x8DB9, //CJK UNIFIED IDEOGRAPH + 0xD7D9: 0x8DBF, //CJK UNIFIED IDEOGRAPH + 0xD7DA: 0x8DC1, //CJK UNIFIED IDEOGRAPH + 0xD7DB: 0x8ED8, //CJK UNIFIED IDEOGRAPH + 0xD7DC: 0x8EDE, //CJK UNIFIED IDEOGRAPH + 0xD7DD: 0x8EDD, //CJK UNIFIED IDEOGRAPH + 0xD7DE: 0x8EDC, //CJK UNIFIED IDEOGRAPH + 0xD7DF: 0x8ED7, //CJK UNIFIED IDEOGRAPH + 0xD7E0: 0x8EE0, //CJK UNIFIED IDEOGRAPH + 0xD7E1: 0x8EE1, //CJK UNIFIED IDEOGRAPH + 0xD7E2: 0x9024, //CJK UNIFIED IDEOGRAPH + 0xD7E3: 0x900B, //CJK UNIFIED IDEOGRAPH + 0xD7E4: 0x9011, //CJK UNIFIED IDEOGRAPH + 0xD7E5: 0x901C, //CJK UNIFIED IDEOGRAPH + 0xD7E6: 0x900C, //CJK UNIFIED IDEOGRAPH + 0xD7E7: 0x9021, //CJK UNIFIED IDEOGRAPH + 0xD7E8: 0x90EF, //CJK UNIFIED IDEOGRAPH + 0xD7E9: 0x90EA, //CJK UNIFIED IDEOGRAPH + 0xD7EA: 0x90F0, //CJK UNIFIED IDEOGRAPH + 0xD7EB: 0x90F4, //CJK UNIFIED IDEOGRAPH + 0xD7EC: 0x90F2, //CJK UNIFIED IDEOGRAPH + 0xD7ED: 0x90F3, //CJK UNIFIED IDEOGRAPH + 0xD7EE: 0x90D4, //CJK UNIFIED IDEOGRAPH + 0xD7EF: 0x90EB, //CJK UNIFIED IDEOGRAPH + 0xD7F0: 0x90EC, //CJK UNIFIED IDEOGRAPH + 0xD7F1: 0x90E9, //CJK UNIFIED IDEOGRAPH + 0xD7F2: 0x9156, //CJK UNIFIED IDEOGRAPH + 0xD7F3: 0x9158, //CJK UNIFIED IDEOGRAPH + 0xD7F4: 0x915A, //CJK UNIFIED IDEOGRAPH + 0xD7F5: 0x9153, //CJK UNIFIED IDEOGRAPH + 0xD7F6: 0x9155, //CJK UNIFIED IDEOGRAPH + 0xD7F7: 0x91EC, //CJK UNIFIED IDEOGRAPH + 0xD7F8: 0x91F4, //CJK UNIFIED IDEOGRAPH + 0xD7F9: 0x91F1, //CJK UNIFIED IDEOGRAPH + 0xD7FA: 0x91F3, //CJK UNIFIED IDEOGRAPH + 0xD7FB: 0x91F8, //CJK UNIFIED IDEOGRAPH + 0xD7FC: 0x91E4, //CJK UNIFIED IDEOGRAPH + 0xD7FD: 0x91F9, //CJK UNIFIED IDEOGRAPH + 0xD7FE: 0x91EA, //CJK UNIFIED IDEOGRAPH + 0xD840: 0x91EB, //CJK UNIFIED IDEOGRAPH + 0xD841: 0x91F7, //CJK UNIFIED IDEOGRAPH + 0xD842: 0x91E8, //CJK UNIFIED IDEOGRAPH + 0xD843: 0x91EE, //CJK UNIFIED IDEOGRAPH + 0xD844: 0x957A, //CJK UNIFIED IDEOGRAPH + 0xD845: 0x9586, //CJK UNIFIED IDEOGRAPH + 0xD846: 0x9588, //CJK UNIFIED IDEOGRAPH + 0xD847: 0x967C, //CJK UNIFIED IDEOGRAPH + 0xD848: 0x966D, //CJK UNIFIED IDEOGRAPH + 0xD849: 0x966B, //CJK UNIFIED IDEOGRAPH + 0xD84A: 0x9671, //CJK UNIFIED IDEOGRAPH + 0xD84B: 0x966F, //CJK UNIFIED IDEOGRAPH + 0xD84C: 0x96BF, //CJK UNIFIED IDEOGRAPH + 0xD84D: 0x976A, //CJK UNIFIED IDEOGRAPH + 0xD84E: 0x9804, //CJK UNIFIED IDEOGRAPH + 0xD84F: 0x98E5, //CJK UNIFIED IDEOGRAPH + 0xD850: 0x9997, //CJK UNIFIED IDEOGRAPH + 0xD851: 0x509B, //CJK UNIFIED IDEOGRAPH + 0xD852: 0x5095, //CJK UNIFIED IDEOGRAPH + 0xD853: 0x5094, //CJK UNIFIED IDEOGRAPH + 0xD854: 0x509E, //CJK UNIFIED IDEOGRAPH + 0xD855: 0x508B, //CJK UNIFIED IDEOGRAPH + 0xD856: 0x50A3, //CJK UNIFIED IDEOGRAPH + 0xD857: 0x5083, //CJK UNIFIED IDEOGRAPH + 0xD858: 0x508C, //CJK UNIFIED IDEOGRAPH + 0xD859: 0x508E, //CJK UNIFIED IDEOGRAPH + 0xD85A: 0x509D, //CJK UNIFIED IDEOGRAPH + 0xD85B: 0x5068, //CJK UNIFIED IDEOGRAPH + 0xD85C: 0x509C, //CJK UNIFIED IDEOGRAPH + 0xD85D: 0x5092, //CJK UNIFIED IDEOGRAPH + 0xD85E: 0x5082, //CJK UNIFIED IDEOGRAPH + 0xD85F: 0x5087, //CJK UNIFIED IDEOGRAPH + 0xD860: 0x515F, //CJK UNIFIED IDEOGRAPH + 0xD861: 0x51D4, //CJK UNIFIED IDEOGRAPH + 0xD862: 0x5312, //CJK UNIFIED IDEOGRAPH + 0xD863: 0x5311, //CJK UNIFIED IDEOGRAPH + 0xD864: 0x53A4, //CJK UNIFIED IDEOGRAPH + 0xD865: 0x53A7, //CJK UNIFIED IDEOGRAPH + 0xD866: 0x5591, //CJK UNIFIED IDEOGRAPH + 0xD867: 0x55A8, //CJK UNIFIED IDEOGRAPH + 0xD868: 0x55A5, //CJK UNIFIED IDEOGRAPH + 0xD869: 0x55AD, //CJK UNIFIED IDEOGRAPH + 0xD86A: 0x5577, //CJK UNIFIED IDEOGRAPH + 0xD86B: 0x5645, //CJK UNIFIED IDEOGRAPH + 0xD86C: 0x55A2, //CJK UNIFIED IDEOGRAPH + 0xD86D: 0x5593, //CJK UNIFIED IDEOGRAPH + 0xD86E: 0x5588, //CJK UNIFIED IDEOGRAPH + 0xD86F: 0x558F, //CJK UNIFIED IDEOGRAPH + 0xD870: 0x55B5, //CJK UNIFIED IDEOGRAPH + 0xD871: 0x5581, //CJK UNIFIED IDEOGRAPH + 0xD872: 0x55A3, //CJK UNIFIED IDEOGRAPH + 0xD873: 0x5592, //CJK UNIFIED IDEOGRAPH + 0xD874: 0x55A4, //CJK UNIFIED IDEOGRAPH + 0xD875: 0x557D, //CJK UNIFIED IDEOGRAPH + 0xD876: 0x558C, //CJK UNIFIED IDEOGRAPH + 0xD877: 0x55A6, //CJK UNIFIED IDEOGRAPH + 0xD878: 0x557F, //CJK UNIFIED IDEOGRAPH + 0xD879: 0x5595, //CJK UNIFIED IDEOGRAPH + 0xD87A: 0x55A1, //CJK UNIFIED IDEOGRAPH + 0xD87B: 0x558E, //CJK UNIFIED IDEOGRAPH + 0xD87C: 0x570C, //CJK UNIFIED IDEOGRAPH + 0xD87D: 0x5829, //CJK UNIFIED IDEOGRAPH + 0xD87E: 0x5837, //CJK UNIFIED IDEOGRAPH + 0xD8A1: 0x5819, //CJK UNIFIED IDEOGRAPH + 0xD8A2: 0x581E, //CJK UNIFIED IDEOGRAPH + 0xD8A3: 0x5827, //CJK UNIFIED IDEOGRAPH + 0xD8A4: 0x5823, //CJK UNIFIED IDEOGRAPH + 0xD8A5: 0x5828, //CJK UNIFIED IDEOGRAPH + 0xD8A6: 0x57F5, //CJK UNIFIED IDEOGRAPH + 0xD8A7: 0x5848, //CJK UNIFIED IDEOGRAPH + 0xD8A8: 0x5825, //CJK UNIFIED IDEOGRAPH + 0xD8A9: 0x581C, //CJK UNIFIED IDEOGRAPH + 0xD8AA: 0x581B, //CJK UNIFIED IDEOGRAPH + 0xD8AB: 0x5833, //CJK UNIFIED IDEOGRAPH + 0xD8AC: 0x583F, //CJK UNIFIED IDEOGRAPH + 0xD8AD: 0x5836, //CJK UNIFIED IDEOGRAPH + 0xD8AE: 0x582E, //CJK UNIFIED IDEOGRAPH + 0xD8AF: 0x5839, //CJK UNIFIED IDEOGRAPH + 0xD8B0: 0x5838, //CJK UNIFIED IDEOGRAPH + 0xD8B1: 0x582D, //CJK UNIFIED IDEOGRAPH + 0xD8B2: 0x582C, //CJK UNIFIED IDEOGRAPH + 0xD8B3: 0x583B, //CJK UNIFIED IDEOGRAPH + 0xD8B4: 0x5961, //CJK UNIFIED IDEOGRAPH + 0xD8B5: 0x5AAF, //CJK UNIFIED IDEOGRAPH + 0xD8B6: 0x5A94, //CJK UNIFIED IDEOGRAPH + 0xD8B7: 0x5A9F, //CJK UNIFIED IDEOGRAPH + 0xD8B8: 0x5A7A, //CJK UNIFIED IDEOGRAPH + 0xD8B9: 0x5AA2, //CJK UNIFIED IDEOGRAPH + 0xD8BA: 0x5A9E, //CJK UNIFIED IDEOGRAPH + 0xD8BB: 0x5A78, //CJK UNIFIED IDEOGRAPH + 0xD8BC: 0x5AA6, //CJK UNIFIED IDEOGRAPH + 0xD8BD: 0x5A7C, //CJK UNIFIED IDEOGRAPH + 0xD8BE: 0x5AA5, //CJK UNIFIED IDEOGRAPH + 0xD8BF: 0x5AAC, //CJK UNIFIED IDEOGRAPH + 0xD8C0: 0x5A95, //CJK UNIFIED IDEOGRAPH + 0xD8C1: 0x5AAE, //CJK UNIFIED IDEOGRAPH + 0xD8C2: 0x5A37, //CJK UNIFIED IDEOGRAPH + 0xD8C3: 0x5A84, //CJK UNIFIED IDEOGRAPH + 0xD8C4: 0x5A8A, //CJK UNIFIED IDEOGRAPH + 0xD8C5: 0x5A97, //CJK UNIFIED IDEOGRAPH + 0xD8C6: 0x5A83, //CJK UNIFIED IDEOGRAPH + 0xD8C7: 0x5A8B, //CJK UNIFIED IDEOGRAPH + 0xD8C8: 0x5AA9, //CJK UNIFIED IDEOGRAPH + 0xD8C9: 0x5A7B, //CJK UNIFIED IDEOGRAPH + 0xD8CA: 0x5A7D, //CJK UNIFIED IDEOGRAPH + 0xD8CB: 0x5A8C, //CJK UNIFIED IDEOGRAPH + 0xD8CC: 0x5A9C, //CJK UNIFIED IDEOGRAPH + 0xD8CD: 0x5A8F, //CJK UNIFIED IDEOGRAPH + 0xD8CE: 0x5A93, //CJK UNIFIED IDEOGRAPH + 0xD8CF: 0x5A9D, //CJK UNIFIED IDEOGRAPH + 0xD8D0: 0x5BEA, //CJK UNIFIED IDEOGRAPH + 0xD8D1: 0x5BCD, //CJK UNIFIED IDEOGRAPH + 0xD8D2: 0x5BCB, //CJK UNIFIED IDEOGRAPH + 0xD8D3: 0x5BD4, //CJK UNIFIED IDEOGRAPH + 0xD8D4: 0x5BD1, //CJK UNIFIED IDEOGRAPH + 0xD8D5: 0x5BCA, //CJK UNIFIED IDEOGRAPH + 0xD8D6: 0x5BCE, //CJK UNIFIED IDEOGRAPH + 0xD8D7: 0x5C0C, //CJK UNIFIED IDEOGRAPH + 0xD8D8: 0x5C30, //CJK UNIFIED IDEOGRAPH + 0xD8D9: 0x5D37, //CJK UNIFIED IDEOGRAPH + 0xD8DA: 0x5D43, //CJK UNIFIED IDEOGRAPH + 0xD8DB: 0x5D6B, //CJK UNIFIED IDEOGRAPH + 0xD8DC: 0x5D41, //CJK UNIFIED IDEOGRAPH + 0xD8DD: 0x5D4B, //CJK UNIFIED IDEOGRAPH + 0xD8DE: 0x5D3F, //CJK UNIFIED IDEOGRAPH + 0xD8DF: 0x5D35, //CJK UNIFIED IDEOGRAPH + 0xD8E0: 0x5D51, //CJK UNIFIED IDEOGRAPH + 0xD8E1: 0x5D4E, //CJK UNIFIED IDEOGRAPH + 0xD8E2: 0x5D55, //CJK UNIFIED IDEOGRAPH + 0xD8E3: 0x5D33, //CJK UNIFIED IDEOGRAPH + 0xD8E4: 0x5D3A, //CJK UNIFIED IDEOGRAPH + 0xD8E5: 0x5D52, //CJK UNIFIED IDEOGRAPH + 0xD8E6: 0x5D3D, //CJK UNIFIED IDEOGRAPH + 0xD8E7: 0x5D31, //CJK UNIFIED IDEOGRAPH + 0xD8E8: 0x5D59, //CJK UNIFIED IDEOGRAPH + 0xD8E9: 0x5D42, //CJK UNIFIED IDEOGRAPH + 0xD8EA: 0x5D39, //CJK UNIFIED IDEOGRAPH + 0xD8EB: 0x5D49, //CJK UNIFIED IDEOGRAPH + 0xD8EC: 0x5D38, //CJK UNIFIED IDEOGRAPH + 0xD8ED: 0x5D3C, //CJK UNIFIED IDEOGRAPH + 0xD8EE: 0x5D32, //CJK UNIFIED IDEOGRAPH + 0xD8EF: 0x5D36, //CJK UNIFIED IDEOGRAPH + 0xD8F0: 0x5D40, //CJK UNIFIED IDEOGRAPH + 0xD8F1: 0x5D45, //CJK UNIFIED IDEOGRAPH + 0xD8F2: 0x5E44, //CJK UNIFIED IDEOGRAPH + 0xD8F3: 0x5E41, //CJK UNIFIED IDEOGRAPH + 0xD8F4: 0x5F58, //CJK UNIFIED IDEOGRAPH + 0xD8F5: 0x5FA6, //CJK UNIFIED IDEOGRAPH + 0xD8F6: 0x5FA5, //CJK UNIFIED IDEOGRAPH + 0xD8F7: 0x5FAB, //CJK UNIFIED IDEOGRAPH + 0xD8F8: 0x60C9, //CJK UNIFIED IDEOGRAPH + 0xD8F9: 0x60B9, //CJK UNIFIED IDEOGRAPH + 0xD8FA: 0x60CC, //CJK UNIFIED IDEOGRAPH + 0xD8FB: 0x60E2, //CJK UNIFIED IDEOGRAPH + 0xD8FC: 0x60CE, //CJK UNIFIED IDEOGRAPH + 0xD8FD: 0x60C4, //CJK UNIFIED IDEOGRAPH + 0xD8FE: 0x6114, //CJK UNIFIED IDEOGRAPH + 0xD940: 0x60F2, //CJK UNIFIED IDEOGRAPH + 0xD941: 0x610A, //CJK UNIFIED IDEOGRAPH + 0xD942: 0x6116, //CJK UNIFIED IDEOGRAPH + 0xD943: 0x6105, //CJK UNIFIED IDEOGRAPH + 0xD944: 0x60F5, //CJK UNIFIED IDEOGRAPH + 0xD945: 0x6113, //CJK UNIFIED IDEOGRAPH + 0xD946: 0x60F8, //CJK UNIFIED IDEOGRAPH + 0xD947: 0x60FC, //CJK UNIFIED IDEOGRAPH + 0xD948: 0x60FE, //CJK UNIFIED IDEOGRAPH + 0xD949: 0x60C1, //CJK UNIFIED IDEOGRAPH + 0xD94A: 0x6103, //CJK UNIFIED IDEOGRAPH + 0xD94B: 0x6118, //CJK UNIFIED IDEOGRAPH + 0xD94C: 0x611D, //CJK UNIFIED IDEOGRAPH + 0xD94D: 0x6110, //CJK UNIFIED IDEOGRAPH + 0xD94E: 0x60FF, //CJK UNIFIED IDEOGRAPH + 0xD94F: 0x6104, //CJK UNIFIED IDEOGRAPH + 0xD950: 0x610B, //CJK UNIFIED IDEOGRAPH + 0xD951: 0x624A, //CJK UNIFIED IDEOGRAPH + 0xD952: 0x6394, //CJK UNIFIED IDEOGRAPH + 0xD953: 0x63B1, //CJK UNIFIED IDEOGRAPH + 0xD954: 0x63B0, //CJK UNIFIED IDEOGRAPH + 0xD955: 0x63CE, //CJK UNIFIED IDEOGRAPH + 0xD956: 0x63E5, //CJK UNIFIED IDEOGRAPH + 0xD957: 0x63E8, //CJK UNIFIED IDEOGRAPH + 0xD958: 0x63EF, //CJK UNIFIED IDEOGRAPH + 0xD959: 0x63C3, //CJK UNIFIED IDEOGRAPH + 0xD95A: 0x649D, //CJK UNIFIED IDEOGRAPH + 0xD95B: 0x63F3, //CJK UNIFIED IDEOGRAPH + 0xD95C: 0x63CA, //CJK UNIFIED IDEOGRAPH + 0xD95D: 0x63E0, //CJK UNIFIED IDEOGRAPH + 0xD95E: 0x63F6, //CJK UNIFIED IDEOGRAPH + 0xD95F: 0x63D5, //CJK UNIFIED IDEOGRAPH + 0xD960: 0x63F2, //CJK UNIFIED IDEOGRAPH + 0xD961: 0x63F5, //CJK UNIFIED IDEOGRAPH + 0xD962: 0x6461, //CJK UNIFIED IDEOGRAPH + 0xD963: 0x63DF, //CJK UNIFIED IDEOGRAPH + 0xD964: 0x63BE, //CJK UNIFIED IDEOGRAPH + 0xD965: 0x63DD, //CJK UNIFIED IDEOGRAPH + 0xD966: 0x63DC, //CJK UNIFIED IDEOGRAPH + 0xD967: 0x63C4, //CJK UNIFIED IDEOGRAPH + 0xD968: 0x63D8, //CJK UNIFIED IDEOGRAPH + 0xD969: 0x63D3, //CJK UNIFIED IDEOGRAPH + 0xD96A: 0x63C2, //CJK UNIFIED IDEOGRAPH + 0xD96B: 0x63C7, //CJK UNIFIED IDEOGRAPH + 0xD96C: 0x63CC, //CJK UNIFIED IDEOGRAPH + 0xD96D: 0x63CB, //CJK UNIFIED IDEOGRAPH + 0xD96E: 0x63C8, //CJK UNIFIED IDEOGRAPH + 0xD96F: 0x63F0, //CJK UNIFIED IDEOGRAPH + 0xD970: 0x63D7, //CJK UNIFIED IDEOGRAPH + 0xD971: 0x63D9, //CJK UNIFIED IDEOGRAPH + 0xD972: 0x6532, //CJK UNIFIED IDEOGRAPH + 0xD973: 0x6567, //CJK UNIFIED IDEOGRAPH + 0xD974: 0x656A, //CJK UNIFIED IDEOGRAPH + 0xD975: 0x6564, //CJK UNIFIED IDEOGRAPH + 0xD976: 0x655C, //CJK UNIFIED IDEOGRAPH + 0xD977: 0x6568, //CJK UNIFIED IDEOGRAPH + 0xD978: 0x6565, //CJK UNIFIED IDEOGRAPH + 0xD979: 0x658C, //CJK UNIFIED IDEOGRAPH + 0xD97A: 0x659D, //CJK UNIFIED IDEOGRAPH + 0xD97B: 0x659E, //CJK UNIFIED IDEOGRAPH + 0xD97C: 0x65AE, //CJK UNIFIED IDEOGRAPH + 0xD97D: 0x65D0, //CJK UNIFIED IDEOGRAPH + 0xD97E: 0x65D2, //CJK UNIFIED IDEOGRAPH + 0xD9A1: 0x667C, //CJK UNIFIED IDEOGRAPH + 0xD9A2: 0x666C, //CJK UNIFIED IDEOGRAPH + 0xD9A3: 0x667B, //CJK UNIFIED IDEOGRAPH + 0xD9A4: 0x6680, //CJK UNIFIED IDEOGRAPH + 0xD9A5: 0x6671, //CJK UNIFIED IDEOGRAPH + 0xD9A6: 0x6679, //CJK UNIFIED IDEOGRAPH + 0xD9A7: 0x666A, //CJK UNIFIED IDEOGRAPH + 0xD9A8: 0x6672, //CJK UNIFIED IDEOGRAPH + 0xD9A9: 0x6701, //CJK UNIFIED IDEOGRAPH + 0xD9AA: 0x690C, //CJK UNIFIED IDEOGRAPH + 0xD9AB: 0x68D3, //CJK UNIFIED IDEOGRAPH + 0xD9AC: 0x6904, //CJK UNIFIED IDEOGRAPH + 0xD9AD: 0x68DC, //CJK UNIFIED IDEOGRAPH + 0xD9AE: 0x692A, //CJK UNIFIED IDEOGRAPH + 0xD9AF: 0x68EC, //CJK UNIFIED IDEOGRAPH + 0xD9B0: 0x68EA, //CJK UNIFIED IDEOGRAPH + 0xD9B1: 0x68F1, //CJK UNIFIED IDEOGRAPH + 0xD9B2: 0x690F, //CJK UNIFIED IDEOGRAPH + 0xD9B3: 0x68D6, //CJK UNIFIED IDEOGRAPH + 0xD9B4: 0x68F7, //CJK UNIFIED IDEOGRAPH + 0xD9B5: 0x68EB, //CJK UNIFIED IDEOGRAPH + 0xD9B6: 0x68E4, //CJK UNIFIED IDEOGRAPH + 0xD9B7: 0x68F6, //CJK UNIFIED IDEOGRAPH + 0xD9B8: 0x6913, //CJK UNIFIED IDEOGRAPH + 0xD9B9: 0x6910, //CJK UNIFIED IDEOGRAPH + 0xD9BA: 0x68F3, //CJK UNIFIED IDEOGRAPH + 0xD9BB: 0x68E1, //CJK UNIFIED IDEOGRAPH + 0xD9BC: 0x6907, //CJK UNIFIED IDEOGRAPH + 0xD9BD: 0x68CC, //CJK UNIFIED IDEOGRAPH + 0xD9BE: 0x6908, //CJK UNIFIED IDEOGRAPH + 0xD9BF: 0x6970, //CJK UNIFIED IDEOGRAPH + 0xD9C0: 0x68B4, //CJK UNIFIED IDEOGRAPH + 0xD9C1: 0x6911, //CJK UNIFIED IDEOGRAPH + 0xD9C2: 0x68EF, //CJK UNIFIED IDEOGRAPH + 0xD9C3: 0x68C6, //CJK UNIFIED IDEOGRAPH + 0xD9C4: 0x6914, //CJK UNIFIED IDEOGRAPH + 0xD9C5: 0x68F8, //CJK UNIFIED IDEOGRAPH + 0xD9C6: 0x68D0, //CJK UNIFIED IDEOGRAPH + 0xD9C7: 0x68FD, //CJK UNIFIED IDEOGRAPH + 0xD9C8: 0x68FC, //CJK UNIFIED IDEOGRAPH + 0xD9C9: 0x68E8, //CJK UNIFIED IDEOGRAPH + 0xD9CA: 0x690B, //CJK UNIFIED IDEOGRAPH + 0xD9CB: 0x690A, //CJK UNIFIED IDEOGRAPH + 0xD9CC: 0x6917, //CJK UNIFIED IDEOGRAPH + 0xD9CD: 0x68CE, //CJK UNIFIED IDEOGRAPH + 0xD9CE: 0x68C8, //CJK UNIFIED IDEOGRAPH + 0xD9CF: 0x68DD, //CJK UNIFIED IDEOGRAPH + 0xD9D0: 0x68DE, //CJK UNIFIED IDEOGRAPH + 0xD9D1: 0x68E6, //CJK UNIFIED IDEOGRAPH + 0xD9D2: 0x68F4, //CJK UNIFIED IDEOGRAPH + 0xD9D3: 0x68D1, //CJK UNIFIED IDEOGRAPH + 0xD9D4: 0x6906, //CJK UNIFIED IDEOGRAPH + 0xD9D5: 0x68D4, //CJK UNIFIED IDEOGRAPH + 0xD9D6: 0x68E9, //CJK UNIFIED IDEOGRAPH + 0xD9D7: 0x6915, //CJK UNIFIED IDEOGRAPH + 0xD9D8: 0x6925, //CJK UNIFIED IDEOGRAPH + 0xD9D9: 0x68C7, //CJK UNIFIED IDEOGRAPH + 0xD9DA: 0x6B39, //CJK UNIFIED IDEOGRAPH + 0xD9DB: 0x6B3B, //CJK UNIFIED IDEOGRAPH + 0xD9DC: 0x6B3F, //CJK UNIFIED IDEOGRAPH + 0xD9DD: 0x6B3C, //CJK UNIFIED IDEOGRAPH + 0xD9DE: 0x6B94, //CJK UNIFIED IDEOGRAPH + 0xD9DF: 0x6B97, //CJK UNIFIED IDEOGRAPH + 0xD9E0: 0x6B99, //CJK UNIFIED IDEOGRAPH + 0xD9E1: 0x6B95, //CJK UNIFIED IDEOGRAPH + 0xD9E2: 0x6BBD, //CJK UNIFIED IDEOGRAPH + 0xD9E3: 0x6BF0, //CJK UNIFIED IDEOGRAPH + 0xD9E4: 0x6BF2, //CJK UNIFIED IDEOGRAPH + 0xD9E5: 0x6BF3, //CJK UNIFIED IDEOGRAPH + 0xD9E6: 0x6C30, //CJK UNIFIED IDEOGRAPH + 0xD9E7: 0x6DFC, //CJK UNIFIED IDEOGRAPH + 0xD9E8: 0x6E46, //CJK UNIFIED IDEOGRAPH + 0xD9E9: 0x6E47, //CJK UNIFIED IDEOGRAPH + 0xD9EA: 0x6E1F, //CJK UNIFIED IDEOGRAPH + 0xD9EB: 0x6E49, //CJK UNIFIED IDEOGRAPH + 0xD9EC: 0x6E88, //CJK UNIFIED IDEOGRAPH + 0xD9ED: 0x6E3C, //CJK UNIFIED IDEOGRAPH + 0xD9EE: 0x6E3D, //CJK UNIFIED IDEOGRAPH + 0xD9EF: 0x6E45, //CJK UNIFIED IDEOGRAPH + 0xD9F0: 0x6E62, //CJK UNIFIED IDEOGRAPH + 0xD9F1: 0x6E2B, //CJK UNIFIED IDEOGRAPH + 0xD9F2: 0x6E3F, //CJK UNIFIED IDEOGRAPH + 0xD9F3: 0x6E41, //CJK UNIFIED IDEOGRAPH + 0xD9F4: 0x6E5D, //CJK UNIFIED IDEOGRAPH + 0xD9F5: 0x6E73, //CJK UNIFIED IDEOGRAPH + 0xD9F6: 0x6E1C, //CJK UNIFIED IDEOGRAPH + 0xD9F7: 0x6E33, //CJK UNIFIED IDEOGRAPH + 0xD9F8: 0x6E4B, //CJK UNIFIED IDEOGRAPH + 0xD9F9: 0x6E40, //CJK UNIFIED IDEOGRAPH + 0xD9FA: 0x6E51, //CJK UNIFIED IDEOGRAPH + 0xD9FB: 0x6E3B, //CJK UNIFIED IDEOGRAPH + 0xD9FC: 0x6E03, //CJK UNIFIED IDEOGRAPH + 0xD9FD: 0x6E2E, //CJK UNIFIED IDEOGRAPH + 0xD9FE: 0x6E5E, //CJK UNIFIED IDEOGRAPH + 0xDA40: 0x6E68, //CJK UNIFIED IDEOGRAPH + 0xDA41: 0x6E5C, //CJK UNIFIED IDEOGRAPH + 0xDA42: 0x6E61, //CJK UNIFIED IDEOGRAPH + 0xDA43: 0x6E31, //CJK UNIFIED IDEOGRAPH + 0xDA44: 0x6E28, //CJK UNIFIED IDEOGRAPH + 0xDA45: 0x6E60, //CJK UNIFIED IDEOGRAPH + 0xDA46: 0x6E71, //CJK UNIFIED IDEOGRAPH + 0xDA47: 0x6E6B, //CJK UNIFIED IDEOGRAPH + 0xDA48: 0x6E39, //CJK UNIFIED IDEOGRAPH + 0xDA49: 0x6E22, //CJK UNIFIED IDEOGRAPH + 0xDA4A: 0x6E30, //CJK UNIFIED IDEOGRAPH + 0xDA4B: 0x6E53, //CJK UNIFIED IDEOGRAPH + 0xDA4C: 0x6E65, //CJK UNIFIED IDEOGRAPH + 0xDA4D: 0x6E27, //CJK UNIFIED IDEOGRAPH + 0xDA4E: 0x6E78, //CJK UNIFIED IDEOGRAPH + 0xDA4F: 0x6E64, //CJK UNIFIED IDEOGRAPH + 0xDA50: 0x6E77, //CJK UNIFIED IDEOGRAPH + 0xDA51: 0x6E55, //CJK UNIFIED IDEOGRAPH + 0xDA52: 0x6E79, //CJK UNIFIED IDEOGRAPH + 0xDA53: 0x6E52, //CJK UNIFIED IDEOGRAPH + 0xDA54: 0x6E66, //CJK UNIFIED IDEOGRAPH + 0xDA55: 0x6E35, //CJK UNIFIED IDEOGRAPH + 0xDA56: 0x6E36, //CJK UNIFIED IDEOGRAPH + 0xDA57: 0x6E5A, //CJK UNIFIED IDEOGRAPH + 0xDA58: 0x7120, //CJK UNIFIED IDEOGRAPH + 0xDA59: 0x711E, //CJK UNIFIED IDEOGRAPH + 0xDA5A: 0x712F, //CJK UNIFIED IDEOGRAPH + 0xDA5B: 0x70FB, //CJK UNIFIED IDEOGRAPH + 0xDA5C: 0x712E, //CJK UNIFIED IDEOGRAPH + 0xDA5D: 0x7131, //CJK UNIFIED IDEOGRAPH + 0xDA5E: 0x7123, //CJK UNIFIED IDEOGRAPH + 0xDA5F: 0x7125, //CJK UNIFIED IDEOGRAPH + 0xDA60: 0x7122, //CJK UNIFIED IDEOGRAPH + 0xDA61: 0x7132, //CJK UNIFIED IDEOGRAPH + 0xDA62: 0x711F, //CJK UNIFIED IDEOGRAPH + 0xDA63: 0x7128, //CJK UNIFIED IDEOGRAPH + 0xDA64: 0x713A, //CJK UNIFIED IDEOGRAPH + 0xDA65: 0x711B, //CJK UNIFIED IDEOGRAPH + 0xDA66: 0x724B, //CJK UNIFIED IDEOGRAPH + 0xDA67: 0x725A, //CJK UNIFIED IDEOGRAPH + 0xDA68: 0x7288, //CJK UNIFIED IDEOGRAPH + 0xDA69: 0x7289, //CJK UNIFIED IDEOGRAPH + 0xDA6A: 0x7286, //CJK UNIFIED IDEOGRAPH + 0xDA6B: 0x7285, //CJK UNIFIED IDEOGRAPH + 0xDA6C: 0x728B, //CJK UNIFIED IDEOGRAPH + 0xDA6D: 0x7312, //CJK UNIFIED IDEOGRAPH + 0xDA6E: 0x730B, //CJK UNIFIED IDEOGRAPH + 0xDA6F: 0x7330, //CJK UNIFIED IDEOGRAPH + 0xDA70: 0x7322, //CJK UNIFIED IDEOGRAPH + 0xDA71: 0x7331, //CJK UNIFIED IDEOGRAPH + 0xDA72: 0x7333, //CJK UNIFIED IDEOGRAPH + 0xDA73: 0x7327, //CJK UNIFIED IDEOGRAPH + 0xDA74: 0x7332, //CJK UNIFIED IDEOGRAPH + 0xDA75: 0x732D, //CJK UNIFIED IDEOGRAPH + 0xDA76: 0x7326, //CJK UNIFIED IDEOGRAPH + 0xDA77: 0x7323, //CJK UNIFIED IDEOGRAPH + 0xDA78: 0x7335, //CJK UNIFIED IDEOGRAPH + 0xDA79: 0x730C, //CJK UNIFIED IDEOGRAPH + 0xDA7A: 0x742E, //CJK UNIFIED IDEOGRAPH + 0xDA7B: 0x742C, //CJK UNIFIED IDEOGRAPH + 0xDA7C: 0x7430, //CJK UNIFIED IDEOGRAPH + 0xDA7D: 0x742B, //CJK UNIFIED IDEOGRAPH + 0xDA7E: 0x7416, //CJK UNIFIED IDEOGRAPH + 0xDAA1: 0x741A, //CJK UNIFIED IDEOGRAPH + 0xDAA2: 0x7421, //CJK UNIFIED IDEOGRAPH + 0xDAA3: 0x742D, //CJK UNIFIED IDEOGRAPH + 0xDAA4: 0x7431, //CJK UNIFIED IDEOGRAPH + 0xDAA5: 0x7424, //CJK UNIFIED IDEOGRAPH + 0xDAA6: 0x7423, //CJK UNIFIED IDEOGRAPH + 0xDAA7: 0x741D, //CJK UNIFIED IDEOGRAPH + 0xDAA8: 0x7429, //CJK UNIFIED IDEOGRAPH + 0xDAA9: 0x7420, //CJK UNIFIED IDEOGRAPH + 0xDAAA: 0x7432, //CJK UNIFIED IDEOGRAPH + 0xDAAB: 0x74FB, //CJK UNIFIED IDEOGRAPH + 0xDAAC: 0x752F, //CJK UNIFIED IDEOGRAPH + 0xDAAD: 0x756F, //CJK UNIFIED IDEOGRAPH + 0xDAAE: 0x756C, //CJK UNIFIED IDEOGRAPH + 0xDAAF: 0x75E7, //CJK UNIFIED IDEOGRAPH + 0xDAB0: 0x75DA, //CJK UNIFIED IDEOGRAPH + 0xDAB1: 0x75E1, //CJK UNIFIED IDEOGRAPH + 0xDAB2: 0x75E6, //CJK UNIFIED IDEOGRAPH + 0xDAB3: 0x75DD, //CJK UNIFIED IDEOGRAPH + 0xDAB4: 0x75DF, //CJK UNIFIED IDEOGRAPH + 0xDAB5: 0x75E4, //CJK UNIFIED IDEOGRAPH + 0xDAB6: 0x75D7, //CJK UNIFIED IDEOGRAPH + 0xDAB7: 0x7695, //CJK UNIFIED IDEOGRAPH + 0xDAB8: 0x7692, //CJK UNIFIED IDEOGRAPH + 0xDAB9: 0x76DA, //CJK UNIFIED IDEOGRAPH + 0xDABA: 0x7746, //CJK UNIFIED IDEOGRAPH + 0xDABB: 0x7747, //CJK UNIFIED IDEOGRAPH + 0xDABC: 0x7744, //CJK UNIFIED IDEOGRAPH + 0xDABD: 0x774D, //CJK UNIFIED IDEOGRAPH + 0xDABE: 0x7745, //CJK UNIFIED IDEOGRAPH + 0xDABF: 0x774A, //CJK UNIFIED IDEOGRAPH + 0xDAC0: 0x774E, //CJK UNIFIED IDEOGRAPH + 0xDAC1: 0x774B, //CJK UNIFIED IDEOGRAPH + 0xDAC2: 0x774C, //CJK UNIFIED IDEOGRAPH + 0xDAC3: 0x77DE, //CJK UNIFIED IDEOGRAPH + 0xDAC4: 0x77EC, //CJK UNIFIED IDEOGRAPH + 0xDAC5: 0x7860, //CJK UNIFIED IDEOGRAPH + 0xDAC6: 0x7864, //CJK UNIFIED IDEOGRAPH + 0xDAC7: 0x7865, //CJK UNIFIED IDEOGRAPH + 0xDAC8: 0x785C, //CJK UNIFIED IDEOGRAPH + 0xDAC9: 0x786D, //CJK UNIFIED IDEOGRAPH + 0xDACA: 0x7871, //CJK UNIFIED IDEOGRAPH + 0xDACB: 0x786A, //CJK UNIFIED IDEOGRAPH + 0xDACC: 0x786E, //CJK UNIFIED IDEOGRAPH + 0xDACD: 0x7870, //CJK UNIFIED IDEOGRAPH + 0xDACE: 0x7869, //CJK UNIFIED IDEOGRAPH + 0xDACF: 0x7868, //CJK UNIFIED IDEOGRAPH + 0xDAD0: 0x785E, //CJK UNIFIED IDEOGRAPH + 0xDAD1: 0x7862, //CJK UNIFIED IDEOGRAPH + 0xDAD2: 0x7974, //CJK UNIFIED IDEOGRAPH + 0xDAD3: 0x7973, //CJK UNIFIED IDEOGRAPH + 0xDAD4: 0x7972, //CJK UNIFIED IDEOGRAPH + 0xDAD5: 0x7970, //CJK UNIFIED IDEOGRAPH + 0xDAD6: 0x7A02, //CJK UNIFIED IDEOGRAPH + 0xDAD7: 0x7A0A, //CJK UNIFIED IDEOGRAPH + 0xDAD8: 0x7A03, //CJK UNIFIED IDEOGRAPH + 0xDAD9: 0x7A0C, //CJK UNIFIED IDEOGRAPH + 0xDADA: 0x7A04, //CJK UNIFIED IDEOGRAPH + 0xDADB: 0x7A99, //CJK UNIFIED IDEOGRAPH + 0xDADC: 0x7AE6, //CJK UNIFIED IDEOGRAPH + 0xDADD: 0x7AE4, //CJK UNIFIED IDEOGRAPH + 0xDADE: 0x7B4A, //CJK UNIFIED IDEOGRAPH + 0xDADF: 0x7B3B, //CJK UNIFIED IDEOGRAPH + 0xDAE0: 0x7B44, //CJK UNIFIED IDEOGRAPH + 0xDAE1: 0x7B48, //CJK UNIFIED IDEOGRAPH + 0xDAE2: 0x7B4C, //CJK UNIFIED IDEOGRAPH + 0xDAE3: 0x7B4E, //CJK UNIFIED IDEOGRAPH + 0xDAE4: 0x7B40, //CJK UNIFIED IDEOGRAPH + 0xDAE5: 0x7B58, //CJK UNIFIED IDEOGRAPH + 0xDAE6: 0x7B45, //CJK UNIFIED IDEOGRAPH + 0xDAE7: 0x7CA2, //CJK UNIFIED IDEOGRAPH + 0xDAE8: 0x7C9E, //CJK UNIFIED IDEOGRAPH + 0xDAE9: 0x7CA8, //CJK UNIFIED IDEOGRAPH + 0xDAEA: 0x7CA1, //CJK UNIFIED IDEOGRAPH + 0xDAEB: 0x7D58, //CJK UNIFIED IDEOGRAPH + 0xDAEC: 0x7D6F, //CJK UNIFIED IDEOGRAPH + 0xDAED: 0x7D63, //CJK UNIFIED IDEOGRAPH + 0xDAEE: 0x7D53, //CJK UNIFIED IDEOGRAPH + 0xDAEF: 0x7D56, //CJK UNIFIED IDEOGRAPH + 0xDAF0: 0x7D67, //CJK UNIFIED IDEOGRAPH + 0xDAF1: 0x7D6A, //CJK UNIFIED IDEOGRAPH + 0xDAF2: 0x7D4F, //CJK UNIFIED IDEOGRAPH + 0xDAF3: 0x7D6D, //CJK UNIFIED IDEOGRAPH + 0xDAF4: 0x7D5C, //CJK UNIFIED IDEOGRAPH + 0xDAF5: 0x7D6B, //CJK UNIFIED IDEOGRAPH + 0xDAF6: 0x7D52, //CJK UNIFIED IDEOGRAPH + 0xDAF7: 0x7D54, //CJK UNIFIED IDEOGRAPH + 0xDAF8: 0x7D69, //CJK UNIFIED IDEOGRAPH + 0xDAF9: 0x7D51, //CJK UNIFIED IDEOGRAPH + 0xDAFA: 0x7D5F, //CJK UNIFIED IDEOGRAPH + 0xDAFB: 0x7D4E, //CJK UNIFIED IDEOGRAPH + 0xDAFC: 0x7F3E, //CJK UNIFIED IDEOGRAPH + 0xDAFD: 0x7F3F, //CJK UNIFIED IDEOGRAPH + 0xDAFE: 0x7F65, //CJK UNIFIED IDEOGRAPH + 0xDB40: 0x7F66, //CJK UNIFIED IDEOGRAPH + 0xDB41: 0x7FA2, //CJK UNIFIED IDEOGRAPH + 0xDB42: 0x7FA0, //CJK UNIFIED IDEOGRAPH + 0xDB43: 0x7FA1, //CJK UNIFIED IDEOGRAPH + 0xDB44: 0x7FD7, //CJK UNIFIED IDEOGRAPH + 0xDB45: 0x8051, //CJK UNIFIED IDEOGRAPH + 0xDB46: 0x804F, //CJK UNIFIED IDEOGRAPH + 0xDB47: 0x8050, //CJK UNIFIED IDEOGRAPH + 0xDB48: 0x80FE, //CJK UNIFIED IDEOGRAPH + 0xDB49: 0x80D4, //CJK UNIFIED IDEOGRAPH + 0xDB4A: 0x8143, //CJK UNIFIED IDEOGRAPH + 0xDB4B: 0x814A, //CJK UNIFIED IDEOGRAPH + 0xDB4C: 0x8152, //CJK UNIFIED IDEOGRAPH + 0xDB4D: 0x814F, //CJK UNIFIED IDEOGRAPH + 0xDB4E: 0x8147, //CJK UNIFIED IDEOGRAPH + 0xDB4F: 0x813D, //CJK UNIFIED IDEOGRAPH + 0xDB50: 0x814D, //CJK UNIFIED IDEOGRAPH + 0xDB51: 0x813A, //CJK UNIFIED IDEOGRAPH + 0xDB52: 0x81E6, //CJK UNIFIED IDEOGRAPH + 0xDB53: 0x81EE, //CJK UNIFIED IDEOGRAPH + 0xDB54: 0x81F7, //CJK UNIFIED IDEOGRAPH + 0xDB55: 0x81F8, //CJK UNIFIED IDEOGRAPH + 0xDB56: 0x81F9, //CJK UNIFIED IDEOGRAPH + 0xDB57: 0x8204, //CJK UNIFIED IDEOGRAPH + 0xDB58: 0x823C, //CJK UNIFIED IDEOGRAPH + 0xDB59: 0x823D, //CJK UNIFIED IDEOGRAPH + 0xDB5A: 0x823F, //CJK UNIFIED IDEOGRAPH + 0xDB5B: 0x8275, //CJK UNIFIED IDEOGRAPH + 0xDB5C: 0x833B, //CJK UNIFIED IDEOGRAPH + 0xDB5D: 0x83CF, //CJK UNIFIED IDEOGRAPH + 0xDB5E: 0x83F9, //CJK UNIFIED IDEOGRAPH + 0xDB5F: 0x8423, //CJK UNIFIED IDEOGRAPH + 0xDB60: 0x83C0, //CJK UNIFIED IDEOGRAPH + 0xDB61: 0x83E8, //CJK UNIFIED IDEOGRAPH + 0xDB62: 0x8412, //CJK UNIFIED IDEOGRAPH + 0xDB63: 0x83E7, //CJK UNIFIED IDEOGRAPH + 0xDB64: 0x83E4, //CJK UNIFIED IDEOGRAPH + 0xDB65: 0x83FC, //CJK UNIFIED IDEOGRAPH + 0xDB66: 0x83F6, //CJK UNIFIED IDEOGRAPH + 0xDB67: 0x8410, //CJK UNIFIED IDEOGRAPH + 0xDB68: 0x83C6, //CJK UNIFIED IDEOGRAPH + 0xDB69: 0x83C8, //CJK UNIFIED IDEOGRAPH + 0xDB6A: 0x83EB, //CJK UNIFIED IDEOGRAPH + 0xDB6B: 0x83E3, //CJK UNIFIED IDEOGRAPH + 0xDB6C: 0x83BF, //CJK UNIFIED IDEOGRAPH + 0xDB6D: 0x8401, //CJK UNIFIED IDEOGRAPH + 0xDB6E: 0x83DD, //CJK UNIFIED IDEOGRAPH + 0xDB6F: 0x83E5, //CJK UNIFIED IDEOGRAPH + 0xDB70: 0x83D8, //CJK UNIFIED IDEOGRAPH + 0xDB71: 0x83FF, //CJK UNIFIED IDEOGRAPH + 0xDB72: 0x83E1, //CJK UNIFIED IDEOGRAPH + 0xDB73: 0x83CB, //CJK UNIFIED IDEOGRAPH + 0xDB74: 0x83CE, //CJK UNIFIED IDEOGRAPH + 0xDB75: 0x83D6, //CJK UNIFIED IDEOGRAPH + 0xDB76: 0x83F5, //CJK UNIFIED IDEOGRAPH + 0xDB77: 0x83C9, //CJK UNIFIED IDEOGRAPH + 0xDB78: 0x8409, //CJK UNIFIED IDEOGRAPH + 0xDB79: 0x840F, //CJK UNIFIED IDEOGRAPH + 0xDB7A: 0x83DE, //CJK UNIFIED IDEOGRAPH + 0xDB7B: 0x8411, //CJK UNIFIED IDEOGRAPH + 0xDB7C: 0x8406, //CJK UNIFIED IDEOGRAPH + 0xDB7D: 0x83C2, //CJK UNIFIED IDEOGRAPH + 0xDB7E: 0x83F3, //CJK UNIFIED IDEOGRAPH + 0xDBA1: 0x83D5, //CJK UNIFIED IDEOGRAPH + 0xDBA2: 0x83FA, //CJK UNIFIED IDEOGRAPH + 0xDBA3: 0x83C7, //CJK UNIFIED IDEOGRAPH + 0xDBA4: 0x83D1, //CJK UNIFIED IDEOGRAPH + 0xDBA5: 0x83EA, //CJK UNIFIED IDEOGRAPH + 0xDBA6: 0x8413, //CJK UNIFIED IDEOGRAPH + 0xDBA7: 0x83C3, //CJK UNIFIED IDEOGRAPH + 0xDBA8: 0x83EC, //CJK UNIFIED IDEOGRAPH + 0xDBA9: 0x83EE, //CJK UNIFIED IDEOGRAPH + 0xDBAA: 0x83C4, //CJK UNIFIED IDEOGRAPH + 0xDBAB: 0x83FB, //CJK UNIFIED IDEOGRAPH + 0xDBAC: 0x83D7, //CJK UNIFIED IDEOGRAPH + 0xDBAD: 0x83E2, //CJK UNIFIED IDEOGRAPH + 0xDBAE: 0x841B, //CJK UNIFIED IDEOGRAPH + 0xDBAF: 0x83DB, //CJK UNIFIED IDEOGRAPH + 0xDBB0: 0x83FE, //CJK UNIFIED IDEOGRAPH + 0xDBB1: 0x86D8, //CJK UNIFIED IDEOGRAPH + 0xDBB2: 0x86E2, //CJK UNIFIED IDEOGRAPH + 0xDBB3: 0x86E6, //CJK UNIFIED IDEOGRAPH + 0xDBB4: 0x86D3, //CJK UNIFIED IDEOGRAPH + 0xDBB5: 0x86E3, //CJK UNIFIED IDEOGRAPH + 0xDBB6: 0x86DA, //CJK UNIFIED IDEOGRAPH + 0xDBB7: 0x86EA, //CJK UNIFIED IDEOGRAPH + 0xDBB8: 0x86DD, //CJK UNIFIED IDEOGRAPH + 0xDBB9: 0x86EB, //CJK UNIFIED IDEOGRAPH + 0xDBBA: 0x86DC, //CJK UNIFIED IDEOGRAPH + 0xDBBB: 0x86EC, //CJK UNIFIED IDEOGRAPH + 0xDBBC: 0x86E9, //CJK UNIFIED IDEOGRAPH + 0xDBBD: 0x86D7, //CJK UNIFIED IDEOGRAPH + 0xDBBE: 0x86E8, //CJK UNIFIED IDEOGRAPH + 0xDBBF: 0x86D1, //CJK UNIFIED IDEOGRAPH + 0xDBC0: 0x8848, //CJK UNIFIED IDEOGRAPH + 0xDBC1: 0x8856, //CJK UNIFIED IDEOGRAPH + 0xDBC2: 0x8855, //CJK UNIFIED IDEOGRAPH + 0xDBC3: 0x88BA, //CJK UNIFIED IDEOGRAPH + 0xDBC4: 0x88D7, //CJK UNIFIED IDEOGRAPH + 0xDBC5: 0x88B9, //CJK UNIFIED IDEOGRAPH + 0xDBC6: 0x88B8, //CJK UNIFIED IDEOGRAPH + 0xDBC7: 0x88C0, //CJK UNIFIED IDEOGRAPH + 0xDBC8: 0x88BE, //CJK UNIFIED IDEOGRAPH + 0xDBC9: 0x88B6, //CJK UNIFIED IDEOGRAPH + 0xDBCA: 0x88BC, //CJK UNIFIED IDEOGRAPH + 0xDBCB: 0x88B7, //CJK UNIFIED IDEOGRAPH + 0xDBCC: 0x88BD, //CJK UNIFIED IDEOGRAPH + 0xDBCD: 0x88B2, //CJK UNIFIED IDEOGRAPH + 0xDBCE: 0x8901, //CJK UNIFIED IDEOGRAPH + 0xDBCF: 0x88C9, //CJK UNIFIED IDEOGRAPH + 0xDBD0: 0x8995, //CJK UNIFIED IDEOGRAPH + 0xDBD1: 0x8998, //CJK UNIFIED IDEOGRAPH + 0xDBD2: 0x8997, //CJK UNIFIED IDEOGRAPH + 0xDBD3: 0x89DD, //CJK UNIFIED IDEOGRAPH + 0xDBD4: 0x89DA, //CJK UNIFIED IDEOGRAPH + 0xDBD5: 0x89DB, //CJK UNIFIED IDEOGRAPH + 0xDBD6: 0x8A4E, //CJK UNIFIED IDEOGRAPH + 0xDBD7: 0x8A4D, //CJK UNIFIED IDEOGRAPH + 0xDBD8: 0x8A39, //CJK UNIFIED IDEOGRAPH + 0xDBD9: 0x8A59, //CJK UNIFIED IDEOGRAPH + 0xDBDA: 0x8A40, //CJK UNIFIED IDEOGRAPH + 0xDBDB: 0x8A57, //CJK UNIFIED IDEOGRAPH + 0xDBDC: 0x8A58, //CJK UNIFIED IDEOGRAPH + 0xDBDD: 0x8A44, //CJK UNIFIED IDEOGRAPH + 0xDBDE: 0x8A45, //CJK UNIFIED IDEOGRAPH + 0xDBDF: 0x8A52, //CJK UNIFIED IDEOGRAPH + 0xDBE0: 0x8A48, //CJK UNIFIED IDEOGRAPH + 0xDBE1: 0x8A51, //CJK UNIFIED IDEOGRAPH + 0xDBE2: 0x8A4A, //CJK UNIFIED IDEOGRAPH + 0xDBE3: 0x8A4C, //CJK UNIFIED IDEOGRAPH + 0xDBE4: 0x8A4F, //CJK UNIFIED IDEOGRAPH + 0xDBE5: 0x8C5F, //CJK UNIFIED IDEOGRAPH + 0xDBE6: 0x8C81, //CJK UNIFIED IDEOGRAPH + 0xDBE7: 0x8C80, //CJK UNIFIED IDEOGRAPH + 0xDBE8: 0x8CBA, //CJK UNIFIED IDEOGRAPH + 0xDBE9: 0x8CBE, //CJK UNIFIED IDEOGRAPH + 0xDBEA: 0x8CB0, //CJK UNIFIED IDEOGRAPH + 0xDBEB: 0x8CB9, //CJK UNIFIED IDEOGRAPH + 0xDBEC: 0x8CB5, //CJK UNIFIED IDEOGRAPH + 0xDBED: 0x8D84, //CJK UNIFIED IDEOGRAPH + 0xDBEE: 0x8D80, //CJK UNIFIED IDEOGRAPH + 0xDBEF: 0x8D89, //CJK UNIFIED IDEOGRAPH + 0xDBF0: 0x8DD8, //CJK UNIFIED IDEOGRAPH + 0xDBF1: 0x8DD3, //CJK UNIFIED IDEOGRAPH + 0xDBF2: 0x8DCD, //CJK UNIFIED IDEOGRAPH + 0xDBF3: 0x8DC7, //CJK UNIFIED IDEOGRAPH + 0xDBF4: 0x8DD6, //CJK UNIFIED IDEOGRAPH + 0xDBF5: 0x8DDC, //CJK UNIFIED IDEOGRAPH + 0xDBF6: 0x8DCF, //CJK UNIFIED IDEOGRAPH + 0xDBF7: 0x8DD5, //CJK UNIFIED IDEOGRAPH + 0xDBF8: 0x8DD9, //CJK UNIFIED IDEOGRAPH + 0xDBF9: 0x8DC8, //CJK UNIFIED IDEOGRAPH + 0xDBFA: 0x8DD7, //CJK UNIFIED IDEOGRAPH + 0xDBFB: 0x8DC5, //CJK UNIFIED IDEOGRAPH + 0xDBFC: 0x8EEF, //CJK UNIFIED IDEOGRAPH + 0xDBFD: 0x8EF7, //CJK UNIFIED IDEOGRAPH + 0xDBFE: 0x8EFA, //CJK UNIFIED IDEOGRAPH + 0xDC40: 0x8EF9, //CJK UNIFIED IDEOGRAPH + 0xDC41: 0x8EE6, //CJK UNIFIED IDEOGRAPH + 0xDC42: 0x8EEE, //CJK UNIFIED IDEOGRAPH + 0xDC43: 0x8EE5, //CJK UNIFIED IDEOGRAPH + 0xDC44: 0x8EF5, //CJK UNIFIED IDEOGRAPH + 0xDC45: 0x8EE7, //CJK UNIFIED IDEOGRAPH + 0xDC46: 0x8EE8, //CJK UNIFIED IDEOGRAPH + 0xDC47: 0x8EF6, //CJK UNIFIED IDEOGRAPH + 0xDC48: 0x8EEB, //CJK UNIFIED IDEOGRAPH + 0xDC49: 0x8EF1, //CJK UNIFIED IDEOGRAPH + 0xDC4A: 0x8EEC, //CJK UNIFIED IDEOGRAPH + 0xDC4B: 0x8EF4, //CJK UNIFIED IDEOGRAPH + 0xDC4C: 0x8EE9, //CJK UNIFIED IDEOGRAPH + 0xDC4D: 0x902D, //CJK UNIFIED IDEOGRAPH + 0xDC4E: 0x9034, //CJK UNIFIED IDEOGRAPH + 0xDC4F: 0x902F, //CJK UNIFIED IDEOGRAPH + 0xDC50: 0x9106, //CJK UNIFIED IDEOGRAPH + 0xDC51: 0x912C, //CJK UNIFIED IDEOGRAPH + 0xDC52: 0x9104, //CJK UNIFIED IDEOGRAPH + 0xDC53: 0x90FF, //CJK UNIFIED IDEOGRAPH + 0xDC54: 0x90FC, //CJK UNIFIED IDEOGRAPH + 0xDC55: 0x9108, //CJK UNIFIED IDEOGRAPH + 0xDC56: 0x90F9, //CJK UNIFIED IDEOGRAPH + 0xDC57: 0x90FB, //CJK UNIFIED IDEOGRAPH + 0xDC58: 0x9101, //CJK UNIFIED IDEOGRAPH + 0xDC59: 0x9100, //CJK UNIFIED IDEOGRAPH + 0xDC5A: 0x9107, //CJK UNIFIED IDEOGRAPH + 0xDC5B: 0x9105, //CJK UNIFIED IDEOGRAPH + 0xDC5C: 0x9103, //CJK UNIFIED IDEOGRAPH + 0xDC5D: 0x9161, //CJK UNIFIED IDEOGRAPH + 0xDC5E: 0x9164, //CJK UNIFIED IDEOGRAPH + 0xDC5F: 0x915F, //CJK UNIFIED IDEOGRAPH + 0xDC60: 0x9162, //CJK UNIFIED IDEOGRAPH + 0xDC61: 0x9160, //CJK UNIFIED IDEOGRAPH + 0xDC62: 0x9201, //CJK UNIFIED IDEOGRAPH + 0xDC63: 0x920A, //CJK UNIFIED IDEOGRAPH + 0xDC64: 0x9225, //CJK UNIFIED IDEOGRAPH + 0xDC65: 0x9203, //CJK UNIFIED IDEOGRAPH + 0xDC66: 0x921A, //CJK UNIFIED IDEOGRAPH + 0xDC67: 0x9226, //CJK UNIFIED IDEOGRAPH + 0xDC68: 0x920F, //CJK UNIFIED IDEOGRAPH + 0xDC69: 0x920C, //CJK UNIFIED IDEOGRAPH + 0xDC6A: 0x9200, //CJK UNIFIED IDEOGRAPH + 0xDC6B: 0x9212, //CJK UNIFIED IDEOGRAPH + 0xDC6C: 0x91FF, //CJK UNIFIED IDEOGRAPH + 0xDC6D: 0x91FD, //CJK UNIFIED IDEOGRAPH + 0xDC6E: 0x9206, //CJK UNIFIED IDEOGRAPH + 0xDC6F: 0x9204, //CJK UNIFIED IDEOGRAPH + 0xDC70: 0x9227, //CJK UNIFIED IDEOGRAPH + 0xDC71: 0x9202, //CJK UNIFIED IDEOGRAPH + 0xDC72: 0x921C, //CJK UNIFIED IDEOGRAPH + 0xDC73: 0x9224, //CJK UNIFIED IDEOGRAPH + 0xDC74: 0x9219, //CJK UNIFIED IDEOGRAPH + 0xDC75: 0x9217, //CJK UNIFIED IDEOGRAPH + 0xDC76: 0x9205, //CJK UNIFIED IDEOGRAPH + 0xDC77: 0x9216, //CJK UNIFIED IDEOGRAPH + 0xDC78: 0x957B, //CJK UNIFIED IDEOGRAPH + 0xDC79: 0x958D, //CJK UNIFIED IDEOGRAPH + 0xDC7A: 0x958C, //CJK UNIFIED IDEOGRAPH + 0xDC7B: 0x9590, //CJK UNIFIED IDEOGRAPH + 0xDC7C: 0x9687, //CJK UNIFIED IDEOGRAPH + 0xDC7D: 0x967E, //CJK UNIFIED IDEOGRAPH + 0xDC7E: 0x9688, //CJK UNIFIED IDEOGRAPH + 0xDCA1: 0x9689, //CJK UNIFIED IDEOGRAPH + 0xDCA2: 0x9683, //CJK UNIFIED IDEOGRAPH + 0xDCA3: 0x9680, //CJK UNIFIED IDEOGRAPH + 0xDCA4: 0x96C2, //CJK UNIFIED IDEOGRAPH + 0xDCA5: 0x96C8, //CJK UNIFIED IDEOGRAPH + 0xDCA6: 0x96C3, //CJK UNIFIED IDEOGRAPH + 0xDCA7: 0x96F1, //CJK UNIFIED IDEOGRAPH + 0xDCA8: 0x96F0, //CJK UNIFIED IDEOGRAPH + 0xDCA9: 0x976C, //CJK UNIFIED IDEOGRAPH + 0xDCAA: 0x9770, //CJK UNIFIED IDEOGRAPH + 0xDCAB: 0x976E, //CJK UNIFIED IDEOGRAPH + 0xDCAC: 0x9807, //CJK UNIFIED IDEOGRAPH + 0xDCAD: 0x98A9, //CJK UNIFIED IDEOGRAPH + 0xDCAE: 0x98EB, //CJK UNIFIED IDEOGRAPH + 0xDCAF: 0x9CE6, //CJK UNIFIED IDEOGRAPH + 0xDCB0: 0x9EF9, //CJK UNIFIED IDEOGRAPH + 0xDCB1: 0x4E83, //CJK UNIFIED IDEOGRAPH + 0xDCB2: 0x4E84, //CJK UNIFIED IDEOGRAPH + 0xDCB3: 0x4EB6, //CJK UNIFIED IDEOGRAPH + 0xDCB4: 0x50BD, //CJK UNIFIED IDEOGRAPH + 0xDCB5: 0x50BF, //CJK UNIFIED IDEOGRAPH + 0xDCB6: 0x50C6, //CJK UNIFIED IDEOGRAPH + 0xDCB7: 0x50AE, //CJK UNIFIED IDEOGRAPH + 0xDCB8: 0x50C4, //CJK UNIFIED IDEOGRAPH + 0xDCB9: 0x50CA, //CJK UNIFIED IDEOGRAPH + 0xDCBA: 0x50B4, //CJK UNIFIED IDEOGRAPH + 0xDCBB: 0x50C8, //CJK UNIFIED IDEOGRAPH + 0xDCBC: 0x50C2, //CJK UNIFIED IDEOGRAPH + 0xDCBD: 0x50B0, //CJK UNIFIED IDEOGRAPH + 0xDCBE: 0x50C1, //CJK UNIFIED IDEOGRAPH + 0xDCBF: 0x50BA, //CJK UNIFIED IDEOGRAPH + 0xDCC0: 0x50B1, //CJK UNIFIED IDEOGRAPH + 0xDCC1: 0x50CB, //CJK UNIFIED IDEOGRAPH + 0xDCC2: 0x50C9, //CJK UNIFIED IDEOGRAPH + 0xDCC3: 0x50B6, //CJK UNIFIED IDEOGRAPH + 0xDCC4: 0x50B8, //CJK UNIFIED IDEOGRAPH + 0xDCC5: 0x51D7, //CJK UNIFIED IDEOGRAPH + 0xDCC6: 0x527A, //CJK UNIFIED IDEOGRAPH + 0xDCC7: 0x5278, //CJK UNIFIED IDEOGRAPH + 0xDCC8: 0x527B, //CJK UNIFIED IDEOGRAPH + 0xDCC9: 0x527C, //CJK UNIFIED IDEOGRAPH + 0xDCCA: 0x55C3, //CJK UNIFIED IDEOGRAPH + 0xDCCB: 0x55DB, //CJK UNIFIED IDEOGRAPH + 0xDCCC: 0x55CC, //CJK UNIFIED IDEOGRAPH + 0xDCCD: 0x55D0, //CJK UNIFIED IDEOGRAPH + 0xDCCE: 0x55CB, //CJK UNIFIED IDEOGRAPH + 0xDCCF: 0x55CA, //CJK UNIFIED IDEOGRAPH + 0xDCD0: 0x55DD, //CJK UNIFIED IDEOGRAPH + 0xDCD1: 0x55C0, //CJK UNIFIED IDEOGRAPH + 0xDCD2: 0x55D4, //CJK UNIFIED IDEOGRAPH + 0xDCD3: 0x55C4, //CJK UNIFIED IDEOGRAPH + 0xDCD4: 0x55E9, //CJK UNIFIED IDEOGRAPH + 0xDCD5: 0x55BF, //CJK UNIFIED IDEOGRAPH + 0xDCD6: 0x55D2, //CJK UNIFIED IDEOGRAPH + 0xDCD7: 0x558D, //CJK UNIFIED IDEOGRAPH + 0xDCD8: 0x55CF, //CJK UNIFIED IDEOGRAPH + 0xDCD9: 0x55D5, //CJK UNIFIED IDEOGRAPH + 0xDCDA: 0x55E2, //CJK UNIFIED IDEOGRAPH + 0xDCDB: 0x55D6, //CJK UNIFIED IDEOGRAPH + 0xDCDC: 0x55C8, //CJK UNIFIED IDEOGRAPH + 0xDCDD: 0x55F2, //CJK UNIFIED IDEOGRAPH + 0xDCDE: 0x55CD, //CJK UNIFIED IDEOGRAPH + 0xDCDF: 0x55D9, //CJK UNIFIED IDEOGRAPH + 0xDCE0: 0x55C2, //CJK UNIFIED IDEOGRAPH + 0xDCE1: 0x5714, //CJK UNIFIED IDEOGRAPH + 0xDCE2: 0x5853, //CJK UNIFIED IDEOGRAPH + 0xDCE3: 0x5868, //CJK UNIFIED IDEOGRAPH + 0xDCE4: 0x5864, //CJK UNIFIED IDEOGRAPH + 0xDCE5: 0x584F, //CJK UNIFIED IDEOGRAPH + 0xDCE6: 0x584D, //CJK UNIFIED IDEOGRAPH + 0xDCE7: 0x5849, //CJK UNIFIED IDEOGRAPH + 0xDCE8: 0x586F, //CJK UNIFIED IDEOGRAPH + 0xDCE9: 0x5855, //CJK UNIFIED IDEOGRAPH + 0xDCEA: 0x584E, //CJK UNIFIED IDEOGRAPH + 0xDCEB: 0x585D, //CJK UNIFIED IDEOGRAPH + 0xDCEC: 0x5859, //CJK UNIFIED IDEOGRAPH + 0xDCED: 0x5865, //CJK UNIFIED IDEOGRAPH + 0xDCEE: 0x585B, //CJK UNIFIED IDEOGRAPH + 0xDCEF: 0x583D, //CJK UNIFIED IDEOGRAPH + 0xDCF0: 0x5863, //CJK UNIFIED IDEOGRAPH + 0xDCF1: 0x5871, //CJK UNIFIED IDEOGRAPH + 0xDCF2: 0x58FC, //CJK UNIFIED IDEOGRAPH + 0xDCF3: 0x5AC7, //CJK UNIFIED IDEOGRAPH + 0xDCF4: 0x5AC4, //CJK UNIFIED IDEOGRAPH + 0xDCF5: 0x5ACB, //CJK UNIFIED IDEOGRAPH + 0xDCF6: 0x5ABA, //CJK UNIFIED IDEOGRAPH + 0xDCF7: 0x5AB8, //CJK UNIFIED IDEOGRAPH + 0xDCF8: 0x5AB1, //CJK UNIFIED IDEOGRAPH + 0xDCF9: 0x5AB5, //CJK UNIFIED IDEOGRAPH + 0xDCFA: 0x5AB0, //CJK UNIFIED IDEOGRAPH + 0xDCFB: 0x5ABF, //CJK UNIFIED IDEOGRAPH + 0xDCFC: 0x5AC8, //CJK UNIFIED IDEOGRAPH + 0xDCFD: 0x5ABB, //CJK UNIFIED IDEOGRAPH + 0xDCFE: 0x5AC6, //CJK UNIFIED IDEOGRAPH + 0xDD40: 0x5AB7, //CJK UNIFIED IDEOGRAPH + 0xDD41: 0x5AC0, //CJK UNIFIED IDEOGRAPH + 0xDD42: 0x5ACA, //CJK UNIFIED IDEOGRAPH + 0xDD43: 0x5AB4, //CJK UNIFIED IDEOGRAPH + 0xDD44: 0x5AB6, //CJK UNIFIED IDEOGRAPH + 0xDD45: 0x5ACD, //CJK UNIFIED IDEOGRAPH + 0xDD46: 0x5AB9, //CJK UNIFIED IDEOGRAPH + 0xDD47: 0x5A90, //CJK UNIFIED IDEOGRAPH + 0xDD48: 0x5BD6, //CJK UNIFIED IDEOGRAPH + 0xDD49: 0x5BD8, //CJK UNIFIED IDEOGRAPH + 0xDD4A: 0x5BD9, //CJK UNIFIED IDEOGRAPH + 0xDD4B: 0x5C1F, //CJK UNIFIED IDEOGRAPH + 0xDD4C: 0x5C33, //CJK UNIFIED IDEOGRAPH + 0xDD4D: 0x5D71, //CJK UNIFIED IDEOGRAPH + 0xDD4E: 0x5D63, //CJK UNIFIED IDEOGRAPH + 0xDD4F: 0x5D4A, //CJK UNIFIED IDEOGRAPH + 0xDD50: 0x5D65, //CJK UNIFIED IDEOGRAPH + 0xDD51: 0x5D72, //CJK UNIFIED IDEOGRAPH + 0xDD52: 0x5D6C, //CJK UNIFIED IDEOGRAPH + 0xDD53: 0x5D5E, //CJK UNIFIED IDEOGRAPH + 0xDD54: 0x5D68, //CJK UNIFIED IDEOGRAPH + 0xDD55: 0x5D67, //CJK UNIFIED IDEOGRAPH + 0xDD56: 0x5D62, //CJK UNIFIED IDEOGRAPH + 0xDD57: 0x5DF0, //CJK UNIFIED IDEOGRAPH + 0xDD58: 0x5E4F, //CJK UNIFIED IDEOGRAPH + 0xDD59: 0x5E4E, //CJK UNIFIED IDEOGRAPH + 0xDD5A: 0x5E4A, //CJK UNIFIED IDEOGRAPH + 0xDD5B: 0x5E4D, //CJK UNIFIED IDEOGRAPH + 0xDD5C: 0x5E4B, //CJK UNIFIED IDEOGRAPH + 0xDD5D: 0x5EC5, //CJK UNIFIED IDEOGRAPH + 0xDD5E: 0x5ECC, //CJK UNIFIED IDEOGRAPH + 0xDD5F: 0x5EC6, //CJK UNIFIED IDEOGRAPH + 0xDD60: 0x5ECB, //CJK UNIFIED IDEOGRAPH + 0xDD61: 0x5EC7, //CJK UNIFIED IDEOGRAPH + 0xDD62: 0x5F40, //CJK UNIFIED IDEOGRAPH + 0xDD63: 0x5FAF, //CJK UNIFIED IDEOGRAPH + 0xDD64: 0x5FAD, //CJK UNIFIED IDEOGRAPH + 0xDD65: 0x60F7, //CJK UNIFIED IDEOGRAPH + 0xDD66: 0x6149, //CJK UNIFIED IDEOGRAPH + 0xDD67: 0x614A, //CJK UNIFIED IDEOGRAPH + 0xDD68: 0x612B, //CJK UNIFIED IDEOGRAPH + 0xDD69: 0x6145, //CJK UNIFIED IDEOGRAPH + 0xDD6A: 0x6136, //CJK UNIFIED IDEOGRAPH + 0xDD6B: 0x6132, //CJK UNIFIED IDEOGRAPH + 0xDD6C: 0x612E, //CJK UNIFIED IDEOGRAPH + 0xDD6D: 0x6146, //CJK UNIFIED IDEOGRAPH + 0xDD6E: 0x612F, //CJK UNIFIED IDEOGRAPH + 0xDD6F: 0x614F, //CJK UNIFIED IDEOGRAPH + 0xDD70: 0x6129, //CJK UNIFIED IDEOGRAPH + 0xDD71: 0x6140, //CJK UNIFIED IDEOGRAPH + 0xDD72: 0x6220, //CJK UNIFIED IDEOGRAPH + 0xDD73: 0x9168, //CJK UNIFIED IDEOGRAPH + 0xDD74: 0x6223, //CJK UNIFIED IDEOGRAPH + 0xDD75: 0x6225, //CJK UNIFIED IDEOGRAPH + 0xDD76: 0x6224, //CJK UNIFIED IDEOGRAPH + 0xDD77: 0x63C5, //CJK UNIFIED IDEOGRAPH + 0xDD78: 0x63F1, //CJK UNIFIED IDEOGRAPH + 0xDD79: 0x63EB, //CJK UNIFIED IDEOGRAPH + 0xDD7A: 0x6410, //CJK UNIFIED IDEOGRAPH + 0xDD7B: 0x6412, //CJK UNIFIED IDEOGRAPH + 0xDD7C: 0x6409, //CJK UNIFIED IDEOGRAPH + 0xDD7D: 0x6420, //CJK UNIFIED IDEOGRAPH + 0xDD7E: 0x6424, //CJK UNIFIED IDEOGRAPH + 0xDDA1: 0x6433, //CJK UNIFIED IDEOGRAPH + 0xDDA2: 0x6443, //CJK UNIFIED IDEOGRAPH + 0xDDA3: 0x641F, //CJK UNIFIED IDEOGRAPH + 0xDDA4: 0x6415, //CJK UNIFIED IDEOGRAPH + 0xDDA5: 0x6418, //CJK UNIFIED IDEOGRAPH + 0xDDA6: 0x6439, //CJK UNIFIED IDEOGRAPH + 0xDDA7: 0x6437, //CJK UNIFIED IDEOGRAPH + 0xDDA8: 0x6422, //CJK UNIFIED IDEOGRAPH + 0xDDA9: 0x6423, //CJK UNIFIED IDEOGRAPH + 0xDDAA: 0x640C, //CJK UNIFIED IDEOGRAPH + 0xDDAB: 0x6426, //CJK UNIFIED IDEOGRAPH + 0xDDAC: 0x6430, //CJK UNIFIED IDEOGRAPH + 0xDDAD: 0x6428, //CJK UNIFIED IDEOGRAPH + 0xDDAE: 0x6441, //CJK UNIFIED IDEOGRAPH + 0xDDAF: 0x6435, //CJK UNIFIED IDEOGRAPH + 0xDDB0: 0x642F, //CJK UNIFIED IDEOGRAPH + 0xDDB1: 0x640A, //CJK UNIFIED IDEOGRAPH + 0xDDB2: 0x641A, //CJK UNIFIED IDEOGRAPH + 0xDDB3: 0x6440, //CJK UNIFIED IDEOGRAPH + 0xDDB4: 0x6425, //CJK UNIFIED IDEOGRAPH + 0xDDB5: 0x6427, //CJK UNIFIED IDEOGRAPH + 0xDDB6: 0x640B, //CJK UNIFIED IDEOGRAPH + 0xDDB7: 0x63E7, //CJK UNIFIED IDEOGRAPH + 0xDDB8: 0x641B, //CJK UNIFIED IDEOGRAPH + 0xDDB9: 0x642E, //CJK UNIFIED IDEOGRAPH + 0xDDBA: 0x6421, //CJK UNIFIED IDEOGRAPH + 0xDDBB: 0x640E, //CJK UNIFIED IDEOGRAPH + 0xDDBC: 0x656F, //CJK UNIFIED IDEOGRAPH + 0xDDBD: 0x6592, //CJK UNIFIED IDEOGRAPH + 0xDDBE: 0x65D3, //CJK UNIFIED IDEOGRAPH + 0xDDBF: 0x6686, //CJK UNIFIED IDEOGRAPH + 0xDDC0: 0x668C, //CJK UNIFIED IDEOGRAPH + 0xDDC1: 0x6695, //CJK UNIFIED IDEOGRAPH + 0xDDC2: 0x6690, //CJK UNIFIED IDEOGRAPH + 0xDDC3: 0x668B, //CJK UNIFIED IDEOGRAPH + 0xDDC4: 0x668A, //CJK UNIFIED IDEOGRAPH + 0xDDC5: 0x6699, //CJK UNIFIED IDEOGRAPH + 0xDDC6: 0x6694, //CJK UNIFIED IDEOGRAPH + 0xDDC7: 0x6678, //CJK UNIFIED IDEOGRAPH + 0xDDC8: 0x6720, //CJK UNIFIED IDEOGRAPH + 0xDDC9: 0x6966, //CJK UNIFIED IDEOGRAPH + 0xDDCA: 0x695F, //CJK UNIFIED IDEOGRAPH + 0xDDCB: 0x6938, //CJK UNIFIED IDEOGRAPH + 0xDDCC: 0x694E, //CJK UNIFIED IDEOGRAPH + 0xDDCD: 0x6962, //CJK UNIFIED IDEOGRAPH + 0xDDCE: 0x6971, //CJK UNIFIED IDEOGRAPH + 0xDDCF: 0x693F, //CJK UNIFIED IDEOGRAPH + 0xDDD0: 0x6945, //CJK UNIFIED IDEOGRAPH + 0xDDD1: 0x696A, //CJK UNIFIED IDEOGRAPH + 0xDDD2: 0x6939, //CJK UNIFIED IDEOGRAPH + 0xDDD3: 0x6942, //CJK UNIFIED IDEOGRAPH + 0xDDD4: 0x6957, //CJK UNIFIED IDEOGRAPH + 0xDDD5: 0x6959, //CJK UNIFIED IDEOGRAPH + 0xDDD6: 0x697A, //CJK UNIFIED IDEOGRAPH + 0xDDD7: 0x6948, //CJK UNIFIED IDEOGRAPH + 0xDDD8: 0x6949, //CJK UNIFIED IDEOGRAPH + 0xDDD9: 0x6935, //CJK UNIFIED IDEOGRAPH + 0xDDDA: 0x696C, //CJK UNIFIED IDEOGRAPH + 0xDDDB: 0x6933, //CJK UNIFIED IDEOGRAPH + 0xDDDC: 0x693D, //CJK UNIFIED IDEOGRAPH + 0xDDDD: 0x6965, //CJK UNIFIED IDEOGRAPH + 0xDDDE: 0x68F0, //CJK UNIFIED IDEOGRAPH + 0xDDDF: 0x6978, //CJK UNIFIED IDEOGRAPH + 0xDDE0: 0x6934, //CJK UNIFIED IDEOGRAPH + 0xDDE1: 0x6969, //CJK UNIFIED IDEOGRAPH + 0xDDE2: 0x6940, //CJK UNIFIED IDEOGRAPH + 0xDDE3: 0x696F, //CJK UNIFIED IDEOGRAPH + 0xDDE4: 0x6944, //CJK UNIFIED IDEOGRAPH + 0xDDE5: 0x6976, //CJK UNIFIED IDEOGRAPH + 0xDDE6: 0x6958, //CJK UNIFIED IDEOGRAPH + 0xDDE7: 0x6941, //CJK UNIFIED IDEOGRAPH + 0xDDE8: 0x6974, //CJK UNIFIED IDEOGRAPH + 0xDDE9: 0x694C, //CJK UNIFIED IDEOGRAPH + 0xDDEA: 0x693B, //CJK UNIFIED IDEOGRAPH + 0xDDEB: 0x694B, //CJK UNIFIED IDEOGRAPH + 0xDDEC: 0x6937, //CJK UNIFIED IDEOGRAPH + 0xDDED: 0x695C, //CJK UNIFIED IDEOGRAPH + 0xDDEE: 0x694F, //CJK UNIFIED IDEOGRAPH + 0xDDEF: 0x6951, //CJK UNIFIED IDEOGRAPH + 0xDDF0: 0x6932, //CJK UNIFIED IDEOGRAPH + 0xDDF1: 0x6952, //CJK UNIFIED IDEOGRAPH + 0xDDF2: 0x692F, //CJK UNIFIED IDEOGRAPH + 0xDDF3: 0x697B, //CJK UNIFIED IDEOGRAPH + 0xDDF4: 0x693C, //CJK UNIFIED IDEOGRAPH + 0xDDF5: 0x6B46, //CJK UNIFIED IDEOGRAPH + 0xDDF6: 0x6B45, //CJK UNIFIED IDEOGRAPH + 0xDDF7: 0x6B43, //CJK UNIFIED IDEOGRAPH + 0xDDF8: 0x6B42, //CJK UNIFIED IDEOGRAPH + 0xDDF9: 0x6B48, //CJK UNIFIED IDEOGRAPH + 0xDDFA: 0x6B41, //CJK UNIFIED IDEOGRAPH + 0xDDFB: 0x6B9B, //CJK UNIFIED IDEOGRAPH + 0xDDFC: 0xFA0D, //CJK COMPATIBILITY IDEOGRAPH + 0xDDFD: 0x6BFB, //CJK UNIFIED IDEOGRAPH + 0xDDFE: 0x6BFC, //CJK UNIFIED IDEOGRAPH + 0xDE40: 0x6BF9, //CJK UNIFIED IDEOGRAPH + 0xDE41: 0x6BF7, //CJK UNIFIED IDEOGRAPH + 0xDE42: 0x6BF8, //CJK UNIFIED IDEOGRAPH + 0xDE43: 0x6E9B, //CJK UNIFIED IDEOGRAPH + 0xDE44: 0x6ED6, //CJK UNIFIED IDEOGRAPH + 0xDE45: 0x6EC8, //CJK UNIFIED IDEOGRAPH + 0xDE46: 0x6E8F, //CJK UNIFIED IDEOGRAPH + 0xDE47: 0x6EC0, //CJK UNIFIED IDEOGRAPH + 0xDE48: 0x6E9F, //CJK UNIFIED IDEOGRAPH + 0xDE49: 0x6E93, //CJK UNIFIED IDEOGRAPH + 0xDE4A: 0x6E94, //CJK UNIFIED IDEOGRAPH + 0xDE4B: 0x6EA0, //CJK UNIFIED IDEOGRAPH + 0xDE4C: 0x6EB1, //CJK UNIFIED IDEOGRAPH + 0xDE4D: 0x6EB9, //CJK UNIFIED IDEOGRAPH + 0xDE4E: 0x6EC6, //CJK UNIFIED IDEOGRAPH + 0xDE4F: 0x6ED2, //CJK UNIFIED IDEOGRAPH + 0xDE50: 0x6EBD, //CJK UNIFIED IDEOGRAPH + 0xDE51: 0x6EC1, //CJK UNIFIED IDEOGRAPH + 0xDE52: 0x6E9E, //CJK UNIFIED IDEOGRAPH + 0xDE53: 0x6EC9, //CJK UNIFIED IDEOGRAPH + 0xDE54: 0x6EB7, //CJK UNIFIED IDEOGRAPH + 0xDE55: 0x6EB0, //CJK UNIFIED IDEOGRAPH + 0xDE56: 0x6ECD, //CJK UNIFIED IDEOGRAPH + 0xDE57: 0x6EA6, //CJK UNIFIED IDEOGRAPH + 0xDE58: 0x6ECF, //CJK UNIFIED IDEOGRAPH + 0xDE59: 0x6EB2, //CJK UNIFIED IDEOGRAPH + 0xDE5A: 0x6EBE, //CJK UNIFIED IDEOGRAPH + 0xDE5B: 0x6EC3, //CJK UNIFIED IDEOGRAPH + 0xDE5C: 0x6EDC, //CJK UNIFIED IDEOGRAPH + 0xDE5D: 0x6ED8, //CJK UNIFIED IDEOGRAPH + 0xDE5E: 0x6E99, //CJK UNIFIED IDEOGRAPH + 0xDE5F: 0x6E92, //CJK UNIFIED IDEOGRAPH + 0xDE60: 0x6E8E, //CJK UNIFIED IDEOGRAPH + 0xDE61: 0x6E8D, //CJK UNIFIED IDEOGRAPH + 0xDE62: 0x6EA4, //CJK UNIFIED IDEOGRAPH + 0xDE63: 0x6EA1, //CJK UNIFIED IDEOGRAPH + 0xDE64: 0x6EBF, //CJK UNIFIED IDEOGRAPH + 0xDE65: 0x6EB3, //CJK UNIFIED IDEOGRAPH + 0xDE66: 0x6ED0, //CJK UNIFIED IDEOGRAPH + 0xDE67: 0x6ECA, //CJK UNIFIED IDEOGRAPH + 0xDE68: 0x6E97, //CJK UNIFIED IDEOGRAPH + 0xDE69: 0x6EAE, //CJK UNIFIED IDEOGRAPH + 0xDE6A: 0x6EA3, //CJK UNIFIED IDEOGRAPH + 0xDE6B: 0x7147, //CJK UNIFIED IDEOGRAPH + 0xDE6C: 0x7154, //CJK UNIFIED IDEOGRAPH + 0xDE6D: 0x7152, //CJK UNIFIED IDEOGRAPH + 0xDE6E: 0x7163, //CJK UNIFIED IDEOGRAPH + 0xDE6F: 0x7160, //CJK UNIFIED IDEOGRAPH + 0xDE70: 0x7141, //CJK UNIFIED IDEOGRAPH + 0xDE71: 0x715D, //CJK UNIFIED IDEOGRAPH + 0xDE72: 0x7162, //CJK UNIFIED IDEOGRAPH + 0xDE73: 0x7172, //CJK UNIFIED IDEOGRAPH + 0xDE74: 0x7178, //CJK UNIFIED IDEOGRAPH + 0xDE75: 0x716A, //CJK UNIFIED IDEOGRAPH + 0xDE76: 0x7161, //CJK UNIFIED IDEOGRAPH + 0xDE77: 0x7142, //CJK UNIFIED IDEOGRAPH + 0xDE78: 0x7158, //CJK UNIFIED IDEOGRAPH + 0xDE79: 0x7143, //CJK UNIFIED IDEOGRAPH + 0xDE7A: 0x714B, //CJK UNIFIED IDEOGRAPH + 0xDE7B: 0x7170, //CJK UNIFIED IDEOGRAPH + 0xDE7C: 0x715F, //CJK UNIFIED IDEOGRAPH + 0xDE7D: 0x7150, //CJK UNIFIED IDEOGRAPH + 0xDE7E: 0x7153, //CJK UNIFIED IDEOGRAPH + 0xDEA1: 0x7144, //CJK UNIFIED IDEOGRAPH + 0xDEA2: 0x714D, //CJK UNIFIED IDEOGRAPH + 0xDEA3: 0x715A, //CJK UNIFIED IDEOGRAPH + 0xDEA4: 0x724F, //CJK UNIFIED IDEOGRAPH + 0xDEA5: 0x728D, //CJK UNIFIED IDEOGRAPH + 0xDEA6: 0x728C, //CJK UNIFIED IDEOGRAPH + 0xDEA7: 0x7291, //CJK UNIFIED IDEOGRAPH + 0xDEA8: 0x7290, //CJK UNIFIED IDEOGRAPH + 0xDEA9: 0x728E, //CJK UNIFIED IDEOGRAPH + 0xDEAA: 0x733C, //CJK UNIFIED IDEOGRAPH + 0xDEAB: 0x7342, //CJK UNIFIED IDEOGRAPH + 0xDEAC: 0x733B, //CJK UNIFIED IDEOGRAPH + 0xDEAD: 0x733A, //CJK UNIFIED IDEOGRAPH + 0xDEAE: 0x7340, //CJK UNIFIED IDEOGRAPH + 0xDEAF: 0x734A, //CJK UNIFIED IDEOGRAPH + 0xDEB0: 0x7349, //CJK UNIFIED IDEOGRAPH + 0xDEB1: 0x7444, //CJK UNIFIED IDEOGRAPH + 0xDEB2: 0x744A, //CJK UNIFIED IDEOGRAPH + 0xDEB3: 0x744B, //CJK UNIFIED IDEOGRAPH + 0xDEB4: 0x7452, //CJK UNIFIED IDEOGRAPH + 0xDEB5: 0x7451, //CJK UNIFIED IDEOGRAPH + 0xDEB6: 0x7457, //CJK UNIFIED IDEOGRAPH + 0xDEB7: 0x7440, //CJK UNIFIED IDEOGRAPH + 0xDEB8: 0x744F, //CJK UNIFIED IDEOGRAPH + 0xDEB9: 0x7450, //CJK UNIFIED IDEOGRAPH + 0xDEBA: 0x744E, //CJK UNIFIED IDEOGRAPH + 0xDEBB: 0x7442, //CJK UNIFIED IDEOGRAPH + 0xDEBC: 0x7446, //CJK UNIFIED IDEOGRAPH + 0xDEBD: 0x744D, //CJK UNIFIED IDEOGRAPH + 0xDEBE: 0x7454, //CJK UNIFIED IDEOGRAPH + 0xDEBF: 0x74E1, //CJK UNIFIED IDEOGRAPH + 0xDEC0: 0x74FF, //CJK UNIFIED IDEOGRAPH + 0xDEC1: 0x74FE, //CJK UNIFIED IDEOGRAPH + 0xDEC2: 0x74FD, //CJK UNIFIED IDEOGRAPH + 0xDEC3: 0x751D, //CJK UNIFIED IDEOGRAPH + 0xDEC4: 0x7579, //CJK UNIFIED IDEOGRAPH + 0xDEC5: 0x7577, //CJK UNIFIED IDEOGRAPH + 0xDEC6: 0x6983, //CJK UNIFIED IDEOGRAPH + 0xDEC7: 0x75EF, //CJK UNIFIED IDEOGRAPH + 0xDEC8: 0x760F, //CJK UNIFIED IDEOGRAPH + 0xDEC9: 0x7603, //CJK UNIFIED IDEOGRAPH + 0xDECA: 0x75F7, //CJK UNIFIED IDEOGRAPH + 0xDECB: 0x75FE, //CJK UNIFIED IDEOGRAPH + 0xDECC: 0x75FC, //CJK UNIFIED IDEOGRAPH + 0xDECD: 0x75F9, //CJK UNIFIED IDEOGRAPH + 0xDECE: 0x75F8, //CJK UNIFIED IDEOGRAPH + 0xDECF: 0x7610, //CJK UNIFIED IDEOGRAPH + 0xDED0: 0x75FB, //CJK UNIFIED IDEOGRAPH + 0xDED1: 0x75F6, //CJK UNIFIED IDEOGRAPH + 0xDED2: 0x75ED, //CJK UNIFIED IDEOGRAPH + 0xDED3: 0x75F5, //CJK UNIFIED IDEOGRAPH + 0xDED4: 0x75FD, //CJK UNIFIED IDEOGRAPH + 0xDED5: 0x7699, //CJK UNIFIED IDEOGRAPH + 0xDED6: 0x76B5, //CJK UNIFIED IDEOGRAPH + 0xDED7: 0x76DD, //CJK UNIFIED IDEOGRAPH + 0xDED8: 0x7755, //CJK UNIFIED IDEOGRAPH + 0xDED9: 0x775F, //CJK UNIFIED IDEOGRAPH + 0xDEDA: 0x7760, //CJK UNIFIED IDEOGRAPH + 0xDEDB: 0x7752, //CJK UNIFIED IDEOGRAPH + 0xDEDC: 0x7756, //CJK UNIFIED IDEOGRAPH + 0xDEDD: 0x775A, //CJK UNIFIED IDEOGRAPH + 0xDEDE: 0x7769, //CJK UNIFIED IDEOGRAPH + 0xDEDF: 0x7767, //CJK UNIFIED IDEOGRAPH + 0xDEE0: 0x7754, //CJK UNIFIED IDEOGRAPH + 0xDEE1: 0x7759, //CJK UNIFIED IDEOGRAPH + 0xDEE2: 0x776D, //CJK UNIFIED IDEOGRAPH + 0xDEE3: 0x77E0, //CJK UNIFIED IDEOGRAPH + 0xDEE4: 0x7887, //CJK UNIFIED IDEOGRAPH + 0xDEE5: 0x789A, //CJK UNIFIED IDEOGRAPH + 0xDEE6: 0x7894, //CJK UNIFIED IDEOGRAPH + 0xDEE7: 0x788F, //CJK UNIFIED IDEOGRAPH + 0xDEE8: 0x7884, //CJK UNIFIED IDEOGRAPH + 0xDEE9: 0x7895, //CJK UNIFIED IDEOGRAPH + 0xDEEA: 0x7885, //CJK UNIFIED IDEOGRAPH + 0xDEEB: 0x7886, //CJK UNIFIED IDEOGRAPH + 0xDEEC: 0x78A1, //CJK UNIFIED IDEOGRAPH + 0xDEED: 0x7883, //CJK UNIFIED IDEOGRAPH + 0xDEEE: 0x7879, //CJK UNIFIED IDEOGRAPH + 0xDEEF: 0x7899, //CJK UNIFIED IDEOGRAPH + 0xDEF0: 0x7880, //CJK UNIFIED IDEOGRAPH + 0xDEF1: 0x7896, //CJK UNIFIED IDEOGRAPH + 0xDEF2: 0x787B, //CJK UNIFIED IDEOGRAPH + 0xDEF3: 0x797C, //CJK UNIFIED IDEOGRAPH + 0xDEF4: 0x7982, //CJK UNIFIED IDEOGRAPH + 0xDEF5: 0x797D, //CJK UNIFIED IDEOGRAPH + 0xDEF6: 0x7979, //CJK UNIFIED IDEOGRAPH + 0xDEF7: 0x7A11, //CJK UNIFIED IDEOGRAPH + 0xDEF8: 0x7A18, //CJK UNIFIED IDEOGRAPH + 0xDEF9: 0x7A19, //CJK UNIFIED IDEOGRAPH + 0xDEFA: 0x7A12, //CJK UNIFIED IDEOGRAPH + 0xDEFB: 0x7A17, //CJK UNIFIED IDEOGRAPH + 0xDEFC: 0x7A15, //CJK UNIFIED IDEOGRAPH + 0xDEFD: 0x7A22, //CJK UNIFIED IDEOGRAPH + 0xDEFE: 0x7A13, //CJK UNIFIED IDEOGRAPH + 0xDF40: 0x7A1B, //CJK UNIFIED IDEOGRAPH + 0xDF41: 0x7A10, //CJK UNIFIED IDEOGRAPH + 0xDF42: 0x7AA3, //CJK UNIFIED IDEOGRAPH + 0xDF43: 0x7AA2, //CJK UNIFIED IDEOGRAPH + 0xDF44: 0x7A9E, //CJK UNIFIED IDEOGRAPH + 0xDF45: 0x7AEB, //CJK UNIFIED IDEOGRAPH + 0xDF46: 0x7B66, //CJK UNIFIED IDEOGRAPH + 0xDF47: 0x7B64, //CJK UNIFIED IDEOGRAPH + 0xDF48: 0x7B6D, //CJK UNIFIED IDEOGRAPH + 0xDF49: 0x7B74, //CJK UNIFIED IDEOGRAPH + 0xDF4A: 0x7B69, //CJK UNIFIED IDEOGRAPH + 0xDF4B: 0x7B72, //CJK UNIFIED IDEOGRAPH + 0xDF4C: 0x7B65, //CJK UNIFIED IDEOGRAPH + 0xDF4D: 0x7B73, //CJK UNIFIED IDEOGRAPH + 0xDF4E: 0x7B71, //CJK UNIFIED IDEOGRAPH + 0xDF4F: 0x7B70, //CJK UNIFIED IDEOGRAPH + 0xDF50: 0x7B61, //CJK UNIFIED IDEOGRAPH + 0xDF51: 0x7B78, //CJK UNIFIED IDEOGRAPH + 0xDF52: 0x7B76, //CJK UNIFIED IDEOGRAPH + 0xDF53: 0x7B63, //CJK UNIFIED IDEOGRAPH + 0xDF54: 0x7CB2, //CJK UNIFIED IDEOGRAPH + 0xDF55: 0x7CB4, //CJK UNIFIED IDEOGRAPH + 0xDF56: 0x7CAF, //CJK UNIFIED IDEOGRAPH + 0xDF57: 0x7D88, //CJK UNIFIED IDEOGRAPH + 0xDF58: 0x7D86, //CJK UNIFIED IDEOGRAPH + 0xDF59: 0x7D80, //CJK UNIFIED IDEOGRAPH + 0xDF5A: 0x7D8D, //CJK UNIFIED IDEOGRAPH + 0xDF5B: 0x7D7F, //CJK UNIFIED IDEOGRAPH + 0xDF5C: 0x7D85, //CJK UNIFIED IDEOGRAPH + 0xDF5D: 0x7D7A, //CJK UNIFIED IDEOGRAPH + 0xDF5E: 0x7D8E, //CJK UNIFIED IDEOGRAPH + 0xDF5F: 0x7D7B, //CJK UNIFIED IDEOGRAPH + 0xDF60: 0x7D83, //CJK UNIFIED IDEOGRAPH + 0xDF61: 0x7D7C, //CJK UNIFIED IDEOGRAPH + 0xDF62: 0x7D8C, //CJK UNIFIED IDEOGRAPH + 0xDF63: 0x7D94, //CJK UNIFIED IDEOGRAPH + 0xDF64: 0x7D84, //CJK UNIFIED IDEOGRAPH + 0xDF65: 0x7D7D, //CJK UNIFIED IDEOGRAPH + 0xDF66: 0x7D92, //CJK UNIFIED IDEOGRAPH + 0xDF67: 0x7F6D, //CJK UNIFIED IDEOGRAPH + 0xDF68: 0x7F6B, //CJK UNIFIED IDEOGRAPH + 0xDF69: 0x7F67, //CJK UNIFIED IDEOGRAPH + 0xDF6A: 0x7F68, //CJK UNIFIED IDEOGRAPH + 0xDF6B: 0x7F6C, //CJK UNIFIED IDEOGRAPH + 0xDF6C: 0x7FA6, //CJK UNIFIED IDEOGRAPH + 0xDF6D: 0x7FA5, //CJK UNIFIED IDEOGRAPH + 0xDF6E: 0x7FA7, //CJK UNIFIED IDEOGRAPH + 0xDF6F: 0x7FDB, //CJK UNIFIED IDEOGRAPH + 0xDF70: 0x7FDC, //CJK UNIFIED IDEOGRAPH + 0xDF71: 0x8021, //CJK UNIFIED IDEOGRAPH + 0xDF72: 0x8164, //CJK UNIFIED IDEOGRAPH + 0xDF73: 0x8160, //CJK UNIFIED IDEOGRAPH + 0xDF74: 0x8177, //CJK UNIFIED IDEOGRAPH + 0xDF75: 0x815C, //CJK UNIFIED IDEOGRAPH + 0xDF76: 0x8169, //CJK UNIFIED IDEOGRAPH + 0xDF77: 0x815B, //CJK UNIFIED IDEOGRAPH + 0xDF78: 0x8162, //CJK UNIFIED IDEOGRAPH + 0xDF79: 0x8172, //CJK UNIFIED IDEOGRAPH + 0xDF7A: 0x6721, //CJK UNIFIED IDEOGRAPH + 0xDF7B: 0x815E, //CJK UNIFIED IDEOGRAPH + 0xDF7C: 0x8176, //CJK UNIFIED IDEOGRAPH + 0xDF7D: 0x8167, //CJK UNIFIED IDEOGRAPH + 0xDF7E: 0x816F, //CJK UNIFIED IDEOGRAPH + 0xDFA1: 0x8144, //CJK UNIFIED IDEOGRAPH + 0xDFA2: 0x8161, //CJK UNIFIED IDEOGRAPH + 0xDFA3: 0x821D, //CJK UNIFIED IDEOGRAPH + 0xDFA4: 0x8249, //CJK UNIFIED IDEOGRAPH + 0xDFA5: 0x8244, //CJK UNIFIED IDEOGRAPH + 0xDFA6: 0x8240, //CJK UNIFIED IDEOGRAPH + 0xDFA7: 0x8242, //CJK UNIFIED IDEOGRAPH + 0xDFA8: 0x8245, //CJK UNIFIED IDEOGRAPH + 0xDFA9: 0x84F1, //CJK UNIFIED IDEOGRAPH + 0xDFAA: 0x843F, //CJK UNIFIED IDEOGRAPH + 0xDFAB: 0x8456, //CJK UNIFIED IDEOGRAPH + 0xDFAC: 0x8476, //CJK UNIFIED IDEOGRAPH + 0xDFAD: 0x8479, //CJK UNIFIED IDEOGRAPH + 0xDFAE: 0x848F, //CJK UNIFIED IDEOGRAPH + 0xDFAF: 0x848D, //CJK UNIFIED IDEOGRAPH + 0xDFB0: 0x8465, //CJK UNIFIED IDEOGRAPH + 0xDFB1: 0x8451, //CJK UNIFIED IDEOGRAPH + 0xDFB2: 0x8440, //CJK UNIFIED IDEOGRAPH + 0xDFB3: 0x8486, //CJK UNIFIED IDEOGRAPH + 0xDFB4: 0x8467, //CJK UNIFIED IDEOGRAPH + 0xDFB5: 0x8430, //CJK UNIFIED IDEOGRAPH + 0xDFB6: 0x844D, //CJK UNIFIED IDEOGRAPH + 0xDFB7: 0x847D, //CJK UNIFIED IDEOGRAPH + 0xDFB8: 0x845A, //CJK UNIFIED IDEOGRAPH + 0xDFB9: 0x8459, //CJK UNIFIED IDEOGRAPH + 0xDFBA: 0x8474, //CJK UNIFIED IDEOGRAPH + 0xDFBB: 0x8473, //CJK UNIFIED IDEOGRAPH + 0xDFBC: 0x845D, //CJK UNIFIED IDEOGRAPH + 0xDFBD: 0x8507, //CJK UNIFIED IDEOGRAPH + 0xDFBE: 0x845E, //CJK UNIFIED IDEOGRAPH + 0xDFBF: 0x8437, //CJK UNIFIED IDEOGRAPH + 0xDFC0: 0x843A, //CJK UNIFIED IDEOGRAPH + 0xDFC1: 0x8434, //CJK UNIFIED IDEOGRAPH + 0xDFC2: 0x847A, //CJK UNIFIED IDEOGRAPH + 0xDFC3: 0x8443, //CJK UNIFIED IDEOGRAPH + 0xDFC4: 0x8478, //CJK UNIFIED IDEOGRAPH + 0xDFC5: 0x8432, //CJK UNIFIED IDEOGRAPH + 0xDFC6: 0x8445, //CJK UNIFIED IDEOGRAPH + 0xDFC7: 0x8429, //CJK UNIFIED IDEOGRAPH + 0xDFC8: 0x83D9, //CJK UNIFIED IDEOGRAPH + 0xDFC9: 0x844B, //CJK UNIFIED IDEOGRAPH + 0xDFCA: 0x842F, //CJK UNIFIED IDEOGRAPH + 0xDFCB: 0x8442, //CJK UNIFIED IDEOGRAPH + 0xDFCC: 0x842D, //CJK UNIFIED IDEOGRAPH + 0xDFCD: 0x845F, //CJK UNIFIED IDEOGRAPH + 0xDFCE: 0x8470, //CJK UNIFIED IDEOGRAPH + 0xDFCF: 0x8439, //CJK UNIFIED IDEOGRAPH + 0xDFD0: 0x844E, //CJK UNIFIED IDEOGRAPH + 0xDFD1: 0x844C, //CJK UNIFIED IDEOGRAPH + 0xDFD2: 0x8452, //CJK UNIFIED IDEOGRAPH + 0xDFD3: 0x846F, //CJK UNIFIED IDEOGRAPH + 0xDFD4: 0x84C5, //CJK UNIFIED IDEOGRAPH + 0xDFD5: 0x848E, //CJK UNIFIED IDEOGRAPH + 0xDFD6: 0x843B, //CJK UNIFIED IDEOGRAPH + 0xDFD7: 0x8447, //CJK UNIFIED IDEOGRAPH + 0xDFD8: 0x8436, //CJK UNIFIED IDEOGRAPH + 0xDFD9: 0x8433, //CJK UNIFIED IDEOGRAPH + 0xDFDA: 0x8468, //CJK UNIFIED IDEOGRAPH + 0xDFDB: 0x847E, //CJK UNIFIED IDEOGRAPH + 0xDFDC: 0x8444, //CJK UNIFIED IDEOGRAPH + 0xDFDD: 0x842B, //CJK UNIFIED IDEOGRAPH + 0xDFDE: 0x8460, //CJK UNIFIED IDEOGRAPH + 0xDFDF: 0x8454, //CJK UNIFIED IDEOGRAPH + 0xDFE0: 0x846E, //CJK UNIFIED IDEOGRAPH + 0xDFE1: 0x8450, //CJK UNIFIED IDEOGRAPH + 0xDFE2: 0x870B, //CJK UNIFIED IDEOGRAPH + 0xDFE3: 0x8704, //CJK UNIFIED IDEOGRAPH + 0xDFE4: 0x86F7, //CJK UNIFIED IDEOGRAPH + 0xDFE5: 0x870C, //CJK UNIFIED IDEOGRAPH + 0xDFE6: 0x86FA, //CJK UNIFIED IDEOGRAPH + 0xDFE7: 0x86D6, //CJK UNIFIED IDEOGRAPH + 0xDFE8: 0x86F5, //CJK UNIFIED IDEOGRAPH + 0xDFE9: 0x874D, //CJK UNIFIED IDEOGRAPH + 0xDFEA: 0x86F8, //CJK UNIFIED IDEOGRAPH + 0xDFEB: 0x870E, //CJK UNIFIED IDEOGRAPH + 0xDFEC: 0x8709, //CJK UNIFIED IDEOGRAPH + 0xDFED: 0x8701, //CJK UNIFIED IDEOGRAPH + 0xDFEE: 0x86F6, //CJK UNIFIED IDEOGRAPH + 0xDFEF: 0x870D, //CJK UNIFIED IDEOGRAPH + 0xDFF0: 0x8705, //CJK UNIFIED IDEOGRAPH + 0xDFF1: 0x88D6, //CJK UNIFIED IDEOGRAPH + 0xDFF2: 0x88CB, //CJK UNIFIED IDEOGRAPH + 0xDFF3: 0x88CD, //CJK UNIFIED IDEOGRAPH + 0xDFF4: 0x88CE, //CJK UNIFIED IDEOGRAPH + 0xDFF5: 0x88DE, //CJK UNIFIED IDEOGRAPH + 0xDFF6: 0x88DB, //CJK UNIFIED IDEOGRAPH + 0xDFF7: 0x88DA, //CJK UNIFIED IDEOGRAPH + 0xDFF8: 0x88CC, //CJK UNIFIED IDEOGRAPH + 0xDFF9: 0x88D0, //CJK UNIFIED IDEOGRAPH + 0xDFFA: 0x8985, //CJK UNIFIED IDEOGRAPH + 0xDFFB: 0x899B, //CJK UNIFIED IDEOGRAPH + 0xDFFC: 0x89DF, //CJK UNIFIED IDEOGRAPH + 0xDFFD: 0x89E5, //CJK UNIFIED IDEOGRAPH + 0xDFFE: 0x89E4, //CJK UNIFIED IDEOGRAPH + 0xE040: 0x89E1, //CJK UNIFIED IDEOGRAPH + 0xE041: 0x89E0, //CJK UNIFIED IDEOGRAPH + 0xE042: 0x89E2, //CJK UNIFIED IDEOGRAPH + 0xE043: 0x89DC, //CJK UNIFIED IDEOGRAPH + 0xE044: 0x89E6, //CJK UNIFIED IDEOGRAPH + 0xE045: 0x8A76, //CJK UNIFIED IDEOGRAPH + 0xE046: 0x8A86, //CJK UNIFIED IDEOGRAPH + 0xE047: 0x8A7F, //CJK UNIFIED IDEOGRAPH + 0xE048: 0x8A61, //CJK UNIFIED IDEOGRAPH + 0xE049: 0x8A3F, //CJK UNIFIED IDEOGRAPH + 0xE04A: 0x8A77, //CJK UNIFIED IDEOGRAPH + 0xE04B: 0x8A82, //CJK UNIFIED IDEOGRAPH + 0xE04C: 0x8A84, //CJK UNIFIED IDEOGRAPH + 0xE04D: 0x8A75, //CJK UNIFIED IDEOGRAPH + 0xE04E: 0x8A83, //CJK UNIFIED IDEOGRAPH + 0xE04F: 0x8A81, //CJK UNIFIED IDEOGRAPH + 0xE050: 0x8A74, //CJK UNIFIED IDEOGRAPH + 0xE051: 0x8A7A, //CJK UNIFIED IDEOGRAPH + 0xE052: 0x8C3C, //CJK UNIFIED IDEOGRAPH + 0xE053: 0x8C4B, //CJK UNIFIED IDEOGRAPH + 0xE054: 0x8C4A, //CJK UNIFIED IDEOGRAPH + 0xE055: 0x8C65, //CJK UNIFIED IDEOGRAPH + 0xE056: 0x8C64, //CJK UNIFIED IDEOGRAPH + 0xE057: 0x8C66, //CJK UNIFIED IDEOGRAPH + 0xE058: 0x8C86, //CJK UNIFIED IDEOGRAPH + 0xE059: 0x8C84, //CJK UNIFIED IDEOGRAPH + 0xE05A: 0x8C85, //CJK UNIFIED IDEOGRAPH + 0xE05B: 0x8CCC, //CJK UNIFIED IDEOGRAPH + 0xE05C: 0x8D68, //CJK UNIFIED IDEOGRAPH + 0xE05D: 0x8D69, //CJK UNIFIED IDEOGRAPH + 0xE05E: 0x8D91, //CJK UNIFIED IDEOGRAPH + 0xE05F: 0x8D8C, //CJK UNIFIED IDEOGRAPH + 0xE060: 0x8D8E, //CJK UNIFIED IDEOGRAPH + 0xE061: 0x8D8F, //CJK UNIFIED IDEOGRAPH + 0xE062: 0x8D8D, //CJK UNIFIED IDEOGRAPH + 0xE063: 0x8D93, //CJK UNIFIED IDEOGRAPH + 0xE064: 0x8D94, //CJK UNIFIED IDEOGRAPH + 0xE065: 0x8D90, //CJK UNIFIED IDEOGRAPH + 0xE066: 0x8D92, //CJK UNIFIED IDEOGRAPH + 0xE067: 0x8DF0, //CJK UNIFIED IDEOGRAPH + 0xE068: 0x8DE0, //CJK UNIFIED IDEOGRAPH + 0xE069: 0x8DEC, //CJK UNIFIED IDEOGRAPH + 0xE06A: 0x8DF1, //CJK UNIFIED IDEOGRAPH + 0xE06B: 0x8DEE, //CJK UNIFIED IDEOGRAPH + 0xE06C: 0x8DD0, //CJK UNIFIED IDEOGRAPH + 0xE06D: 0x8DE9, //CJK UNIFIED IDEOGRAPH + 0xE06E: 0x8DE3, //CJK UNIFIED IDEOGRAPH + 0xE06F: 0x8DE2, //CJK UNIFIED IDEOGRAPH + 0xE070: 0x8DE7, //CJK UNIFIED IDEOGRAPH + 0xE071: 0x8DF2, //CJK UNIFIED IDEOGRAPH + 0xE072: 0x8DEB, //CJK UNIFIED IDEOGRAPH + 0xE073: 0x8DF4, //CJK UNIFIED IDEOGRAPH + 0xE074: 0x8F06, //CJK UNIFIED IDEOGRAPH + 0xE075: 0x8EFF, //CJK UNIFIED IDEOGRAPH + 0xE076: 0x8F01, //CJK UNIFIED IDEOGRAPH + 0xE077: 0x8F00, //CJK UNIFIED IDEOGRAPH + 0xE078: 0x8F05, //CJK UNIFIED IDEOGRAPH + 0xE079: 0x8F07, //CJK UNIFIED IDEOGRAPH + 0xE07A: 0x8F08, //CJK UNIFIED IDEOGRAPH + 0xE07B: 0x8F02, //CJK UNIFIED IDEOGRAPH + 0xE07C: 0x8F0B, //CJK UNIFIED IDEOGRAPH + 0xE07D: 0x9052, //CJK UNIFIED IDEOGRAPH + 0xE07E: 0x903F, //CJK UNIFIED IDEOGRAPH + 0xE0A1: 0x9044, //CJK UNIFIED IDEOGRAPH + 0xE0A2: 0x9049, //CJK UNIFIED IDEOGRAPH + 0xE0A3: 0x903D, //CJK UNIFIED IDEOGRAPH + 0xE0A4: 0x9110, //CJK UNIFIED IDEOGRAPH + 0xE0A5: 0x910D, //CJK UNIFIED IDEOGRAPH + 0xE0A6: 0x910F, //CJK UNIFIED IDEOGRAPH + 0xE0A7: 0x9111, //CJK UNIFIED IDEOGRAPH + 0xE0A8: 0x9116, //CJK UNIFIED IDEOGRAPH + 0xE0A9: 0x9114, //CJK UNIFIED IDEOGRAPH + 0xE0AA: 0x910B, //CJK UNIFIED IDEOGRAPH + 0xE0AB: 0x910E, //CJK UNIFIED IDEOGRAPH + 0xE0AC: 0x916E, //CJK UNIFIED IDEOGRAPH + 0xE0AD: 0x916F, //CJK UNIFIED IDEOGRAPH + 0xE0AE: 0x9248, //CJK UNIFIED IDEOGRAPH + 0xE0AF: 0x9252, //CJK UNIFIED IDEOGRAPH + 0xE0B0: 0x9230, //CJK UNIFIED IDEOGRAPH + 0xE0B1: 0x923A, //CJK UNIFIED IDEOGRAPH + 0xE0B2: 0x9266, //CJK UNIFIED IDEOGRAPH + 0xE0B3: 0x9233, //CJK UNIFIED IDEOGRAPH + 0xE0B4: 0x9265, //CJK UNIFIED IDEOGRAPH + 0xE0B5: 0x925E, //CJK UNIFIED IDEOGRAPH + 0xE0B6: 0x9283, //CJK UNIFIED IDEOGRAPH + 0xE0B7: 0x922E, //CJK UNIFIED IDEOGRAPH + 0xE0B8: 0x924A, //CJK UNIFIED IDEOGRAPH + 0xE0B9: 0x9246, //CJK UNIFIED IDEOGRAPH + 0xE0BA: 0x926D, //CJK UNIFIED IDEOGRAPH + 0xE0BB: 0x926C, //CJK UNIFIED IDEOGRAPH + 0xE0BC: 0x924F, //CJK UNIFIED IDEOGRAPH + 0xE0BD: 0x9260, //CJK UNIFIED IDEOGRAPH + 0xE0BE: 0x9267, //CJK UNIFIED IDEOGRAPH + 0xE0BF: 0x926F, //CJK UNIFIED IDEOGRAPH + 0xE0C0: 0x9236, //CJK UNIFIED IDEOGRAPH + 0xE0C1: 0x9261, //CJK UNIFIED IDEOGRAPH + 0xE0C2: 0x9270, //CJK UNIFIED IDEOGRAPH + 0xE0C3: 0x9231, //CJK UNIFIED IDEOGRAPH + 0xE0C4: 0x9254, //CJK UNIFIED IDEOGRAPH + 0xE0C5: 0x9263, //CJK UNIFIED IDEOGRAPH + 0xE0C6: 0x9250, //CJK UNIFIED IDEOGRAPH + 0xE0C7: 0x9272, //CJK UNIFIED IDEOGRAPH + 0xE0C8: 0x924E, //CJK UNIFIED IDEOGRAPH + 0xE0C9: 0x9253, //CJK UNIFIED IDEOGRAPH + 0xE0CA: 0x924C, //CJK UNIFIED IDEOGRAPH + 0xE0CB: 0x9256, //CJK UNIFIED IDEOGRAPH + 0xE0CC: 0x9232, //CJK UNIFIED IDEOGRAPH + 0xE0CD: 0x959F, //CJK UNIFIED IDEOGRAPH + 0xE0CE: 0x959C, //CJK UNIFIED IDEOGRAPH + 0xE0CF: 0x959E, //CJK UNIFIED IDEOGRAPH + 0xE0D0: 0x959B, //CJK UNIFIED IDEOGRAPH + 0xE0D1: 0x9692, //CJK UNIFIED IDEOGRAPH + 0xE0D2: 0x9693, //CJK UNIFIED IDEOGRAPH + 0xE0D3: 0x9691, //CJK UNIFIED IDEOGRAPH + 0xE0D4: 0x9697, //CJK UNIFIED IDEOGRAPH + 0xE0D5: 0x96CE, //CJK UNIFIED IDEOGRAPH + 0xE0D6: 0x96FA, //CJK UNIFIED IDEOGRAPH + 0xE0D7: 0x96FD, //CJK UNIFIED IDEOGRAPH + 0xE0D8: 0x96F8, //CJK UNIFIED IDEOGRAPH + 0xE0D9: 0x96F5, //CJK UNIFIED IDEOGRAPH + 0xE0DA: 0x9773, //CJK UNIFIED IDEOGRAPH + 0xE0DB: 0x9777, //CJK UNIFIED IDEOGRAPH + 0xE0DC: 0x9778, //CJK UNIFIED IDEOGRAPH + 0xE0DD: 0x9772, //CJK UNIFIED IDEOGRAPH + 0xE0DE: 0x980F, //CJK UNIFIED IDEOGRAPH + 0xE0DF: 0x980D, //CJK UNIFIED IDEOGRAPH + 0xE0E0: 0x980E, //CJK UNIFIED IDEOGRAPH + 0xE0E1: 0x98AC, //CJK UNIFIED IDEOGRAPH + 0xE0E2: 0x98F6, //CJK UNIFIED IDEOGRAPH + 0xE0E3: 0x98F9, //CJK UNIFIED IDEOGRAPH + 0xE0E4: 0x99AF, //CJK UNIFIED IDEOGRAPH + 0xE0E5: 0x99B2, //CJK UNIFIED IDEOGRAPH + 0xE0E6: 0x99B0, //CJK UNIFIED IDEOGRAPH + 0xE0E7: 0x99B5, //CJK UNIFIED IDEOGRAPH + 0xE0E8: 0x9AAD, //CJK UNIFIED IDEOGRAPH + 0xE0E9: 0x9AAB, //CJK UNIFIED IDEOGRAPH + 0xE0EA: 0x9B5B, //CJK UNIFIED IDEOGRAPH + 0xE0EB: 0x9CEA, //CJK UNIFIED IDEOGRAPH + 0xE0EC: 0x9CED, //CJK UNIFIED IDEOGRAPH + 0xE0ED: 0x9CE7, //CJK UNIFIED IDEOGRAPH + 0xE0EE: 0x9E80, //CJK UNIFIED IDEOGRAPH + 0xE0EF: 0x9EFD, //CJK UNIFIED IDEOGRAPH + 0xE0F0: 0x50E6, //CJK UNIFIED IDEOGRAPH + 0xE0F1: 0x50D4, //CJK UNIFIED IDEOGRAPH + 0xE0F2: 0x50D7, //CJK UNIFIED IDEOGRAPH + 0xE0F3: 0x50E8, //CJK UNIFIED IDEOGRAPH + 0xE0F4: 0x50F3, //CJK UNIFIED IDEOGRAPH + 0xE0F5: 0x50DB, //CJK UNIFIED IDEOGRAPH + 0xE0F6: 0x50EA, //CJK UNIFIED IDEOGRAPH + 0xE0F7: 0x50DD, //CJK UNIFIED IDEOGRAPH + 0xE0F8: 0x50E4, //CJK UNIFIED IDEOGRAPH + 0xE0F9: 0x50D3, //CJK UNIFIED IDEOGRAPH + 0xE0FA: 0x50EC, //CJK UNIFIED IDEOGRAPH + 0xE0FB: 0x50F0, //CJK UNIFIED IDEOGRAPH + 0xE0FC: 0x50EF, //CJK UNIFIED IDEOGRAPH + 0xE0FD: 0x50E3, //CJK UNIFIED IDEOGRAPH + 0xE0FE: 0x50E0, //CJK UNIFIED IDEOGRAPH + 0xE140: 0x51D8, //CJK UNIFIED IDEOGRAPH + 0xE141: 0x5280, //CJK UNIFIED IDEOGRAPH + 0xE142: 0x5281, //CJK UNIFIED IDEOGRAPH + 0xE143: 0x52E9, //CJK UNIFIED IDEOGRAPH + 0xE144: 0x52EB, //CJK UNIFIED IDEOGRAPH + 0xE145: 0x5330, //CJK UNIFIED IDEOGRAPH + 0xE146: 0x53AC, //CJK UNIFIED IDEOGRAPH + 0xE147: 0x5627, //CJK UNIFIED IDEOGRAPH + 0xE148: 0x5615, //CJK UNIFIED IDEOGRAPH + 0xE149: 0x560C, //CJK UNIFIED IDEOGRAPH + 0xE14A: 0x5612, //CJK UNIFIED IDEOGRAPH + 0xE14B: 0x55FC, //CJK UNIFIED IDEOGRAPH + 0xE14C: 0x560F, //CJK UNIFIED IDEOGRAPH + 0xE14D: 0x561C, //CJK UNIFIED IDEOGRAPH + 0xE14E: 0x5601, //CJK UNIFIED IDEOGRAPH + 0xE14F: 0x5613, //CJK UNIFIED IDEOGRAPH + 0xE150: 0x5602, //CJK UNIFIED IDEOGRAPH + 0xE151: 0x55FA, //CJK UNIFIED IDEOGRAPH + 0xE152: 0x561D, //CJK UNIFIED IDEOGRAPH + 0xE153: 0x5604, //CJK UNIFIED IDEOGRAPH + 0xE154: 0x55FF, //CJK UNIFIED IDEOGRAPH + 0xE155: 0x55F9, //CJK UNIFIED IDEOGRAPH + 0xE156: 0x5889, //CJK UNIFIED IDEOGRAPH + 0xE157: 0x587C, //CJK UNIFIED IDEOGRAPH + 0xE158: 0x5890, //CJK UNIFIED IDEOGRAPH + 0xE159: 0x5898, //CJK UNIFIED IDEOGRAPH + 0xE15A: 0x5886, //CJK UNIFIED IDEOGRAPH + 0xE15B: 0x5881, //CJK UNIFIED IDEOGRAPH + 0xE15C: 0x587F, //CJK UNIFIED IDEOGRAPH + 0xE15D: 0x5874, //CJK UNIFIED IDEOGRAPH + 0xE15E: 0x588B, //CJK UNIFIED IDEOGRAPH + 0xE15F: 0x587A, //CJK UNIFIED IDEOGRAPH + 0xE160: 0x5887, //CJK UNIFIED IDEOGRAPH + 0xE161: 0x5891, //CJK UNIFIED IDEOGRAPH + 0xE162: 0x588E, //CJK UNIFIED IDEOGRAPH + 0xE163: 0x5876, //CJK UNIFIED IDEOGRAPH + 0xE164: 0x5882, //CJK UNIFIED IDEOGRAPH + 0xE165: 0x5888, //CJK UNIFIED IDEOGRAPH + 0xE166: 0x587B, //CJK UNIFIED IDEOGRAPH + 0xE167: 0x5894, //CJK UNIFIED IDEOGRAPH + 0xE168: 0x588F, //CJK UNIFIED IDEOGRAPH + 0xE169: 0x58FE, //CJK UNIFIED IDEOGRAPH + 0xE16A: 0x596B, //CJK UNIFIED IDEOGRAPH + 0xE16B: 0x5ADC, //CJK UNIFIED IDEOGRAPH + 0xE16C: 0x5AEE, //CJK UNIFIED IDEOGRAPH + 0xE16D: 0x5AE5, //CJK UNIFIED IDEOGRAPH + 0xE16E: 0x5AD5, //CJK UNIFIED IDEOGRAPH + 0xE16F: 0x5AEA, //CJK UNIFIED IDEOGRAPH + 0xE170: 0x5ADA, //CJK UNIFIED IDEOGRAPH + 0xE171: 0x5AED, //CJK UNIFIED IDEOGRAPH + 0xE172: 0x5AEB, //CJK UNIFIED IDEOGRAPH + 0xE173: 0x5AF3, //CJK UNIFIED IDEOGRAPH + 0xE174: 0x5AE2, //CJK UNIFIED IDEOGRAPH + 0xE175: 0x5AE0, //CJK UNIFIED IDEOGRAPH + 0xE176: 0x5ADB, //CJK UNIFIED IDEOGRAPH + 0xE177: 0x5AEC, //CJK UNIFIED IDEOGRAPH + 0xE178: 0x5ADE, //CJK UNIFIED IDEOGRAPH + 0xE179: 0x5ADD, //CJK UNIFIED IDEOGRAPH + 0xE17A: 0x5AD9, //CJK UNIFIED IDEOGRAPH + 0xE17B: 0x5AE8, //CJK UNIFIED IDEOGRAPH + 0xE17C: 0x5ADF, //CJK UNIFIED IDEOGRAPH + 0xE17D: 0x5B77, //CJK UNIFIED IDEOGRAPH + 0xE17E: 0x5BE0, //CJK UNIFIED IDEOGRAPH + 0xE1A1: 0x5BE3, //CJK UNIFIED IDEOGRAPH + 0xE1A2: 0x5C63, //CJK UNIFIED IDEOGRAPH + 0xE1A3: 0x5D82, //CJK UNIFIED IDEOGRAPH + 0xE1A4: 0x5D80, //CJK UNIFIED IDEOGRAPH + 0xE1A5: 0x5D7D, //CJK UNIFIED IDEOGRAPH + 0xE1A6: 0x5D86, //CJK UNIFIED IDEOGRAPH + 0xE1A7: 0x5D7A, //CJK UNIFIED IDEOGRAPH + 0xE1A8: 0x5D81, //CJK UNIFIED IDEOGRAPH + 0xE1A9: 0x5D77, //CJK UNIFIED IDEOGRAPH + 0xE1AA: 0x5D8A, //CJK UNIFIED IDEOGRAPH + 0xE1AB: 0x5D89, //CJK UNIFIED IDEOGRAPH + 0xE1AC: 0x5D88, //CJK UNIFIED IDEOGRAPH + 0xE1AD: 0x5D7E, //CJK UNIFIED IDEOGRAPH + 0xE1AE: 0x5D7C, //CJK UNIFIED IDEOGRAPH + 0xE1AF: 0x5D8D, //CJK UNIFIED IDEOGRAPH + 0xE1B0: 0x5D79, //CJK UNIFIED IDEOGRAPH + 0xE1B1: 0x5D7F, //CJK UNIFIED IDEOGRAPH + 0xE1B2: 0x5E58, //CJK UNIFIED IDEOGRAPH + 0xE1B3: 0x5E59, //CJK UNIFIED IDEOGRAPH + 0xE1B4: 0x5E53, //CJK UNIFIED IDEOGRAPH + 0xE1B5: 0x5ED8, //CJK UNIFIED IDEOGRAPH + 0xE1B6: 0x5ED1, //CJK UNIFIED IDEOGRAPH + 0xE1B7: 0x5ED7, //CJK UNIFIED IDEOGRAPH + 0xE1B8: 0x5ECE, //CJK UNIFIED IDEOGRAPH + 0xE1B9: 0x5EDC, //CJK UNIFIED IDEOGRAPH + 0xE1BA: 0x5ED5, //CJK UNIFIED IDEOGRAPH + 0xE1BB: 0x5ED9, //CJK UNIFIED IDEOGRAPH + 0xE1BC: 0x5ED2, //CJK UNIFIED IDEOGRAPH + 0xE1BD: 0x5ED4, //CJK UNIFIED IDEOGRAPH + 0xE1BE: 0x5F44, //CJK UNIFIED IDEOGRAPH + 0xE1BF: 0x5F43, //CJK UNIFIED IDEOGRAPH + 0xE1C0: 0x5F6F, //CJK UNIFIED IDEOGRAPH + 0xE1C1: 0x5FB6, //CJK UNIFIED IDEOGRAPH + 0xE1C2: 0x612C, //CJK UNIFIED IDEOGRAPH + 0xE1C3: 0x6128, //CJK UNIFIED IDEOGRAPH + 0xE1C4: 0x6141, //CJK UNIFIED IDEOGRAPH + 0xE1C5: 0x615E, //CJK UNIFIED IDEOGRAPH + 0xE1C6: 0x6171, //CJK UNIFIED IDEOGRAPH + 0xE1C7: 0x6173, //CJK UNIFIED IDEOGRAPH + 0xE1C8: 0x6152, //CJK UNIFIED IDEOGRAPH + 0xE1C9: 0x6153, //CJK UNIFIED IDEOGRAPH + 0xE1CA: 0x6172, //CJK UNIFIED IDEOGRAPH + 0xE1CB: 0x616C, //CJK UNIFIED IDEOGRAPH + 0xE1CC: 0x6180, //CJK UNIFIED IDEOGRAPH + 0xE1CD: 0x6174, //CJK UNIFIED IDEOGRAPH + 0xE1CE: 0x6154, //CJK UNIFIED IDEOGRAPH + 0xE1CF: 0x617A, //CJK UNIFIED IDEOGRAPH + 0xE1D0: 0x615B, //CJK UNIFIED IDEOGRAPH + 0xE1D1: 0x6165, //CJK UNIFIED IDEOGRAPH + 0xE1D2: 0x613B, //CJK UNIFIED IDEOGRAPH + 0xE1D3: 0x616A, //CJK UNIFIED IDEOGRAPH + 0xE1D4: 0x6161, //CJK UNIFIED IDEOGRAPH + 0xE1D5: 0x6156, //CJK UNIFIED IDEOGRAPH + 0xE1D6: 0x6229, //CJK UNIFIED IDEOGRAPH + 0xE1D7: 0x6227, //CJK UNIFIED IDEOGRAPH + 0xE1D8: 0x622B, //CJK UNIFIED IDEOGRAPH + 0xE1D9: 0x642B, //CJK UNIFIED IDEOGRAPH + 0xE1DA: 0x644D, //CJK UNIFIED IDEOGRAPH + 0xE1DB: 0x645B, //CJK UNIFIED IDEOGRAPH + 0xE1DC: 0x645D, //CJK UNIFIED IDEOGRAPH + 0xE1DD: 0x6474, //CJK UNIFIED IDEOGRAPH + 0xE1DE: 0x6476, //CJK UNIFIED IDEOGRAPH + 0xE1DF: 0x6472, //CJK UNIFIED IDEOGRAPH + 0xE1E0: 0x6473, //CJK UNIFIED IDEOGRAPH + 0xE1E1: 0x647D, //CJK UNIFIED IDEOGRAPH + 0xE1E2: 0x6475, //CJK UNIFIED IDEOGRAPH + 0xE1E3: 0x6466, //CJK UNIFIED IDEOGRAPH + 0xE1E4: 0x64A6, //CJK UNIFIED IDEOGRAPH + 0xE1E5: 0x644E, //CJK UNIFIED IDEOGRAPH + 0xE1E6: 0x6482, //CJK UNIFIED IDEOGRAPH + 0xE1E7: 0x645E, //CJK UNIFIED IDEOGRAPH + 0xE1E8: 0x645C, //CJK UNIFIED IDEOGRAPH + 0xE1E9: 0x644B, //CJK UNIFIED IDEOGRAPH + 0xE1EA: 0x6453, //CJK UNIFIED IDEOGRAPH + 0xE1EB: 0x6460, //CJK UNIFIED IDEOGRAPH + 0xE1EC: 0x6450, //CJK UNIFIED IDEOGRAPH + 0xE1ED: 0x647F, //CJK UNIFIED IDEOGRAPH + 0xE1EE: 0x643F, //CJK UNIFIED IDEOGRAPH + 0xE1EF: 0x646C, //CJK UNIFIED IDEOGRAPH + 0xE1F0: 0x646B, //CJK UNIFIED IDEOGRAPH + 0xE1F1: 0x6459, //CJK UNIFIED IDEOGRAPH + 0xE1F2: 0x6465, //CJK UNIFIED IDEOGRAPH + 0xE1F3: 0x6477, //CJK UNIFIED IDEOGRAPH + 0xE1F4: 0x6573, //CJK UNIFIED IDEOGRAPH + 0xE1F5: 0x65A0, //CJK UNIFIED IDEOGRAPH + 0xE1F6: 0x66A1, //CJK UNIFIED IDEOGRAPH + 0xE1F7: 0x66A0, //CJK UNIFIED IDEOGRAPH + 0xE1F8: 0x669F, //CJK UNIFIED IDEOGRAPH + 0xE1F9: 0x6705, //CJK UNIFIED IDEOGRAPH + 0xE1FA: 0x6704, //CJK UNIFIED IDEOGRAPH + 0xE1FB: 0x6722, //CJK UNIFIED IDEOGRAPH + 0xE1FC: 0x69B1, //CJK UNIFIED IDEOGRAPH + 0xE1FD: 0x69B6, //CJK UNIFIED IDEOGRAPH + 0xE1FE: 0x69C9, //CJK UNIFIED IDEOGRAPH + 0xE240: 0x69A0, //CJK UNIFIED IDEOGRAPH + 0xE241: 0x69CE, //CJK UNIFIED IDEOGRAPH + 0xE242: 0x6996, //CJK UNIFIED IDEOGRAPH + 0xE243: 0x69B0, //CJK UNIFIED IDEOGRAPH + 0xE244: 0x69AC, //CJK UNIFIED IDEOGRAPH + 0xE245: 0x69BC, //CJK UNIFIED IDEOGRAPH + 0xE246: 0x6991, //CJK UNIFIED IDEOGRAPH + 0xE247: 0x6999, //CJK UNIFIED IDEOGRAPH + 0xE248: 0x698E, //CJK UNIFIED IDEOGRAPH + 0xE249: 0x69A7, //CJK UNIFIED IDEOGRAPH + 0xE24A: 0x698D, //CJK UNIFIED IDEOGRAPH + 0xE24B: 0x69A9, //CJK UNIFIED IDEOGRAPH + 0xE24C: 0x69BE, //CJK UNIFIED IDEOGRAPH + 0xE24D: 0x69AF, //CJK UNIFIED IDEOGRAPH + 0xE24E: 0x69BF, //CJK UNIFIED IDEOGRAPH + 0xE24F: 0x69C4, //CJK UNIFIED IDEOGRAPH + 0xE250: 0x69BD, //CJK UNIFIED IDEOGRAPH + 0xE251: 0x69A4, //CJK UNIFIED IDEOGRAPH + 0xE252: 0x69D4, //CJK UNIFIED IDEOGRAPH + 0xE253: 0x69B9, //CJK UNIFIED IDEOGRAPH + 0xE254: 0x69CA, //CJK UNIFIED IDEOGRAPH + 0xE255: 0x699A, //CJK UNIFIED IDEOGRAPH + 0xE256: 0x69CF, //CJK UNIFIED IDEOGRAPH + 0xE257: 0x69B3, //CJK UNIFIED IDEOGRAPH + 0xE258: 0x6993, //CJK UNIFIED IDEOGRAPH + 0xE259: 0x69AA, //CJK UNIFIED IDEOGRAPH + 0xE25A: 0x69A1, //CJK UNIFIED IDEOGRAPH + 0xE25B: 0x699E, //CJK UNIFIED IDEOGRAPH + 0xE25C: 0x69D9, //CJK UNIFIED IDEOGRAPH + 0xE25D: 0x6997, //CJK UNIFIED IDEOGRAPH + 0xE25E: 0x6990, //CJK UNIFIED IDEOGRAPH + 0xE25F: 0x69C2, //CJK UNIFIED IDEOGRAPH + 0xE260: 0x69B5, //CJK UNIFIED IDEOGRAPH + 0xE261: 0x69A5, //CJK UNIFIED IDEOGRAPH + 0xE262: 0x69C6, //CJK UNIFIED IDEOGRAPH + 0xE263: 0x6B4A, //CJK UNIFIED IDEOGRAPH + 0xE264: 0x6B4D, //CJK UNIFIED IDEOGRAPH + 0xE265: 0x6B4B, //CJK UNIFIED IDEOGRAPH + 0xE266: 0x6B9E, //CJK UNIFIED IDEOGRAPH + 0xE267: 0x6B9F, //CJK UNIFIED IDEOGRAPH + 0xE268: 0x6BA0, //CJK UNIFIED IDEOGRAPH + 0xE269: 0x6BC3, //CJK UNIFIED IDEOGRAPH + 0xE26A: 0x6BC4, //CJK UNIFIED IDEOGRAPH + 0xE26B: 0x6BFE, //CJK UNIFIED IDEOGRAPH + 0xE26C: 0x6ECE, //CJK UNIFIED IDEOGRAPH + 0xE26D: 0x6EF5, //CJK UNIFIED IDEOGRAPH + 0xE26E: 0x6EF1, //CJK UNIFIED IDEOGRAPH + 0xE26F: 0x6F03, //CJK UNIFIED IDEOGRAPH + 0xE270: 0x6F25, //CJK UNIFIED IDEOGRAPH + 0xE271: 0x6EF8, //CJK UNIFIED IDEOGRAPH + 0xE272: 0x6F37, //CJK UNIFIED IDEOGRAPH + 0xE273: 0x6EFB, //CJK UNIFIED IDEOGRAPH + 0xE274: 0x6F2E, //CJK UNIFIED IDEOGRAPH + 0xE275: 0x6F09, //CJK UNIFIED IDEOGRAPH + 0xE276: 0x6F4E, //CJK UNIFIED IDEOGRAPH + 0xE277: 0x6F19, //CJK UNIFIED IDEOGRAPH + 0xE278: 0x6F1A, //CJK UNIFIED IDEOGRAPH + 0xE279: 0x6F27, //CJK UNIFIED IDEOGRAPH + 0xE27A: 0x6F18, //CJK UNIFIED IDEOGRAPH + 0xE27B: 0x6F3B, //CJK UNIFIED IDEOGRAPH + 0xE27C: 0x6F12, //CJK UNIFIED IDEOGRAPH + 0xE27D: 0x6EED, //CJK UNIFIED IDEOGRAPH + 0xE27E: 0x6F0A, //CJK UNIFIED IDEOGRAPH + 0xE2A1: 0x6F36, //CJK UNIFIED IDEOGRAPH + 0xE2A2: 0x6F73, //CJK UNIFIED IDEOGRAPH + 0xE2A3: 0x6EF9, //CJK UNIFIED IDEOGRAPH + 0xE2A4: 0x6EEE, //CJK UNIFIED IDEOGRAPH + 0xE2A5: 0x6F2D, //CJK UNIFIED IDEOGRAPH + 0xE2A6: 0x6F40, //CJK UNIFIED IDEOGRAPH + 0xE2A7: 0x6F30, //CJK UNIFIED IDEOGRAPH + 0xE2A8: 0x6F3C, //CJK UNIFIED IDEOGRAPH + 0xE2A9: 0x6F35, //CJK UNIFIED IDEOGRAPH + 0xE2AA: 0x6EEB, //CJK UNIFIED IDEOGRAPH + 0xE2AB: 0x6F07, //CJK UNIFIED IDEOGRAPH + 0xE2AC: 0x6F0E, //CJK UNIFIED IDEOGRAPH + 0xE2AD: 0x6F43, //CJK UNIFIED IDEOGRAPH + 0xE2AE: 0x6F05, //CJK UNIFIED IDEOGRAPH + 0xE2AF: 0x6EFD, //CJK UNIFIED IDEOGRAPH + 0xE2B0: 0x6EF6, //CJK UNIFIED IDEOGRAPH + 0xE2B1: 0x6F39, //CJK UNIFIED IDEOGRAPH + 0xE2B2: 0x6F1C, //CJK UNIFIED IDEOGRAPH + 0xE2B3: 0x6EFC, //CJK UNIFIED IDEOGRAPH + 0xE2B4: 0x6F3A, //CJK UNIFIED IDEOGRAPH + 0xE2B5: 0x6F1F, //CJK UNIFIED IDEOGRAPH + 0xE2B6: 0x6F0D, //CJK UNIFIED IDEOGRAPH + 0xE2B7: 0x6F1E, //CJK UNIFIED IDEOGRAPH + 0xE2B8: 0x6F08, //CJK UNIFIED IDEOGRAPH + 0xE2B9: 0x6F21, //CJK UNIFIED IDEOGRAPH + 0xE2BA: 0x7187, //CJK UNIFIED IDEOGRAPH + 0xE2BB: 0x7190, //CJK UNIFIED IDEOGRAPH + 0xE2BC: 0x7189, //CJK UNIFIED IDEOGRAPH + 0xE2BD: 0x7180, //CJK UNIFIED IDEOGRAPH + 0xE2BE: 0x7185, //CJK UNIFIED IDEOGRAPH + 0xE2BF: 0x7182, //CJK UNIFIED IDEOGRAPH + 0xE2C0: 0x718F, //CJK UNIFIED IDEOGRAPH + 0xE2C1: 0x717B, //CJK UNIFIED IDEOGRAPH + 0xE2C2: 0x7186, //CJK UNIFIED IDEOGRAPH + 0xE2C3: 0x7181, //CJK UNIFIED IDEOGRAPH + 0xE2C4: 0x7197, //CJK UNIFIED IDEOGRAPH + 0xE2C5: 0x7244, //CJK UNIFIED IDEOGRAPH + 0xE2C6: 0x7253, //CJK UNIFIED IDEOGRAPH + 0xE2C7: 0x7297, //CJK UNIFIED IDEOGRAPH + 0xE2C8: 0x7295, //CJK UNIFIED IDEOGRAPH + 0xE2C9: 0x7293, //CJK UNIFIED IDEOGRAPH + 0xE2CA: 0x7343, //CJK UNIFIED IDEOGRAPH + 0xE2CB: 0x734D, //CJK UNIFIED IDEOGRAPH + 0xE2CC: 0x7351, //CJK UNIFIED IDEOGRAPH + 0xE2CD: 0x734C, //CJK UNIFIED IDEOGRAPH + 0xE2CE: 0x7462, //CJK UNIFIED IDEOGRAPH + 0xE2CF: 0x7473, //CJK UNIFIED IDEOGRAPH + 0xE2D0: 0x7471, //CJK UNIFIED IDEOGRAPH + 0xE2D1: 0x7475, //CJK UNIFIED IDEOGRAPH + 0xE2D2: 0x7472, //CJK UNIFIED IDEOGRAPH + 0xE2D3: 0x7467, //CJK UNIFIED IDEOGRAPH + 0xE2D4: 0x746E, //CJK UNIFIED IDEOGRAPH + 0xE2D5: 0x7500, //CJK UNIFIED IDEOGRAPH + 0xE2D6: 0x7502, //CJK UNIFIED IDEOGRAPH + 0xE2D7: 0x7503, //CJK UNIFIED IDEOGRAPH + 0xE2D8: 0x757D, //CJK UNIFIED IDEOGRAPH + 0xE2D9: 0x7590, //CJK UNIFIED IDEOGRAPH + 0xE2DA: 0x7616, //CJK UNIFIED IDEOGRAPH + 0xE2DB: 0x7608, //CJK UNIFIED IDEOGRAPH + 0xE2DC: 0x760C, //CJK UNIFIED IDEOGRAPH + 0xE2DD: 0x7615, //CJK UNIFIED IDEOGRAPH + 0xE2DE: 0x7611, //CJK UNIFIED IDEOGRAPH + 0xE2DF: 0x760A, //CJK UNIFIED IDEOGRAPH + 0xE2E0: 0x7614, //CJK UNIFIED IDEOGRAPH + 0xE2E1: 0x76B8, //CJK UNIFIED IDEOGRAPH + 0xE2E2: 0x7781, //CJK UNIFIED IDEOGRAPH + 0xE2E3: 0x777C, //CJK UNIFIED IDEOGRAPH + 0xE2E4: 0x7785, //CJK UNIFIED IDEOGRAPH + 0xE2E5: 0x7782, //CJK UNIFIED IDEOGRAPH + 0xE2E6: 0x776E, //CJK UNIFIED IDEOGRAPH + 0xE2E7: 0x7780, //CJK UNIFIED IDEOGRAPH + 0xE2E8: 0x776F, //CJK UNIFIED IDEOGRAPH + 0xE2E9: 0x777E, //CJK UNIFIED IDEOGRAPH + 0xE2EA: 0x7783, //CJK UNIFIED IDEOGRAPH + 0xE2EB: 0x78B2, //CJK UNIFIED IDEOGRAPH + 0xE2EC: 0x78AA, //CJK UNIFIED IDEOGRAPH + 0xE2ED: 0x78B4, //CJK UNIFIED IDEOGRAPH + 0xE2EE: 0x78AD, //CJK UNIFIED IDEOGRAPH + 0xE2EF: 0x78A8, //CJK UNIFIED IDEOGRAPH + 0xE2F0: 0x787E, //CJK UNIFIED IDEOGRAPH + 0xE2F1: 0x78AB, //CJK UNIFIED IDEOGRAPH + 0xE2F2: 0x789E, //CJK UNIFIED IDEOGRAPH + 0xE2F3: 0x78A5, //CJK UNIFIED IDEOGRAPH + 0xE2F4: 0x78A0, //CJK UNIFIED IDEOGRAPH + 0xE2F5: 0x78AC, //CJK UNIFIED IDEOGRAPH + 0xE2F6: 0x78A2, //CJK UNIFIED IDEOGRAPH + 0xE2F7: 0x78A4, //CJK UNIFIED IDEOGRAPH + 0xE2F8: 0x7998, //CJK UNIFIED IDEOGRAPH + 0xE2F9: 0x798A, //CJK UNIFIED IDEOGRAPH + 0xE2FA: 0x798B, //CJK UNIFIED IDEOGRAPH + 0xE2FB: 0x7996, //CJK UNIFIED IDEOGRAPH + 0xE2FC: 0x7995, //CJK UNIFIED IDEOGRAPH + 0xE2FD: 0x7994, //CJK UNIFIED IDEOGRAPH + 0xE2FE: 0x7993, //CJK UNIFIED IDEOGRAPH + 0xE340: 0x7997, //CJK UNIFIED IDEOGRAPH + 0xE341: 0x7988, //CJK UNIFIED IDEOGRAPH + 0xE342: 0x7992, //CJK UNIFIED IDEOGRAPH + 0xE343: 0x7990, //CJK UNIFIED IDEOGRAPH + 0xE344: 0x7A2B, //CJK UNIFIED IDEOGRAPH + 0xE345: 0x7A4A, //CJK UNIFIED IDEOGRAPH + 0xE346: 0x7A30, //CJK UNIFIED IDEOGRAPH + 0xE347: 0x7A2F, //CJK UNIFIED IDEOGRAPH + 0xE348: 0x7A28, //CJK UNIFIED IDEOGRAPH + 0xE349: 0x7A26, //CJK UNIFIED IDEOGRAPH + 0xE34A: 0x7AA8, //CJK UNIFIED IDEOGRAPH + 0xE34B: 0x7AAB, //CJK UNIFIED IDEOGRAPH + 0xE34C: 0x7AAC, //CJK UNIFIED IDEOGRAPH + 0xE34D: 0x7AEE, //CJK UNIFIED IDEOGRAPH + 0xE34E: 0x7B88, //CJK UNIFIED IDEOGRAPH + 0xE34F: 0x7B9C, //CJK UNIFIED IDEOGRAPH + 0xE350: 0x7B8A, //CJK UNIFIED IDEOGRAPH + 0xE351: 0x7B91, //CJK UNIFIED IDEOGRAPH + 0xE352: 0x7B90, //CJK UNIFIED IDEOGRAPH + 0xE353: 0x7B96, //CJK UNIFIED IDEOGRAPH + 0xE354: 0x7B8D, //CJK UNIFIED IDEOGRAPH + 0xE355: 0x7B8C, //CJK UNIFIED IDEOGRAPH + 0xE356: 0x7B9B, //CJK UNIFIED IDEOGRAPH + 0xE357: 0x7B8E, //CJK UNIFIED IDEOGRAPH + 0xE358: 0x7B85, //CJK UNIFIED IDEOGRAPH + 0xE359: 0x7B98, //CJK UNIFIED IDEOGRAPH + 0xE35A: 0x5284, //CJK UNIFIED IDEOGRAPH + 0xE35B: 0x7B99, //CJK UNIFIED IDEOGRAPH + 0xE35C: 0x7BA4, //CJK UNIFIED IDEOGRAPH + 0xE35D: 0x7B82, //CJK UNIFIED IDEOGRAPH + 0xE35E: 0x7CBB, //CJK UNIFIED IDEOGRAPH + 0xE35F: 0x7CBF, //CJK UNIFIED IDEOGRAPH + 0xE360: 0x7CBC, //CJK UNIFIED IDEOGRAPH + 0xE361: 0x7CBA, //CJK UNIFIED IDEOGRAPH + 0xE362: 0x7DA7, //CJK UNIFIED IDEOGRAPH + 0xE363: 0x7DB7, //CJK UNIFIED IDEOGRAPH + 0xE364: 0x7DC2, //CJK UNIFIED IDEOGRAPH + 0xE365: 0x7DA3, //CJK UNIFIED IDEOGRAPH + 0xE366: 0x7DAA, //CJK UNIFIED IDEOGRAPH + 0xE367: 0x7DC1, //CJK UNIFIED IDEOGRAPH + 0xE368: 0x7DC0, //CJK UNIFIED IDEOGRAPH + 0xE369: 0x7DC5, //CJK UNIFIED IDEOGRAPH + 0xE36A: 0x7D9D, //CJK UNIFIED IDEOGRAPH + 0xE36B: 0x7DCE, //CJK UNIFIED IDEOGRAPH + 0xE36C: 0x7DC4, //CJK UNIFIED IDEOGRAPH + 0xE36D: 0x7DC6, //CJK UNIFIED IDEOGRAPH + 0xE36E: 0x7DCB, //CJK UNIFIED IDEOGRAPH + 0xE36F: 0x7DCC, //CJK UNIFIED IDEOGRAPH + 0xE370: 0x7DAF, //CJK UNIFIED IDEOGRAPH + 0xE371: 0x7DB9, //CJK UNIFIED IDEOGRAPH + 0xE372: 0x7D96, //CJK UNIFIED IDEOGRAPH + 0xE373: 0x7DBC, //CJK UNIFIED IDEOGRAPH + 0xE374: 0x7D9F, //CJK UNIFIED IDEOGRAPH + 0xE375: 0x7DA6, //CJK UNIFIED IDEOGRAPH + 0xE376: 0x7DAE, //CJK UNIFIED IDEOGRAPH + 0xE377: 0x7DA9, //CJK UNIFIED IDEOGRAPH + 0xE378: 0x7DA1, //CJK UNIFIED IDEOGRAPH + 0xE379: 0x7DC9, //CJK UNIFIED IDEOGRAPH + 0xE37A: 0x7F73, //CJK UNIFIED IDEOGRAPH + 0xE37B: 0x7FE2, //CJK UNIFIED IDEOGRAPH + 0xE37C: 0x7FE3, //CJK UNIFIED IDEOGRAPH + 0xE37D: 0x7FE5, //CJK UNIFIED IDEOGRAPH + 0xE37E: 0x7FDE, //CJK UNIFIED IDEOGRAPH + 0xE3A1: 0x8024, //CJK UNIFIED IDEOGRAPH + 0xE3A2: 0x805D, //CJK UNIFIED IDEOGRAPH + 0xE3A3: 0x805C, //CJK UNIFIED IDEOGRAPH + 0xE3A4: 0x8189, //CJK UNIFIED IDEOGRAPH + 0xE3A5: 0x8186, //CJK UNIFIED IDEOGRAPH + 0xE3A6: 0x8183, //CJK UNIFIED IDEOGRAPH + 0xE3A7: 0x8187, //CJK UNIFIED IDEOGRAPH + 0xE3A8: 0x818D, //CJK UNIFIED IDEOGRAPH + 0xE3A9: 0x818C, //CJK UNIFIED IDEOGRAPH + 0xE3AA: 0x818B, //CJK UNIFIED IDEOGRAPH + 0xE3AB: 0x8215, //CJK UNIFIED IDEOGRAPH + 0xE3AC: 0x8497, //CJK UNIFIED IDEOGRAPH + 0xE3AD: 0x84A4, //CJK UNIFIED IDEOGRAPH + 0xE3AE: 0x84A1, //CJK UNIFIED IDEOGRAPH + 0xE3AF: 0x849F, //CJK UNIFIED IDEOGRAPH + 0xE3B0: 0x84BA, //CJK UNIFIED IDEOGRAPH + 0xE3B1: 0x84CE, //CJK UNIFIED IDEOGRAPH + 0xE3B2: 0x84C2, //CJK UNIFIED IDEOGRAPH + 0xE3B3: 0x84AC, //CJK UNIFIED IDEOGRAPH + 0xE3B4: 0x84AE, //CJK UNIFIED IDEOGRAPH + 0xE3B5: 0x84AB, //CJK UNIFIED IDEOGRAPH + 0xE3B6: 0x84B9, //CJK UNIFIED IDEOGRAPH + 0xE3B7: 0x84B4, //CJK UNIFIED IDEOGRAPH + 0xE3B8: 0x84C1, //CJK UNIFIED IDEOGRAPH + 0xE3B9: 0x84CD, //CJK UNIFIED IDEOGRAPH + 0xE3BA: 0x84AA, //CJK UNIFIED IDEOGRAPH + 0xE3BB: 0x849A, //CJK UNIFIED IDEOGRAPH + 0xE3BC: 0x84B1, //CJK UNIFIED IDEOGRAPH + 0xE3BD: 0x84D0, //CJK UNIFIED IDEOGRAPH + 0xE3BE: 0x849D, //CJK UNIFIED IDEOGRAPH + 0xE3BF: 0x84A7, //CJK UNIFIED IDEOGRAPH + 0xE3C0: 0x84BB, //CJK UNIFIED IDEOGRAPH + 0xE3C1: 0x84A2, //CJK UNIFIED IDEOGRAPH + 0xE3C2: 0x8494, //CJK UNIFIED IDEOGRAPH + 0xE3C3: 0x84C7, //CJK UNIFIED IDEOGRAPH + 0xE3C4: 0x84CC, //CJK UNIFIED IDEOGRAPH + 0xE3C5: 0x849B, //CJK UNIFIED IDEOGRAPH + 0xE3C6: 0x84A9, //CJK UNIFIED IDEOGRAPH + 0xE3C7: 0x84AF, //CJK UNIFIED IDEOGRAPH + 0xE3C8: 0x84A8, //CJK UNIFIED IDEOGRAPH + 0xE3C9: 0x84D6, //CJK UNIFIED IDEOGRAPH + 0xE3CA: 0x8498, //CJK UNIFIED IDEOGRAPH + 0xE3CB: 0x84B6, //CJK UNIFIED IDEOGRAPH + 0xE3CC: 0x84CF, //CJK UNIFIED IDEOGRAPH + 0xE3CD: 0x84A0, //CJK UNIFIED IDEOGRAPH + 0xE3CE: 0x84D7, //CJK UNIFIED IDEOGRAPH + 0xE3CF: 0x84D4, //CJK UNIFIED IDEOGRAPH + 0xE3D0: 0x84D2, //CJK UNIFIED IDEOGRAPH + 0xE3D1: 0x84DB, //CJK UNIFIED IDEOGRAPH + 0xE3D2: 0x84B0, //CJK UNIFIED IDEOGRAPH + 0xE3D3: 0x8491, //CJK UNIFIED IDEOGRAPH + 0xE3D4: 0x8661, //CJK UNIFIED IDEOGRAPH + 0xE3D5: 0x8733, //CJK UNIFIED IDEOGRAPH + 0xE3D6: 0x8723, //CJK UNIFIED IDEOGRAPH + 0xE3D7: 0x8728, //CJK UNIFIED IDEOGRAPH + 0xE3D8: 0x876B, //CJK UNIFIED IDEOGRAPH + 0xE3D9: 0x8740, //CJK UNIFIED IDEOGRAPH + 0xE3DA: 0x872E, //CJK UNIFIED IDEOGRAPH + 0xE3DB: 0x871E, //CJK UNIFIED IDEOGRAPH + 0xE3DC: 0x8721, //CJK UNIFIED IDEOGRAPH + 0xE3DD: 0x8719, //CJK UNIFIED IDEOGRAPH + 0xE3DE: 0x871B, //CJK UNIFIED IDEOGRAPH + 0xE3DF: 0x8743, //CJK UNIFIED IDEOGRAPH + 0xE3E0: 0x872C, //CJK UNIFIED IDEOGRAPH + 0xE3E1: 0x8741, //CJK UNIFIED IDEOGRAPH + 0xE3E2: 0x873E, //CJK UNIFIED IDEOGRAPH + 0xE3E3: 0x8746, //CJK UNIFIED IDEOGRAPH + 0xE3E4: 0x8720, //CJK UNIFIED IDEOGRAPH + 0xE3E5: 0x8732, //CJK UNIFIED IDEOGRAPH + 0xE3E6: 0x872A, //CJK UNIFIED IDEOGRAPH + 0xE3E7: 0x872D, //CJK UNIFIED IDEOGRAPH + 0xE3E8: 0x873C, //CJK UNIFIED IDEOGRAPH + 0xE3E9: 0x8712, //CJK UNIFIED IDEOGRAPH + 0xE3EA: 0x873A, //CJK UNIFIED IDEOGRAPH + 0xE3EB: 0x8731, //CJK UNIFIED IDEOGRAPH + 0xE3EC: 0x8735, //CJK UNIFIED IDEOGRAPH + 0xE3ED: 0x8742, //CJK UNIFIED IDEOGRAPH + 0xE3EE: 0x8726, //CJK UNIFIED IDEOGRAPH + 0xE3EF: 0x8727, //CJK UNIFIED IDEOGRAPH + 0xE3F0: 0x8738, //CJK UNIFIED IDEOGRAPH + 0xE3F1: 0x8724, //CJK UNIFIED IDEOGRAPH + 0xE3F2: 0x871A, //CJK UNIFIED IDEOGRAPH + 0xE3F3: 0x8730, //CJK UNIFIED IDEOGRAPH + 0xE3F4: 0x8711, //CJK UNIFIED IDEOGRAPH + 0xE3F5: 0x88F7, //CJK UNIFIED IDEOGRAPH + 0xE3F6: 0x88E7, //CJK UNIFIED IDEOGRAPH + 0xE3F7: 0x88F1, //CJK UNIFIED IDEOGRAPH + 0xE3F8: 0x88F2, //CJK UNIFIED IDEOGRAPH + 0xE3F9: 0x88FA, //CJK UNIFIED IDEOGRAPH + 0xE3FA: 0x88FE, //CJK UNIFIED IDEOGRAPH + 0xE3FB: 0x88EE, //CJK UNIFIED IDEOGRAPH + 0xE3FC: 0x88FC, //CJK UNIFIED IDEOGRAPH + 0xE3FD: 0x88F6, //CJK UNIFIED IDEOGRAPH + 0xE3FE: 0x88FB, //CJK UNIFIED IDEOGRAPH + 0xE440: 0x88F0, //CJK UNIFIED IDEOGRAPH + 0xE441: 0x88EC, //CJK UNIFIED IDEOGRAPH + 0xE442: 0x88EB, //CJK UNIFIED IDEOGRAPH + 0xE443: 0x899D, //CJK UNIFIED IDEOGRAPH + 0xE444: 0x89A1, //CJK UNIFIED IDEOGRAPH + 0xE445: 0x899F, //CJK UNIFIED IDEOGRAPH + 0xE446: 0x899E, //CJK UNIFIED IDEOGRAPH + 0xE447: 0x89E9, //CJK UNIFIED IDEOGRAPH + 0xE448: 0x89EB, //CJK UNIFIED IDEOGRAPH + 0xE449: 0x89E8, //CJK UNIFIED IDEOGRAPH + 0xE44A: 0x8AAB, //CJK UNIFIED IDEOGRAPH + 0xE44B: 0x8A99, //CJK UNIFIED IDEOGRAPH + 0xE44C: 0x8A8B, //CJK UNIFIED IDEOGRAPH + 0xE44D: 0x8A92, //CJK UNIFIED IDEOGRAPH + 0xE44E: 0x8A8F, //CJK UNIFIED IDEOGRAPH + 0xE44F: 0x8A96, //CJK UNIFIED IDEOGRAPH + 0xE450: 0x8C3D, //CJK UNIFIED IDEOGRAPH + 0xE451: 0x8C68, //CJK UNIFIED IDEOGRAPH + 0xE452: 0x8C69, //CJK UNIFIED IDEOGRAPH + 0xE453: 0x8CD5, //CJK UNIFIED IDEOGRAPH + 0xE454: 0x8CCF, //CJK UNIFIED IDEOGRAPH + 0xE455: 0x8CD7, //CJK UNIFIED IDEOGRAPH + 0xE456: 0x8D96, //CJK UNIFIED IDEOGRAPH + 0xE457: 0x8E09, //CJK UNIFIED IDEOGRAPH + 0xE458: 0x8E02, //CJK UNIFIED IDEOGRAPH + 0xE459: 0x8DFF, //CJK UNIFIED IDEOGRAPH + 0xE45A: 0x8E0D, //CJK UNIFIED IDEOGRAPH + 0xE45B: 0x8DFD, //CJK UNIFIED IDEOGRAPH + 0xE45C: 0x8E0A, //CJK UNIFIED IDEOGRAPH + 0xE45D: 0x8E03, //CJK UNIFIED IDEOGRAPH + 0xE45E: 0x8E07, //CJK UNIFIED IDEOGRAPH + 0xE45F: 0x8E06, //CJK UNIFIED IDEOGRAPH + 0xE460: 0x8E05, //CJK UNIFIED IDEOGRAPH + 0xE461: 0x8DFE, //CJK UNIFIED IDEOGRAPH + 0xE462: 0x8E00, //CJK UNIFIED IDEOGRAPH + 0xE463: 0x8E04, //CJK UNIFIED IDEOGRAPH + 0xE464: 0x8F10, //CJK UNIFIED IDEOGRAPH + 0xE465: 0x8F11, //CJK UNIFIED IDEOGRAPH + 0xE466: 0x8F0E, //CJK UNIFIED IDEOGRAPH + 0xE467: 0x8F0D, //CJK UNIFIED IDEOGRAPH + 0xE468: 0x9123, //CJK UNIFIED IDEOGRAPH + 0xE469: 0x911C, //CJK UNIFIED IDEOGRAPH + 0xE46A: 0x9120, //CJK UNIFIED IDEOGRAPH + 0xE46B: 0x9122, //CJK UNIFIED IDEOGRAPH + 0xE46C: 0x911F, //CJK UNIFIED IDEOGRAPH + 0xE46D: 0x911D, //CJK UNIFIED IDEOGRAPH + 0xE46E: 0x911A, //CJK UNIFIED IDEOGRAPH + 0xE46F: 0x9124, //CJK UNIFIED IDEOGRAPH + 0xE470: 0x9121, //CJK UNIFIED IDEOGRAPH + 0xE471: 0x911B, //CJK UNIFIED IDEOGRAPH + 0xE472: 0x917A, //CJK UNIFIED IDEOGRAPH + 0xE473: 0x9172, //CJK UNIFIED IDEOGRAPH + 0xE474: 0x9179, //CJK UNIFIED IDEOGRAPH + 0xE475: 0x9173, //CJK UNIFIED IDEOGRAPH + 0xE476: 0x92A5, //CJK UNIFIED IDEOGRAPH + 0xE477: 0x92A4, //CJK UNIFIED IDEOGRAPH + 0xE478: 0x9276, //CJK UNIFIED IDEOGRAPH + 0xE479: 0x929B, //CJK UNIFIED IDEOGRAPH + 0xE47A: 0x927A, //CJK UNIFIED IDEOGRAPH + 0xE47B: 0x92A0, //CJK UNIFIED IDEOGRAPH + 0xE47C: 0x9294, //CJK UNIFIED IDEOGRAPH + 0xE47D: 0x92AA, //CJK UNIFIED IDEOGRAPH + 0xE47E: 0x928D, //CJK UNIFIED IDEOGRAPH + 0xE4A1: 0x92A6, //CJK UNIFIED IDEOGRAPH + 0xE4A2: 0x929A, //CJK UNIFIED IDEOGRAPH + 0xE4A3: 0x92AB, //CJK UNIFIED IDEOGRAPH + 0xE4A4: 0x9279, //CJK UNIFIED IDEOGRAPH + 0xE4A5: 0x9297, //CJK UNIFIED IDEOGRAPH + 0xE4A6: 0x927F, //CJK UNIFIED IDEOGRAPH + 0xE4A7: 0x92A3, //CJK UNIFIED IDEOGRAPH + 0xE4A8: 0x92EE, //CJK UNIFIED IDEOGRAPH + 0xE4A9: 0x928E, //CJK UNIFIED IDEOGRAPH + 0xE4AA: 0x9282, //CJK UNIFIED IDEOGRAPH + 0xE4AB: 0x9295, //CJK UNIFIED IDEOGRAPH + 0xE4AC: 0x92A2, //CJK UNIFIED IDEOGRAPH + 0xE4AD: 0x927D, //CJK UNIFIED IDEOGRAPH + 0xE4AE: 0x9288, //CJK UNIFIED IDEOGRAPH + 0xE4AF: 0x92A1, //CJK UNIFIED IDEOGRAPH + 0xE4B0: 0x928A, //CJK UNIFIED IDEOGRAPH + 0xE4B1: 0x9286, //CJK UNIFIED IDEOGRAPH + 0xE4B2: 0x928C, //CJK UNIFIED IDEOGRAPH + 0xE4B3: 0x9299, //CJK UNIFIED IDEOGRAPH + 0xE4B4: 0x92A7, //CJK UNIFIED IDEOGRAPH + 0xE4B5: 0x927E, //CJK UNIFIED IDEOGRAPH + 0xE4B6: 0x9287, //CJK UNIFIED IDEOGRAPH + 0xE4B7: 0x92A9, //CJK UNIFIED IDEOGRAPH + 0xE4B8: 0x929D, //CJK UNIFIED IDEOGRAPH + 0xE4B9: 0x928B, //CJK UNIFIED IDEOGRAPH + 0xE4BA: 0x922D, //CJK UNIFIED IDEOGRAPH + 0xE4BB: 0x969E, //CJK UNIFIED IDEOGRAPH + 0xE4BC: 0x96A1, //CJK UNIFIED IDEOGRAPH + 0xE4BD: 0x96FF, //CJK UNIFIED IDEOGRAPH + 0xE4BE: 0x9758, //CJK UNIFIED IDEOGRAPH + 0xE4BF: 0x977D, //CJK UNIFIED IDEOGRAPH + 0xE4C0: 0x977A, //CJK UNIFIED IDEOGRAPH + 0xE4C1: 0x977E, //CJK UNIFIED IDEOGRAPH + 0xE4C2: 0x9783, //CJK UNIFIED IDEOGRAPH + 0xE4C3: 0x9780, //CJK UNIFIED IDEOGRAPH + 0xE4C4: 0x9782, //CJK UNIFIED IDEOGRAPH + 0xE4C5: 0x977B, //CJK UNIFIED IDEOGRAPH + 0xE4C6: 0x9784, //CJK UNIFIED IDEOGRAPH + 0xE4C7: 0x9781, //CJK UNIFIED IDEOGRAPH + 0xE4C8: 0x977F, //CJK UNIFIED IDEOGRAPH + 0xE4C9: 0x97CE, //CJK UNIFIED IDEOGRAPH + 0xE4CA: 0x97CD, //CJK UNIFIED IDEOGRAPH + 0xE4CB: 0x9816, //CJK UNIFIED IDEOGRAPH + 0xE4CC: 0x98AD, //CJK UNIFIED IDEOGRAPH + 0xE4CD: 0x98AE, //CJK UNIFIED IDEOGRAPH + 0xE4CE: 0x9902, //CJK UNIFIED IDEOGRAPH + 0xE4CF: 0x9900, //CJK UNIFIED IDEOGRAPH + 0xE4D0: 0x9907, //CJK UNIFIED IDEOGRAPH + 0xE4D1: 0x999D, //CJK UNIFIED IDEOGRAPH + 0xE4D2: 0x999C, //CJK UNIFIED IDEOGRAPH + 0xE4D3: 0x99C3, //CJK UNIFIED IDEOGRAPH + 0xE4D4: 0x99B9, //CJK UNIFIED IDEOGRAPH + 0xE4D5: 0x99BB, //CJK UNIFIED IDEOGRAPH + 0xE4D6: 0x99BA, //CJK UNIFIED IDEOGRAPH + 0xE4D7: 0x99C2, //CJK UNIFIED IDEOGRAPH + 0xE4D8: 0x99BD, //CJK UNIFIED IDEOGRAPH + 0xE4D9: 0x99C7, //CJK UNIFIED IDEOGRAPH + 0xE4DA: 0x9AB1, //CJK UNIFIED IDEOGRAPH + 0xE4DB: 0x9AE3, //CJK UNIFIED IDEOGRAPH + 0xE4DC: 0x9AE7, //CJK UNIFIED IDEOGRAPH + 0xE4DD: 0x9B3E, //CJK UNIFIED IDEOGRAPH + 0xE4DE: 0x9B3F, //CJK UNIFIED IDEOGRAPH + 0xE4DF: 0x9B60, //CJK UNIFIED IDEOGRAPH + 0xE4E0: 0x9B61, //CJK UNIFIED IDEOGRAPH + 0xE4E1: 0x9B5F, //CJK UNIFIED IDEOGRAPH + 0xE4E2: 0x9CF1, //CJK UNIFIED IDEOGRAPH + 0xE4E3: 0x9CF2, //CJK UNIFIED IDEOGRAPH + 0xE4E4: 0x9CF5, //CJK UNIFIED IDEOGRAPH + 0xE4E5: 0x9EA7, //CJK UNIFIED IDEOGRAPH + 0xE4E6: 0x50FF, //CJK UNIFIED IDEOGRAPH + 0xE4E7: 0x5103, //CJK UNIFIED IDEOGRAPH + 0xE4E8: 0x5130, //CJK UNIFIED IDEOGRAPH + 0xE4E9: 0x50F8, //CJK UNIFIED IDEOGRAPH + 0xE4EA: 0x5106, //CJK UNIFIED IDEOGRAPH + 0xE4EB: 0x5107, //CJK UNIFIED IDEOGRAPH + 0xE4EC: 0x50F6, //CJK UNIFIED IDEOGRAPH + 0xE4ED: 0x50FE, //CJK UNIFIED IDEOGRAPH + 0xE4EE: 0x510B, //CJK UNIFIED IDEOGRAPH + 0xE4EF: 0x510C, //CJK UNIFIED IDEOGRAPH + 0xE4F0: 0x50FD, //CJK UNIFIED IDEOGRAPH + 0xE4F1: 0x510A, //CJK UNIFIED IDEOGRAPH + 0xE4F2: 0x528B, //CJK UNIFIED IDEOGRAPH + 0xE4F3: 0x528C, //CJK UNIFIED IDEOGRAPH + 0xE4F4: 0x52F1, //CJK UNIFIED IDEOGRAPH + 0xE4F5: 0x52EF, //CJK UNIFIED IDEOGRAPH + 0xE4F6: 0x5648, //CJK UNIFIED IDEOGRAPH + 0xE4F7: 0x5642, //CJK UNIFIED IDEOGRAPH + 0xE4F8: 0x564C, //CJK UNIFIED IDEOGRAPH + 0xE4F9: 0x5635, //CJK UNIFIED IDEOGRAPH + 0xE4FA: 0x5641, //CJK UNIFIED IDEOGRAPH + 0xE4FB: 0x564A, //CJK UNIFIED IDEOGRAPH + 0xE4FC: 0x5649, //CJK UNIFIED IDEOGRAPH + 0xE4FD: 0x5646, //CJK UNIFIED IDEOGRAPH + 0xE4FE: 0x5658, //CJK UNIFIED IDEOGRAPH + 0xE540: 0x565A, //CJK UNIFIED IDEOGRAPH + 0xE541: 0x5640, //CJK UNIFIED IDEOGRAPH + 0xE542: 0x5633, //CJK UNIFIED IDEOGRAPH + 0xE543: 0x563D, //CJK UNIFIED IDEOGRAPH + 0xE544: 0x562C, //CJK UNIFIED IDEOGRAPH + 0xE545: 0x563E, //CJK UNIFIED IDEOGRAPH + 0xE546: 0x5638, //CJK UNIFIED IDEOGRAPH + 0xE547: 0x562A, //CJK UNIFIED IDEOGRAPH + 0xE548: 0x563A, //CJK UNIFIED IDEOGRAPH + 0xE549: 0x571A, //CJK UNIFIED IDEOGRAPH + 0xE54A: 0x58AB, //CJK UNIFIED IDEOGRAPH + 0xE54B: 0x589D, //CJK UNIFIED IDEOGRAPH + 0xE54C: 0x58B1, //CJK UNIFIED IDEOGRAPH + 0xE54D: 0x58A0, //CJK UNIFIED IDEOGRAPH + 0xE54E: 0x58A3, //CJK UNIFIED IDEOGRAPH + 0xE54F: 0x58AF, //CJK UNIFIED IDEOGRAPH + 0xE550: 0x58AC, //CJK UNIFIED IDEOGRAPH + 0xE551: 0x58A5, //CJK UNIFIED IDEOGRAPH + 0xE552: 0x58A1, //CJK UNIFIED IDEOGRAPH + 0xE553: 0x58FF, //CJK UNIFIED IDEOGRAPH + 0xE554: 0x5AFF, //CJK UNIFIED IDEOGRAPH + 0xE555: 0x5AF4, //CJK UNIFIED IDEOGRAPH + 0xE556: 0x5AFD, //CJK UNIFIED IDEOGRAPH + 0xE557: 0x5AF7, //CJK UNIFIED IDEOGRAPH + 0xE558: 0x5AF6, //CJK UNIFIED IDEOGRAPH + 0xE559: 0x5B03, //CJK UNIFIED IDEOGRAPH + 0xE55A: 0x5AF8, //CJK UNIFIED IDEOGRAPH + 0xE55B: 0x5B02, //CJK UNIFIED IDEOGRAPH + 0xE55C: 0x5AF9, //CJK UNIFIED IDEOGRAPH + 0xE55D: 0x5B01, //CJK UNIFIED IDEOGRAPH + 0xE55E: 0x5B07, //CJK UNIFIED IDEOGRAPH + 0xE55F: 0x5B05, //CJK UNIFIED IDEOGRAPH + 0xE560: 0x5B0F, //CJK UNIFIED IDEOGRAPH + 0xE561: 0x5C67, //CJK UNIFIED IDEOGRAPH + 0xE562: 0x5D99, //CJK UNIFIED IDEOGRAPH + 0xE563: 0x5D97, //CJK UNIFIED IDEOGRAPH + 0xE564: 0x5D9F, //CJK UNIFIED IDEOGRAPH + 0xE565: 0x5D92, //CJK UNIFIED IDEOGRAPH + 0xE566: 0x5DA2, //CJK UNIFIED IDEOGRAPH + 0xE567: 0x5D93, //CJK UNIFIED IDEOGRAPH + 0xE568: 0x5D95, //CJK UNIFIED IDEOGRAPH + 0xE569: 0x5DA0, //CJK UNIFIED IDEOGRAPH + 0xE56A: 0x5D9C, //CJK UNIFIED IDEOGRAPH + 0xE56B: 0x5DA1, //CJK UNIFIED IDEOGRAPH + 0xE56C: 0x5D9A, //CJK UNIFIED IDEOGRAPH + 0xE56D: 0x5D9E, //CJK UNIFIED IDEOGRAPH + 0xE56E: 0x5E69, //CJK UNIFIED IDEOGRAPH + 0xE56F: 0x5E5D, //CJK UNIFIED IDEOGRAPH + 0xE570: 0x5E60, //CJK UNIFIED IDEOGRAPH + 0xE571: 0x5E5C, //CJK UNIFIED IDEOGRAPH + 0xE572: 0x7DF3, //CJK UNIFIED IDEOGRAPH + 0xE573: 0x5EDB, //CJK UNIFIED IDEOGRAPH + 0xE574: 0x5EDE, //CJK UNIFIED IDEOGRAPH + 0xE575: 0x5EE1, //CJK UNIFIED IDEOGRAPH + 0xE576: 0x5F49, //CJK UNIFIED IDEOGRAPH + 0xE577: 0x5FB2, //CJK UNIFIED IDEOGRAPH + 0xE578: 0x618B, //CJK UNIFIED IDEOGRAPH + 0xE579: 0x6183, //CJK UNIFIED IDEOGRAPH + 0xE57A: 0x6179, //CJK UNIFIED IDEOGRAPH + 0xE57B: 0x61B1, //CJK UNIFIED IDEOGRAPH + 0xE57C: 0x61B0, //CJK UNIFIED IDEOGRAPH + 0xE57D: 0x61A2, //CJK UNIFIED IDEOGRAPH + 0xE57E: 0x6189, //CJK UNIFIED IDEOGRAPH + 0xE5A1: 0x619B, //CJK UNIFIED IDEOGRAPH + 0xE5A2: 0x6193, //CJK UNIFIED IDEOGRAPH + 0xE5A3: 0x61AF, //CJK UNIFIED IDEOGRAPH + 0xE5A4: 0x61AD, //CJK UNIFIED IDEOGRAPH + 0xE5A5: 0x619F, //CJK UNIFIED IDEOGRAPH + 0xE5A6: 0x6192, //CJK UNIFIED IDEOGRAPH + 0xE5A7: 0x61AA, //CJK UNIFIED IDEOGRAPH + 0xE5A8: 0x61A1, //CJK UNIFIED IDEOGRAPH + 0xE5A9: 0x618D, //CJK UNIFIED IDEOGRAPH + 0xE5AA: 0x6166, //CJK UNIFIED IDEOGRAPH + 0xE5AB: 0x61B3, //CJK UNIFIED IDEOGRAPH + 0xE5AC: 0x622D, //CJK UNIFIED IDEOGRAPH + 0xE5AD: 0x646E, //CJK UNIFIED IDEOGRAPH + 0xE5AE: 0x6470, //CJK UNIFIED IDEOGRAPH + 0xE5AF: 0x6496, //CJK UNIFIED IDEOGRAPH + 0xE5B0: 0x64A0, //CJK UNIFIED IDEOGRAPH + 0xE5B1: 0x6485, //CJK UNIFIED IDEOGRAPH + 0xE5B2: 0x6497, //CJK UNIFIED IDEOGRAPH + 0xE5B3: 0x649C, //CJK UNIFIED IDEOGRAPH + 0xE5B4: 0x648F, //CJK UNIFIED IDEOGRAPH + 0xE5B5: 0x648B, //CJK UNIFIED IDEOGRAPH + 0xE5B6: 0x648A, //CJK UNIFIED IDEOGRAPH + 0xE5B7: 0x648C, //CJK UNIFIED IDEOGRAPH + 0xE5B8: 0x64A3, //CJK UNIFIED IDEOGRAPH + 0xE5B9: 0x649F, //CJK UNIFIED IDEOGRAPH + 0xE5BA: 0x6468, //CJK UNIFIED IDEOGRAPH + 0xE5BB: 0x64B1, //CJK UNIFIED IDEOGRAPH + 0xE5BC: 0x6498, //CJK UNIFIED IDEOGRAPH + 0xE5BD: 0x6576, //CJK UNIFIED IDEOGRAPH + 0xE5BE: 0x657A, //CJK UNIFIED IDEOGRAPH + 0xE5BF: 0x6579, //CJK UNIFIED IDEOGRAPH + 0xE5C0: 0x657B, //CJK UNIFIED IDEOGRAPH + 0xE5C1: 0x65B2, //CJK UNIFIED IDEOGRAPH + 0xE5C2: 0x65B3, //CJK UNIFIED IDEOGRAPH + 0xE5C3: 0x66B5, //CJK UNIFIED IDEOGRAPH + 0xE5C4: 0x66B0, //CJK UNIFIED IDEOGRAPH + 0xE5C5: 0x66A9, //CJK UNIFIED IDEOGRAPH + 0xE5C6: 0x66B2, //CJK UNIFIED IDEOGRAPH + 0xE5C7: 0x66B7, //CJK UNIFIED IDEOGRAPH + 0xE5C8: 0x66AA, //CJK UNIFIED IDEOGRAPH + 0xE5C9: 0x66AF, //CJK UNIFIED IDEOGRAPH + 0xE5CA: 0x6A00, //CJK UNIFIED IDEOGRAPH + 0xE5CB: 0x6A06, //CJK UNIFIED IDEOGRAPH + 0xE5CC: 0x6A17, //CJK UNIFIED IDEOGRAPH + 0xE5CD: 0x69E5, //CJK UNIFIED IDEOGRAPH + 0xE5CE: 0x69F8, //CJK UNIFIED IDEOGRAPH + 0xE5CF: 0x6A15, //CJK UNIFIED IDEOGRAPH + 0xE5D0: 0x69F1, //CJK UNIFIED IDEOGRAPH + 0xE5D1: 0x69E4, //CJK UNIFIED IDEOGRAPH + 0xE5D2: 0x6A20, //CJK UNIFIED IDEOGRAPH + 0xE5D3: 0x69FF, //CJK UNIFIED IDEOGRAPH + 0xE5D4: 0x69EC, //CJK UNIFIED IDEOGRAPH + 0xE5D5: 0x69E2, //CJK UNIFIED IDEOGRAPH + 0xE5D6: 0x6A1B, //CJK UNIFIED IDEOGRAPH + 0xE5D7: 0x6A1D, //CJK UNIFIED IDEOGRAPH + 0xE5D8: 0x69FE, //CJK UNIFIED IDEOGRAPH + 0xE5D9: 0x6A27, //CJK UNIFIED IDEOGRAPH + 0xE5DA: 0x69F2, //CJK UNIFIED IDEOGRAPH + 0xE5DB: 0x69EE, //CJK UNIFIED IDEOGRAPH + 0xE5DC: 0x6A14, //CJK UNIFIED IDEOGRAPH + 0xE5DD: 0x69F7, //CJK UNIFIED IDEOGRAPH + 0xE5DE: 0x69E7, //CJK UNIFIED IDEOGRAPH + 0xE5DF: 0x6A40, //CJK UNIFIED IDEOGRAPH + 0xE5E0: 0x6A08, //CJK UNIFIED IDEOGRAPH + 0xE5E1: 0x69E6, //CJK UNIFIED IDEOGRAPH + 0xE5E2: 0x69FB, //CJK UNIFIED IDEOGRAPH + 0xE5E3: 0x6A0D, //CJK UNIFIED IDEOGRAPH + 0xE5E4: 0x69FC, //CJK UNIFIED IDEOGRAPH + 0xE5E5: 0x69EB, //CJK UNIFIED IDEOGRAPH + 0xE5E6: 0x6A09, //CJK UNIFIED IDEOGRAPH + 0xE5E7: 0x6A04, //CJK UNIFIED IDEOGRAPH + 0xE5E8: 0x6A18, //CJK UNIFIED IDEOGRAPH + 0xE5E9: 0x6A25, //CJK UNIFIED IDEOGRAPH + 0xE5EA: 0x6A0F, //CJK UNIFIED IDEOGRAPH + 0xE5EB: 0x69F6, //CJK UNIFIED IDEOGRAPH + 0xE5EC: 0x6A26, //CJK UNIFIED IDEOGRAPH + 0xE5ED: 0x6A07, //CJK UNIFIED IDEOGRAPH + 0xE5EE: 0x69F4, //CJK UNIFIED IDEOGRAPH + 0xE5EF: 0x6A16, //CJK UNIFIED IDEOGRAPH + 0xE5F0: 0x6B51, //CJK UNIFIED IDEOGRAPH + 0xE5F1: 0x6BA5, //CJK UNIFIED IDEOGRAPH + 0xE5F2: 0x6BA3, //CJK UNIFIED IDEOGRAPH + 0xE5F3: 0x6BA2, //CJK UNIFIED IDEOGRAPH + 0xE5F4: 0x6BA6, //CJK UNIFIED IDEOGRAPH + 0xE5F5: 0x6C01, //CJK UNIFIED IDEOGRAPH + 0xE5F6: 0x6C00, //CJK UNIFIED IDEOGRAPH + 0xE5F7: 0x6BFF, //CJK UNIFIED IDEOGRAPH + 0xE5F8: 0x6C02, //CJK UNIFIED IDEOGRAPH + 0xE5F9: 0x6F41, //CJK UNIFIED IDEOGRAPH + 0xE5FA: 0x6F26, //CJK UNIFIED IDEOGRAPH + 0xE5FB: 0x6F7E, //CJK UNIFIED IDEOGRAPH + 0xE5FC: 0x6F87, //CJK UNIFIED IDEOGRAPH + 0xE5FD: 0x6FC6, //CJK UNIFIED IDEOGRAPH + 0xE5FE: 0x6F92, //CJK UNIFIED IDEOGRAPH + 0xE640: 0x6F8D, //CJK UNIFIED IDEOGRAPH + 0xE641: 0x6F89, //CJK UNIFIED IDEOGRAPH + 0xE642: 0x6F8C, //CJK UNIFIED IDEOGRAPH + 0xE643: 0x6F62, //CJK UNIFIED IDEOGRAPH + 0xE644: 0x6F4F, //CJK UNIFIED IDEOGRAPH + 0xE645: 0x6F85, //CJK UNIFIED IDEOGRAPH + 0xE646: 0x6F5A, //CJK UNIFIED IDEOGRAPH + 0xE647: 0x6F96, //CJK UNIFIED IDEOGRAPH + 0xE648: 0x6F76, //CJK UNIFIED IDEOGRAPH + 0xE649: 0x6F6C, //CJK UNIFIED IDEOGRAPH + 0xE64A: 0x6F82, //CJK UNIFIED IDEOGRAPH + 0xE64B: 0x6F55, //CJK UNIFIED IDEOGRAPH + 0xE64C: 0x6F72, //CJK UNIFIED IDEOGRAPH + 0xE64D: 0x6F52, //CJK UNIFIED IDEOGRAPH + 0xE64E: 0x6F50, //CJK UNIFIED IDEOGRAPH + 0xE64F: 0x6F57, //CJK UNIFIED IDEOGRAPH + 0xE650: 0x6F94, //CJK UNIFIED IDEOGRAPH + 0xE651: 0x6F93, //CJK UNIFIED IDEOGRAPH + 0xE652: 0x6F5D, //CJK UNIFIED IDEOGRAPH + 0xE653: 0x6F00, //CJK UNIFIED IDEOGRAPH + 0xE654: 0x6F61, //CJK UNIFIED IDEOGRAPH + 0xE655: 0x6F6B, //CJK UNIFIED IDEOGRAPH + 0xE656: 0x6F7D, //CJK UNIFIED IDEOGRAPH + 0xE657: 0x6F67, //CJK UNIFIED IDEOGRAPH + 0xE658: 0x6F90, //CJK UNIFIED IDEOGRAPH + 0xE659: 0x6F53, //CJK UNIFIED IDEOGRAPH + 0xE65A: 0x6F8B, //CJK UNIFIED IDEOGRAPH + 0xE65B: 0x6F69, //CJK UNIFIED IDEOGRAPH + 0xE65C: 0x6F7F, //CJK UNIFIED IDEOGRAPH + 0xE65D: 0x6F95, //CJK UNIFIED IDEOGRAPH + 0xE65E: 0x6F63, //CJK UNIFIED IDEOGRAPH + 0xE65F: 0x6F77, //CJK UNIFIED IDEOGRAPH + 0xE660: 0x6F6A, //CJK UNIFIED IDEOGRAPH + 0xE661: 0x6F7B, //CJK UNIFIED IDEOGRAPH + 0xE662: 0x71B2, //CJK UNIFIED IDEOGRAPH + 0xE663: 0x71AF, //CJK UNIFIED IDEOGRAPH + 0xE664: 0x719B, //CJK UNIFIED IDEOGRAPH + 0xE665: 0x71B0, //CJK UNIFIED IDEOGRAPH + 0xE666: 0x71A0, //CJK UNIFIED IDEOGRAPH + 0xE667: 0x719A, //CJK UNIFIED IDEOGRAPH + 0xE668: 0x71A9, //CJK UNIFIED IDEOGRAPH + 0xE669: 0x71B5, //CJK UNIFIED IDEOGRAPH + 0xE66A: 0x719D, //CJK UNIFIED IDEOGRAPH + 0xE66B: 0x71A5, //CJK UNIFIED IDEOGRAPH + 0xE66C: 0x719E, //CJK UNIFIED IDEOGRAPH + 0xE66D: 0x71A4, //CJK UNIFIED IDEOGRAPH + 0xE66E: 0x71A1, //CJK UNIFIED IDEOGRAPH + 0xE66F: 0x71AA, //CJK UNIFIED IDEOGRAPH + 0xE670: 0x719C, //CJK UNIFIED IDEOGRAPH + 0xE671: 0x71A7, //CJK UNIFIED IDEOGRAPH + 0xE672: 0x71B3, //CJK UNIFIED IDEOGRAPH + 0xE673: 0x7298, //CJK UNIFIED IDEOGRAPH + 0xE674: 0x729A, //CJK UNIFIED IDEOGRAPH + 0xE675: 0x7358, //CJK UNIFIED IDEOGRAPH + 0xE676: 0x7352, //CJK UNIFIED IDEOGRAPH + 0xE677: 0x735E, //CJK UNIFIED IDEOGRAPH + 0xE678: 0x735F, //CJK UNIFIED IDEOGRAPH + 0xE679: 0x7360, //CJK UNIFIED IDEOGRAPH + 0xE67A: 0x735D, //CJK UNIFIED IDEOGRAPH + 0xE67B: 0x735B, //CJK UNIFIED IDEOGRAPH + 0xE67C: 0x7361, //CJK UNIFIED IDEOGRAPH + 0xE67D: 0x735A, //CJK UNIFIED IDEOGRAPH + 0xE67E: 0x7359, //CJK UNIFIED IDEOGRAPH + 0xE6A1: 0x7362, //CJK UNIFIED IDEOGRAPH + 0xE6A2: 0x7487, //CJK UNIFIED IDEOGRAPH + 0xE6A3: 0x7489, //CJK UNIFIED IDEOGRAPH + 0xE6A4: 0x748A, //CJK UNIFIED IDEOGRAPH + 0xE6A5: 0x7486, //CJK UNIFIED IDEOGRAPH + 0xE6A6: 0x7481, //CJK UNIFIED IDEOGRAPH + 0xE6A7: 0x747D, //CJK UNIFIED IDEOGRAPH + 0xE6A8: 0x7485, //CJK UNIFIED IDEOGRAPH + 0xE6A9: 0x7488, //CJK UNIFIED IDEOGRAPH + 0xE6AA: 0x747C, //CJK UNIFIED IDEOGRAPH + 0xE6AB: 0x7479, //CJK UNIFIED IDEOGRAPH + 0xE6AC: 0x7508, //CJK UNIFIED IDEOGRAPH + 0xE6AD: 0x7507, //CJK UNIFIED IDEOGRAPH + 0xE6AE: 0x757E, //CJK UNIFIED IDEOGRAPH + 0xE6AF: 0x7625, //CJK UNIFIED IDEOGRAPH + 0xE6B0: 0x761E, //CJK UNIFIED IDEOGRAPH + 0xE6B1: 0x7619, //CJK UNIFIED IDEOGRAPH + 0xE6B2: 0x761D, //CJK UNIFIED IDEOGRAPH + 0xE6B3: 0x761C, //CJK UNIFIED IDEOGRAPH + 0xE6B4: 0x7623, //CJK UNIFIED IDEOGRAPH + 0xE6B5: 0x761A, //CJK UNIFIED IDEOGRAPH + 0xE6B6: 0x7628, //CJK UNIFIED IDEOGRAPH + 0xE6B7: 0x761B, //CJK UNIFIED IDEOGRAPH + 0xE6B8: 0x769C, //CJK UNIFIED IDEOGRAPH + 0xE6B9: 0x769D, //CJK UNIFIED IDEOGRAPH + 0xE6BA: 0x769E, //CJK UNIFIED IDEOGRAPH + 0xE6BB: 0x769B, //CJK UNIFIED IDEOGRAPH + 0xE6BC: 0x778D, //CJK UNIFIED IDEOGRAPH + 0xE6BD: 0x778F, //CJK UNIFIED IDEOGRAPH + 0xE6BE: 0x7789, //CJK UNIFIED IDEOGRAPH + 0xE6BF: 0x7788, //CJK UNIFIED IDEOGRAPH + 0xE6C0: 0x78CD, //CJK UNIFIED IDEOGRAPH + 0xE6C1: 0x78BB, //CJK UNIFIED IDEOGRAPH + 0xE6C2: 0x78CF, //CJK UNIFIED IDEOGRAPH + 0xE6C3: 0x78CC, //CJK UNIFIED IDEOGRAPH + 0xE6C4: 0x78D1, //CJK UNIFIED IDEOGRAPH + 0xE6C5: 0x78CE, //CJK UNIFIED IDEOGRAPH + 0xE6C6: 0x78D4, //CJK UNIFIED IDEOGRAPH + 0xE6C7: 0x78C8, //CJK UNIFIED IDEOGRAPH + 0xE6C8: 0x78C3, //CJK UNIFIED IDEOGRAPH + 0xE6C9: 0x78C4, //CJK UNIFIED IDEOGRAPH + 0xE6CA: 0x78C9, //CJK UNIFIED IDEOGRAPH + 0xE6CB: 0x799A, //CJK UNIFIED IDEOGRAPH + 0xE6CC: 0x79A1, //CJK UNIFIED IDEOGRAPH + 0xE6CD: 0x79A0, //CJK UNIFIED IDEOGRAPH + 0xE6CE: 0x799C, //CJK UNIFIED IDEOGRAPH + 0xE6CF: 0x79A2, //CJK UNIFIED IDEOGRAPH + 0xE6D0: 0x799B, //CJK UNIFIED IDEOGRAPH + 0xE6D1: 0x6B76, //CJK UNIFIED IDEOGRAPH + 0xE6D2: 0x7A39, //CJK UNIFIED IDEOGRAPH + 0xE6D3: 0x7AB2, //CJK UNIFIED IDEOGRAPH + 0xE6D4: 0x7AB4, //CJK UNIFIED IDEOGRAPH + 0xE6D5: 0x7AB3, //CJK UNIFIED IDEOGRAPH + 0xE6D6: 0x7BB7, //CJK UNIFIED IDEOGRAPH + 0xE6D7: 0x7BCB, //CJK UNIFIED IDEOGRAPH + 0xE6D8: 0x7BBE, //CJK UNIFIED IDEOGRAPH + 0xE6D9: 0x7BAC, //CJK UNIFIED IDEOGRAPH + 0xE6DA: 0x7BCE, //CJK UNIFIED IDEOGRAPH + 0xE6DB: 0x7BAF, //CJK UNIFIED IDEOGRAPH + 0xE6DC: 0x7BB9, //CJK UNIFIED IDEOGRAPH + 0xE6DD: 0x7BCA, //CJK UNIFIED IDEOGRAPH + 0xE6DE: 0x7BB5, //CJK UNIFIED IDEOGRAPH + 0xE6DF: 0x7CC5, //CJK UNIFIED IDEOGRAPH + 0xE6E0: 0x7CC8, //CJK UNIFIED IDEOGRAPH + 0xE6E1: 0x7CCC, //CJK UNIFIED IDEOGRAPH + 0xE6E2: 0x7CCB, //CJK UNIFIED IDEOGRAPH + 0xE6E3: 0x7DF7, //CJK UNIFIED IDEOGRAPH + 0xE6E4: 0x7DDB, //CJK UNIFIED IDEOGRAPH + 0xE6E5: 0x7DEA, //CJK UNIFIED IDEOGRAPH + 0xE6E6: 0x7DE7, //CJK UNIFIED IDEOGRAPH + 0xE6E7: 0x7DD7, //CJK UNIFIED IDEOGRAPH + 0xE6E8: 0x7DE1, //CJK UNIFIED IDEOGRAPH + 0xE6E9: 0x7E03, //CJK UNIFIED IDEOGRAPH + 0xE6EA: 0x7DFA, //CJK UNIFIED IDEOGRAPH + 0xE6EB: 0x7DE6, //CJK UNIFIED IDEOGRAPH + 0xE6EC: 0x7DF6, //CJK UNIFIED IDEOGRAPH + 0xE6ED: 0x7DF1, //CJK UNIFIED IDEOGRAPH + 0xE6EE: 0x7DF0, //CJK UNIFIED IDEOGRAPH + 0xE6EF: 0x7DEE, //CJK UNIFIED IDEOGRAPH + 0xE6F0: 0x7DDF, //CJK UNIFIED IDEOGRAPH + 0xE6F1: 0x7F76, //CJK UNIFIED IDEOGRAPH + 0xE6F2: 0x7FAC, //CJK UNIFIED IDEOGRAPH + 0xE6F3: 0x7FB0, //CJK UNIFIED IDEOGRAPH + 0xE6F4: 0x7FAD, //CJK UNIFIED IDEOGRAPH + 0xE6F5: 0x7FED, //CJK UNIFIED IDEOGRAPH + 0xE6F6: 0x7FEB, //CJK UNIFIED IDEOGRAPH + 0xE6F7: 0x7FEA, //CJK UNIFIED IDEOGRAPH + 0xE6F8: 0x7FEC, //CJK UNIFIED IDEOGRAPH + 0xE6F9: 0x7FE6, //CJK UNIFIED IDEOGRAPH + 0xE6FA: 0x7FE8, //CJK UNIFIED IDEOGRAPH + 0xE6FB: 0x8064, //CJK UNIFIED IDEOGRAPH + 0xE6FC: 0x8067, //CJK UNIFIED IDEOGRAPH + 0xE6FD: 0x81A3, //CJK UNIFIED IDEOGRAPH + 0xE6FE: 0x819F, //CJK UNIFIED IDEOGRAPH + 0xE740: 0x819E, //CJK UNIFIED IDEOGRAPH + 0xE741: 0x8195, //CJK UNIFIED IDEOGRAPH + 0xE742: 0x81A2, //CJK UNIFIED IDEOGRAPH + 0xE743: 0x8199, //CJK UNIFIED IDEOGRAPH + 0xE744: 0x8197, //CJK UNIFIED IDEOGRAPH + 0xE745: 0x8216, //CJK UNIFIED IDEOGRAPH + 0xE746: 0x824F, //CJK UNIFIED IDEOGRAPH + 0xE747: 0x8253, //CJK UNIFIED IDEOGRAPH + 0xE748: 0x8252, //CJK UNIFIED IDEOGRAPH + 0xE749: 0x8250, //CJK UNIFIED IDEOGRAPH + 0xE74A: 0x824E, //CJK UNIFIED IDEOGRAPH + 0xE74B: 0x8251, //CJK UNIFIED IDEOGRAPH + 0xE74C: 0x8524, //CJK UNIFIED IDEOGRAPH + 0xE74D: 0x853B, //CJK UNIFIED IDEOGRAPH + 0xE74E: 0x850F, //CJK UNIFIED IDEOGRAPH + 0xE74F: 0x8500, //CJK UNIFIED IDEOGRAPH + 0xE750: 0x8529, //CJK UNIFIED IDEOGRAPH + 0xE751: 0x850E, //CJK UNIFIED IDEOGRAPH + 0xE752: 0x8509, //CJK UNIFIED IDEOGRAPH + 0xE753: 0x850D, //CJK UNIFIED IDEOGRAPH + 0xE754: 0x851F, //CJK UNIFIED IDEOGRAPH + 0xE755: 0x850A, //CJK UNIFIED IDEOGRAPH + 0xE756: 0x8527, //CJK UNIFIED IDEOGRAPH + 0xE757: 0x851C, //CJK UNIFIED IDEOGRAPH + 0xE758: 0x84FB, //CJK UNIFIED IDEOGRAPH + 0xE759: 0x852B, //CJK UNIFIED IDEOGRAPH + 0xE75A: 0x84FA, //CJK UNIFIED IDEOGRAPH + 0xE75B: 0x8508, //CJK UNIFIED IDEOGRAPH + 0xE75C: 0x850C, //CJK UNIFIED IDEOGRAPH + 0xE75D: 0x84F4, //CJK UNIFIED IDEOGRAPH + 0xE75E: 0x852A, //CJK UNIFIED IDEOGRAPH + 0xE75F: 0x84F2, //CJK UNIFIED IDEOGRAPH + 0xE760: 0x8515, //CJK UNIFIED IDEOGRAPH + 0xE761: 0x84F7, //CJK UNIFIED IDEOGRAPH + 0xE762: 0x84EB, //CJK UNIFIED IDEOGRAPH + 0xE763: 0x84F3, //CJK UNIFIED IDEOGRAPH + 0xE764: 0x84FC, //CJK UNIFIED IDEOGRAPH + 0xE765: 0x8512, //CJK UNIFIED IDEOGRAPH + 0xE766: 0x84EA, //CJK UNIFIED IDEOGRAPH + 0xE767: 0x84E9, //CJK UNIFIED IDEOGRAPH + 0xE768: 0x8516, //CJK UNIFIED IDEOGRAPH + 0xE769: 0x84FE, //CJK UNIFIED IDEOGRAPH + 0xE76A: 0x8528, //CJK UNIFIED IDEOGRAPH + 0xE76B: 0x851D, //CJK UNIFIED IDEOGRAPH + 0xE76C: 0x852E, //CJK UNIFIED IDEOGRAPH + 0xE76D: 0x8502, //CJK UNIFIED IDEOGRAPH + 0xE76E: 0x84FD, //CJK UNIFIED IDEOGRAPH + 0xE76F: 0x851E, //CJK UNIFIED IDEOGRAPH + 0xE770: 0x84F6, //CJK UNIFIED IDEOGRAPH + 0xE771: 0x8531, //CJK UNIFIED IDEOGRAPH + 0xE772: 0x8526, //CJK UNIFIED IDEOGRAPH + 0xE773: 0x84E7, //CJK UNIFIED IDEOGRAPH + 0xE774: 0x84E8, //CJK UNIFIED IDEOGRAPH + 0xE775: 0x84F0, //CJK UNIFIED IDEOGRAPH + 0xE776: 0x84EF, //CJK UNIFIED IDEOGRAPH + 0xE777: 0x84F9, //CJK UNIFIED IDEOGRAPH + 0xE778: 0x8518, //CJK UNIFIED IDEOGRAPH + 0xE779: 0x8520, //CJK UNIFIED IDEOGRAPH + 0xE77A: 0x8530, //CJK UNIFIED IDEOGRAPH + 0xE77B: 0x850B, //CJK UNIFIED IDEOGRAPH + 0xE77C: 0x8519, //CJK UNIFIED IDEOGRAPH + 0xE77D: 0x852F, //CJK UNIFIED IDEOGRAPH + 0xE77E: 0x8662, //CJK UNIFIED IDEOGRAPH + 0xE7A1: 0x8756, //CJK UNIFIED IDEOGRAPH + 0xE7A2: 0x8763, //CJK UNIFIED IDEOGRAPH + 0xE7A3: 0x8764, //CJK UNIFIED IDEOGRAPH + 0xE7A4: 0x8777, //CJK UNIFIED IDEOGRAPH + 0xE7A5: 0x87E1, //CJK UNIFIED IDEOGRAPH + 0xE7A6: 0x8773, //CJK UNIFIED IDEOGRAPH + 0xE7A7: 0x8758, //CJK UNIFIED IDEOGRAPH + 0xE7A8: 0x8754, //CJK UNIFIED IDEOGRAPH + 0xE7A9: 0x875B, //CJK UNIFIED IDEOGRAPH + 0xE7AA: 0x8752, //CJK UNIFIED IDEOGRAPH + 0xE7AB: 0x8761, //CJK UNIFIED IDEOGRAPH + 0xE7AC: 0x875A, //CJK UNIFIED IDEOGRAPH + 0xE7AD: 0x8751, //CJK UNIFIED IDEOGRAPH + 0xE7AE: 0x875E, //CJK UNIFIED IDEOGRAPH + 0xE7AF: 0x876D, //CJK UNIFIED IDEOGRAPH + 0xE7B0: 0x876A, //CJK UNIFIED IDEOGRAPH + 0xE7B1: 0x8750, //CJK UNIFIED IDEOGRAPH + 0xE7B2: 0x874E, //CJK UNIFIED IDEOGRAPH + 0xE7B3: 0x875F, //CJK UNIFIED IDEOGRAPH + 0xE7B4: 0x875D, //CJK UNIFIED IDEOGRAPH + 0xE7B5: 0x876F, //CJK UNIFIED IDEOGRAPH + 0xE7B6: 0x876C, //CJK UNIFIED IDEOGRAPH + 0xE7B7: 0x877A, //CJK UNIFIED IDEOGRAPH + 0xE7B8: 0x876E, //CJK UNIFIED IDEOGRAPH + 0xE7B9: 0x875C, //CJK UNIFIED IDEOGRAPH + 0xE7BA: 0x8765, //CJK UNIFIED IDEOGRAPH + 0xE7BB: 0x874F, //CJK UNIFIED IDEOGRAPH + 0xE7BC: 0x877B, //CJK UNIFIED IDEOGRAPH + 0xE7BD: 0x8775, //CJK UNIFIED IDEOGRAPH + 0xE7BE: 0x8762, //CJK UNIFIED IDEOGRAPH + 0xE7BF: 0x8767, //CJK UNIFIED IDEOGRAPH + 0xE7C0: 0x8769, //CJK UNIFIED IDEOGRAPH + 0xE7C1: 0x885A, //CJK UNIFIED IDEOGRAPH + 0xE7C2: 0x8905, //CJK UNIFIED IDEOGRAPH + 0xE7C3: 0x890C, //CJK UNIFIED IDEOGRAPH + 0xE7C4: 0x8914, //CJK UNIFIED IDEOGRAPH + 0xE7C5: 0x890B, //CJK UNIFIED IDEOGRAPH + 0xE7C6: 0x8917, //CJK UNIFIED IDEOGRAPH + 0xE7C7: 0x8918, //CJK UNIFIED IDEOGRAPH + 0xE7C8: 0x8919, //CJK UNIFIED IDEOGRAPH + 0xE7C9: 0x8906, //CJK UNIFIED IDEOGRAPH + 0xE7CA: 0x8916, //CJK UNIFIED IDEOGRAPH + 0xE7CB: 0x8911, //CJK UNIFIED IDEOGRAPH + 0xE7CC: 0x890E, //CJK UNIFIED IDEOGRAPH + 0xE7CD: 0x8909, //CJK UNIFIED IDEOGRAPH + 0xE7CE: 0x89A2, //CJK UNIFIED IDEOGRAPH + 0xE7CF: 0x89A4, //CJK UNIFIED IDEOGRAPH + 0xE7D0: 0x89A3, //CJK UNIFIED IDEOGRAPH + 0xE7D1: 0x89ED, //CJK UNIFIED IDEOGRAPH + 0xE7D2: 0x89F0, //CJK UNIFIED IDEOGRAPH + 0xE7D3: 0x89EC, //CJK UNIFIED IDEOGRAPH + 0xE7D4: 0x8ACF, //CJK UNIFIED IDEOGRAPH + 0xE7D5: 0x8AC6, //CJK UNIFIED IDEOGRAPH + 0xE7D6: 0x8AB8, //CJK UNIFIED IDEOGRAPH + 0xE7D7: 0x8AD3, //CJK UNIFIED IDEOGRAPH + 0xE7D8: 0x8AD1, //CJK UNIFIED IDEOGRAPH + 0xE7D9: 0x8AD4, //CJK UNIFIED IDEOGRAPH + 0xE7DA: 0x8AD5, //CJK UNIFIED IDEOGRAPH + 0xE7DB: 0x8ABB, //CJK UNIFIED IDEOGRAPH + 0xE7DC: 0x8AD7, //CJK UNIFIED IDEOGRAPH + 0xE7DD: 0x8ABE, //CJK UNIFIED IDEOGRAPH + 0xE7DE: 0x8AC0, //CJK UNIFIED IDEOGRAPH + 0xE7DF: 0x8AC5, //CJK UNIFIED IDEOGRAPH + 0xE7E0: 0x8AD8, //CJK UNIFIED IDEOGRAPH + 0xE7E1: 0x8AC3, //CJK UNIFIED IDEOGRAPH + 0xE7E2: 0x8ABA, //CJK UNIFIED IDEOGRAPH + 0xE7E3: 0x8ABD, //CJK UNIFIED IDEOGRAPH + 0xE7E4: 0x8AD9, //CJK UNIFIED IDEOGRAPH + 0xE7E5: 0x8C3E, //CJK UNIFIED IDEOGRAPH + 0xE7E6: 0x8C4D, //CJK UNIFIED IDEOGRAPH + 0xE7E7: 0x8C8F, //CJK UNIFIED IDEOGRAPH + 0xE7E8: 0x8CE5, //CJK UNIFIED IDEOGRAPH + 0xE7E9: 0x8CDF, //CJK UNIFIED IDEOGRAPH + 0xE7EA: 0x8CD9, //CJK UNIFIED IDEOGRAPH + 0xE7EB: 0x8CE8, //CJK UNIFIED IDEOGRAPH + 0xE7EC: 0x8CDA, //CJK UNIFIED IDEOGRAPH + 0xE7ED: 0x8CDD, //CJK UNIFIED IDEOGRAPH + 0xE7EE: 0x8CE7, //CJK UNIFIED IDEOGRAPH + 0xE7EF: 0x8DA0, //CJK UNIFIED IDEOGRAPH + 0xE7F0: 0x8D9C, //CJK UNIFIED IDEOGRAPH + 0xE7F1: 0x8DA1, //CJK UNIFIED IDEOGRAPH + 0xE7F2: 0x8D9B, //CJK UNIFIED IDEOGRAPH + 0xE7F3: 0x8E20, //CJK UNIFIED IDEOGRAPH + 0xE7F4: 0x8E23, //CJK UNIFIED IDEOGRAPH + 0xE7F5: 0x8E25, //CJK UNIFIED IDEOGRAPH + 0xE7F6: 0x8E24, //CJK UNIFIED IDEOGRAPH + 0xE7F7: 0x8E2E, //CJK UNIFIED IDEOGRAPH + 0xE7F8: 0x8E15, //CJK UNIFIED IDEOGRAPH + 0xE7F9: 0x8E1B, //CJK UNIFIED IDEOGRAPH + 0xE7FA: 0x8E16, //CJK UNIFIED IDEOGRAPH + 0xE7FB: 0x8E11, //CJK UNIFIED IDEOGRAPH + 0xE7FC: 0x8E19, //CJK UNIFIED IDEOGRAPH + 0xE7FD: 0x8E26, //CJK UNIFIED IDEOGRAPH + 0xE7FE: 0x8E27, //CJK UNIFIED IDEOGRAPH + 0xE840: 0x8E14, //CJK UNIFIED IDEOGRAPH + 0xE841: 0x8E12, //CJK UNIFIED IDEOGRAPH + 0xE842: 0x8E18, //CJK UNIFIED IDEOGRAPH + 0xE843: 0x8E13, //CJK UNIFIED IDEOGRAPH + 0xE844: 0x8E1C, //CJK UNIFIED IDEOGRAPH + 0xE845: 0x8E17, //CJK UNIFIED IDEOGRAPH + 0xE846: 0x8E1A, //CJK UNIFIED IDEOGRAPH + 0xE847: 0x8F2C, //CJK UNIFIED IDEOGRAPH + 0xE848: 0x8F24, //CJK UNIFIED IDEOGRAPH + 0xE849: 0x8F18, //CJK UNIFIED IDEOGRAPH + 0xE84A: 0x8F1A, //CJK UNIFIED IDEOGRAPH + 0xE84B: 0x8F20, //CJK UNIFIED IDEOGRAPH + 0xE84C: 0x8F23, //CJK UNIFIED IDEOGRAPH + 0xE84D: 0x8F16, //CJK UNIFIED IDEOGRAPH + 0xE84E: 0x8F17, //CJK UNIFIED IDEOGRAPH + 0xE84F: 0x9073, //CJK UNIFIED IDEOGRAPH + 0xE850: 0x9070, //CJK UNIFIED IDEOGRAPH + 0xE851: 0x906F, //CJK UNIFIED IDEOGRAPH + 0xE852: 0x9067, //CJK UNIFIED IDEOGRAPH + 0xE853: 0x906B, //CJK UNIFIED IDEOGRAPH + 0xE854: 0x912F, //CJK UNIFIED IDEOGRAPH + 0xE855: 0x912B, //CJK UNIFIED IDEOGRAPH + 0xE856: 0x9129, //CJK UNIFIED IDEOGRAPH + 0xE857: 0x912A, //CJK UNIFIED IDEOGRAPH + 0xE858: 0x9132, //CJK UNIFIED IDEOGRAPH + 0xE859: 0x9126, //CJK UNIFIED IDEOGRAPH + 0xE85A: 0x912E, //CJK UNIFIED IDEOGRAPH + 0xE85B: 0x9185, //CJK UNIFIED IDEOGRAPH + 0xE85C: 0x9186, //CJK UNIFIED IDEOGRAPH + 0xE85D: 0x918A, //CJK UNIFIED IDEOGRAPH + 0xE85E: 0x9181, //CJK UNIFIED IDEOGRAPH + 0xE85F: 0x9182, //CJK UNIFIED IDEOGRAPH + 0xE860: 0x9184, //CJK UNIFIED IDEOGRAPH + 0xE861: 0x9180, //CJK UNIFIED IDEOGRAPH + 0xE862: 0x92D0, //CJK UNIFIED IDEOGRAPH + 0xE863: 0x92C3, //CJK UNIFIED IDEOGRAPH + 0xE864: 0x92C4, //CJK UNIFIED IDEOGRAPH + 0xE865: 0x92C0, //CJK UNIFIED IDEOGRAPH + 0xE866: 0x92D9, //CJK UNIFIED IDEOGRAPH + 0xE867: 0x92B6, //CJK UNIFIED IDEOGRAPH + 0xE868: 0x92CF, //CJK UNIFIED IDEOGRAPH + 0xE869: 0x92F1, //CJK UNIFIED IDEOGRAPH + 0xE86A: 0x92DF, //CJK UNIFIED IDEOGRAPH + 0xE86B: 0x92D8, //CJK UNIFIED IDEOGRAPH + 0xE86C: 0x92E9, //CJK UNIFIED IDEOGRAPH + 0xE86D: 0x92D7, //CJK UNIFIED IDEOGRAPH + 0xE86E: 0x92DD, //CJK UNIFIED IDEOGRAPH + 0xE86F: 0x92CC, //CJK UNIFIED IDEOGRAPH + 0xE870: 0x92EF, //CJK UNIFIED IDEOGRAPH + 0xE871: 0x92C2, //CJK UNIFIED IDEOGRAPH + 0xE872: 0x92E8, //CJK UNIFIED IDEOGRAPH + 0xE873: 0x92CA, //CJK UNIFIED IDEOGRAPH + 0xE874: 0x92C8, //CJK UNIFIED IDEOGRAPH + 0xE875: 0x92CE, //CJK UNIFIED IDEOGRAPH + 0xE876: 0x92E6, //CJK UNIFIED IDEOGRAPH + 0xE877: 0x92CD, //CJK UNIFIED IDEOGRAPH + 0xE878: 0x92D5, //CJK UNIFIED IDEOGRAPH + 0xE879: 0x92C9, //CJK UNIFIED IDEOGRAPH + 0xE87A: 0x92E0, //CJK UNIFIED IDEOGRAPH + 0xE87B: 0x92DE, //CJK UNIFIED IDEOGRAPH + 0xE87C: 0x92E7, //CJK UNIFIED IDEOGRAPH + 0xE87D: 0x92D1, //CJK UNIFIED IDEOGRAPH + 0xE87E: 0x92D3, //CJK UNIFIED IDEOGRAPH + 0xE8A1: 0x92B5, //CJK UNIFIED IDEOGRAPH + 0xE8A2: 0x92E1, //CJK UNIFIED IDEOGRAPH + 0xE8A3: 0x92C6, //CJK UNIFIED IDEOGRAPH + 0xE8A4: 0x92B4, //CJK UNIFIED IDEOGRAPH + 0xE8A5: 0x957C, //CJK UNIFIED IDEOGRAPH + 0xE8A6: 0x95AC, //CJK UNIFIED IDEOGRAPH + 0xE8A7: 0x95AB, //CJK UNIFIED IDEOGRAPH + 0xE8A8: 0x95AE, //CJK UNIFIED IDEOGRAPH + 0xE8A9: 0x95B0, //CJK UNIFIED IDEOGRAPH + 0xE8AA: 0x96A4, //CJK UNIFIED IDEOGRAPH + 0xE8AB: 0x96A2, //CJK UNIFIED IDEOGRAPH + 0xE8AC: 0x96D3, //CJK UNIFIED IDEOGRAPH + 0xE8AD: 0x9705, //CJK UNIFIED IDEOGRAPH + 0xE8AE: 0x9708, //CJK UNIFIED IDEOGRAPH + 0xE8AF: 0x9702, //CJK UNIFIED IDEOGRAPH + 0xE8B0: 0x975A, //CJK UNIFIED IDEOGRAPH + 0xE8B1: 0x978A, //CJK UNIFIED IDEOGRAPH + 0xE8B2: 0x978E, //CJK UNIFIED IDEOGRAPH + 0xE8B3: 0x9788, //CJK UNIFIED IDEOGRAPH + 0xE8B4: 0x97D0, //CJK UNIFIED IDEOGRAPH + 0xE8B5: 0x97CF, //CJK UNIFIED IDEOGRAPH + 0xE8B6: 0x981E, //CJK UNIFIED IDEOGRAPH + 0xE8B7: 0x981D, //CJK UNIFIED IDEOGRAPH + 0xE8B8: 0x9826, //CJK UNIFIED IDEOGRAPH + 0xE8B9: 0x9829, //CJK UNIFIED IDEOGRAPH + 0xE8BA: 0x9828, //CJK UNIFIED IDEOGRAPH + 0xE8BB: 0x9820, //CJK UNIFIED IDEOGRAPH + 0xE8BC: 0x981B, //CJK UNIFIED IDEOGRAPH + 0xE8BD: 0x9827, //CJK UNIFIED IDEOGRAPH + 0xE8BE: 0x98B2, //CJK UNIFIED IDEOGRAPH + 0xE8BF: 0x9908, //CJK UNIFIED IDEOGRAPH + 0xE8C0: 0x98FA, //CJK UNIFIED IDEOGRAPH + 0xE8C1: 0x9911, //CJK UNIFIED IDEOGRAPH + 0xE8C2: 0x9914, //CJK UNIFIED IDEOGRAPH + 0xE8C3: 0x9916, //CJK UNIFIED IDEOGRAPH + 0xE8C4: 0x9917, //CJK UNIFIED IDEOGRAPH + 0xE8C5: 0x9915, //CJK UNIFIED IDEOGRAPH + 0xE8C6: 0x99DC, //CJK UNIFIED IDEOGRAPH + 0xE8C7: 0x99CD, //CJK UNIFIED IDEOGRAPH + 0xE8C8: 0x99CF, //CJK UNIFIED IDEOGRAPH + 0xE8C9: 0x99D3, //CJK UNIFIED IDEOGRAPH + 0xE8CA: 0x99D4, //CJK UNIFIED IDEOGRAPH + 0xE8CB: 0x99CE, //CJK UNIFIED IDEOGRAPH + 0xE8CC: 0x99C9, //CJK UNIFIED IDEOGRAPH + 0xE8CD: 0x99D6, //CJK UNIFIED IDEOGRAPH + 0xE8CE: 0x99D8, //CJK UNIFIED IDEOGRAPH + 0xE8CF: 0x99CB, //CJK UNIFIED IDEOGRAPH + 0xE8D0: 0x99D7, //CJK UNIFIED IDEOGRAPH + 0xE8D1: 0x99CC, //CJK UNIFIED IDEOGRAPH + 0xE8D2: 0x9AB3, //CJK UNIFIED IDEOGRAPH + 0xE8D3: 0x9AEC, //CJK UNIFIED IDEOGRAPH + 0xE8D4: 0x9AEB, //CJK UNIFIED IDEOGRAPH + 0xE8D5: 0x9AF3, //CJK UNIFIED IDEOGRAPH + 0xE8D6: 0x9AF2, //CJK UNIFIED IDEOGRAPH + 0xE8D7: 0x9AF1, //CJK UNIFIED IDEOGRAPH + 0xE8D8: 0x9B46, //CJK UNIFIED IDEOGRAPH + 0xE8D9: 0x9B43, //CJK UNIFIED IDEOGRAPH + 0xE8DA: 0x9B67, //CJK UNIFIED IDEOGRAPH + 0xE8DB: 0x9B74, //CJK UNIFIED IDEOGRAPH + 0xE8DC: 0x9B71, //CJK UNIFIED IDEOGRAPH + 0xE8DD: 0x9B66, //CJK UNIFIED IDEOGRAPH + 0xE8DE: 0x9B76, //CJK UNIFIED IDEOGRAPH + 0xE8DF: 0x9B75, //CJK UNIFIED IDEOGRAPH + 0xE8E0: 0x9B70, //CJK UNIFIED IDEOGRAPH + 0xE8E1: 0x9B68, //CJK UNIFIED IDEOGRAPH + 0xE8E2: 0x9B64, //CJK UNIFIED IDEOGRAPH + 0xE8E3: 0x9B6C, //CJK UNIFIED IDEOGRAPH + 0xE8E4: 0x9CFC, //CJK UNIFIED IDEOGRAPH + 0xE8E5: 0x9CFA, //CJK UNIFIED IDEOGRAPH + 0xE8E6: 0x9CFD, //CJK UNIFIED IDEOGRAPH + 0xE8E7: 0x9CFF, //CJK UNIFIED IDEOGRAPH + 0xE8E8: 0x9CF7, //CJK UNIFIED IDEOGRAPH + 0xE8E9: 0x9D07, //CJK UNIFIED IDEOGRAPH + 0xE8EA: 0x9D00, //CJK UNIFIED IDEOGRAPH + 0xE8EB: 0x9CF9, //CJK UNIFIED IDEOGRAPH + 0xE8EC: 0x9CFB, //CJK UNIFIED IDEOGRAPH + 0xE8ED: 0x9D08, //CJK UNIFIED IDEOGRAPH + 0xE8EE: 0x9D05, //CJK UNIFIED IDEOGRAPH + 0xE8EF: 0x9D04, //CJK UNIFIED IDEOGRAPH + 0xE8F0: 0x9E83, //CJK UNIFIED IDEOGRAPH + 0xE8F1: 0x9ED3, //CJK UNIFIED IDEOGRAPH + 0xE8F2: 0x9F0F, //CJK UNIFIED IDEOGRAPH + 0xE8F3: 0x9F10, //CJK UNIFIED IDEOGRAPH + 0xE8F4: 0x511C, //CJK UNIFIED IDEOGRAPH + 0xE8F5: 0x5113, //CJK UNIFIED IDEOGRAPH + 0xE8F6: 0x5117, //CJK UNIFIED IDEOGRAPH + 0xE8F7: 0x511A, //CJK UNIFIED IDEOGRAPH + 0xE8F8: 0x5111, //CJK UNIFIED IDEOGRAPH + 0xE8F9: 0x51DE, //CJK UNIFIED IDEOGRAPH + 0xE8FA: 0x5334, //CJK UNIFIED IDEOGRAPH + 0xE8FB: 0x53E1, //CJK UNIFIED IDEOGRAPH + 0xE8FC: 0x5670, //CJK UNIFIED IDEOGRAPH + 0xE8FD: 0x5660, //CJK UNIFIED IDEOGRAPH + 0xE8FE: 0x566E, //CJK UNIFIED IDEOGRAPH + 0xE940: 0x5673, //CJK UNIFIED IDEOGRAPH + 0xE941: 0x5666, //CJK UNIFIED IDEOGRAPH + 0xE942: 0x5663, //CJK UNIFIED IDEOGRAPH + 0xE943: 0x566D, //CJK UNIFIED IDEOGRAPH + 0xE944: 0x5672, //CJK UNIFIED IDEOGRAPH + 0xE945: 0x565E, //CJK UNIFIED IDEOGRAPH + 0xE946: 0x5677, //CJK UNIFIED IDEOGRAPH + 0xE947: 0x571C, //CJK UNIFIED IDEOGRAPH + 0xE948: 0x571B, //CJK UNIFIED IDEOGRAPH + 0xE949: 0x58C8, //CJK UNIFIED IDEOGRAPH + 0xE94A: 0x58BD, //CJK UNIFIED IDEOGRAPH + 0xE94B: 0x58C9, //CJK UNIFIED IDEOGRAPH + 0xE94C: 0x58BF, //CJK UNIFIED IDEOGRAPH + 0xE94D: 0x58BA, //CJK UNIFIED IDEOGRAPH + 0xE94E: 0x58C2, //CJK UNIFIED IDEOGRAPH + 0xE94F: 0x58BC, //CJK UNIFIED IDEOGRAPH + 0xE950: 0x58C6, //CJK UNIFIED IDEOGRAPH + 0xE951: 0x5B17, //CJK UNIFIED IDEOGRAPH + 0xE952: 0x5B19, //CJK UNIFIED IDEOGRAPH + 0xE953: 0x5B1B, //CJK UNIFIED IDEOGRAPH + 0xE954: 0x5B21, //CJK UNIFIED IDEOGRAPH + 0xE955: 0x5B14, //CJK UNIFIED IDEOGRAPH + 0xE956: 0x5B13, //CJK UNIFIED IDEOGRAPH + 0xE957: 0x5B10, //CJK UNIFIED IDEOGRAPH + 0xE958: 0x5B16, //CJK UNIFIED IDEOGRAPH + 0xE959: 0x5B28, //CJK UNIFIED IDEOGRAPH + 0xE95A: 0x5B1A, //CJK UNIFIED IDEOGRAPH + 0xE95B: 0x5B20, //CJK UNIFIED IDEOGRAPH + 0xE95C: 0x5B1E, //CJK UNIFIED IDEOGRAPH + 0xE95D: 0x5BEF, //CJK UNIFIED IDEOGRAPH + 0xE95E: 0x5DAC, //CJK UNIFIED IDEOGRAPH + 0xE95F: 0x5DB1, //CJK UNIFIED IDEOGRAPH + 0xE960: 0x5DA9, //CJK UNIFIED IDEOGRAPH + 0xE961: 0x5DA7, //CJK UNIFIED IDEOGRAPH + 0xE962: 0x5DB5, //CJK UNIFIED IDEOGRAPH + 0xE963: 0x5DB0, //CJK UNIFIED IDEOGRAPH + 0xE964: 0x5DAE, //CJK UNIFIED IDEOGRAPH + 0xE965: 0x5DAA, //CJK UNIFIED IDEOGRAPH + 0xE966: 0x5DA8, //CJK UNIFIED IDEOGRAPH + 0xE967: 0x5DB2, //CJK UNIFIED IDEOGRAPH + 0xE968: 0x5DAD, //CJK UNIFIED IDEOGRAPH + 0xE969: 0x5DAF, //CJK UNIFIED IDEOGRAPH + 0xE96A: 0x5DB4, //CJK UNIFIED IDEOGRAPH + 0xE96B: 0x5E67, //CJK UNIFIED IDEOGRAPH + 0xE96C: 0x5E68, //CJK UNIFIED IDEOGRAPH + 0xE96D: 0x5E66, //CJK UNIFIED IDEOGRAPH + 0xE96E: 0x5E6F, //CJK UNIFIED IDEOGRAPH + 0xE96F: 0x5EE9, //CJK UNIFIED IDEOGRAPH + 0xE970: 0x5EE7, //CJK UNIFIED IDEOGRAPH + 0xE971: 0x5EE6, //CJK UNIFIED IDEOGRAPH + 0xE972: 0x5EE8, //CJK UNIFIED IDEOGRAPH + 0xE973: 0x5EE5, //CJK UNIFIED IDEOGRAPH + 0xE974: 0x5F4B, //CJK UNIFIED IDEOGRAPH + 0xE975: 0x5FBC, //CJK UNIFIED IDEOGRAPH + 0xE976: 0x619D, //CJK UNIFIED IDEOGRAPH + 0xE977: 0x61A8, //CJK UNIFIED IDEOGRAPH + 0xE978: 0x6196, //CJK UNIFIED IDEOGRAPH + 0xE979: 0x61C5, //CJK UNIFIED IDEOGRAPH + 0xE97A: 0x61B4, //CJK UNIFIED IDEOGRAPH + 0xE97B: 0x61C6, //CJK UNIFIED IDEOGRAPH + 0xE97C: 0x61C1, //CJK UNIFIED IDEOGRAPH + 0xE97D: 0x61CC, //CJK UNIFIED IDEOGRAPH + 0xE97E: 0x61BA, //CJK UNIFIED IDEOGRAPH + 0xE9A1: 0x61BF, //CJK UNIFIED IDEOGRAPH + 0xE9A2: 0x61B8, //CJK UNIFIED IDEOGRAPH + 0xE9A3: 0x618C, //CJK UNIFIED IDEOGRAPH + 0xE9A4: 0x64D7, //CJK UNIFIED IDEOGRAPH + 0xE9A5: 0x64D6, //CJK UNIFIED IDEOGRAPH + 0xE9A6: 0x64D0, //CJK UNIFIED IDEOGRAPH + 0xE9A7: 0x64CF, //CJK UNIFIED IDEOGRAPH + 0xE9A8: 0x64C9, //CJK UNIFIED IDEOGRAPH + 0xE9A9: 0x64BD, //CJK UNIFIED IDEOGRAPH + 0xE9AA: 0x6489, //CJK UNIFIED IDEOGRAPH + 0xE9AB: 0x64C3, //CJK UNIFIED IDEOGRAPH + 0xE9AC: 0x64DB, //CJK UNIFIED IDEOGRAPH + 0xE9AD: 0x64F3, //CJK UNIFIED IDEOGRAPH + 0xE9AE: 0x64D9, //CJK UNIFIED IDEOGRAPH + 0xE9AF: 0x6533, //CJK UNIFIED IDEOGRAPH + 0xE9B0: 0x657F, //CJK UNIFIED IDEOGRAPH + 0xE9B1: 0x657C, //CJK UNIFIED IDEOGRAPH + 0xE9B2: 0x65A2, //CJK UNIFIED IDEOGRAPH + 0xE9B3: 0x66C8, //CJK UNIFIED IDEOGRAPH + 0xE9B4: 0x66BE, //CJK UNIFIED IDEOGRAPH + 0xE9B5: 0x66C0, //CJK UNIFIED IDEOGRAPH + 0xE9B6: 0x66CA, //CJK UNIFIED IDEOGRAPH + 0xE9B7: 0x66CB, //CJK UNIFIED IDEOGRAPH + 0xE9B8: 0x66CF, //CJK UNIFIED IDEOGRAPH + 0xE9B9: 0x66BD, //CJK UNIFIED IDEOGRAPH + 0xE9BA: 0x66BB, //CJK UNIFIED IDEOGRAPH + 0xE9BB: 0x66BA, //CJK UNIFIED IDEOGRAPH + 0xE9BC: 0x66CC, //CJK UNIFIED IDEOGRAPH + 0xE9BD: 0x6723, //CJK UNIFIED IDEOGRAPH + 0xE9BE: 0x6A34, //CJK UNIFIED IDEOGRAPH + 0xE9BF: 0x6A66, //CJK UNIFIED IDEOGRAPH + 0xE9C0: 0x6A49, //CJK UNIFIED IDEOGRAPH + 0xE9C1: 0x6A67, //CJK UNIFIED IDEOGRAPH + 0xE9C2: 0x6A32, //CJK UNIFIED IDEOGRAPH + 0xE9C3: 0x6A68, //CJK UNIFIED IDEOGRAPH + 0xE9C4: 0x6A3E, //CJK UNIFIED IDEOGRAPH + 0xE9C5: 0x6A5D, //CJK UNIFIED IDEOGRAPH + 0xE9C6: 0x6A6D, //CJK UNIFIED IDEOGRAPH + 0xE9C7: 0x6A76, //CJK UNIFIED IDEOGRAPH + 0xE9C8: 0x6A5B, //CJK UNIFIED IDEOGRAPH + 0xE9C9: 0x6A51, //CJK UNIFIED IDEOGRAPH + 0xE9CA: 0x6A28, //CJK UNIFIED IDEOGRAPH + 0xE9CB: 0x6A5A, //CJK UNIFIED IDEOGRAPH + 0xE9CC: 0x6A3B, //CJK UNIFIED IDEOGRAPH + 0xE9CD: 0x6A3F, //CJK UNIFIED IDEOGRAPH + 0xE9CE: 0x6A41, //CJK UNIFIED IDEOGRAPH + 0xE9CF: 0x6A6A, //CJK UNIFIED IDEOGRAPH + 0xE9D0: 0x6A64, //CJK UNIFIED IDEOGRAPH + 0xE9D1: 0x6A50, //CJK UNIFIED IDEOGRAPH + 0xE9D2: 0x6A4F, //CJK UNIFIED IDEOGRAPH + 0xE9D3: 0x6A54, //CJK UNIFIED IDEOGRAPH + 0xE9D4: 0x6A6F, //CJK UNIFIED IDEOGRAPH + 0xE9D5: 0x6A69, //CJK UNIFIED IDEOGRAPH + 0xE9D6: 0x6A60, //CJK UNIFIED IDEOGRAPH + 0xE9D7: 0x6A3C, //CJK UNIFIED IDEOGRAPH + 0xE9D8: 0x6A5E, //CJK UNIFIED IDEOGRAPH + 0xE9D9: 0x6A56, //CJK UNIFIED IDEOGRAPH + 0xE9DA: 0x6A55, //CJK UNIFIED IDEOGRAPH + 0xE9DB: 0x6A4D, //CJK UNIFIED IDEOGRAPH + 0xE9DC: 0x6A4E, //CJK UNIFIED IDEOGRAPH + 0xE9DD: 0x6A46, //CJK UNIFIED IDEOGRAPH + 0xE9DE: 0x6B55, //CJK UNIFIED IDEOGRAPH + 0xE9DF: 0x6B54, //CJK UNIFIED IDEOGRAPH + 0xE9E0: 0x6B56, //CJK UNIFIED IDEOGRAPH + 0xE9E1: 0x6BA7, //CJK UNIFIED IDEOGRAPH + 0xE9E2: 0x6BAA, //CJK UNIFIED IDEOGRAPH + 0xE9E3: 0x6BAB, //CJK UNIFIED IDEOGRAPH + 0xE9E4: 0x6BC8, //CJK UNIFIED IDEOGRAPH + 0xE9E5: 0x6BC7, //CJK UNIFIED IDEOGRAPH + 0xE9E6: 0x6C04, //CJK UNIFIED IDEOGRAPH + 0xE9E7: 0x6C03, //CJK UNIFIED IDEOGRAPH + 0xE9E8: 0x6C06, //CJK UNIFIED IDEOGRAPH + 0xE9E9: 0x6FAD, //CJK UNIFIED IDEOGRAPH + 0xE9EA: 0x6FCB, //CJK UNIFIED IDEOGRAPH + 0xE9EB: 0x6FA3, //CJK UNIFIED IDEOGRAPH + 0xE9EC: 0x6FC7, //CJK UNIFIED IDEOGRAPH + 0xE9ED: 0x6FBC, //CJK UNIFIED IDEOGRAPH + 0xE9EE: 0x6FCE, //CJK UNIFIED IDEOGRAPH + 0xE9EF: 0x6FC8, //CJK UNIFIED IDEOGRAPH + 0xE9F0: 0x6F5E, //CJK UNIFIED IDEOGRAPH + 0xE9F1: 0x6FC4, //CJK UNIFIED IDEOGRAPH + 0xE9F2: 0x6FBD, //CJK UNIFIED IDEOGRAPH + 0xE9F3: 0x6F9E, //CJK UNIFIED IDEOGRAPH + 0xE9F4: 0x6FCA, //CJK UNIFIED IDEOGRAPH + 0xE9F5: 0x6FA8, //CJK UNIFIED IDEOGRAPH + 0xE9F6: 0x7004, //CJK UNIFIED IDEOGRAPH + 0xE9F7: 0x6FA5, //CJK UNIFIED IDEOGRAPH + 0xE9F8: 0x6FAE, //CJK UNIFIED IDEOGRAPH + 0xE9F9: 0x6FBA, //CJK UNIFIED IDEOGRAPH + 0xE9FA: 0x6FAC, //CJK UNIFIED IDEOGRAPH + 0xE9FB: 0x6FAA, //CJK UNIFIED IDEOGRAPH + 0xE9FC: 0x6FCF, //CJK UNIFIED IDEOGRAPH + 0xE9FD: 0x6FBF, //CJK UNIFIED IDEOGRAPH + 0xE9FE: 0x6FB8, //CJK UNIFIED IDEOGRAPH + 0xEA40: 0x6FA2, //CJK UNIFIED IDEOGRAPH + 0xEA41: 0x6FC9, //CJK UNIFIED IDEOGRAPH + 0xEA42: 0x6FAB, //CJK UNIFIED IDEOGRAPH + 0xEA43: 0x6FCD, //CJK UNIFIED IDEOGRAPH + 0xEA44: 0x6FAF, //CJK UNIFIED IDEOGRAPH + 0xEA45: 0x6FB2, //CJK UNIFIED IDEOGRAPH + 0xEA46: 0x6FB0, //CJK UNIFIED IDEOGRAPH + 0xEA47: 0x71C5, //CJK UNIFIED IDEOGRAPH + 0xEA48: 0x71C2, //CJK UNIFIED IDEOGRAPH + 0xEA49: 0x71BF, //CJK UNIFIED IDEOGRAPH + 0xEA4A: 0x71B8, //CJK UNIFIED IDEOGRAPH + 0xEA4B: 0x71D6, //CJK UNIFIED IDEOGRAPH + 0xEA4C: 0x71C0, //CJK UNIFIED IDEOGRAPH + 0xEA4D: 0x71C1, //CJK UNIFIED IDEOGRAPH + 0xEA4E: 0x71CB, //CJK UNIFIED IDEOGRAPH + 0xEA4F: 0x71D4, //CJK UNIFIED IDEOGRAPH + 0xEA50: 0x71CA, //CJK UNIFIED IDEOGRAPH + 0xEA51: 0x71C7, //CJK UNIFIED IDEOGRAPH + 0xEA52: 0x71CF, //CJK UNIFIED IDEOGRAPH + 0xEA53: 0x71BD, //CJK UNIFIED IDEOGRAPH + 0xEA54: 0x71D8, //CJK UNIFIED IDEOGRAPH + 0xEA55: 0x71BC, //CJK UNIFIED IDEOGRAPH + 0xEA56: 0x71C6, //CJK UNIFIED IDEOGRAPH + 0xEA57: 0x71DA, //CJK UNIFIED IDEOGRAPH + 0xEA58: 0x71DB, //CJK UNIFIED IDEOGRAPH + 0xEA59: 0x729D, //CJK UNIFIED IDEOGRAPH + 0xEA5A: 0x729E, //CJK UNIFIED IDEOGRAPH + 0xEA5B: 0x7369, //CJK UNIFIED IDEOGRAPH + 0xEA5C: 0x7366, //CJK UNIFIED IDEOGRAPH + 0xEA5D: 0x7367, //CJK UNIFIED IDEOGRAPH + 0xEA5E: 0x736C, //CJK UNIFIED IDEOGRAPH + 0xEA5F: 0x7365, //CJK UNIFIED IDEOGRAPH + 0xEA60: 0x736B, //CJK UNIFIED IDEOGRAPH + 0xEA61: 0x736A, //CJK UNIFIED IDEOGRAPH + 0xEA62: 0x747F, //CJK UNIFIED IDEOGRAPH + 0xEA63: 0x749A, //CJK UNIFIED IDEOGRAPH + 0xEA64: 0x74A0, //CJK UNIFIED IDEOGRAPH + 0xEA65: 0x7494, //CJK UNIFIED IDEOGRAPH + 0xEA66: 0x7492, //CJK UNIFIED IDEOGRAPH + 0xEA67: 0x7495, //CJK UNIFIED IDEOGRAPH + 0xEA68: 0x74A1, //CJK UNIFIED IDEOGRAPH + 0xEA69: 0x750B, //CJK UNIFIED IDEOGRAPH + 0xEA6A: 0x7580, //CJK UNIFIED IDEOGRAPH + 0xEA6B: 0x762F, //CJK UNIFIED IDEOGRAPH + 0xEA6C: 0x762D, //CJK UNIFIED IDEOGRAPH + 0xEA6D: 0x7631, //CJK UNIFIED IDEOGRAPH + 0xEA6E: 0x763D, //CJK UNIFIED IDEOGRAPH + 0xEA6F: 0x7633, //CJK UNIFIED IDEOGRAPH + 0xEA70: 0x763C, //CJK UNIFIED IDEOGRAPH + 0xEA71: 0x7635, //CJK UNIFIED IDEOGRAPH + 0xEA72: 0x7632, //CJK UNIFIED IDEOGRAPH + 0xEA73: 0x7630, //CJK UNIFIED IDEOGRAPH + 0xEA74: 0x76BB, //CJK UNIFIED IDEOGRAPH + 0xEA75: 0x76E6, //CJK UNIFIED IDEOGRAPH + 0xEA76: 0x779A, //CJK UNIFIED IDEOGRAPH + 0xEA77: 0x779D, //CJK UNIFIED IDEOGRAPH + 0xEA78: 0x77A1, //CJK UNIFIED IDEOGRAPH + 0xEA79: 0x779C, //CJK UNIFIED IDEOGRAPH + 0xEA7A: 0x779B, //CJK UNIFIED IDEOGRAPH + 0xEA7B: 0x77A2, //CJK UNIFIED IDEOGRAPH + 0xEA7C: 0x77A3, //CJK UNIFIED IDEOGRAPH + 0xEA7D: 0x7795, //CJK UNIFIED IDEOGRAPH + 0xEA7E: 0x7799, //CJK UNIFIED IDEOGRAPH + 0xEAA1: 0x7797, //CJK UNIFIED IDEOGRAPH + 0xEAA2: 0x78DD, //CJK UNIFIED IDEOGRAPH + 0xEAA3: 0x78E9, //CJK UNIFIED IDEOGRAPH + 0xEAA4: 0x78E5, //CJK UNIFIED IDEOGRAPH + 0xEAA5: 0x78EA, //CJK UNIFIED IDEOGRAPH + 0xEAA6: 0x78DE, //CJK UNIFIED IDEOGRAPH + 0xEAA7: 0x78E3, //CJK UNIFIED IDEOGRAPH + 0xEAA8: 0x78DB, //CJK UNIFIED IDEOGRAPH + 0xEAA9: 0x78E1, //CJK UNIFIED IDEOGRAPH + 0xEAAA: 0x78E2, //CJK UNIFIED IDEOGRAPH + 0xEAAB: 0x78ED, //CJK UNIFIED IDEOGRAPH + 0xEAAC: 0x78DF, //CJK UNIFIED IDEOGRAPH + 0xEAAD: 0x78E0, //CJK UNIFIED IDEOGRAPH + 0xEAAE: 0x79A4, //CJK UNIFIED IDEOGRAPH + 0xEAAF: 0x7A44, //CJK UNIFIED IDEOGRAPH + 0xEAB0: 0x7A48, //CJK UNIFIED IDEOGRAPH + 0xEAB1: 0x7A47, //CJK UNIFIED IDEOGRAPH + 0xEAB2: 0x7AB6, //CJK UNIFIED IDEOGRAPH + 0xEAB3: 0x7AB8, //CJK UNIFIED IDEOGRAPH + 0xEAB4: 0x7AB5, //CJK UNIFIED IDEOGRAPH + 0xEAB5: 0x7AB1, //CJK UNIFIED IDEOGRAPH + 0xEAB6: 0x7AB7, //CJK UNIFIED IDEOGRAPH + 0xEAB7: 0x7BDE, //CJK UNIFIED IDEOGRAPH + 0xEAB8: 0x7BE3, //CJK UNIFIED IDEOGRAPH + 0xEAB9: 0x7BE7, //CJK UNIFIED IDEOGRAPH + 0xEABA: 0x7BDD, //CJK UNIFIED IDEOGRAPH + 0xEABB: 0x7BD5, //CJK UNIFIED IDEOGRAPH + 0xEABC: 0x7BE5, //CJK UNIFIED IDEOGRAPH + 0xEABD: 0x7BDA, //CJK UNIFIED IDEOGRAPH + 0xEABE: 0x7BE8, //CJK UNIFIED IDEOGRAPH + 0xEABF: 0x7BF9, //CJK UNIFIED IDEOGRAPH + 0xEAC0: 0x7BD4, //CJK UNIFIED IDEOGRAPH + 0xEAC1: 0x7BEA, //CJK UNIFIED IDEOGRAPH + 0xEAC2: 0x7BE2, //CJK UNIFIED IDEOGRAPH + 0xEAC3: 0x7BDC, //CJK UNIFIED IDEOGRAPH + 0xEAC4: 0x7BEB, //CJK UNIFIED IDEOGRAPH + 0xEAC5: 0x7BD8, //CJK UNIFIED IDEOGRAPH + 0xEAC6: 0x7BDF, //CJK UNIFIED IDEOGRAPH + 0xEAC7: 0x7CD2, //CJK UNIFIED IDEOGRAPH + 0xEAC8: 0x7CD4, //CJK UNIFIED IDEOGRAPH + 0xEAC9: 0x7CD7, //CJK UNIFIED IDEOGRAPH + 0xEACA: 0x7CD0, //CJK UNIFIED IDEOGRAPH + 0xEACB: 0x7CD1, //CJK UNIFIED IDEOGRAPH + 0xEACC: 0x7E12, //CJK UNIFIED IDEOGRAPH + 0xEACD: 0x7E21, //CJK UNIFIED IDEOGRAPH + 0xEACE: 0x7E17, //CJK UNIFIED IDEOGRAPH + 0xEACF: 0x7E0C, //CJK UNIFIED IDEOGRAPH + 0xEAD0: 0x7E1F, //CJK UNIFIED IDEOGRAPH + 0xEAD1: 0x7E20, //CJK UNIFIED IDEOGRAPH + 0xEAD2: 0x7E13, //CJK UNIFIED IDEOGRAPH + 0xEAD3: 0x7E0E, //CJK UNIFIED IDEOGRAPH + 0xEAD4: 0x7E1C, //CJK UNIFIED IDEOGRAPH + 0xEAD5: 0x7E15, //CJK UNIFIED IDEOGRAPH + 0xEAD6: 0x7E1A, //CJK UNIFIED IDEOGRAPH + 0xEAD7: 0x7E22, //CJK UNIFIED IDEOGRAPH + 0xEAD8: 0x7E0B, //CJK UNIFIED IDEOGRAPH + 0xEAD9: 0x7E0F, //CJK UNIFIED IDEOGRAPH + 0xEADA: 0x7E16, //CJK UNIFIED IDEOGRAPH + 0xEADB: 0x7E0D, //CJK UNIFIED IDEOGRAPH + 0xEADC: 0x7E14, //CJK UNIFIED IDEOGRAPH + 0xEADD: 0x7E25, //CJK UNIFIED IDEOGRAPH + 0xEADE: 0x7E24, //CJK UNIFIED IDEOGRAPH + 0xEADF: 0x7F43, //CJK UNIFIED IDEOGRAPH + 0xEAE0: 0x7F7B, //CJK UNIFIED IDEOGRAPH + 0xEAE1: 0x7F7C, //CJK UNIFIED IDEOGRAPH + 0xEAE2: 0x7F7A, //CJK UNIFIED IDEOGRAPH + 0xEAE3: 0x7FB1, //CJK UNIFIED IDEOGRAPH + 0xEAE4: 0x7FEF, //CJK UNIFIED IDEOGRAPH + 0xEAE5: 0x802A, //CJK UNIFIED IDEOGRAPH + 0xEAE6: 0x8029, //CJK UNIFIED IDEOGRAPH + 0xEAE7: 0x806C, //CJK UNIFIED IDEOGRAPH + 0xEAE8: 0x81B1, //CJK UNIFIED IDEOGRAPH + 0xEAE9: 0x81A6, //CJK UNIFIED IDEOGRAPH + 0xEAEA: 0x81AE, //CJK UNIFIED IDEOGRAPH + 0xEAEB: 0x81B9, //CJK UNIFIED IDEOGRAPH + 0xEAEC: 0x81B5, //CJK UNIFIED IDEOGRAPH + 0xEAED: 0x81AB, //CJK UNIFIED IDEOGRAPH + 0xEAEE: 0x81B0, //CJK UNIFIED IDEOGRAPH + 0xEAEF: 0x81AC, //CJK UNIFIED IDEOGRAPH + 0xEAF0: 0x81B4, //CJK UNIFIED IDEOGRAPH + 0xEAF1: 0x81B2, //CJK UNIFIED IDEOGRAPH + 0xEAF2: 0x81B7, //CJK UNIFIED IDEOGRAPH + 0xEAF3: 0x81A7, //CJK UNIFIED IDEOGRAPH + 0xEAF4: 0x81F2, //CJK UNIFIED IDEOGRAPH + 0xEAF5: 0x8255, //CJK UNIFIED IDEOGRAPH + 0xEAF6: 0x8256, //CJK UNIFIED IDEOGRAPH + 0xEAF7: 0x8257, //CJK UNIFIED IDEOGRAPH + 0xEAF8: 0x8556, //CJK UNIFIED IDEOGRAPH + 0xEAF9: 0x8545, //CJK UNIFIED IDEOGRAPH + 0xEAFA: 0x856B, //CJK UNIFIED IDEOGRAPH + 0xEAFB: 0x854D, //CJK UNIFIED IDEOGRAPH + 0xEAFC: 0x8553, //CJK UNIFIED IDEOGRAPH + 0xEAFD: 0x8561, //CJK UNIFIED IDEOGRAPH + 0xEAFE: 0x8558, //CJK UNIFIED IDEOGRAPH + 0xEB40: 0x8540, //CJK UNIFIED IDEOGRAPH + 0xEB41: 0x8546, //CJK UNIFIED IDEOGRAPH + 0xEB42: 0x8564, //CJK UNIFIED IDEOGRAPH + 0xEB43: 0x8541, //CJK UNIFIED IDEOGRAPH + 0xEB44: 0x8562, //CJK UNIFIED IDEOGRAPH + 0xEB45: 0x8544, //CJK UNIFIED IDEOGRAPH + 0xEB46: 0x8551, //CJK UNIFIED IDEOGRAPH + 0xEB47: 0x8547, //CJK UNIFIED IDEOGRAPH + 0xEB48: 0x8563, //CJK UNIFIED IDEOGRAPH + 0xEB49: 0x853E, //CJK UNIFIED IDEOGRAPH + 0xEB4A: 0x855B, //CJK UNIFIED IDEOGRAPH + 0xEB4B: 0x8571, //CJK UNIFIED IDEOGRAPH + 0xEB4C: 0x854E, //CJK UNIFIED IDEOGRAPH + 0xEB4D: 0x856E, //CJK UNIFIED IDEOGRAPH + 0xEB4E: 0x8575, //CJK UNIFIED IDEOGRAPH + 0xEB4F: 0x8555, //CJK UNIFIED IDEOGRAPH + 0xEB50: 0x8567, //CJK UNIFIED IDEOGRAPH + 0xEB51: 0x8560, //CJK UNIFIED IDEOGRAPH + 0xEB52: 0x858C, //CJK UNIFIED IDEOGRAPH + 0xEB53: 0x8566, //CJK UNIFIED IDEOGRAPH + 0xEB54: 0x855D, //CJK UNIFIED IDEOGRAPH + 0xEB55: 0x8554, //CJK UNIFIED IDEOGRAPH + 0xEB56: 0x8565, //CJK UNIFIED IDEOGRAPH + 0xEB57: 0x856C, //CJK UNIFIED IDEOGRAPH + 0xEB58: 0x8663, //CJK UNIFIED IDEOGRAPH + 0xEB59: 0x8665, //CJK UNIFIED IDEOGRAPH + 0xEB5A: 0x8664, //CJK UNIFIED IDEOGRAPH + 0xEB5B: 0x879B, //CJK UNIFIED IDEOGRAPH + 0xEB5C: 0x878F, //CJK UNIFIED IDEOGRAPH + 0xEB5D: 0x8797, //CJK UNIFIED IDEOGRAPH + 0xEB5E: 0x8793, //CJK UNIFIED IDEOGRAPH + 0xEB5F: 0x8792, //CJK UNIFIED IDEOGRAPH + 0xEB60: 0x8788, //CJK UNIFIED IDEOGRAPH + 0xEB61: 0x8781, //CJK UNIFIED IDEOGRAPH + 0xEB62: 0x8796, //CJK UNIFIED IDEOGRAPH + 0xEB63: 0x8798, //CJK UNIFIED IDEOGRAPH + 0xEB64: 0x8779, //CJK UNIFIED IDEOGRAPH + 0xEB65: 0x8787, //CJK UNIFIED IDEOGRAPH + 0xEB66: 0x87A3, //CJK UNIFIED IDEOGRAPH + 0xEB67: 0x8785, //CJK UNIFIED IDEOGRAPH + 0xEB68: 0x8790, //CJK UNIFIED IDEOGRAPH + 0xEB69: 0x8791, //CJK UNIFIED IDEOGRAPH + 0xEB6A: 0x879D, //CJK UNIFIED IDEOGRAPH + 0xEB6B: 0x8784, //CJK UNIFIED IDEOGRAPH + 0xEB6C: 0x8794, //CJK UNIFIED IDEOGRAPH + 0xEB6D: 0x879C, //CJK UNIFIED IDEOGRAPH + 0xEB6E: 0x879A, //CJK UNIFIED IDEOGRAPH + 0xEB6F: 0x8789, //CJK UNIFIED IDEOGRAPH + 0xEB70: 0x891E, //CJK UNIFIED IDEOGRAPH + 0xEB71: 0x8926, //CJK UNIFIED IDEOGRAPH + 0xEB72: 0x8930, //CJK UNIFIED IDEOGRAPH + 0xEB73: 0x892D, //CJK UNIFIED IDEOGRAPH + 0xEB74: 0x892E, //CJK UNIFIED IDEOGRAPH + 0xEB75: 0x8927, //CJK UNIFIED IDEOGRAPH + 0xEB76: 0x8931, //CJK UNIFIED IDEOGRAPH + 0xEB77: 0x8922, //CJK UNIFIED IDEOGRAPH + 0xEB78: 0x8929, //CJK UNIFIED IDEOGRAPH + 0xEB79: 0x8923, //CJK UNIFIED IDEOGRAPH + 0xEB7A: 0x892F, //CJK UNIFIED IDEOGRAPH + 0xEB7B: 0x892C, //CJK UNIFIED IDEOGRAPH + 0xEB7C: 0x891F, //CJK UNIFIED IDEOGRAPH + 0xEB7D: 0x89F1, //CJK UNIFIED IDEOGRAPH + 0xEB7E: 0x8AE0, //CJK UNIFIED IDEOGRAPH + 0xEBA1: 0x8AE2, //CJK UNIFIED IDEOGRAPH + 0xEBA2: 0x8AF2, //CJK UNIFIED IDEOGRAPH + 0xEBA3: 0x8AF4, //CJK UNIFIED IDEOGRAPH + 0xEBA4: 0x8AF5, //CJK UNIFIED IDEOGRAPH + 0xEBA5: 0x8ADD, //CJK UNIFIED IDEOGRAPH + 0xEBA6: 0x8B14, //CJK UNIFIED IDEOGRAPH + 0xEBA7: 0x8AE4, //CJK UNIFIED IDEOGRAPH + 0xEBA8: 0x8ADF, //CJK UNIFIED IDEOGRAPH + 0xEBA9: 0x8AF0, //CJK UNIFIED IDEOGRAPH + 0xEBAA: 0x8AC8, //CJK UNIFIED IDEOGRAPH + 0xEBAB: 0x8ADE, //CJK UNIFIED IDEOGRAPH + 0xEBAC: 0x8AE1, //CJK UNIFIED IDEOGRAPH + 0xEBAD: 0x8AE8, //CJK UNIFIED IDEOGRAPH + 0xEBAE: 0x8AFF, //CJK UNIFIED IDEOGRAPH + 0xEBAF: 0x8AEF, //CJK UNIFIED IDEOGRAPH + 0xEBB0: 0x8AFB, //CJK UNIFIED IDEOGRAPH + 0xEBB1: 0x8C91, //CJK UNIFIED IDEOGRAPH + 0xEBB2: 0x8C92, //CJK UNIFIED IDEOGRAPH + 0xEBB3: 0x8C90, //CJK UNIFIED IDEOGRAPH + 0xEBB4: 0x8CF5, //CJK UNIFIED IDEOGRAPH + 0xEBB5: 0x8CEE, //CJK UNIFIED IDEOGRAPH + 0xEBB6: 0x8CF1, //CJK UNIFIED IDEOGRAPH + 0xEBB7: 0x8CF0, //CJK UNIFIED IDEOGRAPH + 0xEBB8: 0x8CF3, //CJK UNIFIED IDEOGRAPH + 0xEBB9: 0x8D6C, //CJK UNIFIED IDEOGRAPH + 0xEBBA: 0x8D6E, //CJK UNIFIED IDEOGRAPH + 0xEBBB: 0x8DA5, //CJK UNIFIED IDEOGRAPH + 0xEBBC: 0x8DA7, //CJK UNIFIED IDEOGRAPH + 0xEBBD: 0x8E33, //CJK UNIFIED IDEOGRAPH + 0xEBBE: 0x8E3E, //CJK UNIFIED IDEOGRAPH + 0xEBBF: 0x8E38, //CJK UNIFIED IDEOGRAPH + 0xEBC0: 0x8E40, //CJK UNIFIED IDEOGRAPH + 0xEBC1: 0x8E45, //CJK UNIFIED IDEOGRAPH + 0xEBC2: 0x8E36, //CJK UNIFIED IDEOGRAPH + 0xEBC3: 0x8E3C, //CJK UNIFIED IDEOGRAPH + 0xEBC4: 0x8E3D, //CJK UNIFIED IDEOGRAPH + 0xEBC5: 0x8E41, //CJK UNIFIED IDEOGRAPH + 0xEBC6: 0x8E30, //CJK UNIFIED IDEOGRAPH + 0xEBC7: 0x8E3F, //CJK UNIFIED IDEOGRAPH + 0xEBC8: 0x8EBD, //CJK UNIFIED IDEOGRAPH + 0xEBC9: 0x8F36, //CJK UNIFIED IDEOGRAPH + 0xEBCA: 0x8F2E, //CJK UNIFIED IDEOGRAPH + 0xEBCB: 0x8F35, //CJK UNIFIED IDEOGRAPH + 0xEBCC: 0x8F32, //CJK UNIFIED IDEOGRAPH + 0xEBCD: 0x8F39, //CJK UNIFIED IDEOGRAPH + 0xEBCE: 0x8F37, //CJK UNIFIED IDEOGRAPH + 0xEBCF: 0x8F34, //CJK UNIFIED IDEOGRAPH + 0xEBD0: 0x9076, //CJK UNIFIED IDEOGRAPH + 0xEBD1: 0x9079, //CJK UNIFIED IDEOGRAPH + 0xEBD2: 0x907B, //CJK UNIFIED IDEOGRAPH + 0xEBD3: 0x9086, //CJK UNIFIED IDEOGRAPH + 0xEBD4: 0x90FA, //CJK UNIFIED IDEOGRAPH + 0xEBD5: 0x9133, //CJK UNIFIED IDEOGRAPH + 0xEBD6: 0x9135, //CJK UNIFIED IDEOGRAPH + 0xEBD7: 0x9136, //CJK UNIFIED IDEOGRAPH + 0xEBD8: 0x9193, //CJK UNIFIED IDEOGRAPH + 0xEBD9: 0x9190, //CJK UNIFIED IDEOGRAPH + 0xEBDA: 0x9191, //CJK UNIFIED IDEOGRAPH + 0xEBDB: 0x918D, //CJK UNIFIED IDEOGRAPH + 0xEBDC: 0x918F, //CJK UNIFIED IDEOGRAPH + 0xEBDD: 0x9327, //CJK UNIFIED IDEOGRAPH + 0xEBDE: 0x931E, //CJK UNIFIED IDEOGRAPH + 0xEBDF: 0x9308, //CJK UNIFIED IDEOGRAPH + 0xEBE0: 0x931F, //CJK UNIFIED IDEOGRAPH + 0xEBE1: 0x9306, //CJK UNIFIED IDEOGRAPH + 0xEBE2: 0x930F, //CJK UNIFIED IDEOGRAPH + 0xEBE3: 0x937A, //CJK UNIFIED IDEOGRAPH + 0xEBE4: 0x9338, //CJK UNIFIED IDEOGRAPH + 0xEBE5: 0x933C, //CJK UNIFIED IDEOGRAPH + 0xEBE6: 0x931B, //CJK UNIFIED IDEOGRAPH + 0xEBE7: 0x9323, //CJK UNIFIED IDEOGRAPH + 0xEBE8: 0x9312, //CJK UNIFIED IDEOGRAPH + 0xEBE9: 0x9301, //CJK UNIFIED IDEOGRAPH + 0xEBEA: 0x9346, //CJK UNIFIED IDEOGRAPH + 0xEBEB: 0x932D, //CJK UNIFIED IDEOGRAPH + 0xEBEC: 0x930E, //CJK UNIFIED IDEOGRAPH + 0xEBED: 0x930D, //CJK UNIFIED IDEOGRAPH + 0xEBEE: 0x92CB, //CJK UNIFIED IDEOGRAPH + 0xEBEF: 0x931D, //CJK UNIFIED IDEOGRAPH + 0xEBF0: 0x92FA, //CJK UNIFIED IDEOGRAPH + 0xEBF1: 0x9325, //CJK UNIFIED IDEOGRAPH + 0xEBF2: 0x9313, //CJK UNIFIED IDEOGRAPH + 0xEBF3: 0x92F9, //CJK UNIFIED IDEOGRAPH + 0xEBF4: 0x92F7, //CJK UNIFIED IDEOGRAPH + 0xEBF5: 0x9334, //CJK UNIFIED IDEOGRAPH + 0xEBF6: 0x9302, //CJK UNIFIED IDEOGRAPH + 0xEBF7: 0x9324, //CJK UNIFIED IDEOGRAPH + 0xEBF8: 0x92FF, //CJK UNIFIED IDEOGRAPH + 0xEBF9: 0x9329, //CJK UNIFIED IDEOGRAPH + 0xEBFA: 0x9339, //CJK UNIFIED IDEOGRAPH + 0xEBFB: 0x9335, //CJK UNIFIED IDEOGRAPH + 0xEBFC: 0x932A, //CJK UNIFIED IDEOGRAPH + 0xEBFD: 0x9314, //CJK UNIFIED IDEOGRAPH + 0xEBFE: 0x930C, //CJK UNIFIED IDEOGRAPH + 0xEC40: 0x930B, //CJK UNIFIED IDEOGRAPH + 0xEC41: 0x92FE, //CJK UNIFIED IDEOGRAPH + 0xEC42: 0x9309, //CJK UNIFIED IDEOGRAPH + 0xEC43: 0x9300, //CJK UNIFIED IDEOGRAPH + 0xEC44: 0x92FB, //CJK UNIFIED IDEOGRAPH + 0xEC45: 0x9316, //CJK UNIFIED IDEOGRAPH + 0xEC46: 0x95BC, //CJK UNIFIED IDEOGRAPH + 0xEC47: 0x95CD, //CJK UNIFIED IDEOGRAPH + 0xEC48: 0x95BE, //CJK UNIFIED IDEOGRAPH + 0xEC49: 0x95B9, //CJK UNIFIED IDEOGRAPH + 0xEC4A: 0x95BA, //CJK UNIFIED IDEOGRAPH + 0xEC4B: 0x95B6, //CJK UNIFIED IDEOGRAPH + 0xEC4C: 0x95BF, //CJK UNIFIED IDEOGRAPH + 0xEC4D: 0x95B5, //CJK UNIFIED IDEOGRAPH + 0xEC4E: 0x95BD, //CJK UNIFIED IDEOGRAPH + 0xEC4F: 0x96A9, //CJK UNIFIED IDEOGRAPH + 0xEC50: 0x96D4, //CJK UNIFIED IDEOGRAPH + 0xEC51: 0x970B, //CJK UNIFIED IDEOGRAPH + 0xEC52: 0x9712, //CJK UNIFIED IDEOGRAPH + 0xEC53: 0x9710, //CJK UNIFIED IDEOGRAPH + 0xEC54: 0x9799, //CJK UNIFIED IDEOGRAPH + 0xEC55: 0x9797, //CJK UNIFIED IDEOGRAPH + 0xEC56: 0x9794, //CJK UNIFIED IDEOGRAPH + 0xEC57: 0x97F0, //CJK UNIFIED IDEOGRAPH + 0xEC58: 0x97F8, //CJK UNIFIED IDEOGRAPH + 0xEC59: 0x9835, //CJK UNIFIED IDEOGRAPH + 0xEC5A: 0x982F, //CJK UNIFIED IDEOGRAPH + 0xEC5B: 0x9832, //CJK UNIFIED IDEOGRAPH + 0xEC5C: 0x9924, //CJK UNIFIED IDEOGRAPH + 0xEC5D: 0x991F, //CJK UNIFIED IDEOGRAPH + 0xEC5E: 0x9927, //CJK UNIFIED IDEOGRAPH + 0xEC5F: 0x9929, //CJK UNIFIED IDEOGRAPH + 0xEC60: 0x999E, //CJK UNIFIED IDEOGRAPH + 0xEC61: 0x99EE, //CJK UNIFIED IDEOGRAPH + 0xEC62: 0x99EC, //CJK UNIFIED IDEOGRAPH + 0xEC63: 0x99E5, //CJK UNIFIED IDEOGRAPH + 0xEC64: 0x99E4, //CJK UNIFIED IDEOGRAPH + 0xEC65: 0x99F0, //CJK UNIFIED IDEOGRAPH + 0xEC66: 0x99E3, //CJK UNIFIED IDEOGRAPH + 0xEC67: 0x99EA, //CJK UNIFIED IDEOGRAPH + 0xEC68: 0x99E9, //CJK UNIFIED IDEOGRAPH + 0xEC69: 0x99E7, //CJK UNIFIED IDEOGRAPH + 0xEC6A: 0x9AB9, //CJK UNIFIED IDEOGRAPH + 0xEC6B: 0x9ABF, //CJK UNIFIED IDEOGRAPH + 0xEC6C: 0x9AB4, //CJK UNIFIED IDEOGRAPH + 0xEC6D: 0x9ABB, //CJK UNIFIED IDEOGRAPH + 0xEC6E: 0x9AF6, //CJK UNIFIED IDEOGRAPH + 0xEC6F: 0x9AFA, //CJK UNIFIED IDEOGRAPH + 0xEC70: 0x9AF9, //CJK UNIFIED IDEOGRAPH + 0xEC71: 0x9AF7, //CJK UNIFIED IDEOGRAPH + 0xEC72: 0x9B33, //CJK UNIFIED IDEOGRAPH + 0xEC73: 0x9B80, //CJK UNIFIED IDEOGRAPH + 0xEC74: 0x9B85, //CJK UNIFIED IDEOGRAPH + 0xEC75: 0x9B87, //CJK UNIFIED IDEOGRAPH + 0xEC76: 0x9B7C, //CJK UNIFIED IDEOGRAPH + 0xEC77: 0x9B7E, //CJK UNIFIED IDEOGRAPH + 0xEC78: 0x9B7B, //CJK UNIFIED IDEOGRAPH + 0xEC79: 0x9B82, //CJK UNIFIED IDEOGRAPH + 0xEC7A: 0x9B93, //CJK UNIFIED IDEOGRAPH + 0xEC7B: 0x9B92, //CJK UNIFIED IDEOGRAPH + 0xEC7C: 0x9B90, //CJK UNIFIED IDEOGRAPH + 0xEC7D: 0x9B7A, //CJK UNIFIED IDEOGRAPH + 0xEC7E: 0x9B95, //CJK UNIFIED IDEOGRAPH + 0xECA1: 0x9B7D, //CJK UNIFIED IDEOGRAPH + 0xECA2: 0x9B88, //CJK UNIFIED IDEOGRAPH + 0xECA3: 0x9D25, //CJK UNIFIED IDEOGRAPH + 0xECA4: 0x9D17, //CJK UNIFIED IDEOGRAPH + 0xECA5: 0x9D20, //CJK UNIFIED IDEOGRAPH + 0xECA6: 0x9D1E, //CJK UNIFIED IDEOGRAPH + 0xECA7: 0x9D14, //CJK UNIFIED IDEOGRAPH + 0xECA8: 0x9D29, //CJK UNIFIED IDEOGRAPH + 0xECA9: 0x9D1D, //CJK UNIFIED IDEOGRAPH + 0xECAA: 0x9D18, //CJK UNIFIED IDEOGRAPH + 0xECAB: 0x9D22, //CJK UNIFIED IDEOGRAPH + 0xECAC: 0x9D10, //CJK UNIFIED IDEOGRAPH + 0xECAD: 0x9D19, //CJK UNIFIED IDEOGRAPH + 0xECAE: 0x9D1F, //CJK UNIFIED IDEOGRAPH + 0xECAF: 0x9E88, //CJK UNIFIED IDEOGRAPH + 0xECB0: 0x9E86, //CJK UNIFIED IDEOGRAPH + 0xECB1: 0x9E87, //CJK UNIFIED IDEOGRAPH + 0xECB2: 0x9EAE, //CJK UNIFIED IDEOGRAPH + 0xECB3: 0x9EAD, //CJK UNIFIED IDEOGRAPH + 0xECB4: 0x9ED5, //CJK UNIFIED IDEOGRAPH + 0xECB5: 0x9ED6, //CJK UNIFIED IDEOGRAPH + 0xECB6: 0x9EFA, //CJK UNIFIED IDEOGRAPH + 0xECB7: 0x9F12, //CJK UNIFIED IDEOGRAPH + 0xECB8: 0x9F3D, //CJK UNIFIED IDEOGRAPH + 0xECB9: 0x5126, //CJK UNIFIED IDEOGRAPH + 0xECBA: 0x5125, //CJK UNIFIED IDEOGRAPH + 0xECBB: 0x5122, //CJK UNIFIED IDEOGRAPH + 0xECBC: 0x5124, //CJK UNIFIED IDEOGRAPH + 0xECBD: 0x5120, //CJK UNIFIED IDEOGRAPH + 0xECBE: 0x5129, //CJK UNIFIED IDEOGRAPH + 0xECBF: 0x52F4, //CJK UNIFIED IDEOGRAPH + 0xECC0: 0x5693, //CJK UNIFIED IDEOGRAPH + 0xECC1: 0x568C, //CJK UNIFIED IDEOGRAPH + 0xECC2: 0x568D, //CJK UNIFIED IDEOGRAPH + 0xECC3: 0x5686, //CJK UNIFIED IDEOGRAPH + 0xECC4: 0x5684, //CJK UNIFIED IDEOGRAPH + 0xECC5: 0x5683, //CJK UNIFIED IDEOGRAPH + 0xECC6: 0x567E, //CJK UNIFIED IDEOGRAPH + 0xECC7: 0x5682, //CJK UNIFIED IDEOGRAPH + 0xECC8: 0x567F, //CJK UNIFIED IDEOGRAPH + 0xECC9: 0x5681, //CJK UNIFIED IDEOGRAPH + 0xECCA: 0x58D6, //CJK UNIFIED IDEOGRAPH + 0xECCB: 0x58D4, //CJK UNIFIED IDEOGRAPH + 0xECCC: 0x58CF, //CJK UNIFIED IDEOGRAPH + 0xECCD: 0x58D2, //CJK UNIFIED IDEOGRAPH + 0xECCE: 0x5B2D, //CJK UNIFIED IDEOGRAPH + 0xECCF: 0x5B25, //CJK UNIFIED IDEOGRAPH + 0xECD0: 0x5B32, //CJK UNIFIED IDEOGRAPH + 0xECD1: 0x5B23, //CJK UNIFIED IDEOGRAPH + 0xECD2: 0x5B2C, //CJK UNIFIED IDEOGRAPH + 0xECD3: 0x5B27, //CJK UNIFIED IDEOGRAPH + 0xECD4: 0x5B26, //CJK UNIFIED IDEOGRAPH + 0xECD5: 0x5B2F, //CJK UNIFIED IDEOGRAPH + 0xECD6: 0x5B2E, //CJK UNIFIED IDEOGRAPH + 0xECD7: 0x5B7B, //CJK UNIFIED IDEOGRAPH + 0xECD8: 0x5BF1, //CJK UNIFIED IDEOGRAPH + 0xECD9: 0x5BF2, //CJK UNIFIED IDEOGRAPH + 0xECDA: 0x5DB7, //CJK UNIFIED IDEOGRAPH + 0xECDB: 0x5E6C, //CJK UNIFIED IDEOGRAPH + 0xECDC: 0x5E6A, //CJK UNIFIED IDEOGRAPH + 0xECDD: 0x5FBE, //CJK UNIFIED IDEOGRAPH + 0xECDE: 0x5FBB, //CJK UNIFIED IDEOGRAPH + 0xECDF: 0x61C3, //CJK UNIFIED IDEOGRAPH + 0xECE0: 0x61B5, //CJK UNIFIED IDEOGRAPH + 0xECE1: 0x61BC, //CJK UNIFIED IDEOGRAPH + 0xECE2: 0x61E7, //CJK UNIFIED IDEOGRAPH + 0xECE3: 0x61E0, //CJK UNIFIED IDEOGRAPH + 0xECE4: 0x61E5, //CJK UNIFIED IDEOGRAPH + 0xECE5: 0x61E4, //CJK UNIFIED IDEOGRAPH + 0xECE6: 0x61E8, //CJK UNIFIED IDEOGRAPH + 0xECE7: 0x61DE, //CJK UNIFIED IDEOGRAPH + 0xECE8: 0x64EF, //CJK UNIFIED IDEOGRAPH + 0xECE9: 0x64E9, //CJK UNIFIED IDEOGRAPH + 0xECEA: 0x64E3, //CJK UNIFIED IDEOGRAPH + 0xECEB: 0x64EB, //CJK UNIFIED IDEOGRAPH + 0xECEC: 0x64E4, //CJK UNIFIED IDEOGRAPH + 0xECED: 0x64E8, //CJK UNIFIED IDEOGRAPH + 0xECEE: 0x6581, //CJK UNIFIED IDEOGRAPH + 0xECEF: 0x6580, //CJK UNIFIED IDEOGRAPH + 0xECF0: 0x65B6, //CJK UNIFIED IDEOGRAPH + 0xECF1: 0x65DA, //CJK UNIFIED IDEOGRAPH + 0xECF2: 0x66D2, //CJK UNIFIED IDEOGRAPH + 0xECF3: 0x6A8D, //CJK UNIFIED IDEOGRAPH + 0xECF4: 0x6A96, //CJK UNIFIED IDEOGRAPH + 0xECF5: 0x6A81, //CJK UNIFIED IDEOGRAPH + 0xECF6: 0x6AA5, //CJK UNIFIED IDEOGRAPH + 0xECF7: 0x6A89, //CJK UNIFIED IDEOGRAPH + 0xECF8: 0x6A9F, //CJK UNIFIED IDEOGRAPH + 0xECF9: 0x6A9B, //CJK UNIFIED IDEOGRAPH + 0xECFA: 0x6AA1, //CJK UNIFIED IDEOGRAPH + 0xECFB: 0x6A9E, //CJK UNIFIED IDEOGRAPH + 0xECFC: 0x6A87, //CJK UNIFIED IDEOGRAPH + 0xECFD: 0x6A93, //CJK UNIFIED IDEOGRAPH + 0xECFE: 0x6A8E, //CJK UNIFIED IDEOGRAPH + 0xED40: 0x6A95, //CJK UNIFIED IDEOGRAPH + 0xED41: 0x6A83, //CJK UNIFIED IDEOGRAPH + 0xED42: 0x6AA8, //CJK UNIFIED IDEOGRAPH + 0xED43: 0x6AA4, //CJK UNIFIED IDEOGRAPH + 0xED44: 0x6A91, //CJK UNIFIED IDEOGRAPH + 0xED45: 0x6A7F, //CJK UNIFIED IDEOGRAPH + 0xED46: 0x6AA6, //CJK UNIFIED IDEOGRAPH + 0xED47: 0x6A9A, //CJK UNIFIED IDEOGRAPH + 0xED48: 0x6A85, //CJK UNIFIED IDEOGRAPH + 0xED49: 0x6A8C, //CJK UNIFIED IDEOGRAPH + 0xED4A: 0x6A92, //CJK UNIFIED IDEOGRAPH + 0xED4B: 0x6B5B, //CJK UNIFIED IDEOGRAPH + 0xED4C: 0x6BAD, //CJK UNIFIED IDEOGRAPH + 0xED4D: 0x6C09, //CJK UNIFIED IDEOGRAPH + 0xED4E: 0x6FCC, //CJK UNIFIED IDEOGRAPH + 0xED4F: 0x6FA9, //CJK UNIFIED IDEOGRAPH + 0xED50: 0x6FF4, //CJK UNIFIED IDEOGRAPH + 0xED51: 0x6FD4, //CJK UNIFIED IDEOGRAPH + 0xED52: 0x6FE3, //CJK UNIFIED IDEOGRAPH + 0xED53: 0x6FDC, //CJK UNIFIED IDEOGRAPH + 0xED54: 0x6FED, //CJK UNIFIED IDEOGRAPH + 0xED55: 0x6FE7, //CJK UNIFIED IDEOGRAPH + 0xED56: 0x6FE6, //CJK UNIFIED IDEOGRAPH + 0xED57: 0x6FDE, //CJK UNIFIED IDEOGRAPH + 0xED58: 0x6FF2, //CJK UNIFIED IDEOGRAPH + 0xED59: 0x6FDD, //CJK UNIFIED IDEOGRAPH + 0xED5A: 0x6FE2, //CJK UNIFIED IDEOGRAPH + 0xED5B: 0x6FE8, //CJK UNIFIED IDEOGRAPH + 0xED5C: 0x71E1, //CJK UNIFIED IDEOGRAPH + 0xED5D: 0x71F1, //CJK UNIFIED IDEOGRAPH + 0xED5E: 0x71E8, //CJK UNIFIED IDEOGRAPH + 0xED5F: 0x71F2, //CJK UNIFIED IDEOGRAPH + 0xED60: 0x71E4, //CJK UNIFIED IDEOGRAPH + 0xED61: 0x71F0, //CJK UNIFIED IDEOGRAPH + 0xED62: 0x71E2, //CJK UNIFIED IDEOGRAPH + 0xED63: 0x7373, //CJK UNIFIED IDEOGRAPH + 0xED64: 0x736E, //CJK UNIFIED IDEOGRAPH + 0xED65: 0x736F, //CJK UNIFIED IDEOGRAPH + 0xED66: 0x7497, //CJK UNIFIED IDEOGRAPH + 0xED67: 0x74B2, //CJK UNIFIED IDEOGRAPH + 0xED68: 0x74AB, //CJK UNIFIED IDEOGRAPH + 0xED69: 0x7490, //CJK UNIFIED IDEOGRAPH + 0xED6A: 0x74AA, //CJK UNIFIED IDEOGRAPH + 0xED6B: 0x74AD, //CJK UNIFIED IDEOGRAPH + 0xED6C: 0x74B1, //CJK UNIFIED IDEOGRAPH + 0xED6D: 0x74A5, //CJK UNIFIED IDEOGRAPH + 0xED6E: 0x74AF, //CJK UNIFIED IDEOGRAPH + 0xED6F: 0x7510, //CJK UNIFIED IDEOGRAPH + 0xED70: 0x7511, //CJK UNIFIED IDEOGRAPH + 0xED71: 0x7512, //CJK UNIFIED IDEOGRAPH + 0xED72: 0x750F, //CJK UNIFIED IDEOGRAPH + 0xED73: 0x7584, //CJK UNIFIED IDEOGRAPH + 0xED74: 0x7643, //CJK UNIFIED IDEOGRAPH + 0xED75: 0x7648, //CJK UNIFIED IDEOGRAPH + 0xED76: 0x7649, //CJK UNIFIED IDEOGRAPH + 0xED77: 0x7647, //CJK UNIFIED IDEOGRAPH + 0xED78: 0x76A4, //CJK UNIFIED IDEOGRAPH + 0xED79: 0x76E9, //CJK UNIFIED IDEOGRAPH + 0xED7A: 0x77B5, //CJK UNIFIED IDEOGRAPH + 0xED7B: 0x77AB, //CJK UNIFIED IDEOGRAPH + 0xED7C: 0x77B2, //CJK UNIFIED IDEOGRAPH + 0xED7D: 0x77B7, //CJK UNIFIED IDEOGRAPH + 0xED7E: 0x77B6, //CJK UNIFIED IDEOGRAPH + 0xEDA1: 0x77B4, //CJK UNIFIED IDEOGRAPH + 0xEDA2: 0x77B1, //CJK UNIFIED IDEOGRAPH + 0xEDA3: 0x77A8, //CJK UNIFIED IDEOGRAPH + 0xEDA4: 0x77F0, //CJK UNIFIED IDEOGRAPH + 0xEDA5: 0x78F3, //CJK UNIFIED IDEOGRAPH + 0xEDA6: 0x78FD, //CJK UNIFIED IDEOGRAPH + 0xEDA7: 0x7902, //CJK UNIFIED IDEOGRAPH + 0xEDA8: 0x78FB, //CJK UNIFIED IDEOGRAPH + 0xEDA9: 0x78FC, //CJK UNIFIED IDEOGRAPH + 0xEDAA: 0x78F2, //CJK UNIFIED IDEOGRAPH + 0xEDAB: 0x7905, //CJK UNIFIED IDEOGRAPH + 0xEDAC: 0x78F9, //CJK UNIFIED IDEOGRAPH + 0xEDAD: 0x78FE, //CJK UNIFIED IDEOGRAPH + 0xEDAE: 0x7904, //CJK UNIFIED IDEOGRAPH + 0xEDAF: 0x79AB, //CJK UNIFIED IDEOGRAPH + 0xEDB0: 0x79A8, //CJK UNIFIED IDEOGRAPH + 0xEDB1: 0x7A5C, //CJK UNIFIED IDEOGRAPH + 0xEDB2: 0x7A5B, //CJK UNIFIED IDEOGRAPH + 0xEDB3: 0x7A56, //CJK UNIFIED IDEOGRAPH + 0xEDB4: 0x7A58, //CJK UNIFIED IDEOGRAPH + 0xEDB5: 0x7A54, //CJK UNIFIED IDEOGRAPH + 0xEDB6: 0x7A5A, //CJK UNIFIED IDEOGRAPH + 0xEDB7: 0x7ABE, //CJK UNIFIED IDEOGRAPH + 0xEDB8: 0x7AC0, //CJK UNIFIED IDEOGRAPH + 0xEDB9: 0x7AC1, //CJK UNIFIED IDEOGRAPH + 0xEDBA: 0x7C05, //CJK UNIFIED IDEOGRAPH + 0xEDBB: 0x7C0F, //CJK UNIFIED IDEOGRAPH + 0xEDBC: 0x7BF2, //CJK UNIFIED IDEOGRAPH + 0xEDBD: 0x7C00, //CJK UNIFIED IDEOGRAPH + 0xEDBE: 0x7BFF, //CJK UNIFIED IDEOGRAPH + 0xEDBF: 0x7BFB, //CJK UNIFIED IDEOGRAPH + 0xEDC0: 0x7C0E, //CJK UNIFIED IDEOGRAPH + 0xEDC1: 0x7BF4, //CJK UNIFIED IDEOGRAPH + 0xEDC2: 0x7C0B, //CJK UNIFIED IDEOGRAPH + 0xEDC3: 0x7BF3, //CJK UNIFIED IDEOGRAPH + 0xEDC4: 0x7C02, //CJK UNIFIED IDEOGRAPH + 0xEDC5: 0x7C09, //CJK UNIFIED IDEOGRAPH + 0xEDC6: 0x7C03, //CJK UNIFIED IDEOGRAPH + 0xEDC7: 0x7C01, //CJK UNIFIED IDEOGRAPH + 0xEDC8: 0x7BF8, //CJK UNIFIED IDEOGRAPH + 0xEDC9: 0x7BFD, //CJK UNIFIED IDEOGRAPH + 0xEDCA: 0x7C06, //CJK UNIFIED IDEOGRAPH + 0xEDCB: 0x7BF0, //CJK UNIFIED IDEOGRAPH + 0xEDCC: 0x7BF1, //CJK UNIFIED IDEOGRAPH + 0xEDCD: 0x7C10, //CJK UNIFIED IDEOGRAPH + 0xEDCE: 0x7C0A, //CJK UNIFIED IDEOGRAPH + 0xEDCF: 0x7CE8, //CJK UNIFIED IDEOGRAPH + 0xEDD0: 0x7E2D, //CJK UNIFIED IDEOGRAPH + 0xEDD1: 0x7E3C, //CJK UNIFIED IDEOGRAPH + 0xEDD2: 0x7E42, //CJK UNIFIED IDEOGRAPH + 0xEDD3: 0x7E33, //CJK UNIFIED IDEOGRAPH + 0xEDD4: 0x9848, //CJK UNIFIED IDEOGRAPH + 0xEDD5: 0x7E38, //CJK UNIFIED IDEOGRAPH + 0xEDD6: 0x7E2A, //CJK UNIFIED IDEOGRAPH + 0xEDD7: 0x7E49, //CJK UNIFIED IDEOGRAPH + 0xEDD8: 0x7E40, //CJK UNIFIED IDEOGRAPH + 0xEDD9: 0x7E47, //CJK UNIFIED IDEOGRAPH + 0xEDDA: 0x7E29, //CJK UNIFIED IDEOGRAPH + 0xEDDB: 0x7E4C, //CJK UNIFIED IDEOGRAPH + 0xEDDC: 0x7E30, //CJK UNIFIED IDEOGRAPH + 0xEDDD: 0x7E3B, //CJK UNIFIED IDEOGRAPH + 0xEDDE: 0x7E36, //CJK UNIFIED IDEOGRAPH + 0xEDDF: 0x7E44, //CJK UNIFIED IDEOGRAPH + 0xEDE0: 0x7E3A, //CJK UNIFIED IDEOGRAPH + 0xEDE1: 0x7F45, //CJK UNIFIED IDEOGRAPH + 0xEDE2: 0x7F7F, //CJK UNIFIED IDEOGRAPH + 0xEDE3: 0x7F7E, //CJK UNIFIED IDEOGRAPH + 0xEDE4: 0x7F7D, //CJK UNIFIED IDEOGRAPH + 0xEDE5: 0x7FF4, //CJK UNIFIED IDEOGRAPH + 0xEDE6: 0x7FF2, //CJK UNIFIED IDEOGRAPH + 0xEDE7: 0x802C, //CJK UNIFIED IDEOGRAPH + 0xEDE8: 0x81BB, //CJK UNIFIED IDEOGRAPH + 0xEDE9: 0x81C4, //CJK UNIFIED IDEOGRAPH + 0xEDEA: 0x81CC, //CJK UNIFIED IDEOGRAPH + 0xEDEB: 0x81CA, //CJK UNIFIED IDEOGRAPH + 0xEDEC: 0x81C5, //CJK UNIFIED IDEOGRAPH + 0xEDED: 0x81C7, //CJK UNIFIED IDEOGRAPH + 0xEDEE: 0x81BC, //CJK UNIFIED IDEOGRAPH + 0xEDEF: 0x81E9, //CJK UNIFIED IDEOGRAPH + 0xEDF0: 0x825B, //CJK UNIFIED IDEOGRAPH + 0xEDF1: 0x825A, //CJK UNIFIED IDEOGRAPH + 0xEDF2: 0x825C, //CJK UNIFIED IDEOGRAPH + 0xEDF3: 0x8583, //CJK UNIFIED IDEOGRAPH + 0xEDF4: 0x8580, //CJK UNIFIED IDEOGRAPH + 0xEDF5: 0x858F, //CJK UNIFIED IDEOGRAPH + 0xEDF6: 0x85A7, //CJK UNIFIED IDEOGRAPH + 0xEDF7: 0x8595, //CJK UNIFIED IDEOGRAPH + 0xEDF8: 0x85A0, //CJK UNIFIED IDEOGRAPH + 0xEDF9: 0x858B, //CJK UNIFIED IDEOGRAPH + 0xEDFA: 0x85A3, //CJK UNIFIED IDEOGRAPH + 0xEDFB: 0x857B, //CJK UNIFIED IDEOGRAPH + 0xEDFC: 0x85A4, //CJK UNIFIED IDEOGRAPH + 0xEDFD: 0x859A, //CJK UNIFIED IDEOGRAPH + 0xEDFE: 0x859E, //CJK UNIFIED IDEOGRAPH + 0xEE40: 0x8577, //CJK UNIFIED IDEOGRAPH + 0xEE41: 0x857C, //CJK UNIFIED IDEOGRAPH + 0xEE42: 0x8589, //CJK UNIFIED IDEOGRAPH + 0xEE43: 0x85A1, //CJK UNIFIED IDEOGRAPH + 0xEE44: 0x857A, //CJK UNIFIED IDEOGRAPH + 0xEE45: 0x8578, //CJK UNIFIED IDEOGRAPH + 0xEE46: 0x8557, //CJK UNIFIED IDEOGRAPH + 0xEE47: 0x858E, //CJK UNIFIED IDEOGRAPH + 0xEE48: 0x8596, //CJK UNIFIED IDEOGRAPH + 0xEE49: 0x8586, //CJK UNIFIED IDEOGRAPH + 0xEE4A: 0x858D, //CJK UNIFIED IDEOGRAPH + 0xEE4B: 0x8599, //CJK UNIFIED IDEOGRAPH + 0xEE4C: 0x859D, //CJK UNIFIED IDEOGRAPH + 0xEE4D: 0x8581, //CJK UNIFIED IDEOGRAPH + 0xEE4E: 0x85A2, //CJK UNIFIED IDEOGRAPH + 0xEE4F: 0x8582, //CJK UNIFIED IDEOGRAPH + 0xEE50: 0x8588, //CJK UNIFIED IDEOGRAPH + 0xEE51: 0x8585, //CJK UNIFIED IDEOGRAPH + 0xEE52: 0x8579, //CJK UNIFIED IDEOGRAPH + 0xEE53: 0x8576, //CJK UNIFIED IDEOGRAPH + 0xEE54: 0x8598, //CJK UNIFIED IDEOGRAPH + 0xEE55: 0x8590, //CJK UNIFIED IDEOGRAPH + 0xEE56: 0x859F, //CJK UNIFIED IDEOGRAPH + 0xEE57: 0x8668, //CJK UNIFIED IDEOGRAPH + 0xEE58: 0x87BE, //CJK UNIFIED IDEOGRAPH + 0xEE59: 0x87AA, //CJK UNIFIED IDEOGRAPH + 0xEE5A: 0x87AD, //CJK UNIFIED IDEOGRAPH + 0xEE5B: 0x87C5, //CJK UNIFIED IDEOGRAPH + 0xEE5C: 0x87B0, //CJK UNIFIED IDEOGRAPH + 0xEE5D: 0x87AC, //CJK UNIFIED IDEOGRAPH + 0xEE5E: 0x87B9, //CJK UNIFIED IDEOGRAPH + 0xEE5F: 0x87B5, //CJK UNIFIED IDEOGRAPH + 0xEE60: 0x87BC, //CJK UNIFIED IDEOGRAPH + 0xEE61: 0x87AE, //CJK UNIFIED IDEOGRAPH + 0xEE62: 0x87C9, //CJK UNIFIED IDEOGRAPH + 0xEE63: 0x87C3, //CJK UNIFIED IDEOGRAPH + 0xEE64: 0x87C2, //CJK UNIFIED IDEOGRAPH + 0xEE65: 0x87CC, //CJK UNIFIED IDEOGRAPH + 0xEE66: 0x87B7, //CJK UNIFIED IDEOGRAPH + 0xEE67: 0x87AF, //CJK UNIFIED IDEOGRAPH + 0xEE68: 0x87C4, //CJK UNIFIED IDEOGRAPH + 0xEE69: 0x87CA, //CJK UNIFIED IDEOGRAPH + 0xEE6A: 0x87B4, //CJK UNIFIED IDEOGRAPH + 0xEE6B: 0x87B6, //CJK UNIFIED IDEOGRAPH + 0xEE6C: 0x87BF, //CJK UNIFIED IDEOGRAPH + 0xEE6D: 0x87B8, //CJK UNIFIED IDEOGRAPH + 0xEE6E: 0x87BD, //CJK UNIFIED IDEOGRAPH + 0xEE6F: 0x87DE, //CJK UNIFIED IDEOGRAPH + 0xEE70: 0x87B2, //CJK UNIFIED IDEOGRAPH + 0xEE71: 0x8935, //CJK UNIFIED IDEOGRAPH + 0xEE72: 0x8933, //CJK UNIFIED IDEOGRAPH + 0xEE73: 0x893C, //CJK UNIFIED IDEOGRAPH + 0xEE74: 0x893E, //CJK UNIFIED IDEOGRAPH + 0xEE75: 0x8941, //CJK UNIFIED IDEOGRAPH + 0xEE76: 0x8952, //CJK UNIFIED IDEOGRAPH + 0xEE77: 0x8937, //CJK UNIFIED IDEOGRAPH + 0xEE78: 0x8942, //CJK UNIFIED IDEOGRAPH + 0xEE79: 0x89AD, //CJK UNIFIED IDEOGRAPH + 0xEE7A: 0x89AF, //CJK UNIFIED IDEOGRAPH + 0xEE7B: 0x89AE, //CJK UNIFIED IDEOGRAPH + 0xEE7C: 0x89F2, //CJK UNIFIED IDEOGRAPH + 0xEE7D: 0x89F3, //CJK UNIFIED IDEOGRAPH + 0xEE7E: 0x8B1E, //CJK UNIFIED IDEOGRAPH + 0xEEA1: 0x8B18, //CJK UNIFIED IDEOGRAPH + 0xEEA2: 0x8B16, //CJK UNIFIED IDEOGRAPH + 0xEEA3: 0x8B11, //CJK UNIFIED IDEOGRAPH + 0xEEA4: 0x8B05, //CJK UNIFIED IDEOGRAPH + 0xEEA5: 0x8B0B, //CJK UNIFIED IDEOGRAPH + 0xEEA6: 0x8B22, //CJK UNIFIED IDEOGRAPH + 0xEEA7: 0x8B0F, //CJK UNIFIED IDEOGRAPH + 0xEEA8: 0x8B12, //CJK UNIFIED IDEOGRAPH + 0xEEA9: 0x8B15, //CJK UNIFIED IDEOGRAPH + 0xEEAA: 0x8B07, //CJK UNIFIED IDEOGRAPH + 0xEEAB: 0x8B0D, //CJK UNIFIED IDEOGRAPH + 0xEEAC: 0x8B08, //CJK UNIFIED IDEOGRAPH + 0xEEAD: 0x8B06, //CJK UNIFIED IDEOGRAPH + 0xEEAE: 0x8B1C, //CJK UNIFIED IDEOGRAPH + 0xEEAF: 0x8B13, //CJK UNIFIED IDEOGRAPH + 0xEEB0: 0x8B1A, //CJK UNIFIED IDEOGRAPH + 0xEEB1: 0x8C4F, //CJK UNIFIED IDEOGRAPH + 0xEEB2: 0x8C70, //CJK UNIFIED IDEOGRAPH + 0xEEB3: 0x8C72, //CJK UNIFIED IDEOGRAPH + 0xEEB4: 0x8C71, //CJK UNIFIED IDEOGRAPH + 0xEEB5: 0x8C6F, //CJK UNIFIED IDEOGRAPH + 0xEEB6: 0x8C95, //CJK UNIFIED IDEOGRAPH + 0xEEB7: 0x8C94, //CJK UNIFIED IDEOGRAPH + 0xEEB8: 0x8CF9, //CJK UNIFIED IDEOGRAPH + 0xEEB9: 0x8D6F, //CJK UNIFIED IDEOGRAPH + 0xEEBA: 0x8E4E, //CJK UNIFIED IDEOGRAPH + 0xEEBB: 0x8E4D, //CJK UNIFIED IDEOGRAPH + 0xEEBC: 0x8E53, //CJK UNIFIED IDEOGRAPH + 0xEEBD: 0x8E50, //CJK UNIFIED IDEOGRAPH + 0xEEBE: 0x8E4C, //CJK UNIFIED IDEOGRAPH + 0xEEBF: 0x8E47, //CJK UNIFIED IDEOGRAPH + 0xEEC0: 0x8F43, //CJK UNIFIED IDEOGRAPH + 0xEEC1: 0x8F40, //CJK UNIFIED IDEOGRAPH + 0xEEC2: 0x9085, //CJK UNIFIED IDEOGRAPH + 0xEEC3: 0x907E, //CJK UNIFIED IDEOGRAPH + 0xEEC4: 0x9138, //CJK UNIFIED IDEOGRAPH + 0xEEC5: 0x919A, //CJK UNIFIED IDEOGRAPH + 0xEEC6: 0x91A2, //CJK UNIFIED IDEOGRAPH + 0xEEC7: 0x919B, //CJK UNIFIED IDEOGRAPH + 0xEEC8: 0x9199, //CJK UNIFIED IDEOGRAPH + 0xEEC9: 0x919F, //CJK UNIFIED IDEOGRAPH + 0xEECA: 0x91A1, //CJK UNIFIED IDEOGRAPH + 0xEECB: 0x919D, //CJK UNIFIED IDEOGRAPH + 0xEECC: 0x91A0, //CJK UNIFIED IDEOGRAPH + 0xEECD: 0x93A1, //CJK UNIFIED IDEOGRAPH + 0xEECE: 0x9383, //CJK UNIFIED IDEOGRAPH + 0xEECF: 0x93AF, //CJK UNIFIED IDEOGRAPH + 0xEED0: 0x9364, //CJK UNIFIED IDEOGRAPH + 0xEED1: 0x9356, //CJK UNIFIED IDEOGRAPH + 0xEED2: 0x9347, //CJK UNIFIED IDEOGRAPH + 0xEED3: 0x937C, //CJK UNIFIED IDEOGRAPH + 0xEED4: 0x9358, //CJK UNIFIED IDEOGRAPH + 0xEED5: 0x935C, //CJK UNIFIED IDEOGRAPH + 0xEED6: 0x9376, //CJK UNIFIED IDEOGRAPH + 0xEED7: 0x9349, //CJK UNIFIED IDEOGRAPH + 0xEED8: 0x9350, //CJK UNIFIED IDEOGRAPH + 0xEED9: 0x9351, //CJK UNIFIED IDEOGRAPH + 0xEEDA: 0x9360, //CJK UNIFIED IDEOGRAPH + 0xEEDB: 0x936D, //CJK UNIFIED IDEOGRAPH + 0xEEDC: 0x938F, //CJK UNIFIED IDEOGRAPH + 0xEEDD: 0x934C, //CJK UNIFIED IDEOGRAPH + 0xEEDE: 0x936A, //CJK UNIFIED IDEOGRAPH + 0xEEDF: 0x9379, //CJK UNIFIED IDEOGRAPH + 0xEEE0: 0x9357, //CJK UNIFIED IDEOGRAPH + 0xEEE1: 0x9355, //CJK UNIFIED IDEOGRAPH + 0xEEE2: 0x9352, //CJK UNIFIED IDEOGRAPH + 0xEEE3: 0x934F, //CJK UNIFIED IDEOGRAPH + 0xEEE4: 0x9371, //CJK UNIFIED IDEOGRAPH + 0xEEE5: 0x9377, //CJK UNIFIED IDEOGRAPH + 0xEEE6: 0x937B, //CJK UNIFIED IDEOGRAPH + 0xEEE7: 0x9361, //CJK UNIFIED IDEOGRAPH + 0xEEE8: 0x935E, //CJK UNIFIED IDEOGRAPH + 0xEEE9: 0x9363, //CJK UNIFIED IDEOGRAPH + 0xEEEA: 0x9367, //CJK UNIFIED IDEOGRAPH + 0xEEEB: 0x9380, //CJK UNIFIED IDEOGRAPH + 0xEEEC: 0x934E, //CJK UNIFIED IDEOGRAPH + 0xEEED: 0x9359, //CJK UNIFIED IDEOGRAPH + 0xEEEE: 0x95C7, //CJK UNIFIED IDEOGRAPH + 0xEEEF: 0x95C0, //CJK UNIFIED IDEOGRAPH + 0xEEF0: 0x95C9, //CJK UNIFIED IDEOGRAPH + 0xEEF1: 0x95C3, //CJK UNIFIED IDEOGRAPH + 0xEEF2: 0x95C5, //CJK UNIFIED IDEOGRAPH + 0xEEF3: 0x95B7, //CJK UNIFIED IDEOGRAPH + 0xEEF4: 0x96AE, //CJK UNIFIED IDEOGRAPH + 0xEEF5: 0x96B0, //CJK UNIFIED IDEOGRAPH + 0xEEF6: 0x96AC, //CJK UNIFIED IDEOGRAPH + 0xEEF7: 0x9720, //CJK UNIFIED IDEOGRAPH + 0xEEF8: 0x971F, //CJK UNIFIED IDEOGRAPH + 0xEEF9: 0x9718, //CJK UNIFIED IDEOGRAPH + 0xEEFA: 0x971D, //CJK UNIFIED IDEOGRAPH + 0xEEFB: 0x9719, //CJK UNIFIED IDEOGRAPH + 0xEEFC: 0x979A, //CJK UNIFIED IDEOGRAPH + 0xEEFD: 0x97A1, //CJK UNIFIED IDEOGRAPH + 0xEEFE: 0x979C, //CJK UNIFIED IDEOGRAPH + 0xEF40: 0x979E, //CJK UNIFIED IDEOGRAPH + 0xEF41: 0x979D, //CJK UNIFIED IDEOGRAPH + 0xEF42: 0x97D5, //CJK UNIFIED IDEOGRAPH + 0xEF43: 0x97D4, //CJK UNIFIED IDEOGRAPH + 0xEF44: 0x97F1, //CJK UNIFIED IDEOGRAPH + 0xEF45: 0x9841, //CJK UNIFIED IDEOGRAPH + 0xEF46: 0x9844, //CJK UNIFIED IDEOGRAPH + 0xEF47: 0x984A, //CJK UNIFIED IDEOGRAPH + 0xEF48: 0x9849, //CJK UNIFIED IDEOGRAPH + 0xEF49: 0x9845, //CJK UNIFIED IDEOGRAPH + 0xEF4A: 0x9843, //CJK UNIFIED IDEOGRAPH + 0xEF4B: 0x9925, //CJK UNIFIED IDEOGRAPH + 0xEF4C: 0x992B, //CJK UNIFIED IDEOGRAPH + 0xEF4D: 0x992C, //CJK UNIFIED IDEOGRAPH + 0xEF4E: 0x992A, //CJK UNIFIED IDEOGRAPH + 0xEF4F: 0x9933, //CJK UNIFIED IDEOGRAPH + 0xEF50: 0x9932, //CJK UNIFIED IDEOGRAPH + 0xEF51: 0x992F, //CJK UNIFIED IDEOGRAPH + 0xEF52: 0x992D, //CJK UNIFIED IDEOGRAPH + 0xEF53: 0x9931, //CJK UNIFIED IDEOGRAPH + 0xEF54: 0x9930, //CJK UNIFIED IDEOGRAPH + 0xEF55: 0x9998, //CJK UNIFIED IDEOGRAPH + 0xEF56: 0x99A3, //CJK UNIFIED IDEOGRAPH + 0xEF57: 0x99A1, //CJK UNIFIED IDEOGRAPH + 0xEF58: 0x9A02, //CJK UNIFIED IDEOGRAPH + 0xEF59: 0x99FA, //CJK UNIFIED IDEOGRAPH + 0xEF5A: 0x99F4, //CJK UNIFIED IDEOGRAPH + 0xEF5B: 0x99F7, //CJK UNIFIED IDEOGRAPH + 0xEF5C: 0x99F9, //CJK UNIFIED IDEOGRAPH + 0xEF5D: 0x99F8, //CJK UNIFIED IDEOGRAPH + 0xEF5E: 0x99F6, //CJK UNIFIED IDEOGRAPH + 0xEF5F: 0x99FB, //CJK UNIFIED IDEOGRAPH + 0xEF60: 0x99FD, //CJK UNIFIED IDEOGRAPH + 0xEF61: 0x99FE, //CJK UNIFIED IDEOGRAPH + 0xEF62: 0x99FC, //CJK UNIFIED IDEOGRAPH + 0xEF63: 0x9A03, //CJK UNIFIED IDEOGRAPH + 0xEF64: 0x9ABE, //CJK UNIFIED IDEOGRAPH + 0xEF65: 0x9AFE, //CJK UNIFIED IDEOGRAPH + 0xEF66: 0x9AFD, //CJK UNIFIED IDEOGRAPH + 0xEF67: 0x9B01, //CJK UNIFIED IDEOGRAPH + 0xEF68: 0x9AFC, //CJK UNIFIED IDEOGRAPH + 0xEF69: 0x9B48, //CJK UNIFIED IDEOGRAPH + 0xEF6A: 0x9B9A, //CJK UNIFIED IDEOGRAPH + 0xEF6B: 0x9BA8, //CJK UNIFIED IDEOGRAPH + 0xEF6C: 0x9B9E, //CJK UNIFIED IDEOGRAPH + 0xEF6D: 0x9B9B, //CJK UNIFIED IDEOGRAPH + 0xEF6E: 0x9BA6, //CJK UNIFIED IDEOGRAPH + 0xEF6F: 0x9BA1, //CJK UNIFIED IDEOGRAPH + 0xEF70: 0x9BA5, //CJK UNIFIED IDEOGRAPH + 0xEF71: 0x9BA4, //CJK UNIFIED IDEOGRAPH + 0xEF72: 0x9B86, //CJK UNIFIED IDEOGRAPH + 0xEF73: 0x9BA2, //CJK UNIFIED IDEOGRAPH + 0xEF74: 0x9BA0, //CJK UNIFIED IDEOGRAPH + 0xEF75: 0x9BAF, //CJK UNIFIED IDEOGRAPH + 0xEF76: 0x9D33, //CJK UNIFIED IDEOGRAPH + 0xEF77: 0x9D41, //CJK UNIFIED IDEOGRAPH + 0xEF78: 0x9D67, //CJK UNIFIED IDEOGRAPH + 0xEF79: 0x9D36, //CJK UNIFIED IDEOGRAPH + 0xEF7A: 0x9D2E, //CJK UNIFIED IDEOGRAPH + 0xEF7B: 0x9D2F, //CJK UNIFIED IDEOGRAPH + 0xEF7C: 0x9D31, //CJK UNIFIED IDEOGRAPH + 0xEF7D: 0x9D38, //CJK UNIFIED IDEOGRAPH + 0xEF7E: 0x9D30, //CJK UNIFIED IDEOGRAPH + 0xEFA1: 0x9D45, //CJK UNIFIED IDEOGRAPH + 0xEFA2: 0x9D42, //CJK UNIFIED IDEOGRAPH + 0xEFA3: 0x9D43, //CJK UNIFIED IDEOGRAPH + 0xEFA4: 0x9D3E, //CJK UNIFIED IDEOGRAPH + 0xEFA5: 0x9D37, //CJK UNIFIED IDEOGRAPH + 0xEFA6: 0x9D40, //CJK UNIFIED IDEOGRAPH + 0xEFA7: 0x9D3D, //CJK UNIFIED IDEOGRAPH + 0xEFA8: 0x7FF5, //CJK UNIFIED IDEOGRAPH + 0xEFA9: 0x9D2D, //CJK UNIFIED IDEOGRAPH + 0xEFAA: 0x9E8A, //CJK UNIFIED IDEOGRAPH + 0xEFAB: 0x9E89, //CJK UNIFIED IDEOGRAPH + 0xEFAC: 0x9E8D, //CJK UNIFIED IDEOGRAPH + 0xEFAD: 0x9EB0, //CJK UNIFIED IDEOGRAPH + 0xEFAE: 0x9EC8, //CJK UNIFIED IDEOGRAPH + 0xEFAF: 0x9EDA, //CJK UNIFIED IDEOGRAPH + 0xEFB0: 0x9EFB, //CJK UNIFIED IDEOGRAPH + 0xEFB1: 0x9EFF, //CJK UNIFIED IDEOGRAPH + 0xEFB2: 0x9F24, //CJK UNIFIED IDEOGRAPH + 0xEFB3: 0x9F23, //CJK UNIFIED IDEOGRAPH + 0xEFB4: 0x9F22, //CJK UNIFIED IDEOGRAPH + 0xEFB5: 0x9F54, //CJK UNIFIED IDEOGRAPH + 0xEFB6: 0x9FA0, //CJK UNIFIED IDEOGRAPH + 0xEFB7: 0x5131, //CJK UNIFIED IDEOGRAPH + 0xEFB8: 0x512D, //CJK UNIFIED IDEOGRAPH + 0xEFB9: 0x512E, //CJK UNIFIED IDEOGRAPH + 0xEFBA: 0x5698, //CJK UNIFIED IDEOGRAPH + 0xEFBB: 0x569C, //CJK UNIFIED IDEOGRAPH + 0xEFBC: 0x5697, //CJK UNIFIED IDEOGRAPH + 0xEFBD: 0x569A, //CJK UNIFIED IDEOGRAPH + 0xEFBE: 0x569D, //CJK UNIFIED IDEOGRAPH + 0xEFBF: 0x5699, //CJK UNIFIED IDEOGRAPH + 0xEFC0: 0x5970, //CJK UNIFIED IDEOGRAPH + 0xEFC1: 0x5B3C, //CJK UNIFIED IDEOGRAPH + 0xEFC2: 0x5C69, //CJK UNIFIED IDEOGRAPH + 0xEFC3: 0x5C6A, //CJK UNIFIED IDEOGRAPH + 0xEFC4: 0x5DC0, //CJK UNIFIED IDEOGRAPH + 0xEFC5: 0x5E6D, //CJK UNIFIED IDEOGRAPH + 0xEFC6: 0x5E6E, //CJK UNIFIED IDEOGRAPH + 0xEFC7: 0x61D8, //CJK UNIFIED IDEOGRAPH + 0xEFC8: 0x61DF, //CJK UNIFIED IDEOGRAPH + 0xEFC9: 0x61ED, //CJK UNIFIED IDEOGRAPH + 0xEFCA: 0x61EE, //CJK UNIFIED IDEOGRAPH + 0xEFCB: 0x61F1, //CJK UNIFIED IDEOGRAPH + 0xEFCC: 0x61EA, //CJK UNIFIED IDEOGRAPH + 0xEFCD: 0x61F0, //CJK UNIFIED IDEOGRAPH + 0xEFCE: 0x61EB, //CJK UNIFIED IDEOGRAPH + 0xEFCF: 0x61D6, //CJK UNIFIED IDEOGRAPH + 0xEFD0: 0x61E9, //CJK UNIFIED IDEOGRAPH + 0xEFD1: 0x64FF, //CJK UNIFIED IDEOGRAPH + 0xEFD2: 0x6504, //CJK UNIFIED IDEOGRAPH + 0xEFD3: 0x64FD, //CJK UNIFIED IDEOGRAPH + 0xEFD4: 0x64F8, //CJK UNIFIED IDEOGRAPH + 0xEFD5: 0x6501, //CJK UNIFIED IDEOGRAPH + 0xEFD6: 0x6503, //CJK UNIFIED IDEOGRAPH + 0xEFD7: 0x64FC, //CJK UNIFIED IDEOGRAPH + 0xEFD8: 0x6594, //CJK UNIFIED IDEOGRAPH + 0xEFD9: 0x65DB, //CJK UNIFIED IDEOGRAPH + 0xEFDA: 0x66DA, //CJK UNIFIED IDEOGRAPH + 0xEFDB: 0x66DB, //CJK UNIFIED IDEOGRAPH + 0xEFDC: 0x66D8, //CJK UNIFIED IDEOGRAPH + 0xEFDD: 0x6AC5, //CJK UNIFIED IDEOGRAPH + 0xEFDE: 0x6AB9, //CJK UNIFIED IDEOGRAPH + 0xEFDF: 0x6ABD, //CJK UNIFIED IDEOGRAPH + 0xEFE0: 0x6AE1, //CJK UNIFIED IDEOGRAPH + 0xEFE1: 0x6AC6, //CJK UNIFIED IDEOGRAPH + 0xEFE2: 0x6ABA, //CJK UNIFIED IDEOGRAPH + 0xEFE3: 0x6AB6, //CJK UNIFIED IDEOGRAPH + 0xEFE4: 0x6AB7, //CJK UNIFIED IDEOGRAPH + 0xEFE5: 0x6AC7, //CJK UNIFIED IDEOGRAPH + 0xEFE6: 0x6AB4, //CJK UNIFIED IDEOGRAPH + 0xEFE7: 0x6AAD, //CJK UNIFIED IDEOGRAPH + 0xEFE8: 0x6B5E, //CJK UNIFIED IDEOGRAPH + 0xEFE9: 0x6BC9, //CJK UNIFIED IDEOGRAPH + 0xEFEA: 0x6C0B, //CJK UNIFIED IDEOGRAPH + 0xEFEB: 0x7007, //CJK UNIFIED IDEOGRAPH + 0xEFEC: 0x700C, //CJK UNIFIED IDEOGRAPH + 0xEFED: 0x700D, //CJK UNIFIED IDEOGRAPH + 0xEFEE: 0x7001, //CJK UNIFIED IDEOGRAPH + 0xEFEF: 0x7005, //CJK UNIFIED IDEOGRAPH + 0xEFF0: 0x7014, //CJK UNIFIED IDEOGRAPH + 0xEFF1: 0x700E, //CJK UNIFIED IDEOGRAPH + 0xEFF2: 0x6FFF, //CJK UNIFIED IDEOGRAPH + 0xEFF3: 0x7000, //CJK UNIFIED IDEOGRAPH + 0xEFF4: 0x6FFB, //CJK UNIFIED IDEOGRAPH + 0xEFF5: 0x7026, //CJK UNIFIED IDEOGRAPH + 0xEFF6: 0x6FFC, //CJK UNIFIED IDEOGRAPH + 0xEFF7: 0x6FF7, //CJK UNIFIED IDEOGRAPH + 0xEFF8: 0x700A, //CJK UNIFIED IDEOGRAPH + 0xEFF9: 0x7201, //CJK UNIFIED IDEOGRAPH + 0xEFFA: 0x71FF, //CJK UNIFIED IDEOGRAPH + 0xEFFB: 0x71F9, //CJK UNIFIED IDEOGRAPH + 0xEFFC: 0x7203, //CJK UNIFIED IDEOGRAPH + 0xEFFD: 0x71FD, //CJK UNIFIED IDEOGRAPH + 0xEFFE: 0x7376, //CJK UNIFIED IDEOGRAPH + 0xF040: 0x74B8, //CJK UNIFIED IDEOGRAPH + 0xF041: 0x74C0, //CJK UNIFIED IDEOGRAPH + 0xF042: 0x74B5, //CJK UNIFIED IDEOGRAPH + 0xF043: 0x74C1, //CJK UNIFIED IDEOGRAPH + 0xF044: 0x74BE, //CJK UNIFIED IDEOGRAPH + 0xF045: 0x74B6, //CJK UNIFIED IDEOGRAPH + 0xF046: 0x74BB, //CJK UNIFIED IDEOGRAPH + 0xF047: 0x74C2, //CJK UNIFIED IDEOGRAPH + 0xF048: 0x7514, //CJK UNIFIED IDEOGRAPH + 0xF049: 0x7513, //CJK UNIFIED IDEOGRAPH + 0xF04A: 0x765C, //CJK UNIFIED IDEOGRAPH + 0xF04B: 0x7664, //CJK UNIFIED IDEOGRAPH + 0xF04C: 0x7659, //CJK UNIFIED IDEOGRAPH + 0xF04D: 0x7650, //CJK UNIFIED IDEOGRAPH + 0xF04E: 0x7653, //CJK UNIFIED IDEOGRAPH + 0xF04F: 0x7657, //CJK UNIFIED IDEOGRAPH + 0xF050: 0x765A, //CJK UNIFIED IDEOGRAPH + 0xF051: 0x76A6, //CJK UNIFIED IDEOGRAPH + 0xF052: 0x76BD, //CJK UNIFIED IDEOGRAPH + 0xF053: 0x76EC, //CJK UNIFIED IDEOGRAPH + 0xF054: 0x77C2, //CJK UNIFIED IDEOGRAPH + 0xF055: 0x77BA, //CJK UNIFIED IDEOGRAPH + 0xF056: 0x78FF, //CJK UNIFIED IDEOGRAPH + 0xF057: 0x790C, //CJK UNIFIED IDEOGRAPH + 0xF058: 0x7913, //CJK UNIFIED IDEOGRAPH + 0xF059: 0x7914, //CJK UNIFIED IDEOGRAPH + 0xF05A: 0x7909, //CJK UNIFIED IDEOGRAPH + 0xF05B: 0x7910, //CJK UNIFIED IDEOGRAPH + 0xF05C: 0x7912, //CJK UNIFIED IDEOGRAPH + 0xF05D: 0x7911, //CJK UNIFIED IDEOGRAPH + 0xF05E: 0x79AD, //CJK UNIFIED IDEOGRAPH + 0xF05F: 0x79AC, //CJK UNIFIED IDEOGRAPH + 0xF060: 0x7A5F, //CJK UNIFIED IDEOGRAPH + 0xF061: 0x7C1C, //CJK UNIFIED IDEOGRAPH + 0xF062: 0x7C29, //CJK UNIFIED IDEOGRAPH + 0xF063: 0x7C19, //CJK UNIFIED IDEOGRAPH + 0xF064: 0x7C20, //CJK UNIFIED IDEOGRAPH + 0xF065: 0x7C1F, //CJK UNIFIED IDEOGRAPH + 0xF066: 0x7C2D, //CJK UNIFIED IDEOGRAPH + 0xF067: 0x7C1D, //CJK UNIFIED IDEOGRAPH + 0xF068: 0x7C26, //CJK UNIFIED IDEOGRAPH + 0xF069: 0x7C28, //CJK UNIFIED IDEOGRAPH + 0xF06A: 0x7C22, //CJK UNIFIED IDEOGRAPH + 0xF06B: 0x7C25, //CJK UNIFIED IDEOGRAPH + 0xF06C: 0x7C30, //CJK UNIFIED IDEOGRAPH + 0xF06D: 0x7E5C, //CJK UNIFIED IDEOGRAPH + 0xF06E: 0x7E50, //CJK UNIFIED IDEOGRAPH + 0xF06F: 0x7E56, //CJK UNIFIED IDEOGRAPH + 0xF070: 0x7E63, //CJK UNIFIED IDEOGRAPH + 0xF071: 0x7E58, //CJK UNIFIED IDEOGRAPH + 0xF072: 0x7E62, //CJK UNIFIED IDEOGRAPH + 0xF073: 0x7E5F, //CJK UNIFIED IDEOGRAPH + 0xF074: 0x7E51, //CJK UNIFIED IDEOGRAPH + 0xF075: 0x7E60, //CJK UNIFIED IDEOGRAPH + 0xF076: 0x7E57, //CJK UNIFIED IDEOGRAPH + 0xF077: 0x7E53, //CJK UNIFIED IDEOGRAPH + 0xF078: 0x7FB5, //CJK UNIFIED IDEOGRAPH + 0xF079: 0x7FB3, //CJK UNIFIED IDEOGRAPH + 0xF07A: 0x7FF7, //CJK UNIFIED IDEOGRAPH + 0xF07B: 0x7FF8, //CJK UNIFIED IDEOGRAPH + 0xF07C: 0x8075, //CJK UNIFIED IDEOGRAPH + 0xF07D: 0x81D1, //CJK UNIFIED IDEOGRAPH + 0xF07E: 0x81D2, //CJK UNIFIED IDEOGRAPH + 0xF0A1: 0x81D0, //CJK UNIFIED IDEOGRAPH + 0xF0A2: 0x825F, //CJK UNIFIED IDEOGRAPH + 0xF0A3: 0x825E, //CJK UNIFIED IDEOGRAPH + 0xF0A4: 0x85B4, //CJK UNIFIED IDEOGRAPH + 0xF0A5: 0x85C6, //CJK UNIFIED IDEOGRAPH + 0xF0A6: 0x85C0, //CJK UNIFIED IDEOGRAPH + 0xF0A7: 0x85C3, //CJK UNIFIED IDEOGRAPH + 0xF0A8: 0x85C2, //CJK UNIFIED IDEOGRAPH + 0xF0A9: 0x85B3, //CJK UNIFIED IDEOGRAPH + 0xF0AA: 0x85B5, //CJK UNIFIED IDEOGRAPH + 0xF0AB: 0x85BD, //CJK UNIFIED IDEOGRAPH + 0xF0AC: 0x85C7, //CJK UNIFIED IDEOGRAPH + 0xF0AD: 0x85C4, //CJK UNIFIED IDEOGRAPH + 0xF0AE: 0x85BF, //CJK UNIFIED IDEOGRAPH + 0xF0AF: 0x85CB, //CJK UNIFIED IDEOGRAPH + 0xF0B0: 0x85CE, //CJK UNIFIED IDEOGRAPH + 0xF0B1: 0x85C8, //CJK UNIFIED IDEOGRAPH + 0xF0B2: 0x85C5, //CJK UNIFIED IDEOGRAPH + 0xF0B3: 0x85B1, //CJK UNIFIED IDEOGRAPH + 0xF0B4: 0x85B6, //CJK UNIFIED IDEOGRAPH + 0xF0B5: 0x85D2, //CJK UNIFIED IDEOGRAPH + 0xF0B6: 0x8624, //CJK UNIFIED IDEOGRAPH + 0xF0B7: 0x85B8, //CJK UNIFIED IDEOGRAPH + 0xF0B8: 0x85B7, //CJK UNIFIED IDEOGRAPH + 0xF0B9: 0x85BE, //CJK UNIFIED IDEOGRAPH + 0xF0BA: 0x8669, //CJK UNIFIED IDEOGRAPH + 0xF0BB: 0x87E7, //CJK UNIFIED IDEOGRAPH + 0xF0BC: 0x87E6, //CJK UNIFIED IDEOGRAPH + 0xF0BD: 0x87E2, //CJK UNIFIED IDEOGRAPH + 0xF0BE: 0x87DB, //CJK UNIFIED IDEOGRAPH + 0xF0BF: 0x87EB, //CJK UNIFIED IDEOGRAPH + 0xF0C0: 0x87EA, //CJK UNIFIED IDEOGRAPH + 0xF0C1: 0x87E5, //CJK UNIFIED IDEOGRAPH + 0xF0C2: 0x87DF, //CJK UNIFIED IDEOGRAPH + 0xF0C3: 0x87F3, //CJK UNIFIED IDEOGRAPH + 0xF0C4: 0x87E4, //CJK UNIFIED IDEOGRAPH + 0xF0C5: 0x87D4, //CJK UNIFIED IDEOGRAPH + 0xF0C6: 0x87DC, //CJK UNIFIED IDEOGRAPH + 0xF0C7: 0x87D3, //CJK UNIFIED IDEOGRAPH + 0xF0C8: 0x87ED, //CJK UNIFIED IDEOGRAPH + 0xF0C9: 0x87D8, //CJK UNIFIED IDEOGRAPH + 0xF0CA: 0x87E3, //CJK UNIFIED IDEOGRAPH + 0xF0CB: 0x87A4, //CJK UNIFIED IDEOGRAPH + 0xF0CC: 0x87D7, //CJK UNIFIED IDEOGRAPH + 0xF0CD: 0x87D9, //CJK UNIFIED IDEOGRAPH + 0xF0CE: 0x8801, //CJK UNIFIED IDEOGRAPH + 0xF0CF: 0x87F4, //CJK UNIFIED IDEOGRAPH + 0xF0D0: 0x87E8, //CJK UNIFIED IDEOGRAPH + 0xF0D1: 0x87DD, //CJK UNIFIED IDEOGRAPH + 0xF0D2: 0x8953, //CJK UNIFIED IDEOGRAPH + 0xF0D3: 0x894B, //CJK UNIFIED IDEOGRAPH + 0xF0D4: 0x894F, //CJK UNIFIED IDEOGRAPH + 0xF0D5: 0x894C, //CJK UNIFIED IDEOGRAPH + 0xF0D6: 0x8946, //CJK UNIFIED IDEOGRAPH + 0xF0D7: 0x8950, //CJK UNIFIED IDEOGRAPH + 0xF0D8: 0x8951, //CJK UNIFIED IDEOGRAPH + 0xF0D9: 0x8949, //CJK UNIFIED IDEOGRAPH + 0xF0DA: 0x8B2A, //CJK UNIFIED IDEOGRAPH + 0xF0DB: 0x8B27, //CJK UNIFIED IDEOGRAPH + 0xF0DC: 0x8B23, //CJK UNIFIED IDEOGRAPH + 0xF0DD: 0x8B33, //CJK UNIFIED IDEOGRAPH + 0xF0DE: 0x8B30, //CJK UNIFIED IDEOGRAPH + 0xF0DF: 0x8B35, //CJK UNIFIED IDEOGRAPH + 0xF0E0: 0x8B47, //CJK UNIFIED IDEOGRAPH + 0xF0E1: 0x8B2F, //CJK UNIFIED IDEOGRAPH + 0xF0E2: 0x8B3C, //CJK UNIFIED IDEOGRAPH + 0xF0E3: 0x8B3E, //CJK UNIFIED IDEOGRAPH + 0xF0E4: 0x8B31, //CJK UNIFIED IDEOGRAPH + 0xF0E5: 0x8B25, //CJK UNIFIED IDEOGRAPH + 0xF0E6: 0x8B37, //CJK UNIFIED IDEOGRAPH + 0xF0E7: 0x8B26, //CJK UNIFIED IDEOGRAPH + 0xF0E8: 0x8B36, //CJK UNIFIED IDEOGRAPH + 0xF0E9: 0x8B2E, //CJK UNIFIED IDEOGRAPH + 0xF0EA: 0x8B24, //CJK UNIFIED IDEOGRAPH + 0xF0EB: 0x8B3B, //CJK UNIFIED IDEOGRAPH + 0xF0EC: 0x8B3D, //CJK UNIFIED IDEOGRAPH + 0xF0ED: 0x8B3A, //CJK UNIFIED IDEOGRAPH + 0xF0EE: 0x8C42, //CJK UNIFIED IDEOGRAPH + 0xF0EF: 0x8C75, //CJK UNIFIED IDEOGRAPH + 0xF0F0: 0x8C99, //CJK UNIFIED IDEOGRAPH + 0xF0F1: 0x8C98, //CJK UNIFIED IDEOGRAPH + 0xF0F2: 0x8C97, //CJK UNIFIED IDEOGRAPH + 0xF0F3: 0x8CFE, //CJK UNIFIED IDEOGRAPH + 0xF0F4: 0x8D04, //CJK UNIFIED IDEOGRAPH + 0xF0F5: 0x8D02, //CJK UNIFIED IDEOGRAPH + 0xF0F6: 0x8D00, //CJK UNIFIED IDEOGRAPH + 0xF0F7: 0x8E5C, //CJK UNIFIED IDEOGRAPH + 0xF0F8: 0x8E62, //CJK UNIFIED IDEOGRAPH + 0xF0F9: 0x8E60, //CJK UNIFIED IDEOGRAPH + 0xF0FA: 0x8E57, //CJK UNIFIED IDEOGRAPH + 0xF0FB: 0x8E56, //CJK UNIFIED IDEOGRAPH + 0xF0FC: 0x8E5E, //CJK UNIFIED IDEOGRAPH + 0xF0FD: 0x8E65, //CJK UNIFIED IDEOGRAPH + 0xF0FE: 0x8E67, //CJK UNIFIED IDEOGRAPH + 0xF140: 0x8E5B, //CJK UNIFIED IDEOGRAPH + 0xF141: 0x8E5A, //CJK UNIFIED IDEOGRAPH + 0xF142: 0x8E61, //CJK UNIFIED IDEOGRAPH + 0xF143: 0x8E5D, //CJK UNIFIED IDEOGRAPH + 0xF144: 0x8E69, //CJK UNIFIED IDEOGRAPH + 0xF145: 0x8E54, //CJK UNIFIED IDEOGRAPH + 0xF146: 0x8F46, //CJK UNIFIED IDEOGRAPH + 0xF147: 0x8F47, //CJK UNIFIED IDEOGRAPH + 0xF148: 0x8F48, //CJK UNIFIED IDEOGRAPH + 0xF149: 0x8F4B, //CJK UNIFIED IDEOGRAPH + 0xF14A: 0x9128, //CJK UNIFIED IDEOGRAPH + 0xF14B: 0x913A, //CJK UNIFIED IDEOGRAPH + 0xF14C: 0x913B, //CJK UNIFIED IDEOGRAPH + 0xF14D: 0x913E, //CJK UNIFIED IDEOGRAPH + 0xF14E: 0x91A8, //CJK UNIFIED IDEOGRAPH + 0xF14F: 0x91A5, //CJK UNIFIED IDEOGRAPH + 0xF150: 0x91A7, //CJK UNIFIED IDEOGRAPH + 0xF151: 0x91AF, //CJK UNIFIED IDEOGRAPH + 0xF152: 0x91AA, //CJK UNIFIED IDEOGRAPH + 0xF153: 0x93B5, //CJK UNIFIED IDEOGRAPH + 0xF154: 0x938C, //CJK UNIFIED IDEOGRAPH + 0xF155: 0x9392, //CJK UNIFIED IDEOGRAPH + 0xF156: 0x93B7, //CJK UNIFIED IDEOGRAPH + 0xF157: 0x939B, //CJK UNIFIED IDEOGRAPH + 0xF158: 0x939D, //CJK UNIFIED IDEOGRAPH + 0xF159: 0x9389, //CJK UNIFIED IDEOGRAPH + 0xF15A: 0x93A7, //CJK UNIFIED IDEOGRAPH + 0xF15B: 0x938E, //CJK UNIFIED IDEOGRAPH + 0xF15C: 0x93AA, //CJK UNIFIED IDEOGRAPH + 0xF15D: 0x939E, //CJK UNIFIED IDEOGRAPH + 0xF15E: 0x93A6, //CJK UNIFIED IDEOGRAPH + 0xF15F: 0x9395, //CJK UNIFIED IDEOGRAPH + 0xF160: 0x9388, //CJK UNIFIED IDEOGRAPH + 0xF161: 0x9399, //CJK UNIFIED IDEOGRAPH + 0xF162: 0x939F, //CJK UNIFIED IDEOGRAPH + 0xF163: 0x938D, //CJK UNIFIED IDEOGRAPH + 0xF164: 0x93B1, //CJK UNIFIED IDEOGRAPH + 0xF165: 0x9391, //CJK UNIFIED IDEOGRAPH + 0xF166: 0x93B2, //CJK UNIFIED IDEOGRAPH + 0xF167: 0x93A4, //CJK UNIFIED IDEOGRAPH + 0xF168: 0x93A8, //CJK UNIFIED IDEOGRAPH + 0xF169: 0x93B4, //CJK UNIFIED IDEOGRAPH + 0xF16A: 0x93A3, //CJK UNIFIED IDEOGRAPH + 0xF16B: 0x93A5, //CJK UNIFIED IDEOGRAPH + 0xF16C: 0x95D2, //CJK UNIFIED IDEOGRAPH + 0xF16D: 0x95D3, //CJK UNIFIED IDEOGRAPH + 0xF16E: 0x95D1, //CJK UNIFIED IDEOGRAPH + 0xF16F: 0x96B3, //CJK UNIFIED IDEOGRAPH + 0xF170: 0x96D7, //CJK UNIFIED IDEOGRAPH + 0xF171: 0x96DA, //CJK UNIFIED IDEOGRAPH + 0xF172: 0x5DC2, //CJK UNIFIED IDEOGRAPH + 0xF173: 0x96DF, //CJK UNIFIED IDEOGRAPH + 0xF174: 0x96D8, //CJK UNIFIED IDEOGRAPH + 0xF175: 0x96DD, //CJK UNIFIED IDEOGRAPH + 0xF176: 0x9723, //CJK UNIFIED IDEOGRAPH + 0xF177: 0x9722, //CJK UNIFIED IDEOGRAPH + 0xF178: 0x9725, //CJK UNIFIED IDEOGRAPH + 0xF179: 0x97AC, //CJK UNIFIED IDEOGRAPH + 0xF17A: 0x97AE, //CJK UNIFIED IDEOGRAPH + 0xF17B: 0x97A8, //CJK UNIFIED IDEOGRAPH + 0xF17C: 0x97AB, //CJK UNIFIED IDEOGRAPH + 0xF17D: 0x97A4, //CJK UNIFIED IDEOGRAPH + 0xF17E: 0x97AA, //CJK UNIFIED IDEOGRAPH + 0xF1A1: 0x97A2, //CJK UNIFIED IDEOGRAPH + 0xF1A2: 0x97A5, //CJK UNIFIED IDEOGRAPH + 0xF1A3: 0x97D7, //CJK UNIFIED IDEOGRAPH + 0xF1A4: 0x97D9, //CJK UNIFIED IDEOGRAPH + 0xF1A5: 0x97D6, //CJK UNIFIED IDEOGRAPH + 0xF1A6: 0x97D8, //CJK UNIFIED IDEOGRAPH + 0xF1A7: 0x97FA, //CJK UNIFIED IDEOGRAPH + 0xF1A8: 0x9850, //CJK UNIFIED IDEOGRAPH + 0xF1A9: 0x9851, //CJK UNIFIED IDEOGRAPH + 0xF1AA: 0x9852, //CJK UNIFIED IDEOGRAPH + 0xF1AB: 0x98B8, //CJK UNIFIED IDEOGRAPH + 0xF1AC: 0x9941, //CJK UNIFIED IDEOGRAPH + 0xF1AD: 0x993C, //CJK UNIFIED IDEOGRAPH + 0xF1AE: 0x993A, //CJK UNIFIED IDEOGRAPH + 0xF1AF: 0x9A0F, //CJK UNIFIED IDEOGRAPH + 0xF1B0: 0x9A0B, //CJK UNIFIED IDEOGRAPH + 0xF1B1: 0x9A09, //CJK UNIFIED IDEOGRAPH + 0xF1B2: 0x9A0D, //CJK UNIFIED IDEOGRAPH + 0xF1B3: 0x9A04, //CJK UNIFIED IDEOGRAPH + 0xF1B4: 0x9A11, //CJK UNIFIED IDEOGRAPH + 0xF1B5: 0x9A0A, //CJK UNIFIED IDEOGRAPH + 0xF1B6: 0x9A05, //CJK UNIFIED IDEOGRAPH + 0xF1B7: 0x9A07, //CJK UNIFIED IDEOGRAPH + 0xF1B8: 0x9A06, //CJK UNIFIED IDEOGRAPH + 0xF1B9: 0x9AC0, //CJK UNIFIED IDEOGRAPH + 0xF1BA: 0x9ADC, //CJK UNIFIED IDEOGRAPH + 0xF1BB: 0x9B08, //CJK UNIFIED IDEOGRAPH + 0xF1BC: 0x9B04, //CJK UNIFIED IDEOGRAPH + 0xF1BD: 0x9B05, //CJK UNIFIED IDEOGRAPH + 0xF1BE: 0x9B29, //CJK UNIFIED IDEOGRAPH + 0xF1BF: 0x9B35, //CJK UNIFIED IDEOGRAPH + 0xF1C0: 0x9B4A, //CJK UNIFIED IDEOGRAPH + 0xF1C1: 0x9B4C, //CJK UNIFIED IDEOGRAPH + 0xF1C2: 0x9B4B, //CJK UNIFIED IDEOGRAPH + 0xF1C3: 0x9BC7, //CJK UNIFIED IDEOGRAPH + 0xF1C4: 0x9BC6, //CJK UNIFIED IDEOGRAPH + 0xF1C5: 0x9BC3, //CJK UNIFIED IDEOGRAPH + 0xF1C6: 0x9BBF, //CJK UNIFIED IDEOGRAPH + 0xF1C7: 0x9BC1, //CJK UNIFIED IDEOGRAPH + 0xF1C8: 0x9BB5, //CJK UNIFIED IDEOGRAPH + 0xF1C9: 0x9BB8, //CJK UNIFIED IDEOGRAPH + 0xF1CA: 0x9BD3, //CJK UNIFIED IDEOGRAPH + 0xF1CB: 0x9BB6, //CJK UNIFIED IDEOGRAPH + 0xF1CC: 0x9BC4, //CJK UNIFIED IDEOGRAPH + 0xF1CD: 0x9BB9, //CJK UNIFIED IDEOGRAPH + 0xF1CE: 0x9BBD, //CJK UNIFIED IDEOGRAPH + 0xF1CF: 0x9D5C, //CJK UNIFIED IDEOGRAPH + 0xF1D0: 0x9D53, //CJK UNIFIED IDEOGRAPH + 0xF1D1: 0x9D4F, //CJK UNIFIED IDEOGRAPH + 0xF1D2: 0x9D4A, //CJK UNIFIED IDEOGRAPH + 0xF1D3: 0x9D5B, //CJK UNIFIED IDEOGRAPH + 0xF1D4: 0x9D4B, //CJK UNIFIED IDEOGRAPH + 0xF1D5: 0x9D59, //CJK UNIFIED IDEOGRAPH + 0xF1D6: 0x9D56, //CJK UNIFIED IDEOGRAPH + 0xF1D7: 0x9D4C, //CJK UNIFIED IDEOGRAPH + 0xF1D8: 0x9D57, //CJK UNIFIED IDEOGRAPH + 0xF1D9: 0x9D52, //CJK UNIFIED IDEOGRAPH + 0xF1DA: 0x9D54, //CJK UNIFIED IDEOGRAPH + 0xF1DB: 0x9D5F, //CJK UNIFIED IDEOGRAPH + 0xF1DC: 0x9D58, //CJK UNIFIED IDEOGRAPH + 0xF1DD: 0x9D5A, //CJK UNIFIED IDEOGRAPH + 0xF1DE: 0x9E8E, //CJK UNIFIED IDEOGRAPH + 0xF1DF: 0x9E8C, //CJK UNIFIED IDEOGRAPH + 0xF1E0: 0x9EDF, //CJK UNIFIED IDEOGRAPH + 0xF1E1: 0x9F01, //CJK UNIFIED IDEOGRAPH + 0xF1E2: 0x9F00, //CJK UNIFIED IDEOGRAPH + 0xF1E3: 0x9F16, //CJK UNIFIED IDEOGRAPH + 0xF1E4: 0x9F25, //CJK UNIFIED IDEOGRAPH + 0xF1E5: 0x9F2B, //CJK UNIFIED IDEOGRAPH + 0xF1E6: 0x9F2A, //CJK UNIFIED IDEOGRAPH + 0xF1E7: 0x9F29, //CJK UNIFIED IDEOGRAPH + 0xF1E8: 0x9F28, //CJK UNIFIED IDEOGRAPH + 0xF1E9: 0x9F4C, //CJK UNIFIED IDEOGRAPH + 0xF1EA: 0x9F55, //CJK UNIFIED IDEOGRAPH + 0xF1EB: 0x5134, //CJK UNIFIED IDEOGRAPH + 0xF1EC: 0x5135, //CJK UNIFIED IDEOGRAPH + 0xF1ED: 0x5296, //CJK UNIFIED IDEOGRAPH + 0xF1EE: 0x52F7, //CJK UNIFIED IDEOGRAPH + 0xF1EF: 0x53B4, //CJK UNIFIED IDEOGRAPH + 0xF1F0: 0x56AB, //CJK UNIFIED IDEOGRAPH + 0xF1F1: 0x56AD, //CJK UNIFIED IDEOGRAPH + 0xF1F2: 0x56A6, //CJK UNIFIED IDEOGRAPH + 0xF1F3: 0x56A7, //CJK UNIFIED IDEOGRAPH + 0xF1F4: 0x56AA, //CJK UNIFIED IDEOGRAPH + 0xF1F5: 0x56AC, //CJK UNIFIED IDEOGRAPH + 0xF1F6: 0x58DA, //CJK UNIFIED IDEOGRAPH + 0xF1F7: 0x58DD, //CJK UNIFIED IDEOGRAPH + 0xF1F8: 0x58DB, //CJK UNIFIED IDEOGRAPH + 0xF1F9: 0x5912, //CJK UNIFIED IDEOGRAPH + 0xF1FA: 0x5B3D, //CJK UNIFIED IDEOGRAPH + 0xF1FB: 0x5B3E, //CJK UNIFIED IDEOGRAPH + 0xF1FC: 0x5B3F, //CJK UNIFIED IDEOGRAPH + 0xF1FD: 0x5DC3, //CJK UNIFIED IDEOGRAPH + 0xF1FE: 0x5E70, //CJK UNIFIED IDEOGRAPH + 0xF240: 0x5FBF, //CJK UNIFIED IDEOGRAPH + 0xF241: 0x61FB, //CJK UNIFIED IDEOGRAPH + 0xF242: 0x6507, //CJK UNIFIED IDEOGRAPH + 0xF243: 0x6510, //CJK UNIFIED IDEOGRAPH + 0xF244: 0x650D, //CJK UNIFIED IDEOGRAPH + 0xF245: 0x6509, //CJK UNIFIED IDEOGRAPH + 0xF246: 0x650C, //CJK UNIFIED IDEOGRAPH + 0xF247: 0x650E, //CJK UNIFIED IDEOGRAPH + 0xF248: 0x6584, //CJK UNIFIED IDEOGRAPH + 0xF249: 0x65DE, //CJK UNIFIED IDEOGRAPH + 0xF24A: 0x65DD, //CJK UNIFIED IDEOGRAPH + 0xF24B: 0x66DE, //CJK UNIFIED IDEOGRAPH + 0xF24C: 0x6AE7, //CJK UNIFIED IDEOGRAPH + 0xF24D: 0x6AE0, //CJK UNIFIED IDEOGRAPH + 0xF24E: 0x6ACC, //CJK UNIFIED IDEOGRAPH + 0xF24F: 0x6AD1, //CJK UNIFIED IDEOGRAPH + 0xF250: 0x6AD9, //CJK UNIFIED IDEOGRAPH + 0xF251: 0x6ACB, //CJK UNIFIED IDEOGRAPH + 0xF252: 0x6ADF, //CJK UNIFIED IDEOGRAPH + 0xF253: 0x6ADC, //CJK UNIFIED IDEOGRAPH + 0xF254: 0x6AD0, //CJK UNIFIED IDEOGRAPH + 0xF255: 0x6AEB, //CJK UNIFIED IDEOGRAPH + 0xF256: 0x6ACF, //CJK UNIFIED IDEOGRAPH + 0xF257: 0x6ACD, //CJK UNIFIED IDEOGRAPH + 0xF258: 0x6ADE, //CJK UNIFIED IDEOGRAPH + 0xF259: 0x6B60, //CJK UNIFIED IDEOGRAPH + 0xF25A: 0x6BB0, //CJK UNIFIED IDEOGRAPH + 0xF25B: 0x6C0C, //CJK UNIFIED IDEOGRAPH + 0xF25C: 0x7019, //CJK UNIFIED IDEOGRAPH + 0xF25D: 0x7027, //CJK UNIFIED IDEOGRAPH + 0xF25E: 0x7020, //CJK UNIFIED IDEOGRAPH + 0xF25F: 0x7016, //CJK UNIFIED IDEOGRAPH + 0xF260: 0x702B, //CJK UNIFIED IDEOGRAPH + 0xF261: 0x7021, //CJK UNIFIED IDEOGRAPH + 0xF262: 0x7022, //CJK UNIFIED IDEOGRAPH + 0xF263: 0x7023, //CJK UNIFIED IDEOGRAPH + 0xF264: 0x7029, //CJK UNIFIED IDEOGRAPH + 0xF265: 0x7017, //CJK UNIFIED IDEOGRAPH + 0xF266: 0x7024, //CJK UNIFIED IDEOGRAPH + 0xF267: 0x701C, //CJK UNIFIED IDEOGRAPH + 0xF268: 0x702A, //CJK UNIFIED IDEOGRAPH + 0xF269: 0x720C, //CJK UNIFIED IDEOGRAPH + 0xF26A: 0x720A, //CJK UNIFIED IDEOGRAPH + 0xF26B: 0x7207, //CJK UNIFIED IDEOGRAPH + 0xF26C: 0x7202, //CJK UNIFIED IDEOGRAPH + 0xF26D: 0x7205, //CJK UNIFIED IDEOGRAPH + 0xF26E: 0x72A5, //CJK UNIFIED IDEOGRAPH + 0xF26F: 0x72A6, //CJK UNIFIED IDEOGRAPH + 0xF270: 0x72A4, //CJK UNIFIED IDEOGRAPH + 0xF271: 0x72A3, //CJK UNIFIED IDEOGRAPH + 0xF272: 0x72A1, //CJK UNIFIED IDEOGRAPH + 0xF273: 0x74CB, //CJK UNIFIED IDEOGRAPH + 0xF274: 0x74C5, //CJK UNIFIED IDEOGRAPH + 0xF275: 0x74B7, //CJK UNIFIED IDEOGRAPH + 0xF276: 0x74C3, //CJK UNIFIED IDEOGRAPH + 0xF277: 0x7516, //CJK UNIFIED IDEOGRAPH + 0xF278: 0x7660, //CJK UNIFIED IDEOGRAPH + 0xF279: 0x77C9, //CJK UNIFIED IDEOGRAPH + 0xF27A: 0x77CA, //CJK UNIFIED IDEOGRAPH + 0xF27B: 0x77C4, //CJK UNIFIED IDEOGRAPH + 0xF27C: 0x77F1, //CJK UNIFIED IDEOGRAPH + 0xF27D: 0x791D, //CJK UNIFIED IDEOGRAPH + 0xF27E: 0x791B, //CJK UNIFIED IDEOGRAPH + 0xF2A1: 0x7921, //CJK UNIFIED IDEOGRAPH + 0xF2A2: 0x791C, //CJK UNIFIED IDEOGRAPH + 0xF2A3: 0x7917, //CJK UNIFIED IDEOGRAPH + 0xF2A4: 0x791E, //CJK UNIFIED IDEOGRAPH + 0xF2A5: 0x79B0, //CJK UNIFIED IDEOGRAPH + 0xF2A6: 0x7A67, //CJK UNIFIED IDEOGRAPH + 0xF2A7: 0x7A68, //CJK UNIFIED IDEOGRAPH + 0xF2A8: 0x7C33, //CJK UNIFIED IDEOGRAPH + 0xF2A9: 0x7C3C, //CJK UNIFIED IDEOGRAPH + 0xF2AA: 0x7C39, //CJK UNIFIED IDEOGRAPH + 0xF2AB: 0x7C2C, //CJK UNIFIED IDEOGRAPH + 0xF2AC: 0x7C3B, //CJK UNIFIED IDEOGRAPH + 0xF2AD: 0x7CEC, //CJK UNIFIED IDEOGRAPH + 0xF2AE: 0x7CEA, //CJK UNIFIED IDEOGRAPH + 0xF2AF: 0x7E76, //CJK UNIFIED IDEOGRAPH + 0xF2B0: 0x7E75, //CJK UNIFIED IDEOGRAPH + 0xF2B1: 0x7E78, //CJK UNIFIED IDEOGRAPH + 0xF2B2: 0x7E70, //CJK UNIFIED IDEOGRAPH + 0xF2B3: 0x7E77, //CJK UNIFIED IDEOGRAPH + 0xF2B4: 0x7E6F, //CJK UNIFIED IDEOGRAPH + 0xF2B5: 0x7E7A, //CJK UNIFIED IDEOGRAPH + 0xF2B6: 0x7E72, //CJK UNIFIED IDEOGRAPH + 0xF2B7: 0x7E74, //CJK UNIFIED IDEOGRAPH + 0xF2B8: 0x7E68, //CJK UNIFIED IDEOGRAPH + 0xF2B9: 0x7F4B, //CJK UNIFIED IDEOGRAPH + 0xF2BA: 0x7F4A, //CJK UNIFIED IDEOGRAPH + 0xF2BB: 0x7F83, //CJK UNIFIED IDEOGRAPH + 0xF2BC: 0x7F86, //CJK UNIFIED IDEOGRAPH + 0xF2BD: 0x7FB7, //CJK UNIFIED IDEOGRAPH + 0xF2BE: 0x7FFD, //CJK UNIFIED IDEOGRAPH + 0xF2BF: 0x7FFE, //CJK UNIFIED IDEOGRAPH + 0xF2C0: 0x8078, //CJK UNIFIED IDEOGRAPH + 0xF2C1: 0x81D7, //CJK UNIFIED IDEOGRAPH + 0xF2C2: 0x81D5, //CJK UNIFIED IDEOGRAPH + 0xF2C3: 0x8264, //CJK UNIFIED IDEOGRAPH + 0xF2C4: 0x8261, //CJK UNIFIED IDEOGRAPH + 0xF2C5: 0x8263, //CJK UNIFIED IDEOGRAPH + 0xF2C6: 0x85EB, //CJK UNIFIED IDEOGRAPH + 0xF2C7: 0x85F1, //CJK UNIFIED IDEOGRAPH + 0xF2C8: 0x85ED, //CJK UNIFIED IDEOGRAPH + 0xF2C9: 0x85D9, //CJK UNIFIED IDEOGRAPH + 0xF2CA: 0x85E1, //CJK UNIFIED IDEOGRAPH + 0xF2CB: 0x85E8, //CJK UNIFIED IDEOGRAPH + 0xF2CC: 0x85DA, //CJK UNIFIED IDEOGRAPH + 0xF2CD: 0x85D7, //CJK UNIFIED IDEOGRAPH + 0xF2CE: 0x85EC, //CJK UNIFIED IDEOGRAPH + 0xF2CF: 0x85F2, //CJK UNIFIED IDEOGRAPH + 0xF2D0: 0x85F8, //CJK UNIFIED IDEOGRAPH + 0xF2D1: 0x85D8, //CJK UNIFIED IDEOGRAPH + 0xF2D2: 0x85DF, //CJK UNIFIED IDEOGRAPH + 0xF2D3: 0x85E3, //CJK UNIFIED IDEOGRAPH + 0xF2D4: 0x85DC, //CJK UNIFIED IDEOGRAPH + 0xF2D5: 0x85D1, //CJK UNIFIED IDEOGRAPH + 0xF2D6: 0x85F0, //CJK UNIFIED IDEOGRAPH + 0xF2D7: 0x85E6, //CJK UNIFIED IDEOGRAPH + 0xF2D8: 0x85EF, //CJK UNIFIED IDEOGRAPH + 0xF2D9: 0x85DE, //CJK UNIFIED IDEOGRAPH + 0xF2DA: 0x85E2, //CJK UNIFIED IDEOGRAPH + 0xF2DB: 0x8800, //CJK UNIFIED IDEOGRAPH + 0xF2DC: 0x87FA, //CJK UNIFIED IDEOGRAPH + 0xF2DD: 0x8803, //CJK UNIFIED IDEOGRAPH + 0xF2DE: 0x87F6, //CJK UNIFIED IDEOGRAPH + 0xF2DF: 0x87F7, //CJK UNIFIED IDEOGRAPH + 0xF2E0: 0x8809, //CJK UNIFIED IDEOGRAPH + 0xF2E1: 0x880C, //CJK UNIFIED IDEOGRAPH + 0xF2E2: 0x880B, //CJK UNIFIED IDEOGRAPH + 0xF2E3: 0x8806, //CJK UNIFIED IDEOGRAPH + 0xF2E4: 0x87FC, //CJK UNIFIED IDEOGRAPH + 0xF2E5: 0x8808, //CJK UNIFIED IDEOGRAPH + 0xF2E6: 0x87FF, //CJK UNIFIED IDEOGRAPH + 0xF2E7: 0x880A, //CJK UNIFIED IDEOGRAPH + 0xF2E8: 0x8802, //CJK UNIFIED IDEOGRAPH + 0xF2E9: 0x8962, //CJK UNIFIED IDEOGRAPH + 0xF2EA: 0x895A, //CJK UNIFIED IDEOGRAPH + 0xF2EB: 0x895B, //CJK UNIFIED IDEOGRAPH + 0xF2EC: 0x8957, //CJK UNIFIED IDEOGRAPH + 0xF2ED: 0x8961, //CJK UNIFIED IDEOGRAPH + 0xF2EE: 0x895C, //CJK UNIFIED IDEOGRAPH + 0xF2EF: 0x8958, //CJK UNIFIED IDEOGRAPH + 0xF2F0: 0x895D, //CJK UNIFIED IDEOGRAPH + 0xF2F1: 0x8959, //CJK UNIFIED IDEOGRAPH + 0xF2F2: 0x8988, //CJK UNIFIED IDEOGRAPH + 0xF2F3: 0x89B7, //CJK UNIFIED IDEOGRAPH + 0xF2F4: 0x89B6, //CJK UNIFIED IDEOGRAPH + 0xF2F5: 0x89F6, //CJK UNIFIED IDEOGRAPH + 0xF2F6: 0x8B50, //CJK UNIFIED IDEOGRAPH + 0xF2F7: 0x8B48, //CJK UNIFIED IDEOGRAPH + 0xF2F8: 0x8B4A, //CJK UNIFIED IDEOGRAPH + 0xF2F9: 0x8B40, //CJK UNIFIED IDEOGRAPH + 0xF2FA: 0x8B53, //CJK UNIFIED IDEOGRAPH + 0xF2FB: 0x8B56, //CJK UNIFIED IDEOGRAPH + 0xF2FC: 0x8B54, //CJK UNIFIED IDEOGRAPH + 0xF2FD: 0x8B4B, //CJK UNIFIED IDEOGRAPH + 0xF2FE: 0x8B55, //CJK UNIFIED IDEOGRAPH + 0xF340: 0x8B51, //CJK UNIFIED IDEOGRAPH + 0xF341: 0x8B42, //CJK UNIFIED IDEOGRAPH + 0xF342: 0x8B52, //CJK UNIFIED IDEOGRAPH + 0xF343: 0x8B57, //CJK UNIFIED IDEOGRAPH + 0xF344: 0x8C43, //CJK UNIFIED IDEOGRAPH + 0xF345: 0x8C77, //CJK UNIFIED IDEOGRAPH + 0xF346: 0x8C76, //CJK UNIFIED IDEOGRAPH + 0xF347: 0x8C9A, //CJK UNIFIED IDEOGRAPH + 0xF348: 0x8D06, //CJK UNIFIED IDEOGRAPH + 0xF349: 0x8D07, //CJK UNIFIED IDEOGRAPH + 0xF34A: 0x8D09, //CJK UNIFIED IDEOGRAPH + 0xF34B: 0x8DAC, //CJK UNIFIED IDEOGRAPH + 0xF34C: 0x8DAA, //CJK UNIFIED IDEOGRAPH + 0xF34D: 0x8DAD, //CJK UNIFIED IDEOGRAPH + 0xF34E: 0x8DAB, //CJK UNIFIED IDEOGRAPH + 0xF34F: 0x8E6D, //CJK UNIFIED IDEOGRAPH + 0xF350: 0x8E78, //CJK UNIFIED IDEOGRAPH + 0xF351: 0x8E73, //CJK UNIFIED IDEOGRAPH + 0xF352: 0x8E6A, //CJK UNIFIED IDEOGRAPH + 0xF353: 0x8E6F, //CJK UNIFIED IDEOGRAPH + 0xF354: 0x8E7B, //CJK UNIFIED IDEOGRAPH + 0xF355: 0x8EC2, //CJK UNIFIED IDEOGRAPH + 0xF356: 0x8F52, //CJK UNIFIED IDEOGRAPH + 0xF357: 0x8F51, //CJK UNIFIED IDEOGRAPH + 0xF358: 0x8F4F, //CJK UNIFIED IDEOGRAPH + 0xF359: 0x8F50, //CJK UNIFIED IDEOGRAPH + 0xF35A: 0x8F53, //CJK UNIFIED IDEOGRAPH + 0xF35B: 0x8FB4, //CJK UNIFIED IDEOGRAPH + 0xF35C: 0x9140, //CJK UNIFIED IDEOGRAPH + 0xF35D: 0x913F, //CJK UNIFIED IDEOGRAPH + 0xF35E: 0x91B0, //CJK UNIFIED IDEOGRAPH + 0xF35F: 0x91AD, //CJK UNIFIED IDEOGRAPH + 0xF360: 0x93DE, //CJK UNIFIED IDEOGRAPH + 0xF361: 0x93C7, //CJK UNIFIED IDEOGRAPH + 0xF362: 0x93CF, //CJK UNIFIED IDEOGRAPH + 0xF363: 0x93C2, //CJK UNIFIED IDEOGRAPH + 0xF364: 0x93DA, //CJK UNIFIED IDEOGRAPH + 0xF365: 0x93D0, //CJK UNIFIED IDEOGRAPH + 0xF366: 0x93F9, //CJK UNIFIED IDEOGRAPH + 0xF367: 0x93EC, //CJK UNIFIED IDEOGRAPH + 0xF368: 0x93CC, //CJK UNIFIED IDEOGRAPH + 0xF369: 0x93D9, //CJK UNIFIED IDEOGRAPH + 0xF36A: 0x93A9, //CJK UNIFIED IDEOGRAPH + 0xF36B: 0x93E6, //CJK UNIFIED IDEOGRAPH + 0xF36C: 0x93CA, //CJK UNIFIED IDEOGRAPH + 0xF36D: 0x93D4, //CJK UNIFIED IDEOGRAPH + 0xF36E: 0x93EE, //CJK UNIFIED IDEOGRAPH + 0xF36F: 0x93E3, //CJK UNIFIED IDEOGRAPH + 0xF370: 0x93D5, //CJK UNIFIED IDEOGRAPH + 0xF371: 0x93C4, //CJK UNIFIED IDEOGRAPH + 0xF372: 0x93CE, //CJK UNIFIED IDEOGRAPH + 0xF373: 0x93C0, //CJK UNIFIED IDEOGRAPH + 0xF374: 0x93D2, //CJK UNIFIED IDEOGRAPH + 0xF375: 0x93E7, //CJK UNIFIED IDEOGRAPH + 0xF376: 0x957D, //CJK UNIFIED IDEOGRAPH + 0xF377: 0x95DA, //CJK UNIFIED IDEOGRAPH + 0xF378: 0x95DB, //CJK UNIFIED IDEOGRAPH + 0xF379: 0x96E1, //CJK UNIFIED IDEOGRAPH + 0xF37A: 0x9729, //CJK UNIFIED IDEOGRAPH + 0xF37B: 0x972B, //CJK UNIFIED IDEOGRAPH + 0xF37C: 0x972C, //CJK UNIFIED IDEOGRAPH + 0xF37D: 0x9728, //CJK UNIFIED IDEOGRAPH + 0xF37E: 0x9726, //CJK UNIFIED IDEOGRAPH + 0xF3A1: 0x97B3, //CJK UNIFIED IDEOGRAPH + 0xF3A2: 0x97B7, //CJK UNIFIED IDEOGRAPH + 0xF3A3: 0x97B6, //CJK UNIFIED IDEOGRAPH + 0xF3A4: 0x97DD, //CJK UNIFIED IDEOGRAPH + 0xF3A5: 0x97DE, //CJK UNIFIED IDEOGRAPH + 0xF3A6: 0x97DF, //CJK UNIFIED IDEOGRAPH + 0xF3A7: 0x985C, //CJK UNIFIED IDEOGRAPH + 0xF3A8: 0x9859, //CJK UNIFIED IDEOGRAPH + 0xF3A9: 0x985D, //CJK UNIFIED IDEOGRAPH + 0xF3AA: 0x9857, //CJK UNIFIED IDEOGRAPH + 0xF3AB: 0x98BF, //CJK UNIFIED IDEOGRAPH + 0xF3AC: 0x98BD, //CJK UNIFIED IDEOGRAPH + 0xF3AD: 0x98BB, //CJK UNIFIED IDEOGRAPH + 0xF3AE: 0x98BE, //CJK UNIFIED IDEOGRAPH + 0xF3AF: 0x9948, //CJK UNIFIED IDEOGRAPH + 0xF3B0: 0x9947, //CJK UNIFIED IDEOGRAPH + 0xF3B1: 0x9943, //CJK UNIFIED IDEOGRAPH + 0xF3B2: 0x99A6, //CJK UNIFIED IDEOGRAPH + 0xF3B3: 0x99A7, //CJK UNIFIED IDEOGRAPH + 0xF3B4: 0x9A1A, //CJK UNIFIED IDEOGRAPH + 0xF3B5: 0x9A15, //CJK UNIFIED IDEOGRAPH + 0xF3B6: 0x9A25, //CJK UNIFIED IDEOGRAPH + 0xF3B7: 0x9A1D, //CJK UNIFIED IDEOGRAPH + 0xF3B8: 0x9A24, //CJK UNIFIED IDEOGRAPH + 0xF3B9: 0x9A1B, //CJK UNIFIED IDEOGRAPH + 0xF3BA: 0x9A22, //CJK UNIFIED IDEOGRAPH + 0xF3BB: 0x9A20, //CJK UNIFIED IDEOGRAPH + 0xF3BC: 0x9A27, //CJK UNIFIED IDEOGRAPH + 0xF3BD: 0x9A23, //CJK UNIFIED IDEOGRAPH + 0xF3BE: 0x9A1E, //CJK UNIFIED IDEOGRAPH + 0xF3BF: 0x9A1C, //CJK UNIFIED IDEOGRAPH + 0xF3C0: 0x9A14, //CJK UNIFIED IDEOGRAPH + 0xF3C1: 0x9AC2, //CJK UNIFIED IDEOGRAPH + 0xF3C2: 0x9B0B, //CJK UNIFIED IDEOGRAPH + 0xF3C3: 0x9B0A, //CJK UNIFIED IDEOGRAPH + 0xF3C4: 0x9B0E, //CJK UNIFIED IDEOGRAPH + 0xF3C5: 0x9B0C, //CJK UNIFIED IDEOGRAPH + 0xF3C6: 0x9B37, //CJK UNIFIED IDEOGRAPH + 0xF3C7: 0x9BEA, //CJK UNIFIED IDEOGRAPH + 0xF3C8: 0x9BEB, //CJK UNIFIED IDEOGRAPH + 0xF3C9: 0x9BE0, //CJK UNIFIED IDEOGRAPH + 0xF3CA: 0x9BDE, //CJK UNIFIED IDEOGRAPH + 0xF3CB: 0x9BE4, //CJK UNIFIED IDEOGRAPH + 0xF3CC: 0x9BE6, //CJK UNIFIED IDEOGRAPH + 0xF3CD: 0x9BE2, //CJK UNIFIED IDEOGRAPH + 0xF3CE: 0x9BF0, //CJK UNIFIED IDEOGRAPH + 0xF3CF: 0x9BD4, //CJK UNIFIED IDEOGRAPH + 0xF3D0: 0x9BD7, //CJK UNIFIED IDEOGRAPH + 0xF3D1: 0x9BEC, //CJK UNIFIED IDEOGRAPH + 0xF3D2: 0x9BDC, //CJK UNIFIED IDEOGRAPH + 0xF3D3: 0x9BD9, //CJK UNIFIED IDEOGRAPH + 0xF3D4: 0x9BE5, //CJK UNIFIED IDEOGRAPH + 0xF3D5: 0x9BD5, //CJK UNIFIED IDEOGRAPH + 0xF3D6: 0x9BE1, //CJK UNIFIED IDEOGRAPH + 0xF3D7: 0x9BDA, //CJK UNIFIED IDEOGRAPH + 0xF3D8: 0x9D77, //CJK UNIFIED IDEOGRAPH + 0xF3D9: 0x9D81, //CJK UNIFIED IDEOGRAPH + 0xF3DA: 0x9D8A, //CJK UNIFIED IDEOGRAPH + 0xF3DB: 0x9D84, //CJK UNIFIED IDEOGRAPH + 0xF3DC: 0x9D88, //CJK UNIFIED IDEOGRAPH + 0xF3DD: 0x9D71, //CJK UNIFIED IDEOGRAPH + 0xF3DE: 0x9D80, //CJK UNIFIED IDEOGRAPH + 0xF3DF: 0x9D78, //CJK UNIFIED IDEOGRAPH + 0xF3E0: 0x9D86, //CJK UNIFIED IDEOGRAPH + 0xF3E1: 0x9D8B, //CJK UNIFIED IDEOGRAPH + 0xF3E2: 0x9D8C, //CJK UNIFIED IDEOGRAPH + 0xF3E3: 0x9D7D, //CJK UNIFIED IDEOGRAPH + 0xF3E4: 0x9D6B, //CJK UNIFIED IDEOGRAPH + 0xF3E5: 0x9D74, //CJK UNIFIED IDEOGRAPH + 0xF3E6: 0x9D75, //CJK UNIFIED IDEOGRAPH + 0xF3E7: 0x9D70, //CJK UNIFIED IDEOGRAPH + 0xF3E8: 0x9D69, //CJK UNIFIED IDEOGRAPH + 0xF3E9: 0x9D85, //CJK UNIFIED IDEOGRAPH + 0xF3EA: 0x9D73, //CJK UNIFIED IDEOGRAPH + 0xF3EB: 0x9D7B, //CJK UNIFIED IDEOGRAPH + 0xF3EC: 0x9D82, //CJK UNIFIED IDEOGRAPH + 0xF3ED: 0x9D6F, //CJK UNIFIED IDEOGRAPH + 0xF3EE: 0x9D79, //CJK UNIFIED IDEOGRAPH + 0xF3EF: 0x9D7F, //CJK UNIFIED IDEOGRAPH + 0xF3F0: 0x9D87, //CJK UNIFIED IDEOGRAPH + 0xF3F1: 0x9D68, //CJK UNIFIED IDEOGRAPH + 0xF3F2: 0x9E94, //CJK UNIFIED IDEOGRAPH + 0xF3F3: 0x9E91, //CJK UNIFIED IDEOGRAPH + 0xF3F4: 0x9EC0, //CJK UNIFIED IDEOGRAPH + 0xF3F5: 0x9EFC, //CJK UNIFIED IDEOGRAPH + 0xF3F6: 0x9F2D, //CJK UNIFIED IDEOGRAPH + 0xF3F7: 0x9F40, //CJK UNIFIED IDEOGRAPH + 0xF3F8: 0x9F41, //CJK UNIFIED IDEOGRAPH + 0xF3F9: 0x9F4D, //CJK UNIFIED IDEOGRAPH + 0xF3FA: 0x9F56, //CJK UNIFIED IDEOGRAPH + 0xF3FB: 0x9F57, //CJK UNIFIED IDEOGRAPH + 0xF3FC: 0x9F58, //CJK UNIFIED IDEOGRAPH + 0xF3FD: 0x5337, //CJK UNIFIED IDEOGRAPH + 0xF3FE: 0x56B2, //CJK UNIFIED IDEOGRAPH + 0xF440: 0x56B5, //CJK UNIFIED IDEOGRAPH + 0xF441: 0x56B3, //CJK UNIFIED IDEOGRAPH + 0xF442: 0x58E3, //CJK UNIFIED IDEOGRAPH + 0xF443: 0x5B45, //CJK UNIFIED IDEOGRAPH + 0xF444: 0x5DC6, //CJK UNIFIED IDEOGRAPH + 0xF445: 0x5DC7, //CJK UNIFIED IDEOGRAPH + 0xF446: 0x5EEE, //CJK UNIFIED IDEOGRAPH + 0xF447: 0x5EEF, //CJK UNIFIED IDEOGRAPH + 0xF448: 0x5FC0, //CJK UNIFIED IDEOGRAPH + 0xF449: 0x5FC1, //CJK UNIFIED IDEOGRAPH + 0xF44A: 0x61F9, //CJK UNIFIED IDEOGRAPH + 0xF44B: 0x6517, //CJK UNIFIED IDEOGRAPH + 0xF44C: 0x6516, //CJK UNIFIED IDEOGRAPH + 0xF44D: 0x6515, //CJK UNIFIED IDEOGRAPH + 0xF44E: 0x6513, //CJK UNIFIED IDEOGRAPH + 0xF44F: 0x65DF, //CJK UNIFIED IDEOGRAPH + 0xF450: 0x66E8, //CJK UNIFIED IDEOGRAPH + 0xF451: 0x66E3, //CJK UNIFIED IDEOGRAPH + 0xF452: 0x66E4, //CJK UNIFIED IDEOGRAPH + 0xF453: 0x6AF3, //CJK UNIFIED IDEOGRAPH + 0xF454: 0x6AF0, //CJK UNIFIED IDEOGRAPH + 0xF455: 0x6AEA, //CJK UNIFIED IDEOGRAPH + 0xF456: 0x6AE8, //CJK UNIFIED IDEOGRAPH + 0xF457: 0x6AF9, //CJK UNIFIED IDEOGRAPH + 0xF458: 0x6AF1, //CJK UNIFIED IDEOGRAPH + 0xF459: 0x6AEE, //CJK UNIFIED IDEOGRAPH + 0xF45A: 0x6AEF, //CJK UNIFIED IDEOGRAPH + 0xF45B: 0x703C, //CJK UNIFIED IDEOGRAPH + 0xF45C: 0x7035, //CJK UNIFIED IDEOGRAPH + 0xF45D: 0x702F, //CJK UNIFIED IDEOGRAPH + 0xF45E: 0x7037, //CJK UNIFIED IDEOGRAPH + 0xF45F: 0x7034, //CJK UNIFIED IDEOGRAPH + 0xF460: 0x7031, //CJK UNIFIED IDEOGRAPH + 0xF461: 0x7042, //CJK UNIFIED IDEOGRAPH + 0xF462: 0x7038, //CJK UNIFIED IDEOGRAPH + 0xF463: 0x703F, //CJK UNIFIED IDEOGRAPH + 0xF464: 0x703A, //CJK UNIFIED IDEOGRAPH + 0xF465: 0x7039, //CJK UNIFIED IDEOGRAPH + 0xF466: 0x7040, //CJK UNIFIED IDEOGRAPH + 0xF467: 0x703B, //CJK UNIFIED IDEOGRAPH + 0xF468: 0x7033, //CJK UNIFIED IDEOGRAPH + 0xF469: 0x7041, //CJK UNIFIED IDEOGRAPH + 0xF46A: 0x7213, //CJK UNIFIED IDEOGRAPH + 0xF46B: 0x7214, //CJK UNIFIED IDEOGRAPH + 0xF46C: 0x72A8, //CJK UNIFIED IDEOGRAPH + 0xF46D: 0x737D, //CJK UNIFIED IDEOGRAPH + 0xF46E: 0x737C, //CJK UNIFIED IDEOGRAPH + 0xF46F: 0x74BA, //CJK UNIFIED IDEOGRAPH + 0xF470: 0x76AB, //CJK UNIFIED IDEOGRAPH + 0xF471: 0x76AA, //CJK UNIFIED IDEOGRAPH + 0xF472: 0x76BE, //CJK UNIFIED IDEOGRAPH + 0xF473: 0x76ED, //CJK UNIFIED IDEOGRAPH + 0xF474: 0x77CC, //CJK UNIFIED IDEOGRAPH + 0xF475: 0x77CE, //CJK UNIFIED IDEOGRAPH + 0xF476: 0x77CF, //CJK UNIFIED IDEOGRAPH + 0xF477: 0x77CD, //CJK UNIFIED IDEOGRAPH + 0xF478: 0x77F2, //CJK UNIFIED IDEOGRAPH + 0xF479: 0x7925, //CJK UNIFIED IDEOGRAPH + 0xF47A: 0x7923, //CJK UNIFIED IDEOGRAPH + 0xF47B: 0x7927, //CJK UNIFIED IDEOGRAPH + 0xF47C: 0x7928, //CJK UNIFIED IDEOGRAPH + 0xF47D: 0x7924, //CJK UNIFIED IDEOGRAPH + 0xF47E: 0x7929, //CJK UNIFIED IDEOGRAPH + 0xF4A1: 0x79B2, //CJK UNIFIED IDEOGRAPH + 0xF4A2: 0x7A6E, //CJK UNIFIED IDEOGRAPH + 0xF4A3: 0x7A6C, //CJK UNIFIED IDEOGRAPH + 0xF4A4: 0x7A6D, //CJK UNIFIED IDEOGRAPH + 0xF4A5: 0x7AF7, //CJK UNIFIED IDEOGRAPH + 0xF4A6: 0x7C49, //CJK UNIFIED IDEOGRAPH + 0xF4A7: 0x7C48, //CJK UNIFIED IDEOGRAPH + 0xF4A8: 0x7C4A, //CJK UNIFIED IDEOGRAPH + 0xF4A9: 0x7C47, //CJK UNIFIED IDEOGRAPH + 0xF4AA: 0x7C45, //CJK UNIFIED IDEOGRAPH + 0xF4AB: 0x7CEE, //CJK UNIFIED IDEOGRAPH + 0xF4AC: 0x7E7B, //CJK UNIFIED IDEOGRAPH + 0xF4AD: 0x7E7E, //CJK UNIFIED IDEOGRAPH + 0xF4AE: 0x7E81, //CJK UNIFIED IDEOGRAPH + 0xF4AF: 0x7E80, //CJK UNIFIED IDEOGRAPH + 0xF4B0: 0x7FBA, //CJK UNIFIED IDEOGRAPH + 0xF4B1: 0x7FFF, //CJK UNIFIED IDEOGRAPH + 0xF4B2: 0x8079, //CJK UNIFIED IDEOGRAPH + 0xF4B3: 0x81DB, //CJK UNIFIED IDEOGRAPH + 0xF4B4: 0x81D9, //CJK UNIFIED IDEOGRAPH + 0xF4B5: 0x820B, //CJK UNIFIED IDEOGRAPH + 0xF4B6: 0x8268, //CJK UNIFIED IDEOGRAPH + 0xF4B7: 0x8269, //CJK UNIFIED IDEOGRAPH + 0xF4B8: 0x8622, //CJK UNIFIED IDEOGRAPH + 0xF4B9: 0x85FF, //CJK UNIFIED IDEOGRAPH + 0xF4BA: 0x8601, //CJK UNIFIED IDEOGRAPH + 0xF4BB: 0x85FE, //CJK UNIFIED IDEOGRAPH + 0xF4BC: 0x861B, //CJK UNIFIED IDEOGRAPH + 0xF4BD: 0x8600, //CJK UNIFIED IDEOGRAPH + 0xF4BE: 0x85F6, //CJK UNIFIED IDEOGRAPH + 0xF4BF: 0x8604, //CJK UNIFIED IDEOGRAPH + 0xF4C0: 0x8609, //CJK UNIFIED IDEOGRAPH + 0xF4C1: 0x8605, //CJK UNIFIED IDEOGRAPH + 0xF4C2: 0x860C, //CJK UNIFIED IDEOGRAPH + 0xF4C3: 0x85FD, //CJK UNIFIED IDEOGRAPH + 0xF4C4: 0x8819, //CJK UNIFIED IDEOGRAPH + 0xF4C5: 0x8810, //CJK UNIFIED IDEOGRAPH + 0xF4C6: 0x8811, //CJK UNIFIED IDEOGRAPH + 0xF4C7: 0x8817, //CJK UNIFIED IDEOGRAPH + 0xF4C8: 0x8813, //CJK UNIFIED IDEOGRAPH + 0xF4C9: 0x8816, //CJK UNIFIED IDEOGRAPH + 0xF4CA: 0x8963, //CJK UNIFIED IDEOGRAPH + 0xF4CB: 0x8966, //CJK UNIFIED IDEOGRAPH + 0xF4CC: 0x89B9, //CJK UNIFIED IDEOGRAPH + 0xF4CD: 0x89F7, //CJK UNIFIED IDEOGRAPH + 0xF4CE: 0x8B60, //CJK UNIFIED IDEOGRAPH + 0xF4CF: 0x8B6A, //CJK UNIFIED IDEOGRAPH + 0xF4D0: 0x8B5D, //CJK UNIFIED IDEOGRAPH + 0xF4D1: 0x8B68, //CJK UNIFIED IDEOGRAPH + 0xF4D2: 0x8B63, //CJK UNIFIED IDEOGRAPH + 0xF4D3: 0x8B65, //CJK UNIFIED IDEOGRAPH + 0xF4D4: 0x8B67, //CJK UNIFIED IDEOGRAPH + 0xF4D5: 0x8B6D, //CJK UNIFIED IDEOGRAPH + 0xF4D6: 0x8DAE, //CJK UNIFIED IDEOGRAPH + 0xF4D7: 0x8E86, //CJK UNIFIED IDEOGRAPH + 0xF4D8: 0x8E88, //CJK UNIFIED IDEOGRAPH + 0xF4D9: 0x8E84, //CJK UNIFIED IDEOGRAPH + 0xF4DA: 0x8F59, //CJK UNIFIED IDEOGRAPH + 0xF4DB: 0x8F56, //CJK UNIFIED IDEOGRAPH + 0xF4DC: 0x8F57, //CJK UNIFIED IDEOGRAPH + 0xF4DD: 0x8F55, //CJK UNIFIED IDEOGRAPH + 0xF4DE: 0x8F58, //CJK UNIFIED IDEOGRAPH + 0xF4DF: 0x8F5A, //CJK UNIFIED IDEOGRAPH + 0xF4E0: 0x908D, //CJK UNIFIED IDEOGRAPH + 0xF4E1: 0x9143, //CJK UNIFIED IDEOGRAPH + 0xF4E2: 0x9141, //CJK UNIFIED IDEOGRAPH + 0xF4E3: 0x91B7, //CJK UNIFIED IDEOGRAPH + 0xF4E4: 0x91B5, //CJK UNIFIED IDEOGRAPH + 0xF4E5: 0x91B2, //CJK UNIFIED IDEOGRAPH + 0xF4E6: 0x91B3, //CJK UNIFIED IDEOGRAPH + 0xF4E7: 0x940B, //CJK UNIFIED IDEOGRAPH + 0xF4E8: 0x9413, //CJK UNIFIED IDEOGRAPH + 0xF4E9: 0x93FB, //CJK UNIFIED IDEOGRAPH + 0xF4EA: 0x9420, //CJK UNIFIED IDEOGRAPH + 0xF4EB: 0x940F, //CJK UNIFIED IDEOGRAPH + 0xF4EC: 0x9414, //CJK UNIFIED IDEOGRAPH + 0xF4ED: 0x93FE, //CJK UNIFIED IDEOGRAPH + 0xF4EE: 0x9415, //CJK UNIFIED IDEOGRAPH + 0xF4EF: 0x9410, //CJK UNIFIED IDEOGRAPH + 0xF4F0: 0x9428, //CJK UNIFIED IDEOGRAPH + 0xF4F1: 0x9419, //CJK UNIFIED IDEOGRAPH + 0xF4F2: 0x940D, //CJK UNIFIED IDEOGRAPH + 0xF4F3: 0x93F5, //CJK UNIFIED IDEOGRAPH + 0xF4F4: 0x9400, //CJK UNIFIED IDEOGRAPH + 0xF4F5: 0x93F7, //CJK UNIFIED IDEOGRAPH + 0xF4F6: 0x9407, //CJK UNIFIED IDEOGRAPH + 0xF4F7: 0x940E, //CJK UNIFIED IDEOGRAPH + 0xF4F8: 0x9416, //CJK UNIFIED IDEOGRAPH + 0xF4F9: 0x9412, //CJK UNIFIED IDEOGRAPH + 0xF4FA: 0x93FA, //CJK UNIFIED IDEOGRAPH + 0xF4FB: 0x9409, //CJK UNIFIED IDEOGRAPH + 0xF4FC: 0x93F8, //CJK UNIFIED IDEOGRAPH + 0xF4FD: 0x940A, //CJK UNIFIED IDEOGRAPH + 0xF4FE: 0x93FF, //CJK UNIFIED IDEOGRAPH + 0xF540: 0x93FC, //CJK UNIFIED IDEOGRAPH + 0xF541: 0x940C, //CJK UNIFIED IDEOGRAPH + 0xF542: 0x93F6, //CJK UNIFIED IDEOGRAPH + 0xF543: 0x9411, //CJK UNIFIED IDEOGRAPH + 0xF544: 0x9406, //CJK UNIFIED IDEOGRAPH + 0xF545: 0x95DE, //CJK UNIFIED IDEOGRAPH + 0xF546: 0x95E0, //CJK UNIFIED IDEOGRAPH + 0xF547: 0x95DF, //CJK UNIFIED IDEOGRAPH + 0xF548: 0x972E, //CJK UNIFIED IDEOGRAPH + 0xF549: 0x972F, //CJK UNIFIED IDEOGRAPH + 0xF54A: 0x97B9, //CJK UNIFIED IDEOGRAPH + 0xF54B: 0x97BB, //CJK UNIFIED IDEOGRAPH + 0xF54C: 0x97FD, //CJK UNIFIED IDEOGRAPH + 0xF54D: 0x97FE, //CJK UNIFIED IDEOGRAPH + 0xF54E: 0x9860, //CJK UNIFIED IDEOGRAPH + 0xF54F: 0x9862, //CJK UNIFIED IDEOGRAPH + 0xF550: 0x9863, //CJK UNIFIED IDEOGRAPH + 0xF551: 0x985F, //CJK UNIFIED IDEOGRAPH + 0xF552: 0x98C1, //CJK UNIFIED IDEOGRAPH + 0xF553: 0x98C2, //CJK UNIFIED IDEOGRAPH + 0xF554: 0x9950, //CJK UNIFIED IDEOGRAPH + 0xF555: 0x994E, //CJK UNIFIED IDEOGRAPH + 0xF556: 0x9959, //CJK UNIFIED IDEOGRAPH + 0xF557: 0x994C, //CJK UNIFIED IDEOGRAPH + 0xF558: 0x994B, //CJK UNIFIED IDEOGRAPH + 0xF559: 0x9953, //CJK UNIFIED IDEOGRAPH + 0xF55A: 0x9A32, //CJK UNIFIED IDEOGRAPH + 0xF55B: 0x9A34, //CJK UNIFIED IDEOGRAPH + 0xF55C: 0x9A31, //CJK UNIFIED IDEOGRAPH + 0xF55D: 0x9A2C, //CJK UNIFIED IDEOGRAPH + 0xF55E: 0x9A2A, //CJK UNIFIED IDEOGRAPH + 0xF55F: 0x9A36, //CJK UNIFIED IDEOGRAPH + 0xF560: 0x9A29, //CJK UNIFIED IDEOGRAPH + 0xF561: 0x9A2E, //CJK UNIFIED IDEOGRAPH + 0xF562: 0x9A38, //CJK UNIFIED IDEOGRAPH + 0xF563: 0x9A2D, //CJK UNIFIED IDEOGRAPH + 0xF564: 0x9AC7, //CJK UNIFIED IDEOGRAPH + 0xF565: 0x9ACA, //CJK UNIFIED IDEOGRAPH + 0xF566: 0x9AC6, //CJK UNIFIED IDEOGRAPH + 0xF567: 0x9B10, //CJK UNIFIED IDEOGRAPH + 0xF568: 0x9B12, //CJK UNIFIED IDEOGRAPH + 0xF569: 0x9B11, //CJK UNIFIED IDEOGRAPH + 0xF56A: 0x9C0B, //CJK UNIFIED IDEOGRAPH + 0xF56B: 0x9C08, //CJK UNIFIED IDEOGRAPH + 0xF56C: 0x9BF7, //CJK UNIFIED IDEOGRAPH + 0xF56D: 0x9C05, //CJK UNIFIED IDEOGRAPH + 0xF56E: 0x9C12, //CJK UNIFIED IDEOGRAPH + 0xF56F: 0x9BF8, //CJK UNIFIED IDEOGRAPH + 0xF570: 0x9C40, //CJK UNIFIED IDEOGRAPH + 0xF571: 0x9C07, //CJK UNIFIED IDEOGRAPH + 0xF572: 0x9C0E, //CJK UNIFIED IDEOGRAPH + 0xF573: 0x9C06, //CJK UNIFIED IDEOGRAPH + 0xF574: 0x9C17, //CJK UNIFIED IDEOGRAPH + 0xF575: 0x9C14, //CJK UNIFIED IDEOGRAPH + 0xF576: 0x9C09, //CJK UNIFIED IDEOGRAPH + 0xF577: 0x9D9F, //CJK UNIFIED IDEOGRAPH + 0xF578: 0x9D99, //CJK UNIFIED IDEOGRAPH + 0xF579: 0x9DA4, //CJK UNIFIED IDEOGRAPH + 0xF57A: 0x9D9D, //CJK UNIFIED IDEOGRAPH + 0xF57B: 0x9D92, //CJK UNIFIED IDEOGRAPH + 0xF57C: 0x9D98, //CJK UNIFIED IDEOGRAPH + 0xF57D: 0x9D90, //CJK UNIFIED IDEOGRAPH + 0xF57E: 0x9D9B, //CJK UNIFIED IDEOGRAPH + 0xF5A1: 0x9DA0, //CJK UNIFIED IDEOGRAPH + 0xF5A2: 0x9D94, //CJK UNIFIED IDEOGRAPH + 0xF5A3: 0x9D9C, //CJK UNIFIED IDEOGRAPH + 0xF5A4: 0x9DAA, //CJK UNIFIED IDEOGRAPH + 0xF5A5: 0x9D97, //CJK UNIFIED IDEOGRAPH + 0xF5A6: 0x9DA1, //CJK UNIFIED IDEOGRAPH + 0xF5A7: 0x9D9A, //CJK UNIFIED IDEOGRAPH + 0xF5A8: 0x9DA2, //CJK UNIFIED IDEOGRAPH + 0xF5A9: 0x9DA8, //CJK UNIFIED IDEOGRAPH + 0xF5AA: 0x9D9E, //CJK UNIFIED IDEOGRAPH + 0xF5AB: 0x9DA3, //CJK UNIFIED IDEOGRAPH + 0xF5AC: 0x9DBF, //CJK UNIFIED IDEOGRAPH + 0xF5AD: 0x9DA9, //CJK UNIFIED IDEOGRAPH + 0xF5AE: 0x9D96, //CJK UNIFIED IDEOGRAPH + 0xF5AF: 0x9DA6, //CJK UNIFIED IDEOGRAPH + 0xF5B0: 0x9DA7, //CJK UNIFIED IDEOGRAPH + 0xF5B1: 0x9E99, //CJK UNIFIED IDEOGRAPH + 0xF5B2: 0x9E9B, //CJK UNIFIED IDEOGRAPH + 0xF5B3: 0x9E9A, //CJK UNIFIED IDEOGRAPH + 0xF5B4: 0x9EE5, //CJK UNIFIED IDEOGRAPH + 0xF5B5: 0x9EE4, //CJK UNIFIED IDEOGRAPH + 0xF5B6: 0x9EE7, //CJK UNIFIED IDEOGRAPH + 0xF5B7: 0x9EE6, //CJK UNIFIED IDEOGRAPH + 0xF5B8: 0x9F30, //CJK UNIFIED IDEOGRAPH + 0xF5B9: 0x9F2E, //CJK UNIFIED IDEOGRAPH + 0xF5BA: 0x9F5B, //CJK UNIFIED IDEOGRAPH + 0xF5BB: 0x9F60, //CJK UNIFIED IDEOGRAPH + 0xF5BC: 0x9F5E, //CJK UNIFIED IDEOGRAPH + 0xF5BD: 0x9F5D, //CJK UNIFIED IDEOGRAPH + 0xF5BE: 0x9F59, //CJK UNIFIED IDEOGRAPH + 0xF5BF: 0x9F91, //CJK UNIFIED IDEOGRAPH + 0xF5C0: 0x513A, //CJK UNIFIED IDEOGRAPH + 0xF5C1: 0x5139, //CJK UNIFIED IDEOGRAPH + 0xF5C2: 0x5298, //CJK UNIFIED IDEOGRAPH + 0xF5C3: 0x5297, //CJK UNIFIED IDEOGRAPH + 0xF5C4: 0x56C3, //CJK UNIFIED IDEOGRAPH + 0xF5C5: 0x56BD, //CJK UNIFIED IDEOGRAPH + 0xF5C6: 0x56BE, //CJK UNIFIED IDEOGRAPH + 0xF5C7: 0x5B48, //CJK UNIFIED IDEOGRAPH + 0xF5C8: 0x5B47, //CJK UNIFIED IDEOGRAPH + 0xF5C9: 0x5DCB, //CJK UNIFIED IDEOGRAPH + 0xF5CA: 0x5DCF, //CJK UNIFIED IDEOGRAPH + 0xF5CB: 0x5EF1, //CJK UNIFIED IDEOGRAPH + 0xF5CC: 0x61FD, //CJK UNIFIED IDEOGRAPH + 0xF5CD: 0x651B, //CJK UNIFIED IDEOGRAPH + 0xF5CE: 0x6B02, //CJK UNIFIED IDEOGRAPH + 0xF5CF: 0x6AFC, //CJK UNIFIED IDEOGRAPH + 0xF5D0: 0x6B03, //CJK UNIFIED IDEOGRAPH + 0xF5D1: 0x6AF8, //CJK UNIFIED IDEOGRAPH + 0xF5D2: 0x6B00, //CJK UNIFIED IDEOGRAPH + 0xF5D3: 0x7043, //CJK UNIFIED IDEOGRAPH + 0xF5D4: 0x7044, //CJK UNIFIED IDEOGRAPH + 0xF5D5: 0x704A, //CJK UNIFIED IDEOGRAPH + 0xF5D6: 0x7048, //CJK UNIFIED IDEOGRAPH + 0xF5D7: 0x7049, //CJK UNIFIED IDEOGRAPH + 0xF5D8: 0x7045, //CJK UNIFIED IDEOGRAPH + 0xF5D9: 0x7046, //CJK UNIFIED IDEOGRAPH + 0xF5DA: 0x721D, //CJK UNIFIED IDEOGRAPH + 0xF5DB: 0x721A, //CJK UNIFIED IDEOGRAPH + 0xF5DC: 0x7219, //CJK UNIFIED IDEOGRAPH + 0xF5DD: 0x737E, //CJK UNIFIED IDEOGRAPH + 0xF5DE: 0x7517, //CJK UNIFIED IDEOGRAPH + 0xF5DF: 0x766A, //CJK UNIFIED IDEOGRAPH + 0xF5E0: 0x77D0, //CJK UNIFIED IDEOGRAPH + 0xF5E1: 0x792D, //CJK UNIFIED IDEOGRAPH + 0xF5E2: 0x7931, //CJK UNIFIED IDEOGRAPH + 0xF5E3: 0x792F, //CJK UNIFIED IDEOGRAPH + 0xF5E4: 0x7C54, //CJK UNIFIED IDEOGRAPH + 0xF5E5: 0x7C53, //CJK UNIFIED IDEOGRAPH + 0xF5E6: 0x7CF2, //CJK UNIFIED IDEOGRAPH + 0xF5E7: 0x7E8A, //CJK UNIFIED IDEOGRAPH + 0xF5E8: 0x7E87, //CJK UNIFIED IDEOGRAPH + 0xF5E9: 0x7E88, //CJK UNIFIED IDEOGRAPH + 0xF5EA: 0x7E8B, //CJK UNIFIED IDEOGRAPH + 0xF5EB: 0x7E86, //CJK UNIFIED IDEOGRAPH + 0xF5EC: 0x7E8D, //CJK UNIFIED IDEOGRAPH + 0xF5ED: 0x7F4D, //CJK UNIFIED IDEOGRAPH + 0xF5EE: 0x7FBB, //CJK UNIFIED IDEOGRAPH + 0xF5EF: 0x8030, //CJK UNIFIED IDEOGRAPH + 0xF5F0: 0x81DD, //CJK UNIFIED IDEOGRAPH + 0xF5F1: 0x8618, //CJK UNIFIED IDEOGRAPH + 0xF5F2: 0x862A, //CJK UNIFIED IDEOGRAPH + 0xF5F3: 0x8626, //CJK UNIFIED IDEOGRAPH + 0xF5F4: 0x861F, //CJK UNIFIED IDEOGRAPH + 0xF5F5: 0x8623, //CJK UNIFIED IDEOGRAPH + 0xF5F6: 0x861C, //CJK UNIFIED IDEOGRAPH + 0xF5F7: 0x8619, //CJK UNIFIED IDEOGRAPH + 0xF5F8: 0x8627, //CJK UNIFIED IDEOGRAPH + 0xF5F9: 0x862E, //CJK UNIFIED IDEOGRAPH + 0xF5FA: 0x8621, //CJK UNIFIED IDEOGRAPH + 0xF5FB: 0x8620, //CJK UNIFIED IDEOGRAPH + 0xF5FC: 0x8629, //CJK UNIFIED IDEOGRAPH + 0xF5FD: 0x861E, //CJK UNIFIED IDEOGRAPH + 0xF5FE: 0x8625, //CJK UNIFIED IDEOGRAPH + 0xF640: 0x8829, //CJK UNIFIED IDEOGRAPH + 0xF641: 0x881D, //CJK UNIFIED IDEOGRAPH + 0xF642: 0x881B, //CJK UNIFIED IDEOGRAPH + 0xF643: 0x8820, //CJK UNIFIED IDEOGRAPH + 0xF644: 0x8824, //CJK UNIFIED IDEOGRAPH + 0xF645: 0x881C, //CJK UNIFIED IDEOGRAPH + 0xF646: 0x882B, //CJK UNIFIED IDEOGRAPH + 0xF647: 0x884A, //CJK UNIFIED IDEOGRAPH + 0xF648: 0x896D, //CJK UNIFIED IDEOGRAPH + 0xF649: 0x8969, //CJK UNIFIED IDEOGRAPH + 0xF64A: 0x896E, //CJK UNIFIED IDEOGRAPH + 0xF64B: 0x896B, //CJK UNIFIED IDEOGRAPH + 0xF64C: 0x89FA, //CJK UNIFIED IDEOGRAPH + 0xF64D: 0x8B79, //CJK UNIFIED IDEOGRAPH + 0xF64E: 0x8B78, //CJK UNIFIED IDEOGRAPH + 0xF64F: 0x8B45, //CJK UNIFIED IDEOGRAPH + 0xF650: 0x8B7A, //CJK UNIFIED IDEOGRAPH + 0xF651: 0x8B7B, //CJK UNIFIED IDEOGRAPH + 0xF652: 0x8D10, //CJK UNIFIED IDEOGRAPH + 0xF653: 0x8D14, //CJK UNIFIED IDEOGRAPH + 0xF654: 0x8DAF, //CJK UNIFIED IDEOGRAPH + 0xF655: 0x8E8E, //CJK UNIFIED IDEOGRAPH + 0xF656: 0x8E8C, //CJK UNIFIED IDEOGRAPH + 0xF657: 0x8F5E, //CJK UNIFIED IDEOGRAPH + 0xF658: 0x8F5B, //CJK UNIFIED IDEOGRAPH + 0xF659: 0x8F5D, //CJK UNIFIED IDEOGRAPH + 0xF65A: 0x9146, //CJK UNIFIED IDEOGRAPH + 0xF65B: 0x9144, //CJK UNIFIED IDEOGRAPH + 0xF65C: 0x9145, //CJK UNIFIED IDEOGRAPH + 0xF65D: 0x91B9, //CJK UNIFIED IDEOGRAPH + 0xF65E: 0x943F, //CJK UNIFIED IDEOGRAPH + 0xF65F: 0x943B, //CJK UNIFIED IDEOGRAPH + 0xF660: 0x9436, //CJK UNIFIED IDEOGRAPH + 0xF661: 0x9429, //CJK UNIFIED IDEOGRAPH + 0xF662: 0x943D, //CJK UNIFIED IDEOGRAPH + 0xF663: 0x943C, //CJK UNIFIED IDEOGRAPH + 0xF664: 0x9430, //CJK UNIFIED IDEOGRAPH + 0xF665: 0x9439, //CJK UNIFIED IDEOGRAPH + 0xF666: 0x942A, //CJK UNIFIED IDEOGRAPH + 0xF667: 0x9437, //CJK UNIFIED IDEOGRAPH + 0xF668: 0x942C, //CJK UNIFIED IDEOGRAPH + 0xF669: 0x9440, //CJK UNIFIED IDEOGRAPH + 0xF66A: 0x9431, //CJK UNIFIED IDEOGRAPH + 0xF66B: 0x95E5, //CJK UNIFIED IDEOGRAPH + 0xF66C: 0x95E4, //CJK UNIFIED IDEOGRAPH + 0xF66D: 0x95E3, //CJK UNIFIED IDEOGRAPH + 0xF66E: 0x9735, //CJK UNIFIED IDEOGRAPH + 0xF66F: 0x973A, //CJK UNIFIED IDEOGRAPH + 0xF670: 0x97BF, //CJK UNIFIED IDEOGRAPH + 0xF671: 0x97E1, //CJK UNIFIED IDEOGRAPH + 0xF672: 0x9864, //CJK UNIFIED IDEOGRAPH + 0xF673: 0x98C9, //CJK UNIFIED IDEOGRAPH + 0xF674: 0x98C6, //CJK UNIFIED IDEOGRAPH + 0xF675: 0x98C0, //CJK UNIFIED IDEOGRAPH + 0xF676: 0x9958, //CJK UNIFIED IDEOGRAPH + 0xF677: 0x9956, //CJK UNIFIED IDEOGRAPH + 0xF678: 0x9A39, //CJK UNIFIED IDEOGRAPH + 0xF679: 0x9A3D, //CJK UNIFIED IDEOGRAPH + 0xF67A: 0x9A46, //CJK UNIFIED IDEOGRAPH + 0xF67B: 0x9A44, //CJK UNIFIED IDEOGRAPH + 0xF67C: 0x9A42, //CJK UNIFIED IDEOGRAPH + 0xF67D: 0x9A41, //CJK UNIFIED IDEOGRAPH + 0xF67E: 0x9A3A, //CJK UNIFIED IDEOGRAPH + 0xF6A1: 0x9A3F, //CJK UNIFIED IDEOGRAPH + 0xF6A2: 0x9ACD, //CJK UNIFIED IDEOGRAPH + 0xF6A3: 0x9B15, //CJK UNIFIED IDEOGRAPH + 0xF6A4: 0x9B17, //CJK UNIFIED IDEOGRAPH + 0xF6A5: 0x9B18, //CJK UNIFIED IDEOGRAPH + 0xF6A6: 0x9B16, //CJK UNIFIED IDEOGRAPH + 0xF6A7: 0x9B3A, //CJK UNIFIED IDEOGRAPH + 0xF6A8: 0x9B52, //CJK UNIFIED IDEOGRAPH + 0xF6A9: 0x9C2B, //CJK UNIFIED IDEOGRAPH + 0xF6AA: 0x9C1D, //CJK UNIFIED IDEOGRAPH + 0xF6AB: 0x9C1C, //CJK UNIFIED IDEOGRAPH + 0xF6AC: 0x9C2C, //CJK UNIFIED IDEOGRAPH + 0xF6AD: 0x9C23, //CJK UNIFIED IDEOGRAPH + 0xF6AE: 0x9C28, //CJK UNIFIED IDEOGRAPH + 0xF6AF: 0x9C29, //CJK UNIFIED IDEOGRAPH + 0xF6B0: 0x9C24, //CJK UNIFIED IDEOGRAPH + 0xF6B1: 0x9C21, //CJK UNIFIED IDEOGRAPH + 0xF6B2: 0x9DB7, //CJK UNIFIED IDEOGRAPH + 0xF6B3: 0x9DB6, //CJK UNIFIED IDEOGRAPH + 0xF6B4: 0x9DBC, //CJK UNIFIED IDEOGRAPH + 0xF6B5: 0x9DC1, //CJK UNIFIED IDEOGRAPH + 0xF6B6: 0x9DC7, //CJK UNIFIED IDEOGRAPH + 0xF6B7: 0x9DCA, //CJK UNIFIED IDEOGRAPH + 0xF6B8: 0x9DCF, //CJK UNIFIED IDEOGRAPH + 0xF6B9: 0x9DBE, //CJK UNIFIED IDEOGRAPH + 0xF6BA: 0x9DC5, //CJK UNIFIED IDEOGRAPH + 0xF6BB: 0x9DC3, //CJK UNIFIED IDEOGRAPH + 0xF6BC: 0x9DBB, //CJK UNIFIED IDEOGRAPH + 0xF6BD: 0x9DB5, //CJK UNIFIED IDEOGRAPH + 0xF6BE: 0x9DCE, //CJK UNIFIED IDEOGRAPH + 0xF6BF: 0x9DB9, //CJK UNIFIED IDEOGRAPH + 0xF6C0: 0x9DBA, //CJK UNIFIED IDEOGRAPH + 0xF6C1: 0x9DAC, //CJK UNIFIED IDEOGRAPH + 0xF6C2: 0x9DC8, //CJK UNIFIED IDEOGRAPH + 0xF6C3: 0x9DB1, //CJK UNIFIED IDEOGRAPH + 0xF6C4: 0x9DAD, //CJK UNIFIED IDEOGRAPH + 0xF6C5: 0x9DCC, //CJK UNIFIED IDEOGRAPH + 0xF6C6: 0x9DB3, //CJK UNIFIED IDEOGRAPH + 0xF6C7: 0x9DCD, //CJK UNIFIED IDEOGRAPH + 0xF6C8: 0x9DB2, //CJK UNIFIED IDEOGRAPH + 0xF6C9: 0x9E7A, //CJK UNIFIED IDEOGRAPH + 0xF6CA: 0x9E9C, //CJK UNIFIED IDEOGRAPH + 0xF6CB: 0x9EEB, //CJK UNIFIED IDEOGRAPH + 0xF6CC: 0x9EEE, //CJK UNIFIED IDEOGRAPH + 0xF6CD: 0x9EED, //CJK UNIFIED IDEOGRAPH + 0xF6CE: 0x9F1B, //CJK UNIFIED IDEOGRAPH + 0xF6CF: 0x9F18, //CJK UNIFIED IDEOGRAPH + 0xF6D0: 0x9F1A, //CJK UNIFIED IDEOGRAPH + 0xF6D1: 0x9F31, //CJK UNIFIED IDEOGRAPH + 0xF6D2: 0x9F4E, //CJK UNIFIED IDEOGRAPH + 0xF6D3: 0x9F65, //CJK UNIFIED IDEOGRAPH + 0xF6D4: 0x9F64, //CJK UNIFIED IDEOGRAPH + 0xF6D5: 0x9F92, //CJK UNIFIED IDEOGRAPH + 0xF6D6: 0x4EB9, //CJK UNIFIED IDEOGRAPH + 0xF6D7: 0x56C6, //CJK UNIFIED IDEOGRAPH + 0xF6D8: 0x56C5, //CJK UNIFIED IDEOGRAPH + 0xF6D9: 0x56CB, //CJK UNIFIED IDEOGRAPH + 0xF6DA: 0x5971, //CJK UNIFIED IDEOGRAPH + 0xF6DB: 0x5B4B, //CJK UNIFIED IDEOGRAPH + 0xF6DC: 0x5B4C, //CJK UNIFIED IDEOGRAPH + 0xF6DD: 0x5DD5, //CJK UNIFIED IDEOGRAPH + 0xF6DE: 0x5DD1, //CJK UNIFIED IDEOGRAPH + 0xF6DF: 0x5EF2, //CJK UNIFIED IDEOGRAPH + 0xF6E0: 0x6521, //CJK UNIFIED IDEOGRAPH + 0xF6E1: 0x6520, //CJK UNIFIED IDEOGRAPH + 0xF6E2: 0x6526, //CJK UNIFIED IDEOGRAPH + 0xF6E3: 0x6522, //CJK UNIFIED IDEOGRAPH + 0xF6E4: 0x6B0B, //CJK UNIFIED IDEOGRAPH + 0xF6E5: 0x6B08, //CJK UNIFIED IDEOGRAPH + 0xF6E6: 0x6B09, //CJK UNIFIED IDEOGRAPH + 0xF6E7: 0x6C0D, //CJK UNIFIED IDEOGRAPH + 0xF6E8: 0x7055, //CJK UNIFIED IDEOGRAPH + 0xF6E9: 0x7056, //CJK UNIFIED IDEOGRAPH + 0xF6EA: 0x7057, //CJK UNIFIED IDEOGRAPH + 0xF6EB: 0x7052, //CJK UNIFIED IDEOGRAPH + 0xF6EC: 0x721E, //CJK UNIFIED IDEOGRAPH + 0xF6ED: 0x721F, //CJK UNIFIED IDEOGRAPH + 0xF6EE: 0x72A9, //CJK UNIFIED IDEOGRAPH + 0xF6EF: 0x737F, //CJK UNIFIED IDEOGRAPH + 0xF6F0: 0x74D8, //CJK UNIFIED IDEOGRAPH + 0xF6F1: 0x74D5, //CJK UNIFIED IDEOGRAPH + 0xF6F2: 0x74D9, //CJK UNIFIED IDEOGRAPH + 0xF6F3: 0x74D7, //CJK UNIFIED IDEOGRAPH + 0xF6F4: 0x766D, //CJK UNIFIED IDEOGRAPH + 0xF6F5: 0x76AD, //CJK UNIFIED IDEOGRAPH + 0xF6F6: 0x7935, //CJK UNIFIED IDEOGRAPH + 0xF6F7: 0x79B4, //CJK UNIFIED IDEOGRAPH + 0xF6F8: 0x7A70, //CJK UNIFIED IDEOGRAPH + 0xF6F9: 0x7A71, //CJK UNIFIED IDEOGRAPH + 0xF6FA: 0x7C57, //CJK UNIFIED IDEOGRAPH + 0xF6FB: 0x7C5C, //CJK UNIFIED IDEOGRAPH + 0xF6FC: 0x7C59, //CJK UNIFIED IDEOGRAPH + 0xF6FD: 0x7C5B, //CJK UNIFIED IDEOGRAPH + 0xF6FE: 0x7C5A, //CJK UNIFIED IDEOGRAPH + 0xF740: 0x7CF4, //CJK UNIFIED IDEOGRAPH + 0xF741: 0x7CF1, //CJK UNIFIED IDEOGRAPH + 0xF742: 0x7E91, //CJK UNIFIED IDEOGRAPH + 0xF743: 0x7F4F, //CJK UNIFIED IDEOGRAPH + 0xF744: 0x7F87, //CJK UNIFIED IDEOGRAPH + 0xF745: 0x81DE, //CJK UNIFIED IDEOGRAPH + 0xF746: 0x826B, //CJK UNIFIED IDEOGRAPH + 0xF747: 0x8634, //CJK UNIFIED IDEOGRAPH + 0xF748: 0x8635, //CJK UNIFIED IDEOGRAPH + 0xF749: 0x8633, //CJK UNIFIED IDEOGRAPH + 0xF74A: 0x862C, //CJK UNIFIED IDEOGRAPH + 0xF74B: 0x8632, //CJK UNIFIED IDEOGRAPH + 0xF74C: 0x8636, //CJK UNIFIED IDEOGRAPH + 0xF74D: 0x882C, //CJK UNIFIED IDEOGRAPH + 0xF74E: 0x8828, //CJK UNIFIED IDEOGRAPH + 0xF74F: 0x8826, //CJK UNIFIED IDEOGRAPH + 0xF750: 0x882A, //CJK UNIFIED IDEOGRAPH + 0xF751: 0x8825, //CJK UNIFIED IDEOGRAPH + 0xF752: 0x8971, //CJK UNIFIED IDEOGRAPH + 0xF753: 0x89BF, //CJK UNIFIED IDEOGRAPH + 0xF754: 0x89BE, //CJK UNIFIED IDEOGRAPH + 0xF755: 0x89FB, //CJK UNIFIED IDEOGRAPH + 0xF756: 0x8B7E, //CJK UNIFIED IDEOGRAPH + 0xF757: 0x8B84, //CJK UNIFIED IDEOGRAPH + 0xF758: 0x8B82, //CJK UNIFIED IDEOGRAPH + 0xF759: 0x8B86, //CJK UNIFIED IDEOGRAPH + 0xF75A: 0x8B85, //CJK UNIFIED IDEOGRAPH + 0xF75B: 0x8B7F, //CJK UNIFIED IDEOGRAPH + 0xF75C: 0x8D15, //CJK UNIFIED IDEOGRAPH + 0xF75D: 0x8E95, //CJK UNIFIED IDEOGRAPH + 0xF75E: 0x8E94, //CJK UNIFIED IDEOGRAPH + 0xF75F: 0x8E9A, //CJK UNIFIED IDEOGRAPH + 0xF760: 0x8E92, //CJK UNIFIED IDEOGRAPH + 0xF761: 0x8E90, //CJK UNIFIED IDEOGRAPH + 0xF762: 0x8E96, //CJK UNIFIED IDEOGRAPH + 0xF763: 0x8E97, //CJK UNIFIED IDEOGRAPH + 0xF764: 0x8F60, //CJK UNIFIED IDEOGRAPH + 0xF765: 0x8F62, //CJK UNIFIED IDEOGRAPH + 0xF766: 0x9147, //CJK UNIFIED IDEOGRAPH + 0xF767: 0x944C, //CJK UNIFIED IDEOGRAPH + 0xF768: 0x9450, //CJK UNIFIED IDEOGRAPH + 0xF769: 0x944A, //CJK UNIFIED IDEOGRAPH + 0xF76A: 0x944B, //CJK UNIFIED IDEOGRAPH + 0xF76B: 0x944F, //CJK UNIFIED IDEOGRAPH + 0xF76C: 0x9447, //CJK UNIFIED IDEOGRAPH + 0xF76D: 0x9445, //CJK UNIFIED IDEOGRAPH + 0xF76E: 0x9448, //CJK UNIFIED IDEOGRAPH + 0xF76F: 0x9449, //CJK UNIFIED IDEOGRAPH + 0xF770: 0x9446, //CJK UNIFIED IDEOGRAPH + 0xF771: 0x973F, //CJK UNIFIED IDEOGRAPH + 0xF772: 0x97E3, //CJK UNIFIED IDEOGRAPH + 0xF773: 0x986A, //CJK UNIFIED IDEOGRAPH + 0xF774: 0x9869, //CJK UNIFIED IDEOGRAPH + 0xF775: 0x98CB, //CJK UNIFIED IDEOGRAPH + 0xF776: 0x9954, //CJK UNIFIED IDEOGRAPH + 0xF777: 0x995B, //CJK UNIFIED IDEOGRAPH + 0xF778: 0x9A4E, //CJK UNIFIED IDEOGRAPH + 0xF779: 0x9A53, //CJK UNIFIED IDEOGRAPH + 0xF77A: 0x9A54, //CJK UNIFIED IDEOGRAPH + 0xF77B: 0x9A4C, //CJK UNIFIED IDEOGRAPH + 0xF77C: 0x9A4F, //CJK UNIFIED IDEOGRAPH + 0xF77D: 0x9A48, //CJK UNIFIED IDEOGRAPH + 0xF77E: 0x9A4A, //CJK UNIFIED IDEOGRAPH + 0xF7A1: 0x9A49, //CJK UNIFIED IDEOGRAPH + 0xF7A2: 0x9A52, //CJK UNIFIED IDEOGRAPH + 0xF7A3: 0x9A50, //CJK UNIFIED IDEOGRAPH + 0xF7A4: 0x9AD0, //CJK UNIFIED IDEOGRAPH + 0xF7A5: 0x9B19, //CJK UNIFIED IDEOGRAPH + 0xF7A6: 0x9B2B, //CJK UNIFIED IDEOGRAPH + 0xF7A7: 0x9B3B, //CJK UNIFIED IDEOGRAPH + 0xF7A8: 0x9B56, //CJK UNIFIED IDEOGRAPH + 0xF7A9: 0x9B55, //CJK UNIFIED IDEOGRAPH + 0xF7AA: 0x9C46, //CJK UNIFIED IDEOGRAPH + 0xF7AB: 0x9C48, //CJK UNIFIED IDEOGRAPH + 0xF7AC: 0x9C3F, //CJK UNIFIED IDEOGRAPH + 0xF7AD: 0x9C44, //CJK UNIFIED IDEOGRAPH + 0xF7AE: 0x9C39, //CJK UNIFIED IDEOGRAPH + 0xF7AF: 0x9C33, //CJK UNIFIED IDEOGRAPH + 0xF7B0: 0x9C41, //CJK UNIFIED IDEOGRAPH + 0xF7B1: 0x9C3C, //CJK UNIFIED IDEOGRAPH + 0xF7B2: 0x9C37, //CJK UNIFIED IDEOGRAPH + 0xF7B3: 0x9C34, //CJK UNIFIED IDEOGRAPH + 0xF7B4: 0x9C32, //CJK UNIFIED IDEOGRAPH + 0xF7B5: 0x9C3D, //CJK UNIFIED IDEOGRAPH + 0xF7B6: 0x9C36, //CJK UNIFIED IDEOGRAPH + 0xF7B7: 0x9DDB, //CJK UNIFIED IDEOGRAPH + 0xF7B8: 0x9DD2, //CJK UNIFIED IDEOGRAPH + 0xF7B9: 0x9DDE, //CJK UNIFIED IDEOGRAPH + 0xF7BA: 0x9DDA, //CJK UNIFIED IDEOGRAPH + 0xF7BB: 0x9DCB, //CJK UNIFIED IDEOGRAPH + 0xF7BC: 0x9DD0, //CJK UNIFIED IDEOGRAPH + 0xF7BD: 0x9DDC, //CJK UNIFIED IDEOGRAPH + 0xF7BE: 0x9DD1, //CJK UNIFIED IDEOGRAPH + 0xF7BF: 0x9DDF, //CJK UNIFIED IDEOGRAPH + 0xF7C0: 0x9DE9, //CJK UNIFIED IDEOGRAPH + 0xF7C1: 0x9DD9, //CJK UNIFIED IDEOGRAPH + 0xF7C2: 0x9DD8, //CJK UNIFIED IDEOGRAPH + 0xF7C3: 0x9DD6, //CJK UNIFIED IDEOGRAPH + 0xF7C4: 0x9DF5, //CJK UNIFIED IDEOGRAPH + 0xF7C5: 0x9DD5, //CJK UNIFIED IDEOGRAPH + 0xF7C6: 0x9DDD, //CJK UNIFIED IDEOGRAPH + 0xF7C7: 0x9EB6, //CJK UNIFIED IDEOGRAPH + 0xF7C8: 0x9EF0, //CJK UNIFIED IDEOGRAPH + 0xF7C9: 0x9F35, //CJK UNIFIED IDEOGRAPH + 0xF7CA: 0x9F33, //CJK UNIFIED IDEOGRAPH + 0xF7CB: 0x9F32, //CJK UNIFIED IDEOGRAPH + 0xF7CC: 0x9F42, //CJK UNIFIED IDEOGRAPH + 0xF7CD: 0x9F6B, //CJK UNIFIED IDEOGRAPH + 0xF7CE: 0x9F95, //CJK UNIFIED IDEOGRAPH + 0xF7CF: 0x9FA2, //CJK UNIFIED IDEOGRAPH + 0xF7D0: 0x513D, //CJK UNIFIED IDEOGRAPH + 0xF7D1: 0x5299, //CJK UNIFIED IDEOGRAPH + 0xF7D2: 0x58E8, //CJK UNIFIED IDEOGRAPH + 0xF7D3: 0x58E7, //CJK UNIFIED IDEOGRAPH + 0xF7D4: 0x5972, //CJK UNIFIED IDEOGRAPH + 0xF7D5: 0x5B4D, //CJK UNIFIED IDEOGRAPH + 0xF7D6: 0x5DD8, //CJK UNIFIED IDEOGRAPH + 0xF7D7: 0x882F, //CJK UNIFIED IDEOGRAPH + 0xF7D8: 0x5F4F, //CJK UNIFIED IDEOGRAPH + 0xF7D9: 0x6201, //CJK UNIFIED IDEOGRAPH + 0xF7DA: 0x6203, //CJK UNIFIED IDEOGRAPH + 0xF7DB: 0x6204, //CJK UNIFIED IDEOGRAPH + 0xF7DC: 0x6529, //CJK UNIFIED IDEOGRAPH + 0xF7DD: 0x6525, //CJK UNIFIED IDEOGRAPH + 0xF7DE: 0x6596, //CJK UNIFIED IDEOGRAPH + 0xF7DF: 0x66EB, //CJK UNIFIED IDEOGRAPH + 0xF7E0: 0x6B11, //CJK UNIFIED IDEOGRAPH + 0xF7E1: 0x6B12, //CJK UNIFIED IDEOGRAPH + 0xF7E2: 0x6B0F, //CJK UNIFIED IDEOGRAPH + 0xF7E3: 0x6BCA, //CJK UNIFIED IDEOGRAPH + 0xF7E4: 0x705B, //CJK UNIFIED IDEOGRAPH + 0xF7E5: 0x705A, //CJK UNIFIED IDEOGRAPH + 0xF7E6: 0x7222, //CJK UNIFIED IDEOGRAPH + 0xF7E7: 0x7382, //CJK UNIFIED IDEOGRAPH + 0xF7E8: 0x7381, //CJK UNIFIED IDEOGRAPH + 0xF7E9: 0x7383, //CJK UNIFIED IDEOGRAPH + 0xF7EA: 0x7670, //CJK UNIFIED IDEOGRAPH + 0xF7EB: 0x77D4, //CJK UNIFIED IDEOGRAPH + 0xF7EC: 0x7C67, //CJK UNIFIED IDEOGRAPH + 0xF7ED: 0x7C66, //CJK UNIFIED IDEOGRAPH + 0xF7EE: 0x7E95, //CJK UNIFIED IDEOGRAPH + 0xF7EF: 0x826C, //CJK UNIFIED IDEOGRAPH + 0xF7F0: 0x863A, //CJK UNIFIED IDEOGRAPH + 0xF7F1: 0x8640, //CJK UNIFIED IDEOGRAPH + 0xF7F2: 0x8639, //CJK UNIFIED IDEOGRAPH + 0xF7F3: 0x863C, //CJK UNIFIED IDEOGRAPH + 0xF7F4: 0x8631, //CJK UNIFIED IDEOGRAPH + 0xF7F5: 0x863B, //CJK UNIFIED IDEOGRAPH + 0xF7F6: 0x863E, //CJK UNIFIED IDEOGRAPH + 0xF7F7: 0x8830, //CJK UNIFIED IDEOGRAPH + 0xF7F8: 0x8832, //CJK UNIFIED IDEOGRAPH + 0xF7F9: 0x882E, //CJK UNIFIED IDEOGRAPH + 0xF7FA: 0x8833, //CJK UNIFIED IDEOGRAPH + 0xF7FB: 0x8976, //CJK UNIFIED IDEOGRAPH + 0xF7FC: 0x8974, //CJK UNIFIED IDEOGRAPH + 0xF7FD: 0x8973, //CJK UNIFIED IDEOGRAPH + 0xF7FE: 0x89FE, //CJK UNIFIED IDEOGRAPH + 0xF840: 0x8B8C, //CJK UNIFIED IDEOGRAPH + 0xF841: 0x8B8E, //CJK UNIFIED IDEOGRAPH + 0xF842: 0x8B8B, //CJK UNIFIED IDEOGRAPH + 0xF843: 0x8B88, //CJK UNIFIED IDEOGRAPH + 0xF844: 0x8C45, //CJK UNIFIED IDEOGRAPH + 0xF845: 0x8D19, //CJK UNIFIED IDEOGRAPH + 0xF846: 0x8E98, //CJK UNIFIED IDEOGRAPH + 0xF847: 0x8F64, //CJK UNIFIED IDEOGRAPH + 0xF848: 0x8F63, //CJK UNIFIED IDEOGRAPH + 0xF849: 0x91BC, //CJK UNIFIED IDEOGRAPH + 0xF84A: 0x9462, //CJK UNIFIED IDEOGRAPH + 0xF84B: 0x9455, //CJK UNIFIED IDEOGRAPH + 0xF84C: 0x945D, //CJK UNIFIED IDEOGRAPH + 0xF84D: 0x9457, //CJK UNIFIED IDEOGRAPH + 0xF84E: 0x945E, //CJK UNIFIED IDEOGRAPH + 0xF84F: 0x97C4, //CJK UNIFIED IDEOGRAPH + 0xF850: 0x97C5, //CJK UNIFIED IDEOGRAPH + 0xF851: 0x9800, //CJK UNIFIED IDEOGRAPH + 0xF852: 0x9A56, //CJK UNIFIED IDEOGRAPH + 0xF853: 0x9A59, //CJK UNIFIED IDEOGRAPH + 0xF854: 0x9B1E, //CJK UNIFIED IDEOGRAPH + 0xF855: 0x9B1F, //CJK UNIFIED IDEOGRAPH + 0xF856: 0x9B20, //CJK UNIFIED IDEOGRAPH + 0xF857: 0x9C52, //CJK UNIFIED IDEOGRAPH + 0xF858: 0x9C58, //CJK UNIFIED IDEOGRAPH + 0xF859: 0x9C50, //CJK UNIFIED IDEOGRAPH + 0xF85A: 0x9C4A, //CJK UNIFIED IDEOGRAPH + 0xF85B: 0x9C4D, //CJK UNIFIED IDEOGRAPH + 0xF85C: 0x9C4B, //CJK UNIFIED IDEOGRAPH + 0xF85D: 0x9C55, //CJK UNIFIED IDEOGRAPH + 0xF85E: 0x9C59, //CJK UNIFIED IDEOGRAPH + 0xF85F: 0x9C4C, //CJK UNIFIED IDEOGRAPH + 0xF860: 0x9C4E, //CJK UNIFIED IDEOGRAPH + 0xF861: 0x9DFB, //CJK UNIFIED IDEOGRAPH + 0xF862: 0x9DF7, //CJK UNIFIED IDEOGRAPH + 0xF863: 0x9DEF, //CJK UNIFIED IDEOGRAPH + 0xF864: 0x9DE3, //CJK UNIFIED IDEOGRAPH + 0xF865: 0x9DEB, //CJK UNIFIED IDEOGRAPH + 0xF866: 0x9DF8, //CJK UNIFIED IDEOGRAPH + 0xF867: 0x9DE4, //CJK UNIFIED IDEOGRAPH + 0xF868: 0x9DF6, //CJK UNIFIED IDEOGRAPH + 0xF869: 0x9DE1, //CJK UNIFIED IDEOGRAPH + 0xF86A: 0x9DEE, //CJK UNIFIED IDEOGRAPH + 0xF86B: 0x9DE6, //CJK UNIFIED IDEOGRAPH + 0xF86C: 0x9DF2, //CJK UNIFIED IDEOGRAPH + 0xF86D: 0x9DF0, //CJK UNIFIED IDEOGRAPH + 0xF86E: 0x9DE2, //CJK UNIFIED IDEOGRAPH + 0xF86F: 0x9DEC, //CJK UNIFIED IDEOGRAPH + 0xF870: 0x9DF4, //CJK UNIFIED IDEOGRAPH + 0xF871: 0x9DF3, //CJK UNIFIED IDEOGRAPH + 0xF872: 0x9DE8, //CJK UNIFIED IDEOGRAPH + 0xF873: 0x9DED, //CJK UNIFIED IDEOGRAPH + 0xF874: 0x9EC2, //CJK UNIFIED IDEOGRAPH + 0xF875: 0x9ED0, //CJK UNIFIED IDEOGRAPH + 0xF876: 0x9EF2, //CJK UNIFIED IDEOGRAPH + 0xF877: 0x9EF3, //CJK UNIFIED IDEOGRAPH + 0xF878: 0x9F06, //CJK UNIFIED IDEOGRAPH + 0xF879: 0x9F1C, //CJK UNIFIED IDEOGRAPH + 0xF87A: 0x9F38, //CJK UNIFIED IDEOGRAPH + 0xF87B: 0x9F37, //CJK UNIFIED IDEOGRAPH + 0xF87C: 0x9F36, //CJK UNIFIED IDEOGRAPH + 0xF87D: 0x9F43, //CJK UNIFIED IDEOGRAPH + 0xF87E: 0x9F4F, //CJK UNIFIED IDEOGRAPH + 0xF8A1: 0x9F71, //CJK UNIFIED IDEOGRAPH + 0xF8A2: 0x9F70, //CJK UNIFIED IDEOGRAPH + 0xF8A3: 0x9F6E, //CJK UNIFIED IDEOGRAPH + 0xF8A4: 0x9F6F, //CJK UNIFIED IDEOGRAPH + 0xF8A5: 0x56D3, //CJK UNIFIED IDEOGRAPH + 0xF8A6: 0x56CD, //CJK UNIFIED IDEOGRAPH + 0xF8A7: 0x5B4E, //CJK UNIFIED IDEOGRAPH + 0xF8A8: 0x5C6D, //CJK UNIFIED IDEOGRAPH + 0xF8A9: 0x652D, //CJK UNIFIED IDEOGRAPH + 0xF8AA: 0x66ED, //CJK UNIFIED IDEOGRAPH + 0xF8AB: 0x66EE, //CJK UNIFIED IDEOGRAPH + 0xF8AC: 0x6B13, //CJK UNIFIED IDEOGRAPH + 0xF8AD: 0x705F, //CJK UNIFIED IDEOGRAPH + 0xF8AE: 0x7061, //CJK UNIFIED IDEOGRAPH + 0xF8AF: 0x705D, //CJK UNIFIED IDEOGRAPH + 0xF8B0: 0x7060, //CJK UNIFIED IDEOGRAPH + 0xF8B1: 0x7223, //CJK UNIFIED IDEOGRAPH + 0xF8B2: 0x74DB, //CJK UNIFIED IDEOGRAPH + 0xF8B3: 0x74E5, //CJK UNIFIED IDEOGRAPH + 0xF8B4: 0x77D5, //CJK UNIFIED IDEOGRAPH + 0xF8B5: 0x7938, //CJK UNIFIED IDEOGRAPH + 0xF8B6: 0x79B7, //CJK UNIFIED IDEOGRAPH + 0xF8B7: 0x79B6, //CJK UNIFIED IDEOGRAPH + 0xF8B8: 0x7C6A, //CJK UNIFIED IDEOGRAPH + 0xF8B9: 0x7E97, //CJK UNIFIED IDEOGRAPH + 0xF8BA: 0x7F89, //CJK UNIFIED IDEOGRAPH + 0xF8BB: 0x826D, //CJK UNIFIED IDEOGRAPH + 0xF8BC: 0x8643, //CJK UNIFIED IDEOGRAPH + 0xF8BD: 0x8838, //CJK UNIFIED IDEOGRAPH + 0xF8BE: 0x8837, //CJK UNIFIED IDEOGRAPH + 0xF8BF: 0x8835, //CJK UNIFIED IDEOGRAPH + 0xF8C0: 0x884B, //CJK UNIFIED IDEOGRAPH + 0xF8C1: 0x8B94, //CJK UNIFIED IDEOGRAPH + 0xF8C2: 0x8B95, //CJK UNIFIED IDEOGRAPH + 0xF8C3: 0x8E9E, //CJK UNIFIED IDEOGRAPH + 0xF8C4: 0x8E9F, //CJK UNIFIED IDEOGRAPH + 0xF8C5: 0x8EA0, //CJK UNIFIED IDEOGRAPH + 0xF8C6: 0x8E9D, //CJK UNIFIED IDEOGRAPH + 0xF8C7: 0x91BE, //CJK UNIFIED IDEOGRAPH + 0xF8C8: 0x91BD, //CJK UNIFIED IDEOGRAPH + 0xF8C9: 0x91C2, //CJK UNIFIED IDEOGRAPH + 0xF8CA: 0x946B, //CJK UNIFIED IDEOGRAPH + 0xF8CB: 0x9468, //CJK UNIFIED IDEOGRAPH + 0xF8CC: 0x9469, //CJK UNIFIED IDEOGRAPH + 0xF8CD: 0x96E5, //CJK UNIFIED IDEOGRAPH + 0xF8CE: 0x9746, //CJK UNIFIED IDEOGRAPH + 0xF8CF: 0x9743, //CJK UNIFIED IDEOGRAPH + 0xF8D0: 0x9747, //CJK UNIFIED IDEOGRAPH + 0xF8D1: 0x97C7, //CJK UNIFIED IDEOGRAPH + 0xF8D2: 0x97E5, //CJK UNIFIED IDEOGRAPH + 0xF8D3: 0x9A5E, //CJK UNIFIED IDEOGRAPH + 0xF8D4: 0x9AD5, //CJK UNIFIED IDEOGRAPH + 0xF8D5: 0x9B59, //CJK UNIFIED IDEOGRAPH + 0xF8D6: 0x9C63, //CJK UNIFIED IDEOGRAPH + 0xF8D7: 0x9C67, //CJK UNIFIED IDEOGRAPH + 0xF8D8: 0x9C66, //CJK UNIFIED IDEOGRAPH + 0xF8D9: 0x9C62, //CJK UNIFIED IDEOGRAPH + 0xF8DA: 0x9C5E, //CJK UNIFIED IDEOGRAPH + 0xF8DB: 0x9C60, //CJK UNIFIED IDEOGRAPH + 0xF8DC: 0x9E02, //CJK UNIFIED IDEOGRAPH + 0xF8DD: 0x9DFE, //CJK UNIFIED IDEOGRAPH + 0xF8DE: 0x9E07, //CJK UNIFIED IDEOGRAPH + 0xF8DF: 0x9E03, //CJK UNIFIED IDEOGRAPH + 0xF8E0: 0x9E06, //CJK UNIFIED IDEOGRAPH + 0xF8E1: 0x9E05, //CJK UNIFIED IDEOGRAPH + 0xF8E2: 0x9E00, //CJK UNIFIED IDEOGRAPH + 0xF8E3: 0x9E01, //CJK UNIFIED IDEOGRAPH + 0xF8E4: 0x9E09, //CJK UNIFIED IDEOGRAPH + 0xF8E5: 0x9DFF, //CJK UNIFIED IDEOGRAPH + 0xF8E6: 0x9DFD, //CJK UNIFIED IDEOGRAPH + 0xF8E7: 0x9E04, //CJK UNIFIED IDEOGRAPH + 0xF8E8: 0x9EA0, //CJK UNIFIED IDEOGRAPH + 0xF8E9: 0x9F1E, //CJK UNIFIED IDEOGRAPH + 0xF8EA: 0x9F46, //CJK UNIFIED IDEOGRAPH + 0xF8EB: 0x9F74, //CJK UNIFIED IDEOGRAPH + 0xF8EC: 0x9F75, //CJK UNIFIED IDEOGRAPH + 0xF8ED: 0x9F76, //CJK UNIFIED IDEOGRAPH + 0xF8EE: 0x56D4, //CJK UNIFIED IDEOGRAPH + 0xF8EF: 0x652E, //CJK UNIFIED IDEOGRAPH + 0xF8F0: 0x65B8, //CJK UNIFIED IDEOGRAPH + 0xF8F1: 0x6B18, //CJK UNIFIED IDEOGRAPH + 0xF8F2: 0x6B19, //CJK UNIFIED IDEOGRAPH + 0xF8F3: 0x6B17, //CJK UNIFIED IDEOGRAPH + 0xF8F4: 0x6B1A, //CJK UNIFIED IDEOGRAPH + 0xF8F5: 0x7062, //CJK UNIFIED IDEOGRAPH + 0xF8F6: 0x7226, //CJK UNIFIED IDEOGRAPH + 0xF8F7: 0x72AA, //CJK UNIFIED IDEOGRAPH + 0xF8F8: 0x77D8, //CJK UNIFIED IDEOGRAPH + 0xF8F9: 0x77D9, //CJK UNIFIED IDEOGRAPH + 0xF8FA: 0x7939, //CJK UNIFIED IDEOGRAPH + 0xF8FB: 0x7C69, //CJK UNIFIED IDEOGRAPH + 0xF8FC: 0x7C6B, //CJK UNIFIED IDEOGRAPH + 0xF8FD: 0x7CF6, //CJK UNIFIED IDEOGRAPH + 0xF8FE: 0x7E9A, //CJK UNIFIED IDEOGRAPH + 0xF940: 0x7E98, //CJK UNIFIED IDEOGRAPH + 0xF941: 0x7E9B, //CJK UNIFIED IDEOGRAPH + 0xF942: 0x7E99, //CJK UNIFIED IDEOGRAPH + 0xF943: 0x81E0, //CJK UNIFIED IDEOGRAPH + 0xF944: 0x81E1, //CJK UNIFIED IDEOGRAPH + 0xF945: 0x8646, //CJK UNIFIED IDEOGRAPH + 0xF946: 0x8647, //CJK UNIFIED IDEOGRAPH + 0xF947: 0x8648, //CJK UNIFIED IDEOGRAPH + 0xF948: 0x8979, //CJK UNIFIED IDEOGRAPH + 0xF949: 0x897A, //CJK UNIFIED IDEOGRAPH + 0xF94A: 0x897C, //CJK UNIFIED IDEOGRAPH + 0xF94B: 0x897B, //CJK UNIFIED IDEOGRAPH + 0xF94C: 0x89FF, //CJK UNIFIED IDEOGRAPH + 0xF94D: 0x8B98, //CJK UNIFIED IDEOGRAPH + 0xF94E: 0x8B99, //CJK UNIFIED IDEOGRAPH + 0xF94F: 0x8EA5, //CJK UNIFIED IDEOGRAPH + 0xF950: 0x8EA4, //CJK UNIFIED IDEOGRAPH + 0xF951: 0x8EA3, //CJK UNIFIED IDEOGRAPH + 0xF952: 0x946E, //CJK UNIFIED IDEOGRAPH + 0xF953: 0x946D, //CJK UNIFIED IDEOGRAPH + 0xF954: 0x946F, //CJK UNIFIED IDEOGRAPH + 0xF955: 0x9471, //CJK UNIFIED IDEOGRAPH + 0xF956: 0x9473, //CJK UNIFIED IDEOGRAPH + 0xF957: 0x9749, //CJK UNIFIED IDEOGRAPH + 0xF958: 0x9872, //CJK UNIFIED IDEOGRAPH + 0xF959: 0x995F, //CJK UNIFIED IDEOGRAPH + 0xF95A: 0x9C68, //CJK UNIFIED IDEOGRAPH + 0xF95B: 0x9C6E, //CJK UNIFIED IDEOGRAPH + 0xF95C: 0x9C6D, //CJK UNIFIED IDEOGRAPH + 0xF95D: 0x9E0B, //CJK UNIFIED IDEOGRAPH + 0xF95E: 0x9E0D, //CJK UNIFIED IDEOGRAPH + 0xF95F: 0x9E10, //CJK UNIFIED IDEOGRAPH + 0xF960: 0x9E0F, //CJK UNIFIED IDEOGRAPH + 0xF961: 0x9E12, //CJK UNIFIED IDEOGRAPH + 0xF962: 0x9E11, //CJK UNIFIED IDEOGRAPH + 0xF963: 0x9EA1, //CJK UNIFIED IDEOGRAPH + 0xF964: 0x9EF5, //CJK UNIFIED IDEOGRAPH + 0xF965: 0x9F09, //CJK UNIFIED IDEOGRAPH + 0xF966: 0x9F47, //CJK UNIFIED IDEOGRAPH + 0xF967: 0x9F78, //CJK UNIFIED IDEOGRAPH + 0xF968: 0x9F7B, //CJK UNIFIED IDEOGRAPH + 0xF969: 0x9F7A, //CJK UNIFIED IDEOGRAPH + 0xF96A: 0x9F79, //CJK UNIFIED IDEOGRAPH + 0xF96B: 0x571E, //CJK UNIFIED IDEOGRAPH + 0xF96C: 0x7066, //CJK UNIFIED IDEOGRAPH + 0xF96D: 0x7C6F, //CJK UNIFIED IDEOGRAPH + 0xF96E: 0x883C, //CJK UNIFIED IDEOGRAPH + 0xF96F: 0x8DB2, //CJK UNIFIED IDEOGRAPH + 0xF970: 0x8EA6, //CJK UNIFIED IDEOGRAPH + 0xF971: 0x91C3, //CJK UNIFIED IDEOGRAPH + 0xF972: 0x9474, //CJK UNIFIED IDEOGRAPH + 0xF973: 0x9478, //CJK UNIFIED IDEOGRAPH + 0xF974: 0x9476, //CJK UNIFIED IDEOGRAPH + 0xF975: 0x9475, //CJK UNIFIED IDEOGRAPH + 0xF976: 0x9A60, //CJK UNIFIED IDEOGRAPH + 0xF977: 0x9C74, //CJK UNIFIED IDEOGRAPH + 0xF978: 0x9C73, //CJK UNIFIED IDEOGRAPH + 0xF979: 0x9C71, //CJK UNIFIED IDEOGRAPH + 0xF97A: 0x9C75, //CJK UNIFIED IDEOGRAPH + 0xF97B: 0x9E14, //CJK UNIFIED IDEOGRAPH + 0xF97C: 0x9E13, //CJK UNIFIED IDEOGRAPH + 0xF97D: 0x9EF6, //CJK UNIFIED IDEOGRAPH + 0xF97E: 0x9F0A, //CJK UNIFIED IDEOGRAPH + 0xF9A1: 0x9FA4, //CJK UNIFIED IDEOGRAPH + 0xF9A2: 0x7068, //CJK UNIFIED IDEOGRAPH + 0xF9A3: 0x7065, //CJK UNIFIED IDEOGRAPH + 0xF9A4: 0x7CF7, //CJK UNIFIED IDEOGRAPH + 0xF9A5: 0x866A, //CJK UNIFIED IDEOGRAPH + 0xF9A6: 0x883E, //CJK UNIFIED IDEOGRAPH + 0xF9A7: 0x883D, //CJK UNIFIED IDEOGRAPH + 0xF9A8: 0x883F, //CJK UNIFIED IDEOGRAPH + 0xF9A9: 0x8B9E, //CJK UNIFIED IDEOGRAPH + 0xF9AA: 0x8C9C, //CJK UNIFIED IDEOGRAPH + 0xF9AB: 0x8EA9, //CJK UNIFIED IDEOGRAPH + 0xF9AC: 0x8EC9, //CJK UNIFIED IDEOGRAPH + 0xF9AD: 0x974B, //CJK UNIFIED IDEOGRAPH + 0xF9AE: 0x9873, //CJK UNIFIED IDEOGRAPH + 0xF9AF: 0x9874, //CJK UNIFIED IDEOGRAPH + 0xF9B0: 0x98CC, //CJK UNIFIED IDEOGRAPH + 0xF9B1: 0x9961, //CJK UNIFIED IDEOGRAPH + 0xF9B2: 0x99AB, //CJK UNIFIED IDEOGRAPH + 0xF9B3: 0x9A64, //CJK UNIFIED IDEOGRAPH + 0xF9B4: 0x9A66, //CJK UNIFIED IDEOGRAPH + 0xF9B5: 0x9A67, //CJK UNIFIED IDEOGRAPH + 0xF9B6: 0x9B24, //CJK UNIFIED IDEOGRAPH + 0xF9B7: 0x9E15, //CJK UNIFIED IDEOGRAPH + 0xF9B8: 0x9E17, //CJK UNIFIED IDEOGRAPH + 0xF9B9: 0x9F48, //CJK UNIFIED IDEOGRAPH + 0xF9BA: 0x6207, //CJK UNIFIED IDEOGRAPH + 0xF9BB: 0x6B1E, //CJK UNIFIED IDEOGRAPH + 0xF9BC: 0x7227, //CJK UNIFIED IDEOGRAPH + 0xF9BD: 0x864C, //CJK UNIFIED IDEOGRAPH + 0xF9BE: 0x8EA8, //CJK UNIFIED IDEOGRAPH + 0xF9BF: 0x9482, //CJK UNIFIED IDEOGRAPH + 0xF9C0: 0x9480, //CJK UNIFIED IDEOGRAPH + 0xF9C1: 0x9481, //CJK UNIFIED IDEOGRAPH + 0xF9C2: 0x9A69, //CJK UNIFIED IDEOGRAPH + 0xF9C3: 0x9A68, //CJK UNIFIED IDEOGRAPH + 0xF9C4: 0x9B2E, //CJK UNIFIED IDEOGRAPH + 0xF9C5: 0x9E19, //CJK UNIFIED IDEOGRAPH + 0xF9C6: 0x7229, //CJK UNIFIED IDEOGRAPH + 0xF9C7: 0x864B, //CJK UNIFIED IDEOGRAPH + 0xF9C8: 0x8B9F, //CJK UNIFIED IDEOGRAPH + 0xF9C9: 0x9483, //CJK UNIFIED IDEOGRAPH + 0xF9CA: 0x9C79, //CJK UNIFIED IDEOGRAPH + 0xF9CB: 0x9EB7, //CJK UNIFIED IDEOGRAPH + 0xF9CC: 0x7675, //CJK UNIFIED IDEOGRAPH + 0xF9CD: 0x9A6B, //CJK UNIFIED IDEOGRAPH + 0xF9CE: 0x9C7A, //CJK UNIFIED IDEOGRAPH + 0xF9CF: 0x9E1D, //CJK UNIFIED IDEOGRAPH + 0xF9D0: 0x7069, //CJK UNIFIED IDEOGRAPH + 0xF9D1: 0x706A, //CJK UNIFIED IDEOGRAPH + 0xF9D2: 0x9EA4, //CJK UNIFIED IDEOGRAPH + 0xF9D3: 0x9F7E, //CJK UNIFIED IDEOGRAPH + 0xF9D4: 0x9F49, //CJK UNIFIED IDEOGRAPH + 0xF9D5: 0x9F98, //CJK UNIFIED IDEOGRAPH + 0xF9D6: 0x7881, //CJK UNIFIED IDEOGRAPH + 0xF9D7: 0x92B9, //CJK UNIFIED IDEOGRAPH + 0xF9D8: 0x88CF, //CJK UNIFIED IDEOGRAPH + 0xF9D9: 0x58BB, //CJK UNIFIED IDEOGRAPH + 0xF9DA: 0x6052, //CJK UNIFIED IDEOGRAPH + 0xF9DB: 0x7CA7, //CJK UNIFIED IDEOGRAPH + 0xF9DC: 0x5AFA, //CJK UNIFIED IDEOGRAPH + 0xF9DD: 0x2554, //BOX DRAWINGS DOUBLE DOWN AND RIGHT + 0xF9DE: 0x2566, //BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + 0xF9DF: 0x2557, //BOX DRAWINGS DOUBLE DOWN AND LEFT + 0xF9E0: 0x2560, //BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + 0xF9E1: 0x256C, //BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + 0xF9E2: 0x2563, //BOX DRAWINGS DOUBLE VERTICAL AND LEFT + 0xF9E3: 0x255A, //BOX DRAWINGS DOUBLE UP AND RIGHT + 0xF9E4: 0x2569, //BOX DRAWINGS DOUBLE UP AND HORIZONTAL + 0xF9E5: 0x255D, //BOX DRAWINGS DOUBLE UP AND LEFT + 0xF9E6: 0x2552, //BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE + 0xF9E7: 0x2564, //BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE + 0xF9E8: 0x2555, //BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE + 0xF9E9: 0x255E, //BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + 0xF9EA: 0x256A, //BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + 0xF9EB: 0x2561, //BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + 0xF9EC: 0x2558, //BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE + 0xF9ED: 0x2567, //BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE + 0xF9EE: 0x255B, //BOX DRAWINGS UP SINGLE AND LEFT DOUBLE + 0xF9EF: 0x2553, //BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE + 0xF9F0: 0x2565, //BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE + 0xF9F1: 0x2556, //BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE + 0xF9F2: 0x255F, //BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE + 0xF9F3: 0x256B, //BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE + 0xF9F4: 0x2562, //BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE + 0xF9F5: 0x2559, //BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE + 0xF9F6: 0x2568, //BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE + 0xF9F7: 0x255C, //BOX DRAWINGS UP DOUBLE AND LEFT SINGLE + 0xF9F8: 0x2551, //BOX DRAWINGS DOUBLE VERTICAL + 0xF9F9: 0x2550, //BOX DRAWINGS DOUBLE HORIZONTAL + 0xF9FA: 0x256D, //BOX DRAWINGS LIGHT ARC DOWN AND RIGHT + 0xF9FB: 0x256E, //BOX DRAWINGS LIGHT ARC DOWN AND LEFT + 0xF9FC: 0x2570, //BOX DRAWINGS LIGHT ARC UP AND RIGHT + 0xF9FD: 0x256F, //BOX DRAWINGS LIGHT ARC UP AND LEFT + 0xF9FE: 0x2593, //DARK SHADE + }, +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/log.go b/vendor/github.com/denisenkom/go-mssqldb/log.go new file mode 100644 index 00000000..9b8c551e --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/log.go @@ -0,0 +1,30 @@ +package mssql + +import ( + "log" +) + +type Logger interface { + Printf(format string, v ...interface{}) + Println(v ...interface{}) +} + +type optionalLogger struct { + logger Logger +} + +func (o optionalLogger) Printf(format string, v ...interface{}) { + if o.logger != nil { + o.logger.Printf(format, v...) + } else { + log.Printf(format, v...) + } +} + +func (o optionalLogger) Println(v ...interface{}) { + if o.logger != nil { + o.logger.Println(v...) + } else { + log.Println(v...) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql.go b/vendor/github.com/denisenkom/go-mssqldb/mssql.go new file mode 100644 index 00000000..9065da53 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql.go @@ -0,0 +1,973 @@ +package mssql + +import ( + "context" + "database/sql" + "database/sql/driver" + "encoding/binary" + "errors" + "fmt" + "io" + "math" + "net" + "reflect" + "strings" + "time" + "unicode" +) + +// ReturnStatus may be used to return the return value from a proc. +// +// var rs mssql.ReturnStatus +// _, err := db.Exec("theproc", &rs) +// log.Printf("return status = %d", rs) +type ReturnStatus int32 + +var driverInstance = &Driver{processQueryText: true} +var driverInstanceNoProcess = &Driver{processQueryText: false} + +func init() { + sql.Register("mssql", driverInstance) + sql.Register("sqlserver", driverInstanceNoProcess) + createDialer = func(p *connectParams) Dialer { + return netDialer{&net.Dialer{KeepAlive: p.keepAlive}} + } +} + +var createDialer func(p *connectParams) Dialer + +type netDialer struct { + nd *net.Dialer +} + +func (d netDialer) DialContext(ctx context.Context, network string, addr string) (net.Conn, error) { + return d.nd.DialContext(ctx, network, addr) +} + +type Driver struct { + log optionalLogger + + processQueryText bool +} + +// OpenConnector opens a new connector. Useful to dial with a context. +func (d *Driver) OpenConnector(dsn string) (*Connector, error) { + params, err := parseConnectParams(dsn) + if err != nil { + return nil, err + } + return &Connector{ + params: params, + driver: d, + }, nil +} + +func (d *Driver) Open(dsn string) (driver.Conn, error) { + return d.open(context.Background(), dsn) +} + +func SetLogger(logger Logger) { + driverInstance.SetLogger(logger) + driverInstanceNoProcess.SetLogger(logger) +} + +func (d *Driver) SetLogger(logger Logger) { + d.log = optionalLogger{logger} +} + +// NewConnector creates a new connector from a DSN. +// The returned connector may be used with sql.OpenDB. +func NewConnector(dsn string) (*Connector, error) { + params, err := parseConnectParams(dsn) + if err != nil { + return nil, err + } + c := &Connector{ + params: params, + driver: driverInstanceNoProcess, + } + return c, nil +} + +// Connector holds the parsed DSN and is ready to make a new connection +// at any time. +// +// In the future, settings that cannot be passed through a string DSN +// may be set directly on the connector. +type Connector struct { + params connectParams + driver *Driver + + // SessionInitSQL is executed after marking a given session to be reset. + // When not present, the next query will still reset the session to the + // database defaults. + // + // When present the connection will immediately mark the session to + // be reset, then execute the SessionInitSQL text to setup the session + // that may be different from the base database defaults. + // + // For Example, the application relies on the following defaults + // but is not allowed to set them at the database system level. + // + // SET XACT_ABORT ON; + // SET TEXTSIZE -1; + // SET ANSI_NULLS ON; + // SET LOCK_TIMEOUT 10000; + // + // SessionInitSQL should not attempt to manually call sp_reset_connection. + // This will happen at the TDS layer. + // + // SessionInitSQL is optional. The session will be reset even if + // SessionInitSQL is empty. + SessionInitSQL string + + // Dialer sets a custom dialer for all network operations. + // If Dialer is not set, normal net dialers are used. + Dialer Dialer +} + +type Dialer interface { + DialContext(ctx context.Context, network string, addr string) (net.Conn, error) +} + +func (c *Connector) getDialer(p *connectParams) Dialer { + if c != nil && c.Dialer != nil { + return c.Dialer + } + return createDialer(p) +} + +type Conn struct { + connector *Connector + sess *tdsSession + transactionCtx context.Context + resetSession bool + + processQueryText bool + connectionGood bool + + outs map[string]interface{} + returnStatus *ReturnStatus +} + +func (c *Conn) setReturnStatus(s ReturnStatus) { + if c.returnStatus == nil { + return + } + *c.returnStatus = s +} + +func (c *Conn) checkBadConn(err error) error { + // this is a hack to address Issue #275 + // we set connectionGood flag to false if + // error indicates that connection is not usable + // but we return actual error instead of ErrBadConn + // this will cause connection to stay in a pool + // but next request to this connection will return ErrBadConn + + // it might be possible to revise this hack after + // https://github.com/golang/go/issues/20807 + // is implemented + switch err { + case nil: + return nil + case io.EOF: + c.connectionGood = false + return driver.ErrBadConn + case driver.ErrBadConn: + // It is an internal programming error if driver.ErrBadConn + // is ever passed to this function. driver.ErrBadConn should + // only ever be returned in response to a *mssql.Conn.connectionGood == false + // check in the external facing API. + panic("driver.ErrBadConn in checkBadConn. This should not happen.") + } + + switch err.(type) { + case net.Error: + c.connectionGood = false + return err + case StreamError: + c.connectionGood = false + return err + default: + return err + } +} + +func (c *Conn) clearOuts() { + c.outs = nil +} + +func (c *Conn) simpleProcessResp(ctx context.Context) error { + tokchan := make(chan tokenStruct, 5) + go processResponse(ctx, c.sess, tokchan, c.outs) + c.clearOuts() + for tok := range tokchan { + switch token := tok.(type) { + case doneStruct: + if token.isError() { + return c.checkBadConn(token.getError()) + } + case error: + return c.checkBadConn(token) + } + } + return nil +} + +func (c *Conn) Commit() error { + if !c.connectionGood { + return driver.ErrBadConn + } + if err := c.sendCommitRequest(); err != nil { + return c.checkBadConn(err) + } + return c.simpleProcessResp(c.transactionCtx) +} + +func (c *Conn) sendCommitRequest() error { + headers := []headerStruct{ + {hdrtype: dataStmHdrTransDescr, + data: transDescrHdr{c.sess.tranid, 1}.pack()}, + } + reset := c.resetSession + c.resetSession = false + if err := sendCommitXact(c.sess.buf, headers, "", 0, 0, "", reset); err != nil { + if c.sess.logFlags&logErrors != 0 { + c.sess.log.Printf("Failed to send CommitXact with %v", err) + } + c.connectionGood = false + return fmt.Errorf("Faild to send CommitXact: %v", err) + } + return nil +} + +func (c *Conn) Rollback() error { + if !c.connectionGood { + return driver.ErrBadConn + } + if err := c.sendRollbackRequest(); err != nil { + return c.checkBadConn(err) + } + return c.simpleProcessResp(c.transactionCtx) +} + +func (c *Conn) sendRollbackRequest() error { + headers := []headerStruct{ + {hdrtype: dataStmHdrTransDescr, + data: transDescrHdr{c.sess.tranid, 1}.pack()}, + } + reset := c.resetSession + c.resetSession = false + if err := sendRollbackXact(c.sess.buf, headers, "", 0, 0, "", reset); err != nil { + if c.sess.logFlags&logErrors != 0 { + c.sess.log.Printf("Failed to send RollbackXact with %v", err) + } + c.connectionGood = false + return fmt.Errorf("Failed to send RollbackXact: %v", err) + } + return nil +} + +func (c *Conn) Begin() (driver.Tx, error) { + return c.begin(context.Background(), isolationUseCurrent) +} + +func (c *Conn) begin(ctx context.Context, tdsIsolation isoLevel) (tx driver.Tx, err error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + err = c.sendBeginRequest(ctx, tdsIsolation) + if err != nil { + return nil, c.checkBadConn(err) + } + tx, err = c.processBeginResponse(ctx) + if err != nil { + return nil, c.checkBadConn(err) + } + return +} + +func (c *Conn) sendBeginRequest(ctx context.Context, tdsIsolation isoLevel) error { + c.transactionCtx = ctx + headers := []headerStruct{ + {hdrtype: dataStmHdrTransDescr, + data: transDescrHdr{0, 1}.pack()}, + } + reset := c.resetSession + c.resetSession = false + if err := sendBeginXact(c.sess.buf, headers, tdsIsolation, "", reset); err != nil { + if c.sess.logFlags&logErrors != 0 { + c.sess.log.Printf("Failed to send BeginXact with %v", err) + } + c.connectionGood = false + return fmt.Errorf("Failed to send BeginXact: %v", err) + } + return nil +} + +func (c *Conn) processBeginResponse(ctx context.Context) (driver.Tx, error) { + if err := c.simpleProcessResp(ctx); err != nil { + return nil, err + } + // successful BEGINXACT request will return sess.tranid + // for started transaction + return c, nil +} + +func (d *Driver) open(ctx context.Context, dsn string) (*Conn, error) { + params, err := parseConnectParams(dsn) + if err != nil { + return nil, err + } + return d.connect(ctx, nil, params) +} + +// connect to the server, using the provided context for dialing only. +func (d *Driver) connect(ctx context.Context, c *Connector, params connectParams) (*Conn, error) { + sess, err := connect(ctx, c, d.log, params) + if err != nil { + // main server failed, try fail-over partner + if params.failOverPartner == "" { + return nil, err + } + + params.host = params.failOverPartner + if params.failOverPort != 0 { + params.port = params.failOverPort + } + + sess, err = connect(ctx, c, d.log, params) + if err != nil { + // fail-over partner also failed, now fail + return nil, err + } + } + + conn := &Conn{ + connector: c, + sess: sess, + transactionCtx: context.Background(), + processQueryText: d.processQueryText, + connectionGood: true, + } + conn.sess.log = d.log + + return conn, nil +} + +func (c *Conn) Close() error { + return c.sess.buf.transport.Close() +} + +type Stmt struct { + c *Conn + query string + paramCount int + notifSub *queryNotifSub +} + +type queryNotifSub struct { + msgText string + options string + timeout uint32 +} + +func (c *Conn) Prepare(query string) (driver.Stmt, error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + if len(query) > 10 && strings.EqualFold(query[:10], "INSERTBULK") { + return c.prepareCopyIn(context.Background(), query) + } + return c.prepareContext(context.Background(), query) +} + +func (c *Conn) prepareContext(ctx context.Context, query string) (*Stmt, error) { + paramCount := -1 + if c.processQueryText { + query, paramCount = parseParams(query) + } + return &Stmt{c, query, paramCount, nil}, nil +} + +func (s *Stmt) Close() error { + return nil +} + +func (s *Stmt) SetQueryNotification(id, options string, timeout time.Duration) { + to := uint32(timeout / time.Second) + if to < 1 { + to = 1 + } + s.notifSub = &queryNotifSub{id, options, to} +} + +func (s *Stmt) NumInput() int { + return s.paramCount +} + +func (s *Stmt) sendQuery(args []namedValue) (err error) { + headers := []headerStruct{ + {hdrtype: dataStmHdrTransDescr, + data: transDescrHdr{s.c.sess.tranid, 1}.pack()}, + } + + if s.notifSub != nil { + headers = append(headers, + headerStruct{ + hdrtype: dataStmHdrQueryNotif, + data: queryNotifHdr{ + s.notifSub.msgText, + s.notifSub.options, + s.notifSub.timeout, + }.pack(), + }) + } + + conn := s.c + + // no need to check number of parameters here, it is checked by database/sql + if conn.sess.logFlags&logSQL != 0 { + conn.sess.log.Println(s.query) + } + if conn.sess.logFlags&logParams != 0 && len(args) > 0 { + for i := 0; i < len(args); i++ { + if len(args[i].Name) > 0 { + s.c.sess.log.Printf("\t@%s\t%v\n", args[i].Name, args[i].Value) + } else { + s.c.sess.log.Printf("\t@p%d\t%v\n", i+1, args[i].Value) + } + } + } + + reset := conn.resetSession + conn.resetSession = false + if len(args) == 0 { + if err = sendSqlBatch72(conn.sess.buf, s.query, headers, reset); err != nil { + if conn.sess.logFlags&logErrors != 0 { + conn.sess.log.Printf("Failed to send SqlBatch with %v", err) + } + conn.connectionGood = false + return fmt.Errorf("failed to send SQL Batch: %v", err) + } + } else { + proc := sp_ExecuteSql + var params []param + if isProc(s.query) { + proc.name = s.query + params, _, err = s.makeRPCParams(args, 0) + if err != nil { + return + } + } else { + var decls []string + params, decls, err = s.makeRPCParams(args, 2) + if err != nil { + return + } + params[0] = makeStrParam(s.query) + params[1] = makeStrParam(strings.Join(decls, ",")) + } + if err = sendRpc(conn.sess.buf, headers, proc, 0, params, reset); err != nil { + if conn.sess.logFlags&logErrors != 0 { + conn.sess.log.Printf("Failed to send Rpc with %v", err) + } + conn.connectionGood = false + return fmt.Errorf("Failed to send RPC: %v", err) + } + } + return +} + +// isProc takes the query text in s and determines if it is a stored proc name +// or SQL text. +func isProc(s string) bool { + if len(s) == 0 { + return false + } + const ( + outside = iota + text + escaped + ) + st := outside + var rn1, rPrev rune + for _, r := range s { + rPrev = rn1 + rn1 = r + switch r { + // No newlines or string sequences. + case '\n', '\r', '\'', ';': + return false + } + switch st { + case outside: + switch { + case unicode.IsSpace(r): + return false + case r == '[': + st = escaped + continue + case r == ']' && rPrev == ']': + st = escaped + continue + case unicode.IsLetter(r): + st = text + } + case text: + switch { + case r == '.': + st = outside + continue + case unicode.IsSpace(r): + return false + } + case escaped: + switch { + case r == ']': + st = outside + continue + } + } + } + return true +} + +func (s *Stmt) makeRPCParams(args []namedValue, offset int) ([]param, []string, error) { + var err error + params := make([]param, len(args)+offset) + decls := make([]string, len(args)) + for i, val := range args { + params[i+offset], err = s.makeParam(val.Value) + if err != nil { + return nil, nil, err + } + var name string + if len(val.Name) > 0 { + name = "@" + val.Name + } else { + name = fmt.Sprintf("@p%d", val.Ordinal) + } + params[i+offset].Name = name + decls[i] = fmt.Sprintf("%s %s", name, makeDecl(params[i+offset].ti)) + } + return params, decls, nil +} + +type namedValue struct { + Name string + Ordinal int + Value driver.Value +} + +func convertOldArgs(args []driver.Value) []namedValue { + list := make([]namedValue, len(args)) + for i, v := range args { + list[i] = namedValue{ + Ordinal: i + 1, + Value: v, + } + } + return list +} + +func (s *Stmt) Query(args []driver.Value) (driver.Rows, error) { + return s.queryContext(context.Background(), convertOldArgs(args)) +} + +func (s *Stmt) queryContext(ctx context.Context, args []namedValue) (rows driver.Rows, err error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } + if err = s.sendQuery(args); err != nil { + return nil, s.c.checkBadConn(err) + } + return s.processQueryResponse(ctx) +} + +func (s *Stmt) processQueryResponse(ctx context.Context) (res driver.Rows, err error) { + tokchan := make(chan tokenStruct, 5) + ctx, cancel := context.WithCancel(ctx) + go processResponse(ctx, s.c.sess, tokchan, s.c.outs) + s.c.clearOuts() + // process metadata + var cols []columnStruct +loop: + for tok := range tokchan { + switch token := tok.(type) { + // By ignoring DONE token we effectively + // skip empty result-sets. + // This improves results in queries like that: + // set nocount on; select 1 + // see TestIgnoreEmptyResults test + //case doneStruct: + //break loop + case []columnStruct: + cols = token + break loop + case doneStruct: + if token.isError() { + return nil, s.c.checkBadConn(token.getError()) + } + case ReturnStatus: + s.c.setReturnStatus(token) + case error: + return nil, s.c.checkBadConn(token) + } + } + res = &Rows{stmt: s, tokchan: tokchan, cols: cols, cancel: cancel} + return +} + +func (s *Stmt) Exec(args []driver.Value) (driver.Result, error) { + return s.exec(context.Background(), convertOldArgs(args)) +} + +func (s *Stmt) exec(ctx context.Context, args []namedValue) (res driver.Result, err error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } + if err = s.sendQuery(args); err != nil { + return nil, s.c.checkBadConn(err) + } + if res, err = s.processExec(ctx); err != nil { + return nil, s.c.checkBadConn(err) + } + return +} + +func (s *Stmt) processExec(ctx context.Context) (res driver.Result, err error) { + tokchan := make(chan tokenStruct, 5) + go processResponse(ctx, s.c.sess, tokchan, s.c.outs) + s.c.clearOuts() + var rowCount int64 + for token := range tokchan { + switch token := token.(type) { + case doneInProcStruct: + if token.Status&doneCount != 0 { + rowCount += int64(token.RowCount) + } + case doneStruct: + if token.Status&doneCount != 0 { + rowCount += int64(token.RowCount) + } + if token.isError() { + return nil, token.getError() + } + case ReturnStatus: + s.c.setReturnStatus(token) + case error: + return nil, token + } + } + return &Result{s.c, rowCount}, nil +} + +type Rows struct { + stmt *Stmt + cols []columnStruct + tokchan chan tokenStruct + + nextCols []columnStruct + + cancel func() +} + +func (rc *Rows) Close() error { + rc.cancel() + for _ = range rc.tokchan { + } + rc.tokchan = nil + return nil +} + +func (rc *Rows) Columns() (res []string) { + res = make([]string, len(rc.cols)) + for i, col := range rc.cols { + res[i] = col.ColName + } + return +} + +func (rc *Rows) Next(dest []driver.Value) error { + if !rc.stmt.c.connectionGood { + return driver.ErrBadConn + } + if rc.nextCols != nil { + return io.EOF + } + for tok := range rc.tokchan { + switch tokdata := tok.(type) { + case []columnStruct: + rc.nextCols = tokdata + return io.EOF + case []interface{}: + for i := range dest { + dest[i] = tokdata[i] + } + return nil + case doneStruct: + if tokdata.isError() { + return rc.stmt.c.checkBadConn(tokdata.getError()) + } + case error: + return rc.stmt.c.checkBadConn(tokdata) + } + } + return io.EOF +} + +func (rc *Rows) HasNextResultSet() bool { + return rc.nextCols != nil +} + +func (rc *Rows) NextResultSet() error { + rc.cols = rc.nextCols + rc.nextCols = nil + if rc.cols == nil { + return io.EOF + } + return nil +} + +// It should return +// the value type that can be used to scan types into. For example, the database +// column type "bigint" this should return "reflect.TypeOf(int64(0))". +func (r *Rows) ColumnTypeScanType(index int) reflect.Type { + return makeGoLangScanType(r.cols[index].ti) +} + +// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the +// database system type name without the length. Type names should be uppercase. +// Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT", +// "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML", +// "TIMESTAMP". +func (r *Rows) ColumnTypeDatabaseTypeName(index int) string { + return makeGoLangTypeName(r.cols[index].ti) +} + +// RowsColumnTypeLength may be implemented by Rows. It should return the length +// of the column type if the column is a variable length type. If the column is +// not a variable length type ok should return false. +// If length is not limited other than system limits, it should return math.MaxInt64. +// The following are examples of returned values for various types: +// TEXT (math.MaxInt64, true) +// varchar(10) (10, true) +// nvarchar(10) (10, true) +// decimal (0, false) +// int (0, false) +// bytea(30) (30, true) +func (r *Rows) ColumnTypeLength(index int) (int64, bool) { + return makeGoLangTypeLength(r.cols[index].ti) +} + +// It should return +// the precision and scale for decimal types. If not applicable, ok should be false. +// The following are examples of returned values for various types: +// decimal(38, 4) (38, 4, true) +// int (0, 0, false) +// decimal (math.MaxInt64, math.MaxInt64, true) +func (r *Rows) ColumnTypePrecisionScale(index int) (int64, int64, bool) { + return makeGoLangTypePrecisionScale(r.cols[index].ti) +} + +// The nullable value should +// be true if it is known the column may be null, or false if the column is known +// to be not nullable. +// If the column nullability is unknown, ok should be false. +func (r *Rows) ColumnTypeNullable(index int) (nullable, ok bool) { + nullable = r.cols[index].Flags&colFlagNullable != 0 + ok = true + return +} + +func makeStrParam(val string) (res param) { + res.ti.TypeId = typeNVarChar + res.buffer = str2ucs2(val) + res.ti.Size = len(res.buffer) + return +} + +func (s *Stmt) makeParam(val driver.Value) (res param, err error) { + if val == nil { + res.ti.TypeId = typeNull + res.buffer = nil + res.ti.Size = 0 + return + } + switch val := val.(type) { + case int64: + res.ti.TypeId = typeIntN + res.buffer = make([]byte, 8) + res.ti.Size = 8 + binary.LittleEndian.PutUint64(res.buffer, uint64(val)) + case sql.NullInt64: + // only null values should be getting here + res.ti.TypeId = typeIntN + res.ti.Size = 8 + res.buffer = []byte{} + + case float64: + res.ti.TypeId = typeFltN + res.ti.Size = 8 + res.buffer = make([]byte, 8) + binary.LittleEndian.PutUint64(res.buffer, math.Float64bits(val)) + case sql.NullFloat64: + // only null values should be getting here + res.ti.TypeId = typeFltN + res.ti.Size = 8 + res.buffer = []byte{} + + case []byte: + res.ti.TypeId = typeBigVarBin + res.ti.Size = len(val) + res.buffer = val + case string: + res = makeStrParam(val) + case sql.NullString: + // only null values should be getting here + res.ti.TypeId = typeNVarChar + res.buffer = nil + res.ti.Size = 8000 + case bool: + res.ti.TypeId = typeBitN + res.ti.Size = 1 + res.buffer = make([]byte, 1) + if val { + res.buffer[0] = 1 + } + case sql.NullBool: + // only null values should be getting here + res.ti.TypeId = typeBitN + res.ti.Size = 1 + res.buffer = []byte{} + + case time.Time: + if s.c.sess.loginAck.TDSVersion >= verTDS73 { + res.ti.TypeId = typeDateTimeOffsetN + res.ti.Scale = 7 + res.buffer = encodeDateTimeOffset(val, int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + } else { + res.ti.TypeId = typeDateTimeN + res.buffer = encodeDateTime(val) + res.ti.Size = len(res.buffer) + } + default: + return s.makeParamExtra(val) + } + return +} + +type Result struct { + c *Conn + rowsAffected int64 +} + +func (r *Result) RowsAffected() (int64, error) { + return r.rowsAffected, nil +} + +func (r *Result) LastInsertId() (int64, error) { + s, err := r.c.Prepare("select cast(@@identity as bigint)") + if err != nil { + return 0, err + } + defer s.Close() + rows, err := s.Query(nil) + if err != nil { + return 0, err + } + defer rows.Close() + dest := make([]driver.Value, 1) + err = rows.Next(dest) + if err != nil { + return 0, err + } + if dest[0] == nil { + return -1, errors.New("There is no generated identity value") + } + lastInsertId := dest[0].(int64) + return lastInsertId, nil +} + +var _ driver.Pinger = &Conn{} + +// Ping is used to check if the remote server is available and satisfies the Pinger interface. +func (c *Conn) Ping(ctx context.Context) error { + if !c.connectionGood { + return driver.ErrBadConn + } + stmt := &Stmt{c, `select 1;`, 0, nil} + _, err := stmt.ExecContext(ctx, nil) + return err +} + +var _ driver.ConnBeginTx = &Conn{} + +// BeginTx satisfies ConnBeginTx. +func (c *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + if opts.ReadOnly { + return nil, errors.New("Read-only transactions are not supported") + } + + var tdsIsolation isoLevel + switch sql.IsolationLevel(opts.Isolation) { + case sql.LevelDefault: + tdsIsolation = isolationUseCurrent + case sql.LevelReadUncommitted: + tdsIsolation = isolationReadUncommited + case sql.LevelReadCommitted: + tdsIsolation = isolationReadCommited + case sql.LevelWriteCommitted: + return nil, errors.New("LevelWriteCommitted isolation level is not supported") + case sql.LevelRepeatableRead: + tdsIsolation = isolationRepeatableRead + case sql.LevelSnapshot: + tdsIsolation = isolationSnapshot + case sql.LevelSerializable: + tdsIsolation = isolationSerializable + case sql.LevelLinearizable: + return nil, errors.New("LevelLinearizable isolation level is not supported") + default: + return nil, errors.New("Isolation level is not supported or unknown") + } + return c.begin(ctx, tdsIsolation) +} + +func (c *Conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + if len(query) > 10 && strings.EqualFold(query[:10], "INSERTBULK") { + return c.prepareCopyIn(ctx, query) + } + + return c.prepareContext(ctx, query) +} + +func (s *Stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } + list := make([]namedValue, len(args)) + for i, nv := range args { + list[i] = namedValue(nv) + } + return s.queryContext(ctx, list) +} + +func (s *Stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } + list := make([]namedValue, len(args)) + for i, nv := range args { + list[i] = namedValue(nv) + } + return s.exec(ctx, list) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go110.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go110.go new file mode 100644 index 00000000..833f0471 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go110.go @@ -0,0 +1,47 @@ +// +build go1.10 + +package mssql + +import ( + "context" + "database/sql/driver" +) + +var _ driver.Connector = &Connector{} +var _ driver.SessionResetter = &Conn{} + +func (c *Conn) ResetSession(ctx context.Context) error { + if !c.connectionGood { + return driver.ErrBadConn + } + c.resetSession = true + + if c.connector == nil || len(c.connector.SessionInitSQL) == 0 { + return nil + } + + s, err := c.prepareContext(ctx, c.connector.SessionInitSQL) + if err != nil { + return driver.ErrBadConn + } + _, err = s.exec(ctx, nil) + if err != nil { + return driver.ErrBadConn + } + + return nil +} + +// Connect to the server and return a TDS connection. +func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) { + conn, err := c.driver.connect(ctx, c, c.params) + if err == nil { + err = conn.ResetSession(ctx) + } + return conn, err +} + +// Driver underlying the Connector. +func (c *Connector) Driver() driver.Driver { + return c.driver +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go new file mode 100644 index 00000000..65a11720 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go @@ -0,0 +1,171 @@ +// +build go1.9 + +package mssql + +import ( + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "reflect" + "time" + + // "github.com/cockroachdb/apd" + "cloud.google.com/go/civil" +) + +// Type alias provided for compatibility. + +type MssqlDriver = Driver // Deprecated: users should transition to the new name when possible. +type MssqlBulk = Bulk // Deprecated: users should transition to the new name when possible. +type MssqlBulkOptions = BulkOptions // Deprecated: users should transition to the new name when possible. +type MssqlConn = Conn // Deprecated: users should transition to the new name when possible. +type MssqlResult = Result // Deprecated: users should transition to the new name when possible. +type MssqlRows = Rows // Deprecated: users should transition to the new name when possible. +type MssqlStmt = Stmt // Deprecated: users should transition to the new name when possible. + +var _ driver.NamedValueChecker = &Conn{} + +// VarChar parameter types. +type VarChar string + +type NVarCharMax string +type VarCharMax string + +// DateTime1 encodes parameters to original DateTime SQL types. +type DateTime1 time.Time + +// DateTimeOffset encodes parameters to DateTimeOffset, preserving the UTC offset. +type DateTimeOffset time.Time + +func convertInputParameter(val interface{}) (interface{}, error) { + switch v := val.(type) { + case VarChar: + return val, nil + case NVarCharMax: + return val, nil + case VarCharMax: + return val, nil + case DateTime1: + return val, nil + case DateTimeOffset: + return val, nil + case civil.Date: + return val, nil + case civil.DateTime: + return val, nil + case civil.Time: + return val, nil + // case *apd.Decimal: + // return nil + default: + return driver.DefaultParameterConverter.ConvertValue(v) + } +} + +func (c *Conn) CheckNamedValue(nv *driver.NamedValue) error { + switch v := nv.Value.(type) { + case sql.Out: + if c.outs == nil { + c.outs = make(map[string]interface{}) + } + c.outs[nv.Name] = v.Dest + + if v.Dest == nil { + return errors.New("destination is a nil pointer") + } + + dest_info := reflect.ValueOf(v.Dest) + if dest_info.Kind() != reflect.Ptr { + return errors.New("destination not a pointer") + } + + if dest_info.IsNil() { + return errors.New("destination is a nil pointer") + } + + pointed_value := reflect.Indirect(dest_info) + + // don't allow pointer to a pointer, only pointer to a value can be handled + // correctly + if pointed_value.Kind() == reflect.Ptr { + return errors.New("destination is a pointer to a pointer") + } + + // Unwrap the Out value and check the inner value. + val := pointed_value.Interface() + if val == nil { + return errors.New("MSSQL does not allow NULL value without type for OUTPUT parameters") + } + conv, err := convertInputParameter(val) + if err != nil { + return err + } + if conv == nil { + // if we replace with nil we would lose type information + nv.Value = sql.Out{Dest: val} + } else { + nv.Value = sql.Out{Dest: conv} + } + return nil + case *ReturnStatus: + *v = 0 // By default the return value should be zero. + c.returnStatus = v + return driver.ErrRemoveArgument + default: + var err error + nv.Value, err = convertInputParameter(nv.Value) + return err + } +} + +func (s *Stmt) makeParamExtra(val driver.Value) (res param, err error) { + switch val := val.(type) { + case VarChar: + res.ti.TypeId = typeBigVarChar + res.buffer = []byte(val) + res.ti.Size = len(res.buffer) + case VarCharMax: + res.ti.TypeId = typeBigVarChar + res.buffer = []byte(val) + res.ti.Size = 0 // currently zero forces varchar(max) + case NVarCharMax: + res.ti.TypeId = typeNVarChar + res.buffer = str2ucs2(string(val)) + res.ti.Size = 0 // currently zero forces nvarchar(max) + case DateTime1: + t := time.Time(val) + res.ti.TypeId = typeDateTimeN + res.buffer = encodeDateTime(t) + res.ti.Size = len(res.buffer) + case DateTimeOffset: + res.ti.TypeId = typeDateTimeOffsetN + res.ti.Scale = 7 + res.buffer = encodeDateTimeOffset(time.Time(val), int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + case civil.Date: + res.ti.TypeId = typeDateN + res.buffer = encodeDate(val.In(time.UTC)) + res.ti.Size = len(res.buffer) + case civil.DateTime: + res.ti.TypeId = typeDateTime2N + res.ti.Scale = 7 + res.buffer = encodeDateTime2(val.In(time.UTC), int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + case civil.Time: + res.ti.TypeId = typeTimeN + res.ti.Scale = 7 + res.buffer = encodeTime(val.Hour, val.Minute, val.Second, val.Nanosecond, int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + case sql.Out: + res, err = s.makeParam(val.Dest) + res.Flags = fByRevValue + default: + err = fmt.Errorf("mssql: unknown type for %T", val) + } + return +} + +func scanIntoOut(name string, fromServer, scanInto interface{}) error { + return convertAssign(scanInto, fromServer) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go new file mode 100644 index 00000000..9680f510 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go @@ -0,0 +1,16 @@ +// +build !go1.9 + +package mssql + +import ( + "database/sql/driver" + "fmt" +) + +func (s *Stmt) makeParamExtra(val driver.Value) (param, error) { + return param{}, fmt.Errorf("mssql: unknown type for %T", val) +} + +func scanIntoOut(name string, fromServer, scanInto interface{}) error { + return fmt.Errorf("mssql: unsupported OUTPUT type, use a newer Go version") +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_test.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_test.go new file mode 100644 index 00000000..2ec8b956 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_test.go @@ -0,0 +1,39 @@ +package mssql + +import ( + "context" + "testing" +) + +func TestBadOpen(t *testing.T) { + drv := driverWithProcess(t) + _, err := drv.open(context.Background(), "port=bad") + if err == nil { + t.Fail() + } +} + +func TestIsProc(t *testing.T) { + list := []struct { + s string + is bool + }{ + {"proc", true}, + {"select 1;", false}, + {"select 1", false}, + {"[proc 1]", true}, + {"[proc\n1]", false}, + {"schema.name", true}, + {"[schema].[name]", true}, + {"schema.[name]", true}, + {"[schema].name", true}, + {"schema.[proc name]", true}, + } + + for _, item := range list { + got := isProc(item.s) + if got != item.is { + t.Errorf("for %q, got %t want %t", item.s, got, item.is) + } + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/net.go b/vendor/github.com/denisenkom/go-mssqldb/net.go new file mode 100644 index 00000000..e3864d1a --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/net.go @@ -0,0 +1,103 @@ +package mssql + +import ( + "fmt" + "net" + "time" +) + +type timeoutConn struct { + c net.Conn + timeout time.Duration + buf *tdsBuffer + packetPending bool + continueRead bool +} + +func newTimeoutConn(conn net.Conn, timeout time.Duration) *timeoutConn { + return &timeoutConn{ + c: conn, + timeout: timeout, + } +} + +func (c *timeoutConn) Read(b []byte) (n int, err error) { + if c.buf != nil { + if c.packetPending { + c.packetPending = false + err = c.buf.FinishPacket() + if err != nil { + err = fmt.Errorf("Cannot send handshake packet: %s", err.Error()) + return + } + c.continueRead = false + } + if !c.continueRead { + var packet packetType + packet, err = c.buf.BeginRead() + if err != nil { + err = fmt.Errorf("Cannot read handshake packet: %s", err.Error()) + return + } + if packet != packPrelogin { + err = fmt.Errorf("unexpected packet %d, expecting prelogin", packet) + return + } + c.continueRead = true + } + n, err = c.buf.Read(b) + return + } + if c.timeout > 0 { + err = c.c.SetDeadline(time.Now().Add(c.timeout)) + if err != nil { + return + } + } + return c.c.Read(b) +} + +func (c *timeoutConn) Write(b []byte) (n int, err error) { + if c.buf != nil { + if !c.packetPending { + c.buf.BeginPacket(packPrelogin, false) + c.packetPending = true + } + n, err = c.buf.Write(b) + if err != nil { + return + } + return + } + if c.timeout > 0 { + err = c.c.SetDeadline(time.Now().Add(c.timeout)) + if err != nil { + return + } + } + return c.c.Write(b) +} + +func (c timeoutConn) Close() error { + return c.c.Close() +} + +func (c timeoutConn) LocalAddr() net.Addr { + return c.c.LocalAddr() +} + +func (c timeoutConn) RemoteAddr() net.Addr { + return c.c.RemoteAddr() +} + +func (c timeoutConn) SetDeadline(t time.Time) error { + panic("Not implemented") +} + +func (c timeoutConn) SetReadDeadline(t time.Time) error { + panic("Not implemented") +} + +func (c timeoutConn) SetWriteDeadline(t time.Time) error { + panic("Not implemented") +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/ntlm.go b/vendor/github.com/denisenkom/go-mssqldb/ntlm.go new file mode 100644 index 00000000..7c0cc4f7 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/ntlm.go @@ -0,0 +1,283 @@ +// +build !windows + +package mssql + +import ( + "crypto/des" + "crypto/md5" + "crypto/rand" + "encoding/binary" + "errors" + "strings" + "unicode/utf16" + + "golang.org/x/crypto/md4" +) + +const ( + _NEGOTIATE_MESSAGE = 1 + _CHALLENGE_MESSAGE = 2 + _AUTHENTICATE_MESSAGE = 3 +) + +const ( + _NEGOTIATE_UNICODE = 0x00000001 + _NEGOTIATE_OEM = 0x00000002 + _NEGOTIATE_TARGET = 0x00000004 + _NEGOTIATE_SIGN = 0x00000010 + _NEGOTIATE_SEAL = 0x00000020 + _NEGOTIATE_DATAGRAM = 0x00000040 + _NEGOTIATE_LMKEY = 0x00000080 + _NEGOTIATE_NTLM = 0x00000200 + _NEGOTIATE_ANONYMOUS = 0x00000800 + _NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000 + _NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000 + _NEGOTIATE_ALWAYS_SIGN = 0x00008000 + _NEGOTIATE_TARGET_TYPE_DOMAIN = 0x00010000 + _NEGOTIATE_TARGET_TYPE_SERVER = 0x00020000 + _NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x00080000 + _NEGOTIATE_IDENTIFY = 0x00100000 + _REQUEST_NON_NT_SESSION_KEY = 0x00400000 + _NEGOTIATE_TARGET_INFO = 0x00800000 + _NEGOTIATE_VERSION = 0x02000000 + _NEGOTIATE_128 = 0x20000000 + _NEGOTIATE_KEY_EXCH = 0x40000000 + _NEGOTIATE_56 = 0x80000000 +) + +const _NEGOTIATE_FLAGS = _NEGOTIATE_UNICODE | + _NEGOTIATE_NTLM | + _NEGOTIATE_OEM_DOMAIN_SUPPLIED | + _NEGOTIATE_OEM_WORKSTATION_SUPPLIED | + _NEGOTIATE_ALWAYS_SIGN | + _NEGOTIATE_EXTENDED_SESSIONSECURITY + +type ntlmAuth struct { + Domain string + UserName string + Password string + Workstation string +} + +func getAuth(user, password, service, workstation string) (auth, bool) { + if !strings.ContainsRune(user, '\\') { + return nil, false + } + domain_user := strings.SplitN(user, "\\", 2) + return &ntlmAuth{ + Domain: domain_user[0], + UserName: domain_user[1], + Password: password, + Workstation: workstation, + }, true +} + +func utf16le(val string) []byte { + var v []byte + for _, r := range val { + if utf16.IsSurrogate(r) { + r1, r2 := utf16.EncodeRune(r) + v = append(v, byte(r1), byte(r1>>8)) + v = append(v, byte(r2), byte(r2>>8)) + } else { + v = append(v, byte(r), byte(r>>8)) + } + } + return v +} + +func (auth *ntlmAuth) InitialBytes() ([]byte, error) { + domain_len := len(auth.Domain) + workstation_len := len(auth.Workstation) + msg := make([]byte, 40+domain_len+workstation_len) + copy(msg, []byte("NTLMSSP\x00")) + binary.LittleEndian.PutUint32(msg[8:], _NEGOTIATE_MESSAGE) + binary.LittleEndian.PutUint32(msg[12:], _NEGOTIATE_FLAGS) + // Domain Name Fields + binary.LittleEndian.PutUint16(msg[16:], uint16(domain_len)) + binary.LittleEndian.PutUint16(msg[18:], uint16(domain_len)) + binary.LittleEndian.PutUint32(msg[20:], 40) + // Workstation Fields + binary.LittleEndian.PutUint16(msg[24:], uint16(workstation_len)) + binary.LittleEndian.PutUint16(msg[26:], uint16(workstation_len)) + binary.LittleEndian.PutUint32(msg[28:], uint32(40+domain_len)) + // Version + binary.LittleEndian.PutUint32(msg[32:], 0) + binary.LittleEndian.PutUint32(msg[36:], 0) + // Payload + copy(msg[40:], auth.Domain) + copy(msg[40+domain_len:], auth.Workstation) + return msg, nil +} + +var errorNTLM = errors.New("NTLM protocol error") + +func createDesKey(bytes, material []byte) { + material[0] = bytes[0] + material[1] = (byte)(bytes[0]<<7 | (bytes[1]&0xff)>>1) + material[2] = (byte)(bytes[1]<<6 | (bytes[2]&0xff)>>2) + material[3] = (byte)(bytes[2]<<5 | (bytes[3]&0xff)>>3) + material[4] = (byte)(bytes[3]<<4 | (bytes[4]&0xff)>>4) + material[5] = (byte)(bytes[4]<<3 | (bytes[5]&0xff)>>5) + material[6] = (byte)(bytes[5]<<2 | (bytes[6]&0xff)>>6) + material[7] = (byte)(bytes[6] << 1) +} + +func oddParity(bytes []byte) { + for i := 0; i < len(bytes); i++ { + b := bytes[i] + needsParity := (((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ (b >> 4) ^ (b >> 3) ^ (b >> 2) ^ (b >> 1)) & 0x01) == 0 + if needsParity { + bytes[i] = bytes[i] | byte(0x01) + } else { + bytes[i] = bytes[i] & byte(0xfe) + } + } +} + +func encryptDes(key []byte, cleartext []byte, ciphertext []byte) { + var desKey [8]byte + createDesKey(key, desKey[:]) + cipher, err := des.NewCipher(desKey[:]) + if err != nil { + panic(err) + } + cipher.Encrypt(ciphertext, cleartext) +} + +func response(challenge [8]byte, hash [21]byte) (ret [24]byte) { + encryptDes(hash[:7], challenge[:], ret[:8]) + encryptDes(hash[7:14], challenge[:], ret[8:16]) + encryptDes(hash[14:], challenge[:], ret[16:]) + return +} + +func lmHash(password string) (hash [21]byte) { + var lmpass [14]byte + copy(lmpass[:14], []byte(strings.ToUpper(password))) + magic := []byte("KGS!@#$%") + encryptDes(lmpass[:7], magic, hash[:8]) + encryptDes(lmpass[7:], magic, hash[8:]) + return +} + +func lmResponse(challenge [8]byte, password string) [24]byte { + hash := lmHash(password) + return response(challenge, hash) +} + +func ntlmHash(password string) (hash [21]byte) { + h := md4.New() + h.Write(utf16le(password)) + h.Sum(hash[:0]) + return +} + +func ntResponse(challenge [8]byte, password string) [24]byte { + hash := ntlmHash(password) + return response(challenge, hash) +} + +func clientChallenge() (nonce [8]byte) { + _, err := rand.Read(nonce[:]) + if err != nil { + panic(err) + } + return +} + +func ntlmSessionResponse(clientNonce [8]byte, serverChallenge [8]byte, password string) [24]byte { + var sessionHash [16]byte + h := md5.New() + h.Write(serverChallenge[:]) + h.Write(clientNonce[:]) + h.Sum(sessionHash[:0]) + var hash [8]byte + copy(hash[:], sessionHash[:8]) + passwordHash := ntlmHash(password) + return response(hash, passwordHash) +} + +func (auth *ntlmAuth) NextBytes(bytes []byte) ([]byte, error) { + if string(bytes[0:8]) != "NTLMSSP\x00" { + return nil, errorNTLM + } + if binary.LittleEndian.Uint32(bytes[8:12]) != _CHALLENGE_MESSAGE { + return nil, errorNTLM + } + flags := binary.LittleEndian.Uint32(bytes[20:24]) + var challenge [8]byte + copy(challenge[:], bytes[24:32]) + + var lm, nt []byte + if (flags & _NEGOTIATE_EXTENDED_SESSIONSECURITY) != 0 { + nonce := clientChallenge() + var lm_bytes [24]byte + copy(lm_bytes[:8], nonce[:]) + lm = lm_bytes[:] + nt_bytes := ntlmSessionResponse(nonce, challenge, auth.Password) + nt = nt_bytes[:] + } else { + lm_bytes := lmResponse(challenge, auth.Password) + lm = lm_bytes[:] + nt_bytes := ntResponse(challenge, auth.Password) + nt = nt_bytes[:] + } + lm_len := len(lm) + nt_len := len(nt) + + domain16 := utf16le(auth.Domain) + domain_len := len(domain16) + user16 := utf16le(auth.UserName) + user_len := len(user16) + workstation16 := utf16le(auth.Workstation) + workstation_len := len(workstation16) + + msg := make([]byte, 88+lm_len+nt_len+domain_len+user_len+workstation_len) + copy(msg, []byte("NTLMSSP\x00")) + binary.LittleEndian.PutUint32(msg[8:], _AUTHENTICATE_MESSAGE) + // Lm Challenge Response Fields + binary.LittleEndian.PutUint16(msg[12:], uint16(lm_len)) + binary.LittleEndian.PutUint16(msg[14:], uint16(lm_len)) + binary.LittleEndian.PutUint32(msg[16:], 88) + // Nt Challenge Response Fields + binary.LittleEndian.PutUint16(msg[20:], uint16(nt_len)) + binary.LittleEndian.PutUint16(msg[22:], uint16(nt_len)) + binary.LittleEndian.PutUint32(msg[24:], uint32(88+lm_len)) + // Domain Name Fields + binary.LittleEndian.PutUint16(msg[28:], uint16(domain_len)) + binary.LittleEndian.PutUint16(msg[30:], uint16(domain_len)) + binary.LittleEndian.PutUint32(msg[32:], uint32(88+lm_len+nt_len)) + // User Name Fields + binary.LittleEndian.PutUint16(msg[36:], uint16(user_len)) + binary.LittleEndian.PutUint16(msg[38:], uint16(user_len)) + binary.LittleEndian.PutUint32(msg[40:], uint32(88+lm_len+nt_len+domain_len)) + // Workstation Fields + binary.LittleEndian.PutUint16(msg[44:], uint16(workstation_len)) + binary.LittleEndian.PutUint16(msg[46:], uint16(workstation_len)) + binary.LittleEndian.PutUint32(msg[48:], uint32(88+lm_len+nt_len+domain_len+user_len)) + // Encrypted Random Session Key Fields + binary.LittleEndian.PutUint16(msg[52:], 0) + binary.LittleEndian.PutUint16(msg[54:], 0) + binary.LittleEndian.PutUint32(msg[56:], uint32(88+lm_len+nt_len+domain_len+user_len+workstation_len)) + // Negotiate Flags + binary.LittleEndian.PutUint32(msg[60:], flags) + // Version + binary.LittleEndian.PutUint32(msg[64:], 0) + binary.LittleEndian.PutUint32(msg[68:], 0) + // MIC + binary.LittleEndian.PutUint32(msg[72:], 0) + binary.LittleEndian.PutUint32(msg[76:], 0) + binary.LittleEndian.PutUint32(msg[88:], 0) + binary.LittleEndian.PutUint32(msg[84:], 0) + // Payload + copy(msg[88:], lm) + copy(msg[88+lm_len:], nt) + copy(msg[88+lm_len+nt_len:], domain16) + copy(msg[88+lm_len+nt_len+domain_len:], user16) + copy(msg[88+lm_len+nt_len+domain_len+user_len:], workstation16) + return msg, nil +} + +func (auth *ntlmAuth) Free() { +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/ntlm_test.go b/vendor/github.com/denisenkom/go-mssqldb/ntlm_test.go new file mode 100644 index 00000000..db56f4e3 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/ntlm_test.go @@ -0,0 +1,76 @@ +// +build !windows + +package mssql + +import ( + "encoding/hex" + "testing" +) + +func TestLMOWFv1(t *testing.T) { + hash := lmHash("Password") + val := [21]byte{ + 0xe5, 0x2c, 0xac, 0x67, 0x41, 0x9a, 0x9a, 0x22, + 0x4a, 0x3b, 0x10, 0x8f, 0x3f, 0xa6, 0xcb, 0x6d, + 0, 0, 0, 0, 0, + } + if hash != val { + t.Errorf("got:\n%sexpected:\n%s", hex.Dump(hash[:]), hex.Dump(val[:])) + } +} + +func TestNTLMOWFv1(t *testing.T) { + hash := ntlmHash("Password") + val := [21]byte{ + 0xa4, 0xf4, 0x9c, 0x40, 0x65, 0x10, 0xbd, 0xca, 0xb6, 0x82, 0x4e, 0xe7, 0xc3, 0x0f, 0xd8, 0x52, + 0, 0, 0, 0, 0, + } + if hash != val { + t.Errorf("got:\n%sexpected:\n%s", hex.Dump(hash[:]), hex.Dump(val[:])) + } +} + +func TestNTLMv1Response(t *testing.T) { + challenge := [8]byte{ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + } + nt := ntResponse(challenge, "Password") + val := [24]byte{ + 0x67, 0xc4, 0x30, 0x11, 0xf3, 0x02, 0x98, 0xa2, 0xad, 0x35, 0xec, 0xe6, 0x4f, 0x16, 0x33, 0x1c, + 0x44, 0xbd, 0xbe, 0xd9, 0x27, 0x84, 0x1f, 0x94, + } + if nt != val { + t.Errorf("got:\n%sexpected:\n%s", hex.Dump(nt[:]), hex.Dump(val[:])) + } +} + +func TestLMv1Response(t *testing.T) { + challenge := [8]byte{ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + } + nt := lmResponse(challenge, "Password") + val := [24]byte{ + 0x98, 0xde, 0xf7, 0xb8, 0x7f, 0x88, 0xaa, 0x5d, 0xaf, 0xe2, 0xdf, 0x77, 0x96, 0x88, 0xa1, 0x72, + 0xde, 0xf1, 0x1c, 0x7d, 0x5c, 0xcd, 0xef, 0x13, + } + if nt != val { + t.Errorf("got:\n%sexpected:\n%s", hex.Dump(nt[:]), hex.Dump(val[:])) + } +} + +func TestNTLMSessionResponse(t *testing.T) { + challenge := [8]byte{ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + } + nonce := [8]byte{ + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + } + nt := ntlmSessionResponse(nonce, challenge, "Password") + val := [24]byte{ + 0x75, 0x37, 0xf8, 0x03, 0xae, 0x36, 0x71, 0x28, 0xca, 0x45, 0x82, 0x04, 0xbd, 0xe7, 0xca, 0xf8, + 0x1e, 0x97, 0xed, 0x26, 0x83, 0x26, 0x72, 0x32, + } + if nt != val { + t.Errorf("got:\n%sexpected:\n%s", hex.Dump(nt[:]), hex.Dump(val[:])) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/parser.go b/vendor/github.com/denisenkom/go-mssqldb/parser.go new file mode 100644 index 00000000..8021ca60 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/parser.go @@ -0,0 +1,257 @@ +package mssql + +import ( + "bytes" + "io" + "strconv" +) + +type parser struct { + r *bytes.Reader + w bytes.Buffer + paramCount int + paramMax int + + // using map as a set + namedParams map[string]bool +} + +func (p *parser) next() (rune, bool) { + ch, _, err := p.r.ReadRune() + if err != nil { + if err != io.EOF { + panic(err) + } + return 0, false + } + return ch, true +} + +func (p *parser) unread() { + err := p.r.UnreadRune() + if err != nil { + panic(err) + } +} + +func (p *parser) write(ch rune) { + p.w.WriteRune(ch) +} + +type stateFunc func(*parser) stateFunc + +func parseParams(query string) (string, int) { + p := &parser{ + r: bytes.NewReader([]byte(query)), + namedParams: map[string]bool{}, + } + state := parseNormal + for state != nil { + state = state(p) + } + return p.w.String(), p.paramMax + len(p.namedParams) +} + +func parseNormal(p *parser) stateFunc { + for { + ch, ok := p.next() + if !ok { + return nil + } + if ch == '?' { + return parseOrdinalParameter + } else if ch == '$' || ch == ':' { + ch2, ok := p.next() + if !ok { + p.write(ch) + return nil + } + p.unread() + if ch2 >= '0' && ch2 <= '9' { + return parseOrdinalParameter + } else if 'a' <= ch2 && ch2 <= 'z' || 'A' <= ch2 && ch2 <= 'Z' { + return parseNamedParameter + } + } + p.write(ch) + switch ch { + case '\'': + return parseQuote + case '"': + return parseDoubleQuote + case '[': + return parseBracket + case '-': + return parseLineComment + case '/': + return parseComment + } + } +} + +func parseOrdinalParameter(p *parser) stateFunc { + var paramN int + var ok bool + for { + var ch rune + ch, ok = p.next() + if ok && ch >= '0' && ch <= '9' { + paramN = paramN*10 + int(ch-'0') + } else { + break + } + } + if ok { + p.unread() + } + if paramN == 0 { + p.paramCount++ + paramN = p.paramCount + } + if paramN > p.paramMax { + p.paramMax = paramN + } + p.w.WriteString("@p") + p.w.WriteString(strconv.Itoa(paramN)) + if !ok { + return nil + } + return parseNormal +} + +func parseNamedParameter(p *parser) stateFunc { + var paramName string + var ok bool + for { + var ch rune + ch, ok = p.next() + if ok && (ch >= '0' && ch <= '9' || 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z') { + paramName = paramName + string(ch) + } else { + break + } + } + if ok { + p.unread() + } + p.namedParams[paramName] = true + p.w.WriteString("@") + p.w.WriteString(paramName) + if !ok { + return nil + } + return parseNormal +} + +func parseQuote(p *parser) stateFunc { + for { + ch, ok := p.next() + if !ok { + return nil + } + p.write(ch) + if ch == '\'' { + return parseNormal + } + } +} + +func parseDoubleQuote(p *parser) stateFunc { + for { + ch, ok := p.next() + if !ok { + return nil + } + p.write(ch) + if ch == '"' { + return parseNormal + } + } +} + +func parseBracket(p *parser) stateFunc { + for { + ch, ok := p.next() + if !ok { + return nil + } + p.write(ch) + if ch == ']' { + ch, ok = p.next() + if !ok { + return nil + } + if ch != ']' { + p.unread() + return parseNormal + } + p.write(ch) + } + } +} + +func parseLineComment(p *parser) stateFunc { + ch, ok := p.next() + if !ok { + return nil + } + if ch != '-' { + p.unread() + return parseNormal + } + p.write(ch) + for { + ch, ok = p.next() + if !ok { + return nil + } + p.write(ch) + if ch == '\n' { + return parseNormal + } + } +} + +func parseComment(p *parser) stateFunc { + var nested int + ch, ok := p.next() + if !ok { + return nil + } + if ch != '*' { + p.unread() + return parseNormal + } + p.write(ch) + for { + ch, ok = p.next() + if !ok { + return nil + } + p.write(ch) + for ch == '*' { + ch, ok = p.next() + if !ok { + return nil + } + p.write(ch) + if ch == '/' { + if nested == 0 { + return parseNormal + } else { + nested-- + } + } + } + for ch == '/' { + ch, ok = p.next() + if !ok { + return nil + } + p.write(ch) + if ch == '*' { + nested++ + } + } + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/parser_test.go b/vendor/github.com/denisenkom/go-mssqldb/parser_test.go new file mode 100644 index 00000000..d09250df --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/parser_test.go @@ -0,0 +1,60 @@ +package mssql + +import ( + "testing" +) + +func TestParseParams(t *testing.T) { + values := []struct { + s string + d string + n int + }{ + {"select ?", "select @p1", 1}, + {"select ?, ?", "select @p1, @p2", 2}, + {"select ? -- ?", "select @p1 -- ?", 1}, + {"select ? -- ?\n, ?", "select @p1 -- ?\n, @p2", 2}, + {"select ? - ?", "select @p1 - @p2", 2}, + {"select ? /* ? */, ?", "select @p1 /* ? */, @p2", 2}, + {"select ? /* ? * ? */, ?", "select @p1 /* ? * ? */, @p2", 2}, + {"select \"foo?\", [foo?], 'foo?', ?", "select \"foo?\", [foo?], 'foo?', @p1", 1}, + {"select \"x\"\"y\", [x]]y], 'x''y', ?", "select \"x\"\"y\", [x]]y], 'x''y', @p1", 1}, + {"select \"foo?\", ?", "select \"foo?\", @p1", 1}, + {"select 'foo?', ?", "select 'foo?', @p1", 1}, + {"select [foo?], ?", "select [foo?], @p1", 1}, + {"select $1", "select @p1", 1}, + {"select $1, $2", "select @p1, @p2", 2}, + {"select $1, $1", "select @p1, @p1", 1}, + {"select :1", "select @p1", 1}, + {"select :1, :2", "select @p1, @p2", 2}, + {"select :1, :1", "select @p1, @p1", 1}, + {"select ?1", "select @p1", 1}, + {"select ?1, ?2", "select @p1, @p2", 2}, + {"select ?1, ?1", "select @p1, @p1", 1}, + {"select $12", "select @p12", 12}, + {"select ? /* ? /* ? */ ? */ ?", "select @p1 /* ? /* ? */ ? */ @p2", 2}, + {"select ? /* ? / ? */ ?", "select @p1 /* ? / ? */ @p2", 2}, + {"select $", "select $", 0}, + {"select x::y", "select x:@y", 1}, + {"select '", "select '", 0}, + {"select \"", "select \"", 0}, + {"select [", "select [", 0}, + {"select []", "select []", 0}, + {"select -", "select -", 0}, + {"select /", "select /", 0}, + {"select 1/1", "select 1/1", 0}, + {"select /*", "select /*", 0}, + {"select /**", "select /**", 0}, + {"select /*/", "select /*/", 0}, + } + + for _, v := range values { + d, n := parseParams(v.s) + if d != v.d { + t.Errorf("Parse params don't match for %s, got %s but expected %s", v.s, d, v.d) + } + if n != v.n { + t.Errorf("Parse number of params don't match for %s, got %d but expected %d", v.s, n, v.n) + } + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/queries_go110_test.go b/vendor/github.com/denisenkom/go-mssqldb/queries_go110_test.go new file mode 100644 index 00000000..197ddedb --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/queries_go110_test.go @@ -0,0 +1,189 @@ +// +build go1.10 + +package mssql + +import ( + "context" + "database/sql" + "strings" + "testing" + "time" + + "cloud.google.com/go/civil" +) + +func TestSessionInitSQL(t *testing.T) { + checkConnStr(t) + SetLogger(testLogger{t}) + + d := &Driver{} + connector, err := d.OpenConnector(makeConnStr(t).String()) + if err != nil { + t.Fatal("unable to open connector", err) + } + + // Do not use these settings in your application + // unless you know what they do. + // Thes are for this unit test only. + // + // Sessions will be reset even if SessionInitSQL is not set. + connector.SessionInitSQL = ` +SET XACT_ABORT ON; -- 16384 +SET ANSI_NULLS ON; -- 32 +SET ARITHIGNORE ON; -- 128 +` + + pool := sql.OpenDB(connector) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + var opt int32 + err = pool.QueryRowContext(ctx, ` +select Options = @@OPTIONS; +`).Scan(&opt) + if err != nil { + t.Fatal("failed to run query", err) + } + mask := int32(16384 | 128 | 32) + + if opt&mask != mask { + t.Fatal("incorrect session settings", opt) + } +} + +func TestParameterTypes(t *testing.T) { + checkConnStr(t) + pool, err := sql.Open("sqlserver", makeConnStr(t).String()) + if err != nil { + t.Fatal(err) + } + defer pool.Close() + + tin, err := time.Parse(time.RFC3339, "2006-01-02T22:04:05-07:00") + if err != nil { + t.Fatal(err) + } + + var nv, v, nvcm, vcm, dt1, dt2, tm, d, dto string + row := pool.QueryRow(` +select + nv = SQL_VARIANT_PROPERTY(@nv,'BaseType'), + v = SQL_VARIANT_PROPERTY(@v,'BaseType'), + @nvcm, + @vcm, + dt1 = SQL_VARIANT_PROPERTY(@dt1,'BaseType'), + dt2 = SQL_VARIANT_PROPERTY(@dt2,'BaseType'), + d = SQL_VARIANT_PROPERTY(@d,'BaseType'), + tm = SQL_VARIANT_PROPERTY(@tm,'BaseType'), + dto = SQL_VARIANT_PROPERTY(@dto,'BaseType') +; + `, + sql.Named("nv", "base type nvarchar"), + sql.Named("v", VarChar("base type varchar")), + sql.Named("nvcm", NVarCharMax(strings.Repeat("x", 5000))), + sql.Named("vcm", VarCharMax(strings.Repeat("x", 5000))), + sql.Named("dt1", DateTime1(tin)), + sql.Named("dt2", civil.DateTimeOf(tin)), + sql.Named("d", civil.DateOf(tin)), + sql.Named("tm", civil.TimeOf(tin)), + sql.Named("dto", DateTimeOffset(tin)), + ) + err = row.Scan(&nv, &v, &nvcm, &vcm, &dt1, &dt2, &d, &tm, &dto) + if err != nil { + t.Fatal(err) + } + + if nv != "nvarchar" { + t.Errorf(`want "nvarchar" got %q`, nv) + } + if v != "varchar" { + t.Errorf(`want "varchar" got %q`, v) + } + if nvcm != strings.Repeat("x", 5000) { + t.Errorf(`incorrect value returned for nvarchar(max): %q`, nvcm) + } + if vcm != strings.Repeat("x", 5000) { + t.Errorf(`incorrect value returned for varchar(max): %q`, vcm) + } + if dt1 != "datetime" { + t.Errorf(`want "datetime" got %q`, dt1) + } + if dt2 != "datetime2" { + t.Errorf(`want "datetime2" got %q`, dt2) + } + if d != "date" { + t.Errorf(`want "date" got %q`, d) + } + if tm != "time" { + t.Errorf(`want "time" got %q`, tm) + } + if dto != "datetimeoffset" { + t.Errorf(`want "datetimeoffset" got %q`, dto) + } +} + +func TestParameterValues(t *testing.T) { + checkConnStr(t) + pool, err := sql.Open("sqlserver", makeConnStr(t).String()) + if err != nil { + t.Fatal(err) + } + defer pool.Close() + + sin := "high five" + tin, err := time.Parse(time.RFC3339, "2006-01-02T22:04:05-07:00") + if err != nil { + t.Fatal(err) + } + + var nv, v, tgo, dt1, dt2, tm, d, dto string + err = pool.QueryRow(` +select + nv = @nv, + v = @v, + tgo = @tgo, + dt1 = convert(nvarchar(200), @dt1, 121), + dt2 = convert(nvarchar(200), @dt2, 121), + d = convert(nvarchar(200), @d, 121), + tm = convert(nvarchar(200), @tm, 121), + dto = convert(nvarchar(200), @dto, 121) +; + `, + sql.Named("nv", sin), + sql.Named("v", sin), + sql.Named("tgo", tin), + sql.Named("dt1", DateTime1(tin)), + sql.Named("dt2", civil.DateTimeOf(tin)), + sql.Named("d", civil.DateOf(tin)), + sql.Named("tm", civil.TimeOf(tin)), + sql.Named("dto", DateTimeOffset(tin)), + ).Scan(&nv, &v, &tgo, &dt1, &dt2, &d, &tm, &dto) + if err != nil { + t.Fatal(err) + } + if want := sin; nv != want { + t.Errorf(`want %q got %q`, want, nv) + } + if want := sin; v != want { + t.Errorf(`want %q got %q`, want, v) + } + if want := "2006-01-02T22:04:05-07:00"; tgo != want { + t.Errorf(`want %q got %q`, want, tgo) + } + if want := "2006-01-02 22:04:05.000"; dt1 != want { + t.Errorf(`want %q got %q`, want, dt1) + } + if want := "2006-01-02 22:04:05.0000000"; dt2 != want { + t.Errorf(`want %q got %q`, want, dt2) + } + if want := "2006-01-02"; d != want { + t.Errorf(`want %q got %q`, want, d) + } + if want := "22:04:05.0000000"; tm != want { + t.Errorf(`want %q got %q`, want, tm) + } + if want := "2006-01-02 22:04:05.0000000 -07:00"; dto != want { + t.Errorf(`want %q got %q`, want, dto) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/queries_go19_test.go b/vendor/github.com/denisenkom/go-mssqldb/queries_go19_test.go new file mode 100644 index 00000000..9e855eef --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/queries_go19_test.go @@ -0,0 +1,856 @@ +// +build go1.9 + +package mssql + +import ( + "bytes" + "context" + "database/sql" + "fmt" + "regexp" + "testing" + "time" +) + +func TestOutputParam(t *testing.T) { + checkConnStr(t) + SetLogger(testLogger{t}) + + db, err := sql.Open("sqlserver", makeConnStr(t).String()) + if err != nil { + t.Fatalf("failed to open driver sqlserver") + } + defer db.Close() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + t.Run("sp with rows", func(t *testing.T) { + sqltextcreate := ` +CREATE PROCEDURE spwithrows + @intparam INT = NULL OUTPUT +AS +BEGIN + -- return 2 rows + SELECT @intparam + union + SELECT 20 + + -- set output parameter value + SELECT @intparam = 10 +END; +` + sqltextdrop := `DROP PROCEDURE spwithrows;` + sqltextrun := `spwithrows` + + db.ExecContext(ctx, sqltextdrop) + _, err = db.ExecContext(ctx, sqltextcreate) + if err != nil { + t.Fatal(err) + } + defer db.ExecContext(ctx, sqltextdrop) + if err != nil { + t.Error(err) + } + + var intparam int = 5 + rows, err := db.QueryContext(ctx, sqltextrun, + sql.Named("intparam", sql.Out{Dest: &intparam}), + ) + if err != nil { + t.Error(err) + } + // reading first row + if !rows.Next() { + t.Error("Next returned false") + } + var rowval int + err = rows.Scan(&rowval) + if err != nil { + t.Error(err) + } + if rowval != 5 { + t.Errorf("expected 5, got %d", rowval) + } + + // if uncommented would trigger race condition warning + //if intparam != 10 { + // t.Log("output parameter value is not yet 10, it is ", intparam) + //} + + // reading second row + if !rows.Next() { + t.Error("Next returned false") + } + err = rows.Scan(&rowval) + if err != nil { + t.Error(err) + } + if rowval != 20 { + t.Errorf("expected 20, got %d", rowval) + } + + if rows.Next() { + t.Error("Next returned true but should return false after last row was returned") + } + + if intparam != 10 { + t.Errorf("expected 10, got %d", intparam) + } + }) + + t.Run("sp with no rows", func(t *testing.T) { + sqltextcreate := ` +CREATE PROCEDURE abassign + @aid INT = 5, + @bid INT = NULL OUTPUT, + @cstr NVARCHAR(2000) = NULL OUTPUT, + @datetime datetime = NULL OUTPUT +AS +BEGIN + SELECT @bid = @aid, @cstr = 'OK', @datetime = '2010-01-01T00:00:00'; +END; +` + sqltextdrop := `DROP PROCEDURE abassign;` + sqltextrun := `abassign` + + db.ExecContext(ctx, sqltextdrop) + _, err = db.ExecContext(ctx, sqltextcreate) + if err != nil { + t.Fatal(err) + } + defer db.ExecContext(ctx, sqltextdrop) + if err != nil { + t.Error(err) + } + + t.Run("should work", func(t *testing.T) { + var bout int64 + var cout string + _, err = db.ExecContext(ctx, sqltextrun, + sql.Named("aid", 5), + sql.Named("bid", sql.Out{Dest: &bout}), + sql.Named("cstr", sql.Out{Dest: &cout}), + ) + if err != nil { + t.Error(err) + } + + if bout != 5 { + t.Errorf("expected 5, got %d", bout) + } + + if cout != "OK" { + t.Errorf("expected OK, got %s", cout) + } + }) + + t.Run("should work if aid is not passed", func(t *testing.T) { + var bout int64 + var cout string + _, err = db.ExecContext(ctx, sqltextrun, + sql.Named("bid", sql.Out{Dest: &bout}), + sql.Named("cstr", sql.Out{Dest: &cout}), + ) + if err != nil { + t.Error(err) + } + + if bout != 5 { + t.Errorf("expected 5, got %d", bout) + } + + if cout != "OK" { + t.Errorf("expected OK, got %s", cout) + } + }) + + t.Run("should work for DateTime1 parameter", func(t *testing.T) { + tin, err := time.Parse(time.RFC3339, "2006-01-02T22:04:05-07:00") + if err != nil { + t.Fatal(err) + } + expected, err := time.Parse(time.RFC3339, "2010-01-01T00:00:00-00:00") + if err != nil { + t.Fatal(err) + } + var datetime_param DateTime1 + datetime_param = DateTime1(tin) + _, err = db.ExecContext(ctx, sqltextrun, + sql.Named("datetime", sql.Out{Dest: &datetime_param}), + ) + if err != nil { + t.Error(err) + } + if time.Time(datetime_param).UTC() != expected.UTC() { + t.Errorf("Datetime returned '%v' does not match expected value '%v'", + time.Time(datetime_param).UTC(), expected.UTC()) + } + }) + + t.Run("destination is not a pointer", func(t *testing.T) { + var int_out int64 + var str_out string + // test when destination is not a pointer + _, actual := db.ExecContext(ctx, sqltextrun, + sql.Named("bid", sql.Out{Dest: int_out}), + sql.Named("cstr", sql.Out{Dest: &str_out}), + ) + pattern := ".*destination not a pointer.*" + match, err := regexp.MatchString(pattern, actual.Error()) + if err != nil { + t.Error(err) + } + if !match { + t.Errorf("Error '%v', does not match pattern '%v'.", actual, pattern) + } + }) + + t.Run("should convert int64 to int", func(t *testing.T) { + var bout int + var cout string + _, err := db.ExecContext(ctx, sqltextrun, + sql.Named("bid", sql.Out{Dest: &bout}), + sql.Named("cstr", sql.Out{Dest: &cout}), + ) + if err != nil { + t.Error(err) + } + + if bout != 5 { + t.Errorf("expected 5, got %d", bout) + } + }) + + t.Run("should fail if destination has invalid type", func(t *testing.T) { + // Error type should not be supported + var err_out Error + _, err := db.ExecContext(ctx, sqltextrun, + sql.Named("bid", sql.Out{Dest: &err_out}), + ) + if err == nil { + t.Error("Expected to fail but it didn't") + } + + // double inderection should not work + var out_out = sql.Out{Dest: &err_out} + _, err = db.ExecContext(ctx, sqltextrun, + sql.Named("bid", sql.Out{Dest: out_out}), + ) + if err == nil { + t.Error("Expected to fail but it didn't") + } + }) + + t.Run("should fail if parameter has invalid type", func(t *testing.T) { + // passing invalid parameter type + var err_val Error + _, err = db.ExecContext(ctx, sqltextrun, err_val) + if err == nil { + t.Error("Expected to fail but it didn't") + } + }) + + t.Run("destination is a nil pointer", func(t *testing.T) { + var str_out string + // test when destination is nil pointer + _, actual := db.ExecContext(ctx, sqltextrun, + sql.Named("bid", sql.Out{Dest: nil}), + sql.Named("cstr", sql.Out{Dest: &str_out}), + ) + pattern := ".*destination is a nil pointer.*" + match, err := regexp.MatchString(pattern, actual.Error()) + if err != nil { + t.Error(err) + } + if !match { + t.Errorf("Error '%v', does not match pattern '%v'.", actual, pattern) + } + }) + + t.Run("destination is a nil pointer 2", func(t *testing.T) { + var int_ptr *int + _, actual := db.ExecContext(ctx, sqltextrun, + sql.Named("bid", sql.Out{Dest: int_ptr}), + ) + pattern := ".*destination is a nil pointer.*" + match, err := regexp.MatchString(pattern, actual.Error()) + if err != nil { + t.Error(err) + } + if !match { + t.Errorf("Error '%v', does not match pattern '%v'.", actual, pattern) + } + }) + + t.Run("pointer to a pointer", func(t *testing.T) { + var str_out *string + _, actual := db.ExecContext(ctx, sqltextrun, + sql.Named("cstr", sql.Out{Dest: &str_out}), + ) + pattern := ".*destination is a pointer to a pointer.*" + match, err := regexp.MatchString(pattern, actual.Error()) + if err != nil { + t.Error(err) + } + if !match { + t.Errorf("Error '%v', does not match pattern '%v'.", actual, pattern) + } + }) + }) +} + +func TestOutputINOUTParam(t *testing.T) { + sqltextcreate := ` +CREATE PROCEDURE abinout + @aid INT = 1, + @bid INT = 2 OUTPUT, + @cstr NVARCHAR(2000) = NULL OUTPUT, + @vout VARCHAR(2000) = NULL OUTPUT, + @nullint INT = NULL OUTPUT, + @nullfloat FLOAT = NULL OUTPUT, + @nullstr NVARCHAR(10) = NULL OUTPUT, + @nullbit BIT = NULL OUTPUT, + @varbin VARBINARY(10) = NULL OUTPUT +AS +BEGIN + SELECT + @bid = @aid + @bid, + @cstr = 'OK', + @Vout = 'DREAM' + ; +END; +` + sqltextdrop := `DROP PROCEDURE abinout;` + sqltextrun := `abinout` + + checkConnStr(t) + SetLogger(testLogger{t}) + + db, err := sql.Open("sqlserver", makeConnStr(t).String()) + if err != nil { + t.Fatalf("failed to open driver sqlserver") + } + defer db.Close() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + db.ExecContext(ctx, sqltextdrop) + _, err = db.ExecContext(ctx, sqltextcreate) + if err != nil { + t.Fatal(err) + } + defer db.ExecContext(ctx, sqltextdrop) + + t.Run("original test", func(t *testing.T) { + var bout int64 = 3 + var cout string + var vout VarChar + _, err = db.ExecContext(ctx, sqltextrun, + sql.Named("aid", 5), + sql.Named("bid", sql.Out{Dest: &bout}), + sql.Named("cstr", sql.Out{Dest: &cout}), + sql.Named("vout", sql.Out{Dest: &vout}), + ) + if err != nil { + t.Error(err) + } + + if bout != 8 { + t.Errorf("expected 8, got %d", bout) + } + + if cout != "OK" { + t.Errorf("expected OK, got %s", cout) + } + if string(vout) != "DREAM" { + t.Errorf("expected DREAM, got %s", vout) + } + }) + + t.Run("test null values returned into nullable", func(t *testing.T) { + var nullint sql.NullInt64 + var nullfloat sql.NullFloat64 + var nullstr sql.NullString + var nullbit sql.NullBool + _, err = db.ExecContext(ctx, sqltextrun, + sql.Named("nullint", sql.Out{Dest: &nullint}), + sql.Named("nullfloat", sql.Out{Dest: &nullfloat}), + sql.Named("nullstr", sql.Out{Dest: &nullstr}), + sql.Named("nullbit", sql.Out{Dest: &nullbit}), + ) + if err != nil { + t.Error(err) + } + + if nullint.Valid { + t.Errorf("expected NULL, got %v", nullint) + } + if nullfloat.Valid { + t.Errorf("expected NULL, got %v", nullfloat) + } + if nullstr.Valid { + t.Errorf("expected NULL, got %v", nullstr) + } + if nullbit.Valid { + t.Errorf("expected NULL, got %v", nullbit) + } + }) + + // Not yet supported + //t.Run("test null values returned into pointers", func(t *testing.T) { + // var nullint *int64 + // var nullfloat *float64 + // var nullstr *string + // var nullbit *bool + // _, err = db.ExecContext(ctx, sqltextrun, + // sql.Named("nullint", sql.Out{Dest: &nullint}), + // sql.Named("nullfloat", sql.Out{Dest: &nullfloat}), + // sql.Named("nullstr", sql.Out{Dest: &nullstr}), + // sql.Named("nullbit", sql.Out{Dest: &nullbit}), + // ) + // if err != nil { + // t.Error(err) + // } + + // if nullint != nil { + // t.Errorf("expected NULL, got %v", nullint) + // } + // if nullfloat != nil { + // t.Errorf("expected NULL, got %v", nullfloat) + // } + // if nullstr != nil { + // t.Errorf("expected NULL, got %v", nullstr) + // } + // if nullbit != nil { + // t.Errorf("expected NULL, got %v", nullbit) + // } + //}) + + t.Run("test non null values into nullable", func(t *testing.T) { + nullint := sql.NullInt64{10, true} + nullfloat := sql.NullFloat64{1.5, true} + nullstr := sql.NullString{"hello", true} + nullbit := sql.NullBool{true, true} + _, err = db.ExecContext(ctx, sqltextrun, + sql.Named("nullint", sql.Out{Dest: &nullint}), + sql.Named("nullfloat", sql.Out{Dest: &nullfloat}), + sql.Named("nullstr", sql.Out{Dest: &nullstr}), + sql.Named("nullbit", sql.Out{Dest: &nullbit}), + ) + if err != nil { + t.Error(err) + } + if !nullint.Valid { + t.Error("expected non null value, but got null") + } + if nullint.Int64 != 10 { + t.Errorf("expected 10, got %d", nullint.Int64) + } + if !nullfloat.Valid { + t.Error("expected non null value, but got null") + } + if nullfloat.Float64 != 1.5 { + t.Errorf("expected 1.5, got %v", nullfloat.Float64) + } + if !nullstr.Valid { + t.Error("expected non null value, but got null") + } + if nullstr.String != "hello" { + t.Errorf("expected hello, got %s", nullstr.String) + } + }) + t.Run("test return into byte[]", func(t *testing.T) { + cstr := []byte{1, 2, 3} + _, err = db.ExecContext(ctx, sqltextrun, + sql.Named("varbin", sql.Out{Dest: &cstr}), + ) + if err != nil { + t.Error(err) + } + expected := []byte{1, 2, 3} + if bytes.Compare(cstr, expected) != 0 { + t.Errorf("expected [1,2,3], got %v", cstr) + } + }) + t.Run("test int into string", func(t *testing.T) { + var str string + _, err = db.ExecContext(ctx, sqltextrun, + sql.Named("bid", sql.Out{Dest: &str}), + ) + if err != nil { + t.Error(err) + } + if str != "1" { + t.Errorf("expected '1', got %v", str) + } + }) + t.Run("typeless null for output parameter should return error", func(t *testing.T) { + var val interface{} + _, actual := db.ExecContext(ctx, sqltextrun, + sql.Named("bid", sql.Out{Dest: &val}), + ) + if actual == nil { + t.Error("Expected to fail but didn't") + } + pattern := ".*MSSQL does not allow NULL value without type for OUTPUT parameters.*" + match, err := regexp.MatchString(pattern, actual.Error()) + if err != nil { + t.Error(err) + } + if !match { + t.Errorf("Error '%v', does not match pattern '%v'.", actual, pattern) + } + }) +} + +// TestTLSServerReadClose tests writing to an encrypted database connection. +// Currently the database server will close the connection while the server is +// reading the TDS packets and before any of the data has been parsed. +// +// When two queries are sent in reverse order, they PASS, but if we send only +// a single ping (SELECT 1;) first, then the long query the query fails. +// +// The long query text is never parsed. In fact, you can comment out, return +// early, or have malformed sql in the long query text. Just the length matters. +// The error happens when sending the TDS Batch packet to SQL Server the server +// closes the connection.. +// +// It appears the driver sends valid TDS packets. In fact, if prefixed with 4 +// "SELECT 1;" TDS Batch queries then the long query works, but if zero or one +// "SELECT 1;" TDS Batch queries are send prior the long query fails to send. +// +// Lastly, this only manafests itself with an encrypted connection. This has been +// observed with SQL Server Azure, SQL Server 13.0.1742 on Windows, and SQL Server +// 14.0.900.75 on Linux. It also fails when using the "dev.boringcrypto" (a C based +// TLS crypto). I haven't found any knobs on SQL Server to expose the error message +// nor have I found a good way to decrypt the TDS stream. KeyLogWriter in the TLS +// config may help with that, but wireshark wasn't decrypting TDS based TLS streams +// even when using that. +// +// Issue https://github.com/denisenkom/go-mssqldb/issues/166 +func TestTLSServerReadClose(t *testing.T) { + query := ` +with + config_cte (config) as ( + select * + from ( values + ('_partition:{\"Fill\":{\"PatternType\":\"solid\",\"FgColor\":\"99ff99\"}}') + , ('_separation:{\"Fill\":{\"PatternType\":\"solid\",\"FgColor\":\"99ffff\"}}') + , ('Monthly Earnings:\$#,##0.00 ;(\$#,##0.00)') + , ('Weekly Earnings:\$#,##0.00 ;(\$#,##0.00)') + , ('Total Earnings:\$#,##0.00 ;(\$#,##0.00)') + , ('Average Earnings:\$#,##0.00 ;(\$#,##0.00)') + , ('Last Month Earning:#,##0.00 ;(#,##0.00)') + , ('Award:\$#,##0.00 ;(\$#,##0.00)') + , ('Amount:\$#,##0.00 ;(\$#,##0.00)') + , ('Grand Total:\$#,##0.00 ;(\$#,##0.00)') + , ('Total:\$#,##0.00 ;(\$#,##0.00)') + , ('Price Each:\$#,##0.00 ;(\$#,##0.00)') + , ('Hyperwallet:\$#,##0.00 ;(\$#,##0.00)') + , ('Credit/Debit:\$#,##0.00 ;(\$#,##0.00)') + , ('Earning:#,##0.00 ;(#,##0.00)') + , ('Change Earning:#,##0.00 ;(#,##0.00)') + , ('CheckAmount:#,##0.00 ;(#,##0.00)') + , ('Residual:#,##0.00 ;(#,##0.00)') + , ('Prev Residual:#,##0.00 ;(#,##0.00)') + , ('Team Bonuses:#,##0.00 ;(#,##0.00)') + , ('Change:#,##0.00 ;(#,##0.00)') + , ('Shipping Total:#,##0.00 ;(#,##0.00)') + , ('SubTotal:\$#,##0.00 ;(\$#,##0.00)') + , ('Total Diff:#,##0.00 ;(#,##0.00)') + , ('SubTotal Diff:#,##0.00 ;(#,##0.00)') + , ('Return Total:#,##0.00 ;(#,##0.00)') + , ('Return SubTotal:#,##0.00 ;(#,##0.00)') + , ('Return Total Diff:#,##0.00 ;(#,##0.00)') + , ('Return SubTotal Diff:#,##0.00 ;(#,##0.00)') + , ('Cancel Total:#,##0.00 ;(#,##0.00)') + , ('Cancel SubTotal:#,##0.00 ;(#,##0.00)') + , ('Cancel Total Diff:#,##0.00 ;(#,##0.00)') + , ('Cancel SubTotal Diff:#,##0.00 ;(#,##0.00)') + , ('Replacement Total:#,##0.00 ;(#,##0.00)') + , ('Replacement SubTotal:#,##0.00 ;(#,##0.00)') + , ('Replacement Total Diff:#,##0.00 ;(#,##0.00)') + , ('Replacement SubTotal Diff:#,##0.00 ;(#,##0.00)') + , ('Jan Residual:#,##0.00 ;(#,##0.00)') + , ('Jan Bonus:#,##0.00 ;(#,##0.00)') + , ('Jan Total:#,##0.00 ;(#,##0.00)') + , ('January Residual:#,##0.00 ;(#,##0.00)') + , ('Feb Residual:#,##0.00 ;(#,##0.00)') + , ('Feb Bonus:#,##0.00 ;(#,##0.00)') + , ('Feb Total:#,##0.00 ;(#,##0.00)') + , ('February Residual:#,##0.00 ;(#,##0.00)') + , ('Mar Residual:#,##0.00 ;(#,##0.00)') + , ('Mar Bonus:#,##0.00 ;(#,##0.00)') + , ('Mar Total:#,##0.00 ;(#,##0.00)') + , ('March Residual:#,##0.00 ;(#,##0.00)') + , ('Apr Residual:#,##0.00 ;(#,##0.00)') + , ('Apr Bonus:#,##0.00 ;(#,##0.00)') + , ('Apr Total:#,##0.00 ;(#,##0.00)') + , ('April Residual:#,##0.00 ;(#,##0.00)') + , ('May Residual:#,##0.00 ;(#,##0.00)') + , ('May Bonus:#,##0.00 ;(#,##0.00)') + , ('May Total:#,##0.00 ;(#,##0.00)') + , ('Jun Residual:#,##0.00 ;(#,##0.00)') + , ('Jun Bonus:#,##0.00 ;(#,##0.00)') + , ('Jun Total:#,##0.00 ;(#,##0.00)') + , ('June Residual:#,##0.00 ;(#,##0.00)') + , ('Jul Residual:#,##0.00 ;(#,##0.00)') + , ('Jul Bonus:#,##0.00 ;(#,##0.00)') + , ('Jul Total:#,##0.00 ;(#,##0.00)') + , ('July Residual:#,##0.00 ;(#,##0.00)') + , ('Aug Residual:#,##0.00 ;(#,##0.00)') + , ('Aug Bonus:#,##0.00 ;(#,##0.00)') + , ('Aug Total:#,##0.00 ;(#,##0.00)') + , ('August Residual:#,##0.00 ;(#,##0.00)') + , ('Sep Residual:#,##0.00 ;(#,##0.00)') + , ('Sep Bonus:#,##0.00 ;(#,##0.00)') + , ('Sep Total:#,##0.00 ;(#,##0.00)') + , ('September Residual:#,##0.00 ;(#,##0.00)') + , ('Oct Residual:#,##0.00 ;(#,##0.00)') + , ('Oct Bonus:#,##0.00 ;(#,##0.00)') + , ('Oct Total:#,##0.00 ;(#,##0.00)') + , ('October Residual:#,##0.00 ;(#,##0.00)') + , ('Nov Residual:#,##0.00 ;(#,##0.00)') + , ('Nov Bonus:#,##0.00 ;(#,##0.00)') + , ('Nov Total:#,##0.00 ;(#,##0.00)') + , ('November Residual:#,##0.00 ;(#,##0.00)') + , ('Dec Residual:#,##0.00 ;(#,##0.00)') + , ('Dec Bonus:#,##0.00 ;(#,##0.00)') + , ('Dec Total:#,##0.00 ;(#,##0.00)') + , ('December Residual:#,##0.00 ;(#,##0.00)') + , ('January Bonus:#,##0.00 ;(#,##0.00)') + , ('February Bonus:#,##0.00 ;(#,##0.00)') + , ('March Bonus:#,##0.00 ;(#,##0.00)') + , ('April Bonus:#,##0.00 ;(#,##0.00)') + , ('May Bonus:#,##0.00 ;(#,##0.00)') + , ('June Bonus:#,##0.00 ;(#,##0.00)') + , ('July Bonus:#,##0.00 ;(#,##0.00)') + , ('August Bonus:#,##0.00 ;(#,##0.00)') + , ('September Bonus:#,##0.00 ;(#,##0.00)') + , ('October Bonus:#,##0.00 ;(#,##0.00)') + , ('November Bonus:#,##0.00 ;(#,##0.00)') + , ('December Bonus:#,##0.00 ;(#,##0.00)') + , ('January Adj:#,##0.00 ;(#,##0.00)') + , ('February Adj:#,##0.00 ;(#,##0.00)') + , ('March Adj:#,##0.00 ;(#,##0.00)') + , ('April Adj:#,##0.00 ;(#,##0.00)') + , ('May Adj:#,##0.00 ;(#,##0.00)') + , ('June Adj:#,##0.00 ;(#,##0.00)') + , ('July Adj:#,##0.00 ;(#,##0.00)') + , ('August Adj:#,##0.00 ;(#,##0.00)') + , ('September Adj:#,##0.00 ;(#,##0.00)') + , ('October Adj:#,##0.00 ;(#,##0.00)') + , ('November Adj:#,##0.00 ;(#,##0.00)') + , ('December Adj:#,##0.00 ;(#,##0.00)') + , ('2016- 2015 YTD Dif:#,##0.00 ;(#,##0.00)') + , ('2017- 2016 YTD Dif:#,##0.00 ;(#,##0.00)') + , ('2018- 2017 YTD Dif:#,##0.00 ;(#,##0.00)') + , ('Dec to Jan Dif Residual:#,##0.00 ;(#,##0.00)') + , ('Jan to Feb Dif Residual:#,##0.00 ;(#,##0.00)') + , ('Feb to Mar Dif Residual:#,##0.00 ;(#,##0.00)') + , ('Mar to Apr Dif Residual:#,##0.00 ;(#,##0.00)') + , ('Apr to May Dif Residual:#,##0.00 ;(#,##0.00)') + , ('May to Jun Dif Residual:#,##0.00 ;(#,##0.00)') + , ('Jun to Jul Dif Residual:#,##0.00 ;(#,##0.00)') + , ('Jul to Aug Dif Residual:#,##0.00 ;(#,##0.00)') + , ('Aug to Sep Dif Residual:#,##0.00 ;(#,##0.00)') + , ('Sep to Oct Dif Residual:#,##0.00 ;(#,##0.00)') + , ('Oct to Nov Dif Residual:#,##0.00 ;(#,##0.00)') + , ('Nov to Dec Dif Residual:#,##0.00 ;(#,##0.00)') + , ('Dec to Jan Dif Bonus:#,##0.00 ;(#,##0.00)') + , ('Jan to Feb Dif Bonus:#,##0.00 ;(#,##0.00)') + , ('Feb to Mar Dif Bonus:#,##0.00 ;(#,##0.00)') + , ('Mar to Apr Dif Bonus:#,##0.00 ;(#,##0.00)') + , ('Apr to May Dif Bonus:#,##0.00 ;(#,##0.00)') + , ('May to Jun Dif Bonus:#,##0.00 ;(#,##0.00)') + , ('Jun to Jul Dif Bonus:#,##0.00 ;(#,##0.00)') + , ('Jul to Aug Dif Bonus:#,##0.00 ;(#,##0.00)') + , ('Aug to Sep Dif Bonus:#,##0.00 ;(#,##0.00)') + , ('Sep to Oct Dif Bonus:#,##0.00 ;(#,##0.00)') + , ('Oct to Nov Dif Bonus:#,##0.00 ;(#,##0.00)') + , ('Nov to Dec Dif Bonus:#,##0.00 ;(#,##0.00)') + , ('Dec to Jan Dif Total:#,##0.00 ;(#,##0.00)') + , ('Jan to Feb Dif Total:#,##0.00 ;(#,##0.00)') + , ('Feb to Mar Dif Total:#,##0.00 ;(#,##0.00)') + , ('Mar to Apr Dif Total:#,##0.00 ;(#,##0.00)') + , ('Apr to May Dif Total:#,##0.00 ;(#,##0.00)') + , ('May to Jun Dif Total:#,##0.00 ;(#,##0.00)') + , ('Jun to Jul Dif Total:#,##0.00 ;(#,##0.00)') + , ('Jul to Aug Dif Total:#,##0.00 ;(#,##0.00)') + , ('Aug to Sep Dif Total:#,##0.00 ;(#,##0.00)') + , ('Sep to Oct Dif Total:#,##0.00 ;(#,##0.00)') + , ('Oct to Nov Dif Total:#,##0.00 ;(#,##0.00)') + , ('Nov to Dec Dif Total:#,##0.00 ;(#,##0.00)') + , ('Jan Refund Cnt:#,##0 ;(#,##0)') + , ('Feb Refund Cnt:#,##0 ;(#,##0)') + , ('Mar Refund Cnt:#,##0 ;(#,##0)') + , ('Apr Refund Cnt:#,##0 ;(#,##0)') + , ('May Refund Cnt:#,##0 ;(#,##0)') + , ('Jun Refund Cnt:#,##0 ;(#,##0)') + , ('Jul Refund Cnt:#,##0 ;(#,##0)') + , ('Aug Refund Cnt:#,##0 ;(#,##0)') + , ('Sep Refund Cnt:#,##0 ;(#,##0)') + , ('Oct Refund Cnt:#,##0 ;(#,##0)') + , ('Nov Refund Cnt:#,##0 ;(#,##0)') + , ('Dec Refund Cnt:#,##0 ;(#,##0)') + , ('Jan Purchase Cnt:#,##0 ;(#,##0)') + , ('Feb Purchase Cnt:#,##0 ;(#,##0)') + , ('Mar Purchase Cnt:#,##0 ;(#,##0)') + , ('Apr Purchase Cnt:#,##0 ;(#,##0)') + , ('May Purchase Cnt:#,##0 ;(#,##0)') + , ('Jun Purchase Cnt:#,##0 ;(#,##0)') + , ('Jul Purchase Cnt:#,##0 ;(#,##0)') + , ('Aug Purchase Cnt:#,##0 ;(#,##0)') + , ('Sep Purchase Cnt:#,##0 ;(#,##0)') + , ('Oct Purchase Cnt:#,##0 ;(#,##0)') + , ('Nov Purchase Cnt:#,##0 ;(#,##0)') + , ('Dec Purchase Cnt:#,##0 ;(#,##0)') + , ('Jan Refund Amt:#,##0.00 ;(#,##0.00)') + , ('Feb Refund Amt:#,##0.00 ;(#,##0.00)') + , ('Mar Refund Amt:#,##0.00 ;(#,##0.00)') + , ('Apr Refund Amt:#,##0.00 ;(#,##0.00)') + , ('May Refund Amt:#,##0.00 ;(#,##0.00)') + , ('Jun Refund Amt:#,##0.00 ;(#,##0.00)') + , ('Jul Refund Amt:#,##0.00 ;(#,##0.00)') + , ('Aug Refund Amt:#,##0.00 ;(#,##0.00)') + , ('Sep Refund Amt:#,##0.00 ;(#,##0.00)') + , ('Oct Refund Amt:#,##0.00 ;(#,##0.00)') + , ('Nov Refund Amt:#,##0.00 ;(#,##0.00)') + , ('Dec Refund Amt:#,##0.00 ;(#,##0.00)') + , ('Jan Purchase Amt:#,##0.00 ;(#,##0.00)') + , ('Feb Purchase Amt:#,##0.00 ;(#,##0.00)') + , ('Mar Purchase Amt:#,##0.00 ;(#,##0.00)') + , ('Apr Purchase Amt:#,##0.00 ;(#,##0.00)') + , ('May Purchase Amt:#,##0.00 ;(#,##0.00)') + , ('Jun Purchase Amt:#,##0.00 ;(#,##0.00)') + , ('Jul Purchase Amt:#,##0.00 ;(#,##0.00)') + , ('Aug Purchase Amt:#,##0.00 ;(#,##0.00)') + , ('Sep Purchase Amt:#,##0.00 ;(#,##0.00)') + , ('Oct Purchase Amt:#,##0.00 ;(#,##0.00)') + , ('Nov Purchase Amt:#,##0.00 ;(#,##0.00)') + , ('Dec Purchase Amt:#,##0.00 ;(#,##0.00)') + ) X(a)) + select * from config_cte + ` + t.Logf("query len (utf16 bytes)=%d, len/4096=%f\n", len(query)*2, float64(len(query)*2)/4096) + + db := open(t) + defer db.Close() + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + type run struct { + name string + pings []int + pass bool + + conn *sql.Conn + } + + // Use separate Conns from the connection pool to ensure separation. + runs := []*run{ + {name: "rev", pings: []int{4, 1}, pass: true}, + {name: "forward", pings: []int{1}, pass: true}, + } + for _, r := range runs { + var err error + r.conn, err = db.Conn(ctx) + if err != nil { + t.Fatal(err) + } + defer r.conn.Close() + } + + for _, r := range runs { + for _, ping := range r.pings { + t.Run(fmt.Sprintf("%s-ping-%d", r.name, ping), func(t *testing.T) { + for i := 0; i < ping; i++ { + if err := r.conn.PingContext(ctx); err != nil { + if r.pass { + t.Error("failed to ping server", err) + } else { + t.Log("failed to ping server", err) + } + return + } + } + + rows, err := r.conn.QueryContext(ctx, query) + if err != nil { + if r.pass { + t.Errorf("QueryContext: %+v", err) + } else { + t.Logf("QueryContext: %+v", err) + } + return + } + for rows.Next() { + // Nothing. + } + rows.Close() + }) + } + } +} + +func TestDateTimeParam19(t *testing.T) { + conn := open(t) + defer conn.Close() + + // testing DateTime1, only supported on go 1.9 + var emptydate time.Time + mindate1 := time.Date(1753, 1, 1, 0, 0, 0, 0, time.UTC) + maxdate1 := time.Date(9999, 12, 31, 23, 59, 59, 997000000, time.UTC) + testdates1 := []DateTime1{ + DateTime1(mindate1), + DateTime1(maxdate1), + DateTime1(time.Date(1752, 12, 31, 23, 59, 59, 997000000, time.UTC)), // just a little below minimum date + DateTime1(time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC)), // just a little over maximum date + DateTime1(emptydate), + } + + for _, test := range testdates1 { + t.Run(fmt.Sprintf("Test datetime for %v", test), func(t *testing.T) { + var res time.Time + expected := time.Time(test) + queryParamRoundTrip(conn, test, &res) + // clip value + if expected.Before(mindate1) { + expected = mindate1 + } + if expected.After(maxdate1) { + expected = maxdate1 + } + if expected.Sub(res) != 0 { + t.Errorf("expected: '%s', got: '%s' delta: %d", expected, res, expected.Sub(res)) + } + }) + } +} + +func TestReturnStatus(t *testing.T) { + conn := open(t) + defer conn.Close() + + _, err := conn.Exec("if object_id('retstatus') is not null drop proc retstatus;") + if err != nil { + t.Fatal(err) + } + _, err = conn.Exec("create proc retstatus as return 2;") + if err != nil { + t.Fatal(err) + } + + var rs ReturnStatus + _, err = conn.Exec("retstatus", &rs) + conn.Exec("drop proc retstatus;") + if err != nil { + t.Fatal(err) + } + if rs != 2 { + t.Errorf("expected status=2, got %d", rs) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/queries_test.go b/vendor/github.com/denisenkom/go-mssqldb/queries_test.go new file mode 100644 index 00000000..255de306 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/queries_test.go @@ -0,0 +1,2186 @@ +package mssql + +import ( + "bytes" + "context" + "database/sql" + "database/sql/driver" + "fmt" + "log" + "math" + "net" + "reflect" + "strings" + "sync" + "testing" + "time" +) + +func driverWithProcess(t *testing.T) *Driver { + return &Driver{ + log: optionalLogger{testLogger{t}}, + processQueryText: true, + } +} +func driverNoProcess(t *testing.T) *Driver { + return &Driver{ + log: optionalLogger{testLogger{t}}, + processQueryText: false, + } +} + +func TestSelect(t *testing.T) { + conn := open(t) + defer conn.Close() + + t.Run("scan into interface{}", func(t *testing.T) { + type testStruct struct { + sql string + val interface{} + } + + longstr := strings.Repeat("x", 10000) + + values := []testStruct{ + {"1", int64(1)}, + {"-1", int64(-1)}, + {"cast(1 as int)", int64(1)}, + {"cast(-1 as int)", int64(-1)}, + {"cast(1 as tinyint)", int64(1)}, + {"cast(255 as tinyint)", int64(255)}, + {"cast(1 as smallint)", int64(1)}, + {"cast(-1 as smallint)", int64(-1)}, + {"cast(1 as bigint)", int64(1)}, + {"cast(-1 as bigint)", int64(-1)}, + {"cast(1 as bit)", true}, + {"cast(0 as bit)", false}, + {"'abc'", string("abc")}, + {"cast(0.5 as float)", float64(0.5)}, + {"cast(0.5 as real)", float64(0.5)}, + {"cast(1 as decimal)", []byte("1")}, + {"cast(1.2345 as money)", []byte("1.2345")}, + {"cast(-1.2345 as money)", []byte("-1.2345")}, + {"cast(1.2345 as smallmoney)", []byte("1.2345")}, + {"cast(-1.2345 as smallmoney)", []byte("-1.2345")}, + {"cast(0.5 as decimal(18,1))", []byte("0.5")}, + {"cast(-0.5 as decimal(18,1))", []byte("-0.5")}, + {"cast(-0.5 as numeric(18,1))", []byte("-0.5")}, + {"cast(4294967296 as numeric(20,0))", []byte("4294967296")}, + {"cast(-0.5 as numeric(18,2))", []byte("-0.50")}, + {"N'abc'", string("abc")}, + {"cast(null as nvarchar(3))", nil}, + {"NULL", nil}, + {"cast('1753-01-01' as datetime)", time.Date(1753, 1, 1, 0, 0, 0, 0, time.UTC)}, + {"cast('2000-01-01' as datetime)", time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)}, + {"cast('2000-01-01T12:13:14.12' as datetime)", + time.Date(2000, 1, 1, 12, 13, 14, 120000000, time.UTC)}, + {"cast('2014-06-26 11:08:09.673' as datetime)", time.Date(2014, 06, 26, 11, 8, 9, 673000000, time.UTC)}, + {"cast('9999-12-31T23:59:59.997' as datetime)", time.Date(9999, 12, 31, 23, 59, 59, 997000000, time.UTC)}, + {"cast(NULL as datetime)", nil}, + {"cast('1900-01-01T00:00:00' as smalldatetime)", + time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)}, + {"cast('2000-01-01T12:13:00' as smalldatetime)", + time.Date(2000, 1, 1, 12, 13, 0, 0, time.UTC)}, + {"cast('2079-06-06T23:59:00' as smalldatetime)", + time.Date(2079, 6, 6, 23, 59, 0, 0, time.UTC)}, + {"cast(NULL as smalldatetime)", nil}, + {"cast(0x6F9619FF8B86D011B42D00C04FC964FF as uniqueidentifier)", + []byte{0x6F, 0x96, 0x19, 0xFF, 0x8B, 0x86, 0xD0, 0x11, 0xB4, 0x2D, 0x00, 0xC0, 0x4F, 0xC9, 0x64, 0xFF}}, + {"cast(NULL as uniqueidentifier)", nil}, + {"cast(0x1234 as varbinary(2))", []byte{0x12, 0x34}}, + {"cast(N'abc' as nvarchar(max))", "abc"}, + {"cast(null as nvarchar(max))", nil}, + {"cast('' as xml)", ""}, + {"cast('abc' as text)", "abc"}, + {"cast(null as text)", nil}, + {"cast(N'abc' as ntext)", "abc"}, + {"cast(0x1234 as image)", []byte{0x12, 0x34}}, + {"cast('abc' as char(3))", "abc"}, + {"cast('abc' as varchar(3))", "abc"}, + {"cast(N'проверка' as nvarchar(max))", "проверка"}, + {"cast(N'Δοκιμή' as nvarchar(max))", "Δοκιμή"}, + {"cast(cast(N'สวัสดี' as nvarchar(max)) collate Thai_CI_AI as varchar(max))", "สวัสดี"}, // cp874 + {"cast(cast(N'你好' as nvarchar(max)) collate Chinese_PRC_CI_AI as varchar(max))", "你好"}, // cp936 + {"cast(cast(N'こんにちは' as nvarchar(max)) collate Japanese_CI_AI as varchar(max))", "こんにちは"}, // cp939 + {"cast(cast(N'안녕하세요.' as nvarchar(max)) collate Korean_90_CI_AI as varchar(max))", "안녕하세요."}, // cp949 + {"cast(cast(N'你好' as nvarchar(max)) collate Chinese_Hong_Kong_Stroke_90_CI_AI as varchar(max))", "你好"}, // cp950 + {"cast(cast(N'cześć' as nvarchar(max)) collate Polish_CI_AI as varchar(max))", "cześć"}, // cp1250 + {"cast(cast(N'Алло' as nvarchar(max)) collate Cyrillic_General_CI_AI as varchar(max))", "Алло"}, // cp1251 + {"cast(cast(N'Bonjour' as nvarchar(max)) collate French_CI_AI as varchar(max))", "Bonjour"}, // cp1252 + {"cast(cast(N'Γεια σας' as nvarchar(max)) collate Greek_CI_AI as varchar(max))", "Γεια σας"}, // cp1253 + {"cast(cast(N'Merhaba' as nvarchar(max)) collate Turkish_CI_AI as varchar(max))", "Merhaba"}, // cp1254 + {"cast(cast(N'שלום' as nvarchar(max)) collate Hebrew_CI_AI as varchar(max))", "שלום"}, // cp1255 + {"cast(cast(N'مرحبا' as nvarchar(max)) collate Arabic_CI_AI as varchar(max))", "مرحبا"}, // cp1256 + {"cast(cast(N'Sveiki' as nvarchar(max)) collate Lithuanian_CI_AI as varchar(max))", "Sveiki"}, // cp1257 + {"cast(cast(N'chào' as nvarchar(max)) collate Vietnamese_CI_AI as varchar(max))", "chào"}, // cp1258 + {fmt.Sprintf("cast(N'%s' as nvarchar(max))", longstr), longstr}, + {"cast(NULL as sql_variant)", nil}, + {"cast(cast(0x6F9619FF8B86D011B42D00C04FC964FF as uniqueidentifier) as sql_variant)", + []byte{0x6F, 0x96, 0x19, 0xFF, 0x8B, 0x86, 0xD0, 0x11, 0xB4, 0x2D, 0x00, 0xC0, 0x4F, 0xC9, 0x64, 0xFF}}, + {"cast(cast(1 as bit) as sql_variant)", true}, + {"cast(cast(10 as tinyint) as sql_variant)", int64(10)}, + {"cast(cast(-10 as smallint) as sql_variant)", int64(-10)}, + {"cast(cast(-20 as int) as sql_variant)", int64(-20)}, + {"cast(cast(-20 as bigint) as sql_variant)", int64(-20)}, + {"cast(cast('2000-01-01' as datetime) as sql_variant)", time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)}, + {"cast(cast('2000-01-01T12:13:00' as smalldatetime) as sql_variant)", + time.Date(2000, 1, 1, 12, 13, 0, 0, time.UTC)}, + {"cast(cast(0.125 as real) as sql_variant)", float64(0.125)}, + {"cast(cast(0.125 as float) as sql_variant)", float64(0.125)}, + {"cast(cast(1.2345 as smallmoney) as sql_variant)", []byte("1.2345")}, + {"cast(cast(1.2345 as money) as sql_variant)", []byte("1.2345")}, + {"cast(cast(0x1234 as varbinary(2)) as sql_variant)", []byte{0x12, 0x34}}, + {"cast(cast(0x1234 as binary(2)) as sql_variant)", []byte{0x12, 0x34}}, + {"cast(cast(-0.5 as decimal(18,1)) as sql_variant)", []byte("-0.5")}, + {"cast(cast(-0.5 as numeric(18,1)) as sql_variant)", []byte("-0.5")}, + {"cast(cast('abc' as varchar(3)) as sql_variant)", "abc"}, + {"cast(cast('abc' as char(3)) as sql_variant)", "abc"}, + {"cast(N'abc' as sql_variant)", "abc"}, + } + + for _, test := range values { + t.Run(test.sql, func(t *testing.T) { + stmt, err := conn.Prepare("select " + test.sql) + if err != nil { + t.Error("Prepare failed:", test.sql, err.Error()) + return + } + defer stmt.Close() + + row := stmt.QueryRow() + var retval interface{} + err = row.Scan(&retval) + if err != nil { + t.Error("Scan failed:", test.sql, err.Error()) + return + } + var same bool + switch decodedval := retval.(type) { + case []byte: + switch decodedvaltest := test.val.(type) { + case []byte: + same = bytes.Equal(decodedval, decodedvaltest) + default: + same = false + } + default: + same = retval == test.val + } + if !same { + t.Errorf("Values don't match '%s' '%s' for test: %s", retval, test.val, test.sql) + return + } + }) + } + }) + t.Run("scan into *int64", func(t *testing.T) { + t.Run("from integer", func(t *testing.T) { + row := conn.QueryRow("select 11") + var retval *int64 + err := row.Scan(&retval) + if err != nil { + t.Error("Scan failed", err.Error()) + return + } + if *retval != 11 { + t.Errorf("Expected 11, got %v", retval) + } + }) + t.Run("from null", func(t *testing.T) { + row := conn.QueryRow("select null") + var retval *int64 + err := row.Scan(&retval) + if err != nil { + t.Error("Scan failed", err.Error()) + return + } + if retval != nil { + t.Errorf("Expected nil, got %v", retval) + } + }) + }) +} + +func TestSelectDateTimeOffset(t *testing.T) { + type testStruct struct { + sql string + val time.Time + } + values := []testStruct{ + {"cast('2010-11-15T11:56:45.123+14:00' as datetimeoffset(3))", + time.Date(2010, 11, 15, 11, 56, 45, 123000000, time.FixedZone("", 14*60*60))}, + {"cast(cast('2010-11-15T11:56:45.123-14:00' as datetimeoffset(3)) as sql_variant)", + time.Date(2010, 11, 15, 11, 56, 45, 123000000, time.FixedZone("", -14*60*60))}, + {"cast('0001-01-01T00:00:00.0000000+00:00' as datetimeoffset(7))", + time.Date(1, 1, 1, 0, 0, 0, 0, time.FixedZone("", 0))}, + {"cast('9999-12-31T23:59:59.9999999+00:00' as datetimeoffset(7))", + time.Date(9999, 12, 31, 23, 59, 59, 999999900, time.FixedZone("", 0))}, + } + + conn := open(t) + defer conn.Close() + for _, test := range values { + row := conn.QueryRow("select " + test.sql) + var retval interface{} + err := row.Scan(&retval) + if err != nil { + t.Error("Scan failed:", test.sql, err.Error()) + continue + } + retvalDate := retval.(time.Time) + if retvalDate.UTC() != test.val.UTC() { + t.Errorf("UTC values don't match '%v' '%v' for test: %s", retvalDate, test.val, test.sql) + continue + } + if retvalDate.String() != test.val.String() { + t.Errorf("Locations don't match '%v' '%v' for test: %s", retvalDate.String(), test.val.String(), test.sql) + continue + } + } +} + +func TestSelectNewTypes(t *testing.T) { + conn := open(t) + defer conn.Close() + var ver string + err := conn.QueryRow("select SERVERPROPERTY('productversion')").Scan(&ver) + if err != nil { + t.Fatalf("cannot select productversion: %s", err) + } + var n int + _, err = fmt.Sscanf(ver, "%d", &n) + if err != nil { + t.Fatalf("cannot parse productversion: %s", err) + } + // 8 is SQL 2000, 9 is SQL 2005, 10 is SQL 2008, 11 is SQL 2012 + if n < 10 { + return + } + // run tests for new data types available only in SQL Server 2008 and later + type testStruct struct { + sql string + val interface{} + } + values := []testStruct{ + {"cast('0001-01-01' as date)", + time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)}, + {"cast('2000-01-01' as date)", + time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)}, + {"cast('9999-12-31' as date)", + time.Date(9999, 12, 31, 0, 0, 0, 0, time.UTC)}, + {"cast(NULL as date)", nil}, + {"cast('00:00:00.0000000' as time(7))", + time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)}, + {"cast('00:00:45.123' as time(3))", + time.Date(1, 1, 1, 00, 00, 45, 123000000, time.UTC)}, + {"cast('11:56:45.123' as time(3))", + time.Date(1, 1, 1, 11, 56, 45, 123000000, time.UTC)}, + {"cast('11:56:45' as time(0))", + time.Date(1, 1, 1, 11, 56, 45, 0, time.UTC)}, + {"cast('23:59:59.9999999' as time(7))", + time.Date(1, 1, 1, 23, 59, 59, 999999900, time.UTC)}, + {"cast(null as time(0))", nil}, + {"cast('0001-01-01T00:00:00.0000000' as datetime2(7))", + time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)}, + {"cast('2010-11-15T11:56:45.123' as datetime2(3))", + time.Date(2010, 11, 15, 11, 56, 45, 123000000, time.UTC)}, + {"cast('2010-11-15T11:56:45' as datetime2(0))", + time.Date(2010, 11, 15, 11, 56, 45, 0, time.UTC)}, + {"cast(cast('2000-01-01' as date) as sql_variant)", + time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)}, + {"cast(cast('00:00:45.123' as time(3)) as sql_variant)", + time.Date(1, 1, 1, 00, 00, 45, 123000000, time.UTC)}, + {"cast(cast('2010-11-15T11:56:45.123' as datetime2(3)) as sql_variant)", + time.Date(2010, 11, 15, 11, 56, 45, 123000000, time.UTC)}, + {"cast('9999-12-31T23:59:59.9999999' as datetime2(7))", + time.Date(9999, 12, 31, 23, 59, 59, 999999900, time.UTC)}, + {"cast(null as datetime2(3))", nil}, + } + for _, test := range values { + stmt, err := conn.Prepare("select " + test.sql) + if err != nil { + t.Error("Prepare failed:", test.sql, err.Error()) + return + } + defer stmt.Close() + + row := stmt.QueryRow() + var retval interface{} + err = row.Scan(&retval) + if err != nil { + t.Error("Scan failed:", test.sql, err.Error()) + continue + } + if retval != test.val { + t.Errorf("Values don't match '%s' '%s' for test: %s", retval, test.val, test.sql) + continue + } + } +} + +func TestTrans(t *testing.T) { + conn := open(t) + defer conn.Close() + + var tx *sql.Tx + var err error + if tx, err = conn.Begin(); err != nil { + t.Fatal("Begin failed", err.Error()) + } + if err = tx.Commit(); err != nil { + t.Fatal("Commit failed", err.Error()) + } + + if tx, err = conn.Begin(); err != nil { + t.Fatal("Begin failed", err.Error()) + } + if _, err = tx.Exec("create table #abc (fld int)"); err != nil { + t.Fatal("Create table failed", err.Error()) + } + if err = tx.Rollback(); err != nil { + t.Fatal("Rollback failed", err.Error()) + } +} + +func TestNull(t *testing.T) { + conn := open(t) + defer conn.Close() + + t.Run("scan into interface{}", func(t *testing.T) { + types := []string{ + "tinyint", + "smallint", + "int", + "bigint", + "real", + "float", + "smallmoney", + "money", + "decimal", + //"varbinary(15)", + //"binary(15)", + "nvarchar(15)", + "nchar(15)", + "varchar(15)", + "char(15)", + "bit", + "smalldatetime", + "date", + "time", + "datetime", + "datetime2", + "datetimeoffset", + "uniqueidentifier", + "sql_variant", + } + for _, typ := range types { + t.Run(typ, func(t *testing.T) { + row := conn.QueryRow("declare @x "+typ+" = ?; select @x", nil) + var retval interface{} + err := row.Scan(&retval) + if err != nil { + t.Error("Scan failed for type "+typ, err.Error()) + return + } + if retval != nil { + t.Error("Value should be nil, but it is ", retval) + return + } + }) + } + }) + + t.Run("scan into NullInt64", func(t *testing.T) { + types := []string{ + "tinyint", + "smallint", + "int", + "bigint", + "real", + "float", + "smallmoney", + "money", + "decimal", + //"varbinary(15)", + //"binary(15)", + "nvarchar(15)", + "nchar(15)", + "varchar(15)", + "char(15)", + "bit", + "smalldatetime", + "date", + "time", + "datetime", + "datetime2", + "datetimeoffset", + "uniqueidentifier", + "sql_variant", + } + for _, typ := range types { + row := conn.QueryRow("declare @x "+typ+" = ?; select @x", nil) + var retval sql.NullInt64 + err := row.Scan(&retval) + if err != nil { + t.Error("Scan failed for type "+typ, err.Error()) + return + } + if retval.Valid { + t.Error("Value should be nil, but it is ", retval) + return + } + } + }) + + t.Run("scan into *int", func(t *testing.T) { + types := []string{ + "tinyint", + "smallint", + "int", + "bigint", + "real", + "float", + "smallmoney", + "money", + "decimal", + //"varbinary(15)", + //"binary(15)", + "nvarchar(15)", + "nchar(15)", + "varchar(15)", + "char(15)", + "bit", + "smalldatetime", + "date", + "time", + "datetime", + "datetime2", + "datetimeoffset", + "uniqueidentifier", + "sql_variant", + } + for _, typ := range types { + row := conn.QueryRow("declare @x "+typ+" = ?; select @x", nil) + var retval *int + err := row.Scan(&retval) + if err != nil { + t.Error("Scan failed for type "+typ, err.Error()) + return + } + if retval != nil { + t.Error("Value should be nil, but it is ", retval) + return + } + } + }) +} + +func TestParams(t *testing.T) { + longstr := strings.Repeat("x", 10000) + longbytes := make([]byte, 10000) + testdate, err := time.Parse(time.RFC3339, "2010-01-01T00:00:00-00:00") + if err != nil { + t.Fatal(err) + } + values := []interface{}{ + int64(5), + "hello", + "", + []byte{1, 2, 3}, + []byte{}, + float64(1.12313554), + true, + false, + nil, + longstr, + longbytes, + testdate.UTC(), + } + + conn := open(t) + defer conn.Close() + + for _, val := range values { + t.Run(fmt.Sprintf("%T:%#v", val, val), func(t *testing.T) { + row := conn.QueryRow("select ?", val) + var retval interface{} + err := row.Scan(&retval) + if err != nil { + t.Error("Scan failed", err.Error()) + return + } + var same bool + switch decodedval := retval.(type) { + case []byte: + switch decodedvaltest := val.(type) { + case []byte: + same = bytes.Equal(decodedval, decodedvaltest) + default: + same = false + } + case time.Time: + same = decodedval.UTC() == val + default: + same = retval == val + } + if !same { + t.Error("Value don't match", retval, val) + return + } + }) + } +} + +func TestExec(t *testing.T) { + conn := open(t) + defer conn.Close() + + res, err := conn.Exec("create table #abc (fld int)") + if err != nil { + t.Fatal("Exec failed", err.Error()) + } + _ = res +} + +func TestShortTimeout(t *testing.T) { + if testing.Short() { + t.Skip("short") + } + checkConnStr(t) + SetLogger(testLogger{t}) + dsn := makeConnStr(t) + dsnParams := dsn.Query() + dsnParams.Set("Connection Timeout", "2") + dsn.RawQuery = dsnParams.Encode() + conn, err := sql.Open("mssql", dsn.String()) + if err != nil { + t.Fatal("Open connection failed:", err.Error()) + } + defer conn.Close() + + _, err = conn.Exec("waitfor delay '00:00:15'") + if err == nil { + t.Fatal("Exec should fail with timeout, but no failure occurred") + } + if neterr, ok := err.(net.Error); !ok || !neterr.Timeout() { + t.Fatal("failure not a timeout, failed with", err) + } + + // connection should be usable after timeout + row := conn.QueryRow("select 1") + var val int64 + err = row.Scan(&val) + if err != nil { + t.Fatal("Scan failed with", err) + } +} + +func TestTwoQueries(t *testing.T) { + conn := open(t) + defer conn.Close() + + rows, err := conn.Query("select 1") + if err != nil { + t.Fatal("First exec failed", err) + } + if !rows.Next() { + t.Fatal("First query didn't return row") + } + var i int + if err = rows.Scan(&i); err != nil { + t.Fatal("Scan failed", err) + } + if i != 1 { + t.Fatalf("Wrong value returned %d, should be 1", i) + } + + if rows, err = conn.Query("select 2"); err != nil { + t.Fatal("Second query failed", err) + } + if !rows.Next() { + t.Fatal("Second query didn't return row") + } + if err = rows.Scan(&i); err != nil { + t.Fatal("Scan failed", err) + } + if i != 2 { + t.Fatalf("Wrong value returned %d, should be 2", i) + } +} + +func TestError(t *testing.T) { + conn := open(t) + defer conn.Close() + + _, err := conn.Query("exec bad") + if err == nil { + t.Fatal("Query should fail") + } + + if sqlerr, ok := err.(Error); !ok { + t.Fatalf("Should be sql error, actually %T, %v", err, err) + } else { + if sqlerr.Number != 2812 { // Could not find stored procedure 'bad' + t.Fatalf("Should be specific error code 2812, actually %d %s", sqlerr.Number, sqlerr) + } + } +} + +func TestQueryNoRows(t *testing.T) { + conn := open(t) + defer conn.Close() + + var rows *sql.Rows + var err error + if rows, err = conn.Query("create table #abc (fld int)"); err != nil { + t.Fatal("Query failed", err) + } + if rows.Next() { + t.Fatal("Query shoulnd't return any rows") + } +} + +func TestQueryManyNullsRow(t *testing.T) { + conn := open(t) + defer conn.Close() + + var row *sql.Row + var err error + if row = conn.QueryRow("select null, null, null, null, null, null, null, null"); err != nil { + t.Fatal("Query failed", err) + } + var v [8]sql.NullInt64 + if err = row.Scan(&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7]); err != nil { + t.Fatal("Scan failed", err) + } +} + +func TestOrderBy(t *testing.T) { + conn := open(t) + defer conn.Close() + + tx, err := conn.Begin() + if err != nil { + t.Fatal("Begin tran failed", err) + } + defer tx.Rollback() + + _, err = tx.Exec("if (exists(select * from INFORMATION_SCHEMA.TABLES where TABLE_NAME='tbl')) drop table tbl") + if err != nil { + t.Fatal("Drop table failed", err) + } + + _, err = tx.Exec("create table tbl (fld1 int primary key, fld2 int)") + if err != nil { + t.Fatal("Create table failed", err) + } + _, err = tx.Exec("insert into tbl (fld1, fld2) values (1, 2)") + if err != nil { + t.Fatal("Insert failed", err) + } + _, err = tx.Exec("insert into tbl (fld1, fld2) values (2, 1)") + if err != nil { + t.Fatal("Insert failed", err) + } + + rows, err := tx.Query("select * from tbl order by fld1") + if err != nil { + t.Fatal("Query failed", err) + } + + for rows.Next() { + var fld1 int32 + var fld2 int32 + err = rows.Scan(&fld1, &fld2) + if err != nil { + t.Fatal("Scan failed", err) + } + } + + err = rows.Err() + if err != nil { + t.Fatal("Rows have errors", err) + } +} + +func TestScanDecimal(t *testing.T) { + conn := open(t) + defer conn.Close() + + var f float64 + err := conn.QueryRow("select cast(0.5 as numeric(25,1))").Scan(&f) + if err != nil { + t.Error("query row / scan failed:", err.Error()) + return + } + if math.Abs(f-0.5) > 0.000001 { + t.Error("Value is not 0.5:", f) + return + } + + var s string + err = conn.QueryRow("select cast(-0.05 as numeric(25,2))").Scan(&s) + if err != nil { + t.Error("query row / scan failed:", err.Error()) + return + } + if s != "-0.05" { + t.Error("Value is not -0.05:", s) + return + } +} + +func TestAffectedRows(t *testing.T) { + conn := open(t) + defer conn.Close() + + tx, err := conn.Begin() + if err != nil { + t.Fatal("Begin tran failed", err) + } + defer tx.Rollback() + + res, err := tx.Exec("create table #foo (bar int)") + if err != nil { + t.Fatal("create table failed") + } + n, err := res.RowsAffected() + if err != nil { + t.Fatal("rows affected failed") + } + if n != 0 { + t.Error("Expected 0 rows affected, got ", n) + } + + res, err = tx.Exec("insert into #foo (bar) values (1)") + if err != nil { + t.Fatal("insert failed") + } + n, err = res.RowsAffected() + if err != nil { + t.Fatal("rows affected failed") + } + if n != 1 { + t.Error("Expected 1 row affected, got ", n) + } + + res, err = tx.Exec("insert into #foo (bar) values (?)", 2) + if err != nil { + t.Fatal("insert failed", err) + } + n, err = res.RowsAffected() + if err != nil { + t.Fatal("rows affected failed") + } + if n != 1 { + t.Error("Expected 1 row affected, got ", n) + } +} + +func TestIdentity(t *testing.T) { + conn := open(t) + defer conn.Close() + + tx, err := conn.Begin() + if err != nil { + t.Fatal("Begin tran failed", err) + } + defer tx.Rollback() + + res, err := tx.Exec("create table #foo (bar int identity, baz int unique)") + if err != nil { + t.Fatal("create table failed") + } + + res, err = tx.Exec("insert into #foo (baz) values (1)") + if err != nil { + t.Fatal("insert failed") + } + n, err := res.LastInsertId() + if err != nil { + t.Fatal("last insert id failed") + } + if n != 1 { + t.Error("Expected 1 for identity, got ", n) + } + + res, err = tx.Exec("insert into #foo (baz) values (20)") + if err != nil { + t.Fatal("insert failed") + } + n, err = res.LastInsertId() + if err != nil { + t.Fatal("last insert id failed") + } + if n != 2 { + t.Error("Expected 2 for identity, got ", n) + } + + res, err = tx.Exec("insert into #foo (baz) values (1)") + if err == nil { + t.Fatal("insert should fail") + } + + res, err = tx.Exec("insert into #foo (baz) values (?)", 1) + if err == nil { + t.Fatal("insert should fail") + } +} + +func queryParamRoundTrip(db *sql.DB, param interface{}, dest interface{}) { + err := db.QueryRow("select ?", param).Scan(dest) + if err != nil { + log.Panicf("select / scan failed: %v", err.Error()) + } +} + +func TestDateTimeParam(t *testing.T) { + conn := open(t) + defer conn.Close() + type testStruct struct { + t time.Time + } + var emptydate time.Time + mindate := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC) + maxdate := time.Date(9999, 12, 31, 23, 59, 59, 999999900, time.UTC) + values := []testStruct{ + {time.Date(2015, time.October, 12, 10, 22, 0, 0, time.FixedZone("PST", -8*60*60))}, // back to the future day + {time.Date(1961, time.April, 12, 9, 7, 0, 0, time.FixedZone("MSK", 3*60*60))}, // First man in space + {time.Date(1969, time.July, 20, 20, 18, 0, 0, time.UTC)}, // First man on the Moon + {time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)}, // UNIX date + {time.Date(1982, 1, 3, 12, 13, 14, 300, time.FixedZone("YAKT", 9*60*60))}, // some random date + {time.Date(4, 6, 3, 12, 13, 14, 150000000, time.UTC)}, // some random date + {mindate}, // minimal value + {maxdate}, // maximum value + {time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC)}, // just over limit + {emptydate}, + } + for _, test := range values { + t.Run(fmt.Sprintf("Test for %v", test.t), func(t *testing.T) { + var t2 time.Time + queryParamRoundTrip(conn, test.t, &t2) + expected := test.t + // clip value + if test.t.Before(mindate) { + expected = mindate + } + if test.t.After(maxdate) { + expected = maxdate + } + + if expected.Sub(t2) != 0 { + t.Errorf("expected: '%s', got: '%s' delta: %d", expected, t2, expected.Sub(t2)) + } + }) + } + +} + +func TestUniqueIdentifierParam(t *testing.T) { + conn := open(t) + defer conn.Close() + type testStruct struct { + name string + uuid interface{} + } + + expected := UniqueIdentifier{0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, + 0xCD, 0xEF, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + } + + values := []testStruct{ + { + "[]byte", + []byte{0x67, 0x45, 0x23, 0x01, + 0xAB, 0x89, + 0xEF, 0xCD, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}}, + { + "string", + "01234567-89ab-cdef-0123-456789abcdef"}, + } + + for _, test := range values { + t.Run(test.name, func(t *testing.T) { + var uuid2 UniqueIdentifier + err := conn.QueryRow("select ?", test.uuid).Scan(&uuid2) + if err != nil { + t.Fatal("select / scan failed", err.Error()) + } + + if expected != uuid2 { + t.Errorf("uniqueidentifier does not match: '%s' '%s'", expected, uuid2) + } + }) + } +} + +func TestBigQuery(t *testing.T) { + conn := open(t) + defer conn.Close() + rows, err := conn.Query(`WITH n(n) AS + ( + SELECT 1 + UNION ALL + SELECT n+1 FROM n WHERE n < 10000 + ) + SELECT n, @@version FROM n ORDER BY n + OPTION (MAXRECURSION 10000);`) + if err != nil { + t.Fatal("cannot exec query", err) + } + rows.Next() + rows.Close() + var res int + err = conn.QueryRow("select 0").Scan(&res) + if err != nil { + t.Fatal("cannot scan value", err) + } + if res != 0 { + t.Fatal("expected 0, got ", res) + } +} + +func TestBug32(t *testing.T) { + conn := open(t) + defer conn.Close() + + tx, err := conn.Begin() + if err != nil { + t.Fatal("Begin tran failed", err) + } + defer tx.Rollback() + + _, err = tx.Exec("if (exists(select * from INFORMATION_SCHEMA.TABLES where TABLE_NAME='tbl')) drop table tbl") + if err != nil { + t.Fatal("Drop table failed", err) + } + + _, err = tx.Exec("create table tbl(a int primary key,fld bit null)") + if err != nil { + t.Fatal("Create table failed", err) + } + + _, err = tx.Exec("insert into tbl (a,fld) values (1,nullif(?, ''))", "") + if err != nil { + t.Fatal("Insert failed", err) + } +} + +func TestIgnoreEmptyResults(t *testing.T) { + conn := open(t) + defer conn.Close() + rows, err := conn.Query("set nocount on; select 2") + if err != nil { + t.Fatal("Query failed", err.Error()) + } + if !rows.Next() { + t.Fatal("Query didn't return row") + } + var fld1 int32 + err = rows.Scan(&fld1) + if err != nil { + t.Fatal("Scan failed", err) + } + if fld1 != 2 { + t.Fatal("Returned value doesn't match") + } +} + +func TestStmt_SetQueryNotification(t *testing.T) { + checkConnStr(t) + mssqldriver := driverWithProcess(t) + cn, err := mssqldriver.Open(makeConnStr(t).String()) + if err != nil { + t.Fatalf("failed to open connection: %v", err) + } + stmt, err := cn.Prepare("SELECT 1") + if err != nil { + t.Error("Connection failed", err) + } + + sqlstmt := stmt.(*Stmt) + sqlstmt.SetQueryNotification("ABC", "service=WebCacheNotifications", time.Hour) + + rows, err := sqlstmt.Query(nil) + if err == nil { + rows.Close() + } + // notifications are sent to Service Broker + // see for more info: https://github.com/denisenkom/go-mssqldb/pull/90 +} + +func TestErrorInfo(t *testing.T) { + conn := open(t) + defer conn.Close() + + _, err := conn.Exec("select bad") + if sqlError, ok := err.(Error); ok { + if sqlError.SQLErrorNumber() != 207 /*invalid column name*/ { + t.Errorf("Query failed with unexpected error number %d %s", sqlError.SQLErrorNumber(), sqlError.SQLErrorMessage()) + } + if sqlError.SQLErrorLineNo() != 1 { + t.Errorf("Unexpected line number returned %v, expected %v", sqlError.SQLErrorLineNo(), 1) + } + } else { + t.Error("Failed to convert error to SQLErorr", err) + } + _, err = conn.Exec("RAISERROR('test message', 18, 111)") + if sqlError, ok := err.(Error); ok { + if sqlError.SQLErrorNumber() != 50000 { + t.Errorf("Query failed with unexpected error number %d %s", sqlError.SQLErrorNumber(), sqlError.SQLErrorMessage()) + } + if sqlError.SQLErrorMessage() != "test message" { + t.Fail() + } + if sqlError.SQLErrorClass() != 18 { + t.Fail() + } + if sqlError.SQLErrorState() != 111 { + t.Fail() + } + if sqlError.SQLErrorLineNo() != 1 { + t.Errorf("Unexpected line number returned %v, expected %v", sqlError.SQLErrorLineNo(), 1) + } + // just call those methods to make sure we have some coverage for them + sqlError.SQLErrorServerName() + sqlError.SQLErrorProcName() + } else { + t.Error("Failed to convert error to SQLErorr", err) + } +} + +func TestSetLanguage(t *testing.T) { + conn := open(t) + defer conn.Close() + + _, err := conn.Exec("set language russian") + if err != nil { + t.Errorf("Query failed with unexpected error %s", err) + } + + row := conn.QueryRow("select cast(getdate() as varchar(50))") + var val interface{} + err = row.Scan(&val) + if err != nil { + t.Errorf("Query failed with unexpected error %s", err) + } + t.Log("Returned value", val) +} + +func TestConnectionClosing(t *testing.T) { + pool := open(t) + defer pool.Close() + for i := 1; i <= 100; i++ { + if pool.Stats().OpenConnections > 1 { + t.Errorf("Open connections is expected to stay <= 1, but it is %d", pool.Stats().OpenConnections) + return + } + + stmt, err := pool.Query("select 1") + if err != nil { + t.Fatalf("Query failed with unexpected error %s", err) + } + for stmt.Next() { + var val interface{} + err := stmt.Scan(&val) + if err != nil { + t.Fatalf("Query failed with unexpected error %s", err) + } + } + } +} + +func TestBeginTranError(t *testing.T) { + checkConnStr(t) + drv := driverWithProcess(t) + conn, err := drv.open(context.Background(), makeConnStr(t).String()) + if err != nil { + t.Fatalf("Open failed with error %v", err) + } + + defer conn.Close() + // close actual connection to make begin transaction to fail during sending of a packet + conn.sess.buf.transport.Close() + + ctx := context.Background() + _, err = conn.begin(ctx, isolationSnapshot) + if err == nil || conn.connectionGood == true { + t.Errorf("begin should fail as a bad connection, err=%v", err) + } + + // reopen connection + conn, err = drv.open(context.Background(), makeConnStr(t).String()) + if err != nil { + t.Fatalf("Open failed with error %v", err) + } + err = conn.sendBeginRequest(ctx, isolationSerializable) + if err != nil { + t.Fatalf("sendBeginRequest failed with error %v", err) + } + + // close connection to cause processBeginResponse to fail + conn.sess.buf.transport.Close() + _, err = conn.processBeginResponse(ctx) + switch err { + case nil: + t.Error("processBeginResponse should fail but it succeeded") + case driver.ErrBadConn: + t.Error("processBeginResponse should fail with error different from ErrBadConn but it did") + } + + if conn.connectionGood { + t.Fatal("Connection should be in a bad state") + } +} + +func TestCommitTranError(t *testing.T) { + checkConnStr(t) + drv := driverWithProcess(t) + conn, err := drv.open(context.Background(), makeConnStr(t).String()) + if err != nil { + t.Fatalf("Open failed with error %v", err) + } + + defer conn.Close() + // close actual connection to make commit transaction to fail during sending of a packet + conn.sess.buf.transport.Close() + + ctx := context.Background() + err = conn.Commit() + if err == nil || conn.connectionGood { + t.Errorf("begin should fail and set the connection to bad, but it returned %v", err) + } + + // reopen connection + conn, err = drv.open(context.Background(), makeConnStr(t).String()) + if err != nil { + t.Fatalf("Open failed with error %v", err) + } + err = conn.sendCommitRequest() + if err != nil { + t.Fatalf("sendCommitRequest failed with error %v", err) + } + + // close connection to cause processBeginResponse to fail + conn.sess.buf.transport.Close() + err = conn.simpleProcessResp(ctx) + switch err { + case nil: + t.Error("simpleProcessResp should fail but it succeeded") + case driver.ErrBadConn: + t.Error("simpleProcessResp should fail with error different from ErrBadConn but it did") + } + + if conn.connectionGood { + t.Fatal("Connection should be in a bad state") + } + + // reopen connection + conn, err = drv.open(context.Background(), makeConnStr(t).String()) + defer conn.Close() + if err != nil { + t.Fatalf("Open failed with error %v", err) + } + // should fail because there is no transaction + err = conn.Commit() + switch err { + case nil: + t.Error("Commit should fail but it succeeded") + case driver.ErrBadConn: + t.Error("Commit should fail with error different from ErrBadConn but it did") + } +} + +func TestRollbackTranError(t *testing.T) { + checkConnStr(t) + drv := driverWithProcess(t) + conn, err := drv.open(context.Background(), makeConnStr(t).String()) + if err != nil { + t.Fatalf("Open failed with error %v", err) + } + + defer conn.Close() + // close actual connection to make commit transaction to fail during sending of a packet + conn.sess.buf.transport.Close() + + ctx := context.Background() + err = conn.Rollback() + if err == nil || conn.connectionGood { + t.Errorf("Rollback should fail and set connection to bad but it returned %v", err) + } + + // reopen connection + conn, err = drv.open(context.Background(), makeConnStr(t).String()) + if err != nil { + t.Fatalf("Open failed with error %v", err) + } + err = conn.sendRollbackRequest() + if err != nil { + t.Fatalf("sendCommitRequest failed with error %v", err) + } + + // close connection to cause processBeginResponse to fail + conn.sess.buf.transport.Close() + err = conn.simpleProcessResp(ctx) + switch err { + case nil: + t.Error("simpleProcessResp should fail but it succeeded") + case driver.ErrBadConn: + t.Error("simpleProcessResp should fail with error different from ErrBadConn but it did") + } + + if conn.connectionGood { + t.Fatal("Connection should be in a bad state") + } + + // reopen connection + conn, err = drv.open(context.Background(), makeConnStr(t).String()) + defer conn.Close() + if err != nil { + t.Fatalf("Open failed with error %v", err) + } + // should fail because there is no transaction + err = conn.Rollback() + switch err { + case nil: + t.Error("Commit should fail but it succeeded") + case driver.ErrBadConn: + t.Error("Commit should fail with error different from ErrBadConn but it did") + } +} + +func TestSendQueryErrors(t *testing.T) { + checkConnStr(t) + drv := driverWithProcess(t) + conn, err := drv.open(context.Background(), makeConnStr(t).String()) + if err != nil { + t.FailNow() + } + + defer conn.Close() + stmt, err := conn.prepareContext(context.Background(), "select 1") + if err != nil { + t.FailNow() + } + + // should fail because parameter is invalid + _, err = stmt.Query([]driver.Value{conn}) + if err == nil { + t.Fail() + } + + // close actual connection to make commit transaction to fail during sending of a packet + conn.sess.buf.transport.Close() + + // should fail because connection is closed + _, err = stmt.Query([]driver.Value{}) + if err == nil || stmt.c.connectionGood { + t.Fail() + } + + stmt, err = conn.prepareContext(context.Background(), "select ?") + if err != nil { + t.FailNow() + } + // should fail because connection is closed + _, err = stmt.Query([]driver.Value{int64(1)}) + if err == nil || stmt.c.connectionGood { + t.Fail() + } +} + +func TestProcessQueryErrors(t *testing.T) { + checkConnStr(t) + drv := driverWithProcess(t) + conn, err := drv.open(context.Background(), makeConnStr(t).String()) + if err != nil { + t.Fatal("open expected to succeed, but it failed with", err) + } + stmt, err := conn.prepareContext(context.Background(), "select 1") + if err != nil { + t.Fatal("prepareContext expected to succeed, but it failed with", err) + } + err = stmt.sendQuery([]namedValue{}) + if err != nil { + t.Fatal("sendQuery expected to succeed, but it failed with", err) + } + // close actual connection to make reading response to fail + conn.sess.buf.transport.Close() + _, err = stmt.processQueryResponse(context.Background()) + if err == nil { + t.Error("processQueryResponse expected to fail but it succeeded") + } + // should not fail with ErrBadConn because query was successfully sent to server + if err == driver.ErrBadConn { + t.Error("processQueryResponse expected to fail with error other than ErrBadConn but it failed with it") + } + + if conn.connectionGood { + t.Fatal("Connection should be in a bad state") + } +} + +func TestSendExecErrors(t *testing.T) { + checkConnStr(t) + drv := driverWithProcess(t) + conn, err := drv.open(context.Background(), makeConnStr(t).String()) + if err != nil { + t.FailNow() + } + + defer conn.Close() + stmt, err := conn.prepareContext(context.Background(), "select 1") + if err != nil { + t.FailNow() + } + + // should fail because parameter is invalid + _, err = stmt.Exec([]driver.Value{conn}) + if err == nil { + t.Fail() + } + + // close actual connection to make commit transaction to fail during sending of a packet + conn.sess.buf.transport.Close() + + // should fail because connection is closed + _, err = stmt.Exec([]driver.Value{}) + if err == nil || stmt.c.connectionGood { + t.Fail() + } + + stmt, err = conn.prepareContext(context.Background(), "select ?") + if err != nil { + t.FailNow() + } + // should fail because connection is closed + _, err = stmt.Exec([]driver.Value{int64(1)}) + if err == nil || stmt.c.connectionGood { + t.Fail() + } +} + +func TestLongConnection(t *testing.T) { + checkConnStr(t) + + list := []struct { + connTimeout string + queryTimeout string + ctxTimeout time.Duration + wantFail bool + }{ + {"1", "00:00:02", 6 * time.Second, true}, + {"2", "00:00:01", 6 * time.Second, false}, + + // Check no connection timeout. + {"0", "00:00:01", 2 * time.Second, false}, + // {"0", "00:00:45", 60 * time.Second, false}, // Skip for normal testing to limit time. + } + + for i, item := range list { + t.Run(fmt.Sprintf("item-index-%d,want-fail=%t", i, item.wantFail), func(t *testing.T) { + dsn := makeConnStr(t) + dsnParams := dsn.Query() + dsnParams.Set("connection timeout", item.connTimeout) + dsn.RawQuery = dsnParams.Encode() + + db, err := sql.Open("sqlserver", dsn.String()) + if err != nil { + t.Fatalf("failed to open driver sqlserver") + } + defer db.Close() + + ctx, cancel := context.WithTimeout(context.Background(), item.ctxTimeout) + defer cancel() + + _, err = db.ExecContext(ctx, "WAITFOR DELAY '"+item.queryTimeout+"';") + if item.wantFail && err == nil { + t.Fatal("exec no error") + } + if !item.wantFail && err != nil { + t.Fatal("exec error", err) + } + }) + } +} + +func TestNextResultSet(t *testing.T) { + conn := open(t) + defer conn.Close() + rows, err := conn.Query("select 1; select 2") + if err != nil { + t.Fatal("Query failed", err.Error()) + } + defer func() { + err := rows.Err() + if err != nil { + t.Error("unexpected error:", err) + } + }() + + defer rows.Close() + + if !rows.Next() { + t.Fatal("Query didn't return row") + } + var fld1, fld2 int32 + err = rows.Scan(&fld1) + if err != nil { + t.Fatal("Scan failed", err) + } + if fld1 != 1 { + t.Fatal("Returned value doesn't match") + } + if rows.Next() { + t.Fatal("Query returned unexpected second row.") + } + // calling next again should still return false + if rows.Next() { + t.Fatal("Query returned unexpected second row.") + } + if !rows.NextResultSet() { + t.Fatal("NextResultSet should return true but returned false") + } + if !rows.Next() { + t.Fatal("Query didn't return row") + } + err = rows.Scan(&fld2) + if err != nil { + t.Fatal("Scan failed", err) + } + if fld2 != 2 { + t.Fatal("Returned value doesn't match") + } + if rows.NextResultSet() { + t.Fatal("NextResultSet should return false but returned true") + } +} + +func TestColumnTypeIntrospection(t *testing.T) { + type tst struct { + expr string + typeName string + reflType reflect.Type + hasSize bool + size int64 + hasPrecScale bool + precision int64 + scale int64 + } + tests := []tst{ + {"cast(1 as bit)", "BIT", reflect.TypeOf(true), false, 0, false, 0, 0}, + {"cast(1 as tinyint)", "TINYINT", reflect.TypeOf(int64(0)), false, 0, false, 0, 0}, + {"cast(1 as smallint)", "SMALLINT", reflect.TypeOf(int64(0)), false, 0, false, 0, 0}, + {"1", "INT", reflect.TypeOf(int64(0)), false, 0, false, 0, 0}, + {"cast(1 as bigint)", "BIGINT", reflect.TypeOf(int64(0)), false, 0, false, 0, 0}, + {"cast(1 as real)", "REAL", reflect.TypeOf(0.0), false, 0, false, 0, 0}, + {"cast(1 as float)", "FLOAT", reflect.TypeOf(0.0), false, 0, false, 0, 0}, + {"cast('abc' as varbinary(3))", "VARBINARY", reflect.TypeOf([]byte{}), true, 3, false, 0, 0}, + {"cast('abc' as varbinary(max))", "VARBINARY", reflect.TypeOf([]byte{}), true, 2147483645, false, 0, 0}, + {"cast(1 as datetime)", "DATETIME", reflect.TypeOf(time.Time{}), false, 0, false, 0, 0}, + {"cast(1 as smalldatetime)", "SMALLDATETIME", reflect.TypeOf(time.Time{}), false, 0, false, 0, 0}, + {"cast(getdate() as datetime2(7))", "DATETIME2", reflect.TypeOf(time.Time{}), false, 0, false, 0, 0}, + {"cast(getdate() as datetimeoffset(7))", "DATETIMEOFFSET", reflect.TypeOf(time.Time{}), false, 0, false, 0, 0}, + {"cast(getdate() as date)", "DATE", reflect.TypeOf(time.Time{}), false, 0, false, 0, 0}, + {"cast(getdate() as time)", "TIME", reflect.TypeOf(time.Time{}), false, 0, false, 0, 0}, + {"'abc'", "VARCHAR", reflect.TypeOf(""), true, 3, false, 0, 0}, + {"cast('abc' as varchar(max))", "VARCHAR", reflect.TypeOf(""), true, 2147483645, false, 0, 0}, + {"N'abc'", "NVARCHAR", reflect.TypeOf(""), true, 3, false, 0, 0}, + {"cast(N'abc' as NVARCHAR(MAX))", "NVARCHAR", reflect.TypeOf(""), true, 1073741822, false, 0, 0}, + {"cast(1 as decimal)", "DECIMAL", reflect.TypeOf([]byte{}), false, 0, true, 18, 0}, + {"cast(1 as decimal(5, 2))", "DECIMAL", reflect.TypeOf([]byte{}), false, 0, true, 5, 2}, + {"cast(1 as numeric(10, 4))", "DECIMAL", reflect.TypeOf([]byte{}), false, 0, true, 10, 4}, + {"cast(1 as money)", "MONEY", reflect.TypeOf([]byte{}), false, 0, false, 0, 0}, + {"cast(1 as smallmoney)", "SMALLMONEY", reflect.TypeOf([]byte{}), false, 0, false, 0, 0}, + {"cast(0x6F9619FF8B86D011B42D00C04FC964FF as uniqueidentifier)", "UNIQUEIDENTIFIER", reflect.TypeOf([]byte{}), false, 0, false, 0, 0}, + {"cast('' as xml)", "XML", reflect.TypeOf(""), true, 1073741822, false, 0, 0}, + {"cast('abc' as text)", "TEXT", reflect.TypeOf(""), true, 2147483647, false, 0, 0}, + {"cast(N'abc' as ntext)", "NTEXT", reflect.TypeOf(""), true, 1073741823, false, 0, 0}, + {"cast('abc' as image)", "IMAGE", reflect.TypeOf([]byte{}), true, 2147483647, false, 0, 0}, + {"cast('abc' as char(3))", "CHAR", reflect.TypeOf(""), true, 3, false, 0, 0}, + {"cast(N'abc' as nchar(3))", "NCHAR", reflect.TypeOf(""), true, 3, false, 0, 0}, + {"cast(1 as sql_variant)", "SQL_VARIANT", reflect.TypeOf(nil), false, 0, false, 0, 0}, + } + conn := open(t) + defer conn.Close() + for _, tt := range tests { + rows, err := conn.Query("select " + tt.expr) + if err != nil { + t.Fatalf("Query failed with unexpected error %s", err) + } + ct, err := rows.ColumnTypes() + if err != nil { + t.Fatalf("Query failed with unexpected error %s", err) + } + if ct[0].DatabaseTypeName() != tt.typeName { + t.Errorf("Expected type %s but returned %s", tt.typeName, ct[0].DatabaseTypeName()) + } + size, ok := ct[0].Length() + if ok != tt.hasSize { + t.Errorf("Expected has size %v but returned %v for %s", tt.hasSize, ok, tt.expr) + } else { + if ok && size != tt.size { + t.Errorf("Expected size %d but returned %d for %s", tt.size, size, tt.expr) + } + } + + prec, scale, ok := ct[0].DecimalSize() + if ok != tt.hasPrecScale { + t.Errorf("Expected has prec/scale %v but returned %v for %s", tt.hasPrecScale, ok, tt.expr) + } else { + if ok && prec != tt.precision { + t.Errorf("Expected precision %d but returned %d for %s", tt.precision, prec, tt.expr) + } + if ok && scale != tt.scale { + t.Errorf("Expected scale %d but returned %d for %s", tt.scale, scale, tt.expr) + } + } + + if ct[0].ScanType() != tt.reflType { + t.Errorf("Expected ScanType %v but got %v for %s", tt.reflType, ct[0].ScanType(), tt.expr) + } + } +} + +func TestColumnIntrospection(t *testing.T) { + type tst struct { + expr string + fieldName string + typeName string + nullable bool + hasSize bool + size int64 + hasPrecScale bool + precision int64 + scale int64 + } + tests := []tst{ + {"f1 int null", "f1", "INT", true, false, 0, false, 0, 0}, + {"f2 varchar(15) not null", "f2", "VARCHAR", false, true, 15, false, 0, 0}, + {"f3 decimal(5, 2) null", "f3", "DECIMAL", true, false, 0, true, 5, 2}, + } + conn := open(t) + defer conn.Close() + + // making table variable with specified fields and making a select from it + exprs := make([]string, len(tests)) + for i, test := range tests { + exprs[i] = test.expr + } + exprJoined := strings.Join(exprs, ",") + rows, err := conn.Query(fmt.Sprintf("declare @tbl table(%s); select * from @tbl", exprJoined)) + if err != nil { + t.Fatalf("Query failed with unexpected error %s", err) + } + + ct, err := rows.ColumnTypes() + if err != nil { + t.Fatalf("ColumnTypes failed with unexpected error %s", err) + } + for i, test := range tests { + if ct[i].Name() != test.fieldName { + t.Errorf("Field expected have name %s but it has name %s", test.fieldName, ct[i].Name()) + } + + if ct[i].DatabaseTypeName() != test.typeName { + t.Errorf("Invalid type name returned %s expected %s", ct[i].DatabaseTypeName(), test.typeName) + } + + nullable, ok := ct[i].Nullable() + if ok { + if nullable != test.nullable { + t.Errorf("Invalid nullable value returned %v", nullable) + } + } else { + t.Error("Nullable was expected to support Nullable but it didn't") + } + + size, ok := ct[i].Length() + if ok != test.hasSize { + t.Errorf("Expected has size %v but returned %v for %s", test.hasSize, ok, test.expr) + } else { + if ok && size != test.size { + t.Errorf("Expected size %d but returned %d for %s", test.size, size, test.expr) + } + } + + prec, scale, ok := ct[i].DecimalSize() + if ok != test.hasPrecScale { + t.Errorf("Expected has prec/scale %v but returned %v for %s", test.hasPrecScale, ok, test.expr) + } else { + if ok && prec != test.precision { + t.Errorf("Expected precision %d but returned %d for %s", test.precision, prec, test.expr) + } + if ok && scale != test.scale { + t.Errorf("Expected scale %d but returned %d for %s", test.scale, scale, test.expr) + } + } + } +} + +func TestContext(t *testing.T) { + conn := open(t) + defer conn.Close() + + opts := &sql.TxOptions{ + Isolation: sql.LevelSerializable, + } + ctx := context.Background() + tx, err := conn.BeginTx(ctx, opts) + if err != nil { + t.Errorf("BeginTx failed with unexpected error %s", err) + return + } + rows, err := tx.QueryContext(ctx, "DBCC USEROPTIONS") + properties := make(map[string]string) + for rows.Next() { + var name, value string + if err = rows.Scan(&name, &value); err != nil { + t.Errorf("Scan failed with unexpected error %s", err) + } + properties[name] = value + } + + if properties["isolation level"] != "serializable" { + t.Errorf("Expected isolation level to be serializable but it is %s", properties["isolation level"]) + } + + row := tx.QueryRowContext(ctx, "select 1") + var val int64 + if err = row.Scan(&val); err != nil { + t.Errorf("QueryRowContext failed with unexpected error %s", err) + } + if val != 1 { + t.Error("Incorrect value returned from query") + } + + _, err = tx.ExecContext(ctx, "select 1") + if err != nil { + t.Errorf("ExecContext failed with unexpected error %s", err) + return + } + + _, err = tx.PrepareContext(ctx, "select 1") + if err != nil { + t.Errorf("PrepareContext failed with unexpected error %s", err) + return + } +} + +func TestBeginTxtReadOnlyNotSupported(t *testing.T) { + conn := open(t) + defer conn.Close() + opts := &sql.TxOptions{ReadOnly: true} + _, err := conn.BeginTx(context.Background(), opts) + if err == nil { + t.Error("BeginTx expected to fail for read only transaction because MSSQL doesn't support it, but it succeeded") + } +} + +func TestConn_BeginTx(t *testing.T) { + conn := open(t) + defer conn.Close() + _, err := conn.Exec("create table test (f int)") + defer conn.Exec("drop table test") + if err != nil { + t.Fatal("create table failed with error", err) + } + + tx1, err := conn.BeginTx(context.Background(), nil) + if err != nil { + t.Fatal("BeginTx failed with error", err) + } + tx2, err := conn.BeginTx(context.Background(), nil) + if err != nil { + t.Fatal("BeginTx failed with error", err) + } + _, err = tx1.Exec("insert into test (f) values (1)") + if err != nil { + t.Fatal("insert failed with error", err) + } + _, err = tx2.Exec("insert into test (f) values (2)") + if err != nil { + t.Fatal("insert failed with error", err) + } + tx1.Rollback() + tx2.Commit() + + rows, err := conn.Query("select f from test") + if err != nil { + t.Fatal("select failed with error", err) + } + values := []int64{} + for rows.Next() { + var val int64 + err = rows.Scan(&val) + if err != nil { + t.Fatal("scan failed with error", err) + } + values = append(values, val) + } + if !reflect.DeepEqual(values, []int64{2}) { + t.Errorf("Values is expected to be [1] but it is %v", values) + } +} + +func TestNamedParameters(t *testing.T) { + conn := open(t) + defer conn.Close() + row := conn.QueryRow( + "select :param2, :param1, :param2", + sql.Named("param1", 1), + sql.Named("param2", 2)) + var col1, col2, col3 int64 + err := row.Scan(&col1, &col2, &col3) + if err != nil { + t.Errorf("Scan failed with unexpected error %s", err) + return + } + if col1 != 2 || col2 != 1 || col3 != 2 { + t.Errorf("Unexpected values returned col1=%d, col2=%d, col3=%d", col1, col2, col3) + } +} + +func TestBadNamedParameters(t *testing.T) { + conn := open(t) + defer conn.Close() + row := conn.QueryRow( + "select :param2, :param1, :param2", + sql.Named("badparam1", 1), + sql.Named("param2", 2)) + var col1, col2, col3 int64 + err := row.Scan(&col1, &col2, &col3) + if err == nil { + t.Error("Scan succeeded unexpectedly") + return + } + t.Logf("Scan failed as expected with error %s", err) +} + +func TestMixedParameters(t *testing.T) { + conn := open(t) + defer conn.Close() + row := conn.QueryRow( + "select :2, :param1, :param2", + 5, // this parameter will be unused + 6, + sql.Named("param1", 1), + sql.Named("param2", 2)) + var col1, col2, col3 int64 + err := row.Scan(&col1, &col2, &col3) + if err != nil { + t.Errorf("Scan failed with unexpected error %s", err) + return + } + if col1 != 6 || col2 != 1 || col3 != 2 { + t.Errorf("Unexpected values returned col1=%d, col2=%d, col3=%d", col1, col2, col3) + } +} + +/* +func TestMixedParametersExample(t *testing.T) { + conn := open(t) + defer conn.Close() + row := conn.QueryRow( + "select :id, ?", + sql.Named("id", 1), + 2, + ) + var col1, col2 int64 + err := row.Scan(&col1, &col2) + if err != nil { + t.Errorf("Scan failed with unexpected error %s", err) + return + } + if col1 != 1 || col2 != 2 { + t.Errorf("Unexpected values returned col1=%d, col2=%d", col1, col2) + } +} +*/ + +func TestPinger(t *testing.T) { + conn := open(t) + defer conn.Close() + err := conn.Ping() + if err != nil { + t.Errorf("Failed to hit database") + } +} + +func TestQueryCancelLowLevel(t *testing.T) { + checkConnStr(t) + drv := driverWithProcess(t) + conn, err := drv.open(context.Background(), makeConnStr(t).String()) + if err != nil { + t.Fatalf("Open failed with error %v", err) + } + + defer conn.Close() + ctx, cancel := context.WithCancel(context.Background()) + stmt, err := conn.prepareContext(ctx, "waitfor delay '00:00:03'") + if err != nil { + t.Fatalf("Prepare failed with error %v", err) + } + err = stmt.sendQuery([]namedValue{}) + if err != nil { + t.Fatalf("sendQuery failed with error %v", err) + } + + cancel() + + _, err = stmt.processExec(ctx) + if err != context.Canceled { + t.Errorf("Expected error to be Cancelled but got %v", err) + } + + // same connection should be usable again after it was cancelled + stmt, err = conn.prepareContext(context.Background(), "select 1") + if err != nil { + t.Fatalf("Prepare failed with error %v", err) + } + rows, err := stmt.Query([]driver.Value{}) + if err != nil { + t.Fatalf("Query failed with error %v", err) + } + + values := []driver.Value{nil} + err = rows.Next(values) + if err != nil { + t.Fatalf("Next failed with error %v", err) + } +} + +func TestQueryCancelHighLevel(t *testing.T) { + conn := open(t) + defer conn.Close() + + ctx, cancel := context.WithCancel(context.Background()) + go func() { + time.Sleep(200 * time.Millisecond) + cancel() + }() + _, err := conn.ExecContext(ctx, "waitfor delay '00:00:03'") + if err != context.Canceled { + t.Errorf("ExecContext expected to fail with Cancelled but it returned %v", err) + } + + // connection should be usable after timeout + row := conn.QueryRow("select 1") + var val int64 + err = row.Scan(&val) + if err != nil { + t.Fatal("Scan failed with", err) + } +} + +func TestQueryTimeout(t *testing.T) { + conn := open(t) + defer conn.Close() + ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + defer cancel() + _, err := conn.ExecContext(ctx, "waitfor delay '00:00:03'") + if err != context.DeadlineExceeded { + t.Errorf("ExecContext expected to fail with DeadlineExceeded but it returned %v", err) + } + + // connection should be usable after timeout + row := conn.QueryRow("select 1") + var val int64 + err = row.Scan(&val) + if err != nil { + t.Fatal("Scan failed with", err) + } +} + +func TestDriverParams(t *testing.T) { + checkConnStr(t) + SetLogger(testLogger{t}) + type sqlCmd struct { + Name string + Driver string + Query string + Param []interface{} + Expect []interface{} + } + + list := []sqlCmd{ + { + Name: "preprocess-ordinal", + Driver: "mssql", + Query: `select V1=:1`, + Param: []interface{}{"abc"}, + Expect: []interface{}{"abc"}, + }, + { + Name: "preprocess-name", + Driver: "mssql", + Query: `select V1=:First`, + Param: []interface{}{sql.Named("First", "abc")}, + Expect: []interface{}{"abc"}, + }, + { + Name: "raw-ordinal", + Driver: "sqlserver", + Query: `select V1=@p1`, + Param: []interface{}{"abc"}, + Expect: []interface{}{"abc"}, + }, + { + Name: "raw-name", + Driver: "sqlserver", + Query: `select V1=@First`, + Param: []interface{}{sql.Named("First", "abc")}, + Expect: []interface{}{"abc"}, + }, + } + + for cmdIndex, cmd := range list { + t.Run(cmd.Name, func(t *testing.T) { + db, err := sql.Open(cmd.Driver, makeConnStr(t).String()) + if err != nil { + t.Fatalf("failed to open driver %q", cmd.Driver) + } + defer db.Close() + + rows, err := db.Query(cmd.Query, cmd.Param...) + if err != nil { + t.Fatalf("failed to run query %q %v", cmd.Query, err) + } + defer rows.Close() + + columns, err := rows.Columns() + if err != nil { + t.Fatalf("failed to get column schema %v", err) + } + clen := len(columns) + + if clen != len(cmd.Expect) { + t.Fatalf("query column has %d, expect %d columns", clen, len(cmd.Expect)) + } + + values := make([]interface{}, clen) + into := make([]interface{}, clen) + for i := 0; i < clen; i++ { + into[i] = &values[i] + } + for rows.Next() { + err = rows.Scan(into...) + if err != nil { + t.Fatalf("failed to scan into row for %d %q", cmdIndex, cmd.Driver) + } + for i := range cmd.Expect { + if values[i] != cmd.Expect[i] { + t.Fatalf("expected value in index %d %v != actual value %v", i, cmd.Expect[i], values[i]) + } + } + } + }) + } +} + +type connInterrupt struct { + net.Conn + + mu sync.Mutex + disruptRead bool + disruptWrite bool +} + +func (c *connInterrupt) Interrupt(write bool) { + c.mu.Lock() + if write { + c.disruptWrite = true + } else { + c.disruptRead = true + } + c.mu.Unlock() +} + +func (c *connInterrupt) Read(b []byte) (n int, err error) { + c.mu.Lock() + dis := c.disruptRead + c.mu.Unlock() + if dis { + return 0, disconnectError{} + } + return c.Conn.Read(b) +} + +func (c *connInterrupt) Write(b []byte) (n int, err error) { + c.mu.Lock() + dis := c.disruptWrite + c.mu.Unlock() + if dis { + return 0, disconnectError{} + } + return c.Conn.Write(b) +} + +type dialerInterrupt struct { + nd netDialer + + mu sync.Mutex + list []*connInterrupt +} + +func (d *dialerInterrupt) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { + conn, err := d.nd.DialContext(ctx, network, addr) + if err != nil { + return nil, err + } + ci := &connInterrupt{Conn: conn} + d.mu.Lock() + d.list = append(d.list, ci) + d.mu.Unlock() + return ci, err +} + +func (d *dialerInterrupt) Interrupt(write bool) { + d.mu.Lock() + defer d.mu.Unlock() + + for _, ci := range d.list { + ci.Interrupt(write) + } +} + +var _ net.Error = disconnectError{} + +type disconnectError struct{} + +func (disconnectError) Error() string { + return "disconnect" +} + +func (disconnectError) Timeout() bool { + return true +} + +func (disconnectError) Temporary() bool { + return true +} + +// TestDisconnect1 ensures errors and states are handled correctly if +// the server is disconnected mid-query. +func TestDisconnect1(t *testing.T) { + if testing.Short() { + t.Skip("short") + } + checkConnStr(t) + SetLogger(testLogger{t}) + + // Revert to the normal dialer after the test is done. + normalCreateDialer := createDialer + defer func() { + createDialer = normalCreateDialer + }() + + waitDisrupt := make(chan struct{}) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) + defer cancel() + + createDialer = func(p *connectParams) Dialer { + nd := netDialer{&net.Dialer{Timeout: p.dial_timeout, KeepAlive: p.keepAlive}} + di := &dialerInterrupt{nd: nd} + go func() { + <-waitDisrupt + di.Interrupt(true) + di.Interrupt(false) + }() + return di + } + db, err := sql.Open("sqlserver", makeConnStr(t).String()) + if err != nil { + t.Fatal(err) + } + + if err := db.PingContext(ctx); err != nil { + t.Fatal(err) + } + defer db.Close() + + _, err = db.ExecContext(ctx, `SET LOCK_TIMEOUT 1800;`) + if err != nil { + t.Fatal(err) + } + + go func() { + time.Sleep(time.Second * 1) + close(waitDisrupt) + }() + t.Log("prepare for query") + _, err = db.ExecContext(ctx, `waitfor delay '00:00:3';`) + if err != nil { + t.Log("expected error after disconnect", err) + return + } + t.Fatal("wanted error after Exec") +} + +// TestDisconnect2 tests a read error so the query is started +// but results cannot be read. +func TestDisconnect2(t *testing.T) { + if testing.Short() { + t.Skip("short") + } + checkConnStr(t) + SetLogger(testLogger{t}) + + // Revert to the normal dialer after the test is done. + normalCreateDialer := createDialer + defer func() { + createDialer = normalCreateDialer + }() + + end := make(chan error) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + go func() { + waitDisrupt := make(chan struct{}) + ctx, cancel = context.WithTimeout(ctx, time.Second*2) + defer cancel() + + createDialer = func(p *connectParams) Dialer { + nd := netDialer{&net.Dialer{Timeout: p.dial_timeout, KeepAlive: p.keepAlive}} + di := &dialerInterrupt{nd: nd} + go func() { + <-waitDisrupt + di.Interrupt(false) + }() + return di + } + db, err := sql.Open("sqlserver", makeConnStr(t).String()) + if err != nil { + t.Fatal(err) + } + + if err := db.PingContext(ctx); err != nil { + t.Fatal(err) + } + defer db.Close() + + _, err = db.ExecContext(ctx, `SET LOCK_TIMEOUT 1800;`) + if err != nil { + t.Fatal(err) + } + close(waitDisrupt) + + _, err = db.ExecContext(ctx, `waitfor delay '00:00:3';`) + end <- err + }() + + timeout := time.After(10 * time.Second) + select { + case err := <-end: + if err == nil { + t.Fatal("test err") + } + case <-timeout: + t.Fatal("timeout") + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/rpc.go b/vendor/github.com/denisenkom/go-mssqldb/rpc.go new file mode 100644 index 00000000..4ca22578 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/rpc.go @@ -0,0 +1,89 @@ +package mssql + +import ( + "encoding/binary" +) + +type procId struct { + id uint16 + name string +} + +// parameter flags +const ( + fByRevValue = 1 + fDefaultValue = 2 +) + +type param struct { + Name string + Flags uint8 + ti typeInfo + buffer []byte +} + +const ( + fWithRecomp = 1 + fNoMetaData = 2 + fReuseMetaData = 4 +) + +var ( + sp_Cursor = procId{1, ""} + sp_CursorOpen = procId{2, ""} + sp_CursorPrepare = procId{3, ""} + sp_CursorExecute = procId{4, ""} + sp_CursorPrepExec = procId{5, ""} + sp_CursorUnprepare = procId{6, ""} + sp_CursorFetch = procId{7, ""} + sp_CursorOption = procId{8, ""} + sp_CursorClose = procId{9, ""} + sp_ExecuteSql = procId{10, ""} + sp_Prepare = procId{11, ""} + sp_PrepExec = procId{13, ""} + sp_PrepExecRpc = procId{14, ""} + sp_Unprepare = procId{15, ""} +) + +// http://msdn.microsoft.com/en-us/library/dd357576.aspx +func sendRpc(buf *tdsBuffer, headers []headerStruct, proc procId, flags uint16, params []param, resetSession bool) (err error) { + buf.BeginPacket(packRPCRequest, resetSession) + writeAllHeaders(buf, headers) + if len(proc.name) == 0 { + var idswitch uint16 = 0xffff + err = binary.Write(buf, binary.LittleEndian, &idswitch) + if err != nil { + return + } + err = binary.Write(buf, binary.LittleEndian, &proc.id) + if err != nil { + return + } + } else { + err = writeUsVarChar(buf, proc.name) + if err != nil { + return + } + } + err = binary.Write(buf, binary.LittleEndian, &flags) + if err != nil { + return + } + for _, param := range params { + if err = writeBVarChar(buf, param.Name); err != nil { + return + } + if err = binary.Write(buf, binary.LittleEndian, param.Flags); err != nil { + return + } + err = writeTypeInfo(buf, ¶m.ti) + if err != nil { + return + } + err = param.ti.Writer(buf, param.ti, param.buffer) + if err != nil { + return + } + } + return buf.FinishPacket() +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go b/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go new file mode 100644 index 00000000..9b5bc689 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go @@ -0,0 +1,266 @@ +package mssql + +import ( + "fmt" + "strings" + "syscall" + "unsafe" +) + +var ( + secur32_dll = syscall.NewLazyDLL("secur32.dll") + initSecurityInterface = secur32_dll.NewProc("InitSecurityInterfaceW") + sec_fn *SecurityFunctionTable +) + +func init() { + ptr, _, _ := initSecurityInterface.Call() + sec_fn = (*SecurityFunctionTable)(unsafe.Pointer(ptr)) +} + +const ( + SEC_E_OK = 0 + SECPKG_CRED_OUTBOUND = 2 + SEC_WINNT_AUTH_IDENTITY_UNICODE = 2 + ISC_REQ_DELEGATE = 0x00000001 + ISC_REQ_REPLAY_DETECT = 0x00000004 + ISC_REQ_SEQUENCE_DETECT = 0x00000008 + ISC_REQ_CONFIDENTIALITY = 0x00000010 + ISC_REQ_CONNECTION = 0x00000800 + SECURITY_NETWORK_DREP = 0 + SEC_I_CONTINUE_NEEDED = 0x00090312 + SEC_I_COMPLETE_NEEDED = 0x00090313 + SEC_I_COMPLETE_AND_CONTINUE = 0x00090314 + SECBUFFER_VERSION = 0 + SECBUFFER_TOKEN = 2 + NTLMBUF_LEN = 12000 +) + +const ISC_REQ = ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT | + ISC_REQ_SEQUENCE_DETECT | + ISC_REQ_CONNECTION | + ISC_REQ_DELEGATE + +type SecurityFunctionTable struct { + dwVersion uint32 + EnumerateSecurityPackages uintptr + QueryCredentialsAttributes uintptr + AcquireCredentialsHandle uintptr + FreeCredentialsHandle uintptr + Reserved2 uintptr + InitializeSecurityContext uintptr + AcceptSecurityContext uintptr + CompleteAuthToken uintptr + DeleteSecurityContext uintptr + ApplyControlToken uintptr + QueryContextAttributes uintptr + ImpersonateSecurityContext uintptr + RevertSecurityContext uintptr + MakeSignature uintptr + VerifySignature uintptr + FreeContextBuffer uintptr + QuerySecurityPackageInfo uintptr + Reserved3 uintptr + Reserved4 uintptr + Reserved5 uintptr + Reserved6 uintptr + Reserved7 uintptr + Reserved8 uintptr + QuerySecurityContextToken uintptr + EncryptMessage uintptr + DecryptMessage uintptr +} + +type SEC_WINNT_AUTH_IDENTITY struct { + User *uint16 + UserLength uint32 + Domain *uint16 + DomainLength uint32 + Password *uint16 + PasswordLength uint32 + Flags uint32 +} + +type TimeStamp struct { + LowPart uint32 + HighPart int32 +} + +type SecHandle struct { + dwLower uintptr + dwUpper uintptr +} + +type SecBuffer struct { + cbBuffer uint32 + BufferType uint32 + pvBuffer *byte +} + +type SecBufferDesc struct { + ulVersion uint32 + cBuffers uint32 + pBuffers *SecBuffer +} + +type SSPIAuth struct { + Domain string + UserName string + Password string + Service string + cred SecHandle + ctxt SecHandle +} + +func getAuth(user, password, service, workstation string) (auth, bool) { + if user == "" { + return &SSPIAuth{Service: service}, true + } + if !strings.ContainsRune(user, '\\') { + return nil, false + } + domain_user := strings.SplitN(user, "\\", 2) + return &SSPIAuth{ + Domain: domain_user[0], + UserName: domain_user[1], + Password: password, + Service: service, + }, true +} + +func (auth *SSPIAuth) InitialBytes() ([]byte, error) { + var identity *SEC_WINNT_AUTH_IDENTITY + if auth.UserName != "" { + identity = &SEC_WINNT_AUTH_IDENTITY{ + Flags: SEC_WINNT_AUTH_IDENTITY_UNICODE, + Password: syscall.StringToUTF16Ptr(auth.Password), + PasswordLength: uint32(len(auth.Password)), + Domain: syscall.StringToUTF16Ptr(auth.Domain), + DomainLength: uint32(len(auth.Domain)), + User: syscall.StringToUTF16Ptr(auth.UserName), + UserLength: uint32(len(auth.UserName)), + } + } + var ts TimeStamp + sec_ok, _, _ := syscall.Syscall9(sec_fn.AcquireCredentialsHandle, + 9, + 0, + uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("Negotiate"))), + SECPKG_CRED_OUTBOUND, + 0, + uintptr(unsafe.Pointer(identity)), + 0, + 0, + uintptr(unsafe.Pointer(&auth.cred)), + uintptr(unsafe.Pointer(&ts))) + if sec_ok != SEC_E_OK { + return nil, fmt.Errorf("AcquireCredentialsHandle failed %x", sec_ok) + } + + var buf SecBuffer + var desc SecBufferDesc + desc.ulVersion = SECBUFFER_VERSION + desc.cBuffers = 1 + desc.pBuffers = &buf + + outbuf := make([]byte, NTLMBUF_LEN) + buf.cbBuffer = NTLMBUF_LEN + buf.BufferType = SECBUFFER_TOKEN + buf.pvBuffer = &outbuf[0] + + var attrs uint32 + sec_ok, _, _ = syscall.Syscall12(sec_fn.InitializeSecurityContext, + 12, + uintptr(unsafe.Pointer(&auth.cred)), + 0, + uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(auth.Service))), + ISC_REQ, + 0, + SECURITY_NETWORK_DREP, + 0, + 0, + uintptr(unsafe.Pointer(&auth.ctxt)), + uintptr(unsafe.Pointer(&desc)), + uintptr(unsafe.Pointer(&attrs)), + uintptr(unsafe.Pointer(&ts))) + if sec_ok == SEC_I_COMPLETE_AND_CONTINUE || + sec_ok == SEC_I_COMPLETE_NEEDED { + syscall.Syscall6(sec_fn.CompleteAuthToken, + 2, + uintptr(unsafe.Pointer(&auth.ctxt)), + uintptr(unsafe.Pointer(&desc)), + 0, 0, 0, 0) + } else if sec_ok != SEC_E_OK && + sec_ok != SEC_I_CONTINUE_NEEDED { + syscall.Syscall6(sec_fn.FreeCredentialsHandle, + 1, + uintptr(unsafe.Pointer(&auth.cred)), + 0, 0, 0, 0, 0) + return nil, fmt.Errorf("InitialBytes InitializeSecurityContext failed %x", sec_ok) + } + return outbuf[:buf.cbBuffer], nil +} + +func (auth *SSPIAuth) NextBytes(bytes []byte) ([]byte, error) { + var in_buf, out_buf SecBuffer + var in_desc, out_desc SecBufferDesc + + in_desc.ulVersion = SECBUFFER_VERSION + in_desc.cBuffers = 1 + in_desc.pBuffers = &in_buf + + out_desc.ulVersion = SECBUFFER_VERSION + out_desc.cBuffers = 1 + out_desc.pBuffers = &out_buf + + in_buf.BufferType = SECBUFFER_TOKEN + in_buf.pvBuffer = &bytes[0] + in_buf.cbBuffer = uint32(len(bytes)) + + outbuf := make([]byte, NTLMBUF_LEN) + out_buf.BufferType = SECBUFFER_TOKEN + out_buf.pvBuffer = &outbuf[0] + out_buf.cbBuffer = NTLMBUF_LEN + + var attrs uint32 + var ts TimeStamp + sec_ok, _, _ := syscall.Syscall12(sec_fn.InitializeSecurityContext, + 12, + uintptr(unsafe.Pointer(&auth.cred)), + uintptr(unsafe.Pointer(&auth.ctxt)), + uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(auth.Service))), + ISC_REQ, + 0, + SECURITY_NETWORK_DREP, + uintptr(unsafe.Pointer(&in_desc)), + 0, + uintptr(unsafe.Pointer(&auth.ctxt)), + uintptr(unsafe.Pointer(&out_desc)), + uintptr(unsafe.Pointer(&attrs)), + uintptr(unsafe.Pointer(&ts))) + if sec_ok == SEC_I_COMPLETE_AND_CONTINUE || + sec_ok == SEC_I_COMPLETE_NEEDED { + syscall.Syscall6(sec_fn.CompleteAuthToken, + 2, + uintptr(unsafe.Pointer(&auth.ctxt)), + uintptr(unsafe.Pointer(&out_desc)), + 0, 0, 0, 0) + } else if sec_ok != SEC_E_OK && + sec_ok != SEC_I_CONTINUE_NEEDED { + return nil, fmt.Errorf("NextBytes InitializeSecurityContext failed %x", sec_ok) + } + + return outbuf[:out_buf.cbBuffer], nil +} + +func (auth *SSPIAuth) Free() { + syscall.Syscall6(sec_fn.DeleteSecurityContext, + 1, + uintptr(unsafe.Pointer(&auth.ctxt)), + 0, 0, 0, 0, 0) + syscall.Syscall6(sec_fn.FreeCredentialsHandle, + 1, + uintptr(unsafe.Pointer(&auth.cred)), + 0, 0, 0, 0, 0) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/tds.go b/vendor/github.com/denisenkom/go-mssqldb/tds.go new file mode 100644 index 00000000..16d9ca82 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/tds.go @@ -0,0 +1,1367 @@ +package mssql + +import ( + "context" + "crypto/tls" + "crypto/x509" + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + "net" + "net/url" + "os" + "sort" + "strconv" + "strings" + "time" + "unicode" + "unicode/utf16" + "unicode/utf8" +) + +func parseInstances(msg []byte) map[string]map[string]string { + results := map[string]map[string]string{} + if len(msg) > 3 && msg[0] == 5 { + out_s := string(msg[3:]) + tokens := strings.Split(out_s, ";") + instdict := map[string]string{} + got_name := false + var name string + for _, token := range tokens { + if got_name { + instdict[name] = token + got_name = false + } else { + name = token + if len(name) == 0 { + if len(instdict) == 0 { + break + } + results[strings.ToUpper(instdict["InstanceName"])] = instdict + instdict = map[string]string{} + continue + } + got_name = true + } + } + } + return results +} + +func getInstances(ctx context.Context, d Dialer, address string) (map[string]map[string]string, error) { + maxTime := 5 * time.Second + ctx, cancel := context.WithTimeout(ctx, maxTime) + defer cancel() + conn, err := d.DialContext(ctx, "udp", address+":1434") + if err != nil { + return nil, err + } + defer conn.Close() + conn.SetDeadline(time.Now().Add(maxTime)) + _, err = conn.Write([]byte{3}) + if err != nil { + return nil, err + } + var resp = make([]byte, 16*1024-1) + read, err := conn.Read(resp) + if err != nil { + return nil, err + } + return parseInstances(resp[:read]), nil +} + +// tds versions +const ( + verTDS70 = 0x70000000 + verTDS71 = 0x71000000 + verTDS71rev1 = 0x71000001 + verTDS72 = 0x72090002 + verTDS73A = 0x730A0003 + verTDS73 = verTDS73A + verTDS73B = 0x730B0003 + verTDS74 = 0x74000004 +) + +// packet types +// https://msdn.microsoft.com/en-us/library/dd304214.aspx +const ( + packSQLBatch packetType = 1 + packRPCRequest = 3 + packReply = 4 + + // 2.2.1.7 Attention: https://msdn.microsoft.com/en-us/library/dd341449.aspx + // 4.19.2 Out-of-Band Attention Signal: https://msdn.microsoft.com/en-us/library/dd305167.aspx + packAttention = 6 + + packBulkLoadBCP = 7 + packTransMgrReq = 14 + packNormal = 15 + packLogin7 = 16 + packSSPIMessage = 17 + packPrelogin = 18 +) + +// prelogin fields +// http://msdn.microsoft.com/en-us/library/dd357559.aspx +const ( + preloginVERSION = 0 + preloginENCRYPTION = 1 + preloginINSTOPT = 2 + preloginTHREADID = 3 + preloginMARS = 4 + preloginTRACEID = 5 + preloginTERMINATOR = 0xff +) + +const ( + encryptOff = 0 // Encryption is available but off. + encryptOn = 1 // Encryption is available and on. + encryptNotSup = 2 // Encryption is not available. + encryptReq = 3 // Encryption is required. +) + +type tdsSession struct { + buf *tdsBuffer + loginAck loginAckStruct + database string + partner string + columns []columnStruct + tranid uint64 + logFlags uint64 + log optionalLogger + routedServer string + routedPort uint16 +} + +const ( + logErrors = 1 + logMessages = 2 + logRows = 4 + logSQL = 8 + logParams = 16 + logTransaction = 32 + logDebug = 64 +) + +type columnStruct struct { + UserType uint32 + Flags uint16 + ColName string + ti typeInfo +} + +type keySlice []uint8 + +func (p keySlice) Len() int { return len(p) } +func (p keySlice) Less(i, j int) bool { return p[i] < p[j] } +func (p keySlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + +// http://msdn.microsoft.com/en-us/library/dd357559.aspx +func writePrelogin(w *tdsBuffer, fields map[uint8][]byte) error { + var err error + + w.BeginPacket(packPrelogin, false) + offset := uint16(5*len(fields) + 1) + keys := make(keySlice, 0, len(fields)) + for k, _ := range fields { + keys = append(keys, k) + } + sort.Sort(keys) + // writing header + for _, k := range keys { + err = w.WriteByte(k) + if err != nil { + return err + } + err = binary.Write(w, binary.BigEndian, offset) + if err != nil { + return err + } + v := fields[k] + size := uint16(len(v)) + err = binary.Write(w, binary.BigEndian, size) + if err != nil { + return err + } + offset += size + } + err = w.WriteByte(preloginTERMINATOR) + if err != nil { + return err + } + // writing values + for _, k := range keys { + v := fields[k] + written, err := w.Write(v) + if err != nil { + return err + } + if written != len(v) { + return errors.New("Write method didn't write the whole value") + } + } + return w.FinishPacket() +} + +func readPrelogin(r *tdsBuffer) (map[uint8][]byte, error) { + packet_type, err := r.BeginRead() + if err != nil { + return nil, err + } + struct_buf, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + if packet_type != 4 { + return nil, errors.New("Invalid respones, expected packet type 4, PRELOGIN RESPONSE") + } + offset := 0 + results := map[uint8][]byte{} + for true { + rec_type := struct_buf[offset] + if rec_type == preloginTERMINATOR { + break + } + + rec_offset := binary.BigEndian.Uint16(struct_buf[offset+1:]) + rec_len := binary.BigEndian.Uint16(struct_buf[offset+3:]) + value := struct_buf[rec_offset : rec_offset+rec_len] + results[rec_type] = value + offset += 5 + } + return results, nil +} + +// OptionFlags2 +// http://msdn.microsoft.com/en-us/library/dd304019.aspx +const ( + fLanguageFatal = 1 + fODBC = 2 + fTransBoundary = 4 + fCacheConnect = 8 + fIntSecurity = 0x80 +) + +// TypeFlags +const ( + // 4 bits for fSQLType + // 1 bit for fOLEDB + fReadOnlyIntent = 32 +) + +type login struct { + TDSVersion uint32 + PacketSize uint32 + ClientProgVer uint32 + ClientPID uint32 + ConnectionID uint32 + OptionFlags1 uint8 + OptionFlags2 uint8 + TypeFlags uint8 + OptionFlags3 uint8 + ClientTimeZone int32 + ClientLCID uint32 + HostName string + UserName string + Password string + AppName string + ServerName string + CtlIntName string + Language string + Database string + ClientID [6]byte + SSPI []byte + AtchDBFile string + ChangePassword string +} + +type loginHeader struct { + Length uint32 + TDSVersion uint32 + PacketSize uint32 + ClientProgVer uint32 + ClientPID uint32 + ConnectionID uint32 + OptionFlags1 uint8 + OptionFlags2 uint8 + TypeFlags uint8 + OptionFlags3 uint8 + ClientTimeZone int32 + ClientLCID uint32 + HostNameOffset uint16 + HostNameLength uint16 + UserNameOffset uint16 + UserNameLength uint16 + PasswordOffset uint16 + PasswordLength uint16 + AppNameOffset uint16 + AppNameLength uint16 + ServerNameOffset uint16 + ServerNameLength uint16 + ExtensionOffset uint16 + ExtensionLenght uint16 + CtlIntNameOffset uint16 + CtlIntNameLength uint16 + LanguageOffset uint16 + LanguageLength uint16 + DatabaseOffset uint16 + DatabaseLength uint16 + ClientID [6]byte + SSPIOffset uint16 + SSPILength uint16 + AtchDBFileOffset uint16 + AtchDBFileLength uint16 + ChangePasswordOffset uint16 + ChangePasswordLength uint16 + SSPILongLength uint32 +} + +// convert Go string to UTF-16 encoded []byte (littleEndian) +// done manually rather than using bytes and binary packages +// for performance reasons +func str2ucs2(s string) []byte { + res := utf16.Encode([]rune(s)) + ucs2 := make([]byte, 2*len(res)) + for i := 0; i < len(res); i++ { + ucs2[2*i] = byte(res[i]) + ucs2[2*i+1] = byte(res[i] >> 8) + } + return ucs2 +} + +func ucs22str(s []byte) (string, error) { + if len(s)%2 != 0 { + return "", fmt.Errorf("Illegal UCS2 string length: %d", len(s)) + } + buf := make([]uint16, len(s)/2) + for i := 0; i < len(s); i += 2 { + buf[i/2] = binary.LittleEndian.Uint16(s[i:]) + } + return string(utf16.Decode(buf)), nil +} + +func manglePassword(password string) []byte { + var ucs2password []byte = str2ucs2(password) + for i, ch := range ucs2password { + ucs2password[i] = ((ch<<4)&0xff | (ch >> 4)) ^ 0xA5 + } + return ucs2password +} + +// http://msdn.microsoft.com/en-us/library/dd304019.aspx +func sendLogin(w *tdsBuffer, login login) error { + w.BeginPacket(packLogin7, false) + hostname := str2ucs2(login.HostName) + username := str2ucs2(login.UserName) + password := manglePassword(login.Password) + appname := str2ucs2(login.AppName) + servername := str2ucs2(login.ServerName) + ctlintname := str2ucs2(login.CtlIntName) + language := str2ucs2(login.Language) + database := str2ucs2(login.Database) + atchdbfile := str2ucs2(login.AtchDBFile) + changepassword := str2ucs2(login.ChangePassword) + hdr := loginHeader{ + TDSVersion: login.TDSVersion, + PacketSize: login.PacketSize, + ClientProgVer: login.ClientProgVer, + ClientPID: login.ClientPID, + ConnectionID: login.ConnectionID, + OptionFlags1: login.OptionFlags1, + OptionFlags2: login.OptionFlags2, + TypeFlags: login.TypeFlags, + OptionFlags3: login.OptionFlags3, + ClientTimeZone: login.ClientTimeZone, + ClientLCID: login.ClientLCID, + HostNameLength: uint16(utf8.RuneCountInString(login.HostName)), + UserNameLength: uint16(utf8.RuneCountInString(login.UserName)), + PasswordLength: uint16(utf8.RuneCountInString(login.Password)), + AppNameLength: uint16(utf8.RuneCountInString(login.AppName)), + ServerNameLength: uint16(utf8.RuneCountInString(login.ServerName)), + CtlIntNameLength: uint16(utf8.RuneCountInString(login.CtlIntName)), + LanguageLength: uint16(utf8.RuneCountInString(login.Language)), + DatabaseLength: uint16(utf8.RuneCountInString(login.Database)), + ClientID: login.ClientID, + SSPILength: uint16(len(login.SSPI)), + AtchDBFileLength: uint16(utf8.RuneCountInString(login.AtchDBFile)), + ChangePasswordLength: uint16(utf8.RuneCountInString(login.ChangePassword)), + } + offset := uint16(binary.Size(hdr)) + hdr.HostNameOffset = offset + offset += uint16(len(hostname)) + hdr.UserNameOffset = offset + offset += uint16(len(username)) + hdr.PasswordOffset = offset + offset += uint16(len(password)) + hdr.AppNameOffset = offset + offset += uint16(len(appname)) + hdr.ServerNameOffset = offset + offset += uint16(len(servername)) + hdr.CtlIntNameOffset = offset + offset += uint16(len(ctlintname)) + hdr.LanguageOffset = offset + offset += uint16(len(language)) + hdr.DatabaseOffset = offset + offset += uint16(len(database)) + hdr.SSPIOffset = offset + offset += uint16(len(login.SSPI)) + hdr.AtchDBFileOffset = offset + offset += uint16(len(atchdbfile)) + hdr.ChangePasswordOffset = offset + offset += uint16(len(changepassword)) + hdr.Length = uint32(offset) + var err error + err = binary.Write(w, binary.LittleEndian, &hdr) + if err != nil { + return err + } + _, err = w.Write(hostname) + if err != nil { + return err + } + _, err = w.Write(username) + if err != nil { + return err + } + _, err = w.Write(password) + if err != nil { + return err + } + _, err = w.Write(appname) + if err != nil { + return err + } + _, err = w.Write(servername) + if err != nil { + return err + } + _, err = w.Write(ctlintname) + if err != nil { + return err + } + _, err = w.Write(language) + if err != nil { + return err + } + _, err = w.Write(database) + if err != nil { + return err + } + _, err = w.Write(login.SSPI) + if err != nil { + return err + } + _, err = w.Write(atchdbfile) + if err != nil { + return err + } + _, err = w.Write(changepassword) + if err != nil { + return err + } + return w.FinishPacket() +} + +func readUcs2(r io.Reader, numchars int) (res string, err error) { + buf := make([]byte, numchars*2) + _, err = io.ReadFull(r, buf) + if err != nil { + return "", err + } + return ucs22str(buf) +} + +func readUsVarChar(r io.Reader) (res string, err error) { + var numchars uint16 + err = binary.Read(r, binary.LittleEndian, &numchars) + if err != nil { + return "", err + } + return readUcs2(r, int(numchars)) +} + +func writeUsVarChar(w io.Writer, s string) (err error) { + buf := str2ucs2(s) + var numchars int = len(buf) / 2 + if numchars > 0xffff { + panic("invalid size for US_VARCHAR") + } + err = binary.Write(w, binary.LittleEndian, uint16(numchars)) + if err != nil { + return + } + _, err = w.Write(buf) + return +} + +func readBVarChar(r io.Reader) (res string, err error) { + var numchars uint8 + err = binary.Read(r, binary.LittleEndian, &numchars) + if err != nil { + return "", err + } + + // A zero length could be returned, return an empty string + if numchars == 0 { + return "", nil + } + return readUcs2(r, int(numchars)) +} + +func writeBVarChar(w io.Writer, s string) (err error) { + buf := str2ucs2(s) + var numchars int = len(buf) / 2 + if numchars > 0xff { + panic("invalid size for B_VARCHAR") + } + err = binary.Write(w, binary.LittleEndian, uint8(numchars)) + if err != nil { + return + } + _, err = w.Write(buf) + return +} + +func readBVarByte(r io.Reader) (res []byte, err error) { + var length uint8 + err = binary.Read(r, binary.LittleEndian, &length) + if err != nil { + return + } + res = make([]byte, length) + _, err = io.ReadFull(r, res) + return +} + +func readUshort(r io.Reader) (res uint16, err error) { + err = binary.Read(r, binary.LittleEndian, &res) + return +} + +func readByte(r io.Reader) (res byte, err error) { + var b [1]byte + _, err = r.Read(b[:]) + res = b[0] + return +} + +// Packet Data Stream Headers +// http://msdn.microsoft.com/en-us/library/dd304953.aspx +type headerStruct struct { + hdrtype uint16 + data []byte +} + +const ( + dataStmHdrQueryNotif = 1 // query notifications + dataStmHdrTransDescr = 2 // MARS transaction descriptor (required) + dataStmHdrTraceActivity = 3 +) + +// Query Notifications Header +// http://msdn.microsoft.com/en-us/library/dd304949.aspx +type queryNotifHdr struct { + notifyId string + ssbDeployment string + notifyTimeout uint32 +} + +func (hdr queryNotifHdr) pack() (res []byte) { + notifyId := str2ucs2(hdr.notifyId) + ssbDeployment := str2ucs2(hdr.ssbDeployment) + + res = make([]byte, 2+len(notifyId)+2+len(ssbDeployment)+4) + b := res + + binary.LittleEndian.PutUint16(b, uint16(len(notifyId))) + b = b[2:] + copy(b, notifyId) + b = b[len(notifyId):] + + binary.LittleEndian.PutUint16(b, uint16(len(ssbDeployment))) + b = b[2:] + copy(b, ssbDeployment) + b = b[len(ssbDeployment):] + + binary.LittleEndian.PutUint32(b, hdr.notifyTimeout) + + return res +} + +// MARS Transaction Descriptor Header +// http://msdn.microsoft.com/en-us/library/dd340515.aspx +type transDescrHdr struct { + transDescr uint64 // transaction descriptor returned from ENVCHANGE + outstandingReqCnt uint32 // outstanding request count +} + +func (hdr transDescrHdr) pack() (res []byte) { + res = make([]byte, 8+4) + binary.LittleEndian.PutUint64(res, hdr.transDescr) + binary.LittleEndian.PutUint32(res[8:], hdr.outstandingReqCnt) + return res +} + +func writeAllHeaders(w io.Writer, headers []headerStruct) (err error) { + // Calculating total length. + var totallen uint32 = 4 + for _, hdr := range headers { + totallen += 4 + 2 + uint32(len(hdr.data)) + } + // writing + err = binary.Write(w, binary.LittleEndian, totallen) + if err != nil { + return err + } + for _, hdr := range headers { + var headerlen uint32 = 4 + 2 + uint32(len(hdr.data)) + err = binary.Write(w, binary.LittleEndian, headerlen) + if err != nil { + return err + } + err = binary.Write(w, binary.LittleEndian, hdr.hdrtype) + if err != nil { + return err + } + _, err = w.Write(hdr.data) + if err != nil { + return err + } + } + return nil +} + +func sendSqlBatch72(buf *tdsBuffer, sqltext string, headers []headerStruct, resetSession bool) (err error) { + buf.BeginPacket(packSQLBatch, resetSession) + + if err = writeAllHeaders(buf, headers); err != nil { + return + } + + _, err = buf.Write(str2ucs2(sqltext)) + if err != nil { + return + } + return buf.FinishPacket() +} + +// 2.2.1.7 Attention: https://msdn.microsoft.com/en-us/library/dd341449.aspx +// 4.19.2 Out-of-Band Attention Signal: https://msdn.microsoft.com/en-us/library/dd305167.aspx +func sendAttention(buf *tdsBuffer) error { + buf.BeginPacket(packAttention, false) + return buf.FinishPacket() +} + +type connectParams struct { + logFlags uint64 + port uint64 + host string + instance string + database string + user string + password string + dial_timeout time.Duration + conn_timeout time.Duration + keepAlive time.Duration + encrypt bool + disableEncryption bool + trustServerCertificate bool + certificate string + hostInCertificate string + serverSPN string + workstation string + appname string + typeFlags uint8 + failOverPartner string + failOverPort uint64 + packetSize uint16 +} + +func splitConnectionString(dsn string) (res map[string]string) { + res = map[string]string{} + parts := strings.Split(dsn, ";") + for _, part := range parts { + if len(part) == 0 { + continue + } + lst := strings.SplitN(part, "=", 2) + name := strings.TrimSpace(strings.ToLower(lst[0])) + if len(name) == 0 { + continue + } + var value string = "" + if len(lst) > 1 { + value = strings.TrimSpace(lst[1]) + } + res[name] = value + } + return res +} + +// Splits a URL in the ODBC format +func splitConnectionStringOdbc(dsn string) (map[string]string, error) { + res := map[string]string{} + + type parserState int + const ( + // Before the start of a key + parserStateBeforeKey parserState = iota + + // Inside a key + parserStateKey + + // Beginning of a value. May be bare or braced + parserStateBeginValue + + // Inside a bare value + parserStateBareValue + + // Inside a braced value + parserStateBracedValue + + // A closing brace inside a braced value. + // May be the end of the value or an escaped closing brace, depending on the next character + parserStateBracedValueClosingBrace + + // After a value. Next character should be a semicolon or whitespace. + parserStateEndValue + ) + + var state = parserStateBeforeKey + + var key string + var value string + + for i, c := range dsn { + switch state { + case parserStateBeforeKey: + switch { + case c == '=': + return res, fmt.Errorf("Unexpected character = at index %d. Expected start of key or semi-colon or whitespace.", i) + case !unicode.IsSpace(c) && c != ';': + state = parserStateKey + key += string(c) + } + + case parserStateKey: + switch c { + case '=': + key = normalizeOdbcKey(key) + if len(key) == 0 { + return res, fmt.Errorf("Unexpected end of key at index %d.", i) + } + + state = parserStateBeginValue + + case ';': + // Key without value + key = normalizeOdbcKey(key) + if len(key) == 0 { + return res, fmt.Errorf("Unexpected end of key at index %d.", i) + } + + res[key] = value + key = "" + value = "" + state = parserStateBeforeKey + + default: + key += string(c) + } + + case parserStateBeginValue: + switch { + case c == '{': + state = parserStateBracedValue + case c == ';': + // Empty value + res[key] = value + key = "" + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + state = parserStateBareValue + value += string(c) + } + + case parserStateBareValue: + if c == ';' { + res[key] = strings.TrimRightFunc(value, unicode.IsSpace) + key = "" + value = "" + state = parserStateBeforeKey + } else { + value += string(c) + } + + case parserStateBracedValue: + if c == '}' { + state = parserStateBracedValueClosingBrace + } else { + value += string(c) + } + + case parserStateBracedValueClosingBrace: + if c == '}' { + // Escaped closing brace + value += string(c) + state = parserStateBracedValue + continue + } + + // End of braced value + res[key] = value + key = "" + value = "" + + // This character is the first character past the end, + // so it needs to be parsed like the parserStateEndValue state. + state = parserStateEndValue + switch { + case c == ';': + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) + } + + case parserStateEndValue: + switch { + case c == ';': + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) + } + } + } + + switch state { + case parserStateBeforeKey: // Okay + case parserStateKey: // Unfinished key. Treat as key without value. + key = normalizeOdbcKey(key) + if len(key) == 0 { + return res, fmt.Errorf("Unexpected end of key at index %d.", len(dsn)) + } + res[key] = value + case parserStateBeginValue: // Empty value + res[key] = value + case parserStateBareValue: + res[key] = strings.TrimRightFunc(value, unicode.IsSpace) + case parserStateBracedValue: + return res, fmt.Errorf("Unexpected end of braced value at index %d.", len(dsn)) + case parserStateBracedValueClosingBrace: // End of braced value + res[key] = value + case parserStateEndValue: // Okay + } + + return res, nil +} + +// Normalizes the given string as an ODBC-format key +func normalizeOdbcKey(s string) string { + return strings.ToLower(strings.TrimRightFunc(s, unicode.IsSpace)) +} + +// Splits a URL of the form sqlserver://username:password@host/instance?param1=value¶m2=value +func splitConnectionStringURL(dsn string) (map[string]string, error) { + res := map[string]string{} + + u, err := url.Parse(dsn) + if err != nil { + return res, err + } + + if u.Scheme != "sqlserver" { + return res, fmt.Errorf("scheme %s is not recognized", u.Scheme) + } + + if u.User != nil { + res["user id"] = u.User.Username() + p, exists := u.User.Password() + if exists { + res["password"] = p + } + } + + host, port, err := net.SplitHostPort(u.Host) + if err != nil { + host = u.Host + } + + if len(u.Path) > 0 { + res["server"] = host + "\\" + u.Path[1:] + } else { + res["server"] = host + } + + if len(port) > 0 { + res["port"] = port + } + + query := u.Query() + for k, v := range query { + if len(v) > 1 { + return res, fmt.Errorf("key %s provided more than once", k) + } + res[strings.ToLower(k)] = v[0] + } + + return res, nil +} + +func parseConnectParams(dsn string) (connectParams, error) { + var p connectParams + + var params map[string]string + if strings.HasPrefix(dsn, "odbc:") { + parameters, err := splitConnectionStringOdbc(dsn[len("odbc:"):]) + if err != nil { + return p, err + } + params = parameters + } else if strings.HasPrefix(dsn, "sqlserver://") { + parameters, err := splitConnectionStringURL(dsn) + if err != nil { + return p, err + } + params = parameters + } else { + params = splitConnectionString(dsn) + } + + strlog, ok := params["log"] + if ok { + var err error + p.logFlags, err = strconv.ParseUint(strlog, 10, 64) + if err != nil { + return p, fmt.Errorf("Invalid log parameter '%s': %s", strlog, err.Error()) + } + } + server := params["server"] + parts := strings.SplitN(server, `\`, 2) + p.host = parts[0] + if p.host == "." || strings.ToUpper(p.host) == "(LOCAL)" || p.host == "" { + p.host = "localhost" + } + if len(parts) > 1 { + p.instance = parts[1] + } + p.database = params["database"] + p.user = params["user id"] + p.password = params["password"] + + p.port = 1433 + strport, ok := params["port"] + if ok { + var err error + p.port, err = strconv.ParseUint(strport, 10, 16) + if err != nil { + f := "Invalid tcp port '%v': %v" + return p, fmt.Errorf(f, strport, err.Error()) + } + } + + // https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-network-packet-size-server-configuration-option + // Default packet size remains at 4096 bytes + p.packetSize = 4096 + strpsize, ok := params["packet size"] + if ok { + var err error + psize, err := strconv.ParseUint(strpsize, 0, 16) + if err != nil { + f := "Invalid packet size '%v': %v" + return p, fmt.Errorf(f, strpsize, err.Error()) + } + + // Ensure packet size falls within the TDS protocol range of 512 to 32767 bytes + // NOTE: Encrypted connections have a maximum size of 16383 bytes. If you request + // a higher packet size, the server will respond with an ENVCHANGE request to + // alter the packet size to 16383 bytes. + p.packetSize = uint16(psize) + if p.packetSize < 512 { + p.packetSize = 512 + } else if p.packetSize > 32767 { + p.packetSize = 32767 + } + } + + // https://msdn.microsoft.com/en-us/library/dd341108.aspx + // + // Do not set a connection timeout. Use Context to manage such things. + // Default to zero, but still allow it to be set. + if strconntimeout, ok := params["connection timeout"]; ok { + timeout, err := strconv.ParseUint(strconntimeout, 10, 64) + if err != nil { + f := "Invalid connection timeout '%v': %v" + return p, fmt.Errorf(f, strconntimeout, err.Error()) + } + p.conn_timeout = time.Duration(timeout) * time.Second + } + p.dial_timeout = 15 * time.Second + if strdialtimeout, ok := params["dial timeout"]; ok { + timeout, err := strconv.ParseUint(strdialtimeout, 10, 64) + if err != nil { + f := "Invalid dial timeout '%v': %v" + return p, fmt.Errorf(f, strdialtimeout, err.Error()) + } + p.dial_timeout = time.Duration(timeout) * time.Second + } + + // default keep alive should be 30 seconds according to spec: + // https://msdn.microsoft.com/en-us/library/dd341108.aspx + p.keepAlive = 30 * time.Second + if keepAlive, ok := params["keepalive"]; ok { + timeout, err := strconv.ParseUint(keepAlive, 10, 64) + if err != nil { + f := "Invalid keepAlive value '%s': %s" + return p, fmt.Errorf(f, keepAlive, err.Error()) + } + p.keepAlive = time.Duration(timeout) * time.Second + } + encrypt, ok := params["encrypt"] + if ok { + if strings.EqualFold(encrypt, "DISABLE") { + p.disableEncryption = true + } else { + var err error + p.encrypt, err = strconv.ParseBool(encrypt) + if err != nil { + f := "Invalid encrypt '%s': %s" + return p, fmt.Errorf(f, encrypt, err.Error()) + } + } + } else { + p.trustServerCertificate = true + } + trust, ok := params["trustservercertificate"] + if ok { + var err error + p.trustServerCertificate, err = strconv.ParseBool(trust) + if err != nil { + f := "Invalid trust server certificate '%s': %s" + return p, fmt.Errorf(f, trust, err.Error()) + } + } + p.certificate = params["certificate"] + p.hostInCertificate, ok = params["hostnameincertificate"] + if !ok { + p.hostInCertificate = p.host + } + + serverSPN, ok := params["serverspn"] + if ok { + p.serverSPN = serverSPN + } else { + p.serverSPN = fmt.Sprintf("MSSQLSvc/%s:%d", p.host, p.port) + } + + workstation, ok := params["workstation id"] + if ok { + p.workstation = workstation + } else { + workstation, err := os.Hostname() + if err == nil { + p.workstation = workstation + } + } + + appname, ok := params["app name"] + if !ok { + appname = "go-mssqldb" + } + p.appname = appname + + appintent, ok := params["applicationintent"] + if ok { + if appintent == "ReadOnly" { + p.typeFlags |= fReadOnlyIntent + } + } + + failOverPartner, ok := params["failoverpartner"] + if ok { + p.failOverPartner = failOverPartner + } + + failOverPort, ok := params["failoverport"] + if ok { + var err error + p.failOverPort, err = strconv.ParseUint(failOverPort, 0, 16) + if err != nil { + f := "Invalid tcp port '%v': %v" + return p, fmt.Errorf(f, failOverPort, err.Error()) + } + } + + return p, nil +} + +type auth interface { + InitialBytes() ([]byte, error) + NextBytes([]byte) ([]byte, error) + Free() +} + +// SQL Server AlwaysOn Availability Group Listeners are bound by DNS to a +// list of IP addresses. So if there is more than one, try them all and +// use the first one that allows a connection. +func dialConnection(ctx context.Context, c *Connector, p connectParams) (conn net.Conn, err error) { + var ips []net.IP + ips, err = net.LookupIP(p.host) + if err != nil { + ip := net.ParseIP(p.host) + if ip == nil { + return nil, err + } + ips = []net.IP{ip} + } + if len(ips) == 1 { + d := c.getDialer(&p) + addr := net.JoinHostPort(ips[0].String(), strconv.Itoa(int(p.port))) + conn, err = d.DialContext(ctx, "tcp", addr) + + } else { + //Try Dials in parallel to avoid waiting for timeouts. + connChan := make(chan net.Conn, len(ips)) + errChan := make(chan error, len(ips)) + portStr := strconv.Itoa(int(p.port)) + for _, ip := range ips { + go func(ip net.IP) { + d := c.getDialer(&p) + addr := net.JoinHostPort(ip.String(), portStr) + conn, err := d.DialContext(ctx, "tcp", addr) + if err == nil { + connChan <- conn + } else { + errChan <- err + } + }(ip) + } + // Wait for either the *first* successful connection, or all the errors + wait_loop: + for i, _ := range ips { + select { + case conn = <-connChan: + // Got a connection to use, close any others + go func(n int) { + for i := 0; i < n; i++ { + select { + case conn := <-connChan: + conn.Close() + case <-errChan: + } + } + }(len(ips) - i - 1) + // Remove any earlier errors we may have collected + err = nil + break wait_loop + case err = <-errChan: + } + } + } + // Can't do the usual err != nil check, as it is possible to have gotten an error before a successful connection + if conn == nil { + f := "Unable to open tcp connection with host '%v:%v': %v" + return nil, fmt.Errorf(f, p.host, p.port, err.Error()) + } + return conn, err +} + +func connect(ctx context.Context, c *Connector, log optionalLogger, p connectParams) (res *tdsSession, err error) { + dialCtx := ctx + if p.dial_timeout > 0 { + var cancel func() + dialCtx, cancel = context.WithTimeout(ctx, p.dial_timeout) + defer cancel() + } + // if instance is specified use instance resolution service + if p.instance != "" { + p.instance = strings.ToUpper(p.instance) + d := c.getDialer(&p) + instances, err := getInstances(dialCtx, d, p.host) + if err != nil { + f := "Unable to get instances from Sql Server Browser on host %v: %v" + return nil, fmt.Errorf(f, p.host, err.Error()) + } + strport, ok := instances[p.instance]["tcp"] + if !ok { + f := "No instance matching '%v' returned from host '%v'" + return nil, fmt.Errorf(f, p.instance, p.host) + } + p.port, err = strconv.ParseUint(strport, 0, 16) + if err != nil { + f := "Invalid tcp port returned from Sql Server Browser '%v': %v" + return nil, fmt.Errorf(f, strport, err.Error()) + } + } + +initiate_connection: + conn, err := dialConnection(dialCtx, c, p) + if err != nil { + return nil, err + } + + toconn := newTimeoutConn(conn, p.conn_timeout) + + outbuf := newTdsBuffer(p.packetSize, toconn) + sess := tdsSession{ + buf: outbuf, + log: log, + logFlags: p.logFlags, + } + + instance_buf := []byte(p.instance) + instance_buf = append(instance_buf, 0) // zero terminate instance name + var encrypt byte + if p.disableEncryption { + encrypt = encryptNotSup + } else if p.encrypt { + encrypt = encryptOn + } else { + encrypt = encryptOff + } + fields := map[uint8][]byte{ + preloginVERSION: {0, 0, 0, 0, 0, 0}, + preloginENCRYPTION: {encrypt}, + preloginINSTOPT: instance_buf, + preloginTHREADID: {0, 0, 0, 0}, + preloginMARS: {0}, // MARS disabled + } + + err = writePrelogin(outbuf, fields) + if err != nil { + return nil, err + } + + fields, err = readPrelogin(outbuf) + if err != nil { + return nil, err + } + + encryptBytes, ok := fields[preloginENCRYPTION] + if !ok { + return nil, fmt.Errorf("Encrypt negotiation failed") + } + encrypt = encryptBytes[0] + if p.encrypt && (encrypt == encryptNotSup || encrypt == encryptOff) { + return nil, fmt.Errorf("Server does not support encryption") + } + + if encrypt != encryptNotSup { + var config tls.Config + if p.certificate != "" { + pem, err := ioutil.ReadFile(p.certificate) + if err != nil { + return nil, fmt.Errorf("Cannot read certificate %q: %v", p.certificate, err) + } + certs := x509.NewCertPool() + certs.AppendCertsFromPEM(pem) + config.RootCAs = certs + } + if p.trustServerCertificate { + config.InsecureSkipVerify = true + } + config.ServerName = p.hostInCertificate + // fix for https://github.com/denisenkom/go-mssqldb/issues/166 + // Go implementation of TLS payload size heuristic algorithm splits single TDS package to multiple TCP segments, + // while SQL Server seems to expect one TCP segment per encrypted TDS package. + // Setting DynamicRecordSizingDisabled to true disables that algorithm and uses 16384 bytes per TLS package + config.DynamicRecordSizingDisabled = true + outbuf.transport = conn + toconn.buf = outbuf + tlsConn := tls.Client(toconn, &config) + err = tlsConn.Handshake() + + toconn.buf = nil + outbuf.transport = tlsConn + if err != nil { + return nil, fmt.Errorf("TLS Handshake failed: %v", err) + } + if encrypt == encryptOff { + outbuf.afterFirst = func() { + outbuf.transport = toconn + } + } + } + + login := login{ + TDSVersion: verTDS74, + PacketSize: uint32(outbuf.PackageSize()), + Database: p.database, + OptionFlags2: fODBC, // to get unlimited TEXTSIZE + HostName: p.workstation, + ServerName: p.host, + AppName: p.appname, + TypeFlags: p.typeFlags, + } + auth, auth_ok := getAuth(p.user, p.password, p.serverSPN, p.workstation) + if auth_ok { + login.SSPI, err = auth.InitialBytes() + if err != nil { + return nil, err + } + login.OptionFlags2 |= fIntSecurity + defer auth.Free() + } else { + login.UserName = p.user + login.Password = p.password + } + err = sendLogin(outbuf, login) + if err != nil { + return nil, err + } + + // processing login response + var sspi_msg []byte +continue_login: + tokchan := make(chan tokenStruct, 5) + go processResponse(context.Background(), &sess, tokchan, nil) + success := false + for tok := range tokchan { + switch token := tok.(type) { + case sspiMsg: + sspi_msg, err = auth.NextBytes(token) + if err != nil { + return nil, err + } + case loginAckStruct: + success = true + sess.loginAck = token + case error: + return nil, fmt.Errorf("Login error: %s", token.Error()) + case doneStruct: + if token.isError() { + return nil, fmt.Errorf("Login error: %s", token.getError()) + } + } + } + if sspi_msg != nil { + outbuf.BeginPacket(packSSPIMessage, false) + _, err = outbuf.Write(sspi_msg) + if err != nil { + return nil, err + } + err = outbuf.FinishPacket() + if err != nil { + return nil, err + } + sspi_msg = nil + goto continue_login + } + if !success { + return nil, fmt.Errorf("Login failed") + } + if sess.routedServer != "" { + toconn.Close() + p.host = sess.routedServer + p.port = uint64(sess.routedPort) + goto initiate_connection + } + return &sess, nil +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/tds_test.go b/vendor/github.com/denisenkom/go-mssqldb/tds_test.go new file mode 100644 index 00000000..eeb3dfd6 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/tds_test.go @@ -0,0 +1,522 @@ +package mssql + +import ( + "bytes" + "context" + "database/sql" + "encoding/hex" + "fmt" + "net/url" + "os" + "testing" + "time" +) + +type MockTransport struct { + bytes.Buffer +} + +func (t *MockTransport) Close() error { + return nil +} + +func TestSendLogin(t *testing.T) { + memBuf := new(MockTransport) + buf := newTdsBuffer(1024, memBuf) + login := login{ + TDSVersion: verTDS73, + PacketSize: 0x1000, + ClientProgVer: 0x01060100, + ClientPID: 100, + ClientTimeZone: -4 * 60, + ClientID: [6]byte{0x12, 0x34, 0x56, 0x78, 0x90, 0xab}, + OptionFlags1: 0xe0, + OptionFlags3: 8, + HostName: "subdev1", + UserName: "test", + Password: "testpwd", + AppName: "appname", + ServerName: "servername", + CtlIntName: "library", + Language: "en", + Database: "database", + ClientLCID: 0x204, + AtchDBFile: "filepath", + } + err := sendLogin(buf, login) + if err != nil { + t.Error("sendLogin should succeed") + } + ref := []byte{ + 16, 1, 0, 222, 0, 0, 1, 0, 198 + 16, 0, 0, 0, 3, 0, 10, 115, 0, 16, 0, 0, 0, 1, + 6, 1, 100, 0, 0, 0, 0, 0, 0, 0, 224, 0, 0, 8, 16, 255, 255, 255, 4, 2, 0, + 0, 94, 0, 7, 0, 108, 0, 4, 0, 116, 0, 7, 0, 130, 0, 7, 0, 144, 0, 10, 0, 0, + 0, 0, 0, 164, 0, 7, 0, 178, 0, 2, 0, 182, 0, 8, 0, 18, 52, 86, 120, 144, 171, + 198, 0, 0, 0, 198, 0, 8, 0, 214, 0, 0, 0, 0, 0, 0, 0, 115, 0, 117, 0, 98, + 0, 100, 0, 101, 0, 118, 0, 49, 0, 116, 0, 101, 0, 115, 0, 116, 0, 226, 165, + 243, 165, 146, 165, 226, 165, 162, 165, 210, 165, 227, 165, 97, 0, 112, + 0, 112, 0, 110, 0, 97, 0, 109, 0, 101, 0, 115, 0, 101, 0, 114, 0, 118, 0, + 101, 0, 114, 0, 110, 0, 97, 0, 109, 0, 101, 0, 108, 0, 105, 0, 98, 0, 114, + 0, 97, 0, 114, 0, 121, 0, 101, 0, 110, 0, 100, 0, 97, 0, 116, 0, 97, 0, 98, + 0, 97, 0, 115, 0, 101, 0, 102, 0, 105, 0, 108, 0, 101, 0, 112, 0, 97, 0, + 116, 0, 104, 0} + out := memBuf.Bytes() + if !bytes.Equal(ref, out) { + fmt.Println("Expected:") + fmt.Print(hex.Dump(ref)) + fmt.Println("Returned:") + fmt.Print(hex.Dump(out)) + t.Error("input output don't match") + } +} + +func TestSendSqlBatch(t *testing.T) { + checkConnStr(t) + p, err := parseConnectParams(makeConnStr(t).String()) + if err != nil { + t.Error("parseConnectParams failed:", err.Error()) + return + } + + conn, err := connect(context.Background(), nil, optionalLogger{testLogger{t}}, p) + if err != nil { + t.Error("Open connection failed:", err.Error()) + return + } + defer conn.buf.transport.Close() + + headers := []headerStruct{ + {hdrtype: dataStmHdrTransDescr, + data: transDescrHdr{0, 1}.pack()}, + } + err = sendSqlBatch72(conn.buf, "select 1", headers, true) + if err != nil { + t.Error("Sending sql batch failed", err.Error()) + return + } + + ch := make(chan tokenStruct, 5) + go processResponse(context.Background(), conn, ch, nil) + + var lastRow []interface{} +loop: + for tok := range ch { + switch token := tok.(type) { + case doneStruct: + break loop + case []columnStruct: + conn.columns = token + case []interface{}: + lastRow = token + default: + fmt.Println("unknown token", tok) + } + } + + if len(lastRow) == 0 { + t.Fatal("expected row but no row set") + } + + switch value := lastRow[0].(type) { + case int32: + if value != 1 { + t.Error("Invalid value returned, should be 1", value) + return + } + } +} + +func checkConnStr(t *testing.T) { + if len(os.Getenv("SQLSERVER_DSN")) > 0 { + return + } + if len(os.Getenv("HOST")) > 0 && len(os.Getenv("DATABASE")) > 0 { + return + } + t.Skip("no database connection string") +} + +// makeConnStr returns a URL struct so it may be modified by various +// tests before used as a DSN. +func makeConnStr(t *testing.T) *url.URL { + dsn := os.Getenv("SQLSERVER_DSN") + if len(dsn) > 0 { + parsed, err := url.Parse(dsn) + if err != nil { + t.Fatal("unable to parse SQLSERVER_DSN as URL", err) + } + values := parsed.Query() + if values.Get("log") == "" { + values.Set("log", "127") + } + parsed.RawQuery = values.Encode() + return parsed + } + values := url.Values{} + values.Set("log", "127") + values.Set("database", os.Getenv("DATABASE")) + return &url.URL{ + Scheme: "sqlserver", + Host: os.Getenv("HOST"), + Path: os.Getenv("INSTANCE"), + User: url.UserPassword(os.Getenv("SQLUSER"), os.Getenv("SQLPASSWORD")), + RawQuery: values.Encode(), + } +} + +type testLogger struct { + t *testing.T +} + +func (l testLogger) Printf(format string, v ...interface{}) { + l.t.Logf(format, v...) +} + +func (l testLogger) Println(v ...interface{}) { + l.t.Log(v...) +} + +func open(t *testing.T) *sql.DB { + checkConnStr(t) + SetLogger(testLogger{t}) + conn, err := sql.Open("mssql", makeConnStr(t).String()) + if err != nil { + t.Error("Open connection failed:", err.Error()) + return nil + } + + return conn +} + +func TestConnect(t *testing.T) { + checkConnStr(t) + SetLogger(testLogger{t}) + conn, err := sql.Open("mssql", makeConnStr(t).String()) + if err != nil { + t.Error("Open connection failed:", err.Error()) + return + } + defer conn.Close() +} + +func simpleQuery(conn *sql.DB, t *testing.T) (stmt *sql.Stmt) { + stmt, err := conn.Prepare("select 1 as a") + if err != nil { + t.Error("Prepare failed:", err.Error()) + return nil + } + return stmt +} + +func checkSimpleQuery(rows *sql.Rows, t *testing.T) { + numrows := 0 + for rows.Next() { + var val int + err := rows.Scan(&val) + if err != nil { + t.Error("Scan failed:", err.Error()) + } + if val != 1 { + t.Error("query should return 1") + } + numrows++ + } + if numrows != 1 { + t.Error("query should return 1 row, returned", numrows) + } +} + +func TestQuery(t *testing.T) { + conn := open(t) + if conn == nil { + return + } + defer conn.Close() + + stmt := simpleQuery(conn, t) + if stmt == nil { + return + } + defer stmt.Close() + + rows, err := stmt.Query() + if err != nil { + t.Error("Query failed:", err.Error()) + } + defer rows.Close() + + columns, err := rows.Columns() + if err != nil { + t.Error("getting columns failed", err.Error()) + } + if len(columns) != 1 && columns[0] != "a" { + t.Error("returned incorrect columns (expected ['a']):", columns) + } + + checkSimpleQuery(rows, t) +} + +func TestMultipleQueriesSequentialy(t *testing.T) { + + conn := open(t) + defer conn.Close() + + stmt, err := conn.Prepare("select 1 as a") + if err != nil { + t.Error("Prepare failed:", err.Error()) + return + } + defer stmt.Close() + + rows, err := stmt.Query() + if err != nil { + t.Error("Query failed:", err.Error()) + return + } + defer rows.Close() + checkSimpleQuery(rows, t) + + rows, err = stmt.Query() + if err != nil { + t.Error("Query failed:", err.Error()) + return + } + defer rows.Close() + checkSimpleQuery(rows, t) +} + +func TestMultipleQueryClose(t *testing.T) { + conn := open(t) + defer conn.Close() + + stmt, err := conn.Prepare("select 1 as a") + if err != nil { + t.Error("Prepare failed:", err.Error()) + return + } + defer stmt.Close() + + rows, err := stmt.Query() + if err != nil { + t.Error("Query failed:", err.Error()) + return + } + rows.Close() + + rows, err = stmt.Query() + if err != nil { + t.Error("Query failed:", err.Error()) + return + } + defer rows.Close() + checkSimpleQuery(rows, t) +} + +func TestPing(t *testing.T) { + conn := open(t) + defer conn.Close() + conn.Ping() +} + +func TestSecureWithInvalidHostName(t *testing.T) { + checkConnStr(t) + SetLogger(testLogger{t}) + + dsn := makeConnStr(t) + dsnParams := dsn.Query() + dsnParams.Set("encrypt", "true") + dsnParams.Set("TrustServerCertificate", "false") + dsnParams.Set("hostNameInCertificate", "foo.bar") + dsn.RawQuery = dsnParams.Encode() + + conn, err := sql.Open("mssql", dsn.String()) + if err != nil { + t.Fatal("Open connection failed:", err.Error()) + } + defer conn.Close() + err = conn.Ping() + if err == nil { + t.Fatal("Connected to fake foo.bar server") + } +} + +func TestSecureConnection(t *testing.T) { + checkConnStr(t) + SetLogger(testLogger{t}) + + dsn := makeConnStr(t) + dsnParams := dsn.Query() + dsnParams.Set("encrypt", "true") + dsnParams.Set("TrustServerCertificate", "true") + dsn.RawQuery = dsnParams.Encode() + + conn, err := sql.Open("mssql", dsn.String()) + if err != nil { + t.Fatal("Open connection failed:", err.Error()) + } + defer conn.Close() + var msg string + err = conn.QueryRow("select 'secret'").Scan(&msg) + if err != nil { + t.Fatal("cannot scan value", err) + } + if msg != "secret" { + t.Fatal("expected secret, got: ", msg) + } + var secure bool + err = conn.QueryRow("select encrypt_option from sys.dm_exec_connections where session_id=@@SPID").Scan(&secure) + if err != nil { + t.Fatal("cannot scan value", err) + } + if !secure { + t.Fatal("connection is not encrypted") + } +} + +func TestInvalidConnectionString(t *testing.T) { + connStrings := []string{ + "log=invalid", + "port=invalid", + "packet size=invalid", + "connection timeout=invalid", + "dial timeout=invalid", + "keepalive=invalid", + "encrypt=invalid", + "trustservercertificate=invalid", + "failoverport=invalid", + + // ODBC mode + "odbc:password={", + "odbc:password={somepass", + "odbc:password={somepass}}", + "odbc:password={some}pass", + } + for _, connStr := range connStrings { + _, err := parseConnectParams(connStr) + if err == nil { + t.Errorf("Connection expected to fail for connection string %s but it didn't", connStr) + continue + } else { + t.Logf("Connection failed for %s as expected with error %v", connStr, err) + } + } +} + +func TestValidConnectionString(t *testing.T) { + type testStruct struct { + connStr string + check func(connectParams) bool + } + connStrings := []testStruct{ + {"server=server\\instance;database=testdb;user id=tester;password=pwd", func(p connectParams) bool { + return p.host == "server" && p.instance == "instance" && p.user == "tester" && p.password == "pwd" + }}, + {"server=.", func(p connectParams) bool { return p.host == "localhost" }}, + {"server=(local)", func(p connectParams) bool { return p.host == "localhost" }}, + {"ServerSPN=serverspn;Workstation ID=workstid", func(p connectParams) bool { return p.serverSPN == "serverspn" && p.workstation == "workstid" }}, + {"failoverpartner=fopartner;failoverport=2000", func(p connectParams) bool { return p.failOverPartner == "fopartner" && p.failOverPort == 2000 }}, + {"app name=appname;applicationintent=ReadOnly", func(p connectParams) bool { return p.appname == "appname" && (p.typeFlags&fReadOnlyIntent != 0) }}, + {"encrypt=disable", func(p connectParams) bool { return p.disableEncryption }}, + {"encrypt=true", func(p connectParams) bool { return p.encrypt && !p.disableEncryption }}, + {"encrypt=false", func(p connectParams) bool { return !p.encrypt && !p.disableEncryption }}, + {"trustservercertificate=true", func(p connectParams) bool { return p.trustServerCertificate }}, + {"trustservercertificate=false", func(p connectParams) bool { return !p.trustServerCertificate }}, + {"certificate=abc", func(p connectParams) bool { return p.certificate == "abc" }}, + {"hostnameincertificate=abc", func(p connectParams) bool { return p.hostInCertificate == "abc" }}, + {"connection timeout=3;dial timeout=4;keepalive=5", func(p connectParams) bool { + return p.conn_timeout == 3*time.Second && p.dial_timeout == 4*time.Second && p.keepAlive == 5*time.Second + }}, + {"log=63", func(p connectParams) bool { return p.logFlags == 63 && p.port == 1433 }}, + {"log=63;port=1000", func(p connectParams) bool { return p.logFlags == 63 && p.port == 1000 }}, + {"log=64", func(p connectParams) bool { return p.logFlags == 64 && p.packetSize == 4096 }}, + {"log=64;packet size=0", func(p connectParams) bool { return p.logFlags == 64 && p.packetSize == 512 }}, + {"log=64;packet size=300", func(p connectParams) bool { return p.logFlags == 64 && p.packetSize == 512 }}, + {"log=64;packet size=8192", func(p connectParams) bool { return p.logFlags == 64 && p.packetSize == 8192 }}, + {"log=64;packet size=48000", func(p connectParams) bool { return p.logFlags == 64 && p.packetSize == 32767 }}, + + // those are supported currently, but maybe should not be + {"someparam", func(p connectParams) bool { return true }}, + {";;=;", func(p connectParams) bool { return true }}, + + // ODBC mode + {"odbc:server=somehost;user id=someuser;password=somepass", func(p connectParams) bool { + return p.host == "somehost" && p.user == "someuser" && p.password == "somepass" + }}, + {"odbc:server=somehost;user id=someuser;password=some{pass", func(p connectParams) bool { + return p.host == "somehost" && p.user == "someuser" && p.password == "some{pass" + }}, + {"odbc:server={somehost};user id={someuser};password={somepass}", func(p connectParams) bool { + return p.host == "somehost" && p.user == "someuser" && p.password == "somepass" + }}, + {"odbc:server={somehost};user id={someuser};password={some=pass}", func(p connectParams) bool { + return p.host == "somehost" && p.user == "someuser" && p.password == "some=pass" + }}, + {"odbc:server={somehost};user id={someuser};password={some;pass}", func(p connectParams) bool { + return p.host == "somehost" && p.user == "someuser" && p.password == "some;pass" + }}, + {"odbc:server={somehost};user id={someuser};password={some{pass}", func(p connectParams) bool { + return p.host == "somehost" && p.user == "someuser" && p.password == "some{pass" + }}, + {"odbc:server={somehost};user id={someuser};password={some}}pass}", func(p connectParams) bool { + return p.host == "somehost" && p.user == "someuser" && p.password == "some}pass" + }}, + {"odbc:server={somehost};user id={someuser};password={some{}}p=a;ss}", func(p connectParams) bool { + return p.host == "somehost" && p.user == "someuser" && p.password == "some{}p=a;ss" + }}, + {"odbc: server = somehost; user id = someuser ; password = {some pass } ", func(p connectParams) bool { + return p.host == "somehost" && p.user == "someuser" && p.password == "some pass " + }}, + + // URL mode + {"sqlserver://somehost?connection+timeout=30", func(p connectParams) bool { + return p.host == "somehost" && p.port == 1433 && p.instance == "" && p.conn_timeout == 30*time.Second + }}, + {"sqlserver://someuser@somehost?connection+timeout=30", func(p connectParams) bool { + return p.host == "somehost" && p.port == 1433 && p.instance == "" && p.user == "someuser" && p.password == "" && p.conn_timeout == 30*time.Second + }}, + {"sqlserver://someuser:@somehost?connection+timeout=30", func(p connectParams) bool { + return p.host == "somehost" && p.port == 1433 && p.instance == "" && p.user == "someuser" && p.password == "" && p.conn_timeout == 30*time.Second + }}, + {"sqlserver://someuser:foo%3A%2F%5C%21~%40;bar@somehost?connection+timeout=30", func(p connectParams) bool { + return p.host == "somehost" && p.port == 1433 && p.instance == "" && p.user == "someuser" && p.password == "foo:/\\!~@;bar" && p.conn_timeout == 30*time.Second + }}, + {"sqlserver://someuser:foo%3A%2F%5C%21~%40;bar@somehost:1434?connection+timeout=30", func(p connectParams) bool { + return p.host == "somehost" && p.port == 1434 && p.instance == "" && p.user == "someuser" && p.password == "foo:/\\!~@;bar" && p.conn_timeout == 30*time.Second + }}, + {"sqlserver://someuser:foo%3A%2F%5C%21~%40;bar@somehost:1434/someinstance?connection+timeout=30", func(p connectParams) bool { + return p.host == "somehost" && p.port == 1434 && p.instance == "someinstance" && p.user == "someuser" && p.password == "foo:/\\!~@;bar" && p.conn_timeout == 30*time.Second + }}, + } + for _, ts := range connStrings { + p, err := parseConnectParams(ts.connStr) + if err == nil { + t.Logf("Connection string was parsed successfully %s", ts.connStr) + } else { + t.Errorf("Connection string %s failed to parse with error %s", ts.connStr, err) + continue + } + + if !ts.check(p) { + t.Errorf("Check failed on conn str %s", ts.connStr) + } + } +} + +func TestBadConnect(t *testing.T) { + checkConnStr(t) + SetLogger(testLogger{t}) + connURL := makeConnStr(t) + connURL.User = url.UserPassword("baduser", "badpwd") + badDSN := connURL.String() + + conn, err := sql.Open("mssql", badDSN) + if err != nil { + t.Error("Open connection failed:", err.Error()) + } + defer conn.Close() + + err = conn.Ping() + if err == nil { + t.Error("Ping should fail for connection: ", badDSN) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/token.go b/vendor/github.com/denisenkom/go-mssqldb/token.go new file mode 100644 index 00000000..1acac8a5 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/token.go @@ -0,0 +1,804 @@ +package mssql + +import ( + "context" + "encoding/binary" + "errors" + "fmt" + "io" + "net" + "strconv" + "strings" +) + +//go:generate stringer -type token + +type token byte + +// token ids +const ( + tokenReturnStatus token = 121 // 0x79 + tokenColMetadata token = 129 // 0x81 + tokenOrder token = 169 // 0xA9 + tokenError token = 170 // 0xAA + tokenInfo token = 171 // 0xAB + tokenReturnValue token = 0xAC + tokenLoginAck token = 173 // 0xad + tokenRow token = 209 // 0xd1 + tokenNbcRow token = 210 // 0xd2 + tokenEnvChange token = 227 // 0xE3 + tokenSSPI token = 237 // 0xED + tokenDone token = 253 // 0xFD + tokenDoneProc token = 254 + tokenDoneInProc token = 255 +) + +// done flags +// https://msdn.microsoft.com/en-us/library/dd340421.aspx +const ( + doneFinal = 0 + doneMore = 1 + doneError = 2 + doneInxact = 4 + doneCount = 0x10 + doneAttn = 0x20 + doneSrvError = 0x100 +) + +// ENVCHANGE types +// http://msdn.microsoft.com/en-us/library/dd303449.aspx +const ( + envTypDatabase = 1 + envTypLanguage = 2 + envTypCharset = 3 + envTypPacketSize = 4 + envSortId = 5 + envSortFlags = 6 + envSqlCollation = 7 + envTypBeginTran = 8 + envTypCommitTran = 9 + envTypRollbackTran = 10 + envEnlistDTC = 11 + envDefectTran = 12 + envDatabaseMirrorPartner = 13 + envPromoteTran = 15 + envTranMgrAddr = 16 + envTranEnded = 17 + envResetConnAck = 18 + envStartedInstanceName = 19 + envRouting = 20 +) + +// COLMETADATA flags +// https://msdn.microsoft.com/en-us/library/dd357363.aspx +const ( + colFlagNullable = 1 + // TODO implement more flags +) + +// interface for all tokens +type tokenStruct interface{} + +type orderStruct struct { + ColIds []uint16 +} + +type doneStruct struct { + Status uint16 + CurCmd uint16 + RowCount uint64 + errors []Error +} + +func (d doneStruct) isError() bool { + return d.Status&doneError != 0 || len(d.errors) > 0 +} + +func (d doneStruct) getError() Error { + if len(d.errors) > 0 { + return d.errors[len(d.errors)-1] + } else { + return Error{Message: "Request failed but didn't provide reason"} + } +} + +type doneInProcStruct doneStruct + +var doneFlags2str = map[uint16]string{ + doneFinal: "final", + doneMore: "more", + doneError: "error", + doneInxact: "inxact", + doneCount: "count", + doneAttn: "attn", + doneSrvError: "srverror", +} + +func doneFlags2Str(flags uint16) string { + strs := make([]string, 0, len(doneFlags2str)) + for flag, tag := range doneFlags2str { + if flags&flag != 0 { + strs = append(strs, tag) + } + } + return strings.Join(strs, "|") +} + +// ENVCHANGE stream +// http://msdn.microsoft.com/en-us/library/dd303449.aspx +func processEnvChg(sess *tdsSession) { + size := sess.buf.uint16() + r := &io.LimitedReader{R: sess.buf, N: int64(size)} + for { + var err error + var envtype uint8 + err = binary.Read(r, binary.LittleEndian, &envtype) + if err == io.EOF { + return + } + if err != nil { + badStreamPanic(err) + } + switch envtype { + case envTypDatabase: + sess.database, err = readBVarChar(r) + if err != nil { + badStreamPanic(err) + } + _, err = readBVarChar(r) + if err != nil { + badStreamPanic(err) + } + case envTypLanguage: + // currently ignored + // new value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // old value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envTypCharset: + // currently ignored + // new value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // old value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envTypPacketSize: + packetsize, err := readBVarChar(r) + if err != nil { + badStreamPanic(err) + } + _, err = readBVarChar(r) + if err != nil { + badStreamPanic(err) + } + packetsizei, err := strconv.Atoi(packetsize) + if err != nil { + badStreamPanicf("Invalid Packet size value returned from server (%s): %s", packetsize, err.Error()) + } + sess.buf.ResizeBuffer(packetsizei) + case envSortId: + // currently ignored + // new value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envSortFlags: + // currently ignored + // new value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envSqlCollation: + // currently ignored + var collationSize uint8 + err = binary.Read(r, binary.LittleEndian, &collationSize) + if err != nil { + badStreamPanic(err) + } + + // SQL Collation data should contain 5 bytes in length + if collationSize != 5 { + badStreamPanicf("Invalid SQL Collation size value returned from server: %d", collationSize) + } + + // 4 bytes, contains: LCID ColFlags Version + var info uint32 + err = binary.Read(r, binary.LittleEndian, &info) + if err != nil { + badStreamPanic(err) + } + + // 1 byte, contains: sortID + var sortID uint8 + err = binary.Read(r, binary.LittleEndian, &sortID) + if err != nil { + badStreamPanic(err) + } + + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envTypBeginTran: + tranid, err := readBVarByte(r) + if len(tranid) != 8 { + badStreamPanicf("invalid size of transaction identifier: %d", len(tranid)) + } + sess.tranid = binary.LittleEndian.Uint64(tranid) + if err != nil { + badStreamPanic(err) + } + if sess.logFlags&logTransaction != 0 { + sess.log.Printf("BEGIN TRANSACTION %x\n", sess.tranid) + } + _, err = readBVarByte(r) + if err != nil { + badStreamPanic(err) + } + case envTypCommitTran, envTypRollbackTran: + _, err = readBVarByte(r) + if err != nil { + badStreamPanic(err) + } + _, err = readBVarByte(r) + if err != nil { + badStreamPanic(err) + } + if sess.logFlags&logTransaction != 0 { + if envtype == envTypCommitTran { + sess.log.Printf("COMMIT TRANSACTION %x\n", sess.tranid) + } else { + sess.log.Printf("ROLLBACK TRANSACTION %x\n", sess.tranid) + } + } + sess.tranid = 0 + case envEnlistDTC: + // currently ignored + // new value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // old value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envDefectTran: + // currently ignored + // new value + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envDatabaseMirrorPartner: + sess.partner, err = readBVarChar(r) + if err != nil { + badStreamPanic(err) + } + _, err = readBVarChar(r) + if err != nil { + badStreamPanic(err) + } + case envPromoteTran: + // currently ignored + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // dtc token + // spec says it should be L_VARBYTE, so this code might be wrong + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envTranMgrAddr: + // currently ignored + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // XACT_MANAGER_ADDRESS = B_VARBYTE + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envTranEnded: + // currently ignored + // old value, B_VARBYTE + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envResetConnAck: + // currently ignored + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envStartedInstanceName: + // currently ignored + // old value, should be 0 + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // instance name + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + case envRouting: + // RoutingData message is: + // ValueLength USHORT + // Protocol (TCP = 0) BYTE + // ProtocolProperty (new port) USHORT + // AlternateServer US_VARCHAR + _, err := readUshort(r) + if err != nil { + badStreamPanic(err) + } + protocol, err := readByte(r) + if err != nil || protocol != 0 { + badStreamPanic(err) + } + newPort, err := readUshort(r) + if err != nil { + badStreamPanic(err) + } + newServer, err := readUsVarChar(r) + if err != nil { + badStreamPanic(err) + } + // consume the OLDVALUE = %x00 %x00 + _, err = readUshort(r) + if err != nil { + badStreamPanic(err) + } + sess.routedServer = newServer + sess.routedPort = newPort + default: + // ignore rest of records because we don't know how to skip those + sess.log.Printf("WARN: Unknown ENVCHANGE record detected with type id = %d\n", envtype) + break + } + + } +} + +// http://msdn.microsoft.com/en-us/library/dd358180.aspx +func parseReturnStatus(r *tdsBuffer) ReturnStatus { + return ReturnStatus(r.int32()) +} + +func parseOrder(r *tdsBuffer) (res orderStruct) { + len := int(r.uint16()) + res.ColIds = make([]uint16, len/2) + for i := 0; i < len/2; i++ { + res.ColIds[i] = r.uint16() + } + return res +} + +// https://msdn.microsoft.com/en-us/library/dd340421.aspx +func parseDone(r *tdsBuffer) (res doneStruct) { + res.Status = r.uint16() + res.CurCmd = r.uint16() + res.RowCount = r.uint64() + return res +} + +// https://msdn.microsoft.com/en-us/library/dd340553.aspx +func parseDoneInProc(r *tdsBuffer) (res doneInProcStruct) { + res.Status = r.uint16() + res.CurCmd = r.uint16() + res.RowCount = r.uint64() + return res +} + +type sspiMsg []byte + +func parseSSPIMsg(r *tdsBuffer) sspiMsg { + size := r.uint16() + buf := make([]byte, size) + r.ReadFull(buf) + return sspiMsg(buf) +} + +type loginAckStruct struct { + Interface uint8 + TDSVersion uint32 + ProgName string + ProgVer uint32 +} + +func parseLoginAck(r *tdsBuffer) loginAckStruct { + size := r.uint16() + buf := make([]byte, size) + r.ReadFull(buf) + var res loginAckStruct + res.Interface = buf[0] + res.TDSVersion = binary.BigEndian.Uint32(buf[1:]) + prognamelen := buf[1+4] + var err error + if res.ProgName, err = ucs22str(buf[1+4+1 : 1+4+1+prognamelen*2]); err != nil { + badStreamPanic(err) + } + res.ProgVer = binary.BigEndian.Uint32(buf[size-4:]) + return res +} + +// http://msdn.microsoft.com/en-us/library/dd357363.aspx +func parseColMetadata72(r *tdsBuffer) (columns []columnStruct) { + count := r.uint16() + if count == 0xffff { + // no metadata is sent + return nil + } + columns = make([]columnStruct, count) + for i := range columns { + column := &columns[i] + column.UserType = r.uint32() + column.Flags = r.uint16() + + // parsing TYPE_INFO structure + column.ti = readTypeInfo(r) + column.ColName = r.BVarChar() + } + return columns +} + +// http://msdn.microsoft.com/en-us/library/dd357254.aspx +func parseRow(r *tdsBuffer, columns []columnStruct, row []interface{}) { + for i, column := range columns { + row[i] = column.ti.Reader(&column.ti, r) + } +} + +// http://msdn.microsoft.com/en-us/library/dd304783.aspx +func parseNbcRow(r *tdsBuffer, columns []columnStruct, row []interface{}) { + bitlen := (len(columns) + 7) / 8 + pres := make([]byte, bitlen) + r.ReadFull(pres) + for i, col := range columns { + if pres[i/8]&(1<<(uint(i)%8)) != 0 { + row[i] = nil + continue + } + row[i] = col.ti.Reader(&col.ti, r) + } +} + +// http://msdn.microsoft.com/en-us/library/dd304156.aspx +func parseError72(r *tdsBuffer) (res Error) { + length := r.uint16() + _ = length // ignore length + res.Number = r.int32() + res.State = r.byte() + res.Class = r.byte() + res.Message = r.UsVarChar() + res.ServerName = r.BVarChar() + res.ProcName = r.BVarChar() + res.LineNo = r.int32() + return +} + +// http://msdn.microsoft.com/en-us/library/dd304156.aspx +func parseInfo(r *tdsBuffer) (res Error) { + length := r.uint16() + _ = length // ignore length + res.Number = r.int32() + res.State = r.byte() + res.Class = r.byte() + res.Message = r.UsVarChar() + res.ServerName = r.BVarChar() + res.ProcName = r.BVarChar() + res.LineNo = r.int32() + return +} + +// https://msdn.microsoft.com/en-us/library/dd303881.aspx +func parseReturnValue(r *tdsBuffer) (nv namedValue) { + /* + ParamOrdinal + ParamName + Status + UserType + Flags + TypeInfo + CryptoMetadata + Value + */ + r.uint16() + nv.Name = r.BVarChar() + r.byte() + r.uint32() // UserType (uint16 prior to 7.2) + r.uint16() + ti := readTypeInfo(r) + nv.Value = ti.Reader(&ti, r) + return +} + +func processSingleResponse(sess *tdsSession, ch chan tokenStruct, outs map[string]interface{}) { + defer func() { + if err := recover(); err != nil { + if sess.logFlags&logErrors != 0 { + sess.log.Printf("ERROR: Intercepted panic %v", err) + } + ch <- err + } + close(ch) + }() + + packet_type, err := sess.buf.BeginRead() + if err != nil { + if sess.logFlags&logErrors != 0 { + sess.log.Printf("ERROR: BeginRead failed %v", err) + } + ch <- err + return + } + if packet_type != packReply { + badStreamPanic(fmt.Errorf("unexpected packet type in reply: got %v, expected %v", packet_type, packReply)) + } + var columns []columnStruct + errs := make([]Error, 0, 5) + for { + token := token(sess.buf.byte()) + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got token %v", token) + } + switch token { + case tokenSSPI: + ch <- parseSSPIMsg(sess.buf) + return + case tokenReturnStatus: + returnStatus := parseReturnStatus(sess.buf) + ch <- returnStatus + case tokenLoginAck: + loginAck := parseLoginAck(sess.buf) + ch <- loginAck + case tokenOrder: + order := parseOrder(sess.buf) + ch <- order + case tokenDoneInProc: + done := parseDoneInProc(sess.buf) + if sess.logFlags&logRows != 0 && done.Status&doneCount != 0 { + sess.log.Printf("(%d row(s) affected)\n", done.RowCount) + } + ch <- done + case tokenDone, tokenDoneProc: + done := parseDone(sess.buf) + done.errors = errs + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got DONE or DONEPROC status=%d", done.Status) + } + if done.Status&doneSrvError != 0 { + ch <- errors.New("SQL Server had internal error") + return + } + if sess.logFlags&logRows != 0 && done.Status&doneCount != 0 { + sess.log.Printf("(%d row(s) affected)\n", done.RowCount) + } + ch <- done + if done.Status&doneMore == 0 { + return + } + case tokenColMetadata: + columns = parseColMetadata72(sess.buf) + ch <- columns + case tokenRow: + row := make([]interface{}, len(columns)) + parseRow(sess.buf, columns, row) + ch <- row + case tokenNbcRow: + row := make([]interface{}, len(columns)) + parseNbcRow(sess.buf, columns, row) + ch <- row + case tokenEnvChange: + processEnvChg(sess) + case tokenError: + err := parseError72(sess.buf) + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got ERROR %d %s", err.Number, err.Message) + } + errs = append(errs, err) + if sess.logFlags&logErrors != 0 { + sess.log.Println(err.Message) + } + case tokenInfo: + info := parseInfo(sess.buf) + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got INFO %d %s", info.Number, info.Message) + } + if sess.logFlags&logMessages != 0 { + sess.log.Println(info.Message) + } + case tokenReturnValue: + nv := parseReturnValue(sess.buf) + if len(nv.Name) > 0 { + name := nv.Name[1:] // Remove the leading "@". + if ov, has := outs[name]; has { + err = scanIntoOut(name, nv.Value, ov) + if err != nil { + fmt.Println("scan error", err) + ch <- err + } + } + } + default: + badStreamPanic(fmt.Errorf("unknown token type returned: %v", token)) + } + } +} + +type parseRespIter byte + +const ( + parseRespIterContinue parseRespIter = iota // Continue parsing current token. + parseRespIterNext // Fetch the next token. + parseRespIterDone // Done with parsing the response. +) + +type parseRespState byte + +const ( + parseRespStateNormal parseRespState = iota // Normal response state. + parseRespStateCancel // Query is canceled, wait for server to confirm. + parseRespStateClosing // Waiting for tokens to come through. +) + +type parseResp struct { + sess *tdsSession + ctxDone <-chan struct{} + state parseRespState + cancelError error +} + +func (ts *parseResp) sendAttention(ch chan tokenStruct) parseRespIter { + if err := sendAttention(ts.sess.buf); err != nil { + ts.dlogf("failed to send attention signal %v", err) + ch <- err + return parseRespIterDone + } + ts.state = parseRespStateCancel + return parseRespIterContinue +} + +func (ts *parseResp) dlog(msg string) { + if ts.sess.logFlags&logDebug != 0 { + ts.sess.log.Println(msg) + } +} +func (ts *parseResp) dlogf(f string, v ...interface{}) { + if ts.sess.logFlags&logDebug != 0 { + ts.sess.log.Printf(f, v...) + } +} + +func (ts *parseResp) iter(ctx context.Context, ch chan tokenStruct, tokChan chan tokenStruct) parseRespIter { + switch ts.state { + default: + panic("unknown state") + case parseRespStateNormal: + select { + case tok, ok := <-tokChan: + if !ok { + ts.dlog("response finished") + return parseRespIterDone + } + if err, ok := tok.(net.Error); ok && err.Timeout() { + ts.cancelError = err + ts.dlog("got timeout error, sending attention signal to server") + return ts.sendAttention(ch) + } + // Pass the token along. + ch <- tok + return parseRespIterContinue + + case <-ts.ctxDone: + ts.ctxDone = nil + ts.dlog("got cancel message, sending attention signal to server") + return ts.sendAttention(ch) + } + case parseRespStateCancel: // Read all responses until a DONE or error is received.Auth + select { + case tok, ok := <-tokChan: + if !ok { + ts.dlog("response finished but waiting for attention ack") + return parseRespIterNext + } + switch tok := tok.(type) { + default: + // Ignore all other tokens while waiting. + // The TDS spec says other tokens may arrive after an attention + // signal is sent. Ignore these tokens and continue looking for + // a DONE with attention confirm mark. + case doneStruct: + if tok.Status&doneAttn != 0 { + ts.dlog("got cancellation confirmation from server") + if ts.cancelError != nil { + ch <- ts.cancelError + ts.cancelError = nil + } else { + ch <- ctx.Err() + } + return parseRespIterDone + } + + // If an error happens during cancel, pass it along and just stop. + // We are uncertain to receive more tokens. + case error: + ch <- tok + ts.state = parseRespStateClosing + } + return parseRespIterContinue + case <-ts.ctxDone: + ts.ctxDone = nil + ts.state = parseRespStateClosing + return parseRespIterContinue + } + case parseRespStateClosing: // Wait for current token chan to close. + if _, ok := <-tokChan; !ok { + ts.dlog("response finished") + return parseRespIterDone + } + return parseRespIterContinue + } +} + +func processResponse(ctx context.Context, sess *tdsSession, ch chan tokenStruct, outs map[string]interface{}) { + ts := &parseResp{ + sess: sess, + ctxDone: ctx.Done(), + } + defer func() { + // Ensure any remaining error is piped through + // or the query may look like it executed when it actually failed. + if ts.cancelError != nil { + ch <- ts.cancelError + ts.cancelError = nil + } + close(ch) + }() + + // Loop over multiple responses. + for { + ts.dlog("initiating response reading") + + tokChan := make(chan tokenStruct) + go processSingleResponse(sess, tokChan, outs) + + // Loop over multiple tokens in response. + tokensLoop: + for { + switch ts.iter(ctx, ch, tokChan) { + case parseRespIterContinue: + // Nothing, continue to next token. + case parseRespIterNext: + break tokensLoop + case parseRespIterDone: + return + } + } + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/token_string.go b/vendor/github.com/denisenkom/go-mssqldb/token_string.go new file mode 100644 index 00000000..c075b23b --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/token_string.go @@ -0,0 +1,53 @@ +// Code generated by "stringer -type token"; DO NOT EDIT + +package mssql + +import "fmt" + +const ( + _token_name_0 = "tokenReturnStatus" + _token_name_1 = "tokenColMetadata" + _token_name_2 = "tokenOrdertokenErrortokenInfo" + _token_name_3 = "tokenLoginAck" + _token_name_4 = "tokenRowtokenNbcRow" + _token_name_5 = "tokenEnvChange" + _token_name_6 = "tokenSSPI" + _token_name_7 = "tokenDonetokenDoneProctokenDoneInProc" +) + +var ( + _token_index_0 = [...]uint8{0, 17} + _token_index_1 = [...]uint8{0, 16} + _token_index_2 = [...]uint8{0, 10, 20, 29} + _token_index_3 = [...]uint8{0, 13} + _token_index_4 = [...]uint8{0, 8, 19} + _token_index_5 = [...]uint8{0, 14} + _token_index_6 = [...]uint8{0, 9} + _token_index_7 = [...]uint8{0, 9, 22, 37} +) + +func (i token) String() string { + switch { + case i == 121: + return _token_name_0 + case i == 129: + return _token_name_1 + case 169 <= i && i <= 171: + i -= 169 + return _token_name_2[_token_index_2[i]:_token_index_2[i+1]] + case i == 173: + return _token_name_3 + case 209 <= i && i <= 210: + i -= 209 + return _token_name_4[_token_index_4[i]:_token_index_4[i+1]] + case i == 227: + return _token_name_5 + case i == 237: + return _token_name_6 + case 253 <= i && i <= 255: + i -= 253 + return _token_name_7[_token_index_7[i]:_token_index_7[i+1]] + default: + return fmt.Sprintf("token(%d)", i) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/tran.go b/vendor/github.com/denisenkom/go-mssqldb/tran.go new file mode 100644 index 00000000..cb643681 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/tran.go @@ -0,0 +1,110 @@ +package mssql + +// Transaction Manager requests +// http://msdn.microsoft.com/en-us/library/dd339887.aspx + +import ( + "encoding/binary" +) + +const ( + tmGetDtcAddr = 0 + tmPropagateXact = 1 + tmBeginXact = 5 + tmPromoteXact = 6 + tmCommitXact = 7 + tmRollbackXact = 8 + tmSaveXact = 9 +) + +type isoLevel uint8 + +const ( + isolationUseCurrent isoLevel = 0 + isolationReadUncommited = 1 + isolationReadCommited = 2 + isolationRepeatableRead = 3 + isolationSerializable = 4 + isolationSnapshot = 5 +) + +func sendBeginXact(buf *tdsBuffer, headers []headerStruct, isolation isoLevel, name string, resetSession bool) (err error) { + buf.BeginPacket(packTransMgrReq, resetSession) + writeAllHeaders(buf, headers) + var rqtype uint16 = tmBeginXact + err = binary.Write(buf, binary.LittleEndian, &rqtype) + if err != nil { + return + } + err = binary.Write(buf, binary.LittleEndian, &isolation) + if err != nil { + return + } + err = writeBVarChar(buf, name) + if err != nil { + return + } + return buf.FinishPacket() +} + +const ( + fBeginXact = 1 +) + +func sendCommitXact(buf *tdsBuffer, headers []headerStruct, name string, flags uint8, isolation uint8, newname string, resetSession bool) error { + buf.BeginPacket(packTransMgrReq, resetSession) + writeAllHeaders(buf, headers) + var rqtype uint16 = tmCommitXact + err := binary.Write(buf, binary.LittleEndian, &rqtype) + if err != nil { + return err + } + err = writeBVarChar(buf, name) + if err != nil { + return err + } + err = binary.Write(buf, binary.LittleEndian, &flags) + if err != nil { + return err + } + if flags&fBeginXact != 0 { + err = binary.Write(buf, binary.LittleEndian, &isolation) + if err != nil { + return err + } + err = writeBVarChar(buf, name) + if err != nil { + return err + } + } + return buf.FinishPacket() +} + +func sendRollbackXact(buf *tdsBuffer, headers []headerStruct, name string, flags uint8, isolation uint8, newname string, resetSession bool) error { + buf.BeginPacket(packTransMgrReq, resetSession) + writeAllHeaders(buf, headers) + var rqtype uint16 = tmRollbackXact + err := binary.Write(buf, binary.LittleEndian, &rqtype) + if err != nil { + return err + } + err = writeBVarChar(buf, name) + if err != nil { + return err + } + err = binary.Write(buf, binary.LittleEndian, &flags) + if err != nil { + return err + } + if flags&fBeginXact != 0 { + err = binary.Write(buf, binary.LittleEndian, &isolation) + if err != nil { + return err + } + err = writeBVarChar(buf, name) + if err != nil { + return err + } + } + return buf.FinishPacket() +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/types.go b/vendor/github.com/denisenkom/go-mssqldb/types.go new file mode 100644 index 00000000..3bad788b --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/types.go @@ -0,0 +1,1566 @@ +package mssql + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "math" + "reflect" + "strconv" + "time" + + "github.com/denisenkom/go-mssqldb/internal/cp" +) + +// fixed-length data types +// http://msdn.microsoft.com/en-us/library/dd341171.aspx +const ( + typeNull = 0x1f + typeInt1 = 0x30 + typeBit = 0x32 + typeInt2 = 0x34 + typeInt4 = 0x38 + typeDateTim4 = 0x3a + typeFlt4 = 0x3b + typeMoney = 0x3c + typeDateTime = 0x3d + typeFlt8 = 0x3e + typeMoney4 = 0x7a + typeInt8 = 0x7f +) + +// variable-length data types +// http://msdn.microsoft.com/en-us/library/dd358341.aspx +const ( + // byte len types + typeGuid = 0x24 + typeIntN = 0x26 + typeDecimal = 0x37 // legacy + typeNumeric = 0x3f // legacy + typeBitN = 0x68 + typeDecimalN = 0x6a + typeNumericN = 0x6c + typeFltN = 0x6d + typeMoneyN = 0x6e + typeDateTimeN = 0x6f + typeDateN = 0x28 + typeTimeN = 0x29 + typeDateTime2N = 0x2a + typeDateTimeOffsetN = 0x2b + typeChar = 0x2f // legacy + typeVarChar = 0x27 // legacy + typeBinary = 0x2d // legacy + typeVarBinary = 0x25 // legacy + + // short length types + typeBigVarBin = 0xa5 + typeBigVarChar = 0xa7 + typeBigBinary = 0xad + typeBigChar = 0xaf + typeNVarChar = 0xe7 + typeNChar = 0xef + typeXml = 0xf1 + typeUdt = 0xf0 + + // long length types + typeText = 0x23 + typeImage = 0x22 + typeNText = 0x63 + typeVariant = 0x62 +) +const _PLP_NULL = 0xFFFFFFFFFFFFFFFF +const _UNKNOWN_PLP_LEN = 0xFFFFFFFFFFFFFFFE +const _PLP_TERMINATOR = 0x00000000 + +// TYPE_INFO rule +// http://msdn.microsoft.com/en-us/library/dd358284.aspx +type typeInfo struct { + TypeId uint8 + Size int + Scale uint8 + Prec uint8 + Buffer []byte + Collation cp.Collation + UdtInfo udtInfo + XmlInfo xmlInfo + Reader func(ti *typeInfo, r *tdsBuffer) (res interface{}) + Writer func(w io.Writer, ti typeInfo, buf []byte) (err error) +} + +// Common Language Runtime (CLR) Instances +// http://msdn.microsoft.com/en-us/library/dd357962.aspx +type udtInfo struct { + //MaxByteSize uint32 + DBName string + SchemaName string + TypeName string + AssemblyQualifiedName string +} + +// XML Values +// http://msdn.microsoft.com/en-us/library/dd304764.aspx +type xmlInfo struct { + SchemaPresent uint8 + DBName string + OwningSchema string + XmlSchemaCollection string +} + +func readTypeInfo(r *tdsBuffer) (res typeInfo) { + res.TypeId = r.byte() + switch res.TypeId { + case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4, + typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8: + // those are fixed length types + switch res.TypeId { + case typeNull: + res.Size = 0 + case typeInt1, typeBit: + res.Size = 1 + case typeInt2: + res.Size = 2 + case typeInt4, typeDateTim4, typeFlt4, typeMoney4: + res.Size = 4 + case typeMoney, typeDateTime, typeFlt8, typeInt8: + res.Size = 8 + } + res.Reader = readFixedType + res.Buffer = make([]byte, res.Size) + default: // all others are VARLENTYPE + readVarLen(&res, r) + } + return +} + +// https://msdn.microsoft.com/en-us/library/dd358284.aspx +func writeTypeInfo(w io.Writer, ti *typeInfo) (err error) { + err = binary.Write(w, binary.LittleEndian, ti.TypeId) + if err != nil { + return + } + switch ti.TypeId { + case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4, + typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8: + // those are fixed length + // https://msdn.microsoft.com/en-us/library/dd341171.aspx + ti.Writer = writeFixedType + default: // all others are VARLENTYPE + err = writeVarLen(w, ti) + if err != nil { + return + } + } + return +} + +func writeFixedType(w io.Writer, ti typeInfo, buf []byte) (err error) { + _, err = w.Write(buf) + return +} + +// https://msdn.microsoft.com/en-us/library/dd358341.aspx +func writeVarLen(w io.Writer, ti *typeInfo) (err error) { + switch ti.TypeId { + case typeDateN: + ti.Writer = writeByteLenType + case typeTimeN, typeDateTime2N, typeDateTimeOffsetN: + if err = binary.Write(w, binary.LittleEndian, ti.Scale); err != nil { + return + } + ti.Writer = writeByteLenType + case typeIntN, typeDecimal, typeNumeric, + typeBitN, typeDecimalN, typeNumericN, typeFltN, + typeMoneyN, typeDateTimeN, typeChar, + typeVarChar, typeBinary, typeVarBinary: + + // byle len types + if ti.Size > 0xff { + panic("Invalid size for BYLELEN_TYPE") + } + if err = binary.Write(w, binary.LittleEndian, uint8(ti.Size)); err != nil { + return + } + switch ti.TypeId { + case typeDecimal, typeNumeric, typeDecimalN, typeNumericN: + err = binary.Write(w, binary.LittleEndian, ti.Prec) + if err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, ti.Scale) + if err != nil { + return + } + } + ti.Writer = writeByteLenType + case typeGuid: + if !(ti.Size == 0x10 || ti.Size == 0x00) { + panic("Invalid size for BYLELEN_TYPE") + } + if err = binary.Write(w, binary.LittleEndian, uint8(ti.Size)); err != nil { + return + } + ti.Writer = writeByteLenType + case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar, + typeNVarChar, typeNChar, typeXml, typeUdt: + // short len types + if ti.Size > 8000 || ti.Size == 0 { + if err = binary.Write(w, binary.LittleEndian, uint16(0xffff)); err != nil { + return + } + ti.Writer = writePLPType + } else { + if err = binary.Write(w, binary.LittleEndian, uint16(ti.Size)); err != nil { + return + } + ti.Writer = writeShortLenType + } + switch ti.TypeId { + case typeBigVarChar, typeBigChar, typeNVarChar, typeNChar: + if err = writeCollation(w, ti.Collation); err != nil { + return + } + case typeXml: + if err = binary.Write(w, binary.LittleEndian, ti.XmlInfo.SchemaPresent); err != nil { + return + } + } + case typeText, typeImage, typeNText, typeVariant: + // LONGLEN_TYPE + if err = binary.Write(w, binary.LittleEndian, uint32(ti.Size)); err != nil { + return + } + if err = writeCollation(w, ti.Collation); err != nil { + return + } + ti.Writer = writeLongLenType + default: + panic("Invalid type") + } + return +} + +// http://msdn.microsoft.com/en-us/library/ee780895.aspx +func decodeDateTim4(buf []byte) time.Time { + days := binary.LittleEndian.Uint16(buf) + mins := binary.LittleEndian.Uint16(buf[2:]) + return time.Date(1900, 1, 1+int(days), + 0, int(mins), 0, 0, time.UTC) +} + +func encodeDateTim4(val time.Time) (buf []byte) { + buf = make([]byte, 4) + + ref := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC) + dur := val.Sub(ref) + days := dur / (24 * time.Hour) + mins := val.Hour()*60 + val.Minute() + if days < 0 { + days = 0 + mins = 0 + } + + binary.LittleEndian.PutUint16(buf[:2], uint16(days)) + binary.LittleEndian.PutUint16(buf[2:], uint16(mins)) + return +} + +// encodes datetime value +// type identifier is typeDateTimeN +func encodeDateTime(t time.Time) (res []byte) { + // base date in days since Jan 1st 1900 + basedays := gregorianDays(1900, 1) + // days since Jan 1st 1900 (same TZ as t) + days := gregorianDays(t.Year(), t.YearDay()) - basedays + tm := 300*(t.Second()+t.Minute()*60+t.Hour()*60*60) + t.Nanosecond()*300/1e9 + // minimum and maximum possible + mindays := gregorianDays(1753, 1) - basedays + maxdays := gregorianDays(9999, 365) - basedays + if days < mindays { + days = mindays + tm = 0 + } + if days > maxdays { + days = maxdays + tm = (23*60*60+59*60+59)*300 + 299 + } + res = make([]byte, 8) + binary.LittleEndian.PutUint32(res[0:4], uint32(days)) + binary.LittleEndian.PutUint32(res[4:8], uint32(tm)) + return +} + +func decodeDateTime(buf []byte) time.Time { + days := int32(binary.LittleEndian.Uint32(buf)) + tm := binary.LittleEndian.Uint32(buf[4:]) + ns := int(math.Trunc(float64(tm%300)/0.3+0.5)) * 1000000 + secs := int(tm / 300) + return time.Date(1900, 1, 1+int(days), + 0, 0, secs, ns, time.UTC) +} + +func readFixedType(ti *typeInfo, r *tdsBuffer) interface{} { + r.ReadFull(ti.Buffer) + buf := ti.Buffer + switch ti.TypeId { + case typeNull: + return nil + case typeInt1: + return int64(buf[0]) + case typeBit: + return buf[0] != 0 + case typeInt2: + return int64(int16(binary.LittleEndian.Uint16(buf))) + case typeInt4: + return int64(int32(binary.LittleEndian.Uint32(buf))) + case typeDateTim4: + return decodeDateTim4(buf) + case typeFlt4: + return math.Float32frombits(binary.LittleEndian.Uint32(buf)) + case typeMoney4: + return decodeMoney4(buf) + case typeMoney: + return decodeMoney(buf) + case typeDateTime: + return decodeDateTime(buf) + case typeFlt8: + return math.Float64frombits(binary.LittleEndian.Uint64(buf)) + case typeInt8: + return int64(binary.LittleEndian.Uint64(buf)) + default: + badStreamPanicf("Invalid typeid") + } + panic("shoulnd't get here") +} + +func readByteLenType(ti *typeInfo, r *tdsBuffer) interface{} { + size := r.byte() + if size == 0 { + return nil + } + r.ReadFull(ti.Buffer[:size]) + buf := ti.Buffer[:size] + switch ti.TypeId { + case typeDateN: + if len(buf) != 3 { + badStreamPanicf("Invalid size for DATENTYPE") + } + return decodeDate(buf) + case typeTimeN: + return decodeTime(ti.Scale, buf) + case typeDateTime2N: + return decodeDateTime2(ti.Scale, buf) + case typeDateTimeOffsetN: + return decodeDateTimeOffset(ti.Scale, buf) + case typeGuid: + return decodeGuid(buf) + case typeIntN: + switch len(buf) { + case 1: + return int64(buf[0]) + case 2: + return int64(int16((binary.LittleEndian.Uint16(buf)))) + case 4: + return int64(int32(binary.LittleEndian.Uint32(buf))) + case 8: + return int64(binary.LittleEndian.Uint64(buf)) + default: + badStreamPanicf("Invalid size for INTNTYPE: %d", len(buf)) + } + case typeDecimal, typeNumeric, typeDecimalN, typeNumericN: + return decodeDecimal(ti.Prec, ti.Scale, buf) + case typeBitN: + if len(buf) != 1 { + badStreamPanicf("Invalid size for BITNTYPE") + } + return buf[0] != 0 + case typeFltN: + switch len(buf) { + case 4: + return float64(math.Float32frombits(binary.LittleEndian.Uint32(buf))) + case 8: + return math.Float64frombits(binary.LittleEndian.Uint64(buf)) + default: + badStreamPanicf("Invalid size for FLTNTYPE") + } + case typeMoneyN: + switch len(buf) { + case 4: + return decodeMoney4(buf) + case 8: + return decodeMoney(buf) + default: + badStreamPanicf("Invalid size for MONEYNTYPE") + } + case typeDateTim4: + return decodeDateTim4(buf) + case typeDateTime: + return decodeDateTime(buf) + case typeDateTimeN: + switch len(buf) { + case 4: + return decodeDateTim4(buf) + case 8: + return decodeDateTime(buf) + default: + badStreamPanicf("Invalid size for DATETIMENTYPE") + } + case typeChar, typeVarChar: + return decodeChar(ti.Collation, buf) + case typeBinary, typeVarBinary: + // a copy, because the backing array for ti.Buffer is reused + // and can be overwritten by the next row while this row waits + // in a buffered chan + cpy := make([]byte, len(buf)) + copy(cpy, buf) + return cpy + default: + badStreamPanicf("Invalid typeid") + } + panic("shoulnd't get here") +} + +func writeByteLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { + if ti.Size > 0xff { + panic("Invalid size for BYTELEN_TYPE") + } + err = binary.Write(w, binary.LittleEndian, uint8(len(buf))) + if err != nil { + return + } + _, err = w.Write(buf) + return +} + +func readShortLenType(ti *typeInfo, r *tdsBuffer) interface{} { + size := r.uint16() + if size == 0xffff { + return nil + } + r.ReadFull(ti.Buffer[:size]) + buf := ti.Buffer[:size] + switch ti.TypeId { + case typeBigVarChar, typeBigChar: + return decodeChar(ti.Collation, buf) + case typeBigVarBin, typeBigBinary: + // a copy, because the backing array for ti.Buffer is reused + // and can be overwritten by the next row while this row waits + // in a buffered chan + cpy := make([]byte, len(buf)) + copy(cpy, buf) + return cpy + case typeNVarChar, typeNChar: + return decodeNChar(buf) + case typeUdt: + return decodeUdt(*ti, buf) + default: + badStreamPanicf("Invalid typeid") + } + panic("shoulnd't get here") +} + +func writeShortLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { + if buf == nil { + err = binary.Write(w, binary.LittleEndian, uint16(0xffff)) + return + } + if ti.Size > 0xfffe { + panic("Invalid size for USHORTLEN_TYPE") + } + err = binary.Write(w, binary.LittleEndian, uint16(ti.Size)) + if err != nil { + return + } + _, err = w.Write(buf) + return +} + +func readLongLenType(ti *typeInfo, r *tdsBuffer) interface{} { + // information about this format can be found here: + // http://msdn.microsoft.com/en-us/library/dd304783.aspx + // and here: + // http://msdn.microsoft.com/en-us/library/dd357254.aspx + textptrsize := int(r.byte()) + if textptrsize == 0 { + return nil + } + textptr := make([]byte, textptrsize) + r.ReadFull(textptr) + timestamp := r.uint64() + _ = timestamp // ignore timestamp + size := r.int32() + if size == -1 { + return nil + } + buf := make([]byte, size) + r.ReadFull(buf) + switch ti.TypeId { + case typeText: + return decodeChar(ti.Collation, buf) + case typeImage: + return buf + case typeNText: + return decodeNChar(buf) + default: + badStreamPanicf("Invalid typeid") + } + panic("shoulnd't get here") +} +func writeLongLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { + //textptr + err = binary.Write(w, binary.LittleEndian, byte(0x10)) + if err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) + if err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) + if err != nil { + return + } + //timestamp? + err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) + if err != nil { + return + } + + err = binary.Write(w, binary.LittleEndian, uint32(ti.Size)) + if err != nil { + return + } + _, err = w.Write(buf) + return +} + +func readCollation(r *tdsBuffer) (res cp.Collation) { + res.LcidAndFlags = r.uint32() + res.SortId = r.byte() + return +} + +func writeCollation(w io.Writer, col cp.Collation) (err error) { + if err = binary.Write(w, binary.LittleEndian, col.LcidAndFlags); err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, col.SortId) + return +} + +// reads variant value +// http://msdn.microsoft.com/en-us/library/dd303302.aspx +func readVariantType(ti *typeInfo, r *tdsBuffer) interface{} { + size := r.int32() + if size == 0 { + return nil + } + vartype := r.byte() + propbytes := int32(r.byte()) + switch vartype { + case typeGuid: + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return buf + case typeBit: + return r.byte() != 0 + case typeInt1: + return int64(r.byte()) + case typeInt2: + return int64(int16(r.uint16())) + case typeInt4: + return int64(r.int32()) + case typeInt8: + return int64(r.uint64()) + case typeDateTime: + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeDateTime(buf) + case typeDateTim4: + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeDateTim4(buf) + case typeFlt4: + return float64(math.Float32frombits(r.uint32())) + case typeFlt8: + return math.Float64frombits(r.uint64()) + case typeMoney4: + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeMoney4(buf) + case typeMoney: + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeMoney(buf) + case typeDateN: + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeDate(buf) + case typeTimeN: + scale := r.byte() + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeTime(scale, buf) + case typeDateTime2N: + scale := r.byte() + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeDateTime2(scale, buf) + case typeDateTimeOffsetN: + scale := r.byte() + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeDateTimeOffset(scale, buf) + case typeBigVarBin, typeBigBinary: + r.uint16() // max length, ignoring + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return buf + case typeDecimalN, typeNumericN: + prec := r.byte() + scale := r.byte() + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeDecimal(prec, scale, buf) + case typeBigVarChar, typeBigChar: + col := readCollation(r) + r.uint16() // max length, ignoring + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeChar(col, buf) + case typeNVarChar, typeNChar: + _ = readCollation(r) + r.uint16() // max length, ignoring + buf := make([]byte, size-2-propbytes) + r.ReadFull(buf) + return decodeNChar(buf) + default: + badStreamPanicf("Invalid variant typeid") + } + panic("shoulnd't get here") +} + +// partially length prefixed stream +// http://msdn.microsoft.com/en-us/library/dd340469.aspx +func readPLPType(ti *typeInfo, r *tdsBuffer) interface{} { + size := r.uint64() + var buf *bytes.Buffer + switch size { + case _PLP_NULL: + // null + return nil + case _UNKNOWN_PLP_LEN: + // size unknown + buf = bytes.NewBuffer(make([]byte, 0, 1000)) + default: + buf = bytes.NewBuffer(make([]byte, 0, size)) + } + for true { + chunksize := r.uint32() + if chunksize == 0 { + break + } + if _, err := io.CopyN(buf, r, int64(chunksize)); err != nil { + badStreamPanicf("Reading PLP type failed: %s", err.Error()) + } + } + switch ti.TypeId { + case typeXml: + return decodeXml(*ti, buf.Bytes()) + case typeBigVarChar, typeBigChar, typeText: + return decodeChar(ti.Collation, buf.Bytes()) + case typeBigVarBin, typeBigBinary, typeImage: + return buf.Bytes() + case typeNVarChar, typeNChar, typeNText: + return decodeNChar(buf.Bytes()) + case typeUdt: + return decodeUdt(*ti, buf.Bytes()) + } + panic("shoulnd't get here") +} + +func writePLPType(w io.Writer, ti typeInfo, buf []byte) (err error) { + if err = binary.Write(w, binary.LittleEndian, uint64(_UNKNOWN_PLP_LEN)); err != nil { + return + } + for { + chunksize := uint32(len(buf)) + if chunksize == 0 { + err = binary.Write(w, binary.LittleEndian, uint32(_PLP_TERMINATOR)) + return + } + if err = binary.Write(w, binary.LittleEndian, chunksize); err != nil { + return + } + if _, err = w.Write(buf[:chunksize]); err != nil { + return + } + buf = buf[chunksize:] + } +} + +func readVarLen(ti *typeInfo, r *tdsBuffer) { + switch ti.TypeId { + case typeDateN: + ti.Size = 3 + ti.Reader = readByteLenType + ti.Buffer = make([]byte, ti.Size) + case typeTimeN, typeDateTime2N, typeDateTimeOffsetN: + ti.Scale = r.byte() + switch ti.Scale { + case 0, 1, 2: + ti.Size = 3 + case 3, 4: + ti.Size = 4 + case 5, 6, 7: + ti.Size = 5 + default: + badStreamPanicf("Invalid scale for TIME/DATETIME2/DATETIMEOFFSET type") + } + switch ti.TypeId { + case typeDateTime2N: + ti.Size += 3 + case typeDateTimeOffsetN: + ti.Size += 5 + } + ti.Reader = readByteLenType + ti.Buffer = make([]byte, ti.Size) + case typeGuid, typeIntN, typeDecimal, typeNumeric, + typeBitN, typeDecimalN, typeNumericN, typeFltN, + typeMoneyN, typeDateTimeN, typeChar, + typeVarChar, typeBinary, typeVarBinary: + // byle len types + ti.Size = int(r.byte()) + ti.Buffer = make([]byte, ti.Size) + switch ti.TypeId { + case typeDecimal, typeNumeric, typeDecimalN, typeNumericN: + ti.Prec = r.byte() + ti.Scale = r.byte() + } + ti.Reader = readByteLenType + case typeXml: + ti.XmlInfo.SchemaPresent = r.byte() + if ti.XmlInfo.SchemaPresent != 0 { + // dbname + ti.XmlInfo.DBName = r.BVarChar() + // owning schema + ti.XmlInfo.OwningSchema = r.BVarChar() + // xml schema collection + ti.XmlInfo.XmlSchemaCollection = r.UsVarChar() + } + ti.Reader = readPLPType + case typeUdt: + ti.Size = int(r.uint16()) + ti.UdtInfo.DBName = r.BVarChar() + ti.UdtInfo.SchemaName = r.BVarChar() + ti.UdtInfo.TypeName = r.BVarChar() + ti.UdtInfo.AssemblyQualifiedName = r.UsVarChar() + + ti.Buffer = make([]byte, ti.Size) + ti.Reader = readPLPType + case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar, + typeNVarChar, typeNChar: + // short len types + ti.Size = int(r.uint16()) + switch ti.TypeId { + case typeBigVarChar, typeBigChar, typeNVarChar, typeNChar: + ti.Collation = readCollation(r) + } + if ti.Size == 0xffff { + ti.Reader = readPLPType + } else { + ti.Buffer = make([]byte, ti.Size) + ti.Reader = readShortLenType + } + case typeText, typeImage, typeNText, typeVariant: + // LONGLEN_TYPE + ti.Size = int(r.int32()) + switch ti.TypeId { + case typeText, typeNText: + ti.Collation = readCollation(r) + // ignore tablenames + numparts := int(r.byte()) + for i := 0; i < numparts; i++ { + r.UsVarChar() + } + ti.Reader = readLongLenType + case typeImage: + // ignore tablenames + numparts := int(r.byte()) + for i := 0; i < numparts; i++ { + r.UsVarChar() + } + ti.Reader = readLongLenType + case typeVariant: + ti.Reader = readVariantType + } + default: + badStreamPanicf("Invalid type %d", ti.TypeId) + } + return +} + +func decodeMoney(buf []byte) []byte { + money := int64(uint64(buf[4]) | + uint64(buf[5])<<8 | + uint64(buf[6])<<16 | + uint64(buf[7])<<24 | + uint64(buf[0])<<32 | + uint64(buf[1])<<40 | + uint64(buf[2])<<48 | + uint64(buf[3])<<56) + return scaleBytes(strconv.FormatInt(money, 10), 4) +} + +func decodeMoney4(buf []byte) []byte { + money := int32(binary.LittleEndian.Uint32(buf[0:4])) + return scaleBytes(strconv.FormatInt(int64(money), 10), 4) +} + +func decodeGuid(buf []byte) []byte { + res := make([]byte, 16) + copy(res, buf) + return res +} + +func decodeDecimal(prec uint8, scale uint8, buf []byte) []byte { + var sign uint8 + sign = buf[0] + dec := Decimal{ + positive: sign != 0, + prec: prec, + scale: scale, + } + buf = buf[1:] + l := len(buf) / 4 + for i := 0; i < l; i++ { + dec.integer[i] = binary.LittleEndian.Uint32(buf[0:4]) + buf = buf[4:] + } + return dec.Bytes() +} + +// http://msdn.microsoft.com/en-us/library/ee780895.aspx +func decodeDateInt(buf []byte) (days int) { + days = int(buf[0]) + int(buf[1])*256 + int(buf[2])*256*256 + return +} + +func decodeDate(buf []byte) time.Time { + return time.Date(1, 1, 1+decodeDateInt(buf), 0, 0, 0, 0, time.UTC) +} + +func encodeDate(val time.Time) (buf []byte) { + days, _, _ := dateTime2(val) + buf = make([]byte, 3) + buf[0] = byte(days) + buf[1] = byte(days >> 8) + buf[2] = byte(days >> 16) + return +} + +func decodeTimeInt(scale uint8, buf []byte) (sec int, ns int) { + var acc uint64 = 0 + for i := len(buf) - 1; i >= 0; i-- { + acc <<= 8 + acc |= uint64(buf[i]) + } + for i := 0; i < 7-int(scale); i++ { + acc *= 10 + } + nsbig := acc * 100 + sec = int(nsbig / 1000000000) + ns = int(nsbig % 1000000000) + return +} + +// calculate size of time field in bytes +func calcTimeSize(scale int) int { + if scale <= 2 { + return 3 + } else if scale <= 4 { + return 4 + } else { + return 5 + } +} + +// writes time value into a field buffer +// buffer should be at least calcTimeSize long +func encodeTimeInt(seconds, ns, scale int, buf []byte) { + ns_total := int64(seconds)*1000*1000*1000 + int64(ns) + t := ns_total / int64(math.Pow10(int(scale)*-1)*1e9) + buf[0] = byte(t) + buf[1] = byte(t >> 8) + buf[2] = byte(t >> 16) + buf[3] = byte(t >> 24) + buf[4] = byte(t >> 32) +} + +func decodeTime(scale uint8, buf []byte) time.Time { + sec, ns := decodeTimeInt(scale, buf) + return time.Date(1, 1, 1, 0, 0, sec, ns, time.UTC) +} + +func encodeTime(hour, minute, second, ns, scale int) (buf []byte) { + seconds := hour*3600 + minute*60 + second + buf = make([]byte, calcTimeSize(scale)) + encodeTimeInt(seconds, ns, scale, buf) + return +} + +func decodeDateTime2(scale uint8, buf []byte) time.Time { + timesize := len(buf) - 3 + sec, ns := decodeTimeInt(scale, buf[:timesize]) + days := decodeDateInt(buf[timesize:]) + return time.Date(1, 1, 1+days, 0, 0, sec, ns, time.UTC) +} + +func encodeDateTime2(val time.Time, scale int) (buf []byte) { + days, seconds, ns := dateTime2(val) + timesize := calcTimeSize(scale) + buf = make([]byte, 3+timesize) + encodeTimeInt(seconds, ns, scale, buf) + buf[timesize] = byte(days) + buf[timesize+1] = byte(days >> 8) + buf[timesize+2] = byte(days >> 16) + return +} + +func decodeDateTimeOffset(scale uint8, buf []byte) time.Time { + timesize := len(buf) - 3 - 2 + sec, ns := decodeTimeInt(scale, buf[:timesize]) + buf = buf[timesize:] + days := decodeDateInt(buf[:3]) + buf = buf[3:] + offset := int(int16(binary.LittleEndian.Uint16(buf))) // in mins + return time.Date(1, 1, 1+days, 0, 0, sec+offset*60, ns, + time.FixedZone("", offset*60)) +} + +func encodeDateTimeOffset(val time.Time, scale int) (buf []byte) { + timesize := calcTimeSize(scale) + buf = make([]byte, timesize+2+3) + days, seconds, ns := dateTime2(val.In(time.UTC)) + encodeTimeInt(seconds, ns, scale, buf) + buf[timesize] = byte(days) + buf[timesize+1] = byte(days >> 8) + buf[timesize+2] = byte(days >> 16) + _, offset := val.Zone() + offset /= 60 + buf[timesize+3] = byte(offset) + buf[timesize+4] = byte(offset >> 8) + return +} + +// returns days since Jan 1st 0001 in Gregorian calendar +func gregorianDays(year, yearday int) int { + year0 := year - 1 + return year0*365 + year0/4 - year0/100 + year0/400 + yearday - 1 +} + +func dateTime2(t time.Time) (days int, seconds int, ns int) { + // days since Jan 1 1 (in same TZ as t) + days = gregorianDays(t.Year(), t.YearDay()) + seconds = t.Second() + t.Minute()*60 + t.Hour()*60*60 + ns = t.Nanosecond() + if days < 0 { + days = 0 + seconds = 0 + ns = 0 + } + max := gregorianDays(9999, 365) + if days > max { + days = max + seconds = 59 + 59*60 + 23*60*60 + ns = 999999900 + } + return +} + +func decodeChar(col cp.Collation, buf []byte) string { + return cp.CharsetToUTF8(col, buf) +} + +func decodeUcs2(buf []byte) string { + res, err := ucs22str(buf) + if err != nil { + badStreamPanicf("Invalid UCS2 encoding: %s", err.Error()) + } + return res +} + +func decodeNChar(buf []byte) string { + return decodeUcs2(buf) +} + +func decodeXml(ti typeInfo, buf []byte) string { + return decodeUcs2(buf) +} + +func decodeUdt(ti typeInfo, buf []byte) []byte { + return buf +} + +// makes go/sql type instance as described below +// It should return +// the value type that can be used to scan types into. For example, the database +// column type "bigint" this should return "reflect.TypeOf(int64(0))". +func makeGoLangScanType(ti typeInfo) reflect.Type { + switch ti.TypeId { + case typeInt1: + return reflect.TypeOf(int64(0)) + case typeInt2: + return reflect.TypeOf(int64(0)) + case typeInt4: + return reflect.TypeOf(int64(0)) + case typeInt8: + return reflect.TypeOf(int64(0)) + case typeFlt4: + return reflect.TypeOf(float64(0)) + case typeIntN: + switch ti.Size { + case 1: + return reflect.TypeOf(int64(0)) + case 2: + return reflect.TypeOf(int64(0)) + case 4: + return reflect.TypeOf(int64(0)) + case 8: + return reflect.TypeOf(int64(0)) + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return reflect.TypeOf(float64(0)) + case typeFltN: + switch ti.Size { + case 4: + return reflect.TypeOf(float64(0)) + case 8: + return reflect.TypeOf(float64(0)) + default: + panic("invalid size of FLNNTYPE") + } + case typeBigVarBin: + return reflect.TypeOf([]byte{}) + case typeVarChar: + return reflect.TypeOf("") + case typeNVarChar: + return reflect.TypeOf("") + case typeBit, typeBitN: + return reflect.TypeOf(true) + case typeDecimalN, typeNumericN: + return reflect.TypeOf([]byte{}) + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return reflect.TypeOf([]byte{}) + case 8: + return reflect.TypeOf([]byte{}) + default: + panic("invalid size of MONEYN") + } + case typeDateTim4: + return reflect.TypeOf(time.Time{}) + case typeDateTime: + return reflect.TypeOf(time.Time{}) + case typeDateTimeN: + switch ti.Size { + case 4: + return reflect.TypeOf(time.Time{}) + case 8: + return reflect.TypeOf(time.Time{}) + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return reflect.TypeOf(time.Time{}) + case typeDateN: + return reflect.TypeOf(time.Time{}) + case typeTimeN: + return reflect.TypeOf(time.Time{}) + case typeDateTimeOffsetN: + return reflect.TypeOf(time.Time{}) + case typeBigVarChar: + return reflect.TypeOf("") + case typeBigChar: + return reflect.TypeOf("") + case typeNChar: + return reflect.TypeOf("") + case typeGuid: + return reflect.TypeOf([]byte{}) + case typeXml: + return reflect.TypeOf("") + case typeText: + return reflect.TypeOf("") + case typeNText: + return reflect.TypeOf("") + case typeImage: + return reflect.TypeOf([]byte{}) + case typeBigBinary: + return reflect.TypeOf([]byte{}) + case typeVariant: + return reflect.TypeOf(nil) + default: + panic(fmt.Sprintf("not implemented makeGoLangScanType for type %d", ti.TypeId)) + } +} + +func makeDecl(ti typeInfo) string { + switch ti.TypeId { + case typeNull: + // maybe we should use something else here + // this is tested in TestNull + return "nvarchar(1)" + case typeInt1: + return "tinyint" + case typeBigBinary: + return fmt.Sprintf("binary(%d)", ti.Size) + case typeInt2: + return "smallint" + case typeInt4: + return "int" + case typeInt8: + return "bigint" + case typeFlt4: + return "real" + case typeIntN: + switch ti.Size { + case 1: + return "tinyint" + case 2: + return "smallint" + case 4: + return "int" + case 8: + return "bigint" + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return "float" + case typeFltN: + switch ti.Size { + case 4: + return "real" + case 8: + return "float" + default: + panic("invalid size of FLNNTYPE") + } + case typeDecimal, typeDecimalN: + return fmt.Sprintf("decimal(%d, %d)", ti.Prec, ti.Scale) + case typeNumeric, typeNumericN: + return fmt.Sprintf("numeric(%d, %d)", ti.Prec, ti.Scale) + case typeMoney4: + return "smallmoney" + case typeMoney: + return "money" + case typeMoneyN: + switch ti.Size { + case 4: + return "smallmoney" + case 8: + return "money" + default: + panic("invalid size of MONEYNTYPE") + } + case typeBigVarBin: + if ti.Size > 8000 || ti.Size == 0 { + return "varbinary(max)" + } else { + return fmt.Sprintf("varbinary(%d)", ti.Size) + } + case typeNChar: + return fmt.Sprintf("nchar(%d)", ti.Size/2) + case typeBigChar, typeChar: + return fmt.Sprintf("char(%d)", ti.Size) + case typeBigVarChar, typeVarChar: + if ti.Size > 4000 || ti.Size == 0 { + return fmt.Sprintf("varchar(max)") + } else { + return fmt.Sprintf("varchar(%d)", ti.Size) + } + case typeNVarChar: + if ti.Size > 8000 || ti.Size == 0 { + return "nvarchar(max)" + } else { + return fmt.Sprintf("nvarchar(%d)", ti.Size/2) + } + case typeBit, typeBitN: + return "bit" + case typeDateN: + return "date" + case typeDateTim4: + return "smalldatetime" + case typeDateTime: + return "datetime" + case typeDateTimeN: + switch ti.Size { + case 4: + return "smalldatetime" + case 8: + return "datetime" + default: + panic("invalid size of DATETIMNTYPE") + } + case typeTimeN: + return "time" + case typeDateTime2N: + return fmt.Sprintf("datetime2(%d)", ti.Scale) + case typeDateTimeOffsetN: + return fmt.Sprintf("datetimeoffset(%d)", ti.Scale) + case typeText: + return "text" + case typeNText: + return "ntext" + case typeUdt: + return ti.UdtInfo.TypeName + case typeGuid: + return "uniqueidentifier" + default: + panic(fmt.Sprintf("not implemented makeDecl for type %#x", ti.TypeId)) + } +} + +// makes go/sql type name as described below +// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the +// database system type name without the length. Type names should be uppercase. +// Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT", +// "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML", +// "TIMESTAMP". +func makeGoLangTypeName(ti typeInfo) string { + switch ti.TypeId { + case typeInt1: + return "TINYINT" + case typeInt2: + return "SMALLINT" + case typeInt4: + return "INT" + case typeInt8: + return "BIGINT" + case typeFlt4: + return "REAL" + case typeIntN: + switch ti.Size { + case 1: + return "TINYINT" + case 2: + return "SMALLINT" + case 4: + return "INT" + case 8: + return "BIGINT" + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return "FLOAT" + case typeFltN: + switch ti.Size { + case 4: + return "REAL" + case 8: + return "FLOAT" + default: + panic("invalid size of FLNNTYPE") + } + case typeBigVarBin: + return "VARBINARY" + case typeVarChar: + return "VARCHAR" + case typeNVarChar: + return "NVARCHAR" + case typeBit, typeBitN: + return "BIT" + case typeDecimalN, typeNumericN: + return "DECIMAL" + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return "SMALLMONEY" + case 8: + return "MONEY" + default: + panic("invalid size of MONEYN") + } + case typeDateTim4: + return "SMALLDATETIME" + case typeDateTime: + return "DATETIME" + case typeDateTimeN: + switch ti.Size { + case 4: + return "SMALLDATETIME" + case 8: + return "DATETIME" + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return "DATETIME2" + case typeDateN: + return "DATE" + case typeTimeN: + return "TIME" + case typeDateTimeOffsetN: + return "DATETIMEOFFSET" + case typeBigVarChar: + return "VARCHAR" + case typeBigChar: + return "CHAR" + case typeNChar: + return "NCHAR" + case typeGuid: + return "UNIQUEIDENTIFIER" + case typeXml: + return "XML" + case typeText: + return "TEXT" + case typeNText: + return "NTEXT" + case typeImage: + return "IMAGE" + case typeVariant: + return "SQL_VARIANT" + case typeBigBinary: + return "BINARY" + default: + panic(fmt.Sprintf("not implemented makeGoLangTypeName for type %d", ti.TypeId)) + } +} + +// makes go/sql type length as described below +// It should return the length +// of the column type if the column is a variable length type. If the column is +// not a variable length type ok should return false. +// If length is not limited other than system limits, it should return math.MaxInt64. +// The following are examples of returned values for various types: +// TEXT (math.MaxInt64, true) +// varchar(10) (10, true) +// nvarchar(10) (10, true) +// decimal (0, false) +// int (0, false) +// bytea(30) (30, true) +func makeGoLangTypeLength(ti typeInfo) (int64, bool) { + switch ti.TypeId { + case typeInt1: + return 0, false + case typeInt2: + return 0, false + case typeInt4: + return 0, false + case typeInt8: + return 0, false + case typeFlt4: + return 0, false + case typeIntN: + switch ti.Size { + case 1: + return 0, false + case 2: + return 0, false + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return 0, false + case typeFltN: + switch ti.Size { + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of FLNNTYPE") + } + case typeBit, typeBitN: + return 0, false + case typeDecimalN, typeNumericN: + return 0, false + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of MONEYN") + } + case typeDateTim4, typeDateTime: + return 0, false + case typeDateTimeN: + switch ti.Size { + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return 0, false + case typeDateN: + return 0, false + case typeTimeN: + return 0, false + case typeDateTimeOffsetN: + return 0, false + case typeBigVarBin: + if ti.Size == 0xffff { + return 2147483645, true + } else { + return int64(ti.Size), true + } + case typeVarChar: + return int64(ti.Size), true + case typeBigVarChar: + if ti.Size == 0xffff { + return 2147483645, true + } else { + return int64(ti.Size), true + } + case typeBigChar: + return int64(ti.Size), true + case typeNVarChar: + if ti.Size == 0xffff { + return 2147483645 / 2, true + } else { + return int64(ti.Size) / 2, true + } + case typeNChar: + return int64(ti.Size) / 2, true + case typeGuid: + return 0, false + case typeXml: + return 1073741822, true + case typeText: + return 2147483647, true + case typeNText: + return 1073741823, true + case typeImage: + return 2147483647, true + case typeVariant: + return 0, false + case typeBigBinary: + return 0, false + default: + panic(fmt.Sprintf("not implemented makeGoLangTypeLength for type %d", ti.TypeId)) + } +} + +// makes go/sql type precision and scale as described below +// It should return the length +// of the column type if the column is a variable length type. If the column is +// not a variable length type ok should return false. +// If length is not limited other than system limits, it should return math.MaxInt64. +// The following are examples of returned values for various types: +// TEXT (math.MaxInt64, true) +// varchar(10) (10, true) +// nvarchar(10) (10, true) +// decimal (0, false) +// int (0, false) +// bytea(30) (30, true) +func makeGoLangTypePrecisionScale(ti typeInfo) (int64, int64, bool) { + switch ti.TypeId { + case typeInt1: + return 0, 0, false + case typeInt2: + return 0, 0, false + case typeInt4: + return 0, 0, false + case typeInt8: + return 0, 0, false + case typeFlt4: + return 0, 0, false + case typeIntN: + switch ti.Size { + case 1: + return 0, 0, false + case 2: + return 0, 0, false + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return 0, 0, false + case typeFltN: + switch ti.Size { + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of FLNNTYPE") + } + case typeBit, typeBitN: + return 0, 0, false + case typeDecimalN, typeNumericN: + return int64(ti.Prec), int64(ti.Scale), true + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of MONEYN") + } + case typeDateTim4, typeDateTime: + return 0, 0, false + case typeDateTimeN: + switch ti.Size { + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return 0, 0, false + case typeDateN: + return 0, 0, false + case typeTimeN: + return 0, 0, false + case typeDateTimeOffsetN: + return 0, 0, false + case typeBigVarBin: + return 0, 0, false + case typeVarChar: + return 0, 0, false + case typeBigVarChar: + return 0, 0, false + case typeBigChar: + return 0, 0, false + case typeNVarChar: + return 0, 0, false + case typeNChar: + return 0, 0, false + case typeGuid: + return 0, 0, false + case typeXml: + return 0, 0, false + case typeText: + return 0, 0, false + case typeNText: + return 0, 0, false + case typeImage: + return 0, 0, false + case typeVariant: + return 0, 0, false + case typeBigBinary: + return 0, 0, false + default: + panic(fmt.Sprintf("not implemented makeGoLangTypePrecisionScale for type %d", ti.TypeId)) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/types_test.go b/vendor/github.com/denisenkom/go-mssqldb/types_test.go new file mode 100644 index 00000000..38d8a4b5 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/types_test.go @@ -0,0 +1,123 @@ +package mssql + +import ( + "reflect" + "testing" + "time" +) + +func TestMakeGoLangScanType(t *testing.T) { + if (reflect.TypeOf(int64(0)) != makeGoLangScanType(typeInfo{TypeId: typeInt8})) { + t.Errorf("invalid type returned for typeDateTime") + } + if (reflect.TypeOf(float64(0)) != makeGoLangScanType(typeInfo{TypeId: typeFlt4})) { + t.Errorf("invalid type returned for typeDateTime") + } + if (reflect.TypeOf(float64(0)) != makeGoLangScanType(typeInfo{TypeId: typeFlt8})) { + t.Errorf("invalid type returned for typeDateTime") + } + if (reflect.TypeOf("") != makeGoLangScanType(typeInfo{TypeId: typeVarChar})) { + t.Errorf("invalid type returned for typeDateTime") + } + if (reflect.TypeOf(time.Time{}) != makeGoLangScanType(typeInfo{TypeId: typeDateTime})) { + t.Errorf("invalid type returned for typeDateTime") + } + if (reflect.TypeOf(time.Time{}) != makeGoLangScanType(typeInfo{TypeId: typeDateTim4})) { + t.Errorf("invalid type returned for typeDateTim4") + } + if (reflect.TypeOf(int64(0)) != makeGoLangScanType(typeInfo{TypeId: typeInt1})) { + t.Errorf("invalid type returned for typeInt1") + } + if (reflect.TypeOf(int64(0)) != makeGoLangScanType(typeInfo{TypeId: typeInt2})) { + t.Errorf("invalid type returned for typeInt2") + } + if (reflect.TypeOf(int64(0)) != makeGoLangScanType(typeInfo{TypeId: typeInt4})) { + t.Errorf("invalid type returned for typeInt4") + } + if (reflect.TypeOf(int64(0)) != makeGoLangScanType(typeInfo{TypeId: typeIntN, Size: 4})) { + t.Errorf("invalid type returned for typeIntN") + } + if (reflect.TypeOf([]byte{}) != makeGoLangScanType(typeInfo{TypeId: typeMoney, Size: 8})) { + t.Errorf("invalid type returned for typeIntN") + } +} + +func TestMakeGoLangTypeName(t *testing.T) { + defer handlePanic(t) + + tests := []struct { + typeName string + typeString string + typeID uint8 + }{ + {"typeDateTime", "DATETIME", typeDateTime}, + {"typeDateTim4", "SMALLDATETIME", typeDateTim4}, + {"typeBigBinary", "BINARY", typeBigBinary}, + //TODO: Add other supported types + } + + for _, tt := range tests { + if makeGoLangTypeName(typeInfo{TypeId: tt.typeID}) != tt.typeString { + t.Errorf("invalid type name returned for %s", tt.typeName) + } + } +} + +func TestMakeGoLangTypeLength(t *testing.T) { + defer handlePanic(t) + + tests := []struct { + typeName string + typeVarLen bool + typeLen int64 + typeID uint8 + }{ + {"typeDateTime", false, 0, typeDateTime}, + {"typeDateTim4", false, 0, typeDateTim4}, + {"typeBigBinary", false, 0, typeBigBinary}, + //TODO: Add other supported types + } + + for _, tt := range tests { + n, v := makeGoLangTypeLength(typeInfo{TypeId: tt.typeID}) + if v != tt.typeVarLen { + t.Errorf("invalid type length variability returned for %s", tt.typeName) + } + if n != tt.typeLen { + t.Errorf("invalid type length returned for %s", tt.typeName) + } + } +} + +func TestMakeGoLangTypePrecisionScale(t *testing.T) { + defer handlePanic(t) + + tests := []struct { + typeName string + typeID uint8 + typeVarLen bool + typePrec int64 + typeScale int64 + }{ + {"typeDateTime", typeDateTime, false, 0, 0}, + {"typeDateTim4", typeDateTim4, false, 0, 0}, + {"typeBigBinary", typeBigBinary, false, 0, 0}, + //TODO: Add other supported types + } + + for _, tt := range tests { + prec, scale, varLen := makeGoLangTypePrecisionScale(typeInfo{TypeId: tt.typeID}) + if varLen != tt.typeVarLen { + t.Errorf("invalid type length variability returned for %s", tt.typeName) + } + if prec != tt.typePrec || scale != tt.typeScale { + t.Errorf("invalid type precision and/or scale returned for %s", tt.typeName) + } + } +} + +func handlePanic(t *testing.T) { + if r := recover(); r != nil { + t.Errorf("recovered panic") + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go b/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go new file mode 100644 index 00000000..c8ef3149 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go @@ -0,0 +1,74 @@ +package mssql + +import ( + "database/sql/driver" + "encoding/hex" + "errors" + "fmt" +) + +type UniqueIdentifier [16]byte + +func (u *UniqueIdentifier) Scan(v interface{}) error { + reverse := func(b []byte) { + for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { + b[i], b[j] = b[j], b[i] + } + } + + switch vt := v.(type) { + case []byte: + if len(vt) != 16 { + return errors.New("mssql: invalid UniqueIdentifier length") + } + + var raw UniqueIdentifier + + copy(raw[:], vt) + + reverse(raw[0:4]) + reverse(raw[4:6]) + reverse(raw[6:8]) + *u = raw + + return nil + case string: + if len(vt) != 36 { + return errors.New("mssql: invalid UniqueIdentifier string length") + } + + b := []byte(vt) + for i, c := range b { + switch c { + case '-': + b = append(b[:i], b[i+1:]...) + } + } + + _, err := hex.Decode(u[:], []byte(b)) + return err + default: + return fmt.Errorf("mssql: cannot convert %T to UniqueIdentifier", v) + } +} + +func (u UniqueIdentifier) Value() (driver.Value, error) { + reverse := func(b []byte) { + for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { + b[i], b[j] = b[j], b[i] + } + } + + raw := make([]byte, len(u)) + copy(raw, u[:]) + + reverse(raw[0:4]) + reverse(raw[4:6]) + reverse(raw[6:8]) + + return raw, nil +} + +func (u UniqueIdentifier) String() string { + return fmt.Sprintf("%X-%X-%X-%X-%X", u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier_test.go b/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier_test.go new file mode 100644 index 00000000..2a29133a --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier_test.go @@ -0,0 +1,70 @@ +package mssql + +import ( + "bytes" + "database/sql" + "database/sql/driver" + "fmt" + "testing" +) + +func TestUniqueIdentifier(t *testing.T) { + dbUUID := UniqueIdentifier{0x67, 0x45, 0x23, 0x01, + 0xAB, 0x89, + 0xEF, 0xCD, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + } + + uuid := UniqueIdentifier{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF} + + t.Run("Scan", func(t *testing.T) { + t.Run("[]byte", func(t *testing.T) { + var sut UniqueIdentifier + if err := sut.Scan(dbUUID[:]); err != nil { + t.Fatal(err) + } + if sut != uuid { + t.Errorf("bytes not swapped correctly: got %q; want %q", sut, uuid) + } + }) + + t.Run("string", func(t *testing.T) { + var sut UniqueIdentifier + if err := sut.Scan(uuid.String()); err != nil { + t.Fatal(err) + } + if sut != uuid { + t.Errorf("string not scanned correctly: got %q; want %q", sut, uuid) + } + }) + }) + + t.Run("Value", func(t *testing.T) { + sut := uuid + v, err := sut.Value() + if err != nil { + t.Fatal(err) + } + + b, ok := v.([]byte) + if !ok { + t.Fatalf("(%T) is not []byte", v) + } + + if !bytes.Equal(b, dbUUID[:]) { + t.Errorf("got %q; want %q", b, dbUUID) + } + }) +} + +func TestUniqueIdentifierString(t *testing.T) { + sut := UniqueIdentifier{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF} + expected := "01234567-89AB-CDEF-0123-456789ABCDEF" + if actual := sut.String(); actual != expected { + t.Errorf("sut.String() = %s; want %s", sut, expected) + } +} + +var _ fmt.Stringer = UniqueIdentifier{} +var _ sql.Scanner = &UniqueIdentifier{} +var _ driver.Valuer = UniqueIdentifier{}